summaryrefslogtreecommitdiffstats
path: root/gnu/usr.bin
diff options
context:
space:
mode:
Diffstat (limited to 'gnu/usr.bin')
-rw-r--r--gnu/usr.bin/Makefile7
-rw-r--r--gnu/usr.bin/Makefile.inc3
-rw-r--r--gnu/usr.bin/as/CONTRIBUTORS11
-rw-r--r--gnu/usr.bin/as/COPYING339
-rw-r--r--gnu/usr.bin/as/ChangeLog429
-rw-r--r--gnu/usr.bin/as/Makefile73
-rw-r--r--gnu/usr.bin/as/Makefile.in409
-rw-r--r--gnu/usr.bin/as/NOTES16
-rw-r--r--gnu/usr.bin/as/NOTES.config52
-rw-r--r--gnu/usr.bin/as/README212
-rw-r--r--gnu/usr.bin/as/README-vms248
-rw-r--r--gnu/usr.bin/as/README.coff79
-rw-r--r--gnu/usr.bin/as/README.pic25
-rw-r--r--gnu/usr.bin/as/README.rich144
-rw-r--r--gnu/usr.bin/as/VERSION1
-rw-r--r--gnu/usr.bin/as/app.c746
-rw-r--r--gnu/usr.bin/as/as.1271
-rw-r--r--gnu/usr.bin/as/as.1aout271
-rw-r--r--gnu/usr.bin/as/as.c429
-rw-r--r--gnu/usr.bin/as/as.h424
-rw-r--r--gnu/usr.bin/as/atof-generic.c526
-rw-r--r--gnu/usr.bin/as/bignum-copy.c76
-rw-r--r--gnu/usr.bin/as/bignum.h64
-rw-r--r--gnu/usr.bin/as/bit_fix.h54
-rw-r--r--gnu/usr.bin/as/cond.c219
-rw-r--r--gnu/usr.bin/as/config-gas.com76
-rw-r--r--gnu/usr.bin/as/config/Makefile.hp3007
-rw-r--r--gnu/usr.bin/as/config/Makefile.i3865
-rw-r--r--gnu/usr.bin/as/config/Makefile.pc5327
-rw-r--r--gnu/usr.bin/as/config/Makefile.sparc5
-rw-r--r--gnu/usr.bin/as/config/Makefile.vax4
-rw-r--r--gnu/usr.bin/as/config/aout.h440
-rw-r--r--gnu/usr.bin/as/config/atof-ieee.c524
-rw-r--r--gnu/usr.bin/as/config/atof-ns32k.c436
-rw-r--r--gnu/usr.bin/as/config/atof-tahoe.c428
-rw-r--r--gnu/usr.bin/as/config/atof-vax.c497
-rw-r--r--gnu/usr.bin/as/config/coff.h783
-rw-r--r--gnu/usr.bin/as/config/cplus-dem.c927
-rw-r--r--gnu/usr.bin/as/config/ho-ansi.h29
-rw-r--r--gnu/usr.bin/as/config/ho-decstation.h29
-rw-r--r--gnu/usr.bin/as/config/ho-generic.h30
-rw-r--r--gnu/usr.bin/as/config/ho-hpux.h34
-rw-r--r--gnu/usr.bin/as/config/ho-i386.h30
-rw-r--r--gnu/usr.bin/as/config/ho-i386aix.h24
-rw-r--r--gnu/usr.bin/as/config/ho-rs6000.h22
-rw-r--r--gnu/usr.bin/as/config/ho-sun3.h3
-rw-r--r--gnu/usr.bin/as/config/ho-sun386.h5
-rw-r--r--gnu/usr.bin/as/config/ho-sun4.h3
-rw-r--r--gnu/usr.bin/as/config/ho-sunos.h81
-rw-r--r--gnu/usr.bin/as/config/ho-sysv.h27
-rw-r--r--gnu/usr.bin/as/config/ho-vax.h27
-rw-r--r--gnu/usr.bin/as/config/ho-vms.h30
-rw-r--r--gnu/usr.bin/as/config/mh-i3861
-rw-r--r--gnu/usr.bin/as/config/mh-i386aix5
-rw-r--r--gnu/usr.bin/as/config/mh-i386v41
-rw-r--r--gnu/usr.bin/as/config/mt-ebmon29k6
-rw-r--r--gnu/usr.bin/as/config/mt-h83005
-rw-r--r--gnu/usr.bin/as/config/mt-h8300hds4
-rw-r--r--gnu/usr.bin/as/config/mt-i386aix3
-rw-r--r--gnu/usr.bin/as/config/mt-mips1
-rw-r--r--gnu/usr.bin/as/config/mt-rs60001
-rw-r--r--gnu/usr.bin/as/config/obj-aout.c647
-rw-r--r--gnu/usr.bin/as/config/obj-aout.h305
-rw-r--r--gnu/usr.bin/as/config/obj-bfd-sunos.c71
-rw-r--r--gnu/usr.bin/as/config/obj-bfd-sunos.h69
-rw-r--r--gnu/usr.bin/as/config/obj-bout.c476
-rw-r--r--gnu/usr.bin/as/config/obj-bout.h313
-rw-r--r--gnu/usr.bin/as/config/obj-coff.c1978
-rw-r--r--gnu/usr.bin/as/config/obj-coff.h598
-rw-r--r--gnu/usr.bin/as/config/obj-coffbfd.c2182
-rw-r--r--gnu/usr.bin/as/config/obj-coffbfd.h516
-rw-r--r--gnu/usr.bin/as/config/obj-generic.c41
-rw-r--r--gnu/usr.bin/as/config/obj-generic.h78
-rw-r--r--gnu/usr.bin/as/config/obj-ieee.c539
-rw-r--r--gnu/usr.bin/as/config/obj-ieee.h46
-rw-r--r--gnu/usr.bin/as/config/obj-vms.c5484
-rw-r--r--gnu/usr.bin/as/config/obj-vms.h474
-rw-r--r--gnu/usr.bin/as/config/tc-a29k.c1113
-rw-r--r--gnu/usr.bin/as/config/tc-a29k.h40
-rw-r--r--gnu/usr.bin/as/config/tc-generic.c0
-rw-r--r--gnu/usr.bin/as/config/tc-generic.h37
-rw-r--r--gnu/usr.bin/as/config/tc-h8300.c1295
-rw-r--r--gnu/usr.bin/as/config/tc-h8300.h38
-rw-r--r--gnu/usr.bin/as/config/tc-i386.c2338
-rw-r--r--gnu/usr.bin/as/config/tc-i386.h251
-rw-r--r--gnu/usr.bin/as/config/tc-i860.c1295
-rw-r--r--gnu/usr.bin/as/config/tc-i860.h24
-rw-r--r--gnu/usr.bin/as/config/tc-i960.c2759
-rw-r--r--gnu/usr.bin/as/config/tc-i960.h281
-rw-r--r--gnu/usr.bin/as/config/tc-m68851.h304
-rw-r--r--gnu/usr.bin/as/config/tc-m68k.c4084
-rw-r--r--gnu/usr.bin/as/config/tc-m68k.h62
-rw-r--r--gnu/usr.bin/as/config/tc-m68kmote.h64
-rw-r--r--gnu/usr.bin/as/config/tc-m88k.c1435
-rw-r--r--gnu/usr.bin/as/config/tc-m88k.h35
-rw-r--r--gnu/usr.bin/as/config/tc-mips.c0
-rw-r--r--gnu/usr.bin/as/config/tc-mips.h0
-rw-r--r--gnu/usr.bin/as/config/tc-ns32k.c2015
-rw-r--r--gnu/usr.bin/as/config/tc-ns32k.h66
-rw-r--r--gnu/usr.bin/as/config/tc-rs6000.c0
-rw-r--r--gnu/usr.bin/as/config/tc-rs6000.h0
-rw-r--r--gnu/usr.bin/as/config/tc-sparc.c1803
-rw-r--r--gnu/usr.bin/as/config/tc-sparc.h52
-rw-r--r--gnu/usr.bin/as/config/tc-tahoe.c1924
-rw-r--r--gnu/usr.bin/as/config/tc-tahoe.h36
-rw-r--r--gnu/usr.bin/as/config/tc-vax.c3073
-rw-r--r--gnu/usr.bin/as/config/tc-vax.h25
-rw-r--r--gnu/usr.bin/as/config/te-dpx2.h8
-rw-r--r--gnu/usr.bin/as/config/te-generic.h25
-rw-r--r--gnu/usr.bin/as/config/te-hpux.h99
-rw-r--r--gnu/usr.bin/as/config/te-i386aix.h19
-rw-r--r--gnu/usr.bin/as/config/te-ic960.h46
-rw-r--r--gnu/usr.bin/as/config/te-sco386.h7
-rw-r--r--gnu/usr.bin/as/config/te-sequent.h32
-rw-r--r--gnu/usr.bin/as/config/te-sun3.h49
-rw-r--r--gnu/usr.bin/as/config/te-sysv32.h4
-rw-r--r--gnu/usr.bin/as/config/vax-inst.h77
-rw-r--r--gnu/usr.bin/as/configdos.bat14
-rwxr-xr-xgnu/usr.bin/as/configure.in204
-rw-r--r--gnu/usr.bin/as/debug.c104
-rw-r--r--gnu/usr.bin/as/doc/Makefile3
-rw-r--r--gnu/usr.bin/as/doc/as-all.texinfo4995
-rw-r--r--gnu/usr.bin/as/expr.c1000
-rw-r--r--gnu/usr.bin/as/expr.h85
-rw-r--r--gnu/usr.bin/as/flo-const.c161
-rw-r--r--gnu/usr.bin/as/flo-copy.c70
-rw-r--r--gnu/usr.bin/as/flonum-mult.c203
-rw-r--r--gnu/usr.bin/as/flonum.h125
-rw-r--r--gnu/usr.bin/as/frags.c296
-rw-r--r--gnu/usr.bin/as/frags.h89
-rw-r--r--gnu/usr.bin/as/gas-format.el79
-rw-r--r--gnu/usr.bin/as/hash.c992
-rw-r--r--gnu/usr.bin/as/hash.h65
-rw-r--r--gnu/usr.bin/as/hex-value.c61
-rw-r--r--gnu/usr.bin/as/input-file.c327
-rw-r--r--gnu/usr.bin/as/input-file.h88
-rw-r--r--gnu/usr.bin/as/input-scrub.c420
-rw-r--r--gnu/usr.bin/as/link.cmd10
-rw-r--r--gnu/usr.bin/as/listing.c1079
-rw-r--r--gnu/usr.bin/as/listing.h115
-rw-r--r--gnu/usr.bin/as/make-gas.com86
-rw-r--r--gnu/usr.bin/as/makefile.dos593
-rw-r--r--gnu/usr.bin/as/messages.c595
-rw-r--r--gnu/usr.bin/as/obj.h77
-rw-r--r--gnu/usr.bin/as/obstack.c374
-rw-r--r--gnu/usr.bin/as/obstack.h448
-rw-r--r--gnu/usr.bin/as/opcode/ChangeLog56
-rw-r--r--gnu/usr.bin/as/opcode/a29k.h327
-rw-r--r--gnu/usr.bin/as/opcode/h8300.h266
-rw-r--r--gnu/usr.bin/as/opcode/i386.h833
-rw-r--r--gnu/usr.bin/as/opcode/i860.h495
-rw-r--r--gnu/usr.bin/as/opcode/i960.h434
-rw-r--r--gnu/usr.bin/as/opcode/m68k.h2003
-rw-r--r--gnu/usr.bin/as/opcode/m88k.h282
-rw-r--r--gnu/usr.bin/as/opcode/mips.h363
-rw-r--r--gnu/usr.bin/as/opcode/np1.h422
-rw-r--r--gnu/usr.bin/as/opcode/ns32k.h491
-rw-r--r--gnu/usr.bin/as/opcode/pn.h282
-rw-r--r--gnu/usr.bin/as/opcode/pyr.h287
-rw-r--r--gnu/usr.bin/as/opcode/sparc.h885
-rw-r--r--gnu/usr.bin/as/opcode/tahoe.h247
-rw-r--r--gnu/usr.bin/as/opcode/vax.h382
-rw-r--r--gnu/usr.bin/as/output-file.c122
-rw-r--r--gnu/usr.bin/as/output-file.h40
-rw-r--r--gnu/usr.bin/as/read.c2386
-rw-r--r--gnu/usr.bin/as/read.h156
-rw-r--r--gnu/usr.bin/as/struc-symbol.h130
-rw-r--r--gnu/usr.bin/as/subsegs.c311
-rw-r--r--gnu/usr.bin/as/subsegs.h93
-rw-r--r--gnu/usr.bin/as/symbols.c658
-rw-r--r--gnu/usr.bin/as/symbols.h82
-rw-r--r--gnu/usr.bin/as/tc.h112
-rwxr-xr-xgnu/usr.bin/as/testscripts/doboth20
-rwxr-xr-xgnu/usr.bin/as/testscripts/doobjcmp89
-rwxr-xr-xgnu/usr.bin/as/testscripts/dostriptest15
-rwxr-xr-xgnu/usr.bin/as/testscripts/dotest44
-rwxr-xr-xgnu/usr.bin/as/testscripts/dounsortreloc9
-rwxr-xr-xgnu/usr.bin/as/testscripts/dounsortsymbols9
-rw-r--r--gnu/usr.bin/as/version.c30
-rw-r--r--gnu/usr.bin/as/write.c1222
-rw-r--r--gnu/usr.bin/as/write.h120
-rw-r--r--gnu/usr.bin/as/xmalloc.c75
-rw-r--r--gnu/usr.bin/as/xrealloc.c74
-rw-r--r--gnu/usr.bin/awk/ACKNOWLEDGMENT8
-rw-r--r--gnu/usr.bin/awk/FUTURES69
-rw-r--r--gnu/usr.bin/awk/LIMITATIONS2
-rw-r--r--gnu/usr.bin/awk/Makefile20
-rw-r--r--gnu/usr.bin/awk/NEWS207
-rw-r--r--gnu/usr.bin/awk/PORTS9
-rw-r--r--gnu/usr.bin/awk/PROBLEMS6
-rw-r--r--gnu/usr.bin/awk/README25
-rw-r--r--gnu/usr.bin/awk/array.c316
-rw-r--r--gnu/usr.bin/awk/awk.1252
-rw-r--r--gnu/usr.bin/awk/awk.h133
-rw-r--r--gnu/usr.bin/awk/awk.y144
-rw-r--r--gnu/usr.bin/awk/builtin.c690
-rw-r--r--gnu/usr.bin/awk/config.h48
-rw-r--r--gnu/usr.bin/awk/dfa.c2805
-rw-r--r--gnu/usr.bin/awk/dfa.h425
-rw-r--r--gnu/usr.bin/awk/doc/Makefile3
-rw-r--r--gnu/usr.bin/awk/doc/gawk.texi11270
-rw-r--r--gnu/usr.bin/awk/eval.c135
-rw-r--r--gnu/usr.bin/awk/field.c133
-rw-r--r--gnu/usr.bin/awk/getopt.c203
-rw-r--r--gnu/usr.bin/awk/getopt.h31
-rw-r--r--gnu/usr.bin/awk/getopt1.c81
-rw-r--r--gnu/usr.bin/awk/io.c242
-rw-r--r--gnu/usr.bin/awk/iop.c37
-rw-r--r--gnu/usr.bin/awk/main.c202
-rw-r--r--gnu/usr.bin/awk/msg.c21
-rw-r--r--gnu/usr.bin/awk/node.c90
-rw-r--r--gnu/usr.bin/awk/patchlevel.h2
-rw-r--r--gnu/usr.bin/awk/protos.h55
-rw-r--r--gnu/usr.bin/awk/re.c58
-rw-r--r--gnu/usr.bin/awk/regex.c2854
-rw-r--r--gnu/usr.bin/awk/regex.h260
-rw-r--r--gnu/usr.bin/awk/version.c7
-rw-r--r--gnu/usr.bin/bc/COPYING341
-rw-r--r--gnu/usr.bin/bc/Makefile6
-rw-r--r--gnu/usr.bin/bc/bc.1730
-rw-r--r--gnu/usr.bin/bc/bc.c1369
-rw-r--r--gnu/usr.bin/bc/bcdefs.h154
-rw-r--r--gnu/usr.bin/bc/config.h4
-rw-r--r--gnu/usr.bin/bc/const.h87
-rw-r--r--gnu/usr.bin/bc/execute.c783
-rw-r--r--gnu/usr.bin/bc/global.c42
-rw-r--r--gnu/usr.bin/bc/global.h108
-rw-r--r--gnu/usr.bin/bc/libmath.b255
-rw-r--r--gnu/usr.bin/bc/load.c333
-rw-r--r--gnu/usr.bin/bc/main.c204
-rw-r--r--gnu/usr.bin/bc/math.h40
-rw-r--r--gnu/usr.bin/bc/number.c1405
-rw-r--r--gnu/usr.bin/bc/number.h60
-rw-r--r--gnu/usr.bin/bc/proto.h165
-rw-r--r--gnu/usr.bin/bc/scan.c1368
-rw-r--r--gnu/usr.bin/bc/storage.c967
-rw-r--r--gnu/usr.bin/bc/util.c794
-rw-r--r--gnu/usr.bin/bc/version.h3
-rw-r--r--gnu/usr.bin/bc/y.tab.h40
-rw-r--r--gnu/usr.bin/binutils/gdb/Makefile75
-rw-r--r--gnu/usr.bin/binutils/gdb/gdb.1390
-rw-r--r--gnu/usr.bin/binutils/gdb/i386/freebsd-nat.c619
-rw-r--r--gnu/usr.bin/binutils/gdb/i386/nm.h100
-rw-r--r--gnu/usr.bin/binutils/gdb/i386/tm.h90
-rw-r--r--gnu/usr.bin/binutils/gdb/i386/version.c3
-rw-r--r--gnu/usr.bin/binutils/gdb/i386/xm.h29
-rw-r--r--gnu/usr.bin/cc/Makefile4
-rw-r--r--gnu/usr.bin/cc/Makefile.inc27
-rw-r--r--gnu/usr.bin/cc/README2
-rw-r--r--gnu/usr.bin/cc/c++/Makefile6
-rw-r--r--gnu/usr.bin/cc/c++/g++.c28
-rw-r--r--gnu/usr.bin/cc/cc/Makefile15
-rw-r--r--gnu/usr.bin/cc/cc/cc.120
-rw-r--r--gnu/usr.bin/cc/cc/gcc.c789
-rw-r--r--gnu/usr.bin/cc/cc1/Makefile8
-rw-r--r--gnu/usr.bin/cc/cc1/c-aux-info.c2
-rw-r--r--gnu/usr.bin/cc/cc1/c-decl.c118
-rw-r--r--gnu/usr.bin/cc/cc1/c-iterate.c20
-rw-r--r--gnu/usr.bin/cc/cc1/c-lang.c2
-rw-r--r--gnu/usr.bin/cc/cc1/c-lex.c8
-rw-r--r--gnu/usr.bin/cc/cc1/c-parse.c53
-rw-r--r--gnu/usr.bin/cc/cc1/c-typeck.c200
-rw-r--r--gnu/usr.bin/cc/cc1plus/Makefile8
-rw-r--r--gnu/usr.bin/cc/cc1plus/call.c151
-rw-r--r--gnu/usr.bin/cc/cc1plus/class.c344
-rw-r--r--gnu/usr.bin/cc/cc1plus/cp-tree.h20
-rw-r--r--gnu/usr.bin/cc/cc1plus/cvt.c219
-rw-r--r--gnu/usr.bin/cc/cc1plus/decl.c658
-rw-r--r--gnu/usr.bin/cc/cc1plus/decl2.c190
-rw-r--r--gnu/usr.bin/cc/cc1plus/edsel.c2
-rw-r--r--gnu/usr.bin/cc/cc1plus/errfn.c34
-rw-r--r--gnu/usr.bin/cc/cc1plus/error.c89
-rw-r--r--gnu/usr.bin/cc/cc1plus/except.c123
-rw-r--r--gnu/usr.bin/cc/cc1plus/expr.c9
-rw-r--r--gnu/usr.bin/cc/cc1plus/gc.c26
-rw-r--r--gnu/usr.bin/cc/cc1plus/hash.h60
-rw-r--r--gnu/usr.bin/cc/cc1plus/init.c87
-rw-r--r--gnu/usr.bin/cc/cc1plus/lex.c223
-rw-r--r--gnu/usr.bin/cc/cc1plus/lex.h11
-rw-r--r--gnu/usr.bin/cc/cc1plus/method.c249
-rw-r--r--gnu/usr.bin/cc/cc1plus/parse.c7852
-rw-r--r--gnu/usr.bin/cc/cc1plus/pt.c345
-rw-r--r--gnu/usr.bin/cc/cc1plus/search.c40
-rw-r--r--gnu/usr.bin/cc/cc1plus/sig.c12
-rw-r--r--gnu/usr.bin/cc/cc1plus/spew.c26
-rw-r--r--gnu/usr.bin/cc/cc1plus/tree.c231
-rw-r--r--gnu/usr.bin/cc/cc1plus/typeck.c254
-rw-r--r--gnu/usr.bin/cc/cc1plus/typeck2.c46
-rw-r--r--gnu/usr.bin/cc/cc_int/Makefile10
-rw-r--r--gnu/usr.bin/cc/cc_int/aux-output.c1052
-rw-r--r--gnu/usr.bin/cc/cc_int/bc-emit.c8
-rw-r--r--gnu/usr.bin/cc/cc_int/bc-optab.c6
-rw-r--r--gnu/usr.bin/cc/cc_int/c-common.c166
-rw-r--r--gnu/usr.bin/cc/cc_int/caller-save.c44
-rw-r--r--gnu/usr.bin/cc/cc_int/calls.c221
-rw-r--r--gnu/usr.bin/cc/cc_int/combine.c352
-rw-r--r--gnu/usr.bin/cc/cc_int/convert.c8
-rw-r--r--gnu/usr.bin/cc/cc_int/cse.c372
-rw-r--r--gnu/usr.bin/cc/cc_int/dbxout.c22
-rw-r--r--gnu/usr.bin/cc/cc_int/dwarfout.c215
-rw-r--r--gnu/usr.bin/cc/cc_int/emit-rtl.c114
-rw-r--r--gnu/usr.bin/cc/cc_int/explow.c20
-rw-r--r--gnu/usr.bin/cc/cc_int/expmed.c344
-rw-r--r--gnu/usr.bin/cc/cc_int/expr.c839
-rw-r--r--gnu/usr.bin/cc/cc_int/final.c41
-rw-r--r--gnu/usr.bin/cc/cc_int/flow.c193
-rw-r--r--gnu/usr.bin/cc/cc_int/fold-const.c92
-rw-r--r--gnu/usr.bin/cc/cc_int/function.c258
-rw-r--r--gnu/usr.bin/cc/cc_int/getpwd.c9
-rw-r--r--gnu/usr.bin/cc/cc_int/global.c99
-rw-r--r--gnu/usr.bin/cc/cc_int/insn-emit.c592
-rw-r--r--gnu/usr.bin/cc/cc_int/insn-extract.c420
-rw-r--r--gnu/usr.bin/cc/cc_int/insn-opinit.c10
-rw-r--r--gnu/usr.bin/cc/cc_int/insn-output.c1330
-rw-r--r--gnu/usr.bin/cc/cc_int/insn-recog.c4794
-rw-r--r--gnu/usr.bin/cc/cc_int/integrate.c88
-rw-r--r--gnu/usr.bin/cc/cc_int/jump.c65
-rw-r--r--gnu/usr.bin/cc/cc_int/local-alloc.c59
-rw-r--r--gnu/usr.bin/cc/cc_int/loop.c93
-rw-r--r--gnu/usr.bin/cc/cc_int/obstack.c6
-rw-r--r--gnu/usr.bin/cc/cc_int/optabs.c236
-rw-r--r--gnu/usr.bin/cc/cc_int/print-tree.c139
-rw-r--r--gnu/usr.bin/cc/cc_int/real.c250
-rw-r--r--gnu/usr.bin/cc/cc_int/recog.c20
-rw-r--r--gnu/usr.bin/cc/cc_int/reg-stack.c26
-rw-r--r--gnu/usr.bin/cc/cc_int/regclass.c36
-rw-r--r--gnu/usr.bin/cc/cc_int/reload.c296
-rw-r--r--gnu/usr.bin/cc/cc_int/reload1.c370
-rw-r--r--gnu/usr.bin/cc/cc_int/reorg.c175
-rw-r--r--gnu/usr.bin/cc/cc_int/rtl.c10
-rw-r--r--gnu/usr.bin/cc/cc_int/rtlanal.c36
-rw-r--r--gnu/usr.bin/cc/cc_int/sched.c118
-rw-r--r--gnu/usr.bin/cc/cc_int/sdbout.c4
-rw-r--r--gnu/usr.bin/cc/cc_int/stmt.c314
-rw-r--r--gnu/usr.bin/cc/cc_int/stor-layout.c37
-rw-r--r--gnu/usr.bin/cc/cc_int/stupid.c44
-rw-r--r--gnu/usr.bin/cc/cc_int/toplev.c70
-rw-r--r--gnu/usr.bin/cc/cc_int/tree.c204
-rw-r--r--gnu/usr.bin/cc/cc_int/unroll.c263
-rw-r--r--gnu/usr.bin/cc/cc_int/varasm.c40
-rw-r--r--gnu/usr.bin/cc/cc_int/version.c2
-rw-r--r--gnu/usr.bin/cc/cc_int/xcoffout.c42
-rw-r--r--gnu/usr.bin/cc/cccp/Makefile11
-rw-r--r--gnu/usr.bin/cc/cpp/Makefile7
-rw-r--r--gnu/usr.bin/cc/cpp/cccp.c618
-rw-r--r--gnu/usr.bin/cc/cpp/cexp.c116
-rw-r--r--gnu/usr.bin/cc/cpp/cpp.1675
-rw-r--r--gnu/usr.bin/cc/doc/Makefile8
-rw-r--r--gnu/usr.bin/cc/doc/cpp.texi2807
-rw-r--r--gnu/usr.bin/cc/doc/extend.texi2919
-rw-r--r--gnu/usr.bin/cc/doc/gcc.texi4525
-rw-r--r--gnu/usr.bin/cc/doc/gpcompare.texi236
-rw-r--r--gnu/usr.bin/cc/doc/gxxint.texi1271
-rw-r--r--gnu/usr.bin/cc/doc/install.texi2089
-rw-r--r--gnu/usr.bin/cc/doc/invoke.texi4214
-rw-r--r--gnu/usr.bin/cc/doc/md.texi3965
-rw-r--r--gnu/usr.bin/cc/doc/reno.texi752
-rw-r--r--gnu/usr.bin/cc/doc/rtl.texi2800
-rw-r--r--gnu/usr.bin/cc/doc/templates.texi235
-rw-r--r--gnu/usr.bin/cc/doc/tm.texi6337
-rw-r--r--gnu/usr.bin/cc/f77/Makefile9
-rw-r--r--gnu/usr.bin/cc/f77/f77.167
-rw-r--r--gnu/usr.bin/cc/f77/f77.c542
-rw-r--r--gnu/usr.bin/cc/include/bc-arity.h42
-rw-r--r--gnu/usr.bin/cc/include/bi-run.h2
-rw-r--r--gnu/usr.bin/cc/include/bytecode.h4
-rw-r--r--gnu/usr.bin/cc/include/c-gperf.h60
-rw-r--r--gnu/usr.bin/cc/include/expr.h14
-rw-r--r--gnu/usr.bin/cc/include/gbl-ctors.h15
-rw-r--r--gnu/usr.bin/cc/include/hard-reg-set.h2
-rw-r--r--gnu/usr.bin/cc/include/i386/bsd.h3
-rw-r--r--gnu/usr.bin/cc/include/i386/i386.h542
-rw-r--r--gnu/usr.bin/cc/include/i386/unix.h11
-rw-r--r--gnu/usr.bin/cc/include/insn-codes.h341
-rw-r--r--gnu/usr.bin/cc/include/insn-flags.h73
-rw-r--r--gnu/usr.bin/cc/include/integrate.h2
-rw-r--r--gnu/usr.bin/cc/include/longlong.h2
-rw-r--r--gnu/usr.bin/cc/include/machmode.def2
-rw-r--r--gnu/usr.bin/cc/include/obstack.h19
-rw-r--r--gnu/usr.bin/cc/include/output.h2
-rw-r--r--gnu/usr.bin/cc/include/pcp.h6
-rw-r--r--gnu/usr.bin/cc/include/real.h4
-rw-r--r--gnu/usr.bin/cc/include/regs.h8
-rw-r--r--gnu/usr.bin/cc/include/reload.h11
-rw-r--r--gnu/usr.bin/cc/include/rtl.h14
-rw-r--r--gnu/usr.bin/cc/include/stack.h2
-rw-r--r--gnu/usr.bin/cc/include/tm.h168
-rw-r--r--gnu/usr.bin/cc/include/tree.h32
-rw-r--r--gnu/usr.bin/cc/legal/md880
-rw-r--r--gnu/usr.bin/cc/legal/parse.y3813
-rw-r--r--gnu/usr.bin/cc/libgcc/Makefile10
-rw-r--r--gnu/usr.bin/cc/libgcc/libgcc1.c2
-rw-r--r--gnu/usr.bin/cc/libgcc/libgcc2.c204
-rw-r--r--gnu/usr.bin/cpio/COPYING339
-rw-r--r--gnu/usr.bin/cpio/COPYING.LIB481
-rw-r--r--gnu/usr.bin/cpio/ChangeLog781
-rw-r--r--gnu/usr.bin/cpio/Makefile10
-rw-r--r--gnu/usr.bin/cpio/NEWS55
-rw-r--r--gnu/usr.bin/cpio/README56
-rw-r--r--gnu/usr.bin/cpio/alloca.c475
-rw-r--r--gnu/usr.bin/cpio/copyin.c1272
-rw-r--r--gnu/usr.bin/cpio/copyout.c936
-rw-r--r--gnu/usr.bin/cpio/copypass.c449
-rw-r--r--gnu/usr.bin/cpio/cpio.1312
-rw-r--r--gnu/usr.bin/cpio/cpio.h69
-rw-r--r--gnu/usr.bin/cpio/cpiohdr.h90
-rw-r--r--gnu/usr.bin/cpio/defer.c43
-rw-r--r--gnu/usr.bin/cpio/defer.h8
-rw-r--r--gnu/usr.bin/cpio/dirname.c66
-rw-r--r--gnu/usr.bin/cpio/dstring.c114
-rw-r--r--gnu/usr.bin/cpio/dstring.h49
-rw-r--r--gnu/usr.bin/cpio/error.c106
-rw-r--r--gnu/usr.bin/cpio/extern.h181
-rw-r--r--gnu/usr.bin/cpio/filemode.c229
-rw-r--r--gnu/usr.bin/cpio/filetypes.h84
-rw-r--r--gnu/usr.bin/cpio/fnmatch.c200
-rw-r--r--gnu/usr.bin/cpio/fnmatch.h60
-rw-r--r--gnu/usr.bin/cpio/getopt.c744
-rw-r--r--gnu/usr.bin/cpio/getopt.h129
-rw-r--r--gnu/usr.bin/cpio/getopt1.c176
-rw-r--r--gnu/usr.bin/cpio/global.c168
-rw-r--r--gnu/usr.bin/cpio/idcache.c206
-rw-r--r--gnu/usr.bin/cpio/lchown.c27
-rw-r--r--gnu/usr.bin/cpio/main.c485
-rw-r--r--gnu/usr.bin/cpio/makepath.c297
-rw-r--r--gnu/usr.bin/cpio/rmt.h98
-rw-r--r--gnu/usr.bin/cpio/rtapelib.c582
-rw-r--r--gnu/usr.bin/cpio/stripslash.c39
-rw-r--r--gnu/usr.bin/cpio/system.h139
-rw-r--r--gnu/usr.bin/cpio/tar.c522
-rw-r--r--gnu/usr.bin/cpio/tar.h112
-rw-r--r--gnu/usr.bin/cpio/tarhdr.h62
-rw-r--r--gnu/usr.bin/cpio/tcexparg.c240
-rw-r--r--gnu/usr.bin/cpio/userspec.c180
-rw-r--r--gnu/usr.bin/cpio/util.c1102
-rw-r--r--gnu/usr.bin/cpio/version.c2
-rw-r--r--gnu/usr.bin/cpio/xmalloc.c65
-rw-r--r--gnu/usr.bin/cpio/xstrdup.c32
-rw-r--r--gnu/usr.bin/cvs/BUGS248
-rw-r--r--gnu/usr.bin/cvs/FAQ10006
-rw-r--r--gnu/usr.bin/cvs/INSTALL356
-rw-r--r--gnu/usr.bin/cvs/MINOR-BUGS60
-rw-r--r--gnu/usr.bin/cvs/Makefile5
-rw-r--r--gnu/usr.bin/cvs/Makefile.inc8
-rw-r--r--gnu/usr.bin/cvs/NEWS863
-rw-r--r--gnu/usr.bin/cvs/PROJECTS59
-rw-r--r--gnu/usr.bin/cvs/README207
-rw-r--r--gnu/usr.bin/cvs/TODO474
-rw-r--r--gnu/usr.bin/cvs/contrib/Makefile37
-rw-r--r--gnu/usr.bin/cvs/contrib/README90
-rw-r--r--gnu/usr.bin/cvs/contrib/ccvs-rsh.pl97
-rw-r--r--gnu/usr.bin/cvs/contrib/clmerge.pl152
-rw-r--r--gnu/usr.bin/cvs/contrib/cln_hist.pl92
-rw-r--r--gnu/usr.bin/cvs/contrib/commit_prep.pl216
-rw-r--r--gnu/usr.bin/cvs/contrib/cvs-format.el81
-rw-r--r--gnu/usr.bin/cvs/contrib/cvs_acls.pl143
-rw-r--r--gnu/usr.bin/cvs/contrib/cvscheck.man53
-rw-r--r--gnu/usr.bin/cvs/contrib/cvscheck.sh84
-rw-r--r--gnu/usr.bin/cvs/contrib/cvshelp.man562
-rw-r--r--gnu/usr.bin/cvs/contrib/descend.man115
-rw-r--r--gnu/usr.bin/cvs/contrib/descend.sh116
-rw-r--r--gnu/usr.bin/cvs/contrib/dirfns.shar481
-rw-r--r--gnu/usr.bin/cvs/contrib/easy-import.pl388
-rw-r--r--gnu/usr.bin/cvs/contrib/intro.doc112
-rw-r--r--gnu/usr.bin/cvs/contrib/log.pl169
-rw-r--r--gnu/usr.bin/cvs/contrib/log_accum.pl496
-rw-r--r--gnu/usr.bin/cvs/contrib/mfpipe.pl88
-rw-r--r--gnu/usr.bin/cvs/contrib/pcl-cvs/ChangeLog774
-rw-r--r--gnu/usr.bin/cvs/contrib/pcl-cvs/INSTALL89
-rw-r--r--gnu/usr.bin/cvs/contrib/pcl-cvs/Makefile16
-rw-r--r--gnu/usr.bin/cvs/contrib/pcl-cvs/NEWS113
-rw-r--r--gnu/usr.bin/cvs/contrib/pcl-cvs/README29
-rw-r--r--gnu/usr.bin/cvs/contrib/pcl-cvs/compile-all.el52
-rw-r--r--gnu/usr.bin/cvs/contrib/pcl-cvs/compile.sh2
-rw-r--r--gnu/usr.bin/cvs/contrib/pcl-cvs/pcl-cvs-lucid.el133
-rw-r--r--gnu/usr.bin/cvs/contrib/pcl-cvs/pcl-cvs-startup.el14
-rw-r--r--gnu/usr.bin/cvs/contrib/pcl-cvs/pcl-cvs.el2493
-rw-r--r--gnu/usr.bin/cvs/contrib/pcl-cvs/pcl-cvs.texinfo1744
-rw-r--r--gnu/usr.bin/cvs/contrib/rcs-to-cvs.sh185
-rw-r--r--gnu/usr.bin/cvs/contrib/rcs2log.sh592
-rw-r--r--gnu/usr.bin/cvs/contrib/rcs2sccs.sh143
-rw-r--r--gnu/usr.bin/cvs/contrib/rcslock.pl235
-rw-r--r--gnu/usr.bin/cvs/contrib/sccs2rcs.csh277
-rw-r--r--gnu/usr.bin/cvs/cvs/ChangeLog3205
-rw-r--r--gnu/usr.bin/cvs/cvs/Makefile20
-rw-r--r--gnu/usr.bin/cvs/cvs/NOTES60
-rw-r--r--gnu/usr.bin/cvs/cvs/README-rm-add48
-rw-r--r--gnu/usr.bin/cvs/cvs/add.c539
-rw-r--r--gnu/usr.bin/cvs/cvs/admin.c179
-rw-r--r--gnu/usr.bin/cvs/cvs/checkin.c204
-rw-r--r--gnu/usr.bin/cvs/cvs/checkout.c874
-rw-r--r--gnu/usr.bin/cvs/cvs/classify.c504
-rw-r--r--gnu/usr.bin/cvs/cvs/client.c3542
-rw-r--r--gnu/usr.bin/cvs/cvs/client.h163
-rw-r--r--gnu/usr.bin/cvs/cvs/commit.c1834
-rw-r--r--gnu/usr.bin/cvs/cvs/convert.sh28
-rw-r--r--gnu/usr.bin/cvs/cvs/create_adm.c144
-rw-r--r--gnu/usr.bin/cvs/cvs/cvs.12185
-rw-r--r--gnu/usr.bin/cvs/cvs/cvs.5367
-rw-r--r--gnu/usr.bin/cvs/cvs/cvs.h570
-rw-r--r--gnu/usr.bin/cvs/cvs/cvsrc.c151
-rw-r--r--gnu/usr.bin/cvs/cvs/diff.c633
-rw-r--r--gnu/usr.bin/cvs/cvs/entries.c555
-rw-r--r--gnu/usr.bin/cvs/cvs/expand_path.c139
-rw-r--r--gnu/usr.bin/cvs/cvs/find_names.c275
-rw-r--r--gnu/usr.bin/cvs/cvs/history.c1489
-rw-r--r--gnu/usr.bin/cvs/cvs/ignore.c286
-rw-r--r--gnu/usr.bin/cvs/cvs/import.c1181
-rw-r--r--gnu/usr.bin/cvs/cvs/lock.c608
-rw-r--r--gnu/usr.bin/cvs/cvs/log.c178
-rw-r--r--gnu/usr.bin/cvs/cvs/login.c287
-rw-r--r--gnu/usr.bin/cvs/cvs/logmsg.c486
-rw-r--r--gnu/usr.bin/cvs/cvs/main.c769
-rw-r--r--gnu/usr.bin/cvs/cvs/modules.c884
-rw-r--r--gnu/usr.bin/cvs/cvs/no_diff.c135
-rw-r--r--gnu/usr.bin/cvs/cvs/options.h286
-rw-r--r--gnu/usr.bin/cvs/cvs/parseinfo.c171
-rw-r--r--gnu/usr.bin/cvs/cvs/patch.c615
-rw-r--r--gnu/usr.bin/cvs/cvs/patchlevel.h1
-rw-r--r--gnu/usr.bin/cvs/cvs/rcs.c1726
-rw-r--r--gnu/usr.bin/cvs/cvs/rcs.h107
-rw-r--r--gnu/usr.bin/cvs/cvs/rcscmds.c102
-rw-r--r--gnu/usr.bin/cvs/cvs/recurse.c646
-rw-r--r--gnu/usr.bin/cvs/cvs/release.c259
-rw-r--r--gnu/usr.bin/cvs/cvs/remove.c213
-rw-r--r--gnu/usr.bin/cvs/cvs/repos.c147
-rw-r--r--gnu/usr.bin/cvs/cvs/root.c182
-rw-r--r--gnu/usr.bin/cvs/cvs/rtag.c692
-rw-r--r--gnu/usr.bin/cvs/cvs/sanity.sh1674
-rw-r--r--gnu/usr.bin/cvs/cvs/server.c3992
-rw-r--r--gnu/usr.bin/cvs/cvs/server.h136
-rw-r--r--gnu/usr.bin/cvs/cvs/status.c282
-rw-r--r--gnu/usr.bin/cvs/cvs/tag.c582
-rw-r--r--gnu/usr.bin/cvs/cvs/update.c1908
-rw-r--r--gnu/usr.bin/cvs/cvs/update.h9
-rw-r--r--gnu/usr.bin/cvs/cvs/vers_ts.c326
-rw-r--r--gnu/usr.bin/cvs/cvs/wrapper.c371
-rw-r--r--gnu/usr.bin/cvs/cvsbug/Makefile25
-rw-r--r--gnu/usr.bin/cvs/cvsbug/cvsbug.8269
-rw-r--r--gnu/usr.bin/cvs/cvsbug/cvsbug.sh528
-rw-r--r--gnu/usr.bin/cvs/cvsinit/Makefile27
-rw-r--r--gnu/usr.bin/cvs/cvsinit/cvsinit.8142
-rw-r--r--gnu/usr.bin/cvs/cvsinit/cvsinit.sh162
-rw-r--r--gnu/usr.bin/cvs/doc/Makefile5
-rw-r--r--gnu/usr.bin/cvs/doc/cvs-paper.ms1073
-rw-r--r--gnu/usr.bin/cvs/doc/cvs.texinfo6931
-rw-r--r--gnu/usr.bin/cvs/doc/cvsclient.texi673
-rw-r--r--gnu/usr.bin/cvs/examples/Makefile18
-rw-r--r--gnu/usr.bin/cvs/examples/checkoutlist20
-rw-r--r--gnu/usr.bin/cvs/examples/commitinfo27
-rw-r--r--gnu/usr.bin/cvs/examples/cvswrappers29
-rw-r--r--gnu/usr.bin/cvs/examples/editinfo32
-rw-r--r--gnu/usr.bin/cvs/examples/loginfo39
-rw-r--r--gnu/usr.bin/cvs/examples/modules581
-rw-r--r--gnu/usr.bin/cvs/examples/rcsinfo18
-rw-r--r--gnu/usr.bin/cvs/examples/rcstemplate7
-rw-r--r--gnu/usr.bin/cvs/examples/taginfo25
-rw-r--r--gnu/usr.bin/cvs/examples/unwrap21
-rw-r--r--gnu/usr.bin/cvs/examples/wrap21
-rw-r--r--gnu/usr.bin/cvs/lib/ChangeLog335
-rw-r--r--gnu/usr.bin/cvs/lib/Makefile17
-rw-r--r--gnu/usr.bin/cvs/lib/argmatch.c89
-rw-r--r--gnu/usr.bin/cvs/lib/config.h233
-rw-r--r--gnu/usr.bin/cvs/lib/config.h.proto233
-rw-r--r--gnu/usr.bin/cvs/lib/error.c188
-rw-r--r--gnu/usr.bin/cvs/lib/error.h47
-rw-r--r--gnu/usr.bin/cvs/lib/filesubr.c640
-rw-r--r--gnu/usr.bin/cvs/lib/getdate.y996
-rw-r--r--gnu/usr.bin/cvs/lib/getline.c126
-rw-r--r--gnu/usr.bin/cvs/lib/getline.h15
-rw-r--r--gnu/usr.bin/cvs/lib/getopt.c763
-rw-r--r--gnu/usr.bin/cvs/lib/getopt.h131
-rw-r--r--gnu/usr.bin/cvs/lib/getopt1.c187
-rw-r--r--gnu/usr.bin/cvs/lib/hash.c400
-rw-r--r--gnu/usr.bin/cvs/lib/hash.h55
-rw-r--r--gnu/usr.bin/cvs/lib/myndbm.c213
-rw-r--r--gnu/usr.bin/cvs/lib/myndbm.h36
-rw-r--r--gnu/usr.bin/cvs/lib/run.c533
-rw-r--r--gnu/usr.bin/cvs/lib/save-cwd.c141
-rw-r--r--gnu/usr.bin/cvs/lib/save-cwd.h20
-rw-r--r--gnu/usr.bin/cvs/lib/sighandle.c405
-rw-r--r--gnu/usr.bin/cvs/lib/strippath.c80
-rw-r--r--gnu/usr.bin/cvs/lib/stripslash.c44
-rw-r--r--gnu/usr.bin/cvs/lib/subr.c322
-rw-r--r--gnu/usr.bin/cvs/lib/system.h496
-rw-r--r--gnu/usr.bin/cvs/lib/version.c34
-rw-r--r--gnu/usr.bin/cvs/lib/wait.h32
-rw-r--r--gnu/usr.bin/cvs/lib/xgetwd.c79
-rw-r--r--gnu/usr.bin/cvs/lib/yesno.c41
-rw-r--r--gnu/usr.bin/cvs/mkmodules/Makefile10
-rw-r--r--gnu/usr.bin/cvs/mkmodules/mkmodules.165
-rw-r--r--gnu/usr.bin/cvs/mkmodules/mkmodules.c435
-rw-r--r--gnu/usr.bin/dc/COPYING339
-rw-r--r--gnu/usr.bin/dc/ChangeLog77
-rw-r--r--gnu/usr.bin/dc/Makefile8
-rw-r--r--gnu/usr.bin/dc/NEWS7
-rw-r--r--gnu/usr.bin/dc/README13
-rw-r--r--gnu/usr.bin/dc/dc.1278
-rw-r--r--gnu/usr.bin/dc/dc.c908
-rw-r--r--gnu/usr.bin/dc/decimal.c1235
-rw-r--r--gnu/usr.bin/dc/decimal.h93
-rw-r--r--gnu/usr.bin/dc/doc/Makefile3
-rw-r--r--gnu/usr.bin/dc/doc/dc.texinfo381
-rw-r--r--gnu/usr.bin/dialog/COPYING339
-rw-r--r--gnu/usr.bin/dialog/Makefile12
-rw-r--r--gnu/usr.bin/dialog/README161
-rw-r--r--gnu/usr.bin/dialog/README.lib3
-rwxr-xr-xgnu/usr.bin/dialog/TESTS/checklist33
-rwxr-xr-xgnu/usr.bin/dialog/TESTS/infobox15
-rwxr-xr-xgnu/usr.bin/dialog/TESTS/inputbox28
-rwxr-xr-xgnu/usr.bin/dialog/TESTS/menubox35
-rwxr-xr-xgnu/usr.bin/dialog/TESTS/msgbox14
-rwxr-xr-xgnu/usr.bin/dialog/TESTS/prgbox12
-rwxr-xr-xgnu/usr.bin/dialog/TESTS/radiolist33
-rwxr-xr-xgnu/usr.bin/dialog/TESTS/textbox42
-rwxr-xr-xgnu/usr.bin/dialog/TESTS/yesno23
-rw-r--r--gnu/usr.bin/dialog/dialog.1239
-rw-r--r--gnu/usr.bin/dialog/dialog.c372
-rw-r--r--gnu/usr.bin/diff/COPYING339
-rw-r--r--gnu/usr.bin/diff/Makefile12
-rw-r--r--gnu/usr.bin/diff/NEWS126
-rw-r--r--gnu/usr.bin/diff/analyze.c1084
-rw-r--r--gnu/usr.bin/diff/cmpbuf.c40
-rw-r--r--gnu/usr.bin/diff/cmpbuf.h20
-rw-r--r--gnu/usr.bin/diff/config.h118
-rw-r--r--gnu/usr.bin/diff/context.c468
-rw-r--r--gnu/usr.bin/diff/diff.1473
-rw-r--r--gnu/usr.bin/diff/diff.c1112
-rw-r--r--gnu/usr.bin/diff/diff.h340
-rw-r--r--gnu/usr.bin/diff/diff.texi3916
-rw-r--r--gnu/usr.bin/diff/diff3.c1778
-rw-r--r--gnu/usr.bin/diff/dir.c216
-rw-r--r--gnu/usr.bin/diff/doc/Makefile7
-rw-r--r--gnu/usr.bin/diff/ed.c200
-rw-r--r--gnu/usr.bin/diff/getopt.c748
-rw-r--r--gnu/usr.bin/diff/getopt.h129
-rw-r--r--gnu/usr.bin/diff/getopt1.c180
-rw-r--r--gnu/usr.bin/diff/ifdef.c428
-rw-r--r--gnu/usr.bin/diff/io.c714
-rw-r--r--gnu/usr.bin/diff/normal.c71
-rw-r--r--gnu/usr.bin/diff/sdiff.c1180
-rw-r--r--gnu/usr.bin/diff/side.c284
-rw-r--r--gnu/usr.bin/diff/system.h267
-rw-r--r--gnu/usr.bin/diff/util.c754
-rw-r--r--gnu/usr.bin/diff/version.c5
-rw-r--r--gnu/usr.bin/diff/xmalloc.c81
-rw-r--r--gnu/usr.bin/diff3/Makefile8
-rw-r--r--gnu/usr.bin/diff3/diff3.1210
-rw-r--r--gnu/usr.bin/gdb/COPYING339
-rw-r--r--gnu/usr.bin/gdb/COPYING.LIB481
-rw-r--r--gnu/usr.bin/gdb/Makefile3
-rw-r--r--gnu/usr.bin/gdb/README.FreeBSD21
-rw-r--r--gnu/usr.bin/gdb/VERSION1
-rw-r--r--gnu/usr.bin/gdb/bfd/COPYING339
-rw-r--r--gnu/usr.bin/gdb/bfd/Makefile26
-rw-r--r--gnu/usr.bin/gdb/bfd/README.FreeBSD4
-rw-r--r--gnu/usr.bin/gdb/bfd/VERSION1
-rw-r--r--gnu/usr.bin/gdb/bfd/aout-target.h555
-rw-r--r--gnu/usr.bin/gdb/bfd/aout32.c23
-rw-r--r--gnu/usr.bin/gdb/bfd/aoutx.h4994
-rw-r--r--gnu/usr.bin/gdb/bfd/archive.c2016
-rw-r--r--gnu/usr.bin/gdb/bfd/archures.c745
-rw-r--r--gnu/usr.bin/gdb/bfd/bfd.c825
-rw-r--r--gnu/usr.bin/gdb/bfd/bfd.h2151
-rw-r--r--gnu/usr.bin/gdb/bfd/cache.c343
-rw-r--r--gnu/usr.bin/gdb/bfd/coff-i386.c354
-rw-r--r--gnu/usr.bin/gdb/bfd/coffcode.h2544
-rw-r--r--gnu/usr.bin/gdb/bfd/coffgen.c1693
-rw-r--r--gnu/usr.bin/gdb/bfd/coffswap.h741
-rw-r--r--gnu/usr.bin/gdb/bfd/core.c106
-rw-r--r--gnu/usr.bin/gdb/bfd/cpu-i386.c44
-rw-r--r--gnu/usr.bin/gdb/bfd/ctor.c155
-rw-r--r--gnu/usr.bin/gdb/bfd/ecoff.c4953
-rw-r--r--gnu/usr.bin/gdb/bfd/ecofflink.c1616
-rw-r--r--gnu/usr.bin/gdb/bfd/elf.c397
-rw-r--r--gnu/usr.bin/gdb/bfd/elf32-i386.c931
-rw-r--r--gnu/usr.bin/gdb/bfd/elf32-target.h358
-rw-r--r--gnu/usr.bin/gdb/bfd/elf32.c23
-rw-r--r--gnu/usr.bin/gdb/bfd/elfcode.h6351
-rw-r--r--gnu/usr.bin/gdb/bfd/format.c318
-rw-r--r--gnu/usr.bin/gdb/bfd/freebsd386.c113
-rw-r--r--gnu/usr.bin/gdb/bfd/genlink.h106
-rw-r--r--gnu/usr.bin/gdb/bfd/hash.c470
-rw-r--r--gnu/usr.bin/gdb/bfd/i386aout.c68
-rw-r--r--gnu/usr.bin/gdb/bfd/init.c79
-rw-r--r--gnu/usr.bin/gdb/bfd/libaout.h578
-rw-r--r--gnu/usr.bin/gdb/bfd/libbfd.c880
-rw-r--r--gnu/usr.bin/gdb/bfd/libbfd.h488
-rw-r--r--gnu/usr.bin/gdb/bfd/libcoff.h369
-rw-r--r--gnu/usr.bin/gdb/bfd/libecoff.h297
-rw-r--r--gnu/usr.bin/gdb/bfd/libelf.h633
-rw-r--r--gnu/usr.bin/gdb/bfd/linker.c2442
-rw-r--r--gnu/usr.bin/gdb/bfd/opncls.c548
-rw-r--r--gnu/usr.bin/gdb/bfd/reloc.c1635
-rw-r--r--gnu/usr.bin/gdb/bfd/section.c969
-rw-r--r--gnu/usr.bin/gdb/bfd/srec.c1073
-rw-r--r--gnu/usr.bin/gdb/bfd/stab-syms.c64
-rw-r--r--gnu/usr.bin/gdb/bfd/syms.c557
-rw-r--r--gnu/usr.bin/gdb/bfd/sysdep.h47
-rw-r--r--gnu/usr.bin/gdb/bfd/targets.c770
-rw-r--r--gnu/usr.bin/gdb/bfd/trad-core.c340
-rw-r--r--gnu/usr.bin/gdb/doc/GDBvn.texi1
-rw-r--r--gnu/usr.bin/gdb/doc/Makefile4
-rw-r--r--gnu/usr.bin/gdb/doc/all-cfg.texi117
-rw-r--r--gnu/usr.bin/gdb/doc/annotate.texi708
-rw-r--r--gnu/usr.bin/gdb/doc/gdb-cfg.texi117
-rw-r--r--gnu/usr.bin/gdb/doc/gdb.texinfo8921
-rw-r--r--gnu/usr.bin/gdb/doc/gdbint.texinfo2669
-rw-r--r--gnu/usr.bin/gdb/doc/h8-cfg.texi47
-rw-r--r--gnu/usr.bin/gdb/doc/inc-hist.texi155
-rw-r--r--gnu/usr.bin/gdb/doc/remote.texi1424
-rw-r--r--gnu/usr.bin/gdb/doc/stabs.texinfo4035
-rw-r--r--gnu/usr.bin/gdb/gdb/COPYING339
-rw-r--r--gnu/usr.bin/gdb/gdb/Makefile75
-rw-r--r--gnu/usr.bin/gdb/gdb/annotate.c521
-rw-r--r--gnu/usr.bin/gdb/gdb/annotate.h95
-rw-r--r--gnu/usr.bin/gdb/gdb/ansidecl.h141
-rw-r--r--gnu/usr.bin/gdb/gdb/aout/aout64.h473
-rw-r--r--gnu/usr.bin/gdb/gdb/aout/ar.h36
-rw-r--r--gnu/usr.bin/gdb/gdb/aout/encap.h135
-rw-r--r--gnu/usr.bin/gdb/gdb/aout/host.h22
-rw-r--r--gnu/usr.bin/gdb/gdb/aout/ranlib.h62
-rw-r--r--gnu/usr.bin/gdb/gdb/aout/reloc.h66
-rw-r--r--gnu/usr.bin/gdb/gdb/aout/stab.def264
-rw-r--r--gnu/usr.bin/gdb/gdb/aout/stab_gnu.h36
-rw-r--r--gnu/usr.bin/gdb/gdb/bfdlink.h411
-rw-r--r--gnu/usr.bin/gdb/gdb/blockframe.c866
-rw-r--r--gnu/usr.bin/gdb/gdb/breakpoint.c4052
-rw-r--r--gnu/usr.bin/gdb/gdb/breakpoint.h419
-rw-r--r--gnu/usr.bin/gdb/gdb/buildsym.c964
-rw-r--r--gnu/usr.bin/gdb/gdb/buildsym.h259
-rw-r--r--gnu/usr.bin/gdb/gdb/c-exp.y1601
-rw-r--r--gnu/usr.bin/gdb/gdb/c-lang.c469
-rw-r--r--gnu/usr.bin/gdb/gdb/c-lang.h38
-rw-r--r--gnu/usr.bin/gdb/gdb/c-typeprint.c795
-rw-r--r--gnu/usr.bin/gdb/gdb/c-valprint.c513
-rw-r--r--gnu/usr.bin/gdb/gdb/call-cmds.h28
-rw-r--r--gnu/usr.bin/gdb/gdb/ch-exp.y1997
-rw-r--r--gnu/usr.bin/gdb/gdb/ch-lang.c355
-rw-r--r--gnu/usr.bin/gdb/gdb/ch-lang.h44
-rw-r--r--gnu/usr.bin/gdb/gdb/ch-typeprint.c315
-rw-r--r--gnu/usr.bin/gdb/gdb/ch-valprint.c581
-rw-r--r--gnu/usr.bin/gdb/gdb/coff/ecoff.h369
-rw-r--r--gnu/usr.bin/gdb/gdb/coff/i386.h221
-rw-r--r--gnu/usr.bin/gdb/gdb/coff/internal.h542
-rw-r--r--gnu/usr.bin/gdb/gdb/coff/sym.h477
-rw-r--r--gnu/usr.bin/gdb/gdb/coff/symconst.h176
-rw-r--r--gnu/usr.bin/gdb/gdb/coffread.c2101
-rw-r--r--gnu/usr.bin/gdb/gdb/command.c1331
-rw-r--r--gnu/usr.bin/gdb/gdb/command.h246
-rw-r--r--gnu/usr.bin/gdb/gdb/compat_que.c63
-rw-r--r--gnu/usr.bin/gdb/gdb/complaints.c158
-rw-r--r--gnu/usr.bin/gdb/gdb/complaints.h46
-rw-r--r--gnu/usr.bin/gdb/gdb/copying.c327
-rw-r--r--gnu/usr.bin/gdb/gdb/core.c339
-rw-r--r--gnu/usr.bin/gdb/gdb/coredep.c125
-rw-r--r--gnu/usr.bin/gdb/gdb/corelow.c333
-rw-r--r--gnu/usr.bin/gdb/gdb/cp-valprint.c512
-rw-r--r--gnu/usr.bin/gdb/gdb/dbxread.c2462
-rw-r--r--gnu/usr.bin/gdb/gdb/dcache.c236
-rw-r--r--gnu/usr.bin/gdb/gdb/dcache.h83
-rw-r--r--gnu/usr.bin/gdb/gdb/defs.h947
-rw-r--r--gnu/usr.bin/gdb/gdb/demangle.c181
-rw-r--r--gnu/usr.bin/gdb/gdb/demangle.h80
-rw-r--r--gnu/usr.bin/gdb/gdb/dis-asm.h179
-rw-r--r--gnu/usr.bin/gdb/gdb/dis-buf.c70
-rw-r--r--gnu/usr.bin/gdb/gdb/disassemble.c148
-rw-r--r--gnu/usr.bin/gdb/gdb/dwarfread.c3876
-rw-r--r--gnu/usr.bin/gdb/gdb/elf/common.h227
-rw-r--r--gnu/usr.bin/gdb/gdb/elf/dwarf.h314
-rw-r--r--gnu/usr.bin/gdb/gdb/elf/external.h190
-rw-r--r--gnu/usr.bin/gdb/gdb/elf/internal.h174
-rw-r--r--gnu/usr.bin/gdb/gdb/elfread.c805
-rw-r--r--gnu/usr.bin/gdb/gdb/environ.c194
-rw-r--r--gnu/usr.bin/gdb/gdb/environ.h58
-rw-r--r--gnu/usr.bin/gdb/gdb/eval.c1226
-rw-r--r--gnu/usr.bin/gdb/gdb/exec.c506
-rw-r--r--gnu/usr.bin/gdb/gdb/expprint.c624
-rw-r--r--gnu/usr.bin/gdb/gdb/expression.h316
-rw-r--r--gnu/usr.bin/gdb/gdb/findvar.c1242
-rw-r--r--gnu/usr.bin/gdb/gdb/floatformat.h87
-rw-r--r--gnu/usr.bin/gdb/gdb/fopen-bin.h27
-rw-r--r--gnu/usr.bin/gdb/gdb/fopen-same.h27
-rw-r--r--gnu/usr.bin/gdb/gdb/fork-child.c300
-rw-r--r--gnu/usr.bin/gdb/gdb/frame.h240
-rw-r--r--gnu/usr.bin/gdb/gdb/freebsd-nat.c619
-rw-r--r--gnu/usr.bin/gdb/gdb/gdb-stabs.h76
-rw-r--r--gnu/usr.bin/gdb/gdb/gdb.1390
-rw-r--r--gnu/usr.bin/gdb/gdb/gdbcmd.h101
-rw-r--r--gnu/usr.bin/gdb/gdb/gdbcore.h139
-rw-r--r--gnu/usr.bin/gdb/gdb/gdbm.h91
-rw-r--r--gnu/usr.bin/gdb/gdb/gdbtypes.c1581
-rw-r--r--gnu/usr.bin/gdb/gdb/gdbtypes.h735
-rw-r--r--gnu/usr.bin/gdb/gdb/getopt.h129
-rw-r--r--gnu/usr.bin/gdb/gdb/i386-dis.c1959
-rw-r--r--gnu/usr.bin/gdb/gdb/i386-pinsn.c37
-rw-r--r--gnu/usr.bin/gdb/gdb/i386-tdep.c668
-rw-r--r--gnu/usr.bin/gdb/gdb/ieee.h132
-rw-r--r--gnu/usr.bin/gdb/gdb/infcmd.c1384
-rw-r--r--gnu/usr.bin/gdb/gdb/inferior.h420
-rw-r--r--gnu/usr.bin/gdb/gdb/inflow.c711
-rw-r--r--gnu/usr.bin/gdb/gdb/infptrace.c508
-rw-r--r--gnu/usr.bin/gdb/gdb/infrun.c2037
-rw-r--r--gnu/usr.bin/gdb/gdb/inftarg.c328
-rw-r--r--gnu/usr.bin/gdb/gdb/init.c54
-rw-r--r--gnu/usr.bin/gdb/gdb/kcorelow.c363
-rw-r--r--gnu/usr.bin/gdb/gdb/language.c1311
-rw-r--r--gnu/usr.bin/gdb/gdb/language.h413
-rw-r--r--gnu/usr.bin/gdb/gdb/libiberty.h107
-rw-r--r--gnu/usr.bin/gdb/gdb/m2-exp.y1169
-rw-r--r--gnu/usr.bin/gdb/gdb/m2-lang.c447
-rw-r--r--gnu/usr.bin/gdb/gdb/m2-lang.h31
-rw-r--r--gnu/usr.bin/gdb/gdb/m2-typeprint.c49
-rw-r--r--gnu/usr.bin/gdb/gdb/m2-valprint.c45
-rw-r--r--gnu/usr.bin/gdb/gdb/main.c571
-rw-r--r--gnu/usr.bin/gdb/gdb/maint.c295
-rw-r--r--gnu/usr.bin/gdb/gdb/mdebugread.c4053
-rw-r--r--gnu/usr.bin/gdb/gdb/mem-break.c104
-rw-r--r--gnu/usr.bin/gdb/gdb/minsyms.c648
-rw-r--r--gnu/usr.bin/gdb/gdb/mipsread.c457
-rw-r--r--gnu/usr.bin/gdb/gdb/nlmread.c308
-rw-r--r--gnu/usr.bin/gdb/gdb/nm.h100
-rw-r--r--gnu/usr.bin/gdb/gdb/objfiles.c868
-rw-r--r--gnu/usr.bin/gdb/gdb/objfiles.h451
-rw-r--r--gnu/usr.bin/gdb/gdb/obstack.h513
-rw-r--r--gnu/usr.bin/gdb/gdb/parse.c890
-rw-r--r--gnu/usr.bin/gdb/gdb/parser-defs.h186
-rw-r--r--gnu/usr.bin/gdb/gdb/partial-stab.h679
-rw-r--r--gnu/usr.bin/gdb/gdb/printcmd.c2220
-rw-r--r--gnu/usr.bin/gdb/gdb/remote-utils.c704
-rw-r--r--gnu/usr.bin/gdb/gdb/remote-utils.h142
-rw-r--r--gnu/usr.bin/gdb/gdb/remote.c1470
-rw-r--r--gnu/usr.bin/gdb/gdb/ser-unix.c684
-rw-r--r--gnu/usr.bin/gdb/gdb/serial.c265
-rw-r--r--gnu/usr.bin/gdb/gdb/serial.h158
-rw-r--r--gnu/usr.bin/gdb/gdb/signals.h27
-rw-r--r--gnu/usr.bin/gdb/gdb/solib.c1549
-rw-r--r--gnu/usr.bin/gdb/gdb/solib.h56
-rw-r--r--gnu/usr.bin/gdb/gdb/source.c1415
-rw-r--r--gnu/usr.bin/gdb/gdb/stabsread.c3948
-rw-r--r--gnu/usr.bin/gdb/gdb/stabsread.h212
-rw-r--r--gnu/usr.bin/gdb/gdb/stack.c1482
-rw-r--r--gnu/usr.bin/gdb/gdb/symfile.c1684
-rw-r--r--gnu/usr.bin/gdb/gdb/symfile.h250
-rw-r--r--gnu/usr.bin/gdb/gdb/symmisc.c988
-rw-r--r--gnu/usr.bin/gdb/gdb/symtab.c3251
-rw-r--r--gnu/usr.bin/gdb/gdb/symtab.h1176
-rw-r--r--gnu/usr.bin/gdb/gdb/target.c1316
-rw-r--r--gnu/usr.bin/gdb/gdb/target.h649
-rw-r--r--gnu/usr.bin/gdb/gdb/terminal.h62
-rw-r--r--gnu/usr.bin/gdb/gdb/thread.c371
-rw-r--r--gnu/usr.bin/gdb/gdb/thread.h36
-rw-r--r--gnu/usr.bin/gdb/gdb/tm-i386v.h296
-rw-r--r--gnu/usr.bin/gdb/gdb/tm.h90
-rw-r--r--gnu/usr.bin/gdb/gdb/top.c2494
-rw-r--r--gnu/usr.bin/gdb/gdb/top.h48
-rw-r--r--gnu/usr.bin/gdb/gdb/typeprint.c297
-rw-r--r--gnu/usr.bin/gdb/gdb/typeprint.h21
-rw-r--r--gnu/usr.bin/gdb/gdb/utils.c1790
-rw-r--r--gnu/usr.bin/gdb/gdb/valarith.c1068
-rw-r--r--gnu/usr.bin/gdb/gdb/valops.c1898
-rw-r--r--gnu/usr.bin/gdb/gdb/valprint.c1087
-rw-r--r--gnu/usr.bin/gdb/gdb/valprint.h44
-rw-r--r--gnu/usr.bin/gdb/gdb/value.h482
-rw-r--r--gnu/usr.bin/gdb/gdb/values.c1508
-rw-r--r--gnu/usr.bin/gdb/gdb/version.c3
-rw-r--r--gnu/usr.bin/gdb/gdb/wait.h38
-rw-r--r--gnu/usr.bin/gdb/gdb/xm.h29
-rw-r--r--gnu/usr.bin/gdb/libiberty/COPYING.LIB481
-rw-r--r--gnu/usr.bin/gdb/libiberty/Makefile13
-rw-r--r--gnu/usr.bin/gdb/libiberty/README.FreeBSD4
-rw-r--r--gnu/usr.bin/gdb/libiberty/alloca-conf.h11
-rw-r--r--gnu/usr.bin/gdb/libiberty/argv.c344
-rw-r--r--gnu/usr.bin/gdb/libiberty/basename.c59
-rw-r--r--gnu/usr.bin/gdb/libiberty/concat.c167
-rw-r--r--gnu/usr.bin/gdb/libiberty/config.h1
-rw-r--r--gnu/usr.bin/gdb/libiberty/cplus-dem.c2876
-rw-r--r--gnu/usr.bin/gdb/libiberty/fdmatch.c73
-rw-r--r--gnu/usr.bin/gdb/libiberty/getopt.c747
-rw-r--r--gnu/usr.bin/gdb/libiberty/getopt1.c187
-rw-r--r--gnu/usr.bin/gdb/libiberty/ieee-float.c150
-rw-r--r--gnu/usr.bin/gdb/libiberty/ieee-float.h65
-rw-r--r--gnu/usr.bin/gdb/libiberty/obstack.c493
-rw-r--r--gnu/usr.bin/gdb/libiberty/sigsetmask.c44
-rw-r--r--gnu/usr.bin/gdb/libiberty/spaces.c71
-rw-r--r--gnu/usr.bin/gdb/libiberty/strerror.c823
-rw-r--r--gnu/usr.bin/gdb/libiberty/strsignal.c643
-rw-r--r--gnu/usr.bin/gdb/libiberty/vasprintf.c139
-rw-r--r--gnu/usr.bin/gdb/libiberty/xmalloc.c85
-rw-r--r--gnu/usr.bin/gdb/mmalloc/COPYING.LIB481
-rw-r--r--gnu/usr.bin/gdb/mmalloc/Makefile10
-rw-r--r--gnu/usr.bin/gdb/mmalloc/README.FreeBSD4
-rw-r--r--gnu/usr.bin/gdb/mmalloc/attach.c218
-rw-r--r--gnu/usr.bin/gdb/mmalloc/detach.c71
-rw-r--r--gnu/usr.bin/gdb/mmalloc/keys.c66
-rw-r--r--gnu/usr.bin/gdb/mmalloc/mcalloc.c53
-rw-r--r--gnu/usr.bin/gdb/mmalloc/mfree.c247
-rw-r--r--gnu/usr.bin/gdb/mmalloc/mmalloc.c334
-rw-r--r--gnu/usr.bin/gdb/mmalloc/mmalloc.h390
-rw-r--r--gnu/usr.bin/gdb/mmalloc/mmalloc.texi258
-rw-r--r--gnu/usr.bin/gdb/mmalloc/mmap-sup.c144
-rw-r--r--gnu/usr.bin/gdb/mmalloc/mmcheck.c196
-rw-r--r--gnu/usr.bin/gdb/mmalloc/mmemalign.c64
-rw-r--r--gnu/usr.bin/gdb/mmalloc/mmstats.c46
-rw-r--r--gnu/usr.bin/gdb/mmalloc/mmtrace.c166
-rw-r--r--gnu/usr.bin/gdb/mmalloc/mrealloc.c160
-rw-r--r--gnu/usr.bin/gdb/mmalloc/mvalloc.c40
-rw-r--r--gnu/usr.bin/gdb/mmalloc/sbrk-sup.c96
-rw-r--r--gnu/usr.bin/grep/AUTHORS29
-rw-r--r--gnu/usr.bin/grep/COPYING339
-rw-r--r--gnu/usr.bin/grep/Makefile17
-rw-r--r--gnu/usr.bin/grep/NEWS35
-rw-r--r--gnu/usr.bin/grep/PROJECTS15
-rw-r--r--gnu/usr.bin/grep/README28
-rw-r--r--gnu/usr.bin/grep/dfa.c2511
-rw-r--r--gnu/usr.bin/grep/dfa.h360
-rw-r--r--gnu/usr.bin/grep/getopt.c731
-rw-r--r--gnu/usr.bin/grep/getopt.h129
-rw-r--r--gnu/usr.bin/grep/getpagesize.h42
-rw-r--r--gnu/usr.bin/grep/grep.1399
-rw-r--r--gnu/usr.bin/grep/grep.c1049
-rw-r--r--gnu/usr.bin/grep/grep.h53
-rw-r--r--gnu/usr.bin/grep/kwset.c805
-rw-r--r--gnu/usr.bin/grep/kwset.h69
-rw-r--r--gnu/usr.bin/grep/obstack.c454
-rw-r--r--gnu/usr.bin/grep/obstack.h484
-rw-r--r--gnu/usr.bin/grep/search.c481
-rw-r--r--gnu/usr.bin/grep/tests/check.sh24
-rw-r--r--gnu/usr.bin/grep/tests/khadafy.lines32
-rw-r--r--gnu/usr.bin/grep/tests/khadafy.regexp1
-rw-r--r--gnu/usr.bin/grep/tests/scriptgen.awk10
-rw-r--r--gnu/usr.bin/grep/tests/spencer.tests122
-rw-r--r--gnu/usr.bin/groff/BUG-REPORT57
-rw-r--r--gnu/usr.bin/groff/COPYING339
-rw-r--r--gnu/usr.bin/groff/ChangeLog5351
-rw-r--r--gnu/usr.bin/groff/INSTALL122
-rw-r--r--gnu/usr.bin/groff/Makefile13
-rw-r--r--gnu/usr.bin/groff/Makefile.ccpg26
-rw-r--r--gnu/usr.bin/groff/Makefile.cfg131
-rw-r--r--gnu/usr.bin/groff/Makefile.comm247
-rw-r--r--gnu/usr.bin/groff/Makefile.cpg20
-rw-r--r--gnu/usr.bin/groff/Makefile.dev27
-rw-r--r--gnu/usr.bin/groff/Makefile.in387
-rw-r--r--gnu/usr.bin/groff/Makefile.init25
-rw-r--r--gnu/usr.bin/groff/Makefile.lib14
-rw-r--r--gnu/usr.bin/groff/Makefile.man4
-rw-r--r--gnu/usr.bin/groff/Makefile.sub7
-rw-r--r--gnu/usr.bin/groff/Makefile.tty53
-rw-r--r--gnu/usr.bin/groff/NEWS683
-rw-r--r--gnu/usr.bin/groff/PROBLEMS544
-rw-r--r--gnu/usr.bin/groff/PROJECTS19
-rw-r--r--gnu/usr.bin/groff/README38
-rw-r--r--gnu/usr.bin/groff/TODO26
-rw-r--r--gnu/usr.bin/groff/VERSION1
-rw-r--r--gnu/usr.bin/groff/acgroff.m4403
-rw-r--r--gnu/usr.bin/groff/addftinfo/Makefile13
-rw-r--r--gnu/usr.bin/groff/addftinfo/Makefile.dep3
-rw-r--r--gnu/usr.bin/groff/addftinfo/Makefile.sub6
-rw-r--r--gnu/usr.bin/groff/addftinfo/addftinfo.cc194
-rw-r--r--gnu/usr.bin/groff/addftinfo/addftinfo.man84
-rw-r--r--gnu/usr.bin/groff/addftinfo/guess.cc490
-rw-r--r--gnu/usr.bin/groff/addftinfo/guess.h44
-rw-r--r--gnu/usr.bin/groff/afmtodit/Makefile.sub21
-rw-r--r--gnu/usr.bin/groff/afmtodit/afmtodit.man204
-rw-r--r--gnu/usr.bin/groff/afmtodit/afmtodit.pl325
-rwxr-xr-xgnu/usr.bin/groff/configure1409
-rw-r--r--gnu/usr.bin/groff/configure.in50
-rw-r--r--gnu/usr.bin/groff/devX100-12/CB306
-rw-r--r--gnu/usr.bin/groff/devX100-12/CBI306
-rw-r--r--gnu/usr.bin/groff/devX100-12/CI306
-rw-r--r--gnu/usr.bin/groff/devX100-12/CR306
-rw-r--r--gnu/usr.bin/groff/devX100-12/DESC9
-rw-r--r--gnu/usr.bin/groff/devX100-12/HB306
-rw-r--r--gnu/usr.bin/groff/devX100-12/HBI306
-rw-r--r--gnu/usr.bin/groff/devX100-12/HI306
-rw-r--r--gnu/usr.bin/groff/devX100-12/HR306
-rw-r--r--gnu/usr.bin/groff/devX100-12/Makefile10
-rw-r--r--gnu/usr.bin/groff/devX100-12/Makefile.sub2
-rw-r--r--gnu/usr.bin/groff/devX100-12/NB306
-rw-r--r--gnu/usr.bin/groff/devX100-12/NBI306
-rw-r--r--gnu/usr.bin/groff/devX100-12/NI306
-rw-r--r--gnu/usr.bin/groff/devX100-12/NR306
-rw-r--r--gnu/usr.bin/groff/devX100-12/S226
-rw-r--r--gnu/usr.bin/groff/devX100-12/TB306
-rw-r--r--gnu/usr.bin/groff/devX100-12/TBI306
-rw-r--r--gnu/usr.bin/groff/devX100-12/TI306
-rw-r--r--gnu/usr.bin/groff/devX100-12/TR306
-rw-r--r--gnu/usr.bin/groff/devX100/CB306
-rw-r--r--gnu/usr.bin/groff/devX100/CBI306
-rw-r--r--gnu/usr.bin/groff/devX100/CI306
-rw-r--r--gnu/usr.bin/groff/devX100/CR306
-rw-r--r--gnu/usr.bin/groff/devX100/DESC9
-rw-r--r--gnu/usr.bin/groff/devX100/HB306
-rw-r--r--gnu/usr.bin/groff/devX100/HBI306
-rw-r--r--gnu/usr.bin/groff/devX100/HI306
-rw-r--r--gnu/usr.bin/groff/devX100/HR306
-rw-r--r--gnu/usr.bin/groff/devX100/Makefile10
-rw-r--r--gnu/usr.bin/groff/devX100/Makefile.sub2
-rw-r--r--gnu/usr.bin/groff/devX100/NB306
-rw-r--r--gnu/usr.bin/groff/devX100/NBI306
-rw-r--r--gnu/usr.bin/groff/devX100/NI306
-rw-r--r--gnu/usr.bin/groff/devX100/NR306
-rw-r--r--gnu/usr.bin/groff/devX100/S226
-rw-r--r--gnu/usr.bin/groff/devX100/TB306
-rw-r--r--gnu/usr.bin/groff/devX100/TBI306
-rw-r--r--gnu/usr.bin/groff/devX100/TI306
-rw-r--r--gnu/usr.bin/groff/devX100/TR306
-rw-r--r--gnu/usr.bin/groff/devX75-12/CB306
-rw-r--r--gnu/usr.bin/groff/devX75-12/CBI306
-rw-r--r--gnu/usr.bin/groff/devX75-12/CI306
-rw-r--r--gnu/usr.bin/groff/devX75-12/CR306
-rw-r--r--gnu/usr.bin/groff/devX75-12/DESC9
-rw-r--r--gnu/usr.bin/groff/devX75-12/HB306
-rw-r--r--gnu/usr.bin/groff/devX75-12/HBI306
-rw-r--r--gnu/usr.bin/groff/devX75-12/HI306
-rw-r--r--gnu/usr.bin/groff/devX75-12/HR306
-rw-r--r--gnu/usr.bin/groff/devX75-12/Makefile10
-rw-r--r--gnu/usr.bin/groff/devX75-12/Makefile.sub2
-rw-r--r--gnu/usr.bin/groff/devX75-12/NB306
-rw-r--r--gnu/usr.bin/groff/devX75-12/NBI306
-rw-r--r--gnu/usr.bin/groff/devX75-12/NI306
-rw-r--r--gnu/usr.bin/groff/devX75-12/NR306
-rw-r--r--gnu/usr.bin/groff/devX75-12/S226
-rw-r--r--gnu/usr.bin/groff/devX75-12/TB306
-rw-r--r--gnu/usr.bin/groff/devX75-12/TBI306
-rw-r--r--gnu/usr.bin/groff/devX75-12/TI306
-rw-r--r--gnu/usr.bin/groff/devX75-12/TR306
-rw-r--r--gnu/usr.bin/groff/devX75/CB306
-rw-r--r--gnu/usr.bin/groff/devX75/CBI306
-rw-r--r--gnu/usr.bin/groff/devX75/CI306
-rw-r--r--gnu/usr.bin/groff/devX75/CR306
-rw-r--r--gnu/usr.bin/groff/devX75/DESC9
-rw-r--r--gnu/usr.bin/groff/devX75/HB306
-rw-r--r--gnu/usr.bin/groff/devX75/HBI306
-rw-r--r--gnu/usr.bin/groff/devX75/HI306
-rw-r--r--gnu/usr.bin/groff/devX75/HR306
-rw-r--r--gnu/usr.bin/groff/devX75/Makefile10
-rw-r--r--gnu/usr.bin/groff/devX75/Makefile.sub2
-rw-r--r--gnu/usr.bin/groff/devX75/NB306
-rw-r--r--gnu/usr.bin/groff/devX75/NBI306
-rw-r--r--gnu/usr.bin/groff/devX75/NI306
-rw-r--r--gnu/usr.bin/groff/devX75/NR306
-rw-r--r--gnu/usr.bin/groff/devX75/S226
-rw-r--r--gnu/usr.bin/groff/devX75/TB306
-rw-r--r--gnu/usr.bin/groff/devX75/TBI306
-rw-r--r--gnu/usr.bin/groff/devX75/TI306
-rw-r--r--gnu/usr.bin/groff/devX75/TR306
-rw-r--r--gnu/usr.bin/groff/devascii/DESC.proto8
-rw-r--r--gnu/usr.bin/groff/devascii/Makefile6
-rw-r--r--gnu/usr.bin/groff/devascii/Makefile.sub31
-rw-r--r--gnu/usr.bin/groff/devascii/R.proto165
-rw-r--r--gnu/usr.bin/groff/devdvi/B347
-rw-r--r--gnu/usr.bin/groff/devdvi/BI352
-rw-r--r--gnu/usr.bin/groff/devdvi/CW158
-rw-r--r--gnu/usr.bin/groff/devdvi/DESC.in10
-rw-r--r--gnu/usr.bin/groff/devdvi/EX144
-rw-r--r--gnu/usr.bin/groff/devdvi/H302
-rw-r--r--gnu/usr.bin/groff/devdvi/HB302
-rw-r--r--gnu/usr.bin/groff/devdvi/HI303
-rw-r--r--gnu/usr.bin/groff/devdvi/I353
-rw-r--r--gnu/usr.bin/groff/devdvi/MI136
-rw-r--r--gnu/usr.bin/groff/devdvi/Makefile14
-rw-r--r--gnu/usr.bin/groff/devdvi/Makefile.sub11
-rw-r--r--gnu/usr.bin/groff/devdvi/R430
-rw-r--r--gnu/usr.bin/groff/devdvi/S152
-rw-r--r--gnu/usr.bin/groff/devdvi/SA143
-rw-r--r--gnu/usr.bin/groff/devdvi/SB132
-rwxr-xr-xgnu/usr.bin/groff/devdvi/generate/CompileFonts15
-rw-r--r--gnu/usr.bin/groff/devdvi/generate/Makefile93
-rw-r--r--gnu/usr.bin/groff/devdvi/generate/cork.map206
-rw-r--r--gnu/usr.bin/groff/devdvi/generate/msam.map127
-rw-r--r--gnu/usr.bin/groff/devdvi/generate/msbm.map121
-rw-r--r--gnu/usr.bin/groff/devdvi/generate/texb.map127
-rw-r--r--gnu/usr.bin/groff/devdvi/generate/texex.map100
-rw-r--r--gnu/usr.bin/groff/devdvi/generate/texi.map127
-rw-r--r--gnu/usr.bin/groff/devdvi/generate/texmi.map32
-rw-r--r--gnu/usr.bin/groff/devdvi/generate/texr.map127
-rw-r--r--gnu/usr.bin/groff/devdvi/generate/texsy.map100
-rw-r--r--gnu/usr.bin/groff/devdvi/generate/textt.map126
-rw-r--r--gnu/usr.bin/groff/devkoi8-r/DESC.proto8
-rw-r--r--gnu/usr.bin/groff/devkoi8-r/Makefile6
-rw-r--r--gnu/usr.bin/groff/devkoi8-r/Makefile.sub32
-rw-r--r--gnu/usr.bin/groff/devkoi8-r/R.proto239
-rw-r--r--gnu/usr.bin/groff/devlatin1/DESC.proto8
-rw-r--r--gnu/usr.bin/groff/devlatin1/Makefile6
-rw-r--r--gnu/usr.bin/groff/devlatin1/Makefile.sub32
-rw-r--r--gnu/usr.bin/groff/devlatin1/R.proto353
-rw-r--r--gnu/usr.bin/groff/devps/AB559
-rw-r--r--gnu/usr.bin/groff/devps/ABI560
-rw-r--r--gnu/usr.bin/groff/devps/AI559
-rw-r--r--gnu/usr.bin/groff/devps/AR558
-rw-r--r--gnu/usr.bin/groff/devps/BMB438
-rw-r--r--gnu/usr.bin/groff/devps/BMBI441
-rw-r--r--gnu/usr.bin/groff/devps/BMI434
-rw-r--r--gnu/usr.bin/groff/devps/BMR430
-rw-r--r--gnu/usr.bin/groff/devps/CB336
-rw-r--r--gnu/usr.bin/groff/devps/CBI337
-rw-r--r--gnu/usr.bin/groff/devps/CI337
-rw-r--r--gnu/usr.bin/groff/devps/CR336
-rw-r--r--gnu/usr.bin/groff/devps/DESC.in11
-rw-r--r--gnu/usr.bin/groff/devps/HB546
-rw-r--r--gnu/usr.bin/groff/devps/HBI547
-rw-r--r--gnu/usr.bin/groff/devps/HI617
-rw-r--r--gnu/usr.bin/groff/devps/HNB546
-rw-r--r--gnu/usr.bin/groff/devps/HNBI547
-rw-r--r--gnu/usr.bin/groff/devps/HNI617
-rw-r--r--gnu/usr.bin/groff/devps/HNR616
-rw-r--r--gnu/usr.bin/groff/devps/HR616
-rw-r--r--gnu/usr.bin/groff/devps/Makefile37
-rw-r--r--gnu/usr.bin/groff/devps/Makefile.sub35
-rw-r--r--gnu/usr.bin/groff/devps/NB446
-rw-r--r--gnu/usr.bin/groff/devps/NBI447
-rw-r--r--gnu/usr.bin/groff/devps/NI447
-rw-r--r--gnu/usr.bin/groff/devps/NR447
-rw-r--r--gnu/usr.bin/groff/devps/PB449
-rw-r--r--gnu/usr.bin/groff/devps/PBI451
-rw-r--r--gnu/usr.bin/groff/devps/PI453
-rw-r--r--gnu/usr.bin/groff/devps/PR456
-rw-r--r--gnu/usr.bin/groff/devps/S227
-rw-r--r--gnu/usr.bin/groff/devps/SS194
-rw-r--r--gnu/usr.bin/groff/devps/TB533
-rw-r--r--gnu/usr.bin/groff/devps/TBI515
-rw-r--r--gnu/usr.bin/groff/devps/TI528
-rw-r--r--gnu/usr.bin/groff/devps/TR519
-rw-r--r--gnu/usr.bin/groff/devps/ZCMI477
-rw-r--r--gnu/usr.bin/groff/devps/ZD193
-rw-r--r--gnu/usr.bin/groff/devps/ZDR193
-rw-r--r--gnu/usr.bin/groff/devps/download5
-rw-r--r--gnu/usr.bin/groff/devps/generate/Makefile224
-rwxr-xr-xgnu/usr.bin/groff/devps/generate/afmname44
-rw-r--r--gnu/usr.bin/groff/devps/generate/dingbatsmap2
-rw-r--r--gnu/usr.bin/groff/devps/generate/dingbatsrmap1
-rw-r--r--gnu/usr.bin/groff/devps/generate/lgreekmap28
-rw-r--r--gnu/usr.bin/groff/devps/generate/symbol.sed33
-rw-r--r--gnu/usr.bin/groff/devps/generate/symbolchars60
-rw-r--r--gnu/usr.bin/groff/devps/generate/symbolsl.afm203
-rw-r--r--gnu/usr.bin/groff/devps/generate/textmap449
-rw-r--r--gnu/usr.bin/groff/devps/prologue.ps221
-rw-r--r--gnu/usr.bin/groff/devps/psstrip.sed6
-rw-r--r--gnu/usr.bin/groff/devps/symbol.afm215
-rw-r--r--gnu/usr.bin/groff/devps/symbolmap508
-rw-r--r--gnu/usr.bin/groff/devps/symbolsl.ps41
-rw-r--r--gnu/usr.bin/groff/devps/text.enc231
-rw-r--r--gnu/usr.bin/groff/devps/zapfdr.afm222
-rw-r--r--gnu/usr.bin/groff/devps/zapfdr.ps225
-rw-r--r--gnu/usr.bin/groff/doc/Makefile55
-rw-r--r--gnu/usr.bin/groff/doc/meintro.me2246
-rw-r--r--gnu/usr.bin/groff/doc/meref.me2194
-rw-r--r--gnu/usr.bin/groff/eqn/Makefile22
-rw-r--r--gnu/usr.bin/groff/eqn/Makefile.dep31
-rw-r--r--gnu/usr.bin/groff/eqn/Makefile.sub27
-rw-r--r--gnu/usr.bin/groff/eqn/TODO41
-rw-r--r--gnu/usr.bin/groff/eqn/box.cc611
-rw-r--r--gnu/usr.bin/groff/eqn/box.h277
-rw-r--r--gnu/usr.bin/groff/eqn/delim.cc380
-rw-r--r--gnu/usr.bin/groff/eqn/eqn.h51
-rw-r--r--gnu/usr.bin/groff/eqn/eqn.man862
-rw-r--r--gnu/usr.bin/groff/eqn/eqn.y331
-rw-r--r--gnu/usr.bin/groff/eqn/lex.cc1160
-rw-r--r--gnu/usr.bin/groff/eqn/limit.cc195
-rw-r--r--gnu/usr.bin/groff/eqn/list.cc236
-rw-r--r--gnu/usr.bin/groff/eqn/main.cc352
-rw-r--r--gnu/usr.bin/groff/eqn/mark.cc121
-rw-r--r--gnu/usr.bin/groff/eqn/neqn.sh5
-rw-r--r--gnu/usr.bin/groff/eqn/other.cc601
-rw-r--r--gnu/usr.bin/groff/eqn/over.cc196
-rw-r--r--gnu/usr.bin/groff/eqn/pbox.h141
-rw-r--r--gnu/usr.bin/groff/eqn/pile.cc293
-rw-r--r--gnu/usr.bin/groff/eqn/script.cc221
-rw-r--r--gnu/usr.bin/groff/eqn/special.cc115
-rw-r--r--gnu/usr.bin/groff/eqn/sqrt.cc179
-rw-r--r--gnu/usr.bin/groff/eqn/text.cc528
-rw-r--r--gnu/usr.bin/groff/font/Makefile.dev27
-rw-r--r--gnu/usr.bin/groff/font/Makefile.tty53
-rw-r--r--gnu/usr.bin/groff/gendef.sh24
-rw-r--r--gnu/usr.bin/groff/grodvi/Makefile13
-rw-r--r--gnu/usr.bin/groff/grodvi/Makefile.dep2
-rw-r--r--gnu/usr.bin/groff/grodvi/Makefile.sub6
-rw-r--r--gnu/usr.bin/groff/grodvi/dvi.cc895
-rw-r--r--gnu/usr.bin/groff/grodvi/grodvi.man154
-rw-r--r--gnu/usr.bin/groff/groff/Makefile13
-rw-r--r--gnu/usr.bin/groff/groff/Makefile.dep4
-rw-r--r--gnu/usr.bin/groff/groff/Makefile.sub8
-rw-r--r--gnu/usr.bin/groff/groff/groff.cc588
-rw-r--r--gnu/usr.bin/groff/groff/groff.man365
-rw-r--r--gnu/usr.bin/groff/groff/pipeline.c234
-rw-r--r--gnu/usr.bin/groff/groff/pipeline.h30
-rw-r--r--gnu/usr.bin/groff/grog/Makefile.sub22
-rw-r--r--gnu/usr.bin/groff/grog/grog.man54
-rw-r--r--gnu/usr.bin/groff/grog/grog.pl149
-rw-r--r--gnu/usr.bin/groff/grog/grog.sh78
-rw-r--r--gnu/usr.bin/groff/grops/Makefile13
-rw-r--r--gnu/usr.bin/groff/grops/Makefile.dep6
-rw-r--r--gnu/usr.bin/groff/grops/Makefile.sub7
-rw-r--r--gnu/usr.bin/groff/grops/TODO29
-rw-r--r--gnu/usr.bin/groff/grops/grops.man817
-rw-r--r--gnu/usr.bin/groff/grops/ps.cc1516
-rw-r--r--gnu/usr.bin/groff/grops/ps.h122
-rw-r--r--gnu/usr.bin/groff/grops/psfig.diff106
-rw-r--r--gnu/usr.bin/groff/grops/psrm.cc1091
-rw-r--r--gnu/usr.bin/groff/grotty/Makefile13
-rw-r--r--gnu/usr.bin/groff/grotty/Makefile.dep2
-rw-r--r--gnu/usr.bin/groff/grotty/Makefile.sub6
-rw-r--r--gnu/usr.bin/groff/grotty/TODO3
-rw-r--r--gnu/usr.bin/groff/grotty/grotty.man195
-rw-r--r--gnu/usr.bin/groff/grotty/tty.cc441
-rw-r--r--gnu/usr.bin/groff/include/Makefile.sub19
-rw-r--r--gnu/usr.bin/groff/include/assert.h39
-rw-r--r--gnu/usr.bin/groff/include/cmap.h56
-rw-r--r--gnu/usr.bin/groff/include/cset.h75
-rw-r--r--gnu/usr.bin/groff/include/defs.h9
-rw-r--r--gnu/usr.bin/groff/include/device.h21
-rw-r--r--gnu/usr.bin/groff/include/driver.h36
-rw-r--r--gnu/usr.bin/groff/include/errarg.h46
-rw-r--r--gnu/usr.bin/groff/include/error.h58
-rw-r--r--gnu/usr.bin/groff/include/font.h113
-rw-r--r--gnu/usr.bin/groff/include/index.h42
-rw-r--r--gnu/usr.bin/groff/include/lib.h125
-rw-r--r--gnu/usr.bin/groff/include/macropath.h21
-rw-r--r--gnu/usr.bin/groff/include/posix.h49
-rw-r--r--gnu/usr.bin/groff/include/printer.h66
-rw-r--r--gnu/usr.bin/groff/include/ptable.h166
-rw-r--r--gnu/usr.bin/groff/include/refid.h35
-rw-r--r--gnu/usr.bin/groff/include/search.h96
-rw-r--r--gnu/usr.bin/groff/include/searchpath.h29
-rw-r--r--gnu/usr.bin/groff/include/stringclass.h187
-rw-r--r--gnu/usr.bin/groff/include/unix.h0
-rw-r--r--gnu/usr.bin/groff/indxbib/Makefile21
-rw-r--r--gnu/usr.bin/groff/indxbib/Makefile.dep5
-rw-r--r--gnu/usr.bin/groff/indxbib/Makefile.sub24
-rw-r--r--gnu/usr.bin/groff/indxbib/dirnamemax.c49
-rw-r--r--gnu/usr.bin/groff/indxbib/eign133
-rw-r--r--gnu/usr.bin/groff/indxbib/indxbib.cc743
-rw-r--r--gnu/usr.bin/groff/indxbib/indxbib.man187
-rw-r--r--gnu/usr.bin/groff/indxbib/signal.c63
-rw-r--r--gnu/usr.bin/groff/libbib/Makefile13
-rw-r--r--gnu/usr.bin/groff/libbib/Makefile.dep12
-rw-r--r--gnu/usr.bin/groff/libbib/Makefile.sub4
-rw-r--r--gnu/usr.bin/groff/libbib/common.cc38
-rw-r--r--gnu/usr.bin/groff/libbib/index.cc618
-rw-r--r--gnu/usr.bin/groff/libbib/linear.cc484
-rw-r--r--gnu/usr.bin/groff/libbib/map.c75
-rw-r--r--gnu/usr.bin/groff/libbib/search.cc130
-rw-r--r--gnu/usr.bin/groff/libdriver/Makefile13
-rw-r--r--gnu/usr.bin/groff/libdriver/Makefile.dep6
-rw-r--r--gnu/usr.bin/groff/libdriver/Makefile.sub3
-rw-r--r--gnu/usr.bin/groff/libdriver/input.cc474
-rw-r--r--gnu/usr.bin/groff/libdriver/printer.cc240
-rw-r--r--gnu/usr.bin/groff/libgroff/Makefile23
-rw-r--r--gnu/usr.bin/groff/libgroff/Makefile.dep39
-rw-r--r--gnu/usr.bin/groff/libgroff/Makefile.sub15
-rw-r--r--gnu/usr.bin/groff/libgroff/assert.cc34
-rw-r--r--gnu/usr.bin/groff/libgroff/change_lf.cc37
-rw-r--r--gnu/usr.bin/groff/libgroff/cmap.cc62
-rw-r--r--gnu/usr.bin/groff/libgroff/cset.cc108
-rw-r--r--gnu/usr.bin/groff/libgroff/device.cc36
-rw-r--r--gnu/usr.bin/groff/libgroff/errarg.cc118
-rw-r--r--gnu/usr.bin/groff/libgroff/error.cc137
-rw-r--r--gnu/usr.bin/groff/libgroff/fatal.cc27
-rw-r--r--gnu/usr.bin/groff/libgroff/filename.cc1
-rw-r--r--gnu/usr.bin/groff/libgroff/fmod.c28
-rw-r--r--gnu/usr.bin/groff/libgroff/font.cc911
-rw-r--r--gnu/usr.bin/groff/libgroff/fontfile.cc64
-rw-r--r--gnu/usr.bin/groff/libgroff/getcwd.c38
-rw-r--r--gnu/usr.bin/groff/libgroff/iftoa.c65
-rw-r--r--gnu/usr.bin/groff/libgroff/illegal.cc22
-rw-r--r--gnu/usr.bin/groff/libgroff/itoa.c43
-rw-r--r--gnu/usr.bin/groff/libgroff/lf.cc61
-rw-r--r--gnu/usr.bin/groff/libgroff/lineno.cc1
-rw-r--r--gnu/usr.bin/groff/libgroff/macropath.cc28
-rw-r--r--gnu/usr.bin/groff/libgroff/matherr.c45
-rw-r--r--gnu/usr.bin/groff/libgroff/nametoindex.cc117
-rw-r--r--gnu/usr.bin/groff/libgroff/new.cc67
-rw-r--r--gnu/usr.bin/groff/libgroff/prime.cc26
-rw-r--r--gnu/usr.bin/groff/libgroff/progname.cc1
-rw-r--r--gnu/usr.bin/groff/libgroff/ptable.cc51
-rw-r--r--gnu/usr.bin/groff/libgroff/putenv.c96
-rw-r--r--gnu/usr.bin/groff/libgroff/searchpath.cc117
-rw-r--r--gnu/usr.bin/groff/libgroff/strerror.c37
-rw-r--r--gnu/usr.bin/groff/libgroff/string.cc310
-rw-r--r--gnu/usr.bin/groff/libgroff/strsave.cc31
-rw-r--r--gnu/usr.bin/groff/libgroff/strtol.c131
-rw-r--r--gnu/usr.bin/groff/libgroff/tmpfile.cc99
-rw-r--r--gnu/usr.bin/groff/lkbib/Makefile13
-rw-r--r--gnu/usr.bin/groff/lkbib/Makefile.dep2
-rw-r--r--gnu/usr.bin/groff/lkbib/Makefile.sub6
-rw-r--r--gnu/usr.bin/groff/lkbib/lkbib.cc122
-rw-r--r--gnu/usr.bin/groff/lkbib/lkbib.man90
-rw-r--r--gnu/usr.bin/groff/lookbib/Makefile13
-rw-r--r--gnu/usr.bin/groff/lookbib/Makefile.dep2
-rw-r--r--gnu/usr.bin/groff/lookbib/Makefile.sub7
-rw-r--r--gnu/usr.bin/groff/lookbib/lookbib.cc127
-rw-r--r--gnu/usr.bin/groff/lookbib/lookbib.man58
-rw-r--r--gnu/usr.bin/groff/man/Makefile10
-rw-r--r--gnu/usr.bin/groff/man/Makefile.sub2
-rw-r--r--gnu/usr.bin/groff/man/groff_char.man545
-rw-r--r--gnu/usr.bin/groff/man/groff_font.man351
-rw-r--r--gnu/usr.bin/groff/man/groff_out.man215
-rwxr-xr-xgnu/usr.bin/groff/mdate.sh41
-rw-r--r--gnu/usr.bin/groff/mm/ChangeLog288
-rw-r--r--gnu/usr.bin/groff/mm/Makefile36
-rw-r--r--gnu/usr.bin/groff/mm/Makefile.sub35
-rw-r--r--gnu/usr.bin/groff/mm/NOTES101
-rw-r--r--gnu/usr.bin/groff/mm/README26
-rw-r--r--gnu/usr.bin/groff/mm/groff_mm.man763
-rw-r--r--gnu/usr.bin/groff/mm/groff_mmse.man36
-rw-r--r--gnu/usr.bin/groff/mm/mm/0.MT145
-rw-r--r--gnu/usr.bin/groff/mm/mm/4.MT65
-rw-r--r--gnu/usr.bin/groff/mm/mm/5.MT33
-rw-r--r--gnu/usr.bin/groff/mm/mm/ms.cov83
-rw-r--r--gnu/usr.bin/groff/mm/mm/se_ms.cov2
-rw-r--r--gnu/usr.bin/groff/mm/tmac.m2635
-rw-r--r--gnu/usr.bin/groff/mm/tmac.mse42
-rw-r--r--gnu/usr.bin/groff/nroff/Makefile13
-rw-r--r--gnu/usr.bin/groff/nroff/Makefile.sub17
-rwxr-xr-xgnu/usr.bin/groff/nroff/conftest.sh4
-rw-r--r--gnu/usr.bin/groff/nroff/nroff.man71
-rwxr-xr-xgnu/usr.bin/groff/nroff/nroff.sh56
-rwxr-xr-xgnu/usr.bin/groff/nroff/psroff.sh2
-rw-r--r--gnu/usr.bin/groff/pfbtops/Makefile12
-rw-r--r--gnu/usr.bin/groff/pfbtops/Makefile.dep1
-rw-r--r--gnu/usr.bin/groff/pfbtops/Makefile.sub5
-rw-r--r--gnu/usr.bin/groff/pfbtops/pfbtops.c112
-rw-r--r--gnu/usr.bin/groff/pfbtops/pfbtops.man27
-rw-r--r--gnu/usr.bin/groff/pic/Makefile16
-rw-r--r--gnu/usr.bin/groff/pic/Makefile.dep22
-rw-r--r--gnu/usr.bin/groff/pic/Makefile.sub11
-rw-r--r--gnu/usr.bin/groff/pic/TODO37
-rw-r--r--gnu/usr.bin/groff/pic/common.cc497
-rw-r--r--gnu/usr.bin/groff/pic/common.h70
-rw-r--r--gnu/usr.bin/groff/pic/depend21
-rw-r--r--gnu/usr.bin/groff/pic/lex.cc1938
-rw-r--r--gnu/usr.bin/groff/pic/main.cc611
-rwxr-xr-xgnu/usr.bin/groff/pic/make-dos-dist299
-rw-r--r--gnu/usr.bin/groff/pic/object.cc1815
-rw-r--r--gnu/usr.bin/groff/pic/object.h215
-rw-r--r--gnu/usr.bin/groff/pic/output.h79
-rw-r--r--gnu/usr.bin/groff/pic/pic.h101
-rw-r--r--gnu/usr.bin/groff/pic/pic.man730
-rw-r--r--gnu/usr.bin/groff/pic/pic.y1780
-rw-r--r--gnu/usr.bin/groff/pic/position.h47
-rw-r--r--gnu/usr.bin/groff/pic/tex.cc411
-rw-r--r--gnu/usr.bin/groff/pic/text.h28
-rw-r--r--gnu/usr.bin/groff/pic/troff.cc500
-rw-r--r--gnu/usr.bin/groff/psbb/Makefile10
-rw-r--r--gnu/usr.bin/groff/psbb/Makefile.dep1
-rw-r--r--gnu/usr.bin/groff/psbb/Makefile.sub5
-rw-r--r--gnu/usr.bin/groff/psbb/psbb.c169
-rw-r--r--gnu/usr.bin/groff/psbb/psbb.man26
-rw-r--r--gnu/usr.bin/groff/refer/Makefile14
-rw-r--r--gnu/usr.bin/groff/refer/Makefile.dep17
-rw-r--r--gnu/usr.bin/groff/refer/Makefile.sub10
-rw-r--r--gnu/usr.bin/groff/refer/TODO124
-rw-r--r--gnu/usr.bin/groff/refer/command.cc807
-rw-r--r--gnu/usr.bin/groff/refer/command.h36
-rw-r--r--gnu/usr.bin/groff/refer/label.y1173
-rw-r--r--gnu/usr.bin/groff/refer/ref.cc1144
-rw-r--r--gnu/usr.bin/groff/refer/ref.h120
-rw-r--r--gnu/usr.bin/groff/refer/refer.cc1221
-rw-r--r--gnu/usr.bin/groff/refer/refer.h78
-rw-r--r--gnu/usr.bin/groff/refer/refer.man1282
-rw-r--r--gnu/usr.bin/groff/refer/token.cc374
-rw-r--r--gnu/usr.bin/groff/refer/token.h81
-rw-r--r--gnu/usr.bin/groff/soelim/Makefile.dep2
-rw-r--r--gnu/usr.bin/groff/soelim/Makefile.sub6
-rw-r--r--gnu/usr.bin/groff/soelim/TODO1
-rw-r--r--gnu/usr.bin/groff/soelim/soelim.cc278
-rw-r--r--gnu/usr.bin/groff/soelim/soelim.man42
-rw-r--r--gnu/usr.bin/groff/src/include/defs.h9
-rw-r--r--gnu/usr.bin/groff/tbl/Makefile13
-rw-r--r--gnu/usr.bin/groff/tbl/Makefile.dep6
-rw-r--r--gnu/usr.bin/groff/tbl/Makefile.sub7
-rw-r--r--gnu/usr.bin/groff/tbl/main.cc1497
-rw-r--r--gnu/usr.bin/groff/tbl/table.cc2764
-rw-r--r--gnu/usr.bin/groff/tbl/table.h152
-rw-r--r--gnu/usr.bin/groff/tbl/tbl.man143
-rwxr-xr-xgnu/usr.bin/groff/test-groff26
-rw-r--r--gnu/usr.bin/groff/tfmtodit/Makefile13
-rw-r--r--gnu/usr.bin/groff/tfmtodit/Makefile.dep2
-rw-r--r--gnu/usr.bin/groff/tfmtodit/Makefile.sub6
-rw-r--r--gnu/usr.bin/groff/tfmtodit/tfmtodit.cc850
-rw-r--r--gnu/usr.bin/groff/tfmtodit/tfmtodit.man150
-rw-r--r--gnu/usr.bin/groff/tmac/Makefile48
-rw-r--r--gnu/usr.bin/groff/tmac/Makefile.sub43
-rw-r--r--gnu/usr.bin/groff/tmac/TODO38
-rw-r--r--gnu/usr.bin/groff/tmac/doc-common456
-rw-r--r--gnu/usr.bin/groff/tmac/doc-ditroff281
-rw-r--r--gnu/usr.bin/groff/tmac/doc-nroff225
-rw-r--r--gnu/usr.bin/groff/tmac/doc-syms314
-rw-r--r--gnu/usr.bin/groff/tmac/eqnrc61
-rw-r--r--gnu/usr.bin/groff/tmac/fixmacros.sed6
-rw-r--r--gnu/usr.bin/groff/tmac/groff_ms.man218
-rw-r--r--gnu/usr.bin/groff/tmac/man.local2
-rw-r--r--gnu/usr.bin/groff/tmac/man.ultrix103
-rw-r--r--gnu/usr.bin/groff/tmac/me.man274
-rw-r--r--gnu/usr.bin/groff/tmac/strip.sed2
-rw-r--r--gnu/usr.bin/groff/tmac/tmac.X46
-rw-r--r--gnu/usr.bin/groff/tmac/tmac.Xps44
-rw-r--r--gnu/usr.bin/groff/tmac/tmac.an326
-rw-r--r--gnu/usr.bin/groff/tmac/tmac.andoc12
-rw-r--r--gnu/usr.bin/groff/tmac/tmac.doc3427
-rw-r--r--gnu/usr.bin/groff/tmac/tmac.doc.old1858
-rw-r--r--gnu/usr.bin/groff/tmac/tmac.dvi134
-rw-r--r--gnu/usr.bin/groff/tmac/tmac.e1649
-rw-r--r--gnu/usr.bin/groff/tmac/tmac.latin1101
-rw-r--r--gnu/usr.bin/groff/tmac/tmac.pic10
-rw-r--r--gnu/usr.bin/groff/tmac/tmac.ps53
-rw-r--r--gnu/usr.bin/groff/tmac/tmac.psatk61
-rw-r--r--gnu/usr.bin/groff/tmac/tmac.psfig87
-rw-r--r--gnu/usr.bin/groff/tmac/tmac.psnew26
-rw-r--r--gnu/usr.bin/groff/tmac/tmac.psold60
-rw-r--r--gnu/usr.bin/groff/tmac/tmac.pspic57
-rw-r--r--gnu/usr.bin/groff/tmac/tmac.s1844
-rw-r--r--gnu/usr.bin/groff/tmac/tmac.tty48
-rw-r--r--gnu/usr.bin/groff/tmac/tmac.tty-char196
-rw-r--r--gnu/usr.bin/groff/tmac/troffrc31
-rw-r--r--gnu/usr.bin/groff/troff/Makefile26
-rw-r--r--gnu/usr.bin/groff/troff/Makefile.dep34
-rw-r--r--gnu/usr.bin/groff/troff/Makefile.sub30
-rw-r--r--gnu/usr.bin/groff/troff/TODO136
-rw-r--r--gnu/usr.bin/groff/troff/charinfo.h165
-rw-r--r--gnu/usr.bin/groff/troff/column.cc732
-rw-r--r--gnu/usr.bin/groff/troff/dictionary.cc211
-rw-r--r--gnu/usr.bin/groff/troff/dictionary.h92
-rw-r--r--gnu/usr.bin/groff/troff/div.cc1131
-rw-r--r--gnu/usr.bin/groff/troff/div.h147
-rw-r--r--gnu/usr.bin/groff/troff/env.cc3052
-rw-r--r--gnu/usr.bin/groff/troff/env.h327
-rw-r--r--gnu/usr.bin/groff/troff/hvunits.h340
-rw-r--r--gnu/usr.bin/groff/troff/hyphen.us4449
-rw-r--r--gnu/usr.bin/groff/troff/hyphen.us-ru4833
-rw-r--r--gnu/usr.bin/groff/troff/input.cc5951
-rw-r--r--gnu/usr.bin/groff/troff/node.cc4851
-rw-r--r--gnu/usr.bin/groff/troff/node.h493
-rw-r--r--gnu/usr.bin/groff/troff/number.cc669
-rw-r--r--gnu/usr.bin/groff/troff/reg.cc458
-rw-r--r--gnu/usr.bin/groff/troff/reg.h73
-rw-r--r--gnu/usr.bin/groff/troff/request.h80
-rw-r--r--gnu/usr.bin/groff/troff/symbol.cc148
-rw-r--r--gnu/usr.bin/groff/troff/symbol.h73
-rw-r--r--gnu/usr.bin/groff/troff/token.h194
-rw-r--r--gnu/usr.bin/groff/troff/troff.h83
-rw-r--r--gnu/usr.bin/groff/troff/troff.man2027
-rw-r--r--gnu/usr.bin/groff/xditview/ChangeLog274
-rw-r--r--gnu/usr.bin/groff/xditview/DESC9
-rw-r--r--gnu/usr.bin/groff/xditview/Dvi.c544
-rw-r--r--gnu/usr.bin/groff/xditview/Dvi.h46
-rw-r--r--gnu/usr.bin/groff/xditview/DviChar.c664
-rw-r--r--gnu/usr.bin/groff/xditview/DviChar.h37
-rw-r--r--gnu/usr.bin/groff/xditview/DviP.h233
-rw-r--r--gnu/usr.bin/groff/xditview/FontMap17
-rw-r--r--gnu/usr.bin/groff/xditview/GXditview.ad57
-rw-r--r--gnu/usr.bin/groff/xditview/INSTALL20
-rw-r--r--gnu/usr.bin/groff/xditview/Imakefile52
-rw-r--r--gnu/usr.bin/groff/xditview/Makefile34
-rw-r--r--gnu/usr.bin/groff/xditview/Menu.h46
-rw-r--r--gnu/usr.bin/groff/xditview/README14
-rw-r--r--gnu/usr.bin/groff/xditview/TODO15
-rw-r--r--gnu/usr.bin/groff/xditview/XFontName.c256
-rw-r--r--gnu/usr.bin/groff/xditview/XFontName.h45
-rw-r--r--gnu/usr.bin/groff/xditview/device.c589
-rw-r--r--gnu/usr.bin/groff/xditview/device.h21
-rw-r--r--gnu/usr.bin/groff/xditview/draw.c721
-rw-r--r--gnu/usr.bin/groff/xditview/font.c471
-rw-r--r--gnu/usr.bin/groff/xditview/gxditview.man246
-rw-r--r--gnu/usr.bin/groff/xditview/lex.c103
-rw-r--r--gnu/usr.bin/groff/xditview/page.c88
-rw-r--r--gnu/usr.bin/groff/xditview/parse.c334
-rw-r--r--gnu/usr.bin/groff/xditview/xdit.bm14
-rw-r--r--gnu/usr.bin/groff/xditview/xdit_mask.bm14
-rw-r--r--gnu/usr.bin/groff/xditview/xditview.c588
-rw-r--r--gnu/usr.bin/groff/xditview/xtotroff.c303
-rw-r--r--gnu/usr.bin/gzip/COPYING339
-rw-r--r--gnu/usr.bin/gzip/ChangeLog587
-rw-r--r--gnu/usr.bin/gzip/Makefile31
-rw-r--r--gnu/usr.bin/gzip/NEWS221
-rw-r--r--gnu/usr.bin/gzip/README144
-rw-r--r--gnu/usr.bin/gzip/THANKS276
-rw-r--r--gnu/usr.bin/gzip/TODO58
-rw-r--r--gnu/usr.bin/gzip/algorithm.doc164
-rw-r--r--gnu/usr.bin/gzip/bits.c205
-rw-r--r--gnu/usr.bin/gzip/crypt.c6
-rw-r--r--gnu/usr.bin/gzip/crypt.h12
-rw-r--r--gnu/usr.bin/gzip/deflate.c763
-rw-r--r--gnu/usr.bin/gzip/getopt.c755
-rw-r--r--gnu/usr.bin/gzip/getopt.h127
-rw-r--r--gnu/usr.bin/gzip/gzexe150
-rw-r--r--gnu/usr.bin/gzip/gzexe.143
-rw-r--r--gnu/usr.bin/gzip/gzip.1477
-rw-r--r--gnu/usr.bin/gzip/gzip.c1744
-rw-r--r--gnu/usr.bin/gzip/gzip.h315
-rw-r--r--gnu/usr.bin/gzip/inflate.c954
-rw-r--r--gnu/usr.bin/gzip/lzw.c26
-rw-r--r--gnu/usr.bin/gzip/lzw.h42
-rw-r--r--gnu/usr.bin/gzip/match.S379
-rw-r--r--gnu/usr.bin/gzip/revision.h16
-rw-r--r--gnu/usr.bin/gzip/tailor.h328
-rw-r--r--gnu/usr.bin/gzip/trees.c1075
-rw-r--r--gnu/usr.bin/gzip/unlzh.c401
-rw-r--r--gnu/usr.bin/gzip/unlzw.c377
-rw-r--r--gnu/usr.bin/gzip/unpack.c239
-rw-r--r--gnu/usr.bin/gzip/unzip.c199
-rw-r--r--gnu/usr.bin/gzip/util.c462
-rw-r--r--gnu/usr.bin/gzip/zdiff69
-rw-r--r--gnu/usr.bin/gzip/zdiff.144
-rw-r--r--gnu/usr.bin/gzip/zforce41
-rw-r--r--gnu/usr.bin/gzip/zforce.120
-rw-r--r--gnu/usr.bin/gzip/zgrep72
-rw-r--r--gnu/usr.bin/gzip/zgrep.144
-rw-r--r--gnu/usr.bin/gzip/zip.c117
-rw-r--r--gnu/usr.bin/gzip/zmore51
-rw-r--r--gnu/usr.bin/gzip/zmore.1145
-rw-r--r--gnu/usr.bin/gzip/znew145
-rw-r--r--gnu/usr.bin/gzip/znew.139
-rw-r--r--gnu/usr.bin/ld/Makefile16
-rw-r--r--gnu/usr.bin/ld/PORTING192
-rw-r--r--gnu/usr.bin/ld/cplus-dem.c975
-rw-r--r--gnu/usr.bin/ld/etc.c66
-rw-r--r--gnu/usr.bin/ld/i386/md-static-funcs.c16
-rw-r--r--gnu/usr.bin/ld/i386/md.c360
-rw-r--r--gnu/usr.bin/ld/i386/md.h226
-rw-r--r--gnu/usr.bin/ld/i386/mdprologue.S93
-rw-r--r--gnu/usr.bin/ld/ld.1217
-rw-r--r--gnu/usr.bin/ld/ld.1aout217
-rw-r--r--gnu/usr.bin/ld/ld.c3701
-rw-r--r--gnu/usr.bin/ld/ld.h702
-rw-r--r--gnu/usr.bin/ld/ldconfig/Makefile13
-rw-r--r--gnu/usr.bin/ld/ldconfig/ldconfig.8131
-rw-r--r--gnu/usr.bin/ld/ldconfig/ldconfig.c453
-rw-r--r--gnu/usr.bin/ld/ldd/Makefile7
-rw-r--r--gnu/usr.bin/ld/ldd/ldd.125
-rw-r--r--gnu/usr.bin/ld/ldd/ldd.c139
-rw-r--r--gnu/usr.bin/ld/lib.c865
-rw-r--r--gnu/usr.bin/ld/rrs.c1246
-rw-r--r--gnu/usr.bin/ld/rtld/Makefile33
-rw-r--r--gnu/usr.bin/ld/rtld/malloc.c481
-rw-r--r--gnu/usr.bin/ld/rtld/md-prologue.c39
-rw-r--r--gnu/usr.bin/ld/rtld/rtld.1144
-rw-r--r--gnu/usr.bin/ld/rtld/rtld.c1704
-rw-r--r--gnu/usr.bin/ld/rtld/sbrk.c101
-rw-r--r--gnu/usr.bin/ld/shlib.c314
-rw-r--r--gnu/usr.bin/ld/sparc/md-static-funcs.c37
-rw-r--r--gnu/usr.bin/ld/sparc/md.c351
-rw-r--r--gnu/usr.bin/ld/sparc/md.h292
-rw-r--r--gnu/usr.bin/ld/sparc/mdprologue.S101
-rw-r--r--gnu/usr.bin/ld/symbol.c161
-rw-r--r--gnu/usr.bin/ld/symseg.h359
-rw-r--r--gnu/usr.bin/ld/warnings.c758
-rw-r--r--gnu/usr.bin/ld/xbits.c167
-rw-r--r--gnu/usr.bin/man/COPYING339
-rw-r--r--gnu/usr.bin/man/Makefile10
-rw-r--r--gnu/usr.bin/man/Makefile.inc23
-rw-r--r--gnu/usr.bin/man/Makefile.shprog30
-rw-r--r--gnu/usr.bin/man/README134
-rw-r--r--gnu/usr.bin/man/TODO123
-rw-r--r--gnu/usr.bin/man/apropos/Makefile6
-rw-r--r--gnu/usr.bin/man/apropos/apropos.man27
-rw-r--r--gnu/usr.bin/man/apropos/apropos.sh64
-rw-r--r--gnu/usr.bin/man/catman/Makefile7
-rw-r--r--gnu/usr.bin/man/catman/catman.1160
-rw-r--r--gnu/usr.bin/man/catman/catman.perl395
-rw-r--r--gnu/usr.bin/man/lib/Makefile33
-rw-r--r--gnu/usr.bin/man/lib/config.h_dist210
-rw-r--r--gnu/usr.bin/man/lib/gripes.c180
-rw-r--r--gnu/usr.bin/man/lib/gripes.h30
-rw-r--r--gnu/usr.bin/man/lib/util.c149
-rw-r--r--gnu/usr.bin/man/makewhatis/Makefile7
-rw-r--r--gnu/usr.bin/man/makewhatis/makewhatis.1155
-rw-r--r--gnu/usr.bin/man/makewhatis/makewhatis.perl498
-rw-r--r--gnu/usr.bin/man/man/Makefile33
-rw-r--r--gnu/usr.bin/man/man/glob.c689
-rw-r--r--gnu/usr.bin/man/man/man.c1432
-rw-r--r--gnu/usr.bin/man/man/man.man134
-rw-r--r--gnu/usr.bin/man/man/manpath.c520
-rw-r--r--gnu/usr.bin/man/man/manpath.h26
-rw-r--r--gnu/usr.bin/man/man/ndir.h51
-rw-r--r--gnu/usr.bin/man/man/strdup.c39
-rw-r--r--gnu/usr.bin/man/man/version.h17
-rw-r--r--gnu/usr.bin/man/manpath/Makefile33
-rw-r--r--gnu/usr.bin/man/manpath/manpath.c520
-rw-r--r--gnu/usr.bin/man/manpath/manpath.config30
-rw-r--r--gnu/usr.bin/man/manpath/manpath.h26
-rw-r--r--gnu/usr.bin/man/manpath/manpath.man56
-rw-r--r--gnu/usr.bin/man/whatis/Makefile6
-rw-r--r--gnu/usr.bin/man/whatis/whatis.man27
-rw-r--r--gnu/usr.bin/man/whatis/whatis.sh66
-rw-r--r--gnu/usr.bin/mkisofs/COPYING345
-rw-r--r--gnu/usr.bin/mkisofs/ChangeLog695
-rwxr-xr-xgnu/usr.bin/mkisofs/Configure43
-rw-r--r--gnu/usr.bin/mkisofs/Makefile6
-rw-r--r--gnu/usr.bin/mkisofs/Makefile.in51
-rw-r--r--gnu/usr.bin/mkisofs/README84
-rw-r--r--gnu/usr.bin/mkisofs/TODO15
-rw-r--r--gnu/usr.bin/mkisofs/config.h1
-rw-r--r--gnu/usr.bin/mkisofs/defaults.h34
-rw-r--r--gnu/usr.bin/mkisofs/diag/Makefile16
-rw-r--r--gnu/usr.bin/mkisofs/diag/README74
-rw-r--r--gnu/usr.bin/mkisofs/diag/dump.c201
-rw-r--r--gnu/usr.bin/mkisofs/diag/isodump.c436
-rw-r--r--gnu/usr.bin/mkisofs/diag/isoinfo.c522
-rw-r--r--gnu/usr.bin/mkisofs/diag/isovfy.c490
-rw-r--r--gnu/usr.bin/mkisofs/exclude.c53
-rw-r--r--gnu/usr.bin/mkisofs/exclude.h8
-rw-r--r--gnu/usr.bin/mkisofs/hash.c177
-rw-r--r--gnu/usr.bin/mkisofs/iso9660.h107
-rw-r--r--gnu/usr.bin/mkisofs/make.com16
-rw-r--r--gnu/usr.bin/mkisofs/mkisofs.8274
-rw-r--r--gnu/usr.bin/mkisofs/mkisofs.c760
-rw-r--r--gnu/usr.bin/mkisofs/mkisofs.h263
-rw-r--r--gnu/usr.bin/mkisofs/rock.c530
-rw-r--r--gnu/usr.bin/mkisofs/tree.c1011
-rw-r--r--gnu/usr.bin/mkisofs/vms.c269
-rw-r--r--gnu/usr.bin/mkisofs/vms.h19
-rw-r--r--gnu/usr.bin/mkisofs/write.c785
-rw-r--r--gnu/usr.bin/patch/EXTERN.h24
-rw-r--r--gnu/usr.bin/patch/INTERN.h22
-rw-r--r--gnu/usr.bin/patch/Makefile6
-rw-r--r--gnu/usr.bin/patch/backupfile.c402
-rw-r--r--gnu/usr.bin/patch/backupfile.h46
-rw-r--r--gnu/usr.bin/patch/common.h197
-rw-r--r--gnu/usr.bin/patch/config.h81
-rw-r--r--gnu/usr.bin/patch/getopt.c731
-rw-r--r--gnu/usr.bin/patch/getopt.h129
-rw-r--r--gnu/usr.bin/patch/getopt1.c176
-rw-r--r--gnu/usr.bin/patch/inp.c382
-rw-r--r--gnu/usr.bin/patch/inp.h21
-rw-r--r--gnu/usr.bin/patch/patch.1587
-rw-r--r--gnu/usr.bin/patch/patch.c974
-rw-r--r--gnu/usr.bin/patch/patchlevel.h1
-rw-r--r--gnu/usr.bin/patch/pch.c1323
-rw-r--r--gnu/usr.bin/patch/pch.h39
-rw-r--r--gnu/usr.bin/patch/util.c433
-rw-r--r--gnu/usr.bin/patch/util.h91
-rw-r--r--gnu/usr.bin/patch/version.c28
-rw-r--r--gnu/usr.bin/patch/version.h12
-rw-r--r--gnu/usr.bin/perl/Artistic117
-rw-r--r--gnu/usr.bin/perl/Copying248
-rw-r--r--gnu/usr.bin/perl/Makefile10
-rw-r--r--gnu/usr.bin/perl/README195
-rw-r--r--gnu/usr.bin/perl/VERSION1
-rw-r--r--gnu/usr.bin/perl/Wishlist9
-rw-r--r--gnu/usr.bin/perl/eg/ADB8
-rw-r--r--gnu/usr.bin/perl/eg/README22
-rw-r--r--gnu/usr.bin/perl/eg/changes34
-rw-r--r--gnu/usr.bin/perl/eg/client34
-rw-r--r--gnu/usr.bin/perl/eg/down30
-rw-r--r--gnu/usr.bin/perl/eg/dus22
-rw-r--r--gnu/usr.bin/perl/eg/findcp53
-rw-r--r--gnu/usr.bin/perl/eg/findtar17
-rw-r--r--gnu/usr.bin/perl/eg/g/gcp114
-rw-r--r--gnu/usr.bin/perl/eg/g/gcp.man77
-rw-r--r--gnu/usr.bin/perl/eg/g/ged21
-rw-r--r--gnu/usr.bin/perl/eg/g/ghosts33
-rw-r--r--gnu/usr.bin/perl/eg/g/gsh117
-rw-r--r--gnu/usr.bin/perl/eg/g/gsh.man80
-rw-r--r--gnu/usr.bin/perl/eg/muck141
-rw-r--r--gnu/usr.bin/perl/eg/muck.man21
-rw-r--r--gnu/usr.bin/perl/eg/myrup29
-rw-r--r--gnu/usr.bin/perl/eg/nih10
-rw-r--r--gnu/usr.bin/perl/eg/perlsh15
-rw-r--r--gnu/usr.bin/perl/eg/relink91
-rw-r--r--gnu/usr.bin/perl/eg/rename83
-rw-r--r--gnu/usr.bin/perl/eg/rmfrom7
-rw-r--r--gnu/usr.bin/perl/eg/scan/scan_df51
-rw-r--r--gnu/usr.bin/perl/eg/scan/scan_last57
-rw-r--r--gnu/usr.bin/perl/eg/scan/scan_messages222
-rw-r--r--gnu/usr.bin/perl/eg/scan/scan_passwd30
-rw-r--r--gnu/usr.bin/perl/eg/scan/scan_ps32
-rw-r--r--gnu/usr.bin/perl/eg/scan/scan_sudo54
-rw-r--r--gnu/usr.bin/perl/eg/scan/scan_suid84
-rw-r--r--gnu/usr.bin/perl/eg/scan/scanner87
-rw-r--r--gnu/usr.bin/perl/eg/server27
-rw-r--r--gnu/usr.bin/perl/eg/shmkill24
-rw-r--r--gnu/usr.bin/perl/eg/sysvipc/README9
-rw-r--r--gnu/usr.bin/perl/eg/sysvipc/ipcmsg47
-rw-r--r--gnu/usr.bin/perl/eg/sysvipc/ipcsem46
-rw-r--r--gnu/usr.bin/perl/eg/sysvipc/ipcshm50
-rw-r--r--gnu/usr.bin/perl/eg/travesty46
-rw-r--r--gnu/usr.bin/perl/eg/van/empty45
-rw-r--r--gnu/usr.bin/perl/eg/van/unvanish66
-rw-r--r--gnu/usr.bin/perl/eg/van/vanexp21
-rw-r--r--gnu/usr.bin/perl/eg/van/vanish65
-rw-r--r--gnu/usr.bin/perl/eg/who13
-rw-r--r--gnu/usr.bin/perl/emacs/perl-mode.el631
-rw-r--r--gnu/usr.bin/perl/emacs/perldb.el423
-rw-r--r--gnu/usr.bin/perl/emacs/perldb.pl568
-rw-r--r--gnu/usr.bin/perl/emacs/tedstuff296
-rw-r--r--gnu/usr.bin/perl/h2pl/README71
-rw-r--r--gnu/usr.bin/perl/h2pl/cbreak.pl34
-rw-r--r--gnu/usr.bin/perl/h2pl/cbreak2.pl33
-rw-r--r--gnu/usr.bin/perl/h2pl/eg/sizeof.ph14
-rw-r--r--gnu/usr.bin/perl/h2pl/eg/sys/errno.pl92
-rw-r--r--gnu/usr.bin/perl/h2pl/eg/sys/ioctl.pl186
-rw-r--r--gnu/usr.bin/perl/h2pl/eg/sysexits.pl16
-rw-r--r--gnu/usr.bin/perl/h2pl/getioctlsizes13
-rw-r--r--gnu/usr.bin/perl/h2pl/mksizes42
-rw-r--r--gnu/usr.bin/perl/h2pl/mkvars31
-rw-r--r--gnu/usr.bin/perl/h2pl/tcbreak17
-rw-r--r--gnu/usr.bin/perl/h2pl/tcbreak217
-rw-r--r--gnu/usr.bin/perl/lib/Makefile17
-rw-r--r--gnu/usr.bin/perl/lib/abbrev.pl33
-rw-r--r--gnu/usr.bin/perl/lib/assert.pl52
-rw-r--r--gnu/usr.bin/perl/lib/bigfloat.pl233
-rw-r--r--gnu/usr.bin/perl/lib/bigint.pl271
-rw-r--r--gnu/usr.bin/perl/lib/bigrat.pl148
-rw-r--r--gnu/usr.bin/perl/lib/cacheout.pl40
-rw-r--r--gnu/usr.bin/perl/lib/chat2.pl339
-rw-r--r--gnu/usr.bin/perl/lib/complete.pl110
-rw-r--r--gnu/usr.bin/perl/lib/ctime.pl51
-rw-r--r--gnu/usr.bin/perl/lib/dumpvar.pl37
-rw-r--r--gnu/usr.bin/perl/lib/exceptions.pl54
-rw-r--r--gnu/usr.bin/perl/lib/fastcwd.pl35
-rw-r--r--gnu/usr.bin/perl/lib/find.pl106
-rw-r--r--gnu/usr.bin/perl/lib/finddepth.pl105
-rw-r--r--gnu/usr.bin/perl/lib/flush.pl23
-rw-r--r--gnu/usr.bin/perl/lib/getcwd.pl62
-rw-r--r--gnu/usr.bin/perl/lib/getopt.pl41
-rw-r--r--gnu/usr.bin/perl/lib/getopts.pl50
-rw-r--r--gnu/usr.bin/perl/lib/importenv.pl16
-rw-r--r--gnu/usr.bin/perl/lib/look.pl44
-rw-r--r--gnu/usr.bin/perl/lib/newgetopt.pl271
-rw-r--r--gnu/usr.bin/perl/lib/open2.pl54
-rw-r--r--gnu/usr.bin/perl/lib/perldb.pl598
-rw-r--r--gnu/usr.bin/perl/lib/pwd.pl72
-rw-r--r--gnu/usr.bin/perl/lib/shellwords.pl48
-rw-r--r--gnu/usr.bin/perl/lib/stat.pl31
-rw-r--r--gnu/usr.bin/perl/lib/syslog.pl224
-rw-r--r--gnu/usr.bin/perl/lib/termcap.pl165
-rw-r--r--gnu/usr.bin/perl/lib/timelocal.pl83
-rw-r--r--gnu/usr.bin/perl/lib/validate.pl104
-rw-r--r--gnu/usr.bin/perl/misc/c2ph1071
-rw-r--r--gnu/usr.bin/perl/misc/c2ph.1191
-rw-r--r--gnu/usr.bin/perl/misc/pstruct1071
-rw-r--r--gnu/usr.bin/perl/perl/EXTERN.h29
-rw-r--r--gnu/usr.bin/perl/perl/INTERN.h29
-rw-r--r--gnu/usr.bin/perl/perl/Makefile17
-rw-r--r--gnu/usr.bin/perl/perl/arg.h1001
-rw-r--r--gnu/usr.bin/perl/perl/array.c290
-rw-r--r--gnu/usr.bin/perl/perl/array.h48
-rwxr-xr-xgnu/usr.bin/perl/perl/cflags91
-rw-r--r--gnu/usr.bin/perl/perl/cmd.c1266
-rw-r--r--gnu/usr.bin/perl/perl/cmd.h182
-rw-r--r--gnu/usr.bin/perl/perl/config.H892
-rw-r--r--gnu/usr.bin/perl/perl/config.h769
-rw-r--r--gnu/usr.bin/perl/perl/config.sh268
-rw-r--r--gnu/usr.bin/perl/perl/cons.c1453
-rw-r--r--gnu/usr.bin/perl/perl/consarg.c1299
-rw-r--r--gnu/usr.bin/perl/perl/crypt.c200
-rw-r--r--gnu/usr.bin/perl/perl/doarg.c1856
-rw-r--r--gnu/usr.bin/perl/perl/doio.c2958
-rw-r--r--gnu/usr.bin/perl/perl/dolist.c1976
-rw-r--r--gnu/usr.bin/perl/perl/dump.c379
-rw-r--r--gnu/usr.bin/perl/perl/eval.c3016
-rw-r--r--gnu/usr.bin/perl/perl/form.c422
-rw-r--r--gnu/usr.bin/perl/perl/form.h51
-rw-r--r--gnu/usr.bin/perl/perl/handy.h153
-rw-r--r--gnu/usr.bin/perl/perl/hash.c718
-rw-r--r--gnu/usr.bin/perl/perl/hash.h78
-rw-r--r--gnu/usr.bin/perl/perl/malloc.c513
-rw-r--r--gnu/usr.bin/perl/perl/patchlevel.h1
-rw-r--r--gnu/usr.bin/perl/perl/perl.16013
-rw-r--r--gnu/usr.bin/perl/perl/perl.c1462
-rw-r--r--gnu/usr.bin/perl/perl/perl.h1066
-rw-r--r--gnu/usr.bin/perl/perl/perly.c3063
-rw-r--r--gnu/usr.bin/perl/perl/perly.h83
-rw-r--r--gnu/usr.bin/perl/perl/regcomp.c1481
-rw-r--r--gnu/usr.bin/perl/perl/regcomp.h203
-rw-r--r--gnu/usr.bin/perl/perl/regexec.c913
-rw-r--r--gnu/usr.bin/perl/perl/regexp.h56
-rw-r--r--gnu/usr.bin/perl/perl/spat.h49
-rw-r--r--gnu/usr.bin/perl/perl/stab.c1058
-rw-r--r--gnu/usr.bin/perl/perl/stab.h148
-rw-r--r--gnu/usr.bin/perl/perl/str.c1602
-rw-r--r--gnu/usr.bin/perl/perl/str.h174
-rw-r--r--gnu/usr.bin/perl/perl/t/README11
-rwxr-xr-xgnu/usr.bin/perl/perl/t/TEST102
-rwxr-xr-xgnu/usr.bin/perl/perl/t/base/cond.t19
-rwxr-xr-xgnu/usr.bin/perl/perl/t/base/if.t11
-rwxr-xr-xgnu/usr.bin/perl/perl/t/base/lex.t78
-rwxr-xr-xgnu/usr.bin/perl/perl/t/base/pat.t11
-rwxr-xr-xgnu/usr.bin/perl/perl/t/base/term.t42
-rwxr-xr-xgnu/usr.bin/perl/perl/t/cmd/elsif.t25
-rwxr-xr-xgnu/usr.bin/perl/perl/t/cmd/for.t49
-rwxr-xr-xgnu/usr.bin/perl/perl/t/cmd/mod.t33
-rwxr-xr-xgnu/usr.bin/perl/perl/t/cmd/subval.t179
-rwxr-xr-xgnu/usr.bin/perl/perl/t/cmd/switch.t75
-rwxr-xr-xgnu/usr.bin/perl/perl/t/cmd/while.t110
-rwxr-xr-xgnu/usr.bin/perl/perl/t/comp/cmdopt.t83
-rwxr-xr-xgnu/usr.bin/perl/perl/t/comp/cpp.t51
-rwxr-xr-xgnu/usr.bin/perl/perl/t/comp/decl.t49
-rwxr-xr-xgnu/usr.bin/perl/perl/t/comp/multiline.t40
-rwxr-xr-xgnu/usr.bin/perl/perl/t/comp/package.t33
-rwxr-xr-xgnu/usr.bin/perl/perl/t/comp/script.t23
-rwxr-xr-xgnu/usr.bin/perl/perl/t/comp/term.t35
-rwxr-xr-xgnu/usr.bin/perl/perl/t/io/argv.t36
-rwxr-xr-xgnu/usr.bin/perl/perl/t/io/dup.t32
-rwxr-xr-xgnu/usr.bin/perl/perl/t/io/fs.t85
-rwxr-xr-xgnu/usr.bin/perl/perl/t/io/inplace.t21
-rwxr-xr-xgnu/usr.bin/perl/perl/t/io/pipe.t56
-rwxr-xr-xgnu/usr.bin/perl/perl/t/io/print.t32
-rwxr-xr-xgnu/usr.bin/perl/perl/t/io/tell.t44
-rwxr-xr-xgnu/usr.bin/perl/perl/t/lib/big.t280
-rwxr-xr-xgnu/usr.bin/perl/perl/t/op/append.t21
-rwxr-xr-xgnu/usr.bin/perl/perl/t/op/array.t120
-rwxr-xr-xgnu/usr.bin/perl/perl/t/op/auto.t48
-rwxr-xr-xgnu/usr.bin/perl/perl/t/op/chop.t30
-rwxr-xr-xgnu/usr.bin/perl/perl/t/op/cond.t12
-rwxr-xr-xgnu/usr.bin/perl/perl/t/op/dbm.t106
-rwxr-xr-xgnu/usr.bin/perl/perl/t/op/delete.t29
-rwxr-xr-xgnu/usr.bin/perl/perl/t/op/do.t44
-rwxr-xr-xgnu/usr.bin/perl/perl/t/op/each.t53
-rwxr-xr-xgnu/usr.bin/perl/perl/t/op/eval.t57
-rwxr-xr-xgnu/usr.bin/perl/perl/t/op/exec.t21
-rwxr-xr-xgnu/usr.bin/perl/perl/t/op/exp.t27
-rwxr-xr-xgnu/usr.bin/perl/perl/t/op/flip.t26
-rwxr-xr-xgnu/usr.bin/perl/perl/t/op/fork.t16
-rwxr-xr-xgnu/usr.bin/perl/perl/t/op/glob.t22
-rwxr-xr-xgnu/usr.bin/perl/perl/t/op/goto.t33
-rwxr-xr-xgnu/usr.bin/perl/perl/t/op/groups.t47
-rwxr-xr-xgnu/usr.bin/perl/perl/t/op/index.t42
-rwxr-xr-xgnu/usr.bin/perl/perl/t/op/int.t17
-rwxr-xr-xgnu/usr.bin/perl/perl/t/op/join.t12
-rwxr-xr-xgnu/usr.bin/perl/perl/t/op/list.t83
-rwxr-xr-xgnu/usr.bin/perl/perl/t/op/local.t45
-rwxr-xr-xgnu/usr.bin/perl/perl/t/op/magic.t32
-rwxr-xr-xgnu/usr.bin/perl/perl/t/op/mkdir.t15
-rwxr-xr-xgnu/usr.bin/perl/perl/t/op/oct.t9
-rwxr-xr-xgnu/usr.bin/perl/perl/t/op/ord.t14
-rwxr-xr-xgnu/usr.bin/perl/perl/t/op/pack.t20
-rwxr-xr-xgnu/usr.bin/perl/perl/t/op/pat.t184
-rwxr-xr-xgnu/usr.bin/perl/perl/t/op/push.t44
-rwxr-xr-xgnu/usr.bin/perl/perl/t/op/range.t36
-rw-r--r--gnu/usr.bin/perl/perl/t/op/re_tests274
-rwxr-xr-xgnu/usr.bin/perl/perl/t/op/read.t20
-rwxr-xr-xgnu/usr.bin/perl/perl/t/op/readdir.t20
-rwxr-xr-xgnu/usr.bin/perl/perl/t/op/regexp.t35
-rwxr-xr-xgnu/usr.bin/perl/perl/t/op/repeat.t42
-rwxr-xr-xgnu/usr.bin/perl/perl/t/op/s.t179
-rwxr-xr-xgnu/usr.bin/perl/perl/t/op/sleep.t8
-rwxr-xr-xgnu/usr.bin/perl/perl/t/op/sort.t48
-rwxr-xr-xgnu/usr.bin/perl/perl/t/op/split.t57
-rwxr-xr-xgnu/usr.bin/perl/perl/t/op/sprintf.t8
-rwxr-xr-xgnu/usr.bin/perl/perl/t/op/stat.t176
-rwxr-xr-xgnu/usr.bin/perl/perl/t/op/study.t69
-rwxr-xr-xgnu/usr.bin/perl/perl/t/op/substr.t47
-rwxr-xr-xgnu/usr.bin/perl/perl/t/op/time.t43
-rwxr-xr-xgnu/usr.bin/perl/perl/t/op/undef.t56
-rwxr-xr-xgnu/usr.bin/perl/perl/t/op/unshift.t14
-rwxr-xr-xgnu/usr.bin/perl/perl/t/op/vec.t24
-rwxr-xr-xgnu/usr.bin/perl/perl/t/op/write.t129
-rw-r--r--gnu/usr.bin/perl/perl/t/printme6
-rw-r--r--gnu/usr.bin/perl/perl/tdoio.c2951
-rw-r--r--gnu/usr.bin/perl/perl/toke.c2767
-rw-r--r--gnu/usr.bin/perl/perl/usersub.c151
-rw-r--r--gnu/usr.bin/perl/perl/util.c1783
-rw-r--r--gnu/usr.bin/perl/perl/util.h64
-rw-r--r--gnu/usr.bin/perl/sperl/Makefile30
-rw-r--r--gnu/usr.bin/perl/tperl/Makefile28
-rw-r--r--gnu/usr.bin/perl/usub/Makefile32
-rw-r--r--gnu/usr.bin/perl/usub/README117
-rw-r--r--gnu/usr.bin/perl/usub/curses.mus813
-rwxr-xr-xgnu/usr.bin/perl/usub/man2mus66
-rwxr-xr-xgnu/usr.bin/perl/usub/mus135
-rwxr-xr-xgnu/usr.bin/perl/usub/pager190
-rw-r--r--gnu/usr.bin/perl/usub/usersub.c77
-rw-r--r--gnu/usr.bin/perl/x2p/EXTERN.h29
-rw-r--r--gnu/usr.bin/perl/x2p/INTERN.h29
-rw-r--r--gnu/usr.bin/perl/x2p/Makefile23
-rw-r--r--gnu/usr.bin/perl/x2p/a2p.1199
-rw-r--r--gnu/usr.bin/perl/x2p/a2p.h344
-rw-r--r--gnu/usr.bin/perl/x2p/a2p.y406
-rw-r--r--gnu/usr.bin/perl/x2p/a2py.c1304
-rwxr-xr-xgnu/usr.bin/perl/x2p/find2perl568
-rwxr-xr-xgnu/usr.bin/perl/x2p/h2ph262
-rwxr-xr-xgnu/usr.bin/perl/x2p/h2ph.141
-rw-r--r--gnu/usr.bin/perl/x2p/handy.h49
-rw-r--r--gnu/usr.bin/perl/x2p/hash.c253
-rw-r--r--gnu/usr.bin/perl/x2p/hash.h63
-rw-r--r--gnu/usr.bin/perl/x2p/malloc.c516
-rwxr-xr-xgnu/usr.bin/perl/x2p/s2p769
-rw-r--r--gnu/usr.bin/perl/x2p/s2p.1108
-rw-r--r--gnu/usr.bin/perl/x2p/str.c470
-rw-r--r--gnu/usr.bin/perl/x2p/str.h49
-rw-r--r--gnu/usr.bin/perl/x2p/util.c271
-rw-r--r--gnu/usr.bin/perl/x2p/util.h56
-rw-r--r--gnu/usr.bin/perl/x2p/walk.c2089
-rw-r--r--gnu/usr.bin/ptx/Makefile9
-rw-r--r--gnu/usr.bin/ptx/bumpalloc.h4
-rw-r--r--gnu/usr.bin/ptx/doc/Makefile3
-rw-r--r--gnu/usr.bin/ptx/doc/ptx.texinfo554
-rw-r--r--gnu/usr.bin/ptx/ptx.c24
-rw-r--r--gnu/usr.bin/rcs/CREDITS24
-rw-r--r--gnu/usr.bin/rcs/Makefile2
-rw-r--r--gnu/usr.bin/rcs/Makefile.inc8
-rw-r--r--gnu/usr.bin/rcs/NEWS548
-rw-r--r--gnu/usr.bin/rcs/REFS90
-rw-r--r--gnu/usr.bin/rcs/ci/Makefile9
-rw-r--r--gnu/usr.bin/rcs/ci/ci.1210
-rw-r--r--gnu/usr.bin/rcs/ci/ci.c615
-rw-r--r--gnu/usr.bin/rcs/co/Makefile9
-rw-r--r--gnu/usr.bin/rcs/co/co.1285
-rw-r--r--gnu/usr.bin/rcs/co/co.c382
-rw-r--r--gnu/usr.bin/rcs/doc/rcs.ms78
-rw-r--r--gnu/usr.bin/rcs/ident/Makefile9
-rw-r--r--gnu/usr.bin/rcs/ident/ident.1126
-rw-r--r--gnu/usr.bin/rcs/ident/ident.c170
-rw-r--r--gnu/usr.bin/rcs/lib/Makefile15
-rw-r--r--gnu/usr.bin/rcs/lib/conf.h382
-rw-r--r--gnu/usr.bin/rcs/lib/maketime.c604
-rw-r--r--gnu/usr.bin/rcs/lib/maketime.h39
-rw-r--r--gnu/usr.bin/rcs/lib/merger.c77
-rw-r--r--gnu/usr.bin/rcs/lib/partime.c1250
-rw-r--r--gnu/usr.bin/rcs/lib/partime.h71
-rw-r--r--gnu/usr.bin/rcs/lib/rcsbase.h358
-rw-r--r--gnu/usr.bin/rcs/lib/rcsedit.c1013
-rw-r--r--gnu/usr.bin/rcs/lib/rcsfcmp.c127
-rw-r--r--gnu/usr.bin/rcs/lib/rcsfnms.c632
-rw-r--r--gnu/usr.bin/rcs/lib/rcsgen.c343
-rw-r--r--gnu/usr.bin/rcs/lib/rcskeep.c201
-rw-r--r--gnu/usr.bin/rcs/lib/rcskeys.c79
-rw-r--r--gnu/usr.bin/rcs/lib/rcslex.c835
-rw-r--r--gnu/usr.bin/rcs/lib/rcsmap.c9
-rw-r--r--gnu/usr.bin/rcs/lib/rcsrev.c503
-rw-r--r--gnu/usr.bin/rcs/lib/rcssyn.c422
-rw-r--r--gnu/usr.bin/rcs/lib/rcstime.c191
-rw-r--r--gnu/usr.bin/rcs/lib/rcsutil.c847
-rw-r--r--gnu/usr.bin/rcs/lib/version.c2
-rw-r--r--gnu/usr.bin/rcs/merge/Makefile7
-rw-r--r--gnu/usr.bin/rcs/merge/merge.1125
-rw-r--r--gnu/usr.bin/rcs/merge/merge.c56
-rw-r--r--gnu/usr.bin/rcs/rcs/Makefile13
-rw-r--r--gnu/usr.bin/rcs/rcs/rcs.1105
-rw-r--r--gnu/usr.bin/rcs/rcs/rcs.c903
-rw-r--r--gnu/usr.bin/rcs/rcs/rcsfile.5254
-rw-r--r--gnu/usr.bin/rcs/rcs/rcsintro.118
-rw-r--r--gnu/usr.bin/rcs/rcsclean/Makefile9
-rw-r--r--gnu/usr.bin/rcs/rcsclean/rcsclean.148
-rw-r--r--gnu/usr.bin/rcs/rcsclean/rcsclean.c114
-rw-r--r--gnu/usr.bin/rcs/rcsdiff/Makefile9
-rw-r--r--gnu/usr.bin/rcs/rcsdiff/rcsdiff.120
-rw-r--r--gnu/usr.bin/rcs/rcsdiff/rcsdiff.c254
-rw-r--r--gnu/usr.bin/rcs/rcsfreeze/Makefile13
-rw-r--r--gnu/usr.bin/rcs/rcsfreeze/rcsfreeze.sh37
-rw-r--r--gnu/usr.bin/rcs/rcsmerge/Makefile9
-rw-r--r--gnu/usr.bin/rcs/rcsmerge/rcsmerge.157
-rw-r--r--gnu/usr.bin/rcs/rcsmerge/rcsmerge.c216
-rwxr-xr-xgnu/usr.bin/rcs/rcstest195
-rw-r--r--gnu/usr.bin/rcs/rlog/Makefile9
-rw-r--r--gnu/usr.bin/rcs/rlog/rlog.184
-rw-r--r--gnu/usr.bin/rcs/rlog/rlog.c496
-rw-r--r--gnu/usr.bin/sdiff/Makefile9
-rw-r--r--gnu/usr.bin/sdiff/sdiff.1198
-rw-r--r--gnu/usr.bin/send-pr/COPYING339
-rw-r--r--gnu/usr.bin/send-pr/Makefile36
-rw-r--r--gnu/usr.bin/send-pr/README43
-rw-r--r--gnu/usr.bin/send-pr/categories8
-rw-r--r--gnu/usr.bin/send-pr/doc/Makefile3
-rw-r--r--gnu/usr.bin/send-pr/doc/categ.texi123
-rw-r--r--gnu/usr.bin/send-pr/doc/fields.texi518
-rw-r--r--gnu/usr.bin/send-pr/doc/s-usage.texi519
-rw-r--r--gnu/usr.bin/send-pr/doc/send-pr.texi657
-rw-r--r--gnu/usr.bin/send-pr/doc/states.texi53
-rw-r--r--gnu/usr.bin/send-pr/doc/version.texi1
-rwxr-xr-xgnu/usr.bin/send-pr/install-sid.sh82
-rw-r--r--gnu/usr.bin/send-pr/send-pr-el.in744
-rw-r--r--gnu/usr.bin/send-pr/send-pr.1260
-rw-r--r--gnu/usr.bin/send-pr/send-pr.sh516
-rw-r--r--gnu/usr.bin/sort/Makefile11
-rw-r--r--gnu/usr.bin/sort/error.c112
-rw-r--r--gnu/usr.bin/sort/getopt.c271
-rw-r--r--gnu/usr.bin/sort/getopt.h12
-rw-r--r--gnu/usr.bin/sort/getopt1.c11
-rw-r--r--gnu/usr.bin/sort/long-options.c20
-rw-r--r--gnu/usr.bin/sort/long-options.h11
-rw-r--r--gnu/usr.bin/sort/sort.14
-rw-r--r--gnu/usr.bin/sort/sort.c1003
-rw-r--r--gnu/usr.bin/sort/system.h95
-rw-r--r--gnu/usr.bin/sort/version.c12
-rw-r--r--gnu/usr.bin/tar/Makefile11
-rw-r--r--gnu/usr.bin/tar/Makefile.gnu10
-rw-r--r--gnu/usr.bin/tar/buffer.c2
-rw-r--r--gnu/usr.bin/tar/create.c38
-rw-r--r--gnu/usr.bin/tar/extract.c44
-rw-r--r--gnu/usr.bin/tar/getdate.y8
-rw-r--r--gnu/usr.bin/tar/getopt.c4
-rw-r--r--gnu/usr.bin/tar/getopt.h4
-rw-r--r--gnu/usr.bin/tar/getopt1.c6
-rw-r--r--gnu/usr.bin/tar/list.c13
-rw-r--r--gnu/usr.bin/tar/port.c4
-rw-r--r--gnu/usr.bin/tar/regex.c4932
-rw-r--r--gnu/usr.bin/tar/tar.1387
-rw-r--r--gnu/usr.bin/tar/tar.c57
-rw-r--r--gnu/usr.bin/tar/tar.h6
-rw-r--r--gnu/usr.bin/texinfo/Makefile9
-rw-r--r--gnu/usr.bin/texinfo/Makefile.inc4
-rw-r--r--gnu/usr.bin/texinfo/doc/Makefile8
-rw-r--r--gnu/usr.bin/texinfo/doc/info-stnd.texi1359
-rw-r--r--gnu/usr.bin/texinfo/doc/info.texi861
-rw-r--r--gnu/usr.bin/texinfo/doc/makeinfo.texi285
-rw-r--r--gnu/usr.bin/texinfo/doc/texi.texi15626
-rw-r--r--gnu/usr.bin/texinfo/info-files/Makefile14
-rw-r--r--gnu/usr.bin/texinfo/info-files/dir54
-rw-r--r--gnu/usr.bin/texinfo/info/Makefile26
-rw-r--r--gnu/usr.bin/texinfo/info/dir.c224
-rw-r--r--gnu/usr.bin/texinfo/info/display.c561
-rw-r--r--gnu/usr.bin/texinfo/info/display.h76
-rw-r--r--gnu/usr.bin/texinfo/info/doc.c128
-rw-r--r--gnu/usr.bin/texinfo/info/doc.h58
-rw-r--r--gnu/usr.bin/texinfo/info/dribble.c71
-rw-r--r--gnu/usr.bin/texinfo/info/dribble.h41
-rw-r--r--gnu/usr.bin/texinfo/info/echo_area.c1500
-rw-r--r--gnu/usr.bin/texinfo/info/echo_area.h63
-rw-r--r--gnu/usr.bin/texinfo/info/filesys.c625
-rw-r--r--gnu/usr.bin/texinfo/info/filesys.h84
-rw-r--r--gnu/usr.bin/texinfo/info/footnotes.c264
-rw-r--r--gnu/usr.bin/texinfo/info/footnotes.h46
-rw-r--r--gnu/usr.bin/texinfo/info/funs.h110
-rw-r--r--gnu/usr.bin/texinfo/info/gc.c95
-rw-r--r--gnu/usr.bin/texinfo/info/gc.h36
-rw-r--r--gnu/usr.bin/texinfo/info/general.h81
-rw-r--r--gnu/usr.bin/texinfo/info/getopt.c731
-rw-r--r--gnu/usr.bin/texinfo/info/getopt.h129
-rw-r--r--gnu/usr.bin/texinfo/info/getopt1.c176
-rw-r--r--gnu/usr.bin/texinfo/info/indices.c667
-rw-r--r--gnu/usr.bin/texinfo/info/indices.h39
-rw-r--r--gnu/usr.bin/texinfo/info/info-utils.c653
-rw-r--r--gnu/usr.bin/texinfo/info/info-utils.h144
-rw-r--r--gnu/usr.bin/texinfo/info/info.1230
-rw-r--r--gnu/usr.bin/texinfo/info/info.c511
-rw-r--r--gnu/usr.bin/texinfo/info/info.h96
-rw-r--r--gnu/usr.bin/texinfo/info/infodoc.c689
-rw-r--r--gnu/usr.bin/texinfo/info/infomap.c328
-rw-r--r--gnu/usr.bin/texinfo/info/infomap.h82
-rw-r--r--gnu/usr.bin/texinfo/info/m-x.c195
-rw-r--r--gnu/usr.bin/texinfo/info/nodemenu.c321
-rw-r--r--gnu/usr.bin/texinfo/info/nodes.c1167
-rw-r--r--gnu/usr.bin/texinfo/info/nodes.h164
-rw-r--r--gnu/usr.bin/texinfo/info/search.c566
-rw-r--r--gnu/usr.bin/texinfo/info/search.h78
-rw-r--r--gnu/usr.bin/texinfo/info/session.c4168
-rw-r--r--gnu/usr.bin/texinfo/info/session.h146
-rw-r--r--gnu/usr.bin/texinfo/info/signals.c189
-rw-r--r--gnu/usr.bin/texinfo/info/signals.h85
-rw-r--r--gnu/usr.bin/texinfo/info/termdep.h64
-rw-r--r--gnu/usr.bin/texinfo/info/terminal.c768
-rw-r--r--gnu/usr.bin/texinfo/info/terminal.h126
-rw-r--r--gnu/usr.bin/texinfo/info/tilde.c379
-rw-r--r--gnu/usr.bin/texinfo/info/tilde.h62
-rw-r--r--gnu/usr.bin/texinfo/info/variables.c272
-rw-r--r--gnu/usr.bin/texinfo/info/variables.h64
-rw-r--r--gnu/usr.bin/texinfo/info/window.c1478
-rw-r--r--gnu/usr.bin/texinfo/info/window.h229
-rw-r--r--gnu/usr.bin/texinfo/info/xmalloc.c78
-rw-r--r--gnu/usr.bin/texinfo/makedoc/Makefile20
-rw-r--r--gnu/usr.bin/texinfo/makedoc/makedoc.c477
-rw-r--r--gnu/usr.bin/texinfo/makedoc/xmalloc.c78
-rw-r--r--gnu/usr.bin/texinfo/makeinfo/Makefile22
-rw-r--r--gnu/usr.bin/texinfo/makeinfo/makeinfo.c7549
-rw-r--r--gnu/usr.bin/texinfo/misc/Makefile96
-rw-r--r--gnu/usr.bin/texinfo/misc/Makefile.in95
-rw-r--r--gnu/usr.bin/texinfo/misc/NEWS171
-rw-r--r--gnu/usr.bin/texinfo/misc/README54
-rw-r--r--gnu/usr.bin/texinfo/misc/deref.c238
-rwxr-xr-xgnu/usr.bin/texinfo/misc/fixfonts84
-rwxr-xr-xgnu/usr.bin/texinfo/misc/mkinstalldirs35
-rwxr-xr-xgnu/usr.bin/texinfo/misc/tex3patch71
-rwxr-xr-xgnu/usr.bin/texinfo/misc/texi2dvi263
-rw-r--r--gnu/usr.bin/texinfo/texindex/Makefile21
-rw-r--r--gnu/usr.bin/texinfo/texindex/texindex.c1700
2069 files changed, 787007 insertions, 28701 deletions
diff --git a/gnu/usr.bin/Makefile b/gnu/usr.bin/Makefile
new file mode 100644
index 0000000..53d9a18
--- /dev/null
+++ b/gnu/usr.bin/Makefile
@@ -0,0 +1,7 @@
+# $Id: Makefile,v 1.29 1995/12/18 08:04:53 peter Exp $
+
+SUBDIR= as awk bc cc cpio cvs dc dialog diff diff3 gdb \
+ grep groff gzip ld man mkisofs patch perl ptx rcs sdiff send-pr \
+ sort tar texinfo
+
+.include <bsd.subdir.mk>
diff --git a/gnu/usr.bin/Makefile.inc b/gnu/usr.bin/Makefile.inc
new file mode 100644
index 0000000..5371a22
--- /dev/null
+++ b/gnu/usr.bin/Makefile.inc
@@ -0,0 +1,3 @@
+# $Id$
+
+BINDIR?= /usr/bin
diff --git a/gnu/usr.bin/as/CONTRIBUTORS b/gnu/usr.bin/as/CONTRIBUTORS
new file mode 100644
index 0000000..cfcc7bc
--- /dev/null
+++ b/gnu/usr.bin/as/CONTRIBUTORS
@@ -0,0 +1,11 @@
+(This file under construction).
+
+If you've contributed to gas and your name isn't listed here, it is
+not meant as a slight. I just don't know about it. Email me,
+rich@cygnus.com and I'll correct the situation.
+
+Dean Elsnor wrote the original gas for vax.
+
+Jay Fenalson maintained gas for a while.
+
+K. Richard Pixley currently maintains gas.
diff --git a/gnu/usr.bin/as/COPYING b/gnu/usr.bin/as/COPYING
new file mode 100644
index 0000000..a43ea21
--- /dev/null
+++ b/gnu/usr.bin/as/COPYING
@@ -0,0 +1,339 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 675 Mass Ave, Cambridge, MA 02139, USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ Appendix: How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) 19yy <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) 19yy name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/gnu/usr.bin/as/ChangeLog b/gnu/usr.bin/as/ChangeLog
new file mode 100644
index 0000000..db77234
--- /dev/null
+++ b/gnu/usr.bin/as/ChangeLog
@@ -0,0 +1,429 @@
+Sun Mar 1 17:02:06 1992 K. Richard Pixley (rich@cygnus.com)
+
+ * README: updated to 1.92.3, included mail announcement.
+
+Sat Feb 29 00:53:16 1992 K. Richard Pixley (rich@cygnus.com)
+
+ * tc-sparc.c (md_apply_fix): relocation overflow checks.
+
+ * atof-generic.c (atof_generic): recognize 99e999 as infinity for
+ older, broken, compilers.
+
+ * version.c: bump to 1.92.3, drop "Cygnus".
+
+ * input-scrub.c (as_where): use myname (which comes from argv[0])
+ as part of all error messages.
+
+ * mess-dose renaming:
+ flonum-copy.c -> flo-copy.c
+ flonum-const.c -> flo-const.c
+ config/a.out.gnu.h -> config/aout.h
+ config/coff.gnu.h -> config/coff.h
+
+ * Makefile.in, obj-aout.h, obj-coff.h: reflect file renaming.
+
+ * output-file.c (output_file_create): add "b" to the fopen to
+ humor mess-dos.
+
+ * configure.in: tahoe needs atof-tahoe.
+
+ * config/tc-tahoe.[hc], config/atof-tahoe.c, opcode/tahoe.h: new
+ files. This is kinda blind cause I don't have anything to run
+ through it or compare against.
+
+ * read.c (read_a_source_file), expr.c (operand): fix a very old
+ bug in label reading exposed by m88k. Also, m88k can't have a
+ pseudo "set".
+
+ * config/m88k.[hc]: freshen copyrights, version 2 gpl, update to
+ current gas.
+
+ * config/m88k-opcode.h moved to opcode/m88k.h
+
+ * read.c: NO_DOT_PSEUDOS from hacks unfinished work.
+
+ * opcode/m68k.h: Sun's JFcc aliases appear to be variable length.
+ Make them so.
+
+ * opcode/a29k.h: remove rcsid.
+
+ * config/te-sun3.h: remove semicolon typo.
+
+ * config/obj-vms.c: another patch from eric youngdale.
+
+ * write.c: white space only.
+
+ * config/tc-i960.c: change from intel for header flags.
+
+ * config/te-sequent.h, config/obj-aout.h: first cut at building
+ sequent headers.
+
+ * config/tc-ns32k.c: patches from Jyrki Kuoppala <jkp@cs.hut.fi>.
+
+ * struct-symbol.h: removed redundant decl of N_TYPE_seg.
+
+ * config/tc-sparc.c (sparc_ip), opcode/sparc.h: changes from chris
+ torek to correct a problem with "neg". some white space.
+
+ * confic/tc-m68k.c: a fix pulled from hack's unfinished work and
+ my mail archives. Try again to get pcrel working. Fix stupid
+ botch on cpu_type comparison.
+
+ * config/tc-sparc.c: .empty pseudo-op from
+ gordoni@cs.adelaide.edu.au.
+
+ * opcode/sparc.h: some new aliases from chris torek.
+
+ * opcode/i386.h: some new aliases and opcodes. also patches from
+ Steve Bleazard <steve@robobar.co.uk>.
+
+ * config/te-hpux.h: new file.
+
+ * configure.in: when targetting hpux, use te-hpux.h.
+
+ * config/obj-aout.c (obj-pre-write-hook), config/obj-bout.[ch]
+ (obj-pre-write-hook), config/obj-coff.[ch] (obj-pre-write-hook),
+ config/obj-generic.h, config/obj-vms.h, write.c
+ (write_object_file): move magic number fiddling out of write.c
+ and into obj-pre-write-hook.
+
+ * config/tc-i860.c: gcc -Wall cleanup.
+
+Fri Feb 28 00:30:36 1992 K. Richard Pixley (rich@rtl.cygnus.com)
+
+ * configure.in: if target is sun3, use te-sun3.h.
+
+ * config/tc-m68k.h, config/te-sun3.h: moved #define of
+ default_magic_number_for_object_file from former to latter.
+
+ * config/te-sun3.h: removed sun_asm_syntax and te_sun3, they
+ aren't used.
+
+ * all: white space changes.
+ " -> " becomes "->"
+ "foo [" becomes "foo["
+ "a . b" becomes "a.b"
+ "\(if\|for\|while\|switch\)(" become "\\1("
+ "\\([^\n]\\)[ \t]*\\([=!+-*/<>]\\)=[ \t]*" become "\\1 \\2= "
+
+ * read.c, write.c, config/tc-i386.c: white space and comments
+ only.
+
+ * config/obj-vms.c: convert PUT_LONG and PUT_SHORT to squirt byte
+ swapped numbers.
+
+ * as.c, flonum-const.c, hex-value.c, input-file.c, version.c,
+ config/obj-aout.h, config/obj-vms.c: VMS -> HO_VMS.
+
+ * config/ho-vms.h: added HO_VMS.
+
+Thu Feb 27 18:25:11 1992 K. Richard Pixley (rich@rtl.cygnus.com)
+
+ * config/ChangeLog: removed. entries merged into this file.
+
+ * config/ho-vms.h: new file. Move the VMS stuff out of ho-vax.h
+ into ho-vms.h.
+
+ * configure.in: use ho-i386v4 for i386-sysvr4.
+
+ * config/ho-i386v4: new file.
+
+Tue Feb 25 19:54:04 1992 (Eric Youngdale at youngdale@v6550c.nrl.navy.mil)
+
+ * config/obj-vms.c (VMS_write_object_file): Add work-around
+ for g++ compiler bug involving external vtables.
+
+Mon Feb 24 22:19:10 1992 (Eric Youngdale at youngdale@v6550c.nrl.navy.mil)
+
+ * README-vms: Describe how to get a VMS obj file to a vms machine
+ via NFS.
+
+ * configure.in: For i386-sysv*, use gas_host=i386.
+
+ * Makefile.in: Remove continuation line markers when the next line
+ is blank.
+
+ * read.c (line_comment_chars): Make external.
+
+ * input-file.c: Remove redundant include of <assert.h>.
+
+ * config/ho-vax.h [VMS]: Include <ctype.h> and <perror.h>.
+
+ * config/obj-vms.h: Remove said includes. Add RELOC_32 to
+ reloc_type to prevent compilation error.
+
+ * config/obj-vms.c: Change bcopy to memcpy throughout.
+ (VMS_local_stab_Parse): Fix typo.
+ (VMS_local_stab_Parse, VMS_RSYM_Parse, Define_Local_Symbols,
+ Define_Routine, VMS_write_object_file): Allow 'f' for functions
+ as well as 'F'.
+
+Mon Feb 24 03:48:04 1992 K. Richard Pixley (rich@cygnus.com)
+
+ * README: updated to reflect current testing status.
+
+ * README.rich, NOTES, NOTES.config: updated slightly, marked as
+ "under construction".
+
+ * CONTRIBUTORS: new file.
+
+ * README-vms: options to configure are now -options=, not
+ +options=.
+
+ * version.c: bumped version to 1.92.2.
+
+Mon Feb 24 03:27:00 1992 Eric Youngdale (youngdale at v6550c.nrl.navy.mil)
+
+ * config.sub: Added vms as a target system. (So people do not
+ have to try to figure out that "vax-dec-vms" would work).
+
+ * configure.in: Added vms as a target os, and object file format.
+ (Useless on a vms system, but this is for people who want to
+ cross assemble).
+
+ * config-gas.com: New file. Script for VMS systems to set up the
+ configuration to build gas for VMS, and create config.status.
+
+ * make-gas.com: Redone to work with the bfd-gas scheme.
+
+ * as.c: Add const modifier to version_string.
+
+ * atof-vax.c: Remove redundant include of flonum.h. (This is also
+ included via as.h).
+
+ * expr.c: Add "const" modifier to hex_value.
+
+ * read.c: Add "const" modifier to line_comment_chars, and
+ line_separator_chars. Make use of the -1 switch for backward
+ compatibility with gcc 1.nn.
+ (s_ignore): remove redundant declaration of is_end_of_line.
+
+ * symbols.c: Finish conversion to S_* macros in the VMS only
+ parts of the program. Add "const" modifier to
+ md_[long,short]_jump_size. Remove declaration of const_flag
+ (which will be declared in obj-vms.h).
+
+ * write.c: Add "const" modifier to md_[long,short]_jump_size.
+ Fix arguments to VMS_write_object_file.
+
+ * obj-vms.h: New file (sort of). Mostly canibalized from other
+ files, using:
+
+ - objrecdef.h: Removed structure definition that we do not use,
+ and removed dollar signs from identifiers, since Unix System 5
+ does not like them.
+
+ - obj-aout.h: Took S_*, some H_* macros, and a number of
+ symbol definitions.
+
+ - a.out.hp.h: Took nlist structure. We do not really use this
+ per se, but it is easiest to let gas think that we do. When we
+ write the object file, we just pick out the parts that we need.
+
+ - stab.h: Just included it, since on non VMS and non a.out systems
+ we have no guarantee of having it. (Define N_* symbols).
+
+ *obj-vms.c: Renamed from vms.c. Did the following:
+
+ - Reworked to use the S_* macros.
+
+ - Add "const" modifier to version_string.
+
+ - Added global[ref,def,value] support
+
+ - (VMS_Store_PIC_Symbol_Reference):fix a bug with static constants.
+
+ - Remove a few redunant includes - all are now included through as.h.
+
+ - (obj_crawl_symbol_chain): Clean up (a lot), and remove non-VMS
+ code. Add definition for obj_read_begin_hook.
+
+ - Borrow the stab[s,d,n] routines from obj-aout.c.
+
+ - Borrow the seg_N_TYPE and N_TYPE_seg arrays from aout.c
+
+ - Use <fab.h>,<rab.h> and <xab.h> instead of <vms/fabdef.h>
+ <vms/rabdef.h> and <vms/xabdef.h>, for more consistent results.
+ (Some peoples <vms/*.h> files are different than others).
+
+ - Merged vms-dbg.c into obj-vms.c. Modified to use
+ the S_* macros. Added code to remove the psect hack from
+ variable names before writing them to the debugger records.
+
+
+
+ The following patches make cross assembly possible.
+
+ * as.c, read.c, symbols.c, write.c: Change "ifdef VMS" to
+ "ifdef OBJ_VMS".
+
+ * vms.c:
+
+ - Wrap the #include of some VMS system dependent headers
+ with "ifdef VMS".
+
+ - (get_VMS_time_on_unix): Add new routine. Generates current
+ time in VMS format to be written into object file.
+
+ - (Write_VMS_MHD_Records): Use get_VMS_time_on_unix if we are not
+ running on a VMS system.
+
+ - (Flush_VMS_Object_Record_Buffer): Add code to write correct
+ record format when running on a non-VMS system.
+
+ - (Create_VMS_Object_File): Use different mode if running under
+ unix.
+
+ - (VMS_TBT_Source_File): If we are not running on a VMS system,
+ write a source file record for the debugger that looks reasonable.
+
+Mon Feb 24 02:06:00 1992 K. Richard Pixley (rich@cygnus.com)
+
+ * Makefile.in: remove $(srcdir)/../include from INCLUDES. It
+ isn't needed.
+
+ * README: updated with current state.
+
+ * read.c (stringer): read arbitrary expressions between the commas
+ and treat them as ".byte" values. At least some i860 assembler
+ does this so now we do too. Also white space throughout.
+
+ * expr.c, expr.h, frags.c, symbols.c, write.c: white space only.
+
+Mon Feb 24 01:45:40 1992 K. Richard Pixley (rich@cygnus.com)
+
+ * config/te-sequent.h, config/tc-ns32k.h, config/tc-ns32k.c:
+ SEQUENT_COMPATIBILITY -> TE_SEQUENT.
+
+ * config/obj-aout.c: if OLD_GAS and i386, then screw up the magic
+ number.
+
+ * config/obj-bout.c: do not include aout/stab_gnu.h if NO_LISTING.
+
+ * config/obj-bout.h: added enum reloc_type.
+
+ * config/tc-i386.c: on OLD_GAS, .align is power of two, rather
+ than bytes.
+
+ * config/tc-i386.h: on OLD_GAS, the filler byte should be zero
+ rather than NOOP.
+
+ * config/tc-i860.c: relocs are 12bytes on this target. Also white
+ space.
+
+ * config/tc-m68kmote.c: removed. Not ready yet.
+
+ * config/a.out.gnu.h, config/tc-a29k.c, config/tc-m68k.c,
+ config/tc-ns32k.c: white space only.
+
+ * config/tc-a29k.h, config/tc-i860.h, config/tc-i960.h,
+ config/tc-m68k.h, config/tc-ns32k.h, config/tc-sparc.h,
+ config/tc-vax.h: NO_LISTING
+
+ * config/tc-m68k.h, config/tc-i860.h, config/tc-vax.h:
+ REVERSE_SORT_RELOCS if OLD_GAS.
+
+ * config/mt-m68k: removed. not needed.
+
+Fri Feb 21 06:22:15 1992 K. Richard Pixley (rich@rtl.cygnus.com)
+
+ * config/obj-aout.c: do not include stab.gnu.h if NO_LISTING.
+
+ * config/tc-i860.c, config/a.out.gnu.h: move i860 relocs to a proper place.
+
+ * config/a.out.h: removed.
+
+Fri Feb 21 06:21:07 1992 K. Richard Pixley (rich@rtl.cygnus.com)
+
+ * Makefile.in: put header files before C source for TAGS; remove
+ references to non-existent syscalls.h.
+
+ * read.c, write.c subsegs.c: back out the .bss changes.
+
+Fri Feb 21 02:17:22 1992 Minh Tran-Le (TRANLE@INTELLICORP.COM)
+
+ * config/tc-i386.c: config/tc-i386.c: added handling of the
+ following opcodes: i/o opcodes - inb, inw, outb and outw.
+ string manipulation with att syntax - scmp, slod, smov, ssca,
+ ssto.
+
+Fri Feb 21 01:53:50 1992 Minh Tran-Le (TRANLE@INTELLICORP.COM)
+
+ * config/obj-coff.c: (for aix386) Moved the symbols .text, .data
+ and .bss to just after .file .
+
+ In obj_crawl_symbol_chain() where it tries to put the external
+ symbols apart, with the condition:
+ (!S_IS_DEFINED(symbolP) &&
+ !S_IS_DEBUG(symbolP) &&
+ !SF_GET_STATICS(symbolP))
+ it was moving too many symbols out. So I switch it back to the
+ condition:
+ (S_GET_STORAGE_CLASS(symbolP) == C_EXT && !SF_GET_FUNCTION(symbolP))
+
+ In obj_emit_relocations() added the conditional on KEEP_RELOC_INFO
+ so that we don't use the F_RELFLG which make the linker complain
+ that somebody has stripped the relocation info.
+
+ Also, the AIX ld program require that the relocation table
+ is sorted by r_vaddr like the standard ATT assembler does.
+
+ [he also changed the sizeof(struct ...)'s into the coff
+ style FOOSZ macros. I'm not sure this is right, but I can't
+ remember why. xoxorich.]
+
+Fri Feb 21 01:08:48 1992 Minh Tran-Le (TRANLE@INTELLICORP.COM)
+
+ * symbols.c (local_label_name): symbols now start with ^A.
+
+ * read.c, subsegs.c, write.c obj-coff.c: added handling of
+ `.bss` pseudo op for unitialized data. The new gcc (1.37.9x)
+ generate these sections. .align: will use NOP_OPCODE or 0
+ for padding. This is just for being nice to the
+ disassembler.
+
+ * expr.c (operand): changed to generate local label "\001L0"
+ starting with a ^A so that it is recognized as a local label.
+
+ * as.c (perform_an_assembly_pass): zero bss_fix_root, too.
+
+Fri Feb 21 01:08:48 1992 K. Richard Pixley (rich@cygnus.com)
+
+ * Makefile.in, configure.in, doc: use the doc. Build it, install
+ it, clean it, etc.
+
+Tue Feb 18 02:21:25 1992 K. Richard Pixley (rich at cygnus.com)
+
+ * read.c: white space and comments only.
+
+ * configure.in: use the new atof-ns32.c for ns32k.
+
+ * write.c: comment change only.
+
+Tue Feb 18 02:11:10 1992 K. Richard Pixley (rich at cygnus.com)
+
+ * config/tc-m88k.[hc]: pulled in from hack's unfinished work. These
+ aren't yet integrated.
+
+ * config/tc-i860.[hc]: blew off the dust. Something must still be
+ done about conflicting relocation types.
+
+ * config/tc-ns32k.c: Replaced previous tc_aout_fix_to_chars stub
+ with the real thing.
+
+ * config/tc-i960.c, tc-sparc.c: white space and comments only.
+
+ * config/tc-a29k.h: delete duplicate macro definition.
+
+ * new file config/atof-ns32k.c copied from hack's last unreleased
+ gas.
+
+Mon Feb 17 07:51:06 1992 K. Richard Pixley (rich at cygnus.com)
+
+ * config/tc-ns32k.c: actually make tc_aout_fix_to_chars work
+ rather than abort.
+
+ * nearly everything. flush ChangeLog, package as gas-1.92.1.
+ ChangeLog's prior to this are sketchy at best. I have logs.
+ They just aren't ChangeLogs.
+
diff --git a/gnu/usr.bin/as/Makefile b/gnu/usr.bin/as/Makefile
new file mode 100644
index 0000000..50e4ac8
--- /dev/null
+++ b/gnu/usr.bin/as/Makefile
@@ -0,0 +1,73 @@
+# from: @(#)Makefile 6.1 (Berkeley) 3/3/91
+# $Id: Makefile,v 1.8 1995/05/30 04:45:55 rgrimes Exp $
+
+.include "config/Makefile.$(MACHINE)"
+
+.if !defined (gas_hosttype)
+gas_hosttype=$(MACHINE)
+.endif
+.if !defined (gas_target)
+gas_target=$(MACHINE)
+.endif
+.if !defined (gas_objformat)
+gas_objformat=aout
+.endif
+
+.if exists(${.CURDIR}/obj)
+ADDINCLUDE=-I${.CURDIR}/obj
+.endif
+
+PROG= as
+SRCS+= app.c as.c atof-generic.c bignum-copy.c \
+ cond.c expr.c flo-const.c flo-copy.c flonum-mult.c \
+ frags.c hash.c hex-value.c input-file.c input-scrub.c \
+ listing.c messages.c obstack.c output-file.c read.c subsegs.c \
+ symbols.c version.c write.c xmalloc.c xrealloc.c \
+ obj-$(gas_objformat).c
+CFLAGS+= -I$(.CURDIR) ${ADDINCLUDE} -I$(.CURDIR)/config \
+ -DOLD_GAS -DSIGTY=void -Derror=as_fatal \
+ -DSUB_SEGMENT_ALIGN=4 -DFREEBSD_AOUT
+
+CONF_HEADERS= targ-cpu.h obj-format.h host.h targ-env.h
+
+.PATH: $(.CURDIR)/config
+
+SUBDIR+= doc
+
+beforedepend ${PROG}: ${CONF_HEADERS}
+
+targ-cpu.h: Makefile config/Makefile.$(MACHINE) $(.CURDIR)/config/tc-$(gas_target).h
+ @cmp -s $(.CURDIR)/config/tc-$(gas_target).h targ-cpu.h || \
+ ( ${ECHO} "updating ${.TARGET}..." ; /bin/rm -f targ-cpu.h ; \
+ cp $(.CURDIR)/config/tc-$(gas_target).h targ-cpu.h )
+
+obj-format.h: Makefile config/Makefile.$(MACHINE) $(.CURDIR)/config/obj-$(gas_objformat).h
+ @cmp -s $(.CURDIR)/config/obj-$(gas_objformat).h obj-format.h || \
+ ( ${ECHO} "updating ${.TARGET}..." ; /bin/rm -f obj-format.h ; \
+ cp $(.CURDIR)/config/obj-$(gas_objformat).h obj-format.h )
+
+.if exists ($(.CURDIR)/config/ho-$(gas_hosttype).h)
+config_hostfile= $(.CURDIR)/config/ho-$(gas_hosttype).h
+.else
+config_hostfile= $(.CURDIR)/config/ho-generic.h
+.endif
+
+host.h: Makefile config/Makefile.$(MACHINE) $(config_hostfile)
+ @cmp -s $(config_hostfile) host.h || \
+ ( ${ECHO} "updating ${.TARGET}..." ; /bin/rm -f host.h ; \
+ cp $(config_hostfile) host.h )
+
+.if exists ($(.CURDIR)/config/te-$(MACHINE).h)
+config_targenvfile= $(.CURDIR)/config/te-$(MACHINE).h
+.else
+config_targenvfile= $(.CURDIR)/config/te-generic.h
+.endif
+
+targ-env.h: Makefile config/Makefile.$(MACHINE) $(config_targenvfile)
+ @cmp -s $(config_targenvfile) targ-env.h || \
+ ( ${ECHO} "updating ${.TARGET}..." ; /bin/rm -f targ-env.h ; \
+ cp $(config_targenvfile) targ-env.h )
+
+CLEANFILES+= ${CONF_HEADERS}
+
+.include <bsd.prog.mk>
diff --git a/gnu/usr.bin/as/Makefile.in b/gnu/usr.bin/as/Makefile.in
new file mode 100644
index 0000000..9e76458
--- /dev/null
+++ b/gnu/usr.bin/as/Makefile.in
@@ -0,0 +1,409 @@
+# Makefile for GNU Assembler
+# Copyright (C) 1987-1992 Free Software Foundation, Inc.
+
+#This file is part of GNU GAS.
+
+#GNU GAS is free software; you can redistribute it and/or modify
+#it under the terms of the GNU General Public License as published by
+#the Free Software Foundation; either version 2, or (at your option)
+#any later version.
+
+#GNU GAS is distributed in the hope that it will be useful,
+#but WITHOUT ANY WARRANTY; without even the implied warranty of
+#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+#GNU General Public License for more details.
+
+#You should have received a copy of the GNU General Public License
+#along with GNU GAS; see the file COPYING. If not, write to
+#the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+# The targets for external use include:
+# all, doc, proto, install, uninstall, includes, TAGS,
+# clean, cleanconfig, realclean, stage1, stage2, stage3, stage4.
+
+# Variables that exist for you to override.
+# See below for how to change them for certain systems.
+
+srcdir = .
+
+prefix = /usr/local
+
+bindir = $(prefix)/bin
+datadir = $(prefix)/lib
+libdir = $(prefix)/lib
+mandir = $(datadir)/man
+man1dir = $(mandir)/man1
+man2dir = $(mandir)/man2
+man3dir = $(mandir)/man3
+man4dir = $(mandir)/man4
+man5dir = $(mandir)/man5
+man6dir = $(mandir)/man6
+man7dir = $(mandir)/man7
+man8dir = $(mandir)/man8
+man9dir = $(mandir)/man9
+infodir = $(datadir)/info
+includedir = $(prefix)/include
+docdir = $(datadir)/doc
+
+SHELL = /bin/sh
+
+INSTALL = install -c
+INSTALL_PROGRAM = $(INSTALL)
+INSTALL_DATA = $(INSTALL)
+
+AR = ar
+AR_FLAGS = qv
+BISON = bison
+MAKEINFO = makeinfo
+RANLIB = ranlib
+MINUS_G = -g
+
+# Lists of files for various purposes.
+
+REAL_SOURCES = \
+ $(srcdir)/app.c \
+ $(srcdir)/as.c \
+ $(srcdir)/atof-generic.c \
+ $(srcdir)/bignum-copy.c \
+ $(srcdir)/cond.c \
+ $(srcdir)/expr.c \
+ $(srcdir)/flo-const.c \
+ $(srcdir)/flo-copy.c \
+ $(srcdir)/flonum-mult.c \
+ $(srcdir)/frags.c \
+ $(srcdir)/hash.c \
+ $(srcdir)/hex-value.c \
+ $(srcdir)/input-file.c \
+ $(srcdir)/input-scrub.c \
+ $(srcdir)/messages.c \
+ $(srcdir)/obstack.c \
+ $(srcdir)/output-file.c \
+ $(srcdir)/read.c \
+ $(srcdir)/strerror.c \
+ $(srcdir)/strstr.c \
+ $(srcdir)/subsegs.c \
+ $(srcdir)/symbols.c \
+ $(srcdir)/version.c \
+ $(srcdir)/write.c \
+ $(srcdir)/listing.c \
+ $(srcdir)/xmalloc.c \
+ $(srcdir)/xrealloc.c
+
+# in an expedient order
+LINKED_SOURCES = \
+ targ-cpu.c \
+ obj-format.c \
+ atof-targ.c
+
+SOURCES = $(LINKED_SOURCES) $(REAL_SOURCES)
+
+REAL_HEADERS = \
+ $(srcdir)/as.h \
+ $(srcdir)/bignum.h \
+ $(srcdir)/expr.h \
+ $(srcdir)/flonum.h \
+ $(srcdir)/frags.h \
+ $(srcdir)/hash.h \
+ $(srcdir)/input-file.h \
+ $(srcdir)/listing.h \
+ $(srcdir)/tc.h \
+ $(srcdir)/obj.h \
+ $(srcdir)/obstack.h \
+ $(srcdir)/read.h \
+ $(srcdir)/struc-symbol.h \
+ $(srcdir)/subsegs.h \
+ $(srcdir)/symbols.h \
+ $(srcdir)/write.h
+
+LINKED_HEADERS = \
+ a.out.gnu.h \
+ a.out.h \
+ host.h \
+ targ-env.h \
+ targ-cpu.h \
+ obj-format.h \
+ atof-targ.h
+
+HEADERS = $(LINKED_HEADERS) $(REAL_HEADERS)
+
+OBJS = \
+ targ-cpu.o \
+ obj-format.o \
+ atof-targ.o \
+ app.o \
+ as.o \
+ atof-generic.o \
+ bignum-copy.o \
+ cond.o \
+ expr.o \
+ flo-const.o \
+ flo-copy.o \
+ flonum-mult.o \
+ frags.o \
+ hash.o \
+ hex-value.o \
+ input-file.o \
+ input-scrub.o \
+ messages.o \
+ obstack.o \
+ output-file.o \
+ read.o \
+ strerror.o \
+ strstr.o \
+ subsegs.o \
+ symbols.o \
+ version.o \
+ write.o \
+ listing.o \
+ xmalloc.o \
+ xrealloc.o
+
+#### host, target, and site specific Makefile frags come in here.
+
+all: as.new
+ (cd doc ; $(MAKE) all)
+
+info:
+ (cd doc ; $(MAKE) info)
+
+install-info:
+ (cd doc ; $(MAKE) install-info)
+
+clean-info:
+ (cd doc ; $(MAKE) clean-info)
+
+# Now figure out from those variables how to compile and link.
+
+# This is the variable actually used when we compile.
+ALL_CFLAGS = $(MINUS_G) $(INTERNAL_CFLAGS) $(CFLAGS) $(HDEFINES) $(TDEFINES) -DPIC -DOLD_GAS
+
+# How to link with both our special library facilities
+# and the system's installed libraries.
+
+LIBS = $(HLIBS)
+
+# Specify the directories to be searched for header files.
+# Both . and srcdir are used, in that order,
+# so that tm.h and config.h will be found in the compilation
+# subdirectory rather than in the source directory.
+INCLUDES = -I. -I$(srcdir) -I$(srcdir)/config # -I$(srcdir)/../include
+SUBDIR_INCLUDES = -I.. -I$(srcdir) -I$(srcdir)/config
+
+# Always use -I$(srcdir)/config when compiling.
+.c.o:
+ $(CC) -c $(ALL_CFLAGS) $(CPPFLAGS) $(INCLUDES) $<
+
+# This tells GNU make version 3 not to export all the variables
+# defined in this file into the environment.
+.NOEXPORT:
+
+# Files to be copied away after each stage in building.
+STAGESTUFF = *.o as.new
+
+as.new: $(OBJS) $(LIBDEPS)
+ -mv -f as.new as.old
+ $(CC) $(ALL_CFLAGS) $(LDFLAGS) -o as.new $(OBJS) $(LIBS)
+
+config.status:
+ @echo You must configure gas. Look at the INSTALL file for details.
+ @false
+
+# Compiling object files from source files.
+
+app.o : app.c as.h host.h targ-env.h obj-format.h \
+ targ-cpu.h struc-symbol.h \
+ write.h flonum.h bignum.h expr.h frags.h hash.h read.h symbols.h tc.h obj.h
+as.o : as.c as.h host.h targ-env.h obj-format.h \
+ targ-cpu.h struc-symbol.h \
+ write.h flonum.h bignum.h expr.h frags.h hash.h read.h symbols.h tc.h obj.h
+atof-generic.o : atof-generic.c as.h host.h targ-env.h obj-format.h \
+ targ-cpu.h struc-symbol.h \
+ write.h flonum.h bignum.h expr.h frags.h hash.h read.h symbols.h tc.h obj.h
+bignum-copy.o : bignum-copy.c as.h host.h \
+ targ-env.h obj-format.h \
+ targ-cpu.h struc-symbol.h \
+ write.h flonum.h bignum.h expr.h frags.h hash.h read.h symbols.h tc.h obj.h
+cond.o : cond.c as.h host.h targ-env.h obj-format.h \
+ targ-cpu.h struc-symbol.h \
+ write.h flonum.h bignum.h expr.h frags.h hash.h read.h symbols.h tc.h obj.h
+
+debug.o : debug.c as.h host.h targ-env.h obj-format.h \
+ targ-cpu.h struc-symbol.h \
+ write.h flonum.h bignum.h expr.h frags.h hash.h read.h symbols.h tc.h obj.h \
+ subsegs.h
+expr.o : expr.c as.h host.h targ-env.h obj-format.h \
+ targ-cpu.h struc-symbol.h \
+ write.h flonum.h bignum.h expr.h frags.h hash.h read.h symbols.h tc.h obj.h
+
+flo-const.o : flo-const.c flonum.h bignum.h
+flo-copy.o : flo-copy.c as.h host.h targ-env.h obj-format.h \
+ targ-cpu.h struc-symbol.h \
+ write.h flonum.h bignum.h expr.h frags.h hash.h read.h symbols.h tc.h obj.h
+flonum-mult.o : flonum-mult.c flonum.h bignum.h
+frags.o : frags.c as.h host.h targ-env.h obj-format.h \
+ targ-cpu.h struc-symbol.h \
+ write.h flonum.h bignum.h expr.h frags.h hash.h read.h symbols.h tc.h obj.h \
+ subsegs.h
+hash.o : hash.c as.h host.h targ-env.h obj-format.h \
+ targ-cpu.h struc-symbol.h \
+ write.h flonum.h bignum.h expr.h frags.h hash.h read.h symbols.h tc.h obj.h
+hex-value.o : hex-value.c
+input-file.o : input-file.c as.h host.h \
+ targ-env.h obj-format.h targ-cpu.h \
+ struc-symbol.h write.h flonum.h bignum.h expr.h \
+ frags.h hash.h read.h symbols.h tc.h obj.h input-file.h
+input-scrub.o : input-scrub.c /usr/include/errno.h /usr/include/sys/errno.h \
+ as.h host.h targ-env.h obj-format.h \
+ targ-cpu.h struc-symbol.h \
+ write.h flonum.h bignum.h expr.h frags.h hash.h read.h symbols.h tc.h obj.h \
+ input-file.h
+listing.o : listing.c as.h host.h targ-env.h flonum.h bignum.h \
+ listing.h obj-format.h targ-cpu.h struc-symbol.h write.h expr.h \
+ frags.h hash.h read.h symbols.h tc.h obj.h input-file.h
+messages.o : messages.c as.h host.h targ-env.h obj-format.h \
+ targ-cpu.h struc-symbol.h \
+ write.h flonum.h bignum.h expr.h frags.h hash.h read.h symbols.h tc.h obj.h
+obstack.o : obstack.c
+output-file.o : output-file.c as.h host.h targ-env.h obj-format.h \
+ targ-cpu.h struc-symbol.h \
+ write.h flonum.h bignum.h expr.h frags.h hash.h read.h symbols.h tc.h obj.h \
+ output-file.h
+read.o : read.c as.h host.h targ-env.h obj-format.h \
+ targ-cpu.h struc-symbol.h \
+ write.h flonum.h bignum.h expr.h frags.h hash.h read.h symbols.h tc.h obj.h
+
+strstr.o : strstr.c
+subsegs.o : subsegs.c as.h host.h targ-env.h obj-format.h \
+ targ-cpu.h struc-symbol.h \
+ write.h flonum.h bignum.h expr.h frags.h hash.h read.h symbols.h tc.h obj.h \
+ subsegs.h
+symbols.o : symbols.c as.h host.h targ-env.h obj-format.h \
+ targ-cpu.h struc-symbol.h \
+ write.h flonum.h bignum.h expr.h frags.h hash.h read.h symbols.h tc.h obj.h \
+ subsegs.h
+version.o : version.c
+write.o : write.c as.h host.h targ-env.h obj-format.h \
+ targ-cpu.h struc-symbol.h \
+ write.h flonum.h bignum.h expr.h frags.h hash.h read.h symbols.h tc.h obj.h \
+ subsegs.h output-file.h
+xmalloc.o : xmalloc.c
+xrealloc.o : xrealloc.c
+atof-targ.o : atof-targ.c as.h host.h targ-env.h obj-format.h \
+ targ-cpu.h struc-symbol.h \
+ write.h flonum.h bignum.h expr.h frags.h hash.h read.h \
+ symbols.h tc.h obj.h
+obj-format.o : obj-format.c as.h host.h targ-env.h obj-format.h \
+ targ-cpu.h struc-symbol.h \
+ write.h flonum.h bignum.h expr.h frags.h hash.h read.h \
+ symbols.h tc.h obj.h
+targ-cpu.o : targ-cpu.c targ-env.h obj-format.h \
+ targ-cpu.h struc-symbol.h \
+ write.h flonum.h bignum.h expr.h frags.h hash.h read.h \
+ symbols.h tc.h obj.h $(TARG_CPU_DEPENDENTS)
+
+# Remake the info files.
+
+doc: $(srcdir)/as.info
+
+$(srcdir)/as.info: $(srcdir)/doc/as.texinfo
+ (cd doc; make as.info; mv as.info $srcdir)
+
+clean:
+ (cd doc ; $(MAKE) clean)
+ -rm -f $(STAGESTUFF) core
+
+# Like clean but also delete the links made to configure gas.
+distclean: clean
+ -rm -f config.status Makefile host.h targ-env.h targ-cpu.h \
+ targ-cpu.c obj-format.h obj-format.c atof-targ.c \
+ gas.aux gas.cps gas.fns gas.info gas.kys gas.pgs \
+ gas.tps gas.vrs TAGS gas.info* gas.?? gas.??s gas.log \
+ gas.toc gas.*aux *.dvi
+
+# Entry points `install', `includes' and `uninstall'.
+
+# Copy the files into directories where they will be run.
+install:
+ if [ "$(host_alias)" = "$(target_alias)" ] ; then \
+ $(INSTALL_PROGRAM) as.new $(bindir)/as ; \
+ else \
+ $(INSTALL_PROGRAM) as.new $(bindir)/as-$(target_alias) ; \
+ fi
+
+# Create the installation directory.
+install-dir:
+ -mkdir $(libdir)
+ -mkdir $(libdir)/gcc
+ -mkdir $(libdir)/gcc/$(target)
+ -mkdir $(libdir)/gcc/$(target)/$(version)
+
+# Cancel installation by deleting the installed files.
+uninstall:
+ -rm -rf $(libsubdir)
+ -rm -rf $(bindir)/as
+ -rm -rf $(mandir)/gas.$(manext)
+
+
+# These exist for maintenance purposes.
+
+tags TAGS: force
+ etags $(REAL_HEADERS) $(REAL_SOURCES) $(srcdir)/config/*.[hc] $(srcdir)/README $(srcdir)/Makefile.in
+
+bootstrap: as.new force
+ $(MAKE) stage1
+ $(MAKE) CC="$(CC)" CFLAGS="-O -Bstage1/ $(CFLAGS)" libdir=$(libdir) ALLOCA= as.new
+ $(MAKE) stage2
+ $(MAKE) CC="$(CC)" CFLAGS="-O -Bstage2/ $(CFLAGS)" libdir=$(libdir) ALLOCA= as.new
+ $(MAKE) comparison against=stage2
+
+bootstrap2: force
+ $(MAKE) CC="$(CC)" CFLAGS="-O -Bstage1/ $(CFLAGS)" libdir=$(libdir) ALLOCA= as.new
+ $(MAKE) stage2
+ $(MAKE) CC="$(CC)" CFLAGS="-O -Bstage2/ $(CFLAGS)" libdir=$(libdir) ALLOCA= as.new
+ $(MAKE) comparison against=stage2
+
+bootstrap3: force
+ $(MAKE) CC="$(CC)" CFLAGS="-O -Bstage2/ $(CFLAGS)" libdir=$(libdir) ALLOCA= as.new
+ $(MAKE) comparison against=stage2
+
+# Copy the object files from a particular stage into a subdirectory.
+stage1: force
+ -mkdir stage1
+ -mv $(STAGESTUFF) stage1
+ if [ -f stage1/as.new -a ! -f stage1/as ] ; then (cd stage1 ; ln -s as.new as) ; fi
+
+stage2: force
+ -mkdir stage2
+ -mv $(STAGESTUFF) stage2
+ if [ -f stage2/as.new -a ! -f stage2/as ] ; then (cd stage2 ; ln -s as.new as) ; fi
+
+stage3: force
+ -mkdir stage3
+ -mv $(STAGESTUFF) stage3
+ if [ -f stage3/as.new -a ! -f stage3/as ] ; then (cd stage3 ; ln -s as.new as) ; fi
+
+against=stage2
+
+comparison: force
+ for i in $(STAGESTUFF) ; do cmp $$i $(against)/$$i ; done
+
+de-stage1: force
+ - (cd stage1 ; rm as ; mv -f * ..)
+ - rmdir stage1
+
+de-stage2: force
+ - (cd stage2 ; rm as ; mv -f * ..)
+ - rmdir stage2
+
+de-stage3: force
+ - (cd stage3 ; rm as ; mv -f * ..)
+ - rmdir stage3
+
+#In GNU Make, ignore whether `stage*' exists.
+.PHONY: stage1 stage2 stage3 stage4 clean realclean TAGS bootstrap
+
+force:
+
+Makefile: $(srcdir)/Makefile.in $(host_makefile_frag) $(target_makefile_frag)
+ $(SHELL) ./config.status
+
diff --git a/gnu/usr.bin/as/NOTES b/gnu/usr.bin/as/NOTES
new file mode 100644
index 0000000..9f18fac
--- /dev/null
+++ b/gnu/usr.bin/as/NOTES
@@ -0,0 +1,16 @@
+to do:
+
+remove DONTDEF
+remove the ifdef's from fx_callj tests?
+what are callj tests?
+space tighten sparc alignment.
+fix number_to_chars, & family to have no side effects.
+md_ => tp_
+multiple segments.
+share b.out with a.out.
+
+regress:
+
++-inf
+
+stack:
diff --git a/gnu/usr.bin/as/NOTES.config b/gnu/usr.bin/as/NOTES.config
new file mode 100644
index 0000000..a511519
--- /dev/null
+++ b/gnu/usr.bin/as/NOTES.config
@@ -0,0 +1,52 @@
+(This file under construction).
+
+
+ The GAS Configuration Plan
+
+Theory:
+
+The goal of the new configuration scheme is to bury all object format,
+target processor, and host machine dependancies in object, target, and
+host specific files. That is, to move as many #ifdef's as possible
+out of the gas common code.
+
+Here's how it works. There is a .h and a .c file for each object file
+format, a .h and a .c file for each target processor, and a .h for
+each host. configure creates {sym}links in the current directory to
+the appropriate files in the config directory.
+
+Implementation:
+
+host.h is a {sym}link to .../config/ho-yourhost.h. It is intended to
+be used to hide host compiler, system header file, and system library
+differences between host machines. If your host needs actual c source
+files, then either: these are generally useful functions, in which
+case you should probably build a local library outside of the gas
+source tree, or someone, perhaps me, is confused about what is needed
+by different hosts.
+
+obj-format.h is a {sym}link to .../config/obj-something.h. It is
+intended to hide object file format differences from the bulk of gas,
+and from most of the cpu backend.
+
+All gas .c files include as.h.
+
+as.h #define's "gas", includes host.h, defines a number of gas
+specific structures and types, and then includes tp.h, obj.h, and
+target-environment.h.
+
+te-something.h defines a target environment specific preprocessor
+flag, eg, TE_SUN, and then includes obj-format.h.
+
+obj-format.h defines an object format specific preprocessor flag, eg,
+OBJ_AOUT, OBJ_BOUT, OBJ_COFF, includes "target-processor.h", and then
+defines the object specific macros, functions, types, and structures.
+
+target-processor.h
+
+target-processor.
+
+Porting:
+
+There appear to be four major types of ports; new hosts, new target
+processors, new object file formats, and new target environments.
diff --git a/gnu/usr.bin/as/README b/gnu/usr.bin/as/README
new file mode 100644
index 0000000..73b7605
--- /dev/null
+++ b/gnu/usr.bin/as/README
@@ -0,0 +1,212 @@
+This is a pre-alpha version of the GNU assembler, version 1.92.3.
+
+(this is a copy of the mail announcement. Real README follows below.)
+
+This session I merged the m88k support. It configures, builds, and
+assembles things, including some gcc2 output. I have no way of
+knowing if the output is right.
+
+I've merged the tahoe support. It configures and builds. I couldn't
+build the cygnus version of gcc2 for this machine, so I have no idea
+whether gas is assembling anything at all for it.
+
+I've walked through my bug and patch archives. Gas now makes a
+tolerable guess at a.out headers for hpux and sequent, although I have
+no way to know if these are right yet.
+
+Ming tran-le's changes for 386aix will probably drop out soon. He
+needs multiple segments and I don't plan to get that in before the
+real release.
+
+Eric youngdale's help with vms has been invaluable. According to him,
+this gas is doing vms. I didn't quite get a cross to vms working and
+don't plan to spend any more time on it.
+
+The gas manual is included in the distribution, configuration, and
+Makefiles. It should build, be printable, and readable through info.
+
+I have not yet verified that this gas has all of the unreleased
+changes that hack made after the last gas release. At this point I
+plan to ignore these until those bugs are re-reported in an alpha or
+full release I don't think it's worth my time.
+
+I have not yet verified any hosts other than sun4, although I have
+three-staged sun3 native.
+
+I have not updated the configuration doc.
+
+I do not plan to bring in any new backends for the upcoming release
+unless someone hands them to me on a platter as eric did for vms. I
+merged the m88k and tahoe ports because they were simple for me at
+this point, but would have been difficult for someone else. I may yet
+do this for the ncube support as well.
+
+I've looked at the osf stuff and discarded it for this release. I'm
+not sure I like what they've done for macho object format and without
+macho headers, I can't even build their version.
+
+I've looked at the utah stuff and discarded it for this release.
+They, too, have made some sweeping changes to support their object
+format that I'm not sure were necessary. In any case, merging this
+would be too much work for me right now.
+
+I've looked at the tron port. It's remarkably clean and it's a.out
+format. I don't plan to merge this for the full release for two
+reasons. First, it's so clean, they will be able to add their stuff
+on top and build a seperate distribution without much trouble.
+Second, I'm get responses from them, and hope that they will be able
+to do the merge.
+
+
+To do before alpha:
+
+* merge patches and address bugs as they arrive.
+
+* kill a remaining bug. The following input:
+
+ .text
+a .word 3
+b .word 4
+c .half b-a
+
+kills most risc ports. I believe that this represents a failing of
+the internal representation of relocs (aka fixS's). The fix is
+relatively straightforward and I intend to make it.
+
+* add autoconf style configuration for hosts (not targets).
+
+* test via three-staging (preferably with gcc2) on all a.out based
+ machines to which I have access.
+
+* update/clean out README's and build a brief porting guide.
+
+There is still a copyright issue on the coff back end, so it may need
+to be pulled for the full release. If this gets resolved, I hope to
+see coff run personally on at least one native machine before full
+release.
+
+
+Real README:
+
+This is a pre-alpha version of the GNU assembler, version 1.92.3.
+
+A number of things have changed and the wonderful world of gas looks
+very different. There's still a lot of irrelevant garbage lying
+around that will be cleaned up soon. The gas manual now builds and
+installs, but internal documentation is still scarce, as are logs of
+the changes made since the last gas release. My apologies, and I'll
+try to get something useful
+
+At this point I believe gas to be ansi only code for most target
+cpu's. That is, there should be relatively few, if any host system
+dependencies. Most of my recent effort has been spent testing and
+dusting off ports for which Cygnus hasn't had recent need.
+
+Hosting has recently been tested on only:
+
+ sun4
+ sun3
+
+I believe that gas can currently be targetted for:
+
+ sun4
+ sun3
+
+and "ports" for other cpu's and object file formats from the following
+set are probably trivial at this point:
+
+ a.out
+
+ a29k
+ i386
+ i860
+ i960
+ m68k
+ m88k
+ ns32k
+ tahoe
+ sparc
+ vax
+
+I have tested most of these in "generic" a.out configurations so I
+feel pretty confident in them. If anything else works, it's an
+accident.
+
+Some ports now generate object files that are somewhat differently
+shaped, but should be more correct. Specifically:
+
+* Most a.out ports now sort the relocation table in numerically
+ ascending order. In previous versions of gas, the relocation table
+ was sorted in descending order. To get the previous functionality,
+ compile with -DREVERSE_SORT_RELOCS.
+
+* ns32k: The last gas I have from hack simply looks broken for ns32k.
+ I think this one works, but don't have an assembler that I trust
+ against which to compare.
+
+* i386: now uses ".align x" to mean x bytes rather than 2^x bytes. It
+ also pads with the noop instruction rather than zeroes.
+
+In all cases, compiling with -DOLD_GAS will produce an assembler that
+should produce object files that are bitwise identical to the previous
+version of gas.
+
+
+
+ NEW FEATURES!
+
+
+This isn't a complete catalog. I've forgotten what all has been done.
+
+* support for i960, a29k, m88k, and tahoe.
+
+* support for 68030 and 68040, including the ability to limit the
+ instructions that gas will accept. ie, you can assemble for EXACTLY
+ 68000 and no more.
+
+* object file formats have been broken out into separate backends.
+
+* a new "backend" has been created to represent the target
+ environment. That is, gas now mimics various other assemblers
+ rather than creating it's own requirements. A side effect of this
+ is that this version of gas may not behave the same way as previous
+ versions.
+
+* ansi. gas is now strictly ansi code so host ports should be
+ trivial.
+
+
+
+ REPORTING BUGS IN GAS
+
+
+Bugs in THIS RELEASE of gas should be reported directly to
+rich@cygnus.com. NOT to bug-gnu-utils@prep.ai.mit.edu.
+
+If you report a bug in GAS, please remember to include:
+
+A description of exactly what went wrong.
+
+How GAS was configured,
+
+The Operating System GAS was running under.
+
+The options given to GAS.
+
+The actual input file that caused the problem.
+
+It is silly to report a bug in GAS without including an input file for
+GAS. Don't ask us to generate the file just because you made it from
+files you think we have access to.
+
+1. You might be mistaken.
+2. It might take us a lot of time to install things to regenerate that file.
+3. We might get a different file from the one you got, and might not see any
+bug.
+
+To save us these delays and uncertainties, always send the input file
+for the program that failed.
+
+If the input file is very large, and you are on the internet, you may
+want to make it avaliable for anonymous FTP instead of mailing it. If you
+do, include instructions for FTP'ing it in your bug report.
diff --git a/gnu/usr.bin/as/README-vms b/gnu/usr.bin/as/README-vms
new file mode 100644
index 0000000..796c603
--- /dev/null
+++ b/gnu/usr.bin/as/README-vms
@@ -0,0 +1,248 @@
+ This document explains a couple of things that are specific to VMS.
+There are currently two "chapters", the first deals with cross-assembly
+issues, and the second deals with the VMS debugger and GNU-CC.
+
+
+***********************************************************************
+****************** Notes for Cross Assembly with VMS ******************
+***********************************************************************
+
+ If you wish to build gas on a non-VMS system to cross-assemble,
+you should use:
+
+configure ${hosttype} -target=vms
+
+and then follow the usual procedure. The object files generated on
+Unix will be correct from a binary point of view, but the real trick is
+getting them to the VMS machine. The format of the object file is
+a variable-length record, but each record contains binary data. gas
+writes the records in the same format that VMS would expect,
+namely a two-byte count followed by that number of bytes.
+
+ If you try to copy the file to a VMS system using ftp, the ftp
+protocol will screw up the file by looking for nulls (record terminator for
+unix) and it will insert it's own record terminators at that point. This
+will obviously corrupt the file.
+
+ If you try to transfer the file with ftp in binary mode, the
+file itself will not be corrupt, but VMS will think that the file contains
+fixed-length records of 512 bytes. You can use the public-domain FILE
+utility to change this with a command like:
+
+$FILE foo.o/type=variable
+
+If you do not have this utility available, the following program can be
+used to perform this task:
+
+ #include <fab.h>
+
+ #define RME$C_SETRFM 1
+
+ struct FAB * fab;
+
+ main(int argc, char * argv[]){
+ int i, status;
+ fab = (struct FAB*) malloc(sizeof(struct FAB));
+ *fab = cc$rms_fab; /* initialize FAB*/
+ fab->fab$b_fac = FAB$M_PUT;
+ fab->fab$l_fop |= FAB$M_ESC;
+ fab->fab$l_ctx = RME$C_SETRFM;
+ fab->fab$w_ifi = 0;
+ for(i=1;i<argc;i++){
+ printf("Setting %s to variable length records.\n",argv[i]);
+ fab->fab$l_fna = argv[i];
+ fab->fab$b_fns = strlen(argv[i]);
+ status = sys$open(fab,0,0);
+ if((status & 7) != 1) lib$signal(status);
+ fab->fab$b_rfm = FAB$C_VAR;
+ status = sys$modify(fab,0,0);
+ if((status & 7) != 1) lib$signal(status);
+ status = sys$close(fab,0,0);
+ if((status & 7) != 1) lib$signal(status);
+ };
+ }
+
+ If you have NFS running on the VMS system, what you need to do
+depends upon which NFS software you are running on the VMS system. There
+are a number of different TCP/IP packages for VMS available, and only very
+limited testing has been performed. In the tests that has been done so
+far, the contents of the file will always be correct when transferring the
+file via NFS, but the record attributes may or may not be correct.
+
+ One proprietary TCP/IP/NFS package for VMS is known to
+automatically fix the record attributes of the object file if you NFS mount
+a unix disk from the VMS system, and if the file has a ".obj" extension on
+the unix system. Other TCP/IP packages might do this for you as well, but
+they have not been checked.
+
+No matter what method you use to get the file to the VMS system, it is
+always a good idea to check to make sure that it is the correct type by
+doing a "$dir/full" on the object file. The desired record attributes will
+be "None". Undesirable record attributes will be "Stream-LF" or anything
+else.
+
+Once you get the files on the VMS system, you can check their integrity
+with the "$anal/obj" command. (Naturally at some point you should rename
+the .o files to .obj). As far as the debugger is concerned, the records
+will be correct, but the debugger will not be able to find the source files,
+since it only has the file name, and not the full directory specification.
+You must give the debugger some help by telling it which directories to
+search for the individual files - once you have done this you should be
+able to proceed normally.
+
+ It is a good idea to use names for your files which will be valid
+under VMS, since otherwise you will have no way of getting the debugger to
+find the source file when deugging.
+
+The reason for this is that the object file normally contins specific
+information that the debugger can use to positively identify a file, and if
+you are assembling on a unix system this information simply does not exist
+in a meaningful way. You must help the debugger by using the "SET FILE="
+command to tell the debugger where to look for source files. The debugger
+records will be correct, except that the debugger will not be initially
+able to find the source files. You can use the "SET FILE" command to tell
+the debugger where to look for the source files.
+
+I have only tested this with a SVr4 i486 machine, and everything seems to
+work OK, with the limited testing that I have done. Other machines may
+or may not work. You should read the chapters on cross-compilers in the gcc
+manual before fooling with this. Since gas does not need to do any floating
+point arithmetic, the floating point constants that are generated here should
+be correct - the only concern is with constant folding in the main compiler.
+The range and precision of floats and doubles are similar on the 486 (with
+a builtin 80387) and the VAX, although there is a factor of 2 to 4
+difference in the range. The double, as implemented on the 486, is quite
+similar to the G_FLOAT on the VAX.
+
+***********************************************************************
+****************** Notes for using GNU CC with the VMS debugger********
+***********************************************************************
+
+
+ 1) You should be aware that GNU-C, as with any other decent compiler,
+will do things when optimization is turned on that you may not expect.
+Sometimes intermediate results are not written to variables, if they are only
+used in one place, and sometimes variables that are not used at all will not be
+written to the symbol table. Also, parameters to inline functions are often
+inaccessible. You can see the assembly code equivalent by using KP7 in the
+debugger, and from this you can tell if in fact a variable should have the
+value that you expect. You can find out if a variable lives withing a register
+by doing a 'show symbol/addr'.
+
+ 2) Overly complex data types, such as:
+
+int (*(*(*(*(*(* sarr6)[1])[1])[2])[3])[4])[5];
+
+will not be debugged properly, since the debugging record overflows an internal
+debugger buffer. gcc-as will convert these to *void as far as the debugger
+symbol table is concerned, which will avoid any problems, and the assembler
+will give you a message informing you that this has happened.
+
+ 3) You must, of course, compile and link with /debug. If you link
+without debug, you still get traceback table in the executable, but there is no
+symbol table for variables.
+
+ 4) Included in the patches to VMS.C are fixes to two bugs that are
+unrelated to the changes that I have made. One of these made it impossible to
+debug small programs sometimes, and the other caused the debugger to become
+confused about which routine it was in, and give this incorrect info in
+tracebacks.
+
+ 5) If you are using the GNU-C++ compiler, you should modify the
+compiler driver file GNU_CC:[000000]GCC.COM (or GXX.COM). If you have a
+seperate GXX.COM, then you need to change one line in GXX.COM to:
+$ if f$locate("D",p2) .ne. P2_Length then Debug = " ""-G0"""
+ Notice zero---> ^
+If you are using a GCC.COM that does both C and C++, add the following lines to
+GCC.COM:
+
+$!
+$! Use old style debugging records for VMS
+$!
+$ if (Debug.nes."" ).and. Plus then Debug = " ""-G0"""
+
+after the variables Plus and Debug are set. The reason for this, is that C++
+compiler by default generates debugging records that are more complex,
+with many new syntactical elements that allow for the new features of the
+language. The -G0 switch tells the C++ compiler to use the old style debugging
+records. Until the debugger understands C++ there is not any point to try and
+use the expanded syntax.
+
+ 6) When you have nested scopes, i.e.:
+main(){
+ int i;
+ {int i;
+ {int i;
+};};}
+and you say "EXAM i" the debugger needs to figure out which variable you
+actually want to reference. I have arranged things to define a block to the
+debugger when you use brackets to enter a new scope, so in the example above,
+the variables would be described as:
+TEST\main\i
+TEST\main\$0\i
+TEST\main\$0\$0\i
+At each level, the block name is a number with a dollar sign prefix, the
+numbers start with 0 and count upward. When you say EXAM i, the debugger looks
+at the current PC, and decides which block it is currently in. It works from
+the innermost level outward until it finds a block that has the variable "i"
+defined. You can always specify the scope explicitly.
+
+ 7) With C++, there can be a lot of inline functions, and it would be
+rather restrictive to force the user to debug the program by converting all of
+the inline functions to normal functions. What I have done is to essentially
+"add" (with the debugger) source lines from the include files that contain the
+inline functions. Thus when you step into an inline function it appears as if
+you have called the function, and you can examine variables and so forth.
+There are several *very* important differences, however. First of all, since
+there is no function call involved, you cannot step over the inline function
+call - you always step into it. Secondly, since the same source lines are used
+in many locations, there is a seperate copy of the source for *each* usage.
+Without this, breakpoints do not work, since we must have a 1-to-1 mapping
+between source lines and PC.
+ Since you cannot step over inline function calls, it can be a real pain
+if you are not really interested in what is going on for that function call.
+What I have done is to use the "-D" switch for the assembler to toggle the
+following behavior. With the "-D" switch, all inline functions are included in
+the object file, and you can debug everything. Without the "-D" switch
+(default case with VMS implementation), inline functions are included *only* if
+they did not come from system header files (i.e. from GNU_CC_INCLUDE: or
+GNU_GXX_INCLUDE:). Thus, without the switch the user only debugs his/her own
+inline functions, and not the system ones. (This is especially useful if you do
+a lot of stream I/O in C++). This probably will not provide enough granularity
+for many users, but for now this is still somewhat experimental, and I would
+like to reflect upon it and get some feedback before I go any further.
+Possible solutions include an interactive prompting, a logical name, or a new
+command line option in gcc.c (which is then passed through somehow to the guts
+of the assembler).
+ The inline functions from header files appear after the source code
+for the source file. This has the advantage that the source file itself is
+numbered with the same line numbers that you get with an editor. In addition,
+the entire header file is not included, since the assembler makes a list of
+the min and max source lines that are used, and only includes those lines from
+the first to the last actually used. (It is easy to change it to include the
+whole file).
+
+ 8) When you are debugging C++ objects, the object "this" is refered to
+as "$this". Actually, the compiler writes it as ".this", but the period is
+not good for the debugger, so I have a routine to convert it to a $. (It
+actually converts all periods to $, but only for variables, since this was
+intended to allow us to access "this".
+
+ 9) If you use the asm("...") keyword for global symbols, you will not
+be able to see that symbol with the debugger. The reason is that there are two
+records for the symbol stored in the data structures of the assembler. One
+contains the info such as psect number and offset, and the other one contains
+the information having to do with the data type of the variable. In order to
+debug as symbol, you need to be able to coorelate these records, and the only
+way to do this is by name. The record with the storage attributes will take
+the name used in the asm directive, and the record that specifies the data type
+has the actual variable name, and thus when you use the asm directive to change
+a variable name, the symbol becomes invisible.
+
+ 10) Older versions of the compiler ( GNU-C 1.37.92 and earlier) place
+global constants in the text psect. This is unfortunate, since to the linker
+this appears to be an entry point. I sent a patch to the compiler to RMS,
+which will generate a .const section for these variables, and patched the
+assembler to put these variables into a psect just like that for normal
+variables, except that they are marked NOWRT. static constants are still
+placed in the text psect, since there is no need for any external access.
diff --git a/gnu/usr.bin/as/README.coff b/gnu/usr.bin/as/README.coff
new file mode 100644
index 0000000..46c61cd
--- /dev/null
+++ b/gnu/usr.bin/as/README.coff
@@ -0,0 +1,79 @@
+The coff patches intend to do the following :
+
+ . Generate coff files very compatible with vanilla linker.
+ . Understands coff debug directives.
+
+Here are the guidelines of the work I have done :
+
+ . Encapsulate format dependent code in macros where it is possible.
+ . Where not possible differenciate with #ifdef
+ . try not to change the calling conventions of the existing functions.
+ I made one exception : symbol_new. I would be pleased to hear about
+ a better solution. (symbols.c)
+ . Extend the use of N_TYPE_seg seg_N_TYPE tables so that segments can
+ be manipulated without using their format dependent name. (subsegs.c)
+ . Write a function to parse the .def debug directives
+ . Write two small peaces of code to handle the .ln directive.
+ . In write.c try to move all the cross compilation specifics (md_..) to
+ format dependent files.
+ . Encapsulate the data structures using generic types, macros calls.
+ . Added too much code to resolve the complexity of the symbol table
+ generated. Most of the code deals with debug stuff.
+ . Create another makefile, shorter, cleaner.
+ . Create a config.gas shell script to mimic the gcc,gdb... configuration
+ mechanism. This reduce the complexity of the makefile.
+ . Isolate the format dependent code in two files
+ coff.c coff.h
+ aout.c aout.h
+ elf.c elf.h [ Not yet ;-]
+ . added a little stack management routine for coff in file stack.c
+ . isolate os specific flags in m- files
+
+If further development is planed on it is should solve the following problems :
+
+ . Encapsulate DESC & OTHER tests in a macro call. I'm not aware
+ of their exact semantics.
+ . Clean up the seg_N_TYPE N_TYPE_seg naming scheme
+ . Try to remove as much reference to segment dependent names as possible
+ . Find a cleaner solution for symbol_new.
+ . Report the modifications on vax, ns32k, sparc machine dependent files.
+ To acheive this goal, search for \<N_, sy_, symbol_new and symbolS.
+ . Allow an arbitrary number of segments (spare sections .ctor .dtor .bletch)
+ . Find a way to extend the debug information without breaking sdb
+ compatibility. Mainly intended for G++.
+ . should it do something to generate shared libraries objects ?
+
+I have tested this code on the following processor/os. gcc-1.37.1 was
+ used for all the tests.
+
+386 SCO unix ODT
+ gcc-1.37.1, gas, emacs-18.55
+
+386 Esix rev C
+ gas-1.37/write.s
+
+386 Ix 2.02
+ gas, all the X11R4 mit clients
+
+386 CTIX 3.2
+ xsol (X11R4 solitary game), gas
+
+68030 unisoft 1.3
+ the kernel (V.3.2) + tcp/ip extensions
+ bash-1.05, bison-1.11, compress-4.0, cproto, shar-3.49, diff-1.14,
+ dist-18.55, flex-2.3, gas-1.37, gcc-1.37.1, gdb-3.6, grep-1.5,
+ kermit, make-3.58, makedep, patch, printf, makeinfo, g++-1.37.1,
+ tar-1.08, texi2roff, uuencode, uutraf-1.2, libg++-1.37.2, groff-0.5
+
+68020 sunos 3.5 (no, not coff, just to be sure that I didn't
+ introduce errors)
+ gcc-1.37.1, gas, emacs-18.55, gdb-3.6, bison-1.11, diff-1.14,
+ make-3.58, tar-1.08
+
+68030 sunos 4.0.3 (idem)
+ gas
+
+I would be glad to hear about new experiences
+
+ Loic (loic@adesign.uucp or loic@afp.uucp)
+
diff --git a/gnu/usr.bin/as/README.pic b/gnu/usr.bin/as/README.pic
new file mode 100644
index 0000000..adde6fe
--- /dev/null
+++ b/gnu/usr.bin/as/README.pic
@@ -0,0 +1,25 @@
+A few short notes on PIC support.
+
+. References to the symbol "_GLOBAL_OFFSET_TABLE_" are special. These always
+ PC relative to the start of the current instruction. Also, they occur
+ in "complex" expressions in function prologs, eg.
+
+ move _GLOBAL_OFFSET_TABLE_ + (. - L1 ), %some_register
+
+ The expression parser can't handle these generically, so the expression
+ above is recognised as a special case.
+
+. Some archs have special PIC assembler syntax to reference static and global
+ data. This is handled in targ-cpu.c.
+
+. Correct relocation_info must be output (eg. fields r_jmptable and r_baserel).
+
+. Internal labels must be output in the symbol table if they are referred to
+ by PIC instructions. The linker must allocate a GOT slot for them.
+
+. The former meaning of the -k switch ("WORKING_DOT" stuff), has been nuked
+ in favour of enabling PIC code recognition.
+
+
+-pk
+
diff --git a/gnu/usr.bin/as/README.rich b/gnu/usr.bin/as/README.rich
new file mode 100644
index 0000000..5a2ecc4
--- /dev/null
+++ b/gnu/usr.bin/as/README.rich
@@ -0,0 +1,144 @@
+(This file is under construction.)
+
+
+ The Code Pedigree of This Directory
+
+
+This directory contains a big merge of several development lines of
+gas as well as a few bug fixes and some configuration that I've added
+in order to retain my own sanity.
+
+A little history.
+
+The only common baseline of all versions was gas-1.31.
+
+From 1.31, Intel branched off and added:
+
+ support for the Intel 80960 (i960) processor.
+ support for b.out object files.
+ some bug fixes.
+ sloppy mac MPW support
+ Intel gnu/960 makefiles and version numbering.
+
+Many of the bug fixes found their way into the main development line
+prior to 1.36. ALL intel changes were ifdef'd I80960. This was good
+as it isolated the changes, but bad in that it connected the b.out
+support to the i960 support, and bad in that the bug fixes were only
+active in the i960+b.out executables of gas, (although most of these
+were nicely marked with comments indicating that they were probably
+general bug fixes.)
+
+To pick up the main FSF development line again, along the way to 1.36,
+several new processors were added, many bugs fixed, and the world was
+a somewhat better place in general.
+
+From gas-1.36, Loic at Axis Design (france!) encapsulated object
+format specific actions, added coff versions of those encapsulations,
+and a config.gas style configuration and Makefile. This was a big
+change and a lot of work.
+
+Then along came the FIRST FSF release of gas-1.37. I say this because
+there have been at least two releases of gas-1.37. Only two of them
+do we care about for this story, so let's call them gas-1.37.1 and
+gas-1.37.2.
+
+Here starts the confusion. Firstly, gas-1.37.1 did not compile.
+
+In the meantime, John Gilmore at Cygnus Support had been hacking
+gas-1.37.1. He got it to compile. He added support for the AMD 29000
+processor. AND he started encapsulating some of the a.out specific
+pieces of code mostly into functions. AND he rebuilt the relocation
+info to be generic. AND he restructured somewhat so that for a single
+host, cross assemblers could be built for all targets in the same
+directory. Useful work but a considerable nuisance because the a29k
+changes were not partitioned from the encapsulation changes, the
+encapsulation changes were incomplete, and the encapsulation required
+functions where alternate structuring might have used macros. Let's
+call this version gas-1.37.1+a29k.
+
+By the time gas-1.37.2 was "released", (remember that it TOO was
+labelled by FSF as gas-1.37), it compiled, but it also added i860
+support and ansi style const declarations.
+
+At this point, Loic rolled his changes into gas-1.37.2.
+
+What I've done.
+
+I collected all the stray versions of gas that sounded relevant to my
+goals of cross assembly and alternate object file formats and the FSF
+releases from which the stray versions had branched.
+
+I rolled the Intel i960 changes from 1.31 into versions that I call
+1.34+i960, 1.36+i960, and then 1.37.1+i960.
+
+Then I merged 1.37.1+i960 with 1.37.1+a29k to produce what I call
+1.37.1+i960+a29k or 1.37.3.
+
+From 1.37.3, I pulled in Loic's stuff. This wasn't easy as Loic's
+stuff hit all the same points as John's encapsulations. Loic's goal
+was to split the a.out from coff dependancies for native assembly on
+coff, while John's was to split for multiple cross assembly from a
+single host.
+
+Loic's config arranged files much like emacs into m-*, etc. I've
+rearranged these somewhat.
+
+Theory:
+
+The goal of the new configuration scheme is to bury all object format,
+target processor, and host machine dependancies in object, target, and
+host specific files. That is, to move all #ifdef's out of the gas
+common code.
+
+Here's how it works. There is a .h and a .c file for each object file
+format, a .h and a .c file for each target processor, and a .h for
+each host. config.gas creates {sym}links in the current directory to
+the appropriate files in the config directory. config.gas also serves
+as a list of triplets {host, target, object-format} that have been
+tested at one time or another. I also recommend that config.gas be
+used to document triplet specific notes as to purpose of the triplet,
+etc.
+
+Implementation:
+
+host.h is a {sym}link to .../config/xm-yourhost.h. It is intended to
+be used to hide host compiler, system header file, and system library
+differences between host machines. If your host needs actual c source
+files, then either: these are generally useful functions, in which
+case you should probably build a local library outside of the gas
+source tree, or someone, perhaps me, is confused about what is needed
+by different hosts.
+
+obj-format.h is a {sym}link to .../config/obj-something.h. It is intended
+
+All gas .c files include as.h.
+
+as.h #define's "gas", includes host.h, defines a number of gas
+specific structures and types, and then includes tp.h, obj.h, and
+target-environment.h.
+
+target-environment.h defines a target environment specific
+preprocessor flag, eg, TE_SUN, and then includes obj-format.h.
+
+obj-format.h defines an object format specific preprocessor flag, eg,
+OBJ_AOUT, OBJ_BOUT, OBJ_COFF, includes "target-processor.h", and then
+defines the object specific macros, functions, types, and structures.
+
+target-processor.h
+
+target-processor.
+
+Porting:
+
+There appear to be four major types of ports; new hosts, new target
+processors, new object file formats, and new target environments.
+
+
+-----
+
+reloc now stored internally as generic. (symbols too?) (segment types
+vs. names?)
+
+I don't mean to overlook anyone here. There have also been several
+other development lines here that I looked at and elected to bypass.
+Specifically, xxx's stabs in coff stuff was particularly tempting.
diff --git a/gnu/usr.bin/as/VERSION b/gnu/usr.bin/as/VERSION
new file mode 100644
index 0000000..a3f79bb
--- /dev/null
+++ b/gnu/usr.bin/as/VERSION
@@ -0,0 +1 @@
+1.92.3
diff --git a/gnu/usr.bin/as/app.c b/gnu/usr.bin/as/app.c
new file mode 100644
index 0000000..15e88e9
--- /dev/null
+++ b/gnu/usr.bin/as/app.c
@@ -0,0 +1,746 @@
+/* This is the Assembler Pre-Processor
+ Copyright (C) 1987, 1990, 1991, 1992, 1994 Free Software Foundation, Inc.
+
+ This file is part of GAS, the GNU Assembler.
+
+ GAS is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GAS is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GAS; see the file COPYING. If not, write to
+ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* Modified by Allen Wirfs-Brock, Instantiations Inc 2/90 */
+/* App, the assembler pre-processor. This pre-processor strips out excess
+ spaces, turns single-quoted characters into a decimal constant, and turns
+ # <number> <filename> <garbage> into a .line <number>\n.file <filename>
+ pair. This needs better error-handling. */
+
+#ifndef lint
+static char rcsid[] = "$Id: app.c,v 1.3 1994/12/23 22:35:59 nate Exp $";
+#endif
+
+#include <stdio.h>
+#include "as.h" /* For BAD_CASE() only */
+
+#if (__STDC__ != 1)
+#ifndef const
+#define const /* empty */
+#endif
+#endif
+
+static char lex[256];
+static const char symbol_chars[] =
+"$._ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
+
+#define LEX_IS_SYMBOL_COMPONENT 1
+#define LEX_IS_WHITESPACE 2
+#define LEX_IS_LINE_SEPARATOR 3
+#define LEX_IS_COMMENT_START 4
+#define LEX_IS_LINE_COMMENT_START 5
+#define LEX_IS_TWOCHAR_COMMENT_1ST 6
+#define LEX_IS_TWOCHAR_COMMENT_2ND 7
+#define LEX_IS_STRINGQUOTE 8
+#define LEX_IS_COLON 9
+#define LEX_IS_NEWLINE 10
+#define LEX_IS_ONECHAR_QUOTE 11
+#define IS_SYMBOL_COMPONENT(c) (lex[c] == LEX_IS_SYMBOL_COMPONENT)
+#define IS_WHITESPACE(c) (lex[c] == LEX_IS_WHITESPACE)
+#define IS_LINE_SEPARATOR(c) (lex[c] == LEX_IS_LINE_SEPARATOR)
+#define IS_COMMENT(c) (lex[c] == LEX_IS_COMMENT_START)
+#define IS_LINE_COMMENT(c) (lex[c] == LEX_IS_LINE_COMMENT_START)
+#define IS_NEWLINE(c) (lex[c] == LEX_IS_NEWLINE)
+
+static int process_escape PARAMS ((int));
+
+/* FIXME-soon: The entire lexer/parser thingy should be
+ built statically at compile time rather than dynamically
+ each and every time the assembler is run. xoxorich. */
+
+void
+do_scrub_begin ()
+{
+ const char *p;
+
+ lex[' '] = LEX_IS_WHITESPACE;
+ lex['\t'] = LEX_IS_WHITESPACE;
+ lex['\n'] = LEX_IS_NEWLINE;
+ lex[';'] = LEX_IS_LINE_SEPARATOR;
+ lex['"'] = LEX_IS_STRINGQUOTE;
+#ifndef TC_HPPA
+ lex['\''] = LEX_IS_ONECHAR_QUOTE;
+#endif
+ lex[':'] = LEX_IS_COLON;
+
+
+
+#ifdef SINGLE_QUOTE_STRINGS
+ lex['\''] = LEX_IS_STRINGQUOTE;
+#endif
+
+ /* Note that these override the previous defaults, e.g. if ';' is a
+ comment char, then it isn't a line separator. */
+ for (p = symbol_chars; *p; ++p)
+ {
+ lex[(unsigned char) *p] = LEX_IS_SYMBOL_COMPONENT;
+ } /* declare symbol characters */
+
+ for (p = comment_chars; *p; p++)
+ {
+ lex[(unsigned char) *p] = LEX_IS_COMMENT_START;
+ } /* declare comment chars */
+
+ for (p = line_comment_chars; *p; p++)
+ {
+ lex[(unsigned char) *p] = LEX_IS_LINE_COMMENT_START;
+ } /* declare line comment chars */
+
+ for (p = line_separator_chars; *p; p++)
+ {
+ lex[(unsigned char) *p] = LEX_IS_LINE_SEPARATOR;
+ } /* declare line separators */
+
+ /* Only allow slash-star comments if slash is not in use */
+ if (lex['/'] == 0)
+ {
+ lex['/'] = LEX_IS_TWOCHAR_COMMENT_1ST;
+ }
+ /* FIXME-soon. This is a bad hack but otherwise, we can't do
+ c-style comments when '/' is a line comment char. xoxorich. */
+ if (lex['*'] == 0)
+ {
+ lex['*'] = LEX_IS_TWOCHAR_COMMENT_2ND;
+ }
+} /* do_scrub_begin() */
+
+FILE *scrub_file;
+
+int
+scrub_from_file ()
+{
+ return getc (scrub_file);
+}
+
+void
+scrub_to_file (ch)
+ int ch;
+{
+ ungetc (ch, scrub_file);
+} /* scrub_to_file() */
+
+char *scrub_string;
+char *scrub_last_string;
+
+int
+scrub_from_string ()
+{
+ return scrub_string == scrub_last_string ? EOF : *scrub_string++;
+} /* scrub_from_string() */
+
+void
+scrub_to_string (ch)
+ int ch;
+{
+ *--scrub_string = ch;
+} /* scrub_to_string() */
+
+/* Saved state of the scrubber */
+static int state;
+static int old_state;
+static char *out_string;
+static char out_buf[20];
+static int add_newlines = 0;
+
+/* Data structure for saving the state of app across #include's. Note that
+ app is called asynchronously to the parsing of the .include's, so our
+ state at the time .include is interpreted is completely unrelated.
+ That's why we have to save it all. */
+
+struct app_save
+ {
+ int state;
+ int old_state;
+ char *out_string;
+ char out_buf[sizeof (out_buf)];
+ int add_newlines;
+ char *scrub_string;
+ char *scrub_last_string;
+ FILE *scrub_file;
+ };
+
+char *
+app_push ()
+{
+ register struct app_save *saved;
+
+ saved = (struct app_save *) xmalloc (sizeof (*saved));
+ saved->state = state;
+ saved->old_state = old_state;
+ saved->out_string = out_string;
+ memcpy (saved->out_buf, out_buf, sizeof (out_buf));
+ saved->add_newlines = add_newlines;
+ saved->scrub_string = scrub_string;
+ saved->scrub_last_string = scrub_last_string;
+ saved->scrub_file = scrub_file;
+
+ /* do_scrub_begin() is not useful, just wastes time. */
+ return (char *) saved;
+}
+
+void
+app_pop (arg)
+ char *arg;
+{
+ register struct app_save *saved = (struct app_save *) arg;
+
+ /* There is no do_scrub_end (). */
+ state = saved->state;
+ old_state = saved->old_state;
+ out_string = saved->out_string;
+ memcpy (out_buf, saved->out_buf, sizeof (out_buf));
+ add_newlines = saved->add_newlines;
+ scrub_string = saved->scrub_string;
+ scrub_last_string = saved->scrub_last_string;
+ scrub_file = saved->scrub_file;
+
+ free (arg);
+} /* app_pop() */
+
+/* @@ This assumes that \n &c are the same on host and target. This is not
+ necessarily true. */
+static int
+process_escape (ch)
+ int ch;
+{
+ switch (ch)
+ {
+ case 'b':
+ return '\b';
+ case 'f':
+ return '\f';
+ case 'n':
+ return '\n';
+ case 'r':
+ return '\r';
+ case 't':
+ return '\t';
+ case '\'':
+ return '\'';
+ case '"':
+ return '\"';
+ default:
+ return ch;
+ }
+}
+int
+do_scrub_next_char (get, unget)
+ int (*get) ();
+ void (*unget) ();
+{
+ /*State 0: beginning of normal line
+ 1: After first whitespace on line (flush more white)
+ 2: After first non-white (opcode) on line (keep 1white)
+ 3: after second white on line (into operands) (flush white)
+ 4: after putting out a .line, put out digits
+ 5: parsing a string, then go to old-state
+ 6: putting out \ escape in a "d string.
+ 7: After putting out a .appfile, put out string.
+ 8: After putting out a .appfile string, flush until newline.
+ 9: After seeing symbol char in state 3 (keep 1white after symchar)
+ 10: After seeing whitespace in state 9 (keep white before symchar)
+ 11: After seeing a symbol character in state 0 (eg a label definition)
+ -1: output string in out_string and go to the state in old_state
+ -2: flush text until a '*' '/' is seen, then go to state old_state
+ */
+
+ /* I added states 9 and 10 because the MIPS ECOFF assembler uses
+ constructs like ``.loc 1 20''. This was turning into ``.loc
+ 120''. States 9 and 10 ensure that a space is never dropped in
+ between characters which could appear in a identifier. Ian
+ Taylor, ian@cygnus.com.
+
+ I added state 11 so that something like "Lfoo add %r25,%r26,%r27" works
+ correctly on the PA (and any other target where colons are optional).
+ Jeff Law, law@cs.utah.edu. */
+
+ register int ch, ch2 = 0;
+ int not_cpp_line = 0;
+
+ switch (state)
+ {
+ case -1:
+ ch = *out_string++;
+ if (*out_string == 0)
+ {
+ state = old_state;
+ old_state = 3;
+ }
+ return ch;
+
+ case -2:
+ for (;;)
+ {
+ do
+ {
+ ch = (*get) ();
+ }
+ while (ch != EOF && ch != '\n' && ch != '*');
+ if (ch == '\n' || ch == EOF)
+ return ch;
+
+ /* At this point, ch must be a '*' */
+ while ((ch = (*get) ()) == '*')
+ {
+ ;
+ }
+ if (ch == EOF || ch == '/')
+ break;
+ (*unget) (ch);
+ }
+ state = old_state;
+ return ' ';
+
+ case 4:
+ ch = (*get) ();
+ if (ch == EOF || (ch >= '0' && ch <= '9'))
+ return ch;
+ else
+ {
+ while (ch != EOF && IS_WHITESPACE (ch))
+ ch = (*get) ();
+ if (ch == '"')
+ {
+ (*unget) (ch);
+ out_string = "\n\t.appfile ";
+ old_state = 7;
+ state = -1;
+ return *out_string++;
+ }
+ else
+ {
+ while (ch != EOF && ch != '\n')
+ ch = (*get) ();
+ state = 0;
+ return ch;
+ }
+ }
+
+ case 5:
+ ch = (*get) ();
+ if (lex[ch] == LEX_IS_STRINGQUOTE)
+ {
+ state = old_state;
+ return ch;
+ }
+#ifndef NO_STRING_ESCAPES
+ else if (ch == '\\')
+ {
+ state = 6;
+ return ch;
+ }
+#endif
+ else if (ch == EOF)
+ {
+ as_warn ("End of file in string: inserted '\"'");
+ state = old_state;
+ (*unget) ('\n');
+ return '"';
+ }
+ else
+ {
+ return ch;
+ }
+
+ case 6:
+ state = 5;
+ ch = (*get) ();
+ switch (ch)
+ {
+ /* Handle strings broken across lines, by turning '\n' into
+ '\\' and 'n'. */
+ case '\n':
+ (*unget) ('n');
+ add_newlines++;
+ return '\\';
+
+ case '"':
+ case '\\':
+ case 'b':
+ case 'f':
+ case 'n':
+ case 'r':
+ case 't':
+#ifdef BACKSLASH_V
+ case 'v':
+#endif /* BACKSLASH_V */
+ case 'x':
+ case 'X':
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ break;
+#if defined(IGNORE_NONSTANDARD_ESCAPES) | defined(ONLY_STANDARD_ESCAPES)
+ default:
+ as_warn ("Unknown escape '\\%c' in string: Ignored", ch);
+ break;
+#else /* ONLY_STANDARD_ESCAPES */
+ default:
+ /* Accept \x as x for any x */
+ break;
+#endif /* ONLY_STANDARD_ESCAPES */
+
+ case EOF:
+ as_warn ("End of file in string: '\"' inserted");
+ return '"';
+ }
+ return ch;
+
+ case 7:
+ ch = (*get) ();
+ state = 5;
+ old_state = 8;
+ return ch;
+
+ case 8:
+ do
+ ch = (*get) ();
+ while (ch != '\n');
+ state = 0;
+ return ch;
+ }
+
+ /* OK, we are somewhere in states 0 through 4 or 9 through 11 */
+
+ /* flushchar: */
+ ch = (*get) ();
+recycle:
+ if (ch == EOF)
+ {
+ if (state != 0)
+ as_warn ("End of file not at end of a line: Newline inserted.");
+ return ch;
+ }
+
+ switch (lex[ch])
+ {
+ case LEX_IS_WHITESPACE:
+ do
+ /* Preserve a single whitespace character at the beginning of
+ a line. */
+ if (state == 0)
+ {
+ state = 1;
+ return ch;
+ }
+ else
+ ch = (*get) ();
+ while (ch != EOF && IS_WHITESPACE (ch));
+ if (ch == EOF)
+ return ch;
+
+ if (IS_COMMENT (ch)
+ || (state == 0 && IS_LINE_COMMENT (ch))
+ || ch == '/'
+ || IS_LINE_SEPARATOR (ch))
+ {
+ /* cpp never outputs a leading space before the #, so try to
+ avoid being confused. */
+ not_cpp_line = 1;
+ goto recycle;
+ }
+#ifdef MRI
+ (*unget) (ch); /* Put back */
+ return ' '; /* Always return one space at start of line */
+#endif
+
+ /* If we're in state 2 or 11, we've seen a non-white character
+ followed by whitespace. If the next character is ':', this
+ is whitespace after a label name which we *must* ignore. */
+ if ((state == 2 || state == 11) && lex[ch] == LEX_IS_COLON)
+ {
+ state = 1;
+ return ch;
+ }
+
+ switch (state)
+ {
+ case 0:
+ state++;
+ goto recycle; /* Punted leading sp */
+ case 1:
+ /* We can arrive here if we leave a leading whitespace character
+ at the beginning of a line. */
+ goto recycle;
+ case 2:
+ state = 3;
+ (*unget) (ch);
+ return ' '; /* Sp after opco */
+ case 3:
+ goto recycle; /* Sp in operands */
+ case 9:
+ case 10:
+ state = 10; /* Sp after symbol char */
+ goto recycle;
+ case 11:
+ state = 1;
+ (*unget) (ch);
+ return ' '; /* Sp after label definition. */
+ default:
+ BAD_CASE (state);
+ }
+ break;
+
+ case LEX_IS_TWOCHAR_COMMENT_1ST:
+ ch2 = (*get) ();
+ if (ch2 != EOF && lex[ch2] == LEX_IS_TWOCHAR_COMMENT_2ND)
+ {
+ for (;;)
+ {
+ do
+ {
+ ch2 = (*get) ();
+ if (ch2 != EOF && IS_NEWLINE (ch2))
+ add_newlines++;
+ }
+ while (ch2 != EOF &&
+ (lex[ch2] != LEX_IS_TWOCHAR_COMMENT_2ND));
+
+ while (ch2 != EOF &&
+ (lex[ch2] == LEX_IS_TWOCHAR_COMMENT_2ND))
+ {
+ ch2 = (*get) ();
+ }
+
+ if (ch2 == EOF
+ || lex[ch2] == LEX_IS_TWOCHAR_COMMENT_1ST)
+ break;
+ (*unget) (ch);
+ }
+ if (ch2 == EOF)
+ as_warn ("End of file in multiline comment");
+
+ ch = ' ';
+ goto recycle;
+ }
+ else
+ {
+ if (ch2 != EOF)
+ (*unget) (ch2);
+ if (state == 9 || state == 10)
+ state = 3;
+ return ch;
+ }
+ break;
+
+ case LEX_IS_STRINGQUOTE:
+ if (state == 9 || state == 10)
+ old_state = 3;
+ else
+ old_state = state;
+ state = 5;
+ return ch;
+#ifndef MRI
+#ifndef IEEE_STYLE
+ case LEX_IS_ONECHAR_QUOTE:
+ ch = (*get) ();
+ if (ch == EOF)
+ {
+ as_warn ("End-of-file after a one-character quote; \\000 inserted");
+ ch = 0;
+ }
+ if (ch == '\\')
+ {
+ ch = (*get) ();
+ ch = process_escape (ch);
+ }
+ sprintf (out_buf, "%d", (int) (unsigned char) ch);
+
+
+ /* None of these 'x constants for us. We want 'x'. */
+ if ((ch = (*get) ()) != '\'')
+ {
+#ifdef REQUIRE_CHAR_CLOSE_QUOTE
+ as_warn ("Missing close quote: (assumed)");
+#else
+ (*unget) (ch);
+#endif
+ }
+ if (strlen (out_buf) == 1)
+ {
+ return out_buf[0];
+ }
+ if (state == 9 || state == 10)
+ old_state = 3;
+ else
+ old_state = state;
+ state = -1;
+ out_string = out_buf;
+ return *out_string++;
+#endif
+#endif
+ case LEX_IS_COLON:
+ if (state == 9 || state == 10)
+ state = 3;
+ else if (state != 3)
+ state = 1;
+ return ch;
+
+ case LEX_IS_NEWLINE:
+ /* Roll out a bunch of newlines from inside comments, etc. */
+ if (add_newlines)
+ {
+ --add_newlines;
+ (*unget) (ch);
+ }
+ /* fall thru into... */
+
+ case LEX_IS_LINE_SEPARATOR:
+ state = 0;
+ return ch;
+
+ case LEX_IS_LINE_COMMENT_START:
+ if (state == 0) /* Only comment at start of line. */
+ {
+ /* FIXME-someday: The two character comment stuff was badly
+ thought out. On i386, we want '/' as line comment start
+ AND we want C style comments. hence this hack. The
+ whole lexical process should be reworked. xoxorich. */
+ if (ch == '/')
+ {
+ ch2 = (*get) ();
+ if (ch2 == '*')
+ {
+ state = -2;
+ return (do_scrub_next_char (get, unget));
+ }
+ else
+ {
+ (*unget) (ch2);
+ }
+ } /* bad hack */
+
+ if (ch != '#')
+ not_cpp_line = 1;
+
+ do
+ ch = (*get) ();
+ while (ch != EOF && IS_WHITESPACE (ch));
+ if (ch == EOF)
+ {
+ as_warn ("EOF in comment: Newline inserted");
+ return '\n';
+ }
+ if (ch < '0' || ch > '9' || not_cpp_line)
+ {
+ /* Non-numerics: Eat whole comment line */
+ while (ch != EOF && !IS_NEWLINE (ch))
+ ch = (*get) ();
+ if (ch == EOF)
+ as_warn ("EOF in Comment: Newline inserted");
+ state = 0;
+ return '\n';
+ }
+ /* Numerics begin comment. Perhaps CPP `# 123 "filename"' */
+ (*unget) (ch);
+ old_state = 4;
+ state = -1;
+ out_string = "\t.appline ";
+ return *out_string++;
+ }
+
+ /* We have a line comment character which is not at the start of
+ a line. If this is also a normal comment character, fall
+ through. Otherwise treat it as a default character. */
+ if (strchr (comment_chars, ch) == NULL)
+ goto de_fault;
+ /* Fall through. */
+ case LEX_IS_COMMENT_START:
+ do
+ ch = (*get) ();
+ while (ch != EOF && !IS_NEWLINE (ch));
+ if (ch == EOF)
+ as_warn ("EOF in comment: Newline inserted");
+ state = 0;
+ return '\n';
+
+ case LEX_IS_SYMBOL_COMPONENT:
+ if (state == 10)
+ {
+ /* This is a symbol character following another symbol
+ character, with whitespace in between. We skipped the
+ whitespace earlier, so output it now. */
+ (*unget) (ch);
+ state = 3;
+ return ' ';
+ }
+ if (state == 3)
+ state = 9;
+ /* Fall through. */
+ default:
+ de_fault:
+ /* Some relatively `normal' character. */
+ if (state == 0)
+ {
+ state = 11; /* Now seeing label definition */
+ return ch;
+ }
+ else if (state == 1)
+ {
+ state = 2; /* Ditto */
+ return ch;
+ }
+ else if (state == 9)
+ {
+ if (lex[ch] != LEX_IS_SYMBOL_COMPONENT)
+ state = 3;
+ return ch;
+ }
+ else if (state == 10)
+ {
+ state = 3;
+ return ch;
+ }
+ else
+ {
+ return ch; /* Opcode or operands already */
+ }
+ }
+ return -1;
+}
+
+#ifdef TEST
+
+const char comment_chars[] = "|";
+const char line_comment_chars[] = "#";
+
+main ()
+{
+ int ch;
+
+ app_begin ();
+ while ((ch = do_scrub_next_char (stdin)) != EOF)
+ putc (ch, stdout);
+}
+
+as_warn (str)
+ char *str;
+{
+ fputs (str, stderr);
+ putc ('\n', stderr);
+}
+
+#endif
+
+/* end of app.c */
diff --git a/gnu/usr.bin/as/as.1 b/gnu/usr.bin/as/as.1
new file mode 100644
index 0000000..66f7ee5
--- /dev/null
+++ b/gnu/usr.bin/as/as.1
@@ -0,0 +1,271 @@
+.\" Copyright (c) 1991, 1992 Free Software Foundation
+.\" See section COPYING for conditions for redistribution
+.TH as 1 "21 January 1992" "cygnus support" "GNU Development Tools"
+
+.SH NAME
+as \- the portable GNU assembler.
+
+.SH SYNOPSIS
+.na
+.B as
+.RB "[\|" \-a "\||\|" \-al "\||\|" -as\c
+\&\|]
+.RB "[\|" \-D "\|]"
+.RB "[\|" \-f "\|]"
+.RB "[\|" \-I
+.I path\c
+\&\|]
+.RB "[\|" \-k "\|]"
+.RB "[\|" \-L "\|]"
+.RB "[\|" \-o
+.I objfile\c
+\&\|]
+.RB "[\|" \-R "\|]"
+.RB "[\|" \-v "\|]"
+.RB "[\|" \-w "\|]"
+.RB "[\|" \-\^\- "\ |\ " \c
+.I files\c
+\&\|.\|.\|.\|]
+
+.I i960-only options:
+.br
+.RB "[\|" \-ACA "\||\|" \-ACA_A "\||\|" \-ACB\c
+.RB "\||\|" \-ACC "\||\|" \-AKA "\||\|" \-AKB\c
+.RB "\||\|" \-AKC "\||\|" \-AMC "\|]"
+.RB "[\|" \-b "\|]"
+.RB "[\|" \-norelax "\|]"
+
+.I m680x0-only options:
+.br
+.RB "[\|" \-l "\|]"
+.RB "[\|" \-mc68000 "\||\|" \-mc68010 "\||\|" \-mc68020 "\|]"
+.ad b
+
+.SH DESCRIPTION
+GNU \c
+.B as\c
+\& is really a family of assemblers.
+If you use (or have used) the GNU assembler on one architecture, you
+should find a fairly similar environment when you use it on another
+architecture. Each version has much in common with the others,
+including object file formats, most assembler directives (often called
+\c
+.I pseudo-ops)\c
+\& and assembler syntax.
+
+For information on the syntax and pseudo-ops used by GNU \c
+.B as\c
+\&, see `\|\c
+.B as\c
+\|' entry in \c
+.B info \c
+(or the manual \c
+.I
+.I
+Using as: The GNU Assembler\c
+\&).
+
+\c
+.B as\c
+\& is primarily intended to assemble the output of the GNU C
+compiler \c
+.B gcc\c
+\& for use by the linker \c
+.B ld\c
+\&. Nevertheless,
+we've tried to make \c
+.B as\c
+\& assemble correctly everything that the native
+assembler would.
+This doesn't mean \c
+.B as\c
+\& always uses the same syntax as another
+assembler for the same architecture; for example, we know of several
+incompatible versions of 680x0 assembly language syntax.
+
+Each time you run \c
+.B as\c
+\& it assembles exactly one source
+program. The source program is made up of one or more files.
+(The standard input is also a file.)
+
+If \c
+.B as\c
+\& is given no file names it attempts to read one input file
+from the \c
+.B as\c
+\& standard input, which is normally your terminal. You
+may have to type \c
+.B ctl-D\c
+\& to tell \c
+.B as\c
+\& there is no more program
+to assemble. Use `\|\c
+.B \-\^\-\c
+\|' if you need to explicitly name the standard input file
+in your command line.
+
+.B as\c
+\& may write warnings and error messages to the standard error
+file (usually your terminal). This should not happen when \c
+.B as\c
+\& is
+run automatically by a compiler. Warnings report an assumption made so
+that \c
+.B as\c
+\& could keep assembling a flawed program; errors report a
+grave problem that stops the assembly.
+
+.SH OPTIONS
+.TP
+.BR \-a \||\| \-al \||\| \-as
+Turn on assembly listings; `\|\c
+.B \-al\c
+\&\|', listing only, `\|\c
+.B \-as\c
+\&\|', symbols
+only, `\|\c
+.B \-a\c
+\&\|', everything.
+.TP
+.B \-D
+This option is accepted only for script compatibility with calls to
+other assemblers; it has no effect on \c
+.B as\c
+\&.
+.TP
+.B \-f
+``fast''--skip preprocessing (assume source is compiler output).
+.TP
+.BI "\-I\ " path
+Add
+.I path
+to the search list for
+.B .include
+directives.
+.TP
+.B \-k
+Handle position independent code, generated by gcc -fpic.
+.TP
+.B \-L
+Keep (in symbol table) local symbols, starting with `\|\c
+.B L\c
+\|'
+.TP
+.BI "\-o\ " objfile
+Name the object-file output from \c
+.B as
+.TP
+.B \-R
+Fold data section into text section
+.TP
+.B \-v
+Announce \c
+.B as\c
+\& version
+.TP
+.B \-W
+Suppress warning messages
+.TP
+.IR "\-\^\-" "\ |\ " "files\|.\|.\|."
+Source files to assemble, or standard input (\c
+.BR "\-\^\-" ")"
+.TP
+.BI \-A var
+.I
+(When configured for Intel 960.)
+Specify which variant of the 960 architecture is the target.
+.TP
+.B \-b
+.I
+(When configured for Intel 960.)
+Add code to collect statistics about branches taken.
+.TP
+.B \-norelax
+.I
+(When configured for Intel 960.)
+Do not alter compare-and-branch instructions for long displacements;
+error if necessary.
+.TP
+.B \-l
+.I
+(When configured for Motorola 68000).
+.br
+Shorten references to undefined symbols, to one word instead of two.
+.TP
+.BR "\-mc68000" "\||\|" "\-mc68010" "\||\|" "\-mc68020"
+.I
+(When configured for Motorola 68000).
+.br
+Specify what processor in the 68000 family is the target (default 68020)
+
+.PP
+Options may be in any order, and may be
+before, after, or between file names. The order of file names is
+significant.
+
+`\|\c
+.B \-\^\-\c
+\|' (two hyphens) by itself names the standard input file
+explicitly, as one of the files for \c
+.B as\c
+\& to assemble.
+
+Except for `\|\c
+.B \-\^\-\c
+\|' any command line argument that begins with a
+hyphen (`\|\c
+.B \-\c
+\|') is an option. Each option changes the behavior of
+\c
+.B as\c
+\&. No option changes the way another option works. An
+option is a `\|\c
+.B \-\c
+\|' followed by one or more letters; the case of
+the letter is important. All options are optional.
+
+The `\|\c
+.B \-o\c
+\|' option expects exactly one file name to follow. The file
+name may either immediately follow the option's letter (compatible
+with older assemblers) or it may be the next command argument (GNU
+standard).
+
+These two command lines are equivalent:
+.br
+.B
+as\ \ \-o\ \ my\-object\-file.o\ \ mumble.s
+.br
+.B
+as\ \ \-omy\-object\-file.o\ \ mumble.s
+
+.SH "SEE ALSO"
+.RB "`\|" as "\|'"
+entry in
+.B
+info\c
+\&;
+.I
+Using as: The GNU Assembler\c
+\&;
+.BR gcc "(" 1 "),"
+.BR ld "(" 1 ")."
+
+.SH COPYING
+Copyright (c) 1991, 1992 Free Software Foundation, Inc.
+.PP
+Permission is granted to make and distribute verbatim copies of
+this manual provided the copyright notice and this permission notice
+are preserved on all copies.
+.PP
+Permission is granted to copy and distribute modified versions of this
+manual under the conditions for verbatim copying, provided that the
+entire resulting derived work is distributed under the terms of a
+permission notice identical to this one.
+.PP
+Permission is granted to copy and distribute translations of this
+manual into another language, under the above conditions for modified
+versions, except that this permission notice may be included in
+translations approved by the Free Software Foundation instead of in
+the original English.
diff --git a/gnu/usr.bin/as/as.1aout b/gnu/usr.bin/as/as.1aout
new file mode 100644
index 0000000..66f7ee5
--- /dev/null
+++ b/gnu/usr.bin/as/as.1aout
@@ -0,0 +1,271 @@
+.\" Copyright (c) 1991, 1992 Free Software Foundation
+.\" See section COPYING for conditions for redistribution
+.TH as 1 "21 January 1992" "cygnus support" "GNU Development Tools"
+
+.SH NAME
+as \- the portable GNU assembler.
+
+.SH SYNOPSIS
+.na
+.B as
+.RB "[\|" \-a "\||\|" \-al "\||\|" -as\c
+\&\|]
+.RB "[\|" \-D "\|]"
+.RB "[\|" \-f "\|]"
+.RB "[\|" \-I
+.I path\c
+\&\|]
+.RB "[\|" \-k "\|]"
+.RB "[\|" \-L "\|]"
+.RB "[\|" \-o
+.I objfile\c
+\&\|]
+.RB "[\|" \-R "\|]"
+.RB "[\|" \-v "\|]"
+.RB "[\|" \-w "\|]"
+.RB "[\|" \-\^\- "\ |\ " \c
+.I files\c
+\&\|.\|.\|.\|]
+
+.I i960-only options:
+.br
+.RB "[\|" \-ACA "\||\|" \-ACA_A "\||\|" \-ACB\c
+.RB "\||\|" \-ACC "\||\|" \-AKA "\||\|" \-AKB\c
+.RB "\||\|" \-AKC "\||\|" \-AMC "\|]"
+.RB "[\|" \-b "\|]"
+.RB "[\|" \-norelax "\|]"
+
+.I m680x0-only options:
+.br
+.RB "[\|" \-l "\|]"
+.RB "[\|" \-mc68000 "\||\|" \-mc68010 "\||\|" \-mc68020 "\|]"
+.ad b
+
+.SH DESCRIPTION
+GNU \c
+.B as\c
+\& is really a family of assemblers.
+If you use (or have used) the GNU assembler on one architecture, you
+should find a fairly similar environment when you use it on another
+architecture. Each version has much in common with the others,
+including object file formats, most assembler directives (often called
+\c
+.I pseudo-ops)\c
+\& and assembler syntax.
+
+For information on the syntax and pseudo-ops used by GNU \c
+.B as\c
+\&, see `\|\c
+.B as\c
+\|' entry in \c
+.B info \c
+(or the manual \c
+.I
+.I
+Using as: The GNU Assembler\c
+\&).
+
+\c
+.B as\c
+\& is primarily intended to assemble the output of the GNU C
+compiler \c
+.B gcc\c
+\& for use by the linker \c
+.B ld\c
+\&. Nevertheless,
+we've tried to make \c
+.B as\c
+\& assemble correctly everything that the native
+assembler would.
+This doesn't mean \c
+.B as\c
+\& always uses the same syntax as another
+assembler for the same architecture; for example, we know of several
+incompatible versions of 680x0 assembly language syntax.
+
+Each time you run \c
+.B as\c
+\& it assembles exactly one source
+program. The source program is made up of one or more files.
+(The standard input is also a file.)
+
+If \c
+.B as\c
+\& is given no file names it attempts to read one input file
+from the \c
+.B as\c
+\& standard input, which is normally your terminal. You
+may have to type \c
+.B ctl-D\c
+\& to tell \c
+.B as\c
+\& there is no more program
+to assemble. Use `\|\c
+.B \-\^\-\c
+\|' if you need to explicitly name the standard input file
+in your command line.
+
+.B as\c
+\& may write warnings and error messages to the standard error
+file (usually your terminal). This should not happen when \c
+.B as\c
+\& is
+run automatically by a compiler. Warnings report an assumption made so
+that \c
+.B as\c
+\& could keep assembling a flawed program; errors report a
+grave problem that stops the assembly.
+
+.SH OPTIONS
+.TP
+.BR \-a \||\| \-al \||\| \-as
+Turn on assembly listings; `\|\c
+.B \-al\c
+\&\|', listing only, `\|\c
+.B \-as\c
+\&\|', symbols
+only, `\|\c
+.B \-a\c
+\&\|', everything.
+.TP
+.B \-D
+This option is accepted only for script compatibility with calls to
+other assemblers; it has no effect on \c
+.B as\c
+\&.
+.TP
+.B \-f
+``fast''--skip preprocessing (assume source is compiler output).
+.TP
+.BI "\-I\ " path
+Add
+.I path
+to the search list for
+.B .include
+directives.
+.TP
+.B \-k
+Handle position independent code, generated by gcc -fpic.
+.TP
+.B \-L
+Keep (in symbol table) local symbols, starting with `\|\c
+.B L\c
+\|'
+.TP
+.BI "\-o\ " objfile
+Name the object-file output from \c
+.B as
+.TP
+.B \-R
+Fold data section into text section
+.TP
+.B \-v
+Announce \c
+.B as\c
+\& version
+.TP
+.B \-W
+Suppress warning messages
+.TP
+.IR "\-\^\-" "\ |\ " "files\|.\|.\|."
+Source files to assemble, or standard input (\c
+.BR "\-\^\-" ")"
+.TP
+.BI \-A var
+.I
+(When configured for Intel 960.)
+Specify which variant of the 960 architecture is the target.
+.TP
+.B \-b
+.I
+(When configured for Intel 960.)
+Add code to collect statistics about branches taken.
+.TP
+.B \-norelax
+.I
+(When configured for Intel 960.)
+Do not alter compare-and-branch instructions for long displacements;
+error if necessary.
+.TP
+.B \-l
+.I
+(When configured for Motorola 68000).
+.br
+Shorten references to undefined symbols, to one word instead of two.
+.TP
+.BR "\-mc68000" "\||\|" "\-mc68010" "\||\|" "\-mc68020"
+.I
+(When configured for Motorola 68000).
+.br
+Specify what processor in the 68000 family is the target (default 68020)
+
+.PP
+Options may be in any order, and may be
+before, after, or between file names. The order of file names is
+significant.
+
+`\|\c
+.B \-\^\-\c
+\|' (two hyphens) by itself names the standard input file
+explicitly, as one of the files for \c
+.B as\c
+\& to assemble.
+
+Except for `\|\c
+.B \-\^\-\c
+\|' any command line argument that begins with a
+hyphen (`\|\c
+.B \-\c
+\|') is an option. Each option changes the behavior of
+\c
+.B as\c
+\&. No option changes the way another option works. An
+option is a `\|\c
+.B \-\c
+\|' followed by one or more letters; the case of
+the letter is important. All options are optional.
+
+The `\|\c
+.B \-o\c
+\|' option expects exactly one file name to follow. The file
+name may either immediately follow the option's letter (compatible
+with older assemblers) or it may be the next command argument (GNU
+standard).
+
+These two command lines are equivalent:
+.br
+.B
+as\ \ \-o\ \ my\-object\-file.o\ \ mumble.s
+.br
+.B
+as\ \ \-omy\-object\-file.o\ \ mumble.s
+
+.SH "SEE ALSO"
+.RB "`\|" as "\|'"
+entry in
+.B
+info\c
+\&;
+.I
+Using as: The GNU Assembler\c
+\&;
+.BR gcc "(" 1 "),"
+.BR ld "(" 1 ")."
+
+.SH COPYING
+Copyright (c) 1991, 1992 Free Software Foundation, Inc.
+.PP
+Permission is granted to make and distribute verbatim copies of
+this manual provided the copyright notice and this permission notice
+are preserved on all copies.
+.PP
+Permission is granted to copy and distribute modified versions of this
+manual under the conditions for verbatim copying, provided that the
+entire resulting derived work is distributed under the terms of a
+permission notice identical to this one.
+.PP
+Permission is granted to copy and distribute translations of this
+manual into another language, under the above conditions for modified
+versions, except that this permission notice may be included in
+translations approved by the Free Software Foundation instead of in
+the original English.
diff --git a/gnu/usr.bin/as/as.c b/gnu/usr.bin/as/as.c
new file mode 100644
index 0000000..920efb7
--- /dev/null
+++ b/gnu/usr.bin/as/as.c
@@ -0,0 +1,429 @@
+/* as.c - GAS main program.
+ Copyright (C) 1987, 1990, 1991, 1992 Free Software Foundation, Inc.
+
+ This file is part of GAS, the GNU Assembler.
+
+ GAS is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GAS is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GAS; see the file COPYING. If not, write to
+ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/*
+ * Main program for AS; a 32-bit assembler of GNU.
+ * Understands command arguments.
+ * Has a few routines that don't fit in other modules because they
+ * are shared.
+ *
+ *
+ * bugs
+ *
+ * : initialisers
+ * Since no-one else says they will support them in future: I
+ * don't support them now.
+ *
+ */
+#ifndef lint
+static char rcsid[] = "$Id: as.c,v 1.2 1993/11/03 00:51:09 paul Exp $";
+#endif
+
+#include <stdio.h>
+#include <string.h>
+
+#ifdef _POSIX_SOURCE
+#include <sys/types.h> /* For pid_t in signal.h */
+#endif
+#include <signal.h>
+
+#define COMMON
+
+#include "as.h"
+#include "subsegs.h"
+#if __STDC__ == 1
+
+/* This prototype for got_sig() is ansi. If you want
+ anything else, then your compiler is lying to you when
+ it says that it is __STDC__. If you want to change it,
+ #ifdef protect it from those of us with real ansi
+ compilers. */
+
+#define SIGTY void
+
+static void got_sig(int sig);
+static char *stralloc(char *str);
+static void perform_an_assembly_pass(int argc, char **argv);
+
+#else /* __STDC__ */
+
+#ifndef SIGTY
+#define SIGTY int
+#endif
+
+static SIGTY got_sig();
+static char *stralloc(); /* Make a (safe) copy of a string. */
+static void perform_an_assembly_pass();
+
+#endif /* not __STDC__ */
+
+#ifdef DONTDEF
+static char * gdb_symbol_file_name;
+long gdb_begin();
+#endif
+
+int listing; /* true if a listing is wanted */
+
+char *myname; /* argv[0] */
+extern const char version_string[];
+
+int main(argc,argv)
+int argc;
+char **argv;
+{
+ int work_argc; /* variable copy of argc */
+ char **work_argv; /* variable copy of argv */
+ char *arg; /* an arg to program */
+ char a; /* an arg flag (after -) */
+ static const int sig[] = { SIGHUP, SIGINT, SIGPIPE, SIGTERM, 0};
+
+ for (a=0;sig[a] != 0;a++)
+ if (signal(sig[a], SIG_IGN) != SIG_IGN)
+ signal(sig[a], got_sig);
+
+ myname=argv[0];
+ memset(flagseen, '\0', sizeof(flagseen)); /* aint seen nothing yet */
+#ifndef OBJ_DEFAULT_OUTPUT_FILE_NAME
+#define OBJ_DEFAULT_OUTPUT_FILE_NAME "a.out"
+#endif /* OBJ_DEFAULT_OUTPUT_FILE_NAME */
+ out_file_name = OBJ_DEFAULT_OUTPUT_FILE_NAME;
+
+ symbol_begin(); /* symbols.c */
+ subsegs_begin(); /* subsegs.c */
+ read_begin(); /* read.c */
+ md_begin(); /* MACHINE.c */
+ input_scrub_begin(); /* input_scrub.c */
+#ifdef DONTDEF
+ gdb_symbol_file_name = 0;
+#endif
+ /*
+ * Parse arguments, but we are only interested in flags.
+ * When we find a flag, we process it then make it's argv[] NULL.
+ * This helps any future argv[] scanners avoid what we processed.
+ * Since it is easy to do here we interpret the special arg "-"
+ * to mean "use stdin" and we set that argv[] pointing to "".
+ * After we have munged argv[], the only things left are source file
+ * name(s) and ""(s) denoting stdin. These file names are used
+ * (perhaps more than once) later.
+ */
+ /* FIXME-SOMEDAY this should use getopt. */
+ work_argc = argc-1; /* don't count argv[0] */
+ work_argv = argv+1; /* skip argv[0] */
+ for (;work_argc--;work_argv++) {
+ arg = * work_argv; /* work_argv points to this argument */
+
+ if (*arg != '-') /* Filename. We need it later. */
+ continue; /* Keep scanning args looking for flags. */
+ if (arg[1] == '-' && arg[2] == 0) {
+ /* "--" as an argument means read STDIN */
+ /* on this scan, we don't want to think about filenames */
+ * work_argv = ""; /* Code that means 'use stdin'. */
+ continue;
+ }
+ /* This better be a switch. */
+ arg ++; /*->letter. */
+
+ while ((a = * arg) != '\0') {/* scan all the 1-char flags */
+ arg ++; /* arg->after letter. */
+ a &= 0x7F; /* ascii only please */
+ /* if (flagseen[a])
+ as_tsktsk("%s: Flag option - %c has already been seen.", myname, a); */
+ flagseen[a] = 1;
+ switch (a) {
+
+ case 'a':
+ {
+ int loop =1;
+
+ while (loop) {
+ switch (*arg)
+ {
+ case 'l':
+ listing |= LISTING_LISTING;
+ arg++;
+ break;
+ case 's':
+ listing |= LISTING_SYMBOLS;
+ arg++;
+ break;
+ case 'h':
+ listing |= LISTING_HLL;
+ arg++;
+ break;
+
+ case 'n':
+ listing |= LISTING_NOFORM;
+ arg++;
+ break;
+ case 'd':
+ listing |= LISTING_NODEBUG;
+ arg++;
+ break;
+ default:
+ if (!listing)
+ listing= LISTING_DEFAULT;
+ loop = 0;
+ break;
+ }
+ }
+ }
+
+ break;
+
+
+ case 'f':
+ break; /* -f means fast - no need for "app" preprocessor. */
+
+ case 'D':
+ /* DEBUG is implemented: it debugs different */
+ /* things to other people's assemblers. */
+ break;
+
+#ifdef DONTDEF
+ case 'G': /* GNU AS switch: include gdbsyms. */
+ if (*arg) /* Rest of argument is file-name. */
+ gdb_symbol_file_name = stralloc (arg);
+ else if (work_argc) { /* Next argument is file-name. */
+ work_argc --;
+ * work_argv = NULL; /* Not a source file-name. */
+ gdb_symbol_file_name = * ++ work_argv;
+ } else
+ as_warn("%s: I expected a filename after -G", myname);
+ arg = ""; /* Finished with this arg. */
+ break;
+#endif
+
+ case 'I': { /* Include file directory */
+
+ char *temp = NULL;
+ if (*arg)
+ temp = stralloc (arg);
+ else if (work_argc) {
+ * work_argv = NULL;
+ work_argc--;
+ temp = * ++ work_argv;
+ } else
+ as_warn("%s: I expected a filename after -I", myname);
+ add_include_dir (temp);
+ arg = ""; /* Finished with this arg. */
+ break;
+ }
+
+#if 00000
+ case 'k':
+ break;
+#endif
+
+ case 'L': /* -L means keep L* symbols */
+ break;
+
+ case 'o':
+ if (*arg) /* Rest of argument is object file-name. */
+ out_file_name = stralloc (arg);
+ else if (work_argc) { /* Want next arg for a file-name. */
+ * work_argv = NULL; /* This is not a file-name. */
+ work_argc--;
+ out_file_name = * ++ work_argv;
+ } else
+ as_warn("%s: I expected a filename after -o. \"%s\" assumed.", myname, out_file_name);
+ arg = ""; /* Finished with this arg. */
+ break;
+
+ case 'R':
+ /* -R means put data into text segment */
+ break;
+
+ case 'v':
+#ifdef OBJ_VMS
+ {
+ extern char *compiler_version_string;
+ compiler_version_string = arg;
+ }
+#else /* not OBJ_VMS */
+ fprintf(stderr,version_string);
+ if (*arg && strcmp(arg,"ersion"))
+ as_warn("Unknown -v option ignored");
+#endif /* not OBJ_VMS */
+ while (*arg) arg++; /* Skip the rest */
+ break;
+
+ case 'W':
+ /* -W means don't warn about things */
+ case 'X':
+ /* -X means treat warnings as errors */
+ case 'Z':
+ /* -Z means attempt to generate object file even after errors. */
+ break;
+
+ default:
+ --arg;
+ if (md_parse_option(&arg,&work_argc,&work_argv) == 0)
+ as_warn("%s: I don't understand '%c' flag.", myname, a);
+ if (arg && *arg)
+ arg++;
+ break;
+ }
+ }
+ /*
+ * We have just processed a "-..." arg, which was not a
+ * file-name. Smash it so the
+ * things that look for filenames won't ever see it.
+ *
+ * Whatever work_argv points to, it has already been used
+ * as part of a flag, so DON'T re-use it as a filename.
+ */
+ *work_argv = NULL; /* NULL means 'not a file-name' */
+ }
+#ifdef DONTDEF
+ if (gdb_begin(gdb_symbol_file_name) == 0)
+ flagseen['G'] = 0; /* Don't do any gdbsym stuff. */
+#endif
+ /* Here with flags set up in flagseen[]. */
+
+ perform_an_assembly_pass(argc,argv); /* Assemble it. */
+#ifdef TC_I960
+ brtab_emit();
+#endif
+ if (seen_at_least_1_file()
+ && !((had_warnings() && flagseen['Z'])
+ || had_errors() > 0)) {
+ write_object_file(); /* relax() addresses then emit object file */
+ } /* we also check in write_object_file() just before emit. */
+
+ input_scrub_end();
+ md_end(); /* MACHINE.c */
+
+#ifndef NO_LISTING
+ listing_print("");
+#endif
+
+#ifndef HO_VMS
+ return((had_warnings() && flagseen['Z'])
+ || had_errors() > 0); /* WIN */
+#else /* HO_VMS */
+ return(!((had_warnings() && flagseen['Z'])
+ || had_errors() > 0)); /* WIN */
+#endif /* HO_VMS */
+
+} /* main() */
+
+
+/* perform_an_assembly_pass()
+ *
+ * Here to attempt 1 pass over each input file.
+ * We scan argv[*] looking for filenames or exactly "" which is
+ * shorthand for stdin. Any argv that is NULL is not a file-name.
+ * We set need_pass_2 TRUE if, after this, we still have unresolved
+ * expressions of the form (unknown value)+-(unknown value).
+ *
+ * Note the un*x semantics: there is only 1 logical input file, but it
+ * may be a catenation of many 'physical' input files.
+ */
+static void perform_an_assembly_pass(argc, argv)
+int argc;
+char **argv;
+{
+ int saw_a_file = 0;
+ need_pass_2 = 0;
+
+#ifdef MANY_SEGMENTS
+ unsigned int i;
+
+ for (i= SEG_E0; i < SEG_UNKNOWN; i++)
+ {
+ segment_info[i].fix_root = 0;
+ }
+ /* Create the three fixed ones */
+ subseg_new (SEG_E0, 0);
+ subseg_new (SEG_E1, 0);
+ subseg_new (SEG_E2, 0);
+ strcpy(segment_info[SEG_E0].scnhdr.s_name,".text");
+ strcpy(segment_info[SEG_E1].scnhdr.s_name,".data");
+ strcpy(segment_info[SEG_E2].scnhdr.s_name,".bss");
+
+ subseg_new (SEG_E0, 0);
+#else /* not MANY_SEGMENTS */
+ text_fix_root = NULL;
+ data_fix_root = NULL;
+ bss_fix_root = NULL;
+
+ subseg_new (SEG_TEXT, 0);
+#endif /* not MANY_SEGMENTS */
+
+ argv++; /* skip argv[0] */
+ argc--; /* skip argv[0] */
+ while (argc--) {
+ if (*argv) { /* Is it a file-name argument? */
+ saw_a_file++;
+ /* argv->"" if stdin desired, else->filename */
+ read_a_source_file(*argv);
+ }
+ argv++; /* completed that argv */
+ }
+ if (!saw_a_file)
+ read_a_source_file("");
+} /* perform_an_assembly_pass() */
+
+/*
+ * stralloc()
+ *
+ * Allocate memory for a new copy of a string. Copy the string.
+ * Return the address of the new string. Die if there is any error.
+ */
+
+static char *
+ stralloc (str)
+char * str;
+{
+ register char * retval;
+ register long len;
+
+ len = strlen (str) + 1;
+ retval = xmalloc (len);
+ (void) strcpy(retval, str);
+ return(retval);
+}
+
+#ifdef comment
+static void lose() {
+ as_fatal("%s: 2nd pass not implemented - get your code from random(3)", myname);
+ return;
+} /* lose() */
+#endif /* comment */
+
+static SIGTY
+ got_sig(sig)
+int sig;
+{
+ static here_before = 0;
+
+ as_bad("Interrupted by signal %d", sig);
+ if (here_before++)
+ exit(1);
+ return((SIGTY) 0);
+}
+
+/*
+ * Local Variables:
+ * comment-column: 0
+ * fill-column: 131
+ * End:
+ */
+
+/* end of as.c */
diff --git a/gnu/usr.bin/as/as.h b/gnu/usr.bin/as/as.h
new file mode 100644
index 0000000..2e7243d
--- /dev/null
+++ b/gnu/usr.bin/as/as.h
@@ -0,0 +1,424 @@
+/* as.h - global header file
+ Copyright (C) 1987, 1990, 1991, 1992 Free Software Foundation, Inc.
+
+ This file is part of GAS, the GNU Assembler.
+
+ GAS is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GAS is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GAS; see the file COPYING. If not, write to
+ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/*
+ * $Id: as.h,v 1.3 1994/12/23 22:36:01 nate Exp $
+ */
+
+#define GAS 1
+/* #include <ansidecl.h> */
+#include "host.h"
+#include "flonum.h"
+
+#if __STDC__ != 1
+#define volatile /**/
+#ifndef const
+#define const /**/
+#endif /* const */
+#endif /* __STDC__ */
+
+#ifdef __GNUC__
+#define alloca __builtin_alloca
+#define register
+#endif /* __GNUC__ */
+
+#ifndef __LINE__
+#define __LINE__ "unknown"
+#endif /* __LINE__ */
+
+#ifndef __FILE__
+#define __FILE__ "unknown"
+#endif /* __FILE__ */
+
+#ifndef PARAMS
+#if __STDC__ != 1
+#define PARAMS(x) ()
+#else
+#define PARAMS(x) x
+#endif
+#endif /*PARAMS */
+
+/*
+ * I think this stuff is largely out of date. xoxorich.
+ *
+ * CAPITALISED names are #defined.
+ * "lowercaseH" is #defined if "lowercase.h" has been #include-d.
+ * "lowercaseT" is a typedef of "lowercase" objects.
+ * "lowercaseP" is type "pointer to object of type 'lowercase'".
+ * "lowercaseS" is typedef struct ... lowercaseS.
+ *
+ * #define DEBUG to enable all the "know" assertion tests.
+ * #define SUSPECT when debugging.
+ * #define COMMON as "extern" for all modules except one, where you #define
+ * COMMON as "".
+ * If TEST is #defined, then we are testing a module: #define COMMON as "".
+ */
+
+/* These #defines are for parameters of entire assembler. */
+
+/* #define SUSPECT JF remove for speed testing */
+/* These #includes are for type definitions etc. */
+
+#include <stdio.h>
+#include <assert.h>
+#include <string.h>
+
+#define obstack_chunk_alloc xmalloc
+#define obstack_chunk_free xfree
+
+#define xfree free
+
+#define BAD_CASE(value) \
+{ \
+ as_fatal("Case value %d unexpected at line %d of file \"%s\"\n", \
+ value, __LINE__, __FILE__); \
+ }
+
+
+/* These are assembler-wide concepts */
+
+
+#ifndef COMMON
+#ifdef TEST
+#define COMMON /* declare our COMMONs storage here. */
+#else
+#define COMMON extern /* our commons live elswhere */
+#endif
+#endif
+/* COMMON now defined */
+#define DEBUG /* temporary */
+
+#ifdef DEBUG
+#undef NDEBUG
+#ifndef know
+#define know(p) assert(p) /* Verify our assumptions! */
+#endif /* not yet defined */
+#else
+#define know(p) /* know() checks are no-op.ed */
+#endif
+
+/* input_scrub.c */
+
+/*
+ * Supplies sanitised buffers to read.c.
+ * Also understands printing line-number part of error messages.
+ */
+
+
+/* subsegs.c Sub-segments. Also, segment(=expression type)s.*/
+
+/*
+ * This table describes the use of segments as EXPRESSION types.
+ *
+ * X_seg X_add_symbol X_subtract_symbol X_add_number
+ * SEG_ABSENT no (legal) expression
+ * SEG_PASS1 no (defined) "
+ * SEG_BIG * > 32 bits const.
+ * SEG_ABSOLUTE 0
+ * SEG_DATA * 0
+ * SEG_TEXT * 0
+ * SEG_BSS * 0
+ * SEG_UNKNOWN * 0
+ * SEG_DIFFERENCE 0 * 0
+ * SEG_REGISTER *
+ *
+ * The blank fields MUST be 0, and are nugatory.
+ * The '0' fields MAY be 0. The '*' fields MAY NOT be 0.
+ *
+ * SEG_BIG: X_add_number is < 0 if the result is in
+ * generic_floating_point_number. The value is -'c' where c is the
+ * character that introduced the constant. e.g. "0f6.9" will have -'f'
+ * as a X_add_number value.
+ * X_add_number > 0 is a count of how many littlenums it took to
+ * represent a bignum.
+ * SEG_DIFFERENCE:
+ * If segments of both symbols are known, they are the same segment.
+ * X_add_symbol != X_sub_symbol (then we just cancel them, => SEG_ABSOLUTE).
+ */
+
+
+#ifdef MANY_SEGMENTS
+#define N_SEGMENTS 10
+#define SEG_NORMAL(x) ((x) >= SEG_E0 && (x) <= SEG_E9)
+#define SEG_LIST SEG_E0,SEG_E1,SEG_E2,SEG_E3,SEG_E4,SEG_E5,SEG_E6,SEG_E7,SEG_E8,SEG_E9
+#define SEG_DATA SEG_E1
+#define SEG_TEXT SEG_E0
+#define SEG_BSS SEG_E2
+#else
+#define N_SEGMENTS 3
+#define SEG_NORMAL(x) ((x) == SEG_TEXT || (x) == SEG_DATA || (x) == SEG_BSS)
+#define SEG_LIST SEG_TEXT,SEG_DATA,SEG_BSS
+#endif
+
+typedef enum _segT {
+ SEG_ABSOLUTE = 0,
+ SEG_LIST,
+ SEG_UNKNOWN,
+ SEG_ABSENT, /* Mythical Segment (absent): NO expression seen. */
+ SEG_PASS1, /* Mythical Segment: Need another pass. */
+ SEG_GOOF, /* Only happens if AS has a logic error. */
+ /* Invented so we don't crash printing */
+ /* error message involving weird segment. */
+ SEG_BIG, /* Bigger than 32 bits constant. */
+ SEG_DIFFERENCE, /* Mythical Segment: absolute difference. */
+ SEG_DEBUG, /* Debug segment */
+ SEG_NTV, /* Transfert vector preload segment */
+ SEG_PTV, /* Transfert vector postload segment */
+ SEG_REGISTER, /* Mythical: a register-valued expression */
+} segT;
+
+#define SEG_MAXIMUM_ORDINAL (SEG_REGISTER)
+
+typedef int subsegT;
+
+COMMON subsegT now_subseg;
+/* What subseg we are accreting now? */
+
+
+COMMON segT now_seg;
+/* Segment our instructions emit to. */
+/* Only OK values are SEG_TEXT or SEG_DATA. */
+
+
+extern char *const seg_name[];
+extern int section_alignment[];
+
+
+/* relax() */
+
+typedef enum _relax_state {
+ rs_fill, /* Variable chars to be repeated fr_offset times. Fr_symbol
+ unused. Used with fr_offset == 0 for a constant length
+ frag. */
+
+ rs_align, /* Align: Fr_offset: power of 2. 1 variable char: fill
+ character. */
+
+ rs_org, /* Org: Fr_offset, fr_symbol: address. 1 variable char: fill
+ character. */
+
+ rs_machine_dependent,
+
+#ifndef WORKING_DOT_WORD
+ rs_broken_word, /* JF: gunpoint */
+#endif
+} relax_stateT;
+
+/* typedef unsigned char relax_substateT; */
+/* JF this is more likely to leave the end of a struct frag on an align
+ boundry. Be very careful with this. */
+typedef unsigned long relax_substateT;
+
+typedef unsigned long relax_addressT;/* Enough bits for address. */
+/* Still an integer type. */
+
+
+/* frags.c */
+
+/*
+ * A code fragment (frag) is some known number of chars, followed by some
+ * unknown number of chars. Typically the unknown number of chars is an
+ * instruction address whose size is yet unknown. We always know the greatest
+ * possible size the unknown number of chars may become, and reserve that
+ * much room at the end of the frag.
+ * Once created, frags do not change address during assembly.
+ * We chain the frags in (a) forward-linked list(s). The object-file address
+ * of the 1st char of a frag is generally not known until after relax().
+ * Many things at assembly time describe an address by {object-file-address
+ * of a particular frag}+offset.
+
+ BUG: it may be smarter to have a single pointer off to various different
+ notes for different frag kinds. See how code pans
+ */
+struct frag /* a code fragment */
+{
+ unsigned long fr_address; /* Object file address. */
+ struct frag *fr_next; /* Chain forward; ascending address order. */
+ /* Rooted in frch_root. */
+
+ long fr_fix; /* (Fixed) number of chars we know we have. */
+ /* May be 0. */
+ long fr_var; /* (Variable) number of chars after above. */
+ /* May be 0. */
+ struct symbol *fr_symbol; /* For variable-length tail. */
+ long fr_offset; /* For variable-length tail. */
+ char *fr_opcode; /*->opcode low addr byte,for relax()ation*/
+ relax_stateT fr_type; /* What state is my tail in? */
+ relax_substateT fr_subtype;
+ /* These are needed only on the NS32K machines */
+ char fr_pcrel_adjust;
+ char fr_bsr;
+#ifndef NO_LISTING
+ struct list_info_struct *line;
+#endif
+ char fr_literal[1]; /* Chars begin here. */
+ /* One day we will compile fr_literal[0]. */
+};
+#define SIZEOF_STRUCT_FRAG \
+((int)zero_address_frag.fr_literal-(int)&zero_address_frag)
+/* We want to say fr_literal[0] above. */
+
+typedef struct frag fragS;
+
+COMMON fragS *frag_now; /* -> current frag we are building. */
+/* This frag is incomplete. */
+/* It is, however, included in frchain_now. */
+/* Frag_now->fr_fix is bogus. Use: */
+/* Virtual frag_now->fr_fix == obstack_next_free(&frags)-frag_now->fr_literal.*/
+
+COMMON fragS zero_address_frag; /* For foreign-segment symbol fixups. */
+COMMON fragS bss_address_frag; /* For local common (N_BSS segment) fixups. */
+
+/* main program "as.c" (command arguments etc) */
+
+COMMON char
+ flagseen[128]; /* ['x'] TRUE if "-x" seen. */
+
+COMMON char *
+ out_file_name; /* name of emitted object file */
+
+COMMON int need_pass_2; /* TRUE if we need a second pass. */
+
+typedef struct {
+ char * poc_name; /* assembler mnemonic, lower case, no '.' */
+ void (*poc_handler)(); /* Do the work */
+ int poc_val; /* Value to pass to handler */
+} pseudo_typeS;
+
+#if (__STDC__ == 1) & !defined(NO_STDARG)
+
+int had_errors(void);
+int had_warnings(void);
+void as_bad(const char *Format, ...);
+void as_fatal(const char *Format, ...);
+void as_tsktsk(const char *Format, ...);
+void as_warn(const char *Format, ...);
+
+#else
+
+int had_errors();
+int had_warnings();
+void as_bad();
+void as_fatal();
+void as_tsktsk();
+void as_warn();
+
+#endif /* __STDC__ & !NO_STDARG */
+
+#if __STDC__ == 1
+
+char *app_push(void);
+char *atof_ieee(char *str, int what_kind, LITTLENUM_TYPE *words);
+char *input_scrub_include_file(char *filename, char *position);
+char *input_scrub_new_file(char *filename);
+char *input_scrub_next_buffer(char **bufp);
+char *strstr(const char *s, const char *wanted);
+char *xmalloc(int size);
+char *xrealloc(char *ptr, long n);
+int do_scrub_next_char(int (*get)(), void (*unget)());
+int gen_to_words(LITTLENUM_TYPE *words, int precision, long exponent_bits);
+int had_err(void);
+int had_errors(void);
+int had_warnings(void);
+int ignore_input(void);
+int scrub_from_file(void);
+int scrub_from_file(void);
+int scrub_from_string(void);
+int seen_at_least_1_file(void);
+void app_pop(char *arg);
+void as_howmuch(FILE *stream);
+void as_perror(const char *gripe, const char *filename);
+void as_where(char **, unsigned int *);
+void bump_line_counters(void);
+void do_scrub_begin(void);
+void input_scrub_begin(void);
+void input_scrub_close(void);
+void input_scrub_end(void);
+void int_to_gen(long x);
+void new_logical_line(char *fname, int line_number);
+void scrub_to_file(int ch);
+void scrub_to_string(int ch);
+void subseg_change(segT seg, int subseg);
+void subseg_new(segT seg, subsegT subseg);
+void subsegs_begin(void);
+
+#else /* not __STDC__ */
+
+char *app_push();
+char *atof_ieee();
+char *input_scrub_include_file();
+char *input_scrub_new_file();
+char *input_scrub_next_buffer();
+char *strstr();
+char *xmalloc();
+char *xrealloc();
+int do_scrub_next_char();
+int gen_to_words();
+int had_err();
+int had_errors();
+int had_warnings();
+int ignore_input();
+int scrub_from_file();
+int scrub_from_file();
+int scrub_from_string();
+int seen_at_least_1_file();
+void app_pop();
+void as_howmuch();
+void as_perror();
+void as_where();
+void bump_line_counters();
+void do_scrub_begin();
+void input_scrub_begin();
+void input_scrub_close();
+void input_scrub_end();
+void int_to_gen();
+void new_logical_line();
+void scrub_to_file();
+void scrub_to_string();
+void subseg_change();
+void subseg_new();
+void subsegs_begin();
+
+#endif /* not __STDC__ */
+
+/* this one starts the chain of target dependant headers */
+#include "targ-env.h"
+
+/* these define types needed by the interfaces */
+#include "struc-symbol.h"
+#include "write.h"
+#include "expr.h"
+#include "frags.h"
+#include "hash.h"
+#include "read.h"
+#include "symbols.h"
+
+#include "tc.h"
+#include "obj.h"
+
+#include "listing.h"
+
+/*
+ * Local Variables:
+ * comment-column: 0
+ * fill-column: 131
+ * End:
+ */
+
+/* end of as.h */
diff --git a/gnu/usr.bin/as/atof-generic.c b/gnu/usr.bin/as/atof-generic.c
new file mode 100644
index 0000000..47a58b1
--- /dev/null
+++ b/gnu/usr.bin/as/atof-generic.c
@@ -0,0 +1,526 @@
+/* atof_generic.c - turn a string of digits into a Flonum
+ Copyright (C) 1987, 1990, 1991, 1992 Free Software Foundation, Inc.
+
+ This file is part of GAS, the GNU Assembler.
+
+ GAS is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GAS is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GAS; see the file COPYING. If not, write to
+ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#ifndef lint
+static char rcsid[] = "$Id: atof-generic.c,v 1.2 1993/11/03 00:51:14 paul Exp $";
+#endif
+
+#include <ctype.h>
+#include <string.h>
+
+#include "as.h"
+
+#ifdef __GNUC__
+#define alloca __builtin_alloca
+#else
+#ifdef sparc
+#include <alloca.h>
+#endif
+#endif
+
+/* #define FALSE (0) */
+/* #define TRUE (1) */
+
+/***********************************************************************\
+ * *
+ * Given a string of decimal digits , with optional decimal *
+ * mark and optional decimal exponent (place value) of the *
+ * lowest_order decimal digit: produce a floating point *
+ * number. The number is 'generic' floating point: our *
+ * caller will encode it for a specific machine architecture. *
+ * *
+ * Assumptions *
+ * uses base (radix) 2 *
+ * this machine uses 2's complement binary integers *
+ * target flonums use " " " " *
+ * target flonums exponents fit in a long *
+ * *
+ \***********************************************************************/
+
+/*
+
+ Syntax:
+
+ <flonum> ::= <optional-sign> <decimal-number> <optional-exponent>
+ <optional-sign> ::= '+' | '-' | {empty}
+ <decimal-number> ::= <integer>
+ | <integer> <radix-character>
+ | <integer> <radix-character> <integer>
+ | <radix-character> <integer>
+
+ <optional-exponent> ::= {empty}
+ | <exponent-character> <optional-sign> <integer>
+
+ <integer> ::= <digit> | <digit> <integer>
+ <digit> ::= '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9'
+ <exponent-character> ::= {one character from "string_of_decimal_exponent_marks"}
+ <radix-character> ::= {one character from "string_of_decimal_marks"}
+
+ */
+
+int /* 0 if OK */
+ atof_generic (
+ address_of_string_pointer, /* return pointer to just
+ AFTER number we read. */
+ string_of_decimal_marks, /* At most one per number. */
+ string_of_decimal_exponent_marks,
+ address_of_generic_floating_point_number)
+char **address_of_string_pointer;
+const char *string_of_decimal_marks;
+const char *string_of_decimal_exponent_marks;
+FLONUM_TYPE *address_of_generic_floating_point_number;
+{
+ int return_value; /* 0 means OK. */
+ char * first_digit;
+ /* char *last_digit; JF unused */
+ int number_of_digits_before_decimal;
+ int number_of_digits_after_decimal;
+ long decimal_exponent;
+ int number_of_digits_available;
+ char digits_sign_char;
+
+ /*
+ * Scan the input string, abstracting (1)digits (2)decimal mark (3) exponent.
+ * It would be simpler to modify the string, but we don't; just to be nice
+ * to caller.
+ * We need to know how many digits we have, so we can allocate space for
+ * the digits' value.
+ */
+
+ char *p;
+ char c;
+ int seen_significant_digit;
+
+ first_digit = *address_of_string_pointer;
+ c = *first_digit;
+
+ if (c == '-' || c == '+') {
+ digits_sign_char = c;
+ first_digit++;
+ } else
+ digits_sign_char = '+';
+
+ if ((first_digit[0] == 'n' || first_digit[0] == 'N')
+ && (first_digit[1] == 'a' || first_digit[1] == 'A')
+ && (first_digit[2] == 'n' || first_digit[2] == 'N')) {
+ address_of_generic_floating_point_number->sign = 0;
+ address_of_generic_floating_point_number->exponent = 0;
+ address_of_generic_floating_point_number->leader =
+ address_of_generic_floating_point_number->low;
+ *address_of_string_pointer = first_digit + 3;
+ return(0);
+ }
+
+ /* 99e999 is a "special" token to some older, broken compilers. */
+ if ((first_digit[0] == 'i' || first_digit[0] == 'I')
+ && (first_digit[1] == 'n' || first_digit[1] == 'N')
+ && (first_digit[2] == 'f' || first_digit[2] == 'F')) {
+ address_of_generic_floating_point_number->sign =
+ digits_sign_char == '+' ? 'P' : 'N';
+ address_of_generic_floating_point_number->exponent = 0;
+ address_of_generic_floating_point_number->leader =
+ address_of_generic_floating_point_number->low;
+
+ if ((first_digit[3] == 'i' || first_digit[3] == 'I')
+ && (first_digit[4] == 'n' || first_digit[4] == 'N')
+ && (first_digit[5] == 'i' || first_digit[5] == 'I')
+ && (first_digit[6] == 't' || first_digit[6] == 'T')
+ && (first_digit[7] == 'y' || first_digit[7] == 'Y')) {
+ *address_of_string_pointer = first_digit + 8;
+ } else {
+ *address_of_string_pointer = first_digit + 3;
+ }
+ return(0);
+ }
+
+ if (strncmp(first_digit, "99e999", 6) == 0) {
+ address_of_generic_floating_point_number->sign =
+ digits_sign_char == '+' ? 'P' : 'N';
+ address_of_generic_floating_point_number->exponent = 0;
+ address_of_generic_floating_point_number->leader =
+ address_of_generic_floating_point_number->low;
+ *address_of_string_pointer = first_digit + 6;
+ return(0);
+ }
+
+ number_of_digits_before_decimal = 0;
+ number_of_digits_after_decimal = 0;
+ decimal_exponent = 0;
+ seen_significant_digit = 0;
+ for (p = first_digit; (((c = * p) != '\0')
+ && (!c || ! strchr(string_of_decimal_marks, c))
+ && (!c || !strchr(string_of_decimal_exponent_marks, c)));
+ p++) {
+ if (isdigit(c)) {
+ if (seen_significant_digit || c > '0') {
+ ++number_of_digits_before_decimal;
+ seen_significant_digit = 1;
+ } else {
+ first_digit++;
+ }
+ } else {
+ break; /* p -> char after pre-decimal digits. */
+ }
+ } /* For each digit before decimal mark. */
+
+#ifndef OLD_FLOAT_READS
+ /* Ignore trailing 0's after the decimal point. The original code here
+ * (ifdef'd out) does not do this, and numbers like
+ * 4.29496729600000000000e+09 (2**31)
+ * come out inexact for some reason related to length of the digit
+ * string.
+ */
+ if (c && strchr(string_of_decimal_marks, c)) {
+ int zeros = 0; /* Length of current string of zeros */
+
+ for (p++; (c = *p) && isdigit(c); p++) {
+ if (c == '0') {
+ zeros++;
+ } else {
+ number_of_digits_after_decimal += 1 + zeros;
+ zeros = 0;
+ }
+ }
+ }
+#else
+ if (c && strchr(string_of_decimal_marks, c)) {
+ for (p++; (((c = *p) != '\0')
+ && (!c || !strchr(string_of_decimal_exponent_marks, c)));
+ p++) {
+ if (isdigit(c)) {
+ number_of_digits_after_decimal++; /* This may be retracted below. */
+ if (/* seen_significant_digit || */ c > '0') {
+ seen_significant_digit = TRUE;
+ }
+ } else {
+ if (!seen_significant_digit) {
+ number_of_digits_after_decimal = 0;
+ }
+ break;
+ }
+ } /* For each digit after decimal mark. */
+ }
+
+ while (number_of_digits_after_decimal && first_digit[number_of_digits_before_decimal
+ + number_of_digits_after_decimal] == '0')
+ --number_of_digits_after_decimal;
+ /* last_digit = p; JF unused */
+#endif
+
+ if (c && strchr(string_of_decimal_exponent_marks, c) ) {
+ char digits_exponent_sign_char;
+
+ c = *++p;
+ if (c && strchr ("+-",c)) {
+ digits_exponent_sign_char = c;
+ c = *++p;
+ } else {
+ digits_exponent_sign_char = '+';
+ }
+
+ for ( ; (c); c = *++p) {
+ if (isdigit(c)) {
+ decimal_exponent = decimal_exponent * 10 + c - '0';
+ /*
+ * BUG! If we overflow here, we lose!
+ */
+ } else {
+ break;
+ }
+ }
+
+ if (digits_exponent_sign_char == '-') {
+ decimal_exponent = -decimal_exponent;
+ }
+ }
+
+ *address_of_string_pointer = p;
+
+
+
+ number_of_digits_available =
+ number_of_digits_before_decimal + number_of_digits_after_decimal;
+ return_value = 0;
+ if (number_of_digits_available == 0) {
+ address_of_generic_floating_point_number->exponent = 0; /* Not strictly necessary */
+ address_of_generic_floating_point_number->leader
+ = -1 + address_of_generic_floating_point_number->low;
+ address_of_generic_floating_point_number->sign = digits_sign_char;
+ /* We have just concocted (+/-)0.0E0 */
+
+ } else {
+ int count; /* Number of useful digits left to scan. */
+
+ LITTLENUM_TYPE *digits_binary_low;
+ int precision;
+ int maximum_useful_digits;
+ int number_of_digits_to_use;
+ int more_than_enough_bits_for_digits;
+ int more_than_enough_littlenums_for_digits;
+ int size_of_digits_in_littlenums;
+ int size_of_digits_in_chars;
+ FLONUM_TYPE power_of_10_flonum;
+ FLONUM_TYPE digits_flonum;
+
+ precision = (address_of_generic_floating_point_number->high
+ - address_of_generic_floating_point_number->low
+ + 1); /* Number of destination littlenums. */
+
+ /* Includes guard bits (two littlenums worth) */
+ maximum_useful_digits = (((double) (precision - 2))
+ * ((double) (LITTLENUM_NUMBER_OF_BITS))
+ / (LOG_TO_BASE_2_OF_10))
+ + 2; /* 2 :: guard digits. */
+
+ if (number_of_digits_available > maximum_useful_digits) {
+ number_of_digits_to_use = maximum_useful_digits;
+ } else {
+ number_of_digits_to_use = number_of_digits_available;
+ }
+
+ decimal_exponent += number_of_digits_before_decimal - number_of_digits_to_use;
+
+ more_than_enough_bits_for_digits
+ = ((((double)number_of_digits_to_use) * LOG_TO_BASE_2_OF_10) + 1);
+
+ more_than_enough_littlenums_for_digits
+ = (more_than_enough_bits_for_digits
+ / LITTLENUM_NUMBER_OF_BITS)
+ + 2;
+
+ /*
+ * Compute (digits) part. In "12.34E56" this is the "1234" part.
+ * Arithmetic is exact here. If no digits are supplied then
+ * this part is a 0 valued binary integer.
+ * Allocate room to build up the binary number as littlenums.
+ * We want this memory to disappear when we leave this function.
+ * Assume no alignment problems => (room for n objects) ==
+ * n * (room for 1 object).
+ */
+
+ size_of_digits_in_littlenums = more_than_enough_littlenums_for_digits;
+ size_of_digits_in_chars = size_of_digits_in_littlenums
+ * sizeof(LITTLENUM_TYPE);
+
+ digits_binary_low = (LITTLENUM_TYPE *)
+ alloca(size_of_digits_in_chars);
+
+ memset((char *)digits_binary_low, '\0', size_of_digits_in_chars);
+
+ /* Digits_binary_low[] is allocated and zeroed. */
+
+ /*
+ * Parse the decimal digits as if * digits_low was in the units position.
+ * Emit a binary number into digits_binary_low[].
+ *
+ * Use a large-precision version of:
+ * (((1st-digit) * 10 + 2nd-digit) * 10 + 3rd-digit ...) * 10 + last-digit
+ */
+
+ for (p = first_digit, count = number_of_digits_to_use; count; p++, --count) {
+ c = *p;
+ if (isdigit(c)) {
+ /*
+ * Multiply by 10. Assume can never overflow.
+ * Add this digit to digits_binary_low[].
+ */
+
+ long carry;
+ LITTLENUM_TYPE *littlenum_pointer;
+ LITTLENUM_TYPE *littlenum_limit;
+
+ littlenum_limit = digits_binary_low
+ + more_than_enough_littlenums_for_digits
+ - 1;
+
+ carry = c - '0'; /* char -> binary */
+
+ for (littlenum_pointer = digits_binary_low;
+ littlenum_pointer <= littlenum_limit;
+ littlenum_pointer++) {
+ long work;
+
+ work = carry + 10 * (long) (*littlenum_pointer);
+ *littlenum_pointer = work & LITTLENUM_MASK;
+ carry = work >> LITTLENUM_NUMBER_OF_BITS;
+ }
+
+ if (carry != 0) {
+ /*
+ * We have a GROSS internal error.
+ * This should never happen.
+ */
+ as_fatal("failed sanity check."); /* RMS prefers abort() to any message. */
+ }
+ } else {
+ ++ count; /* '.' doesn't alter digits used count. */
+ } /* if valid digit */
+ } /* for each digit */
+
+
+ /*
+ * Digits_binary_low[] properly encodes the value of the digits.
+ * Forget about any high-order littlenums that are 0.
+ */
+ while (digits_binary_low[size_of_digits_in_littlenums - 1] == 0
+ && size_of_digits_in_littlenums >= 2)
+ size_of_digits_in_littlenums--;
+
+ digits_flonum.low = digits_binary_low;
+ digits_flonum.high = digits_binary_low + size_of_digits_in_littlenums - 1;
+ digits_flonum.leader = digits_flonum.high;
+ digits_flonum.exponent = 0;
+ /*
+ * The value of digits_flonum.sign should not be important.
+ * We have already decided the output's sign.
+ * We trust that the sign won't influence the other parts of the number!
+ * So we give it a value for these reasons:
+ * (1) courtesy to humans reading/debugging
+ * these numbers so they don't get excited about strange values
+ * (2) in future there may be more meaning attached to sign,
+ * and what was
+ * harmless noise may become disruptive, ill-conditioned (or worse)
+ * input.
+ */
+ digits_flonum.sign = '+';
+
+ {
+ /*
+ * Compute the mantssa (& exponent) of the power of 10.
+ * If sucessful, then multiply the power of 10 by the digits
+ * giving return_binary_mantissa and return_binary_exponent.
+ */
+
+ LITTLENUM_TYPE *power_binary_low;
+ int decimal_exponent_is_negative;
+ /* This refers to the "-56" in "12.34E-56". */
+ /* FALSE: decimal_exponent is positive (or 0) */
+ /* TRUE: decimal_exponent is negative */
+ FLONUM_TYPE temporary_flonum;
+ LITTLENUM_TYPE *temporary_binary_low;
+ int size_of_power_in_littlenums;
+ int size_of_power_in_chars;
+
+ size_of_power_in_littlenums = precision;
+ /* Precision has a built-in fudge factor so we get a few guard bits. */
+
+ decimal_exponent_is_negative = decimal_exponent < 0;
+ if (decimal_exponent_is_negative) {
+ decimal_exponent = -decimal_exponent;
+ }
+
+ /* From now on: the decimal exponent is > 0. Its sign is seperate. */
+
+ size_of_power_in_chars = size_of_power_in_littlenums
+ * sizeof(LITTLENUM_TYPE) + 2;
+
+ power_binary_low = (LITTLENUM_TYPE *) alloca(size_of_power_in_chars);
+ temporary_binary_low = (LITTLENUM_TYPE *) alloca(size_of_power_in_chars);
+ memset((char *)power_binary_low, '\0', size_of_power_in_chars);
+ * power_binary_low = 1;
+ power_of_10_flonum.exponent = 0;
+ power_of_10_flonum.low = power_binary_low;
+ power_of_10_flonum.leader = power_binary_low;
+ power_of_10_flonum.high = power_binary_low + size_of_power_in_littlenums - 1;
+ power_of_10_flonum.sign = '+';
+ temporary_flonum.low = temporary_binary_low;
+ temporary_flonum.high = temporary_binary_low + size_of_power_in_littlenums - 1;
+ /*
+ * (power) == 1.
+ * Space for temporary_flonum allocated.
+ */
+
+ /*
+ * ...
+ *
+ * WHILE more bits
+ * DO find next bit (with place value)
+ * multiply into power mantissa
+ * OD
+ */
+ {
+ int place_number_limit;
+ /* Any 10^(2^n) whose "n" exceeds this */
+ /* value will fall off the end of */
+ /* flonum_XXXX_powers_of_ten[]. */
+ int place_number;
+ const FLONUM_TYPE *multiplicand; /* -> 10^(2^n) */
+
+ place_number_limit = table_size_of_flonum_powers_of_ten;
+
+ multiplicand = (decimal_exponent_is_negative
+ ? flonum_negative_powers_of_ten
+ : flonum_positive_powers_of_ten);
+
+ for (place_number = 1; /* Place value of this bit of exponent. */
+ decimal_exponent; /* Quit when no more 1 bits in exponent. */
+ decimal_exponent >>= 1, place_number++) {
+ if (decimal_exponent & 1) {
+ if (place_number > place_number_limit) {
+ /*
+ * The decimal exponent has a magnitude so great that
+ * our tables can't help us fragment it. Although this
+ * routine is in error because it can't imagine a
+ * number that big, signal an error as if it is the
+ * user's fault for presenting such a big number.
+ */
+ return_value = ERROR_EXPONENT_OVERFLOW;
+ /*
+ * quit out of loop gracefully
+ */
+ decimal_exponent = 0;
+ } else {
+#ifdef TRACE
+ printf("before multiply, place_number = %d., power_of_10_flonum:\n",
+ place_number);
+
+ flonum_print(&power_of_10_flonum);
+ (void)putchar('\n');
+#endif
+ flonum_multip(multiplicand + place_number,
+ &power_of_10_flonum, &temporary_flonum);
+ flonum_copy(&temporary_flonum, &power_of_10_flonum);
+ } /* If this bit of decimal_exponent was computable.*/
+ } /* If this bit of decimal_exponent was set. */
+ } /* For each bit of binary representation of exponent */
+#ifdef TRACE
+ printf(" after computing power_of_10_flonum: ");
+ flonum_print(&power_of_10_flonum );
+ (void) putchar('\n');
+#endif
+ }
+
+ }
+
+ /*
+ * power_of_10_flonum is power of ten in binary (mantissa) , (exponent).
+ * It may be the number 1, in which case we don't NEED to multiply.
+ *
+ * Multiply (decimal digits) by power_of_10_flonum.
+ */
+
+ flonum_multip(&power_of_10_flonum, &digits_flonum, address_of_generic_floating_point_number);
+ /* Assert sign of the number we made is '+'. */
+ address_of_generic_floating_point_number->sign = digits_sign_char;
+
+ } /* If we had any significant digits. */
+ return(return_value);
+} /* atof_generic () */
+
+/* end of atof_generic.c */
diff --git a/gnu/usr.bin/as/bignum-copy.c b/gnu/usr.bin/as/bignum-copy.c
new file mode 100644
index 0000000..ec90e39
--- /dev/null
+++ b/gnu/usr.bin/as/bignum-copy.c
@@ -0,0 +1,76 @@
+/* bignum_copy.c - copy a bignum
+ Copyright (C) 1987, 1990, 1991, 1992 Free Software Foundation, Inc.
+
+ This file is part of GAS, the GNU Assembler.
+
+ GAS is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GAS is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GAS; see the file COPYING. If not, write to
+ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#ifndef lint
+static char rcsid[] = "$Id: bignum-copy.c,v 1.2 1993/11/03 00:51:16 paul Exp $";
+#endif
+
+#include "as.h"
+
+/*
+ * bignum_copy ()
+ *
+ * Copy a bignum from in to out.
+ * If the output is shorter than the input, copy lower-order littlenums.
+ * Return 0 or the number of significant littlenums dropped.
+ * Assumes littlenum arrays are densely packed: no unused chars between
+ * the littlenums. Uses memcpy() to move littlenums, and wants to
+ * know length (in chars) of the input bignum.
+ */
+
+/* void */
+int
+ bignum_copy(in, in_length, out, out_length)
+register LITTLENUM_TYPE *in;
+register int in_length; /* in sizeof(littlenum)s */
+register LITTLENUM_TYPE *out;
+register int out_length; /* in sizeof(littlenum)s */
+{
+ int significant_littlenums_dropped;
+
+ if (out_length < in_length) {
+ LITTLENUM_TYPE *p; /* -> most significant (non-zero) input
+ littlenum. */
+
+ memcpy((void *) out, (void *) in,
+ out_length << LITTLENUM_SHIFT);
+ for (p = in + in_length - 1; p >= in; --p) {
+ if (* p) break;
+ }
+ significant_littlenums_dropped = p - in - in_length + 1;
+
+ if (significant_littlenums_dropped < 0) {
+ significant_littlenums_dropped = 0;
+ }
+ } else {
+ memcpy((char *) out, (char *) in,
+ in_length << LITTLENUM_SHIFT);
+
+ if (out_length > in_length) {
+ memset((char *) (out + out_length),
+ '\0', (out_length - in_length) << LITTLENUM_SHIFT);
+ }
+
+ significant_littlenums_dropped = 0;
+ }
+
+ return(significant_littlenums_dropped);
+} /* bignum_copy() */
+
+/* end of bignum-copy.c */
diff --git a/gnu/usr.bin/as/bignum.h b/gnu/usr.bin/as/bignum.h
new file mode 100644
index 0000000..64efadc
--- /dev/null
+++ b/gnu/usr.bin/as/bignum.h
@@ -0,0 +1,64 @@
+/* bignum.h-arbitrary precision integers
+ Copyright (C) 1987, 1992 Free Software Foundation, Inc.
+
+ This file is part of GAS, the GNU Assembler.
+
+ GAS is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GAS is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GAS; see the file COPYING. If not, write to
+ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/*
+ * $Id: bignum.h,v 1.2 1993/11/03 00:51:18 paul Exp $
+ */
+
+/***********************************************************************\
+ * *
+ * Arbitrary-precision integer arithmetic. *
+ * For speed, we work in groups of bits, even though this *
+ * complicates algorithms. *
+ * Each group of bits is called a 'littlenum'. *
+ * A bunch of littlenums representing a (possibly large) *
+ * integer is called a 'bignum'. *
+ * Bignums are >= 0. *
+ * *
+ \***********************************************************************/
+
+#define LITTLENUM_NUMBER_OF_BITS (16)
+#define LITTLENUM_RADIX (1 << LITTLENUM_NUMBER_OF_BITS)
+#define LITTLENUM_MASK (0xFFFF)
+#define LITTLENUM_SHIFT (1)
+#define CHARS_PER_LITTLENUM (1 << LITTLENUM_SHIFT)
+#ifndef BITS_PER_CHAR
+#define BITS_PER_CHAR (8)
+#endif
+
+typedef unsigned short LITTLENUM_TYPE;
+
+/* JF truncated this to get around a problem with GCC */
+#define LOG_TO_BASE_2_OF_10 (3.3219280948873623478703194294893901758651)
+/* WARNING: I haven't checked that the trailing digits are correct! */
+
+ /* lengths are in sizeof(littlenum)s */
+#if __STDC__ == 1
+
+int bignum_copy(LITTLENUM_TYPE *in, int in_length,
+ LITTLENUM_TYPE *out, int out_length);
+
+#else
+
+int bignum_copy();
+
+#endif /* __STDC__ */
+
+
+/* end of bignum.h */
diff --git a/gnu/usr.bin/as/bit_fix.h b/gnu/usr.bin/as/bit_fix.h
new file mode 100644
index 0000000..14988ff
--- /dev/null
+++ b/gnu/usr.bin/as/bit_fix.h
@@ -0,0 +1,54 @@
+/* write.h
+
+ Copyright (C) 1987, 1992 Free Software Foundation, Inc.
+
+ This file is part of GAS, the GNU Assembler.
+
+ GAS is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GAS is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GAS; see the file COPYING. If not, write to
+ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+/*
+ * $Id: bit_fix.h,v 1.1 1993/11/03 00:51:19 paul Exp $
+ */
+
+
+/* The bit_fix was implemented to support machines that need variables
+ to be inserted in bitfields other than 1, 2 and 4 bytes.
+ Furthermore it gives us a possibillity to mask in bits in the symbol
+ when it's fixed in the objectcode and check the symbols limits.
+
+ The or-mask is used to set the huffman bits in displacements for the
+ ns32k port.
+ The acbi, addqi, movqi, cmpqi instruction requires an assembler that
+ can handle bitfields. Ie handle an expression, evaluate it and insert
+ the result in an some bitfield. ( ex: 5 bits in a short field of a opcode)
+ */
+
+#ifndef __bit_fix_h__
+#define __bit_fix_h__
+
+struct bit_fix {
+ int fx_bit_size; /* Length of bitfield */
+ int fx_bit_offset; /* Bit offset to bitfield */
+ long fx_bit_base; /* Where do we apply the bitfix.
+ If this is zero, default is assumed. */
+ long fx_bit_base_adj; /* Adjustment of base */
+ long fx_bit_max; /* Signextended max for bitfield */
+ long fx_bit_min; /* Signextended min for bitfield */
+ long fx_bit_add; /* Or mask, used for huffman prefix */
+};
+typedef struct bit_fix bit_fixS;
+
+#endif /* __bit_fix_h__ */
+
+ /* end of bit_fix.h */
diff --git a/gnu/usr.bin/as/cond.c b/gnu/usr.bin/as/cond.c
new file mode 100644
index 0000000..3eb8db7
--- /dev/null
+++ b/gnu/usr.bin/as/cond.c
@@ -0,0 +1,219 @@
+/* cond.c - conditional assembly pseudo-ops, and .include
+ Copyright (C) 1990, 1991, 1992, 1993 Free Software Foundation, Inc.
+
+ This file is part of GAS, the GNU Assembler.
+
+ GAS is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GAS is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GAS; see the file COPYING. If not, write to
+ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#ifndef lint
+static char rcsid[] = "$Id: cond.c,v 1.2 1994/12/23 22:36:03 nate Exp $";
+#endif
+
+#include "as.h"
+
+#include "obstack.h"
+
+/* This is allocated to grow and shrink as .ifdef/.endif pairs are scanned. */
+struct obstack cond_obstack;
+
+struct file_line
+{
+ char *file;
+ unsigned int line;
+}; /* file_line */
+
+/* This is what we push and pop. */
+struct conditional_frame
+ {
+ struct file_line if_file_line; /* the source file & line number of the "if" */
+ struct file_line else_file_line; /* the source file & line of the "else" */
+ struct conditional_frame *previous_cframe;
+ int else_seen; /* have we seen an else yet? */
+ int ignoring; /* if we are currently ignoring input. */
+ int dead_tree; /* if a conditional at a higher level is ignoring input. */
+ }; /* conditional_frame */
+
+static void initialize_cframe PARAMS ((struct conditional_frame *cframe));
+
+static struct conditional_frame *current_cframe = NULL;
+
+void
+s_ifdef (arg)
+ int arg;
+{
+ register char *name; /* points to name of symbol */
+ register struct symbol *symbolP; /* Points to symbol */
+ struct conditional_frame cframe;
+
+ SKIP_WHITESPACE (); /* Leading whitespace is part of operand. */
+ name = input_line_pointer;
+
+ if (!is_name_beginner (*name))
+ {
+ as_bad ("invalid identifier for \".ifdef\"");
+ obstack_1grow (&cond_obstack, 0);
+ }
+ else
+ {
+ get_symbol_end ();
+ ++input_line_pointer;
+ symbolP = symbol_find (name);
+
+ initialize_cframe (&cframe);
+ cframe.ignoring = cframe.dead_tree || !((symbolP != 0) ^ arg);
+ current_cframe = (struct conditional_frame *) obstack_copy (&cond_obstack, &cframe, sizeof (cframe));
+ } /* if a valid identifyer name */
+
+ return;
+} /* s_ifdef() */
+
+void
+s_if (arg)
+ int arg;
+{
+ expressionS operand;
+ struct conditional_frame cframe;
+
+ SKIP_WHITESPACE (); /* Leading whitespace is part of operand. */
+ expression (&operand);
+
+#ifdef notyet
+ if (operand.X_op != O_constant)
+ as_bad ("non-constant expression in \".if\" statement");
+#else
+ if (operand.X_add_symbol != NULL || operand.X_subtract_symbol != NULL) {
+ as_bad("non-constant expression in \".if\" statement");
+ } /* bad condition */
+#endif
+
+ /* If the above error is signaled, this will dispatch
+ using an undefined result. No big deal. */
+ initialize_cframe (&cframe);
+ cframe.ignoring = cframe.dead_tree || !((operand.X_add_number != 0) ^ arg);
+ current_cframe = (struct conditional_frame *) obstack_copy (&cond_obstack, &cframe, sizeof (cframe));
+ return;
+} /* s_if() */
+
+void
+s_endif (arg)
+ int arg;
+{
+ struct conditional_frame *hold;
+
+ if (current_cframe == NULL)
+ {
+ as_bad ("\".endif\" without \".if\"");
+ }
+ else
+ {
+ hold = current_cframe;
+ current_cframe = current_cframe->previous_cframe;
+ obstack_free (&cond_obstack, hold);
+ } /* if one pop too many */
+
+ return;
+} /* s_endif() */
+
+void
+s_else (arg)
+ int arg;
+{
+ if (current_cframe == NULL)
+ {
+ as_bad (".else without matching .if - ignored");
+
+ }
+ else if (current_cframe->else_seen)
+ {
+ as_bad ("duplicate \"else\" - ignored");
+ as_bad_where (current_cframe->else_file_line.file,
+ current_cframe->else_file_line.line,
+ "here is the previous \"else\"");
+ as_bad_where (current_cframe->if_file_line.file,
+ current_cframe->if_file_line.line,
+ "here is the previous \"if\"");
+ }
+ else
+ {
+ as_where (&current_cframe->else_file_line.file,
+ &current_cframe->else_file_line.line);
+
+ if (!current_cframe->dead_tree)
+ {
+ current_cframe->ignoring = !current_cframe->ignoring;
+ } /* if not a dead tree */
+
+ current_cframe->else_seen = 1;
+ } /* if error else do it */
+
+ return;
+} /* s_else() */
+
+void
+s_ifeqs (arg)
+ int arg;
+{
+ as_bad ("ifeqs not implemented.");
+
+ return;
+} /* s_ifeqs() */
+
+void
+s_end (arg)
+ int arg;
+{
+ return;
+} /* s_end() */
+
+int
+ignore_input ()
+{
+ /* We cannot ignore certain pseudo ops. */
+ if (input_line_pointer[-1] == '.'
+ && ((input_line_pointer[0] == 'i'
+ && (!strncmp (input_line_pointer, "if", 2)
+ || !strncmp (input_line_pointer, "ifdef", 5)
+ || !strncmp (input_line_pointer, "ifndef", 6)))
+ || (input_line_pointer[0] == 'e'
+ && (!strncmp (input_line_pointer, "else", 4)
+ || !strncmp (input_line_pointer, "endif", 5)))))
+ {
+ return 0;
+ }
+
+ return ((current_cframe != NULL) && (current_cframe->ignoring));
+} /* ignore_input() */
+
+static void
+initialize_cframe (cframe)
+ struct conditional_frame *cframe;
+{
+ memset (cframe, 0, sizeof (*cframe));
+ as_where (&cframe->if_file_line.file,
+ &cframe->if_file_line.line);
+ cframe->previous_cframe = current_cframe;
+ cframe->dead_tree = current_cframe != NULL && current_cframe->ignoring;
+
+ return;
+} /* initialize_cframe() */
+
+/*
+ * Local Variables:
+ * fill-column: 131
+ * comment-column: 0
+ * End:
+ */
+
+/* end of cond.c */
diff --git a/gnu/usr.bin/as/config-gas.com b/gnu/usr.bin/as/config-gas.com
new file mode 100644
index 0000000..48e2e49
--- /dev/null
+++ b/gnu/usr.bin/as/config-gas.com
@@ -0,0 +1,76 @@
+$!
+$! This file sets things up to build gas on a VMS system to generate object
+$! files for a VMS system. We do not use the configure script, since we
+$! do not have /bin/sh to execute it.
+$!
+$! If you are running this file, then obviously the host is vax-dec-vms.
+$!
+$gas_host="vms"
+$!
+$cpu_type="vax"
+$emulation="generic"
+$obj_format="vms"
+$atof="vax"
+$!
+$! host specific information
+$call link host.h [.config]ho-'gas_host'.h
+$!
+$! Target specific information
+$call link targ-cpu.c [.config]tc-'cpu_type'.c
+$call link targ-cpu.h [.config]tc-'cpu_type'.h
+$call link targ-env.h [.config]te-'emulation'.h
+$!
+$! Code to handle the object file format.
+$call link obj-format.h [.config]obj-'obj_format'.h
+$call link obj-format.c [.config]obj-'obj_format'.c
+$!
+$! Code to handle floating point.
+$call link atof-targ.c [.config]atof-'atof'.c
+$!
+$!
+$! Create the file version.opt, which helps identify the executalbe.
+$!
+$search version.c version_string,"="/match=and/output=t.tmp
+$open ifile$ t.tmp
+$read ifile$ line
+$close ifile$
+$delete/nolog t.tmp;
+$ijk=f$locate("""",line)+1
+$line=f$extract(ijk,f$length(line)-ijk,line)
+$ijk=f$locate("""",line)
+$line=f$extract(0,ijk,line)
+$ijk=f$locate("\n",line)
+$line=f$extract(0,ijk,line)
+$!
+$i=0
+$loop:
+$elm=f$element(i," ",line)
+$if elm.eqs."" then goto no_ident
+$if (elm.les."9").and.(elm.ges."0") then goto write_ident
+$i=i+1
+$goto loop
+$!
+$no_ident:
+$elm="?.??"
+$!
+$!
+$write_ident:
+$open ifile$ version.opt/write
+$write ifile$ "ident="+""""+elm+""""
+$close ifile$
+$!
+$ !
+$ if f$search("config.status") .nes. "" then delete config.status.*
+$ open/write file config.status
+$ write file "Links are now set up for use with a vax running VMS."
+$ close file
+$ type config.status
+$exit
+$!
+$!
+$link:
+$subroutine
+$if f$search(p1).nes."" then delete/nolog 'p1';
+$copy 'p2' 'p1'
+$write sys$output "Linked ''p2' to ''p1'."
+$endsubroutine
diff --git a/gnu/usr.bin/as/config/Makefile.hp300 b/gnu/usr.bin/as/config/Makefile.hp300
new file mode 100644
index 0000000..4261d35
--- /dev/null
+++ b/gnu/usr.bin/as/config/Makefile.hp300
@@ -0,0 +1,7 @@
+# from: @(#)Makefile.hp300 6.1 (Berkeley) 3/3/91
+# $Id: Makefile.hp300,v 1.4 1993/10/16 03:23:04 cgd Exp $
+
+CFLAGS+= -Dm68851
+SRCS+= tc-m68k.c atof-ieee.c
+
+gas_target= m68k
diff --git a/gnu/usr.bin/as/config/Makefile.i386 b/gnu/usr.bin/as/config/Makefile.i386
new file mode 100644
index 0000000..4cee919
--- /dev/null
+++ b/gnu/usr.bin/as/config/Makefile.i386
@@ -0,0 +1,5 @@
+# from: @(#)Makefile.i386 6.1 (Berkeley) 3/3/91
+# $Id: Makefile.i386,v 1.2 1993/11/03 00:52:58 paul Exp $
+
+CFLAGS+= -DNON_BROKEN_WORDS -DPIC
+SRCS+= tc-i386.c atof-ieee.c
diff --git a/gnu/usr.bin/as/config/Makefile.pc532 b/gnu/usr.bin/as/config/Makefile.pc532
new file mode 100644
index 0000000..d4b22ab
--- /dev/null
+++ b/gnu/usr.bin/as/config/Makefile.pc532
@@ -0,0 +1,7 @@
+# $Id: Makefile.pc532,v 1.1 1993/10/16 03:23:37 cgd Exp $
+
+SRCS+= tc-ns32k.c atof-ns32k.c
+
+CFLAGS+= -DNS32532 -DNS32381
+
+gas_target= ns32k
diff --git a/gnu/usr.bin/as/config/Makefile.sparc b/gnu/usr.bin/as/config/Makefile.sparc
new file mode 100644
index 0000000..6dc9658
--- /dev/null
+++ b/gnu/usr.bin/as/config/Makefile.sparc
@@ -0,0 +1,5 @@
+# from: @(#)Makefile.i386 6.1 (Berkeley) 3/3/91
+# $Id: Makefile.sparc,v 1.1 1993/11/03 00:53:00 paul Exp $
+
+CFLAGS+= -DNON_BROKEN_WORDS -DPIC
+SRCS+= tc-sparc.c atof-ieee.c
diff --git a/gnu/usr.bin/as/config/Makefile.vax b/gnu/usr.bin/as/config/Makefile.vax
new file mode 100644
index 0000000..f62b087
--- /dev/null
+++ b/gnu/usr.bin/as/config/Makefile.vax
@@ -0,0 +1,4 @@
+# from: @(#)Makefile.vax 6.1 (Berkeley) 3/3/91
+# $Id: Makefile.vax,v 1.3 1993/10/02 20:58:23 pk Exp $
+
+SRCS+= tc-vax.c atof-vax.c
diff --git a/gnu/usr.bin/as/config/aout.h b/gnu/usr.bin/as/config/aout.h
new file mode 100644
index 0000000..9856cb0
--- /dev/null
+++ b/gnu/usr.bin/as/config/aout.h
@@ -0,0 +1,440 @@
+/* This file is aout.h
+
+ Copyright (C) 1987-1992 Free Software Foundation, Inc.
+
+ This file is part of GAS, the GNU Assembler.
+
+ GAS is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GAS is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GAS; see the file COPYING. If not, write to
+ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#ifndef __A_OUT_GNU_H__
+#define __A_OUT_GNU_H__
+
+enum reloc_type {
+
+#ifdef TC_M88K
+ RELOC_LO16, /* lo16(sym) */
+ RELOC_HI16, /* hi16(sym) */
+ RELOC_PC16, /* bb0, bb1, bcnd */
+ RELOC_PC26, /* br, bsr */
+ RELOC_32, /* jump tables, etc */
+ RELOC_IW16, /* global access through linker regs 28 */
+ NO_RELOC,
+#else /* not TC_M88K */
+#ifdef TC_I860
+
+/* NOTE: three bits max, see struct reloc_info_i860.r_type */
+ NO_RELOC = 0, BRADDR, LOW0, LOW1, LOW2, LOW3, LOW4, SPLIT0, SPLIT1, SPLIT2, RELOC_32,
+
+#else /* not TC_I860 */
+
+ RELOC_8, RELOC_16, RELOC_32, /* simple relocations */
+ RELOC_DISP8, RELOC_DISP16, RELOC_DISP32, /* pc-rel displacement */
+ RELOC_WDISP30, RELOC_WDISP22,
+ RELOC_HI22, RELOC_22,
+ RELOC_13, RELOC_LO10,
+ RELOC_SFA_BASE, RELOC_SFA_OFF13,
+ RELOC_BASE10, RELOC_BASE13, RELOC_BASE22, /* P.I.C. (base-relative) */
+ RELOC_PC10, RELOC_PC22, /* for some sort of pc-rel P.I.C. (?) */
+ RELOC_JMP_TBL, /* P.I.C. jump table */
+ RELOC_SEGOFF16, /* reputedly for shared libraries somehow */
+ RELOC_GLOB_DAT, RELOC_JMP_SLOT, RELOC_RELATIVE,
+#ifndef TC_SPARC
+ RELOC_11,
+ RELOC_WDISP2_14,
+ RELOC_WDISP19,
+ RELOC_HHI22,
+ RELOC_HLO10,
+
+ /* 29K relocation types */
+ RELOC_JUMPTARG, RELOC_CONST, RELOC_CONSTH,
+
+ RELOC_WDISP14, RELOC_WDISP21,
+#endif /* not TC_SPARC */
+ NO_RELOC,
+
+#ifdef TC_I386
+ /* Used internally by gas */
+ RELOC_GOT,
+ RELOC_GOTOFF,
+#endif
+
+#endif /* not TC_I860 */
+#endif /* not TC_M88K */
+};
+
+
+#ifdef TC_I860
+ /* NOTE: two bits max, see reloc_info_i860.r_type */
+enum highlow_type {
+ NO_SPEC = 0, PAIR, HIGH, HIGHADJ,
+};
+#endif /* TC_I860 */
+
+
+#define __GNU_EXEC_MACROS__
+
+#ifndef __STRUCT_EXEC_OVERRIDE__
+
+/* This is the layout on disk of a Unix V7, Berkeley, SunOS, Vax Ultrix
+ "struct exec". Don't assume that on this machine, the "struct exec"
+ will lay out the same sizes or alignments. */
+
+struct exec_bytes {
+ unsigned char a_info[4];
+ unsigned char a_text[4];
+ unsigned char a_data[4];
+ unsigned char a_bss[4];
+ unsigned char a_syms[4];
+ unsigned char a_entry[4];
+ unsigned char a_trsize[4];
+ unsigned char a_drsize[4];
+};
+
+/* How big the "struct exec" is on disk */
+#define EXEC_BYTES_SIZE (8 * 4)
+
+/* This is the layout in memory of a "struct exec" while we process it. */
+
+struct exec
+{
+ unsigned long a_info; /* Use macros N_MAGIC, etc for access */
+ unsigned a_text; /* length of text, in bytes */
+ unsigned a_data; /* length of data, in bytes */
+ unsigned a_bss; /* length of uninitialized data area for file, in bytes */
+ unsigned a_syms; /* length of symbol table data in file, in bytes */
+ unsigned a_entry; /* start address */
+ unsigned a_trsize; /* length of relocation info for text, in bytes */
+ unsigned a_drsize; /* length of relocation info for data, in bytes */
+};
+
+#endif /* __STRUCT_EXEC_OVERRIDE__ */
+
+/* these go in the N_MACHTYPE field */
+/* These symbols could be defined by code from Suns...punt 'em */
+#undef M_UNKNOWN
+#undef M_68010
+#undef M_68020
+#undef M_SPARC
+enum machine_type {
+ M_UNKNOWN = 0,
+ M_68010 = 1,
+ M_68020 = 2,
+ M_SPARC = 3,
+ /* skip a bunch so we don't run into any of sun's numbers */
+ M_386 = 100,
+ M_29K = 101,
+ M_RS6000 = 102, /* IBM RS/6000 */
+ /* HP/BSD formats */
+ M_HP200 = 200, /* hp200 (68010) BSD binary */
+ M_HP300 = 300, /* hp300 (68020+68881) BSD binary */
+ M_HPUX23 = 0x020C, /* hp200/300 HPUX binary */
+};
+
+#define N_MAGIC(exec) ((exec).a_info & 0xffff)
+#define N_MACHTYPE(exec) ((enum machine_type)(((exec).a_info >> 16) & 0xff))
+#define N_FLAGS(exec) (((exec).a_info >> 24) & 0xff)
+#define N_SET_INFO(exec, magic, type, flags) \
+ ((exec).a_info = ((magic) & 0xffff) \
+ | (((int)(type) & 0xff) << 16) \
+ | (((flags) & 0xff) << 24))
+#define N_SET_MAGIC(exec, magic) \
+ ((exec).a_info = (((exec).a_info & 0xffff0000) | ((magic) & 0xffff)))
+
+#define N_SET_MACHTYPE(exec, machtype) \
+ ((exec).a_info = \
+ ((exec).a_info&0xff00ffff) | ((((int)(machtype))&0xff) << 16))
+
+#define N_SET_FLAGS(exec, flags) \
+ ((exec).a_info = \
+ ((exec).a_info&0x00ffffff) | (((flags) & 0xff) << 24))
+
+/* Code indicating object file or impure executable. */
+#define OMAGIC 0407
+/* Code indicating pure executable. */
+#define NMAGIC 0410
+/* Code indicating demand-paged executable. */
+#define ZMAGIC 0413
+
+/* Virtual Address of text segment from the a.out file. For OMAGIC,
+ (almost always "unlinked .o's" these days), should be zero.
+ For linked files, should reflect reality if we know it. */
+
+#ifndef N_TXTADDR
+#define N_TXTADDR(x) (N_MAGIC(x) == OMAGIC? 0 : TEXT_START_ADDR)
+#endif
+
+#ifndef N_BADMAG
+#define N_BADMAG(x) (N_MAGIC(x) != OMAGIC \
+ && N_MAGIC(x) != NMAGIC \
+ && N_MAGIC(x) != ZMAGIC)
+#endif
+
+/* By default, segment size is constant. But on some machines, it can
+ be a function of the a.out header (e.g. machine type). */
+#ifndef N_SEGSIZE
+#define N_SEGSIZE(x) SEGMENT_SIZE
+#endif
+
+ /* This complexity is for encapsulated COFF support */
+#ifndef _N_HDROFF
+#define _N_HDROFF(x) (N_SEGSIZE(x) - sizeof (struct exec))
+#endif
+
+#ifndef N_TXTOFF
+#define N_TXTOFF(x) (N_MAGIC(x) == ZMAGIC ? \
+ _N_HDROFF((x)) + sizeof (struct exec) : \
+ sizeof (struct exec))
+#endif
+
+
+#ifndef N_DATOFF
+#define N_DATOFF(x) ( N_TXTOFF(x) + (x).a_text )
+#endif
+
+#ifndef N_TRELOFF
+#define N_TRELOFF(x) ( N_DATOFF(x) + (x).a_data )
+#endif
+
+#ifndef N_DRELOFF
+#define N_DRELOFF(x) ( N_TRELOFF(x) + (x).a_trsize )
+#endif
+
+#ifndef N_SYMOFF
+#define N_SYMOFF(x) ( N_DRELOFF(x) + (x).a_drsize )
+#endif
+
+#ifndef N_STROFF
+#define N_STROFF(x) ( N_SYMOFF(x) + (x).a_syms )
+#endif
+
+/* Address of text segment in memory after it is loaded. */
+#ifndef N_TXTADDR
+#define N_TXTADDR(x) 0
+#endif
+
+#ifndef N_DATADDR
+#define N_DATADDR(x) \
+ (N_MAGIC(x) == OMAGIC? (N_TXTADDR(x)+(x).a_text) \
+ : (N_SEGSIZE(x) + ((N_TXTADDR(x)+(x).a_text-1) & ~(N_SEGSIZE(x)-1))))
+#endif
+
+/* Address of bss segment in memory after it is loaded. */
+#define N_BSSADDR(x) (N_DATADDR(x) + (x).a_data)
+
+struct nlist {
+ union {
+ char *n_name;
+ struct nlist *n_next;
+ long n_strx;
+ } n_un;
+ unsigned char n_type;
+ char n_other;
+ short n_desc;
+ unsigned long n_value;
+};
+
+#define N_UNDF 0
+#define N_ABS 2
+#define N_TEXT 4
+#define N_DATA 6
+#define N_BSS 8
+#define N_COMM 0x12 /* common (visible in shared lib commons) */
+#define N_FN 0x1F /* File name of a .o file */
+
+/* Note: N_EXT can only usefully be OR-ed with N_UNDF, N_ABS, N_TEXT,
+ N_DATA, or N_BSS. When the low-order bit of other types is set,
+ (e.g. N_WARNING versus N_FN), they are two different types. */
+#define N_EXT 1
+#define N_TYPE 036
+#define N_STAB 0340
+
+/* The following type indicates the definition of a symbol as being
+ an indirect reference to another symbol. The other symbol
+ appears as an undefined reference, immediately following this symbol.
+
+ Indirection is asymmetrical. The other symbol's value will be used
+ to satisfy requests for the indirect symbol, but not vice versa.
+ If the other symbol does not have a definition, libraries will
+ be searched to find a definition. */
+
+#define N_INDR 0xa
+
+/* The following type indicates the size of the symbol it refers to */
+#define N_SIZE 0xc
+
+/* The following symbols refer to set elements.
+ All the N_SET[ATDB] symbols with the same name form one set.
+ Space is allocated for the set in the text section, and each set
+ element's value is stored into one word of the space.
+ The first word of the space is the length of the set (number of elements).
+
+ The address of the set is made into an N_SETV symbol
+ whose name is the same as the name of the set.
+ This symbol acts like a N_DATA global symbol
+ in that it can satisfy undefined external references. */
+
+/* These appear as input to LD, in a .o file. */
+#define N_SETA 0x14 /* Absolute set element symbol */
+#define N_SETT 0x16 /* Text set element symbol */
+#define N_SETD 0x18 /* Data set element symbol */
+#define N_SETB 0x1A /* Bss set element symbol */
+
+/* This is output from LD. */
+#define N_SETV 0x1C /* Pointer to set vector in data area. */
+
+/* Warning symbol. The text gives a warning message, the next symbol
+ in the table will be undefined. When the symbol is referenced, the
+ message is printed. */
+
+#define N_WARNING 0x1e
+
+/* This structure describes a single relocation to be performed.
+ The text-relocation section of the file is a vector of these structures,
+ all of which apply to the text section.
+ Likewise, the data-relocation section applies to the data section. */
+
+/* The following enum and struct were borrowed from SunOS's
+ /usr/include/sun4/a.out.h and extended to handle
+ other machines. It is currently used on SPARC and AMD 29000.
+
+ reloc_ext_bytes is how it looks on disk. reloc_info_extended is
+ how we might process it on a native host. */
+
+struct reloc_ext_bytes {
+ unsigned char r_address[4];
+ unsigned char r_index[3];
+ unsigned char r_bits[1];
+ unsigned char r_addend[4];
+};
+
+struct reloc_info_i860
+{
+ unsigned long r_address;
+ /*
+ * Using bit fields here is a bad idea because the order is not portable. :-(
+ */
+ unsigned int r_symbolnum: 24;
+ unsigned int r_pcrel : 1;
+ unsigned int r_extern : 1;
+ /* combining the two field simplifies the argument passing in "new_fix()" */
+ /* and is compatible with the existing Sparc #ifdef's */
+ /* r_type: highlow_type - bits 5,4; reloc_type - bits 3-0 */
+ unsigned int r_type : 6;
+ long r_addend;
+};
+
+
+#define RELOC_EXT_BITS_EXTERN_BIG 0x80
+#define RELOC_EXT_BITS_EXTERN_LITTLE 0x01
+
+#define RELOC_EXT_BITS_TYPE_BIG 0x1F
+#define RELOC_EXT_BITS_TYPE_SH_BIG 0
+#define RELOC_EXT_BITS_TYPE_LITTLE 0xF8
+#define RELOC_EXT_BITS_TYPE_SH_LITTLE 3
+
+#define RELOC_EXT_SIZE 12 /* Bytes per relocation entry */
+
+struct reloc_info_extended
+{
+ unsigned long r_address;
+ unsigned int r_index:24;
+# define r_symbolnum r_index
+ unsigned r_extern:1;
+ unsigned :2;
+ /* RS/6000 compiler does not support enum bitfield
+ enum reloc_type r_type:5; */
+ enum reloc_type r_type;
+ long int r_addend;
+};
+
+/* The standard, old-fashioned, Berkeley compatible relocation struct */
+
+struct reloc_std_bytes {
+ unsigned char r_address[4];
+ unsigned char r_index[3];
+ unsigned char r_bits[1];
+};
+
+#define RELOC_STD_BITS_PCREL_BIG 0x80
+#define RELOC_STD_BITS_PCREL_LITTLE 0x01
+
+#define RELOC_STD_BITS_LENGTH_BIG 0x60
+#define RELOC_STD_BITS_LENGTH_SH_BIG 5 /* To shift to units place */
+#define RELOC_STD_BITS_LENGTH_LITTLE 0x06
+#define RELOC_STD_BITS_LENGTH_SH_LITTLE 1
+
+#define RELOC_STD_BITS_EXTERN_BIG 0x10
+#define RELOC_STD_BITS_EXTERN_LITTLE 0x08
+
+#define RELOC_STD_BITS_BASEREL_BIG 0x08
+#define RELOC_STD_BITS_BASEREL_LITTLE 0x08
+
+#define RELOC_STD_BITS_JMPTABLE_BIG 0x04
+#define RELOC_STD_BITS_JMPTABLE_LITTLE 0x04
+
+#define RELOC_STD_BITS_RELATIVE_BIG 0x02
+#define RELOC_STD_BITS_RELATIVE_LITTLE 0x02
+
+#define RELOC_STD_SIZE 8 /* Bytes per relocation entry */
+
+#ifndef CUSTOM_RELOC_FORMAT
+struct relocation_info {
+ /* Address (within segment) to be relocated. */
+ int r_address;
+ /* The meaning of r_symbolnum depends on r_extern. */
+#if defined(TC_NS32K) && !defined(TE_SEQUENT)
+ unsigned int r_symbolnum:22;
+ unsigned int r_copy:1;
+ unsigned int r_relative:1;
+#else
+ unsigned int r_symbolnum:24;
+#endif
+ /* Nonzero means value is a pc-relative offset
+ and it should be relocated for changes in its own address
+ as well as for changes in the symbol or section specified. */
+ unsigned int r_pcrel:1;
+ /* Length (as exponent of 2) of the field to be relocated.
+ Thus, a value of 2 indicates 1<<2 bytes. */
+ unsigned int r_length:2;
+ /* 1 => relocate with value of symbol.
+ r_symbolnum is the index of the symbol
+ in file's the symbol table.
+ 0 => relocate with the address of a segment.
+ r_symbolnum is N_TEXT, N_DATA, N_BSS or N_ABS
+ (the N_EXT bit may be set also, but signifies nothing). */
+ unsigned int r_extern:1;
+#ifdef TC_NS32K
+#ifdef TE_SEQUENT
+ unsigned int r_bsr:1;
+#else
+ unsigned int r_jmptable:1;
+#endif
+ unsigned int r_disp:2;
+ unsigned int r_baserel:1;
+#else
+ /* The next three bits are for SunOS shared libraries, and seem to
+ be undocumented. */
+ unsigned int r_baserel:1; /* Linkage table relative */
+ unsigned int r_jmptable:1; /* pc-relative to jump table */
+ unsigned int r_relative:1; /* "relative relocation" */
+ /* unused */
+ unsigned int r_pad:1; /* Padding -- set to zero */
+#endif
+};
+#endif /* CUSTOM_RELOC_FORMAT */
+
+#endif /* __A_OUT_GNU_H__ */
+
+/* end of aout.h */
diff --git a/gnu/usr.bin/as/config/atof-ieee.c b/gnu/usr.bin/as/config/atof-ieee.c
new file mode 100644
index 0000000..7040f11
--- /dev/null
+++ b/gnu/usr.bin/as/config/atof-ieee.c
@@ -0,0 +1,524 @@
+/* atof_ieee.c - turn a Flonum into an IEEE floating point number
+ Copyright (C) 1987, 1992 Free Software Foundation, Inc.
+
+ This file is part of GAS, the GNU Assembler.
+
+ GAS is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GAS is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GAS; see the file COPYING. If not, write to
+ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#ifndef lint
+static char rcsid[] = "$Id: atof-ieee.c,v 1.2 1993/11/03 00:53:04 paul Exp $";
+#endif
+
+#include "as.h"
+
+extern FLONUM_TYPE generic_floating_point_number; /* Flonums returned here. */
+
+#ifndef NULL
+#define NULL (0)
+#endif
+
+extern char EXP_CHARS[];
+/* Precision in LittleNums. */
+#define MAX_PRECISION (6)
+#define F_PRECISION (2)
+#define D_PRECISION (4)
+#define X_PRECISION (6)
+#define P_PRECISION (6)
+
+/* Length in LittleNums of guard bits. */
+#define GUARD (2)
+
+static unsigned long mask[] = {
+ 0x00000000,
+ 0x00000001,
+ 0x00000003,
+ 0x00000007,
+ 0x0000000f,
+ 0x0000001f,
+ 0x0000003f,
+ 0x0000007f,
+ 0x000000ff,
+ 0x000001ff,
+ 0x000003ff,
+ 0x000007ff,
+ 0x00000fff,
+ 0x00001fff,
+ 0x00003fff,
+ 0x00007fff,
+ 0x0000ffff,
+ 0x0001ffff,
+ 0x0003ffff,
+ 0x0007ffff,
+ 0x000fffff,
+ 0x001fffff,
+ 0x003fffff,
+ 0x007fffff,
+ 0x00ffffff,
+ 0x01ffffff,
+ 0x03ffffff,
+ 0x07ffffff,
+ 0x0fffffff,
+ 0x1fffffff,
+ 0x3fffffff,
+ 0x7fffffff,
+ 0xffffffff,
+};
+
+
+static int bits_left_in_littlenum;
+static int littlenums_left;
+static LITTLENUM_TYPE *littlenum_pointer;
+
+static int
+ next_bits (number_of_bits)
+int number_of_bits;
+{
+ int return_value;
+
+ if (!littlenums_left)
+ return(0);
+ if (number_of_bits >= bits_left_in_littlenum) {
+ return_value = mask[bits_left_in_littlenum] & *littlenum_pointer;
+ number_of_bits -= bits_left_in_littlenum;
+ return_value <<= number_of_bits;
+
+ if (--littlenums_left) {
+ bits_left_in_littlenum = LITTLENUM_NUMBER_OF_BITS - number_of_bits;
+ --littlenum_pointer;
+ return_value |= (*littlenum_pointer >> bits_left_in_littlenum) & mask[number_of_bits];
+ }
+ } else {
+ bits_left_in_littlenum -= number_of_bits;
+ return_value = mask[number_of_bits] & (*littlenum_pointer >> bits_left_in_littlenum);
+ }
+ return(return_value);
+}
+
+/* Num had better be less than LITTLENUM_NUMBER_OF_BITS */
+static void
+ unget_bits(num)
+int num;
+{
+ if (!littlenums_left) {
+ ++littlenum_pointer;
+ ++littlenums_left;
+ bits_left_in_littlenum = num;
+ } else if (bits_left_in_littlenum + num > LITTLENUM_NUMBER_OF_BITS) {
+ bits_left_in_littlenum = num - (LITTLENUM_NUMBER_OF_BITS - bits_left_in_littlenum);
+ ++littlenum_pointer;
+ ++littlenums_left;
+ } else
+ bits_left_in_littlenum += num;
+}
+
+static void
+ make_invalid_floating_point_number(words)
+LITTLENUM_TYPE *words;
+{
+ as_bad("cannot create floating-point number");
+ words[0] = ((unsigned) -1) >> 1; /* Zero the leftmost bit */
+ words[1] = -1;
+ words[2] = -1;
+ words[3] = -1;
+ words[4] = -1;
+ words[5] = -1;
+}
+
+/***********************************************************************\
+ * Warning: this returns 16-bit LITTLENUMs. It is up to the caller *
+ * to figure out any alignment problems and to conspire for the *
+ * bytes/word to be emitted in the right order. Bigendians beware! *
+ * *
+ \***********************************************************************/
+
+/* Note that atof-ieee always has X and P precisions enabled. it is up
+ to md_atof to filter them out if the target machine does not support
+ them. */
+
+char * /* Return pointer past text consumed. */
+ atof_ieee(str, what_kind, words)
+char *str; /* Text to convert to binary. */
+char what_kind; /* 'd', 'f', 'g', 'h' */
+LITTLENUM_TYPE *words; /* Build the binary here. */
+{
+ static LITTLENUM_TYPE bits[MAX_PRECISION + MAX_PRECISION + GUARD];
+ /* Extra bits for zeroed low-order bits. */
+ /* The 1st MAX_PRECISION are zeroed, */
+ /* the last contain flonum bits. */
+ char *return_value;
+ int precision; /* Number of 16-bit words in the format. */
+ long exponent_bits;
+ FLONUM_TYPE save_gen_flonum;
+
+ /* We have to save the generic_floating_point_number because it
+ contains storage allocation about the array of LITTLENUMs
+ where the value is actually stored. We will allocate our
+ own array of littlenums below, but have to restore the global
+ one on exit. */
+ save_gen_flonum = generic_floating_point_number;
+
+ return_value = str;
+ generic_floating_point_number.low = bits + MAX_PRECISION;
+ generic_floating_point_number.high = NULL;
+ generic_floating_point_number.leader = NULL;
+ generic_floating_point_number.exponent = NULL;
+ generic_floating_point_number.sign = '\0';
+
+ /* Use more LittleNums than seems */
+ /* necessary: the highest flonum may have */
+ /* 15 leading 0 bits, so could be useless. */
+
+ memset(bits, '\0', sizeof(LITTLENUM_TYPE) * MAX_PRECISION);
+
+ switch (what_kind) {
+ case 'f':
+ case 'F':
+ case 's':
+ case 'S':
+ precision = F_PRECISION;
+ exponent_bits = 8;
+ break;
+
+ case 'd':
+ case 'D':
+ case 'r':
+ case 'R':
+ precision = D_PRECISION;
+ exponent_bits = 11;
+ break;
+
+ case 'x':
+ case 'X':
+ case 'e':
+ case 'E':
+ precision = X_PRECISION;
+ exponent_bits = 15;
+ break;
+
+ case 'p':
+ case 'P':
+
+ precision = P_PRECISION;
+ exponent_bits = -1;
+ break;
+
+ default:
+ make_invalid_floating_point_number(words);
+ return(NULL);
+ }
+
+ generic_floating_point_number.high = generic_floating_point_number.low + precision - 1 + GUARD;
+
+ if (atof_generic(&return_value, ".", EXP_CHARS, &generic_floating_point_number)) {
+ /* as_bad("Error converting floating point number (Exponent overflow?)"); */
+ make_invalid_floating_point_number(words);
+ return(NULL);
+ }
+ gen_to_words(words, precision, exponent_bits);
+
+ /* Restore the generic_floating_point_number's storage alloc
+ (and everything else). */
+ generic_floating_point_number = save_gen_flonum;
+
+ return(return_value);
+}
+
+/* Turn generic_floating_point_number into a real float/double/extended */
+int gen_to_words(words, precision, exponent_bits)
+LITTLENUM_TYPE *words;
+int precision;
+long exponent_bits;
+{
+ int return_value = 0;
+
+ long exponent_1;
+ long exponent_2;
+ long exponent_3;
+ long exponent_4;
+ int exponent_skippage;
+ LITTLENUM_TYPE word1;
+ LITTLENUM_TYPE *lp;
+
+ if (generic_floating_point_number.low > generic_floating_point_number.leader) {
+ /* 0.0e0 seen. */
+ if (generic_floating_point_number.sign == '+')
+ words[0] = 0x0000;
+ else
+ words[0] = 0x8000;
+ memset(&words[1], '\0', sizeof(LITTLENUM_TYPE) * (precision - 1));
+ return(return_value);
+ }
+
+ /* NaN: Do the right thing */
+ if (generic_floating_point_number.sign == 0) {
+ if (precision == F_PRECISION) {
+ words[0] = 0x7fff;
+ words[1] = 0xffff;
+ } else {
+ words[0] = 0x7fff;
+ words[1] = 0xffff;
+ words[2] = 0xffff;
+ words[3] = 0xffff;
+ }
+ return return_value;
+ } else if (generic_floating_point_number.sign == 'P') {
+ /* +INF: Do the right thing */
+ if (precision == F_PRECISION) {
+ words[0] = 0x7f80;
+ words[1] = 0;
+ } else {
+ words[0] = 0x7ff0;
+ words[1] = 0;
+ words[2] = 0;
+ words[3] = 0;
+ }
+ return(return_value);
+ } else if (generic_floating_point_number.sign == 'N') {
+ /* Negative INF */
+ if (precision == F_PRECISION) {
+ words[0] = 0xff80;
+ words[1] = 0x0;
+ } else {
+ words[0] = 0xfff0;
+ words[1] = 0x0;
+ words[2] = 0x0;
+ words[3] = 0x0;
+ }
+ return(return_value);
+ }
+ /*
+ * The floating point formats we support have:
+ * Bit 15 is sign bit.
+ * Bits 14:n are excess-whatever exponent.
+ * Bits n-1:0 (if any) are most significant bits of fraction.
+ * Bits 15:0 of the next word(s) are the next most significant bits.
+ *
+ * So we need: number of bits of exponent, number of bits of
+ * mantissa.
+ */
+ bits_left_in_littlenum = LITTLENUM_NUMBER_OF_BITS;
+ littlenum_pointer = generic_floating_point_number.leader;
+ littlenums_left = 1 + generic_floating_point_number.leader - generic_floating_point_number.low;
+ /* Seek (and forget) 1st significant bit */
+ for (exponent_skippage = 0; !next_bits(1); ++exponent_skippage) ;;
+ exponent_1 = generic_floating_point_number.exponent + generic_floating_point_number.leader
+ + 1 - generic_floating_point_number.low;
+ /* Radix LITTLENUM_RADIX, point just higher than generic_floating_point_number.leader. */
+ exponent_2 = exponent_1 * LITTLENUM_NUMBER_OF_BITS;
+ /* Radix 2. */
+ exponent_3 = exponent_2 - exponent_skippage;
+ /* Forget leading zeros, forget 1st bit. */
+ exponent_4 = exponent_3 + ((1 << (exponent_bits - 1)) - 2);
+ /* Offset exponent. */
+
+ lp = words;
+
+ /* Word 1. Sign, exponent and perhaps high bits. */
+ word1 = (generic_floating_point_number.sign == '+') ? 0 : (1 << (LITTLENUM_NUMBER_OF_BITS - 1));
+
+ /* Assume 2's complement integers. */
+ if (exponent_4 < 1 && exponent_4 >= -62) {
+ int prec_bits;
+ int num_bits;
+
+ unget_bits(1);
+ num_bits = -exponent_4;
+ prec_bits = LITTLENUM_NUMBER_OF_BITS * precision - (exponent_bits + 1 + num_bits);
+ if (precision == X_PRECISION && exponent_bits == 15)
+ prec_bits -= LITTLENUM_NUMBER_OF_BITS + 1;
+
+ if (num_bits >= LITTLENUM_NUMBER_OF_BITS - exponent_bits) {
+ /* Bigger than one littlenum */
+ num_bits -= (LITTLENUM_NUMBER_OF_BITS - 1) - exponent_bits;
+ *lp++ = word1;
+ if (num_bits + exponent_bits + 1 >= precision * LITTLENUM_NUMBER_OF_BITS) {
+ /* Exponent overflow */
+ make_invalid_floating_point_number(words);
+ return(return_value);
+ }
+ if (precision == X_PRECISION && exponent_bits == 15) {
+ *lp++ = 0;
+ *lp++ = 0;
+ num_bits -= LITTLENUM_NUMBER_OF_BITS - 1;
+ }
+ while (num_bits >= LITTLENUM_NUMBER_OF_BITS) {
+ num_bits -= LITTLENUM_NUMBER_OF_BITS;
+ *lp++ = 0;
+ }
+ if (num_bits)
+ *lp++ = next_bits(LITTLENUM_NUMBER_OF_BITS - (num_bits));
+ } else {
+ if (precision == X_PRECISION && exponent_bits == 15) {
+ *lp++ = word1;
+ *lp++ = 0;
+ if (num_bits == LITTLENUM_NUMBER_OF_BITS) {
+ *lp++ = 0;
+ *lp++ = next_bits(LITTLENUM_NUMBER_OF_BITS - 1);
+ } else if (num_bits == LITTLENUM_NUMBER_OF_BITS - 1)
+ *lp++ = 0;
+ else
+ *lp++ = next_bits(LITTLENUM_NUMBER_OF_BITS - 1 - num_bits);
+ num_bits = 0;
+ } else {
+ word1 |= next_bits((LITTLENUM_NUMBER_OF_BITS - 1) - (exponent_bits + num_bits));
+ *lp++ = word1;
+ }
+ }
+ while (lp < words + precision)
+ *lp++ = next_bits(LITTLENUM_NUMBER_OF_BITS);
+
+ /* Round the mantissa up, but don't change the number */
+ if (next_bits(1)) {
+ --lp;
+ if (prec_bits > LITTLENUM_NUMBER_OF_BITS) {
+ int n = 0;
+ int tmp_bits;
+
+ n = 0;
+ tmp_bits = prec_bits;
+ while (tmp_bits > LITTLENUM_NUMBER_OF_BITS) {
+ if (lp[n] != (LITTLENUM_TYPE) - 1)
+ break;
+ --n;
+ tmp_bits -= LITTLENUM_NUMBER_OF_BITS;
+ }
+ if (tmp_bits > LITTLENUM_NUMBER_OF_BITS || (lp[n] & mask[tmp_bits]) != mask[tmp_bits]) {
+ unsigned long carry;
+
+ for (carry = 1; carry && (lp >= words); lp --) {
+ carry = *lp + carry;
+ *lp = carry;
+ carry >>= LITTLENUM_NUMBER_OF_BITS;
+ }
+ }
+ } else if ((*lp & mask[prec_bits]) != mask[prec_bits])
+ lp++;
+ }
+
+ return return_value;
+ } else if (exponent_4 & ~ mask[exponent_bits]) {
+ /*
+ * Exponent overflow. Lose immediately.
+ */
+
+ /*
+ * We leave return_value alone: admit we read the
+ * number, but return a floating exception
+ * because we can't encode the number.
+ */
+ make_invalid_floating_point_number (words);
+ return return_value;
+ } else {
+ word1 |= (exponent_4 << ((LITTLENUM_NUMBER_OF_BITS - 1) - exponent_bits))
+ | next_bits ((LITTLENUM_NUMBER_OF_BITS - 1) - exponent_bits);
+ }
+
+ *lp++ = word1;
+
+ /* X_PRECISION is special: it has 16 bits of zero in the middle,
+ followed by a 1 bit. */
+ if (exponent_bits == 15 && precision == X_PRECISION) {
+ *lp++ = 0;
+ *lp++ = 1 << (LITTLENUM_NUMBER_OF_BITS) | next_bits(LITTLENUM_NUMBER_OF_BITS - 1);
+ }
+
+ /* The rest of the words are just mantissa bits. */
+ while (lp < words + precision)
+ *lp++ = next_bits(LITTLENUM_NUMBER_OF_BITS);
+
+ if (next_bits(1)) {
+ unsigned long carry;
+ /*
+ * Since the NEXT bit is a 1, round UP the mantissa.
+ * The cunning design of these hidden-1 floats permits
+ * us to let the mantissa overflow into the exponent, and
+ * it 'does the right thing'. However, we lose if the
+ * highest-order bit of the lowest-order word flips.
+ * Is that clear?
+ */
+
+ /* #if (sizeof(carry)) < ((sizeof(bits[0]) * BITS_PER_CHAR) + 2)
+ Please allow at least 1 more bit in carry than is in a LITTLENUM.
+ We need that extra bit to hold a carry during a LITTLENUM carry
+ propagation. Another extra bit (kept 0) will assure us that we
+ don't get a sticky sign bit after shifting right, and that
+ permits us to propagate the carry without any masking of bits.
+ #endif */
+ for (carry = 1, lp--; carry && (lp >= words); lp--) {
+ carry = *lp + carry;
+ *lp = carry;
+ carry >>= LITTLENUM_NUMBER_OF_BITS;
+ }
+ if ((word1 ^ *words) & (1 << (LITTLENUM_NUMBER_OF_BITS - 1))) {
+ /* We leave return_value alone: admit we read the
+ * number, but return a floating exception
+ * because we can't encode the number.
+ */
+ *words &= ~(1 << (LITTLENUM_NUMBER_OF_BITS - 1));
+ /* make_invalid_floating_point_number (words); */
+ /* return return_value; */
+ }
+ }
+ return (return_value);
+}
+
+/* This routine is a real kludge. Someone really should do it better, but
+ I'm too lazy, and I don't understand this stuff all too well anyway
+ (JF)
+ */
+void
+ int_to_gen(x)
+long x;
+{
+ char buf[20];
+ char *bufp;
+
+ sprintf(buf,"%ld",x);
+ bufp = &buf[0];
+ if (atof_generic(&bufp, ".", EXP_CHARS, &generic_floating_point_number))
+ as_bad("Error converting number to floating point (Exponent overflow?)");
+}
+
+#ifdef TEST
+char *
+ print_gen(gen)
+FLONUM_TYPE *gen;
+{
+ FLONUM_TYPE f;
+ LITTLENUM_TYPE arr[10];
+ double dv;
+ float fv;
+ static char sbuf[40];
+
+ if (gen) {
+ f = generic_floating_point_number;
+ generic_floating_point_number = *gen;
+ }
+ gen_to_words(&arr[0], 4, 11);
+ memcpy(&dv, &arr[0], sizeof(double));
+ sprintf(sbuf, "%x %x %x %x %.14G ", arr[0], arr[1], arr[2], arr[3], dv);
+ gen_to_words(&arr[0], 2, 8);
+ memcpy(&fv, &arr[0], sizeof(float));
+ sprintf(sbuf + strlen(sbuf), "%x %x %.12g\n", arr[0], arr[1], fv);
+
+ if (gen) {
+ generic_floating_point_number = f;
+ }
+
+ return(sbuf);
+}
+#endif
+
+/* end of atof-ieee.c */
diff --git a/gnu/usr.bin/as/config/atof-ns32k.c b/gnu/usr.bin/as/config/atof-ns32k.c
new file mode 100644
index 0000000..cadeec0
--- /dev/null
+++ b/gnu/usr.bin/as/config/atof-ns32k.c
@@ -0,0 +1,436 @@
+/* atof_ns32k.c - turn a Flonum into a ns32k floating point number
+ Copyright (C) 1987 Free Software Foundation, Inc.
+
+This file is part of GAS, the GNU Assembler.
+
+GAS is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 1, or (at your option)
+any later version.
+
+GAS is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GAS; see the file COPYING. If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* this is atof-m68k.c hacked for ns32k */
+
+#include "as.h"
+
+extern FLONUM_TYPE generic_floating_point_number; /* Flonums returned here. */
+
+extern char EXP_CHARS[];
+ /* Precision in LittleNums. */
+#define MAX_PRECISION (4)
+#define F_PRECISION (2)
+#define D_PRECISION (4)
+
+ /* Length in LittleNums of guard bits. */
+#define GUARD (2)
+
+int /* Number of chars in flonum type 'letter'. */
+atof_sizeof (letter)
+ char letter;
+{
+ int return_value;
+
+ /*
+ * Permitting uppercase letters is probably a bad idea.
+ * Please use only lower-cased letters in case the upper-cased
+ * ones become unsupported!
+ */
+ switch (letter)
+ {
+ case 'f':
+ return_value = F_PRECISION;
+ break;
+
+ case 'd':
+ return_value = D_PRECISION;
+ break;
+
+ default:
+ return_value = 0;
+ break;
+ }
+ return (return_value);
+}
+
+static unsigned long int mask[] = {
+ 0x00000000,
+ 0x00000001,
+ 0x00000003,
+ 0x00000007,
+ 0x0000000f,
+ 0x0000001f,
+ 0x0000003f,
+ 0x0000007f,
+ 0x000000ff,
+ 0x000001ff,
+ 0x000003ff,
+ 0x000007ff,
+ 0x00000fff,
+ 0x00001fff,
+ 0x00003fff,
+ 0x00007fff,
+ 0x0000ffff,
+ 0x0001ffff,
+ 0x0003ffff,
+ 0x0007ffff,
+ 0x000fffff,
+ 0x001fffff,
+ 0x003fffff,
+ 0x007fffff,
+ 0x00ffffff,
+ 0x01ffffff,
+ 0x03ffffff,
+ 0x07ffffff,
+ 0x0fffffff,
+ 0x1fffffff,
+ 0x3fffffff,
+ 0x7fffffff,
+ 0xffffffff
+ };
+
+static int bits_left_in_littlenum;
+static int littlenums_left;
+static LITTLENUM_TYPE * littlenum_pointer;
+
+static int
+next_bits (number_of_bits)
+ int number_of_bits;
+{
+ int return_value;
+
+ if (!littlenums_left)
+ return 0;
+ if (number_of_bits >= bits_left_in_littlenum)
+ {
+ return_value = mask[bits_left_in_littlenum] & *littlenum_pointer;
+ number_of_bits -= bits_left_in_littlenum;
+ return_value <<= number_of_bits;
+ if (littlenums_left) {
+ bits_left_in_littlenum = LITTLENUM_NUMBER_OF_BITS - number_of_bits;
+ littlenum_pointer --;
+ --littlenums_left;
+ return_value |= (*littlenum_pointer>>bits_left_in_littlenum) & mask[number_of_bits];
+ }
+ }
+ else
+ {
+ bits_left_in_littlenum -= number_of_bits;
+ return_value = mask[number_of_bits] & (*littlenum_pointer>>bits_left_in_littlenum);
+ }
+ return (return_value);
+}
+
+static void
+make_invalid_floating_point_number (words)
+ LITTLENUM_TYPE * words;
+{
+ words[0]= ((unsigned)-1)>>1; /* Zero the leftmost bit */
+ words[1]= -1;
+ words[2]= -1;
+ words[3]= -1;
+}
+
+/***********************************************************************\
+* *
+* Warning: this returns 16-bit LITTLENUMs, because that is *
+* what the VAX thinks in. It is up to the caller to figure *
+* out any alignment problems and to conspire for the bytes/word *
+* to be emitted in the right order. Bigendians beware! *
+* *
+\***********************************************************************/
+
+char * /* Return pointer past text consumed. */
+atof_ns32k (str, what_kind, words)
+ char * str; /* Text to convert to binary. */
+ char what_kind; /* 'd', 'f', 'g', 'h' */
+ LITTLENUM_TYPE * words; /* Build the binary here. */
+{
+ FLONUM_TYPE f;
+ LITTLENUM_TYPE bits[MAX_PRECISION + MAX_PRECISION + GUARD];
+ /* Extra bits for zeroed low-order bits. */
+ /* The 1st MAX_PRECISION are zeroed, */
+ /* the last contain flonum bits. */
+ char * return_value;
+ int precision; /* Number of 16-bit words in the format. */
+ long int exponent_bits;
+
+ long int exponent_1;
+ long int exponent_2;
+ long int exponent_3;
+ long int exponent_4;
+ int exponent_skippage;
+ LITTLENUM_TYPE word1;
+ LITTLENUM_TYPE * lp;
+
+ return_value = str;
+ f.low = bits + MAX_PRECISION;
+ f.high = NULL;
+ f.leader = NULL;
+ f.exponent = NULL;
+ f.sign = '\0';
+
+ /* Use more LittleNums than seems */
+ /* necessary: the highest flonum may have */
+ /* 15 leading 0 bits, so could be useless. */
+
+ bzero (bits, sizeof(LITTLENUM_TYPE) * MAX_PRECISION);
+
+ switch (what_kind) {
+ case 'f':
+ precision = F_PRECISION;
+ exponent_bits = 8;
+ break;
+
+ case 'd':
+ precision = D_PRECISION;
+ exponent_bits = 11;
+ break;
+
+ default:
+ make_invalid_floating_point_number (words);
+ return NULL;
+ }
+
+ f.high = f.low + precision - 1 + GUARD;
+
+ if (atof_generic (& return_value, ".", EXP_CHARS, & f)) {
+ as_warn("Error converting floating point number (Exponent overflow?)");
+ make_invalid_floating_point_number (words);
+ return NULL;
+ }
+
+ if (f.low > f.leader) {
+ /* 0.0e0 seen. */
+ bzero (words, sizeof(LITTLENUM_TYPE) * precision);
+ return return_value;
+ }
+
+ if (f.sign != '+' && f.sign != '-') {
+ make_invalid_floating_point_number(words);
+ return NULL;
+ }
+
+
+ /*
+ * All vaxen floating_point formats (so far) have:
+ * Bit 15 is sign bit.
+ * Bits 14:n are excess-whatever exponent.
+ * Bits n-1:0 (if any) are most significant bits of fraction.
+ * Bits 15:0 of the next word are the next most significant bits.
+ * And so on for each other word.
+ *
+ * So we need: number of bits of exponent, number of bits of
+ * mantissa.
+ */
+ bits_left_in_littlenum = LITTLENUM_NUMBER_OF_BITS;
+ littlenum_pointer = f.leader;
+ littlenums_left = 1 + f.leader-f.low;
+ /* Seek (and forget) 1st significant bit */
+ for (exponent_skippage = 0;! next_bits(1); exponent_skippage ++)
+ ;
+ exponent_1 = f.exponent + f.leader + 1 - f.low;
+ /* Radix LITTLENUM_RADIX, point just higher than f.leader. */
+ exponent_2 = exponent_1 * LITTLENUM_NUMBER_OF_BITS;
+ /* Radix 2. */
+ exponent_3 = exponent_2 - exponent_skippage;
+ /* Forget leading zeros, forget 1st bit. */
+ exponent_4 = exponent_3 + ((1 << (exponent_bits - 1)) - 2);
+ /* Offset exponent. */
+
+ if (exponent_4 & ~ mask[exponent_bits]) {
+ /*
+ * Exponent overflow. Lose immediately.
+ */
+
+ /*
+ * We leave return_value alone: admit we read the
+ * number, but return a floating exception
+ * because we can't encode the number.
+ */
+
+ as_warn("Exponent overflow in floating-point number");
+ make_invalid_floating_point_number (words);
+ return return_value;
+ }
+ lp = words;
+
+ /* Word 1. Sign, exponent and perhaps high bits. */
+ /* Assume 2's complement integers. */
+ word1 = ((exponent_4 & mask[exponent_bits]) << (15 - exponent_bits)) |
+ ((f.sign == '+') ? 0 : 0x8000) | next_bits (15 - exponent_bits);
+ * lp ++ = word1;
+
+ /* The rest of the words are just mantissa bits. */
+ for (; lp < words + precision; lp++)
+ * lp = next_bits (LITTLENUM_NUMBER_OF_BITS);
+
+ if (next_bits (1)) {
+ unsigned long int carry;
+ /*
+ * Since the NEXT bit is a 1, round UP the mantissa.
+ * The cunning design of these hidden-1 floats permits
+ * us to let the mantissa overflow into the exponent, and
+ * it 'does the right thing'. However, we lose if the
+ * highest-order bit of the lowest-order word flips.
+ * Is that clear?
+ */
+
+
+/* #if (sizeof(carry)) < ((sizeof(bits[0]) * BITS_PER_CHAR) + 2)
+ Please allow at least 1 more bit in carry than is in a LITTLENUM.
+ We need that extra bit to hold a carry during a LITTLENUM carry
+ propagation. Another extra bit (kept 0) will assure us that we
+ don't get a sticky sign bit after shifting right, and that
+ permits us to propagate the carry without any masking of bits.
+#endif */
+ for (carry = 1, lp --; carry && (lp >= words); lp --) {
+ carry = * lp + carry;
+ * lp = carry;
+ carry >>= LITTLENUM_NUMBER_OF_BITS;
+ }
+ if ( (word1 ^ *words) & (1 << (LITTLENUM_NUMBER_OF_BITS - 1)) ) {
+ /* We leave return_value alone: admit we read the
+ * number, but return a floating exception
+ * because we can't encode the number.
+ */
+ make_invalid_floating_point_number (words);
+ return return_value;
+ }
+ }
+ return (return_value);
+}
+
+/* This is really identical to atof_ns32k except for some details */
+
+gen_to_words(words,precision,exponent_bits)
+LITTLENUM_TYPE *words;
+long int exponent_bits;
+{
+ int return_value=0;
+
+ long int exponent_1;
+ long int exponent_2;
+ long int exponent_3;
+ long int exponent_4;
+ int exponent_skippage;
+ LITTLENUM_TYPE word1;
+ LITTLENUM_TYPE * lp;
+
+ if (generic_floating_point_number.low > generic_floating_point_number.leader) {
+ /* 0.0e0 seen. */
+ bzero (words, sizeof(LITTLENUM_TYPE) * precision);
+ return return_value;
+ }
+
+ /*
+ * All vaxen floating_point formats (so far) have:
+ * Bit 15 is sign bit.
+ * Bits 14:n are excess-whatever exponent.
+ * Bits n-1:0 (if any) are most significant bits of fraction.
+ * Bits 15:0 of the next word are the next most significant bits.
+ * And so on for each other word.
+ *
+ * So we need: number of bits of exponent, number of bits of
+ * mantissa.
+ */
+ bits_left_in_littlenum = LITTLENUM_NUMBER_OF_BITS;
+ littlenum_pointer = generic_floating_point_number.leader;
+ littlenums_left = 1+generic_floating_point_number.leader - generic_floating_point_number.low;
+ /* Seek (and forget) 1st significant bit */
+ for (exponent_skippage = 0;! next_bits(1); exponent_skippage ++)
+ ;
+ exponent_1 = generic_floating_point_number.exponent + generic_floating_point_number.leader + 1 -
+ generic_floating_point_number.low;
+ /* Radix LITTLENUM_RADIX, point just higher than generic_floating_point_number.leader. */
+ exponent_2 = exponent_1 * LITTLENUM_NUMBER_OF_BITS;
+ /* Radix 2. */
+ exponent_3 = exponent_2 - exponent_skippage;
+ /* Forget leading zeros, forget 1st bit. */
+ exponent_4 = exponent_3 + ((1 << (exponent_bits - 1)) - 2);
+ /* Offset exponent. */
+
+ if (exponent_4 & ~ mask[exponent_bits]) {
+ /*
+ * Exponent overflow. Lose immediately.
+ */
+
+ /*
+ * We leave return_value alone: admit we read the
+ * number, but return a floating exception
+ * because we can't encode the number.
+ */
+
+ make_invalid_floating_point_number (words);
+ return return_value;
+ }
+ lp = words;
+
+ /* Word 1. Sign, exponent and perhaps high bits. */
+ /* Assume 2's complement integers. */
+ word1 = ((exponent_4 & mask[exponent_bits]) << (15 - exponent_bits)) |
+ ((generic_floating_point_number.sign == '+') ? 0 : 0x8000) | next_bits (15 - exponent_bits);
+ * lp ++ = word1;
+
+ /* The rest of the words are just mantissa bits. */
+ for (; lp < words + precision; lp++)
+ * lp = next_bits (LITTLENUM_NUMBER_OF_BITS);
+
+ if (next_bits (1)) {
+ unsigned long int carry;
+ /*
+ * Since the NEXT bit is a 1, round UP the mantissa.
+ * The cunning design of these hidden-1 floats permits
+ * us to let the mantissa overflow into the exponent, and
+ * it 'does the right thing'. However, we lose if the
+ * highest-order bit of the lowest-order word flips.
+ * Is that clear?
+ */
+
+
+/* #if (sizeof(carry)) < ((sizeof(bits[0]) * BITS_PER_CHAR) + 2)
+ Please allow at least 1 more bit in carry than is in a LITTLENUM.
+ We need that extra bit to hold a carry during a LITTLENUM carry
+ propagation. Another extra bit (kept 0) will assure us that we
+ don't get a sticky sign bit after shifting right, and that
+ permits us to propagate the carry without any masking of bits.
+#endif */
+ for (carry = 1, lp --; carry && (lp >= words); lp --) {
+ carry = * lp + carry;
+ * lp = carry;
+ carry >>= LITTLENUM_NUMBER_OF_BITS;
+ }
+ if ( (word1 ^ *words) & (1 << (LITTLENUM_NUMBER_OF_BITS - 1)) ) {
+ /* We leave return_value alone: admit we read the
+ * number, but return a floating exception
+ * because we can't encode the number.
+ */
+ make_invalid_floating_point_number (words);
+ return return_value;
+ }
+ }
+ return (return_value);
+}
+
+/* This routine is a real kludge. Someone really should do it better, but
+ I'm too lazy, and I don't understand this stuff all too well anyway
+ (JF)
+ */
+void int_to_gen(x)
+long x;
+{
+ char buf[20];
+ char *bufp;
+
+ sprintf(buf,"%ld",x);
+ bufp= &buf[0];
+ if (atof_generic(&bufp,".", EXP_CHARS, &generic_floating_point_number))
+ as_warn("Error converting number to floating point (Exponent overflow?)");
+}
diff --git a/gnu/usr.bin/as/config/atof-tahoe.c b/gnu/usr.bin/as/config/atof-tahoe.c
new file mode 100644
index 0000000..64d00ea
--- /dev/null
+++ b/gnu/usr.bin/as/config/atof-tahoe.c
@@ -0,0 +1,428 @@
+/* atof_tahoe.c - turn a string into a Tahoe floating point number
+ Copyright (C) 1987 Free Software Foundation, Inc.
+ */
+
+/* This is really a simplified version of atof_vax.c. I glommed it wholesale
+ and then shaved it down. I don't even know how it works. (Don't you find
+ my honesty refreshing? bowen@cs.Buffalo.EDU (Devon E Bowen)
+
+ I don't allow uppercase letters in the precision descrpitors. Ie 'f' and
+ 'd' are allowed but 'F' and 'D' aren't */
+
+#include "as.h"
+
+/* Precision in LittleNums. */
+#define MAX_PRECISION (4)
+#define D_PRECISION (4)
+#define F_PRECISION (2)
+
+/* Precision in chars. */
+#define D_PRECISION_CHARS (8)
+#define F_PRECISION_CHARS (4)
+
+ /* Length in LittleNums of guard bits. */
+#define GUARD (2)
+
+static const long int mask [] = {
+ 0x00000000,
+ 0x00000001,
+ 0x00000003,
+ 0x00000007,
+ 0x0000000f,
+ 0x0000001f,
+ 0x0000003f,
+ 0x0000007f,
+ 0x000000ff,
+ 0x000001ff,
+ 0x000003ff,
+ 0x000007ff,
+ 0x00000fff,
+ 0x00001fff,
+ 0x00003fff,
+ 0x00007fff,
+ 0x0000ffff,
+ 0x0001ffff,
+ 0x0003ffff,
+ 0x0007ffff,
+ 0x000fffff,
+ 0x001fffff,
+ 0x003fffff,
+ 0x007fffff,
+ 0x00ffffff,
+ 0x01ffffff,
+ 0x03ffffff,
+ 0x07ffffff,
+ 0x0fffffff,
+ 0x1fffffff,
+ 0x3fffffff,
+ 0x7fffffff,
+ 0xffffffff
+ };
+
+
+/* Shared between flonum_gen2tahoe and next_bits */
+static int bits_left_in_littlenum;
+static LITTLENUM_TYPE * littlenum_pointer;
+static LITTLENUM_TYPE * littlenum_end;
+
+#if __STDC__ == 1
+
+int flonum_gen2tahoe(int format_letter, FLONUM_TYPE *f, LITTLENUM_TYPE *words);
+
+#else /* not __STDC__ */
+
+int flonum_gen2tahoe();
+
+#endif /* not __STDC__ */
+
+
+static int
+next_bits (number_of_bits)
+ int number_of_bits;
+{
+ int return_value;
+
+ if(littlenum_pointer<littlenum_end)
+ return 0;
+ if (number_of_bits >= bits_left_in_littlenum)
+ {
+ return_value = mask [bits_left_in_littlenum] & * littlenum_pointer;
+ number_of_bits -= bits_left_in_littlenum;
+ return_value <<= number_of_bits;
+ bits_left_in_littlenum = LITTLENUM_NUMBER_OF_BITS - number_of_bits;
+ littlenum_pointer --;
+ if(littlenum_pointer>=littlenum_end)
+ return_value |= ((*littlenum_pointer) >> (bits_left_in_littlenum)) &
+ mask [number_of_bits];
+ }
+ else
+ {
+ bits_left_in_littlenum -= number_of_bits;
+ return_value = mask [number_of_bits] &
+ ((*littlenum_pointer) >> bits_left_in_littlenum);
+ }
+ return (return_value);
+}
+
+static void
+make_invalid_floating_point_number (words)
+ LITTLENUM_TYPE * words;
+{
+ *words = 0x8000; /* Floating Reserved Operand Code */
+}
+
+static int /* 0 means letter is OK. */
+what_kind_of_float (letter, precisionP, exponent_bitsP)
+ char letter; /* In: lowercase please. What kind of float? */
+ int * precisionP; /* Number of 16-bit words in the float. */
+ long int * exponent_bitsP; /* Number of exponent bits. */
+{
+ int retval; /* 0: OK. */
+
+ retval = 0;
+ switch (letter)
+ {
+ case 'f':
+ * precisionP = F_PRECISION;
+ * exponent_bitsP = 8;
+ break;
+
+ case 'd':
+ * precisionP = D_PRECISION;
+ * exponent_bitsP = 8;
+ break;
+
+ default:
+ retval = 69;
+ break;
+ }
+ return (retval);
+}
+
+/***********************************************************************\
+* *
+* Warning: this returns 16-bit LITTLENUMs, because that is *
+* what the VAX thinks in. It is up to the caller to figure *
+* out any alignment problems and to conspire for the bytes/word *
+* to be emitted in the right order. Bigendians beware! *
+* *
+\***********************************************************************/
+
+char * /* Return pointer past text consumed. */
+atof_tahoe (str, what_kind, words)
+ char * str; /* Text to convert to binary. */
+ char what_kind; /* 'd', 'f', 'g', 'h' */
+ LITTLENUM_TYPE * words; /* Build the binary here. */
+{
+ FLONUM_TYPE f;
+ LITTLENUM_TYPE bits [MAX_PRECISION + MAX_PRECISION + GUARD];
+ /* Extra bits for zeroed low-order bits. */
+ /* The 1st MAX_PRECISION are zeroed, */
+ /* the last contain flonum bits. */
+ char * return_value;
+ int precision; /* Number of 16-bit words in the format. */
+ long int exponent_bits;
+
+ return_value = str;
+ f . low = bits + MAX_PRECISION;
+ f . high = NULL;
+ f . leader = NULL;
+ f . exponent = NULL;
+ f . sign = '\0';
+
+ if (what_kind_of_float (what_kind, & precision, & exponent_bits))
+ {
+ return_value = NULL; /* We lost. */
+ make_invalid_floating_point_number (words);
+ }
+ if (return_value)
+ {
+ memset(bits, '\0', sizeof(LITTLENUM_TYPE) * MAX_PRECISION);
+
+ /* Use more LittleNums than seems */
+ /* necessary: the highest flonum may have */
+ /* 15 leading 0 bits, so could be useless. */
+ f . high = f . low + precision - 1 + GUARD;
+
+ if (atof_generic (& return_value, ".", "eE", & f))
+ {
+ make_invalid_floating_point_number (words);
+ return_value = NULL; /* we lost */
+ }
+ else
+ {
+ if (flonum_gen2tahoe (what_kind, & f, words))
+ {
+ return_value = NULL;
+ }
+ }
+ }
+ return (return_value);
+}
+
+/*
+ * In: a flonum, a Tahoe floating point format.
+ * Out: a Tahoe floating-point bit pattern.
+ */
+
+int /* 0: OK. */
+flonum_gen2tahoe (format_letter, f, words)
+ char format_letter; /* One of 'd' 'f'. */
+ FLONUM_TYPE * f;
+ LITTLENUM_TYPE * words; /* Deliver answer here. */
+{
+ LITTLENUM_TYPE * lp;
+ int precision;
+ long int exponent_bits;
+ int return_value; /* 0 == OK. */
+
+ return_value = what_kind_of_float(format_letter,&precision,&exponent_bits);
+ if (return_value != 0)
+ {
+ make_invalid_floating_point_number (words);
+ }
+ else
+ {
+ if (f -> low > f -> leader)
+ {
+ /* 0.0e0 seen. */
+ memset(words, '\0', sizeof(LITTLENUM_TYPE) * precision);
+ }
+ else
+ {
+ long int exponent_1;
+ long int exponent_2;
+ long int exponent_3;
+ long int exponent_4;
+ int exponent_skippage;
+ LITTLENUM_TYPE word1;
+
+ /* JF: Deal with new Nan, +Inf and -Inf codes */
+ if(f->sign!='-' && f->sign!='+') {
+ make_invalid_floating_point_number(words);
+ return return_value;
+ }
+ /*
+ * All tahoe floating_point formats have:
+ * Bit 15 is sign bit.
+ * Bits 14:n are excess-whatever exponent.
+ * Bits n-1:0 (if any) are most significant bits of fraction.
+ * Bits 15:0 of the next word are the next most significant bits.
+ * And so on for each other word.
+ *
+ * So we need: number of bits of exponent, number of bits of
+ * mantissa.
+ */
+
+ bits_left_in_littlenum = LITTLENUM_NUMBER_OF_BITS;
+ littlenum_pointer = f -> leader;
+ littlenum_end = f->low;
+ /* Seek (and forget) 1st significant bit */
+ for (exponent_skippage = 0;
+ ! next_bits(1);
+ exponent_skippage ++)
+ {
+ }
+ exponent_1 = f -> exponent + f -> leader + 1 - f -> low;
+ /* Radix LITTLENUM_RADIX, point just higher than f -> leader. */
+ exponent_2 = exponent_1 * LITTLENUM_NUMBER_OF_BITS;
+ /* Radix 2. */
+ exponent_3 = exponent_2 - exponent_skippage;
+ /* Forget leading zeros, forget 1st bit. */
+ exponent_4 = exponent_3 + (1 << (exponent_bits - 1));
+ /* Offset exponent. */
+
+ if (exponent_4 & ~ mask [exponent_bits])
+ {
+ /*
+ * Exponent overflow. Lose immediately.
+ */
+
+ make_invalid_floating_point_number (words);
+
+ /*
+ * We leave return_value alone: admit we read the
+ * number, but return a floating exception
+ * because we can't encode the number.
+ */
+ }
+ else
+ {
+ lp = words;
+
+ /* Word 1. Sign, exponent and perhaps high bits. */
+ /* Assume 2's complement integers. */
+ word1 = ((exponent_4 & mask [exponent_bits]) << (15 - exponent_bits))
+ | ((f -> sign == '+') ? 0 : 0x8000)
+ | next_bits (15 - exponent_bits);
+ * lp ++ = word1;
+
+ /* The rest of the words are just mantissa bits. */
+ for (; lp < words + precision; lp++)
+ {
+ * lp = next_bits (LITTLENUM_NUMBER_OF_BITS);
+ }
+
+ if (next_bits (1))
+ {
+ /*
+ * Since the NEXT bit is a 1, round UP the mantissa.
+ * The cunning design of these hidden-1 floats permits
+ * us to let the mantissa overflow into the exponent, and
+ * it 'does the right thing'. However, we lose if the
+ * highest-order bit of the lowest-order word flips.
+ * Is that clear?
+ */
+
+ unsigned long int carry;
+
+ /*
+ #if (sizeof(carry)) < ((sizeof(bits[0]) * BITS_PER_CHAR) + 2)
+ Please allow at least 1 more bit in carry than is in a LITTLENUM.
+ We need that extra bit to hold a carry during a LITTLENUM carry
+ propagation. Another extra bit (kept 0) will assure us that we
+ don't get a sticky sign bit after shifting right, and that
+ permits us to propagate the carry without any masking of bits.
+ #endif
+ */
+ for (carry = 1, lp --;
+ carry && (lp >= words);
+ lp --)
+ {
+ carry = * lp + carry;
+ * lp = carry;
+ carry >>= LITTLENUM_NUMBER_OF_BITS;
+ }
+
+ if ( (word1 ^ *words) & (1 << (LITTLENUM_NUMBER_OF_BITS - 1)) )
+ {
+ make_invalid_floating_point_number (words);
+ /*
+ * We leave return_value alone: admit we read the
+ * number, but return a floating exception
+ * because we can't encode the number.
+ */
+ }
+ } /* if (we needed to round up) */
+ } /* if (exponent overflow) */
+ } /* if (0.0e0) */
+ } /* if (float_type was OK) */
+ return (return_value);
+}
+
+/*
+ * md_atof()
+ *
+ * In: input_line_pointer -> the 1st character of a floating-point
+ * number.
+ * 1 letter denoting the type of statement that wants a
+ * binary floating point number returned.
+ * Address of where to build floating point literal.
+ * Assumed to be 'big enough'.
+ * Address of where to return size of literal (in chars).
+ *
+ * Out: Input_line_pointer -> of next char after floating number.
+ * Error message, or "".
+ * Floating point literal.
+ * Number of chars we used for the literal.
+ */
+
+char *
+md_atof (what_statement_type, literalP, sizeP)
+ char what_statement_type;
+ char * literalP;
+ int * sizeP;
+{
+ LITTLENUM_TYPE words [MAX_PRECISION];
+ register char kind_of_float;
+ register int number_of_chars;
+ register LITTLENUM_TYPE * littlenum_pointer;
+
+ switch (what_statement_type)
+ {
+ case 'f': /* .ffloat */
+ case 'd': /* .dfloat */
+ kind_of_float = what_statement_type;
+ break;
+
+ default:
+ kind_of_float = 0;
+ break;
+ };
+
+ if (kind_of_float)
+ {
+ register LITTLENUM_TYPE * limit;
+
+ input_line_pointer = atof_tahoe (input_line_pointer,
+ kind_of_float,
+ words);
+ /*
+ * The atof_tahoe() builds up 16-bit numbers.
+ * Since the assembler may not be running on
+ * a different-endian machine, be very careful about
+ * converting words to chars.
+ */
+ number_of_chars = (kind_of_float == 'f' ? F_PRECISION_CHARS :
+ (kind_of_float == 'd' ? D_PRECISION_CHARS : 0));
+ know(number_of_chars<=MAX_PRECISION*sizeof(LITTLENUM_TYPE));
+ limit = words + (number_of_chars / sizeof(LITTLENUM_TYPE));
+ for (littlenum_pointer = words;
+ littlenum_pointer < limit;
+ littlenum_pointer ++)
+ {
+ md_number_to_chars(literalP,*littlenum_pointer,
+ sizeof(LITTLENUM_TYPE));
+ literalP += sizeof(LITTLENUM_TYPE);
+ };
+ }
+ else
+ {
+ number_of_chars = 0;
+ };
+
+ * sizeP = number_of_chars;
+ return (kind_of_float ? "" : "Bad call to md_atof()");
+} /* md_atof() */
+
+/* atof_tahoe.c */
diff --git a/gnu/usr.bin/as/config/atof-vax.c b/gnu/usr.bin/as/config/atof-vax.c
new file mode 100644
index 0000000..56ad35a
--- /dev/null
+++ b/gnu/usr.bin/as/config/atof-vax.c
@@ -0,0 +1,497 @@
+/* atof_vax.c - turn a Flonum into a VAX floating point number
+ Copyright (C) 1987, 1992 Free Software Foundation, Inc.
+
+ This file is part of GAS, the GNU Assembler.
+
+ GAS is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GAS is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GAS; see the file COPYING. If not, write to
+ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* JF added these two for md_atof() */
+#include "as.h"
+
+/* Precision in LittleNums. */
+#define MAX_PRECISION (8)
+#define H_PRECISION (8)
+#define G_PRECISION (4)
+#define D_PRECISION (4)
+#define F_PRECISION (2)
+
+/* Length in LittleNums of guard bits. */
+#define GUARD (2)
+
+#if __STDC__ == 1
+
+int flonum_gen2vax(int format_letter, FLONUM_TYPE *f, LITTLENUM_TYPE *words);
+
+#else /* not __STDC__ */
+
+int flonum_gen2vax();
+
+#endif /* not __STDC__ */
+
+int /* Number of chars in flonum type 'letter'. */
+ atof_vax_sizeof (letter)
+char letter;
+{
+ int return_value;
+
+ /*
+ * Permitting uppercase letters is probably a bad idea.
+ * Please use only lower-cased letters in case the upper-cased
+ * ones become unsupported!
+ */
+ switch (letter)
+ {
+ case 'f':
+ case 'F':
+ return_value = 4;
+ break;
+
+ case 'd':
+ case 'D':
+ case 'g':
+ case 'G':
+ return_value = 8;
+ break;
+
+ case 'h':
+ case 'H':
+ return_value = 16;
+ break;
+
+ default:
+ return_value = 0;
+ break;
+ }
+ return (return_value);
+} /* atof_vax_sizeof */
+
+static const long mask[] = {
+ 0x00000000,
+ 0x00000001,
+ 0x00000003,
+ 0x00000007,
+ 0x0000000f,
+ 0x0000001f,
+ 0x0000003f,
+ 0x0000007f,
+ 0x000000ff,
+ 0x000001ff,
+ 0x000003ff,
+ 0x000007ff,
+ 0x00000fff,
+ 0x00001fff,
+ 0x00003fff,
+ 0x00007fff,
+ 0x0000ffff,
+ 0x0001ffff,
+ 0x0003ffff,
+ 0x0007ffff,
+ 0x000fffff,
+ 0x001fffff,
+ 0x003fffff,
+ 0x007fffff,
+ 0x00ffffff,
+ 0x01ffffff,
+ 0x03ffffff,
+ 0x07ffffff,
+ 0x0fffffff,
+ 0x1fffffff,
+ 0x3fffffff,
+ 0x7fffffff,
+ 0xffffffff
+ };
+
+
+/* Shared between flonum_gen2vax and next_bits */
+static int bits_left_in_littlenum;
+static LITTLENUM_TYPE * littlenum_pointer;
+static LITTLENUM_TYPE * littlenum_end;
+
+static int
+ next_bits (number_of_bits)
+int number_of_bits;
+{
+ int return_value;
+
+ if (littlenum_pointer<littlenum_end)
+ return 0;
+ if (number_of_bits >= bits_left_in_littlenum)
+ {
+ return_value = mask[bits_left_in_littlenum] & * littlenum_pointer;
+ number_of_bits -= bits_left_in_littlenum;
+ return_value <<= number_of_bits;
+ bits_left_in_littlenum = LITTLENUM_NUMBER_OF_BITS - number_of_bits;
+ littlenum_pointer --;
+ if (littlenum_pointer >= littlenum_end)
+ return_value |= ( (* littlenum_pointer) >> (bits_left_in_littlenum) ) & mask[number_of_bits];
+ }
+ else
+ {
+ bits_left_in_littlenum -= number_of_bits;
+ return_value = mask[number_of_bits] & ( (* littlenum_pointer) >> bits_left_in_littlenum);
+ }
+ return (return_value);
+}
+
+static void
+ make_invalid_floating_point_number (words)
+LITTLENUM_TYPE * words;
+{
+ * words = 0x8000; /* Floating Reserved Operand Code */
+}
+
+static int /* 0 means letter is OK. */
+ what_kind_of_float (letter, precisionP, exponent_bitsP)
+char letter; /* In: lowercase please. What kind of float? */
+int * precisionP; /* Number of 16-bit words in the float. */
+long * exponent_bitsP; /* Number of exponent bits. */
+{
+ int retval; /* 0: OK. */
+
+ retval = 0;
+ switch (letter)
+ {
+ case 'f':
+ * precisionP = F_PRECISION;
+ * exponent_bitsP = 8;
+ break;
+
+ case 'd':
+ * precisionP = D_PRECISION;
+ * exponent_bitsP = 8;
+ break;
+
+ case 'g':
+ * precisionP = G_PRECISION;
+ * exponent_bitsP = 11;
+ break;
+
+ case 'h':
+ * precisionP = H_PRECISION;
+ * exponent_bitsP = 15;
+ break;
+
+ default:
+ retval = 69;
+ break;
+ }
+ return (retval);
+}
+
+/***********************************************************************\
+ * *
+ * Warning: this returns 16-bit LITTLENUMs, because that is *
+ * what the VAX thinks in. It is up to the caller to figure *
+ * out any alignment problems and to conspire for the bytes/word *
+ * to be emitted in the right order. Bigendians beware! *
+ * *
+ \***********************************************************************/
+
+char * /* Return pointer past text consumed. */
+ atof_vax(str, what_kind, words)
+char *str; /* Text to convert to binary. */
+char what_kind; /* 'd', 'f', 'g', 'h' */
+LITTLENUM_TYPE *words; /* Build the binary here. */
+{
+ FLONUM_TYPE f;
+ LITTLENUM_TYPE bits[MAX_PRECISION + MAX_PRECISION + GUARD];
+ /* Extra bits for zeroed low-order bits. */
+ /* The 1st MAX_PRECISION are zeroed, */
+ /* the last contain flonum bits. */
+ char *return_value;
+ int precision; /* Number of 16-bit words in the format. */
+ long exponent_bits;
+
+ return_value = str;
+ f.low = bits + MAX_PRECISION;
+ f.high = NULL;
+ f.leader = NULL;
+ f.exponent = NULL;
+ f.sign = '\0';
+
+ if (what_kind_of_float (what_kind, & precision, & exponent_bits)) {
+ return_value = NULL; /* We lost. */
+ make_invalid_floating_point_number (words);
+ }
+
+ if (return_value) {
+ memset(bits, '\0', sizeof(LITTLENUM_TYPE) * MAX_PRECISION);
+
+ /* Use more LittleNums than seems */
+ /* necessary: the highest flonum may have */
+ /* 15 leading 0 bits, so could be useless. */
+ f.high = f.low + precision - 1 + GUARD;
+
+ if (atof_generic (& return_value, ".", "eE", & f)) {
+ make_invalid_floating_point_number (words);
+ return_value = NULL; /* we lost */
+ } else {
+ if (flonum_gen2vax(what_kind, & f, words)) {
+ return_value = NULL;
+ }
+ }
+ }
+ return(return_value);
+} /* atof_vax() */
+
+/*
+ * In: a flonum, a vax floating point format.
+ * Out: a vax floating-point bit pattern.
+ */
+
+int /* 0: OK. */
+ flonum_gen2vax (format_letter, f, words)
+char format_letter; /* One of 'd' 'f' 'g' 'h'. */
+FLONUM_TYPE *f;
+LITTLENUM_TYPE *words; /* Deliver answer here. */
+{
+ LITTLENUM_TYPE *lp;
+ int precision;
+ long exponent_bits;
+ int return_value; /* 0 == OK. */
+
+ return_value = what_kind_of_float(format_letter, &precision, &exponent_bits);
+
+ if (return_value != 0) {
+ make_invalid_floating_point_number (words);
+ } else {
+ if (f->low > f->leader) {
+ /* 0.0e0 seen. */
+memset(words, '\0', sizeof(LITTLENUM_TYPE) * precision);
+ } else {
+ long exponent_1;
+ long exponent_2;
+ long exponent_3;
+ long exponent_4;
+ int exponent_skippage;
+ LITTLENUM_TYPE word1;
+
+ /* JF: Deal with new Nan, +Inf and -Inf codes */
+ if (f->sign != '-' && f->sign != '+') {
+ make_invalid_floating_point_number(words);
+ return return_value;
+ }
+ /*
+ * All vaxen floating_point formats (so far) have:
+ * Bit 15 is sign bit.
+ * Bits 14:n are excess-whatever exponent.
+ * Bits n-1:0 (if any) are most significant bits of fraction.
+ * Bits 15:0 of the next word are the next most significant bits.
+ * And so on for each other word.
+ *
+ * All this to be compatible with a KF11?? (Which is still faster
+ * than lots of vaxen I can think of, but it also has higher
+ * maintenance costs ... sigh).
+ *
+ * So we need: number of bits of exponent, number of bits of
+ * mantissa.
+ */
+
+#ifdef NEVER /******* This zeroing seems redundant - Dean 3may86 **********/
+ /*
+ * No matter how few bits we got back from the atof()
+ * routine, add enough zero littlenums so the rest of the
+ * code won't run out of "significant" bits in the mantissa.
+ */
+ {
+ LITTLENUM_TYPE *ltp;
+ for (ltp = f->leader + 1;
+ ltp <= f->low + precision;
+ ltp++) {
+ *ltp = 0;
+ }
+ }
+#endif
+
+ bits_left_in_littlenum = LITTLENUM_NUMBER_OF_BITS;
+ littlenum_pointer = f->leader;
+ littlenum_end = f->low;
+ /* Seek (and forget) 1st significant bit */
+ for (exponent_skippage = 0;
+ ! next_bits(1);
+ exponent_skippage ++) ;;
+
+ exponent_1 = f->exponent + f->leader + 1 - f->low;
+ /* Radix LITTLENUM_RADIX, point just higher than f->leader. */
+ exponent_2 = exponent_1 * LITTLENUM_NUMBER_OF_BITS;
+ /* Radix 2. */
+ exponent_3 = exponent_2 - exponent_skippage;
+ /* Forget leading zeros, forget 1st bit. */
+ exponent_4 = exponent_3 + (1 << (exponent_bits - 1));
+ /* Offset exponent. */
+
+ if (exponent_4 & ~mask[exponent_bits]) {
+ /*
+ * Exponent overflow. Lose immediately.
+ */
+
+ make_invalid_floating_point_number (words);
+
+ /*
+ * We leave return_value alone: admit we read the
+ * number, but return a floating exception
+ * because we can't encode the number.
+ */
+ } else {
+ lp = words;
+
+ /* Word 1. Sign, exponent and perhaps high bits. */
+ /* Assume 2's complement integers. */
+ word1 = (((exponent_4 &mask[exponent_bits]) << (15 - exponent_bits))
+ | ((f->sign == '+') ? 0 : 0x8000)
+ | next_bits(15 - exponent_bits));
+ *lp++ = word1;
+
+ /* The rest of the words are just mantissa bits. */
+ for (; lp < words + precision; lp++) {
+ *lp = next_bits(LITTLENUM_NUMBER_OF_BITS);
+ }
+
+ if (next_bits (1)) {
+ /*
+ * Since the NEXT bit is a 1, round UP the mantissa.
+ * The cunning design of these hidden-1 floats permits
+ * us to let the mantissa overflow into the exponent, and
+ * it 'does the right thing'. However, we lose if the
+ * highest-order bit of the lowest-order word flips.
+ * Is that clear?
+ */
+
+ unsigned long carry;
+
+ /*
+ #if (sizeof(carry)) < ((sizeof(bits[0]) * BITS_PER_CHAR) + 2)
+ Please allow at least 1 more bit in carry than is in a LITTLENUM.
+ We need that extra bit to hold a carry during a LITTLENUM carry
+ propagation. Another extra bit (kept 0) will assure us that we
+ don't get a sticky sign bit after shifting right, and that
+ permits us to propagate the carry without any masking of bits.
+ #endif
+ */
+ for (carry = 1, lp--;
+ carry && (lp >= words);
+ lp--) {
+ carry = *lp + carry;
+ *lp = carry;
+ carry >>= LITTLENUM_NUMBER_OF_BITS;
+ }
+
+ if ((word1 ^ *words) & (1 << (LITTLENUM_NUMBER_OF_BITS - 1))) {
+ make_invalid_floating_point_number(words);
+ /*
+ * We leave return_value alone: admit we read the
+ * number, but return a floating exception
+ * because we can't encode the number.
+ */
+ }
+ } /* if (we needed to round up) */
+ } /* if (exponent overflow) */
+ } /* if (0.0e0) */
+ } /* if (float_type was OK) */
+ return(return_value);
+} /* flonum_gen2vax() */
+
+
+/* JF this used to be in vax.c but this looks like a better place for it */
+
+/*
+ * md_atof()
+ *
+ * In: input_line_pointer->the 1st character of a floating-point
+ * number.
+ * 1 letter denoting the type of statement that wants a
+ * binary floating point number returned.
+ * Address of where to build floating point literal.
+ * Assumed to be 'big enough'.
+ * Address of where to return size of literal (in chars).
+ *
+ * Out: Input_line_pointer->of next char after floating number.
+ * Error message, or "".
+ * Floating point literal.
+ * Number of chars we used for the literal.
+ */
+
+#define MAXIMUM_NUMBER_OF_LITTLENUMS (8) /* For .hfloats. */
+
+char *
+ md_atof (what_statement_type, literalP, sizeP)
+char what_statement_type;
+char * literalP;
+int * sizeP;
+{
+ LITTLENUM_TYPE words[MAXIMUM_NUMBER_OF_LITTLENUMS];
+ register char kind_of_float;
+ register int number_of_chars;
+ register LITTLENUM_TYPE * littlenum_pointer;
+
+ switch (what_statement_type)
+ {
+ case 'F': /* .float */
+ case 'f': /* .ffloat */
+ kind_of_float = 'f';
+ break;
+
+ case 'D': /* .double */
+ case 'd': /* .dfloat */
+ kind_of_float = 'd';
+ break;
+
+ case 'g': /* .gfloat */
+ kind_of_float = 'g';
+ break;
+
+ case 'h': /* .hfloat */
+ kind_of_float = 'h';
+ break;
+
+ default:
+ kind_of_float = 0;
+ break;
+ };
+
+ if (kind_of_float)
+ {
+ register LITTLENUM_TYPE * limit;
+
+ input_line_pointer = atof_vax (input_line_pointer,
+ kind_of_float,
+ words);
+ /*
+ * The atof_vax() builds up 16-bit numbers.
+ * Since the assembler may not be running on
+ * a little-endian machine, be very careful about
+ * converting words to chars.
+ */
+ number_of_chars = atof_vax_sizeof (kind_of_float);
+ know( number_of_chars <= MAXIMUM_NUMBER_OF_LITTLENUMS * sizeof(LITTLENUM_TYPE) );
+ limit = words + (number_of_chars / sizeof(LITTLENUM_TYPE));
+ for (littlenum_pointer = words;
+ littlenum_pointer < limit;
+ littlenum_pointer ++)
+ {
+ md_number_to_chars (literalP, * littlenum_pointer, sizeof(LITTLENUM_TYPE));
+ literalP += sizeof(LITTLENUM_TYPE);
+ };
+ }
+ else
+ {
+ number_of_chars = 0;
+ };
+
+ * sizeP = number_of_chars;
+ return (kind_of_float ? "" : "Bad call to md_atof()");
+} /* md_atof() */
+
+/* end of atof-vax.c */
diff --git a/gnu/usr.bin/as/config/coff.h b/gnu/usr.bin/as/config/coff.h
new file mode 100644
index 0000000..a54f35b
--- /dev/null
+++ b/gnu/usr.bin/as/config/coff.h
@@ -0,0 +1,783 @@
+/* coff.h
+ Copyright (C) 1987, 1992 Free Software Foundation, Inc.
+
+ This file is part of GAS, the GNU Assembler.
+
+ GAS is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GAS is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GAS; see the file COPYING. If not, write to
+ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/*
+ * At this point I'm sure this file is right for i960 and I'm pretty sure it's
+ * right for a29k, although it hasn't been tested rigorously. Please feel free
+ * to add your own machine's description here. Without that info, it isn't
+ * possible to build cross development tools from elsewhere nor is it easy to
+ * continue to support your machines format.
+ *
+ * The TC_foo ifdef's are mine. They are what gas uses. The other ifdef's
+ * remain for documentation from other scavenged files. xoxorich.
+ */
+
+/********************** FILE HEADER **********************/
+
+struct filehdr {
+ unsigned short f_magic; /* magic number */
+ unsigned short f_nscns; /* number of sections */
+ long f_timdat; /* time & date stamp */
+ long f_symptr; /* file pointer to symtab */
+ long f_nsyms; /* number of symtab entries */
+ unsigned short f_opthdr; /* sizeof(optional hdr) */
+ unsigned short f_flags; /* flags */
+};
+
+/* Bits for f_flags:
+ * F_RELFLG relocation info stripped from file
+ * F_EXEC file is executable (no unresolved externel references)
+ * F_LNNO line nunbers stripped from file
+ * F_LSYMS local symbols stripped from file
+ * F_AR32WR file has byte ordering of an AR32WR machine (e.g. vax)
+ */
+#define F_RELFLG (0x0001)
+#define F_EXEC (0x0002)
+#define F_LNNO (0x0004)
+#define F_LSYMS (0x0008)
+
+#ifdef TC_I960
+#define F_AR32WR (0x0010) /* File has 32 bits per word, least
+ significant byte first. */
+#else /* TC_I960 */
+#define F_AR32WR (0x0100)
+#endif /* TC_I960 */
+
+#define F_MINMAL (0x0010) /* ??? */
+#define F_UPDATE (0x0020) /* ??? */
+#define F_SWABD (0x0040) /* ??? */
+#define F_AR16WR (0x0080) /* File has the byte ordering used by
+ the PDP*-11/70 processor. */
+#define F_AR32W (0x0200) /* File has 32 bits per word, most
+ significant byte first. */
+
+/*
+ * Intel 80960 (I960) processor flags.
+ * F_I960TYPE == mask for processor type field.
+ */
+
+#define F_I960TYPE (0xf000)
+#define F_I960CORE (0x1000)
+#define F_I960KB (0x2000)
+#define F_I960SB (0x2000)
+#define F_I960MC (0x3000)
+#define F_I960XA (0x4000)
+#define F_I960CA (0x5000)
+#define F_I960KA (0x6000)
+#define F_I960SA (0x6000)
+
+/*
+ * i80960 Magic Numbers
+ */
+
+#define I960ROMAGIC (0x160) /* read-only text segments */
+#define I960RWMAGIC (0x161) /* read-write text segments */
+
+#define I960BADMAG(x) (((x).f_magic != I960ROMAGIC) && ((x).f_magic != I960RWMAGIC))
+
+#define SIPFBOMAGIC (0x17a) /* Am29000 (Byte 0 is MSB - Big Endian) */
+#define SIPRBOMAGIC (0x17b) /* Am29000 (Byte 0 is LSB - Little Endian) */
+
+#define A29KBADMAG(x) (((x).f_magic != SIPFBOMAGIC) && ((x).f_magic != SIPRBOMAGIC))
+
+#ifdef TE_I386AIX
+# define I386MAGIC (0x175) /* Danbury AIX C compiler */
+# define I386SVMAGIC (0x14c) /* System V C Compiler */
+# define I386BADMAG(x) (((x).f_magic != I386MAGIC) && \
+ ((x).f_magic != I386SVMAGIC))
+#else /* not TE_I386AIX */
+# define I386MAGIC 0x14c
+# define I386BADMAG(x) (((x).f_magic != I386MAGIC))
+#endif /* not TE_I386AIX */
+
+
+#define FILHDR struct filehdr
+#define FILHSZ sizeof(FILHDR)
+
+
+/********************** AOUT "OPTIONAL HEADER" **********************/
+
+typedef struct {
+ unsigned long phys_addr;
+ unsigned long bitarray;
+} TAGBITS;
+
+/* These appear to be used only by exec(2). I don't know who cares
+ about them in a cross development environment. In any case, this
+ is my collection after researching the issue for a few hours.
+ Apparently, most have these have remained essentially unchanged
+ since v7 days, although a few new ones have been added. xoxorich. */
+
+#define BAD0MAGIC (0401) /* (?) "lpd (UNIX/RT)" */
+#define BAD1MAGIC (0405) /* (?) overlay */
+#define OMAGIC (0407) /* old impure format. data immediately
+ follows text. both sections are rw. */
+#define NMAGIC (0410) /* split i&d, read-only text */
+#define A_MAGIC3 (0411) /* (?) "separated I&D" */
+#define ZMAGIC (0413) /* like NMAGIC, but demand loaded */
+#define PAGEMAGIC2 (0414) /* (?) like ZMAGIC, but address zero
+ explicitly unmapped. */
+#define REGMAGIC (0414) /* (?) a PAGEMAGIC2 alias? */
+#define PAGEMAGIC3 (0415) /* (?) like ZMAGIC, but address zero mapped. */
+#define A_MAGIC5 (0437) /* (?) "system overlay, separated I&D" */
+/* intended for non-unix cross development */
+#define SASMAGIC (010000) /* Single Address Space */
+#define MASMAGIC (020000) /* (?) "Multiple (separate I & D) Address Spaces" */
+
+typedef struct aouthdr {
+ short magic; /* type of file */
+ short vstamp; /* version stamp */
+ unsigned long tsize; /* text size in bytes, padded to FW bdry*/
+ unsigned long dsize; /* initialized data " " */
+ unsigned long bsize; /* uninitialized data " " */
+#if U3B
+ unsigned long dum1;
+ unsigned long dum2; /* pad to entry point */
+#endif
+ unsigned long entry; /* entry pt. */
+ unsigned long text_start; /* base of text used for this file */
+ unsigned long data_start; /* base of data used for this file */
+ /* CAREFUL: some formats omit the tagentries member. */
+ unsigned long tagentries; /* number of tag entries to
+ follow (always zero for i960) */
+} AOUTHDR;
+
+/* return a pointer to the tag bits array */
+
+#define TAGPTR(aout) ((TAGBITS *) (&(aout.tagentries)+1))
+
+/* compute size of a header */
+
+/*#define AOUTSZ(aout) (sizeof(AOUTHDR)+(aout.tagentries*sizeof(TAGBITS)))*/
+#define AOUTSZ (sizeof(AOUTHDR))
+
+
+/********************** STORAGE CLASSES **********************/
+
+#define C_EFCN -1 /* physical end of function */
+#define C_NULL 0
+#define C_AUTO 1 /* automatic variable */
+#define C_EXT 2 /* external symbol */
+#define C_STAT 3 /* static */
+#define C_REG 4 /* register variable */
+#define C_EXTDEF 5 /* external definition */
+#define C_LABEL 6 /* label */
+#define C_ULABEL 7 /* undefined label */
+#define C_MOS 8 /* member of structure */
+#define C_ARG 9 /* function argument */
+#define C_STRTAG 10 /* structure tag */
+#define C_MOU 11 /* member of union */
+#define C_UNTAG 12 /* union tag */
+#define C_TPDEF 13 /* type definition */
+#define C_USTATIC 14 /* undefined static */
+#define C_ENTAG 15 /* enumeration tag */
+#define C_MOE 16 /* member of enumeration */
+#define C_REGPARM 17 /* register parameter */
+#define C_FIELD 18 /* bit field */
+
+#ifdef TC_I960
+#define C_AUTOARG 19 /* auto argument */
+#define C_LASTENT 20 /* dummy entry (end of block) */
+#endif /* TC_I960 */
+
+#ifdef TC_A29K
+#define C_GLBLREG 19 /* global register */
+#define C_EXTREG 20 /* external global register */
+#define C_DEFREG 21 /* ext. def. of global register */
+#define C_STARTOF 22 /* as29 $SIZEOF and $STARTOF symbols */
+#endif /* TC_A29K */
+
+#define C_BLOCK 100 /* ".bb" or ".eb" */
+#define C_FCN 101 /* ".bf" or ".ef" */
+#define C_EOS 102 /* end of structure */
+#define C_FILE 103 /* file name */
+#define C_LINE 104 /* line # reformatted as symbol table entry */
+#define C_ALIAS 105 /* duplicate tag */
+#define C_HIDDEN 106 /* ext symbol in dmert public lib. like static,
+ used to avoid name conflicts. */
+
+#ifdef TC_I960
+/* New storage classes for 80960 */
+#define C_SCALL 107 /* Procedure reachable via system call */
+/* C_LEAFPROC is obsolete. Use C_LEAFEXT or C_LEAFSTAT */
+#define C_LEAFPROC 108 /* Leaf procedure, "call" via BAL */
+#define C_LEAFEXT 108
+#define C_OPTVAR 109 /* Optimized variable */
+#define C_DEFINE 110 /* Preprocessor #define */
+#define C_PRAGMA 111 /* Advice to compiler or linker */
+#define C_SEGMENT 112 /* 80960 segment name */
+#define C_LEAFSTAT 113 /* Static leaf */
+#endif /* TC_I960 */
+
+#ifdef TC_A29K
+#define C_SHADOW 107 /* shadow symbol */
+#endif /* TC_A29K */
+
+/********************** SECTION HEADER **********************/
+
+struct scnhdr {
+ char s_name[8]; /* section name */
+ long s_paddr; /* physical address, aliased s_nlib */
+ long s_vaddr; /* virtual address */
+ long s_size; /* section size */
+ long s_scnptr; /* file ptr to raw data for section */
+ long s_relptr; /* file ptr to relocation */
+ long s_lnnoptr; /* file ptr to line numbers */
+ unsigned short s_nreloc; /* number of relocation entries */
+ unsigned short s_nlnno; /* number of line number entries */
+ long s_flags; /* flags */
+
+#ifdef TC_I960
+ unsigned long s_align; /* section alignment */
+#endif /* TC_I960 */
+};
+
+#define SCNHDR struct scnhdr
+#define SCNHSZ sizeof(SCNHDR)
+
+/*
+ * names of "special" sections
+ */
+#define _TEXT ".text" /* executable code section */
+#define _DATA ".data" /* initialized data */
+#define _BSS ".bss" /* un-initialized data */
+#define _DEBUG ".debug" /* special section used by dbx */
+#define _COMMENT ".comment" /* version info */
+#define _LIB ".lib" /* shared lib info section */
+#define _TV ".tv"
+
+/*
+ * s_flags "type"
+ */
+
+/*
+ * In instances where it is necessary for a linker to
+ * produce an output file which contains text or data not
+ * based at virtual address 0, e.g. for a ROM, then the
+ * linker should accept address base information as command
+ * input and use PAD sections to skip over unused addresses.
+ * (at least for a29k. Maybe others.)
+ */
+
+#define STYP_REG (0x0000) /* "regular" section: allocated, relocated, loaded */
+#define STYP_DSECT (0x0001) /* "dummy" section: not allocated, relocated, not loaded */
+#define STYP_NOLOAD (0x0002) /* "noload" section: allocated, relocated, not loaded */
+#define STYP_GROUP (0x0004) /* "grouped" section: formed of input sections */
+#define STYP_PAD (0x0008) /* "padding" section: not allocated, not relocated, loaded */
+#define STYP_COPY (0x0010) /* "copy" section: for decision function used by field update; not allocated, not relocated,
+ loaded; reloc & lineno entries processed normally */
+#define STYP_TEXT (0x0020) /* section contains text only */
+#define S_SHRSEG (0x0020) /* In 3b Update files (output of ogen), sections which appear in SHARED segments of the Pfile
+ will have the S_SHRSEG flag set by ogen, to inform dufr that updating 1 copy of the proc. will
+ update all process invocations. */
+#define STYP_DATA (0x0040) /* section contains data only */
+#define STYP_BSS (0x0080) /* section contains bss only */
+#define S_NEWFCN (0x0100) /* In a minimal file or an update file, a new function (as compared with a replaced function) */
+#define STYP_INFO (0x0200) /* comment section : not allocated not relocated, not loaded */
+#define STYP_OVER (0x0400) /* overlay section : relocated not allocated or loaded */
+#define STYP_LIB (0x0800) /* for .lib section : same as INFO */
+#define STYP_MERGE (0x2000) /* merge section -- combines with text, data or bss sections only */
+#define STYP_REVERSE_PAD (0x4000) /* section will be padded with no-op instructions wherever padding is necessary and there is a
+ word of contiguous bytes beginning on a word boundary. */
+
+#ifdef TC_A29K
+/* NOTE: The use of STYP_BSSREG for relocation is not yet defined. */
+#define STYP_BSSREG 0x1200 /* Global register area (like STYP_INFO) */
+#define STYP_ENVIR 0x2200 /* Environment (like STYP_INFO) */
+#define STYP_ABS 0x4000 /* Absolute (allocated, not reloc, loaded) */
+#define STYP_LIT 0x8020 /* Literal data (like STYP_TEXT) */
+#endif /* TC_A29K */
+
+/********************** LINE NUMBERS **********************/
+
+/* 1 line number entry for every "breakpointable" source line in a section.
+ * Line numbers are grouped on a per function basis; first entry in a function
+ * grouping will have l_lnno = 0 and in place of physical address will be the
+ * symbol table index of the function name.
+ */
+struct lineno {
+ union {
+ long l_symndx; /* symbol index of function name, iff l_lnno == 0*/
+ long l_paddr; /* (physical) address of line number */
+ } l_addr;
+ unsigned short l_lnno; /* line number */
+#ifdef TC_I960
+ /* not used on a29k */
+ char padding[2]; /* force alignment */
+#endif /* TC_I960 */
+};
+
+#define LINENO struct lineno
+#define LINESZ sizeof(LINENO)
+
+
+/********************** SYMBOLS **********************/
+
+#define SYMNMLEN 8 /* # characters in a symbol name */
+#define FILNMLEN 14 /* # characters in a file name */
+#define DIMNUM 4 /* # array dimensions in auxiliary entry */
+
+struct syment {
+ union {
+ char _n_name[SYMNMLEN]; /* old COFF version */
+ struct {
+ long _n_zeroes; /* new == 0 */
+ long _n_offset; /* offset into string table */
+ } _n_n;
+ char *_n_nptr[2]; /* allows for overlaying */
+ } _n;
+ long n_value; /* value of symbol */
+ short n_scnum; /* section number */
+
+#ifdef TC_I960
+ /* This isn't yet used on the i960. In some formats this
+ is two bytes of padding. In others, it is missing entirely. */
+ unsigned short n_flags; /* copy of flags from filhdr */
+#endif /* TC_I960 */
+
+#ifdef TC_A29K
+ unsigned short n_type; /* type and derived type */
+#else /* TC_A29K */
+ /* at least i960 uses long */
+ unsigned long n_type; /* type and derived type */
+#endif /* TC_A29K */
+
+ char n_sclass; /* storage class */
+ char n_numaux; /* number of aux. entries */
+
+#ifndef TC_A29K
+ char pad2[2]; /* force alignment */
+#endif /* TC_A29K */
+};
+
+#define SYMENT struct syment
+#define SYMESZ sizeof(SYMENT) /* This had better also be sizeof(AUXENT) */
+
+#define n_name _n._n_name
+#define n_ptr _n._n_nptr[1]
+#define n_zeroes _n._n_n._n_zeroes
+#define n_offset _n._n_n._n_offset
+
+ /*
+ * Relocatable symbols have number of the section in which they are defined,
+ * or one of the following:
+ */
+
+#define N_SCNUM ((short) 1-65535) /* section num where symbol defined */
+#define N_UNDEF ((short)0) /* undefined symbol */
+#define N_ABS ((short)-1) /* value of symbol is absolute */
+#define N_DEBUG ((short)-2) /* debugging symbol -- symbol value is meaningless */
+#define N_TV ((short)-3) /* indicates symbol needs preload transfer vector */
+#define P_TV ((short)-4) /* indicates symbol needs transfer vector (postload) */
+
+/*
+ * Type of a symbol, in low 4 bits of the word
+ */
+#define T_NULL 0 /* type not assigned */
+#define T_VOID 1 /* function argument (only used by compiler) (but now real void). */
+#define T_CHAR 2 /* character */
+#define T_SHORT 3 /* short integer */
+#define T_INT 4 /* integer */
+#define T_LONG 5 /* long integer */
+#define T_FLOAT 6 /* floating point */
+#define T_DOUBLE 7 /* double word */
+#define T_STRUCT 8 /* structure */
+#define T_UNION 9 /* union */
+#define T_ENUM 10 /* enumeration */
+#define T_MOE 11 /* member of enumeration */
+#define T_UCHAR 12 /* unsigned character */
+#define T_USHORT 13 /* unsigned short */
+#define T_UINT 14 /* unsigned integer */
+#define T_ULONG 15 /* unsigned long */
+
+#ifdef TC_I960
+#define T_LNGDBL 16 /* long double */
+#endif /* TC_I960 */
+
+/*
+ * derived types, in n_type
+ */
+#define DT_NON (0) /* no derived type */
+#define DT_PTR (1) /* pointer */
+#define DT_FCN (2) /* function */
+#define DT_ARY (3) /* array */
+
+#ifndef TC_I960
+
+#define N_BTMASK (0x0f)
+#define N_TMASK (0x30)
+#define N_BTSHFT (4)
+#define N_TSHIFT (2)
+
+#else /* TC_I960 */
+
+#define N_BTMASK (0x1f)
+#define N_TMASK (0x60)
+#define N_BTSHFT (5)
+#define N_TSHIFT (2)
+
+#endif /* TC_I960 */
+
+#define BTYPE(x) ((x) & N_BTMASK)
+
+#define ISPTR(x) (((x) & N_TMASK) == (DT_PTR << N_BTSHFT))
+#define ISFCN(x) (((x) & N_TMASK) == (DT_FCN << N_BTSHFT))
+#define ISARY(x) (((x) & N_TMASK) == (DT_ARY << N_BTSHFT))
+
+#define DECREF(x) ((((x)>>N_TSHIFT)&~N_BTMASK)|((x)&N_BTMASK))
+
+union auxent {
+ struct {
+ long x_tagndx; /* str, un, or enum tag indx */
+ union {
+ struct {
+ unsigned short x_lnno; /* declaration line number */
+ unsigned short x_size; /* str/union/array size */
+ } x_lnsz;
+ long x_fsize; /* size of function */
+ } x_misc;
+ union {
+ struct { /* if ISFCN, tag, or .bb */
+ long x_lnnoptr; /* ptr to fcn line # */
+ long x_endndx; /* entry ndx past block end */
+ } x_fcn;
+ struct { /* if ISARY, up to 4 dimen. */
+ unsigned short x_dimen[DIMNUM];
+ } x_ary;
+ } x_fcnary;
+ unsigned short x_tvndx; /* tv index */
+ } x_sym;
+
+ /* This was just a struct x_file with x_fname only in a29k. xoxorich. */
+ union {
+ char x_fname[FILNMLEN];
+ struct {
+ long x_zeroes;
+ long x_offset;
+ } x_n;
+ } x_file;
+
+ struct {
+ long x_scnlen; /* section length */
+ unsigned short x_nreloc; /* # relocation entries */
+ unsigned short x_nlinno; /* # line numbers */
+ } x_scn;
+
+ struct {
+ long x_tvfill; /* tv fill value */
+ unsigned short x_tvlen; /* length of .tv */
+
+ /* This field was typo'd x_tvrna on a29k. xoxorich. */
+ unsigned short x_tvran[2]; /* tv range */
+ } x_tv; /* info about .tv section (in auxent of symbol .tv)) */
+
+#ifdef TC_I960
+ /******************************************
+ * I960-specific *2nd* aux. entry formats
+ ******************************************/
+ struct {
+ /* This is a very old typo that keeps getting propogated. */
+#define x_stdindx x_stindx
+ long x_stindx; /* sys. table entry */
+ } x_sc; /* system call entry */
+
+ struct {
+ unsigned long x_balntry; /* BAL entry point */
+ } x_bal; /* BAL-callable function */
+
+ struct {
+ unsigned long x_timestamp; /* time stamp */
+ char x_idstring[20]; /* producer identity string */
+ } x_ident; /* Producer ident info */
+
+ char a[sizeof(struct syment)]; /* force auxent/syment sizes to match */
+#endif /* TC_I960 */
+};
+
+#define AUXENT union auxent
+#define AUXESZ sizeof(AUXENT) /* This had better also be sizeof(SYMENT) */
+
+#if VAX || I960
+# define _ETEXT "_etext"
+#else
+# define _ETEXT "etext"
+#endif
+
+/********************** RELOCATION DIRECTIVES **********************/
+
+struct reloc {
+ long r_vaddr; /* Virtual address of reference */
+ long r_symndx; /* Index into symbol table */
+ unsigned short r_type; /* Relocation type */
+#ifdef TC_I960
+ /* not used for a29k */
+ char pad[2]; /* Unused */
+#endif /* TC_I960 */
+};
+
+#define RELOC struct reloc
+#define RELSZ sizeof(RELOC)
+
+#define R_ABS (0x00) /* reference is absolute */
+
+#ifdef TC_I960
+#define R_RELLONG (0x11) /* Direct 32-bit relocation */
+#define R_IPRSHORT (0x18)
+#define R_IPRMED (0x19) /* 24-bit ip-relative relocation */
+#define R_IPRLONG (0x1a)
+#define R_OPTCALL (0x1b) /* 32-bit optimizable call (leafproc/sysproc) */
+#define R_OPTCALLX (0x1c) /* 64-bit optimizable call (leafproc/sysproc) */
+#define R_GETSEG (0x1d)
+#define R_GETPA (0x1e)
+#define R_TAGWORD (0x1f)
+#endif /* TC_I960 */
+
+#ifdef TC_A29K
+/*
+ * NOTE: All the "I" forms refer to Am29000 instruction
+ * formats. The linker is expected to know how the numeric
+ * information is split and/or aligned within the
+ * instruction word(s). R_BYTE works for instructions, too.
+ *
+ * If the parameter to a CONSTH instruction is a relocatable
+ * type, two relocation records are written. The first has
+ * an r_type of R_IHIHALF (33 octal) and a normal r_vaddr
+ * and r_symndx. The second relocation record has an r_type
+ * of R_IHCONST (34 octal), a normal r_vaddr (which is
+ * redundant), and an r_symndx containing the 32-bit
+ * constant offset to the relocation instead of the actual
+ * symbol table index. This second record is always
+ * written, even if the constant offset is zero. The
+ * constant fields of the instruction are set to zero.
+ */
+
+#define R_IREL (0x18) /* instruction relative (jmp/call) */
+#define R_IABS (0x19) /* instruction absolute (jmp/call) */
+#define R_ILOHALF (0x1a) /* instruction low half (const) */
+#define R_IHIHALF (0x1b) /* instruction high half (consth) part 1 */
+#define R_IHCONST (0x1c) /* instruction high half (consth) part 2
+ constant offset of R_IHIHALF relocation */
+#define R_BYTE (0x1d) /* relocatable byte value */
+#define R_HWORD (0x1e) /* relocatable halfword value */
+#define R_WORD (0x1f) /* relocatable word value */
+#define R_IGLBLRC (0x20) /* instruction global register RC */
+#define R_IGLBLRA (0x21) /* instruction global register RA */
+#define R_IGLBLRB (0x22) /* instruction global register RB */
+#endif /* TC_A29K */
+
+
+#define DEFAULT_DATA_SECTION_ALIGNMENT 4
+#define DEFAULT_BSS_SECTION_ALIGNMENT 4
+#define DEFAULT_TEXT_SECTION_ALIGNMENT 16
+/* For new sections we haven't heard of before */
+#define DEFAULT_SECTION_ALIGNMENT 4
+
+#if defined(TC_I386)
+/*
+ * X86 generic
+ * 8-bit offset reference in 8-bits
+ * 8-bit offset reference in 16-bits
+ * 12-bit segment reference
+ * auxiliary relocation entry
+ */
+#define R_OFF8 07
+#define R_OFF16 010
+#define R_SEG12 011
+#define R_AUX 013
+
+/*
+ * B16 and X86 generics
+ * 16-bit direct reference
+ * 16-bit "relative" reference
+ * 16-bit "indirect" (TV) reference
+ */
+#define R_DIR16 01
+#define R_REL16 02
+#define R_IND16 03
+
+/*
+ * 3B generic
+ * 24-bit direct reference
+ * 24-bit "relative" reference
+ * 16-bit optimized "indirect" TV reference
+ * 24-bit "indirect" TV reference
+ * 32-bit "indirect" TV reference
+ */
+#define R_DIR24 04
+#define R_REL24 05
+#define R_OPT16 014
+#define R_IND24 015
+#define R_IND32 016
+
+/*
+ * XL generics
+ * 10-bit direct reference
+ * 10-bit "relative" reference
+ * 32-bit "relative" reference
+ */
+#define R_DIR10 025
+#define R_REL10 026
+#define R_REL32 027
+
+/*
+ * 3B and M32 generics
+ * 32-bit direct reference
+ */
+#define R_DIR32 06
+
+/*
+ * M32 generic
+ * 32-bit direct reference with bytes swapped
+ */
+#define R_DIR32S 012
+
+#endif /* TC_I386 */
+
+#if defined(TE_I386AIX)
+
+#define UINFOSIZ 64 /* size of user info buffer */
+typedef char uinfo_t[UINFOSIZ];
+
+struct env387 {
+ unsigned short control;
+ unsigned short r0;
+ unsigned short status;
+ unsigned short r1;
+ unsigned short tag;
+ unsigned short r2;
+ unsigned long eip;
+ unsigned short code_seg;
+ unsigned short opcode;
+ unsigned long operand;
+ unsigned short operand_seg;
+ unsigned short r3;
+ unsigned char regs[8][10];
+};
+
+#define CD_NAMELEN 16 /* length of most names in this header */
+#define CORHDRSIZ 2048 /* size to which header is padded out */
+#define MAX_CORE_SEGS 32 /* maximum segments in a core dump */
+#define NUM_FREGS 1 /* # of saved FP regs */
+
+/*
+ * These are defined such that 286 and 386 kernels can produce
+ * compatible dumps.
+ */
+#define CD_AX 0
+#define CD_BX 1
+#define CD_CX 2
+#define CD_DX 3
+#define CD_SI 4
+#define CD_DI 5
+#define CD_BP 6
+#define CD_SP 7
+#define CD_FL 8
+#define CD_IP 9
+#define CD_CS 10
+#define CD_DS 11
+#define CD_ES 12
+#define CD_FS 13
+#define CD_GS 14
+#define CD_SS 15
+#define NUM_REGS 16
+
+#ifndef SPATHLEN
+# define SPATHLEN 16 /* sys/param.h */
+#endif
+#ifndef NSIG
+# define NSIG 63 /* sys/signal.h */
+# define SIGSETSZ ((NSIG+31)/32)
+typedef struct ksigmask {
+ unsigned long sigs[SIGSETSZ];
+} ksigmask_t;
+#endif
+
+struct corehdr {
+ char cd_magic[4]; /* COR_MAGIC = "core" */
+
+ /* general information about the dump itself */
+ struct dumpseg { /* table of contents for dump */
+ long cs_type; /* seg. type; see below */
+ long cs_len; /* length (in bytes) of segment */
+ long cs_offset; /* offset (in dump) of segment */
+ long cs_address; /* address segment had in mem */
+ } cd_segs[MAX_CORE_SEGS];
+
+ /* general information about the process */
+ char cd_comm[CD_NAMELEN]; /* command being run */
+ char cd_mach[CD_NAMELEN]; /* type of machine it ran on */
+ char cd_site[CD_NAMELEN]; /* name of site it ran on */
+ long cd_ldtype; /* type of load module running */
+ char cd_intsize; /* sizeof(int) */
+ char cd_dptrsize; /* sizeof(char *) */
+ char cd_tptrsize; /* sizeof(int (*)()) */
+ char cd_unused;
+
+ /* user-mode program state */
+ long cd_regs[NUM_REGS]; /* user-mode general registers */
+ struct env387 cd_fpregs; /* user-mode floating-point state */
+
+ /* kernel-mode program state */
+ int (*cd_sig[NSIG])(); /* disposition of signals */
+ ksigmask_t cd_sigmask; /* signals to be blocked */
+ ksigmask_t cd_sigpend; /* signals currently pending */
+ long cd_cursig; /* signal that caused the dump */
+
+ long cd_pid; /* process ID of the corpse */
+ long cd_ppid; /* parent process ID of corpse */
+ short cd_uid; /* process effective user ID */
+ short cd_ruid; /* process real user ID */
+ short cd_gid; /* process effective group ID */
+ short cd_rgid; /* process real group ID */
+
+ uinfo_t cd_uinfo; /* buffer of user information */
+ char cd_locname[32]; /* name of /local */
+ char cd_uvers[CD_NAMELEN]; /* user version string */
+ unsigned short cd_spath[SPATHLEN]; /* sitepath */
+};
+
+#ifndef NOCHECKS
+/* this will generate an error if sizeof(struct corehdr) > CORHDRSIZ */
+struct { char xxcdxx[CORHDRSIZ+1-sizeof(struct corehdr)]; };
+#endif /* ! NOCHECKS */
+
+/*
+ * segment types (in cs_type)
+ * each segment in the address space appears here, whether or not it
+ * is actually dumped. Read/only segments will not actually be dumped.
+ * A segment that is not in the dump will have a cs_offset of zero.
+ */
+#define COR_TYPE_CODE 'x' /* process code - NOT IN DUMP */
+#define COR_TYPE_DATA 'd' /* process data segment */
+#define COR_TYPE_STACK 's' /* process stack segment */
+#define COR_TYPE_LIBCODE 'X' /* shared lib code - NOT IN DUMP*/
+#define COR_TYPE_LIBDATA 'D' /* shared lib data */
+#define COR_TYPE_READ 'r' /* other read/only - NOT IN DUMP*/
+#define COR_TYPE_WRITE 'w' /* other writeable */
+#define COR_TYPE_MSC '?' /* other, mapped in segment */
+
+#endif /* TE_I386AIX */
+
+/*
+ * Local Variables:
+ * comment-column: 0
+ * End:
+ */
+
+/* end of coff.h */
diff --git a/gnu/usr.bin/as/config/cplus-dem.c b/gnu/usr.bin/as/config/cplus-dem.c
new file mode 100644
index 0000000..79d3279
--- /dev/null
+++ b/gnu/usr.bin/as/config/cplus-dem.c
@@ -0,0 +1,927 @@
+/* Demangler for GNU C++
+ Copyright (C) 1989, 1992 Free Software Foundation, Inc.
+ written by James Clark (jjc@jclark.uucp)
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* This is for g++ 1.36.1 (November 6 version). It will probably
+ require changes for any other version. */
+
+/* This file exports one function
+
+ char *cplus_demangle (const char *name)
+
+ If `name' is a mangled function name produced by g++, then
+ a pointer to a malloced string giving a C++ representation
+ of the name will be returned; otherwise NULL will be returned.
+ It is the caller's responsibility to free the string which
+ is returned.
+
+ For example,
+
+ cplus_demangle ("_foo__1Ai")
+
+ returns
+
+ "A::foo(int)"
+
+ This file imports xmalloc and xrealloc, which are like malloc and
+ realloc except that they generate a fatal error if there is no
+ available memory. */
+
+/* #define nounderscore 1 /* define this is names don't start with _ */
+
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+
+#if !defined(sequent) && !defined(NeXT)
+#include <memory.h>
+#else
+#define memcpy(s1, s2, n) strncpy(s1, s2, n)
+#define memcmp(s1, s2, n) strncmp(s1, s2, n)
+#define strchr(s, c) index(s, c)
+#endif
+
+#if __STDC__ != 1
+#define const
+#endif
+
+#if __STDC__ == 1
+extern char *cplus_demangle (const char *type);
+#else
+extern char *cplus_demangle ();
+#endif
+
+#if __STDC__ == 1
+extern char *xmalloc (int);
+extern char *xrealloc (char *, int);
+#else
+extern char *xmalloc ();
+extern char *xrealloc ();
+#endif
+
+static char **typevec = 0;
+static int ntypes = 0;
+static int typevec_size = 0;
+
+static struct {
+ const char *in;
+ const char *out;
+} optable[] = {
+ "new", " new",
+ "delete", " delete",
+ "ne", "!=",
+ "eq", "==",
+ "ge", ">=",
+ "gt", ">",
+ "le", "<=",
+ "lt", "<",
+ "plus", "+",
+ "minus", "-",
+ "mult", "*",
+ "negate", "-",
+ "trunc_mod", "%",
+ "trunc_div", "/",
+ "truth_andif", "&&",
+ "truth_orif", "||",
+ "postincrement", "++",
+ "postdecrement", "--",
+ "bit_ior", "|",
+ "bit_xor", "^",
+ "bit_and", "&",
+ "bit_not", "~",
+ "call", "()",
+ "cond", "?:",
+ "alshift", "<<",
+ "arshift", ">>",
+ "component", "->",
+ "nop", "", /* for operator= */
+};
+
+/* Beware: these aren't '\0' terminated. */
+
+typedef struct {
+ char *b; /* pointer to start of string */
+ char *p; /* pointer after last character */
+ char *e; /* pointer after end of allocated space */
+} string;
+
+#if __STDC__ == 1
+static void string_need (string *s, int n);
+static void string_delete (string *s);
+static void string_init (string *s);
+static void string_clear (string *s);
+static int string_empty (string *s);
+static void string_append (string *p, const char *s);
+static void string_appends (string *p, string *s);
+static void string_appendn (string *p, const char *s, int n);
+static void string_prepend (string *p, const char *s);
+#if 0
+static void string_prepends (string *p, string *s);
+#endif
+static void string_prependn (string *p, const char *s, int n);
+static int get_count (const char **type, int *count);
+static int do_args (const char **type, string *decl);
+static int do_type (const char **type, string *result);
+static int do_arg (const char **type, string *result);
+static int do_args (const char **type, string *decl);
+static void munge_function_name (string *name);
+#else
+static void string_need ();
+static void string_delete ();
+static void string_init ();
+static void string_clear ();
+static int string_empty ();
+static void string_append ();
+static void string_appends ();
+static void string_appendn ();
+static void string_prepend ();
+static void string_prepends ();
+static void string_prependn ();
+static int get_count ();
+static int do_args ();
+static int do_type ();
+static int do_arg ();
+static int do_args ();
+static void munge_function_name ();
+#endif
+
+char *
+ cplus_demangle (type)
+const char *type;
+{
+ string decl;
+ int n;
+ int success = 0;
+ int constructor = 0;
+ int const_flag = 0;
+ int i;
+ const char *p;
+
+ if (type == NULL || *type == '\0')
+ return NULL;
+#ifndef nounderscore
+ if (*type++ != '_')
+ return NULL;
+#endif
+ p = type;
+ while (*p != '\0' && !(*p == '_' && p[1] == '_'))
+ p++;
+ if (*p == '\0')
+ {
+ /* destructor */
+ if (type[0] == '_' && type[1] == '$' && type[2] == '_')
+ {
+ int n = (strlen (type) - 3)*2 + 3 + 2 + 1;
+ char *tem = (char *) xmalloc (n);
+ strcpy (tem, type + 3);
+ strcat (tem, "::~");
+ strcat (tem, type + 3);
+ strcat (tem, "()");
+ return tem;
+ }
+ /* static data member */
+ if (*type != '_' && (p = strchr (type, '$')) != '\0')
+ {
+ int n = strlen (type) + 2;
+ char *tem = (char *) xmalloc (n);
+ memcpy (tem, type, p - type);
+ strcpy (tem + (p - type), "::");
+ strcpy (tem + (p - type) + 2, p + 1);
+ return tem;
+ }
+ return NULL;
+ }
+
+ string_init (&decl);
+
+ if (p == type)
+ {
+ if (!isdigit (p[2]))
+ {
+ string_delete (&decl);
+ return NULL;
+ }
+ constructor = 1;
+ }
+ else
+ {
+ string_appendn (&decl, type, p - type);
+ munge_function_name (&decl);
+ }
+ p += 2;
+
+ switch (*p)
+ {
+ case 'C':
+ /* a const member function */
+ if (!isdigit (p[1]))
+ {
+ string_delete (&decl);
+ return NULL;
+ }
+ p += 1;
+ const_flag = 1;
+ /* fall through */
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ n = 0;
+ do
+ {
+ n *= 10;
+ n += *p - '0';
+ p += 1;
+ }
+ while (isdigit (*p));
+ if (strlen (p) < n)
+ {
+ string_delete (&decl);
+ return NULL;
+ }
+ if (constructor)
+ {
+ string_appendn (&decl, p, n);
+ string_append (&decl, "::");
+ string_appendn (&decl, p, n);
+ }
+ else
+ {
+ string_prepend (&decl, "::");
+ string_prependn (&decl, p, n);
+ }
+ p += n;
+ success = do_args (&p, &decl);
+ if (const_flag)
+ string_append (&decl, " const");
+ break;
+ case 'F':
+ p += 1;
+ success = do_args (&p, &decl);
+ break;
+ }
+
+ for (i = 0; i < ntypes; i++)
+ if (typevec[i] != NULL)
+ free (typevec[i]);
+ ntypes = 0;
+ if (typevec != NULL)
+ {
+ free ((char *)typevec);
+ typevec = NULL;
+ typevec_size = 0;
+ }
+
+ if (success)
+ {
+ string_appendn (&decl, "", 1);
+ return decl.b;
+ }
+ else
+ {
+ string_delete (&decl);
+ return NULL;
+ }
+}
+
+static int
+ get_count (type, count)
+const char **type;
+int *count;
+{
+ if (!isdigit (**type))
+ return 0;
+ *count = **type - '0';
+ *type += 1;
+ /* see flush_repeats in cplus-method.c */
+ if (isdigit (**type))
+ {
+ const char *p = *type;
+ int n = *count;
+ do
+ {
+ n *= 10;
+ n += *p - '0';
+ p += 1;
+ }
+ while (isdigit (*p));
+ if (*p == '_')
+ {
+ *type = p + 1;
+ *count = n;
+ }
+ }
+ return 1;
+}
+
+/* result will be initialised here; it will be freed on failure */
+
+static int
+ do_type (type, result)
+const char **type;
+string *result;
+{
+ int n;
+ int done;
+ int non_empty;
+ int success;
+ string decl;
+ const char *remembered_type;
+
+ string_init (&decl);
+ string_init (result);
+
+ done = 0;
+ success = 1;
+ while (success && !done)
+ {
+ int member;
+ switch (**type)
+ {
+ case 'P':
+ *type += 1;
+ string_prepend (&decl, "*");
+ break;
+
+ case 'R':
+ *type += 1;
+ string_prepend (&decl, "&");
+ break;
+
+ case 'T':
+ *type += 1;
+ if (!get_count (type, &n) || n >= ntypes)
+ success = 0;
+ else
+ {
+ remembered_type = typevec[n];
+ type = &remembered_type;
+ }
+ break;
+
+ case 'F':
+ *type += 1;
+ if (!string_empty (&decl) && decl.b[0] == '*')
+ {
+ string_prepend (&decl, "(");
+ string_append (&decl, ")");
+ }
+ if (!do_args (type, &decl) || **type != '_')
+ success = 0;
+ else
+ *type += 1;
+ break;
+
+ case 'M':
+ case 'O':
+ {
+ int constp = 0;
+ int volatilep = 0;
+
+ member = **type == 'M';
+ *type += 1;
+ if (!isdigit (**type))
+ {
+ success = 0;
+ break;
+ }
+ n = 0;
+ do
+ {
+ n *= 10;
+ n += **type - '0';
+ *type += 1;
+ }
+ while (isdigit (**type));
+ if (strlen (*type) < n)
+ {
+ success = 0;
+ break;
+ }
+ string_append (&decl, ")");
+ string_prepend (&decl, "::");
+ string_prependn (&decl, *type, n);
+ string_prepend (&decl, "(");
+ *type += n;
+ if (member)
+ {
+ if (**type == 'C')
+ {
+ *type += 1;
+ constp = 1;
+ }
+ if (**type == 'V')
+ {
+ *type += 1;
+ volatilep = 1;
+ }
+ if (*(*type)++ != 'F')
+ {
+ success = 0;
+ break;
+ }
+ }
+ if ((member && !do_args (type, &decl)) || **type != '_')
+ {
+ success = 0;
+ break;
+ }
+ *type += 1;
+ if (constp)
+ {
+ if (non_empty)
+ string_append (&decl, " ");
+ else
+ non_empty = 1;
+ string_append (&decl, "const");
+ }
+ if (volatilep)
+ {
+ if (non_empty)
+ string_append (&decl, " ");
+ else
+ non_empty = 1;
+ string_append (&decl, "volatilep");
+ }
+ break;
+ }
+
+ case 'C':
+ if ((*type)[1] == 'P')
+ {
+ *type += 1;
+ if (!string_empty (&decl))
+ string_prepend (&decl, " ");
+ string_prepend (&decl, "const");
+ break;
+ }
+
+ /* fall through */
+ default:
+ done = 1;
+ break;
+ }
+ }
+
+ done = 0;
+ non_empty = 0;
+ while (success && !done)
+ {
+ switch (**type)
+ {
+ case 'C':
+ *type += 1;
+ if (non_empty)
+ string_append (result, " ");
+ else
+ non_empty = 1;
+ string_append (result, "const");
+ break;
+ case 'U':
+ *type += 1;
+ if (non_empty)
+ string_append (result, " ");
+ else
+ non_empty = 1;
+ string_append (result, "unsigned");
+ break;
+ case 'V':
+ *type += 1;
+ if (non_empty)
+ string_append (result, " ");
+ else
+ non_empty = 1;
+ string_append (result, "volatile");
+ break;
+ default:
+ done = 1;
+ break;
+ }
+ }
+
+ if (success)
+ switch (**type)
+ {
+ case '\0':
+ case '_':
+ break;
+ case 'v':
+ *type += 1;
+ if (non_empty)
+ string_append (result, " ");
+ string_append (result, "void");
+ break;
+ case 'l':
+ *type += 1;
+ if (non_empty)
+ string_append (result, " ");
+ string_append (result, "long");
+ break;
+ case 'i':
+ *type += 1;
+ if (non_empty)
+ string_append (result, " ");
+ string_append (result, "int");
+ break;
+ case 's':
+ *type += 1;
+ if (non_empty)
+ string_append (result, " ");
+ string_append (result, "short");
+ break;
+ case 'c':
+ *type += 1;
+ if (non_empty)
+ string_append (result, " ");
+ string_append (result, "char");
+ break;
+ case 'r':
+ *type += 1;
+ if (non_empty)
+ string_append (result, " ");
+ string_append (result, "long double");
+ break;
+ case 'd':
+ *type += 1;
+ if (non_empty)
+ string_append (result, " ");
+ string_append (result, "double");
+ break;
+ case 'f':
+ *type += 1;
+ if (non_empty)
+ string_append (result, " ");
+ string_append (result, "float");
+ break;
+ case 'G':
+ *type += 1;
+ if (!isdigit (**type))
+ {
+ success = 0;
+ break;
+ }
+ /* fall through */
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ n = 0;
+ do
+ {
+ n *= 10;
+ n += **type - '0';
+ *type += 1;
+ }
+ while (isdigit (**type));
+ if (strlen (*type) < n)
+ {
+ success = 0;
+ break;
+ }
+ if (non_empty)
+ string_append (result, " ");
+ string_appendn (result, *type, n);
+ *type += n;
+ break;
+ default:
+ success = 0;
+ break;
+ }
+
+ if (success)
+ {
+ if (!string_empty (&decl))
+ {
+ string_append (result, " ");
+ string_appends (result, &decl);
+ }
+ string_delete (&decl);
+ return 1;
+ }
+ else
+ {
+ string_delete (&decl);
+ string_delete (result);
+ return 0;
+ }
+}
+
+/* `result' will be initialised in do_type; it will be freed on failure */
+
+static int
+ do_arg (type, result)
+const char **type;
+string *result;
+{
+ char *tem;
+ int len;
+ const char *start;
+ const char *end;
+
+ start = *type;
+ if (!do_type (type, result))
+ return 0;
+ end = *type;
+ if (ntypes >= typevec_size)
+ {
+ if (typevec_size == 0)
+ {
+ typevec_size = 3;
+ typevec = (char **) xmalloc (sizeof (char*)*typevec_size);
+ }
+ else
+ {
+ typevec_size *= 2;
+ typevec = (char **) xrealloc ((char *)typevec, sizeof (char*)*typevec_size);
+ }
+ }
+ len = end - start;
+ tem = (char *) xmalloc (len + 1);
+ memcpy (tem, start, len);
+ tem[len] = '\0';
+ typevec[ntypes++] = tem;
+ return 1;
+}
+
+/* `decl' must be already initialised, usually non-empty;
+ it won't be freed on failure */
+
+static int
+ do_args (type, decl)
+const char **type;
+string *decl;
+{
+ string arg;
+ int need_comma = 0;
+
+ string_append (decl, "(");
+
+ while (**type != '_' && **type != '\0' && **type != 'e' && **type != 'v')
+ {
+ if (**type == 'N')
+ {
+ int r;
+ int t;
+ *type += 1;
+ if (!get_count (type, &r) || !get_count (type, &t) || t >= ntypes)
+ return 0;
+ while (--r >= 0)
+ {
+ const char *tem = typevec[t];
+ if (need_comma)
+ string_append (decl, ", ");
+ if (!do_arg (&tem, &arg))
+ return 0;
+ string_appends (decl, &arg);
+ string_delete (&arg);
+ need_comma = 1;
+ }
+ }
+ else
+ {
+ if (need_comma)
+ string_append (decl, ", ");
+ if (!do_arg (type, &arg))
+ return 0;
+ string_appends (decl, &arg);
+ string_delete (&arg);
+ need_comma = 1;
+ }
+ }
+
+ if (**type == 'v')
+ *type += 1;
+ else if (**type == 'e')
+ {
+ *type += 1;
+ if (need_comma)
+ string_append (decl, ",");
+ string_append (decl, "...");
+ }
+
+ string_append (decl, ")");
+ return 1;
+}
+
+static void
+ munge_function_name (name)
+string *name;
+{
+ if (!string_empty (name) && name->p - name->b >= 3
+ && name->b[0] == 'o' && name->b[1] == 'p' && name->b[2] == '$')
+ {
+ int i;
+ /* see if it's an assignment expression */
+ if (name->p - name->b >= 10 /* op$assign_ */
+ && memcmp (name->b + 3, "assign_", 7) == 0)
+ {
+ for (i = 0; i < sizeof (optable)/sizeof (optable[0]); i++)
+ {
+ int len = name->p - name->b - 10;
+ if (strlen (optable[i].in) == len
+ && memcmp (optable[i].in, name->b + 10, len) == 0)
+ {
+ string_clear (name);
+ string_append (name, "operator");
+ string_append (name, optable[i].out);
+ string_append (name, "=");
+ return;
+ }
+ }
+ }
+ else
+ {
+ for (i = 0; i < sizeof (optable)/sizeof (optable[0]); i++)
+ {
+ int len = name->p - name->b - 3;
+ if (strlen (optable[i].in) == len
+ && memcmp (optable[i].in, name->b + 3, len) == 0)
+ {
+ string_clear (name);
+ string_append (name, "operator");
+ string_append (name, optable[i].out);
+ return;
+ }
+ }
+ }
+ return;
+ }
+ else if (!string_empty (name) && name->p - name->b >= 5
+ && memcmp (name->b, "type$", 5) == 0)
+ {
+ /* type conversion operator */
+ string type;
+ const char *tem = name->b + 5;
+ if (do_type (&tem, &type))
+ {
+ string_clear (name);
+ string_append (name, "operator ");
+ string_appends (name, &type);
+ string_delete (&type);
+ return;
+ }
+ }
+}
+
+/* a mini string-handling package */
+
+static void
+ string_need (s, n)
+string *s;
+int n;
+{
+ if (s->b == NULL)
+ {
+ if (n < 32)
+ n = 32;
+ s->p = s->b = (char *) xmalloc (n);
+ s->e = s->b + n;
+ }
+ else if (s->e - s->p < n)
+ {
+ int tem = s->p - s->b;
+ n += tem;
+ n *= 2;
+ s->b = (char *) xrealloc (s->b, n);
+ s->p = s->b + tem;
+ s->e = s->b + n;
+ }
+}
+
+static void
+ string_delete (s)
+string *s;
+{
+ if (s->b != NULL)
+ {
+ free (s->b);
+ s->b = s->e = s->p = NULL;
+ }
+}
+
+static void
+ string_init (s)
+string *s;
+{
+ s->b = s->p = s->e = NULL;
+}
+
+static void
+ string_clear (s)
+string *s;
+{
+ s->p = s->b;
+}
+
+static int
+ string_empty (s)
+string *s;
+{
+ return s->b == s->p;
+}
+
+static void
+ string_append (p, s)
+string *p;
+const char *s;
+{
+ int n;
+ if (s == NULL || *s == '\0')
+ return;
+ n = strlen (s);
+ string_need (p, n);
+ memcpy (p->p, s, n);
+ p->p += n;
+}
+
+static void
+ string_appends (p, s)
+string *p, *s;
+{
+ int n;
+ if (s->b == s->p)
+ return;
+ n = s->p - s->b;
+ string_need (p, n);
+ memcpy (p->p, s->b, n);
+ p->p += n;
+}
+
+static void
+ string_appendn (p, s, n)
+string *p;
+const char *s;
+int n;
+{
+ if (n == 0)
+ return;
+ string_need (p, n);
+ memcpy (p->p, s, n);
+ p->p += n;
+}
+
+static void
+ string_prepend (p, s)
+string *p;
+const char *s;
+{
+ if (s == NULL || *s == '\0')
+ return;
+ string_prependn (p, s, strlen (s));
+}
+
+#if 0
+static void
+ string_prepends (p, s)
+string *p, *s;
+{
+ if (s->b == s->p)
+ return;
+ string_prependn (p, s->b, s->p - s->b);
+}
+#endif
+
+static void
+ string_prependn (p, s, n)
+string *p;
+const char *s;
+int n;
+{
+ char *q;
+
+ if (n == 0)
+ return;
+ string_need (p, n);
+ for (q = p->p - 1; q >= p->b; q--)
+ q[n] = q[0];
+ memcpy (p->b, s, n);
+ p->p += n;
+}
+
+/* end of cplus-dem.c */
diff --git a/gnu/usr.bin/as/config/ho-ansi.h b/gnu/usr.bin/as/config/ho-ansi.h
new file mode 100644
index 0000000..bd2d909
--- /dev/null
+++ b/gnu/usr.bin/as/config/ho-ansi.h
@@ -0,0 +1,29 @@
+/* ho-ansi.h Host-specific header file for generic ansi environments.
+ Copyright (C) 1987, 1991, 1992 Free Software Foundation, Inc.
+
+ This file is part of GAS, the GNU Assembler.
+
+ GAS is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GAS is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GAS; see the file COPYING. If not, write to
+ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#define M_ANSI 1
+
+#include <stdlib.h>
+#include <string.h>
+#include <memory.h>
+
+#define sys_nerr _sys_nerr
+#define sys_errlist _sys_errlist
+
+/* end of ho-ansi.h */
diff --git a/gnu/usr.bin/as/config/ho-decstation.h b/gnu/usr.bin/as/config/ho-decstation.h
new file mode 100644
index 0000000..69a4699
--- /dev/null
+++ b/gnu/usr.bin/as/config/ho-decstation.h
@@ -0,0 +1,29 @@
+/* ho-pmax.h Host-specific header file for decstation 3100.
+ Copyright (C) 1987, 1990, 1991, 1992 Free Software Foundation, Inc.
+
+ This file is part of GAS, the GNU Assembler.
+
+ GAS is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GAS is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GAS; see the file COPYING. If not, write to
+ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <string.h>
+
+extern char *malloc();
+extern int free();
+
+#if !defined(__GNUC__)
+#define know(x)
+#endif /* not gcc */
+
+/* end of ho-decstation.h */
diff --git a/gnu/usr.bin/as/config/ho-generic.h b/gnu/usr.bin/as/config/ho-generic.h
new file mode 100644
index 0000000..7c7129f
--- /dev/null
+++ b/gnu/usr.bin/as/config/ho-generic.h
@@ -0,0 +1,30 @@
+/* ho-generic.h Generic host-specific header file.
+ Copyright 1987, 1991, 1992 Free Software Foundation, Inc.
+
+ This file is part of GAS, the GNU Assembler.
+
+ GAS is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GAS is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GAS; see the file COPYING. If not, write to
+ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* It is my intent that this become a file capable of config'ing and
+ compiling for nearly any host as aid for testing and porting.
+ xoxorich. */
+
+#define M_GENERIC 1
+
+#define HAVE_STRERROR
+
+extern int free();
+
+/* end of ho-generic.h */
diff --git a/gnu/usr.bin/as/config/ho-hpux.h b/gnu/usr.bin/as/config/ho-hpux.h
new file mode 100644
index 0000000..ebea9e2
--- /dev/null
+++ b/gnu/usr.bin/as/config/ho-hpux.h
@@ -0,0 +1,34 @@
+/* ho-hpux.h -- Header to compile the assembler under HP-UX
+ Copyright (C) 1988, 1991, 1992 Free Software Foundation, Inc.
+
+ This file is part of GAS, the GNU Assembler.
+
+ GAS is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GAS is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GAS; see the file COPYING. If not, write to
+ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "ho-sysv.h"
+
+/* This header file contains the #defines specific
+ to HPUX changes sent me by cph@zurich.ai.mit.edu */
+#ifndef hpux
+#define hpux
+#endif
+
+#ifdef setbuffer
+#undef setbuffer
+#endif /* setbuffer */
+
+#define setbuffer(stream, buf, size)
+
+/* end of ho-hpux.h */
diff --git a/gnu/usr.bin/as/config/ho-i386.h b/gnu/usr.bin/as/config/ho-i386.h
new file mode 100644
index 0000000..04de366
--- /dev/null
+++ b/gnu/usr.bin/as/config/ho-i386.h
@@ -0,0 +1,30 @@
+/* ho-i386.h i386 specific header file.
+ Copyright (C) 1987, 1991, 1992 Free Software Foundation, Inc.
+
+ This file is part of GAS, the GNU Assembler.
+
+ GAS is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GAS is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GAS; see the file COPYING. If not, write to
+ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+/*
+ * $Id: ho-i386.h,v 1.1 1993/11/03 00:53:21 paul Exp $
+ */
+
+
+#define HO_I386 1
+
+#define NO_STDARG
+
+#include "ho-sysv.h"
+
+/* end of ho-i386.h */
diff --git a/gnu/usr.bin/as/config/ho-i386aix.h b/gnu/usr.bin/as/config/ho-i386aix.h
new file mode 100644
index 0000000..d439f74
--- /dev/null
+++ b/gnu/usr.bin/as/config/ho-i386aix.h
@@ -0,0 +1,24 @@
+/* ho-386aix.h AIX PS/2 i386 specific header file.
+ Copyright (C) 1987, 1991, 1992 Free Software Foundation, Inc.
+
+ This file is part of GAS, the GNU Assembler.
+
+ GAS is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GAS is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GAS; see the file COPYING. If not, write to
+ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#define HO_I386 1
+
+#include "ho-sysv.h"
+
+/* end of ho-i386aix.h */
diff --git a/gnu/usr.bin/as/config/ho-rs6000.h b/gnu/usr.bin/as/config/ho-rs6000.h
new file mode 100644
index 0000000..ed49484
--- /dev/null
+++ b/gnu/usr.bin/as/config/ho-rs6000.h
@@ -0,0 +1,22 @@
+/* ho-rs6000.h Rs6000 host-specific header file.
+ Copyright (C) 1987, 1991, 1992 Free Software Foundation, Inc.
+
+ This file is part of GAS, the GNU Assembler.
+
+ GAS is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GAS is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GAS; see the file COPYING. If not, write to
+ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#define M_RS6000 1
+
+/* end of ho-rs6000.h */
diff --git a/gnu/usr.bin/as/config/ho-sun3.h b/gnu/usr.bin/as/config/ho-sun3.h
new file mode 100644
index 0000000..0d68e6f
--- /dev/null
+++ b/gnu/usr.bin/as/config/ho-sun3.h
@@ -0,0 +1,3 @@
+#include <ho-sunos.h>
+
+/* end of ho-sun3.h */
diff --git a/gnu/usr.bin/as/config/ho-sun386.h b/gnu/usr.bin/as/config/ho-sun386.h
new file mode 100644
index 0000000..6c74df4
--- /dev/null
+++ b/gnu/usr.bin/as/config/ho-sun386.h
@@ -0,0 +1,5 @@
+#include <ho-sunos.h>
+
+extern int sprintf();
+
+/* end of ho-sun386.h */
diff --git a/gnu/usr.bin/as/config/ho-sun4.h b/gnu/usr.bin/as/config/ho-sun4.h
new file mode 100644
index 0000000..cf619e8
--- /dev/null
+++ b/gnu/usr.bin/as/config/ho-sun4.h
@@ -0,0 +1,3 @@
+#include <ho-sunos.h>
+
+/* end of ho-sun4.h */
diff --git a/gnu/usr.bin/as/config/ho-sunos.h b/gnu/usr.bin/as/config/ho-sunos.h
new file mode 100644
index 0000000..9c6cc01
--- /dev/null
+++ b/gnu/usr.bin/as/config/ho-sunos.h
@@ -0,0 +1,81 @@
+/* This file is ho-sunos.h
+ Copyright (C) 1987-1992 Free Software Foundation, Inc.
+
+ This file is part of GAS, the GNU Assembler.
+
+ GAS is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GAS is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GAS; see the file COPYING. If not, write to
+ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#if __STDC__ != 1
+#define NO_STDARG
+#endif /* not __STDC__ */
+
+#if !defined(__GNUC__) && (__STDC__ != 1)
+#include <memory.h>
+#else
+extern int memset();
+#endif
+
+/* #include <sys/stdtypes.h> before <stddef.h> when compiling by GCC. */
+#include <sys/stdtypes.h>
+#include <stddef.h>
+#include <ctype.h>
+#include <string.h>
+
+/* externs for system libraries. */
+
+/*extern int abort();*/
+/*extern int exit();*/
+extern char *malloc();
+extern char *realloc();
+extern char *strchr();
+extern char *strrchr();
+extern int _filbuf();
+extern int _flsbuf();
+extern int fclose();
+extern int fgetc();
+extern int fprintf();
+extern int fread();
+extern int free();
+extern int perror();
+extern int printf();
+extern int rewind();
+extern int setvbuf();
+extern int sscanf();
+extern int strcmp();
+extern int strlen();
+extern int strncmp();
+extern int time();
+extern int ungetc();
+extern int vfprintf();
+extern int vprintf();
+extern int vsprintf();
+extern long atol();
+
+#ifndef tolower
+extern int tolower();
+#endif /* tolower */
+
+#ifndef toupper
+extern int toupper();
+#endif /* toupper */
+
+/*
+ * Local Variables:
+ * fill-column: 80
+ * comment-column: 0
+ * End:
+ */
+
+/* end of ho-sunos.h */
diff --git a/gnu/usr.bin/as/config/ho-sysv.h b/gnu/usr.bin/as/config/ho-sysv.h
new file mode 100644
index 0000000..5407e5d
--- /dev/null
+++ b/gnu/usr.bin/as/config/ho-sysv.h
@@ -0,0 +1,27 @@
+/* ho-sysv.h System V specific header file.
+ Copyright (C) 1987, 1991, 1992 Free Software Foundation, Inc.
+
+ This file is part of GAS, the GNU Assembler.
+
+ GAS is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GAS is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GAS; see the file COPYING. If not, write to
+ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#define HO_USG
+
+#define setbuffer(stream, buf, size) setvbuf((stream), (buf), _IOLBF, (size))
+
+extern int free();
+extern char *malloc();
+
+/* end of ho-sysv.h */
diff --git a/gnu/usr.bin/as/config/ho-vax.h b/gnu/usr.bin/as/config/ho-vax.h
new file mode 100644
index 0000000..ea77e81
--- /dev/null
+++ b/gnu/usr.bin/as/config/ho-vax.h
@@ -0,0 +1,27 @@
+/* ho-vax.h Intended for vax ultrix
+ Copyright (C) 1987, 1991, 1992 Free Software Foundation, Inc.
+
+ This file is part of GAS, the GNU Assembler.
+
+ GAS is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GAS is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GAS; see the file COPYING. If not, write to
+ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#if __STDC__ != 1
+#define NO_STDARG
+#endif /* not ansi */
+
+extern char *malloc();
+extern int free();
+
+/* end of ho-vax.h */
diff --git a/gnu/usr.bin/as/config/ho-vms.h b/gnu/usr.bin/as/config/ho-vms.h
new file mode 100644
index 0000000..63f448e
--- /dev/null
+++ b/gnu/usr.bin/as/config/ho-vms.h
@@ -0,0 +1,30 @@
+/* ho-vax.h Intended for vax vms
+ Copyright (C) 1987, 1991, 1992 Free Software Foundation, Inc.
+
+ This file is part of GAS, the GNU Assembler.
+
+ GAS is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GAS is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GAS; see the file COPYING. If not, write to
+ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#define HO_VAX 1
+
+#include "ho-vax.h"
+
+/* We get better performance if we use the macros rather than the functions.*/
+#include <ctype.h>
+
+/* We need this to make sure that sys_nerr has the right Psect hack. */
+#include <perror.h>
+
+/* end of ho-vms.h */
diff --git a/gnu/usr.bin/as/config/mh-i386 b/gnu/usr.bin/as/config/mh-i386
new file mode 100644
index 0000000..3375d42
--- /dev/null
+++ b/gnu/usr.bin/as/config/mh-i386
@@ -0,0 +1 @@
+ALLOCA=alloca.o
diff --git a/gnu/usr.bin/as/config/mh-i386aix b/gnu/usr.bin/as/config/mh-i386aix
new file mode 100644
index 0000000..a1e5d77
--- /dev/null
+++ b/gnu/usr.bin/as/config/mh-i386aix
@@ -0,0 +1,5 @@
+# Define SYSV as -DSYSV if you are using a System V operating system.
+SYSV = -DSYSV
+RANLIB = /bin/true
+CC = gcc
+MINUS_G = -O
diff --git a/gnu/usr.bin/as/config/mh-i386v4 b/gnu/usr.bin/as/config/mh-i386v4
new file mode 100644
index 0000000..5bfcd28
--- /dev/null
+++ b/gnu/usr.bin/as/config/mh-i386v4
@@ -0,0 +1 @@
+HLIBS=-lucb
diff --git a/gnu/usr.bin/as/config/mt-ebmon29k b/gnu/usr.bin/as/config/mt-ebmon29k
new file mode 100644
index 0000000..528e6fc
--- /dev/null
+++ b/gnu/usr.bin/as/config/mt-ebmon29k
@@ -0,0 +1,6 @@
+TARG_CPU_DEPENDENTS=
+LOCAL_LOADLIBES=../bfd$(subdir)/libbfd.a
+TDEFINES=-DBFD_HEADERS -DMANY_SEGMENTS -DBFD
+
+
+
diff --git a/gnu/usr.bin/as/config/mt-h8300 b/gnu/usr.bin/as/config/mt-h8300
new file mode 100644
index 0000000..d968db2
--- /dev/null
+++ b/gnu/usr.bin/as/config/mt-h8300
@@ -0,0 +1,5 @@
+TARG_CPU_DEPENDENTS=$(srcdir)/../include/opcode/h8300.h
+LOCAL_LOADLIBES=$(srcdir)/../bfd/$(srcdir)/libbfd.a
+TDEFINES=-DBFD_HEADERS -DMANY_SEGMENTS -DBFD
+
+CC=gcc
diff --git a/gnu/usr.bin/as/config/mt-h8300hds b/gnu/usr.bin/as/config/mt-h8300hds
new file mode 100644
index 0000000..1e6eb3c
--- /dev/null
+++ b/gnu/usr.bin/as/config/mt-h8300hds
@@ -0,0 +1,4 @@
+TARG_CPU_DEPENDENTS=$(srcdir)/../include/h8300-opcode.h
+LOCAL_LOADLIBES=$(srcdir)/../bfd/$(srcdir)/libbfd.a
+TDEFINES=-DBFD -DMANY_SEGMENTS
+
diff --git a/gnu/usr.bin/as/config/mt-i386aix b/gnu/usr.bin/as/config/mt-i386aix
new file mode 100644
index 0000000..225fc36
--- /dev/null
+++ b/gnu/usr.bin/as/config/mt-i386aix
@@ -0,0 +1,3 @@
+# TDEFINES = -DBFD_HEADERS
+CC = gcc
+MINUS_G = -O
diff --git a/gnu/usr.bin/as/config/mt-mips b/gnu/usr.bin/as/config/mt-mips
new file mode 100644
index 0000000..f40f51d
--- /dev/null
+++ b/gnu/usr.bin/as/config/mt-mips
@@ -0,0 +1 @@
+ALL=fake-as
diff --git a/gnu/usr.bin/as/config/mt-rs6000 b/gnu/usr.bin/as/config/mt-rs6000
new file mode 100644
index 0000000..f40f51d
--- /dev/null
+++ b/gnu/usr.bin/as/config/mt-rs6000
@@ -0,0 +1 @@
+ALL=fake-as
diff --git a/gnu/usr.bin/as/config/obj-aout.c b/gnu/usr.bin/as/config/obj-aout.c
new file mode 100644
index 0000000..146f346
--- /dev/null
+++ b/gnu/usr.bin/as/config/obj-aout.c
@@ -0,0 +1,647 @@
+/* a.out object file format
+ Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
+
+ This file is part of GAS, the GNU Assembler.
+
+ GAS is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2,
+ or (at your option) any later version.
+
+ GAS is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+ the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public
+ License along with GAS; see the file COPYING. If not, write
+ to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "as.h"
+#include "obstack.h"
+
+
+#include <stab.h>
+
+/* in: segT out: N_TYPE bits */
+const short seg_N_TYPE[] = {
+ N_ABS,
+ N_TEXT,
+ N_DATA,
+ N_BSS,
+ N_UNDF, /* unknown */
+ N_UNDF, /* absent */
+ N_UNDF, /* pass1 */
+ N_UNDF, /* error */
+ N_UNDF, /* bignum/flonum */
+ N_UNDF, /* difference */
+ N_UNDF, /* debug */
+ N_UNDF, /* ntv */
+ N_UNDF, /* ptv */
+ N_REGISTER, /* register */
+};
+
+const segT N_TYPE_seg[N_TYPE+2] = { /* N_TYPE == 0x1E = 32-2 */
+ SEG_UNKNOWN, SEG_GOOF, /* N_UNDF == 0 */
+ SEG_ABSOLUTE, SEG_GOOF, /* N_ABS == 2 */
+ SEG_TEXT, SEG_GOOF, /* N_TEXT == 4 */
+ SEG_DATA, SEG_GOOF, /* N_DATA == 6 */
+ SEG_BSS, SEG_GOOF, /* N_BSS == 8 */
+ SEG_GOOF, SEG_GOOF, /* N_INDR == 0xa */
+ SEG_GOOF, SEG_GOOF, /* 0xc */
+ SEG_GOOF, SEG_GOOF, /* 0xe */
+ SEG_GOOF, SEG_GOOF, /* 0x10 */
+ SEG_REGISTER, SEG_GOOF, /* 0x12 (dummy N_REGISTER) */
+ SEG_GOOF, SEG_GOOF, /* N_SETA == 0x14 */
+ SEG_GOOF, SEG_GOOF, /* N_SETT == 0x16 */
+ SEG_GOOF, SEG_GOOF, /* N_SETD == 0x18 */
+ SEG_GOOF, SEG_GOOF, /* N_SETB == 0x1a */
+ SEG_GOOF, SEG_GOOF, /* N_SETV == 0x1c */
+ SEG_GOOF, SEG_GOOF, /* N_WARNING == 0x1e */
+};
+
+#if __STDC__ == 1
+static void obj_aout_stab(int what);
+static void obj_aout_line(void);
+static void obj_aout_desc(void);
+#else /* not __STDC__ */
+static void obj_aout_desc();
+static void obj_aout_stab();
+static void obj_aout_line();
+#endif /* not __STDC__ */
+
+const pseudo_typeS obj_pseudo_table[] = {
+#ifndef IGNORE_DEBUG
+ /* stabs debug info */
+ { "line", obj_aout_line, 0 }, /* source code line number */
+ { "ln", obj_aout_line, 0 }, /* coff line number that we use anyway */
+ { "desc", obj_aout_desc, 0 }, /* desc */
+ { "stabd", obj_aout_stab, 'd' }, /* stabs */
+ { "stabn", obj_aout_stab, 'n' }, /* stabs */
+ { "stabs", obj_aout_stab, 's' }, /* stabs */
+#else /* IGNORE_DEBUG */
+ { "line", obj_aout_line, 0 }, /* source code line number */
+ { "ln", obj_aout_line, 0 }, /* coff line number that we use anyway */
+ { "desc", obj_aout_desc, 0 }, /* desc */
+ { "stabd", obj_aout_stab, 'd' }, /* stabs */
+ { "stabn", obj_aout_stab, 'n' }, /* stabs */
+ { "stabs", obj_aout_stab, 's' }, /* stabs */
+#endif /* IGNORE_DEBUG */
+
+ /* coff debug pseudos (ignored) */
+ { "def", s_ignore, 0 },
+ { "dim", s_ignore, 0 },
+ { "endef", s_ignore, 0 },
+ { "ident", s_ignore, 0 },
+ { "line", s_ignore, 0 },
+ { "ln", s_ignore, 0 },
+ { "scl", s_ignore, 0 },
+ { "size", s_size, 0 },
+ { "tag", s_ignore, 0 },
+ { "type", s_type, 0 },
+ { "val", s_ignore, 0 },
+ { "version", s_ignore, 0 },
+
+ /* stabs-in-coff (?) debug pseudos (ignored) */
+ { "optim", s_ignore, 0 }, /* For sun386i cc (?) */
+
+ /* other stuff */
+ { "ABORT", s_abort, 0 },
+
+ { NULL} /* end sentinel */
+}; /* obj_pseudo_table */
+
+
+/* Relocation. */
+
+/*
+ * emit_relocations()
+ *
+ * Crawl along a fixS chain. Emit the segment's relocations.
+ */
+void obj_emit_relocations(where, fixP, segment_address_in_file)
+char **where;
+fixS *fixP; /* Fixup chain for this segment. */
+relax_addressT segment_address_in_file;
+{
+ for (; fixP; fixP = fixP->fx_next) {
+ if (fixP->fx_addsy != NULL) {
+ tc_aout_fix_to_chars(*where, fixP, segment_address_in_file);
+ *where += md_reloc_size;
+ } /* if there is an add symbol */
+ } /* for each fix */
+
+ return;
+} /* obj_emit_relocations() */
+
+/* Aout file generation & utilities */
+void obj_header_append(where, headers)
+char **where;
+object_headers *headers;
+{
+ tc_headers_hook(headers);
+
+#if defined(FREEBSD_AOUT) || defined(NETBSD_AOUT)
+ /* `a_info' (magic, mid, flags) is in network byte-order */
+ (*where)[0] = ((char *)&headers->header.a_info)[0];
+ (*where)[1] = ((char *)&headers->header.a_info)[1];
+ (*where)[2] = ((char *)&headers->header.a_info)[2];
+ (*where)[3] = ((char *)&headers->header.a_info)[3];
+#else
+ md_number_to_chars(*where, headers->header.a_info,
+ sizeof(headers->header.a_info));
+#endif
+ *where += sizeof(headers->header.a_info);
+
+#ifdef TE_HPUX
+ md_number_to_chars(*where, 0, 4); *where += 4; /* a_spare1 */
+ md_number_to_chars(*where, 0, 4); *where += 4; /* a_spare2 */
+#endif /* TE_HPUX */
+
+ md_number_to_chars(*where, headers->header.a_text, 4); *where += 4;
+ md_number_to_chars(*where, headers->header.a_data, 4); *where += 4;
+ md_number_to_chars(*where, headers->header.a_bss, 4); *where += 4;
+
+#ifndef TE_HPUX
+ md_number_to_chars(*where, headers->header.a_syms, 4); *where += 4;
+ md_number_to_chars(*where, headers->header.a_entry, 4); *where += 4;
+#endif /* not TE_HPUX */
+
+ md_number_to_chars(*where, headers->header.a_trsize, 4); *where += 4;
+ md_number_to_chars(*where, headers->header.a_drsize, 4); *where += 4;
+
+#ifdef TE_SEQUENT
+ memset(*where, '\0', 3 * 2 * 4); *where += 3 * 2 * 4; /* global descriptor table? */
+ md_number_to_chars(*where, 0, 4); *where += 4; /* shdata - length of initialized shared data */
+ md_number_to_chars(*where, 0, 4); *where += 4; /* shbss - length of uninitialized shared data */
+ md_number_to_chars(*where, 0, 4); *where += 4; /* shdrsize - length of shared data relocation */
+
+ memset(*where, '\0', 11 * 4); *where += 11 * 4; /* boostrap for standalone */
+ memset(*where, '\0', 3 * 4); *where += 3 * 4; /* reserved */
+ md_number_to_chars(*where, 0, 4); *where += 4; /* version */
+#endif /* TE_SEQUENT */
+
+#ifdef TE_HPUX
+ md_number_to_chars(*where, 0, 4); *where += 4; /* a_spare3 - HP = pascal interface size */
+ md_number_to_chars(*where, 0, 4); *where += 4; /* a_spare4 - HP = symbol table size */
+ md_number_to_chars(*where, 0, 4); *where += 4; /* a_spare5 - HP = debug name table size */
+
+ md_number_to_chars(*where, headers->header.a_entry, 4); *where += 4;
+
+ md_number_to_chars(*where, 0, 4); *where += 4; /* a_spare6 - HP = source line table size */
+ md_number_to_chars(*where, 0, 4); *where += 4; /* a_spare7 - HP = value table size */
+
+ md_number_to_chars(*where, headers->header.a_syms, 4); *where += 4;
+
+ md_number_to_chars(*where, 0, 4); *where += 4; /* a_spare8 */
+#endif /* TE_HPUX */
+
+ return;
+} /* obj_append_header() */
+
+void obj_symbol_to_chars(where, symbolP)
+char **where;
+symbolS *symbolP;
+{
+ md_number_to_chars((char *)&(S_GET_OFFSET(symbolP)), S_GET_OFFSET(symbolP), sizeof(S_GET_OFFSET(symbolP)));
+ md_number_to_chars((char *)&(S_GET_DESC(symbolP)), S_GET_DESC(symbolP), sizeof(S_GET_DESC(symbolP)));
+ md_number_to_chars((char *)&(S_GET_VALUE(symbolP)), S_GET_VALUE(symbolP), sizeof(S_GET_VALUE(symbolP)));
+
+ append(where, (char *)&symbolP->sy_symbol, sizeof(obj_symbol_type));
+} /* obj_symbol_to_chars() */
+
+void obj_emit_symbols(where, symbol_rootP)
+char **where;
+symbolS *symbol_rootP;
+{
+ symbolS * symbolP;
+
+ /*
+ * Emit all symbols left in the symbol chain.
+ */
+ for (symbolP = symbol_rootP; symbolP; symbolP = symbol_next(symbolP)) {
+ /* Used to save the offset of the name. It is used to point
+ to the string in memory but must be a file offset. */
+ register char *temp;
+
+ temp = S_GET_NAME(symbolP);
+ S_SET_OFFSET(symbolP, symbolP->sy_name_offset);
+
+ /*
+ * Put aux info in lower four bits of `n_other' field
+ * Do this only now, because things like S_IS_DEFINED()
+ * depend on S_GET_OTHER() for some unspecified reason.
+ */
+ if (symbolP->sy_aux)
+ S_SET_OTHER(symbolP, (symbolP->sy_aux & 0xf));
+
+ /* Any symbol still undefined and is not a dbg symbol is made N_EXT. */
+ if (!S_IS_DEBUG(symbolP) && !S_IS_DEFINED(symbolP))
+ S_SET_EXTERNAL(symbolP);
+
+ if (S_GET_TYPE(symbolP) == N_SIZE) {
+ expressionS *exp = (expressionS*)symbolP->sy_sizexp;
+ long size = 0;
+
+ if (exp == NULL) {
+ as_bad("Internal error: no size expression");
+ return;
+ }
+
+ switch (exp->X_seg) {
+ case SEG_ABSOLUTE:
+ size = exp->X_add_number;
+ break;
+ case SEG_DIFFERENCE:
+ size = S_GET_VALUE(exp->X_add_symbol) -
+ S_GET_VALUE(exp->X_subtract_symbol) +
+ exp->X_add_number;
+ break;
+ default:
+ as_bad("Unsupported .size expression");
+ break;
+ }
+ S_SET_VALUE(symbolP, size);
+ }
+
+ obj_symbol_to_chars(where, symbolP);
+ S_SET_NAME(symbolP,temp);
+ }
+} /* emit_symbols() */
+
+#if comment
+/* uneeded if symbol is born zeroed. */
+void obj_symbol_new_hook(symbolP)
+symbolS *symbolP;
+{
+ S_SET_OTHER(symbolP, 0);
+ S_SET_DESC(symbolP, 0);
+ return;
+} /* obj_symbol_new_hook() */
+#endif /* comment */
+
+static void obj_aout_line() {
+ /* Assume delimiter is part of expression. */
+ /* BSD4.2 as fails with delightful bug, so we */
+ /* are not being incompatible here. */
+ new_logical_line((char *)NULL, (int)(get_absolute_expression()));
+ demand_empty_rest_of_line();
+} /* obj_aout_line() */
+
+/*
+ * stab()
+ *
+ * Handle .stabX directives, which used to be open-coded.
+ * So much creeping featurism overloaded the semantics that we decided
+ * to put all .stabX thinking in one place. Here.
+ *
+ * We try to make any .stabX directive legal. Other people's AS will often
+ * do assembly-time consistency checks: eg assigning meaning to n_type bits
+ * and "protecting" you from setting them to certain values. (They also zero
+ * certain bits before emitting symbols. Tut tut.)
+ *
+ * If an expression is not absolute we either gripe or use the relocation
+ * information. Other people's assemblers silently forget information they
+ * don't need and invent information they need that you didn't supply.
+ *
+ * .stabX directives always make a symbol table entry. It may be junk if
+ * the rest of your .stabX directive is malformed.
+ */
+static void obj_aout_stab(what)
+int what;
+{
+#ifndef NO_LISTING
+ extern int listing;
+#endif /* NO_LISTING */
+
+ register symbolS *symbolP = 0;
+ register char *string;
+ int saved_type = 0;
+ int length;
+ int goof; /* TRUE if we have aborted. */
+ long longint;
+
+ /*
+ * Enter with input_line_pointer pointing past .stabX and any following
+ * whitespace.
+ */
+ goof = 0; /* JF who forgot this?? */
+ if (what == 's') {
+ string = demand_copy_C_string(& length);
+ SKIP_WHITESPACE();
+ if (* input_line_pointer == ',')
+ input_line_pointer ++;
+ else {
+ as_bad("I need a comma after symbol's name");
+ goof = 1;
+ }
+ } else
+ string = "";
+
+ /*
+ * Input_line_pointer->after ','. String->symbol name.
+ */
+ if (! goof) {
+ symbolP = symbol_new(string,
+ SEG_UNKNOWN,
+ 0,
+ (struct frag *)0);
+ switch (what) {
+ case 'd':
+ S_SET_NAME(symbolP, NULL); /* .stabd feature. */
+ S_SET_VALUE(symbolP, obstack_next_free(&frags) - frag_now->fr_literal);
+ symbolP->sy_frag = frag_now;
+ break;
+
+ case 'n':
+ symbolP->sy_frag = &zero_address_frag;
+ break;
+
+ case 's':
+ symbolP->sy_frag = & zero_address_frag;
+ break;
+
+ default:
+ BAD_CASE(what);
+ break;
+ }
+
+ if (get_absolute_expression_and_terminator(&longint) == ',')
+ symbolP->sy_symbol.n_type = saved_type = longint;
+ else {
+ as_bad("I want a comma after the n_type expression");
+ goof = 1;
+ input_line_pointer --; /* Backup over a non-',' char. */
+ }
+ }
+
+ if (!goof) {
+ if (get_absolute_expression_and_terminator(&longint) == ',')
+ S_SET_OTHER(symbolP, longint);
+ else {
+ as_bad("I want a comma after the n_other expression");
+ goof = 1;
+ input_line_pointer--; /* Backup over a non-',' char. */
+ }
+ }
+
+ if (!goof) {
+ S_SET_DESC(symbolP, get_absolute_expression());
+ if (what == 's' || what == 'n') {
+ if (*input_line_pointer != ',') {
+ as_bad("I want a comma after the n_desc expression");
+ goof = 1;
+ } else {
+ input_line_pointer++;
+ }
+ }
+ }
+
+ if ((!goof) && (what == 's' || what == 'n')) {
+ pseudo_set(symbolP);
+ symbolP->sy_symbol.n_type = saved_type;
+ }
+#ifndef NO_LISTING
+ if (listing && !goof)
+ {
+ if (symbolP->sy_symbol.n_type == N_SLINE)
+ {
+
+ listing_source_line(symbolP->sy_symbol.n_desc);
+ }
+ else if (symbolP->sy_symbol.n_type == N_SO
+ || symbolP->sy_symbol.n_type == N_SOL)
+ {
+ listing_source_file(string);
+ }
+ }
+#endif
+
+ if (goof)
+ ignore_rest_of_line();
+ else
+ demand_empty_rest_of_line ();
+} /* obj_aout_stab() */
+
+static void obj_aout_desc() {
+ register char *name;
+ register char c;
+ register char *p;
+ register symbolS *symbolP;
+ register int temp;
+
+ /*
+ * Frob invented at RMS' request. Set the n_desc of a symbol.
+ */
+ name = input_line_pointer;
+ c = get_symbol_end();
+ p = input_line_pointer;
+ * p = c;
+ SKIP_WHITESPACE();
+ if (*input_line_pointer != ',') {
+ *p = 0;
+ as_bad("Expected comma after name \"%s\"", name);
+ *p = c;
+ ignore_rest_of_line();
+ } else {
+ input_line_pointer ++;
+ temp = get_absolute_expression();
+ *p = 0;
+ symbolP = symbol_find_or_make(name);
+ *p = c;
+ S_SET_DESC(symbolP,temp);
+ }
+ demand_empty_rest_of_line();
+} /* obj_aout_desc() */
+
+void obj_read_begin_hook() {
+ return;
+} /* obj_read_begin_hook() */
+
+void obj_crawl_symbol_chain(headers)
+object_headers *headers;
+{
+ symbolS *symbolP;
+ symbolS **symbolPP;
+ int symbol_number = 0;
+
+ /* JF deal with forward references first... */
+ for (symbolP = symbol_rootP; symbolP; symbolP = symbol_next(symbolP)) {
+ if (symbolP->sy_forward) {
+ S_SET_VALUE(symbolP, S_GET_VALUE(symbolP)
+ + S_GET_VALUE(symbolP->sy_forward)
+ + symbolP->sy_forward->sy_frag->fr_address);
+
+ symbolP->sy_forward=0;
+ } /* if it has a forward reference */
+ } /* walk the symbol chain */
+
+ tc_crawl_symbol_chain(headers);
+
+ symbolPP = &symbol_rootP; /*->last symbol chain link. */
+ while ((symbolP = *symbolPP) != NULL) {
+ if (flagseen['R'] && (S_GET_SEGMENT(symbolP) == SEG_DATA)) {
+ S_SET_SEGMENT(symbolP, SEG_TEXT);
+ } /* if pusing data into text */
+
+ S_SET_VALUE(symbolP, S_GET_VALUE(symbolP) + symbolP->sy_frag->fr_address);
+
+ /* OK, here is how we decide which symbols go out into the
+ brave new symtab. Symbols that do are:
+
+ * symbols with no name (stabd's?)
+ * symbols with debug info in their N_TYPE
+ * symbols marked "forceout" (to force out local `L'
+ symbols in PIC code)
+
+ Symbols that don't are:
+ * symbols that are registers
+ * symbols with \1 as their 3rd character (numeric labels)
+ * "local labels" as defined by S_LOCAL_NAME(name)
+ if the -L switch was passed to gas.
+
+ All other symbols are output. We complain if a deleted
+ symbol was marked external. */
+
+
+ if (!S_IS_REGISTER(symbolP)
+ && (!S_GET_NAME(symbolP)
+ || S_IS_DEBUG(symbolP)
+#ifdef TC_I960
+ /* FIXME-SOON this ifdef seems highly dubious to me. xoxorich. */
+ || !S_IS_DEFINED(symbolP)
+ || S_IS_EXTERNAL(symbolP)
+#endif /* TC_I960 */
+ || (S_GET_NAME(symbolP)[0] != '\001' &&
+ (flagseen['L'] || ! S_LOCAL_NAME(symbolP))
+#ifdef PIC
+ || (flagseen['k'] && symbolP->sy_forceout)
+#endif
+ )
+ )
+#ifdef PIC
+ && (!flagseen['k'] ||
+ symbolP != GOT_symbol || got_referenced != 0
+ )
+#endif
+ ) {
+ symbolP->sy_number = symbol_number++;
+
+ /* The + 1 after strlen account for the \0 at the
+ end of each string */
+ if (!S_IS_STABD(symbolP)) {
+ /* Ordinary case. */
+ symbolP->sy_name_offset = string_byte_count;
+ string_byte_count += strlen(S_GET_NAME(symbolP)) + 1;
+ }
+ else /* .Stabd case. */
+ symbolP->sy_name_offset = 0;
+
+ /*
+ * If symbol has a known size, output an extra symbol
+ * of type N_SIZE and with the same name.
+ * We cannot evaluate the size expression just yet, as
+ * some its terms may not have had their final values
+ * set. We defer this until `obj_emit_symbols()'
+ */
+ if (flagseen['k'] &&
+ S_GET_TYPE(symbolP) != N_SIZE &&
+#ifndef GRACE_PERIOD_EXPIRED
+ /*Can be enabled when no more old ld's around*/
+ (symbolP->sy_aux == AUX_OBJECT) &&
+#endif
+ symbolP->sy_sizexp) {
+
+ symbolS *addme;
+
+ /* Put a new symbol on the chain */
+#ifdef NSIZE_PREFIX /*XXX*/
+ char buf[BUFSIZ];
+
+ buf[0] = NSIZE_PREFIX;
+ strncpy(buf+1, S_GET_NAME(symbolP), BUFSIZ-2);
+ addme = symbol_make(buf);
+#else
+ addme = symbol_make(S_GET_NAME(symbolP));
+#endif
+ /* Set type and transfer size expression */
+ addme->sy_symbol.n_type = N_SIZE;
+ addme->sy_sizexp = symbolP->sy_sizexp;
+ symbolP->sy_sizexp = NULL;
+
+ /* Set external if symbolP is */
+ if (S_IS_EXTERN(symbolP))
+ S_SET_EXTERNAL(addme);
+
+ }
+ symbolPP = &(symbol_next(symbolP));
+ } else {
+ if ((S_IS_EXTERNAL(symbolP) || !S_IS_DEFINED(symbolP))
+#ifdef PIC
+ && (!flagseen['k'] ||
+ symbolP != GOT_symbol || got_referenced != 0
+ )
+#endif
+ ) {
+ as_bad("Local symbol %s never defined.", decode_local_label_name(S_GET_NAME(symbolP)));
+ } /* oops. */
+
+ /* Unhook it from the chain */
+ *symbolPP = symbol_next(symbolP);
+ } /* if this symbol should be in the output */
+ } /* for each symbol */
+
+ H_SET_SYMBOL_TABLE_SIZE(headers, symbol_number);
+
+ return;
+} /* obj_crawl_symbol_chain() */
+
+/*
+ * Find strings by crawling along symbol table chain.
+ */
+
+void obj_emit_strings(where)
+char **where;
+{
+ symbolS *symbolP;
+
+#ifdef CROSS_COMPILE
+ /* Gotta do md_ byte-ordering stuff for string_byte_count first - KWK */
+ md_number_to_chars(*where, string_byte_count, sizeof(string_byte_count));
+ *where += sizeof(string_byte_count);
+#else /* CROSS_COMPILE */
+ append (where, (char *)&string_byte_count, (unsigned long)sizeof(string_byte_count));
+#endif /* CROSS_COMPILE */
+
+ for (symbolP = symbol_rootP; symbolP; symbolP = symbol_next(symbolP)) {
+ if (S_GET_NAME(symbolP))
+ append(&next_object_file_charP, S_GET_NAME(symbolP),
+ (unsigned long)(strlen (S_GET_NAME(symbolP)) + 1));
+ } /* walk symbol chain */
+
+ return;
+} /* obj_emit_strings() */
+
+void obj_pre_write_hook(headers)
+object_headers *headers;
+{
+ H_SET_INFO(headers,
+ DEFAULT_MAGIC_NUMBER_FOR_OBJECT_FILE,
+ AOUT_MACHTYPE,
+ AOUT_FLAGS,
+ AOUT_VERSION);
+
+ H_SET_ENTRY_POINT(headers, 0);
+
+ tc_aout_pre_write_hook(headers);
+ return;
+} /* obj_pre_write_hook() */
+
+/*
+ * Local Variables:
+ * comment-column: 0
+ * fill-column: 131
+ * End:
+ */
+
+/* end of obj-aout.c */
diff --git a/gnu/usr.bin/as/config/obj-aout.h b/gnu/usr.bin/as/config/obj-aout.h
new file mode 100644
index 0000000..1ac0f5c
--- /dev/null
+++ b/gnu/usr.bin/as/config/obj-aout.h
@@ -0,0 +1,305 @@
+/* obj-aout.h, a.out object file format for gas, the assembler.
+ Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
+
+ This file is part of GAS, the GNU Assembler.
+
+ GAS is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2,
+ or (at your option) any later version.
+
+ GAS is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+ the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public
+ License along with GAS; see the file COPYING. If not, write
+ to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ $Id: obj-aout.h,v 1.3 1994/12/23 22:37:34 nate Exp $
+ */
+
+
+/* Tag to validate a.out object file format processing */
+#define OBJ_AOUT 1
+
+#include "targ-cpu.h"
+
+#include "aout.h" /* Needed to define struct nlist. Sigh. */
+
+#ifndef AOUT_MACHTYPE
+#define AOUT_MACHTYPE 0
+#endif
+
+#ifndef AOUT_VERSION
+#define AOUT_VERSION 0
+#endif
+
+#ifndef AOUT_FLAGS
+#define AOUT_FLAGS 0
+#endif
+
+extern const short seg_N_TYPE[];
+extern const segT N_TYPE_seg[];
+#define N_REGISTER 0x12 /* Fake register type */
+
+#ifndef DEFAULT_MAGIC_NUMBER_FOR_OBJECT_FILE
+#define DEFAULT_MAGIC_NUMBER_FOR_OBJECT_FILE (OMAGIC)
+#endif /* DEFAULT_MAGIC_NUMBER_FOR_OBJECT_FILE */
+
+/* First character of operand in `.type' directives */
+#define TYPE_OPERAND_FMT '@'
+
+/* SYMBOL TABLE */
+/* Symbol table entry data type */
+
+typedef struct nlist obj_symbol_type; /* Symbol table entry */
+
+/* Symbol table macros and constants */
+
+/*
+ * Macros to extract information from a symbol table entry.
+ * This syntaxic indirection allows independence regarding a.out or coff.
+ * The argument (s) of all these macros is a pointer to a symbol table entry.
+ */
+
+/* True if the symbol is external */
+#define S_IS_EXTERNAL(s) ((s)->sy_symbol.n_type & N_EXT)
+
+/* True if symbol has been defined, ie is in N_{TEXT,DATA,BSS,ABS} or N_EXT */
+#define S_IS_DEFINED(s) ((S_GET_TYPE(s) != N_UNDF) || (S_GET_OTHER(s) != 0) || (S_GET_DESC(s) != 0))
+
+#define S_IS_REGISTER(s) ((s)->sy_symbol.n_type == N_REGISTER)
+
+/* True if a debug special symbol entry */
+#define S_IS_DEBUG(s) ((s)->sy_symbol.n_type & N_STAB)
+/* True if a symbol is local symbol name */
+/* A symbol name whose name begin with ^A is a gas internal pseudo symbol
+ nameless symbols come from .stab directives. */
+#define S_IS_LOCAL(s) (S_GET_NAME(s) && \
+ !S_IS_DEBUG(s) && \
+ (S_GET_NAME(s)[0] == '\001' || \
+ (S_LOCAL_NAME(s) && !flagseen['L'])))
+/* True if a symbol is not defined in this file */
+#define S_IS_EXTERN(s) ((s)->sy_symbol.n_type & N_EXT)
+/* True if the symbol has been generated because of a .stabd directive */
+#define S_IS_STABD(s) (S_GET_NAME(s) == (char *)0)
+
+/* Accessors */
+/* The value of the symbol */
+#define S_GET_VALUE(s) (((s)->sy_symbol.n_value))
+/* The name of the symbol */
+#define S_GET_NAME(s) ((s)->sy_symbol.n_un.n_name)
+/* The pointer to the string table */
+#define S_GET_OFFSET(s) ((s)->sy_symbol.n_un.n_strx)
+/* The type of the symbol */
+#define S_GET_TYPE(s) ((s)->sy_symbol.n_type & N_TYPE)
+/* The numeric value of the segment */
+#define S_GET_SEGMENT(s) (N_TYPE_seg[S_GET_TYPE(s)])
+/* The n_other expression value */
+#define S_GET_OTHER(s) ((s)->sy_symbol.n_other)
+/* The n_desc expression value */
+#define S_GET_DESC(s) ((s)->sy_symbol.n_desc)
+
+/* Modifiers */
+/* Set the value of the symbol */
+#define S_SET_VALUE(s,v) ((s)->sy_symbol.n_value = (unsigned long) (v))
+/* Assume that a symbol cannot be simultaneously in more than on segment */
+/* set segment */
+#define S_SET_SEGMENT(s,seg) ((s)->sy_symbol.n_type &= ~N_TYPE,(s)->sy_symbol.n_type|=SEGMENT_TO_SYMBOL_TYPE(seg))
+/* The symbol is external */
+#define S_SET_EXTERNAL(s) ((s)->sy_symbol.n_type |= N_EXT)
+/* The symbol is not external */
+#define S_CLEAR_EXTERNAL(s) ((s)->sy_symbol.n_type &= ~N_EXT)
+/* Set the name of the symbol */
+#define S_SET_NAME(s,v) ((s)->sy_symbol.n_un.n_name = (v))
+/* Set the offset in the string table */
+#define S_SET_OFFSET(s,v) ((s)->sy_symbol.n_un.n_strx = (v))
+/* Set the n_other expression value */
+#define S_SET_OTHER(s,v) ((s)->sy_symbol.n_other = (v))
+/* Set the n_desc expression value */
+#define S_SET_DESC(s,v) ((s)->sy_symbol.n_desc = (v))
+
+/* File header macro and type definition */
+
+#define H_GET_FILE_SIZE(h) (H_GET_HEADER_SIZE(h) \
+ + H_GET_TEXT_SIZE(h) \
+ + H_GET_DATA_SIZE(h) \
+ + H_GET_SYMBOL_TABLE_SIZE(h) \
+ + H_GET_TEXT_RELOCATION_SIZE(h) \
+ + H_GET_DATA_RELOCATION_SIZE(h) \
+ + H_GET_STRING_SIZE(h))
+
+#ifndef H_GET_HEADER_SIZE
+#define H_GET_HEADER_SIZE(h) (sizeof(struct exec))
+#endif /* not H_GET_HEADER_SIZE */
+
+#define H_GET_TEXT_SIZE(h) ((h)->header.a_text)
+#define H_GET_DATA_SIZE(h) ((h)->header.a_data)
+#define H_GET_BSS_SIZE(h) ((h)->header.a_bss)
+#define H_GET_TEXT_RELOCATION_SIZE(h) ((h)->header.a_trsize)
+#define H_GET_DATA_RELOCATION_SIZE(h) ((h)->header.a_drsize)
+#define H_GET_SYMBOL_TABLE_SIZE(h) ((h)->header.a_syms)
+#define H_GET_ENTRY_POINT(h) ((h)->header.a_entry)
+#define H_GET_STRING_SIZE(h) ((h)->string_table_size)
+#define H_GET_LINENO_SIZE(h) (0)
+
+#if defined(FREEBSD_AOUT) || defined(NETBSD_AOUT)
+
+#if defined(FREEBSD_AOUT)
+/* duplicate part of <sys/imgact_aout.h> */
+#define H_GET_FLAGS(h) \
+ ( (((h)->header.a_info)&0xffff) \
+ ? ((h)->header.a_info >> 26) & 0x3f ) \
+ : 0 \
+ )
+#define H_GET_MACHTYPE(h) \
+ ( (((h)->header.a_info)&0xffff) \
+ ? ((h)->header.a_info >>16 ) & 0x3ff) \
+ : 0 \
+ )
+
+#define H_GET_MAGIC_NUMBER(h) \
+ ( (((h)->header.a_info)&0xffff) \
+ ? ((h)->header.a_info & 0xffff) \
+ : (ntohl(((h)->header.a_info))&0xffff) \
+ )
+
+#define H_SET_INFO(h,mag,mid,f,v) \
+ ( (h)->header.a_info = \
+ htonl( (((f)&0x3f)<<26) | (((mid)&0x03ff)<<16) | (((mag)&0xffff)) ) )
+
+#endif /* FREEBSD_AOUT */
+
+#if defined(NETBSD_AOUT)
+/* SH*T, duplicate part of <a.out.h> */
+#define H_GET_FLAGS(h) \
+ ( (((h)->header.a_info)&0xffff0000) \
+ ? ((ntohl(((h)->header.a_info))>>26)&0x3f) \
+ : 0 \
+ )
+
+#define H_GET_MACHTYPE(h) \
+ ( (((h)->header.a_info)&0xffff0000) \
+ ? ((ntohl(((h)->header.a_info))>>16)&0x3ff) \
+ : 0 \
+ )
+
+#define H_GET_MAGIC_NUMBER(h) \
+ ( (((h)->header.a_info)&0xffff0000) \
+ ? (ntohl(((h)->header.a_info))&0xffff) \
+ : ((h)->header.a_info & 0xffff) \
+ )
+
+#define H_SET_INFO(h,mag,mid,f,v) \
+ ( (h)->header.a_info = \
+ htonl( (((f)&0x3f)<<26) | (((mid)&0x03ff)<<16) | (((mag)&0xffff)) ) )
+
+#endif /* NETBSD_AOUT */
+
+#define EX_DYNAMIC 0x20
+#define EX_PIC 0x10
+#undef AOUT_FLAGS
+#define AOUT_FLAGS (flagseen['k'] ? EX_PIC : 0)
+
+#define H_GET_DYNAMIC(h) (H_GET_FLAGS(h) & EX_DYNAMIC)
+
+#define H_GET_VERSION(h) (0)
+
+#define H_SET_DYNAMIC(h,v) \
+ H_SET_INFO(h, H_GET_MAGIC_NUMBER(h), H_GET_MACHTYPE(h), \
+ (v)?(H_GET_FLAGS(h)|0x20):(H_GET_FLAGS(h)&(~0x20)), 0)
+
+#define H_SET_VERSION(h,v)
+
+#define H_SET_MACHTYPE(h,v) \
+ H_SET_INFO(h, H_GET_MAGIC_NUMBER(h), (v), H_GET_FLAGS(h), 0)
+
+#define H_SET_MAGIC_NUMBER(h,v) \
+ H_SET_INFO(h, (v), H_GET_MACHTYPE(h), H_GET_FLAGS(h), 0)
+
+#else /* !(FREEBSD_AOUT || NETBSD_AOUT) */
+
+#define H_GET_DYNAMIC(h) ((h)->header.a_info >> 31)
+#define H_GET_VERSION(h) (((h)->header.a_info >> 24) & 0x7f)
+#define H_GET_MACHTYPE(h) (((h)->header.a_info >> 16) & 0xff)
+#define H_GET_MAGIC_NUMBER(h) ((h)->header.a_info & 0xffff)
+
+#define H_SET_DYNAMIC(h,v) ((h)->header.a_info = \
+ (((v) << 31) \
+ | (H_GET_VERSION(h) << 24) \
+ | (H_GET_MACHTYPE(h) << 16) \
+ | (H_GET_MAGIC_NUMBER(h))))
+
+#define H_SET_VERSION(h,v) ((h)->header.a_info = \
+ ((H_GET_DYNAMIC(h) << 31) \
+ | ((v) << 24) \
+ | (H_GET_MACHTYPE(h) << 16) \
+ | (H_GET_MAGIC_NUMBER(h))))
+
+#define H_SET_MACHTYPE(h,v) ((h)->header.a_info = \
+ ((H_GET_DYNAMIC(h) << 31) \
+ | (H_GET_VERSION(h) << 24) \
+ | ((v) << 16) \
+ | (H_GET_MAGIC_NUMBER(h))))
+
+#define H_SET_MAGIC_NUMBER(h,v) ((h)->header.a_info = \
+ ((H_GET_DYNAMIC(h) << 31) \
+ | (H_GET_VERSION(h) << 24) \
+ | (H_GET_MACHTYPE(h) << 16) \
+ | ((v))))
+#define H_SET_INFO(h,mag,mid,f,v) ((h)->header.a_info = \
+ ((((f)==0x20) << 31) \
+ | ((v) << 24) \
+ | ((mid) << 16) \
+ | ((mag))) )
+#endif /* FREEBSD_AOUT || NETBSD_AOUT */
+
+#define H_SET_TEXT_SIZE(h,v) ((h)->header.a_text = md_section_align(SEG_TEXT, (v)))
+#define H_SET_DATA_SIZE(h,v) ((h)->header.a_data = md_section_align(SEG_DATA, (v)))
+#define H_SET_BSS_SIZE(h,v) ((h)->header.a_bss = md_section_align(SEG_BSS, (v)))
+
+#define H_SET_RELOCATION_SIZE(h,t,d) (H_SET_TEXT_RELOCATION_SIZE((h),(t)),\
+ H_SET_DATA_RELOCATION_SIZE((h),(d)))
+
+#define H_SET_TEXT_RELOCATION_SIZE(h,v) ((h)->header.a_trsize = (v))
+#define H_SET_DATA_RELOCATION_SIZE(h,v) ((h)->header.a_drsize = (v))
+#define H_SET_SYMBOL_TABLE_SIZE(h,v) ((h)->header.a_syms = (v) * \
+ sizeof(struct nlist))
+
+#define H_SET_ENTRY_POINT(h,v) ((h)->header.a_entry = (v))
+#define H_SET_STRING_SIZE(h,v) ((h)->string_table_size = (v))
+
+/*
+ * Current means for getting the name of a segment.
+ * This will change for infinite-segments support (e.g. COFF).
+ */
+#define segment_name(seg) (seg_name[(int)(seg)])
+extern char *const seg_name[];
+
+typedef struct {
+ struct exec header; /* a.out header */
+ long string_table_size; /* names + '\0' + sizeof(int) */
+} object_headers;
+
+/* line numbering stuff. */
+#define OBJ_EMIT_LINENO(a, b, c) {;}
+
+#define obj_symbol_new_hook(s) {;}
+
+#if __STDC__ == 1
+struct fix;
+void tc_aout_fix_to_chars(char *where, struct fix *fixP, relax_addressT segment_address);
+#else /* not __STDC__ */
+void tc_aout_fix_to_chars();
+#endif /* not __STDC__ */
+
+/*
+ * Local Variables:
+ * comment-column: 0
+ * fill-column: 131
+ * End:
+ */
+
+/* end of obj-aout.h */
diff --git a/gnu/usr.bin/as/config/obj-bfd-sunos.c b/gnu/usr.bin/as/config/obj-bfd-sunos.c
new file mode 100644
index 0000000..6db63de5
--- /dev/null
+++ b/gnu/usr.bin/as/config/obj-bfd-sunos.c
@@ -0,0 +1,71 @@
+/* obj-bfd-sunos.c
+ Copyright (C) 1987, 1992 Free Software Foundation, Inc.
+
+ This file is part of GAS, the GNU Assembler.
+
+ GAS is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GAS is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GAS; see the file COPYING. If not, write to
+ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+
+#include "as.h"
+
+static
+
+ const short seg_N_TYPE[] = {
+ N_ABS,
+ N_TEXT,
+ N_DATA,
+ N_BSS,
+ N_UNDF, /* unknown */
+ N_UNDF, /* absent */
+ N_UNDF, /* pass1 */
+ N_UNDF, /* error */
+ N_UNDF, /* bignum/flonum */
+ N_UNDF, /* difference */
+ N_REGISTER, /* register */
+ };
+
+const segT N_TYPE_seg[N_TYPE+2] = { /* N_TYPE == 0x1E = 32-2 */
+ SEG_UNKNOWN, /* N_UNDF == 0 */
+ SEG_GOOF,
+ SEG_ABSOLUTE, /* N_ABS == 2 */
+ SEG_GOOF,
+ SEG_TEXT, /* N_TEXT == 4 */
+ SEG_GOOF,
+ SEG_DATA, /* N_DATA == 6 */
+ SEG_GOOF,
+ SEG_BSS, /* N_BSS == 8 */
+ SEG_GOOF,
+ SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF,
+ SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF,
+ SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF,
+ SEG_REGISTER, /* dummy N_REGISTER for regs = 30 */
+ SEG_GOOF,
+};
+
+
+void obj_symbol_new_hook(symbolP)
+symbolS *symbolP;
+{
+ return;
+} /* obj_symbol_new_hook() */
+
+/*
+ * Local Variables:
+ * comment-column: 0
+ * fill-column: 131
+ * End:
+ */
+
+/* end of obj-bfd-sunos.c */
diff --git a/gnu/usr.bin/as/config/obj-bfd-sunos.h b/gnu/usr.bin/as/config/obj-bfd-sunos.h
new file mode 100644
index 0000000..122594e
--- /dev/null
+++ b/gnu/usr.bin/as/config/obj-bfd-sunos.h
@@ -0,0 +1,69 @@
+/*
+ Copyright (C) 1987, 1992 Free Software Foundation, Inc.
+
+ This file is part of GAS, the GNU Assembler.
+
+ GAS is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GAS is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GAS; see the file COPYING. If not, write to
+ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/*
+ * This file is obj-bfd-sunos.h.
+ */
+
+/* define an obj specific macro off which target cpu back ends may key. */
+#define OBJ_BFD
+#define OBJ_BFD_SUNOS
+
+#include "bfd.h"
+
+/* include whatever target cpu is appropriate. */
+#include "targ-cpu.h"
+
+/*
+ * SYMBOLS
+ */
+
+/*
+ * If your object format needs to reorder symbols, define this. When
+ * defined, symbols are kept on a doubly linked list and functions are
+ * made available for push, insert, append, and delete. If not defined,
+ * symbols are kept on a singly linked list, only the append and clear
+ * facilities are available, and they are macros.
+ */
+
+/* #define SYMBOLS_NEED_PACKPOINTERS */
+
+typedef asymbol obj_symbol_type;
+typedef void *object_headers;
+
+#define S_SET_NAME(s, v) ((s)->sy_symbol.name = (v))
+#define S_GET_NAME(s) ((s)->sy_symbol.name)
+#define S_SET_SEGMENT(s,v) ((s)->sy_symbol.udata = (v))
+#define S_GET_SEGMENT(s) ((s)->sy_symbol.udata)
+#define S_SET_EXTERNAL(s) ((s)->sy_symbol.flags |= BSF_GLOBAL)
+#define S_SET_VALUE(s,v) ((s)->sy_symbol.value = (v))
+#define S_GET_VALUE(s) ((s)->sy_symbol.value)
+#define S_IS_DEFINED(s) (!((s)->sy_symbol.flags & BSF_UNDEFINED))
+
+#define DEFAULT_MAGIC_NUMBER_FOR_OBJECT_FILE (0) /* your magic number */
+#define OBJ_EMIT_LINENO(a,b,c) /* must be *something*. This no-op's it out. */
+
+/*
+ * Local Variables:
+ * comment-column: 0
+ * fill-column: 131
+ * End:
+ */
+
+/* end of obj-bfd-sunos.h */
diff --git a/gnu/usr.bin/as/config/obj-bout.c b/gnu/usr.bin/as/config/obj-bout.c
new file mode 100644
index 0000000..734f3a3
--- /dev/null
+++ b/gnu/usr.bin/as/config/obj-bout.c
@@ -0,0 +1,476 @@
+/* b.out object file format
+ Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
+
+ This file is part of GAS, the GNU Assembler.
+
+ GAS is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2,
+ or (at your option) any later version.
+
+ GAS is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+ the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public
+ License along with GAS; see the file COPYING. If not, write
+ to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "as.h"
+#include "obstack.h"
+
+#ifndef NO_LISTING
+#include "aout/stab_gnu.h"
+#endif /* NO_LISTING */
+
+const short /* in: segT out: N_TYPE bits */
+ seg_N_TYPE[] = {
+ N_ABS,
+ N_TEXT,
+ N_DATA,
+ N_BSS,
+ N_UNDF, /* unknown */
+ N_UNDF, /* absent */
+ N_UNDF, /* pass1 */
+ N_UNDF, /* error */
+ N_UNDF, /* bignum/flonum */
+ N_UNDF, /* difference */
+ N_REGISTER, /* register */
+ };
+
+const segT N_TYPE_seg[N_TYPE+2] = { /* N_TYPE == 0x1E = 32-2 */
+ SEG_UNKNOWN, /* N_UNDF == 0 */
+ SEG_GOOF,
+ SEG_ABSOLUTE, /* N_ABS == 2 */
+ SEG_GOOF,
+ SEG_TEXT, /* N_TEXT == 4 */
+ SEG_GOOF,
+ SEG_DATA, /* N_DATA == 6 */
+ SEG_GOOF,
+ SEG_BSS, /* N_BSS == 8 */
+ SEG_GOOF,
+ SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF,
+ SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF,
+ SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF,
+ SEG_REGISTER, /* dummy N_REGISTER for regs = 30 */
+ SEG_GOOF,
+};
+
+#if __STDC__ == 1
+static void obj_bout_stab(int what);
+static void obj_bout_line(void);
+static void obj_bout_desc(void);
+#else /* not __STDC__ */
+static void obj_bout_desc();
+static void obj_bout_stab();
+static void obj_bout_line();
+#endif /* not __STDC__ */
+
+const pseudo_typeS obj_pseudo_table[] = {
+ /* stabs (aka a.out aka b.out directives for debug symbols) */
+ { "desc", obj_bout_desc, 0 }, /* def */
+ { "line", obj_bout_line, 0 }, /* source code line number */
+ { "stabd", obj_bout_stab, 'd' }, /* stabs */
+ { "stabn", obj_bout_stab, 'n' }, /* stabs */
+ { "stabs", obj_bout_stab, 's' }, /* stabs */
+
+ /* coff debugging directives. Currently ignored silently */
+ { "def", s_ignore, 0 },
+ { "dim", s_ignore, 0 },
+ { "endef", s_ignore, 0 },
+ { "ln", s_ignore, 0 },
+ { "scl", s_ignore, 0 },
+ { "size", s_ignore, 0 },
+ { "tag", s_ignore, 0 },
+ { "type", s_ignore, 0 },
+ { "val", s_ignore, 0 },
+
+ /* other stuff we don't handle */
+ { "ABORT", s_ignore, 0 },
+ { "ident", s_ignore, 0 },
+
+ { NULL} /* end sentinel */
+}; /* obj_pseudo_table */
+
+/* Relocation. */
+
+/*
+ * emit_relocations()
+ *
+ * Crawl along a fixS chain. Emit the segment's relocations.
+ */
+void obj_emit_relocations(where, fixP, segment_address_in_file)
+char **where;
+fixS *fixP; /* Fixup chain for this segment. */
+relax_addressT segment_address_in_file;
+{
+ for (; fixP; fixP = fixP->fx_next) {
+ if (fixP->fx_addsy != NULL) {
+ tc_bout_fix_to_chars(*where, fixP, segment_address_in_file);
+ *where += sizeof(struct relocation_info);
+ } /* if there's a symbol */
+ } /* for each fixup */
+
+} /* emit_relocations() */
+
+/* Aout file generation & utilities */
+
+/* Convert a lvalue to machine dependent data */
+void obj_header_append(where, headers)
+char **where;
+object_headers *headers;
+{
+ /* Always leave in host byte order */
+
+ headers->header.a_talign = section_alignment[SEG_TEXT];
+
+ if (headers->header.a_talign < 2){
+ headers->header.a_talign = 2;
+ } /* force to at least 2 */
+
+ headers->header.a_dalign = section_alignment[SEG_DATA];
+ headers->header.a_balign = section_alignment[SEG_BSS];
+
+ headers->header.a_tload = 0;
+ headers->header.a_dload = md_section_align(SEG_DATA, H_GET_TEXT_SIZE(headers));
+
+ append(where, (char *) &headers->header, sizeof(headers->header));
+} /* a_header_append() */
+
+void obj_symbol_to_chars(where, symbolP)
+char **where;
+symbolS *symbolP;
+{
+ /* leave in host byte order */
+ append(where, (char *)&symbolP->sy_symbol, sizeof(obj_symbol_type));
+} /* obj_symbol_to_chars() */
+
+void obj_emit_symbols(where, symbol_rootP)
+char **where;
+symbolS *symbol_rootP;
+{
+ symbolS * symbolP;
+
+ /*
+ * Emit all symbols left in the symbol chain.
+ */
+ for (symbolP = symbol_rootP; symbolP; symbolP = symbol_next(symbolP)) {
+ /* Used to save the offset of the name. It is used to point
+ to the string in memory but must be a file offset. */
+ char *temp;
+
+ temp = S_GET_NAME(symbolP);
+ S_SET_OFFSET(symbolP, symbolP->sy_name_offset);
+
+ /* Any symbol still undefined and is not a dbg symbol is made N_EXT. */
+ if (!S_IS_DEBUG(symbolP) && !S_IS_DEFINED(symbolP)) S_SET_EXTERNAL(symbolP);
+
+ obj_symbol_to_chars(where, symbolP);
+ S_SET_NAME(symbolP,temp);
+ }
+} /* emit_symbols() */
+
+void obj_symbol_new_hook(symbolP)
+symbolS *symbolP;
+{
+ S_SET_OTHER(symbolP, 0);
+ S_SET_DESC(symbolP, 0);
+ return;
+} /* obj_symbol_new_hook() */
+
+static void obj_bout_line() {
+ /* Assume delimiter is part of expression. */
+ /* BSD4.2 as fails with delightful bug, so we */
+ /* are not being incompatible here. */
+ new_logical_line ((char *)NULL, (int)(get_absolute_expression ()));
+ demand_empty_rest_of_line();
+} /* obj_bout_line() */
+
+/*
+ * stab()
+ *
+ * Handle .stabX directives, which used to be open-coded.
+ * So much creeping featurism overloaded the semantics that we decided
+ * to put all .stabX thinking in one place. Here.
+ *
+ * We try to make any .stabX directive legal. Other people's AS will often
+ * do assembly-time consistency checks: eg assigning meaning to n_type bits
+ * and "protecting" you from setting them to certain values. (They also zero
+ * certain bits before emitting symbols. Tut tut.)
+ *
+ * If an expression is not absolute we either gripe or use the relocation
+ * information. Other people's assemblers silently forget information they
+ * don't need and invent information they need that you didn't supply.
+ *
+ * .stabX directives always make a symbol table entry. It may be junk if
+ * the rest of your .stabX directive is malformed.
+ */
+static void obj_bout_stab(what)
+int what;
+{
+ register symbolS * symbolP = 0;
+ register char * string;
+ int saved_type = 0;
+ int length;
+ int goof; /* TRUE if we have aborted. */
+ long longint;
+
+ /*
+ * Enter with input_line_pointer pointing past .stabX and any following
+ * whitespace.
+ */
+ goof = 0; /* JF who forgot this?? */
+ if (what == 's') {
+ string = demand_copy_C_string(& length);
+ SKIP_WHITESPACE();
+ if (*input_line_pointer == ',')
+ input_line_pointer ++;
+ else {
+ as_bad("I need a comma after symbol's name");
+ goof = 1;
+ }
+ } else
+ string = "";
+
+ /*
+ * Input_line_pointer->after ','. String->symbol name.
+ */
+ if (!goof) {
+ symbolP = symbol_new(string,
+ SEG_UNKNOWN,
+ 0,
+ (struct frag *)0);
+ switch (what) {
+ case 'd':
+ S_SET_NAME(symbolP,NULL); /* .stabd feature. */
+ S_SET_VALUE(symbolP,obstack_next_free(&frags) -
+ frag_now->fr_literal);
+ symbolP->sy_frag = frag_now;
+ break;
+
+ case 'n':
+ symbolP->sy_frag = &zero_address_frag;
+ break;
+
+ case 's':
+ symbolP->sy_frag = & zero_address_frag;
+ break;
+
+ default:
+ BAD_CASE(what);
+ break;
+ }
+ if (get_absolute_expression_and_terminator(& longint) == ',')
+ symbolP->sy_symbol.n_type = saved_type = longint;
+ else {
+ as_bad("I want a comma after the n_type expression");
+ goof = 1;
+ input_line_pointer--; /* Backup over a non-',' char. */
+ }
+ }
+ if (! goof) {
+ if (get_absolute_expression_and_terminator (& longint) == ',')
+ S_SET_OTHER(symbolP,longint);
+ else {
+ as_bad("I want a comma after the n_other expression");
+ goof = 1;
+ input_line_pointer--; /* Backup over a non-',' char. */
+ }
+ }
+ if (! goof) {
+ S_SET_DESC(symbolP, get_absolute_expression ());
+ if (what == 's' || what == 'n') {
+ if (* input_line_pointer != ',') {
+ as_bad("I want a comma after the n_desc expression");
+ goof = 1;
+ } else {
+ input_line_pointer ++;
+ }
+ }
+ }
+ if ((!goof) && (what == 's' || what == 'n')) {
+ pseudo_set(symbolP);
+ symbolP->sy_symbol.n_type = saved_type;
+ }
+#ifndef NO_LISTING
+ {
+ extern int listing;
+
+ if (listing && !goof) {
+ if (symbolP->sy_symbol.n_type == N_SLINE) {
+
+ listing_source_line(symbolP->sy_symbol.n_desc);
+ } else if (symbolP->sy_symbol.n_type == N_SO
+ || symbolP->sy_symbol.n_type == N_SOL) {
+ listing_source_file(string);
+ }
+ }
+ }
+
+#endif
+
+ if (goof)
+ ignore_rest_of_line ();
+ else
+ demand_empty_rest_of_line ();
+} /* obj_bout_stab() */
+
+static void obj_bout_desc() {
+ register char *name;
+ register char c;
+ register char *p;
+ register symbolS * symbolP;
+ register int temp;
+
+ /*
+ * Frob invented at RMS' request. Set the n_desc of a symbol.
+ */
+ name = input_line_pointer;
+ c = get_symbol_end();
+ p = input_line_pointer;
+ * p = c;
+ SKIP_WHITESPACE();
+ if (*input_line_pointer != ',') {
+ *p = 0;
+ as_bad("Expected comma after name \"%s\"", name);
+ *p = c;
+ ignore_rest_of_line();
+ } else {
+ input_line_pointer ++;
+ temp = get_absolute_expression ();
+ *p = 0;
+ symbolP = symbol_find_or_make(name);
+ *p = c;
+ S_SET_DESC(symbolP,temp);
+ }
+ demand_empty_rest_of_line();
+} /* obj_bout_desc() */
+
+void obj_read_begin_hook() {
+ return;
+} /* obj_read_begin_hook() */
+
+void obj_crawl_symbol_chain(headers)
+object_headers *headers;
+{
+ symbolS **symbolPP;
+ symbolS *symbolP;
+ int symbol_number = 0;
+
+ /* JF deal with forward references first... */
+ for (symbolP = symbol_rootP; symbolP; symbolP = symbol_next(symbolP)) {
+ if (symbolP->sy_forward) {
+ S_SET_VALUE(symbolP, S_GET_VALUE(symbolP)
+ + S_GET_VALUE(symbolP->sy_forward)
+ + symbolP->sy_forward->sy_frag->fr_address);
+
+ symbolP->sy_forward=0;
+ } /* if it has a forward reference */
+ } /* walk the symbol chain */
+
+ tc_crawl_symbol_chain(headers);
+
+ symbolPP = & symbol_rootP; /*->last symbol chain link. */
+ while ((symbolP = *symbolPP) != NULL) {
+ if (flagseen['R'] && (S_GET_SEGMENT(symbolP) == SEG_DATA)) {
+ S_SET_SEGMENT(symbolP, SEG_TEXT);
+ } /* if pusing data into text */
+
+ S_SET_VALUE(symbolP, S_GET_VALUE(symbolP) + symbolP->sy_frag->fr_address);
+
+ /* OK, here is how we decide which symbols go out into the
+ brave new symtab. Symbols that do are:
+
+ * symbols with no name (stabd's?)
+ * symbols with debug info in their N_TYPE
+
+ Symbols that don't are:
+ * symbols that are registers
+ * symbols with \1 as their 3rd character (numeric labels)
+ * "local labels" as defined by S_LOCAL_NAME(name)
+ if the -L switch was passed to gas.
+
+ All other symbols are output. We complain if a deleted
+ symbol was marked external. */
+
+
+ if (1
+ && !S_IS_REGISTER(symbolP)
+ && (!S_GET_NAME(symbolP)
+ || S_IS_DEBUG(symbolP)
+#ifdef TC_I960
+ /* FIXME-SOON this ifdef seems highly dubious to me. xoxorich. */
+ || !S_IS_DEFINED(symbolP)
+ || S_IS_EXTERNAL(symbolP)
+#endif /* TC_I960 */
+ || (S_GET_NAME(symbolP)[0] != '\001' && (flagseen['L'] || ! S_LOCAL_NAME(symbolP))))) {
+ symbolP->sy_number = symbol_number++;
+
+ /* The + 1 after strlen account for the \0 at the
+ end of each string */
+ if (!S_IS_STABD(symbolP)) {
+ /* Ordinary case. */
+ symbolP->sy_name_offset = string_byte_count;
+ string_byte_count += strlen(S_GET_NAME(symbolP)) + 1;
+ }
+ else /* .Stabd case. */
+ symbolP->sy_name_offset = 0;
+ symbolPP = &(symbol_next(symbolP));
+ } else {
+ if (S_IS_EXTERNAL(symbolP) || !S_IS_DEFINED(symbolP)) {
+ as_bad("Local symbol %s never defined", S_GET_NAME(symbolP));
+ } /* oops. */
+
+ /* Unhook it from the chain */
+ *symbolPP = symbol_next(symbolP);
+ } /* if this symbol should be in the output */
+ } /* for each symbol */
+
+ H_SET_SYMBOL_TABLE_SIZE(headers, symbol_number);
+
+ return;
+} /* obj_crawl_symbol_chain() */
+
+/*
+ * Find strings by crawling along symbol table chain.
+ */
+
+void obj_emit_strings(where)
+char **where;
+{
+ symbolS *symbolP;
+
+#ifdef CROSS_COMPILE
+ /* Gotta do md_ byte-ordering stuff for string_byte_count first - KWK */
+ md_number_to_chars(*where, string_byte_count, sizeof(string_byte_count));
+ *where += sizeof(string_byte_count);
+#else /* CROSS_COMPILE */
+ append(where, (char *) &string_byte_count, (unsigned long) sizeof(string_byte_count));
+#endif /* CROSS_COMPILE */
+
+ for (symbolP = symbol_rootP; symbolP; symbolP = symbol_next(symbolP)) {
+ if (S_GET_NAME(symbolP))
+ append(where, S_GET_NAME(symbolP), (unsigned long)(strlen (S_GET_NAME(symbolP)) + 1));
+ } /* walk symbol chain */
+
+ return;
+} /* obj_emit_strings() */
+
+void obj_pre_write_hook(headers)
+object_headers *headers;
+{
+ H_SET_MAGIC_NUMBER(headers, BMAGIC);
+ H_SET_ENTRY_POINT(headers, 0);
+
+ return;
+} /* obj_pre_write_hook() */
+
+/*
+ * Local Variables:
+ * comment-column: 0
+ * fill-column: 131
+ * End:
+ */
+
+/* end of obj-bout.c */
diff --git a/gnu/usr.bin/as/config/obj-bout.h b/gnu/usr.bin/as/config/obj-bout.h
new file mode 100644
index 0000000..6de818a
--- /dev/null
+++ b/gnu/usr.bin/as/config/obj-bout.h
@@ -0,0 +1,313 @@
+/* b.out object file format
+ Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
+
+ This file is part of GAS, the GNU Assembler.
+
+ GAS is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2,
+ or (at your option) any later version.
+
+ GAS is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+ the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public
+ License along with GAS; see the file COPYING. If not, write
+ to the Free Software Foundation, 675 Mass Ave, Cambridge, MA
+ 02139, USA. */
+
+/*
+ * This file is a modified version of 'a.out.h'. It is to be used in all GNU
+ * tools modified to support the i80960 b.out format (or tools that operate on
+ * object files created by such tools).
+ *
+ * All i80960 development is done in a CROSS-DEVELOPMENT environment. I.e.,
+ * object code is generated on, and executed under the direction of a symbolic
+ * debugger running on, a host system. We do not want to be subject to the
+ * vagaries of which host it is or whether it supports COFF or a.out format, or
+ * anything else. We DO want to:
+ *
+ * o always generate the same format object files, regardless of host.
+ *
+ * o have an 'a.out' header that we can modify for our own purposes
+ * (the 80960 is typically an embedded processor and may require
+ * enhanced linker support that the normal a.out.h header can't
+ * accommodate).
+ *
+ * As for byte-ordering, the following rules apply:
+ *
+ * o Text and data that is actually downloaded to the target is always
+ * in i80960 (little-endian) order.
+ *
+ * o All other numbers (in the header, symbols, relocation directives)
+ * are in host byte-order: object files CANNOT be lifted from a
+ * little-end host and used on a big-endian (or vice versa) without
+ * modification.
+ *
+ * o The downloader ('comm960') takes care to generate a pseudo-header
+ * with correct (i80960) byte-ordering before shipping text and data
+ * off to the NINDY monitor in the target systems. Symbols and
+ * relocation info are never sent to the target.
+ */
+
+
+#define OBJ_BOUT 1
+
+#include "targ-cpu.h"
+
+/* bout uses host byte order for headers */
+#ifdef CROSS_COMPILE
+#undef CROSS_COMPILE
+#endif /* CROSS_COMPILE */
+
+/* We want \v. */
+#define BACKSLASH_V 1
+
+#define OBJ_DEFAULT_OUTPUT_FILE_NAME "b.out"
+
+extern const short seg_N_TYPE[];
+extern const segT N_TYPE_seg[];
+
+#define BMAGIC 0415
+/* We don't accept the following (see N_BADMAG macro).
+ * They're just here so GNU code will compile.
+ */
+#define OMAGIC 0407 /* old impure format */
+#define NMAGIC 0410 /* read-only text */
+#define ZMAGIC 0413 /* demand load format */
+
+/* FILE HEADER
+ * All 'lengths' are given as a number of bytes.
+ * All 'alignments' are for relinkable files only; an alignment of
+ * 'n' indicates the corresponding segment must begin at an
+ * address that is a multiple of (2**n).
+ */
+struct exec {
+ /* Standard stuff */
+ unsigned long a_magic; /* Identifies this as a b.out file */
+ unsigned long a_text; /* Length of text */
+ unsigned long a_data; /* Length of data */
+ unsigned long a_bss; /* Length of runtime uninitialized data area */
+ unsigned long a_syms; /* Length of symbol table */
+ unsigned long a_entry; /* Runtime start address */
+ unsigned long a_trsize; /* Length of text relocation info */
+ unsigned long a_drsize; /* Length of data relocation info */
+
+ /* Added for i960 */
+ unsigned long a_tload; /* Text runtime load address */
+ unsigned long a_dload; /* Data runtime load address */
+ unsigned char a_talign; /* Alignment of text segment */
+ unsigned char a_dalign; /* Alignment of data segment */
+ unsigned char a_balign; /* Alignment of bss segment */
+ unsigned char unused; /* (Just to make struct size a multiple of 4) */
+};
+
+#define N_BADMAG(x) (((x).a_magic) != BMAGIC)
+#define N_TXTOFF(x) ( sizeof(struct exec) )
+#define N_DATOFF(x) ( N_TXTOFF(x) + (x).a_text )
+#define N_TROFF(x) ( N_DATOFF(x) + (x).a_data )
+#define N_DROFF(x) ( N_TROFF(x) + (x).a_trsize )
+#define N_SYMOFF(x) ( N_DROFF(x) + (x).a_drsize )
+#define N_STROFF(x) ( N_SYMOFF(x) + (x).a_syms )
+
+/* A single entry in the symbol table
+ */
+struct nlist {
+ union {
+ char *n_name;
+ struct nlist *n_next;
+ long n_strx; /* Index into string table */
+ } n_un;
+ unsigned char n_type; /* See below */
+ char n_other; /* Used in i80960 support -- see below */
+ short n_desc;
+ unsigned long n_value;
+};
+
+typedef struct nlist obj_symbol_type;
+
+/* Legal values of n_type
+ */
+#define N_UNDF 0 /* Undefined symbol */
+#define N_ABS 2 /* Absolute symbol */
+#define N_TEXT 4 /* Text symbol */
+#define N_DATA 6 /* Data symbol */
+#define N_BSS 8 /* BSS symbol */
+#define N_FN 31 /* Filename symbol */
+
+#define N_EXT 1 /* External symbol (OR'd in with one of above) */
+#define N_TYPE 036 /* Mask for all the type bits */
+#define N_STAB 0340 /* Mask for all bits used for SDB entries */
+
+#ifndef CUSTOM_RELOC_FORMAT
+struct relocation_info {
+ int r_address; /* File address of item to be relocated */
+ unsigned
+ r_index:24,/* Index of symbol on which relocation is based*/
+ r_pcrel:1, /* 1 => relocate PC-relative; else absolute
+ * On i960, pc-relative implies 24-bit
+ * address, absolute implies 32-bit.
+ */
+ r_length:2, /* Number of bytes to relocate:
+ * 0 => 1 byte
+ * 1 => 2 bytes
+ * 2 => 4 bytes -- only value used for i960
+ */
+ r_extern:1,
+ r_bsr:1, /* Something for the GNU NS32K assembler */
+ r_disp:1, /* Something for the GNU NS32K assembler */
+ r_callj:1, /* 1 if relocation target is an i960 'callj' */
+ nuthin:1; /* Unused */
+};
+#endif /* CUSTOM_RELOC_FORMAT */
+
+/*
+ * Macros to extract information from a symbol table entry.
+ * This syntaxic indirection allows independence regarding a.out or coff.
+ * The argument (s) of all these macros is a pointer to a symbol table entry.
+ */
+
+/* Predicates */
+/* True if the symbol is external */
+#define S_IS_EXTERNAL(s) ((s)->sy_symbol.n_type & N_EXT)
+
+/* True if symbol has been defined, ie is in N_{TEXT,DATA,BSS,ABS} or N_EXT */
+#define S_IS_DEFINED(s) ((S_GET_TYPE(s) != N_UNDF) || (S_GET_DESC(s) != 0))
+#define S_IS_REGISTER(s) ((s)->sy_symbol.n_type == N_REGISTER)
+
+/* True if a debug special symbol entry */
+#define S_IS_DEBUG(s) ((s)->sy_symbol.n_type & N_STAB)
+/* True if a symbol is local symbol name */
+/* A symbol name whose name begin with ^A is a gas internal pseudo symbol
+ nameless symbols come from .stab directives. */
+#define S_IS_LOCAL(s) (S_GET_NAME(s) && \
+ !S_IS_DEBUG(s) && \
+ (S_GET_NAME(s)[0] == '\001' || \
+ (S_LOCAL_NAME(s) && !flagseen['L'])))
+/* True if a symbol is not defined in this file */
+#define S_IS_EXTERN(s) ((s)->sy_symbol.n_type & N_EXT)
+/* True if the symbol has been generated because of a .stabd directive */
+#define S_IS_STABD(s) (S_GET_NAME(s) == NULL)
+
+/* Accessors */
+/* The value of the symbol */
+#define S_GET_VALUE(s) ((unsigned long) ((s)->sy_symbol.n_value))
+/* The name of the symbol */
+#define S_GET_NAME(s) ((s)->sy_symbol.n_un.n_name)
+/* The pointer to the string table */
+#define S_GET_OFFSET(s) ((s)->sy_symbol.n_un.n_strx)
+/* The type of the symbol */
+#define S_GET_TYPE(s) ((s)->sy_symbol.n_type & N_TYPE)
+/* The numeric value of the segment */
+#define S_GET_SEGMENT(s) (N_TYPE_seg[S_GET_TYPE(s)])
+/* The n_other expression value */
+#define S_GET_OTHER(s) ((s)->sy_symbol.n_other)
+/* The n_desc expression value */
+#define S_GET_DESC(s) ((s)->sy_symbol.n_desc)
+
+/* Modifiers */
+/* Set the value of the symbol */
+#define S_SET_VALUE(s,v) ((s)->sy_symbol.n_value = (unsigned long) (v))
+/* Assume that a symbol cannot be simultaneously in more than on segment */
+/* set segment */
+#define S_SET_SEGMENT(s,seg) ((s)->sy_symbol.n_type &= ~N_TYPE,(s)->sy_symbol.n_type|=SEGMENT_TO_SYMBOL_TYPE(seg))
+/* The symbol is external */
+#define S_SET_EXTERNAL(s) ((s)->sy_symbol.n_type |= N_EXT)
+/* The symbol is not external */
+#define S_CLEAR_EXTERNAL(s) ((s)->sy_symbol.n_type &= ~N_EXT)
+/* Set the name of the symbol */
+#define S_SET_NAME(s,v) ((s)->sy_symbol.n_un.n_name = (v))
+/* Set the offset in the string table */
+#define S_SET_OFFSET(s,v) ((s)->sy_symbol.n_un.n_strx = (v))
+/* Set the n_other expression value */
+#define S_SET_OTHER(s,v) ((s)->sy_symbol.n_other = (v))
+/* Set the n_desc expression value */
+#define S_SET_DESC(s,v) ((s)->sy_symbol.n_desc = (v))
+
+/* File header macro and type definition */
+
+#define H_GET_FILE_SIZE(h) (sizeof(struct exec) + \
+ H_GET_TEXT_SIZE(h) + H_GET_DATA_SIZE(h) + \
+ H_GET_SYMBOL_TABLE_SIZE(h) + \
+ H_GET_TEXT_RELOCATION_SIZE(h) + \
+ H_GET_DATA_RELOCATION_SIZE(h) + \
+ (h)->string_table_size)
+
+#define H_GET_HEADER_SIZE(h) (sizeof(struct exec))
+#define H_GET_TEXT_SIZE(h) ((h)->header.a_text)
+#define H_GET_DATA_SIZE(h) ((h)->header.a_data)
+#define H_GET_BSS_SIZE(h) ((h)->header.a_bss)
+#define H_GET_TEXT_RELOCATION_SIZE(h) ((h)->header.a_trsize)
+#define H_GET_DATA_RELOCATION_SIZE(h) ((h)->header.a_drsize)
+#define H_GET_SYMBOL_TABLE_SIZE(h) ((h)->header.a_syms)
+#define H_GET_MAGIC_NUMBER(h) ((h)->header.a_info)
+#define H_GET_ENTRY_POINT(h) ((h)->header.a_entry)
+#define H_GET_STRING_SIZE(h) ((h)->string_table_size)
+#define H_GET_LINENO_SIZE(h) (0)
+
+#ifdef EXEC_MACHINE_TYPE
+#define H_GET_MACHINE_TYPE(h) ((h)->header.a_machtype)
+#endif /* EXEC_MACHINE_TYPE */
+#ifdef EXEC_VERSION
+#define H_GET_VERSION(h) ((h)->header.a_version)
+#endif /* EXEC_VERSION */
+
+#define H_SET_TEXT_SIZE(h,v) ((h)->header.a_text = (v))
+#define H_SET_DATA_SIZE(h,v) ((h)->header.a_data = (v))
+#define H_SET_BSS_SIZE(h,v) ((h)->header.a_bss = (v))
+
+#define H_SET_RELOCATION_SIZE(h,t,d) (H_SET_TEXT_RELOCATION_SIZE((h),(t)),\
+ H_SET_DATA_RELOCATION_SIZE((h),(d)))
+
+#define H_SET_TEXT_RELOCATION_SIZE(h,v) ((h)->header.a_trsize = (v))
+#define H_SET_DATA_RELOCATION_SIZE(h,v) ((h)->header.a_drsize = (v))
+#define H_SET_SYMBOL_TABLE_SIZE(h,v) ((h)->header.a_syms = (v) * \
+ sizeof(struct nlist))
+
+#define H_SET_MAGIC_NUMBER(h,v) ((h)->header.a_magic = (v))
+
+#define H_SET_ENTRY_POINT(h,v) ((h)->header.a_entry = (v))
+#define H_SET_STRING_SIZE(h,v) ((h)->string_table_size = (v))
+#ifdef EXEC_MACHINE_TYPE
+#define H_SET_MACHINE_TYPE(h,v) ((h)->header.a_machtype = (v))
+#endif /* EXEC_MACHINE_TYPE */
+#ifdef EXEC_VERSION
+#define H_SET_VERSION(h,v) ((h)->header.a_version = (v))
+#endif /* EXEC_VERSION */
+
+/*
+ * Current means for getting the name of a segment.
+ * This will change for infinite-segments support (e.g. COFF).
+ */
+#define segment_name(seg) ( seg_name[(int)(seg)] )
+extern char *const seg_name[];
+
+typedef struct {
+ struct exec header; /* a.out header */
+ long string_table_size; /* names + '\0' + sizeof(int) */
+} object_headers;
+
+/* unused hooks. */
+#define OBJ_EMIT_LINENO(a, b, c) {;}
+
+#if __STDC__
+struct fix;
+void tc_aout_fix_to_chars(char *where, struct fix *fixP, relax_addressT segment_address);
+#else /* not __STDC__ */
+void tc_aout_fix_to_chars();
+#endif /* not __STDC__ */
+
+enum reloc_type {
+ NO_RELOC, RELOC_32,
+};
+
+/*
+ * Local Variables:
+ * comment-column: 0
+ * fill-column: 131
+ * End:
+ */
+
+/* end of obj-bout.h */
diff --git a/gnu/usr.bin/as/config/obj-coff.c b/gnu/usr.bin/as/config/obj-coff.c
new file mode 100644
index 0000000..b57c6cd
--- /dev/null
+++ b/gnu/usr.bin/as/config/obj-coff.c
@@ -0,0 +1,1978 @@
+/* coff object file format
+ Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
+
+ This file is part of GAS.
+
+ GAS is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GAS is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GAS; see the file COPYING. If not, write to
+ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "as.h"
+
+#include "obstack.h"
+
+lineno* lineno_rootP;
+
+const short seg_N_TYPE[] = { /* in: segT out: N_TYPE bits */
+ C_ABS_SECTION,
+ C_TEXT_SECTION,
+ C_DATA_SECTION,
+ C_BSS_SECTION,
+ C_UNDEF_SECTION, /* SEG_UNKNOWN */
+ C_UNDEF_SECTION, /* SEG_ABSENT */
+ C_UNDEF_SECTION, /* SEG_PASS1 */
+ C_UNDEF_SECTION, /* SEG_GOOF */
+ C_UNDEF_SECTION, /* SEG_BIG */
+ C_UNDEF_SECTION, /* SEG_DIFFERENCE */
+ C_DEBUG_SECTION, /* SEG_DEBUG */
+ C_NTV_SECTION, /* SEG_NTV */
+ C_PTV_SECTION, /* SEG_PTV */
+ C_REGISTER_SECTION, /* SEG_REGISTER */
+};
+
+
+/* Add 4 to the real value to get the index and compensate the negatives */
+
+const segT N_TYPE_seg[32] =
+{
+ SEG_PTV, /* C_PTV_SECTION == -4 */
+ SEG_NTV, /* C_NTV_SECTION == -3 */
+ SEG_DEBUG, /* C_DEBUG_SECTION == -2 */
+ SEG_ABSOLUTE, /* C_ABS_SECTION == -1 */
+ SEG_UNKNOWN, /* C_UNDEF_SECTION == 0 */
+ SEG_TEXT, /* C_TEXT_SECTION == 1 */
+ SEG_DATA, /* C_DATA_SECTION == 2 */
+ SEG_BSS, /* C_BSS_SECTION == 3 */
+ SEG_REGISTER, /* C_REGISTER_SECTION == 4 */
+ SEG_GOOF,SEG_GOOF,SEG_GOOF,SEG_GOOF,SEG_GOOF,SEG_GOOF,SEG_GOOF,SEG_GOOF,
+ SEG_GOOF,SEG_GOOF,SEG_GOOF,SEG_GOOF,SEG_GOOF,SEG_GOOF,SEG_GOOF,SEG_GOOF,
+ SEG_GOOF,SEG_GOOF,SEG_GOOF,SEG_GOOF,SEG_GOOF,SEG_GOOF,SEG_GOOF
+ };
+
+#if __STDC__ == 1
+
+char *s_get_name(symbolS *s);
+static symbolS *tag_find_or_make(char *name);
+static symbolS* tag_find(char *name);
+#ifdef BFD_HEADERS
+static void obj_coff_section_header_append(char **where, struct internal_scnhdr *header);
+#else
+static void obj_coff_section_header_append(char **where, SCNHDR *header);
+#endif
+static void obj_coff_def(int what);
+static void obj_coff_dim(void);
+static void obj_coff_endef(void);
+static void obj_coff_line(void);
+static void obj_coff_ln(void);
+static void obj_coff_scl(void);
+static void obj_coff_size(void);
+static void obj_coff_stab(int what);
+static void obj_coff_tag(void);
+static void obj_coff_type(void);
+static void obj_coff_val(void);
+static void tag_init(void);
+static void tag_insert(char *name, symbolS *symbolP);
+
+#else /* not __STDC__ */
+
+char *s_get_name();
+static symbolS *tag_find();
+static symbolS *tag_find_or_make();
+static void obj_coff_section_header_append();
+static void obj_coff_def();
+static void obj_coff_dim();
+static void obj_coff_endef();
+static void obj_coff_line();
+static void obj_coff_ln();
+static void obj_coff_scl();
+static void obj_coff_size();
+static void obj_coff_stab();
+static void obj_coff_tag();
+static void obj_coff_type();
+static void obj_coff_val();
+static void tag_init();
+static void tag_insert();
+
+#endif /* not __STDC__ */
+
+static struct hash_control *tag_hash;
+static symbolS *def_symbol_in_progress = NULL;
+
+const pseudo_typeS obj_pseudo_table[] = {
+#ifndef IGNORE_DEBUG
+ { "def", obj_coff_def, 0 },
+ { "dim", obj_coff_dim, 0 },
+ { "endef", obj_coff_endef, 0 },
+ { "line", obj_coff_line, 0 },
+ { "ln", obj_coff_ln, 0 },
+ { "scl", obj_coff_scl, 0 },
+ { "size", obj_coff_size, 0 },
+ { "tag", obj_coff_tag, 0 },
+ { "type", obj_coff_type, 0 },
+ { "val", obj_coff_val, 0 },
+#else
+ { "def", s_ignore, 0 },
+ { "dim", s_ignore, 0 },
+ { "endef", s_ignore, 0 },
+ { "line", s_ignore, 0 },
+ { "ln", s_ignore, 0 },
+ { "scl", s_ignore, 0 },
+ { "size", s_ignore, 0 },
+ { "tag", s_ignore, 0 },
+ { "type", s_ignore, 0 },
+ { "val", s_ignore, 0 },
+#endif /* ignore debug */
+
+ { "ident", s_ignore, 0 }, /* we don't yet handle this. */
+
+
+ /* stabs aka a.out aka b.out directives for debug symbols.
+ Currently ignored silently. Except for .line at which
+ we guess from context. */
+ { "desc", s_ignore, 0 }, /* def */
+ /* { "line", s_ignore, 0 }, */ /* source code line number */
+ { "stabd", obj_coff_stab, 'd' }, /* stabs */
+ { "stabn", obj_coff_stab, 'n' }, /* stabs */
+ { "stabs", obj_coff_stab, 's' }, /* stabs */
+
+ /* stabs-in-coff (?) debug pseudos (ignored) */
+ { "optim", s_ignore, 0 }, /* For sun386i cc (?) */
+ /* other stuff */
+ { "ABORT", s_abort, 0 },
+
+ { NULL} /* end sentinel */
+}; /* obj_pseudo_table */
+
+
+/* obj dependant output values */
+#ifdef BFD_HEADERS
+static struct internal_scnhdr bss_section_header;
+struct internal_scnhdr data_section_header;
+struct internal_scnhdr text_section_header;
+#else
+static SCNHDR bss_section_header;
+SCNHDR data_section_header;
+SCNHDR text_section_header;
+#endif
+/* Relocation. */
+
+static int reloc_compare(p1, p2)
+#ifdef BFD_HEADERS
+struct internal_reloc *p1, *p2;
+#else
+RELOC *p1, *p2;
+#endif
+{
+ return (int)(p1->r_vaddr - p2->r_vaddr);
+}
+
+/*
+ * emit_relocations()
+ *
+ * Crawl along a fixS chain. Emit the segment's relocations.
+ */
+
+void obj_emit_relocations(where, fixP, segment_address_in_file)
+char **where;
+fixS *fixP; /* Fixup chain for this segment. */
+relax_addressT segment_address_in_file;
+{
+#ifdef BFD_HEADERS
+ struct internal_reloc *ri_table;
+#else
+ RELOC *ri_table;
+#endif
+ symbolS *symbolP;
+ int i, count;
+ fixS *p;
+
+ for (count = 0, p = fixP; p ; p = p->fx_next)
+ if (p->fx_addsy) count++;
+ if (!count)
+ return;
+
+#ifdef BFD_HEADERS
+ ri_table = (struct internal_reloc *) calloc(sizeof(*ri_table),count);
+#else
+ ri_table = (RELOC *) calloc(sizeof(*ri_table),count);
+#endif
+ if (!ri_table)
+ as_fatal ("obj_emit_relocations: Could not malloc relocation table");
+
+#ifdef TC_I960
+ callj_table = (char *)malloc (sizeof(char)*count);
+ if (!callj_table)
+ as_fatal ("obj_emit_relocations: Could not malloc callj table");
+#endif
+
+ for (i = 0; fixP; fixP = fixP->fx_next) {
+ if (symbolP = fixP->fx_addsy) {
+#if defined(TC_M68K)
+ ri_table[i].r_type = (fixP->fx_pcrel ?
+ (fixP->fx_size == 1 ? R_PCRBYTE :
+ fixP->fx_size == 2 ? R_PCRWORD :
+ R_PCRLONG):
+ (fixP->fx_size == 1 ? R_RELBYTE :
+ fixP->fx_size == 2 ? R_RELWORD :
+ R_RELLONG));
+#elif defined(TC_I386)
+ /* FIXME-SOON R_OFF8 & R_DIR16 are a vague guess, completly
+ untested. */
+ ri_table[i].r_type = (fixP->fx_pcrel ?
+ (fixP->fx_size == 1 ? R_PCRBYTE :
+ fixP->fx_size == 2 ? R_PCRWORD :
+ R_PCRLONG):
+ (fixP->fx_size == 1 ? R_OFF8 :
+ fixP->fx_size == 2 ? R_DIR16 :
+ R_DIR32));
+#elif defined(TC_I960)
+ ri_table[i].r_type = (fixP->fx_pcrel
+ ? R_IPRMED
+ : R_RELLONG);
+ callj_table[i] = fixP->fx_callj ? 1 : 0;
+#elif defined(TC_A29K)
+ ri_table[i].r_type = tc_coff_fix2rtype(fixP);
+
+#else
+#error you lose
+#endif /* TC_M68K || TC_I386 */
+ ri_table[i].r_vaddr = (fixP->fx_frag->fr_address
+ + fixP->fx_where);
+ /* If symbol associated to relocation entry is a bss symbol
+ or undefined symbol just remember the index of the symbol.
+ Otherwise store the index of the symbol describing the
+ section the symbol belong to. This heuristic speeds up ld.
+ */
+ /* Local symbols can generate relocation information. In case
+ of structure return for instance. But they have no symbol
+ number because they won't be emitted in the final object.
+ In the case where they are in the BSS section, this leads
+ to an incorrect r_symndx.
+ Under bsd the loader do not care if the symbol reference
+ is incorrect. But the SYS V ld complains about this. To
+ avoid this we associate the symbol to the associated
+ section, *even* if it is the BSS section. */
+ /* If someone can tell me why the other symbols of the bss
+ section are not associated with the .bss section entry,
+ I'd be gratefull. I guess that it has to do with the special
+ nature of the .bss section. Or maybe this is because the
+ bss symbols are declared in the common section and can
+ be resized later. Can it break code some where ? */
+ ri_table[i].r_symndx = (S_GET_SEGMENT(symbolP) == SEG_TEXT
+ ? dot_text_symbol->sy_number
+ : (S_GET_SEGMENT(symbolP) == SEG_DATA
+ ? dot_data_symbol->sy_number
+ : ((SF_GET_LOCAL(symbolP)
+ ? dot_bss_symbol->sy_number
+ : symbolP->sy_number)))); /* bss or undefined */
+
+ /* md_ri_to_chars((char *) &ri, ri); */ /* Last step : write md f */
+
+ i++;
+ } /* if there's a symbol */
+ } /* for each fixP */
+
+ /*
+ * AIX ld prefer to have the reloc table with r_vaddr sorted.
+ * But sorting it should not hurt any other ld.
+ */
+ qsort (ri_table, count, sizeof(*ri_table), reloc_compare);
+
+ for (i = 0; i < count; i++)
+ {
+#ifdef BFD_HEADERS
+ *where += bfd_coff_swap_reloc_out(stdoutput, &ri_table[i], *where);
+# ifdef TC_A29K
+ /* The 29k has a special kludge for the high 16 bit reloc.
+ Two relocations are emmited, R_IHIHALF, and R_IHCONST.
+ The second one doesn't contain a symbol, but uses the
+ value for offset */
+ if (ri_table[i].r_type == R_IHIHALF)
+ {
+ /* now emit the second bit */
+ ri_table[i].r_type = R_IHCONST;
+ ri_table[i].r_symndx = fixP->fx_addnumber;
+ *where += bfd_coff_swap_reloc_out(stdoutput, &ri_table[i],
+ *where);
+ }
+# endif /* TC_A29K */
+
+#else /* not BFD_HEADERS */
+ append(where, (char *) &ri_table[i], RELSZ);
+#endif /* not BFD_HEADERS */
+
+#ifdef TC_I960
+ if (callj_table[i])
+ {
+ ri_table[i].r_type = R_OPTCALL;
+# ifdef BFD_HEADERS
+ *where += bfd_coff_swap_reloc_out(stdoutput, &ri_table[i],
+ *where);
+# else
+ append(where, (char *) &ri_table[i], (unsigned long)RELSZ);
+# endif /* BFD_HEADERS */
+ } /* if it's a callj, do it again for the opcode */
+#endif /* TC_I960 */
+ }
+
+ free (ri_table);
+#ifdef TC_I960
+ free (callj_table);
+#endif
+
+ return;
+} /* obj_emit_relocations() */
+
+/* Coff file generation & utilities */
+
+#ifdef BFD_HEADERS
+void obj_header_append(where, headers)
+char **where;
+object_headers *headers;
+{
+ tc_headers_hook(headers);
+ *where += bfd_coff_swap_filehdr_out(stdoutput, &(headers->filehdr), *where);
+#ifndef OBJ_COFF_OMIT_OPTIONAL_HEADER
+ *where += bfd_coff_swap_aouthdr_out(stdoutput, &(headers->aouthdr), *where);
+#endif
+ obj_coff_section_header_append(where, &text_section_header);
+ obj_coff_section_header_append(where, &data_section_header);
+ obj_coff_section_header_append(where, &bss_section_header);
+
+}
+
+#else
+
+void obj_header_append(where, headers)
+char **where;
+object_headers *headers;
+{
+ tc_headers_hook(headers);
+
+#ifdef CROSS_COMPILE
+ /* Eventually swap bytes for cross compilation for file header */
+ md_number_to_chars(*where, headers->filehdr.f_magic, sizeof(headers->filehdr.f_magic));
+ *where += sizeof(headers->filehdr.f_magic);
+ md_number_to_chars(*where, headers->filehdr.f_nscns, sizeof(headers->filehdr.f_nscns));
+ *where += sizeof(headers->filehdr.f_nscns);
+ md_number_to_chars(*where, headers->filehdr.f_timdat, sizeof(headers->filehdr.f_timdat));
+ *where += sizeof(headers->filehdr.f_timdat);
+ md_number_to_chars(*where, headers->filehdr.f_symptr, sizeof(headers->filehdr.f_symptr));
+ *where += sizeof(headers->filehdr.f_symptr);
+ md_number_to_chars(*where, headers->filehdr.f_nsyms, sizeof(headers->filehdr.f_nsyms));
+ *where += sizeof(headers->filehdr.f_nsyms);
+ md_number_to_chars(*where, headers->filehdr.f_opthdr, sizeof(headers->filehdr.f_opthdr));
+ *where += sizeof(headers->filehdr.f_opthdr);
+ md_number_to_chars(*where, headers->filehdr.f_flags, sizeof(headers->filehdr.f_flags));
+ *where += sizeof(headers->filehdr.f_flags);
+
+#ifndef OBJ_COFF_OMIT_OPTIONAL_HEADER
+ /* Eventually swap bytes for cross compilation for a.out header */
+ md_number_to_chars(*where, headers->aouthdr.magic, sizeof(headers->aouthdr.magic));
+ *where += sizeof(headers->aouthdr.magic);
+ md_number_to_chars(*where, headers->aouthdr.vstamp, sizeof(headers->aouthdr.vstamp));
+ *where += sizeof(headers->aouthdr.vstamp);
+ md_number_to_chars(*where, headers->aouthdr.tsize, sizeof(headers->aouthdr.tsize));
+ *where += sizeof(headers->aouthdr.tsize);
+ md_number_to_chars(*where, headers->aouthdr.dsize, sizeof(headers->aouthdr.dsize));
+ *where += sizeof(headers->aouthdr.dsize);
+ md_number_to_chars(*where, headers->aouthdr.bsize, sizeof(headers->aouthdr.bsize));
+ *where += sizeof(headers->aouthdr.bsize);
+ md_number_to_chars(*where, headers->aouthdr.entry, sizeof(headers->aouthdr.entry));
+ *where += sizeof(headers->aouthdr.entry);
+ md_number_to_chars(*where, headers->aouthdr.text_start, sizeof(headers->aouthdr.text_start));
+ *where += sizeof(headers->aouthdr.text_start);
+ md_number_to_chars(*where, headers->aouthdr.data_start, sizeof(headers->aouthdr.data_start));
+ *where += sizeof(headers->aouthdr.data_start);
+ md_number_to_chars(*where, headers->aouthdr.tagentries, sizeof(headers->aouthdr.tagentries));
+ *where += sizeof(headers->aouthdr.tagentries);
+#endif /* OBJ_COFF_OMIT_OPTIONAL_HEADER */
+
+#else /* CROSS_COMPILE */
+
+ append(where, (char *) &headers->filehdr, sizeof(headers->filehdr));
+#ifndef OBJ_COFF_OMIT_OPTIONAL_HEADER
+ append(where, (char *) &headers->aouthdr, sizeof(headers->aouthdr));
+#endif /* OBJ_COFF_OMIT_OPTIONAL_HEADER */
+
+#endif /* CROSS_COMPILE */
+
+ /* Output the section headers */
+ obj_coff_section_header_append(where, &text_section_header);
+ obj_coff_section_header_append(where, &data_section_header);
+ obj_coff_section_header_append(where, &bss_section_header);
+
+ return;
+} /* obj_header_append() */
+#endif
+void obj_symbol_to_chars(where, symbolP)
+char **where;
+symbolS *symbolP;
+{
+#ifdef BFD_HEADERS
+ unsigned int numaux = symbolP->sy_symbol.ost_entry.n_numaux;
+ unsigned int i;
+
+ if (S_GET_SEGMENT(symbolP) == SEG_REGISTER) {
+ S_SET_SEGMENT(symbolP, SEG_ABSOLUTE);
+ }
+ *where += bfd_coff_swap_sym_out(stdoutput, &symbolP->sy_symbol.ost_entry,
+ *where);
+
+ for (i = 0; i < numaux; i++)
+ {
+ *where += bfd_coff_swap_aux_out(stdoutput,
+ &symbolP->sy_symbol.ost_auxent[i],
+ S_GET_DATA_TYPE(symbolP),
+ S_GET_STORAGE_CLASS(symbolP),
+ *where);
+ }
+
+#else /* BFD_HEADERS */
+ SYMENT *syment = &symbolP->sy_symbol.ost_entry;
+ int i;
+ char numaux = syment->n_numaux;
+ unsigned short type = S_GET_DATA_TYPE(symbolP);
+
+#ifdef CROSS_COMPILE
+ md_number_to_chars(*where, syment->n_value, sizeof(syment->n_value));
+ *where += sizeof(syment->n_value);
+ md_number_to_chars(*where, syment->n_scnum, sizeof(syment->n_scnum));
+ *where += sizeof(syment->n_scnum);
+ md_number_to_chars(*where, 0, sizeof(short)); /* pad n_flags */
+ *where += sizeof(short);
+ md_number_to_chars(*where, syment->n_type, sizeof(syment->n_type));
+ *where += sizeof(syment->n_type);
+ md_number_to_chars(*where, syment->n_sclass, sizeof(syment->n_sclass));
+ *where += sizeof(syment->n_sclass);
+ md_number_to_chars(*where, syment->n_numaux, sizeof(syment->n_numaux));
+ *where += sizeof(syment->n_numaux);
+#else /* CROSS_COMPILE */
+ append(where, (char *) syment, sizeof(*syment));
+#endif /* CROSS_COMPILE */
+
+ /* Should do the following : if (.file entry) MD(..)... else if (static entry) MD(..) */
+ if (numaux > OBJ_COFF_MAX_AUXENTRIES) {
+ as_bad("Internal error? too many auxents for symbol");
+ } /* too many auxents */
+
+ for (i = 0; i < numaux; ++i) {
+#ifdef CROSS_COMPILE
+#if 0 /* This code has never been tested */
+ /* The most common case, x_sym entry. */
+ if ((SF_GET(symbolP) & (SF_FILE | SF_STATICS)) == 0) {
+ md_number_to_chars(*where, auxP->x_sym.x_tagndx, sizeof(auxP->x_sym.x_tagndx));
+ *where += sizeof(auxP->x_sym.x_tagndx);
+ if (ISFCN(type)) {
+ md_number_to_chars(*where, auxP->x_sym.x_misc.x_fsize, sizeof(auxP->x_sym.x_misc.x_fsize));
+ *where += sizeof(auxP->x_sym.x_misc.x_fsize);
+ } else {
+ md_number_to_chars(*where, auxP->x_sym.x_misc.x_lnno, sizeof(auxP->x_sym.x_misc.x_lnno));
+ *where += sizeof(auxP->x_sym.x_misc.x_lnno);
+ md_number_to_chars(*where, auxP->x_sym.x_misc.x_size, sizeof(auxP->x_sym.x_misc.x_size));
+ *where += sizeof(auxP->x_sym.x_misc.x_size);
+ }
+ if (ISARY(type)) {
+ register int index;
+ for (index = 0; index < DIMNUM; index++)
+ md_number_to_chars(*where, auxP->x_sym.x_fcnary.x_ary.x_dimen[index], sizeof(auxP->x_sym.x_fcnary.x_ary.x_dimen[index]));
+ *where += sizeof(auxP->x_sym.x_fcnary.x_ary.x_dimen[index]);
+ } else {
+ md_number_to_chars(*where, auxP->x_sym.x_fcnary.x_fcn.x_lnnoptr, sizeof(auxP->x_sym.x_fcnary.x_fcn.x_lnnoptr));
+ *where += sizeof(auxP->x_sym.x_fcnary.x_fcn.x_lnnoptr);
+ md_number_to_chars(*where, auxP->x_sym.x_fcnary.x_fcn.x_endndx, sizeof(auxP->x_sym.x_fcnary.x_fcn.x_endndx));
+ *where += sizeof(auxP->x_sym.x_fcnary.x_fcn.x_endndx);
+ }
+ md_number_to_chars(*where, auxP->x_sym.x_tvndx, sizeof(auxP->x_sym.x_tvndx));
+ *where += sizeof(auxP->x_sym.x_tvndx);
+ } else if (SF_GET_FILE(symbolP)) { /* .file */
+ ;
+ } else if (SF_GET_STATICS(symbolP)) { /* .text, .data, .bss symbols */
+ md_number_to_chars(*where, auxP->x_scn.x_scnlen, sizeof(auxP->x_scn.x_scnlen));
+ *where += sizeof(auxP->x_scn.x_scnlen);
+ md_number_to_chars(*where, auxP->x_scn.x_nreloc, sizeof(auxP->x_scn.x_nreloc));
+ *where += sizeof(auxP->x_scn.x_nreloc);
+ md_number_to_chars(*where, auxP->x_scn.x_nlinno, sizeof(auxP->x_scn.x_nlinno));
+ *where += sizeof(auxP->x_scn.x_nlinno);
+ }
+#endif /* 0 */
+#else /* CROSS_COMPILE */
+ append(where, (char *) &symbolP->sy_symbol.ost_auxent[i], sizeof(symbolP->sy_symbol.ost_auxent[i]));
+#endif /* CROSS_COMPILE */
+
+ }; /* for each aux in use */
+#endif /* BFD_HEADERS */
+ return;
+} /* obj_symbol_to_chars() */
+
+#ifdef BFD_HEADERS
+static void obj_coff_section_header_append(where, header)
+char **where;
+struct internal_scnhdr *header;
+{
+ *where += bfd_coff_swap_scnhdr_out(stdoutput, header, *where);
+}
+#else
+static void obj_coff_section_header_append(where, header)
+char **where;
+SCNHDR *header;
+{
+#ifdef CROSS_COMPILE
+ memcpy(*where, header->s_name, sizeof(header->s_name));
+ *where += sizeof(header->s_name);
+
+ md_number_to_chars(*where, header->s_paddr, sizeof(header->s_paddr));
+ *where += sizeof(header->s_paddr);
+
+ md_number_to_chars(*where, header->s_vaddr, sizeof(header->s_vaddr));
+ *where += sizeof(header->s_vaddr);
+
+ md_number_to_chars(*where, header->s_size, sizeof(header->s_size));
+ *where += sizeof(header->s_size);
+
+ md_number_to_chars(*where, header->s_scnptr, sizeof(header->s_scnptr));
+ *where += sizeof(header->s_scnptr);
+
+ md_number_to_chars(*where, header->s_relptr, sizeof(header->s_relptr));
+ *where += sizeof(header->s_relptr);
+
+ md_number_to_chars(*where, header->s_lnnoptr, sizeof(header->s_lnnoptr));
+ *where += sizeof(header->s_lnnoptr);
+
+ md_number_to_chars(*where, header->s_nreloc, sizeof(header->s_nreloc));
+ *where += sizeof(header->s_nreloc);
+
+ md_number_to_chars(*where, header->s_nlnno, sizeof(header->s_nlnno));
+ *where += sizeof(header->s_nlnno);
+
+ md_number_to_chars(*where, header->s_flags, sizeof(header->s_flags));
+ *where += sizeof(header->s_flags);
+
+#ifdef TC_I960
+ md_number_to_chars(*where, header->s_align, sizeof(header->s_align));
+ *where += sizeof(header->s_align);
+#endif /* TC_I960 */
+
+#else /* CROSS_COMPILE */
+
+ append(where, (char *) header, sizeof(*header));
+
+#endif /* CROSS_COMPILE */
+
+ return;
+} /* obj_coff_section_header_append() */
+
+#endif
+void obj_emit_symbols(where, symbol_rootP)
+char **where;
+symbolS *symbol_rootP;
+{
+ symbolS *symbolP;
+ /*
+ * Emit all symbols left in the symbol chain.
+ */
+ for (symbolP = symbol_rootP; symbolP; symbolP = symbol_next(symbolP)) {
+ /* Used to save the offset of the name. It is used to point
+ to the string in memory but must be a file offset. */
+ register char * temp;
+
+ tc_coff_symbol_emit_hook(symbolP);
+
+ temp = S_GET_NAME(symbolP);
+ if (SF_GET_STRING(symbolP)) {
+ S_SET_OFFSET(symbolP, symbolP->sy_name_offset);
+ S_SET_ZEROES(symbolP, 0);
+ } else {
+ memset(symbolP->sy_symbol.ost_entry.n_name, '\0', SYMNMLEN);
+ strncpy(symbolP->sy_symbol.ost_entry.n_name, temp, SYMNMLEN);
+ }
+ obj_symbol_to_chars(where, symbolP);
+ S_SET_NAME(symbolP,temp);
+ }
+} /* obj_emit_symbols() */
+
+/* Merge a debug symbol containing debug information into a normal symbol. */
+
+void c_symbol_merge(debug, normal)
+symbolS *debug;
+symbolS *normal;
+{
+ S_SET_DATA_TYPE(normal, S_GET_DATA_TYPE(debug));
+ S_SET_STORAGE_CLASS(normal, S_GET_STORAGE_CLASS(debug));
+
+ if (S_GET_NUMBER_AUXILIARY(debug) > S_GET_NUMBER_AUXILIARY(normal)) {
+ S_SET_NUMBER_AUXILIARY(normal, S_GET_NUMBER_AUXILIARY(debug));
+ } /* take the most we have */
+
+ if (S_GET_NUMBER_AUXILIARY(debug) > 0) {
+ memcpy((char*)&normal->sy_symbol.ost_auxent[0], (char*)&debug->sy_symbol.ost_auxent[0], S_GET_NUMBER_AUXILIARY(debug) * AUXESZ);
+ } /* Move all the auxiliary information */
+
+ /* Move the debug flags. */
+ SF_SET_DEBUG_FIELD(normal, SF_GET_DEBUG_FIELD(debug));
+} /* c_symbol_merge() */
+
+static symbolS *previous_file_symbol = NULL;
+
+void c_dot_file_symbol(filename)
+char *filename;
+{
+ symbolS* symbolP;
+
+ symbolP = symbol_new(".file",
+ SEG_DEBUG,
+ 0,
+ &zero_address_frag);
+
+ S_SET_STORAGE_CLASS(symbolP, C_FILE);
+ S_SET_NUMBER_AUXILIARY(symbolP, 1);
+ SA_SET_FILE_FNAME(symbolP, filename);
+ SF_SET_DEBUG(symbolP);
+ S_SET_VALUE(symbolP, (long) previous_file_symbol);
+
+ previous_file_symbol = symbolP;
+
+ /* Make sure that the symbol is first on the symbol chain */
+ if (symbol_rootP != symbolP) {
+ if (symbolP == symbol_lastP) {
+ symbol_lastP = symbol_lastP->sy_previous;
+ } /* if it was the last thing on the list */
+
+ symbol_remove(symbolP, &symbol_rootP, &symbol_lastP);
+ symbol_insert(symbolP, symbol_rootP, &symbol_rootP, &symbol_lastP);
+ symbol_rootP = symbolP;
+ } /* if not first on the list */
+
+} /* c_dot_file_symbol() */
+/*
+ * Build a 'section static' symbol.
+ */
+
+char *c_section_symbol(name, value, length, nreloc, nlnno)
+char *name;
+long value;
+long length;
+unsigned short nreloc;
+unsigned short nlnno;
+{
+ symbolS *symbolP;
+
+ symbolP = symbol_new(name,
+ (name[1] == 't'
+ ? SEG_TEXT
+ : (name[1] == 'd'
+ ? SEG_DATA
+ : SEG_BSS)),
+ value,
+ &zero_address_frag);
+
+ S_SET_STORAGE_CLASS(symbolP, C_STAT);
+ S_SET_NUMBER_AUXILIARY(symbolP, 1);
+
+ SA_SET_SCN_SCNLEN(symbolP, length);
+ SA_SET_SCN_NRELOC(symbolP, nreloc);
+ SA_SET_SCN_NLINNO(symbolP, nlnno);
+
+ SF_SET_STATICS(symbolP);
+
+ return (char*)symbolP;
+} /* c_section_symbol() */
+
+void c_section_header(header,
+ name,
+ core_address,
+ size,
+ data_ptr,
+ reloc_ptr,
+ lineno_ptr,
+ reloc_number,
+ lineno_number,
+ alignment)
+#ifdef BFD_HEADERS
+struct internal_scnhdr *header;
+#else
+SCNHDR *header;
+#endif
+char *name;
+long core_address;
+long size;
+long data_ptr;
+long reloc_ptr;
+long lineno_ptr;
+long reloc_number;
+long lineno_number;
+long alignment;
+{
+ strncpy(header->s_name, name, 8);
+ header->s_paddr = header->s_vaddr = core_address;
+ header->s_scnptr = ((header->s_size = size) != 0) ? data_ptr : 0;
+ header->s_relptr = reloc_ptr;
+ header->s_lnnoptr = lineno_ptr;
+ header->s_nreloc = reloc_number;
+ header->s_nlnno = lineno_number;
+
+#ifdef OBJ_COFF_SECTION_HEADER_HAS_ALIGNMENT
+#ifdef OBJ_COFF_BROKEN_ALIGNMENT
+ header->s_align = ((name[1] == 'b' || (size > 0)) ? 16 : 0);
+#else
+ header->s_align = ((alignment == 0)
+ ? 0
+ : (1 << alignment));
+#endif /* OBJ_COFF_BROKEN_ALIGNMENT */
+#endif /* OBJ_COFF_SECTION_HEADER_HAS_ALIGNMENT */
+
+ header->s_flags = STYP_REG | (name[1] == 't'
+ ? STYP_TEXT
+ : (name[1] == 'd'
+ ? STYP_DATA
+ : (name[1] == 'b'
+ ? STYP_BSS
+ : STYP_INFO)));
+ return;
+} /* c_section_header() */
+
+/* Line number handling */
+
+int function_lineoff = -1; /* Offset in line#s where the last function
+ started (the odd entry for line #0) */
+int text_lineno_number = 0;
+int our_lineno_number = 0; /* we use this to build pointers from .bf's
+ into the linetable. It should match
+ exactly the values that are later
+ assigned in text_lineno_number by
+ write.c. */
+lineno* lineno_lastP = (lineno*)0;
+
+int
+ c_line_new(paddr, line_number, frag)
+long paddr;
+unsigned short line_number;
+fragS* frag;
+{
+ lineno* new_line = (lineno*)xmalloc(sizeof(lineno));
+
+ new_line->line.l_addr.l_paddr = paddr;
+ new_line->line.l_lnno = line_number;
+ new_line->frag = (char*)frag;
+ new_line->next = (lineno*)0;
+
+ if (lineno_rootP == (lineno*)0)
+ lineno_rootP = new_line;
+ else
+ lineno_lastP->next = new_line;
+ lineno_lastP = new_line;
+ return LINESZ * our_lineno_number++;
+}
+
+void obj_emit_lineno(where, line, file_start)
+char **where;
+lineno *line;
+char *file_start;
+{
+#ifdef BFD_HEADERS
+ struct bfd_internal_lineno *line_entry;
+#else
+ LINENO *line_entry;
+#endif
+ for (; line; line = line->next) {
+ line_entry = &line->line;
+
+ /* FIXME-SOMEDAY Resolving the sy_number of function linno's used to be done in
+ write_object_file() but their symbols need a fileptr to the lnno, so
+ I moved this resolution check here. xoxorich. */
+
+ if (line_entry->l_lnno == 0) {
+ /* There is a good chance that the symbol pointed to
+ is not the one that will be emitted and that the
+ sy_number is not accurate. */
+ /* char *name; */
+ symbolS *symbolP;
+
+ symbolP = (symbolS *) line_entry->l_addr.l_symndx;
+
+ line_entry->l_addr.l_symndx = symbolP->sy_number;
+ symbolP->sy_symbol.ost_auxent[0].x_sym.x_fcnary.x_fcn.x_lnnoptr = *where - file_start;
+
+ } /* if this is a function linno */
+#ifdef BFD_HEADERS
+ *where += bfd_coff_swap_lineno_out(stdoutput, line_entry, *where);
+#else
+ /* No matter which member of the union we process, they are
+ both long. */
+#ifdef CROSS_COMPILE
+ md_number_to_chars(*where, line_entry->l_addr.l_paddr, sizeof(line_entry->l_addr.l_paddr));
+ *where += sizeof(line_entry->l_addr.l_paddr);
+
+ md_number_to_chars(*where, line_entry->l_lnno, sizeof(line_entry->l_lnno));
+ *where += sizeof(line_entry->l_lnno);
+
+#ifdef TC_I960
+ **where = '0';
+ ++*where;
+ **where = '0';
+ ++*where;
+#endif /* TC_I960 */
+
+#else /* CROSS_COMPILE */
+ append(where, (char *) line_entry, LINESZ);
+#endif /* CROSS_COMPILE */
+#endif /* BFD_HEADERS */
+ } /* for each line number */
+
+ return ;
+} /* obj_emit_lineno() */
+
+void obj_symbol_new_hook(symbolP)
+symbolS *symbolP;
+{
+ char underscore = 0; /* Symbol has leading _ */
+
+ /* Effective symbol */
+ /* Store the pointer in the offset. */
+ S_SET_ZEROES(symbolP, 0L);
+ S_SET_DATA_TYPE(symbolP, T_NULL);
+ S_SET_STORAGE_CLASS(symbolP, 0);
+ S_SET_NUMBER_AUXILIARY(symbolP, 0);
+ /* Additional information */
+ symbolP->sy_symbol.ost_flags = 0;
+ /* Auxiliary entries */
+ memset((char*) &symbolP->sy_symbol.ost_auxent[0], '\0', AUXESZ);
+
+#ifdef STRIP_UNDERSCORE
+ /* Remove leading underscore at the beginning of the symbol.
+ * This is to be compatible with the standard librairies.
+ */
+ if (*S_GET_NAME(symbolP) == '_') {
+ underscore = 1;
+ S_SET_NAME(symbolP, S_GET_NAME(symbolP) + 1);
+ } /* strip underscore */
+#endif /* STRIP_UNDERSCORE */
+
+ if (S_IS_STRING(symbolP))
+ SF_SET_STRING(symbolP);
+ if (!underscore && S_IS_LOCAL(symbolP))
+ SF_SET_LOCAL(symbolP);
+
+ return;
+} /* obj_symbol_new_hook() */
+
+/* stack stuff */
+stack* stack_init(chunk_size, element_size)
+unsigned long chunk_size;
+unsigned long element_size;
+{
+ stack* st;
+
+ if ((st = (stack*)malloc(sizeof(stack))) == (stack*)0)
+ return (stack*)0;
+ if ((st->data = malloc(chunk_size)) == (char*)0) {
+ free(st);
+ return (stack*)0;
+ }
+ st->pointer = 0;
+ st->size = chunk_size;
+ st->chunk_size = chunk_size;
+ st->element_size = element_size;
+ return st;
+} /* stack_init() */
+
+void stack_delete(st)
+stack* st;
+{
+ free(st->data);
+ free(st);
+}
+
+char *stack_push(st, element)
+stack *st;
+char *element;
+{
+ if (st->pointer + st->element_size >= st->size) {
+ st->size += st->chunk_size;
+ if ((st->data = xrealloc(st->data, st->size)) == (char*)0)
+ return (char*)0;
+ }
+ memcpy(st->data + st->pointer, element, st->element_size);
+ st->pointer += st->element_size;
+ return st->data + st->pointer;
+} /* stack_push() */
+
+char* stack_pop(st)
+stack* st;
+{
+ if ((st->pointer -= st->element_size) < 0) {
+ st->pointer = 0;
+ return (char*)0;
+ }
+ return st->data + st->pointer;
+}
+
+char* stack_top(st)
+stack* st;
+{
+ return st->data + st->pointer - st->element_size;
+}
+
+
+/*
+ * Handle .ln directives.
+ */
+
+static void obj_coff_ln() {
+ if (def_symbol_in_progress != NULL) {
+ as_warn(".ln pseudo-op inside .def/.endef: ignored.");
+ demand_empty_rest_of_line();
+ return;
+ } /* wrong context */
+
+ c_line_new(obstack_next_free(&frags) - frag_now->fr_literal,
+ get_absolute_expression(),
+ frag_now);
+
+ demand_empty_rest_of_line();
+ return;
+} /* obj_coff_line() */
+
+/*
+ * def()
+ *
+ * Handle .def directives.
+ *
+ * One might ask : why can't we symbol_new if the symbol does not
+ * already exist and fill it with debug information. Because of
+ * the C_EFCN special symbol. It would clobber the value of the
+ * function symbol before we have a chance to notice that it is
+ * a C_EFCN. And a second reason is that the code is more clear this
+ * way. (at least I think it is :-).
+ *
+ */
+
+#define SKIP_SEMI_COLON() while (*input_line_pointer++ != ';')
+#define SKIP_WHITESPACES() while (*input_line_pointer == ' ' || \
+ *input_line_pointer == '\t') \
+ input_line_pointer++;
+
+static void obj_coff_def(what)
+int what;
+{
+ char name_end; /* Char after the end of name */
+ char *symbol_name; /* Name of the debug symbol */
+ char *symbol_name_copy; /* Temporary copy of the name */
+ unsigned int symbol_name_length;
+ /*$char* directiveP;$ */ /* Name of the pseudo opcode */
+ /*$char directive[MAX_DIRECTIVE];$ */ /* Backup of the directive */
+ /*$char end = 0;$ */ /* If 1, stop parsing */
+
+ if (def_symbol_in_progress != NULL) {
+ as_warn(".def pseudo-op used inside of .def/.endef: ignored.");
+ demand_empty_rest_of_line();
+ return;
+ } /* if not inside .def/.endef */
+
+ SKIP_WHITESPACES();
+
+ def_symbol_in_progress = (symbolS *) obstack_alloc(&notes, sizeof(*def_symbol_in_progress));
+ memset(def_symbol_in_progress, '\0', sizeof(*def_symbol_in_progress));
+
+ symbol_name = input_line_pointer;
+ name_end = get_symbol_end();
+ symbol_name_length = strlen(symbol_name);
+ symbol_name_copy = xmalloc(symbol_name_length + 1);
+ strcpy(symbol_name_copy, symbol_name);
+
+ /* Initialize the new symbol */
+#ifdef STRIP_UNDERSCORE
+ S_SET_NAME(def_symbol_in_progress, (*symbol_name_copy == '_'
+ ? symbol_name_copy + 1
+ : symbol_name_copy));
+#else /* STRIP_UNDERSCORE */
+ S_SET_NAME(def_symbol_in_progress, symbol_name_copy);
+#endif /* STRIP_UNDERSCORE */
+ /* free(symbol_name_copy); */
+ def_symbol_in_progress->sy_name_offset = ~0;
+ def_symbol_in_progress->sy_number = ~0;
+ def_symbol_in_progress->sy_frag = &zero_address_frag;
+
+ if (S_IS_STRING(def_symbol_in_progress)) {
+ SF_SET_STRING(def_symbol_in_progress);
+ } /* "long" name */
+
+ *input_line_pointer = name_end;
+
+ demand_empty_rest_of_line();
+ return;
+} /* obj_coff_def() */
+
+unsigned int dim_index;
+static void obj_coff_endef() {
+ symbolS *symbolP;
+ /* DIM BUG FIX sac@cygnus.com */
+ dim_index =0;
+ if (def_symbol_in_progress == NULL) {
+ as_warn(".endef pseudo-op used outside of .def/.endef: ignored.");
+ demand_empty_rest_of_line();
+ return;
+ } /* if not inside .def/.endef */
+
+ /* Set the section number according to storage class. */
+ switch (S_GET_STORAGE_CLASS(def_symbol_in_progress)) {
+ case C_STRTAG:
+ case C_ENTAG:
+ case C_UNTAG:
+ SF_SET_TAG(def_symbol_in_progress);
+ /* intentional fallthrough */
+ case C_FILE:
+ case C_TPDEF:
+ SF_SET_DEBUG(def_symbol_in_progress);
+ S_SET_SEGMENT(def_symbol_in_progress, SEG_DEBUG);
+ break;
+
+ case C_EFCN:
+ SF_SET_LOCAL(def_symbol_in_progress); /* Do not emit this symbol. */
+ /* intentional fallthrough */
+ case C_BLOCK:
+ SF_SET_PROCESS(def_symbol_in_progress); /* Will need processing before writing */
+ /* intentional fallthrough */
+ case C_FCN:
+ S_SET_SEGMENT(def_symbol_in_progress, SEG_TEXT);
+
+ if (def_symbol_in_progress->sy_symbol.ost_entry.n_name[1] == 'b') { /* .bf */
+ if (function_lineoff < 0) {
+ fprintf(stderr, "`.bf' symbol without preceding function\n");
+ } /* missing function symbol */
+ SA_GET_SYM_LNNOPTR(def_symbol_in_progress) = function_lineoff;
+ SF_SET_PROCESS(def_symbol_in_progress); /* Will need relocating */
+ function_lineoff = -1;
+ }
+ break;
+
+#ifdef C_AUTOARG
+ case C_AUTOARG:
+#endif /* C_AUTOARG */
+ case C_AUTO:
+ case C_REG:
+ case C_MOS:
+ case C_MOE:
+ case C_MOU:
+ case C_ARG:
+ case C_REGPARM:
+ case C_FIELD:
+ case C_EOS:
+ SF_SET_DEBUG(def_symbol_in_progress);
+ S_SET_SEGMENT(def_symbol_in_progress, SEG_ABSOLUTE);
+ break;
+
+ case C_EXT:
+ case C_STAT:
+ case C_LABEL:
+ /* Valid but set somewhere else (s_comm, s_lcomm, colon) */
+ break;
+
+ case C_USTATIC:
+ case C_EXTDEF:
+ case C_ULABEL:
+ as_warn("unexpected storage class %d", S_GET_STORAGE_CLASS(def_symbol_in_progress));
+ break;
+ } /* switch on storage class */
+
+ /* Now that we have built a debug symbol, try to
+ find if we should merge with an existing symbol
+ or not. If a symbol is C_EFCN or SEG_ABSOLUTE or
+ untagged SEG_DEBUG it never merges. */
+
+ /* Two cases for functions. Either debug followed
+ by definition or definition followed by debug.
+ For definition first, we will merge the debug
+ symbol into the definition. For debug first, the
+ lineno entry MUST point to the definition
+ function or else it will point off into space
+ when obj_crawl_symbol_chain() merges the debug
+ symbol into the real symbol. Therefor, let's
+ presume the debug symbol is a real function
+ reference. */
+
+ /* FIXME-SOON If for some reason the definition
+ label/symbol is never seen, this will probably
+ leave an undefined symbol at link time. */
+
+ if (S_GET_STORAGE_CLASS(def_symbol_in_progress) == C_EFCN
+ || (S_GET_SEGMENT(def_symbol_in_progress) == SEG_DEBUG
+ && !SF_GET_TAG(def_symbol_in_progress))
+ || S_GET_SEGMENT(def_symbol_in_progress) == SEG_ABSOLUTE
+ || (symbolP = symbol_find_base(S_GET_NAME(def_symbol_in_progress), DO_NOT_STRIP)) == NULL) {
+
+ symbol_append(def_symbol_in_progress, symbol_lastP, &symbol_rootP, &symbol_lastP);
+
+ } else {
+ /* This symbol already exists, merge the
+ newly created symbol into the old one.
+ This is not mandatory. The linker can
+ handle duplicate symbols correctly. But I
+ guess that it save a *lot* of space if
+ the assembly file defines a lot of
+ symbols. [loic] */
+
+ /* The debug entry (def_symbol_in_progress)
+ is merged into the previous definition. */
+
+ c_symbol_merge(def_symbol_in_progress, symbolP);
+ /* FIXME-SOON Should *def_symbol_in_progress be free'd? xoxorich. */
+ def_symbol_in_progress = symbolP;
+
+ if (SF_GET_FUNCTION(def_symbol_in_progress)
+ || SF_GET_TAG(def_symbol_in_progress)) {
+ /* For functions, and tags, the symbol *must* be where the debug symbol
+ appears. Move the existing symbol to the current place. */
+ /* If it already is at the end of the symbol list, do nothing */
+ if (def_symbol_in_progress != symbol_lastP) {
+ symbol_remove(def_symbol_in_progress, &symbol_rootP, &symbol_lastP);
+ symbol_append(def_symbol_in_progress, symbol_lastP, &symbol_rootP, &symbol_lastP);
+ } /* if not already in place */
+ } /* if function */
+ } /* normal or mergable */
+
+ if (SF_GET_TAG(def_symbol_in_progress)
+ && symbol_find_base(S_GET_NAME(def_symbol_in_progress), DO_NOT_STRIP) == NULL) {
+ tag_insert(S_GET_NAME(def_symbol_in_progress), def_symbol_in_progress);
+ } /* If symbol is a {structure,union} tag, associate symbol to its name. */
+
+ if (SF_GET_FUNCTION(def_symbol_in_progress)) {
+ know(sizeof(def_symbol_in_progress) <= sizeof(long));
+ function_lineoff = c_line_new((long) def_symbol_in_progress, 0, &zero_address_frag);
+ SF_SET_PROCESS(def_symbol_in_progress);
+
+ if (symbolP == NULL) {
+ /* That is, if this is the first
+ time we've seen the function... */
+ symbol_table_insert(def_symbol_in_progress);
+ } /* definition follows debug */
+ } /* Create the line number entry pointing to the function being defined */
+
+ def_symbol_in_progress = NULL;
+ demand_empty_rest_of_line();
+ return;
+} /* obj_coff_endef() */
+
+static void obj_coff_dim()
+{
+ register int dim_index;
+
+ if (def_symbol_in_progress == NULL) {
+ as_warn(".dim pseudo-op used outside of .def/.endef: ignored.");
+ demand_empty_rest_of_line();
+ return;
+ } /* if not inside .def/.endef */
+
+ S_SET_NUMBER_AUXILIARY(def_symbol_in_progress, 1);
+
+ for (dim_index = 0; dim_index < DIMNUM; dim_index++) {
+ SKIP_WHITESPACES();
+ SA_SET_SYM_DIMEN(def_symbol_in_progress, dim_index, get_absolute_expression());
+
+ switch (*input_line_pointer) {
+
+ case ',':
+ input_line_pointer++;
+ break;
+
+ default:
+ as_warn("badly formed .dim directive ignored");
+ /* intentional fallthrough */
+ case '\n':
+ case ';':
+ dim_index = DIMNUM;
+ break;
+ } /* switch on following character */
+ } /* for each dimension */
+
+ demand_empty_rest_of_line();
+ return;
+} /* obj_coff_dim() */
+
+static void obj_coff_line() {
+ if (def_symbol_in_progress == NULL) {
+ obj_coff_ln();
+ return;
+ } /* if it looks like a stabs style line */
+
+ S_SET_NUMBER_AUXILIARY(def_symbol_in_progress, 1);
+ SA_SET_SYM_LNNO(def_symbol_in_progress, get_absolute_expression());
+
+ demand_empty_rest_of_line();
+ return;
+} /* obj_coff_line() */
+
+static void obj_coff_size() {
+ if (def_symbol_in_progress == NULL) {
+ as_warn(".size pseudo-op used outside of .def/.endef ignored.");
+ demand_empty_rest_of_line();
+ return;
+ } /* if not inside .def/.endef */
+
+ S_SET_NUMBER_AUXILIARY(def_symbol_in_progress, 1);
+ SA_SET_SYM_SIZE(def_symbol_in_progress, get_absolute_expression());
+ demand_empty_rest_of_line();
+ return;
+} /* obj_coff_size() */
+
+static void obj_coff_scl() {
+ if (def_symbol_in_progress == NULL) {
+ as_warn(".scl pseudo-op used outside of .def/.endef ignored.");
+ demand_empty_rest_of_line();
+ return;
+ } /* if not inside .def/.endef */
+
+ S_SET_STORAGE_CLASS(def_symbol_in_progress, get_absolute_expression());
+ demand_empty_rest_of_line();
+ return;
+} /* obj_coff_scl() */
+
+static void obj_coff_tag() {
+ char *symbol_name;
+ char name_end;
+
+ if (def_symbol_in_progress == NULL) {
+ as_warn(".tag pseudo-op used outside of .def/.endef ignored.");
+ demand_empty_rest_of_line();
+ return;
+ } /* if not inside .def/.endef */
+
+ S_SET_NUMBER_AUXILIARY(def_symbol_in_progress, 1);
+ symbol_name = input_line_pointer;
+ name_end = get_symbol_end();
+
+ /* Assume that the symbol referred to by .tag is always defined. */
+ /* This was a bad assumption. I've added find_or_make. xoxorich. */
+ SA_SET_SYM_TAGNDX(def_symbol_in_progress, (long) tag_find_or_make(symbol_name));
+ if (SA_GET_SYM_TAGNDX(def_symbol_in_progress) == 0L) {
+ as_warn("tag not found for .tag %s", symbol_name);
+ } /* not defined */
+
+ SF_SET_TAGGED(def_symbol_in_progress);
+ *input_line_pointer = name_end;
+
+ demand_empty_rest_of_line();
+ return;
+} /* obj_coff_tag() */
+
+static void obj_coff_type() {
+ if (def_symbol_in_progress == NULL) {
+ as_warn(".type pseudo-op used outside of .def/.endef ignored.");
+ demand_empty_rest_of_line();
+ return;
+ } /* if not inside .def/.endef */
+
+ S_SET_DATA_TYPE(def_symbol_in_progress, get_absolute_expression());
+
+ if (ISFCN(S_GET_DATA_TYPE(def_symbol_in_progress)) &&
+ S_GET_STORAGE_CLASS(def_symbol_in_progress) != C_TPDEF) {
+ SF_SET_FUNCTION(def_symbol_in_progress);
+ } /* is a function */
+
+ demand_empty_rest_of_line();
+ return;
+} /* obj_coff_type() */
+
+static void obj_coff_val() {
+ if (def_symbol_in_progress == NULL) {
+ as_warn(".val pseudo-op used outside of .def/.endef ignored.");
+ demand_empty_rest_of_line();
+ return;
+ } /* if not inside .def/.endef */
+
+ if (is_name_beginner(*input_line_pointer)) {
+ char *symbol_name = input_line_pointer;
+ char name_end = get_symbol_end();
+
+ if (!strcmp(symbol_name, ".")) {
+ def_symbol_in_progress->sy_frag = frag_now;
+ S_SET_VALUE(def_symbol_in_progress, obstack_next_free(&frags) - frag_now->fr_literal);
+ /* If the .val is != from the .def (e.g. statics) */
+ } else if (strcmp(S_GET_NAME(def_symbol_in_progress), symbol_name)) {
+ def_symbol_in_progress->sy_forward = symbol_find_or_make(symbol_name);
+
+ /* If the segment is undefined when the forward
+ reference is solved, then copy the segment id
+ from the forward symbol. */
+ SF_SET_GET_SEGMENT(def_symbol_in_progress);
+ }
+ /* Otherwise, it is the name of a non debug symbol and its value will be calculated later. */
+ *input_line_pointer = name_end;
+ } else {
+ S_SET_VALUE(def_symbol_in_progress, get_absolute_expression());
+ } /* if symbol based */
+
+ demand_empty_rest_of_line();
+ return;
+} /* obj_coff_val() */
+
+/*
+ * Maintain a list of the tagnames of the structres.
+ */
+
+static void tag_init() {
+ tag_hash = hash_new();
+ return ;
+} /* tag_init() */
+
+static void tag_insert(name, symbolP)
+char *name;
+symbolS *symbolP;
+{
+ register char * error_string;
+
+ if (*(error_string = hash_jam(tag_hash, name, (char *)symbolP))) {
+ as_fatal("Inserting \"%s\" into structure table failed: %s",
+ name, error_string);
+ }
+ return ;
+} /* tag_insert() */
+
+static symbolS *tag_find_or_make(name)
+char *name;
+{
+ symbolS *symbolP;
+
+ if ((symbolP = tag_find(name)) == NULL) {
+ symbolP = symbol_new(name,
+ SEG_UNKNOWN,
+ 0,
+ &zero_address_frag);
+
+ tag_insert(S_GET_NAME(symbolP), symbolP);
+ symbol_table_insert(symbolP);
+ } /* not found */
+
+ return(symbolP);
+} /* tag_find_or_make() */
+
+static symbolS *tag_find(name)
+char *name;
+{
+#ifdef STRIP_UNDERSCORE
+ if (*name == '_') name++;
+#endif /* STRIP_UNDERSCORE */
+ return((symbolS*)hash_find(tag_hash, name));
+} /* tag_find() */
+
+void obj_read_begin_hook() {
+ /* These had better be the same. Usually 18 bytes. */
+#ifndef BFD_HEADERS
+ know(sizeof(SYMENT) == sizeof(AUXENT));
+ know(SYMESZ == AUXESZ);
+#endif
+ tag_init();
+
+ return;
+} /* obj_read_begin_hook() */
+
+void obj_crawl_symbol_chain(headers)
+object_headers *headers;
+{
+ int symbol_number = 0;
+ lineno *lineP;
+ symbolS *last_functionP = NULL;
+ symbolS *last_tagP;
+ symbolS *symbolP;
+ symbolS *symbol_externP = NULL;
+ symbolS *symbol_extern_lastP = NULL;
+
+ /* Initialize the stack used to keep track of the matching .bb .be */
+ stack* block_stack = stack_init(512, sizeof(symbolS*));
+
+ /* JF deal with forward references first... */
+ for (symbolP = symbol_rootP; symbolP; symbolP = symbol_next(symbolP)) {
+
+ if (symbolP->sy_forward) {
+ S_SET_VALUE(symbolP, (S_GET_VALUE(symbolP)
+ + S_GET_VALUE(symbolP->sy_forward)
+ + symbolP->sy_forward->sy_frag->fr_address));
+
+ if (
+#ifndef TE_I386AIX
+ SF_GET_GET_SEGMENT(symbolP)
+#else
+ SF_GET_GET_SEGMENT(symbolP)
+ && S_GET_SEGMENT(symbolP) == SEG_UNKNOWN
+#endif /* TE_I386AIX */
+ ) {
+ S_SET_SEGMENT(symbolP, S_GET_SEGMENT(symbolP->sy_forward));
+ } /* forward segment also */
+
+ symbolP->sy_forward=0;
+ } /* if it has a forward reference */
+ } /* walk the symbol chain */
+
+ tc_crawl_symbol_chain(headers);
+
+ /* The symbol list should be ordered according to the following sequence
+ * order :
+ * . .file symbol
+ * . debug entries for functions
+ * . fake symbols for .text .data and .bss
+ * . defined symbols
+ * . undefined symbols
+ * But this is not mandatory. The only important point is to put the
+ * undefined symbols at the end of the list.
+ */
+
+ if (symbol_rootP == NULL
+ || S_GET_STORAGE_CLASS(symbol_rootP) != C_FILE) {
+ know(!previous_file_symbol);
+ c_dot_file_symbol("fake");
+ } /* Is there a .file symbol ? If not insert one at the beginning. */
+
+ /*
+ * Build up static symbols for .text, .data and .bss
+ */
+ dot_text_symbol = (symbolS*)
+ c_section_symbol(".text",
+ 0,
+ H_GET_TEXT_SIZE(headers),
+ 0/*text_relocation_number */,
+ 0/*text_lineno_number */);
+#ifdef TE_I386AIX
+ symbol_remove(dot_text_symbol, &symbol_rootP, &symbol_lastP);
+ symbol_append(dot_text_symbol, previous_file_symbol,
+ &symbol_rootP, &symbol_lastP);
+#endif /* TE_I386AIX */
+
+ dot_data_symbol = (symbolS*)
+ c_section_symbol(".data",
+ H_GET_TEXT_SIZE(headers),
+ H_GET_DATA_SIZE(headers),
+ 0/*data_relocation_number */,
+ 0); /* There are no data lineno entries */
+#ifdef TE_I386AIX
+ symbol_remove(dot_data_symbol, &symbol_rootP, &symbol_lastP);
+ symbol_append(dot_data_symbol, dot_text_symbol,
+ &symbol_rootP, &symbol_lastP);
+#endif /* TE_I386AIX */
+
+ dot_bss_symbol = (symbolS*)
+ c_section_symbol(".bss",
+ H_GET_TEXT_SIZE(headers) + H_GET_DATA_SIZE(headers),
+ H_GET_BSS_SIZE(headers),
+ 0, /* No relocation for a bss section. */
+ 0); /* There are no bss lineno entries */
+#ifdef TE_I386AIX
+ symbol_remove(dot_bss_symbol, &symbol_rootP, &symbol_lastP);
+ symbol_append(dot_bss_symbol, dot_data_symbol,
+ &symbol_rootP, &symbol_lastP);
+#endif /* TE_I386AIX */
+
+#if defined(DEBUG)
+ verify_symbol_chain(symbol_rootP, symbol_lastP);
+#endif /* DEBUG */
+
+ /* Three traversals of symbol chains here. The
+ first traversal yanks externals into a temporary
+ chain, removing the externals from the global
+ chain, numbers symbols, and does some other guck.
+ The second traversal is on the temporary chain of
+ externals and just appends them to the global
+ chain again, numbering them as we go. The third
+ traversal patches pointers to symbols (using sym
+ indexes). The last traversal was once done as
+ part of the first pass, but that fails when a
+ reference preceeds a definition as the definition
+ has no number at the time we process the
+ reference. */
+
+ /* Note that symbolP will be NULL at the end of a loop
+ if an external was at the beginning of the list (it
+ gets moved off the list). Hence the weird check in
+ the loop control.
+ */
+ for (symbolP = symbol_rootP;
+ symbolP;
+ symbolP = symbolP ? symbol_next(symbolP) : symbol_rootP) {
+ if (!SF_GET_DEBUG(symbolP)) {
+ /* Debug symbols do not need all this rubbish */
+ symbolS* real_symbolP;
+
+ /* L* and C_EFCN symbols never merge. */
+ if (!SF_GET_LOCAL(symbolP)
+ && (real_symbolP = symbol_find_base(S_GET_NAME(symbolP), DO_NOT_STRIP))
+ && real_symbolP != symbolP) {
+ /* FIXME-SOON: where do dups come from? Maybe tag references before definitions? xoxorich. */
+ /* Move the debug data from the debug symbol to the
+ real symbol. Do NOT do the oposite (i.e. move from
+ real symbol to debug symbol and remove real symbol from the
+ list.) Because some pointers refer to the real symbol
+ whereas no pointers refer to the debug symbol. */
+ c_symbol_merge(symbolP, real_symbolP);
+ /* Replace the current symbol by the real one */
+ /* The symbols will never be the last or the first
+ because : 1st symbol is .file and 3 last symbols are
+ .text, .data, .bss */
+ symbol_remove(real_symbolP, &symbol_rootP, &symbol_lastP);
+ symbol_insert(real_symbolP, symbolP, &symbol_rootP, &symbol_lastP);
+ symbol_remove(symbolP, &symbol_rootP, &symbol_lastP);
+ symbolP = real_symbolP;
+ } /* if not local but dup'd */
+
+ if (flagseen['R'] && (S_GET_SEGMENT(symbolP) == SEG_DATA)) {
+ S_SET_SEGMENT(symbolP, SEG_TEXT);
+ } /* push data into text */
+
+ S_SET_VALUE(symbolP, S_GET_VALUE(symbolP) + symbolP->sy_frag->fr_address);
+
+ if (!S_IS_DEFINED(symbolP) && !SF_GET_LOCAL(symbolP)) {
+ S_SET_EXTERNAL(symbolP);
+ } else if (S_GET_STORAGE_CLASS(symbolP) == C_NULL) {
+ if (S_GET_SEGMENT(symbolP) == SEG_TEXT){
+ S_SET_STORAGE_CLASS(symbolP, C_LABEL);
+ } else {
+ S_SET_STORAGE_CLASS(symbolP, C_STAT);
+ }
+ } /* no storage class yet */
+
+ /* Mainly to speed up if not -g */
+ if (SF_GET_PROCESS(symbolP)) {
+ /* Handle the nested blocks auxiliary info. */
+ if (S_GET_STORAGE_CLASS(symbolP) == C_BLOCK) {
+ if (!strcmp(S_GET_NAME(symbolP), ".bb"))
+ stack_push(block_stack, (char *) &symbolP);
+ else { /* .eb */
+ register symbolS* begin_symbolP;
+ begin_symbolP = *(symbolS**)stack_pop(block_stack);
+ if (begin_symbolP == (symbolS*)0)
+ as_warn("mismatched .eb");
+ else
+ SA_SET_SYM_ENDNDX(begin_symbolP, symbol_number+2);
+ }
+ }
+ /* If we are able to identify the type of a function, and we
+ are out of a function (last_functionP == 0) then, the
+ function symbol will be associated with an auxiliary
+ entry. */
+ if (last_functionP == (symbolS*)0 &&
+ SF_GET_FUNCTION(symbolP)) {
+ last_functionP = symbolP;
+
+ if (S_GET_NUMBER_AUXILIARY(symbolP) < 1) {
+ S_SET_NUMBER_AUXILIARY(symbolP, 1);
+ } /* make it at least 1 */
+
+ /* Clobber possible stale .dim information. */
+ memset(symbolP->sy_symbol.ost_auxent[0].x_sym.x_fcnary.x_ary.x_dimen,
+ '\0', sizeof(symbolP->sy_symbol.ost_auxent[0].x_sym.x_fcnary.x_ary.x_dimen));
+ }
+ /* The C_FCN doesn't need any additional information.
+ I don't even know if this is needed for sdb. But the
+ standard assembler generates it, so...
+ */
+ if (S_GET_STORAGE_CLASS(symbolP) == C_EFCN) {
+ if (last_functionP == (symbolS*)0)
+ as_fatal("C_EFCN symbol out of scope");
+ SA_SET_SYM_FSIZE(last_functionP,
+ (long)(S_GET_VALUE(symbolP) -
+ S_GET_VALUE(last_functionP)));
+ SA_SET_SYM_ENDNDX(last_functionP, symbol_number);
+ last_functionP = (symbolS*)0;
+ }
+ }
+ } else if (SF_GET_TAG(symbolP)) {
+ /* First descriptor of a structure must point to
+ the first slot after the structure description. */
+ last_tagP = symbolP;
+
+ } else if (S_GET_STORAGE_CLASS(symbolP) == C_EOS) {
+ /* +2 take in account the current symbol */
+ SA_SET_SYM_ENDNDX(last_tagP, symbol_number + 2);
+ } else if (S_GET_STORAGE_CLASS(symbolP) == C_FILE) {
+ if (S_GET_VALUE(symbolP)) {
+ S_SET_VALUE((symbolS *) S_GET_VALUE(symbolP), symbol_number);
+ S_SET_VALUE(symbolP, 0);
+ } /* no one points at the first .file symbol */
+ } /* if debug or tag or eos or file */
+
+ /* We must put the external symbols apart. The loader
+ does not bomb if we do not. But the references in
+ the endndx field for a .bb symbol are not corrected
+ if an external symbol is removed between .bb and .be.
+ I.e in the following case :
+ [20] .bb endndx = 22
+ [21] foo external
+ [22] .be
+ ld will move the symbol 21 to the end of the list but
+ endndx will still be 22 instead of 21. */
+
+
+ if (SF_GET_LOCAL(symbolP)) {
+ /* remove C_EFCN and LOCAL (L...) symbols */
+ /* next pointer remains valid */
+ symbol_remove(symbolP, &symbol_rootP, &symbol_lastP);
+
+ } else if (
+#ifdef TE_I386AIX
+ S_GET_STORAGE_CLASS(symbolP) == C_EXT && !SF_GET_FUNCTION(symbolP)
+#else /* not TE_I386AIX */
+ !S_IS_DEFINED(symbolP) && !S_IS_DEBUG(symbolP) && !SF_GET_STATICS(symbolP)
+#endif /* not TE_I386AIX */
+ ) {
+ /* if external, Remove from the list */
+ symbolS *hold = symbol_previous(symbolP);
+
+ symbol_remove(symbolP, &symbol_rootP, &symbol_lastP);
+ symbol_clear_list_pointers(symbolP);
+ symbol_append(symbolP, symbol_extern_lastP, &symbol_externP, &symbol_extern_lastP);
+ symbolP = hold;
+ } else {
+ if (SF_GET_STRING(symbolP)) {
+ symbolP->sy_name_offset = string_byte_count;
+ string_byte_count += strlen(S_GET_NAME(symbolP)) + 1;
+ } else {
+ symbolP->sy_name_offset = 0;
+ } /* fix "long" names */
+
+ symbolP->sy_number = symbol_number;
+ symbol_number += 1 + S_GET_NUMBER_AUXILIARY(symbolP);
+ } /* if local symbol */
+ } /* traverse the symbol list */
+
+ for (symbolP = symbol_externP; symbol_externP;) {
+ symbolS *tmp = symbol_externP;
+
+ /* append */
+ symbol_remove(tmp, &symbol_externP, &symbol_extern_lastP);
+ symbol_append(tmp, symbol_lastP, &symbol_rootP, &symbol_lastP);
+
+ /* and process */
+ if (SF_GET_STRING(tmp)) {
+ tmp->sy_name_offset = string_byte_count;
+ string_byte_count += strlen(S_GET_NAME(tmp)) + 1;
+ } else {
+ tmp->sy_name_offset = 0;
+ } /* fix "long" names */
+
+ tmp->sy_number = symbol_number;
+ symbol_number += 1 + S_GET_NUMBER_AUXILIARY(tmp);
+ } /* append the entire extern chain */
+
+ /* When a tag reference preceeds the tag definition,
+ the definition will not have a number at the time
+ we process the reference during the first
+ traversal. Thus, a second traversal. */
+
+ for (symbolP = symbol_rootP; symbolP; symbolP = symbol_next(symbolP)) {
+ if (SF_GET_TAGGED(symbolP)) {
+ SA_SET_SYM_TAGNDX(symbolP, ((symbolS*) SA_GET_SYM_TAGNDX(symbolP))->sy_number);
+ } /* If the symbol has a tagndx entry, resolve it */
+ } /* second traversal */
+
+ know(symbol_externP == NULL);
+ know(symbol_extern_lastP == NULL);
+
+ /* FIXME-SOMEDAY I'm counting line no's here so we know what to put in the section
+ headers, and I'm resolving the addresses since I'm not sure how to
+ do it later. I am NOT resolving the linno's representing functions.
+ Their symbols need a fileptr pointing to this linno when emitted.
+ Thus, I resolve them on emit. xoxorich. */
+
+ for (lineP = lineno_rootP; lineP; lineP = lineP->next) {
+ if (lineP->line.l_lnno > 0) {
+ lineP->line.l_addr.l_paddr += ((fragS*)lineP->frag)->fr_address;
+ } else {
+ ;
+ }
+ text_lineno_number++;
+ } /* for each line number */
+
+ H_SET_SYMBOL_TABLE_SIZE(headers, symbol_number);
+
+ return;
+} /* obj_crawl_symbol_chain() */
+
+/*
+ * Find strings by crawling along symbol table chain.
+ */
+
+void obj_emit_strings(where)
+char **where;
+{
+ symbolS *symbolP;
+
+#ifdef CROSS_COMPILE
+ /* Gotta do md_ byte-ordering stuff for string_byte_count first - KWK */
+ md_number_to_chars(*where, string_byte_count, sizeof(string_byte_count));
+ *where += sizeof(string_byte_count);
+#else /* CROSS_COMPILE */
+ append(where, (char *) &string_byte_count, (unsigned long) sizeof(string_byte_count));
+#endif /* CROSS_COMPILE */
+
+ for (symbolP = symbol_rootP; symbolP; symbolP = symbol_next(symbolP)) {
+ if (SF_GET_STRING(symbolP)) {
+ append(where, S_GET_NAME(symbolP), (unsigned long)(strlen(S_GET_NAME(symbolP)) + 1));
+ } /* if it has a string */
+ } /* walk the symbol chain */
+
+ return;
+} /* obj_emit_strings() */
+
+void obj_pre_write_hook(headers)
+object_headers *headers;
+{
+ register int text_relocation_number = 0;
+ register int data_relocation_number = 0;
+ register fixS *fixP;
+
+ H_SET_MAGIC_NUMBER(headers, FILE_HEADER_MAGIC);
+ H_SET_ENTRY_POINT(headers, 0);
+
+ /* FIXME-SOMEDAY this should be done at
+ fixup_segment time but I'm going to wait until I
+ do multiple segments. xoxorich. */
+ /* Count the number of relocation entries for text and data */
+ for (fixP = text_fix_root; fixP; fixP = fixP->fx_next) {
+ if (fixP->fx_addsy) {
+ ++text_relocation_number;
+#ifdef TC_I960
+ /* two relocs per callj under coff. */
+ if (fixP->fx_callj) {
+ ++text_relocation_number;
+ } /* if callj and not already fixed. */
+#endif /* TC_I960 */
+#ifdef TC_A29K
+ /* Count 2 for a constH */
+ if (fixP->fx_r_type == RELOC_CONSTH) {
+ ++text_relocation_number;
+ }
+#endif
+
+ } /* if not yet fixed */
+ } /* for each fix */
+
+ SA_SET_SCN_NRELOC(dot_text_symbol, text_relocation_number);
+ /* Assign the number of line number entries for the text section */
+ SA_SET_SCN_NLINNO(dot_text_symbol, text_lineno_number);
+ /* Assign the size of the section */
+ SA_SET_SCN_SCNLEN(dot_text_symbol, H_GET_TEXT_SIZE(headers));
+
+ for (fixP = data_fix_root; fixP; fixP = fixP->fx_next) {
+ if (fixP->fx_addsy) {
+ ++data_relocation_number;
+ } /* if still relocatable */
+#ifdef TC_A29K
+ /* Count 2 for a constH */
+ if (fixP->fx_r_type == RELOC_CONSTH) {
+ ++data_relocation_number;
+ }
+#endif
+
+ } /* for each fix */
+
+
+ SA_SET_SCN_NRELOC(dot_data_symbol, data_relocation_number);
+ /* Assign the size of the section */
+ SA_SET_SCN_SCNLEN(dot_data_symbol, H_GET_DATA_SIZE(headers));
+
+ /* Assign the size of the section */
+ SA_SET_SCN_SCNLEN(dot_bss_symbol, H_GET_BSS_SIZE(headers));
+
+ /* pre write hook can add relocs (for 960 and 29k coff) so */
+ headers->relocation_size = text_relocation_number * RELSZ +
+ data_relocation_number *RELSZ;
+
+
+
+ /* Fill in extra coff fields */
+
+ /* Initialize general line number information. */
+ H_SET_LINENO_SIZE(headers, text_lineno_number * LINESZ);
+
+ /* filehdr */
+ H_SET_FILE_MAGIC_NUMBER(headers, FILE_HEADER_MAGIC);
+ H_SET_NUMBER_OF_SECTIONS(headers, 3); /* text+data+bss */
+#ifndef OBJ_COFF_OMIT_TIMESTAMP
+ H_SET_TIME_STAMP(headers, (long)time((long*)0));
+#else /* OBJ_COFF_OMIT_TIMESTAMP */
+ H_SET_TIME_STAMP(headers, 0);
+#endif /* OBJ_COFF_OMIT_TIMESTAMP */
+ H_SET_SYMBOL_TABLE_POINTER(headers, H_GET_SYMBOL_TABLE_FILE_OFFSET(headers));
+#if 0
+ printf("FILHSZ %x\n", FILHSZ);
+ printf("OBJ_COFF_AOUTHDRSZ %x\n", OBJ_COFF_AOUTHDRSZ);
+ printf("section headers %x\n", H_GET_NUMBER_OF_SECTIONS(headers) * SCNHSZ);
+ printf("get text size %x\n", H_GET_TEXT_SIZE(headers));
+ printf("get data size %x\n", H_GET_DATA_SIZE(headers));
+ printf("get relocation size %x\n", H_GET_RELOCATION_SIZE(headers));
+ printf("get lineno size %x\n", H_GET_LINENO_SIZE(headers));
+#endif
+ /* symbol table size allready set */
+ H_SET_SIZEOF_OPTIONAL_HEADER(headers, OBJ_COFF_AOUTHDRSZ);
+
+ /* do not added the F_RELFLG for the standard COFF.
+ * The AIX linker complain on file with relocation info striped flag.
+ */
+#ifdef KEEP_RELOC_INFO
+ H_SET_FLAGS(headers, (text_lineno_number == 0 ? F_LNNO : 0)
+ | BYTE_ORDERING);
+#else
+ H_SET_FLAGS(headers, (text_lineno_number == 0 ? F_LNNO : 0)
+ | ((text_relocation_number + data_relocation_number) ? 0 : F_RELFLG)
+ | BYTE_ORDERING);
+#endif
+ /* aouthdr */
+ /* magic number allready set */
+ H_SET_VERSION_STAMP(headers, 0);
+ /* Text, data, bss size; entry point; text_start and data_start are already set */
+
+ /* Build section headers */
+
+ c_section_header(&text_section_header,
+ ".text",
+ 0,
+ H_GET_TEXT_SIZE(headers),
+ H_GET_TEXT_FILE_OFFSET(headers),
+ (SA_GET_SCN_NRELOC(dot_text_symbol)
+ ? H_GET_RELOCATION_FILE_OFFSET(headers)
+ : 0),
+ (text_lineno_number
+ ? H_GET_LINENO_FILE_OFFSET(headers)
+ : 0),
+ SA_GET_SCN_NRELOC(dot_text_symbol),
+ text_lineno_number,
+ section_alignment[(int) SEG_TEXT]);
+
+ c_section_header(&data_section_header,
+ ".data",
+ H_GET_TEXT_SIZE(headers),
+ H_GET_DATA_SIZE(headers),
+ (H_GET_DATA_SIZE(headers)
+ ? H_GET_DATA_FILE_OFFSET(headers)
+ : 0),
+ (SA_GET_SCN_NRELOC(dot_data_symbol)
+ ? (H_GET_RELOCATION_FILE_OFFSET(headers)
+ + text_section_header.s_nreloc * RELSZ)
+ : 0),
+ 0, /* No line number information */
+ SA_GET_SCN_NRELOC(dot_data_symbol),
+ 0, /* No line number information */
+ section_alignment[(int) SEG_DATA]);
+
+ c_section_header(&bss_section_header,
+ ".bss",
+ H_GET_TEXT_SIZE(headers) + H_GET_DATA_SIZE(headers),
+ H_GET_BSS_SIZE(headers),
+ 0, /* No file offset */
+ 0, /* No relocation information */
+ 0, /* No line number information */
+ 0, /* No relocation information */
+ 0, /* No line number information */
+ section_alignment[(int) SEG_BSS]);
+
+ return;
+} /* obj_pre_write_hook() */
+
+/* This is a copy from aout. All I do is neglect to actually build the symbol. */
+
+static void obj_coff_stab(what)
+int what;
+{
+ char *string;
+ expressionS e;
+ int goof = 0; /* TRUE if we have aborted. */
+ int length;
+ int saved_type = 0;
+ long longint;
+ symbolS *symbolP = 0;
+
+ if (what == 's') {
+ string = demand_copy_C_string(&length);
+ SKIP_WHITESPACE();
+
+ if (*input_line_pointer == ',') {
+ input_line_pointer++;
+ } else {
+ as_bad("I need a comma after symbol's name");
+ goof = 1;
+ } /* better be a comma */
+ } /* skip the string */
+
+ /*
+ * Input_line_pointer->after ','. String->symbol name.
+ */
+ if (!goof) {
+ if (get_absolute_expression_and_terminator(&longint) != ',') {
+ as_bad("I want a comma after the n_type expression");
+ goof = 1;
+ input_line_pointer--; /* Backup over a non-',' char. */
+ } /* on error */
+ } /* no error */
+
+ if (!goof) {
+ if (get_absolute_expression_and_terminator(&longint) != ',') {
+ as_bad("I want a comma after the n_other expression");
+ goof = 1;
+ input_line_pointer--; /* Backup over a non-',' char. */
+ } /* on error */
+ } /* no error */
+
+ if (!goof) {
+ get_absolute_expression();
+
+ if (what == 's' || what == 'n') {
+ if (*input_line_pointer != ',') {
+ as_bad("I want a comma after the n_desc expression");
+ goof = 1;
+ } else {
+ input_line_pointer++;
+ } /* on goof */
+ } /* not stabd */
+ } /* no error */
+
+ expression(&e);
+
+ if (goof) {
+ ignore_rest_of_line();
+ } else {
+ demand_empty_rest_of_line();
+ } /* on error */
+} /* obj_coff_stab() */
+
+#ifdef DEBUG
+/* for debugging */
+char *s_get_name(s)
+symbolS *s;
+{
+ return((s == NULL) ? "(NULL)" : S_GET_NAME(s));
+} /* s_get_name() */
+
+void symbol_dump() {
+ symbolS *symbolP;
+
+ for (symbolP = symbol_rootP; symbolP; symbolP = symbol_next(symbolP)) {
+ printf("%3ld: 0x%lx \"%s\" type = %ld, class = %d, segment = %d\n",
+ symbolP->sy_number,
+ (unsigned long) symbolP,
+ S_GET_NAME(symbolP),
+ (long) S_GET_DATA_TYPE(symbolP),
+ S_GET_STORAGE_CLASS(symbolP),
+ (int) S_GET_SEGMENT(symbolP));
+ } /* traverse symbols */
+
+ return;
+} /* symbol_dump() */
+#endif /* DEBUG */
+
+
+/*
+ * Local Variables:
+ * comment-column: 0
+ * fill-column: 131
+ * End:
+ */
+
+/* end of obj-coff.c */
diff --git a/gnu/usr.bin/as/config/obj-coff.h b/gnu/usr.bin/as/config/obj-coff.h
new file mode 100644
index 0000000..3f1f7ea
--- /dev/null
+++ b/gnu/usr.bin/as/config/obj-coff.h
@@ -0,0 +1,598 @@
+/* coff object file format
+ Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
+
+ This file is part of GAS.
+
+ GAS is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GAS is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GAS; see the file COPYING. If not, write to
+ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#define OBJ_COFF 1
+
+#include "targ-cpu.h"
+
+
+
+#ifdef BFD_HEADERS
+#ifdef TC_A29K
+#include "bfd.h"
+#include "coff/a29k.h"
+
+/* This internal_lineno crap is to stop namespace pollution from the bfd internal
+ coff headerfile. */
+
+#define internal_lineno bfd_internal_lineno
+#include "coff/internal.h"
+#undef internal_lineno
+/*
+ #undef RELOC
+ #undef SYMENT
+ #undef AUXENT
+ #undef LINENO
+ #undef FILHDR
+ #undef SCNHDR
+ #define RELOC struct internal_reloc
+ #define SYMENT struct internal_syment
+ #define AUXENT union internal_auxent
+ #define SCNHDR struct internal_scnhdr
+ #define LINENO struct bfd_internal_lineno
+ #define AOUTHDR struct internal_aouthdr
+ #define FILHDR struct internal_filehdr
+ #define AOUTHDRSZ sizeof(struct external_aouthdr)
+ */
+/*#define x_endndx x_endndx.l
+ #define x_tagndx x_tagndx.l*/
+#define TARGET_FORMAT "coff-a29k-big"
+extern bfd *stdoutput;
+
+#else /* not TC_A29K */
+# ifdef TC_I386
+# include "bfd.h"
+# include "coff/i386.h"
+# define internal_lineno bfd_internal_lineno
+# include "coff/internal.h"
+# undef internal_lineno
+# define TARGET_FORMAT "coff-i386"
+extern bfd *stdoutput;
+
+#else /* not TC_I386 */
+#error help me
+#endif /* not TC_I386 */
+
+#endif /* not TC_A29K */
+
+#else /* not BFD_HEADERS */
+
+#ifdef USE_NATIVE_HEADERS
+#include <filehdr.h>
+#include <aouthdr.h>
+#include <scnhdr.h>
+#include <storclass.h>
+#include <linenum.h>
+#include <syms.h>
+#include <reloc.h>
+#include <sys/types.h>
+#else /* not USE_NATIVE_HEADERS */
+#include "coff.h"
+#endif /* not USE_NATIVE_HEADERS */
+
+#endif /* not BFD_HEADERS */
+
+/* Define some processor dependent values according to the processor we are on. */
+#ifdef TC_M68K
+
+#define BYTE_ORDERING F_AR32W /* See filehdr.h for more info. */
+#ifndef FILE_HEADER_MAGIC
+#define FILE_HEADER_MAGIC MC68MAGIC /* ... */
+#endif /* FILE_HEADER_MAGIC */
+
+#elif defined(TC_I386)
+
+#define BYTE_ORDERING F_AR32WR /* See filehdr.h for more info. */
+#ifndef FILE_HEADER_MAGIC
+#define FILE_HEADER_MAGIC I386MAGIC /* ... */
+#endif /* FILE_HEADER_MAGIC */
+
+#elif defined(TC_I960)
+
+#define BYTE_ORDERING F_AR32WR /* See filehdr.h for more info. */
+#ifndef FILE_HEADER_MAGIC
+#define FILE_HEADER_MAGIC I960ROMAGIC /* ... */
+#endif /* FILE_HEADER_MAGIC */
+
+#elif defined(TC_A29K)
+
+#define BYTE_ORDERING F_AR32W /* big endian. */
+#ifndef FILE_HEADER_MAGIC
+#define FILE_HEADER_MAGIC SIPFBOMAGIC
+#endif /* FILE_HEADER_MAGIC */
+
+#else
+you lose
+#endif
+
+#ifndef OBJ_COFF_MAX_AUXENTRIES
+#define OBJ_COFF_MAX_AUXENTRIES 1
+#endif /* OBJ_COFF_MAX_AUXENTRIES */
+
+ extern const short seg_N_TYPE[];
+extern const segT N_TYPE_seg[];
+
+#ifndef BFD_HEADERS
+
+/* Add these definitions to have a consistent convention for all the
+ types used in COFF format. */
+#define AOUTHDR struct aouthdr
+#define AOUTHDRSZ sizeof(AOUTHDR)
+#endif
+
+/* SYMBOL TABLE */
+
+/* targets may also set this */
+#ifndef SYMBOLS_NEED_BACKPOINTERS
+#define SYMBOLS_NEED_BACKPOINTERS 1
+#endif /* SYMBOLS_NEED_BACKPOINTERS */
+
+/* Symbol table entry data type */
+
+typedef struct {
+#ifdef BFD_HEADERS
+ struct internal_syment ost_entry; /* Basic symbol */
+ union internal_auxent ost_auxent[OBJ_COFF_MAX_AUXENTRIES]; /* Auxiliary entry. */
+#else
+ SYMENT ost_entry; /* Basic symbol */
+ AUXENT ost_auxent[OBJ_COFF_MAX_AUXENTRIES]; /* Auxiliary entry. */
+#endif
+ unsigned int ost_flags; /* obj_coff internal use only flags */
+} obj_symbol_type;
+
+#define DO_NOT_STRIP 0
+#define DO_STRIP 1
+
+/* Symbol table macros and constants */
+
+/* Possible and usefull section number in symbol table
+ * The values of TEXT, DATA and BSS may not be portable.
+ */
+
+#define C_TEXT_SECTION ((short)1)
+#define C_DATA_SECTION ((short)2)
+#define C_BSS_SECTION ((short)3)
+#define C_ABS_SECTION N_ABS
+#define C_UNDEF_SECTION N_UNDEF
+#define C_DEBUG_SECTION N_DEBUG
+#define C_NTV_SECTION N_TV
+#define C_PTV_SECTION P_TV
+#define C_REGISTER_SECTION 4
+
+/*
+ * Macros to extract information from a symbol table entry.
+ * This syntaxic indirection allows independence regarding a.out or coff.
+ * The argument (s) of all these macros is a pointer to a symbol table entry.
+ */
+
+/* Predicates */
+/* True if the symbol is external */
+#define S_IS_EXTERNAL(s) ((s)->sy_symbol.ost_entry.n_scnum == C_UNDEF_SECTION)
+/* True if symbol has been defined, ie :
+ section > 0 (DATA, TEXT or BSS)
+ section == 0 and value > 0 (external bss symbol) */
+#define S_IS_DEFINED(s) ((s)->sy_symbol.ost_entry.n_scnum > C_UNDEF_SECTION || \
+ ((s)->sy_symbol.ost_entry.n_scnum == C_UNDEF_SECTION && \
+ (s)->sy_symbol.ost_entry.n_value > 0))
+/* True if a debug special symbol entry */
+#define S_IS_DEBUG(s) ((s)->sy_symbol.ost_entry.n_scnum == C_DEBUG_SECTION)
+/* True if a symbol is local symbol name */
+/* A symbol name whose name begin with ^A is a gas internal pseudo symbol */
+#define S_IS_LOCAL(s) (S_GET_NAME(s)[0] == '\001' || \
+ (s)->sy_symbol.ost_entry.n_scnum == C_REGISTER_SECTION || \
+ (S_LOCAL_NAME(s) && !flagseen['L']))
+/* True if a symbol is not defined in this file */
+#define S_IS_EXTERN(s) ((s)->sy_symbol.ost_entry.n_scnum == 0 && (s)->sy_symbol.ost_entry.n_value == 0)
+/*
+ * True if a symbol can be multiply defined (bss symbols have this def
+ * though it is bad practice)
+ */
+#define S_IS_COMMON(s) ((s)->sy_symbol.ost_entry.n_scnum == 0 && (s)->sy_symbol.ost_entry.n_value != 0)
+/* True if a symbol name is in the string table, i.e. its length is > 8. */
+#define S_IS_STRING(s) (strlen(S_GET_NAME(s)) > 8 ? 1 : 0)
+
+/* Accessors */
+/* The name of the symbol */
+#define S_GET_NAME(s) ((char*)(s)->sy_symbol.ost_entry.n_offset)
+/* The pointer to the string table */
+#define S_GET_OFFSET(s) ((s)->sy_symbol.ost_entry.n_offset)
+/* The zeroes if symbol name is longer than 8 chars */
+#define S_GET_ZEROES(s) ((s)->sy_symbol.ost_entry.n_zeroes)
+/* The value of the symbol */
+#define S_GET_VALUE(s) ((unsigned) ((s)->sy_symbol.ost_entry.n_value))
+/* The numeric value of the segment */
+#define S_GET_SEGMENT(s) (N_TYPE_seg[(s)->sy_symbol.ost_entry.n_scnum+4])
+/* The data type */
+#define S_GET_DATA_TYPE(s) ((s)->sy_symbol.ost_entry.n_type)
+/* The storage class */
+#define S_GET_STORAGE_CLASS(s) ((s)->sy_symbol.ost_entry.n_sclass)
+/* The number of auxiliary entries */
+#define S_GET_NUMBER_AUXILIARY(s) ((s)->sy_symbol.ost_entry.n_numaux)
+
+/* Modifiers */
+/* Set the name of the symbol */
+#define S_SET_NAME(s,v) ((s)->sy_symbol.ost_entry.n_offset = (unsigned long)(v))
+/* Set the offset of the symbol */
+#define S_SET_OFFSET(s,v) ((s)->sy_symbol.ost_entry.n_offset = (v))
+/* The zeroes if symbol name is longer than 8 chars */
+#define S_SET_ZEROES(s,v) ((s)->sy_symbol.ost_entry.n_zeroes = (v))
+/* Set the value of the symbol */
+#define S_SET_VALUE(s,v) ((s)->sy_symbol.ost_entry.n_value = (v))
+/* The numeric value of the segment */
+#define S_SET_SEGMENT(s,v) ((s)->sy_symbol.ost_entry.n_scnum = SEGMENT_TO_SYMBOL_TYPE(v))
+/* The data type */
+#define S_SET_DATA_TYPE(s,v) ((s)->sy_symbol.ost_entry.n_type = (v))
+/* The storage class */
+#define S_SET_STORAGE_CLASS(s,v) ((s)->sy_symbol.ost_entry.n_sclass = (v))
+/* The number of auxiliary entries */
+#define S_SET_NUMBER_AUXILIARY(s,v) ((s)->sy_symbol.ost_entry.n_numaux = (v))
+
+/* Additional modifiers */
+/* The symbol is external (does not mean undefined) */
+#define S_SET_EXTERNAL(s) { S_SET_STORAGE_CLASS(s, C_EXT) ; SF_CLEAR_LOCAL(s); }
+
+/* Auxiliary entry macros. SA_ stands for symbol auxiliary */
+/* Omit the tv related fields */
+/* Accessors */
+#ifdef BFD_HEADERS
+#define SA_GET_SYM_TAGNDX(s) ((s)->sy_symbol.ost_auxent[0].x_sym.x_tagndx.l)
+#else
+#define SA_GET_SYM_TAGNDX(s) ((s)->sy_symbol.ost_auxent[0].x_sym.x_tagndx)
+#endif
+#define SA_GET_SYM_LNNO(s) ((s)->sy_symbol.ost_auxent[0].x_sym.x_misc.x_lnsz.x_lnno)
+#define SA_GET_SYM_SIZE(s) ((s)->sy_symbol.ost_auxent[0].x_sym.x_misc.x_lnsz.x_size)
+#define SA_GET_SYM_FSIZE(s) ((s)->sy_symbol.ost_auxent[0].x_sym.x_misc.x_fsize)
+#define SA_GET_SYM_LNNOPTR(s) ((s)->sy_symbol.ost_auxent[0].x_sym.x_fcnary.x_fcn.x_lnnoptr)
+#ifdef BFD_HEADERS
+#define SA_GET_SYM_ENDNDX(s) ((s)->sy_symbol.ost_auxent[0].x_sym.x_fcnary.x_fcn.x_endndx.l)
+#else
+#define SA_GET_SYM_ENDNDX(s) ((s)->sy_symbol.ost_auxent[0].x_sym.x_fcnary.x_fcn.x_endndx)
+#endif
+#define SA_GET_SYM_DIMEN(s,i) ((s)->sy_symbol.ost_auxent[0].x_sym.x_fcnary.x_ary.x_dimen[(i)])
+#define SA_GET_FILE_FNAME(s) ((s)->sy_symbol.ost_auxent[0].x_file.x_fname)
+#define SA_GET_SCN_SCNLEN(s) ((s)->sy_symbol.ost_auxent[0].x_scn.x_scnlen)
+#define SA_GET_SCN_NRELOC(s) ((s)->sy_symbol.ost_auxent[0].x_scn.x_nreloc)
+#define SA_GET_SCN_NLINNO(s) ((s)->sy_symbol.ost_auxent[0].x_scn.x_nlinno)
+
+/* Modifiers */
+#ifdef BFD_HEADERS
+#define SA_SET_SYM_TAGNDX(s,v) ((s)->sy_symbol.ost_auxent[0].x_sym.x_tagndx.l=(v))
+#else
+#define SA_SET_SYM_TAGNDX(s,v) ((s)->sy_symbol.ost_auxent[0].x_sym.x_tagndx=(v))
+#endif
+#define SA_SET_SYM_LNNO(s,v) ((s)->sy_symbol.ost_auxent[0].x_sym.x_misc.x_lnsz.x_lnno=(v))
+#define SA_SET_SYM_SIZE(s,v) ((s)->sy_symbol.ost_auxent[0].x_sym.x_misc.x_lnsz.x_size=(v))
+#define SA_SET_SYM_FSIZE(s,v) ((s)->sy_symbol.ost_auxent[0].x_sym.x_misc.x_fsize=(v))
+#define SA_SET_SYM_LNNOPTR(s,v) ((s)->sy_symbol.ost_auxent[0].x_sym.x_fcnary.x_fcn.x_lnnoptr=(v))
+#ifdef BFD_HEADERS
+#define SA_SET_SYM_ENDNDX(s,v) ((s)->sy_symbol.ost_auxent[0].x_sym.x_fcnary.x_fcn.x_endndx.l=(v))
+#else
+#define SA_SET_SYM_ENDNDX(s,v) ((s)->sy_symbol.ost_auxent[0].x_sym.x_fcnary.x_fcn.x_endndx=(v))
+#endif
+#define SA_SET_SYM_DIMEN(s,i,v) ((s)->sy_symbol.ost_auxent[0].x_sym.x_fcnary.x_ary.x_dimen[(i)]=(v))
+#define SA_SET_FILE_FNAME(s,v) strncpy((s)->sy_symbol.ost_auxent[0].x_file.x_fname,(v),FILNMLEN)
+#define SA_SET_SCN_SCNLEN(s,v) ((s)->sy_symbol.ost_auxent[0].x_scn.x_scnlen=(v))
+#define SA_SET_SCN_NRELOC(s,v) ((s)->sy_symbol.ost_auxent[0].x_scn.x_nreloc=(v))
+#define SA_SET_SCN_NLINNO(s,v) ((s)->sy_symbol.ost_auxent[0].x_scn.x_nlinno=(v))
+
+/*
+ * Internal use only definitions. SF_ stands for symbol flags.
+ *
+ * These values can be assigned to sy_symbol.ost_flags field of a symbolS.
+ *
+ * You'll break i960 if you shift the SYSPROC bits anywhere else. for
+ * more on the balname/callname hack, see tc-i960.h. b.out is done
+ * differently.
+ */
+
+#define SF_I960_MASK (0x000001ff) /* Bits 0-8 are used by the i960 port. */
+#define SF_SYSPROC (0x0000003f) /* bits 0-5 are used to store the sysproc number */
+#define SF_IS_SYSPROC (0x00000040) /* bit 6 marks symbols that are sysprocs */
+#define SF_BALNAME (0x00000080) /* bit 7 marks BALNAME symbols */
+#define SF_CALLNAME (0x00000100) /* bit 8 marks CALLNAME symbols */
+
+#define SF_NORMAL_MASK (0x0000ffff) /* bits 12-15 are general purpose. */
+
+#define SF_STATICS (0x00001000) /* Mark the .text & all symbols */
+#define SF_DEFINED (0x00002000) /* Symbol is defined in this file */
+#define SF_STRING (0x00004000) /* Symbol name length > 8 */
+#define SF_LOCAL (0x00008000) /* Symbol must not be emitted */
+
+#define SF_DEBUG_MASK (0xffff0000) /* bits 16-31 are debug info */
+
+#define SF_FUNCTION (0x00010000) /* The symbol is a function */
+#define SF_PROCESS (0x00020000) /* Process symbol before write */
+#define SF_TAGGED (0x00040000) /* Is associated with a tag */
+#define SF_TAG (0x00080000) /* Is a tag */
+#define SF_DEBUG (0x00100000) /* Is in debug or abs section */
+#define SF_GET_SEGMENT (0x00200000) /* Get the section of the forward symbol. */
+/* All other bits are unused. */
+
+/* Accessors */
+#define SF_GET(s) ((s)->sy_symbol.ost_flags)
+#define SF_GET_NORMAL_FIELD(s) ((s)->sy_symbol.ost_flags & SF_NORMAL_MASK)
+#define SF_GET_DEBUG_FIELD(s) ((s)->sy_symbol.ost_flags & SF_DEBUG_MASK)
+#define SF_GET_FILE(s) ((s)->sy_symbol.ost_flags & SF_FILE)
+#define SF_GET_STATICS(s) ((s)->sy_symbol.ost_flags & SF_STATICS)
+#define SF_GET_DEFINED(s) ((s)->sy_symbol.ost_flags & SF_DEFINED)
+#define SF_GET_STRING(s) ((s)->sy_symbol.ost_flags & SF_STRING)
+#define SF_GET_LOCAL(s) ((s)->sy_symbol.ost_flags & SF_LOCAL)
+#define SF_GET_FUNCTION(s) ((s)->sy_symbol.ost_flags & SF_FUNCTION)
+#define SF_GET_PROCESS(s) ((s)->sy_symbol.ost_flags & SF_PROCESS)
+#define SF_GET_DEBUG(s) ((s)->sy_symbol.ost_flags & SF_DEBUG)
+#define SF_GET_TAGGED(s) ((s)->sy_symbol.ost_flags & SF_TAGGED)
+#define SF_GET_TAG(s) ((s)->sy_symbol.ost_flags & SF_TAG)
+#define SF_GET_GET_SEGMENT(s) ((s)->sy_symbol.ost_flags & SF_GET_SEGMENT)
+#define SF_GET_I960(s) ((s)->sy_symbol.ost_flags & SF_I960_MASK) /* used by i960 */
+#define SF_GET_BALNAME(s) ((s)->sy_symbol.ost_flags & SF_BALNAME) /* used by i960 */
+#define SF_GET_CALLNAME(s) ((s)->sy_symbol.ost_flags & SF_CALLNAME) /* used by i960 */
+#define SF_GET_IS_SYSPROC(s) ((s)->sy_symbol.ost_flags & SF_IS_SYSPROC) /* used by i960 */
+#define SF_GET_SYSPROC(s) ((s)->sy_symbol.ost_flags & SF_SYSPROC) /* used by i960 */
+
+/* Modifiers */
+#define SF_SET(s,v) ((s)->sy_symbol.ost_flags = (v))
+#define SF_SET_NORMAL_FIELD(s,v)((s)->sy_symbol.ost_flags |= ((v) & SF_NORMAL_MASK))
+#define SF_SET_DEBUG_FIELD(s,v) ((s)->sy_symbol.ost_flags |= ((v) & SF_DEBUG_MASK))
+#define SF_SET_FILE(s) ((s)->sy_symbol.ost_flags |= SF_FILE)
+#define SF_SET_STATICS(s) ((s)->sy_symbol.ost_flags |= SF_STATICS)
+#define SF_SET_DEFINED(s) ((s)->sy_symbol.ost_flags |= SF_DEFINED)
+#define SF_SET_STRING(s) ((s)->sy_symbol.ost_flags |= SF_STRING)
+#define SF_SET_LOCAL(s) ((s)->sy_symbol.ost_flags |= SF_LOCAL)
+#define SF_CLEAR_LOCAL(s) ((s)->sy_symbol.ost_flags &= ~SF_LOCAL)
+#define SF_SET_FUNCTION(s) ((s)->sy_symbol.ost_flags |= SF_FUNCTION)
+#define SF_SET_PROCESS(s) ((s)->sy_symbol.ost_flags |= SF_PROCESS)
+#define SF_SET_DEBUG(s) ((s)->sy_symbol.ost_flags |= SF_DEBUG)
+#define SF_SET_TAGGED(s) ((s)->sy_symbol.ost_flags |= SF_TAGGED)
+#define SF_SET_TAG(s) ((s)->sy_symbol.ost_flags |= SF_TAG)
+#define SF_SET_GET_SEGMENT(s) ((s)->sy_symbol.ost_flags |= SF_GET_SEGMENT)
+#define SF_SET_I960(s,v) ((s)->sy_symbol.ost_flags |= ((v) & SF_I960_MASK)) /* used by i960 */
+#define SF_SET_BALNAME(s) ((s)->sy_symbol.ost_flags |= SF_BALNAME) /* used by i960 */
+#define SF_SET_CALLNAME(s) ((s)->sy_symbol.ost_flags |= SF_CALLNAME) /* used by i960 */
+#define SF_SET_IS_SYSPROC(s) ((s)->sy_symbol.ost_flags |= SF_IS_SYSPROC) /* used by i960 */
+#define SF_SET_SYSPROC(s,v) ((s)->sy_symbol.ost_flags |= ((v) & SF_SYSPROC)) /* used by i960 */
+
+/* File header macro and type definition */
+
+/*
+ * File position calculators. Beware to use them when all the
+ * appropriate fields are set in the header.
+ */
+
+#ifdef OBJ_COFF_OMIT_OPTIONAL_HEADER
+#define OBJ_COFF_AOUTHDRSZ (0)
+#else
+#define OBJ_COFF_AOUTHDRSZ (AOUTHDRSZ)
+#endif /* OBJ_COFF_OMIT_OPTIONAL_HEADER */
+
+#define H_GET_FILE_SIZE(h) \
+ (long)(FILHSZ + OBJ_COFF_AOUTHDRSZ + \
+ H_GET_NUMBER_OF_SECTIONS(h) * SCNHSZ + \
+ H_GET_TEXT_SIZE(h) + H_GET_DATA_SIZE(h) + \
+ H_GET_RELOCATION_SIZE(h) + H_GET_LINENO_SIZE(h) + \
+ H_GET_SYMBOL_TABLE_SIZE(h) + \
+ (h)->string_table_size)
+#define H_GET_TEXT_FILE_OFFSET(h) \
+ (long)(FILHSZ + OBJ_COFF_AOUTHDRSZ + \
+ H_GET_NUMBER_OF_SECTIONS(h) * SCNHSZ)
+#define H_GET_DATA_FILE_OFFSET(h) \
+ (long)(FILHSZ + OBJ_COFF_AOUTHDRSZ + \
+ H_GET_NUMBER_OF_SECTIONS(h) * SCNHSZ + \
+ H_GET_TEXT_SIZE(h))
+#define H_GET_BSS_FILE_OFFSET(h) 0
+#define H_GET_RELOCATION_FILE_OFFSET(h) \
+ (long)(FILHSZ + OBJ_COFF_AOUTHDRSZ + \
+ H_GET_NUMBER_OF_SECTIONS(h) * SCNHSZ + \
+ H_GET_TEXT_SIZE(h) + H_GET_DATA_SIZE(h))
+#define H_GET_LINENO_FILE_OFFSET(h) \
+ (long)(FILHSZ + OBJ_COFF_AOUTHDRSZ + \
+ H_GET_NUMBER_OF_SECTIONS(h) * SCNHSZ + \
+ H_GET_TEXT_SIZE(h) + H_GET_DATA_SIZE(h) + \
+ H_GET_RELOCATION_SIZE(h))
+#define H_GET_SYMBOL_TABLE_FILE_OFFSET(h) \
+ (long)(FILHSZ + OBJ_COFF_AOUTHDRSZ + \
+ H_GET_NUMBER_OF_SECTIONS(h) * SCNHSZ + \
+ H_GET_TEXT_SIZE(h) + H_GET_DATA_SIZE(h) + \
+ H_GET_RELOCATION_SIZE(h) + H_GET_LINENO_SIZE(h))
+
+/* Accessors */
+/* aouthdr */
+#define H_GET_MAGIC_NUMBER(h) ((h)->aouthdr.magic)
+#define H_GET_VERSION_STAMP(h) ((h)->aouthdr.vstamp)
+#define H_GET_TEXT_SIZE(h) ((h)->aouthdr.tsize)
+#define H_GET_DATA_SIZE(h) ((h)->aouthdr.dsize)
+#define H_GET_BSS_SIZE(h) ((h)->aouthdr.bsize)
+#define H_GET_ENTRY_POINT(h) ((h)->aouthdr.entry)
+#define H_GET_TEXT_START(h) ((h)->aouthdr.text_start)
+#define H_GET_DATA_START(h) ((h)->aouthdr.data_start)
+/* filehdr */
+#define H_GET_FILE_MAGIC_NUMBER(h) ((h)->filehdr.f_magic)
+#define H_GET_NUMBER_OF_SECTIONS(h) ((h)->filehdr.f_nscns)
+#define H_GET_TIME_STAMP(h) ((h)->filehdr.f_timdat)
+#define H_GET_SYMBOL_TABLE_POINTER(h) ((h)->filehdr.f_symptr)
+#define H_GET_SYMBOL_COUNT(h) ((h)->filehdr.f_nsyms)
+#define H_GET_SYMBOL_TABLE_SIZE(h) (H_GET_SYMBOL_COUNT(h) * SYMESZ)
+#define H_GET_SIZEOF_OPTIONAL_HEADER(h) ((h)->filehdr.f_opthdr)
+#define H_GET_FLAGS(h) ((h)->filehdr.f_flags)
+/* Extra fields to achieve bsd a.out compatibility and for convenience */
+#define H_GET_RELOCATION_SIZE(h) ((h)->relocation_size)
+#define H_GET_STRING_SIZE(h) ((h)->string_table_size)
+#define H_GET_LINENO_SIZE(h) ((h)->lineno_size)
+
+#ifndef OBJ_COFF_OMIT_OPTIONAL_HEADER
+#define H_GET_HEADER_SIZE(h) (sizeof(FILHDR) \
+ + sizeof(AOUTHDR)\
+ + (H_GET_NUMBER_OF_SECTIONS(h) * SCNHSZ))
+#else /* OBJ_COFF_OMIT_OPTIONAL_HEADER */
+#define H_GET_HEADER_SIZE(h) (sizeof(FILHDR) \
+ + (H_GET_NUMBER_OF_SECTIONS(h) * SCNHSZ))
+#endif /* OBJ_COFF_OMIT_OPTIONAL_HEADER */
+
+#define H_GET_TEXT_RELOCATION_SIZE(h) (text_section_header.s_nreloc * RELSZ)
+#define H_GET_DATA_RELOCATION_SIZE(h) (data_section_header.s_nreloc * RELSZ)
+
+/* Modifiers */
+/* aouthdr */
+#define H_SET_MAGIC_NUMBER(h,v) ((h)->aouthdr.magic = (v))
+#define H_SET_VERSION_STAMP(h,v) ((h)->aouthdr.vstamp = (v))
+#define H_SET_TEXT_SIZE(h,v) ((h)->aouthdr.tsize = (v))
+#define H_SET_DATA_SIZE(h,v) ((h)->aouthdr.dsize = (v))
+#define H_SET_BSS_SIZE(h,v) ((h)->aouthdr.bsize = (v))
+#define H_SET_ENTRY_POINT(h,v) ((h)->aouthdr.entry = (v))
+#define H_SET_TEXT_START(h,v) ((h)->aouthdr.text_start = (v))
+#define H_SET_DATA_START(h,v) ((h)->aouthdr.data_start = (v))
+/* filehdr */
+#define H_SET_FILE_MAGIC_NUMBER(h,v) ((h)->filehdr.f_magic = (v))
+#define H_SET_NUMBER_OF_SECTIONS(h,v) ((h)->filehdr.f_nscns = (v))
+#define H_SET_TIME_STAMP(h,v) ((h)->filehdr.f_timdat = (v))
+#define H_SET_SYMBOL_TABLE_POINTER(h,v) ((h)->filehdr.f_symptr = (v))
+#define H_SET_SYMBOL_TABLE_SIZE(h,v) ((h)->filehdr.f_nsyms = (v))
+#define H_SET_SIZEOF_OPTIONAL_HEADER(h,v) ((h)->filehdr.f_opthdr = (v))
+#define H_SET_FLAGS(h,v) ((h)->filehdr.f_flags = (v))
+/* Extra fields to achieve bsd a.out compatibility and for convinience */
+#define H_SET_RELOCATION_SIZE(h,t,d) ((h)->relocation_size = (t)+(d))
+#define H_SET_STRING_SIZE(h,v) ((h)->string_table_size = (v))
+#define H_SET_LINENO_SIZE(h,v) ((h)->lineno_size = (v))
+
+/* Segment flipping */
+#define segment_name(v) (seg_name[(int) (v)])
+
+typedef struct {
+#ifdef BFD_HEADERS
+ struct internal_aouthdr aouthdr; /* a.out header */
+ struct internal_filehdr filehdr; /* File header, not machine dep. */
+#else
+ AOUTHDR aouthdr; /* a.out header */
+ FILHDR filehdr; /* File header, not machine dep. */
+#endif
+ long string_table_size; /* names + '\0' + sizeof(int) */
+ long relocation_size; /* Cumulated size of relocation
+ information for all sections in
+ bytes. */
+ long lineno_size; /* Size of the line number information
+ table in bytes */
+} object_headers;
+
+/* -------------- Line number handling ------- */
+extern int text_lineno_number;
+
+/* line numbering stuff. */
+
+typedef struct internal_lineno {
+#ifdef BFD_HEADERS
+ struct bfd_internal_lineno line;
+#else
+ LINENO line; /* The lineno structure itself */
+#endif
+ char* frag; /* Frag to which the line number is related */
+ struct internal_lineno* next; /* Forward chain pointer */
+} lineno;
+
+extern lineno *lineno_lastP;
+extern lineno *lineno_rootP;
+#define OBJ_EMIT_LINENO(a, b, c) obj_emit_lineno((a),(b),(c))
+
+#if __STDC__ == 1
+void obj_emit_lineno(char **where, lineno *line, char *file_start);
+#else /* not __STDC__ */
+void obj_emit_lineno();
+#endif /* not __STDC__ */
+
+/* stack stuff */
+typedef struct {
+ unsigned long chunk_size;
+ unsigned long element_size;
+ unsigned long size;
+ char* data;
+ unsigned long pointer;
+} stack;
+
+#if __STDC__ == 1
+
+char *stack_pop(stack *st);
+char *stack_push(stack *st, char *element);
+char *stack_top(stack *st);
+stack *stack_init(unsigned long chunk_size, unsigned long element_size);
+void c_dot_file_symbol(char *filename);
+void obj_extra_stuff(object_headers *headers);
+void stack_delete(stack *st);
+
+#ifndef tc_headers_hook
+void tc_headers_hook(object_headers *headers);
+#endif /* tc_headers_hook */
+
+#ifndef tc_coff_symbol_emit_hook
+void tc_coff_symbol_emit_hook(); /* really tc_coff_symbol_emit_hook(symbolS *symbolP) */
+#endif /* tc_coff_symbol_emit_hook */
+
+void c_section_header(
+#ifdef BFD_HEADERS
+ struct internal_scnhdr *header,
+#else
+ SCNHDR *header,
+#endif
+
+ char *name,
+ long core_address,
+ long size,
+ long data_ptr,
+ long reloc_ptr,
+ long lineno_ptr,
+ long reloc_number,
+ long lineno_number,
+ long alignment);
+
+#else /* not __STDC__ */
+
+char *stack_pop();
+char *stack_push();
+char *stack_top();
+stack *stack_init();
+void c_dot_file_symbol();
+void c_section_header();
+void obj_extra_stuff();
+void stack_delete();
+void tc_headers_hook();
+void tc_coff_symbol_emit_hook();
+
+#endif /* not __STDC__ */
+
+
+/* sanity check */
+
+#ifdef TC_I960
+#ifndef C_LEAFSTAT
+hey! Where is the C_LEAFSTAT definition? i960-coff support is depending on it.
+#endif /* no C_LEAFSTAT */
+#endif /* TC_I960 */
+#ifdef BFD_HEADERS
+ extern struct internal_scnhdr data_section_header;
+extern struct internal_scnhdr text_section_header;
+#else
+extern SCNHDR data_section_header;
+extern SCNHDR text_section_header;
+#endif
+
+/*
+ * Local Variables:
+ * comment-column: 0
+ * fill-column: 131
+ * End:
+ */
+
+/* end of obj-coff.h */
diff --git a/gnu/usr.bin/as/config/obj-coffbfd.c b/gnu/usr.bin/as/config/obj-coffbfd.c
new file mode 100644
index 0000000..352893a
--- /dev/null
+++ b/gnu/usr.bin/as/config/obj-coffbfd.c
@@ -0,0 +1,2182 @@
+/* coff object file format with bfd
+ Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
+
+ This file is part of GAS.
+
+ GAS is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GAS is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GAS; see the file COPYING. If not, write to
+ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/*
+
+ How does this releate to the rest of GAS ?
+
+ Well, all the other files in gas are more or less a black box. It
+ takes care of opening files, parsing command lines, stripping blanks
+ etc etc. This module gets a chance to register what it wants to do by
+ saying that it is interested in various pseduo ops. The other big
+ change is write_object_file. This runs through all the data
+ structures that gas builds, and outputs the file in the format of our
+ choice.
+
+ Hacked for BFDness by steve chamberlain
+
+ This object module now supports the Hitachi H8/300 and the AMD 29k
+
+ sac@cygnus.com
+ */
+
+#include "as.h"
+#include "obstack.h"
+#include "subsegs.h"
+#include "frags.h"
+#include "../bfd/libbfd.h"
+
+
+/* This vector is used to turn an internal segment into a section #
+ suitable for insertion into a coff symbol table
+ */
+
+const short seg_N_TYPE[] = { /* in: segT out: N_TYPE bits */
+ C_ABS_SECTION,
+ 1,
+ 2,
+ 3,
+ 4,
+ 5,
+ 6,
+ 7,
+ 8,
+ 9,
+ 10,
+ C_UNDEF_SECTION, /* SEG_UNKNOWN */
+ C_UNDEF_SECTION, /* SEG_ABSENT */
+ C_UNDEF_SECTION, /* SEG_PASS1 */
+ C_UNDEF_SECTION, /* SEG_GOOF */
+ C_UNDEF_SECTION, /* SEG_BIG */
+ C_UNDEF_SECTION, /* SEG_DIFFERENCE */
+ C_DEBUG_SECTION, /* SEG_DEBUG */
+ C_NTV_SECTION, /* SEG_NTV */
+ C_PTV_SECTION, /* SEG_PTV */
+ C_REGISTER_SECTION, /* SEG_REGISTER */
+};
+
+
+int function_lineoff = -1; /* Offset in line#s where the last function
+ started (the odd entry for line #0) */
+
+int our_lineno_number = 0; /* we use this to build pointers from .bf's
+ into the linetable. It should match
+ exactly the values that are later
+ assigned in text_lineno_number by
+ write.c. */
+
+int text_lineno_number = 0;
+
+/* Add 4 to the real value to get the index and compensate the
+ negatives. This vector is used by S_GET_SEGMENT to turn a coff
+ section number into a segment number
+ */
+static symbolS *previous_file_symbol = NULL;
+void c_symbol_merge();
+static int line_base;
+
+symbolS *c_section_symbol();
+bfd *abfd;
+void EXFUN(bfd_as_write_hook,(struct internal_filehdr *,
+ bfd *abfd));
+
+static void EXFUN(fixup_segment,(fixS * fixP,
+ segT this_segment_type));
+
+static void EXFUN(fill_section,(bfd *abfd ,
+ struct internal_filehdr *f, unsigned
+ long *));
+
+
+char *EXFUN(s_get_name,(symbolS *s));
+static symbolS *EXFUN(tag_find_or_make,(char *name));
+static symbolS* EXFUN(tag_find,(char *name));
+
+
+static int
+ EXFUN(c_line_new,(
+ symbolS *symbol,
+ long paddr,
+ unsigned short line_number,
+ fragS* frag));
+
+
+static void EXFUN(w_symbols,
+ (bfd *abfd ,
+ char *where ,
+ symbolS *symbol_rootP));
+
+
+
+static void EXFUN( obj_coff_def,(int what));
+static void EXFUN( obj_coff_lcomm,(void));
+static void EXFUN( obj_coff_dim,(void));
+static void EXFUN( obj_coff_text,(void));
+static void EXFUN( obj_coff_data,(void));
+static void EXFUN( obj_coff_endef,(void));
+static void EXFUN( obj_coff_line,(void));
+static void EXFUN( obj_coff_ln,(void));
+static void EXFUN( obj_coff_scl,(void));
+static void EXFUN( obj_coff_size,(void));
+static void EXFUN( obj_coff_tag,(void));
+static void EXFUN( obj_coff_type,(void));
+static void EXFUN( obj_coff_val,(void));
+static void EXFUN( obj_coff_section,(void));
+static void EXFUN( tag_init,(void));
+static void EXFUN( tag_insert,(char *name, symbolS *symbolP));
+
+
+static struct hash_control *tag_hash;
+static symbolS *def_symbol_in_progress = NULL;
+
+const pseudo_typeS obj_pseudo_table[] = {
+ { "def", obj_coff_def, 0 },
+ { "dim", obj_coff_dim, 0 },
+ { "endef", obj_coff_endef, 0 },
+ { "line", obj_coff_line, 0 },
+ { "ln", obj_coff_ln, 0 },
+ { "scl", obj_coff_scl, 0 },
+ { "size", obj_coff_size, 0 },
+ { "tag", obj_coff_tag, 0 },
+ { "type", obj_coff_type, 0 },
+ { "val", obj_coff_val, 0 },
+ { "section", obj_coff_section, 0 },
+ { "text", obj_coff_text, 0 },
+ { "data", obj_coff_data, 0 },
+ /* we don't yet handle this. */
+ { "ident", s_ignore, 0 },
+ { "ABORT", s_abort, 0 },
+ { "lcomm", obj_coff_lcomm, 0},
+ { NULL} /* end sentinel */
+}; /* obj_pseudo_table */
+
+
+
+/* Section stuff
+
+ We allow more than just the standard 3 sections, infact, we allow
+ 10 sections, (though the usual three have to be there).
+
+ This structure performs the mappings for us:
+
+ */
+
+/* OBS stuff
+ static struct internal_scnhdr bss_section_header;
+ struct internal_scnhdr data_section_header;
+ struct internal_scnhdr text_section_header;
+
+ const segT N_TYPE_seg[32] =
+ {
+
+ };
+
+ */
+
+#define N_SEG 32
+typedef struct
+{
+ segT seg_t;
+ int i;
+} seg_info_type;
+
+seg_info_type seg_info_off_by_4[N_SEG] =
+{
+ {SEG_PTV, },
+ {SEG_NTV, },
+ {SEG_DEBUG, },
+ {SEG_ABSOLUTE, },
+ {SEG_UNKNOWN, },
+ {SEG_E0},
+ {SEG_E1},
+ {SEG_E2},
+ {SEG_E3},
+ {SEG_E4},
+ {SEG_E5},
+ {SEG_E6},
+ {SEG_E7},
+ {SEG_E8},
+ {SEG_E9},
+ {15},
+ {16},
+ {17},
+ {18},
+ {19},
+ {20},
+ {0},
+ {0},
+ {0},
+ {SEG_REGISTER},0,0,0,0};
+
+#define SEG_INFO_FROM_SECTION_NUMBER(x) (seg_info_off_by_4[(x)+4])
+#define SEG_INFO_FROM_SEG_NUMBER(x) (seg_info_off_by_4[(x)])
+
+
+relax_addressT
+ DEFUN(relax_align,(address, alignment),
+ register relax_addressT address AND
+ register long alignment )
+{
+ relax_addressT mask;
+ relax_addressT new_address;
+
+ mask = ~ ( (~0) << alignment );
+ new_address = (address + mask) & (~ mask);
+ return (new_address - address);
+} /* relax_align() */
+
+
+segT
+ DEFUN(s_get_segment,(x) ,
+ symbolS* x)
+{
+ return SEG_INFO_FROM_SECTION_NUMBER(x->sy_symbol.ost_entry.n_scnum).seg_t;
+}
+
+
+
+/* calculate the size of the frag chain and fill in the section header
+ to contain all of it, also fill in the addr of the sections */
+static unsigned int DEFUN(size_section,(abfd, idx),
+ bfd *abfd AND
+ unsigned int idx)
+{
+
+ unsigned int size = 0;
+ fragS *frag = segment_info[idx].frchainP->frch_root;
+ while (frag) {
+ if (frag->fr_address != size) {
+ printf("Out of step\n");
+ size = frag->fr_address;
+ }
+ size += frag->fr_fix;
+ switch (frag->fr_type) {
+ case rs_fill:
+ case rs_org:
+ size += frag->fr_offset * frag->fr_var;
+ break;
+ case rs_align:
+ size += relax_align(size, frag->fr_offset);
+ }
+ frag = frag->fr_next;
+ }
+ segment_info[idx].scnhdr.s_size = size;
+ return size;
+}
+
+
+static unsigned int DEFUN(count_entries_in_chain,(idx),
+ unsigned int idx)
+{
+ unsigned int nrelocs;
+ fixS *fixup_ptr;
+
+ /* Count the relocations */
+ fixup_ptr = segment_info[idx].fix_root;
+ nrelocs = 0;
+ while (fixup_ptr != (fixS *)NULL)
+ {
+ if (TC_COUNT_RELOC(fixup_ptr))
+ {
+
+#ifdef TC_A29K
+
+ if (fixup_ptr->fx_r_type == RELOC_CONSTH)
+ nrelocs+=2;
+ else
+ nrelocs++;
+#else
+ nrelocs++;
+#endif
+ }
+
+ fixup_ptr = fixup_ptr->fx_next;
+ }
+ return nrelocs;
+}
+
+/* output all the relocations for a section */
+void DEFUN(do_relocs_for,(abfd, file_cursor),
+ bfd *abfd AND
+ unsigned long *file_cursor)
+{
+ unsigned int nrelocs;
+ unsigned int idx;
+
+ for (idx = SEG_E0; idx < SEG_E9; idx++)
+ {
+ if (segment_info[idx].scnhdr.s_name[0])
+ {
+
+ struct external_reloc *ext_ptr;
+ struct external_reloc *external_reloc_vec;
+ unsigned int external_reloc_size;
+ unsigned int count = 0;
+ unsigned int base = segment_info[idx].scnhdr.s_paddr;
+ fixS * fix_ptr = segment_info[idx].fix_root;
+ nrelocs = count_entries_in_chain(idx);
+ external_reloc_size = nrelocs * RELSZ;
+ external_reloc_vec =
+ (struct external_reloc*)malloc(external_reloc_size);
+
+
+
+ ext_ptr = external_reloc_vec;
+
+ /* Fill in the internal coff style reloc struct from the
+ internal fix list */
+ while (fix_ptr)
+ {
+ symbolS *symbol_ptr;
+ struct internal_reloc intr;
+
+ /* Only output some of the relocations */
+ if (TC_COUNT_RELOC(fix_ptr))
+ {
+#ifdef TC_RELOC_MANGLE
+ TC_RELOC_MANGLE(fix_ptr, &intr, base);
+
+#else
+ symbolS *dot;
+ symbol_ptr = fix_ptr->fx_addsy;
+
+ intr.r_type = TC_COFF_FIX2RTYPE(fix_ptr);
+ intr.r_vaddr =
+ base + fix_ptr->fx_frag->fr_address + fix_ptr->fx_where ;
+
+ intr.r_offset = fix_ptr->fx_offset;
+
+ intr.r_offset = 0;
+
+ /* Turn the segment of the symbol into an offset
+ */
+ if (symbol_ptr)
+ {
+ dot = segment_info[S_GET_SEGMENT(symbol_ptr)].dot;
+ if (dot)
+ {
+ intr.r_symndx = dot->sy_number;
+ }
+ else
+ {
+ intr.r_symndx = symbol_ptr->sy_number;
+ }
+
+ }
+ else
+ {
+ intr.r_symndx = -1;
+
+
+ }
+#endif
+
+ (void)bfd_coff_swap_reloc_out(abfd, &intr, ext_ptr);
+ ext_ptr++;
+
+#if defined(TC_A29K)
+ /* The 29k has a special kludge for the high 16 bit reloc.
+ Two relocations are emmited, R_IHIHALF, and
+ R_IHCONST. The second one doesn't contain a symbol,
+ but uses the value for offset */
+
+ if (intr.r_type == R_IHIHALF)
+ {
+ /* now emit the second bit */
+ intr.r_type = R_IHCONST;
+ intr.r_symndx = fix_ptr->fx_addnumber;
+ (void)bfd_coff_swap_reloc_out(abfd,&intr,ext_ptr);
+ ext_ptr++;
+ }
+#endif
+ }
+
+ fix_ptr = fix_ptr->fx_next;
+ }
+
+ /* Write out the reloc table */
+ segment_info[idx].scnhdr.s_relptr = *file_cursor;
+ segment_info[idx].scnhdr.s_nreloc = nrelocs;
+ bfd_write((PTR)external_reloc_vec, 1, external_reloc_size, abfd);
+ *file_cursor += external_reloc_size;
+ free( external_reloc_vec);
+ }
+ }
+}
+
+
+/* run through a frag chain and write out the data to go with it, fill
+ in the scnhdrs with the info on the file postions
+ */
+static void DEFUN(fill_section,(abfd, filehdr, file_cursor),
+ bfd *abfd AND
+ struct internal_filehdr *filehdr AND
+ unsigned long *file_cursor)
+{
+
+ unsigned int i;
+ unsigned int paddr = 0;
+
+ for (i = SEG_E0; i < SEG_UNKNOWN; i++)
+ {
+ unsigned int offset = 0;
+
+ struct internal_scnhdr *s = &( segment_info[i].scnhdr);
+
+ if (s->s_name[0])
+ {
+ fragS *frag = segment_info[i].frchainP->frch_root;
+ char *buffer = malloc(s->s_size);
+ s->s_scnptr = *file_cursor;
+ s->s_paddr = paddr;
+ s->s_vaddr = paddr;
+
+ s->s_flags = STYP_REG;
+ if (strcmp(s->s_name,".text") == 0)
+ s->s_flags |= STYP_TEXT;
+ else if (strcmp(s->s_name,".data") == 0)
+ s->s_flags |= STYP_DATA;
+ else if (strcmp(s->s_name,".bss") == 0)
+ s->s_flags |= STYP_BSS | STYP_NOLOAD;
+
+ while (frag) {
+ unsigned int fill_size;
+ switch (frag->fr_type) {
+
+ case rs_fill:
+ case rs_align:
+ case rs_org:
+ if (frag->fr_fix)
+ {
+ memcpy(buffer + frag->fr_address,
+ frag->fr_literal,
+ frag->fr_fix);
+ offset += frag->fr_fix;
+ }
+
+ fill_size = frag->fr_var;
+ if (fill_size)
+ {
+ unsigned int count ;
+ unsigned int off = frag->fr_fix;
+ for (count = frag->fr_offset; count; count--)
+ {
+ memcpy(buffer + frag->fr_address + off,
+ frag->fr_literal + frag->fr_fix,
+ fill_size);
+ off += fill_size;
+ offset += fill_size;
+
+ }
+
+ }
+ break;
+ default:
+ abort();
+ }
+ frag = frag->fr_next;
+ }
+
+
+ bfd_write(buffer, s->s_size,1,abfd);
+ free(buffer);
+
+ *file_cursor += s->s_size;
+ paddr += s->s_size;
+ }
+ }
+
+}
+
+
+
+/* Coff file generation & utilities */
+
+
+static void
+ DEFUN(coff_header_append,(abfd, filehdr, aouthdr),
+ bfd *abfd AND
+ struct internal_filehdr *filehdr AND
+ struct internal_aouthdr *aouthdr)
+{
+ unsigned int i;
+ char buffer[1000];
+ char buffero[1000];
+
+ bfd_seek(abfd, 0, 0);
+#if 0
+ filehdr.f_opthdr = bfd_coff_swap_aouthdr_out(abfd, aouthdr,
+ buffero);
+#else
+ filehdr->f_opthdr = 0;
+#endif
+ i = bfd_coff_swap_filehdr_out(abfd, filehdr, buffer);
+
+ bfd_write(buffer, i ,1, abfd);
+ bfd_write(buffero, filehdr->f_opthdr, 1, abfd);
+
+ for (i = SEG_E0; i < SEG_E9; i++)
+ {
+ if (segment_info[i].scnhdr.s_name[0])
+ {
+ unsigned int size =
+ bfd_coff_swap_scnhdr_out(abfd,
+ &(segment_info[i].scnhdr),
+ buffer);
+ bfd_write(buffer, size, 1, abfd);
+ }
+ }
+}
+
+
+char *
+ DEFUN(symbol_to_chars,(abfd, where, symbolP),
+ bfd*abfd AND
+ char *where AND
+ symbolS *symbolP)
+{
+ unsigned int numaux = symbolP->sy_symbol.ost_entry.n_numaux;
+ unsigned int i;
+
+ /* Turn any symbols with register attributes into abs symbols */
+ if (S_GET_SEGMENT(symbolP) == SEG_REGISTER)
+ {
+ S_SET_SEGMENT(symbolP, SEG_ABSOLUTE);
+ }
+ /* At the same time, relocate all symbols to their output value */
+
+ S_SET_VALUE(symbolP,
+ segment_info[S_GET_SEGMENT(symbolP)].scnhdr.s_paddr
+ + S_GET_VALUE(symbolP));
+
+ where += bfd_coff_swap_sym_out(abfd, &symbolP->sy_symbol.ost_entry,
+ where);
+
+ for (i = 0; i < numaux; i++)
+ {
+ where += bfd_coff_swap_aux_out(abfd,
+ &symbolP->sy_symbol.ost_auxent[i],
+ S_GET_DATA_TYPE(symbolP),
+ S_GET_STORAGE_CLASS(symbolP),
+ where);
+ }
+ return where;
+
+}
+
+
+
+
+void obj_symbol_new_hook(symbolP)
+symbolS *symbolP;
+{
+ char underscore = 0; /* Symbol has leading _ */
+
+ /* Effective symbol */
+ /* Store the pointer in the offset. */
+ S_SET_ZEROES(symbolP, 0L);
+ S_SET_DATA_TYPE(symbolP, T_NULL);
+ S_SET_STORAGE_CLASS(symbolP, 0);
+ S_SET_NUMBER_AUXILIARY(symbolP, 0);
+ /* Additional information */
+ symbolP->sy_symbol.ost_flags = 0;
+ /* Auxiliary entries */
+ memset((char*) &symbolP->sy_symbol.ost_auxent[0], '\0', AUXESZ);
+
+#ifdef STRIP_UNDERSCORE
+ /* Remove leading underscore at the beginning of the symbol.
+ * This is to be compatible with the standard librairies.
+ */
+ if (*S_GET_NAME(symbolP) == '_') {
+ underscore = 1;
+ S_SET_NAME(symbolP, S_GET_NAME(symbolP) + 1);
+ } /* strip underscore */
+#endif /* STRIP_UNDERSCORE */
+
+ if (S_IS_STRING(symbolP))
+ SF_SET_STRING(symbolP);
+ if (!underscore && S_IS_LOCAL(symbolP))
+ SF_SET_LOCAL(symbolP);
+
+ return;
+} /* obj_symbol_new_hook() */
+
+/* stack stuff */
+stack* stack_init(chunk_size, element_size)
+unsigned long chunk_size;
+unsigned long element_size;
+{
+ stack* st;
+
+ if ((st = (stack*)malloc(sizeof(stack))) == (stack*)0)
+ return (stack*)0;
+ if ((st->data = malloc(chunk_size)) == (char*)0) {
+ free(st);
+ return (stack*)0;
+ }
+ st->pointer = 0;
+ st->size = chunk_size;
+ st->chunk_size = chunk_size;
+ st->element_size = element_size;
+ return st;
+} /* stack_init() */
+
+void stack_delete(st)
+stack* st;
+{
+ free(st->data);
+ free(st);
+}
+
+char *stack_push(st, element)
+stack *st;
+char *element;
+{
+ if (st->pointer + st->element_size >= st->size) {
+ st->size += st->chunk_size;
+ if ((st->data = xrealloc(st->data, st->size)) == (char*)0)
+ return (char*)0;
+ }
+ memcpy(st->data + st->pointer, element, st->element_size);
+ st->pointer += st->element_size;
+ return st->data + st->pointer;
+} /* stack_push() */
+
+char* stack_pop(st)
+stack* st;
+{
+ if ((st->pointer -= st->element_size) < 0) {
+ st->pointer = 0;
+ return (char*)0;
+ }
+
+ return st->data + st->pointer;
+}
+
+char* stack_top(st)
+stack* st;
+{
+ return st->data + st->pointer - st->element_size;
+}
+
+
+/*
+ * Handle .ln directives.
+ */
+
+static void obj_coff_ln()
+{
+ int l;
+
+ if (def_symbol_in_progress != NULL) {
+ as_warn(".ln pseudo-op inside .def/.endef: ignored.");
+ demand_empty_rest_of_line();
+ return;
+ } /* wrong context */
+
+ c_line_new(0,
+ obstack_next_free(&frags) - frag_now->fr_literal,
+ l = get_absolute_expression(),
+ frag_now);
+#ifndef NO_LISTING
+ {
+ extern int listing;
+
+ if (listing)
+ {
+ listing_source_line(l + line_base - 1);
+ }
+
+ }
+#endif
+ demand_empty_rest_of_line();
+ return;
+} /* obj_coff_line() */
+
+/*
+ * def()
+ *
+ * Handle .def directives.
+ *
+ * One might ask : why can't we symbol_new if the symbol does not
+ * already exist and fill it with debug information. Because of
+ * the C_EFCN special symbol. It would clobber the value of the
+ * function symbol before we have a chance to notice that it is
+ * a C_EFCN. And a second reason is that the code is more clear this
+ * way. (at least I think it is :-).
+ *
+ */
+
+#define SKIP_SEMI_COLON() while (*input_line_pointer++ != ';')
+#define SKIP_WHITESPACES() while (*input_line_pointer == ' ' || \
+ *input_line_pointer == '\t') \
+ input_line_pointer++;
+
+static void
+ DEFUN(obj_coff_def,(what),
+ int what)
+{
+ char name_end; /* Char after the end of name */
+ char *symbol_name; /* Name of the debug symbol */
+ char *symbol_name_copy; /* Temporary copy of the name */
+ unsigned int symbol_name_length;
+ /*$char* directiveP;$ */ /* Name of the pseudo opcode */
+ /*$char directive[MAX_DIRECTIVE];$ */ /* Backup of the directive */
+ /*$char end = 0;$ */ /* If 1, stop parsing */
+
+ if (def_symbol_in_progress != NULL) {
+ as_warn(".def pseudo-op used inside of .def/.endef: ignored.");
+ demand_empty_rest_of_line();
+ return;
+ } /* if not inside .def/.endef */
+
+ SKIP_WHITESPACES();
+
+ def_symbol_in_progress = (symbolS *) obstack_alloc(&notes, sizeof(*def_symbol_in_progress));
+ memset(def_symbol_in_progress, '\0', sizeof(*def_symbol_in_progress));
+
+ symbol_name = input_line_pointer;
+ name_end = get_symbol_end();
+ symbol_name_length = strlen(symbol_name);
+ symbol_name_copy = xmalloc(symbol_name_length + 1);
+ strcpy(symbol_name_copy, symbol_name);
+
+ /* Initialize the new symbol */
+#ifdef STRIP_UNDERSCORE
+ S_SET_NAME(def_symbol_in_progress, (*symbol_name_copy == '_'
+ ? symbol_name_copy + 1
+ : symbol_name_copy));
+#else /* STRIP_UNDERSCORE */
+ S_SET_NAME(def_symbol_in_progress, symbol_name_copy);
+#endif /* STRIP_UNDERSCORE */
+ /* free(symbol_name_copy); */
+ def_symbol_in_progress->sy_name_offset = ~0;
+ def_symbol_in_progress->sy_number = ~0;
+ def_symbol_in_progress->sy_frag = &zero_address_frag;
+
+ if (S_IS_STRING(def_symbol_in_progress)) {
+ SF_SET_STRING(def_symbol_in_progress);
+ } /* "long" name */
+
+ *input_line_pointer = name_end;
+
+ demand_empty_rest_of_line();
+ return;
+} /* obj_coff_def() */
+
+unsigned int dim_index;
+static void
+ DEFUN_VOID(obj_coff_endef)
+{
+ symbolS *symbolP = 0;
+ /* DIM BUG FIX sac@cygnus.com */
+ dim_index =0;
+ if (def_symbol_in_progress == NULL) {
+ as_warn(".endef pseudo-op used outside of .def/.endef: ignored.");
+ demand_empty_rest_of_line();
+ return;
+ } /* if not inside .def/.endef */
+
+ /* Set the section number according to storage class. */
+ switch (S_GET_STORAGE_CLASS(def_symbol_in_progress)) {
+ case C_STRTAG:
+ case C_ENTAG:
+ case C_UNTAG:
+ SF_SET_TAG(def_symbol_in_progress);
+ /* intentional fallthrough */
+ case C_FILE:
+ case C_TPDEF:
+ SF_SET_DEBUG(def_symbol_in_progress);
+ S_SET_SEGMENT(def_symbol_in_progress, SEG_DEBUG);
+ break;
+
+ case C_EFCN:
+ SF_SET_LOCAL(def_symbol_in_progress); /* Do not emit this symbol. */
+ /* intentional fallthrough */
+ case C_BLOCK:
+ SF_SET_PROCESS(def_symbol_in_progress); /* Will need processing before writing */
+ /* intentional fallthrough */
+ case C_FCN:
+ S_SET_SEGMENT(def_symbol_in_progress, SEG_E0);
+
+ if (def_symbol_in_progress->sy_symbol.ost_entry.n_name[1] == 'b') { /* .bf */
+ if (function_lineoff < 0) {
+ fprintf(stderr, "`.bf' symbol without preceding function\n");
+ } /* missing function symbol */
+ SA_GET_SYM_LNNOPTR(def_symbol_in_progress) = function_lineoff;
+ SF_SET_PROCESS(def_symbol_in_progress); /* Will need relocating */
+ function_lineoff = -1;
+ }
+ break;
+
+#ifdef C_AUTOARG
+ case C_AUTOARG:
+#endif /* C_AUTOARG */
+ case C_AUTO:
+ case C_REG:
+ case C_MOS:
+ case C_MOE:
+ case C_MOU:
+ case C_ARG:
+ case C_REGPARM:
+ case C_FIELD:
+ case C_EOS:
+ SF_SET_DEBUG(def_symbol_in_progress);
+ S_SET_SEGMENT(def_symbol_in_progress, SEG_ABSOLUTE);
+ break;
+
+ case C_EXT:
+ case C_STAT:
+ case C_LABEL:
+ /* Valid but set somewhere else (s_comm, s_lcomm, colon) */
+ break;
+
+ case C_USTATIC:
+ case C_EXTDEF:
+ case C_ULABEL:
+ as_warn("unexpected storage class %d", S_GET_STORAGE_CLASS(def_symbol_in_progress));
+ break;
+ } /* switch on storage class */
+
+ /* Now that we have built a debug symbol, try to
+ find if we should merge with an existing symbol
+ or not. If a symbol is C_EFCN or SEG_ABSOLUTE or
+ untagged SEG_DEBUG it never merges. */
+
+ /* Two cases for functions. Either debug followed
+ by definition or definition followed by debug.
+ For definition first, we will merge the debug
+ symbol into the definition. For debug first, the
+ lineno entry MUST point to the definition
+ function or else it will point off into space
+ when crawl_symbols() merges the debug
+ symbol into the real symbol. Therefor, let's
+ presume the debug symbol is a real function
+ reference. */
+
+ /* FIXME-SOON If for some reason the definition
+ label/symbol is never seen, this will probably
+ leave an undefined symbol at link time. */
+
+ if (S_GET_STORAGE_CLASS(def_symbol_in_progress) == C_EFCN
+ || (S_GET_SEGMENT(def_symbol_in_progress) == SEG_DEBUG
+ && !SF_GET_TAG(def_symbol_in_progress))
+ || S_GET_SEGMENT(def_symbol_in_progress) == SEG_ABSOLUTE
+ || (symbolP = symbol_find_base(S_GET_NAME(def_symbol_in_progress), DO_NOT_STRIP)) == NULL) {
+
+ symbol_append(def_symbol_in_progress, symbol_lastP, &symbol_rootP, &symbol_lastP);
+
+ } else {
+ /* This symbol already exists, merge the
+ newly created symbol into the old one.
+ This is not mandatory. The linker can
+ handle duplicate symbols correctly. But I
+ guess that it save a *lot* of space if
+ the assembly file defines a lot of
+ symbols. [loic] */
+
+ /* The debug entry (def_symbol_in_progress)
+ is merged into the previous definition. */
+
+ c_symbol_merge(def_symbol_in_progress, symbolP);
+ /* FIXME-SOON Should *def_symbol_in_progress be free'd? xoxorich. */
+ def_symbol_in_progress = symbolP;
+
+ if (SF_GET_FUNCTION(def_symbol_in_progress)
+ || SF_GET_TAG(def_symbol_in_progress)) {
+ /* For functions, and tags, the symbol *must* be where the debug symbol
+ appears. Move the existing symbol to the current place. */
+ /* If it already is at the end of the symbol list, do nothing */
+ if (def_symbol_in_progress != symbol_lastP) {
+ symbol_remove(def_symbol_in_progress, &symbol_rootP, &symbol_lastP);
+ symbol_append(def_symbol_in_progress, symbol_lastP, &symbol_rootP, &symbol_lastP);
+ } /* if not already in place */
+ } /* if function */
+ } /* normal or mergable */
+
+ if (SF_GET_TAG(def_symbol_in_progress)
+ && symbol_find_base(S_GET_NAME(def_symbol_in_progress), DO_NOT_STRIP) == NULL) {
+ tag_insert(S_GET_NAME(def_symbol_in_progress), def_symbol_in_progress);
+ } /* If symbol is a {structure,union} tag, associate symbol to its name. */
+
+ if (SF_GET_FUNCTION(def_symbol_in_progress)) {
+ know(sizeof(def_symbol_in_progress) <= sizeof(long));
+ function_lineoff
+ = c_line_new(def_symbol_in_progress,0, 0, &zero_address_frag);
+
+
+
+ SF_SET_PROCESS(def_symbol_in_progress);
+
+ if (symbolP == NULL) {
+ /* That is, if this is the first
+ time we've seen the function... */
+ symbol_table_insert(def_symbol_in_progress);
+ } /* definition follows debug */
+ } /* Create the line number entry pointing to the function being defined */
+
+ def_symbol_in_progress = NULL;
+ demand_empty_rest_of_line();
+ return;
+} /* obj_coff_endef() */
+
+static void
+ DEFUN_VOID(obj_coff_dim)
+{
+ register int dim_index;
+
+ if (def_symbol_in_progress == NULL)
+ {
+ as_warn(".dim pseudo-op used outside of .def/.endef: ignored.");
+ demand_empty_rest_of_line();
+ return;
+ } /* if not inside .def/.endef */
+
+ S_SET_NUMBER_AUXILIARY(def_symbol_in_progress, 1);
+
+ for (dim_index = 0; dim_index < DIMNUM; dim_index++)
+ {
+ SKIP_WHITESPACES();
+ SA_SET_SYM_DIMEN(def_symbol_in_progress, dim_index, get_absolute_expression());
+
+ switch (*input_line_pointer)
+ {
+
+ case ',':
+ input_line_pointer++;
+ break;
+
+ default:
+ as_warn("badly formed .dim directive ignored");
+ /* intentional fallthrough */
+ case '\n':
+ case ';':
+ dim_index = DIMNUM;
+ break;
+ } /* switch on following character */
+ } /* for each dimension */
+
+ demand_empty_rest_of_line();
+ return;
+} /* obj_coff_dim() */
+
+static void obj_coff_line()
+{
+ int this_base;
+
+ if (def_symbol_in_progress == NULL) {
+ obj_coff_ln();
+ return;
+ } /* if it looks like a stabs style line */
+
+ this_base = get_absolute_expression();
+ if (this_base > line_base)
+ {
+ line_base = this_base;
+ }
+
+
+#ifndef NO_LISTING
+ {
+ extern int listing;
+ if (listing && 0) {
+ listing_source_line(line_base);
+ }
+ }
+#endif
+ S_SET_NUMBER_AUXILIARY(def_symbol_in_progress, 1);
+ SA_SET_SYM_LNNO(def_symbol_in_progress, line_base);
+
+ demand_empty_rest_of_line();
+ return;
+} /* obj_coff_line() */
+
+static void obj_coff_size() {
+ if (def_symbol_in_progress == NULL) {
+ as_warn(".size pseudo-op used outside of .def/.endef ignored.");
+ demand_empty_rest_of_line();
+ return;
+ } /* if not inside .def/.endef */
+
+ S_SET_NUMBER_AUXILIARY(def_symbol_in_progress, 1);
+ SA_SET_SYM_SIZE(def_symbol_in_progress, get_absolute_expression());
+ demand_empty_rest_of_line();
+ return;
+} /* obj_coff_size() */
+
+static void obj_coff_scl() {
+ if (def_symbol_in_progress == NULL) {
+ as_warn(".scl pseudo-op used outside of .def/.endef ignored.");
+ demand_empty_rest_of_line();
+ return;
+ } /* if not inside .def/.endef */
+
+ S_SET_STORAGE_CLASS(def_symbol_in_progress, get_absolute_expression());
+ demand_empty_rest_of_line();
+ return;
+} /* obj_coff_scl() */
+
+static void obj_coff_tag() {
+ char *symbol_name;
+ char name_end;
+
+ if (def_symbol_in_progress == NULL) {
+ as_warn(".tag pseudo-op used outside of .def/.endef ignored.");
+ demand_empty_rest_of_line();
+ return;
+ } /* if not inside .def/.endef */
+
+ S_SET_NUMBER_AUXILIARY(def_symbol_in_progress, 1);
+ symbol_name = input_line_pointer;
+ name_end = get_symbol_end();
+
+ /* Assume that the symbol referred to by .tag is always defined. */
+ /* This was a bad assumption. I've added find_or_make. xoxorich. */
+ SA_SET_SYM_TAGNDX(def_symbol_in_progress, (long) tag_find_or_make(symbol_name));
+ if (SA_GET_SYM_TAGNDX(def_symbol_in_progress) == 0L) {
+ as_warn("tag not found for .tag %s", symbol_name);
+ } /* not defined */
+
+ SF_SET_TAGGED(def_symbol_in_progress);
+ *input_line_pointer = name_end;
+
+ demand_empty_rest_of_line();
+ return;
+} /* obj_coff_tag() */
+
+static void obj_coff_type() {
+ if (def_symbol_in_progress == NULL) {
+ as_warn(".type pseudo-op used outside of .def/.endef ignored.");
+ demand_empty_rest_of_line();
+ return;
+ } /* if not inside .def/.endef */
+
+ S_SET_DATA_TYPE(def_symbol_in_progress, get_absolute_expression());
+
+ if (ISFCN(S_GET_DATA_TYPE(def_symbol_in_progress)) &&
+ S_GET_STORAGE_CLASS(def_symbol_in_progress) != C_TPDEF) {
+ SF_SET_FUNCTION(def_symbol_in_progress);
+ } /* is a function */
+
+ demand_empty_rest_of_line();
+ return;
+} /* obj_coff_type() */
+
+static void obj_coff_val() {
+ if (def_symbol_in_progress == NULL) {
+ as_warn(".val pseudo-op used outside of .def/.endef ignored.");
+ demand_empty_rest_of_line();
+ return;
+ } /* if not inside .def/.endef */
+
+ if (is_name_beginner(*input_line_pointer)) {
+ char *symbol_name = input_line_pointer;
+ char name_end = get_symbol_end();
+
+ if (!strcmp(symbol_name, ".")) {
+ def_symbol_in_progress->sy_frag = frag_now;
+ S_SET_VALUE(def_symbol_in_progress, obstack_next_free(&frags) - frag_now->fr_literal);
+ /* If the .val is != from the .def (e.g. statics) */
+ } else if (strcmp(S_GET_NAME(def_symbol_in_progress), symbol_name)) {
+ def_symbol_in_progress->sy_forward = symbol_find_or_make(symbol_name);
+
+ /* If the segment is undefined when the forward
+ reference is solved, then copy the segment id
+ from the forward symbol. */
+ SF_SET_GET_SEGMENT(def_symbol_in_progress);
+ }
+ /* Otherwise, it is the name of a non debug symbol and its value will be calculated later. */
+ *input_line_pointer = name_end;
+ } else {
+ S_SET_VALUE(def_symbol_in_progress, get_absolute_expression());
+ } /* if symbol based */
+
+ demand_empty_rest_of_line();
+ return;
+} /* obj_coff_val() */
+
+/*
+ * Maintain a list of the tagnames of the structres.
+ */
+
+static void tag_init() {
+ tag_hash = hash_new();
+ return ;
+} /* tag_init() */
+
+static void tag_insert(name, symbolP)
+char *name;
+symbolS *symbolP;
+{
+ register char * error_string;
+
+ if (*(error_string = hash_jam(tag_hash, name, (char *)symbolP))) {
+ as_fatal("Inserting \"%s\" into structure table failed: %s",
+ name, error_string);
+ }
+ return ;
+} /* tag_insert() */
+
+static symbolS *tag_find_or_make(name)
+char *name;
+{
+ symbolS *symbolP;
+
+ if ((symbolP = tag_find(name)) == NULL) {
+ symbolP = symbol_new(name,
+ SEG_UNKNOWN,
+ 0,
+ &zero_address_frag);
+
+ tag_insert(S_GET_NAME(symbolP), symbolP);
+ symbol_table_insert(symbolP);
+ } /* not found */
+
+ return(symbolP);
+} /* tag_find_or_make() */
+
+static symbolS *tag_find(name)
+char *name;
+{
+#ifdef STRIP_UNDERSCORE
+ if (*name == '_') name++;
+#endif /* STRIP_UNDERSCORE */
+ return((symbolS*)hash_find(tag_hash, name));
+} /* tag_find() */
+
+void obj_read_begin_hook() {
+ /* These had better be the same. Usually 18 bytes. */
+#ifndef BFD_HEADERS
+ know(sizeof(SYMENT) == sizeof(AUXENT));
+ know(SYMESZ == AUXESZ);
+#endif
+ tag_init();
+
+ return;
+} /* obj_read_begin_hook() */
+
+/* This function runs through the symbol table and puts all the
+ externals onto another chain */
+
+/* The chain of externals */
+symbolS *symbol_externP = NULL;
+symbolS *symbol_extern_lastP = NULL;
+
+stack*block_stack;
+symbolS *last_functionP = NULL;
+symbolS *last_tagP;
+
+
+static unsigned int DEFUN_VOID(yank_symbols)
+{
+ symbolS *symbolP;
+ unsigned int symbol_number =0;
+
+ for (symbolP = symbol_rootP;
+ symbolP;
+ symbolP = symbolP ? symbol_next(symbolP) : symbol_rootP) {
+ if (!SF_GET_DEBUG(symbolP)) {
+ /* Debug symbols do not need all this rubbish */
+ symbolS* real_symbolP;
+
+ /* L* and C_EFCN symbols never merge. */
+ if (!SF_GET_LOCAL(symbolP)
+ && (real_symbolP = symbol_find_base(S_GET_NAME(symbolP), DO_NOT_STRIP))
+ && real_symbolP != symbolP) {
+ /* FIXME-SOON: where do dups come from?
+ Maybe tag references before definitions? xoxorich. */
+ /* Move the debug data from the debug symbol to the
+ real symbol. Do NOT do the oposite (i.e. move from
+ real symbol to debug symbol and remove real symbol from the
+ list.) Because some pointers refer to the real symbol
+ whereas no pointers refer to the debug symbol. */
+ c_symbol_merge(symbolP, real_symbolP);
+ /* Replace the current symbol by the real one */
+ /* The symbols will never be the last or the first
+ because : 1st symbol is .file and 3 last symbols are
+ .text, .data, .bss */
+ symbol_remove(real_symbolP, &symbol_rootP, &symbol_lastP);
+ symbol_insert(real_symbolP, symbolP, &symbol_rootP, &symbol_lastP);
+ symbol_remove(symbolP, &symbol_rootP, &symbol_lastP);
+ symbolP = real_symbolP;
+ } /* if not local but dup'd */
+
+ if (flagseen['R'] && (S_GET_SEGMENT(symbolP) == SEG_E1)) {
+ S_SET_SEGMENT(symbolP, SEG_E0);
+ } /* push data into text */
+
+ S_SET_VALUE(symbolP,
+ S_GET_VALUE(symbolP) + symbolP->sy_frag->fr_address);
+
+ if (!S_IS_DEFINED(symbolP) && !SF_GET_LOCAL(symbolP))
+ {
+ S_SET_EXTERNAL(symbolP);
+ }
+ else if (S_GET_STORAGE_CLASS(symbolP) == C_NULL)
+ {
+ if (S_GET_SEGMENT(symbolP) == SEG_E0)
+ {
+ S_SET_STORAGE_CLASS(symbolP, C_LABEL);
+ }
+ else
+ {
+ S_SET_STORAGE_CLASS(symbolP, C_STAT);
+ }
+ }
+
+ /* Mainly to speed up if not -g */
+ if (SF_GET_PROCESS(symbolP))
+ {
+ /* Handle the nested blocks auxiliary info. */
+ if (S_GET_STORAGE_CLASS(symbolP) == C_BLOCK) {
+ if (!strcmp(S_GET_NAME(symbolP), ".bb"))
+ stack_push(block_stack, (char *) &symbolP);
+ else { /* .eb */
+ register symbolS* begin_symbolP;
+ begin_symbolP = *(symbolS**)stack_pop(block_stack);
+ if (begin_symbolP == (symbolS*)0)
+ as_warn("mismatched .eb");
+ else
+ SA_SET_SYM_ENDNDX(begin_symbolP, symbol_number+2);
+ }
+ }
+ /* If we are able to identify the type of a function, and we
+ are out of a function (last_functionP == 0) then, the
+ function symbol will be associated with an auxiliary
+ entry. */
+ if (last_functionP == (symbolS*)0 &&
+ SF_GET_FUNCTION(symbolP)) {
+ last_functionP = symbolP;
+
+ if (S_GET_NUMBER_AUXILIARY(symbolP) < 1) {
+ S_SET_NUMBER_AUXILIARY(symbolP, 1);
+ } /* make it at least 1 */
+
+ /* Clobber possible stale .dim information. */
+ memset(symbolP->sy_symbol.ost_auxent[0].x_sym.x_fcnary.x_ary.x_dimen,
+ '\0', sizeof(symbolP->sy_symbol.ost_auxent[0].x_sym.x_fcnary.x_ary.x_dimen));
+ }
+ /* The C_FCN doesn't need any additional information.
+ I don't even know if this is needed for sdb. But the
+ standard assembler generates it, so...
+ */
+ if (S_GET_STORAGE_CLASS(symbolP) == C_EFCN) {
+ if (last_functionP == (symbolS*)0)
+ as_fatal("C_EFCN symbol out of scope");
+ SA_SET_SYM_FSIZE(last_functionP,
+ (long)(S_GET_VALUE(symbolP) -
+ S_GET_VALUE(last_functionP)));
+ SA_SET_SYM_ENDNDX(last_functionP, symbol_number);
+ last_functionP = (symbolS*)0;
+ }
+ }
+ } else if (SF_GET_TAG(symbolP)) {
+ /* First descriptor of a structure must point to
+ the first slot after the structure description. */
+ last_tagP = symbolP;
+
+ } else if (S_GET_STORAGE_CLASS(symbolP) == C_EOS) {
+ /* +2 take in account the current symbol */
+ SA_SET_SYM_ENDNDX(last_tagP, symbol_number + 2);
+ } else if (S_GET_STORAGE_CLASS(symbolP) == C_FILE) {
+ if (S_GET_VALUE(symbolP)) {
+ S_SET_VALUE((symbolS *) S_GET_VALUE(symbolP), symbol_number);
+ S_SET_VALUE(symbolP, 0);
+ } /* no one points at the first .file symbol */
+ } /* if debug or tag or eos or file */
+
+ /* We must put the external symbols apart. The loader
+ does not bomb if we do not. But the references in
+ the endndx field for a .bb symbol are not corrected
+ if an external symbol is removed between .bb and .be.
+ I.e in the following case :
+ [20] .bb endndx = 22
+ [21] foo external
+ [22] .be
+ ld will move the symbol 21 to the end of the list but
+ endndx will still be 22 instead of 21. */
+
+
+ if (SF_GET_LOCAL(symbolP)) {
+ /* remove C_EFCN and LOCAL (L...) symbols */
+ /* next pointer remains valid */
+ symbol_remove(symbolP, &symbol_rootP, &symbol_lastP);
+
+ }
+ else if (!S_IS_DEFINED(symbolP)
+ && !S_IS_DEBUG(symbolP)
+ && !SF_GET_STATICS(symbolP) &&
+ S_GET_STORAGE_CLASS(symbolP) == C_EXT)
+ { /* C_EXT && !SF_GET_FUNCTION(symbolP)) */
+ /* if external, Remove from the list */
+ symbolS *hold = symbol_previous(symbolP);
+
+ symbol_remove(symbolP, &symbol_rootP, &symbol_lastP);
+ symbol_clear_list_pointers(symbolP);
+ symbol_append(symbolP, symbol_extern_lastP, &symbol_externP, &symbol_extern_lastP);
+ symbolP = hold;
+ } else {
+ if (SF_GET_STRING(symbolP)) {
+ symbolP->sy_name_offset = string_byte_count;
+ string_byte_count += strlen(S_GET_NAME(symbolP)) + 1;
+ } else {
+ symbolP->sy_name_offset = 0;
+ } /* fix "long" names */
+
+ symbolP->sy_number = symbol_number;
+ symbol_number += 1 + S_GET_NUMBER_AUXILIARY(symbolP);
+ } /* if local symbol */
+ } /* traverse the symbol list */
+ return symbol_number;
+
+}
+
+
+static unsigned int DEFUN_VOID(glue_symbols)
+{
+ unsigned int symbol_number = 0;
+ symbolS *symbolP;
+ for (symbolP = symbol_externP; symbol_externP;) {
+ symbolS *tmp = symbol_externP;
+
+ /* append */
+ symbol_remove(tmp, &symbol_externP, &symbol_extern_lastP);
+ symbol_append(tmp, symbol_lastP, &symbol_rootP, &symbol_lastP);
+
+ /* and process */
+ if (SF_GET_STRING(tmp)) {
+ tmp->sy_name_offset = string_byte_count;
+ string_byte_count += strlen(S_GET_NAME(tmp)) + 1;
+ } else {
+ tmp->sy_name_offset = 0;
+ } /* fix "long" names */
+
+ tmp->sy_number = symbol_number;
+ symbol_number += 1 + S_GET_NUMBER_AUXILIARY(tmp);
+ } /* append the entire extern chain */
+ return symbol_number;
+
+}
+
+static unsigned int DEFUN_VOID(tie_tags)
+{
+ unsigned int symbol_number = 0;
+
+ symbolS*symbolP;
+ for (symbolP = symbol_rootP; symbolP; symbolP =
+ symbol_next(symbolP))
+ {
+ symbolP->sy_number = symbol_number;
+
+
+
+ if (SF_GET_TAGGED(symbolP))
+ {
+ SA_SET_SYM_TAGNDX
+ (symbolP,
+ ((symbolS*) SA_GET_SYM_TAGNDX(symbolP))->sy_number);
+ }
+
+ symbol_number += 1 + S_GET_NUMBER_AUXILIARY(symbolP);
+ }
+ return symbol_number;
+
+}
+
+static void
+ DEFUN(crawl_symbols,(headers, abfd),
+ struct internal_filehdr *headers AND
+ bfd *abfd)
+{
+
+ unsigned int i;
+ unsigned int ptr = 0;
+
+
+ symbolS *symbolP;
+
+ /* Initialize the stack used to keep track of the matching .bb .be */
+
+ block_stack = stack_init(512, sizeof(symbolS*));
+ /* JF deal with forward references first... */
+ for (symbolP = symbol_rootP;
+ symbolP;
+ symbolP = symbol_next(symbolP))
+ {
+
+ if (symbolP->sy_forward) {
+ S_SET_VALUE(symbolP, (S_GET_VALUE(symbolP)
+ + S_GET_VALUE(symbolP->sy_forward)
+ + symbolP->sy_forward->sy_frag->fr_address));
+
+ if (SF_GET_GET_SEGMENT(symbolP)) {
+ S_SET_SEGMENT(symbolP, S_GET_SEGMENT(symbolP->sy_forward));
+ } /* forward segment also */
+
+ symbolP->sy_forward=0;
+ } /* if it has a forward reference */
+ } /* walk the symbol chain */
+
+
+ /* The symbol list should be ordered according to the following sequence
+ * order :
+ * . .file symbol
+ * . debug entries for functions
+ * . fake symbols for the sections, including.text .data and .bss
+ * . defined symbols
+ * . undefined symbols
+ * But this is not mandatory. The only important point is to put the
+ * undefined symbols at the end of the list.
+ */
+
+ if (symbol_rootP == NULL
+ || S_GET_STORAGE_CLASS(symbol_rootP) != C_FILE) {
+ c_dot_file_symbol("fake");
+ }
+ /* Is there a .file symbol ? If not insert one at the beginning. */
+
+ /*
+ * Build up static symbols for the sections, they are filled in later
+ */
+
+
+ for (i = SEG_E0; i < SEG_E9; i++)
+ {
+ if (segment_info[i].scnhdr.s_name[0])
+ {
+ segment_info[i].dot =
+ c_section_symbol(segment_info[i].scnhdr.s_name,
+ i-SEG_E0+1);
+
+ }
+ }
+
+
+ /* Take all the externals out and put them into another chain */
+ headers->f_nsyms = yank_symbols();
+ /* Take the externals and glue them onto the end.*/
+ headers->f_nsyms += glue_symbols();
+
+ headers->f_nsyms = tie_tags();
+ know(symbol_externP == NULL);
+ know(symbol_extern_lastP == NULL);
+
+ return;
+}
+
+/*
+ * Find strings by crawling along symbol table chain.
+ */
+
+void DEFUN(w_strings,(where),
+ char *where)
+{
+ symbolS *symbolP;
+
+ /* Gotta do md_ byte-ordering stuff for string_byte_count first - KWK */
+ md_number_to_chars(where, string_byte_count, sizeof(string_byte_count));
+ where += sizeof(string_byte_count);
+ for (symbolP = symbol_rootP;
+ symbolP;
+ symbolP = symbol_next(symbolP))
+ {
+ unsigned int size;
+
+ if (SF_GET_STRING(symbolP)) {
+ size = strlen(S_GET_NAME(symbolP)) + 1;
+
+ memcpy(where, S_GET_NAME(symbolP),size);
+ where += size;
+
+ }
+ }
+
+}
+
+
+
+
+
+static void
+ DEFUN(do_linenos_for,(abfd, file_cursor),
+ bfd *abfd AND
+ unsigned long *file_cursor)
+{
+ unsigned int idx;
+
+ for (idx = SEG_E0; idx < SEG_E9; idx++)
+ {
+ segment_info_type *s = segment_info + idx;
+
+
+ if (s->scnhdr.s_nlnno != 0)
+ {
+ struct lineno_list *line_ptr ;
+
+ struct external_lineno *buffer =
+ (struct external_lineno *)xmalloc(s->scnhdr.s_nlnno * LINESZ);
+
+ struct external_lineno *dst= buffer;
+
+ /* Run through the table we've built and turn it into its external
+ form, take this chance to remove duplicates */
+
+ for (line_ptr = s->lineno_list_head;
+ line_ptr != (struct lineno_list *)NULL;
+ line_ptr = line_ptr->next)
+ {
+
+ if (line_ptr->line.l_lnno == 0)
+ {
+ /* Turn a pointer to a symbol into the symbols' index */
+ line_ptr->line.l_addr.l_symndx =
+ ( (symbolS *)line_ptr->line.l_addr.l_symndx)->sy_number;
+ }
+ else
+ {
+ line_ptr->line.l_addr.l_paddr += ((struct frag * )(line_ptr->frag))->fr_address;
+ }
+
+
+ (void) bfd_coff_swap_lineno_out(abfd, &(line_ptr->line), dst);
+ dst++;
+
+ }
+
+ s->scnhdr.s_lnnoptr = *file_cursor;
+
+ bfd_write(buffer, 1, s->scnhdr.s_nlnno* LINESZ, abfd);
+ free(buffer);
+
+ *file_cursor += s->scnhdr.s_nlnno * LINESZ;
+ }
+ }
+}
+
+
+/* Now we run through the list of frag chains in a segment and
+ make all the subsegment frags appear at the end of the
+ list, as if the seg 0 was extra long */
+
+static void DEFUN_VOID(remove_subsegs)
+{
+ unsigned int i;
+
+ for (i = SEG_E0; i < SEG_UNKNOWN; i++)
+ {
+ frchainS *head = segment_info[i].frchainP;
+ fragS dummy;
+ fragS * prev_frag = &dummy;
+
+ while (head && head->frch_seg == i)
+ {
+ prev_frag->fr_next = head->frch_root;
+ prev_frag = head->frch_last;
+ head = head->frch_next;
+ }
+ prev_frag->fr_next = 0;
+ }
+}
+
+
+extern void DEFUN_VOID(write_object_file)
+{
+ int i;
+ struct frchain *frchain_ptr;
+
+ struct internal_filehdr filehdr;
+ struct internal_aouthdr aouthdr;
+ unsigned long file_cursor;
+ bfd *abfd;
+ unsigned int addr = 0;
+ abfd = bfd_openw(out_file_name, TARGET_FORMAT);
+
+
+ if (abfd == 0) {
+ as_perror ("FATAL: Can't create %s", out_file_name);
+ exit(42);
+ }
+ bfd_set_format(abfd, bfd_object);
+ bfd_set_arch_mach(abfd, BFD_ARCH, 0);
+
+
+
+ string_byte_count = 4;
+
+ for (frchain_ptr = frchain_root;
+ frchain_ptr != (struct frchain *)NULL;
+ frchain_ptr = frchain_ptr->frch_next) {
+ /* Run through all the sub-segments and align them up. Also close any
+ open frags. We tack a .fill onto the end of the frag chain so
+ that any .align's size can be worked by looking at the next
+ frag */
+
+ subseg_new(frchain_ptr->frch_seg, frchain_ptr->frch_subseg);
+#define SUB_SEGMENT_ALIGN 1
+ frag_align(SUB_SEGMENT_ALIGN,0);
+ frag_wane(frag_now);
+ frag_now->fr_fix = 0;
+ know( frag_now->fr_next == NULL );
+ }
+
+
+ remove_subsegs();
+
+
+ for (i = SEG_E0; i < SEG_UNKNOWN; i++)
+ {
+ relax_segment(segment_info[i].frchainP->frch_root, i);
+ }
+
+
+
+
+
+ filehdr.f_nscns = 0;
+
+ /* Find out how big the sections are */
+ for (i = SEG_E0; i < SEG_UNKNOWN; i++)
+ {
+
+ if (segment_info[i].scnhdr.s_name[0])
+ {
+ filehdr.f_nscns++;
+ }
+ segment_info[i].scnhdr.s_paddr = addr;
+ if (i == SEG_E2) {
+ /* THis is a special case, we leave the size alone, which will have */
+ /* been made up from all and any lcomms seen */
+ }
+ else {
+ addr += size_section(abfd, i);
+ }
+ }
+
+
+
+ /* Turn the gas native symbol table shape into a coff symbol table */
+ crawl_symbols(&filehdr, abfd);
+#ifndef TC_H8300
+ for (i = SEG_E0; i < SEG_UNKNOWN; i++)
+ {
+ fixup_segment(segment_info[i].fix_root, i);
+ }
+#endif
+
+ file_cursor = FILHSZ + SCNHSZ * filehdr.f_nscns ;
+
+ bfd_seek(abfd, file_cursor, 0);
+
+
+ do_relocs_for(abfd, &file_cursor);
+
+ do_linenos_for(abfd, &file_cursor);
+
+
+ /* Plant the data */
+
+ fill_section(abfd,&filehdr, &file_cursor);
+
+ filehdr.f_magic = COFF_MAGIC;
+ filehdr.f_timdat = 0;
+ filehdr.f_flags = 0;
+
+
+
+ {
+
+ unsigned int symtable_size = filehdr.f_nsyms * SYMESZ;
+ char *buffer1 = malloc(symtable_size + string_byte_count + 4);
+ char *ptr = buffer1;
+ filehdr.f_symptr = bfd_tell(abfd);
+ w_symbols(abfd, buffer1, symbol_rootP);
+ w_strings(buffer1 + symtable_size);
+ bfd_write(buffer1, 1,symtable_size + string_byte_count + 4, abfd);
+ free(buffer1);
+
+ }
+ coff_header_append(abfd, &filehdr, &aouthdr);
+
+ bfd_close_all_done(abfd);
+}
+
+
+static void DEFUN(change_to_section,(name, len, exp),
+ char *name AND
+ unsigned int len AND
+ unsigned int exp)
+{
+ unsigned int i;
+ /* Find out if we've already got a section of this name etc */
+ for (i = SEG_E0; i < SEG_E9 && segment_info[i].scnhdr.s_name[0] ; i++)
+ {
+ if (strncmp(segment_info[i].scnhdr.s_name, name, len) == 0)
+ {
+ subseg_new(i, exp);
+ return;
+
+ }
+ }
+ /* No section, add one */
+ strncpy(segment_info[i].scnhdr.s_name, name, 8);
+ subseg_new(i, exp);
+}
+
+static void
+ DEFUN_VOID(obj_coff_section)
+{
+ /* Strip out the section name */
+ char *section_name ;
+ char *section_name_end;
+ char c;
+
+ unsigned int len;
+ unsigned int exp;
+
+ section_name = input_line_pointer;
+ c = get_symbol_end();
+ section_name_end = input_line_pointer;
+
+ len = section_name_end - section_name ;
+ input_line_pointer++;
+ SKIP_WHITESPACE();
+ if (c == ',')
+ {
+ exp = get_absolute_expression();
+ }
+ else if ( *input_line_pointer == ',')
+ {
+
+ input_line_pointer++;
+ exp = get_absolute_expression();
+ }
+ else
+ {
+ exp = 0;
+ }
+
+ change_to_section(section_name, len,exp);
+ *section_name_end = c;
+
+}
+
+
+static void obj_coff_text()
+{
+ change_to_section(".text",5, get_absolute_expression());
+}
+
+
+static void obj_coff_data()
+{
+ change_to_section(".data",5, get_absolute_expression());
+}
+
+void c_symbol_merge(debug, normal)
+symbolS *debug;
+symbolS *normal;
+{
+ S_SET_DATA_TYPE(normal, S_GET_DATA_TYPE(debug));
+ S_SET_STORAGE_CLASS(normal, S_GET_STORAGE_CLASS(debug));
+
+ if (S_GET_NUMBER_AUXILIARY(debug) > S_GET_NUMBER_AUXILIARY(normal)) {
+ S_SET_NUMBER_AUXILIARY(normal, S_GET_NUMBER_AUXILIARY(debug));
+ } /* take the most we have */
+
+ if (S_GET_NUMBER_AUXILIARY(debug) > 0) {
+ memcpy((char*)&normal->sy_symbol.ost_auxent[0], (char*)&debug->sy_symbol.ost_auxent[0], S_GET_NUMBER_AUXILIARY(debug) * AUXESZ);
+ } /* Move all the auxiliary information */
+
+ /* Move the debug flags. */
+ SF_SET_DEBUG_FIELD(normal, SF_GET_DEBUG_FIELD(debug));
+} /* c_symbol_merge() */
+
+static int
+ DEFUN(c_line_new,(symbol, paddr, line_number, frag),
+ symbolS *symbol AND
+ long paddr AND
+ unsigned short line_number AND
+ fragS* frag)
+{
+ struct lineno_list* new_line =
+ (struct lineno_list *)xmalloc(sizeof(struct lineno_list));
+
+ segment_info_type *s = segment_info + now_seg;
+ new_line->line.l_lnno = line_number;
+
+ if (line_number == 0)
+ {
+ new_line->line.l_addr.l_symndx = (long)symbol;
+ }
+ else
+ {
+ new_line->line.l_addr.l_paddr = paddr;
+ }
+
+ new_line->frag = (char*)frag;
+ new_line->next = (struct lineno_list*)NULL;
+
+
+ if (s->lineno_list_head == (struct lineno_list *)NULL)
+ {
+ s->lineno_list_head = new_line;
+ }
+ else
+ {
+ s->lineno_list_tail->next = new_line;
+ }
+ s->lineno_list_tail = new_line;
+ return LINESZ * s->scnhdr.s_nlnno ++;
+}
+
+void c_dot_file_symbol(filename)
+char *filename;
+{
+ symbolS* symbolP;
+
+ symbolP = symbol_new(".file",
+ SEG_DEBUG,
+ 0,
+ &zero_address_frag);
+
+ S_SET_STORAGE_CLASS(symbolP, C_FILE);
+ S_SET_NUMBER_AUXILIARY(symbolP, 1);
+ SA_SET_FILE_FNAME(symbolP, filename);
+#ifndef NO_LISTING
+ {
+ extern int listing;
+ if (listing)
+ {
+ listing_source_file(filename);
+ }
+
+ }
+
+#endif
+ SF_SET_DEBUG(symbolP);
+ S_SET_VALUE(symbolP, (long) previous_file_symbol);
+
+ previous_file_symbol = symbolP;
+
+ /* Make sure that the symbol is first on the symbol chain */
+ if (symbol_rootP != symbolP) {
+ if (symbolP == symbol_lastP) {
+ symbol_lastP = symbol_lastP->sy_previous;
+ } /* if it was the last thing on the list */
+
+ symbol_remove(symbolP, &symbol_rootP, &symbol_lastP);
+ symbol_insert(symbolP, symbol_rootP, &symbol_rootP, &symbol_lastP);
+ symbol_rootP = symbolP;
+ } /* if not first on the list */
+
+} /* c_dot_file_symbol() */
+
+/*
+ * Build a 'section static' symbol.
+ */
+
+symbolS *c_section_symbol(name,idx)
+char *name;
+int idx;
+{
+ symbolS *symbolP;
+
+ symbolP = symbol_new(name,idx,
+ 0,
+ &zero_address_frag);
+
+ S_SET_STORAGE_CLASS(symbolP, C_STAT);
+ S_SET_NUMBER_AUXILIARY(symbolP, 1);
+
+ SF_SET_STATICS(symbolP);
+
+ return symbolP;
+} /* c_section_symbol() */
+
+static void
+ DEFUN(w_symbols,(abfd, where, symbol_rootP),
+ bfd *abfd AND
+ char *where AND
+ symbolS *symbol_rootP)
+{
+ symbolS *symbolP;
+ unsigned int i;
+
+ /* First fill in those values we have only just worked out */
+ for (i = SEG_E0; i < SEG_E9; i++)
+ {
+ symbolP = segment_info[i].dot;
+ if (symbolP)
+ {
+
+ SA_SET_SCN_SCNLEN(symbolP, segment_info[i].scnhdr.s_size);
+ SA_SET_SCN_NRELOC(symbolP, segment_info[i].scnhdr.s_nreloc);
+ SA_SET_SCN_NLINNO(symbolP, segment_info[i].scnhdr.s_nlnno);
+
+ }
+ }
+
+ /*
+ * Emit all symbols left in the symbol chain.
+ */
+ for (symbolP = symbol_rootP; symbolP; symbolP = symbol_next(symbolP)) {
+ /* Used to save the offset of the name. It is used to point
+ to the string in memory but must be a file offset. */
+ register char * temp;
+
+ tc_coff_symbol_emit_hook(symbolP);
+
+ temp = S_GET_NAME(symbolP);
+ if (SF_GET_STRING(symbolP)) {
+ S_SET_OFFSET(symbolP, symbolP->sy_name_offset);
+ S_SET_ZEROES(symbolP, 0);
+ } else {
+ memset(symbolP->sy_symbol.ost_entry.n_name, '\0', SYMNMLEN);
+ strncpy(symbolP->sy_symbol.ost_entry.n_name, temp, SYMNMLEN);
+ }
+ where = symbol_to_chars(abfd, where, symbolP);
+ S_SET_NAME(symbolP,temp);
+ }
+
+} /* w_symbols() */
+
+static void DEFUN_VOID(obj_coff_lcomm)
+{
+ char *name;
+ char c;
+ int temp;
+ char *p;
+ symbolS *symbolP;
+ name = input_line_pointer;
+
+
+
+ c = get_symbol_end();
+ p = input_line_pointer;
+ *p = c;
+ SKIP_WHITESPACE();
+ if (*input_line_pointer != ',') {
+ as_bad("Expected comma after name");
+ ignore_rest_of_line();
+ return;
+ }
+ if (*input_line_pointer == '\n') {
+ as_bad("Missing size expression");
+ return;
+ }
+ input_line_pointer++;
+ if ((temp = get_absolute_expression ()) < 0) {
+ as_warn("lcomm length (%d.) <0! Ignored.", temp);
+ ignore_rest_of_line();
+ return;
+ }
+ *p = 0;
+ symbolP = symbol_find_or_make(name);
+ S_SET_VALUE(symbolP, segment_info[SEG_E2].scnhdr.s_size);
+ S_SET_SEGMENT(symbolP, SEG_E2);
+ segment_info[SEG_E2].scnhdr.s_size += temp;
+ S_SET_STORAGE_CLASS(symbolP, C_STAT);
+ demand_empty_rest_of_line();
+}
+
+
+#if 1
+static void DEFUN(fixup_segment,(fixP, this_segment_type),
+ register fixS * fixP AND
+ segT this_segment_type)
+{
+ register symbolS *add_symbolP;
+ register symbolS *sub_symbolP;
+ register long add_number;
+ register int size;
+ register char *place;
+ register long where;
+ register char pcrel;
+ register fragS *fragP;
+ register segT add_symbol_segment = SEG_ABSOLUTE;
+
+
+ for ( ; fixP; fixP = fixP->fx_next)
+ {
+ fragP = fixP->fx_frag;
+ know(fragP);
+ where = fixP->fx_where;
+ place = fragP->fr_literal + where;
+ size = fixP->fx_size;
+ add_symbolP = fixP->fx_addsy;
+#ifdef TC_I960
+ if (fixP->fx_callj && TC_S_IS_CALLNAME(add_symbolP)) {
+ /* Relocation should be done via the
+ associated 'bal' entry point
+ symbol. */
+
+ if (!TC_S_IS_BALNAME(tc_get_bal_of_call(add_symbolP))) {
+ as_bad("No 'bal' entry point for leafproc %s",
+ S_GET_NAME(add_symbolP));
+ continue;
+ }
+ fixP->fx_addsy = add_symbolP = tc_get_bal_of_call(add_symbolP);
+ } /* callj relocation */
+#endif
+ sub_symbolP = fixP->fx_subsy;
+ add_number = fixP->fx_offset;
+ pcrel = fixP->fx_pcrel;
+
+ if (add_symbolP) {
+ add_symbol_segment = S_GET_SEGMENT(add_symbolP);
+ } /* if there is an addend */
+
+ if (sub_symbolP) {
+ if (!add_symbolP) {
+ /* Its just -sym */
+ if (S_GET_SEGMENT(sub_symbolP) != SEG_ABSOLUTE) {
+ as_bad("Negative of non-absolute symbol %s", S_GET_NAME(sub_symbolP));
+ } /* not absolute */
+
+ add_number -= S_GET_VALUE(sub_symbolP);
+
+ /* if sub_symbol is in the same segment that add_symbol
+ and add_symbol is either in DATA, TEXT, BSS or ABSOLUTE */
+ } else if ((S_GET_SEGMENT(sub_symbolP) == add_symbol_segment)
+ && (SEG_NORMAL(add_symbol_segment)
+ || (add_symbol_segment == SEG_ABSOLUTE))) {
+ /* Difference of 2 symbols from same segment. */
+ /* Can't make difference of 2 undefineds: 'value' means */
+ /* something different for N_UNDF. */
+#ifdef TC_I960
+ /* Makes no sense to use the difference of 2 arbitrary symbols
+ * as the target of a call instruction.
+ */
+ if (fixP->fx_callj) {
+ as_bad("callj to difference of 2 symbols");
+ }
+#endif /* TC_I960 */
+ add_number += S_GET_VALUE(add_symbolP) -
+ S_GET_VALUE(sub_symbolP);
+
+ add_symbolP = NULL;
+ fixP->fx_addsy = NULL;
+ } else {
+ /* Different segments in subtraction. */
+ know(!(S_IS_EXTERNAL(sub_symbolP) && (S_GET_SEGMENT(sub_symbolP) == SEG_ABSOLUTE)));
+
+ if ((S_GET_SEGMENT(sub_symbolP) == SEG_ABSOLUTE)) {
+ add_number -= S_GET_VALUE(sub_symbolP);
+ } else {
+ as_bad("Can't emit reloc {- %s-seg symbol \"%s\"} @ file address %d.",
+ segment_name(S_GET_SEGMENT(sub_symbolP)),
+ S_GET_NAME(sub_symbolP), fragP->fr_address + where);
+ } /* if absolute */
+ }
+ } /* if sub_symbolP */
+
+ if (add_symbolP) {
+ if (add_symbol_segment == this_segment_type && pcrel) {
+ /*
+ * This fixup was made when the symbol's segment was
+ * SEG_UNKNOWN, but it is now in the local segment.
+ * So we know how to do the address without relocation.
+ */
+#ifdef TC_I960
+ /* reloc_callj() may replace a 'call' with a 'calls' or a 'bal',
+ * in which cases it modifies *fixP as appropriate. In the case
+ * of a 'calls', no further work is required, and *fixP has been
+ * set up to make the rest of the code below a no-op.
+ */
+ reloc_callj(fixP);
+#endif /* TC_I960 */
+
+ add_number += S_GET_VALUE(add_symbolP);
+ add_number -= md_pcrel_from (fixP);
+ pcrel = 0; /* Lie. Don't want further pcrel processing. */
+ fixP->fx_addsy = NULL; /* No relocations please. */
+ } else
+ {
+ switch (add_symbol_segment)
+ {
+ case SEG_ABSOLUTE:
+#ifdef TC_I960
+ reloc_callj(fixP); /* See comment about reloc_callj() above*/
+#endif /* TC_I960 */
+ add_number += S_GET_VALUE(add_symbolP);
+ fixP->fx_addsy = NULL;
+ add_symbolP = NULL;
+ break;
+ default:
+
+ add_number += S_GET_VALUE(add_symbolP) +
+ segment_info[S_GET_SEGMENT(add_symbolP)].scnhdr.s_paddr ;
+ break;
+
+ case SEG_UNKNOWN:
+#ifdef TC_I960
+ if ((int)fixP->fx_bit_fixP == 13) {
+ /* This is a COBR instruction. They have only a
+ * 13-bit displacement and are only to be used
+ * for local branches: flag as error, don't generate
+ * relocation.
+ */
+ as_bad("can't use COBR format with external label");
+ fixP->fx_addsy = NULL; /* No relocations please. */
+ continue;
+ } /* COBR */
+#endif /* TC_I960 */
+
+
+
+ break;
+
+
+ } /* switch on symbol seg */
+ } /* if not in local seg */
+ } /* if there was a + symbol */
+
+ if (pcrel) {
+ add_number -= md_pcrel_from(fixP);
+ if (add_symbolP == 0) {
+ fixP->fx_addsy = & abs_symbol;
+ } /* if there's an add_symbol */
+ } /* if pcrel */
+
+ if (!fixP->fx_bit_fixP) {
+ if ((size == 1
+ && (add_number & ~0xFF) && (add_number & ~0xFF != (-1 & ~0xFF))) ||
+ (size == 2
+ && (add_number & ~0xFFFF) && (add_number & ~0xFFFF != (-1 & ~0xFFFF)))) {
+ as_bad("Value of %d too large for field of %d bytes at 0x%x",
+ add_number, size, fragP->fr_address + where);
+ } /* generic error checking */
+ } /* not a bit fix */
+ /* once this fix has been applied, we don't have to output anything
+ nothing more need be done -*/
+ md_apply_fix(fixP, add_number);
+
+ } /* For each fixS in this segment. */
+
+
+} /* fixup_segment() */
+#endif
+
+/*
+ * Local Variables:
+ * fill-column: 131
+ * End:
+ */
+
+/* end of obj-coffbfd.c */
diff --git a/gnu/usr.bin/as/config/obj-coffbfd.h b/gnu/usr.bin/as/config/obj-coffbfd.h
new file mode 100644
index 0000000..5ccefab
--- /dev/null
+++ b/gnu/usr.bin/as/config/obj-coffbfd.h
@@ -0,0 +1,516 @@
+/* coff object file format
+ Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
+
+ This file is part of GAS.
+
+ GAS is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GAS is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GAS; see the file COPYING. If not, write to
+ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#ifndef OBJ_FORMAT_H
+#define OBJ_FORMAT_H
+
+#define OBJ_COFF 1
+
+#include "targ-cpu.h"
+
+#include "bfd.h"
+
+/*extern bfd *stdoutput;*/
+/* This internal_lineno crap is to stop namespace pollution from the
+ bfd internal coff headerfile. */
+
+#define internal_lineno bfd_internal_lineno
+#include "coff/internal.h"
+#undef internal_lineno
+
+#if defined(TC_H8300)
+#include "coff/h8300.h"
+#define TARGET_FORMAT "coff-h8300"
+#elif defined(TC_A29K)
+#include "coff/a29k.h"
+#define TARGET_FORMAT "coff-a29k-big"
+#else
+help me
+#endif
+
+#if 0
+ /* Define some processor dependent values according to the processor we are
+ on. */
+#if defined(TC_H8300)
+#define BYTE_ORDERING 0
+#define FILE_HEADER_MAGIC H8300MAGIC
+#elif defined(TC_M68K)
+
+#define BYTE_ORDERING F_AR32W /* See filehdr.h for more info. */
+#ifndef FILE_HEADER_MAGIC
+#define FILE_HEADER_MAGIC MC68MAGIC /* ... */
+#endif /* FILE_HEADER_MAGIC */
+
+#elif defined(TC_I386)
+
+#define BYTE_ORDERING F_AR32WR /* See filehdr.h for more info. */
+#ifndef FILE_HEADER_MAGIC
+#define FILE_HEADER_MAGIC I386MAGIC /* ... */
+#endif /* FILE_HEADER_MAGIC */
+
+#elif defined(TC_I960)
+
+#define BYTE_ORDERING F_AR32WR /* See filehdr.h for more info. */
+#ifndef FILE_HEADER_MAGIC
+#define FILE_HEADER_MAGIC I960ROMAGIC /* ... */
+#endif /* FILE_HEADER_MAGIC */
+
+#elif defined(TC_A29K)
+
+#define BYTE_ORDERING F_AR32W /* big endian. */
+#ifndef FILE_HEADER_MAGIC
+#define FILE_HEADER_MAGIC SIPFBOMAGIC
+#endif /* FILE_HEADER_MAGIC */
+
+#else
+you lose
+#endif
+
+#endif
+
+#ifndef OBJ_COFF_MAX_AUXENTRIES
+#define OBJ_COFF_MAX_AUXENTRIES 1
+#endif /* OBJ_COFF_MAX_AUXENTRIES */
+
+
+ extern const segT N_TYPE_seg[];
+
+/* Magic number of paged executable. */
+#define DEFAULT_MAGIC_NUMBER_FOR_OBJECT_FILE 0x8300
+
+
+/* SYMBOL TABLE */
+
+/* targets may also set this */
+#ifndef SYMBOLS_NEED_BACKPOINTERS
+#define SYMBOLS_NEED_BACKPOINTERS 1
+#endif /* SYMBOLS_NEED_BACKPOINTERS */
+
+/* Symbol table entry data type */
+
+typedef struct
+{
+ struct internal_syment ost_entry; /* Basic symbol */
+ union internal_auxent ost_auxent[OBJ_COFF_MAX_AUXENTRIES]; /* Auxiliary entry. */
+
+ unsigned int ost_flags; /* obj_coff internal use only flags */
+} obj_symbol_type;
+
+#ifndef DO_NOT_STRIP
+#define DO_NOT_STRIP 0
+#define DO_STRIP 1
+#endif
+/* Symbol table macros and constants */
+
+/* Possible and usefull section number in symbol table
+ * The values of TEXT, DATA and BSS may not be portable.
+ */
+
+#define C_ABS_SECTION N_ABS
+#define C_UNDEF_SECTION N_UNDEF
+#define C_DEBUG_SECTION N_DEBUG
+#define C_NTV_SECTION N_TV
+#define C_PTV_SECTION P_TV
+#define C_REGISTER_SECTION 20
+
+/*
+ * Macros to extract information from a symbol table entry.
+ * This syntaxic indirection allows independence regarding a.out or coff.
+ * The argument (s) of all these macros is a pointer to a symbol table entry.
+ */
+
+/* Predicates */
+/* True if the symbol is external */
+#define S_IS_EXTERNAL(s) ((s)->sy_symbol.ost_entry.n_scnum == C_UNDEF_SECTION)
+/* True if symbol has been defined, ie :
+ section > 0 (DATA, TEXT or BSS)
+ section == 0 and value > 0 (external bss symbol) */
+#define S_IS_DEFINED(s) ((s)->sy_symbol.ost_entry.n_scnum > C_UNDEF_SECTION || \
+ ((s)->sy_symbol.ost_entry.n_scnum == C_UNDEF_SECTION && \
+ (s)->sy_symbol.ost_entry.n_value > 0))
+/* True if a debug special symbol entry */
+#define S_IS_DEBUG(s) ((s)->sy_symbol.ost_entry.n_scnum == C_DEBUG_SECTION)
+/* True if a symbol is local symbol name */
+/* A symbol name whose name begin with ^A is a gas internal pseudo symbol */
+#define S_IS_LOCAL(s) (S_GET_NAME(s)[0] == '\001' || \
+ (s)->sy_symbol.ost_entry.n_scnum == C_REGISTER_SECTION || \
+ (S_LOCAL_NAME(s) && !flagseen['L']))
+/* True if a symbol is not defined in this file */
+#define S_IS_EXTERN(s) ((s)->sy_symbol.ost_entry.n_scnum == 0 && (s)->sy_symbol.ost_entry.n_value == 0)
+/*
+ * True if a symbol can be multiply defined (bss symbols have this def
+ * though it is bad practice)
+ */
+#define S_IS_COMMON(s) ((s)->sy_symbol.ost_entry.n_scnum == 0 && (s)->sy_symbol.ost_entry.n_value != 0)
+/* True if a symbol name is in the string table, i.e. its length is > 8. */
+#define S_IS_STRING(s) (strlen(S_GET_NAME(s)) > 8 ? 1 : 0)
+
+/* Accessors */
+/* The name of the symbol */
+#define S_GET_NAME(s) ((char*)(s)->sy_symbol.ost_entry.n_offset)
+/* The pointer to the string table */
+#define S_GET_OFFSET(s) ((s)->sy_symbol.ost_entry.n_offset)
+/* The zeroes if symbol name is longer than 8 chars */
+#define S_GET_ZEROES(s) ((s)->sy_symbol.ost_entry.n_zeroes)
+/* The value of the symbol */
+#define S_GET_VALUE(s) ((unsigned) ((s)->sy_symbol.ost_entry.n_value))
+/* The numeric value of the segment */
+#define S_GET_SEGMENT(s) s_get_segment(s)
+/* The data type */
+#define S_GET_DATA_TYPE(s) ((s)->sy_symbol.ost_entry.n_type)
+/* The storage class */
+#define S_GET_STORAGE_CLASS(s) ((s)->sy_symbol.ost_entry.n_sclass)
+/* The number of auxiliary entries */
+#define S_GET_NUMBER_AUXILIARY(s) ((s)->sy_symbol.ost_entry.n_numaux)
+
+/* Modifiers */
+/* Set the name of the symbol */
+#define S_SET_NAME(s,v) ((s)->sy_symbol.ost_entry.n_offset = (unsigned long)(v))
+/* Set the offset of the symbol */
+#define S_SET_OFFSET(s,v) ((s)->sy_symbol.ost_entry.n_offset = (v))
+/* The zeroes if symbol name is longer than 8 chars */
+#define S_SET_ZEROES(s,v) ((s)->sy_symbol.ost_entry.n_zeroes = (v))
+/* Set the value of the symbol */
+#define S_SET_VALUE(s,v) ((s)->sy_symbol.ost_entry.n_value = (v))
+/* The numeric value of the segment */
+#define S_SET_SEGMENT(s,v) ((s)->sy_symbol.ost_entry.n_scnum = SEGMENT_TO_SYMBOL_TYPE(v))
+/* The data type */
+#define S_SET_DATA_TYPE(s,v) ((s)->sy_symbol.ost_entry.n_type = (v))
+/* The storage class */
+#define S_SET_STORAGE_CLASS(s,v) ((s)->sy_symbol.ost_entry.n_sclass = (v))
+/* The number of auxiliary entries */
+#define S_SET_NUMBER_AUXILIARY(s,v) ((s)->sy_symbol.ost_entry.n_numaux = (v))
+
+/* Additional modifiers */
+/* The symbol is external (does not mean undefined) */
+#define S_SET_EXTERNAL(s) { S_SET_STORAGE_CLASS(s, C_EXT) ; SF_CLEAR_LOCAL(s); }
+
+/* Auxiliary entry macros. SA_ stands for symbol auxiliary */
+/* Omit the tv related fields */
+/* Accessors */
+#ifdef BFD_HEADERS
+#define SA_GET_SYM_TAGNDX(s) ((s)->sy_symbol.ost_auxent[0].x_sym.x_tagndx.l)
+#else
+#define SA_GET_SYM_TAGNDX(s) ((s)->sy_symbol.ost_auxent[0].x_sym.x_tagndx)
+#endif
+#define SA_GET_SYM_LNNO(s) ((s)->sy_symbol.ost_auxent[0].x_sym.x_misc.x_lnsz.x_lnno)
+#define SA_GET_SYM_SIZE(s) ((s)->sy_symbol.ost_auxent[0].x_sym.x_misc.x_lnsz.x_size)
+#define SA_GET_SYM_FSIZE(s) ((s)->sy_symbol.ost_auxent[0].x_sym.x_misc.x_fsize)
+#define SA_GET_SYM_LNNOPTR(s) ((s)->sy_symbol.ost_auxent[0].x_sym.x_fcnary.x_fcn.x_lnnoptr)
+#ifdef BFD_HEADERS
+#define SA_GET_SYM_ENDNDX(s) ((s)->sy_symbol.ost_auxent[0].x_sym.x_fcnary.x_fcn.x_endndx.l)
+#else
+#define SA_GET_SYM_ENDNDX(s) ((s)->sy_symbol.ost_auxent[0].x_sym.x_fcnary.x_fcn.x_endndx)
+#endif
+#define SA_GET_SYM_DIMEN(s,i) ((s)->sy_symbol.ost_auxent[0].x_sym.x_fcnary.x_ary.x_dimen[(i)])
+#define SA_GET_FILE_FNAME(s) ((s)->sy_symbol.ost_auxent[0].x_file.x_fname)
+#define SA_GET_SCN_SCNLEN(s) ((s)->sy_symbol.ost_auxent[0].x_scn.x_scnlen)
+#define SA_GET_SCN_NRELOC(s) ((s)->sy_symbol.ost_auxent[0].x_scn.x_nreloc)
+#define SA_GET_SCN_NLINNO(s) ((s)->sy_symbol.ost_auxent[0].x_scn.x_nlinno)
+
+/* Modifiers */
+#ifdef BFD_HEADERS
+#define SA_SET_SYM_TAGNDX(s,v) ((s)->sy_symbol.ost_auxent[0].x_sym.x_tagndx.l=(v))
+#else
+#define SA_SET_SYM_TAGNDX(s,v) ((s)->sy_symbol.ost_auxent[0].x_sym.x_tagndx=(v))
+#endif
+#define SA_SET_SYM_LNNO(s,v) ((s)->sy_symbol.ost_auxent[0].x_sym.x_misc.x_lnsz.x_lnno=(v))
+#define SA_SET_SYM_SIZE(s,v) ((s)->sy_symbol.ost_auxent[0].x_sym.x_misc.x_lnsz.x_size=(v))
+#define SA_SET_SYM_FSIZE(s,v) ((s)->sy_symbol.ost_auxent[0].x_sym.x_misc.x_fsize=(v))
+#define SA_SET_SYM_LNNOPTR(s,v) ((s)->sy_symbol.ost_auxent[0].x_sym.x_fcnary.x_fcn.x_lnnoptr=(v))
+#ifdef BFD_HEADERS
+#define SA_SET_SYM_ENDNDX(s,v) ((s)->sy_symbol.ost_auxent[0].x_sym.x_fcnary.x_fcn.x_endndx.l=(v))
+#else
+#define SA_SET_SYM_ENDNDX(s,v) ((s)->sy_symbol.ost_auxent[0].x_sym.x_fcnary.x_fcn.x_endndx=(v))
+#endif
+#define SA_SET_SYM_DIMEN(s,i,v) ((s)->sy_symbol.ost_auxent[0].x_sym.x_fcnary.x_ary.x_dimen[(i)]=(v))
+#define SA_SET_FILE_FNAME(s,v) strncpy((s)->sy_symbol.ost_auxent[0].x_file.x_fname,(v),FILNMLEN)
+#define SA_SET_SCN_SCNLEN(s,v) ((s)->sy_symbol.ost_auxent[0].x_scn.x_scnlen=(v))
+#define SA_SET_SCN_NRELOC(s,v) ((s)->sy_symbol.ost_auxent[0].x_scn.x_nreloc=(v))
+#define SA_SET_SCN_NLINNO(s,v) ((s)->sy_symbol.ost_auxent[0].x_scn.x_nlinno=(v))
+
+/*
+ * Internal use only definitions. SF_ stands for symbol flags.
+ *
+ * These values can be assigned to sy_symbol.ost_flags field of a symbolS.
+ *
+ * You'll break i960 if you shift the SYSPROC bits anywhere else. for
+ * more on the balname/callname hack, see tc-i960.h. b.out is done
+ * differently.
+ */
+
+#define SF_I960_MASK (0x000001ff) /* Bits 0-8 are used by the i960 port. */
+#define SF_SYSPROC (0x0000003f) /* bits 0-5 are used to store the sysproc number */
+#define SF_IS_SYSPROC (0x00000040) /* bit 6 marks symbols that are sysprocs */
+#define SF_BALNAME (0x00000080) /* bit 7 marks BALNAME symbols */
+#define SF_CALLNAME (0x00000100) /* bit 8 marks CALLNAME symbols */
+
+#define SF_NORMAL_MASK (0x0000ffff) /* bits 12-15 are general purpose. */
+
+#define SF_STATICS (0x00001000) /* Mark the .text & all symbols */
+#define SF_DEFINED (0x00002000) /* Symbol is defined in this file */
+#define SF_STRING (0x00004000) /* Symbol name length > 8 */
+#define SF_LOCAL (0x00008000) /* Symbol must not be emitted */
+
+#define SF_DEBUG_MASK (0xffff0000) /* bits 16-31 are debug info */
+
+#define SF_FUNCTION (0x00010000) /* The symbol is a function */
+#define SF_PROCESS (0x00020000) /* Process symbol before write */
+#define SF_TAGGED (0x00040000) /* Is associated with a tag */
+#define SF_TAG (0x00080000) /* Is a tag */
+#define SF_DEBUG (0x00100000) /* Is in debug or abs section */
+#define SF_GET_SEGMENT (0x00200000) /* Get the section of the forward symbol. */
+/* All other bits are unused. */
+
+/* Accessors */
+#define SF_GET(s) ((s)->sy_symbol.ost_flags)
+#define SF_GET_NORMAL_FIELD(s) ((s)->sy_symbol.ost_flags & SF_NORMAL_MASK)
+#define SF_GET_DEBUG_FIELD(s) ((s)->sy_symbol.ost_flags & SF_DEBUG_MASK)
+#define SF_GET_FILE(s) ((s)->sy_symbol.ost_flags & SF_FILE)
+#define SF_GET_STATICS(s) ((s)->sy_symbol.ost_flags & SF_STATICS)
+#define SF_GET_DEFINED(s) ((s)->sy_symbol.ost_flags & SF_DEFINED)
+#define SF_GET_STRING(s) ((s)->sy_symbol.ost_flags & SF_STRING)
+#define SF_GET_LOCAL(s) ((s)->sy_symbol.ost_flags & SF_LOCAL)
+#define SF_GET_FUNCTION(s) ((s)->sy_symbol.ost_flags & SF_FUNCTION)
+#define SF_GET_PROCESS(s) ((s)->sy_symbol.ost_flags & SF_PROCESS)
+#define SF_GET_DEBUG(s) ((s)->sy_symbol.ost_flags & SF_DEBUG)
+#define SF_GET_TAGGED(s) ((s)->sy_symbol.ost_flags & SF_TAGGED)
+#define SF_GET_TAG(s) ((s)->sy_symbol.ost_flags & SF_TAG)
+#define SF_GET_GET_SEGMENT(s) ((s)->sy_symbol.ost_flags & SF_GET_SEGMENT)
+#define SF_GET_I960(s) ((s)->sy_symbol.ost_flags & SF_I960_MASK) /* used by i960 */
+#define SF_GET_BALNAME(s) ((s)->sy_symbol.ost_flags & SF_BALNAME) /* used by i960 */
+#define SF_GET_CALLNAME(s) ((s)->sy_symbol.ost_flags & SF_CALLNAME) /* used by i960 */
+#define SF_GET_IS_SYSPROC(s) ((s)->sy_symbol.ost_flags & SF_IS_SYSPROC) /* used by i960 */
+#define SF_GET_SYSPROC(s) ((s)->sy_symbol.ost_flags & SF_SYSPROC) /* used by i960 */
+
+/* Modifiers */
+#define SF_SET(s,v) ((s)->sy_symbol.ost_flags = (v))
+#define SF_SET_NORMAL_FIELD(s,v)((s)->sy_symbol.ost_flags |= ((v) & SF_NORMAL_MASK))
+#define SF_SET_DEBUG_FIELD(s,v) ((s)->sy_symbol.ost_flags |= ((v) & SF_DEBUG_MASK))
+#define SF_SET_FILE(s) ((s)->sy_symbol.ost_flags |= SF_FILE)
+#define SF_SET_STATICS(s) ((s)->sy_symbol.ost_flags |= SF_STATICS)
+#define SF_SET_DEFINED(s) ((s)->sy_symbol.ost_flags |= SF_DEFINED)
+#define SF_SET_STRING(s) ((s)->sy_symbol.ost_flags |= SF_STRING)
+#define SF_SET_LOCAL(s) ((s)->sy_symbol.ost_flags |= SF_LOCAL)
+#define SF_CLEAR_LOCAL(s) ((s)->sy_symbol.ost_flags &= ~SF_LOCAL)
+#define SF_SET_FUNCTION(s) ((s)->sy_symbol.ost_flags |= SF_FUNCTION)
+#define SF_SET_PROCESS(s) ((s)->sy_symbol.ost_flags |= SF_PROCESS)
+#define SF_SET_DEBUG(s) ((s)->sy_symbol.ost_flags |= SF_DEBUG)
+#define SF_SET_TAGGED(s) ((s)->sy_symbol.ost_flags |= SF_TAGGED)
+#define SF_SET_TAG(s) ((s)->sy_symbol.ost_flags |= SF_TAG)
+#define SF_SET_GET_SEGMENT(s) ((s)->sy_symbol.ost_flags |= SF_GET_SEGMENT)
+#define SF_SET_I960(s,v) ((s)->sy_symbol.ost_flags |= ((v) & SF_I960_MASK)) /* used by i960 */
+#define SF_SET_BALNAME(s) ((s)->sy_symbol.ost_flags |= SF_BALNAME) /* used by i960 */
+#define SF_SET_CALLNAME(s) ((s)->sy_symbol.ost_flags |= SF_CALLNAME) /* used by i960 */
+#define SF_SET_IS_SYSPROC(s) ((s)->sy_symbol.ost_flags |= SF_IS_SYSPROC) /* used by i960 */
+#define SF_SET_SYSPROC(s,v) ((s)->sy_symbol.ost_flags |= ((v) & SF_SYSPROC)) /* used by i960 */
+
+/* File header macro and type definition */
+
+/*
+ * File position calculators. Beware to use them when all the
+ * appropriate fields are set in the header.
+ */
+
+#ifdef OBJ_COFF_OMIT_OPTIONAL_HEADER
+#define OBJ_COFF_AOUTHDRSZ (0)
+#else
+#define OBJ_COFF_AOUTHDRSZ (AOUTHDRSZ)
+#endif /* OBJ_COFF_OMIT_OPTIONAL_HEADER */
+
+#define H_GET_FILE_SIZE(h) \
+ (long)(FILHSZ + OBJ_COFF_AOUTHDRSZ + \
+ H_GET_NUMBER_OF_SECTIONS(h) * SCNHSZ + \
+ H_GET_TEXT_SIZE(h) + H_GET_DATA_SIZE(h) + \
+ H_GET_RELOCATION_SIZE(h) + H_GET_LINENO_SIZE(h) + \
+ H_GET_SYMBOL_TABLE_SIZE(h) + \
+ (h)->string_table_size)
+#define H_GET_TEXT_FILE_OFFSET(h) \
+ (long)(FILHSZ + OBJ_COFF_AOUTHDRSZ + \
+ H_GET_NUMBER_OF_SECTIONS(h) * SCNHSZ)
+#define H_GET_DATA_FILE_OFFSET(h) \
+ (long)(FILHSZ + OBJ_COFF_AOUTHDRSZ + \
+ H_GET_NUMBER_OF_SECTIONS(h) * SCNHSZ + \
+ H_GET_TEXT_SIZE(h))
+#define H_GET_BSS_FILE_OFFSET(h) 0
+#define H_GET_RELOCATION_FILE_OFFSET(h) \
+ (long)(FILHSZ + OBJ_COFF_AOUTHDRSZ + \
+ H_GET_NUMBER_OF_SECTIONS(h) * SCNHSZ + \
+ H_GET_TEXT_SIZE(h) + H_GET_DATA_SIZE(h))
+#define H_GET_LINENO_FILE_OFFSET(h) \
+ (long)(FILHSZ + OBJ_COFF_AOUTHDRSZ + \
+ H_GET_NUMBER_OF_SECTIONS(h) * SCNHSZ + \
+ H_GET_TEXT_SIZE(h) + H_GET_DATA_SIZE(h) + \
+ H_GET_RELOCATION_SIZE(h))
+#define H_GET_SYMBOL_TABLE_FILE_OFFSET(h) \
+ (long)(FILHSZ + OBJ_COFF_AOUTHDRSZ + \
+ H_GET_NUMBER_OF_SECTIONS(h) * SCNHSZ + \
+ H_GET_TEXT_SIZE(h) + H_GET_DATA_SIZE(h) + \
+ H_GET_RELOCATION_SIZE(h) + H_GET_LINENO_SIZE(h))
+
+/* Accessors */
+/* aouthdr */
+#define H_GET_MAGIC_NUMBER(h) ((h)->aouthdr.magic)
+#define H_GET_VERSION_STAMP(h) ((h)->aouthdr.vstamp)
+#define H_GET_TEXT_SIZE(h) ((h)->aouthdr.tsize)
+#define H_GET_DATA_SIZE(h) ((h)->aouthdr.dsize)
+#define H_GET_BSS_SIZE(h) ((h)->aouthdr.bsize)
+#define H_GET_ENTRY_POINT(h) ((h)->aouthdr.entry)
+#define H_GET_TEXT_START(h) ((h)->aouthdr.text_start)
+#define H_GET_DATA_START(h) ((h)->aouthdr.data_start)
+/* filehdr */
+#define H_GET_FILE_MAGIC_NUMBER(h) ((h)->filehdr.f_magic)
+#define H_GET_NUMBER_OF_SECTIONS(h) ((h)->filehdr.f_nscns)
+#define H_GET_TIME_STAMP(h) ((h)->filehdr.f_timdat)
+#define H_GET_SYMBOL_TABLE_POINTER(h) ((h)->filehdr.f_symptr)
+#define H_GET_SYMBOL_COUNT(h) ((h)->filehdr.f_nsyms)
+#define H_GET_SYMBOL_TABLE_SIZE(h) (H_GET_SYMBOL_COUNT(h) * SYMESZ)
+#define H_GET_SIZEOF_OPTIONAL_HEADER(h) ((h)->filehdr.f_opthdr)
+#define H_GET_FLAGS(h) ((h)->filehdr.f_flags)
+/* Extra fields to achieve bsd a.out compatibility and for convenience */
+#define H_GET_RELOCATION_SIZE(h) ((h)->relocation_size)
+#define H_GET_STRING_SIZE(h) ((h)->string_table_size)
+#define H_GET_LINENO_SIZE(h) ((h)->lineno_size)
+
+#ifndef OBJ_COFF_OMIT_OPTIONAL_HEADER
+#define H_GET_HEADER_SIZE(h) (sizeof(FILHDR) \
+ + sizeof(AOUTHDR)\
+ + (H_GET_NUMBER_OF_SECTIONS(h) * SCNHSZ))
+#else /* OBJ_COFF_OMIT_OPTIONAL_HEADER */
+#define H_GET_HEADER_SIZE(h) (sizeof(FILHDR) \
+ + (H_GET_NUMBER_OF_SECTIONS(h) * SCNHSZ))
+#endif /* OBJ_COFF_OMIT_OPTIONAL_HEADER */
+
+#define H_GET_TEXT_RELOCATION_SIZE(h) (text_section_header.s_nreloc * RELSZ)
+#define H_GET_DATA_RELOCATION_SIZE(h) (data_section_header.s_nreloc * RELSZ)
+
+/* Modifiers */
+/* aouthdr */
+#define H_SET_MAGIC_NUMBER(h,v) ((h)->aouthdr.magic = (v))
+#define H_SET_VERSION_STAMP(h,v) ((h)->aouthdr.vstamp = (v))
+#define H_SET_TEXT_SIZE(h,v) ((h)->aouthdr.tsize = (v))
+#define H_SET_DATA_SIZE(h,v) ((h)->aouthdr.dsize = (v))
+#define H_SET_BSS_SIZE(h,v) ((h)->aouthdr.bsize = (v))
+#define H_SET_ENTRY_POINT(h,v) ((h)->aouthdr.entry = (v))
+#define H_SET_TEXT_START(h,v) ((h)->aouthdr.text_start = (v))
+#define H_SET_DATA_START(h,v) ((h)->aouthdr.data_start = (v))
+/* filehdr */
+#define H_SET_FILE_MAGIC_NUMBER(h,v) ((h)->filehdr.f_magic = (v))
+#define H_SET_NUMBER_OF_SECTIONS(h,v) ((h)->filehdr.f_nscns = (v))
+#define H_SET_TIME_STAMP(h,v) ((h)->filehdr.f_timdat = (v))
+#define H_SET_SYMBOL_TABLE_POINTER(h,v) ((h)->filehdr.f_symptr = (v))
+#define H_SET_SYMBOL_TABLE_SIZE(h,v) ((h)->filehdr.f_nsyms = (v))
+#define H_SET_SIZEOF_OPTIONAL_HEADER(h,v) ((h)->filehdr.f_opthdr = (v))
+#define H_SET_FLAGS(h,v) ((h)->filehdr.f_flags = (v))
+/* Extra fields to achieve bsd a.out compatibility and for convinience */
+#define H_SET_RELOCATION_SIZE(h,t,d) ((h)->relocation_size = (t)+(d))
+#define H_SET_STRING_SIZE(h,v) ((h)->string_table_size = (v))
+#define H_SET_LINENO_SIZE(h,v) ((h)->lineno_size = (v))
+
+/* Segment flipping */
+#define segment_name(v) (seg_name[(int) (v)])
+
+typedef struct {
+#ifdef BFD_HEADERS
+ struct internal_aouthdr aouthdr; /* a.out header */
+ struct internal_filehdr filehdr; /* File header, not machine dep. */
+#else
+ AOUTHDR aouthdr; /* a.out header */
+ FILHDR filehdr; /* File header, not machine dep. */
+#endif
+ long string_table_size; /* names + '\0' + sizeof(int) */
+ long relocation_size; /* Cumulated size of relocation
+ information for all sections in
+ bytes. */
+ long lineno_size; /* Size of the line number information
+ table in bytes */
+} object_headers;
+
+
+
+struct lineno_list
+{
+
+ struct bfd_internal_lineno line;
+ char* frag; /* Frag to which the line number is related */
+ struct lineno_list* next; /* Forward chain pointer */
+} ;
+
+
+
+
+/* stack stuff */
+typedef struct {
+ unsigned long chunk_size;
+ unsigned long element_size;
+ unsigned long size;
+ char* data;
+ unsigned long pointer;
+} stack;
+
+
+
+char *EXFUN(stack_pop,(stack *st));
+char *EXFUN(stack_push,(stack *st, char *element));
+char *EXFUN(stack_top,(stack *st));
+stack *EXFUN(stack_init,(unsigned long chunk_size, unsigned long element_size));
+void EXFUN(c_dot_file_symbol,(char *filename));
+void EXFUN(obj_extra_stuff,(object_headers *headers));
+void EXFUN(stack_delete,(stack *st));
+
+
+
+void EXFUN(c_section_header,(
+
+ struct internal_scnhdr *header,
+ char *name,
+ long core_address,
+ long size,
+ long data_ptr,
+ long reloc_ptr,
+ long lineno_ptr,
+ long reloc_number,
+ long lineno_number,
+ long alignment));
+
+
+/* sanity check */
+
+#ifdef TC_I960
+#ifndef C_LEAFSTAT
+hey! Where is the C_LEAFSTAT definition? i960-coff support is depending on it.
+#endif /* no C_LEAFSTAT */
+#endif /* TC_I960 */
+#ifdef BFD_HEADERS
+ extern struct internal_scnhdr data_section_header;
+extern struct internal_scnhdr text_section_header;
+#else
+extern SCNHDR data_section_header;
+extern SCNHDR text_section_header;
+#endif
+#endif
+
+/*
+ * Local Variables:
+ * comment-column: 0
+ * fill-column: 131
+ * End:
+ */
+
+/* end of obj-coffbfd.h */
diff --git a/gnu/usr.bin/as/config/obj-generic.c b/gnu/usr.bin/as/config/obj-generic.c
new file mode 100644
index 0000000..2f69ce4
--- /dev/null
+++ b/gnu/usr.bin/as/config/obj-generic.c
@@ -0,0 +1,41 @@
+/* This file is obj-generic.c and is intended to be a template for
+ object format specific source files.
+
+ Copyright (C) 1987-1992 Free Software Foundation, Inc.
+
+ This file is part of GAS, the GNU Assembler.
+
+ GAS is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GAS is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GAS; see the file COPYING. If not, write to
+ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* Chars that can be used to separate mant from exp in floating point nums */
+char EXP_CHARS[] = "eE";
+
+/* Chars that mean this number is a floating point constant */
+/* As in 0f12.456 */
+/* or 0d1.2345e12 */
+char FLT_CHARS[] = "rRsSfFdDxXpP";
+
+/* These chars start a comment anywhere in a source file (except inside
+ another comment */
+const char comment_chars[] = "#";
+
+/*
+ * Local Variables:
+ * comment-column: 0
+ * fill-column: 131
+ * End:
+ */
+
+/* end of obj-generic.c */
diff --git a/gnu/usr.bin/as/config/obj-generic.h b/gnu/usr.bin/as/config/obj-generic.h
new file mode 100644
index 0000000..24a6ace
--- /dev/null
+++ b/gnu/usr.bin/as/config/obj-generic.h
@@ -0,0 +1,78 @@
+/* This file is obj-generic.h
+ Copyright (C) 1987-1992 Free Software Foundation, Inc.
+
+ This file is part of GAS, the GNU Assembler.
+
+ GAS is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GAS is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GAS; see the file COPYING. If not, write to
+ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/*
+ * This file is obj-generic.h and is intended to be a template for
+ * object format specific header files.
+ */
+
+/* define an obj specific macro off which target cpu back ends may key. */
+#define OBJ_GENERIC 1
+
+/* include whatever target cpu is appropriate. */
+#include "targ-cpu.h"
+
+/*
+ * SYMBOLS
+ */
+
+/*
+ * If your object format needs to reorder symbols, define this. When
+ * defined, symbols are kept on a doubly linked list and functions are
+ * made available for push, insert, append, and delete. If not defined,
+ * symbols are kept on a singly linked list, only the append and clear
+ * facilities are available, and they are macros.
+ */
+
+/* #define SYMBOLS_NEED_PACKPOINTERS */
+
+/* */
+typedef struct {
+ void *nothing;
+} obj_symbol_type; /* should be the format's symbol structure */
+
+typedef void *object_headers;
+
+/* symbols have names */
+#define S_GET_NAME(s) ("foo") /* get the name of a symbolP */
+#define S_SET_NAME(s,v) ;
+ /* symbols have segments */
+#define S_GET_SEGMENT(s) (SEG_UNKNOWN)
+#define S_SET_SEGMENT(s,v) ;
+ /* symbols have a value */
+#define S_GET_VALUE(s) (0)
+#define S_SET_VALUE(s,v) ;
+ /* symbols may be external */
+#define S_IS_EXTERNAL(s) (0)
+#define S_SET_EXTERNAL(s) ;
+
+ /* symbols may or may not be defined */
+#define S_IS_DEFINED(s) (0)
+
+
+#define OBJ_EMIT_LINENO(a,b,c) /* must be *something*. This no-op's it out. */
+
+/*
+ * Local Variables:
+ * comment-column: 0
+ * fill-column: 131
+ * End:
+ */
+
+/* end of obj-generic.h */
diff --git a/gnu/usr.bin/as/config/obj-ieee.c b/gnu/usr.bin/as/config/obj-ieee.c
new file mode 100644
index 0000000..c190999
--- /dev/null
+++ b/gnu/usr.bin/as/config/obj-ieee.c
@@ -0,0 +1,539 @@
+/* obj-format for ieee-695 records.
+ Copyright (C) 1991, 1992 Free Software Foundation, Inc.
+
+ This file is part of GAS, the GNU Assembler.
+
+ GAS is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GAS is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GAS; see the file COPYING. If not, write to
+ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+
+/*
+ created by
+
+ steve chamberlain steve@cygnus.com
+ */
+
+/*
+ this will hopefully become the port through which bfd and gas talk,
+ for the moment, only ieee is known to work well.
+ */
+
+#include "bfd.h"
+#include "as.h"
+#include "subsegs.h"
+#include "output-file.h"
+#include "frags.h"
+
+bfd *abfd;
+
+/* How many addresses does the .align take? */
+static relax_addressT relax_align(address, alignment)
+register relax_addressT address; /* Address now. */
+register long alignment; /* Alignment (binary). */
+{
+ relax_addressT mask;
+ relax_addressT new_address;
+
+ mask = ~ ( (~0) << alignment );
+ new_address = (address + mask) & (~ mask);
+ return (new_address - address);
+} /* relax_align() */
+
+/* calculate the size of the frag chain and create a bfd section
+ to contain all of it */
+static void DEFUN(size_section,(abfd, idx),
+ bfd *abfd AND
+ unsigned int idx)
+{
+ asection *sec;
+ unsigned int size = 0;
+ fragS *frag = segment_info[idx].frag_root;
+ while (frag) {
+ if (frag->fr_address != size) {
+ printf("Out of step\n");
+ size = frag->fr_address;
+ }
+ size += frag->fr_fix;
+ switch (frag->fr_type) {
+ case rs_fill:
+ case rs_org:
+ size += frag->fr_offset * frag->fr_var;
+ break;
+ case rs_align:
+ size += relax_align(size, frag->fr_offset);
+ }
+ frag = frag->fr_next;
+ }
+ if (size) {
+ char *name = segment_info[idx].name;
+ if (name == (char *)NULL) {
+ name = ".data";
+ }
+ segment_info[idx].user_stuff = (char *)(sec = bfd_make_section(abfd, name));
+ /* Make it output through itself */
+ sec->output_section = sec;
+ sec->flags |= SEC_HAS_CONTENTS;
+ bfd_set_section_size(abfd, sec, size);
+ }
+}
+
+/* run through a frag chain and write out the data to go with it */
+static void DEFUN(fill_section,(abfd, idx),
+ bfd *abfd AND
+ unsigned int idx)
+{
+ asection *sec = segment_info[idx].user_stuff;
+ if (sec) {
+ fragS *frag = segment_info[idx].frag_root;
+ unsigned int offset = 0;
+ while (frag) {
+ unsigned int fill_size;
+ unsigned int count;
+ switch (frag->fr_type) {
+ case rs_fill:
+ case rs_align:
+ case rs_org:
+ if (frag->fr_fix)
+ {
+ bfd_set_section_contents(abfd,
+ sec,
+ frag->fr_literal,
+ frag->fr_address,
+ frag->fr_fix);
+ }
+ offset += frag->fr_fix;
+ fill_size = frag->fr_var;
+ if (fill_size)
+ {
+ unsigned int off = frag->fr_fix;
+ for (count = frag->fr_offset; count; count--)
+ {
+ bfd_set_section_contents(abfd, sec,
+ frag->fr_literal +
+ frag->fr_fix,
+ frag->fr_address + off,
+ fill_size);
+ off += fill_size;
+ }
+ }
+ break;
+ default:
+ abort();
+ }
+ frag = frag->fr_next;
+ }
+ }
+}
+
+/* Count the relocations in a chain */
+
+static unsigned int DEFUN(count_entries_in_chain,(idx),
+ unsigned int idx)
+{
+ unsigned int nrelocs;
+ fixS *fixup_ptr;
+
+ /* Count the relocations */
+ fixup_ptr = segment_info[idx].fix_root;
+ nrelocs = 0;
+ while (fixup_ptr != (fixS *)NULL)
+ {
+ fixup_ptr = fixup_ptr->fx_next;
+ nrelocs ++ ;
+ }
+ return nrelocs;
+}
+
+/* output all the relocations for a section */
+void DEFUN(do_relocs_for,(idx),
+ unsigned int idx)
+{
+ unsigned int nrelocs;
+ arelent **reloc_ptr_vector;
+ arelent *reloc_vector;
+ asymbol **ptrs;
+ asection *section = (asection *)(segment_info[idx].user_stuff);
+ unsigned int i;
+ fixS *from;
+ if (section) {
+ nrelocs = count_entries_in_chain(idx);
+
+ reloc_ptr_vector = (arelent**)malloc((nrelocs+1) * sizeof(arelent *));
+ reloc_vector = (arelent*)malloc(nrelocs * sizeof(arelent));
+ ptrs = (asymbol **)malloc(nrelocs * sizeof(asymbol *));
+ from = segment_info[idx].fix_root;
+ for (i = 0; i < nrelocs; i++)
+ {
+ arelent *to = reloc_vector + i;
+ asymbol *s ;
+ reloc_ptr_vector[i] = to;
+ to->howto = (reloc_howto_type *)(from->fx_r_type);
+
+ /* We can't represent complicated things in a reloc yet */
+ /* if (from->fx_addsy == 0 ||
+ from->fx_subsy != 0) abort();
+ */
+ s = &( from->fx_addsy->sy_symbol.sy);
+ to->address = ((char *)( from->fx_frag->fr_address +
+ from->fx_where))
+ - ((char *)(&(from->fx_frag->fr_literal)));
+ to->addend = from->fx_offset ;
+ /* If we know the symbol which we want to relocate to, turn this
+ reloaction into a section relative.
+
+ If this relocation is pcrelative, and we know the
+ destination, we still want to keep the relocation - since
+ the linker might relax some of the bytes, but it stops
+ being pc relative and turns into an absolute relocation.
+
+ */
+ if (s) {
+ if ((s->flags & BSF_UNDEFINED) == 0) {
+ to->section = s->section;
+ to->addend += s->value ;
+ to->sym_ptr_ptr = 0;
+ if (to->howto->pcrel_offset) {
+ /* This is a pcrel relocation, the addend should be adjusted */
+ to->addend -= to->address +1;
+ }
+ }
+ else {
+ to->section = 0;
+ *ptrs = &(from->fx_addsy->sy_symbol.sy);
+ to->sym_ptr_ptr = ptrs;
+
+ if (to->howto->pcrel_offset) {
+ /* This is a pcrel relocation, the addend should be adjusted */
+ to->addend -= to->address -1;
+ }
+ }
+
+ }
+ else {
+ to->section = 0;
+ }
+
+ ptrs++;
+ from = from->fx_next;
+ }
+
+ /* attatch to the section */
+ section->orelocation = reloc_ptr_vector;
+ section->reloc_count = nrelocs;
+ section->flags |= SEC_LOAD;
+ }
+}
+
+/* do the symbols.. */
+static void DEFUN(do_symbols, (abfd),
+ bfd *abfd)
+{
+ extern symbolS *symbol_rootP;
+ symbolS *ptr;
+ asymbol **symbol_ptr_vec;
+ asymbol *symbol_vec;
+ unsigned int count = 0;
+ unsigned int index;
+
+
+ for (ptr = symbol_rootP;
+ ptr != (symbolS *)NULL;
+ ptr = ptr->sy_next)
+ {
+ if (SEG_NORMAL(ptr->sy_symbol.seg))
+ {
+ ptr->sy_symbol.sy.section =
+ (asection *)(segment_info[ptr->sy_symbol.seg].user_stuff);
+ ptr->sy_symbol.sy.value += ptr->sy_frag->fr_address;
+ if (ptr->sy_symbol.sy.flags == 0) {
+ ptr->sy_symbol.sy.flags = BSF_LOCAL ;
+ }
+ }
+ else {
+ switch (ptr->sy_symbol.seg) {
+ case SEG_ABSOLUTE:
+ ptr->sy_symbol.sy.flags |= BSF_ABSOLUTE;
+ ptr->sy_symbol.sy.section = 0;
+ break;
+ case SEG_UNKNOWN:
+ ptr->sy_symbol.sy.flags = BSF_UNDEFINED ;
+ ptr->sy_symbol.sy.section = 0;
+ break;
+ default:
+ abort();
+ }
+ }
+ count++;
+ }
+ symbol_ptr_vec = (asymbol **)malloc((count+1) * sizeof(asymbol *));
+
+ index = 0;
+ for (ptr = symbol_rootP;
+ ptr != (symbolS *)NULL;
+ ptr = ptr->sy_next)
+ {
+ symbol_ptr_vec[index] = &(ptr->sy_symbol.sy);
+ index++;
+ }
+ symbol_ptr_vec[index] =0;
+ abfd->outsymbols = symbol_ptr_vec;
+ abfd->symcount = count;
+}
+
+/* The generic as->bfd converter. Other backends may have special case
+ code */
+
+void DEFUN_VOID(bfd_as_write_hook)
+{
+ int i;
+
+ for (i = SEG_E0; i < SEG_UNKNOWN; i++) {
+ size_section(abfd, i);
+ }
+
+
+ for (i = SEG_E0; i < SEG_UNKNOWN; i++)
+ fill_section(abfd,i);
+
+ do_symbols(abfd);
+
+ for (i = SEG_E0; i < SEG_UNKNOWN; i++)
+ do_relocs_for(i);
+
+}
+
+
+
+S_GET_VALUE(x)
+symbolS *x;
+{
+ return x->sy_symbol.sy.value;
+}
+
+S_SET_SEGMENT(x,y)
+symbolS *x ;
+int y;
+{
+ x->sy_symbol.seg = y;
+}
+
+S_IS_DEFINED(x)
+symbolS *x;
+{
+ if (SEG_NORMAL(x->sy_symbol.seg))
+ {
+ return 1;
+ }
+ switch (x->sy_symbol.seg)
+ {
+ case SEG_UNKNOWN:
+ return 0;
+ default:
+ abort();
+ }
+}
+
+S_IS_EXTERNAL(x) { abort(); }
+S_GET_DESC(x) { abort() ; }
+
+S_GET_SEGMENT(x)
+symbolS *x;
+{ return x->sy_symbol.seg; }
+
+S_SET_EXTERNAL(x)
+symbolS *x;
+{
+ x->sy_symbol.sy.flags |= BSF_GLOBAL | BSF_EXPORT;
+}
+
+S_SET_NAME(x,y)
+symbolS*x;
+char *y; {
+ x->sy_symbol.sy.name = y; }
+
+S_SET_VALUE(s,v)
+symbolS *s;
+long v;
+{
+ s->sy_symbol.sy.value = v;
+}
+
+S_GET_OTHER(x) { abort() ;}
+S_IS_DEBUG(x) { abort(); }
+
+char *segment_name() { abort(); }
+
+void obj_read_begin_hook() { }
+
+static void obj_ieee_section(ignore)
+int ignore;
+{
+ extern char *input_line_pointer;
+ extern char is_end_of_line[];
+ char *p= input_line_pointer;
+ char *s = p;
+ int i;
+ /* Look up the name, if it doesn't exist, make it */
+ while (*p &&* p != ' ' && *p != ',' && !is_end_of_line[*p]) {
+ p++;
+ }
+ for (i = SEG_E0; i < SEG_UNKNOWN; i++) {
+ if (segment_info[i].hadone){
+ if (strncmp(segment_info[i].name, s, p-s) == 0) {
+ goto ok;
+
+ }
+ }
+ else break;
+ }
+ if (i == SEG_UNKNOWN) {
+ as_bad("too many sections");
+ return;
+ }
+
+ segment_info[i].hadone = 1;
+ segment_info[i].name = malloc(p-s + 1);
+ memcpy(segment_info[i].name, s, p-s);
+ segment_info[i].name[p-s] = 0;
+ ok:
+ subseg_new(i,0);
+ while (!is_end_of_line[*p])
+ p++;
+ input_line_pointer = p;
+
+}
+
+
+void cons();
+void s_ignore();
+
+
+/*
+ * stringer()
+ *
+ * We read 0 or more ',' seperated, double-quoted strings.
+ *
+ * Caller should have checked need_pass_2 is FALSE because we don't check it.
+ */
+
+void stringer();
+void s_globl();
+const pseudo_typeS obj_pseudo_table[] =
+{
+ {"section", obj_ieee_section, 0},
+ {"data.b", cons, 1},
+ {"data.w", cons, 2},
+ {"data.l", cons, 4},
+ {"export", s_globl, 0},
+ {"option", s_ignore, 0},
+ {"end", s_ignore, 0},
+ {"import", s_ignore, 0},
+ {"sdata", stringer, 0},
+ 0,
+
+};
+
+
+
+void obj_symbol_new_hook(symbolP)
+symbolS *symbolP;
+{
+ symbolP->sy_symbol.sy.the_bfd = abfd;
+}
+
+
+
+
+
+#if 1
+extern void DEFUN_VOID(write_object_file)
+{
+ int i;
+ struct frchain *frchain_ptr;
+ struct frag *frag_ptr;
+
+ abfd = bfd_openw(out_file_name, "ieee");
+
+ if (abfd == 0) {
+ as_perror ("FATAL: Can't create %s", out_file_name);
+ exit(42);
+ }
+ bfd_set_format(abfd, bfd_object);
+ bfd_set_arch_mach(abfd, bfd_arch_h8300, 0);
+ subseg_new(1,0);
+ subseg_new(2,0);
+ subseg_new(3,0);
+ for (frchain_ptr = frchain_root;
+ frchain_ptr != (struct frchain *)NULL;
+ frchain_ptr = frchain_ptr->frch_next) {
+ /* Run through all the sub-segments and align them up. Also close any
+ open frags. We tack a .fill onto the end of the frag chain so
+ that any .align's size can be worked by looking at the next
+ frag */
+
+ subseg_new(frchain_ptr->frch_seg, frchain_ptr->frch_subseg);
+#define SUB_SEGMENT_ALIGN 2
+ frag_align(SUB_SEGMENT_ALIGN,0);
+ frag_wane(frag_now);
+ frag_now->fr_fix = 0;
+ know( frag_now->fr_next == NULL );
+ }
+
+ /* Now build one big frag chain for each segment, linked through
+ fr_next. */
+ for (i = SEG_E0; i < SEG_UNKNOWN; i++)
+ {
+
+ fragS ** prev_frag_ptr_ptr ;
+ struct frchain *next_frchain_ptr;
+
+ /* struct frag **head_ptr = segment_info[i].frag_root;*/
+
+ segment_info[i].frag_root = segment_info[i].frchainP->frch_root;
+#if 0
+ /* Im not sure what this is for */
+ for (frchain_ptr = segment_info[i].frchainP->frch_root;
+ frchain_ptr != (struct frchain *)NULL;
+ frchain_ptr = frchain_ptr->frch_next)
+ {
+ *head_ptr = frchain_ptr;
+ head_ptr = &frchain_ptr->next;
+ }
+
+
+#endif
+ }
+
+ for (i = SEG_E0; i < SEG_UNKNOWN; i++) {
+ relax_segment(segment_info[i].frag_root, i);
+ }
+
+ /* Now the addresses of the frags are correct within the segment */
+
+ bfd_as_write_hook();
+ bfd_close(abfd);
+}
+
+#endif
+
+H_SET_TEXT_SIZE(a,b) { abort(); }
+H_GET_TEXT_SIZE() { abort(); }
+H_SET_BSS_SIZE() { abort(); }
+H_SET_STRING_SIZE() { abort(); }
+H_SET_RELOCATION_SIZE() { abort(); }
+H_SET_MAGIC_NUMBER() { abort(); }
+H_GET_FILE_SIZE() { abort(); }
+H_GET_TEXT_RELOCATION_SIZE() { abort(); }
+
+/* end of obj-ieee.c */
diff --git a/gnu/usr.bin/as/config/obj-ieee.h b/gnu/usr.bin/as/config/obj-ieee.h
new file mode 100644
index 0000000..b2864bc
--- /dev/null
+++ b/gnu/usr.bin/as/config/obj-ieee.h
@@ -0,0 +1,46 @@
+/* This file is obj-ieee.h
+
+ Copyright (C) 1987-1992 Free Software Foundation, Inc.
+
+ This file is part of GAS, the GNU Assembler.
+
+ GAS is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GAS is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GAS; see the file COPYING. If not, write to
+ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#define BFD 1
+
+#include <bfd.h>
+
+typedef struct
+{
+asymbol sy;
+int seg;
+} obj_symbol_type;
+
+#define S_GET_NAME(s) (((s)->sy_symbol.sy.name))
+
+typedef struct {
+int x;
+}
+object_headers;
+
+#define DEFAULT_MAGIC_NUMBER_FOR_OBJECT_FILE 1
+
+
+int lineno_rootP;
+
+
+#define IEEE_STYLE
+
+/* end of obj-ieee.h */
diff --git a/gnu/usr.bin/as/config/obj-vms.c b/gnu/usr.bin/as/config/obj-vms.c
new file mode 100644
index 0000000..2a51ba9
--- /dev/null
+++ b/gnu/usr.bin/as/config/obj-vms.c
@@ -0,0 +1,5484 @@
+/* vms.c -- Write out a VAX/VMS object file
+ Copyright (C) 1987, 1988, 1992 Free Software Foundation, Inc.
+
+This file is part of GAS, the GNU Assembler.
+
+GAS is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GAS is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GAS; see the file COPYING. If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* Written by David L. Kashtan */
+/* Modified by Eric Youngdale to write VMS debug records for program
+ variables */
+#include "as.h"
+#include "subsegs.h"
+#include "obstack.h"
+
+/* What we do if there is a goof. */
+#define error as_fatal
+
+#ifdef HO_VMS /* These are of no use if we are cross assembling. */
+#include <fab.h> /* Define File Access Block */
+#include <nam.h> /* Define NAM Block */
+#include <xab.h> /* Define XAB - all different types*/
+#endif
+/*
+ * Version string of the compiler that produced the code we are
+ * assembling. (And this assembler, if we do not have compiler info.)
+ */
+extern const char version_string[];
+char *compiler_version_string;
+
+/* Flag that determines how we map names. This takes several values, and
+ * is set with the -h switch. A value of zero implies names should be
+ * upper case, and the presence of the -h switch inhibits the case hack.
+ * No -h switch at all sets vms_name_mapping to 0, and allows case hacking.
+ * A value of 2 (set with -h2) implies names should be
+ * all lower case, with no case hack. A value of 3 (set with -h3) implies
+ * that case should be preserved. */
+
+/* If the -+ switch is given, then the hash is appended to any name that is
+ * longer than 31 characters, irregardless of the setting of the -h switch.
+ */
+
+char vms_name_mapping = 0;
+
+
+extern char *strchr ();
+extern char *myname;
+static symbolS *Entry_Point_Symbol = 0; /* Pointer to "_main" */
+
+/*
+ * We augment the "gas" symbol structure with this
+ */
+struct VMS_Symbol
+{
+ struct VMS_Symbol *Next;
+ struct symbol *Symbol;
+ int Size;
+ int Psect_Index;
+ int Psect_Offset;
+};
+struct VMS_Symbol *VMS_Symbols = 0;
+
+/* We need this to keep track of the various input files, so that we can
+ * give the debugger the correct source line.
+ */
+
+struct input_file
+{
+ struct input_file *next;
+ struct input_file *same_file_fpnt;
+ int file_number;
+ int max_line;
+ int min_line;
+ int offset;
+ char flag;
+ char *name;
+ symbolS *spnt;
+};
+
+static struct input_file *file_root = (struct input_file *) NULL;
+
+
+static struct input_file *find_file (symbolS *);
+
+/*
+ * This enum is used to keep track of the various types of variables that
+ * may be present.
+ */
+
+enum advanced_type
+{
+ BASIC, POINTER, ARRAY, ENUM, STRUCT, UNION, FUNCTION, VOID, UNKNOWN
+};
+
+/*
+ * This structure contains the information from the stabs directives, and the
+ * information is filled in by VMS_typedef_parse. Everything that is needed
+ * to generate the debugging record for a given symbol is present here.
+ * This could be done more efficiently, using nested struct/unions, but for now
+ * I am happy that it works.
+ */
+struct VMS_DBG_Symbol
+{
+ struct VMS_DBG_Symbol *next;
+ enum advanced_type advanced; /* description of what this is */
+ int dbx_type; /* this record is for this type */
+ int type2; /* For advanced types this is the type referred to.
+ i.e. the type a pointer points to, or the type
+ of object that makes up an array */
+ int VMS_type; /* Use this type when generating a variable def */
+ int index_min; /* used for arrays - this will be present for all */
+ int index_max; /* entries, but will be meaningless for non-arrays */
+ int data_size; /* size in bytes of the data type. For an array, this
+ is the size of one element in the array */
+ int struc_numb; /* Number of the structure/union/enum - used for ref */
+};
+
+struct VMS_DBG_Symbol *VMS_Symbol_type_list =
+{(struct VMS_DBG_Symbol *) NULL};
+
+/*
+ * We need this structure to keep track of forward references to
+ * struct/union/enum that have not been defined yet. When they are ultimately
+ * defined, then we can go back and generate the TIR commands to make a back
+ * reference.
+ */
+
+struct forward_ref
+{
+ struct forward_ref *next;
+ int dbx_type;
+ int struc_numb;
+ char resolved;
+};
+
+struct forward_ref *f_ref_root =
+{(struct forward_ref *) NULL};
+
+/*
+ * This routine is used to compare the names of certain types to various
+ * fixed types that are known by the debugger.
+ */
+#define type_check(x) !strcmp( symbol_name , x )
+
+/*
+ * This variable is used to keep track of the name of the symbol we are
+ * working on while we are parsing the stabs directives.
+ */
+static char *symbol_name;
+
+/* We use this counter to assign numbers to all of the structures, unions
+ * and enums that we define. When we actually declare a variable to the
+ * debugger, we can simply do it by number, rather than describing the
+ * whole thing each time.
+ */
+
+static structure_count = 0;
+
+/* This variable is used to keep track of the current structure number
+ * for a given variable. If this is < 0, that means that the structure
+ * has not yet been defined to the debugger. This is still cool, since
+ * the VMS object language has ways of fixing things up after the fact,
+ * so we just make a note of this, and generate fixups at the end.
+ */
+static int struct_number;
+
+
+/*
+ * Variable descriptors are used tell the debugger the data types of certain
+ * more complicated variables (basically anything involving a structure,
+ * union, enum, array or pointer). Some non-pointer variables of the
+ * basic types that the debugger knows about do not require a variable
+ * descriptor.
+ *
+ * Since it is impossible to have a variable descriptor longer than 128
+ * bytes by virtue of the way that the VMS object language is set up,
+ * it makes not sense to make the arrays any longer than this, or worrying
+ * about dynamic sizing of the array.
+ *
+ * These are the arrays and counters that we use to build a variable
+ * descriptor.
+ */
+
+#define MAX_DEBUG_RECORD 128
+static char Local[MAX_DEBUG_RECORD]; /* buffer for variable descriptor */
+static char Asuffix[MAX_DEBUG_RECORD]; /* buffer for array descriptor */
+static int Lpnt; /* index into Local */
+static int Apoint; /* index into Asuffix */
+static char overflow; /* flag to indicate we have written too much*/
+static int total_len; /* used to calculate the total length of variable
+ descriptor plus array descriptor - used for len byte*/
+
+/* Flag if we have told user about finding global constants in the text
+ section. */
+static gave_compiler_message = 0;
+
+/* A pointer to the current routine that we are working on. */
+
+static symbolS *Current_Routine;
+
+/* The psect number for $code a.k.a. the text section. */
+
+static int Text_Psect;
+
+
+/*
+ * Global data (Object records limited to 512 bytes by VAX-11 "C" runtime)
+ */
+static int VMS_Object_File_FD; /* File Descriptor for object file */
+static char Object_Record_Buffer[512]; /* Buffer for object file records */
+static int Object_Record_Offset;/* Offset to end of data */
+static int Current_Object_Record_Type; /* Type of record in above */
+
+/*
+ * Macros for placing data into the object record buffer
+ */
+
+#define PUT_LONG(val) \
+{ md_number_to_chars(Object_Record_Buffer + \
+ Object_Record_Offset, val, 4); \
+ Object_Record_Offset += 4; }
+
+#define PUT_SHORT(val) \
+{ md_number_to_chars(Object_Record_Buffer + \
+ Object_Record_Offset, val, 2); \
+ Object_Record_Offset += 2; }
+
+#define PUT_CHAR(val) Object_Record_Buffer[Object_Record_Offset++] = val
+
+#define PUT_COUNTED_STRING(cp) {\
+ register char *p = cp; \
+ PUT_CHAR(strlen(p)); \
+ while (*p) PUT_CHAR(*p++);}
+
+/*
+ * Macro for determining if a Name has psect attributes attached
+ * to it.
+ */
+#define PSECT_ATTRIBUTES_STRING "$$PsectAttributes_"
+#define PSECT_ATTRIBUTES_STRING_LENGTH 18
+
+#define HAS_PSECT_ATTRIBUTES(Name) \
+ (strncmp((Name[0] == '_' ? Name + 1 : Name), \
+ PSECT_ATTRIBUTES_STRING, \
+ PSECT_ATTRIBUTES_STRING_LENGTH) == 0)
+
+
+ /* in: segT out: N_TYPE bits */
+const short seg_N_TYPE[] =
+{
+ N_ABS,
+ N_TEXT,
+ N_DATA,
+ N_BSS,
+ N_UNDF, /* unknown */
+ N_UNDF, /* absent */
+ N_UNDF, /* pass1 */
+ N_UNDF, /* error */
+ N_UNDF, /* bignum/flonum */
+ N_UNDF, /* difference */
+ N_UNDF, /* debug */
+ N_UNDF, /* ntv */
+ N_UNDF, /* ptv */
+ N_REGISTER, /* register */
+};
+
+const segT N_TYPE_seg[N_TYPE + 2] =
+{ /* N_TYPE == 0x1E = 32-2 */
+ SEG_UNKNOWN, /* N_UNDF == 0 */
+ SEG_GOOF,
+ SEG_ABSOLUTE, /* N_ABS == 2 */
+ SEG_GOOF,
+ SEG_TEXT, /* N_TEXT == 4 */
+ SEG_GOOF,
+ SEG_DATA, /* N_DATA == 6 */
+ SEG_GOOF,
+ SEG_BSS, /* N_BSS == 8 */
+ SEG_GOOF,
+ SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF,
+ SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF,
+ SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF,
+ SEG_REGISTER, /* dummy N_REGISTER for regs = 30 */
+ SEG_GOOF,
+};
+
+
+/* The following code defines the special types of pseudo-ops that we
+ * use with VMS.
+ */
+
+char const_flag = 0;
+
+void
+s_const ()
+{
+ register int temp;
+
+ temp = get_absolute_expression ();
+ subseg_new (SEG_DATA, (subsegT) temp);
+ const_flag = 1;
+ demand_empty_rest_of_line ();
+}
+
+/*
+ * stab()
+ *
+ * Handle .stabX directives, which used to be open-coded.
+ * So much creeping featurism overloaded the semantics that we decided
+ * to put all .stabX thinking in one place. Here.
+ *
+ * We try to make any .stabX directive legal. Other people's AS will often
+ * do assembly-time consistency checks: eg assigning meaning to n_type bits
+ * and "protecting" you from setting them to certain values. (They also zero
+ * certain bits before emitting symbols. Tut tut.)
+ *
+ * If an expression is not absolute we either gripe or use the relocation
+ * information. Other people's assemblers silently forget information they
+ * don't need and invent information they need that you didn't supply.
+ *
+ * .stabX directives always make a symbol table entry. It may be junk if
+ * the rest of your .stabX directive is malformed.
+ */
+static void
+obj_aout_stab (what)
+ int what;
+{
+ register symbolS *symbolP = 0;
+ register char *string;
+ int saved_type = 0;
+ int length;
+ int goof; /* TRUE if we have aborted. */
+ long longint;
+
+/*
+ * Enter with input_line_pointer pointing past .stabX and any following
+ * whitespace.
+ */
+ goof = 0; /* JF who forgot this?? */
+ if (what == 's')
+ {
+ string = demand_copy_C_string (&length);
+ SKIP_WHITESPACE ();
+ if (*input_line_pointer == ',')
+ input_line_pointer++;
+ else
+ {
+ as_bad ("I need a comma after symbol's name");
+ goof = 1;
+ }
+ }
+ else
+ string = "";
+
+/*
+ * Input_line_pointer->after ','. String->symbol name.
+ */
+ if (!goof)
+ {
+ symbolP = symbol_new (string,
+ SEG_UNKNOWN,
+ 0,
+ (struct frag *) 0);
+ switch (what)
+ {
+ case 'd':
+ S_SET_NAME (symbolP, NULL); /* .stabd feature. */
+ S_SET_VALUE (symbolP, obstack_next_free (&frags) - frag_now->fr_literal);
+ symbolP->sy_frag = frag_now;
+ break;
+
+ case 'n':
+ symbolP->sy_frag = &zero_address_frag;
+ break;
+
+ case 's':
+ symbolP->sy_frag = &zero_address_frag;
+ break;
+
+ default:
+ BAD_CASE (what);
+ break;
+ }
+
+ if (get_absolute_expression_and_terminator (&longint) == ',')
+ symbolP->sy_symbol.n_type = saved_type = longint;
+ else
+ {
+ as_bad ("I want a comma after the n_type expression");
+ goof = 1;
+ input_line_pointer--; /* Backup over a non-',' char. */
+ }
+ }
+
+ if (!goof)
+ {
+ if (get_absolute_expression_and_terminator (&longint) == ',')
+ S_SET_OTHER (symbolP, longint);
+ else
+ {
+ as_bad ("I want a comma after the n_other expression");
+ goof = 1;
+ input_line_pointer--; /* Backup over a non-',' char. */
+ }
+ }
+
+ if (!goof)
+ {
+ S_SET_DESC (symbolP, get_absolute_expression ());
+ if (what == 's' || what == 'n')
+ {
+ if (*input_line_pointer != ',')
+ {
+ as_bad ("I want a comma after the n_desc expression");
+ goof = 1;
+ }
+ else
+ {
+ input_line_pointer++;
+ }
+ }
+ }
+
+ if ((!goof) && (what == 's' || what == 'n'))
+ {
+ pseudo_set (symbolP);
+ symbolP->sy_symbol.n_type = saved_type;
+ }
+
+ if (goof)
+ ignore_rest_of_line ();
+ else
+ demand_empty_rest_of_line ();
+} /* obj_aout_stab() */
+
+const pseudo_typeS obj_pseudo_table[] =
+{
+ {"stabd", obj_aout_stab, 'd'},/* stabs */
+ {"stabn", obj_aout_stab, 'n'},/* stabs */
+ {"stabs", obj_aout_stab, 's'},/* stabs */
+ {"const", s_const, 0},
+ {0, 0, 0},
+
+}; /* obj_pseudo_table */
+
+void
+obj_read_begin_hook ()
+{
+ return;
+} /* obj_read_begin_hook() */
+
+void
+obj_crawl_symbol_chain (headers)
+ object_headers *headers;
+{
+ symbolS *symbolP;
+ symbolS **symbolPP;
+ int symbol_number = 0;
+
+ /* JF deal with forward references first... */
+ for (symbolP = symbol_rootP; symbolP; symbolP = symbol_next (symbolP))
+ {
+ if (symbolP->sy_forward)
+ {
+ S_SET_VALUE (symbolP, S_GET_VALUE (symbolP)
+ + S_GET_VALUE (symbolP->sy_forward)
+ + symbolP->sy_forward->sy_frag->fr_address);
+ symbolP->sy_forward = 0;
+ } /* if it has a forward reference */
+ } /* walk the symbol chain */
+
+ { /* crawl symbol table */
+ register int symbol_number = 0;
+
+ {
+ symbolPP = &symbol_rootP; /* -> last symbol chain link. */
+ while ((symbolP = *symbolPP) != NULL)
+ {
+ S_GET_VALUE (symbolP) += symbolP->sy_frag->fr_address;
+
+ /* OK, here is how we decide which symbols go out into the
+ brave new symtab. Symbols that do are:
+
+ * symbols with no name (stabd's?)
+ * symbols with debug info in their N_TYPE
+
+ Symbols that don't are:
+ * symbols that are registers
+ * symbols with \1 as their 3rd character (numeric labels)
+ * "local labels" as defined by S_LOCAL_NAME(name)
+ if the -L switch was passed to gas.
+
+ All other symbols are output. We complain if a deleted
+ symbol was marked external. */
+
+
+ if (!S_IS_REGISTER (symbolP))
+ {
+ symbolP->sy_name_offset = 0;
+ symbolPP = &(symbol_next (symbolP));
+ }
+ else
+ {
+ if (S_IS_EXTERNAL (symbolP) || !S_IS_DEFINED (symbolP))
+ {
+ as_bad ("Local symbol %s never defined", S_GET_NAME (symbolP));
+ } /* oops. */
+
+ } /* if this symbol should be in the output */
+ } /* for each symbol */
+ }
+ H_SET_STRING_SIZE (headers, string_byte_count);
+ H_SET_SYMBOL_TABLE_SIZE (headers, symbol_number);
+ } /* crawl symbol table */
+
+} /* obj_crawl_symbol_chain() */
+
+
+ /****** VMS OBJECT FILE HACKING ROUTINES *******/
+
+
+/*
+ * Create the VMS object file
+ */
+static
+Create_VMS_Object_File ()
+{
+#if defined(eunice) || !defined(HO_VMS)
+ VMS_Object_File_FD = creat (out_file_name, 0777, "var");
+#else /* eunice */
+ VMS_Object_File_FD = creat (out_file_name, 0, "rfm=var",
+ "mbc=16", "deq=64", "fop=tef", "shr=nil");
+#endif /* eunice */
+ /*
+ * Deal with errors
+ */
+ if (VMS_Object_File_FD < 0)
+ {
+ char Error_Line[256];
+
+ sprintf (Error_Line, "Couldn't create VMS object file \"%s\"",
+ out_file_name);
+ error (Error_Line);
+ }
+ /*
+ * Initialize object file hacking variables
+ */
+ Object_Record_Offset = 0;
+ Current_Object_Record_Type = -1;
+}
+
+
+/*
+ * Flush the object record buffer to the object file
+ */
+static
+Flush_VMS_Object_Record_Buffer ()
+{
+ int i;
+ short int zero;
+ /*
+ * If the buffer is empty, we are done
+ */
+ if (Object_Record_Offset == 0)
+ return;
+ /*
+ * Write the data to the file
+ */
+#ifndef HO_VMS /* For cross-assembly purposes. */
+ i = write (VMS_Object_File_FD, &Object_Record_Offset, 2);
+#endif /* not HO_VMS */
+ i = write (VMS_Object_File_FD,
+ Object_Record_Buffer,
+ Object_Record_Offset);
+ if (i != Object_Record_Offset)
+ error ("I/O error writing VMS object file");
+#ifndef HO_VMS /* When cross-assembling, we need to pad the record to an even
+ number of bytes. */
+ /* pad it if needed */
+ zero = 0;
+ if (Object_Record_Offset & 1 != 0)
+ write (VMS_Object_File_FD, &zero, 1);
+#endif /* not HO_VMS */
+ /*
+ * The buffer is now empty
+ */
+ Object_Record_Offset = 0;
+}
+
+
+/*
+ * Declare a particular type of object file record
+ */
+static
+Set_VMS_Object_File_Record (Type)
+ int Type;
+{
+ /*
+ * If the type matches, we are done
+ */
+ if (Type == Current_Object_Record_Type)
+ return;
+ /*
+ * Otherwise: flush the buffer
+ */
+ Flush_VMS_Object_Record_Buffer ();
+ /*
+ * Set the new type
+ */
+ Current_Object_Record_Type = Type;
+}
+
+
+
+/*
+ * Close the VMS Object file
+ */
+static
+Close_VMS_Object_File ()
+{
+ short int m_one = -1;
+#ifndef HO_VMS /* For cross-assembly purposes. */
+/* Write a 0xffff into the file, which means "End of File" */
+ write (VMS_Object_File_FD, &m_one, 2);
+#endif /* not HO_VMS */
+ close (VMS_Object_File_FD);
+}
+
+
+/*
+ * Store immediate data in current Psect
+ */
+static
+VMS_Store_Immediate_Data (Pointer, Size, Record_Type)
+ register char *Pointer;
+ int Size;
+ int Record_Type;
+{
+ register int i;
+
+ /*
+ * We are writing a "Record_Type" record
+ */
+ Set_VMS_Object_File_Record (Record_Type);
+ /*
+ * We can only store 128 bytes at a time
+ */
+ while (Size > 0)
+ {
+ /*
+ * Store a maximum of 128 bytes
+ */
+ i = (Size > 128) ? 128 : Size;
+ Size -= i;
+ /*
+ * If we cannot accommodate this record, flush the
+ * buffer.
+ */
+ if ((Object_Record_Offset + i + 1) >=
+ sizeof (Object_Record_Buffer))
+ Flush_VMS_Object_Record_Buffer ();
+ /*
+ * If the buffer is empty we must insert record type
+ */
+ if (Object_Record_Offset == 0)
+ PUT_CHAR (Record_Type);
+ /*
+ * Store the count
+ */
+ PUT_CHAR (-i & 0xff);
+ /*
+ * Store the data
+ */
+ while (--i >= 0)
+ PUT_CHAR (*Pointer++);
+ /*
+ * Flush the buffer if it is more than 75% full
+ */
+ if (Object_Record_Offset >
+ (sizeof (Object_Record_Buffer) * 3 / 4))
+ Flush_VMS_Object_Record_Buffer ();
+ }
+}
+
+/*
+ * Make a data reference
+ */
+static
+VMS_Set_Data (Psect_Index, Offset, Record_Type, Force)
+ int Psect_Index;
+ int Offset;
+ int Record_Type;
+ int Force;
+{
+ /*
+ * We are writing a "Record_Type" record
+ */
+ Set_VMS_Object_File_Record (Record_Type);
+ /*
+ * If the buffer is empty we must insert the record type
+ */
+ if (Object_Record_Offset == 0)
+ PUT_CHAR (Record_Type);
+ /*
+ * Stack the Psect base + Longword Offset
+ */
+ if (Force == 1)
+ {
+ if (Psect_Index > 127)
+ {
+ PUT_CHAR (TIR_S_C_STA_WPL);
+ PUT_SHORT (Psect_Index);
+ PUT_LONG (Offset);
+ }
+ else
+ {
+ PUT_CHAR (TIR_S_C_STA_PL);
+ PUT_CHAR (Psect_Index);
+ PUT_LONG (Offset);
+ }
+ }
+ else
+ {
+ if (Offset > 32767)
+ {
+ PUT_CHAR (TIR_S_C_STA_WPL);
+ PUT_SHORT (Psect_Index);
+ PUT_LONG (Offset);
+ }
+ else if (Offset > 127)
+ {
+ PUT_CHAR (TIR_S_C_STA_WPW);
+ PUT_SHORT (Psect_Index);
+ PUT_SHORT (Offset);
+ }
+ else
+ {
+ PUT_CHAR (TIR_S_C_STA_WPB);
+ PUT_SHORT (Psect_Index);
+ PUT_CHAR (Offset);
+ };
+ };
+ /*
+ * Set relocation base
+ */
+ PUT_CHAR (TIR_S_C_STO_PIDR);
+ /*
+ * Flush the buffer if it is more than 75% full
+ */
+ if (Object_Record_Offset >
+ (sizeof (Object_Record_Buffer) * 3 / 4))
+ Flush_VMS_Object_Record_Buffer ();
+}
+
+/*
+ * Make a debugger reference to a struct, union or enum.
+ */
+static
+VMS_Store_Struct (int Struct_Index)
+{
+ /*
+ * We are writing a "OBJ_S_C_DBG" record
+ */
+ Set_VMS_Object_File_Record (OBJ_S_C_DBG);
+ /*
+ * If the buffer is empty we must insert the record type
+ */
+ if (Object_Record_Offset == 0)
+ PUT_CHAR (OBJ_S_C_DBG);
+ PUT_CHAR (TIR_S_C_STA_UW);
+ PUT_SHORT (Struct_Index);
+ PUT_CHAR (TIR_S_C_CTL_STKDL);
+ PUT_CHAR (TIR_S_C_STO_L);
+ /*
+ * Flush the buffer if it is more than 75% full
+ */
+ if (Object_Record_Offset >
+ (sizeof (Object_Record_Buffer) * 3 / 4))
+ Flush_VMS_Object_Record_Buffer ();
+}
+
+/*
+ * Make a debugger reference to partially define a struct, union or enum.
+ */
+static
+VMS_Def_Struct (int Struct_Index)
+{
+ /*
+ * We are writing a "OBJ_S_C_DBG" record
+ */
+ Set_VMS_Object_File_Record (OBJ_S_C_DBG);
+ /*
+ * If the buffer is empty we must insert the record type
+ */
+ if (Object_Record_Offset == 0)
+ PUT_CHAR (OBJ_S_C_DBG);
+ PUT_CHAR (TIR_S_C_STA_UW);
+ PUT_SHORT (Struct_Index);
+ PUT_CHAR (TIR_S_C_CTL_DFLOC);
+ /*
+ * Flush the buffer if it is more than 75% full
+ */
+ if (Object_Record_Offset >
+ (sizeof (Object_Record_Buffer) * 3 / 4))
+ Flush_VMS_Object_Record_Buffer ();
+}
+
+static
+VMS_Set_Struct (int Struct_Index)
+{ /* see previous functions for comments */
+ Set_VMS_Object_File_Record (OBJ_S_C_DBG);
+ if (Object_Record_Offset == 0)
+ PUT_CHAR (OBJ_S_C_DBG);
+ PUT_CHAR (TIR_S_C_STA_UW);
+ PUT_SHORT (Struct_Index);
+ PUT_CHAR (TIR_S_C_CTL_STLOC);
+ if (Object_Record_Offset >
+ (sizeof (Object_Record_Buffer) * 3 / 4))
+ Flush_VMS_Object_Record_Buffer ();
+}
+
+/*
+ * Write the Traceback Module Begin record
+ */
+static
+VMS_TBT_Module_Begin ()
+{
+ register char *cp, *cp1;
+ int Size;
+ char Module_Name[256];
+ char Local[256];
+
+ /*
+ * Get module name (the FILENAME part of the object file)
+ */
+ cp = out_file_name;
+ cp1 = Module_Name;
+ while (*cp)
+ {
+ if ((*cp == ']') || (*cp == '>') ||
+ (*cp == ':') || (*cp == '/'))
+ {
+ cp1 = Module_Name;
+ cp++;
+ continue;
+ }
+ *cp1++ = islower (*cp) ? toupper (*cp++) : *cp++;
+ }
+ *cp1 = 0;
+ /*
+ * Limit it to 31 characters
+ */
+ while (--cp1 >= Module_Name)
+ if (*cp1 == '.')
+ *cp1 = 0;
+ if (strlen (Module_Name) > 31)
+ {
+ if (flagseen['+'])
+ printf ("%s: Module name truncated: %s\n", myname, Module_Name);
+ Module_Name[31] = 0;
+ }
+ /*
+ * Arrange to store the data locally (leave room for size byte)
+ */
+ cp = Local + 1;
+ /*
+ * Begin module
+ */
+ *cp++ = DST_S_C_MODBEG;
+ /*
+ * Unused
+ */
+ *cp++ = 0;
+ /*
+ * Language type == "C"
+ */
+ *(long *) cp = DST_S_C_C;
+ cp += sizeof (long);
+ /*
+ * Store the module name
+ */
+ *cp++ = strlen (Module_Name);
+ cp1 = Module_Name;
+ while (*cp1)
+ *cp++ = *cp1++;
+ /*
+ * Now we can store the record size
+ */
+ Size = (cp - Local);
+ Local[0] = Size - 1;
+ /*
+ * Put it into the object record
+ */
+ VMS_Store_Immediate_Data (Local, Size, OBJ_S_C_TBT);
+}
+
+
+/*
+ * Write the Traceback Module End record
+*/
+static
+VMS_TBT_Module_End ()
+{
+ char Local[2];
+
+ /*
+ * End module
+ */
+ Local[0] = 1;
+ Local[1] = DST_S_C_MODEND;
+ /*
+ * Put it into the object record
+ */
+ VMS_Store_Immediate_Data (Local, 2, OBJ_S_C_TBT);
+}
+
+
+/*
+ * Write the Traceback Routine Begin record
+ */
+static
+VMS_TBT_Routine_Begin (symbolP, Psect)
+ struct symbol *symbolP;
+ int Psect;
+{
+ register char *cp, *cp1;
+ char *Name;
+ int Offset;
+ int Size;
+ char Local[512];
+
+ /*
+ * Strip the leading "_" from the name
+ */
+ Name = S_GET_NAME (symbolP);
+ if (*Name == '_')
+ Name++;
+ /*
+ * Get the text psect offset
+ */
+ Offset = S_GET_VALUE (symbolP);
+ /*
+ * Calculate the record size
+ */
+ Size = 1 + 1 + 4 + 1 + strlen (Name);
+ /*
+ * Record Size
+ */
+ Local[0] = Size;
+ /*
+ * Begin Routine
+ */
+ Local[1] = DST_S_C_RTNBEG;
+ /*
+ * Uses CallS/CallG
+ */
+ Local[2] = 0;
+ /*
+ * Store the data so far
+ */
+ VMS_Store_Immediate_Data (Local, 3, OBJ_S_C_TBT);
+ /*
+ * Make sure we are still generating a OBJ_S_C_TBT record
+ */
+ if (Object_Record_Offset == 0)
+ PUT_CHAR (OBJ_S_C_TBT);
+ /*
+ * Now get the symbol address
+ */
+ PUT_CHAR (TIR_S_C_STA_WPL);
+ PUT_SHORT (Psect);
+ PUT_LONG (Offset);
+ /*
+ * Store the data reference
+ */
+ PUT_CHAR (TIR_S_C_STO_PIDR);
+ /*
+ * Store the counted string as data
+ */
+ cp = Local;
+ cp1 = Name;
+ Size = strlen (cp1) + 1;
+ *cp++ = Size - 1;
+ while (*cp1)
+ *cp++ = *cp1++;
+ VMS_Store_Immediate_Data (Local, Size, OBJ_S_C_TBT);
+}
+
+
+/*
+ * Write the Traceback Routine End record
+ * We *must* search the symbol table to find the next routine, since
+ * the assember has a way of reassembling the symbol table OUT OF ORDER
+ * Thus the next routine in the symbol list is not necessarily the
+ * next one in memory. For debugging to work correctly we must know the
+ * size of the routine.
+ */
+static
+VMS_TBT_Routine_End (Max_Size, sp)
+ int Max_Size;
+ symbolS *sp;
+{
+ symbolS *symbolP;
+ int Size = 0x7fffffff;
+ char Local[16];
+
+
+ for (symbolP = symbol_rootP; symbolP; symbolP = symbol_next (symbolP))
+ {
+ if (!S_IS_DEBUG (symbolP) && S_GET_TYPE (symbolP) == N_TEXT)
+ {
+ if (*S_GET_NAME (symbolP) == 'L')
+ continue;
+ if ((S_GET_VALUE (symbolP) > S_GET_VALUE (sp)) &&
+ (S_GET_VALUE (symbolP) < Size))
+ Size = S_GET_VALUE (symbolP);
+ /* check if gcc_compiled. has size of zero */
+ if ((S_GET_VALUE (symbolP) == S_GET_VALUE (sp)) &&
+ sp != symbolP &&
+ (!strcmp (S_GET_NAME (sp), "gcc_compiled.") ||
+ !strcmp (S_GET_NAME (sp), "gcc2_compiled.")))
+ Size = S_GET_VALUE (symbolP);
+
+ };
+ };
+ if (Size == 0x7fffffff)
+ Size = Max_Size;
+ Size -= S_GET_VALUE (sp); /* and get the size of the routine */
+ /*
+ * Record Size
+ */
+ Local[0] = 6;
+ /*
+ * End of Routine
+ */
+ Local[1] = DST_S_C_RTNEND;
+ /*
+ * Unused
+ */
+ Local[2] = 0;
+ /*
+ * Size of routine
+ */
+ *((long *) (Local + 3)) = Size;
+ /*
+ * Store the record
+ */
+ VMS_Store_Immediate_Data (Local, 7, OBJ_S_C_TBT);
+}
+
+/*
+ * Write the Traceback Block End record
+ */
+static
+VMS_TBT_Block_Begin (symbolP, Psect, Name)
+ struct symbol *symbolP;
+ int Psect;
+ char *Name;
+{
+ register char *cp, *cp1;
+ int Offset;
+ int Size;
+ char Local[512];
+ /*
+ * Begin block
+ */
+ Size = 1 + 1 + 4 + 1 + strlen (Name);
+ /*
+ * Record Size
+ */
+ Local[0] = Size;
+ /*
+ * Begin Block - We simulate with a phony routine
+ */
+ Local[1] = DST_S_C_BLKBEG;
+ /*
+ * Uses CallS/CallG
+ */
+ Local[2] = 0;
+ /*
+ * Store the data so far
+ */
+ VMS_Store_Immediate_Data (Local, 3, OBJ_S_C_DBG);
+ /*
+ * Make sure we are still generating a OBJ_S_C_DBG record
+ */
+ if (Object_Record_Offset == 0)
+ PUT_CHAR (OBJ_S_C_DBG);
+ /*
+ * Now get the symbol address
+ */
+ PUT_CHAR (TIR_S_C_STA_WPL);
+ PUT_SHORT (Psect);
+ /*
+ * Get the text psect offset
+ */
+ Offset = S_GET_VALUE (symbolP);
+ PUT_LONG (Offset);
+ /*
+ * Store the data reference
+ */
+ PUT_CHAR (TIR_S_C_STO_PIDR);
+ /*
+ * Store the counted string as data
+ */
+ cp = Local;
+ cp1 = Name;
+ Size = strlen (cp1) + 1;
+ *cp++ = Size - 1;
+ while (*cp1)
+ *cp++ = *cp1++;
+ VMS_Store_Immediate_Data (Local, Size, OBJ_S_C_DBG);
+}
+
+
+/*
+ * Write the Traceback Block End record
+ */
+static
+VMS_TBT_Block_End (int Size)
+{
+ char Local[16];
+
+ /*
+ * End block - simulate with a phony end routine
+ */
+ Local[0] = 6;
+ Local[1] = DST_S_C_BLKEND;
+ *((long *) (Local + 3)) = Size;
+ /*
+ * Unused
+ */
+ Local[2] = 0;
+ VMS_Store_Immediate_Data (Local, 7, OBJ_S_C_DBG);
+}
+
+
+
+/*
+ * Write a Line number / PC correlation record
+ */
+static
+VMS_TBT_Line_PC_Correlation (Line_Number, Offset, Psect, Do_Delta)
+ int Line_Number;
+ int Offset;
+ int Psect;
+ int Do_Delta;
+{
+ register char *cp;
+ char Local[64];
+
+ /*
+* If not delta, set our PC/Line number correlation
+*/
+ if (Do_Delta == 0)
+ {
+ /*
+ * Size
+ */
+ Local[0] = 1 + 1 + 2 + 1 + 4;
+ /*
+ * Line Number/PC correlation
+ */
+ Local[1] = DST_S_C_LINE_NUM;
+ /*
+ * Set Line number
+ */
+ Local[2] = DST_S_C_SET_LINE_NUM;
+ *((unsigned short *) (Local + 3)) = Line_Number - 1;
+ /*
+ * Set PC
+ */
+ Local[5] = DST_S_C_SET_ABS_PC;
+ VMS_Store_Immediate_Data (Local, 6, OBJ_S_C_TBT);
+ /*
+ * Make sure we are still generating a OBJ_S_C_TBT record
+ */
+ if (Object_Record_Offset == 0)
+ PUT_CHAR (OBJ_S_C_TBT);
+ if (Psect < 255)
+ {
+ PUT_CHAR (TIR_S_C_STA_PL);
+ PUT_CHAR (Psect);
+ }
+ else
+ {
+ PUT_CHAR (TIR_S_C_STA_WPL);
+ PUT_SHORT (Psect);
+ }
+ PUT_LONG (Offset);
+ PUT_CHAR (TIR_S_C_STO_PIDR);
+ /*
+ * Do a PC offset of 0 to register the line number
+ */
+ Local[0] = 2;
+ Local[1] = DST_S_C_LINE_NUM;
+ Local[2] = 0; /* Increment PC by 0 and register line # */
+ VMS_Store_Immediate_Data (Local, 3, OBJ_S_C_TBT);
+ }
+ else
+ {
+ /*
+ * If Delta is negative, terminate the line numbers
+ */
+ if (Do_Delta < 0)
+ {
+ Local[0] = 1 + 1 + 4;
+ Local[1] = DST_S_C_LINE_NUM;
+ Local[2] = DST_S_C_TERM_L;
+ *((long *) (Local + 3)) = Offset;
+ VMS_Store_Immediate_Data (Local, 7, OBJ_S_C_TBT);
+ /*
+ * Done
+ */
+ return;
+ }
+ /*
+ * Do a PC/Line delta
+ */
+ cp = Local + 1;
+ *cp++ = DST_S_C_LINE_NUM;
+ if (Line_Number > 1)
+ {
+ /*
+ * We need to increment the line number
+ */
+ if (Line_Number - 1 <= 255)
+ {
+ *cp++ = DST_S_C_INCR_LINUM;
+ *cp++ = Line_Number - 1;
+ }
+ else
+ {
+ *cp++ = DST_S_C_INCR_LINUM_W;
+ *(short *) cp = Line_Number - 1;
+ cp += sizeof (short);
+ }
+ }
+ /*
+ * Increment the PC
+ */
+ if (Offset <= 128)
+ {
+ *cp++ = -Offset;
+ }
+ else
+ {
+ if (Offset < 0x10000)
+ {
+ *cp++ = DST_S_C_DELTA_PC_W;
+ *(short *) cp = Offset;
+ cp += sizeof (short);
+ }
+ else
+ {
+ *cp++ = DST_S_C_DELTA_PC_L;
+ *(long *) cp = Offset;
+ cp += sizeof (long);
+ }
+ }
+ Local[0] = cp - (Local + 1);
+ VMS_Store_Immediate_Data (Local, cp - Local, OBJ_S_C_TBT);
+ }
+}
+
+
+/*
+ * Describe a source file to the debugger
+ */
+static
+VMS_TBT_Source_File (Filename, ID_Number)
+ char *Filename;
+ int ID_Number;
+{
+ register char *cp, *cp1;
+ int Status, i;
+ char Local[512];
+#ifndef HO_VMS /* Used for cross-assembly */
+ i = strlen (Filename);
+#else /* HO_VMS */
+ static struct FAB Fab;
+ static struct NAM Nam;
+ static struct XABDAT Date_Xab;
+ static struct XABFHC File_Header_Xab;
+ char Es_String[255], Rs_String[255];
+
+ /*
+ * Setup the Fab
+ */
+ Fab.fab$b_bid = FAB$C_BID;
+ Fab.fab$b_bln = sizeof (Fab);
+ Fab.fab$l_nam = (&Nam);
+ Fab.fab$l_xab = (char *) &Date_Xab;
+ /*
+ * Setup the Nam block so we can find out the FULL name
+ * of the source file.
+ */
+ Nam.nam$b_bid = NAM$C_BID;
+ Nam.nam$b_bln = sizeof (Nam);
+ Nam.nam$l_rsa = Rs_String;
+ Nam.nam$b_rss = sizeof (Rs_String);
+ Nam.nam$l_esa = Es_String;
+ Nam.nam$b_ess = sizeof (Es_String);
+ /*
+ * Setup the Date and File Header Xabs
+ */
+ Date_Xab.xab$b_cod = XAB$C_DAT;
+ Date_Xab.xab$b_bln = sizeof (Date_Xab);
+ Date_Xab.xab$l_nxt = (char *) &File_Header_Xab;
+ File_Header_Xab.xab$b_cod = XAB$C_FHC;
+ File_Header_Xab.xab$b_bln = sizeof (File_Header_Xab);
+ /*
+ * Get the file information
+ */
+ Fab.fab$l_fna = Filename;
+ Fab.fab$b_fns = strlen (Filename);
+ Status = sys$open (&Fab);
+ if (!(Status & 1))
+ {
+ printf ("gas: Couldn't find source file \"%s\", Error = %%X%x\n",
+ Filename, Status);
+ return (0);
+ }
+ sys$close (&Fab);
+ /*
+ * Calculate the size of the resultant string
+ */
+ i = Nam.nam$b_rsl;
+#endif /* HO_VMS */
+ /*
+ * Size of record
+ */
+ Local[0] = 1 + 1 + 1 + 1 + 1 + 2 + 8 + 4 + 2 + 1 + 1 + i + 1;
+ /*
+ * Source declaration
+ */
+ Local[1] = DST_S_C_SOURCE;
+ /*
+ * Make formfeeds count as source records
+ */
+ Local[2] = DST_S_C_SRC_FORMFEED;
+ /*
+ * Declare source file
+ */
+ Local[3] = DST_S_C_SRC_DECLFILE;
+ Local[4] = 1 + 2 + 8 + 4 + 2 + 1 + 1 + i + 1;
+ cp = Local + 5;
+ /*
+ * Flags
+ */
+ *cp++ = 0;
+ /*
+ * File ID
+ */
+ *(short *) cp = ID_Number;
+ cp += sizeof (short);
+#ifndef HO_VMS
+ /*
+ * Creation Date. Unknown, so we fill with zeroes.
+ */
+ *(long *) cp = 0;
+ cp += sizeof (long);
+ *(long *) cp = 0;
+ cp += sizeof (long);
+ /*
+ * End of file block
+ */
+ *(long *) cp = 0;
+ cp += sizeof (long);
+ /*
+ * First free byte
+ */
+ *(short *) cp = 0;
+ cp += sizeof (short);
+ /*
+ * Record format
+ */
+ *cp++ = 0;
+ /*
+ * Filename
+ */
+ *cp++ = i;
+ cp1 = Filename;
+#else /* Use this code when assembling for VMS on a VMS system */
+ /*
+ * Creation Date
+ */
+ *(long *) cp = ((long *) &Date_Xab.xab$q_cdt)[0];
+ cp += sizeof (long);
+ *(long *) cp = ((long *) &Date_Xab.xab$q_cdt)[1];
+ cp += sizeof (long);
+ /*
+ * End of file block
+ */
+ *(long *) cp = File_Header_Xab.xab$l_ebk;
+ cp += sizeof (long);
+ /*
+ * First free byte
+ */
+ *(short *) cp = File_Header_Xab.xab$w_ffb;
+ cp += sizeof (short);
+ /*
+ * Record format
+ */
+ *cp++ = File_Header_Xab.xab$b_rfo;
+ /*
+ * Filename
+ */
+ *cp++ = i;
+ cp1 = Rs_String;
+#endif /* HO_VMS */
+ while (--i >= 0)
+ *cp++ = *cp1++;
+ /*
+ * Library module name (none)
+ */
+ *cp++ = 0;
+ /*
+ * Done
+ */
+ VMS_Store_Immediate_Data (Local, cp - Local, OBJ_S_C_TBT);
+ return 1;
+}
+
+
+/*
+ * Give the number of source lines to the debugger
+ */
+static
+VMS_TBT_Source_Lines (ID_Number, Starting_Line_Number, Number_Of_Lines)
+ int ID_Number;
+ int Starting_Line_Number;
+ int Number_Of_Lines;
+{
+ char *cp, *cp1;
+ char Local[16];
+
+ /*
+ * Size of record
+ */
+ Local[0] = 1 + 1 + 2 + 1 + 4 + 1 + 2;
+ /*
+ * Source declaration
+ */
+ Local[1] = DST_S_C_SOURCE;
+ /*
+ * Set Source File
+ */
+ cp = Local + 2;
+ *cp++ = DST_S_C_SRC_SETFILE;
+ /*
+ * File ID Number
+ */
+ *(short *) cp = ID_Number;
+ cp += sizeof (short);
+ /*
+ * Set record number
+ */
+ *cp++ = DST_S_C_SRC_SETREC_L;
+ *(long *) cp = Starting_Line_Number;
+ cp += sizeof (long);
+ /*
+ * Define lines
+ */
+ *cp++ = DST_S_C_SRC_DEFLINES_W;
+ *(short *) cp = Number_Of_Lines;
+ cp += sizeof (short);
+ /*
+ * Done
+ */
+ VMS_Store_Immediate_Data (Local, cp - Local, OBJ_S_C_TBT);
+}
+
+
+
+
+/* This routine locates a file in the list of files. If an entry does not
+ * exist, one is created. For include files, a new entry is always created
+ * such that inline functions can be properly debugged. */
+static struct input_file *
+find_file (sp)
+ symbolS *sp;
+{
+ struct input_file *same_file;
+ struct input_file *fpnt;
+ same_file = (struct input_file *) NULL;
+ for (fpnt = file_root; fpnt; fpnt = fpnt->next)
+ {
+ if (fpnt == (struct input_file *) NULL)
+ break;
+ if (fpnt->spnt == sp)
+ return fpnt;
+ };
+ for (fpnt = file_root; fpnt; fpnt = fpnt->next)
+ {
+ if (fpnt == (struct input_file *) NULL)
+ break;
+ if (strcmp (S_GET_NAME (sp), fpnt->name) == 0)
+ {
+ if (fpnt->flag == 1)
+ return fpnt;
+ same_file = fpnt;
+ break;
+ };
+ };
+ fpnt = (struct input_file *) malloc (sizeof (struct input_file));
+ if (file_root == (struct input_file *) NULL)
+ file_root = fpnt;
+ else
+ {
+ struct input_file *fpnt1;
+ for (fpnt1 = file_root; fpnt1->next; fpnt1 = fpnt1->next) ;
+ fpnt1->next = fpnt;
+ };
+ fpnt->next = (struct input_file *) NULL;
+ fpnt->name = S_GET_NAME (sp);
+ fpnt->min_line = 0x7fffffff;
+ fpnt->max_line = 0;
+ fpnt->offset = 0;
+ fpnt->flag = 0;
+ fpnt->file_number = 0;
+ fpnt->spnt = sp;
+ fpnt->same_file_fpnt = same_file;
+ return fpnt;
+}
+
+/*
+ * The following functions and definitions are used to generate object records
+ * that will describe program variables to the VMS debugger.
+ *
+ * This file contains many of the routines needed to output debugging info into
+ * the object file that the VMS debugger needs to understand symbols. These
+ * routines are called very late in the assembly process, and thus we can be
+ * fairly lax about changing things, since the GSD and the TIR sections have
+ * already been output.
+ */
+
+
+/* This routine converts a number string into an integer, and stops when it
+ * sees an invalid character the return value is the address of the character
+ * just past the last character read. No error is generated.
+ */
+static char *
+cvt_integer (str, rtn)
+ char *str;
+ int *rtn;
+{
+ int ival, neg;
+ neg = *str == '-' ? ++str, -1 : 1;
+ ival = 0; /* first get the number of the type for dbx */
+ while ((*str <= '9') && (*str >= '0'))
+ ival = 10 * ival + *str++ - '0';
+ *rtn = neg * ival;
+ return str;
+}
+
+/* this routine fixes the names that are generated by C++, ".this" is a good
+ * example. The period does not work for the debugger, since it looks like
+ * the syntax for a structure element, and thus it gets mightily confused
+ *
+ * We also use this to strip the PsectAttribute hack from the name before we
+ * write a debugger record */
+
+static char *
+fix_name (pnt)
+ char *pnt;
+{
+ char *pnt1;
+ /*
+ * Kill any leading "_"
+ */
+ if (*pnt == '_')
+ pnt++;
+ /*
+ * Is there a Psect Attribute to skip??
+ */
+ if (HAS_PSECT_ATTRIBUTES (pnt))
+ {
+ /*
+ * Yes: Skip it
+ */
+ pnt += PSECT_ATTRIBUTES_STRING_LENGTH;
+ while (*pnt)
+ {
+ if ((pnt[0] == '$') && (pnt[1] == '$'))
+ {
+ pnt += 2;
+ break;
+ }
+ pnt++;
+ }
+ }
+/* Here we fix the .this -> $this conversion */
+ for (pnt1 = pnt; *pnt1 != 0; pnt1++)
+ {
+ if (*pnt1 == '.')
+ *pnt1 = '$';
+ };
+ return pnt;
+}
+
+/* When defining a structure, this routine is called to find the name of
+ * the actual structure. It is assumed that str points to the equal sign
+ * in the definition, and it moves backward until it finds the start of the
+ * name. If it finds a 0, then it knows that this structure def is in the
+ * outermost level, and thus symbol_name points to the symbol name.
+ */
+static char *
+get_struct_name (str)
+ char *str;
+{
+ char *pnt;
+ pnt = str;
+ while ((*pnt != ':') && (*pnt != '\0'))
+ pnt--;
+ if (*pnt == '\0')
+ return symbol_name;
+ *pnt-- = '\0';
+ while ((*pnt != ';') && (*pnt != '='))
+ pnt--;
+ if (*pnt == ';')
+ return pnt + 1;
+ while ((*pnt < '0') || (*pnt > '9'))
+ pnt++;
+ while ((*pnt >= '0') && (*pnt <= '9'))
+ pnt++;
+ return pnt;
+}
+
+/* search symbol list for type number dbx_type. Return a pointer to struct */
+static struct VMS_DBG_Symbol *
+find_symbol (dbx_type)
+ int dbx_type;
+{
+ struct VMS_DBG_Symbol *spnt;
+ spnt = VMS_Symbol_type_list;
+ while (spnt != (struct VMS_DBG_Symbol *) NULL)
+ {
+ if (spnt->dbx_type == dbx_type)
+ break;
+ spnt = spnt->next;
+ };
+ if (spnt == (struct VMS_DBG_Symbol *) NULL)
+ return 0; /*Dunno what this is*/
+ return spnt;
+}
+
+
+/* this routine puts info into either Local or Asuffix, depending on the sign
+ * of size. The reason is that it is easier to build the variable descriptor
+ * backwards, while the array descriptor is best built forwards. In the end
+ * they get put together, if there is not a struct/union/enum along the way
+ */
+static
+push (value, size)
+ int value, size;
+{
+ char *pnt;
+ int i;
+ int size1;
+ long int val;
+ val = value;
+ pnt = (char *) &val;
+ size1 = size;
+ if (size < 0)
+ {
+ size1 = -size;
+ pnt += size1 - 1;
+ };
+ if (size < 0)
+ for (i = 0; i < size1; i++)
+ {
+ Local[Lpnt--] = *pnt--;
+ if (Lpnt < 0)
+ {
+ overflow = 1;
+ Lpnt = 1;
+ };
+ }
+ else
+ for (i = 0; i < size1; i++)
+ {
+ Asuffix[Apoint++] = *pnt++;
+ if (Apoint >= MAX_DEBUG_RECORD)
+ {
+ overflow = 1;
+ Apoint = MAX_DEBUG_RECORD - 1;
+ };
+ }
+}
+
+/* this routine generates the array descriptor for a given array */
+static
+array_suffix (spnt2)
+ struct VMS_DBG_Symbol *spnt2;
+{
+ struct VMS_DBG_Symbol *spnt;
+ struct VMS_DBG_Symbol *spnt1;
+ int rank;
+ int total_size;
+ int i;
+ rank = 0;
+ spnt = spnt2;
+ while (spnt->advanced != ARRAY)
+ {
+ spnt = find_symbol (spnt->type2);
+ if (spnt == (struct VMS_DBG_Symbol *) NULL)
+ return;
+ };
+ spnt1 = spnt;
+ spnt1 = spnt;
+ total_size = 1;
+ while (spnt1->advanced == ARRAY)
+ {
+ rank++;
+ total_size *= (spnt1->index_max - spnt1->index_min + 1);
+ spnt1 = find_symbol (spnt1->type2);
+ };
+ total_size = total_size * spnt1->data_size;
+ push (spnt1->data_size, 2);
+ if (spnt1->VMS_type == 0xa3)
+ push (0, 1);
+ else
+ push (spnt1->VMS_type, 1);
+ push (4, 1);
+ for (i = 0; i < 6; i++)
+ push (0, 1);
+ push (0xc0, 1);
+ push (rank, 1);
+ push (total_size, 4);
+ push (0, 4);
+ spnt1 = spnt;
+ while (spnt1->advanced == ARRAY)
+ {
+ push (spnt1->index_max - spnt1->index_min + 1, 4);
+ spnt1 = find_symbol (spnt1->type2);
+ };
+ spnt1 = spnt;
+ while (spnt1->advanced == ARRAY)
+ {
+ push (spnt1->index_min, 4);
+ push (spnt1->index_max, 4);
+ spnt1 = find_symbol (spnt1->type2);
+ };
+}
+
+/* this routine generates the start of a variable descriptor based upon
+ * a struct/union/enum that has yet to be defined. We define this spot as
+ * a new location, and save four bytes for the address. When the struct is
+ * finally defined, then we can go back and plug in the correct address
+*/
+static
+new_forward_ref (dbx_type)
+ int dbx_type;
+{
+ struct forward_ref *fpnt;
+ fpnt = (struct forward_ref *) malloc (sizeof (struct forward_ref));
+ fpnt->next = f_ref_root;
+ f_ref_root = fpnt;
+ fpnt->dbx_type = dbx_type;
+ fpnt->struc_numb = ++structure_count;
+ fpnt->resolved = 'N';
+ push (3, -1);
+ total_len = 5;
+ push (total_len, -2);
+ struct_number = -fpnt->struc_numb;
+}
+
+/* this routine generates the variable descriptor used to describe non-basic
+ * variables. It calls itself recursively until it gets to the bottom of it
+ * all, and then builds the descriptor backwards. It is easiest to do it this
+ *way since we must periodically write length bytes, and it is easiest if we know
+ *the value when it is time to write it.
+ */
+static int
+gen1 (spnt, array_suffix_len)
+ struct VMS_DBG_Symbol *spnt;
+ int array_suffix_len;
+{
+ struct VMS_DBG_Symbol *spnt1;
+ int i;
+ switch (spnt->advanced)
+ {
+ case VOID:
+ push (DBG_S_C_VOID, -1);
+ total_len += 1;
+ push (total_len, -2);
+ return 0;
+ case BASIC:
+ case FUNCTION:
+ if (array_suffix_len == 0)
+ {
+ push (spnt->VMS_type, -1);
+ push (DBG_S_C_BASIC, -1);
+ total_len = 2;
+ push (total_len, -2);
+ return 1;
+ };
+ push (0, -4);
+ push (0xfa02, -2);
+ total_len = -2;
+ return 1;
+ case STRUCT:
+ case UNION:
+ case ENUM:
+ struct_number = spnt->struc_numb;
+ if (struct_number < 0)
+ {
+ new_forward_ref (spnt->dbx_type);
+ return 1;
+ }
+ push (DBG_S_C_STRUCT, -1);
+ total_len = 5;
+ push (total_len, -2);
+ return 1;
+ case POINTER:
+ spnt1 = find_symbol (spnt->type2);
+ i = 1;
+ if (spnt1 == (struct VMS_DBG_Symbol *) NULL)
+ new_forward_ref (spnt->type2);
+ else
+ i = gen1 (spnt1, 0);
+ if (i)
+ { /* (*void) is a special case, do not put pointer suffix*/
+ push (DBG_S_C_POINTER, -1);
+ total_len += 3;
+ push (total_len, -2);
+ };
+ return 1;
+ case ARRAY:
+ spnt1 = spnt;
+ while (spnt1->advanced == ARRAY)
+ {
+ spnt1 = find_symbol (spnt1->type2);
+ if (spnt1 == (struct VMS_DBG_Symbol *) NULL)
+ {
+ printf ("gcc-as warning(debugger output):");
+ printf ("Forward reference error, dbx type %d\n",
+ spnt->type2);
+ return;
+ }
+ };
+/* It is too late to generate forward references, so the user gets a message.
+ * This should only happen on a compiler error */
+ i = gen1 (spnt1, 1);
+ i = Apoint;
+ array_suffix (spnt);
+ array_suffix_len = Apoint - i;
+ switch (spnt1->advanced)
+ {
+ case BASIC:
+ case FUNCTION:
+ break;
+ default:
+ push (0, -2);
+ total_len += 2;
+ push (total_len, -2);
+ push (0xfa, -1);
+ push (0x0101, -2);
+ push (DBG_S_C_COMPLEX_ARRAY, -1);
+ };
+ total_len += array_suffix_len + 8;
+ push (total_len, -2);
+ };
+}
+
+/* This generates a suffix for a variable. If it is not a defined type yet,
+ * then dbx_type contains the type we are expecting so we can generate a
+ * forward reference. This calls gen1 to build most of the descriptor, and
+ * then it puts the icing on at the end. It then dumps whatever is needed
+ * to get a complete descriptor (i.e. struct reference, array suffix ).
+ */
+static
+generate_suffix (spnt, dbx_type)
+ struct VMS_DBG_Symbol *spnt;
+ int dbx_type;
+{
+ int ilen;
+ int i;
+ char pvoid[6] =
+ {5, 0xaf, 0, 1, 0, 5};
+ struct VMS_DBG_Symbol *spnt1;
+ Apoint = 0;
+ Lpnt = MAX_DEBUG_RECORD - 1;
+ total_len = 0;
+ struct_number = 0;
+ overflow = 0;
+ if (spnt == (struct VMS_DBG_Symbol *) NULL)
+ new_forward_ref (dbx_type);
+ else
+ {
+ if (spnt->VMS_type != 0xa3)
+ return 0; /* no suffix needed */
+ gen1 (spnt, 0);
+ };
+ push (0x00af, -2);
+ total_len += 4;
+ push (total_len, -1);
+/* if the variable descriptor overflows the record, output a descriptor for
+ * a pointer to void.
+ */
+ if ((total_len >= MAX_DEBUG_RECORD) || overflow)
+ {
+ printf (" Variable descriptor %d too complicated. Defined as *void ", spnt->dbx_type);
+ VMS_Store_Immediate_Data (pvoid, 6, OBJ_S_C_DBG);
+ return;
+ };
+ i = 0;
+ while (Lpnt < MAX_DEBUG_RECORD - 1)
+ Local[i++] = Local[++Lpnt];
+ Lpnt = i;
+/* we use this for a reference to a structure that has already been defined */
+ if (struct_number > 0)
+ {
+ VMS_Store_Immediate_Data (Local, Lpnt, OBJ_S_C_DBG);
+ Lpnt = 0;
+ VMS_Store_Struct (struct_number);
+ };
+/* we use this for a forward reference to a structure that has yet to be
+*defined. We store four bytes of zero to make room for the actual address once
+* it is known
+*/
+ if (struct_number < 0)
+ {
+ struct_number = -struct_number;
+ VMS_Store_Immediate_Data (Local, Lpnt, OBJ_S_C_DBG);
+ Lpnt = 0;
+ VMS_Def_Struct (struct_number);
+ for (i = 0; i < 4; i++)
+ Local[Lpnt++] = 0;
+ VMS_Store_Immediate_Data (Local, Lpnt, OBJ_S_C_DBG);
+ Lpnt = 0;
+ };
+ i = 0;
+ while (i < Apoint)
+ Local[Lpnt++] = Asuffix[i++];
+ if (Lpnt != 0)
+ VMS_Store_Immediate_Data (Local, Lpnt, OBJ_S_C_DBG);
+ Lpnt = 0;
+}
+
+/* This routine generates a symbol definition for a C sybmol for the debugger.
+ * It takes a psect and offset for global symbols - if psect < 0, then this is
+ * a local variable and the offset is relative to FP. In this case it can
+ * be either a variable (Offset < 0) or a parameter (Offset > 0).
+ */
+static
+VMS_DBG_record (spnt, Psect, Offset, Name)
+ struct VMS_DBG_Symbol *spnt;
+ int Psect;
+ int Offset;
+ char *Name;
+{
+ char *pnt;
+ char *Name_pnt;
+ int j;
+ int maxlen;
+ int i = 0;
+ Name_pnt = fix_name (Name); /* if there are bad characters in name, convert them */
+ if (Psect < 0)
+ { /* this is a local variable, referenced to SP */
+ maxlen = 7 + strlen (Name_pnt);
+ Local[i++] = maxlen;
+ Local[i++] = spnt->VMS_type;
+ if (Offset > 0)
+ Local[i++] = DBG_S_C_FUNCTION_PARAMETER;
+ else
+ Local[i++] = DBG_S_C_LOCAL_SYM;
+ pnt = (char *) &Offset;
+ for (j = 0; j < 4; j++)
+ Local[i++] = *pnt++; /* copy the offset */
+ }
+ else
+ {
+ maxlen = 7 + strlen (Name_pnt); /* symbols fixed in memory */
+ Local[i++] = 7 + strlen (Name_pnt);
+ Local[i++] = spnt->VMS_type;
+ Local[i++] = 1;
+ VMS_Store_Immediate_Data (Local, i, OBJ_S_C_DBG);
+ i = 0;
+ VMS_Set_Data (Psect, Offset, OBJ_S_C_DBG, 0);
+ }
+ Local[i++] = strlen (Name_pnt);
+ while (*Name_pnt != '\0')
+ Local[i++] = *Name_pnt++;
+ VMS_Store_Immediate_Data (Local, i, OBJ_S_C_DBG);
+ if (spnt->VMS_type == DBG_S_C_ADVANCED_TYPE)
+ generate_suffix (spnt, 0);
+}
+
+
+/* This routine parses the stabs entries in order to make the definition
+ * for the debugger of local symbols and function parameters
+ */
+static int
+VMS_local_stab_Parse (sp)
+ symbolS *sp;
+{
+ char *pnt;
+ char *pnt1;
+ char *str;
+ struct VMS_DBG_Symbol *spnt;
+ struct VMS_Symbol *vsp;
+ int dbx_type;
+ int VMS_type;
+ dbx_type = 0;
+ str = S_GET_NAME (sp);
+ pnt = (char *) strchr (str, ':');
+ if (pnt == (char *) NULL)
+ return; /* no colon present */
+ pnt1 = pnt++; /* save this for later, and skip colon */
+ if (*pnt == 'c')
+ return 0; /* ignore static constants */
+/* there is one little catch that we must be aware of. Sometimes function
+ * parameters are optimized into registers, and the compiler, in its infiite
+ * wisdom outputs stabs records for *both*. In general we want to use the
+ * register if it is present, so we must search the rest of the symbols for
+ * this function to see if this parameter is assigned to a register.
+ */
+ {
+ char *str1;
+ char *pnt2;
+ symbolS *sp1;
+ if (*pnt == 'p')
+ {
+ for (sp1 = symbol_next (sp); sp1; sp1 = symbol_next (sp1))
+ {
+ if (!S_IS_DEBUG (sp1))
+ continue;
+ if (S_GET_RAW_TYPE (sp1) == N_FUN)
+ {
+ char * pnt3=(char*) strchr (S_GET_NAME (sp1), ':') + 1;
+ if (*pnt3 == 'F' || *pnt3 == 'f') break;
+ };
+ if (S_GET_RAW_TYPE (sp1) != N_RSYM)
+ continue;
+ str1 = S_GET_NAME (sp1); /* and get the name */
+ pnt2 = str;
+ while (*pnt2 != ':')
+ {
+ if (*pnt2 != *str1)
+ break;
+ pnt2++;
+ str1++;
+ };
+ if ((*str1 != ':') || (*pnt2 != ':'))
+ continue;
+ return; /* they are the same! lets skip this one */
+ }; /* for */
+/* first find the dbx symbol type from list, and then find VMS type */
+ pnt++; /* skip p in case no register */
+ }; /* if */
+ }; /* p block */
+ pnt = cvt_integer (pnt, &dbx_type);
+ spnt = find_symbol (dbx_type);
+ if (spnt == (struct VMS_DBG_Symbol *) NULL)
+ return 0; /*Dunno what this is*/
+ *pnt1 = '\0';
+ VMS_DBG_record (spnt, -1, S_GET_VALUE (sp), str);
+ *pnt1 = ':'; /* and restore the string */
+ return 1;
+}
+
+/* This routine parses a stabs entry to find the information required to define
+ * a variable. It is used for global and static variables.
+ * Basically we need to know the address of the symbol. With older versions
+ * of the compiler, const symbols are
+ * treated differently, in that if they are global they are written into the
+ * text psect. The global symbol entry for such a const is actually written
+ * as a program entry point (Yuk!!), so if we cannot find a symbol in the list
+ * of psects, we must search the entry points as well. static consts are even
+ * harder, since they are never assigned a memory address. The compiler passes
+ * a stab to tell us the value, but I am not sure what to do with it.
+ */
+
+static
+VMS_stab_parse (sp, expected_type, type1, type2, Text_Psect)
+ symbolS *sp;
+ char expected_type;
+ int type1, type2, Text_Psect;
+{
+ char *pnt;
+ char *pnt1;
+ char *str;
+ symbolS *sp1;
+ struct VMS_DBG_Symbol *spnt;
+ struct VMS_Symbol *vsp;
+ int dbx_type;
+ int VMS_type;
+ dbx_type = 0;
+ str = S_GET_NAME (sp);
+ pnt = (char *) strchr (str, ':');
+ if (pnt == (char *) NULL)
+ return; /* no colon present */
+ pnt1 = pnt; /* save this for later*/
+ pnt++;
+ if (*pnt == expected_type)
+ {
+ pnt = cvt_integer (pnt + 1, &dbx_type);
+ spnt = find_symbol (dbx_type);
+ if (spnt == (struct VMS_DBG_Symbol *) NULL)
+ return 0; /*Dunno what this is*/
+/* now we need to search the symbol table to find the psect and offset for
+ * this variable.
+ */
+ *pnt1 = '\0';
+ vsp = VMS_Symbols;
+ while (vsp != (struct VMS_Symbol *) NULL)
+ {
+ pnt = S_GET_NAME (vsp->Symbol);
+ if (pnt != (char *) NULL)
+ if (*pnt++ == '_')
+/* make sure name is the same, and make sure correct symbol type */
+ if ((strlen (pnt) == strlen (str)) && (strcmp (pnt, str) == 0)
+ && ((S_GET_RAW_TYPE (vsp->Symbol) == type1) ||
+ (S_GET_RAW_TYPE (vsp->Symbol) == type2)))
+ break;
+ vsp = vsp->Next;
+ };
+ if (vsp != (struct VMS_Symbol *) NULL)
+ {
+ VMS_DBG_record (spnt, vsp->Psect_Index, vsp->Psect_Offset, str);
+ *pnt1 = ':'; /* and restore the string */
+ return 1;
+ };
+/* the symbol was not in the symbol list, but it may be an "entry point"
+ if it was a constant */
+ for (sp1 = symbol_rootP; sp1; sp1 = symbol_next (sp1))
+ {
+ /*
+ * Dispatch on STAB type
+ */
+ if (S_IS_DEBUG (sp1) || (S_GET_TYPE (sp1) != N_TEXT))
+ continue;
+ pnt = S_GET_NAME (sp1);
+ if (*pnt == '_')
+ pnt++;
+ if (strcmp (pnt, str) == 0)
+ {
+ if (!gave_compiler_message && expected_type == 'G')
+ {
+ printf ("***Warning - the assembly code generated by the compiler has placed\n");
+ printf ("global constant(s) in the text psect. These will not be available to\n");
+ printf ("other modules, since this is not the correct way to handle this. You\n");
+ printf ("have two options: 1) get a patched compiler that does not put global\n");
+ printf ("constants in the text psect, or 2) remove the 'const' keyword from\n");
+ printf ("definitions of global variables in your source module(s). Don't say\n");
+ printf ("I didn't warn you!");
+ gave_compiler_message = 1;
+ };
+ VMS_DBG_record (spnt,
+ Text_Psect,
+ S_GET_VALUE (sp1),
+ str);
+ *pnt1 = ':';
+ *S_GET_NAME (sp1) = 'L';
+ /* fool assembler to not output this
+ * as a routine in the TBT */
+ return 1;
+ };
+ };
+ };
+ *pnt1 = ':'; /* and restore the string */
+ return 0;
+}
+
+static
+VMS_GSYM_Parse (sp, Text_Psect)
+ symbolS *sp;
+ int Text_Psect;
+{ /* Global variables */
+ VMS_stab_parse (sp, 'G', (N_UNDF | N_EXT), (N_DATA | N_EXT), Text_Psect);
+}
+
+
+static
+VMS_LCSYM_Parse (sp, Text_Psect)
+ symbolS *sp;
+ int Text_Psect;
+{ /* Static symbols - uninitialized */
+ VMS_stab_parse (sp, 'S', N_BSS, -1, Text_Psect);
+}
+
+static
+VMS_STSYM_Parse (sp, Text_Psect)
+ symbolS *sp;
+ int Text_Psect;
+{ /* Static symbols - initialized */
+ VMS_stab_parse (sp, 'S', N_DATA, -1, Text_Psect);
+}
+
+
+/* for register symbols, we must figure out what range of addresses within the
+ * psect are valid. We will use the brackets in the stab directives to give us
+ * guidance as to the PC range that this variable is in scope. I am still not
+ * completely comfortable with this but as I learn more, I seem to get a better
+ * handle on what is going on.
+ * Caveat Emptor.
+ */
+static
+VMS_RSYM_Parse (sp, Current_Routine, Text_Psect)
+ symbolS *sp, *Current_Routine;
+ int Text_Psect;
+{
+ char *pnt;
+ char *pnt1;
+ char *str;
+ int dbx_type;
+ struct VMS_DBG_Symbol *spnt;
+ int j;
+ int maxlen;
+ int i = 0;
+ int bcnt = 0;
+ int Min_Offset = -1; /* min PC of validity */
+ int Max_Offset = 0; /* max PC of validity */
+ symbolS *symbolP;
+ for (symbolP = sp; symbolP; symbolP = symbol_next (symbolP))
+ {
+ /*
+ * Dispatch on STAB type
+ */
+ switch (S_GET_RAW_TYPE (symbolP))
+ {
+ case N_LBRAC:
+ if (bcnt++ == 0)
+ Min_Offset = S_GET_VALUE (symbolP);
+ break;
+ case N_RBRAC:
+ if (--bcnt == 0)
+ Max_Offset =
+ S_GET_VALUE (symbolP) - 1;
+ break;
+ }
+ if ((Min_Offset != -1) && (bcnt == 0))
+ break;
+ if (S_GET_RAW_TYPE (symbolP) == N_FUN)
+ {
+ pnt=(char*) strchr (S_GET_NAME (symbolP), ':') + 1;
+ if (*pnt == 'F' || *pnt == 'f') break;
+ };
+ }
+/* check to see that the addresses were defined. If not, then there were no
+ * brackets in the function, and we must try to search for the next function
+ * Since functions can be in any order, we should search all of the symbol list
+ * to find the correct ending address. */
+ if (Min_Offset == -1)
+ {
+ int Max_Source_Offset;
+ int This_Offset;
+ Min_Offset = S_GET_VALUE (sp);
+ for (symbolP = symbol_rootP; symbolP; symbolP = symbol_next (symbolP))
+ {
+ /*
+ * Dispatch on STAB type
+ */
+ This_Offset = S_GET_VALUE (symbolP);
+ switch (S_GET_RAW_TYPE (symbolP))
+ {
+ case N_TEXT | N_EXT:
+ if ((This_Offset > Min_Offset) && (This_Offset < Max_Offset))
+ Max_Offset = This_Offset;
+ break;
+ case N_SLINE:
+ if (This_Offset > Max_Source_Offset)
+ Max_Source_Offset = This_Offset;
+ }
+ }
+/* if this is the last routine, then we use the PC of the last source line
+ * as a marker of the max PC for which this reg is valid */
+ if (Max_Offset == 0x7fffffff)
+ Max_Offset = Max_Source_Offset;
+ };
+ dbx_type = 0;
+ str = S_GET_NAME (sp);
+ pnt = (char *) strchr (str, ':');
+ if (pnt == (char *) NULL)
+ return; /* no colon present */
+ pnt1 = pnt; /* save this for later*/
+ pnt++;
+ if (*pnt != 'r')
+ return 0;
+ pnt = cvt_integer (pnt + 1, &dbx_type);
+ spnt = find_symbol (dbx_type);
+ if (spnt == (struct VMS_DBG_Symbol *) NULL)
+ return 0; /*Dunno what this is yet*/
+ *pnt1 = '\0';
+ pnt = fix_name (S_GET_NAME (sp)); /* if there are bad characters in name, convert them */
+ maxlen = 25 + strlen (pnt);
+ Local[i++] = maxlen;
+ Local[i++] = spnt->VMS_type;
+ Local[i++] = 0xfb;
+ Local[i++] = strlen (pnt) + 1;
+ Local[i++] = 0x00;
+ Local[i++] = 0x00;
+ Local[i++] = 0x00;
+ Local[i++] = strlen (pnt);
+ while (*pnt != '\0')
+ Local[i++] = *pnt++;
+ Local[i++] = 0xfd;
+ Local[i++] = 0x0f;
+ Local[i++] = 0x00;
+ Local[i++] = 0x03;
+ Local[i++] = 0x01;
+ VMS_Store_Immediate_Data (Local, i, OBJ_S_C_DBG);
+ i = 0;
+ VMS_Set_Data (Text_Psect, Min_Offset, OBJ_S_C_DBG, 1);
+ VMS_Set_Data (Text_Psect, Max_Offset, OBJ_S_C_DBG, 1);
+ Local[i++] = 0x03;
+ Local[i++] = S_GET_VALUE (sp);
+ Local[i++] = 0x00;
+ Local[i++] = 0x00;
+ Local[i++] = 0x00;
+ VMS_Store_Immediate_Data (Local, i, OBJ_S_C_DBG);
+ *pnt1 = ':';
+ if (spnt->VMS_type == DBG_S_C_ADVANCED_TYPE)
+ generate_suffix (spnt, 0);
+}
+
+/* this function examines a structure definition, checking all of the elements
+ * to make sure that all of them are fully defined. The only thing that we
+ * kick out are arrays of undefined structs, since we do not know how big
+ * they are. All others we can handle with a normal forward reference.
+ */
+static int
+forward_reference (pnt)
+ char *pnt;
+{
+ int i;
+ struct VMS_DBG_Symbol *spnt;
+ struct VMS_DBG_Symbol *spnt1;
+ pnt = cvt_integer (pnt + 1, &i);
+ if (*pnt == ';')
+ return 0; /* no forward references */
+ do
+ {
+ pnt = (char *) strchr (pnt, ':');
+ pnt = cvt_integer (pnt + 1, &i);
+ spnt = find_symbol (i);
+ if (spnt == (struct VMS_DBG_Symbol *) NULL)
+ return 0;
+ while ((spnt->advanced == POINTER) || (spnt->advanced == ARRAY))
+ {
+ i = spnt->type2;
+ spnt1 = find_symbol (spnt->type2);
+ if ((spnt->advanced == ARRAY) &&
+ (spnt1 == (struct VMS_DBG_Symbol *) NULL))
+ return 1;
+ if (spnt1 == (struct VMS_DBG_Symbol *) NULL)
+ break;
+ spnt = spnt1;
+ };
+ pnt = cvt_integer (pnt + 1, &i);
+ pnt = cvt_integer (pnt + 1, &i);
+ } while (*++pnt != ';');
+ return 0; /* no forward refences found */
+}
+
+/* This routine parses the stabs directives to find any definitions of dbx type
+ * numbers. It makes a note of all of them, creating a structure element
+ * of VMS_DBG_Symbol that describes it. This also generates the info for the
+ * debugger that describes the struct/union/enum, so that further references
+ * to these data types will be by number
+ * We have to process pointers right away, since there can be references
+ * to them later in the same stabs directive. We cannot have forward
+ * references to pointers, (but we can have a forward reference to a pointer to
+ * a structure/enum/union) and this is why we process them immediately.
+ * After we process the pointer, then we search for defs that are nested even
+ * deeper.
+ */
+static int
+VMS_typedef_parse (str)
+ char *str;
+{
+ char *pnt;
+ char *pnt1;
+ char *pnt2;
+ int i;
+ int dtype;
+ struct forward_ref *fpnt;
+ int i1, i2, i3;
+ int convert_integer;
+ struct VMS_DBG_Symbol *spnt;
+ struct VMS_DBG_Symbol *spnt1;
+/* check for any nested def's */
+ pnt = (char *) strchr (str + 1, '=');
+ if ((pnt != (char *) NULL) && (*(str + 1) != '*'))
+ if (VMS_typedef_parse (pnt) == 1)
+ return 1;
+/* now find dbx_type of entry */
+ pnt = str - 1;
+ if (*pnt == 'c')
+ { /* check for static constants */
+ *str = '\0'; /* for now we ignore them */
+ return 0;
+ };
+ while ((*pnt <= '9') && (*pnt >= '0'))
+ pnt--;
+ pnt++; /* and get back to the number */
+ cvt_integer (pnt, &i1);
+ spnt = find_symbol (i1);
+/* first we see if this has been defined already, due to a forward reference*/
+ if (spnt == (struct VMS_DBG_Symbol *) NULL)
+ {
+ if (VMS_Symbol_type_list == (struct VMS_DBG_Symbol *) NULL)
+ {
+ spnt = (struct VMS_DBG_Symbol *) malloc (sizeof (struct VMS_DBG_Symbol));
+ spnt->next = (struct VMS_DBG_Symbol *) NULL;
+ VMS_Symbol_type_list = spnt;
+ }
+ else
+ {
+ spnt = (struct VMS_DBG_Symbol *) malloc (sizeof (struct VMS_DBG_Symbol));
+ spnt->next = VMS_Symbol_type_list;
+ VMS_Symbol_type_list = spnt;
+ };
+ spnt->dbx_type = i1; /* and save the type */
+ };
+/* for structs and unions, do a partial parse, otherwise we sometimes get
+ * circular definitions that are impossible to resolve. We read enough info
+ * so that any reference to this type has enough info to be resolved
+ */
+ pnt = str + 1; /* point to character past equal sign */
+ if ((*pnt == 'u') || (*pnt == 's'))
+ {
+ };
+ if ((*pnt <= '9') && (*pnt >= '0'))
+ {
+ if (type_check ("void"))
+ { /* this is the void symbol */
+ *str = '\0';
+ spnt->advanced = VOID;
+ return 0;
+ };
+ if (type_check ("unknown type"))
+ { /* this is the void symbol */
+ *str = '\0';
+ spnt->advanced = UNKNOWN;
+ return 0;
+ };
+ printf ("gcc-as warning(debugger output):");
+ printf (" %d is an unknown untyped variable.\n", spnt->dbx_type);
+ return 1; /* do not know what this is */
+ };
+/* now define this module*/
+ pnt = str + 1; /* point to character past equal sign */
+ switch (*pnt)
+ {
+ case 'r':
+ spnt->advanced = BASIC;
+ if (type_check ("int"))
+ {
+ spnt->VMS_type = DBG_S_C_SLINT;
+ spnt->data_size = 4;
+ }
+ else if (type_check ("long int"))
+ {
+ spnt->VMS_type = DBG_S_C_SLINT;
+ spnt->data_size = 4;
+ }
+ else if (type_check ("unsigned int"))
+ {
+ spnt->VMS_type = DBG_S_C_ULINT;
+ spnt->data_size = 4;
+ }
+ else if (type_check ("long unsigned int"))
+ {
+ spnt->VMS_type = DBG_S_C_ULINT;
+ spnt->data_size = 4;
+ }
+ else if (type_check ("short int"))
+ {
+ spnt->VMS_type = DBG_S_C_SSINT;
+ spnt->data_size = 2;
+ }
+ else if (type_check ("short unsigned int"))
+ {
+ spnt->VMS_type = DBG_S_C_USINT;
+ spnt->data_size = 2;
+ }
+ else if (type_check ("char"))
+ {
+ spnt->VMS_type = DBG_S_C_SCHAR;
+ spnt->data_size = 1;
+ }
+ else if (type_check ("signed char"))
+ {
+ spnt->VMS_type = DBG_S_C_SCHAR;
+ spnt->data_size = 1;
+ }
+ else if (type_check ("unsigned char"))
+ {
+ spnt->VMS_type = DBG_S_C_UCHAR;
+ spnt->data_size = 1;
+ }
+ else if (type_check ("float"))
+ {
+ spnt->VMS_type = DBG_S_C_REAL4;
+ spnt->data_size = 4;
+ }
+ else if (type_check ("double"))
+ {
+ spnt->VMS_type = DBG_S_C_REAL8;
+ spnt->data_size = 8;
+ }
+ pnt1 = (char *) strchr (str, ';') + 1;
+ break;
+ case 's':
+ case 'u':
+ if (*pnt == 's')
+ spnt->advanced = STRUCT;
+ else
+ spnt->advanced = UNION;
+ spnt->VMS_type = DBG_S_C_ADVANCED_TYPE;
+ pnt1 = cvt_integer (pnt + 1, &spnt->data_size);
+ if (forward_reference (pnt))
+ {
+ spnt->struc_numb = -1;
+ return 1;
+ }
+ spnt->struc_numb = ++structure_count;
+ pnt1--;
+ pnt = get_struct_name (str);
+ VMS_Def_Struct (spnt->struc_numb);
+ fpnt = f_ref_root;
+ while (fpnt != (struct forward_ref *) NULL)
+ {
+ if (fpnt->dbx_type == spnt->dbx_type)
+ {
+ fpnt->resolved = 'Y';
+ VMS_Set_Struct (fpnt->struc_numb);
+ VMS_Store_Struct (spnt->struc_numb);
+ };
+ fpnt = fpnt->next;
+ };
+ VMS_Set_Struct (spnt->struc_numb);
+ i = 0;
+ Local[i++] = 11 + strlen (pnt);
+ Local[i++] = DBG_S_C_STRUCT_START;
+ Local[i++] = 0x80;
+ for (i1 = 0; i1 < 4; i1++)
+ Local[i++] = 0x00;
+ Local[i++] = strlen (pnt);
+ pnt2 = pnt;
+ while (*pnt2 != '\0')
+ Local[i++] = *pnt2++;
+ i2 = spnt->data_size * 8; /* number of bits */
+ pnt2 = (char *) &i2;
+ for (i1 = 0; i1 < 4; i1++)
+ Local[i++] = *pnt2++;
+ VMS_Store_Immediate_Data (Local, i, OBJ_S_C_DBG);
+ i = 0;
+ if (pnt != symbol_name)
+ {
+ pnt += strlen (pnt);
+ *pnt = ':';
+ }; /* replace colon for later */
+ while (*++pnt1 != ';')
+ {
+ pnt = (char *) strchr (pnt1, ':');
+ *pnt = '\0';
+ pnt2 = pnt1;
+ pnt1 = cvt_integer (pnt + 1, &dtype);
+ pnt1 = cvt_integer (pnt1 + 1, &i2);
+ pnt1 = cvt_integer (pnt1 + 1, &i3);
+ if ((dtype == 1) && (i3 != 32))
+ { /* bitfield */
+ Apoint = 0;
+ push (19 + strlen (pnt2), 1);
+ push (0xfa22, 2);
+ push (1 + strlen (pnt2), 4);
+ push (strlen (pnt2), 1);
+ while (*pnt2 != '\0')
+ push (*pnt2++, 1);
+ push (i3, 2); /* size of bitfield */
+ push (0x0d22, 2);
+ push (0x00, 4);
+ push (i2, 4); /* start position */
+ VMS_Store_Immediate_Data (Asuffix, Apoint, OBJ_S_C_DBG);
+ Apoint = 0;
+ }
+ else
+ {
+ Local[i++] = 7 + strlen (pnt2);
+ spnt1 = find_symbol (dtype);
+ /* check if this is a forward reference */
+ if (spnt1 != (struct VMS_DBG_Symbol *) NULL)
+ Local[i++] = spnt1->VMS_type;
+ else
+ Local[i++] = DBG_S_C_ADVANCED_TYPE;
+ Local[i++] = DBG_S_C_STRUCT_ITEM;
+ pnt = (char *) &i2;
+ for (i1 = 0; i1 < 4; i1++)
+ Local[i++] = *pnt++;
+ Local[i++] = strlen (pnt2);
+ while (*pnt2 != '\0')
+ Local[i++] = *pnt2++;
+ VMS_Store_Immediate_Data (Local, i, OBJ_S_C_DBG);
+ i = 0;
+ if (spnt1 == (struct VMS_DBG_Symbol *) NULL)
+ generate_suffix (spnt1, dtype);
+ else if (spnt1->VMS_type == DBG_S_C_ADVANCED_TYPE)
+ generate_suffix (spnt1, 0);
+ };
+ };
+ pnt1++;
+ Local[i++] = 0x01; /* length byte */
+ Local[i++] = DBG_S_C_STRUCT_END;
+ VMS_Store_Immediate_Data (Local, i, OBJ_S_C_DBG);
+ i = 0;
+ break;
+ case 'e':
+ spnt->advanced = ENUM;
+ spnt->VMS_type = DBG_S_C_ADVANCED_TYPE;
+ spnt->struc_numb = ++structure_count;
+ spnt->data_size = 4;
+ VMS_Def_Struct (spnt->struc_numb);
+ fpnt = f_ref_root;
+ while (fpnt != (struct forward_ref *) NULL)
+ {
+ if (fpnt->dbx_type == spnt->dbx_type)
+ {
+ fpnt->resolved = 'Y';
+ VMS_Set_Struct (fpnt->struc_numb);
+ VMS_Store_Struct (spnt->struc_numb);
+ };
+ fpnt = fpnt->next;
+ };
+ VMS_Set_Struct (spnt->struc_numb);
+ i = 0;
+ Local[i++] = 3 + strlen (symbol_name);
+ Local[i++] = DBG_S_C_ENUM_START;
+ Local[i++] = 0x20;
+ Local[i++] = strlen (symbol_name);
+ pnt2 = symbol_name;
+ while (*pnt2 != '\0')
+ Local[i++] = *pnt2++;
+ VMS_Store_Immediate_Data (Local, i, OBJ_S_C_DBG);
+ i = 0;
+ while (*++pnt != ';')
+ {
+ pnt1 = (char *) strchr (pnt, ':');
+ *pnt1++ = '\0';
+ pnt1 = cvt_integer (pnt1, &i1);
+ Local[i++] = 7 + strlen (pnt);
+ Local[i++] = DBG_S_C_ENUM_ITEM;
+ Local[i++] = 0x00;
+ pnt2 = (char *) &i1;
+ for (i2 = 0; i2 < 4; i2++)
+ Local[i++] = *pnt2++;
+ Local[i++] = strlen (pnt);
+ pnt2 = pnt;
+ while (*pnt != '\0')
+ Local[i++] = *pnt++;
+ VMS_Store_Immediate_Data (Local, i, OBJ_S_C_DBG);
+ i = 0;
+ pnt = pnt1; /* Skip final semicolon */
+ };
+ Local[i++] = 0x01; /* len byte */
+ Local[i++] = DBG_S_C_ENUM_END;
+ VMS_Store_Immediate_Data (Local, i, OBJ_S_C_DBG);
+ i = 0;
+ pnt1 = pnt + 1;
+ break;
+ case 'a':
+ spnt->advanced = ARRAY;
+ spnt->VMS_type = DBG_S_C_ADVANCED_TYPE;
+ pnt = (char *) strchr (pnt, ';');
+ if (pnt == (char *) NULL)
+ return 1;
+ pnt1 = cvt_integer (pnt + 1, &spnt->index_min);
+ pnt1 = cvt_integer (pnt1 + 1, &spnt->index_max);
+ pnt1 = cvt_integer (pnt1 + 1, &spnt->type2);
+ break;
+ case 'f':
+ spnt->advanced = FUNCTION;
+ spnt->VMS_type = DBG_S_C_FUNCTION_ADDR;
+ /* this masquerades as a basic type*/
+ spnt->data_size = 4;
+ pnt1 = cvt_integer (pnt + 1, &spnt->type2);
+ break;
+ case '*':
+ spnt->advanced = POINTER;
+ spnt->VMS_type = DBG_S_C_ADVANCED_TYPE;
+ spnt->data_size = 4;
+ pnt1 = cvt_integer (pnt + 1, &spnt->type2);
+ pnt = (char *) strchr (str + 1, '=');
+ if ((pnt != (char *) NULL))
+ if (VMS_typedef_parse (pnt) == 1)
+ return 1;
+ break;
+ default:
+ spnt->advanced = UNKNOWN;
+ spnt->VMS_type = 0;
+ printf ("gcc-as warning(debugger output):");
+ printf (" %d is an unknown type of variable.\n", spnt->dbx_type);
+ return 1; /* unable to decipher */
+ };
+/* this removes the evidence of the definition so that the outer levels of
+parsing do not have to worry about it */
+ pnt = str;
+ while (*pnt1 != '\0')
+ *pnt++ = *pnt1++;
+ *pnt = '\0';
+ return 0;
+}
+
+
+/*
+ * This is the root routine that parses the stabs entries for definitions.
+ * it calls VMS_typedef_parse, which can in turn call itself.
+ * We need to be careful, since sometimes there are forward references to
+ * other symbol types, and these cannot be resolved until we have completed
+ * the parse.
+ */
+static int
+VMS_LSYM_Parse ()
+{
+ char *pnt;
+ char *pnt1;
+ char *pnt2;
+ char *str;
+ char fixit[10];
+ int incomplete, i, pass, incom1;
+ struct VMS_DBG_Symbol *spnt;
+ struct VMS_Symbol *vsp;
+ struct forward_ref *fpnt;
+ symbolS *sp;
+ pass = 0;
+ incomplete = 0;
+ do
+ {
+ incom1 = incomplete;
+ incomplete = 0;
+ for (sp = symbol_rootP; sp; sp = symbol_next (sp))
+ {
+ /*
+ * Deal with STAB symbols
+ */
+ if (S_IS_DEBUG (sp))
+ {
+ /*
+ * Dispatch on STAB type
+ */
+ switch (S_GET_RAW_TYPE (sp))
+ {
+ case N_GSYM:
+ case N_LCSYM:
+ case N_STSYM:
+ case N_PSYM:
+ case N_RSYM:
+ case N_LSYM:
+ case N_FUN: /*sometimes these contain typedefs*/
+ str = S_GET_NAME (sp);
+ symbol_name = str;
+ pnt = (char *) strchr (str, ':');
+ if (pnt == (char *) NULL)
+ break;
+ *pnt = '\0';
+ pnt1 = pnt + 1;
+ pnt2 = (char *) strchr (pnt1, '=');
+ if (pnt2 == (char *) NULL)
+ {
+ *pnt = ':'; /* replace colon */
+ break;
+ }; /* no symbol here */
+ incomplete += VMS_typedef_parse (pnt2);
+ *pnt = ':'; /* put back colon so variable def code finds dbx_type*/
+ break;
+ } /*switch*/
+ } /* if */
+ } /*for*/
+ pass++;
+ } while ((incomplete != 0) && (incomplete != incom1));
+ /* repeat until all refs resolved if possible */
+/* if (pass > 1) printf(" Required %d passes\n",pass);*/
+ if (incomplete != 0)
+ {
+ printf ("gcc-as warning(debugger output):");
+ printf ("Unable to resolve %d circular references.\n", incomplete);
+ };
+ fpnt = f_ref_root;
+ symbol_name = "\0";
+ while (fpnt != (struct forward_ref *) NULL)
+ {
+ if (fpnt->resolved != 'Y')
+ {
+ if (find_symbol (fpnt->dbx_type) !=
+ (struct VMS_DBG_Symbol *) NULL)
+ {
+ printf ("gcc-as warning(debugger output):");
+ printf ("Forward reference error, dbx type %d\n",
+ fpnt->dbx_type);
+ break;
+ };
+ fixit[0] = 0;
+ sprintf (&fixit[1], "%d=s4;", fpnt->dbx_type);
+ pnt2 = (char *) strchr (&fixit[1], '=');
+ VMS_typedef_parse (pnt2);
+ };
+ fpnt = fpnt->next;
+ };
+}
+
+static
+Define_Local_Symbols (s1, s2)
+ symbolS *s1, *s2;
+{
+ symbolS *symbolP1;
+ for (symbolP1 = symbol_next (s1); symbolP1 != s2; symbolP1 = symbol_next (symbolP1))
+ {
+ if (symbolP1 == (symbolS *) NULL)
+ return;
+ if (S_GET_RAW_TYPE (symbolP1) == N_FUN)
+ {
+ char * pnt=(char*) strchr (S_GET_NAME (symbolP1), ':') + 1;
+ if (*pnt == 'F' || *pnt == 'f') break;
+ };
+ /*
+ * Deal with STAB symbols
+ */
+ if (S_IS_DEBUG (symbolP1))
+ {
+ /*
+ * Dispatch on STAB type
+ */
+ switch (S_GET_RAW_TYPE (symbolP1))
+ {
+ case N_LSYM:
+ case N_PSYM:
+ VMS_local_stab_Parse (symbolP1);
+ break;
+ case N_RSYM:
+ VMS_RSYM_Parse (symbolP1, Current_Routine, Text_Psect);
+ break;
+ } /*switch*/
+ } /* if */
+ } /* for */
+}
+
+
+/* This function crawls the symbol chain searching for local symbols that need
+ * to be described to the debugger. When we enter a new scope with a "{", it
+ * creates a new "block", which helps the debugger keep track of which scope
+ * we are currently in.
+ */
+
+static symbolS *
+Define_Routine (symbolP, Level)
+ symbolS *symbolP;
+ int Level;
+{
+ symbolS *sstart;
+ symbolS *symbolP1;
+ char str[10];
+ int rcount = 0;
+ int Offset;
+ sstart = symbolP;
+ for (symbolP1 = symbol_next (symbolP); symbolP1; symbolP1 = symbol_next (symbolP1))
+ {
+ if (S_GET_RAW_TYPE (symbolP1) == N_FUN)
+ {
+ char * pnt=(char*) strchr (S_GET_NAME (symbolP1), ':') + 1;
+ if (*pnt == 'F' || *pnt == 'f') break;
+ };
+ /*
+ * Deal with STAB symbols
+ */
+ if (S_IS_DEBUG (symbolP1))
+ {
+ /*
+ * Dispatch on STAB type
+ */
+ switch (S_GET_RAW_TYPE (symbolP1))
+ {
+ case N_LBRAC:
+ if (Level != 0)
+ {
+ sprintf (str, "$%d", rcount++);
+ VMS_TBT_Block_Begin (symbolP1, Text_Psect, str);
+ };
+ Offset = S_GET_VALUE (symbolP1);
+ Define_Local_Symbols (sstart, symbolP1);
+ symbolP1 =
+ Define_Routine (symbolP1, Level + 1);
+ if (Level != 0)
+ VMS_TBT_Block_End (S_GET_VALUE (symbolP1) -
+ Offset);
+ sstart = symbolP1;
+ break;
+ case N_RBRAC:
+ return symbolP1;
+ } /*switch*/
+ } /* if */
+ } /* for */
+ /* we end up here if there were no brackets in this function. Define
+everything */
+ Define_Local_Symbols (sstart, (symbolS *) 0);
+ return symbolP1;
+}
+
+
+static
+VMS_DBG_Define_Routine (symbolP, Curr_Routine, Txt_Psect)
+ symbolS *symbolP;
+ symbolS *Curr_Routine;
+ int Txt_Psect;
+{
+ Current_Routine = Curr_Routine;
+ Text_Psect = Txt_Psect;
+ Define_Routine (symbolP, 0);
+}
+
+
+
+
+#ifndef HO_VMS
+#include <sys/types.h>
+#include <time.h>
+
+/* Manufacure a VMS like time on a unix based system. */
+get_VMS_time_on_unix (char *Now)
+{
+ char *pnt;
+ time_t timeb;
+ time (&timeb);
+ pnt = ctime (&timeb);
+ pnt[3] = 0;
+ pnt[7] = 0;
+ pnt[10] = 0;
+ pnt[16] = 0;
+ pnt[24] = 0;
+ sprintf (Now, "%2s-%3s-%s %s", pnt + 8, pnt + 4, pnt + 20, pnt + 11);
+}
+
+#endif /* not HO_VMS */
+/*
+ * Write the MHD (Module Header) records
+ */
+static
+Write_VMS_MHD_Records ()
+{
+ register char *cp, *cp1;
+ register int i;
+ struct
+ {
+ int Size;
+ char *Ptr;
+ } Descriptor;
+ char Module_Name[256];
+ char Now[18];
+
+ /*
+ * We are writing a module header record
+ */
+ Set_VMS_Object_File_Record (OBJ_S_C_HDR);
+ /*
+ * ***************************
+ * *MAIN MODULE HEADER RECORD*
+ * ***************************
+ *
+ * Store record type and header type
+ */
+ PUT_CHAR (OBJ_S_C_HDR);
+ PUT_CHAR (MHD_S_C_MHD);
+ /*
+ * Structure level is 0
+ */
+ PUT_CHAR (OBJ_S_C_STRLVL);
+ /*
+ * Maximum record size is size of the object record buffer
+ */
+ PUT_SHORT (sizeof (Object_Record_Buffer));
+ /*
+ * Get module name (the FILENAME part of the object file)
+ */
+ cp = out_file_name;
+ cp1 = Module_Name;
+ while (*cp)
+ {
+ if ((*cp == ']') || (*cp == '>') ||
+ (*cp == ':') || (*cp == '/'))
+ {
+ cp1 = Module_Name;
+ cp++;
+ continue;
+ }
+ *cp1++ = islower (*cp) ? toupper (*cp++) : *cp++;
+ }
+ *cp1 = 0;
+ /*
+ * Limit it to 31 characters and store in the object record
+ */
+ while (--cp1 >= Module_Name)
+ if (*cp1 == '.')
+ *cp1 = 0;
+ if (strlen (Module_Name) > 31)
+ {
+ if (flagseen['+'])
+ printf ("%s: Module name truncated: %s\n", myname, Module_Name);
+ Module_Name[31] = 0;
+ }
+ PUT_COUNTED_STRING (Module_Name);
+ /*
+ * Module Version is "V1.0"
+ */
+ PUT_COUNTED_STRING ("V1.0");
+ /*
+ * Creation time is "now" (17 chars of time string)
+ */
+#ifndef HO_VMS
+ get_VMS_time_on_unix (&Now[0]);
+#else /* HO_VMS */
+ Descriptor.Size = 17;
+ Descriptor.Ptr = Now;
+ sys$asctim (0, &Descriptor, 0, 0);
+#endif /* HO_VMS */
+ for (i = 0; i < 17; i++)
+ PUT_CHAR (Now[i]);
+ /*
+ * Patch time is "never" (17 zeros)
+ */
+ for (i = 0; i < 17; i++)
+ PUT_CHAR (0);
+ /*
+ * Flush the record
+ */
+ Flush_VMS_Object_Record_Buffer ();
+ /*
+ * *************************
+ * *LANGUAGE PROCESSOR NAME*
+ * *************************
+ *
+ * Store record type and header type
+ */
+ PUT_CHAR (OBJ_S_C_HDR);
+ PUT_CHAR (MHD_S_C_LNM);
+ /*
+ * Store language processor name and version
+ * (not a counted string!)
+ */
+ cp = compiler_version_string;
+ if (cp == 0)
+ {
+ cp = "GNU AS V";
+ while (*cp)
+ PUT_CHAR (*cp++);
+ cp = strchr (&version_string, '.');
+ while (*cp != ' ')
+ cp--;
+ cp++;
+ };
+ while (*cp >= 32)
+ PUT_CHAR (*cp++);
+ /*
+ * Flush the record
+ */
+ Flush_VMS_Object_Record_Buffer ();
+}
+
+
+/*
+ * Write the EOM (End Of Module) record
+ */
+static
+Write_VMS_EOM_Record (Psect, Offset)
+ int Psect;
+ int Offset;
+{
+ /*
+ * We are writing an end-of-module record
+ */
+ Set_VMS_Object_File_Record (OBJ_S_C_EOM);
+ /*
+ * Store record Type
+ */
+ PUT_CHAR (OBJ_S_C_EOM);
+ /*
+ * Store the error severity (0)
+ */
+ PUT_CHAR (0);
+ /*
+ * Store the entry point, if it exists
+ */
+ if (Psect >= 0)
+ {
+ /*
+ * Store the entry point Psect
+ */
+ PUT_CHAR (Psect);
+ /*
+ * Store the entry point Psect offset
+ */
+ PUT_LONG (Offset);
+ }
+ /*
+ * Flush the record
+ */
+ Flush_VMS_Object_Record_Buffer ();
+}
+
+
+/* this hash routine borrowed from GNU-EMACS, and strengthened slightly ERY*/
+
+static int
+hash_string (ptr)
+ unsigned char *ptr;
+{
+ register unsigned char *p = ptr;
+ register unsigned char *end = p + strlen (ptr);
+ register unsigned char c;
+ register int hash = 0;
+
+ while (p != end)
+ {
+ c = *p++;
+ hash = ((hash << 3) + (hash << 15) + (hash >> 28) + c);
+ }
+ return hash;
+}
+
+/*
+ * Generate a Case-Hacked VMS symbol name (limited to 31 chars)
+ */
+static
+VMS_Case_Hack_Symbol (In, Out)
+ register char *In;
+ register char *Out;
+{
+ long int init = 0;
+ long int result;
+ char *pnt;
+ char *new_name;
+ char *old_name;
+ register int i;
+ int destructor = 0; /*hack to allow for case sens in a destructor*/
+ int truncate = 0;
+ int Case_Hack_Bits = 0;
+ int Saw_Dollar = 0;
+ static char Hex_Table[16] =
+ {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
+
+ /*
+ * Kill any leading "_"
+ */
+ if ((In[0] == '_') && ((In[1] > '9') || (In[1] < '0')))
+ In++;
+
+ new_name = Out; /* save this for later*/
+
+#if barfoo /* Dead code */
+ if ((In[0] == '_') && (In[1] == '$') && (In[2] == '_'))
+ destructor = 1;
+#endif
+
+ /* We may need to truncate the symbol, save the hash for later*/
+ if (strlen (In) > 23)
+ result = hash_string (In);
+ /*
+ * Is there a Psect Attribute to skip??
+ */
+ if (HAS_PSECT_ATTRIBUTES (In))
+ {
+ /*
+ * Yes: Skip it
+ */
+ In += PSECT_ATTRIBUTES_STRING_LENGTH;
+ while (*In)
+ {
+ if ((In[0] == '$') && (In[1] == '$'))
+ {
+ In += 2;
+ break;
+ }
+ In++;
+ }
+ }
+
+ old_name = In;
+/* if (strlen(In) > 31 && flagseen['+'])
+ printf("%s: Symbol name truncated: %s\n",myname,In);*/
+ /*
+ * Do the case conversion
+ */
+ i = 23; /* Maximum of 23 chars */
+ while (*In && (--i >= 0))
+ {
+ Case_Hack_Bits <<= 1;
+ if (*In == '$')
+ Saw_Dollar = 1;
+ if ((destructor == 1) && (i == 21))
+ Saw_Dollar = 0;
+ switch (vms_name_mapping)
+ {
+ case 0:
+ if (isupper(*In)) {
+ *Out++ = *In++;
+ Case_Hack_Bits |= 1;
+ } else {
+ *Out++ = islower(*In) ? toupper(*In++) : *In++;
+ }
+ break;
+ case 3: *Out++ = *In++;
+ break;
+ case 2:
+ if (islower(*In)) {
+ *Out++ = *In++;
+ } else {
+ *Out++ = isupper(*In) ? tolower(*In++) : *In++;
+ }
+ break;
+ };
+ }
+ /*
+ * If we saw a dollar sign, we don't do case hacking
+ */
+ if (flagseen['h'] || Saw_Dollar)
+ Case_Hack_Bits = 0;
+
+ /*
+ * If we have more than 23 characters and everything is lowercase
+ * we can insert the full 31 characters
+ */
+ if (*In)
+ {
+ /*
+ * We have more than 23 characters
+ * If we must add the case hack, then we have truncated the str
+ */
+ pnt = Out;
+ truncate = 1;
+ if (Case_Hack_Bits == 0)
+ {
+ /*
+ * And so far they are all lower case:
+ * Check up to 8 more characters
+ * and ensure that they are lowercase
+ */
+ for (i = 0; (In[i] != 0) && (i < 8); i++)
+ if (isupper(In[i]) && !Saw_Dollar && !flagseen['h'])
+ break;
+
+ if (In[i] == 0)
+ truncate = 0;
+
+ if ((i == 8) || (In[i] == 0))
+ {
+ /*
+ * They are: Copy up to 31 characters
+ * to the output string
+ */
+ i = 8;
+ while ((--i >= 0) && (*In))
+ switch (vms_name_mapping){
+ case 0: *Out++ = islower(*In) ?
+ toupper (*In++) :
+ *In++;
+ break;
+ case 3: *Out++ = *In++;
+ break;
+ case 2: *Out++ = isupper(*In) ?
+ tolower(*In++) :
+ *In++;
+ break;
+ };
+ }
+ }
+ }
+ /*
+ * If there were any uppercase characters in the name we
+ * take on the case hacking string
+ */
+
+ /* Old behavior for regular GNU-C compiler */
+ if (!flagseen['+'])
+ truncate = 0;
+ if ((Case_Hack_Bits != 0) || (truncate == 1))
+ {
+ if (truncate == 0)
+ {
+ *Out++ = '_';
+ for (i = 0; i < 6; i++)
+ {
+ *Out++ = Hex_Table[Case_Hack_Bits & 0xf];
+ Case_Hack_Bits >>= 4;
+ }
+ *Out++ = 'X';
+ }
+ else
+ {
+ Out = pnt; /*Cut back to 23 characters maximum */
+ *Out++ = '_';
+ for (i = 0; i < 7; i++)
+ {
+ init = result & 0x01f;
+ if (init < 10)
+ *Out++ = '0' + init;
+ else
+ *Out++ = 'A' + init - 10;
+ result = result >> 5;
+ }
+ }
+ } /*Case Hack */
+ /*
+ * Done
+ */
+ *Out = 0;
+ if (truncate == 1 && flagseen['+'] && flagseen['H'])
+ printf ("%s: Symbol %s replaced by %s\n", myname, old_name, new_name);
+}
+
+
+/*
+ * Scan a symbol name for a psect attribute specification
+ */
+#define GLOBALSYMBOL_BIT 0x10000
+#define GLOBALVALUE_BIT 0x20000
+
+
+static
+VMS_Modify_Psect_Attributes (Name, Attribute_Pointer)
+ char *Name;
+ int *Attribute_Pointer;
+{
+ register int i;
+ register char *cp;
+ int Negate;
+ static struct
+ {
+ char *Name;
+ int Value;
+ } Attributes[] =
+ {
+ {"PIC", GPS_S_M_PIC},
+ {"LIB", GPS_S_M_LIB},
+ {"OVR", GPS_S_M_OVR},
+ {"REL", GPS_S_M_REL},
+ {"GBL", GPS_S_M_GBL},
+ {"SHR", GPS_S_M_SHR},
+ {"EXE", GPS_S_M_EXE},
+ {"RD", GPS_S_M_RD},
+ {"WRT", GPS_S_M_WRT},
+ {"VEC", GPS_S_M_VEC},
+ {"GLOBALSYMBOL", GLOBALSYMBOL_BIT},
+ {"GLOBALVALUE", GLOBALVALUE_BIT},
+ {0, 0}
+ };
+
+ /*
+ * Kill leading "_"
+ */
+ if (*Name == '_')
+ Name++;
+ /*
+ * Check for a PSECT attribute list
+ */
+ if (!HAS_PSECT_ATTRIBUTES (Name))
+ return; /* If not, return */
+ /*
+ * Skip the attribute list indicator
+ */
+ Name += PSECT_ATTRIBUTES_STRING_LENGTH;
+ /*
+ * Process the attributes ("_" separated, "$" terminated)
+ */
+ while (*Name != '$')
+ {
+ /*
+ * Assume not negating
+ */
+ Negate = 0;
+ /*
+ * Check for "NO"
+ */
+ if ((Name[0] == 'N') && (Name[1] == 'O'))
+ {
+ /*
+ * We are negating (and skip the NO)
+ */
+ Negate = 1;
+ Name += 2;
+ }
+ /*
+ * Find the token delimiter
+ */
+ cp = Name;
+ while (*cp && (*cp != '_') && (*cp != '$'))
+ cp++;
+ /*
+ * Look for the token in the attribute list
+ */
+ for (i = 0; Attributes[i].Name; i++)
+ {
+ /*
+ * If the strings match, set/clear the attr.
+ */
+ if (strncmp (Name, Attributes[i].Name, cp - Name) == 0)
+ {
+ /*
+ * Set or clear
+ */
+ if (Negate)
+ *Attribute_Pointer &=
+ ~Attributes[i].Value;
+ else
+ *Attribute_Pointer |=
+ Attributes[i].Value;
+ /*
+ * Done
+ */
+ break;
+ }
+ }
+ /*
+ * Now skip the attribute
+ */
+ Name = cp;
+ if (*Name == '_')
+ Name++;
+ }
+ /*
+ * Done
+ */
+ return;
+}
+
+
+/*
+ * Define a global symbol
+ */
+static
+VMS_Global_Symbol_Spec (Name, Psect_Number, Psect_Offset, Defined)
+ char *Name;
+ int Psect_Number;
+ int Psect_Offset;
+{
+ char Local[32];
+
+ /*
+ * We are writing a GSD record
+ */
+ Set_VMS_Object_File_Record (OBJ_S_C_GSD);
+ /*
+ * If the buffer is empty we must insert the GSD record type
+ */
+ if (Object_Record_Offset == 0)
+ PUT_CHAR (OBJ_S_C_GSD);
+ /*
+ * We are writing a Global symbol definition subrecord
+ */
+ if (Psect_Number <= 255)
+ {
+ PUT_CHAR (GSD_S_C_SYM);
+ }
+ else
+ {
+ PUT_CHAR (GSD_S_C_SYMW);
+ }
+ /*
+ * Data type is undefined
+ */
+ PUT_CHAR (0);
+ /*
+ * Switch on Definition/Reference
+ */
+ if ((Defined & 1) != 0)
+ {
+ /*
+ * Definition:
+ * Flags = "RELOCATABLE" and "DEFINED" for regular symbol
+ * = "DEFINED" for globalvalue (Defined & 2 == 1)
+ */
+ if ((Defined & 2) == 0)
+ {
+ PUT_SHORT (GSY_S_M_DEF | GSY_S_M_REL);
+ }
+ else
+ {
+ PUT_SHORT (GSY_S_M_DEF);
+ };
+ /*
+ * Psect Number
+ */
+ if (Psect_Number <= 255)
+ {
+ PUT_CHAR (Psect_Number);
+ }
+ else
+ {
+ PUT_SHORT (Psect_Number);
+ }
+ /*
+ * Offset
+ */
+ PUT_LONG (Psect_Offset);
+ }
+ else
+ {
+ /*
+ * Reference:
+ * Flags = "RELOCATABLE" for regular symbol,
+ * = "" for globalvalue (Defined & 2 == 1)
+ */
+ if ((Defined & 2) == 0)
+ {
+ PUT_SHORT (GSY_S_M_REL);
+ }
+ else
+ {
+ PUT_SHORT (0);
+ };
+ }
+ /*
+ * Finally, the global symbol name
+ */
+ VMS_Case_Hack_Symbol (Name, Local);
+ PUT_COUNTED_STRING (Local);
+ /*
+ * Flush the buffer if it is more than 75% full
+ */
+ if (Object_Record_Offset >
+ (sizeof (Object_Record_Buffer) * 3 / 4))
+ Flush_VMS_Object_Record_Buffer ();
+}
+
+
+/*
+ * Define a psect
+ */
+static int
+VMS_Psect_Spec (Name, Size, Type, vsp)
+ char *Name;
+ int Size;
+ char *Type;
+ struct VMS_Symbol *vsp;
+{
+ char Local[32];
+ int Psect_Attributes;
+
+ /*
+ * Generate the appropriate PSECT flags given the PSECT type
+ */
+ if (strcmp (Type, "COMMON") == 0)
+ {
+ /*
+ * Common block psects are: PIC,OVR,REL,GBL,SHR,RD,WRT
+ */
+ Psect_Attributes = (GPS_S_M_PIC | GPS_S_M_OVR | GPS_S_M_REL | GPS_S_M_GBL |
+ GPS_S_M_SHR | GPS_S_M_RD | GPS_S_M_WRT);
+ }
+ else if (strcmp (Type, "CONST") == 0)
+ {
+ /*
+ * Common block psects are: PIC,OVR,REL,GBL,SHR,RD
+ */
+ Psect_Attributes = (GPS_S_M_PIC | GPS_S_M_OVR | GPS_S_M_REL | GPS_S_M_GBL |
+ GPS_S_M_SHR | GPS_S_M_RD);
+ }
+ else if (strcmp (Type, "DATA") == 0)
+ {
+ /*
+ * The Data psects are PIC,REL,RD,WRT
+ */
+ Psect_Attributes =
+ (GPS_S_M_PIC | GPS_S_M_REL | GPS_S_M_RD | GPS_S_M_WRT);
+ }
+ else if (strcmp (Type, "TEXT") == 0)
+ {
+ /*
+ * The Text psects are PIC,REL,SHR,EXE,RD
+ */
+ Psect_Attributes =
+ (GPS_S_M_PIC | GPS_S_M_REL | GPS_S_M_SHR |
+ GPS_S_M_EXE | GPS_S_M_RD);
+ }
+ else
+ {
+ /*
+ * Error: Unknown psect type
+ */
+ error ("Unknown VMS psect type");
+ }
+ /*
+ * Modify the psect attributes according to any attribute string
+ */
+ if (HAS_PSECT_ATTRIBUTES (Name))
+ VMS_Modify_Psect_Attributes (Name, &Psect_Attributes);
+ /*
+ * Check for globalref/def/val.
+ */
+ if ((Psect_Attributes & GLOBALVALUE_BIT) != 0)
+ {
+ /*
+ * globalvalue symbols were generated before. This code
+ * prevents unsightly psect buildup, and makes sure that
+ * fixup references are emitted correctly.
+ */
+ vsp->Psect_Index = -1; /* to catch errors */
+ S_GET_RAW_TYPE (vsp->Symbol) = N_UNDF; /* make refs work */
+ return 1; /* decrement psect counter */
+ };
+
+ if ((Psect_Attributes & GLOBALSYMBOL_BIT) != 0)
+ {
+ switch (S_GET_RAW_TYPE (vsp->Symbol))
+ {
+ case N_UNDF | N_EXT:
+ VMS_Global_Symbol_Spec (Name, vsp->Psect_Index,
+ vsp->Psect_Offset, 0);
+ vsp->Psect_Index = -1;
+ S_GET_RAW_TYPE (vsp->Symbol) = N_UNDF;
+ return 1; /* return and indicate no psect */
+ case N_DATA | N_EXT:
+ VMS_Global_Symbol_Spec (Name, vsp->Psect_Index,
+ vsp->Psect_Offset, 1);
+ /* In this case we still generate the psect */
+ break;
+ default:
+ {
+ char Error_Line[256];
+ sprintf (Error_Line, "Globalsymbol attribute for"
+ " symbol %s was unexpected.\n", Name);
+ error (Error_Line);
+ break;
+ };
+ }; /* switch */
+ };
+
+ Psect_Attributes &= 0xffff; /* clear out the globalref/def stuff */
+ /*
+ * We are writing a GSD record
+ */
+ Set_VMS_Object_File_Record (OBJ_S_C_GSD);
+ /*
+ * If the buffer is empty we must insert the GSD record type
+ */
+ if (Object_Record_Offset == 0)
+ PUT_CHAR (OBJ_S_C_GSD);
+ /*
+ * We are writing a PSECT definition subrecord
+ */
+ PUT_CHAR (GSD_S_C_PSC);
+ /*
+ * Psects are always LONGWORD aligned
+ */
+ PUT_CHAR (2);
+ /*
+ * Specify the psect attributes
+ */
+ PUT_SHORT (Psect_Attributes);
+ /*
+ * Specify the allocation
+ */
+ PUT_LONG (Size);
+ /*
+ * Finally, the psect name
+ */
+ VMS_Case_Hack_Symbol (Name, Local);
+ PUT_COUNTED_STRING (Local);
+ /*
+ * Flush the buffer if it is more than 75% full
+ */
+ if (Object_Record_Offset >
+ (sizeof (Object_Record_Buffer) * 3 / 4))
+ Flush_VMS_Object_Record_Buffer ();
+ return 0;
+}
+
+
+/*
+ * Given the pointer to a symbol we calculate how big the data at the
+ * symbol is. We do this by looking for the next symbol (local or
+ * global) which will indicate the start of another datum.
+ */
+static int
+VMS_Initialized_Data_Size (sp, End_Of_Data)
+ register struct symbol *sp;
+ int End_Of_Data;
+{
+ register struct symbol *sp1, *Next_Symbol;
+
+ /*
+ * Find the next symbol
+ * it delimits this datum
+ */
+ Next_Symbol = 0;
+ for (sp1 = symbol_rootP; sp1; sp1 = symbol_next (sp1))
+ {
+ /*
+ * The data type must match
+ */
+ if (S_GET_TYPE (sp1) != N_DATA)
+ continue;
+ /*
+ * The symbol must be AFTER this symbol
+ */
+ if (S_GET_VALUE (sp1) <= S_GET_VALUE (sp))
+ continue;
+ /*
+ * We ignore THIS symbol
+ */
+ if (sp1 == sp)
+ continue;
+ /*
+ * If there is already a candidate selected for the
+ * next symbol, see if we are a better candidate
+ */
+ if (Next_Symbol)
+ {
+ /*
+ * We are a better candidate if we are "closer"
+ * to the symbol
+ */
+ if (S_GET_VALUE (sp1) >
+ S_GET_VALUE (Next_Symbol))
+ continue;
+ /*
+ * Win: Make this the candidate
+ */
+ Next_Symbol = sp1;
+ }
+ else
+ {
+ /*
+ * This is the 1st candidate
+ */
+ Next_Symbol = sp1;
+ }
+ }
+ /*
+ * Calculate its size
+ */
+ return (Next_Symbol ?
+ (S_GET_VALUE (Next_Symbol) -
+ S_GET_VALUE (sp)) :
+ (End_Of_Data - S_GET_VALUE (sp)));
+}
+
+/*
+ * Check symbol names for the Psect hack with a globalvalue, and then
+ * generate globalvalues for those that have it.
+ */
+static
+VMS_Emit_Globalvalues (text_siz, data_siz, Data_Segment)
+ unsigned text_siz;
+ unsigned data_siz;
+ char *Data_Segment;
+{
+ register symbolS *sp;
+ char *stripped_name, *Name;
+ int Size;
+ int Psect_Attributes;
+ int globalvalue;
+
+ /*
+ * Scan the symbol table for globalvalues, and emit def/ref when
+ * required. These will be caught again later and converted to
+ * N_UNDF
+ */
+ for (sp = symbol_rootP; sp; sp = sp->sy_next)
+ {
+ /*
+ * See if this is something we want to look at.
+ */
+ if ((S_GET_RAW_TYPE (sp) != (N_DATA | N_EXT)) &&
+ (S_GET_RAW_TYPE (sp) != (N_UNDF | N_EXT)))
+ continue;
+ /*
+ * See if this has globalvalue specification.
+ */
+ Name = S_GET_NAME (sp);
+
+ if (!HAS_PSECT_ATTRIBUTES (Name))
+ continue;
+
+ stripped_name = (char *) malloc (strlen (Name) + 1);
+ strcpy (stripped_name, Name);
+ Psect_Attributes = 0;
+ VMS_Modify_Psect_Attributes (stripped_name, &Psect_Attributes);
+
+ if ((Psect_Attributes & GLOBALVALUE_BIT) != 0)
+ {
+ switch (S_GET_RAW_TYPE (sp))
+ {
+ case N_UNDF | N_EXT:
+ VMS_Global_Symbol_Spec (stripped_name, 0, 0, 2);
+ break;
+ case N_DATA | N_EXT:
+ Size = VMS_Initialized_Data_Size (sp, text_siz + data_siz);
+ if (Size > 4)
+ error ("Invalid data type for globalvalue");
+ globalvalue = 0;
+
+ memcpy (&globalvalue, Data_Segment + S_GET_VALUE (sp) -
+ text_siz, Size);
+ /* Three times for good luck. The linker seems to get confused
+ if there are fewer than three */
+ VMS_Global_Symbol_Spec (stripped_name, 0, 0, 2);
+ VMS_Global_Symbol_Spec (stripped_name, 0, globalvalue, 3);
+ VMS_Global_Symbol_Spec (stripped_name, 0, globalvalue, 3);
+ break;
+ default:
+ printf (" Invalid globalvalue of %s\n", stripped_name);
+ break;
+ }; /* switch */
+ }; /* if */
+ free (stripped_name); /* clean up */
+ }; /* for */
+
+}
+
+
+/*
+ * Define a procedure entry pt/mask
+ */
+static
+VMS_Procedure_Entry_Pt (Name, Psect_Number, Psect_Offset, Entry_Mask)
+ char *Name;
+ int Psect_Number;
+ int Psect_Offset;
+ int Entry_Mask;
+{
+ char Local[32];
+
+ /*
+ * We are writing a GSD record
+ */
+ Set_VMS_Object_File_Record (OBJ_S_C_GSD);
+ /*
+ * If the buffer is empty we must insert the GSD record type
+ */
+ if (Object_Record_Offset == 0)
+ PUT_CHAR (OBJ_S_C_GSD);
+ /*
+ * We are writing a Procedure Entry Pt/Mask subrecord
+ */
+ if (Psect_Number <= 255)
+ {
+ PUT_CHAR (GSD_S_C_EPM);
+ }
+ else
+ {
+ PUT_CHAR (GSD_S_C_EPMW);
+ }
+ /*
+ * Data type is undefined
+ */
+ PUT_CHAR (0);
+ /*
+ * Flags = "RELOCATABLE" and "DEFINED"
+ */
+ PUT_SHORT (GSY_S_M_DEF | GSY_S_M_REL);
+ /*
+ * Psect Number
+ */
+ if (Psect_Number <= 255)
+ {
+ PUT_CHAR (Psect_Number);
+ }
+ else
+ {
+ PUT_SHORT (Psect_Number);
+ }
+ /*
+ * Offset
+ */
+ PUT_LONG (Psect_Offset);
+ /*
+ * Entry mask
+ */
+ PUT_SHORT (Entry_Mask);
+ /*
+ * Finally, the global symbol name
+ */
+ VMS_Case_Hack_Symbol (Name, Local);
+ PUT_COUNTED_STRING (Local);
+ /*
+ * Flush the buffer if it is more than 75% full
+ */
+ if (Object_Record_Offset >
+ (sizeof (Object_Record_Buffer) * 3 / 4))
+ Flush_VMS_Object_Record_Buffer ();
+}
+
+
+/*
+ * Set the current location counter to a particular Psect and Offset
+ */
+static
+VMS_Set_Psect (Psect_Index, Offset, Record_Type)
+ int Psect_Index;
+ int Offset;
+ int Record_Type;
+{
+ /*
+ * We are writing a "Record_Type" record
+ */
+ Set_VMS_Object_File_Record (Record_Type);
+ /*
+ * If the buffer is empty we must insert the record type
+ */
+ if (Object_Record_Offset == 0)
+ PUT_CHAR (Record_Type);
+ /*
+ * Stack the Psect base + Longword Offset
+ */
+ if (Psect_Index < 255)
+ {
+ PUT_CHAR (TIR_S_C_STA_PL);
+ PUT_CHAR (Psect_Index);
+ }
+ else
+ {
+ PUT_CHAR (TIR_S_C_STA_WPL);
+ PUT_SHORT (Psect_Index);
+ }
+ PUT_LONG (Offset);
+ /*
+ * Set relocation base
+ */
+ PUT_CHAR (TIR_S_C_CTL_SETRB);
+ /*
+ * Flush the buffer if it is more than 75% full
+ */
+ if (Object_Record_Offset >
+ (sizeof (Object_Record_Buffer) * 3 / 4))
+ Flush_VMS_Object_Record_Buffer ();
+}
+
+
+/*
+ * Store repeated immediate data in current Psect
+ */
+static
+VMS_Store_Repeated_Data (Repeat_Count, Pointer, Size, Record_Type)
+ int Repeat_Count;
+ register char *Pointer;
+ int Size;
+ int Record_Type;
+{
+
+ /*
+ * Ignore zero bytes/words/longwords
+ */
+ if ((Size == sizeof (char)) && (*Pointer == 0))
+ return;
+ if ((Size == sizeof (short)) && (*(short *) Pointer == 0))
+ return;
+ if ((Size == sizeof (long)) && (*(long *) Pointer == 0))
+ return;
+ /*
+ * If the data is too big for a TIR_S_C_STO_RIVB sub-record
+ * then we do it manually
+ */
+ if (Size > 255)
+ {
+ while (--Repeat_Count >= 0)
+ VMS_Store_Immediate_Data (Pointer, Size, Record_Type);
+ return;
+ }
+ /*
+ * We are writing a "Record_Type" record
+ */
+ Set_VMS_Object_File_Record (Record_Type);
+ /*
+ * If the buffer is empty we must insert record type
+ */
+ if (Object_Record_Offset == 0)
+ PUT_CHAR (Record_Type);
+ /*
+ * Stack the repeat count
+ */
+ PUT_CHAR (TIR_S_C_STA_LW);
+ PUT_LONG (Repeat_Count);
+ /*
+ * And now the command and its data
+ */
+ PUT_CHAR (TIR_S_C_STO_RIVB);
+ PUT_CHAR (Size);
+ while (--Size >= 0)
+ PUT_CHAR (*Pointer++);
+ /*
+ * Flush the buffer if it is more than 75% full
+ */
+ if (Object_Record_Offset >
+ (sizeof (Object_Record_Buffer) * 3 / 4))
+ Flush_VMS_Object_Record_Buffer ();
+}
+
+
+/*
+ * Store a Position Independent Reference
+ */
+static
+VMS_Store_PIC_Symbol_Reference (Symbol, Offset, PC_Relative,
+ Psect, Psect_Offset, Record_Type)
+ struct symbol *Symbol;
+ int Offset;
+ int PC_Relative;
+ int Psect;
+ int Psect_Offset;
+ int Record_Type;
+{
+ register struct VMS_Symbol *vsp =
+ (struct VMS_Symbol *) (Symbol->sy_number);
+ char Local[32];
+
+ /*
+ * We are writing a "Record_Type" record
+ */
+ Set_VMS_Object_File_Record (Record_Type);
+ /*
+ * If the buffer is empty we must insert record type
+ */
+ if (Object_Record_Offset == 0)
+ PUT_CHAR (Record_Type);
+ /*
+ * Set to the appropriate offset in the Psect
+ */
+ if (PC_Relative)
+ {
+ /*
+ * For a Code reference we need to fix the operand
+ * specifier as well (so back up 1 byte)
+ */
+ VMS_Set_Psect (Psect, Psect_Offset - 1, Record_Type);
+ }
+ else
+ {
+ /*
+ * For a Data reference we just store HERE
+ */
+ VMS_Set_Psect (Psect, Psect_Offset, Record_Type);
+ }
+ /*
+ * Make sure we are still generating a "Record Type" record
+ */
+ if (Object_Record_Offset == 0)
+ PUT_CHAR (Record_Type);
+ /*
+ * Dispatch on symbol type (so we can stack its value)
+ */
+ switch (S_GET_RAW_TYPE (Symbol))
+ {
+ /*
+ * Global symbol
+ */
+#ifdef NOT_VAX_11_C_COMPATIBLE
+ case N_UNDF | N_EXT:
+ case N_DATA | N_EXT:
+#endif /* NOT_VAX_11_C_COMPATIBLE */
+ case N_UNDF:
+ case N_TEXT | N_EXT:
+ /*
+ * Get the symbol name (case hacked)
+ */
+ VMS_Case_Hack_Symbol (S_GET_NAME (Symbol), Local);
+ /*
+ * Stack the global symbol value
+ */
+ PUT_CHAR (TIR_S_C_STA_GBL);
+ PUT_COUNTED_STRING (Local);
+ if (Offset)
+ {
+ /*
+ * Stack the longword offset
+ */
+ PUT_CHAR (TIR_S_C_STA_LW);
+ PUT_LONG (Offset);
+ /*
+ * Add the two, leaving the result on the stack
+ */
+ PUT_CHAR (TIR_S_C_OPR_ADD);
+ }
+ break;
+ /*
+ * Uninitialized local data
+ */
+ case N_BSS:
+ /*
+ * Stack the Psect (+offset)
+ */
+ if (vsp->Psect_Index < 255)
+ {
+ PUT_CHAR (TIR_S_C_STA_PL);
+ PUT_CHAR (vsp->Psect_Index);
+ }
+ else
+ {
+ PUT_CHAR (TIR_S_C_STA_WPL);
+ PUT_SHORT (vsp->Psect_Index);
+ }
+ PUT_LONG (vsp->Psect_Offset + Offset);
+ break;
+ /*
+ * Local text
+ */
+ case N_TEXT:
+ /*
+ * Stack the Psect (+offset)
+ */
+ if (vsp->Psect_Index < 255)
+ {
+ PUT_CHAR (TIR_S_C_STA_PL);
+ PUT_CHAR (vsp->Psect_Index);
+ }
+ else
+ {
+ PUT_CHAR (TIR_S_C_STA_WPL);
+ PUT_SHORT (vsp->Psect_Index);
+ }
+ PUT_LONG (S_GET_VALUE (Symbol) + Offset);
+ break;
+ /*
+ * Initialized local or global data
+ */
+ case N_DATA:
+#ifndef NOT_VAX_11_C_COMPATIBLE
+ case N_UNDF | N_EXT:
+ case N_DATA | N_EXT:
+#endif /* NOT_VAX_11_C_COMPATIBLE */
+ /*
+ * Stack the Psect (+offset)
+ */
+ if (vsp->Psect_Index < 255)
+ {
+ PUT_CHAR (TIR_S_C_STA_PL);
+ PUT_CHAR (vsp->Psect_Index);
+ }
+ else
+ {
+ PUT_CHAR (TIR_S_C_STA_WPL);
+ PUT_SHORT (vsp->Psect_Index);
+ }
+ PUT_LONG (vsp->Psect_Offset + Offset);
+ break;
+ }
+ /*
+ * Store either a code or data reference
+ */
+ PUT_CHAR (PC_Relative ? TIR_S_C_STO_PICR : TIR_S_C_STO_PIDR);
+ /*
+ * Flush the buffer if it is more than 75% full
+ */
+ if (Object_Record_Offset >
+ (sizeof (Object_Record_Buffer) * 3 / 4))
+ Flush_VMS_Object_Record_Buffer ();
+}
+
+
+/*
+ * Check in the text area for an indirect pc-relative reference
+ * and fix it up with addressing mode 0xff [PC indirect]
+ *
+ * THIS SHOULD BE REPLACED BY THE USE OF TIR_S_C_STO_PIRR IN THE
+ * PIC CODE GENERATING FIXUP ROUTINE.
+ */
+static
+VMS_Fix_Indirect_Reference (Text_Psect, Offset, fragP, text_frag_root)
+ int Text_Psect;
+ int Offset;
+ register fragS *fragP;
+ struct frag *text_frag_root;
+{
+ /*
+ * The addressing mode byte is 1 byte before the address
+ */
+ Offset--;
+ /*
+ * Is it in THIS frag??
+ */
+ if ((Offset < fragP->fr_address) ||
+ (Offset >= (fragP->fr_address + fragP->fr_fix)))
+ {
+ /*
+ * We need to search for the fragment containing this
+ * Offset
+ */
+ for (fragP = text_frag_root; fragP; fragP = fragP->fr_next)
+ {
+ if ((Offset >= fragP->fr_address) &&
+ (Offset < (fragP->fr_address + fragP->fr_fix)))
+ break;
+ }
+ /*
+ * If we couldn't find the frag, things are BAD!!
+ */
+ if (fragP == 0)
+ error ("Couldn't find fixup fragment when checking for indirect reference");
+ }
+ /*
+ * Check for indirect PC relative addressing mode
+ */
+ if (fragP->fr_literal[Offset - fragP->fr_address] == (char) 0xff)
+ {
+ static char Address_Mode = 0xff;
+
+ /*
+ * Yes: Store the indirect mode back into the image
+ * to fix up the damage done by STO_PICR
+ */
+ VMS_Set_Psect (Text_Psect, Offset, OBJ_S_C_TIR);
+ VMS_Store_Immediate_Data (&Address_Mode, 1, OBJ_S_C_TIR);
+ }
+}
+
+
+
+/*
+ * This is a hacked _doprnt() for VAX-11 "C". It understands that
+ * it is ONLY called by as_fatal(Format, Args) with a pointer to the
+ * "Args" argument. From this we can make it all work right!
+ */
+#if !defined(eunice) && defined(HO_VMS)
+_doprnt (Format, a, f)
+ char *Format;
+ FILE *f;
+ char **a;
+{
+ int Nargs = ((int *) a)[-2]; /* This understands as_fatal() */
+
+ switch (Nargs)
+ {
+ default:
+ fprintf (f, "_doprnt error on \"%s\"!!", Format);
+ break;
+ case 1:
+ fprintf (f, Format);
+ break;
+ case 2:
+ fprintf (f, Format, a[0]);
+ break;
+ case 3:
+ fprintf (f, Format, a[0], a[1]);
+ break;
+ case 4:
+ fprintf (f, Format, a[0], a[1], a[2]);
+ break;
+ case 5:
+ fprintf (f, Format, a[0], a[1], a[2], a[3]);
+ break;
+ case 6:
+ fprintf (f, Format, a[0], a[1], a[2], a[3], a[4]);
+ break;
+ case 7:
+ fprintf (f, Format, a[0], a[1], a[2], a[3], a[4], a[5]);
+ break;
+ case 8:
+ fprintf (f, Format, a[0], a[1], a[2], a[3], a[4], a[5], a[6]);
+ break;
+ case 9:
+ fprintf (f, Format, a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7]);
+ break;
+ case 10:
+ fprintf (f, Format, a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8]);
+ break;
+ }
+}
+
+#endif /* eunice */
+
+
+/*
+ * If the procedure "main()" exists we have to add the instruction
+ * "jsb c$main_args" at the beginning to be compatible with VAX-11 "C".
+ */
+VMS_Check_For_Main ()
+{
+ register symbolS *symbolP;
+#ifdef HACK_DEC_C_STARTUP /* JF */
+ register struct frchain *frchainP;
+ register fragS *fragP;
+ register fragS **prev_fragPP;
+ register struct fix *fixP;
+ register fragS *New_Frag;
+ int i;
+#endif /* HACK_DEC_C_STARTUP */
+
+ symbolP = (struct symbol *) symbol_find ("_main");
+ if (symbolP && !S_IS_DEBUG (symbolP) &&
+ S_IS_EXTERNAL (symbolP) && (S_GET_TYPE (symbolP) == N_TEXT))
+ {
+#ifdef HACK_DEC_C_STARTUP
+ if (!flagseen['+'])
+ {
+#endif
+ /*
+ * Remember the entry point symbol
+ */
+ Entry_Point_Symbol = symbolP;
+#ifdef HACK_DEC_C_STARTUP
+ }
+ else
+ {
+ /*
+ * Scan all the fragment chains for the one with "_main"
+ * (Actually we know the fragment from the symbol, but we need
+ * the previous fragment so we can change its pointer)
+ */
+ frchainP = frchain_root;
+ while (frchainP)
+ {
+ /*
+ * Scan all the fragments in this chain, remembering
+ * the "previous fragment"
+ */
+ prev_fragPP = &frchainP->frch_root;
+ fragP = frchainP->frch_root;
+ while (fragP && (fragP != frchainP->frch_last))
+ {
+ /*
+ * Is this the fragment?
+ */
+ if (fragP == symbolP->sy_frag)
+ {
+ /*
+ * Yes: Modify the fragment by replacing
+ * it with a new fragment.
+ */
+ New_Frag = (fragS *)
+ xmalloc (sizeof (*New_Frag) +
+ fragP->fr_fix +
+ fragP->fr_var +
+ 5);
+ /*
+ * The fragments are the same except
+ * that the "fixed" area is larger
+ */
+ *New_Frag = *fragP;
+ New_Frag->fr_fix += 6;
+ /*
+ * Copy the literal data opening a hole
+ * 2 bytes after "_main" (i.e. just after
+ * the entry mask). Into which we place
+ * the JSB instruction.
+ */
+ New_Frag->fr_literal[0] = fragP->fr_literal[0];
+ New_Frag->fr_literal[1] = fragP->fr_literal[1];
+ New_Frag->fr_literal[2] = 0x16; /* Jsb */
+ New_Frag->fr_literal[3] = 0xef;
+ New_Frag->fr_literal[4] = 0;
+ New_Frag->fr_literal[5] = 0;
+ New_Frag->fr_literal[6] = 0;
+ New_Frag->fr_literal[7] = 0;
+ for (i = 2; i < fragP->fr_fix + fragP->fr_var; i++)
+ New_Frag->fr_literal[i + 6] =
+ fragP->fr_literal[i];
+ /*
+ * Now replace the old fragment with the
+ * newly generated one.
+ */
+ *prev_fragPP = New_Frag;
+ /*
+ * Remember the entry point symbol
+ */
+ Entry_Point_Symbol = symbolP;
+ /*
+ * Scan the text area fixup structures
+ * as offsets in the fragment may have
+ * changed
+ */
+ for (fixP = text_fix_root; fixP; fixP = fixP->fx_next)
+ {
+ /*
+ * Look for references to this
+ * fragment.
+ */
+ if (fixP->fx_frag == fragP)
+ {
+ /*
+ * Change the fragment
+ * pointer
+ */
+ fixP->fx_frag = New_Frag;
+ /*
+ * If the offset is after
+ * the entry mask we need
+ * to account for the JSB
+ * instruction we just
+ * inserted.
+ */
+ if (fixP->fx_where >= 2)
+ fixP->fx_where += 6;
+ }
+ }
+ /*
+ * Scan the symbols as offsets in the
+ * fragment may have changed
+ */
+ for (symbolP = symbol_rootP;
+ symbolP;
+ symbolP = symbol_next (symbolP))
+ {
+ /*
+ * Look for references to this
+ * fragment.
+ */
+ if (symbolP->sy_frag == fragP)
+ {
+ /*
+ * Change the fragment
+ * pointer
+ */
+ symbolP->sy_frag = New_Frag;
+ /*
+ * If the offset is after
+ * the entry mask we need
+ * to account for the JSB
+ * instruction we just
+ * inserted.
+ */
+ if (S_GET_VALUE (symbolP) >= 2)
+ S_GET_VALUE (symbolP) += 6;
+ }
+ }
+ /*
+ * Make a symbol reference to
+ * "_c$main_args" so we can get
+ * its address inserted into the
+ * JSB instruction.
+ */
+ symbolP = (symbolS *) xmalloc (sizeof (*symbolP));
+ S_GET_NAME (symbolP) = "_c$main_args";
+ S_SET_TYPE (symbolP, N_UNDF);
+ S_GET_OTHER (symbolP) = 0;
+ S_GET_DESC (symbolP) = 0;
+ S_GET_VALUE (symbolP) = 0;
+ symbolP->sy_name_offset = 0;
+ symbolP->sy_number = 0;
+ symbolP->sy_frag = New_Frag;
+ symbolP->sy_forward = 0;
+ /* this actually inserts at the beginning of the list */
+ symbol_append (symbol_rootP, symbolP, &symbol_rootP, &symbol_lastP);
+
+ symbol_rootP = symbolP;
+ /*
+ * Generate a text fixup structure
+ * to get "_c$main_args" stored into the
+ * JSB instruction.
+ */
+ fixP = (struct fix *) xmalloc (sizeof (*fixP));
+ fixP->fx_frag = New_Frag;
+ fixP->fx_where = 4;
+ fixP->fx_addsy = symbolP;
+ fixP->fx_subsy = 0;
+ fixP->fx_offset = 0;
+ fixP->fx_size = sizeof (long);
+ fixP->fx_pcrel = 1;
+ fixP->fx_next = text_fix_root;
+ text_fix_root = fixP;
+ /*
+ * Now make sure we exit from the loop
+ */
+ frchainP = 0;
+ break;
+ }
+ /*
+ * Try the next fragment
+ */
+ prev_fragPP = &fragP->fr_next;
+ fragP = fragP->fr_next;
+ }
+ /*
+ * Try the next fragment chain
+ */
+ if (frchainP)
+ frchainP = frchainP->frch_next;
+ }
+ }
+#endif /* HACK_DEC_C_STARTUP */
+ }
+}
+
+/*
+ * Write a VAX/VMS object file (everything else has been done!)
+ */
+VMS_write_object_file (text_siz, data_siz, text_frag_root, data_frag_root)
+ unsigned text_siz;
+ unsigned data_siz;
+ struct frag *text_frag_root;
+ struct frag *data_frag_root;
+{
+ register fragS *fragP;
+ register symbolS *symbolP;
+ register symbolS *sp;
+ register struct fix *fixP;
+ register struct VMS_Symbol *vsp;
+ char *Data_Segment;
+ int Local_Initialized_Data_Size = 0;
+ int Globalref;
+ int Psect_Number = 0; /* Psect Index Number */
+ int Text_Psect = -1; /* Text Psect Index */
+ int Data_Psect = -2; /* Data Psect Index JF: Was -1 */
+ int Bss_Psect = -3; /* Bss Psect Index JF: Was -1 */
+
+ /*
+ * Create the VMS object file
+ */
+ Create_VMS_Object_File ();
+ /*
+ * Write the module header records
+ */
+ Write_VMS_MHD_Records ();
+
+ /*
+ * Store the Data segment:
+ *
+ * Since this is REALLY hard to do any other way,
+ * we actually manufacture the data segment and
+ * the store the appropriate values out of it.
+ * We need to generate this early, so that globalvalues
+ * can be properly emitted.
+ */
+ if (data_siz > 0)
+ {
+ /*
+ * Allocate the data segment
+ */
+ Data_Segment = (char *) xmalloc (data_siz);
+ /*
+ * Run through the data fragments, filling in the segment
+ */
+ for (fragP = data_frag_root; fragP; fragP = fragP->fr_next)
+ {
+ register long int count;
+ register char *fill_literal;
+ register long int fill_size;
+ int i;
+
+ i = fragP->fr_address - text_siz;
+ if (fragP->fr_fix)
+ memcpy (Data_Segment + i,
+ fragP->fr_literal,
+ fragP->fr_fix);
+ i += fragP->fr_fix;
+
+ fill_literal = fragP->fr_literal + fragP->fr_fix;
+ fill_size = fragP->fr_var;
+ for (count = fragP->fr_offset; count; count--)
+ {
+ if (fill_size)
+ memcpy (Data_Segment + i, fill_literal, fill_size);
+ i += fill_size;
+ }
+ }
+ }
+
+
+ /*
+ * Generate the VMS object file records
+ * 1st GSD then TIR records
+ */
+
+ /******* Global Symbol Dictionary *******/
+ /*
+ * Emit globalvalues now. We must do this before the text psect
+ * is defined, or we will get linker warnings about multiply defined
+ * symbols. All of the globalvalues "reference" psect 0, although
+ * it really does not have anything to do with it.
+ */
+ VMS_Emit_Globalvalues (text_siz, data_siz, Data_Segment);
+ /*
+ * Define the Text Psect
+ */
+ Text_Psect = Psect_Number++;
+ VMS_Psect_Spec ("$code", text_siz, "TEXT", 0);
+ /*
+ * Define the BSS Psect
+ */
+ if (local_bss_counter > 0)
+ {
+ Bss_Psect = Psect_Number++;
+ VMS_Psect_Spec ("$uninitialized_data", local_bss_counter, "DATA",
+ 0);
+ }
+#ifndef gxx_bug_fixed
+ /*
+ * The g++ compiler does not write out external references to vtables
+ * correctly. Check for this and holler if we see it happening.
+ * If that compiler bug is ever fixed we can remove this.
+ */
+ for (sp = symbol_rootP; sp; sp = symbol_next (sp))
+ {
+ /*
+ * Dispatch on symbol type
+ */
+ switch (S_GET_RAW_TYPE (sp)) {
+ /*
+ * Global Reference
+ */
+ case N_UNDF:
+ /*
+ * Make a GSD global symbol reference
+ * record.
+ */
+ if (strncmp (S_GET_NAME (sp),"__vt.",5) == 0)
+ {
+ S_GET_RAW_TYPE (sp) = N_UNDF | N_EXT;
+ as_warn("g++ wrote an extern reference to %s as a routine.",
+ S_GET_NAME (sp));
+ as_warn("I will fix it, but I hope that it was not really a routine");
+ };
+ break;
+ default:
+ break;
+ }
+ }
+#endif /* gxx_bug_fixed */
+ /*
+ * Now scan the symbols and emit the appropriate GSD records
+ */
+ for (sp = symbol_rootP; sp; sp = symbol_next (sp))
+ {
+ /*
+ * Dispatch on symbol type
+ */
+ switch (S_GET_RAW_TYPE (sp))
+ {
+ /*
+ * Global uninitialized data
+ */
+ case N_UNDF | N_EXT:
+ /*
+ * Make a VMS data symbol entry
+ */
+ vsp = (struct VMS_Symbol *)
+ xmalloc (sizeof (*vsp));
+ vsp->Symbol = sp;
+ vsp->Size = S_GET_VALUE (sp);
+ vsp->Psect_Index = Psect_Number++;
+ vsp->Psect_Offset = 0;
+ vsp->Next = VMS_Symbols;
+ VMS_Symbols = vsp;
+ sp->sy_number = (int) vsp;
+ /*
+ * Make the psect for this data
+ */
+ if (S_GET_OTHER (sp))
+ Globalref = VMS_Psect_Spec (
+ S_GET_NAME (sp),
+ vsp->Size,
+ "CONST",
+ vsp);
+ else
+ Globalref = VMS_Psect_Spec (
+ S_GET_NAME (sp),
+ vsp->Size,
+ "COMMON",
+ vsp);
+ if (Globalref)
+ Psect_Number--;
+#ifdef NOT_VAX_11_C_COMPATIBLE
+ /*
+ * Place a global symbol at the
+ * beginning of the Psect
+ */
+ VMS_Global_Symbol_Spec (S_GET_NAME (sp),
+ vsp->Psect_Index,
+ 0,
+ 1);
+#endif /* NOT_VAX_11_C_COMPATIBLE */
+ break;
+ /*
+ * Local uninitialized data
+ */
+ case N_BSS:
+ /*
+ * Make a VMS data symbol entry
+ */
+ vsp = (struct VMS_Symbol *)
+ xmalloc (sizeof (*vsp));
+ vsp->Symbol = sp;
+ vsp->Size = 0;
+ vsp->Psect_Index = Bss_Psect;
+ vsp->Psect_Offset =
+ S_GET_VALUE (sp) -
+ bss_address_frag.fr_address;
+ vsp->Next = VMS_Symbols;
+ VMS_Symbols = vsp;
+ sp->sy_number = (int) vsp;
+ break;
+ /*
+ * Global initialized data
+ */
+ case N_DATA | N_EXT:
+ /*
+ * Make a VMS data symbol entry
+ */
+ vsp = (struct VMS_Symbol *)
+ xmalloc (sizeof (*vsp));
+ vsp->Symbol = sp;
+ vsp->Size = VMS_Initialized_Data_Size (sp,
+ text_siz + data_siz);
+ vsp->Psect_Index = Psect_Number++;
+ vsp->Psect_Offset = 0;
+ vsp->Next = VMS_Symbols;
+ VMS_Symbols = vsp;
+ sp->sy_number = (int) vsp;
+ /*
+ * Make its psect
+ */
+ if (S_GET_OTHER (sp))
+ Globalref = VMS_Psect_Spec (
+ S_GET_NAME (sp),
+ vsp->Size,
+ "CONST",
+ vsp);
+ else
+ Globalref = VMS_Psect_Spec (
+ S_GET_NAME (sp),
+ vsp->Size,
+ "COMMON",
+ vsp);
+ if (Globalref)
+ Psect_Number--;
+#ifdef NOT_VAX_11_C_COMPATIBLE
+ /*
+ * Place a global symbol at the
+ * beginning of the Psect
+ */
+ VMS_Global_Symbol_Spec (S_GET_NAME (sp),
+ vsp->Psect_Index,
+ 0,
+ 1);
+#endif /* NOT_VAX_11_C_COMPATIBLE */
+ break;
+ /*
+ * Local initialized data
+ */
+ case N_DATA:
+ /*
+ * Make a VMS data symbol entry
+ */
+ vsp = (struct VMS_Symbol *)
+ xmalloc (sizeof (*vsp));
+ vsp->Symbol = sp;
+ vsp->Size =
+ VMS_Initialized_Data_Size (sp,
+ text_siz + data_siz);
+ vsp->Psect_Index = Data_Psect;
+ vsp->Psect_Offset =
+ Local_Initialized_Data_Size;
+ Local_Initialized_Data_Size += vsp->Size;
+ vsp->Next = VMS_Symbols;
+ VMS_Symbols = vsp;
+ sp->sy_number = (int) vsp;
+ break;
+ /*
+ * Global Text definition
+ */
+ case N_TEXT | N_EXT:
+ {
+ unsigned short Entry_Mask;
+
+ /*
+ * Get the entry mask
+ */
+ fragP = sp->sy_frag;
+ Entry_Mask = (fragP->fr_literal[0] & 0xff) +
+ ((fragP->fr_literal[1] & 0xff)
+ << 8);
+ /*
+ * Define the Procedure entry pt.
+ */
+ VMS_Procedure_Entry_Pt (S_GET_NAME (sp),
+ Text_Psect,
+ S_GET_VALUE (sp),
+ Entry_Mask);
+ break;
+ }
+ /*
+ * Local Text definition
+ */
+ case N_TEXT:
+ /*
+ * Make a VMS data symbol entry
+ */
+ if (Text_Psect != -1)
+ {
+ vsp = (struct VMS_Symbol *)
+ xmalloc (sizeof (*vsp));
+ vsp->Symbol = sp;
+ vsp->Size = 0;
+ vsp->Psect_Index = Text_Psect;
+ vsp->Psect_Offset = S_GET_VALUE (sp);
+ vsp->Next = VMS_Symbols;
+ VMS_Symbols = vsp;
+ sp->sy_number = (int) vsp;
+ }
+ break;
+ /*
+ * Global Reference
+ */
+ case N_UNDF:
+ /*
+ * Make a GSD global symbol reference
+ * record.
+ */
+ VMS_Global_Symbol_Spec (S_GET_NAME (sp),
+ 0,
+ 0,
+ 0);
+ break;
+ /*
+ * Anything else
+ */
+ default:
+ /*
+ * Ignore STAB symbols
+ * Including .stabs emitted by g++
+ */
+ if (S_IS_DEBUG (sp) || (S_GET_TYPE (sp) == 22))
+ break;
+ /*
+ * Error
+ */
+ if (S_GET_TYPE (sp) != 22)
+ printf (" ERROR, unknown type (%d)\n",
+ S_GET_TYPE (sp));
+ break;
+ }
+ }
+ /*
+ * Define the Data Psect
+ */
+ if ((data_siz > 0) && (Local_Initialized_Data_Size > 0))
+ {
+ /*
+ * Do it
+ */
+ Data_Psect = Psect_Number++;
+ VMS_Psect_Spec ("$data",
+ Local_Initialized_Data_Size,
+ "DATA", 0);
+ /*
+ * Scan the VMS symbols and fill in the data psect
+ */
+ for (vsp = VMS_Symbols; vsp; vsp = vsp->Next)
+ {
+ /*
+ * Only look for undefined psects
+ */
+ if (vsp->Psect_Index < 0)
+ {
+ /*
+ * And only initialized data
+ */
+ if ((S_GET_TYPE (vsp->Symbol) == N_DATA) && !S_IS_EXTERNAL (vsp->Symbol))
+ vsp->Psect_Index = Data_Psect;
+ }
+ }
+ }
+
+ /******* Text Information and Relocation Records *******/
+ /*
+ * Write the text segment data
+ */
+ if (text_siz > 0)
+ {
+ /*
+ * Scan the text fragments
+ */
+ for (fragP = text_frag_root; fragP; fragP = fragP->fr_next)
+ {
+ /*
+ * Stop if we get to the data fragments
+ */
+ if (fragP == data_frag_root)
+ break;
+ /*
+ * Ignore fragments with no data
+ */
+ if ((fragP->fr_fix == 0) && (fragP->fr_var == 0))
+ continue;
+ /*
+ * Go the the appropriate offset in the
+ * Text Psect.
+ */
+ VMS_Set_Psect (Text_Psect, fragP->fr_address, OBJ_S_C_TIR);
+ /*
+ * Store the "fixed" part
+ */
+ if (fragP->fr_fix)
+ VMS_Store_Immediate_Data (fragP->fr_literal,
+ fragP->fr_fix,
+ OBJ_S_C_TIR);
+ /*
+ * Store the "variable" part
+ */
+ if (fragP->fr_var && fragP->fr_offset)
+ VMS_Store_Repeated_Data (fragP->fr_offset,
+ fragP->fr_literal +
+ fragP->fr_fix,
+ fragP->fr_var,
+ OBJ_S_C_TIR);
+ }
+ /*
+ * Now we go through the text segment fixups and
+ * generate TIR records to fix up addresses within
+ * the Text Psect
+ */
+ for (fixP = text_fix_root; fixP; fixP = fixP->fx_next)
+ {
+ /*
+ * We DO handle the case of "Symbol - Symbol" as
+ * long as it is in the same segment.
+ */
+ if (fixP->fx_subsy && fixP->fx_addsy)
+ {
+ int i;
+
+ /*
+ * They need to be in the same segment
+ */
+ if (S_GET_RAW_TYPE (fixP->fx_subsy) !=
+ S_GET_RAW_TYPE (fixP->fx_addsy))
+ error ("Fixup data addsy and subsy didn't have the same type");
+ /*
+ * And they need to be in one that we
+ * can check the psect on
+ */
+ if ((S_GET_TYPE (fixP->fx_addsy) != N_DATA) &&
+ (S_GET_TYPE (fixP->fx_addsy) != N_TEXT))
+ error ("Fixup data addsy and subsy didn't have an appropriate type");
+ /*
+ * This had better not be PC relative!
+ */
+ if (fixP->fx_pcrel)
+ error ("Fixup data was erroneously \"pcrel\"");
+ /*
+ * Subtract their values to get the
+ * difference.
+ */
+ i = S_GET_VALUE (fixP->fx_addsy) -
+ S_GET_VALUE (fixP->fx_subsy);
+ /*
+ * Now generate the fixup object records
+ * Set the psect and store the data
+ */
+ VMS_Set_Psect (Text_Psect,
+ fixP->fx_where +
+ fixP->fx_frag->fr_address,
+ OBJ_S_C_TIR);
+ VMS_Store_Immediate_Data (&i,
+ fixP->fx_size,
+ OBJ_S_C_TIR);
+ /*
+ * Done
+ */
+ continue;
+ }
+ /*
+ * Size will HAVE to be "long"
+ */
+ if (fixP->fx_size != sizeof (long))
+ error ("Fixup datum was not a longword");
+ /*
+ * Symbol must be "added" (if it is ever
+ * subtracted we can
+ * fix this assumption)
+ */
+ if (fixP->fx_addsy == 0)
+ error ("Fixup datum was not \"fixP->fx_addsy\"");
+ /*
+ * Store the symbol value in a PIC fashion
+ */
+ VMS_Store_PIC_Symbol_Reference (fixP->fx_addsy,
+ fixP->fx_offset,
+ fixP->fx_pcrel,
+ Text_Psect,
+ fixP->fx_where +
+ fixP->fx_frag->fr_address,
+ OBJ_S_C_TIR);
+ /*
+ * Check for indirect address reference,
+ * which has to be fixed up (as the linker
+ * will screw it up with TIR_S_C_STO_PICR).
+ */
+ if (fixP->fx_pcrel)
+ VMS_Fix_Indirect_Reference (Text_Psect,
+ fixP->fx_where +
+ fixP->fx_frag->fr_address,
+ fixP->fx_frag,
+ text_frag_root);
+ }
+ }
+ /*
+ * Store the Data segment:
+ *
+ * Since this is REALLY hard to do any other way,
+ * we actually manufacture the data segment and
+ * the store the appropriate values out of it.
+ * The segment was manufactured before, now we just
+ * dump it into the appropriate psects.
+ */
+ if (data_siz > 0)
+ {
+
+ /*
+ * Now we can run through all the data symbols
+ * and store the data
+ */
+ for (vsp = VMS_Symbols; vsp; vsp = vsp->Next)
+ {
+ /*
+ * Ignore anything other than data symbols
+ */
+ if (S_GET_TYPE (vsp->Symbol) != N_DATA)
+ continue;
+ /*
+ * Set the Psect + Offset
+ */
+ VMS_Set_Psect (vsp->Psect_Index,
+ vsp->Psect_Offset,
+ OBJ_S_C_TIR);
+ /*
+ * Store the data
+ */
+ VMS_Store_Immediate_Data (Data_Segment +
+ S_GET_VALUE (vsp->Symbol) -
+ text_siz,
+ vsp->Size,
+ OBJ_S_C_TIR);
+ }
+ /*
+ * Now we go through the data segment fixups and
+ * generate TIR records to fix up addresses within
+ * the Data Psects
+ */
+ for (fixP = data_fix_root; fixP; fixP = fixP->fx_next)
+ {
+ /*
+ * Find the symbol for the containing datum
+ */
+ for (vsp = VMS_Symbols; vsp; vsp = vsp->Next)
+ {
+ /*
+ * Only bother with Data symbols
+ */
+ sp = vsp->Symbol;
+ if (S_GET_TYPE (sp) != N_DATA)
+ continue;
+ /*
+ * Ignore symbol if After fixup
+ */
+ if (S_GET_VALUE (sp) >
+ (fixP->fx_where +
+ fixP->fx_frag->fr_address))
+ continue;
+ /*
+ * See if the datum is here
+ */
+ if ((S_GET_VALUE (sp) + vsp->Size) <=
+ (fixP->fx_where +
+ fixP->fx_frag->fr_address))
+ continue;
+ /*
+ * We DO handle the case of "Symbol - Symbol" as
+ * long as it is in the same segment.
+ */
+ if (fixP->fx_subsy && fixP->fx_addsy)
+ {
+ int i;
+
+ /*
+ * They need to be in the same segment
+ */
+ if (S_GET_RAW_TYPE (fixP->fx_subsy) !=
+ S_GET_RAW_TYPE (fixP->fx_addsy))
+ error ("Fixup data addsy and subsy didn't have the same type");
+ /*
+ * And they need to be in one that we
+ * can check the psect on
+ */
+ if ((S_GET_TYPE (fixP->fx_addsy) != N_DATA) &&
+ (S_GET_TYPE (fixP->fx_addsy) != N_TEXT))
+ error ("Fixup data addsy and subsy didn't have an appropriate type");
+ /*
+ * This had better not be PC relative!
+ */
+ if (fixP->fx_pcrel)
+ error ("Fixup data was erroneously \"pcrel\"");
+ /*
+ * Subtract their values to get the
+ * difference.
+ */
+ i = S_GET_VALUE (fixP->fx_addsy) -
+ S_GET_VALUE (fixP->fx_subsy);
+ /*
+ * Now generate the fixup object records
+ * Set the psect and store the data
+ */
+ VMS_Set_Psect (vsp->Psect_Index,
+ fixP->fx_frag->fr_address +
+ fixP->fx_where -
+ S_GET_VALUE (vsp->Symbol) +
+ vsp->Psect_Offset,
+ OBJ_S_C_TIR);
+ VMS_Store_Immediate_Data (&i,
+ fixP->fx_size,
+ OBJ_S_C_TIR);
+ /*
+ * Done
+ */
+ break;
+ }
+ /*
+ * Size will HAVE to be "long"
+ */
+ if (fixP->fx_size != sizeof (long))
+ error ("Fixup datum was not a longword");
+ /*
+ * Symbol must be "added" (if it is ever
+ * subtracted we can
+ * fix this assumption)
+ */
+ if (fixP->fx_addsy == 0)
+ error ("Fixup datum was not \"fixP->fx_addsy\"");
+ /*
+ * Store the symbol value in a PIC fashion
+ */
+ VMS_Store_PIC_Symbol_Reference (
+ fixP->fx_addsy,
+ fixP->fx_offset,
+ fixP->fx_pcrel,
+ vsp->Psect_Index,
+ fixP->fx_frag->fr_address +
+ fixP->fx_where -
+ S_GET_VALUE (vsp->Symbol) +
+ vsp->Psect_Offset,
+ OBJ_S_C_TIR);
+ /*
+ * Done
+ */
+ break;
+ }
+
+ }
+ }
+
+ /*
+ * Write the Traceback Begin Module record
+ */
+ VMS_TBT_Module_Begin ();
+ /*
+ * Scan the symbols and write out the routines
+ * (this makes the assumption that symbols are in
+ * order of ascending text segment offset)
+ */
+ {
+ struct symbol *Current_Routine = 0;
+ int Current_Line_Number = 0;
+ int Current_Offset = -1;
+ struct input_file *Current_File;
+
+/* Output debugging info for global variables and static variables that are not
+ * specific to one routine. We also need to examine all stabs directives, to
+ * find the definitions to all of the advanced data types, and this is done by
+ * VMS_LSYM_Parse. This needs to be done before any definitions are output to
+ * the object file, since there can be forward references in the stabs
+ * directives. When through with parsing, the text of the stabs directive
+ * is altered, with the definitions removed, so that later passes will see
+ * directives as they would be written if the type were already defined.
+ *
+ * We also look for files and include files, and make a list of them. We
+ * examine the source file numbers to establish the actual lines that code was
+ * generated from, and then generate offsets.
+ */
+ VMS_LSYM_Parse ();
+ for (symbolP = symbol_rootP; symbolP; symbolP = symbol_next (symbolP))
+ {
+ /*
+ * Deal with STAB symbols
+ */
+ if (S_IS_DEBUG (symbolP))
+ {
+ /*
+ * Dispatch on STAB type
+ */
+ switch ((unsigned char) S_GET_RAW_TYPE (symbolP))
+ {
+ case N_SLINE:
+ if (S_GET_DESC (symbolP) > Current_File->max_line)
+ Current_File->max_line = S_GET_DESC (symbolP);
+ if (S_GET_DESC (symbolP) < Current_File->min_line)
+ Current_File->min_line = S_GET_DESC (symbolP);
+ break;
+ case N_SO:
+ Current_File = find_file (symbolP);
+ Current_File->flag = 1;
+ Current_File->min_line = 1;
+ break;
+ case N_SOL:
+ Current_File = find_file (symbolP);
+ break;
+ case N_GSYM:
+ VMS_GSYM_Parse (symbolP, Text_Psect);
+ break;
+ case N_LCSYM:
+ VMS_LCSYM_Parse (symbolP, Text_Psect);
+ break;
+ case N_FUN: /* For static constant symbols */
+ case N_STSYM:
+ VMS_STSYM_Parse (symbolP, Text_Psect);
+ break;
+ }
+ }
+ }
+
+ /* now we take a quick sweep through the files and assign offsets
+ to each one. This will essentially be the starting line number to the
+ debugger for each file. Output the info for the debugger to specify the
+ files, and then tell it how many lines to use */
+ {
+ int File_Number = 0;
+ int Debugger_Offset = 0;
+ int file_available;
+ Current_File = file_root;
+ for (Current_File = file_root; Current_File; Current_File = Current_File->next)
+ {
+ if (Current_File == (struct input_file *) NULL)
+ break;
+ if (Current_File->max_line == 0)
+ continue;
+ if ((strncmp (Current_File->name, "GNU_GXX_INCLUDE:", 16) == 0) &&
+ !flagseen['D'])
+ continue;
+ if ((strncmp (Current_File->name, "GNU_CC_INCLUDE:", 15) == 0) &&
+ !flagseen['D'])
+ continue;
+/* show a few extra lines at the start of the region selected */
+ if (Current_File->min_line > 2)
+ Current_File->min_line -= 2;
+ Current_File->offset = Debugger_Offset - Current_File->min_line + 1;
+ Debugger_Offset += Current_File->max_line - Current_File->min_line + 1;
+ if (Current_File->same_file_fpnt != (struct input_file *) NULL)
+ Current_File->file_number = Current_File->same_file_fpnt->file_number;
+ else
+ {
+ Current_File->file_number = ++File_Number;
+ file_available = VMS_TBT_Source_File (Current_File->name,
+ Current_File->file_number);
+ if (!file_available)
+ {
+ Current_File->file_number = 0;
+ File_Number--;
+ continue;
+ };
+ };
+ VMS_TBT_Source_Lines (Current_File->file_number,
+ Current_File->min_line,
+ Current_File->max_line - Current_File->min_line + 1);
+ }; /* for */
+ }; /* scope */
+ Current_File = (struct input_file *) NULL;
+
+ for (symbolP = symbol_rootP; symbolP; symbolP = symbol_next (symbolP))
+ {
+ /*
+ * Deal with text symbols
+ */
+ if (!S_IS_DEBUG (symbolP) && (S_GET_TYPE (symbolP) == N_TEXT))
+ {
+ /*
+ * Ignore symbols starting with "L",
+ * as they are local symbols
+ */
+ if (*S_GET_NAME (symbolP) == 'L')
+ continue;
+ /*
+ * If there is a routine start defined,
+ * terminate it.
+ */
+ if (Current_Routine)
+ {
+ /*
+ * End the routine
+ */
+ VMS_TBT_Routine_End (text_siz, Current_Routine);
+ }
+ /*
+ * Store the routine begin traceback info
+ */
+ if (Text_Psect != -1)
+ {
+ VMS_TBT_Routine_Begin (symbolP, Text_Psect);
+ Current_Routine = symbolP;
+ }
+/* Output local symbols, i.e. all symbols that are associated with a specific
+ * routine. We output them now so the debugger recognizes them as local to
+ * this routine.
+ */
+ {
+ symbolS *symbolP1;
+ char *pnt;
+ char *pnt1;
+ for (symbolP1 = Current_Routine; symbolP1; symbolP1 = symbol_next (symbolP1))
+ {
+ if (!S_IS_DEBUG (symbolP1))
+ continue;
+ if (S_GET_RAW_TYPE (symbolP1) != N_FUN)
+ continue;
+ pnt = S_GET_NAME (symbolP);
+ pnt1 = S_GET_NAME (symbolP1);
+ if (*pnt++ != '_')
+ continue;
+ while (*pnt++ == *pnt1++)
+ {
+ };
+ if (*pnt1 != 'F' && *pnt1 != 'f') continue;
+ if ((*(--pnt) == '\0') && (*(--pnt1) == ':'))
+ break;
+ };
+ if (symbolP1 != (symbolS *) NULL)
+ VMS_DBG_Define_Routine (symbolP1, Current_Routine, Text_Psect);
+ } /* local symbol block */
+ /*
+ * Done
+ */
+ continue;
+ }
+ /*
+ * Deal with STAB symbols
+ */
+ if (S_IS_DEBUG (symbolP))
+ {
+ /*
+ * Dispatch on STAB type
+ */
+ switch ((unsigned char) S_GET_RAW_TYPE (symbolP))
+ {
+ /*
+ * Line number
+ */
+ case N_SLINE:
+ /* Offset the line into the correct portion
+ * of the file */
+ if (Current_File->file_number == 0)
+ break;
+ /* Sometimes the same offset gets several source
+ * lines assigned to it.
+ * We should be selective about which lines
+ * we allow, we should prefer lines that are
+ * in the main source file when debugging
+ * inline functions. */
+ if ((Current_File->file_number != 1) &&
+ S_GET_VALUE (symbolP) ==
+ Current_Offset)
+ break;
+ /* calculate actual debugger source line */
+ S_GET_DESC (symbolP)
+ += Current_File->offset;
+ /*
+ * If this is the 1st N_SLINE, setup
+ * PC/Line correlation. Otherwise
+ * do the delta PC/Line. If the offset
+ * for the line number is not +ve we need
+ * to do another PC/Line correlation
+ * setup
+ */
+ if (Current_Offset == -1)
+ {
+ VMS_TBT_Line_PC_Correlation (
+ S_GET_DESC (symbolP),
+ S_GET_VALUE (symbolP),
+ Text_Psect,
+ 0);
+ }
+ else
+ {
+ if ((S_GET_DESC (symbolP) -
+ Current_Line_Number) <= 0)
+ {
+ /*
+ * Line delta is not +ve, we
+ * need to close the line and
+ * start a new PC/Line
+ * correlation.
+ */
+ VMS_TBT_Line_PC_Correlation (0,
+ S_GET_VALUE (symbolP) -
+ Current_Offset,
+ 0,
+ -1);
+ VMS_TBT_Line_PC_Correlation (
+ S_GET_DESC (symbolP),
+ S_GET_VALUE (symbolP),
+ Text_Psect,
+ 0);
+ }
+ else
+ {
+ /*
+ * Line delta is +ve, all is well
+ */
+ VMS_TBT_Line_PC_Correlation (
+ S_GET_DESC (symbolP) -
+ Current_Line_Number,
+ S_GET_VALUE (symbolP) -
+ Current_Offset,
+ 0,
+ 1);
+ }
+ }
+ /*
+ * Update the current line/PC
+ */
+ Current_Line_Number = S_GET_DESC (symbolP);
+ Current_Offset = S_GET_VALUE (symbolP);
+ /*
+ * Done
+ */
+ break;
+ /*
+ * Source file
+ */
+ case N_SO:
+ /*
+ * Remember that we had a source file
+ * and emit the source file debugger
+ * record
+ */
+ Current_File =
+ find_file (symbolP);
+ break;
+/* We need to make sure that we are really in the actual source file when
+ * we compute the maximum line number. Otherwise the debugger gets really
+ * confused */
+ case N_SOL:
+ Current_File =
+ find_file (symbolP);
+ break;
+ }
+ }
+ }
+ /*
+ * If there is a routine start defined,
+ * terminate it (and the line numbers)
+ */
+ if (Current_Routine)
+ {
+ /*
+ * Terminate the line numbers
+ */
+ VMS_TBT_Line_PC_Correlation (0,
+ text_siz - S_GET_VALUE (Current_Routine),
+ 0,
+ -1);
+ /*
+ * Terminate the routine
+ */
+ VMS_TBT_Routine_End (text_siz, Current_Routine);
+ }
+ }
+ /*
+ * Write the Traceback End Module TBT record
+ */
+ VMS_TBT_Module_End ();
+
+ /*
+ * Write the End Of Module record
+ */
+ if (Entry_Point_Symbol == 0)
+ Write_VMS_EOM_Record (-1, 0);
+ else
+ Write_VMS_EOM_Record (Text_Psect,
+ S_GET_VALUE (Entry_Point_Symbol));
+
+ /*
+ * All done, close the object file
+ */
+ Close_VMS_Object_File ();
+}
+
+/* end of obj-vms.c */
diff --git a/gnu/usr.bin/as/config/obj-vms.h b/gnu/usr.bin/as/config/obj-vms.h
new file mode 100644
index 0000000..f997535
--- /dev/null
+++ b/gnu/usr.bin/as/config/obj-vms.h
@@ -0,0 +1,474 @@
+/* VMS object file format
+ Copyright (C) 1989, 1990, 1991 Free Software Foundation, Inc.
+
+This file is part of GAS, the GNU Assembler.
+
+GAS is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 2,
+or (at your option) any later version.
+
+GAS is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public
+License along with GAS; see the file COPYING. If not, write
+to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* Tag to validate a.out object file format processing */
+#define OBJ_VMS 1
+
+#include "targ-cpu.h"
+
+/* This flag is used to remember whether we are in the const or the
+ data section. By and large they are identical, but we set a no-write
+ bit for psects in the const section. */
+
+extern char const_flag;
+
+
+/* These are defined in obj-vms.c. */
+extern const short seg_N_TYPE[];
+extern const segT N_TYPE_seg[];
+
+enum reloc_type {
+ NO_RELOC, RELOC_32
+};
+
+#define N_BADMAG(x) (0)
+#define N_TXTOFF(x) ( sizeof(struct exec) )
+#define N_DATOFF(x) ( N_TXTOFF(x) + (x).a_text )
+#define N_TROFF(x) ( N_DATOFF(x) + (x).a_data )
+#define N_DROFF(x) ( N_TROFF(x) + (x).a_trsize )
+#define N_SYMOFF(x) ( N_DROFF(x) + (x).a_drsize )
+#define N_STROFF(x) ( N_SYMOFF(x) + (x).a_syms )
+
+/* We use this copy of the exec header for VMS. We do not actually use it, but
+ what we actually do is let gas fill in the relevant slots, and when we get
+ around to writing an obj file, we just pick out what we need. */
+
+struct exec
+{
+ unsigned long a_text; /* length of text, in bytes */
+ unsigned long a_data; /* length of data, in bytes */
+ unsigned long a_bss; /* length of uninitialized data area for file, in bytes */
+ unsigned long a_trsize; /* length of relocation info for text, in bytes */
+ unsigned long a_drsize; /* length of relocation info for data, in bytes */
+ unsigned long a_entry; /* start address */
+ unsigned long a_syms; /* length of symbol table data in file, in bytes */
+};
+
+typedef struct {
+ struct exec header; /* a.out header */
+ long string_table_size; /* names + '\0' + sizeof(int) */
+} object_headers;
+
+/* A single entry in the symbol table
+ */
+struct nlist {
+ union {
+ char *n_name;
+ struct nlist *n_next;
+ long n_strx; /* Index into string table */
+ } n_un;
+ unsigned char n_type; /* See below */
+ char n_other; /* Used in i80960 support -- see below */
+ short n_desc;
+ unsigned long n_value;
+};
+
+/* Legal values of n_type
+ */
+#define N_UNDF 0 /* Undefined symbol */
+#define N_ABS 2 /* Absolute symbol */
+#define N_TEXT 4 /* Text symbol */
+#define N_DATA 6 /* Data symbol */
+#define N_BSS 8 /* BSS symbol */
+#define N_FN 31 /* Filename symbol */
+
+#define N_EXT 1 /* External symbol (OR'd in with one of above) */
+#define N_TYPE 036 /* Mask for all the type bits */
+
+#define N_STAB 0340 /* Mask for all bits used for SDB entries */
+
+#define N_GSYM 0x20 /* global symbol: name,,0,type,0 */
+#define N_FNAME 0x22 /* procedure name (f77 kludge): name,,0 */
+#define N_FUN 0x24 /* procedure: name,,0,linenumber,address */
+#define N_STSYM 0x26 /* static symbol: name,,0,type,address */
+#define N_LCSYM 0x28 /* .lcomm symbol: name,,0,type,address */
+#define N_RSYM 0x40 /* register sym: name,,0,type,register */
+#define N_SLINE 0x44 /* src line: 0,,0,linenumber,address */
+#define N_CATCH 0x54 /* */
+#define N_SSYM 0x60 /* structure elt: name,,0,type,struct_offset */
+#define N_SO 0x64 /* source file name: name,,0,0,address */
+#define N_LSYM 0x80 /* local sym: name,,0,type,offset */
+#define N_SOL 0x84 /* #included file name: name,,0,0,address */
+#define N_PSYM 0xa0 /* parameter: name,,0,type,offset */
+#define N_ENTRY 0xa4 /* alternate entry: name,linenumber,address */
+#define N_LBRAC 0xc0 /* left bracket: 0,,0,nesting level,address */
+#define N_RBRAC 0xe0 /* right bracket: 0,,0,nesting level,address */
+#define N_BCOMM 0xe2 /* begin common: name,, */
+#define N_ECOMM 0xe4 /* end common: name,, */
+#define N_ECOML 0xe8 /* end common (local name): ,,address */
+#define N_LENG 0xfe /* second stab entry with length information */
+
+/* SYMBOL TABLE */
+/* Symbol table entry data type */
+
+typedef struct nlist obj_symbol_type; /* Symbol table entry */
+
+/* Symbol table macros and constants */
+
+/*
+ * Macros to extract information from a symbol table entry.
+ * This syntaxic indirection allows independence regarding a.out or coff.
+ * The argument (s) of all these macros is a pointer to a symbol table entry.
+ */
+
+/* True if the symbol is external */
+#define S_IS_EXTERNAL(s) ((s)->sy_symbol.n_type & N_EXT)
+
+/* True if symbol has been defined, ie is in N_{TEXT,DATA,BSS,ABS} or N_EXT */
+#define S_IS_DEFINED(s) (S_GET_TYPE(s) != N_UNDF)
+
+#define S_IS_REGISTER(s) ((s)->sy_symbol.n_type == N_REGISTER)
+
+/* True if a debug special symbol entry */
+#define S_IS_DEBUG(s) ((s)->sy_symbol.n_type & N_STAB)
+/* True if a symbol is local symbol name */
+/* A symbol name whose name begin with ^A is a gas internal pseudo symbol
+ nameless symbols come from .stab directives. */
+#define S_IS_LOCAL(s) (S_GET_NAME(s) && \
+ !S_IS_DEBUG(s) && \
+ (S_GET_NAME(s)[0] == '\001' || \
+ (S_LOCAL_NAME(s) && !flagseen['L'])))
+/* True if a symbol is not defined in this file */
+#define S_IS_EXTERN(s) ((s)->sy_symbol.n_type & N_EXT)
+/* True if the symbol has been generated because of a .stabd directive */
+#define S_IS_STABD(s) (S_GET_NAME(s) == (char *)0)
+
+/* Accessors */
+/* The value of the symbol */
+#define S_GET_VALUE(s) (((s)->sy_symbol.n_value))
+/* The name of the symbol */
+#define S_GET_NAME(s) ((s)->sy_symbol.n_un.n_name)
+/* The pointer to the string table */
+#define S_GET_OFFSET(s) ((s)->sy_symbol.n_un.n_strx)
+/* The raw type of the symbol */
+#define S_GET_RAW_TYPE(s) ((s)->sy_symbol.n_type)
+/* The type of the symbol */
+#define S_GET_TYPE(s) ((s)->sy_symbol.n_type & N_TYPE)
+/* The numeric value of the segment */
+#define S_GET_SEGMENT(s) (N_TYPE_seg[S_GET_TYPE(s)])
+/* The n_other expression value */
+#define S_GET_OTHER(s) ((s)->sy_symbol.n_other)
+/* The n_desc expression value */
+#define S_GET_DESC(s) ((s)->sy_symbol.n_desc)
+
+/* Modifiers */
+/* Set the value of the symbol */
+#define S_SET_VALUE(s,v) ((s)->sy_symbol.n_value = (unsigned long) (v))
+/* Assume that a symbol cannot be simultaneously in more than on segment */
+ /* set segment */
+#define S_SET_SEGMENT(s,seg) ((s)->sy_symbol.n_type &= ~N_TYPE,(s)->sy_symbol.n_type|=SEGMENT_TO_SYMBOL_TYPE(seg))
+/* The symbol is external */
+#define S_SET_EXTERNAL(s) ((s)->sy_symbol.n_type |= N_EXT)
+/* The symbol is not external */
+#define S_CLEAR_EXTERNAL(s) ((s)->sy_symbol.n_type &= ~N_EXT)
+/* Set the name of the symbol */
+#define S_SET_NAME(s,v) ((s)->sy_symbol.n_un.n_name = (v))
+/* Set the offset in the string table */
+#define S_SET_OFFSET(s,v) ((s)->sy_symbol.n_un.n_strx = (v))
+/* Set the n_other expression value */
+#define S_SET_OTHER(s,v) ((s)->sy_symbol.n_other = (v))
+/* Set the n_desc expression value */
+#define S_SET_DESC(s,v) ((s)->sy_symbol.n_desc = (v))
+
+
+/* File header macro and type definition */
+
+#define H_GET_TEXT_SIZE(h) ((h)->header.a_text)
+#define H_GET_DATA_SIZE(h) ((h)->header.a_data)
+#define H_GET_BSS_SIZE(h) ((h)->header.a_bss)
+
+#define H_SET_TEXT_SIZE(h,v) ((h)->header.a_text = md_section_align(SEG_TEXT, (v)))
+#define H_SET_DATA_SIZE(h,v) ((h)->header.a_data = md_section_align(SEG_DATA, (v)))
+#define H_SET_BSS_SIZE(h,v) ((h)->header.a_bss = md_section_align(SEG_BSS, (v)))
+
+#define H_SET_STRING_SIZE(h,v) ((h)->string_table_size = (v))
+#define H_SET_SYMBOL_TABLE_SIZE(h,v) ((h)->header.a_syms = (v) * \
+ sizeof(struct nlist))
+
+/*
+ * Current means for getting the name of a segment.
+ * This will change for infinite-segments support (e.g. COFF).
+ */
+#define segment_name(seg) ( seg_name[(int)(seg)] )
+extern char *const seg_name[];
+
+
+/* line numbering stuff. */
+#define OBJ_EMIT_LINENO(a, b, c) {;}
+
+#define obj_symbol_new_hook(s) {;}
+
+#ifdef __STDC__
+struct fix;
+void tc_aout_fix_to_chars(char *where, struct fix *fixP, relax_addressT segment_address);
+#else
+void tc_aout_fix_to_chars();
+#endif /* __STDC__ */
+
+/* The rest of this file contains definitions for constants used within the actual
+ VMS object file. We do not use a $ in the symbols (as per usual VMS
+ convention) since System V gags on it. */
+
+#define OBJ_S_C_HDR 0
+#define OBJ_S_C_HDR_MHD 0
+#define OBJ_S_C_HDR_LNM 1
+#define OBJ_S_C_HDR_SRC 2
+#define OBJ_S_C_HDR_TTL 3
+#define OBJ_S_C_HDR_CPR 4
+#define OBJ_S_C_HDR_MTC 5
+#define OBJ_S_C_HDR_GTX 6
+#define OBJ_S_C_GSD 1
+#define OBJ_S_C_GSD_PSC 0
+#define OBJ_S_C_GSD_SYM 1
+#define OBJ_S_C_GSD_EPM 2
+#define OBJ_S_C_GSD_PRO 3
+#define OBJ_S_C_GSD_SYMW 4
+#define OBJ_S_C_GSD_EPMW 5
+#define OBJ_S_C_GSD_PROW 6
+#define OBJ_S_C_GSD_IDC 7
+#define OBJ_S_C_GSD_ENV 8
+#define OBJ_S_C_GSD_LSY 9
+#define OBJ_S_C_GSD_LEPM 10
+#define OBJ_S_C_GSD_LPRO 11
+#define OBJ_S_C_GSD_SPSC 12
+#define OBJ_S_C_TIR 2
+#define OBJ_S_C_EOM 3
+#define OBJ_S_C_DBG 4
+#define OBJ_S_C_TBT 5
+#define OBJ_S_C_LNK 6
+#define OBJ_S_C_EOMW 7
+#define OBJ_S_C_MAXRECTYP 7
+#define OBJ_S_K_SUBTYP 1
+#define OBJ_S_C_SUBTYP 1
+#define OBJ_S_C_MAXRECSIZ 2048
+#define OBJ_S_C_STRLVL 0
+#define OBJ_S_C_SYMSIZ 31
+#define OBJ_S_C_STOREPLIM -1
+#define OBJ_S_C_PSCALILIM 9
+
+#define MHD_S_C_MHD 0
+#define MHD_S_C_LNM 1
+#define MHD_S_C_SRC 2
+#define MHD_S_C_TTL 3
+#define MHD_S_C_CPR 4
+#define MHD_S_C_MTC 5
+#define MHD_S_C_GTX 6
+#define MHD_S_C_MAXHDRTYP 6
+
+#define GSD_S_K_ENTRIES 1
+#define GSD_S_C_ENTRIES 1
+#define GSD_S_C_PSC 0
+#define GSD_S_C_SYM 1
+#define GSD_S_C_EPM 2
+#define GSD_S_C_PRO 3
+#define GSD_S_C_SYMW 4
+#define GSD_S_C_EPMW 5
+#define GSD_S_C_PROW 6
+#define GSD_S_C_IDC 7
+#define GSD_S_C_ENV 8
+#define GSD_S_C_LSY 9
+#define GSD_S_C_LEPM 10
+#define GSD_S_C_LPRO 11
+#define GSD_S_C_SPSC 12
+#define GSD_S_C_SYMV 13
+#define GSD_S_C_EPMV 14
+#define GSD_S_C_PROV 15
+#define GSD_S_C_MAXRECTYP 15
+
+#define GSY_S_M_WEAK 1
+#define GSY_S_M_DEF 2
+#define GSY_S_M_UNI 4
+#define GSY_S_M_REL 8
+
+#define GPS_S_M_PIC 1
+#define GPS_S_M_LIB 2
+#define GPS_S_M_OVR 4
+#define GPS_S_M_REL 8
+#define GPS_S_M_GBL 16
+#define GPS_S_M_SHR 32
+#define GPS_S_M_EXE 64
+#define GPS_S_M_RD 128
+#define GPS_S_M_WRT 256
+#define GPS_S_M_VEC 512
+#define GPS_S_K_NAME 9
+#define GPS_S_C_NAME 9
+
+#define TIR_S_C_STA_GBL 0
+#define TIR_S_C_STA_SB 1
+#define TIR_S_C_STA_SW 2
+#define TIR_S_C_STA_LW 3
+#define TIR_S_C_STA_PB 4
+#define TIR_S_C_STA_PW 5
+#define TIR_S_C_STA_PL 6
+#define TIR_S_C_STA_UB 7
+#define TIR_S_C_STA_UW 8
+#define TIR_S_C_STA_BFI 9
+#define TIR_S_C_STA_WFI 10
+#define TIR_S_C_STA_LFI 11
+#define TIR_S_C_STA_EPM 12
+#define TIR_S_C_STA_CKARG 13
+#define TIR_S_C_STA_WPB 14
+#define TIR_S_C_STA_WPW 15
+#define TIR_S_C_STA_WPL 16
+#define TIR_S_C_STA_LSY 17
+#define TIR_S_C_STA_LIT 18
+#define TIR_S_C_STA_LEPM 19
+#define TIR_S_C_MAXSTACOD 19
+#define TIR_S_C_MINSTOCOD 20
+#define TIR_S_C_STO_SB 20
+#define TIR_S_C_STO_SW 21
+#define TIR_S_C_STO_L 22
+#define TIR_S_C_STO_BD 23
+#define TIR_S_C_STO_WD 24
+#define TIR_S_C_STO_LD 25
+#define TIR_S_C_STO_LI 26
+#define TIR_S_C_STO_PIDR 27
+#define TIR_S_C_STO_PICR 28
+#define TIR_S_C_STO_RSB 29
+#define TIR_S_C_STO_RSW 30
+#define TIR_S_C_STO_RL 31
+#define TIR_S_C_STO_VPS 32
+#define TIR_S_C_STO_USB 33
+#define TIR_S_C_STO_USW 34
+#define TIR_S_C_STO_RUB 35
+#define TIR_S_C_STO_RUW 36
+#define TIR_S_C_STO_B 37
+#define TIR_S_C_STO_W 38
+#define TIR_S_C_STO_RB 39
+#define TIR_S_C_STO_RW 40
+#define TIR_S_C_STO_RIVB 41
+#define TIR_S_C_STO_PIRR 42
+#define TIR_S_C_MAXSTOCOD 42
+#define TIR_S_C_MINOPRCOD 50
+#define TIR_S_C_OPR_NOP 50
+#define TIR_S_C_OPR_ADD 51
+#define TIR_S_C_OPR_SUB 52
+#define TIR_S_C_OPR_MUL 53
+#define TIR_S_C_OPR_DIV 54
+#define TIR_S_C_OPR_AND 55
+#define TIR_S_C_OPR_IOR 56
+#define TIR_S_C_OPR_EOR 57
+#define TIR_S_C_OPR_NEG 58
+#define TIR_S_C_OPR_COM 59
+#define TIR_S_C_OPR_INSV 60
+#define TIR_S_C_OPR_ASH 61
+#define TIR_S_C_OPR_USH 62
+#define TIR_S_C_OPR_ROT 63
+#define TIR_S_C_OPR_SEL 64
+#define TIR_S_C_OPR_REDEF 65
+#define TIR_S_C_OPR_DFLIT 66
+#define TIR_S_C_MAXOPRCOD 66
+#define TIR_S_C_MINCTLCOD 80
+#define TIR_S_C_CTL_SETRB 80
+#define TIR_S_C_CTL_AUGRB 81
+#define TIR_S_C_CTL_DFLOC 82
+#define TIR_S_C_CTL_STLOC 83
+#define TIR_S_C_CTL_STKDL 84
+#define TIR_S_C_MAXCTLCOD 84
+
+/*
+ * Debugger symbol definitions: These are done by hand, as no
+ * machine-readable version seems
+ * to be available.
+ */
+#define DST_S_C_C 7 /* Language == "C" */
+#define DST_S_C_VERSION 153
+#define DST_S_C_SOURCE 155 /* Source file */
+#define DST_S_C_PROLOG 162
+#define DST_S_C_BLKBEG 176 /* Beginning of block */
+#define DST_S_C_BLKEND 177 /* End of block */
+#define DST_S_C_ENTRY 181
+#define DST_S_C_PSECT 184
+#define DST_S_C_LINE_NUM 185 /* Line Number */
+#define DST_S_C_LBLORLIT 186
+#define DST_S_C_LABEL 187
+#define DST_S_C_MODBEG 188 /* Beginning of module */
+#define DST_S_C_MODEND 189 /* End of module */
+#define DST_S_C_RTNBEG 190 /* Beginning of routine */
+#define DST_S_C_RTNEND 191 /* End of routine */
+#define DST_S_C_DELTA_PC_W 1 /* Incr PC */
+#define DST_S_C_INCR_LINUM 2 /* Incr Line # */
+#define DST_S_C_INCR_LINUM_W 3 /* Incr Line # */
+#define DST_S_C_SET_LINUM_INCR 4
+#define DST_S_C_SET_LINUM_INCR_W 5
+#define DST_S_C_RESET_LINUM_INCR 6
+#define DST_S_C_BEG_STMT_MODE 7
+#define DST_S_C_END_STMT_MODE 8
+#define DST_S_C_SET_LINE_NUM 9 /* Set Line # */
+#define DST_S_C_SET_PC 10
+#define DST_S_C_SET_PC_W 11
+#define DST_S_C_SET_PC_L 12
+#define DST_S_C_SET_STMTNUM 13
+#define DST_S_C_TERM 14 /* End of lines */
+#define DST_S_C_TERM_W 15 /* End of lines */
+#define DST_S_C_SET_ABS_PC 16 /* Set PC */
+#define DST_S_C_DELTA_PC_L 17 /* Incr PC */
+#define DST_S_C_INCR_LINUM_L 18 /* Incr Line # */
+#define DST_S_C_SET_LINUM_B 19 /* Set Line # */
+#define DST_S_C_SET_LINUM_L 20 /* Set Line # */
+#define DST_S_C_TERM_L 21 /* End of lines */
+/* these are used with DST_S_C_SOURCE */
+#define DST_S_C_SRC_FORMFEED 16 /* ^L counts */
+#define DST_S_C_SRC_DECLFILE 1 /* Declare file */
+#define DST_S_C_SRC_SETFILE 2 /* Set file */
+#define DST_S_C_SRC_SETREC_L 3 /* Set record */
+#define DST_S_C_SRC_DEFLINES_W 10 /* # of line */
+/* the following are the codes for the various data types. Anything not on
+ * the list is included under 'advanced_type'
+ */
+#define DBG_S_C_UCHAR 0x02
+#define DBG_S_C_USINT 0x03
+#define DBG_S_C_ULINT 0x04
+#define DBG_S_C_SCHAR 0x06
+#define DBG_S_C_SSINT 0x07
+#define DBG_S_C_SLINT 0x08
+#define DBG_S_C_REAL4 0x0a
+#define DBG_S_C_REAL8 0x0b
+#define DBG_S_C_FUNCTION_ADDR 0x17
+#define DBG_S_C_ADVANCED_TYPE 0xa3
+/* These are the codes that are used to generate the definitions of struct
+ * union and enum records
+ */
+#define DBG_S_C_ENUM_ITEM 0xa4
+#define DBG_S_C_ENUM_START 0xa5
+#define DBG_S_C_ENUM_END 0xa6
+#define DBG_S_C_STRUCT_START 0xab
+#define DBG_S_C_STRUCT_ITEM 0xff
+#define DBG_S_C_STRUCT_END 0xac
+/* These are the codes that are used in the suffix records to determine the
+ * actual data type
+ */
+#define DBG_S_C_BASIC 0x01
+#define DBG_S_C_BASIC_ARRAY 0x02
+#define DBG_S_C_STRUCT 0x03
+#define DBG_S_C_POINTER 0x04
+#define DBG_S_C_VOID 0x05
+#define DBG_S_C_COMPLEX_ARRAY 0x07
+/* These codes are used in the generation of the symbol definition records
+ */
+#define DBG_S_C_FUNCTION_PARAMETER 0xc9
+#define DBG_S_C_LOCAL_SYM 0xd9
+/*
+ * Local Variables:
+ * comment-column: 0
+ * fill-column: 131
+ * End:
+ */
+
+/* end of obj-vms.h */
diff --git a/gnu/usr.bin/as/config/tc-a29k.c b/gnu/usr.bin/as/config/tc-a29k.c
new file mode 100644
index 0000000..3e95db0
--- /dev/null
+++ b/gnu/usr.bin/as/config/tc-a29k.c
@@ -0,0 +1,1113 @@
+/* tc-a29k.c -- Assemble for the AMD 29000.
+ Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
+
+ This file is part of GAS, the GNU Assembler.
+
+ GAS is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GAS is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GAS; see the file COPYING. If not, write to
+ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* John Gilmore has reorganized this module somewhat, to make it easier
+ to convert it to new machines' assemblers as desired. There was too
+ much bloody rewriting required before. There still probably is. */
+
+#include "as.h"
+
+#include "opcode/a29k.h"
+
+/* Make it easier to clone this machine desc into another one. */
+#define machine_opcode a29k_opcode
+#define machine_opcodes a29k_opcodes
+#define machine_ip a29k_ip
+#define machine_it a29k_it
+
+const relax_typeS md_relax_table[] = { 0 };
+
+#define IMMEDIATE_BIT 0x01000000 /* Turns RB into Immediate */
+#define ABSOLUTE_BIT 0x01000000 /* Turns PC-relative to Absolute */
+#define CE_BIT 0x00800000 /* Coprocessor enable in LOAD */
+#define UI_BIT 0x00000080 /* Unsigned integer in CONVERT */
+
+/* handle of the OPCODE hash table */
+static struct hash_control *op_hash = NULL;
+
+struct machine_it {
+ char *error;
+ unsigned long opcode;
+ struct nlist *nlistp;
+ expressionS exp;
+ int pcrel;
+ int reloc_offset; /* Offset of reloc within insn */
+ enum reloc_type reloc;
+} the_insn;
+
+#if __STDC__ == 1
+
+/* static int getExpression(char *str); */
+static void machine_ip(char *str);
+/* static void print_insn(struct machine_it *insn); */
+static void s_data1(void);
+static void s_use(void);
+
+#else /* not __STDC__ */
+
+/* static int getExpression(); */
+static void machine_ip();
+/* static void print_insn(); */
+static void s_data1();
+static void s_use();
+
+#endif /* not __STDC__ */
+
+const pseudo_typeS
+ md_pseudo_table[] = {
+ { "align", s_align_bytes, 4 },
+ { "block", s_space, 0 },
+ { "cputype", s_ignore, 0 }, /* CPU as 29000 or 29050 */
+ { "reg", s_lsym, 0 }, /* Register equate, same as equ */
+ { "space", s_ignore, 0 }, /* Listing control */
+ { "sect", s_ignore, 0 }, /* Creation of coff sections */
+ { "use", s_use, 0 },
+ { "word", cons, 4 },
+ { NULL, 0, 0 },
+ };
+
+int md_short_jump_size = 4;
+int md_long_jump_size = 4;
+#if defined(BFD_HEADERS)
+#ifdef RELSZ
+int md_reloc_size = RELSZ; /* Coff headers */
+#else
+int md_reloc_size = 12; /* something else headers */
+#endif
+#else
+int md_reloc_size = 12; /* Not bfdized*/
+#endif
+
+/* This array holds the chars that always start a comment. If the
+ pre-processor is disabled, these aren't very useful */
+char comment_chars[] = ";";
+
+/* This array holds the chars that only start a comment at the beginning of
+ a line. If the line seems to have the form '# 123 filename'
+ .line and .file directives will appear in the pre-processed output */
+/* Note that input_file.c hand checks for '#' at the beginning of the
+ first line of the input file. This is because the compiler outputs
+ #NO_APP at the beginning of its output. */
+/* Also note that comments like this one will always work */
+char line_comment_chars[] = "#";
+
+/* We needed an unused char for line separation to work around the
+ lack of macros, using sed and such. */
+char line_separator_chars[] = "@";
+
+/* Chars that can be used to separate mant from exp in floating point nums */
+char EXP_CHARS[] = "eE";
+
+/* Chars that mean this number is a floating point constant */
+/* As in 0f12.456 */
+/* or 0d1.2345e12 */
+char FLT_CHARS[] = "rRsSfFdDxXpP";
+
+/* Also be aware that MAXIMUM_NUMBER_OF_CHARS_FOR_FLOAT may have to be
+ changed in read.c. Ideally it shouldn't have to know about it at all,
+ but nothing is ideal around here.
+ */
+
+static unsigned char octal[256];
+#define isoctal(c) octal[c]
+ static unsigned char toHex[256];
+
+/*
+ * anull bit - causes the branch delay slot instructions to not be executed
+ */
+#define ANNUL (1 << 29)
+
+static void
+ s_use()
+{
+
+ if (strncmp(input_line_pointer, ".text", 5) == 0) {
+ input_line_pointer += 5;
+ s_text();
+ return;
+ }
+ if (strncmp(input_line_pointer, ".data", 5) == 0) {
+ input_line_pointer += 5;
+ s_data();
+ return;
+ }
+ if (strncmp(input_line_pointer, ".data1", 6) == 0) {
+ input_line_pointer += 6;
+ s_data1();
+ return;
+ }
+ /* Literals can't go in the text segment because you can't read
+ from instruction memory on some 29k's. So, into initialized data. */
+ if (strncmp(input_line_pointer, ".lit", 4) == 0) {
+ input_line_pointer += 4;
+ subseg_new(SEG_DATA, 200);
+ demand_empty_rest_of_line();
+ return;
+ }
+
+ as_bad("Unknown segment type");
+ demand_empty_rest_of_line();
+ return;
+}
+
+static void
+ s_data1()
+{
+ subseg_new(SEG_DATA, 1);
+ demand_empty_rest_of_line();
+ return;
+}
+
+/* Install symbol definition that maps REGNAME to REGNO.
+ FIXME-SOON: These are not recognized in mixed case. */
+
+static void
+ insert_sreg (regname, regnum)
+char *regname;
+int regnum;
+{
+ /* FIXME-SOON, put something in these syms so they won't be output to the symbol
+ table of the resulting object file. */
+
+ /* Must be large enough to hold the names of the special registers. */
+ char buf[80];
+ int i;
+
+ symbol_table_insert(symbol_new(regname, SEG_REGISTER, regnum, &zero_address_frag));
+ for (i = 0; regname[i]; i++)
+ buf[i] = islower (regname[i]) ? toupper (regname[i]) : regname[i];
+ buf[i] = '\0';
+
+ symbol_table_insert(symbol_new(buf, SEG_REGISTER, regnum, &zero_address_frag));
+} /* insert_sreg() */
+
+/* Install symbol definitions for assorted special registers.
+ See ASM29K Ref page 2-9. */
+
+void define_some_regs() {
+#define SREG 256
+
+ /* Protected special-purpose register names */
+ insert_sreg ("vab", SREG+0);
+ insert_sreg ("ops", SREG+1);
+ insert_sreg ("cps", SREG+2);
+ insert_sreg ("cfg", SREG+3);
+ insert_sreg ("cha", SREG+4);
+ insert_sreg ("chd", SREG+5);
+ insert_sreg ("chc", SREG+6);
+ insert_sreg ("rbp", SREG+7);
+ insert_sreg ("tmc", SREG+8);
+ insert_sreg ("tmr", SREG+9);
+ insert_sreg ("pc0", SREG+10);
+ insert_sreg ("pc1", SREG+11);
+ insert_sreg ("pc2", SREG+12);
+ insert_sreg ("mmu", SREG+13);
+ insert_sreg ("lru", SREG+14);
+
+ /* Unprotected special-purpose register names */
+ insert_sreg ("ipc", SREG+128);
+ insert_sreg ("ipa", SREG+129);
+ insert_sreg ("ipb", SREG+130);
+ insert_sreg ("q", SREG+131);
+ insert_sreg ("alu", SREG+132);
+ insert_sreg ("bp", SREG+133);
+ insert_sreg ("fc", SREG+134);
+ insert_sreg ("cr", SREG+135);
+ insert_sreg ("fpe", SREG+160);
+ insert_sreg ("inte",SREG+161);
+ insert_sreg ("fps", SREG+162);
+ /* "", SREG+163); Reserved */
+ insert_sreg ("exop",SREG+164);
+} /* define_some_regs() */
+
+/* This function is called once, at assembler startup time. It should
+ set up all the tables, etc. that the MD part of the assembler will need. */
+void
+ md_begin()
+{
+ register char *retval = NULL;
+ int lose = 0;
+ register int skipnext = 0;
+ register unsigned int i;
+ register char *strend, *strend2;
+
+ /* Hash up all the opcodes for fast use later. */
+
+ op_hash = hash_new();
+ if (op_hash == NULL)
+ as_fatal("Virtual memory exhausted");
+
+ for (i = 0; i < num_opcodes; i++)
+ {
+ const char *name = machine_opcodes[i].name;
+
+ if (skipnext) {
+ skipnext = 0;
+ continue;
+ }
+
+ /* Hack to avoid multiple opcode entries. We pre-locate all the
+ variations (b/i field and P/A field) and handle them. */
+
+ if (!strcmp (name, machine_opcodes[i+1].name)) {
+ if ((machine_opcodes[i].opcode ^ machine_opcodes[i+1].opcode)
+ != 0x01000000)
+ goto bad_table;
+ strend = machine_opcodes[i ].args+strlen(machine_opcodes[i ].args)-1;
+ strend2 = machine_opcodes[i+1].args+strlen(machine_opcodes[i+1].args)-1;
+ switch (*strend) {
+ case 'b':
+ if (*strend2 != 'i') goto bad_table;
+ break;
+ case 'i':
+ if (*strend2 != 'b') goto bad_table;
+ break;
+ case 'P':
+ if (*strend2 != 'A') goto bad_table;
+ break;
+ case 'A':
+ if (*strend2 != 'P') goto bad_table;
+ break;
+ default:
+ bad_table:
+ fprintf (stderr, "internal error: can't handle opcode %s\n", name);
+ lose = 1;
+ }
+
+ /* OK, this is an i/b or A/P pair. We skip the higher-valued one,
+ and let the code for operand checking handle OR-ing in the bit. */
+ if (machine_opcodes[i].opcode & 1)
+ continue;
+ else
+ skipnext = 1;
+ }
+
+ retval = hash_insert (op_hash, name, &machine_opcodes[i]);
+ if (retval != NULL && *retval != '\0')
+ {
+ fprintf (stderr, "internal error: can't hash `%s': %s\n",
+ machine_opcodes[i].name, retval);
+ lose = 1;
+ }
+ }
+
+ if (lose)
+ as_fatal("Broken assembler. No assembly attempted.");
+
+ for (i = '0'; i < '8'; ++i)
+ octal[i] = 1;
+ for (i = '0'; i <= '9'; ++i)
+ toHex[i] = i - '0';
+ for (i = 'a'; i <= 'f'; ++i)
+ toHex[i] = i + 10 - 'a';
+ for (i = 'A'; i <= 'F'; ++i)
+ toHex[i] = i + 10 - 'A';
+
+ define_some_regs ();
+}
+
+void md_end() {
+ return;
+}
+
+/* Assemble a single instruction. Its label has already been handled
+ by the generic front end. We just parse opcode and operands, and
+ produce the bytes of data and relocation. */
+
+void md_assemble(str)
+char *str;
+{
+ char *toP;
+ /* !!!! int rsd; */
+
+ know(str);
+ machine_ip(str);
+ toP = frag_more(4);
+ /* put out the opcode */
+ md_number_to_chars(toP, the_insn.opcode, 4);
+
+ /* put out the symbol-dependent stuff */
+ if (the_insn.reloc != NO_RELOC) {
+ fix_new(
+ frag_now, /* which frag */
+ (toP - frag_now->fr_literal + the_insn.reloc_offset), /* where */
+ 4, /* size */
+ the_insn.exp.X_add_symbol,
+ the_insn.exp.X_subtract_symbol,
+ the_insn.exp.X_add_number,
+ the_insn.pcrel,
+ the_insn.reloc
+ );
+ }
+}
+
+char *
+ parse_operand (s, operandp)
+char *s;
+expressionS *operandp;
+{
+ char *save = input_line_pointer;
+ char *new;
+ segT seg;
+
+ input_line_pointer = s;
+ seg = expr (0, operandp);
+ new = input_line_pointer;
+ input_line_pointer = save;
+
+ switch (seg) {
+ case SEG_ABSOLUTE:
+ case SEG_TEXT:
+ case SEG_DATA:
+ case SEG_BSS:
+ case SEG_UNKNOWN:
+ case SEG_DIFFERENCE:
+ case SEG_BIG:
+ case SEG_REGISTER:
+ return new;
+
+ case SEG_ABSENT:
+ as_bad("Missing operand");
+ return new;
+
+ default:
+ as_bad("Don't understand operand of type %s", segment_name (seg));
+ return new;
+ }
+}
+
+/* Instruction parsing. Takes a string containing the opcode.
+ Operands are at input_line_pointer. Output is in the_insn.
+ Warnings or errors are generated. */
+
+static void
+ machine_ip(str)
+char *str;
+{
+ char *s;
+ const char *args;
+ /* !!!! char c; */
+ /* !!!! unsigned long i; */
+ struct machine_opcode *insn;
+ char *argsStart;
+ unsigned long opcode;
+ /* !!!! unsigned int mask; */
+ expressionS the_operand;
+ expressionS *operand = &the_operand;
+ unsigned int reg;
+
+ /* Must handle `div0' opcode. */
+ s = str;
+ if (isalpha(*s))
+ for (; isalnum(*s); ++s)
+ if (isupper (*s))
+ *s = tolower (*s);
+
+ switch (*s) {
+ case '\0':
+ break;
+
+ case ' ': /* FIXME-SOMEDAY more whitespace */
+ *s++ = '\0';
+ break;
+
+ default:
+ as_bad("Unknown opcode: `%s'", str);
+ return;
+ }
+ if ((insn = (struct machine_opcode *) hash_find(op_hash, str)) == NULL) {
+ as_bad("Unknown opcode `%s'.", str);
+ return;
+ }
+ argsStart = s;
+ opcode = insn->opcode;
+ memset(&the_insn, '\0', sizeof(the_insn));
+ the_insn.reloc = NO_RELOC;
+
+ /*
+ * Build the opcode, checking as we go to make
+ * sure that the operands match.
+ *
+ * If an operand matches, we modify the_insn or opcode appropriately,
+ * and do a "continue". If an operand fails to match, we "break".
+ */
+ if (insn->args[0] != '\0')
+ s = parse_operand (s, operand); /* Prime the pump */
+
+ for (args = insn->args; ; ++args) {
+ switch (*args) {
+
+ case '\0': /* end of args */
+ if (*s == '\0') {
+ /* We are truly done. */
+ the_insn.opcode = opcode;
+ return;
+ }
+ as_bad("Too many operands: %s", s);
+ break;
+
+ case ',': /* Must match a comma */
+ if (*s++ == ',') {
+ s = parse_operand (s, operand); /* Parse next opnd */
+ continue;
+ }
+ break;
+
+ case 'v': /* Trap numbers (immediate field) */
+ if (operand->X_seg == SEG_ABSOLUTE) {
+ if (operand->X_add_number < 256) {
+ opcode |= (operand->X_add_number << 16);
+ continue;
+ } else {
+ as_bad("Immediate value of %d is too large",
+ operand->X_add_number);
+ continue;
+ }
+ }
+ the_insn.reloc = RELOC_8;
+ the_insn.reloc_offset = 1; /* BIG-ENDIAN Byte 1 of insn */
+ the_insn.exp = *operand;
+ continue;
+
+ case 'b': /* A general register or 8-bit immediate */
+ case 'i':
+ /* We treat the two cases identically since we mashed
+ them together in the opcode table. */
+ if (operand->X_seg == SEG_REGISTER)
+ goto general_reg;
+
+ opcode |= IMMEDIATE_BIT;
+ if (operand->X_seg == SEG_ABSOLUTE) {
+ if (operand->X_add_number < 256) {
+ opcode |= operand->X_add_number;
+ continue;
+ } else {
+ as_bad("Immediate value of %d is too large",
+ operand->X_add_number);
+ continue;
+ }
+ }
+ the_insn.reloc = RELOC_8;
+ the_insn.reloc_offset = 3; /* BIG-ENDIAN Byte 3 of insn */
+ the_insn.exp = *operand;
+ continue;
+
+ case 'a': /* next operand must be a register */
+ case 'c':
+ general_reg:
+ /* lrNNN or grNNN or %%expr or a user-def register name */
+ if (operand->X_seg != SEG_REGISTER)
+ break; /* Only registers */
+ know (operand->X_add_symbol == 0);
+ know (operand->X_subtract_symbol == 0);
+ reg = operand->X_add_number;
+ if (reg >= SREG)
+ break; /* No special registers */
+
+ /*
+ * Got the register, now figure out where
+ * it goes in the opcode.
+ */
+ switch (*args) {
+ case 'a':
+ opcode |= reg << 8;
+ continue;
+
+ case 'b':
+ case 'i':
+ opcode |= reg;
+ continue;
+
+ case 'c':
+ opcode |= reg << 16;
+ continue;
+ }
+ as_fatal("failed sanity check.");
+ break;
+
+ case 'x': /* 16 bit constant, zero-extended */
+ case 'X': /* 16 bit constant, one-extended */
+ if (operand->X_seg == SEG_ABSOLUTE) {
+ opcode |= (operand->X_add_number & 0xFF) << 0 |
+ ((operand->X_add_number & 0xFF00) << 8);
+ continue;
+ }
+ the_insn.reloc = RELOC_CONST;
+ the_insn.exp = *operand;
+ continue;
+
+ case 'h':
+ if (operand->X_seg == SEG_ABSOLUTE) {
+ opcode |= (operand->X_add_number & 0x00FF0000) >> 16 |
+ (((unsigned long)operand->X_add_number
+ /* avoid sign ext */ & 0xFF000000) >> 8);
+ continue;
+ }
+ the_insn.reloc = RELOC_CONSTH;
+ the_insn.exp = *operand;
+ continue;
+
+ case 'P': /* PC-relative jump address */
+ case 'A': /* Absolute jump address */
+ /* These two are treated together since we folded the
+ opcode table entries together. */
+ if (operand->X_seg == SEG_ABSOLUTE) {
+ opcode |= ABSOLUTE_BIT |
+ (operand->X_add_number & 0x0003FC00) << 6 |
+ ((operand->X_add_number & 0x000003FC) >> 2);
+ continue;
+ }
+ the_insn.reloc = RELOC_JUMPTARG;
+ the_insn.exp = *operand;
+ the_insn.pcrel = 1; /* Assume PC-relative jump */
+ /* FIXME-SOON, Do we figure out whether abs later, after know sym val? */
+ continue;
+
+ case 'e': /* Coprocessor enable bit for LOAD/STORE insn */
+ if (operand->X_seg == SEG_ABSOLUTE) {
+ if (operand->X_add_number == 0)
+ continue;
+ if (operand->X_add_number == 1) {
+ opcode |= CE_BIT;
+ continue;
+ }
+ }
+ break;
+
+ case 'n': /* Control bits for LOAD/STORE instructions */
+ if (operand->X_seg == SEG_ABSOLUTE &&
+ operand->X_add_number < 128) {
+ opcode |= (operand->X_add_number << 16);
+ continue;
+ }
+ break;
+
+ case 's': /* Special register number */
+ if (operand->X_seg != SEG_REGISTER)
+ break; /* Only registers */
+ if (operand->X_add_number < SREG)
+ break; /* Not a special register */
+ opcode |= (operand->X_add_number & 0xFF) << 8;
+ continue;
+
+ case 'u': /* UI bit of CONVERT */
+ if (operand->X_seg == SEG_ABSOLUTE) {
+ if (operand->X_add_number == 0)
+ continue;
+ if (operand->X_add_number == 1) {
+ opcode |= UI_BIT;
+ continue;
+ }
+ }
+ break;
+
+ case 'r': /* RND bits of CONVERT */
+ if (operand->X_seg == SEG_ABSOLUTE &&
+ operand->X_add_number < 8) {
+ opcode |= operand->X_add_number << 4;
+ continue;
+ }
+ break;
+
+ case 'd': /* FD bits of CONVERT */
+ if (operand->X_seg == SEG_ABSOLUTE &&
+ operand->X_add_number < 4) {
+ opcode |= operand->X_add_number << 2;
+ continue;
+ }
+ break;
+
+
+ case 'f': /* FS bits of CONVERT */
+ if (operand->X_seg == SEG_ABSOLUTE &&
+ operand->X_add_number < 4) {
+ opcode |= operand->X_add_number << 0;
+ continue;
+ }
+ break;
+
+ case 'C':
+ if (operand->X_seg == SEG_ABSOLUTE &&
+ operand->X_add_number < 4) {
+ opcode |= operand->X_add_number << 16;
+ continue;
+ }
+ break;
+
+ case 'F':
+ if (operand->X_seg == SEG_ABSOLUTE &&
+ operand->X_add_number < 16) {
+ opcode |= operand->X_add_number << 18;
+ continue;
+ }
+ break;
+
+ default:
+ BAD_CASE (*args);
+ }
+ /* Types or values of args don't match. */
+ as_bad("Invalid operands");
+ return;
+ }
+}
+
+/*
+ This is identical to the md_atof in m68k.c. I think this is right,
+ but I'm not sure.
+
+ Turn a string in input_line_pointer into a floating point constant of type
+ type, and store the appropriate bytes in *litP. The number of LITTLENUMS
+ emitted is stored in *sizeP. An error message is returned, or NULL on OK.
+ */
+
+/* Equal to MAX_PRECISION in atof-ieee.c */
+#define MAX_LITTLENUMS 6
+
+char *
+ md_atof(type,litP,sizeP)
+char type;
+char *litP;
+int *sizeP;
+{
+ int prec;
+ LITTLENUM_TYPE words[MAX_LITTLENUMS];
+ LITTLENUM_TYPE *wordP;
+ char *t;
+
+ switch (type) {
+
+ case 'f':
+ case 'F':
+ case 's':
+ case 'S':
+ prec = 2;
+ break;
+
+ case 'd':
+ case 'D':
+ case 'r':
+ case 'R':
+ prec = 4;
+ break;
+
+ case 'x':
+ case 'X':
+ prec = 6;
+ break;
+
+ case 'p':
+ case 'P':
+ prec = 6;
+ break;
+
+ default:
+ *sizeP=0;
+ return "Bad call to MD_ATOF()";
+ }
+ t=atof_ieee(input_line_pointer,type,words);
+ if (t)
+ input_line_pointer=t;
+ *sizeP=prec * sizeof(LITTLENUM_TYPE);
+ for (wordP=words;prec--;) {
+ md_number_to_chars(litP,(long)(*wordP++),sizeof(LITTLENUM_TYPE));
+ litP+=sizeof(LITTLENUM_TYPE);
+ }
+ return ""; /* Someone should teach Dean about null pointers */
+}
+
+/*
+ * Write out big-endian.
+ */
+void
+ md_number_to_chars(buf, val, n)
+char *buf;
+long val;
+int n;
+{
+
+ switch (n) {
+
+ case 4:
+ *buf++ = val >> 24;
+ *buf++ = val >> 16;
+ case 2:
+ *buf++ = val >> 8;
+ case 1:
+ *buf = val;
+ break;
+
+ default:
+ as_fatal("failed sanity check.");
+ }
+ return;
+}
+
+void md_apply_fix(fixP, val)
+fixS *fixP;
+long val;
+{
+ char *buf = fixP->fx_where + fixP->fx_frag->fr_literal;
+
+ fixP->fx_addnumber = val; /* Remember value for emit_reloc */
+
+
+ know(fixP->fx_size == 4);
+ know(fixP->fx_r_type < NO_RELOC);
+
+ /*
+ * This is a hack. There should be a better way to
+ * handle this.
+ */
+ if (fixP->fx_r_type == RELOC_WDISP30 && fixP->fx_addsy) {
+ val += fixP->fx_where + fixP->fx_frag->fr_address;
+ }
+
+ switch (fixP->fx_r_type) {
+
+ case RELOC_32:
+ buf[0] = val >> 24;
+ buf[1] = val >> 16;
+ buf[2] = val >> 8;
+ buf[3] = val;
+ break;
+
+ case RELOC_8:
+ buf[0] = val;
+ break;
+
+ case RELOC_WDISP30:
+ val = (val >>= 2) + 1;
+ buf[0] |= (val >> 24) & 0x3f;
+ buf[1]= (val >> 16);
+ buf[2] = val >> 8;
+ buf[3] = val;
+ break;
+
+ case RELOC_HI22:
+ buf[1] |= (val >> 26) & 0x3f;
+ buf[2] = val >> 18;
+ buf[3] = val >> 10;
+ break;
+
+ case RELOC_LO10:
+ buf[2] |= (val >> 8) & 0x03;
+ buf[3] = val;
+ break;
+
+ case RELOC_BASE13:
+ buf[2] |= (val >> 8) & 0x1f;
+ buf[3] = val;
+ break;
+
+ case RELOC_WDISP22:
+ val = (val >>= 2) + 1;
+ /* FALLTHROUGH */
+ case RELOC_BASE22:
+ buf[1] |= (val >> 16) & 0x3f;
+ buf[2] = val >> 8;
+ buf[3] = val;
+ break;
+
+#if 0
+ case RELOC_PC10:
+ case RELOC_PC22:
+ case RELOC_JMP_TBL:
+ case RELOC_SEGOFF16:
+ case RELOC_GLOB_DAT:
+ case RELOC_JMP_SLOT:
+ case RELOC_RELATIVE:
+#endif
+ case RELOC_JUMPTARG: /* 00XX00XX pattern in a word */
+ buf[1] = val >> 10; /* Holds bits 0003FFFC of address */
+ buf[3] = val >> 2;
+ break;
+
+ case RELOC_CONST: /* 00XX00XX pattern in a word */
+ buf[1] = val >> 8; /* Holds bits 0000XXXX */
+ buf[3] = val;
+ break;
+
+ case RELOC_CONSTH: /* 00XX00XX pattern in a word */
+ buf[1] = val >> 24; /* Holds bits XXXX0000 */
+ buf[3] = val >> 16;
+ break;
+
+ case NO_RELOC:
+ default:
+ as_bad("bad relocation type: 0x%02x", fixP->fx_r_type);
+ break;
+ }
+ return;
+}
+
+#ifdef OBJ_COFF
+short tc_coff_fix2rtype(fixP)
+fixS *fixP;
+{
+
+ /* FIXME-NOW: relocation type handling is not yet written for
+ a29k. */
+
+
+ switch (fixP->fx_r_type) {
+ case RELOC_32: return(R_WORD);
+ case RELOC_8: return(R_BYTE);
+ case RELOC_CONST: return (R_ILOHALF);
+ case RELOC_CONSTH: return (R_IHIHALF);
+ case RELOC_JUMPTARG: return (R_IREL);
+ default: printf("need %o3\n", fixP->fx_r_type);
+ abort(0);
+ } /* switch on type */
+
+ return(0);
+} /* tc_coff_fix2rtype() */
+#endif /* OBJ_COFF */
+
+/* should never be called for sparc */
+void md_create_short_jump(ptr, from_addr, to_addr, frag, to_symbol)
+char *ptr;
+long from_addr, to_addr;
+fragS *frag;
+symbolS *to_symbol;
+{
+ as_fatal("a29k_create_short_jmp\n");
+}
+
+/* should never be called for 29k */
+void md_convert_frag(headers, fragP)
+object_headers *headers;
+register fragS *fragP;
+{
+ as_fatal("sparc_convert_frag\n");
+}
+
+/* should never be called for 29k */
+void md_create_long_jump(ptr, from_addr, to_addr, frag, to_symbol)
+char *ptr;
+long from_addr;
+long to_addr;
+fragS *frag;
+symbolS *to_symbol;
+{
+ as_fatal("sparc_create_long_jump\n");
+}
+
+/* should never be called for a29k */
+int md_estimate_size_before_relax(fragP, segtype)
+register fragS *fragP;
+segT segtype;
+{
+ as_fatal("sparc_estimate_size_before_relax\n");
+ return(0);
+}
+
+#if 0
+/* for debugging only */
+static void
+ print_insn(insn)
+struct machine_it *insn;
+{
+ char *Reloc[] = {
+ "RELOC_8",
+ "RELOC_16",
+ "RELOC_32",
+ "RELOC_DISP8",
+ "RELOC_DISP16",
+ "RELOC_DISP32",
+ "RELOC_WDISP30",
+ "RELOC_WDISP22",
+ "RELOC_HI22",
+ "RELOC_22",
+ "RELOC_13",
+ "RELOC_LO10",
+ "RELOC_SFA_BASE",
+ "RELOC_SFA_OFF13",
+ "RELOC_BASE10",
+ "RELOC_BASE13",
+ "RELOC_BASE22",
+ "RELOC_PC10",
+ "RELOC_PC22",
+ "RELOC_JMP_TBL",
+ "RELOC_SEGOFF16",
+ "RELOC_GLOB_DAT",
+ "RELOC_JMP_SLOT",
+ "RELOC_RELATIVE",
+ "NO_RELOC"
+ };
+
+ if (insn->error) {
+ fprintf(stderr, "ERROR: %s\n");
+ }
+ fprintf(stderr, "opcode=0x%08x\n", insn->opcode);
+ fprintf(stderr, "reloc = %s\n", Reloc[insn->reloc]);
+ fprintf(stderr, "exp = {\n");
+ fprintf(stderr, "\t\tX_add_symbol = %s\n",
+ insn->exp.X_add_symbol ?
+ (S_GET_NAME(insn->exp.X_add_symbol) ?
+ S_GET_NAME(insn->exp.X_add_symbol) : "???") : "0");
+ fprintf(stderr, "\t\tX_sub_symbol = %s\n",
+ insn->exp.X_subtract_symbol ?
+ (S_GET_NAME(insn->exp.X_subtract_symbol) ?
+ S_GET_NAME(insn->exp.X_subtract_symbol) : "???") : "0");
+ fprintf(stderr, "\t\tX_add_number = %d\n",
+ insn->exp.X_add_number);
+ fprintf(stderr, "}\n");
+ return;
+}
+#endif
+
+/* Translate internal representation of relocation info to target format.
+
+ On sparc/29k: first 4 bytes are normal unsigned long address, next three
+ bytes are index, most sig. byte first. Byte 7 is broken up with
+ bit 7 as external, bits 6 & 5 unused, and the lower
+ five bits as relocation type. Next 4 bytes are long addend. */
+/* Thanx and a tip of the hat to Michael Bloom, mb@ttidca.tti.com */
+
+#ifdef OBJ_AOUT
+
+void tc_aout_fix_to_chars(where, fixP, segment_address_in_file)
+char *where;
+fixS *fixP;
+relax_addressT segment_address_in_file;
+{
+ long r_symbolnum;
+
+ know(fixP->fx_r_type < NO_RELOC);
+ know(fixP->fx_addsy != NULL);
+
+ md_number_to_chars(where,
+ fixP->fx_frag->fr_address + fixP->fx_where - segment_address_in_file,
+ 4);
+
+ r_symbolnum = (S_IS_DEFINED(fixP->fx_addsy)
+ ? S_GET_TYPE(fixP->fx_addsy)
+ : fixP->fx_addsy->sy_number);
+
+ where[4] = (r_symbolnum >> 16) & 0x0ff;
+ where[5] = (r_symbolnum >> 8) & 0x0ff;
+ where[6] = r_symbolnum & 0x0ff;
+ where[7] = (((!S_IS_DEFINED(fixP->fx_addsy)) << 7) & 0x80) | (0 & 0x60) | (fixP->fx_r_type & 0x1F);
+ /* Also easy */
+ md_number_to_chars(&where[8], fixP->fx_addnumber, 4);
+
+ return;
+} /* tc_aout_fix_to_chars() */
+
+#endif /* OBJ_AOUT */
+
+int
+ md_parse_option(argP,cntP,vecP)
+char **argP;
+int *cntP;
+char ***vecP;
+{
+ return(0);
+}
+
+
+/* Default the values of symbols known that should be "predefined". We
+ don't bother to predefine them unless you actually use one, since there
+ are a lot of them. */
+
+symbolS *md_undefined_symbol (name)
+char *name;
+{
+ long regnum;
+ char testbuf[5+ /*SLOP*/ 5];
+
+ if (name[0] == 'g' || name[0] == 'G' || name[0] == 'l' || name[0] == 'L')
+ {
+ /* Perhaps a global or local register name */
+ if (name[1] == 'r' || name[1] == 'R')
+ {
+ /* Parse the number, make sure it has no extra zeroes or trailing
+ chars */
+ regnum = atol(&name[2]);
+ if (regnum > 127)
+ return 0;
+ sprintf(testbuf, "%ld", regnum);
+ if (strcmp (testbuf, &name[2]) != 0)
+ return 0; /* gr007 or lr7foo or whatever */
+
+ /* We have a wiener! Define and return a new symbol for it. */
+ if (name[0] == 'l' || name[0] == 'L')
+ regnum += 128;
+ return(symbol_new(name, SEG_REGISTER, regnum, &zero_address_frag));
+ }
+ }
+
+ return 0;
+}
+
+/* Parse an operand that is machine-specific. */
+
+void md_operand(expressionP)
+expressionS *expressionP;
+{
+
+ if (input_line_pointer[0] == '%' && input_line_pointer[1] == '%')
+ {
+ /* We have a numeric register expression. No biggy. */
+ input_line_pointer += 2; /* Skip %% */
+ (void)expression (expressionP);
+ if (expressionP->X_seg != SEG_ABSOLUTE
+ || expressionP->X_add_number > 255)
+ as_bad("Invalid expression after %%%%\n");
+ expressionP->X_seg = SEG_REGISTER;
+ }
+ else if (input_line_pointer[0] == '&')
+ {
+ /* We are taking the 'address' of a register...this one is not
+ in the manual, but it *is* in traps/fpsymbol.h! What they
+ seem to want is the register number, as an absolute number. */
+ input_line_pointer++; /* Skip & */
+ (void)expression (expressionP);
+ if (expressionP->X_seg != SEG_REGISTER)
+ as_bad("Invalid register in & expression");
+ else
+ expressionP->X_seg = SEG_ABSOLUTE;
+ }
+}
+
+/* Round up a section size to the appropriate boundary. */
+long
+ md_section_align (segment, size)
+segT segment;
+long size;
+{
+ return size; /* Byte alignment is fine */
+}
+
+/* Exactly what point is a PC-relative offset relative TO?
+ On the 29000, they're relative to the address of the instruction,
+ which we have set up as the address of the fixup too. */
+long md_pcrel_from (fixP)
+fixS *fixP;
+{
+ return fixP->fx_where + fixP->fx_frag->fr_address;
+}
+
+/*
+ * Local Variables:
+ * comment-column: 0
+ * End:
+ */
+
+/* end of tc-a29k.c */
diff --git a/gnu/usr.bin/as/config/tc-a29k.h b/gnu/usr.bin/as/config/tc-a29k.h
new file mode 100644
index 0000000..a362595
--- /dev/null
+++ b/gnu/usr.bin/as/config/tc-a29k.h
@@ -0,0 +1,40 @@
+/* tc-a29k.h -- Assemble for the AMD 29000.
+ Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
+
+ This file is part of GAS, the GNU Assembler.
+
+ GAS is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GAS is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GAS; see the file COPYING. If not, write to
+ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#define TC_A29K
+
+#define NO_LISTING
+
+#define tc_aout_pre_write_hook(x) {;} /* not used */
+#define tc_coff_symbol_emit_hook(a) {;} /* not used */
+#define tc_crawl_symbol_chain(a) {;} /* not used */
+#define tc_headers_hook(a) {;} /* not used */
+
+#define AOUT_MACHTYPE 101
+#define TC_COFF_FIX2RTYPE(fix_ptr) tc_coff_fix2rtype(fix_ptr)
+#define BFD_ARCH bfd_arch_a29k
+#define COFF_MAGIC SIPFBOMAGIC
+
+/* Should the reloc be output ?
+ on the 29k, this is true only if there is a symbol attatched.
+ on the h8, this is allways true, since no fixup is done
+ */
+#define TC_COUNT_RELOC(x) (x->fx_addsy)
+
+/* end of tc-a29k.h */
diff --git a/gnu/usr.bin/as/config/tc-generic.c b/gnu/usr.bin/as/config/tc-generic.c
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/gnu/usr.bin/as/config/tc-generic.c
diff --git a/gnu/usr.bin/as/config/tc-generic.h b/gnu/usr.bin/as/config/tc-generic.h
new file mode 100644
index 0000000..7a16dd0
--- /dev/null
+++ b/gnu/usr.bin/as/config/tc-generic.h
@@ -0,0 +1,37 @@
+/* This file is tc-generic.h
+
+ Copyright (C) 1987-1992 Free Software Foundation, Inc.
+
+ This file is part of GAS, the GNU Assembler.
+
+ GAS is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GAS is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GAS; see the file COPYING. If not, write to
+ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/*
+ * This file is tc-generic.h and is intended to be a template for target cpu
+ * specific header files. It is my intent that this file compile. It is also
+ * my intent that this file grow into something that can be used as both a
+ * template for porting, and a stub for testing. xoxorich.
+ */
+
+#define TC_GENERIC 1
+
+/*
+ * Local Variables:
+ * comment-column: 0
+ * fill-column: 131
+ * End:
+ */
+
+/* end of tc-generic.h */
diff --git a/gnu/usr.bin/as/config/tc-h8300.c b/gnu/usr.bin/as/config/tc-h8300.c
new file mode 100644
index 0000000..2ce2f2b
--- /dev/null
+++ b/gnu/usr.bin/as/config/tc-h8300.c
@@ -0,0 +1,1295 @@
+/* tc-h8300.c -- Assemble code for the Hitachi H8/300
+ Copyright (C) 1991, 1992 Free Software Foundation.
+
+ This file is part of GAS, the GNU Assembler.
+
+ GAS is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GAS is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GAS; see the file COPYING. If not, write to
+ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+
+/*
+ Written By Steve Chamberlain
+ sac@cygnus.com
+ */
+
+#include <stdio.h>
+#include "as.h"
+#include "bfd.h"
+#include "opcode/h8300.h"
+#include <ctype.h>
+#include "listing.h"
+
+char comment_chars[] = { ';',0 };
+char line_separator_chars[] = { '$' ,0};
+
+/* This table describes all the machine specific pseudo-ops the assembler
+ has to support. The fields are:
+ pseudo-op name without dot
+ function to call to execute this pseudo-op
+ Integer arg to pass to the function
+ */
+
+void cons();
+
+const pseudo_typeS md_pseudo_table[] = {
+ { "int", cons, 2 },
+ { 0,0,0 }
+};
+
+int md_reloc_size ;
+
+const char EXP_CHARS[] = "eE";
+
+/* Chars that mean this number is a floating point constant */
+/* As in 0f12.456 */
+/* or 0d1.2345e12 */
+char FLT_CHARS[] = "rRsSfFdDxXpP";
+
+
+const relax_typeS md_relax_table[1];
+
+
+static struct hash_control *opcode_hash_control; /* Opcode mnemonics */
+
+
+/*
+ This function is called once, at assembler startup time. This should
+ set up all the tables, etc that the MD part of the assembler needs
+ */
+#if 0
+/* encode the size and number into the number field
+ xxnnnn
+ 00 8 bit
+ 01 16 bit
+ 10 ccr
+ nnnnreg number
+ */
+#define WORD_REG 0x10
+#define BYTE_REG 0x00
+#define CCR_REG 0x20
+struct reg_entry
+{
+ char *name;
+ char number;
+};
+
+struct reg_entry reg_list[] = {
+ "r0",WORD_REG +0,
+ "r1",WORD_REG +1,
+ "r2",WORD_REG +2,
+ "r3",WORD_REG +3,
+ "r4",WORD_REG +4,
+ "r5",WORD_REG +5,
+ "r6",WORD_REG +6,
+ "r7",WORD_REG +7,
+ "fp",WORD_REG +6,
+ "sp",WORD_REG +7,
+ "r0h",BYTE_REG + 0,
+ "r0l",BYTE_REG + 1,
+ "r1h",BYTE_REG + 2,
+ "r1l",BYTE_REG + 3,
+ "r2h",BYTE_REG + 4,
+ "r2l",BYTE_REG + 5,
+ "r3h",BYTE_REG + 6,
+ "r3l",BYTE_REG + 7,
+ "r4h",BYTE_REG + 8,
+ "r4l",BYTE_REG + 9,
+ "r5h",BYTE_REG + 10,
+ "r5l",BYTE_REG + 11,
+ "r6h",BYTE_REG + 12,
+ "r6l",BYTE_REG + 13,
+ "r7h",BYTE_REG + 14,
+ "r7l",BYTE_REG + 15,
+ "ccr",CCR_REG,
+ 0,0
+ }
+;
+
+
+#endif
+
+
+void md_begin ()
+{
+ struct h8_opcode *opcode;
+ const struct reg_entry *reg;
+ char prev_buffer[100];
+ int idx = 0;
+
+ opcode_hash_control = hash_new();
+ prev_buffer[0] = 0;
+
+ for (opcode = h8_opcodes; opcode->name; opcode++)
+ {
+ /* Strip off any . part when inserting the opcode and only enter
+ unique codes into the hash table
+ */
+ char *src= opcode->name;
+ unsigned int len = strlen(src);
+ char *dst = malloc(len+1);
+ char *buffer = dst;
+ opcode->size = 0;
+ while (*src) {
+ if (*src == '.') {
+ *dst++ = 0;
+ src++;
+ opcode->size = *src;
+ break;
+ }
+ *dst++ = *src++;
+ }
+ if (strcmp(buffer, prev_buffer))
+ {
+ hash_insert(opcode_hash_control, buffer, (char *)opcode);
+ strcpy(prev_buffer, buffer);
+ idx++;
+ }
+ opcode->idx = idx;
+
+
+ /* Find the number of operands */
+ opcode->noperands = 0;
+ while (opcode->args.nib[opcode->noperands] != E)
+ opcode->noperands ++;
+ /* Find the length of the opcode in bytes */
+ opcode->length =0;
+ while (opcode->data.nib[opcode->length*2] != E)
+ opcode->length++;
+ }
+
+}
+
+
+struct h8_exp {
+ char *e_beg;
+ char *e_end;
+ expressionS e_exp;
+};
+struct h8_op
+{
+ unsigned int dispreg;
+ op_type mode;
+ unsigned reg;
+ expressionS exp;
+};
+
+
+
+/*
+ parse operands
+ WREG r0,r1,r2,r3,r4,r5,r6,r7,fp,sp
+ r0l,r0h,..r7l,r7h
+ @WREG
+ @WREG+
+ @-WREG
+ #const
+
+ */
+
+op_type r8_sord[] = {RS8, RD8};
+op_type r16_sord[] = {RS16, RD16};
+op_type rind_sord[] = {RSIND, RDIND};
+op_type abs_sord[2] = {ABS16SRC, ABS16DST};
+op_type disp_sord[] = {DISPSRC, DISPDST};
+
+/* try and parse a reg name, returns number of chars consumed */
+int
+ DEFUN(parse_reg,(src, mode, reg, dst),
+ char *src AND
+ op_type *mode AND
+ unsigned int *reg AND
+ int dst)
+{
+ if (src[0] == 's' && src[1] == 'p')
+ {
+ *mode = r16_sord[dst];
+ *reg = 7;
+ return 2;
+ }
+ if (src[0] == 'c' && src[1] == 'c' && src[2] == 'r')
+ {
+ *mode = CCR;
+ *reg = 0;
+ return 3;
+ }
+ if (src[0] == 'f' && src[1] == 'p')
+ {
+ *mode = r16_sord[dst];
+ *reg = 6;
+ return 2;
+ }
+ if (src[0] == 'r')
+ {
+ if (src[1] >= '0' && src[1] <= '7')
+ {
+ if (src[2] == 'l')
+ {
+ *mode = r8_sord[dst];
+ *reg = (src[1] - '0') + 8;
+ return 3;
+ }
+ if (src[2] == 'h')
+ {
+ *mode = r8_sord[dst];
+ *reg = (src[1] - '0') ;
+ return 3;
+ }
+ *mode = r16_sord[dst];
+ *reg = (src[1] - '0');
+ return 2;
+ }
+ }
+ return 0;
+}
+
+char *
+ DEFUN(parse_exp,(s, op),
+ char *s AND
+ expressionS *op)
+{
+ char *save = input_line_pointer;
+ char *new;
+ segT seg;
+ input_line_pointer = s;
+ seg = expr(0,op);
+ new = input_line_pointer;
+ input_line_pointer = save;
+ if (SEG_NORMAL(seg))
+ return new;
+ switch (seg) {
+ case SEG_ABSOLUTE:
+ case SEG_UNKNOWN:
+ case SEG_DIFFERENCE:
+ case SEG_BIG:
+ case SEG_REGISTER:
+ return new;
+ case SEG_ABSENT:
+ as_bad("Missing operand");
+ return new;
+ default:
+ as_bad("Don't understand operand of type %s", segment_name (seg));
+ return new;
+ }
+}
+
+static char *
+ DEFUN(skip_colonthing,(ptr),
+ char *ptr)
+{
+ if (*ptr == ':') {
+ ptr++;
+ while (isdigit(*ptr))
+ ptr++;
+
+ }
+ return ptr;
+}
+
+/* The many forms of operand:
+
+ Rn Register direct
+ @Rn Register indirect
+ @(exp[:16], Rn) Register indirect with displacement
+ @Rn+
+ @-Rn
+ @aa:8 absolute 8 bit
+ @aa:16 absolute 16 bit
+ @aa absolute 16 bit
+
+ #xx[:size] immediate data
+ @(exp:[8], pc) pc rel
+ @@aa[:8] memory indirect
+
+ */
+
+static void
+ DEFUN(get_operand,(ptr, op, dst),
+ char **ptr AND
+ struct h8_op *op AND
+ unsigned int dst)
+{
+ char *src = *ptr;
+ op_type mode;
+ unsigned int num;
+ unsigned int len;
+ unsigned int size;
+ op->mode = E;
+
+ len = parse_reg(src, &op->mode, &op->reg, dst);
+ if (len) {
+ *ptr = src + len;
+ return ;
+ }
+
+ if (*src == '@')
+ {
+ src++;
+ if (*src == '@')
+ {
+ src++;
+ src = parse_exp(src,&op->exp);
+ src = skip_colonthing(src);
+
+ *ptr = src;
+
+ op->mode = MEMIND;
+ return;
+
+ }
+
+
+ if (*src == '-')
+ {
+ src++;
+ len = parse_reg(src, &mode, &num, dst);
+ if (len == 0)
+ {
+ /* Oops, not a reg after all, must be ordinary exp */
+ src--;
+ /* must be a symbol */
+ op->mode = abs_sord[dst];
+ *ptr = skip_colonthing(parse_exp(src, &op->exp));
+
+ return;
+
+
+ }
+
+ if (mode != r16_sord[dst])
+ {
+ as_bad("@- needs word register");
+ }
+ op->mode = RDDEC;
+ op->reg = num;
+ *ptr = src + len;
+ return;
+ }
+ if (*src == '(' && ')')
+ {
+ /* Disp */
+ src++;
+ src = parse_exp(src, &op->exp);
+
+ if (*src == ')')
+ {
+ src++;
+ op->mode = abs_sord[dst];
+ *ptr = src;
+ return;
+ }
+ src = skip_colonthing(src);
+
+ if (*src != ',')
+ {
+ as_bad("expected @(exp, reg16)");
+ }
+ src++;
+ len = parse_reg(src, &mode, &op->reg, dst);
+ if (len == 0 || mode != r16_sord[dst])
+ {
+ as_bad("expected @(exp, reg16)");
+ }
+ op->mode = disp_sord[dst];
+ src += len;
+ src = skip_colonthing(src);
+
+ if (*src != ')' && '(')
+ {
+ as_bad("expected @(exp, reg16)");
+
+ }
+ *ptr = src +1;
+
+ return;
+ }
+ len = parse_reg(src, &mode, &num, dst);
+
+ if (len) {
+ src += len;
+ if (*src == '+')
+ {
+ src++;
+ if (mode != RS16)
+ {
+ as_bad("@Rn+ needs src word register");
+ }
+ op->mode = RSINC;
+ op->reg = num;
+ *ptr = src;
+ return;
+ }
+ if (mode != r16_sord[dst])
+ {
+ as_bad("@Rn needs word register");
+ }
+ op->mode =rind_sord[dst];
+ op->reg = num;
+ *ptr = src;
+ return;
+ }
+ else
+ {
+ /* must be a symbol */
+ op->mode = abs_sord[dst];
+ *ptr = skip_colonthing(parse_exp(src, &op->exp));
+
+ return;
+ }
+ }
+
+
+ if (*src == '#') {
+ src++;
+ op->mode = IMM16;
+ src = parse_exp(src, &op->exp);
+ *ptr= skip_colonthing(src);
+
+ return;
+ }
+ else {
+ *ptr = parse_exp(src, &op->exp);
+ op->mode = DISP8;
+ }
+}
+
+
+static
+ char *
+ DEFUN(get_operands,(noperands,op_end, operand),
+ unsigned int noperands AND
+ char *op_end AND
+ struct h8_op *operand)
+{
+ char *ptr = op_end;
+ switch (noperands)
+ {
+ case 0:
+ operand[0].mode = 0;
+ operand[1].mode = 0;
+ break;
+
+ case 1:
+ ptr++;
+ get_operand(& ptr, operand +0,0);
+ operand[1].mode =0;
+ break;
+
+ case 2:
+ ptr++;
+ get_operand(& ptr, operand +0,0);
+ if (*ptr == ',') ptr++;
+ get_operand(& ptr, operand +1, 1);
+ break;
+
+ default:
+ abort();
+ }
+
+
+ return ptr;
+}
+
+/* Passed a pointer to a list of opcodes which use different
+ addressing modes, return the opcode which matches the opcodes
+ provided
+ */
+static
+ struct h8_opcode *
+ DEFUN(get_specific,(opcode, operands),
+ struct h8_opcode *opcode AND
+ struct h8_op *operands)
+
+{
+ struct h8_opcode *this_try = opcode ;
+ int found = 0;
+ unsigned int noperands = opcode->noperands;
+
+ unsigned int dispreg;
+ unsigned int this_index = opcode->idx;
+ while (this_index == opcode->idx && !found)
+ {
+ unsigned int i;
+
+ this_try = opcode ++;
+ for (i = 0; i < noperands; i++)
+ {
+ op_type op = (this_try->args.nib[i]) & ~(B30|B31);
+ switch (op)
+ {
+ case Hex0:
+ case Hex1:
+ case Hex2:
+ case Hex3:
+ case Hex4:
+ case Hex5:
+ case Hex6:
+ case Hex7:
+ case Hex8:
+ case Hex9:
+ case HexA:
+ case HexB:
+ case HexC:
+ case HexD:
+ case HexE:
+ case HexF:
+ break;
+ case DISPSRC:
+ case DISPDST:
+ operands[0].dispreg = operands[i].reg;
+ case RD8:
+ case RS8:
+ case RDIND:
+ case RSIND:
+ case RD16:
+ case RS16:
+ case CCR:
+ case RSINC:
+ case RDDEC:
+ if (operands[i].mode != op) goto fail;
+ break;
+ case KBIT:
+ case IMM16:
+ case IMM3:
+ case IMM8:
+ if (operands[i].mode != IMM16) goto fail;
+ break;
+ case MEMIND:
+ if (operands[i].mode != MEMIND) goto fail;
+ break;
+ case ABS16SRC:
+ case ABS8SRC:
+ case ABS16OR8SRC:
+ case ABS16ORREL8SRC:
+
+ if (operands[i].mode != ABS16SRC) goto fail;
+ break;
+ case ABS16OR8DST:
+ case ABS16DST:
+ case ABS8DST:
+ if (operands[i].mode != ABS16DST) goto fail;
+ break;
+ }
+ }
+ found =1;
+ fail: ;
+ }
+ if (found)
+ return this_try;
+ else
+ return 0;
+}
+
+static void
+ DEFUN(check_operand,(operand, width, string),
+ struct h8_op *operand AND
+ unsigned int width AND
+ char *string)
+{
+ if (operand->exp.X_add_symbol == 0
+ && operand->exp.X_subtract_symbol == 0)
+ {
+
+ /* No symbol involved, let's look at offset, it's dangerous if any of
+ the high bits are not 0 or ff's, find out by oring or anding with
+ the width and seeing if the answer is 0 or all fs*/
+ if ((operand->exp.X_add_number | width) != ~0 &&
+ (operand->exp.X_add_number & ~width) != 0)
+ {
+ as_warn("operand %s0x%x out of range.", string, operand->exp.X_add_number);
+ }
+ }
+
+}
+
+/* Now we know what sort of opcodes it is, lets build the bytes -
+ */
+static void
+ DEFUN (build_bytes,(this_try, operand),
+ struct h8_opcode *this_try AND
+ struct h8_op *operand)
+
+{
+ unsigned int i;
+
+ char *output = frag_more(this_try->length);
+ char *output_ptr = output;
+ op_type *nibble_ptr = this_try->data.nib;
+ char part;
+ op_type c;
+ char high;
+ int nib;
+ top: ;
+ while (*nibble_ptr != E)
+ {
+ int nibble;
+ for (nibble = 0; nibble <2; nibble++)
+ {
+ c = *nibble_ptr & ~(B30|B31);
+ switch (c)
+ {
+ default:
+ abort();
+ case KBIT:
+ switch (operand[0].exp.X_add_number)
+ {
+ case 1:
+ nib = 0;
+ break;
+ case 2:
+ nib = 8;
+ break;
+ default:
+ as_bad("Need #1 or #2 here");
+ break;
+ }
+ /* stop it making a fix */
+ operand[0].mode = 0;
+ break;
+ case 0:
+ case 1:
+ case 2: case 3: case 4: case 5: case 6:
+ case 7: case 8: case 9: case 10: case 11:
+ case 12: case 13: case 14: case 15:
+ nib = c;
+ break;
+ case DISPREG:
+ nib = operand[0].dispreg;
+ break;
+ case IMM8:
+ operand[0].mode = IMM8;
+ nib = 0;
+ break;
+
+ case DISPDST:
+ nib = 0;
+ break;
+ case IMM3:
+ if (operand[0].exp.X_add_symbol == 0) {
+ operand[0].mode = 0; /* stop it making a fix */
+ nib = (operand[0].exp.X_add_number);
+ }
+ else as_bad("can't have symbol for bit number");
+ if (nib < 0 || nib > 7)
+ {
+ as_bad("Bit number out of range %d", nib);
+ }
+
+ break;
+
+ case ABS16DST:
+ nib = 0;
+ break;
+ case ABS8DST:
+ operand[1].mode = ABS8DST;
+ nib = 0;
+ break;
+ case ABS8SRC:
+ operand[0].mode = ABS8SRC;
+ nib = 0;
+ break;
+ case ABS16OR8DST:
+ operand[1].mode = c;
+
+ nib = 0;
+
+ break;
+
+ case ABS16ORREL8SRC:
+ operand[0].mode = c;
+ nib=0;
+ break;
+
+ case ABS16OR8SRC:
+ operand[0].mode = ABS16OR8SRC;
+ nib = 0;
+ break;
+ case DISPSRC:
+ operand[0].mode = ABS16SRC;
+ nib = 0;
+ break;
+
+ case DISP8:
+ operand[0].mode = DISP8;
+ nib = 0;
+ break;
+
+ case ABS16SRC:
+ case IMM16:
+ case IGNORE:
+ case MEMIND:
+
+ nib=0;
+ break;
+ case RS8:
+ case RS16:
+ case RSIND:
+ case RSINC:
+ nib = operand[0].reg;
+ break;
+
+ case RD8:
+ case RD16:
+ case RDDEC:
+ case RDIND:
+ nib = operand[1].reg;
+ break;
+
+ case E:
+ abort();
+ break;
+ }
+ if (*nibble_ptr & B31) {
+ nib |=0x8;
+ }
+
+ if (nibble == 0) {
+ *output_ptr = nib << 4;
+ }
+ else {
+ *output_ptr |= nib;
+ output_ptr++;
+ }
+ nibble_ptr++;
+ }
+
+ }
+
+ /* output any fixes */
+ for (i = 0; i < 2; i++)
+ {
+ switch (operand[i].mode) {
+ case 0:
+ break;
+
+ case DISP8:
+ check_operand(operand+i, 0x7f,"@");
+
+ fix_new(frag_now,
+ output - frag_now->fr_literal + 1,
+ 1,
+ operand[i].exp.X_add_symbol,
+ operand[i].exp.X_subtract_symbol,
+ operand[i].exp.X_add_number -1,
+ 1,
+ R_PCRBYTE);
+ break;
+ case IMM8:
+ check_operand(operand+i, 0xff,"#");
+ /* If there is nothing else going on we can safely
+ reloc in place */
+ if (operand[i].exp.X_add_symbol == 0)
+ {
+ output[1] = operand[i].exp.X_add_number;
+ }
+ else
+ {
+ fix_new(frag_now,
+ output - frag_now->fr_literal + 1,
+ 1,
+ operand[i].exp.X_add_symbol,
+ operand[i].exp.X_subtract_symbol,
+ operand[i].exp.X_add_number,
+ 0,
+ R_RELBYTE);
+ }
+
+ break;
+ case MEMIND:
+ check_operand(operand+i, 0xff,"@@");
+ fix_new(frag_now,
+ output - frag_now->fr_literal + 1,
+ 1,
+ operand[i].exp.X_add_symbol,
+ operand[i].exp.X_subtract_symbol,
+ operand[i].exp.X_add_number,
+ 0,
+ R_RELBYTE);
+ break;
+ case ABS8DST:
+ case ABS8SRC:
+ check_operand(operand+i, 0xff,"@");
+ fix_new(frag_now,
+ output - frag_now->fr_literal + 1,
+ 1,
+ operand[i].exp.X_add_symbol,
+ operand[i].exp.X_subtract_symbol,
+ operand[i].exp.X_add_number,
+ 0,
+ R_RELBYTE);
+ break;
+
+ case ABS16OR8SRC:
+ case ABS16OR8DST:
+ check_operand(operand+i, 0xffff,"@");
+
+ fix_new(frag_now,
+ output - frag_now->fr_literal + 2,
+ 2,
+ operand[i].exp.X_add_symbol,
+ operand[i].exp.X_subtract_symbol,
+ operand[i].exp.X_add_number,
+ 0,
+ R_MOVB1);
+ break;
+
+ case ABS16ORREL8SRC:
+ check_operand(operand+i, 0xffff,"@");
+
+ fix_new(frag_now,
+ output - frag_now->fr_literal + 2,
+ 2,
+ operand[i].exp.X_add_symbol,
+ operand[i].exp.X_subtract_symbol,
+ operand[i].exp.X_add_number,
+ 0,
+ R_JMP1);
+ break;
+
+
+ case ABS16SRC:
+ case ABS16DST:
+ case IMM16:
+ case DISPSRC:
+ case DISPDST:
+ check_operand(operand+i, 0xffff,"@");
+ if (operand[i].exp.X_add_symbol == 0)
+ {
+ /* This should be done with bfd */
+ output[3] = operand[i].exp.X_add_number & 0xff;
+ output[2] = operand[i].exp.X_add_number >> 8;
+
+ }
+ else
+ {
+
+ fix_new(frag_now,
+ output - frag_now->fr_literal + 2,
+ 2,
+ operand[i].exp.X_add_symbol,
+ operand[i].exp.X_subtract_symbol,
+ operand[i].exp.X_add_number,
+ 0,
+ R_RELWORD);
+ }
+
+ break;
+ case RS8:
+ case RD8:
+ case RS16:
+ case RD16:
+ case RDDEC:
+ case KBIT:
+ case RSINC:
+ case RDIND:
+ case RSIND:
+ case CCR:
+
+ break;
+ default:
+ abort();
+ }
+ }
+
+}
+/*
+ try and give an intelligent error message for common and simple to
+ detect errors
+ */
+
+static void
+ DEFUN(clever_message, (opcode, operand),
+ struct h8_opcode *opcode AND
+ struct h8_op *operand)
+{
+ struct h8_opcode *scan = opcode;
+
+ /* Find out if there was more than one possible opccode */
+
+ if ((opcode+1)->idx != opcode->idx)
+ {
+ unsigned int argn;
+
+ /* Only one opcode of this flavour, try and guess which operand
+ didn't match */
+ for (argn = 0; argn < opcode->noperands; argn++)
+ {
+ switch (opcode->args.nib[argn])
+ {
+ case RD16:
+ if (operand[argn].mode != RD16)
+ {
+ as_bad("destination operand must be 16 bit register");
+ }
+ return;
+ case RS8:
+
+ if (operand[argn].mode != RS8)
+ {
+ as_bad("source operand must be 8 bit register");
+ }
+ return;
+ case ABS16DST:
+ if (operand[argn].mode != ABS16DST)
+ {
+ as_bad("destination operand must be 16bit absolute address");
+ return;
+ }
+
+ case RD8:
+ if (operand[argn].mode != RD8)
+ {
+ as_bad("destination operand must be 8 bit register");
+ }
+ return;
+
+ case ABS16SRC:
+ if (operand[argn].mode != ABS16SRC)
+ {
+ as_bad("source operand must be 16bit absolute address");
+ return;
+ }
+ }
+ }
+ }
+ as_bad("invalid operands");
+}
+
+/* This is the guts of the machine-dependent assembler. STR points to a
+ machine dependent instruction. This funciton is supposed to emit
+ the frags/bytes it assembles to.
+ */
+
+
+
+void
+ DEFUN(md_assemble,(str),
+ char *str)
+{
+ char *op_start;
+ char *op_end;
+ unsigned int i;
+ struct h8_op operand[2];
+ struct h8_opcode * opcode;
+ struct h8_opcode * prev_opcode;
+
+ char *dot = 0;
+ char c;
+ /* Drop leading whitespace */
+ while (*str == ' ')
+ str++;
+
+ /* find the op code end */
+ for (op_start = op_end = str;
+ *op_end != 0 && *op_end != ' ';
+ op_end ++)
+ {
+ if (*op_end == '.') {
+ dot = op_end+1;
+ *op_end = 0;
+ op_end+=2;
+ break;
+ }
+ }
+
+ ;
+
+ if (op_end == op_start)
+ {
+ as_bad("can't find opcode ");
+ }
+ c = *op_end;
+
+ *op_end = 0;
+
+ opcode = (struct h8_opcode *) hash_find(opcode_hash_control,
+ op_start);
+
+ if (opcode == NULL)
+ {
+ as_bad("unknown opcode");
+ return;
+ }
+
+
+ input_line_pointer = get_operands(opcode->noperands, op_end,
+ operand);
+ *op_end = c;
+ prev_opcode = opcode;
+
+ opcode = get_specific(opcode, operand);
+
+ if (opcode == 0)
+ {
+ /* Couldn't find an opcode which matched the operands */
+ char *where =frag_more(2);
+ where[0] = 0x0;
+ where[1] = 0x0;
+ clever_message(prev_opcode, operand);
+
+ return;
+ }
+ if (opcode->size && dot)
+ {
+ if (opcode->size != *dot)
+ {
+ as_warn("mismatch between opcode size and operand size");
+ }
+ }
+
+ build_bytes(opcode, operand);
+
+}
+
+void
+ DEFUN(tc_crawl_symbol_chain, (headers),
+ object_headers *headers)
+{
+ printf("call to tc_crawl_symbol_chain \n");
+}
+
+symbolS *DEFUN(md_undefined_symbol,(name),
+ char *name)
+{
+ return 0;
+}
+
+void
+ DEFUN(tc_headers_hook,(headers),
+ object_headers *headers)
+{
+ printf("call to tc_headers_hook \n");
+}
+void
+ DEFUN_VOID(md_end)
+{
+}
+
+/* Various routines to kill one day */
+/* Equal to MAX_PRECISION in atof-ieee.c */
+#define MAX_LITTLENUMS 6
+
+/* Turn a string in input_line_pointer into a floating point constant of type
+ type, and store the appropriate bytes in *litP. The number of LITTLENUMS
+ emitted is stored in *sizeP. An error message is returned, or NULL on OK.
+ */
+char *
+ md_atof(type,litP,sizeP)
+char type;
+char *litP;
+int *sizeP;
+{
+ int prec;
+ LITTLENUM_TYPE words[MAX_LITTLENUMS];
+ LITTLENUM_TYPE *wordP;
+ char *t;
+ char *atof_ieee();
+
+ switch (type) {
+ case 'f':
+ case 'F':
+ case 's':
+ case 'S':
+ prec = 2;
+ break;
+
+ case 'd':
+ case 'D':
+ case 'r':
+ case 'R':
+ prec = 4;
+ break;
+
+ case 'x':
+ case 'X':
+ prec = 6;
+ break;
+
+ case 'p':
+ case 'P':
+ prec = 6;
+ break;
+
+ default:
+ *sizeP=0;
+ return "Bad call to MD_ATOF()";
+ }
+ t=atof_ieee(input_line_pointer,type,words);
+ if (t)
+ input_line_pointer=t;
+
+ *sizeP=prec * sizeof(LITTLENUM_TYPE);
+ for (wordP=words;prec--;) {
+ md_number_to_chars(litP,(long)(*wordP++),sizeof(LITTLENUM_TYPE));
+ litP+=sizeof(LITTLENUM_TYPE);
+ }
+ return ""; /* Someone should teach Dean about null pointers */
+}
+
+int
+ md_parse_option(argP, cntP, vecP)
+char **argP;
+int *cntP;
+char ***vecP;
+
+{
+ return 0;
+
+}
+
+int md_short_jump_size;
+
+void tc_aout_fix_to_chars () { printf("call to tc_aout_fix_to_chars \n");
+ abort(); }
+void md_create_short_jump(ptr, from_addr, to_addr, frag, to_symbol)
+char *ptr;
+long from_addr;
+long to_addr;
+fragS *frag;
+symbolS *to_symbol;
+{
+ as_fatal("failed sanity check.");
+}
+
+void
+ md_create_long_jump(ptr,from_addr,to_addr,frag,to_symbol)
+char *ptr;
+long from_addr, to_addr;
+fragS *frag;
+symbolS *to_symbol;
+{
+ as_fatal("failed sanity check.");
+}
+
+void
+ md_convert_frag(headers, fragP)
+object_headers *headers;
+fragS * fragP;
+
+{ printf("call to md_convert_frag \n"); abort(); }
+
+long
+ DEFUN(md_section_align,(seg, size),
+ segT seg AND
+ long size)
+{
+ return((size + (1 << section_alignment[(int) seg]) - 1) & (-1 << section_alignment[(int) seg]));
+
+}
+
+void
+ md_apply_fix(fixP, val)
+fixS *fixP;
+long val;
+{
+ char *buf = fixP->fx_where + fixP->fx_frag->fr_literal;
+
+ switch (fixP->fx_size) {
+ case 1:
+ *buf++=val;
+ break;
+ case 2:
+ *buf++=(val>>8);
+ *buf++=val;
+ break;
+ case 4:
+ *buf++=(val>>24);
+ *buf++=(val>>16);
+ *buf++=(val>>8);
+ *buf++=val;
+ break;
+ default:
+ abort();
+
+ }
+}
+
+void DEFUN(md_operand, (expressionP),expressionS *expressionP)
+{ }
+
+int md_long_jump_size;
+int
+ md_estimate_size_before_relax(fragP, segment_type)
+register fragS *fragP;
+register segT segment_type;
+{
+ printf("call tomd_estimate_size_before_relax \n"); abort(); }
+/* Put number into target byte order */
+
+void DEFUN(md_number_to_chars,(ptr, use, nbytes),
+ char *ptr AND
+ long use AND
+ int nbytes)
+{
+ switch (nbytes) {
+ case 4: *ptr++ = (use >> 24) & 0xff;
+ case 3: *ptr++ = (use >> 16) & 0xff;
+ case 2: *ptr++ = (use >> 8) & 0xff;
+ case 1: *ptr++ = (use >> 0) & 0xff;
+ break;
+ default:
+ abort();
+ }
+}
+long md_pcrel_from(fixP)
+fixS *fixP; { abort(); }
+
+void tc_coff_symbol_emit_hook() { }
+
+
+void tc_reloc_mangle(fix_ptr, intr, base)
+fixS *fix_ptr;
+struct internal_reloc *intr;
+bfd_vma base;
+
+{
+ symbolS *symbol_ptr;
+
+ symbol_ptr = fix_ptr->fx_addsy;
+
+ /* If this relocation is attached to a symbol then it's ok
+ to output it */
+ if (fix_ptr->fx_r_type == RELOC_32) {
+ /* cons likes to create reloc32's whatever the size of the reloc..
+ */
+ switch (fix_ptr->fx_size)
+ {
+
+ case 2:
+ intr->r_type = R_RELWORD;
+ break;
+ case 1:
+ intr->r_type = R_RELBYTE;
+ break;
+ default:
+ abort();
+
+ }
+
+ }
+ else {
+ intr->r_type = fix_ptr->fx_r_type;
+ }
+
+ intr->r_vaddr = fix_ptr->fx_frag->fr_address + fix_ptr->fx_where +base;
+ intr->r_offset = fix_ptr->fx_offset;
+
+ if (symbol_ptr)
+ intr->r_symndx = symbol_ptr->sy_number;
+ else
+ intr->r_symndx = -1;
+
+
+}
+
+/* end of tc-h8300.c */
diff --git a/gnu/usr.bin/as/config/tc-h8300.h b/gnu/usr.bin/as/config/tc-h8300.h
new file mode 100644
index 0000000..dc01f6c
--- /dev/null
+++ b/gnu/usr.bin/as/config/tc-h8300.h
@@ -0,0 +1,38 @@
+/* This file is tc-h8300.h
+
+ Copyright (C) 1987-1992 Free Software Foundation, Inc.
+
+ This file is part of GAS, the GNU Assembler.
+
+ GAS is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GAS is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GAS; see the file COPYING. If not, write to
+ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+
+#define TC_H8300
+
+/* This macro translates between an internal fix and an coff reloc type */
+#define TC_COFF_FIX2RTYPE(fixP) abort();
+
+#define BFD_ARCH bfd_arch_h8300
+#define COFF_MAGIC 0x8300
+#define TC_COUNT_RELOC(x) (1)
+
+
+#define TC_RELOC_MANGLE(a,b,c) tc_reloc_mangle(a,b,c)
+
+#define DO_NOT_STRIP 1
+#define DO_STRIP 0
+#define LISTING_HEADER "Hitachi H8/300 GAS "
+
+/* end of tc-h8300.h */
diff --git a/gnu/usr.bin/as/config/tc-i386.c b/gnu/usr.bin/as/config/tc-i386.c
new file mode 100644
index 0000000..7aa2174
--- /dev/null
+++ b/gnu/usr.bin/as/config/tc-i386.c
@@ -0,0 +1,2338 @@
+/* i386.c -- Assemble code for the Intel 80386
+ Copyright (C) 1989, 1991, 1992 Free Software Foundation.
+
+ This file is part of GAS, the GNU Assembler.
+
+ GAS is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GAS is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GAS; see the file COPYING. If not, write to
+ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/*
+ Intel 80386 machine specific gas.
+ Written by Eliot Dresselhaus (eliot@mgm.mit.edu).
+ Bugs & suggestions are completely welcome. This is free software.
+ Please help us make it better.
+ */
+
+#ifndef lint
+static char rcsid[] = "$Id: tc-i386.c,v 1.3 1994/12/23 22:37:35 nate Exp $";
+#endif
+
+#include "as.h"
+
+#include "obstack.h"
+#include "opcode/i386.h"
+
+/* 'md_assemble ()' gathers together information and puts it into a
+ i386_insn. */
+
+typedef struct {
+ /* TM holds the template for the insn were currently assembling. */
+ template tm;
+ /* SUFFIX holds the opcode suffix (e.g. 'l' for 'movl') if given. */
+ char suffix;
+ /* Operands are coded with OPERANDS, TYPES, DISPS, IMMS, and REGS. */
+
+ /* OPERANDS gives the number of given operands. */
+ unsigned int operands;
+
+ /* REG_OPERANDS, DISP_OPERANDS, MEM_OPERANDS, IMM_OPERANDS give the number of
+ given register, displacement, memory operands and immediate operands. */
+ unsigned int reg_operands, disp_operands, mem_operands, imm_operands;
+
+ /* TYPES [i] is the type (see above #defines) which tells us how to
+ search through DISPS [i] & IMMS [i] & REGS [i] for the required
+ operand. */
+ unsigned int types[MAX_OPERANDS];
+
+ /* Displacements (if given) for each operand. */
+ expressionS *disps[MAX_OPERANDS];
+
+#ifdef PIC
+ /* Relocation type for operand */
+ enum reloc_type disp_reloc[MAX_OPERANDS];
+#endif
+
+ /* Immediate operands (if given) for each operand. */
+ expressionS *imms[MAX_OPERANDS];
+
+ /* Register operands (if given) for each operand. */
+ reg_entry *regs[MAX_OPERANDS];
+
+ /* BASE_REG, INDEX_REG, and LOG2_SCALE_FACTOR are used to encode
+ the base index byte below. */
+ reg_entry *base_reg;
+ reg_entry *index_reg;
+ unsigned int log2_scale_factor;
+
+ /* SEG gives the seg_entry of this insn. It is equal to zero unless
+ an explicit segment override is given. */
+ const seg_entry *seg; /* segment for memory operands (if given) */
+
+ /* PREFIX holds all the given prefix opcodes (usually null).
+ PREFIXES is the size of PREFIX. */
+ /* richfix: really unsigned? */
+ unsigned char prefix[MAX_PREFIXES];
+ unsigned int prefixes;
+
+ /* RM and IB are the modrm byte and the base index byte where the addressing
+ modes of this insn are encoded. */
+
+ modrm_byte rm;
+ base_index_byte bi;
+
+} i386_insn;
+
+/* This array holds the chars that always start a comment. If the
+ pre-processor is disabled, these aren't very useful */
+const char comment_chars[] = "#";
+
+/* This array holds the chars that only start a comment at the beginning of
+ a line. If the line seems to have the form '# 123 filename'
+ .line and .file directives will appear in the pre-processed output */
+/* Note that input_file.c hand checks for '#' at the beginning of the
+ first line of the input file. This is because the compiler outputs
+ #NO_APP at the beginning of its output. */
+/* Also note that comments started like this one will always work if
+ '/' isn't otherwise defined. */
+const char line_comment_chars[] = "#/"; /* removed '#' xoxorich. */
+
+/* Chars that can be used to separate mant from exp in floating point nums */
+const char EXP_CHARS[] = "eE";
+
+/* Chars that mean this number is a floating point constant */
+/* As in 0f12.456 */
+/* or 0d1.2345e12 */
+const char FLT_CHARS[] = "fFdDxX";
+
+/* tables for lexical analysis */
+static char opcode_chars[256];
+static char register_chars[256];
+static char operand_chars[256];
+static char space_chars[256];
+static char identifier_chars[256];
+static char digit_chars[256];
+
+/* lexical macros */
+#define is_opcode_char(x) (opcode_chars[(unsigned char) x])
+#define is_operand_char(x) (operand_chars[(unsigned char) x])
+#define is_register_char(x) (register_chars[(unsigned char) x])
+#define is_space_char(x) (space_chars[(unsigned char) x])
+#define is_identifier_char(x) (identifier_chars[(unsigned char) x])
+#define is_digit_char(x) (digit_chars[(unsigned char) x])
+
+/* put here all non-digit non-letter charcters that may occur in an operand */
+static char operand_special_chars[] = "%$-+(,)*._~/<>|&^!:";
+
+static char *ordinal_names[] = { "first", "second", "third" }; /* for printfs */
+
+/* md_assemble() always leaves the strings it's passed unaltered. To
+ effect this we maintain a stack of saved characters that we've smashed
+ with '\0's (indicating end of strings for various sub-fields of the
+ assembler instruction). */
+static char save_stack[32];
+static char *save_stack_p; /* stack pointer */
+#define END_STRING_AND_SAVE(s) *save_stack_p++ = *s; *s = '\0'
+#define RESTORE_END_STRING(s) *s = *--save_stack_p
+
+ /* The instruction we're assembling. */
+ static i386_insn i;
+
+/* Per instruction expressionS buffers: 2 displacements & 2 immediate max. */
+static expressionS disp_expressions[2], im_expressions[2];
+
+/* pointers to ebp & esp entries in reg_hash hash table */
+static reg_entry *ebp, *esp;
+
+static int this_operand; /* current operand we are working on */
+
+/*
+ Interface to relax_segment.
+ There are 2 relax states for 386 jump insns: one for conditional & one
+ for unconditional jumps. This is because the these two types of jumps
+ add different sizes to frags when we're figuring out what sort of jump
+ to choose to reach a given label. */
+
+/* types */
+#define COND_JUMP 1 /* conditional jump */
+#define UNCOND_JUMP 2 /* unconditional jump */
+/* sizes */
+#define BYTE 0
+#define WORD 1
+#define DWORD 2
+#define UNKNOWN_SIZE 3
+
+#define ENCODE_RELAX_STATE(type,size) ((type<<2) | (size))
+#define SIZE_FROM_RELAX_STATE(s) \
+ ( (((s) & 0x3) == BYTE ? 1 : (((s) & 0x3) == WORD ? 2 : 4)) )
+
+const relax_typeS md_relax_table[] = {
+ /*
+ The fields are:
+ 1) most positive reach of this state,
+ 2) most negative reach of this state,
+ 3) how many bytes this mode will add to the size of the current frag
+ 4) which index into the table to try if we can't fit into this one.
+ */
+ {1, 1, 0, 0},
+ {1, 1, 0, 0},
+ {1, 1, 0, 0},
+ {1, 1, 0, 0},
+
+ /* For now we don't use word displacement jumps: they may be
+ untrustworthy. */
+ {127+1, -128+1, 0, ENCODE_RELAX_STATE(COND_JUMP,DWORD) },
+ /* word conditionals add 3 bytes to frag:
+ 2 opcode prefix; 1 displacement bytes */
+ {32767+2, -32768+2, 3, ENCODE_RELAX_STATE(COND_JUMP,DWORD) },
+ /* dword conditionals adds 4 bytes to frag:
+ 1 opcode prefix; 3 displacement bytes */
+ {0, 0, 4, 0},
+ {1, 1, 0, 0},
+
+ {127+1, -128+1, 0, ENCODE_RELAX_STATE(UNCOND_JUMP,DWORD) },
+ /* word jmp adds 2 bytes to frag:
+ 1 opcode prefix; 1 displacement bytes */
+ {32767+2, -32768+2, 2, ENCODE_RELAX_STATE(UNCOND_JUMP,DWORD) },
+ /* dword jmp adds 3 bytes to frag:
+ 0 opcode prefix; 3 displacement bytes */
+ {0, 0, 3, 0},
+ {1, 1, 0, 0},
+
+};
+
+#if __STDC__ == 1
+
+static char *output_invalid(int c);
+static int fits_in_signed_byte(long num);
+static int fits_in_signed_word(long num);
+static int fits_in_unsigned_byte(long num);
+static int fits_in_unsigned_word(long num);
+static int i386_operand(char *operand_string);
+static int smallest_imm_type(long num);
+static reg_entry *parse_register(char *reg_string);
+static unsigned long mode_from_disp_size(unsigned long t);
+static unsigned long opcode_suffix_to_type(unsigned long s);
+static void s_bss(void);
+
+#else /* not __STDC__ */
+
+static char *output_invalid();
+static int fits_in_signed_byte();
+static int fits_in_signed_word();
+static int fits_in_unsigned_byte();
+static int fits_in_unsigned_word();
+static int i386_operand();
+static int smallest_imm_type();
+static reg_entry *parse_register();
+static unsigned long mode_from_disp_size();
+static unsigned long opcode_suffix_to_type();
+static void s_bss();
+
+#endif /* not __STDC__ */
+
+
+/* Ignore certain directives generated by gcc. This probably should
+ not be here. */
+void dummy ()
+{
+ while (*input_line_pointer && *input_line_pointer != '\n')
+ input_line_pointer++;
+}
+
+const pseudo_typeS md_pseudo_table[] = {
+ { "bss", s_bss, 0 },
+
+#ifndef OLD_GAS
+ { "align", s_align_bytes, 0 },
+#else /* OLD_GAS */
+ { "align", s_align_ptwo, 0 },
+#endif /* OLD_GAS */
+
+ { "ffloat", float_cons, 'f' },
+ { "dfloat", float_cons, 'd' },
+ { "tfloat", float_cons, 'x' },
+ { "value", cons, 2 },
+ { 0, 0, 0 }
+};
+
+/* for interface with expression () */
+extern char * input_line_pointer;
+
+/* obstack for constructing various things in md_begin */
+struct obstack o;
+
+/* hash table for opcode lookup */
+static struct hash_control *op_hash = (struct hash_control *) 0;
+/* hash table for register lookup */
+static struct hash_control *reg_hash = (struct hash_control *) 0;
+/* hash table for prefix lookup */
+static struct hash_control *prefix_hash = (struct hash_control *) 0;
+
+
+void md_begin ()
+{
+ char * hash_err;
+
+ obstack_begin (&o,4096);
+
+ /* initialize op_hash hash table */
+ op_hash = hash_new(); /* xmalloc handles error */
+
+ {
+ register const template *optab;
+ register templates *core_optab;
+ char *prev_name;
+
+ optab = i386_optab; /* setup for loop */
+ prev_name = optab->name;
+ obstack_grow (&o, optab, sizeof(template));
+ core_optab = (templates *) xmalloc (sizeof (templates));
+
+ for (optab++; optab < i386_optab_end; optab++) {
+ if (! strcmp (optab->name, prev_name)) {
+ /* same name as before --> append to current template list */
+ obstack_grow (&o, optab, sizeof(template));
+ } else {
+ /* different name --> ship out current template list;
+ add to hash table; & begin anew */
+ /* Note: end must be set before start! since obstack_next_free changes
+ upon opstack_finish */
+ core_optab->end = (template *) obstack_next_free(&o);
+ core_optab->start = (template *) obstack_finish(&o);
+ hash_err = hash_insert (op_hash, prev_name, (char *) core_optab);
+ if (hash_err && *hash_err) {
+ hash_error:
+ as_fatal("Internal Error: Can't hash %s: %s", prev_name, hash_err);
+ }
+ prev_name = optab->name;
+ core_optab = (templates *) xmalloc (sizeof(templates));
+ obstack_grow (&o, optab, sizeof(template));
+ }
+ }
+ }
+
+ /* initialize reg_hash hash table */
+ reg_hash = hash_new();
+ {
+ register const reg_entry *regtab;
+
+ for (regtab = i386_regtab; regtab < i386_regtab_end; regtab++) {
+ hash_err = hash_insert (reg_hash, regtab->reg_name, regtab);
+ if (hash_err && *hash_err) goto hash_error;
+ }
+ }
+
+ esp = (reg_entry *) hash_find (reg_hash, "esp");
+ ebp = (reg_entry *) hash_find (reg_hash, "ebp");
+
+ /* initialize reg_hash hash table */
+ prefix_hash = hash_new();
+ {
+ register const prefix_entry *prefixtab;
+
+ for (prefixtab = i386_prefixtab;
+ prefixtab < i386_prefixtab_end; prefixtab++) {
+ hash_err = hash_insert (prefix_hash, prefixtab->prefix_name, prefixtab);
+ if (hash_err && *hash_err) goto hash_error;
+ }
+ }
+
+ /* fill in lexical tables: opcode_chars, operand_chars, space_chars */
+ {
+ register unsigned int c;
+
+ memset(opcode_chars, '\0', sizeof(opcode_chars));
+ memset(operand_chars, '\0', sizeof(operand_chars));
+ memset(space_chars, '\0', sizeof(space_chars));
+ memset(identifier_chars, '\0', sizeof(identifier_chars));
+ memset(digit_chars, '\0', sizeof(digit_chars));
+
+ for (c = 0; c < 256; c++) {
+ if (islower(c) || isdigit(c)) {
+ opcode_chars[c] = c;
+ register_chars[c] = c;
+ } else if (isupper(c)) {
+ opcode_chars[c] = tolower(c);
+ register_chars[c] = opcode_chars[c];
+ } else if (c == PREFIX_SEPERATOR) {
+ opcode_chars[c] = c;
+ } else if (c == ')' || c == '(') {
+ register_chars[c] = c;
+ }
+
+ if (isupper(c) || islower(c) || isdigit(c))
+ operand_chars[c] = c;
+ else if (c && strchr(operand_special_chars, c))
+ operand_chars[c] = c;
+
+ if (isdigit(c) || c == '-') digit_chars[c] = c;
+
+ if (isalpha(c) || c == '_' || c == '.' || isdigit(c))
+ identifier_chars[c] = c;
+
+ if (c == ' ' || c == '\t') space_chars[c] = c;
+ }
+ }
+}
+
+void md_end() {} /* not much to do here. */
+
+
+#define DEBUG386
+#ifdef DEBUG386
+
+/* debugging routines for md_assemble */
+static void pi (), pte (), pt (), pe (), ps ();
+
+static void pi (line, x)
+char * line;
+i386_insn *x;
+{
+ register template *p;
+ int i;
+
+ fprintf (stdout, "%s: template ", line);
+ pte (&x->tm);
+ fprintf (stdout, " modrm: mode %x reg %x reg/mem %x",
+ x->rm.mode, x->rm.reg, x->rm.regmem);
+ fprintf (stdout, " base %x index %x scale %x\n",
+ x->bi.base, x->bi.index, x->bi.scale);
+ for (i = 0; i < x->operands; i++) {
+ fprintf (stdout, " #%d: ", i+1);
+ pt (x->types[i]);
+ fprintf (stdout, "\n");
+ if (x->types[i] & Reg) fprintf (stdout, "%s\n", x->regs[i]->reg_name);
+ if (x->types[i] & Imm) pe (x->imms[i]);
+ if (x->types[i] & (Disp|Abs)) pe (x->disps[i]);
+ }
+}
+
+static void pte (t)
+template *t;
+{
+ int i;
+ fprintf (stdout, " %d operands ", t->operands);
+ fprintf (stdout, "opcode %x ",
+ t->base_opcode);
+ if (t->extension_opcode != None)
+ fprintf (stdout, "ext %x ", t->extension_opcode);
+ if (t->opcode_modifier&D)
+ fprintf (stdout, "D");
+ if (t->opcode_modifier&W)
+ fprintf (stdout, "W");
+ fprintf (stdout, "\n");
+ for (i = 0; i < t->operands; i++) {
+ fprintf (stdout, " #%d type ", i+1);
+ pt (t->operand_types[i]);
+ fprintf (stdout, "\n");
+ }
+}
+
+static void pe (e)
+expressionS *e;
+{
+ fprintf (stdout, " segment %s\n", segment_name (e->X_seg));
+ fprintf (stdout, " add_number %d (%x)\n",
+ e->X_add_number, e->X_add_number);
+ if (e->X_add_symbol) {
+ fprintf (stdout, " add_symbol ");
+ ps (e->X_add_symbol);
+ fprintf (stdout, "\n");
+ }
+ if (e->X_subtract_symbol) {
+ fprintf (stdout, " sub_symbol ");
+ ps (e->X_subtract_symbol);
+ fprintf (stdout, "\n");
+ }
+}
+
+static void ps (s)
+symbolS *s;
+{
+ fprintf (stdout, "%s type %s%s",
+ S_GET_NAME(s),
+ S_IS_EXTERNAL(s) ? "EXTERNAL " : "",
+ segment_name(S_GET_SEGMENT(s)));
+}
+
+struct type_name {
+ unsigned int mask;
+ char *tname;
+} type_names[] = {
+ { Reg8, "r8" }, { Reg16, "r16" }, { Reg32, "r32" }, { Imm8, "i8" },
+ { Imm8S, "i8s" },
+ { Imm16, "i16" }, { Imm32, "i32" }, { Mem8, "Mem8"}, { Mem16, "Mem16"},
+ { Mem32, "Mem32"}, { BaseIndex, "BaseIndex" },
+ { Abs8, "Abs8" }, { Abs16, "Abs16" }, { Abs32, "Abs32" },
+ { Disp8, "d8" }, { Disp16, "d16" },
+ { Disp32, "d32" }, { SReg2, "SReg2" }, { SReg3, "SReg3" }, { Acc, "Acc" },
+ { InOutPortReg, "InOutPortReg" }, { ShiftCount, "ShiftCount" },
+ { Imm1, "i1" }, { Control, "control reg" }, {Test, "test reg"},
+ { FloatReg, "FReg"}, {FloatAcc, "FAcc"},
+ { JumpAbsolute, "Jump Absolute"},
+ { 0, "" }
+};
+
+static void pt (t)
+unsigned int t;
+{
+ register struct type_name *ty;
+
+ if (t == Unknown) {
+ fprintf (stdout, "Unknown");
+ } else {
+ for (ty = type_names; ty->mask; ty++)
+ if (t & ty->mask) fprintf (stdout, "%s, ", ty->tname);
+ }
+ fflush (stdout);
+}
+
+#endif /* DEBUG386 */
+
+/*
+ This is the guts of the machine-dependent assembler. LINE points to a
+ machine dependent instruction. This funciton is supposed to emit
+ the frags/bytes it assembles to.
+ */
+void md_assemble (line)
+char *line;
+{
+ /* Holds temlate once we've found it. */
+ register template *t;
+
+ /* Possible templates for current insn */
+ templates *current_templates = (templates *) 0;
+
+ /* Initialize globals. */
+ memset(&i, '\0', sizeof(i));
+ memset(disp_expressions, '\0', sizeof(disp_expressions));
+ memset(im_expressions, '\0', sizeof(im_expressions));
+ save_stack_p = save_stack; /* reset stack pointer */
+
+ /* Fist parse an opcode & call i386_operand for the operands.
+ We assume that the scrubber has arranged it so that line[0] is the valid
+ start of a (possibly prefixed) opcode. */
+ {
+ register char *l = line; /* Fast place to put LINE. */
+
+ /* 1 if operand is pending after ','. */
+ unsigned int expecting_operand = 0;
+ /* 1 if we found a prefix only acceptable with string insns. */
+ unsigned int expecting_string_instruction = 0;
+ /* Non-zero if operand parens not balenced. */
+ unsigned int paren_not_balenced;
+ char * token_start = l;
+
+ while (! is_space_char(*l) && *l != END_OF_INSN) {
+ if (! is_opcode_char(*l)) {
+ as_bad("invalid character %s in opcode", output_invalid(*l));
+ return;
+ } else if (*l != PREFIX_SEPERATOR) {
+ *l = opcode_chars[(unsigned char) *l]; /* fold case of opcodes */
+ l++;
+ } else { /* this opcode's got a prefix */
+ register unsigned int q;
+ register prefix_entry * prefix;
+
+ if (l == token_start) {
+ as_bad("expecting prefix; got nothing");
+ return;
+ }
+ END_STRING_AND_SAVE (l);
+ prefix = (prefix_entry *) hash_find (prefix_hash, token_start);
+ if (! prefix) {
+ as_bad("no such opcode prefix ('%s')", token_start);
+ return;
+ }
+ RESTORE_END_STRING (l);
+ /* check for repeated prefix */
+ for (q = 0; q < i.prefixes; q++)
+ if (i.prefix[q] == prefix->prefix_code) {
+ as_bad("same prefix used twice; you don't really want this!");
+ return;
+ }
+ if (i.prefixes == MAX_PREFIXES) {
+ as_bad("too many opcode prefixes");
+ return;
+ }
+ i.prefix[i.prefixes++] = prefix->prefix_code;
+ if (prefix->prefix_code == REPE || prefix->prefix_code == REPNE)
+ expecting_string_instruction = 1;
+ /* skip past PREFIX_SEPERATOR and reset token_start */
+ token_start = ++l;
+ }
+ }
+ END_STRING_AND_SAVE (l);
+ if (token_start == l) {
+ as_bad("expecting opcode; got nothing");
+ return;
+ }
+
+ /* Lookup insn in hash; try intel & att naming conventions if appropriate;
+ that is: we only use the opcode suffix 'b' 'w' or 'l' if we need to. */
+ current_templates = (templates *) hash_find (op_hash, token_start);
+ if (! current_templates) {
+ int last_index = strlen(token_start) - 1;
+ char last_char = token_start[last_index];
+ switch (last_char) {
+ case DWORD_OPCODE_SUFFIX:
+ case WORD_OPCODE_SUFFIX:
+ case BYTE_OPCODE_SUFFIX:
+ token_start[last_index] = '\0';
+ current_templates = (templates *) hash_find (op_hash, token_start);
+ token_start[last_index] = last_char;
+ i.suffix = last_char;
+ }
+ if (!current_templates) {
+ as_bad("no such 386 instruction: `%s'", token_start); return;
+ }
+ }
+ RESTORE_END_STRING (l);
+
+ /* check for rep/repne without a string instruction */
+ if (expecting_string_instruction &&
+ ! IS_STRING_INSTRUCTION (current_templates->
+ start->base_opcode)) {
+ as_bad("expecting string instruction after rep/repne");
+ return;
+ }
+
+ /* There may be operands to parse. */
+ if (*l != END_OF_INSN &&
+ /* For string instructions, we ignore any operands if given. This
+ kludges, for example, 'rep/movsb %ds:(%esi), %es:(%edi)' where
+ the operands are always going to be the same, and are not really
+ encoded in machine code. */
+ ! IS_STRING_INSTRUCTION (current_templates->
+ start->base_opcode)) {
+ /* parse operands */
+ do {
+ /* skip optional white space before operand */
+ while (! is_operand_char(*l) && *l != END_OF_INSN) {
+ if (! is_space_char(*l)) {
+ as_bad("invalid character %s before %s operand",
+ output_invalid(*l),
+ ordinal_names[i.operands]);
+ return;
+ }
+ l++;
+ }
+ token_start = l; /* after white space */
+ paren_not_balenced = 0;
+ while (paren_not_balenced || *l != ',') {
+ if (*l == END_OF_INSN) {
+ if (paren_not_balenced) {
+ as_bad("unbalenced parenthesis in %s operand.",
+ ordinal_names[i.operands]);
+ return;
+ } else break; /* we are done */
+ } else if (! is_operand_char(*l) && ! is_space_char(*l)) {
+ as_bad("invalid character %s in %s operand",
+ output_invalid(*l),
+ ordinal_names[i.operands]);
+ return;
+ }
+ if (*l == '(') ++paren_not_balenced;
+ if (*l == ')') --paren_not_balenced;
+ l++;
+ }
+ if (l != token_start) { /* yes, we've read in another operand */
+ unsigned int operand_ok;
+ this_operand = i.operands++;
+ if (i.operands > MAX_OPERANDS) {
+ as_bad("spurious operands; (%d operands/instruction max)",
+ MAX_OPERANDS);
+ return;
+ }
+ /* now parse operand adding info to 'i' as we go along */
+ END_STRING_AND_SAVE (l);
+ operand_ok = i386_operand (token_start);
+ RESTORE_END_STRING (l); /* restore old contents */
+ if (!operand_ok) return;
+ } else {
+ if (expecting_operand) {
+ expecting_operand_after_comma:
+ as_bad("expecting operand after ','; got nothing");
+ return;
+ }
+ if (*l == ',') {
+ as_bad("expecting operand before ','; got nothing");
+ return;
+ }
+ }
+
+ /* now *l must be either ',' or END_OF_INSN */
+ if (*l == ',') {
+ if (*++l == END_OF_INSN) { /* just skip it, if it's \n complain */
+ goto expecting_operand_after_comma;
+ }
+ expecting_operand = 1;
+ }
+ } while (*l != END_OF_INSN); /* until we get end of insn */
+ }
+ }
+
+ /* Now we've parsed the opcode into a set of templates, and have the
+ operands at hand.
+ Next, we find a template that matches the given insn,
+ making sure the overlap of the given operands types is consistent
+ with the template operand types. */
+
+#define MATCH(overlap,given_type) \
+ (overlap && \
+ (overlap & (JumpAbsolute|BaseIndex|Mem8)) \
+ == (given_type & (JumpAbsolute|BaseIndex|Mem8)))
+
+ /* If m0 and m1 are register matches they must be consistent
+ with the expected operand types t0 and t1.
+ That is, if both m0 & m1 are register matches
+ i.e. ( ((m0 & (Reg)) && (m1 & (Reg)) ) ?
+ then, either 1. or 2. must be true:
+ 1. the expected operand type register overlap is null:
+ (t0 & t1 & Reg) == 0
+ AND
+ the given register overlap is null:
+ (m0 & m1 & Reg) == 0
+ 2. the expected operand type register overlap == the given
+ operand type overlap: (t0 & t1 & m0 & m1 & Reg).
+ */
+#define CONSISTENT_REGISTER_MATCH(m0, m1, t0, t1) \
+ ( ((m0 & (Reg)) && (m1 & (Reg))) ? \
+ ( ((t0 & t1 & (Reg)) == 0 && (m0 & m1 & (Reg)) == 0) || \
+ ((t0 & t1) & (m0 & m1) & (Reg)) \
+ ) : 1)
+ {
+ register unsigned int overlap0, overlap1;
+ expressionS * exp;
+ unsigned int overlap2;
+ unsigned int found_reverse_match;
+
+ overlap0 = overlap1 = overlap2 = found_reverse_match = 0;
+ for (t = current_templates->start;
+ t < current_templates->end;
+ t++) {
+
+ /* must have right number of operands */
+ if (i.operands != t->operands) continue;
+ else if (!t->operands) break; /* 0 operands always matches */
+
+ overlap0 = i.types[0] & t->operand_types[0];
+ switch (t->operands) {
+ case 1:
+ if (! MATCH (overlap0,i.types[0])) continue;
+ break;
+ case 2: case 3:
+ overlap1 = i.types[1] & t->operand_types[1];
+ if (! MATCH (overlap0,i.types[0]) ||
+ ! MATCH (overlap1,i.types[1]) ||
+ ! CONSISTENT_REGISTER_MATCH(overlap0, overlap1,
+ t->operand_types[0],
+ t->operand_types[1])) {
+
+ /* check if other direction is valid ... */
+ if (! (t->opcode_modifier & COMES_IN_BOTH_DIRECTIONS))
+ continue;
+
+ /* try reversing direction of operands */
+ overlap0 = i.types[0] & t->operand_types[1];
+ overlap1 = i.types[1] & t->operand_types[0];
+ if (! MATCH (overlap0,i.types[0]) ||
+ ! MATCH (overlap1,i.types[1]) ||
+ ! CONSISTENT_REGISTER_MATCH (overlap0, overlap1,
+ t->operand_types[0],
+ t->operand_types[1])) {
+ /* does not match either direction */
+ continue;
+ }
+ /* found a reverse match here -- slip through */
+ /* found_reverse_match holds which of D or FloatD we've found */
+ found_reverse_match = t->opcode_modifier & COMES_IN_BOTH_DIRECTIONS;
+ } /* endif: not forward match */
+ /* found either forward/reverse 2 operand match here */
+ if (t->operands == 3) {
+ overlap2 = i.types[2] & t->operand_types[2];
+ if (! MATCH (overlap2,i.types[2]) ||
+ ! CONSISTENT_REGISTER_MATCH (overlap0, overlap2,
+ t->operand_types[0],
+ t->operand_types[2]) ||
+ ! CONSISTENT_REGISTER_MATCH (overlap1, overlap2,
+ t->operand_types[1],
+ t->operand_types[2]))
+ continue;
+ }
+ /* found either forward/reverse 2 or 3 operand match here:
+ slip through to break */
+ }
+ break; /* we've found a match; break out of loop */
+ } /* for (t = ... */
+ if (t == current_templates->end) { /* we found no match */
+ as_bad("operands given don't match any known 386 instruction");
+ return;
+ }
+
+ /* Copy the template we found (we may change it!). */
+ memcpy(&i.tm, t, sizeof(template));
+ t = &i.tm; /* alter new copy of template */
+
+ /* If there's no opcode suffix we try to invent one based on register
+ operands. */
+ if (! i.suffix && i.reg_operands) {
+ /* We take i.suffix from the LAST register operand specified. This
+ assumes that the last register operands is the destination register
+ operand. */
+ int o;
+ for (o = 0; o < MAX_OPERANDS; o++)
+ if (i.types[o] & Reg) {
+ i.suffix = (i.types[o] == Reg8) ? BYTE_OPCODE_SUFFIX :
+ (i.types[o] == Reg16) ? WORD_OPCODE_SUFFIX :
+ DWORD_OPCODE_SUFFIX;
+ }
+ }
+
+ /* Make still unresolved immediate matches conform to size of immediate
+ given in i.suffix. Note: overlap2 cannot be an immediate!
+ We assume this. */
+ if ((overlap0 & (Imm8|Imm8S|Imm16|Imm32))
+ && overlap0 != Imm8 && overlap0 != Imm8S
+ && overlap0 != Imm16 && overlap0 != Imm32) {
+ if (! i.suffix) {
+ as_bad("no opcode suffix given; can't determine immediate size");
+ return;
+ }
+ overlap0 &= (i.suffix == BYTE_OPCODE_SUFFIX ? (Imm8|Imm8S) :
+ (i.suffix == WORD_OPCODE_SUFFIX ? Imm16 : Imm32));
+ }
+ if ((overlap1 & (Imm8|Imm8S|Imm16|Imm32))
+ && overlap1 != Imm8 && overlap1 != Imm8S
+ && overlap1 != Imm16 && overlap1 != Imm32) {
+ if (! i.suffix) {
+ as_bad("no opcode suffix given; can't determine immediate size");
+ return;
+ }
+ overlap1 &= (i.suffix == BYTE_OPCODE_SUFFIX ? (Imm8|Imm8S) :
+ (i.suffix == WORD_OPCODE_SUFFIX ? Imm16 : Imm32));
+ }
+
+ i.types[0] = overlap0;
+ i.types[1] = overlap1;
+ i.types[2] = overlap2;
+
+ if (overlap0 & ImplicitRegister) i.reg_operands--;
+ if (overlap1 & ImplicitRegister) i.reg_operands--;
+ if (overlap2 & ImplicitRegister) i.reg_operands--;
+ if (overlap0 & Imm1) i.imm_operands = 0; /* kludge for shift insns */
+
+ if (found_reverse_match) {
+ unsigned int save;
+ save = t->operand_types[0];
+ t->operand_types[0] = t->operand_types[1];
+ t->operand_types[1] = save;
+ }
+
+ /* Finalize opcode. First, we change the opcode based on the operand
+ size given by i.suffix: we never have to change things for byte insns,
+ or when no opcode suffix is need to size the operands. */
+
+ if (! i.suffix && (t->opcode_modifier & W)) {
+ as_bad("no opcode suffix given and no register operands; can't size instruction");
+ return;
+ }
+
+ if (i.suffix && i.suffix != BYTE_OPCODE_SUFFIX) {
+ /* Select between byte and word/dword operations. */
+ if (t->opcode_modifier & W)
+ t->base_opcode |= W;
+ /* Now select between word & dword operations via the
+ operand size prefix. */
+ if (i.suffix == WORD_OPCODE_SUFFIX) {
+ if (i.prefixes == MAX_PREFIXES) {
+ as_bad("%d prefixes given and 'w' opcode suffix gives too many prefixes",
+ MAX_PREFIXES);
+ return;
+ }
+ i.prefix[i.prefixes++] = WORD_PREFIX_OPCODE;
+ }
+ }
+
+ /* For insns with operands there are more diddles to do to the opcode. */
+ if (i.operands) {
+ /* If we found a reverse match we must alter the opcode direction bit
+ found_reverse_match holds bit to set (different for int &
+ float insns). */
+
+ if (found_reverse_match) {
+ t->base_opcode |= found_reverse_match;
+ }
+
+ /*
+ The imul $imm, %reg instruction is converted into
+ imul $imm, %reg, %reg. */
+ if (t->opcode_modifier & imulKludge) {
+ i.regs[2] = i.regs[1]; /* Pretend we saw the 3 operand case. */
+ i.reg_operands = 2;
+ }
+
+ /* Certain instructions expect the destination to be in the i.rm.reg
+ field. This is by far the exceptional case. For these instructions,
+ if the source operand is a register, we must reverse the i.rm.reg
+ and i.rm.regmem fields. We accomplish this by faking that the
+ two register operands were given in the reverse order. */
+ if ((t->opcode_modifier & ReverseRegRegmem) && i.reg_operands == 2) {
+ unsigned int first_reg_operand = (i.types[0] & Reg) ? 0 : 1;
+ unsigned int second_reg_operand = first_reg_operand + 1;
+ reg_entry *tmp = i.regs[first_reg_operand];
+ i.regs[first_reg_operand] = i.regs[second_reg_operand];
+ i.regs[second_reg_operand] = tmp;
+ }
+
+ if (t->opcode_modifier & ShortForm) {
+ /* The register or float register operand is in operand 0 or 1. */
+ unsigned int o = (i.types[0] & (Reg|FloatReg)) ? 0 : 1;
+ /* Register goes in low 3 bits of opcode. */
+ t->base_opcode |= i.regs[o]->reg_num;
+ } else if (t->opcode_modifier & ShortFormW) {
+ /* Short form with 0x8 width bit. Register is always dest. operand */
+ t->base_opcode |= i.regs[1]->reg_num;
+ if (i.suffix == WORD_OPCODE_SUFFIX ||
+ i.suffix == DWORD_OPCODE_SUFFIX)
+ t->base_opcode |= 0x8;
+ } else if (t->opcode_modifier & Seg2ShortForm) {
+ if (t->base_opcode == POP_SEG_SHORT && i.regs[0]->reg_num == 1) {
+ as_bad("you can't 'pop cs' on the 386.");
+ return;
+ }
+ t->base_opcode |= (i.regs[0]->reg_num << 3);
+ } else if (t->opcode_modifier & Seg3ShortForm) {
+ /* 'push %fs' is 0x0fa0; 'pop %fs' is 0x0fa1.
+ 'push %gs' is 0x0fa8; 'pop %fs' is 0x0fa9.
+ So, only if i.regs[0]->reg_num == 5 (%gs) do we need
+ to change the opcode. */
+ if (i.regs[0]->reg_num == 5)
+ t->base_opcode |= 0x08;
+ } else if (t->opcode_modifier & Modrm) {
+ /* The opcode is completed (modulo t->extension_opcode which must
+ be put into the modrm byte.
+ Now, we make the modrm & index base bytes based on all the info
+ we've collected. */
+
+ /* i.reg_operands MUST be the number of real register operands;
+ implicit registers do not count. */
+ if (i.reg_operands == 2) {
+ unsigned int source, dest;
+ source = (i.types[0] & (Reg|SReg2|SReg3|Control|Debug|Test)) ? 0 : 1;
+ dest = source + 1;
+ i.rm.mode = 3;
+ /* We must be careful to make sure that all segment/control/test/
+ debug registers go into the i.rm.reg field (despite the whether
+ they are source or destination operands). */
+ if (i.regs[dest]->reg_type & (SReg2|SReg3|Control|Debug|Test)) {
+ i.rm.reg = i.regs[dest]->reg_num;
+ i.rm.regmem = i.regs[source]->reg_num;
+ } else {
+ i.rm.reg = i.regs[source]->reg_num;
+ i.rm.regmem = i.regs[dest]->reg_num;
+ }
+ } else { /* if it's not 2 reg operands... */
+ if (i.mem_operands) {
+ unsigned int fake_zero_displacement = 0;
+ unsigned int o = (i.types[0] & Mem) ? 0 : ((i.types[1] & Mem) ? 1 : 2);
+
+ /* Encode memory operand into modrm byte and base index byte. */
+
+ if (i.base_reg == esp && ! i.index_reg) {
+ /* <disp>(%esp) becomes two byte modrm with no index register. */
+ i.rm.regmem = ESCAPE_TO_TWO_BYTE_ADDRESSING;
+ i.rm.mode = mode_from_disp_size(i.types[o]);
+ i.bi.base = ESP_REG_NUM;
+ i.bi.index = NO_INDEX_REGISTER;
+ i.bi.scale = 0; /* Must be zero! */
+ } else if (i.base_reg == ebp && !i.index_reg) {
+ if (! (i.types[o] & Disp)) {
+ /* Must fake a zero byte displacement.
+ There is no direct way to code '(%ebp)' directly. */
+ fake_zero_displacement = 1;
+ /* fake_zero_displacement code does not set this. */
+ i.types[o] |= Disp8;
+ }
+ i.rm.mode = mode_from_disp_size(i.types[o]);
+ i.rm.regmem = EBP_REG_NUM;
+ } else if (! i.base_reg && (i.types[o] & BaseIndex)) {
+ /* There are three cases here.
+ Case 1: '<32bit disp>(,1)' -- indirect absolute.
+ (Same as cases 2 & 3 with NO index register)
+ Case 2: <32bit disp> (,<index>) -- no base register with disp
+ Case 3: (, <index>) --- no base register;
+ no disp (must add 32bit 0 disp). */
+ i.rm.regmem = ESCAPE_TO_TWO_BYTE_ADDRESSING;
+ i.rm.mode = 0; /* 32bit mode */
+ i.bi.base = NO_BASE_REGISTER;
+ i.types[o] &= ~Disp;
+ i.types[o] |= Disp32; /* Must be 32bit! */
+ if (i.index_reg) { /* case 2 or case 3 */
+ i.bi.index = i.index_reg->reg_num;
+ i.bi.scale = i.log2_scale_factor;
+ if (i.disp_operands == 0)
+ fake_zero_displacement = 1; /* case 3 */
+ } else {
+ i.bi.index = NO_INDEX_REGISTER;
+ i.bi.scale = 0;
+ }
+ } else if (i.disp_operands && !i.base_reg && !i.index_reg) {
+ /* Operand is just <32bit disp> */
+ i.rm.regmem = EBP_REG_NUM;
+ i.rm.mode = 0;
+ i.types[o] &= ~Disp;
+ i.types[o] |= Disp32;
+ } else {
+ /* It's not a special case; rev'em up. */
+ i.rm.regmem = i.base_reg->reg_num;
+ i.rm.mode = mode_from_disp_size(i.types[o]);
+ if (i.index_reg) {
+ i.rm.regmem = ESCAPE_TO_TWO_BYTE_ADDRESSING;
+ i.bi.base = i.base_reg->reg_num;
+ i.bi.index = i.index_reg->reg_num;
+ i.bi.scale = i.log2_scale_factor;
+ if (i.base_reg == ebp && i.disp_operands == 0) { /* pace */
+ fake_zero_displacement = 1;
+ i.types[o] |= Disp8;
+ i.rm.mode = mode_from_disp_size(i.types[o]);
+ }
+ }
+ }
+ if (fake_zero_displacement) {
+ /* Fakes a zero displacement assuming that i.types[o] holds
+ the correct displacement size. */
+ exp = &disp_expressions[i.disp_operands++];
+ i.disps[o] = exp;
+ exp->X_seg = SEG_ABSOLUTE;
+ exp->X_add_number = 0;
+ exp->X_add_symbol = (symbolS *) 0;
+ exp->X_subtract_symbol = (symbolS *) 0;
+ }
+
+ /* Select the correct segment for the memory operand. */
+ if (i.seg) {
+ unsigned int seg_index;
+ const seg_entry *default_seg;
+
+ if (i.rm.regmem == ESCAPE_TO_TWO_BYTE_ADDRESSING) {
+ seg_index = (i.rm.mode<<3) | i.bi.base;
+ default_seg = two_byte_segment_defaults[seg_index];
+ } else {
+ seg_index = (i.rm.mode<<3) | i.rm.regmem;
+ default_seg = one_byte_segment_defaults[seg_index];
+ }
+ /* If the specified segment is not the default, use an
+ opcode prefix to select it */
+ if (i.seg != default_seg) {
+ if (i.prefixes == MAX_PREFIXES) {
+ as_bad("%d prefixes given and %s segment override gives too many prefixes",
+ MAX_PREFIXES, i.seg->seg_name);
+ return;
+ }
+ i.prefix[i.prefixes++] = i.seg->seg_prefix;
+ }
+ }
+ }
+
+ /* Fill in i.rm.reg or i.rm.regmem field with register operand
+ (if any) based on t->extension_opcode. Again, we must be careful
+ to make sure that segment/control/debug/test registers are coded
+ into the i.rm.reg field. */
+ if (i.reg_operands) {
+ unsigned int o =
+ (i.types[0] & (Reg|SReg2|SReg3|Control|Debug|Test)) ? 0 :
+ (i.types[1] & (Reg|SReg2|SReg3|Control|Debug|Test)) ? 1 : 2;
+ /* If there is an extension opcode to put here, the register number
+ must be put into the regmem field. */
+ if (t->extension_opcode != None)
+ i.rm.regmem = i.regs[o]->reg_num;
+ else i.rm.reg = i.regs[o]->reg_num;
+
+ /* Now, if no memory operand has set i.rm.mode = 0, 1, 2
+ we must set it to 3 to indicate this is a register operand
+ int the regmem field */
+ if (! i.mem_operands) i.rm.mode = 3;
+ }
+
+ /* Fill in i.rm.reg field with extension opcode (if any). */
+ if (t->extension_opcode != None)
+ i.rm.reg = t->extension_opcode;
+ }
+ }
+ }
+ }
+
+ /* Handle conversion of 'int $3' --> special int3 insn. */
+ if (t->base_opcode == INT_OPCODE && i.imms[0]->X_add_number == 3) {
+ t->base_opcode = INT3_OPCODE;
+ i.imm_operands = 0;
+ }
+
+ /* We are ready to output the insn. */
+ {
+ register char * p;
+
+ /* Output jumps. */
+ if (t->opcode_modifier & Jump) {
+ int n = i.disps[0]->X_add_number;
+
+ switch (i.disps[0]->X_seg) {
+ case SEG_ABSOLUTE:
+ if (fits_in_signed_byte(n)) {
+ p = frag_more (2);
+ p[0] = t->base_opcode;
+ p[1] = n;
+#if 0 /* leave out 16 bit jumps - pace */
+ } else if (fits_in_signed_word(n)) {
+ p = frag_more (4);
+ p[0] = WORD_PREFIX_OPCODE;
+ p[1] = t->base_opcode;
+ md_number_to_chars (&p[2], n, 2);
+#endif
+ } else { /* It's an absolute dword displacement. */
+ if (t->base_opcode == JUMP_PC_RELATIVE) { /* pace */
+ /* unconditional jump */
+ p = frag_more (5);
+ p[0] = 0xe9;
+ md_number_to_chars (&p[1], n, 4);
+ } else {
+ /* conditional jump */
+ p = frag_more (6);
+ p[0] = TWO_BYTE_OPCODE_ESCAPE;
+ p[1] = t->base_opcode + 0x10;
+ md_number_to_chars (&p[2], n, 4);
+ }
+ }
+ break;
+ default:
+ /* It's a symbol; end frag & setup for relax.
+ Make sure there are 6 chars left in the current frag; if not
+ we'll have to start a new one. */
+ /* I caught it failing with obstack_room == 6,
+ so I changed to <= pace */
+ if (obstack_room (&frags) <= 6) {
+ frag_wane(frag_now);
+ frag_new (0);
+ }
+ p = frag_more (1);
+ p[0] = t->base_opcode;
+ frag_var (rs_machine_dependent,
+ 6, /* 2 opcode/prefix + 4 displacement */
+ 1,
+ ((unsigned char) *p == JUMP_PC_RELATIVE
+ ? ENCODE_RELAX_STATE (UNCOND_JUMP, BYTE)
+ : ENCODE_RELAX_STATE (COND_JUMP, BYTE)),
+ i.disps[0]->X_add_symbol,
+ n, p);
+/*
+ * XXX - what do we do about jmp x@PLT ??
+ * kludged in md_estimate_size_before_relax() below
+ */
+ break;
+ }
+ } else if (t->opcode_modifier & (JumpByte|JumpDword)) {
+ int size = (t->opcode_modifier & JumpByte) ? 1 : 4;
+ int n = i.disps[0]->X_add_number;
+
+ if (fits_in_unsigned_byte(t->base_opcode)) {
+ FRAG_APPEND_1_CHAR (t->base_opcode);
+ } else {
+ p = frag_more (2); /* opcode can be at most two bytes */
+ /* put out high byte first: can't use md_number_to_chars! */
+ *p++ = (t->base_opcode >> 8) & 0xff;
+ *p = t->base_opcode & 0xff;
+ }
+
+ p = frag_more (size);
+ switch (i.disps[0]->X_seg) {
+ case SEG_ABSOLUTE:
+ md_number_to_chars (p, n, size);
+ if (size == 1 && ! fits_in_signed_byte(n)) {
+ as_bad("loop/jecx only takes byte displacement; %d shortened to %d",
+ n, *p);
+ }
+ break;
+ default:
+ fix_new (frag_now, p - frag_now->fr_literal, size,
+ i.disps[0]->X_add_symbol, i.disps[0]->X_subtract_symbol,
+ i.disps[0]->X_add_number, 1, i.disp_reloc[0], i.disps[0]->X_got_symbol);
+ break;
+ }
+ } else if (t->opcode_modifier & JumpInterSegment) {
+ p = frag_more (1 + 2 + 4); /* 1 opcode; 2 segment; 4 offset */
+ p[0] = t->base_opcode;
+ if (i.imms[1]->X_seg == SEG_ABSOLUTE)
+ md_number_to_chars (p + 1, i.imms[1]->X_add_number, 4);
+ else
+ fix_new (frag_now, p + 1 - frag_now->fr_literal, 4,
+ i.imms[1]->X_add_symbol,
+ i.imms[1]->X_subtract_symbol,
+ i.imms[1]->X_add_number, 0, NO_RELOC, i.imms[1]->X_got_symbol);
+ if (i.imms[0]->X_seg != SEG_ABSOLUTE)
+ as_bad("can't handle non absolute segment in long call/jmp");
+ md_number_to_chars (p + 5, i.imms[0]->X_add_number, 2);
+ } else {
+ /* Output normal instructions here. */
+ unsigned char *q;
+#ifdef PIC
+ /*
+ * Remember # of opcode bytes to put in pcrel_adjust
+ * for use in _GLOBAL_OFFSET_TABLE_ expressions.
+ */
+ int nopbytes = 0;
+#endif
+
+ /* First the prefix bytes. */
+ for (q = i.prefix; q < i.prefix + i.prefixes; q++) {
+ p = frag_more (1);
+ nopbytes += 1;
+ md_number_to_chars (p, (unsigned int) *q, 1);
+ }
+
+ /* Now the opcode; be careful about word order here! */
+ if (fits_in_unsigned_byte(t->base_opcode)) {
+ nopbytes += 1;
+ FRAG_APPEND_1_CHAR (t->base_opcode);
+ } else if (fits_in_unsigned_word(t->base_opcode)) {
+ p = frag_more (2);
+ nopbytes += 2;
+ /* put out high byte first: can't use md_number_to_chars! */
+ *p++ = (t->base_opcode >> 8) & 0xff;
+ *p = t->base_opcode & 0xff;
+ } else { /* opcode is either 3 or 4 bytes */
+ if (t->base_opcode & 0xff000000) {
+ p = frag_more (4);
+ nopbytes += 4;
+ *p++ = (t->base_opcode >> 24) & 0xff;
+ } else {
+ p = frag_more (3);
+ nopbytes += 3;
+ }
+ *p++ = (t->base_opcode >> 16) & 0xff;
+ *p++ = (t->base_opcode >> 8) & 0xff;
+ *p = (t->base_opcode ) & 0xff;
+ }
+
+ /* Now the modrm byte and base index byte (if present). */
+ if (t->opcode_modifier & Modrm) {
+ p = frag_more (1);
+ nopbytes += 1;
+ /* md_number_to_chars (p, i.rm, 1); */
+ md_number_to_chars (p, (i.rm.regmem<<0 | i.rm.reg<<3 | i.rm.mode<<6), 1);
+ /* If i.rm.regmem == ESP (4) && i.rm.mode != Mode 3 (Register mode)
+ ==> need second modrm byte. */
+ if (i.rm.regmem == ESCAPE_TO_TWO_BYTE_ADDRESSING && i.rm.mode != 3) {
+ p = frag_more (1);
+ nopbytes += 1;
+ /* md_number_to_chars (p, i.bi, 1); */
+ md_number_to_chars (p,(i.bi.base<<0 | i.bi.index<<3 | i.bi.scale<<6), 1);
+ }
+ }
+
+ if (i.disp_operands) {
+ register unsigned int n;
+
+ for (n = 0; n < i.operands; n++) {
+ if (i.disps[n]) {
+ if (i.disps[n]->X_seg == SEG_ABSOLUTE) {
+ if (i.types[n] & (Disp8|Abs8)) {
+ p = frag_more (1);
+ md_number_to_chars (p, i.disps[n]->X_add_number, 1);
+ } else if (i.types[n] & (Disp16|Abs16)) {
+ p = frag_more (2);
+ md_number_to_chars (p, i.disps[n]->X_add_number, 2);
+ } else { /* Disp32|Abs32 */
+ p = frag_more (4);
+ md_number_to_chars (p, i.disps[n]->X_add_number, 4);
+ }
+ } else { /* not SEG_ABSOLUTE */
+ /* need a 32-bit fixup (don't support 8bit non-absolute disps) */
+
+ fixS *fixP;
+ p = frag_more (4);
+ fixP = fix_new (frag_now, p - frag_now->fr_literal, 4,
+ i.disps[n]->X_add_symbol, i.disps[n]->X_subtract_symbol,
+ i.disps[n]->X_add_number, 0, i.disp_reloc[n], i.disps[n]->X_got_symbol);
+#ifdef PIC
+ if (i.disps[n]->X_got_symbol) {
+ fixP->fx_pcrel_adjust = nopbytes;
+ }
+#endif
+ }
+ }
+ }
+ } /* end displacement output */
+
+ /* output immediate */
+ if (i.imm_operands) {
+ register unsigned int n;
+
+ for (n = 0; n < i.operands; n++) {
+ if (i.imms[n]) {
+ if (i.imms[n]->X_seg == SEG_ABSOLUTE) {
+ if (i.types[n] & (Imm8|Imm8S)) {
+ p = frag_more (1);
+ md_number_to_chars (p, i.imms[n]->X_add_number, 1);
+ } else if (i.types[n] & Imm16) {
+ p = frag_more (2);
+ md_number_to_chars (p, i.imms[n]->X_add_number, 2);
+ } else {
+ p = frag_more (4);
+ md_number_to_chars (p, i.imms[n]->X_add_number, 4);
+ }
+ } else { /* not SEG_ABSOLUTE */
+ /* need a 32-bit fixup (don't support 8bit non-absolute ims) */
+ /* try to support other sizes ... */
+ fixS *fixP;
+ int size;
+ if (i.types[n] & (Imm8|Imm8S))
+ size = 1;
+ else if (i.types[n] & Imm16)
+ size = 2;
+ else
+ size = 4;
+ p = frag_more (size);
+ fixP = fix_new (frag_now, p - frag_now->fr_literal, size,
+ i.imms[n]->X_add_symbol, i.imms[n]->X_subtract_symbol,
+ i.imms[n]->X_add_number, 0, NO_RELOC, i.imms[n]->X_got_symbol);
+#ifdef PIC
+ if (i.imms[n]->X_got_symbol) {
+ fixP->fx_pcrel_adjust = nopbytes;
+ }
+#endif
+ }
+ }
+ }
+ } /* end immediate output */
+ }
+
+#ifdef DEBUG386
+ if (flagseen['D']) {
+ pi (line, &i);
+ }
+#endif /* DEBUG386 */
+
+ }
+ return;
+}
+
+/* Parse OPERAND_STRING into the i386_insn structure I. Returns non-zero
+ on error. */
+
+static int i386_operand (operand_string)
+char *operand_string;
+{
+ register char *op_string = operand_string;
+
+ /* Address of '\0' at end of operand_string. */
+ char * end_of_operand_string = operand_string + strlen(operand_string);
+
+ /* Start and end of displacement string expression (if found). */
+ char *displacement_string_start = NULL;
+ char *displacement_string_end = NULL;
+
+ /* We check for an absolute prefix (differentiating,
+ for example, 'jmp pc_relative_label' from 'jmp *absolute_label'. */
+ if (*op_string == ABSOLUTE_PREFIX) {
+ op_string++;
+ i.types[this_operand] |= JumpAbsolute;
+ }
+
+ /* Check if operand is a register. */
+ if (*op_string == REGISTER_PREFIX) {
+ register reg_entry *r;
+ if (!(r = parse_register (op_string))) {
+ as_bad("bad register name ('%s')", op_string);
+ return 0;
+ }
+ /* Check for segment override, rather than segment register by
+ searching for ':' after %<x>s where <x> = s, c, d, e, f, g. */
+ if ((r->reg_type & (SReg2|SReg3)) && op_string[3] == ':') {
+ switch (r->reg_num) {
+ case 0:
+ i.seg = (seg_entry *) &es; break;
+ case 1:
+ i.seg = (seg_entry *) &cs; break;
+ case 2:
+ i.seg = (seg_entry *) &ss; break;
+ case 3:
+ i.seg = (seg_entry *) &ds; break;
+ case 4:
+ i.seg = (seg_entry *) &fs; break;
+ case 5:
+ i.seg = (seg_entry *) &gs; break;
+ }
+ op_string += 4; /* skip % <x> s : */
+ operand_string = op_string; /* Pretend given string starts here. */
+ if (!is_digit_char(*op_string) && !is_identifier_char(*op_string)
+ && *op_string != '(' && *op_string != ABSOLUTE_PREFIX) {
+ as_bad("bad memory operand after segment override");
+ return 0;
+ }
+ /* Handle case of %es:*foo. */
+ if (*op_string == ABSOLUTE_PREFIX) {
+ op_string++;
+ i.types[this_operand] |= JumpAbsolute;
+ }
+ goto do_memory_reference;
+ }
+ i.types[this_operand] |= r->reg_type;
+ i.regs[this_operand] = r;
+ i.reg_operands++;
+ } else if (*op_string == IMMEDIATE_PREFIX) { /* ... or an immediate */
+ char *save_input_line_pointer;
+ segT exp_seg = SEG_GOOF;
+ expressionS *exp;
+
+ if (i.imm_operands == MAX_IMMEDIATE_OPERANDS) {
+ as_bad("only 1 or 2 immediate operands are allowed");
+ return 0;
+ }
+
+ exp = &im_expressions[i.imm_operands++];
+ i.imms[this_operand] = exp;
+ save_input_line_pointer = input_line_pointer;
+ /* must advance op_string! */
+ input_line_pointer = ++op_string;
+ SKIP_WHITESPACE ();
+
+ exp_seg = expression(exp);
+ input_line_pointer = save_input_line_pointer;
+
+ switch (exp_seg) {
+ case SEG_ABSENT: /* missing or bad expr becomes absolute 0 */
+ as_bad("missing or invalid immediate expression '%s' taken as 0",
+ operand_string);
+ exp->X_seg = SEG_ABSOLUTE;
+ exp->X_add_number = 0;
+ exp->X_add_symbol = (symbolS *) 0;
+ exp->X_subtract_symbol = (symbolS *) 0;
+ i.types[this_operand] |= Imm;
+ break;
+ case SEG_ABSOLUTE:
+ i.types[this_operand] |= smallest_imm_type(exp->X_add_number);
+ break;
+ case SEG_TEXT: case SEG_DATA: case SEG_BSS: case SEG_UNKNOWN:
+ case SEG_DIFFERENCE:
+ i.types[this_operand] |= Imm32; /* this is an address ==> 32bit */
+ break;
+ default:
+ seg_unimplemented:
+ as_bad("Unimplemented segment type %d in parse_operand", exp_seg);
+ return 0;
+ }
+ /* shorten this type of this operand if the instruction wants
+ * fewer bits than are present in the immediate. The bit field
+ * code can put out 'andb $0xffffff, %al', for example. pace
+ * also 'movw $foo,(%eax)'
+ */
+ switch (i.suffix) {
+ case WORD_OPCODE_SUFFIX:
+ i.types[this_operand] |= Imm16;
+ break;
+ case BYTE_OPCODE_SUFFIX:
+ i.types[this_operand] |= Imm16 | Imm8 | Imm8S;
+ break;
+ }
+ } else if (is_digit_char(*op_string) || is_identifier_char(*op_string)
+ || *op_string == '(') {
+ /* This is a memory reference of some sort. */
+ register char * base_string;
+ unsigned int found_base_index_form;
+
+ do_memory_reference:
+ if (i.mem_operands == MAX_MEMORY_OPERANDS) {
+ as_bad("more than 1 memory reference in instruction");
+ return 0;
+ }
+ i.mem_operands++;
+
+ /* Determine type of memory operand from opcode_suffix;
+ no opcode suffix implies general memory references. */
+ switch (i.suffix) {
+ case BYTE_OPCODE_SUFFIX:
+ i.types[this_operand] |= Mem8;
+ break;
+ case WORD_OPCODE_SUFFIX:
+ i.types[this_operand] |= Mem16;
+ break;
+ case DWORD_OPCODE_SUFFIX:
+ default:
+ i.types[this_operand] |= Mem32;
+ }
+
+ /* Check for base index form. We detect the base index form by
+ looking for an ')' at the end of the operand, searching
+ for the '(' matching it, and finding a REGISTER_PREFIX or ','
+ after it. */
+ base_string = end_of_operand_string - 1;
+ found_base_index_form = 0;
+ if (*base_string == ')') {
+ unsigned int parens_balenced = 1;
+ /* We've already checked that the number of left & right ()'s are equal,
+ so this loop will not be infinite. */
+ do {
+ base_string--;
+ if (*base_string == ')') parens_balenced++;
+ if (*base_string == '(') parens_balenced--;
+ } while (parens_balenced);
+ base_string++; /* Skip past '('. */
+ if (*base_string == REGISTER_PREFIX || *base_string == ',')
+ found_base_index_form = 1;
+ }
+
+ /* If we can't parse a base index register expression, we've found
+ a pure displacement expression. We set up displacement_string_start
+ and displacement_string_end for the code below. */
+ if (! found_base_index_form) {
+ displacement_string_start = op_string;
+ displacement_string_end = end_of_operand_string;
+ } else {
+ char *base_reg_name, *index_reg_name, *num_string;
+ int num;
+
+ i.types[this_operand] |= BaseIndex;
+
+ /* If there is a displacement set-up for it to be parsed later. */
+ if (base_string != op_string + 1) {
+ displacement_string_start = op_string;
+ displacement_string_end = base_string - 1;
+ }
+
+ /* Find base register (if any). */
+ if (*base_string != ',') {
+ base_reg_name = base_string++;
+ /* skip past register name & parse it */
+ while (isalpha(*base_string)) base_string++;
+ if (base_string == base_reg_name+1) {
+ as_bad("can't find base register name after '(%c'",
+ REGISTER_PREFIX);
+ return 0;
+ }
+ END_STRING_AND_SAVE (base_string);
+ if (! (i.base_reg = parse_register (base_reg_name))) {
+ as_bad("bad base register name ('%s')", base_reg_name);
+ return 0;
+ }
+ RESTORE_END_STRING (base_string);
+ }
+
+ /* Now check seperator; must be ',' ==> index reg
+ OR num ==> no index reg. just scale factor
+ OR ')' ==> end. (scale factor = 1) */
+ if (*base_string != ',' && *base_string != ')') {
+ as_bad("expecting ',' or ')' after base register in `%s'",
+ operand_string);
+ return 0;
+ }
+
+ /* There may index reg here; and there may be a scale factor. */
+ if (*base_string == ',' && *(base_string+1) == REGISTER_PREFIX) {
+ index_reg_name = ++base_string;
+ while (isalpha(*++base_string));
+ END_STRING_AND_SAVE (base_string);
+ if (! (i.index_reg = parse_register(index_reg_name))) {
+ as_bad("bad index register name ('%s')", index_reg_name);
+ return 0;
+ }
+ RESTORE_END_STRING (base_string);
+ }
+
+ /* Check for scale factor. */
+ if (*base_string == ',' && isdigit(*(base_string+1))) {
+ num_string = ++base_string;
+ while (is_digit_char(*base_string)) base_string++;
+ if (base_string == num_string) {
+ as_bad("can't find a scale factor after ','");
+ return 0;
+ }
+ END_STRING_AND_SAVE (base_string);
+ /* We've got a scale factor. */
+ if (! sscanf (num_string, "%d", &num)) {
+ as_bad("can't parse scale factor from '%s'", num_string);
+ return 0;
+ }
+ RESTORE_END_STRING (base_string);
+ switch (num) { /* must be 1 digit scale */
+ case 1: i.log2_scale_factor = 0; break;
+ case 2: i.log2_scale_factor = 1; break;
+ case 4: i.log2_scale_factor = 2; break;
+ case 8: i.log2_scale_factor = 3; break;
+ default:
+ as_bad("expecting scale factor of 1, 2, 4, 8; got %d", num);
+ return 0;
+ }
+ } else {
+ if (! i.index_reg && *base_string == ',') {
+ as_bad("expecting index register or scale factor after ','; got '%c'",
+ *(base_string+1));
+ return 0;
+ }
+ }
+ }
+
+ /* If there's an expression begining the operand, parse it,
+ assuming displacement_string_start and displacement_string_end
+ are meaningful. */
+ if (displacement_string_start) {
+ register expressionS *exp;
+ segT exp_seg = SEG_GOOF;
+ char *save_input_line_pointer;
+ exp = &disp_expressions[i.disp_operands];
+ i.disps[this_operand] = exp;
+ i.disp_reloc[this_operand] = NO_RELOC;
+ i.disp_operands++;
+ save_input_line_pointer = input_line_pointer;
+ input_line_pointer = displacement_string_start;
+ END_STRING_AND_SAVE (displacement_string_end);
+#ifdef PIC
+ {
+ /*
+ * We can have operands of the form
+ * <symbol>@GOTOFF+<nnn>
+ * Take the easy way out here and copy everything
+ * into a temporary buffer...
+ */
+ register char *cp;
+ if (flagseen['k'] &&
+ (cp = strchr(input_line_pointer,'@'))) {
+ char tmpbuf[BUFSIZ];
+
+ if (strncmp(cp+1, "PLT", 3) == 0) {
+ i.disp_reloc[this_operand] = RELOC_JMP_TBL;
+ *cp = '\0';
+ strcpy(tmpbuf, input_line_pointer);
+ strcat(tmpbuf, cp+1+3);
+ *cp = '@';
+ } else if (strncmp(cp+1, "GOTOFF", 6) == 0) {
+ i.disp_reloc[this_operand] = RELOC_GOTOFF;
+ *cp = '\0';
+ strcpy(tmpbuf, input_line_pointer);
+ strcat(tmpbuf, cp+1+6);
+ *cp = '@';
+ } else if (strncmp(cp+1, "GOT", 3) == 0) {
+ i.disp_reloc[this_operand] = RELOC_GOT;
+ *cp = '\0';
+ strcpy(tmpbuf, input_line_pointer);
+ strcat(tmpbuf, cp+1+3);
+ *cp = '@';
+ } else
+ as_bad("Bad reloc specifier '%s' in expression", cp+1);
+ input_line_pointer = tmpbuf;
+ }
+ }
+#endif
+ exp_seg = expression(exp);
+#ifdef PIC
+ if (i.disp_reloc[this_operand] == RELOC_GOTOFF)
+ exp->X_add_symbol->sy_forceout = 1;
+#endif
+ if (*input_line_pointer)
+ as_bad("Ignoring junk '%s' after expression",input_line_pointer);
+ RESTORE_END_STRING (displacement_string_end);
+ input_line_pointer = save_input_line_pointer;
+ switch (exp_seg) {
+ case SEG_ABSENT:
+ /* missing expr becomes absolute 0 */
+ as_bad("missing or invalid displacement '%s' taken as 0",
+ operand_string);
+ if (i.disp_reloc[this_operand] != NO_RELOC || !found_base_index_form || !i.base_reg) {
+ i.types[this_operand] |= (Disp|Abs);
+ exp->X_seg = SEG_ABSOLUTE;
+ exp->X_add_number = 0;
+ exp->X_add_symbol = (symbolS *) 0;
+ exp->X_subtract_symbol = (symbolS *) 0;
+ } else {
+#ifdef DEBUGxxx
+ printf("displacement removed in operand `%s'\n", operand_string);
+#endif
+ i.disp_operands--;
+ i.disps[this_operand] = 0;
+ }
+ break;
+ case SEG_ABSOLUTE:
+ if (i.disp_reloc[this_operand] != NO_RELOC || !found_base_index_form || !i.base_reg || exp->X_add_symbol || exp->X_subtract_symbol || exp->X_add_number != 0)
+ i.types[this_operand] |= SMALLEST_DISP_TYPE (exp->X_add_number);
+ else {
+#ifdef DEBUGxxx
+ printf("displacement removed in operand `%s'\n", operand_string);
+#endif
+ i.disp_operands--;
+ i.disps[this_operand] = 0;
+ }
+ break;
+ case SEG_TEXT: case SEG_DATA: case SEG_BSS:
+ case SEG_UNKNOWN: /* must be 32 bit displacement (i.e. address) */
+ if (i.disp_reloc[this_operand] != NO_RELOC || !found_base_index_form || !i.base_reg || exp->X_add_symbol || exp->X_subtract_symbol || exp->X_add_number != 0)
+ i.types[this_operand] |= Disp32;
+ else {
+#ifdef DEBUGxxx
+ printf("displacement removed in operand `%s'\n", operand_string);
+#endif
+ i.disp_operands--;
+ i.disps[this_operand] = 0;
+ }
+ break;
+ default:
+ goto seg_unimplemented;
+ }
+ }
+
+ /* Make sure the memory operand we've been dealt is valid. */
+ if (i.base_reg && i.index_reg &&
+ ! (i.base_reg->reg_type & i.index_reg->reg_type & Reg)) {
+ as_bad("register size mismatch in (base,index,scale) expression");
+ return 0;
+ }
+ /*
+ * special case for (%dx) while doing input/output op
+ */
+ if ((i.base_reg &&
+ (i.base_reg->reg_type == (Reg16|InOutPortReg)) &&
+ (i.index_reg == 0)))
+ return 1;
+ if ((i.base_reg && (i.base_reg->reg_type & Reg32) == 0) ||
+ (i.index_reg && (i.index_reg->reg_type & Reg32) == 0)) {
+ as_bad("base/index register must be 32 bit register");
+ return 0;
+ }
+ if (i.index_reg && i.index_reg == esp) {
+ as_bad("%s may not be used as an index register", esp->reg_name);
+ return 0;
+ }
+ } else { /* it's not a memory operand; argh! */
+ as_bad("invalid char %s begining %s operand '%s'",
+ output_invalid(*op_string), ordinal_names[this_operand],
+ op_string);
+ return 0;
+ }
+ return 1; /* normal return */
+}
+
+/*
+ * md_estimate_size_before_relax()
+ *
+ * Called just before relax().
+ * Any symbol that is now undefined will not become defined.
+ * Return the correct fr_subtype in the frag.
+ * Return the initial "guess for fr_var" to caller.
+ * The guess for fr_var is ACTUALLY the growth beyond fr_fix.
+ * Whatever we do to grow fr_fix or fr_var contributes to our returned value.
+ * Although it may not be explicit in the frag, pretend fr_var starts with a
+ * 0 value.
+ */
+int
+ md_estimate_size_before_relax (fragP, segment)
+register fragS * fragP;
+register segT segment;
+{
+ register unsigned char * opcode;
+ register int old_fr_fix;
+
+ old_fr_fix = fragP->fr_fix;
+ opcode = (unsigned char *) fragP->fr_opcode;
+ /* We've already got fragP->fr_subtype right; all we have to do is check
+ for un-relaxable symbols. */
+ if (S_GET_SEGMENT(fragP->fr_symbol) != segment) {
+ /* symbol is undefined in this segment */
+ switch (opcode[0]) {
+ case JUMP_PC_RELATIVE: /* make jmp (0xeb) a dword displacement jump */
+ opcode[0] = 0xe9; /* dword disp jmp */
+ fragP->fr_fix += 4;
+ fix_new (fragP, old_fr_fix, 4,
+ fragP->fr_symbol,
+ (symbolS *) 0,
+ fragP->fr_offset, 1,
+#ifdef PIC
+/* XXX - oops, the JMP_TBL relocation info should have percolated through
+ * here, define a field in frag to this?
+ */
+ (flagseen['k'] && S_GET_SEGMENT(fragP->fr_symbol) == SEG_UNKNOWN)?
+ RELOC_JMP_TBL :
+#endif
+ NO_RELOC, (symbolS *)0);
+ break;
+
+ default:
+ /* This changes the byte-displacement jump 0x7N -->
+ the dword-displacement jump 0x0f8N */
+ opcode[1] = opcode[0] + 0x10;
+ opcode[0] = TWO_BYTE_OPCODE_ESCAPE; /* two-byte escape */
+ fragP->fr_fix += 1 + 4; /* we've added an opcode byte */
+ fix_new (fragP, old_fr_fix + 1, 4,
+ fragP->fr_symbol,
+ (symbolS *) 0,
+ fragP->fr_offset, 1,
+#ifdef PIC
+/*XXX*/ (flagseen['k'] && S_GET_SEGMENT(fragP->fr_symbol) == SEG_UNKNOWN)?
+ RELOC_JMP_TBL :
+#endif
+ NO_RELOC, (symbolS *)0);
+ break;
+ }
+ frag_wane (fragP);
+ }
+ return (fragP->fr_var + fragP->fr_fix - old_fr_fix);
+} /* md_estimate_size_before_relax() */
+
+/*
+ * md_convert_frag();
+ *
+ * Called after relax() is finished.
+ * In: Address of frag.
+ * fr_type == rs_machine_dependent.
+ * fr_subtype is what the address relaxed to.
+ *
+ * Out: Any fixSs and constants are set up.
+ * Caller will turn frag into a ".space 0".
+ */
+void
+ md_convert_frag (headers, fragP)
+object_headers *headers;
+register fragS * fragP;
+{
+ register unsigned char *opcode;
+ unsigned char *where_to_put_displacement = NULL;
+ unsigned int target_address;
+ unsigned int opcode_address;
+ unsigned int extension = 0;
+ int displacement_from_opcode_start;
+
+ opcode = (unsigned char *) fragP->fr_opcode;
+
+ /* Address we want to reach in file space. */
+ target_address = S_GET_VALUE(fragP->fr_symbol) + fragP->fr_offset;
+
+ /* Address opcode resides at in file space. */
+ opcode_address = fragP->fr_address + fragP->fr_fix;
+
+ /* Displacement from opcode start to fill into instruction. */
+ displacement_from_opcode_start = target_address - opcode_address;
+
+ switch (fragP->fr_subtype) {
+ case ENCODE_RELAX_STATE (COND_JUMP, BYTE):
+ case ENCODE_RELAX_STATE (UNCOND_JUMP, BYTE):
+ /* don't have to change opcode */
+ extension = 1; /* 1 opcode + 1 displacement */
+ where_to_put_displacement = &opcode[1];
+ break;
+
+ case ENCODE_RELAX_STATE (COND_JUMP, WORD):
+ opcode[1] = TWO_BYTE_OPCODE_ESCAPE;
+ opcode[2] = opcode[0] + 0x10;
+ opcode[0] = WORD_PREFIX_OPCODE;
+ extension = 4; /* 3 opcode + 2 displacement */
+ where_to_put_displacement = &opcode[3];
+ break;
+
+ case ENCODE_RELAX_STATE (UNCOND_JUMP, WORD):
+ opcode[1] = 0xe9;
+ opcode[0] = WORD_PREFIX_OPCODE;
+ extension = 3; /* 2 opcode + 2 displacement */
+ where_to_put_displacement = &opcode[2];
+ break;
+
+ case ENCODE_RELAX_STATE (COND_JUMP, DWORD):
+ opcode[1] = opcode[0] + 0x10;
+ opcode[0] = TWO_BYTE_OPCODE_ESCAPE;
+ extension = 5; /* 2 opcode + 4 displacement */
+ where_to_put_displacement = &opcode[2];
+ break;
+
+ case ENCODE_RELAX_STATE (UNCOND_JUMP, DWORD):
+ opcode[0] = 0xe9;
+ extension = 4; /* 1 opcode + 4 displacement */
+ where_to_put_displacement = &opcode[1];
+ break;
+
+ default:
+ BAD_CASE(fragP->fr_subtype);
+ break;
+}
+ /* now put displacement after opcode */
+ md_number_to_chars ((char *) where_to_put_displacement,
+ displacement_from_opcode_start - extension,
+ SIZE_FROM_RELAX_STATE (fragP->fr_subtype));
+ fragP->fr_fix += extension;
+}
+
+
+int md_short_jump_size = 2; /* size of byte displacement jmp */
+int md_long_jump_size = 5; /* size of dword displacement jmp */
+int md_reloc_size = 8; /* Size of relocation record */
+
+void md_create_short_jump(ptr, from_addr, to_addr, frag, to_symbol)
+char *ptr;
+long from_addr, to_addr;
+fragS *frag;
+symbolS *to_symbol;
+{
+ long offset;
+
+ offset = to_addr - (from_addr + 2);
+ md_number_to_chars (ptr, (long) 0xeb, 1); /* opcode for byte-disp jump */
+ md_number_to_chars (ptr + 1, offset, 1);
+}
+
+void md_create_long_jump (ptr, from_addr, to_addr, frag, to_symbol)
+char *ptr;
+long from_addr, to_addr;
+fragS *frag;
+symbolS *to_symbol;
+{
+ long offset;
+
+ if (flagseen['m']) {
+ offset = to_addr - S_GET_VALUE(to_symbol);
+ md_number_to_chars (ptr, 0xe9, 1); /* opcode for long jmp */
+ md_number_to_chars (ptr + 1, offset, 4);
+ fix_new (frag, (ptr+1) - frag->fr_literal, 4,
+ to_symbol, (symbolS *) 0, (long) 0, 0, NO_RELOC, (symbolS *)0);
+ } else {
+ offset = to_addr - (from_addr + 5);
+ md_number_to_chars(ptr, (long) 0xe9, 1);
+ md_number_to_chars(ptr + 1, offset, 4);
+ }
+}
+
+int
+ md_parse_option(argP,cntP,vecP)
+char **argP;
+int *cntP;
+char ***vecP;
+{
+#ifdef PIC
+ if (argP && *argP && **argP == 'k') {
+#if 00
+ char *tmp = xmalloc(3+1+strlen(operand_special_chars));
+ strcpy(tmp, operand_special_chars);
+ strcat(tmp, "@[]");
+ operand_special_chars = tmp;
+#endif
+ /* Allow `[', `]' in expressions and `@' in operands */
+ operand_chars['@'] = '@';
+ operand_chars['['] = '[';
+ operand_chars[']'] = ']';
+
+ /* Disallow `[' as a name beginner */
+ lex_type['['] = 0;
+
+ /* Predefine GOT symbol */
+ GOT_symbol = symbol_find_or_make("__GLOBAL_OFFSET_TABLE_");
+ }
+#endif
+ return 1;
+}
+
+ /* write out in little endian. */
+void /* Knows about order of bytes in address. */
+ md_number_to_chars(con, value, nbytes)
+char con[]; /* Return 'nbytes' of chars here. */
+long value; /* The value of the bits. */
+int nbytes; /* Number of bytes in the output. */
+{
+ register char * p = con;
+
+ switch (nbytes) {
+ case 1:
+ p[0] = value & 0xff;
+ break;
+ case 2:
+ p[0] = value & 0xff;
+ p[1] = (value >> 8) & 0xff;
+ break;
+ case 4:
+ p[0] = value & 0xff;
+ p[1] = (value>>8) & 0xff;
+ p[2] = (value>>16) & 0xff;
+ p[3] = (value>>24) & 0xff;
+ break;
+ default:
+ BAD_CASE (nbytes);
+ }
+}
+
+
+/* Apply a fixup (fixS) to segment data, once it has been determined
+ by our caller that we have all the info we need to fix it up.
+
+ On the 386, immediates, displacements, and data pointers are all in
+ the same (little-endian) format, so we don't need to care about which
+ we are handling. */
+
+void
+ md_apply_fix (fixP, value)
+fixS * fixP; /* The fix we're to put in */
+long value; /* The value of the bits. */
+{
+ register char * p = fixP->fx_where + fixP->fx_frag->fr_literal;
+
+ switch (fixP->fx_size) {
+ case 1:
+ *p = value;
+ break;
+ case 2:
+ *p++ = value;
+ *p = (value>>8);
+ break;
+ case 4:
+ *p++ = value;
+ *p++ = (value>>8);
+ *p++ = (value>>16);
+ *p = (value>>24);
+ break;
+ default:
+ BAD_CASE (fixP->fx_size);
+ }
+}
+
+long /* Knows about the byte order in a word. */
+ md_chars_to_number (con, nbytes)
+unsigned char con[]; /* Low order byte 1st. */
+int nbytes; /* Number of bytes in the input. */
+{
+ long retval;
+ for (retval=0, con+=nbytes-1; nbytes--; con--)
+ {
+ retval <<= BITS_PER_CHAR;
+ retval |= *con;
+ }
+ return retval;
+}
+
+/* Not needed for coff since relocation structure does not
+ contain bitfields. */
+#if defined(OBJ_AOUT) | defined(OBJ_BOUT)
+#ifdef comment
+/* Output relocation information in the target's format. */
+void
+ md_ri_to_chars(the_bytes, ri)
+char *the_bytes;
+struct reloc_info_generic *ri;
+{
+ /* this is easy */
+ md_number_to_chars(the_bytes, ri->r_address, 4);
+ /* now the fun stuff */
+ the_bytes[6] = (ri->r_symbolnum >> 16) & 0x0ff;
+ the_bytes[5] = (ri->r_symbolnum >> 8) & 0x0ff;
+ the_bytes[4] = ri->r_symbolnum & 0x0ff;
+ the_bytes[7] = (((ri->r_extern << 3) & 0x08) | ((ri->r_length << 1) & 0x06) |
+ ((ri->r_pcrel << 0) & 0x01)) & 0x0F;
+}
+#endif /* comment */
+
+void tc_aout_fix_to_chars(where, fixP, segment_address_in_file)
+char *where;
+fixS *fixP;
+relax_addressT segment_address_in_file;
+{
+ /*
+ * In: length of relocation (or of address) in chars: 1, 2 or 4.
+ * Out: GNU LD relocation length code: 0, 1, or 2.
+ */
+
+ static unsigned char nbytes_r_length[] = { 42, 0, 1, 42, 2 };
+ long r_symbolnum;
+
+ know(fixP->fx_addsy != NULL);
+
+ md_number_to_chars(where,
+ fixP->fx_frag->fr_address + fixP->fx_where - segment_address_in_file,
+ 4);
+
+ r_symbolnum = (S_IS_DEFINED(fixP->fx_addsy)
+ ? S_GET_TYPE(fixP->fx_addsy)
+ : fixP->fx_addsy->sy_number);
+
+#ifdef PIC
+ {
+ int extra_bits = 0;
+ int extrn_bit = !S_IS_DEFINED(fixP->fx_addsy);
+
+ switch (fixP->fx_r_type) {
+ case NO_RELOC:
+ break;
+ case RELOC_32:
+ if (!flagseen['k'] || !S_IS_EXTERNAL(fixP->fx_addsy))
+ break;
+ r_symbolnum = fixP->fx_addsy->sy_number;
+ extrn_bit = 1;
+ break;
+ case RELOC_GOT:
+ extra_bits = (1 << 4) & 0x10; /* r_baserel */
+ r_symbolnum = fixP->fx_addsy->sy_number;
+ if (!extrn_bit && !S_IS_EXTERNAL(fixP->fx_addsy))
+ as_warn("GOT relocation burb: `%s' should be global",
+ S_GET_NAME(fixP->fx_addsy));
+ extrn_bit = 1;
+ break;
+ case RELOC_GOTOFF:
+ extra_bits = (1 << 4) & 0x10; /* r_baserel */
+ r_symbolnum = fixP->fx_addsy->sy_number;
+ if (extrn_bit || S_IS_EXTERNAL(fixP->fx_addsy))
+ as_warn("GOT relocation burb: `%s' should be static",
+ S_GET_NAME(fixP->fx_addsy));
+ break;
+ case RELOC_JMP_TBL:
+ extra_bits = (1 << 5) & 0x20; /* r_jmptable */
+ break;
+ case RELOC_RELATIVE:
+ /* consider using this bit (together with r_baserel) for
+ * GOTOFFs, so ld can check
+ */
+ as_fatal("relocation botch");
+ extra_bits = (1 << 6) & 0x40; /* r_relative */
+ break;
+ }
+ where[6] = (r_symbolnum >> 16) & 0x0ff;
+ where[5] = (r_symbolnum >> 8) & 0x0ff;
+ where[4] = r_symbolnum & 0x0ff;
+ where[7] = ( ((extrn_bit << 3) & 0x08)
+ | ((nbytes_r_length[fixP->fx_size] << 1) & 0x06)
+ | ((fixP->fx_pcrel << 0) & 0x01)
+ | (extra_bits)
+ );
+ }
+#else
+ where[6] = (r_symbolnum >> 16) & 0x0ff;
+ where[5] = (r_symbolnum >> 8) & 0x0ff;
+ where[4] = r_symbolnum & 0x0ff;
+ where[7] = ((((!S_IS_DEFINED(fixP->fx_addsy)) << 3) & 0x08)
+ | ((nbytes_r_length[fixP->fx_size] << 1) & 0x06)
+ | (((fixP->fx_pcrel << 0) & 0x01) & 0x0f));
+#endif
+
+ return;
+} /* tc_aout_fix_to_chars() */
+
+#endif /* OBJ_AOUT or OBJ_BOUT */
+
+
+#define MAX_LITTLENUMS 6
+
+/* Turn the string pointed to by litP into a floating point constant of type
+ type, and emit the appropriate bytes. The number of LITTLENUMS emitted
+ is stored in *sizeP. An error message is returned, or NULL on OK.
+ */
+char *
+ md_atof(type,litP,sizeP)
+char type;
+char *litP;
+int *sizeP;
+{
+ int prec;
+ LITTLENUM_TYPE words[MAX_LITTLENUMS];
+ LITTLENUM_TYPE *wordP;
+ char *t;
+
+ switch (type) {
+ case 'f':
+ case 'F':
+ prec = 2;
+ break;
+
+ case 'd':
+ case 'D':
+ prec = 4;
+ break;
+
+ case 'x':
+ case 'X':
+ prec = 5;
+ break;
+
+ default:
+ *sizeP=0;
+ return "Bad call to md_atof ()";
+ }
+ t = atof_ieee (input_line_pointer,type,words);
+ if (t)
+ input_line_pointer=t;
+
+ *sizeP = prec * sizeof(LITTLENUM_TYPE);
+ /* this loops outputs the LITTLENUMs in REVERSE order; in accord with
+ the bigendian 386 */
+ for (wordP = words + prec - 1;prec--;) {
+ md_number_to_chars (litP, (long) (*wordP--), sizeof(LITTLENUM_TYPE));
+ litP += sizeof(LITTLENUM_TYPE);
+ }
+ return ""; /* Someone should teach Dean about null pointers */
+}
+
+char output_invalid_buf[8];
+
+static char * output_invalid (c)
+char c;
+{
+ if (isprint(c)) sprintf (output_invalid_buf, "'%c'", c);
+ else sprintf (output_invalid_buf, "(0x%x)", (unsigned) c);
+ return output_invalid_buf;
+}
+
+static reg_entry *parse_register (reg_string)
+char *reg_string; /* reg_string starts *before* REGISTER_PREFIX */
+{
+ register char *s = reg_string;
+ register char *p;
+ char reg_name_given[MAX_REG_NAME_SIZE];
+
+ s++; /* skip REGISTER_PREFIX */
+ for (p = reg_name_given; is_register_char (*s); p++, s++) {
+ *p = register_chars[*s];
+ if (p >= reg_name_given + MAX_REG_NAME_SIZE)
+ return (reg_entry *) 0;
+ }
+ *p = '\0';
+ return (reg_entry *) hash_find (reg_hash, reg_name_given);
+}
+
+
+/* We have no need to default values of symbols. */
+
+/* ARGSUSED */
+symbolS *
+ md_undefined_symbol (name)
+char *name;
+{
+#ifdef PIC
+ /* HACK:
+ * Sun's ld expects __GLOBAL_OFFSET_TABLE_,
+ * gcc generates _GLOBAL_OFFSET_TABLE_
+ * should probably fix ld - new SVR4 style??
+ */
+ if (*name == '_' && *(name+1) == 'G' &&
+ strcmp(name, "_GLOBAL_OFFSET_TABLE_") == 0)
+ return symbol_find("__GLOBAL_OFFSET_TABLE_");
+#endif
+ return 0;
+}
+
+/* Parse an operand that is machine-specific.
+ We just return without modifying the expression if we have nothing
+ to do. */
+
+/* ARGSUSED */
+void
+ md_operand (expressionP)
+expressionS *expressionP;
+{
+}
+
+/* Round up a section size to the appropriate boundary. */
+long
+ md_section_align (segment, size)
+segT segment;
+long size;
+{
+ return size; /* Byte alignment is fine */
+}
+
+/* Exactly what point is a PC-relative offset relative TO?
+ On the i386, they're relative to the address of the offset, plus
+ its size. (??? Is this right? FIXME-SOON!) */
+long
+ md_pcrel_from (fixP)
+fixS *fixP;
+{
+#ifdef PIC
+ /*
+ * _GLOBAL_OFFSET_TABLE_ refs are relative to the offset of the
+ * current instruction. fx_pcrel_adjust has been setup to account
+ * for the number of opcode bytes preceding the fixup location,
+ * it is zero for eg. .long pseudo-ops.
+ */
+ if (fixP->fx_gotsy)
+ return fixP->fx_where + fixP->fx_frag->fr_address - fixP->fx_pcrel_adjust;
+ else
+#endif
+ return fixP->fx_size + fixP->fx_where + fixP->fx_frag->fr_address;
+}
+
+ /* these were macros, but I don't trust macros that eval their
+ arguments more than once. Besides, gcc can static inline them.
+ xoxorich. */
+
+static unsigned long mode_from_disp_size(t)
+unsigned long t;
+{
+ return((t & (Disp8))
+ ? 1
+ : ((t & (Disp32)) ? 2 : 0));
+} /* mode_from_disp_size() */
+
+/* convert opcode suffix ('b' 'w' 'l' typically) into type specifyer */
+
+static unsigned long opcode_suffix_to_type(s)
+unsigned long s;
+{
+ return(s == BYTE_OPCODE_SUFFIX
+ ? Byte : (s == WORD_OPCODE_SUFFIX
+ ? Word : DWord));
+} /* opcode_suffix_to_type() */
+
+static int fits_in_signed_byte(num)
+long num;
+{
+ return((num >= -128) && (num <= 127));
+} /* fits_in_signed_byte() */
+
+static int fits_in_unsigned_byte(num)
+long num;
+{
+ return((num & 0xff) == num);
+} /* fits_in_unsigned_byte() */
+
+static int fits_in_unsigned_word(num)
+long num;
+{
+ return((num & 0xffff) == num);
+} /* fits_in_unsigned_word() */
+
+static int fits_in_signed_word(num)
+long num;
+{
+ return((-32768 <= num) && (num <= 32767));
+} /* fits_in_signed_word() */
+
+static int smallest_imm_type(num)
+long num;
+{
+ return((num == 1)
+ ? (Imm1|Imm8|Imm8S|Imm16|Imm32)
+ : (fits_in_signed_byte(num)
+ ? (Imm8S|Imm8|Imm16|Imm32)
+ : (fits_in_unsigned_byte(num)
+ ? (Imm8|Imm16|Imm32)
+ : ((fits_in_signed_word(num) || fits_in_unsigned_word(num))
+ ? (Imm16|Imm32)
+ : (Imm32)))));
+} /* smallest_imm_type() */
+
+static void s_bss()
+{
+ register int temp;
+
+ temp = get_absolute_expression ();
+ subseg_new (SEG_BSS, (subsegT)temp);
+ demand_empty_rest_of_line();
+}
+
+/*
+ * Local Variables:
+ * comment-column: 0
+ * End:
+ */
+
+/* end of tc-i386.c */
diff --git a/gnu/usr.bin/as/config/tc-i386.h b/gnu/usr.bin/as/config/tc-i386.h
new file mode 100644
index 0000000..fd4d335
--- /dev/null
+++ b/gnu/usr.bin/as/config/tc-i386.h
@@ -0,0 +1,251 @@
+/* tc-i386.h -- Header file for tc-i386.c
+ Copyright (C) 1989, 1992 Free Software Foundation.
+
+ This file is part of GAS, the GNU Assembler.
+
+ GAS is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GAS is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GAS; see the file COPYING. If not, write to
+ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/*
+ * $Id: tc-i386.h,v 1.2 1994/12/23 22:37:36 nate Exp $
+ */
+
+#ifndef TC_I386
+#define TC_I386 1
+
+#define AOUT_MACHTYPE 134
+
+#define REVERSE_SORT_RELOCS
+
+#define LOCAL_LABELS_FB
+
+#define tc_coff_symbol_emit_hook(a) ; /* not used */
+
+ /* Local labels starts with .L */
+ /* fixme-now: this is for testing against old gas */
+/* #define LOCAL_LABEL(name) ((name)[0] == '.' && (name)[1] == 'L') */
+#define tc_aout_pre_write_hook(x) {;} /* not used */
+#define tc_crawl_symbol_chain(a) {;} /* not used */
+#define tc_headers_hook(a) {;} /* not used */
+
+#define MAX_OPERANDS 3 /* max operands per insn */
+#define MAX_PREFIXES 4 /* max prefixes per opcode */
+#define MAX_IMMEDIATE_OPERANDS 2 /* max immediates per insn */
+#define MAX_MEMORY_OPERANDS 2 /* max memory ref per insn
+ * lcall uses 2
+ */
+/* we define the syntax here (modulo base,index,scale syntax) */
+#define REGISTER_PREFIX '%'
+#define IMMEDIATE_PREFIX '$'
+#define ABSOLUTE_PREFIX '*'
+#define PREFIX_SEPERATOR '/'
+
+#define TWO_BYTE_OPCODE_ESCAPE 0x0f
+
+#ifndef OLD_GAS
+#define NOP_OPCODE 0x90
+#else /* OLD_GAS */
+#define NOP_OPCODE 0x00
+#endif /* OLD_GAS */
+
+/* register numbers */
+#define EBP_REG_NUM 5
+#define ESP_REG_NUM 4
+
+/* modrm_byte.regmem for twobyte escape */
+#define ESCAPE_TO_TWO_BYTE_ADDRESSING ESP_REG_NUM
+/* index_base_byte.index for no index register addressing */
+#define NO_INDEX_REGISTER ESP_REG_NUM
+/* index_base_byte.base for no base register addressing */
+#define NO_BASE_REGISTER EBP_REG_NUM
+
+ /* these are the att as opcode suffixes, making movl --> mov, for example */
+#define DWORD_OPCODE_SUFFIX 'l'
+#define WORD_OPCODE_SUFFIX 'w'
+#define BYTE_OPCODE_SUFFIX 'b'
+
+ /* modrm.mode = REGMEM_FIELD_HAS_REG when a register is in there */
+#define REGMEM_FIELD_HAS_REG 0x3 /* always = 0x3 */
+#define REGMEM_FIELD_HAS_MEM (~REGMEM_FIELD_HAS_REG)
+
+#define END_OF_INSN '\0'
+
+/*
+ When an operand is read in it is classified by its type. This type includes
+ all the possible ways an operand can be used. Thus, '%eax' is both 'register
+ # 0' and 'The Accumulator'. In our language this is expressed by OR'ing
+ 'Reg32' (any 32 bit register) and 'Acc' (the accumulator).
+ Operands are classified so that we can match given operand types with
+ the opcode table in i386-opcode.h.
+ */
+#define Unknown 0x0
+/* register */
+#define Reg8 0x1 /* 8 bit reg */
+#define Reg16 0x2 /* 16 bit reg */
+#define Reg32 0x4 /* 32 bit reg */
+#define Reg (Reg8|Reg16|Reg32) /* gen'l register */
+#define WordReg (Reg16|Reg32) /* for push/pop operands */
+/* immediate */
+#define Imm8 0x8 /* 8 bit immediate */
+#define Imm8S 0x10 /* 8 bit immediate sign extended */
+#define Imm16 0x20 /* 16 bit immediate */
+#define Imm32 0x40 /* 32 bit immediate */
+#define Imm1 0x80 /* 1 bit immediate */
+#define ImmUnknown Imm32 /* for unknown expressions */
+#define Imm (Imm8|Imm8S|Imm16|Imm32) /* gen'l immediate */
+/* memory */
+#define Disp8 0x200 /* 8 bit displacement (for jumps) */
+#define Disp16 0x400 /* 16 bit displacement */
+#define Disp32 0x800 /* 32 bit displacement */
+#define Disp (Disp8|Disp16|Disp32) /* General displacement */
+#define DispUnknown Disp32 /* for unknown size displacements */
+#define Mem8 0x1000
+#define Mem16 0x2000
+#define Mem32 0x4000
+#define BaseIndex 0x8000
+#define Mem (Disp|Mem8|Mem16|Mem32|BaseIndex) /* General memory */
+#define WordMem (Mem16|Mem32|Disp|BaseIndex)
+#define ByteMem (Mem8|Disp|BaseIndex)
+/* specials */
+#define InOutPortReg 0x10000 /* register to hold in/out port addr = dx */
+#define ShiftCount 0x20000 /* register to hold shift cound = cl */
+#define Control 0x40000 /* Control register */
+#define Debug 0x80000 /* Debug register */
+#define Test 0x100000 /* Test register */
+#define FloatReg 0x200000 /* Float register */
+#define FloatAcc 0x400000 /* Float stack top %st(0) */
+#define SReg2 0x800000 /* 2 bit segment register */
+#define SReg3 0x1000000 /* 3 bit segment register */
+#define Acc 0x2000000 /* Accumulator %al or %ax or %eax */
+#define ImplicitRegister (InOutPortReg|ShiftCount|Acc|FloatAcc)
+#define JumpAbsolute 0x4000000
+#define Abs8 0x08000000
+#define Abs16 0x10000000
+#define Abs32 0x20000000
+#define Abs (Abs8|Abs16|Abs32)
+
+#define Byte (Reg8|Imm8|Imm8S)
+#define Word (Reg16|Imm16)
+#define DWord (Reg32|Imm32)
+
+#define SMALLEST_DISP_TYPE(num) \
+ fits_in_signed_byte(num) ? (Disp8|Disp32|Abs8|Abs32) : (Disp32|Abs32)
+
+typedef struct {
+ /* instruction name sans width suffix ("mov" for movl insns) */
+ char *name;
+
+ /* how many operands */
+ unsigned int operands;
+
+ /* base_opcode is the fundamental opcode byte with a optional prefix(es). */
+ unsigned int base_opcode;
+
+ /* extension_opcode is the 3 bit extension for group <n> insns.
+ If this template has no extension opcode (the usual case) use None */
+ unsigned char extension_opcode;
+#define None 0xff /* If no extension_opcode is possible. */
+
+ /* the bits in opcode_modifier are used to generate the final opcode from
+ the base_opcode. These bits also are used to detect alternate forms of
+ the same instruction */
+ unsigned int opcode_modifier;
+
+ /* opcode_modifier bits: */
+#define W 0x1 /* set if operands are words or dwords */
+#define D 0x2 /* D = 0 if Reg --> Regmem; D = 1 if Regmem --> Reg */
+ /* direction flag for floating insns: MUST BE 0x400 */
+#define FloatD 0x400
+ /* shorthand */
+#define DW (D|W)
+#define ShortForm 0x10 /* register is in low 3 bits of opcode */
+#define ShortFormW 0x20 /* ShortForm and W bit is 0x8 */
+#define Seg2ShortForm 0x40 /* encoding of load segment reg insns */
+#define Seg3ShortForm 0x80 /* fs/gs segment register insns. */
+#define Jump 0x100 /* special case for jump insns. */
+#define JumpInterSegment 0x200 /* special case for intersegment leaps/calls */
+ /* 0x400 CANNOT BE USED since it's already used by FloatD above */
+#define DONT_USE 0x400
+#define NoModrm 0x800
+#define Modrm 0x1000
+#define imulKludge 0x2000
+#define JumpByte 0x4000
+#define JumpDword 0x8000
+#define ReverseRegRegmem 0x10000
+
+ /* (opcode_modifier & COMES_IN_ALL_SIZES) is true if the
+ instuction comes in byte, word, and dword sizes and is encoded into
+ machine code in the canonical way. */
+#define COMES_IN_ALL_SIZES (W)
+
+ /* (opcode_modifier & COMES_IN_BOTH_DIRECTIONS) indicates that the
+ source and destination operands can be reversed by setting either
+ the D (for integer insns) or the FloatD (for floating insns) bit
+ in base_opcode. */
+#define COMES_IN_BOTH_DIRECTIONS (D|FloatD)
+
+ /* operand_types[i] describes the type of operand i. This is made
+ by OR'ing together all of the possible type masks. (e.g.
+ 'operand_types[i] = Reg|Imm' specifies that operand i can be
+ either a register or an immediate operand */
+ unsigned int operand_types[3];
+} template;
+
+/*
+ 'templates' is for grouping together 'template' structures for opcodes
+ of the same name. This is only used for storing the insns in the grand
+ ole hash table of insns.
+ The templates themselves start at START and range up to (but not including)
+ END.
+ */
+typedef struct {
+ template *start;
+ template *end;
+} templates;
+
+/* these are for register name --> number & type hash lookup */
+typedef struct {
+ char *reg_name;
+ unsigned int reg_type;
+ unsigned int reg_num;
+} reg_entry;
+
+typedef struct {
+ char *seg_name;
+ unsigned int seg_prefix;
+} seg_entry;
+
+/* these are for prefix name --> prefix code hash lookup */
+typedef struct {
+ char *prefix_name;
+ unsigned char prefix_code;
+} prefix_entry;
+
+/* 386 operand encoding bytes: see 386 book for details of this. */
+typedef struct {
+ unsigned regmem:3; /* codes register or memory operand */
+ unsigned reg:3; /* codes register operand (or extended opcode) */
+ unsigned mode:2; /* how to interpret regmem & reg */
+} modrm_byte;
+
+/* 386 opcode byte to code indirect addressing. */
+typedef struct {
+ unsigned base:3;
+ unsigned index:3;
+ unsigned scale:2;
+} base_index_byte;
+
+#endif /* TC_I386 */
+
+/* end of tc-i386.h */
diff --git a/gnu/usr.bin/as/config/tc-i860.c b/gnu/usr.bin/as/config/tc-i860.c
new file mode 100644
index 0000000..4907990
--- /dev/null
+++ b/gnu/usr.bin/as/config/tc-i860.c
@@ -0,0 +1,1295 @@
+/* tc-i860.c -- Assemble for the I860
+ Copyright (C) 1989, 1992 Free Software Foundation, Inc.
+
+ This file is part of GAS, the GNU Assembler.
+
+ GAS is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GAS is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GAS; see the file COPYING. If not, write to
+ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "as.h"
+
+#include "opcode/i860.h"
+
+void md_begin();
+void md_end();
+void md_number_to_chars();
+void md_assemble();
+char *md_atof();
+void md_convert_frag();
+void md_create_short_jump();
+void md_create_long_jump();
+int md_estimate_size_before_relax();
+void md_number_to_imm();
+void md_number_to_disp();
+void md_number_to_field();
+void md_ri_to_chars();
+static void i860_ip();
+
+const relax_typeS md_relax_table[] = { 0 };
+
+/* handle of the OPCODE hash table */
+static struct hash_control *op_hash = NULL;
+
+static void s_dual(), s_enddual();
+static void s_atmp();
+
+const pseudo_typeS
+ md_pseudo_table[] = {
+ { "dual", s_dual, 4 },
+ { "enddual", s_enddual, 4 },
+ { "atmp", s_atmp, 4 },
+ { NULL, 0, 0 },
+ };
+
+int md_short_jump_size = 4;
+int md_long_jump_size = 4;
+
+/* This array holds the chars that always start a comment. If the
+ pre-processor is disabled, these aren't very useful */
+char comment_chars[] = "!/"; /* JF removed '|' from comment_chars */
+
+/* This array holds the chars that only start a comment at the beginning of
+ a line. If the line seems to have the form '# 123 filename'
+ .line and .file directives will appear in the pre-processed output */
+/* Note that input_file.c hand checks for '#' at the beginning of the
+ first line of the input file. This is because the compiler outputs
+ #NO_APP at the beginning of its output. */
+/* Also note that comments like this one will always work. */
+char line_comment_chars[] = "#/";
+
+/* Chars that can be used to separate mant from exp in floating point nums */
+char EXP_CHARS[] = "eE";
+
+/* Chars that mean this number is a floating point constant */
+/* As in 0f12.456 */
+/* or 0d1.2345e12 */
+char FLT_CHARS[] = "rRsSfFdDxXpP";
+
+/* Also be aware that MAXIMUM_NUMBER_OF_CHARS_FOR_FLOAT may have to be
+ changed in read.c. Ideally it shouldn't have to know about it at all,
+ but nothing is ideal around here.
+ */
+int size_reloc_info = sizeof(struct relocation_info);
+
+static unsigned char octal[256];
+#define isoctal(c) octal[c]
+ static unsigned char toHex[256];
+
+struct i860_it {
+ char *error;
+ unsigned long opcode;
+ struct nlist *nlistp;
+ expressionS exp;
+ int pcrel;
+ enum expand_type expand;
+ enum highlow_type highlow;
+ enum reloc_type reloc;
+} the_insn;
+
+#if __STDC__ == 1
+
+#ifdef comment
+static void print_insn(struct i860_it *insn);
+#endif /* comment */
+
+static int getExpression(char *str);
+
+#else /* not __STDC__ */
+
+#ifdef comment
+static void print_insn();
+#endif /* comment */
+
+static int getExpression();
+
+#endif /* not __STDC__ */
+
+static char *expr_end;
+static char last_expand; /* error if expansion after branch */
+
+enum dual
+{
+ DUAL_OFF = 0, DUAL_ON, DUAL_DDOT, DUAL_ONDDOT,
+};
+static enum dual dual_mode = DUAL_OFF; /* dual-instruction mode */
+
+static void
+ s_dual() /* floating point instructions have dual set */
+{
+ dual_mode = DUAL_ON;
+}
+
+static void
+ s_enddual() /* floating point instructions have dual set */
+{
+ dual_mode = DUAL_OFF;
+}
+
+static int atmp = 31; /* temporary register for pseudo's */
+
+static void
+ s_atmp()
+{
+ register int temp;
+ if (strncmp(input_line_pointer, "sp", 2) == 0) {
+ input_line_pointer += 2;
+ atmp = 2;
+ }
+ else if (strncmp(input_line_pointer, "fp", 2) == 0) {
+ input_line_pointer += 2;
+ atmp = 3;
+ }
+ else if (strncmp(input_line_pointer, "r", 1) == 0) {
+ input_line_pointer += 1;
+ temp = get_absolute_expression();
+ if (temp >= 0 && temp <= 31)
+ atmp = temp;
+ else
+ as_bad("Unknown temporary pseudo register");
+ }
+ else {
+ as_bad("Unknown temporary pseudo register");
+ }
+ demand_empty_rest_of_line();
+ return;
+}
+
+/* This function is called once, at assembler startup time. It should
+ set up all the tables, etc. that the MD part of the assembler will need. */
+void
+ md_begin()
+{
+ register char *retval = NULL;
+ int lose = 0;
+ register unsigned int i = 0;
+
+ op_hash = hash_new();
+ if (op_hash == NULL)
+ as_fatal("Virtual memory exhausted");
+
+ while (i < NUMOPCODES)
+ {
+ const char *name = i860_opcodes[i].name;
+ retval = hash_insert(op_hash, name, &i860_opcodes[i]);
+ if (retval != NULL && *retval != '\0')
+ {
+ fprintf (stderr, "internal error: can't hash `%s': %s\n",
+ i860_opcodes[i].name, retval);
+ lose = 1;
+ }
+ do
+ {
+ if (i860_opcodes[i].match & i860_opcodes[i].lose)
+ {
+ fprintf (stderr, "internal error: losing opcode: `%s' \"%s\"\n",
+ i860_opcodes[i].name, i860_opcodes[i].args);
+ lose = 1;
+ }
+ ++i;
+ } while (i < NUMOPCODES
+ && !strcmp(i860_opcodes[i].name, name));
+ }
+
+ if (lose)
+ as_fatal("Broken assembler. No assembly attempted.");
+
+ for (i = '0'; i < '8'; ++i)
+ octal[i] = 1;
+ for (i = '0'; i <= '9'; ++i)
+ toHex[i] = i - '0';
+ for (i = 'a'; i <= 'f'; ++i)
+ toHex[i] = i + 10 - 'a';
+ for (i = 'A'; i <= 'F'; ++i)
+ toHex[i] = i + 10 - 'A';
+}
+
+void
+ md_end()
+{
+ return;
+}
+
+void
+ md_assemble(str)
+char *str;
+{
+ char *toP;
+/* int rsd; FIXME: remove this line. */
+ int no_opcodes = 1;
+ int i;
+ struct i860_it pseudo[3];
+
+ assert(str);
+ i860_ip(str);
+
+ /* check for expandable flag to produce pseudo-instructions */
+ if (the_insn.expand != 0 && the_insn.highlow == NO_SPEC) {
+ for (i = 0; i < 3; i++)
+ pseudo[i] = the_insn;
+
+ switch (the_insn.expand) {
+
+ case E_DELAY:
+ no_opcodes = 1;
+ break;
+
+ case E_MOV:
+ if (the_insn.exp.X_add_symbol == NULL &&
+ the_insn.exp.X_subtract_symbol == NULL &&
+ (the_insn.exp.X_add_number < (1 << 15) &&
+ the_insn.exp.X_add_number >= -(1 << 15)))
+ break;
+ /* or l%const,r0,ireg_dest */
+ pseudo[0].opcode = (the_insn.opcode & 0x001f0000) | 0xe4000000;
+ pseudo[0].highlow = PAIR;
+ /* orh h%const,ireg_dest,ireg_dest */
+ pseudo[1].opcode = (the_insn.opcode & 0x03ffffff) | 0xec000000 |
+ ((the_insn.opcode & 0x001f0000) << 5);
+ pseudo[1].highlow = HIGH;
+ no_opcodes = 2;
+ break;
+
+ case E_ADDR:
+ if (the_insn.exp.X_add_symbol == NULL &&
+ the_insn.exp.X_subtract_symbol == NULL)
+ break;
+ /* orh ha%addr_expr,r0,r31 */
+ pseudo[0].opcode = 0xec000000 | (atmp<<16);
+ pseudo[0].highlow = HIGHADJ;
+ pseudo[0].reloc = LOW0; /* must overwrite */
+ /* l%addr_expr(r31),ireg_dest */
+ pseudo[1].opcode = (the_insn.opcode & ~0x003e0000) | (atmp << 21);
+ pseudo[1].highlow = PAIR;
+ no_opcodes = 2;
+ break;
+
+ case E_U32: /* 2nd version emulates Intel as, not doc. */
+ if (the_insn.exp.X_add_symbol == NULL &&
+ the_insn.exp.X_subtract_symbol == NULL &&
+ (the_insn.exp.X_add_number < (1 << 16) &&
+ the_insn.exp.X_add_number >= 0))
+ break;
+ /* $(opcode)h h%const,ireg_src2,ireg_dest
+ pseudo[0].opcode = (the_insn.opcode & 0xf3ffffff) | 0x0c000000; */
+ /* $(opcode)h h%const,ireg_src2,r31 */
+ pseudo[0].opcode = (the_insn.opcode & 0xf3e0ffff) | 0x0c000000 |
+ (atmp << 16);
+ pseudo[0].highlow = HIGH;
+ /* $(opcode) l%const,ireg_dest,ireg_dest
+ pseudo[1].opcode = (the_insn.opcode & 0xf01f0000) | 0x04000000 |
+ ((the_insn.opcode & 0x001f0000) << 5); */
+ /* $(opcode) l%const,r31,ireg_dest */
+ pseudo[1].opcode = (the_insn.opcode & 0xf01f0000) | 0x04000000 |
+ (atmp << 21);
+ pseudo[1].highlow = PAIR;
+ no_opcodes = 2;
+ break;
+
+ case E_AND: /* 2nd version emulates Intel as, not doc. */
+ if (the_insn.exp.X_add_symbol == NULL &&
+ the_insn.exp.X_subtract_symbol == NULL &&
+ (the_insn.exp.X_add_number < (1 << 16) &&
+ the_insn.exp.X_add_number >= 0))
+ break;
+ /* andnot h%const,ireg_src2,ireg_dest
+ pseudo[0].opcode = (the_insn.opcode & 0x03ffffff) | 0xd4000000; */
+ /* andnot h%const,ireg_src2,r31 */
+ pseudo[0].opcode = (the_insn.opcode & 0x03e0ffff) | 0xd4000000 |
+ (atmp << 16);
+ pseudo[0].highlow = HIGH;
+ pseudo[0].exp.X_add_number = -1 - the_insn.exp.X_add_number;
+ /* andnot l%const,ireg_dest,ireg_dest
+ pseudo[1].opcode = (the_insn.opcode & 0x001f0000) | 0xd4000000 |
+ ((the_insn.opcode & 0x001f0000) << 5); */
+ /* andnot l%const,r31,ireg_dest */
+ pseudo[1].opcode = (the_insn.opcode & 0x001f0000) | 0xd4000000 |
+ (atmp << 21);
+ pseudo[1].highlow = PAIR;
+ pseudo[1].exp.X_add_number = -1 - the_insn.exp.X_add_number;
+ no_opcodes = 2;
+ break;
+
+ case E_S32:
+ if (the_insn.exp.X_add_symbol == NULL &&
+ the_insn.exp.X_subtract_symbol == NULL &&
+ (the_insn.exp.X_add_number < (1 << 15) &&
+ the_insn.exp.X_add_number >= -(1 << 15)))
+ break;
+ /* orh h%const,r0,r31 */
+ pseudo[0].opcode = 0xec000000 | (atmp << 16);
+ pseudo[0].highlow = HIGH;
+ /* or l%const,r31,r31 */
+ pseudo[1].opcode = 0xe4000000 | (atmp << 21) | (atmp << 16);
+ pseudo[1].highlow = PAIR;
+ /* r31,ireg_src2,ireg_dest */
+ pseudo[2].opcode = (the_insn.opcode & ~0x0400ffff) | (atmp << 11);
+ pseudo[2].reloc = NO_RELOC;
+ no_opcodes = 3;
+ break;
+
+ default:
+ as_fatal("failed sanity check.");
+ }
+
+ the_insn = pseudo[0];
+ /* check for expanded opcode after branch or in dual */
+ if (no_opcodes > 1 && last_expand == 1)
+ as_warn("Expanded opcode after delayed branch: `%s'", str);
+ if (no_opcodes > 1 && dual_mode != DUAL_OFF)
+ as_warn("Expanded opcode in dual mode: `%s'", str);
+ }
+
+ i = 0;
+ do { /* always produce at least one opcode */
+ toP = frag_more(4);
+ /* put out the opcode */
+ md_number_to_chars(toP, the_insn.opcode, 4);
+
+ /* check for expanded opcode after branch or in dual */
+ last_expand = the_insn.pcrel;
+
+ /* put out the symbol-dependent stuff */
+ if (the_insn.reloc != NO_RELOC) {
+ fix_new(frag_now, /* which frag */
+ (toP - frag_now->fr_literal), /* where */
+ 4, /* size */
+ the_insn.exp.X_add_symbol,
+ the_insn.exp.X_subtract_symbol,
+ the_insn.exp.X_add_number,
+ the_insn.pcrel,
+ /* merge bit fields into one argument */
+ (int)(((the_insn.highlow & 0x3) << 4) | (the_insn.reloc & 0xf)));
+ }
+ the_insn = pseudo[++i];
+ } while (--no_opcodes > 0);
+
+}
+
+static void
+ i860_ip(str)
+char *str;
+{
+ char *s;
+ const char *args;
+ char c;
+/* unsigned long i; FIXME: remove this line. */
+ struct i860_opcode *insn;
+ char *argsStart;
+ unsigned long opcode;
+ unsigned int mask;
+ int match = 0;
+ int comma = 0;
+
+
+ for (s = str; islower(*s) || *s == '.' || *s == '3'; ++s)
+ ;
+ switch (*s) {
+
+ case '\0':
+ break;
+
+ case ',':
+ comma = 1;
+
+ /*FALLTHROUGH*/
+
+ case ' ':
+ *s++ = '\0';
+ break;
+
+ default:
+ as_bad("Unknown opcode: `%s'", str);
+ exit(1);
+ }
+
+ if (strncmp(str, "d.", 2) == 0) { /* check for d. opcode prefix */
+ if (dual_mode == DUAL_ON)
+ dual_mode = DUAL_ONDDOT;
+ else
+ dual_mode = DUAL_DDOT;
+ str += 2;
+ }
+
+ if ((insn = (struct i860_opcode *) hash_find(op_hash, str)) == NULL) {
+ if (dual_mode == DUAL_DDOT || dual_mode == DUAL_ONDDOT)
+ str -= 2;
+ as_bad("Unknown opcode: `%s'", str);
+ return;
+ }
+ if (comma) {
+ *--s = ',';
+ }
+ argsStart = s;
+ for (;;) {
+ opcode = insn->match;
+ memset(&the_insn, '\0', sizeof(the_insn));
+ the_insn.reloc = NO_RELOC;
+
+ /*
+ * Build the opcode, checking as we go to make
+ * sure that the operands match
+ */
+ for (args = insn->args; ; ++args) {
+ switch (*args) {
+
+ case '\0': /* end of args */
+ if (*s == '\0') {
+ match = 1;
+ }
+ break;
+
+ case '+':
+ case '(': /* these must match exactly */
+ case ')':
+ case ',':
+ case ' ':
+ if (*s++ == *args)
+ continue;
+ break;
+
+ case '#': /* must be at least one digit */
+ if (isdigit(*s++)) {
+ while (isdigit(*s)) {
+ ++s;
+ }
+ continue;
+ }
+ break;
+
+ case '1': /* next operand must be a register */
+ case '2':
+ case 'd':
+ switch (*s) {
+
+ case 'f': /* frame pointer */
+ s++;
+ if (*s++ == 'p') {
+ mask = 0x3;
+ break;
+ }
+ goto error;
+
+ case 's': /* stack pointer */
+ s++;
+ if (*s++ == 'p') {
+ mask= 0x2;
+ break;
+ }
+ goto error;
+
+ case 'r': /* any register */
+ s++;
+ if (!isdigit(c = *s++)) {
+ goto error;
+ }
+ if (isdigit(*s)) {
+ if ((c = 10 * (c - '0') + (*s++ - '0')) >= 32) {
+ goto error;
+ }
+ } else {
+ c -= '0';
+ }
+ mask= c;
+ break;
+
+ default: /* not this opcode */
+ goto error;
+ }
+ /*
+ * Got the register, now figure out where
+ * it goes in the opcode.
+ */
+ switch (*args) {
+
+ case '1':
+ opcode |= mask << 11;
+ continue;
+
+ case '2':
+ opcode |= mask << 21;
+ continue;
+
+ case 'd':
+ opcode |= mask << 16;
+ continue;
+
+ }
+ break;
+
+ case 'e': /* next operand is a floating point register */
+ case 'f':
+ case 'g':
+ if (*s++ == 'f' && isdigit(*s)) {
+ mask = *s++;
+ if (isdigit(*s)) {
+ mask = 10 * (mask - '0') + (*s++ - '0');
+ if (mask >= 32) {
+ break;
+ }
+ } else {
+ mask -= '0';
+ }
+ switch (*args) {
+
+ case 'e':
+ opcode |= mask << 11;
+ continue;
+
+ case 'f':
+ opcode |= mask << 21;
+ continue;
+
+ case 'g':
+ opcode |= mask << 16;
+ if (dual_mode != DUAL_OFF)
+ opcode |= (1 << 9); /* dual mode instruction */
+ if (dual_mode == DUAL_DDOT)
+ dual_mode = DUAL_OFF;
+ if (dual_mode == DUAL_ONDDOT)
+ dual_mode = DUAL_ON;
+ if ((opcode & (1 << 10)) && (mask == ((opcode >> 11) & 0x1f)))
+ as_warn("Fsr1 equals fdest with Pipelining");
+ continue;
+ }
+ }
+ break;
+
+ case 'c': /* next operand must be a control register */
+ if (strncmp(s, "fir", 3) == 0) {
+ opcode |= 0x0 << 21;
+ s += 3;
+ continue;
+ }
+ if (strncmp(s, "psr", 3) == 0) {
+ opcode |= 0x1 << 21;
+ s += 3;
+ continue;
+ }
+ if (strncmp(s, "dirbase", 7) == 0) {
+ opcode |= 0x2 << 21;
+ s += 7;
+ continue;
+ }
+ if (strncmp(s, "db", 2) == 0) {
+ opcode |= 0x3 << 21;
+ s += 2;
+ continue;
+ }
+ if (strncmp(s, "fsr", 3) == 0) {
+ opcode |= 0x4 << 21;
+ s += 3;
+ continue;
+ }
+ if (strncmp(s, "epsr", 4) == 0) {
+ opcode |= 0x5 << 21;
+ s += 4;
+ continue;
+ }
+ break;
+
+ case '5': /* 5 bit immediate in src1 */
+ memset(&the_insn, '\0', sizeof(the_insn));
+ if ( !getExpression(s)) {
+ s = expr_end;
+ if (the_insn.exp.X_add_number & ~0x1f)
+ as_bad("5-bit immediate too large");
+ opcode |= (the_insn.exp.X_add_number & 0x1f) << 11;
+ memset(&the_insn, '\0', sizeof(the_insn));
+ the_insn.reloc = NO_RELOC;
+ continue;
+ }
+ break;
+
+ case 'l': /* 26 bit immediate, relative branch */
+ the_insn.reloc = BRADDR;
+ the_insn.pcrel = 1;
+ goto immediate;
+
+ case 's': /* 16 bit immediate, split relative branch */
+ /* upper 5 bits of offset in dest field */
+ the_insn.pcrel = 1;
+ the_insn.reloc = SPLIT0;
+ goto immediate;
+
+ case 'S': /* 16 bit immediate, split (st), aligned */
+ if (opcode & (1 << 28))
+ if (opcode & 0x1)
+ the_insn.reloc = SPLIT2;
+ else
+ the_insn.reloc = SPLIT1;
+ else
+ the_insn.reloc = SPLIT0;
+ goto immediate;
+
+ case 'I': /* 16 bit immediate, aligned */
+ if (opcode & (1 << 28))
+ if (opcode & 0x1)
+ the_insn.reloc = LOW2;
+ else
+ the_insn.reloc = LOW1;
+ else
+ the_insn.reloc = LOW0;
+ goto immediate;
+
+ case 'i': /* 16 bit immediate */
+ the_insn.reloc = LOW0;
+
+ /*FALLTHROUGH*/
+
+ immediate:
+ if (*s == ' ')
+ s++;
+ if (strncmp(s, "ha%", 3) == 0) {
+ the_insn.highlow = HIGHADJ;
+ s += 3;
+ } else if (strncmp(s, "h%", 2) == 0) {
+ the_insn.highlow = HIGH;
+ s += 2;
+ } else if (strncmp(s, "l%", 2) == 0) {
+ the_insn.highlow = PAIR;
+ s += 2;
+ }
+ the_insn.expand = insn->expand;
+
+ /* Note that if the getExpression() fails, we will still have
+ created U entries in the symbol table for the 'symbols'
+ in the input string. Try not to create U symbols for
+ registers, etc. */
+
+ if ( !getExpression(s)) {
+ s = expr_end;
+ continue;
+ }
+ break;
+
+ default:
+ as_fatal("failed sanity check.");
+ }
+ break;
+ }
+ error:
+ if (match == 0)
+ {
+ /* Args don't match. */
+ if (&insn[1] - i860_opcodes < NUMOPCODES
+ && !strcmp(insn->name, insn[1].name))
+ {
+ ++insn;
+ s = argsStart;
+ continue;
+ }
+ else
+ {
+ as_bad("Illegal operands");
+ return;
+ }
+ }
+ break;
+ }
+
+ the_insn.opcode = opcode;
+ return;
+}
+
+static int
+ getExpression(str)
+char *str;
+{
+ char *save_in;
+ segT seg;
+
+ save_in = input_line_pointer;
+ input_line_pointer = str;
+ switch (seg = expression(&the_insn.exp)) {
+
+ case SEG_ABSOLUTE:
+ case SEG_TEXT:
+ case SEG_DATA:
+ case SEG_BSS:
+ case SEG_UNKNOWN:
+ case SEG_DIFFERENCE:
+ case SEG_BIG:
+ case SEG_ABSENT:
+ break;
+
+ default:
+ the_insn.error = "bad segment";
+ expr_end = input_line_pointer;
+ input_line_pointer=save_in;
+ return 1;
+ }
+ expr_end = input_line_pointer;
+ input_line_pointer = save_in;
+ return 0;
+}
+
+
+/*
+ This is identical to the md_atof in m68k.c. I think this is right,
+ but I'm not sure.
+
+ Turn a string in input_line_pointer into a floating point constant of type
+ type, and store the appropriate bytes in *litP. The number of LITTLENUMS
+ emitted is stored in *sizeP. An error message is returned, or NULL on OK.
+ */
+
+/* Equal to MAX_PRECISION in atof-ieee.c */
+#define MAX_LITTLENUMS 6
+
+char *
+ md_atof(type,litP,sizeP)
+char type;
+char *litP;
+int *sizeP;
+{
+ int prec;
+ LITTLENUM_TYPE words[MAX_LITTLENUMS];
+ LITTLENUM_TYPE *wordP;
+ char *t;
+ char *atof_ieee();
+
+ switch (type) {
+
+ case 'f':
+ case 'F':
+ case 's':
+ case 'S':
+ prec = 2;
+ break;
+
+ case 'd':
+ case 'D':
+ case 'r':
+ case 'R':
+ prec = 4;
+ break;
+
+ case 'x':
+ case 'X':
+ prec = 6;
+ break;
+
+ case 'p':
+ case 'P':
+ prec = 6;
+ break;
+
+ default:
+ *sizeP=0;
+ return "Bad call to MD_ATOF()";
+ }
+ t=atof_ieee(input_line_pointer,type,words);
+ if (t)
+ input_line_pointer=t;
+ *sizeP=prec * sizeof(LITTLENUM_TYPE);
+ for (wordP=words;prec--;) {
+ md_number_to_chars(litP,(long)(*wordP++),sizeof(LITTLENUM_TYPE));
+ litP+=sizeof(LITTLENUM_TYPE);
+ }
+ return ""; /* Someone should teach Dean about null pointers */
+}
+
+/*
+ * Write out big-endian.
+ */
+void
+ md_number_to_chars(buf, val, n)
+char *buf;
+long val;
+int n;
+{
+ switch (n) {
+
+ case 4:
+ *buf++ = val >> 24;
+ *buf++ = val >> 16;
+ case 2:
+ *buf++ = val >> 8;
+ case 1:
+ *buf = val;
+ break;
+
+ default:
+ as_fatal("failed sanity check.");
+ }
+ return;
+}
+
+void md_number_to_imm(buf, val, n, fixP)
+char *buf;
+long val;
+int n;
+fixS *fixP;
+{
+ enum reloc_type reloc = fixP->fx_r_type & 0xf;
+ enum highlow_type highlow = (fixP->fx_r_type >> 4) & 0x3;
+
+ assert(buf);
+ assert(n == 4); /* always on i860 */
+
+ switch (highlow) {
+
+ case HIGHADJ: /* adjusts the high-order 16-bits */
+ if (val & (1 << 15))
+ val += (1 << 16);
+
+ /*FALLTHROUGH*/
+
+ case HIGH: /* selects the high-order 16-bits */
+ val >>= 16;
+ break;
+
+ case PAIR: /* selects the low-order 16-bits */
+ val = val & 0xffff;
+ break;
+
+ default:
+ break;
+ }
+
+ switch (reloc) {
+
+ case BRADDR: /* br, call, bc, bc.t, bnc, bnc.t w/26-bit immediate */
+ if (fixP->fx_pcrel != 1)
+ as_bad("26-bit branch w/o pc relative set: 0x%08x", val);
+ val >>= 2; /* align pcrel offset, see manual */
+
+ if (val >= (1 << 25) || val < -(1 << 25)) /* check for overflow */
+ as_bad("26-bit branch offset overflow: 0x%08x", val);
+ buf[0] = (buf[0] & 0xfc) | ((val >> 24) & 0x3);
+ buf[1] = val >> 16;
+ buf[2] = val >> 8;
+ buf[3] = val;
+ break;
+
+ case SPLIT2: /* 16 bit immediate, 4-byte aligned */
+ if (val & 0x3)
+ as_bad("16-bit immediate 4-byte alignment error: 0x%08x", val);
+ val &= ~0x3; /* 4-byte align value */
+ /*FALLTHROUGH*/
+ case SPLIT1: /* 16 bit immediate, 2-byte aligned */
+ if (val & 0x1)
+ as_bad("16-bit immediate 2-byte alignment error: 0x%08x", val);
+ val &= ~0x1; /* 2-byte align value */
+ /*FALLTHROUGH*/
+ case SPLIT0: /* st,bla,bte,btne w/16-bit immediate */
+ if (fixP->fx_pcrel == 1)
+ val >>= 2; /* align pcrel offset, see manual */
+ /* check for bounds */
+ if (highlow != PAIR && (val >= (1 << 16) || val < -(1 << 15)))
+ as_bad("16-bit branch offset overflow: 0x%08x", val);
+ buf[1] = (buf[1] & ~0x1f) | ((val >> 11) & 0x1f);
+ buf[2] = (buf[2] & ~0x7) | ((val >> 8) & 0x7);
+ buf[3] |= val; /* perserve bottom opcode bits */
+ break;
+
+ case LOW4: /* fld,pfld,pst,flush 16-byte aligned */
+ if (val & 0xf)
+ as_bad("16-bit immediate 16-byte alignment error: 0x%08x", val);
+ val &= ~0xf; /* 16-byte align value */
+ /*FALLTHROUGH*/
+ case LOW3: /* fld,pfld,pst,flush 8-byte aligned */
+ if (val & 0x7)
+ as_bad("16-bit immediate 8-byte alignment error: 0x%08x", val);
+ val &= ~0x7; /* 8-byte align value */
+ /*FALLTHROUGH*/
+ case LOW2: /* 16 bit immediate, 4-byte aligned */
+ if (val & 0x3)
+ as_bad("16-bit immediate 4-byte alignment error: 0x%08x", val);
+ val &= ~0x3; /* 4-byte align value */
+ /*FALLTHROUGH*/
+ case LOW1: /* 16 bit immediate, 2-byte aligned */
+ if (val & 0x1)
+ as_bad("16-bit immediate 2-byte alignment error: 0x%08x", val);
+ val &= ~0x1; /* 2-byte align value */
+ /*FALLTHROUGH*/
+ case LOW0: /* 16 bit immediate, byte aligned */
+ /* check for bounds */
+ if (highlow != PAIR && (val >= (1 << 16) || val < -(1 << 15)))
+ as_bad("16-bit immediate overflow: 0x%08x", val);
+ buf[2] = val >> 8;
+ buf[3] |= val; /* perserve bottom opcode bits */
+ break;
+
+ case RELOC_32:
+ md_number_to_chars(buf, val, 4);
+ break;
+
+ case NO_RELOC:
+ default:
+ as_bad("bad relocation type: 0x%02x", reloc);
+ break;
+ }
+ return;
+}
+
+/* should never be called for i860 */
+void
+ md_create_short_jump(ptr, from_addr, to_addr, frag, to_symbol)
+char *ptr;
+long from_addr, to_addr;
+fragS *frag;
+symbolS *to_symbol;
+{
+ as_fatal("i860_create_short_jmp\n");
+}
+
+/* should never be called for i860 */
+void
+ md_number_to_disp(buf, val, n)
+char *buf;
+long val;
+int n;
+{
+ as_fatal("md_number_to_disp\n");
+}
+
+/* should never be called for i860 */
+void
+ md_number_to_field(buf,val,fix)
+char *buf;
+long val;
+void *fix;
+{
+ as_fatal("i860_number_to_field\n");
+}
+
+/* the bit-field entries in the relocation_info struct plays hell
+ with the byte-order problems of cross-assembly. So as a hack,
+ I added this mach. dependent ri twiddler. Ugly, but it gets
+ you there. -KWK */
+/* on i860: first 4 bytes are normal unsigned long address, next three
+ bytes are index, most sig. byte first. Byte 7 is broken up with
+ bit 7 as pcrel, bit 6 as extern, and the lower six bits as
+ relocation type (highlow 5-4). Next 4 bytes are long addend. */
+/* Thanx and a tip of the hat to Michael Bloom, mb@ttidca.tti.com */
+void
+ md_ri_to_chars(ri_p, ri)
+struct relocation_info *ri_p, ri;
+{
+#if 0
+ unsigned char the_bytes[sizeof(*ri_p)];
+
+ /* this is easy */
+ md_number_to_chars(the_bytes, ri.r_address, sizeof(ri.r_address));
+ /* now the fun stuff */
+ the_bytes[4] = (ri.r_index >> 16) & 0x0ff;
+ the_bytes[5] = (ri.r_index >> 8) & 0x0ff;
+ the_bytes[6] = ri.r_index & 0x0ff;
+ the_bytes[7] = ((ri.r_extern << 7) & 0x80) | (0 & 0x60) | (ri.r_type & 0x1F);
+ /* Also easy */
+ md_number_to_chars(&the_bytes[8], ri.r_addend, sizeof(ri.r_addend));
+ /* now put it back where you found it, Junior... */
+ memcpy((char *) ri_p, the_bytes, sizeof(*ri_p));
+#endif
+}
+
+/* should never be called for i860 */
+void
+ md_convert_frag(headers, fragP)
+object_headers *headers;
+register fragS *fragP;
+{
+ as_fatal("i860_convert_frag\n");
+}
+
+/* should never be called for i860 */
+void
+ md_create_long_jump(ptr, from_addr, to_addr, frag, to_symbol)
+char *ptr;
+long from_addr,
+ to_addr;
+fragS *frag;
+symbolS *to_symbol;
+{
+ as_fatal("i860_create_long_jump\n");
+}
+
+/* should never be called for i860 */
+int
+ md_estimate_size_before_relax(fragP, segtype)
+register fragS *fragP;
+segT segtype;
+{
+ as_fatal("i860_estimate_size_before_relax\n");
+ return(0);
+}
+
+#ifdef comment
+/* for debugging only, must match enum reloc_type */
+static char *Reloc[] = {
+ "NO_RELOC",
+ "BRADDR",
+ "LOW0",
+ "LOW1",
+ "LOW2",
+ "LOW3",
+ "LOW4",
+ "SPLIT0",
+ "SPLIT1",
+ "SPLIT2",
+ "RELOC_32",
+};
+static char *Highlow[] = {
+ "NO_SPEC",
+ "PAIR",
+ "HIGH",
+ "HIGHADJ",
+};
+
+static void
+ print_insn(insn)
+struct i860_it *insn;
+{
+ if (insn->error) {
+ fprintf(stderr, "ERROR: %s\n", insn->error);
+ }
+ fprintf(stderr, "opcode=0x%08x\t", insn->opcode);
+ fprintf(stderr, "expand=0x%08x\t", insn->expand);
+ fprintf(stderr, "reloc = %s\t", Reloc[insn->reloc]);
+ fprintf(stderr, "highlow = %s\n", Highlow[insn->highlow]);
+ fprintf(stderr, "exp = {\n");
+ fprintf(stderr, "\t\tX_add_symbol = %s\n",
+ insn->exp.X_add_symbol ?
+ (S_GET_NAME(insn->exp.X_add_symbol) ?
+ S_GET_NAME(insn->exp.X_add_symbol) : "???") : "0");
+ fprintf(stderr, "\t\tX_sub_symbol = %s\n",
+ insn->exp.X_subtract_symbol ?
+ (S_GET_NAME(insn->exp.X_subtract_symbol) ?
+ S_GET_NAME(insn->exp.X_subtract_symbol) : "???") : "0");
+ fprintf(stderr, "\t\tX_add_number = %d\n",
+ insn->exp.X_add_number);
+ fprintf(stderr, "}\n");
+ return;
+}
+#endif /* comment */
+
+int
+ md_parse_option(argP,cntP,vecP)
+char **argP;
+int *cntP;
+char ***vecP;
+{
+ return 1;
+}
+
+#ifdef comment
+/*
+ * I860 relocations are completely different, so it needs
+ * this machine dependent routine to emit them.
+ */
+void
+ emit_machine_reloc(fixP, segment_address_in_file)
+register fixS *fixP;
+relax_addressT segment_address_in_file;
+{
+ struct reloc_info_i860 ri;
+ register symbolS *symbolP;
+ extern char *next_object_file_charP;
+ long add_number;
+
+ memset((char *) &ri, '\0', sizeof(ri));
+ for (; fixP; fixP = fixP->fx_next) {
+
+ if (fixP->fx_r_type & ~0x3f) {
+ as_fatal("fixP->fx_r_type = %d\n", fixP->fx_r_type);
+ }
+ ri.r_pcrel = fixP->fx_pcrel;
+ ri.r_type = fixP->fx_r_type;
+
+ if ((symbolP = fixP->fx_addsy) != NULL) {
+ ri.r_address = fixP->fx_frag->fr_address +
+ fixP->fx_where - segment_address_in_file;
+ if (!S_IS_DEFINED(symbolP)) {
+ ri.r_extern = 1;
+ ri.r_symbolnum = symbolP->sy_number;
+ } else {
+ ri.r_extern = 0;
+ ri.r_symbolnum = S_GET_TYPE(symbolP);
+ }
+ if (symbolP && symbolP->sy_frag) {
+ ri.r_addend = symbolP->sy_frag->fr_address;
+ }
+ ri.r_type = fixP->fx_r_type;
+ if (fixP->fx_pcrel) {
+ /* preserve actual offset vs. pc + 4 */
+ ri.r_addend -= (ri.r_address + 4);
+ } else {
+ ri.r_addend = fixP->fx_addnumber;
+ }
+
+ md_ri_to_chars((char *) &ri, ri);
+ append(&next_object_file_charP, (char *)& ri, sizeof(ri));
+ }
+ }
+ return;
+}
+#endif /* comment */
+
+#ifdef OBJ_AOUT
+
+/* on i860: first 4 bytes are normal unsigned long address, next three
+ bytes are index, most sig. byte first. Byte 7 is broken up with
+ bit 7 as pcrel, bit 6 as extern, and the lower six bits as
+ relocation type (highlow 5-4). Next 4 bytes are long addend.
+
+ ie,
+
+ struct reloc_info_i860 {
+ unsigned long r_address;
+ unsigned int r_symbolnum : 24;
+ unsigned int r_pcrel : 1;
+ unsigned int r_extern : 1;
+ unsigned int r_type : 6;
+ long r_addend;
+ }
+
+ */
+
+int md_reloc_size = 12;
+
+void tc_aout_fix_to_chars(where, fixP, segment_address_in_file)
+char *where;
+fixS *fixP;
+relax_addressT segment_address_in_file;
+{
+ long r_index;
+ long r_extern;
+ long r_addend = 0;
+ long r_address;
+
+ know(fixP->fx_addsy);
+ know(!(fixP->fx_r_type & ~0x3f));
+
+ if (!S_IS_DEFINED(fixP->fx_addsy)) {
+ r_extern = 1;
+ r_index = fixP->fx_addsy->sy_number;
+ } else {
+ r_extern = 0;
+ r_index = S_GET_TYPE(fixP->fx_addsy);
+ }
+
+ md_number_to_chars(where,
+ r_address = fixP->fx_frag->fr_address + fixP->fx_where - segment_address_in_file,
+ 4);
+
+ where[4] = (r_index >> 16) & 0x0ff;
+ where[5] = (r_index >> 8) & 0x0ff;
+ where[6] = r_index & 0x0ff;
+ where[7] = (((fixP->fx_pcrel << 7) & 0x80)
+ | ((r_extern << 6) & 0x40)
+ | (fixP->fx_r_type & 0x3F));
+
+ if (fixP->fx_addsy->sy_frag) {
+ r_addend = fixP->fx_addsy->sy_frag->fr_address;
+ }
+
+ if (fixP->fx_pcrel) {
+ /* preserve actual offset vs. pc + 4 */
+ r_addend -= (r_address + 4);
+ } else {
+ r_addend = fixP->fx_addnumber;
+ }
+
+ md_number_to_chars(&where[8], r_addend, 4);
+
+ return;
+} /* tc_aout_fix_to_chars() */
+
+#endif /* OBJ_AOUT */
+
+/* Parse an operand that is machine-specific.
+ We just return without modifying the expression if we have nothing
+ to do. */
+
+/* ARGSUSED */
+void
+ md_operand (expressionP)
+expressionS *expressionP;
+{
+}
+
+/* We have no need to default values of symbols. */
+
+/* ARGSUSED */
+symbolS *
+ md_undefined_symbol (name)
+char *name;
+{
+ return 0;
+}
+
+/* Round up a section size to the appropriate boundary. */
+long
+ md_section_align (segment, size)
+segT segment;
+long size;
+{
+ return size; /* Byte alignment is fine */
+}
+
+/* Exactly what point is a PC-relative offset relative TO?
+ On the i860, they're relative to the address of the offset, plus
+ its size. (??? Is this right? FIXME-SOON!) */
+long
+ md_pcrel_from (fixP)
+fixS *fixP;
+{
+ return fixP->fx_size + fixP->fx_where + fixP->fx_frag->fr_address;
+}
+
+void
+ md_apply_fix(fixP, val)
+fixS *fixP;
+long val;
+{
+ char *place = fixP->fx_where + fixP->fx_frag->fr_literal;
+
+ /* fixme-soon: looks to me like i860 never has bit fixes. Let's see. xoxorich. */
+ know(fixP->fx_bit_fixP == NULL);
+ if (!fixP->fx_bit_fixP) {
+
+ /* fixme-soon: also looks like fx_im_disp is always 0. Let's see. xoxorich. */
+ know(fixP->fx_im_disp == 0);
+ switch (fixP->fx_im_disp) {
+ case 0:
+ fixP->fx_addnumber = val;
+ md_number_to_imm(place, val, fixP->fx_size, fixP);
+ break;
+ case 1:
+ md_number_to_disp(place,
+ fixP->fx_pcrel ? val + fixP->fx_pcrel_adjust : val,
+ fixP->fx_size);
+ break;
+ case 2: /* fix requested for .long .word etc */
+ md_number_to_chars(place, val, fixP->fx_size);
+ break;
+ default:
+ as_fatal("Internal error in md_apply_fix() in file \"%s\"", __FILE__);
+ } /* OVE: maybe one ought to put _imm _disp _chars in one md-func */
+ } else {
+ md_number_to_field(place, val, fixP->fx_bit_fixP);
+ }
+
+ return;
+} /* md_apply_fix() */
+
+/*
+ * Local Variables:
+ * fill-column: 131
+ * comment-column: 0
+ * End:
+ */
+
+/* end of tc-i860.c */
diff --git a/gnu/usr.bin/as/config/tc-i860.h b/gnu/usr.bin/as/config/tc-i860.h
new file mode 100644
index 0000000..adc0d8f
--- /dev/null
+++ b/gnu/usr.bin/as/config/tc-i860.h
@@ -0,0 +1,24 @@
+/*
+ * This file is tc-i860.h.
+ */
+
+#define TC_I860 1
+
+#define NO_LISTING
+
+#ifdef OLD_GAS
+#define REVERSE_SORT_RELOCS
+#endif /* OLD_GAS */
+
+#define tc_headers_hook(a) {;} /* not used */
+#define tc_crawl_symbol_chain(a) {;} /* not used */
+#define tc_aout_pre_write_hook(x) {;} /* not used */
+
+/*
+ * Local Variables:
+ * comment-column: 0
+ * fill-column: 131
+ * End:
+ */
+
+/* end of tc-i860.h */
diff --git a/gnu/usr.bin/as/config/tc-i960.c b/gnu/usr.bin/as/config/tc-i960.c
new file mode 100644
index 0000000..37089c3
--- /dev/null
+++ b/gnu/usr.bin/as/config/tc-i960.c
@@ -0,0 +1,2759 @@
+/* tc-i960.c - All the i80960-specific stuff
+ Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
+
+ This file is part of GAS.
+
+ GAS is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GAS is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GAS; see the file COPYING. If not, write to
+ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* See comment on md_parse_option for 80960-specific invocation options. */
+
+/******************************************************************************
+ * i80690 NOTE!!!:
+ * Header, symbol, and relocation info will be used on the host machine
+ * only -- only executable code is actually downloaded to the i80960.
+ * Therefore, leave all such information in host byte order.
+ *
+ * (That's a slight lie -- we DO download some header information, but
+ * the downloader converts the file format and corrects the byte-ordering
+ * of the relevant fields while doing so.)
+ *
+ ***************************************************************************** */
+
+/* There are 4 different lengths of (potentially) symbol-based displacements
+ * in the 80960 instruction set, each of which could require address fix-ups
+ * and (in the case of external symbols) emission of relocation directives:
+ *
+ * 32-bit (MEMB)
+ * This is a standard length for the base assembler and requires no
+ * special action.
+ *
+ * 13-bit (COBR)
+ * This is a non-standard length, but the base assembler has a hook for
+ * bit field address fixups: the fixS structure can point to a descriptor
+ * of the field, in which case our md_number_to_field() routine gets called
+ * to process it.
+ *
+ * I made the hook a little cleaner by having fix_new() (in the base
+ * assembler) return a pointer to the fixS in question. And I made it a
+ * little simpler by storing the field size (in this case 13) instead of
+ * of a pointer to another structure: 80960 displacements are ALWAYS
+ * stored in the low-order bits of a 4-byte word.
+ *
+ * Since the target of a COBR cannot be external, no relocation directives
+ * for this size displacement have to be generated. But the base assembler
+ * had to be modified to issue error messages if the symbol did turn out
+ * to be external.
+ *
+ * 24-bit (CTRL)
+ * Fixups are handled as for the 13-bit case (except that 24 is stored
+ * in the fixS).
+ *
+ * The relocation directive generated is the same as that for the 32-bit
+ * displacement, except that it's PC-relative (the 32-bit displacement
+ * never is). The i80960 version of the linker needs a mod to
+ * distinguish and handle the 24-bit case.
+ *
+ * 12-bit (MEMA)
+ * MEMA formats are always promoted to MEMB (32-bit) if the displacement
+ * is based on a symbol, because it could be relocated at link time.
+ * The only time we use the 12-bit format is if an absolute value of
+ * less than 4096 is specified, in which case we need neither a fixup nor
+ * a relocation directive.
+ */
+
+#include <stdio.h>
+#include <ctype.h>
+
+#include "as.h"
+
+#include "obstack.h"
+
+#include "opcode/i960.h"
+
+extern char *input_line_pointer;
+extern struct hash_control *po_hash;
+extern char *next_object_file_charP;
+
+#ifdef OBJ_COFF
+int md_reloc_size = sizeof(struct reloc);
+#else /* OBJ_COFF */
+int md_reloc_size = sizeof(struct relocation_info);
+#endif /* OBJ_COFF */
+
+/***************************
+ * Local i80960 routines *
+ ************************** */
+
+static void brcnt_emit(); /* Emit branch-prediction instrumentation code */
+static char * brlab_next(); /* Return next branch local label */
+void brtab_emit(); /* Emit br-predict instrumentation table */
+static void cobr_fmt(); /* Generate COBR instruction */
+static void ctrl_fmt(); /* Generate CTRL instruction */
+static char * emit(); /* Emit (internally) binary */
+static int get_args(); /* Break arguments out of comma-separated list */
+static void get_cdisp(); /* Handle COBR or CTRL displacement */
+static char * get_ispec(); /* Find index specification string */
+static int get_regnum(); /* Translate text to register number */
+static int i_scan(); /* Lexical scan of instruction source */
+static void mem_fmt(); /* Generate MEMA or MEMB instruction */
+static void mema_to_memb(); /* Convert MEMA instruction to MEMB format */
+static segT parse_expr(); /* Parse an expression */
+static int parse_ldconst();/* Parse and replace a 'ldconst' pseudo-op */
+static void parse_memop(); /* Parse a memory operand */
+static void parse_po(); /* Parse machine-dependent pseudo-op */
+static void parse_regop(); /* Parse a register operand */
+static void reg_fmt(); /* Generate a REG format instruction */
+void reloc_callj(); /* Relocate a 'callj' instruction */
+static void relax_cobr(); /* "De-optimize" cobr into compare/branch */
+static void s_leafproc(); /* Process '.leafproc' pseudo-op */
+static void s_sysproc(); /* Process '.sysproc' pseudo-op */
+static int shift_ok(); /* Will a 'shlo' substiture for a 'ldconst'? */
+static void syntax(); /* Give syntax error */
+static int targ_has_sfr(); /* Target chip supports spec-func register? */
+static int targ_has_iclass();/* Target chip supports instruction set? */
+/* static void unlink_sym(); */ /* Remove a symbol from the symbol list */
+
+/* See md_parse_option() for meanings of these options */
+static char norelax = 0; /* True if -norelax switch seen */
+static char instrument_branches = 0; /* True if -b switch seen */
+
+/* Characters that always start a comment.
+ * If the pre-processor is disabled, these aren't very useful.
+ */
+char comment_chars[] = "#";
+
+/* Characters that only start a comment at the beginning of
+ * a line. If the line seems to have the form '# 123 filename'
+ * .line and .file directives will appear in the pre-processed output.
+ *
+ * Note that input_file.c hand checks for '#' at the beginning of the
+ * first line of the input file. This is because the compiler outputs
+ * #NO_APP at the beginning of its output.
+ */
+
+/* Also note that comments started like this one will always work. */
+
+char line_comment_chars[] = "";
+
+/* Chars that can be used to separate mant from exp in floating point nums */
+char EXP_CHARS[] = "eE";
+
+/* Chars that mean this number is a floating point constant,
+ * as in 0f12.456 or 0d1.2345e12
+ */
+char FLT_CHARS[] = "fFdDtT";
+
+
+/* Table used by base assembler to relax addresses based on varying length
+ * instructions. The fields are:
+ * 1) most positive reach of this state,
+ * 2) most negative reach of this state,
+ * 3) how many bytes this mode will add to the size of the current frag
+ * 4) which index into the table to try if we can't fit into this one.
+ *
+ * For i80960, the only application is the (de-)optimization of cobr
+ * instructions into separate compare and branch instructions when a 13-bit
+ * displacement won't hack it.
+ */
+const relax_typeS
+ md_relax_table[] = {
+ {0, 0, 0,0}, /* State 0 => no more relaxation possible */
+ {4088, -4096, 0,2}, /* State 1: conditional branch (cobr) */
+ {0x800000-8,-0x800000,4,0}, /* State 2: compare (reg) & branch (ctrl) */
+ };
+
+
+/* These are the machine dependent pseudo-ops.
+ *
+ * This table describes all the machine specific pseudo-ops the assembler
+ * has to support. The fields are:
+ * pseudo-op name without dot
+ * function to call to execute this pseudo-op
+ * integer arg to pass to the function
+ */
+#define S_LEAFPROC 1
+#define S_SYSPROC 2
+
+const pseudo_typeS
+ md_pseudo_table[] = {
+
+ { "bss", s_lcomm, 1 },
+ { "extended", float_cons, 't' },
+ { "leafproc", parse_po, S_LEAFPROC },
+ { "sysproc", parse_po, S_SYSPROC },
+
+ { "word", cons, 4 },
+ { "quad", big_cons, 16 },
+
+ { 0, 0, 0 }
+ };
+
+/* Macros to extract info from an 'expressionS' structure 'e' */
+#define adds(e) e.X_add_symbol
+#define subs(e) e.X_subtract_symbol
+#define offs(e) e.X_add_number
+#define segs(e) e.X_seg
+
+
+ /* Branch-prediction bits for CTRL/COBR format opcodes */
+#define BP_MASK 0x00000002 /* Mask for branch-prediction bit */
+#define BP_TAKEN 0x00000000 /* Value to OR in to predict branch */
+#define BP_NOT_TAKEN 0x00000002 /* Value to OR in to predict no branch */
+
+
+ /* Some instruction opcodes that we need explicitly */
+#define BE 0x12000000
+#define BG 0x11000000
+#define BGE 0x13000000
+#define BL 0x14000000
+#define BLE 0x16000000
+#define BNE 0x15000000
+#define BNO 0x10000000
+#define BO 0x17000000
+#define CHKBIT 0x5a002700
+#define CMPI 0x5a002080
+#define CMPO 0x5a002000
+
+#define B 0x08000000
+#define BAL 0x0b000000
+#define CALL 0x09000000
+#define CALLS 0x66003800
+#define RET 0x0a000000
+
+
+ /* These masks are used to build up a set of MEMB mode bits. */
+#define A_BIT 0x0400
+#define I_BIT 0x0800
+#define MEMB_BIT 0x1000
+#define D_BIT 0x2000
+
+
+ /* Mask for the only mode bit in a MEMA instruction (if set, abase reg is used) */
+#define MEMA_ABASE 0x2000
+
+ /* Info from which a MEMA or MEMB format instruction can be generated */
+ typedef struct {
+ long opcode; /* (First) 32 bits of instruction */
+ int disp; /* 0-(none), 12- or, 32-bit displacement needed */
+ char *e; /* The expression in the source instruction from
+ * which the displacement should be determined
+ */
+ } memS;
+
+
+/* The two pieces of info we need to generate a register operand */
+struct regop {
+ int mode; /* 0 =>local/global/spec reg; 1=> literal or fp reg */
+ int special; /* 0 =>not a sfr; 1=> is a sfr (not valid w/mode=0) */
+ int n; /* Register number or literal value */
+};
+
+
+/* Number and assembler mnemonic for all registers that can appear in operands */
+static struct {
+ char *reg_name;
+ int reg_num;
+} regnames[] = {
+ { "pfp", 0 }, { "sp", 1 }, { "rip", 2 }, { "r3", 3 },
+ { "r4", 4 }, { "r5", 5 }, { "r6", 6 }, { "r7", 7 },
+ { "r8", 8 }, { "r9", 9 }, { "r10", 10 }, { "r11", 11 },
+ { "r12", 12 }, { "r13", 13 }, { "r14", 14 }, { "r15", 15 },
+ { "g0", 16 }, { "g1", 17 }, { "g2", 18 }, { "g3", 19 },
+ { "g4", 20 }, { "g5", 21 }, { "g6", 22 }, { "g7", 23 },
+ { "g8", 24 }, { "g9", 25 }, { "g10", 26 }, { "g11", 27 },
+ { "g12", 28 }, { "g13", 29 }, { "g14", 30 }, { "fp", 31 },
+
+ /* Numbers for special-function registers are for assembler internal
+ * use only: they are scaled back to range [0-31] for binary output.
+ */
+# define SF0 32
+
+ { "sf0", 32 }, { "sf1", 33 }, { "sf2", 34 }, { "sf3", 35 },
+ { "sf4", 36 }, { "sf5", 37 }, { "sf6", 38 }, { "sf7", 39 },
+ { "sf8", 40 }, { "sf9", 41 }, { "sf10",42 }, { "sf11",43 },
+ { "sf12",44 }, { "sf13",45 }, { "sf14",46 }, { "sf15",47 },
+ { "sf16",48 }, { "sf17",49 }, { "sf18",50 }, { "sf19",51 },
+ { "sf20",52 }, { "sf21",53 }, { "sf22",54 }, { "sf23",55 },
+ { "sf24",56 }, { "sf25",57 }, { "sf26",58 }, { "sf27",59 },
+ { "sf28",60 }, { "sf29",61 }, { "sf30",62 }, { "sf31",63 },
+
+ /* Numbers for floating point registers are for assembler internal use
+ * only: they are scaled back to [0-3] for binary output.
+ */
+# define FP0 64
+
+ { "fp0", 64 }, { "fp1", 65 }, { "fp2", 66 }, { "fp3", 67 },
+
+ { NULL, 0 }, /* END OF LIST */
+};
+
+#define IS_RG_REG(n) ((0 <= (n)) && ((n) < SF0))
+#define IS_SF_REG(n) ((SF0 <= (n)) && ((n) < FP0))
+#define IS_FP_REG(n) ((n) >= FP0)
+
+/* Number and assembler mnemonic for all registers that can appear as 'abase'
+ * (indirect addressing) registers.
+ */
+static struct {
+ char *areg_name;
+ int areg_num;
+} aregs[] = {
+ { "(pfp)", 0 }, { "(sp)", 1 }, { "(rip)", 2 }, { "(r3)", 3 },
+ { "(r4)", 4 }, { "(r5)", 5 }, { "(r6)", 6 }, { "(r7)", 7 },
+ { "(r8)", 8 }, { "(r9)", 9 }, { "(r10)", 10 }, { "(r11)", 11 },
+ { "(r12)", 12 }, { "(r13)", 13 }, { "(r14)", 14 }, { "(r15)", 15 },
+ { "(g0)", 16 }, { "(g1)", 17 }, { "(g2)", 18 }, { "(g3)", 19 },
+ { "(g4)", 20 }, { "(g5)", 21 }, { "(g6)", 22 }, { "(g7)", 23 },
+ { "(g8)", 24 }, { "(g9)", 25 }, { "(g10)", 26 }, { "(g11)", 27 },
+ { "(g12)", 28 }, { "(g13)", 29 }, { "(g14)", 30 }, { "(fp)", 31 },
+
+# define IPREL 32
+ /* for assembler internal use only: this number never appears in binary
+ * output.
+ */
+ { "(ip)", IPREL },
+
+ { NULL, 0 }, /* END OF LIST */
+};
+
+
+/* Hash tables */
+static struct hash_control *op_hash = NULL; /* Opcode mnemonics */
+static struct hash_control *reg_hash = NULL; /* Register name hash table */
+static struct hash_control *areg_hash = NULL; /* Abase register hash table */
+
+
+/* Architecture for which we are assembling */
+#define ARCH_ANY 0 /* Default: no architecture checking done */
+#define ARCH_KA 1
+#define ARCH_KB 2
+#define ARCH_MC 3
+#define ARCH_CA 4
+int architecture = ARCH_ANY; /* Architecture requested on invocation line */
+int iclasses_seen = 0; /* OR of instruction classes (I_* constants)
+ * for which we've actually assembled
+ * instructions.
+ */
+
+
+/* BRANCH-PREDICTION INSTRUMENTATION
+ *
+ * The following supports generation of branch-prediction instrumentation
+ * (turned on by -b switch). The instrumentation collects counts
+ * of branches taken/not-taken for later input to a utility that will
+ * set the branch prediction bits of the instructions in accordance with
+ * the behavior observed. (Note that the KX series does not have
+ * brach-prediction.)
+ *
+ * The instrumentation consists of:
+ *
+ * (1) before and after each conditional branch, a call to an external
+ * routine that increments and steps over an inline counter. The
+ * counter itself, initialized to 0, immediately follows the call
+ * instruction. For each branch, the counter following the branch
+ * is the number of times the branch was not taken, and the difference
+ * between the counters is the number of times it was taken. An
+ * example of an instrumented conditional branch:
+ *
+ * call BR_CNT_FUNC
+ * .word 0
+ * LBRANCH23: be label
+ * call BR_CNT_FUNC
+ * .word 0
+ *
+ * (2) a table of pointers to the instrumented branches, so that an
+ * external postprocessing routine can locate all of the counters.
+ * the table begins with a 2-word header: a pointer to the next in
+ * a linked list of such tables (initialized to 0); and a count
+ * of the number of entries in the table (exclusive of the header.
+ *
+ * Note that input source code is expected to already contain calls
+ * an external routine that will link the branch local table into a
+ * list of such tables.
+ */
+
+static int br_cnt = 0; /* Number of branches instrumented so far.
+ * Also used to generate unique local labels
+ * for each instrumented branch
+ */
+
+#define BR_LABEL_BASE "LBRANCH"
+/* Basename of local labels on instrumented
+ * branches, to avoid conflict with compiler-
+ * generated local labels.
+ */
+
+#define BR_CNT_FUNC "__inc_branch"
+/* Name of the external routine that will
+ * increment (and step over) an inline counter.
+ */
+
+#define BR_TAB_NAME "__BRANCH_TABLE__"
+/* Name of the table of pointers to branches.
+ * A local (i.e., non-external) symbol.
+ */
+
+/*****************************************************************************
+ * md_begin: One-time initialization.
+ *
+ * Set up hash tables.
+ *
+ **************************************************************************** */
+void
+ md_begin()
+{
+ int i; /* Loop counter */
+ const struct i960_opcode *oP; /* Pointer into opcode table */
+ char *retval; /* Value returned by hash functions */
+
+ if (((op_hash = hash_new()) == 0)
+ || ((reg_hash = hash_new()) == 0)
+ || ((areg_hash = hash_new()) == 0)) {
+ as_fatal("virtual memory exceeded");
+ }
+
+ retval = ""; /* For some reason, the base assembler uses an empty
+ * string for "no error message", instead of a NULL
+ * pointer.
+ */
+
+ for (oP=i960_opcodes; oP->name && !*retval; oP++) {
+ retval = hash_insert(op_hash, oP->name, oP);
+ }
+
+ for (i=0; regnames[i].reg_name && !*retval; i++) {
+ retval = hash_insert(reg_hash, regnames[i].reg_name,
+ &regnames[i].reg_num);
+ }
+
+ for (i=0; aregs[i].areg_name && !*retval; i++){
+ retval = hash_insert(areg_hash, aregs[i].areg_name,
+ &aregs[i].areg_num);
+ }
+
+ if (*retval) {
+ as_fatal("Hashing returned \"%s\".", retval);
+ }
+} /* md_begin() */
+
+/*****************************************************************************
+ * md_end: One-time final cleanup
+ *
+ * None necessary
+ *
+ **************************************************************************** */
+void
+ md_end()
+{
+}
+
+/*****************************************************************************
+ * md_assemble: Assemble an instruction
+ *
+ * Assumptions about the passed-in text:
+ * - all comments, labels removed
+ * - text is an instruction
+ * - all white space compressed to single blanks
+ * - all character constants have been replaced with decimal
+ *
+ **************************************************************************** */
+void
+ md_assemble(textP)
+char *textP; /* Source text of instruction */
+{
+ char *args[4]; /* Parsed instruction text, containing NO whitespace:
+ * arg[0]->opcode mnemonic
+ * arg[1-3]->operands, with char constants
+ * replaced by decimal numbers
+ */
+ int n_ops; /* Number of instruction operands */
+
+ struct i960_opcode *oP;
+ /* Pointer to instruction description */
+ int branch_predict;
+ /* TRUE iff opcode mnemonic included branch-prediction
+ * suffix (".f" or ".t")
+ */
+ long bp_bits; /* Setting of branch-prediction bit(s) to be OR'd
+ * into instruction opcode of CTRL/COBR format
+ * instructions.
+ */
+ int n; /* Offset of last character in opcode mnemonic */
+
+ static const char bp_error_msg[] = "branch prediction invalid on this opcode";
+
+
+ /* Parse instruction into opcode and operands */
+ memset(args, '\0', sizeof(args));
+ n_ops = i_scan(textP, args);
+ if (n_ops == -1){
+ return; /* Error message already issued */
+ }
+
+ /* Do "macro substitution" (sort of) on 'ldconst' pseudo-instruction */
+ if (!strcmp(args[0],"ldconst")){
+ n_ops = parse_ldconst(args);
+ if (n_ops == -1){
+ return;
+ }
+ }
+
+ /* Check for branch-prediction suffix on opcode mnemonic, strip it off */
+ n = strlen(args[0]) - 1;
+ branch_predict = 0;
+ bp_bits = 0;
+ if (args[0][n-1] == '.' && (args[0][n] == 't' || args[0][n] == 'f')){
+ /* We could check here to see if the target architecture
+ * supports branch prediction, but why bother? The bit
+ * will just be ignored by processors that don't use it.
+ */
+ branch_predict = 1;
+ bp_bits = (args[0][n] == 't') ? BP_TAKEN : BP_NOT_TAKEN;
+ args[0][n-1] = '\0'; /* Strip suffix from opcode mnemonic */
+ }
+
+ /* Look up opcode mnemonic in table and check number of operands.
+ * Check that opcode is legal for the target architecture.
+ * If all looks good, assemble instruction.
+ */
+ oP = (struct i960_opcode *) hash_find(op_hash, args[0]);
+ if (!oP || !targ_has_iclass(oP->iclass)) {
+ as_bad("invalid opcode, \"%s\".", args[0]);
+
+ } else if (n_ops != oP->num_ops) {
+ as_bad("improper number of operands. expecting %d, got %d", oP->num_ops, n_ops);
+
+ } else {
+ switch (oP->format){
+ case FBRA:
+ case CTRL:
+ ctrl_fmt(args[1], oP->opcode | bp_bits, oP->num_ops);
+ if (oP->format == FBRA){
+ /* Now generate a 'bno' to same arg */
+ ctrl_fmt(args[1], BNO | bp_bits, 1);
+ }
+ break;
+ case COBR:
+ case COJ:
+ cobr_fmt(args, oP->opcode | bp_bits, oP);
+ break;
+ case REG:
+ if (branch_predict){
+ as_warn(bp_error_msg);
+ }
+ reg_fmt(args, oP);
+ break;
+ case MEM1:
+ case MEM2:
+ case MEM4:
+ case MEM8:
+ case MEM12:
+ case MEM16:
+ if (branch_predict){
+ as_warn(bp_error_msg);
+ }
+ mem_fmt(args, oP);
+ break;
+ case CALLJ:
+ if (branch_predict){
+ as_warn(bp_error_msg);
+ }
+ /* Output opcode & set up "fixup" (relocation);
+ * flag relocation as 'callj' type.
+ */
+ know(oP->num_ops == 1);
+ get_cdisp(args[1], "CTRL", oP->opcode, 24, 0, 1);
+ break;
+ default:
+ BAD_CASE(oP->format);
+ break;
+ }
+ }
+} /* md_assemble() */
+
+/*****************************************************************************
+ * md_number_to_chars: convert a number to target byte order
+ *
+ **************************************************************************** */
+void
+ md_number_to_chars(buf, value, n)
+char *buf; /* Put output here */
+long value; /* The integer to be converted */
+int n; /* Number of bytes to output (significant bytes
+ * in 'value')
+ */
+{
+ while (n--){
+ *buf++ = value;
+ value >>= 8;
+ }
+
+ /* XXX line number probably botched for this warning message. */
+ if (value != 0 && value != -1){
+ as_bad("Displacement too long for instruction field length.");
+ }
+
+ return;
+} /* md_number_to_chars() */
+
+/*****************************************************************************
+ * md_chars_to_number: convert from target byte order to host byte order.
+ *
+ **************************************************************************** */
+int
+ md_chars_to_number(val, n)
+unsigned char *val; /* Value in target byte order */
+int n; /* Number of bytes in the input */
+{
+ int retval;
+
+ for (retval=0; n--;){
+ retval <<= 8;
+ retval |= val[n];
+ }
+ return retval;
+}
+
+
+#define MAX_LITTLENUMS 6
+#define LNUM_SIZE sizeof(LITTLENUM_TYPE)
+
+/*****************************************************************************
+ * md_atof: convert ascii to floating point
+ *
+ * Turn a string at input_line_pointer into a floating point constant of type
+ * 'type', and store the appropriate bytes at *litP. The number of LITTLENUMS
+ * emitted is returned at 'sizeP'. An error message is returned, or a pointer
+ * to an empty message if OK.
+ *
+ * Note we call the i386 floating point routine, rather than complicating
+ * things with more files or symbolic links.
+ *
+ **************************************************************************** */
+char * md_atof(type, litP, sizeP)
+int type;
+char *litP;
+int *sizeP;
+{
+ LITTLENUM_TYPE words[MAX_LITTLENUMS];
+ LITTLENUM_TYPE *wordP;
+ int prec;
+ char *t;
+ char *atof_ieee();
+
+ switch (type) {
+ case 'f':
+ case 'F':
+ prec = 2;
+ break;
+
+ case 'd':
+ case 'D':
+ prec = 4;
+ break;
+
+ case 't':
+ case 'T':
+ prec = 5;
+ type = 'x'; /* That's what atof_ieee() understands */
+ break;
+
+ default:
+ *sizeP=0;
+ return "Bad call to md_atof()";
+ }
+
+ t = atof_ieee(input_line_pointer, type, words);
+ if (t){
+ input_line_pointer = t;
+ }
+
+ *sizeP = prec * LNUM_SIZE;
+
+ /* Output the LITTLENUMs in REVERSE order in accord with i80960
+ * word-order. (Dunno why atof_ieee doesn't do it in the right
+ * order in the first place -- probably because it's a hack of
+ * atof_m68k.)
+ */
+
+ for (wordP = words + prec - 1; prec--;){
+ md_number_to_chars(litP, (long) (*wordP--), LNUM_SIZE);
+ litP += sizeof(LITTLENUM_TYPE);
+ }
+
+ return ""; /* Someone should teach Dean about null pointers */
+}
+
+
+/*****************************************************************************
+ * md_number_to_imm
+ *
+ **************************************************************************** */
+void
+ md_number_to_imm(buf, val, n)
+char *buf;
+long val;
+int n;
+{
+ md_number_to_chars(buf, val, n);
+}
+
+
+/*****************************************************************************
+ * md_number_to_disp
+ *
+ **************************************************************************** */
+void
+ md_number_to_disp(buf, val, n)
+char *buf;
+long val;
+int n;
+{
+ md_number_to_chars(buf, val, n);
+}
+
+/*****************************************************************************
+ * md_number_to_field:
+ *
+ * Stick a value (an address fixup) into a bit field of
+ * previously-generated instruction.
+ *
+ **************************************************************************** */
+void
+ md_number_to_field(instrP, val, bfixP)
+char *instrP; /* Pointer to instruction to be fixed */
+long val; /* Address fixup value */
+bit_fixS *bfixP; /* Description of bit field to be fixed up */
+{
+ int numbits; /* Length of bit field to be fixed */
+ long instr; /* 32-bit instruction to be fixed-up */
+ long sign; /* 0 or -1, according to sign bit of 'val' */
+
+ /* Convert instruction back to host byte order
+ */
+ instr = md_chars_to_number(instrP, 4);
+
+ /* Surprise! -- we stored the number of bits
+ * to be modified rather than a pointer to a structure.
+ */
+ numbits = (int)bfixP;
+ if (numbits == 1){
+ /* This is a no-op, stuck here by reloc_callj() */
+ return;
+ }
+
+ know ((numbits == 13) || (numbits == 24));
+
+ /* Propagate sign bit of 'val' for the given number of bits.
+ * Result should be all 0 or all 1
+ */
+ sign = val >> ((int)numbits - 1);
+ if (((val < 0) && (sign != -1))
+ || ((val > 0) && (sign != 0))){
+ as_bad("Fixup of %d too large for field width of %d",
+ val, numbits);
+ } else {
+ /* Put bit field into instruction and write back in target
+ * byte order.
+ */
+ val &= ~(-1 << (int)numbits); /* Clear unused sign bits */
+ instr |= val;
+ md_number_to_chars(instrP, instr, 4);
+ }
+} /* md_number_to_field() */
+
+
+/*****************************************************************************
+ * md_parse_option
+ * Invocation line includes a switch not recognized by the base assembler.
+ * See if it's a processor-specific option. For the 960, these are:
+ *
+ * -norelax:
+ * Conditional branch instructions that require displacements
+ * greater than 13 bits (or that have external targets) should
+ * generate errors. The default is to replace each such
+ * instruction with the corresponding compare (or chkbit) and
+ * branch instructions. Note that the Intel "j" cobr directives
+ * are ALWAYS "de-optimized" in this way when necessary,
+ * regardless of the setting of this option.
+ *
+ * -b:
+ * Add code to collect information about branches taken, for
+ * later optimization of branch prediction bits by a separate
+ * tool. COBR and CNTL format instructions have branch
+ * prediction bits (in the CX architecture); if "BR" represents
+ * an instruction in one of these classes, the following rep-
+ * resents the code generated by the assembler:
+ *
+ * call <increment routine>
+ * .word 0 # pre-counter
+ * Label: BR
+ * call <increment routine>
+ * .word 0 # post-counter
+ *
+ * A table of all such "Labels" is also generated.
+ *
+ *
+ * -AKA, -AKB, -AKC, -ASA, -ASB, -AMC, -ACA:
+ * Select the 80960 architecture. Instructions or features not
+ * supported by the selected architecture cause fatal errors.
+ * The default is to generate code for any instruction or feature
+ * that is supported by SOME version of the 960 (even if this
+ * means mixing architectures!).
+ *
+ **************************************************************************** */
+int
+ md_parse_option(argP, cntP, vecP)
+char **argP;
+int *cntP;
+char ***vecP;
+{
+ char *p;
+ struct tabentry { char *flag; int arch; };
+ static struct tabentry arch_tab[] = {
+ "KA", ARCH_KA,
+ "KB", ARCH_KB,
+ "SA", ARCH_KA, /* Synonym for KA */
+ "SB", ARCH_KB, /* Synonym for KB */
+ "KC", ARCH_MC, /* Synonym for MC */
+ "MC", ARCH_MC,
+ "CA", ARCH_CA,
+ NULL, 0
+ };
+ struct tabentry *tp;
+
+ if (!strcmp(*argP,"norelax")){
+ norelax = 1;
+
+ } else if (**argP == 'b'){
+ instrument_branches = 1;
+
+ } else if (**argP == 'A'){
+ p = (*argP) + 1;
+
+ for (tp = arch_tab; tp->flag != NULL; tp++){
+ if (!strcmp(p,tp->flag)){
+ break;
+ }
+ }
+
+ if (tp->flag == NULL){
+ as_bad("unknown architecture: %s", p);
+ } else {
+ architecture = tp->arch;
+ }
+ } else {
+ /* Unknown option */
+ (*argP)++;
+ return 0;
+ }
+ **argP = '\0'; /* Done parsing this switch */
+ return 1;
+}
+
+/*****************************************************************************
+ * md_convert_frag:
+ * Called by base assembler after address relaxation is finished: modify
+ * variable fragments according to how much relaxation was done.
+ *
+ * If the fragment substate is still 1, a 13-bit displacement was enough
+ * to reach the symbol in question. Set up an address fixup, but otherwise
+ * leave the cobr instruction alone.
+ *
+ * If the fragment substate is 2, a 13-bit displacement was not enough.
+ * Replace the cobr with a two instructions (a compare and a branch).
+ *
+ **************************************************************************** */
+void
+ md_convert_frag(headers, fragP)
+object_headers *headers;
+fragS * fragP;
+{
+ fixS *fixP; /* Structure describing needed address fix */
+
+ switch (fragP->fr_subtype){
+ case 1:
+ /* LEAVE SINGLE COBR INSTRUCTION */
+ fixP = fix_new(fragP,
+ fragP->fr_opcode-fragP->fr_literal,
+ 4,
+ fragP->fr_symbol,
+ 0,
+ fragP->fr_offset,
+ 1,
+ 0);
+
+ fixP->fx_bit_fixP = (bit_fixS *) 13; /* size of bit field */
+ break;
+ case 2:
+ /* REPLACE COBR WITH COMPARE/BRANCH INSTRUCTIONS */
+ relax_cobr(fragP);
+ break;
+ default:
+ BAD_CASE(fragP->fr_subtype);
+ break;
+ }
+}
+
+/*****************************************************************************
+ * md_estimate_size_before_relax: How much does it look like *fragP will grow?
+ *
+ * Called by base assembler just before address relaxation.
+ * Return the amount by which the fragment will grow.
+ *
+ * Any symbol that is now undefined will not become defined; cobr's
+ * based on undefined symbols will have to be replaced with a compare
+ * instruction and a branch instruction, and the code fragment will grow
+ * by 4 bytes.
+ *
+ **************************************************************************** */
+int
+ md_estimate_size_before_relax(fragP, segment_type)
+register fragS *fragP;
+register segT segment_type;
+{
+ /* If symbol is undefined in this segment, go to "relaxed" state
+ * (compare and branch instructions instead of cobr) right now.
+ */
+ if (S_GET_SEGMENT(fragP->fr_symbol) != segment_type) {
+ relax_cobr(fragP);
+ return 4;
+ }
+ return 0;
+} /* md_estimate_size_before_relax() */
+
+
+/*****************************************************************************
+ * md_ri_to_chars:
+ * This routine exists in order to overcome machine byte-order problems
+ * when dealing with bit-field entries in the relocation_info struct.
+ *
+ * But relocation info will be used on the host machine only (only
+ * executable code is actually downloaded to the i80960). Therefore,
+ * we leave it in host byte order.
+ *
+ **************************************************************************** */
+void md_ri_to_chars(where, ri)
+char *where;
+struct relocation_info *ri;
+{
+ *((struct relocation_info *) where) = *ri; /* structure assignment */
+} /* md_ri_to_chars() */
+
+#ifndef WORKING_DOT_WORD
+
+int md_short_jump_size = 0;
+int md_long_jump_size = 0;
+
+void md_create_short_jump(ptr, from_addr, to_addr, frag, to_symbol)
+char *ptr;
+long from_addr;
+long to_addr;
+fragS *frag;
+symbolS *to_symbol;
+{
+ as_fatal("failed sanity check.");
+}
+
+void
+ md_create_long_jump(ptr,from_addr,to_addr,frag,to_symbol)
+char *ptr;
+long from_addr, to_addr;
+fragS *frag;
+symbolS *to_symbol;
+{
+ as_fatal("failed sanity check.");
+}
+#endif
+
+/*************************************************************
+ * *
+ * FOLLOWING ARE THE LOCAL ROUTINES, IN ALPHABETICAL ORDER *
+ * *
+ ************************************************************ */
+
+
+
+/*****************************************************************************
+ * brcnt_emit: Emit code to increment inline branch counter.
+ *
+ * See the comments above the declaration of 'br_cnt' for details on
+ * branch-prediction instrumentation.
+ **************************************************************************** */
+static void
+ brcnt_emit()
+{
+ ctrl_fmt(BR_CNT_FUNC,CALL,1);/* Emit call to "increment" routine */
+ emit(0); /* Emit inline counter to be incremented */
+}
+
+/*****************************************************************************
+ * brlab_next: generate the next branch local label
+ *
+ * See the comments above the declaration of 'br_cnt' for details on
+ * branch-prediction instrumentation.
+ **************************************************************************** */
+static char *
+ brlab_next()
+{
+ static char buf[20];
+
+ sprintf(buf, "%s%d", BR_LABEL_BASE, br_cnt++);
+ return buf;
+}
+
+/*****************************************************************************
+ * brtab_emit: generate the fetch-prediction branch table.
+ *
+ * See the comments above the declaration of 'br_cnt' for details on
+ * branch-prediction instrumentation.
+ *
+ * The code emitted here would be functionally equivalent to the following
+ * example assembler source.
+ *
+ * .data
+ * .align 2
+ * BR_TAB_NAME:
+ * .word 0 # link to next table
+ * .word 3 # length of table
+ * .word LBRANCH0 # 1st entry in table proper
+ * .word LBRANCH1
+ * .word LBRANCH2
+ ***************************************************************************** */
+void
+ brtab_emit()
+{
+ int i;
+ char buf[20];
+ char *p; /* Where the binary was output to */
+ fixS *fixP; /*->description of deferred address fixup */
+
+ if (!instrument_branches){
+ return;
+ }
+
+ subseg_new(SEG_DATA,0); /* .data */
+ frag_align(2,0); /* .align 2 */
+ record_alignment(now_seg,2);
+ colon(BR_TAB_NAME); /* BR_TAB_NAME: */
+ emit(0); /* .word 0 #link to next table */
+ emit(br_cnt); /* .word n #length of table */
+
+ for (i=0; i<br_cnt; i++){
+ sprintf(buf, "%s%d", BR_LABEL_BASE, i);
+ p = emit(0);
+ fixP = fix_new(frag_now,
+ p - frag_now->fr_literal,
+ 4,
+ symbol_find(buf),
+ 0,
+ 0,
+ 0,
+ 0);
+ fixP->fx_im_disp = 2; /* 32-bit displacement fix */
+ }
+}
+
+/*****************************************************************************
+ * cobr_fmt: generate a COBR-format instruction
+ *
+ **************************************************************************** */
+static
+ void
+ cobr_fmt(arg, opcode, oP)
+char *arg[]; /* arg[0]->opcode mnemonic, arg[1-3]->operands (ascii) */
+long opcode; /* Opcode, with branch-prediction bits already set
+ * if necessary.
+ */
+struct i960_opcode *oP;
+/*->description of instruction */
+{
+ long instr; /* 32-bit instruction */
+ struct regop regop; /* Description of register operand */
+ int n; /* Number of operands */
+ int var_frag; /* 1 if varying length code fragment should
+ * be emitted; 0 if an address fix
+ * should be emitted.
+ */
+
+ instr = opcode;
+ n = oP->num_ops;
+
+ if (n >= 1) {
+ /* First operand (if any) of a COBR is always a register
+ * operand. Parse it.
+ */
+ parse_regop(&regop, arg[1], oP->operand[0]);
+ instr |= (regop.n << 19) | (regop.mode << 13);
+ }
+ if (n >= 2) {
+ /* Second operand (if any) of a COBR is always a register
+ * operand. Parse it.
+ */
+ parse_regop(&regop, arg[2], oP->operand[1]);
+ instr |= (regop.n << 14) | regop.special;
+ }
+
+
+ if (n < 3){
+ emit(instr);
+
+ } else {
+ if (instrument_branches){
+ brcnt_emit();
+ colon(brlab_next());
+ }
+
+ /* A third operand to a COBR is always a displacement.
+ * Parse it; if it's relaxable (a cobr "j" directive, or any
+ * cobr other than bbs/bbc when the "-norelax" option is not in
+ * use) set up a variable code fragment; otherwise set up an
+ * address fix.
+ */
+ var_frag = !norelax || (oP->format == COJ); /* TRUE or FALSE */
+ get_cdisp(arg[3], "COBR", instr, 13, var_frag, 0);
+
+ if (instrument_branches){
+ brcnt_emit();
+ }
+ }
+} /* cobr_fmt() */
+
+
+/*****************************************************************************
+ * ctrl_fmt: generate a CTRL-format instruction
+ *
+ **************************************************************************** */
+static
+ void
+ ctrl_fmt(targP, opcode, num_ops)
+char *targP; /* Pointer to text of lone operand (if any) */
+long opcode; /* Template of instruction */
+int num_ops; /* Number of operands */
+{
+ int instrument; /* TRUE iff we should add instrumentation to track
+ * how often the branch is taken
+ */
+
+
+ if (num_ops == 0){
+ emit(opcode); /* Output opcode */
+ } else {
+
+ instrument = instrument_branches && (opcode != CALL)
+ && (opcode != B) && (opcode != RET) && (opcode != BAL);
+
+ if (instrument){
+ brcnt_emit();
+ colon(brlab_next());
+ }
+
+ /* The operand MUST be an ip-relative displacment. Parse it
+ * and set up address fix for the instruction we just output.
+ */
+ get_cdisp(targP, "CTRL", opcode, 24, 0, 0);
+
+ if (instrument){
+ brcnt_emit();
+ }
+ }
+
+}
+
+
+/*****************************************************************************
+ * emit: output instruction binary
+ *
+ * Output instruction binary, in target byte order, 4 bytes at a time.
+ * Return pointer to where it was placed.
+ *
+ **************************************************************************** */
+static
+ char *
+ emit(instr)
+long instr; /* Word to be output, host byte order */
+{
+ char *toP; /* Where to output it */
+
+ toP = frag_more(4); /* Allocate storage */
+ md_number_to_chars(toP, instr, 4); /* Convert to target byte order */
+ return toP;
+}
+
+
+/*****************************************************************************
+ * get_args: break individual arguments out of comma-separated list
+ *
+ * Input assumptions:
+ * - all comments and labels have been removed
+ * - all strings of whitespace have been collapsed to a single blank.
+ * - all character constants ('x') have been replaced with decimal
+ *
+ * Output:
+ * args[0] is untouched. args[1] points to first operand, etc. All args:
+ * - are NULL-terminated
+ * - contain no whitespace
+ *
+ * Return value:
+ * Number of operands (0,1,2, or 3) or -1 on error.
+ *
+ **************************************************************************** */
+static int get_args(p, args)
+register char *p; /* Pointer to comma-separated operands; MUCKED BY US */
+char *args[]; /* Output arg: pointers to operands placed in args[1-3].
+ * MUST ACCOMMODATE 4 ENTRIES (args[0-3]).
+ */
+{
+ register int n; /* Number of operands */
+ register char *to;
+ /* char buf[4]; */
+ /* int len; */
+
+
+ /* Skip lead white space */
+ while (*p == ' '){
+ p++;
+ }
+
+ if (*p == '\0'){
+ return 0;
+ }
+
+ n = 1;
+ args[1] = p;
+
+ /* Squeze blanks out by moving non-blanks toward start of string.
+ * Isolate operands, whenever comma is found.
+ */
+ to = p;
+ while (*p != '\0'){
+
+ if (*p == ' '){
+ p++;
+
+ } else if (*p == ','){
+
+ /* Start of operand */
+ if (n == 3){
+ as_bad("too many operands");
+ return -1;
+ }
+ *to++ = '\0'; /* Terminate argument */
+ args[++n] = to; /* Start next argument */
+ p++;
+
+ } else {
+ *to++ = *p++;
+ }
+ }
+ *to = '\0';
+ return n;
+}
+
+
+/*****************************************************************************
+ * get_cdisp: handle displacement for a COBR or CTRL instruction.
+ *
+ * Parse displacement for a COBR or CTRL instruction.
+ *
+ * If successful, output the instruction opcode and set up for it,
+ * depending on the arg 'var_frag', either:
+ * o an address fixup to be done when all symbol values are known, or
+ * o a varying length code fragment, with address fixup info. This
+ * will be done for cobr instructions that may have to be relaxed
+ * in to compare/branch instructions (8 bytes) if the final address
+ * displacement is greater than 13 bits.
+ *
+ **************************************************************************** */
+static
+ void
+ get_cdisp(dispP, ifmtP, instr, numbits, var_frag, callj)
+char *dispP; /*->displacement as specified in source instruction */
+char *ifmtP; /*->"COBR" or "CTRL" (for use in error message) */
+long instr; /* Instruction needing the displacement */
+int numbits; /* # bits of displacement (13 for COBR, 24 for CTRL) */
+int var_frag; /* 1 if varying length code fragment should be emitted;
+ * 0 if an address fix should be emitted.
+ */
+int callj; /* 1 if callj relocation should be done; else 0 */
+{
+ expressionS e; /* Parsed expression */
+ fixS *fixP; /* Structure describing needed address fix */
+ char *outP; /* Where instruction binary is output to */
+
+ fixP = NULL;
+
+ switch (parse_expr(dispP,&e)) {
+
+ case SEG_GOOF:
+ as_bad("expression syntax error");
+ break;
+
+ case SEG_TEXT:
+ case SEG_UNKNOWN:
+ if (var_frag) {
+ outP = frag_more(8); /* Allocate worst-case storage */
+ md_number_to_chars(outP, instr, 4);
+ frag_variant(rs_machine_dependent, 4, 4, 1,
+ adds(e), offs(e), outP, 0, 0);
+ } else {
+ /* Set up a new fix structure, so address can be updated
+ * when all symbol values are known.
+ */
+ outP = emit(instr);
+ fixP = fix_new(frag_now,
+ outP - frag_now->fr_literal,
+ 4,
+ adds(e),
+ 0,
+ offs(e),
+ 1,
+ 0);
+
+ fixP->fx_callj = callj;
+
+ /* We want to modify a bit field when the address is
+ * known. But we don't need all the garbage in the
+ * bit_fix structure. So we're going to lie and store
+ * the number of bits affected instead of a pointer.
+ */
+ fixP->fx_bit_fixP = (bit_fixS *) numbits;
+ }
+ break;
+
+ case SEG_DATA:
+ case SEG_BSS:
+ as_bad("attempt to branch into different segment");
+ break;
+
+ default:
+ as_bad("target of %s instruction must be a label", ifmtP);
+ break;
+ }
+}
+
+
+/*****************************************************************************
+ * get_ispec: parse a memory operand for an index specification
+ *
+ * Here, an "index specification" is taken to be anything surrounded
+ * by square brackets and NOT followed by anything else.
+ *
+ * If it's found, detach it from the input string, remove the surrounding
+ * square brackets, and return a pointer to it. Otherwise, return NULL.
+ *
+ **************************************************************************** */
+static
+ char *
+ get_ispec(textP)
+char *textP; /*->memory operand from source instruction, no white space */
+{
+ char *start; /*->start of index specification */
+ char *end; /*->end of index specification */
+
+ /* Find opening square bracket, if any
+ */
+ start = strchr(textP, '[');
+
+ if (start != NULL){
+
+ /* Eliminate '[', detach from rest of operand */
+ *start++ = '\0';
+
+ end = strchr(start, ']');
+
+ if (end == NULL){
+ as_bad("unmatched '['");
+
+ } else {
+ /* Eliminate ']' and make sure it was the last thing
+ * in the string.
+ */
+ *end = '\0';
+ if (*(end+1) != '\0'){
+ as_bad("garbage after index spec ignored");
+ }
+ }
+ }
+ return start;
+}
+
+/*****************************************************************************
+ * get_regnum:
+ *
+ * Look up a (suspected) register name in the register table and return the
+ * associated register number (or -1 if not found).
+ *
+ **************************************************************************** */
+static
+ int
+ get_regnum(regname)
+char *regname; /* Suspected register name */
+{
+ int *rP;
+
+ rP = (int *) hash_find(reg_hash, regname);
+ return (rP == NULL) ? -1 : *rP;
+}
+
+
+/*****************************************************************************
+ * i_scan: perform lexical scan of ascii assembler instruction.
+ *
+ * Input assumptions:
+ * - input string is an i80960 instruction (not a pseudo-op)
+ * - all comments and labels have been removed
+ * - all strings of whitespace have been collapsed to a single blank.
+ *
+ * Output:
+ * args[0] points to opcode, other entries point to operands. All strings:
+ * - are NULL-terminated
+ * - contain no whitespace
+ * - have character constants ('x') replaced with a decimal number
+ *
+ * Return value:
+ * Number of operands (0,1,2, or 3) or -1 on error.
+ *
+ **************************************************************************** */
+static int i_scan(iP, args)
+register char *iP; /* Pointer to ascii instruction; MUCKED BY US. */
+char *args[]; /* Output arg: pointers to opcode and operands placed
+ * here. MUST ACCOMMODATE 4 ENTRIES.
+ */
+{
+
+ /* Isolate opcode */
+ if (*(iP) == ' ') {
+ iP++;
+ } /* Skip lead space, if any */
+ args[0] = iP;
+ for (; *iP != ' '; iP++) {
+ if (*iP == '\0') {
+ /* There are no operands */
+ if (args[0] == iP) {
+ /* We never moved: there was no opcode either! */
+ as_bad("missing opcode");
+ return -1;
+ }
+ return 0;
+ }
+ }
+ *iP++ = '\0'; /* Terminate opcode */
+ return(get_args(iP, args));
+} /* i_scan() */
+
+
+/*****************************************************************************
+ * mem_fmt: generate a MEMA- or MEMB-format instruction
+ *
+ **************************************************************************** */
+static void mem_fmt(args, oP)
+char *args[]; /* args[0]->opcode mnemonic, args[1-3]->operands */
+struct i960_opcode *oP; /* Pointer to description of instruction */
+{
+ int i; /* Loop counter */
+ struct regop regop; /* Description of register operand */
+ char opdesc; /* Operand descriptor byte */
+ memS instr; /* Description of binary to be output */
+ char *outP; /* Where the binary was output to */
+ expressionS expr; /* Parsed expression */
+ fixS *fixP; /*->description of deferred address fixup */
+
+ memset(&instr, '\0', sizeof(memS));
+ instr.opcode = oP->opcode;
+
+ /* Process operands. */
+ for (i = 1; i <= oP->num_ops; i++){
+ opdesc = oP->operand[i-1];
+
+ if (MEMOP(opdesc)){
+ parse_memop(&instr, args[i], oP->format);
+ } else {
+ parse_regop(&regop, args[i], opdesc);
+ instr.opcode |= regop.n << 19;
+ }
+ }
+
+ /* Output opcode */
+ outP = emit(instr.opcode);
+
+ if (instr.disp == 0){
+ return;
+ }
+
+ /* Parse and process the displacement */
+ switch (parse_expr(instr.e,&expr)){
+
+ case SEG_GOOF:
+ as_bad("expression syntax error");
+ break;
+
+ case SEG_ABSOLUTE:
+ if (instr.disp == 32){
+ (void) emit(offs(expr)); /* Output displacement */
+ } else {
+ /* 12-bit displacement */
+ if (offs(expr) & ~0xfff){
+ /* Won't fit in 12 bits: convert already-output
+ * instruction to MEMB format, output
+ * displacement.
+ */
+ mema_to_memb(outP);
+ (void) emit(offs(expr));
+ } else {
+ /* WILL fit in 12 bits: OR into opcode and
+ * overwrite the binary we already put out
+ */
+ instr.opcode |= offs(expr);
+ md_number_to_chars(outP, instr.opcode, 4);
+ }
+ }
+ break;
+
+ case SEG_DIFFERENCE:
+ case SEG_TEXT:
+ case SEG_DATA:
+ case SEG_BSS:
+ case SEG_UNKNOWN:
+ if (instr.disp == 12){
+ /* Displacement is dependent on a symbol, whose value
+ * may change at link time. We HAVE to reserve 32 bits.
+ * Convert already-output opcode to MEMB format.
+ */
+ mema_to_memb(outP);
+ }
+
+ /* Output 0 displacement and set up address fixup for when
+ * this symbol's value becomes known.
+ */
+ outP = emit((long) 0);
+ fixP = fix_new(frag_now,
+ outP - frag_now->fr_literal,
+ 4,
+ adds(expr),
+ subs(expr),
+ offs(expr),
+ 0,
+ 0);
+ fixP->fx_im_disp = 2; /* 32-bit displacement fix */
+ break;
+
+ default:
+ BAD_CASE(segs(expr));
+ break;
+ }
+} /* memfmt() */
+
+
+/*****************************************************************************
+ * mema_to_memb: convert a MEMA-format opcode to a MEMB-format opcode.
+ *
+ * There are 2 possible MEMA formats:
+ * - displacement only
+ * - displacement + abase
+ *
+ * They are distinguished by the setting of the MEMA_ABASE bit.
+ *
+ **************************************************************************** */
+static void mema_to_memb(opcodeP)
+char *opcodeP; /* Where to find the opcode, in target byte order */
+{
+ long opcode; /* Opcode in host byte order */
+ long mode; /* Mode bits for MEMB instruction */
+
+ opcode = md_chars_to_number(opcodeP, 4);
+ know(!(opcode & MEMB_BIT));
+
+ mode = MEMB_BIT | D_BIT;
+ if (opcode & MEMA_ABASE){
+ mode |= A_BIT;
+ }
+
+ opcode &= 0xffffc000; /* Clear MEMA offset and mode bits */
+ opcode |= mode; /* Set MEMB mode bits */
+
+ md_number_to_chars(opcodeP, opcode, 4);
+} /* mema_to_memb() */
+
+
+/*****************************************************************************
+ * parse_expr: parse an expression
+ *
+ * Use base assembler's expression parser to parse an expression.
+ * It, unfortunately, runs off a global which we have to save/restore
+ * in order to make it work for us.
+ *
+ * An empty expression string is treated as an absolute 0.
+ *
+ * Return "segment" to which the expression evaluates.
+ * Return SEG_GOOF regardless of expression evaluation if entire input
+ * string is not consumed in the evaluation -- tolerate no dangling junk!
+ *
+ **************************************************************************** */
+static
+ segT
+ parse_expr(textP, expP)
+char *textP; /* Text of expression to be parsed */
+expressionS *expP; /* Where to put the results of parsing */
+{
+ char *save_in; /* Save global here */
+ segT seg; /* Segment to which expression evaluates */
+ symbolS *symP;
+
+ know(textP);
+
+ if (*textP == '\0') {
+ /* Treat empty string as absolute 0 */
+ expP->X_add_symbol = expP->X_subtract_symbol = NULL;
+ expP->X_add_number = 0;
+ seg = expP->X_seg = SEG_ABSOLUTE;
+
+ } else {
+ save_in = input_line_pointer; /* Save global */
+ input_line_pointer = textP; /* Make parser work for us */
+
+ seg = expression(expP);
+ if (input_line_pointer - textP != strlen(textP)) {
+ /* Did not consume all of the input */
+ seg = SEG_GOOF;
+ }
+ symP = expP->X_add_symbol;
+ if (symP && (hash_find(reg_hash, S_GET_NAME(symP)))) {
+ /* Register name in an expression */
+ seg = SEG_GOOF;
+ }
+
+ input_line_pointer = save_in; /* Restore global */
+ }
+ return seg;
+}
+
+
+/*****************************************************************************
+ * parse_ldcont:
+ * Parse and replace a 'ldconst' pseudo-instruction with an appropriate
+ * i80960 instruction.
+ *
+ * Assumes the input consists of:
+ * arg[0] opcode mnemonic ('ldconst')
+ * arg[1] first operand (constant)
+ * arg[2] name of register to be loaded
+ *
+ * Replaces opcode and/or operands as appropriate.
+ *
+ * Returns the new number of arguments, or -1 on failure.
+ *
+ **************************************************************************** */
+static
+ int
+ parse_ldconst(arg)
+char *arg[]; /* See above */
+{
+ int n; /* Constant to be loaded */
+ int shift; /* Shift count for "shlo" instruction */
+ static char buf[5]; /* Literal for first operand */
+ static char buf2[5]; /* Literal for second operand */
+ expressionS e; /* Parsed expression */
+
+
+ arg[3] = NULL; /* So we can tell at the end if it got used or not */
+
+ switch (parse_expr(arg[1],&e)){
+
+ case SEG_TEXT:
+ case SEG_DATA:
+ case SEG_BSS:
+ case SEG_UNKNOWN:
+ case SEG_DIFFERENCE:
+ /* We're dependent on one or more symbols -- use "lda" */
+ arg[0] = "lda";
+ break;
+
+ case SEG_ABSOLUTE:
+ /* Try the following mappings:
+ * ldconst 0,<reg> ->mov 0,<reg>
+ * ldconst 31,<reg> ->mov 31,<reg>
+ * ldconst 32,<reg> ->addo 1,31,<reg>
+ * ldconst 62,<reg> ->addo 31,31,<reg>
+ * ldconst 64,<reg> ->shlo 8,3,<reg>
+ * ldconst -1,<reg> ->subo 1,0,<reg>
+ * ldconst -31,<reg>->subo 31,0,<reg>
+ *
+ * anthing else becomes:
+ * lda xxx,<reg>
+ */
+ n = offs(e);
+ if ((0 <= n) && (n <= 31)){
+ arg[0] = "mov";
+
+ } else if ((-31 <= n) && (n <= -1)){
+ arg[0] = "subo";
+ arg[3] = arg[2];
+ sprintf(buf, "%d", -n);
+ arg[1] = buf;
+ arg[2] = "0";
+
+ } else if ((32 <= n) && (n <= 62)){
+ arg[0] = "addo";
+ arg[3] = arg[2];
+ arg[1] = "31";
+ sprintf(buf, "%d", n-31);
+ arg[2] = buf;
+
+ } else if ((shift = shift_ok(n)) != 0){
+ arg[0] = "shlo";
+ arg[3] = arg[2];
+ sprintf(buf, "%d", shift);
+ arg[1] = buf;
+ sprintf(buf2, "%d", n >> shift);
+ arg[2] = buf2;
+
+ } else {
+ arg[0] = "lda";
+ }
+ break;
+
+ default:
+ as_bad("invalid constant");
+ return -1;
+ break;
+ }
+ return (arg[3] == 0) ? 2: 3;
+}
+
+/*****************************************************************************
+ * parse_memop: parse a memory operand
+ *
+ * This routine is based on the observation that the 4 mode bits of the
+ * MEMB format, taken individually, have fairly consistent meaning:
+ *
+ * M3 (bit 13): 1 if displacement is present (D_BIT)
+ * M2 (bit 12): 1 for MEMB instructions (MEMB_BIT)
+ * M1 (bit 11): 1 if index is present (I_BIT)
+ * M0 (bit 10): 1 if abase is present (A_BIT)
+ *
+ * So we parse the memory operand and set bits in the mode as we find
+ * things. Then at the end, if we go to MEMB format, we need only set
+ * the MEMB bit (M2) and our mode is built for us.
+ *
+ * Unfortunately, I said "fairly consistent". The exceptions:
+ *
+ * DBIA
+ * 0100 Would seem illegal, but means "abase-only".
+ *
+ * 0101 Would seem to mean "abase-only" -- it means IP-relative.
+ * Must be converted to 0100.
+ *
+ * 0110 Would seem to mean "index-only", but is reserved.
+ * We turn on the D bit and provide a 0 displacement.
+ *
+ * The other thing to observe is that we parse from the right, peeling
+ * things * off as we go: first any index spec, then any abase, then
+ * the displacement.
+ *
+ **************************************************************************** */
+static
+ void
+ parse_memop(memP, argP, optype)
+memS *memP; /* Where to put the results */
+char *argP; /* Text of the operand to be parsed */
+int optype; /* MEM1, MEM2, MEM4, MEM8, MEM12, or MEM16 */
+{
+ char *indexP; /* Pointer to index specification with "[]" removed */
+ char *p; /* Temp char pointer */
+ char iprel_flag;/* True if this is an IP-relative operand */
+ int regnum; /* Register number */
+ int scale; /* Scale factor: 1,2,4,8, or 16. Later converted
+ * to internal format (0,1,2,3,4 respectively).
+ */
+ int mode; /* MEMB mode bits */
+ int *intP; /* Pointer to register number */
+
+ /* The following table contains the default scale factors for each
+ * type of memory instruction. It is accessed using (optype-MEM1)
+ * as an index -- thus it assumes the 'optype' constants are assigned
+ * consecutive values, in the order they appear in this table
+ */
+ static int def_scale[] = {
+ 1, /* MEM1 */
+ 2, /* MEM2 */
+ 4, /* MEM4 */
+ 8, /* MEM8 */
+ -1, /* MEM12 -- no valid default */
+ 16 /* MEM16 */
+ };
+
+
+ iprel_flag = mode = 0;
+
+ /* Any index present? */
+ indexP = get_ispec(argP);
+ if (indexP) {
+ p = strchr(indexP, '*');
+ if (p == NULL) {
+ /* No explicit scale -- use default for this
+ *instruction type.
+ */
+ scale = def_scale[ optype - MEM1 ];
+ } else {
+ *p++ = '\0'; /* Eliminate '*' */
+
+ /* Now indexP->a '\0'-terminated register name,
+ * and p->a scale factor.
+ */
+
+ if (!strcmp(p,"16")){
+ scale = 16;
+ } else if (strchr("1248",*p) && (p[1] == '\0')){
+ scale = *p - '0';
+ } else {
+ scale = -1;
+ }
+ }
+
+ regnum = get_regnum(indexP); /* Get index reg. # */
+ if (!IS_RG_REG(regnum)){
+ as_bad("invalid index register");
+ return;
+ }
+
+ /* Convert scale to its binary encoding */
+ switch (scale){
+ case 1: scale = 0 << 7; break;
+ case 2: scale = 1 << 7; break;
+ case 4: scale = 2 << 7; break;
+ case 8: scale = 3 << 7; break;
+ case 16: scale = 4 << 7; break;
+ default: as_bad("invalid scale factor"); return;
+ };
+
+ memP->opcode |= scale | regnum; /* Set index bits in opcode */
+ mode |= I_BIT; /* Found a valid index spec */
+ }
+
+ /* Any abase (Register Indirect) specification present? */
+ if ((p = strrchr(argP,'(')) != NULL) {
+ /* "(" is there -- does it start a legal abase spec?
+ * (If not it could be part of a displacement expression.)
+ */
+ intP = (int *) hash_find(areg_hash, p);
+ if (intP != NULL){
+ /* Got an abase here */
+ regnum = *intP;
+ *p = '\0'; /* discard register spec */
+ if (regnum == IPREL){
+ /* We have to specialcase ip-rel mode */
+ iprel_flag = 1;
+ } else {
+ memP->opcode |= regnum << 14;
+ mode |= A_BIT;
+ }
+ }
+ }
+
+ /* Any expression present? */
+ memP->e = argP;
+ if (*argP != '\0'){
+ mode |= D_BIT;
+ }
+
+ /* Special-case ip-relative addressing */
+ if (iprel_flag){
+ if (mode & I_BIT){
+ syntax();
+ } else {
+ memP->opcode |= 5 << 10; /* IP-relative mode */
+ memP->disp = 32;
+ }
+ return;
+ }
+
+ /* Handle all other modes */
+ switch (mode){
+ case D_BIT | A_BIT:
+ /* Go with MEMA instruction format for now (grow to MEMB later
+ * if 12 bits is not enough for the displacement).
+ * MEMA format has a single mode bit: set it to indicate
+ * that abase is present.
+ */
+ memP->opcode |= MEMA_ABASE;
+ memP->disp = 12;
+ break;
+
+ case D_BIT:
+ /* Go with MEMA instruction format for now (grow to MEMB later
+ * if 12 bits is not enough for the displacement).
+ */
+ memP->disp = 12;
+ break;
+
+ case A_BIT:
+ /* For some reason, the bit string for this mode is not
+ * consistent: it should be 0 (exclusive of the MEMB bit),
+ * so we set it "by hand" here.
+ */
+ memP->opcode |= MEMB_BIT;
+ break;
+
+ case A_BIT | I_BIT:
+ /* set MEMB bit in mode, and OR in mode bits */
+ memP->opcode |= mode | MEMB_BIT;
+ break;
+
+ case I_BIT:
+ /* Treat missing displacement as displacement of 0 */
+ mode |= D_BIT;
+ /***********************
+ * Fall into next case *
+ ********************** */
+ case D_BIT | A_BIT | I_BIT:
+ case D_BIT | I_BIT:
+ /* set MEMB bit in mode, and OR in mode bits */
+ memP->opcode |= mode | MEMB_BIT;
+ memP->disp = 32;
+ break;
+
+ default:
+ syntax();
+ break;
+ }
+}
+
+/*****************************************************************************
+ * parse_po: parse machine-dependent pseudo-op
+ *
+ * This is a top-level routine for machine-dependent pseudo-ops. It slurps
+ * up the rest of the input line, breaks out the individual arguments,
+ * and dispatches them to the correct handler.
+ **************************************************************************** */
+static
+ void
+ parse_po(po_num)
+int po_num; /* Pseudo-op number: currently S_LEAFPROC or S_SYSPROC */
+{
+ char *args[4]; /* Pointers operands, with no embedded whitespace.
+ * arg[0] unused.
+ * arg[1-3]->operands
+ */
+ int n_ops; /* Number of operands */
+ char *p; /* Pointer to beginning of unparsed argument string */
+ char eol; /* Character that indicated end of line */
+
+ extern char is_end_of_line[];
+
+ /* Advance input pointer to end of line. */
+ p = input_line_pointer;
+ while (!is_end_of_line[ *input_line_pointer ]){
+ input_line_pointer++;
+ }
+ eol = *input_line_pointer; /* Save end-of-line char */
+ *input_line_pointer = '\0'; /* Terminate argument list */
+
+ /* Parse out operands */
+ n_ops = get_args(p, args);
+ if (n_ops == -1){
+ return;
+ }
+
+ /* Dispatch to correct handler */
+ switch (po_num){
+ case S_SYSPROC: s_sysproc(n_ops, args); break;
+ case S_LEAFPROC: s_leafproc(n_ops, args); break;
+ default: BAD_CASE(po_num); break;
+ }
+
+ /* Restore eol, so line numbers get updated correctly. Base assembler
+ * assumes we leave input pointer pointing at char following the eol.
+ */
+ *input_line_pointer++ = eol;
+}
+
+/*****************************************************************************
+ * parse_regop: parse a register operand.
+ *
+ * In case of illegal operand, issue a message and return some valid
+ * information so instruction processing can continue.
+ **************************************************************************** */
+static
+ void
+ parse_regop(regopP, optext, opdesc)
+struct regop *regopP; /* Where to put description of register operand */
+char *optext; /* Text of operand */
+char opdesc; /* Descriptor byte: what's legal for this operand */
+{
+ int n; /* Register number */
+ expressionS e; /* Parsed expression */
+
+ /* See if operand is a register */
+ n = get_regnum(optext);
+ if (n >= 0){
+ if (IS_RG_REG(n)){
+ /* global or local register */
+ if (!REG_ALIGN(opdesc,n)){
+ as_bad("unaligned register");
+ }
+ regopP->n = n;
+ regopP->mode = 0;
+ regopP->special = 0;
+ return;
+ } else if (IS_FP_REG(n) && FP_OK(opdesc)){
+ /* Floating point register, and it's allowed */
+ regopP->n = n - FP0;
+ regopP->mode = 1;
+ regopP->special = 0;
+ return;
+ } else if (IS_SF_REG(n) && SFR_OK(opdesc)){
+ /* Special-function register, and it's allowed */
+ regopP->n = n - SF0;
+ regopP->mode = 0;
+ regopP->special = 1;
+ if (!targ_has_sfr(regopP->n)){
+ as_bad("no such sfr in this architecture");
+ }
+ return;
+ }
+ } else if (LIT_OK(opdesc)){
+ /*
+ * How about a literal?
+ */
+ regopP->mode = 1;
+ regopP->special = 0;
+ if (FP_OK(opdesc)){ /* floating point literal acceptable */
+ /* Skip over 0f, 0d, or 0e prefix */
+ if ( (optext[0] == '0')
+ && (optext[1] >= 'd')
+ && (optext[1] <= 'f') ){
+ optext += 2;
+ }
+
+ if (!strcmp(optext,"0.0") || !strcmp(optext,"0") ){
+ regopP->n = 0x10;
+ return;
+ }
+ if (!strcmp(optext,"1.0") || !strcmp(optext,"1") ){
+ regopP->n = 0x16;
+ return;
+ }
+
+ } else { /* fixed point literal acceptable */
+ if ((parse_expr(optext,&e) != SEG_ABSOLUTE)
+ || (offs(e) < 0) || (offs(e) > 31)){
+ as_bad("illegal literal");
+ offs(e) = 0;
+ }
+ regopP->n = offs(e);
+ return;
+ }
+ }
+
+ /* Nothing worked */
+ syntax();
+ regopP->mode = 0; /* Register r0 is always a good one */
+ regopP->n = 0;
+ regopP->special = 0;
+} /* parse_regop() */
+
+/*****************************************************************************
+ * reg_fmt: generate a REG-format instruction
+ *
+ **************************************************************************** */
+static void reg_fmt(args, oP)
+char *args[]; /* args[0]->opcode mnemonic, args[1-3]->operands */
+struct i960_opcode *oP; /* Pointer to description of instruction */
+{
+ long instr; /* Binary to be output */
+ struct regop regop; /* Description of register operand */
+ int n_ops; /* Number of operands */
+
+
+ instr = oP->opcode;
+ n_ops = oP->num_ops;
+
+ if (n_ops >= 1){
+ parse_regop(&regop, args[1], oP->operand[0]);
+
+ if ((n_ops == 1) && !(instr & M3)){
+ /* 1-operand instruction in which the dst field should
+ * be used (instead of src1).
+ */
+ regop.n <<= 19;
+ if (regop.special){
+ regop.mode = regop.special;
+ }
+ regop.mode <<= 13;
+ regop.special = 0;
+ } else {
+ /* regop.n goes in bit 0, needs no shifting */
+ regop.mode <<= 11;
+ regop.special <<= 5;
+ }
+ instr |= regop.n | regop.mode | regop.special;
+ }
+
+ if (n_ops >= 2) {
+ parse_regop(&regop, args[2], oP->operand[1]);
+
+ if ((n_ops == 2) && !(instr & M3)){
+ /* 2-operand instruction in which the dst field should
+ * be used instead of src2).
+ */
+ regop.n <<= 19;
+ if (regop.special){
+ regop.mode = regop.special;
+ }
+ regop.mode <<= 13;
+ regop.special = 0;
+ } else {
+ regop.n <<= 14;
+ regop.mode <<= 12;
+ regop.special <<= 6;
+ }
+ instr |= regop.n | regop.mode | regop.special;
+ }
+ if (n_ops == 3){
+ parse_regop(&regop, args[3], oP->operand[2]);
+ if (regop.special){
+ regop.mode = regop.special;
+ }
+ instr |= (regop.n <<= 19) | (regop.mode <<= 13);
+ }
+ emit(instr);
+}
+
+
+/*****************************************************************************
+ * relax_cobr:
+ * Replace cobr instruction in a code fragment with equivalent branch and
+ * compare instructions, so it can reach beyond a 13-bit displacement.
+ * Set up an address fix/relocation for the new branch instruction.
+ *
+ **************************************************************************** */
+
+/* This "conditional jump" table maps cobr instructions into equivalent
+ * compare and branch opcodes.
+ */
+static
+ struct {
+ long compare;
+ long branch;
+ } coj[] = { /* COBR OPCODE: */
+ CHKBIT, BNO, /* 0x30 - bbc */
+ CMPO, BG, /* 0x31 - cmpobg */
+ CMPO, BE, /* 0x32 - cmpobe */
+ CMPO, BGE, /* 0x33 - cmpobge */
+ CMPO, BL, /* 0x34 - cmpobl */
+ CMPO, BNE, /* 0x35 - cmpobne */
+ CMPO, BLE, /* 0x36 - cmpoble */
+ CHKBIT, BO, /* 0x37 - bbs */
+ CMPI, BNO, /* 0x38 - cmpibno */
+ CMPI, BG, /* 0x39 - cmpibg */
+ CMPI, BE, /* 0x3a - cmpibe */
+ CMPI, BGE, /* 0x3b - cmpibge */
+ CMPI, BL, /* 0x3c - cmpibl */
+ CMPI, BNE, /* 0x3d - cmpibne */
+ CMPI, BLE, /* 0x3e - cmpible */
+ CMPI, BO, /* 0x3f - cmpibo */
+ };
+
+static
+ void
+ relax_cobr(fragP)
+register fragS *fragP; /* fragP->fr_opcode is assumed to point to
+ * the cobr instruction, which comes at the
+ * end of the code fragment.
+ */
+{
+ int opcode, src1, src2, m1, s2;
+ /* Bit fields from cobr instruction */
+ long bp_bits; /* Branch prediction bits from cobr instruction */
+ long instr; /* A single i960 instruction */
+ char *iP; /*->instruction to be replaced */
+ fixS *fixP; /* Relocation that can be done at assembly time */
+
+ /* PICK UP & PARSE COBR INSTRUCTION */
+ iP = fragP->fr_opcode;
+ instr = md_chars_to_number(iP, 4);
+ opcode = ((instr >> 24) & 0xff) - 0x30; /* "-0x30" for table index */
+ src1 = (instr >> 19) & 0x1f;
+ m1 = (instr >> 13) & 1;
+ s2 = instr & 1;
+ src2 = (instr >> 14) & 0x1f;
+ bp_bits= instr & BP_MASK;
+
+ /* GENERATE AND OUTPUT COMPARE INSTRUCTION */
+ instr = coj[opcode].compare
+ | src1 | (m1 << 11) | (s2 << 6) | (src2 << 14);
+ md_number_to_chars(iP, instr, 4);
+
+ /* OUTPUT BRANCH INSTRUCTION */
+ md_number_to_chars(iP+4, coj[opcode].branch | bp_bits, 4);
+
+ /* SET UP ADDRESS FIXUP/RELOCATION */
+ fixP = fix_new(fragP,
+ iP+4 - fragP->fr_literal,
+ 4,
+ fragP->fr_symbol,
+ 0,
+ fragP->fr_offset,
+ 1,
+ 0);
+
+ fixP->fx_bit_fixP = (bit_fixS *) 24; /* Store size of bit field */
+
+ fragP->fr_fix += 4;
+ frag_wane(fragP);
+}
+
+
+/*****************************************************************************
+ * reloc_callj: Relocate a 'callj' instruction
+ *
+ * This is a "non-(GNU)-standard" machine-dependent hook. The base
+ * assembler calls it when it decides it can relocate an address at
+ * assembly time instead of emitting a relocation directive.
+ *
+ * Check to see if the relocation involves a 'callj' instruction to a:
+ * sysproc: Replace the default 'call' instruction with a 'calls'
+ * leafproc: Replace the default 'call' instruction with a 'bal'.
+ * other proc: Do nothing.
+ *
+ * See b.out.h for details on the 'n_other' field in a symbol structure.
+ *
+ * IMPORTANT!:
+ * Assumes the caller has already figured out, in the case of a leafproc,
+ * to use the 'bal' entry point, and has substituted that symbol into the
+ * passed fixup structure.
+ *
+ **************************************************************************** */
+void reloc_callj(fixP)
+fixS *fixP; /* Relocation that can be done at assembly time */
+{
+ char *where; /*->the binary for the instruction being relocated */
+
+ if (!fixP->fx_callj) {
+ return;
+ } /* This wasn't a callj instruction in the first place */
+
+ where = fixP->fx_frag->fr_literal + fixP->fx_where;
+
+ if (TC_S_IS_SYSPROC(fixP->fx_addsy)) {
+ /* Symbol is a .sysproc: replace 'call' with 'calls'.
+ * System procedure number is (other-1).
+ */
+ md_number_to_chars(where, CALLS|TC_S_GET_SYSPROC(fixP->fx_addsy), 4);
+
+ /* Nothing else needs to be done for this instruction.
+ * Make sure 'md_number_to_field()' will perform a no-op.
+ */
+ fixP->fx_bit_fixP = (bit_fixS *) 1;
+
+ } else if (TC_S_IS_CALLNAME(fixP->fx_addsy)) {
+ /* Should not happen: see block comment above */
+ as_fatal("Trying to 'bal' to %s", S_GET_NAME(fixP->fx_addsy));
+
+ } else if (TC_S_IS_BALNAME(fixP->fx_addsy)) {
+ /* Replace 'call' with 'bal'; both instructions have
+ * the same format, so calling code should complete
+ * relocation as if nothing happened here.
+ */
+ md_number_to_chars(where, BAL, 4);
+ } else if (TC_S_IS_BADPROC(fixP->fx_addsy)) {
+ as_bad("Looks like a proc, but can't tell what kind.\n");
+ } /* switch on proc type */
+
+ /* else Symbol is neither a sysproc nor a leafproc */
+
+ return;
+} /* reloc_callj() */
+
+
+/*****************************************************************************
+ * s_leafproc: process .leafproc pseudo-op
+ *
+ * .leafproc takes two arguments, the second one is optional:
+ * arg[1]: name of 'call' entry point to leaf procedure
+ * arg[2]: name of 'bal' entry point to leaf procedure
+ *
+ * If the two arguments are identical, or if the second one is missing,
+ * the first argument is taken to be the 'bal' entry point.
+ *
+ * If there are 2 distinct arguments, we must make sure that the 'bal'
+ * entry point immediately follows the 'call' entry point in the linked
+ * list of symbols.
+ *
+ **************************************************************************** */
+static void s_leafproc(n_ops, args)
+int n_ops; /* Number of operands */
+char *args[]; /* args[1]->1st operand, args[2]->2nd operand */
+{
+ symbolS *callP; /* Pointer to leafproc 'call' entry point symbol */
+ symbolS *balP; /* Pointer to leafproc 'bal' entry point symbol */
+
+ if ((n_ops != 1) && (n_ops != 2)) {
+ as_bad("should have 1 or 2 operands");
+ return;
+ } /* Check number of arguments */
+
+ /* Find or create symbol for 'call' entry point. */
+ callP = symbol_find_or_make(args[1]);
+
+ if (TC_S_IS_CALLNAME(callP)) {
+ as_warn("Redefining leafproc %s", S_GET_NAME(callP));
+ } /* is leafproc */
+
+ /* If that was the only argument, use it as the 'bal' entry point.
+ * Otherwise, mark it as the 'call' entry point and find or create
+ * another symbol for the 'bal' entry point.
+ */
+ if ((n_ops == 1) || !strcmp(args[1],args[2])) {
+ TC_S_FORCE_TO_BALNAME(callP);
+
+ } else {
+ TC_S_FORCE_TO_CALLNAME(callP);
+
+ balP = symbol_find_or_make(args[2]);
+ if (TC_S_IS_CALLNAME(balP)) {
+ as_warn("Redefining leafproc %s", S_GET_NAME(balP));
+ }
+ TC_S_FORCE_TO_BALNAME(balP);
+
+ tc_set_bal_of_call(callP, balP);
+ } /* if only one arg, or the args are the same */
+
+ return;
+} /* s_leafproc() */
+
+
+/*
+ * s_sysproc: process .sysproc pseudo-op
+ *
+ * .sysproc takes two arguments:
+ * arg[1]: name of entry point to system procedure
+ * arg[2]: 'entry_num' (index) of system procedure in the range
+ * [0,31] inclusive.
+ *
+ * For [ab].out, we store the 'entrynum' in the 'n_other' field of
+ * the symbol. Since that entry is normally 0, we bias 'entrynum'
+ * by adding 1 to it. It must be unbiased before it is used.
+ */
+static void s_sysproc(n_ops, args)
+int n_ops; /* Number of operands */
+char *args[]; /* args[1]->1st operand, args[2]->2nd operand */
+{
+ expressionS exp;
+ symbolS *symP;
+
+ if (n_ops != 2) {
+ as_bad("should have two operands");
+ return;
+ } /* bad arg count */
+
+ /* Parse "entry_num" argument and check it for validity. */
+ if ((parse_expr(args[2],&exp) != SEG_ABSOLUTE)
+ || (offs(exp) < 0)
+ || (offs(exp) > 31)) {
+ as_bad("'entry_num' must be absolute number in [0,31]");
+ return;
+ }
+
+ /* Find/make symbol and stick entry number (biased by +1) into it */
+ symP = symbol_find_or_make(args[1]);
+
+ if (TC_S_IS_SYSPROC(symP)) {
+ as_warn("Redefining entrynum for sysproc %s", S_GET_NAME(symP));
+ } /* redefining */
+
+ TC_S_SET_SYSPROC(symP, offs(exp)); /* encode entry number */
+ TC_S_FORCE_TO_SYSPROC(symP);
+
+ return;
+} /* s_sysproc() */
+
+
+/*****************************************************************************
+ * shift_ok:
+ * Determine if a "shlo" instruction can be used to implement a "ldconst".
+ * This means that some number X < 32 can be shifted left to produce the
+ * constant of interest.
+ *
+ * Return the shift count, or 0 if we can't do it.
+ * Caller calculates X by shifting original constant right 'shift' places.
+ *
+ **************************************************************************** */
+static
+ int
+ shift_ok(n)
+int n; /* The constant of interest */
+{
+ int shift; /* The shift count */
+
+ if (n <= 0){
+ /* Can't do it for negative numbers */
+ return 0;
+ }
+
+ /* Shift 'n' right until a 1 is about to be lost */
+ for (shift = 0; (n & 1) == 0; shift++){
+ n >>= 1;
+ }
+
+ if (n >= 32){
+ return 0;
+ }
+ return shift;
+}
+
+
+/*****************************************************************************
+ * syntax: issue syntax error
+ *
+ **************************************************************************** */
+static void syntax() {
+ as_bad("syntax error");
+} /* syntax() */
+
+
+/*****************************************************************************
+ * targ_has_sfr:
+ * Return TRUE iff the target architecture supports the specified
+ * special-function register (sfr).
+ *
+ **************************************************************************** */
+static
+ int
+ targ_has_sfr(n)
+int n; /* Number (0-31) of sfr */
+{
+ switch (architecture){
+ case ARCH_KA:
+ case ARCH_KB:
+ case ARCH_MC:
+ return 0;
+ case ARCH_CA:
+ default:
+ return ((0 <= n) && (n <= 2));
+ }
+}
+
+
+/*****************************************************************************
+ * targ_has_iclass:
+ * Return TRUE iff the target architecture supports the indicated
+ * class of instructions.
+ *
+ **************************************************************************** */
+static
+ int
+ targ_has_iclass(ic)
+int ic; /* Instruction class; one of:
+ * I_BASE, I_CX, I_DEC, I_KX, I_FP, I_MIL, I_CASIM
+ */
+{
+ iclasses_seen |= ic;
+ switch (architecture){
+ case ARCH_KA: return ic & (I_BASE | I_KX);
+ case ARCH_KB: return ic & (I_BASE | I_KX | I_FP | I_DEC);
+ case ARCH_MC: return ic & (I_BASE | I_KX | I_FP | I_DEC | I_MIL);
+ case ARCH_CA: return ic & (I_BASE | I_CX | I_CASIM);
+ default:
+ if ((iclasses_seen & (I_KX|I_FP|I_DEC|I_MIL))
+ && (iclasses_seen & I_CX)){
+ as_warn("architecture of opcode conflicts with that of earlier instruction(s)");
+ iclasses_seen &= ~ic;
+ }
+ return 1;
+ }
+}
+
+
+/* Parse an operand that is machine-specific.
+ We just return without modifying the expression if we have nothing
+ to do. */
+
+/* ARGSUSED */
+void
+ md_operand (expressionP)
+expressionS *expressionP;
+{
+}
+
+/* We have no need to default values of symbols. */
+
+/* ARGSUSED */
+symbolS *md_undefined_symbol(name)
+char *name;
+{
+ return 0;
+} /* md_undefined_symbol() */
+
+/* Exactly what point is a PC-relative offset relative TO?
+ On the i960, they're relative to the address of the instruction,
+ which we have set up as the address of the fixup too. */
+long
+ md_pcrel_from (fixP)
+fixS *fixP;
+{
+ return fixP->fx_where + fixP->fx_frag->fr_address;
+}
+
+void
+ md_apply_fix(fixP, val)
+fixS *fixP;
+long val;
+{
+ char *place = fixP->fx_where + fixP->fx_frag->fr_literal;
+
+ if (!fixP->fx_bit_fixP) {
+
+ switch (fixP->fx_im_disp) {
+ case 0:
+ fixP->fx_addnumber = val;
+ md_number_to_imm(place, val, fixP->fx_size, fixP);
+ break;
+ case 1:
+ md_number_to_disp(place,
+ fixP->fx_pcrel ? val + fixP->fx_pcrel_adjust : val,
+ fixP->fx_size);
+ break;
+ case 2: /* fix requested for .long .word etc */
+ md_number_to_chars(place, val, fixP->fx_size);
+ break;
+ default:
+ as_fatal("Internal error in md_apply_fix() in file \"%s\"", __FILE__);
+ } /* OVE: maybe one ought to put _imm _disp _chars in one md-func */
+ } else {
+ md_number_to_field(place, val, fixP->fx_bit_fixP);
+ }
+
+ return;
+} /* md_apply_fix() */
+
+#if defined(OBJ_AOUT) | defined(OBJ_BOUT)
+void tc_bout_fix_to_chars(where, fixP, segment_address_in_file)
+char *where;
+fixS *fixP;
+relax_addressT segment_address_in_file;
+{
+ static unsigned char nbytes_r_length[] = { 42, 0, 1, 42, 2 };
+ struct relocation_info ri;
+ symbolS *symbolP;
+
+ /* JF this is for paranoia */
+ memset((char *)&ri, '\0', sizeof(ri));
+
+ know((symbolP = fixP->fx_addsy) != 0);
+
+ /* These two 'cuz of NS32K */
+ ri.r_callj = fixP->fx_callj;
+
+ ri.r_length = nbytes_r_length[fixP->fx_size];
+ ri.r_pcrel = fixP->fx_pcrel;
+ ri.r_address = fixP->fx_frag->fr_address + fixP->fx_where - segment_address_in_file;
+
+ if (!S_IS_DEFINED(symbolP)) {
+ ri.r_extern = 1;
+ ri.r_index = symbolP->sy_number;
+ } else {
+ ri.r_extern = 0;
+ ri.r_index = S_GET_TYPE(symbolP);
+ }
+
+ /* Output the relocation information in machine-dependent form. */
+ md_ri_to_chars(where, &ri);
+
+ return;
+} /* tc_bout_fix_to_chars() */
+
+#endif /* OBJ_AOUT or OBJ_BOUT */
+
+/* Align an address by rounding it up to the specified boundary.
+ */
+long md_section_align(seg, addr)
+segT seg;
+long addr; /* Address to be rounded up */
+{
+ return((addr + (1 << section_alignment[(int) seg]) - 1) & (-1 << section_alignment[(int) seg]));
+} /* md_section_align() */
+
+#ifdef OBJ_COFF
+void tc_headers_hook(headers)
+object_headers *headers;
+{
+ /* FIXME: remove this line */ /* unsigned short arch_flag = 0; */
+
+ if ((iclasses_seen == I_BASE) || (iclasses_seen == 0)) {
+ headers->filehdr.f_flags |= F_I960CORE;
+ } else if (iclasses_seen & I_CX){
+ headers->filehdr.f_flags |= F_I960CA;
+ } else if (iclasses_seen & I_MIL){
+ headers->filehdr.f_flags |= F_I960MC;
+ } else if (iclasses_seen & (I_DEC|I_FP)){
+ headers->filehdr.f_flags |= F_I960KB;
+ } else {
+ headers->filehdr.f_flags |= F_I960KA;
+ } /* set arch flag */
+
+ if (flagseen['R']) {
+ headers->filehdr.f_magic = I960RWMAGIC;
+ headers->aouthdr.magic = OMAGIC;
+ } else {
+ headers->filehdr.f_magic = I960ROMAGIC;
+ headers->aouthdr.magic = NMAGIC;
+ } /* set magic numbers */
+
+ return;
+} /* tc_headers_hook() */
+#endif /* OBJ_COFF */
+
+/*
+ * Things going on here:
+ *
+ * For bout, We need to assure a couple of simplifying
+ * assumptions about leafprocs for the linker: the leafproc
+ * entry symbols will be defined in the same assembly in
+ * which they're declared with the '.leafproc' directive;
+ * and if a leafproc has both 'call' and 'bal' entry points
+ * they are both global or both local.
+ *
+ * For coff, the call symbol has a second aux entry that
+ * contains the bal entry point. The bal symbol becomes a
+ * label.
+ *
+ * For coff representation, the call symbol has a second aux entry that
+ * contains the bal entry point. The bal symbol becomes a label.
+ *
+ */
+
+void tc_crawl_symbol_chain(headers)
+object_headers *headers;
+{
+ symbolS *symbolP;
+
+ for (symbolP = symbol_rootP; symbolP; symbolP = symbol_next(symbolP)) {
+#ifdef OBJ_COFF
+ if (TC_S_IS_SYSPROC(symbolP)) {
+ /* second aux entry already contains the sysproc number */
+ S_SET_NUMBER_AUXILIARY(symbolP, 2);
+ S_SET_STORAGE_CLASS(symbolP, C_SCALL);
+ S_SET_DATA_TYPE(symbolP, S_GET_DATA_TYPE(symbolP) | (DT_FCN << N_BTSHFT));
+ continue;
+ } /* rewrite sysproc */
+#endif /* OBJ_COFF */
+
+ if (!TC_S_IS_BALNAME(symbolP) && !TC_S_IS_CALLNAME(symbolP)) {
+ continue;
+ } /* Not a leafproc symbol */
+
+ if (!S_IS_DEFINED(symbolP)) {
+ as_bad("leafproc symbol '%s' undefined", S_GET_NAME(symbolP));
+ } /* undefined leaf */
+
+ if (TC_S_IS_CALLNAME(symbolP)) {
+ symbolS *balP = tc_get_bal_of_call(symbolP);
+ if (S_IS_EXTERNAL(symbolP) != S_IS_EXTERNAL(balP)) {
+ S_SET_EXTERNAL(symbolP);
+ S_SET_EXTERNAL(balP);
+ as_warn("Warning: making leafproc entries %s and %s both global\n",
+ S_GET_NAME(symbolP), S_GET_NAME(balP));
+ } /* externality mismatch */
+ } /* if callname */
+ } /* walk the symbol chain */
+
+ return;
+} /* tc_crawl_symbol_chain() */
+
+/*
+ * For aout or bout, the bal immediately follows the call.
+ *
+ * For coff, we cheat and store a pointer to the bal symbol
+ * in the second aux entry of the call.
+ */
+
+void tc_set_bal_of_call(callP, balP)
+symbolS *callP;
+symbolS *balP;
+{
+ know(TC_S_IS_CALLNAME(callP));
+ know(TC_S_IS_BALNAME(balP));
+
+#ifdef OBJ_COFF
+
+ callP->sy_symbol.ost_auxent[1].x_bal.x_balntry = (int) balP;
+ S_SET_NUMBER_AUXILIARY(callP,2);
+
+#elif defined(OBJ_AOUT) || defined(OBJ_BOUT)
+
+ /* If the 'bal' entry doesn't immediately follow the 'call'
+ * symbol, unlink it from the symbol list and re-insert it.
+ */
+ if (symbol_next(callP) != balP) {
+ symbol_remove(balP, &symbol_rootP, &symbol_lastP);
+ symbol_append(balP, callP, &symbol_rootP, &symbol_lastP);
+ } /* if not in order */
+
+#else
+ (as yet unwritten.);
+#endif /* switch on OBJ_FORMAT */
+
+ return;
+} /* tc_set_bal_of_call() */
+
+char *_tc_get_bal_of_call(callP)
+symbolS *callP;
+{
+ symbolS *retval;
+
+ know(TC_S_IS_CALLNAME(callP));
+
+#ifdef OBJ_COFF
+ retval = (symbolS *) (callP->sy_symbol.ost_auxent[1].x_bal.x_balntry);
+#elif defined(OBJ_AOUT) || defined(OBJ_BOUT)
+ retval = symbol_next(callP);
+#else
+ (as yet unwritten.);
+#endif /* switch on OBJ_FORMAT */
+
+ know(TC_S_IS_BALNAME(retval));
+ return((char *) retval);
+} /* _tc_get_bal_of_call() */
+
+void tc_coff_symbol_emit_hook(symbolP)
+symbolS *symbolP;
+{
+ if (TC_S_IS_CALLNAME(symbolP)) {
+#ifdef OBJ_COFF
+ symbolS *balP = tc_get_bal_of_call(symbolP);
+
+ /* second aux entry contains the bal entry point */
+ /* S_SET_NUMBER_AUXILIARY(symbolP, 2); */
+ symbolP->sy_symbol.ost_auxent[1].x_bal.x_balntry = S_GET_VALUE(balP);
+ S_SET_STORAGE_CLASS(symbolP, (!SF_GET_LOCAL(symbolP) ? C_LEAFEXT : C_LEAFSTAT));
+ S_SET_DATA_TYPE(symbolP, S_GET_DATA_TYPE(symbolP) | (DT_FCN << N_BTSHFT));
+ /* fix up the bal symbol */
+ S_SET_STORAGE_CLASS(balP, C_LABEL);
+#endif /* OBJ_COFF */
+ } /* only on calls */
+
+ return;
+} /* tc_coff_symbol_emit_hook() */
+
+/*
+ * Local Variables:
+ * comment-column: 0
+ * fill-column: 131
+ * End:
+ */
+
+/* end of tc-i960.c */
diff --git a/gnu/usr.bin/as/config/tc-i960.h b/gnu/usr.bin/as/config/tc-i960.h
new file mode 100644
index 0000000..236c9b1
--- /dev/null
+++ b/gnu/usr.bin/as/config/tc-i960.h
@@ -0,0 +1,281 @@
+/* tc-i960.h - Basic 80960 instruction formats.
+ Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
+
+ This file is part of GAS, the GNU Assembler.
+
+ GAS is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2,
+ or (at your option) any later version.
+
+ GAS is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+ the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public
+ License along with GAS; see the file COPYING. If not, write
+ to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#ifndef TC_I960
+#define TC_I960 1
+
+#define NO_LISTING
+
+/*
+ * The 'COJ' instructions are actually COBR instructions with the 'b' in
+ * the mnemonic replaced by a 'j'; they are ALWAYS "de-optimized" if necessary:
+ * if the displacement will not fit in 13 bits, the assembler will replace them
+ * with the corresponding compare and branch instructions.
+ *
+ * All of the 'MEMn' instructions are the same format; the 'n' in the name
+ * indicates the default index scale factor (the size of the datum operated on).
+ *
+ * The FBRA formats are not actually an instruction format. They are the
+ * "convenience directives" for branching on floating-point comparisons,
+ * each of which generates 2 instructions (a 'bno' and one other branch).
+ *
+ * The CALLJ format is not actually an instruction format. It indicates that
+ * the instruction generated (a CTRL-format 'call') should have its relocation
+ * specially flagged for link-time replacement with a 'bal' or 'calls' if
+ * appropriate.
+ */
+
+/* tailor gas */
+#define SYMBOLS_NEED_BACKPOINTERS
+#define LOCAL_LABELS_FB
+#define WANT_BITFIELDS
+
+/* tailor the coff format */
+#define OBJ_COFF_SECTION_HEADER_HAS_ALIGNMENT
+#define OBJ_COFF_MAX_AUXENTRIES (2)
+
+/* other */
+#define CTRL 0
+#define COBR 1
+#define COJ 2
+#define REG 3
+#define MEM1 4
+#define MEM2 5
+#define MEM4 6
+#define MEM8 7
+#define MEM12 8
+#define MEM16 9
+#define FBRA 10
+#define CALLJ 11
+
+/* Masks for the mode bits in REG format instructions */
+#define M1 0x0800
+#define M2 0x1000
+#define M3 0x2000
+
+/* Generate the 12-bit opcode for a REG format instruction by placing the
+ * high 8 bits in instruction bits 24-31, the low 4 bits in instruction bits
+ * 7-10.
+ */
+
+#define REG_OPC(opc) ((opc & 0xff0) << 20) | ((opc & 0xf) << 7)
+
+/* Generate a template for a REG format instruction: place the opcode bits
+ * in the appropriate fields and OR in mode bits for the operands that will not
+ * be used. I.e.,
+ * set m1=1, if src1 will not be used
+ * set m2=1, if src2 will not be used
+ * set m3=1, if dst will not be used
+ *
+ * Setting the "unused" mode bits to 1 speeds up instruction execution(!).
+ * The information is also useful to us because some 1-operand REG instructions
+ * use the src1 field, others the dst field; and some 2-operand REG instructions
+ * use src1/src2, others src1/dst. The set mode bits enable us to distinguish.
+ */
+#define R_0(opc) ( REG_OPC(opc) | M1 | M2 | M3 ) /* No operands */
+#define R_1(opc) ( REG_OPC(opc) | M2 | M3 ) /* 1 operand: src1 */
+#define R_1D(opc) ( REG_OPC(opc) | M1 | M2 ) /* 1 operand: dst */
+#define R_2(opc) ( REG_OPC(opc) | M3 ) /* 2 ops: src1/src2 */
+#define R_2D(opc) ( REG_OPC(opc) | M2 ) /* 2 ops: src1/dst */
+#define R_3(opc) ( REG_OPC(opc) ) /* 3 operands */
+
+/* DESCRIPTOR BYTES FOR REGISTER OPERANDS
+ *
+ * Interpret names as follows:
+ * R: global or local register only
+ * RS: global, local, or (if target allows) special-function register only
+ * RL: global or local register, or integer literal
+ * RSL: global, local, or (if target allows) special-function register;
+ * or integer literal
+ * F: global, local, or floating-point register
+ * FL: global, local, or floating-point register; or literal (including
+ * floating point)
+ *
+ * A number appended to a name indicates that registers must be aligned,
+ * as follows:
+ * 2: register number must be multiple of 2
+ * 4: register number must be multiple of 4
+ */
+
+#define SFR 0x10 /* Mask for the "sfr-OK" bit */
+#define LIT 0x08 /* Mask for the "literal-OK" bit */
+#define FP 0x04 /* Mask for "floating-point-OK" bit */
+
+/* This macro ors the bits together. Note that 'align' is a mask
+ * for the low 0, 1, or 2 bits of the register number, as appropriate.
+ */
+#define OP(align,lit,fp,sfr) ( align | lit | fp | sfr )
+
+#define R OP( 0, 0, 0, 0 )
+#define RS OP( 0, 0, 0, SFR )
+#define RL OP( 0, LIT, 0, 0 )
+#define RSL OP( 0, LIT, 0, SFR )
+#define F OP( 0, 0, FP, 0 )
+#define FL OP( 0, LIT, FP, 0 )
+#define R2 OP( 1, 0, 0, 0 )
+#define RL2 OP( 1, LIT, 0, 0 )
+#define F2 OP( 1, 0, FP, 0 )
+#define FL2 OP( 1, LIT, FP, 0 )
+#define R4 OP( 3, 0, 0, 0 )
+#define RL4 OP( 3, LIT, 0, 0 )
+#define F4 OP( 3, 0, FP, 0 )
+#define FL4 OP( 3, LIT, FP, 0 )
+
+#define M 0x7f /* Memory operand (MEMA & MEMB format instructions) */
+
+/* Macros to extract info from the register operand descriptor byte 'od'.
+ */
+#define SFR_OK(od) (od & SFR) /* TRUE if sfr operand allowed */
+#define LIT_OK(od) (od & LIT) /* TRUE if literal operand allowed */
+#define FP_OK(od) (od & FP) /* TRUE if floating-point op allowed */
+#define REG_ALIGN(od,n) ((od & 0x3 & n) == 0)
+/* TRUE if reg #n is properly aligned */
+#define MEMOP(od) (od == M) /* TRUE if operand is a memory operand*/
+
+/* Classes of 960 intructions:
+ * - each instruction falls into one class.
+ * - each target architecture supports one or more classes.
+ *
+ * EACH CONSTANT MUST CONTAIN 1 AND ONLY 1 SET BIT!: see targ_has_iclass().
+ */
+#define I_BASE 0x01 /* 80960 base instruction set */
+#define I_CX 0x02 /* 80960Cx instruction */
+#define I_DEC 0x04 /* Decimal instruction */
+#define I_FP 0x08 /* Floating point instruction */
+#define I_KX 0x10 /* 80960Kx instruction */
+#define I_MIL 0x20 /* Military instruction */
+
+/* MEANING OF 'n_other' in the symbol record.
+ *
+ * If non-zero, the 'n_other' fields indicates either a leaf procedure or
+ * a system procedure, as follows:
+ *
+ * 1 <= n_other <= 32 :
+ * The symbol is the entry point to a system procedure.
+ * 'n_value' is the address of the entry, as for any other
+ * procedure. The system procedure number (which can be used in
+ * a 'calls' instruction) is (n_other-1). These entries come from
+ * '.sysproc' directives.
+ *
+ * n_other == N_CALLNAME
+ * the symbol is the 'call' entry point to a leaf procedure.
+ * The *next* symbol in the symbol table must be the corresponding
+ * 'bal' entry point to the procedure (see following). These
+ * entries come from '.leafproc' directives in which two different
+ * symbols are specified (the first one is represented here).
+ *
+ *
+ * n_other == N_BALNAME
+ * the symbol is the 'bal' entry point to a leaf procedure.
+ * These entries result from '.leafproc' directives in which only
+ * one symbol is specified, or in which the same symbol is
+ * specified twice.
+ *
+ * Note that an N_CALLNAME entry *must* have a corresponding N_BALNAME entry,
+ * but not every N_BALNAME entry must have an N_CALLNAME entry.
+ */
+#define N_CALLNAME (-1)
+#define N_BALNAME (-2)
+
+
+/* i960 uses a custom relocation record. */
+
+/* let obj-aout.h know */
+#define CUSTOM_RELOC_FORMAT 1
+/* let a.out.gnu.h know */
+#define N_RELOCATION_INFO_DECLARED 1
+struct relocation_info {
+ int r_address; /* File address of item to be relocated */
+ unsigned
+ r_index:24,/* Index of symbol on which relocation is based*/
+ r_pcrel:1, /* 1 => relocate PC-relative; else absolute
+ * On i960, pc-relative implies 24-bit
+ * address, absolute implies 32-bit.
+ */
+ r_length:2, /* Number of bytes to relocate:
+ * 0 => 1 byte
+ * 1 => 2 bytes
+ * 2 => 4 bytes -- only value used for i960
+ */
+ r_extern:1,
+ r_bsr:1, /* Something for the GNU NS32K assembler */
+ r_disp:1, /* Something for the GNU NS32K assembler */
+ r_callj:1, /* 1 if relocation target is an i960 'callj' */
+ nuthin:1; /* Unused */
+};
+
+/* hacks for tracking callj's */
+#if defined(OBJ_AOUT) | defined(OBJ_BOUT)
+
+#define TC_S_IS_SYSPROC(s) ((1 <= S_GET_OTHER(s)) && (S_GET_OTHER(s) <= 32))
+#define TC_S_IS_BALNAME(s) (S_GET_OTHER(s) == N_BALNAME)
+#define TC_S_IS_CALLNAME(s) (S_GET_OTHER(s) == N_CALLNAME)
+#define TC_S_IS_BADPROC(s) ((S_GET_OTHER(s) != 0) && !TC_S_IS_CALLNAME(s) && !TC_S_IS_BALNAME(s) && !TC_S_IS_SYSPROC(s))
+
+#define TC_S_SET_SYSPROC(s, p) (S_SET_OTHER((s), (p)+1))
+#define TC_S_GET_SYSPROC(s) (S_GET_OTHER(s)-1)
+
+#define TC_S_FORCE_TO_BALNAME(s) (S_SET_OTHER((s), N_BALNAME))
+#define TC_S_FORCE_TO_CALLNAME(s) (S_SET_OTHER((s), N_CALLNAME))
+#define TC_S_FORCE_TO_SYSPROC(s) {;}
+
+#elif defined(OBJ_COFF)
+
+#define TC_S_IS_SYSPROC(s) (S_GET_STORAGE_CLASS(s) == C_SCALL)
+#define TC_S_IS_BALNAME(s) (SF_GET_BALNAME(s))
+#define TC_S_IS_CALLNAME(s) (SF_GET_CALLNAME(s))
+#define TC_S_IS_BADPROC(s) (TC_S_IS_SYSPROC(s) && TC_S_GET_SYSPROC(s) < 0 && 31 < TC_S_GET_SYSPROC(s))
+
+#define TC_S_SET_SYSPROC(s, p) ((s)->sy_symbol.ost_auxent[1].x_sc.x_stindx = (p))
+#define TC_S_GET_SYSPROC(s) ((s)->sy_symbol.ost_auxent[1].x_sc.x_stindx)
+
+#define TC_S_FORCE_TO_BALNAME(s) (SF_SET_BALNAME(s))
+#define TC_S_FORCE_TO_CALLNAME(s) (SF_SET_CALLNAME(s))
+#define TC_S_FORCE_TO_SYSPROC(s) (S_SET_STORAGE_CLASS((s), C_SCALL))
+
+#else /* switch on OBJ */
+you lose
+#endif /* witch on OBJ */
+
+#if __STDC__ == 1
+
+ void brtab_emit(void);
+void reloc_callj(); /* this is really reloc_callj(fixS *fixP) but I don't want to change header inclusion order. */
+void tc_set_bal_of_call(); /* this is really tc_set_bal_of_call(symbolS *callP, symbolS *balP) */
+
+#else /* not __STDC__ */
+
+void brtab_emit();
+void reloc_callj();
+void tc_set_bal_of_call();
+
+#endif /* not __STDC__ */
+
+char *_tc_get_bal_of_call(); /* this is really symbolS *tc_get_bal_of_call(symbolS *callP). */
+#define tc_get_bal_of_call(c) ((symbolS *) _tc_get_bal_of_call(c))
+#endif
+
+/*
+ * Local Variables:
+ * comment-column: 0
+ * fill-column: 131
+ * End:
+ */
+
+/* end of tc-i960.h */
diff --git a/gnu/usr.bin/as/config/tc-m68851.h b/gnu/usr.bin/as/config/tc-m68851.h
new file mode 100644
index 0000000..8e69702
--- /dev/null
+++ b/gnu/usr.bin/as/config/tc-m68851.h
@@ -0,0 +1,304 @@
+/* This file is tc-m68851.h
+
+ Copyright (C) 1987-1992 Free Software Foundation, Inc.
+
+ This file is part of GAS, the GNU Assembler.
+
+ GAS is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GAS is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GAS; see the file COPYING. If not, write to
+ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/*
+ * pmmu.h
+ */
+
+/* I suppose we have to copyright this file. Someone on the net sent it
+ to us as part of the changes for the m68851 Memory Management Unit */
+
+/* Copyright (C) 1987 Free Software Foundation, Inc.
+
+ This file is part of Gas, the GNU Assembler.
+
+ The GNU assembler is distributed in the hope that it will be
+ useful, but WITHOUT ANY WARRANTY. No author or distributor
+ accepts responsibility to anyone for the consequences of using it
+ or for whether it serves any particular purpose or works at all,
+ unless he says so in writing. Refer to the GNU Assembler General
+ Public License for full details.
+
+ Everyone is granted permission to copy, modify and redistribute
+ the GNU Assembler, but only under the conditions described in the
+ GNU Assembler General Public License. A copy of this license is
+ supposed to have been given to you along with the GNU Assembler
+ so you can know your rights and responsibilities. It should be
+ in a file named COPYING. Among other things, the copyright
+ notice and this notice must be preserved on all copies. */
+
+#ifdef m68851
+
+/*
+ I didn't use much imagination in choosing the
+ following codes, so many of them aren't very
+ mnemonic. -rab
+
+ P pmmu register
+ Possible values:
+ 000 TC Translation Control reg
+ 100 CAL Current Access Level
+ 101 VAL Validate Access Level
+ 110 SCC Stack Change Control
+ 111 AC Access Control
+
+ W wide pmmu registers
+ Possible values:
+ 001 DRP Dma Root Pointer
+ 010 SRP Supervisor Root Pointer
+ 011 CRP Cpu Root Pointer
+
+ f function code register
+ 0 SFC
+ 1 DFC
+
+ V VAL register only
+
+ X BADx, BACx
+ 100 BAD Breakpoint Acknowledge Data
+ 101 BAC Breakpoint Acknowledge Control
+
+ Y PSR
+ Z PCSR
+
+ | memory (modes 2-6, 7.*)
+
+ */
+
+/*
+ * these defines should be in m68k.c but
+ * i put them here to keep all the m68851 stuff
+ * together -rab
+ * JF--Make sure these #s don't clash with the ones in m68k.c
+ * That would be BAD.
+ */
+#define TC (FPS+1) /* 48 */
+#define DRP (TC+1) /* 49 */
+#define SRP (DRP+1) /* 50 */
+#define CRP (SRP+1) /* 51 */
+#define CAL (CRP+1) /* 52 */
+#define VAL (CAL+1) /* 53 */
+#define SCC (VAL+1) /* 54 */
+#define AC (SCC+1) /* 55 */
+#define BAD (AC+1) /* 56,57,58,59, 60,61,62,63 */
+#define BAC (BAD+8) /* 64,65,66,67, 68,69,70,71 */
+#define PSR (BAC+8) /* 72 */
+#define PCSR (PSR+1) /* 73 */
+
+/* name */ /* opcode */ /* match */ /* args */
+
+{"pbac", one(0xf0c7), one(0xffbf), "Bc"},
+{"pbacw", one(0xf087), one(0xffbf), "Bc"},
+{"pbas", one(0xf0c6), one(0xffbf), "Bc"},
+{"pbasw", one(0xf086), one(0xffbf), "Bc"},
+{"pbbc", one(0xf0c1), one(0xffbf), "Bc"},
+{"pbbcw", one(0xf081), one(0xffbf), "Bc"},
+{"pbbs", one(0xf0c0), one(0xffbf), "Bc"},
+{"pbbsw", one(0xf080), one(0xffbf), "Bc"},
+{"pbcc", one(0xf0cf), one(0xffbf), "Bc"},
+{"pbccw", one(0xf08f), one(0xffbf), "Bc"},
+{"pbcs", one(0xf0ce), one(0xffbf), "Bc"},
+{"pbcsw", one(0xf08e), one(0xffbf), "Bc"},
+{"pbgc", one(0xf0cd), one(0xffbf), "Bc"},
+{"pbgcw", one(0xf08d), one(0xffbf), "Bc"},
+{"pbgs", one(0xf0cc), one(0xffbf), "Bc"},
+{"pbgsw", one(0xf08c), one(0xffbf), "Bc"},
+{"pbic", one(0xf0cb), one(0xffbf), "Bc"},
+{"pbicw", one(0xf08b), one(0xffbf), "Bc"},
+{"pbis", one(0xf0ca), one(0xffbf), "Bc"},
+{"pbisw", one(0xf08a), one(0xffbf), "Bc"},
+{"pblc", one(0xf0c3), one(0xffbf), "Bc"},
+{"pblcw", one(0xf083), one(0xffbf), "Bc"},
+{"pbls", one(0xf0c2), one(0xffbf), "Bc"},
+{"pblsw", one(0xf082), one(0xffbf), "Bc"},
+{"pbsc", one(0xf0c5), one(0xffbf), "Bc"},
+{"pbscw", one(0xf085), one(0xffbf), "Bc"},
+{"pbss", one(0xf0c4), one(0xffbf), "Bc"},
+{"pbssw", one(0xf084), one(0xffbf), "Bc"},
+{"pbwc", one(0xf0c9), one(0xffbf), "Bc"},
+{"pbwcw", one(0xf089), one(0xffbf), "Bc"},
+{"pbws", one(0xf0c8), one(0xffbf), "Bc"},
+{"pbwsw", one(0xf088), one(0xffbf), "Bc"},
+
+
+{"pdbac", two(0xf048, 0x0007), two(0xfff8, 0xffff), "DsBw"},
+{"pdbas", two(0xf048, 0x0006), two(0xfff8, 0xffff), "DsBw"},
+{"pdbbc", two(0xf048, 0x0001), two(0xfff8, 0xffff), "DsBw"},
+{"pdbbs", two(0xf048, 0x0000), two(0xfff8, 0xffff), "DsBw"},
+{"pdbcc", two(0xf048, 0x000f), two(0xfff8, 0xffff), "DsBw"},
+{"pdbcs", two(0xf048, 0x000e), two(0xfff8, 0xffff), "DsBw"},
+{"pdbgc", two(0xf048, 0x000d), two(0xfff8, 0xffff), "DsBw"},
+{"pdbgs", two(0xf048, 0x000c), two(0xfff8, 0xffff), "DsBw"},
+{"pdbic", two(0xf048, 0x000b), two(0xfff8, 0xffff), "DsBw"},
+{"pdbis", two(0xf048, 0x000a), two(0xfff8, 0xffff), "DsBw"},
+{"pdblc", two(0xf048, 0x0003), two(0xfff8, 0xffff), "DsBw"},
+{"pdbls", two(0xf048, 0x0002), two(0xfff8, 0xffff), "DsBw"},
+{"pdbsc", two(0xf048, 0x0005), two(0xfff8, 0xffff), "DsBw"},
+{"pdbss", two(0xf048, 0x0004), two(0xfff8, 0xffff), "DsBw"},
+{"pdbwc", two(0xf048, 0x0009), two(0xfff8, 0xffff), "DsBw"},
+{"pdbws", two(0xf048, 0x0008), two(0xfff8, 0xffff), "DsBw"},
+
+{"pflusha", two(0xf000, 0x2400), two(0xffff, 0xffff), "" },
+
+{"pflush", two(0xf000, 0x3010), two(0xffc0, 0xfe10), "T3T9" },
+{"pflush", two(0xf000, 0x3810), two(0xffc0, 0xfe10), "T3T9&s" },
+{"pflush", two(0xf000, 0x3008), two(0xffc0, 0xfe18), "D3T9" },
+{"pflush", two(0xf000, 0x3808), two(0xffc0, 0xfe18), "D3T9&s" },
+{"pflush", two(0xf000, 0x3000), two(0xffc0, 0xfe1e), "f3T9" },
+{"pflush", two(0xf000, 0x3800), two(0xffc0, 0xfe1e), "f3T9&s" },
+
+{"pflushs", two(0xf000, 0x3410), two(0xfff8, 0xfe10), "T3T9" },
+{"pflushs", two(0xf000, 0x3c00), two(0xfff8, 0xfe00), "T3T9&s" },
+{"pflushs", two(0xf000, 0x3408), two(0xfff8, 0xfe18), "D3T9" },
+{"pflushs", two(0xf000, 0x3c08), two(0xfff8, 0xfe18), "D3T9&s" },
+{"pflushs", two(0xf000, 0x3400), two(0xfff8, 0xfe1e), "f3T9" },
+{"pflushs", two(0xf000, 0x3c00), two(0xfff8, 0xfe1e), "f3T9&s"},
+
+{"pflushr", two(0xf000, 0xa000), two(0xffc0, 0xffff), "|s" },
+
+{"ploadr", two(0xf000, 0x2210), two(0xffc0, 0xfff0), "T3&s" },
+{"ploadr", two(0xf000, 0x2208), two(0xffc0, 0xfff8), "D3&s" },
+{"ploadr", two(0xf000, 0x2200), two(0xffc0, 0xfffe), "f3&s" },
+{"ploadw", two(0xf000, 0x2010), two(0xffc0, 0xfff0), "T3&s" },
+{"ploadw", two(0xf000, 0x2008), two(0xffc0, 0xfff8), "D3&s" },
+{"ploadw", two(0xf000, 0x2000), two(0xffc0, 0xfffe), "f3&s" },
+
+ /* TC, CRP, DRP, SRP, CAL, VAL, SCC, AC */
+{"pmove", two(0xf000, 0x4000), two(0xffc0, 0xe3ff), "*sP8" },
+{"pmove", two(0xf000, 0x4200), two(0xffc0, 0xe3ff), "P8%s" },
+{"pmove", two(0xf000, 0x4000), two(0xffc0, 0xe3ff), "|sW8" },
+{"pmove", two(0xf000, 0x4200), two(0xffc0, 0xe3ff), "W8~s" },
+
+ /* BADx, BACx */
+{"pmove", two(0xf000, 0x6200), two(0xffc0, 0xe3e3), "*sX3" },
+{"pmove", two(0xf000, 0x6000), two(0xffc0, 0xe3e3), "X3%s" },
+
+ /* PSR, PCSR */
+ /* {"pmove", two(0xf000, 0x6100), two(oxffc0, oxffff), "*sZ8" }, */
+{"pmove", two(0xf000, 0x6000), two(0xffc0, 0xffff), "*sY8" },
+{"pmove", two(0xf000, 0x6200), two(0xffc0, 0xffff), "Y8%s" },
+{"pmove", two(0xf000, 0x6600), two(0xffc0, 0xffff), "Z8%s" },
+
+{"prestore", one(0xf140), one(0xffc0), "&s"},
+{"prestore", one(0xf158), one(0xfff8), "+s"},
+{"psave", one(0xf100), one(0xffc0), "&s"},
+{"psave", one(0xf100), one(0xffc0), "+s"},
+
+{"psac", two(0xf040, 0x0007), two(0xffc0, 0xffff), "@s"},
+{"psas", two(0xf040, 0x0006), two(0xffc0, 0xffff), "@s"},
+{"psbc", two(0xf040, 0x0001), two(0xffc0, 0xffff), "@s"},
+{"psbs", two(0xf040, 0x0000), two(0xffc0, 0xffff), "@s"},
+{"pscc", two(0xf040, 0x000f), two(0xffc0, 0xffff), "@s"},
+{"pscs", two(0xf040, 0x000e), two(0xffc0, 0xffff), "@s"},
+{"psgc", two(0xf040, 0x000d), two(0xffc0, 0xffff), "@s"},
+{"psgs", two(0xf040, 0x000c), two(0xffc0, 0xffff), "@s"},
+{"psic", two(0xf040, 0x000b), two(0xffc0, 0xffff), "@s"},
+{"psis", two(0xf040, 0x000a), two(0xffc0, 0xffff), "@s"},
+{"pslc", two(0xf040, 0x0003), two(0xffc0, 0xffff), "@s"},
+{"psls", two(0xf040, 0x0002), two(0xffc0, 0xffff), "@s"},
+{"pssc", two(0xf040, 0x0005), two(0xffc0, 0xffff), "@s"},
+{"psss", two(0xf040, 0x0004), two(0xffc0, 0xffff), "@s"},
+{"pswc", two(0xf040, 0x0009), two(0xffc0, 0xffff), "@s"},
+{"psws", two(0xf040, 0x0008), two(0xffc0, 0xffff), "@s"},
+
+{"ptestr", two(0xf000, 0x8210), two(0xffc0, 0xe3f0), "T3&sQ8" },
+{"ptestr", two(0xf000, 0x8310), two(0xffc0, 0xe310), "T3&sQ8A9" },
+{"ptestr", two(0xf000, 0x8208), two(0xffc0, 0xe3f8), "D3&sQ8" },
+{"ptestr", two(0xf000, 0x8308), two(0xffc0, 0xe318), "D3&sQ8A9" },
+{"ptestr", two(0xf000, 0x8200), two(0xffc0, 0xe3fe), "f3&sQ8" },
+{"ptestr", two(0xf000, 0x8300), two(0xffc0, 0xe31e), "f3&sQ8A9" },
+
+{"ptestw", two(0xf000, 0x8010), two(0xffc0, 0xe3f0), "T3&sQ8" },
+{"ptestw", two(0xf000, 0x8110), two(0xffc0, 0xe310), "T3&sQ8A9" },
+{"ptestw", two(0xf000, 0x8008), two(0xffc0, 0xe3f8), "D3&sQ8" },
+{"ptestw", two(0xf000, 0x8108), two(0xffc0, 0xe318), "D3&sQ8A9" },
+{"ptestw", two(0xf000, 0x8000), two(0xffc0, 0xe3fe), "f3&sQ8" },
+{"ptestw", two(0xf000, 0x8100), two(0xffc0, 0xe31e), "f3&sQ8A9" },
+
+{"ptrapacw", two(0xf07a, 0x0007), two(0xffff, 0xffff), "#w"},
+{"ptrapacl", two(0xf07b, 0x0007), two(0xffff, 0xffff), "#l"},
+{"ptrapac", two(0xf07c, 0x0007), two(0xffff, 0xffff), ""},
+
+{"ptrapasw", two(0xf07a, 0x0006), two(0xffff, 0xffff), "#w"},
+{"ptrapasl", two(0xf07b, 0x0006), two(0xffff, 0xffff), "#l"},
+{"ptrapas", two(0xf07c, 0x0006), two(0xffff, 0xffff), ""},
+
+{"ptrapbcw", two(0xf07a, 0x0001), two(0xffff, 0xffff), "#w"},
+{"ptrapbcl", two(0xf07b, 0x0001), two(0xffff, 0xffff), "#l"},
+{"ptrapbc", two(0xf07c, 0x0001), two(0xffff, 0xffff), ""},
+
+{"ptrapbsw", two(0xf07a, 0x0000), two(0xffff, 0xffff), "#w"},
+{"ptrapbsl", two(0xf07b, 0x0000), two(0xffff, 0xffff), "#l"},
+{"ptrapbs", two(0xf07c, 0x0000), two(0xffff, 0xffff), ""},
+
+{"ptrapccw", two(0xf07a, 0x000f), two(0xffff, 0xffff), "#w"},
+{"ptrapccl", two(0xf07b, 0x000f), two(0xffff, 0xffff), "#l"},
+{"ptrapcc", two(0xf07c, 0x000f), two(0xffff, 0xffff), ""},
+
+{"ptrapcsw", two(0xf07a, 0x000e), two(0xffff, 0xffff), "#w"},
+{"ptrapcsl", two(0xf07b, 0x000e), two(0xffff, 0xffff), "#l"},
+{"ptrapcs", two(0xf07c, 0x000e), two(0xffff, 0xffff), ""},
+
+{"ptrapgcw", two(0xf07a, 0x000d), two(0xffff, 0xffff), "#w"},
+{"ptrapgcl", two(0xf07b, 0x000d), two(0xffff, 0xffff), "#l"},
+{"ptrapgc", two(0xf07c, 0x000d), two(0xffff, 0xffff), ""},
+
+{"ptrapgsw", two(0xf07a, 0x000c), two(0xffff, 0xffff), "#w"},
+{"ptrapgsl", two(0xf07b, 0x000c), two(0xffff, 0xffff), "#l"},
+{"ptrapgs", two(0xf07c, 0x000c), two(0xffff, 0xffff), ""},
+
+{"ptrapicw", two(0xf07a, 0x000b), two(0xffff, 0xffff), "#w"},
+{"ptrapicl", two(0xf07b, 0x000b), two(0xffff, 0xffff), "#l"},
+{"ptrapic", two(0xf07c, 0x000b), two(0xffff, 0xffff), ""},
+
+{"ptrapisw", two(0xf07a, 0x000a), two(0xffff, 0xffff), "#w"},
+{"ptrapisl", two(0xf07b, 0x000a), two(0xffff, 0xffff), "#l"},
+{"ptrapis", two(0xf07c, 0x000a), two(0xffff, 0xffff), ""},
+
+{"ptraplcw", two(0xf07a, 0x0003), two(0xffff, 0xffff), "#w"},
+{"ptraplcl", two(0xf07b, 0x0003), two(0xffff, 0xffff), "#l"},
+{"ptraplc", two(0xf07c, 0x0003), two(0xffff, 0xffff), ""},
+
+{"ptraplsw", two(0xf07a, 0x0002), two(0xffff, 0xffff), "#w"},
+{"ptraplsl", two(0xf07b, 0x0002), two(0xffff, 0xffff), "#l"},
+{"ptrapls", two(0xf07c, 0x0002), two(0xffff, 0xffff), ""},
+
+{"ptrapscw", two(0xf07a, 0x0005), two(0xffff, 0xffff), "#w"},
+{"ptrapscl", two(0xf07b, 0x0005), two(0xffff, 0xffff), "#l"},
+{"ptrapsc", two(0xf07c, 0x0005), two(0xffff, 0xffff), ""},
+
+{"ptrapssw", two(0xf07a, 0x0004), two(0xffff, 0xffff), "#w"},
+{"ptrapssl", two(0xf07b, 0x0004), two(0xffff, 0xffff), "#l"},
+{"ptrapss", two(0xf07c, 0x0004), two(0xffff, 0xffff), ""},
+
+{"ptrapwcw", two(0xf07a, 0x0009), two(0xffff, 0xffff), "#w"},
+{"ptrapwcl", two(0xf07b, 0x0009), two(0xffff, 0xffff), "#l"},
+{"ptrapwc", two(0xf07c, 0x0009), two(0xffff, 0xffff), ""},
+
+{"ptrapwsw", two(0xf07a, 0x0008), two(0xffff, 0xffff), "#w"},
+{"ptrapwsl", two(0xf07b, 0x0008), two(0xffff, 0xffff), "#l"},
+{"ptrapws", two(0xf07c, 0x0008), two(0xffff, 0xffff), ""},
+
+{"pvalid", two(0xf000, 0x2800), two(0xffc0, 0xffff), "Vs&s"},
+{"pvalid", two(0xf000, 0x2c00), two(0xffc0, 0xfff8), "A3&s" },
+
+#endif /* m68851 */
+
+/* end of tc-m68851.h */
diff --git a/gnu/usr.bin/as/config/tc-m68k.c b/gnu/usr.bin/as/config/tc-m68k.c
new file mode 100644
index 0000000..2872103
--- /dev/null
+++ b/gnu/usr.bin/as/config/tc-m68k.c
@@ -0,0 +1,4084 @@
+/* tc-m68k.c All the m68020 specific stuff in one convenient, huge,
+ slow to compile, easy to find file.
+
+ Copyright (C) 1987, 1991, 1992 Free Software Foundation, Inc.
+
+ This file is part of GAS, the GNU Assembler.
+
+ GAS is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GAS is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GAS; see the file COPYING. If not, write to
+ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <ctype.h>
+
+#include "as.h"
+
+#include "obstack.h"
+
+/* note that this file includes real declarations and thus can only be included by one source file per executable. */
+#include "opcode/m68k.h"
+#ifdef TE_SUN
+/* This variable contains the value to write out at the beginning of
+ the a.out file. The 2<<16 means that this is a 68020 file instead
+ of an old-style 68000 file */
+
+long omagic = 2<<16|OMAGIC; /* Magic byte for header file */
+#else
+long omagic = OMAGIC;
+#endif
+
+/* This array holds the chars that always start a comment. If the
+ pre-processor is disabled, these aren't very useful */
+const char comment_chars[] = "|";
+
+/* This array holds the chars that only start a comment at the beginning of
+ a line. If the line seems to have the form '# 123 filename'
+ .line and .file directives will appear in the pre-processed output */
+/* Note that input_file.c hand checks for '#' at the beginning of the
+ first line of the input file. This is because the compiler outputs
+ #NO_APP at the beginning of its output. */
+/* Also note that comments like this one will always work. */
+const char line_comment_chars[] = "#";
+
+/* Chars that can be used to separate mant from exp in floating point nums */
+const char EXP_CHARS[] = "eE";
+
+/* Chars that mean this number is a floating point constant */
+/* As in 0f12.456 */
+/* or 0d1.2345e12 */
+
+const char FLT_CHARS[] = "rRsSfFdDxXeEpP";
+
+/* Also be aware that MAXIMUM_NUMBER_OF_CHARS_FOR_FLOAT may have to be
+ changed in read.c. Ideally it shouldn't have to know about it at all,
+ but nothing is ideal around here.
+ */
+
+int md_reloc_size = 8; /* Size of relocation record */
+
+/* Its an arbitrary name: This means I don't approve of it */
+/* See flames below */
+static struct obstack robyn;
+
+#define TAB(x,y) (((x)<<2)+(y))
+#define TABTYPE(xy) ((xy) >> 2)
+#define BYTE 0
+#define SHORT 1
+#define LONG 2
+#define SZ_UNDEF 3
+
+#define BRANCH 1
+#define FBRANCH 2
+#define PCREL 3
+#define BCC68000 4
+#define DBCC 5
+#define PCLEA 6
+
+/* Operands we can parse: (And associated modes)
+
+ numb: 8 bit num
+ numw: 16 bit num
+ numl: 32 bit num
+ dreg: data reg 0-7
+ reg: address or data register
+ areg: address register
+ apc: address register, PC, ZPC or empty string
+ num: 16 or 32 bit num
+ num2: like num
+ sz: w or l if omitted, l assumed
+ scale: 1 2 4 or 8 if omitted, 1 assumed
+
+ 7.4 IMMED #num --> NUM
+ 0.? DREG dreg --> dreg
+ 1.? AREG areg --> areg
+ 2.? AINDR areg@ --> *(areg)
+ 3.? AINC areg@+ --> *(areg++)
+ 4.? ADEC areg@- --> *(--areg)
+ 5.? AOFF apc@(numw) --> *(apc+numw) -- empty string and ZPC not allowed here
+ 6.? AINDX apc@(num,reg:sz:scale) --> *(apc+num+reg*scale)
+ 6.? AINDX apc@(reg:sz:scale) --> same, with num=0
+ 6.? APODX apc@(num)@(num2,reg:sz:scale) --> *(*(apc+num)+num2+reg*scale)
+ 6.? APODX apc@(num)@(reg:sz:scale) --> same, with num2=0
+ 6.? AMIND apc@(num)@(num2) --> *(*(apc+num)+num2) (previous mode without an index reg)
+ 6.? APRDX apc@(num,reg:sz:scale)@(num2) --> *(*(apc+num+reg*scale)+num2)
+ 6.? APRDX apc@(reg:sz:scale)@(num2) --> same, with num=0
+ 7.0 ABSL num:sz --> *(num)
+ num --> *(num) (sz L assumed)
+ *** MSCR otherreg --> Magic
+ With -l option
+ 5.? AOFF apc@(num) --> *(apc+num) -- empty string and ZPC not allowed here still
+
+ examples:
+ #foo #0x35 #12
+ d2
+ a4
+ a3@
+ a5@+
+ a6@-
+ a2@(12) pc@(14)
+ a1@(5,d2:w:1) @(45,d6:l:4)
+ pc@(a2) @(d4)
+ etc...
+
+
+ #name@(numw) -->turn into PC rel mode
+ apc@(num8,reg:sz:scale) --> *(apc+num8+reg*scale)
+
+ */
+
+enum operand_type {
+ IMMED = 1,
+ DREG,
+ AREG,
+ AINDR,
+ ADEC,
+ AINC,
+ AOFF,
+ AINDX,
+ APODX,
+ AMIND,
+ APRDX,
+ ABSL,
+ MSCR,
+ REGLST,
+};
+
+
+struct m68k_exp {
+ char *e_beg;
+ char *e_end;
+ expressionS e_exp;
+ short e_siz; /* 0 == default 1 == short/byte 2 == word 3 == long */
+};
+
+/* DATA and ADDR have to be contiguous, so that reg-DATA gives 0-7 == data reg,
+ 8-15 == addr reg for operands that take both types */
+
+enum _register {
+ DATA = 1, /* 1- 8 == data registers 0-7 */
+ DATA0 = DATA,
+ DATA1,
+ DATA2,
+ DATA3,
+ DATA4,
+ DATA5,
+ DATA6,
+ DATA7,
+
+ ADDR,
+ ADDR0 = ADDR,
+ ADDR1,
+ ADDR2,
+ ADDR3,
+ ADDR4,
+ ADDR5,
+ ADDR6,
+ ADDR7,
+
+ /* Note that COPNUM == processor #1 -- COPNUM+7 == #8, which stores as 000 */
+ /* I think... */
+
+ SP = ADDR7,
+
+ FPREG, /* Eight FP registers */
+ FP0 = FPREG,
+ FP1,
+ FP2,
+ FP3,
+ FP4,
+ FP5,
+ FP6,
+ FP7,
+ COPNUM = (FPREG+8), /* Co-processor #1-#8 */
+ COP0 = COPNUM,
+ COP1,
+ COP2,
+ COP3,
+ COP4,
+ COP5,
+ COP6,
+ COP7,
+ PC, /* Program counter */
+ ZPC, /* Hack for Program space, but 0 addressing */
+ SR, /* Status Reg */
+ CCR, /* Condition code Reg */
+
+ /* These have to be in order for the movec instruction to work. */
+ USP, /* User Stack Pointer */
+ ISP, /* Interrupt stack pointer */
+ SFC,
+ DFC,
+ CACR,
+ VBR,
+ CAAR,
+ MSP,
+ ITT0,
+ ITT1,
+ DTT0,
+ DTT1,
+ MMUSR,
+ TC,
+ SRP,
+ URP,
+ /* end of movec ordering constraints */
+
+ FPI,
+ FPS,
+ FPC,
+
+ DRP,
+ CRP,
+ CAL,
+ VAL,
+ SCC,
+ AC,
+ BAD,
+ BAD0 = BAD,
+ BAD1,
+ BAD2,
+ BAD3,
+ BAD4,
+ BAD5,
+ BAD6,
+ BAD7,
+ BAC,
+ BAC0 = BAC,
+ BAC1,
+ BAC2,
+ BAC3,
+ BAC4,
+ BAC5,
+ BAC6,
+ BAC7,
+ PSR,
+ PCSR,
+
+ IC, /* instruction cache token */
+ DC, /* data cache token */
+ NC, /* no cache token */
+ BC, /* both caches token */
+
+};
+
+/* Internal form of an operand. */
+struct m68k_op {
+ char *error; /* Couldn't parse it */
+ enum operand_type mode; /* What mode this instruction is in. */
+ enum _register reg; /* Base register */
+ struct m68k_exp *con1;
+ int ireg; /* Index register */
+ int isiz; /* 0 == unspec 1 == byte(?) 2 == short 3 == long */
+ int imul; /* Multipy ireg by this (1,2,4,or 8) */
+ struct m68k_exp *con2;
+};
+
+/* internal form of a 68020 instruction */
+struct m68k_it {
+ char *error;
+ char *args; /* list of opcode info */
+ int numargs;
+
+ int numo; /* Number of shorts in opcode */
+ short opcode[11];
+
+ struct m68k_op operands[6];
+
+ int nexp; /* number of exprs in use */
+ struct m68k_exp exprs[4];
+
+ int nfrag; /* Number of frags we have to produce */
+ struct {
+ int fragoff; /* Where in the current opcode[] the frag ends */
+ symbolS *fadd;
+ long foff;
+ int fragty;
+ } fragb[4];
+
+ int nrel; /* Num of reloc strucs in use */
+ struct {
+ int n;
+ symbolS *add,
+ *sub,
+ *got;
+ long off;
+ char wid;
+ char pcrel;
+ enum reloc_type rtype;
+ } reloc[5]; /* Five is enough??? */
+};
+
+#define cpu_of_arch(x) ((x) & m68000up)
+#define float_of_arch(x) ((x) & mfloat)
+#define mmu_of_arch(x) ((x) & mmmu)
+
+static struct m68k_it the_ins; /* the instruction being assembled */
+
+/* Macros for adding things to the m68k_it struct */
+
+#define addword(w) the_ins.opcode[the_ins.numo++]=(w)
+
+/* Like addword, but goes BEFORE general operands */
+#define insop(w) { \
+ int z; \
+ for (z=the_ins.numo;z>opcode->m_codenum;--z) \
+ the_ins.opcode[z]=the_ins.opcode[z-1]; \
+ for (z=0;z<the_ins.nrel;z++) \
+ the_ins.reloc[z].n+=2; \
+ the_ins.opcode[opcode->m_codenum]=w; \
+ the_ins.numo++; \
+ }
+
+
+#define add_exp(beg,end) (the_ins.exprs[the_ins.nexp].e_beg=beg, \
+ the_ins.exprs[the_ins.nexp].e_end=end, \
+ &the_ins.exprs[the_ins.nexp++] \
+ )
+
+
+/* The numo+1 kludge is so we can hit the low order byte of the prev word. Blecch*/
+#define add_fix(width, exp, pc_rel, r_type) { \
+ the_ins.reloc[the_ins.nrel].n= ((width) == 'B') ? (the_ins.numo*2-1) : \
+ (((width) == 'b') ? ((the_ins.numo-1)*2) : (the_ins.numo*2)); \
+ the_ins.reloc[the_ins.nrel].add=adds((exp)); \
+ the_ins.reloc[the_ins.nrel].sub=subs((exp)); \
+ the_ins.reloc[the_ins.nrel].off=offs((exp)); \
+ the_ins.reloc[the_ins.nrel].got=gots((exp)); \
+ the_ins.reloc[the_ins.nrel].wid=width; \
+ the_ins.reloc[the_ins.nrel].pcrel=pc_rel; \
+ the_ins.reloc[the_ins.nrel++].rtype=r_type; \
+ }
+
+#define add_frag(add,off,type) {\
+ the_ins.fragb[the_ins.nfrag].fragoff=the_ins.numo;\
+ the_ins.fragb[the_ins.nfrag].fadd=add;\
+ the_ins.fragb[the_ins.nfrag].foff=off;\
+ the_ins.fragb[the_ins.nfrag++].fragty=type;\
+ }
+
+#define isvar(exp) ((exp) && (adds(exp) || subs(exp) || gots(exp)))
+
+#define seg(exp) ((exp)->e_exp.X_seg)
+#define adds(exp) ((exp)->e_exp.X_add_symbol)
+#define subs(exp) ((exp)->e_exp.X_subtract_symbol)
+#define offs(exp) ((exp)->e_exp.X_add_number)
+#define gots(exp) ((exp)->e_exp.X_got_symbol)
+
+
+struct m68k_incant {
+ char *m_operands;
+ unsigned long m_opcode;
+ short m_opnum;
+ short m_codenum;
+ enum m68k_architecture m_arch;
+ struct m68k_incant *m_next;
+};
+
+#define getone(x) ((((x)->m_opcode)>>16)&0xffff)
+#define gettwo(x) (((x)->m_opcode)&0xffff)
+
+
+#if __STDC__ == 1
+
+static char *crack_operand(char *str, struct m68k_op *opP);
+static int get_num(struct m68k_exp *exp, int ok);
+static int get_regs(int i, char *str, struct m68k_op *opP);
+static int reverse_16_bits(int in);
+static int reverse_8_bits(int in);
+static int try_index(char **s, struct m68k_op *opP);
+static void install_gen_operand(int mode, int val);
+static void install_operand(int mode, int val);
+static void s_bss(void);
+static void s_data1(void);
+static void s_data2(void);
+static void s_even(void);
+static void s_proc(void);
+
+#else /* not __STDC__ */
+
+static char *crack_operand();
+static int get_num();
+static int get_regs();
+static int reverse_16_bits();
+static int reverse_8_bits();
+static int try_index();
+static void install_gen_operand();
+static void install_operand();
+static void s_bss();
+static void s_data1();
+static void s_data2();
+static void s_even();
+static void s_proc();
+
+#endif /* not __STDC__ */
+
+static enum m68k_architecture current_architecture = 0;
+
+/* BCC68000 is for patching in an extra jmp instruction for long offsets
+ on the 68000. The 68000 doesn't support long branches with branchs */
+
+/* This table desribes how you change sizes for the various types of variable
+ size expressions. This version only supports two kinds. */
+
+/* Note that calls to frag_var need to specify the maximum expansion needed */
+/* This is currently 10 bytes for DBCC */
+
+/* The fields are:
+ How far Forward this mode will reach:
+ How far Backward this mode will reach:
+ How many bytes this mode will add to the size of the frag
+ Which mode to go to if the offset won't fit in this one
+ */
+const relax_typeS
+ md_relax_table[] = {
+ { 1, 1, 0, 0 }, /* First entries aren't used */
+ { 1, 1, 0, 0 }, /* For no good reason except */
+ { 1, 1, 0, 0 }, /* that the VAX doesn't either */
+ { 1, 1, 0, 0 },
+
+ { (127), (-128), 0, TAB(BRANCH,SHORT)},
+ { (32767), (-32768), 2, TAB(BRANCH,LONG) },
+ { 0, 0, 4, 0 },
+ { 1, 1, 0, 0 },
+
+ { 1, 1, 0, 0 }, /* FBRANCH doesn't come BYTE */
+ { (32767), (-32768), 2, TAB(FBRANCH,LONG)},
+ { 0, 0, 4, 0 },
+ { 1, 1, 0, 0 },
+
+ { 1, 1, 0, 0 }, /* PCREL doesn't come BYTE */
+ { (32767), (-32768), 2, TAB(PCREL,LONG)},
+ { 0, 0, 4, 0 },
+ { 1, 1, 0, 0 },
+
+ { (127), (-128), 0, TAB(BCC68000,SHORT)},
+ { (32767), (-32768), 2, TAB(BCC68000,LONG) },
+ { 0, 0, 6, 0 }, /* jmp long space */
+ { 1, 1, 0, 0 },
+
+ { 1, 1, 0, 0 }, /* DBCC doesn't come BYTE */
+ { (32767), (-32768), 2, TAB(DBCC,LONG) },
+ { 0, 0, 10, 0 }, /* bra/jmp long space */
+ { 1, 1, 0, 0 },
+
+ { 1, 1, 0, 0 }, /* PCLEA doesn't come BYTE */
+ { 32767, -32768, 2, TAB(PCLEA,LONG) },
+ { 0, 0, 6, 0 },
+ { 1, 1, 0, 0 },
+
+ };
+
+/* These are the machine dependent pseudo-ops. These are included so
+ the assembler can work on the output from the SUN C compiler, which
+ generates these.
+ */
+
+/* This table describes all the machine specific pseudo-ops the assembler
+ has to support. The fields are:
+ pseudo-op name without dot
+ function to call to execute this pseudo-op
+ Integer arg to pass to the function
+ */
+const pseudo_typeS md_pseudo_table[] = {
+ { "data1", s_data1, 0 },
+ { "data2", s_data2, 0 },
+ { "bss", s_bss, 0 },
+ { "even", s_even, 0 },
+ { "skip", s_space, 0 },
+ { "proc", s_proc, 0 },
+ { 0, 0, 0 }
+};
+
+
+/* #define isbyte(x) ((x) >= -128 && (x) <= 127) */
+/* #define isword(x) ((x) >= -32768 && (x) <= 32767) */
+
+#define issbyte(x) ((x) >= -128 && (x) <= 127)
+#define isubyte(x) ((x) >= 0 && (x) <= 255)
+#define issword(x) ((x) >= -32768 && (x) <= 32767)
+#define isuword(x) ((x) >= 0 && (x) <= 65535)
+
+#define isbyte(x) ((x) >= -128 && (x) <= 255)
+#define isword(x) ((x) >= -32768 && (x) <= 65535)
+#define islong(x) (1)
+
+extern char *input_line_pointer;
+
+enum {
+ FAIL = 0,
+ OK = 1,
+};
+
+/* JF these tables here are for speed at the expense of size */
+/* You can replace them with the #if 0 versions if you really
+ need space and don't mind it running a bit slower */
+
+static char mklower_table[256];
+#define mklower(c) (mklower_table[(unsigned char)(c)])
+static char notend_table[256];
+static char alt_notend_table[256];
+#define notend(s) (!(notend_table[(unsigned char)(*s)] || (*s == ':' &&\
+ alt_notend_table[(unsigned char)(s[1])])))
+
+#if 0
+#define mklower(c) (isupper(c) ? tolower(c) : c)
+#endif
+
+/* Handle the extra arg for fix_new when doing PIC */
+#ifdef PIC
+#define FIX_NO_RELOC NO_RELOC, NULL
+#else
+#define FIX_NO_RELOC NO_RELOC
+#endif /* PIC */
+
+
+/* JF modified this to handle cases where the first part of a symbol name
+ looks like a register */
+
+/*
+ * m68k_reg_parse() := if it looks like a register, return it's token &
+ * advance the pointer.
+ */
+
+enum _register m68k_reg_parse(ccp)
+register char **ccp;
+{
+#ifndef MAX_REG_NAME_LEN
+#define MAX_REG_NAME_LEN (6)
+#endif /* MAX_REG_NAME_LEN */
+ register char c[MAX_REG_NAME_LEN];
+ char *p, *q;
+ register int n = 0,
+ ret = FAIL;
+
+ c[0] = mklower(ccp[0][0]);
+#ifdef REGISTER_PREFIX
+ if (c[0] != REGISTER_PREFIX) {
+ return(FAIL);
+ } /* need prefix */
+#endif
+
+ for (p = c, q = ccp[0]; p < c + MAX_REG_NAME_LEN; ++p, ++q)
+ {
+ if (*q == 0)
+ {
+ *p = 0;
+ break;
+ }
+ else
+ *p = mklower(*q);
+ } /* downcase */
+
+ switch (c[0]) {
+ case 'a':
+ if (c[1] >= '0' && c[1] <= '7') {
+ n=2;
+ ret=ADDR+c[1]-'0';
+ }
+#ifndef NO_68851
+ else if (c[1] == 'c') {
+ n = 2;
+ ret = AC;
+ }
+#endif
+ break;
+#ifndef NO_68851
+ case 'b':
+ if (c[1] == 'a') {
+ if (c[2] == 'd') {
+ if (c[3] >= '0' && c[3] <= '7') {
+ n = 4;
+ ret = BAD + c[3] - '0';
+ }
+ } /* BAD */
+ if (c[2] == 'c') {
+ if (c[3] >= '0' && c[3] <= '7') {
+ n = 4;
+ ret = BAC + c[3] - '0';
+ }
+ } /* BAC */
+ } else if (c[1] == 'c') {
+ n = 2;
+ ret = BC;
+ } /* BC */
+ break;
+#endif
+ case 'c':
+#ifndef NO_68851
+ if (c[1] == 'a' && c[2] == 'l') {
+ n = 3;
+ ret = CAL;
+ } else
+#endif
+ /* This supports both CCR and CC as the ccr reg. */
+ if (c[1] == 'c' && c[2] == 'r') {
+ n=3;
+ ret = CCR;
+ } else if (c[1] == 'c') {
+ n=2;
+ ret = CCR;
+ } else if (c[1] == 'a' && (c[2] == 'a' || c[2] == 'c') && c[3] == 'r') {
+ n=4;
+ ret = c[2] == 'a' ? CAAR : CACR;
+ }
+#ifndef NO_68851
+ else if (c[1] == 'r' && c[2] == 'p') {
+ n = 3;
+ ret = (CRP);
+ }
+#endif
+ break;
+ case 'd':
+ if (c[1] >= '0' && c[1] <= '7') {
+ n = 2;
+ ret = DATA + c[1] - '0';
+ } else if (c[1] == 'f' && c[2] == 'c') {
+ n = 3;
+ ret = DFC;
+ } else if (c[1] == 'c') {
+ n = 2;
+ ret = DC;
+ } else if (c[1] == 't' && c[2] == 't') {
+ if ('0' <= c[3] && c[3] <= '1') {
+ n = 4;
+ ret = DTT0 + (c[3] - '0');
+ } /* DTT[01] */
+ }
+#ifndef NO_68851
+ else if (c[1] == 'r' && c[2] == 'p') {
+ n = 3;
+ ret = (DRP);
+ }
+#endif
+ break;
+ case 'f':
+ if (c[1] == 'p') {
+ if (c[2] >= '0' && c[2] <= '7') {
+ n=3;
+ ret = FPREG+c[2]-'0';
+ if (c[3] == ':')
+ ccp[0][3]=',';
+ } else if (c[2] == 'i') {
+ n=3;
+ ret = FPI;
+ } else if (c[2] == 's') {
+ n= (c[3] == 'r' ? 4 : 3);
+ ret = FPS;
+ } else if (c[2] == 'c') {
+ n= (c[3] == 'r' ? 4 : 3);
+ ret = FPC;
+ }
+ }
+ break;
+ case 'i':
+ if (c[1] == 's' && c[2] == 'p') {
+ n = 3;
+ ret = ISP;
+ } else if (c[1] == 'c') {
+ n = 2;
+ ret = IC;
+ } else if (c[1] == 't' && c[2] == 't') {
+ if ('0' <= c[3] && c[3] <= '1') {
+ n = 4;
+ ret = ITT0 + (c[3] - '0');
+ } /* ITT[01] */
+ }
+ break;
+ case 'm':
+ if (c[1] == 's' && c[2] == 'p') {
+ n = 3;
+ ret = MSP;
+ } else if (c[1] == 'm' && c[2] == 'u' && c[3] == 's' && c[4] == 'r') {
+ n = 5;
+ ret = MMUSR;
+ }
+ break;
+ case 'n':
+ if (c[1] == 'c') {
+ n = 2;
+ ret = NC;
+ }
+ break;
+ case 'p':
+ if (c[1] == 'c') {
+#ifndef NO_68851
+ if (c[2] == 's' && c[3] == 'r') {
+ n=4;
+ ret = (PCSR);
+ } else
+#endif
+ {
+ n=2;
+ ret = PC;
+ }
+ }
+#ifndef NO_68851
+ else if (c[1] == 's' && c[2] == 'r') {
+ n = 3;
+ ret = (PSR);
+ }
+#endif
+ break;
+ case 's':
+#ifndef NO_68851
+ if (c[1] == 'c' && c[2] == 'c') {
+ n = 3;
+ ret = (SCC);
+ } else
+#endif
+ if (c[1] == 'r') {
+ if (c[2] == 'p') {
+ n = 3;
+ ret = SRP;
+ } else {
+ n = 2;
+ ret = SR;
+ } /* srp else sr */
+ } else if (c[1] == 'p') {
+ n = 2;
+ ret = SP;
+ } else if (c[1] == 'f' && c[2] == 'c') {
+ n = 3;
+ ret = SFC;
+ }
+ break;
+ case 't':
+ if (c[1] == 'c') {
+ n = 2;
+ ret = TC;
+ }
+ break;
+ case 'u':
+ if (c[1] == 's' && c[2] == 'p') {
+ n=3;
+ ret = USP;
+ } else if (c[1] == 'r' && c[2] == 'p') {
+ n = 3;
+ ret = URP;
+ }
+ break;
+ case 'v':
+#ifndef NO_68851
+ if (c[1] == 'a' && c[2] == 'l') {
+ n = 3;
+ ret = (VAL);
+ } else
+#endif
+ if (c[1] == 'b' && c[2] == 'r') {
+ n=3;
+ ret = VBR;
+ }
+ break;
+ case 'z':
+ if (c[1] == 'p' && c[2] == 'c') {
+ n=3;
+ ret = ZPC;
+ }
+ break;
+ default:
+ break;
+ }
+ if (n) {
+#ifdef REGISTER_PREFIX
+ n++;
+#endif
+ if (isalnum(ccp[0][n]) || ccp[0][n] == '_')
+ ret=FAIL;
+ else
+ ccp[0]+=n;
+ } else
+ ret = FAIL;
+ return ret;
+}
+
+#define SKIP_WHITE() { str++; if (*str == ' ') str++;}
+
+/*
+ * m68k_ip_op := '#' + <anything>
+ * | <register> + range_sep + get_regs
+ * ;
+ *
+ * range_sep := '/' | '-' ;
+ *
+ * SKIP_WHITE := <empty> | ' ' ;
+ *
+ */
+
+int
+ m68k_ip_op(str,opP)
+char *str;
+register struct m68k_op *opP;
+{
+ char *strend;
+ long i;
+ char *parse_index();
+
+ if (*str == ' ') {
+ str++;
+ } /* Find the beginning of the string */
+
+ if (!*str) {
+ opP->error="Missing operand";
+ return FAIL;
+ } /* Out of gas */
+
+ for (strend = str; *strend; strend++) ;;
+
+ --strend;
+
+ if (*str == '#') {
+ str++;
+ opP->con1=add_exp(str,strend);
+ opP->mode=IMMED;
+ return OK;
+ } /* Guess what: A constant. Shar and enjoy */
+
+ i = m68k_reg_parse(&str);
+
+ /* is a register, is exactly a register, and is followed by '@' */
+
+ if ((i == FAIL || *str != '\0') && *str != '@') {
+ char *stmp;
+
+ if (i != FAIL && (*str == '/' || *str == '-')) {
+ opP->mode=REGLST;
+ return(get_regs(i,str,opP));
+ }
+ if ((stmp=strchr(str,'@')) != '\0') {
+ opP->con1=add_exp(str,stmp-1);
+ if (stmp == strend) {
+ opP->mode=AINDX;
+ return(OK);
+ }
+
+ if ((current_architecture & m68020up) == 0) {
+ return(FAIL);
+ } /* if target is not a '20 or better */
+
+ stmp++;
+ if (*stmp++ != '(' || *strend-- != ')') {
+ opP->error="Malformed operand";
+ return(FAIL);
+ }
+ i=try_index(&stmp,opP);
+ opP->con2=add_exp(stmp,strend);
+
+ if (i == FAIL) {
+ opP->mode=AMIND;
+ } else {
+ opP->mode=APODX;
+ }
+ return(OK);
+ } /* if there's an '@' */
+ opP->mode = ABSL;
+ opP->con1 = add_exp(str,strend);
+ return(OK);
+ } /* not a register, not exactly a register, or no '@' */
+
+ opP->reg=i;
+
+ if (*str == '\0') {
+ if (i >= DATA+0 && i <= DATA+7)
+ opP->mode=DREG;
+ else if (i >= ADDR+0 && i <= ADDR+7)
+ opP->mode=AREG;
+ else
+ opP->mode=MSCR;
+ return OK;
+ }
+
+ if ((i<ADDR+0 || i>ADDR+7) && i != PC && i != ZPC && i != FAIL) { /* Can't indirect off non address regs */
+ opP->error="Invalid indirect register";
+ return FAIL;
+ }
+ know(*str == '@');
+
+ str++;
+ switch (*str) {
+ case '\0':
+ opP->mode=AINDR;
+ return OK;
+ case '-':
+ opP->mode=ADEC;
+ return OK;
+ case '+':
+ opP->mode=AINC;
+ return OK;
+ case '(':
+ str++;
+ break;
+ default:
+ opP->error="Junk after indirect";
+ return FAIL;
+ }
+ /* Some kind of indexing involved. Lets find out how bad it is */
+ i=try_index(&str,opP);
+ /* Didn't start with an index reg, maybe its offset or offset,reg */
+ if (i == FAIL) {
+ char *beg_str;
+
+ beg_str=str;
+ for (i=1;i;) {
+ switch (*str++) {
+ case '\0':
+ opP->error="Missing )";
+ return FAIL;
+ case ',': i=0; break;
+ case '(': i++; break;
+ case ')': --i; break;
+ }
+ }
+ /* if (str[-3] == ':') {
+ int siz;
+
+ switch (str[-2]) {
+ case 'b':
+ case 'B':
+ siz=1;
+ break;
+ case 'w':
+ case 'W':
+ siz=2;
+ break;
+ case 'l':
+ case 'L':
+ siz=3;
+ break;
+ default:
+ opP->error="Specified size isn't :w or :l";
+ return FAIL;
+ }
+ opP->con1=add_exp(beg_str,str-4);
+ opP->con1->e_siz=siz;
+ } else */
+ opP->con1=add_exp(beg_str,str-2);
+ /* Should be offset,reg */
+ if (str[-1] == ',') {
+ i=try_index(&str,opP);
+ if (i == FAIL) {
+ opP->error="Malformed index reg";
+ return FAIL;
+ }
+ }
+ }
+ /* We've now got offset) offset,reg) or reg) */
+
+ if (*str == '\0') {
+ /* Th-the-thats all folks */
+ if (opP->reg == FAIL) opP->mode = AINDX; /* Other form of indirect */
+ else if (opP->ireg == FAIL) opP->mode = AOFF;
+ else opP->mode = AINDX;
+ return(OK);
+ }
+ /* Next thing had better be another @ */
+ if (*str != '@' || str[1] != '(') {
+ opP->error = "junk after indirect";
+ return(FAIL);
+ }
+
+ if ((current_architecture & m68020up) == 0) {
+ return(FAIL);
+ } /* if target is not a '20 or better */
+
+ str+=2;
+
+ if (opP->ireg != FAIL) {
+ opP->mode = APRDX;
+
+ i = try_index(&str, opP);
+ if (i != FAIL) {
+ opP->error = "Two index registers! not allowed!";
+ return(FAIL);
+ }
+ } else {
+ i = try_index(&str, opP);
+ }
+
+ if (i == FAIL) {
+ char *beg_str;
+
+ beg_str = str;
+
+ for (i = 1; i; ) {
+ switch (*str++) {
+ case '\0':
+ opP->error="Missing )";
+ return(FAIL);
+ case ',': i=0; break;
+ case '(': i++; break;
+ case ')': --i; break;
+ }
+ }
+
+ opP->con2=add_exp(beg_str,str-2);
+
+ if (str[-1] == ',') {
+ if (opP->ireg != FAIL) {
+ opP->error = "Can't have two index regs";
+ return(FAIL);
+ }
+
+ i = try_index(&str, opP);
+
+ if (i == FAIL) {
+ opP->error = "malformed index reg";
+ return(FAIL);
+ }
+
+ opP->mode = APODX;
+ } else if (opP->ireg != FAIL) {
+ opP->mode = APRDX;
+ } else {
+ opP->mode = AMIND;
+ }
+ } else {
+ opP->mode = APODX;
+ }
+
+ if (*str != '\0') {
+ opP->error="Junk after indirect";
+ return FAIL;
+ }
+ return(OK);
+} /* m68k_ip_op() */
+
+/*
+ *
+ * try_index := data_or_address_register + ')' + SKIP_W
+ * | data_or_address_register + ':' + SKIP_W + size_spec + SKIP_W + multiplier + ')' + SKIP_W
+ *
+ * multiplier := <empty>
+ * | ':' + multiplier_number
+ * ;
+ *
+ * multiplier_number := '1' | '2' | '4' | '8' ;
+ *
+ * size_spec := 'l' | 'L' | 'w' | 'W' ;
+ *
+ * SKIP_W := <empty> | ' ' ;
+ *
+ */
+
+static int try_index(s,opP)
+char **s;
+struct m68k_op *opP;
+{
+ register int i;
+ char *ss;
+#define SKIP_W() { ss++; if (*ss == ' ') ss++;}
+
+ ss= *s;
+ /* SKIP_W(); */
+ i=m68k_reg_parse(&ss);
+ if (!(i >= DATA+0 && i <= ADDR+7)) { /* if i is not DATA or ADDR reg */
+ *s=ss;
+ return FAIL;
+ }
+ opP->ireg=i;
+ /* SKIP_W(); */
+ if (*ss == ')') {
+ opP->isiz=0;
+ opP->imul=1;
+ SKIP_W();
+ *s=ss;
+ return OK;
+ }
+ if (*ss != ':') {
+ opP->error="Missing : in index register";
+ *s=ss;
+ return FAIL;
+ }
+ SKIP_W();
+ switch (*ss) {
+ case 'w':
+ case 'W':
+ opP->isiz=2;
+ break;
+ case 'l':
+ case 'L':
+ opP->isiz=3;
+ break;
+ default:
+ opP->error="Index register size spec not :w or :l";
+ *s=ss;
+ return FAIL;
+ }
+ SKIP_W();
+ if (*ss == ':') {
+ SKIP_W();
+ switch (*ss) {
+ case '1':
+ case '2':
+ case '4':
+ case '8':
+ opP->imul= *ss-'0';
+ break;
+ default:
+ opP->error="index multiplier not 1, 2, 4 or 8";
+ *s=ss;
+ return FAIL;
+ }
+ SKIP_W();
+ } else opP->imul=1;
+ if (*ss != ')') {
+ opP->error="Missing )";
+ *s=ss;
+ return FAIL;
+ }
+ SKIP_W();
+ *s=ss;
+ return OK;
+} /* try_index() */
+
+#ifdef TEST1 /* TEST1 tests m68k_ip_op(), which parses operands */
+main()
+{
+ char buf[128];
+ struct m68k_op thark;
+
+ for (;;) {
+ if (!gets(buf))
+ break;
+ memset(&thark, '\0', sizeof(thark));
+ if (!m68k_ip_op(buf,&thark)) printf("FAIL:");
+ if (thark.error)
+ printf("op1 error %s in %s\n",thark.error,buf);
+ printf("mode %d, reg %d, ",thark.mode,thark.reg);
+ if (thark.b_const)
+ printf("Constant: '%.*s',",1+thark.e_const-thark.b_const,thark.b_const);
+ printf("ireg %d, isiz %d, imul %d ",thark.ireg,thark.isiz,thark.imul);
+ if (thark.b_iadd)
+ printf("Iadd: '%.*s'",1+thark.e_iadd-thark.b_iadd,thark.b_iadd);
+ printf("\n");
+ }
+ exit(0);
+}
+
+#endif
+
+
+static struct hash_control* op_hash = NULL; /* handle of the OPCODE hash table
+ NULL means any use before m68k_ip_begin()
+ will crash */
+
+
+/*
+ * m 6 8 k _ i p ( )
+ *
+ * This converts a string into a 68k instruction.
+ * The string must be a bare single instruction in sun format
+ * with RMS-style 68020 indirects
+ * (example: )
+ *
+ * It provides some error messages: at most one fatal error message (which
+ * stops the scan) and at most one warning message for each operand.
+ * The 68k instruction is returned in exploded form, since we have no
+ * knowledge of how you parse (or evaluate) your expressions.
+ * We do however strip off and decode addressing modes and operation
+ * mnemonic.
+ *
+ * This function's value is a string. If it is not "" then an internal
+ * logic error was found: read this code to assign meaning to the string.
+ * No argument string should generate such an error string:
+ * it means a bug in our code, not in the user's text.
+ *
+ * You MUST have called m68k_ip_begin() once and m86_ip_end() never before using
+ * this function.
+ */
+
+/* JF this function no longer returns a useful value. Sorry */
+void m68k_ip (instring)
+char *instring;
+{
+ register char *p;
+ register struct m68k_op *opP;
+ register struct m68k_incant *opcode;
+ register char *s;
+ register int tmpreg = 0,
+ baseo = 0,
+ outro = 0,
+ nextword;
+ int siz1,
+ siz2;
+ char c;
+ int losing;
+ int opsfound;
+ int reloc_type;
+ char *crack_operand();
+ LITTLENUM_TYPE words[6];
+ LITTLENUM_TYPE *wordp;
+
+ if (*instring == ' ')
+ instring++; /* skip leading whitespace */
+
+ /* Scan up to end of operation-code, which MUST end in end-of-string
+ or exactly 1 space. */
+ for (p = instring; *p != '\0'; p++)
+ if (*p == ' ')
+ break;
+
+
+ if (p == instring) {
+ the_ins.error = "No operator";
+ the_ins.opcode[0] = NULL;
+ /* the_ins.numo=1; */
+ return;
+ }
+
+ /* p now points to the end of the opcode name, probably whitespace.
+ make sure the name is null terminated by clobbering the whitespace,
+ look it up in the hash table, then fix it back. */
+ c = *p;
+ *p = '\0';
+ opcode = (struct m68k_incant *)hash_find (op_hash, instring);
+ *p = c;
+
+ if (opcode == NULL) {
+ the_ins.error = "Unknown operator";
+ the_ins.opcode[0] = NULL;
+ /* the_ins.numo=1; */
+ return;
+ }
+
+ /* found a legitimate opcode, start matching operands */
+ while (*p == ' ') ++p;
+
+ for (opP = &the_ins.operands[0]; *p; opP++) {
+
+ p = crack_operand(p, opP);
+
+ if (opP->error) {
+ the_ins.error=opP->error;
+ return;
+ }
+ }
+
+ opsfound = opP - &the_ins.operands[0];
+
+ /* This ugly hack is to support the floating pt opcodes in their standard form */
+ /* Essentially, we fake a first enty of type COP#1 */
+ if (opcode->m_operands[0] == 'I') {
+ int n;
+
+ for (n=opsfound;n>0;--n)
+ the_ins.operands[n]=the_ins.operands[n-1];
+
+ /* memcpy((char *)(&the_ins.operands[1]), (char *)(&the_ins.operands[0]), opsfound*sizeof(the_ins.operands[0])); */
+ memset((char *)(&the_ins.operands[0]), '\0', sizeof(the_ins.operands[0]));
+ the_ins.operands[0].mode=MSCR;
+ the_ins.operands[0].reg=COPNUM; /* COP #1 */
+ opsfound++;
+ }
+
+ /* We've got the operands. Find an opcode that'll accept them */
+ for (losing = 0; ; ) {
+ /* if we didn't get the right number of ops,
+ or we have no common model with this pattern
+ then reject this pattern. */
+
+ if (opsfound != opcode->m_opnum
+ || ((opcode->m_arch & current_architecture) == 0)) {
+
+ ++losing;
+
+ } else {
+ for (s=opcode->m_operands, opP = &the_ins.operands[0]; *s && !losing; s += 2, opP++) {
+ /* Warning: this switch is huge! */
+ /* I've tried to organize the cases into this order:
+ non-alpha first, then alpha by letter. lower-case goes directly
+ before uppercase counterpart. */
+ /* Code with multiple case ...: gets sorted by the lowest case ...
+ it belongs to. I hope this makes sense. */
+ switch (*s) {
+#ifdef PIC
+ case ' ':
+ /* this operand is just here to indicate a jump-table branch */
+ if (!flagseen['k'])
+ losing++;
+ break;
+#endif /* PIC */
+
+ case '!':
+ if (opP->mode == MSCR || opP->mode == IMMED
+ || opP->mode == DREG || opP->mode == AREG
+ || opP->mode == AINC || opP->mode == ADEC
+ || opP->mode == REGLST)
+ losing++;
+ break;
+
+ case '#':
+ if (opP->mode != IMMED)
+ losing++;
+ else {
+ long t;
+
+ t=get_num(opP->con1,80);
+ if (s[1] == 'b' && !isbyte(t))
+ losing++;
+ else if (s[1] == 'w' && !isword(t))
+ losing++;
+ }
+ break;
+
+ case '^':
+ case 'T':
+ if (opP->mode != IMMED)
+ losing++;
+ break;
+
+ case '$':
+ if (opP->mode == MSCR || opP->mode == AREG ||
+ opP->mode == IMMED || opP->reg == PC || opP->reg == ZPC || opP->mode == REGLST)
+ losing++;
+ break;
+
+ case '%':
+ if (opP->mode == MSCR || opP->reg == PC ||
+ opP->reg == ZPC || opP->mode == REGLST)
+ losing++;
+ break;
+
+
+ case '&':
+ if (opP->mode == MSCR || opP->mode == DREG ||
+ opP->mode == AREG || opP->mode == IMMED || opP->reg == PC || opP->reg == ZPC ||
+ opP->mode == AINC || opP->mode == ADEC || opP->mode == REGLST)
+ losing++;
+ break;
+
+ case '*':
+ if (opP->mode == MSCR || opP->mode == REGLST)
+ losing++;
+ break;
+
+ case '+':
+ if (opP->mode != AINC)
+ losing++;
+ break;
+
+ case '-':
+ if (opP->mode != ADEC)
+ losing++;
+ break;
+
+ case '/':
+ if (opP->mode == MSCR || opP->mode == AREG ||
+ opP->mode == AINC || opP->mode == ADEC || opP->mode == IMMED || opP->mode == REGLST)
+ losing++;
+ break;
+
+ case ';':
+ if (opP->mode == MSCR || opP->mode == AREG || opP->mode == REGLST)
+ losing++;
+ break;
+
+ case '?':
+ if (opP->mode == MSCR || opP->mode == AREG ||
+ opP->mode == AINC || opP->mode == ADEC || opP->mode == IMMED || opP->reg == PC ||
+ opP->reg == ZPC || opP->mode == REGLST)
+ losing++;
+ break;
+
+ case '@':
+ if (opP->mode == MSCR || opP->mode == AREG ||
+ opP->mode == IMMED || opP->mode == REGLST)
+ losing++;
+ break;
+
+ case '~': /* For now! (JF FOO is this right?) */
+ if (opP->mode == MSCR || opP->mode == DREG ||
+ opP->mode == AREG || opP->mode == IMMED || opP->reg == PC || opP->reg == ZPC || opP->mode == REGLST)
+ losing++;
+ break;
+
+ case 'A':
+ if (opP->mode != AREG)
+ losing++;
+ break;
+ case 'a':
+ if (opP->mode != AINDR) {
+ ++losing;
+ } /* if not address register indirect */
+ break;
+ case 'B': /* FOO */
+ if (opP->mode != ABSL || (flagseen['S'] && instring[0] == 'j'
+ && instring[1] == 'b'
+ && instring[2] == 's'
+ && instring[3] == 'r'))
+ losing++;
+ break;
+
+ case 'C':
+ if (opP->mode != MSCR || opP->reg != CCR)
+ losing++;
+ break;
+
+ case 'd': /* FOO This mode is a KLUDGE!! */
+ if (opP->mode != AOFF && (opP->mode != ABSL ||
+ opP->con1->e_beg[0] != '(' || opP->con1->e_end[0] != ')'))
+ losing++;
+ break;
+
+ case 'D':
+ if (opP->mode != DREG)
+ losing++;
+ break;
+
+ case 'F':
+ if (opP->mode != MSCR || opP->reg<(FPREG+0) || opP->reg>(FPREG+7))
+ losing++;
+ break;
+
+ case 'I':
+ if (opP->mode != MSCR || opP->reg<COPNUM ||
+ opP->reg >= COPNUM+7)
+ losing++;
+ break;
+
+ case 'J':
+ if (opP->mode != MSCR
+ || opP->reg < USP
+ || opP->reg > URP
+ || cpu_of_arch(current_architecture) < m68010 /* before 68010 had none */
+ || (cpu_of_arch(current_architecture) < m68020
+ && opP->reg != SFC
+ && opP->reg != DFC
+ && opP->reg != USP
+ && opP->reg != VBR) /* 68010's had only these */
+ || (cpu_of_arch(current_architecture) < m68040
+ && opP->reg != SFC
+ && opP->reg != DFC
+ && opP->reg != USP
+ && opP->reg != VBR
+ && opP->reg != CACR
+ && opP->reg != CAAR
+ && opP->reg != MSP
+ && opP->reg != ISP) /* 680[23]0's have only these */
+ || (cpu_of_arch(current_architecture) == m68040 /* 68040 has all but this */
+ && opP->reg == CAAR)) {
+ losing++;
+ } /* doesn't cut it */
+ break;
+
+ case 'k':
+ if (opP->mode != IMMED)
+ losing++;
+ break;
+
+ case 'l':
+ case 'L':
+ if (opP->mode == DREG || opP->mode == AREG || opP->mode == FPREG) {
+ if (s[1] == '8')
+ losing++;
+ else {
+ opP->mode=REGLST;
+ opP->reg=1<<(opP->reg-DATA);
+ }
+ } else if (opP->mode != REGLST) {
+ losing++;
+ } else if (s[1] == '8' && opP->reg&0x0FFffFF)
+ losing++;
+ else if (s[1] == '3' && opP->reg&0x7000000)
+ losing++;
+ break;
+
+ case 'M':
+ if (opP->mode != IMMED)
+ losing++;
+ else {
+ long t;
+
+ t=get_num(opP->con1,80);
+ if (!issbyte(t) || isvar(opP->con1))
+ losing++;
+ }
+ break;
+
+ case 'O':
+ if (opP->mode != DREG && opP->mode != IMMED)
+ losing++;
+ break;
+
+ case 'Q':
+ if (opP->mode != IMMED)
+ losing++;
+ else {
+ long t;
+
+ t=get_num(opP->con1,80);
+ if (t<1 || t>8 || isvar(opP->con1))
+ losing++;
+ }
+ break;
+
+ case 'R':
+ if (opP->mode != DREG && opP->mode != AREG)
+ losing++;
+ break;
+
+ case 's':
+ if (opP->mode != MSCR || !(opP->reg == FPI || opP->reg == FPS || opP->reg == FPC))
+ losing++;
+ break;
+
+ case 'S':
+ if (opP->mode != MSCR || opP->reg != SR)
+ losing++;
+ break;
+
+ case 'U':
+ if (opP->mode != MSCR || opP->reg != USP)
+ losing++;
+ break;
+
+ /* JF these are out of order. We could put them
+ in order if we were willing to put up with
+ bunches of #ifdef m68851s in the code */
+#ifndef NO_68851
+ /* Memory addressing mode used by pflushr */
+ case '|':
+ if (opP->mode == MSCR || opP->mode == DREG ||
+ opP->mode == AREG || opP->mode == REGLST)
+ losing++;
+ break;
+
+ case 'f':
+ if (opP->mode != MSCR || (opP->reg != SFC && opP->reg != DFC))
+ losing++;
+ break;
+
+ case 'P':
+ if (opP->mode != MSCR || (opP->reg != TC && opP->reg != CAL &&
+ opP->reg != VAL && opP->reg != SCC && opP->reg != AC))
+ losing++;
+ break;
+
+ case 'V':
+ if (opP->reg != VAL)
+ losing++;
+ break;
+
+ case 'W':
+ if (opP->mode != MSCR || (opP->reg != DRP && opP->reg != SRP &&
+ opP->reg != CRP))
+ losing++;
+ break;
+
+ case 'X':
+ if (opP->mode != MSCR ||
+ (!(opP->reg >= BAD && opP->reg <= BAD+7) &&
+ !(opP->reg >= BAC && opP->reg <= BAC+7)))
+ losing++;
+ break;
+
+ case 'Y':
+ if (opP->reg != PSR)
+ losing++;
+ break;
+
+ case 'Z':
+ if (opP->reg != PCSR)
+ losing++;
+ break;
+#endif
+ case 'c':
+ if (opP->reg != NC
+ && opP->reg != IC
+ && opP->reg != DC
+ && opP->reg != BC) {
+ losing++;
+ } /* not a cache specifier. */
+ break;
+
+ case '_':
+ if (opP->mode != ABSL) {
+ ++losing;
+ } /* not absolute */
+ break;
+
+ default:
+ as_fatal("Internal error: Operand mode %c unknown in line %s of file \"%s\"",
+ *s, __LINE__, __FILE__);
+ } /* switch on type of operand */
+
+ if (losing) break;
+ } /* for each operand */
+ } /* if immediately wrong */
+
+ if (!losing) {
+ break;
+ } /* got it. */
+
+ opcode = opcode->m_next;
+
+ if (!opcode) {
+ the_ins.error = "instruction/operands mismatch";
+ return;
+ } /* Fell off the end */
+
+ losing = 0;
+ }
+
+ /* now assemble it */
+
+ the_ins.args=opcode->m_operands;
+ the_ins.numargs=opcode->m_opnum;
+ the_ins.numo=opcode->m_codenum;
+ the_ins.opcode[0]=getone(opcode);
+ the_ins.opcode[1]=gettwo(opcode);
+
+ for (s = the_ins.args, opP = &the_ins.operands[0]; *s; s += 2, opP++) {
+ /* This switch is a doozy.
+ Watch the first step; its a big one! */
+ switch (s[0]) {
+
+#ifdef PIC
+ case ' ':
+ /* this operand is just here to indicate a jump-table branch */
+ break;
+#endif /* PIC */
+
+ case '*':
+ case '~':
+ case '%':
+ case ';':
+ case '@':
+ case '!':
+ case '&':
+ case '$':
+ case '?':
+ case '/':
+#ifndef NO_68851
+ case '|':
+#endif
+
+#ifdef PIC
+ /* Use GLOB_DAT for operand references in PIC mode */
+ if (flagseen['k'])
+ reloc_type = RELOC_GLOB_DAT;
+ else
+#endif /* PIC */
+ reloc_type = NO_RELOC;
+
+ switch (opP->mode) {
+ int literal;
+
+ case IMMED:
+ tmpreg=0x3c; /* 7.4 */
+ if (*opP->con1->e_beg == ':') {
+ ++opP->con1->e_beg;
+ literal = 1;
+ } else
+ literal = 0;
+ if (strchr("bwl",s[1])) nextword=get_num(opP->con1,80);
+ else nextword=nextword=get_num(opP->con1,0);
+ if (isvar(opP->con1)) {
+#ifdef PIC
+ /* KLUDGE!!! In PIC assembly, an immediate reference to
+ __GLOBAL_OFFSET_TABLE_ is turned into a pc-relative
+ reference to __GLOBAL_OFFSET_TABLE_ - 6,
+ for the sake of Sun compatibility. */
+ if (s[1] == 'l' && flagseen['k'] && gots(opP->con1)) {
+ offs(opP->con1) -= 6;
+ add_fix(s[1], opP->con1, 1, NO_RELOC);
+ } else
+#endif /* PIC */
+ add_fix(s[1],opP->con1,0,reloc_type);
+ }
+ switch (s[1]) {
+ case 'b':
+ if (!isbyte(nextword))
+ opP->error="operand out of range";
+ addword(nextword);
+ baseo=0;
+ break;
+ case 'w':
+ if (!isword(nextword))
+ opP->error="operand out of range";
+ addword(nextword);
+ baseo=0;
+ break;
+ case 'l':
+ addword(nextword>>16);
+ addword(nextword);
+ baseo=0;
+ break;
+
+ case 'f':
+ baseo=2;
+ outro=8;
+ break;
+ case 'F':
+ baseo=4;
+ outro=11;
+ break;
+ case 'x':
+ baseo=6;
+ outro=15;
+ break;
+ case 'p':
+ baseo=6;
+ outro= -1;
+ break;
+ default:
+ as_fatal("Internal error: Can't decode %c%c in line %s of file \"%s\"",
+ *s, s[1], __LINE__, __FILE__);
+ }
+ if (!baseo)
+ break;
+
+ if (literal) {
+ if (seg(opP->con1) == SEG_BIG)
+ goto bignum;
+ while (baseo -= 2) {
+ addword(0);
+ addword(0);
+ }
+ addword(nextword>>16);
+ addword(nextword);
+ break;
+ }
+
+ /* We gotta put out some float */
+ if (seg(opP->con1) != SEG_BIG) {
+ int_to_gen(nextword);
+ gen_to_words(words,baseo,(long int)outro);
+ for (wordp=words;baseo--;wordp++)
+ addword(*wordp);
+ break;
+ } /* Its BIG */
+ if (offs(opP->con1)>0) {
+ as_warn("Bignum assumed to be binary bit-pattern");
+ bignum:
+ if (offs(opP->con1)>baseo) {
+ as_warn("Bignum too big for %c format; truncated",s[1]);
+ offs(opP->con1)=baseo;
+ }
+ baseo-=offs(opP->con1);
+ for (wordp=generic_bignum+offs(opP->con1)-1;offs(opP->con1)--;--wordp)
+ addword(*wordp);
+ while (baseo--)
+ addword(0);
+ break;
+ }
+ gen_to_words(words,baseo,(long)outro);
+ for (wordp=words;baseo--;wordp++)
+ addword(*wordp);
+ break;
+ case DREG:
+ tmpreg=opP->reg-DATA; /* 0.dreg */
+ break;
+ case AREG:
+ tmpreg=0x08+opP->reg-ADDR; /* 1.areg */
+ break;
+ case AINDR:
+ tmpreg=0x10+opP->reg-ADDR; /* 2.areg */
+ break;
+ case ADEC:
+ tmpreg=0x20+opP->reg-ADDR; /* 4.areg */
+ break;
+ case AINC:
+ tmpreg=0x18+opP->reg-ADDR; /* 3.areg */
+ break;
+ case AOFF:
+
+ nextword=get_num(opP->con1,80);
+ /* Force into index mode. Hope this works */
+
+ /* We do the first bit for 32-bit displacements,
+ and the second bit for 16 bit ones. It is
+ possible that we should make the default be
+ WORD instead of LONG, but I think that'd
+ break GCC, so we put up with a little
+ inefficiency for the sake of working output.
+ */
+
+ if ( !issword(nextword)
+ || ( isvar(opP->con1)
+ && ((opP->con1->e_siz == 0
+ && flagseen['l'] == 0)
+ || opP->con1->e_siz == 3))) {
+
+ if (opP->reg == PC)
+ tmpreg=0x3B; /* 7.3 */
+ else
+ tmpreg=0x30+opP->reg-ADDR; /* 6.areg */
+ if (isvar(opP->con1)) {
+ if (opP->reg == PC && !subs(opP->con1)) {
+ add_frag(adds(opP->con1),
+ offs(opP->con1),
+ TAB(PCLEA,SZ_UNDEF));
+ break;
+ } else {
+ addword(0x0170);
+ add_fix('l',opP->con1,0,reloc_type);
+ }
+ } else
+ addword(0x0170);
+ addword(nextword>>16);
+ } else {
+ if (opP->reg == PC)
+ tmpreg=0x3A; /* 7.2 */
+ else
+ tmpreg=0x28+opP->reg-ADDR; /* 5.areg */
+
+ if (isvar(opP->con1)) {
+ if (opP->reg == PC) {
+ add_fix('w',opP->con1,1,NO_RELOC);
+ } else
+ add_fix('w',opP->con1,0,reloc_type);
+ }
+ }
+ addword(nextword);
+ break;
+
+ case APODX:
+ case AMIND:
+ case APRDX:
+ know(current_architecture & m68020up);
+ /* intentional fall-through */
+ case AINDX:
+ nextword=0;
+ baseo=get_num(opP->con1,80);
+ outro=get_num(opP->con2,80);
+ /* Figure out the 'addressing mode' */
+ /* Also turn on the BASE_DISABLE bit, if needed */
+ if (opP->reg == PC || opP->reg == ZPC) {
+ tmpreg=0x3b; /* 7.3 */
+ if (opP->reg == ZPC)
+ nextword|=0x80;
+ } else if (opP->reg == FAIL) {
+ nextword|=0x80;
+ tmpreg=0x30; /* 6.garbage */
+ } else tmpreg=0x30+opP->reg-ADDR; /* 6.areg */
+
+ siz1= (opP->con1) ? opP->con1->e_siz : 0;
+ siz2= (opP->con2) ? opP->con2->e_siz : 0;
+
+ /* Index register stuff */
+ if (opP->ireg >= DATA+0 && opP->ireg <= ADDR+7) {
+ nextword|=(opP->ireg-DATA)<<12;
+
+ if (opP->isiz == 0 || opP->isiz == 3)
+ nextword|=0x800;
+ switch (opP->imul) {
+ case 1: break;
+ case 2: nextword|=0x200; break;
+ case 4: nextword|=0x400; break;
+ case 8: nextword|=0x600; break;
+ default: as_fatal("failed sanity check.");
+ }
+ /* IF its simple,
+ GET US OUT OF HERE! */
+
+ /* Must be INDEX, with an index
+ register. Address register
+ cannot be ZERO-PC, and either
+ :b was forced, or we know
+ it will fit */
+ if (opP->mode == AINDX
+ && opP->reg != FAIL
+ && opP->reg != ZPC
+ && (siz1 == 1
+ || ( issbyte(baseo)
+ && !isvar(opP->con1)))) {
+ nextword +=baseo&0xff;
+ addword(nextword);
+ if (isvar(opP->con1))
+ add_fix('B',opP->con1,0,reloc_type);
+ break;
+ }
+ } else
+ nextword|=0x40; /* No index reg */
+
+ /* It aint simple */
+ nextword|=0x100;
+ /* If the guy specified a width, we assume that
+ it is wide enough. Maybe it isn't. If so, we lose
+ */
+ switch (siz1) {
+ case 0:
+ if (isvar(opP->con1) || !issword(baseo)) {
+ siz1=3;
+ nextword|=0x30;
+ } else if (baseo == 0)
+ nextword|=0x10;
+ else {
+ nextword|=0x20;
+ siz1=2;
+ }
+ break;
+ case 1:
+ as_warn("Byte dispacement won't work. Defaulting to :w");
+ case 2:
+ nextword|=0x20;
+ break;
+ case 3:
+ nextword|=0x30;
+ break;
+ }
+
+ /* Figure out innner displacement stuff */
+ if (opP->mode != AINDX) {
+ switch (siz2) {
+ case 0:
+ if (isvar(opP->con2) || !issword(outro)) {
+ siz2=3;
+ nextword|=0x3;
+ } else if (outro == 0)
+ nextword|=0x1;
+ else {
+ nextword|=0x2;
+ siz2=2;
+ }
+ break;
+ case 1:
+ as_warn("Byte dispacement won't work. Defaulting to :w");
+ case 2:
+ nextword|=0x2;
+ break;
+ case 3:
+ nextword|=0x3;
+ break;
+ }
+ if (opP->mode == APODX) nextword|=0x04;
+ else if (opP->mode == AMIND) nextword|=0x40;
+ }
+ addword(nextword);
+
+ if (isvar(opP->con1)) {
+ if (opP->reg == PC || opP->reg == ZPC) {
+ add_fix(siz1 == 3 ? 'l' : 'w',opP->con1,1,NO_RELOC);
+ opP->con1->e_exp.X_add_number+=6;
+ } else
+ add_fix(siz1 == 3 ? 'l' : 'w',opP->con1,0,reloc_type);
+ }
+ if (siz1 == 3)
+ addword(baseo>>16);
+ if (siz1)
+ addword(baseo);
+
+ if (isvar(opP->con2)) {
+ if (opP->reg == PC || opP->reg == ZPC) {
+ add_fix(siz2 == 3 ? 'l' : 'w',opP->con2,1,NO_RELOC);
+ opP->con1->e_exp.X_add_number+=6;
+ } else
+ add_fix(siz2 == 3 ? 'l' : 'w',opP->con2,0,reloc_type);
+ }
+ if (siz2 == 3)
+ addword(outro>>16);
+ if (siz2)
+ addword(outro);
+
+ break;
+
+ case ABSL:
+ nextword=get_num(opP->con1,80);
+ switch (opP->con1->e_siz) {
+ default:
+ as_warn("Unknown size for absolute reference");
+ case 0:
+ if (!isvar(opP->con1) && issword(offs(opP->con1))) {
+ tmpreg=0x38; /* 7.0 */
+ addword(nextword);
+ break;
+ }
+ /* Don't generate pc relative code
+ on 68010 and 68000 */
+ if (isvar(opP->con1)
+ && !subs(opP->con1)
+ && seg(opP->con1) == SEG_TEXT
+ && now_seg == SEG_TEXT
+ && cpu_of_arch(current_architecture) >= m68020
+ && !flagseen['S']
+ && !strchr("~%&$?", s[0])) {
+ tmpreg=0x3A; /* 7.2 */
+ add_frag(adds(opP->con1),
+ offs(opP->con1),
+ TAB(PCREL,SZ_UNDEF));
+ break;
+ }
+ case 3: /* Fall through into long */
+ if (isvar(opP->con1))
+ add_fix('l',opP->con1,0,NO_RELOC);
+
+ tmpreg=0x39; /* 7.1 mode */
+ addword(nextword>>16);
+ addword(nextword);
+ break;
+
+ case 2: /* Word */
+ if (isvar(opP->con1))
+ add_fix('w',opP->con1,0,NO_RELOC);
+
+ tmpreg=0x38; /* 7.0 mode */
+ addword(nextword);
+ break;
+ }
+ break;
+ case MSCR:
+ default:
+ as_bad("unknown/incorrect operand");
+ /* abort(); */
+ }
+ install_gen_operand(s[1],tmpreg);
+ break;
+
+ case '#':
+ case '^':
+ switch (s[1]) { /* JF: I hate floating point! */
+ case 'j':
+ tmpreg=70;
+ break;
+ case '8':
+ tmpreg=20;
+ break;
+ case 'C':
+ tmpreg=50;
+ break;
+ case '3':
+ default:
+ tmpreg=80;
+ break;
+ }
+ tmpreg=get_num(opP->con1,tmpreg);
+ if (isvar(opP->con1))
+ add_fix(s[1],opP->con1,0,NO_RELOC);
+ switch (s[1]) {
+ case 'b': /* Danger: These do no check for
+ certain types of overflow.
+ user beware! */
+ if (!isbyte(tmpreg))
+ opP->error="out of range";
+ insop(tmpreg);
+ if (isvar(opP->con1))
+ the_ins.reloc[the_ins.nrel-1].n=(opcode->m_codenum)*2;
+ break;
+ case 'w':
+ if (!isword(tmpreg))
+ opP->error="out of range";
+ insop(tmpreg);
+ if (isvar(opP->con1))
+ the_ins.reloc[the_ins.nrel-1].n=(opcode->m_codenum)*2;
+ break;
+ case 'l':
+ insop(tmpreg); /* Because of the way insop works, we put these two out backwards */
+ insop(tmpreg>>16);
+ if (isvar(opP->con1))
+ the_ins.reloc[the_ins.nrel-1].n=(opcode->m_codenum)*2;
+ break;
+ case '3':
+ tmpreg&=0xFF;
+ case '8':
+ case 'C':
+ install_operand(s[1],tmpreg);
+ break;
+ default:
+ as_fatal("Internal error: Unknown mode #%c in line %s of file \"%s\"", s[1], __LINE__, __FILE__);
+ }
+ break;
+
+ case '+':
+ case '-':
+ case 'A':
+ case 'a':
+ install_operand(s[1], opP->reg - ADDR);
+ break;
+
+ case 'B':
+ tmpreg = get_num(opP->con1, 80);
+ switch (s[1]) {
+ case 'B':
+ /* Offset is relative to next word */
+ opP->con1->e_exp.X_add_number -= 1;
+ add_fix('B', opP->con1, 1,NO_RELOC);
+ break;
+ case 'W':
+ add_fix('w', opP->con1, 1,NO_RELOC);
+ addword(0);
+ break;
+ case 'L':
+ long_branch:
+ if (cpu_of_arch(current_architecture) < m68020) /* 68000 or 010 */
+ as_warn("Can't use long branches on 68000/68010");
+ the_ins.opcode[the_ins.numo-1]|=0xff;
+ add_fix('l',opP->con1,1,NO_RELOC);
+ addword(0);
+ addword(0);
+ break;
+ case 'g':
+#ifdef PIC
+ /* If we have the optional kludgey 2nd operand,
+ make this go via the jump table. */
+ if (flagseen['k'] && s[2] == ' ') {
+ the_ins.opcode[the_ins.numo-1] |= 0xFF;
+ add_fix('l', opP->con1, 1, RELOC_JMP_TBL);
+ addword(0);
+ addword(0);
+ break;
+ }
+#endif /* PIC */
+ if (subs(opP->con1)) /* We can't relax it */
+ goto long_branch;
+
+ /* This could either be a symbol, or an
+ absolute address. No matter, the
+ frag hacking will finger it out.
+ Not quite: it can't switch from
+ BRANCH to BCC68000 for the case
+ where opnd is absolute (it needs
+ to use the 68000 hack since no
+ conditional abs jumps). */
+ if (((cpu_of_arch(current_architecture) < m68020) || (0 == adds(opP->con1)))
+ && (the_ins.opcode[0] >= 0x6200)
+ && (the_ins.opcode[0] <= 0x6f00)) {
+ add_frag(adds(opP->con1),offs(opP->con1),TAB(BCC68000,SZ_UNDEF));
+ } else {
+ add_frag(adds(opP->con1),offs(opP->con1),TAB(BRANCH,SZ_UNDEF));
+ }
+ break;
+ case 'w':
+ if (isvar(opP->con1)) {
+ /* check for DBcc instruction */
+ if ((the_ins.opcode[0] & 0xf0f8) == 0x50c8) {
+ /* size varies if patch */
+ /* needed for long form */
+ add_frag(adds(opP->con1),offs(opP->con1),TAB(DBCC,SZ_UNDEF));
+ break;
+ }
+
+ /* Don't ask! */
+ opP->con1->e_exp.X_add_number+=2;
+ add_fix('w',opP->con1,1,NO_RELOC);
+ }
+ addword(0);
+ break;
+ case 'C': /* Fixed size LONG coproc branches */
+ the_ins.opcode[the_ins.numo-1]|=0x40;
+ /* Offset the displacement to be relative to byte disp location */
+ /* Coproc branches don't have a byte disp option, but they are
+ compatible with the ordinary branches, which do... */
+ opP->con1->e_exp.X_add_number+=4;
+ add_fix('l',opP->con1,1,NO_RELOC);
+ addword(0);
+ addword(0);
+ break;
+ case 'c': /* Var size Coprocesssor branches */
+ if (subs(opP->con1)) {
+ add_fix('l',opP->con1,1,NO_RELOC);
+ add_frag((symbolS *)0,(long)0,TAB(FBRANCH,LONG));
+ } else if (adds(opP->con1)) {
+ add_frag(adds(opP->con1),offs(opP->con1),TAB(FBRANCH,SZ_UNDEF));
+ } else {
+ /* add_frag((symbolS *)0,offs(opP->con1),TAB(FBRANCH,SHORT)); */
+ the_ins.opcode[the_ins.numo-1]|=0x40;
+ add_fix('l',opP->con1,1,NO_RELOC);
+ addword(0);
+ addword(4);
+ }
+ break;
+ default:
+ as_fatal("Internal error: operand type B%c unknown in line %s of file \"%s\"",
+ s[1], __LINE__, __FILE__);
+ }
+ break;
+
+ case 'C': /* Ignore it */
+ break;
+
+ case 'd': /* JF this is a kludge */
+ if (opP->mode == AOFF) {
+ install_operand('s',opP->reg-ADDR);
+ } else {
+ char *tmpP;
+
+ tmpP=opP->con1->e_end-2;
+ opP->con1->e_beg++;
+ opP->con1->e_end-=4; /* point to the , */
+ baseo=m68k_reg_parse(&tmpP);
+ if (baseo<ADDR+0 || baseo>ADDR+7) {
+ as_bad("Unknown address reg, using A0");
+ baseo=0;
+ } else baseo-=ADDR;
+ install_operand('s',baseo);
+ }
+ tmpreg=get_num(opP->con1,80);
+ if (!issword(tmpreg)) {
+ as_warn("Expression out of range, using 0");
+ tmpreg=0;
+ }
+ addword(tmpreg);
+ break;
+
+ case 'D':
+ install_operand(s[1],opP->reg-DATA);
+ break;
+
+ case 'F':
+ install_operand(s[1],opP->reg-FPREG);
+ break;
+
+ case 'I':
+ tmpreg=1+opP->reg-COPNUM;
+ if (tmpreg == 8)
+ tmpreg=0;
+ install_operand(s[1],tmpreg);
+ break;
+
+ case 'J': /* JF foo */
+ switch (opP->reg) {
+ case SFC: tmpreg=0x000; break;
+ case DFC: tmpreg=0x001; break;
+ case CACR: tmpreg=0x002; break;
+ case TC: tmpreg=0x003; break;
+ case ITT0: tmpreg=0x004; break;
+ case ITT1: tmpreg=0x005; break;
+ case DTT0: tmpreg=0x006; break;
+ case DTT1: tmpreg=0x007; break;
+
+ case USP: tmpreg=0x800; break;
+ case VBR: tmpreg=0x801; break;
+ case CAAR: tmpreg=0x802; break;
+ case MSP: tmpreg=0x803; break;
+ case ISP: tmpreg=0x804; break;
+ case MMUSR: tmpreg=0x805; break;
+ case URP: tmpreg=0x806; break;
+ case SRP: tmpreg=0x807; break;
+ default:
+ as_fatal("failed sanity check.");
+ }
+ install_operand(s[1],tmpreg);
+ break;
+
+ case 'k':
+ tmpreg=get_num(opP->con1,55);
+ install_operand(s[1],tmpreg&0x7f);
+ break;
+
+ case 'l':
+ tmpreg=opP->reg;
+ if (s[1] == 'w') {
+ if (tmpreg&0x7FF0000)
+ as_bad("Floating point register in register list");
+ insop(reverse_16_bits(tmpreg));
+ } else {
+ if (tmpreg&0x700FFFF)
+ as_bad("Wrong register in floating-point reglist");
+ install_operand(s[1],reverse_8_bits(tmpreg>>16));
+ }
+ break;
+
+ case 'L':
+ tmpreg=opP->reg;
+ if (s[1] == 'w') {
+ if (tmpreg&0x7FF0000)
+ as_bad("Floating point register in register list");
+ insop(tmpreg);
+ } else if (s[1] == '8') {
+ if (tmpreg&0x0FFFFFF)
+ as_bad("incorrect register in reglist");
+ install_operand(s[1],tmpreg>>24);
+ } else {
+ if (tmpreg&0x700FFFF)
+ as_bad("wrong register in floating-point reglist");
+ else
+ install_operand(s[1],tmpreg>>16);
+ }
+ break;
+
+ case 'M':
+ install_operand(s[1],get_num(opP->con1,60));
+ break;
+
+ case 'O':
+ tmpreg= (opP->mode == DREG)
+ ? 0x20+opP->reg-DATA
+ : (get_num(opP->con1,40)&0x1F);
+ install_operand(s[1],tmpreg);
+ break;
+
+ case 'Q':
+ tmpreg=get_num(opP->con1,10);
+ if (tmpreg == 8)
+ tmpreg=0;
+ install_operand(s[1],tmpreg);
+ break;
+
+ case 'R':
+ /* This depends on the fact that ADDR registers are
+ eight more than their corresponding DATA regs, so
+ the result will have the ADDR_REG bit set */
+ install_operand(s[1],opP->reg-DATA);
+ break;
+
+ case 's':
+ if (opP->reg == FPI) tmpreg=0x1;
+ else if (opP->reg == FPS) tmpreg=0x2;
+ else if (opP->reg == FPC) tmpreg=0x4;
+ else as_fatal("failed sanity check.");
+ install_operand(s[1],tmpreg);
+ break;
+
+ case 'S': /* Ignore it */
+ break;
+
+ case 'T':
+ install_operand(s[1],get_num(opP->con1,30));
+ break;
+
+ case 'U': /* Ignore it */
+ break;
+
+ case 'c':
+ switch (opP->reg) {
+ case NC: tmpreg = 0; break;
+ case DC: tmpreg = 1; break;
+ case IC: tmpreg = 2; break;
+ case BC: tmpreg = 3; break;
+ default:
+ as_fatal("failed sanity check");
+ } /* switch on cache token */
+ install_operand(s[1], tmpreg);
+ break;
+#ifndef NO_68851
+ /* JF: These are out of order, I fear. */
+ case 'f':
+ switch (opP->reg) {
+ case SFC:
+ tmpreg=0;
+ break;
+ case DFC:
+ tmpreg=1;
+ break;
+ default:
+ as_fatal("failed sanity check.");
+ }
+ install_operand(s[1],tmpreg);
+ break;
+
+ case 'P':
+ switch (opP->reg) {
+ case TC:
+ tmpreg=0;
+ break;
+ case CAL:
+ tmpreg=4;
+ break;
+ case VAL:
+ tmpreg=5;
+ break;
+ case SCC:
+ tmpreg=6;
+ break;
+ case AC:
+ tmpreg=7;
+ break;
+ default:
+ as_fatal("failed sanity check.");
+ }
+ install_operand(s[1],tmpreg);
+ break;
+
+ case 'V':
+ if (opP->reg == VAL)
+ break;
+ as_fatal("failed sanity check.");
+
+ case 'W':
+ switch (opP->reg) {
+
+ case DRP:
+ tmpreg=1;
+ break;
+ case SRP:
+ tmpreg=2;
+ break;
+ case CRP:
+ tmpreg=3;
+ break;
+ default:
+ as_fatal("failed sanity check.");
+ }
+ install_operand(s[1],tmpreg);
+ break;
+
+ case 'X':
+ switch (opP->reg) {
+ case BAD: case BAD+1: case BAD+2: case BAD+3:
+ case BAD+4: case BAD+5: case BAD+6: case BAD+7:
+ tmpreg = (4 << 10) | ((opP->reg - BAD) << 2);
+ break;
+
+ case BAC: case BAC+1: case BAC+2: case BAC+3:
+ case BAC+4: case BAC+5: case BAC+6: case BAC+7:
+ tmpreg = (5 << 10) | ((opP->reg - BAC) << 2);
+ break;
+
+ default:
+ as_fatal("failed sanity check.");
+ }
+ install_operand(s[1], tmpreg);
+ break;
+ case 'Y':
+ know(opP->reg == PSR);
+ break;
+ case 'Z':
+ know(opP->reg == PCSR);
+ break;
+#endif /* m68851 */
+ case '_':
+ tmpreg=get_num(opP->con1,80);
+ install_operand(s[1], tmpreg);
+ break;
+ default:
+ as_fatal("Internal error: Operand type %c unknown in line %s of file \"%s\"", s[0], __LINE__, __FILE__);
+ }
+ }
+ /* By the time whe get here (FINALLY) the_ins contains the complete
+ instruction, ready to be emitted... */
+} /* m68k_ip() */
+
+/*
+ * get_regs := '/' + ?
+ * | '-' + <register>
+ * | '-' + <register> + ?
+ * | <empty>
+ * ;
+ *
+
+ * The idea here must be to scan in a set of registers but I don't
+ * understand it. Looks awfully sloppy to me but I don't have any doc on
+ * this format so...
+
+ *
+ *
+ */
+
+static int get_regs(i,str,opP)
+int i;
+struct m68k_op *opP;
+char *str;
+{
+ /* 26, 25, 24, 23-16, 15-8, 0-7 */
+ /* Low order 24 bits encoded fpc,fps,fpi,fp7-fp0,a7-a0,d7-d0 */
+ unsigned long cur_regs = 0;
+ int reg1,
+ reg2;
+
+#define ADD_REG(x) { if (x == FPI) cur_regs|=(1<<24);\
+else if (x == FPS) cur_regs|=(1<<25);\
+else if (x == FPC) cur_regs|=(1<<26);\
+else cur_regs|=(1<<(x-1)); }
+
+ reg1=i;
+ for (;;) {
+ if (*str == '/') {
+ ADD_REG(reg1);
+ str++;
+ } else if (*str == '-') {
+ str++;
+ reg2=m68k_reg_parse(&str);
+ if (reg2<DATA || reg2 >= FPREG+8 || reg1 == FPI || reg1 == FPS || reg1 == FPC) {
+ opP->error="unknown register in register list";
+ return FAIL;
+ }
+ while (reg1 <= reg2) {
+ ADD_REG(reg1);
+ reg1++;
+ }
+ if (*str == '\0')
+ break;
+ } else if (*str == '\0') {
+ ADD_REG(reg1);
+ break;
+ } else {
+ opP->error="unknow character in register list";
+ return FAIL;
+ }
+ /* DJA -- Bug Fix. Did't handle d1-d2/a1 until the following instruction was added */
+ if (*str == '/')
+ str ++;
+ reg1=m68k_reg_parse(&str);
+ if ((reg1<DATA || reg1 >= FPREG+8) && !(reg1 == FPI || reg1 == FPS || reg1 == FPC)) {
+ opP->error="unknown register in register list";
+ return FAIL;
+ }
+ }
+ opP->reg=cur_regs;
+ return OK;
+} /* get_regs() */
+
+static int reverse_16_bits(in)
+int in;
+{
+ int out=0;
+ int n;
+
+ static int mask[16] = {
+ 0x0001,0x0002,0x0004,0x0008,0x0010,0x0020,0x0040,0x0080,
+ 0x0100,0x0200,0x0400,0x0800,0x1000,0x2000,0x4000,0x8000
+ };
+ for (n=0;n<16;n++) {
+ if (in&mask[n])
+ out|=mask[15-n];
+ }
+ return out;
+} /* reverse_16_bits() */
+
+static int reverse_8_bits(in)
+int in;
+{
+ int out=0;
+ int n;
+
+ static int mask[8] = {
+ 0x0001,0x0002,0x0004,0x0008,0x0010,0x0020,0x0040,0x0080,
+ };
+
+ for (n=0;n<8;n++) {
+ if (in&mask[n])
+ out|=mask[7-n];
+ }
+ return out;
+} /* reverse_8_bits() */
+
+static void install_operand(mode,val)
+int mode;
+int val;
+{
+ switch (mode) {
+ case 's':
+ the_ins.opcode[0]|=val & 0xFF; /* JF FF is for M kludge */
+ break;
+ case 'd':
+ the_ins.opcode[0]|=val<<9;
+ break;
+ case '1':
+ the_ins.opcode[1]|=val<<12;
+ break;
+ case '2':
+ the_ins.opcode[1]|=val<<6;
+ break;
+ case '3':
+ the_ins.opcode[1]|=val;
+ break;
+ case '4':
+ the_ins.opcode[2]|=val<<12;
+ break;
+ case '5':
+ the_ins.opcode[2]|=val<<6;
+ break;
+ case '6':
+ /* DANGER! This is a hack to force cas2l and cas2w cmds
+ to be three words long! */
+ the_ins.numo++;
+ the_ins.opcode[2]|=val;
+ break;
+ case '7':
+ the_ins.opcode[1]|=val<<7;
+ break;
+ case '8':
+ the_ins.opcode[1]|=val<<10;
+ break;
+#ifndef NO_68851
+ case '9':
+ the_ins.opcode[1]|=val<<5;
+ break;
+#endif
+
+ case 't':
+ the_ins.opcode[1]|=(val<<10)|(val<<7);
+ break;
+ case 'D':
+ the_ins.opcode[1]|=(val<<12)|val;
+ break;
+ case 'g':
+ the_ins.opcode[0]|=val=0xff;
+ break;
+ case 'i':
+ the_ins.opcode[0]|=val<<9;
+ break;
+ case 'C':
+ the_ins.opcode[1]|=val;
+ break;
+ case 'j':
+ the_ins.opcode[1]|=val;
+ the_ins.numo++; /* What a hack */
+ break;
+ case 'k':
+ the_ins.opcode[1]|=val<<4;
+ break;
+ case 'b':
+ case 'w':
+ case 'l':
+ break;
+ case 'e':
+ the_ins.opcode[0] |= (val << 6);
+ break;
+ case 'L':
+ the_ins.opcode[1] = (val >> 16);
+ the_ins.opcode[2] = val & 0xffff;
+ break;
+ case 'c':
+ default:
+ as_fatal("failed sanity check.");
+ }
+} /* install_operand() */
+
+static void install_gen_operand(mode,val)
+int mode;
+int val;
+{
+ switch (mode) {
+ case 's':
+ the_ins.opcode[0]|=val;
+ break;
+ case 'd':
+ /* This is a kludge!!! */
+ the_ins.opcode[0]|=(val&0x07)<<9|(val&0x38)<<3;
+ break;
+ case 'b':
+ case 'w':
+ case 'l':
+ case 'f':
+ case 'F':
+ case 'x':
+ case 'p':
+ the_ins.opcode[0]|=val;
+ break;
+ /* more stuff goes here */
+ default:
+ as_fatal("failed sanity check.");
+ }
+} /* install_gen_operand() */
+
+/*
+ * verify that we have some number of paren pairs, do m68k_ip_op(), and
+ * then deal with the bitfield hack.
+ */
+
+static char *crack_operand(str,opP)
+register char *str;
+register struct m68k_op *opP;
+{
+ register int parens;
+ register int c;
+ register char *beg_str;
+
+ if (!str) {
+ return str;
+ }
+ beg_str=str;
+ for (parens=0;*str && (parens>0 || notend(str));str++) {
+ if (*str == '(') parens++;
+ else if (*str == ')') {
+ if (!parens) { /* ERROR */
+ opP->error="Extra )";
+ return str;
+ }
+ --parens;
+ }
+ }
+ if (!*str && parens) { /* ERROR */
+ opP->error="Missing )";
+ return str;
+ }
+ c= *str;
+ *str='\0';
+ if (m68k_ip_op(beg_str,opP) == FAIL) {
+ *str=c;
+ return str;
+ }
+ *str=c;
+ if (c == '}')
+ c= *++str; /* JF bitfield hack */
+ if (c) {
+ c= *++str;
+ if (!c)
+ as_bad("Missing operand");
+ }
+ return str;
+}
+
+/* See the comment up above where the #define notend(... is */
+#if 0
+notend(s)
+char *s;
+{
+ if (*s == ',') return 0;
+ if (*s == '{' || *s == '}')
+ return 0;
+ if (*s != ':') return 1;
+ /* This kludge here is for the division cmd, which is a kludge */
+ if (index("aAdD#",s[1])) return 0;
+ return 1;
+}
+#endif
+
+/*
+ * Generate a new fixup for one of the relocs in the_ins.
+ */
+static void
+ make_fix(m, where)
+int m;
+char *where;
+{
+ int n;
+
+ switch (the_ins.reloc[m].wid) {
+ case 'B':
+ case 'b':
+ n=1;
+ break;
+ case '3':
+ case 'w':
+ n=2;
+ break;
+ case 'l':
+ n=4;
+ break;
+ default:
+ as_fatal("Don't know how to figure width of %c in md_assemble()",the_ins.reloc[m].wid);
+ }
+ fix_new(frag_now,
+ where - frag_now->fr_literal + the_ins.reloc[m].n,
+ n,
+ the_ins.reloc[m].add,
+ the_ins.reloc[m].sub,
+ the_ins.reloc[m].off,
+ the_ins.reloc[m].pcrel,
+ the_ins.reloc[m].rtype
+#ifdef PIC
+ , the_ins.reloc[m].got
+#endif /* PIC */
+ );
+#ifdef PIC
+ if (the_ins.reloc[m].rtype == RELOC_GLOB_DAT
+ && the_ins.reloc[m].add != NULL)
+ the_ins.reloc[m].add->sy_forceout = 1;
+#endif /* PIC */
+}
+
+/* This is the guts of the machine-dependent assembler. STR points to a
+ machine dependent instruction. This function is supposed to emit
+ the frags/bytes it assembles to.
+ */
+void
+ md_assemble(str)
+char *str;
+{
+ char *er;
+ short *fromP;
+ char *toP = NULL;
+ int m,n = 0;
+ char *to_beg_P;
+ int shorts_this_frag;
+
+
+ if (current_architecture == 0) {
+ current_architecture = (m68020
+#ifndef NO_68881
+ | m68881
+#endif
+#ifndef NO_68851
+ | m68851
+#endif
+ );
+ } /* default current_architecture */
+
+ memset((char *)(&the_ins), '\0', sizeof(the_ins)); /* JF for paranoia sake */
+ m68k_ip(str);
+ er=the_ins.error;
+ if (!er) {
+ for (n=the_ins.numargs;n;--n)
+ if (the_ins.operands[n].error) {
+ er=the_ins.operands[n].error;
+ break;
+ }
+ }
+ if (er) {
+ as_bad("\"%s\" -- Statement '%s' ignored",er,str);
+ return;
+ }
+
+ if (the_ins.nfrag == 0) { /* No frag hacking involved; just put it out */
+ toP=frag_more(2*the_ins.numo);
+ fromP= &the_ins.opcode[0];
+ for (m=the_ins.numo;m;--m) {
+ md_number_to_chars(toP,(long)(*fromP),2);
+ toP+=2;
+ fromP++;
+ }
+ /* put out symbol-dependent info */
+ for (m = 0; m < the_ins.nrel; m++) {
+ make_fix(m, toP-the_ins.numo*2);
+ }
+ return;
+ }
+
+ /* There's some frag hacking */
+ for (n=0,fromP= &the_ins.opcode[0];n<the_ins.nfrag;n++) {
+ int wid;
+
+ if (n == 0) wid=2*the_ins.fragb[n].fragoff;
+ else wid=2*(the_ins.numo-the_ins.fragb[n-1].fragoff);
+ toP=frag_more(wid);
+ to_beg_P=toP;
+ shorts_this_frag=0;
+ for (m=wid/2;m;--m) {
+ md_number_to_chars(toP,(long)(*fromP),2);
+ toP+=2;
+ fromP++;
+ shorts_this_frag++;
+ }
+ for (m=0;m<the_ins.nrel;m++) {
+ if ((the_ins.reloc[m].n) >= 2*shorts_this_frag /* 2*the_ins.fragb[n].fragoff */) {
+ the_ins.reloc[m].n-= 2*shorts_this_frag /* 2*the_ins.fragb[n].fragoff */;
+ break;
+ }
+ if (the_ins.reloc[m].wid == 0)
+ continue;
+ make_fix(m, toP-the_ins.numo*2);
+ the_ins.reloc[m].wid=0;
+ }
+ /* know(the_ins.fragb[n].fadd); */
+ (void)frag_var(rs_machine_dependent,10,0,(relax_substateT)(the_ins.fragb[n].fragty),
+ the_ins.fragb[n].fadd,the_ins.fragb[n].foff,to_beg_P);
+ }
+ n=(the_ins.numo-the_ins.fragb[n-1].fragoff);
+ shorts_this_frag=0;
+ if (n) {
+ toP=frag_more(n*sizeof(short));
+ while (n--) {
+ md_number_to_chars(toP,(long)(*fromP),2);
+ toP+=2;
+ fromP++;
+ shorts_this_frag++;
+ }
+ }
+ for (m=0;m<the_ins.nrel;m++) {
+ if (the_ins.reloc[m].wid == 0)
+ continue;
+ make_fix(m, toP - /* the_ins.numo */ shorts_this_frag*2);
+ }
+}
+
+/* This function is called once, at assembler startup time. This should
+ set up all the tables, etc that the MD part of the assembler needs
+ */
+void
+ md_begin()
+{
+ /*
+ * md_begin -- set up hash tables with 68000 instructions.
+ * similar to what the vax assembler does. ---phr
+ */
+ /* RMS claims the thing to do is take the m68k-opcode.h table, and make
+ a copy of it at runtime, adding in the information we want but isn't
+ there. I think it'd be better to have an awk script hack the table
+ at compile time. Or even just xstr the table and use it as-is. But
+ my lord ghod hath spoken, so we do it this way. Excuse the ugly var
+ names. */
+
+ register const struct m68k_opcode *ins;
+ register struct m68k_incant *hack,
+ *slak;
+ register char *retval = 0; /* empty string, or error msg text */
+ register unsigned int i;
+ register char c;
+
+ if ((op_hash = hash_new()) == NULL)
+ as_fatal("Virtual memory exhausted");
+
+ obstack_begin(&robyn,4000);
+ for (ins = m68k_opcodes; ins < endop; ins++) {
+ hack=slak=(struct m68k_incant *)obstack_alloc(&robyn,sizeof(struct m68k_incant));
+ do {
+ /* we *could* ignore insns that don't match our
+ arch here but just leaving them out of the
+ hash. */
+ slak->m_operands=ins->args;
+ slak->m_opnum=strlen(slak->m_operands)/2;
+ slak->m_arch = ins->arch;
+ slak->m_opcode=ins->opcode;
+ /* This is kludgey */
+ slak->m_codenum=((ins->match)&0xffffL) ? 2 : 1;
+ if ((ins+1) != endop && !strcmp(ins->name,(ins+1)->name)) {
+ slak->m_next=(struct m68k_incant *) obstack_alloc(&robyn,sizeof(struct m68k_incant));
+ ins++;
+ } else
+ slak->m_next=0;
+ slak=slak->m_next;
+ } while (slak);
+
+ retval = hash_insert (op_hash, ins->name,(char *)hack);
+ /* Didn't his mommy tell him about null pointers? */
+ if (retval && *retval)
+ as_fatal("Internal Error: Can't hash %s: %s",ins->name,retval);
+ }
+
+ for (i = 0; i < sizeof(mklower_table) ; i++)
+ mklower_table[i] = (isupper(c = (char) i)) ? tolower(c) : c;
+
+ for (i = 0 ; i < sizeof(notend_table) ; i++) {
+ notend_table[i] = 0;
+ alt_notend_table[i] = 0;
+ }
+ notend_table[','] = 1;
+ notend_table['{'] = 1;
+ notend_table['}'] = 1;
+ alt_notend_table['a'] = 1;
+ alt_notend_table['A'] = 1;
+ alt_notend_table['d'] = 1;
+ alt_notend_table['D'] = 1;
+ alt_notend_table['#'] = 1;
+ alt_notend_table['f'] = 1;
+ alt_notend_table['F'] = 1;
+#ifdef REGISTER_PREFIX
+ alt_notend_table[REGISTER_PREFIX] = 1;
+#endif
+}
+
+#if 0
+#define notend(s) ((*s == ',' || *s == '}' || *s == '{' \
+ || (*s == ':' && strchr("aAdD#", s[1]))) \
+ ? 0 : 1)
+#endif
+
+/* This funciton is called once, before the assembler exits. It is
+ supposed to do any final cleanup for this part of the assembler.
+ */
+void
+ md_end()
+{
+}
+
+/* Equal to MAX_PRECISION in atof-ieee.c */
+#define MAX_LITTLENUMS 6
+
+/* Turn a string in input_line_pointer into a floating point constant of type
+ type, and store the appropriate bytes in *litP. The number of LITTLENUMS
+ emitted is stored in *sizeP. An error message is returned, or NULL on OK.
+ */
+char *
+ md_atof(type,litP,sizeP)
+char type;
+char *litP;
+int *sizeP;
+{
+ int prec;
+ LITTLENUM_TYPE words[MAX_LITTLENUMS];
+ LITTLENUM_TYPE *wordP;
+ char *t;
+ char *atof_ieee();
+
+ switch (type) {
+ case 'f':
+ case 'F':
+ case 's':
+ case 'S':
+ prec = 2;
+ break;
+
+ case 'd':
+ case 'D':
+ case 'r':
+ case 'R':
+ prec = 4;
+ break;
+
+ case 'x':
+ case 'X':
+ prec = 6;
+ break;
+
+ case 'p':
+ case 'P':
+ prec = 6;
+ break;
+
+ default:
+ *sizeP=0;
+ return "Bad call to MD_ATOF()";
+ }
+ t=atof_ieee(input_line_pointer,type,words);
+ if (t)
+ input_line_pointer=t;
+
+ *sizeP=prec * sizeof(LITTLENUM_TYPE);
+ for (wordP=words;prec--;) {
+ md_number_to_chars(litP,(long)(*wordP++),sizeof(LITTLENUM_TYPE));
+ litP+=sizeof(LITTLENUM_TYPE);
+ }
+ return ""; /* Someone should teach Dean about null pointers */
+}
+
+/* Turn an integer of n bytes (in val) into a stream of bytes appropriate
+ for use in the a.out file, and stores them in the array pointed to by buf.
+ This knows about the endian-ness of the target machine and does
+ THE RIGHT THING, whatever it is. Possible values for n are 1 (byte)
+ 2 (short) and 4 (long) Floating numbers are put out as a series of
+ LITTLENUMS (shorts, here at least)
+ */
+void
+ md_number_to_chars(buf, val, n)
+char *buf;
+long val;
+int n;
+{
+ switch (n) {
+ case 1:
+ *buf++=val;
+ break;
+ case 2:
+ *buf++=(val>>8);
+ *buf++=val;
+ break;
+ case 4:
+ *buf++=(val>>24);
+ *buf++=(val>>16);
+ *buf++=(val>>8);
+ *buf++=val;
+ break;
+ default:
+ as_fatal("failed sanity check.");
+ }
+}
+
+void
+ md_apply_fix(fixP, val)
+fixS *fixP;
+long val;
+{
+ char *buf = fixP->fx_where + fixP->fx_frag->fr_literal;
+
+ switch (fixP->fx_size) {
+ case 1:
+ *buf++ = val;
+ break;
+ case 2:
+ *buf++ = (val >> 8);
+ *buf++ = val;
+ break;
+ case 4:
+ *buf++ = (val >> 24);
+ *buf++ = (val >> 16);
+ *buf++ = (val >> 8);
+ *buf++ = val;
+ break;
+ default:
+ BAD_CASE (fixP->fx_size);
+ }
+}
+
+
+/* *fragP has been relaxed to its final size, and now needs to have
+ the bytes inside it modified to conform to the new size There is UGLY
+ MAGIC here. ..
+ */
+void
+ md_convert_frag(headers, fragP)
+object_headers *headers;
+register fragS *fragP;
+{
+ long disp;
+ long ext = 0;
+
+ /* Address in object code of the displacement. */
+ register int object_address = fragP->fr_fix + fragP->fr_address;
+
+#ifdef IBM_COMPILER_SUX
+ /* This is wrong but it convinces the native rs6000 compiler to
+ generate the code we want. */
+ register char *buffer_address = fragP->fr_literal;
+ buffer_address += fragP->fr_fix;
+#else /* IBM_COMPILER_SUX */
+ /* Address in gas core of the place to store the displacement. */
+ register char *buffer_address = fragP->fr_fix + fragP->fr_literal;
+#endif /* IBM_COMPILER_SUX */
+
+ /* No longer true: know(fragP->fr_symbol); */
+
+ /* The displacement of the address, from current location. */
+ disp = fragP->fr_symbol ? S_GET_VALUE(fragP->fr_symbol) : 0;
+ disp = (disp + fragP->fr_offset) - object_address;
+
+ switch (fragP->fr_subtype) {
+ case TAB(BCC68000,BYTE):
+ case TAB(BRANCH,BYTE):
+ know(issbyte(disp));
+ if (disp == 0)
+ as_bad("short branch with zero offset: use :w");
+ fragP->fr_opcode[1]=disp;
+ ext=0;
+ break;
+ case TAB(DBCC,SHORT):
+ know(issword(disp));
+ ext=2;
+ break;
+ case TAB(BCC68000,SHORT):
+ case TAB(BRANCH,SHORT):
+ know(issword(disp));
+ fragP->fr_opcode[1]=0x00;
+ ext=2;
+ break;
+ case TAB(BRANCH,LONG):
+ if (cpu_of_arch(current_architecture) < m68020) {
+ if (fragP->fr_opcode[0] == 0x61) {
+ fragP->fr_opcode[0]= 0x4E;
+ fragP->fr_opcode[1]= 0xB9; /* JBSR with ABSL LONG offset */
+ subseg_change(SEG_TEXT, 0);
+
+ fix_new(fragP,
+ fragP->fr_fix,
+ 4,
+ fragP->fr_symbol,
+ 0,
+ fragP->fr_offset,
+ 0,
+ FIX_NO_RELOC);
+
+ fragP->fr_fix+=4;
+ ext=0;
+ } else if (fragP->fr_opcode[0] == 0x60) {
+ fragP->fr_opcode[0]= 0x4E;
+ fragP->fr_opcode[1]= 0xF9; /* JMP with ABSL LONG offset */
+ subseg_change(SEG_TEXT, 0);
+ fix_new(fragP, fragP->fr_fix, 4, fragP->fr_symbol, 0, fragP->fr_offset,0,
+ FIX_NO_RELOC);
+ fragP->fr_fix+=4;
+ ext=0;
+ } else {
+ as_bad("Long branch offset not supported.");
+ }
+ } else {
+ fragP->fr_opcode[1]=0xff;
+ ext=4;
+ }
+ break;
+ case TAB(BCC68000,LONG):
+ /* only Bcc 68000 instructions can come here */
+ /* change bcc into b!cc/jmp absl long */
+ fragP->fr_opcode[0] ^= 0x01; /* invert bcc */
+ fragP->fr_opcode[1] = 0x6; /* branch offset = 6 */
+
+ /* JF: these used to be fr_opcode[2,3], but they may be in a
+ different frag, in which case refering to them is a no-no.
+ Only fr_opcode[0,1] are guaranteed to work. */
+ *buffer_address++ = 0x4e; /* put in jmp long (0x4ef9) */
+ *buffer_address++ = 0xf9;
+ fragP->fr_fix += 2; /* account for jmp instruction */
+ subseg_change(SEG_TEXT,0);
+ fix_new(fragP, fragP->fr_fix, 4, fragP->fr_symbol, 0,
+ fragP->fr_offset,0,
+ FIX_NO_RELOC);
+ fragP->fr_fix += 4;
+ ext=0;
+ break;
+ case TAB(DBCC,LONG):
+ /* only DBcc 68000 instructions can come here */
+ /* change dbcc into dbcc/jmp absl long */
+ /* JF: these used to be fr_opcode[2-7], but that's wrong */
+ *buffer_address++ = 0x00; /* branch offset = 4 */
+ *buffer_address++ = 0x04;
+ *buffer_address++ = 0x60; /* put in bra pc+6 */
+ *buffer_address++ = 0x06;
+ *buffer_address++ = 0x4e; /* put in jmp long (0x4ef9) */
+ *buffer_address++ = 0xf9;
+
+ fragP->fr_fix += 6; /* account for bra/jmp instructions */
+ subseg_change(SEG_TEXT,0);
+ fix_new(fragP, fragP->fr_fix, 4, fragP->fr_symbol, 0,
+ fragP->fr_offset,0,
+ FIX_NO_RELOC);
+ fragP->fr_fix += 4;
+ ext=0;
+ break;
+ case TAB(FBRANCH,SHORT):
+ know((fragP->fr_opcode[1]&0x40) == 0);
+ ext=2;
+ break;
+ case TAB(FBRANCH,LONG):
+ fragP->fr_opcode[1]|=0x40; /* Turn on LONG bit */
+ ext=4;
+ break;
+ case TAB(PCREL,SHORT):
+ ext=2;
+ break;
+ case TAB(PCREL,LONG):
+ /* The thing to do here is force it to ABSOLUTE LONG, since
+ PCREL is really trying to shorten an ABSOLUTE address anyway */
+ /* JF FOO This code has not been tested */
+ subseg_change(SEG_TEXT,0);
+ fix_new(fragP, fragP->fr_fix, 4, fragP->fr_symbol, 0, fragP->fr_offset, 0, FIX_NO_RELOC);
+ if ((fragP->fr_opcode[1] & 0x3F) != 0x3A)
+ as_bad("Internal error (long PC-relative operand) for insn 0x%04lx at 0x%lx",
+ fragP->fr_opcode[0],fragP->fr_address);
+ fragP->fr_opcode[1]&= ~0x3F;
+ fragP->fr_opcode[1]|=0x39; /* Mode 7.1 */
+ fragP->fr_fix+=4;
+ /* md_number_to_chars(buffer_address,
+ (long)(fragP->fr_symbol->sy_value + fragP->fr_offset),
+ 4); */
+ ext=0;
+ break;
+ case TAB(PCLEA,SHORT):
+ subseg_change(SEG_TEXT,0);
+ fix_new(fragP, (int) (fragP->fr_fix), 2, fragP->fr_symbol, (symbolS *) 0, fragP->fr_offset, 1, FIX_NO_RELOC);
+ fragP->fr_opcode[1] &= ~0x3F;
+ fragP->fr_opcode[1] |= 0x3A;
+ ext=2;
+ break;
+ case TAB(PCLEA,LONG):
+ subseg_change(SEG_TEXT,0);
+ fix_new(fragP, (int) (fragP->fr_fix) + 2, 4, fragP->fr_symbol, (symbolS *) 0, fragP->fr_offset + 2, 1, FIX_NO_RELOC);
+ *buffer_address++ = 0x01;
+ *buffer_address++ = 0x70;
+ fragP->fr_fix+=2;
+ /* buffer_address+=2; */
+ ext=4;
+ break;
+
+} /* switch on subtype */
+
+ if (ext) {
+ md_number_to_chars(buffer_address, (long) disp, (int) ext);
+ fragP->fr_fix += ext;
+ /* H_SET_TEXT_SIZE(headers, H_GET_TEXT_SIZE(headers) + ext); */
+ } /* if extending */
+
+ return;
+} /* md_convert_frag() */
+
+/* Force truly undefined symbols to their maximum size, and generally set up
+ the frag list to be relaxed
+ */
+int md_estimate_size_before_relax(fragP, segment)
+register fragS *fragP;
+segT segment;
+{
+ int old_fix;
+ register char *buffer_address = fragP->fr_fix + fragP->fr_literal;
+
+ old_fix = fragP->fr_fix;
+
+ /* handle SZ_UNDEF first, it can be changed to BYTE or SHORT */
+ switch (fragP->fr_subtype) {
+
+ case TAB(BRANCH,SZ_UNDEF): {
+ if ((fragP->fr_symbol != NULL) /* Not absolute */
+ && S_GET_SEGMENT(fragP->fr_symbol) == segment) {
+ fragP->fr_subtype = TAB(TABTYPE(fragP->fr_subtype), BYTE);
+ break;
+ } else if ((fragP->fr_symbol == 0) || (cpu_of_arch(current_architecture) < m68020)) {
+ /* On 68000, or for absolute value, switch to abs long */
+ /* FIXME, we should check abs val, pick short or long */
+ if (fragP->fr_opcode[0] == 0x61) {
+ fragP->fr_opcode[0]= 0x4E;
+ fragP->fr_opcode[1]= 0xB9; /* JSR with ABSL LONG offset */
+ subseg_change(SEG_TEXT, 0);
+ fix_new(fragP, fragP->fr_fix, 4,
+ fragP->fr_symbol, 0, fragP->fr_offset, 0, FIX_NO_RELOC);
+ fragP->fr_fix+=4;
+ frag_wane(fragP);
+ } else if (fragP->fr_opcode[0] == 0x60) {
+ fragP->fr_opcode[0]= 0x4E;
+ fragP->fr_opcode[1]= 0xF9; /* JMP with ABSL LONG offset */
+ subseg_change(SEG_TEXT, 0);
+ fix_new(fragP, fragP->fr_fix, 4,
+ fragP->fr_symbol, 0, fragP->fr_offset, 0, FIX_NO_RELOC);
+ fragP->fr_fix+=4;
+ frag_wane(fragP);
+ } else {
+ as_warn("Long branch offset to extern symbol not supported.");
+ }
+ } else if (flagseen['l']) { /* Symbol is still undefined. Make it simple */
+ fix_new(fragP, (int) (fragP->fr_fix), 2, fragP->fr_symbol,
+ (symbolS *) 0, fragP->fr_offset, 1, FIX_NO_RELOC);
+ fragP->fr_fix += 2;
+ fragP->fr_opcode[1] = 0x00;
+ frag_wane(fragP);
+ } else {
+ fix_new(fragP, (int) (fragP->fr_fix), 4, fragP->fr_symbol,
+ (symbolS *) 0, fragP->fr_offset, 1,
+#ifdef PIC
+ /* With -k, make all external branches go via the jump table. */
+ (flagseen['k']? RELOC_JMP_TBL: NO_RELOC), NULL
+#else
+ NO_RELOC
+#endif
+ );
+ fragP->fr_fix += 4;
+ fragP->fr_opcode[1] = 0xff;
+ frag_wane(fragP);
+ break;
+ }
+
+ break;
+ } /* case TAB(BRANCH,SZ_UNDEF) */
+
+ case TAB(FBRANCH,SZ_UNDEF): {
+ if (S_GET_SEGMENT(fragP->fr_symbol) == segment || flagseen['l']) {
+ fragP->fr_subtype = TAB(FBRANCH,SHORT);
+ fragP->fr_var += 2;
+ } else {
+ fragP->fr_subtype = TAB(FBRANCH,LONG);
+ fragP->fr_var += 4;
+ }
+ break;
+ } /* TAB(FBRANCH,SZ_UNDEF) */
+
+ case TAB(PCREL,SZ_UNDEF): {
+ if (S_GET_SEGMENT(fragP->fr_symbol) == segment || flagseen['l']) {
+ fragP->fr_subtype = TAB(PCREL,SHORT);
+ fragP->fr_var += 2;
+ } else {
+ fragP->fr_subtype = TAB(PCREL,LONG);
+ fragP->fr_var += 4;
+ }
+ break;
+ } /* TAB(PCREL,SZ_UNDEF) */
+
+ case TAB(BCC68000,SZ_UNDEF): {
+ if ((fragP->fr_symbol != NULL)
+ && S_GET_SEGMENT(fragP->fr_symbol) == segment) {
+ fragP->fr_subtype=TAB(BCC68000,BYTE);
+ break;
+ }
+ /* only Bcc 68000 instructions can come here */
+ /* change bcc into b!cc/jmp absl long */
+ fragP->fr_opcode[0] ^= 0x01; /* invert bcc */
+ if (flagseen['l']) {
+ fragP->fr_opcode[1] = 0x04; /* branch offset = 6 */
+ /* JF: these were fr_opcode[2,3] */
+ buffer_address[0] = 0x4e; /* put in jmp long (0x4ef9) */
+ buffer_address[1] = 0xf8;
+ fragP->fr_fix += 2; /* account for jmp instruction */
+ subseg_change(SEG_TEXT,0);
+ fix_new(fragP, fragP->fr_fix, 2, fragP->fr_symbol, 0,
+ fragP->fr_offset, 0, FIX_NO_RELOC);
+ fragP->fr_fix += 2;
+ } else {
+ fragP->fr_opcode[1] = 0x06; /* branch offset = 6 */
+ /* JF: these were fr_opcode[2,3] */
+ buffer_address[2] = 0x4e; /* put in jmp long (0x4ef9) */
+ buffer_address[3] = 0xf9;
+ fragP->fr_fix += 2; /* account for jmp instruction */
+ subseg_change(SEG_TEXT,0);
+ fix_new(fragP, fragP->fr_fix, 4, fragP->fr_symbol, 0,
+ fragP->fr_offset, 0, FIX_NO_RELOC);
+ fragP->fr_fix += 4;
+ }
+ frag_wane(fragP);
+ break;
+ } /* case TAB(BCC68000,SZ_UNDEF) */
+
+ case TAB(DBCC,SZ_UNDEF): {
+ if (fragP->fr_symbol != NULL && S_GET_SEGMENT(fragP->fr_symbol) == segment) {
+ fragP->fr_subtype=TAB(DBCC,SHORT);
+ fragP->fr_var+=2;
+ break;
+ }
+ /* only DBcc 68000 instructions can come here */
+ /* change dbcc into dbcc/jmp absl long */
+ /* JF: these used to be fr_opcode[2-4], which is wrong. */
+ buffer_address[0] = 0x00; /* branch offset = 4 */
+ buffer_address[1] = 0x04;
+ buffer_address[2] = 0x60; /* put in bra pc + ... */
+
+ if (flagseen['l']) {
+ /* JF: these were fr_opcode[5-7] */
+ buffer_address[3] = 0x04; /* plus 4 */
+ buffer_address[4] = 0x4e;/* Put in Jump Word */
+ buffer_address[5] = 0xf8;
+ fragP->fr_fix += 6; /* account for bra/jmp instruction */
+ subseg_change(SEG_TEXT,0);
+ fix_new(fragP, fragP->fr_fix, 2, fragP->fr_symbol, 0,
+ fragP->fr_offset, 0, FIX_NO_RELOC);
+ fragP->fr_fix += 2;
+ } else {
+ /* JF: these were fr_opcode[5-7] */
+ buffer_address[3] = 0x06; /* Plus 6 */
+ buffer_address[4] = 0x4e; /* put in jmp long (0x4ef9) */
+ buffer_address[5] = 0xf9;
+ fragP->fr_fix += 6; /* account for bra/jmp instruction */
+ subseg_change(SEG_TEXT,0);
+ fix_new(fragP, fragP->fr_fix, 4, fragP->fr_symbol, 0,
+ fragP->fr_offset, 0, FIX_NO_RELOC);
+ fragP->fr_fix += 4;
+ }
+
+ frag_wane(fragP);
+ break;
+ } /* case TAB(DBCC,SZ_UNDEF) */
+
+ case TAB(PCLEA,SZ_UNDEF): {
+ if ((S_GET_SEGMENT(fragP->fr_symbol)) == segment || flagseen['l']) {
+ fragP->fr_subtype=TAB(PCLEA,SHORT);
+ fragP->fr_var+=2;
+ } else {
+ fragP->fr_subtype=TAB(PCLEA,LONG);
+ fragP->fr_var+=6;
+ }
+ break;
+ } /* TAB(PCLEA,SZ_UNDEF) */
+
+ default:
+ break;
+
+ } /* switch on subtype looking for SZ_UNDEF's. */
+
+ /* now that SZ_UNDEF are taken care of, check others */
+ switch (fragP->fr_subtype) {
+ case TAB(BCC68000,BYTE):
+ case TAB(BRANCH,BYTE):
+ /* We can't do a short jump to the next instruction,
+ so we force word mode. */
+ if (fragP->fr_symbol && S_GET_VALUE(fragP->fr_symbol) == 0 &&
+ fragP->fr_symbol->sy_frag == fragP->fr_next) {
+ fragP->fr_subtype=TAB(TABTYPE(fragP->fr_subtype),SHORT);
+ fragP->fr_var+=2;
+ }
+ break;
+ default:
+ break;
+}
+ return fragP->fr_var + fragP->fr_fix - old_fix;
+}
+
+#if defined(OBJ_AOUT) | defined(OBJ_BOUT)
+/* the bit-field entries in the relocation_info struct plays hell
+ with the byte-order problems of cross-assembly. So as a hack,
+ I added this mach. dependent ri twiddler. Ugly, but it gets
+ you there. -KWK */
+/* on m68k: first 4 bytes are normal unsigned long, next three bytes
+ are symbolnum, most sig. byte first. Last byte is broken up with
+ bit 7 as pcrel, bits 6 & 5 as length, bit 4 as pcrel, and the lower
+ nibble as nuthin. (on Sun 3 at least) */
+/* Translate the internal relocation information into target-specific
+ format. */
+#ifdef comment
+void
+ md_ri_to_chars(the_bytes, ri)
+char *the_bytes;
+struct reloc_info_generic *ri;
+{
+ /* this is easy */
+ md_number_to_chars(the_bytes, ri->r_address, 4);
+ /* now the fun stuff */
+ the_bytes[4] = (ri->r_symbolnum >> 16) & 0x0ff;
+ the_bytes[5] = (ri->r_symbolnum >> 8) & 0x0ff;
+ the_bytes[6] = ri->r_symbolnum & 0x0ff;
+ the_bytes[7] = (((ri->r_pcrel << 7) & 0x80) | ((ri->r_length << 5) & 0x60) |
+ ((ri->r_extern << 4) & 0x10));
+}
+#endif /* comment */
+
+void tc_aout_fix_to_chars(where, fixP, segment_address_in_file)
+char *where;
+fixS *fixP;
+relax_addressT segment_address_in_file;
+{
+ /*
+ * In: length of relocation (or of address) in chars: 1, 2 or 4.
+ * Out: GNU LD relocation length code: 0, 1, or 2.
+ */
+
+ static unsigned char nbytes_r_length[] = { 42, 0, 1, 42, 2 };
+ long r_symbolnum;
+ int r_flags;
+
+ know(fixP->fx_addsy != NULL);
+
+ md_number_to_chars(where,
+ fixP->fx_frag->fr_address + fixP->fx_where - segment_address_in_file,
+ 4);
+
+ r_symbolnum = (S_IS_DEFINED(fixP->fx_addsy)
+ ? S_GET_TYPE(fixP->fx_addsy)
+ : fixP->fx_addsy->sy_number);
+ r_flags = (fixP->fx_pcrel? 0x80: 0)
+ | ((nbytes_r_length[fixP->fx_size] & 3) << 5)
+ | (!S_IS_DEFINED(fixP->fx_addsy)? 0x10: 0);
+
+#ifdef PIC
+ switch (fixP->fx_r_type) {
+ case NO_RELOC:
+ break;
+ case RELOC_32:
+ if (flagseen['k'] && S_IS_EXTERNAL(fixP->fx_addsy)) {
+ r_symbolnum = fixP->fx_addsy->sy_number;
+ r_flags |= 0x10; /* set extern bit */
+ }
+ break;
+ case RELOC_GLOB_DAT:
+ r_flags |= 8; /* set baserel bit */
+ r_symbolnum = fixP->fx_addsy->sy_number;
+ if (S_IS_EXTERNAL(fixP->fx_addsy))
+ r_flags |= 0x10;
+ break;
+ case RELOC_JMP_TBL:
+ r_flags |= 4; /* set jmptable bit */
+ break;
+ case RELOC_RELATIVE:
+ /* should never happen */
+ r_flags |= 2; /* set relative bit */
+ break;
+ }
+#endif /* PIC */
+
+ where[4] = (r_symbolnum >> 16) & 0x0ff;
+ where[5] = (r_symbolnum >> 8) & 0x0ff;
+ where[6] = r_symbolnum & 0x0ff;
+ where[7] = r_flags;
+
+ return;
+} /* tc_aout_fix_to_chars() */
+
+#endif /* OBJ_AOUT or OBJ_BOUT */
+
+#ifndef WORKING_DOT_WORD
+const int md_short_jump_size = 4;
+const int md_long_jump_size = 6;
+
+void
+ md_create_short_jump(ptr,from_addr,to_addr,frag,to_symbol)
+char *ptr;
+long from_addr,
+ to_addr;
+fragS *frag;
+symbolS *to_symbol;
+{
+ long offset;
+
+ offset = to_addr - (from_addr+2);
+
+ md_number_to_chars(ptr ,(long)0x6000,2);
+ md_number_to_chars(ptr+2,(long)offset,2);
+}
+
+void
+ md_create_long_jump(ptr,from_addr,to_addr,frag,to_symbol)
+char *ptr;
+long from_addr,
+ to_addr;
+fragS *frag;
+symbolS *to_symbol;
+{
+ long offset;
+
+ if (cpu_of_arch(current_architecture) < m68020) {
+ offset=to_addr-S_GET_VALUE(to_symbol);
+ md_number_to_chars(ptr ,(long)0x4EF9,2);
+ md_number_to_chars(ptr+2,(long)offset,4);
+ fix_new(frag,(ptr+2)-frag->fr_literal,4,to_symbol,(symbolS *)0,(long)0,0,
+ FIX_NO_RELOC);
+ } else {
+ offset=to_addr - (from_addr+2);
+ md_number_to_chars(ptr ,(long)0x60ff,2);
+ md_number_to_chars(ptr+2,(long)offset,4);
+ }
+}
+
+#endif
+/* Different values of OK tell what its OK to return. Things that aren't OK are an error (what a shock, no?)
+
+ 0: Everything is OK
+ 10: Absolute 1:8 only
+ 20: Absolute 0:7 only
+ 30: absolute 0:15 only
+ 40: Absolute 0:31 only
+ 50: absolute 0:127 only
+ 55: absolute -64:63 only
+ 60: absolute -128:127 only
+ 70: absolute 0:4095 only
+ 80: No bignums
+
+ */
+
+static int get_num(exp,ok)
+struct m68k_exp *exp;
+int ok;
+{
+#ifdef TEST2
+ long l = 0;
+
+ if (!exp->e_beg)
+ return 0;
+ if (*exp->e_beg == '0') {
+ if (exp->e_beg[1] == 'x')
+ sscanf(exp->e_beg+2,"%x",&l);
+ else
+ sscanf(exp->e_beg+1,"%O",&l);
+ return l;
+ }
+ return atol(exp->e_beg);
+#else
+ char *save_in;
+ char c_save;
+
+ if (!exp) {
+ /* Can't do anything */
+ return 0;
+ }
+ if (!exp->e_beg || !exp->e_end) {
+ seg(exp)=SEG_ABSOLUTE;
+ adds(exp)=0;
+ subs(exp)=0;
+ offs(exp)= (ok == 10) ? 1 : 0;
+ as_warn("Null expression defaults to %ld",offs(exp));
+ return 0;
+ }
+
+ exp->e_siz=0;
+ if (/* ok != 80 && */exp->e_end[-1] == ':' && (exp->e_end-exp->e_beg) >= 2) {
+ switch (exp->e_end[0]) {
+ case 's':
+ case 'S':
+ case 'b':
+ case 'B':
+ exp->e_siz=1;
+ break;
+ case 'w':
+ case 'W':
+ exp->e_siz=2;
+ break;
+ case 'l':
+ case 'L':
+ exp->e_siz=3;
+ break;
+ default:
+ as_bad("Unknown size for expression \"%c\"",exp->e_end[0]);
+ }
+ exp->e_end-=2;
+ }
+ c_save=exp->e_end[1];
+ exp->e_end[1]='\0';
+ save_in=input_line_pointer;
+ input_line_pointer=exp->e_beg;
+ switch (expression(&(exp->e_exp))) {
+ case SEG_PASS1:
+ seg(exp)=SEG_ABSOLUTE;
+ adds(exp)=0;
+ subs(exp)=0;
+ offs(exp)= (ok == 10) ? 1 : 0;
+ as_warn("Unknown expression: '%s' defaulting to %d",exp->e_beg,offs(exp));
+ break;
+
+ case SEG_ABSENT:
+ /* Do the same thing the VAX asm does */
+ seg(exp)=SEG_ABSOLUTE;
+ adds(exp)=0;
+ subs(exp)=0;
+ offs(exp)=0;
+ if (ok == 10) {
+ as_warn("expression out of range: defaulting to 1");
+ offs(exp)=1;
+ }
+ break;
+ case SEG_ABSOLUTE:
+ switch (ok) {
+ case 10:
+ if (offs(exp)<1 || offs(exp)>8) {
+ as_warn("expression out of range: defaulting to 1");
+ offs(exp)=1;
+ }
+ break;
+ case 20:
+ if (offs(exp)<0 || offs(exp)>7)
+ goto outrange;
+ break;
+ case 30:
+ if (offs(exp)<0 || offs(exp)>15)
+ goto outrange;
+ break;
+ case 40:
+ if (offs(exp)<0 || offs(exp)>32)
+ goto outrange;
+ break;
+ case 50:
+ if (offs(exp)<0 || offs(exp)>127)
+ goto outrange;
+ break;
+ case 55:
+ if (offs(exp)<-64 || offs(exp)>63)
+ goto outrange;
+ break;
+ case 60:
+ if (offs(exp)<-128 || offs(exp)>127)
+ goto outrange;
+ break;
+ case 70:
+ if (offs(exp)<0 || offs(exp)>4095) {
+ outrange:
+ as_warn("expression out of range: defaulting to 0");
+ offs(exp)=0;
+ }
+ break;
+ default:
+ break;
+ }
+ break;
+ case SEG_TEXT:
+ case SEG_DATA:
+ case SEG_BSS:
+ case SEG_UNKNOWN:
+ case SEG_DIFFERENCE:
+ if (ok >= 10 && ok <= 70) {
+ seg(exp)=SEG_ABSOLUTE;
+ adds(exp)=0;
+ subs(exp)=0;
+ offs(exp)= (ok == 10) ? 1 : 0;
+ as_warn("Can't deal with expression \"%s\": defaulting to %ld",exp->e_beg,offs(exp));
+ }
+ break;
+ case SEG_BIG:
+ if (ok == 80 && offs(exp)<0) { /* HACK! Turn it into a long */
+ LITTLENUM_TYPE words[6];
+
+ gen_to_words(words,2,8L);/* These numbers are magic! */
+ seg(exp)=SEG_ABSOLUTE;
+ adds(exp)=0;
+ subs(exp)=0;
+ offs(exp)=words[1]|(words[0]<<16);
+ } else if (ok != 0) {
+ seg(exp)=SEG_ABSOLUTE;
+ adds(exp)=0;
+ subs(exp)=0;
+ offs(exp)= (ok == 10) ? 1 : 0;
+ as_warn("Can't deal with expression \"%s\": defaulting to %ld",exp->e_beg,offs(exp));
+ }
+ break;
+ default:
+ as_fatal("failed sanity check.");
+ }
+ if (input_line_pointer != exp->e_end+1)
+ as_bad("Ignoring junk after expression");
+ exp->e_end[1]=c_save;
+ input_line_pointer=save_in;
+ if (exp->e_siz) {
+ switch (exp->e_siz) {
+ case 1:
+ if (!isbyte(offs(exp)))
+ as_warn("expression doesn't fit in BYTE");
+ break;
+ case 2:
+ if (!isword(offs(exp)))
+ as_warn("expression doesn't fit in WORD");
+ break;
+ }
+ }
+ return offs(exp);
+#endif
+} /* get_num() */
+
+/* These are the back-ends for the various machine dependent pseudo-ops. */
+void demand_empty_rest_of_line(); /* Hate those extra verbose names */
+
+static void s_data1() {
+ subseg_new(SEG_DATA,1);
+ demand_empty_rest_of_line();
+} /* s_data1() */
+
+static void s_data2() {
+ subseg_new(SEG_DATA,2);
+ demand_empty_rest_of_line();
+} /* s_data2() */
+
+static void s_bss() {
+ /* We don't support putting frags in the BSS segment, but we
+ can put them into initialized data for now... */
+ subseg_new(SEG_DATA,255); /* FIXME-SOON */
+ demand_empty_rest_of_line();
+} /* s_bss() */
+
+static void s_even() {
+ register int temp;
+ register long temp_fill;
+
+ temp = 1; /* JF should be 2? */
+ temp_fill = get_absolute_expression ();
+ if ( ! need_pass_2 ) /* Never make frag if expect extra pass. */
+ frag_align (temp, (int)temp_fill);
+ demand_empty_rest_of_line();
+} /* s_even() */
+
+static void s_proc() {
+ demand_empty_rest_of_line();
+} /* s_proc() */
+
+/* s_space is defined in read.c .skip is simply an alias to it. */
+
+/*
+ * md_parse_option
+ * Invocation line includes a switch not recognized by the base assembler.
+ * See if it's a processor-specific option. These are:
+ *
+ * -[A]m[c]68000, -[A]m[c]68008, -[A]m[c]68010, -[A]m[c]68020, -[A]m[c]68030, -[A]m[c]68040
+ * -[A]m[c]68881, -[A]m[c]68882, -[A]m[c]68851
+ * Select the architecture. Instructions or features not
+ * supported by the selected architecture cause fatal
+ * errors. More than one may be specified. The default is
+ * -m68020 -m68851 -m68881. Note that -m68008 is a synonym
+ * for -m68000, and -m68882 is a synonym for -m68881.
+ *
+ * MAYBE_FLOAT_TOO is defined below so that specifying a processor type
+ * (e.g. m68020) also requests that float instructions be included. This
+ * is the default setup, mostly to avoid hassling users. A better
+ * rearrangement of this structure would be to add an option to DENY
+ * floating point opcodes, for people who want to really know there's none
+ * of that funny floaty stuff going on. FIXME-later.
+ */
+#ifndef MAYBE_FLOAT_TOO
+#define MAYBE_FLOAT_TOO m68881
+#endif
+
+int md_parse_option(argP,cntP,vecP)
+char **argP;
+int *cntP;
+char ***vecP;
+{
+ switch (**argP) {
+ case 'l': /* -l means keep external to 2 bit offset
+ rather than 16 bit one */
+ break;
+
+ case 'S': /* -S means that jbsr's always turn into jsr's. */
+ break;
+
+ case 'A':
+ (*argP)++;
+ /* intentional fall-through */
+ case 'm':
+ (*argP)++;
+
+ if (**argP == 'c') {
+ (*argP)++;
+ } /* allow an optional "c" */
+
+ if (!strcmp(*argP, "68000")
+ || !strcmp(*argP, "68008")) {
+ current_architecture |= m68000;
+ } else if (!strcmp(*argP, "68010")) {
+#ifdef TE_SUN
+ omagic= 1<<16|OMAGIC;
+#endif
+ current_architecture |= m68010;
+
+ } else if (!strcmp(*argP, "68020")) {
+ current_architecture |= m68020 | MAYBE_FLOAT_TOO;
+
+ } else if (!strcmp(*argP, "68030")) {
+ current_architecture |= m68030 | MAYBE_FLOAT_TOO;
+
+ } else if (!strcmp(*argP, "68040")) {
+ current_architecture |= m68040 | MAYBE_FLOAT_TOO;
+
+#ifndef NO_68881
+ } else if (!strcmp(*argP, "68881")) {
+ current_architecture |= m68881;
+
+ } else if (!strcmp(*argP, "68882")) {
+ current_architecture |= m68882;
+
+#endif /* NO_68881 */
+#ifndef NO_68851
+ } else if (!strcmp(*argP,"68851")) {
+ current_architecture |= m68851;
+
+#endif /* NO_68851 */
+ } else {
+ as_warn("Unknown architecture, \"%s\". option ignored", *argP);
+ } /* switch on architecture */
+
+ while (**argP) (*argP)++;
+
+ break;
+
+ case 'p':
+ if (!strcmp(*argP,"pic")) {
+ (*argP) += 3;
+ break; /* -pic, Position Independent Code */
+ } else {
+ return(0);
+ } /* pic or not */
+
+#ifdef PIC
+ case 'k':
+ /* Predefine GOT symbol */
+ GOT_symbol = symbol_find_or_make("__GLOBAL_OFFSET_TABLE_");
+ break;
+#endif /* PIC */
+
+ default:
+ return 0;
+ }
+ return 1;
+}
+
+
+#ifdef TEST2
+
+/* TEST2: Test md_assemble() */
+/* Warning, this routine probably doesn't work anymore */
+
+main()
+{
+ struct m68k_it the_ins;
+ char buf[120];
+ char *cp;
+ int n;
+
+ m68k_ip_begin();
+ for (;;) {
+ if (!gets(buf) || !*buf)
+ break;
+ if (buf[0] == '|' || buf[1] == '.')
+ continue;
+ for (cp=buf;*cp;cp++)
+ if (*cp == '\t')
+ *cp=' ';
+ if (is_label(buf))
+ continue;
+ memset(&the_ins, '\0', sizeof(the_ins));
+ m68k_ip(&the_ins,buf);
+ if (the_ins.error) {
+ printf("Error %s in %s\n",the_ins.error,buf);
+ } else {
+ printf("Opcode(%d.%s): ",the_ins.numo,the_ins.args);
+ for (n=0;n<the_ins.numo;n++)
+ printf(" 0x%x",the_ins.opcode[n]&0xffff);
+ printf(" ");
+ print_the_insn(&the_ins.opcode[0],stdout);
+ (void)putchar('\n');
+ }
+ for (n=0;n<strlen(the_ins.args)/2;n++) {
+ if (the_ins.operands[n].error) {
+ printf("op%d Error %s in %s\n",n,the_ins.operands[n].error,buf);
+ continue;
+ }
+ printf("mode %d, reg %d, ",the_ins.operands[n].mode,the_ins.operands[n].reg);
+ if (the_ins.operands[n].b_const)
+ printf("Constant: '%.*s', ",1+the_ins.operands[n].e_const-the_ins.operands[n].b_const,the_ins.operands[n].b_const);
+ printf("ireg %d, isiz %d, imul %d, ",the_ins.operands[n].ireg,the_ins.operands[n].isiz,the_ins.operands[n].imul);
+ if (the_ins.operands[n].b_iadd)
+ printf("Iadd: '%.*s',",1+the_ins.operands[n].e_iadd-the_ins.operands[n].b_iadd,the_ins.operands[n].b_iadd);
+ (void)putchar('\n');
+ }
+ }
+ m68k_ip_end();
+ return 0;
+}
+
+is_label(str)
+char *str;
+{
+ while (*str == ' ')
+ str++;
+ while (*str && *str != ' ')
+ str++;
+ if (str[-1] == ':' || str[1] == '=')
+ return 1;
+ return 0;
+}
+
+#endif
+
+/* Possible states for relaxation:
+
+ 0 0 branch offset byte (bra, etc)
+ 0 1 word
+ 0 2 long
+
+ 1 0 indexed offsets byte a0@(32,d4:w:1) etc
+ 1 1 word
+ 1 2 long
+
+ 2 0 two-offset index word-word a0@(32,d4)@(45) etc
+ 2 1 word-long
+ 2 2 long-word
+ 2 3 long-long
+
+ */
+
+
+
+#ifdef DONTDEF
+abort()
+{
+ printf("ABORT!\n");
+ exit(12);
+}
+
+print_frags()
+{
+ fragS *fragP;
+ extern fragS *text_frag_root;
+
+ for (fragP=text_frag_root;fragP;fragP=fragP->fr_next) {
+ printf("addr %lu next 0x%x fix %ld var %ld symbol 0x%x offset %ld\n",
+ fragP->fr_address,fragP->fr_next,fragP->fr_fix,fragP->fr_var,fragP->fr_symbol,fragP->fr_offset);
+ printf("opcode 0x%x type %d subtype %d\n\n",fragP->fr_opcode,fragP->fr_type,fragP->fr_subtype);
+ }
+ fflush(stdout);
+ return 0;
+}
+#endif
+
+
+/* We have no need to default values of symbols. */
+
+/* ARGSUSED */
+symbolS *
+ md_undefined_symbol (name)
+char *name;
+{
+ return 0;
+}
+
+/* Parse an operand that is machine-specific.
+ We just return without modifying the expression if we have nothing
+ to do. */
+
+/* ARGSUSED */
+void
+ md_operand (expressionP)
+expressionS *expressionP;
+{
+}
+
+/* Round up a section size to the appropriate boundary. */
+long
+ md_section_align (segment, size)
+segT segment;
+long size;
+{
+ return size; /* Byte alignment is fine */
+}
+
+/* Exactly what point is a PC-relative offset relative TO?
+ On the 68k, they're relative to the address of the offset. */
+long
+ md_pcrel_from (fixP)
+fixS *fixP;
+{
+ return(fixP->fx_where + fixP->fx_frag->fr_address);
+}
+
+/*
+ * Local Variables:
+ * comment-column: 0
+ * fill-column: 131
+ * End:
+ */
+
+/* end of tc-m68k.c */
diff --git a/gnu/usr.bin/as/config/tc-m68k.h b/gnu/usr.bin/as/config/tc-m68k.h
new file mode 100644
index 0000000..33d8d96
--- /dev/null
+++ b/gnu/usr.bin/as/config/tc-m68k.h
@@ -0,0 +1,62 @@
+/* This file is tc-m68k.h
+
+ Copyright (C) 1987-1992 Free Software Foundation, Inc.
+
+ This file is part of GAS, the GNU Assembler.
+
+ GAS is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GAS is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GAS; see the file COPYING. If not, write to
+ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/*
+ * This file is tp-generic.h and is intended to be a template for
+ * target processor specific header files.
+ */
+
+#define MID_M68K 135
+#define MID_M68K4K 136
+#include <machine/param.h>
+
+#define TC_M68K 1
+
+#ifdef OLD_GAS
+#define REVERSE_SORT_RELOCS
+#endif /* OLD_GAS */
+
+#define AOUT_MACHTYPE MID_MACHINE
+#define LOCAL_LABELS_FB
+
+#define tc_crawl_symbol_chain(a) {;} /* not used */
+#define tc_headers_hook(a) {;} /* not used */
+#define tc_aout_pre_write_hook(x) {;} /* not used */
+
+#define LISTING_WORD_SIZE 2 /* A word is 2 bytes */
+#define LISTING_LHS_WIDTH 2 /* One word on the first line */
+#define LISTING_LHS_WIDTH_SECOND 2 /* One word on the second line */
+#define LISTING_LHS_CONT_LINES 4 /* And 4 lines max */
+#define LISTING_HEADER "68K GAS "
+
+/* Copied from write.c */
+#define M68K_AIM_KLUDGE(aim, this_state,this_type) \
+ if (aim == 0 && this_state == 4) { /* hard encoded from tc-m68k.c */ \
+ aim=this_type->rlx_forward+1; /* Force relaxation into word mode */ \
+ }
+
+/*
+ * Local Variables:
+ * comment-column: 0
+ * fill-column: 131
+ * End:
+ */
+
+/* end of tc-m68k.h */
diff --git a/gnu/usr.bin/as/config/tc-m68kmote.h b/gnu/usr.bin/as/config/tc-m68kmote.h
new file mode 100644
index 0000000..70afae3
--- /dev/null
+++ b/gnu/usr.bin/as/config/tc-m68kmote.h
@@ -0,0 +1,64 @@
+/* This file is tc-m68kmote.h
+
+ Copyright (C) 1987-1992 Free Software Foundation, Inc.
+
+ This file is part of GAS, the GNU Assembler.
+
+ GAS is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GAS is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GAS; see the file COPYING. If not, write to
+ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/*
+ * This file is tp-generic.h and is intended to be a template for
+ * target processor specific header files.
+ */
+
+#define TC_M68K 1
+
+#ifdef TE_SUN3
+/* This variable contains the value to write out at the beginning of
+ the a.out file. The 2<<16 means that this is a 68020 file instead
+ of an old-style 68000 file */
+
+#define DEFAULT_MAGIC_NUMBER_FOR_OBJECT_FILE (2<<16|OMAGIC); /* Magic byte for file header */
+#endif /* TE_SUN3 */
+
+#define AOUT_MACHTYPE 0x2
+#define REVERSE_SORT_RELOCS /* FIXME-NOW: this line can be removed. */
+#define LOCAL_LABELS_FB
+
+#define tc_crawl_symbol_chain(a) {;} /* not used */
+#define tc_headers_hook(a) {;} /* not used */
+#define tc_aout_pre_write_hook(x) {;} /* not used */
+
+#define LISTING_WORD_SIZE 2 /* A word is 2 bytes */
+#define LISTING_LHS_WIDTH 3 /* 3 word on the first line */
+#define LISTING_LHS_WIDTH_SECOND 3 /* One word on the second line */
+#define LISTING_LHS_CONT_LINES 4 /* And 4 lines max */
+#define LISTING_HEADER "68K GAS "
+
+/* Copied from write.c */
+#define M68K_AIM_KLUDGE(aim, this_state,this_type) \
+ if (aim == 0 && this_state == 4) { /* hard encoded from tc-m68k.c */ \
+ aim=this_type->rlx_forward+1; /* Force relaxation into word mode */ \
+ }
+#define MRI
+
+/*
+ * Local Variables:
+ * comment-column: 0
+ * fill-column: 131
+ * End:
+ */
+
+/* end of tc-m68kmote.h */
diff --git a/gnu/usr.bin/as/config/tc-m88k.c b/gnu/usr.bin/as/config/tc-m88k.c
new file mode 100644
index 0000000..34c6ba3
--- /dev/null
+++ b/gnu/usr.bin/as/config/tc-m88k.c
@@ -0,0 +1,1435 @@
+/* m88k.c -- Assembler for the Motorola 88000
+ Contributed by Devon Bowen of Buffalo University
+ and Torbjorn Granlund of the Swedish Institute of Computer Science.
+ Copyright (C) 1989-1992 Free Software Foundation, Inc.
+
+ This file is part of GAS, the GNU Assembler.
+
+ GAS is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GAS is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GAS; see the file COPYING. If not, write to
+ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "as.h"
+#include "opcode/m88k.h"
+
+struct m88k_insn
+{
+ unsigned long opcode;
+ expressionS exp;
+ enum reloc_type reloc;
+};
+
+#if __STDC__ == 1
+
+static int calcop(struct m88k_opcode *format, char *param, struct m88k_insn *insn);
+
+#else /* not __STDC__ */
+
+static int calcop();
+
+#endif /* not __STDC__ */
+
+char *getval ();
+char *get_reg ();
+char *get_imm16 ();
+char *get_bf ();
+char *get_pcr ();
+char *get_cmp ();
+char *get_cnd ();
+char *get_cr ();
+char *get_fcr ();
+char *get_vec9 ();
+
+struct field_val_assoc
+{
+ char *name;
+ unsigned val;
+};
+
+struct field_val_assoc cr_regs[] =
+{
+ {"PID", 0},
+ {"PSR", 1},
+ {"EPSR", 2},
+ {"SSBR", 3},
+ {"SXIP", 4},
+ {"SNIP", 5},
+ {"SFIP", 6},
+ {"VBR", 7},
+ {"DMT0", 8},
+ {"DMD0", 9},
+ {"DMA0", 10},
+ {"DMT1", 11},
+ {"DMD1", 12},
+ {"DMA1", 13},
+ {"DMT2", 14},
+ {"DMD2", 15},
+ {"DMA2", 16},
+ {"SR0", 17},
+ {"SR1", 18},
+ {"SR2", 19},
+ {"SR3", 20},
+
+ {NULL, 0},
+};
+
+struct field_val_assoc fcr_regs[] =
+{
+ {"FPECR", 0},
+ {"FPHS1", 1},
+ {"FPLS1", 2},
+ {"FPHS2", 3},
+ {"FPLS2", 4},
+ {"FPPT", 5},
+ {"FPRH", 6},
+ {"FPRL", 7},
+ {"FPIT", 8},
+
+ {"FPSR", 62},
+ {"FPCR", 63},
+
+ {NULL, 0},
+};
+
+struct field_val_assoc cmpslot[] =
+{
+/* Integer Floating point */
+ {"nc", 0},
+ {"cp", 1},
+ {"eq", 2},
+ {"ne", 3},
+ {"gt", 4},
+ {"le", 5},
+ {"lt", 6},
+ {"ge", 7},
+ {"hi", 8}, {"ou", 8},
+ {"ls", 9}, {"ib", 9},
+ {"lo", 10}, {"in", 10},
+ {"hs", 11}, {"ob", 11},
+
+ {NULL, 0},
+};
+
+struct field_val_assoc cndmsk[] =
+{
+ {"gt0", 1},
+ {"eq0", 2},
+ {"ge0", 3},
+ {"lt0", 12},
+ {"ne0", 13},
+ {"le0", 14},
+
+ {NULL, 0},
+};
+
+extern char *myname;
+static struct hash_control *op_hash = NULL;
+
+/* These bits should be turned off in the first address of every segment */
+int md_seg_align = 7;
+
+/* This is the number to put at the beginning of the a.out file */
+long omagic = OMAGIC;
+
+/* These chars start a comment anywhere in a source file (except inside
+ another comment */
+char comment_chars[] = ";";
+
+/* These chars only start a comment at the beginning of a line. */
+char line_comment_chars[] = "#";
+
+/* Chars that can be used to separate mant from exp in floating point nums */
+char EXP_CHARS[] = "eE";
+
+/* Chars that mean this number is a floating point constant */
+/* as in 0f123.456 */
+/* or 0H1.234E-12 (see exp chars above) */
+char FLT_CHARS[] = "dDfF";
+
+extern void float_cons (), cons (), s_globl (), s_line (),
+ s_space (), s_set (), stringer (), s_lcomm ();
+static void s_bss ();
+
+const pseudo_typeS md_pseudo_table[] = {
+ {"align", s_align_bytes, 0 },
+ {"def", s_set, 0},
+ {"dfloat", float_cons, 'd'},
+ {"ffloat", float_cons, 'f'},
+ {"global", s_globl, 0},
+ {"half", cons, 2 },
+ {"bss", s_bss, 0},
+ {"string", stringer, 0},
+ {"word", cons, 4 },
+ {"zero", s_space, 0},
+ {0}
+};
+
+const int md_reloc_size = 12; /* Size of relocation record */
+
+void
+md_begin ()
+{
+ char *retval = NULL;
+ unsigned int i = 0;
+
+ /* initialize hash table */
+
+ op_hash = hash_new ();
+ if (op_hash == NULL)
+ as_fatal ("Could not initialize hash table");
+
+ /* loop until you see the end of the list */
+
+ while (*m88k_opcodes[i].name)
+ {
+ char *name = m88k_opcodes[i].name;
+
+ /* hash each mnemonic and record its position */
+
+ retval = hash_insert (op_hash, name, &m88k_opcodes[i]);
+
+ if (retval != NULL && *retval != '\0')
+ as_fatal ("Can't hash instruction '%s':%s",
+ m88k_opcodes[i].name, retval);
+
+ /* skip to next unique mnemonic or end of list */
+
+ for (i++; !strcmp (m88k_opcodes[i].name, name); i++)
+ ;
+ }
+}
+
+int
+md_parse_option (argP, cntP, vecP)
+ char **argP;
+ int *cntP;
+ char ***vecP;
+{
+ as_warn ("unknown option: -%s", *argP);
+ return(0);
+}
+
+void
+md_assemble (op)
+ char *op;
+{
+ char *param, *thisfrag;
+ struct m88k_opcode *format;
+ struct m88k_insn insn;
+
+ assert (op);
+
+ /* skip over instruction to find parameters */
+
+ for (param = op; *param != 0 && !isspace (*param); param++)
+ ;
+ if (*param != 0)
+ *param++ = 0;
+
+ /* try to find the instruction in the hash table */
+
+ if ((format = (struct m88k_opcode *) hash_find (op_hash, op)) == NULL)
+ {
+ as_fatal ("Invalid mnemonic '%s'", op);
+ return;
+ }
+
+ /* try parsing this instruction into insn */
+
+ insn.exp.X_add_symbol = 0;
+ insn.exp.X_subtract_symbol = 0;
+ insn.exp.X_add_number = 0;
+ insn.exp.X_seg = 0;
+ insn.reloc = NO_RELOC;
+
+ while (!calcop(format, param, &insn))
+ {
+ /* if it doesn't parse try the next instruction */
+
+ if (!strcmp (format[0].name, format[1].name))
+ format++;
+ else
+ {
+ as_fatal ("Parameter syntax error");
+ return;
+ }
+ }
+
+ /* grow the current frag and plop in the opcode */
+
+ thisfrag = frag_more (4);
+ md_number_to_chars (thisfrag, insn.opcode, 4);
+
+ /* if this instruction requires labels mark it for later */
+
+ switch (insn.reloc)
+ {
+ case NO_RELOC:
+ break;
+
+ case RELOC_LO16:
+ case RELOC_HI16:
+ fix_new (frag_now,
+ thisfrag - frag_now->fr_literal + 2,
+ 2,
+ insn.exp.X_add_symbol,
+ insn.exp.X_subtract_symbol,
+ insn.exp.X_add_number,
+ 0,
+ insn.reloc);
+ break;
+
+ case RELOC_IW16:
+ fix_new (frag_now,
+ thisfrag - frag_now->fr_literal,
+ 4,
+ insn.exp.X_add_symbol,
+ insn.exp.X_subtract_symbol,
+ insn.exp.X_add_number,
+ 0,
+ insn.reloc);
+ break;
+
+ case RELOC_PC16:
+ fix_new (frag_now,
+ thisfrag - frag_now->fr_literal + 2,
+ 2,
+ insn.exp.X_add_symbol,
+ insn.exp.X_subtract_symbol,
+ insn.exp.X_add_number,
+ 1,
+ insn.reloc);
+ break;
+
+ case RELOC_PC26:
+ fix_new (frag_now,
+ thisfrag - frag_now->fr_literal,
+ 4,
+ insn.exp.X_add_symbol,
+ insn.exp.X_subtract_symbol,
+ insn.exp.X_add_number,
+ 1,
+ insn.reloc);
+ break;
+
+ default:
+ as_fatal ("Unknown relocation type");
+ break;
+ }
+}
+
+int
+calcop (format, param, insn)
+ struct m88k_opcode *format;
+ char *param;
+ struct m88k_insn *insn;
+{
+ char *fmt = format->op_spec;
+ int f;
+ unsigned val;
+ unsigned opcode;
+
+ insn->opcode = format->opcode;
+ opcode = 0;
+
+ for (;;)
+ {
+ if (param == 0)
+ return 0;
+ f = *fmt++;
+ switch (f)
+ {
+ case 0:
+ insn->opcode |= opcode;
+ return *param == 0;
+
+ default:
+ if (f != *param++)
+ return 0;
+ break;
+
+ case 'd':
+ param = get_reg (param, &val);
+ opcode |= val << 21;
+ break;
+
+ case '1':
+ param = get_reg (param, &val);
+ opcode |= val << 16;
+ break;
+
+ case '2':
+ param = get_reg (param, &val);
+ opcode |= val;
+ break;
+
+ case '3':
+ param = get_reg (param, &val);
+ opcode |= (val << 16) | val;
+ break;
+
+ case 'I':
+ param = get_imm16 (param, insn);
+ break;
+
+ case 'b':
+ param = get_bf (param, &val);
+ opcode |= val;
+ break;
+
+ case 'p':
+ param = get_pcr (param, insn, RELOC_PC16);
+ break;
+
+ case 'P':
+ param = get_pcr (param, insn, RELOC_PC26);
+ break;
+
+ case 'B':
+ param = get_cmp (param, &val);
+ opcode |= val;
+ break;
+
+ case 'M':
+ param = get_cnd (param, &val);
+ opcode |= val;
+ break;
+
+ case 'c':
+ param = get_cr (param, &val);
+ opcode |= val << 5;
+ break;
+
+ case 'f':
+ param = get_fcr (param, &val);
+ opcode |= val << 5;
+ break;
+
+ case 'V':
+ param = get_vec9 (param, &val);
+ opcode |= val;
+ break;
+
+ case '?':
+ /* Having this here repeats the warning somtimes.
+ But can't we stand that? */
+ as_warn ("Use of obsolete instruction");
+ break;
+ }
+ }
+}
+
+char *
+match_name (param, assoc_tab, valp)
+ char *param;
+ struct field_val_assoc *assoc_tab;
+ unsigned *valp;
+{
+ int i;
+ char *name;
+ int name_len;
+
+ for (i = 0;; i++)
+ {
+ name = assoc_tab[i].name;
+ if (name == NULL)
+ return NULL;
+ name_len = strlen (name);
+ if (!strncmp (param, name, name_len))
+ {
+ *valp = assoc_tab[i].val;
+ return param + name_len;
+ }
+ }
+}
+
+char *
+get_reg (param, regnop)
+ char *param;
+ unsigned *regnop;
+{
+ unsigned c;
+ unsigned regno;
+
+ c = *param++;
+ if (c == 'r')
+ {
+ regno = *param++ - '0';
+ if (regno < 10)
+ {
+ if (regno == 0)
+ {
+ *regnop = 0;
+ return param;
+ }
+ c = *param - '0';
+ if (c < 10)
+ {
+ regno = regno * 10 + c;
+ if (c < 32)
+ {
+ *regnop = regno;
+ return param + 1;
+ }
+ }
+ else
+ {
+ *regnop = regno;
+ return param;
+ }
+ }
+ return NULL;
+ }
+ else if (c == 's' && param[0] == 'p')
+ {
+ *regnop = 31;
+ return param + 1;
+ }
+
+ return 0;
+}
+
+char *
+get_imm16 (param, insn)
+ char *param;
+ struct m88k_insn *insn;
+{
+ enum reloc_type reloc = NO_RELOC;
+ unsigned int val;
+ segT seg;
+ char *save_ptr;
+
+ if (!strncmp (param, "hi16", 4) && !isalnum (param[4]))
+ {
+ reloc = RELOC_HI16;
+ param += 4;
+ }
+ else if (!strncmp (param, "lo16", 4) && !isalnum (param[4]))
+ {
+ reloc = RELOC_LO16;
+ param += 4;
+ }
+ else if (!strncmp (param, "iw16", 4) && !isalnum (param[4]))
+ {
+ reloc = RELOC_IW16;
+ param += 4;
+ }
+
+ save_ptr = input_line_pointer;
+ input_line_pointer = param;
+ seg = expression (&insn->exp);
+ param = input_line_pointer;
+ input_line_pointer = save_ptr;
+
+ val = insn->exp.X_add_number;
+
+ if (seg == SEG_ABSOLUTE)
+ {
+ /* Insert the value now, and reset reloc to NO_RELOC. */
+ if (reloc == NO_RELOC)
+ {
+ /* Warn about too big expressions if not surrounded by xx16. */
+ if (val > 0xffff)
+ as_warn ("Expression truncated to 16 bits");
+ }
+
+ if (reloc == RELOC_HI16)
+ val >>= 16;
+
+ insn->opcode |= val & 0xffff;
+ reloc = NO_RELOC;
+ }
+ else if (reloc == NO_RELOC)
+ /* We accept a symbol even without lo16, hi16, etc, and assume
+ lo16 was intended. */
+ reloc = RELOC_LO16;
+
+ insn->reloc = reloc;
+
+ return param;
+}
+
+char *
+get_pcr (param, insn, reloc)
+ char *param;
+ struct m88k_insn *insn;
+ enum reloc_type reloc;
+{
+ char *saveptr, *saveparam;
+ segT seg;
+
+ saveptr = input_line_pointer;
+ input_line_pointer = param;
+
+ seg = expression (&insn->exp);
+
+ saveparam = input_line_pointer;
+ input_line_pointer = saveptr;
+
+ /* Botch: We should relocate now if SEG_ABSOLUTE. */
+ insn->reloc = reloc;
+
+ return saveparam;
+}
+
+char *
+get_cmp (param, valp)
+ char *param;
+ unsigned *valp;
+{
+ unsigned int val;
+ char *save_ptr;
+
+ save_ptr = param;
+
+ param = match_name (param, cmpslot, valp);
+ val = *valp;
+
+ if (param == NULL)
+ {
+ param = save_ptr;
+
+ save_ptr = input_line_pointer;
+ input_line_pointer = param;
+ val = get_absolute_expression ();
+ param = input_line_pointer;
+ input_line_pointer = save_ptr;
+
+ if (val >= 32)
+ {
+ as_warn ("Expression truncated to 5 bits");
+ val %= 32;
+ }
+ }
+
+ *valp = val << 21;
+ return param;
+}
+
+char *
+get_cnd (param, valp)
+ char *param;
+ unsigned *valp;
+{
+ unsigned int val;
+
+ if (isdigit (*param))
+ {
+ param = getval (param, &val);
+
+ if (val >= 32)
+ {
+ as_warn ("Expression truncated to 5 bits");
+ val %= 32;
+ }
+ }
+ else
+ {
+ if (isupper (*param))
+ *param = tolower (*param);
+
+ if (isupper (param[1]))
+ param[1] = tolower (param[1]);
+
+ param = match_name (param, cndmsk, valp);
+
+ if (param == NULL)
+ return NULL;
+
+ val = *valp;
+ }
+
+ *valp = val << 21;
+ return param;
+}
+
+char *
+get_bf2 (param, bc)
+ char *param;
+ int bc;
+{
+ int depth = 0;
+ int c;
+
+ for (;;)
+ {
+ c = *param;
+ if (c == 0)
+ return param;
+ else if (c == '(')
+ depth++;
+ else if (c == ')')
+ depth--;
+ else if (c == bc && depth <= 0)
+ return param;
+ param++;
+ }
+}
+
+char *
+get_bf_offset_expression (param, offsetp)
+ char *param;
+ unsigned *offsetp;
+{
+ unsigned offset;
+
+ if (isalpha (param[0]))
+ {
+ if (isupper (param[0]))
+ param[0] = tolower (param[0]);
+ if (isupper (param[1]))
+ param[1] = tolower (param[1]);
+
+ param = match_name (param, cmpslot, offsetp);
+
+ return param;
+ }
+ else
+ {
+ input_line_pointer = param;
+ offset = get_absolute_expression ();
+ param = input_line_pointer;
+ }
+
+ *offsetp = offset;
+ return param;
+}
+
+char *
+get_bf (param, valp)
+ char *param;
+ unsigned *valp;
+{
+ unsigned offset = 0;
+ unsigned width = 0;
+ char *xp;
+ char *save_ptr;
+
+ xp = get_bf2 (param, '<');
+
+ save_ptr = input_line_pointer;
+ input_line_pointer = param;
+ if (*xp == 0)
+ {
+ /* We did not find '<'. We have an offset (width implicitly 32). */
+ param = get_bf_offset_expression (param, &offset);
+ if (param == NULL)
+ return NULL;
+ input_line_pointer = save_ptr;
+ }
+ else
+ {
+ *xp++ = 0; /* Overwrite the '<' */
+ param = get_bf2 (xp, '>');
+ if (*param == 0)
+ return NULL;
+ *param++ = 0; /* Overwrite the '>' */
+
+ width = get_absolute_expression ();
+ xp = get_bf_offset_expression (xp, &offset);
+ input_line_pointer = save_ptr;
+
+ if (xp + 1 != param)
+ return NULL;
+ }
+
+ *valp = ((width % 32) << 5) | (offset % 32);
+
+ return param;
+}
+
+char *
+get_cr (param, regnop)
+ char *param;
+ unsigned *regnop;
+{
+ unsigned regno;
+ unsigned c;
+/* int i; FIXME remove this */
+/* int name_len; FIXME remove this */
+
+ if (!strncmp (param, "cr", 2))
+ {
+ param += 2;
+
+ regno = *param++ - '0';
+ if (regno < 10)
+ {
+ if (regno == 0)
+ {
+ *regnop = 0;
+ return param;
+ }
+ c = *param - '0';
+ if (c < 10)
+ {
+ regno = regno * 10 + c;
+ if (c < 64)
+ {
+ *regnop = regno;
+ return param + 1;
+ }
+ }
+ else
+ {
+ *regnop = regno;
+ return param;
+ }
+ }
+ return NULL;
+ }
+
+ param = match_name (param, cr_regs, regnop);
+
+ return param;
+}
+
+char *
+get_fcr (param, regnop)
+ char *param;
+ unsigned *regnop;
+{
+ unsigned regno;
+ unsigned c;
+/* int i; FIXME remove this */
+/* int name_len; FIXME: remove this */
+
+ if (!strncmp (param, "fcr", 3))
+ {
+ param += 3;
+
+ regno = *param++ - '0';
+ if (regno < 10)
+ {
+ if (regno == 0)
+ {
+ *regnop = 0;
+ return param;
+ }
+ c = *param - '0';
+ if (c < 10)
+ {
+ regno = regno * 10 + c;
+ if (c < 64)
+ {
+ *regnop = regno;
+ return param + 1;
+ }
+ }
+ else
+ {
+ *regnop = regno;
+ return param;
+ }
+ }
+ return NULL;
+ }
+
+ param = match_name (param, fcr_regs, regnop);
+
+ return param;
+}
+
+char *
+get_vec9 (param, valp)
+ char *param;
+ unsigned *valp;
+{
+ unsigned val;
+ char *save_ptr;
+
+ save_ptr = input_line_pointer;
+ input_line_pointer = param;
+ val = get_absolute_expression ();
+ param = input_line_pointer;
+ input_line_pointer = save_ptr;
+
+ if (val >= 1 << 9)
+ as_warn ("Expression truncated to 9 bits");
+
+ *valp = val % (1 << 9);
+
+ return param;
+}
+
+#define hexval(z) \
+ (isdigit (z) ? (z) - '0' : \
+ islower (z) ? (z) - 'a' + 10 : \
+ isupper (z) ? (z) - 'A' + 10 : -1)
+
+char *
+getval (param, valp)
+ char *param;
+ unsigned int *valp;
+{
+ unsigned int val = 0;
+ unsigned int c;
+
+ c = *param++;
+ if (c == '0')
+ {
+ c = *param++;
+ if (c == 'x' || c == 'X')
+ {
+ c = *param++;
+ c = hexval (c);
+ while (c < 16)
+ {
+ val = val * 16 + c;
+ c = *param++;
+ c = hexval (c);
+ }
+ }
+ else
+ {
+ c -= '0';
+ while (c < 8)
+ {
+ val = val * 8 + c;
+ c = *param++ - '0';
+ }
+ }
+ }
+ else
+ {
+ c -= '0';
+ while (c < 10)
+ {
+ val = val * 10 + c;
+ c = *param++ - '0';
+ }
+ }
+
+ *valp = val;
+ return param - 1;
+}
+
+void
+md_number_to_chars (buf, val, nbytes)
+char *buf;
+long val;
+int nbytes;
+{
+ switch (nbytes)
+ {
+ case 4:
+ *buf++ = val >> 24;
+ *buf++ = val >> 16;
+ case 2:
+ *buf++ = val >> 8;
+ case 1:
+ *buf = val;
+ break;
+
+ default:
+ abort ();
+ }
+}
+
+#ifdef comment
+
+void
+md_number_to_imm (buf, val, nbytes, fixP, seg_type)
+unsigned char *buf;
+unsigned int val;
+int nbytes;
+fixS *fixP;
+int seg_type;
+{
+ if (seg_type != N_TEXT || fixP->fx_r_type == NO_RELOC)
+ {
+ switch (nbytes)
+ {
+ case 4:
+ *buf++ = val >> 24;
+ *buf++ = val >> 16;
+ case 2:
+ *buf++ = val >> 8;
+ case 1:
+ *buf = val;
+ break;
+
+ default:
+ abort ();
+ }
+ return;
+ }
+
+ switch (fixP->fx_r_type)
+ {
+ case RELOC_IW16:
+ buf[2] = val >> 8;
+ buf[3] = val;
+ break;
+
+ case RELOC_LO16:
+ buf[0] = val >> 8;
+ buf[1] = val;
+ break;
+
+ case RELOC_HI16:
+ buf[0] = val >> 24;
+ buf[1] = val >> 16;
+ break;
+
+ case RELOC_PC16:
+ val += 4;
+ buf[0] = val >> 10;
+ buf[1] = val >> 2;
+ break;
+
+ case RELOC_PC26:
+ val += 4;
+ buf[0] |= (val >> 26) & 0x03;
+ buf[1] = val >> 18;
+ buf[2] = val >> 10;
+ buf[3] = val >> 2;
+ break;
+
+ case RELOC_32:
+ buf[0] = val >> 24;
+ buf[1] = val >> 16;
+ buf[2] = val >> 8;
+ buf[3] = val;
+ break;
+
+ default:
+ as_fatal ("Bad relocation type");
+ break;
+ }
+}
+#endif /* comment */
+
+/* Apply a fixS to the frags, now that we know the value it ought to
+ hold. */
+
+void md_apply_fix(fixP, val)
+fixS *fixP;
+long val;
+{
+ char *buf = fixP->fx_where + fixP->fx_frag->fr_literal;
+
+ fixP->fx_addnumber = val;
+
+
+ switch (fixP->fx_r_type) {
+
+ case RELOC_IW16:
+ buf[2] = val >> 8;
+ buf[3] = val;
+ break;
+
+ case RELOC_LO16:
+ buf[0] = val >> 8;
+ buf[1] = val;
+ break;
+
+ case RELOC_HI16:
+ buf[0] = val >> 24;
+ buf[1] = val >> 16;
+ break;
+
+ case RELOC_PC16:
+ val += 4;
+ buf[0] = val >> 10;
+ buf[1] = val >> 2;
+ break;
+
+ case RELOC_PC26:
+ val += 4;
+ buf[0] |= (val >> 26) & 0x03;
+ buf[1] = val >> 18;
+ buf[2] = val >> 10;
+ buf[3] = val >> 2;
+ break;
+
+ case RELOC_32:
+ buf[0] = val >> 24;
+ buf[1] = val >> 16;
+ buf[2] = val >> 8;
+ buf[3] = val;
+ break;
+
+ case NO_RELOC:
+ switch (fixP->fx_size) {
+ case 4:
+ *buf++ = val >> 24;
+ *buf++ = val >> 16;
+ case 2:
+ *buf++ = val >> 8;
+ case 1:
+ *buf = val;
+ break;
+
+ default:
+ abort ();
+ }
+
+ default:
+ as_bad("bad relocation type: 0x%02x", fixP->fx_r_type);
+ break;
+ }
+
+ return;
+} /* md_apply_fix() */
+
+void
+md_number_to_disp (buf, val, nbytes)
+char *buf;
+int val;
+int nbytes;
+{
+ as_fatal ("md_number_to_disp not defined");
+ md_number_to_chars (buf, val, nbytes);
+}
+
+void
+md_number_to_field (buf, val, nbytes)
+char *buf;
+int val;
+int nbytes;
+{
+ as_fatal ("md_number_to_field not defined");
+ md_number_to_chars (buf, val, nbytes);
+}
+
+#define MAX_LITTLENUMS 6
+
+/* Turn a string in input_line_pointer into a floating point constant of type
+ type, and store the appropriate bytes in *litP. The number of LITTLENUMS
+ emitted is stored in *sizeP. An error message is returned, or NULL on OK.
+ */
+char *
+md_atof (type, litP, sizeP)
+ char type;
+ char *litP;
+ int *sizeP;
+{
+ int prec;
+ LITTLENUM_TYPE words[MAX_LITTLENUMS];
+ LITTLENUM_TYPE *wordP;
+ char *t;
+ char *atof_ieee ();
+
+ switch (type)
+ {
+ case 'f':
+ case 'F':
+ case 's':
+ case 'S':
+ prec = 2;
+ break;
+
+ case 'd':
+ case 'D':
+ case 'r':
+ case 'R':
+ prec = 4;
+ break;
+
+ case 'x':
+ case 'X':
+ prec = 6;
+ break;
+
+ case 'p':
+ case 'P':
+ prec = 6;
+ break;
+
+ default:
+ *sizeP=0;
+ return "Bad call to MD_ATOF()";
+ }
+ t=atof_ieee (input_line_pointer, type, words);
+ if (t)
+ input_line_pointer=t;
+
+ *sizeP=prec * sizeof (LITTLENUM_TYPE);
+ for (wordP=words;prec--;)
+ {
+ md_number_to_chars (litP, (long) (*wordP++), sizeof (LITTLENUM_TYPE));
+ litP+=sizeof (LITTLENUM_TYPE);
+ }
+ return ""; /* Someone should teach Dean about null pointers */
+}
+
+int md_short_jump_size = 4;
+
+void
+md_create_short_jump (ptr, from_addr, to_addr, frag, to_symbol)
+ char *ptr;
+ long from_addr, to_addr;
+ fragS *frag;
+ symbolS *to_symbol;
+{
+ ptr[0] = 0xc0; ptr[1] = 0x00; ptr[2] = 0x00; ptr[3] = 0x00;
+ fix_new (frag,
+ ptr - frag->fr_literal,
+ 4,
+ to_symbol,
+ (symbolS *) 0,
+ (long int) 0,
+ 0,
+ RELOC_PC26); /* Botch: Shouldn't this be RELOC_PC16? */
+}
+
+int md_long_jump_size = 4;
+
+void
+md_create_long_jump (ptr, from_addr, to_addr, frag, to_symbol)
+ char *ptr;
+ long from_addr, to_addr;
+ fragS *frag;
+ symbolS *to_symbol;
+{
+ ptr[0] = 0xc0; ptr[1] = 0x00; ptr[2] = 0x00; ptr[3] = 0x00;
+ fix_new (frag,
+ ptr - frag->fr_literal,
+ 4,
+ to_symbol,
+ (symbolS *) 0,
+ (long int) 0,
+ 0,
+ RELOC_PC26);
+}
+
+int
+md_estimate_size_before_relax (fragP, segment_type)
+ fragS *fragP;
+ segT segment_type;
+{
+ as_fatal("Relaxation should never occur");
+ return(0);
+}
+
+const relax_typeS md_relax_table[] = {0};
+
+void
+md_convert_frag (headers, fragP)
+object_headers *headers;
+ fragS *fragP;
+{
+ as_fatal ("Relaxation should never occur");
+}
+
+void
+md_end ()
+{
+}
+
+#ifdef comment
+
+/*
+ * Risc relocations are completely different, so it needs
+ * this machine dependent routine to emit them.
+ */
+void
+emit_relocations (fixP, segment_address_in_file)
+ fixS *fixP;
+ relax_addressT segment_address_in_file;
+{
+ struct reloc_info_m88k ri;
+ symbolS *symbolP;
+ extern char *next_object_file_charP;
+
+ bzero ((char *) &ri, sizeof (ri));
+ for (; fixP; fixP = fixP->fx_next) {
+
+ if (fixP->fx_r_type >= NO_RELOC) {
+ fprintf (stderr, "fixP->fx_r_type = %d\n", fixP->fx_r_type);
+ abort ();
+ }
+
+ if ((symbolP = fixP->fx_addsy) != NULL) {
+ ri.r_address = fixP->fx_frag->fr_address +
+ fixP->fx_where - segment_address_in_file;
+ if ((symbolP->sy_type & N_TYPE) == N_UNDF) {
+ ri.r_extern = 1;
+ ri.r_symbolnum = symbolP->sy_number;
+ } else {
+ ri.r_extern = 0;
+ ri.r_symbolnum = symbolP->sy_type & N_TYPE;
+ }
+ if (symbolP && symbolP->sy_frag) {
+ ri.r_addend = symbolP->sy_frag->fr_address;
+ }
+ ri.r_type = fixP->fx_r_type;
+ if (fixP->fx_pcrel) {
+/* ri.r_addend -= fixP->fx_where; */
+ ri.r_addend -= ri.r_address;
+ } else {
+ ri.r_addend = fixP->fx_addnumber;
+ }
+
+/* md_ri_to_chars ((char *) &ri, ri); */
+ append (&next_object_file_charP, (char *)& ri, sizeof (ri));
+ }
+ }
+ return;
+}
+#endif /* comment */
+
+/* Translate internal representation of relocation info to target format.
+
+ On m88k: first 4 bytes are normal unsigned long address,
+ next three bytes are index, most sig. byte first.
+ Byte 7 is broken up with bit 7 as external,
+ bits 6, 5, & 4 unused, and the lower four bits as relocation
+ type.
+ Next 4 bytes are long addend. */
+
+void tc_aout_fix_to_chars(where, fixP, segment_address_in_file)
+char *where;
+fixS *fixP;
+relax_addressT segment_address_in_file;
+{
+ long r_index;
+ long r_extern;
+ long r_addend = 0;
+ long r_address;
+
+ know(fixP->fx_addsy);
+
+ if (!S_IS_DEFINED(fixP->fx_addsy)) {
+ r_extern = 1;
+ r_index = fixP->fx_addsy->sy_number;
+ } else {
+ r_extern = 0;
+ r_index = S_GET_TYPE(fixP->fx_addsy);
+ }
+
+ /* this is easy */
+ md_number_to_chars(where,
+ r_address = fixP->fx_frag->fr_address + fixP->fx_where - segment_address_in_file,
+ 4);
+
+ /* now the fun stuff */
+ where[4] = (r_index >> 16) & 0x0ff;
+ where[5] = (r_index >> 8) & 0x0ff;
+ where[6] = r_index & 0x0ff;
+ where[7] = ((r_extern << 7) & 0x80) | (0 & 0x70) | (fixP->fx_r_type & 0xf);
+
+ /* Also easy */
+ if (fixP->fx_addsy->sy_frag) {
+ r_addend = fixP->fx_addsy->sy_frag->fr_address;
+ }
+
+ if (fixP->fx_pcrel) {
+ r_addend -= r_address;
+ } else {
+ r_addend = fixP->fx_addnumber;
+ }
+
+ md_number_to_chars(&where[8], r_addend, 4);
+
+ return;
+} /* tc_aout_fix_to_chars() */
+
+
+static void
+s_bss()
+{
+ char *name;
+ char c;
+ char *p;
+ int temp, bss_align = 1;
+ symbolS *symbolP;
+ extern char is_end_of_line[256];
+
+ name = input_line_pointer;
+ c = get_symbol_end();
+ p = input_line_pointer;
+ *p = c;
+ SKIP_WHITESPACE();
+ if ( * input_line_pointer != ',' )
+ {
+ as_warn("Expected comma after name");
+ ignore_rest_of_line();
+ return;
+ }
+ input_line_pointer ++;
+ if ((temp = get_absolute_expression()) < 0)
+ {
+ as_warn("BSS length (%d.) <0! Ignored.", temp);
+ ignore_rest_of_line();
+ return;
+ }
+ *p = 0;
+ symbolP = symbol_find_or_make(name);
+ *p = c;
+ if (*input_line_pointer == ',')
+ {
+ input_line_pointer++;
+ bss_align = get_absolute_expression();
+ while (local_bss_counter % bss_align != 0)
+ local_bss_counter++;
+ }
+
+ if (!S_IS_DEFINED(symbolP)
+ || (S_GET_SEGMENT(symbolP) == SEG_BSS
+ && S_GET_VALUE(symbolP) == local_bss_counter)) {
+ S_SET_VALUE(symbolP, local_bss_counter);
+ S_SET_SEGMENT(symbolP, SEG_BSS);
+ symbolP->sy_frag = &bss_address_frag;
+ local_bss_counter += temp;
+ } else {
+ as_warn( "Ignoring attempt to re-define symbol from %d. to %d.",
+ S_GET_VALUE(symbolP), local_bss_counter );
+ }
+ while (!is_end_of_line[*input_line_pointer])
+ {
+ input_line_pointer++;
+ }
+
+ return;
+}
+
+/* We have no need to default values of symbols. */
+
+/* ARGSUSED */
+symbolS *md_undefined_symbol(name)
+char *name;
+{
+ return 0;
+} /* md_undefined_symbol() */
+
+/* Parse an operand that is machine-specific.
+ We just return without modifying the expression if we have nothing
+ to do. */
+
+/* ARGSUSED */
+void md_operand(expressionP)
+expressionS *expressionP;
+{
+} /* md_operand() */
+
+/* Round up a section size to the appropriate boundary. */
+long md_section_align(segment, size)
+segT segment;
+long size;
+{
+ return((size + 7) & ~7); /* Round all sects to multiple of 8 */
+} /* md_section_align() */
+
+/* Exactly what point is a PC-relative offset relative TO?
+ On the sparc, they're relative to the address of the offset, plus
+ its size. This gets us to the following instruction.
+ (??? Is this right? FIXME-SOON) */
+long md_pcrel_from(fixP)
+fixS *fixP;
+{
+ return(fixP->fx_size + fixP->fx_where + fixP->fx_frag->fr_address);
+} /* md_pcrel_from() */
+
+ /* end of tc-m88k.c */
diff --git a/gnu/usr.bin/as/config/tc-m88k.h b/gnu/usr.bin/as/config/tc-m88k.h
new file mode 100644
index 0000000..f518085
--- /dev/null
+++ b/gnu/usr.bin/as/config/tc-m88k.h
@@ -0,0 +1,35 @@
+/* m88k.h -- Assembler for the Motorola 88000
+ Contributed by Devon Bowen of Buffalo University
+ and Torbjorn Granlund of the Swedish Institute of Computer Science.
+ Copyright (C) 1989-1992 Free Software Foundation, Inc.
+
+ This file is part of GAS, the GNU Assembler.
+
+ GAS is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GAS is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GAS; see the file COPYING. If not, write to
+ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#define TC_M88K 1
+
+#define NO_LISTING
+#define NO_DOT_PSEUDOS
+#define ALLOW_ATSIGN
+
+#define LOCAL_LABEL(name) (name[0] == '@' \
+ && ( name[1] == 'L' || name[1] == '.' ))
+
+#define tc_crawl_symbol_chain(a) {;} /* not used */
+#define tc_headers_hook(a) {;} /* not used */
+#define tc_aout_pre_write_hook(x) {;} /* not used */
+
+ /* end of tc-m88k.h */
diff --git a/gnu/usr.bin/as/config/tc-mips.c b/gnu/usr.bin/as/config/tc-mips.c
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/gnu/usr.bin/as/config/tc-mips.c
diff --git a/gnu/usr.bin/as/config/tc-mips.h b/gnu/usr.bin/as/config/tc-mips.h
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/gnu/usr.bin/as/config/tc-mips.h
diff --git a/gnu/usr.bin/as/config/tc-ns32k.c b/gnu/usr.bin/as/config/tc-ns32k.c
new file mode 100644
index 0000000..33fceb5
--- /dev/null
+++ b/gnu/usr.bin/as/config/tc-ns32k.c
@@ -0,0 +1,2015 @@
+/* ns32k.c -- Assemble on the National Semiconductor 32k series
+ Copyright (C) 1987, 1992 Free Software Foundation, Inc.
+
+ This file is part of GAS, the GNU Assembler.
+
+ GAS is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GAS is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GAS; see the file COPYING. If not, write to
+ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/*#define SHOW_NUM 1*/ /* uncomment for debugging */
+
+#include <stdio.h>
+#include <ctype.h>
+#ifdef USG
+#include <string.h>
+#else
+#include <strings.h>
+#endif
+#include "opcode/ns32k.h"
+
+#include "as.h"
+
+#include "obstack.h"
+
+/* Macros */
+#define IIF_ENTRIES 13 /* number of entries in iif */
+#define PRIVATE_SIZE 256 /* size of my garbage memory */
+#define MAX_ARGS 4
+#define DEFAULT -1 /* addr_mode returns this value when plain constant or label is encountered */
+
+#define IIF(ptr,a1,c1,e1,g1,i1,k1,m1,o1,q1,s1,u1) \
+ iif.iifP[ptr].type= a1; \
+ iif.iifP[ptr].size= c1; \
+ iif.iifP[ptr].object= e1; \
+ iif.iifP[ptr].object_adjust= g1; \
+ iif.iifP[ptr].pcrel= i1; \
+ iif.iifP[ptr].pcrel_adjust= k1; \
+ iif.iifP[ptr].im_disp= m1; \
+ iif.iifP[ptr].relax_substate= o1; \
+ iif.iifP[ptr].bit_fixP= q1; \
+ iif.iifP[ptr].addr_mode= s1; \
+ iif.iifP[ptr].bsr= u1;
+
+#ifdef TE_SEQUENT
+#define LINE_COMMENT_CHARS "|"
+#define ABSOLUTE_PREFIX '@'
+#define IMMEDIATE_PREFIX '#'
+#endif
+
+#ifndef LINE_COMMENT_CHARS
+#define LINE_COMMENT_CHARS "#"
+#endif
+
+const char comment_chars[] = "#";
+const char line_comment_chars[] = LINE_COMMENT_CHARS;
+#if !defined(ABSOLUTE_PREFIX) && !defined(IMMEDIATE_PREFIX)
+#define ABSOLUTE_PREFIX '@' /* One or the other MUST be defined */
+#endif
+
+struct addr_mode {
+ char mode; /* addressing mode of operand (0-31) */
+ char scaled_mode; /* mode combined with scaled mode */
+ char scaled_reg; /* register used in scaled+1 (1-8) */
+ char float_flag; /* set if R0..R7 was F0..F7 ie a floating-point-register */
+ char am_size; /* estimated max size of general addr-mode parts*/
+ char im_disp; /* if im_disp == 1 we have a displacement */
+ char pcrel; /* 1 if pcrel, this is really redundant info */
+ char disp_suffix[2]; /* length of displacement(s), 0=undefined */
+ char *disp[2]; /* pointer(s) at displacement(s)
+ or immediates(s) (ascii) */
+ char index_byte; /* index byte */
+};
+typedef struct addr_mode addr_modeS;
+
+
+char *freeptr,*freeptr_static; /* points at some number of free bytes */
+struct hash_control *inst_hash_handle;
+
+struct ns32k_opcode *desc; /* pointer at description of instruction */
+addr_modeS addr_modeP;
+char EXP_CHARS[] = "eE";
+char FLT_CHARS[] = "fd"; /* we don't want to support lowercase, do we */
+
+/* UPPERCASE denotes live names
+ * when an instruction is built, IIF is used as an intermidiate form to store
+ * the actual parts of the instruction. A ns32k machine instruction can
+ * be divided into a couple of sub PARTs. When an instruction is assembled
+ * the appropriate PART get an assignment. When an IIF has been completed it's
+ * converted to a FRAGment as specified in AS.H */
+
+/* internal structs */
+struct option {
+ char *pattern;
+ unsigned long or;
+ unsigned long and;
+};
+
+typedef struct {
+ int type; /* how to interpret object */
+ int size; /* Estimated max size of object */
+ unsigned long object; /* binary data */
+ int object_adjust; /* number added to object */
+ int pcrel; /* True if object is pcrel */
+ int pcrel_adjust; /* length in bytes from the
+ instruction start to the
+ displacement */
+ int im_disp; /* True if the object is a displacement */
+ relax_substateT relax_substate; /* Initial relaxsubstate */
+ bit_fixS *bit_fixP; /* Pointer at bit_fix struct */
+ int addr_mode; /* What addrmode do we associate with this iif-entry */
+ char bsr; /* Sequent hack */
+}iif_entryT; /* Internal Instruction Format */
+
+struct int_ins_form {
+ int instr_size; /* Max size of instruction in bytes. */
+ iif_entryT iifP[IIF_ENTRIES + 1];
+};
+struct int_ins_form iif;
+expressionS exprP;
+char *input_line_pointer;
+/* description of the PARTs in IIF
+ *object[n]:
+ * 0 total length in bytes of entries in iif
+ * 1 opcode
+ * 2 index_byte_a
+ * 3 index_byte_b
+ * 4 disp_a_1
+ * 5 disp_a_2
+ * 6 disp_b_1
+ * 7 disp_b_2
+ * 8 imm_a
+ * 9 imm_b
+ * 10 implied1
+ * 11 implied2
+ *
+ * For every entry there is a datalength in bytes. This is stored in size[n].
+ * 0, the objectlength is not explicitly given by the instruction
+ * and the operand is undefined. This is a case for relaxation.
+ * Reserve 4 bytes for the final object.
+ *
+ * 1, the entry contains one byte
+ * 2, the entry contains two bytes
+ * 3, the entry contains three bytes
+ * 4, the entry contains four bytes
+ * etc
+ *
+ * Furthermore, every entry has a data type identifier in type[n].
+ *
+ * 0, the entry is void, ignore it.
+ * 1, the entry is a binary number.
+ * 2, the entry is a pointer at an expression.
+ * Where expression may be as simple as a single '1',
+ * and as complicated as foo-bar+12,
+ * foo and bar may be undefined but suffixed by :{b|w|d} to
+ * control the length of the object.
+ *
+ * 3, the entry is a pointer at a bignum struct
+ *
+ *
+ * The low-order-byte coresponds to low physical memory.
+ * Obviously a FRAGment must be created for each valid disp in PART whose
+ * datalength is undefined (to bad) .
+ * The case where just the expression is undefined is less severe and is
+ * handled by fix. Here the number of bytes in the objectfile is known.
+ * With this representation we simplify the assembly and separates the
+ * machine dependent/independent parts in a more clean way (said OE)
+ */
+
+struct option opt1[]= /* restore, exit */
+{
+ { "r0", 0x80, 0xff },
+ { "r1", 0x40, 0xff },
+ { "r2", 0x20, 0xff },
+ { "r3", 0x10, 0xff },
+ { "r4", 0x08, 0xff },
+ { "r5", 0x04, 0xff },
+ { "r6", 0x02, 0xff },
+ { "r7", 0x01, 0xff },
+ { 0 , 0x00, 0xff }
+};
+struct option opt2[]= /* save, enter */
+{
+ { "r0", 0x01, 0xff },
+ { "r1", 0x02, 0xff },
+ { "r2", 0x04, 0xff },
+ { "r3", 0x08, 0xff },
+ { "r4", 0x10, 0xff },
+ { "r5", 0x20, 0xff },
+ { "r6", 0x40, 0xff },
+ { "r7", 0x80, 0xff },
+ { 0 , 0x00, 0xff }
+};
+struct option opt3[]= /* setcfg */
+{
+ { "c", 0x8, 0xff },
+ { "m", 0x4, 0xff },
+ { "f", 0x2, 0xff },
+ { "i", 0x1, 0xff },
+ { 0 , 0x0, 0xff }
+};
+struct option opt4[]= /* cinv */
+{
+ { "a", 0x4, 0xff },
+ { "i", 0x2, 0xff },
+ { "d", 0x1, 0xff },
+ { 0 , 0x0, 0xff }
+};
+struct option opt5[]= /* string inst */
+{
+ { "b", 0x2, 0xff },
+ { "u", 0xc, 0xff },
+ { "w", 0x4, 0xff },
+ { 0 , 0x0, 0xff }
+};
+struct option opt6[]= /* plain reg ext,cvtp etc */
+{
+ { "r0", 0x00, 0xff },
+ { "r1", 0x01, 0xff },
+ { "r2", 0x02, 0xff },
+ { "r3", 0x03, 0xff },
+ { "r4", 0x04, 0xff },
+ { "r5", 0x05, 0xff },
+ { "r6", 0x06, 0xff },
+ { "r7", 0x07, 0xff },
+ { 0 , 0x00, 0xff }
+};
+
+#if !defined(NS32032) && !defined(NS32532)
+#define NS32032
+#endif
+
+struct option cpureg_532[]= /* lpr spr */
+{
+ { "us", 0x0, 0xff },
+ { "dcr", 0x1, 0xff },
+ { "bpc", 0x2, 0xff },
+ { "dsr", 0x3, 0xff },
+ { "car", 0x4, 0xff },
+ { "fp", 0x8, 0xff },
+ { "sp", 0x9, 0xff },
+ { "sb", 0xa, 0xff },
+ { "usp", 0xb, 0xff },
+ { "cfg", 0xc, 0xff },
+ { "psr", 0xd, 0xff },
+ { "intbase", 0xe, 0xff },
+ { "mod", 0xf, 0xff },
+ { 0 , 0x00, 0xff }
+};
+struct option mmureg_532[]= /* lmr smr */
+{
+ { "mcr", 0x9, 0xff },
+ { "msr", 0xa, 0xff },
+ { "tear", 0xb, 0xff },
+ { "ptb0", 0xc, 0xff },
+ { "ptb1", 0xd, 0xff },
+ { "ivar0", 0xe, 0xff },
+ { "ivar1", 0xf, 0xff },
+ { 0 , 0x0, 0xff }
+};
+
+struct option cpureg_032[]= /* lpr spr */
+{
+ { "upsr", 0x0, 0xff },
+ { "fp", 0x8, 0xff },
+ { "sp", 0x9, 0xff },
+ { "sb", 0xa, 0xff },
+ { "psr", 0xd, 0xff },
+ { "intbase", 0xe, 0xff },
+ { "mod", 0xf, 0xff },
+ { 0 , 0x0, 0xff }
+};
+struct option mmureg_032[]= /* lmr smr */
+{
+ { "bpr0", 0x0, 0xff },
+ { "bpr1", 0x1, 0xff },
+ { "pf0", 0x4, 0xff },
+ { "pf1", 0x5, 0xff },
+ { "sc", 0x8, 0xff },
+ { "msr", 0xa, 0xff },
+ { "bcnt", 0xb, 0xff },
+ { "ptb0", 0xc, 0xff },
+ { "ptb1", 0xd, 0xff },
+ { "eia", 0xf, 0xff },
+ { 0 , 0x0, 0xff }
+};
+
+#if defined(NS32532)
+struct option *cpureg = cpureg_532;
+struct option *mmureg = mmureg_532;
+#else
+struct option *cpureg = cpureg_032;
+struct option *mmureg = mmureg_032;
+#endif
+
+
+const pseudo_typeS md_pseudo_table[]={ /* so far empty */
+ { 0, 0, 0 }
+};
+
+#define IND(x,y) (((x)<<2)+(y))
+
+/* those are index's to relax groups in md_relax_table
+ ie it must be multiplied by 4 to point at a group start. Viz IND(x,y)
+ Se function relax_segment in write.c for more info */
+
+#define BRANCH 1
+#define PCREL 2
+
+/* those are index's to entries in a relax group */
+
+#define BYTE 0
+#define WORD 1
+#define DOUBLE 2
+#define UNDEF 3
+/* Those limits are calculated from the displacement start in memory.
+ The ns32k uses the begining of the instruction as displacement base.
+ This type of displacements could be handled here by moving the limit window
+ up or down. I choose to use an internal displacement base-adjust as there
+ are other routines that must consider this. Also, as we have two various
+ offset-adjusts in the ns32k (acb versus br/brs/jsr/bcond), two set of limits
+ would have had to be used.
+ Now we dont have to think about that. */
+
+
+const relax_typeS md_relax_table[] = {
+ { 1, 1, 0, 0 },
+ { 1, 1, 0, 0 },
+ { 1, 1, 0, 0 },
+ { 1, 1, 0, 0 },
+
+ { (63), (-64), 1, IND(BRANCH,WORD) },
+ { (8191), (-8192), 2, IND(BRANCH,DOUBLE) },
+ { 0, 0, 4, 0 },
+ { 1, 1, 0, 0 }
+};
+
+/* Array used to test if mode contains displacements.
+ Value is true if mode contains displacement. */
+
+char disp_test[] = { 0,0,0,0,0,0,0,0,
+ 1,1,1,1,1,1,1,1,
+ 1,1,1,0,0,1,1,0,
+ 1,1,1,1,1,1,1,1 };
+
+/* Array used to calculate max size of displacements */
+
+char disp_size[] = { 4,1,2,0,4 };
+
+#ifdef PIC
+/* In pic-mode all external pc-relative references are jmpslot
+ references except references to __GLOBAL_OFFSET_TABLE_. */
+static symbolS *got_symbol;
+
+/* The size of got-offsets. */
+static int got_offset_size = 2;
+#endif
+
+
+
+#if __STDC__ == 1
+
+static segT evaluate_expr(expressionS *resultP, char *ptr);
+static void md_number_to_disp(char *buf, long val, int n);
+static void md_number_to_imm(char *buf, long val, int n);
+
+#else /* not __STDC__ */
+
+static segT evaluate_expr();
+static void md_number_to_disp();
+static void md_number_to_imm();
+
+#endif /* not __STDC__ */
+
+/* Parses a general operand into an addressingmode struct
+
+ in: pointer at operand in ascii form
+ pointer at addr_mode struct for result
+ the level of recursion. (always 0 or 1)
+
+ out: data in addr_mode struct
+ */
+int addr_mode(operand,addr_modeP,recursive_level)
+char *operand;
+register addr_modeS *addr_modeP;
+int recursive_level;
+{
+ register char *str;
+ register int i;
+ register int strl;
+ register int mode;
+ int j;
+ mode = DEFAULT; /* default */
+ addr_modeP->scaled_mode=0; /* why not */
+ addr_modeP->scaled_reg=0; /* if 0, not scaled index */
+ addr_modeP->float_flag=0;
+ addr_modeP->am_size=0;
+ addr_modeP->im_disp=0;
+ addr_modeP->pcrel=0; /* not set in this function */
+ addr_modeP->disp_suffix[0]=0;
+ addr_modeP->disp_suffix[1]=0;
+ addr_modeP->disp[0]=NULL;
+ addr_modeP->disp[1]=NULL;
+ str=operand;
+ if (str[0] == 0) {return (0);} /* we don't want this */
+ strl=strlen(str);
+ switch (str[0]) {
+ /* the following three case statements controls the mode-chars
+ this is the place to ed if you want to change them */
+#ifdef ABSOLUTE_PREFIX
+ case ABSOLUTE_PREFIX:
+ if (str[strl-1] == ']') break;
+ addr_modeP->mode=21; /* absolute */
+ addr_modeP->disp[0]=str+1;
+ return (-1);
+#endif
+#ifdef IMMEDIATE_PREFIX
+ case IMMEDIATE_PREFIX:
+ if (str[strl-1] == ']') break;
+ addr_modeP->mode=20; /* immediate */
+ addr_modeP->disp[0]=str+1;
+ return (-1);
+#endif
+ case '.':
+ if (str[strl-1] != ']') {
+ switch (str[1]) {
+ case'-':case'+':
+ if (str[2] != '\000') {
+ addr_modeP->mode=27; /* pc-relativ */
+ addr_modeP->disp[0]=str+2;
+ return (-1);
+ }
+ default:
+ as_warn("Invalid syntax in PC-relative addressing mode");
+ return(0);
+ }
+ }
+ break;
+ case'e':
+ if (str[strl-1] != ']') {
+ if ((!strncmp(str,"ext(",4)) && strl>7) { /* external */
+ addr_modeP->disp[0]=str+4;
+ i=0;
+ j=2;
+ do { /* disp[0]'s termination point */
+ j+=1;
+ if (str[j] == '(') i++;
+ if (str[j] == ')') i--;
+ } while (j < strl && i != 0);
+ if (i != 0 || !(str[j+1] == '-' || str[j+1] == '+') ) {
+ as_warn("Invalid syntax in External addressing mode");
+ return(0);
+ }
+ str[j]='\000'; /* null terminate disp[0] */
+ addr_modeP->disp[1]=str+j+2;
+ addr_modeP->mode=22;
+ return (-1);
+ }
+ }
+ break;
+ default:;
+ }
+ strl=strlen(str);
+ switch (strl) {
+ case 2:
+ switch (str[0]) {
+ case'f':addr_modeP->float_flag=1;
+ case'r':
+ if (str[1] >= '0' && str[1] < '8') {
+ addr_modeP->mode=str[1]-'0';
+ return (-1);
+ }
+ }
+ case 3:
+ if (!strncmp(str,"tos",3)) {
+ addr_modeP->mode=23; /* TopOfStack */
+ return (-1);
+ }
+ default:;
+ }
+ if (strl>4) {
+ if (str[strl - 1] == ')') {
+ if (str[strl - 2] == ')') {
+ if (!strncmp(&str[strl-5],"(fp",3)) {
+ mode=16; /* Memory Relative */
+ }
+ if (!strncmp(&str[strl-5],"(sp",3)) {
+ mode=17;
+ }
+ if (!strncmp(&str[strl-5],"(sb",3)) {
+ mode=18;
+ }
+ if (mode != DEFAULT) { /* memory relative */
+ addr_modeP->mode=mode;
+ j=strl-5; /* temp for end of disp[0] */
+ i=0;
+ do {
+ strl-=1;
+ if (str[strl] == ')') i++;
+ if (str[strl] == '(') i--;
+ } while (strl>-1 && i != 0);
+ if (i != 0) {
+ as_warn("Invalid syntax in Memory Relative addressing mode");
+ return(0);
+ }
+ addr_modeP->disp[1]=str;
+ addr_modeP->disp[0]=str+strl+1;
+ str[j]='\000'; /* null terminate disp[0] */
+ str[strl]='\000'; /* null terminate disp[1] */
+ return (-1);
+ }
+ }
+ switch (str[strl-3]) {
+ case'r':case'R':
+ if (str[strl - 2] >= '0' && str[strl - 2] < '8' && str[strl - 4] == '(') {
+ addr_modeP->mode=str[strl-2]-'0'+8;
+ addr_modeP->disp[0]=str;
+ str[strl-4]=0;
+ return (-1); /* reg rel */
+ }
+ default:
+ if (!strncmp(&str[strl-4],"(fp",3)) {
+ mode=24;
+ }
+ if (!strncmp(&str[strl-4],"(sp",3)) {
+ mode=25;
+ }
+ if (!strncmp(&str[strl-4],"(sb",3)) {
+ mode=26;
+ }
+ if (!strncmp(&str[strl-4],"(pc",3)) {
+ mode=27;
+ }
+ if (mode != DEFAULT) {
+ addr_modeP->mode=mode;
+ addr_modeP->disp[0]=str;
+ str[strl-4]='\0';
+ return (-1); /* memory space */
+ }
+ }
+ }
+ /* no trailing ')' do we have a ']' ? */
+ if (str[strl - 1] == ']') {
+ switch (str[strl-2]) {
+ case'b':mode=28;break;
+ case'w':mode=29;break;
+ case'd':mode=30;break;
+ case'q':mode=31;break;
+ default:;
+ as_warn("Invalid scaled-indexed mode, use (b,w,d,q)");
+ if (str[strl - 3] != ':' || str[strl - 6] != '[' ||
+ str[strl - 5] == 'r' || str[strl - 4] < '0' || str[strl - 4] > '7') {
+ as_warn("Syntax in scaled-indexed mode, use [Rn:m] where n=[0..7] m={b,w,d,q}");
+ }
+ } /* scaled index */
+ {
+ if (recursive_level>0) {
+ as_warn("Scaled-indexed addressing mode combined with scaled-index");
+ return(0);
+ }
+ addr_modeP->am_size+=1; /* scaled index byte */
+ j=str[strl-4]-'0'; /* store temporary */
+ str[strl-6]='\000'; /* nullterminate for recursive call */
+ i=addr_mode(str,addr_modeP,1);
+ if (!i || addr_modeP->mode == 20) {
+ as_warn("Invalid or illegal addressing mode combined with scaled-index");
+ return(0);
+ }
+ addr_modeP->scaled_mode=addr_modeP->mode; /* store the inferior mode */
+ addr_modeP->mode=mode;
+ addr_modeP->scaled_reg=j+1;
+ return (-1);
+ }
+ }
+ }
+ addr_modeP->mode = DEFAULT; /* default to whatever */
+ addr_modeP->disp[0]=str;
+ return (-1);
+}
+
+/* ptr points at string
+ addr_modeP points at struct with result
+ This routine calls addr_mode to determine the general addr.mode of
+ the operand. When this is ready it parses the displacements for size
+ specifying suffixes and determines size of immediate mode via ns32k-opcode.
+ Also builds index bytes if needed.
+ */
+int get_addr_mode(ptr,addr_modeP)
+char *ptr;
+addr_modeS *addr_modeP;
+{
+ int tmp;
+ addr_mode(ptr,addr_modeP,0);
+ if (addr_modeP->mode == DEFAULT || addr_modeP->scaled_mode == -1) {
+ /* resolve ambigious operands, this shouldn't
+ be necessary if one uses standard NSC operand
+ syntax. But the sequent compiler doesn't!!!
+ This finds a proper addressinging mode if it
+ is implicitly stated. See ns32k-opcode.h */
+ (void)evaluate_expr(&exprP,ptr); /* this call takes time Sigh! */
+ if (addr_modeP->mode == DEFAULT) {
+ if (exprP.X_add_symbol || exprP.X_subtract_symbol) {
+ addr_modeP->mode=desc->default_model; /* we have a label */
+ } else {
+ addr_modeP->mode=desc->default_modec; /* we have a constant */
+ }
+ } else {
+ if (exprP.X_add_symbol || exprP.X_subtract_symbol) {
+ addr_modeP->scaled_mode=desc->default_model;
+ } else {
+ addr_modeP->scaled_mode=desc->default_modec;
+ }
+ }
+ /* must put this mess down in addr_mode to handle the scaled case better */
+ }
+ /* It appears as the sequent compiler wants an absolute when we have a
+ label without @. Constants becomes immediates besides the addr case.
+ Think it does so with local labels too, not optimum, pcrel is better.
+ When I have time I will make gas check this and select pcrel when possible
+ Actually that is trivial.
+ */
+ if (tmp=addr_modeP->scaled_reg) { /* build indexbyte */
+ tmp--; /* remember regnumber comes incremented for flagpurpose */
+ tmp|=addr_modeP->scaled_mode<<3;
+ addr_modeP->index_byte=(char)tmp;
+ addr_modeP->am_size+=1;
+ }
+ if (disp_test[addr_modeP->mode]) { /* there was a displacement, probe for length specifying suffix*/
+ {
+ register char c;
+ register char suffix;
+ register char suffix_sub;
+ register int i;
+ register char *toP;
+ register char *fromP;
+
+ addr_modeP->pcrel=0;
+ if (disp_test[addr_modeP->mode]) { /* there is a displacement */
+ if (addr_modeP->mode == 27 || addr_modeP->scaled_mode == 27) { /* do we have pcrel. mode */
+ addr_modeP->pcrel=1;
+ }
+ addr_modeP->im_disp=1;
+ for (i=0;i<2;i++) {
+ suffix_sub=suffix=0;
+ if (toP=addr_modeP->disp[i]) { /* suffix of expression, the largest size rules */
+ fromP=toP;
+ while (c = *fromP++) {
+ *toP++=c;
+ if (c == ':') {
+ switch (*fromP) {
+ case '\0':
+ as_warn("Premature end of suffix--Defaulting to d");
+ suffix=4;
+ continue;
+ case 'b':suffix_sub=1;break;
+ case 'w':suffix_sub=2;break;
+ case 'd':suffix_sub=4;break;
+ default:
+ as_warn("Bad suffix after ':' use {b|w|d} Defaulting to d");
+ suffix=4;
+ }
+ fromP++;
+ toP--; /* So we write over the ':' */
+ if (suffix<suffix_sub) suffix=suffix_sub;
+ }
+ }
+ *toP='\0'; /* terminate properly */
+ addr_modeP->disp_suffix[i]=suffix;
+ addr_modeP->am_size+=suffix ? suffix : 4;
+ }
+ }
+ }
+ }
+ } else {
+ if (addr_modeP->mode == 20) { /* look in ns32k_opcode for size */
+ addr_modeP->disp_suffix[0]=addr_modeP->am_size=desc->im_size;
+ addr_modeP->im_disp=0;
+ }
+ }
+ return addr_modeP->mode;
+}
+
+
+/* read an optionlist */
+void optlist(str,optionP,default_map)
+char *str; /* the string to extract options from */
+struct option *optionP; /* how to search the string */
+unsigned long *default_map; /* default pattern and output */
+{
+ register int i,j,k,strlen1,strlen2;
+ register char *patternP,*strP;
+ strlen1=strlen(str);
+ if (strlen1<1) {
+ as_fatal("Very short instr to option, ie you can't do it on a NULLstr");
+ }
+ for (i = 0; optionP[i].pattern != 0; i++) {
+ strlen2=strlen(optionP[i].pattern);
+ for (j=0;j<strlen1;j++) {
+ patternP=optionP[i].pattern;
+ strP = &str[j];
+ for (k=0;k<strlen2;k++) {
+ if (*(strP++) != *(patternP++)) break;
+ }
+ if (k == strlen2) { /* match */
+ *default_map|=optionP[i].or;
+ *default_map&=optionP[i].and;
+ }
+ }
+ }
+}
+/* search struct for symbols
+ This function is used to get the short integer form of reg names
+ in the instructions lmr, smr, lpr, spr
+ return true if str is found in list */
+
+int list_search(str,optionP,default_map)
+char *str; /* the string to match */
+struct option *optionP; /* list to search */
+unsigned long *default_map; /* default pattern and output */
+{
+ register int i;
+ for (i = 0; optionP[i].pattern != 0; i++) {
+ if (!strncmp(optionP[i].pattern,str,20)) { /* use strncmp to be safe */
+ *default_map|=optionP[i].or;
+ *default_map&=optionP[i].and;
+ return -1;
+ }
+ }
+ as_warn("No such entry in list. (cpu/mmu register)");
+ return 0;
+}
+static segT evaluate_expr(resultP,ptr)
+expressionS *resultP;
+char *ptr;
+{
+ register char *tmp_line;
+ register segT segment;
+ tmp_line = input_line_pointer;
+ input_line_pointer = ptr;
+ segment = expression(&exprP);
+ input_line_pointer = tmp_line;
+ return(segment);
+}
+
+/* Convert operands to iif-format and adds bitfields to the opcode.
+ Operands are parsed in such an order that the opcode is updated from
+ its most significant bit, that is when the operand need to alter the
+ opcode.
+ Be carefull not to put to objects in the same iif-slot.
+ */
+
+void encode_operand(argc,argv,operandsP,suffixP,im_size,opcode_bit_ptr)
+int argc;
+char **argv;
+char *operandsP;
+char *suffixP;
+char im_size;
+char opcode_bit_ptr;
+{
+ register int i,j;
+ int pcrel,tmp,b,loop,pcrel_adjust;
+ for (loop=0;loop<argc;loop++) {
+ i=operandsP[loop<<1]-'1'; /* what operand are we supposed to work on */
+ if (i>3) as_fatal("Internal consistency error. check ns32k-opcode.h");
+ pcrel=0;
+ pcrel_adjust=0;
+ tmp=0;
+ switch (operandsP[(loop<<1)+1]) {
+ case 'f': /* operand of sfsr turns out to be a nasty specialcase */
+ opcode_bit_ptr-=5;
+ case 'F': /* 32 bit float general form */
+ case 'L': /* 64 bit float */
+ case 'Q': /* quad-word */
+ case 'B': /* byte */
+ case 'W': /* word */
+ case 'D': /* double-word */
+ case 'A': /* double-word gen-address-form ie no regs allowed */
+ get_addr_mode(argv[i],&addr_modeP);
+ iif.instr_size+=addr_modeP.am_size;
+ if (opcode_bit_ptr == desc->opcode_size) b = 4; else b = 6;
+ for (j=b;j<(b+2);j++) {
+ if (addr_modeP.disp[j-b]) {
+ IIF(j,
+ 2,
+ addr_modeP.disp_suffix[j-b],
+ (unsigned long)addr_modeP.disp[j-b],
+ 0,
+ addr_modeP.pcrel,
+ iif.instr_size-addr_modeP.am_size, /* this aint used (now) */
+ addr_modeP.im_disp,
+ IND(BRANCH,BYTE),
+ NULL,
+ addr_modeP.scaled_reg ? addr_modeP.scaled_mode:addr_modeP.mode,
+ 0);
+ }
+ }
+ opcode_bit_ptr-=5;
+ iif.iifP[1].object|=((long)addr_modeP.mode)<<opcode_bit_ptr;
+ if (addr_modeP.scaled_reg) {
+ j=b/2;
+ IIF(j,1,1, (unsigned long)addr_modeP.index_byte,0,0,0,0,0, NULL,-1,0);
+ }
+ break;
+ case 'b': /* multiple instruction disp */
+ freeptr++; /* OVE:this is an useful hack */
+ tmp = (int) sprintf(freeptr,
+ "((%s-1)*%d)\000",
+ argv[i], desc->im_size);
+ argv[i]=freeptr;
+ freeptr=(char*)tmp;
+ pcrel-=1; /* make pcrel 0 inspite of what case 'p': wants */
+ /* fall thru */
+ case 'p': /* displacement - pc relative addressing */
+ pcrel+=1;
+ /* fall thru */
+ case 'd': /* displacement */
+ iif.instr_size+=suffixP[i] ? suffixP[i] : 4;
+ IIF(12, 2, suffixP[i], (unsigned long)argv[i], 0,
+ pcrel, pcrel_adjust, 1, IND(BRANCH,BYTE), NULL,-1,0);
+ break;
+ case 'H': /* sequent-hack: the linker wants a bit set when bsr */
+ pcrel=1;
+ iif.instr_size+=suffixP[i] ? suffixP[i] : 4;
+ IIF(12, 2, suffixP[i], (unsigned long)argv[i], 0,
+ pcrel, pcrel_adjust, 1, IND(BRANCH,BYTE), NULL,-1, 1);
+ break;
+ case 'q': /* quick */
+ opcode_bit_ptr-=4;
+ IIF(11,2,42,(unsigned long)argv[i],0,0,0,0,0,
+ bit_fix_new(4,opcode_bit_ptr,-8,7,0,1,0),-1,0);
+ break;
+ case 'r': /* register number (3 bits) */
+ list_search(argv[i],opt6,&tmp);
+ opcode_bit_ptr-=3;
+ iif.iifP[1].object|=tmp<<opcode_bit_ptr;
+ break;
+ case 'O': /* setcfg instruction optionslist */
+ optlist(argv[i],opt3,&tmp);
+ opcode_bit_ptr-=4;
+ iif.iifP[1].object|=tmp<<15;
+ break;
+ case 'C': /* cinv instruction optionslist */
+ optlist(argv[i],opt4,&tmp);
+ opcode_bit_ptr-=4;
+ iif.iifP[1].object|=tmp<<15;/*insert the regtype in opcode */
+ break;
+ case 'S': /* stringinstruction optionslist */
+ optlist(argv[i],opt5,&tmp);
+ opcode_bit_ptr-=4;
+ iif.iifP[1].object|=tmp<<15;
+ break;
+ case 'u':case 'U': /* registerlist */
+ IIF(10,1,1,0,0,0,0,0,0,NULL,-1,0);
+ switch (operandsP[(i<<1)+1]) {
+ case 'u': /* restore, exit */
+ optlist(argv[i],opt1,&iif.iifP[10].object);
+ break;
+ case 'U': /* save,enter */
+ optlist(argv[i],opt2,&iif.iifP[10].object);
+ break;
+ }
+ iif.instr_size+=1;
+ break;
+ case 'M': /* mmu register */
+ list_search(argv[i],mmureg,&tmp);
+ opcode_bit_ptr-=4;
+ iif.iifP[1].object|=tmp<<opcode_bit_ptr;
+ break;
+ case 'P': /* cpu register */
+ list_search(argv[i],cpureg,&tmp);
+ opcode_bit_ptr-=4;
+ iif.iifP[1].object|=tmp<<opcode_bit_ptr;
+ break;
+ case 'g': /* inss exts */
+ iif.instr_size+=1; /* 1 byte is allocated after the opcode */
+ IIF(10,2,1,
+ (unsigned long)argv[i], /* i always 2 here */
+ 0,0,0,0,0,
+ bit_fix_new(3,5,0,7,0,0,0), /* a bit_fix is targeted to the byte */
+ -1,0);
+ case 'G':
+ IIF(11,2,42,
+ (unsigned long)argv[i], /* i always 3 here */
+ 0,0,0,0,0,
+ bit_fix_new(5,0,1,32,-1,0,-1),-1,0);
+ break;
+ case 'i':
+ iif.instr_size+=1;
+ b=2+i; /* put the extension byte after opcode */
+ IIF(b,2,1,0,0,0,0,0,0,0,-1,0);
+ default:
+ as_fatal("Bad opcode-table-option, check in file ns32k-opcode.h");
+ }
+ }
+}
+
+/* in: instruction line
+ out: internal structure of instruction
+ that has been prepared for direct conversion to fragment(s) and
+ fixes in a systematical fashion
+ Return-value = recursive_level
+ */
+/* build iif of one assembly text line */
+int parse(line,recursive_level)
+char *line;
+int recursive_level;
+{
+ register char *lineptr,c,suffix_separator;
+ register int i;
+ int argc,arg_type;
+ char sqr,sep;
+ char suffix[MAX_ARGS],*argv[MAX_ARGS];/* no more than 4 operands */
+ if (recursive_level <= 0) { /* called from md_assemble */
+ for (lineptr=line; (*lineptr) != '\0' && (*lineptr) != ' '; lineptr++);
+ c = *lineptr;
+ *lineptr = '\0';
+ desc = (struct ns32k_opcode*) hash_find(inst_hash_handle,line);
+ if (!desc) {
+ as_fatal("No such opcode");
+ }
+ *lineptr = c;
+ } else {
+ lineptr = line;
+ }
+ argc = 0;
+ if (*desc->operands != NULL) {
+ if (*lineptr++ != '\0') {
+ sqr='[';
+ sep=',';
+ while (*lineptr != '\0') {
+ if (desc->operands[argc << 1]) {
+ suffix[argc] = 0;
+ arg_type =
+ desc->operands[(argc << 1) + 1];
+ switch (arg_type) {
+ case 'd':
+ case 'b':
+ case 'p':
+ case 'H': /* the operand is supposed to be a displacement */
+ /* Hackwarning: do not forget to update the 4 cases above when editing ns32k-opcode.h */
+ suffix_separator = ':';
+ break;
+ default:
+ suffix_separator = '\255'; /* if this char occurs we loose */
+ }
+ suffix[argc] = 0; /* 0 when no ':' is encountered */
+ argv[argc] = freeptr;
+ *freeptr = '\0';
+ while ((c = *lineptr) != '\0' && c != sep) {
+ if (c == sqr) {
+ if (sqr == '[') {
+ sqr = ']';
+ sep = '\0';
+ } else {
+ sqr = '[';
+ sep = ',';
+ }
+ }
+ if (c == suffix_separator) { /* ':' - label/suffix separator */
+ switch (lineptr[1]) {
+ case 'b': suffix[argc] = 1; break;
+ case 'w': suffix[argc] = 2; break;
+ case 'd': suffix[argc] = 4; break;
+ default: as_warn("Bad suffix, defaulting to d");
+ suffix[argc] = 4;
+ if (lineptr[1] == '\0' || lineptr[1] == sep) {
+ lineptr += 1;
+ continue;
+ }
+ }
+ lineptr += 2;
+ continue;
+ }
+ *freeptr++ = c;
+ lineptr++;
+ }
+ *freeptr++ = '\0';
+ argc += 1;
+ if (*lineptr == '\0') continue;
+ lineptr += 1;
+ } else {
+ as_fatal("Too many operands passed to instruction");
+ }
+ }
+ }
+ }
+ if (argc != strlen(desc->operands) / 2) {
+ if (strlen(desc->default_args) != 0) { /* we can apply default, dont goof */
+ if (parse(desc->default_args,1) != 1) { /* check error in default */
+ as_fatal("Wrong numbers of operands in default, check ns32k-opcodes.h");
+ }
+ } else {
+ as_fatal("Wrong number of operands");
+ }
+
+ }
+ for (i = 0; i < IIF_ENTRIES; i++) {
+ iif.iifP[i].type = 0; /* mark all entries as void*/
+ }
+
+ /* build opcode iif-entry */
+ iif.instr_size = desc->opcode_size / 8;
+ IIF(1,1,iif.instr_size,desc->opcode_seed,0,0,0,0,0,0,-1,0);
+
+ /* this call encodes operands to iif format */
+ if (argc) {
+ encode_operand(argc,
+ argv,
+ &desc->operands[0],
+ &suffix[0],
+ desc->im_size,
+ desc->opcode_size);
+ }
+ return(recursive_level);
+}
+
+
+/* Convert iif to fragments.
+ From this point we start to dribble with functions in other files than
+ this one.(Except hash.c) So, if it's possible to make an iif for an other
+ CPU, you don't need to know what frags, relax, obstacks, etc is in order
+ to port this assembler. You only need to know if it's possible to reduce
+ your cpu-instruction to iif-format (takes some work) and adopt the other
+ md_? parts according to given instructions
+ Note that iif was invented for the clean ns32k`s architecure.
+ */
+void convert_iif() {
+ int i;
+ bit_fixS *bit_fixP;
+ fragS *inst_frag;
+ char *inst_offset;
+ char *inst_opcode;
+ char *memP;
+ segT segment;
+ int l;
+ int k;
+ int rem_size; /* count the remaining bytes of instruction */
+ char type;
+ char size = 0;
+ int size_so_far = 0; /* used to calculate pcrel_adjust */
+ int pcrel_symbols = 0;/* kludge by jkp@hut.fi to make
+ movd _foo(pc),_bar(pc) work.
+ It should be done with two frags
+ for one insn, but I don't understand
+ enough to make it work */
+
+ rem_size = iif.instr_size;
+ memP = frag_more(iif.instr_size); /* make sure we have enough bytes for instruction */
+ inst_opcode = memP;
+ inst_offset = (char *)(memP-frag_now->fr_literal);
+ inst_frag = frag_now;
+ for (i=0; i < IIF_ENTRIES; i++) { /* jkp kludge alert */
+ if (iif.iifP[i].type && iif.iifP[i].size == 0 &&
+ iif.iifP[i].pcrel) {
+ evaluate_expr(&exprP, (char *)iif.iifP[i].object);
+ if (exprP.X_add_symbol || exprP.X_subtract_symbol)
+ pcrel_symbols++;
+ }
+ }
+ for (i=0;i<IIF_ENTRIES;i++) {
+ if (type=iif.iifP[i].type) { /* the object exist, so handle it */
+#ifdef PIC
+ int reloc_mode;
+ if ((i == 4 || i == 6)
+ && flagseen['k']
+ && (iif.iifP[i].addr_mode == 18 || iif.iifP[i].addr_mode == 26))
+ reloc_mode = RELOC_GLOB_DAT;
+ else
+ reloc_mode = NO_RELOC;
+#else
+ int reloc_mode = NO_RELOC;
+#endif
+ switch (size=iif.iifP[i].size) {
+ case 42: size=0; /* it's a bitfix that operates on an existing object*/
+ if (iif.iifP[i].bit_fixP->fx_bit_base) { /* expand fx_bit_base to point at opcode */
+ iif.iifP[i].bit_fixP->fx_bit_base = (long) inst_opcode;
+ }
+ case 8: /* bignum or doublefloat */
+ memset(memP, '\0', 8);
+ case 1:case 2:case 3:case 4:/* the final size in objectmemory is known */
+ bit_fixP = iif.iifP[i].bit_fixP;
+ switch (type) {
+ case 1: /* the object is pure binary */
+ if (bit_fixP || iif.iifP[i].pcrel) {
+ fix_new_ns32k(frag_now,
+ (long)(memP-frag_now->fr_literal),
+ size,
+ 0,
+ 0,
+ iif.iifP[i].object,
+ iif.iifP[i].pcrel,
+ (char)size_so_far, /*iif.iifP[i].pcrel_adjust,*/
+ iif.iifP[i].im_disp,
+ bit_fixP,
+ iif.iifP[i].bsr, /* sequent hack */
+ reloc_mode);
+ } else { /* good, just put them bytes out */
+ switch (iif.iifP[i].im_disp) {
+ case 0:
+ md_number_to_chars(memP,iif.iifP[i].object,size);break;
+ case 1:
+ md_number_to_disp(memP,iif.iifP[i].object,size);break;
+ default: as_fatal("iif convert internal pcrel/binary");
+ }
+ }
+ memP+=size;
+ rem_size-=size;
+ break;
+ case 2: /* the object is a pointer at an expression, so unpack
+ it, note that bignums may result from the expression
+ */
+ if ((segment = evaluate_expr(&exprP, (char*)iif.iifP[i].object)) == SEG_BIG || size == 8) {
+ if ((k=exprP.X_add_number)>0) { /* we have a bignum ie a quad */
+ /* this can only happens in a long suffixed instruction */
+ memset(memP, '\0', size); /* size normally is 8 */
+ if (k*2>size) as_warn("Bignum too big for long");
+ if (k == 3) memP += 2;
+ for (l=0;k>0;k--,l+=2) {
+ md_number_to_chars(memP+l,generic_bignum[l>>1],sizeof(LITTLENUM_TYPE));
+ }
+ } else { /* flonum */
+ LITTLENUM_TYPE words[4];
+
+ switch (size) {
+ case 4:
+ gen_to_words(words,2,8);
+ md_number_to_imm(memP ,(long)words[0],sizeof(LITTLENUM_TYPE));
+ md_number_to_imm(memP+sizeof(LITTLENUM_TYPE),(long)words[1],sizeof(LITTLENUM_TYPE));
+ break;
+ case 8:
+ gen_to_words(words,4,11);
+ md_number_to_imm(memP ,(long)words[0],sizeof(LITTLENUM_TYPE));
+ md_number_to_imm(memP+sizeof(LITTLENUM_TYPE) ,(long)words[1],sizeof(LITTLENUM_TYPE));
+ md_number_to_imm(memP+2*sizeof(LITTLENUM_TYPE),(long)words[2],sizeof(LITTLENUM_TYPE));
+ md_number_to_imm(memP+3*sizeof(LITTLENUM_TYPE),(long)words[3],sizeof(LITTLENUM_TYPE));
+ break;
+ }
+ }
+ memP+=size;
+ rem_size-=size;
+ break;
+ }
+ if (bit_fixP ||
+ exprP.X_add_symbol ||
+ exprP.X_subtract_symbol ||
+ iif.iifP[i].pcrel) { /* fixit */
+ /* the expression was undefined due to an undefined label */
+ /* create a fix so we can fix the object later */
+ exprP.X_add_number+=iif.iifP[i].object_adjust;
+ fix_new_ns32k(frag_now,
+ (long)(memP-frag_now->fr_literal),
+ size,
+ exprP.X_add_symbol,
+ exprP.X_subtract_symbol,
+ exprP.X_add_number,
+ iif.iifP[i].pcrel,
+ (char)size_so_far, /*iif.iifP[i].pcrel_adjust,*/
+ iif.iifP[i].im_disp,
+ bit_fixP,
+ iif.iifP[i].bsr, /* sequent hack */
+ reloc_mode);
+
+ } else { /* good, just put them bytes out */
+ switch (iif.iifP[i].im_disp) {
+ case 0:
+ md_number_to_imm(memP,exprP.X_add_number,size);break;
+ case 1:
+ md_number_to_disp(memP,exprP.X_add_number,size);break;
+ default: as_fatal("iif convert internal pcrel/pointer");
+ }
+ }
+ memP+=size;
+ rem_size-=size;
+ break;
+ default: as_fatal("Internal logic error in iif.iifP[n].type");
+ }
+ break;
+ case 0: /* To bad, the object may be undefined as far as its final
+ nsize in object memory is concerned. The size of the object
+ in objectmemory is not explicitly given.
+ If the object is defined its length can be determined and
+ a fix can replace the frag.
+ */
+ {
+ int temp;
+ segment = evaluate_expr(&exprP, (char*)iif.iifP[i].object);
+ if (((exprP.X_add_symbol || exprP.X_subtract_symbol) &&
+ !iif.iifP[i].pcrel) || pcrel_symbols >= 2 /*jkp*/) { /* OVE: hack, clamp to 4 bytes */
+#ifdef PIC
+ if (reloc_mode == RELOC_GLOB_DAT && got_offset_size == 2) {
+ size = 2;
+ /* rewind the bytes not used */
+ obstack_blank_fast(&frags, -2);
+ } else
+#endif
+ size=4; /* we dont wan't to frag this, use 4 so it reaches */
+ fix_new_ns32k(frag_now,
+ (long)(memP-frag_now->fr_literal),
+ size,
+ exprP.X_add_symbol,
+ exprP.X_subtract_symbol,
+ exprP.X_add_number,
+ pcrel_symbols >= 2 ? iif.iifP[i].pcrel : 0, /*jkp*//* never iif.iifP[i].pcrel, */
+ (char)size_so_far, /*iif.iifP[i].pcrel_adjust,*/
+ 1, /* always iif.iifP[i].im_disp, */
+ 0,0,
+ reloc_mode);
+ memP+=size;
+ rem_size-=4;
+ break; /* exit this absolute hack */
+ }
+
+ if (exprP.X_add_symbol || exprP.X_subtract_symbol) { /* frag it */
+ if (exprP.X_subtract_symbol) { /* We cant relax this case */
+ as_fatal("Can't relax difference");
+ } else {
+ /* at this stage we must undo some of the effect caused
+ by frag_more, ie we must make sure that frag_var causes
+ frag_new to creat a valid fix-size in the frag it`s closing
+ */
+ temp = -(rem_size-4);
+ obstack_blank_fast(&frags,temp);
+ /* we rewind none, some or all of the requested size we
+ requested by the first frag_more for this iif chunk.
+ Note: that we allocate 4 bytes to an object we NOT YET
+ know the size of, thus rem_size-4.
+ */
+ (void) frag_variant(rs_machine_dependent,
+ 4,
+ 0,
+ IND(BRANCH,UNDEF), /* expecting the worst */
+ exprP.X_add_symbol,
+ exprP.X_add_number,
+ inst_opcode,
+ (char)size_so_far, /*iif.iifP[i].pcrel_adjust);*/
+ iif.iifP[i].bsr); /* sequent linker hack */
+ rem_size -= 4;
+ if (rem_size > 0) {
+ memP = frag_more(rem_size);
+ }
+ }
+ } else {/* Double work, this is done in md_number_to_disp */
+ /* exprP.X_add_number; fixme-soon what was this supposed to be? xoxorich. */
+ if (-64 <= exprP.X_add_number && exprP.X_add_number <= 63) {
+ size = 1;
+ } else {
+ if (-8192 <= exprP.X_add_number && exprP.X_add_number <= 8191) {
+ size = 2;
+
+ /* Dave Taylor <taylor@think.com> says: Note: The reason the lower
+ limit is -0x1f000000 and not -0x20000000 is that, according to
+ Nat'l Semi's data sheet on the ns32532, ``the pattern 11100000
+ for the most significant byte of the displacement is reserved by
+ National for future enhancements''. */
+ } else if (/* -0x40000000 <= exprP.X_add_number &&
+ exprP.X_add_number <= 0x3fffffff */
+ -0x1f000000 <= exprP.X_add_number &&
+ exprP.X_add_number <= 0x1fffffff) {
+ size = 4;
+ } else {
+ as_warn("Displacement too large for :d");
+ size = 4;
+ }
+ }
+ /* rewind the bytes not used */
+ temp = -(4-size);
+ md_number_to_disp(memP,exprP.X_add_number,size);
+ obstack_blank_fast(&frags,temp);
+ memP += size;
+ rem_size -= 4; /* we allocated this amount */
+ }
+ }
+ break;
+ default:
+ as_fatal("Internal logic error in iif.iifP[].type");
+ }
+ size_so_far += size;
+ size = 0;
+ }
+ }
+}
+
+void md_assemble(line)
+char *line;
+{
+ freeptr=freeptr_static;
+ parse(line,0); /* explode line to more fix form in iif */
+ convert_iif(); /* convert iif to frags, fix's etc */
+#ifdef SHOW_NUM
+ printf(" \t\t\t%s\n",line);
+#endif
+}
+
+
+void md_begin() {
+ /* build a hashtable of the instructions */
+ register const struct ns32k_opcode *ptr;
+ register char *stat;
+ inst_hash_handle=hash_new();
+ for (ptr=ns32k_opcodes;ptr<endop;ptr++) {
+ if (*(stat=hash_insert(inst_hash_handle,ptr->name,(char*)ptr))) {
+ as_fatal("Can't hash %s: %s", ptr->name,stat); /*fatal*/
+ exit(0);
+ }
+ }
+ freeptr_static=(char*)malloc(PRIVATE_SIZE); /* some private space please! */
+}
+
+
+void
+ md_end() {
+ free(freeptr_static);
+ }
+
+/* Must be equal to MAX_PRECISON in atof-ieee.c */
+#define MAX_LITTLENUMS 6
+
+/* Turn the string pointed to by litP into a floating point constant of type
+ type, and emit the appropriate bytes. The number of LITTLENUMS emitted
+ is stored in *sizeP. An error message is returned, or NULL on OK.
+ */
+char *
+ md_atof(type,litP,sizeP)
+char type;
+char *litP;
+int *sizeP;
+{
+ int prec;
+ LITTLENUM_TYPE words[MAX_LITTLENUMS];
+ LITTLENUM_TYPE *wordP;
+ extern char *atof_ns32k();
+ char *t;
+
+ switch (type) {
+ case 'f':
+ prec = 2;
+ break;
+
+ case 'd':
+ prec = 4;
+ break;
+ default:
+ *sizeP = 0;
+ return "Bad call to MD_ATOF()";
+ }
+ t = atof_ns32k(input_line_pointer, type, words);
+ if (t)
+ input_line_pointer=t;
+
+ *sizeP = prec * sizeof(LITTLENUM_TYPE);
+ for (wordP = words +prec; prec--;) {
+ md_number_to_chars(litP, (long)(*--wordP), sizeof(LITTLENUM_TYPE));
+ litP+=sizeof(LITTLENUM_TYPE);
+ }
+ return ""; /* Someone should teach Dean about null pointers */
+}
+
+/* Convert number to chars in correct order */
+
+void
+ md_number_to_chars(buf, value, nbytes)
+char *buf;
+long value;
+int nbytes;
+{
+ while (nbytes--) {
+#ifdef SHOW_NUM
+ printf("%x ",value & 0xff);
+#endif
+ *buf++ = value; /* Lint wants & MASK_CHAR. */
+ value >>= BITS_PER_CHAR;
+ }
+} /* md_number_to_chars() */
+
+
+/* This is a variant of md_numbers_to_chars. The reason for its' existence
+ is the fact that ns32k uses Huffman coded displacements. This implies
+ that the bit order is reversed in displacements and that they are prefixed
+ with a size-tag.
+
+ binary: msb->lsb
+ 0xxxxxxx byte
+ 10xxxxxx xxxxxxxx word
+ 11xxxxxx xxxxxxxx xxxxxxxx xxxxxxxx double word
+
+ This must be taken care of and we do it here!
+ */
+static void md_number_to_disp(buf, val, n)
+char *buf;
+long val;
+char n;
+{
+ switch (n) {
+ case 1:
+ if (val < -64 || val > 63)
+{
+fprintf(stderr, "val = %d\n", val);
+ as_warn("Byte displacement out of range. line number not valid");
+}
+ val &= 0x7f;
+#ifdef SHOW_NUM
+ printf("%x ",val & 0xff);
+#endif
+ *buf++ = val;
+ break;
+ case 2:
+ if (val < -8192 || val > 8191)
+ as_warn("Word displacement out of range. line number not valid");
+ val&=0x3fff;
+ val|=0x8000;
+#ifdef SHOW_NUM
+ printf("%x ",val>>8 & 0xff);
+#endif
+ *buf++=(val>>8);
+#ifdef SHOW_NUM
+ printf("%x ",val & 0xff);
+#endif
+ *buf++=val;
+ break;
+ case 4:
+
+ /* Dave Taylor <taylor@think.com> says: Note: The reason the
+ lower limit is -0x1f000000 and not -0x20000000 is that,
+ according to Nat'l Semi's data sheet on the ns32532, ``the
+ pattern 11100000 for the most significant byte of the
+ displacement is reserved by National for future
+ enhancements''. */
+
+ if (val < -0x1f000000 || val >= 0x20000000)
+ as_warn("Double word displacement out of range");
+ val|=0xc0000000;
+#ifdef SHOW_NUM
+ printf("%x ",val>>24 & 0xff);
+#endif
+ *buf++=(val>>24);
+#ifdef SHOW_NUM
+ printf("%x ",val>>16 & 0xff);
+#endif
+ *buf++=(val>>16);
+#ifdef SHOW_NUM
+ printf("%x ",val>>8 & 0xff);
+#endif
+ *buf++=(val>>8);
+#ifdef SHOW_NUM
+ printf("%x ",val & 0xff);
+#endif
+ *buf++=val;
+ break;
+ default:
+ as_fatal("Internal logic error. line %s, file \"%s\"", __LINE__, __FILE__);
+ }
+}
+
+static void md_number_to_imm(buf,val,n)
+char *buf;
+long val;
+char n;
+{
+ switch (n) {
+ case 1:
+#ifdef SHOW_NUM
+ printf("%x ",val & 0xff);
+#endif
+ *buf++=val;
+ break;
+ case 2:
+#ifdef SHOW_NUM
+ printf("%x ",val>>8 & 0xff);
+#endif
+ *buf++=(val>>8);
+#ifdef SHOW_NUM
+ printf("%x ",val & 0xff);
+#endif
+ *buf++=val;
+ break;
+ case 4:
+#ifdef SHOW_NUM
+ printf("%x ",val>>24 & 0xff);
+#endif
+ *buf++=(val>>24);
+#ifdef SHOW_NUM
+ printf("%x ",val>>16 & 0xff);
+#endif
+ *buf++=(val>>16);
+#ifdef SHOW_NUM
+ printf("%x ",val>>8 & 0xff);
+#endif
+ *buf++=(val>>8);
+#ifdef SHOW_NUM
+ printf("%x ",val & 0xff);
+#endif
+ *buf++=val;
+ break;
+ default:
+ as_fatal("Internal logic error. line %s, file \"%s\"", __LINE__, __FILE__);
+ }
+}
+
+/* Translate internal representation of relocation info into target format.
+
+ OVE: on a ns32k the twiddling continues at an even deeper level
+ here we have to distinguish between displacements and immediates.
+
+ The sequent has a bit for this. It also has a bit for relocobjects that
+ points at the target for a bsr (BranchSubRoutine) !?!?!?!
+
+ This md_ri.... is tailored for sequent.
+ */
+
+#ifdef comment
+void
+ md_ri_to_chars(the_bytes, ri)
+char *the_bytes;
+struct reloc_info_generic *ri;
+{
+ if (ri->r_bsr) { ri->r_pcrel = 0; } /* sequent seems to want this */
+ md_number_to_chars(the_bytes, ri->r_address, sizeof(ri->r_address));
+ md_number_to_chars(the_bytes+4, ((long)(ri->r_symbolnum )
+ | (long)(ri->r_pcrel << 24 )
+ | (long)(ri->r_length << 25 )
+ | (long)(ri->r_extern << 27 )
+ | (long)(ri->r_bsr << 28 )
+ | (long)(ri->r_disp << 29 )),
+ 4);
+ /* the first and second md_number_to_chars never overlaps (32bit cpu case) */
+}
+#endif /* comment */
+
+#ifdef OBJ_AOUT
+void tc_aout_fix_to_chars(where, fixP, segment_address_in_file)
+char *where;
+fixS *fixP;
+relax_addressT segment_address_in_file;
+{
+ /*
+ * In: length of relocation (or of address) in chars: 1, 2 or 4.
+ * Out: GNU LD relocation length code: 0, 1, or 2.
+ */
+
+ static unsigned char nbytes_r_length[] = { 42, 0, 1, 42, 2 };
+ long r_symbolnum;
+ int r_flags;
+
+ know(fixP->fx_addsy != NULL);
+
+ md_number_to_chars(where,
+ fixP->fx_frag->fr_address + fixP->fx_where - segment_address_in_file,
+ 4);
+
+ r_symbolnum = (S_IS_DEFINED(fixP->fx_addsy)
+ ? S_GET_TYPE(fixP->fx_addsy)
+ : fixP->fx_addsy->sy_number);
+ r_flags = (fixP->fx_pcrel ? 1 : 0)
+ | ((nbytes_r_length[fixP->fx_size] & 3) << 1)
+ | (!S_IS_DEFINED(fixP->fx_addsy) ? 8 : 0)
+#if defined(TE_SEQUENT)
+ | (fixP->fx_bsr ? 0x10 : 0)
+#elif defined(PIC)
+ /* Undefined pc-relative relocations are of type jmpslot */
+ | ((!S_IS_DEFINED(fixP->fx_addsy)
+ && fixP->fx_pcrel
+ && fixP->fx_addsy != got_symbol
+ && flagseen['k']) ? 0x10 : 0)
+#endif
+ | (fixP->fx_im_disp & 3) << 5;
+
+#ifdef PIC
+ switch (fixP->fx_r_type) {
+ case NO_RELOC:
+ break;
+ case RELOC_32:
+ if (flagseen['k'] && S_IS_EXTERNAL(fixP->fx_addsy)) {
+ r_symbolnum = fixP->fx_addsy->sy_number;
+ r_flags |= 8; /* set extern bit */
+ }
+ break;
+ case RELOC_GLOB_DAT:
+ if (!fixP->fx_pcrel) {
+ r_flags |= 0x80; /* set baserel bit */
+ r_symbolnum = fixP->fx_addsy->sy_number;
+ if (S_IS_EXTERNAL(fixP->fx_addsy))
+ r_flags |= 8;
+ }
+ break;
+ case RELOC_RELATIVE:
+ /* should never happen */
+ as_fatal("relocation botch");
+ break;
+ }
+#endif /* PIC */
+
+ where[4] = r_symbolnum & 0x0ff;
+ where[5] = (r_symbolnum >> 8) & 0x0ff;
+ where[6] = (r_symbolnum >> 16) & 0x0ff;
+ where[7] = r_flags;
+
+ return;
+} /* tc_aout_fix_to_chars() */
+
+
+#endif /* OBJ_AOUT */
+
+/* fast bitfiddling support */
+/* mask used to zero bitfield before oring in the true field */
+
+static unsigned long l_mask[] = {
+ 0xffffffff, 0xfffffffe, 0xfffffffc, 0xfffffff8,
+ 0xfffffff0, 0xffffffe0, 0xffffffc0, 0xffffff80,
+ 0xffffff00, 0xfffffe00, 0xfffffc00, 0xfffff800,
+ 0xfffff000, 0xffffe000, 0xffffc000, 0xffff8000,
+ 0xffff0000, 0xfffe0000, 0xfffc0000, 0xfff80000,
+ 0xfff00000, 0xffe00000, 0xffc00000, 0xff800000,
+ 0xff000000, 0xfe000000, 0xfc000000, 0xf8000000,
+ 0xf0000000, 0xe0000000, 0xc0000000, 0x80000000,
+};
+static unsigned long r_mask[] = {
+ 0x00000000, 0x00000001, 0x00000003, 0x00000007,
+ 0x0000000f, 0x0000001f, 0x0000003f, 0x0000007f,
+ 0x000000ff, 0x000001ff, 0x000003ff, 0x000007ff,
+ 0x00000fff, 0x00001fff, 0x00003fff, 0x00007fff,
+ 0x0000ffff, 0x0001ffff, 0x0003ffff, 0x0007ffff,
+ 0x000fffff, 0x001fffff, 0x003fffff, 0x007fffff,
+ 0x00ffffff, 0x01ffffff, 0x03ffffff, 0x07ffffff,
+ 0x0fffffff, 0x1fffffff, 0x3fffffff, 0x7fffffff,
+};
+#define MASK_BITS 31
+/* Insert bitfield described by field_ptr and val at buf
+ This routine is written for modification of the first 4 bytes pointed
+ to by buf, to yield speed.
+ The ifdef stuff is for selection between a ns32k-dependent routine
+ and a general version. (My advice: use the general version!)
+ */
+
+static void
+ md_number_to_field(buf,val,field_ptr)
+register char *buf;
+register long val;
+register bit_fixS *field_ptr;
+{
+ register unsigned long object;
+ register unsigned long mask;
+ /* define ENDIAN on a ns32k machine */
+#ifdef ENDIAN
+ register unsigned long *mem_ptr;
+#else
+ register char *mem_ptr;
+#endif
+ if (field_ptr->fx_bit_min <= val && val <= field_ptr->fx_bit_max) {
+#ifdef ENDIAN
+ if (field_ptr->fx_bit_base) { /* override buf */
+ mem_ptr=(unsigned long*)field_ptr->fx_bit_base;
+ } else {
+ mem_ptr=(unsigned long*)buf;
+ }
+#else
+ if (field_ptr->fx_bit_base) { /* override buf */
+ mem_ptr=(char*)field_ptr->fx_bit_base;
+ } else {
+ mem_ptr=buf;
+ }
+#endif
+ mem_ptr+=field_ptr->fx_bit_base_adj;
+#ifdef ENDIAN /* we have a nice ns32k machine with lowbyte at low-physical mem */
+ object = *mem_ptr; /* get some bytes */
+#else /* OVE Goof! the machine is a m68k or dito */
+ /* That takes more byte fiddling */
+ object=0;
+ object|=mem_ptr[3] & 0xff;
+ object<<=8;
+ object|=mem_ptr[2] & 0xff;
+ object<<=8;
+ object|=mem_ptr[1] & 0xff;
+ object<<=8;
+ object|=mem_ptr[0] & 0xff;
+#endif
+ mask=0;
+ mask|=(r_mask[field_ptr->fx_bit_offset]);
+ mask|=(l_mask[field_ptr->fx_bit_offset+field_ptr->fx_bit_size]);
+ object&=mask;
+ val+=field_ptr->fx_bit_add;
+ object|=((val<<field_ptr->fx_bit_offset) & (mask ^ 0xffffffff));
+#ifdef ENDIAN
+ *mem_ptr=object;
+#else
+ mem_ptr[0]=(char)object;
+ object>>=8;
+ mem_ptr[1]=(char)object;
+ object>>=8;
+ mem_ptr[2]=(char)object;
+ object>>=8;
+ mem_ptr[3]=(char)object;
+#endif
+ } else {
+ as_warn("Bit field out of range");
+ }
+}
+
+/* Apply a fixS (fixup of an instruction or data that we didn't have
+ enough info to complete immediately) to the data in a frag.
+
+ On the ns32k, everything is in a different format, so we have broken
+ out separate functions for each kind of thing we could be fixing.
+ They all get called from here. */
+
+void
+ md_apply_fix(fixP, val)
+fixS *fixP;
+long val;
+{
+ char *buf = fixP->fx_where + fixP->fx_frag->fr_literal;
+
+ if (fixP->fx_bit_fixP) { /* Bitfields to fix, sigh */
+ md_number_to_field (buf, val, fixP->fx_bit_fixP);
+ } else switch (fixP->fx_im_disp) {
+
+ case 0: /* Immediate field */
+ md_number_to_imm (buf, val, fixP->fx_size);
+ break;
+
+ case 1: /* Displacement field */
+ md_number_to_disp (buf,
+ fixP->fx_pcrel? val + fixP->fx_pcrel_adjust: val,
+ fixP->fx_size);
+ break;
+
+ case 2: /* Pointer in a data object */
+ md_number_to_chars (buf, val, fixP->fx_size);
+ break;
+ }
+}
+
+/* Convert a relaxed displacement to ditto in final output */
+
+void
+ md_convert_frag(headers, fragP)
+object_headers *headers;
+register fragS *fragP;
+{
+ long disp;
+ long ext = 0;
+
+ /* Address in gas core of the place to store the displacement. */
+ register char *buffer_address = fragP->fr_fix + fragP->fr_literal;
+ /* Address in object code of the displacement. */
+ register int object_address = fragP->fr_fix + fragP->fr_address;
+
+ know(fragP->fr_symbol);
+
+ /* The displacement of the address, from current location. */
+ disp = (S_GET_VALUE(fragP->fr_symbol) + fragP->fr_offset) - object_address;
+ disp += fragP->fr_pcrel_adjust;
+
+ switch (fragP->fr_subtype) {
+ case IND(BRANCH,BYTE):
+ ext = 1;
+ break;
+ case IND(BRANCH,WORD):
+ ext = 2;
+ break;
+ case IND(BRANCH,DOUBLE):
+ ext = 4;
+ break;
+ }
+ if (ext) {
+ md_number_to_disp(buffer_address, (long)disp, (int)ext);
+ fragP->fr_fix += ext;
+ }
+} /* md_convert_frag() */
+
+
+
+/* This function returns the estimated size a variable object will occupy,
+ one can say that we tries to guess the size of the objects before we
+ actually know it */
+
+int md_estimate_size_before_relax(fragP, segment)
+register fragS *fragP;
+segT segment;
+{
+ int old_fix;
+ old_fix = fragP->fr_fix;
+ switch (fragP->fr_subtype) {
+ case IND(BRANCH,UNDEF):
+ if (S_GET_SEGMENT(fragP->fr_symbol) == segment) {
+ /* the symbol has been assigned a value */
+ fragP->fr_subtype = IND(BRANCH,BYTE);
+ } else {
+ /* we don't relax symbols defined in an other segment
+ the thing to do is to assume the object will occupy 4 bytes */
+ fix_new_ns32k(fragP,
+ (int)(fragP->fr_fix),
+ 4,
+ fragP->fr_symbol,
+ (symbolS *)0,
+ fragP->fr_offset,
+ 1,
+ fragP->fr_pcrel_adjust,
+ 1,
+ 0,
+ fragP->fr_bsr, /*sequent hack */
+ NO_RELOC);
+ fragP->fr_fix+=4;
+ /* fragP->fr_opcode[1]=0xff; */
+ frag_wane(fragP);
+ break;
+ }
+ case IND(BRANCH,BYTE):
+ fragP->fr_var+=1;
+ break;
+ default:
+ break;
+ }
+ return fragP->fr_var + fragP->fr_fix - old_fix;
+}
+
+int md_short_jump_size = 3;
+int md_long_jump_size = 5;
+int md_reloc_size = 8; /* Size of relocation record */
+
+void
+ md_create_short_jump(ptr,from_addr,to_addr,frag,to_symbol)
+char *ptr;
+long from_addr,
+ to_addr;
+fragS *frag;
+symbolS *to_symbol;
+{
+ long offset;
+
+ offset = to_addr - from_addr;
+ md_number_to_chars(ptr, (long)0xEA ,1);
+ md_number_to_disp(ptr+1,(long)offset,2);
+}
+
+void
+ md_create_long_jump(ptr,from_addr,to_addr,frag,to_symbol)
+char *ptr;
+long from_addr,
+ to_addr;
+fragS *frag;
+symbolS *to_symbol;
+{
+ long offset;
+
+ offset= to_addr - from_addr;
+ md_number_to_chars(ptr, (long)0xEA, 2);
+ md_number_to_disp(ptr+2,(long)offset,4);
+}
+
+/* JF this is a new function to parse machine-dep options */
+int
+ md_parse_option(argP,cntP,vecP)
+char **argP;
+int *cntP;
+char ***vecP;
+{
+ switch (**argP) {
+ case 'm':
+ (*argP)++;
+
+ if (!strcmp(*argP,"32032")) {
+ cpureg = cpureg_032;
+ mmureg = mmureg_032;
+ } else if (!strcmp(*argP, "32532")) {
+ cpureg = cpureg_532;
+ mmureg = mmureg_532;
+ } else
+ as_warn("Unknown -m option ignored");
+
+ while (**argP)
+ (*argP)++;
+ break;
+
+#ifdef PIC
+ case 'K':
+ got_offset_size = 4;
+ break;
+ case 'k':
+ got_symbol = symbol_find_or_make("__GLOBAL_OFFSET_TABLE_");
+ break;
+#endif
+
+ default:
+ return 0;
+ }
+ return 1;
+}
+
+/*
+ * bit_fix_new()
+ *
+ * Create a bit_fixS in obstack 'notes'.
+ * This struct is used to profile the normal fix. If the bit_fixP is a
+ * valid pointer (not NULL) the bit_fix data will be used to format the fix.
+ */
+bit_fixS *bit_fix_new(size, offset, min, max, add, base_type, base_adj)
+char size; /* Length of bitfield */
+char offset; /* Bit offset to bitfield */
+long base_type; /* 0 or 1, if 1 it's exploded to opcode ptr */
+long base_adj;
+long min; /* Signextended min for bitfield */
+long max; /* Signextended max for bitfield */
+long add; /* Add mask, used for huffman prefix */
+{
+ register bit_fixS * bit_fixP;
+
+ bit_fixP = (bit_fixS *)obstack_alloc(&notes,sizeof(bit_fixS));
+
+ bit_fixP->fx_bit_size = size;
+ bit_fixP->fx_bit_offset = offset;
+ bit_fixP->fx_bit_base = base_type;
+ bit_fixP->fx_bit_base_adj = base_adj;
+ bit_fixP->fx_bit_max = max;
+ bit_fixP->fx_bit_min = min;
+ bit_fixP->fx_bit_add = add;
+
+ return(bit_fixP);
+}
+
+void
+ fix_new_ns32k(frag, where, size, add_symbol, sub_symbol, offset, pcrel,
+ pcrel_adjust, im_disp, bit_fixP, bsr, r_type)
+fragS *frag; /* Which frag? */
+int where; /* Where in that frag? */
+int size; /* 1, 2 or 4 usually. */
+symbolS *add_symbol; /* X_add_symbol. */
+symbolS *sub_symbol; /* X_subtract_symbol. */
+long offset; /* X_add_number. */
+int pcrel; /* TRUE if PC-relative relocation. */
+char pcrel_adjust; /* not zero if adjustment of pcrel offset is needed */
+char im_disp; /* true if the value to write is a displacement */
+bit_fixS *bit_fixP; /* pointer at struct of bit_fix's, ignored if NULL */
+char bsr; /* sequent-linker-hack: 1 when relocobject is a bsr */
+int r_type; /* Relocation type */
+
+{
+#ifdef PIC
+ fixS *fixP = fix_new(frag, where, size, add_symbol, sub_symbol,
+ offset, pcrel, r_type, NULL);
+#else
+ fixS *fixP = fix_new(frag, where, size, add_symbol, sub_symbol,
+ offset, pcrel, r_type);
+#endif /* PIC */
+ fixP->fx_pcrel_adjust = pcrel_adjust;
+ fixP->fx_im_disp = im_disp;
+ fixP->fx_bit_fixP = bit_fixP;
+ fixP->fx_bsr = bsr;
+#ifdef PIC
+ if (r_type == RELOC_GLOB_DAT)
+ add_symbol->sy_forceout = 1;
+#endif /* PIC */
+} /* fix_new_ns32k() */
+
+/* We have no need to default values of symbols. */
+
+symbolS *
+ md_undefined_symbol (name)
+char *name;
+{
+ return 0;
+}
+
+/* Parse an operand that is machine-specific.
+ We just return without modifying the expression if we have nothing
+ to do. */
+
+/* ARGSUSED */
+void
+ md_operand (expressionP)
+expressionS *expressionP;
+{
+}
+
+/* Round up a section size to the appropriate boundary. */
+long
+ md_section_align (segment, size)
+segT segment;
+long size;
+{
+ return size; /* Byte alignment is fine */
+}
+
+/* Exactly what point is a PC-relative offset relative TO?
+ On the National warts, they're relative to the address of the offset,
+ with some funny adjustments in some circumstances during blue moons.
+ (??? Is this right? FIXME-SOON) */
+long
+ md_pcrel_from (fixP)
+fixS *fixP;
+{
+ long res;
+ res = fixP->fx_where + fixP->fx_frag->fr_address;
+#ifdef TE_SEQUENT
+ if (fixP->fx_frag->fr_bsr)
+ res += 0x12; /* FOO Kludge alert! */
+#endif
+ return(res);
+}
+
+/*
+ * Local Variables:
+ * comment-column: 0
+ * End:
+ */
+
+/* end of tc-ns32k.c */
diff --git a/gnu/usr.bin/as/config/tc-ns32k.h b/gnu/usr.bin/as/config/tc-ns32k.h
new file mode 100644
index 0000000..8f97304
--- /dev/null
+++ b/gnu/usr.bin/as/config/tc-ns32k.h
@@ -0,0 +1,66 @@
+/* tc-ns32k.h -- Opcode table for National Semi 32k processor
+ Copyright (C) 1987, 1992 Free Software Foundation, Inc.
+
+ This file is part of GAS, the GNU Assembler.
+
+ GAS is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GAS is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GAS; see the file COPYING. If not, write to
+ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#ifndef TC_NS32K
+#define TC_NS32K 1
+#include "bit_fix.h"
+
+#define LOCAL_LABELS_FB
+
+#define AOUT_MACHTYPE 137
+
+#define tc_aout_pre_write_hook(x) {;} /* not used */
+#define tc_crawl_symbol_chain(a) {;} /* not used */
+#define tc_headers_hook(a) {;} /* not used */
+
+#ifndef DEF_MODEC
+#define DEF_MODEC 20
+#endif
+
+#ifndef DEF_MODEL
+#define DEF_MODEL 20
+#endif
+
+#define MAX_ARGS 4
+#define ARG_LEN 50
+
+#if __STDC__ == 1
+
+void fix_new_ns32k(fragS *frag,
+ int where,
+ int size,
+ struct symbol *add_symbol,
+ struct symbol *sub_symbol,
+ long offset,
+ int pcrel,
+ int pcrel_adjust,
+ int im_disp,
+ bit_fixS *bit_fixP, /* really bit_fixS */
+ int bsr,
+ int r_type);
+
+#else /* not __STDC__ */
+
+void fix_new_ns32k();
+
+#endif /* not __STDC__ */
+
+#endif /* TC_NS32K */
+
+/* end of tc-ns32k.h */
diff --git a/gnu/usr.bin/as/config/tc-rs6000.c b/gnu/usr.bin/as/config/tc-rs6000.c
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/gnu/usr.bin/as/config/tc-rs6000.c
diff --git a/gnu/usr.bin/as/config/tc-rs6000.h b/gnu/usr.bin/as/config/tc-rs6000.h
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/gnu/usr.bin/as/config/tc-rs6000.h
diff --git a/gnu/usr.bin/as/config/tc-sparc.c b/gnu/usr.bin/as/config/tc-sparc.c
new file mode 100644
index 0000000..238e5f7
--- /dev/null
+++ b/gnu/usr.bin/as/config/tc-sparc.c
@@ -0,0 +1,1803 @@
+/* tc-sparc.c -- Assemble for the SPARC
+ Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
+
+ This file is part of GAS, the GNU Assembler.
+
+ GAS is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GAS is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GAS; see the file COPYING. If not, write to
+ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#ifndef lint
+static char rcsid[] = "$Id: tc-sparc.c,v 1.3 1994/12/23 22:37:40 nate Exp $";
+#endif
+
+#define cypress 1234
+
+#include <stdio.h>
+#include <ctype.h>
+
+#include "as.h"
+
+/* careful, this file includes data *declarations* */
+#include "opcode/sparc.h"
+
+#define DEBUG_SPARC 1
+void md_begin();
+void md_end();
+void md_number_to_chars();
+void md_assemble();
+char *md_atof();
+void md_convert_frag();
+void md_create_short_jump();
+void md_create_long_jump();
+int md_estimate_size_before_relax();
+void md_ri_to_chars();
+symbolS *md_undefined_symbol();
+static void sparc_ip();
+
+static enum sparc_architecture current_architecture = v6;
+static int architecture_requested = 0;
+static int warn_on_bump = 0;
+
+const relax_typeS md_relax_table[] = {
+ 0 };
+
+/* handle of the OPCODE hash table */
+static struct hash_control *op_hash = NULL;
+
+static void s_seg(), s_proc(), s_data1(), s_reserve(), s_common(), s_empty();
+extern void s_globl(), s_long(), s_short(), s_space(), cons();
+extern void s_align_bytes(), s_ignore();
+
+const pseudo_typeS md_pseudo_table[] = {
+ { "align", s_align_bytes, 0 }, /* Defaulting is invalid (0) */
+ { "empty", s_empty, 0 },
+ { "common", s_common, 0 },
+ { "global", s_globl, 0 },
+ { "half", cons, 2 },
+ { "optim", s_ignore, 0 },
+ { "proc", s_proc, 0 },
+ { "reserve", s_reserve, 0 },
+ { "seg", s_seg, 0 },
+ { "skip", s_space, 0 },
+ { "word", cons, 4 },
+ { NULL, 0, 0 },
+};
+
+const int md_short_jump_size = 4;
+const int md_long_jump_size = 4;
+const int md_reloc_size = 12; /* Size of relocation record */
+
+/* This array holds the chars that always start a comment. If the
+ pre-processor is disabled, these aren't very useful */
+const char comment_chars[] = "!"; /* JF removed '|' from comment_chars */
+
+/* This array holds the chars that only start a comment at the beginning of
+ a line. If the line seems to have the form '# 123 filename'
+ .line and .file directives will appear in the pre-processed output */
+/* Note that input_file.c hand checks for '#' at the beginning of the
+ first line of the input file. This is because the compiler outputs
+ #NO_APP at the beginning of its output. */
+/* Also note that comments started like this one will always
+ work if '/' isn't otherwise defined. */
+const char line_comment_chars[] = "#";
+
+/* Chars that can be used to separate mant from exp in floating point nums */
+const char EXP_CHARS[] = "eE";
+
+/* Chars that mean this number is a floating point constant */
+/* As in 0f12.456 */
+/* or 0d1.2345e12 */
+const char FLT_CHARS[] = "rRsSfFdDxXpP";
+
+/* Also be aware that MAXIMUM_NUMBER_OF_CHARS_FOR_FLOAT may have to be
+ changed in read.c. Ideally it shouldn't have to know about it at all,
+ but nothing is ideal around here.
+ */
+
+static unsigned char octal[256];
+#define isoctal(c) octal[c]
+ static unsigned char toHex[256];
+
+struct sparc_it {
+ char *error;
+ unsigned long opcode;
+ struct nlist *nlistp;
+ expressionS exp;
+ int pcrel;
+ enum reloc_type reloc;
+} the_insn, set_insn;
+
+#if __STDC__ == 1
+#if DEBUG_SPARC
+static void print_insn(struct sparc_it *insn);
+#endif
+static int getExpression(char *str);
+#else /* not __STDC__ */
+#if DEBUG_SPARC
+static void print_insn();
+#endif
+static int getExpression();
+#endif /* not __STDC__ */
+
+static char *Reloc[] = {
+ "RELOC_8",
+ "RELOC_16",
+ "RELOC_32",
+ "RELOC_DISP8",
+ "RELOC_DISP16",
+ "RELOC_DISP32",
+ "RELOC_WDISP30",
+ "RELOC_WDISP22",
+ "RELOC_HI22",
+ "RELOC_22",
+ "RELOC_13",
+ "RELOC_LO10",
+ "RELOC_SFA_BASE",
+ "RELOC_SFA_OFF13",
+ "RELOC_BASE10",
+ "RELOC_BASE13",
+ "RELOC_BASE22",
+ "RELOC_PC10",
+ "RELOC_PC22",
+ "RELOC_JMP_TBL",
+ "RELOC_SEGOFF16",
+ "RELOC_GLOB_DAT",
+ "RELOC_JMP_SLOT",
+ "RELOC_RELATIVE",
+ "NO_RELOC"
+};
+
+static char *expr_end;
+static int special_case;
+
+/*
+ * Instructions that require wierd handling because they're longer than
+ * 4 bytes.
+ */
+#define SPECIAL_CASE_SET 1
+#define SPECIAL_CASE_FDIV 2
+
+/*
+ * sort of like s_lcomm
+ *
+ */
+static int max_alignment = 15;
+
+static void s_reserve() {
+ char *name;
+ char *p;
+ char c;
+ int align;
+ int size;
+ int temp;
+ symbolS *symbolP;
+
+ name = input_line_pointer;
+ c = get_symbol_end();
+ p = input_line_pointer;
+ *p = c;
+ SKIP_WHITESPACE();
+
+ if (*input_line_pointer != ',') {
+ as_bad("Expected comma after name");
+ ignore_rest_of_line();
+ return;
+ }
+
+ ++input_line_pointer;
+
+ if ((size = get_absolute_expression()) < 0) {
+ as_bad("BSS length (%d.) <0! Ignored.", size);
+ ignore_rest_of_line();
+ return;
+ } /* bad length */
+
+ *p = 0;
+ symbolP = symbol_find_or_make(name);
+ *p = c;
+
+ if (strncmp(input_line_pointer, ",\"bss\"", 6) != 0) {
+ as_bad("bad .reserve segment: `%s'", input_line_pointer);
+ return;
+ } /* if not bss */
+
+ input_line_pointer += 6;
+ SKIP_WHITESPACE();
+
+ if (*input_line_pointer == ',') {
+ ++input_line_pointer;
+
+ SKIP_WHITESPACE();
+ if (*input_line_pointer == '\n') {
+ as_bad("Missing alignment");
+ return;
+ }
+
+ align = get_absolute_expression();
+ if (align > max_alignment){
+ align = max_alignment;
+ as_warn("Alignment too large: %d. assumed.", align);
+ } else if (align < 0) {
+ align = 0;
+ as_warn("Alignment negative. 0 assumed.");
+ }
+#ifdef MANY_SEGMENTS
+#define SEG_BSS SEG_E2
+ record_alignment(SEG_E2, align);
+#else
+ record_alignment(SEG_BSS, align);
+#endif
+
+ /* convert to a power of 2 alignment */
+ for (temp = 0; (align & 1) == 0; align >>= 1, ++temp) ;;
+
+ if (align != 1) {
+ as_bad("Alignment not a power of 2");
+ ignore_rest_of_line();
+ return;
+ } /* not a power of two */
+
+ align = temp;
+
+ /* Align */
+ align = ~((~0) << align); /* Convert to a mask */
+ local_bss_counter = (local_bss_counter + align) & (~align);
+ } /* if has optional alignment */
+
+ if (S_GET_OTHER(symbolP) == 0
+ && S_GET_DESC(symbolP) == 0
+ && ((S_GET_SEGMENT(symbolP) == SEG_BSS
+ && S_GET_VALUE(symbolP) == local_bss_counter)
+ || !S_IS_DEFINED(symbolP))) {
+ S_SET_VALUE(symbolP, local_bss_counter);
+ S_SET_SEGMENT(symbolP, SEG_BSS);
+ symbolP->sy_frag = &bss_address_frag;
+ local_bss_counter += size;
+ } else {
+ as_warn("Ignoring attempt to re-define symbol from %d. to %d.",
+ S_GET_VALUE(symbolP), local_bss_counter);
+ } /* if not redefining */
+
+ demand_empty_rest_of_line();
+ return;
+} /* s_reserve() */
+
+static void s_common() {
+ register char *name;
+ register char c;
+ register char *p;
+ register int temp;
+ register symbolS * symbolP;
+
+ name = input_line_pointer;
+ c = get_symbol_end();
+ /* just after name is now '\0' */
+ p = input_line_pointer;
+ *p = c;
+ SKIP_WHITESPACE();
+ if (* input_line_pointer != ',') {
+ as_bad("Expected comma after symbol-name");
+ ignore_rest_of_line();
+ return;
+ }
+ input_line_pointer ++; /* skip ',' */
+ if ((temp = get_absolute_expression ()) < 0) {
+ as_bad(".COMMon length (%d.) <0! Ignored.", temp);
+ ignore_rest_of_line();
+ return;
+ }
+ *p = 0;
+ symbolP = symbol_find_or_make(name);
+ *p = c;
+ if (S_IS_DEFINED(symbolP)) {
+ as_bad("Ignoring attempt to re-define symbol");
+ ignore_rest_of_line();
+ return;
+ }
+ if (S_GET_VALUE(symbolP) != 0) {
+ if (S_GET_VALUE(symbolP) != temp) {
+ as_warn("Length of .comm \"%s\" is already %d. Not changed to %d.",
+ S_GET_NAME(symbolP), S_GET_VALUE(symbolP), temp);
+ }
+ } else {
+ S_SET_VALUE(symbolP, temp);
+ S_SET_EXTERNAL(symbolP);
+ }
+ know(symbolP->sy_frag == &zero_address_frag);
+ if (strncmp(input_line_pointer, ",\"bss\"", 6) != 0
+ && strncmp(input_line_pointer, ",\"data\"", 7) != 0) {
+ p=input_line_pointer;
+ while (*p && *p != '\n')
+ p++;
+ c= *p;
+ *p='\0';
+ as_bad("bad .common segment: `%s'", input_line_pointer);
+ *p=c;
+ return;
+ }
+ input_line_pointer += 6 + (input_line_pointer[2] == 'd'); /* Skip either */
+ demand_empty_rest_of_line();
+ return;
+} /* s_common() */
+
+static void s_seg() {
+
+ if (strncmp(input_line_pointer, "\"text\"", 6) == 0) {
+ input_line_pointer += 6;
+ s_text();
+ return;
+ }
+ if (strncmp(input_line_pointer, "\"data\"", 6) == 0) {
+ input_line_pointer += 6;
+ s_data();
+ return;
+ }
+ if (strncmp(input_line_pointer, "\"data1\"", 7) == 0) {
+ input_line_pointer += 7;
+ s_data1();
+ return;
+ }
+ if (strncmp(input_line_pointer, "\"bss\"", 5) == 0) {
+ input_line_pointer += 5;
+ /* We only support 2 segments -- text and data -- for now, so
+ things in the "bss segment" will have to go into data for now.
+ You can still allocate SEG_BSS stuff with .lcomm or .reserve. */
+ subseg_new(SEG_DATA, 255); /* FIXME-SOMEDAY */
+ return;
+ }
+ as_bad("Unknown segment type");
+ demand_empty_rest_of_line();
+ return;
+} /* s_seg() */
+
+static void s_data1() {
+ subseg_new(SEG_DATA, 1);
+ demand_empty_rest_of_line();
+ return;
+} /* s_data1() */
+
+static void s_proc() {
+ extern char is_end_of_line[];
+
+ while (!is_end_of_line[*input_line_pointer]) {
+ ++input_line_pointer;
+ }
+ ++input_line_pointer;
+ return;
+} /* s_proc() */
+
+/*
+ * GI: This is needed for compatability with Sun's assembler - which
+ * otherwise generates a warning when certain "suspect" instructions
+ * appear in the delay slot of a branch. And more seriously without
+ * this directive in certain cases Sun's assembler will rearrange
+ * code thinking it knows how to alter things when it doesn't.
+ */
+static void
+s_empty()
+{
+ demand_empty_rest_of_line();
+ return;
+} /* s_empty() */
+
+/* This function is called once, at assembler startup time. It should
+ set up all the tables, etc. that the MD part of the assembler will need. */
+void md_begin() {
+ register char *retval = NULL;
+ int lose = 0;
+ register unsigned int i = 0;
+
+ op_hash = hash_new();
+ if (op_hash == NULL)
+ as_fatal("Virtual memory exhausted");
+
+ while (i < NUMOPCODES) {
+ const char *name = sparc_opcodes[i].name;
+ retval = hash_insert(op_hash, name, &sparc_opcodes[i]);
+ if (retval != NULL && *retval != '\0') {
+ fprintf (stderr, "internal error: can't hash `%s': %s\n",
+ sparc_opcodes[i].name, retval);
+ lose = 1;
+ }
+ do
+ {
+ if (sparc_opcodes[i].match & sparc_opcodes[i].lose) {
+ fprintf (stderr, "internal error: losing opcode: `%s' \"%s\"\n",
+ sparc_opcodes[i].name, sparc_opcodes[i].args);
+ lose = 1;
+ }
+ ++i;
+ } while (i < NUMOPCODES
+ && !strcmp(sparc_opcodes[i].name, name));
+ }
+
+ if (lose)
+ as_fatal("Broken assembler. No assembly attempted.");
+
+ for (i = '0'; i < '8'; ++i)
+ octal[i] = 1;
+ for (i = '0'; i <= '9'; ++i)
+ toHex[i] = i - '0';
+ for (i = 'a'; i <= 'f'; ++i)
+ toHex[i] = i + 10 - 'a';
+ for (i = 'A'; i <= 'F'; ++i)
+ toHex[i] = i + 10 - 'A';
+
+#if 0
+ if (flagseen['k'])
+ GOT_symbol = symbol_find_or_make("__GLOBAL_OFFSET_TABLE_");
+#endif
+} /* md_begin() */
+
+void md_end() {
+ return;
+} /* md_end() */
+
+void md_assemble(str)
+char *str;
+{
+ char *toP;
+ int rsd;
+
+ know(str);
+ sparc_ip(str);
+
+ /* See if "set" operand is absolute and small; skip sethi if so. */
+ if (special_case == SPECIAL_CASE_SET && the_insn.exp.X_seg == SEG_ABSOLUTE) {
+ if (the_insn.exp.X_add_number >= -(1<<12)
+ && the_insn.exp.X_add_number < (1<<12)) {
+ the_insn.opcode = 0x80102000 /* or %g0,imm,... */
+ | (the_insn.opcode & 0x3E000000) /* dest reg */
+ | (the_insn.exp.X_add_number & 0x1FFF); /* imm */
+ special_case = 0; /* No longer special */
+ the_insn.reloc = NO_RELOC; /* No longer relocated */
+ }
+ }
+
+ toP = frag_more(4);
+ /* put out the opcode */
+ md_number_to_chars(toP, the_insn.opcode, 4);
+
+ /* put out the symbol-dependent stuff */
+ if (the_insn.reloc != NO_RELOC) {
+ fix_new(frag_now, /* which frag */
+ (toP - frag_now->fr_literal), /* where */
+ 4, /* size */
+ the_insn.exp.X_add_symbol,
+ the_insn.exp.X_subtract_symbol,
+ the_insn.exp.X_add_number,
+ the_insn.pcrel,
+ the_insn.reloc,
+ the_insn.exp.X_got_symbol);
+ }
+ switch (special_case) {
+
+ case SPECIAL_CASE_SET:
+ special_case = 0;
+ know(the_insn.reloc == RELOC_HI22 ||
+ the_insn.reloc == RELOC_BASE22);
+ /* See if "set" operand has no low-order bits; skip OR if so. */
+ if (the_insn.exp.X_seg == SEG_ABSOLUTE
+ && ((the_insn.exp.X_add_number & 0x3FF) == 0))
+ return;
+ toP = frag_more(4);
+ rsd = (the_insn.opcode >> 25) & 0x1f;
+ the_insn.opcode = 0x80102000 | (rsd << 25) | (rsd << 14);
+ md_number_to_chars(toP, the_insn.opcode, 4);
+ fix_new(frag_now, /* which frag */
+ (toP - frag_now->fr_literal), /* where */
+ 4, /* size */
+ the_insn.exp.X_add_symbol,
+ the_insn.exp.X_subtract_symbol,
+ the_insn.exp.X_add_number,
+ the_insn.pcrel,
+ the_insn.reloc==RELOC_BASE22?RELOC_BASE10:RELOC_LO10,
+ the_insn.exp.X_got_symbol);
+ return;
+
+ case SPECIAL_CASE_FDIV:
+ /* According to information leaked from Sun, the "fdiv" instructions
+ on early SPARC machines would produce incorrect results sometimes.
+ The workaround is to add an fmovs of the destination register to
+ itself just after the instruction. This was true on machines
+ with Weitek 1165 float chips, such as the Sun-4/260 and /280. */
+ special_case = 0;
+ assert(the_insn.reloc == NO_RELOC);
+ toP = frag_more(4);
+ rsd = (the_insn.opcode >> 25) & 0x1f;
+ the_insn.opcode = 0x81A00020 | (rsd << 25) | rsd; /* fmovs dest,dest */
+ md_number_to_chars(toP, the_insn.opcode, 4);
+ return;
+
+ case 0:
+ return;
+
+ default:
+ as_fatal("md_assemble: failed sanity check.");
+ }
+} /* md_assemble() */
+
+static void sparc_ip(str)
+char *str;
+{
+ char *error_message = "";
+ char *s;
+ const char *args;
+ char c;
+ struct sparc_opcode *insn;
+ char *argsStart;
+ unsigned long opcode;
+ unsigned int mask = 0;
+ int match = 0;
+ int comma = 0;
+
+ for (s = str; islower(*s) || (*s >= '0' && *s <= '3'); ++s)
+ ;
+ switch (*s) {
+
+ case '\0':
+ break;
+
+ case ',':
+ comma = 1;
+
+ /*FALLTHROUGH */
+
+ case ' ':
+ *s++ = '\0';
+ break;
+
+ default:
+ as_bad("Unknown opcode: `%s'", str);
+ exit(1);
+ }
+ if ((insn = (struct sparc_opcode *) hash_find(op_hash, str)) == NULL) {
+ as_bad("Unknown opcode: `%s'", str);
+ return;
+ }
+ if (comma) {
+ *--s = ',';
+ }
+ argsStart = s;
+ for (;;) {
+ opcode = insn->match;
+ memset(&the_insn, '\0', sizeof(the_insn));
+ the_insn.reloc = NO_RELOC;
+
+ /*
+ * Build the opcode, checking as we go to make
+ * sure that the operands match
+ */
+ for (args = insn->args; ; ++args) {
+ switch (*args) {
+
+ case 'M':
+ case 'm':
+ if (strncmp(s, "%asr", 4) == 0) {
+ s += 4;
+
+ if (isdigit(*s)) {
+ long num = 0;
+
+ while (isdigit(*s)) {
+ num = num*10 + *s-'0';
+ ++s;
+ }
+
+ if (num < 16 || 31 < num) {
+ error_message = ": asr number must be between 15 and 31";
+ goto error;
+ } /* out of range */
+
+ opcode |= (*args == 'M' ? RS1(num) : RD(num));
+ continue;
+ } else {
+ error_message = ": expecting %asrN";
+ goto error;
+ } /* if %asr followed by a number. */
+
+ } /* if %asr */
+ break;
+
+
+ case '\0': /* end of args */
+ if (*s == '\0') {
+ match = 1;
+ }
+ break;
+
+ case '+':
+ if (*s == '+') {
+ ++s;
+ continue;
+ }
+ if (*s == '-') {
+ continue;
+ }
+ break;
+
+ case '[': /* these must match exactly */
+ case ']':
+ case ',':
+ case ' ':
+ if (*s++ == *args)
+ continue;
+ break;
+
+ case '#': /* must be at least one digit */
+ if (isdigit(*s++)) {
+ while (isdigit(*s)) {
+ ++s;
+ }
+ continue;
+ }
+ break;
+
+ case 'C': /* coprocessor state register */
+ if (strncmp(s, "%csr", 4) == 0) {
+ s += 4;
+ continue;
+ }
+ break;
+
+ case 'b': /* next operand is a coprocessor register */
+ case 'c':
+ case 'D':
+ if (*s++ == '%' && *s++ == 'c' && isdigit(*s)) {
+ mask = *s++;
+ if (isdigit(*s)) {
+ mask = 10 * (mask - '0') + (*s++ - '0');
+ if (mask >= 32) {
+ break;
+ }
+ } else {
+ mask -= '0';
+ }
+ switch (*args) {
+
+ case 'b':
+ opcode |= mask << 14;
+ continue;
+
+ case 'c':
+ opcode |= mask;
+ continue;
+
+ case 'D':
+ opcode |= mask << 25;
+ continue;
+ }
+ }
+ break;
+
+ case 'r': /* next operand must be a register */
+ case 's':
+ case '1':
+ case '2':
+ case 'd':
+ case 'x':
+ if (*s++ == '%') {
+ switch (c = *s++) {
+
+ case 'f': /* frame pointer */
+ if (*s++ == 'p') {
+ mask = 0x1e;
+ break;
+ }
+ goto error;
+
+ case 'g': /* global register */
+ if (isoctal(c = *s++)) {
+ mask = c - '0';
+ break;
+ }
+ goto error;
+
+ case 'i': /* in register */
+ if (isoctal(c = *s++)) {
+ mask = c - '0' + 24;
+ break;
+ }
+ goto error;
+
+ case 'l': /* local register */
+ if (isoctal(c = *s++)) {
+ mask= (c - '0' + 16) ;
+ break;
+ }
+ goto error;
+
+ case 'o': /* out register */
+ if (isoctal(c = *s++)) {
+ mask= (c - '0' + 8) ;
+ break;
+ }
+ goto error;
+
+ case 's': /* stack pointer */
+ if (*s++ == 'p') {
+ mask= 0xe;
+ break;
+ }
+ goto error;
+
+ case 'r': /* any register */
+ if (!isdigit(c = *s++)) {
+ goto error;
+ }
+ /* FALLTHROUGH */
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ if (isdigit(*s)) {
+ if ((c = 10 * (c - '0') + (*s++ - '0')) >= 32) {
+ goto error;
+ }
+ } else {
+ c -= '0';
+ }
+ mask= c;
+ break;
+
+ case 'x':
+ opcode |= (mask << 25) | mask;
+ continue;
+
+ default:
+ goto error;
+ }
+ /*
+ * Got the register, now figure out where
+ * it goes in the opcode.
+ */
+ switch (*args) {
+
+ case '1':
+ opcode |= mask << 14;
+ continue;
+
+ case '2':
+ opcode |= mask;
+ continue;
+
+ case 'd':
+ opcode |= mask << 25;
+ continue;
+
+ case 'r':
+ opcode |= (mask << 25) | (mask << 14);
+ continue;
+ case 'x':
+ opcode |= (mask << 25) | mask;
+ continue;
+ }
+ }
+ break;
+
+ case 'e': /* next operand is a floating point register */
+ case 'v':
+ case 'V':
+
+ case 'f':
+ case 'B':
+ case 'R':
+
+ case 'g':
+ case 'H':
+ case 'J': {
+ char format;
+
+ if (*s++ == '%'
+
+ && ((format = *s) == 'f')
+
+ && isdigit(*++s)) {
+
+
+
+ for (mask = 0; isdigit(*s); ++s) {
+ mask = 10 * mask + (*s - '0');
+ } /* read the number */
+
+ if ((*args == 'u'
+ || *args == 'v'
+ || *args == 'B'
+ || *args == 'H')
+ && (mask & 1)) {
+ break;
+ } /* register must be even numbered */
+
+ if ((*args == 'U'
+ || *args == 'V'
+ || *args == 'R'
+ || *args == 'J')
+ && (mask & 3)) {
+ break;
+ } /* register must be multiple of 4 */
+
+ if (format == 'f') {
+ if (mask >= 32) {
+ error_message = ": There are only 32 f registers; [0-31]";
+ goto error;
+ } /* on error */
+ } /* if not an 'f' register. */
+ } /* on error */
+
+ switch (*args) {
+
+ case 'v':
+ case 'V':
+ case 'e':
+ opcode |= RS1(mask);
+ continue;
+
+
+ case 'f':
+ case 'B':
+ case 'R':
+ opcode |= RS2(mask);
+ continue;
+
+ case 'g':
+ case 'H':
+ case 'J':
+ opcode |= RD(mask);
+ continue;
+ } /* pack it in. */
+
+ know(0);
+ break;
+ } /* float arg */
+
+ case 'F':
+ if (strncmp(s, "%fsr", 4) == 0) {
+ s += 4;
+ continue;
+ }
+ break;
+
+ case 'h': /* high 22 bits */
+ /*
+ * In the case of a `set' pseudo instruction
+ * we have an implied `%hi' operator.
+ */
+ if (special_case == SPECIAL_CASE_SET)
+ the_insn.reloc = RELOC_HI22;
+ else
+ the_insn.reloc = RELOC_22;
+ goto immediate;
+
+ case 'l': /* 22 bit PC relative immediate */
+ the_insn.reloc = RELOC_WDISP22;
+ the_insn.pcrel = 1;
+ goto immediate;
+
+ case 'L': /* 30 bit immediate */
+ the_insn.reloc =
+#ifdef PIC
+ flagseen['k']?RELOC_JMP_TBL:
+#endif
+ RELOC_WDISP30;
+ the_insn.pcrel = 1;
+ goto immediate;
+
+ case 'n': /* 22 bit immediate */
+ the_insn.reloc = RELOC_22;
+ goto immediate;
+
+ case 'i': /* 13 bit immediate */
+ the_insn.reloc = RELOC_13;
+
+ /*FALLTHROUGH */
+
+ immediate:
+ if (*s == ' ')
+ s++;
+ if (*s == '%') {
+ if ((c = s[1]) == 'h' && s[2] == 'i') {
+ if (the_insn.reloc != RELOC_22)
+ as_bad(
+ "`%hi' in improper context");
+ the_insn.reloc = RELOC_HI22;
+ s+=3;
+ } else if (c == 'l' && s[2] == 'o') {
+ the_insn.reloc = RELOC_LO10;
+ s+=3;
+ } else
+ break;
+ }
+ /* Note that if the getExpression() fails, we
+ will still have created U entries in the
+ symbol table for the 'symbols' in the input
+ string. Try not to create U symbols for
+ registers, etc. */
+ {
+ /* This stuff checks to see if the
+ expression ends in +%reg If it does,
+ it removes the register from the
+ expression, and re-sets 's' to point
+ to the right place */
+
+ char *s1;
+
+ for (s1 = s; *s1 && *s1 != ',' && *s1 != ']'; s1++) ;;
+
+ if (s1 != s && isdigit(s1[-1])) {
+ if (s1[-2] == '%' && s1[-3] == '+') {
+ s1 -= 3;
+ *s1 = '\0';
+ (void) getExpression(s);
+ *s1 = '+';
+ s = s1;
+ continue;
+ } else if (strchr("goli0123456789", s1[-2]) && s1[-3] == '%' && s1[-4] == '+') {
+ s1 -= 4;
+ *s1 = '\0';
+ (void) getExpression(s);
+ *s1 = '+';
+ s = s1;
+ continue;
+ }
+ }
+ }
+ (void)getExpression(s);
+#ifdef PIC
+ /*
+ * Handle refs to __GLOBAL_OFFSET_TABLE_
+ */
+ if (the_insn.exp.X_got_symbol) {
+ switch(the_insn.reloc) {
+ case RELOC_22:
+ case RELOC_HI22:
+ the_insn.reloc = RELOC_PC22;
+ the_insn.pcrel = 1;
+ break;
+ case RELOC_LO10:
+ the_insn.reloc = RELOC_PC10;
+ the_insn.pcrel = 1;
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (flagseen['k'] && the_insn.exp.X_add_symbol) {
+ switch (the_insn.reloc) {
+ case RELOC_LO10:
+ the_insn.reloc = RELOC_BASE10;
+ the_insn.exp.X_add_symbol->sy_forceout = 1;
+ break;
+ case RELOC_HI22:
+ the_insn.reloc = RELOC_BASE22;
+ the_insn.exp.X_add_symbol->sy_forceout = 1;
+ break;
+ case RELOC_13:
+ the_insn.reloc = RELOC_BASE13;
+ the_insn.exp.X_add_symbol->sy_forceout = 1;
+ break;
+ }
+ }
+#endif
+ s = expr_end;
+ continue;
+
+ case 'a':
+ if (*s++ == 'a') {
+ opcode |= ANNUL;
+ continue;
+ }
+ break;
+
+ case 'A': {
+ char *push = input_line_pointer;
+ expressionS e;
+
+ input_line_pointer = s;
+
+ if (expression(&e) == SEG_ABSOLUTE) {
+ opcode |= e.X_add_number << 5;
+ s = input_line_pointer;
+ input_line_pointer = push;
+ continue;
+ } /* if absolute */
+
+ break;
+ } /* alternate space */
+
+ case 'p':
+ if (strncmp(s, "%psr", 4) == 0) {
+ s += 4;
+ continue;
+ }
+ break;
+
+ case 'q': /* floating point queue */
+ if (strncmp(s, "%fq", 3) == 0) {
+ s += 3;
+ continue;
+ }
+ break;
+
+ case 'Q': /* coprocessor queue */
+ if (strncmp(s, "%cq", 3) == 0) {
+ s += 3;
+ continue;
+ }
+ break;
+
+ case 'S':
+ if (strcmp(str, "set") == 0) {
+ special_case = SPECIAL_CASE_SET;
+ continue;
+ } else if (strncmp(str, "fdiv", 4) == 0) {
+ special_case = SPECIAL_CASE_FDIV;
+ continue;
+ }
+ break;
+
+ case 't':
+ if (strncmp(s, "%tbr", 4) != 0)
+ break;
+ s += 4;
+ continue;
+
+ case 'w':
+ if (strncmp(s, "%wim", 4) != 0)
+ break;
+ s += 4;
+ continue;
+
+ case 'y':
+ if (strncmp(s, "%y", 2) != 0)
+ break;
+ s += 2;
+ continue;
+
+ default:
+ as_fatal("sparc_ip: failed sanity check.");
+ } /* switch on arg code */
+ break;
+ } /* for each arg that we expect */
+ error:
+ if (match == 0) {
+ /* Args don't match. */
+ if (((unsigned) (&insn[1] - sparc_opcodes)) < NUMOPCODES
+ && !strcmp(insn->name, insn[1].name)) {
+ ++insn;
+ s = argsStart;
+ continue;
+ } else {
+ as_bad("Illegal operands%s", error_message);
+ return;
+ }
+ } else {
+ if (insn->architecture > current_architecture) {
+ if (!architecture_requested || warn_on_bump) {
+
+ if (warn_on_bump) {
+ as_warn("architecture bumped from \"%s\" to \"%s\" on \"%s\"",
+ architecture_pname[current_architecture],
+ architecture_pname[insn->architecture],
+ str);
+ } /* if warning */
+
+ current_architecture = insn->architecture;
+ } else {
+ as_bad("architecture mismatch on \"%s\" (\"%s\"). current architecture is \"%s\"",
+ str,
+ architecture_pname[insn->architecture],
+ architecture_pname[current_architecture]);
+ return;
+ } /* if bump ok else error */
+ } /* if architecture higher */
+ } /* if no match */
+
+ break;
+ } /* forever looking for a match */
+
+ the_insn.opcode = opcode;
+#if DEBUG_SPARC
+ if (flagseen['D'])
+ print_insn(&the_insn);
+#endif
+ return;
+} /* sparc_ip() */
+
+static int getExpression(str)
+char *str;
+{
+ char *save_in;
+ segT seg;
+
+ save_in = input_line_pointer;
+ input_line_pointer = str;
+ switch (seg = expression(&the_insn.exp)) {
+
+ case SEG_ABSOLUTE:
+ case SEG_TEXT:
+ case SEG_DATA:
+ case SEG_BSS:
+ case SEG_UNKNOWN:
+ case SEG_DIFFERENCE:
+ case SEG_BIG:
+ case SEG_ABSENT:
+ break;
+
+ default:
+ the_insn.error = "bad segment";
+ expr_end = input_line_pointer;
+ input_line_pointer=save_in;
+ return 1;
+ }
+
+ expr_end = input_line_pointer;
+ input_line_pointer = save_in;
+ return 0;
+} /* getExpression() */
+
+
+/*
+ This is identical to the md_atof in m68k.c. I think this is right,
+ but I'm not sure.
+
+ Turn a string in input_line_pointer into a floating point constant of type
+ type, and store the appropriate bytes in *litP. The number of LITTLENUMS
+ emitted is stored in *sizeP. An error message is returned, or NULL on OK.
+ */
+
+/* Equal to MAX_PRECISION in atof-ieee.c */
+#define MAX_LITTLENUMS 6
+
+char *md_atof(type,litP,sizeP)
+char type;
+char *litP;
+int *sizeP;
+{
+ int prec;
+ LITTLENUM_TYPE words[MAX_LITTLENUMS];
+ LITTLENUM_TYPE *wordP;
+ char *t;
+ char *atof_ieee();
+
+ switch (type) {
+
+ case 'f':
+ case 'F':
+ case 's':
+ case 'S':
+ prec = 2;
+ break;
+
+ case 'd':
+ case 'D':
+ case 'r':
+ case 'R':
+ prec = 4;
+ break;
+
+ case 'x':
+ case 'X':
+ prec = 6;
+ break;
+
+ case 'p':
+ case 'P':
+ prec = 6;
+ break;
+
+ default:
+ *sizeP=0;
+ return "Bad call to MD_ATOF()";
+ }
+ t=atof_ieee(input_line_pointer,type,words);
+ if (t)
+ input_line_pointer=t;
+ *sizeP=prec * sizeof(LITTLENUM_TYPE);
+ for (wordP=words;prec--;) {
+ md_number_to_chars(litP,(long)(*wordP++),sizeof(LITTLENUM_TYPE));
+ litP+=sizeof(LITTLENUM_TYPE);
+ }
+ return ""; /* Someone should teach Dean about null pointers */
+} /* md_atof() */
+
+/*
+ * Write out big-endian.
+ */
+void md_number_to_chars(buf,val,n)
+char *buf;
+long val;
+int n;
+{
+
+ switch (n) {
+
+ case 4:
+ *buf++ = val >> 24;
+ *buf++ = val >> 16;
+ case 2:
+ *buf++ = val >> 8;
+ case 1:
+ *buf = val;
+ break;
+
+ default:
+ as_fatal("md_number_to_chars: failed sanity check.");
+ }
+ return;
+} /* md_number_to_chars() */
+
+static int reloc_check(val, bits, fixP)
+long val;
+int bits;
+fixS *fixP /* For reporting errors */;
+{
+ if (((val & (-1 << bits)) != 0)
+ && ((val & (-1 << bits)) != (-1 << (bits - 0)))) {
+
+ long addr = fixP->fx_where + fixP->fx_frag->fr_address;
+ int ln;
+ char *fname;
+
+ if (fixP->fx_frag->line) {
+ fname = fixP->fx_frag->line->file->filename;
+ ln = fixP->fx_frag->line->line;
+ } else {
+ fname = "";
+ ln = -1;
+ }
+
+ as_warn_where(fname, ln,
+ "Relocation (%s) overflow at %#x, value truncated.",
+ Reloc[fixP->fx_r_type], addr);
+ } /* on overflow */
+
+} /* reloc_check() */
+
+
+/* Apply a fixS to the frags, now that we know the value it ought to
+ hold. */
+
+void md_apply_fix(fixP, val)
+fixS *fixP;
+long val;
+{
+ char *buf = fixP->fx_where + fixP->fx_frag->fr_literal;
+ long addr = fixP->fx_where + fixP->fx_frag->fr_address;
+
+#if DEBUG_SPARC
+ if (flagseen['D'])
+ fprintf(stderr, "md_apply_fix: \"%s\" \"%s\", val %d -- %s\n",
+ ((fixP->fx_addsy != NULL)
+ ? ((S_GET_NAME(fixP->fx_addsy) != NULL)
+ ? S_GET_NAME(fixP->fx_addsy)
+ : "???")
+ : "0"),
+ ((fixP->fx_subsy != NULL)
+ ? ((S_GET_NAME(fixP->fx_subsy) != NULL)
+ ? S_GET_NAME(fixP->fx_subsy)
+ : "???")
+ : "0"),
+ val, Reloc[fixP->fx_r_type]);
+#endif
+
+ assert(fixP->fx_size == 4);
+ assert(fixP->fx_r_type < NO_RELOC);
+
+ fixP->fx_addnumber = val; /* Remember value for emit_reloc */
+
+ /*
+ * This is a hack. There should be a better way to
+ * handle this.
+ */
+ if (fixP->fx_r_type == RELOC_WDISP30 && fixP->fx_addsy) {
+ val += fixP->fx_where + fixP->fx_frag->fr_address;
+ }
+
+ switch (fixP->fx_r_type) {
+
+ /* Michael Bloom <mb@ttidca.tti.com> says... [This] change was
+ made to match the behavior of Sun's assembler. Some broken
+ loaders depend on that. At least one such loader actually
+ adds the section data to what it finds in the addend. (It
+ should only be using the addend like Sun's loader seems to).
+ This caused incorrect relocation: (addend + adjustment)
+ became ( ( 2 * addend ) + adjustment ). [and there should
+ be no cases that reach here anyway. */
+ case RELOC_32:
+ if (fixP->fx_addsy == NULL) {
+ /*
+ * Ok, the remarks above do not hold if the
+ * expression has been reduced to a number.
+ */
+ buf[0] = val >> 24;
+ buf[1] = val >> 16;
+ buf[2] = val >> 8;
+ buf[3] = val;
+ } else {
+ buf[0] = 0;
+ buf[1] = 0;
+ buf[2] = 0;
+ buf[3] = 0;
+ }
+ break;
+
+ case RELOC_JMP_TBL:
+ if (!fixP->fx_addsy) {
+ val = (val >>= 2) + 1;
+ reloc_check(val, 30, fixP);
+
+ buf[0] |= (val >> 24) & 0x3f;
+ buf[1]= (val >> 16);
+ buf[2] = val >> 8;
+ buf[3] = val;
+ }
+ break;
+
+ case RELOC_WDISP30:
+ val = (val >>= 2) + 1;
+ reloc_check(val, 30, fixP);
+
+ buf[0] |= (val >> 24) & 0x3f;
+ buf[1]= (val >> 16);
+ buf[2] = val >> 8;
+ buf[3] = val;
+ break;
+
+ case RELOC_WDISP22:
+ val = (val >>= 2) + 1;
+ reloc_check(val, 22, fixP);
+
+ buf[1] |= (val >> 16) & 0x3f;
+ buf[2] = val >> 8;
+ buf[3] = val;
+ break;
+
+ /*
+ * We should only use the RELOC_HI22 type as a result of the %hi
+ * operator (which is implicit in the case of the `set' pseudo op),
+ * This is NOT the same as using the `sethi' instruction, which merely
+ * puts the 22 bit operand into the high 22 bits of the destination
+ * register.
+ */
+ case RELOC_22:
+ if (!fixP->fx_addsy) {
+ reloc_check(val, 22, fixP);
+
+ buf[1] |= (val >> 16) & 0x3f;
+ buf[2] = val >> 8;
+ buf[3] = val;
+ }
+ break;
+
+ case RELOC_HI22:
+ case RELOC_BASE22:
+ if (!fixP->fx_addsy) {
+ buf[1] |= (val >> 26) & 0x3f;
+ buf[2] = val >> 18;
+ buf[3] = val >> 10;
+ } else {
+ if (flagseen['k'] && fixP->fx_r_type == RELOC_HI22)
+ as_warn("non-PIC access to %s",
+ S_GET_NAME(fixP->fx_addsy));
+ buf[2]=0;
+ buf[3]=0;
+ }
+ break;
+
+ case RELOC_13:
+ case RELOC_BASE13:
+ if (!fixP->fx_addsy) {
+ reloc_check(val, 13, fixP);
+ buf[2] |= (val >> 8) & 0x1f;
+ buf[3] = val;
+ } else {
+ buf[3]=0;
+ }
+ break;
+
+ case RELOC_LO10:
+ case RELOC_BASE10:
+ if (!fixP->fx_addsy) {
+ buf[2] |= (val >> 8) & 0x03;
+ buf[3] = val & 0xff;
+ } else {
+ if (flagseen['k'] && fixP->fx_r_type == RELOC_LO10)
+ as_warn("non-PIC access to %s",
+ S_GET_NAME(fixP->fx_addsy));
+ buf[3]=0;
+ }
+ break;
+
+ case RELOC_PC10:
+ case RELOC_PC22:
+ if (fixP->fx_addsy != GOT_symbol) {
+ as_fatal("GOT");
+ }
+ break;
+
+#if 0
+ case RELOC_8: /* These don't seem to ever be needed. */
+ case RELOC_16:
+ case RELOC_DISP8:
+ case RELOC_DISP16:
+ case RELOC_DISP32:
+ case RELOC_SEGOFF16:
+ case RELOC_SFA_BASE:
+ case RELOC_SFA_OFF13:
+
+ case RELOC_GLOB_DAT: /* These are output by linker only */
+ case RELOC_JMP_SLOT:
+ case RELOC_RELATIVE:
+#endif
+
+ case NO_RELOC:
+ default:
+ as_bad("bad relocation type: 0x%02x", fixP->fx_r_type);
+ break;
+ }
+} /* md_apply_fix() */
+
+/* should never be called for sparc */
+void md_create_short_jump(ptr, from_addr, to_addr, frag, to_symbol)
+char *ptr;
+long from_addr;
+long to_addr;
+fragS *frag;
+symbolS *to_symbol;
+{
+ as_fatal("sparc_create_short_jmp\n");
+} /* md_create_short_jump() */
+
+/* Translate internal representation of relocation info to target format.
+
+ On sparc: first 4 bytes are normal unsigned long address, next three
+ bytes are index, most sig. byte first. Byte 7 is broken up with
+ bit 7 as external, bits 6 & 5 unused, and the lower
+ five bits as relocation type. Next 4 bytes are long addend. */
+/* Thanx and a tip of the hat to Michael Bloom, mb@ttidca.tti.com */
+void tc_aout_fix_to_chars(where, fixP, segment_address_in_file)
+char *where;
+fixS *fixP;
+relax_addressT segment_address_in_file;
+{
+ long r_index;
+ long r_extern;
+ long r_addend = 0;
+ long r_address;
+#ifdef PIC
+ int kflag = 0;
+#endif
+
+ know(fixP->fx_addsy);
+
+ if (!S_IS_DEFINED(fixP->fx_addsy)) {
+ r_extern = 1;
+ r_index = fixP->fx_addsy->sy_number;
+ } else {
+ r_extern = 0;
+ r_index = S_GET_TYPE(fixP->fx_addsy);
+#ifdef PIC
+ if (flagseen['k']) {
+ switch (fixP->fx_r_type) {
+ case RELOC_BASE10:
+ case RELOC_BASE13:
+ case RELOC_BASE22:
+ r_index = fixP->fx_addsy->sy_number;
+ if (S_IS_EXTERNAL(fixP->fx_addsy))
+ r_extern = 1;
+ kflag = 1;
+ break;
+
+ case RELOC_32:
+ if (!S_IS_EXTERNAL(fixP->fx_addsy))
+ break;
+ r_extern = 1;
+ r_index = fixP->fx_addsy->sy_number;
+ break;
+
+ default:
+ break;
+ }
+ }
+#endif
+ }
+
+ /* this is easy */
+ md_number_to_chars(where,
+ r_address = fixP->fx_frag->fr_address + fixP->fx_where - segment_address_in_file,
+ 4);
+
+ /* now the fun stuff */
+ where[4] = (r_index >> 16) & 0x0ff;
+ where[5] = (r_index >> 8) & 0x0ff;
+ where[6] = r_index & 0x0ff;
+ where[7] = ((r_extern << 7) & 0x80) | (0 & 0x60) | (fixP->fx_r_type & 0x1F);
+
+ /* Also easy */
+ if (fixP->fx_addsy->sy_frag) {
+ r_addend = fixP->fx_addsy->sy_frag->fr_address;
+ }
+
+ if (fixP->fx_pcrel) {
+#ifdef PIC
+ if (fixP->fx_gotsy) {
+ r_addend = r_address;
+ r_addend += fixP->fx_addnumber;
+ } else
+#endif
+ r_addend -= r_address;
+ } else {
+#ifdef PIC
+ if (kflag)
+ r_addend = 0;
+ else
+#endif
+ r_addend = fixP->fx_addnumber;
+ }
+
+ md_number_to_chars(&where[8], r_addend, 4);
+
+ return;
+} /* tc_aout_fix_to_chars() */
+
+/* should never be called for sparc */
+void md_convert_frag(headers, fragP)
+object_headers *headers;
+register fragS *fragP;
+{
+ as_fatal("sparc_convert_frag\n");
+} /* md_convert_frag() */
+
+/* should never be called for sparc */
+void md_create_long_jump(ptr, from_addr, to_addr, frag, to_symbol)
+char *ptr;
+long from_addr, to_addr;
+fragS *frag;
+symbolS *to_symbol;
+{
+ as_fatal("sparc_create_long_jump\n");
+} /* md_create_long_jump() */
+
+/* should never be called for sparc */
+int md_estimate_size_before_relax(fragP, segtype)
+fragS *fragP;
+segT segtype;
+{
+ as_fatal("sparc_estimate_size_before_relax\n");
+ return(1);
+} /* md_estimate_size_before_relax() */
+
+#if DEBUG_SPARC
+/* for debugging only */
+static void print_insn(insn)
+struct sparc_it *insn;
+{
+
+ if (insn->error) {
+ fprintf(stderr, "ERROR: %s\n", insn->error);
+ }
+ fprintf(stderr, "opcode=0x%08x\n", insn->opcode);
+ fprintf(stderr, "reloc = %s\n", Reloc[insn->reloc]);
+ fprintf(stderr, "exp = {\n");
+ fprintf(stderr, "\t\tX_add_symbol = %s\n",
+ ((insn->exp.X_add_symbol != NULL)
+ ? ((S_GET_NAME(insn->exp.X_add_symbol) != NULL)
+ ? S_GET_NAME(insn->exp.X_add_symbol)
+ : "???")
+ : "0"));
+ fprintf(stderr, "\t\tX_sub_symbol = %s\n",
+ ((insn->exp.X_subtract_symbol != NULL)
+ ? (S_GET_NAME(insn->exp.X_subtract_symbol)
+ ? S_GET_NAME(insn->exp.X_subtract_symbol)
+ : "???")
+ : "0"));
+ fprintf(stderr, "\t\tX_got_symbol = %s\n",
+ ((insn->exp.X_got_symbol != NULL)
+ ? (S_GET_NAME(insn->exp.X_got_symbol)
+ ? S_GET_NAME(insn->exp.X_got_symbol)
+ : "???")
+ : "0"));
+ fprintf(stderr, "\t\tX_add_number = %d\n",
+ insn->exp.X_add_number);
+ fprintf(stderr, "}\n");
+ return;
+} /* print_insn() */
+#endif
+
+/* Set the hook... */
+
+/* void emit_sparc_reloc();
+ void (*md_emit_relocations)() = emit_sparc_reloc; */
+
+#ifdef comment
+
+/*
+ * Sparc/AM29K relocations are completely different, so it needs
+ * this machine dependent routine to emit them.
+ */
+#if defined(OBJ_AOUT) || defined(OBJ_BOUT)
+void emit_sparc_reloc(fixP, segment_address_in_file)
+register fixS *fixP;
+relax_addressT segment_address_in_file;
+{
+ struct reloc_info_generic ri;
+ register symbolS *symbolP;
+ extern char *next_object_file_charP;
+ /* long add_number; */
+
+ memset((char *) &ri, '\0', sizeof(ri));
+ for (; fixP; fixP = fixP->fx_next) {
+
+ if (fixP->fx_r_type >= NO_RELOC) {
+ as_fatal("fixP->fx_r_type = %d\n", fixP->fx_r_type);
+ }
+
+ if ((symbolP = fixP->fx_addsy) != NULL) {
+ ri.r_address = fixP->fx_frag->fr_address +
+ fixP->fx_where - segment_address_in_file;
+ if ((S_GET_TYPE(symbolP)) == N_UNDF) {
+ ri.r_extern = 1;
+ ri.r_index = symbolP->sy_number;
+ } else {
+ ri.r_extern = 0;
+ ri.r_index = S_GET_TYPE(symbolP);
+ }
+ if (symbolP && symbolP->sy_frag) {
+ ri.r_addend = symbolP->sy_frag->fr_address;
+ }
+ ri.r_type = fixP->fx_r_type;
+ if (fixP->fx_pcrel) {
+ /* ri.r_addend -= fixP->fx_where; */
+ ri.r_addend -= ri.r_address;
+ } else {
+ ri.r_addend = fixP->fx_addnumber;
+ }
+
+ md_ri_to_chars(next_object_file_charP, &ri);
+ next_object_file_charP += md_reloc_size;
+ }
+ }
+ return;
+} /* emit_sparc_reloc() */
+#endif /* aout or bout */
+#endif /* comment */
+
+/*
+ * md_parse_option
+ * Invocation line includes a switch not recognized by the base assembler.
+ * See if it's a processor-specific option. These are:
+ *
+ * -bump
+ * Warn on architecture bumps. See also -A.
+ *
+ * -Av6, -Av7, -Av8
+ * Select the architecture. Instructions or features not
+ * supported by the selected architecture cause fatal errors.
+ *
+ * The default is to start at v6, and bump the architecture up
+ * whenever an instruction is seen at a higher level.
+ *
+ * If -bump is specified, a warning is printing when bumping to
+ * higher levels.
+ *
+ * If an architecture is specified, all instructions must match
+ * that architecture. Any higher level instructions are flagged
+ * as errors.
+ *
+ * if both an architecture and -bump are specified, the
+ * architecture starts at the specified level, but bumps are
+ * warnings.
+ *
+ */
+int md_parse_option(argP, cntP, vecP)
+char **argP;
+int *cntP;
+char ***vecP;
+{
+ char *p;
+ const char **arch;
+
+ if (!strcmp(*argP,"bump")){
+ warn_on_bump = 1;
+
+ } else if (**argP == 'A'){
+ p = (*argP) + 1;
+
+ for (arch = architecture_pname; *arch != NULL; ++arch){
+ if (strcmp(p, *arch) == 0){
+ break;
+ } /* found a match */
+ } /* walk the pname table */
+
+ if (*arch == NULL){
+ as_bad("unknown architecture: %s", p);
+ } else {
+ current_architecture = (enum sparc_architecture) (arch - architecture_pname);
+ architecture_requested = 1;
+ }
+#ifdef PIC
+ } else if (**argP == 'k') {
+ /* Predefine GOT symbol */
+ GOT_symbol = symbol_find_or_make("__GLOBAL_OFFSET_TABLE_");
+#endif
+ } else {
+ /* Unknown option */
+ (*argP)++;
+ return 0;
+ }
+ **argP = '\0'; /* Done parsing this switch */
+ return 1;
+} /* md_parse_option() */
+
+/* We have no need to default values of symbols. */
+
+/* ARGSUSED */
+symbolS *md_undefined_symbol(name)
+char *name;
+{
+ return 0;
+} /* md_undefined_symbol() */
+
+/* Parse an operand that is machine-specific.
+ We just return without modifying the expression if we have nothing
+ to do. */
+
+/* ARGSUSED */
+void md_operand(expressionP)
+expressionS *expressionP;
+{
+} /* md_operand() */
+
+/* Round up a section size to the appropriate boundary. */
+long md_section_align(segment, size)
+segT segment;
+long size;
+{
+ return((size + 7) & ~7); /* Round all sects to multiple of 8 */
+} /* md_section_align() */
+
+/* Exactly what point is a PC-relative offset relative TO?
+ On the sparc, they're relative to the address of the offset, plus
+ its size. This gets us to the following instruction.
+ (??? Is this right? FIXME-SOON) */
+long md_pcrel_from(fixP)
+fixS *fixP;
+{
+#ifdef PIC
+ /*
+ * _GLOBAL_OFFSET_TABLE_ refs are relative to the offset of the
+ * current instruction. We omit fx_size from the computation (which
+ * is always 4 anyway).
+ */
+ if (fixP->fx_gotsy)
+ return fixP->fx_where + fixP->fx_frag->fr_address;
+ else
+#endif
+ return(fixP->fx_size + fixP->fx_where + fixP->fx_frag->fr_address);
+} /* md_pcrel_from() */
+
+void tc_aout_pre_write_hook(headers)
+object_headers *headers;
+{
+ H_SET_VERSION(headers, 1);
+ return;
+} /* tc_aout_pre_write_hook() */
+
+/*
+ * Local Variables:
+ * comment-column: 0
+ * fill-column: 131
+ * End:
+ */
+
+/* end of tc-sparc.c */
diff --git a/gnu/usr.bin/as/config/tc-sparc.h b/gnu/usr.bin/as/config/tc-sparc.h
new file mode 100644
index 0000000..c6dfa31
--- /dev/null
+++ b/gnu/usr.bin/as/config/tc-sparc.h
@@ -0,0 +1,52 @@
+/* tc-sparc.h - Macros and type defines for the sparc.
+ Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
+
+ This file is part of GAS, the GNU Assembler.
+
+ GAS is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2,
+ or (at your option) any later version.
+
+ GAS is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+ the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public
+ License along with GAS; see the file COPYING. If not, write
+ to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/*
+ * $Id: tc-sparc.h,v 1.2 1994/12/23 22:37:41 nate Exp $
+ */
+
+#define TC_SPARC 1
+
+#define LOCAL_LABELS_FB
+#define WORKING_DOT_WORD
+
+#ifdef __NetBSD__
+#define AOUT_MACHTYPE 138
+#endif
+
+#ifdef sun
+#define AOUT_MACHTYPE 3
+#define AOUT_VERSION 1
+#endif
+
+#define tc_headers_hook(a) {;} /* don't need it. */
+#define tc_crawl_symbol_chain(a) {;} /* don't need it. */
+
+void tc_aout_pre_write_hook();
+
+#define LISTING_HEADER "SPARC GAS "
+
+/*
+ * Local Variables:
+ * comment-column: 0
+ * fill-column: 131
+ * End:
+ */
+
+/* end of tc-sparc.h */
diff --git a/gnu/usr.bin/as/config/tc-tahoe.c b/gnu/usr.bin/as/config/tc-tahoe.c
new file mode 100644
index 0000000..4cd1a82
--- /dev/null
+++ b/gnu/usr.bin/as/config/tc-tahoe.c
@@ -0,0 +1,1924 @@
+/* tc-tahoe.c
+ Not part of GAS yet. */
+
+#include "as.h"
+#include "obstack.h"
+
+ /* this bit glommed from tahoe-inst.h */
+
+typedef unsigned char byte;
+typedef byte tahoe_opcodeT;
+
+/*
+ * This is part of tahoe-ins-parse.c & friends.
+ * We want to parse a tahoe instruction text into a tree defined here.
+ */
+
+#define TIT_MAX_OPERANDS (4) /* maximum number of operands in one
+ single tahoe instruction */
+
+struct top /* tahoe instruction operand */
+{
+ int top_ndx; /* -1, or index register. eg 7=[R7] */
+ int top_reg; /* -1, or register number. eg 7 = R7 or (R7) */
+ byte top_mode; /* Addressing mode byte. This byte, defines
+ which of the 11 modes opcode is. */
+
+ char top_access; /* Access type wanted for this opperand
+ 'b'branch ' 'no-instruction 'amrvw' */
+ char top_width; /* Operand width expected, one of "bwlq?-:!" */
+
+ char *top_error; /* Say if operand is inappropriate */
+
+ expressionS exp_of_operand; /* The expression as parsed by expression()*/
+
+ byte top_dispsize; /* Number of bytes in the displacement if we
+ can figure it out */
+};
+
+/* The addressing modes for an operand. These numbers are the acutal values
+ for certain modes, so be carefull if you screw with them. */
+#define TAHOE_DIRECT_REG (0x50)
+#define TAHOE_REG_DEFERRED (0x60)
+
+#define TAHOE_REG_DISP (0xE0)
+#define TAHOE_REG_DISP_DEFERRED (0xF0)
+
+#define TAHOE_IMMEDIATE (0x8F)
+#define TAHOE_IMMEDIATE_BYTE (0x88)
+#define TAHOE_IMMEDIATE_WORD (0x89)
+#define TAHOE_IMMEDIATE_LONGWORD (0x8F)
+#define TAHOE_ABSOLUTE_ADDR (0x9F)
+
+#define TAHOE_DISPLACED_RELATIVE (0xEF)
+#define TAHOE_DISP_REL_DEFERRED (0xFF)
+
+#define TAHOE_AUTO_DEC (0x7E)
+#define TAHOE_AUTO_INC (0x8E)
+#define TAHOE_AUTO_INC_DEFERRED (0x9E)
+/* INDEXED_REG is decided by the existance or lack of a [reg] */
+
+/* These are encoded into top_width when top_access=='b'
+ and it's a psuedo op.*/
+#define TAHOE_WIDTH_ALWAYS_JUMP '-'
+#define TAHOE_WIDTH_CONDITIONAL_JUMP '?'
+#define TAHOE_WIDTH_BIG_REV_JUMP '!'
+#define TAHOE_WIDTH_BIG_NON_REV_JUMP ':'
+
+/* The hex code for certain tahoe commands and modes.
+ This is just for readability. */
+#define TAHOE_JMP (0x71)
+#define TAHOE_PC_REL_LONG (0xEF)
+#define TAHOE_BRB (0x11)
+#define TAHOE_BRW (0x13)
+/* These, when 'ored' with, or added to, a register number,
+ set up the number for the displacement mode. */
+#define TAHOE_PC_OR_BYTE (0xA0)
+#define TAHOE_PC_OR_WORD (0xC0)
+#define TAHOE_PC_OR_LONG (0xE0)
+
+struct tit /* get it out of the sewer, it stands for
+ tahoe instruction tree (Geeze!) */
+{
+ tahoe_opcodeT tit_opcode; /* The opcode. */
+ byte tit_operands; /* How many operands are here. */
+ struct top tit_operand[TIT_MAX_OPERANDS]; /* Operands */
+ char *tit_error; /* "" or fatal error text */
+};
+
+/* end: tahoe-inst.h */
+
+/* tahoe.c - tahoe-specific -
+ Not part of gas yet.
+ */
+
+#include "opcode/tahoe.h"
+
+/* This is the number to put at the beginning of the a.out file */
+long omagic = OMAGIC;
+
+/* These chars start a comment anywhere in a source file (except inside
+ another comment or a quoted string. */
+const char comment_chars[] = "#;";
+
+/* These chars only start a comment at the beginning of a line. */
+const char line_comment_chars[] = "#";
+
+/* Chars that can be used to separate mant from exp in floating point nums */
+const char EXP_CHARS[] = "eE";
+
+/* Chars that mean this number is a floating point constant
+ as in 0f123.456
+ or 0d1.234E-12 (see exp chars above)
+ Note: The Tahoe port doesn't support floating point constants. This is
+ consistant with 'as' If it's needed, I can always add it later. */
+const char FLT_CHARS[] = "df";
+
+/* Also be aware that MAXIMUM_NUMBER_OF_CHARS_FOR_FLOAT may have to be
+ changed in read.c . Ideally it shouldn't have to know about it at all,
+ but nothing is ideal around here.
+ (The tahoe has plenty of room, so the change currently isn't needed.)
+ */
+
+static struct tit t; /* A tahoe instruction after decoding. */
+
+void float_cons ();
+/* A table of pseudo ops (sans .), the function called, and an integer op
+ that the function is called with. */
+
+const pseudo_typeS md_pseudo_table[] =
+{
+ {"dfloat", float_cons, 'd'},
+ {"ffloat", float_cons, 'f'},
+ {0}
+};
+
+/*
+ * For Tahoe, relative addresses of "just the right length" are pretty easy.
+ * The branch displacement is always the last operand, even in
+ * synthetic instructions.
+ * For Tahoe, we encode the relax_substateTs (in e.g. fr_substate) as:
+ *
+ * 4 3 2 1 0 bit number
+ * ---/ /--+-------+-------+-------+-------+-------+
+ * | what state ? | how long ? |
+ * ---/ /--+-------+-------+-------+-------+-------+
+ *
+ * The "how long" bits are 00=byte, 01=word, 10=long.
+ * This is a Un*x convention.
+ * Not all lengths are legit for a given value of (what state).
+ * The four states are listed below.
+ * The "how long" refers merely to the displacement length.
+ * The address usually has some constant bytes in it as well.
+ *
+
+States for Tahoe address relaxing.
+1. TAHOE_WIDTH_ALWAYS_JUMP (-)
+ Format: "b-"
+ Tahoe opcodes are: (Hex)
+ jr 11
+ jbr 11
+ Simple branch.
+ Always, 1 byte opcode, then displacement/absolute.
+ If word or longword, change opcode to brw or jmp.
+
+
+2. TAHOE_WIDTH_CONDITIONAL_JUMP (?)
+ J<cond> where <cond> is a simple flag test.
+ Format: "b?"
+ Tahoe opcodes are: (Hex)
+ jneq/jnequ 21
+ jeql/jeqlu 31
+ jgtr 41
+ jleq 51
+ jgeq 81
+ jlss 91
+ jgtru a1
+ jlequ b1
+ jvc c1
+ jvs d1
+ jlssu/jcs e1
+ jgequ/jcc f1
+ Always, you complement 4th bit to reverse the condition.
+ Always, 1-byte opcode, then 1-byte displacement.
+
+3. TAHOE_WIDTH_BIG_REV_JUMP (!)
+ Jbc/Jbs where cond tests a memory bit.
+ Format: "rlvlb!"
+ Tahoe opcodes are: (Hex)
+ jbs 0e
+ jbc 1e
+ Always, you complement 4th bit to reverse the condition.
+ Always, 1-byte opcde, longword, longword-address, 1-word-displacement
+
+4. TAHOE_WIDTH_BIG_NON_REV_JUMP (:)
+ JaoblXX/Jbssi
+ Format: "rlmlb:"
+ Tahoe opcodes are: (Hex)
+ aojlss 2f
+ jaoblss 2f
+ aojleq 3f
+ jaobleq 3f
+ jbssi 5f
+ Always, we cannot reverse the sense of the branch; we have a word
+ displacement.
+
+We need to modify the opcode is for class 1, 2 and 3 instructions.
+After relax() we may complement the 4th bit of 2 or 3 to reverse sense of
+branch.
+
+We sometimes store context in the operand literal. This way we can figure out
+after relax() what the original addressing mode was. (Was is pc_rel, or
+pc_rel_disp? That sort of thing.) */
+
+/* These displacements are relative to the START address of the
+ displacement which is at the start of the displacement, not the end of
+ the instruction. The hardware pc_rel is at the end of the instructions.
+ That's why all the displacements have the length of the displacement added
+ to them. (WF + length(word))
+
+ The first letter is Byte, Word.
+ 2nd letter is Forward, Backward. */
+#define BF (1+ 127)
+#define BB (1+-128)
+#define WF (2+ 32767)
+#define WB (2+-32768)
+/* Dont need LF, LB because they always reach. [They are coded as 0.] */
+
+#define C(a,b) ENCODE_RELAX(a,b)
+ /* This macro has no side-effects. */
+#define ENCODE_RELAX(what,length) (((what) << 2) + (length))
+#define RELAX_STATE(what) ((what) >> 2)
+#define RELAX_LENGTH(length) ((length) && 3)
+
+#define STATE_ALWAYS_BRANCH (1)
+#define STATE_CONDITIONAL_BRANCH (2)
+#define STATE_BIG_REV_BRANCH (3)
+#define STATE_BIG_NON_REV_BRANCH (4)
+#define STATE_PC_RELATIVE (5)
+
+#define STATE_BYTE (0)
+#define STATE_WORD (1)
+#define STATE_LONG (2)
+#define STATE_UNDF (3) /* Symbol undefined in pass1 */
+
+/* This is the table used by gas to figure out relaxing modes. The fields are
+ forward_branch reach, backward_branch reach, number of bytes it would take,
+ where the next biggest branch is. */
+const relax_typeS
+md_relax_table[] =
+{
+ {
+ 1, 1, 0, 0
+ }, /* error sentinel 0,0 */
+ {
+ 1, 1, 0, 0
+ }, /* unused 0,1 */
+ {
+ 1, 1, 0, 0
+ }, /* unused 0,2 */
+ {
+ 1, 1, 0, 0
+ }, /* unused 0,3 */
+ /* Unconditional branch cases "jrb"
+ The relax part is the actual displacement */
+ {
+ BF, BB, 1, C (1, 1)
+ }, /* brb B`foo 1,0 */
+ {
+ WF, WB, 2, C (1, 2)
+ }, /* brw W`foo 1,1 */
+ {
+ 0, 0, 5, 0
+ }, /* Jmp L`foo 1,2 */
+ {
+ 1, 1, 0, 0
+ }, /* unused 1,3 */
+ /* Reversible Conditional Branch. If the branch won't reach, reverse
+ it, and jump over a brw or a jmp that will reach. The relax part is the
+ actual address. */
+ {
+ BF, BB, 1, C (2, 1)
+ }, /* b<cond> B`foo 2,0 */
+ {
+ WF + 2, WB + 2, 4, C (2, 2)
+ }, /* brev over, brw W`foo, over: 2,1 */
+ {
+ 0, 0, 7, 0
+ }, /* brev over, jmp L`foo, over: 2,2 */
+ {
+ 1, 1, 0, 0
+ }, /* unused 2,3 */
+ /* Another type of reversable branch. But this only has a word
+ displacement. */
+ {
+ 1, 1, 0, 0
+ }, /* unused 3,0 */
+ {
+ WF, WB, 2, C(3, 2)
+ }, /* jbX W`foo 3,1 */
+ {
+ 0, 0, 8, 0
+ }, /* jrevX over, jmp L`foo, over: 3,2 */
+ {
+ 1, 1, 0, 0
+ }, /* unused 3,3 */
+ /* These are the non reversable branches, all of which have a word
+ displacement. If I can't reach, branch over a byte branch, to a
+ jump that will reach. The jumped branch jumps over the reaching
+ branch, to continue with the flow of the program. It's like playing
+ leap frog. */
+ {
+ 1, 1, 0, 0
+ }, /* unused 4,0 */
+ {
+ WF, WB, 2, C (4, 2)
+ }, /* aobl_ W`foo 4,1 */
+ {
+ 0, 0, 10, 0
+ }, /*aobl_ W`hop,br over,hop: jmp L^foo,over 4,2*/
+ {
+ 1, 1, 0, 0
+ }, /* unused 4,3 */
+ /* Normal displacement mode, no jumping or anything like that.
+ The relax points to one byte before the address, thats why all
+ the numbers are up by one. */
+ {
+ BF + 1, BB + 1, 2, C (5, 1)
+ }, /* B^"foo" 5,0 */
+ {
+ WF + 1, WB + 1, 3, C (5, 2)
+ }, /* W^"foo" 5,1 */
+ {
+ 0, 0, 5, 0
+ }, /* L^"foo" 5,2 */
+ {
+ 1, 1, 0, 0
+ }, /* unused 5,3 */
+};
+
+#undef C
+#undef BF
+#undef BB
+#undef WF
+#undef WB
+/* End relax stuff */
+
+static struct hash_control *op_hash = NULL; /* handle of the OPCODE hash table
+ NULL means any use before md_begin() will
+ crash */
+
+/* Init function. Build the hash table. */
+void
+md_begin()
+{
+ struct tot *tP;
+ char *errorval = "";
+ int synthetic_too = 1; /* If 0, just use real opcodes. */
+
+ if ((op_hash = hash_new())){
+ for (tP= totstrs; *tP->name && !*errorval; tP++){
+ errorval = hash_insert (op_hash, tP->name, &tP->detail);
+ }
+ if (synthetic_too){
+ for (tP = synthetic_totstrs; *tP->name && !*errorval; tP++){
+ errorval = hash_insert (op_hash, tP->name, &tP->detail);
+ }
+ }
+ }else{
+ errorval = "Virtual memory exceeded";
+ }
+ if (*errorval)
+ as_fatal(errorval);
+}/* md_begin */
+
+void
+md_end()
+{
+}/* md_end */
+
+int
+md_parse_option (argP, cntP, vecP)
+ char **argP;
+ int *cntP;
+ char ***vecP;
+{
+ char *temp_name; /* name for -t or -d options */
+ char opt;
+
+ switch (**argP){
+ case 'a':
+ as_warn("The -a option doesn't exits. (Dispite what the man page says!");
+
+ case 'J':
+ as_warn("JUMPIFY (-J) not implemented, use psuedo ops instead.");
+ break;
+
+ case 'S':
+ as_warn ("SYMBOL TABLE not implemented");
+ break; /* SYMBOL TABLE not implemented */
+
+ case 'T':
+ as_warn ("TOKEN TRACE not implemented");
+ break; /* TOKEN TRACE not implemented */
+
+ case 'd':
+ case 't':
+ opt= **argP;
+ if (**argP){ /* Rest of argument is filename. */
+ temp_name = *argP;
+ while (**argP)
+ (*argP)++;
+ }else if (*cntP){
+ while (**argP)
+ (*argP)++;
+ --(*cntP);
+ temp_name = *++(*vecP);
+ **vecP = NULL; /* Remember this is not a file-name. */
+ }else{
+ as_warn ("I expected a filename after -%c.",opt);
+ temp_name = "{absent}";
+ }
+
+ if(opt=='d')
+ as_warn ("Displacement length %s ignored!", temp_name);
+ else
+ as_warn ("I don't need or use temp. file \"%s\".", temp_name);
+ break;
+
+ case 'V':
+ as_warn ("I don't use an interpass file! -V ignored");
+ break;
+
+ default:
+ return 0;
+
+ }
+ return 1;
+}
+
+/* The functions in this section take numbers in the machine format, and
+ munges them into Tahoe byte order.
+ They exist primarily for cross assembly purpose. */
+void /* Knows about order of bytes in address. */
+md_number_to_chars (con, value, nbytes)
+ char con[]; /* Return 'nbytes' of chars here. */
+ long int value; /* The value of the bits. */
+ int nbytes; /* Number of bytes in the output. */
+{
+ int n = nbytes;
+ long int v = value;
+
+ con += nbytes - 1; /* Tahoes is (Bleah!) big endian */
+ while (nbytes--){
+ *con-- = value; /* Lint wants & MASK_CHAR. */
+ value >>= BITS_PER_CHAR;
+ }
+ /* XXX line number probably botched for this warning message. */
+ if (value != 0 && value != -1)
+ as_warn ("Displacement (%ld) long for instruction field length (%d).",v,n);
+}
+
+#ifdef comment
+void /* Knows about order of bytes in address. */
+md_number_to_imm (con, value, nbytes)
+ char con[]; /* Return 'nbytes' of chars here. */
+ long int value; /* The value of the bits. */
+ int nbytes; /* Number of bytes in the output. */
+{
+ md_number_to_chars(con, value, nbytes);
+}
+#endif /* comment */
+
+void
+ md_apply_fix(fixP, val)
+fixS *fixP;
+long val;
+{
+ char *place = fixP->fx_where + fixP->fx_frag->fr_literal;
+ md_number_to_chars(place, val, fixP->fx_size);
+ return;
+} /* md_apply_fix() */
+
+void /* Knows about order of bytes in address. */
+md_number_to_disp (con, value, nbytes)
+ char con[]; /* Return 'nbytes' of chars here. */
+ long int value; /* The value of the bits. */
+ int nbytes; /* Number of bytes in the output. */
+{
+ md_number_to_chars(con, value, nbytes);
+}
+
+void /* Knows about order of bytes in address. */
+md_number_to_field (con, value, nbytes)
+ char con[]; /* Return 'nbytes' of chars here. */
+ long int value; /* The value of the bits. */
+ int nbytes; /* Number of bytes in the output. */
+{
+ md_number_to_chars(con, value, nbytes);
+}
+
+/* Put the bits in an order that a tahoe will understand, despite the ordering
+ of the native machine.
+ On Tahoe: first 4 bytes are normal unsigned big endian long,
+ next three bytes are symbolnum, in kind of 3 byte big endian (least sig. byte last).
+ The last byte is broken up with bit 7 as pcrel,
+ bits 6 & 5 as length,
+ bit 4 as extern and the last nibble as 'undefined'. */
+
+#if comment
+void
+md_ri_to_chars (ri_p, ri)
+ struct relocation_info *ri_p, ri;
+{
+ byte the_bytes[sizeof(struct relocation_info)];
+ /* The reason I can't just encode these directly into ri_p is that
+ ri_p may point to ri. */
+
+ /* This is easy */
+ md_number_to_chars (the_bytes, ri.r_address, sizeof(ri.r_address));
+
+ /* now the fun stuff */
+ the_bytes[4] = (ri.r_symbolnum >> 16) & 0x0ff;
+ the_bytes[5] = (ri.r_symbolnum >> 8) & 0x0ff;
+ the_bytes[6] = ri.r_symbolnum & 0x0ff;
+ the_bytes[7] = (((ri.r_extern << 4) & 0x10) | ((ri.r_length << 5) & 0x60) |
+ ((ri.r_pcrel << 7) & 0x80)) & 0xf0;
+
+ bcopy (the_bytes, (char *) ri_p, sizeof (struct relocation_info));
+}
+#endif /* comment */
+
+/* Put the bits in an order that a tahoe will understand, despite the ordering
+ of the native machine.
+ On Tahoe: first 4 bytes are normal unsigned big endian long,
+ next three bytes are symbolnum, in kind of 3 byte big endian (least sig. byte last).
+ The last byte is broken up with bit 7 as pcrel,
+ bits 6 & 5 as length,
+ bit 4 as extern and the last nibble as 'undefined'. */
+
+void tc_aout_fix_to_chars(where, fixP, segment_address_in_file)
+char *where;
+fixS *fixP;
+relax_addressT segment_address_in_file;
+{
+ /*
+ * In: length of relocation (or of address) in chars: 1, 2 or 4.
+ * Out: GNU LD relocation length code: 0, 1, or 2.
+ */
+
+ static unsigned char nbytes_r_length[] = { 42, 0, 1, 42, 2 };
+ long r_symbolnum;
+
+ know(fixP->fx_addsy != NULL);
+
+ md_number_to_chars(where,
+ fixP->fx_frag->fr_address + fixP->fx_where - segment_address_in_file,
+ 4);
+
+ r_symbolnum = (S_IS_DEFINED(fixP->fx_addsy)
+ ? S_GET_TYPE(fixP->fx_addsy)
+ : fixP->fx_addsy->sy_number);
+
+ where[4] = (r_symbolnum >> 16) & 0x0ff;
+ where[5] = (r_symbolnum >> 8) & 0x0ff;
+ where[6] = r_symbolnum & 0x0ff;
+ where[7] = (((fixP->fx_pcrel << 7) & 0x80)
+ | ((nbytes_r_length[fixP->fx_size] << 5) & 0x60)
+ | ((!S_IS_DEFINED(fixP->fx_addsy) << 4) & 0x10));
+
+ return;
+} /* tc_aout_fix_to_chars() */
+
+/* Relocate byte stuff */
+
+/* This is for broken word. */
+const int md_short_jump_size = 3;
+
+void
+md_create_short_jump (ptr, from_addr, to_addr, frag, to_symbol)
+ char *ptr;
+ long from_addr, to_addr;
+ fragS *frag;
+ symbolS *to_symbol;
+{
+ long offset;
+
+ offset = to_addr - (from_addr + 1);
+ *ptr++ = TAHOE_BRW;
+ md_number_to_chars (ptr, offset, 2);
+}
+
+const int md_long_jump_size = 6;
+const int md_reloc_size = 8; /* Size of relocation record */
+
+void
+md_create_long_jump (ptr, from_addr, to_addr, frag, to_symbol)
+ char *ptr;
+ long from_addr, to_addr;
+ fragS *frag;
+ symbolS *to_symbol;
+{
+ long offset;
+
+ offset = to_addr - (from_addr + 4);
+ *ptr++ = TAHOE_JMP;
+ *ptr++ = TAHOE_PC_REL_LONG;
+ md_number_to_chars (ptr, offset, 4);
+}
+
+/*
+ * md_estimate_size_before_relax()
+ *
+ * Called just before relax().
+ * Any symbol that is now undefined will not become defined, so we assumed
+ * that it will be resolved by the linker.
+ * Return the correct fr_subtype in the frag, for relax()
+ * Return the initial "guess for fr_var" to caller. (How big I think this
+ * will be.)
+ * The guess for fr_var is ACTUALLY the growth beyond fr_fix.
+ * Whatever we do to grow fr_fix or fr_var contributes to our returned value.
+ * Although it may not be explicit in the frag, pretend fr_var starts with a
+ * 0 value.
+ */
+int
+md_estimate_size_before_relax (fragP, segment_type)
+ register fragS *fragP;
+ segT segment_type; /* N_DATA or N_TEXT. */
+{
+ register char *p;
+ register int old_fr_fix;
+/* int pc_rel; FIXME: remove this */
+
+ old_fr_fix = fragP->fr_fix;
+ switch (fragP->fr_subtype){
+ case ENCODE_RELAX (STATE_PC_RELATIVE, STATE_UNDF):
+ if (S_GET_SEGMENT(fragP->fr_symbol) == segment_type) {
+ /* The symbol was in the same segment as the opcode, and it's
+ a real pc_rel case so it's a relaxable case. */
+ fragP->fr_subtype = ENCODE_RELAX(STATE_PC_RELATIVE, STATE_BYTE);
+ }else{
+ /* This case is still undefined, so asume it's a long word for the
+ linker to fix. */
+ p = fragP->fr_literal + old_fr_fix;
+ *p |= TAHOE_PC_OR_LONG;
+ /* We now know how big it will be, one long word. */
+ fragP->fr_fix += 1 + 4;
+ fix_new (fragP, old_fr_fix + 1, 4, fragP->fr_symbol, 0,
+ fragP->fr_offset, 1, NO_RELOC);
+ frag_wane (fragP);
+ }
+ break;
+
+ case ENCODE_RELAX (STATE_CONDITIONAL_BRANCH, STATE_UNDF):
+ if (S_GET_SEGMENT(fragP->fr_symbol) == segment_type){
+ fragP->fr_subtype = ENCODE_RELAX (STATE_CONDITIONAL_BRANCH, STATE_BYTE);
+ }else{
+ p = fragP->fr_literal + old_fr_fix;
+ *fragP->fr_opcode ^= 0x10; /* Reverse sense of branch. */
+ *p++ = 6;
+ *p++ = TAHOE_JMP;
+ *p++ = TAHOE_PC_REL_LONG;
+ fragP->fr_fix += 1 + 1 + 1 + 4;
+ fix_new (fragP, old_fr_fix + 3, 4, fragP->fr_symbol, 0,
+ fragP->fr_offset, 1, NO_RELOC);
+ frag_wane (fragP);
+ }
+ break;
+
+ case ENCODE_RELAX (STATE_BIG_REV_BRANCH, STATE_UNDF):
+ if (S_GET_SEGMENT(fragP->fr_symbol) == segment_type){
+ fragP->fr_subtype =
+ ENCODE_RELAX (STATE_BIG_REV_BRANCH, STATE_WORD);
+ }else{
+ p = fragP->fr_literal + old_fr_fix;
+ *fragP->fr_opcode ^= 0x10; /* Reverse sense of branch. */
+ *p++ = 0;
+ *p++ = 6;
+ *p++ = TAHOE_JMP;
+ *p++ = TAHOE_PC_REL_LONG;
+ fragP->fr_fix += 2 + 2 + 4;
+ fix_new (fragP, old_fr_fix + 4, 4, fragP->fr_symbol, 0,
+ fragP->fr_offset, 1, NO_RELOC);
+ frag_wane (fragP);
+ }
+ break;
+
+ case ENCODE_RELAX (STATE_BIG_NON_REV_BRANCH, STATE_UNDF):
+ if (S_GET_SEGMENT(fragP->fr_symbol) == segment_type){
+ fragP->fr_subtype = ENCODE_RELAX (STATE_BIG_NON_REV_BRANCH, STATE_WORD);
+ }else{
+ p = fragP->fr_literal + old_fr_fix;
+ *p++ = 2;
+ *p++ = 0;
+ *p++ = TAHOE_BRB;
+ *p++ = 6;
+ *p++ = TAHOE_JMP;
+ *p++ = TAHOE_PC_REL_LONG;
+ fragP->fr_fix += 2 + 2 + 2 + 4;
+ fix_new (fragP, old_fr_fix + 6, 4, fragP->fr_symbol, 0,
+ fragP->fr_offset, 1, NO_RELOC);
+ frag_wane (fragP);
+ }
+ break;
+
+ case ENCODE_RELAX (STATE_ALWAYS_BRANCH, STATE_UNDF):
+ if (S_GET_SEGMENT(fragP->fr_symbol) == segment_type){
+ fragP->fr_subtype = ENCODE_RELAX (STATE_ALWAYS_BRANCH, STATE_BYTE);
+ }else{
+ p = fragP->fr_literal + old_fr_fix;
+ *fragP->fr_opcode = TAHOE_JMP;
+ *p++ = TAHOE_PC_REL_LONG;
+ fragP->fr_fix += 1 + 4;
+ fix_new (fragP, old_fr_fix + 1, 4, fragP->fr_symbol, 0,
+ fragP->fr_offset, 1, NO_RELOC);
+ frag_wane (fragP);
+ }
+ break;
+
+ default:
+ break;
+ }
+ return (fragP->fr_var + fragP->fr_fix - old_fr_fix);
+} /* md_estimate_size_before_relax() */
+
+/*
+ * md_convert_frag();
+ *
+ * Called after relax() is finished.
+ * In: Address of frag.
+ * fr_type == rs_machine_dependent.
+ * fr_subtype is what the address relaxed to.
+ *
+ * Out: Any fixSs and constants are set up.
+ * Caller will turn frag into a ".space 0".
+ */
+void
+md_convert_frag (headers, fragP)
+object_headers *headers;
+ register fragS *fragP;
+{
+ register char *addressP; /* -> _var to change. */
+ register char *opcodeP; /* -> opcode char(s) to change. */
+ register short int length_code; /* 2=long 1=word 0=byte */
+ register short int extension = 0; /* Size of relaxed address.
+ Added to fr_fix: incl. ALL var chars. */
+ register symbolS *symbolP;
+ register long int where;
+ register long int address_of_var;
+ /* Where, in file space, is _var of *fragP? */
+ register long int target_address;
+ /* Where, in file space, does addr point? */
+
+ know (fragP->fr_type == rs_machine_dependent);
+ length_code = RELAX_LENGTH(fragP->fr_subtype);
+ know (length_code >= 0 && length_code < 3);
+ where = fragP->fr_fix;
+ addressP = fragP->fr_literal + where;
+ opcodeP = fragP->fr_opcode;
+ symbolP = fragP->fr_symbol;
+ know(symbolP);
+ target_address = S_GET_VALUE(symbolP) + fragP->fr_offset;
+ address_of_var = fragP->fr_address + where;
+ switch (fragP->fr_subtype){
+ case ENCODE_RELAX(STATE_PC_RELATIVE, STATE_BYTE):
+ /* *addressP holds the registers number, plus 0x10, if it's deferred
+ mode. To set up the right mode, just OR the size of this displacement */
+ /* Byte displacement. */
+ *addressP++ |= TAHOE_PC_OR_BYTE;
+ *addressP = target_address - (address_of_var + 2);
+ extension = 2;
+ break;
+
+ case ENCODE_RELAX(STATE_PC_RELATIVE, STATE_WORD):
+ /* Word displacement. */
+ *addressP++ |= TAHOE_PC_OR_WORD;
+ md_number_to_chars(addressP, target_address - (address_of_var + 3), 2);
+ extension = 3;
+ break;
+
+ case ENCODE_RELAX (STATE_PC_RELATIVE, STATE_LONG):
+ /* Long word displacement. */
+ *addressP++ |= TAHOE_PC_OR_LONG;
+ md_number_to_chars(addressP, target_address - (address_of_var + 5), 4);
+ extension = 5;
+ break;
+
+ case ENCODE_RELAX (STATE_CONDITIONAL_BRANCH, STATE_BYTE):
+ *addressP = target_address - (address_of_var + 1);
+ extension = 1;
+ break;
+
+ case ENCODE_RELAX (STATE_CONDITIONAL_BRANCH, STATE_WORD):
+ *opcodeP ^= 0x10; /* Reverse sense of test. */
+ *addressP++ = 3; /* Jump over word branch */
+ *addressP++ = TAHOE_BRW;
+ md_number_to_chars (addressP, target_address - (address_of_var + 4), 2);
+ extension = 4;
+ break;
+
+ case ENCODE_RELAX (STATE_CONDITIONAL_BRANCH, STATE_LONG):
+ *opcodeP ^= 0x10; /* Reverse sense of test. */
+ *addressP++ = 6;
+ *addressP++ = TAHOE_JMP;
+ *addressP++ = TAHOE_PC_REL_LONG;
+ md_number_to_chars (addressP, target_address, 4);
+ extension = 7;
+ break;
+
+ case ENCODE_RELAX (STATE_ALWAYS_BRANCH, STATE_BYTE):
+ *addressP = target_address - (address_of_var + 1);
+ extension = 1;
+ break;
+
+ case ENCODE_RELAX (STATE_ALWAYS_BRANCH, STATE_WORD):
+ *opcodeP = TAHOE_BRW;
+ md_number_to_chars (addressP, target_address - (address_of_var + 2), 2);
+ extension = 2;
+ break;
+
+ case ENCODE_RELAX (STATE_ALWAYS_BRANCH, STATE_LONG):
+ *opcodeP = TAHOE_JMP;
+ *addressP++ = TAHOE_PC_REL_LONG;
+ md_number_to_chars(addressP, target_address - (address_of_var + 5), 4);
+ extension = 5;
+ break;
+
+ case ENCODE_RELAX (STATE_BIG_REV_BRANCH, STATE_WORD):
+ md_number_to_chars (addressP, target_address - (address_of_var + 2), 2);
+ extension = 2;
+ break;
+
+ case ENCODE_RELAX (STATE_BIG_REV_BRANCH, STATE_LONG):
+ *opcodeP ^= 0x10;
+ *addressP++ = 0;
+ *addressP++ = 6;
+ *addressP++ = TAHOE_JMP;
+ *addressP++ = TAHOE_PC_REL_LONG;
+ md_number_to_chars (addressP, target_address, 4);
+ extension = 8;
+ break;
+
+ case ENCODE_RELAX (STATE_BIG_NON_REV_BRANCH, STATE_WORD):
+ md_number_to_chars (addressP, target_address - (address_of_var + 2), 2);
+ extension = 2;
+ break;
+
+ case ENCODE_RELAX (STATE_BIG_NON_REV_BRANCH, STATE_LONG):
+ *addressP++ = 0;
+ *addressP++ = 2;
+ *addressP++ = TAHOE_BRB;
+ *addressP++ = 6;
+ *addressP++ = TAHOE_JMP;
+ *addressP++ = TAHOE_PC_REL_LONG;
+ md_number_to_chars (addressP, target_address, 4);
+ extension = 10;
+ break;
+
+ default:
+ BAD_CASE (fragP->fr_subtype);
+ break;
+ }
+ fragP->fr_fix += extension;
+} /* md_convert_frag */
+
+
+/* This is the stuff for md_assemble. */
+#define FP_REG 13
+#define SP_REG 14
+#define PC_REG 15
+#define BIGGESTREG PC_REG
+
+/*
+ * Parse the string pointed to by START
+ * If it represents a valid register, point START to the character after
+ * the last valid register char, and return the register number (0-15).
+ * If invalid, leave START alone, return -1.
+ * The format has to be exact. I don't do things like eat leading zeros
+ * or the like.
+ * Note: This doesn't check for the next character in the string making
+ * this invalid. Ex: R123 would return 12, it's the callers job to check
+ * what start is point to apon return.
+ *
+ * Valid registers are R1-R15, %1-%15, FP (13), SP (14), PC (15)
+ * Case doesn't matter.
+ */
+int
+tahoe_reg_parse(start)
+ char **start; /* A pointer to the string to parse. */
+{
+ register char *regpoint = *start;
+ register int regnum = -1;
+
+ switch(*regpoint++){
+ case '%': /* Registers can start with a %,
+ R or r, and then a number. */
+ case 'R':
+ case 'r':
+ if (isdigit(*regpoint)){
+ /* Got the first digit. */
+ regnum = *regpoint++ - '0';
+ if ((regnum == 1) && isdigit(*regpoint)){
+ /* Its a two digit number. */
+ regnum = 10 + (*regpoint++ - '0');
+ if (regnum > BIGGESTREG){ /* Number too big? */
+ regnum = -1;
+ }
+ }
+ }
+ break;
+ case 'F': /* Is it the FP */
+ case 'f':
+ switch(*regpoint++){
+ case 'p':
+ case 'P':
+ regnum = FP_REG;
+ }
+ break;
+ case 's': /* How about the SP */
+ case 'S':
+ switch(*regpoint++){
+ case 'p':
+ case 'P':
+ regnum = SP_REG;
+ }
+ break;
+ case 'p': /* OR the PC even */
+ case 'P':
+ switch(*regpoint++){
+ case 'c':
+ case 'C':
+ regnum = PC_REG;
+ }
+ break;
+ }
+
+ if (regnum != -1){ /* No error, so move string pointer */
+ *start = regpoint;
+ }
+ return regnum; /* Return results */
+} /* tahoe_reg_parse */
+
+/*
+ * This chops up an operand and figures out its modes and stuff.
+ * It's a little touchy about extra characters.
+ * Optex to start with one extra character so it can be overwritten for
+ * the backward part of the parsing.
+ * You can't put a bunch of extra characters in side to
+ * make the command look cute. ie: * foo ( r1 ) [ r0 ]
+ * If you like doing a lot of typing, try COBOL!
+ * Actually, this parser is a little weak all around. It's designed to be
+ * used with compliers, so I emphisise correct decoding of valid code quickly
+ * rather that catching every possable error.
+ * Note: This uses the expression function, so save input_line_pointer before
+ * calling.
+ *
+ * Sperry defines the semantics of address modes (and values)
+ * by a two-letter code, explained here.
+ *
+ * letter 1: access type
+ *
+ * a address calculation - no data access, registers forbidden
+ * b branch displacement
+ * m read - let go of bus - write back "modify"
+ * r read
+ * w write
+ * v bit field address: like 'a' but registers are OK
+ *
+ * letter 2: data type (i.e. width, alignment)
+ *
+ * b byte
+ * w word
+ * l longword
+ * q quadword (Even regs < 14 allowed) (if 12, you get a warning)
+ * - unconditional synthetic jbr operand
+ * ? simple synthetic reversable branch operand
+ * ! complex synthetic reversable branch operand
+ * : complex synthetic non-reversable branch operand
+ *
+ * The '-?!:' letter 2's are not for external consumption. They are used
+ * by GAS for psuedo ops relaxing code.
+ *
+ * After parsing topP has:
+ *
+ * top_ndx: -1, or the index register. eg 7=[R7]
+ * top_reg: -1, or register number. eg 7 = R7 or (R7)
+ * top_mode: The addressing mode byte. This byte, defines which of
+ * the 11 modes opcode is.
+ * top_access: Access type wanted for this opperand 'b'branch ' '
+ * no-instruction 'amrvw'
+ * top_width: Operand width expected, one of "bwlq?-:!"
+ * exp_of_operand: The expression as parsed by expression()
+ * top_dispsize: Number of bytes in the displacement if we can figure it
+ * out and it's relavent.
+ *
+ * Need syntax checks built.
+ */
+
+void
+tip_op (optex,topP)
+ char *optex; /* The users text input, with one leading character */
+ struct top *topP;/* The tahoe instruction with some fields already set:
+ in: access, width
+ out: ndx, reg, mode, error, dispsize */
+
+{
+ int mode = 0; /* This operand's mode. */
+ char segfault = *optex; /* To keep the back parsing from freaking. */
+ char *point = optex+1; /* Parsing from front to back. */
+ char *end; /* Parsing from back to front. */
+ int reg = -1; /* major register, -1 means absent */
+ int imreg = -1; /* Major register in immediate mode */
+ int ndx = -1; /* index register number, -1 means absent */
+ char dec_inc = ' '; /* Is the SP auto-incremented '+' or
+ auto-decremented '-' or neither ' '. */
+ int immediate = 0; /* 1 if '$' immediate mode */
+ int call_width = 0; /* If the caller casts the displacement */
+ int abs_width = 0; /* The width of the absolute displacment */
+ int com_width = 0; /* Displacement width required by branch */
+ int deferred = 0; /* 1 if '*' deferral is used */
+ byte disp_size = 0; /* How big is this operand. 0 == don't know */
+ char *op_bad = ""; /* Bad operand error */
+
+ char *tp, *temp, c; /* Temporary holders */
+
+ char access = topP->top_access; /* Save on a deref. */
+ char width = topP->top_width;
+
+ int really_none = 0; /* Empty expressions evaluate to 0
+ but I need to know if it's there or not */
+ expressionS *expP; /* -> expression values for this operand */
+
+ /* Does this command restrict the displacement size. */
+ if (access == 'b')
+ com_width = (width == 'b' ? 1 :
+ (width == 'w' ? 2 :
+ (width == 'l' ? 4 : 0)));
+
+ *optex = '\0'; /* This is kind of a back stop for all
+ the searches to fail on if needed.*/
+ if (*point == '*') { /* A dereference? */
+ deferred = 1;
+ point++;
+ }
+
+ /* Force words into a certain mode */
+ /* Bitch, Bitch, Bitch! */
+ /*
+ * Using the ^ operator is ambigous. If I have an absolute label
+ * called 'w' set to, say 2, and I have the expression 'w^1', do I get
+ * 1, forced to be in word displacement mode, or do I get the value of
+ * 'w' or'ed with 1 (3 in this case).
+ * The default is 'w' as an offset, so that's what I use.
+ * Stick with `, it does the same, and isn't ambig.
+ */
+
+ if (*point != '\0' && ((point[1] == '^') || (point[1] == '`')))
+ switch(*point){
+ case 'b':
+ case 'B':
+ case 'w':
+ case 'W':
+ case 'l':
+ case 'L':
+ if (com_width)
+ as_warn("Casting a branch displacement is bad form, and is ignored.");
+ else{
+ c = (isupper(*point) ? tolower(*point) : *point);
+ call_width = ((c == 'b') ? 1 :
+ ((c == 'w') ? 2 : 4));
+ }
+ point += 2;
+ break;
+ }
+
+ /* Setting immediate mode */
+ if (*point == '$'){
+ immediate = 1;
+ point++;
+ }
+
+ /*
+ * I've pulled off all the easy stuff off the front, move to the end and
+ * yank.
+ */
+
+ for(end = point;*end != '\0';end++) /* Move to the end. */
+ ;
+
+ if(end != point) /* Null string? */
+ end--;
+
+ if (end > point && *end == ' ' && end[-1] != '\'')
+ end--; /* Hop white space */
+
+ /* Is this an index reg. */
+ if ((*end == ']') && (end[-1] != '\'')){
+ temp = end;
+
+ /* Find opening brace. */
+ for(--end;(*end != '[' && end != point);end--)
+ ;
+
+ /* If I found the opening brace, get the index register number. */
+ if (*end == '['){
+ tp = end + 1; /* tp should point to the start of a reg. */
+ ndx = tahoe_reg_parse(&tp);
+ if (tp != temp){ /* Reg. parse error. */
+ ndx = -1;
+ } else {
+ end--; /* Found it, move past brace. */
+ }
+ if (ndx == -1){
+ op_bad = "Couldn't parse the [index] in this operand.";
+ end = point; /* Force all the rest of the tests to fail. */
+ }
+ }else{
+ op_bad = "Couldn't find the opening '[' for the index of this operand.";
+ end = point; /* Force all the rest of the tests to fail. */
+ }
+ }
+
+ /* Post increment? */
+ if (*end == '+'){
+ dec_inc = '+';
+/* was: *end--; */
+ end--;
+ }
+
+ /* register in parens? */
+ if ((*end == ')') && (end[-1] != '\'')){
+ temp = end;
+
+ /* Find opening paren. */
+ for(--end;(*end != '(' && end != point);end--)
+ ;
+
+ /* If I found the opening paren, get the register number. */
+ if (*end == '('){
+ tp = end + 1;
+ reg = tahoe_reg_parse(&tp);
+ if (tp != temp){
+ /* Not a register, but could be part of the expression. */
+ reg = -1;
+ end = temp; /* Rest the pointer back */
+ } else {
+ end--; /* Found the reg. move before opening paren. */
+ }
+ }else{
+ op_bad = "Couldn't find the opening '(' for the deref of this operand.";
+ end = point; /* Force all the rest of the tests to fail. */
+ }
+ }
+
+ /* Pre decrement? */
+ if (*end == '-'){
+ if (dec_inc != ' '){
+ op_bad = "Operand can't be both pre-inc and post-dec.";
+ end = point;
+ }else{
+ dec_inc = '-';
+/* was: *end--; */
+ end--;
+ }
+ }
+
+ /*
+ * Everything between point and end is the 'expression', unless it's
+ * a register name.
+ */
+
+ c = end[1];
+ end[1] = '\0';
+
+ tp = point;
+ imreg = tahoe_reg_parse(&point); /* Get the immediate register
+ if it is there.*/
+ if (*point != '\0'){
+ /* If there is junk after point, then the it's not immediate reg. */
+ point = tp;
+ imreg = -1;
+ }
+
+ if (imreg != -1 && reg != -1)
+ op_bad = "I parsed 2 registers in this operand.";
+
+ /*
+ * Evaluate whats left of the expression to see if it's valid.
+ * Note again: This assumes that the calling expression has saved
+ * input_line_pointer. (Nag, nag, nag!)
+ */
+
+ if (*op_bad == '\0'){
+ /* statement has no syntax goofs yet: lets sniff the expression */
+ input_line_pointer = point;
+ expP = &(topP->exp_of_operand);
+ switch (expression (expP)){
+ /* If expression == SEG_PASS1, expression() will have set
+ need_pass_2 = 1. */
+ case SEG_ABSENT:
+ /* No expression. For BSD4.2 compatibility, missing expression is
+ absolute 0 */
+ expP->X_seg = SEG_ABSOLUTE;
+ expP->X_add_number = 0;
+ really_none = 1;
+ case SEG_ABSOLUTE:
+ /* for SEG_ABSOLUTE, we shouldnt need to set X_subtract_symbol,
+ X_add_symbol to any particular value. */
+ /* But, we will program defensively. Since this situation occurs
+ rarely so it costs us little to do so. */
+ expP->X_add_symbol = NULL;
+ expP->X_subtract_symbol = NULL;
+ /* How many bytes are needed to express this abs value? */
+ abs_width =
+ ((((expP->X_add_number & 0xFFFFFF80) == 0) ||
+ ((expP->X_add_number & 0xFFFFFF80) == 0xFFFFFF80)) ? 1 :
+ (((expP->X_add_number & 0xFFFF8000) == 0) ||
+ ((expP->X_add_number & 0xFFFF8000) == 0xFFFF8000)) ? 2 : 4);
+ case SEG_TEXT:
+ case SEG_DATA:
+ case SEG_BSS:
+ case SEG_UNKNOWN:
+ break;
+
+ case SEG_DIFFERENCE:
+ /*
+ * Major bug. We can't handle the case of a
+ * SEG_DIFFERENCE expression in a synthetic opcode
+ * variable-length instruction.
+ * We don't have a frag type that is smart enough to
+ * relax a SEG_DIFFERENCE, and so we just force all
+ * SEG_DIFFERENCEs to behave like SEG_PASS1s.
+ * Clearly, if there is a demand we can invent a new or
+ * modified frag type and then coding up a frag for this
+ * case will be easy. SEG_DIFFERENCE was invented for the
+ * .words after a CASE opcode, and was never intended for
+ * instruction operands.
+ */
+ need_pass_2 = 1;
+ case SEG_PASS1:
+ op_bad = "Can't relocate expression error.";
+ break;
+
+ case SEG_BIG:
+ /* This is an error. Tahoe doesn't allow any expressions
+ bigger that a 32 bit long word. Any bigger has to be referenced
+ by address. */
+ op_bad = "Expression is too large for a 32 bits.";
+ break;
+
+ default:
+ as_fatal("Complier Bug: I got segment %d in tip_op.",expP->X_seg);
+ break;
+ }
+ if (*input_line_pointer != '\0'){
+ op_bad = "Junk at end of expression.";
+ }
+ }
+
+ end[1] = c;
+
+ /* I'm done, so restore optex */
+ *optex = segfault;
+
+
+ /*
+ * At this point in the game, we (in theory) have all the components of
+ * the operand at least parsed. Now it's time to check for syntax/semantic
+ * errors, and build the mode.
+ * This is what I have:
+ * deferred = 1 if '*'
+ * call_width = 0,1,2,4
+ * abs_width = 0,1,2,4
+ * com_width = 0,1,2,4
+ * immediate = 1 if '$'
+ * ndx = -1 or reg num
+ * dec_inc = '-' or '+' or ' '
+ * reg = -1 or reg num
+ * imreg = -1 or reg num
+ * topP->exp_of_operand
+ * really_none
+ */
+ /* Is there a displacement size? */
+ disp_size = (call_width ? call_width :
+ (com_width ? com_width :
+ abs_width ? abs_width : 0));
+
+ if (*op_bad == '\0'){
+ if (imreg != -1){
+ /* Rn */
+ mode = TAHOE_DIRECT_REG;
+ if (deferred || immediate || (dec_inc != ' ') ||
+ (reg != -1) || !really_none)
+ op_bad = "Syntax error in direct register mode.";
+ else if (ndx != -1)
+ op_bad = "You can't index a register in direct register mode.";
+ else if (imreg == SP_REG && access == 'r')
+ op_bad =
+ "SP can't be the source operand with direct register addressing.";
+ else if (access == 'a')
+ op_bad = "Can't take the address of a register.";
+ else if (access == 'b')
+ op_bad = "Direct Register can't be used in a branch.";
+ else if (width == 'q' && ((imreg % 2) || (imreg > 13)))
+ op_bad = "For quad access, the register must be even and < 14.";
+ else if (call_width)
+ op_bad = "You can't cast a direct register.";
+
+ if (*op_bad == '\0'){
+ /* No errors, check for warnings */
+ if (width == 'q' && imreg == 12)
+ as_warn("Using reg 14 for quadwords can tromp the FP register.");
+
+ reg = imreg;
+ }
+
+ /* We know: imm = -1 */
+ }else if (dec_inc == '-'){
+ /* -(SP) */
+ mode = TAHOE_AUTO_DEC;
+ if (deferred || immediate || !really_none)
+ op_bad = "Syntax error in auto-dec mode.";
+ else if (ndx != -1)
+ op_bad = "You can't have an index auto dec mode.";
+ else if (access == 'r')
+ op_bad = "Auto dec mode cant be used for reading.";
+ else if (reg != SP_REG)
+ op_bad = "Auto dec only works of the SP register.";
+ else if (access == 'b')
+ op_bad = "Auto dec can't be used in a branch.";
+ else if (width == 'q')
+ op_bad = "Auto dec won't work with quadwords.";
+
+ /* We know: imm = -1, dec_inc != '-' */
+ }else if (dec_inc == '+'){
+ if (immediate || !really_none)
+ op_bad = "Syntax error in one of the auto-inc modes.";
+ else if (deferred){
+ /* *(SP)+ */
+ mode = TAHOE_AUTO_INC_DEFERRED;
+ if (reg != SP_REG)
+ op_bad = "Auto inc deferred only works of the SP register.";
+ else if (ndx != -1)
+ op_bad = "You can't have an index auto inc deferred mode.";
+ else if (access == 'b')
+ op_bad = "Auto inc can't be used in a branch.";
+ }else{
+ /* (SP)+ */
+ mode = TAHOE_AUTO_INC;
+ if (access == 'm' || access == 'w')
+ op_bad = "You can't write to an auto inc register.";
+ else if (reg != SP_REG)
+ op_bad = "Auto inc only works of the SP register.";
+ else if (access == 'b')
+ op_bad = "Auto inc can't be used in a branch.";
+ else if (width == 'q')
+ op_bad = "Auto inc won't work with quadwords.";
+ else if (ndx != -1)
+ op_bad = "You can't have an index in auto inc mode.";
+ }
+
+ /* We know: imm = -1, dec_inc == ' ' */
+ }else if (reg != -1){
+ if ((ndx != -1) && (reg == SP_REG))
+ op_bad = "You can't index the sp register.";
+ if (deferred){
+ /* *<disp>(Rn) */
+ mode = TAHOE_REG_DISP_DEFERRED;
+ if (immediate)
+ op_bad = "Syntax error in register displaced mode.";
+ }else if (really_none){
+ /* (Rn) */
+ mode = TAHOE_REG_DEFERRED;
+ /* if reg = SP then cant be indexed */
+ }else{
+ /* <disp>(Rn) */
+ mode = TAHOE_REG_DISP;
+ }
+
+ /* We know: imm = -1, dec_inc == ' ', Reg = -1 */
+ }else{
+ if (really_none)
+ op_bad = "An offest is needed for this operand.";
+ if (deferred && immediate){
+ /* *$<ADDR> */
+ mode = TAHOE_ABSOLUTE_ADDR;
+ disp_size = 4;
+ }else if (immediate){
+ /* $<disp> */
+ mode = TAHOE_IMMEDIATE;
+ if (ndx != -1)
+ op_bad = "You can't index a register in immediate mode.";
+ if (access == 'a')
+ op_bad = "Immediate access can't be used as an address.";
+ /* ponder the wisdom of a cast because it doesn't do any good. */
+ }else if (deferred){
+ /* *<disp> */
+ mode = TAHOE_DISP_REL_DEFERRED;
+ }else{
+ /* <disp> */
+ mode = TAHOE_DISPLACED_RELATIVE;
+ }
+ }
+ }
+
+ /*
+ * At this point, all the errors we can do have be checked for.
+ * We can build the 'top'. */
+
+ topP->top_ndx = ndx;
+ topP->top_reg = reg;
+ topP->top_mode = mode;
+ topP->top_error = op_bad;
+ topP->top_dispsize = disp_size;
+} /* tip_op */
+
+/*
+ * t i p ( )
+ *
+ * This converts a string into a tahoe instruction.
+ * The string must be a bare single instruction in tahoe (with BSD4 frobs)
+ * format.
+ * It provides at most one fatal error message (which stops the scan)
+ * some warning messages as it finds them.
+ * The tahoe instruction is returned in exploded form.
+ *
+ * The exploded instruction is returned to a struct tit of your choice.
+ * #include "tahoe-inst.h" to know what a struct tit is.
+ *
+ */
+
+static void
+tip (titP, instring)
+ struct tit *titP; /* We build an exploded instruction here. */
+ char *instring; /* Text of a vax instruction: we modify. */
+{
+ register struct tot_wot *twP = NULL; /* How to bit-encode this opcode. */
+ register char *p; /* 1/skip whitespace.2/scan vot_how */
+ register char *q; /* */
+ register unsigned char count; /* counts number of operands seen */
+ register struct top *operandp;/* scan operands in struct tit */
+ register char *alloperr = ""; /* error over all operands */
+ register char c; /* Remember char, (we clobber it
+ with '\0' temporarily). */
+ char *save_input_line_pointer;
+
+ if (*instring == ' ')
+ ++instring; /* Skip leading whitespace. */
+ for (p = instring; *p && *p != ' '; p++)
+ ; /* MUST end in end-of-string or
+ exactly 1 space. */
+ /* Scanned up to end of operation-code. */
+ /* Operation-code is ended with whitespace. */
+ if (p == instring){
+ titP->tit_error = "No operator";
+ count = 0;
+ titP->tit_opcode = 0;
+ } else {
+ c = *p;
+ *p = '\0';
+ /*
+ * Here with instring pointing to what better be an op-name, and p
+ * pointing to character just past that.
+ * We trust instring points to an op-name, with no whitespace.
+ */
+ twP = (struct tot_wot *) hash_find(op_hash, instring);
+ *p = c; /* Restore char after op-code. */
+ if (twP == 0){
+ titP->tit_error = "Unknown operator";
+ count = 0;
+ titP->tit_opcode = 0;
+ }else{
+ /*
+ * We found a match! So lets pick up as many operands as the
+ * instruction wants, and even gripe if there are too many.
+ * We expect comma to seperate each operand.
+ * We let instring track the text, while p tracks a part of the
+ * struct tot.
+ */
+
+ count = 0; /* no operands seen yet */
+ instring = p+(*p!='\0'); /* point past the operation code */
+ /* tip_op() screws with the input_line_pointer, so save it before
+ I jump in */
+ save_input_line_pointer = input_line_pointer;
+ for (p = twP->args, operandp = titP->tit_operand;
+ !*alloperr && *p;
+ operandp++, p += 2){
+ /*
+ * Here to parse one operand. Leave instring pointing just
+ * past any one ',' that marks the end of this operand.
+ */
+ if (!p[1])
+ as_fatal("Compiler bug: ODD number of bytes in arg structure %s.",
+ twP->args);
+ else if (*instring){
+ for (q = instring; (*q != ',' && *q != '\0'); q++){
+ if (*q == '\'' && q[1] != '\0') /* Jump quoted characters */
+ q++;
+ }
+ c = *q;
+ /*
+ * Q points to ',' or '\0' that ends argument. C is that
+ * character.
+ */
+ *q = '\0';
+ operandp->top_access = p[0];
+ operandp->top_width = p[1];
+ tip_op(instring-1, operandp);
+ *q = c; /* Restore input text. */
+ if (*(operandp->top_error)){
+ alloperr = operandp->top_error;
+ }
+ instring = q + (c ? 1 : 0); /* next operand (if any) */
+ count++; /* won another argument, may have an operr */
+ }else
+ alloperr = "Not enough operands";
+ }
+ /* Restore the pointer. */
+ input_line_pointer = save_input_line_pointer;
+
+ if (!*alloperr){
+ if (*instring == ' ')
+ instring++; /* Skip whitespace. */
+ if (*instring)
+ alloperr = "Too many operands";
+ }
+ titP->tit_error = alloperr;
+ }
+ }
+
+ titP->tit_opcode = twP->code; /* The op-code. */
+ titP->tit_operands = count;
+} /* tip */
+
+/* md_assemble() emit frags for 1 instruction */
+void
+md_assemble (instruction_string)
+ char *instruction_string; /* A string: assemble 1 instruction. */
+{
+ char *p;
+ register struct top *operandP; /* An operand. Scans all operands. */
+/* char c_save; fixme: remove this line */ /* What used to live after an expression. */
+/* struct frag *fragP; fixme: remove this line */ /* Fragment of code we just made. */
+/* register struct top *end_operandP; fixme: remove this line */ /* -> slot just after last operand
+ Limit of the for (each operand). */
+ register expressionS *expP; /* -> expression values for this operand */
+
+ /* These refer to an instruction operand expression. */
+ segT to_seg; /* Target segment of the address. */
+
+ register valueT this_add_number;
+ register struct symbol *this_add_symbol; /* +ve (minuend) symbol. */
+
+/* tahoe_opcodeT opcode_as_number; fixme: remove this line */ /* The opcode as a number. */
+ char *opcodeP; /* Where it is in a frag. */
+/* char *opmodeP; fixme: remove this line */ /* Where opcode type is, in a frag. */
+
+ int dispsize; /* From top_dispsize: tahoe_operand_width
+ (in bytes) */
+ int is_undefined; /* 1 if operand expression's
+ segment not known yet. */
+ int pc_rel; /* Is this operand pc relative? */
+
+ /* Decode the operand. */
+ tip(&t, instruction_string);
+
+ /*
+ * Check to see if this operand decode properly.
+ * Notice that we haven't made any frags yet.
+ * If it goofed, then this instruction will wedge in any pass,
+ * and we can safely flush it, without causing interpass symbol phase
+ * errors. That is, without changing label values in different passes.
+ */
+ if (*t.tit_error){
+ as_warn("Ignoring statement due to \"%s\"", t.tit_error);
+ }else{
+ /* We saw no errors in any operands - try to make frag(s) */
+ /* Emit op-code. */
+ /* Remember where it is, in case we want to modify the op-code later. */
+ opcodeP = frag_more(1);
+ *opcodeP = t.tit_opcode;
+ /* Now do each operand. */
+ for (operandP = t.tit_operand;
+ operandP < t.tit_operand + t.tit_operands;
+ operandP++){ /* for each operand */
+ expP = &(operandP->exp_of_operand);
+ if (operandP->top_ndx >= 0){
+ /* Indexed addressing byte
+ Legality of indexed mode already checked: it is OK */
+ FRAG_APPEND_1_CHAR(0x40 + operandP->top_ndx);
+ } /* if(top_ndx>=0) */
+
+ /* Here to make main operand frag(s). */
+ this_add_number = expP->X_add_number;
+ this_add_symbol = expP->X_add_symbol;
+ to_seg = expP->X_seg;
+ know (to_seg == SEG_UNKNOWN||\
+ to_seg == SEG_ABSOLUTE||\
+ to_seg == SEG_DATA||\
+ to_seg == SEG_TEXT||\
+ to_seg == SEG_BSS);
+ is_undefined = (to_seg == SEG_UNKNOWN);
+ /* Do we know how big this opperand is? */
+ dispsize = operandP->top_dispsize;
+ pc_rel = 0;
+ /* Deal with the branch possabilities. (Note, this doesn't include
+ jumps.)*/
+ if (operandP->top_access == 'b'){
+ /* Branches must be expressions. A psuedo branch can also jump to
+ an absolute address. */
+ if (to_seg == now_seg || is_undefined){
+ /* If is_undefined, then it might BECOME now_seg by relax time. */
+ if (dispsize){
+ /* I know how big the branch is supposed to be (it's a normal
+ branch), so I set up the frag, and let GAS do the rest. */
+ p = frag_more (dispsize);
+ fix_new (frag_now, p - frag_now->fr_literal, dispsize,
+ this_add_symbol, 0, this_add_number, 1, NO_RELOC);
+ } else {
+ /* (to_seg==now_seg || to_seg == SEG_UNKNOWN) && dispsize==0 */
+ /* If we don't know how big it is, then its a synthetic branch,
+ so we set up a simple relax state. */
+ switch (operandP->top_width){
+ case TAHOE_WIDTH_CONDITIONAL_JUMP:
+ /* Simple (conditional) jump. I may have to reverse the
+ condition of opcodeP, and then jump to my destination.
+ I set 1 byte aside for the branch off set, and could need 6
+ more bytes for the pc_rel jump */
+ frag_var (rs_machine_dependent, 7, 1,
+ ENCODE_RELAX (STATE_CONDITIONAL_BRANCH,
+ is_undefined ? STATE_UNDF : STATE_BYTE),
+ this_add_symbol, this_add_number, opcodeP);
+ break;
+ case TAHOE_WIDTH_ALWAYS_JUMP:
+ /* Simple (unconditional) jump. I may have to convert this to
+ a word branch, or an absolute jump. */
+ frag_var (rs_machine_dependent, 5, 1,
+ ENCODE_RELAX (STATE_ALWAYS_BRANCH,
+ is_undefined ? STATE_UNDF : STATE_BYTE),
+ this_add_symbol, this_add_number, opcodeP);
+ break;
+ /* The smallest size for the next 2 cases is word. */
+ case TAHOE_WIDTH_BIG_REV_JUMP:
+ frag_var (rs_machine_dependent, 8, 2,
+ ENCODE_RELAX (STATE_BIG_REV_BRANCH,
+ is_undefined ? STATE_UNDF : STATE_WORD),
+ this_add_symbol, this_add_number,
+ opcodeP);
+ break;
+ case TAHOE_WIDTH_BIG_NON_REV_JUMP:
+ frag_var (rs_machine_dependent, 10, 2,
+ ENCODE_RELAX (STATE_BIG_NON_REV_BRANCH,
+ is_undefined ? STATE_UNDF : STATE_WORD),
+ this_add_symbol, this_add_number,
+ opcodeP);
+ break;
+ default:
+ as_fatal("Compliler bug: Got a case (%d) I wasn't expecting.",
+ operandP->top_width);
+ }
+ }
+ }else{
+ /* to_seg != now_seg && to_seg != seg_unknown (still in branch)
+ In other words, I'm jumping out of my segment so extend the
+ branches to jumps, and let GAS fix them. */
+
+ /* These are "branches" what will always be branches around a jump
+ to the correct addresss in real life.
+ If to_seg is SEG_ABSOLUTE, just encode the branch in,
+ else let GAS fix the address. */
+
+ switch (operandP->top_width){
+ /* The theory:
+ For SEG_ABSOLUTE, then mode is ABSOLUTE_ADDR, jump
+ to that addresss (not pc_rel).
+ For other segs, address is a long word PC rel jump. */
+ case TAHOE_WIDTH_CONDITIONAL_JUMP:
+ /* b<cond> */
+ /* To reverse the condition in a TAHOE branch,
+ complement bit 4 */
+ *opcodeP ^= 0x10;
+ p = frag_more (7);
+ *p++ = 6;
+ *p++ = TAHOE_JMP;
+ *p++ = (operandP->top_mode ==
+ TAHOE_ABSOLUTE_ADDR ? TAHOE_ABSOLUTE_ADDR :
+ TAHOE_PC_REL_LONG);
+ fix_new (frag_now, p - frag_now->fr_literal, 4,
+ this_add_symbol, 0, this_add_number,
+ (to_seg != SEG_ABSOLUTE), NO_RELOC);
+ /*
+ * Now (eg) BLEQ 1f
+ * JMP foo
+ * 1:
+ */
+ break;
+ case TAHOE_WIDTH_ALWAYS_JUMP:
+ /* br, just turn it into a jump */
+ *opcodeP = TAHOE_JMP;
+ p = frag_more (5);
+ *p++ = (operandP->top_mode ==
+ TAHOE_ABSOLUTE_ADDR ? TAHOE_ABSOLUTE_ADDR :
+ TAHOE_PC_REL_LONG);
+ fix_new (frag_now, p - frag_now->fr_literal, 4,
+ this_add_symbol, 0, this_add_number,
+ (to_seg != SEG_ABSOLUTE), NO_RELOC);
+ /* Now (eg) JMP foo */
+ break;
+ case TAHOE_WIDTH_BIG_REV_JUMP:
+ p = frag_more (8);
+ *opcodeP ^= 0x10;
+ *p++ = 0;
+ *p++ = 6;
+ *p++ = TAHOE_JMP;
+ *p++ = (operandP->top_mode ==
+ TAHOE_ABSOLUTE_ADDR ? TAHOE_ABSOLUTE_ADDR :
+ TAHOE_PC_REL_LONG);
+ fix_new (frag_now, p - frag_now->fr_literal, 4,
+ this_add_symbol, 0, this_add_number,
+ (to_seg != SEG_ABSOLUTE), NO_RELOC);
+ /*
+ * Now (eg) ACBx 1f
+ * JMP foo
+ * 1:
+ */
+ break;
+ case TAHOE_WIDTH_BIG_NON_REV_JUMP:
+ p = frag_more (10);
+ *p++ = 0;
+ *p++ = 2;
+ *p++ = TAHOE_BRB;
+ *p++ = 6;
+ *p++ = TAHOE_JMP;
+ *p++ = (operandP->top_mode ==
+ TAHOE_ABSOLUTE_ADDR ? TAHOE_ABSOLUTE_ADDR :
+ TAHOE_PC_REL_LONG);
+ fix_new (frag_now, p - frag_now->fr_literal, 4,
+ this_add_symbol, 0, this_add_number,
+ (to_seg != SEG_ABSOLUTE), NO_RELOC);
+ /*
+ * Now (eg) xOBxxx 1f
+ * BRB 2f
+ * 1: JMP @#foo
+ * 2:
+ */
+ break;
+ case 'b':
+ case 'w':
+ as_warn("Real branch displacements must be expressions.");
+ break;
+ default:
+ as_fatal("Complier error: I got an unknown synthetic branch :%c",
+ operandP->top_width);
+ break;
+ }
+ }
+ }else{
+ /* It ain't a branch operand. */
+ switch (operandP->top_mode){
+ /* Auto-foo access, only works for one reg (SP)
+ so the only thing needed is the mode. */
+ case TAHOE_AUTO_DEC:
+ case TAHOE_AUTO_INC:
+ case TAHOE_AUTO_INC_DEFERRED:
+ FRAG_APPEND_1_CHAR(operandP->top_mode);
+ break;
+
+ /* Numbered Register only access. Only thing needed is the
+ mode + Register number */
+ case TAHOE_DIRECT_REG:
+ case TAHOE_REG_DEFERRED:
+ FRAG_APPEND_1_CHAR(operandP->top_mode + operandP->top_reg);
+ break;
+
+ /* An absolute address. It's size is always 5 bytes.
+ (mode_type + 4 byte address). */
+ case TAHOE_ABSOLUTE_ADDR:
+ know((this_add_symbol == NULL));
+ p = frag_more(5);
+ *p = TAHOE_ABSOLUTE_ADDR;
+ md_number_to_chars(p+1,this_add_number,4);
+ break;
+
+ /* Immediate data. If the size isn't known, then it's an address
+ + and offset, which is 4 bytes big. */
+ case TAHOE_IMMEDIATE:
+ if (this_add_symbol != NULL){
+ p = frag_more (5);
+ *p++ = TAHOE_IMMEDIATE_LONGWORD;
+ fix_new (frag_now, p - frag_now->fr_literal,
+ 4, this_add_symbol,0,this_add_number,
+ 0, NO_RELOC);
+ }else{
+ /* It's a integer, and I know it's size. */
+ if ((unsigned) this_add_number < 0x40){
+ /* Will it fit in a literal? */
+ FRAG_APPEND_1_CHAR((byte) this_add_number);
+ }else{
+ p = frag_more(dispsize+1);
+ switch(dispsize){
+ case 1:
+ *p++ = TAHOE_IMMEDIATE_BYTE;
+ *p = (byte) this_add_number;
+ break;
+ case 2:
+ *p++ = TAHOE_IMMEDIATE_WORD;
+ md_number_to_chars(p,this_add_number,2);
+ break;
+ case 4:
+ *p++ = TAHOE_IMMEDIATE_LONGWORD;
+ md_number_to_chars(p,this_add_number,4);
+ break;
+ }
+ }
+ }
+ break;
+
+ /* Distance from the PC. If the size isn't known, we have to relax
+ into it. The difference between this and disp(sp) is that
+ this offset is pc_rel, and disp(sp) isn't.
+ Note the drop through code. */
+
+ case TAHOE_DISPLACED_RELATIVE:
+ case TAHOE_DISP_REL_DEFERRED:
+ operandP->top_reg = PC_REG;
+ pc_rel = 1;
+
+ /* Register, plus a displacement mode. Save the register number,
+ and weather its deffered or not, and relax the size if it isn't
+ known. */
+ case TAHOE_REG_DISP:
+ case TAHOE_REG_DISP_DEFERRED:
+ if (operandP->top_mode == TAHOE_DISP_REL_DEFERRED ||
+ operandP->top_mode == TAHOE_REG_DISP_DEFERRED)
+ operandP->top_reg += 0x10; /* deffered mode is always 0x10 higher
+ than it's non-deffered sibling. */
+
+ /* Is this a value out of this segment?
+ The first part of this conditional is a cludge to make gas
+ produce the same output as 'as' when there is a lable, in
+ the current segment, displaceing a register. It's strange,
+ and no one in their right mind would do it, but it's easy
+ to cludge. */
+ if ((dispsize == 0 && !pc_rel) ||
+ (to_seg != now_seg && !is_undefined && to_seg != SEG_ABSOLUTE))
+ dispsize = 4;
+
+ if (dispsize == 0){
+ /*
+ * We have a SEG_UNKNOWN symbol, or the size isn't cast.
+ * It might turn out to be in the same segment as
+ * the instruction, permitting relaxation.
+ */
+ p = frag_var(rs_machine_dependent, 5, 2,
+ ENCODE_RELAX(STATE_PC_RELATIVE,
+ is_undefined ? STATE_UNDF:STATE_BYTE),
+ this_add_symbol, this_add_number,0);
+ *p = operandP->top_reg;
+ }else{
+ /* Either this is an abs, or a cast. */
+ p = frag_more (dispsize + 1);
+ switch(dispsize){
+ case 1:
+ *p = TAHOE_PC_OR_BYTE + operandP->top_reg;
+ break;
+ case 2:
+ *p = TAHOE_PC_OR_WORD + operandP->top_reg;
+ break;
+ case 4:
+ *p = TAHOE_PC_OR_LONG + operandP->top_reg;
+ break;
+ };
+ fix_new (frag_now, p + 1 - frag_now->fr_literal,
+ dispsize, this_add_symbol,0,this_add_number,
+ pc_rel, NO_RELOC);
+ }
+ break;
+ default:
+ as_fatal("Barf, bad mode %x\n",operandP->top_mode);
+ }
+ }
+ } /* for(operandP) */
+ } /* if(!need_pass_2 && !goofed) */
+} /* tahoe_assemble() */
+
+
+/* We have no need to default values of symbols. */
+
+/* ARGSUSED */
+symbolS *md_undefined_symbol(name)
+char *name;
+{
+ return 0;
+} /* md_undefined_symbol() */
+
+/* Parse an operand that is machine-specific.
+ We just return without modifying the expression if we have nothing
+ to do. */
+
+/* ARGSUSED */
+void md_operand(expressionP)
+expressionS *expressionP;
+{
+} /* md_operand() */
+
+/* Round up a section size to the appropriate boundary. */
+long md_section_align(segment, size)
+segT segment;
+long size;
+{
+ return((size + 7) & ~7); /* Round all sects to multiple of 8 */
+} /* md_section_align() */
+
+/* Exactly what point is a PC-relative offset relative TO?
+ On the sparc, they're relative to the address of the offset, plus
+ its size. This gets us to the following instruction.
+ (??? Is this right? FIXME-SOON) */
+long md_pcrel_from(fixP)
+fixS *fixP;
+{
+ return(fixP->fx_size + fixP->fx_where + fixP->fx_frag->fr_address);
+} /* md_pcrel_from() */
+
+/* end of tc-tahoe.c */
diff --git a/gnu/usr.bin/as/config/tc-tahoe.h b/gnu/usr.bin/as/config/tc-tahoe.h
new file mode 100644
index 0000000..4593a76
--- /dev/null
+++ b/gnu/usr.bin/as/config/tc-tahoe.h
@@ -0,0 +1,36 @@
+/* This file is tc-tahoe.h
+
+ Copyright (C) 1987-1992 Free Software Foundation, Inc.
+
+ This file is part of GAS, the GNU Assembler.
+
+ GAS is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GAS is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GAS; see the file COPYING. If not, write to
+ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#define TC_TAHOE 1
+
+#define NO_LISTING
+
+#define tc_headers_hook(a) {;} /* don't need it. */
+#define tc_crawl_symbol_chain(a) {;} /* don't need it. */
+#define tc_aout_pre_write_hook(a) {;}
+
+/*
+ * Local Variables:
+ * comment-column: 0
+ * fill-column: 131
+ * End:
+ */
+
+/* end of tc-tahoe.h */
diff --git a/gnu/usr.bin/as/config/tc-vax.c b/gnu/usr.bin/as/config/tc-vax.c
new file mode 100644
index 0000000..2b1970a
--- /dev/null
+++ b/gnu/usr.bin/as/config/tc-vax.c
@@ -0,0 +1,3073 @@
+/* tc-vax.c - vax-specific -
+ Copyright (C) 1987, 1991, 1992 Free Software Foundation, Inc.
+
+ This file is part of GAS, the GNU Assembler.
+
+ GAS is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GAS is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GAS; see the file COPYING. If not, write to
+ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* JF I moved almost all the vax specific stuff into this one file 'cuz RMS
+ seems to think its a good idea. I hope I managed to get all the VAX-isms */
+
+
+#include "as.h"
+
+#include "read.h"
+#include "vax-inst.h"
+#include "obstack.h" /* For FRAG_APPEND_1_CHAR macro in "frags.h" */
+
+/* These chars start a comment anywhere in a source file (except inside
+ another comment */
+const char comment_chars[] = "#";
+
+/* These chars only start a comment at the beginning of a line. */
+/* Note that for the VAX the are the same as comment_chars above. */
+const char line_comment_chars[] = "#";
+
+/* Chars that can be used to separate mant from exp in floating point nums */
+const char EXP_CHARS[] = "eE";
+
+/* Chars that mean this number is a floating point constant */
+/* as in 0f123.456 */
+/* or 0H1.234E-12 (see exp chars above) */
+const char FLT_CHARS[] = "dDfFgGhH";
+
+/* Also be aware that MAXIMUM_NUMBER_OF_CHARS_FOR_FLOAT may have to be
+ changed in read.c. Ideally it shouldn't have to know about it at all,
+ but nothing is ideal around here.
+ */
+
+static expressionS /* Hold details of an operand expression */
+ exp_of_operand[VIT_MAX_OPERANDS];
+
+static struct vit
+ v; /* A vax instruction after decoding. */
+
+LITTLENUM_TYPE big_operand_bits[VIT_MAX_OPERANDS][SIZE_OF_LARGE_NUMBER];
+/* Hold details of big operands. */
+FLONUM_TYPE float_operand[VIT_MAX_OPERANDS];
+/* Above is made to point into */
+/* big_operand_bits by md_begin(). */
+
+/*
+ * For VAX, relative addresses of "just the right length" are easy.
+ * The branch displacement is always the last operand, even in
+ * synthetic instructions.
+ * For VAX, we encode the relax_substateTs (in e.g. fr_substate) as:
+ *
+ * 4 3 2 1 0 bit number
+ * ---/ /--+-------+-------+-------+-------+-------+
+ * | what state ? | how long ? |
+ * ---/ /--+-------+-------+-------+-------+-------+
+ *
+ * The "how long" bits are 00=byte, 01=word, 10=long.
+ * This is a Un*x convention.
+ * Not all lengths are legit for a given value of (what state).
+ * The "how long" refers merely to the displacement length.
+ * The address usually has some constant bytes in it as well.
+ *
+
+ groups for VAX address relaxing.
+
+ 1. "foo" pc-relative.
+ length of byte, word, long
+
+ 2a. J<cond> where <cond> is a simple flag test.
+ length of byte, word, long.
+ VAX opcodes are: (Hex)
+ bneq/bnequ 12
+ beql/beqlu 13
+ bgtr 14
+ bleq 15
+ bgeq 18
+ blss 19
+ bgtru 1a
+ blequ 1b
+ bvc 1c
+ bvs 1d
+ bgequ/bcc 1e
+ blssu/bcs 1f
+ Always, you complement 0th bit to reverse condition.
+ Always, 1-byte opcode, then 1-byte displacement.
+
+ 2b. J<cond> where cond tests a memory bit.
+ length of byte, word, long.
+ Vax opcodes are: (Hex)
+ bbs e0
+ bbc e1
+ bbss e2
+ bbcs e3
+ bbsc e4
+ bbcc e5
+ bbssi e6
+ bbcci e7
+ Always, you complement 0th bit to reverse condition.
+ Always, 1-byte opcde, longword-address, byte-address, 1-byte-displacement
+
+ 2c. J<cond> where cond tests low-order memory bit
+ length of byte,word,long.
+ Vax opcodes are: (Hex)
+ blbs e8
+ blbc e9
+ Always, you complement 0th bit to reverse condition.
+ Always, 1-byte opcode, longword-address, 1-byte displacement.
+
+ 3. Jbs/Jbr.
+ length of byte,word,long.
+ Vax opcodes are: (Hex)
+ bsbb 10
+ brb 11
+ These are like (2) but there is no condition to reverse.
+ Always, 1 byte opcode, then displacement/absolute.
+
+ 4a. JacbX
+ length of word, long.
+ Vax opcodes are: (Hex)
+ acbw 3d
+ acbf 4f
+ acbd 6f
+ abcb 9d
+ acbl f1
+ acbg 4ffd
+ acbh 6ffd
+ Always, we cannot reverse the sense of the branch; we have a word
+ displacement.
+ The double-byte op-codes don't hurt: we never want to modify the
+ opcode, so we don't care how many bytes are between the opcode and
+ the operand.
+
+ 4b. JXobXXX
+ length of long, long, byte.
+ Vax opcodes are: (Hex)
+ aoblss f2
+ aobleq f3
+ sobgeq f4
+ sobgtr f5
+ Always, we cannot reverse the sense of the branch; we have a byte
+ displacement.
+
+ The only time we need to modify the opcode is for class 2 instructions.
+ After relax() we may complement the lowest order bit of such instruction
+ to reverse sense of branch.
+
+ For class 2 instructions, we store context of "where is the opcode literal".
+ We can change an opcode's lowest order bit without breaking anything else.
+
+ We sometimes store context in the operand literal. This way we can figure out
+ after relax() what the original addressing mode was.
+ */
+
+/* These displacements are relative to */
+/* the start address of the displacement. */
+/* The first letter is Byte, Word. */
+/* 2nd letter is Forward, Backward. */
+#define BF (1+ 127)
+#define BB (1+-128)
+#define WF (2+ 32767)
+#define WB (2+-32768)
+/* Dont need LF, LB because they always */
+/* reach. [They are coded as 0.] */
+
+
+#define C(a,b) ENCODE_RELAX(a,b)
+/* This macro has no side-effects. */
+#define ENCODE_RELAX(what,length) (((what) << 2) + (length))
+
+const relax_typeS
+ md_relax_table[] =
+{
+ { 1, 1, 0, 0 }, /* error sentinel 0,0 */
+ { 1, 1, 0, 0 }, /* unused 0,1 */
+ { 1, 1, 0, 0 }, /* unused 0,2 */
+ { 1, 1, 0, 0 }, /* unused 0,3 */
+ { BF + 1, BB + 1, 2, C(1, 1) }, /* B^"foo" 1,0 */
+ { WF + 1, WB + 1, 3, C (1, 2) }, /* W^"foo" 1,1 */
+ { 0, 0, 5, 0 }, /* L^"foo" 1,2 */
+ { 1, 1, 0, 0 }, /* unused 1,3 */
+ { BF, BB, 1, C(2, 1) }, /* b<cond> B^"foo" 2,0 */
+ { WF + 2, WB + 2, 4, C (2, 2) }, /* br.+? brw X 2,1 */
+ { 0, 0, 7, 0 }, /* br.+? jmp X 2,2 */
+ { 1, 1, 0, 0 }, /* unused 2,3 */
+ { BF, BB, 1, C (3, 1) }, /* brb B^foo 3,0 */
+ { WF, WB, 2, C (3, 2) }, /* brw W^foo 3,1 */
+ { 0, 0, 5, 0 }, /* Jmp L^foo 3,2 */
+ { 1, 1, 0, 0 }, /* unused 3,3 */
+ { 1, 1, 0, 0 }, /* unused 4,0 */
+ { WF, WB, 2, C (4, 2) }, /* acb_ ^Wfoo 4,1 */
+ { 0, 0, 10, 0 }, /* acb_,br,jmp L^foo4,2 */
+ { 1, 1, 0, 0 }, /* unused 4,3 */
+ { BF, BB, 1, C (5, 1) }, /* Xob___,,foo 5,0 */
+ { WF + 4, WB + 4, 6, C (5, 2) }, /* Xob.+2,brb.+3,brw5,1 */
+ { 0, 0, 9, 0 }, /* Xob.+2,brb.+6,jmp5,2 */
+};
+
+#undef C
+#undef BF
+#undef BB
+#undef WF
+#undef WB
+
+void float_cons ();
+
+const pseudo_typeS md_pseudo_table[] = {
+ {"dfloat", float_cons, 'd'},
+ {"ffloat", float_cons, 'f'},
+ {"gfloat", float_cons, 'g'},
+ {"hfloat", float_cons, 'h'},
+ {0},
+};
+
+#define STATE_PC_RELATIVE (1)
+#define STATE_CONDITIONAL_BRANCH (2)
+#define STATE_ALWAYS_BRANCH (3) /* includes BSB... */
+#define STATE_COMPLEX_BRANCH (4)
+#define STATE_COMPLEX_HOP (5)
+
+#define STATE_BYTE (0)
+#define STATE_WORD (1)
+#define STATE_LONG (2)
+#define STATE_UNDF (3) /* Symbol undefined in pass1 */
+
+
+#define min(a, b) ((a) < (b) ? (a) : (b))
+
+#if __STDC__ == 1
+
+int flonum_gen2vax(char format_letter, FLONUM_TYPE *f, LITTLENUM_TYPE *words);
+static void vip_end(void);
+static void vip_op_defaults(char *immediate, char *indirect, char *displen);
+
+#else /* not __STDC__ */
+
+int flonum_gen2vax();
+static void vip_end();
+static void vip_op_defaults();
+
+#endif /* not __STDC__ */
+
+void
+ md_begin ()
+{
+ char *vip_begin ();
+ char *errtxt;
+ FLONUM_TYPE *fP;
+ int i;
+
+ if (*(errtxt = vip_begin (1, "$", "*", "`"))) {
+ as_fatal("VIP_BEGIN error:%s", errtxt);
+ }
+
+ for (i = 0, fP = float_operand;
+ fP < float_operand + VIT_MAX_OPERANDS;
+ i++, fP++) {
+ fP->low = &big_operand_bits[i][0];
+ fP->high = &big_operand_bits[i][SIZE_OF_LARGE_NUMBER - 1];
+ }
+}
+
+void
+ md_end ()
+{
+ vip_end ();
+}
+
+void /* Knows about order of bytes in address. */
+ md_number_to_chars(con, value, nbytes)
+char con[]; /* Return 'nbytes' of chars here. */
+long value; /* The value of the bits. */
+int nbytes; /* Number of bytes in the output. */
+{
+ int n;
+ long v;
+
+ n = nbytes;
+ v = value;
+ while (nbytes--) {
+ *con++ = value; /* Lint wants & MASK_CHAR. */
+ value >>= BITS_PER_CHAR;
+ }
+ /* XXX line number probably botched for this warning message. */
+ if (value != 0 && value != -1)
+ as_bad("Displacement (%ld) long for instruction field length (%d).", v, n);
+}
+
+/* Fix up some data or instructions after we find out the value of a symbol
+ that they reference. */
+
+void /* Knows about order of bytes in address. */
+ md_apply_fix(fixP, value)
+fixS *fixP; /* Fixup struct pointer */
+long value; /* The value of the bits. */
+{
+ char *buf = fixP->fx_where + fixP->fx_frag->fr_literal;
+ int nbytes; /* Number of bytes in the output. */
+
+ nbytes = fixP->fx_size;
+ while (nbytes--) {
+ *buf++ = value; /* Lint wants & MASK_CHAR. */
+ value >>= BITS_PER_CHAR;
+ }
+}
+
+long /* Knows about the byte order in a word. */
+ md_chars_to_number (con, nbytes)
+unsigned char con[]; /* Low order byte 1st. */
+int nbytes; /* Number of bytes in the input. */
+{
+ long retval;
+ for (retval = 0, con += nbytes - 1; nbytes--; con--) {
+ retval <<= BITS_PER_CHAR;
+ retval |= *con;
+ }
+ return retval;
+}
+
+/* vax:md_assemble() emit frags for 1 instruction */
+
+void
+ md_assemble (instruction_string)
+char *instruction_string; /* A string: assemble 1 instruction. */
+{
+ /* We saw no errors in any operands - try to make frag(s) */
+ int is_undefined; /* 1 if operand expression's */
+ /* segment not known yet. */
+ int length_code;
+
+ char *p;
+ register struct vop *operandP;/* An operand. Scans all operands. */
+ char *save_input_line_pointer;
+ char c_save; /* What used to live after an expression. */
+ /* fixme: unused? */
+/* struct frag *fragP; */ /* Fragment of code we just made. */
+ register int goofed; /* 1: instruction_string bad for all passes. */
+ register struct vop *end_operandP; /* -> slot just after last operand */
+ /* Limit of the for (each operand). */
+ register expressionS *expP; /* -> expression values for this operand */
+
+ /* These refer to an instruction operand expression. */
+ segT to_seg; /* Target segment of the address. */
+ register valueT this_add_number;
+ register struct symbol *this_add_symbol; /* +ve (minuend) symbol. */
+ register struct symbol *this_subtract_symbol; /* -ve(subtrahend) symbol. */
+
+ long opcode_as_number; /* As a number. */
+ char *opcode_as_chars; /* Least significant byte 1st. */
+ /* As an array of characters. */
+ char *opcode_low_byteP; /* Least significant byte 1st */
+ /* richfix: unused? */
+/* struct details *detP; */ /* The details of an ADxxx frag. */
+ int length; /* length (bytes) meant by vop_short. */
+ int at; /* 0, or 1 if '@' is in addressing mode. */
+ int nbytes; /* From vop_nbytes: vax_operand_width (in bytes) */
+ FLONUM_TYPE *floatP;
+ char *vip ();
+ LITTLENUM_TYPE literal_float[8];
+ /* Big enough for any floating point literal. */
+
+ if (*(p = vip (&v, instruction_string))) {
+ as_fatal("vax_assemble\"%s\" in=\"%s\"", p, instruction_string);
+ }
+ /*
+ * Now we try to find as many as_warn()s as we can. If we do any as_warn()s
+ * then goofed=1. Notice that we don't make any frags yet.
+ * Should goofed be 1, then this instruction will wedge in any pass,
+ * and we can safely flush it, without causing interpass symbol phase
+ * errors. That is, without changing label values in different passes.
+ */
+ if (goofed = (*v.vit_error)) {
+ as_warn ("Ignoring statement due to \"%s\"", v.vit_error);
+ }
+ /*
+ * We need to use expression() and friends, which require us to diddle
+ * input_line_pointer. So we save it and restore it later.
+ */
+ save_input_line_pointer = input_line_pointer;
+ for (operandP = v.vit_operand,
+ expP = exp_of_operand,
+ floatP = float_operand,
+ end_operandP = v.vit_operand + v.vit_operands;
+
+ operandP < end_operandP;
+
+ operandP++, expP++, floatP++) { /* for each operand */
+ if (*(operandP->vop_error)) {
+ as_warn ("Ignoring statement because \"%s\"", (operandP->vop_error));
+ goofed = 1;
+ } else { /* statement has no syntax goofs: lets sniff the expression */
+ int can_be_short = 0; /* 1 if a bignum can be reduced to a short literal. */
+
+ input_line_pointer = operandP->vop_expr_begin;
+ c_save = operandP->vop_expr_end[1];
+ operandP->vop_expr_end[1] = '\0';
+ /* If to_seg == SEG_PASS1, expression() will have set need_pass_2 = 1. */
+ switch (to_seg = expression (expP)) {
+ case SEG_ABSENT:
+ /* for BSD4.2 compatibility, missing expression is absolute 0 */
+ to_seg = expP->X_seg = SEG_ABSOLUTE;
+ expP->X_add_number = 0;
+ /* for SEG_ABSOLUTE, we shouldnt need to set X_subtract_symbol, X_add_symbol to any
+ particular value. But, we will program defensively. Since this situation occurs rarely
+ so it costs us little to do, and stops Dean worrying about the origin of random bits in
+ expressionS's. */
+ expP->X_add_symbol = NULL;
+ expP->X_subtract_symbol = NULL;
+ case SEG_TEXT:
+ case SEG_DATA:
+ case SEG_BSS:
+ case SEG_ABSOLUTE:
+ case SEG_UNKNOWN:
+ break;
+
+ case SEG_DIFFERENCE:
+ case SEG_PASS1:
+ /*
+ * Major bug. We can't handle the case of a
+ * SEG_DIFFERENCE expression in a VIT_OPCODE_SYNTHETIC
+ * variable-length instruction.
+ * We don't have a frag type that is smart enough to
+ * relax a SEG_DIFFERENCE, and so we just force all
+ * SEG_DIFFERENCEs to behave like SEG_PASS1s.
+ * Clearly, if there is a demand we can invent a new or
+ * modified frag type and then coding up a frag for this
+ * case will be easy. SEG_DIFFERENCE was invented for the
+ * .words after a CASE opcode, and was never intended for
+ * instruction operands.
+ */
+ need_pass_2 = 1;
+ as_warn("Can't relocate expression");
+ break;
+
+ case SEG_BIG:
+ /* Preserve the bits. */
+ if (expP->X_add_number > 0) {
+ bignum_copy(generic_bignum, expP->X_add_number,
+ floatP->low, SIZE_OF_LARGE_NUMBER);
+ } else {
+ know(expP->X_add_number < 0);
+ flonum_copy (&generic_floating_point_number,
+ floatP);
+ if (strchr("s i", operandP->vop_short)) { /* Could possibly become S^# */
+ flonum_gen2vax(-expP->X_add_number, floatP, literal_float);
+ switch (-expP->X_add_number) {
+ case 'f':
+ can_be_short =
+ (literal_float[0] & 0xFC0F) == 0x4000
+ && literal_float[1] == 0;
+ break;
+
+ case 'd':
+ can_be_short =
+ (literal_float[0] & 0xFC0F) == 0x4000
+ && literal_float[1] == 0
+ && literal_float[2] == 0
+ && literal_float[3] == 0;
+ break;
+
+ case 'g':
+ can_be_short =
+ (literal_float[0] & 0xFF81) == 0x4000
+ && literal_float[1] == 0
+ && literal_float[2] == 0
+ && literal_float[3] == 0;
+ break;
+
+ case 'h':
+ can_be_short = ((literal_float[0] & 0xFFF8) == 0x4000
+ && (literal_float[1] & 0xE000) == 0
+ && literal_float[2] == 0
+ && literal_float[3] == 0
+ && literal_float[4] == 0
+ && literal_float[5] == 0
+ && literal_float[6] == 0
+ && literal_float[7] == 0);
+ break;
+
+ default:
+ BAD_CASE(-expP->X_add_number);
+ break;
+ } /* switch (float type) */
+ } /* if (could want to become S^#...) */
+ } /* bignum or flonum ? */
+
+ if (operandP->vop_short == 's'
+ || operandP->vop_short == 'i'
+ || (operandP->vop_short == ' '
+ && operandP->vop_reg == 0xF
+ && (operandP->vop_mode & 0xE) == 0x8)) {
+ /* Saw a '#'. */
+ if (operandP->vop_short == ' ') { /* We must chose S^ or I^. */
+ if (expP->X_add_number > 0) { /* Bignum: Short literal impossible. */
+ operandP->vop_short = 'i';
+ operandP->vop_mode = 8;
+ operandP->vop_reg = 0xF; /* VAX PC. */
+ } else { /* Flonum: Try to do it. */
+ if (can_be_short)
+ {
+ operandP->vop_short = 's';
+ operandP->vop_mode = 0;
+ operandP->vop_ndx = -1;
+ operandP->vop_reg = -1;
+ /* JF hope this is the right thing */
+ expP->X_seg = SEG_ABSOLUTE;
+ } else {
+ operandP->vop_short = 'i';
+ operandP->vop_mode = 8;
+ operandP->vop_reg = 0xF; /* VAX PC */
+ }
+ } /* bignum or flonum ? */
+ } /* if #, but no S^ or I^ seen. */
+ /* No more ' ' case: either 's' or 'i'. */
+ if (operandP->vop_short == 's') {
+ /* Wants to be a short literal. */
+ if (expP->X_add_number > 0) {
+ as_warn ("Bignum not permitted in short literal. Immediate mode assumed.");
+ operandP->vop_short = 'i';
+ operandP->vop_mode = 8;
+ operandP->vop_reg = 0xF; /* VAX PC. */
+ } else {
+ if (!can_be_short) {
+ as_warn ("Can't do flonum short literal: immediate mode used.");
+ operandP->vop_short = 'i';
+ operandP->vop_mode = 8;
+ operandP->vop_reg = 0xF; /* VAX PC. */
+ } else { /* Encode short literal now. */
+ int temp = 0;
+
+ switch (-expP->X_add_number) {
+ case 'f':
+ case 'd':
+ temp = literal_float[0] >> 4;
+ break;
+
+ case 'g':
+ temp = literal_float[0] >> 1;
+ break;
+
+ case 'h':
+ temp = ((literal_float[0] << 3) & 070)
+ | ((literal_float[1] >> 13) & 07);
+ break;
+
+ default:
+ BAD_CASE(-expP->X_add_number);
+ break;
+ }
+
+ floatP->low[0] = temp & 077;
+ floatP->low[1] = 0;
+ } /* if can be short literal float */
+ } /* flonum or bignum ? */
+ } else { /* I^# seen: set it up if float. */
+ if (expP->X_add_number < 0) {
+ memcpy(floatP->low, literal_float, sizeof(literal_float));
+ }
+ } /* if S^# seen. */
+ } else {
+ as_warn ("A bignum/flonum may not be a displacement: 0x%x used",
+ expP->X_add_number = 0x80000000);
+ /* Chosen so luser gets the most offset bits to patch later. */
+ }
+ expP->X_add_number = floatP->low[0]
+ | ((LITTLENUM_MASK & (floatP->low[1])) << LITTLENUM_NUMBER_OF_BITS);
+ /*
+ * For the SEG_BIG case we have:
+ * If vop_short == 's' then a short floating literal is in the
+ * lowest 6 bits of floatP->low [0], which is
+ * big_operand_bits [---] [0].
+ * If vop_short == 'i' then the appropriate number of elements
+ * of big_operand_bits [---] [...] are set up with the correct
+ * bits.
+ * Also, just in case width is byte word or long, we copy the lowest
+ * 32 bits of the number to X_add_number.
+ */
+ break;
+
+ default:
+ BAD_CASE (to_seg);
+ break;
+ }
+ if (input_line_pointer != operandP->vop_expr_end + 1) {
+ as_warn ("Junk at end of expression \"%s\"", input_line_pointer);
+ goofed = 1;
+ }
+ operandP->vop_expr_end[1] = c_save;
+ }
+ } /* for (each operand) */
+
+ input_line_pointer = save_input_line_pointer;
+
+ if (need_pass_2 || goofed) {
+ return;
+ }
+
+
+ /* Emit op-code. */
+ /* Remember where it is, in case we want to modify the op-code later. */
+ opcode_low_byteP = frag_more (v.vit_opcode_nbytes);
+ memcpy(opcode_low_byteP, v.vit_opcode, v.vit_opcode_nbytes);
+ opcode_as_number = md_chars_to_number (opcode_as_chars = v.vit_opcode, 4);
+ for (operandP = v.vit_operand,
+ expP = exp_of_operand,
+ floatP = float_operand,
+ end_operandP = v.vit_operand + v.vit_operands;
+
+ operandP < end_operandP;
+
+ operandP++,
+ floatP++,
+ expP++) { /* for each operand */
+ if (operandP->vop_ndx >= 0) {
+ /* indexed addressing byte */
+ /* Legality of indexed mode already checked: it is OK */
+ FRAG_APPEND_1_CHAR (0x40 + operandP->vop_ndx);
+ } /* if (vop_ndx >= 0) */
+
+ /* Here to make main operand frag(s). */
+ this_add_number = expP->X_add_number;
+ this_add_symbol = expP->X_add_symbol;
+ this_subtract_symbol = expP->X_subtract_symbol;
+ to_seg = expP->X_seg;
+ is_undefined = (to_seg == SEG_UNKNOWN);
+ know(to_seg == SEG_UNKNOWN
+ || to_seg == SEG_ABSOLUTE
+ || to_seg == SEG_DATA
+ || to_seg == SEG_TEXT
+ || to_seg == SEG_BSS
+ || to_seg == SEG_BIG);
+ at = operandP->vop_mode & 1;
+ length = (operandP->vop_short == 'b'
+ ? 1 : (operandP->vop_short == 'w'
+ ? 2 : (operandP->vop_short == 'l'
+ ? 4 : 0)));
+ nbytes = operandP->vop_nbytes;
+ if (operandP->vop_access == 'b') {
+ if (to_seg == now_seg || is_undefined) {
+ /* If is_undefined, then it might BECOME now_seg. */
+ if (nbytes) {
+ p = frag_more(nbytes);
+ fix_new(frag_now, p - frag_now->fr_literal, nbytes,
+ this_add_symbol, 0, this_add_number, 1, NO_RELOC);
+ } else { /* to_seg == now_seg || to_seg == SEG_UNKNOWN */
+ /* nbytes == 0 */
+ length_code = is_undefined ? STATE_UNDF : STATE_BYTE;
+ if (opcode_as_number & VIT_OPCODE_SPECIAL) {
+ if (operandP->vop_width == VAX_WIDTH_UNCONDITIONAL_JUMP) {
+ /* br or jsb */
+ frag_var(rs_machine_dependent, 5, 1,
+ ENCODE_RELAX (STATE_ALWAYS_BRANCH, length_code),
+ this_add_symbol, this_add_number,
+ opcode_low_byteP);
+ } else {
+ if (operandP->vop_width == VAX_WIDTH_WORD_JUMP) {
+ length_code = STATE_WORD;
+ /* JF: There is no state_byte for this one! */
+ frag_var(rs_machine_dependent, 10, 2,
+ ENCODE_RELAX (STATE_COMPLEX_BRANCH, length_code),
+ this_add_symbol, this_add_number,
+ opcode_low_byteP);
+ } else {
+ know(operandP->vop_width == VAX_WIDTH_BYTE_JUMP);
+ frag_var(rs_machine_dependent, 9, 1,
+ ENCODE_RELAX (STATE_COMPLEX_HOP, length_code),
+ this_add_symbol, this_add_number,
+ opcode_low_byteP);
+ }
+ }
+ } else {
+ know(operandP->vop_width == VAX_WIDTH_CONDITIONAL_JUMP);
+ frag_var(rs_machine_dependent, 7, 1,
+ ENCODE_RELAX (STATE_CONDITIONAL_BRANCH, length_code),
+ this_add_symbol, this_add_number,
+ opcode_low_byteP);
+ }
+ }
+ } else { /* to_seg != now_seg && to_seg != SEG_UNKNOWN */
+ /*
+ * --- SEG FLOAT MAY APPEAR HERE ----
+ */
+ if (to_seg == SEG_ABSOLUTE) {
+ if (nbytes) {
+ know(!(opcode_as_number & VIT_OPCODE_SYNTHETIC));
+ p = frag_more (nbytes);
+ /* Conventional relocation. */
+ fix_new(frag_now, p - frag_now->fr_literal,
+ nbytes, &abs_symbol, 0, this_add_number, 1, NO_RELOC);
+ } else {
+ know(opcode_as_number & VIT_OPCODE_SYNTHETIC);
+ if (opcode_as_number & VIT_OPCODE_SPECIAL) {
+ if (operandP->vop_width == VAX_WIDTH_UNCONDITIONAL_JUMP) {
+ /* br or jsb */
+ *opcode_low_byteP = opcode_as_chars[0] + VAX_WIDEN_LONG;
+ know(opcode_as_chars[1] == 0);
+ p = frag_more (5);
+ p[0] = VAX_ABSOLUTE_MODE; /* @#... */
+ md_number_to_chars(p + 1, this_add_number, 4);
+ /* Now (eg) JMP @#foo or JSB @#foo. */
+ } else {
+ if (operandP->vop_width == VAX_WIDTH_WORD_JUMP) {
+ p = frag_more (10);
+ p[0] = 2;
+ p[1] = 0;
+ p[2] = VAX_BRB;
+ p[3] = 6;
+ p[4] = VAX_JMP;
+ p[5] = VAX_ABSOLUTE_MODE; /* @#... */
+ md_number_to_chars(p + 6, this_add_number, 4);
+ /*
+ * Now (eg) ACBx 1f
+ * BRB 2f
+ * 1: JMP @#foo
+ * 2:
+ */
+ } else {
+ know(operandP->vop_width == VAX_WIDTH_BYTE_JUMP);
+ p = frag_more (9);
+ p[0] = 2;
+ p[1] = VAX_BRB;
+ p[2] = 6;
+ p[3] = VAX_JMP;
+ p[4] = VAX_PC_RELATIVE_MODE + 1; /* @#... */
+ md_number_to_chars(p + 5, this_add_number, 4);
+ /*
+ * Now (eg) xOBxxx 1f
+ * BRB 2f
+ * 1: JMP @#foo
+ * 2:
+ */
+ }
+ }
+ } else {
+ /* b<cond> */
+ *opcode_low_byteP ^= 1;
+ /* To reverse the condition in a VAX branch, complement the lowest order
+ bit. */
+ p = frag_more (7);
+ p[0] = 6;
+ p[1] = VAX_JMP;
+ p[2] = VAX_ABSOLUTE_MODE; /* @#... */
+ md_number_to_chars(p + 3, this_add_number, 4);
+ /*
+ * Now (eg) BLEQ 1f
+ * JMP @#foo
+ * 1:
+ */
+ }
+ }
+ } else { /* to_seg != now_seg && to_seg != SEG_UNKNOWN && to_Seg != SEG_ABSOLUTE */
+ if (nbytes > 0) {
+ /* Pc-relative. Conventional relocation. */
+ know(!(opcode_as_number & VIT_OPCODE_SYNTHETIC));
+ p = frag_more (nbytes);
+ fix_new(frag_now, p - frag_now->fr_literal,
+ nbytes, &abs_symbol, 0, this_add_number, 1, NO_RELOC);
+ } else {
+ know(opcode_as_number & VIT_OPCODE_SYNTHETIC);
+ if (opcode_as_number & VIT_OPCODE_SPECIAL) {
+ if (operandP->vop_width == VAX_WIDTH_UNCONDITIONAL_JUMP) {
+ /* br or jsb */
+ know(opcode_as_chars[1] == 0);
+ *opcode_low_byteP = opcode_as_chars[0] + VAX_WIDEN_LONG;
+ p = frag_more (5);
+ p[0] = VAX_PC_RELATIVE_MODE;
+ fix_new(frag_now,
+ p + 1 - frag_now->fr_literal, 4,
+ this_add_symbol, 0,
+ this_add_number, 1, NO_RELOC);
+ /* Now eg JMP foo or JSB foo. */
+ } else {
+ if (operandP->vop_width == VAX_WIDTH_WORD_JUMP) {
+ p = frag_more (10);
+ p[0] = 0;
+ p[1] = 2;
+ p[2] = VAX_BRB;
+ p[3] = 6;
+ p[4] = VAX_JMP;
+ p[5] = VAX_PC_RELATIVE_MODE;
+ fix_new(frag_now,
+ p + 6 - frag_now->fr_literal, 4,
+ this_add_symbol, 0,
+ this_add_number, 1, NO_RELOC);
+ /*
+ * Now (eg) ACBx 1f
+ * BRB 2f
+ * 1: JMP foo
+ * 2:
+ */
+ } else {
+ know(operandP->vop_width == VAX_WIDTH_BYTE_JUMP);
+ p = frag_more (10);
+ p[0] = 2;
+ p[1] = VAX_BRB;
+ p[2] = 6;
+ p[3] = VAX_JMP;
+ p[4] = VAX_PC_RELATIVE_MODE;
+ fix_new(frag_now,
+ p + 5 - frag_now->fr_literal,
+ 4, this_add_symbol, 0,
+ this_add_number, 1, NO_RELOC);
+ /*
+ * Now (eg) xOBxxx 1f
+ * BRB 2f
+ * 1: JMP foo
+ * 2:
+ */
+ }
+ }
+ } else {
+ know(operandP->vop_width == VAX_WIDTH_CONDITIONAL_JUMP);
+ *opcode_low_byteP ^= 1; /* Reverse branch condition. */
+ p = frag_more (7);
+ p[0] = 6;
+ p[1] = VAX_JMP;
+ p[2] = VAX_PC_RELATIVE_MODE;
+ fix_new(frag_now, p + 3 - frag_now->fr_literal,
+ 4, this_add_symbol, 0,
+ this_add_number, 1, NO_RELOC);
+ }
+ }
+ }
+ }
+ } else {
+ know(operandP->vop_access != 'b'); /* So it is ordinary operand. */
+ know(operandP->vop_access != ' '); /* ' ' target-independent: elsewhere. */
+ know(operandP->vop_access == 'a'
+ || operandP->vop_access == 'm'
+ || operandP->vop_access == 'r'
+ || operandP->vop_access == 'v'
+ || operandP->vop_access == 'w');
+ if (operandP->vop_short == 's') {
+ if (to_seg == SEG_ABSOLUTE) {
+ if (this_add_number < 0 || this_add_number >= 64) {
+ as_warn("Short literal overflow(%d.), immediate mode assumed.", this_add_number);
+ operandP->vop_short = 'i';
+ operandP->vop_mode = 8;
+ operandP->vop_reg = 0xF;
+ }
+ } else {
+ as_warn ("Forced short literal to immediate mode. now_seg=%s to_seg=%s",
+ segment_name(now_seg), segment_name(to_seg));
+ operandP->vop_short = 'i';
+ operandP->vop_mode = 8;
+ operandP->vop_reg = 0xF;
+ }
+ }
+ if (operandP->vop_reg >= 0 && (operandP->vop_mode < 8
+ || (operandP->vop_reg != 0xF && operandP->vop_mode < 10))) {
+ /* One byte operand. */
+ know(operandP->vop_mode > 3);
+ FRAG_APPEND_1_CHAR (operandP->vop_mode << 4 | operandP->vop_reg);
+ /* All 1-bytes except S^# happen here. */
+ } else { /* {@}{q^}foo{(Rn)} or S^#foo */
+ if (operandP->vop_reg == -1 && operandP->vop_short != 's') {
+ /* "{@}{q^}foo" */
+ if (to_seg == now_seg) {
+ if (length == 0) {
+ know(operandP->vop_short == ' ');
+ p = frag_var(rs_machine_dependent, 10, 2,
+ ENCODE_RELAX (STATE_PC_RELATIVE, STATE_BYTE),
+ this_add_symbol, this_add_number,
+ opcode_low_byteP);
+ know(operandP->vop_mode == 10 + at);
+ *p = at << 4;
+ /* At is the only context we need to carry to */
+ /* other side of relax() process. */
+ /* Must be in the correct bit position of VAX */
+ /* operand spec. byte. */
+ } else {
+ know(length);
+ know(operandP->vop_short != ' ');
+ p = frag_more (length + 1);
+ /* JF is this array stuff really going to work? */
+ p[0] = 0xF | ((at + "?\12\14?\16"[length]) << 4);
+ fix_new(frag_now, p + 1 - frag_now->fr_literal,
+ length, this_add_symbol, 0,
+ this_add_number, 1, NO_RELOC);
+ }
+ } else { /* to_seg != now_seg */
+ if (this_add_symbol == NULL) {
+ know(to_seg == SEG_ABSOLUTE);
+ /* Do @#foo: simpler relocation than foo-.(pc) anyway. */
+ p = frag_more (5);
+ p[0] = VAX_ABSOLUTE_MODE; /* @#... */
+ md_number_to_chars(p + 1, this_add_number, 4);
+ if (length && length != 4)
+ {
+ as_warn ("Length specification ignored. Address mode 9F used");
+ }
+ } else {
+ /* {@}{q^}other_seg */
+ know((length == 0 && operandP->vop_short == ' ')
+ ||(length > 0 && operandP->vop_short != ' '));
+ if (is_undefined) {
+ /*
+ * We have a SEG_UNKNOWN symbol. It might
+ * turn out to be in the same segment as
+ * the instruction, permitting relaxation.
+ */
+ p = frag_var(rs_machine_dependent, 5, 2,
+ ENCODE_RELAX (STATE_PC_RELATIVE, STATE_UNDF),
+ this_add_symbol, this_add_number,
+ 0);
+ p[0] = at << 4;
+ } else {
+ if (length == 0) {
+ know(operandP->vop_short == ' ');
+ length = 4; /* Longest possible. */
+ }
+ p = frag_more (length + 1);
+ p[0] = 0xF | ((at + "?\12\14?\16"[length]) << 4);
+ md_number_to_chars(p + 1, this_add_number, length);
+ fix_new(frag_now,
+ p + 1 - frag_now->fr_literal,
+ length, this_add_symbol, 0,
+ this_add_number, 1, NO_RELOC);
+ }
+ }
+ }
+ } else { /* {@}{q^}foo(Rn) or S^# or I^# or # */
+ if (operandP->vop_mode < 0xA) { /* # or S^# or I^# */
+ /* know( (length == 0 && operandP->vop_short == ' ')
+ || (length > 0 && operandP->vop_short != ' ')); */
+ if (length == 0
+ && to_seg == SEG_ABSOLUTE
+ && operandP->vop_mode == 8 /* No '@'. */
+ && this_add_number < 64
+ && this_add_number >= 0) {
+ operandP->vop_short = 's';
+ }
+ if (operandP->vop_short == 's') {
+ FRAG_APPEND_1_CHAR (this_add_number);
+ } else { /* I^#... */
+ know(nbytes);
+ p = frag_more (nbytes + 1);
+ know(operandP->vop_reg == 0xF);
+ p[0] = (operandP->vop_mode << 4) | 0xF;
+ if (to_seg == SEG_ABSOLUTE) {
+ /*
+ * If nbytes > 4, then we are scrod. We don't know if the
+ * high order bytes are to be 0xFF or 0x00.
+ * BSD4.2 & RMS say use 0x00. OK --- but this
+ * assembler needs ANOTHER rewrite to
+ * cope properly with this bug.
+ */
+ md_number_to_chars(p + 1, this_add_number, min (4, nbytes));
+ if (nbytes > 4)
+ {
+ memset(p + 5, '\0', nbytes - 4);
+ }
+ } else {
+ if (to_seg == SEG_BIG) {
+ /*
+ * Problem here is to get the bytes in the right order.
+ * We stored our constant as LITTLENUMs, not bytes.
+ */
+ LITTLENUM_TYPE *lP;
+
+ lP = floatP->low;
+ if (nbytes & 1) {
+ know(nbytes == 1);
+ p[1] = *lP;
+ } else {
+ for (p++; nbytes; nbytes -= 2, p += 2, lP++)
+ {
+ md_number_to_chars(p, *lP, 2);
+ }
+ }
+ } else {
+ fix_new(frag_now, p + 1 - frag_now->fr_literal,
+ nbytes, this_add_symbol, 0,
+ this_add_number, 0, NO_RELOC);
+ }
+ }
+ }
+ } else { /* {@}{q^}foo(Rn) */
+ know((length == 0 && operandP->vop_short == ' ')
+ ||(length > 0 && operandP->vop_short != ' '));
+ if (length == 0) {
+ if (to_seg == SEG_ABSOLUTE) {
+ register long test;
+
+ test = this_add_number;
+
+ if (test < 0)
+ test = ~test;
+
+ length = test & 0xffff8000 ? 4
+ : test & 0xffffff80 ? 2
+ : 1;
+ } else {
+ length = 4;
+ }
+ }
+ p = frag_more (1 + length);
+ know(operandP->vop_reg >= 0);
+ p[0] = operandP->vop_reg
+ | ((at | "?\12\14?\16"[length]) << 4);
+ if (to_seg == SEG_ABSOLUTE) {
+ md_number_to_chars(p + 1, this_add_number, length);
+ } else {
+ fix_new(frag_now, p + 1 - frag_now->fr_literal,
+ length, this_add_symbol, 0,
+ this_add_number, 0, NO_RELOC);
+ }
+ }
+ }
+ } /* if (single-byte-operand) */
+ }
+ } /* for (operandP) */
+} /* vax_assemble() */
+
+/*
+ * md_estimate_size_before_relax()
+ *
+ * Called just before relax().
+ * Any symbol that is now undefined will not become defined.
+ * Return the correct fr_subtype in the frag.
+ * Return the initial "guess for fr_var" to caller.
+ * The guess for fr_var is ACTUALLY the growth beyond fr_fix.
+ * Whatever we do to grow fr_fix or fr_var contributes to our returned value.
+ * Although it may not be explicit in the frag, pretend fr_var starts with a
+ * 0 value.
+ */
+int
+ md_estimate_size_before_relax (fragP, segment)
+register fragS *fragP;
+register segT segment;
+{
+ register char *p;
+ register int old_fr_fix;
+
+ old_fr_fix = fragP->fr_fix;
+ switch (fragP->fr_subtype) {
+ case ENCODE_RELAX (STATE_PC_RELATIVE, STATE_UNDF):
+ if (S_GET_SEGMENT(fragP->fr_symbol) == segment) { /* A relaxable case. */
+ fragP->fr_subtype = ENCODE_RELAX (STATE_PC_RELATIVE, STATE_BYTE);
+ } else {
+ p = fragP->fr_literal + old_fr_fix;
+ p[0] |= VAX_PC_RELATIVE_MODE; /* Preserve @ bit. */
+ fragP->fr_fix += 1 + 4;
+ fix_new(fragP, old_fr_fix + 1, 4, fragP->fr_symbol, 0,
+ fragP->fr_offset, 1, NO_RELOC);
+ frag_wane(fragP);
+ }
+ break;
+
+ case ENCODE_RELAX (STATE_CONDITIONAL_BRANCH, STATE_UNDF):
+ if (S_GET_SEGMENT(fragP->fr_symbol) == segment) {
+ fragP->fr_subtype = ENCODE_RELAX (STATE_CONDITIONAL_BRANCH, STATE_BYTE);
+ } else {
+ p = fragP->fr_literal + old_fr_fix;
+ *fragP->fr_opcode ^= 1; /* Reverse sense of branch. */
+ p[0] = 6;
+ p[1] = VAX_JMP;
+ p[2] = VAX_PC_RELATIVE_MODE; /* ...(PC) */
+ fragP->fr_fix += 1 + 1 + 1 + 4;
+ fix_new(fragP, old_fr_fix + 3, 4, fragP->fr_symbol, 0,
+ fragP->fr_offset, 1, NO_RELOC);
+ frag_wane(fragP);
+ }
+ break;
+
+ case ENCODE_RELAX (STATE_COMPLEX_BRANCH, STATE_UNDF):
+ if (S_GET_SEGMENT(fragP->fr_symbol) == segment) {
+ fragP->fr_subtype = ENCODE_RELAX (STATE_COMPLEX_BRANCH, STATE_WORD);
+ } else {
+ p = fragP->fr_literal + old_fr_fix;
+ p[0] = 2;
+ p[1] = 0;
+ p[2] = VAX_BRB;
+ p[3] = 6;
+ p[4] = VAX_JMP;
+ p[5] = VAX_PC_RELATIVE_MODE; /* ...(pc) */
+ fragP->fr_fix += 2 + 2 + 1 + 1 + 4;
+ fix_new(fragP, old_fr_fix + 6, 4, fragP->fr_symbol, 0,
+ fragP->fr_offset, 1, NO_RELOC);
+ frag_wane(fragP);
+ }
+ break;
+
+ case ENCODE_RELAX (STATE_COMPLEX_HOP, STATE_UNDF):
+ if (S_GET_SEGMENT(fragP->fr_symbol) == segment) {
+ fragP->fr_subtype = ENCODE_RELAX (STATE_COMPLEX_HOP, STATE_BYTE);
+ } else {
+ p = fragP->fr_literal + old_fr_fix;
+ p[0] = 2;
+ p[1] = VAX_BRB;
+ p[2] = 6;
+ p[3] = VAX_JMP;
+ p[4] = VAX_PC_RELATIVE_MODE; /* ...(pc) */
+ fragP->fr_fix += 1 + 2 + 1 + 1 + 4;
+ fix_new(fragP, old_fr_fix + 5, 4, fragP->fr_symbol, 0,
+ fragP->fr_offset, 1, NO_RELOC);
+ frag_wane(fragP);
+ }
+ break;
+
+ case ENCODE_RELAX (STATE_ALWAYS_BRANCH, STATE_UNDF):
+ if (S_GET_SEGMENT(fragP->fr_symbol) == segment) {
+ fragP->fr_subtype = ENCODE_RELAX (STATE_ALWAYS_BRANCH, STATE_BYTE);
+ } else {
+ p = fragP->fr_literal + old_fr_fix;
+ *fragP->fr_opcode += VAX_WIDEN_LONG;
+ p[0] = VAX_PC_RELATIVE_MODE; /* ...(PC) */
+ fragP->fr_fix += 1 + 4;
+ fix_new(fragP, old_fr_fix + 1, 4, fragP->fr_symbol, 0,
+ fragP->fr_offset, 1, NO_RELOC);
+ frag_wane(fragP);
+ }
+ break;
+
+ default:
+ break;
+ }
+ return (fragP->fr_var + fragP->fr_fix - old_fr_fix);
+} /* md_estimate_size_before_relax() */
+
+/*
+ * md_convert_frag();
+ *
+ * Called after relax() is finished.
+ * In: Address of frag.
+ * fr_type == rs_machine_dependent.
+ * fr_subtype is what the address relaxed to.
+ *
+ * Out: Any fixSs and constants are set up.
+ * Caller will turn frag into a ".space 0".
+ */
+void
+ md_convert_frag (headers, fragP)
+object_headers *headers;
+register fragS *fragP;
+{
+ char *addressP; /* -> _var to change. */
+ char *opcodeP; /* -> opcode char(s) to change. */
+ short int length_code; /* 2=long 1=word 0=byte */
+ short int extension = 0; /* Size of relaxed address. */
+ /* Added to fr_fix: incl. ALL var chars. */
+ symbolS *symbolP;
+ long where;
+ long address_of_var;
+ /* Where, in file space, is _var of *fragP? */
+ long target_address = 0;
+ /* Where, in file space, does addr point? */
+
+ know(fragP->fr_type == rs_machine_dependent);
+ length_code = fragP->fr_subtype & 3; /* depends on ENCODE_RELAX() */
+ know(length_code >= 0 && length_code < 3);
+ where = fragP->fr_fix;
+ addressP = fragP->fr_literal + where;
+ opcodeP = fragP->fr_opcode;
+ symbolP = fragP->fr_symbol;
+ know(symbolP);
+ target_address = S_GET_VALUE(symbolP) + fragP->fr_offset;
+ address_of_var = fragP->fr_address + where;
+
+ switch (fragP->fr_subtype) {
+
+ case ENCODE_RELAX(STATE_PC_RELATIVE, STATE_BYTE):
+ know(*addressP == 0 || *addressP == 0x10); /* '@' bit. */
+ addressP[0] |= 0xAF; /* Byte displacement. */
+ addressP[1] = target_address - (address_of_var + 2);
+ extension = 2;
+ break;
+
+ case ENCODE_RELAX(STATE_PC_RELATIVE, STATE_WORD):
+ know(*addressP == 0 || *addressP == 0x10); /* '@' bit. */
+ addressP[0] |= 0xCF; /* Word displacement. */
+ md_number_to_chars(addressP + 1, target_address - (address_of_var + 3), 2);
+ extension = 3;
+ break;
+
+ case ENCODE_RELAX(STATE_PC_RELATIVE, STATE_LONG):
+ know(*addressP == 0 || *addressP == 0x10); /* '@' bit. */
+ addressP[0] |= 0xEF; /* Long word displacement. */
+ md_number_to_chars(addressP + 1, target_address - (address_of_var + 5), 4);
+ extension = 5;
+ break;
+
+ case ENCODE_RELAX(STATE_CONDITIONAL_BRANCH, STATE_BYTE):
+ addressP[0] = target_address - (address_of_var + 1);
+ extension = 1;
+ break;
+
+ case ENCODE_RELAX(STATE_CONDITIONAL_BRANCH, STATE_WORD):
+ opcodeP[0] ^= 1; /* Reverse sense of test. */
+ addressP[0] = 3;
+ addressP[1] = VAX_BRB + VAX_WIDEN_WORD;
+ md_number_to_chars(addressP + 2, target_address - (address_of_var + 4), 2);
+ extension = 4;
+ break;
+
+ case ENCODE_RELAX(STATE_CONDITIONAL_BRANCH, STATE_LONG):
+ opcodeP[0] ^= 1; /* Reverse sense of test. */
+ addressP[0] = 6;
+ addressP[1] = VAX_JMP;
+ addressP[2] = VAX_PC_RELATIVE_MODE;
+ md_number_to_chars(addressP + 3, target_address, 4);
+ extension = 7;
+ break;
+
+ case ENCODE_RELAX(STATE_ALWAYS_BRANCH, STATE_BYTE):
+ addressP[0] = target_address - (address_of_var + 1);
+ extension = 1;
+ break;
+
+ case ENCODE_RELAX(STATE_ALWAYS_BRANCH, STATE_WORD):
+ opcodeP[0] += VAX_WIDEN_WORD; /* brb -> brw, bsbb -> bsbw */
+ md_number_to_chars(addressP, target_address - (address_of_var + 2), 2);
+ extension = 2;
+ break;
+
+ case ENCODE_RELAX(STATE_ALWAYS_BRANCH, STATE_LONG):
+ opcodeP[0] += VAX_WIDEN_LONG; /* brb -> jmp, bsbb -> jsb */
+ addressP[0] = VAX_PC_RELATIVE_MODE;
+ md_number_to_chars(addressP + 1, target_address - (address_of_var + 5), 4);
+ extension = 5;
+ break;
+
+ case ENCODE_RELAX(STATE_COMPLEX_BRANCH, STATE_WORD):
+ md_number_to_chars(addressP, target_address - (address_of_var + 2), 2);
+ extension = 2;
+ break;
+
+ case ENCODE_RELAX(STATE_COMPLEX_BRANCH, STATE_LONG):
+ addressP[0] = 2;
+ addressP[1] = 0;
+ addressP[2] = VAX_BRB;
+ addressP[3] = 6;
+ addressP[4] = VAX_JMP;
+ addressP[5] = VAX_PC_RELATIVE_MODE;
+ md_number_to_chars(addressP + 6, target_address, 4);
+ extension = 10;
+ break;
+
+ case ENCODE_RELAX(STATE_COMPLEX_HOP, STATE_BYTE):
+ addressP[0] = target_address - (address_of_var + 1);
+ extension = 1;
+ break;
+
+ case ENCODE_RELAX(STATE_COMPLEX_HOP, STATE_WORD):
+ addressP[0] = 2;
+ addressP[1] = VAX_BRB;
+ addressP[2] = 3;
+ addressP[3] = VAX_BRW;
+ md_number_to_chars(addressP + 4, target_address - (address_of_var + 6), 2);
+ extension = 6;
+ break;
+
+ case ENCODE_RELAX(STATE_COMPLEX_HOP, STATE_LONG):
+ addressP[0] = 2;
+ addressP[1] = VAX_BRB;
+ addressP[2] = 6;
+ addressP[3] = VAX_JMP;
+ addressP[4] = VAX_PC_RELATIVE_MODE;
+ md_number_to_chars(addressP + 5, target_address, 4);
+ extension = 9;
+ break;
+
+ default:
+ BAD_CASE(fragP->fr_subtype);
+ break;
+ }
+ fragP->fr_fix += extension;
+} /* md_convert_frag() */
+
+/* Translate internal format of relocation info into target format.
+
+ On vax: first 4 bytes are normal unsigned long, next three bytes
+ are symbolnum, least sig. byte first. Last byte is broken up with
+ the upper nibble as nuthin, bit 3 as extern, bits 2 & 1 as length, and
+ bit 0 as pcrel. */
+#ifdef comment
+void
+ md_ri_to_chars (the_bytes, ri)
+char *the_bytes;
+struct reloc_info_generic ri;
+{
+ /* this is easy */
+ md_number_to_chars(the_bytes, ri.r_address, sizeof (ri.r_address));
+ /* now the fun stuff */
+ the_bytes[6] = (ri.r_symbolnum >> 16) & 0x0ff;
+ the_bytes[5] = (ri.r_symbolnum >> 8) & 0x0ff;
+ the_bytes[4] = ri.r_symbolnum & 0x0ff;
+ the_bytes[7] = (((ri.r_extern << 3) & 0x08) | ((ri.r_length << 1) & 0x06) |
+ ((ri.r_pcrel << 0) & 0x01)) & 0x0F;
+}
+#endif /* comment */
+
+void tc_aout_fix_to_chars(where, fixP, segment_address_in_file)
+char *where;
+fixS *fixP;
+relax_addressT segment_address_in_file;
+{
+ /*
+ * In: length of relocation (or of address) in chars: 1, 2 or 4.
+ * Out: GNU LD relocation length code: 0, 1, or 2.
+ */
+
+ static unsigned char nbytes_r_length[] = { 42, 0, 1, 42, 2 };
+ long r_symbolnum;
+
+ know(fixP->fx_addsy != NULL);
+
+ md_number_to_chars(where,
+ fixP->fx_frag->fr_address + fixP->fx_where - segment_address_in_file,
+ 4);
+
+ r_symbolnum = (S_IS_DEFINED(fixP->fx_addsy)
+ ? S_GET_TYPE(fixP->fx_addsy)
+ : fixP->fx_addsy->sy_number);
+
+ where[6] = (r_symbolnum >> 16) & 0x0ff;
+ where[5] = (r_symbolnum >> 8) & 0x0ff;
+ where[4] = r_symbolnum & 0x0ff;
+ where[7] = ((((!S_IS_DEFINED(fixP->fx_addsy)) << 3) & 0x08)
+ | ((nbytes_r_length[fixP->fx_size] << 1) & 0x06)
+ | (((fixP->fx_pcrel << 0) & 0x01) & 0x0f));
+
+ return;
+} /* tc_aout_fix_to_chars() */
+/*
+ * BUGS, GRIPES, APOLOGIA, etc.
+ *
+ * The opcode table 'votstrs' needs to be sorted on opcode frequency.
+ * That is, AFTER we hash it with hash_...(), we want most-used opcodes
+ * to come out of the hash table faster.
+ *
+ * I am sorry to inflict
+ * yet another VAX assembler on the world, but RMS says we must
+ * do everything from scratch, to prevent pin-heads restricting
+ * this software.
+ */
+
+/*
+ * This is a vaguely modular set of routines in C to parse VAX
+ * assembly code using DEC mnemonics. It is NOT un*x specific.
+ *
+ * The idea here is that the assembler has taken care of all:
+ * labels
+ * macros
+ * listing
+ * pseudo-ops
+ * line continuation
+ * comments
+ * condensing any whitespace down to exactly one space
+ * and all we have to do is parse 1 line into a vax instruction
+ * partially formed. We will accept a line, and deliver:
+ * an error message (hopefully empty)
+ * a skeleton VAX instruction (tree structure)
+ * textual pointers to all the operand expressions
+ * a warning message that notes a silly operand (hopefully empty)
+ */
+
+/*
+ * E D I T H I S T O R Y
+ *
+ * 17may86 Dean Elsner. Bug if line ends immediately after opcode.
+ * 30apr86 Dean Elsner. New vip_op() uses arg block so change call.
+ * 6jan86 Dean Elsner. Crock vip_begin() to call vip_op_defaults().
+ * 2jan86 Dean Elsner. Invent synthetic opcodes.
+ * Widen vax_opcodeT to 32 bits. Use a bit for VIT_OPCODE_SYNTHETIC,
+ * which means this is not a real opcode, it is like a macro; it will
+ * be relax()ed into 1 or more instructions.
+ * Use another bit for VIT_OPCODE_SPECIAL if the op-code is not optimised
+ * like a regular branch instruction. Option added to vip_begin():
+ * exclude synthetic opcodes. Invent synthetic_votstrs[].
+ * 31dec85 Dean Elsner. Invent vit_opcode_nbytes.
+ * Also make vit_opcode into a char[]. We now have n-byte vax opcodes,
+ * so caller's don't have to know the difference between a 1-byte & a
+ * 2-byte op-code. Still need vax_opcodeT concept, so we know how
+ * big an object must be to hold an op.code.
+ * 30dec85 Dean Elsner. Widen typedef vax_opcodeT in "vax-inst.h"
+ * because vax opcodes may be 16 bits. Our crufty C compiler was
+ * happily initialising 8-bit vot_codes with 16-bit numbers!
+ * (Wouldn't the 'phone company like to compress data so easily!)
+ * 29dec85 Dean Elsner. New static table vax_operand_width_size[].
+ * Invented so we know hw many bytes a "I^#42" needs in its immediate
+ * operand. Revised struct vop in "vax-inst.h": explicitly include
+ * byte length of each operand, and it's letter-code datum type.
+ * 17nov85 Dean Elsner. Name Change.
+ * Due to ar(1) truncating names, we learned the hard way that
+ * "vax-inst-parse.c" -> "vax-inst-parse." dropping the "o" off
+ * the archived object name. SO... we shortened the name of this
+ * source file, and changed the makefile.
+ */
+
+static struct hash_control *op_hash = NULL; /* handle of the OPCODE hash table */
+/* NULL means any use before vip_begin() */
+/* will crash */
+
+/*
+ * In: 1 character, from "bdfghloqpw" being the data-type of an operand
+ * of a vax instruction.
+ *
+ * Out: the length of an operand of that type, in bytes.
+ * Special branch operands types "-?!" have length 0.
+ */
+
+static const short int vax_operand_width_size[256] =
+{
+
+#define _ 0
+ _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _,
+ _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _,
+ _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _,
+ _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _,
+ _, _, 1, _, 8, _, 4, 8, 16, _, _, _, 4, _, _, 16, /* ..b.d.fgh...l..o */
+ _, 8, _, _, _, _, _, 2, _, _, _, _, _, _, _, _, /* .q.....w........ */
+ _, _, 1, _, 8, _, 4, 8, 16, _, _, _, 4, _, _, 16, /* ..b.d.fgh...l..o */
+ _, 8, _, _, _, _, _, 2, _, _, _, _, _, _, _, _, /* .q.....w........ */
+ _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _,
+ _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _,
+ _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _,
+ _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _,
+ _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _,
+ _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _,
+ _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _,
+ _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _};
+#undef _
+
+/*
+ * This perversion encodes all the vax opcodes as a bunch of strings.
+ * RMS says we should build our hash-table at run-time. Hmm.
+ * Please would someone arrange these in decreasing frequency of opcode?
+ * Because of the way hash_...() works, the most frequently used opcode
+ * should be textually first and so on.
+ *
+ * Input for this table was 'vax.opcodes', awk(1)ed by 'vax.opcodes.c.awk' .
+ * So change 'vax.opcodes', then re-generate this table.
+ */
+
+#include "opcode/vax.h"
+
+/*
+ * This is a table of optional op-codes. All of them represent
+ * 'synthetic' instructions that seem popular.
+ *
+ * Here we make some pseudo op-codes. Every code has a bit set to say
+ * it is synthetic. This lets you catch them if you want to
+ * ban these opcodes. They are mnemonics for "elastic" instructions
+ * that are supposed to assemble into the fewest bytes needed to do a
+ * branch, or to do a conditional branch, or whatever.
+ *
+ * The opcode is in the usual place [low-order n*8 bits]. This means
+ * that if you mask off the bucky bits, the usual rules apply about
+ * how long the opcode is.
+ *
+ * All VAX branch displacements come at the end of the instruction.
+ * For simple branches (1-byte opcode + 1-byte displacement) the last
+ * operand is coded 'b?' where the "data type" '?' is a clue that we
+ * may reverse the sense of the branch (complement lowest order bit)
+ * and branch around a jump. This is by far the most common case.
+ * That is why the VIT_OPCODE_SYNTHETIC bit is set: it says this is
+ * a 0-byte op-code followed by 2 or more bytes of operand address.
+ *
+ * If the op-code has VIT_OPCODE_SPECIAL set, then we have a more unusual
+ * case.
+ *
+ * For JBSB & JBR the treatment is the similar, except (1) we have a 'bw'
+ * option before (2) we can directly JSB/JMP because there is no condition.
+ * These operands have 'b-' as their access/data type.
+ *
+ * That leaves a bunch of random opcodes: JACBx, JxOBxxx. In these
+ * cases, we do the same idea. JACBxxx are all marked with a 'b!'
+ * JAOBxxx & JSOBxxx are marked with a 'b:'.
+ *
+ */
+#if (VIT_OPCODE_SYNTHETIC != 0x80000000)
+You have just broken the encoding below, which assumes the sign bit
+ means 'I am an imaginary instruction'.
+#endif
+
+#if (VIT_OPCODE_SPECIAL != 0x40000000)
+You have just broken the encoding below, which assumes the 0x40 M bit means
+ 'I am not to be "optimised" the way normal branches are'.
+#endif
+
+ static const struct vot
+ synthetic_votstrs[] =
+{
+ {"jbsb", {"b-", 0xC0000010}}, /* BSD 4.2 */
+ /* jsb used already */
+ {"jbr", {"b-", 0xC0000011}}, /* BSD 4.2 */
+ {"jr", {"b-", 0xC0000011}}, /* consistent */
+ {"jneq", {"b?", 0x80000012}},
+ {"jnequ", {"b?", 0x80000012}},
+ {"jeql", {"b?", 0x80000013}},
+ {"jeqlu", {"b?", 0x80000013}},
+ {"jgtr", {"b?", 0x80000014}},
+ {"jleq", {"b?", 0x80000015}},
+ /* un-used opcodes here */
+ {"jgeq", {"b?", 0x80000018}},
+ {"jlss", {"b?", 0x80000019}},
+ {"jgtru", {"b?", 0x8000001a}},
+ {"jlequ", {"b?", 0x8000001b}},
+ {"jvc", {"b?", 0x8000001c}},
+ {"jvs", {"b?", 0x8000001d}},
+ {"jgequ", {"b?", 0x8000001e}},
+ {"jcc", {"b?", 0x8000001e}},
+ {"jlssu", {"b?", 0x8000001f}},
+ {"jcs", {"b?", 0x8000001f}},
+
+ {"jacbw", {"rwrwmwb!", 0xC000003d}},
+ {"jacbf", {"rfrfmfb!", 0xC000004f}},
+ {"jacbd", {"rdrdmdb!", 0xC000006f}},
+ {"jacbb", {"rbrbmbb!", 0xC000009d}},
+ {"jacbl", {"rlrlmlb!", 0xC00000f1}},
+ {"jacbg", {"rgrgmgb!", 0xC0004ffd}},
+ {"jacbh", {"rhrhmhb!", 0xC0006ffd}},
+
+ {"jbs", {"rlvbb?", 0x800000e0}},
+ {"jbc", {"rlvbb?", 0x800000e1}},
+ {"jbss", {"rlvbb?", 0x800000e2}},
+ {"jbcs", {"rlvbb?", 0x800000e3}},
+ {"jbsc", {"rlvbb?", 0x800000e4}},
+ {"jbcc", {"rlvbb?", 0x800000e5}},
+ {"jbssi", {"rlvbb?", 0x800000e6}},
+ {"jbcci", {"rlvbb?", 0x800000e7}},
+ {"jlbs", {"rlb?", 0x800000e8}}, /* JF changed from rlvbb? */
+ {"jlbc", {"rlb?", 0x800000e9}}, /* JF changed from rlvbb? */
+
+ {"jaoblss", {"rlmlb:", 0xC00000f2}},
+ {"jaobleq", {"rlmlb:", 0xC00000f3}},
+ {"jsobgeq", {"mlb:", 0xC00000f4}}, /* JF was rlmlb: */
+ {"jsobgtr", {"mlb:", 0xC00000f5}}, /* JF was rlmlb: */
+
+ /* CASEx has no branch addresses in our conception of it. */
+ /* You should use ".word ..." statements after the "case ...". */
+
+ {"", ""} /* empty is end sentinel */
+
+}; /* synthetic_votstrs */
+
+/*
+ * v i p _ b e g i n ( )
+ *
+ * Call me once before you decode any lines.
+ * I decode votstrs into a hash table at op_hash (which I create).
+ * I return an error text: hopefully "".
+ * If you want, I will include the 'synthetic' jXXX instructions in the
+ * instruction table.
+ * You must nominate metacharacters for eg DEC's "#", "@", "^".
+ */
+
+char *
+ vip_begin (synthetic_too, immediate, indirect, displen)
+int synthetic_too; /* 1 means include jXXX op-codes. */
+char *immediate, *indirect, *displen;
+{
+ const struct vot *vP; /* scan votstrs */
+ char *retval; /* error text */
+
+ if ((op_hash = hash_new())) {
+ retval = ""; /* OK so far */
+ for (vP = votstrs; *vP->vot_name && !*retval; vP++) {
+ retval = hash_insert(op_hash, vP->vot_name, &vP->vot_detail);
+ }
+ if (synthetic_too) {
+ for (vP = synthetic_votstrs; *vP->vot_name && !*retval; vP++) {
+ retval = hash_insert(op_hash, vP->vot_name, &vP->vot_detail);
+ }
+ }
+ } else {
+ retval = "virtual memory exceeded";
+ }
+#ifndef CONST_TABLE
+ vip_op_defaults(immediate, indirect, displen);
+#endif
+
+ return (retval);
+}
+
+
+/*
+ * v i p _ e n d ( )
+ *
+ * Call me once after you have decoded all lines.
+ * I do any cleaning-up needed.
+ *
+ * We don't have to do any cleanup ourselves: all of our operand
+ * symbol table is static, and free()ing it is naughty.
+ */
+static void vip_end () { }
+
+/*
+ * v i p ( )
+ *
+ * This converts a string into a vax instruction.
+ * The string must be a bare single instruction in dec-vax (with BSD4 frobs)
+ * format.
+ * It provides some error messages: at most one fatal error message (which
+ * stops the scan) and at most one warning message for each operand.
+ * The vax instruction is returned in exploded form, since we have no
+ * knowledge of how you parse (or evaluate) your expressions.
+ * We do however strip off and decode addressing modes and operation
+ * mnemonic.
+ *
+ * The exploded instruction is returned to a struct vit of your choice.
+ * #include "vax-inst.h" to know what a struct vit is.
+ *
+ * This function's value is a string. If it is not "" then an internal
+ * logic error was found: read this code to assign meaning to the string.
+ * No argument string should generate such an error string:
+ * it means a bug in our code, not in the user's text.
+ *
+ * You MUST have called vip_begin() once and vip_end() never before using
+ * this function.
+ */
+
+char * /* "" or bug string */
+ vip (vitP, instring)
+struct vit *vitP; /* We build an exploded instruction here. */
+char *instring; /* Text of a vax instruction: we modify. */
+{
+ register struct vot_wot *vwP; /* How to bit-encode this opcode. */
+ register char *p; /* 1/skip whitespace.2/scan vot_how */
+ register char *q; /* */
+ register char *bug; /* "" or program logic error */
+ register unsigned char count; /* counts number of operands seen */
+ register struct vop *operandp;/* scan operands in struct vit */
+ register char *alloperr; /* error over all operands */
+ register char c; /* Remember char, (we clobber it */
+ /* with '\0' temporarily). */
+ register vax_opcodeT oc; /* Op-code of this instruction. */
+
+ char *vip_op ();
+
+ bug = "";
+ if (*instring == ' ')
+ ++instring; /* Skip leading whitespace. */
+ for (p = instring; *p && *p != ' '; p++) ;; /* MUST end in end-of-string or exactly 1 space. */
+ /* Scanned up to end of operation-code. */
+ /* Operation-code is ended with whitespace. */
+ if (p - instring == 0) {
+ vitP->vit_error = "No operator";
+ count = 0;
+ memset(vitP->vit_opcode, '\0', sizeof(vitP->vit_opcode));
+ } else {
+ c = *p;
+ *p = '\0';
+ /*
+ * Here with instring pointing to what better be an op-name, and p
+ * pointing to character just past that.
+ * We trust instring points to an op-name, with no whitespace.
+ */
+ vwP = (struct vot_wot *) hash_find(op_hash, instring);
+ *p = c; /* Restore char after op-code. */
+ if (vwP == 0) {
+ vitP->vit_error = "Unknown operator";
+ count = 0;
+ memset(vitP->vit_opcode, '\0', sizeof(vitP->vit_opcode));
+ } else {
+ /*
+ * We found a match! So lets pick up as many operands as the
+ * instruction wants, and even gripe if there are too many.
+ * We expect comma to seperate each operand.
+ * We let instring track the text, while p tracks a part of the
+ * struct vot.
+ */
+ /*
+ * The lines below know about 2-byte opcodes starting FD,FE or FF.
+ * They also understand synthetic opcodes. Note:
+ * we return 32 bits of opcode, including bucky bits, BUT
+ * an opcode length is either 8 or 16 bits for vit_opcode_nbytes.
+ */
+ oc = vwP->vot_code; /* The op-code. */
+ vitP->vit_opcode_nbytes = (oc & 0xFF) >= 0xFD ? 2 : 1;
+ md_number_to_chars(vitP->vit_opcode, oc, 4);
+ count = 0; /* no operands seen yet */
+ instring = p; /* point just past operation code */
+ alloperr = "";
+ for (p = vwP->vot_how, operandp = vitP->vit_operand;
+ !*alloperr && !*bug && *p;
+ operandp++, p += 2
+ ) {
+ /*
+ * Here to parse one operand. Leave instring pointing just
+ * past any one ',' that marks the end of this operand.
+ */
+ if (!p[1])
+ bug = "p"; /* ODD(!!) number of bytes in vot_how?? */
+ else if (*instring) {
+ for (q = instring; (c = *q) && c != ','; q++)
+ ;
+ /*
+ * Q points to ',' or '\0' that ends argument. C is that
+ * character.
+ */
+ *q = 0;
+ operandp->vop_width = p[1];
+ operandp->vop_nbytes = vax_operand_width_size[p[1]];
+ operandp->vop_access = p[0];
+ bug = vip_op (instring, operandp);
+ *q = c; /* Restore input text. */
+ if (*(operandp->vop_error))
+ alloperr = "Bad operand";
+ instring = q + (c ? 1 : 0); /* next operand (if any) */
+ count++; /* won another argument, may have an operr */
+ } else
+ alloperr = "Not enough operands";
+ }
+ if (!*alloperr) {
+ if (*instring == ' ')
+ instring++; /* Skip whitespace. */
+ if (*instring)
+ alloperr = "Too many operands";
+ }
+ vitP->vit_error = alloperr;
+ }
+ }
+ vitP->vit_operands = count;
+ return (bug);
+}
+
+#ifdef test
+
+/*
+ * Test program for above.
+ */
+
+struct vit myvit; /* build an exploded vax instruction here */
+char answer[100]; /* human types a line of vax assembler here */
+char *mybug; /* "" or an internal logic diagnostic */
+int mycount; /* number of operands */
+struct vop *myvop; /* scan operands from myvit */
+int mysynth; /* 1 means want synthetic opcodes. */
+char my_immediate[200];
+char my_indirect[200];
+char my_displen[200];
+
+char *vip ();
+
+main ()
+{
+ char *p;
+ char *vip_begin ();
+
+ printf ("0 means no synthetic instructions. ");
+ printf ("Value for vip_begin? ");
+ gets (answer);
+ sscanf (answer, "%d", &mysynth);
+ printf ("Synthetic opcodes %s be included.\n", mysynth ? "will" : "will not");
+ printf ("enter immediate symbols eg enter # ");
+ gets (my_immediate);
+ printf ("enter indirect symbols eg enter @ ");
+ gets (my_indirect);
+ printf ("enter displen symbols eg enter ^ ");
+ gets (my_displen);
+ if (*(p = vip_begin (mysynth, my_immediate, my_indirect, my_displen))) {
+ error ("vip_begin=%s", p);
+ }
+ printf ("An empty input line will quit you from the vax instruction parser\n");
+ for (;;) {
+ printf ("vax instruction: ");
+ fflush (stdout);
+ gets (answer);
+ if (!*answer) {
+ break; /* out of for each input text loop */
+ }
+ mybug = vip (&myvit, answer);
+ if (*mybug) {
+ printf ("BUG:\"%s\"\n", mybug);
+ }
+ if (*myvit.vit_error) {
+ printf ("ERR:\"%s\"\n", myvit.vit_error);
+ }
+ printf ("opcode=");
+ for (mycount = myvit.vit_opcode_nbytes, p = myvit.vit_opcode;
+ mycount;
+ mycount--, p++
+ ) {
+ printf ("%02x ", *p & 0xFF);
+ }
+ printf (" operand count=%d.\n", mycount = myvit.vit_operands);
+ for (myvop = myvit.vit_operand; mycount; mycount--, myvop++) {
+ printf ("mode=%xx reg=%xx ndx=%xx len='%c'=%c%c%d. expr=\"",
+ myvop->vop_mode, myvop->vop_reg, myvop->vop_ndx,
+ myvop->vop_short, myvop->vop_access, myvop->vop_width,
+ myvop->vop_nbytes);
+ for (p = myvop->vop_expr_begin; p <= myvop->vop_expr_end; p++) {
+ putchar (*p);
+ }
+ printf ("\"\n");
+ if (*myvop->vop_error) {
+ printf (" err:\"%s\"\n", myvop->vop_error);
+ }
+ if (*myvop->vop_warn) {
+ printf (" wrn:\"%s\"\n", myvop->vop_warn);
+ }
+ }
+ }
+ vip_end ();
+ exit ();
+}
+
+#endif /* #ifdef test */
+
+/* end of vax_ins_parse.c */
+
+/* JF this used to be a separate file also */
+/* vax_reg_parse.c - convert a VAX register name to a number */
+
+/* Copyright (C) 1987 Free Software Foundation, Inc. A part of GNU. */
+
+/*
+ * v a x _ r e g _ p a r s e ( )
+ *
+ * Take 3 char.s, the last of which may be `\0` (non-existent)
+ * and return the VAX register number that they represent.
+ *
+ * Return -1 if they don't form a register name. Good names return
+ * a number from 0:15 inclusive.
+ *
+ * Case is not important in a name.
+ *
+ * Register names understood are:
+ *
+ * R0
+ * R1
+ * R2
+ * R3
+ * R4
+ * R5
+ * R6
+ * R7
+ * R8
+ * R9
+ * R10
+ * R11
+ * R12 AP
+ * R13 FP
+ * R14 SP
+ * R15 PC
+ *
+ */
+
+#include <ctype.h>
+#define AP (12)
+#define FP (13)
+#define SP (14)
+#define PC (15)
+
+int /* return -1 or 0:15 */
+ vax_reg_parse (c1, c2, c3) /* 3 chars of register name */
+char c1, c2, c3; /* c3 == 0 if 2-character reg name */
+{
+ register int retval; /* return -1:15 */
+
+ retval = -1;
+
+ if (isupper (c1))
+ c1 = tolower (c1);
+ if (isupper (c2))
+ c2 = tolower (c2);
+ if (isdigit (c2) && c1 == 'r') {
+ retval = c2 - '0';
+ if (isdigit (c3)) {
+ retval = retval * 10 + c3 - '0';
+ retval = (retval > 15) ? -1 : retval;
+ /* clamp the register value to 1 hex digit */
+ } else if (c3)
+ retval = -1; /* c3 must be '\0' or a digit */
+ } else if (c3) /* There are no three letter regs */
+ retval = -1;
+ else if (c2 == 'p') {
+ switch (c1) {
+ case 's':
+ retval = SP;
+ break;
+ case 'f':
+ retval = FP;
+ break;
+ case 'a':
+ retval = AP;
+ break;
+ default:
+ retval = -1;
+ }
+ } else if (c1 == 'p' && c2 == 'c')
+ retval = PC;
+ else
+ retval = -1;
+ return (retval);
+}
+
+/*
+ * v i p _ o p ( )
+ *
+ * Parse a vax operand in DEC assembler notation.
+ * For speed, expect a string of whitespace to be reduced to a single ' '.
+ * This is the case for GNU AS, and is easy for other DEC-compatible
+ * assemblers.
+ *
+ * Knowledge about DEC VAX assembler operand notation lives here.
+ * This doesn't even know what a register name is, except it believes
+ * all register names are 2 or 3 characters, and lets vax_reg_parse() say
+ * what number each name represents.
+ * It does, however, know that PC, SP etc are special registers so it can
+ * detect addressing modes that are silly for those registers.
+ *
+ * Where possible, it delivers 1 fatal or 1 warning message if the operand
+ * is suspect. Exactly what we test for is still evolving.
+ */
+
+/*
+ * B u g s
+ *
+ * Arg block.
+ *
+ * There were a number of 'mismatched argument type' bugs to vip_op.
+ * The most general solution is to typedef each (of many) arguments.
+ * We used instead a typedef'd argument block. This is less modular
+ * than using seperate return pointers for each result, but runs faster
+ * on most engines, and seems to keep programmers happy. It will have
+ * to be done properly if we ever want to use vip_op as a general-purpose
+ * module (it was designed to be).
+ *
+ * G^
+ *
+ * Doesn't support DEC "G^" format operands. These always take 5 bytes
+ * to express, and code as modes 8F or 9F. Reason: "G^" deprives you of
+ * optimising to (say) a "B^" if you are lucky in the way you link.
+ * When someone builds a linker smart enough to convert "G^" to "B^", "W^"
+ * whenever possible, then we should implement it.
+ * If there is some other use for "G^", feel free to code it in!
+ *
+ *
+ * speed
+ *
+ * If I nested if ()s more, I could avoid testing (*err) which would save
+ * time, space and page faults. I didn't nest all those if ()s for clarity
+ * and because I think the mode testing can be re-arranged 1st to test the
+ * commoner constructs 1st. Does anybody have statistics on this?
+ *
+ *
+ *
+ * error messages
+ *
+ * In future, we should be able to 'compose' error messages in a scratch area
+ * and give the user MUCH more informative error messages. Although this takes
+ * a little more code at run-time, it will make this module much more self-
+ * documenting. As an example of what sucks now: most error messages have
+ * hardwired into them the DEC VAX metacharacters "#^@" which are nothing like
+ * the Un*x characters "$`*", that most users will expect from this AS.
+ */
+
+/*
+ * The input is a string, ending with '\0'.
+ *
+ * We also require a 'hint' of what kind of operand is expected: so
+ * we can remind caller not to write into literals for instance.
+ *
+ * The output is a skeletal instruction.
+ *
+ * The algorithm has two parts.
+ * 1. extract the syntactic features (parse off all the @^#-()+[] mode crud);
+ * 2. express the @^#-()+[] as some parameters suited to further analysis.
+ *
+ * 2nd step is where we detect the googles of possible invalid combinations
+ * a human (or compiler) might write. Note that if we do a half-way
+ * decent assembler, we don't know how long to make (eg) displacement
+ * fields when we first meet them (because they may not have defined values).
+ * So we must wait until we know how many bits are needed for each address,
+ * then we can know both length and opcodes of instructions.
+ * For reason(s) above, we will pass to our caller a 'broken' instruction
+ * of these major components, from which our caller can generate instructions:
+ * - displacement length I^ S^ L^ B^ W^ unspecified
+ * - mode (many)
+ * - register R0-R15 or absent
+ * - index register R0-R15 or absent
+ * - expression text what we don't parse
+ * - error text(s) why we couldn't understand the operand
+ */
+
+/*
+ * To decode output of this, test errtxt. If errtxt[0] == '\0', then
+ * we had no errors that prevented parsing. Also, if we ever report
+ * an internal bug, errtxt[0] is set non-zero. So one test tells you
+ * if the other outputs are to be taken seriously.
+ */
+
+
+/* vax registers we need to know */
+/* JF #define SP (14) */
+/* JF for one big happy file #define PC (15) */
+
+/*
+ * Because this module is useful for both VMS and UN*X style assemblers
+ * and because of the variety of UN*X assemblers we must recognise
+ * the different conventions for assembler operand notation. For example
+ * VMS says "#42" for immediate mode, while most UN*X say "$42".
+ * We permit arbitrary sets of (single) characters to represent the
+ * 3 concepts that DEC writes '#', '@', '^'.
+ */
+
+/* character tests */
+#define VIP_IMMEDIATE 01 /* Character is like DEC # */
+#define VIP_INDIRECT 02 /* Char is like DEC @ */
+#define VIP_DISPLEN 04 /* Char is like DEC ^ */
+
+#define IMMEDIATEP(c) (vip_metacharacters[(c)&0xff]&VIP_IMMEDIATE)
+#define INDIRECTP(c) (vip_metacharacters[(c)&0xff]&VIP_INDIRECT)
+#define DISPLENP(c) (vip_metacharacters[(c)&0xff]&VIP_DISPLEN)
+
+/* We assume 8 bits per byte. Use vip_op_defaults() to set these up BEFORE we
+ * are ever called.
+ */
+
+#if defined(CONST_TABLE)
+#define _ 0,
+#define I VIP_IMMEDIATE,
+#define S VIP_INDIRECT,
+#define D VIP_DISPLEN,
+static const char
+ vip_metacharacters[256] = {
+ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _/* ^@ ^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 ^[ ^\ ^] ^^ ^_ */
+ _ _ _ _ I _ _ _ _ _ S _ _ _ _ _/* sp ! " # $ % & ' ( ) * + , - . / */
+ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _/*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 [ \ ] ^ _*/
+ D _ _ _ _ _ _ _ _ _ _ _ _ _ _ _/*` 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 { | } ~ ^?*/
+
+ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
+ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
+ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
+ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
+ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
+ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
+ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
+ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
+ };
+#undef _
+#undef I
+#undef S
+#undef D
+#else
+static char vip_metacharacters[256];
+
+/* Macro is faster under GCC; The constant table is faster yet, but only works with ASCII */
+#if 0
+static
+#ifdef __GNUC__
+ inline
+#endif
+ static void
+ vip_op_1(bit,syms)
+int bit;
+char *syms;
+{
+ unsigned char t;
+
+ while (t= *syms++)
+ vip_metacharacters[t]|=bit;
+}
+#else
+#define vip_op_1(bit,syms) { \
+ unsigned char t; \
+ char *table=vip_metacharacters; \
+ while (t= *syms++) \
+ table[t]|=bit; \
+ }
+#endif
+
+static void vip_op_defaults(immediate, indirect, displen) /* can be called any time */
+char *immediate; /* Strings of characters for each job. */
+char *indirect;
+char *displen; /* more arguments may appear in future! */
+{
+ vip_op_1 (VIP_IMMEDIATE, immediate);
+ vip_op_1 (VIP_INDIRECT, indirect);
+ vip_op_1 (VIP_DISPLEN, displen);
+
+ return;
+}
+#endif
+
+
+/*
+ * Dec defines the semantics of address modes (and values)
+ * by a two-letter code, explained here.
+ *
+ * letter 1: access type
+ *
+ * a address calculation - no data access, registers forbidden
+ * b branch displacement
+ * m read - let go of bus - write back "modify"
+ * r read
+ * v bit field address: like 'a' but registers are OK
+ * w write
+ * space no operator (eg ".long foo") [our convention]
+ *
+ * letter 2: data type (i.e. width, alignment)
+ *
+ * b byte
+ * d double precision floating point (D format)
+ * f single precision floating point (F format)
+ * g G format floating
+ * h H format floating
+ * l longword
+ * o octaword
+ * q quadword
+ * w word
+ * ? simple synthetic branch operand
+ * - unconditional synthetic JSB/JSR operand
+ * ! complex synthetic branch operand
+ *
+ * The '-?!' letter 2's are not for external consumption. They are used
+ * for various assemblers. Generally, all unknown widths are assumed 0.
+ * We don't limit your choice of width character.
+ *
+ * DEC operands are hard work to parse. For example, '@' as the first
+ * character means indirect (deferred) mode but elswhere it is a shift
+ * operator.
+ * The long-winded explanation of how this is supposed to work is
+ * cancelled. Read a DEC vax manual.
+ * We try hard not to parse anything that MIGHT be part of the expression
+ * buried in that syntax. For example if we see @...(Rn) we don't check
+ * for '-' before the '(' because mode @-(Rn) does not exist.
+ *
+ * After parsing we have:
+ *
+ * at 1 if leading '@' (or Un*x '*')
+ * len takes one value from " bilsw". eg B^ -> 'b'.
+ * hash 1 if leading '#' (or Un*x '$')
+ * expr_begin, expr_end the expression we did not parse
+ * even though we don't interpret it, we make use
+ * of its presence or absence.
+ * sign -1: -(Rn) 0: absent +1: (Rn)+
+ * paren 1 if () are around register
+ * reg major register number 0:15 -1 means absent
+ * ndx index register number 0:15 -1 means absent
+ *
+ * Again, I dare not explain it: just trace ALL the code!
+ */
+
+char * /* (code here) bug message, "" = OK */
+ /* our code bug, NOT bad assembly language */
+ vip_op (optext, vopP)
+char *optext; /* user's input string e.g.: */
+/* "@B^foo@bar(AP)[FP]:" */
+struct vop *vopP; /* In: vop_access, vop_width. */
+/* Out: _ndx, _reg, _mode, _short, _warn, */
+/* _error _expr_begin, _expr_end, _nbytes. */
+/* vop_nbytes : number of bytes in a datum. */
+{
+ char *p; /* track operand text forward */
+ char *q; /* track operand text backward */
+ int at; /* 1 if leading '@' ('*') seen */
+ char len; /* one of " bilsw" */
+ int hash; /* 1 if leading '#' ('$') seen */
+ int sign = 0; /* -1, 0 or +1 */
+ int paren = 0; /* 1 if () surround register */
+ int reg = 0; /* register number, -1:absent */
+ int ndx = 0; /* index register number -1:absent */
+ char *bug; /* report any logic error in here, "" == OK */
+ char *err; /* report illegal operand, "" == OK */
+ /* " " is a FAKE error: means we won */
+ /* ANY err that begins with ' ' is a fake. */
+ /* " " is converted to "" before return */
+ char *wrn; /* warn about weird modes pf address */
+ char *oldq = NULL; /* preserve q in case we backup */
+ int mode = 0; /* build up 4-bit operand mode here */
+ /* note: index mode is in ndx, this is */
+ /* the major mode of operand address */
+ /*
+ * Notice how we move wrong-arg-type bugs INSIDE this module: if we
+ * get the types wrong below, we lose at compile time rather than at
+ * lint or run time.
+ */
+ char access; /* vop_access. */
+ char width; /* vop_width. */
+
+ int vax_reg_parse (); /* returns 0:15 or -1 if not a register */
+
+ access = vopP->vop_access;
+ width = vopP->vop_width;
+ bug = /* none of our code bugs (yet) */
+ err = /* no user text errors */
+ wrn = ""; /* no warnings even */
+
+ p = optext;
+
+ if (*p == ' ') /* Expect all whitespace reduced to ' '. */
+ p++; /* skip over whitespace */
+
+ if (at = INDIRECTP (*p)) { /* 1 if *p == '@'(or '*' for Un*x) */
+ p++; /* at is determined */
+ if (*p == ' ') /* Expect all whitespace reduced to ' '. */
+ p++; /* skip over whitespace */
+ }
+
+ /*
+ * This code is subtle. It tries to detect all legal (letter)'^'
+ * but it doesn't waste time explicitly testing for premature '\0' because
+ * this case is rejected as a mismatch against either (letter) or '^'.
+ */
+ {
+ register char c;
+
+ c = *p;
+ if (isupper (c))
+ c = tolower (c);
+ if (DISPLENP (p[1]) && strchr ("bilws", len = c))
+ p += 2; /* skip (letter) '^' */
+ else /* no (letter) '^' seen */
+ len = ' '; /* len is determined */
+ }
+
+ if (*p == ' ') /* Expect all whitespace reduced to ' '. */
+ p++; /* skip over whitespace */
+
+ if (hash = IMMEDIATEP (*p)) /* 1 if *p == '#' ('$' for Un*x) */
+ p++; /* hash is determined */
+
+ /*
+ * p points to what may be the beginning of an expression.
+ * We have peeled off the front all that is peelable.
+ * We know at, len, hash.
+ *
+ * Lets point q at the end of the text and parse that (backwards).
+ */
+
+ for (q = p; *q; q++)
+ ;
+ q--; /* now q points at last char of text */
+
+ if (*q == ' ' && q >= p) /* Expect all whitespace reduced to ' '. */
+ q--;
+ /* reverse over whitespace, but don't */
+ /* run back over *p */
+
+ /*
+ * As a matter of policy here, we look for [Rn], although both Rn and S^#
+ * forbid [Rn]. This is because it is easy, and because only a sick
+ * cyborg would have [...] trailing an expression in a VAX-like assembler.
+ * A meticulous parser would first check for Rn followed by '(' or '['
+ * and not parse a trailing ']' if it found another. We just ban expressions
+ * ending in ']'.
+ */
+ if (*q == ']') {
+ while (q >= p && *q != '[')
+ q--;
+ /* either q<p or we got matching '[' */
+ if (q < p)
+ err = "no '[' to match ']'";
+ else {
+ /*
+ * Confusers like "[]" will eventually lose with a bad register
+ * name error. So again we don't need to check for early '\0'.
+ */
+ if (q[3] == ']')
+ ndx = vax_reg_parse (q[1], q[2], 0);
+ else if (q[4] == ']')
+ ndx = vax_reg_parse (q[1], q[2], q[3]);
+ else
+ ndx = -1;
+ /*
+ * Since we saw a ']' we will demand a register name in the [].
+ * If luser hasn't given us one: be rude.
+ */
+ if (ndx < 0)
+ err = "bad register in []";
+ else if (ndx == PC)
+ err = "[PC] index banned";
+ else
+ q--; /* point q just before "[...]" */
+ }
+ } else
+ ndx = -1; /* no ']', so no iNDeX register */
+
+ /*
+ * If err = "..." then we lost: run away.
+ * Otherwise ndx == -1 if there was no "[...]".
+ * Otherwise, ndx is index register number, and q points before "[...]".
+ */
+
+ if (*q == ' ' && q >= p) /* Expect all whitespace reduced to ' '. */
+ q--;
+ /* reverse over whitespace, but don't */
+ /* run back over *p */
+ if (!*err) {
+ sign = 0; /* no ()+ or -() seen yet */
+
+ if (q > p + 3 && *q == '+' && q[-1] == ')') {
+ sign = 1; /* we saw a ")+" */
+ q--; /* q points to ')' */
+ }
+
+ if (*q == ')' && q > p + 2) {
+ paren = 1; /* assume we have "(...)" */
+ while (q >= p && *q != '(')
+ q--;
+ /* either q<p or we got matching '(' */
+ if (q < p)
+ err = "no '(' to match ')'";
+ else {
+ /*
+ * Confusers like "()" will eventually lose with a bad register
+ * name error. So again we don't need to check for early '\0'.
+ */
+ if (q[3] == ')')
+ reg = vax_reg_parse (q[1], q[2], 0);
+ else if (q[4] == ')')
+ reg = vax_reg_parse (q[1], q[2], q[3]);
+ else
+ reg = -1;
+ /*
+ * Since we saw a ')' we will demand a register name in the ')'.
+ * This is nasty: why can't our hypothetical assembler permit
+ * parenthesised expressions? BECAUSE I AM LAZY! That is why.
+ * Abuse luser if we didn't spy a register name.
+ */
+ if (reg < 0) {
+ /* JF allow parenthasized expressions. I hope this works */
+ paren = 0;
+ while (*q != ')')
+ q++;
+ /* err = "unknown register in ()"; */
+ } else
+ q--; /* point just before '(' of "(...)" */
+ /*
+ * If err == "..." then we lost. Run away.
+ * Otherwise if reg >= 0 then we saw (Rn).
+ */
+ }
+ /*
+ * If err == "..." then we lost.
+ * Otherwise paren == 1 and reg = register in "()".
+ */
+ } else
+ paren = 0;
+ /*
+ * If err == "..." then we lost.
+ * Otherwise, q points just before "(Rn)", if any.
+ * If there was a "(...)" then paren == 1, and reg is the register.
+ */
+
+ /*
+ * We should only seek '-' of "-(...)" if:
+ * we saw "(...)" paren == 1
+ * we have no errors so far ! *err
+ * we did not see '+' of "(...)+" sign < 1
+ * We don't check len. We want a specific error message later if
+ * user tries "x^...-(Rn)". This is a feature not a bug.
+ */
+ if (!*err) {
+ if (paren && sign < 1)/* !sign is adequate test */ {
+ if (*q == '-') {
+ sign = -1;
+ q--;
+ }
+ }
+ /*
+ * We have back-tracked over most
+ * of the crud at the end of an operand.
+ * Unless err, we know: sign, paren. If paren, we know reg.
+ * The last case is of an expression "Rn".
+ * This is worth hunting for if !err, !paren.
+ * We wouldn't be here if err.
+ * We remember to save q, in case we didn't want "Rn" anyway.
+ */
+ if (!paren) {
+ if (*q == ' ' && q >= p) /* Expect all whitespace reduced to ' '. */
+ q--;
+ /* reverse over whitespace, but don't */
+ /* run back over *p */
+ if (q > p && q < p + 3) /* room for Rn or Rnn exactly? */
+ reg = vax_reg_parse (p[0], p[1], q < p + 2 ? 0 : p[2]);
+ else
+ reg = -1; /* always comes here if no register at all */
+ /*
+ * Here with a definitive reg value.
+ */
+ if (reg >= 0) {
+ oldq = q;
+ q = p - 1;
+ }
+ }
+ }
+ }
+ /*
+ * have reg. -1:absent; else 0:15
+ */
+
+ /*
+ * We have: err, at, len, hash, ndx, sign, paren, reg.
+ * Also, any remaining expression is from *p through *q inclusive.
+ * Should there be no expression, q == p-1. So expression length = q-p+1.
+ * This completes the first part: parsing the operand text.
+ */
+
+ /*
+ * We now want to boil the data down, checking consistency on the way.
+ * We want: len, mode, reg, ndx, err, p, q, wrn, bug.
+ * We will deliver a 4-bit reg, and a 4-bit mode.
+ */
+
+ /*
+ * Case of branch operand. Different. No L^B^W^I^S^ allowed for instance.
+ *
+ * in: at ?
+ * len ?
+ * hash ?
+ * p:q ?
+ * sign ?
+ * paren ?
+ * reg ?
+ * ndx ?
+ *
+ * out: mode 0
+ * reg -1
+ * len ' '
+ * p:q whatever was input
+ * ndx -1
+ * err " " or error message, and other outputs trashed
+ */
+ /* branch operands have restricted forms */
+ if (!*err && access == 'b') {
+ if (at || hash || sign || paren || ndx >= 0 || reg >= 0 || len != ' ')
+ err = "invalid branch operand";
+ else
+ err = " ";
+ }
+
+ /* Since nobody seems to use it: comment this 'feature'(?) out for now. */
+#ifdef NEVER
+ /*
+ * Case of stand-alone operand. e.g. ".long foo"
+ *
+ * in: at ?
+ * len ?
+ * hash ?
+ * p:q ?
+ * sign ?
+ * paren ?
+ * reg ?
+ * ndx ?
+ *
+ * out: mode 0
+ * reg -1
+ * len ' '
+ * p:q whatever was input
+ * ndx -1
+ * err " " or error message, and other outputs trashed
+ */
+ if (!*err) {
+ if (access == ' ') { /* addresses have restricted forms */
+ if (at)
+ err = "address prohibits @";
+ else {
+ if (hash)
+ err = "address prohibits #";
+ else {
+ if (sign) {
+ if (sign < 0)
+ err = "address prohibits -()";
+ else
+ err = "address prohibits ()+";
+ } else {
+ if (paren)
+ err = "address prohibits ()";
+ else {
+ if (ndx >= 0)
+ err = "address prohibits []";
+ else {
+ if (reg >= 0)
+ err = "address prohibits register";
+ else {
+ if (len != ' ')
+ err = "address prohibits displacement length specifier";
+ else {
+ err = " "; /* succeed */
+ mode = 0;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+#endif /*#Ifdef NEVER*/
+
+ /*
+ * Case of S^#.
+ *
+ * in: at 0
+ * len 's' definition
+ * hash 1 demand
+ * p:q demand not empty
+ * sign 0 by paren == 0
+ * paren 0 by "()" scan logic because "S^" seen
+ * reg -1 or nn by mistake
+ * ndx -1
+ *
+ * out: mode 0
+ * reg -1
+ * len 's'
+ * exp
+ * ndx -1
+ */
+ if (!*err && len == 's') {
+ if (!hash || paren || at || ndx >= 0)
+ err = "invalid operand of S^#";
+ else {
+ if (reg >= 0) {
+ /*
+ * SHIT! we saw S^#Rnn ! put the Rnn back in
+ * expression. KLUDGE! Use oldq so we don't
+ * need to know exact length of reg name.
+ */
+ q = oldq;
+ reg = 0;
+ }
+ /*
+ * We have all the expression we will ever get.
+ */
+ if (p > q)
+ err = "S^# needs expression";
+ else if (access == 'r') {
+ err = " "; /* WIN! */
+ mode = 0;
+ } else
+ err = "S^# may only read-access";
+ }
+ }
+
+ /*
+ * Case of -(Rn), which is weird case.
+ *
+ * in: at 0
+ * len '
+ * hash 0
+ * p:q q<p
+ * sign -1 by definition
+ * paren 1 by definition
+ * reg present by definition
+ * ndx optional
+ *
+ * out: mode 7
+ * reg present
+ * len ' '
+ * exp "" enforce empty expression
+ * ndx optional warn if same as reg
+ */
+ if (!*err && sign < 0) {
+ if (len != ' ' || hash || at || p <= q)
+ err = "invalid operand of -()";
+ else {
+ err = " "; /* win */
+ mode = 7;
+ if (reg == PC)
+ wrn = "-(PC) unpredictable";
+ else if (reg == ndx)
+ wrn = "[]index same as -()register: unpredictable";
+ }
+ }
+
+ /*
+ * We convert "(Rn)" to "@Rn" for our convenience.
+ * (I hope this is convenient: has someone got a better way to parse this?)
+ * A side-effect of this is that "@Rn" is a valid operand.
+ */
+ if (paren && !sign && !hash && !at && len == ' ' && p > q) {
+ at = 1;
+ paren = 0;
+ }
+
+ /*
+ * Case of (Rn)+, which is slightly different.
+ *
+ * in: at
+ * len ' '
+ * hash 0
+ * p:q q<p
+ * sign +1 by definition
+ * paren 1 by definition
+ * reg present by definition
+ * ndx optional
+ *
+ * out: mode 8+@
+ * reg present
+ * len ' '
+ * exp "" enforce empty expression
+ * ndx optional warn if same as reg
+ */
+ if (!*err && sign > 0) {
+ if (len != ' ' || hash || p <= q)
+ err = "invalid operand of ()+";
+ else {
+ err = " "; /* win */
+ mode = 8 + (at ? 1 : 0);
+ if (reg == PC)
+ wrn = "(PC)+ unpredictable";
+ else if (reg == ndx)
+ wrn = "[]index same as ()+register: unpredictable";
+ }
+ }
+
+ /*
+ * Case of #, without S^.
+ *
+ * in: at
+ * len ' ' or 'i'
+ * hash 1 by definition
+ * p:q
+ * sign 0
+ * paren 0
+ * reg absent
+ * ndx optional
+ *
+ * out: mode 8+@
+ * reg PC
+ * len ' ' or 'i'
+ * exp
+ * ndx optional
+ */
+ if (!*err && hash) {
+ if (len != 'i' && len != ' ')
+ err = "# conflicts length";
+ else if (paren)
+ err = "# bars register";
+ else {
+ if (reg >= 0) {
+ /*
+ * SHIT! we saw #Rnn! Put the Rnn back into the expression.
+ * By using oldq, we don't need to know how long Rnn was.
+ * KLUDGE!
+ */
+ q = oldq;
+ reg = -1; /* no register any more */
+ }
+ err = " "; /* win */
+
+ /* JF a bugfix, I think! */
+ if (at && access == 'a')
+ vopP->vop_nbytes=4;
+
+ mode = (at ? 9 : 8);
+ reg = PC;
+ if ((access == 'm' || access == 'w') && !at)
+ wrn = "writing or modifying # is unpredictable";
+ }
+ }
+ /*
+ * If !*err, then sign == 0
+ * hash == 0
+ */
+
+ /*
+ * Case of Rn. We seperate this one because it has a few special
+ * errors the remaining modes lack.
+ *
+ * in: at optional
+ * len ' '
+ * hash 0 by program logic
+ * p:q empty
+ * sign 0 by program logic
+ * paren 0 by definition
+ * reg present by definition
+ * ndx optional
+ *
+ * out: mode 5+@
+ * reg present
+ * len ' ' enforce no length
+ * exp "" enforce empty expression
+ * ndx optional warn if same as reg
+ */
+ if (!*err && !paren && reg >= 0) {
+ if (len != ' ')
+ err = "length not needed";
+ else if (at) {
+ err = " "; /* win */
+ mode = 6; /* @Rn */
+ } else if (ndx >= 0)
+ err = "can't []index a register, because it has no address";
+ else if (access == 'a')
+ err = "a register has no address";
+ else {
+ /*
+ * Idea here is to detect from length of datum
+ * and from register number if we will touch PC.
+ * Warn if we do.
+ * vop_nbytes is number of bytes in operand.
+ * Compute highest byte affected, compare to PC0.
+ */
+ if ((vopP->vop_nbytes + reg * 4) > 60)
+ wrn = "PC part of operand unpredictable";
+ err = " "; /* win */
+ mode = 5; /* Rn */
+ }
+ }
+ /*
+ * If !*err, sign == 0
+ * hash == 0
+ * paren == 1 OR reg == -1
+ */
+
+ /*
+ * Rest of cases fit into one bunch.
+ *
+ * in: at optional
+ * len ' ' or 'b' or 'w' or 'l'
+ * hash 0 by program logic
+ * p:q expected (empty is not an error)
+ * sign 0 by program logic
+ * paren optional
+ * reg optional
+ * ndx optional
+ *
+ * out: mode 10 + @ + len
+ * reg optional
+ * len ' ' or 'b' or 'w' or 'l'
+ * exp maybe empty
+ * ndx optional warn if same as reg
+ */
+ if (!*err) {
+ err = " "; /* win (always) */
+ mode = 10 + (at ? 1 : 0);
+ switch (len) {
+ case 'l':
+ mode += 2;
+ case 'w':
+ mode += 2;
+ case ' ': /* assumed B^ until our caller changes it */
+ case 'b':
+ break;
+ }
+ }
+
+ /*
+ * here with completely specified mode
+ * len
+ * reg
+ * expression p,q
+ * ndx
+ */
+
+ if (*err == ' ')
+ err = ""; /* " " is no longer an error */
+
+ vopP->vop_mode = mode;
+ vopP->vop_reg = reg;
+ vopP->vop_short = len;
+ vopP->vop_expr_begin = p;
+ vopP->vop_expr_end = q;
+ vopP->vop_ndx = ndx;
+ vopP->vop_error = err;
+ vopP->vop_warn = wrn;
+ return (bug);
+
+} /* vip_op() */
+
+/*
+
+ Summary of vip_op outputs.
+
+ mode reg len ndx
+ (Rn) => @Rn
+ {@}Rn 5+@ n ' ' optional
+ branch operand 0 -1 ' ' -1
+ S^#foo 0 -1 's' -1
+ -(Rn) 7 n ' ' optional
+ {@}(Rn)+ 8+@ n ' ' optional
+ {@}#foo, no S^ 8+@ PC " i" optional
+ {@}{q^}{(Rn)} 10+@+q option " bwl" optional
+
+ */
+
+#ifdef TEST /* #Define to use this testbed. */
+
+/*
+ * Follows a test program for this function.
+ * We declare arrays non-local in case some of our tiny-minded machines
+ * default to small stacks. Also, helps with some debuggers.
+ */
+
+#include <stdio.h>
+
+char answer[100]; /* human types into here */
+char *p; /* */
+char *myerr;
+char *mywrn;
+char *mybug;
+char myaccess;
+char mywidth;
+char mymode;
+char myreg;
+char mylen;
+char *myleft;
+char *myright;
+char myndx;
+int my_operand_length;
+char my_immediate[200];
+char my_indirect[200];
+char my_displen[200];
+
+main ()
+{
+ char *vip_op (); /* make cc happy */
+
+ printf ("enter immediate symbols eg enter # ");
+ gets (my_immediate);
+ printf ("enter indirect symbols eg enter @ ");
+ gets (my_indirect);
+ printf ("enter displen symbols eg enter ^ ");
+ gets (my_displen);
+ vip_op_defaults (my_immediate, my_indirect, my_displen);
+ for (;;) {
+ printf ("access,width (eg 'ab' or 'wh') [empty line to quit] : ");
+ fflush (stdout);
+ gets (answer);
+ if (!answer[0])
+ exit (0);
+ myaccess = answer[0];
+ mywidth = answer[1];
+ switch (mywidth) {
+ case 'b':
+ my_operand_length = 1;
+ break;
+ case 'd':
+ my_operand_length = 8;
+ break;
+ case 'f':
+ my_operand_length = 4;
+ break;
+ case 'g':
+ my_operand_length = 16;
+ break;
+ case 'h':
+ my_operand_length = 32;
+ break;
+ case 'l':
+ my_operand_length = 4;
+ break;
+ case 'o':
+ my_operand_length = 16;
+ break;
+ case 'q':
+ my_operand_length = 8;
+ break;
+ case 'w':
+ my_operand_length = 2;
+ break;
+ case '!':
+ case '?':
+ case '-':
+ my_operand_length = 0;
+ break;
+
+ default:
+ my_operand_length = 2;
+ printf ("I dn't understand access width %c\n", mywidth);
+ break;
+ }
+ printf ("VAX assembler instruction operand: ");
+ fflush (stdout);
+ gets (answer);
+ mybug = vip_op (answer, myaccess, mywidth, my_operand_length,
+ &mymode, &myreg, &mylen, &myleft, &myright, &myndx,
+ &myerr, &mywrn);
+ if (*myerr) {
+ printf ("error: \"%s\"\n", myerr);
+ if (*mybug)
+ printf (" bug: \"%s\"\n", mybug);
+ } else {
+ if (*mywrn)
+ printf ("warning: \"%s\"\n", mywrn);
+ mumble ("mode", mymode);
+ mumble ("register", myreg);
+ mumble ("index", myndx);
+ printf ("width:'%c' ", mylen);
+ printf ("expression: \"");
+ while (myleft <= myright)
+ putchar (*myleft++);
+ printf ("\"\n");
+ }
+ }
+}
+
+mumble (text, value)
+char *text;
+int value;
+{
+ printf ("%s:", text);
+ if (value >= 0)
+ printf ("%xx", value);
+ else
+ printf ("ABSENT");
+ printf (" ");
+}
+
+#endif /* ifdef TEST */
+
+/* end: vip_op.c */
+
+const int md_short_jump_size = 3;
+const int md_long_jump_size = 6;
+const int md_reloc_size = 8; /* Size of relocation record */
+
+void
+ md_create_short_jump (ptr, from_addr, to_addr, frag, to_symbol)
+char *ptr;
+long from_addr, to_addr;
+fragS *frag;
+symbolS *to_symbol;
+{
+ long offset;
+
+ offset = to_addr - (from_addr + 1);
+ *ptr++ = 0x31;
+ md_number_to_chars(ptr, offset, 2);
+}
+
+void
+ md_create_long_jump (ptr, from_addr, to_addr, frag, to_symbol)
+char *ptr;
+long from_addr, to_addr;
+fragS *frag;
+symbolS *to_symbol;
+{
+ long offset;
+
+ offset = to_addr - S_GET_VALUE(to_symbol);
+ *ptr++ = 0x17;
+ *ptr++ = 0x9F;
+ md_number_to_chars(ptr, offset, 4);
+ fix_new(frag, ptr - frag->fr_literal, 4, to_symbol, (symbolS *) 0, (long) 0, 0, NO_RELOC);
+}
+
+#ifdef OBJ_VMS
+extern char vms_name_mapping;
+#endif
+
+int
+ md_parse_option (argP, cntP, vecP)
+char **argP;
+int *cntP;
+char ***vecP;
+{
+ char *temp_name; /* name for -t or -d options */
+ char opt;
+
+ switch (**argP) {
+ case 'J':
+ /* as_warn ("I can do better than -J!"); */
+ break;
+
+ case 'S':
+ as_warn ("SYMBOL TABLE not implemented");
+ break; /* SYMBOL TABLE not implemented */
+
+ case 'T':
+ as_warn ("TOKEN TRACE not implemented");
+ break; /* TOKEN TRACE not implemented */
+
+ case 'd':
+ case 't':
+ opt= **argP;
+ if (**argP) { /* Rest of argument is filename. */
+ temp_name = *argP;
+ while (**argP)
+ (*argP)++;
+ } else if (*cntP) {
+ while (**argP)
+ (*argP)++;
+ --(*cntP);
+ temp_name = *++(*vecP);
+ **vecP = NULL; /* Remember this is not a file-name. */
+ } else {
+ as_warn ("I expected a filename after -%c.",opt);
+ temp_name = "{absent}";
+ }
+
+ if (opt == 'd')
+ as_warn ("Displacement length %s ignored!", temp_name);
+ else
+ as_warn ("I don't need or use temp. file \"%s\".", temp_name);
+ break;
+
+ case 'V':
+ as_warn ("I don't use an interpass file! -V ignored");
+ break;
+
+#ifdef OBJ_VMS
+ case '+': /* For g++ */
+ break;
+
+ case '1': /* For backward compatibility */
+ break;
+
+ case 'h': /* No hashing of mixed-case names */
+ vms_name_mapping = 0;
+ (*argP)++;
+ if (**argP) vms_name_mapping = *((*argP)++) - '0';
+ (*argP)--;
+ break;
+
+ case 'H': /* Show new symbol after hash truncation */
+ break;
+#endif
+
+ default:
+ return 0;
+
+ }
+ return 1;
+}
+
+/* We have no need to default values of symbols. */
+
+/* ARGSUSED */
+symbolS *
+ md_undefined_symbol (name)
+char *name;
+{
+ return 0;
+}
+
+/* Parse an operand that is machine-specific.
+ We just return without modifying the expression if we have nothing
+ to do. */
+
+/* ARGSUSED */
+void
+ md_operand (expressionP)
+expressionS *expressionP;
+{
+}
+
+/* Round up a section size to the appropriate boundary. */
+long
+ md_section_align (segment, size)
+segT segment;
+long size;
+{
+ return size; /* Byte alignment is fine */
+}
+
+/* Exactly what point is a PC-relative offset relative TO?
+ On the vax, they're relative to the address of the offset, plus
+ its size. (??? Is this right? FIXME-SOON) */
+long
+ md_pcrel_from (fixP)
+fixS *fixP;
+{
+ return fixP->fx_size + fixP->fx_where + fixP->fx_frag->fr_address;
+}
+
+/* end of tc-vax.c */
diff --git a/gnu/usr.bin/as/config/tc-vax.h b/gnu/usr.bin/as/config/tc-vax.h
new file mode 100644
index 0000000..d3972e1
--- /dev/null
+++ b/gnu/usr.bin/as/config/tc-vax.h
@@ -0,0 +1,25 @@
+/*
+ * This file is tc-vax.h.
+ */
+
+#define TC_VAX 1
+
+#define NO_LISTING
+
+ /* use this to compare against gas-1.38 */
+#ifdef OLD_GAS
+#define REVERSE_SORT_RELOCS
+#endif
+
+#define tc_aout_pre_write_hook(x) {;} /* not used */
+#define tc_crawl_symbol_chain(a) {;} /* not used */
+#define tc_headers_hook(a) {;} /* not used */
+
+/*
+ * Local Variables:
+ * comment-column: 0
+ * fill-column: 131
+ * End:
+ */
+
+/* end of tc-vax.h */
diff --git a/gnu/usr.bin/as/config/te-dpx2.h b/gnu/usr.bin/as/config/te-dpx2.h
new file mode 100644
index 0000000..5f358a2
--- /dev/null
+++ b/gnu/usr.bin/as/config/te-dpx2.h
@@ -0,0 +1,8 @@
+/* Machine specific defines for the dpx2 machine */
+#define dpx2
+#define TC_M68K
+
+/* The magic number is not the usual MC68MAGIC. */
+#define FILE_HEADER_MAGIC MC68KBCSMAGIC
+
+/* end of te-dpx2.h */
diff --git a/gnu/usr.bin/as/config/te-generic.h b/gnu/usr.bin/as/config/te-generic.h
new file mode 100644
index 0000000..f72d5ee
--- /dev/null
+++ b/gnu/usr.bin/as/config/te-generic.h
@@ -0,0 +1,25 @@
+/*
+ * This file is te-generic.h and is intended to be a template for
+ * target environment specific header files.
+ *
+ * It is my intent that this file will evolve into a file suitable for config,
+ * compile, and copying as an aid for testing and porting. xoxorich.
+ */
+/*
+ * $Id: te-generic.h,v 1.1 1993/10/02 20:59:49 pk Exp $
+ */
+
+
+#define TE_GENERIC 1
+
+/* these define interfaces */
+#include "obj-format.h"
+
+/*
+ * Local Variables:
+ * comment-column: 0
+ * fill-column: 131
+ * End:
+ */
+
+/* end of te-generic.h */
diff --git a/gnu/usr.bin/as/config/te-hpux.h b/gnu/usr.bin/as/config/te-hpux.h
new file mode 100644
index 0000000..5458df6
--- /dev/null
+++ b/gnu/usr.bin/as/config/te-hpux.h
@@ -0,0 +1,99 @@
+/* Special version of <a.out.h> for use under hp-ux.
+ Copyright (C) 1988, 1992 Free Software Foundation, Inc.
+
+ This file is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This file is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this file; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#define TE_HPUX
+
+#define HP9000S200_ID (0x20C)
+#define DEFAULT_MAGIC_NUMBER_FOR_OBJECT_FILE (HP9000S200_ID)
+
+ /* hpux has "special" headers. */
+#define H_GET_HEADER_SIZE(h) (64)
+
+#include "obj-format.h"
+
+/* This stuff is from an old a.out.hpux.h. It isn't used anymore,
+ (see obj-aout.c, obj_header_append) but I'm including it here for
+ context. xoxorich. */
+
+#if comment
+
+/* The `exec' structure and overall layout must be close to HP's when
+ we are running on an HP system, otherwise we will not be able to
+ execute the resulting file. */
+
+/* Allow this file to be included twice. */
+#ifndef __GNU_EXEC_MACROS__
+
+struct exec
+{
+ unsigned short a_machtype; /* machine type */
+ unsigned short a_info; /* magic number */
+ unsigned long a_spare1;
+ unsigned long a_spare2;
+ unsigned long a_text; /* length of text, in bytes */
+ unsigned long a_data; /* length of data, in bytes */
+ unsigned long a_bss; /* length of uninitialized data area for file, in bytes */
+ unsigned long a_trsize; /* length of relocation info for text, in bytes */
+ unsigned long a_drsize; /* length of relocation info for data, in bytes */
+ unsigned long a_spare3; /* HP = pascal interface size */
+ unsigned long a_spare4; /* HP = symbol table size */
+ unsigned long a_spare5; /* HP = debug name table size */
+ unsigned long a_entry; /* start address */
+ unsigned long a_spare6; /* HP = source line table size */
+ unsigned long a_spare7; /* HP = value table size */
+ unsigned long a_syms; /* length of symbol table data in file, in bytes */
+ unsigned long a_spare8;
+};
+
+/* Tell a.out.gnu.h not to define `struct exec'. */
+#define __STRUCT_EXEC_OVERRIDE__
+
+#include "a.out.gnu.h"
+
+#undef N_MAGIC
+#undef N_MACHTYPE
+#undef N_FLAGS
+#undef N_SET_INFO
+#undef N_SET_MAGIC
+#undef N_SET_MACHTYPE
+#undef N_SET_FLAGS
+
+#define N_MAGIC(exec) ((exec) . a_magic)
+#define N_MACHTYPE(exec) ((exec) . a_machtype)
+#define N_SET_MAGIC(exec, magic) (((exec) . a_magic) = (magic))
+#define N_SET_MACHTYPE(exec, machtype) (((exec) . a_machtype) = (machtype))
+
+#undef N_BADMAG
+#define N_BADMAG(x) ((_N_BADMAG (x)) || (_N_BADMACH (x)))
+
+#define _N_BADMACH(x) \
+(((N_MACHTYPE (x)) != HP9000S200_ID) && \
+ ((N_MACHTYPE (x)) != HP98x6_ID))
+
+#define HP98x6_ID 0x20A
+#define HP9000S200_ID 0x20C
+
+#undef _N_HDROFF
+#define _N_HDROFF(x) (SEGMENT_SIZE - (sizeof (struct exec)))
+
+#define SEGMENT_SIZE 0x1000
+
+#endif /* __GNU_EXEC_MACROS__ */
+
+#endif /* comment */
+
+/* end of te-hpux.h */
diff --git a/gnu/usr.bin/as/config/te-i386aix.h b/gnu/usr.bin/as/config/te-i386aix.h
new file mode 100644
index 0000000..dcadbc3
--- /dev/null
+++ b/gnu/usr.bin/as/config/te-i386aix.h
@@ -0,0 +1,19 @@
+/*
+ * This file is te-i386aix.h and is built from pieces of code from Minh Tran-Le
+ * <TRANLE@INTELLICORP.COM> by rich@cygnus.com.
+ */
+
+#define TE_I386AIX 1
+
+#include "obj-format.h"
+
+#define KEEP_RELOC_INFO
+
+/*
+ * Local Variables:
+ * comment-column: 0
+ * fill-column: 79
+ * End:
+ */
+
+/* end of te-i386aix.h */
diff --git a/gnu/usr.bin/as/config/te-ic960.h b/gnu/usr.bin/as/config/te-ic960.h
new file mode 100644
index 0000000..7a9dbe7
--- /dev/null
+++ b/gnu/usr.bin/as/config/te-ic960.h
@@ -0,0 +1,46 @@
+/* This file is twe-ic960.h
+
+ Copyright (C) 1987-1992 Free Software Foundation, Inc.
+
+ This file is part of GAS, the GNU Assembler.
+
+ GAS is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GAS is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GAS; see the file COPYING. If not, write to
+ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/*
+ * This file is te-ic960.h and is intended to define ic960 environment
+ * specific differences.
+ */
+
+#define TE_IC960 1
+
+/* intel uses host byte order for headers */
+#ifdef CROSS_COMPILE
+#undef CROSS_COMPILE
+#endif /* CROSS_COMPILE */
+
+#define OBJ_COFF_OMIT_OPTIONAL_HEADER
+#define LOCAL_LABEL(name) ( (name[0] == 'L') \
+ || (name[0] == '.' \
+ && (name[1] == 'C' || name[1] == 'I' || name[1] == '.')))
+#include "obj-format.h"
+
+/*
+ * Local Variables:
+ * comment-column: 0
+ * fill-column: 131
+ * End:
+ */
+
+/* end of te-ic960.h */
diff --git a/gnu/usr.bin/as/config/te-sco386.h b/gnu/usr.bin/as/config/te-sco386.h
new file mode 100644
index 0000000..da8de1d
--- /dev/null
+++ b/gnu/usr.bin/as/config/te-sco386.h
@@ -0,0 +1,7 @@
+/* Machine specific defines for the SCO Unix V.3.2 ODT */
+#define scounix
+
+/* Return true if s (a non null string pointer), points to a local variable name. */
+#define LOCAL_LABEL(n) ((n)[0] == '.' && (n)[1] == 'L')
+
+/* end of te-sco386.h */
diff --git a/gnu/usr.bin/as/config/te-sequent.h b/gnu/usr.bin/as/config/te-sequent.h
new file mode 100644
index 0000000..fbf9d9a
--- /dev/null
+++ b/gnu/usr.bin/as/config/te-sequent.h
@@ -0,0 +1,32 @@
+/*
+ * This file is te-sequent.h and is intended to set up emulation with
+ * sequent's development tools.
+ *
+ */
+
+#define TE_SEQUENT 1
+
+ /* sequent has a "special" header. */
+#define H_GET_HEADER_SIZE(h) (128)
+
+#ifdef TC_I386
+ /* zmagic is 0x22eb */
+#define DEFAULT_MAGIC_NUMBER_FOR_OBJECT_FILE (0x12eb)
+#endif /* TC_I386 */
+
+#ifdef TC_NS32K
+ /* zmagic is 0x10ea */
+#define DEFAULT_MAGIC_NUMBER_FOR_OBJECT_FILE (0x00ea)
+#endif /* TC_NS32K */
+
+/* these define interfaces */
+#include "obj-format.h"
+
+/*
+ * Local Variables:
+ * comment-column: 0
+ * fill-column: 131
+ * End:
+ */
+
+/* end of te-sequent.h */
diff --git a/gnu/usr.bin/as/config/te-sun3.h b/gnu/usr.bin/as/config/te-sun3.h
new file mode 100644
index 0000000..ec4d29a
--- /dev/null
+++ b/gnu/usr.bin/as/config/te-sun3.h
@@ -0,0 +1,49 @@
+/* te-sun3.h -- Sun-3 target environment declarations.
+ Copyright (C) 1987, 1990, 1991, 1992 Free Software Foundation, Inc.
+
+ This file is part of GAS, the GNU Assembler.
+
+ GAS is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GAS is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GAS; see the file COPYING. If not, write to
+ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* This header file contains the #defines specific
+ to SUN computer SUN 3 series computers. (The only kind
+ we have around here, unfortunatly.)
+
+ Rumor has it that this file will work on the Sun-2 if the assembler
+ is called with -m68010 This is not tested. */
+
+
+/* Could also be :
+ #define S_LOCAL_NAME(s) (S_GET_NAME(s)[0] == '.' &&
+ S_GET_NAME(s)[1] == 'L' ||
+ S_GET_NAME(s)[1] == '.')
+ */
+
+/* This variable contains the value to write out at the beginning of
+ the a.out file. The 2<<16 means that this is a 68020 file instead
+ of an old-style 68000 file */
+
+#define DEFAULT_MAGIC_NUMBER_FOR_OBJECT_FILE (2<<16|OMAGIC) /* Magic byte for file header */
+
+#include "obj-format.h"
+
+/*
+ * Local Variables:
+ * comment-column: 0
+ * fill-column: 131
+ * End:
+ */
+
+/* end of te-sun3.h */
diff --git a/gnu/usr.bin/as/config/te-sysv32.h b/gnu/usr.bin/as/config/te-sysv32.h
new file mode 100644
index 0000000..99702fb
--- /dev/null
+++ b/gnu/usr.bin/as/config/te-sysv32.h
@@ -0,0 +1,4 @@
+/* Remove leading underscore from the gcc generated symbol names */
+#define STRIP_UNDERSCORE
+
+/* end of te-sysv32.h */
diff --git a/gnu/usr.bin/as/config/vax-inst.h b/gnu/usr.bin/as/config/vax-inst.h
new file mode 100644
index 0000000..47c5ef0
--- /dev/null
+++ b/gnu/usr.bin/as/config/vax-inst.h
@@ -0,0 +1,77 @@
+/* vax-inst.h - GNU - Part of vax.c
+ Copyright (C) 1987, 1992 Free Software Foundation, Inc.
+
+ This file is part of GAS, the GNU Assembler.
+
+ GAS is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GAS is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GAS; see the file COPYING. If not, write to
+ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/*
+ * This is part of vax-ins-parse.c & friends.
+ * We want to parse a vax instruction text into a tree defined here.
+ */
+
+#define VIT_MAX_OPERANDS (6) /* maximum number of operands in one */
+/* single vax instruction */
+
+struct vop /* vax instruction operand */
+{
+ short int vop_ndx; /* -1, or index register. eg 7=[R7] */
+ short int vop_reg; /* -1, or register number. eg @I^#=0xF */
+ /* Helps distinguish "abs" from "abs(PC)". */
+ short int vop_mode; /* addressing mode 4 bits. eg I^#=0x9 */
+ char vop_short; /* operand displacement length as written */
+ /* ' '=none, "bilsw"=B^I^L^S^W^. */
+ char vop_access; /* 'b'branch ' 'no-instruction 'amrvw'norm */
+ char vop_width; /* Operand width, one of "bdfghloqw" */
+ char *vop_warn; /* warning message of this operand, if any */
+ char *vop_error; /* say if operand is inappropriate */
+ char *vop_expr_begin; /* Unparsed expression, 1st char ... */
+ char *vop_expr_end; /* ... last char. */
+ unsigned char vop_nbytes; /* number of bytes in datum */
+};
+
+
+typedef long vax_opcodeT; /* For initialising array of opcodes */
+/* Some synthetic opcodes > 16 bits! */
+
+#define VIT_OPCODE_SYNTHETIC 0x80000000 /* Not real hardware instruction. */
+#define VIT_OPCODE_SPECIAL 0x40000000 /* Not normal branch optimising. */
+/* Never set without ..._SYNTHETIC */
+
+#define VAX_WIDTH_UNCONDITIONAL_JUMP '-' /* These are encoded into */
+#define VAX_WIDTH_CONDITIONAL_JUMP '?' /* vop_width when vop_access == 'b' */
+#define VAX_WIDTH_WORD_JUMP '!' /* and VIT_OPCODE_SYNTHETIC set. */
+#define VAX_WIDTH_BYTE_JUMP ':' /* */
+
+#define VAX_JMP (0x17) /* Useful for branch optimising. Jump instr*/
+#define VAX_PC_RELATIVE_MODE (0xef) /* Use it after VAX_JMP */
+#define VAX_ABSOLUTE_MODE (0x9F) /* Use as @#... */
+#define VAX_BRB (0x11) /* Canonical branch. */
+#define VAX_BRW (0x31) /* Another canonical branch */
+#define VAX_WIDEN_WORD (0x20) /* Add this to byte branch to get word br. */
+#define VAX_WIDEN_LONG (0x6) /* Add this to byte branch to get long jmp.*/
+/* Needs VAX_PC_RELATIVE_MODE byte after it*/
+
+struct vit /* vax instruction tree */
+{
+ /* vit_opcode is char[] for portability. */
+ char vit_opcode[ sizeof (vax_opcodeT) ];
+ unsigned char vit_opcode_nbytes; /* How long is _opcode? (chars) */
+ unsigned char vit_operands;/* */
+ struct vop vit_operand[VIT_MAX_OPERANDS]; /* operands */
+ char * vit_error; /* "" or error text */
+};
+
+/* end of vax-inst.h */
diff --git a/gnu/usr.bin/as/configdos.bat b/gnu/usr.bin/as/configdos.bat
new file mode 100644
index 0000000..18331cd
--- /dev/null
+++ b/gnu/usr.bin/as/configdos.bat
@@ -0,0 +1,14 @@
+@echo off
+echo Configuring GAS for H8/300
+
+copy config\ho-go32.h host.h
+copy config\tc-h8300.c targ-cpu.c
+copy config\tc-h8300.h targ-cpu.h
+copy config\te-generic.h targ-env.h
+copy config\objcoff-bfd.h obj-format.h
+copy config\objcoff-bfd.c obj-format.c
+copy config\atof-ieee.c atof-targ.c
+
+copy Makefile.dos Makefile
+
+
diff --git a/gnu/usr.bin/as/configure.in b/gnu/usr.bin/as/configure.in
new file mode 100755
index 0000000..52f4b29
--- /dev/null
+++ b/gnu/usr.bin/as/configure.in
@@ -0,0 +1,204 @@
+# This file is configure.in
+#
+# Copyright (C) 1987-1992 Free Software Foundation, Inc.
+#
+# This file is part of GAS, the GNU Assembler.
+#
+# GAS is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# GAS is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GAS; see the file COPYING. If not, write to
+# the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+#
+
+# This file is a shell script that supplies the information necessary
+# to tailor a template configure script into the configure script
+# appropriate for this directory. For more information, check any
+# existing configure script.
+
+srctrigger=as.c
+srcname="gas"
+need_bfd=
+configdirs=doc
+
+# per-host:
+
+gas_host=generic
+
+case "${host_cpu}" in
+a29k | rs6000 | vax)
+ case "${host_os}" in
+ vms*) gas_host=vms ;;
+ *) gas_host=${host_cpu} ;;
+ esac
+ ;;
+mips)
+ case "${host_os}" in
+ ultrix) gas_host=decstation ;;
+ esac
+ ;;
+i386)
+ case "${host_os}" in
+ aix*) gas_host=i386aix ;;
+ sysv4*)
+ gas_host=i386
+ host_makefile_frag=config/ho-i386v4
+ ;;
+ esac
+ ;;
+*)
+ case "${host_os}" in
+ ansi | ultrix | hpux | sysv*) gas_host=${host_os} ;;
+ *)
+ case "${host_vendor}" in
+ sun)
+ case "${host_cpu}" in
+ m68k) gas_host=sun3 ;;
+ i386) gas_host=sun386 ;;
+ sparc) gas_host=sun4 ;;
+ esac
+ ;;
+ esac
+ ;;
+ esac
+ ;;
+esac
+
+# per-target:
+
+# assign cpu type
+environment=generic
+
+cpu_type=${target_cpu}
+
+# assign object format
+case ${target_os} in
+aix*)
+ case "${target_cpu}" in
+ i386) obj_format=coff
+ target_cpu=i386aix
+ environment=i386aix
+ ;;
+ esac
+ ;;
+
+bout*) obj_format=bout ;;
+nindy*) obj_format=bout ;;
+bsd* | sunos*)
+ obj_format=aout
+ case "${target_cpu}" in
+ m68k) environment=sun3 ;;
+ i386 | ns32k)
+ case "${target_vendor}" in
+ sequent) environment=${target_vendor} ;;
+ esac
+ esac
+ ;;
+
+ebmon-old)
+ obj_format=coff
+ need_bfd="$(unsubdir)/../bfd$(subdir)/libbfd.a"
+ target_cpu=ebmon29k
+ ;;
+
+ebmon)
+ obj_format=coffbfd
+ need_bfd="$(unsubdir)/../bfd$(subdir)/libbfd.a"
+ target_cpu=ebmon29k
+ ;;
+
+generic) obj_format=generic ;;
+
+hms)
+ obj_format=coffbfd
+ need_bfd="$(unsubdir)/../bfd$(subdir)/libbfd.a"
+ ;;
+
+hpux)
+ obj_format=aout
+ environment=hpux
+ ;;
+
+sysv32)
+ obj_format=coff
+ environment=sysv32
+ ;;
+
+vms)
+ obj_format=vms
+ ;;
+
+coff* | sysv*)
+ obj_format=coff
+
+ case ${target_vendor} in
+ bull) environment=dpx2 ;;
+ sco) environment=sco386 ;;
+ sun) environment=sun3 ;;
+ *)
+ esac
+ ;;
+vxworks)
+ case ${target_cpu} in
+ i960) obj_format=bout ;;
+ *) obj_format=aout ;;
+ esac
+ ;;
+*)
+ case ${target_vendor} in
+ aout) obj_format=aout ;;
+ bout) obj_format=bout ;;
+ coff)
+ obj_format=coff
+ case ${target_cpu} in
+ i960) environment=ic960 ;;
+ esac
+ ;;
+ sequent)
+ obj_format=aout
+ environment=sequent
+ ;;
+ *) obj_format=aout ;;
+ esac
+ ;;
+
+esac
+
+# assign floating point type
+case ${target_cpu} in
+ns32k) atof=ns32k ;;
+tahoe) atof=tahoe ;;
+vax) atof=vax ;;
+*) atof=ieee ;;
+esac
+
+# and target makefile frag
+
+target_makefile_frag=config/mt-${target_cpu}
+
+files="config/ho-${gas_host}.h config/tc-${cpu_type}.c \
+ config/tc-${cpu_type}.h config/te-${environment}.h \
+ config/obj-${obj_format}.h config/obj-${obj_format}.c \
+ config/atof-${atof}.c"
+
+links="host.h targ-cpu.c targ-cpu.h targ-env.h obj-format.h obj-format.c atof-targ.c"
+
+# post-target:
+
+if [ ${target_alias} != ${host_alias} ] ; then
+ echo INTERNAL_CFLAGS=-DCROSS_COMPILE > Makefile.tem
+ cat Makefile >> Makefile.tem
+ mv Makefile.tem Makefile
+else
+ true
+fi
+
+# end of gas/configure.in
diff --git a/gnu/usr.bin/as/debug.c b/gnu/usr.bin/as/debug.c
new file mode 100644
index 0000000..d0a0c2d
--- /dev/null
+++ b/gnu/usr.bin/as/debug.c
@@ -0,0 +1,104 @@
+/* This file is debug.c
+
+ Copyright (C) 1987-1992 Free Software Foundation, Inc.
+
+ This file is part of GAS, the GNU Assembler.
+
+ GAS is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GAS is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GAS; see the file COPYING. If not, write to
+ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* Routines for debug use only. */
+
+#ifndef lint
+static char rcsid[] = "$Id: debug.c,v 1.1 1993/11/03 00:51:26 paul Exp $";
+#endif
+
+#include "as.h"
+#include "subsegs.h"
+
+dmp_frags()
+{
+ frchainS *chp;
+ char *p;
+
+ for ( chp=frchain_root; chp; chp = chp->frch_next ){
+ switch ( chp->frch_seg ){
+ case SEG_DATA:
+ p ="Data";
+ break;
+ case SEG_TEXT:
+ p ="Text";
+ break;
+ default:
+ p ="???";
+ break;
+ }
+ printf("\nSEGMENT %s %d\n", p, chp->frch_subseg);
+ dmp_frag( chp->frch_root,"\t");
+ }
+}
+
+dmp_frag( fp, indent )
+ struct frag *fp;
+ char *indent;
+{
+ for ( ; fp; fp = fp->fr_next ){
+ printf("%sFRAGMENT @ 0x%x\n", indent, fp);
+ switch( fp->fr_type ){
+ case rs_align:
+ printf("%srs_align(%d)\n",indent, fp->fr_offset);
+ break;
+ case rs_fill:
+ printf("%srs_fill(%d)\n",indent, fp->fr_offset);
+ printf("%s", indent);
+ var_chars( fp, fp->fr_var + fp->fr_fix );
+ printf("%s\t repeated %d times,",
+ indent, fp->fr_offset);
+ printf(" fixed length if # chars == 0)\n");
+ break;
+ case rs_org:
+ printf("%srs_org(%d+sym @0x%x)\n",indent,
+ fp->fr_offset, fp->fr_symbol);
+ printf("%sfill with ",indent);
+ var_chars( fp, 1 );
+ printf("\n");
+ break;
+ case rs_machine_dependent:
+ printf("%smachine_dep\n",indent);
+ break;
+ default:
+ printf("%sunknown type\n",indent);
+ break;
+ }
+ printf("%saddr=%d(0x%x)\n",indent,fp->fr_address,fp->fr_address);
+ printf("%sfr_fix=%d\n",indent,fp->fr_fix);
+ printf("%sfr_var=%d\n",indent,fp->fr_var);
+ printf("%sfr_offset=%d\n",indent,fp->fr_offset);
+ printf("%schars @ 0x%x\n",indent,fp->fr_literal);
+ printf("\n");
+ }
+}
+
+var_chars( fp, n )
+ struct frag *fp;
+ int n;
+{
+ unsigned char *p;
+
+ for ( p=(unsigned char*)fp->fr_literal; n; n-- , p++ ){
+ printf("%02x ", *p );
+ }
+}
+
+/* end of debug.c */
diff --git a/gnu/usr.bin/as/doc/Makefile b/gnu/usr.bin/as/doc/Makefile
new file mode 100644
index 0000000..77a0cf2
--- /dev/null
+++ b/gnu/usr.bin/as/doc/Makefile
@@ -0,0 +1,3 @@
+INFO = as-all
+
+.include <bsd.info.mk>
diff --git a/gnu/usr.bin/as/doc/as-all.texinfo b/gnu/usr.bin/as/doc/as-all.texinfo
new file mode 100644
index 0000000..99076ae
--- /dev/null
+++ b/gnu/usr.bin/as/doc/as-all.texinfo
@@ -0,0 +1,4995 @@
+
+
+\input texinfo @c -*-Texinfo-*-
+@c Copyright (c) 1991 1992 Free Software Foundation, Inc.
+@c %**start of header
+@setfilename as.info
+@settitle Using as
+@setchapternewpage odd
+@c @smallbook
+@c @cropmarks
+@c %**end of header
+
+@finalout
+@syncodeindex ky cp
+
+@c
+@ifinfo
+This file documents the GNU Assembler "as".
+
+Copyright (C) 1991 Free Software Foundation, Inc.
+
+Permission is granted to make and distribute verbatim copies of
+this manual provided the copyright notice and this permission notice
+are preserved on all copies.
+
+@ignore
+Permission is granted to process this file through Tex and print the
+results, provided the printed document carries copying permission
+notice identical to this one except for the removal of this paragraph
+(this paragraph not being relevant to the printed manual).
+
+@end ignore
+Permission is granted to copy and distribute modified versions of this
+manual under the conditions for verbatim copying, provided also that the
+section entitled ``GNU General Public License'' is included exactly as
+in the original, and provided that the entire resulting derived work is
+distributed under the terms of a permission notice identical to this
+one.
+
+Permission is granted to copy and distribute translations of this manual
+into another language, under the above conditions for modified versions,
+except that the section entitled ``GNU General Public License'' may be
+included in a translation approved by the Free Software Foundation
+instead of in the original English.
+@end ifinfo
+
+@titlepage
+@title Using as
+@subtitle The GNU Assembler
+@sp 1
+@subtitle January 1992
+@sp 1
+@sp 13
+The Free Software Foundation Inc. thanks The Nice Computer
+Company of Australia for loaning Dean Elsner to write the
+first (Vax) version of @code{as} for Project GNU.
+The proprietors, management and staff of TNCCA thank FSF for
+distracting the boss while they got some work
+done.
+@sp 3
+@author Dean Elsner, Jay Fenlason & friends
+@c edited by: pesch@cygnus.com
+@page
+@tex
+\def\$#1${{#1}} % Kluge: collect RCS revision info without $...$
+\xdef\manvers{\$Revision: 1.1 $} % For use in headers, footers too
+{\parskip=0pt
+\hfill \manvers\par
+\hfill \TeX{}info \texinfoversion\par
+}
+%"boxit" macro for figures:
+%Modified from Knuth's ``boxit'' macro from TeXbook (answer to exercise 21.3)
+\gdef\boxit#1#2{\vbox{\hrule\hbox{\vrule\kern3pt
+ \vbox{\parindent=0pt\parskip=0pt\hsize=#1\kern3pt\strut\hfil
+#2\hfil\strut\kern3pt}\kern3pt\vrule}\hrule}}%box with visible outline
+\gdef\ibox#1#2{\hbox to #1{#2\hfil}\kern8pt}% invisible box
+@end tex
+
+Edited by Roland Pesch for Cygnus Support.
+
+@vskip 0pt plus 1filll
+Copyright @copyright{} 1991 Free Software Foundation, Inc.
+
+Permission is granted to make and distribute verbatim copies of
+this manual provided the copyright notice and this permission notice
+are preserved on all copies.
+
+Permission is granted to copy and distribute modified versions of this
+manual under the conditions for verbatim copying, provided also that the
+section entitled ``GNU General Public License'' is included exactly as
+in the original, and provided that the entire resulting derived work is
+distributed under the terms of a permission notice identical to this
+one.
+
+Permission is granted to copy and distribute translations of this manual
+into another language, under the above conditions for modified versions,
+except that the section entitled ``GNU General Public License'' may be
+included in a translation approved by the Free Software Foundation
+instead of in the original English.
+@end titlepage
+@page
+@node Top, Overview, (dir), (dir)
+@ifinfo
+This file is a user guide to the GNU assembler @code{as}.
+@end ifinfo
+@menu
+* Overview:: Overview
+* Invoking:: Command-Line Options
+* Syntax:: Syntax
+* Sections:: Sections and Relocation
+* Symbols:: Symbols
+* Expressions:: Expressions
+* Pseudo Ops:: Assembler Directives
+* Machine Dependent:: Machine Dependent Features
+* Copying:: GNU GENERAL PUBLIC LICENSE
+* Index:: Index
+@end menu
+
+@node Overview, Invoking, Top, Top
+@chapter Overview
+@iftex
+This manual is a user guide to the GNU assembler @code{as}.
+@end iftex
+
+@cindex invocation summary
+@cindex option summary
+@cindex summary of options
+Here is a brief summary of how to invoke @code{as}. For details,
+@pxref{Invoking,,Comand-Line Options}.
+
+@c We don't use deffn and friends for the following because they seem
+@c to be limited to one line for the header.
+@smallexample
+ as [ -a | -al | -as ] [ -D ] [ -f ]
+ [ -I @var{path} ] [ -k ] [ -L ]
+ [ -o @var{objfile} ] [ -R ] [ -v ] [ -w ]
+@c am29k has no machine-dependent assembler options
+@c h8/300 has no machine-dependent assembler options
+@c see md_parse_option in i960.c
+ [ -ACA | -ACA_A | -ACB | -ACC | -AKA | -AKB | -AKC | -AMC ]
+ [ -b ] [ -norelax ]
+ [ -l ] [ -mc68000 | -mc68010 | -mc68020 ]
+ [ -- | @var{files} @dots{} ]
+@end smallexample
+
+@table @code
+@item -a | -al | -as
+Turn on assembly listings; @samp{-al}, listing only, @samp{-as}, symbols
+only, @samp{-a}, everything.
+
+@item -D
+This option is accepted only for script compatibility with calls to
+other assemblers; it has no effect on @code{as}.
+
+@item -f
+``fast''---skip preprocessing (assume source is compiler output)
+
+@item -I @var{path}
+Add @var{path} to the search list for @code{.include} directives
+
+@item -k
+Issue warnings when difference tables altered for long displacements.
+
+@item -L
+Keep (in symbol table) local symbols, starting with @samp{L}
+
+@item -o @var{objfile}
+Name the object-file output from @code{as}
+
+@item -R
+Fold data section into text section
+
+@item -v
+Announce @code{as} version
+
+@item -W
+Suppress warning messages
+
+@item -ACA | -ACA_A | -ACB | -ACC | -AKA | -AKB | -AKC | -AMC
+(When configured for Intel 960).
+Specify which variant of the 960 architecture is the target.
+
+@item -b
+(When configured for Intel 960).
+Add code to collect statistics about branches taken.
+
+@item -norelax
+(When configured for Intel 960).
+Do not alter compare-and-branch instructions for long displacements;
+error if necessary.
+
+@item -l
+(When configured for Motorola 68000).
+Shorten references to undefined symbols, to one word instead of two
+
+@item -mc68000 | -mc68010 | -mc68020
+(When configured for Motorola 68000).
+Specify what processor in the 68000 family is the target (default 68020)
+
+@item -- | @var{files} @dots{}
+Standard input, or source files to assemble
+@end table
+
+@menu
+* Manual:: Structure of this Manual
+* GNU Assembler:: as, the GNU Assembler
+* Object Formats:: Object File Formats
+* Command Line:: Command Line
+* Input Files:: Input Files
+* Object:: Output (Object) File
+* Errors:: Error and Warning Messages
+@end menu
+
+@node Manual, GNU Assembler, Overview, Overview
+@section Structure of this Manual
+
+@cindex manual, structure and purpose
+This manual is intended to describe what you need to know to use
+@sc{gnu} @code{as}. We cover the syntax expected in source files, including
+notation for symbols, constants, and expressions; the directives that
+@code{as} understands; and of course how to invoke @code{as}.
+
+This manual also describes some of the machine-dependent features of
+various flavors of the assembler.
+@refill
+
+@cindex machine instructions (not covered)
+On the other hand, this manual is @emph{not} intended as an introduction
+to programming in assembly language---let alone programming in general!
+In a similar vein, we make no attempt to introduce the machine
+architecture; we do @emph{not} describe the instruction set, standard
+mnemonics, registers or addressing modes that are standard to a
+particular architecture.
+You may want to consult the manufacturer's
+machine architecture manual for this information.
+
+
+@c I think this is premature---pesch@cygnus.com, 17jan1991
+@ignore
+Throughout this manual, we assume that you are running @dfn{GNU},
+the portable operating system from the @dfn{Free Software
+Foundation, Inc.}. This restricts our attention to certain kinds of
+computer (in particular, the kinds of computers that GNU can run on);
+once this assumption is granted examples and definitions need less
+qualification.
+
+@code{as} is part of a team of programs that turn a high-level
+human-readable series of instructions into a low-level
+computer-readable series of instructions. Different versions of
+@code{as} are used for different kinds of computer.
+@end ignore
+
+@c There used to be a section "Terminology" here, which defined
+@c "contents", "byte", "word", and "long". Defining "word" to any
+@c particular size is confusing when the .word directive may generate 16
+@c bits on one machine and 32 bits on another; in general, for the user
+@c version of this manual, none of these terms seem essential to define.
+@c They were used very little even in the former draft of the manual;
+@c this draft makes an effort to avoid them (except in names of
+@c directives).
+
+@node GNU Assembler, Object Formats, Manual, Overview
+@section as, the GNU Assembler
+
+GNU @code{as} is really a family of assemblers.
+If you use (or have used) the GNU assembler on one architecture, you
+should find a fairly similar environment when you use it on another
+architecture. Each version has much in common with the others,
+including object file formats, most assembler directives (often called
+@dfn{pseudo-ops)} and assembler syntax.@refill
+
+@cindex purpose of @sc{gnu} @code{as}
+@code{as} is primarily intended to assemble the output of the GNU C
+compiler @code{gcc} for use by the linker @code{ld}. Nevertheless,
+we've tried to make @code{as} assemble correctly everything that the native
+assembler would.
+Any exceptions are documented explicitly (@pxref{Machine Dependent}).
+This doesn't mean @code{as} always uses the same syntax as another
+assembler for the same architecture; for example, we know of several
+incompatible versions of 680x0 assembly language syntax.
+
+Unlike older assemblers, @code{as} is designed to assemble a source
+program in one pass of the source file. This has a subtle impact on the
+@kbd{.org} directive (@pxref{Org,,@code{.org}}).
+
+@node Object Formats, Command Line, GNU Assembler, Overview
+@section Object File Formats
+
+@cindex object file format
+The GNU assembler can be configured to produce several alternative
+object file formats. For the most part, this does not affect how you
+write assembly language programs; but directives for debugging symbols
+are typically different in different file formats. @xref{Symbol
+Attributes,,Symbol Attributes}.
+
+@node Command Line, Input Files, Object Formats, Overview
+@section Command Line
+
+@cindex command line conventions
+After the program name @code{as}, the command line may contain
+options and file names. Options may appear in any order, and may be
+before, after, or between file names. The order of file names is
+significant.
+
+@cindex standard input, as input file
+@kindex --
+@file{--} (two hyphens) by itself names the standard input file
+explicitly, as one of the files for @code{as} to assemble.
+
+@cindex options, command line
+Except for @samp{--} any command line argument that begins with a
+hyphen (@samp{-}) is an option. Each option changes the behavior of
+@code{as}. No option changes the way another option works. An
+option is a @samp{-} followed by one or more letters; the case of
+the letter is important. All options are optional.
+
+Some options expect exactly one file name to follow them. The file
+name may either immediately follow the option's letter (compatible
+with older assemblers) or it may be the next command argument (GNU
+standard). These two command lines are equivalent:
+
+@smallexample
+as -o my-object-file.o mumble.s
+as -omy-object-file.o mumble.s
+@end smallexample
+
+@node Input Files, Object, Command Line, Overview
+@section Input Files
+
+@cindex input
+@cindex source program
+@cindex files, input
+We use the phrase @dfn{source program}, abbreviated @dfn{source}, to
+describe the program input to one run of @code{as}. The program may
+be in one or more files; how the source is partitioned into files
+doesn't change the meaning of the source.
+
+@c I added "con" prefix to "catenation" just to prove I can overcome my
+@c APL training... pesch@cygnus.com
+The source program is a concatenation of the text in all the files, in the
+order specified.
+
+Each time you run @code{as} it assembles exactly one source
+program. The source program is made up of one or more files.
+(The standard input is also a file.)
+
+You give @code{as} a command line that has zero or more input file
+names. The input files are read (from left file name to right). A
+command line argument (in any position) that has no special meaning
+is taken to be an input file name.
+
+If you give @code{as} no file names it attempts to read one input file
+from the @code{as} standard input, which is normally your terminal. You
+may have to type @key{ctl-D} to tell @code{as} there is no more program
+to assemble.
+
+Use @samp{--} if you need to explicitly name the standard input file
+in your command line.
+
+If the source is empty, @code{as} will produce a small, empty object
+file.
+
+@subheading Filenames and Line-numbers
+
+@cindex input file linenumbers
+@cindex line numbers, in input files
+There are two ways of locating a line in the input file (or files) and
+either may be used in reporting error messages. One way refers to a line
+number in a physical file; the other refers to a line number in a
+``logical'' file. @xref{Errors, ,Error and Warning Messages}.
+
+@dfn{Physical files} are those files named in the command line given
+to @code{as}.
+
+@dfn{Logical files} are simply names declared explicitly by assembler
+directives; they bear no relation to physical files. Logical file names
+help error messages reflect the original source file, when @code{as}
+source is itself synthesized from other files.
+@xref{App-File,,@code{.app-file}}.
+
+@node Object, Errors, Input Files, Overview
+@section Output (Object) File
+
+@cindex object file
+@cindex output file
+@kindex a.out
+@kindex .o
+Every time you run @code{as} it produces an output file, which is
+your assembly language program translated into numbers. This file
+is the object file, named @code{a.out} unless you tell @code{as} to
+give it another name by using the @code{-o} option. Conventionally,
+object file names end with @file{.o}. The default name of
+@file{a.out} is used for historical reasons: older assemblers were
+capable of assembling self-contained programs directly into a
+runnable program.
+@c This may still work, but hasn't been tested.
+
+@cindex linker
+@kindex ld
+The object file is meant for input to the linker @code{ld}. It contains
+assembled program code, information to help @code{ld} integrate
+the assembled program into a runnable file, and (optionally) symbolic
+information for the debugger.
+
+@c link above to some info file(s) like the description of a.out.
+@c don't forget to describe GNU info as well as Unix lossage.
+
+@node Errors, , Object, Overview
+@section Error and Warning Messages
+
+@cindex error messsages
+@cindex warning messages
+@cindex messages from @code{as}
+@code{as} may write warnings and error messages to the standard error
+file (usually your terminal). This should not happen when a compiler
+runs @code{as} automatically. Warnings report an assumption made so
+that @code{as} could keep assembling a flawed program; errors report a
+grave problem that stops the assembly.
+
+@cindex format of warning messages
+Warning messages have the format
+
+@smallexample
+file_name:@b{NNN}:Warning Message Text
+@end smallexample
+
+@noindent
+@cindex line numbers, in warnings/errors
+(where @b{NNN} is a line number). If a logical file name has
+been given (@pxref{App-File,,@code{.app-file}}) it is used for the filename, otherwise the
+name of the current input file is used. If a logical line number was
+given
+(@pxref{Ln,,@code{.ln}})
+then it is used to calculate the number printed,
+otherwise the actual line in the current source file is printed. The
+message text is intended to be self explanatory (in the grand Unix
+tradition). @refill
+
+@cindex format of error messages
+Error messages have the format
+@smallexample
+file_name:@b{NNN}:FATAL:Error Message Text
+@end smallexample
+The file name and line number are derived as for warning
+messages. The actual message text may be rather less explanatory
+because many of them aren't supposed to happen.
+
+@node Invoking, Syntax, Overview, Top
+@chapter Command-Line Options
+
+@cindex options, all versions of @code{as}
+This chapter describes command-line options available in @emph{all}
+versions of the GNU assembler; @pxref{Machine Dependent}, for options specific
+to particular machine architectures.
+
+@section Enable Listings: @code{-a}, @code{-al}, @code{-as}
+
+@kindex -a
+@kindex -al
+@kindex -as
+@cindex listings, enabling
+@cindex assembly listings, enabling
+These options enable listing output from the assembler. @samp{-a} by
+itself requests all listing output; @samp{-al} requests only the
+output-program listing, and @samp{-as} requests only a symbol table
+listing.
+
+Once you have specified one of these options, you can further control
+listing output and its appearance using the directives @code{.list},
+@code{.nolist}, @code{.psize}, @code{.eject}, @code{.title}, and
+@code{.sbttl}.
+
+If you do not request listing output with one of the @samp{-a} options, the
+listing-control directives have no effect.
+
+@section @code{-D}
+
+@kindex -D
+This option has no effect whatsoever, but it is accepted to make it more
+likely that scripts written for other assemblers will also work with
+@code{as}.
+
+@section Work Faster: @code{-f}
+
+@kindex -f
+@cindex trusted compiler
+@cindex faster processing (@code{-f})
+@samp{-f} should only be used when assembling programs written by a
+(trusted) compiler. @samp{-f} stops the assembler from pre-processing
+the input file(s) before assembling them. @xref{Pre-processing,
+,Pre-processing}.
+
+@quotation
+@emph{Warning:} if the files actually need to be pre-processed (if they
+contain comments, for example), @code{as} will not work correctly if
+@samp{-f} is used.
+@end quotation
+
+@section @code{.include} search path: @code{-I} @var{path}
+
+@kindex -I @var{path}
+@cindex paths for @code{.include}
+@cindex search path for @code{.include}
+@cindex @code{include} directive search path
+Use this option to add a @var{path} to the list of directories
+@code{as} will search for files specified in @code{.include}
+directives (@pxref{Include,,@code{.include}}). You may use @code{-I} as
+many times as necessary to include a variety of paths. The current
+working directory is always searched first; after that, @code{as}
+searches any @samp{-I} directories in the same order as they were
+specified (left to right) on the command line.
+
+@section Difference Tables: @code{-k}
+
+@kindex -k
+
+@cindex difference tables, warning
+@cindex warning for altered difference tables
+@code{as} sometimes alters the code emitted for directives of the form
+@samp{.word @var{sym1}-@var{sym2}}; @pxref{Word,,@code{.word}}.
+You can use the @samp{-k} option if you want a warning issued when this
+is done.
+
+@section Include Local Labels: @code{-L}
+
+@kindex -L
+@cindex local labels, retaining in output
+Labels beginning with @samp{L} (upper case only) are called @dfn{local
+labels}. @xref{Symbol Names}. Normally you don't see such labels when
+debugging, because they are intended for the use of programs (like
+compilers) that compose assembler programs, not for your notice.
+Normally both @code{as} and @code{ld} discard such labels, so you don't
+normally debug with them.
+
+This option tells @code{as} to retain those @samp{L@dots{}} symbols
+in the object file. Usually if you do this you also tell the linker
+@code{ld} to preserve symbols whose names begin with @samp{L}.
+
+@section Name the Object File: @code{-o}
+
+@kindex -o
+@cindex naming object file
+@cindex object file name
+There is always one object file output when you run @code{as}. By
+default it has the name @file{a.out}. You use this option (which
+takes exactly one filename) to give the object file a different name.
+
+Whatever the object file is called, @code{as} will overwrite any
+existing file of the same name.
+
+@section Join Data and Text Sections: @code{-R}
+
+@kindex -R
+@cindex data and text sections, joining
+@cindex text and data sections, joining
+@cindex joining text and data sections
+@cindex merging text and data sections
+@code{-R} tells @code{as} to write the object file as if all
+data-section data lives in the text section. This is only done at
+the very last moment: your binary data are the same, but data
+section parts are relocated differently. The data section part of
+your object file is zero bytes long because all it bytes are
+appended to the text section. (@xref{Sections,,Sections and Relocation}.)
+
+When you specify @code{-R} it would be possible to generate shorter
+address displacements (because we don't have to cross between text and
+data section). We refrain from doing this simply for compatibility with
+older versions of @code{as}. In future, @code{-R} may work this way.
+
+When @code{as} is configured for COFF output,
+this option is only useful if you use sections named @samp{.text} and
+@samp{.data}.
+
+@section Announce Version: @code{-v}
+
+@kindex -v
+@kindex -version
+@cindex @code{as} version
+@cindex version of @code{as}
+You can find out what version of as is running by including the
+option @samp{-v} (which you can also spell as @samp{-version}) on the
+command line.
+
+@section Suppress Warnings: @code{-W}
+
+@kindex -W
+@cindex suppressing warnings
+@cindex warnings, suppressing
+@code{as} should never give a warning or error message when
+assembling compiler output. But programs written by people often
+cause @code{as} to give a warning that a particular assumption was
+made. All such warnings are directed to the standard error file.
+If you use this option, no warnings are issued. This option only
+affects the warning messages: it does not change any particular of how
+@code{as} assembles your file. Errors, which stop the assembly, are
+still reported.
+
+@node Syntax, Sections, Invoking, Top
+@chapter Syntax
+
+@cindex machine-independent syntax
+@cindex syntax, machine-independent
+This chapter describes the machine-independent syntax allowed in a
+source file. @code{as} syntax is similar to what many other assemblers
+use; it is inspired in BSD 4.2
+assembler, except that @code{as} does not assemble Vax bit-fields.
+
+@menu
+* Pre-processing:: Pre-processing
+* Whitespace:: Whitespace
+* Comments:: Comments
+* Symbol Intro:: Symbols
+* Statements:: Statements
+* Constants:: Constants
+@end menu
+
+@node Pre-processing, Whitespace, Syntax, Syntax
+@section Pre-Processing
+
+@cindex preprocessing
+The pre-processor:
+@itemize @bullet
+@cindex whitespace, removed by preprocessor
+@item
+adjusts and removes extra whitespace. It leaves one space or tab before
+the keywords on a line, and turns any other whitespace on the line into
+a single space.
+
+@cindex comments, removed by preprocessor
+@item
+removes all comments, replacing them with a single space, or an
+appropriate number of newlines.
+
+@cindex constants, converted by preprocessor
+@item
+converts character constants into the appropriate numeric values.
+@end itemize
+
+Excess whitespace, comments, and character constants
+cannot be used in the portions of the input text that are not
+pre-processed.
+
+@cindex turning preprocessing on and off
+@cindex preprocessing, turning on and off
+@kindex #NO_APP
+@kindex #APP
+If the first line of an input file is @code{#NO_APP} or the @samp{-f}
+option is given, the input file will not be pre-processed. Within such
+an input file, parts of the file can be pre-processed by putting a line
+that says @code{#APP} before the text that should be pre-processed, and
+putting a line that says @code{#NO_APP} after them. This feature is
+mainly intend to support @code{asm} statements in compilers whose output
+normally does not need to be pre-processed.
+
+@node Whitespace, Comments, Pre-processing, Syntax
+@section Whitespace
+
+@cindex whitespace
+@dfn{Whitespace} is one or more blanks or tabs, in any order.
+Whitespace is used to separate symbols, and to make programs neater for
+people to read. Unless within character constants
+(@pxref{Characters,,Character Constants}), any whitespace means the same
+as exactly one space.
+
+@node Comments, Symbol Intro, Whitespace, Syntax
+@section Comments
+
+@cindex comments
+There are two ways of rendering comments to @code{as}. In both
+cases the comment is equivalent to one space.
+
+Anything from @samp{/*} through the next @samp{*/} is a comment.
+This means you may not nest these comments.
+
+@smallexample
+/*
+ The only way to include a newline ('\n') in a comment
+ is to use this sort of comment.
+*/
+
+/* This sort of comment does not nest. */
+@end smallexample
+
+@cindex line comment character
+Anything from the @dfn{line comment} character to the next newline
+is considered a comment and is ignored. The line comment character is
+@samp{#} on the Vax;
+@samp{#} on the i960;
+@samp{|} on the 680x0;
+@samp{;} for the AMD 29K family;
+@samp{;} for the machine specific family;
+@pxref{Machine Dependent}. @refill
+@c FIXME: fill in SPARC line comment char
+
+On some machines there are two different line comment characters. One
+will only begin a comment if it is the first non-whitespace character on
+a line, while the other will always begin a comment.
+
+@kindex #
+@cindex lines starting with @code{#}
+@cindex logical line numbers
+To be compatible with past assemblers, a special interpretation is
+given to lines that begin with @samp{#}. Following the @samp{#} an
+absolute expression (@pxref{Expressions}) is expected: this will be
+the logical line number of the @b{next} line. Then a string
+(@xref{Strings}.) is allowed: if present it is a new logical file
+name. The rest of the line, if any, should be whitespace.
+
+If the first non-whitespace characters on the line are not numeric,
+the line is ignored. (Just like a comment.)
+@smallexample
+ # This is an ordinary comment.
+# 42-6 "new_file_name" # New logical file name
+ # This is logical line # 36.
+@end smallexample
+This feature is deprecated, and may disappear from future versions
+of @code{as}.
+
+@node Symbol Intro, Statements, Comments, Syntax
+@section Symbols
+
+@cindex symbols
+@cindex characters used in symbols
+A @dfn{symbol} is one or more characters chosen from the set of all
+letters (both upper and lower case), digits and
+the two characters @samp{_.}
+On most machines, you can also use @code{$} in symbol names; exceptions
+are noted in @ref{Machine Dependent}.
+No symbol may begin with a digit. Case is significant.
+There is no length limit: all characters are significant. Symbols are
+delimited by characters not in that set, or by the beginning of a file
+(since the source program must end with a newline, the end of a file is
+not a possible symbol delimiter). @xref{Symbols}.
+@cindex length of symbols
+
+@node Statements, Constants, Symbol Intro, Syntax
+@section Statements
+
+@cindex statements, structure of
+@cindex line separator character
+@cindex statement separator character
+A @dfn{statement} ends at a newline character (@samp{\n}) or line
+separator character. (The line separator is usually @samp{;}, unless
+this conflicts with the comment character; @pxref{Machine Dependent}.) The
+newline or separator character is considered part of the preceding
+statement. Newlines and separators within character constants are an
+exception: they don't end statements.
+
+@cindex newline, required at file end
+@cindex EOF, newline must precede
+It is an error to end any statement with end-of-file: the last
+character of any input file should be a newline.@refill
+
+@cindex continuing statements
+@cindex multi-line statements
+@cindex statement on multiple lines
+You may write a statement on more than one line if you put a
+backslash (@kbd{\}) immediately in front of any newlines within the
+statement. When @code{as} reads a backslashed newline both
+characters are ignored. You can even put backslashed newlines in
+the middle of symbol names without changing the meaning of your
+source program.
+
+An empty statement is allowed, and may include whitespace. It is ignored.
+
+@cindex instructions and directives
+@cindex directives and instructions
+@c "key symbol" is not used elsewhere in the document; seems pedantic to
+@c @defn{} it in that case, as was done previously... pesch@cygnus.com,
+@c 13feb91.
+A statement begins with zero or more labels, optionally followed by a
+key symbol which determines what kind of statement it is. The key
+symbol determines the syntax of the rest of the statement. If the
+symbol begins with a dot @samp{.} then the statement is an assembler
+directive: typically valid for any computer. If the symbol begins with
+a letter the statement is an assembly language @dfn{instruction}: it
+will assemble into a machine language instruction.
+Different versions of @code{as} for different computers will
+recognize different instructions. In fact, the same symbol may
+represent a different instruction in a different computer's assembly
+language.@refill
+
+@cindex @code{:} (label)
+@cindex label (@code{:})
+A label is a symbol immediately followed by a colon (@code{:}).
+Whitespace before a label or after a colon is permitted, but you may not
+have whitespace between a label's symbol and its colon. @xref{Labels}.
+
+@smallexample
+label: .directive followed by something
+another_label: # This is an empty statement.
+ instruction operand_1, operand_2, @dots{}
+@end smallexample
+
+@node Constants, , Statements, Syntax
+@section Constants
+
+@cindex constants
+A constant is a number, written so that its value is known by
+inspection, without knowing any context. Like this:
+@smallexample
+.byte 74, 0112, 092, 0x4A, 0X4a, 'J, '\J # All the same value.
+.ascii "Ring the bell\7" # A string constant.
+.octa 0x123456789abcdef0123456789ABCDEF0 # A bignum.
+.float 0f-314159265358979323846264338327\
+95028841971.693993751E-40 # - pi, a flonum.
+@end smallexample
+
+@menu
+* Characters:: Character Constants
+* Numbers:: Number Constants
+@end menu
+
+@node Characters, Numbers, Constants, Constants
+@subsection Character Constants
+
+@cindex character constants
+@cindex constants, character
+There are two kinds of character constants. A @dfn{character} stands
+for one character in one byte and its value may be used in
+numeric expressions. String constants (properly called string
+@emph{literals}) are potentially many bytes and their values may not be
+used in arithmetic expressions.
+
+@menu
+* Strings:: Strings
+* Chars:: Characters
+@end menu
+
+@node Strings, Chars, Characters, Characters
+@subsubsection Strings
+
+@cindex string constants
+@cindex constants, string
+A @dfn{string} is written between double-quotes. It may contain
+double-quotes or null characters. The way to get special characters
+into a string is to @dfn{escape} these characters: precede them with
+a backslash @samp{\} character. For example @samp{\\} represents
+one backslash: the first @code{\} is an escape which tells
+@code{as} to interpret the second character literally as a backslash
+(which prevents @code{as} from recognizing the second @code{\} as an
+escape character). The complete list of escapes follows.
+
+@cindex escape codes, character
+@cindex character escape codes
+@table @kbd
+@c @item \a
+@c Mnemonic for ACKnowledge; for ASCII this is octal code 007.
+@c
+@item \b
+@cindex @code{\b} (backspace character)
+@cindex backspace (@code{\b})
+Mnemonic for backspace; for ASCII this is octal code 010.
+
+@c @item \e
+@c Mnemonic for EOText; for ASCII this is octal code 004.
+@c
+@item \f
+@cindex @code{\f} (formfeed character)
+@cindex formfeed (@code{\f})
+Mnemonic for FormFeed; for ASCII this is octal code 014.
+
+@item \n
+@cindex @code{\n} (newline character)
+@cindex newline (@code{\n})
+Mnemonic for newline; for ASCII this is octal code 012.
+
+@c @item \p
+@c Mnemonic for prefix; for ASCII this is octal code 033, usually known as @code{escape}.
+@c
+@item \r
+@cindex @code{\r} (carriage return character)
+@cindex carriage return (@code{\r})
+Mnemonic for carriage-Return; for ASCII this is octal code 015.
+
+@c @item \s
+@c Mnemonic for space; for ASCII this is octal code 040. Included for compliance with
+@c other assemblers.
+@c
+@item \t
+@cindex @code{\t} (tab)
+@cindex tab (@code{\t})
+Mnemonic for horizontal Tab; for ASCII this is octal code 011.
+
+@c @item \v
+@c Mnemonic for Vertical tab; for ASCII this is octal code 013.
+@c @item \x @var{digit} @var{digit} @var{digit}
+@c A hexadecimal character code. The numeric code is 3 hexadecimal digits.
+@c
+@item \ @var{digit} @var{digit} @var{digit}
+@cindex @code{\@var{ddd}} (octal character code)
+@cindex octal character code (@code{\@var{ddd}})
+An octal character code. The numeric code is 3 octal digits.
+For compatibility with other Unix systems, 8 and 9 are accepted as digits:
+for example, @code{\008} has the value 010, and @code{\009} the value 011.
+
+@item \\
+@cindex @code{\\} (@samp{\} character)
+@cindex backslash (@code{\\})
+Represents one @samp{\} character.
+
+@c @item \'
+@c Represents one @samp{'} (accent acute) character.
+@c This is needed in single character literals
+@c (@xref{Characters,,Character Constants}.) to represent
+@c a @samp{'}.
+@c
+@item \"
+@cindex @code{\"} (doublequote character)
+@cindex doublequote (@code{\"})
+Represents one @samp{"} character. Needed in strings to represent
+this character, because an unescaped @samp{"} would end the string.
+
+@item \ @var{anything-else}
+Any other character when escaped by @kbd{\} will give a warning, but
+assemble as if the @samp{\} was not present. The idea is that if
+you used an escape sequence you clearly didn't want the literal
+interpretation of the following character. However @code{as} has no
+other interpretation, so @code{as} knows it is giving you the wrong
+code and warns you of the fact.
+@end table
+
+Which characters are escapable, and what those escapes represent,
+varies widely among assemblers. The current set is what we think
+the BSD 4.2 assembler recognizes, and is a subset of what most C
+compilers recognize. If you are in doubt, don't use an escape
+sequence.
+
+@node Chars, , Strings, Characters
+@subsubsection Characters
+
+@cindex single character constant
+@cindex character, single
+@cindex constant, single character
+A single character may be written as a single quote immediately
+followed by that character. The same escapes apply to characters as
+to strings. So if you want to write the character backslash, you
+must write @kbd{'\\} where the first @code{\} escapes the second
+@code{\}. As you can see, the quote is an acute accent, not a
+grave accent. A newline
+immediately following an acute accent is taken as a literal character
+and does not count as the end of a statement. The value of a character
+constant in a numeric expression is the machine's byte-wide code for
+that character. @code{as} assumes your character code is ASCII:
+@kbd{'A} means 65, @kbd{'B} means 66, and so on. @refill
+
+@node Numbers, , Characters, Constants
+@subsection Number Constants
+
+@cindex constants, number
+@cindex number constants
+@code{as} distinguishes three kinds of numbers according to how they
+are stored in the target machine. @emph{Integers} are numbers that
+would fit into an @code{int} in the C language. @emph{Bignums} are
+integers, but they are stored in more than 32 bits. @emph{Flonums}
+are floating point numbers, described below.
+
+@menu
+* Integers:: Integers
+* Bignums:: Bignums
+* Flonums:: Flonums
+@end menu
+
+@node Integers, Bignums, Numbers, Numbers
+@subsubsection Integers
+@cindex integers
+@cindex constants, integer
+
+@cindex binary integers
+@cindex integers, binary
+A binary integer is @samp{0b} or @samp{0B} followed by zero or more of
+the binary digits @samp{01}.
+
+@cindex octal integers
+@cindex integers, octal
+An octal integer is @samp{0} followed by zero or more of the octal
+digits (@samp{01234567}).
+
+@cindex decimal integers
+@cindex integers, decimal
+A decimal integer starts with a non-zero digit followed by zero or
+more digits (@samp{0123456789}).
+
+@cindex hexadecimal integers
+@cindex integers, hexadecimal
+A hexadecimal integer is @samp{0x} or @samp{0X} followed by one or
+more hexadecimal digits chosen from @samp{0123456789abcdefABCDEF}.
+
+Integers have the usual values. To denote a negative integer, use
+the prefix operator @samp{-} discussed under expressions
+(@pxref{Prefix Ops,,Prefix Operators}).
+
+@node Bignums, Flonums, Integers, Numbers
+@subsubsection Bignums
+
+@cindex bignums
+@cindex constants, bignum
+A @dfn{bignum} has the same syntax and semantics as an integer
+except that the number (or its negative) takes more than 32 bits to
+represent in binary. The distinction is made because in some places
+integers are permitted while bignums are not.
+
+@node Flonums, , Bignums, Numbers
+@subsubsection Flonums
+@cindex flonums
+@cindex floating point numbers
+@cindex constants, floating point
+
+@cindex precision, floating point
+A @dfn{flonum} represents a floating point number. The translation is
+indirect: a decimal floating point number from the text is converted by
+@code{as} to a generic binary floating point number of more than
+sufficient precision. This generic floating point number is converted
+to a particular computer's floating point format (or formats) by a
+portion of @code{as} specialized to that computer.
+
+A flonum is written by writing (in order)
+@itemize @bullet
+@item
+The digit @samp{0}.
+@item
+A letter, to tell @code{as} the rest of the number is a flonum.
+@kbd{e} is recommended. Case is not important.
+@ignore
+@c FIXME: verify if flonum syntax really this vague for most cases
+ (Any otherwise illegal letter
+will work here, but that might be changed. Vax BSD 4.2 assembler seems
+to allow any of @samp{defghDEFGH}.)
+@end ignore
+On the AMD 29K and H8/300 architectures, the letter must be:
+One of the letters @samp{DFPRSX} (in upper or lower case).
+On the Intel 960 architecture, the letter must be:
+One of the letters @samp{DFT} (in upper or lower case).
+@item
+An optional sign: either @samp{+} or @samp{-}.
+@item
+An optional @dfn{integer part}: zero or more decimal digits.
+@item
+An optional @dfn{fractional part}: @samp{.} followed by zero
+or more decimal digits.
+@item
+An optional exponent, consisting of:
+@itemize @bullet
+@item
+An @samp{E} or @samp{e}.
+@c I can't find a config where "EXP_CHARS" is other than 'eE', but in
+@c principle this can perfectly well be different on different targets.
+@item
+Optional sign: either @samp{+} or @samp{-}.
+@item
+One or more decimal digits.
+@end itemize
+@end itemize
+
+At least one of the integer part or the fractional part must be
+present. The floating point number has the usual base-10 value.
+
+@code{as} does all processing using integers. Flonums are computed
+independently of any floating point hardware in the computer running
+@code{as}.
+
+
+@node Sections, Symbols, Syntax, Top
+@chapter Sections and Relocation
+@cindex sections
+@cindex relocation
+
+@menu
+* Secs Background:: Background
+* ld Sections:: ld Sections
+* as Sections:: as Internal Sections
+* Sub-Sections:: Sub-Sections
+* bss:: bss Section
+@end menu
+
+@node Secs Background, ld Sections, Sections, Sections
+@section Background
+
+Roughly, a section is a range of addresses, with no gaps; all data
+``in'' those addresses is treated the same for some particular purpose.
+For example there may be a ``read only'' section.
+
+@cindex linker, and assembler
+@cindex assembler, and linker
+The linker @code{ld} reads many object files (partial programs) and
+combines their contents to form a runnable program. When @code{as}
+emits an object file, the partial program is assumed to start at address
+0. @code{ld} will assign the final addresses the partial program
+occupies, so that different partial programs don't overlap. This is
+actually an over-simplification, but it will suffice to explain how
+@code{as} uses sections.
+
+@code{ld} moves blocks of bytes of your program to their run-time
+addresses. These blocks slide to their run-time addresses as rigid
+units; their length does not change and neither does the order of bytes
+within them. Such a rigid unit is called a @emph{section}. Assigning
+run-time addresses to sections is called @dfn{relocation}. It includes
+the task of adjusting mentions of object-file addresses so they refer to
+the proper run-time addresses.
+For the H8/300, @code{as} pads sections if needed to ensure they end
+on a word (sixteen bit) boundary.
+
+@cindex standard @code{as} sections
+An object file written by @code{as} has at least three sections, any
+of which may be empty. These are named @dfn{text}, @dfn{data} and
+@dfn{bss} sections.
+
+When it generates COFF output,
+@code{as} can also generate whatever other named sections you specify
+using the @samp{.section} directive (@pxref{Section,,@code{.section}}).
+If you don't use any directives that place output in the @samp{.text}
+or @samp{.data} sections, these sections will still exist, but will be empty.
+
+Within the object file, the text section starts at address @code{0}, the
+data section follows, and the bss section follows the data section.
+
+To let @code{ld} know which data will change when the sections are
+relocated, and how to change that data, @code{as} also writes to the
+object file details of the relocation needed. To perform relocation
+@code{ld} must know, each time an address in the object
+file is mentioned:
+@itemize @bullet
+@item
+Where in the object file is the beginning of this reference to
+an address?
+@item
+How long (in bytes) is this reference?
+@item
+Which section does the address refer to? What is the numeric value of
+@display
+(@var{address}) @minus{} (@var{start-address of section})?
+@end display
+@item
+Is the reference to an address ``Program-Counter relative''?
+@end itemize
+
+@cindex addresses, format of
+@cindex section-relative addressing
+In fact, every address @code{as} ever uses is expressed as
+@display
+(@var{section}) + (@var{offset into section})
+@end display
+@noindent
+Further, every expression @code{as} computes is of this section-relative
+nature. @dfn{Absolute expression} means an expression with section
+``absolute'' (@pxref{ld Sections}). A @dfn{pass1 expression} means
+an expression with section ``pass1'' (@pxref{as Sections,,as
+Internal Sections}). In this manual we use the notation @{@var{secname}
+@var{N}@} to mean ``offset @var{N} into section @var{secname}''.
+
+Apart from text, data and bss sections you need to know about the
+@dfn{absolute} section. When @code{ld} mixes partial programs,
+addresses in the absolute section remain unchanged. For example, address
+@code{@{absolute 0@}} is ``relocated'' to run-time address 0 by @code{ld}.
+Although two partial programs' data sections will not overlap addresses
+after linking, @emph{by definition} their absolute sections will overlap.
+Address @code{@{absolute@ 239@}} in one partial program will always be the same
+address when the program is running as address @code{@{absolute@ 239@}} in any
+other partial program.
+
+The idea of sections is extended to the @dfn{undefined} section. Any
+address whose section is unknown at assembly time is by definition
+rendered @{undefined @var{U}@}---where @var{U} will be filled in later.
+Since numbers are always defined, the only way to generate an undefined
+address is to mention an undefined symbol. A reference to a named
+common block would be such a symbol: its value is unknown at assembly
+time so it has section @emph{undefined}.
+
+By analogy the word @emph{section} is used to describe groups of sections in
+the linked program. @code{ld} puts all partial programs' text
+sections in contiguous addresses in the linked program. It is
+customary to refer to the @emph{text section} of a program, meaning all
+the addresses of all partial program's text sections. Likewise for
+data and bss sections.
+
+Some sections are manipulated by @code{ld}; others are invented for
+use of @code{as} and have no meaning except during assembly.
+
+@node ld Sections, as Sections, Secs Background, Sections
+@section ld Sections
+@code{ld} deals with just four kinds of sections, summarized below.
+
+@table @strong
+
+@cindex named sections
+@cindex sections, named
+@item named sections
+@cindex text section
+@cindex data section
+@item text section
+@itemx data section
+These sections hold your program. @code{as} and @code{ld} treat them as
+separate but equal sections. Anything you can say of one section is
+true another.
+When the program is running, however, it is
+customary for the text section to be unalterable. The
+text section is often shared among processes: it will contain
+instructions, constants and the like. The data section of a running
+program is usually alterable: for example, C variables would be stored
+in the data section.
+
+@cindex bss section
+@item bss section
+This section contains zeroed bytes when your program begins running. It
+is used to hold unitialized variables or common storage. The length of
+each partial program's bss section is important, but because it starts
+out containing zeroed bytes there is no need to store explicit zero
+bytes in the object file. The bss section was invented to eliminate
+those explicit zeros from object files.
+
+@cindex absolute section
+@item absolute section
+Address 0 of this section is always ``relocated'' to runtime address 0.
+This is useful if you want to refer to an address that @code{ld} must
+not change when relocating. In this sense we speak of absolute
+addresses being ``unrelocatable'': they don't change during relocation.
+
+@cindex undefined section
+@item undefined section
+This ``section'' is a catch-all for address references to objects not in
+the preceding sections.
+@c FIXME: ref to some other doc on obj-file formats could go here.
+@end table
+
+@cindex relocation example
+An idealized example of three relocatable sections follows.
+The example uses the traditional section names @samp{.text} and @samp{.data}.
+Memory addresses are on the horizontal axis.
+
+@c TEXI2ROFF-KILL
+@ifinfo
+@c END TEXI2ROFF-KILL
+@smallexample
+ +-----+----+--+
+partial program # 1: |ttttt|dddd|00|
+ +-----+----+--+
+
+ text data bss
+ seg. seg. seg.
+
+ +---+---+---+
+partial program # 2: |TTT|DDD|000|
+ +---+---+---+
+
+ +--+---+-----+--+----+---+-----+~~
+linked program: | |TTT|ttttt| |dddd|DDD|00000|
+ +--+---+-----+--+----+---+-----+~~
+
+ addresses: 0 @dots{}
+@end smallexample
+@c TEXI2ROFF-KILL
+@end ifinfo
+@c FIXME make sure no page breaks inside figure!!
+@tex
+
+\line{\it Partial program \#1: \hfil}
+\line{\ibox{2.5cm}{\tt text}\ibox{2cm}{\tt data}\ibox{1cm}{\tt bss}\hfil}
+\line{\boxit{2.5cm}{\tt ttttt}\boxit{2cm}{\tt dddd}\boxit{1cm}{\tt 00}\hfil}
+
+\line{\it Partial program \#2: \hfil}
+\line{\ibox{1cm}{\tt text}\ibox{1.5cm}{\tt data}\ibox{1cm}{\tt bss}\hfil}
+\line{\boxit{1cm}{\tt TTT}\boxit{1.5cm}{\tt DDDD}\boxit{1cm}{\tt 000}\hfil}
+
+\line{\it linked program: \hfil}
+\line{\ibox{.5cm}{}\ibox{1cm}{\tt text}\ibox{2.5cm}{}\ibox{.75cm}{}\ibox{2cm}{\tt data}\ibox{1.5cm}{}\ibox{2cm}{\tt bss}\hfil}
+\line{\boxit{.5cm}{}\boxit{1cm}{\tt TTT}\boxit{2.5cm}{\tt
+ttttt}\boxit{.75cm}{}\boxit{2cm}{\tt dddd}\boxit{1.5cm}{\tt
+DDDD}\boxit{2cm}{\tt 00000}\ \dots\hfil}
+
+\line{\it addresses: \hfil}
+\line{0\dots\hfil}
+
+@end tex
+@c END TEXI2ROFF-KILL
+
+@node as Sections, Sub-Sections, ld Sections, Sections
+@section as Internal Sections
+
+@cindex internal @code{as} sections
+@cindex sections in messages, internal
+These sections are meant only for the internal use of @code{as}. They
+have no meaning at run-time. You don't really need to know about these
+sections for most purposes; but they can be mentioned in @code{as}
+warning messages, so it might be helpful to have an idea of their
+meanings to @code{as}. These sections are used to permit the
+value of every expression in your assembly language program to be a
+section-relative address.
+
+@table @b
+@item absent
+@cindex absent (internal section)
+An expression was expected and none was found.
+
+@item ASSEMBLER-INTERNAL-LOGIC-ERROR!
+@cindex assembler internal logic error
+An internal assembler logic error has been found. This means there is a
+bug in the assembler.
+
+@item bignum/flonum
+@cindex bignum/flonum (internal section)
+If a number can't be written as a C @code{int} constant (a bignum or a
+flonum, but not an integer), it is recorded as belonging to this
+``section''. @code{as} has to remember that a flonum or a bignum
+does not fit into 32 bits, and cannot be an argument (@pxref{Arguments})
+in an expression: this is done by making a flonum or bignum be in a
+separate internal section. This is purely for internal @code{as}
+convenience; bignum/flonum section behaves similarly to absolute
+section.
+
+@item pass1 section
+@cindex pass1 (internal section)
+The expression was impossible to evaluate in the first pass. The
+assembler will attempt a second pass (second reading of the source) to
+evaluate the expression. Your expression mentioned an undefined symbol
+in a way that defies the one-pass (section + offset in section) assembly
+process. No compiler need emit such an expression.
+
+@quotation
+@emph{Warning:} the second pass is currently not implemented. @code{as}
+will abort with an error message if one is required.
+@end quotation
+
+@item difference section
+@cindex difference (internal section)
+As an assist to the C compiler, expressions of the forms
+@display
+ (@var{undefined symbol}) @minus{} (@var{expression})
+ @var{something} @minus{} (@var{undefined symbol})
+ (@var{undefined symbol}) @minus{} (@var{undefined symbol})
+@end display
+
+are permitted, and belong to the difference section. @code{as}
+re-evaluates such expressions after the source file has been read and
+the symbol table built. If by that time there are no undefined symbols
+in the expression then the expression assumes a new section. The
+intention is to permit statements like
+@samp{.word label - base_of_table}
+to be assembled in one pass where both @code{label} and
+@code{base_of_table} are undefined. This is useful for compiling C and
+Algol switch statements, Pascal case statements, FORTRAN computed goto
+statements and the like.
+@c FIXME item debug
+@c FIXME item transfer[t] vector preload
+@c FIXME item transfer[t] vector postload
+@c FIXME item register
+@end table
+
+@node Sub-Sections, bss, as Sections, Sections
+@section Sub-Sections
+
+@cindex numbered subsections
+@cindex grouping data
+Assembled bytes
+conventionally
+fall into two sections: text and data.
+You may have separate groups of
+data in named sections
+that you want to end up near to each other in the object
+file, even though they are not contiguous in the assembler source.
+@code{as} allows you to use @dfn{subsections} for this purpose.
+Within each section, there can be numbered subsections with
+values from 0 to 8192. Objects assembled into the same subsection will
+be grouped with other objects in the same subsection when they are all
+put into the object file. For example, a compiler might want to store
+constants in the text section, but might not want to have them
+interspersed with the program being assembled. In this case, the
+compiler could issue a @samp{.text 0} before each section of code being
+output, and a @samp{.text 1} before each group of constants being output.
+
+Subsections are optional. If you don't use subsections, everything
+will be stored in subsection number zero.
+
+Each subsection is zero-padded up to a multiple of four bytes.
+(Subsections may be padded a different amount on different flavors
+of @code{as}.)
+
+Subsections appear in your object file in numeric order, lowest numbered
+to highest. (All this to be compatible with other people's assemblers.)
+The object file contains no representation of subsections; @code{ld} and
+other programs that manipulate object files will see no trace of them.
+They just see all your text subsections as a text section, and all your
+data subsections as a data section.
+
+To specify which subsection you want subsequent statements assembled
+into, use a numeric argument to specify it, in a @samp{.text
+@var{expression}} or a @samp{.data @var{expression}} statement.
+When generating COFF output, you
+can also use an extra subsection
+argument with arbitrary named sections: @samp{.section @var{name},
+@var{expression}}.
+@var{Expression} should be an absolute expression.
+(@xref{Expressions}.) If you just say @samp{.text} then @samp{.text 0}
+is assumed. Likewise @samp{.data} means @samp{.data 0}. Assembly
+begins in @code{text 0}. For instance:
+@smallexample
+.text 0 # The default subsection is text 0 anyway.
+.ascii "This lives in the first text subsection. *"
+.text 1
+.ascii "But this lives in the second text subsection."
+.data 0
+.ascii "This lives in the data section,"
+.ascii "in the first data subsection."
+.text 0
+.ascii "This lives in the first text section,"
+.ascii "immediately following the asterisk (*)."
+@end smallexample
+
+Each section has a @dfn{location counter} incremented by one for every
+byte assembled into that section. Because subsections are merely a
+convenience restricted to @code{as} there is no concept of a subsection
+location counter. There is no way to directly manipulate a location
+counter---but the @code{.align} directive will change it, and any label
+definition will capture its current value. The location counter of the
+section that statements are being assembled into is said to be the
+@dfn{active} location counter.
+
+@node bss, , Sub-Sections, Sections
+@section bss Section
+
+@cindex bss section
+@cindex common variable storage
+The bss section is used for local common variable storage.
+You may allocate address space in the bss section, but you may
+not dictate data to load into it before your program executes. When
+your program starts running, all the contents of the bss
+section are zeroed bytes.
+
+Addresses in the bss section are allocated with special directives; you
+may not assemble anything directly into the bss section. Hence there
+are no bss subsections. @xref{Comm,,@code{.comm}},
+@pxref{Lcomm,,@code{.lcomm}}.
+
+@node Symbols, Expressions, Sections, Top
+@chapter Symbols
+
+@cindex symbols
+Symbols are a central concept: the programmer uses symbols to name
+things, the linker uses symbols to link, and the debugger uses symbols
+to debug.
+
+@quotation
+@cindex debuggers, and symbol order
+@emph{Warning:} @code{as} does not place symbols in the object file in
+the same order they were declared. This may break some debuggers.
+@end quotation
+
+@menu
+* Labels:: Labels
+* Setting Symbols:: Giving Symbols Other Values
+* Symbol Names:: Symbol Names
+* Dot:: The Special Dot Symbol
+* Symbol Attributes:: Symbol Attributes
+@end menu
+
+@node Labels, Setting Symbols, Symbols, Symbols
+@section Labels
+
+@cindex labels
+A @dfn{label} is written as a symbol immediately followed by a colon
+@samp{:}. The symbol then represents the current value of the
+active location counter, and is, for example, a suitable instruction
+operand. You are warned if you use the same symbol to represent two
+different locations: the first definition overrides any other
+definitions.
+
+@node Setting Symbols, Symbol Names, Labels, Symbols
+@section Giving Symbols Other Values
+
+@cindex assigning values to symbols
+@cindex symbol values, assigning
+A symbol can be given an arbitrary value by writing a symbol, followed
+by an equals sign @samp{=}, followed by an expression
+(@pxref{Expressions}). This is equivalent to using the @code{.set}
+directive. @xref{Set,,@code{.set}}.
+
+@node Symbol Names, Dot, Setting Symbols, Symbols
+@section Symbol Names
+
+@cindex symbol names
+@cindex names, symbol
+Symbol names begin with a letter or with one of
+@samp{_.}
+(On most machines, you can also use @code{$} in symbol names; exceptions
+are noted in @ref{Machine Dependent}.)
+That character may be followed by any string of digits, letters,
+dollar signs (unless otherwise noted in @ref{Machine Dependent}),
+and underscores.
+Case of letters is significant:
+@code{foo} is a different symbol name than @code{Foo}.
+
+For the AMD 29K family, @samp{?} is also allowed in the
+body of a symbol name, though not at its beginning.
+
+Each symbol has exactly one name. Each name in an assembly language
+program refers to exactly one symbol. You may use that symbol name any
+number of times in a program.
+
+@subheading Local Symbol Names
+
+@cindex local symbol names
+@cindex symbol names, local
+@cindex temporary symbol names
+@cindex symbol names, temporary
+Local symbols help compilers and programmers use names temporarily.
+There are ten local symbol names, which are re-used throughout the
+program. You may refer to them using the names @samp{0} @samp{1}
+@dots{} @samp{9}. To define a local symbol, write a label of the form
+@samp{@b{N}:} (where @b{N} represents any digit). To refer to the most
+recent previous definition of that symbol write @samp{@b{N}b}, using the
+same digit as when you defined the label. To refer to the next
+definition of a local label, write @samp{@b{N}f}---where @b{N} gives you
+a choice of 10 forward references. The @samp{b} stands for
+``backwards'' and the @samp{f} stands for ``forwards''.
+
+Local symbols are not emitted by the current GNU C compiler.
+
+There is no restriction on how you can use these labels, but
+remember that at any point in the assembly you can refer to at most
+10 prior local labels and to at most 10 forward local labels.
+
+Local symbol names are only a notation device. They are immediately
+transformed into more conventional symbol names before the assembler
+uses them. The symbol names stored in the symbol table, appearing in
+error messages and optionally emitted to the object file have these
+parts:
+
+@table @code
+@item L
+All local labels begin with @samp{L}. Normally both @code{as} and
+@code{ld} forget symbols that start with @samp{L}. These labels are
+used for symbols you are never intended to see. If you give the
+@samp{-L} option then @code{as} will retain these symbols in the
+object file. If you also instruct @code{ld} to retain these symbols,
+you may use them in debugging.
+
+@item @var{digit}
+If the label is written @samp{0:} then the digit is @samp{0}.
+If the label is written @samp{1:} then the digit is @samp{1}.
+And so on up through @samp{9:}.
+
+@item @ctrl{A}
+This unusual character is included so you don't accidentally invent
+a symbol of the same name. The character has ASCII value
+@samp{\001}.
+
+@item @emph{ordinal number}
+This is a serial number to keep the labels distinct. The first
+@samp{0:} gets the number @samp{1}; The 15th @samp{0:} gets the
+number @samp{15}; @emph{etc.}. Likewise for the other labels @samp{1:}
+through @samp{9:}.
+@end table
+
+For instance, the first @code{1:} is named @code{L1@ctrl{A}1}, the 44th
+@code{3:} is named @code{L3@ctrl{A}44}.
+
+@node Dot, Symbol Attributes, Symbol Names, Symbols
+@section The Special Dot Symbol
+
+@cindex dot (symbol)
+@cindex @code{.} (symbol)
+@cindex current address
+@cindex location counter
+The special symbol @samp{.} refers to the current address that
+@code{as} is assembling into. Thus, the expression @samp{melvin:
+.long .} will cause @code{melvin} to contain its own address.
+Assigning a value to @code{.} is treated the same as a @code{.org}
+directive. Thus, the expression @samp{.=.+4} is the same as saying
+@samp{.block 4}.
+
+@node Symbol Attributes, , Dot, Symbols
+@section Symbol Attributes
+
+@cindex symbol attributes
+@cindex attributes, symbol
+Every symbol has, as well as its name, the attributes ``Value'' and
+``Type''. Depending on output format, symbols can also have auxiliary
+attributes.
+
+If you use a symbol without defining it, @code{as} assumes zero for
+all these attributes, and probably won't warn you. This makes the
+symbol an externally defined symbol, which is generally what you
+would want.
+
+@menu
+* Symbol Value:: Value
+* Symbol Type:: Type
+* a.out Symbols:: Symbol Attributes: @code{a.out}
+* COFF Symbols:: Symbol Attributes for COFF
+@end menu
+
+@node Symbol Value, Symbol Type, Symbol Attributes, Symbol Attributes
+@subsection Value
+
+@cindex value of a symbol
+@cindex symbol value
+The value of a symbol is (usually) 32 bits. For a symbol which labels a
+location in the text, data, bss or absolute sections the value is the
+number of addresses from the start of that section to the label.
+Naturally for text, data and bss sections the value of a symbol changes
+as @code{ld} changes section base addresses during linking. Absolute
+symbols' values do not change during linking: that is why they are
+called absolute.
+
+The value of an undefined symbol is treated in a special way. If it is
+0 then the symbol is not defined in this assembler source program, and
+@code{ld} will try to determine its value from other programs it is
+linked with. You make this kind of symbol simply by mentioning a symbol
+name without defining it. A non-zero value represents a @code{.comm}
+common declaration. The value is how much common storage to reserve, in
+bytes (addresses). The symbol refers to the first address of the
+allocated storage.
+
+@node Symbol Type, a.out Symbols, Symbol Value, Symbol Attributes
+@subsection Type
+
+@cindex type of a symbol
+@cindex symbol type
+The type attribute of a symbol contains relocation (section)
+information, any flag settings indicating that a symbol is external, and
+(optionally), other information for linkers and debuggers. The exact
+format depends on the object-code output format in use.
+
+@node a.out Symbols, COFF Symbols, Symbol Type, Symbol Attributes
+@subsection Symbol Attributes: @code{a.out}
+
+@cindex @code{a.out} symbol attributes
+@cindex symbol attributes, @code{a.out}
+
+@menu
+* Symbol Desc:: Descriptor
+* Symbol Other:: Other
+@end menu
+
+@node Symbol Desc, Symbol Other, a.out Symbols, a.out Symbols
+@subsubsection Descriptor
+
+@cindex descriptor, of @code{a.out} symbol
+This is an arbitrary 16-bit value. You may establish a symbol's
+descriptor value by using a @code{.desc} statement
+(@pxref{Desc,,@code{.desc}}). A descriptor value means nothing to
+@code{as}.
+
+@node Symbol Other, , Symbol Desc, a.out Symbols
+@subsubsection Other
+
+@cindex other attribute, of @code{a.out} symbol
+This is an arbitrary 8-bit value. It means nothing to @code{as}.
+
+@node COFF Symbols, , a.out Symbols, Symbol Attributes
+@subsection Symbol Attributes for COFF
+
+@cindex COFF symbol attributes
+@cindex symbol attributes, COFF
+
+The COFF format supports a multitude of auxiliary symbol attributes;
+like the primary symbol attributes, they are set between @code{.def} and
+@code{.endef} directives.
+
+@subsubsection Primary Attributes
+
+@cindex primary attributes, COFF symbols
+The symbol name is set with @code{.def}; the value and type,
+respectively, with @code{.val} and @code{.type}.
+
+@subsubsection Auxiliary Attributes
+
+@cindex auxiliary attributes, COFF symbols
+The @code{as} directives @code{.dim}, @code{.line}, @code{.scl},
+@code{.size}, and @code{.tag} can generate auxiliary symbol table
+information for COFF.
+
+@node Expressions, Pseudo Ops, Symbols, Top
+@chapter Expressions
+
+@cindex expressions
+@cindex addresses
+@cindex numeric values
+An @dfn{expression} specifies an address or numeric value.
+Whitespace may precede and/or follow an expression.
+
+@menu
+* Empty Exprs:: Empty Expressions
+* Integer Exprs:: Integer Expressions
+@end menu
+
+@node Empty Exprs, Integer Exprs, Expressions, Expressions
+@section Empty Expressions
+
+@cindex empty expressions
+@cindex expressions, empty
+An empty expression has no value: it is just whitespace or null.
+Wherever an absolute expression is required, you may omit the
+expression and @code{as} will assume a value of (absolute) 0. This
+is compatible with other assemblers.
+
+@node Integer Exprs, , Empty Exprs, Expressions
+@section Integer Expressions
+
+@cindex integer expressions
+@cindex expressions, integer
+An @dfn{integer expression} is one or more @emph{arguments} delimited
+by @emph{operators}.
+
+@menu
+* Arguments:: Arguments
+* Operators:: Operators
+* Prefix Ops:: Prefix Operators
+* Infix Ops:: Infix Operators
+@end menu
+
+@node Arguments, Operators, Integer Exprs, Integer Exprs
+@subsection Arguments
+
+@cindex expression arguments
+@cindex arguments in expressions
+@cindex operands in expressions
+@cindex arithmetic operands
+@dfn{Arguments} are symbols, numbers or subexpressions. In other
+contexts arguments are sometimes called ``arithmetic operands''. In
+this manual, to avoid confusing them with the ``instruction operands'' of
+the machine language, we use the term ``argument'' to refer to parts of
+expressions only, reserving the word ``operand'' to refer only to machine
+instruction operands.
+
+Symbols are evaluated to yield @{@var{section} @var{NNN}@} where
+@var{section} is one of text, data, bss, absolute,
+or undefined. @var{NNN} is a signed, 2's complement 32 bit
+integer.
+
+Numbers are usually integers.
+
+A number can be a flonum or bignum. In this case, you are warned
+that only the low order 32 bits are used, and @code{as} pretends
+these 32 bits are an integer. You may write integer-manipulating
+instructions that act on exotic constants, compatible with other
+assemblers.
+
+@cindex subexpressions
+Subexpressions are a left parenthesis @samp{(} followed by an integer
+expression, followed by a right parenthesis @samp{)}; or a prefix
+operator followed by an argument.
+
+@node Operators, Prefix Ops, Arguments, Integer Exprs
+@subsection Operators
+
+@cindex operators, in expressions
+@cindex arithmetic functions
+@cindex functions, in expressions
+@dfn{Operators} are arithmetic functions, like @code{+} or @code{%}. Prefix
+operators are followed by an argument. Infix operators appear
+between their arguments. Operators may be preceded and/or followed by
+whitespace.
+
+@node Prefix Ops, Infix Ops, Operators, Integer Exprs
+@subsection Prefix Operator
+
+@cindex prefix operators
+@code{as} has the following @dfn{prefix operators}. They each take
+one argument, which must be absolute.
+
+@c the tex/end tex stuff surrounding this small table is meant to make
+@c it align, on the printed page, with the similar table in the next
+@c section (which is inside an enumerate).
+@tex
+\global\advance\leftskip by \itemindent
+@end tex
+
+@table @code
+@item -
+@dfn{Negation}. Two's complement negation.
+@item ~
+@dfn{Complementation}. Bitwise not.
+@end table
+
+@tex
+\global\advance\leftskip by -\itemindent
+@end tex
+
+@node Infix Ops, , Prefix Ops, Integer Exprs
+@subsection Infix Operators
+
+@cindex infix operators
+@cindex operators, permitted arguments
+@dfn{Infix operators} take two arguments, one on either side. Operators
+have precedence, but operations with equal precedence are performed left
+to right. Apart from @code{+} or @code{-}, both arguments must be
+absolute, and the result is absolute.
+
+@enumerate
+@cindex operator precedence
+@cindex precedence of operators
+
+@item
+Highest Precedence
+
+@table @code
+@item *
+@dfn{Multiplication}.
+
+@item /
+@dfn{Division}. Truncation is the same as the C operator @samp{/}
+
+@item %
+@dfn{Remainder}.
+
+@item <
+@itemx <<
+@dfn{Shift Left}. Same as the C operator @samp{<<}
+
+@item >
+@itemx >>
+@dfn{Shift Right}. Same as the C operator @samp{>>}
+@end table
+
+@item
+Intermediate precedence
+
+@table @code
+@item |
+
+@dfn{Bitwise Inclusive Or}.
+
+@item &
+@dfn{Bitwise And}.
+
+@item ^
+@dfn{Bitwise Exclusive Or}.
+
+@item !
+@dfn{Bitwise Or Not}.
+@end table
+
+@item
+Lowest Precedence
+
+@table @code
+@item +
+@cindex addition, permitted arguments
+@cindex plus, permitted arguments
+@cindex arguments for addition
+@dfn{Addition}. If either argument is absolute, the result
+has the section of the other argument.
+If either argument is pass1 or undefined, the result is pass1.
+Otherwise @code{+} is illegal.
+
+@item -
+@cindex subtraction, permitted arguments
+@cindex minus, permitted arguments
+@cindex arguments for subtraction
+@dfn{Subtraction}. If the right argument is absolute, the
+result has the section of the left argument.
+If either argument is pass1 the result is pass1.
+If either argument is undefined the result is difference section.
+If both arguments are in the same section, the result is absolute---provided
+that section is one of text, data or bss.
+Otherwise subtraction is illegal.
+@end table
+@end enumerate
+
+The sense of the rule for addition is that it's only meaningful to add
+the @emph{offsets} in an address; you can only have a defined section in
+one of the two arguments.
+
+Similarly, you can't subtract quantities from two different sections.
+
+@node Pseudo Ops, Machine Dependent, Expressions, Top
+@chapter Assembler Directives
+
+@cindex directives, machine independent
+@cindex pseudo-ops, machine independent
+@cindex machine independent directives
+All assembler directives have names that begin with a period (@samp{.}).
+The rest of the name is letters, usually in lower case.
+
+This chapter discusses directives present regardless of the target
+machine configuration for the GNU assembler.
+
+@menu
+* Abort:: @code{.abort}
+* coff-ABORT:: @code{.ABORT}
+* Align:: @code{.align @var{abs-expr} , @var{abs-expr}}
+* App-File:: @code{.app-file @var{string}}
+* Ascii:: @code{.ascii "@var{string}"}@dots{}
+* Asciz:: @code{.asciz "@var{string}"}@dots{}
+* Byte:: @code{.byte @var{expressions}}
+* Comm:: @code{.comm @var{symbol} , @var{length} }
+* Data:: @code{.data @var{subsection}}
+* Def:: @code{.def @var{name}}
+* Desc:: @code{.desc @var{symbol}, @var{abs-expression}}
+* Dim:: @code{.dim}
+* Double:: @code{.double @var{flonums}}
+* Eject:: @code{.eject}
+* Else:: @code{.else}
+* Endef:: @code{.endef}
+* Endif:: @code{.endif}
+* Equ:: @code{.equ @var{symbol}, @var{expression}}
+* Extern:: @code{.extern}
+* File:: @code{.file @var{string}}
+* Fill:: @code{.fill @var{repeat} , @var{size} , @var{value}}
+* Float:: @code{.float @var{flonums}}
+* Global:: @code{.global @var{symbol}}, @code{.globl @var{symbol}}
+* hword:: @code{.hword @var{expressions}}
+* Ident:: @code{.ident}
+* If:: @code{.if @var{absolute expression}}
+* Include:: @code{.include "@var{file}"}
+* Int:: @code{.int @var{expressions}}
+* Lcomm:: @code{.lcomm @var{symbol} , @var{length}}
+* Lflags:: @code{.lflags}
+* Line:: @code{.line @var{line-number}}
+* Ln:: @code{.ln @var{line-number}}
+* List:: @code{.list}
+* Long:: @code{.long @var{expressions}}
+* Lsym:: @code{.lsym @var{symbol}, @var{expression}}
+* Nolist:: @code{.nolist}
+* Octa:: @code{.octa @var{bignums}}
+* Org:: @code{.org @var{new-lc} , @var{fill}}
+* Psize:: @code{.psize @var{lines}, @var{columns}}
+* Quad:: @code{.quad @var{bignums}}
+* Sbttl:: @code{.sbttl "@var{subheading}"}
+* Scl:: @code{.scl @var{class}}
+* Section:: @code{.section @var{name}, @var{subsection}}
+* Set:: @code{.set @var{symbol}, @var{expression}}
+* Short:: @code{.short @var{expressions}}
+* Single:: @code{.single @var{flonums}}
+* Size:: @code{.size}
+* Space:: @code{.space @var{size} , @var{fill}}
+* Stab:: @code{.stabd, .stabn, .stabs}
+* Tag:: @code{.tag @var{structname}}
+* Text:: @code{.text @var{subsection}}
+* Title:: @code{.title "@var{heading}"}
+* Type:: @code{.type @var{int}}
+* Val:: @code{.val @var{addr}}
+* Word:: @code{.word @var{expressions}}
+* Deprecated:: Deprecated Directives
+@end menu
+
+@node Abort, coff-ABORT, Pseudo Ops, Pseudo Ops
+@section @code{.abort}
+
+@cindex @code{abort} directive
+@cindex stopping the assembly
+This directive stops the assembly immediately. It is for
+compatibility with other assemblers. The original idea was that the
+assembly language source would be piped into the assembler. If the sender
+of the source quit, it could use this directive tells @code{as} to
+quit also. One day @code{.abort} will not be supported.
+
+@node coff-ABORT, Align, Abort, Pseudo Ops
+@section @code{.ABORT}
+
+@cindex @code{ABORT} directive
+When producing COFF output, @code{as} accepts this directive as a
+synonym for @samp{.abort}.
+
+
+When producing @code{b.out} output, @code{as} accepts this directive,
+but ignores it.
+
+@node Align, App-File, coff-ABORT, Pseudo Ops
+@section @code{.align @var{abs-expr} , @var{abs-expr}}
+
+@cindex padding the location counter
+@cindex advancing location counter
+@cindex location counter, advancing
+@cindex @code{align} directive
+Pad the location counter (in the current subsection) to a particular
+storage boundary. The first expression (which must be absolute) is the
+number of low-order zero bits the location counter will have after
+advancement. For example @samp{.align 3} will advance the location
+counter until it a multiple of 8. If the location counter is already a
+multiple of 8, no change is needed.
+
+The second expression (also absolute) gives the value to be stored in
+the padding bytes. It (and the comma) may be omitted. If it is
+omitted, the padding bytes are zero.
+
+@node App-File, Ascii, Align, Pseudo Ops
+@section @code{.app-file @var{string}}
+
+@cindex logical file name
+@cindex file name, logical
+@cindex @code{app-file} directive
+@code{.app-file}
+tells @code{as} that we are about to start a new
+logical file. @var{string} is the new file name. In general, the
+filename is recognized whether or not it is surrounded by quotes @samp{"};
+but if you wish to specify an empty file name is permitted,
+you must give the quotes--@code{""}. This statement may go away in
+future: it is only recognized to be compatible with old @code{as}
+programs.@refill
+
+@node Ascii, Asciz, App-File, Pseudo Ops
+@section @code{.ascii "@var{string}"}@dots{}
+
+@cindex @code{ascii} directive
+@cindex string literals
+@code{.ascii} expects zero or more string literals (@pxref{Strings})
+separated by commas. It assembles each string (with no automatic
+trailing zero byte) into consecutive addresses.
+
+@node Asciz, Byte, Ascii, Pseudo Ops
+@section @code{.asciz "@var{string}"}@dots{}
+
+@cindex @code{asciz} directive
+@cindex zero-terminated strings
+@cindex null-terminated strings
+@code{.asciz} is just like @code{.ascii}, but each string is followed by
+a zero byte. The ``z'' in @samp{.asciz} stands for ``zero''.
+
+@node Byte, Comm, Asciz, Pseudo Ops
+@section @code{.byte @var{expressions}}
+
+@cindex @code{byte} directive
+@cindex integers, one byte
+@code{.byte} expects zero or more expressions, separated by commas.
+Each expression is assembled into the next byte.
+
+@node Comm, Data, Byte, Pseudo Ops
+@section @code{.comm @var{symbol} , @var{length} }
+
+@cindex @code{comm} directive
+@cindex symbol, common
+@code{.comm} declares a named common area in the bss section. Normally
+@code{ld} reserves memory addresses for it during linking, so no partial
+program defines the location of the symbol. Use @code{.comm} to tell
+@code{ld} that it must be at least @var{length} bytes long. @code{ld}
+will allocate space for each @code{.comm} symbol that is at least as
+long as the longest @code{.comm} request in any of the partial programs
+linked. @var{length} is an absolute expression.
+
+@node Data, Def, Comm, Pseudo Ops
+@section @code{.data @var{subsection}}
+
+@cindex @code{data} directive
+@code{.data} tells @code{as} to assemble the following statements onto the
+end of the data subsection numbered @var{subsection} (which is an
+absolute expression). If @var{subsection} is omitted, it defaults
+to zero.
+
+@node Def, Desc, Data, Pseudo Ops
+@section @code{.def @var{name}}
+
+@cindex @code{def} directive
+@cindex COFF symbols, debugging
+@cindex debugging COFF symbols
+Begin defining debugging information for a symbol @var{name}; the
+definition extends until the @code{.endef} directive is encountered.
+
+This directive is only observed when @code{as} is configured for COFF
+format output; when producing @code{b.out}, @samp{.def} is recognized,
+but ignored.
+
+@node Desc, Dim, Def, Pseudo Ops
+@section @code{.desc @var{symbol}, @var{abs-expression}}
+
+@cindex @code{desc} directive
+@cindex COFF symbol descriptor
+@cindex symbol descriptor, COFF
+This directive sets the descriptor of the symbol (@pxref{Symbol Attributes})
+to the low 16 bits of an absolute expression.
+
+The @samp{.desc} directive is not available when @code{as} is
+configured for COFF output; it is only for @code{a.out} or @code{b.out}
+object format. For the sake of compatibility, @code{as} will accept
+it, but produce no output, when configured for COFF.
+
+@node Dim, Double, Desc, Pseudo Ops
+@section @code{.dim}
+
+@cindex @code{dim} directive
+@cindex COFF auxiliary symbol information
+@cindex auxiliary symbol information, COFF
+This directive is generated by compilers to include auxiliary debugging
+information in the symbol table. It is only permitted inside
+@code{.def}/@code{.endef} pairs.
+
+@samp{.dim} is only meaningful when generating COFF format output; when
+@code{as} is generating @code{b.out}, it accepts this directive but
+ignores it.
+
+@node Double, Eject, Dim, Pseudo Ops
+@section @code{.double @var{flonums}}
+
+@cindex @code{double} directive
+@cindex floating point numbers (double)
+@code{.double} expects zero or more flonums, separated by commas. It
+assembles floating point numbers.
+The exact kind of floating point numbers emitted depends on how
+@code{as} is configured. @xref{Machine Dependent}.
+
+@node Eject, Else, Double, Pseudo Ops
+@section @code{.eject}
+
+@cindex @code{eject} directive
+@cindex new page, in listings
+@cindex page, in listings
+@cindex listing control: new page
+Force a page break at this point, when generating assembly listings.
+
+@node Else, Endef, Eject, Pseudo Ops
+@section @code{.else}
+
+@cindex @code{else} directive
+@code{.else} is part of the @code{as} support for conditional
+assembly; @pxref{If,,@code{.if}}. It marks the beginning of a section
+of code to be assembled if the condition for the preceding @code{.if}
+was false.
+
+
+@node Endef, Endif, Else, Pseudo Ops
+@section @code{.endef}
+
+@cindex @code{endef} directive
+This directive flags the end of a symbol definition begun with
+@code{.def}.
+
+@samp{.endef} is only meaningful when generating COFF format output; if
+@code{as} is configured to generate @code{b.out}, it accepts this
+directive but ignores it.
+
+@node Endif, Equ, Endef, Pseudo Ops
+@section @code{.endif}
+
+@cindex @code{endif} directive
+@code{.endif} is part of the @code{as} support for conditional assembly;
+it marks the end of a block of code that is only assembled
+conditionally. @xref{If,,@code{.if}}.
+
+@node Equ, Extern, Endif, Pseudo Ops
+@section @code{.equ @var{symbol}, @var{expression}}
+
+@cindex @code{equ} directive
+@cindex assigning values to symbols
+@cindex symbols, assigning values to
+This directive sets the value of @var{symbol} to @var{expression}.
+It is synonymous with @samp{.set}; @pxref{Set,,@code{.set}}.
+
+@node Extern, File, Equ, Pseudo Ops
+@section @code{.extern}
+
+@cindex @code{extern} directive
+@code{.extern} is accepted in the source program---for compatibility
+with other assemblers---but it is ignored. @code{as} treats
+all undefined symbols as external.
+
+@node File, Fill, Extern, Pseudo Ops
+@section @code{.file @var{string}}
+
+@cindex @code{file} directive
+@cindex logical file name
+@cindex file name, logical
+@code{.file} (which may also be spelled @samp{.app-file}) tells
+@code{as} that we are about to start a new logical file.
+@var{string} is the new file name. In general, the filename is
+recognized whether or not it is surrounded by quotes @samp{"}; but if
+you wish to specify an empty file name, you must give the
+quotes--@code{""}. This statement may go away in future: it is only
+recognized to be compatible with old @code{as} programs.
+In some configurations of @code{as}, @code{.file} has already been
+removed to avoid conflicts with other assemblers. @xref{Machine Dependent}.
+
+@node Fill, Float, File, Pseudo Ops
+@section @code{.fill @var{repeat} , @var{size} , @var{value}}
+
+@cindex @code{fill} directive
+@cindex writing patterns in memory
+@cindex patterns, writing in memory
+@var{result}, @var{size} and @var{value} are absolute expressions.
+This emits @var{repeat} copies of @var{size} bytes. @var{Repeat}
+may be zero or more. @var{Size} may be zero or more, but if it is
+more than 8, then it is deemed to have the value 8, compatible with
+other people's assemblers. The contents of each @var{repeat} bytes
+is taken from an 8-byte number. The highest order 4 bytes are
+zero. The lowest order 4 bytes are @var{value} rendered in the
+byte-order of an integer on the computer @code{as} is assembling for.
+Each @var{size} bytes in a repetition is taken from the lowest order
+@var{size} bytes of this number. Again, this bizarre behavior is
+compatible with other people's assemblers.
+
+@var{size} and @var{value} are optional.
+If the second comma and @var{value} are absent, @var{value} is
+assumed zero. If the first comma and following tokens are absent,
+@var{size} is assumed to be 1.
+
+@node Float, Global, Fill, Pseudo Ops
+@section @code{.float @var{flonums}}
+
+@cindex floating point numbers (single)
+@cindex @code{float} directive
+This directive assembles zero or more flonums, separated by commas. It
+has the same effect as @code{.single}.
+The exact kind of floating point numbers emitted depends on how
+@code{as} is configured.
+@xref{Machine Dependent}.
+
+@node Global, hword, Float, Pseudo Ops
+@section @code{.global @var{symbol}}, @code{.globl @var{symbol}}
+
+@cindex @code{global} directive
+@cindex symbol, making visible to linker
+@code{.global} makes the symbol visible to @code{ld}. If you define
+@var{symbol} in your partial program, its value is made available to
+other partial programs that are linked with it. Otherwise,
+@var{symbol} will take its attributes from a symbol of the same name
+from another partial program it is linked with.
+
+Both spellings (@samp{.globl} and @samp{.global}) are accepted, for
+compatibility with other assemblers.
+
+@node hword, Ident, Global, Pseudo Ops
+@section @code{.hword @var{expressions}}
+
+@cindex @code{hword} directive
+@cindex integers, 16-bit
+@cindex numbers, 16-bit
+@cindex sixteen bit integers
+This expects zero or more @var{expressions}, and emits
+a 16 bit number for each.
+
+This directive is a synonym for @samp{.short}; depending on the target
+architecture, it may also be a synonym for @samp{.word}.
+
+@node Ident, If, hword, Pseudo Ops
+@section @code{.ident}
+
+@cindex @code{ident} directive
+This directive is used by some assemblers to place tags in object files.
+@code{as} simply accepts the directive for source-file
+compatibility with such assemblers, but does not actually emit anything
+for it.
+
+@node If, Include, Ident, Pseudo Ops
+@section @code{.if @var{absolute expression}}
+
+@cindex conditional assembly
+@cindex @code{if} directive
+@code{.if} marks the beginning of a section of code which is only
+considered part of the source program being assembled if the argument
+(which must be an @var{absolute expression}) is non-zero. The end of
+the conditional section of code must be marked by @code{.endif}
+(@pxref{Endif,,@code{.endif}}); optionally, you may include code for the
+alternative condition, flagged by @code{.else} (@pxref{Else,,@code{.else}}.
+
+The following variants of @code{.if} are also supported:
+@table @code
+@item .ifdef @var{symbol}
+@cindex @code{ifdef} directive
+Assembles the following section of code if the specified @var{symbol}
+has been defined.
+
+
+@item .ifndef @var{symbol}
+@itemx ifnotdef @var{symbol}
+@cindex @code{ifndef} directive
+@cindex @code{ifnotdef} directive
+Assembles the following section of code if the specified @var{symbol}
+has not been defined. Both spelling variants are equivalent.
+
+@end table
+
+@node Include, Int, If, Pseudo Ops
+@section @code{.include "@var{file}"}
+
+@cindex @code{include} directive
+@cindex supporting files, including
+@cindex files, including
+This directive provides a way to include supporting files at specified
+points in your source program. The code from @var{file} is assembled as
+if it followed the point of the @code{.include}; when the end of the
+included file is reached, assembly of the original file continues. You
+can control the search paths used with the @samp{-I} command-line option
+(@pxref{Invoking,,Command-Line Options}). Quotation marks are required
+around @var{file}.
+
+@node Int, Lcomm, Include, Pseudo Ops
+@section @code{.int @var{expressions}}
+
+@cindex @code{int} directive
+@cindex integers, 32-bit
+Expect zero or more @var{expressions}, of any section, separated by
+commas. For each expression, emit a
+32-bit
+number that will, at run
+time, be the value of that expression. The byte order of the
+expression depends on what kind of computer will run the program.
+
+@node Lcomm, Lflags, Int, Pseudo Ops
+@section @code{.lcomm @var{symbol} , @var{length}}
+
+@cindex @code{lcomm} directive
+@cindex local common symbols
+@cindex symbols, local common
+Reserve @var{length} (an absolute expression) bytes for a local common
+denoted by @var{symbol}. The section and value of @var{symbol} are
+those of the new local common. The addresses are allocated in the bss
+section, so at run-time the bytes will start off zeroed. @var{Symbol}
+is not declared global (@pxref{Global,,@code{.global}}), so is normally
+not visible to @code{ld}.
+
+@node Lflags, Line, Lcomm, Pseudo Ops
+@section @code{.lflags}
+
+@cindex @code{lflags} directive (ignored)
+@code{as} accepts this directive, for compatibility with other
+assemblers, but ignores it.
+
+@node Line, Ln, Lflags, Pseudo Ops
+@section @code{.line @var{line-number}}
+
+@cindex @code{line} directive
+@cindex logical line number
+Tell @code{as} to change the logical line number. @var{line-number} must be
+an absolute expression. The next line will have that logical line
+number. So any other statements on the current line (after a statement
+separator
+character)
+will be reported as on logical line number
+@var{line-number} @minus{} 1.
+One day this directive will be unsupported: it is used only
+for compatibility with existing assembler programs. @refill
+
+@emph{Warning:} In the AMD29K configuration of as, this command is
+only available with the name @code{.ln}, rather than as either
+@code{.line} or @code{.ln}.
+
+Even though this is a directive associated with the @code{a.out} or
+@code{b.out} object-code formats, @code{as} will still recognize it
+when producing COFF output, and will treat @samp{.line} as though it
+were the COFF @samp{.ln} @emph{if} it is found outside a
+@code{.def}/@code{.endef} pair.
+
+Inside a @code{.def}, @samp{.line} is, instead, one of the directives
+used by compilers to generate auxiliary symbol information for
+debugging.
+
+@node Ln, List, Line, Pseudo Ops
+@section @code{.ln @var{line-number}}
+
+@cindex @code{ln} directive
+@samp{.ln} is a synonym for @samp{.line}.
+
+@node List, Long, Ln, Pseudo Ops
+@section @code{.list}
+
+@cindex @code{list} directive
+@cindex listing control, turning on
+Control (in conjunction with the @code{.nolist} directive) whether or
+not assembly listings are generated. These two directives maintain an
+internal counter (which is zero initially). @code{.list} increments the
+counter, and @code{.nolist} decrements it. Assembly listings are
+generated whenever the counter is greater than zero.
+
+By default, listings are disabled. When you enable them (with the
+@samp{-a} command line option; @pxref{Invoking,,Command-Line Options}),
+the initial value of the listing counter is one.
+
+@node Long, Lsym, List, Pseudo Ops
+@section @code{.long @var{expressions}}
+
+@cindex @code{long} directive
+@code{.long} is the same as @samp{.int}, @pxref{Int,,@code{.int}}.
+
+@node Lsym, Nolist, Long, Pseudo Ops
+@section @code{.lsym @var{symbol}, @var{expression}}
+
+@cindex @code{lsym} directive
+@cindex symbol, not referenced in assembly
+@code{.lsym} creates a new symbol named @var{symbol}, but does not put it in
+the hash table, ensuring it cannot be referenced by name during the
+rest of the assembly. This sets the attributes of the symbol to be
+the same as the expression value:
+@smallexample
+@var{other} = @var{descriptor} = 0
+@var{type} = @r{(section of @var{expression})}
+@var{value} = @var{expression}
+@end smallexample
+@noindent
+The new symbol is not flagged as external.
+
+@node Nolist, Octa, Lsym, Pseudo Ops
+@section @code{.nolist}
+
+@cindex @code{nolist} directive
+@cindex listing control, turning off
+Control (in conjunction with the @code{.list} directive) whether or
+not assembly listings are generated. These two directives maintain an
+internal counter (which is zero initially). @code{.list} increments the
+counter, and @code{.nolist} decrements it. Assembly listings are
+generated whenever the counter is greater than zero.
+
+@node Octa, Org, Nolist, Pseudo Ops
+@section @code{.octa @var{bignums}}
+
+@c FIXME: double size emitted for "octa" on i960, others? Or warn?
+@cindex @code{octa} directive
+@cindex integer, 16-byte
+@cindex sixteen byte integer
+This directive expects zero or more bignums, separated by commas. For each
+bignum, it emits a 16-byte integer.
+
+The term ``octa'' comes from contexts in which a ``word'' is two bytes;
+hence @emph{octa}-word for 16 bytes.
+
+@node Org, Psize, Octa, Pseudo Ops
+@section @code{.org @var{new-lc} , @var{fill}}
+
+@cindex @code{org} directive
+@cindex location counter, advancing
+@cindex advancing location counter
+@cindex current address, advancing
+@code{.org} will advance the location counter of the current section to
+@var{new-lc}. @var{new-lc} is either an absolute expression or an
+expression with the same section as the current subsection. That is,
+you can't use @code{.org} to cross sections: if @var{new-lc} has the
+wrong section, the @code{.org} directive is ignored. To be compatible
+with former assemblers, if the section of @var{new-lc} is absolute,
+@code{as} will issue a warning, then pretend the section of @var{new-lc}
+is the same as the current subsection.
+
+@code{.org} may only increase the location counter, or leave it
+unchanged; you cannot use @code{.org} to move the location counter
+backwards.
+
+@c double negative used below "not undefined" because this is a specific
+@c reference to "undefined" (as SEG_UNKNOWN is called in this manual)
+@c section. pesch@cygnus.com 18feb91
+Because @code{as} tries to assemble programs in one pass @var{new-lc}
+may not be undefined. If you really detest this restriction we eagerly await
+a chance to share your improved assembler.
+
+Beware that the origin is relative to the start of the section, not
+to the start of the subsection. This is compatible with other
+people's assemblers.
+
+When the location counter (of the current subsection) is advanced, the
+intervening bytes are filled with @var{fill} which should be an
+absolute expression. If the comma and @var{fill} are omitted,
+@var{fill} defaults to zero.
+
+@node Psize, Quad, Org, Pseudo Ops
+@section @code{.psize @var{lines} , @var{columns}}
+
+@cindex @code{psize} directive
+@cindex listing control: paper size
+@cindex paper size, for listings
+Use this directive to declare the number of lines---and, optionally, the
+number of columns---to use for each page, when generating listings.
+
+If you don't use @code{.psize}, listings will use a default line-count
+of 60. You may omit the comma and @var{columns} specification; the
+default width is 200 columns.
+
+@code{as} will generate formfeeds whenever the specified number of
+lines is exceeded (or whenever you explicitly request one, using
+@code{.eject}).
+
+If you specify @var{lines} as @code{0}, no formfeeds are generated save
+those explicitly specified with @code{.eject}.
+
+@node Quad, Sbttl, Psize, Pseudo Ops
+@section @code{.quad @var{bignums}}
+
+@cindex @code{quad} directive
+@code{.quad} expects zero or more bignums, separated by commas. For
+each bignum, it emits
+an 8-byte integer. If the bignum won't fit in 8
+bytes, it prints a warning message; and just takes the lowest order 8
+bytes of the bignum.@refill
+@cindex eight-byte integer
+@cindex integer, 8-byte
+
+The term ``quad'' comes from contexts in which a ``word'' is two bytes;
+hence @emph{quad}-word for 8 bytes.
+
+@node Sbttl, Scl, Quad, Pseudo Ops
+@section @code{.sbttl "@var{subheading}"}
+
+@cindex @code{sbttl} directive
+@cindex subtitles for listings
+@cindex listing control: subtitle
+Use @var{subheading} as the title (third line, immediately after the
+title line) when generating assembly listings.
+
+This directive affects subsequent pages, as well as the current page if
+it appears within ten lines of the top of a page.
+
+@node Scl, Section, Sbttl, Pseudo Ops
+@section @code{.scl @var{class}}
+
+@cindex @code{scl} directive
+@cindex symbol storage class (COFF)
+@cindex COFF symbol storage class
+Set the storage-class value for a symbol. This directive may only be
+used inside a @code{.def}/@code{.endef} pair. Storage class may flag
+whether a symbol is static or external, or it may record further
+symbolic debugging information.
+
+The @samp{.scl} directive is primarily associated with COFF output; when
+configured to generate @code{b.out} output format, @code{as} will
+accept this directive but ignore it.
+
+@node Section, Set, Scl, Pseudo Ops
+@section @code{.section @var{name}, @var{subsection}}
+
+@cindex @code{section} directive
+@cindex named section (COFF)
+@cindex COFF named section
+Assemble the following code into end of subsection numbered
+@var{subsection} in the COFF named section @var{name}. If you omit
+@var{subsection}, @code{as} uses subsection number zero.
+@samp{.section .text} is equivalent to the @code{.text} directive;
+@samp{.section .data} is equivalent to the @code{.data} directive.
+
+@node Set, Short, Section, Pseudo Ops
+@section @code{.set @var{symbol}, @var{expression}}
+
+@cindex @code{set} directive
+@cindex symbol value, setting
+This directive sets the value of @var{symbol} to @var{expression}. This
+will change @var{symbol}'s value and type to conform to
+@var{expression}. If @var{symbol} was flagged as external, it remains
+flagged. (@xref{Symbol Attributes}.)
+
+You may @code{.set} a symbol many times in the same assembly.
+If the expression's section is unknowable during pass 1, a second
+pass over the source program will be forced. The second pass is
+currently not implemented. @code{as} will abort with an error
+message if one is required.
+
+If you @code{.set} a global symbol, the value stored in the object
+file is the last value stored into it.
+
+@node Short, Single, Set, Pseudo Ops
+@section @code{.short @var{expressions}}
+
+@cindex @code{short} directive
+@code{.short} is the same as @samp{.word}. @xref{Word,,@code{.word}}.
+@node Single, Size, Short, Pseudo Ops
+@section @code{.single @var{flonums}}
+
+@cindex @code{single} directive
+@cindex floating point numbers (single)
+This directive assembles zero or more flonums, separated by commas. It
+has the same effect as @code{.float}.
+The exact kind of floating point numbers emitted depends on how
+@code{as} is configured. @xref{Machine Dependent}.
+
+@node Size, Space, Single, Pseudo Ops
+@section @code{.size}
+
+@cindex @code{size} directive
+This directive is generated by compilers to include auxiliary debugging
+information in the symbol table. It is only permitted inside
+@code{.def}/@code{.endef} pairs.
+
+@samp{.size} is only meaningful when generating COFF format output; when
+@code{as} is generating @code{b.out}, it accepts this directive but
+ignores it.
+
+@node Space, Stab, Size, Pseudo Ops
+@section @code{.space @var{size} , @var{fill}}
+
+@cindex @code{space} directive
+@cindex filling memory
+This directive emits @var{size} bytes, each of value @var{fill}. Both
+@var{size} and @var{fill} are absolute expressions. If the comma
+and @var{fill} are omitted, @var{fill} is assumed to be zero.
+
+@section @code{.space}
+
+@cindex @code{space} directive
+On the AMD 29K, this directive is ignored; it is accepted for
+compatibility with other AMD 29K assemblers.
+
+@quotation
+@emph{Warning:} In other versions of the GNU assembler, the directive
+@code{.space} has the effect of @code{.block} @xref{Machine Dependent}.
+@end quotation
+
+@node Stab, Tag, Space, Pseudo Ops
+@section @code{.stabd, .stabn, .stabs}
+
+@cindex symbolic debuggers, information for
+@cindex @code{stab@var{x}} directives
+There are three directives that begin @samp{.stab}.
+All emit symbols (@pxref{Symbols}), for use by symbolic debuggers.
+The symbols are not entered in the @code{as} hash table: they
+cannot be referenced elsewhere in the source file.
+Up to five fields are required:
+@table @var
+@item string
+This is the symbol's name. It may contain any character except @samp{\000},
+so is more general than ordinary symbol names. Some debuggers used to
+code arbitrarily complex structures into symbol names using this field.
+@item type
+An absolute expression. The symbol's type is set to the low 8
+bits of this expression.
+Any bit pattern is permitted, but @code{ld} and debuggers will choke on
+silly bit patterns.
+@item other
+An absolute expression.
+The symbol's ``other'' attribute is set to the low 8 bits of this expression.
+@item desc
+An absolute expression.
+The symbol's descriptor is set to the low 16 bits of this expression.
+@item value
+An absolute expression which becomes the symbol's value.
+@end table
+
+If a warning is detected while reading a @code{.stabd}, @code{.stabn},
+or @code{.stabs} statement, the symbol has probably already been created
+and you will get a half-formed symbol in your object file. This is
+compatible with earlier assemblers!
+
+@table @code
+@cindex @code{stabd} directive
+@item .stabd @var{type} , @var{other} , @var{desc}
+
+The ``name'' of the symbol generated is not even an empty string.
+It is a null pointer, for compatibility. Older assemblers used a
+null pointer so they didn't waste space in object files with empty
+strings.
+
+The symbol's value is set to the location counter,
+relocatably. When your program is linked, the value of this symbol
+will be where the location counter was when the @code{.stabd} was
+assembled.
+
+@item .stabn @var{type} , @var{other} , @var{desc} , @var{value}
+@cindex @code{stabn} directive
+The name of the symbol is set to the empty string @code{""}.
+
+@item .stabs @var{string} , @var{type} , @var{other} , @var{desc} , @var{value}
+@cindex @code{stabs} directive
+All five fields are specified.
+@end table
+
+@node Tag, Text, Stab, Pseudo Ops
+@section @code{.tag @var{structname}}
+
+@cindex COFF structure debugging
+@cindex structure debugging, COFF
+@cindex @code{tag} directive
+This directive is generated by compilers to include auxiliary debugging
+information in the symbol table. It is only permitted inside
+@code{.def}/@code{.endef} pairs. Tags are used to link structure
+definitions in the symbol table with instances of those structures.
+
+@samp{.tag} is only used when generating COFF format output; when
+@code{as} is generating @code{b.out}, it accepts this directive but
+ignores it.
+
+@node Text, Title, Tag, Pseudo Ops
+@section @code{.text @var{subsection}}
+
+@cindex @code{text} directive
+Tells @code{as} to assemble the following statements onto the end of
+the text subsection numbered @var{subsection}, which is an absolute
+expression. If @var{subsection} is omitted, subsection number zero
+is used.
+
+@node Title, Type, Text, Pseudo Ops
+@section @code{.title "@var{heading}"}
+
+@cindex @code{title} directive
+@cindex listing control: title line
+Use @var{heading} as the title (second line, immediately after the
+source file name and pagenumber) when generating assembly listings.
+
+This directive affects subsequent pages, as well as the current page if
+it appears within ten lines of the top of a page.
+
+@node Type, Val, Title, Pseudo Ops
+@section @code{.type @var{int}}
+
+@cindex COFF symbol type
+@cindex symbol type, COFF
+@cindex @code{type} directive
+This directive, permitted only within @code{.def}/@code{.endef} pairs,
+records the integer @var{int} as the type attribute of a symbol table entry.
+
+@samp{.type} is associated only with COFF format output; when
+@code{as} is configured for @code{b.out} output, it accepts this
+directive but ignores it.
+
+@node Val, Word, Type, Pseudo Ops
+@section @code{.val @var{addr}}
+
+@cindex @code{val} directive
+@cindex COFF value attribute
+@cindex value attribute, COFF
+This directive, permitted only within @code{.def}/@code{.endef} pairs,
+records the address @var{addr} as the value attribute of a symbol table
+entry.
+
+@samp{.val} is used only for COFF output; when @code{as} is
+configured for @code{b.out}, it accepts this directive but ignores it.
+
+@node Word, Deprecated, Val, Pseudo Ops
+@section @code{.word @var{expressions}}
+
+@cindex @code{word} directive
+This directive expects zero or more @var{expressions}, of any section,
+separated by commas.
+
+The size of the number emitted, and its byte order,
+depends on what kind of computer will run the program.
+
+@c on amd29k, i960, sparc the "special treatment to support compilers" doesn't
+@c happen---32-bit addressability, period; no long/short jumps.
+@cindex difference tables altered
+@cindex altered difference tables
+@quotation
+@emph{Warning: Special Treatment to support Compilers}
+@end quotation
+
+Machines with a 32-bit address space, but that do less than 32-bit
+addressing, require the following special treatment. If the machine of
+interest to you does 32-bit addressing (or doesn't require it;
+@pxref{Machine Dependent}), you can ignore this issue.
+
+In order to assemble compiler output into something that will work,
+@code{as} will occasionlly do strange things to @samp{.word} directives.
+Directives of the form @samp{.word sym1-sym2} are often emitted by
+compilers as part of jump tables. Therefore, when @code{as} assembles a
+directive of the form @samp{.word sym1-sym2}, and the difference between
+@code{sym1} and @code{sym2} does not fit in 16 bits, @code{as} will
+create a @dfn{secondary jump table}, immediately before the next label.
+This secondary jump table will be preceded by a short-jump to the
+first byte after the secondary table. This short-jump prevents the flow
+of control from accidentally falling into the new table. Inside the
+table will be a long-jump to @code{sym2}. The original @samp{.word}
+will contain @code{sym1} minus the address of the long-jump to
+@code{sym2}.
+
+If there were several occurrences of @samp{.word sym1-sym2} before the
+secondary jump table, all of them will be adjusted. If there was a
+@samp{.word sym3-sym4}, that also did not fit in sixteen bits, a
+long-jump to @code{sym4} will be included in the secondary jump table,
+and the @code{.word} directives will be adjusted to contain @code{sym3}
+minus the address of the long-jump to @code{sym4}; and so on, for as many
+entries in the original jump table as necessary.
+
+
+@node Deprecated, , Word, Pseudo Ops
+@section Deprecated Directives
+
+@cindex deprecated directives
+@cindex obsolescent directives
+One day these directives won't work.
+They are included for compatibility with older assemblers.
+@table @t
+@item .abort
+@item .app-file
+@item .line
+@end table
+
+@node Machine Dependent, Copying, Pseudo Ops, Top
+@chapter Machine Dependent Features
+
+@cindex machine dependencies
+The machine instruction sets are (almost by definition) different on
+each machine where @code{as} runs. Floating point representations
+vary as well, and @code{as} often supports a few additional
+directives or command-line options for compatibility with other
+assemblers on a particular platform. Finally, some versions of
+@code{as} support special pseudo-instructions for branch
+optimization.
+
+This chapter discusses most of these differences, though it does not
+include details on any machine's instruction set. For details on that
+subject, see the hardware manufacturer's manual.
+
+@menu
+* Vax-Dependent:: VAX Dependent Features
+* AMD29K-Dependent:: AMD 29K Dependent Features
+* H8/300-Dependent:: AMD 29K Dependent Features
+* i960-Dependent:: Intel 80960 Dependent Features
+* M68K-Dependent:: M680x0 Dependent Features
+* Sparc-Dependent:: SPARC Dependent Features
+* i386-Dependent:: 80386 Dependent Features
+@end menu
+
+@node Vax-Dependent, AMD29K-Dependent, Machine Dependent, Machine Dependent
+@section VAX Dependent Features
+
+@cindex VAX support
+@menu
+* Vax-Opts:: VAX Command-Line Options
+* VAX-float:: VAX Floating Point
+* VAX-directives:: Vax Machine Directives
+* VAX-opcodes:: VAX Opcodes
+* VAX-branch:: VAX Branch Improvement
+* VAX-operands:: VAX Operands
+* VAX-no:: Not Supported on VAX
+@end menu
+
+@node Vax-Opts, VAX-float, Vax-Dependent, Vax-Dependent
+@subsection VAX Command-Line Options
+
+@cindex command-line options ignored, VAX
+@cindex VAX command-line options ignored
+The Vax version of @code{as} accepts any of the following options,
+gives a warning message that the option was ignored and proceeds.
+These options are for compatibility with scripts designed for other
+people's assemblers.
+
+@table @asis
+@item @kbd{-D} (Debug)
+@itemx @kbd{-S} (Symbol Table)
+@itemx @kbd{-T} (Token Trace)
+@cindex @code{-D}, ignored on VAX
+@cindex @code{-S}, ignored on VAX
+@cindex @code{-T}, ignored on VAX
+These are obsolete options used to debug old assemblers.
+
+@item @kbd{-d} (Displacement size for JUMPs)
+@cindex @code{-d}, VAX option
+This option expects a number following the @kbd{-d}. Like options
+that expect filenames, the number may immediately follow the
+@kbd{-d} (old standard) or constitute the whole of the command line
+argument that follows @kbd{-d} (GNU standard).
+
+@item @kbd{-V} (Virtualize Interpass Temporary File)
+@cindex @code{-V}, redundant on VAX
+Some other assemblers use a temporary file. This option
+commanded them to keep the information in active memory rather
+than in a disk file. @code{as} always does this, so this
+option is redundant.
+
+@item @kbd{-J} (JUMPify Longer Branches)
+@cindex @code{-J}, ignored on VAX
+Many 32-bit computers permit a variety of branch instructions
+to do the same job. Some of these instructions are short (and
+fast) but have a limited range; others are long (and slow) but
+can branch anywhere in virtual memory. Often there are 3
+flavors of branch: short, medium and long. Some other
+assemblers would emit short and medium branches, unless told by
+this option to emit short and long branches.
+
+@item @kbd{-t} (Temporary File Directory)
+@cindex @code{-t}, ignored on VAX
+Some other assemblers may use a temporary file, and this option
+takes a filename being the directory to site the temporary
+file. @code{as} does not use a temporary disk file, so this
+option makes no difference. @kbd{-t} needs exactly one
+filename.
+@end table
+
+@cindex VMS (VAX) options
+@cindex options for VAX/VMS
+@cindex VAX/VMS options
+@cindex @code{-h} option, VAX/VMS
+@cindex @code{-+} option, VAX/VMS
+@cindex Vax-11 C compatibility
+@cindex symbols with lowercase, VAX/VMS
+@c FIXME! look into "I think" below, correct if needed, delete.
+The Vax version of the assembler accepts two options when
+compiled for VMS. They are @kbd{-h}, and @kbd{-+}. The
+@kbd{-h} option prevents @code{as} from modifying the
+symbol-table entries for symbols that contain lowercase
+characters (I think). The @kbd{-+} option causes @code{as} to
+print warning messages if the FILENAME part of the object file,
+or any symbol name is larger than 31 characters. The @kbd{-+}
+option also insertes some code following the @samp{_main}
+symbol so that the object file will be compatible with Vax-11
+"C".
+
+@node VAX-float, VAX-directives, Vax-Opts, Vax-Dependent
+@subsection VAX Floating Point
+
+@cindex VAX floating point
+@cindex floating point, VAX
+Conversion of flonums to floating point is correct, and
+compatible with previous assemblers. Rounding is
+towards zero if the remainder is exactly half the least significant bit.
+
+@code{D}, @code{F}, @code{G} and @code{H} floating point formats
+are understood.
+
+Immediate floating literals (@emph{e.g.} @samp{S`$6.9})
+are rendered correctly. Again, rounding is towards zero in the
+boundary case.
+
+@cindex @code{float} directive, VAX
+@cindex @code{double} directive, VAX
+The @code{.float} directive produces @code{f} format numbers.
+The @code{.double} directive produces @code{d} format numbers.
+
+@node VAX-directives, VAX-opcodes, VAX-float, Vax-Dependent
+@subsection Vax Machine Directives
+
+@cindex machine directives, VAX
+@cindex VAX machine directives
+The Vax version of the assembler supports four directives for
+generating Vax floating point constants. They are described in the
+table below.
+
+@cindex wide floating point directives, VAX
+@table @code
+@item .dfloat
+@cindex @code{dfloat} directive, VAX
+This expects zero or more flonums, separated by commas, and
+assembles Vax @code{d} format 64-bit floating point constants.
+
+@item .ffloat
+@cindex @code{ffloat} directive, VAX
+This expects zero or more flonums, separated by commas, and
+assembles Vax @code{f} format 32-bit floating point constants.
+
+@item .gfloat
+@cindex @code{gfloat} directive, VAX
+This expects zero or more flonums, separated by commas, and
+assembles Vax @code{g} format 64-bit floating point constants.
+
+@item .hfloat
+@cindex @code{hfloat} directive, VAX
+This expects zero or more flonums, separated by commas, and
+assembles Vax @code{h} format 128-bit floating point constants.
+
+@end table
+
+@node VAX-opcodes, VAX-branch, VAX-directives, Vax-Dependent
+@subsection VAX Opcodes
+
+@cindex VAX opcode mnemonics
+@cindex opcode mnemonics, VAX
+@cindex mnemonics for opcodes, VAX
+All DEC mnemonics are supported. Beware that @code{case@dots{}}
+instructions have exactly 3 operands. The dispatch table that
+follows the @code{case@dots{}} instruction should be made with
+@code{.word} statements. This is compatible with all unix
+assemblers we know of.
+
+@node VAX-branch, VAX-operands, VAX-opcodes, Vax-Dependent
+@subsection VAX Branch Improvement
+
+@cindex VAX branch improvement
+@cindex branch improvement, VAX
+@cindex pseudo-ops for branch, VAX
+Certain pseudo opcodes are permitted. They are for branch
+instructions. They expand to the shortest branch instruction that
+will reach the target. Generally these mnemonics are made by
+substituting @samp{j} for @samp{b} at the start of a DEC mnemonic.
+This feature is included both for compatibility and to help
+compilers. If you don't need this feature, don't use these
+opcodes. Here are the mnemonics, and the code they can expand into.
+
+@table @code
+@item jbsb
+@samp{Jsb} is already an instruction mnemonic, so we chose @samp{jbsb}.
+@table @asis
+@item (byte displacement)
+@kbd{bsbb @dots{}}
+@item (word displacement)
+@kbd{bsbw @dots{}}
+@item (long displacement)
+@kbd{jsb @dots{}}
+@end table
+@item jbr
+@itemx jr
+Unconditional branch.
+@table @asis
+@item (byte displacement)
+@kbd{brb @dots{}}
+@item (word displacement)
+@kbd{brw @dots{}}
+@item (long displacement)
+@kbd{jmp @dots{}}
+@end table
+@item j@var{COND}
+@var{COND} may be any one of the conditional branches
+@code{neq nequ eql eqlu gtr geq lss gtru lequ vc vs gequ cc lssu cs}.
+@var{COND} may also be one of the bit tests
+@code{bs bc bss bcs bsc bcc bssi bcci lbs lbc}.
+@var{NOTCOND} is the opposite condition to @var{COND}.
+@table @asis
+@item (byte displacement)
+@kbd{b@var{COND} @dots{}}
+@item (word displacement)
+@kbd{b@var{NOTCOND} foo ; brw @dots{} ; foo:}
+@item (long displacement)
+@kbd{b@var{NOTCOND} foo ; jmp @dots{} ; foo:}
+@end table
+@item jacb@var{X}
+@var{X} may be one of @code{b d f g h l w}.
+@table @asis
+@item (word displacement)
+@kbd{@var{OPCODE} @dots{}}
+@item (long displacement)
+@example
+@var{OPCODE} @dots{}, foo ;
+brb bar ;
+foo: jmp @dots{} ;
+bar:
+@end example
+@end table
+@item jaob@var{YYY}
+@var{YYY} may be one of @code{lss leq}.
+@item jsob@var{ZZZ}
+@var{ZZZ} may be one of @code{geq gtr}.
+@table @asis
+@item (byte displacement)
+@kbd{@var{OPCODE} @dots{}}
+@item (word displacement)
+@example
+@var{OPCODE} @dots{}, foo ;
+brb bar ;
+foo: brw @var{destination} ;
+bar:
+@end example
+@item (long displacement)
+@example
+@var{OPCODE} @dots{}, foo ;
+brb bar ;
+foo: jmp @var{destination} ;
+bar:
+@end example
+@end table
+@item aobleq
+@itemx aoblss
+@itemx sobgeq
+@itemx sobgtr
+@table @asis
+@item (byte displacement)
+@kbd{@var{OPCODE} @dots{}}
+@item (word displacement)
+@example
+@var{OPCODE} @dots{}, foo ;
+brb bar ;
+foo: brw @var{destination} ;
+bar:
+@end example
+@item (long displacement)
+@example
+@var{OPCODE} @dots{}, foo ;
+brb bar ;
+foo: jmp @var{destination} ;
+bar:
+@end example
+@end table
+@end table
+
+@node VAX-operands, VAX-no, VAX-branch, Vax-Dependent
+@subsection VAX Operands
+
+@cindex VAX operand notation
+@cindex operand notation, VAX
+@cindex immediate character, VAX
+@cindex VAX immediate character
+The immediate character is @samp{$} for Unix compatibility, not
+@samp{#} as DEC writes it.
+
+@cindex indirect character, VAX
+@cindex VAX indirect character
+The indirect character is @samp{*} for Unix compatibility, not
+@samp{@@} as DEC writes it.
+
+@cindex displacement sizing character, VAX
+@cindex VAX displacement sizing character
+The displacement sizing character is @samp{`} (an accent grave) for
+Unix compatibility, not @samp{^} as DEC writes it. The letter
+preceding @samp{`} may have either case. @samp{G} is not
+understood, but all other letters (@code{b i l s w}) are understood.
+
+@cindex register names, VAX
+@cindex VAX register names
+Register names understood are @code{r0 r1 r2 @dots{} r15 ap fp sp
+pc}. Any case of letters will do.
+
+For instance
+@smallexample
+tstb *w`$4(r5)
+@end smallexample
+
+Any expression is permitted in an operand. Operands are comma
+separated.
+
+@c There is some bug to do with recognizing expressions
+@c in operands, but I forget what it is. It is
+@c a syntax clash because () is used as an address mode
+@c and to encapsulate sub-expressions.
+
+@node VAX-no, , VAX-operands, Vax-Dependent
+@subsection Not Supported on VAX
+
+@cindex VAX bitfields not supported
+@cindex bitfields, not supported on VAX
+Vax bit fields can not be assembled with @code{as}. Someone
+can add the required code if they really need it.
+
+@node AMD29K-Dependent, H8/300-Dependent, Vax-Dependent, Machine Dependent
+@section AMD 29K Dependent Features
+
+@cindex AMD 29K support
+@cindex 29K support
+@menu
+* AMD29K Options:: Options
+* AMD29K Syntax:: Syntax
+* AMD29K Floating Point:: Floating Point
+* AMD29K Directives:: AMD 29K Machine Directives
+* AMD29K Opcodes:: Opcodes
+@end menu
+
+@node AMD29K Options, AMD29K Syntax, AMD29K-Dependent, AMD29K-Dependent
+@subsection Options
+@cindex AMD 29K options (none)
+@cindex options for AMD29K (none)
+@code{as} has no additional command-line options for the AMD
+29K family.
+
+@node AMD29K Syntax, AMD29K Floating Point, AMD29K Options, AMD29K-Dependent
+@subsection Syntax
+@menu
+* AMD29K-Chars:: Special Characters
+* AMD29K-Regs:: Register Names
+@end menu
+
+@node AMD29K-Chars, AMD29K-Regs, AMD29K Syntax, AMD29K Syntax
+@subsubsection Special Characters
+
+@cindex line comment character, AMD 29K
+@cindex AMD 29K line comment character
+@samp{;} is the line comment character.
+
+@cindex line separator, AMD 29K
+@cindex AMD 29K line separator
+@cindex statement separator, AMD 29K
+@cindex AMD 29K statement separator
+@samp{@@} can be used instead of a newline to separate statements.
+
+@cindex identifiers, AMD 29K
+@cindex AMD 29K identifiers
+The character @samp{?} is permitted in identifiers (but may not begin
+an identifier).
+
+@node AMD29K-Regs, , AMD29K-Chars, AMD29K Syntax
+@subsubsection Register Names
+
+@cindex AMD 29K register names
+@cindex register names, AMD 29K
+General-purpose registers are represented by predefined symbols of the
+form @samp{GR@var{nnn}} (for global registers) or @samp{LR@var{nnn}}
+(for local registers), where @var{nnn} represents a number between
+@code{0} and @code{127}, written with no leading zeros. The leading
+letters may be in either upper or lower case; for example, @samp{gr13}
+and @samp{LR7} are both valid register names.
+
+You may also refer to general-purpose registers by specifying the
+register number as the result of an expression (prefixed with @samp{%%}
+to flag the expression as a register number):
+@smallexample
+%%@var{expression}
+@end smallexample
+@noindent
+---where @var{expression} must be an absolute expression evaluating to a
+number between @code{0} and @code{255}. The range [0, 127] refers to
+global registers, and the range [128, 255] to local registers.
+
+@cindex special purpose registers, AMD 29K
+@cindex AMD 29K special purpose registers
+@cindex protected registers, AMD 29K
+@cindex AMD 29K protected registers
+In addition, @code{as} understands the following protected
+special-purpose register names for the AMD 29K family:
+
+@smallexample
+ vab chd pc0
+ ops chc pc1
+ cps rbp pc2
+ cfg tmc mmu
+ cha tmr lru
+@end smallexample
+
+These unprotected special-purpose register names are also recognized:
+@smallexample
+ ipc alu fpe
+ ipa bp inte
+ ipb fc fps
+ q cr exop
+@end smallexample
+
+@node AMD29K Floating Point, AMD29K Directives, AMD29K Syntax, AMD29K-Dependent
+@subsection Floating Point
+
+@cindex floating point, AMD 29K (@sc{ieee})
+@cindex AMD 29K floating point (@sc{ieee})
+The AMD 29K family uses @sc{ieee} floating-point numbers.
+
+@node AMD29K Directives, AMD29K Opcodes, AMD29K Floating Point, AMD29K-Dependent
+@subsection AMD 29K Machine Directives
+
+@cindex machine directives, AMD 29K
+@cindex AMD 29K machine directives
+@table @code
+@item .block @var{size} , @var{fill}
+@cindex @code{block} directive, AMD 29K
+This directive emits @var{size} bytes, each of value @var{fill}. Both
+@var{size} and @var{fill} are absolute expressions. If the comma
+and @var{fill} are omitted, @var{fill} is assumed to be zero.
+
+In other versions of the GNU assembler, this directive is called
+@samp{.space}.
+@end table
+
+@table @code
+@item .cputype
+@cindex @code{cputype} directive, AMD 29K
+This directive is ignored; it is accepted for compatibility with other
+AMD 29K assemblers.
+
+@item .file
+@cindex @code{file} directive, AMD 29K
+This directive is ignored; it is accepted for compatibility with other
+AMD 29K assemblers.
+
+@quotation
+@emph{Warning:} in other versions of the GNU assembler, @code{.file} is
+used for the directive called @code{.app-file} in the AMD 29K support.
+@end quotation
+
+@item .line
+@cindex @code{line} directive, AMD 29K
+This directive is ignored; it is accepted for compatibility with other
+AMD 29K assemblers.
+
+@item .reg @var{symbol}, @var{expression}
+@cindex @code{reg} directive, AMD 29K
+@code{.reg} has the same effect as @code{.lsym}; @pxref{Lsym,,@code{.lsym}}.
+
+@item .sect
+@cindex @code{sect} directive, AMD 29K
+This directive is ignored; it is accepted for compatibility with other
+AMD 29K assemblers.
+
+@item .use @var{section name}
+@cindex @code{use} directive, AMD 29K
+Establishes the section and subsection for the following code;
+@var{section name} may be one of @code{.text}, @code{.data},
+@code{.data1}, or @code{.lit}. With one of the first three @var{section
+name} options, @samp{.use} is equivalent to the machine directive
+@var{section name}; the remaining case, @samp{.use .lit}, is the same as
+@samp{.data 200}.
+@end table
+
+@node AMD29K Opcodes, , AMD29K Directives, AMD29K-Dependent
+@subsection Opcodes
+
+@cindex AMD 29K opcodes
+@cindex opcodes for AMD 29K
+@code{as} implements all the standard AMD 29K opcodes. No
+additional pseudo-instructions are needed on this family.
+
+For information on the 29K machine instruction set, see @cite{Am29000
+User's Manual}, Advanced Micro Devices, Inc.
+
+@node H8/300-Dependent, i960-Dependent, AMD29K-Dependent, Machine Dependent
+@section H8/300 Dependent Features
+
+@cindex H8/300 support
+@menu
+* H8/300 Options:: Options
+* H8/300 Syntax:: Syntax
+* H8/300 Floating Point:: Floating Point
+* H8/300 Directives:: H8/300 Machine Directives
+* H8/300 Opcodes:: Opcodes
+@end menu
+
+@node H8/300 Options, H8/300 Syntax, H8/300-Dependent, H8/300-Dependent
+@subsection Options
+
+@cindex H8/300 options (none)
+@cindex options, H8/300 (none)
+@code{as} has no additional command-line options for the Hitachi
+H8/300 family.
+
+@node H8/300 Syntax, H8/300 Floating Point, H8/300 Options, H8/300-Dependent
+@subsection Syntax
+@menu
+* H8/300-Chars:: Special Characters
+* H8/300-Regs:: Register Names
+* H8/300-Addressing:: Addressing Modes
+@end menu
+
+@node H8/300-Chars, H8/300-Regs, H8/300 Syntax, H8/300 Syntax
+@subsubsection Special Characters
+
+@cindex line comment character, H8/300
+@cindex H8/300 line comment character
+@samp{;} is the line comment character.
+
+@cindex line separator, H8/300
+@cindex statement separator, H8/300
+@cindex H8/300 line separator
+@samp{$} can be used instead of a newline to separate statements.
+Therefore @emph{you may not use @samp{$} in symbol names} on the H8/300.
+
+@node H8/300-Regs, H8/300-Addressing, H8/300-Chars, H8/300 Syntax
+@subsubsection Register Names
+
+@cindex H8/300 registers
+@cindex registers, H8/300
+You can use predefined symbols of the form @samp{r@var{n}h} and
+@samp{r@var{n}l} to refer to the H8/300 registers as sixteen 8-bit
+general-purpose registers. @var{n} is a digit from @samp{0} to
+@samp{7}); for instance, both @samp{r0h} and @samp{r7l} are valid
+register names.
+
+You can also use the eight predefined symbols @samp{r@var{n}} to refer
+to the H8/300 registers as 16-bit registers (you must use this form for
+addressing).
+
+The two control registers are called @code{pc} (program counter; a
+16-bit register) and @code{ccr} (condition code register; an 8-bit
+register). @code{r7} is used as the stack pointer, and can also be
+called @code{sp}.
+
+@node H8/300-Addressing, , H8/300-Regs, H8/300 Syntax
+@subsubsection Addressing Modes
+
+@cindex addressing modes, H8/300
+@cindex H8/300 addressing modes
+as understands the following addressing modes for the H8/300:
+@table @code
+@item r@var{n}
+Register direct
+
+@item @@r@var{n}
+Register indirect
+
+@item @@(@var{d}, r@var{n})
+@itemx @@(@var{d}:16, r@var{n})
+Register indirect: 16-bit displacement @var{d} from register @var{n}.
+(You may specify the @samp{:16} for clarity if you wish, but it is not
+required and has no effect.)
+
+@item @@r@var{n}+
+Register indirect with post-increment
+
+@item @@-r@var{n}
+Register indirect with pre-decrement
+
+@item @code{@@}@var{aa}
+@itemx @code{@@}@var{aa}:8
+@itemx @code{@@}@var{aa}:16
+Absolute address @code{aa}. You may specify the @samp{:8} or @samp{:16}
+for clarity, if you wish; but @code{as} neither requires this nor
+uses it---the address size required is taken from context.
+
+@item #@var{xx}
+@itemx #@var{xx}:8
+@itemx #@var{xx}:16
+Immediate data @var{xx}. You may specify the @samp{:8} or @samp{:16}
+for clarity, if you wish; but @code{as} neither requires this nor
+uses it---the data size required is taken from context.
+
+@item @code{@@}@code{@@}@var{aa}
+@itemx @code{@@}@code{@@}@var{aa}:8
+Memory indirect. You may specify the @samp{:8} for clarity, if you
+wish; but @code{as} neither requires this nor uses it.
+@end table
+
+@node H8/300 Floating Point, H8/300 Directives, H8/300 Syntax, H8/300-Dependent
+@subsection Floating Point
+
+@cindex floating point, H8/300 (@sc{ieee})
+@cindex H8/300 floating point (@sc{ieee})
+The H8/300 family uses @sc{ieee} floating-point numbers.
+
+@node H8/300 Directives, H8/300 Opcodes, H8/300 Floating Point, H8/300-Dependent
+@subsection H8/300 Machine Directives
+
+@cindex H8/300 machine directives (none)
+@cindex machine directives, H8/300 (none)
+@cindex @code{word} directive, H8/300
+@cindex @code{int} directive, H8/300
+@code{as} has no machine-dependent directives for the H8/300.
+However, on this platform the @samp{.int} and @samp{.word} directives
+generate 16-bit numbers.
+
+@node H8/300 Opcodes, , H8/300 Directives, H8/300-Dependent
+@subsection Opcodes
+
+@cindex H8/300 opcode summary
+@cindex opcode summary, H8/300
+@cindex mnemonics, H8/300
+@cindex instruction summary, H8/300
+For detailed information on the H8/300 machine instruction set, see
+@cite{H8/300 Series Programming Manual} (Hitachi ADE--602--025).
+
+@code{as} implements all the standard H8/300 opcodes. No additional
+pseudo-instructions are needed on this family.
+
+The following table summarizes the opcodes and their arguments:
+@c kluge due to lack of group outside example
+@page
+@smallexample
+@group
+ Rs @r{source register}
+ Rd @r{destination register}
+ imm @r{immediate data}
+ x:3 @r{a bit (as a number between 0 and 7)}
+ d:8 @r{eight bit displacement from @code{pc}}
+ d:16 @r{sixteen bit displacement from @code{Rs}}
+
+add.b Rs,Rd biand #x:3,Rd
+add.b #imm:8,Rd biand #x:3,@@Rd
+add.w Rs,Rd biand #x:3,@@aa:8
+adds #1,Rd bild #x:3,Rd
+adds #2,Rd bild #x:3,@@Rd
+addx #imm:8,Rd bild #x:3,@@aa:8
+addx Rs,Rd bior #x:3,Rd
+and #imm:8,Rd bior #x:3,@@Rd
+and Rs,Rd bior #x:3,@@aa:8
+andc #imm:8,ccr bist #x:3,Rd
+band #x:3,Rd bist #x:3,@@Rd
+band #x:3,@@Rd bist #x:3,@@aa:8
+bra d:8 bixor #x:3,Rd
+bt d:8 bixor #x:3,@@Rd
+brn d:8 bixor #x:3,@@aa:8
+bf d:8 bld #x:3,Rd
+bhi d:8 bld #x:3,@@Rd
+bls d:8 bld #x:3,@@aa:8
+bcc d:8 bnot #x:3,Rd
+bhs d:8 bnot #x:3,@@Rd
+bcs d:8 bnot #x:3,@@aa:8
+blo d:8 bnot Rs,Rd
+bne d:8 bnot Rs,@@Rd
+beq d:8 bnot Rs,@@aa:8
+bvc d:8 bor #x:3,Rd
+bvs d:8 bor #x:3,@@Rd
+bpl d:8 bor #x:3,@@aa:8
+bmi d:8 bset #x:3,@@Rd
+bge d:8 bset #x:3,@@aa:8
+blt d:8 bset Rs,Rd
+bgt d:8 bset Rs,@@Rd
+ble d:8 bset Rs,@@aa:8
+bclr #x:3,Rd bsr d:8
+bclr #x:3,@@Rd bst #x:3,Rd
+bclr #x:3,@@aa:8 bst #x:3,@@Rd
+bclr Rs,Rd bst #x:3,@@aa:8
+bclr Rs,@@Rd btst #x:3,Rd
+@end group
+@group
+btst #x:3,@@Rd mov.w @@(d:16, Rs),Rd
+btst #x:3,@@aa:8 mov.w @@Rs+,Rd
+btst Rs,Rd mov.w @@aa:16,Rd
+btst Rs,@@Rd mov.w Rs,@@Rd
+btst Rs,@@aa:8 mov.w Rs,@@(d:16, Rd)
+bxor #x:3,Rd mov.w Rs,@@-Rd
+bxor #x:3,@@Rd mov.w Rs,@@aa:16
+bxor #x:3,@@aa:8 movfpe @@aa:16,Rd
+cmp.b #imm:8,Rd movtpe Rs,@@aa:16
+cmp.b Rs,Rd mulxu Rs,Rd
+cmp.w Rs,Rd neg Rs
+daa Rs nop
+das Rs not Rs
+dec Rs or #imm:8,Rd
+divxu Rs,Rd or Rs,Rd
+eepmov orc #imm:8,ccr
+inc Rs pop Rs
+jmp @@Rs push Rs
+jmp @@aa:16 rotl Rs
+jmp @@@@aa rotr Rs
+jsr @@Rs rotxl Rs
+jsr @@aa:16 rotxr Rs
+jsr @@@@aa:8 rte
+ldc #imm:8,ccr rts
+ldc Rs,ccr shal Rs
+mov.b Rs,Rd shar Rs
+mov.b #imm:8,Rd shll Rs
+mov.b @@Rs,Rd shlr Rs
+mov.b @@(d:16, Rs),Rd sleep
+mov.b @@Rs+,Rd stc ccr,Rd
+mov.b @@aa:16,Rd sub.b Rs,Rd
+mov.b @@aa:8,Rd sub.w Rs,Rd
+mov.b Rs,@@Rd subs #1,Rd
+mov.b Rs,@@(d:16, Rd) subs #2,Rd
+mov.b Rs,@@-Rd subx #imm:8,Rd
+mov.b Rs,@@aa:16 subx Rs,Rd
+mov.b Rs,@@aa:8 xor #imm:8,Rd
+mov.w Rs,Rd xor Rs,Rd
+mov.w #imm:16,Rd xorc #imm:8,ccr
+mov.w @@Rs,Rd
+@end group
+@end smallexample
+
+@cindex size suffixes, H8/300
+@cindex H8/300 size suffixes
+Four H8/300 instructions (@code{add}, @code{cmp}, @code{mov},
+@code{sub}) are defined with variants using the suffixes @samp{.b} and
+@samp{.w} to specify the size of a memory operand. @code{as}
+supports these suffixes, but does not require them; since one of the
+operands is always a register, @code{as} can deduce the correct size.
+
+For example, since @code{r0} refers to a 16-bit register,
+@example
+mov r0,@@foo
+@exdent is equivalent to
+mov.w r0,@@foo
+@end example
+
+If you use the size suffixes, @code{as} will issue a warning if
+there's a mismatch between the suffix and the register size.
+
+@node i960-Dependent, M68K-Dependent, H8/300-Dependent, Machine Dependent
+@section Intel 80960 Dependent Features
+
+@cindex i960 support
+@menu
+* Options-i960:: i960 Command-line Options
+* Floating Point-i960:: Floating Point
+* Directives-i960:: i960 Machine Directives
+* Opcodes for i960:: i960 Opcodes
+@end menu
+
+@c FIXME! Add Syntax sec with discussion of bitfields here, at least so
+@c long as they're not turned on for other machines than 960.
+@node Options-i960, Floating Point-i960, i960-Dependent, i960-Dependent
+
+@subsection i960 Command-line Options
+
+@cindex i960 options
+@cindex options, i960
+@table @code
+
+@item -ACA | -ACA_A | -ACB | -ACC | -AKA | -AKB | -AKC | -AMC
+@cindex i960 architecture options
+@cindex architecture options, i960
+@cindex @code{-A} options, i960
+Select the 80960 architecture. Instructions or features not supported
+by the selected architecture cause fatal errors.
+
+@samp{-ACA} is equivalent to @samp{-ACA_A}; @samp{-AKC} is equivalent to
+@samp{-AMC}. Synonyms are provided for compatibility with other tools.
+
+If none of these options is specified, @code{as} will generate code for any
+instruction or feature that is supported by @emph{some} version of the
+960 (even if this means mixing architectures!). In principle,
+@code{as} will attempt to deduce the minimal sufficient processor
+type if none is specified; depending on the object code format, the
+processor type may be recorded in the object file. If it is critical
+that the @code{as} output match a specific architecture, specify that
+architecture explicitly.
+
+@item -b
+@cindex @code{-b} option, i960
+@cindex branch recording, i960
+@cindex i960 branch recording
+Add code to collect information about conditional branches taken, for
+later optimization using branch prediction bits. (The conditional branch
+instructions have branch prediction bits in the CA, CB, and CC
+architectures.) If @var{BR} represents a conditional branch instruction,
+the following represents the code generated by the assembler when
+@samp{-b} is specified:
+
+@smallexample
+ call @var{increment routine}
+ .word 0 # pre-counter
+Label: @var{BR}
+ call @var{increment routine}
+ .word 0 # post-counter
+@end smallexample
+
+The counter following a branch records the number of times that branch
+was @emph{not} taken; the differenc between the two counters is the
+number of times the branch @emph{was} taken.
+
+@cindex @code{gbr960}, i960 postprocessor
+@cindex branch statistics table, i960
+A table of every such @code{Label} is also generated, so that the
+external postprocessor @code{gbr960} (supplied by Intel) can locate all
+the counters. This table is always labelled @samp{__BRANCH_TABLE__};
+this is a local symbol to permit collecting statistics for many separate
+object files. The table is word aligned, and begins with a two-word
+header. The first word, initialized to 0, is used in maintaining linked
+lists of branch tables. The second word is a count of the number of
+entries in the table, which follow immediately: each is a word, pointing
+to one of the labels illustrated above.
+
+@c TEXI2ROFF-KILL
+@ifinfo
+@c END TEXI2ROFF-KILL
+@example
+ +------------+------------+------------+ ... +------------+
+ | | | | | |
+ | *NEXT | COUNT: N | *BRLAB 1 | | *BRLAB N |
+ | | | | | |
+ +------------+------------+------------+ ... +------------+
+
+ __BRANCH_TABLE__ layout
+@end example
+@c TEXI2ROFF-KILL
+@end ifinfo
+@tex
+\vskip 1pc
+\line{\leftskip=0pt\hskip\tableindent
+\boxit{2cm}{\tt *NEXT}\boxit{2cm}{\tt COUNT: \it N}\boxit{2cm}{\tt
+*BRLAB 1}\ibox{1cm}{\quad\dots}\boxit{2cm}{\tt *BRLAB \it N}\hfil}
+\centerline{\it {\tt \_\_BRANCH\_TABLE\_\_} layout}
+@end tex
+@c END TEXI2ROFF-KILL
+
+The first word of the header is used to locate multiple branch tables,
+since each object file may contain one. Normally the links are
+maintained with a call to an initialization routine, placed at the
+beginning of each function in the file. The GNU C compiler will
+generate these calls automatically when you give it a @samp{-b} option.
+For further details, see the documentation of @samp{gbr960}.
+
+@item -norelax
+@cindex @code{-norelax} option, i960
+Normally, Compare-and-Branch instructions with targets that require
+displacements greater than 13 bits (or that have external targets) are
+replaced with the corresponding compare (or @samp{chkbit}) and branch
+instructions. You can use the @samp{-norelax} option to specify that
+@code{as} should generate errors instead, if the target displacement
+is larger than 13 bits.
+
+This option does not affect the Compare-and-Jump instructions; the code
+emitted for them is @emph{always} adjusted when necessary (depending on
+displacement size), regardless of whether you use @samp{-norelax}.
+@end table
+
+@node Floating Point-i960, Directives-i960, Options-i960, i960-Dependent
+@subsection Floating Point
+
+@cindex floating point, i960 (@sc{ieee})
+@cindex i960 floating point (@sc{ieee})
+@code{as} generates @sc{ieee} floating-point numbers for the directives
+@samp{.float}, @samp{.double}, @samp{.extended}, and @samp{.single}.
+
+@node Directives-i960, Opcodes for i960, Floating Point-i960, i960-Dependent
+@subsection i960 Machine Directives
+
+@cindex machine directives, i960
+@cindex i960 machine directives
+
+@table @code
+@cindex @code{bss} directive, i960
+@item .bss @var{symbol}, @var{length}, @var{align}
+Reserve @var{length} bytes in the bss section for a local @var{symbol},
+aligned to the power of two specified by @var{align}. @var{length} and
+@var{align} must be positive absolute expressions. This directive
+differs from @samp{.lcomm} only in that it permits you to specify
+an alignment. @xref{Lcomm,,@code{.lcomm}}.
+@end table
+
+@table @code
+@item .extended @var{flonums}
+@cindex @code{extended} directive, i960
+@code{.extended} expects zero or more flonums, separated by commas; for
+each flonum, @samp{.extended} emits an @sc{ieee} extended-format (80-bit)
+floating-point number.
+
+@item .leafproc @var{call-lab}, @var{bal-lab}
+@cindex @code{leafproc} directive, i960
+You can use the @samp{.leafproc} directive in conjunction with the
+optimized @code{callj} instruction to enable faster calls of leaf
+procedures. If a procedure is known to call no other procedures, you
+may define an entry point that skips procedure prolog code (and that does
+not depend on system-supplied saved context), and declare it as the
+@var{bal-lab} using @samp{.leafproc}. If the procedure also has an
+entry point that goes through the normal prolog, you can specify that
+entry point as @var{call-lab}.
+
+A @samp{.leafproc} declaration is meant for use in conjunction with the
+optimized call instruction @samp{callj}; the directive records the data
+needed later to choose between converting the @samp{callj} into a
+@code{bal} or a @code{call}.
+
+@var{call-lab} is optional; if only one argument is present, or if the
+two arguments are identical, the single argument is assumed to be the
+@code{bal} entry point.
+
+@item .sysproc @var{name}, @var{index}
+@cindex @code{sysproc} directive, i960
+The @samp{.sysproc} directive defines a name for a system procedure.
+After you define it using @samp{.sysproc}, you can use @var{name} to
+refer to the system procedure identified by @var{index} when calling
+procedures with the optimized call instruction @samp{callj}.
+
+Both arguments are required; @var{index} must be between 0 and 31
+(inclusive).
+@end table
+
+@node Opcodes for i960, , Directives-i960, i960-Dependent
+@subsection i960 Opcodes
+
+@cindex opcodes, i960
+@cindex i960 opcodes
+All Intel 960 machine instructions are supported;
+@pxref{Options-i960,,i960 Command-line Options} for a discussion of
+selecting the instruction subset for a particular 960
+architecture.@refill
+
+Some opcodes are processed beyond simply emitting a single corresponding
+instruction: @samp{callj}, and Compare-and-Branch or Compare-and-Jump
+instructions with target displacements larger than 13 bits.
+
+@menu
+* callj-i960:: @code{callj}
+* Compare-and-branch-i960:: Compare-and-Branch
+@end menu
+
+@node callj-i960, Compare-and-branch-i960, Opcodes for i960, Opcodes for i960
+@subsubsection @code{callj}
+
+@cindex @code{callj}, i960 pseudo-opcode
+@cindex i960 @code{callj} pseudo-opcode
+You can write @code{callj} to have the assembler or the linker determine
+the most appropriate form of subroutine call: @samp{call},
+@samp{bal}, or @samp{calls}. If the assembly source contains
+enough information---a @samp{.leafproc} or @samp{.sysproc} directive
+defining the operand---then @code{as} will translate the
+@code{callj}; if not, it will simply emit the @code{callj}, leaving it
+for the linker to resolve.
+
+@node Compare-and-branch-i960, , callj-i960, Opcodes for i960
+@subsubsection Compare-and-Branch
+
+@cindex i960 compare and branch instructions
+@cindex compare and branch instructions, i960
+The 960 architectures provide combined Compare-and-Branch instructions
+that permit you to store the branch target in the lower 13 bits of the
+instruction word itself. However, if you specify a branch target far
+enough away that its address won't fit in 13 bits, the assembler can
+either issue an error, or convert your Compare-and-Branch instruction
+into separate instructions to do the compare and the branch.
+
+@cindex compare and jump expansions, i960
+@cindex i960 compare and jump expansions
+Whether @code{as} gives an error or expands the instruction depends
+on two choices you can make: whether you use the @samp{-norelax} option,
+and whether you use a ``Compare and Branch'' instruction or a ``Compare
+and Jump'' instruction. The ``Jump'' instructions are @emph{always}
+expanded if necessary; the ``Branch'' instructions are expanded when
+necessary @emph{unless} you specify @code{-norelax}---in which case
+@code{as} gives an error instead.
+
+These are the Compare-and-Branch instructions, their ``Jump'' variants,
+and the instruction pairs they may expand into:
+
+@c TEXI2ROFF-KILL
+@ifinfo
+@c END TEXI2ROFF-KILL
+@example
+ Compare and
+ Branch Jump Expanded to
+ ------ ------ ------------
+ bbc chkbit; bno
+ bbs chkbit; bo
+ cmpibe cmpije cmpi; be
+ cmpibg cmpijg cmpi; bg
+ cmpibge cmpijge cmpi; bge
+ cmpibl cmpijl cmpi; bl
+ cmpible cmpijle cmpi; ble
+ cmpibno cmpijno cmpi; bno
+ cmpibne cmpijne cmpi; bne
+ cmpibo cmpijo cmpi; bo
+ cmpobe cmpoje cmpo; be
+ cmpobg cmpojg cmpo; bg
+ cmpobge cmpojge cmpo; bge
+ cmpobl cmpojl cmpo; bl
+ cmpoble cmpojle cmpo; ble
+ cmpobne cmpojne cmpo; bne
+@end example
+@c TEXI2ROFF-KILL
+@end ifinfo
+@tex
+\hskip\tableindent
+\halign{\hfil {\tt #}\quad&\hfil {\tt #}\qquad&{\tt #}\hfil\cr
+\omit{\hfil\it Compare and\hfil}\span\omit&\cr
+{\it Branch}&{\it Jump}&{\it Expanded to}\cr
+ bbc& & chkbit; bno\cr
+ bbs& & chkbit; bo\cr
+ cmpibe& cmpije& cmpi; be\cr
+ cmpibg& cmpijg& cmpi; bg\cr
+ cmpibge& cmpijge& cmpi; bge\cr
+ cmpibl& cmpijl& cmpi; bl\cr
+ cmpible& cmpijle& cmpi; ble\cr
+ cmpibno& cmpijno& cmpi; bno\cr
+ cmpibne& cmpijne& cmpi; bne\cr
+ cmpibo& cmpijo& cmpi; bo\cr
+ cmpobe& cmpoje& cmpo; be\cr
+ cmpobg& cmpojg& cmpo; bg\cr
+ cmpobge& cmpojge& cmpo; bge\cr
+ cmpobl& cmpojl& cmpo; bl\cr
+ cmpoble& cmpojle& cmpo; ble\cr
+ cmpobne& cmpojne& cmpo; bne\cr}
+@end tex
+@c END TEXI2ROFF-KILL
+
+@c FIXME! node conds are only sufficient for m68k alone, all, and vintage
+@node M68K-Dependent, Sparc-Dependent, i960-Dependent, Machine Dependent
+@section M680x0 Dependent Features
+
+@cindex M680x0 support
+@menu
+* M68K-Opts:: M680x0 Options
+* M68K-Syntax:: Syntax
+* M68K-Float:: Floating Point
+* M68K-Directives:: 680x0 Machine Directives
+* M68K-opcodes:: Opcodes
+@end menu
+
+@node M68K-Opts, M68K-Syntax, M68K-Dependent, M68K-Dependent
+@subsection M680x0 Options
+
+@cindex options, M680x0
+@cindex M680x0 options
+The Motorola 680x0 version of @code{as} has two machine dependent options.
+One shortens undefined references from 32 to 16 bits, while the
+other is used to tell @code{as} what kind of machine it is
+assembling for.
+
+@cindex @code{-l} option, M680x0
+You can use the @kbd{-l} option to shorten the size of references to
+undefined symbols. If the @kbd{-l} option is not given, references to
+undefined symbols will be a full long (32 bits) wide. (Since @code{as}
+cannot know where these symbols will end up, @code{as} can only allocate
+space for the linker to fill in later. Since @code{as} doesn't know how
+far away these symbols will be, it allocates as much space as it can.)
+If this option is given, the references will only be one word wide (16
+bits). This may be useful if you want the object file to be as small as
+possible, and you know that the relevant symbols will be less than 17
+bits away.
+
+@cindex @code{-m68000} and related options, M680x0
+@cindex architecture options, M680x0
+@cindex M680x0 architecture options
+The 680x0 version of @code{as} is most frequently used to assemble
+programs for the Motorola MC68020 microprocessor. Occasionally it is
+used to assemble programs for the mostly similar, but slightly different
+MC68000 or MC68010 microprocessors. You can give @code{as} the options
+@samp{-m68000}, @samp{-mc68000}, @samp{-m68010}, @samp{-mc68010},
+@samp{-m68020}, and @samp{-mc68020} to tell it what processor is the
+target.
+
+@node M68K-Syntax, M68K-Float, M68K-Opts, M68K-Dependent
+@subsection Syntax
+
+@cindex M680x0 syntax
+@cindex syntax, M680x0
+@cindex M680x0 size modifiers
+@cindex size modifiers, M680x0
+The 680x0 version of @code{as} uses syntax similar to the Sun assembler.
+Size modifiers are appended directly to the end of the opcode without an
+intervening period. For example, write @samp{movl} rather than
+@samp{move.l}.
+
+
+In the following table @dfn{apc} stands for any of the address
+registers (@samp{a0} through @samp{a7}), nothing, (@samp{}), the
+Program Counter (@samp{pc}), or the zero-address relative to the
+program counter (@samp{zpc}).
+
+@cindex M680x0 addressing modes
+@cindex addressing modes, M680x0
+The following addressing modes are understood:
+@table @dfn
+@item Immediate
+@samp{#@var{digits}}
+
+@item Data Register
+@samp{d0} through @samp{d7}
+
+@item Address Register
+@samp{a0} through @samp{a7}
+
+@item Address Register Indirect
+@samp{a0@@} through @samp{a7@@}
+
+@item Address Register Postincrement
+@samp{a0@@+} through @samp{a7@@+}
+
+@item Address Register Predecrement
+@samp{a0@@-} through @samp{a7@@-}
+
+@item Indirect Plus Offset
+@samp{@var{apc}@@(@var{digits})}
+
+@item Index
+@samp{@var{apc}@@(@var{digits},@var{register}:@var{size}:@var{scale})}
+
+or @samp{@var{apc}@@(@var{register}:@var{size}:@var{scale})}
+
+@item Postindex
+@samp{@var{apc}@@(@var{digits})@@(@var{digits},@var{register}:@var{size}:@var{scale})}
+
+or @samp{@var{apc}@@(@var{digits})@@(@var{register}:@var{size}:@var{scale})}
+
+@item Preindex
+@samp{@var{apc}@@(@var{digits},@var{register}:@var{size}:@var{scale})@@(@var{digits})}
+
+or @samp{@var{apc}@@(@var{register}:@var{size}:@var{scale})@@(@var{digits})}
+
+@item Memory Indirect
+@samp{@var{apc}@@(@var{digits})@@(@var{digits})}
+
+@item Absolute
+@samp{@var{symbol}}, or @samp{@var{digits}}
+@ignore
+@c pesch@cygnus.com: gnu, rich concur the following needs careful
+@c research before documenting.
+ , or either of the above followed
+by @samp{:b}, @samp{:w}, or @samp{:l}.
+@end ignore
+@end table
+
+@node M68K-Float, M68K-Directives, M68K-Syntax, M68K-Dependent
+@subsection Floating Point
+
+@cindex floating point, M680x0
+@cindex M680x0 floating point
+@c FIXME is this "not too well tested" crud STILL true?
+The floating point code is not too well tested, and may have
+subtle bugs in it.
+
+Packed decimal (P) format floating literals are not supported.
+Feel free to add the code!
+
+The floating point formats generated by directives are these.
+
+@table @code
+@item .float
+@cindex @code{float} directive, M680x0
+@code{Single} precision floating point constants.
+
+@item .double
+@cindex @code{double} directive, M680x0
+@code{Double} precision floating point constants.
+@end table
+
+There is no directive to produce regions of memory holding
+extended precision numbers, however they can be used as
+immediate operands to floating-point instructions. Adding a
+directive to create extended precision numbers would not be
+hard, but it has not yet seemed necessary.
+
+@node M68K-Directives, M68K-opcodes, M68K-Float, M68K-Dependent
+@subsection 680x0 Machine Directives
+
+@cindex M680x0 directives
+@cindex directives, M680x0
+In order to be compatible with the Sun assembler the 680x0 assembler
+understands the following directives.
+
+@table @code
+@item .data1
+@cindex @code{data1} directive, M680x0
+This directive is identical to a @code{.data 1} directive.
+
+@item .data2
+@cindex @code{data2} directive, M680x0
+This directive is identical to a @code{.data 2} directive.
+
+@item .even
+@cindex @code{even} directive, M680x0
+This directive is identical to a @code{.align 1} directive.
+@c Is this true? does it work???
+
+@item .skip
+@cindex @code{skip} directive, M680x0
+This directive is identical to a @code{.space} directive.
+@end table
+
+@node M68K-opcodes, , M68K-Directives, M68K-Dependent
+@subsection Opcodes
+
+@cindex M680x0 opcodes
+@cindex opcodes, M680x0
+@cindex instruction set, M680x0
+@c pesch@cygnus.com: I don't see any point in the following
+@c paragraph. Bugs are bugs; how does saying this
+@c help anyone?
+@ignore
+Danger: Several bugs have been found in the opcode table (and
+fixed). More bugs may exist. Be careful when using obscure
+instructions.
+@end ignore
+
+@menu
+* M68K-Branch:: Branch Improvement
+* M68K-Chars:: Special Characters
+@end menu
+
+@node M68K-Branch, M68K-Chars, M68K-opcodes, M68K-opcodes
+@subsubsection Branch Improvement
+
+@cindex pseudo-opcodes, M680x0
+@cindex M680x0 pseudo-opcodes
+@cindex branch improvement, M680x0
+@cindex M680x0 branch improvement
+Certain pseudo opcodes are permitted for branch instructions.
+They expand to the shortest branch instruction that will reach the
+target. Generally these mnemonics are made by substituting @samp{j} for
+@samp{b} at the start of a Motorola mnemonic.
+
+The following table summarizes the pseudo-operations. A @code{*} flags
+cases that are more fully described after the table:
+
+@smallexample
+ Displacement
+ +---------------------------------------------------------
+ | 68020 68000/10
+Pseudo-Op |BYTE WORD LONG LONG non-PC relative
+ +---------------------------------------------------------
+ jbsr |bsrs bsr bsrl jsr jsr
+ jra |bras bra bral jmp jmp
+* jXX |bXXs bXX bXXl bNXs;jmpl bNXs;jmp
+* dbXX |dbXX dbXX dbXX; bra; jmpl
+* fjXX |fbXXw fbXXw fbXXl fbNXw;jmp
+
+XX: condition
+NX: negative of condition XX
+
+@end smallexample
+@center @code{*}---see full description below
+
+@table @code
+@item jbsr
+@itemx jra
+These are the simplest jump pseudo-operations; they always map to one
+particular machine instruction, depending on the displacement to the
+branch target.
+
+@item j@var{XX}
+Here, @samp{j@var{XX}} stands for an entire family of pseudo-operations,
+where @var{XX} is a conditional branch or condition-code test. The full
+list of pseudo-ops in this family is:
+@smallexample
+ jhi jls jcc jcs jne jeq jvc
+ jvs jpl jmi jge jlt jgt jle
+@end smallexample
+
+For the cases of non-PC relative displacements and long displacements on
+the 68000 or 68010, @code{as} will issue a longer code fragment in terms of
+@var{NX}, the opposite condition to @var{XX}:
+@smallexample
+ j@var{XX} foo
+@end smallexample
+gives
+@smallexample
+ b@var{NX}s oof
+ jmp foo
+ oof:
+@end smallexample
+
+@item db@var{XX}
+The full family of pseudo-operations covered here is
+@smallexample
+ dbhi dbls dbcc dbcs dbne dbeq dbvc
+ dbvs dbpl dbmi dbge dblt dbgt dble
+ dbf dbra dbt
+@end smallexample
+
+Other than for word and byte displacements, when the source reads
+@samp{db@var{XX} foo}, @code{as} will emit
+@smallexample
+ db@var{XX} oo1
+ bra oo2
+ oo1:jmpl foo
+ oo2:
+@end smallexample
+
+@item fj@var{XX}
+This family includes
+@smallexample
+ fjne fjeq fjge fjlt fjgt fjle fjf
+ fjt fjgl fjgle fjnge fjngl fjngle fjngt
+ fjnle fjnlt fjoge fjogl fjogt fjole fjolt
+ fjor fjseq fjsf fjsne fjst fjueq fjuge
+ fjugt fjule fjult fjun
+@end smallexample
+
+For branch targets that are not PC relative, @code{as} emits
+@smallexample
+ fb@var{NX} oof
+ jmp foo
+ oof:
+@end smallexample
+when it encounters @samp{fj@var{XX} foo}.
+
+@end table
+
+@node M68K-Chars, , M68K-Branch, M68K-opcodes
+@subsubsection Special Characters
+
+@cindex special characters, M680x0
+@cindex M680x0 immediate character
+@cindex immediate character, M680x0
+@cindex M680x0 line comment character
+@cindex line comment character, M680x0
+@cindex comments, M680x0
+The immediate character is @samp{#} for Sun compatibility. The
+line-comment character is @samp{|}. If a @samp{#} appears at the
+beginning of a line, it is treated as a comment unless it looks like
+@samp{# line file}, in which case it is treated normally.
+
+@node Sparc-Dependent, i386-Dependent, M68K-Dependent, Machine Dependent
+@section SPARC Dependent Features
+
+@cindex SPARC support
+@menu
+* Sparc-Opts:: Options
+* Sparc-Float:: Floating Point
+* Sparc-Directives:: Sparc Machine Directives
+@end menu
+
+@node Sparc-Opts, Sparc-Float, Sparc-Dependent, Sparc-Dependent
+@subsection Options
+
+@cindex options for SPARC (none)
+@cindex SPARC options (none)
+The Sparc has no machine dependent options.
+
+@ignore
+@c FIXME: (sparc) Fill in "syntax" section!
+@c subsection syntax
+I don't know anything about Sparc syntax. Someone who does
+will have to write this section.
+@end ignore
+
+@node Sparc-Float, Sparc-Directives, Sparc-Opts, Sparc-Dependent
+@subsection Floating Point
+
+@cindex floating point, SPARC (@sc{ieee})
+@cindex SPARC floating point (@sc{ieee})
+The Sparc uses @sc{ieee} floating-point numbers.
+
+@node Sparc-Directives, , Sparc-Float, Sparc-Dependent
+@subsection Sparc Machine Directives
+
+@cindex SPARC machine directives
+@cindex machine directives, SPARC
+The Sparc version of @code{as} supports the following additional
+machine directives:
+
+@table @code
+@item .common
+@cindex @code{common} directive, SPARC
+This must be followed by a symbol name, a positive number, and
+@code{"bss"}. This behaves somewhat like @code{.comm}, but the
+syntax is different.
+
+@item .half
+@cindex @code{half} directive, SPARC
+This is functionally identical to @code{.short}.
+
+@item .proc
+@cindex @code{proc} directive, SPARC
+This directive is ignored. Any text following it on the same
+line is also ignored.
+
+@item .reserve
+@cindex @code{reserve} directive, SPARC
+This must be followed by a symbol name, a positive number, and
+@code{"bss"}. This behaves somewhat like @code{.lcomm}, but the
+syntax is different.
+
+@item .seg
+@cindex @code{seg} directive, SPARC
+This must be followed by @code{"text"}, @code{"data"}, or
+@code{"data1"}. It behaves like @code{.text}, @code{.data}, or
+@code{.data 1}.
+
+@item .skip
+@cindex @code{skip} directive, SPARC
+This is functionally identical to the @code{.space} directive.
+
+@item .word
+@cindex @code{word} directive, SPARC
+On the Sparc, the .word directive produces 32 bit values,
+instead of the 16 bit values it produces on many other machines.
+@end table
+
+@c FIXME! Conditionalize for all combinations in this section
+@node i386-Dependent, , Sparc-Dependent, Machine Dependent
+@section 80386 Dependent Features
+
+@cindex i386 support
+@cindex i80306 support
+@menu
+* i386-Options:: Options
+* i386-Syntax:: AT&T Syntax versus Intel Syntax
+* i386-Opcodes:: Opcode Naming
+* i386-Regs:: Register Naming
+* i386-prefixes:: Opcode Prefixes
+* i386-Memory:: Memory References
+* i386-jumps:: Handling of Jump Instructions
+* i386-Float:: Floating Point
+* i386-Notes:: Notes
+@end menu
+
+@node i386-Options, i386-Syntax, i386-Dependent, i386-Dependent
+@subsection Options
+
+@cindex options for i386 (none)
+@cindex i386 options (none)
+The 80386 has no machine dependent options.
+
+@node i386-Syntax, i386-Opcodes, i386-Options, i386-Dependent
+@subsection AT&T Syntax versus Intel Syntax
+
+@cindex i386 syntax compatibility
+@cindex syntax compatibility, i386
+In order to maintain compatibility with the output of @code{gcc},
+@code{as} supports AT&T System V/386 assembler syntax. This is quite
+different from Intel syntax. We mention these differences because
+almost all 80386 documents used only Intel syntax. Notable differences
+between the two syntaxes are:
+
+@itemize @bullet
+@item
+@cindex immediate operands, i386
+@cindex i386 immediate operands
+@cindex register operands, i386
+@cindex i386 register operands
+@cindex jump/call operands, i386
+@cindex i386 jump/call operands
+@cindex operand delimiters, i386
+AT&T immediate operands are preceded by @samp{$}; Intel immediate
+operands are undelimited (Intel @samp{push 4} is AT&T @samp{pushl $4}).
+AT&T register operands are preceded by @samp{%}; Intel register operands
+are undelimited. AT&T absolute (as opposed to PC relative) jump/call
+operands are prefixed by @samp{*}; they are undelimited in Intel syntax.
+
+@item
+@cindex i386 source, destination operands
+@cindex source, destination operands; i386
+AT&T and Intel syntax use the opposite order for source and destination
+operands. Intel @samp{add eax, 4} is @samp{addl $4, %eax}. The
+@samp{source, dest} convention is maintained for compatibility with
+previous Unix assemblers.
+
+@item
+@cindex opcode suffixes, i386
+@cindex sizes operands, i386
+@cindex i386 size suffixes
+In AT&T syntax the size of memory operands is determined from the last
+character of the opcode name. Opcode suffixes of @samp{b}, @samp{w},
+and @samp{l} specify byte (8-bit), word (16-bit), and long (32-bit)
+memory references. Intel syntax accomplishes this by prefixes memory
+operands (@emph{not} the opcodes themselves) with @samp{byte ptr},
+@samp{word ptr}, and @samp{dword ptr}. Thus, Intel @samp{mov al, byte
+ptr @var{foo}} is @samp{movb @var{foo}, %al} in AT&T syntax.
+
+@item
+@cindex return instructions, i386
+@cindex i386 jump, call, return
+Immediate form long jumps and calls are
+@samp{lcall/ljmp $@var{section}, $@var{offset}} in AT&T syntax; the
+Intel syntax is
+@samp{call/jmp far @var{section}:@var{offset}}. Also, the far return
+instruction
+is @samp{lret $@var{stack-adjust}} in AT&T syntax; Intel syntax is
+@samp{ret far @var{stack-adjust}}.
+
+@item
+@cindex sections, i386
+@cindex i386 sections
+The AT&T assembler does not provide support for multiple section
+programs. Unix style systems expect all programs to be single sections.
+@end itemize
+
+@node i386-Opcodes, i386-Regs, i386-Syntax, i386-Dependent
+@subsection Opcode Naming
+
+@cindex i386 opcode naming
+@cindex opcode naming, i386
+Opcode names are suffixed with one character modifiers which specify the
+size of operands. The letters @samp{b}, @samp{w}, and @samp{l} specify
+byte, word, and long operands. If no suffix is specified by an
+instruction and it contains no memory operands then @code{as} tries to
+fill in the missing suffix based on the destination register operand
+(the last one by convention). Thus, @samp{mov %ax, %bx} is equivalent
+to @samp{movw %ax, %bx}; also, @samp{mov $1, %bx} is equivalent to
+@samp{movw $1, %bx}. Note that this is incompatible with the AT&T Unix
+assembler which assumes that a missing opcode suffix implies long
+operand size. (This incompatibility does not affect compiler output
+since compilers always explicitly specify the opcode suffix.)
+
+Almost all opcodes have the same names in AT&T and Intel format. There
+are a few exceptions. The sign extend and zero extend instructions need
+two sizes to specify them. They need a size to sign/zero extend
+@emph{from} and a size to zero extend @emph{to}. This is accomplished
+by using two opcode suffixes in AT&T syntax. Base names for sign extend
+and zero extend are @samp{movs@dots{}} and @samp{movz@dots{}} in AT&T
+syntax (@samp{movsx} and @samp{movzx} in Intel syntax). The opcode
+suffixes are tacked on to this base name, the @emph{from} suffix before
+the @emph{to} suffix. Thus, @samp{movsbl %al, %edx} is AT&T syntax for
+``move sign extend @emph{from} %al @emph{to} %edx.'' Possible suffixes,
+thus, are @samp{bl} (from byte to long), @samp{bw} (from byte to word),
+and @samp{wl} (from word to long).
+
+@cindex conversion instructions, i386
+@cindex i386 conversion instructions
+The Intel-syntax conversion instructions
+
+@itemize @bullet
+@item
+@samp{cbw} --- sign-extend byte in @samp{%al} to word in @samp{%ax},
+
+@item
+@samp{cwde} --- sign-extend word in @samp{%ax} to long in @samp{%eax},
+
+@item
+@samp{cwd} --- sign-extend word in @samp{%ax} to long in @samp{%dx:%ax},
+
+@item
+@samp{cdq} --- sign-extend dword in @samp{%eax} to quad in @samp{%edx:%eax},
+@end itemize
+
+@noindent
+are called @samp{cbtw}, @samp{cwtl}, @samp{cwtd}, and @samp{cltd} in
+AT&T naming. @code{as} accepts either naming for these instructions.
+
+@cindex jump instructions, i386
+@cindex call instructions, i386
+Far call/jump instructions are @samp{lcall} and @samp{ljmp} in
+AT&T syntax, but are @samp{call far} and @samp{jump far} in Intel
+convention.
+
+@node i386-Regs, i386-prefixes, i386-Opcodes, i386-Dependent
+@subsection Register Naming
+
+@cindex i386 registers
+@cindex registers, i386
+Register operands are always prefixes with @samp{%}. The 80386 registers
+consist of
+
+@itemize @bullet
+@item
+the 8 32-bit registers @samp{%eax} (the accumulator), @samp{%ebx},
+@samp{%ecx}, @samp{%edx}, @samp{%edi}, @samp{%esi}, @samp{%ebp} (the
+frame pointer), and @samp{%esp} (the stack pointer).
+
+@item
+the 8 16-bit low-ends of these: @samp{%ax}, @samp{%bx}, @samp{%cx},
+@samp{%dx}, @samp{%di}, @samp{%si}, @samp{%bp}, and @samp{%sp}.
+
+@item
+the 8 8-bit registers: @samp{%ah}, @samp{%al}, @samp{%bh},
+@samp{%bl}, @samp{%ch}, @samp{%cl}, @samp{%dh}, and @samp{%dl} (These
+are the high-bytes and low-bytes of @samp{%ax}, @samp{%bx},
+@samp{%cx}, and @samp{%dx})
+
+@item
+the 6 section registers @samp{%cs} (code section), @samp{%ds}
+(data section), @samp{%ss} (stack section), @samp{%es}, @samp{%fs},
+and @samp{%gs}.
+
+@item
+the 3 processor control registers @samp{%cr0}, @samp{%cr2}, and
+@samp{%cr3}.
+
+@item
+the 6 debug registers @samp{%db0}, @samp{%db1}, @samp{%db2},
+@samp{%db3}, @samp{%db6}, and @samp{%db7}.
+
+@item
+the 2 test registers @samp{%tr6} and @samp{%tr7}.
+
+@item
+the 8 floating point register stack @samp{%st} or equivalently
+@samp{%st(0)}, @samp{%st(1)}, @samp{%st(2)}, @samp{%st(3)},
+@samp{%st(4)}, @samp{%st(5)}, @samp{%st(6)}, and @samp{%st(7)}.
+@end itemize
+
+@node i386-prefixes, i386-Memory, i386-Regs, i386-Dependent
+@subsection Opcode Prefixes
+
+@cindex i386 opcode prefixes
+@cindex opcode prefixes, i386
+@cindex prefixes, i386
+Opcode prefixes are used to modify the following opcode. They are used
+to repeat string instructions, to provide section overrides, to perform
+bus lock operations, and to give operand and address size (16-bit
+operands are specified in an instruction by prefixing what would
+normally be 32-bit operands with a ``operand size'' opcode prefix).
+Opcode prefixes are usually given as single-line instructions with no
+operands, and must directly precede the instruction they act upon. For
+example, the @samp{scas} (scan string) instruction is repeated with:
+@smallexample
+ repne
+ scas
+@end smallexample
+
+Here is a list of opcode prefixes:
+
+@itemize @bullet
+@item
+@cindex section override prefixes, i386
+Section override prefixes @samp{cs}, @samp{ds}, @samp{ss}, @samp{es},
+@samp{fs}, @samp{gs}. These are automatically added by specifying
+using the @var{section}:@var{memory-operand} form for memory references.
+
+@item
+@cindex size prefixes, i386
+Operand/Address size prefixes @samp{data16} and @samp{addr16}
+change 32-bit operands/addresses into 16-bit operands/addresses. Note
+that 16-bit addressing modes (i.e. 8086 and 80286 addressing modes)
+are not supported (yet).
+
+@item
+@cindex bus lock prefixes, i386
+@cindex inhibiting interrupts, i386
+The bus lock prefix @samp{lock} inhibits interrupts during
+execution of the instruction it precedes. (This is only valid with
+certain instructions; see a 80386 manual for details).
+
+@item
+@cindex coprocessor wait, i386
+The wait for coprocessor prefix @samp{wait} waits for the
+coprocessor to complete the current instruction. This should never be
+needed for the 80386/80387 combination.
+
+@item
+@cindex repeat prefixes, i386
+The @samp{rep}, @samp{repe}, and @samp{repne} prefixes are added
+to string instructions to make them repeat @samp{%ecx} times.
+@end itemize
+
+@node i386-Memory, i386-jumps, i386-prefixes, i386-Dependent
+@subsection Memory References
+
+@cindex i386 memory references
+@cindex memory references, i386
+An Intel syntax indirect memory reference of the form
+
+@smallexample
+@var{section}:[@var{base} + @var{index}*@var{scale} + @var{disp}]
+@end smallexample
+
+@noindent
+is translated into the AT&T syntax
+
+@smallexample
+@var{section}:@var{disp}(@var{base}, @var{index}, @var{scale})
+@end smallexample
+
+@noindent
+where @var{base} and @var{index} are the optional 32-bit base and
+index registers, @var{disp} is the optional displacement, and
+@var{scale}, taking the values 1, 2, 4, and 8, multiplies @var{index}
+to calculate the address of the operand. If no @var{scale} is
+specified, @var{scale} is taken to be 1. @var{section} specifies the
+optional section register for the memory operand, and may override the
+default section register (see a 80386 manual for section register
+defaults). Note that section overrides in AT&T syntax @emph{must} have
+be preceded by a @samp{%}. If you specify a section override which
+coincides with the default section register, @code{as} will @emph{not}
+output any section register override prefixes to assemble the given
+instruction. Thus, section overrides can be specified to emphasize which
+section register is used for a given memory operand.
+
+Here are some examples of Intel and AT&T style memory references:
+
+@table @asis
+@item AT&T: @samp{-4(%ebp)}, Intel: @samp{[ebp - 4]}
+@var{base} is @samp{%ebp}; @var{disp} is @samp{-4}. @var{section} is
+missing, and the default section is used (@samp{%ss} for addressing with
+@samp{%ebp} as the base register). @var{index}, @var{scale} are both missing.
+
+@item AT&T: @samp{foo(,%eax,4)}, Intel: @samp{[foo + eax*4]}
+@var{index} is @samp{%eax} (scaled by a @var{scale} 4); @var{disp} is
+@samp{foo}. All other fields are missing. The section register here
+defaults to @samp{%ds}.
+
+@item AT&T: @samp{foo(,1)}; Intel @samp{[foo]}
+This uses the value pointed to by @samp{foo} as a memory operand.
+Note that @var{base} and @var{index} are both missing, but there is only
+@emph{one} @samp{,}. This is a syntactic exception.
+
+@item AT&T: @samp{%gs:foo}; Intel @samp{gs:foo}
+This selects the contents of the variable @samp{foo} with section
+register @var{section} being @samp{%gs}.
+@end table
+
+Absolute (as opposed to PC relative) call and jump operands must be
+prefixed with @samp{*}. If no @samp{*} is specified, @code{as} will
+always choose PC relative addressing for jump/call labels.
+
+Any instruction that has a memory operand @emph{must} specify its size (byte,
+word, or long) with an opcode suffix (@samp{b}, @samp{w}, or @samp{l},
+respectively).
+
+@node i386-jumps, i386-Float, i386-Memory, i386-Dependent
+@subsection Handling of Jump Instructions
+
+@cindex jump optimization, i386
+@cindex i386 jump optimization
+Jump instructions are always optimized to use the smallest possible
+displacements. This is accomplished by using byte (8-bit) displacement
+jumps whenever the target is sufficiently close. If a byte displacement
+is insufficient a long (32-bit) displacement is used. We do not support
+word (16-bit) displacement jumps (i.e. prefixing the jump instruction
+with the @samp{addr16} opcode prefix), since the 80386 insists upon masking
+@samp{%eip} to 16 bits after the word displacement is added.
+
+Note that the @samp{jcxz}, @samp{jecxz}, @samp{loop}, @samp{loopz},
+@samp{loope}, @samp{loopnz} and @samp{loopne} instructions only come in
+byte displacements, so that it is possible that use of these
+instructions (@code{gcc} does not use them) will cause the assembler to
+print an error message (and generate incorrect code). The AT&T 80386
+assembler tries to get around this problem by expanding @samp{jcxz foo} to
+@smallexample
+ jcxz cx_zero
+ jmp cx_nonzero
+cx_zero: jmp foo
+cx_nonzero:
+@end smallexample
+
+@node i386-Float, i386-Notes, i386-jumps, i386-Dependent
+@subsection Floating Point
+
+@cindex i386 floating point
+@cindex floating point, i386
+All 80387 floating point types except packed BCD are supported.
+(BCD support may be added without much difficulty). These data
+types are 16-, 32-, and 64- bit integers, and single (32-bit),
+double (64-bit), and extended (80-bit) precision floating point.
+Each supported type has an opcode suffix and a constructor
+associated with it. Opcode suffixes specify operand's data
+types. Constructors build these data types into memory.
+
+@itemize @bullet
+@item
+@cindex @code{float} directive, i386
+@cindex @code{single} directive, i386
+@cindex @code{double} directive, i386
+@cindex @code{tfloat} directive, i386
+Floating point constructors are @samp{.float} or @samp{.single},
+@samp{.double}, and @samp{.tfloat} for 32-, 64-, and 80-bit formats.
+These correspond to opcode suffixes @samp{s}, @samp{l}, and @samp{t}.
+@samp{t} stands for temporary real, and that the 80387 only supports
+this format via the @samp{fldt} (load temporary real to stack top) and
+@samp{fstpt} (store temporary real and pop stack) instructions.
+
+@item
+@cindex @code{word} directive, i386
+@cindex @code{long} directive, i386
+@cindex @code{int} directive, i386
+@cindex @code{quad} directive, i386
+Integer constructors are @samp{.word}, @samp{.long} or @samp{.int}, and
+@samp{.quad} for the 16-, 32-, and 64-bit integer formats. The corresponding
+opcode suffixes are @samp{s} (single), @samp{l} (long), and @samp{q}
+(quad). As with the temporary real format the 64-bit @samp{q} format is
+only present in the @samp{fildq} (load quad integer to stack top) and
+@samp{fistpq} (store quad integer and pop stack) instructions.
+@end itemize
+
+Register to register operations do not require opcode suffixes,
+so that @samp{fst %st, %st(1)} is equivalent to @samp{fstl %st, %st(1)}.
+
+@cindex i386 @code{fwait} instruction
+@cindex @code{fwait instruction}, i386
+Since the 80387 automatically synchronizes with the 80386 @samp{fwait}
+instructions are almost never needed (this is not the case for the
+80286/80287 and 8086/8087 combinations). Therefore, @code{as} suppresses
+the @samp{fwait} instruction whenever it is implicitly selected by one
+of the @samp{fn@dots{}} instructions. For example, @samp{fsave} and
+@samp{fnsave} are treated identically. In general, all the @samp{fn@dots{}}
+instructions are made equivalent to @samp{f@dots{}} instructions. If
+@samp{fwait} is desired it must be explicitly coded.
+
+@node i386-Notes, , i386-Float, i386-Dependent
+@subsection Notes
+
+@cindex i386 @code{mul}, @code{imul} instructions
+@cindex @code{mul} instruction, i386
+@cindex @code{imul} instruction, i386
+There is some trickery concerning the @samp{mul} and @samp{imul}
+instructions that deserves mention. The 16-, 32-, and 64-bit expanding
+multiplies (base opcode @samp{0xf6}; extension 4 for @samp{mul} and 5
+for @samp{imul}) can be output only in the one operand form. Thus,
+@samp{imul %ebx, %eax} does @emph{not} select the expanding multiply;
+the expanding multiply would clobber the @samp{%edx} register, and this
+would confuse @code{gcc} output. Use @samp{imul %ebx} to get the
+64-bit product in @samp{%edx:%eax}.
+
+We have added a two operand form of @samp{imul} when the first operand
+is an immediate mode expression and the second operand is a register.
+This is just a shorthand, so that, multiplying @samp{%eax} by 69, for
+example, can be done with @samp{imul $69, %eax} rather than @samp{imul
+$69, %eax, %eax}.
+
+
+@node Copying, Index, Machine Dependent, Top
+@unnumbered GNU GENERAL PUBLIC LICENSE
+
+@cindex license
+@cindex GPL
+@cindex copying @code{as}
+@center Version 2, June 1991
+
+@display
+Copyright @copyright{} 1989, 1991 Free Software Foundation, Inc.
+675 Mass Ave, Cambridge, MA 02139, USA
+
+Everyone is permitted to copy and distribute verbatim copies
+of this license document, but changing it is not allowed.
+@end display
+
+@unnumberedsec Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software---to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+@iftex
+@unnumberedsec TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+@end iftex
+@ifinfo
+@center TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+@end ifinfo
+
+@enumerate
+@item
+This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The ``Program'', below,
+refers to any such program or work, and a ``work based on the Program''
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term ``modification''.) Each licensee is addressed as ``you''.
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+@item
+You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+@item
+You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+@enumerate a
+@item
+You must cause the modified files to carry prominent notices
+stating that you changed the files and the date of any change.
+
+@item
+You must cause any work that you distribute or publish, that in
+whole or in part contains or is derived from the Program or any
+part thereof, to be licensed as a whole at no charge to all third
+parties under the terms of this License.
+
+@item
+If the modified program normally reads commands interactively
+when run, you must cause it, when started running for such
+interactive use in the most ordinary way, to print or display an
+announcement including an appropriate copyright notice and a
+notice that there is no warranty (or else, saying that you provide
+a warranty) and that users may redistribute the program under
+these conditions, and telling the user how to view a copy of this
+License. (Exception: if the Program itself is interactive but
+does not normally print such an announcement, your work based on
+the Program is not required to print an announcement.)
+@end enumerate
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+@item
+You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+@enumerate a
+@item
+Accompany it with the complete corresponding machine-readable
+source code, which must be distributed under the terms of Sections
+1 and 2 above on a medium customarily used for software interchange; or,
+
+@item
+Accompany it with a written offer, valid for at least three
+years, to give any third party, for a charge no more than your
+cost of physically performing source distribution, a complete
+machine-readable copy of the corresponding source code, to be
+distributed under the terms of Sections 1 and 2 above on a medium
+customarily used for software interchange; or,
+
+@item
+Accompany it with the information you received as to the offer
+to distribute corresponding source code. (This alternative is
+allowed only for noncommercial distribution and only if you
+received the program in object code or executable form with such
+an offer, in accord with Subsection b above.)
+@end enumerate
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+@item
+You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+@item
+You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+@item
+Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+@item
+If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+@item
+If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+@item
+The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and ``any
+later version'', you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+@item
+If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+@iftex
+@heading NO WARRANTY
+@end iftex
+@ifinfo
+@center NO WARRANTY
+@end ifinfo
+
+@item
+BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM ``AS IS'' WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+@item
+IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+@end enumerate
+
+@iftex
+@heading END OF TERMS AND CONDITIONS
+@end iftex
+@ifinfo
+@center END OF TERMS AND CONDITIONS
+@end ifinfo
+
+@page
+@unnumberedsec Applying These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the ``copyright'' line and a pointer to where the full notice is found.
+
+@smallexample
+@var{one line to give the program's name and an idea of what it does.}
+Copyright (C) 19@var{yy} @var{name of author}
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the
+Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA.
+@end smallexample
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+@smallexample
+Gnomovision version 69, Copyright (C) 19@var{yy} @var{name of author}
+Gnomovision comes with ABSOLUTELY NO WARRANTY; for details
+type `show w'. This is free software, and you are welcome
+to redistribute it under certain conditions; type `show c'
+for details.
+@end smallexample
+
+The hypothetical commands @samp{show w} and @samp{show c} should show
+the appropriate parts of the General Public License. Of course, the
+commands you use may be called something other than @samp{show w} and
+@samp{show c}; they could even be mouse-clicks or menu items---whatever
+suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a ``copyright disclaimer'' for the program, if
+necessary. Here is a sample; alter the names:
+
+@smallexample
+Yoyodyne, Inc., hereby disclaims all copyright interest in
+the program `Gnomovision' (which makes passes at compilers)
+written by James Hacker.
+
+@var{signature of Ty Coon}, 1 April 1989
+Ty Coon, President of Vice
+@end smallexample
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
+
+@node Index, , Copying, Top
+@unnumbered Index
+
+@printindex cp
+
+@summarycontents
+@contents
+@bye
diff --git a/gnu/usr.bin/as/expr.c b/gnu/usr.bin/as/expr.c
new file mode 100644
index 0000000..b504a4b
--- /dev/null
+++ b/gnu/usr.bin/as/expr.c
@@ -0,0 +1,1000 @@
+/* expr.c -operands, expressions-
+ Copyright (C) 1987, 1990, 1991, 1992 Free Software Foundation, Inc.
+
+ This file is part of GAS, the GNU Assembler.
+
+ GAS is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GAS is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GAS; see the file COPYING. If not, write to
+ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/*
+ * This is really a branch office of as-read.c. I split it out to clearly
+ * distinguish the world of expressions from the world of statements.
+ * (It also gives smaller files to re-compile.)
+ * Here, "operand"s are of expressions, not instructions.
+ */
+
+#ifndef lint
+static char rcsid[] = "$Id: expr.c,v 1.2 1993/11/03 00:51:28 paul Exp $";
+#endif
+
+#include <ctype.h>
+#include <string.h>
+
+#include "as.h"
+
+#include "obstack.h"
+
+#if __STDC__ == 1
+static void clean_up_expression(expressionS *expressionP);
+#else /* __STDC__ */
+static void clean_up_expression(); /* Internal. */
+#endif /* not __STDC__ */
+extern const char EXP_CHARS[]; /* JF hide MD floating pt stuff all the same place */
+extern const char FLT_CHARS[];
+
+#ifdef LOCAL_LABELS_DOLLAR
+extern int local_label_defined[];
+#endif
+
+/*
+ * Build any floating-point literal here.
+ * Also build any bignum literal here.
+ */
+
+/* LITTLENUM_TYPE generic_buffer[6]; */ /* JF this is a hack */
+/* Seems atof_machine can backscan through generic_bignum and hit whatever
+ happens to be loaded before it in memory. And its way too complicated
+ for me to fix right. Thus a hack. JF: Just make generic_bignum bigger,
+ and never write into the early words, thus they'll always be zero.
+ I hate Dean's floating-point code. Bleh.
+ */
+LITTLENUM_TYPE generic_bignum[SIZE_OF_LARGE_NUMBER+6];
+FLONUM_TYPE generic_floating_point_number =
+{
+ &generic_bignum[6], /* low (JF: Was 0) */
+ &generic_bignum[SIZE_OF_LARGE_NUMBER+6 - 1], /* high JF: (added +6) */
+ 0, /* leader */
+ 0, /* exponent */
+ 0 /* sign */
+ };
+/* If nonzero, we've been asked to assemble nan, +inf or -inf */
+int generic_floating_point_magic;
+
+/*
+ * Summary of operand().
+ *
+ * in: Input_line_pointer points to 1st char of operand, which may
+ * be a space.
+ *
+ * out: A expressionS. X_seg determines how to understand the rest of the
+ * expressionS.
+ * The operand may have been empty: in this case X_seg == SEG_ABSENT.
+ * Input_line_pointer->(next non-blank) char after operand.
+ *
+ */
+
+static segT
+ operand (expressionP)
+register expressionS * expressionP;
+{
+ register char c;
+ register char *name; /* points to name of symbol */
+ register symbolS * symbolP; /* Points to symbol */
+
+ extern const char hex_value[]; /* In hex_value.c */
+
+#ifdef PIC
+/* XXX */ expressionP->X_got_symbol = 0;
+#endif
+ SKIP_WHITESPACE(); /* Leading whitespace is part of operand. */
+ c = * input_line_pointer ++; /* Input_line_pointer->past char in c. */
+ if (isdigit(c) || (c == 'H' && input_line_pointer[0] == '\''))
+ {
+ register valueT number; /* offset or (absolute) value */
+ register short int digit; /* value of next digit in current radix */
+ /* invented for humans only, hope */
+ /* optimising compiler flushes it! */
+ register short int radix; /* 2, 8, 10 or 16 */
+ /* 0 means we saw start of a floating- */
+ /* point constant. */
+ register short int maxdig = 0;/* Highest permitted digit value. */
+ register int too_many_digits = 0; /* If we see >= this number of */
+ /* digits, assume it is a bignum. */
+ register char * digit_2; /*->2nd digit of number. */
+ int small; /* TRUE if fits in 32 bits. */
+
+
+ if (c == 'H' || c == '0') { /* non-decimal radix */
+ if ((c = *input_line_pointer ++) == 'x' || c == 'X' || c == '\'') {
+ c = *input_line_pointer ++; /* read past "0x" or "0X" or H' */
+ maxdig = radix = 16;
+ too_many_digits = 9;
+ } else {
+ /* If it says '0f' and the line ends or it DOESN'T look like
+ a floating point #, its a local label ref. DTRT */
+ /* likewise for the b's. xoxorich. */
+ if ((c == 'f' || c == 'b' || c == 'B')
+ && (!*input_line_pointer ||
+ (!strchr("+-.0123456789",*input_line_pointer) &&
+ !strchr(EXP_CHARS,*input_line_pointer)))) {
+ maxdig = radix = 10;
+ too_many_digits = 11;
+ c = '0';
+ input_line_pointer -= 2;
+
+ } else if (c == 'b' || c == 'B') {
+ c = *input_line_pointer++;
+ maxdig = radix = 2;
+ too_many_digits = 33;
+
+ } else if (c && strchr(FLT_CHARS,c)) {
+ radix = 0; /* Start of floating-point constant. */
+ /* input_line_pointer->1st char of number. */
+ expressionP->X_add_number = -(isupper(c) ? tolower(c) : c);
+
+ } else { /* By elimination, assume octal radix. */
+ radix = maxdig = 8;
+ too_many_digits = 11;
+ }
+ } /* c == char after "0" or "0x" or "0X" or "0e" etc. */
+ } else {
+ maxdig = radix = 10;
+ too_many_digits = 11;
+ } /* if operand starts with a zero */
+
+ if (radix) { /* Fixed-point integer constant. */
+ /* May be bignum, or may fit in 32 bits. */
+ /*
+ * Most numbers fit into 32 bits, and we want this case to be fast.
+ * So we pretend it will fit into 32 bits. If, after making up a 32
+ * bit number, we realise that we have scanned more digits than
+ * comfortably fit into 32 bits, we re-scan the digits coding
+ * them into a bignum. For decimal and octal numbers we are conservative: some
+ * numbers may be assumed bignums when in fact they do fit into 32 bits.
+ * Numbers of any radix can have excess leading zeros: we strive
+ * to recognise this and cast them back into 32 bits.
+ * We must check that the bignum really is more than 32
+ * bits, and change it back to a 32-bit number if it fits.
+ * The number we are looking for is expected to be positive, but
+ * if it fits into 32 bits as an unsigned number, we let it be a 32-bit
+ * number. The cavalier approach is for speed in ordinary cases.
+ */
+ digit_2 = input_line_pointer;
+ for (number=0; (digit=hex_value[c])<maxdig; c = * input_line_pointer ++)
+ {
+ number = number * radix + digit;
+ }
+ /* C contains character after number. */
+ /* Input_line_pointer->char after C. */
+ small = input_line_pointer - digit_2 < too_many_digits;
+ if (!small)
+ {
+ /*
+ * We saw a lot of digits. Manufacture a bignum the hard way.
+ */
+ LITTLENUM_TYPE *leader; /*->high order littlenum of the bignum. */
+ LITTLENUM_TYPE *pointer; /*->littlenum we are frobbing now. */
+ long carry;
+
+ leader = generic_bignum;
+ generic_bignum[0] = 0;
+ generic_bignum[1] = 0;
+ /* We could just use digit_2, but lets be mnemonic. */
+ input_line_pointer = --digit_2; /*->1st digit. */
+ c = *input_line_pointer++;
+ for (; (carry = hex_value[c]) < maxdig; c = *input_line_pointer++)
+ {
+ for (pointer = generic_bignum;
+ pointer <= leader;
+ pointer++)
+ {
+ long work;
+
+ work = carry + radix * *pointer;
+ *pointer = work & LITTLENUM_MASK;
+ carry = work >> LITTLENUM_NUMBER_OF_BITS;
+ }
+ if (carry)
+ {
+ if (leader < generic_bignum + SIZE_OF_LARGE_NUMBER - 1)
+ { /* Room to grow a longer bignum. */
+ *++leader = carry;
+ }
+ }
+ }
+ /* Again, C is char after number, */
+ /* input_line_pointer->after C. */
+ know(sizeof (int) * 8 == 32);
+ know(LITTLENUM_NUMBER_OF_BITS == 16);
+ /* Hence the constant "2" in the next line. */
+ if (leader < generic_bignum + 2)
+ { /* Will fit into 32 bits. */
+ number =
+ ((generic_bignum[1] & LITTLENUM_MASK) << LITTLENUM_NUMBER_OF_BITS)
+ | (generic_bignum[0] & LITTLENUM_MASK);
+ small = 1;
+ }
+ else
+ {
+ number = leader - generic_bignum + 1; /* Number of littlenums in the bignum. */
+ }
+ }
+ if (small)
+ {
+ /*
+ * Here with number, in correct radix. c is the next char.
+ * Note that unlike Un*x, we allow "011f" "0x9f" to
+ * both mean the same as the (conventional) "9f". This is simply easier
+ * than checking for strict canonical form. Syntax sux!
+ */
+ if (number<10)
+ {
+ if (0
+#ifdef LOCAL_LABELS_FB
+ || c == 'b'
+#endif
+#ifdef LOCAL_LABELS_DOLLAR
+ || (c == '$' && local_label_defined[number])
+#endif
+ )
+ {
+ /*
+ * Backward ref to local label.
+ * Because it is backward, expect it to be DEFINED.
+ */
+ /*
+ * Construct a local label.
+ */
+ name = local_label_name ((int)number, 0);
+ if (((symbolP = symbol_find(name)) != NULL) /* seen before */
+ && (S_IS_DEFINED(symbolP))) /* symbol is defined: OK */
+ { /* Expected path: symbol defined. */
+ /* Local labels are never absolute. Don't waste time checking absoluteness. */
+ know(SEG_NORMAL(S_GET_SEGMENT(symbolP)));
+
+ expressionP->X_add_symbol = symbolP;
+ expressionP->X_add_number = 0;
+ expressionP->X_seg = S_GET_SEGMENT(symbolP);
+ }
+ else
+ { /* Either not seen or not defined. */
+ as_bad("Backw. ref to unknown label \"%d:\", 0 assumed.",
+ number);
+ expressionP->X_add_number = 0;
+ expressionP->X_seg = SEG_ABSOLUTE;
+ }
+ }
+ else
+ {
+ if (0
+#ifdef LOCAL_LABELS_FB
+ || c == 'f'
+#endif
+#ifdef LOCAL_LABELS_DOLLAR
+ || (c == '$' && !local_label_defined[number])
+#endif
+ )
+ {
+ /*
+ * Forward reference. Expect symbol to be undefined or
+ * unknown. Undefined: seen it before. Unknown: never seen
+ * it in this pass.
+ * Construct a local label name, then an undefined symbol.
+ * Don't create a XSEG frag for it: caller may do that.
+ * Just return it as never seen before.
+ */
+ name = local_label_name((int)number, 1);
+ symbolP = symbol_find_or_make(name);
+ /* We have no need to check symbol properties. */
+#ifndef MANY_SEGMENTS
+ /* Since "know" puts its arg into a "string", we
+ can't have newlines in the argument. */
+ know(S_GET_SEGMENT(symbolP) == SEG_UNKNOWN || S_GET_SEGMENT(symbolP) == SEG_TEXT || S_GET_SEGMENT(symbolP) == SEG_DATA);
+#endif
+ expressionP->X_add_symbol = symbolP;
+ expressionP->X_seg = SEG_UNKNOWN;
+ expressionP->X_subtract_symbol = NULL;
+ expressionP->X_add_number = 0;
+ }
+ else
+ { /* Really a number, not a local label. */
+ expressionP->X_add_number = number;
+ expressionP->X_seg = SEG_ABSOLUTE;
+ input_line_pointer--; /* Restore following character. */
+ } /* if (c == 'f') */
+ } /* if (c == 'b') */
+ }
+ else
+ { /* Really a number. */
+ expressionP->X_add_number = number;
+ expressionP->X_seg = SEG_ABSOLUTE;
+ input_line_pointer--; /* Restore following character. */
+ } /* if (number<10) */
+ }
+ else
+ {
+ expressionP->X_add_number = number;
+ expressionP->X_seg = SEG_BIG;
+ input_line_pointer --; /*->char following number. */
+ } /* if (small) */
+ } /* (If integer constant) */
+ else
+ { /* input_line_pointer->*/
+ /* floating-point constant. */
+ int error_code;
+
+ error_code = atof_generic
+ (& input_line_pointer, ".", EXP_CHARS,
+ & generic_floating_point_number);
+
+ if (error_code)
+ {
+ if (error_code == ERROR_EXPONENT_OVERFLOW)
+ {
+ as_bad("Bad floating-point constant: exponent overflow, probably assembling junk");
+ }
+ else
+ {
+ as_bad("Bad floating-point constant: unknown error code=%d.", error_code);
+ }
+ }
+ expressionP->X_seg = SEG_BIG;
+ /* input_line_pointer->just after constant, */
+ /* which may point to whitespace. */
+ know(expressionP->X_add_number < 0); /* < 0 means "floating point". */
+ } /* if (not floating-point constant) */
+ }
+ else if (c == '.' && !is_part_of_name(*input_line_pointer)) {
+ extern struct obstack frags;
+
+ /*
+ JF: '.' is pseudo symbol with value of current location in current
+ segment...
+ */
+ symbolP = symbol_new("\001L0",
+ now_seg,
+ (valueT)(obstack_next_free(&frags)-frag_now->fr_literal),
+ frag_now);
+
+ expressionP->X_add_number=0;
+ expressionP->X_add_symbol=symbolP;
+ expressionP->X_seg = now_seg;
+
+ } else if (is_name_beginner(c)) { /* here if did not begin with a digit */
+
+ /*
+ * Identifier begins here.
+ * This is kludged for speed, so code is repeated.
+ */
+ name = input_line_pointer - 1;
+ c = get_symbol_end();
+ symbolP = symbol_find_or_make(name);
+ /*
+ * If we have an absolute symbol or a reg, then we know its value now.
+ */
+ expressionP->X_seg = S_GET_SEGMENT(symbolP);
+ switch (expressionP->X_seg)
+ {
+ case SEG_ABSOLUTE:
+ case SEG_REGISTER:
+ expressionP->X_add_number = S_GET_VALUE(symbolP);
+ break;
+
+ default:
+ expressionP->X_add_number = 0;
+#ifdef PIC
+ if (symbolP == GOT_symbol) {
+ expressionP->X_got_symbol = symbolP;
+ got_referenced = 1;
+ } else
+#endif
+ expressionP->X_add_symbol = symbolP;
+ }
+ *input_line_pointer = c;
+ expressionP->X_subtract_symbol = NULL;
+ } else if (c == '(' || c == '[') {/* didn't begin with digit & not a name */
+ (void)expression(expressionP);
+ /* Expression() will pass trailing whitespace */
+ if (c == '(' && *input_line_pointer++ != ')' ||
+ c == '[' && *input_line_pointer++ != ']') {
+ as_bad("Missing ')' assumed");
+ input_line_pointer--;
+ }
+ /* here with input_line_pointer->char after "(...)" */
+ } else if (c == '~' || c == '-' || c == '+') {
+ /* unary operator: hope for SEG_ABSOLUTE */
+ switch (operand (expressionP)) {
+ case SEG_ABSOLUTE:
+ /* input_line_pointer->char after operand */
+ if (c == '-') {
+ expressionP->X_add_number = - expressionP->X_add_number;
+ /*
+ * Notice: '-' may overflow: no warning is given. This is compatible
+ * with other people's assemblers. Sigh.
+ */
+ } else if (c == '~') {
+ expressionP->X_add_number = ~ expressionP->X_add_number;
+ } else if (c != '+') {
+ know(0);
+ } /* switch on unary operator */
+ break;
+
+ default: /* unary on non-absolute is unsuported */
+ if (!SEG_NORMAL(operand(expressionP)))
+ {
+ as_bad("Unary operator %c ignored because bad operand follows", c);
+ break;
+ }
+ /* Fall through for normal segments ****/
+ case SEG_PASS1:
+ case SEG_UNKNOWN:
+ if (c == '-') { /* JF I hope this hack works */
+ expressionP->X_subtract_symbol=expressionP->X_add_symbol;
+ expressionP->X_add_symbol=0;
+ expressionP->X_seg=SEG_DIFFERENCE;
+ break;
+ }
+ /* Expression undisturbed from operand(). */
+ }
+ }
+ else if (c == '\'')
+ {
+ /*
+ * Warning: to conform to other people's assemblers NO ESCAPEMENT is permitted
+ * for a single quote. The next character, parity errors and all, is taken
+ * as the value of the operand. VERY KINKY.
+ */
+ expressionP->X_add_number = * input_line_pointer ++;
+ expressionP->X_seg = SEG_ABSOLUTE;
+ }
+ else
+ {
+ /* can't imagine any other kind of operand */
+ expressionP->X_seg = SEG_ABSENT;
+ input_line_pointer --;
+ md_operand (expressionP);
+ }
+ /*
+ * It is more 'efficient' to clean up the expressions when they are created.
+ * Doing it here saves lines of code.
+ */
+ clean_up_expression(expressionP);
+ SKIP_WHITESPACE(); /*->1st char after operand. */
+ know(*input_line_pointer != ' ');
+ return(expressionP->X_seg);
+} /* operand() */
+
+/* Internal. Simplify a struct expression for use by expr() */
+
+/*
+ * In: address of a expressionS.
+ * The X_seg field of the expressionS may only take certain values.
+ * Now, we permit SEG_PASS1 to make code smaller & faster.
+ * Elsewise we waste time special-case testing. Sigh. Ditto SEG_ABSENT.
+ * Out: expressionS may have been modified:
+ * 'foo-foo' symbol references cancelled to 0,
+ * which changes X_seg from SEG_DIFFERENCE to SEG_ABSOLUTE;
+ * Unused fields zeroed to help expr().
+ */
+
+static void
+ clean_up_expression (expressionP)
+register expressionS *expressionP;
+{
+ switch (expressionP->X_seg) {
+ case SEG_ABSENT:
+ case SEG_PASS1:
+ expressionP->X_add_symbol = NULL;
+ expressionP->X_subtract_symbol = NULL;
+ expressionP->X_add_number = 0;
+ break;
+
+ case SEG_BIG:
+ case SEG_ABSOLUTE:
+ expressionP->X_subtract_symbol = NULL;
+ expressionP->X_add_symbol = NULL;
+ break;
+
+ case SEG_UNKNOWN:
+ expressionP->X_subtract_symbol = NULL;
+ break;
+
+ case SEG_DIFFERENCE:
+ /*
+ * It does not hurt to 'cancel' NULL == NULL
+ * when comparing symbols for 'eq'ness.
+ * It is faster to re-cancel them to NULL
+ * than to check for this special case.
+ */
+ if (expressionP->X_subtract_symbol == expressionP->X_add_symbol
+ || (expressionP->X_subtract_symbol
+ && expressionP->X_add_symbol
+ && expressionP->X_subtract_symbol->sy_frag == expressionP->X_add_symbol->sy_frag
+ && S_GET_VALUE(expressionP->X_subtract_symbol) == S_GET_VALUE(expressionP->X_add_symbol))) {
+ expressionP->X_subtract_symbol = NULL;
+ expressionP->X_add_symbol = NULL;
+ expressionP->X_seg = SEG_ABSOLUTE;
+ }
+ break;
+
+ case SEG_REGISTER:
+ expressionP->X_add_symbol = NULL;
+ expressionP->X_subtract_symbol = NULL;
+ break;
+
+ default:
+ if (SEG_NORMAL(expressionP->X_seg)) {
+ expressionP->X_subtract_symbol = NULL;
+ }
+ else {
+ BAD_CASE (expressionP->X_seg);
+ }
+ break;
+ }
+} /* clean_up_expression() */
+
+/*
+ * expr_part ()
+ *
+ * Internal. Made a function because this code is used in 2 places.
+ * Generate error or correct X_?????_symbol of expressionS.
+ */
+
+/*
+ * symbol_1 += symbol_2 ... well ... sort of.
+ */
+
+static segT
+ expr_part (symbol_1_PP, symbol_2_P)
+symbolS ** symbol_1_PP;
+symbolS * symbol_2_P;
+{
+ segT return_value;
+#ifndef MANY_SEGMENTS
+ know((* symbol_1_PP) == NULL || (S_GET_SEGMENT(*symbol_1_PP) == SEG_TEXT) || (S_GET_SEGMENT(*symbol_1_PP) == SEG_DATA) || (S_GET_SEGMENT(*symbol_1_PP) == SEG_BSS) || (!S_IS_DEFINED(* symbol_1_PP)));
+ know(symbol_2_P == NULL || (S_GET_SEGMENT(symbol_2_P) == SEG_TEXT) || (S_GET_SEGMENT(symbol_2_P) == SEG_DATA) || (S_GET_SEGMENT(symbol_2_P) == SEG_BSS) || (!S_IS_DEFINED(symbol_2_P)));
+#endif
+ if (* symbol_1_PP)
+ {
+ if (!S_IS_DEFINED(* symbol_1_PP))
+ {
+ if (symbol_2_P)
+ {
+ return_value = SEG_PASS1;
+ * symbol_1_PP = NULL;
+ }
+ else
+ {
+ know(!S_IS_DEFINED(* symbol_1_PP));
+ return_value = SEG_UNKNOWN;
+ }
+ }
+ else
+ {
+ if (symbol_2_P)
+ {
+ if (!S_IS_DEFINED(symbol_2_P))
+ {
+ * symbol_1_PP = NULL;
+ return_value = SEG_PASS1;
+ }
+ else
+ {
+ /* {seg1} - {seg2} */
+ as_bad("Expression too complex, 2 symbols forgotten: \"%s\" \"%s\"",
+ S_GET_NAME(* symbol_1_PP), S_GET_NAME(symbol_2_P));
+ * symbol_1_PP = NULL;
+ return_value = SEG_ABSOLUTE;
+ }
+ }
+ else
+ {
+ return_value = S_GET_SEGMENT(* symbol_1_PP);
+ }
+ }
+ }
+ else
+ { /* (* symbol_1_PP) == NULL */
+ if (symbol_2_P)
+ {
+ * symbol_1_PP = symbol_2_P;
+ return_value = S_GET_SEGMENT(symbol_2_P);
+ }
+ else
+ {
+ * symbol_1_PP = NULL;
+ return_value = SEG_ABSOLUTE;
+ }
+ }
+#ifndef MANY_SEGMENTS
+ know(return_value == SEG_ABSOLUTE || return_value == SEG_TEXT || return_value == SEG_DATA || return_value == SEG_BSS || return_value == SEG_UNKNOWN || return_value == SEG_PASS1);
+#endif
+ know((*symbol_1_PP) == NULL || (S_GET_SEGMENT(*symbol_1_PP) == return_value));
+ return (return_value);
+} /* expr_part() */
+
+void ps (s)
+symbolS *s;
+{
+ fprintf (stdout, "%s type %s%s",
+ S_GET_NAME(s),
+ S_IS_EXTERNAL(s) ? "EXTERNAL " : "",
+ segment_name(S_GET_SEGMENT(s)));
+}
+void pe (e)
+expressionS *e;
+{
+ fprintf (stdout, " segment %s\n", segment_name (e->X_seg));
+ fprintf (stdout, " add_number %d (%x)\n",
+ e->X_add_number, e->X_add_number);
+ if (e->X_add_symbol) {
+ fprintf (stdout, " add_symbol ");
+ ps (e->X_add_symbol);
+ fprintf (stdout, "\n");
+ }
+ if (e->X_subtract_symbol) {
+ fprintf (stdout, " sub_symbol ");
+ ps (e->X_subtract_symbol);
+ fprintf (stdout, "\n");
+ }
+}
+
+/* Expression parser. */
+
+/*
+ * We allow an empty expression, and just assume (absolute,0) silently.
+ * Unary operators and parenthetical expressions are treated as operands.
+ * As usual, Q == quantity == operand, O == operator, X == expression mnemonics.
+ *
+ * We used to do a aho/ullman shift-reduce parser, but the logic got so
+ * warped that I flushed it and wrote a recursive-descent parser instead.
+ * Now things are stable, would anybody like to write a fast parser?
+ * Most expressions are either register (which does not even reach here)
+ * or 1 symbol. Then "symbol+constant" and "symbol-symbol" are common.
+ * So I guess it doesn't really matter how inefficient more complex expressions
+ * are parsed.
+ *
+ * After expr(RANK,resultP) input_line_pointer->operator of rank <= RANK.
+ * Also, we have consumed any leading or trailing spaces (operand does that)
+ * and done all intervening operators.
+ */
+
+typedef enum
+{
+ O_illegal, /* (0) what we get for illegal op */
+
+ O_multiply, /* (1) * */
+ O_divide, /* (2) / */
+ O_modulus, /* (3) % */
+ O_left_shift, /* (4) < */
+ O_right_shift, /* (5) > */
+ O_bit_inclusive_or, /* (6) | */
+ O_bit_or_not, /* (7) ! */
+ O_bit_exclusive_or, /* (8) ^ */
+ O_bit_and, /* (9) & */
+ O_add, /* (10) + */
+ O_subtract /* (11) - */
+ }
+operatorT;
+
+#define __ O_illegal
+
+static const operatorT op_encoding[256] = { /* maps ASCII->operators */
+
+ __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __,
+ __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __,
+
+ __, O_bit_or_not, __, __, __, O_modulus, O_bit_and, __,
+ __, __, O_multiply, O_add, __, O_subtract, __, O_divide,
+ __, __, __, __, __, __, __, __,
+ __, __, __, __, O_left_shift, __, O_right_shift, __,
+ __, __, __, __, __, __, __, __,
+ __, __, __, __, __, __, __, __,
+ __, __, __, __, __, __, __, __,
+ __, __, __, __, __, __, O_bit_exclusive_or, __,
+ __, __, __, __, __, __, __, __,
+ __, __, __, __, __, __, __, __,
+ __, __, __, __, __, __, __, __,
+ __, __, __, __, O_bit_inclusive_or, __, __, __,
+
+ __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __,
+ __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __,
+ __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __,
+ __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __,
+ __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __,
+ __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __,
+ __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __,
+ __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __
+ };
+
+
+/*
+ * Rank Examples
+ * 0 operand, (expression)
+ * 1 + -
+ * 2 & ^ ! |
+ * 3 * / % << >>
+ */
+static const operator_rankT
+ op_rank[] = { 0, 3, 3, 3, 3, 3, 2, 2, 2, 2, 1, 1 };
+
+/* Return resultP->X_seg. */
+segT expr(rank, resultP)
+ register operator_rankT rank; /* Larger # is higher rank. */
+ register expressionS *resultP; /* Deliver result here. */
+{
+ expressionS right;
+ register operatorT op_left;
+ register char c_left; /* 1st operator character. */
+ register operatorT op_right;
+ register char c_right;
+
+ know(rank >= 0);
+ (void) operand(resultP);
+ know(*input_line_pointer != ' '); /* Operand() gobbles spaces. */
+ c_left = *input_line_pointer; /* Potential operator character. */
+ op_left = op_encoding[c_left];
+
+ while (op_left != O_illegal && op_rank[(int) op_left] > rank) {
+ input_line_pointer++; /*->after 1st character of operator. */
+
+ /* Operators "<<" and ">>" have 2 characters. */
+ if (*input_line_pointer == c_left && (c_left == '<' || c_left == '>')) {
+ input_line_pointer ++;
+ } /*->after operator. */
+ if (SEG_ABSENT == expr (op_rank[(int) op_left], &right)) {
+ as_warn("Missing operand value assumed absolute 0.");
+ resultP->X_add_number = 0;
+ resultP->X_subtract_symbol = NULL;
+ resultP->X_add_symbol = NULL;
+ resultP->X_seg = SEG_ABSOLUTE;
+ }
+
+ know(*input_line_pointer != ' ');
+ c_right = *input_line_pointer;
+ op_right = op_encoding[c_right];
+
+ if (*input_line_pointer == c_right && (c_right == '<' || c_right == '>')) {
+ input_line_pointer ++;
+ } /*->after operator. */
+
+ know((int) op_right == 0 || op_rank[(int) op_right] <= op_rank[(int) op_left]);
+ /* input_line_pointer->after right-hand quantity. */
+ /* left-hand quantity in resultP */
+ /* right-hand quantity in right. */
+ /* operator in op_left. */
+ if (resultP->X_seg == SEG_PASS1 || right.X_seg == SEG_PASS1) {
+ resultP->X_seg = SEG_PASS1;
+ } else {
+ if (resultP->X_seg == SEG_BIG) {
+ as_warn("Left operand of %c is a %s. Integer 0 assumed.",
+ c_left, resultP->X_add_number > 0 ? "bignum" : "float");
+ resultP->X_seg = SEG_ABSOLUTE;
+ resultP->X_add_symbol = 0;
+ resultP->X_subtract_symbol = 0;
+ resultP->X_add_number = 0;
+ }
+ if (right.X_seg == SEG_BIG) {
+ as_warn("Right operand of %c is a %s. Integer 0 assumed.",
+ c_left, right.X_add_number > 0 ? "bignum" : "float");
+ right.X_seg = SEG_ABSOLUTE;
+ right.X_add_symbol = 0;
+ right.X_subtract_symbol = 0;
+ right.X_add_number = 0;
+ }
+ if (op_left == O_subtract) {
+ /*
+ * Convert - into + by exchanging symbols and negating number.
+ * I know -infinity can't be negated in 2's complement:
+ * but then it can't be subtracted either. This trick
+ * does not cause any further inaccuracy.
+ */
+
+ register symbolS * symbolP;
+
+ right.X_add_number = - right.X_add_number;
+ symbolP = right.X_add_symbol;
+ right.X_add_symbol = right.X_subtract_symbol;
+ right.X_subtract_symbol = symbolP;
+ if (symbolP) {
+ right.X_seg = SEG_DIFFERENCE;
+ }
+ op_left = O_add;
+ }
+
+ if (op_left == O_add) {
+ segT seg1;
+ segT seg2;
+#ifndef MANY_SEGMENTS
+ know(resultP->X_seg == SEG_DATA
+ || resultP->X_seg == SEG_TEXT
+ || resultP->X_seg == SEG_BSS
+ || resultP->X_seg == SEG_UNKNOWN
+ || resultP->X_seg == SEG_DIFFERENCE
+ || resultP->X_seg == SEG_ABSOLUTE
+ || resultP->X_seg == SEG_PASS1);
+ know(right.X_seg == SEG_DATA
+ || right.X_seg == SEG_TEXT
+ || right.X_seg == SEG_BSS
+ || right.X_seg == SEG_UNKNOWN
+ || right.X_seg == SEG_DIFFERENCE
+ || right.X_seg == SEG_ABSOLUTE
+ || right.X_seg == SEG_PASS1);
+#endif
+ clean_up_expression(& right);
+ clean_up_expression(resultP);
+
+#ifdef PIC
+/* XXX - kludge here to accomodate "_GLOBAL_OFFSET_TABLE + (x - y)"
+ * expressions: this only works for this special case, the
+ * _GLOBAL_OFFSET_TABLE thing *must* be the left operand, the whole
+ * expression is given the segment of right expression (always a DIFFERENCE,
+ * which should get resolved by fixup_segment())
+ */
+ if (resultP->X_got_symbol) {
+ resultP->X_add_symbol = right.X_add_symbol;
+ resultP->X_subtract_symbol = right.X_subtract_symbol;
+ seg1 = S_GET_SEGMENT(right.X_add_symbol);
+ seg2 = S_GET_SEGMENT(right.X_subtract_symbol);
+ resultP->X_seg = right.X_seg;
+ } else {
+#endif
+ seg1 = expr_part(&resultP->X_add_symbol, right.X_add_symbol);
+ seg2 = expr_part(&resultP->X_subtract_symbol, right.X_subtract_symbol);
+#ifdef PIC
+ }
+#endif
+ if (seg1 == SEG_PASS1 || seg2 == SEG_PASS1) {
+ need_pass_2 = 1;
+ resultP->X_seg = SEG_PASS1;
+ } else if (seg2 == SEG_ABSOLUTE)
+ resultP->X_seg = seg1;
+ else if (seg1 != SEG_UNKNOWN
+ && seg1 != SEG_ABSOLUTE
+ && seg2 != SEG_UNKNOWN
+ && seg1 != seg2) {
+ know(seg2 != SEG_ABSOLUTE);
+ know(resultP->X_subtract_symbol);
+#ifndef MANY_SEGMENTS
+ know(seg1 == SEG_TEXT || seg1 == SEG_DATA || seg1 == SEG_BSS);
+ know(seg2 == SEG_TEXT || seg2 == SEG_DATA || seg2 == SEG_BSS);
+#endif
+ know(resultP->X_add_symbol);
+ know(resultP->X_subtract_symbol);
+ as_bad("Expression too complex: forgetting %s - %s",
+ S_GET_NAME(resultP->X_add_symbol),
+ S_GET_NAME(resultP->X_subtract_symbol));
+ resultP->X_seg = SEG_ABSOLUTE;
+ /* Clean_up_expression() will do the rest. */
+ } else
+ resultP->X_seg = SEG_DIFFERENCE;
+
+ resultP->X_add_number += right.X_add_number;
+ clean_up_expression(resultP);
+ } else { /* Not +. */
+ if (resultP->X_seg == SEG_UNKNOWN || right.X_seg == SEG_UNKNOWN) {
+ resultP->X_seg = SEG_PASS1;
+ need_pass_2 = 1;
+ } else {
+ resultP->X_subtract_symbol = NULL;
+ resultP->X_add_symbol = NULL;
+
+ /* Will be SEG_ABSOLUTE. */
+ if (resultP->X_seg != SEG_ABSOLUTE || right.X_seg != SEG_ABSOLUTE) {
+ as_bad("Relocation error. Absolute 0 assumed.");
+ resultP->X_seg = SEG_ABSOLUTE;
+ resultP->X_add_number = 0;
+ } else {
+ switch (op_left) {
+ case O_bit_inclusive_or:
+ resultP->X_add_number |= right.X_add_number;
+ break;
+
+ case O_modulus:
+ if (right.X_add_number) {
+ resultP->X_add_number %= right.X_add_number;
+ } else {
+ as_warn("Division by 0. 0 assumed.");
+ resultP->X_add_number = 0;
+ }
+ break;
+
+ case O_bit_and:
+ resultP->X_add_number &= right.X_add_number;
+ break;
+
+ case O_multiply:
+ resultP->X_add_number *= right.X_add_number;
+ break;
+
+ case O_divide:
+ if (right.X_add_number) {
+ resultP->X_add_number /= right.X_add_number;
+ } else {
+ as_warn("Division by 0. 0 assumed.");
+ resultP->X_add_number = 0;
+ }
+ break;
+
+ case O_left_shift:
+ resultP->X_add_number <<= right.X_add_number;
+ break;
+
+ case O_right_shift:
+ resultP->X_add_number >>= right.X_add_number;
+ break;
+
+ case O_bit_exclusive_or:
+ resultP->X_add_number ^= right.X_add_number;
+ break;
+
+ case O_bit_or_not:
+ resultP->X_add_number |= ~ right.X_add_number;
+ break;
+
+ default:
+ BAD_CASE(op_left);
+ break;
+ } /* switch (operator) */
+ }
+ } /* If we have to force need_pass_2. */
+ } /* If operator was +. */
+ } /* If we didn't set need_pass_2. */
+ op_left = op_right;
+ } /* While next operator is >= this rank. */
+
+ return(resultP->X_seg);
+} /* expr() */
+
+/*
+ * get_symbol_end()
+ *
+ * This lives here because it belongs equally in expr.c & read.c.
+ * Expr.c is just a branch office read.c anyway, and putting it
+ * here lessens the crowd at read.c.
+ *
+ * Assume input_line_pointer is at start of symbol name.
+ * Advance input_line_pointer past symbol name.
+ * Turn that character into a '\0', returning its former value.
+ * This allows a string compare (RMS wants symbol names to be strings)
+ * of the symbol name.
+ * There will always be a char following symbol name, because all good
+ * lines end in end-of-line.
+ */
+char
+ get_symbol_end()
+{
+ register char c;
+
+ while (is_part_of_name(c = *input_line_pointer++)) ;;
+ *--input_line_pointer = 0;
+ return (c);
+}
+
+
+unsigned int get_single_number()
+{
+ expressionS exp;
+ operand(&exp);
+ return exp.X_add_number;
+
+}
+/*
+ * Local Variables:
+ * comment-column: 0
+ * fill-column: 131
+ * End:
+ */
+
+/* end of expr.c */
diff --git a/gnu/usr.bin/as/expr.h b/gnu/usr.bin/as/expr.h
new file mode 100644
index 0000000..d0b68a5
--- /dev/null
+++ b/gnu/usr.bin/as/expr.h
@@ -0,0 +1,85 @@
+/* expr.h -> header file for expr.c
+ Copyright (C) 1987, 1992 Free Software Foundation, Inc.
+
+ This file is part of GAS, the GNU Assembler.
+
+ GAS is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GAS is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GAS; see the file COPYING. If not, write to
+ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+/*
+ * $Id: expr.h,v 1.2 1993/11/03 00:51:31 paul Exp $
+ */
+
+
+/*
+ * Abbreviations (mnemonics).
+ *
+ * O operator
+ * Q quantity, operand
+ * X eXpression
+ */
+
+/*
+ * By popular demand, we define a struct to represent an expression.
+ * This will no doubt mutate as expressions become baroque.
+ *
+ * Currently, we support expressions like "foo-bar+42".
+ * In other words we permit a (possibly undefined) minuend, a
+ * (possibly undefined) subtrahend and an (absolute) augend.
+ * RMS says this is so we can have 1-pass assembly for any compiler
+ * emmissions, and a 'case' statement might emit 'undefined1 - undefined2'.
+ *
+ * To simplify table-driven dispatch, we also have a "segment" for the
+ * entire expression. That way we don't require complex reasoning about
+ * whether particular components are defined; and we can change component
+ * semantics without re-working all the dispatch tables in the assembler.
+ * In other words the "type" of an expression is its segment.
+ */
+
+typedef struct {
+ symbolS *X_add_symbol; /* foo */
+ symbolS *X_subtract_symbol; /* bar */
+ symbolS *X_got_symbol; /* got */
+ long X_add_number; /* 42. Must be signed. */
+ segT X_seg; /* What segment (expr type)? */
+}
+expressionS;
+
+/* result should be type (expressionS *). */
+#define expression(result) expr(0,result)
+
+/* If an expression is SEG_BIG, look here */
+/* for its value. These common data may */
+/* be clobbered whenever expr() is called. */
+extern FLONUM_TYPE generic_floating_point_number; /* Flonums returned here. */
+/* Enough to hold most precise flonum. */
+extern LITTLENUM_TYPE generic_bignum[]; /* Bignums returned here. */
+#define SIZE_OF_LARGE_NUMBER (20) /* Number of littlenums in above. */
+
+typedef char operator_rankT;
+
+#if __STDC__ == 1
+
+char get_symbol_end(void);
+segT expr(int rank, expressionS *resultP);
+unsigned int get_single_number(void);
+
+#else /* not __STDC__ */
+
+char get_symbol_end();
+segT expr();
+unsigned int get_single_number();
+
+#endif /* not __STDC__ */
+
+/* end of expr.h */
diff --git a/gnu/usr.bin/as/flo-const.c b/gnu/usr.bin/as/flo-const.c
new file mode 100644
index 0000000..90f0af1
--- /dev/null
+++ b/gnu/usr.bin/as/flo-const.c
@@ -0,0 +1,161 @@
+/* flonum_const.c - Useful Flonum constants
+ Copyright (C) 1987, 1990, 1991, 1992 Free Software Foundation, Inc.
+
+ This file is part of GAS, the GNU Assembler.
+
+ GAS is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GAS is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GAS; see the file COPYING. If not, write to
+ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#ifndef lint
+static char rcsid[] = "$Id: flo-const.c,v 1.1 1993/11/03 00:51:32 paul Exp $";
+#endif
+
+#include "flonum.h"
+/* JF: I added the last entry to this table, and I'm not
+ sure if its right or not. Could go either way. I wish
+ I really understood this stuff. */
+
+
+const int table_size_of_flonum_powers_of_ten = 11;
+
+static const LITTLENUM_TYPE zero[] = { 1 };
+
+/***********************************************************************\
+ * *
+ * Warning: the low order bits may be WRONG here. *
+ * I took this from a suspect bc(1) script. *
+ * "minus_X"[] is supposed to be 10^(2^-X) expressed in base 2^16. *
+ * The radix point is just AFTER the highest element of the [] *
+ * *
+ * Because bc rounds DOWN for printing (I think), the lowest *
+ * significance littlenums should probably have 1 added to them. *
+ * *
+ \***********************************************************************/
+
+/* JF: If this equals 6553/(2^16)+39321/(2^32)+... it approaches .1 */
+static const LITTLENUM_TYPE minus_1[] = {
+ 39321, 39321, 39321, 39321, 39321, 39321, 39321, 39321, 39321, 39321,
+ 39321, 39321, 39321, 39321, 39321, 39321, 39321, 39321, 39321, 6553 };
+static const LITTLENUM_TYPE plus_1[] = { 10 };
+
+/* JF: If this equals 655/(2^16) + 23592/(2^32) + ... it approaches .01 */
+static const LITTLENUM_TYPE minus_2[] = {
+ 10485, 36700, 62914, 23592, 49807, 10485, 36700, 62914, 23592, 49807,
+ 10485, 36700, 62914, 23592, 49807, 10485, 36700, 62914, 23592, 655 };
+static const LITTLENUM_TYPE plus_2[] = { 100 };
+
+/* This approaches .0001 */
+static const LITTLENUM_TYPE minus_3[] = {
+ 52533, 20027, 37329, 65116, 64067, 60397, 14784, 18979, 33659, 19503,
+ 2726, 9542, 629, 2202, 40475, 10590, 4299, 47815, 36280, 6 };
+static const LITTLENUM_TYPE plus_3[] = { 10000 };
+
+/* JF: this approaches 1e-8 */
+static const LITTLENUM_TYPE minus_4[] = {
+ 22516, 49501, 54293, 19424, 60699, 6716, 24348, 22618, 23904, 21327,
+ 3919, 44703, 19149, 28803, 48959, 6259, 50273, 62237, 42 };
+/* This equals 1525 * 2^16 + 57600 */
+static const LITTLENUM_TYPE plus_4[] = { 57600, 1525 };
+
+/* This approaches 1e-16 */
+static const LITTLENUM_TYPE minus_5[] = {
+ 22199, 45957, 17005, 26266, 10526, 16260, 55017, 35680, 40443, 19789,
+ 17356, 30195, 55905, 28426, 63010, 44197, 1844 };
+static const LITTLENUM_TYPE plus_5[] = { 28609, 34546, 35 };
+
+static const LITTLENUM_TYPE minus_6[] = {
+ 30926, 26518, 13110, 43018, 54982, 48258, 24658, 15209, 63366, 11929,
+ 20069, 43857, 60487, 51 };
+static const LITTLENUM_TYPE plus_6[] = { 61313, 34220, 16731, 11629, 1262 };
+
+static const LITTLENUM_TYPE minus_7[] = {
+ 29819, 14733, 21490, 40602, 31315, 65186, 2695 };
+static const LITTLENUM_TYPE plus_7[] = {
+ 7937, 49002, 60772, 28216, 38893, 55975, 63988, 59711, 20227, 24 };
+
+static const LITTLENUM_TYPE minus_8[] = {
+ 45849, 19069, 18068, 36324, 37948, 48745, 10873, 64360, 15961, 20566,
+ 24178, 15922, 59427, 110 };
+static const LITTLENUM_TYPE plus_8[] = {
+ 15873, 11925, 39177, 991, 14589, 19735, 25347, 65086, 53853, 938,
+ 37209, 47086, 33626, 23253, 32586, 42547, 9731, 59679, 590 };
+
+static const LITTLENUM_TYPE minus_9[] = {
+ 63601, 55221, 43562, 33661, 29067, 28203, 65417, 64352, 22462, 41110,
+ 12570, 28635, 23199, 50572, 28471, 27074, 46375, 64028, 13106, 63700,
+ 32698, 17493, 32420, 34382, 22750, 20681, 12300 };
+static const LITTLENUM_TYPE plus_9[] = {
+ 63564, 61556, 29377, 54467, 18621, 28141, 36415, 61241, 47119, 30026,
+ 19740, 46002, 13541, 61413, 30480, 38664, 32205, 50593, 51112, 48904,
+ 48263, 43814, 286, 30826, 52813, 62575, 61390, 24540, 21495, 5 };
+
+static const LITTLENUM_TYPE minus_10[] = {
+ 50313, 34681, 1464, 25889, 19575, 41125, 17635, 4598, 49708, 13427,
+ 17287, 56115, 53783, 38255, 32415, 17778, 31596, 7557, 20951, 18477,
+ 40353, 1178, 44405, 11837, 11571, 50963, 15649, 11698, 40675, 2308, };
+static const LITTLENUM_TYPE plus_10[] = {
+ 18520, 53764, 54535, 61910, 61962, 59843, 46270, 58053, 12473, 63785,
+ 2449, 43230, 50044, 47595, 10403, 35766, 32607, 1124, 24966, 35044,
+ 25524, 23631, 18826, 14518, 58448, 14562, 49618, 5588, 25396, 28 };
+
+static const LITTLENUM_TYPE minus_11[] = {
+ 6223, 59909, 62437, 59960, 14652, 45336, 48800, 7647, 51962, 37982,
+ 60436, 58176, 26767, 8440, 9831, 48556, 20994, 14148, 6757, 17221,
+ 60624, 46129, 53210, 44085, 54016, 24259, 11232, 21229, 21313, 81, };
+static const LITTLENUM_TYPE plus_11[] = {
+ 36159, 2055, 33615, 61362, 23581, 62454, 9748, 15275, 39284, 58636,
+ 16269, 42793, 47240, 45774, 50861, 48400, 9413, 40281, 4030, 9572,
+ 7984, 33038, 59522, 19450, 40593, 24486, 54320, 6661, 55766, 805, };
+
+/* Shut up complaints about differing pointer types. They only differ
+ in the const attribute, but there isn't any easy way to do this
+ */
+#define X (LITTLENUM_TYPE *)
+
+const FLONUM_TYPE flonum_negative_powers_of_ten[] = {
+ {X zero, X zero, X zero, 0, '+'},
+ {X minus_1, X minus_1 +19, X minus_1 + 19, -20, '+'},
+ {X minus_2, X minus_2 +19, X minus_2 + 19, -20, '+'},
+ {X minus_3, X minus_3 +19, X minus_3 + 19, -20, '+'},
+ {X minus_4, X minus_4 +18, X minus_4 + 18, -20, '+'},
+ {X minus_5, X minus_5 +16, X minus_5 + 16, -20, '+'},
+ {X minus_6, X minus_6 +13, X minus_6 + 13, -20, '+'},
+ {X minus_7, X minus_7 + 6, X minus_7 + 6, -20, '+'},
+ {X minus_8, X minus_8 +13, X minus_8 + 13, -40, '+'},
+ {X minus_9, X minus_9 +26, X minus_9 + 26, -80, '+'},
+ {X minus_10, X minus_10+29, X minus_10 + 29,-136, '+'},
+ {X minus_11, X minus_11+29, X minus_11 + 29,-242, '+'},
+};
+
+const FLONUM_TYPE flonum_positive_powers_of_ten[] = {
+ {X zero, X zero, X zero, 0, '+'},
+ {X plus_1, X plus_1 + 0, X plus_1 + 0, 0, '+'},
+ {X plus_2, X plus_2 + 0, X plus_2 + 0, 0, '+'},
+ {X plus_3, X plus_3 + 0, X plus_3 + 0, 0, '+'},
+ {X plus_4, X plus_4 + 1, X plus_4 + 1, 0, '+'},
+ {X plus_5, X plus_5 + 2, X plus_5 + 2, 1, '+'},
+ {X plus_6, X plus_6 + 4, X plus_6 + 4, 2, '+'},
+ {X plus_7, X plus_7 + 9, X plus_7 + 9, 4, '+'},
+ {X plus_8, X plus_8 + 18, X plus_8 + 18, 8, '+'},
+ {X plus_9, X plus_9 + 29, X plus_9 + 29, 24, '+'},
+ {X plus_10, X plus_10 + 29, X plus_10 + 29, 77, '+'},
+ {X plus_11, X plus_11 + 29, X plus_11 + 29, 183, '+'},
+};
+
+#ifdef HO_VMS
+dummy1()
+{
+}
+#endif
+/* end of flonum_const.c */
diff --git a/gnu/usr.bin/as/flo-copy.c b/gnu/usr.bin/as/flo-copy.c
new file mode 100644
index 0000000..6e1b306
--- /dev/null
+++ b/gnu/usr.bin/as/flo-copy.c
@@ -0,0 +1,70 @@
+/* flonum_copy.c - copy a flonum
+ Copyright (C) 1987, 1990, 1991, 1992 Free Software Foundation, Inc.
+
+ This file is part of GAS, the GNU Assembler.
+
+ GAS is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GAS is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GAS; see the file COPYING. If not, write to
+ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#ifndef lint
+static char rcsid[] = "$Id: flo-copy.c,v 1.1 1993/11/03 00:51:34 paul Exp $";
+#endif
+
+#include "as.h"
+
+void
+ flonum_copy(in, out)
+FLONUM_TYPE *in;
+FLONUM_TYPE *out;
+{
+ int in_length; /* 0 origin */
+ int out_length; /* 0 origin */
+
+ out->sign = in->sign;
+ in_length = in->leader - in->low;
+
+ if (in_length < 0) {
+ out->leader = out->low - 1; /* 0.0 case */
+ } else {
+ out_length = out->high - out->low;
+ /*
+ * Assume no GAPS in packing of littlenums.
+ * I.e. sizeof(array) == sizeof(element) * number_of_elements.
+ */
+ if (in_length <= out_length) {
+ {
+ /*
+ * For defensive programming, zero any high-order littlenums we don't need.
+ * This is destroying evidence and wasting time, so why bother???
+ */
+ if (in_length < out_length) {
+memset((char *)(out->low + in_length + 1), '\0', out_length - in_length);
+ }
+ }
+ memcpy((void *)(out->low), (void *)(in->low), (int)((in_length + 1) * sizeof(LITTLENUM_TYPE)));
+ out->exponent = in->exponent;
+ out->leader = in->leader - in->low + out->low;
+ } else {
+ int shorten; /* 1-origin. Number of littlenums we drop. */
+
+ shorten = in_length - out_length;
+ /* Assume out_length >= 0 ! */
+ memcpy((void *)( out->low), (void *)(in->low + shorten), (int)((out_length + 1) * sizeof(LITTLENUM_TYPE)));
+ out->leader = out->high;
+ out->exponent = in->exponent + shorten;
+ }
+ } /* if any significant bits */
+} /* flonum_copy() */
+
+/* end of flonum_copy.c */
diff --git a/gnu/usr.bin/as/flonum-mult.c b/gnu/usr.bin/as/flonum-mult.c
new file mode 100644
index 0000000..4fe8f38
--- /dev/null
+++ b/gnu/usr.bin/as/flonum-mult.c
@@ -0,0 +1,203 @@
+/* flonum_mult.c - multiply two flonums
+ Copyright (C) 1987, 1990, 1991, 1992 Free Software Foundation, Inc.
+
+ This file is part of Gas, the GNU Assembler.
+
+ The GNU assembler is distributed in the hope that it will be
+ useful, but WITHOUT ANY WARRANTY. No author or distributor
+ accepts responsibility to anyone for the consequences of using it
+ or for whether it serves any particular purpose or works at all,
+ unless he says so in writing. Refer to the GNU Assembler General
+ Public License for full details.
+
+ Everyone is granted permission to copy, modify and redistribute
+ the GNU Assembler, but only under the conditions described in the
+ GNU Assembler General Public License. A copy of this license is
+ supposed to have been given to you along with the GNU Assembler
+ so you can know your rights and responsibilities. It should be
+ in a file named COPYING. Among other things, the copyright
+ notice and this notice must be preserved on all copies. */
+
+#ifndef lint
+static char rcsid[] = "$Id: flonum-mult.c,v 1.2 1993/11/03 00:51:36 paul Exp $";
+#endif
+
+#include "flonum.h"
+
+/* plan for a . b => p(roduct)
+
+
+ +-------+-------+-/ /-+-------+-------+
+ | a | a | ... | a | a |
+ | A | A-1 | | 1 | 0 |
+ +-------+-------+-/ /-+-------+-------+
+
+
+ +-------+-------+-/ /-+-------+-------+
+ | b | b | ... | b | b |
+ | B | B-1 | | 1 | 0 |
+ +-------+-------+-/ /-+-------+-------+
+
+
+ +-------+-------+-/ /-+-------+-/ /-+-------+-------+
+ | p | p | ... | p | ... | p | p |
+ | A+B+1| A+B | | N | | 1 | 0 |
+ +-------+-------+-/ /-+-------+-/ /-+-------+-------+
+
+ /^\
+ (carry) a .b ... | ... a .b a .b
+ A B | 0 1 0 0
+ |
+ ... | ... a .b
+ | 1 0
+ |
+ | ...
+ |
+ |
+ |
+ | ___
+ | \
+ +----- P = > a .b
+ N /__ i j
+
+ N = 0 ... A+B
+
+ for all i,j where i+j=N
+ [i,j integers > 0]
+
+ a[], b[], p[] may not intersect.
+ Zero length factors signify 0 significant bits: treat as 0.0.
+ 0.0 factors do the right thing.
+ Zero length product OK.
+
+ I chose the ForTran accent "foo[bar]" instead of the C accent "*garply"
+ because I felt the ForTran way was more intuitive. The C way would
+ probably yield better code on most C compilers. Dean Elsner.
+ (C style also gives deeper insight [to me] ... oh well ...)
+ */
+
+void flonum_multip (a, b, product)
+const FLONUM_TYPE *a;
+const FLONUM_TYPE *b;
+FLONUM_TYPE *product;
+{
+ int size_of_a; /* 0 origin */
+ int size_of_b; /* 0 origin */
+ int size_of_product; /* 0 origin */
+ int size_of_sum; /* 0 origin */
+ int extra_product_positions;/* 1 origin */
+ unsigned long work;
+ unsigned long carry;
+ long exponent;
+ LITTLENUM_TYPE * q;
+ long significant; /* TRUE when we emit a non-0 littlenum */
+ /* ForTran accent follows. */
+ int P; /* Scan product low-order -> high. */
+ int N; /* As in sum above. */
+ int A; /* Which [] of a? */
+ int B; /* Which [] of b? */
+
+ if ((a->sign != '-' && a->sign != '+') || (b->sign != '-' && b->sign != '+')) {
+ /* ...
+ Got to fail somehow. Any suggestions? */
+ product->sign=0;
+ return;
+ }
+ product->sign = (a->sign == b->sign) ? '+' : '-';
+ size_of_a = a->leader - a->low;
+ size_of_b = b->leader - b->low;
+ exponent = a->exponent + b->exponent;
+ size_of_product = product->high - product->low;
+ size_of_sum = size_of_a + size_of_b;
+ extra_product_positions = size_of_product - size_of_sum;
+ if (extra_product_positions < 0)
+ {
+ P = extra_product_positions; /* P < 0 */
+ exponent -= extra_product_positions; /* Increases exponent. */
+ }
+ else
+ {
+ P = 0;
+ }
+ carry = 0;
+ significant = 0;
+ for (N = 0;
+ N <= size_of_sum;
+ N++)
+ {
+ work = carry;
+ carry = 0;
+ for (A = 0;
+ A <= N;
+ A ++)
+ {
+ B = N - A;
+ if (A <= size_of_a && B <= size_of_b && B >= 0)
+ {
+#ifdef TRACE
+ printf("a:low[%d.]=%04x b:low[%d.]=%04x work_before=%08x\n", A, a->low[A], B, b->low[B], work);
+#endif
+ work += a->low[A] * b->low[B];
+ carry += work >> LITTLENUM_NUMBER_OF_BITS;
+ work &= LITTLENUM_MASK;
+#ifdef TRACE
+ printf("work=%08x carry=%04x\n", work, carry);
+#endif
+ }
+ }
+ significant |= work;
+ if (significant || P<0)
+ {
+ if (P >= 0)
+ {
+ product->low[P] = work;
+#ifdef TRACE
+ printf("P=%d. work[p]:=%04x\n", P, work);
+#endif
+ }
+ P ++;
+ }
+ else
+ {
+ extra_product_positions ++;
+ exponent ++;
+ }
+ }
+ /*
+ * [P]->position # size_of_sum + 1.
+ * This is where 'carry' should go.
+ */
+#ifdef TRACE
+ printf("final carry =%04x\n", carry);
+#endif
+ if (carry)
+ {
+ if (extra_product_positions > 0)
+ {
+ product->low[P] = carry;
+ }
+ else
+ {
+ /* No room at high order for carry littlenum. */
+ /* Shift right 1 to make room for most significant littlenum. */
+ exponent ++;
+ P --;
+ for (q = product->low + P;
+ q >= product->low;
+ q --)
+ {
+ work = * q;
+ * q = carry;
+ carry = work;
+ }
+ }
+ }
+ else
+ {
+ P --;
+ }
+ product->leader = product->low + P;
+ product->exponent = exponent;
+}
+
+/* end of flonum_mult.c */
diff --git a/gnu/usr.bin/as/flonum.h b/gnu/usr.bin/as/flonum.h
new file mode 100644
index 0000000..cc05dbf
--- /dev/null
+++ b/gnu/usr.bin/as/flonum.h
@@ -0,0 +1,125 @@
+/* flonum.h - Floating point package
+
+ Copyright (C) 1987, 1990, 1991, 1992 Free Software Foundation, Inc.
+
+ This file is part of GAS, the GNU Assembler.
+
+ GAS is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GAS is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GAS; see the file COPYING. If not, write to
+ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+/*
+ * $Id: flonum.h,v 1.2 1993/11/03 00:51:37 paul Exp $
+ */
+
+
+/***********************************************************************\
+ * *
+ * Arbitrary-precision floating point arithmetic. *
+ * *
+ * *
+ * Notation: a floating point number is expressed as *
+ * MANTISSA * (2 ** EXPONENT). *
+ * *
+ * If this offends more traditional mathematicians, then *
+ * please tell me your nomenclature for flonums! *
+ * *
+ \***********************************************************************/
+#if (__STDC__ != 1) && !defined(const)
+#define const /* empty */
+#endif
+
+#include "bignum.h"
+
+/***********************************************************************\
+ * *
+ * Variable precision floating point numbers. *
+ * *
+ * Exponent is the place value of the low littlenum. E.g.: *
+ * If 0: low points to the units littlenum. *
+ * If 1: low points to the LITTLENUM_RADIX littlenum. *
+ * If -1: low points to the 1/LITTLENUM_RADIX littlenum. *
+ * *
+ \***********************************************************************/
+
+/* JF: A sign value of 0 means we have been asked to assemble NaN
+ A sign value of 'P' means we've been asked to assemble +Inf
+ A sign value of 'N' means we've been asked to assemble -Inf
+ */
+struct FLONUM_STRUCT
+{
+ LITTLENUM_TYPE *low; /* low order littlenum of a bignum */
+ LITTLENUM_TYPE *high; /* high order littlenum of a bignum */
+ LITTLENUM_TYPE *leader; /* -> 1st non-zero littlenum */
+ /* If flonum is 0.0, leader == low-1 */
+ long exponent; /* base LITTLENUM_RADIX */
+ char sign; /* '+' or '-' */
+};
+
+typedef struct FLONUM_STRUCT FLONUM_TYPE;
+
+
+/***********************************************************************\
+ * *
+ * Since we can (& do) meet with exponents like 10^5000, it *
+ * is silly to make a table of ~ 10,000 entries, one for each *
+ * power of 10. We keep a table where item [n] is a struct *
+ * FLONUM_FLOATING_POINT representing 10^(2^n). We then *
+ * multiply appropriate entries from this table to get any *
+ * particular power of 10. For the example of 10^5000, a table *
+ * of just 25 entries suffices: 10^(2^-12)...10^(2^+12). *
+ * *
+ \***********************************************************************/
+
+
+extern const FLONUM_TYPE flonum_positive_powers_of_ten[];
+extern const FLONUM_TYPE flonum_negative_powers_of_ten[];
+extern const int table_size_of_flonum_powers_of_ten;
+/* Flonum_XXX_powers_of_ten[] table has */
+/* legal indices from 0 to */
+/* + this number inclusive. */
+
+
+
+/***********************************************************************\
+ * *
+ * Declare worker functions. *
+ * *
+ \***********************************************************************/
+
+#if __STDC__ == 1
+
+int atof_generic(char **address_of_string_pointer,
+ const char *string_of_decimal_marks,
+ const char *string_of_decimal_exponent_marks,
+ FLONUM_TYPE *address_of_generic_floating_point_number);
+
+void flonum_copy(FLONUM_TYPE *in, FLONUM_TYPE *out);
+void flonum_multip(const FLONUM_TYPE *a, const FLONUM_TYPE *b, FLONUM_TYPE *product);
+
+#else /* not __STDC__ */
+
+int atof_generic();
+void flonum_copy();
+void flonum_multip();
+
+#endif /* not __STDC__ */
+
+/***********************************************************************\
+ * *
+ * Declare error codes. *
+ * *
+ \***********************************************************************/
+
+#define ERROR_EXPONENT_OVERFLOW (2)
+
+/* end of flonum.h */
diff --git a/gnu/usr.bin/as/frags.c b/gnu/usr.bin/as/frags.c
new file mode 100644
index 0000000..71f4669
--- /dev/null
+++ b/gnu/usr.bin/as/frags.c
@@ -0,0 +1,296 @@
+/* frags.c - manage frags -
+
+ Copyright (C) 1987, 1990, 1991, 1992 Free Software Foundation, Inc.
+
+ This file is part of GAS, the GNU Assembler.
+
+ GAS is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GAS is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GAS; see the file COPYING. If not, write to
+ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#ifndef lint
+static char rcsid[] = "$Id: frags.c,v 1.2 1993/11/03 00:51:39 paul Exp $";
+#endif
+
+#include "as.h"
+#include "subsegs.h"
+#include "obstack.h"
+
+struct obstack frags; /* All, and only, frags live here. */
+
+fragS zero_address_frag = {
+ 0, /* fr_address */
+ NULL, /* fr_next */
+ 0, /* fr_fix */
+ 0, /* fr_var */
+ 0, /* fr_symbol */
+ 0, /* fr_offset */
+ NULL, /* fr_opcode */
+ rs_fill, /* fr_type */
+ 0, /* fr_subtype */
+ 0, /* fr_pcrel_adjust */
+ 0, /* fr_bsr */
+ 0 /* fr_literal[0] */
+ };
+
+fragS bss_address_frag = {
+ 0, /* fr_address. Gets filled in to make up
+ sy_value-s. */
+ NULL, /* fr_next */
+ 0, /* fr_fix */
+ 0, /* fr_var */
+ 0, /* fr_symbol */
+ 0, /* fr_offset */
+ NULL, /* fr_opcode */
+ rs_fill, /* fr_type */
+ 0, /* fr_subtype */
+ 0, /* fr_pcrel_adjust */
+ 0, /* fr_bsr */
+ 0 /* fr_literal[0] */
+ };
+
+/*
+ * frag_grow()
+ *
+ * Internal.
+ * Try to augment current frag by nchars chars.
+ * If there is no room, close of the current frag with a ".fill 0"
+ * and begin a new frag. Unless the new frag has nchars chars available
+ * do not return. Do not set up any fields of *now_frag.
+ */
+static void frag_grow(nchars)
+unsigned int nchars;
+{
+ if (obstack_room (&frags) < nchars) {
+ unsigned int n,oldn;
+ long oldc;
+
+ frag_wane(frag_now);
+ frag_new(0);
+ oldn=(unsigned)-1;
+ oldc=frags.chunk_size;
+ frags.chunk_size=2*nchars;
+ while ((n=obstack_room(&frags))<nchars && n<oldn) {
+ frag_wane(frag_now);
+ frag_new(0);
+ oldn=n;
+ }
+ frags.chunk_size=oldc;
+ }
+ if (obstack_room (&frags) < nchars)
+ as_fatal("Can't extend frag %d. chars", nchars);
+} /* frag_grow() */
+
+/*
+ * frag_new()
+ *
+ * Call this to close off a completed frag, and start up a new (empty)
+ * frag, in the same subsegment as the old frag.
+ * [frchain_now remains the same but frag_now is updated.]
+ * Because this calculates the correct value of fr_fix by
+ * looking at the obstack 'frags', it needs to know how many
+ * characters at the end of the old frag belong to (the maximal)
+ * fr_var: the rest must belong to fr_fix.
+ * It doesn't actually set up the old frag's fr_var: you may have
+ * set fr_var == 1, but allocated 10 chars to the end of the frag:
+ * in this case you pass old_frags_var_max_size == 10.
+ *
+ * Make a new frag, initialising some components. Link new frag at end
+ * of frchain_now.
+ */
+void frag_new(old_frags_var_max_size)
+int old_frags_var_max_size; /* Number of chars (already allocated on
+ obstack frags) */
+/* in variable_length part of frag. */
+{
+ register fragS * former_last_fragP;
+ /* char *throw_away_pointer; JF unused */
+ register frchainS * frchP;
+ long tmp; /* JF */
+
+ frag_now->fr_fix = (char *) (obstack_next_free (&frags)) -
+ (frag_now->fr_literal) - old_frags_var_max_size;
+ /* Fix up old frag's fr_fix. */
+
+ obstack_finish (&frags);
+ /* This will align the obstack so the */
+ /* next struct we allocate on it will */
+ /* begin at a correct boundary. */
+ frchP = frchain_now;
+ know (frchP);
+ former_last_fragP = frchP->frch_last;
+ know (former_last_fragP);
+ know (former_last_fragP == frag_now);
+ obstack_blank (&frags, SIZEOF_STRUCT_FRAG);
+ /* We expect this will begin at a correct */
+ /* boundary for a struct. */
+ tmp=obstack_alignment_mask(&frags);
+ obstack_alignment_mask(&frags)=0; /* Turn off alignment */
+ /* If we ever hit a machine
+ where strings must be
+ aligned, we Lose Big */
+ frag_now=(fragS *)obstack_finish(&frags);
+ obstack_alignment_mask(&frags)=tmp; /* Restore alignment */
+
+ /* Just in case we don't get zero'd bytes */
+ memset(frag_now, '\0', SIZEOF_STRUCT_FRAG);
+
+ /* obstack_unaligned_done (&frags, &frag_now); */
+ /* know (frags.obstack_c_next_free == frag_now->fr_literal); */
+ /* Generally, frag_now->points to an */
+ /* address rounded up to next alignment. */
+ /* However, characters will add to obstack */
+ /* frags IMMEDIATELY after the struct frag, */
+ /* even if they are not starting at an */
+ /* alignment address. */
+ former_last_fragP->fr_next = frag_now;
+ frchP->frch_last = frag_now;
+
+#ifndef NO_LISTING
+ {
+ extern struct list_info_struct *listing_tail;
+ frag_now->line = listing_tail;
+ }
+#endif
+
+ frag_now->fr_next = NULL;
+} /* frag_new() */
+
+/*
+ * frag_more()
+ *
+ * Start a new frag unless we have n more chars of room in the current frag.
+ * Close off the old frag with a .fill 0.
+ *
+ * Return the address of the 1st char to write into. Advance
+ * frag_now_growth past the new chars.
+ */
+
+char *frag_more (nchars)
+int nchars;
+{
+ register char *retval;
+
+ frag_grow (nchars);
+ retval = obstack_next_free (&frags);
+ obstack_blank_fast (&frags, nchars);
+ return (retval);
+} /* frag_more() */
+
+/*
+ * frag_var()
+ *
+ * Start a new frag unless we have max_chars more chars of room in the current frag.
+ * Close off the old frag with a .fill 0.
+ *
+ * Set up a machine_dependent relaxable frag, then start a new frag.
+ * Return the address of the 1st char of the var part of the old frag
+ * to write into.
+ */
+
+char *frag_var(type, max_chars, var, subtype, symbol, offset, opcode)
+relax_stateT type;
+int max_chars;
+int var;
+relax_substateT subtype;
+symbolS *symbol;
+long offset;
+char *opcode;
+{
+ register char *retval;
+
+ frag_grow (max_chars);
+ retval = obstack_next_free (&frags);
+ obstack_blank_fast (&frags, max_chars);
+ frag_now->fr_var = var;
+ frag_now->fr_type = type;
+ frag_now->fr_subtype = subtype;
+ frag_now->fr_symbol = symbol;
+ frag_now->fr_offset = offset;
+ frag_now->fr_opcode = opcode;
+ /* default these to zero. */
+ frag_now->fr_pcrel_adjust = 0;
+ frag_now->fr_bsr = 0;
+ frag_new (max_chars);
+ return (retval);
+} /* frag_var() */
+
+/*
+ * frag_variant()
+ *
+ * OVE: This variant of frag_var assumes that space for the tail has been
+ * allocated by caller.
+ * No call to frag_grow is done.
+ * Two new arguments have been added.
+ */
+
+char *frag_variant(type, max_chars, var, subtype, symbol, offset, opcode, pcrel_adjust,bsr)
+relax_stateT type;
+int max_chars;
+int var;
+relax_substateT subtype;
+symbolS *symbol;
+long offset;
+char *opcode;
+int pcrel_adjust;
+char bsr;
+{
+ register char *retval;
+
+ /* frag_grow (max_chars); */
+ retval = obstack_next_free (&frags);
+ /* obstack_blank_fast (&frags, max_chars); */ /* OVE: so far the only diff */
+ frag_now->fr_var = var;
+ frag_now->fr_type = type;
+ frag_now->fr_subtype = subtype;
+ frag_now->fr_symbol = symbol;
+ frag_now->fr_offset = offset;
+ frag_now->fr_opcode = opcode;
+ frag_now->fr_pcrel_adjust = pcrel_adjust;
+ frag_now->fr_bsr = bsr;
+ frag_new(max_chars);
+ return(retval);
+} /* frag_variant() */
+
+/*
+ * frag_wane()
+ *
+ * Reduce the variable end of a frag to a harmless state.
+ */
+void frag_wane(fragP)
+register fragS * fragP;
+{
+ fragP->fr_type = rs_fill;
+ fragP->fr_offset = 0;
+ fragP->fr_var = 0;
+}
+
+/*
+ * frag_align()
+ *
+ * Make a frag for ".align foo,bar". Call is "frag_align (foo,bar);".
+ * Foo & bar are absolute integers.
+ *
+ * Call to close off the current frag with a ".align", then start a new
+ * (so far empty) frag, in the same subsegment as the last frag.
+ */
+
+void frag_align(alignment, fill_character)
+int alignment;
+int fill_character;
+{
+ *(frag_var (rs_align, 1, 1, (relax_substateT)0, (symbolS *)0,
+ (long)alignment, (char *)0)) = fill_character;
+} /* frag_align() */
+
+/* end of frags.c */
diff --git a/gnu/usr.bin/as/frags.h b/gnu/usr.bin/as/frags.h
new file mode 100644
index 0000000..0e82c65
--- /dev/null
+++ b/gnu/usr.bin/as/frags.h
@@ -0,0 +1,89 @@
+/* frags.h - Header file for the frag concept.
+
+ Copyright (C) 1987, 1992 Free Software Foundation, Inc.
+
+ This file is part of GAS, the GNU Assembler.
+
+ GAS is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GAS is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GAS; see the file COPYING. If not, write to
+ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+/*
+ * $Id: frags.h,v 1.2 1993/11/03 00:51:40 paul Exp $
+ */
+
+
+extern struct obstack frags;
+/* Frags ONLY live in this obstack. */
+/* We use obstack_next_free() macro */
+/* so please don't put any other objects */
+/* on this stack! */
+
+/*
+ * A macro to speed up appending exactly 1 char
+ * to current frag.
+ */
+/* JF changed < 1 to <= 1 to avoid a race conditon */
+#define FRAG_APPEND_1_CHAR(datum) \
+{ \
+ if (obstack_room( &frags ) <= 1) {\
+ frag_wane (frag_now); \
+ frag_new (0); \
+ } \
+ obstack_1grow( &frags, datum ); \
+ }
+
+
+#if __STDC__ == 1
+
+char *frag_more(int nchars);
+void frag_align(int alignment, int fill_character);
+void frag_new(int old_frags_var_max_size);
+void frag_wane(fragS *fragP);
+
+char *frag_variant(relax_stateT type,
+ int max_chars,
+ int var,
+ relax_substateT subtype,
+ symbolS *symbol,
+ long offset,
+ char *opcode,
+ int pcrel_adjust,
+ int bsr);
+
+char *frag_var(relax_stateT type,
+ int max_chars,
+ int var,
+ relax_substateT subtype,
+ symbolS *symbol,
+ long offset,
+ char *opcode);
+
+#else /* not __STDC__ */
+
+char *frag_more();
+char *frag_var();
+char *frag_variant();
+void frag_align();
+void frag_new();
+void frag_wane();
+
+#endif /* not __STDC__ */
+
+/*
+ * Local Variables:
+ * comment-column: 0
+ * fill-column: 131
+ * End:
+ */
+
+/* end of frags.h */
diff --git a/gnu/usr.bin/as/gas-format.el b/gnu/usr.bin/as/gas-format.el
new file mode 100644
index 0000000..32c6426
--- /dev/null
+++ b/gnu/usr.bin/as/gas-format.el
@@ -0,0 +1,79 @@
+;; -*- lisp-interaction -*-
+;; -*- emacs-lisp -*-
+;;
+;;
+;; originally from...
+;; Rich's personal .emacs file. feel free to copy.
+;;
+;; this file sets emacs up for the type of C source code formatting used within
+;; gas. I don't use gnu indent. If you do, and find a setup that approximates
+;; these settings, please send it to me.
+;;
+;; Last Mod Thu Feb 13 00:59:16 PST 1992, by rich@sendai
+;;
+
+;;
+;;
+;; This section sets constants used by c-mode for formating
+;;
+;;
+
+
+;; If `c-auto-newline' is non-`nil', newlines are inserted both
+;;before and after braces that you insert, and after colons and semicolons.
+;;Correct C indentation is done on all the lines that are made this way.
+
+(setq c-auto-newline nil)
+
+
+;; If `c-tab-always-indent' is non-`nil', the TAB command
+;;in C mode does indentation only if point is at the left margin or within
+;;the line's indentation. If there is non-whitespace to the left of point,
+;;then TAB just inserts a tab character in the buffer. Normally,
+;;this variable is `nil', and TAB always reindents the current line.
+
+(setq c-tab-always-indent nil)
+
+;; C does not have anything analogous to particular function names for which
+;;special forms of indentation are desirable. However, it has a different
+;;need for customization facilities: many different styles of C indentation
+;;are in common use.
+;;
+;; There are six variables you can set to control the style that Emacs C
+;;mode will use.
+;;
+;;`c-indent-level'
+;; Indentation of C statements within surrounding block. The surrounding
+;; block's indentation is the indentation of the line on which the
+;; open-brace appears.
+
+(setq c-indent-level 8)
+
+;;`c-continued-statement-offset'
+;; Extra indentation given to a substatement, such as the then-clause of
+;; an if or body of a while.
+
+(setq c-continued-statement-offset 4)
+
+;;`c-brace-offset'
+;; Extra indentation for line if it starts with an open brace.
+
+(setq c-brace-offset 0)
+
+;;`c-brace-imaginary-offset'
+;; An open brace following other text is treated as if it were this far
+;; to the right of the start of its line.
+
+(setq c-brace-imaginary-offset 0)
+
+;;`c-argdecl-indent'
+;; Indentation level of declarations of C function arguments.
+
+(setq c-argdecl-indent 0)
+
+;;`c-label-offset'
+;; Extra indentation for line that is a label, or case or default.
+
+(setq c-label-offset -8)
+
+;; end of gas-format.el
diff --git a/gnu/usr.bin/as/hash.c b/gnu/usr.bin/as/hash.c
new file mode 100644
index 0000000..70068ea
--- /dev/null
+++ b/gnu/usr.bin/as/hash.c
@@ -0,0 +1,992 @@
+/* hash.c - hash table lookup strings -
+ Copyright (C) 1987, 1990, 1991, 1992 Free Software Foundation, Inc.
+
+ This file is part of GAS, the GNU Assembler.
+
+ GAS is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GAS is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GAS; see the file COPYING. If not, write to
+ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/*
+ * BUGS, GRIPES, APOLOGIA etc.
+ *
+ * A typical user doesn't need ALL this: I intend to make a library out
+ * of it one day - Dean Elsner.
+ * Also, I want to change the definition of a symbol to (address,length)
+ * so I can put arbitrary binary in the names stored. [see hsh.c for that]
+ *
+ * This slime is common coupled inside the module. Com-coupling (and other
+ * vandalism) was done to speed running time. The interfaces at the
+ * module's edges are adequately clean.
+ *
+ * There is no way to (a) run a test script through this heap and (b)
+ * compare results with previous scripts, to see if we have broken any
+ * code. Use GNU (f)utilities to do this. A few commands assist test.
+ * The testing is awkward: it tries to be both batch & interactive.
+ * For now, interactive rules!
+ */
+
+/*
+ * The idea is to implement a symbol table. A test jig is here.
+ * Symbols are arbitrary strings; they can't contain '\0'.
+ * [See hsh.c for a more general symbol flavour.]
+ * Each symbol is associated with a char*, which can point to anything
+ * you want, allowing an arbitrary property list for each symbol.
+ *
+ * The basic operations are:
+ *
+ * new creates symbol table, returns handle
+ * find (symbol) returns char*
+ * insert (symbol,char*) error if symbol already in table
+ * delete (symbol) returns char* if symbol was in table
+ * apply so you can delete all symbols before die()
+ * die destroy symbol table (free up memory)
+ *
+ * Supplementary functions include:
+ *
+ * say how big? what % full?
+ * replace (symbol,newval) report previous value
+ * jam (symbol,value) assert symbol:=value
+ *
+ * You, the caller, have control over errors: this just reports them.
+ *
+ * This package requires malloc(), free().
+ * Malloc(size) returns NULL or address of char[size].
+ * Free(address) frees same.
+ */
+
+/*
+ * The code and its structures are re-enterent.
+ * Before you do anything else, you must call hash_new() which will
+ * return the address of a hash-table-control-block (or NULL if there
+ * is not enough memory). You then use this address as a handle of the
+ * symbol table by passing it to all the other hash_...() functions.
+ * The only approved way to recover the memory used by the symbol table
+ * is to call hash_die() with the handle of the symbol table.
+ *
+ * Before you call hash_die() you normally delete anything pointed to
+ * by individual symbols. After hash_die() you can't use that symbol
+ * table again.
+ *
+ * The char* you associate with a symbol may not be NULL (0) because
+ * NULL is returned whenever a symbol is not in the table. Any other
+ * value is OK, except DELETED, #defined below.
+ *
+ * When you supply a symbol string for insertion, YOU MUST PRESERVE THE
+ * STRING until that symbol is deleted from the table. The reason is that
+ * only the address you supply, NOT the symbol string itself, is stored
+ * in the symbol table.
+ *
+ * You may delete and add symbols arbitrarily.
+ * Any or all symbols may have the same 'value' (char *). In fact, these
+ * routines don't do anything with your symbol values.
+ *
+ * You have no right to know where the symbol:char* mapping is stored,
+ * because it moves around in memory; also because we may change how it
+ * works and we don't want to break your code do we? However the handle
+ * (address of struct hash_control) is never changed in
+ * the life of the symbol table.
+ *
+ * What you CAN find out about a symbol table is:
+ * how many slots are in the hash table?
+ * how many slots are filled with symbols?
+ * (total hashes,collisions) for (reads,writes) (*)
+ * All of the above values vary in time.
+ * (*) some of these numbers will not be meaningful if we change the
+ * internals.
+ */
+
+/*
+ * I N T E R N A L
+ *
+ * Hash table is an array of hash_entries; each entry is a pointer to a
+ * a string and a user-supplied value 1 char* wide.
+ *
+ * The array always has 2 ** n elements, n>0, n integer.
+ * There is also a 'wall' entry after the array, which is always empty
+ * and acts as a sentinel to stop running off the end of the array.
+ * When the array gets too full, we create a new array twice as large
+ * and re-hash the symbols into the new array, then forget the old array.
+ * (Of course, we copy the values into the new array before we junk the
+ * old array!)
+ *
+ */
+
+#ifndef lint
+static char rcsid[] = "$Id: hash.c,v 1.3 1995/05/30 04:46:18 rgrimes Exp $";
+#endif
+
+#include <stdio.h>
+
+#ifndef FALSE
+#define FALSE (0)
+#define TRUE (!FALSE)
+#endif /* no FALSE yet */
+
+#include <ctype.h>
+#define min(a, b) ((a) < (b) ? (a) : (b))
+
+#include "as.h"
+
+#define error as_fatal
+
+#define DELETED ((char *)1) /* guarenteed invalid address */
+#define START_POWER (11) /* power of two: size of new hash table *//* JF was 6 */
+/* JF These next two aren't used any more. */
+/* #define START_SIZE (64) / * 2 ** START_POWER */
+/* #define START_FULL (32) / * number of entries before table expands */
+#define islive(ptr) (ptr->hash_string && ptr->hash_string != DELETED)
+/* above TRUE if a symbol is in entry @ ptr */
+
+#define STAT_SIZE (0) /* number of slots in hash table */
+/* the wall does not count here */
+/* we expect this is always a power of 2 */
+#define STAT_ACCESS (1) /* number of hash_ask()s */
+#define STAT__READ (0) /* reading */
+#define STAT__WRITE (1) /* writing */
+#define STAT_COLLIDE (3) /* number of collisions (total) */
+/* this may exceed STAT_ACCESS if we have */
+/* lots of collisions/access */
+#define STAT_USED (5) /* slots used right now */
+#define STATLENGTH (6) /* size of statistics block */
+#if STATLENGTH != HASH_STATLENGTH
+Panic! Please make #include "stat.h" agree with previous definitions!
+#endif
+
+ /* #define SUSPECT to do runtime checks */
+ /* #define TEST to be a test jig for hash...() */
+
+#ifdef TEST /* TEST: use smaller hash table */
+#undef START_POWER
+#define START_POWER (3)
+#undef START_SIZE
+#define START_SIZE (8)
+#undef START_FULL
+#define START_FULL (4)
+#endif
+
+/*------------------ plan ---------------------------------- i = internal
+
+ struct hash_control * c;
+ struct hash_entry * e; i
+ int b[z]; buffer for statistics
+ z size of b
+ char * s; symbol string (address) [ key ]
+ char * v; value string (address) [datum]
+ boolean f; TRUE if we found s in hash table i
+ char * t; error string; "" means OK
+ int a; access type [0...n) i
+
+ c=hash_new () create new hash_control
+
+ hash_die (c) destroy hash_control (and hash table)
+ table should be empty.
+ doesn't check if table is empty.
+ c has no meaning after this.
+
+ hash_say (c,b,z) report statistics of hash_control.
+ also report number of available statistics.
+
+ v=hash_delete (c,s) delete symbol, return old value if any.
+ ask() NULL means no old value.
+ f
+
+ v=hash_replace (c,s,v) replace old value of s with v.
+ ask() NULL means no old value: no table change.
+ f
+
+ t=hash_insert (c,s,v) insert (s,v) in c.
+ ask() return error string.
+ f it is an error to insert if s is already
+ in table.
+ if any error, c is unchanged.
+
+ t=hash_jam (c,s,v) assert that new value of s will be v. i
+ ask() it may decide to GROW the table. i
+ f i
+ grow() i
+ t=hash_grow (c) grow the hash table. i
+ jam() will invoke JAM. i
+
+ ?=hash_apply (c,y) apply y() to every symbol in c.
+ y evtries visited in 'unspecified' order.
+
+ v=hash_find (c,s) return value of s, or NULL if s not in c.
+ ask()
+ f
+
+ f,e=hash_ask() (c,s,a) return slot where s SHOULD live. i
+ code() maintain collision stats in c. i
+
+ .=hash_code (c,s) compute hash-code for s, i
+ from parameters of c. i
+
+ */
+
+static char hash_found; /* returned by hash_ask() to stop extra */
+/* testing. hash_ask() wants to return both */
+/* a slot and a status. This is the status. */
+/* TRUE: found symbol */
+/* FALSE: absent: empty or deleted slot */
+/* Also returned by hash_jam(). */
+/* TRUE: we replaced a value */
+/* FALSE: we inserted a value */
+
+static struct hash_entry * hash_ask();
+static int hash_code ();
+static char * hash_grow();
+
+/*
+ * h a s h _ n e w ( )
+ *
+ */
+struct hash_control *
+ hash_new() /* create a new hash table */
+/* return NULL if failed */
+/* return handle (address of struct hash) */
+{
+ register struct hash_control * retval;
+ register struct hash_entry * room; /* points to hash table */
+ register struct hash_entry * wall;
+ register struct hash_entry * entry;
+ register int * ip; /* scan stats block of struct hash_control */
+ register int * nd; /* limit of stats block */
+
+ if (( room = (struct hash_entry *) malloc( sizeof(struct
+ hash_entry)*((1<<START_POWER) + 1) ) ) != NULL)
+ /* +1 for the wall entry */
+ {
+ if (( retval = (struct hash_control *) malloc(sizeof(struct
+ hash_control)) ) != NULL)
+ {
+ nd = retval->hash_stat + STATLENGTH;
+ for (ip=retval->hash_stat; ip<nd; ip++)
+ {
+ *ip = 0;
+ }
+
+ retval->hash_stat[STAT_SIZE] = 1<<START_POWER;
+ retval->hash_mask = (1<<START_POWER) - 1;
+ retval->hash_sizelog = START_POWER;
+ /* works for 1's compl ok */
+ retval->hash_where = room;
+ retval->hash_wall =
+ wall = room + (1<<START_POWER);
+ retval->hash_full = (1<<START_POWER)/2;
+ for (entry=room; entry <= wall; entry++)
+ {
+ entry->hash_string = NULL;
+ }
+ }
+ }
+ else
+ {
+ retval = NULL; /* no room for table: fake a failure */
+ }
+ return(retval); /* return NULL or set-up structs */
+}
+
+/*
+ * h a s h _ d i e ( )
+ *
+ * Table should be empty, but this is not checked.
+ * To empty the table, try hash_apply()ing a symbol deleter.
+ * Return to free memory both the hash table and it's control
+ * block.
+ * 'handle' has no meaning after this function.
+ * No errors are recoverable.
+ */
+void
+ hash_die(handle)
+struct hash_control * handle;
+{
+ free((char *)handle->hash_where);
+ free((char *)handle);
+}
+
+/*
+ * h a s h _ s a y ( )
+ *
+ * Return the size of the statistics table, and as many statistics as
+ * we can until either (a) we have run out of statistics or (b) caller
+ * has run out of buffer.
+ * NOTE: hash_say treats all statistics alike.
+ * These numbers may change with time, due to insertions, deletions
+ * and expansions of the table.
+ * The first "statistic" returned is the length of hash_stat[].
+ * Then contents of hash_stat[] are read out (in ascending order)
+ * until your buffer or hash_stat[] is exausted.
+ */
+void
+ hash_say(handle,buffer,bufsiz)
+register struct hash_control * handle;
+register int buffer[/*bufsiz*/];
+register int bufsiz;
+{
+ register int * nd; /* limit of statistics block */
+ register int * ip; /* scan statistics */
+
+ ip = handle->hash_stat;
+ nd = ip + min(bufsiz-1,STATLENGTH);
+ if (bufsiz>0) /* trust nothing! bufsiz <= 0 is dangerous */
+ {
+ *buffer++ = STATLENGTH;
+ for (; ip<nd; ip++,buffer++)
+ {
+ *buffer = *ip;
+ }
+ }
+}
+
+/*
+ * h a s h _ d e l e t e ( )
+ *
+ * Try to delete a symbol from the table.
+ * If it was there, return its value (and adjust STAT_USED).
+ * Otherwise, return NULL.
+ * Anyway, the symbol is not present after this function.
+ *
+ */
+char * /* NULL if string not in table, else */
+ /* returns value of deleted symbol */
+ hash_delete(handle,string)
+register struct hash_control * handle;
+register char * string;
+{
+ register char * retval; /* NULL if string not in table */
+ register struct hash_entry * entry; /* NULL or entry of this symbol */
+
+ entry = hash_ask(handle,string,STAT__WRITE);
+ if (hash_found)
+ {
+ retval = entry->hash_value;
+ entry->hash_string = DELETED; /* mark as deleted */
+ handle->hash_stat[STAT_USED] -= 1; /* slots-in-use count */
+#ifdef SUSPECT
+ if (handle->hash_stat[STAT_USED]<0)
+ {
+ error("hash_delete");
+ }
+#endif /* def SUSPECT */
+ }
+ else
+ {
+ retval = NULL;
+ }
+ return(retval);
+}
+
+/*
+ * h a s h _ r e p l a c e ( )
+ *
+ * Try to replace the old value of a symbol with a new value.
+ * Normally return the old value.
+ * Return NULL and don't change the table if the symbol is not already
+ * in the table.
+ */
+char *
+ hash_replace(handle,string,value)
+register struct hash_control * handle;
+register char * string;
+register char * value;
+{
+ register struct hash_entry * entry;
+ register char * retval;
+
+ entry = hash_ask(handle,string,STAT__WRITE);
+ if (hash_found)
+ {
+ retval = entry->hash_value;
+ entry->hash_value = value;
+ }
+ else
+ {
+ retval = NULL;
+ }
+ ;
+ return (retval);
+}
+
+/*
+ * h a s h _ i n s e r t ( )
+ *
+ * Insert a (symbol-string, value) into the hash table.
+ * Return an error string, "" means OK.
+ * It is an 'error' to insert an existing symbol.
+ */
+
+char * /* return error string */
+ hash_insert(handle,string,value)
+register struct hash_control * handle;
+register char * string;
+register char * value;
+{
+ register struct hash_entry * entry;
+ register char * retval;
+
+ retval = "";
+ if (handle->hash_stat[STAT_USED] > handle->hash_full)
+ {
+ retval = hash_grow(handle);
+ }
+ if ( ! * retval)
+ {
+ entry = hash_ask(handle,string,STAT__WRITE);
+ if (hash_found)
+ {
+ retval = "exists";
+ }
+ else
+ {
+ entry->hash_value = value;
+ entry->hash_string = string;
+ handle->hash_stat[STAT_USED] += 1;
+ }
+ }
+ return(retval);
+}
+
+/*
+ * h a s h _ j a m ( )
+ *
+ * Regardless of what was in the symbol table before, after hash_jam()
+ * the named symbol has the given value. The symbol is either inserted or
+ * (its value is) relpaced.
+ * An error message string is returned, "" means OK.
+ *
+ * WARNING: this may decide to grow the hashed symbol table.
+ * To do this, we call hash_grow(), WHICH WILL recursively CALL US.
+ *
+ * We report status internally: hash_found is TRUE if we replaced, but
+ * false if we inserted.
+ */
+char *
+ hash_jam(handle,string,value)
+register struct hash_control * handle;
+register char * string;
+register char * value;
+{
+ register char * retval;
+ register struct hash_entry * entry;
+
+ retval = "";
+ if (handle->hash_stat[STAT_USED] > handle->hash_full)
+ {
+ retval = hash_grow(handle);
+ }
+ if (! * retval)
+ {
+ entry = hash_ask(handle,string,STAT__WRITE);
+ if ( ! hash_found)
+ {
+ entry->hash_string = string;
+ handle->hash_stat[STAT_USED] += 1;
+ }
+ entry->hash_value = value;
+ }
+ return(retval);
+}
+
+/*
+ * h a s h _ g r o w ( )
+ *
+ * Grow a new (bigger) hash table from the old one.
+ * We choose to double the hash table's size.
+ * Return a human-scrutible error string: "" if OK.
+ * Warning! This uses hash_jam(), which had better not recurse
+ * back here! Hash_jam() conditionally calls us, but we ALWAYS
+ * call hash_jam()!
+ * Internal.
+ */
+static char *
+ hash_grow(handle) /* make a hash table grow */
+struct hash_control * handle;
+{
+ register struct hash_entry * newwall;
+ register struct hash_entry * newwhere;
+ struct hash_entry * newtrack;
+ register struct hash_entry * oldtrack;
+ register struct hash_entry * oldwhere;
+ register struct hash_entry * oldwall;
+ register int temp;
+ int newsize;
+ char * string;
+ char * retval;
+#ifdef SUSPECT
+ int oldused;
+#endif
+
+ /*
+ * capture info about old hash table
+ */
+ oldwhere = handle->hash_where;
+ oldwall = handle->hash_wall;
+#ifdef SUSPECT
+ oldused = handle->hash_stat[STAT_USED];
+#endif
+ /*
+ * attempt to get enough room for a hash table twice as big
+ */
+ temp = handle->hash_stat[STAT_SIZE];
+ if (( newwhere = (struct hash_entry *)
+ xmalloc((long)((temp+temp+1)*sizeof(struct hash_entry)))) != NULL)
+ /* +1 for wall slot */
+ {
+ retval = ""; /* assume success until proven otherwise */
+ /*
+ * have enough room: now we do all the work.
+ * double the size of everything in handle,
+ * note: hash_mask frob works for 1's & for 2's complement machines
+ */
+ handle->hash_mask = handle->hash_mask + handle->hash_mask + 1;
+ handle->hash_stat[STAT_SIZE] <<= 1;
+ newsize = handle->hash_stat[STAT_SIZE];
+ handle->hash_where = newwhere;
+ handle->hash_full <<= 1;
+ handle->hash_sizelog += 1;
+ handle->hash_stat[STAT_USED] = 0;
+ handle->hash_wall =
+ newwall = newwhere + newsize;
+ /*
+ * set all those pesky new slots to vacant.
+ */
+ for (newtrack=newwhere; newtrack <= newwall; newtrack++)
+ {
+ newtrack->hash_string = NULL;
+ }
+ /*
+ * we will do a scan of the old table, the hard way, using the
+ * new control block to re-insert the data into new hash table.
+ */
+ handle->hash_stat[STAT_USED] = 0; /* inserts will bump it up to correct */
+ for (oldtrack=oldwhere; oldtrack < oldwall; oldtrack++)
+ {
+ if (((string = oldtrack->hash_string) != NULL) && string != DELETED)
+ {
+ if ( * (retval = hash_jam(handle,string,oldtrack->hash_value) ) )
+ {
+ break;
+ }
+ }
+ }
+#ifdef SUSPECT
+ if ( !*retval && handle->hash_stat[STAT_USED] != oldused)
+ {
+ retval = "hash_used";
+ }
+#endif
+ if (!*retval)
+ {
+ /*
+ * we have a completely faked up control block.
+ * return the old hash table.
+ */
+ free((char *)oldwhere);
+ /*
+ * Here with success. retval is already "".
+ */
+ }
+ }
+ else
+ {
+ retval = "no room";
+ }
+ return(retval);
+}
+
+/*
+ * h a s h _ a p p l y ( )
+ *
+ * Use this to scan each entry in symbol table.
+ * For each symbol, this calls (applys) a nominated function supplying the
+ * symbol's value (and the symbol's name).
+ * The idea is you use this to destroy whatever is associted with
+ * any values in the table BEFORE you destroy the table with hash_die.
+ * Of course, you can use it for other jobs; whenever you need to
+ * visit all extant symbols in the table.
+ *
+ * We choose to have a call-you-back idea for two reasons:
+ * asthetic: it is a neater idea to use apply than an explicit loop
+ * sensible: if we ever had to grow the symbol table (due to insertions)
+ * then we would lose our place in the table when we re-hashed
+ * symbols into the new table in a different order.
+ *
+ * The order symbols are visited depends entirely on the hashing function.
+ * Whenever you insert a (symbol, value) you risk expanding the table. If
+ * you do expand the table, then the hashing function WILL change, so you
+ * MIGHT get a different order of symbols visited. In other words, if you
+ * want the same order of visiting symbols as the last time you used
+ * hash_apply() then you better not have done any hash_insert()s or
+ * hash_jam()s since the last time you used hash_apply().
+ *
+ * In future we may use the value returned by your nominated function.
+ * One idea is to abort the scan if, after applying the function to a
+ * certain node, the function returns a certain code.
+ * To be safe, please make your functions of type char *. If you always
+ * return NULL, then the scan will complete, visiting every symbol in
+ * the table exactly once. ALL OTHER RETURNED VALUES have no meaning yet!
+ * Caveat Actor!
+ *
+ * The function you supply should be of the form:
+ * char * myfunct(string,value)
+ * char * string; |* the symbol's name *|
+ * char * value; |* the symbol's value *|
+ * {
+ * |* ... *|
+ * return(NULL);
+ * }
+ *
+ * The returned value of hash_apply() is (char*)NULL. In future it may return
+ * other values. NULL means "completed scan OK". Other values have no meaning
+ * yet. (The function has no graceful failures.)
+ */
+char *
+ hash_apply(handle,function)
+struct hash_control * handle;
+char* (*function)();
+{
+ register struct hash_entry * entry;
+ register struct hash_entry * wall;
+
+ wall = handle->hash_wall;
+ for (entry = handle->hash_where; entry < wall; entry++)
+ {
+ if (islive(entry)) /* silly code: tests entry->string twice! */
+ {
+ (*function)(entry->hash_string,entry->hash_value);
+ }
+ }
+ return (NULL);
+}
+
+/*
+ * h a s h _ f i n d ( )
+ *
+ * Given symbol string, find value (if any).
+ * Return found value or NULL.
+ */
+char *
+ hash_find(handle,string) /* return char* or NULL */
+struct hash_control * handle;
+char * string;
+{
+ register struct hash_entry * entry;
+ register char * retval;
+
+ entry = hash_ask(handle,string,STAT__READ);
+ if (hash_found)
+ {
+ retval = entry->hash_value;
+ }
+ else
+ {
+ retval = NULL;
+ }
+ return(retval);
+}
+
+/*
+ * h a s h _ a s k ( )
+ *
+ * Searches for given symbol string.
+ * Return the slot where it OUGHT to live. It may be there.
+ * Return hash_found: TRUE only if symbol is in that slot.
+ * Access argument is to help keep statistics in control block.
+ * Internal.
+ */
+static struct hash_entry * /* string slot, may be empty or deleted */
+ hash_ask(handle,string,access)
+struct hash_control * handle;
+char * string;
+int access; /* access type */
+{
+ register char *string1; /* JF avoid strcmp calls */
+ register char * s;
+ register int c;
+ register struct hash_entry * slot;
+ register int collision; /* count collisions */
+
+ slot = handle->hash_where + hash_code(handle,string); /* start looking here */
+ handle->hash_stat[STAT_ACCESS+access] += 1;
+ collision = 0;
+ hash_found = FALSE;
+ while (((s = slot->hash_string) != NULL) && s != DELETED)
+ {
+ for (string1=string;;) {
+ if ((c= *s++) == 0) {
+ if (!*string1)
+ hash_found = TRUE;
+ break;
+ }
+ if (*string1++ != c)
+ break;
+ }
+ if (hash_found)
+ break;
+ collision++;
+ slot++;
+ }
+ /*
+ * slot: return:
+ * in use: we found string slot
+ * at empty:
+ * at wall: we fell off: wrap round ????
+ * in table: dig here slot
+ * at DELETED: dig here slot
+ */
+ if (slot == handle->hash_wall)
+ {
+ slot = handle->hash_where; /* now look again */
+ while (((s = slot->hash_string) != NULL) && s != DELETED)
+ {
+ for (string1=string;*s;string1++,s++) {
+ if (*string1 != *s)
+ break;
+ }
+ if (*s == *string1) {
+ hash_found = TRUE;
+ break;
+ }
+ collision++;
+ slot++;
+ }
+ /*
+ * slot: return:
+ * in use: we found it slot
+ * empty: wall: ERROR IMPOSSIBLE !!!!
+ * in table: dig here slot
+ * DELETED:dig here slot
+ */
+ }
+ /* fprintf(stderr,"hash_ask(%s)->%d(%d)\n",string,hash_code(handle,string),collision); */
+ handle->hash_stat[STAT_COLLIDE+access] += collision;
+ return(slot); /* also return hash_found */
+}
+
+/*
+ * h a s h _ c o d e
+ *
+ * Does hashing of symbol string to hash number.
+ * Internal.
+ */
+static int
+ hash_code(handle,string)
+struct hash_control * handle;
+register char * string;
+{
+ register long h; /* hash code built here */
+ register long c; /* each character lands here */
+ register int n; /* Amount to shift h by */
+
+ n = (handle->hash_sizelog - 3);
+ h = 0;
+ while ((c = *string++) != 0)
+ {
+ h += c;
+ h = (h<<3) + (h>>n) + c;
+ }
+ return (h & handle->hash_mask);
+}
+
+/*
+ * Here is a test program to exercise above.
+ */
+#ifdef TEST
+
+#define TABLES (6) /* number of hash tables to maintain */
+/* (at once) in any testing */
+#define STATBUFSIZE (12) /* we can have 12 statistics */
+
+int statbuf[STATBUFSIZE]; /* display statistics here */
+char answer[100]; /* human farts here */
+char * hashtable[TABLES]; /* we test many hash tables at once */
+char * h; /* points to curent hash_control */
+char ** pp;
+char * p;
+char * name;
+char * value;
+int size;
+int used;
+char command;
+int number; /* number 0:TABLES-1 of current hashed */
+/* symbol table */
+
+main()
+{
+ char (*applicatee());
+ char * hash_find();
+ char * destroy();
+ char * what();
+ struct hash_control * hash_new();
+ char * hash_replace();
+ int * ip;
+
+ number = 0;
+ h = 0;
+ printf("type h <RETURN> for help\n");
+ for (;;)
+ {
+ printf("hash_test command: ");
+ fgets(answer, 100, stdin);
+ command = answer[0];
+ if (isupper(command)) command = tolower(command); /* ecch! */
+ switch (command)
+ {
+ case '#':
+ printf("old hash table #=%d.\n",number);
+ whattable();
+ break;
+ case '?':
+ for (pp=hashtable; pp<hashtable+TABLES; pp++)
+ {
+ printf("address of hash table #%d control block is %xx\n"
+ ,pp-hashtable,*pp);
+ }
+ break;
+ case 'a':
+ hash_apply(h,applicatee);
+ break;
+ case 'd':
+ hash_apply(h,destroy);
+ hash_die(h);
+ break;
+ case 'f':
+ p = hash_find(h,name=what("symbol"));
+ printf("value of \"%s\" is \"%s\"\n",name,p?p:"NOT-PRESENT");
+ break;
+ case 'h':
+ printf("# show old, select new default hash table number\n");
+ printf("? display all hashtable control block addresses\n");
+ printf("a apply a simple display-er to each symbol in table\n");
+ printf("d die: destroy hashtable\n");
+ printf("f find value of nominated symbol\n");
+ printf("h this help\n");
+ printf("i insert value into symbol\n");
+ printf("j jam value into symbol\n");
+ printf("n new hashtable\n");
+ printf("r replace a value with another\n");
+ printf("s say what %% of table is used\n");
+ printf("q exit this program\n");
+ printf("x delete a symbol from table, report its value\n");
+ break;
+ case 'i':
+ p = hash_insert(h,name=what("symbol"),value=what("value"));
+ if (*p)
+ {
+ printf("symbol=\"%s\" value=\"%s\" error=%s\n",name,value,p);
+ }
+ break;
+ case 'j':
+ p = hash_jam(h,name=what("symbol"),value=what("value"));
+ if (*p)
+ {
+ printf("symbol=\"%s\" value=\"%s\" error=%s\n",name,value,p);
+ }
+ break;
+ case 'n':
+ h = hashtable[number] = (char *) hash_new();
+ break;
+ case 'q':
+ exit();
+ case 'r':
+ p = hash_replace(h,name=what("symbol"),value=what("value"));
+ printf("old value was \"%s\"\n",p?p:"{}");
+ break;
+ case 's':
+ hash_say(h,statbuf,STATBUFSIZE);
+ for (ip=statbuf; ip<statbuf+STATBUFSIZE; ip++)
+ {
+ printf("%d ",*ip);
+ }
+ printf("\n");
+ break;
+ case 'x':
+ p = hash_delete(h,name=what("symbol"));
+ printf("old value was \"%s\"\n",p?p:"{}");
+ break;
+ default:
+ printf("I can't understand command \"%c\"\n",command);
+ break;
+ }
+ }
+}
+
+char *
+ what(description)
+char * description;
+{
+ char * retval;
+ char * malloc();
+
+ printf(" %s : ",description);
+ fgets(answer, 100, stdin);
+ /* will one day clean up answer here */
+ retval = malloc(strlen(answer)+1);
+ if (!retval)
+ {
+ error("room");
+ }
+ (void)strcpy(retval,answer);
+ return(retval);
+}
+
+char *
+ destroy(string,value)
+char * string;
+char * value;
+{
+ free(string);
+ free(value);
+ return(NULL);
+}
+
+
+char *
+ applicatee(string,value)
+char * string;
+char * value;
+{
+ printf("%.20s-%.20s\n",string,value);
+ return(NULL);
+}
+
+whattable() /* determine number: what hash table to use */
+/* also determine h: points to hash_control */
+{
+
+ for (;;)
+ {
+ printf(" what hash table (%d:%d) ? ",0,TABLES-1);
+ fgets(answer, 100, stdin);
+ sscanf(answer,"%d",&number);
+ if (number >= 0 && number<TABLES)
+ {
+ h = hashtable[number];
+ if (!h)
+ {
+ printf("warning: current hash-table-#%d. has no hash-control\n",number);
+ }
+ return;
+ }
+ else
+ {
+ printf("invalid hash table number: %d\n",number);
+ }
+ }
+}
+
+
+
+#endif /* #ifdef TEST */
+
+/* end of hash.c */
diff --git a/gnu/usr.bin/as/hash.h b/gnu/usr.bin/as/hash.h
new file mode 100644
index 0000000..034c2aa
--- /dev/null
+++ b/gnu/usr.bin/as/hash.h
@@ -0,0 +1,65 @@
+/* hash.h - for hash.c
+ Copyright (C) 1987, 1992 Free Software Foundation, Inc.
+
+ This file is part of GAS, the GNU Assembler.
+
+ GAS is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GAS is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GAS; see the file COPYING. If not, write to
+ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+/*
+ * $Id: hash.h,v 1.2 1993/11/03 00:51:46 paul Exp $
+ */
+
+
+#ifndef hashH
+#define hashH
+
+struct hash_entry
+{
+ char *hash_string; /* points to where the symbol string is */
+ /* NULL means slot is not used */
+ /* DELETED means slot was deleted */
+ char *hash_value; /* user's datum, associated with symbol */
+};
+
+
+#define HASH_STATLENGTH (6)
+struct hash_control
+{
+ struct hash_entry *hash_where; /* address of hash table */
+ int hash_sizelog; /* Log of ( hash_mask + 1 ) */
+ int hash_mask; /* masks a hash into index into table */
+ int hash_full; /* when hash_stat[STAT_USED] exceeds this, */
+ /* grow table */
+ struct hash_entry * hash_wall; /* point just after last (usable) entry */
+ /* here we have some statistics */
+ int hash_stat[HASH_STATLENGTH]; /* lies & statistics */
+ /* we need STAT_USED & STAT_SIZE */
+};
+
+ /* fixme: prototype. */
+
+/* returns */
+struct hash_control *hash_new(); /* [control block] */
+void hash_die();
+void hash_say();
+char *hash_delete(); /* previous value */
+char *hash_relpace(); /* previous value */
+char *hash_insert(); /* error string */
+char *hash_apply(); /* 0 means OK */
+char *hash_find(); /* value */
+char *hash_jam(); /* error text (internal) */
+
+#endif /* #ifdef hashH */
+
+/* end of hash.h */
diff --git a/gnu/usr.bin/as/hex-value.c b/gnu/usr.bin/as/hex-value.c
new file mode 100644
index 0000000..432aa02
--- /dev/null
+++ b/gnu/usr.bin/as/hex-value.c
@@ -0,0 +1,61 @@
+/* hex_value.c - char=>radix-value -
+ Copyright (C) 1987, 1990, 1991, 1992 Free Software Foundation, Inc.
+
+ This file is part of GAS, the GNU Assembler.
+
+ GAS is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GAS is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GAS; see the file COPYING. If not, write to
+ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/*
+ * Export: Hex_value[]. Converts digits to their radix-values.
+ * As distributed assumes 8 bits per char (256 entries) and ASCII.
+ */
+
+#ifndef lint
+static char rcsid[] = "$Id: hex-value.c,v 1.2 1993/11/03 00:51:47 paul Exp $";
+#endif
+
+#define __ (42) /* blatently illegal digit value */
+/* exceeds any normal radix */
+
+#if (__STDC__ != 1) && !defined(const)
+#define const /* empty */
+#endif
+const char
+ hex_value[256] = { /* for fast ASCII -> binary */
+ __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __,
+ __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __,
+ __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __,
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, __, __, __, __, __, __,
+ __, 10, 11, 12, 13, 14, 15, __, __, __, __, __, __, __, __, __,
+ __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __,
+ __, 10, 11, 12, 13, 14, 15, __, __, __, __, __, __, __, __, __,
+ __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __,
+ __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __,
+ __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __,
+ __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __,
+ __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __,
+ __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __,
+ __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __,
+ __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __,
+ __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __
+ };
+
+#ifdef HO_VMS
+dummy2()
+{
+}
+#endif
+
+/* end of hex_value.c */
diff --git a/gnu/usr.bin/as/input-file.c b/gnu/usr.bin/as/input-file.c
new file mode 100644
index 0000000..39e19ac
--- /dev/null
+++ b/gnu/usr.bin/as/input-file.c
@@ -0,0 +1,327 @@
+/* input_file.c - Deal with Input Files -
+ Copyright (C) 1987, 1990, 1991, 1992 Free Software Foundation, Inc.
+
+ This file is part of GAS, the GNU Assembler.
+
+ GAS is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GAS is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GAS; see the file COPYING. If not, write to
+ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/*
+ * Confines all details of reading source bytes to this module.
+ * All O/S specific crocks should live here.
+ * What we lose in "efficiency" we gain in modularity.
+ * Note we don't need to #include the "as.h" file. No common coupling!
+ */
+
+#ifndef lint
+static char rcsid[] = "$Id: input-file.c,v 1.2 1993/11/03 00:51:48 paul Exp $";
+#endif
+
+#ifdef USG
+#define setbuffer(stream, buf, size) setvbuf((stream), (buf), _IOFBF, (size))
+#endif
+
+#include <stdio.h>
+#include <string.h>
+
+#include "as.h"
+#include "input-file.h"
+
+/* This variable is non-zero if the file currently being read should be
+ preprocessed by app. It is zero if the file can be read straight in.
+ */
+int preprocess = 0;
+
+/*
+ * This code opens a file, then delivers BUFFER_SIZE character
+ * chunks of the file on demand.
+ * BUFFER_SIZE is supposed to be a number chosen for speed.
+ * The caller only asks once what BUFFER_SIZE is, and asks before
+ * the nature of the input files (if any) is known.
+ */
+
+#define BUFFER_SIZE (32 * 1024)
+
+/*
+ * We use static data: the data area is not sharable.
+ */
+
+FILE *f_in;
+/* static JF remove static so app.c can use file_name */
+char * file_name;
+
+/* Struct for saving the state of this module for file includes. */
+struct saved_file {
+ FILE *f_in;
+ char *file_name;
+ int preprocess;
+ char *app_save;
+};
+
+/* These hooks accomodate most operating systems. */
+
+void input_file_begin() {
+ f_in = (FILE *)0;
+}
+
+void input_file_end () { }
+
+/* Return BUFFER_SIZE. */
+int input_file_buffer_size() {
+ return (BUFFER_SIZE);
+}
+
+int input_file_is_open() {
+ return f_in != (FILE *)0;
+}
+
+/* Push the state of our input, returning a pointer to saved info that
+ can be restored with input_file_pop (). */
+char *input_file_push () {
+ register struct saved_file *saved;
+
+ saved = (struct saved_file *)xmalloc (sizeof *saved);
+
+ saved->f_in = f_in;
+ saved->file_name = file_name;
+ saved->preprocess = preprocess;
+ if (preprocess)
+ saved->app_save = app_push ();
+
+ input_file_begin (); /* Initialize for new file */
+
+ return (char *)saved;
+}
+
+void
+ input_file_pop (arg)
+char *arg;
+{
+ register struct saved_file *saved = (struct saved_file *)arg;
+
+ input_file_end (); /* Close out old file */
+
+ f_in = saved->f_in;
+ file_name = saved->file_name;
+ preprocess = saved->preprocess;
+ if (preprocess)
+ app_pop (saved->app_save);
+
+ free(arg);
+}
+
+#ifdef DONTDEF /* JF save old version in case we need it */
+void
+ input_file_open (filename, preprocess, debugging)
+char * filename; /* "" means use stdin. Must not be 0. */
+int preprocess; /* TRUE if needs app. */
+int debugging; /* TRUE if we are debugging assembler. */
+{
+ assert( filename != 0 ); /* Filename may not be NULL. */
+ if (filename[0])
+ { /* We have a file name. Suck it and see. */
+ file_handle = open (filename, O_RDONLY, 0);
+ file_name = filename;
+ }
+ else
+ { /* use stdin for the input file. */
+ file_handle = fileno (stdin);
+ file_name = "{standard input}"; /* For error messages. */
+ }
+ if (file_handle < 0)
+ as_perror ("Can't open %s for reading", file_name);
+ if ( preprocess )
+ {
+ /*
+ * This code was written in haste for a frobbed BSD 4.2.
+ * I have a flight to catch: will someone please do proper
+ * error checks? - Dean.
+ */
+ int pid;
+ char temporary_file_name[12];
+ int fd;
+ union wait status;
+
+ (void)strcpy (temporary_file_name, "#appXXXXXX");
+ (void)mktemp (temporary_file_name);
+ pid = vfork ();
+ if (pid == -1)
+ {
+ as_perror ("Vfork failed", file_name);
+ _exit (144);
+ }
+ if (pid == 0)
+ {
+ (void)dup2 (file_handle, fileno(stdin));
+ fd = open (temporary_file_name, O_WRONLY + O_TRUNC + O_CREAT, 0666);
+ if (fd == -1)
+ {
+ (void)write(2,"Can't open temporary\n",21);
+ _exit (99);
+ }
+ (void)dup2 (fd, fileno(stdout));
+ /* JF for testing #define PREPROCESSOR "/lib/app" */
+#define PREPROCESSOR "./app"
+ execl (PREPROCESSOR, PREPROCESSOR, 0);
+ execl ("app","app",0);
+ (void)write(2,"Exec of app failed. Get help.\n",31);
+ (void)unlink(temporary_file_name);
+ _exit (11);
+ }
+ (void)wait (& status);
+ if (status.w_status & 0xFF00) /* JF was 0xF000, was wrong */
+ {
+ file_handle = -1;
+ as_bad( "Can't preprocess file \"%s\", status = %xx", file_name, status.w_status );
+ }
+ else
+ {
+ file_handle = open (temporary_file_name, O_RDONLY, 0);
+ if ( ! debugging && unlink(temporary_file_name))
+ as_perror ("Can't delete temp file %s", temporary_file_name);
+ }
+ if (file_handle == -1)
+ as_perror ("Can't retrieve temp file %s", temporary_file_name);
+ }
+}
+#else
+
+void
+ input_file_open (filename,pre)
+char * filename; /* "" means use stdin. Must not be 0. */
+int pre;
+{
+ int c;
+ char buf[80];
+
+ preprocess = pre;
+
+ assert( filename != 0 ); /* Filename may not be NULL. */
+ if (filename[0]) { /* We have a file name. Suck it and see. */
+ f_in=fopen(filename,"r");
+ file_name=filename;
+ } else { /* use stdin for the input file. */
+ f_in = stdin;
+ file_name = "{standard input}"; /* For error messages. */
+ }
+ if (f_in == (FILE *)0) {
+ as_perror ("Can't open %s for reading", file_name);
+ return;
+ }
+
+#ifndef HO_VMS
+ /* Ask stdio to buffer our input at BUFFER_SIZE, with a dynamically
+ allocated buffer. */
+ setvbuf(f_in, (char *)NULL, _IOFBF, BUFFER_SIZE);
+#endif /* HO_VMS */
+
+ c = getc(f_in);
+ if (c == '#') { /* Begins with comment, may not want to preprocess */
+ c = getc(f_in);
+ if (c == 'N') {
+ fgets(buf,80,f_in);
+ if (!strcmp(buf,"O_APP\n"))
+ preprocess=0;
+ if (!strchr(buf,'\n'))
+ ungetc('#',f_in); /* It was longer */
+ else
+ ungetc('\n',f_in);
+ } else if (c == '\n')
+ ungetc('\n',f_in);
+ else
+ ungetc('#',f_in);
+ } else
+ ungetc(c,f_in);
+
+#ifdef DONTDEF
+ if ( preprocess ) {
+ char temporary_file_name[17];
+ FILE *f_out;
+
+ (void)strcpy (temporary_file_name, "/tmp/#appXXXXXX");
+ (void)mktemp (temporary_file_name);
+ f_out=fopen(temporary_file_name,"w+");
+ if (f_out == (FILE *)0)
+ as_perror("Can't open temp file %s",temporary_file_name);
+
+ /* JF this will have to be moved on any system that
+ does not support removal of open files. */
+ (void)unlink(temporary_file_name);/* JF do it NOW */
+ do_scrub(f_in,f_out);
+ (void)fclose(f_in); /* All done with it */
+ (void)rewind(f_out);
+ f_in=f_out;
+ }
+#endif
+}
+#endif
+
+/* Close input file. */
+void input_file_close() {
+ if (f_in != NULL) {
+ fclose (f_in);
+ } /* don't close a null file pointer */
+ f_in = 0;
+} /* input_file_close() */
+
+char *
+ input_file_give_next_buffer (where)
+char * where; /* Where to place 1st character of new buffer. */
+{
+ char * return_value; /* -> Last char of what we read, + 1. */
+ register int size;
+
+ if (f_in == (FILE *)0)
+ return 0;
+ /*
+ * fflush (stdin); could be done here if you want to synchronise
+ * stdin and stdout, for the case where our input file is stdin.
+ * Since the assembler shouldn't do any output to stdout, we
+ * don't bother to synch output and input.
+ */
+ if (preprocess) {
+ char *p;
+ int n;
+ int ch;
+ extern FILE *scrub_file;
+
+ scrub_file=f_in;
+ for (p = where, n = BUFFER_SIZE; n; --n) {
+
+ ch = do_scrub_next_char(scrub_from_file, scrub_to_file);
+ if (ch == EOF)
+ break;
+ *p++=ch;
+ }
+ size=BUFFER_SIZE-n;
+ } else
+ size= fread(where,sizeof(char),BUFFER_SIZE,f_in);
+ if (size < 0)
+ {
+ as_perror ("Can't read from %s", file_name);
+ size = 0;
+ }
+ if (size)
+ return_value = where + size;
+ else
+ {
+ if (fclose (f_in))
+ as_perror ("Can't close %s", file_name);
+ f_in = (FILE *)0;
+ return_value = 0;
+ }
+ return (return_value);
+}
+
+/* end of input-file.c */
diff --git a/gnu/usr.bin/as/input-file.h b/gnu/usr.bin/as/input-file.h
new file mode 100644
index 0000000..0c6da7d
--- /dev/null
+++ b/gnu/usr.bin/as/input-file.h
@@ -0,0 +1,88 @@
+/* input_file.h header for input-file.c
+ Copyright (C) 1987, 1992 Free Software Foundation, Inc.
+
+ This file is part of GAS, the GNU Assembler.
+
+ GAS is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GAS is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GAS; see the file COPYING. If not, write to
+ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/*"input_file.c":Operating-system dependant functions to read source files.*/
+
+/*
+ * $Id: input-file.h,v 1.2 1993/11/03 00:51:50 paul Exp $
+ */
+
+
+/*
+ * No matter what the operating system, this module must provide the
+ * following services to its callers.
+ *
+ * input_file_begin() Call once before anything else.
+ *
+ * input_file_end() Call once after everything else.
+ *
+ * input_file_buffer_size() Call anytime. Returns largest possible
+ * delivery from
+ * input_file_give_next_buffer().
+ *
+ * input_file_open(name) Call once for each input file.
+ *
+ * input_file_give_next_buffer(where) Call once to get each new buffer.
+ * Return 0: no more chars left in file,
+ * the file has already been closed.
+ * Otherwise: return a pointer to just
+ * after the last character we read
+ * into the buffer.
+ * If we can only read 0 characters, then
+ * end-of-file is faked.
+ *
+ * input_file_push() Push state, which can be restored
+ * later. Does implicit input_file_begin.
+ * Returns char * to saved state.
+ *
+ * input_file_pop (arg) Pops previously saved state.
+ *
+ * input_file_close () Closes opened file.
+ *
+ * All errors are reported (using as_perror) so caller doesn't have to think
+ * about I/O errors. No I/O errors are fatal: an end-of-file may be faked.
+ */
+
+#if __STDC__ == 1
+
+char *input_file_give_next_buffer(char *where);
+char *input_file_push(void);
+int input_file_buffer_size(void);
+int input_file_is_open(void);
+void input_file_begin(void);
+void input_file_close(void);
+void input_file_end(void);
+void input_file_open(char *filename, int pre);
+void input_file_pop(char *arg);
+
+#else /* not __STDC__ */
+
+char *input_file_give_next_buffer();
+char *input_file_push();
+int input_file_buffer_size();
+int input_file_is_open();
+void input_file_begin();
+void input_file_close();
+void input_file_end();
+void input_file_open();
+void input_file_pop();
+
+#endif /* not __STDC__ */
+
+/* end of input_file.h */
diff --git a/gnu/usr.bin/as/input-scrub.c b/gnu/usr.bin/as/input-scrub.c
new file mode 100644
index 0000000..0e0a179
--- /dev/null
+++ b/gnu/usr.bin/as/input-scrub.c
@@ -0,0 +1,420 @@
+/* input_scrub.c - Break up input buffers into whole numbers of lines.
+ Copyright (C) 1987, 1990, 1991, 1992 Free Software Foundation, Inc.
+
+ This file is part of GAS, the GNU Assembler.
+
+ GAS is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GAS is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GAS; see the file COPYING. If not, write to
+ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#ifndef lint
+static char rcsid[] = "$Id: input-scrub.c,v 1.3 1994/12/23 22:36:05 nate Exp $";
+#endif
+
+#include <errno.h> /* Need this to make errno declaration right */
+#include "as.h"
+#include "input-file.h"
+
+/*
+ * O/S independent module to supply buffers of sanitised source code
+ * to rest of assembler. We get sanitized input data of arbitrary length.
+ * We break these buffers on line boundaries, recombine pieces that
+ * were broken across buffers, and return a buffer of full lines to
+ * the caller.
+ * The last partial line begins the next buffer we build and return to caller.
+ * The buffer returned to caller is preceeded by BEFORE_STRING and followed
+ * by AFTER_STRING, as sentinels. The last character before AFTER_STRING
+ * is a newline.
+ * Also looks after line numbers, for e.g. error messages.
+ */
+
+/*
+ * We don't care how filthy our buffers are, but our callers assume
+ * that the following sanitation has already been done.
+ *
+ * No comments, reduce a comment to a space.
+ * Reduce a tab to a space unless it is 1st char of line.
+ * All multiple tabs and spaces collapsed into 1 char. Tab only
+ * legal if 1st char of line.
+ * # line file statements converted to .line x;.file y; statements.
+ * Escaped newlines at end of line: remove them but add as many newlines
+ * to end of statement as you removed in the middle, to synch line numbers.
+ */
+
+#define BEFORE_STRING ("\n")
+#define AFTER_STRING ("\0") /* memcpy of 0 chars might choke. */
+#define BEFORE_SIZE (1)
+#define AFTER_SIZE (1)
+
+static char *buffer_start; /*->1st char of full buffer area. */
+static char *partial_where; /*->after last full line in buffer. */
+static int partial_size; /* >=0. Number of chars in partial line in buffer. */
+static char save_source[AFTER_SIZE];
+/* Because we need AFTER_STRING just after last */
+/* full line, it clobbers 1st part of partial */
+/* line. So we preserve 1st part of partial */
+/* line here. */
+static unsigned int buffer_length; /* What is the largest size buffer that */
+/* input_file_give_next_buffer() could */
+/* return to us? */
+
+/* Saved information about the file that .include'd this one. When we hit EOF,
+ we automatically pop to that file. */
+
+static char *next_saved_file;
+
+/* We can have more than one source file open at once, though the info for all
+ but the latest one are saved off in a struct input_save. These files remain
+ open, so we are limited by the number of open files allowed by the
+ underlying OS. We may also sequentially read more than one source file in an
+ assembly. */
+
+/* We must track the physical file and line number for error messages. We also
+ track a "logical" file and line number corresponding to (C?) compiler
+ source line numbers. Whenever we open a file we must fill in
+ physical_input_file. So if it is NULL we have not opened any files yet. */
+
+static char *physical_input_file;
+static char *logical_input_file;
+
+typedef unsigned int line_numberT; /* 1-origin line number in a source file. */
+/* A line ends in '\n' or eof. */
+
+static line_numberT physical_input_line;
+static int logical_input_line;
+
+/* Struct used to save the state of the input handler during include files */
+struct input_save
+ {
+ char *buffer_start;
+ char *partial_where;
+ int partial_size;
+ char save_source[AFTER_SIZE];
+ unsigned int buffer_length;
+ char *physical_input_file;
+ char *logical_input_file;
+ line_numberT physical_input_line;
+ int logical_input_line;
+ char *next_saved_file; /* Chain of input_saves */
+ char *input_file_save; /* Saved state of input routines */
+ char *saved_position; /* Caller's saved position in buf */
+ };
+
+static char *input_scrub_push PARAMS ((char *saved_position));
+static char *input_scrub_pop PARAMS ((char *arg));
+static void as_1_char PARAMS ((unsigned int c, FILE * stream));
+
+/* Push the state of input reading and scrubbing so that we can #include.
+ The return value is a 'void *' (fudged for old compilers) to a save
+ area, which can be restored by passing it to input_scrub_pop(). */
+static char *
+input_scrub_push (saved_position)
+ char *saved_position;
+{
+ register struct input_save *saved;
+
+ saved = (struct input_save *) xmalloc (sizeof *saved);
+
+ saved->saved_position = saved_position;
+ saved->buffer_start = buffer_start;
+ saved->partial_where = partial_where;
+ saved->partial_size = partial_size;
+ saved->buffer_length = buffer_length;
+ saved->physical_input_file = physical_input_file;
+ saved->logical_input_file = logical_input_file;
+ saved->physical_input_line = physical_input_line;
+ saved->logical_input_line = logical_input_line;
+ memcpy (saved->save_source, save_source, sizeof (save_source));
+ saved->next_saved_file = next_saved_file;
+ saved->input_file_save = input_file_push ();
+
+ input_file_begin (); /* Reinitialize! */
+ logical_input_line = -1;
+ logical_input_file = (char *) NULL;
+ buffer_length = input_file_buffer_size ();
+
+ buffer_start = xmalloc ((BEFORE_SIZE + buffer_length + buffer_length + AFTER_SIZE));
+ memcpy (buffer_start, BEFORE_STRING, (int) BEFORE_SIZE);
+
+ return ((char *) saved);
+} /* input_scrub_push() */
+
+static char *
+input_scrub_pop (arg)
+ char *arg;
+{
+ register struct input_save *saved;
+ char *saved_position;
+
+ input_scrub_end (); /* Finish off old buffer */
+
+ saved = (struct input_save *) arg;
+
+ input_file_pop (saved->input_file_save);
+ saved_position = saved->saved_position;
+ buffer_start = saved->buffer_start;
+ buffer_length = saved->buffer_length;
+ physical_input_file = saved->physical_input_file;
+ logical_input_file = saved->logical_input_file;
+ physical_input_line = saved->physical_input_line;
+ logical_input_line = saved->logical_input_line;
+ partial_where = saved->partial_where;
+ partial_size = saved->partial_size;
+ next_saved_file = saved->next_saved_file;
+ memcpy (save_source, saved->save_source, sizeof (save_source));
+
+ free (arg);
+ return saved_position;
+}
+
+
+void
+input_scrub_begin ()
+{
+ know (strlen (BEFORE_STRING) == BEFORE_SIZE);
+ know (strlen (AFTER_STRING) == AFTER_SIZE || (AFTER_STRING[0] == '\0' && AFTER_SIZE == 1));
+
+ input_file_begin ();
+
+ buffer_length = input_file_buffer_size ();
+
+ buffer_start = xmalloc ((BEFORE_SIZE + buffer_length + buffer_length + AFTER_SIZE));
+ memcpy (buffer_start, BEFORE_STRING, (int) BEFORE_SIZE);
+
+ /* Line number things. */
+ logical_input_line = -1;
+ logical_input_file = (char *) NULL;
+ physical_input_file = NULL; /* No file read yet. */
+ next_saved_file = NULL; /* At EOF, don't pop to any other file */
+ do_scrub_begin ();
+}
+
+void
+input_scrub_end ()
+{
+ if (buffer_start)
+ {
+ free (buffer_start);
+ buffer_start = 0;
+ input_file_end ();
+ }
+}
+
+/* Start reading input from a new file. */
+
+char * /* Return start of caller's part of buffer. */
+input_scrub_new_file (filename)
+ char *filename;
+{
+ input_file_open (filename, !flagseen['f']);
+ physical_input_file = filename[0] ? filename : "{standard input}";
+ physical_input_line = 0;
+
+ partial_size = 0;
+ return (buffer_start + BEFORE_SIZE);
+}
+
+
+/* Include a file from the current file. Save our state, cause it to
+ be restored on EOF, and begin handling a new file. Same result as
+ input_scrub_new_file. */
+
+char *
+input_scrub_include_file (filename, position)
+ char *filename;
+ char *position;
+{
+ next_saved_file = input_scrub_push (position);
+ return input_scrub_new_file (filename);
+}
+
+void
+input_scrub_close ()
+{
+ input_file_close ();
+}
+
+char *
+input_scrub_next_buffer (bufp)
+ char **bufp;
+{
+ register char *limit; /*->just after last char of buffer. */
+
+ *bufp = buffer_start + BEFORE_SIZE;
+
+ if (partial_size)
+ {
+ memcpy (buffer_start + BEFORE_SIZE, partial_where,
+ (unsigned int) partial_size);
+ memcpy (buffer_start + BEFORE_SIZE, save_source, AFTER_SIZE);
+ }
+ limit = input_file_give_next_buffer (buffer_start + BEFORE_SIZE + partial_size);
+ if (limit)
+ {
+ register char *p; /* Find last newline. */
+
+ for (p = limit; *--p != '\n';);;
+ ++p;
+ if (p <= buffer_start + BEFORE_SIZE)
+ {
+ as_fatal ("Source line too long. Please change file %s then rebuild assembler.", __FILE__);
+ }
+ partial_where = p;
+ partial_size = limit - p;
+ memcpy (save_source, partial_where, (int) AFTER_SIZE);
+ memcpy (partial_where, AFTER_STRING, (int) AFTER_SIZE);
+ }
+ else
+ {
+ partial_where = 0;
+ if (partial_size > 0)
+ {
+ as_warn ("Partial line at end of file ignored");
+ }
+ /* If we should pop to another file at EOF, do it. */
+ if (next_saved_file)
+ {
+ *bufp = input_scrub_pop (next_saved_file); /* Pop state */
+ /* partial_where is now correct to return, since we popped it. */
+ }
+ }
+ return (partial_where);
+} /* input_scrub_next_buffer() */
+
+/*
+ * The remaining part of this file deals with line numbers, error
+ * messages and so on.
+ */
+
+
+int
+seen_at_least_1_file () /* TRUE if we opened any file. */
+{
+ return (physical_input_file != NULL);
+}
+
+void
+bump_line_counters ()
+{
+ ++physical_input_line;
+ if (logical_input_line >= 0)
+ ++logical_input_line;
+}
+
+/*
+ * new_logical_line()
+ *
+ * Tells us what the new logical line number and file are.
+ * If the line_number is -1, we don't change the current logical line
+ * number. If it is -2, we decrement the logical line number (this is
+ * to support the .appfile pseudo-op inserted into the stream by
+ * do_scrub_next_char).
+ * If the fname is NULL, we don't change the current logical file name.
+ */
+void
+new_logical_line (fname, line_number)
+ char *fname; /* DON'T destroy it! We point to it! */
+ int line_number;
+{
+ if (fname)
+ {
+ logical_input_file = fname;
+ } /* if we have a file name */
+
+ if (line_number >= 0)
+ logical_input_line = line_number;
+ else if (line_number == -2 && logical_input_line > 0)
+ --logical_input_line;
+} /* new_logical_line() */
+
+/*
+ * a s _ w h e r e ()
+ *
+ * Return the current file name and line number.
+ * namep should be char * const *, but there are compilers which screw
+ * up declarations like that, and it's easier to avoid it.
+ */
+void
+as_where (namep, linep)
+ char **namep;
+ unsigned int *linep;
+{
+ if (logical_input_file != NULL
+ && (linep == NULL || logical_input_line >= 0))
+ {
+ *namep = logical_input_file;
+ if (linep != NULL)
+ *linep = logical_input_line;
+ }
+ else if (physical_input_file != NULL)
+ {
+ *namep = physical_input_file;
+ if (linep != NULL)
+ *linep = physical_input_line;
+ }
+ else
+ {
+ *namep = (char *) "*unknown*";
+ if (linep != NULL)
+ *linep = 0;
+ }
+} /* as_where() */
+
+
+
+
+/*
+ * a s _ h o w m u c h ()
+ *
+ * Output to given stream how much of line we have scanned so far.
+ * Assumes we have scanned up to and including input_line_pointer.
+ * No free '\n' at end of line.
+ */
+void
+as_howmuch (stream)
+ FILE *stream; /* Opened for write please. */
+{
+ register char *p; /* Scan input line. */
+ /* register char c; JF unused */
+
+ for (p = input_line_pointer - 1; *p != '\n'; --p)
+ {
+ }
+ ++p; /* p->1st char of line. */
+ for (; p <= input_line_pointer; p++)
+ {
+ /* Assume ASCII. EBCDIC & other micro-computer char sets ignored. */
+ /* c = *p & 0xFF; JF unused */
+ as_1_char ((unsigned char) *p, stream);
+ }
+}
+
+static void
+as_1_char (c, stream)
+ unsigned int c;
+ FILE *stream;
+{
+ if (c > 127)
+ {
+ (void) putc ('%', stream);
+ c -= 128;
+ }
+ if (c < 32)
+ {
+ (void) putc ('^', stream);
+ c += '@';
+ }
+ (void) putc (c, stream);
+}
+
+/* end of input_scrub.c */
diff --git a/gnu/usr.bin/as/link.cmd b/gnu/usr.bin/as/link.cmd
new file mode 100644
index 0000000..a035ca8
--- /dev/null
+++ b/gnu/usr.bin/as/link.cmd
@@ -0,0 +1,10 @@
+ALIGN=1024
+RESNUM 0x0000, 0x8000
+; Putting in .lit1 gives errors.
+ORDER .data=0x80002000, .data1, .lit, .bss
+; Let's put this on the command line so it goes first, which is what
+; GDB expects.
+; LOAD /s2/amd/29k/lib/crt0.o
+LOAD /s2/amd/29k/lib/libqcb0h.lib
+LOAD /s2/amd/29k/lib/libscb0h.lib
+LOAD /s2/amd/29k/lib/libacb0h.lib
diff --git a/gnu/usr.bin/as/listing.c b/gnu/usr.bin/as/listing.c
new file mode 100644
index 0000000..f79a8b4
--- /dev/null
+++ b/gnu/usr.bin/as/listing.c
@@ -0,0 +1,1079 @@
+/* listing.c - mainting assembly listings
+ Copyright (C) 1991, 1992 Free Software Foundation, Inc.
+
+This file is part of GAS, the GNU Assembler.
+
+GAS is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GAS is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GAS; see the file COPYING. If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/*
+ Contributed by Steve Chamberlain
+ sac@cygnus.com
+
+
+ A listing page looks like:
+
+ LISTING_HEADER sourcefilename pagenumber
+ TITLE LINE
+ SUBTITLE LINE
+ linenumber address data source
+ linenumber address data source
+ linenumber address data source
+ linenumber address data source
+
+ If not overridden, the listing commands are:
+
+ .title "stuff"
+ Put "stuff" onto the title line
+ .sbttl "stuff"
+ Put stuff onto the subtitle line
+
+ If these commands come within 10 lines of the top of the page, they
+ will affect the page they are on, as well as any subsequent page
+
+ .eject
+ Thow a page
+ .list
+ Increment the enable listing counter
+ .nolist
+ Decrement the enable listing counter
+
+ .psize Y[,X]
+ Set the paper size to X wide and Y high. Setting a psize Y of
+ zero will suppress form feeds except where demanded by .eject
+
+ If the counter goes below zero, listing is suppressed.
+
+
+ Listings are a maintained by read calling various listing_<foo>
+ functions. What happens most is that the macro NO_LISTING is not
+ defined (from the Makefile), then the macro LISTING_NEWLINE expands
+ into a call to listing_newline. The call is done from read.c, every
+ time it sees a newline, and -l is on the command line.
+
+ The function listing_newline remembers the frag associated with the
+ newline, and creates a new frag - note that this is wasteful, but not
+ a big deal, since listing slows things down a lot anyway. The
+ function also rememebers when the filename changes.
+
+ When all the input has finished, and gas has had a chance to settle
+ down, the listing is output. This is done by running down the list of
+ frag/source file records, and opening the files as needed and printing
+ out the bytes and chars associated with them.
+
+ The only things which the architecture can change about the listing
+ are defined in these macros:
+
+ LISTING_HEADER The name of the architecture
+ LISTING_WORD_SIZE The make of the number of bytes in a word, this determines
+ the clumping of the output data. eg a value of
+ 2 makes words look like 1234 5678, whilst 1
+ would make the same value look like 12 34 56
+ 78
+ LISTING_LHS_WIDTH Number of words of above size for the lhs
+
+ LISTING_LHS_WIDTH_SECOND Number of words for the data on the lhs
+ for the second line
+
+ LISTING_LHS_CONT_LINES Max number of lines to use up for a continutation
+ LISTING_RHS_WIDTH Number of chars from the input file to print
+ on a line
+*/
+
+#ifndef lint
+static char rcsid[] = "$Id: listing.c,v 1.2 1994/12/23 22:36:08 nate Exp $";
+#endif
+
+#include <ctype.h>
+
+#include "as.h"
+#include <obstack.h>
+#include "input-file.h"
+#include "subsegs.h"
+
+#ifndef NO_LISTING
+#ifndef LISTING_HEADER
+#define LISTING_HEADER "GAS LISTING"
+#endif
+#ifndef LISTING_WORD_SIZE
+#define LISTING_WORD_SIZE 4
+#endif
+#ifndef LISTING_LHS_WIDTH
+#define LISTING_LHS_WIDTH 1
+#endif
+#ifndef LISTING_LHS_WIDTH_SECOND
+#define LISTING_LHS_WIDTH_SECOND 1
+#endif
+#ifndef LISTING_RHS_WIDTH
+#define LISTING_RHS_WIDTH 100
+#endif
+#ifndef LISTING_LHS_CONT_LINES
+#define LISTING_LHS_CONT_LINES 4
+#endif
+
+
+
+
+static struct list_info_struct *head;
+struct list_info_struct *listing_tail;
+extern int listing;
+extern fragS *frag_now;
+
+
+static int paper_width = 200;
+static int paper_height = 60;
+
+
+/* this static array is used to keep the text of data to be printed
+ before the start of the line.
+ It is stored so we can give a bit more info on the next line. To much, and large
+ initialized arrays will use up lots of paper.
+ */
+
+static char data_buffer[100];
+static unsigned int data_buffer_size;
+
+
+/* Prototypes. */
+static void listing_message PARAMS ((const char *name, const char *message));
+static file_info_type *file_info PARAMS ((const char *file_name));
+static void new_frag PARAMS ((void));
+static char *buffer_line PARAMS ((file_info_type *file,
+ char *line, unsigned int size));
+static void listing_page PARAMS ((list_info_type *list));
+static unsigned int calc_hex PARAMS ((list_info_type *list));
+static void print_lines PARAMS ((list_info_type *list,
+ char *string,
+ unsigned int address));
+static void list_symbol_table PARAMS ((void));
+static void print_source PARAMS ((file_info_type *current_file,
+ list_info_type *list,
+ char *buffer,
+ unsigned int width));
+static int debugging_pseudo PARAMS ((char *line));
+static void listing_listing PARAMS ((char *name));
+
+
+static void
+listing_message (name, message)
+ const char *name;
+ const char *message;
+{
+ unsigned int l = strlen (name) + strlen (message) + 1;
+ char *n = (char *) xmalloc (l);
+ strcpy (n, name);
+ strcat (n, message);
+ if (listing_tail != (list_info_type *) NULL)
+ {
+ listing_tail->message = n;
+ }
+}
+
+void
+listing_warning (message)
+ const char *message;
+{
+ listing_message ("Warning:", message);
+}
+
+void
+listing_error (message)
+ const char *message;
+{
+ listing_message ("Error:", message);
+}
+
+
+
+
+static file_info_type *file_info_head;
+
+static file_info_type *
+file_info (file_name)
+ const char *file_name;
+{
+ /* Find an entry with this file name */
+ file_info_type *p = file_info_head;
+
+ while (p != (file_info_type *) NULL)
+ {
+ if (strcmp (p->filename, file_name) == 0)
+ return p;
+ p = p->next;
+ }
+
+ /* Make new entry */
+
+ p = (file_info_type *) xmalloc (sizeof (file_info_type));
+ p->next = file_info_head;
+ file_info_head = p;
+ p->filename = xmalloc ((unsigned long) strlen (file_name) + 1);
+ strcpy (p->filename, file_name);
+ p->linenum = 0;
+ p->end_pending = 0;
+
+ /* Do we really prefer binary mode for this?? */
+#define FOPEN_RB "r"
+ p->file = fopen (p->filename, FOPEN_RB);
+ if (p->file)
+ fgetc (p->file);
+
+ return p;
+}
+
+
+static void
+new_frag ()
+{
+
+ frag_wane (frag_now);
+ frag_new (0);
+
+}
+
+void
+listing_newline (ps)
+ char *ps;
+{
+ char *file;
+ unsigned int line;
+ static unsigned int last_line = 0xffff;
+ static char *last_file = NULL;
+ list_info_type *new;
+
+ as_where (&file, &line);
+ if (line != last_line || last_file && file && strcmp(file, last_file))
+ {
+ last_line = line;
+ last_file = file;
+ new_frag ();
+
+ new = (list_info_type *) xmalloc (sizeof (list_info_type));
+ new->frag = frag_now;
+ new->line = line;
+ new->file = file_info (file);
+
+ if (listing_tail)
+ {
+ listing_tail->next = new;
+ }
+ else
+ {
+ head = new;
+ }
+ listing_tail = new;
+ new->next = (list_info_type *) NULL;
+ new->message = (char *) NULL;
+ new->edict = EDICT_NONE;
+ new->hll_file = (file_info_type *) NULL;
+ new->hll_line = 0;
+ new_frag ();
+ }
+}
+
+/* Attach all current frags to the previous line instead of the
+ current line. This is called by the MIPS backend when it discovers
+ that it needs to add some NOP instructions; the added NOP
+ instructions should go with the instruction that has the delay, not
+ with the new instruction. */
+
+void
+listing_prev_line ()
+{
+ list_info_type *l;
+ fragS *f;
+
+ if (head == (list_info_type *) NULL
+ || head == listing_tail)
+ return;
+
+ new_frag ();
+
+ for (l = head; l->next != listing_tail; l = l->next)
+ ;
+
+ for (f = frchain_now->frch_root; f != (fragS *) NULL; f = f->fr_next)
+ if (f->line == listing_tail)
+ f->line = l;
+
+ listing_tail->frag = frag_now;
+ new_frag ();
+}
+
+/*
+ This function returns the next source line from the file supplied,
+ truncated to size. It appends a fake line to the end of each input
+ file to make
+*/
+
+static char *
+buffer_line (file, line, size)
+ file_info_type * file;
+ char *line;
+ unsigned int size;
+{
+ unsigned int count = 0;
+ int c;
+
+ char *p = line;
+
+ /* If we couldn't open the file, return an empty line */
+ if (file->file == (FILE *) NULL)
+ {
+ return "";
+ }
+
+ if (file->linenum == 0)
+ rewind (file->file);
+
+ if (file->end_pending == 10)
+ {
+ *p++ = '\n';
+ fseek (file->file, 0, 0);
+ file->linenum = 0;
+ file->end_pending = 0;
+ }
+ c = fgetc (file->file);
+
+
+ size -= 1; /* leave room for null */
+
+ while (c != EOF && c != '\n')
+ {
+ if (count < size)
+ *p++ = c;
+ count++;
+
+ c = fgetc (file->file);
+
+ }
+ if (c == EOF)
+ {
+ file->end_pending++;
+ *p++ = '.';
+ *p++ = '.';
+ *p++ = '.';
+ }
+ file->linenum++;
+ *p++ = 0;
+ return line;
+}
+
+
+static const char *fn;
+
+static unsigned int eject; /* Eject pending */
+static unsigned int page; /* Current page number */
+static char *title; /* current title */
+static char *subtitle; /* current subtitle */
+static unsigned int on_page; /* number of lines printed on current page */
+
+
+static void
+listing_page (list)
+ list_info_type *list;
+{
+ /* Grope around, see if we can see a title or subtitle edict coming up
+ soon (we look down 10 lines of the page and see if it's there)*/
+ if ((eject || (on_page >= paper_height)) && paper_height != 0)
+ {
+ unsigned int c = 10;
+ int had_title = 0;
+ int had_subtitle = 0;
+
+ page++;
+
+ while (c != 0 && list)
+ {
+ if (list->edict == EDICT_SBTTL && !had_subtitle)
+ {
+ had_subtitle = 1;
+ subtitle = list->edict_arg;
+ }
+ if (list->edict == EDICT_TITLE && !had_title)
+ {
+ had_title = 1;
+ title = list->edict_arg;
+ }
+ list = list->next;
+ c--;
+ }
+
+
+ if (page > 1)
+ {
+ printf ("\f");
+ }
+
+ printf ("%s %s \t\t\tpage %d\n", LISTING_HEADER, fn, page);
+ printf ("%s\n", title);
+ printf ("%s\n", subtitle);
+ on_page = 3;
+ eject = 0;
+ }
+}
+
+
+static unsigned int
+calc_hex (list)
+ list_info_type * list;
+{
+ list_info_type *first = list;
+ unsigned int address = (unsigned int) ~0;
+
+ fragS *frag;
+ fragS *frag_ptr;
+
+ unsigned int byte_in_frag;
+
+
+ /* Find first frag which says it belongs to this line */
+ frag = list->frag;
+ while (frag && frag->line != list)
+ frag = frag->fr_next;
+
+ frag_ptr = frag;
+
+ data_buffer_size = 0;
+
+ /* Dump all the frags which belong to this line */
+ while (frag_ptr != (fragS *) NULL && frag_ptr->line == first)
+ {
+ /* Print as many bytes from the fixed part as is sensible */
+ byte_in_frag = 0;
+ while (byte_in_frag < frag_ptr->fr_fix && data_buffer_size < sizeof (data_buffer) - 10)
+ {
+ if (address == ~0)
+ {
+ address = frag_ptr->fr_address;
+ }
+
+ sprintf (data_buffer + data_buffer_size,
+ "%02X",
+ (frag_ptr->fr_literal[byte_in_frag]) & 0xff);
+ data_buffer_size += 2;
+ byte_in_frag++;
+ }
+ {
+ unsigned int var_rep_max = byte_in_frag;
+ unsigned int var_rep_idx = byte_in_frag;
+
+ /* Print as many bytes from the variable part as is sensible */
+ while (byte_in_frag < frag_ptr->fr_var * frag_ptr->fr_offset
+ && data_buffer_size < sizeof (data_buffer) - 10)
+ {
+ if (address == ~0)
+ {
+ address = frag_ptr->fr_address;
+ }
+ sprintf (data_buffer + data_buffer_size,
+ "%02X",
+ (frag_ptr->fr_literal[var_rep_idx]) & 0xff);
+#if 0
+ data_buffer[data_buffer_size++] = '*';
+ data_buffer[data_buffer_size++] = '*';
+#endif
+ data_buffer_size += 2;
+
+ var_rep_idx++;
+ byte_in_frag++;
+
+ if (var_rep_idx >= frag_ptr->fr_var)
+ var_rep_idx = var_rep_max;
+ }
+ }
+
+ frag_ptr = frag_ptr->fr_next;
+ }
+ data_buffer[data_buffer_size++] = 0;
+ return address;
+}
+
+
+
+
+
+
+static void
+print_lines (list, string, address)
+ list_info_type *list;
+ char *string;
+ unsigned int address;
+{
+ unsigned int idx;
+ unsigned int nchars;
+ unsigned int lines;
+ unsigned int byte_in_word = 0;
+ char *src = data_buffer;
+
+ /* Print the stuff on the first line */
+ listing_page (list);
+ nchars = (LISTING_WORD_SIZE * 2 + 1) * LISTING_LHS_WIDTH;
+ /* Print the hex for the first line */
+ if (address == ~0)
+ {
+ printf ("% 4d ", list->line);
+ for (idx = 0; idx < nchars; idx++)
+ printf (" ");
+
+ printf ("\t%s\n", string ? string : "");
+ on_page++;
+ listing_page (0);
+
+ }
+ else
+ {
+ if (had_errors ())
+ {
+ printf ("% 4d ???? ", list->line);
+ }
+ else
+ {
+ printf ("% 4d %04x ", list->line, address);
+ }
+
+ /* And the data to go along with it */
+ idx = 0;
+
+ while (*src && idx < nchars)
+ {
+ printf ("%c%c", src[0], src[1]);
+ src += 2;
+ byte_in_word++;
+ if (byte_in_word == LISTING_WORD_SIZE)
+ {
+ printf (" ");
+ idx++;
+ byte_in_word = 0;
+ }
+ idx += 2;
+ }
+
+ for (; idx < nchars; idx++)
+ printf (" ");
+
+ printf ("\t%s\n", string ? string : "");
+ on_page++;
+ listing_page (list);
+ if (list->message)
+ {
+ printf ("**** %s\n", list->message);
+ listing_page (list);
+ on_page++;
+ }
+
+ for (lines = 0;
+ lines < LISTING_LHS_CONT_LINES
+ && *src;
+ lines++)
+ {
+ nchars = ((LISTING_WORD_SIZE * 2) + 1) * LISTING_LHS_WIDTH_SECOND - 1;
+ idx = 0;
+ /* Print any more lines of data, but more compactly */
+ printf ("% 4d ", list->line);
+
+ while (*src && idx < nchars)
+ {
+ printf ("%c%c", src[0], src[1]);
+ src += 2;
+ idx += 2;
+ byte_in_word++;
+ if (byte_in_word == LISTING_WORD_SIZE)
+ {
+ printf (" ");
+ idx++;
+ byte_in_word = 0;
+ }
+ }
+
+ printf ("\n");
+ on_page++;
+ listing_page (list);
+
+ }
+
+
+ }
+}
+
+
+static void
+list_symbol_table ()
+{
+ extern symbolS *symbol_rootP;
+ int got_some = 0;
+
+ symbolS *ptr;
+ eject = 1;
+ listing_page (0);
+
+ for (ptr = symbol_rootP; ptr != (symbolS *) NULL; ptr = symbol_next (ptr))
+ {
+ if (ptr->sy_frag->line)
+ {
+ if (S_GET_NAME (ptr))
+ {
+ char buf[30];
+ valueT val = S_GET_VALUE (ptr);
+
+ /* @@ Note that this is dependent on the compilation options,
+ not solely on the target characteristics. */
+ if (sizeof (val) == 4 && sizeof (int) == 4)
+ sprintf (buf, "%08lx", (unsigned long) val);
+#if defined (BFD64)
+ else if (sizeof (val) > 4)
+ {
+ char buf1[30];
+ sprintf_vma (buf1, val);
+ strcpy (buf, "00000000");
+ strcpy (buf + 8 - strlen (buf1), buf1);
+ }
+#endif
+ else
+ abort ();
+
+ if (!got_some)
+ {
+ printf ("DEFINED SYMBOLS\n");
+ on_page++;
+ got_some = 1;
+ }
+
+ printf ("%20s:%-5d %s:%s %s\n",
+ ptr->sy_frag->line->file->filename,
+ ptr->sy_frag->line->line,
+ segment_name (S_GET_SEGMENT (ptr)),
+ buf, S_GET_NAME (ptr));
+
+ on_page++;
+ listing_page (0);
+ }
+ }
+
+ }
+ if (!got_some)
+ {
+ printf ("NO DEFINED SYMBOLS\n");
+ on_page++;
+ }
+ printf ("\n");
+ on_page++;
+ listing_page (0);
+
+ got_some = 0;
+
+ for (ptr = symbol_rootP; ptr != (symbolS *) NULL; ptr = symbol_next (ptr))
+ {
+ if (S_GET_NAME (ptr) && strlen (S_GET_NAME (ptr)) != 0)
+ {
+ if (ptr->sy_frag->line == 0
+#ifdef notyet
+ && S_GET_SEGMENT (ptr) != reg_section)
+#else
+ && !S_IS_REGISTER(ptr))
+#endif
+ {
+ if (!got_some)
+ {
+ got_some = 1;
+ printf ("UNDEFINED SYMBOLS\n");
+ on_page++;
+ listing_page (0);
+ }
+ printf ("%s\n", S_GET_NAME (ptr));
+ on_page++;
+ listing_page (0);
+ }
+ }
+ }
+ if (!got_some)
+ {
+ printf ("NO UNDEFINED SYMBOLS\n");
+ on_page++;
+ listing_page (0);
+ }
+}
+
+static void
+print_source (current_file, list, buffer, width)
+ file_info_type *current_file;
+ list_info_type *list;
+ char *buffer;
+ unsigned int width;
+{
+ if (current_file->file)
+ {
+ while (current_file->linenum < list->hll_line)
+ {
+ char *p = buffer_line (current_file, buffer, width);
+ printf ("%4d:%-13s **** %s\n", current_file->linenum, current_file->filename, p);
+ on_page++;
+ listing_page (list);
+ }
+ }
+}
+
+/* Sometimes the user doesn't want to be bothered by the debugging
+ records inserted by the compiler, see if the line is suspicious */
+
+static int
+debugging_pseudo (line)
+ char *line;
+{
+ while (isspace (*line))
+ line++;
+
+ if (*line != '.')
+ return 0;
+
+ line++;
+
+ if (strncmp (line, "def", 3) == 0)
+ return 1;
+ if (strncmp (line, "val", 3) == 0)
+ return 1;
+ if (strncmp (line, "scl", 3) == 0)
+ return 1;
+ if (strncmp (line, "line", 4) == 0)
+ return 1;
+ if (strncmp (line, "endef", 5) == 0)
+ return 1;
+ if (strncmp (line, "ln", 2) == 0)
+ return 1;
+ if (strncmp (line, "type", 4) == 0)
+ return 1;
+ if (strncmp (line, "size", 4) == 0)
+ return 1;
+ if (strncmp (line, "dim", 3) == 0)
+ return 1;
+ if (strncmp (line, "tag", 3) == 0)
+ return 1;
+
+ if (strncmp (line, "stabs", 5) == 0)
+ return 1;
+ if (strncmp (line, "stabn", 5) == 0)
+ return 1;
+
+ return 0;
+
+}
+
+static void
+listing_listing (name)
+ char *name;
+{
+ list_info_type *list = head;
+ file_info_type *current_hll_file = (file_info_type *) NULL;
+ char *message;
+ char *buffer;
+ char *p;
+ int show_listing = 1;
+ unsigned int width;
+
+ buffer = xmalloc (LISTING_RHS_WIDTH);
+ eject = 1;
+ list = head;
+
+ while (list != (list_info_type *) NULL && 0)
+ {
+ if (list->next)
+ list->frag = list->next->frag;
+ list = list->next;
+
+ }
+
+ list = head->next;
+
+
+ while (list)
+ {
+ width = LISTING_RHS_WIDTH > paper_width ? paper_width :
+ LISTING_RHS_WIDTH;
+
+ switch (list->edict)
+ {
+ case EDICT_LIST:
+ show_listing++;
+ break;
+ case EDICT_NOLIST:
+ show_listing--;
+ break;
+ case EDICT_EJECT:
+ break;
+ case EDICT_NONE:
+ break;
+ case EDICT_TITLE:
+ title = list->edict_arg;
+ break;
+ case EDICT_SBTTL:
+ subtitle = list->edict_arg;
+ break;
+ default:
+ abort ();
+ }
+
+ if (show_listing > 0)
+ {
+ /* Scan down the list and print all the stuff which can be done
+ with this line (or lines). */
+ message = 0;
+
+ if (list->hll_file)
+ {
+ current_hll_file = list->hll_file;
+ }
+
+ if (current_hll_file && list->hll_line && listing & LISTING_HLL)
+ {
+ print_source (current_hll_file, list, buffer, width);
+ }
+
+ while (list->file->file &&
+ list->file->linenum < list->line && !list->file->end_pending) {
+ p = buffer_line (list->file, buffer, width);
+
+ if (!((listing & LISTING_NODEBUG) && debugging_pseudo (p)))
+ {
+ print_lines (list, p, calc_hex (list));
+ }
+ }
+
+ if (list->edict == EDICT_EJECT)
+ {
+ eject = 1;
+ }
+ }
+ else
+ {
+
+ while (list->file->file &&
+ list->file->linenum < list->line && !list->file->end_pending)
+ p = buffer_line (list->file, buffer, width);
+ }
+
+ list = list->next;
+ }
+ free (buffer);
+}
+
+void
+listing_print (name)
+ char *name;
+{
+ title = "";
+ subtitle = "";
+
+ if (listing & LISTING_NOFORM)
+ {
+ paper_height = 0;
+ }
+
+ if (listing & LISTING_LISTING)
+ {
+ listing_listing (name);
+
+ }
+ if (listing & LISTING_SYMBOLS)
+ {
+ list_symbol_table ();
+ }
+}
+
+
+void
+listing_file (name)
+ const char *name;
+{
+ fn = name;
+}
+
+void
+listing_eject (ignore)
+ int ignore;
+{
+ listing_tail->edict = EDICT_EJECT;
+}
+
+void
+listing_flags (ignore)
+ int ignore;
+{
+ while ((*input_line_pointer++) && (*input_line_pointer != '\n'))
+ input_line_pointer++;
+
+}
+
+void
+listing_list (on)
+ int on;
+{
+ listing_tail->edict = on ? EDICT_LIST : EDICT_NOLIST;
+}
+
+
+void
+listing_psize (ignore)
+ int ignore;
+{
+ paper_height = get_absolute_expression ();
+
+ if (paper_height < 0 || paper_height > 1000)
+ {
+ paper_height = 0;
+ as_warn ("strange paper height, set to no form");
+ }
+ if (*input_line_pointer == ',')
+ {
+ input_line_pointer++;
+ paper_width = get_absolute_expression ();
+ }
+}
+
+
+void
+listing_title (depth)
+ int depth;
+{
+ char *start;
+ char *ttl;
+ unsigned int length;
+
+ SKIP_WHITESPACE ();
+ if (*input_line_pointer == '\"')
+ {
+ input_line_pointer++;
+ start = input_line_pointer;
+
+ while (*input_line_pointer)
+ {
+ if (*input_line_pointer == '\"')
+ {
+ length = input_line_pointer - start;
+ ttl = xmalloc (length + 1);
+ memcpy (ttl, start, length);
+ ttl[length] = 0;
+ listing_tail->edict = depth ? EDICT_SBTTL : EDICT_TITLE;
+ listing_tail->edict_arg = ttl;
+ input_line_pointer++;
+ demand_empty_rest_of_line ();
+ return;
+ }
+ else if (*input_line_pointer == '\n')
+ {
+ as_bad ("New line in title");
+ demand_empty_rest_of_line ();
+ return;
+ }
+ else
+ {
+ input_line_pointer++;
+ }
+ }
+ }
+ else
+ {
+ as_bad ("expecting title in quotes");
+ }
+}
+
+
+
+void
+listing_source_line (line)
+ unsigned int line;
+{
+ new_frag ();
+ listing_tail->hll_line = line;
+ new_frag ();
+
+}
+
+void
+listing_source_file (file)
+ const char *file;
+{
+ if (listing_tail)
+ listing_tail->hll_file = file_info (file);
+}
+
+
+
+#else
+
+
+/* Dummy functions for when compiled without listing enabled */
+
+void
+listing_flags (ignore)
+ int ignore;
+{
+ s_ignore (0);
+}
+
+void
+listing_list (on)
+ int on;
+{
+ s_ignore (0);
+}
+
+void
+listing_eject (ignore)
+ int ignore;
+{
+ s_ignore (0);
+}
+
+void
+listing_psize (ignore)
+ int ignore;
+{
+ s_ignore (0);
+}
+
+void
+listing_title (depth)
+ int depth;
+{
+ s_ignore (0);
+}
+
+void
+listing_file (name)
+ const char *name;
+{
+
+}
+
+void
+listing_newline (name)
+ char *name;
+{
+
+}
+
+void
+listing_source_line (n)
+ unsigned int n;
+{
+
+}
+void
+listing_source_file (n)
+ const char *n;
+{
+
+}
+
+#endif
diff --git a/gnu/usr.bin/as/listing.h b/gnu/usr.bin/as/listing.h
new file mode 100644
index 0000000..2220c35
--- /dev/null
+++ b/gnu/usr.bin/as/listing.h
@@ -0,0 +1,115 @@
+/* This file is listing.h
+ Copyright (C) 1987, 1988, 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
+
+ This file is part of GAS, the GNU Assembler.
+
+ GAS is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GAS is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GAS; see the file COPYING. If not, write to
+ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/*
+ * $Id: listing.h,v 1.1 1993/11/03 00:51:56 paul Exp $
+ */
+
+#ifndef __listing_h__
+#define __listing_h__
+
+#define LISTING_LISTING 1
+#define LISTING_SYMBOLS 2
+#define LISTING_NOFORM 4
+#define LISTING_HLL 8
+#define LISTING_NODEBUG 16
+
+#define LISTING_DEFAULT (LISTING_LISTING | LISTING_HLL | LISTING_SYMBOLS)
+
+#ifndef NO_LISTING
+#define LISTING_NEWLINE() { if (listing) listing_newline(input_line_pointer); }
+#else
+#define LISTING_NEWLINE() {;}
+#endif
+
+
+/* This structure remembers which .s were used */
+typedef struct file_info_struct
+{
+ char *filename;
+ int linenum;
+ FILE *file;
+ struct file_info_struct *next;
+ int end_pending;
+
+}
+
+file_info_type;
+
+
+/* this structure rememebrs which line from which file goes into which
+ frag */
+typedef struct list_info_struct
+{
+ /* Frag which this line of source is nearest to */
+ fragS *frag;
+ /* The actual line in the source file */
+ unsigned int line;
+ /* Pointer to the file info struct for the file which this line
+ belongs to */
+ file_info_type *file;
+
+ /* Next in list */
+ struct list_info_struct *next;
+
+
+ /* Pointer to the file info struct for the high level language
+ source line that belongs here */
+ file_info_type *hll_file;
+
+ /* High level language source line */
+ int hll_line;
+
+
+ /* Pointer to any error message associated with this line */
+ char *message;
+
+ enum
+ {
+ EDICT_NONE,
+ EDICT_SBTTL,
+ EDICT_TITLE,
+ EDICT_NOLIST,
+ EDICT_LIST,
+ EDICT_EJECT
+ } edict;
+ char *edict_arg;
+
+}
+
+list_info_type;
+
+void listing_eject PARAMS ((int));
+void listing_error PARAMS ((const char *message));
+void listing_file PARAMS ((const char *name));
+void listing_flags PARAMS ((int));
+void listing_list PARAMS ((int on));
+void listing_newline PARAMS ((char *ps));
+void listing_prev_line PARAMS ((void));
+void listing_print PARAMS ((char *name));
+void listing_psize PARAMS ((int));
+void listing_source_file PARAMS ((const char *));
+void listing_source_line PARAMS ((unsigned int));
+void listing_title PARAMS ((int depth));
+void listing_warning PARAMS ((const char *message));
+void listing_width PARAMS ((unsigned int x));
+
+#endif /* __listing_h__ */
+
+/* end of listing.h */
diff --git a/gnu/usr.bin/as/make-gas.com b/gnu/usr.bin/as/make-gas.com
new file mode 100644
index 0000000..cb3064d
--- /dev/null
+++ b/gnu/usr.bin/as/make-gas.com
@@ -0,0 +1,86 @@
+$! Set the def dir to proper place for use in batch. Works for interactive to.
+$flnm = f$enviroment("PROCEDURE") ! get current procedure name
+$set default 'f$parse(flnm,,,"DEVICE")''f$parse(flnm,,,"DIRECTORY")'
+$!
+$! Command file to build a GNU assembler on VMS
+$!
+$! If you are using a version of GCC that supports global constants
+$! you should remove the define="const=" from the gcc lines.
+$!
+$! Caution: Versions 1.38.1 and earlier had a bug in the handling of
+$! some static constants. If you are using such a version of the
+$! assembler, and you wish to compile without the "const=" hack,
+$! you should first build this version *with* the "const="
+$! definition, and then use that assembler to rebuild it without the
+$! "const=" definition. Failure to do this will result in an assembler
+$! that will mung floating point constants.
+$!
+$! Note: The version of gas shipped on the GCC VMS tapes has been patched
+$! to fix the above mentioned bug.
+$!
+$ write sys$output "If this assembler is going to be used with GCC 1.n, you"
+$ write sys$Output "need to modify the driver to supply the -1 switch to gas."
+$ write sys$output "This is required because of a small change in how global"
+$ write sys$Output "constant variables are handled. Failure to include this"
+$ write sys$output "will result in linker warning messages about mismatched
+$ write sys$output "psect attributes."
+$!
+$ C_DEFS :="""VMS"""
+$! C_DEFS :="""VMS""","""const="""
+$ C_INCLUDES :=/include=([],[.config],[-.include])
+$ C_FLAGS := /debug 'c_includes'
+$!
+$!
+$ if "''p1'" .eqs. "LINK" then goto Link
+$!
+$! This helps gcc 1.nn find the aout/* files.
+$!
+$ aout_dev = f$parse(flnm,,,"DEVICE")
+$ tmp = aout_dev - ":"
+$if f$trnlnm(tmp).nes."" then aout_dev = f$trnlnm(tmp)
+$ aout_dir = aout_dev+f$parse(flnm,,,"DIRECTORY")' -
+ - "GAS]" + "INCLUDE.AOUT.]" - "]["
+$assign 'aout_dir' aout/tran=conc
+$ opcode_dir = aout_dev+f$parse(flnm,,,"DIRECTORY")' -
+ - "GAS]" + "INCLUDE.OPCODE.]" - "]["
+$assign 'opcode_dir' opcode/tran=conc
+$!
+$ gcc 'c_flags'/define=('C_DEFS') as.c
+$ gcc 'c_flags'/define=("error=as_fatal",'C_DEFS') xrealloc.c
+$ gcc 'c_flags'/define=("error=as_fatal",'C_DEFS') xmalloc.c
+$ gcc 'c_flags'/define=("error=as_fatal",'C_DEFS') hash.c
+$ gcc 'c_flags'/define=('C_DEFS') obstack.c
+$ gcc 'c_flags'/define=('C_DEFS') hex-value.c
+$ gcc 'c_flags'/define=('C_DEFS') messages.c
+$ gcc 'c_flags'/define=('C_DEFS') atof-generic.c
+$ gcc 'c_flags'/define=('C_DEFS') expr.c
+$ gcc 'c_flags'/define=('C_DEFS') cond.c
+$ gcc 'c_flags'/define=('C_DEFS') app.c
+$ gcc 'c_flags'/define=('C_DEFS') frags.c
+$ gcc 'c_flags'/define=('C_DEFS') input-file.c
+$ gcc 'c_flags'/define=('C_DEFS') input-scrub.c
+$ gcc 'c_flags'/define=('C_DEFS') output-file.c
+$ gcc 'c_flags'/define=('C_DEFS') read.c
+$ gcc 'c_flags'/define=('C_DEFS') subsegs.c
+$ gcc 'c_flags'/define=('C_DEFS') symbols.c
+$ gcc 'c_flags'/define=('C_DEFS') write.c
+$ gcc 'c_flags'/define=('C_DEFS') version.c
+$ gcc 'c_flags'/define=('C_DEFS') flonum-const.c
+$ gcc 'c_flags'/define=('C_DEFS') flonum-copy.c
+$ gcc 'c_flags'/define=('C_DEFS') flonum-mult.c
+$ gcc 'c_flags'/define=('C_DEFS') strstr.c
+$ gcc 'c_flags'/define=('C_DEFS') bignum-copy.c
+$ gcc 'c_flags'/define=('C_DEFS') listing.c
+$ gcc 'c_flags'/define=('C_DEFS') atof-targ.c
+$ gcc 'c_flags'/define=("error=as_fatal",'C_DEFS') targ-cpu.c
+$ gcc 'c_flags'/define=("error=as_fatal",'C_DEFS') obj-format.c
+$ Link:
+$ link/nomap/exec=gcc-as version.opt/opt+sys$input:/opt
+!
+! Linker options file for GNU assembler
+!
+as,xrealloc,xmalloc,hash,hex-value,atof-generic,messages,expr,app,cond,-
+frags,input-file,input-scrub,output-file,read,subsegs,symbols,write,-
+version,flonum-const,flonum-copy,flonum-mult,strstr,bignum-copy,listing,-
+obstack,targ-cpu,atof-targ,obj-format,-
+gnu_cc:[000000]gcclib/lib,sys$share:vaxcrtl/lib
diff --git a/gnu/usr.bin/as/makefile.dos b/gnu/usr.bin/as/makefile.dos
new file mode 100644
index 0000000..89c74c7
--- /dev/null
+++ b/gnu/usr.bin/as/makefile.dos
@@ -0,0 +1,593 @@
+# Makefile for GNU Assembler
+# Copyright (C) 1987, 1988, 1990, 1991 Free Software Foundation, Inc.
+
+#This file is part of GNU GAS.
+
+#GNU GAS is free software; you can redistribute it and/or modify
+#it under the terms of the GNU General Public License as published by
+#the Free Software Foundation; either version 1, or (at your option)
+#any later version.
+
+#GNU GAS is distributed in the hope that it will be useful,
+#but WITHOUT ANY WARRANTY; without even the implied warranty of
+#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+#GNU General Public License for more details.
+
+#You should have received a copy of the GNU General Public License
+#along with GNU GAS; see the file COPYING. If not, write to
+#the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+# $Id: makefile.dos,v 1.1 1993/10/02 20:57:43 pk Exp $
+
+# The targets for external use include:
+# all, doc, proto, install, uninstall, includes, TAGS,
+# clean, cleanconfig, realclean, stage1, stage2, stage3, stage4.
+
+# Variables that exist for you to override.
+# See below for how to change them for certain systems.
+
+LIBDEPS=
+CROSS=
+HDEFINES=
+CPPFLAGS=
+
+ALLOCA =
+CFLAGS = -g -D__MSDOS__ -D__GO32__ -I../include
+INTERNAL_CFLAGS = $(CROSS)
+OLDCC = cc
+BISON = bison
+BISONFLAGS = -v
+AR = ar
+OLDAR_FLAGS = qc
+AR_FLAGS = rc
+SHELL = /bin/sh
+# on sysV, define this as cp.
+INSTALL = install -c
+# These permit overriding just for certain files.
+INSTALL_PROGRAM = $(INSTALL)
+INSTALL_FILE = $(INSTALL)
+
+# Define this as & to perform parallel make on a Sequent.
+# Note that this has some bugs, and it seems currently necessary
+# to compile all the gen* files first by hand to avoid erroneous results.
+P =
+
+# How to invoke ranlib.
+RANLIB = ranlib
+# Test to use to see whether ranlib exists on the system.
+RANLIB_TEST = [ -f /usr/bin/ranlib -o -f /bin/ranlib ]
+
+# CFLAGS for use with OLDCC, for compiling gnulib.
+# NOTE: -O does not work on some Unix systems!
+CCLIBFLAGS = -O
+
+# Version of ar to use when compiling gnulib.
+OLDAR = ar
+
+version=`$(unsubdir)/../gcc$(subdir)/gcc -dumpversion`
+
+# Directory where sources are, from where we are.
+srcdir = .
+# Common prefix for installation directories.
+# NOTE: This directory must exist when you start installation.
+ddestdir = /usr/local
+# Directory in which to put the executable for the command `gcc'
+bindir = $(ddestdir)/bin
+# Directory in which to put the directories used by the compiler.
+libdir = $(ddestdir)/lib
+# Directory in which the compiler finds executables, libraries, etc.
+libsubdir = $(libdir)/gcc/$(target_alias)/$(version)
+# Number to put in man-page filename.
+manext = 1
+# Directory in which to put man pages.
+mandir = $(destdir)/H-independent/man/man$(manext)
+
+# Additional system libraries to link with.
+CLIB=
+
+# Specify the rule for actually making gnulib.
+GNULIB = gnulib.portable
+
+# Specify the rule for actually making gnulib2.
+GNULIB2 = gnulib2.portable
+
+# List of extra C and assembler files to add to gnulib.
+# Assembler files should have names ending in `.asm'.
+LIBFUNCS_EXTRA =
+
+# Program to convert libraries.
+LIBCONVERT =
+
+# Control whether header files are installed.
+INSTALL_HEADERS=install-headers
+
+# Change this to empty to prevent installing limits.h
+LIMITS_H = limits.h
+
+# Directory to link to, when using the target `maketest'.
+DIR = ../gcc
+
+# For better debugging under COFF, define SEPARATE_AUX_OUTPUT in config.h
+# and define the following variable as `aux-output2.c' in make-...
+AUX_OUTPUT2 =
+
+# Flags to use when cross-building GCC.
+# Prefix to apply to names of object files when using them
+# to run on the machine we are compiling on.
+HOST_PREFIX=
+# Prefix to apply to names of object files when compiling them
+# to run on the machine we are compiling on.
+# The default for this variable is chosen to keep these rules
+# out of the way of the other rules for compiling the same source files.
+HOST_PREFIX_1=loser-
+HOST_CC=$(CC)
+HOST_CFLAGS=$(ALL_CFLAGS)
+HOST_LDFLAGS=$(LDFLAGS)
+HOST_CPPFLAGS=$(CPPFLAGS)
+
+# Choose the real default target.
+ALL=as.new
+
+# End of variables for you to override.
+
+# Lists of files for various purposes.
+
+REAL_SOURCES = \
+ app.c \
+ as.c \
+ atof-generic.c \
+ bignum-copy.c \
+ cond.c \
+ expr.c \
+ fn-const.c \
+ fn-copy.c \
+ flonum-mult.c \
+ frags.c \
+ hash.c \
+ hex-value.c \
+ input-file.c \
+ input-scrub.c \
+ messages.c \
+ output-file.c \
+ read.c \
+ strstr.c \
+ subsegs.c \
+ symbols.c \
+ version.c \
+ write.c \
+ xmalloc.c \
+ xrealloc.c
+
+# in an expedient order
+LINKED_SOURCES = \
+ targ-cpu.c \
+ obj-format.c \
+ atof-targ.c
+
+SOURCES = $(LINKED_SOURCES) $(REAL_SOURCES)
+
+REAL_HEADERS = \
+ as.h \
+ bignum.h \
+ expr.h \
+ flonum.h \
+ frags.h \
+ hash.h \
+ input-file.h \
+ tc.h \
+ obj.h \
+ read.h \
+ struc-symbol.h \
+ subsegs.h \
+ symbols.h \
+ syscalls.h \
+ write.h
+
+LINKED_HEADERS = \
+ a.out.gnu.h \
+ a.out.h \
+ host.h \
+ targ-env.h \
+ targ-cpu.h \
+ obj-format.h \
+ atof-targ.h
+
+HEADERS = $(LINKED_HEADERS) $(REAL_HEADERS)
+
+OBJS = \
+ targ-cpu.o \
+ obj-format.o \
+ atof-targ.o \
+ app.o \
+ as.o \
+ atof-generic.o \
+ bignum-copy.o \
+ cond.o \
+ expr.o \
+ fn-const.o \
+ fn-copy.o \
+ flonum-mult.o \
+ frags.o \
+ hash.o \
+ hex-value.o \
+ input-file.o \
+ input-scrub.o \
+ messages.o \
+ output-file.o \
+ read.o \
+ strstr.o \
+ subsegs.o \
+ symbols.o \
+ version.o \
+ write.o \
+ xmalloc.o \
+ xrealloc.o
+
+#### host, target, and site specific Makefile frags come in here.
+TARG_CPU_DEPENDENTS=../include/h8300-opcode.h
+LOCAL_LOADLIBES=../bfd/libbfd.a
+TDEFINES=-DBFD -DBFD_HEADERS -DMANY_SEGMENTS
+
+
+# Definition of `all' is here so that new rules inserted by sed
+# do not specify the default target.
+# The real definition is under `all.internal'.
+
+all: $(ALL)
+all-info:
+install-info:
+
+fake-as: force
+ - rm -f ./as.new
+ cp /bin/as ./fake-as
+
+# Now figure out from those variables how to compile and link.
+
+# This is the variable actually used when we compile.
+ALL_CFLAGS = $(INTERNAL_CFLAGS) $(CFLAGS) $(HDEFINES) $(TDEFINES)
+
+# Even if ALLOCA is set, don't use it if compiling with GCC.
+USE_ALLOCA= `if [ x"${CC}" = x"${OLDCC}" ] ; then echo ${ALLOCA}; else true; fi`
+USE_HOST_ALLOCA= `if [ x"${CC}" = x"${OLDCC}" ] ; then echo ${HOST_PREFIX}${ALLOCA}; else true; fi`
+
+# Likewise, for use in the tools that must run on this machine
+# even if we are cross-building GCC.
+# We don't use USE_ALLOCA because backquote expansion doesn't work in deps.
+HOST_LIBDEPS= $(HOST_PREFIX)$(OBSTACK) $(HOST_PREFIX)$(ALLOCA) $(HOST_PREFIX)$(MALLOC)
+
+# How to link with both our special library facilities
+# and the system's installed libraries.
+
+LIBS = $(LOCAL_LOADLIBES) $(CLIB) $(unsubdir)/../libiberty$(subdir)/libiberty.a
+
+# Likewise, for use in the tools that must run on this machine
+# even if we are cross-building GCC.
+HOST_LIBS = $(HOST_PREFIX)$(OBSTACK) $(USE_HOST_ALLOCA) $(HOST_PREFIX)$(MALLOC) $(CLIB)
+
+# Specify the directories to be searched for header files.
+# Both . and srcdir are used, in that order,
+# so that tm.h and config.h will be found in the compilation
+# subdirectory rather than in the source directory.
+INCLUDES = -I. -I$(srcdir) -Iconfig
+SUBDIR_INCLUDES = -I.. -I../$(srcdir) -I../config
+
+# Always use -Iconfig when compiling.
+.c.o:
+ $(CC) -c $(ALL_CFLAGS) $(CPPFLAGS) $(INCLUDES) $<
+
+# This tells GNU make version 3 not to export all the variables
+# defined in this file into the environment.
+.NOEXPORT:
+
+# Files to be copied away after each stage in building.
+STAGE_GCC=gcc
+STAGESTUFF = *.o as.new
+
+# The files that "belong" in CONFIG_H are deliberately omitted
+# because having them there would not be useful in actual practice.
+# All they would do is cause complete recompilation every time
+# one of the machine description files is edited.
+# That may or may not be what one wants to do.
+# If it is, rm *.o is an easy way to do it.
+# CONFIG_H = config.h tm.h
+CONFIG_H =
+
+as.new: $(OBJS) $(LIBDEPS)
+ -mv -f as.new as.old
+ >as.rf $(ALL_CFLAGS) $(LDFLAGS) -o as.new $(OBJS) $(LIBS) $(LOADLIBES)
+ $(CC) @as.rf
+
+objdump:
+
+all.internal: native
+# This is what is made with the host's compiler if making a cross assembler.
+native: config.status as
+
+config.status:
+ @echo You must configure gas. Look at the INSTALL file for details.
+ @false
+
+compilations: ${OBJS}
+
+# Compiling object files from source files.
+
+app.o : app.c as.h host.h targ-env.h obj-format.h \
+ targ-cpu.h struc-symbol.h \
+ write.h flonum.h bignum.h expr.h frags.h hash.h read.h symbols.h tc.h obj.h
+as.o : as.c as.h host.h targ-env.h obj-format.h \
+ targ-cpu.h struc-symbol.h \
+ write.h flonum.h bignum.h expr.h frags.h hash.h read.h symbols.h tc.h obj.h
+atof-generic.o : atof-generic.c as.h host.h targ-env.h obj-format.h \
+ targ-cpu.h struc-symbol.h \
+ write.h flonum.h bignum.h expr.h frags.h hash.h read.h symbols.h tc.h obj.h
+bignum-copy.o : bignum-copy.c as.h host.h \
+ targ-env.h obj-format.h \
+ targ-cpu.h struc-symbol.h \
+ write.h flonum.h bignum.h expr.h frags.h hash.h read.h symbols.h tc.h obj.h
+cond.o : cond.c as.h host.h targ-env.h obj-format.h \
+ targ-cpu.h struc-symbol.h \
+ write.h flonum.h bignum.h expr.h frags.h hash.h read.h symbols.h tc.h obj.h \
+
+debug.o : debug.c as.h host.h targ-env.h obj-format.h \
+ targ-cpu.h struc-symbol.h \
+ write.h flonum.h bignum.h expr.h frags.h hash.h read.h symbols.h tc.h obj.h \
+ subsegs.h
+expr.o : expr.c as.h host.h targ-env.h obj-format.h \
+ targ-cpu.h struc-symbol.h \
+ write.h flonum.h bignum.h expr.h frags.h hash.h read.h symbols.h tc.h obj.h \
+
+fn-const.o : fn-const.c flonum.h bignum.h
+fn-copy.o : fn-copy.c as.h host.h targ-env.h obj-format.h \
+ targ-cpu.h struc-symbol.h \
+ write.h flonum.h bignum.h expr.h frags.h hash.h read.h symbols.h tc.h obj.h
+flonum-mult.o : flonum-mult.c flonum.h bignum.h
+frags.o : frags.c as.h host.h targ-env.h obj-format.h \
+ targ-cpu.h struc-symbol.h \
+ write.h flonum.h bignum.h expr.h frags.h hash.h read.h symbols.h tc.h obj.h \
+ subsegs.h
+hash.o : hash.c as.h host.h targ-env.h obj-format.h \
+ targ-cpu.h struc-symbol.h \
+ write.h flonum.h bignum.h expr.h frags.h hash.h read.h symbols.h tc.h obj.h
+hex-value.o : hex-value.c
+input-file.o : input-file.c as.h host.h \
+ targ-env.h obj-format.h targ-cpu.h \
+ struc-symbol.h write.h flonum.h bignum.h expr.h \
+ frags.h hash.h read.h symbols.h tc.h obj.h input-file.h
+input-scrub.o : input-scrub.c \
+ as.h host.h targ-env.h obj-format.h \
+ targ-cpu.h struc-symbol.h \
+ write.h flonum.h bignum.h expr.h frags.h hash.h read.h symbols.h tc.h obj.h \
+ input-file.h
+messages.o : messages.c as.h host.h targ-env.h obj-format.h \
+ targ-cpu.h struc-symbol.h \
+ write.h flonum.h bignum.h expr.h frags.h hash.h read.h symbols.h tc.h obj.h
+obstack.o : obstack.c
+output-file.o : output-file.c as.h host.h targ-env.h obj-format.h \
+ targ-cpu.h struc-symbol.h \
+ write.h flonum.h bignum.h expr.h frags.h hash.h read.h symbols.h tc.h obj.h \
+ output-file.h
+read.o : read.c as.h host.h targ-env.h obj-format.h \
+ targ-cpu.h struc-symbol.h \
+ write.h flonum.h bignum.h expr.h frags.h hash.h read.h symbols.h tc.h obj.h \
+
+strstr.o : strstr.c
+subsegs.o : subsegs.c as.h host.h targ-env.h obj-format.h \
+ targ-cpu.h struc-symbol.h \
+ write.h flonum.h bignum.h expr.h frags.h hash.h read.h symbols.h tc.h obj.h \
+ subsegs.h
+symbols.o : symbols.c as.h host.h targ-env.h obj-format.h \
+ targ-cpu.h struc-symbol.h \
+ write.h flonum.h bignum.h expr.h frags.h hash.h read.h symbols.h tc.h obj.h \
+ subsegs.h
+version.o : version.c
+write.o : write.c as.h host.h targ-env.h obj-format.h \
+ targ-cpu.h struc-symbol.h \
+ write.h flonum.h bignum.h expr.h frags.h hash.h read.h symbols.h tc.h obj.h \
+ subsegs.h output-file.h
+xmalloc.o : xmalloc.c
+xrealloc.o : xrealloc.c
+atof-targ.o : atof-targ.c as.h host.h targ-env.h obj-format.h \
+ targ-cpu.h struc-symbol.h \
+ write.h flonum.h bignum.h expr.h frags.h hash.h read.h \
+ symbols.h tc.h obj.h
+obj-format.o : obj-format.c as.h host.h targ-env.h obj-format.h \
+ targ-cpu.h struc-symbol.h \
+ write.h flonum.h bignum.h expr.h frags.h hash.h read.h \
+ symbols.h tc.h obj.h
+targ-cpu.o : targ-cpu.c targ-env.h obj-format.h \
+ targ-cpu.h struc-symbol.h \
+ write.h flonum.h bignum.h expr.h frags.h hash.h read.h \
+ symbols.h tc.h obj.h $(TARG_CPU_DEPENDENTS)
+
+
+# Compile the libraries to be used by gen*.
+# If we are not cross-building, gen* use the same .o's that cc1 will use,
+# and HOST_PREFIX_1 is `foobar', just to ensure these rules don't conflict
+# with the rules for rtl.o, alloca.o, etc.
+$(HOST_PREFIX_1)alloca.o: alloca.c
+ rm -f $(HOST_PREFIX)alloca.c
+ cp alloca.c $(HOST_PREFIX)alloca.c
+ $(HOST_CC) -c $(HOST_CFLAGS) $(HOST_CPPFLAGS) $(INCLUDES) $(HOST_PREFIX)alloca.c
+
+$(HOST_PREFIX_1)obstack.o: obstack.c
+ rm -f $(HOST_PREFIX)obstack.c
+ cp obstack.c $(HOST_PREFIX)obstack.c
+ $(HOST_CC) -c $(HOST_CFLAGS) $(HOST_CPPFLAGS) $(INCLUDES) $(HOST_PREFIX)obstack.c
+
+$(HOST_PREFIX_1)malloc.o: malloc.c
+ rm -f $(HOST_PREFIX)malloc.c
+ cp malloc.c $(HOST_PREFIX)malloc.c
+ $(HOST_CC) -c $(HOST_CFLAGS) $(HOST_CPPFLAGS) $(INCLUDES) $(HOST_PREFIX)malloc.c
+
+# Remake the info files.
+
+doc: as.info
+
+as.info: doc/as.texinfo
+ (cd doc; make as.info; mv as.info $srcdir)
+
+
+# Deletion of files made during compilation.
+# There are three levels of this: `clean', `cleanconfig' and `realclean'.
+# `clean' deletes what you want to delete ordinarily to save space.
+# This is most, but not all, of the files made by compilation.
+# `cleanconfig' also deletes everything depending
+# on the choice of config files.
+# `realclean' also deletes everything that could be regenerated automatically.
+
+clean:
+ -rm -f $(STAGESTUFF)
+# Delete the temporary source copies for cross compilation.
+ -rm -f $(HOST_PREFIX_1)alloca.c $(HOST_PREFIX_1)malloc.c
+ -rm -f $(HOST_PREFIX_1)obstack.c
+# Delete the stamp files except stamp-gnulib2.
+ -rm -f core
+
+# Like clean but also delete the links made to configure gas.
+cleanconfig: clean
+ -rm -f config.status Makefile host.h targ-env.h
+ -rm -f targ-cpu.h targ-cpu.c
+ -rm -f obj-format.h obj-format.c
+ -rm -f atof-targ.c
+
+# Get rid of every file that's generated from some other file (except INSTALL).
+realclean: cleanconfig
+ -rm -f gas.aux gas.cps gas.fns gas.info gas.kys gas.pgs gas.tps gas.vrs
+ -rm -f TAGS
+ -rm -f gas.info* gas.?? gas.??s gas.log gas.toc gas.*aux
+ -rm -f *.dvi
+
+# Entry points `install', `includes' and `uninstall'.
+
+# Copy the files into directories where they will be run.
+install: $(ALL)
+ $(INSTALL_PROGRAM) $(ALL) $(libsubdir)/as
+# cp $(ALL) $(bindir)/as.new
+# mv -f $(bindir)/as.new $(bindir)/as
+
+# Create the installation directory.
+install-dir:
+ -mkdir $(libdir)
+ -mkdir $(libdir)/gcc
+ -mkdir $(libdir)/gcc/$(target)
+ -mkdir $(libdir)/gcc/$(target)/$(version)
+
+# Install the compiler executables built during cross compilation.
+install-cross: native install-dir
+ -if [ -f cc1 ] ; then $(INSTALL_PROGRAM) cc1 $(libsubdir)/cc1; else true; fi
+ -if [ -f cc1plus ] ; then $(INSTALL_PROGRAM) cc1plus $(libsubdir)/cc1plus; else true; fi
+ $(INSTALL_PROGRAM) cpp $(libsubdir)/cpp
+ ./gcc -dumpspecs > $(libsubdir)/specs
+ $(INSTALL_PROGRAM) gcc $(bindir)/gcc
+
+# Install the man pages.
+install-man: install-dir gcc.1 protoize.1 unprotoize.1
+ $(INSTALL_FILE) gcc.1 $(mandir)/gcc.$(manext)
+ chmod a-x $(mandir)/gcc.$(manext)
+ $(INSTALL_FILE) protoize.1 $(mandir)/protoize.$(manext)
+ chmod a-x $(mandir)/protoize.$(manext)
+ $(INSTALL_FILE) unprotoize.1 $(mandir)/unprotoize.$(manext)
+ chmod a-x $(mandir)/unprotoize.$(manext)
+
+# Cancel installation by deleting the installed files.
+uninstall:
+ -rm -rf $(libsubdir)
+ -rm -rf $(bindir)/as
+ -rm -rf $(mandir)/gas.$(manext)
+
+
+# These exist for maintenance purposes.
+
+tags TAGS: force
+ etags $(REAL_SOURCES) $(REAL_HEADERS) README Makefile config/*.[hc]
+
+bootstrap: $(ALL) force
+ $(MAKE) stage1
+ $(MAKE) CC="$(CC)" CFLAGS="-O -Bstage1/ $(CFLAGS)" libdir=$(libdir) ALLOCA= $(ALL)
+ $(MAKE) stage2
+ $(MAKE) CC="$(CC)" CFLAGS="-O -Bstage2/ $(CFLAGS)" libdir=$(libdir) ALLOCA= $(ALL)
+ $(MAKE) comparison against=stage2
+
+bootstrap2: force
+ $(MAKE) CC="$(CC)" CFLAGS="-O -Bstage1/ $(CFLAGS)" libdir=$(libdir) ALLOCA= $(ALL)
+ $(MAKE) stage2
+ $(MAKE) CC="$(CC)" CFLAGS="-O -Bstage2/ $(CFLAGS)" libdir=$(libdir) ALLOCA= $(ALL)
+ $(MAKE) comparison against=stage2
+
+bootstrap3: force
+ $(MAKE) CC="$(CC)" CFLAGS="-O -Bstage2/ $(CFLAGS)" libdir=$(libdir) ALLOCA= $(ALL)
+ $(MAKE) comparison against=stage2
+
+# Copy the object files from a particular stage into a subdirectory.
+stage1: force
+ -mkdir stage1
+ -mv $(STAGESTUFF) stage1
+ if [ -f stage1/as.new -a ! -f stage1/as ] ; then (cd stage1 ; ln -s as.new as) ; fi
+
+stage2: force
+ -mkdir stage2
+ -mv $(STAGESTUFF) stage2
+ if [ -f stage2/as.new -a ! -f stage2/as ] ; then (cd stage2 ; ln -s as.new as) ; fi
+
+stage3: force
+ -mkdir stage3
+ -mv $(STAGESTUFF) stage3
+ if [ -f stage3/as.new -a ! -f stage3/as ] ; then (cd stage3 ; ln -s as.new as) ; fi
+
+against=stage2
+
+comparison: force
+ for i in $(STAGESTUFF) ; do cmp $$i $(against)/$$i ; done
+
+de-stage1: force
+ - (cd stage1 ; rm as ; mv -f * ..)
+ - rmdir stage1
+
+de-stage2: force
+ - (cd stage2 ; rm as ; mv -f * ..)
+ - rmdir stage2
+
+de-stage3: force
+ - (cd stage3 ; rm as ; mv -f * ..)
+ - rmdir stage3
+
+# Copy just the executable files from a particular stage into a subdirectory,
+# and delete the object files. Use this if you're just verifying a version
+# that is pretty sure to work, and you are short of disk space.
+risky-stage1: force
+ -mkdir stage1
+ -mv cc1 cpp cccp gcc stage1
+ -rm -f stage1/gnulib
+ -cp gnulib stage1 && $(RANLIB) stage1/gnulib
+ -make clean
+
+risky-stage2: force
+ -mkdir stage2
+ -mv cc1 cpp cccp gcc stage2
+ -rm -f stage2/gnulib
+ -cp gnulib stage2 && $(RANLIB) stage2/gnulib
+ -make clean
+
+risky-stage3: force
+ -mkdir stage3
+ -mv cc1 cpp cccp gcc stage3
+ -rm -f stage3/gnulib
+ -cp gnulib stage3 && $(RANLIB) stage3/gnulib
+ -make clean
+
+risky-stage4: force
+ -mkdir stage4
+ -mv cc1 cpp cccp gcc stage4
+ -rm -f stage4/gnulib
+ -cp gnulib stage4 && $(RANLIB) stage4/gnulib
+ -make clean
+
+#In GNU Make, ignore whether `stage*' exists.
+.PHONY: stage1 stage2 stage3 stage4 clean realclean TAGS bootstrap
+.PHONY: risky-stage1 risky-stage2 risky-stage3 risky-stage4
+
+force:
+
+Makefile: Makefile.in $(host_makefile_frag) $(target_makefile_frag)
+ $(SHELL) ./config.status
+
diff --git a/gnu/usr.bin/as/messages.c b/gnu/usr.bin/as/messages.c
new file mode 100644
index 0000000..55e97d9
--- /dev/null
+++ b/gnu/usr.bin/as/messages.c
@@ -0,0 +1,595 @@
+/* messages.c - error reporter -
+ Copyright (C) 1987, 1991, 1992 Free Software Foundation, Inc.
+
+ This file is part of GAS, the GNU Assembler.
+
+ GAS is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GAS is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GAS; see the file COPYING. If not, write to
+ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#ifndef lint
+static char rcsid[] = "$Id: messages.c,v 1.3 1994/12/23 22:36:12 nate Exp $";
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+
+#include "as.h"
+
+#ifndef __STDC__
+#ifndef NO_STDARG
+#define NO_STDARG
+#endif
+#endif
+
+#ifndef NO_STDARG
+#include <stdarg.h>
+#else
+#ifndef NO_VARARGS
+#include <varargs.h>
+#endif /* NO_VARARGS */
+#endif /* NO_STDARG */
+
+extern char *strerror ();
+
+static void as_show_where PARAMS ((void));
+static void as_warn_internal PARAMS ((char *, unsigned int, char *));
+static void as_bad_internal PARAMS ((char *, unsigned int, char *));
+
+/*
+ * Despite the rest of the comments in this file, (FIXME-SOON),
+ * here is the current scheme for error messages etc:
+ *
+ * as_fatal() is used when gas is quite confused and
+ * continuing the assembly is pointless. In this case we
+ * exit immediately with error status.
+ *
+ * as_bad() is used to mark errors that result in what we
+ * presume to be a useless object file. Say, we ignored
+ * something that might have been vital. If we see any of
+ * these, assembly will continue to the end of the source,
+ * no object file will be produced, and we will terminate
+ * with error status. The new option, -Z, tells us to
+ * produce an object file anyway but we still exit with
+ * error status. The assumption here is that you don't want
+ * this object file but we could be wrong.
+ *
+ * as_warn() is used when we have an error from which we
+ * have a plausible error recovery. eg, masking the top
+ * bits of a constant that is longer than will fit in the
+ * destination. In this case we will continue to assemble
+ * the source, although we may have made a bad assumption,
+ * and we will produce an object file and return normal exit
+ * status (ie, no error). The new option -X tells us to
+ * treat all as_warn() errors as as_bad() errors. That is,
+ * no object file will be produced and we will exit with
+ * error status. The idea here is that we don't kill an
+ * entire make because of an error that we knew how to
+ * correct. On the other hand, sometimes you might want to
+ * stop the make at these points.
+ *
+ * as_tsktsk() is used when we see a minor error for which
+ * our error recovery action is almost certainly correct.
+ * In this case, we print a message and then assembly
+ * continues as though no error occurred.
+ */
+
+static void
+identify (file)
+ char *file;
+{
+ static int identified;
+ if (identified)
+ return;
+ identified++;
+
+ if (!file)
+ {
+ unsigned int x;
+ as_where (&file, &x);
+ }
+
+ fprintf (stderr, "%s: Assembler messages:\n", file);
+}
+
+static int warning_count; /* Count of number of warnings issued */
+
+int
+had_warnings ()
+{
+ return (warning_count);
+} /* had_err() */
+
+/* Nonzero if we've hit a 'bad error', and should not write an obj file,
+ and exit with a nonzero error code */
+
+static int error_count;
+
+int
+had_errors ()
+{
+ return (error_count);
+} /* had_errors() */
+
+
+/* Print the current location to stderr. */
+
+static void
+as_show_where ()
+{
+ char *file;
+ unsigned int line;
+
+ as_where (&file, &line);
+ identify (file);
+ fprintf (stderr, "%s:%u: ", file, line);
+}
+
+/*
+ * a s _ p e r r o r
+ *
+ * Like perror(3), but with more info.
+ */
+
+void
+as_perror (gripe, filename)
+ const char *gripe; /* Unpunctuated error theme. */
+ const char *filename;
+{
+ const char *errtxt;
+
+ as_show_where ();
+ fprintf (stderr, gripe, filename);
+#ifdef BFD_ASSEMBLER
+ errtxt = bfd_errmsg (bfd_get_error ());
+#else
+ errtxt = strerror (errno);
+#endif
+ fprintf (stderr, ": %s\n", errtxt);
+ errno = 0;
+#ifdef BFD_ASSEMBLER
+ bfd_set_error (bfd_error_no_error);
+#endif
+}
+
+/*
+ * a s _ t s k t s k ()
+ *
+ * Send to stderr a string as a warning, and locate warning
+ * in input file(s).
+ * Please only use this for when we have some recovery action.
+ * Please explain in string (which may have '\n's) what recovery was done.
+ */
+
+#ifndef NO_STDARG
+void
+as_tsktsk (const char *format,...)
+{
+ va_list args;
+
+ as_show_where ();
+ va_start (args, format);
+ vfprintf (stderr, format, args);
+ va_end (args);
+ (void) putc ('\n', stderr);
+} /* as_tsktsk() */
+
+#else
+#ifndef NO_VARARGS
+void
+as_tsktsk (format, va_alist)
+ char *format;
+ va_dcl
+{
+ va_list args;
+
+ as_show_where ();
+ va_start (args);
+ vfprintf (stderr, format, args);
+ va_end (args);
+ (void) putc ('\n', stderr);
+} /* as_tsktsk() */
+
+#else
+/*VARARGS1 */
+as_tsktsk (format, args)
+ char *format;
+{
+ as_show_where ();
+ _doprnt (format, &args, stderr);
+ (void) putc ('\n', stderr);
+} /* as_tsktsk */
+
+#endif /* not NO_VARARGS */
+#endif /* not NO_STDARG */
+
+/* The common portion of as_warn and as_warn_where. */
+
+static void
+as_warn_internal (file, line, buffer)
+ char *file;
+ unsigned int line;
+ char *buffer;
+{
+ ++warning_count;
+
+ if (file == NULL)
+ as_where (&file, &line);
+
+ identify (file);
+ fprintf (stderr, "%s:%u: Warning: ", file, line);
+ fputs (buffer, stderr);
+ (void) putc ('\n', stderr);
+#ifndef NO_LISTING
+ listing_warning (buffer);
+#endif
+}
+
+/*
+ * a s _ w a r n ()
+ *
+ * Send to stderr a string as a warning, and locate warning
+ * in input file(s).
+ * Please only use this for when we have some recovery action.
+ * Please explain in string (which may have '\n's) what recovery was done.
+ */
+
+#if 1
+#define flag_no_warnings (flagseen['W'])
+#endif
+
+#ifndef NO_STDARG
+void
+as_warn (const char *format,...)
+{
+ va_list args;
+ char buffer[200];
+
+ if (!flag_no_warnings)
+ {
+ va_start (args, format);
+ vsprintf (buffer, format, args);
+ va_end (args);
+ as_warn_internal ((char *) NULL, 0, buffer);
+ }
+} /* as_warn() */
+
+#else
+#ifndef NO_VARARGS
+void
+as_warn (format, va_alist)
+ char *format;
+ va_dcl
+{
+ va_list args;
+ char buffer[200];
+
+ if (!flag_no_warnings)
+ {
+ va_start (args);
+ vsprintf (buffer, format, args);
+ va_end (args);
+ as_warn_internal ((char *) NULL, 0, buffer);
+ }
+} /* as_warn() */
+
+#else
+/*VARARGS1 */
+as_warn (format, args)
+ char *format;
+{
+ if (!flag_no_warnings)
+ {
+ ++warning_count;
+ as_show_where ();
+ fprintf (stderr, "Warning: ");
+ _doprnt (format, &args, stderr);
+ (void) putc ('\n', stderr);
+ }
+} /* as_warn() */
+
+#endif /* not NO_VARARGS */
+#endif /* not NO_STDARG */
+
+/* as_warn_where, like as_bad but the file name and line number are
+ passed in. Unfortunately, we have to repeat the function in order
+ to handle the varargs correctly and portably. */
+
+#ifndef NO_STDARG
+void
+as_warn_where (char *file, unsigned int line, const char *format,...)
+{
+ va_list args;
+ char buffer[200];
+
+ if (!flag_no_warnings)
+ {
+ va_start (args, format);
+ vsprintf (buffer, format, args);
+ va_end (args);
+ as_warn_internal (file, line, buffer);
+ }
+} /* as_warn() */
+
+#else
+#ifndef NO_VARARGS
+void
+as_warn_where (file, line, format, va_alist)
+ char *file;
+ unsigned int line;
+ char *format;
+ va_dcl
+{
+ va_list args;
+ char buffer[200];
+
+ if (!flag_no_warnings)
+ {
+ va_start (args);
+ vsprintf (buffer, format, args);
+ va_end (args);
+ as_warn_internal (file, line, buffer);
+ }
+} /* as_warn() */
+
+#else
+/*VARARGS1 */
+as_warn_where (file, line, format, args)
+ char *file;
+ unsigned int line;
+ char *format;
+{
+ if (!flag_no_warnings)
+ {
+ ++warning_count;
+ identify (file);
+ fprintf (stderr, "%s:%u: Warning: ", file, line);
+ _doprnt (format, &args, stderr);
+ (void) putc ('\n', stderr);
+ }
+} /* as_warn() */
+
+#endif /* not NO_VARARGS */
+#endif /* not NO_STDARG */
+
+/* The common portion of as_bad and as_bad_where. */
+
+static void
+as_bad_internal (file, line, buffer)
+ char *file;
+ unsigned int line;
+ char *buffer;
+{
+ ++error_count;
+
+ if (file == NULL)
+ as_where (&file, &line);
+
+ identify (file);
+ fprintf (stderr, "%s:%u: Error: ", file, line);
+ fputs (buffer, stderr);
+ (void) putc ('\n', stderr);
+#ifndef NO_LISTING
+ listing_error (buffer);
+#endif
+}
+
+/*
+ * a s _ b a d ()
+ *
+ * Send to stderr a string as a warning, and locate warning in input file(s).
+ * Please us when there is no recovery, but we want to continue processing
+ * but not produce an object file.
+ * Please explain in string (which may have '\n's) what recovery was done.
+ */
+
+#ifndef NO_STDARG
+void
+as_bad (const char *format,...)
+{
+ va_list args;
+ char buffer[200];
+
+ va_start (args, format);
+ vsprintf (buffer, format, args);
+ va_end (args);
+
+ as_bad_internal ((char *) NULL, 0, buffer);
+}
+
+#else
+#ifndef NO_VARARGS
+void
+as_bad (format, va_alist)
+ char *format;
+ va_dcl
+{
+ va_list args;
+ char buffer[200];
+
+ va_start (args);
+ vsprintf (buffer, format, args);
+ va_end (args);
+
+ as_bad_internal ((char *) NULL, 0, buffer);
+}
+
+#else
+/*VARARGS1 */
+as_bad (format, args)
+ char *format;
+{
+ ++error_count;
+
+ as_show_where ();
+ fprintf (stderr, "Error: ");
+ _doprnt (format, &args, stderr);
+ (void) putc ('\n', stderr);
+} /* as_bad() */
+
+#endif /* not NO_VARARGS */
+#endif /* not NO_STDARG */
+
+/* as_bad_where, like as_bad but the file name and line number are
+ passed in. Unfortunately, we have to repeat the function in order
+ to handle the varargs correctly and portably. */
+
+#ifndef NO_STDARG
+void
+as_bad_where (char *file, unsigned int line, const char *format,...)
+{
+ va_list args;
+ char buffer[200];
+
+ va_start (args, format);
+ vsprintf (buffer, format, args);
+ va_end (args);
+
+ as_bad_internal (file, line, buffer);
+}
+
+#else
+#ifndef NO_VARARGS
+void
+as_bad_where (file, line, format, va_alist)
+ char *file;
+ unsigned int line;
+ char *format;
+ va_dcl
+{
+ va_list args;
+ char buffer[200];
+
+ va_start (args);
+ vsprintf (buffer, format, args);
+ va_end (args);
+
+ as_bad_internal (file, line, buffer);
+}
+
+#else
+/*VARARGS1 */
+as_bad_where (file, line, format, args)
+ char *file;
+ unsigned int line;
+ char *format;
+{
+ ++error_count;
+
+ identify (file);
+ fprintf (stderr, "%s:%u: Error: ", file, line);
+ _doprnt (format, &args, stderr);
+ (void) putc ('\n', stderr);
+} /* as_bad() */
+
+#endif /* not NO_VARARGS */
+#endif /* not NO_STDARG */
+
+/*
+ * a s _ f a t a l ()
+ *
+ * Send to stderr a string as a fatal message, and print location of error in
+ * input file(s).
+ * Please only use this for when we DON'T have some recovery action.
+ * It exit()s with a warning status.
+ */
+
+#ifndef NO_STDARG
+void
+as_fatal (const char *format,...)
+{
+ va_list args;
+
+ as_show_where ();
+ va_start (args, format);
+ fprintf (stderr, "Fatal error:");
+ vfprintf (stderr, format, args);
+ (void) putc ('\n', stderr);
+ va_end (args);
+ exit (33);
+} /* as_fatal() */
+
+#else
+#ifndef NO_VARARGS
+void
+as_fatal (format, va_alist)
+ char *format;
+ va_dcl
+{
+ va_list args;
+
+ as_show_where ();
+ va_start (args);
+ fprintf (stderr, "Fatal error:");
+ vfprintf (stderr, format, args);
+ (void) putc ('\n', stderr);
+ va_end (args);
+ exit (33);
+} /* as_fatal() */
+
+#else
+/*VARARGS1 */
+as_fatal (format, args)
+ char *format;
+{
+ as_show_where ();
+ fprintf (stderr, "Fatal error:");
+ _doprnt (format, &args, stderr);
+ (void) putc ('\n', stderr);
+ exit (33); /* What is a good exit status? */
+} /* as_fatal() */
+
+#endif /* not NO_VARARGS */
+#endif /* not NO_STDARG */
+
+void
+fprint_value (file, val)
+ FILE *file;
+ valueT val;
+{
+ if (sizeof (val) <= sizeof (long))
+ {
+ fprintf (file, "%ld", val);
+ return;
+ }
+#ifdef BFD_ASSEMBLER
+ if (sizeof (val) <= sizeof (bfd_vma))
+ {
+ fprintf_vma (file, val);
+ return;
+ }
+#endif
+ abort ();
+}
+
+void
+sprint_value (buf, val)
+ char *buf;
+ valueT val;
+{
+ if (sizeof (val) <= sizeof (long))
+ {
+ sprintf (buf, "%ld", val);
+ return;
+ }
+#ifdef BFD_ASSEMBLER
+ if (sizeof (val) <= sizeof (bfd_vma))
+ {
+ sprintf_vma (buf, val);
+ return;
+ }
+#endif
+ abort ();
+}
+
+/* end of messages.c */
diff --git a/gnu/usr.bin/as/obj.h b/gnu/usr.bin/as/obj.h
new file mode 100644
index 0000000..a621941
--- /dev/null
+++ b/gnu/usr.bin/as/obj.h
@@ -0,0 +1,77 @@
+/* obj.h - defines the object dependent hooks for all object
+ format backends.
+
+ Copyright (C) 1987, 1990, 1991, 1992 Free Software Foundation, Inc.
+
+ This file is part of GAS, the GNU Assembler.
+
+ GAS is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GAS is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GAS; see the file COPYING. If not, write to
+ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+/*
+ * $Id: obj.h,v 1.1 1993/11/03 00:52:03 paul Exp $
+ */
+
+
+#if __STDC__ == 1
+
+char *obj_default_output_file_name(void);
+void obj_crawl_symbol_chain(object_headers *headers);
+void obj_emit_relocations(char **where, fixS *fixP, relax_addressT segment_address_in_file);
+void obj_emit_strings(char **where);
+void obj_emit_symbols(char **where, symbolS *symbol_rootP);
+void obj_header_append(char **where, object_headers *headers);
+void obj_read_begin_hook(void);
+
+#ifndef obj_symbol_new_hook
+void obj_symbol_new_hook(symbolS *symbolP);
+#endif /* obj_symbol_new_hook */
+
+void obj_symbol_to_chars(char **where, symbolS *symbolP);
+
+#ifndef obj_pre_write_hook
+void obj_pre_write_hook(object_headers *headers);
+#endif /* obj_pre_write_hook */
+
+#else /* not __STDC__ */
+
+char *obj_default_output_file_name();
+void obj_crawl_symbol_chain();
+void obj_emit_relocations();
+void obj_emit_strings();
+void obj_emit_symbols();
+void obj_header_append();
+void obj_read_begin_hook();
+
+#ifndef obj_symbol_new_hook
+void obj_symbol_new_hook();
+#endif /* obj_symbol_new_hook */
+
+void obj_symbol_to_chars();
+
+#ifndef obj_pre_write_hook
+void obj_pre_write_hook();
+#endif /* obj_pre_write_hook */
+
+#endif /* not __STDC__ */
+
+extern const pseudo_typeS obj_pseudo_table[];
+
+/*
+ * Local Variables:
+ * comment-column: 0
+ * fill-column: 131
+ * End:
+ */
+
+/* end of obj.h */
diff --git a/gnu/usr.bin/as/obstack.c b/gnu/usr.bin/as/obstack.c
new file mode 100644
index 0000000..d7302ea
--- /dev/null
+++ b/gnu/usr.bin/as/obstack.c
@@ -0,0 +1,374 @@
+/* obstack.c - subroutines used implicitly by object stack macros
+ Copyright (C) 1988 Free Software Foundation, Inc.
+
+This program is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 2, or (at your option) any
+later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#ifndef lint
+static char rcsid[] = "$Id: obstack.c,v 1.3 1993/10/02 20:57:47 pk Exp $";
+#endif
+
+#include "obstack.h"
+
+#ifdef __STDC__
+#define POINTER void *
+#else
+#define POINTER char *
+#endif
+
+/* Determine default alignment. */
+struct fooalign {char x; double d;};
+#define DEFAULT_ALIGNMENT ((char *)&((struct fooalign *) 0)->d - (char *)0)
+/* If malloc were really smart, it would round addresses to DEFAULT_ALIGNMENT.
+ But in fact it might be less smart and round addresses to as much as
+ DEFAULT_ROUNDING. So we prepare for it to do that. */
+union fooround {long x; double d;};
+#define DEFAULT_ROUNDING (sizeof (union fooround))
+
+/* When we copy a long block of data, this is the unit to do it with.
+ On some machines, copying successive ints does not work;
+ in such a case, redefine COPYING_UNIT to `long' (if that works)
+ or `char' as a last resort. */
+#ifndef COPYING_UNIT
+#define COPYING_UNIT int
+#endif
+
+/* The non-GNU-C macros copy the obstack into this global variable
+ to avoid multiple evaluation. */
+
+struct obstack *_obstack;
+
+/* Initialize an obstack H for use. Specify chunk size SIZE (0 means default).
+ Objects start on multiples of ALIGNMENT (0 means use default).
+ CHUNKFUN is the function to use to allocate chunks,
+ and FREEFUN the function to free them. */
+
+void
+_obstack_begin (h, size, alignment, chunkfun, freefun)
+ struct obstack *h;
+ int size;
+ int alignment;
+ POINTER (*chunkfun) ();
+ void (*freefun) ();
+{
+ register struct _obstack_chunk* chunk; /* points to new chunk */
+
+ if (alignment == 0)
+ alignment = DEFAULT_ALIGNMENT;
+ if (size == 0)
+ /* Default size is what GNU malloc can fit in a 4096-byte block. */
+ {
+ /* 12 is sizeof (mhead) and 4 is EXTRA from GNU malloc.
+ Use the values for range checking, because if range checking is off,
+ the extra bytes won't be missed terribly, but if range checking is on
+ and we used a larger request, a whole extra 4096 bytes would be
+ allocated.
+
+ These number are irrelevant to the new GNU malloc. I suspect it is
+ less sensitive to the size of the request. */
+ int extra = ((((12 + DEFAULT_ROUNDING - 1) & ~(DEFAULT_ROUNDING - 1))
+ + 4 + DEFAULT_ROUNDING - 1)
+ & ~(DEFAULT_ROUNDING - 1));
+ size = 4096 - extra;
+ }
+
+ h->chunkfun = (struct _obstack_chunk * (*)()) chunkfun;
+ h->freefun = freefun;
+ h->chunk_size = size;
+ h->alignment_mask = alignment - 1;
+
+ chunk = h->chunk = (*h->chunkfun) (h->chunk_size);
+ h->next_free = h->object_base = chunk->contents;
+ h->chunk_limit = chunk->limit
+ = (char *) chunk + h->chunk_size;
+ chunk->prev = 0;
+ /* The initial chunk now contains no empty object. */
+ h->maybe_empty_object = 0;
+}
+
+/* Allocate a new current chunk for the obstack *H
+ on the assumption that LENGTH bytes need to be added
+ to the current object, or a new object of length LENGTH allocated.
+ Copies any partial object from the end of the old chunk
+ to the beginning of the new one. */
+
+void
+_obstack_newchunk (h, length)
+ struct obstack *h;
+ int length;
+{
+ register struct _obstack_chunk* old_chunk = h->chunk;
+ register struct _obstack_chunk* new_chunk;
+ register long new_size;
+ register int obj_size = h->next_free - h->object_base;
+ register int i;
+ int already;
+
+ /* Compute size for new chunk. */
+ new_size = (obj_size + length) + (obj_size >> 3) + 100;
+ if (new_size < h->chunk_size)
+ new_size = h->chunk_size;
+
+ /* Allocate and initialize the new chunk. */
+ new_chunk = h->chunk = (*h->chunkfun) (new_size);
+ new_chunk->prev = old_chunk;
+ new_chunk->limit = h->chunk_limit = (char *) new_chunk + new_size;
+
+ /* Move the existing object to the new chunk.
+ Word at a time is fast and is safe if the object
+ is sufficiently aligned. */
+ if (h->alignment_mask + 1 >= DEFAULT_ALIGNMENT)
+ {
+ for (i = obj_size / sizeof (COPYING_UNIT) - 1;
+ i >= 0; i--)
+ ((COPYING_UNIT *)new_chunk->contents)[i]
+ = ((COPYING_UNIT *)h->object_base)[i];
+ /* We used to copy the odd few remaining bytes as one extra COPYING_UNIT,
+ but that can cross a page boundary on a machine
+ which does not do strict alignment for COPYING_UNITS. */
+ already = obj_size / sizeof (COPYING_UNIT) * sizeof (COPYING_UNIT);
+ }
+ else
+ already = 0;
+ /* Copy remaining bytes one by one. */
+ for (i = already; i < obj_size; i++)
+ new_chunk->contents[i] = h->object_base[i];
+
+ /* If the object just copied was the only data in OLD_CHUNK,
+ free that chunk and remove it from the chain.
+ But not if that chunk might contain an empty object. */
+ if (h->object_base == old_chunk->contents && ! h->maybe_empty_object)
+ {
+ new_chunk->prev = old_chunk->prev;
+ (*h->freefun) (old_chunk);
+ }
+
+ h->object_base = new_chunk->contents;
+ h->next_free = h->object_base + obj_size;
+ /* The new chunk certainly contains no empty object yet. */
+ h->maybe_empty_object = 0;
+}
+
+/* Return nonzero if object OBJ has been allocated from obstack H.
+ This is here for debugging.
+ If you use it in a program, you are probably losing. */
+
+int
+_obstack_allocated_p (h, obj)
+ struct obstack *h;
+ POINTER obj;
+{
+ register struct _obstack_chunk* lp; /* below addr of any objects in this chunk */
+ register struct _obstack_chunk* plp; /* point to previous chunk if any */
+
+ lp = (h)->chunk;
+ /* We use >= rather than > since the object cannot be exactly at
+ the beginning of the chunk but might be an empty object exactly
+ at the end of an adjacent chunk. */
+ while (lp != 0 && ((POINTER)lp >= obj || (POINTER)(lp)->limit < obj))
+ {
+ plp = lp->prev;
+ lp = plp;
+ }
+ return lp != 0;
+}
+
+/* Free objects in obstack H, including OBJ and everything allocate
+ more recently than OBJ. If OBJ is zero, free everything in H. */
+
+#undef obstack_free
+
+/* This function has two names with identical definitions.
+ This is the first one, called from non-ANSI code. */
+
+void
+_obstack_free (h, obj)
+ struct obstack *h;
+ POINTER obj;
+{
+ register struct _obstack_chunk* lp; /* below addr of any objects in this chunk */
+ register struct _obstack_chunk* plp; /* point to previous chunk if any */
+
+ lp = h->chunk;
+ /* We use >= because there cannot be an object at the beginning of a chunk.
+ But there can be an empty object at that address
+ at the end of another chunk. */
+ while (lp != 0 && ((POINTER)lp >= obj || (POINTER)(lp)->limit < obj))
+ {
+ plp = lp->prev;
+ (*h->freefun) (lp);
+ lp = plp;
+ /* If we switch chunks, we can't tell whether the new current
+ chunk contains an empty object, so assume that it may. */
+ h->maybe_empty_object = 1;
+ }
+ if (lp)
+ {
+ h->object_base = h->next_free = (char *)(obj);
+ h->chunk_limit = lp->limit;
+ h->chunk = lp;
+ }
+ else if (obj != 0)
+ /* obj is not in any of the chunks! */
+ abort ();
+}
+
+/* This function is used from ANSI code. */
+
+void
+obstack_free (h, obj)
+ struct obstack *h;
+ POINTER obj;
+{
+ register struct _obstack_chunk* lp; /* below addr of any objects in this chunk */
+ register struct _obstack_chunk* plp; /* point to previous chunk if any */
+
+ lp = h->chunk;
+ /* We use >= because there cannot be an object at the beginning of a chunk.
+ But there can be an empty object at that address
+ at the end of another chunk. */
+ while (lp != 0 && ((POINTER)lp >= obj || (POINTER)(lp)->limit < obj))
+ {
+ plp = lp->prev;
+ (*h->freefun) (lp);
+ lp = plp;
+ /* If we switch chunks, we can't tell whether the new current
+ chunk contains an empty object, so assume that it may. */
+ h->maybe_empty_object = 1;
+ }
+ if (lp)
+ {
+ h->object_base = h->next_free = (char *)(obj);
+ h->chunk_limit = lp->limit;
+ h->chunk = lp;
+ }
+ else if (obj != 0)
+ /* obj is not in any of the chunks! */
+ abort ();
+}
+
+#if 0
+/* These are now turned off because the applications do not use it
+ and it uses bcopy via obstack_grow, which causes trouble on sysV. */
+
+/* Now define the functional versions of the obstack macros.
+ Define them to simply use the corresponding macros to do the job. */
+
+#ifdef __STDC__
+/* These function definitions do not work with non-ANSI preprocessors;
+ they won't pass through the macro names in parentheses. */
+
+/* The function names appear in parentheses in order to prevent
+ the macro-definitions of the names from being expanded there. */
+
+POINTER (obstack_base) (obstack)
+ struct obstack *obstack;
+{
+ return obstack_base (obstack);
+}
+
+POINTER (obstack_next_free) (obstack)
+ struct obstack *obstack;
+{
+ return obstack_next_free (obstack);
+}
+
+int (obstack_object_size) (obstack)
+ struct obstack *obstack;
+{
+ return obstack_object_size (obstack);
+}
+
+int (obstack_room) (obstack)
+ struct obstack *obstack;
+{
+ return obstack_room (obstack);
+}
+
+void (obstack_grow) (obstack, pointer, length)
+ struct obstack *obstack;
+ POINTER pointer;
+ int length;
+{
+ obstack_grow (obstack, pointer, length);
+}
+
+void (obstack_grow0) (obstack, pointer, length)
+ struct obstack *obstack;
+ POINTER pointer;
+ int length;
+{
+ obstack_grow0 (obstack, pointer, length);
+}
+
+void (obstack_1grow) (obstack, character)
+ struct obstack *obstack;
+ int character;
+{
+ obstack_1grow (obstack, character);
+}
+
+void (obstack_blank) (obstack, length)
+ struct obstack *obstack;
+ int length;
+{
+ obstack_blank (obstack, length);
+}
+
+void (obstack_1grow_fast) (obstack, character)
+ struct obstack *obstack;
+ int character;
+{
+ obstack_1grow_fast (obstack, character);
+}
+
+void (obstack_blank_fast) (obstack, length)
+ struct obstack *obstack;
+ int length;
+{
+ obstack_blank_fast (obstack, length);
+}
+
+POINTER (obstack_finish) (obstack)
+ struct obstack *obstack;
+{
+ return obstack_finish (obstack);
+}
+
+POINTER (obstack_alloc) (obstack, length)
+ struct obstack *obstack;
+ int length;
+{
+ return obstack_alloc (obstack, length);
+}
+
+POINTER (obstack_copy) (obstack, pointer, length)
+ struct obstack *obstack;
+ POINTER pointer;
+ int length;
+{
+ return obstack_copy (obstack, pointer, length);
+}
+
+POINTER (obstack_copy0) (obstack, pointer, length)
+ struct obstack *obstack;
+ POINTER pointer;
+ int length;
+{
+ return obstack_copy0 (obstack, pointer, length);
+}
+
+#endif /* __STDC__ */
+
+#endif /* 0 */
diff --git a/gnu/usr.bin/as/obstack.h b/gnu/usr.bin/as/obstack.h
new file mode 100644
index 0000000..c29bb1f
--- /dev/null
+++ b/gnu/usr.bin/as/obstack.h
@@ -0,0 +1,448 @@
+/* obstack.h - object stack macros
+ Copyright (C) 1988 Free Software Foundation, Inc.
+
+This program is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 2, or (at your option) any
+later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+/*
+ * $Id: obstack.h,v 1.2 1993/11/03 00:52:06 paul Exp $
+ */
+
+
+/* Summary:
+
+All the apparent functions defined here are macros. The idea
+is that you would use these pre-tested macros to solve a
+very specific set of problems, and they would run fast.
+Caution: no side-effects in arguments please!! They may be
+evaluated MANY times!!
+
+These macros operate a stack of objects. Each object starts life
+small, and may grow to maturity. (Consider building a word syllable
+by syllable.) An object can move while it is growing. Once it has
+been "finished" it never changes address again. So the "top of the
+stack" is typically an immature growing object, while the rest of the
+stack is of mature, fixed size and fixed address objects.
+
+These routines grab large chunks of memory, using a function you
+supply, called `obstack_chunk_alloc'. On occasion, they free chunks,
+by calling `obstack_chunk_free'. You must define them and declare
+them before using any obstack macros.
+
+Each independent stack is represented by a `struct obstack'.
+Each of the obstack macros expects a pointer to such a structure
+as the first argument.
+
+One motivation for this package is the problem of growing char strings
+in symbol tables. Unless you are "fascist pig with a read-only mind"
+[Gosper's immortal quote from HAKMEM item 154, out of context] you
+would not like to put any arbitrary upper limit on the length of your
+symbols.
+
+In practice this often means you will build many short symbols and a
+few long symbols. At the time you are reading a symbol you don't know
+how long it is. One traditional method is to read a symbol into a
+buffer, realloc()ating the buffer every time you try to read a symbol
+that is longer than the buffer. This is beaut, but you still will
+want to copy the symbol from the buffer to a more permanent
+symbol-table entry say about half the time.
+
+With obstacks, you can work differently. Use one obstack for all symbol
+names. As you read a symbol, grow the name in the obstack gradually.
+When the name is complete, finalize it. Then, if the symbol exists already,
+free the newly read name.
+
+The way we do this is to take a large chunk, allocating memory from
+low addresses. When you want to build a symbol in the chunk you just
+add chars above the current "high water mark" in the chunk. When you
+have finished adding chars, because you got to the end of the symbol,
+you know how long the chars are, and you can create a new object.
+Mostly the chars will not burst over the highest address of the chunk,
+because you would typically expect a chunk to be (say) 100 times as
+long as an average object.
+
+In case that isn't clear, when we have enough chars to make up
+the object, THEY ARE ALREADY CONTIGUOUS IN THE CHUNK (guaranteed)
+so we just point to it where it lies. No moving of chars is
+needed and this is the second win: potentially long strings need
+never be explicitly shuffled. Once an object is formed, it does not
+change its address during its lifetime.
+
+When the chars burst over a chunk boundary, we allocate a larger
+chunk, and then copy the partly formed object from the end of the old
+chunk to the beginning of the new larger chunk. We then carry on
+accreting characters to the end of the object as we normally would.
+
+A special macro is provided to add a single char at a time to a
+growing object. This allows the use of register variables, which
+break the ordinary 'growth' macro.
+
+Summary:
+ We allocate large chunks.
+ We carve out one object at a time from the current chunk.
+ Once carved, an object never moves.
+ We are free to append data of any size to the currently
+ growing object.
+ Exactly one object is growing in an obstack at any one time.
+ You can run one obstack per control block.
+ You may have as many control blocks as you dare.
+ Because of the way we do it, you can `unwind' a obstack
+ back to a previous state. (You may remove objects much
+ as you would with a stack.)
+*/
+
+
+/* Don't do the contents of this file more than once. */
+
+#ifndef __OBSTACKS__
+#define __OBSTACKS__
+
+/* We use subtraction of (char *)0 instead of casting to int
+ because on word-addressable machines a simple cast to int
+ may ignore the byte-within-word field of the pointer. */
+
+#ifndef __PTR_TO_INT
+#define __PTR_TO_INT(P) ((P) - (char *)0)
+#endif
+
+#ifndef __INT_TO_PTR
+#define __INT_TO_PTR(P) ((P) + (char *)0)
+#endif
+
+struct _obstack_chunk /* Lives at front of each chunk. */
+{
+ char *limit; /* 1 past end of this chunk */
+ struct _obstack_chunk *prev; /* address of prior chunk or NULL */
+ char contents[4]; /* objects begin here */
+};
+
+struct obstack /* control current object in current chunk */
+{
+ long chunk_size; /* preferred size to allocate chunks in */
+ struct _obstack_chunk* chunk; /* address of current struct obstack_chunk */
+ char *object_base; /* address of object we are building */
+ char *next_free; /* where to add next char to current object */
+ char *chunk_limit; /* address of char after current chunk */
+ int temp; /* Temporary for some macros. */
+ int alignment_mask; /* Mask of alignment for each object. */
+ struct _obstack_chunk *(*chunkfun) (); /* User's fcn to allocate a chunk. */
+ void (*freefun) (); /* User's function to free a chunk. */
+ /* Nonzero means there is a possibility the current chunk contains
+ a zero-length object. This prevents freeing the chunk
+ if we allocate a bigger chunk to replace it. */
+ char maybe_empty_object;
+};
+
+/* Declare the external functions we use; they are in obstack.c. */
+
+#ifdef __STDC__
+ extern void _obstack_newchunk (struct obstack *, int);
+ extern void _obstack_free (struct obstack *, void *);
+ extern void _obstack_begin (struct obstack *, int, int,
+ void *(*) (), void (*) ());
+#else
+ extern void _obstack_newchunk ();
+ extern void _obstack_free ();
+ extern void _obstack_begin ();
+#endif
+
+#ifdef __STDC__
+
+/* Do the function-declarations after the structs
+ but before defining the macros. */
+
+void obstack_init (struct obstack *obstack);
+
+void * obstack_alloc (struct obstack *obstack, int size);
+
+void * obstack_copy (struct obstack *obstack, void *address, int size);
+void * obstack_copy0 (struct obstack *obstack, void *address, int size);
+
+void obstack_free (struct obstack *obstack, void *block);
+
+void obstack_blank (struct obstack *obstack, int size);
+
+void obstack_grow (struct obstack *obstack, void *data, int size);
+void obstack_grow0 (struct obstack *obstack, void *data, int size);
+
+void obstack_1grow (struct obstack *obstack, int data_char);
+void obstack_ptr_grow (struct obstack *obstack, void *data);
+void obstack_int_grow (struct obstack *obstack, int data);
+
+void * obstack_finish (struct obstack *obstack);
+
+int obstack_object_size (struct obstack *obstack);
+
+int obstack_room (struct obstack *obstack);
+void obstack_1grow_fast (struct obstack *obstack, int data_char);
+void obstack_ptr_grow_fast (struct obstack *obstack, void *data);
+void obstack_int_grow_fast (struct obstack *obstack, int data);
+void obstack_blank_fast (struct obstack *obstack, int size);
+
+void * obstack_base (struct obstack *obstack);
+void * obstack_next_free (struct obstack *obstack);
+int obstack_alignment_mask (struct obstack *obstack);
+int obstack_chunk_size (struct obstack *obstack);
+
+#endif /* __STDC__ */
+
+/* Non-ANSI C cannot really support alternative functions for these macros,
+ so we do not declare them. */
+
+/* Pointer to beginning of object being allocated or to be allocated next.
+ Note that this might not be the final address of the object
+ because a new chunk might be needed to hold the final size. */
+
+#define obstack_base(h) ((h)->object_base)
+
+/* Size for allocating ordinary chunks. */
+
+#define obstack_chunk_size(h) ((h)->chunk_size)
+
+/* Pointer to next byte not yet allocated in current chunk. */
+
+#define obstack_next_free(h) ((h)->next_free)
+
+/* Mask specifying low bits that should be clear in address of an object. */
+
+#define obstack_alignment_mask(h) ((h)->alignment_mask)
+
+#define obstack_init(h) \
+ _obstack_begin ((h), 0, 0, \
+ (void *(*) ()) obstack_chunk_alloc, (void (*) ())obstack_chunk_free)
+
+#define obstack_begin(h, size) \
+ _obstack_begin ((h), (size), 0, \
+ (void *(*) ()) obstack_chunk_alloc, (void (*) ())obstack_chunk_free)
+
+#define obstack_1grow_fast(h,achar) (*((h)->next_free)++ = achar)
+
+#define obstack_blank_fast(h,n) ((h)->next_free += (n))
+
+#if defined (__GNUC__) && defined (__STDC__)
+#if __GNUC__ < 2
+#define __extension__
+#endif
+
+/* For GNU C, if not -traditional,
+ we can define these macros to compute all args only once
+ without using a global variable.
+ Also, we can avoid using the `temp' slot, to make faster code. */
+
+#define obstack_object_size(OBSTACK) \
+ __extension__ \
+ ({ struct obstack *__o = (OBSTACK); \
+ (unsigned) (__o->next_free - __o->object_base); })
+
+#define obstack_room(OBSTACK) \
+ __extension__ \
+ ({ struct obstack *__o = (OBSTACK); \
+ (unsigned) (__o->chunk_limit - __o->next_free); })
+
+/* Note that the call to _obstack_newchunk is enclosed in (..., 0)
+ so that we can avoid having void expressions
+ in the arms of the conditional expression.
+ Casting the third operand to void was tried before,
+ but some compilers won't accept it. */
+#define obstack_grow(OBSTACK,where,length) \
+__extension__ \
+({ struct obstack *__o = (OBSTACK); \
+ int __len = (length); \
+ ((__o->next_free + __len > __o->chunk_limit) \
+ ? (_obstack_newchunk (__o, __len), 0) : 0); \
+ memcpy (__o->next_free, where, __len); \
+ __o->next_free += __len; \
+ (void) 0; })
+
+#define obstack_grow0(OBSTACK,where,length) \
+__extension__ \
+({ struct obstack *__o = (OBSTACK); \
+ int __len = (length); \
+ ((__o->next_free + __len + 1 > __o->chunk_limit) \
+ ? (_obstack_newchunk (__o, __len + 1), 0) : 0), \
+ memcpy (__o->next_free, where, __len), \
+ __o->next_free += __len, \
+ *(__o->next_free)++ = 0; \
+ (void) 0; })
+
+#define obstack_1grow(OBSTACK,datum) \
+__extension__ \
+({ struct obstack *__o = (OBSTACK); \
+ ((__o->next_free + 1 > __o->chunk_limit) \
+ ? (_obstack_newchunk (__o, 1), 0) : 0), \
+ *(__o->next_free)++ = (datum); \
+ (void) 0; })
+
+/* These assume that the obstack alignment is good enough for pointers or ints,
+ and that the data added so far to the current object
+ shares that much alignment. */
+
+#define obstack_ptr_grow(OBSTACK,datum) \
+__extension__ \
+({ struct obstack *__o = (OBSTACK); \
+ ((__o->next_free + sizeof (void *) > __o->chunk_limit) \
+ ? (_obstack_newchunk (__o, sizeof (void *)), 0) : 0), \
+ *(*(void ***)&__o->next_free)++ = ((void *)datum); \
+ (void) 0; })
+
+#define obstack_int_grow(OBSTACK,datum) \
+__extension__ \
+({ struct obstack *__o = (OBSTACK); \
+ ((__o->next_free + sizeof (int) > __o->chunk_limit) \
+ ? (_obstack_newchunk (__o, sizeof (int)), 0) : 0), \
+ *(*(int **)&__o->next_free)++ = ((int)datum); \
+ (void) 0; })
+
+#define obstack_ptr_grow_fast(h,aptr) (*(*(void ***)&(h)->next_free)++ = (void *)aptr)
+#define obstack_int_grow_fast(h,aint) (*(*(int **)&(h)->next_free)++ = (int)aint)
+
+#define obstack_blank(OBSTACK,length) \
+__extension__ \
+({ struct obstack *__o = (OBSTACK); \
+ int __len = (length); \
+ ((__o->chunk_limit - __o->next_free < __len) \
+ ? (_obstack_newchunk (__o, __len), 0) : 0); \
+ __o->next_free += __len; \
+ (void) 0; })
+
+#define obstack_alloc(OBSTACK,length) \
+__extension__ \
+({ struct obstack *__h = (OBSTACK); \
+ obstack_blank (__h, (length)); \
+ obstack_finish (__h); })
+
+#define obstack_copy(OBSTACK,where,length) \
+__extension__ \
+({ struct obstack *__h = (OBSTACK); \
+ obstack_grow (__h, (where), (length)); \
+ obstack_finish (__h); })
+
+#define obstack_copy0(OBSTACK,where,length) \
+__extension__ \
+({ struct obstack *__h = (OBSTACK); \
+ obstack_grow0 (__h, (where), (length)); \
+ obstack_finish (__h); })
+
+/* The local variable is named __o1 to avoid a name conflict
+ when obstack_blank is called. */
+#define obstack_finish(OBSTACK) \
+__extension__ \
+({ struct obstack *__o1 = (OBSTACK); \
+ void *value = (void *) __o1->object_base; \
+ if (__o1->next_free == value) \
+ __o1->maybe_empty_object = 1; \
+ __o1->next_free \
+ = __INT_TO_PTR ((__PTR_TO_INT (__o1->next_free)+__o1->alignment_mask)\
+ & ~ (__o1->alignment_mask)); \
+ ((__o1->next_free - (char *)__o1->chunk \
+ > __o1->chunk_limit - (char *)__o1->chunk) \
+ ? (__o1->next_free = __o1->chunk_limit) : 0); \
+ __o1->object_base = __o1->next_free; \
+ value; })
+
+#define obstack_free(OBSTACK, OBJ) \
+__extension__ \
+({ struct obstack *__o = (OBSTACK); \
+ void *__obj = (OBJ); \
+ if (__obj > (void *)__o->chunk && __obj < (void *)__o->chunk_limit) \
+ __o->next_free = __o->object_base = __obj; \
+ else (obstack_free) (__o, __obj); })
+
+#else /* not __GNUC__ or not __STDC__ */
+
+#define obstack_object_size(h) \
+ (unsigned) ((h)->next_free - (h)->object_base)
+
+#define obstack_room(h) \
+ (unsigned) ((h)->chunk_limit - (h)->next_free)
+
+#define obstack_grow(h,where,length) \
+( (h)->temp = (length), \
+ (((h)->next_free + (h)->temp > (h)->chunk_limit) \
+ ? (_obstack_newchunk ((h), (h)->temp), 0) : 0), \
+ memcpy ((h)->next_free, where, (h)->temp), \
+ (h)->next_free += (h)->temp)
+
+#define obstack_grow0(h,where,length) \
+( (h)->temp = (length), \
+ (((h)->next_free + (h)->temp + 1 > (h)->chunk_limit) \
+ ? (_obstack_newchunk ((h), (h)->temp + 1), 0) : 0), \
+ memcpy ((h)->next_free, where, (h)->temp), \
+ (h)->next_free += (h)->temp, \
+ *((h)->next_free)++ = 0)
+
+#define obstack_1grow(h,datum) \
+( (((h)->next_free + 1 > (h)->chunk_limit) \
+ ? (_obstack_newchunk ((h), 1), 0) : 0), \
+ *((h)->next_free)++ = (datum))
+
+#define obstack_ptr_grow(h,datum) \
+( (((h)->next_free + sizeof (char *) > (h)->chunk_limit) \
+ ? (_obstack_newchunk ((h), sizeof (char *)), 0) : 0), \
+ *(*(char ***)&(h)->next_free)++ = ((char *)datum))
+
+#define obstack_int_grow(h,datum) \
+( (((h)->next_free + sizeof (int) > (h)->chunk_limit) \
+ ? (_obstack_newchunk ((h), sizeof (int)), 0) : 0), \
+ *(*(int **)&(h)->next_free)++ = ((int)datum))
+
+#define obstack_ptr_grow_fast(h,aptr) (*(*(char ***)&(h)->next_free)++ = (char *)aptr)
+#define obstack_int_grow_fast(h,aint) (*(*(int **)&(h)->next_free)++ = (int)aint)
+#define obstack_blank(h,length) \
+( (h)->temp = (length), \
+ (((h)->chunk_limit - (h)->next_free < (h)->temp) \
+ ? (_obstack_newchunk ((h), (h)->temp), 0) : 0), \
+ (h)->next_free += (h)->temp)
+
+#define obstack_alloc(h,length) \
+ (obstack_blank ((h), (length)), obstack_finish ((h)))
+
+#define obstack_copy(h,where,length) \
+ (obstack_grow ((h), (where), (length)), obstack_finish ((h)))
+
+#define obstack_copy0(h,where,length) \
+ (obstack_grow0 ((h), (where), (length)), obstack_finish ((h)))
+
+#define obstack_finish(h) \
+( ((h)->next_free == (h)->object_base \
+ ? (((h)->maybe_empty_object = 1), 0) \
+ : 0), \
+ (h)->temp = __PTR_TO_INT ((h)->object_base), \
+ (h)->next_free \
+ = __INT_TO_PTR ((__PTR_TO_INT ((h)->next_free)+(h)->alignment_mask) \
+ & ~ ((h)->alignment_mask)), \
+ (((h)->next_free - (char *)(h)->chunk \
+ > (h)->chunk_limit - (char *)(h)->chunk) \
+ ? ((h)->next_free = (h)->chunk_limit) : 0), \
+ (h)->object_base = (h)->next_free, \
+ __INT_TO_PTR ((h)->temp))
+
+#ifdef __STDC__
+#define obstack_free(h,obj) \
+( (h)->temp = (char *)(obj) - (char *) (h)->chunk, \
+ (((h)->temp > 0 && (h)->temp < (h)->chunk_limit - (char *) (h)->chunk)\
+ ? (int) ((h)->next_free = (h)->object_base \
+ = (h)->temp + (char *) (h)->chunk) \
+ : (((obstack_free) ((h), (h)->temp + (char *) (h)->chunk), 0), 0)))
+#else
+#define obstack_free(h,obj) \
+( (h)->temp = (char *)(obj) - (char *) (h)->chunk, \
+ (((h)->temp > 0 && (h)->temp < (h)->chunk_limit - (char *) (h)->chunk)\
+ ? (int) ((h)->next_free = (h)->object_base \
+ = (h)->temp + (char *) (h)->chunk) \
+ : (_obstack_free ((h), (h)->temp + (char *) (h)->chunk), 0)))
+#endif
+
+#endif /* not __GNUC__ or not __STDC__ */
+
+#endif /* not __OBSTACKS__ */
diff --git a/gnu/usr.bin/as/opcode/ChangeLog b/gnu/usr.bin/as/opcode/ChangeLog
new file mode 100644
index 0000000..dcb0498
--- /dev/null
+++ b/gnu/usr.bin/as/opcode/ChangeLog
@@ -0,0 +1,56 @@
+Mon Feb 24 02:02:04 1992 K. Richard Pixley (rich@cygnus.com)
+
+ * ns32k.h: SEQUENT_COMPATIBILITY -> TE_SEQUENT.
+
+ * i860.h: added "fst.q".
+
+Fri Feb 21 01:29:51 1992 K. Richard Pixley (rich@cygnus.com)
+
+ * i386.h: added inb, inw, outb, outw opcodes, added att syntax for
+ scmp, slod, smov, ssca, ssto. Curtesy Minh Tran-Le
+ <TRANLE@INTELLICORP.COM>.
+
+Thu Jan 30 07:31:44 1992 Steve Chamberlain (sac at rtl.cygnus.com)
+
+ * h8300.h: turned op_type enum into #define list
+
+Thu Jan 30 01:07:24 1992 John Gilmore (gnu at cygnus.com)
+
+ * sparc.h: Remove "cypress" architecture. Remove "fitox" and
+ similar instructions -- they've been renamed to "fitoq", etc.
+ REALLY fix tsubcctv. Fix "fcmpeq" and "fcmpq" which had wrong
+ number of arguments.
+ * h8300.h: Remove extra ; which produces compiler warning.
+
+Tue Jan 28 22:59:22 1992 Stu Grossman (grossman at cygnus.com)
+
+ * sparc.h: fix opcode for tsubcctv.
+
+Tue Jan 7 17:19:39 1992 K. Richard Pixley (rich at cygnus.com)
+
+ * sparc.h: fba and cba are now aliases for fb and cb respectively.
+
+Fri Dec 27 10:55:50 1991 Per Bothner (bothner at cygnus.com)
+
+ * sparc.h (nop): Made the 'lose' field be even tighter,
+ so only a standard 'nop' is disassembled as a nop.
+
+Sun Dec 22 12:18:18 1991 Michael Tiemann (tiemann at cygnus.com)
+
+ * sparc.h (nop): Add RD_GO to `lose' so that only %g0 in dest is
+ disassembled as a nop.
+
+Tue Dec 10 00:22:20 1991 K. Richard Pixley (rich at rtl.cygnus.com)
+
+ * sparc.h: fix a typo.
+
+Sat Nov 30 20:40:51 1991 Steve Chamberlain (sac at rtl.cygnus.com)
+
+ * a29k.h, arm.h, h8300.h, i386.h, i860.h, i960.h , m68k.h,
+ m88k.h, mips.h , np1.h, ns32k.h, pn.h, pyr.h, sparc.h, tahoe.h,
+ vax.h, ChangeLog: renamed from ../<foo>-opcode.h
+
+
+
+
+
diff --git a/gnu/usr.bin/as/opcode/a29k.h b/gnu/usr.bin/as/opcode/a29k.h
new file mode 100644
index 0000000..8c36167
--- /dev/null
+++ b/gnu/usr.bin/as/opcode/a29k.h
@@ -0,0 +1,327 @@
+/* Table of opcodes for the AMD 29000
+ Copyright (C) 1990, 1991 Free Software Foundation, Inc.
+
+This file is part of GDB and GAS.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 1, or (at your option)
+any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; see the file COPYING. If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+struct a29k_opcode {
+ /* Name of the instruction. */
+ char *name;
+
+ /* Opcode word */
+ unsigned long opcode;
+
+ /* A string of characters which describe the operands.
+ Valid characters are:
+ , Itself. The character appears in the assembly code.
+ a RA. The register number is in bits 8-15 of the instruction.
+ b RB. The register number is in bits 0-7 of the instruction.
+ c RC. The register number is in bits 16-23 of the instruction.
+ i An immediate operand is in bits 0-7 of the instruction.
+ x Bits 0-7 and 16-23 of the instruction are bits 0-7 and 8-15
+ (respectively) of the immediate operand.
+ h Same as x but the instruction contains bits 16-31 of the
+ immediate operand.
+ X Same as x but bits 16-31 of the signed immediate operand
+ are set to 1 (thus the operand is always negative).
+ P,A Bits 0-7 and 16-23 of the instruction are bits 2-9 and 10-17
+ (respectively) of the immediate operand.
+ P=PC-relative, sign-extended to 32 bits.
+ A=Absolute, zero-extended to 32 bits.
+ e CE bit (bit 23) for a load/store instruction.
+ n Control field (bits 16-22) for a load/store instruction.
+ v Immediate operand in bits 16-23 of the instruction.
+ (used for trap numbers).
+ s SA. Special-purpose register number in bits 8-15
+ of the instruction.
+ u UI--bit 7 of the instruction.
+ r RND--bits 4-6 of the instruction.
+ d FD--bits 2-3 of the instruction.
+ f FS--bits 0-1 of the instruction.
+
+ Extensions for 29050:
+
+ d FMT--bits 2-3 of the instruction (not really new).
+ f ACN--bits 0-1 of the instruction (not really new).
+ F FUNC--Special function in bits 18-21 of the instruction.
+ C ACN--bits 16-17 specifying the accumlator register. */
+ char *args;
+};
+
+#ifndef CONST
+#define CONST
+#endif /* CONST */
+
+static CONST struct a29k_opcode a29k_opcodes[] =
+{
+
+{ "add", 0x14000000, "c,a,b" },
+{ "add", 0x15000000, "c,a,i" },
+{ "addc", 0x1c000000, "c,a,b" },
+{ "addc", 0x1d000000, "c,a,i" },
+{ "addcs", 0x18000000, "c,a,b" },
+{ "addcs", 0x19000000, "c,a,i" },
+{ "addcu", 0x1a000000, "c,a,b" },
+{ "addcu", 0x1b000000, "c,a,i" },
+{ "adds", 0x10000000, "c,a,b" },
+{ "adds", 0x11000000, "c,a,i" },
+{ "addu", 0x12000000, "c,a,b" },
+{ "addu", 0x13000000, "c,a,i" },
+{ "and", 0x90000000, "c,a,b" },
+{ "and", 0x91000000, "c,a,i" },
+{ "andn", 0x9c000000, "c,a,b" },
+{ "andn", 0x9d000000, "c,a,i" },
+{ "aseq", 0x70000000, "v,a,b" },
+{ "aseq", 0x71000000, "v,a,i" },
+{ "asge", 0x5c000000, "v,a,b" },
+{ "asge", 0x5d000000, "v,a,i" },
+{ "asgeu", 0x5e000000, "v,a,b" },
+{ "asgeu", 0x5f000000, "v,a,i" },
+{ "asgt", 0x58000000, "v,a,b" },
+{ "asgt", 0x59000000, "v,a,i" },
+{ "asgtu", 0x5a000000, "v,a,b" },
+{ "asgtu", 0x5b000000, "v,a,i" },
+{ "asle", 0x54000000, "v,a,b" },
+{ "asle", 0x55000000, "v,a,i" },
+{ "asleu", 0x56000000, "v,a,b" },
+{ "asleu", 0x57000000, "v,a,i" },
+{ "aslt", 0x50000000, "v,a,b" },
+{ "aslt", 0x51000000, "v,a,i" },
+{ "asltu", 0x52000000, "v,a,b" },
+{ "asltu", 0x53000000, "v,a,i" },
+{ "asneq", 0x72000000, "v,a,b" },
+{ "asneq", 0x73000000, "v,a,i" },
+{ "call", 0xa8000000, "a,P" },
+{ "call", 0xa9000000, "a,A" },
+{ "calli", 0xc8000000, "a,b" },
+{ "class", 0xe6000000, "c,a,f" },
+{ "clz", 0x08000000, "c,b" },
+{ "clz", 0x09000000, "c,i" },
+{ "const", 0x03000000, "a,x" },
+{ "consth", 0x02000000, "a,h" },
+{ "consthz", 0x05000000, "a,h" },
+{ "constn", 0x01000000, "a,X" },
+{ "convert", 0xe4000000, "c,a,u,r,d,f" },
+{ "cpbyte", 0x2e000000, "c,a,b" },
+{ "cpbyte", 0x2f000000, "c,a,i" },
+{ "cpeq", 0x60000000, "c,a,b" },
+{ "cpeq", 0x61000000, "c,a,i" },
+{ "cpge", 0x4c000000, "c,a,b" },
+{ "cpge", 0x4d000000, "c,a,i" },
+{ "cpgeu", 0x4e000000, "c,a,b" },
+{ "cpgeu", 0x4f000000, "c,a,i" },
+{ "cpgt", 0x48000000, "c,a,b" },
+{ "cpgt", 0x49000000, "c,a,i" },
+{ "cpgtu", 0x4a000000, "c,a,b" },
+{ "cpgtu", 0x4b000000, "c,a,i" },
+{ "cple", 0x44000000, "c,a,b" },
+{ "cple", 0x45000000, "c,a,i" },
+{ "cpleu", 0x46000000, "c,a,b" },
+{ "cpleu", 0x47000000, "c,a,i" },
+{ "cplt", 0x40000000, "c,a,b" },
+{ "cplt", 0x41000000, "c,a,i" },
+{ "cpltu", 0x42000000, "c,a,b" },
+{ "cpltu", 0x43000000, "c,a,i" },
+{ "cpneq", 0x62000000, "c,a,b" },
+{ "cpneq", 0x63000000, "c,a,i" },
+{ "dadd", 0xf1000000, "c,a,b" },
+{ "ddiv", 0xf7000000, "c,a,b" },
+{ "deq", 0xeb000000, "c,a,b" },
+{ "dge", 0xef000000, "c,a,b" },
+{ "dgt", 0xed000000, "c,a,b" },
+{ "div", 0x6a000000, "c,a,b" },
+{ "div", 0x6b000000, "c,a,i" },
+{ "div0", 0x68000000, "c,b" },
+{ "div0", 0x69000000, "c,i" },
+{ "divide", 0xe1000000, "c,a,b" },
+{ "dividu", 0xe3000000, "c,a,b" },
+{ "divl", 0x6c000000, "c,a,b" },
+{ "divl", 0x6d000000, "c,a,i" },
+{ "divrem", 0x6e000000, "c,a,b" },
+{ "divrem", 0x6f000000, "c,a,i" },
+{ "dmac", 0xd9000000, "F,C,a,b" },
+{ "dmsm", 0xdb000000, "c,a,b" },
+{ "dmul", 0xf5000000, "c,a,b" },
+{ "dsub", 0xf3000000, "c,a,b" },
+{ "emulate", 0xd7000000, "v,a,b" },
+{ "exbyte", 0x0a000000, "c,a,b" },
+{ "exbyte", 0x0b000000, "c,a,i" },
+{ "exhw", 0x7c000000, "c,a,b" },
+{ "exhw", 0x7d000000, "c,a,i" },
+{ "exhws", 0x7e000000, "c,a" },
+{ "extract", 0x7a000000, "c,a,b" },
+{ "extract", 0x7b000000, "c,a,i" },
+{ "fadd", 0xf0000000, "c,a,b" },
+{ "fdiv", 0xf6000000, "c,a,b" },
+{ "fdmul", 0xf9000000, "c,a,b" },
+{ "feq", 0xea000000, "c,a,b" },
+{ "fge", 0xee000000, "c,a,b" },
+{ "fgt", 0xec000000, "c,a,b" },
+{ "fmac", 0xd8000000, "F,C,a,b" },
+{ "fmsm", 0xda000000, "c,a,b" },
+{ "fmul", 0xf4000000, "c,a,b" },
+{ "fsub", 0xf2000000, "c,a,b" },
+{ "halt", 0x89000000, "" },
+{ "inbyte", 0x0c000000, "c,a,b" },
+{ "inbyte", 0x0d000000, "c,a,i" },
+{ "inhw", 0x78000000, "c,a,b" },
+{ "inhw", 0x79000000, "c,a,i" },
+{ "inv", 0x9f000000, "" },
+{ "iret", 0x88000000, "" },
+{ "iretinv", 0x8c000000, "" },
+{ "jmp", 0xa0000000, "P" },
+{ "jmp", 0xa1000000, "A" },
+{ "jmpf", 0xa4000000, "a,P" },
+{ "jmpf", 0xa5000000, "a,A" },
+{ "jmpfdec", 0xb4000000, "a,P" },
+{ "jmpfdec", 0xb5000000, "a,A" },
+{ "jmpfi", 0xc4000000, "a,b" },
+{ "jmpi", 0xc0000000, "b" },
+{ "jmpt", 0xac000000, "a,P" },
+{ "jmpt", 0xad000000, "a,A" },
+{ "jmpti", 0xcc000000, "a,b" },
+{ "load", 0x16000000, "e,n,a,b" },
+{ "load", 0x17000000, "e,n,a,i" },
+{ "loadl", 0x06000000, "e,n,a,b" },
+{ "loadl", 0x07000000, "e,n,a,i" },
+{ "loadm", 0x36000000, "e,n,a,b" },
+{ "loadm", 0x37000000, "e,n,a,i" },
+{ "loadset", 0x26000000, "e,n,a,b" },
+{ "loadset", 0x27000000, "e,n,a,i" },
+{ "mfacc", 0xe9000100, "c,d,f" },
+{ "mfsr", 0xc6000000, "c,s" },
+{ "mftlb", 0xb6000000, "c,a" },
+{ "mtacc", 0xe8010000, "a,d,f" },
+{ "mtsr", 0xce000000, "s,b" },
+{ "mtsrim", 0x04000000, "s,x" },
+{ "mttlb", 0xbe000000, "a,b" },
+{ "mul", 0x64000000, "c,a,b" },
+{ "mul", 0x65000000, "c,a,i" },
+{ "mull", 0x66000000, "c,a,b" },
+{ "mull", 0x67000000, "c,a,i" },
+{ "multiplu", 0xe2000000, "c,a,b" },
+{ "multiply", 0xe0000000, "c,a,b" },
+{ "multm", 0xde000000, "c,a,b" },
+{ "multmu", 0xdf000000, "c,a,b" },
+{ "mulu", 0x74000000, "c,a,b" },
+{ "mulu", 0x75000000, "c,a,i" },
+{ "nand", 0x9a000000, "c,a,b" },
+{ "nand", 0x9b000000, "c,a,i" },
+{ "nop", 0x70400101, "" },
+{ "nor", 0x98000000, "c,a,b" },
+{ "nor", 0x99000000, "c,a,i" },
+{ "or", 0x92000000, "c,a,b" },
+{ "or", 0x93000000, "c,a,i" },
+{ "orn", 0xaa000000, "c,a,b" },
+{ "orn", 0xab000000, "c,a,i" },
+
+/* The description of "setip" in Chapter 8 ("instruction set") of the user's
+ manual claims that these are absolute register numbers. But section
+ 7.2.1 explains that they are not. The latter is correct, so print
+ these normally ("lr0", "lr5", etc.). */
+{ "setip", 0x9e000000, "c,a,b" },
+
+{ "sll", 0x80000000, "c,a,b" },
+{ "sll", 0x81000000, "c,a,i" },
+{ "sqrt", 0xe5000000, "c,a,f" },
+{ "sra", 0x86000000, "c,a,b" },
+{ "sra", 0x87000000, "c,a,i" },
+{ "srl", 0x82000000, "c,a,b" },
+{ "srl", 0x83000000, "c,a,i" },
+{ "store", 0x1e000000, "e,n,a,b" },
+{ "store", 0x1f000000, "e,n,a,i" },
+{ "storel", 0x0e000000, "e,n,a,b" },
+{ "storel", 0x0f000000, "e,n,a,i" },
+{ "storem", 0x3e000000, "e,n,a,b" },
+{ "storem", 0x3f000000, "e,n,a,i" },
+{ "sub", 0x24000000, "c,a,b" },
+{ "sub", 0x25000000, "c,a,i" },
+{ "subc", 0x2c000000, "c,a,b" },
+{ "subc", 0x2d000000, "c,a,i" },
+{ "subcs", 0x28000000, "c,a,b" },
+{ "subcs", 0x29000000, "c,a,i" },
+{ "subcu", 0x2a000000, "c,a,b" },
+{ "subcu", 0x2b000000, "c,a,i" },
+{ "subr", 0x34000000, "c,a,b" },
+{ "subr", 0x35000000, "c,a,i" },
+{ "subrc", 0x3c000000, "c,a,b" },
+{ "subrc", 0x3d000000, "c,a,i" },
+{ "subrcs", 0x38000000, "c,a,b" },
+{ "subrcs", 0x39000000, "c,a,i" },
+{ "subrcu", 0x3a000000, "c,a,b" },
+{ "subrcu", 0x3b000000, "c,a,i" },
+{ "subrs", 0x30000000, "c,a,b" },
+{ "subrs", 0x31000000, "c,a,i" },
+{ "subru", 0x32000000, "c,a,b" },
+{ "subru", 0x33000000, "c,a,i" },
+{ "subs", 0x20000000, "c,a,b" },
+{ "subs", 0x21000000, "c,a,i" },
+{ "subu", 0x22000000, "c,a,b" },
+{ "subu", 0x23000000, "c,a,i" },
+{ "xnor", 0x96000000, "c,a,b" },
+{ "xnor", 0x97000000, "c,a,i" },
+{ "xor", 0x94000000, "c,a,b" },
+{ "xor", 0x95000000, "c,a,i" },
+
+{ "", 0x0, "" } /* Dummy entry, not included in NUM_OPCODES. This
+ lets code examine entry i+1 without checking
+ if we've run off the end of the table. */
+};
+
+CONST unsigned int num_opcodes = (((sizeof a29k_opcodes) / (sizeof a29k_opcodes[0])) - 1);
+
+/*
+ * $Log: a29k.h,v $
+ * Revision 1.1 1993/10/02 21:00:40 pk
+ * GNU gas 1.92.3 based assembler supporting PIC code (for i386 and sparc).
+ *
+ * Revision 1.2 1992/02/29 17:10:43 rich
+ * various smallish fixes from mail archives
+ *
+ * Revision 1.1.1.1 1992/02/24 02:34:30 rich
+ * devo fork
+ *
+ * Revision 1.1 1991/12/01 02:22:19 sac
+ * Initial revision
+ *
+ * Revision 1.5 1991/11/07 16:59:19 sac
+ * Fixed encoding of mtacc instruction.
+ *
+ * Revision 1.4 1991/08/06 07:20:27 rich
+ * Fixing CONST declarations.
+ *
+ * Revision 1.3 1991/08/05 22:31:05 rich
+ * *** empty log message ***
+ *
+ * Revision 1.2 1991/07/15 23:34:04 steve
+ * *** empty log message ***
+ *
+ * Revision 1.1 1991/05/19 00:19:33 rich
+ * Initial revision
+ *
+ * Revision 1.1.1.1 1991/04/04 18:15:23 rich
+ * new gas main line
+ *
+ * Revision 1.1 1991/04/04 18:15:23 rich
+ * Initial revision
+ *
+ * Revision 1.2 1991/03/30 17:13:19 rich
+ * num_opcodes now unsigned. Also, added rcsid and log.
+ *
+ *
+ */
+
+/* end of a29k-opcode.h */
diff --git a/gnu/usr.bin/as/opcode/h8300.h b/gnu/usr.bin/as/opcode/h8300.h
new file mode 100644
index 0000000..59dea0d
--- /dev/null
+++ b/gnu/usr.bin/as/opcode/h8300.h
@@ -0,0 +1,266 @@
+/* Opcode table for the H8-300
+ Copyright (C) 1991,1992 Free Software Foundation.
+ Written by Steve Chamberlain, sac@cygnus.com.
+
+This file is part of GDB, the GNU Debugger and GAS, the GNU Assembler.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+typedef int op_type;
+
+#define Hex0 0
+#define Hex1 1
+#define Hex2 2
+#define Hex3 3
+#define Hex4 4
+#define Hex5 5
+#define Hex6 6
+#define Hex7 7
+#define Hex8 8
+#define Hex9 9
+#define HexA 10
+#define HexB 11
+#define HexC 12
+#define HexD 13
+#define HexE 14
+#define HexF 15
+#define START 0x20
+#define KBIT 0x21 /* K is #1, or #2, yielding 0x0 or 0x8 */
+#define IMM3 0x22 /* bit number */
+#define RD8 0x23 /* 8 bit reg as 2nd op */
+#define RD16 0x24 /* 16 bit reg as 2nd op */
+#define RS8 0x25 /* 8 bit reg as 1st op */
+#define RS16 0x26 /* 16 bit reg 1st op */
+#define IMM8 0x27 /* constant which fits into 8 bits */
+#define IMM16 0x28 /* constant which fits into 16 bits */
+#define CCR 0x29 /* CCR reg */
+#define ABS8SRC 0x2a /* abs 8 address mode */
+#define ABS8DST 0x2b /* abs 8 address mode */
+#define DISP8 0x2c /* pc rel displacement */
+#define ABS16SRC 0x2d /* abs 16 address mode */
+#define ABS16OR8SRC 0x2e /* abs 16 address mode, but could be abs 8 */
+#define ABS16DST 0x2f /* abs 16 address mode */
+#define ABS16OR8DST 0x30 /* abs 16 address mode */
+#define DISPSRC 0x31 /* @(r:16) address mode src */
+#define DISPDST 0x32 /* @(r:16) address mode dst*/
+#define DISPREG 0x33 /* register from DISP address mode */
+#define RDDEC 0x34 /* @-rn mode */
+#define RSINC 0x35 /* @rn+ mode */
+#define RDIND 0x36 /* @R mode dst */
+#define RSIND 0x37 /* @R mode src */
+#define MEMIND 0x38 /* @@abs8 mode */
+#define ABS16ORREL8SRC 0x39 /* abs 16bit or pcrel */
+#define IGNORE 0x3a
+#define B30 0x40 /* bit 3 must be low */
+#define B31 0x80 /* bit 3 must be high */
+#define E 0x81 /* End of list */
+
+
+
+struct code
+{
+ op_type nib[9];
+} ;
+
+struct arg
+{
+ op_type nib[3];
+} ;
+
+struct h8_opcode
+{
+ char *name;
+ struct arg args;
+ struct code data;
+ char length;
+ char noperands;
+ char idx;
+ char size;
+
+};
+
+
+
+
+
+#ifdef DEFINE_TABLE
+
+#define BITOP(imm, name, op00, op01,op10,op11, op20,op21)\
+{ name, {imm,RD8,E}, {op00, op01, imm, RD8,E}},\
+{ name, {imm,RDIND,E}, {op10, op11, RDIND, 0, op00,op01, imm, 0,E}},\
+{ name, {imm,ABS8DST,E},{op20, op21, ABS8DST, IGNORE, op00,op01, imm, 0,E}}
+
+#define EBITOP(imm, name, op00, op01,op10,op11, op20,op21)\
+ BITOP(imm, name, op00+1, op01, op10,op11, op20,op21),\
+ BITOP(RS8, name, op00, op01, op10,op11, op20,op21)
+
+#define WTWOP(name, op1, op2) \
+{ name, {RS16, RD16, E}, { op1, op2, RS16, RD16, E}}
+
+#define BRANCH(name, op) \
+{ name,{DISP8,E}, { Hex4, op, DISP8,IGNORE,E }}
+
+#define SOP(name) \
+{ name
+#define EOP }
+
+
+#define TWOOP(name, op1, op2,op3) \
+{ name, {IMM8, RD8,E}, { op1, RD8, IMM8,IGNORE,E}},\
+{ name, {RS8, RD8, E}, { op2, op3, RS8, RD8 ,E}}
+
+#define UNOP(name, op1, op2) \
+{ name, {RS8, E}, { op1, op2, 0, RS8, E}}
+
+#define UNOP3(name, op1, op2, op3) \
+{ name , {RS8, E}, {op1, op2, op3, RS8, E}}
+
+struct h8_opcode h8_opcodes[]
+=
+{
+ TWOOP("add.b", Hex8, Hex0,Hex8),
+ WTWOP("add.w", Hex0, Hex9),
+ SOP("adds"), {KBIT,RD16|B30, E}, {Hex0, HexB, KBIT, RD16|B30, E} EOP,
+ TWOOP("addx", Hex9,Hex0,HexE),
+ TWOOP("and", HexE,Hex1,Hex6),
+ SOP("andc"), {IMM8, CCR, E}, { Hex0, Hex6, IMM8,IGNORE, E} EOP,
+ BITOP(IMM3|B30, "band", Hex7, Hex6, Hex7, HexC, Hex7, HexE),
+ BRANCH("bra", Hex0),
+ BRANCH("bt", Hex0),
+ BRANCH("brn", Hex1),
+ BRANCH("bf", Hex1),
+ BRANCH("bhi", Hex2),
+ BRANCH("bls", Hex3),
+ BRANCH("bcc", Hex4),
+ BRANCH("bhs", Hex4),
+ BRANCH("bcs", Hex5),
+ BRANCH("blo", Hex5),
+ BRANCH("bne", Hex6),
+ BRANCH("beq", Hex7),
+ BRANCH("bvc", Hex8),
+ BRANCH("bvs", Hex9),
+ BRANCH("bpl", HexA),
+ BRANCH("bmi", HexB),
+ BRANCH("bge", HexC),
+ BRANCH("blt", HexD),
+ BRANCH("bgt", HexE),
+ BRANCH("ble", HexF),
+ EBITOP(IMM3|B30,"bclr", Hex6, Hex2, Hex7, HexD, Hex7, HexF),
+ BITOP(IMM3|B31,"biand", Hex7, Hex6, Hex7, HexC, Hex7, HexE),
+ BITOP(IMM3|B31, "bild", Hex7, Hex7,Hex7, HexC, Hex7, HexE),
+ BITOP(IMM3|B31, "bior", Hex7, Hex4,Hex7, HexC, Hex7, HexE),
+ BITOP(IMM3|B31, "bist", Hex6, Hex7,Hex7, HexD, Hex7, HexE),
+ BITOP(IMM3|B31, "bixor", Hex7, Hex5,Hex7, HexC, Hex7, HexE),
+ BITOP(IMM3|B30, "bld", Hex7, Hex7,Hex7, HexC, Hex7, HexE),
+ EBITOP(IMM3|B30,"bnot", Hex6, Hex1, Hex7, HexD, Hex7, HexF),
+ BITOP(IMM3|B30,"bor", Hex7, Hex4,Hex7, HexC, Hex7, HexE),
+ EBITOP(IMM3|B30,"bset", Hex6, Hex0,Hex7, HexD, Hex7, HexF),
+ SOP("bsr"),{DISP8, E},{ Hex5, Hex5, DISP8,IGNORE, E}, EOP,
+ BITOP(IMM3|B30, "bst", Hex6, Hex7,Hex7, HexD, Hex7, HexF),
+ EBITOP(IMM3|B30, "btst", Hex6, Hex3,Hex7, HexC, Hex7, HexE),
+ BITOP(IMM3|B30, "bxor", Hex7,Hex5,Hex7, HexC, Hex7, HexE),
+ TWOOP( "cmp.b",HexA, Hex1, HexC),
+ WTWOP( "cmp.w",Hex1,HexD),
+ UNOP( "daa",Hex0, HexF),
+ UNOP( "das",Hex1, HexF),
+ UNOP( "dec",Hex1, HexA),
+ SOP("divxu"),{RS8, RD16|B30, E}, { Hex5, Hex1, RS8, RD16|B30, E} EOP,
+ SOP("eepmov"),{ E}, {Hex7, HexB, Hex5, HexC, Hex5, Hex9, Hex8, HexF,E} EOP,
+ UNOP( "inc", Hex0, HexA),
+ SOP("jmp"),{RSIND|B30, E}, {Hex5, Hex9, RSIND|B30, Hex0, E} EOP,
+ SOP("jmp"),{ABS16ORREL8SRC, E}, {Hex5, HexA, Hex0, Hex0, ABS16ORREL8SRC, IGNORE,IGNORE,IGNORE,E} EOP,
+ SOP("jmp"),{MEMIND, E}, {Hex5, HexB, MEMIND,IGNORE, E} EOP,
+ SOP("jsr"),{RSIND|B30, E}, {Hex5, HexD, RSIND|B30, Hex0, E} EOP,
+ SOP("jsr"),{ABS16ORREL8SRC, E}, {Hex5, HexE, Hex0, Hex0,
+ ABS16ORREL8SRC,IGNORE,IGNORE,IGNORE, E} EOP,
+ SOP("jsr"),{MEMIND, E}, {Hex5, HexF, MEMIND, IGNORE,E} EOP,
+ SOP("ldc"),{IMM8, CCR, E}, { Hex0, Hex7, IMM8,IGNORE, E} EOP,
+ SOP("ldc"),{RS8, CCR, E}, { Hex0, Hex3, Hex0, RS8, E} EOP,
+ SOP("mov.b"),{RS8, RD8, E}, { Hex0, HexC, RS8, RD8, E} EOP,
+ SOP("mov.b"),{IMM8, RD8, E}, { HexF, RD8, IMM8,IGNORE, E} EOP,
+ SOP("mov.b"),{RSIND|B30,RD8, E}, { Hex6, Hex8, RSIND|B30, RD8, E} EOP,
+ SOP("mov.b"),{DISPSRC,RD8, E}, { Hex6, HexE, DISPREG|B30, RD8,
+ DISPSRC, IGNORE, IGNORE, IGNORE, E} EOP,
+ SOP("mov.b"),{RSINC|B30, RD8, E}, { Hex6, HexC, RSINC|B30, RD8, E} EOP,
+ SOP("mov.b"),{ABS16OR8SRC, RD8, E}, { Hex6, HexA, Hex0, RD8,ABS16OR8SRC,
+ IGNORE,IGNORE,IGNORE,E} EOP,
+ SOP("mov.b"),{ABS8SRC, RD8, E}, { Hex2, RD8, ABS8SRC,IGNORE, E} EOP,
+ SOP("mov.b"),{RS8, RDIND|B30, E}, { Hex6, Hex8, RDIND|B31, RS8, E} EOP,
+ SOP("mov.b"),{RS8, DISPDST, E}, { Hex6, HexE, DISPREG|B31,
+ RS8,DISPDST, IGNORE, IGNORE, IGNORE, E} EOP,
+ SOP("mov.b"),{RS8, RDDEC|B31, E}, { Hex6, HexC, RDDEC|B31, RS8, E} EOP,
+ SOP( "mov.b"),{RS8, ABS16OR8DST, E}, { Hex6, HexA, Hex8, RS8,
+ ABS16OR8DST,IGNORE,IGNORE,IGNORE, E} EOP,
+ SOP( "mov.b"),{RS8, ABS8DST, E}, { Hex3, RS8, ABS8DST,IGNORE, E} EOP,
+ SOP( "mov.w"),{RS16|B30, RD16|B30, E},{ Hex0, HexD, RS16|B30,
+ RD16|B30, E} EOP,
+ SOP("mov.w"),{IMM16, RD16|B30, E}, { Hex7, Hex9, Hex0, RD16|B30,
+ IMM16,IGNORE,IGNORE,IGNORE, E} EOP,
+ SOP("mov.w"),{RSIND|B30,RD16|B30, E},{ Hex6, Hex9, RSIND|B30,
+ RD16|B30, E} EOP,
+ SOP("mov.w"),{DISPSRC,RD16|B30, E}, { Hex6, HexF, DISPREG|B30,
+ RD16|B30, DISPSRC, IGNORE, IGNORE, IGNORE,E} EOP,
+ SOP("mov.w"),{RSINC|B30, RD16|B30, E}, { Hex6, HexD, RSINC|B30,
+ RD16|B30, E}EOP,
+ SOP("mov.w"), {ABS16SRC, RD16|B30, E}, { Hex6, HexB, Hex0,
+ RD16|B30,ABS16SRC,IGNORE,IGNORE,IGNORE, E} EOP,
+SOP("mov.w"), {RS16|B30, RDIND|B30, E},{ Hex6, Hex9, RDIND|B31,
+ RS16|B30, E} EOP,
+SOP("mov.w"), {RS16|B30, DISPDST, E}, { Hex6, HexF, DISPREG|B31,
+ RS16|B30,DISPDST, IGNORE,IGNORE,IGNORE,E} EOP,
+SOP("mov.w"), {RS16|B30, RDDEC|B30, E},{ Hex6, HexD, RDDEC|B31,
+ RS16|B30, E} EOP,
+SOP("mov.w"), {RS16|B30, ABS16DST, E}, { Hex6, HexB, Hex8, RS16|B30,
+ ABS16DST, IGNORE, IGNORE, IGNORE, E} EOP,
+SOP("movfpe"), {ABS16SRC, RD8, E}, { Hex6, HexA, Hex4, RD8,
+ ABS16SRC,IGNORE,IGNORE,IGNORE, E} EOP,
+SOP("movtpe"), {RS8, ABS16DST, E}, { Hex6, HexA, HexC, RS8,
+ ABS16DST,IGNORE,IGNORE,IGNORE,
+ E} EOP,
+SOP("mulxu"), {RS8, RD16|B30, E}, { Hex5, Hex0, RS8, RD16|B30, E} EOP,
+SOP( "neg"), {RS8, E}, { Hex1, Hex7, Hex8, RS8, E} EOP,
+SOP( "nop"), {E}, { Hex0, Hex0, Hex0, Hex0,E} EOP,
+SOP( "not"), {RS8,E}, { Hex1, Hex7, Hex0, RS8,E} EOP,
+TWOOP("or", HexC, Hex1, Hex4),
+SOP( "orc"), {IMM8, CCR,E}, { Hex0, Hex4, IMM8,IGNORE,E} EOP,
+SOP( "pop"), {RS16|B30,E}, { Hex6, HexD, Hex7, RS16|B30,E} EOP,
+SOP( "push"), {RS16|B30,E}, { Hex6, HexD, HexF, RS16|B30,E} EOP,
+ UNOP3( "rotl",Hex1, Hex2,Hex8),
+ UNOP3( "rotr",Hex1, Hex3, Hex8),
+ UNOP3( "rotxl",Hex1, Hex2, Hex0),
+ UNOP3( "rotxr",Hex1, Hex3, Hex0),
+SOP("rte"), {E}, { Hex5, Hex6, Hex7, Hex0,E} EOP,
+SOP("rts"), {E}, { Hex5, Hex4, Hex7, Hex0,E} EOP,
+ UNOP3( "shal", Hex1, Hex0, Hex8),
+ UNOP3( "shar", Hex1, Hex1, Hex8),
+ UNOP3( "shll", Hex1, Hex0, Hex0),
+ UNOP3( "shlr", Hex1, Hex1, Hex0),
+SOP("sleep"), {E}, { Hex0, Hex1, Hex8, Hex0,E} EOP,
+SOP("stc"), {CCR, RD8,E}, { Hex0, Hex2, Hex0, RD8,E} EOP,
+SOP("sub.b"), {RS8,RD8,E}, { Hex1, Hex8, RS8, RD8,E} EOP,
+SOP("sub.w"), {RS16|B30, RD16|B30,E}, {Hex1, Hex9, RS16|B30,RD16|B30,E} EOP,
+SOP("subs"), {KBIT,RD16|B30,E}, { Hex1, HexB, KBIT, RD16|B30,E} EOP,
+ TWOOP("subx",HexB, Hex1, HexE),
+ TWOOP("xor", HexD, Hex1, Hex5),
+SOP("xorc"), {IMM8, CCR,E}, { Hex0, Hex5, IMM8,IGNORE,E} EOP,
+ 0
+};
+#else
+extern struct h8_opcode h8_opcodes[] ;
+#endif
+
+
+
+
diff --git a/gnu/usr.bin/as/opcode/i386.h b/gnu/usr.bin/as/opcode/i386.h
new file mode 100644
index 0000000..0c66357
--- /dev/null
+++ b/gnu/usr.bin/as/opcode/i386.h
@@ -0,0 +1,833 @@
+/* i386-opcode.h -- Intel 80386 opcode table
+ Copyright (C) 1989, 1991, Free Software Foundation.
+
+This file is part of GAS, the GNU Assembler.
+
+GAS is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 1, or (at your option)
+any later version.
+
+GAS is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GAS; see the file COPYING. If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* $Id: i386.h,v 1.2 1994/12/11 20:46:55 sef Exp $ */
+
+static const template i386_optab[] = {
+
+#define _ None
+/* move instructions */
+{ "mov", 2, 0xa0, _, DW|NoModrm, Disp32, Acc, 0 },
+{ "mov", 2, 0x88, _, DW|Modrm, Reg, Reg|Mem, 0 },
+{ "mov", 2, 0xb0, _, ShortFormW, Imm, Reg, 0 },
+{ "mov", 2, 0xc6, _, W|Modrm, Imm, Reg|Mem, 0 },
+{ "mov", 2, 0x8c, _, D|Modrm, SReg3|SReg2, Reg16|Mem16, 0 },
+/* move to/from control debug registers */
+{ "mov", 2, 0x0f20, _, D|Modrm, Control, Reg32, 0},
+{ "mov", 2, 0x0f21, _, D|Modrm, Debug, Reg32, 0},
+{ "mov", 2, 0x0f24, _, D|Modrm, Test, Reg32, 0},
+
+/* move with sign extend */
+/* "movsbl" & "movsbw" must not be unified into "movsb" to avoid
+ conflict with the "movs" string move instruction. Thus,
+ {"movsb", 2, 0x0fbe, _, ReverseRegRegmem|Modrm, Reg8|Mem, Reg16|Reg32, 0},
+ is not kosher; we must seperate the two instructions. */
+{"movsbl", 2, 0x0fbe, _, ReverseRegRegmem|Modrm, Reg8|Mem, Reg32, 0},
+{"movsbw", 2, 0x660fbe, _, ReverseRegRegmem|Modrm, Reg8|Mem, Reg16, 0},
+{"movswl", 2, 0x0fbf, _, ReverseRegRegmem|Modrm, Reg16|Mem, Reg32, 0},
+
+/* move with zero extend */
+{"movzb", 2, 0x0fb6, _, ReverseRegRegmem|Modrm, Reg8|Mem, Reg16|Reg32, 0},
+{"movzwl", 2, 0x0fb7, _, ReverseRegRegmem|Modrm, Reg16|Mem, Reg32, 0},
+
+/* push instructions */
+{"push", 1, 0x50, _, ShortForm, WordReg,0,0 },
+{"push", 1, 0xff, 0x6, Modrm, WordReg|WordMem, 0, 0 },
+{"push", 1, 0x6a, _, NoModrm, Imm8S, 0, 0},
+{"push", 1, 0x68, _, NoModrm, Imm16|Imm32, 0, 0},
+{"push", 1, 0x06, _, Seg2ShortForm, SReg2,0,0 },
+{"push", 1, 0x0fa0, _, Seg3ShortForm, SReg3,0,0 },
+/* push all */
+{"pusha", 0, 0x60, _, NoModrm, 0, 0, 0 },
+
+/* pop instructions */
+{"pop", 1, 0x58, _, ShortForm, WordReg,0,0 },
+{"pop", 1, 0x8f, 0x0, Modrm, WordReg|WordMem, 0, 0 },
+#define POP_SEG_SHORT 0x7
+{"pop", 1, 0x07, _, Seg2ShortForm, SReg2,0,0 },
+{"pop", 1, 0x0fa1, _, Seg3ShortForm, SReg3,0,0 },
+/* pop all */
+{"popa", 0, 0x61, _, NoModrm, 0, 0, 0 },
+
+/* xchg exchange instructions
+ xchg commutes: we allow both operand orders */
+{"xchg", 2, 0x90, _, ShortForm, WordReg, Acc, 0 },
+{"xchg", 2, 0x90, _, ShortForm, Acc, WordReg, 0 },
+{"xchg", 2, 0x86, _, W|Modrm, Reg, Reg|Mem, 0 },
+{"xchg", 2, 0x86, _, W|Modrm, Reg|Mem, Reg, 0 },
+
+/* in/out from ports */
+{"in", 2, 0xe4, _, W|NoModrm, Imm8, Acc, 0 },
+{"in", 2, 0xec, _, W|NoModrm, InOutPortReg, Acc, 0 },
+{"out", 2, 0xe6, _, W|NoModrm, Acc, Imm8, 0 },
+{"out", 2, 0xee, _, W|NoModrm, Acc, InOutPortReg, 0 },
+
+#if 0
+{"inb", 1, 0xe4, _, NoModrm, Imm8, 0, 0 },
+{"inb", 1, 0xec, _, NoModrm, WordMem, 0, 0 },
+{"inw", 1, 0x66e5, _, NoModrm, Imm8, 0, 0 },
+{"inw", 1, 0x66ed, _, NoModrm, WordMem, 0, 0 },
+{"outb", 1, 0xe6, _, NoModrm, Imm8, 0, 0 },
+{"outb", 1, 0xee, _, NoModrm, WordMem, 0, 0 },
+{"outw", 1, 0x66e7, _, NoModrm, Imm8, 0, 0 },
+{"outw", 1, 0x66ef, _, NoModrm, WordMem, 0, 0 },
+#endif
+
+/* load effective address */
+{"lea", 2, 0x8d, _, Modrm, WordMem, WordReg, 0 },
+
+/* load segment registers from memory */
+{"lds", 2, 0xc5, _, Modrm, Mem, Reg32, 0},
+{"les", 2, 0xc4, _, Modrm, Mem, Reg32, 0},
+{"lfs", 2, 0x0fb4, _, Modrm, Mem, Reg32, 0},
+{"lgs", 2, 0x0fb5, _, Modrm, Mem, Reg32, 0},
+{"lss", 2, 0x0fb2, _, Modrm, Mem, Reg32, 0},
+
+/* flags register instructions */
+{"clc", 0, 0xf8, _, NoModrm, 0, 0, 0},
+{"cld", 0, 0xfc, _, NoModrm, 0, 0, 0},
+{"cli", 0, 0xfa, _, NoModrm, 0, 0, 0},
+{"clts", 0, 0x0f06, _, NoModrm, 0, 0, 0},
+{"cmc", 0, 0xf5, _, NoModrm, 0, 0, 0},
+{"lahf", 0, 0x9f, _, NoModrm, 0, 0, 0},
+{"sahf", 0, 0x9e, _, NoModrm, 0, 0, 0},
+{"pushf", 0, 0x9c, _, NoModrm, 0, 0, 0},
+{"popf", 0, 0x9d, _, NoModrm, 0, 0, 0},
+{"stc", 0, 0xf9, _, NoModrm, 0, 0, 0},
+{"std", 0, 0xfd, _, NoModrm, 0, 0, 0},
+{"sti", 0, 0xfb, _, NoModrm, 0, 0, 0},
+
+{"add", 2, 0x0, _, DW|Modrm, Reg, Reg|Mem, 0},
+{"add", 2, 0x83, 0, Modrm, Imm8S, WordReg|WordMem, 0},
+{"add", 2, 0x4, _, W|NoModrm, Imm, Acc, 0},
+{"add", 2, 0x80, 0, W|Modrm, Imm, Reg|Mem, 0},
+
+{"inc", 1, 0x40, _, ShortForm, WordReg, 0, 0},
+{"inc", 1, 0xfe, 0, W|Modrm, Reg|Mem, 0, 0},
+
+{"sub", 2, 0x28, _, DW|Modrm, Reg, Reg|Mem, 0},
+{"sub", 2, 0x83, 5, Modrm, Imm8S, WordReg|WordMem, 0},
+{"sub", 2, 0x2c, _, W|NoModrm, Imm, Acc, 0},
+{"sub", 2, 0x80, 5, W|Modrm, Imm, Reg|Mem, 0},
+
+{"dec", 1, 0x48, _, ShortForm, WordReg, 0, 0},
+{"dec", 1, 0xfe, 1, W|Modrm, Reg|Mem, 0, 0},
+
+{"sbb", 2, 0x18, _, DW|Modrm, Reg, Reg|Mem, 0},
+{"sbb", 2, 0x83, 3, Modrm, Imm8S, WordReg|WordMem, 0},
+{"sbb", 2, 0x1c, _, W|NoModrm, Imm, Acc, 0},
+{"sbb", 2, 0x80, 3, W|Modrm, Imm, Reg|Mem, 0},
+
+{"cmp", 2, 0x38, _, DW|Modrm, Reg, Reg|Mem, 0},
+{"cmp", 2, 0x83, 7, Modrm, Imm8S, WordReg|WordMem, 0},
+{"cmp", 2, 0x3c, _, W|NoModrm, Imm, Acc, 0},
+{"cmp", 2, 0x80, 7, W|Modrm, Imm, Reg|Mem, 0},
+
+{"test", 2, 0x84, _, W|Modrm, Reg|Mem, Reg, 0},
+{"test", 2, 0x84, _, W|Modrm, Reg, Reg|Mem, 0},
+{"test", 2, 0xa8, _, W|NoModrm, Imm, Acc, 0},
+{"test", 2, 0xf6, 0, W|Modrm, Imm, Reg|Mem, 0},
+
+{"and", 2, 0x20, _, DW|Modrm, Reg, Reg|Mem, 0},
+{"and", 2, 0x83, 4, Modrm, Imm8S, WordReg|WordMem, 0},
+{"and", 2, 0x24, _, W|NoModrm, Imm, Acc, 0},
+{"and", 2, 0x80, 4, W|Modrm, Imm, Reg|Mem, 0},
+
+{"or", 2, 0x08, _, DW|Modrm, Reg, Reg|Mem, 0},
+{"or", 2, 0x83, 1, Modrm, Imm8S, WordReg|WordMem, 0},
+{"or", 2, 0x0c, _, W|NoModrm, Imm, Acc, 0},
+{"or", 2, 0x80, 1, W|Modrm, Imm, Reg|Mem, 0},
+
+{"xor", 2, 0x30, _, DW|Modrm, Reg, Reg|Mem, 0},
+{"xor", 2, 0x83, 6, Modrm, Imm8S, WordReg|WordMem, 0},
+{"xor", 2, 0x34, _, W|NoModrm, Imm, Acc, 0},
+{"xor", 2, 0x80, 6, W|Modrm, Imm, Reg|Mem, 0},
+
+{"adc", 2, 0x10, _, DW|Modrm, Reg, Reg|Mem, 0},
+{"adc", 2, 0x83, 2, Modrm, Imm8S, WordReg|WordMem, 0},
+{"adc", 2, 0x14, _, W|NoModrm, Imm, Acc, 0},
+{"adc", 2, 0x80, 2, W|Modrm, Imm, Reg|Mem, 0},
+
+{"neg", 1, 0xf6, 3, W|Modrm, Reg|Mem, 0, 0},
+{"not", 1, 0xf6, 2, W|Modrm, Reg|Mem, 0, 0},
+
+{"aaa", 0, 0x37, _, NoModrm, 0, 0, 0},
+{"aas", 0, 0x3f, _, NoModrm, 0, 0, 0},
+{"daa", 0, 0x27, _, NoModrm, 0, 0, 0},
+{"das", 0, 0x2f, _, NoModrm, 0, 0, 0},
+{"aad", 0, 0xd50a, _, NoModrm, 0, 0, 0},
+{"aam", 0, 0xd40a, _, NoModrm, 0, 0, 0},
+
+/* conversion insns */
+/* conversion: intel naming */
+{"cbw", 0, 0x6698, _, NoModrm, 0, 0, 0},
+{"cwd", 0, 0x6699, _, NoModrm, 0, 0, 0},
+{"cwde", 0, 0x98, _, NoModrm, 0, 0, 0},
+{"cdq", 0, 0x99, _, NoModrm, 0, 0, 0},
+/* att naming */
+{"cbtw", 0, 0x6698, _, NoModrm, 0, 0, 0},
+{"cwtl", 0, 0x98, _, NoModrm, 0, 0, 0},
+{"cwtd", 0, 0x6699, _, NoModrm, 0, 0, 0},
+{"cltd", 0, 0x99, _, NoModrm, 0, 0, 0},
+
+/* Warning! the mul/imul (opcode 0xf6) must only have 1 operand! They are
+ expanding 64-bit multiplies, and *cannot* be selected to accomplish
+ 'imul %ebx, %eax' (opcode 0x0faf must be used in this case)
+ These multiplies can only be selected with single opearnd forms. */
+{"mul", 1, 0xf6, 4, W|Modrm, Reg|Mem, 0, 0},
+{"imul", 1, 0xf6, 5, W|Modrm, Reg|Mem, 0, 0},
+
+
+
+
+/* imulKludge here is needed to reverse the i.rm.reg & i.rm.regmem fields.
+ These instructions are exceptions: 'imul $2, %eax, %ecx' would put
+ '%eax' in the reg field and '%ecx' in the regmem field if we did not
+ switch them. */
+{"imul", 2, 0x0faf, _, Modrm|ReverseRegRegmem, WordReg|Mem, WordReg, 0},
+{"imul", 3, 0x6b, _, Modrm|ReverseRegRegmem, Imm8S, WordReg|Mem, WordReg},
+{"imul", 3, 0x69, _, Modrm|ReverseRegRegmem, Imm16|Imm32, WordReg|Mem, WordReg},
+/*
+ imul with 2 operands mimicks imul with 3 by puting register both
+ in i.rm.reg & i.rm.regmem fields
+*/
+{"imul", 2, 0x6b, _, Modrm|imulKludge, Imm8S, WordReg, 0},
+{"imul", 2, 0x69, _, Modrm|imulKludge, Imm16|Imm32, WordReg, 0},
+{"div", 1, 0xf6, 6, W|Modrm, Reg|Mem, 0, 0},
+{"div", 2, 0xf6, 6, W|Modrm, Reg|Mem, Acc, 0},
+{"idiv", 1, 0xf6, 7, W|Modrm, Reg|Mem, 0, 0},
+{"idiv", 2, 0xf6, 7, W|Modrm, Reg|Mem, Acc, 0},
+
+{"rol", 2, 0xd0, 0, W|Modrm, Imm1, Reg|Mem, 0},
+{"rol", 2, 0xc0, 0, W|Modrm, Imm8, Reg|Mem, 0},
+{"rol", 2, 0xd2, 0, W|Modrm, ShiftCount, Reg|Mem, 0},
+{"rol", 1, 0xd0, 0, W|Modrm, Reg|Mem, 0, 0},
+
+{"ror", 2, 0xd0, 1, W|Modrm, Imm1, Reg|Mem, 0},
+{"ror", 2, 0xc0, 1, W|Modrm, Imm8, Reg|Mem, 0},
+{"ror", 2, 0xd2, 1, W|Modrm, ShiftCount, Reg|Mem, 0},
+{"ror", 1, 0xd0, 1, W|Modrm, Reg|Mem, 0, 0},
+
+{"rcl", 2, 0xd0, 2, W|Modrm, Imm1, Reg|Mem, 0},
+{"rcl", 2, 0xc0, 2, W|Modrm, Imm8, Reg|Mem, 0},
+{"rcl", 2, 0xd2, 2, W|Modrm, ShiftCount, Reg|Mem, 0},
+{"rcl", 1, 0xd0, 2, W|Modrm, Reg|Mem, 0, 0},
+
+{"rcr", 2, 0xd0, 3, W|Modrm, Imm1, Reg|Mem, 0},
+{"rcr", 2, 0xc0, 3, W|Modrm, Imm8, Reg|Mem, 0},
+{"rcr", 2, 0xd2, 3, W|Modrm, ShiftCount, Reg|Mem, 0},
+{"rcr", 1, 0xd0, 3, W|Modrm, Reg|Mem, 0, 0},
+
+{"sal", 2, 0xd0, 4, W|Modrm, Imm1, Reg|Mem, 0},
+{"sal", 2, 0xc0, 4, W|Modrm, Imm8, Reg|Mem, 0},
+{"sal", 2, 0xd2, 4, W|Modrm, ShiftCount, Reg|Mem, 0},
+{"sal", 1, 0xd0, 4, W|Modrm, Reg|Mem, 0, 0},
+{"shl", 2, 0xd0, 4, W|Modrm, Imm1, Reg|Mem, 0},
+{"shl", 2, 0xc0, 4, W|Modrm, Imm8, Reg|Mem, 0},
+{"shl", 2, 0xd2, 4, W|Modrm, ShiftCount, Reg|Mem, 0},
+{"shl", 1, 0xd0, 4, W|Modrm, Reg|Mem, 0, 0},
+
+{"shld", 3, 0x0fa4, _, Modrm, Imm8, WordReg, WordReg|Mem},
+{"shld", 3, 0x0fa5, _, Modrm, ShiftCount, WordReg, WordReg|Mem},
+
+{"shr", 2, 0xd0, 5, W|Modrm, Imm1, Reg|Mem, 0},
+{"shr", 2, 0xc0, 5, W|Modrm, Imm8, Reg|Mem, 0},
+{"shr", 2, 0xd2, 5, W|Modrm, ShiftCount, Reg|Mem, 0},
+{"shr", 1, 0xd0, 5, W|Modrm, Reg|Mem, 0, 0},
+
+{"shrd", 3, 0x0fac, _, Modrm, Imm8, WordReg, WordReg|Mem},
+{"shrd", 3, 0x0fad, _, Modrm, ShiftCount, WordReg, WordReg|Mem},
+
+{"sar", 2, 0xd0, 7, W|Modrm, Imm1, Reg|Mem, 0},
+{"sar", 2, 0xc0, 7, W|Modrm, Imm8, Reg|Mem, 0},
+{"sar", 2, 0xd2, 7, W|Modrm, ShiftCount, Reg|Mem, 0},
+{"sar", 1, 0xd0, 7, W|Modrm, Reg|Mem, 0, 0},
+
+/* control transfer instructions */
+#define CALL_PC_RELATIVE 0xe8
+{"call", 1, 0xe8, _, JumpDword, Disp32, 0, 0},
+{"call", 1, 0xff, 2, Modrm, Reg|Mem|JumpAbsolute, 0, 0},
+#define CALL_FAR_IMMEDIATE 0x9a
+{"lcall", 2, 0x9a, _, JumpInterSegment, Imm16, Abs32, 0},
+{"lcall", 1, 0xff, 3, Modrm, Mem, 0, 0},
+
+#define JUMP_PC_RELATIVE 0xeb
+{"jmp", 1, 0xeb, _, Jump, Disp, 0, 0},
+{"jmp", 1, 0xff, 4, Modrm, Reg32|Mem|JumpAbsolute, 0, 0},
+#define JUMP_FAR_IMMEDIATE 0xea
+{"ljmp", 2, 0xea, _, JumpInterSegment, Imm16, Imm32, 0},
+{"ljmp", 1, 0xff, 5, Modrm, Mem, 0, 0},
+
+{"ret", 0, 0xc3, _, NoModrm, 0, 0, 0},
+{"ret", 1, 0xc2, _, NoModrm, Imm16, 0, 0},
+{"lret", 0, 0xcb, _, NoModrm, 0, 0, 0},
+{"lret", 1, 0xca, _, NoModrm, Imm16, 0, 0},
+{"enter", 2, 0xc8, _, NoModrm, Imm16, Imm8, 0},
+{"leave", 0, 0xc9, _, NoModrm, 0, 0, 0},
+
+/* conditional jumps */
+{"jo", 1, 0x70, _, Jump, Disp, 0, 0},
+
+{"jno", 1, 0x71, _, Jump, Disp, 0, 0},
+
+{"jb", 1, 0x72, _, Jump, Disp, 0, 0},
+{"jc", 1, 0x72, _, Jump, Disp, 0, 0},
+{"jnae", 1, 0x72, _, Jump, Disp, 0, 0},
+
+{"jnb", 1, 0x73, _, Jump, Disp, 0, 0},
+{"jnc", 1, 0x73, _, Jump, Disp, 0, 0},
+{"jae", 1, 0x73, _, Jump, Disp, 0, 0},
+
+{"je", 1, 0x74, _, Jump, Disp, 0, 0},
+{"jz", 1, 0x74, _, Jump, Disp, 0, 0},
+
+{"jne", 1, 0x75, _, Jump, Disp, 0, 0},
+{"jnz", 1, 0x75, _, Jump, Disp, 0, 0},
+
+{"jbe", 1, 0x76, _, Jump, Disp, 0, 0},
+{"jna", 1, 0x76, _, Jump, Disp, 0, 0},
+
+{"jnbe", 1, 0x77, _, Jump, Disp, 0, 0},
+{"ja", 1, 0x77, _, Jump, Disp, 0, 0},
+
+{"js", 1, 0x78, _, Jump, Disp, 0, 0},
+
+{"jns", 1, 0x79, _, Jump, Disp, 0, 0},
+
+{"jp", 1, 0x7a, _, Jump, Disp, 0, 0},
+{"jpe", 1, 0x7a, _, Jump, Disp, 0, 0},
+
+{"jnp", 1, 0x7b, _, Jump, Disp, 0, 0},
+{"jpo", 1, 0x7b, _, Jump, Disp, 0, 0},
+
+{"jl", 1, 0x7c, _, Jump, Disp, 0, 0},
+{"jnge", 1, 0x7c, _, Jump, Disp, 0, 0},
+
+{"jnl", 1, 0x7d, _, Jump, Disp, 0, 0},
+{"jge", 1, 0x7d, _, Jump, Disp, 0, 0},
+
+{"jle", 1, 0x7e, _, Jump, Disp, 0, 0},
+{"jng", 1, 0x7e, _, Jump, Disp, 0, 0},
+
+{"jnle", 1, 0x7f, _, Jump, Disp, 0, 0},
+{"jg", 1, 0x7f, _, Jump, Disp, 0, 0},
+
+/* these turn into pseudo operations when disp is larger than 8 bits */
+#define IS_JUMP_ON_CX_ZERO(o) \
+ (o == 0x67e3)
+#define IS_JUMP_ON_ECX_ZERO(o) \
+ (o == 0xe3)
+
+{"jcxz", 1, 0x67e3, _, JumpByte, Disp, 0, 0},
+{"jecxz", 1, 0xe3, _, JumpByte, Disp, 0, 0},
+
+#define IS_LOOP_ECX_TIMES(o) \
+ (o == 0xe2 || o == 0xe1 || o == 0xe0)
+
+{"loop", 1, 0xe2, _, JumpByte, Disp, 0, 0},
+
+{"loopz", 1, 0xe1, _, JumpByte, Disp, 0, 0},
+{"loope", 1, 0xe1, _, JumpByte, Disp, 0, 0},
+
+{"loopnz", 1, 0xe0, _, JumpByte, Disp, 0, 0},
+{"loopne", 1, 0xe0, _, JumpByte, Disp, 0, 0},
+
+/* set byte on flag instructions */
+{"seto", 1, 0x0f90, 0, Modrm, Reg8|Mem, 0, 0},
+
+{"setno", 1, 0x0f91, 0, Modrm, Reg8|Mem, 0, 0},
+
+{"setc", 1, 0x0f92, 0, Modrm, Reg8|Mem, 0, 0},
+{"setb", 1, 0x0f92, 0, Modrm, Reg8|Mem, 0, 0},
+{"setnae", 1, 0x0f92, 0, Modrm, Reg8|Mem, 0, 0},
+
+{"setnc", 1, 0x0f93, 0, Modrm, Reg8|Mem, 0, 0},
+{"setnb", 1, 0x0f93, 0, Modrm, Reg8|Mem, 0, 0},
+{"setae", 1, 0x0f93, 0, Modrm, Reg8|Mem, 0, 0},
+
+{"sete", 1, 0x0f94, 0, Modrm, Reg8|Mem, 0, 0},
+{"setz", 1, 0x0f94, 0, Modrm, Reg8|Mem, 0, 0},
+
+{"setne", 1, 0x0f95, 0, Modrm, Reg8|Mem, 0, 0},
+{"setnz", 1, 0x0f95, 0, Modrm, Reg8|Mem, 0, 0},
+
+{"setbe", 1, 0x0f96, 0, Modrm, Reg8|Mem, 0, 0},
+{"setna", 1, 0x0f96, 0, Modrm, Reg8|Mem, 0, 0},
+
+{"setnbe", 1, 0x0f97, 0, Modrm, Reg8|Mem, 0, 0},
+{"seta", 1, 0x0f97, 0, Modrm, Reg8|Mem, 0, 0},
+
+{"sets", 1, 0x0f98, 0, Modrm, Reg8|Mem, 0, 0},
+
+{"setns", 1, 0x0f99, 0, Modrm, Reg8|Mem, 0, 0},
+
+{"setp", 1, 0x0f9a, 0, Modrm, Reg8|Mem, 0, 0},
+{"setpe", 1, 0x0f9a, 0, Modrm, Reg8|Mem, 0, 0},
+
+{"setnp", 1, 0x0f9b, 0, Modrm, Reg8|Mem, 0, 0},
+{"setpo", 1, 0x0f9b, 0, Modrm, Reg8|Mem, 0, 0},
+
+{"setl", 1, 0x0f9c, 0, Modrm, Reg8|Mem, 0, 0},
+{"setnge", 1, 0x0f9c, 0, Modrm, Reg8|Mem, 0, 0},
+
+{"setnl", 1, 0x0f9d, 0, Modrm, Reg8|Mem, 0, 0},
+{"setge", 1, 0x0f9d, 0, Modrm, Reg8|Mem, 0, 0},
+
+{"setle", 1, 0x0f9e, 0, Modrm, Reg8|Mem, 0, 0},
+{"setng", 1, 0x0f9e, 0, Modrm, Reg8|Mem, 0, 0},
+
+{"setnle", 1, 0x0f9f, 0, Modrm, Reg8|Mem, 0, 0},
+{"setg", 1, 0x0f9f, 0, Modrm, Reg8|Mem, 0, 0},
+
+#define IS_STRING_INSTRUCTION(o) \
+ ((o) == 0xa6 || (o) == 0x6c || (o) == 0x6e || (o) == 0x6e || \
+ (o) == 0xac || (o) == 0xa4 || (o) == 0xae || (o) == 0xaa || \
+ (o) == 0xd7)
+
+/* string manipulation */
+{"cmps", 0, 0xa6, _, W|NoModrm, 0, 0, 0},
+{"scmp", 0, 0xa6, _, W|NoModrm, 0, 0, 0},
+{"ins", 0, 0x6c, _, W|NoModrm, 0, 0, 0},
+{"outs", 0, 0x6e, _, W|NoModrm, 0, 0, 0},
+{"lods", 0, 0xac, _, W|NoModrm, 0, 0, 0},
+{"slod", 0, 0xac, _, W|NoModrm, 0, 0, 0},
+{"movs", 0, 0xa4, _, W|NoModrm, 0, 0, 0},
+{"smov", 0, 0xa4, _, W|NoModrm, 0, 0, 0},
+{"scas", 0, 0xae, _, W|NoModrm, 0, 0, 0},
+{"ssca", 0, 0xae, _, W|NoModrm, 0, 0, 0},
+{"stos", 0, 0xaa, _, W|NoModrm, 0, 0, 0},
+{"ssto", 0, 0xaa, _, W|NoModrm, 0, 0, 0},
+{"xlat", 0, 0xd7, _, NoModrm, 0, 0, 0},
+
+/* bit manipulation */
+{"bsf", 2, 0x0fbc, _, Modrm|ReverseRegRegmem, Reg|Mem, Reg, 0},
+{"bsr", 2, 0x0fbd, _, Modrm|ReverseRegRegmem, Reg|Mem, Reg, 0},
+{"bt", 2, 0x0fa3, _, Modrm, Reg, Reg|Mem, 0},
+{"bt", 2, 0x0fba, 4, Modrm, Imm8, Reg|Mem, 0},
+{"btc", 2, 0x0fbb, _, Modrm, Reg, Reg|Mem, 0},
+{"btc", 2, 0x0fba, 7, Modrm, Imm8, Reg|Mem, 0},
+{"btr", 2, 0x0fb3, _, Modrm, Reg, Reg|Mem, 0},
+{"btr", 2, 0x0fba, 6, Modrm, Imm8, Reg|Mem, 0},
+{"bts", 2, 0x0fab, _, Modrm, Reg, Reg|Mem, 0},
+{"bts", 2, 0x0fba, 5, Modrm, Imm8, Reg|Mem, 0},
+
+/* interrupts & op. sys insns */
+/* See i386.c for conversion of 'int $3' into the special int 3 insn. */
+#define INT_OPCODE 0xcd
+#define INT3_OPCODE 0xcc
+{"int", 1, 0xcd, _, NoModrm, Imm8, 0, 0},
+{"int3", 0, 0xcc, _, NoModrm, 0, 0, 0},
+{"into", 0, 0xce, _, NoModrm, 0, 0, 0},
+{"iret", 0, 0xcf, _, NoModrm, 0, 0, 0},
+
+{"boundl", 2, 0x62, _, Modrm, Reg32, Mem, 0},
+{"boundw", 2, 0x6662, _, Modrm, Reg16, Mem, 0},
+
+{"hlt", 0, 0xf4, _, NoModrm, 0, 0, 0},
+{"wait", 0, 0x9b, _, NoModrm, 0, 0, 0},
+/* nop is actually 'xchgl %eax, %eax' */
+{"nop", 0, 0x90, _, NoModrm, 0, 0, 0},
+
+/* protection control */
+{"arpl", 2, 0x63, _, Modrm, Reg16, Reg16|Mem, 0},
+{"lar", 2, 0x0f02, _, Modrm|ReverseRegRegmem, WordReg|Mem, WordReg, 0},
+{"lgdt", 1, 0x0f01, 2, Modrm, Mem, 0, 0},
+{"lidt", 1, 0x0f01, 3, Modrm, Mem, 0, 0},
+{"lldt", 1, 0x0f00, 2, Modrm, WordReg|Mem, 0, 0},
+{"lmsw", 1, 0x0f01, 6, Modrm, WordReg|Mem, 0, 0},
+{"lsl", 2, 0x0f03, _, Modrm|ReverseRegRegmem, WordReg|Mem, WordReg, 0},
+{"ltr", 1, 0x0f00, 3, Modrm, WordReg|Mem, 0, 0},
+
+{"sgdt", 1, 0x0f01, 0, Modrm, Mem, 0, 0},
+{"sidt", 1, 0x0f01, 1, Modrm, Mem, 0, 0},
+{"sldt", 1, 0x0f00, 0, Modrm, WordReg|Mem, 0, 0},
+{"smsw", 1, 0x0f01, 4, Modrm, WordReg|Mem, 0, 0},
+{"str", 1, 0x0f00, 1, Modrm, Reg16|Mem, 0, 0},
+
+{"verr", 1, 0x0f00, 4, Modrm, WordReg|Mem, 0, 0},
+{"verw", 1, 0x0f00, 5, Modrm, WordReg|Mem, 0, 0},
+
+/* floating point instructions */
+
+/* load */
+{"fld", 1, 0xd9c0, _, ShortForm, FloatReg, 0, 0}, /* register */
+{"flds", 1, 0xd9, 0, Modrm, Mem, 0, 0}, /* %st0 <-- mem float */
+{"fildl", 1, 0xdb, 0, Modrm, Mem, 0, 0}, /* %st0 <-- mem word */
+{"fldl", 1, 0xdd, 0, Modrm, Mem, 0, 0}, /* %st0 <-- mem double */
+{"fldl", 1, 0xd9c0, _, ShortForm, FloatReg, 0, 0}, /* register */
+{"filds", 1, 0xdf, 0, Modrm, Mem, 0, 0}, /* %st0 <-- mem dword */
+{"fildq", 1, 0xdf, 5, Modrm, Mem, 0, 0}, /* %st0 <-- mem qword */
+{"fldt", 1, 0xdb, 5, Modrm, Mem, 0, 0}, /* %st0 <-- mem efloat */
+{"fbld", 1, 0xdf, 4, Modrm, Mem, 0, 0}, /* %st0 <-- mem bcd */
+
+/* store (no pop) */
+{"fst", 1, 0xddd0, _, ShortForm, FloatReg, 0, 0}, /* register */
+{"fsts", 1, 0xd9, 2, Modrm, Mem, 0, 0}, /* %st0 --> mem float */
+{"fistl", 1, 0xdb, 2, Modrm, Mem, 0, 0}, /* %st0 --> mem dword */
+{"fstl", 1, 0xdd, 2, Modrm, Mem, 0, 0}, /* %st0 --> mem double */
+{"fstl", 1, 0xddd0, _, ShortForm, FloatReg, 0, 0}, /* register */
+{"fists", 1, 0xdf, 2, Modrm, Mem, 0, 0}, /* %st0 --> mem word */
+
+/* store (with pop) */
+{"fstp", 1, 0xddd8, _, ShortForm, FloatReg, 0, 0}, /* register */
+{"fstps", 1, 0xd9, 3, Modrm, Mem, 0, 0}, /* %st0 --> mem float */
+{"fistpl", 1, 0xdb, 3, Modrm, Mem, 0, 0}, /* %st0 --> mem word */
+{"fstpl", 1, 0xdd, 3, Modrm, Mem, 0, 0}, /* %st0 --> mem double */
+{"fstpl", 1, 0xddd8, _, ShortForm, FloatReg, 0, 0}, /* register */
+{"fistps", 1, 0xdf, 3, Modrm, Mem, 0, 0}, /* %st0 --> mem dword */
+{"fistpq", 1, 0xdf, 7, Modrm, Mem, 0, 0}, /* %st0 --> mem qword */
+{"fstpt", 1, 0xdb, 7, Modrm, Mem, 0, 0}, /* %st0 --> mem efloat */
+{"fbstp", 1, 0xdf, 6, Modrm, Mem, 0, 0}, /* %st0 --> mem bcd */
+
+/* exchange %st<n> with %st0 */
+{"fxch", 1, 0xd9c8, _, ShortForm, FloatReg, 0, 0},
+
+/* comparison (without pop) */
+{"fcom", 1, 0xd8d0, _, ShortForm, FloatReg, 0, 0},
+{"fcoms", 1, 0xd8, 2, Modrm, Mem, 0, 0}, /* compare %st0, mem float */
+{"ficoml", 1, 0xda, 2, Modrm, Mem, 0, 0}, /* compare %st0, mem word */
+{"fcoml", 1, 0xdc, 2, Modrm, Mem, 0, 0}, /* compare %st0, mem double */
+{"fcoml", 1, 0xd8d0, _, ShortForm, FloatReg, 0, 0},
+{"ficoms", 1, 0xde, 2, Modrm, Mem, 0, 0}, /* compare %st0, mem dword */
+
+/* comparison (with pop) */
+{"fcomp", 1, 0xd8d8, _, ShortForm, FloatReg, 0, 0},
+{"fcomps", 1, 0xd8, 3, Modrm, Mem, 0, 0}, /* compare %st0, mem float */
+{"ficompl", 1, 0xda, 3, Modrm, Mem, 0, 0}, /* compare %st0, mem word */
+{"fcompl", 1, 0xdc, 3, Modrm, Mem, 0, 0}, /* compare %st0, mem double */
+{"fcompl", 1, 0xd8d8, _, ShortForm, FloatReg, 0, 0},
+{"ficomps", 1, 0xde, 3, Modrm, Mem, 0, 0}, /* compare %st0, mem dword */
+{"fcompp", 0, 0xded9, _, NoModrm, 0, 0, 0}, /* compare %st0, %st1 & pop twice */
+
+/* unordered comparison (with pop) */
+{"fucom", 1, 0xdde0, _, ShortForm, FloatReg, 0, 0},
+{"fucomp", 1, 0xdde8, _, ShortForm, FloatReg, 0, 0},
+{"fucompp", 0, 0xdae9, _, NoModrm, 0, 0, 0}, /* ucompare %st0, %st1 & pop twice */
+
+{"ftst", 0, 0xd9e4, _, NoModrm, 0, 0, 0}, /* test %st0 */
+{"fxam", 0, 0xd9e5, _, NoModrm, 0, 0, 0}, /* examine %st0 */
+
+/* load constants into %st0 */
+{"fld1", 0, 0xd9e8, _, NoModrm, 0, 0, 0}, /* %st0 <-- 1.0 */
+{"fldl2t", 0, 0xd9e9, _, NoModrm, 0, 0, 0}, /* %st0 <-- log2(10) */
+{"fldl2e", 0, 0xd9ea, _, NoModrm, 0, 0, 0}, /* %st0 <-- log2(e) */
+{"fldpi", 0, 0xd9eb, _, NoModrm, 0, 0, 0}, /* %st0 <-- pi */
+{"fldlg2", 0, 0xd9ec, _, NoModrm, 0, 0, 0}, /* %st0 <-- log10(2) */
+{"fldln2", 0, 0xd9ed, _, NoModrm, 0, 0, 0}, /* %st0 <-- ln(2) */
+{"fldz", 0, 0xd9ee, _, NoModrm, 0, 0, 0}, /* %st0 <-- 0.0 */
+
+/* arithmetic */
+
+/* add */
+{"fadd", 1, 0xd8c0, _, ShortForm, FloatReg, 0, 0},
+{"fadd", 2, 0xd8c0, _, ShortForm|FloatD, FloatReg, FloatAcc, 0},
+{"fadd", 0, 0xdcc1, _, NoModrm, 0, 0, 0}, /* alias for fadd %st, %st(1) */
+{"faddp", 1, 0xdec0, _, ShortForm, FloatReg, 0, 0},
+{"faddp", 2, 0xdac0, _, ShortForm|FloatD, FloatReg, FloatAcc, 0},
+{"faddp", 0, 0xdec1, _, NoModrm, 0, 0, 0}, /* alias for faddp %st, %st(1) */
+{"fadds", 1, 0xd8, 0, Modrm, Mem, 0, 0},
+{"fiaddl", 1, 0xda, 0, Modrm, Mem, 0, 0},
+{"faddl", 1, 0xdc, 0, Modrm, Mem, 0, 0},
+{"fiadds", 1, 0xde, 0, Modrm, Mem, 0, 0},
+
+/* sub */
+/* Note: intel has decided that certain of these operations are reversed
+ in assembler syntax. */
+{"fsub", 1, 0xd8e0, _, ShortForm, FloatReg, 0, 0},
+{"fsub", 2, 0xd8e0, _, ShortForm, FloatReg, FloatAcc, 0},
+#ifdef NON_BROKEN_OPCODES
+{"fsub", 2, 0xdce8, _, ShortForm, FloatAcc, FloatReg, 0},
+#else
+{"fsub", 2, 0xdce0, _, ShortForm, FloatAcc, FloatReg, 0},
+#endif
+{"fsub", 0, 0xdce1, _, NoModrm, 0, 0, 0},
+{"fsubp", 1, 0xdee0, _, ShortForm, FloatReg, 0, 0},
+{"fsubp", 2, 0xdee0, _, ShortForm, FloatReg, FloatAcc, 0},
+#ifdef NON_BROKEN_OPCODES
+{"fsubp", 2, 0xdee8, _, ShortForm, FloatAcc, FloatReg, 0},
+#else
+{"fsubp", 2, 0xdee0, _, ShortForm, FloatAcc, FloatReg, 0},
+#endif
+{"fsubp", 0, 0xdee1, _, NoModrm, 0, 0, 0},
+{"fsubs", 1, 0xd8, 4, Modrm, Mem, 0, 0},
+{"fisubl", 1, 0xda, 4, Modrm, Mem, 0, 0},
+{"fsubl", 1, 0xdc, 4, Modrm, Mem, 0, 0},
+{"fisubs", 1, 0xde, 4, Modrm, Mem, 0, 0},
+
+/* sub reverse */
+{"fsubr", 1, 0xd8e8, _, ShortForm, FloatReg, 0, 0},
+{"fsubr", 2, 0xd8e8, _, ShortForm, FloatReg, FloatAcc, 0},
+#ifdef NON_BROKEN_OPCODES
+{"fsubr", 2, 0xdce0, _, ShortForm, FloatAcc, FloatReg, 0},
+#else
+{"fsubr", 2, 0xdce8, _, ShortForm, FloatAcc, FloatReg, 0},
+#endif
+{"fsubr", 0, 0xdce9, _, NoModrm, 0, 0, 0},
+{"fsubrp", 1, 0xdee8, _, ShortForm, FloatReg, 0, 0},
+{"fsubrp", 2, 0xdee8, _, ShortForm, FloatReg, FloatAcc, 0},
+#ifdef NON_BROKEN_OPCODES
+{"fsubrp", 2, 0xdee0, _, ShortForm, FloatAcc, FloatReg, 0},
+#else
+{"fsubrp", 2, 0xdee8, _, ShortForm, FloatAcc, FloatReg, 0},
+#endif
+{"fsubrp", 0, 0xdee9, _, NoModrm, 0, 0, 0},
+{"fsubrs", 1, 0xd8, 5, Modrm, Mem, 0, 0},
+{"fisubrl", 1, 0xda, 5, Modrm, Mem, 0, 0},
+{"fsubrl", 1, 0xdc, 5, Modrm, Mem, 0, 0},
+{"fisubrs", 1, 0xde, 5, Modrm, Mem, 0, 0},
+
+/* mul */
+{"fmul", 1, 0xd8c8, _, ShortForm, FloatReg, 0, 0},
+{"fmul", 2, 0xd8c8, _, ShortForm|FloatD, FloatReg, FloatAcc, 0},
+{"fmul", 0, 0xdcc9, _, NoModrm, 0, 0, 0},
+{"fmulp", 1, 0xdec8, _, ShortForm, FloatReg, 0, 0},
+{"fmulp", 2, 0xdec8, _, ShortForm|FloatD, FloatReg, FloatAcc, 0},
+{"fmulp", 0, 0xdec9, _, NoModrm, 0, 0, 0},
+{"fmuls", 1, 0xd8, 1, Modrm, Mem, 0, 0},
+{"fimull", 1, 0xda, 1, Modrm, Mem, 0, 0},
+{"fmull", 1, 0xdc, 1, Modrm, Mem, 0, 0},
+{"fimuls", 1, 0xde, 1, Modrm, Mem, 0, 0},
+
+/* div */
+/* Note: intel has decided that certain of these operations are reversed
+ in assembler syntax. */
+{"fdiv", 1, 0xd8f0, _, ShortForm, FloatReg, 0, 0},
+{"fdiv", 2, 0xd8f0, _, ShortForm, FloatReg, FloatAcc, 0},
+#ifdef NON_BROKEN_OPCODES
+{"fdiv", 2, 0xdcf8, _, ShortForm, FloatAcc, FloatReg, 0},
+#else
+{"fdiv", 2, 0xdcf0, _, ShortForm, FloatAcc, FloatReg, 0},
+#endif
+{"fdiv", 0, 0xdcf1, _, NoModrm, 0, 0, 0},
+{"fdivp", 1, 0xdef0, _, ShortForm, FloatReg, 0, 0},
+{"fdivp", 2, 0xdef0, _, ShortForm, FloatReg, FloatAcc, 0},
+#ifdef NON_BROKEN_OPCODES
+{"fdivp", 2, 0xdef8, _, ShortForm, FloatAcc, FloatReg, 0},
+#else
+{"fdivp", 2, 0xdef0, _, ShortForm, FloatAcc, FloatReg, 0},
+#endif
+{"fdivp", 0, 0xdef1, _, NoModrm, 0, 0, 0},
+{"fdivs", 1, 0xd8, 6, Modrm, Mem, 0, 0},
+{"fidivl", 1, 0xda, 6, Modrm, Mem, 0, 0},
+{"fdivl", 1, 0xdc, 6, Modrm, Mem, 0, 0},
+{"fidivs", 1, 0xde, 6, Modrm, Mem, 0, 0},
+
+/* div reverse */
+{"fdivr", 1, 0xd8f8, _, ShortForm, FloatReg, 0, 0},
+{"fdivr", 2, 0xd8f8, _, ShortForm, FloatReg, FloatAcc, 0},
+#ifdef NON_BROKEN_OPCODES
+{"fdivr", 2, 0xdcf0, _, ShortForm, FloatAcc, FloatReg, 0},
+#else
+{"fdivr", 2, 0xdcf8, _, ShortForm, FloatAcc, FloatReg, 0},
+#endif
+{"fdivr", 0, 0xdcf9, _, NoModrm, 0, 0, 0},
+{"fdivrp", 1, 0xdef8, _, ShortForm, FloatReg, 0, 0},
+{"fdivrp", 2, 0xdef8, _, ShortForm, FloatReg, FloatAcc, 0},
+#ifdef NON_BROKEN_OPCODES
+{"fdivrp", 2, 0xdef0, _, ShortForm, FloatAcc, FloatReg, 0},
+#else
+{"fdivrp", 2, 0xdef8, _, ShortForm, FloatAcc, FloatReg, 0},
+#endif
+{"fdivrp", 0, 0xdef9, _, NoModrm, 0, 0, 0},
+{"fdivrs", 1, 0xd8, 7, Modrm, Mem, 0, 0},
+{"fidivrl", 1, 0xda, 7, Modrm, Mem, 0, 0},
+{"fdivrl", 1, 0xdc, 7, Modrm, Mem, 0, 0},
+{"fidivrs", 1, 0xde, 7, Modrm, Mem, 0, 0},
+
+{"f2xm1", 0, 0xd9f0, _, NoModrm, 0, 0, 0},
+{"fyl2x", 0, 0xd9f1, _, NoModrm, 0, 0, 0},
+{"fptan", 0, 0xd9f2, _, NoModrm, 0, 0, 0},
+{"fpatan", 0, 0xd9f3, _, NoModrm, 0, 0, 0},
+{"fxtract", 0, 0xd9f4, _, NoModrm, 0, 0, 0},
+{"fprem1", 0, 0xd9f5, _, NoModrm, 0, 0, 0},
+{"fdecstp", 0, 0xd9f6, _, NoModrm, 0, 0, 0},
+{"fincstp", 0, 0xd9f7, _, NoModrm, 0, 0, 0},
+{"fprem", 0, 0xd9f8, _, NoModrm, 0, 0, 0},
+{"fyl2xp1", 0, 0xd9f9, _, NoModrm, 0, 0, 0},
+{"fsqrt", 0, 0xd9fa, _, NoModrm, 0, 0, 0},
+{"fsincos", 0, 0xd9fb, _, NoModrm, 0, 0, 0},
+{"frndint", 0, 0xd9fc, _, NoModrm, 0, 0, 0},
+{"fscale", 0, 0xd9fd, _, NoModrm, 0, 0, 0},
+{"fsin", 0, 0xd9fe, _, NoModrm, 0, 0, 0},
+{"fcos", 0, 0xd9ff, _, NoModrm, 0, 0, 0},
+
+{"fchs", 0, 0xd9e0, _, NoModrm, 0, 0, 0},
+{"fabs", 0, 0xd9e1, _, NoModrm, 0, 0, 0},
+
+/* processor control */
+{"fninit", 0, 0xdbe3, _, NoModrm, 0, 0, 0},
+{"finit", 0, 0xdbe3, _, NoModrm, 0, 0, 0},
+{"fldcw", 1, 0xd9, 5, Modrm, Mem, 0, 0},
+{"fnstcw", 1, 0xd9, 7, Modrm, Mem, 0, 0},
+{"fstcw", 1, 0xd9, 7, Modrm, Mem, 0, 0},
+{"fnstsw", 1, 0xdfe0, _, NoModrm, Acc, 0, 0},
+{"fnstsw", 1, 0xdd, 7, Modrm, Mem, 0, 0},
+{"fnstsw", 0, 0xdfe0, _, NoModrm, 0, 0, 0},
+{"fstsw", 1, 0xdfe0, _, NoModrm, Acc, 0, 0},
+{"fstsw", 1, 0xdd, 7, Modrm, Mem, 0, 0},
+{"fstsw", 0, 0xdfe0, _, NoModrm, 0, 0, 0},
+{"fnclex", 0, 0xdbe2, _, NoModrm, 0, 0, 0},
+{"fclex", 0, 0xdbe2, _, NoModrm, 0, 0, 0},
+/*
+ We ignore the short format (287) versions of fstenv/fldenv & fsave/frstor
+ instructions; i'm not sure how to add them or how they are different.
+ My 386/387 book offers no details about this.
+*/
+{"fnstenv", 1, 0xd9, 6, Modrm, Mem, 0, 0},
+{"fstenv", 1, 0xd9, 6, Modrm, Mem, 0, 0},
+{"fldenv", 1, 0xd9, 4, Modrm, Mem, 0, 0},
+{"fnsave", 1, 0xdd, 6, Modrm, Mem, 0, 0},
+{"fsave", 1, 0xdd, 6, Modrm, Mem, 0, 0},
+{"frstor", 1, 0xdd, 4, Modrm, Mem, 0, 0},
+
+{"ffree", 1, 0xddc0, _, ShortForm, FloatReg, 0, 0},
+{"fnop", 0, 0xd9d0, _, NoModrm, 0, 0, 0},
+{"fwait", 0, 0x9b, _, NoModrm, 0, 0, 0},
+
+/*
+ opcode prefixes; we allow them as seperate insns too
+ (see prefix table below)
+*/
+{"aword", 0, 0x67, _, NoModrm, 0, 0, 0},
+{"addr16", 0, 0x67, _, NoModrm, 0, 0, 0},
+{"word", 0, 0x66, _, NoModrm, 0, 0, 0},
+{"data16", 0, 0x66, _, NoModrm, 0, 0, 0},
+{"lock", 0, 0xf0, _, NoModrm, 0, 0, 0},
+{"cs", 0, 0x2e, _, NoModrm, 0, 0, 0},
+{"ds", 0, 0x3e, _, NoModrm, 0, 0, 0},
+{"es", 0, 0x26, _, NoModrm, 0, 0, 0},
+{"fs", 0, 0x64, _, NoModrm, 0, 0, 0},
+{"gs", 0, 0x65, _, NoModrm, 0, 0, 0},
+{"ss", 0, 0x36, _, NoModrm, 0, 0, 0},
+{"rep", 0, 0xf3, _, NoModrm, 0, 0, 0},
+{"repe", 0, 0xf3, _, NoModrm, 0, 0, 0},
+{ "repne", 0, 0xf2, _, NoModrm, 0, 0, 0},
+{"repz", 0, 0xf3, _, NoModrm, 0, 0, 0},
+{ "repnz", 0, 0xf2, _, NoModrm, 0, 0, 0},
+
+/* 486 extensions */
+{"bswap", 1, 0x0fc8, _, ShortForm, Reg32,0,0 },
+{"xadd", 2, 0x0fc0, _, DW|Modrm, Reg, Reg|Mem, 0 },
+{"cmpxchg", 2, 0x0fb0, _, DW|Modrm, Reg, Reg|Mem, 0 },
+{"invd", 0, 0x0f08, _, NoModrm, 0, 0, 0},
+{"wbinvd", 0, 0x0f09, _, NoModrm, 0, 0, 0},
+{"invlpg", 1, 0x0f01, 7, Modrm, Mem, 0, 0},
+
+/* Pentium and late-model 486 extensions */
+{"cpuid", 0, 0x0fa2, _, NoModrm, 0, 0, 0},
+
+{"", 0, 0, 0, 0, 0, 0, 0} /* sentinal */
+};
+#undef _
+
+static const template *i386_optab_end
+ = i386_optab + sizeof (i386_optab)/sizeof(i386_optab[0]);
+
+/* 386 register table */
+
+static const reg_entry i386_regtab[] = {
+ /* 8 bit regs */
+ {"al", Reg8|Acc, 0}, {"cl", Reg8|ShiftCount, 1}, {"dl", Reg8, 2},
+ {"bl", Reg8, 3},
+ {"ah", Reg8, 4}, {"ch", Reg8, 5}, {"dh", Reg8, 6}, {"bh", Reg8, 7},
+ /* 16 bit regs */
+ {"ax", Reg16|Acc, 0}, {"cx", Reg16, 1}, {"dx", Reg16|InOutPortReg, 2}, {"bx", Reg16, 3},
+ {"sp", Reg16, 4}, {"bp", Reg16, 5}, {"si", Reg16, 6}, {"di", Reg16, 7},
+ /* 32 bit regs */
+ {"eax", Reg32|Acc, 0}, {"ecx", Reg32, 1}, {"edx", Reg32, 2}, {"ebx", Reg32, 3},
+ {"esp", Reg32, 4}, {"ebp", Reg32, 5}, {"esi", Reg32, 6}, {"edi", Reg32, 7},
+ /* segment registers */
+ {"es", SReg2, 0}, {"cs", SReg2, 1}, {"ss", SReg2, 2},
+ {"ds", SReg2, 3}, {"fs", SReg3, 4}, {"gs", SReg3, 5},
+ /* control registers */
+ {"cr0", Control, 0}, {"cr2", Control, 2}, {"cr3", Control, 3},
+ /* debug registers */
+ {"db0", Debug, 0}, {"db1", Debug, 1}, {"db2", Debug, 2},
+ {"db3", Debug, 3}, {"db6", Debug, 6}, {"db7", Debug, 7},
+ /* test registers */
+ {"tr6", Test, 6}, {"tr7", Test, 7},
+ /* float registers */
+ {"st(0)", FloatReg|FloatAcc, 0},
+ {"st", FloatReg|FloatAcc, 0},
+ {"st(1)", FloatReg, 1}, {"st(2)", FloatReg, 2},
+ {"st(3)", FloatReg, 3}, {"st(4)", FloatReg, 4}, {"st(5)", FloatReg, 5},
+ {"st(6)", FloatReg, 6}, {"st(7)", FloatReg, 7}
+};
+
+#define MAX_REG_NAME_SIZE 8 /* for parsing register names from input */
+
+static const reg_entry *i386_regtab_end
+ = i386_regtab + sizeof(i386_regtab)/sizeof(i386_regtab[0]);
+
+/* segment stuff */
+static const seg_entry cs = { "cs", 0x2e };
+static const seg_entry ds = { "ds", 0x3e };
+static const seg_entry ss = { "ss", 0x36 };
+static const seg_entry es = { "es", 0x26 };
+static const seg_entry fs = { "fs", 0x64 };
+static const seg_entry gs = { "gs", 0x65 };
+static const seg_entry null = { "", 0x0 };
+
+/*
+ This table is used to store the default segment register implied by all
+ possible memory addressing modes.
+ It is indexed by the mode & modrm entries of the modrm byte as follows:
+ index = (mode<<3) | modrm;
+*/
+static const seg_entry *one_byte_segment_defaults[] = {
+ /* mode 0 */
+ &ds, &ds, &ds, &ds, &null, &ds, &ds, &ds,
+ /* mode 1 */
+ &ds, &ds, &ds, &ds, &null, &ss, &ds, &ds,
+ /* mode 2 */
+ &ds, &ds, &ds, &ds, &null, &ss, &ds, &ds,
+ /* mode 3 --- not a memory reference; never referenced */
+};
+
+static const seg_entry *two_byte_segment_defaults[] = {
+ /* mode 0 */
+ &ds, &ds, &ds, &ds, &ss, &ds, &ds, &ds,
+ /* mode 1 */
+ &ds, &ds, &ds, &ds, &ss, &ds, &ds, &ds,
+ /* mode 2 */
+ &ds, &ds, &ds, &ds, &ss, &ds, &ds, &ds,
+ /* mode 3 --- not a memory reference; never referenced */
+};
+
+static const prefix_entry i386_prefixtab[] = {
+ { "addr16", 0x67 }, /* address size prefix ==> 16bit addressing
+ * (How is this useful?) */
+#define WORD_PREFIX_OPCODE 0x66
+ { "data16", 0x66 }, /* operand size prefix */
+ { "lock", 0xf0 }, /* bus lock prefix */
+ { "wait", 0x9b }, /* wait for coprocessor */
+ { "cs", 0x2e }, { "ds", 0x3e }, /* segment overrides ... */
+ { "es", 0x26 }, { "fs", 0x64 },
+ { "gs", 0x65 }, { "ss", 0x36 },
+/* REPE & REPNE used to detect rep/repne with a non-string instruction */
+#define REPNE 0xf2
+#define REPE 0xf3
+ { "rep", 0xf3 }, { "repe", 0xf3 }, { "repz", 0xf3 }, /* repeat string instructions */
+ { "repne", 0xf2 }, { "repnz", 0xf2 }
+};
+
+static const prefix_entry *i386_prefixtab_end
+ = i386_prefixtab + sizeof(i386_prefixtab)/sizeof(i386_prefixtab[0]);
+
+/* end of i386-opcode.h */
diff --git a/gnu/usr.bin/as/opcode/i860.h b/gnu/usr.bin/as/opcode/i860.h
new file mode 100644
index 0000000..b429a22
--- /dev/null
+++ b/gnu/usr.bin/as/opcode/i860.h
@@ -0,0 +1,495 @@
+/* Table of opcodes for the i860.
+ Copyright (C) 1989 Free Software Foundation, Inc.
+
+This file is part of GAS, the GNU Assembler, and GDB, the GNU disassembler.
+
+GAS/GDB is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 1, or (at your option)
+any later version.
+
+GAS/GDB is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GAS or GDB; see the file COPYING. If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#if !defined(__STDC__) && !defined(const)
+#define const
+#endif
+
+/*
+ * Structure of an opcode table entry.
+ */
+struct i860_opcode
+{
+ const char *name;
+ unsigned long match; /* Bits that must be set. */
+ unsigned long lose; /* Bits that must not be set. */
+ const char *args;
+ /* Nonzero if this is a possible expand-instruction. */
+ char expand;
+};
+
+enum expand_type
+{
+ E_MOV = 1, E_ADDR, E_U32, E_AND, E_S32, E_DELAY
+};
+
+/*
+ All i860 opcodes are 32 bits, except for the pseudoinstructions
+ and the operations utilizing a 32-bit address expression, an
+ unsigned 32-bit constant, or a signed 32-bit constant.
+ These opcodes are expanded into a two-instruction sequence for
+ any situation where the immediate operand does not fit in 32 bits.
+ In the case of the add and subtract operations the expansion is
+ to a three-instruction sequence (ex: orh, or, adds). In cases
+ where the address is to be relocated, the instruction is
+ expanded to handle the worse case, this could be optimized at
+ the final link if the actual address were known.
+
+ The pseudoinstructions are: mov, fmov, pmov, nop, and fnop.
+ These instructions are implemented as a one or two instruction
+ sequence of other operations.
+
+ The match component is a mask saying which bits must match a
+ particular opcode in order for an instruction to be an instance
+ of that opcode.
+
+ The args component is a string containing one character
+ for each operand of the instruction.
+
+Kinds of operands:
+ # Number used by optimizer. It is ignored.
+ 1 src1 integer register.
+ 2 src2 integer register.
+ d dest register.
+ c ctrlreg control register.
+ i 16 bit immediate.
+ I 16 bit immediate, aligned.
+ 5 5 bit immediate.
+ l lbroff 26 bit PC relative immediate.
+ r sbroff 16 bit PC relative immediate.
+ s split 16 bit immediate.
+ S split 16 bit immediate, aligned.
+ e src1 floating point register.
+ f src2 floating point register.
+ g dest floating point register.
+
+*/
+
+/* The order of the opcodes in this table is significant:
+
+ * The assembler requires that all instances of the same mnemonic must be
+ consecutive. If they aren't, the assembler will bomb at runtime.
+
+ * The disassembler should not care about the order of the opcodes. */
+
+static struct i860_opcode i860_opcodes[] =
+{
+
+/* REG-Format Instructions */
+{ "ld.c", 0x30000000, 0xcc000000, "c,d", 0 }, /* ld.c csrc2,idest */
+{ "ld.b", 0x00000000, 0xfc000000, "1(2),d", 0 }, /* ld.b isrc1(isrc2),idest */
+{ "ld.b", 0x04000000, 0xf8000000, "I(2),d", E_ADDR }, /* ld.b #const(isrc2),idest */
+{ "ld.s", 0x10000000, 0xec000001, "1(2),d", 0 }, /* ld.s isrc1(isrc2),idest */
+{ "ld.s", 0x14000001, 0xe8000000, "I(2),d", E_ADDR }, /* ld.s #const(isrc2),idest */
+{ "ld.l", 0x10000001, 0xec000000, "1(2),d", 0 }, /* ld.l isrc1(isrc2),idest */
+{ "ld.l", 0x14000001, 0xe8000000, "I(2),d", E_ADDR }, /* ld.l #const(isrc2),idest */
+
+{ "st.c", 0x38000000, 0xc4000000, "1,c", 0 }, /* st.c isrc1ni,csrc2 */
+{ "st.b", 0x0c000000, 0xf0000000, "1,S(2)", E_ADDR }, /* st.b isrc1ni,#const(isrc2) */
+{ "st.s", 0x1c000000, 0xe0000000, "1,S(2)", E_ADDR }, /* st.s isrc1ni,#const(isrc2) */
+{ "st.l", 0x1c000001, 0xe0000000, "1,S(2)", E_ADDR }, /* st.l isrc1ni,#const(isrc2) */
+
+{ "ixfr", 0x08000000, 0xf4000000, "1,g", 0 }, /* ixfr isrc1ni,fdest */
+
+{ "fld.l", 0x20000002, 0xdc000001, "1(2),g", 0 }, /* fld.l isrc1(isrc2),fdest */
+{ "fld.l", 0x24000002, 0xd8000001, "i(2),g", E_ADDR }, /* fld.l #const(isrc2),fdest */
+{ "fld.l", 0x20000003, 0xdc000000, "1(2)++,g", 0 }, /* fld.l isrc1(isrc2)++,fdest */
+{ "fld.l", 0x24000003, 0xd8000000, "i(2)++,g", E_ADDR }, /* fld.l #const(isrc2)++,fdest */
+{ "fld.d", 0x20000000, 0xdc000007, "1(2),g", 0 }, /* fld.d isrc1(isrc2),fdest */
+{ "fld.d", 0x24000000, 0xd8000007, "i(2),g", E_ADDR }, /* fld.d #const(isrc2),fdest */
+{ "fld.d", 0x20000001, 0xdc000006, "1(2)++,g", 0 }, /* fld.d isrc1(isrc2)++,fdest */
+{ "fld.d", 0x24000001, 0xd8000006, "i(2)++,g", E_ADDR }, /* fld.d #const(isrc2)++,fdest */
+{ "fld.q", 0x20000004, 0xdc000003, "1(2),g", 0 }, /* fld.q isrc1(isrc2),fdest */
+{ "fld.q", 0x24000004, 0xd8000003, "i(2),g", E_ADDR }, /* fld.q #const(isrc2),fdest */
+{ "fld.q", 0x20000005, 0xdc000002, "1(2)++,g", 0 }, /* fld.q isrc1(isrc2)++,fdest */
+{ "fld.q", 0x24000005, 0xd8000002, "i(2)++,g", E_ADDR }, /* fld.q #const(isrc2)++,fdest */
+
+{ "pfld.l", 0x60000000, 0x9c000003, "1(2),g", 0 }, /* pfld.l isrc1(isrc2),fdest */
+{ "pfld.l", 0x64000000, 0x98000003, "i(2),g", E_ADDR }, /* pfld.l #const(isrc2),fdest */
+{ "pfld.l", 0x60000001, 0x9c000002, "1(2)++,g", 0 }, /* pfld.l isrc1(isrc2)++,fdest */
+{ "pfld.l", 0x64000001, 0x98000002, "i(2)++,g", E_ADDR }, /* pfld.l #const(isrc2)++,fdest */
+{ "pfld.d", 0x60000000, 0x9c000007, "1(2),g", 0 }, /* pfld.d isrc1(isrc2),fdest */
+{ "pfld.d", 0x64000000, 0x98000007, "i(2),g", E_ADDR }, /* pfld.d #const(isrc2),fdest */
+{ "pfld.d", 0x60000001, 0x9c000006, "1(2)++,g", 0 }, /* pfld.d isrc1(isrc2)++,fdest */
+{ "pfld.d", 0x64000001, 0x98000006, "i(2)++,g", E_ADDR }, /* pfld.d #const(isrc2)++,fdest */
+
+{ "fst.l", 0x28000002, 0xd4000001, "g,1(2)", 0 }, /* fst.l fdest,isrc1(isrc2) */
+{ "fst.l", 0x2c000002, 0xd0000001, "g,i(2)", E_ADDR }, /* fst.l fdest,#const(isrc2) */
+{ "fst.l", 0x28000003, 0xd4000000, "g,1(2)++", 0 }, /* fst.l fdest,isrc1(isrc2)++ */
+{ "fst.l", 0x2c000003, 0xd0000000, "g,i(2)++", E_ADDR }, /* fst.l fdest,#const(isrc2)++ */
+{ "fst.d", 0x28000000, 0xd4000007, "g,1(2)", 0 }, /* fst.d fdest,isrc1(isrc2) */
+{ "fst.d", 0x2c000000, 0xd0000007, "g,i(2)", E_ADDR }, /* fst.d fdest,#const(isrc2) */
+{ "fst.d", 0x28000001, 0xd4000006, "g,1(2)++", 0 }, /* fst.d fdest,isrc1(isrc2)++ */
+{ "fst.d", 0x2c000001, 0xd0000006, "g,i(2)++", E_ADDR }, /* fst.d fdest,#const(isrc2)++ */
+{ "fst.q", 0x28000004, 0xd4000003, "g,1(2)", 0 }, /* fst.q fdest,isrc1(isrc2) */
+{ "fst.q", 0x2c000004, 0xd0000003, "g,i(2)", E_ADDR }, /* fst.q fdest,#const(isrc2) */
+{ "fst.q", 0x28000005, 0xd4000002, "g,1(2)++", 0 }, /* fst.q fdest,isrc1(isrc2)++ */
+{ "fst.q", 0x2c000005, 0xd0000002, "g,i(2)++", E_ADDR }, /* fst.q fdest,#const(isrc2)++ */
+
+{ "pst.d", 0x3c000000, 0xc0000007, "g,i(2)", E_ADDR }, /* pst.d fdest,#const(isrc2) */
+{ "pst.d", 0x3c000001, 0xc0000006, "g,i(2)++", E_ADDR }, /* pst.d fdest,#const(isrc2)++ */
+
+{ "addu", 0x80000000, 0x7c000000, "1,2,d", 0 }, /* addu isrc1,isrc2,idest */
+{ "addu", 0x84000000, 0x78000000, "i,2,d", E_S32 }, /* addu #const,isrc2,idest */
+{ "adds", 0x90000000, 0x6c000000, "1,2,d", 0 }, /* adds isrc1,isrc2,idest */
+{ "adds", 0x94000000, 0x68000000, "i,2,d", E_S32 }, /* adds #const,isrc2,idest */
+{ "subu", 0x88000000, 0x74000000, "1,2,d", 0 }, /* subu isrc1,isrc2,idest */
+{ "subu", 0x8c000000, 0x70000000, "i,2,d", E_S32 }, /* subu #const,isrc2,idest */
+{ "subs", 0x98000000, 0x64000000, "1,2,d", 0 }, /* subs isrc1,isrc2,idest */
+{ "subs", 0x9c000000, 0x60000000, "i,2,d", E_S32 }, /* subs #const,isrc2,idest */
+
+{ "shl", 0xa0000000, 0x5c000000, "1,2,d", 0 }, /* shl isrc1,isrc2,idest */
+{ "shl", 0xa4000000, 0x58000000, "i,2,d", 0 }, /* shl #const,isrc2,idest */
+{ "shr", 0xa8000000, 0x54000000, "1,2,d", 0 }, /* shr isrc1,isrc2,idest */
+{ "shr", 0xac000000, 0x50000000, "i,2,d", 0 }, /* shr #const,isrc2,idest */
+{ "shrd", 0xb0000000, 0x4c000000, "1,2,d", 0 }, /* shrd isrc1,isrc2,idest */
+{ "shra", 0xb8000000, 0x44000000, "1,2,d", 0 }, /* shra isrc1,isrc2,idest */
+{ "shra", 0xbc000000, 0x40000000, "i,2,d", 0 }, /* shra #const,isrc2,idest */
+
+{ "mov", 0xa0000000, 0x5c00f800, "2,d", 0 }, /* shl r0,isrc2,idest */
+{ "mov", 0x94000000, 0x69e00000, "i,d", E_MOV }, /* adds #const,r0,idest */
+{ "nop", 0xa0000000, 0x5ffff800, "", 0 }, /* shl r0,r0,r0 */
+{ "fnop", 0xb0000000, 0x4ffff800, "", 0 }, /* shrd r0,r0,r0 */
+
+{ "trap", 0x44000000, 0xb8000000, "1,2,d", 0 }, /* trap isrc1ni,isrc2,idest */
+
+{ "flush", 0x34000000, 0xc81f0001, "i(2)", E_ADDR }, /* flush #const(isrc2) */
+{ "flush", 0x34000001, 0xc81f0000, "i(2)++", E_ADDR }, /* flush #const(isrc2)++ */
+
+{ "and", 0xc0000000, 0x3c000000, "1,2,d", 0 }, /* and isrc1,isrc2,idest */
+{ "and", 0xc4000000, 0x38000000, "i,2,d", E_AND }, /* and #const,isrc2,idest */
+{ "andh", 0xc8000000, 0x34000000, "1,2,d", 0 }, /* andh isrc1,isrc2,idest */
+{ "andh", 0xcc000000, 0x30000000, "i,2,d", 0 }, /* andh #const,isrc2,idest */
+{ "andnot", 0xd0000000, 0x2c000000, "1,2,d", 0 }, /* andnot isrc1,isrc2,idest */
+{ "andnot", 0xd4000000, 0x28000000, "i,2,d", E_U32 }, /* andnot #const,isrc2,idest */
+{ "andnoth", 0xd8000000, 0x24000000, "1,2,d", 0 }, /* andnoth isrc1,isrc2,idest */
+{ "andnoth", 0xdc000000, 0x20000000, "i,2,d", 0 }, /* andnoth #const,isrc2,idest */
+{ "or", 0xe0000000, 0x1c000000, "1,2,d", 0 }, /* or isrc1,isrc2,idest */
+{ "or", 0xe4000000, 0x18000000, "i,2,d", E_U32 }, /* or #const,isrc2,idest */
+{ "orh", 0xe8000000, 0x14000000, "1,2,d", 0 }, /* orh isrc1,isrc2,idest */
+{ "orh", 0xec000000, 0x10000000, "i,2,d", 0 }, /* orh #const,isrc2,idest */
+{ "xor", 0xf0000000, 0x0c000000, "1,2,d", 0 }, /* xor isrc1,isrc2,idest */
+{ "xor", 0xf4000000, 0x08000000, "i,2,d", E_U32 }, /* xor #const,isrc2,idest */
+{ "xorh", 0xf8000000, 0x04000000, "1,2,d", 0 }, /* xorh isrc1,isrc2,idest */
+{ "xorh", 0xfc000000, 0x00000000, "i,2,d", 0 }, /* xorh #const,isrc2,idest */
+
+{ "bte", 0x58000000, 0xa4000000, "1,2,s", 0 }, /* bte isrc1s,isrc2,sbroff */
+{ "bte", 0x5c000000, 0xa0000000, "5,2,s", 0 }, /* bte #const5,isrc2,sbroff */
+{ "btne", 0x50000000, 0xac000000, "1,2,s", 0 }, /* btne isrc1s,isrc2,sbroff */
+{ "btne", 0x54000000, 0xa8000000, "5,2,s", 0 }, /* btne #const5,isrc2,sbroff */
+{ "bla", 0xb4000000, 0x48000000, "1,2,s", E_DELAY }, /* bla isrc1s,isrc2,sbroff */
+{ "bri", 0x40000000, 0xbc000000, "1", E_DELAY }, /* bri isrc1ni */
+
+/* Core Escape Instruction Format */
+{ "lock", 0x4c000001, 0xb000001e, "", 0 }, /* lock set BL in dirbase */
+{ "calli", 0x4c000002, 0xb000001d, "1", E_DELAY }, /* calli isrc1ni */
+{ "intovr", 0x4c000004, 0xb000001b, "", 0 }, /* intovr trap on integer overflow */
+{ "unlock", 0x4c000007, 0xb0000018, "", 0 }, /* unlock clear BL in dirbase */
+
+/* CTRL-Format Instructions */
+{ "br", 0x68000000, 0x94000000, "l", E_DELAY }, /* br lbroff */
+{ "call", 0x6c000000, 0x90000000, "l", E_DELAY }, /* call lbroff */
+{ "bc", 0x70000000, 0x8c000000, "l", 0 }, /* bc lbroff */
+{ "bc.t", 0x74000000, 0x88000000, "l", E_DELAY }, /* bc.t lbroff */
+{ "bnc", 0x78000000, 0x84000000, "l", 0 }, /* bnc lbroff */
+{ "bnc.t", 0x7c000000, 0x80000000, "l", E_DELAY }, /* bnc.t lbroff */
+
+/* Floating Point Escape Instruction Format - pfam.p fsrc1,fsrc2,fdest */
+{ "r2p1.ss", 0x48000400, 0xb40003ff, "e,f,g", 0 },
+{ "r2p1.sd", 0x48000480, 0xb400037f, "e,f,g", 0 },
+{ "r2p1.dd", 0x48000580, 0xb400027f, "e,f,g", 0 },
+{ "r2pt.ss", 0x48000401, 0xb40003fe, "e,f,g", 0 },
+{ "r2pt.sd", 0x48000481, 0xb400037e, "e,f,g", 0 },
+{ "r2pt.dd", 0x48000581, 0xb400027e, "e,f,g", 0 },
+{ "r2ap1.ss", 0x48000402, 0xb40003fd, "e,f,g", 0 },
+{ "r2ap1.sd", 0x48000482, 0xb400037d, "e,f,g", 0 },
+{ "r2ap1.dd", 0x48000582, 0xb400027d, "e,f,g", 0 },
+{ "r2apt.ss", 0x48000403, 0xb40003fc, "e,f,g", 0 },
+{ "r2apt.sd", 0x48000483, 0xb400037c, "e,f,g", 0 },
+{ "r2apt.dd", 0x48000583, 0xb400027c, "e,f,g", 0 },
+{ "i2p1.ss", 0x48000404, 0xb40003fb, "e,f,g", 0 },
+{ "i2p1.sd", 0x48000484, 0xb400037b, "e,f,g", 0 },
+{ "i2p1.dd", 0x48000584, 0xb400027b, "e,f,g", 0 },
+{ "i2pt.ss", 0x48000405, 0xb40003fa, "e,f,g", 0 },
+{ "i2pt.sd", 0x48000485, 0xb400037a, "e,f,g", 0 },
+{ "i2pt.dd", 0x48000585, 0xb400027a, "e,f,g", 0 },
+{ "i2ap1.ss", 0x48000406, 0xb40003f9, "e,f,g", 0 },
+{ "i2ap1.sd", 0x48000486, 0xb4000379, "e,f,g", 0 },
+{ "i2ap1.dd", 0x48000586, 0xb4000279, "e,f,g", 0 },
+{ "i2apt.ss", 0x48000407, 0xb40003f8, "e,f,g", 0 },
+{ "i2apt.sd", 0x48000487, 0xb4000378, "e,f,g", 0 },
+{ "i2apt.dd", 0x48000587, 0xb4000278, "e,f,g", 0 },
+{ "rat1p2.ss", 0x48000408, 0xb40003f7, "e,f,g", 0 },
+{ "rat1p2.sd", 0x48000488, 0xb4000377, "e,f,g", 0 },
+{ "rat1p2.dd", 0x48000588, 0xb4000277, "e,f,g", 0 },
+{ "m12apm.ss", 0x48000409, 0xb40003f6, "e,f,g", 0 },
+{ "m12apm.sd", 0x48000489, 0xb4000376, "e,f,g", 0 },
+{ "m12apm.dd", 0x48000589, 0xb4000276, "e,f,g", 0 },
+{ "ra1p2.ss", 0x4800040a, 0xb40003f5, "e,f,g", 0 },
+{ "ra1p2.sd", 0x4800048a, 0xb4000375, "e,f,g", 0 },
+{ "ra1p2.dd", 0x4800058a, 0xb4000275, "e,f,g", 0 },
+{ "m12ttpa.ss", 0x4800040b, 0xb40003f4, "e,f,g", 0 },
+{ "m12ttpa.sd", 0x4800048b, 0xb4000374, "e,f,g", 0 },
+{ "m12ttpa.dd", 0x4800058b, 0xb4000274, "e,f,g", 0 },
+{ "iat1p2.ss", 0x4800040c, 0xb40003f3, "e,f,g", 0 },
+{ "iat1p2.sd", 0x4800048c, 0xb4000373, "e,f,g", 0 },
+{ "iat1p2.dd", 0x4800058c, 0xb4000273, "e,f,g", 0 },
+{ "m12tpm.ss", 0x4800040d, 0xb40003f2, "e,f,g", 0 },
+{ "m12tpm.sd", 0x4800048d, 0xb4000372, "e,f,g", 0 },
+{ "m12tpm.dd", 0x4800058d, 0xb4000272, "e,f,g", 0 },
+{ "ia1p2.ss", 0x4800040e, 0xb40003f1, "e,f,g", 0 },
+{ "ia1p2.sd", 0x4800048e, 0xb4000371, "e,f,g", 0 },
+{ "ia1p2.dd", 0x4800058e, 0xb4000271, "e,f,g", 0 },
+{ "m12tpa.ss", 0x4800040f, 0xb40003f0, "e,f,g", 0 },
+{ "m12tpa.sd", 0x4800048f, 0xb4000370, "e,f,g", 0 },
+{ "m12tpa.dd", 0x4800058f, 0xb4000270, "e,f,g", 0 },
+
+/* Floating Point Escape Instruction Format - pfsm.p fsrc1,fsrc2,fdest */
+{ "r2s1.ss", 0x48000410, 0xb40003ef, "e,f,g", 0 },
+{ "r2s1.sd", 0x48000490, 0xb400036f, "e,f,g", 0 },
+{ "r2s1.dd", 0x48000590, 0xb400026f, "e,f,g", 0 },
+{ "r2st.ss", 0x48000411, 0xb40003ee, "e,f,g", 0 },
+{ "r2st.sd", 0x48000491, 0xb400036e, "e,f,g", 0 },
+{ "r2st.dd", 0x48000591, 0xb400026e, "e,f,g", 0 },
+{ "r2as1.ss", 0x48000412, 0xb40003ed, "e,f,g", 0 },
+{ "r2as1.sd", 0x48000492, 0xb400036d, "e,f,g", 0 },
+{ "r2as1.dd", 0x48000592, 0xb400026d, "e,f,g", 0 },
+{ "r2ast.ss", 0x48000413, 0xb40003ec, "e,f,g", 0 },
+{ "r2ast.sd", 0x48000493, 0xb400036c, "e,f,g", 0 },
+{ "r2ast.dd", 0x48000593, 0xb400026c, "e,f,g", 0 },
+{ "i2s1.ss", 0x48000414, 0xb40003eb, "e,f,g", 0 },
+{ "i2s1.sd", 0x48000494, 0xb400036b, "e,f,g", 0 },
+{ "i2s1.dd", 0x48000594, 0xb400026b, "e,f,g", 0 },
+{ "i2st.ss", 0x48000415, 0xb40003ea, "e,f,g", 0 },
+{ "i2st.sd", 0x48000495, 0xb400036a, "e,f,g", 0 },
+{ "i2st.dd", 0x48000595, 0xb400026a, "e,f,g", 0 },
+{ "i2as1.ss", 0x48000416, 0xb40003e9, "e,f,g", 0 },
+{ "i2as1.sd", 0x48000496, 0xb4000369, "e,f,g", 0 },
+{ "i2as1.dd", 0x48000596, 0xb4000269, "e,f,g", 0 },
+{ "i2ast.ss", 0x48000417, 0xb40003e8, "e,f,g", 0 },
+{ "i2ast.sd", 0x48000497, 0xb4000368, "e,f,g", 0 },
+{ "i2ast.dd", 0x48000597, 0xb4000268, "e,f,g", 0 },
+{ "rat1s2.ss", 0x48000418, 0xb40003e7, "e,f,g", 0 },
+{ "rat1s2.sd", 0x48000498, 0xb4000367, "e,f,g", 0 },
+{ "rat1s2.dd", 0x48000598, 0xb4000267, "e,f,g", 0 },
+{ "m12asm.ss", 0x48000419, 0xb40003e6, "e,f,g", 0 },
+{ "m12asm.sd", 0x48000499, 0xb4000366, "e,f,g", 0 },
+{ "m12asm.dd", 0x48000599, 0xb4000266, "e,f,g", 0 },
+{ "ra1s2.ss", 0x4800041a, 0xb40003e5, "e,f,g", 0 },
+{ "ra1s2.sd", 0x4800049a, 0xb4000365, "e,f,g", 0 },
+{ "ra1s2.dd", 0x4800059a, 0xb4000265, "e,f,g", 0 },
+{ "m12ttsa.ss", 0x4800041b, 0xb40003e4, "e,f,g", 0 },
+{ "m12ttsa.sd", 0x4800049b, 0xb4000364, "e,f,g", 0 },
+{ "m12ttsa.dd", 0x4800059b, 0xb4000264, "e,f,g", 0 },
+{ "iat1s2.ss", 0x4800041c, 0xb40003e3, "e,f,g", 0 },
+{ "iat1s2.sd", 0x4800049c, 0xb4000363, "e,f,g", 0 },
+{ "iat1s2.dd", 0x4800059c, 0xb4000263, "e,f,g", 0 },
+{ "m12tsm.ss", 0x4800041d, 0xb40003e2, "e,f,g", 0 },
+{ "m12tsm.sd", 0x4800049d, 0xb4000362, "e,f,g", 0 },
+{ "m12tsm.dd", 0x4800059d, 0xb4000262, "e,f,g", 0 },
+{ "ia1s2.ss", 0x4800041e, 0xb40003e1, "e,f,g", 0 },
+{ "ia1s2.sd", 0x4800049e, 0xb4000361, "e,f,g", 0 },
+{ "ia1s2.dd", 0x4800059e, 0xb4000261, "e,f,g", 0 },
+{ "m12tsa.ss", 0x4800041f, 0xb40003e0, "e,f,g", 0 },
+{ "m12tsa.sd", 0x4800049f, 0xb4000360, "e,f,g", 0 },
+{ "m12tsa.dd", 0x4800059f, 0xb4000260, "e,f,g", 0 },
+
+/* Floating Point Escape Instruction Format - pfmam.p fsrc1,fsrc2,fdest */
+{ "mr2p1.ss", 0x48000000, 0xb40007ff, "e,f,g", 0 },
+{ "mr2p1.sd", 0x48000080, 0xb400077f, "e,f,g", 0 },
+{ "mr2p1.dd", 0x48000180, 0xb400067f, "e,f,g", 0 },
+{ "mr2pt.ss", 0x48000001, 0xb40007fe, "e,f,g", 0 },
+{ "mr2pt.sd", 0x48000081, 0xb400077e, "e,f,g", 0 },
+{ "mr2pt.dd", 0x48000181, 0xb400067e, "e,f,g", 0 },
+{ "mr2mp1.ss", 0x48000002, 0xb40007fd, "e,f,g", 0 },
+{ "mr2mp1.sd", 0x48000082, 0xb400077d, "e,f,g", 0 },
+{ "mr2mp1.dd", 0x48000182, 0xb400067d, "e,f,g", 0 },
+{ "mr2mpt.ss", 0x48000003, 0xb40007fc, "e,f,g", 0 },
+{ "mr2mpt.sd", 0x48000083, 0xb400077c, "e,f,g", 0 },
+{ "mr2mpt.dd", 0x48000183, 0xb400067c, "e,f,g", 0 },
+{ "mi2p1.ss", 0x48000004, 0xb40007fb, "e,f,g", 0 },
+{ "mi2p1.sd", 0x48000084, 0xb400077b, "e,f,g", 0 },
+{ "mi2p1.dd", 0x48000184, 0xb400067b, "e,f,g", 0 },
+{ "mi2pt.ss", 0x48000005, 0xb40007fa, "e,f,g", 0 },
+{ "mi2pt.sd", 0x48000085, 0xb400077a, "e,f,g", 0 },
+{ "mi2pt.dd", 0x48000185, 0xb400067a, "e,f,g", 0 },
+{ "mi2mp1.ss", 0x48000006, 0xb40007f9, "e,f,g", 0 },
+{ "mi2mp1.sd", 0x48000086, 0xb4000779, "e,f,g", 0 },
+{ "mi2mp1.dd", 0x48000186, 0xb4000679, "e,f,g", 0 },
+{ "mi2mpt.ss", 0x48000007, 0xb40007f8, "e,f,g", 0 },
+{ "mi2mpt.sd", 0x48000087, 0xb4000778, "e,f,g", 0 },
+{ "mi2mpt.dd", 0x48000187, 0xb4000678, "e,f,g", 0 },
+{ "mrmt1p2.ss", 0x48000008, 0xb40007f7, "e,f,g", 0 },
+{ "mrmt1p2.sd", 0x48000088, 0xb4000777, "e,f,g", 0 },
+{ "mrmt1p2.dd", 0x48000188, 0xb4000677, "e,f,g", 0 },
+{ "mm12mpm.ss", 0x48000009, 0xb40007f6, "e,f,g", 0 },
+{ "mm12mpm.sd", 0x48000089, 0xb4000776, "e,f,g", 0 },
+{ "mm12mpm.dd", 0x48000189, 0xb4000676, "e,f,g", 0 },
+{ "mrm1p2.ss", 0x4800000a, 0xb40007f5, "e,f,g", 0 },
+{ "mrm1p2.sd", 0x4800008a, 0xb4000775, "e,f,g", 0 },
+{ "mrm1p2.dd", 0x4800018a, 0xb4000675, "e,f,g", 0 },
+{ "mm12ttpm.ss",0x4800000b, 0xb40007f4, "e,f,g", 0 },
+{ "mm12ttpm.sd",0x4800008b, 0xb4000774, "e,f,g", 0 },
+{ "mm12ttpm.dd",0x4800018b, 0xb4000674, "e,f,g", 0 },
+{ "mimt1p2.ss", 0x4800000c, 0xb40007f3, "e,f,g", 0 },
+{ "mimt1p2.sd", 0x4800008c, 0xb4000773, "e,f,g", 0 },
+{ "mimt1p2.dd", 0x4800018c, 0xb4000673, "e,f,g", 0 },
+{ "mm12tpm.ss", 0x4800000d, 0xb40007f2, "e,f,g", 0 },
+{ "mm12tpm.sd", 0x4800008d, 0xb4000772, "e,f,g", 0 },
+{ "mm12tpm.dd", 0x4800018d, 0xb4000672, "e,f,g", 0 },
+{ "mim1p2.ss", 0x4800000e, 0xb40007f1, "e,f,g", 0 },
+{ "mim1p2.sd", 0x4800008e, 0xb4000771, "e,f,g", 0 },
+{ "mim1p2.dd", 0x4800018e, 0xb4000671, "e,f,g", 0 },
+
+/* Floating Point Escape Instruction Format - pfmsm.p fsrc1,fsrc2,fdest */
+{ "mr2s1.ss", 0x48000010, 0xb40007ef, "e,f,g", 0 },
+{ "mr2s1.sd", 0x48000090, 0xb400076f, "e,f,g", 0 },
+{ "mr2s1.dd", 0x48000190, 0xb400066f, "e,f,g", 0 },
+{ "mr2st.ss", 0x48000011, 0xb40007ee, "e,f,g", 0 },
+{ "mr2st.sd", 0x48000091, 0xb400076e, "e,f,g", 0 },
+{ "mr2st.dd", 0x48000191, 0xb400066e, "e,f,g", 0 },
+{ "mr2ms1.ss", 0x48000012, 0xb40007ed, "e,f,g", 0 },
+{ "mr2ms1.sd", 0x48000092, 0xb400076d, "e,f,g", 0 },
+{ "mr2ms1.dd", 0x48000192, 0xb400066d, "e,f,g", 0 },
+{ "mr2mst.ss", 0x48000013, 0xb40007ec, "e,f,g", 0 },
+{ "mr2mst.sd", 0x48000093, 0xb400076c, "e,f,g", 0 },
+{ "mr2mst.dd", 0x48000193, 0xb400066c, "e,f,g", 0 },
+{ "mi2s1.ss", 0x48000014, 0xb40007eb, "e,f,g", 0 },
+{ "mi2s1.sd", 0x48000094, 0xb400076b, "e,f,g", 0 },
+{ "mi2s1.dd", 0x48000194, 0xb400066b, "e,f,g", 0 },
+{ "mi2st.ss", 0x48000015, 0xb40007ea, "e,f,g", 0 },
+{ "mi2st.sd", 0x48000095, 0xb400076a, "e,f,g", 0 },
+{ "mi2st.dd", 0x48000195, 0xb400066a, "e,f,g", 0 },
+{ "mi2ms1.ss", 0x48000016, 0xb40007e9, "e,f,g", 0 },
+{ "mi2ms1.sd", 0x48000096, 0xb4000769, "e,f,g", 0 },
+{ "mi2ms1.dd", 0x48000196, 0xb4000669, "e,f,g", 0 },
+{ "mi2mst.ss", 0x48000017, 0xb40007e8, "e,f,g", 0 },
+{ "mi2mst.sd", 0x48000097, 0xb4000768, "e,f,g", 0 },
+{ "mi2mst.dd", 0x48000197, 0xb4000668, "e,f,g", 0 },
+{ "mrmt1s2.ss", 0x48000018, 0xb40007e7, "e,f,g", 0 },
+{ "mrmt1s2.sd", 0x48000098, 0xb4000767, "e,f,g", 0 },
+{ "mrmt1s2.dd", 0x48000198, 0xb4000667, "e,f,g", 0 },
+{ "mm12msm.ss", 0x48000019, 0xb40007e6, "e,f,g", 0 },
+{ "mm12msm.sd", 0x48000099, 0xb4000766, "e,f,g", 0 },
+{ "mm12msm.dd", 0x48000199, 0xb4000666, "e,f,g", 0 },
+{ "mrm1s2.ss", 0x4800001a, 0xb40007e5, "e,f,g", 0 },
+{ "mrm1s2.sd", 0x4800009a, 0xb4000765, "e,f,g", 0 },
+{ "mrm1s2.dd", 0x4800019a, 0xb4000665, "e,f,g", 0 },
+{ "mm12ttsm.ss",0x4800001b, 0xb40007e4, "e,f,g", 0 },
+{ "mm12ttsm.sd",0x4800009b, 0xb4000764, "e,f,g", 0 },
+{ "mm12ttsm.dd",0x4800019b, 0xb4000664, "e,f,g", 0 },
+{ "mimt1s2.ss", 0x4800001c, 0xb40007e3, "e,f,g", 0 },
+{ "mimt1s2.sd", 0x4800009c, 0xb4000763, "e,f,g", 0 },
+{ "mimt1s2.dd", 0x4800019c, 0xb4000663, "e,f,g", 0 },
+{ "mm12tsm.ss", 0x4800001d, 0xb40007e2, "e,f,g", 0 },
+{ "mm12tsm.sd", 0x4800009d, 0xb4000762, "e,f,g", 0 },
+{ "mm12tsm.dd", 0x4800019d, 0xb4000662, "e,f,g", 0 },
+{ "mim1s2.ss", 0x4800001e, 0xb40007e1, "e,f,g", 0 },
+{ "mim1s2.sd", 0x4800009e, 0xb4000761, "e,f,g", 0 },
+{ "mim1s2.dd", 0x4800019e, 0xb4000661, "e,f,g", 0 },
+
+
+{ "fmul.ss", 0x48000020, 0xb40007df, "e,f,g", 0 }, /* fmul.p fsrc1,fsrc2,fdest */
+{ "fmul.sd", 0x480000a0, 0xb400075f, "e,f,g", 0 }, /* fmul.p fsrc1,fsrc2,fdest */
+{ "fmul.dd", 0x480001a0, 0xb400065f, "e,f,g", 0 }, /* fmul.p fsrc1,fsrc2,fdest */
+{ "pfmul.ss", 0x48000420, 0xb40003df, "e,f,g", 0 }, /* pfmul.p fsrc1,fsrc2,fdest */
+{ "pfmul.sd", 0x480004a0, 0xb400035f, "e,f,g", 0 }, /* pfmul.p fsrc1,fsrc2,fdest */
+{ "pfmul.dd", 0x480005a0, 0xb400025f, "e,f,g", 0 }, /* pfmul.p fsrc1,fsrc2,fdest */
+{ "pfmul3.dd", 0x480005a4, 0xb400025b, "e,f,g", 0 }, /* pfmul3.p fsrc1,fsrc2,fdest */
+{ "fmlow.dd", 0x480001a1, 0xb400065e, "e,f,g", 0 }, /* fmlow.dd fsrc1,fsrc2,fdest */
+{ "frcp.ss", 0x48000022, 0xb40007dd, "f,g", 0 }, /* frcp.p fsrc2,fdest */
+{ "frcp.sd", 0x480000a2, 0xb400075d, "f,g", 0 }, /* frcp.p fsrc2,fdest */
+{ "frcp.dd", 0x480001a2, 0xb400065d, "f,g", 0 }, /* frcp.p fsrc2,fdest */
+{ "frsqr.ss", 0x48000023, 0xb40007dc, "f,g", 0 }, /* frsqr.p fsrc2,fdest */
+{ "frsqr.sd", 0x480000a3, 0xb400075c, "f,g", 0 }, /* frsqr.p fsrc2,fdest */
+{ "frsqr.dd", 0x480001a3, 0xb400065c, "f,g", 0 }, /* frsqr.p fsrc2,fdest */
+{ "fadd.ss", 0x48000030, 0xb40007cf, "e,f,g", 0 }, /* fadd.p fsrc1,fsrc2,fdest */
+{ "fadd.sd", 0x480000b0, 0xb400074f, "e,f,g", 0 }, /* fadd.p fsrc1,fsrc2,fdest */
+{ "fadd.dd", 0x480001b0, 0xb400064f, "e,f,g", 0 }, /* fadd.p fsrc1,fsrc2,fdest */
+{ "pfadd.ss", 0x48000430, 0xb40003cf, "e,f,g", 0 }, /* pfadd.p fsrc1,fsrc2,fdest */
+{ "pfadd.sd", 0x480004b0, 0xb400034f, "e,f,g", 0 }, /* pfadd.p fsrc1,fsrc2,fdest */
+{ "pfadd.dd", 0x480005b0, 0xb400024f, "e,f,g", 0 }, /* pfadd.p fsrc1,fsrc2,fdest */
+{ "fsub.ss", 0x48000031, 0xb40007ce, "e,f,g", 0 }, /* fsub.p fsrc1,fsrc2,fdest */
+{ "fsub.sd", 0x480000b1, 0xb400074e, "e,f,g", 0 }, /* fsub.p fsrc1,fsrc2,fdest */
+{ "fsub.dd", 0x480001b1, 0xb400064e, "e,f,g", 0 }, /* fsub.p fsrc1,fsrc2,fdest */
+{ "pfsub.ss", 0x48000431, 0xb40003ce, "e,f,g", 0 }, /* pfsub.p fsrc1,fsrc2,fdest */
+{ "pfsub.sd", 0x480004b1, 0xb400034e, "e,f,g", 0 }, /* pfsub.p fsrc1,fsrc2,fdest */
+{ "pfsub.dd", 0x480005b1, 0xb400024e, "e,f,g", 0 }, /* pfsub.p fsrc1,fsrc2,fdest */
+{ "fix.ss", 0x48000032, 0xb40007cd, "e,g", 0 }, /* fix.p fsrc1,fdest */
+{ "fix.sd", 0x480000b2, 0xb400074d, "e,g", 0 }, /* fix.p fsrc1,fdest */
+{ "fix.dd", 0x480001b2, 0xb400064d, "e,g", 0 }, /* fix.p fsrc1,fdest */
+{ "pfix.ss", 0x48000432, 0xb40003cd, "e,g", 0 }, /* pfix.p fsrc1,fdest */
+{ "pfix.sd", 0x480004b2, 0xb400034d, "e,g", 0 }, /* pfix.p fsrc1,fdest */
+{ "pfix.dd", 0x480005b2, 0xb400024d, "e,g", 0 }, /* pfix.p fsrc1,fdest */
+{ "famov.ss", 0x48000033, 0xb40007cc, "e,g", 0 }, /* famov.p fsrc1,fdest */
+{ "famov.ds", 0x48000133, 0xb40006cc, "e,g", 0 }, /* famov.p fsrc1,fdest */
+{ "famov.sd", 0x480000b3, 0xb400074c, "e,g", 0 }, /* famov.p fsrc1,fdest */
+{ "famov.dd", 0x480001b3, 0xb400064c, "e,g", 0 }, /* famov.p fsrc1,fdest */
+{ "pfamov.ss", 0x48000433, 0xb40003cc, "e,g", 0 }, /* pfamov.p fsrc1,fdest */
+{ "pfamov.ds", 0x48000533, 0xb40002cc, "e,g", 0 }, /* pfamov.p fsrc1,fdest */
+{ "pfamov.sd", 0x480004b3, 0xb400034c, "e,g", 0 }, /* pfamov.p fsrc1,fdest */
+{ "pfamov.dd", 0x480005b3, 0xb400024c, "e,g", 0 }, /* pfamov.p fsrc1,fdest */
+/* pfgt has R bit cleared; pfle has R bit set */
+{ "pfgt.ss", 0x48000434, 0xb40003cb, "e,f,g", 0 }, /* pfgt.p fsrc1,fsrc2,fdest */
+{ "pfgt.sd", 0x48000434, 0xb40003cb, "e,f,g", 0 }, /* pfgt.p fsrc1,fsrc2,fdest */
+{ "pfgt.dd", 0x48000534, 0xb40002cb, "e,f,g", 0 }, /* pfgt.p fsrc1,fsrc2,fdest */
+/* pfgt has R bit cleared; pfle has R bit set */
+{ "pfle.ss", 0x480004b4, 0xb400034b, "e,f,g", 0 }, /* pfle.p fsrc1,fsrc2,fdest */
+{ "pfle.sd", 0x480004b4, 0xb400034b, "e,f,g", 0 }, /* pfle.p fsrc1,fsrc2,fdest */
+{ "pfle.dd", 0x480005b4, 0xb400024b, "e,f,g", 0 }, /* pfle.p fsrc1,fsrc2,fdest */
+{ "ftrunc.ss", 0x4800003a, 0xb40007c5, "e,g", 0 }, /* ftrunc.p fsrc1,fdest */
+{ "ftrunc.sd", 0x480000ba, 0xb4000745, "e,g", 0 }, /* ftrunc.p fsrc1,fdest */
+{ "ftrunc.dd", 0x480001ba, 0xb4000645, "e,g", 0 }, /* ftrunc.p fsrc1,fdest */
+{ "pftrunc.ss", 0x4800043a, 0xb40003c5, "e,g", 0 }, /* pftrunc.p fsrc1,fdest */
+{ "pftrunc.sd", 0x480004ba, 0xb4000345, "e,g", 0 }, /* pftrunc.p fsrc1,fdest */
+{ "pftrunc.dd", 0x480005ba, 0xb4000245, "e,g", 0 }, /* pftrunc.p fsrc1,fdest */
+{ "fxfr", 0x48000040, 0xb40007bf, "e,d", 0 }, /* fxfr fsrc1,idest */
+{ "fiadd.ss", 0x48000049, 0xb40007b6, "e,f,g", 0 }, /* fiadd.w fsrc1,fsrc2,fdest */
+{ "fiadd.dd", 0x480001c9, 0xb4000636, "e,f,g", 0 }, /* fiadd.w fsrc1,fsrc2,fdest */
+{ "pfiadd.ss", 0x48000449, 0xb40003b6, "e,f,g", 0 }, /* pfiadd.w fsrc1,fsrc2,fdest */
+{ "pfiadd.dd", 0x480005c9, 0xb4000236, "e,f,g", 0 }, /* pfiadd.w fsrc1,fsrc2,fdest */
+{ "fisub.ss", 0x4800004d, 0xb40007b2, "e,f,g", 0 }, /* fisub.w fsrc1,fsrc2,fdest */
+{ "fisub.dd", 0x480001cd, 0xb4000632, "e,f,g", 0 }, /* fisub.w fsrc1,fsrc2,fdest */
+{ "pfisub.ss", 0x4800044d, 0xb40003b2, "e,f,g", 0 }, /* pfisub.w fsrc1,fsrc2,fdest */
+{ "pfisub.dd", 0x480005cd, 0xb4000232, "e,f,g", 0 }, /* pfisub.w fsrc1,fsrc2,fdest */
+{ "fzchkl", 0x48000057, 0xb40007a8, "e,f,g", 0 }, /* fzchkl fsrc1,fsrc2,fdest */
+{ "pfzchkl", 0x48000457, 0xb40003a8, "e,f,g", 0 }, /* pfzchkl fsrc1,fsrc2,fdest */
+{ "fzchks", 0x4800005f, 0xb40007a0, "e,f,g", 0 }, /* fzchks fsrc1,fsrc2,fdest */
+{ "pfzchks", 0x4800045f, 0xb40003a0, "e,f,g", 0 }, /* pfzchks fsrc1,fsrc2,fdest */
+{ "faddp", 0x48000050, 0xb40007af, "e,f,g", 0 }, /* faddp fsrc1,fsrc2,fdest */
+{ "pfaddp", 0x48000450, 0xb40003af, "e,f,g", 0 }, /* pfaddp fsrc1,fsrc2,fdest */
+{ "faddz", 0x48000051, 0xb40007ae, "e,f,g", 0 }, /* faddz fsrc1,fsrc2,fdest */
+{ "pfaddz", 0x48000451, 0xb40003ae, "e,f,g", 0 }, /* pfaddz fsrc1,fsrc2,fdest */
+{ "form", 0x4800005a, 0xb40007a5, "e,g", 0 }, /* form fsrc1,fdest */
+{ "pform", 0x4800045a, 0xb40003a5, "e,g", 0 }, /* pform fsrc1,fdest */
+
+/* Floating point pseudo-instructions */
+{ "fmov.ss", 0x48000049, 0xb7e007b6, "e,g", 0 }, /* fiadd.ss fsrc1,f0,fdest */
+{ "fmov.dd", 0x480001c9, 0xb7e00636, "e,g", 0 }, /* fiadd.dd fsrc1,f0,fdest */
+{ "fmov.sd", 0x480000b0, 0xb7e0074f, "e,g", 0 }, /* fadd.sd fsrc1,f0,fdest */
+{ "fmov.ds", 0x48000130, 0xb7e006cf, "e,g", 0 }, /* fadd.ds fsrc1,f0,fdest */
+{ "pfmov.ds", 0x48000530, 0xb73002cf, "e,g", 0 }, /* pfadd.ds fsrc1,f0,fdest */
+{ "pfmov.dd", 0x480005c9, 0xb7e00236, "e,g", 0 }, /* pfiadd.dd fsrc1,f0,fdest */
+
+
+};
+
+#define NUMOPCODES ((sizeof i860_opcodes)/(sizeof i860_opcodes[0]))
+
+
diff --git a/gnu/usr.bin/as/opcode/i960.h b/gnu/usr.bin/as/opcode/i960.h
new file mode 100644
index 0000000..6a6ad42
--- /dev/null
+++ b/gnu/usr.bin/as/opcode/i960.h
@@ -0,0 +1,434 @@
+/* Basic 80960 instruction formats.
+ *
+ * The 'COJ' instructions are actually COBR instructions with the 'b' in
+ * the mnemonic replaced by a 'j'; they are ALWAYS "de-optimized" if necessary:
+ * if the displacement will not fit in 13 bits, the assembler will replace them
+ * with the corresponding compare and branch instructions.
+ *
+ * All of the 'MEMn' instructions are the same format; the 'n' in the name
+ * indicates the default index scale factor (the size of the datum operated on).
+ *
+ * The FBRA formats are not actually an instruction format. They are the
+ * "convenience directives" for branching on floating-point comparisons,
+ * each of which generates 2 instructions (a 'bno' and one other branch).
+ *
+ * The CALLJ format is not actually an instruction format. It indicates that
+ * the instruction generated (a CTRL-format 'call') should have its relocation
+ * specially flagged for link-time replacement with a 'bal' or 'calls' if
+ * appropriate.
+ */
+
+/* $Id: i960.h,v 1.1 1993/11/03 00:55:56 paul Exp $ */
+
+#define CTRL 0
+#define COBR 1
+#define COJ 2
+#define REG 3
+#define MEM1 4
+#define MEM2 5
+#define MEM4 6
+#define MEM8 7
+#define MEM12 8
+#define MEM16 9
+#define FBRA 10
+#define CALLJ 11
+
+/* Masks for the mode bits in REG format instructions */
+#define M1 0x0800
+#define M2 0x1000
+#define M3 0x2000
+
+/* Generate the 12-bit opcode for a REG format instruction by placing the
+ * high 8 bits in instruction bits 24-31, the low 4 bits in instruction bits
+ * 7-10.
+ */
+
+#define REG_OPC(opc) ((opc & 0xff0) << 20) | ((opc & 0xf) << 7)
+
+/* Generate a template for a REG format instruction: place the opcode bits
+ * in the appropriate fields and OR in mode bits for the operands that will not
+ * be used. I.e.,
+ * set m1=1, if src1 will not be used
+ * set m2=1, if src2 will not be used
+ * set m3=1, if dst will not be used
+ *
+ * Setting the "unused" mode bits to 1 speeds up instruction execution(!).
+ * The information is also useful to us because some 1-operand REG instructions
+ * use the src1 field, others the dst field; and some 2-operand REG instructions
+ * use src1/src2, others src1/dst. The set mode bits enable us to distinguish.
+ */
+#define R_0(opc) ( REG_OPC(opc) | M1 | M2 | M3 ) /* No operands */
+#define R_1(opc) ( REG_OPC(opc) | M2 | M3 ) /* 1 operand: src1 */
+#define R_1D(opc) ( REG_OPC(opc) | M1 | M2 ) /* 1 operand: dst */
+#define R_2(opc) ( REG_OPC(opc) | M3 ) /* 2 ops: src1/src2 */
+#define R_2D(opc) ( REG_OPC(opc) | M2 ) /* 2 ops: src1/dst */
+#define R_3(opc) ( REG_OPC(opc) ) /* 3 operands */
+
+/* DESCRIPTOR BYTES FOR REGISTER OPERANDS
+ *
+ * Interpret names as follows:
+ * R: global or local register only
+ * RS: global, local, or (if target allows) special-function register only
+ * RL: global or local register, or integer literal
+ * RSL: global, local, or (if target allows) special-function register;
+ * or integer literal
+ * F: global, local, or floating-point register
+ * FL: global, local, or floating-point register; or literal (including
+ * floating point)
+ *
+ * A number appended to a name indicates that registers must be aligned,
+ * as follows:
+ * 2: register number must be multiple of 2
+ * 4: register number must be multiple of 4
+ */
+
+#define SFR 0x10 /* Mask for the "sfr-OK" bit */
+#define LIT 0x08 /* Mask for the "literal-OK" bit */
+#define FP 0x04 /* Mask for "floating-point-OK" bit */
+
+/* This macro ors the bits together. Note that 'align' is a mask
+ * for the low 0, 1, or 2 bits of the register number, as appropriate.
+ */
+#define OP(align,lit,fp,sfr) ( align | lit | fp | sfr )
+
+#define R OP( 0, 0, 0, 0 )
+#define RS OP( 0, 0, 0, SFR )
+#define RL OP( 0, LIT, 0, 0 )
+#define RSL OP( 0, LIT, 0, SFR )
+#define F OP( 0, 0, FP, 0 )
+#define FL OP( 0, LIT, FP, 0 )
+#define R2 OP( 1, 0, 0, 0 )
+#define RL2 OP( 1, LIT, 0, 0 )
+#define F2 OP( 1, 0, FP, 0 )
+#define FL2 OP( 1, LIT, FP, 0 )
+#define R4 OP( 3, 0, 0, 0 )
+#define RL4 OP( 3, LIT, 0, 0 )
+#define F4 OP( 3, 0, FP, 0 )
+#define FL4 OP( 3, LIT, FP, 0 )
+
+#define M 0x7f /* Memory operand (MEMA & MEMB format instructions) */
+
+/* Macros to extract info from the register operand descriptor byte 'od'.
+ */
+#define SFR_OK(od) (od & SFR) /* TRUE if sfr operand allowed */
+#define LIT_OK(od) (od & LIT) /* TRUE if literal operand allowed */
+#define FP_OK(od) (od & FP) /* TRUE if floating-point op allowed */
+#define REG_ALIGN(od,n) ((od & 0x3 & n) == 0)
+ /* TRUE if reg #n is properly aligned */
+#define MEMOP(od) (od == M) /* TRUE if operand is a memory operand*/
+
+/* Description of a single i80960 instruction */
+struct i960_opcode {
+ long opcode; /* 32 bits, constant fields filled in, rest zeroed */
+ char *name; /* Assembler mnemonic */
+ short iclass; /* Class: see #defines below */
+ char format; /* REG, COBR, CTRL, MEMn, COJ, FBRA, or CALLJ */
+ char num_ops; /* Number of operands */
+ char operand[3];/* Operand descriptors; same order as assembler instr */
+};
+
+/* Classes of 960 intructions:
+ * - each instruction falls into one class.
+ * - each target architecture supports one or more classes.
+ *
+ * EACH CONSTANT MUST CONTAIN 1 AND ONLY 1 SET BIT!: see targ_has_iclass().
+ */
+#define I_BASE 0x01 /* 80960 base instruction set */
+#define I_CX 0x02 /* 80960Cx instruction */
+#define I_DEC 0x04 /* Decimal instruction */
+#define I_FP 0x08 /* Floating point instruction */
+#define I_KX 0x10 /* 80960Kx instruction */
+#define I_MIL 0x20 /* Military instruction */
+#define I_CASIM 0x40 /* CA simulator instruction */
+
+/******************************************************************************
+ *
+ * TABLE OF i960 INSTRUCTION DESCRIPTIONS
+ *
+ ******************************************************************************/
+
+const struct i960_opcode i960_opcodes[] = {
+
+ /* if a CTRL instruction has an operand, it's always a displacement */
+
+ { 0x09000000, "callj", I_BASE, CALLJ, 1 },/*default=='call'*/
+ { 0x08000000, "b", I_BASE, CTRL, 1 },
+ { 0x09000000, "call", I_BASE, CTRL, 1 },
+ { 0x0a000000, "ret", I_BASE, CTRL, 0 },
+ { 0x0b000000, "bal", I_BASE, CTRL, 1 },
+ { 0x10000000, "bno", I_BASE, CTRL, 1 },
+ { 0x10000000, "bf", I_BASE, CTRL, 1 }, /* same as bno */
+ { 0x10000000, "bru", I_BASE, CTRL, 1 }, /* same as bno */
+ { 0x11000000, "bg", I_BASE, CTRL, 1 },
+ { 0x11000000, "brg", I_BASE, CTRL, 1 }, /* same as bg */
+ { 0x12000000, "be", I_BASE, CTRL, 1 },
+ { 0x12000000, "bre", I_BASE, CTRL, 1 }, /* same as be */
+ { 0x13000000, "bge", I_BASE, CTRL, 1 },
+ { 0x13000000, "brge", I_BASE, CTRL, 1 }, /* same as bge */
+ { 0x14000000, "bl", I_BASE, CTRL, 1 },
+ { 0x14000000, "brl", I_BASE, CTRL, 1 }, /* same as bl */
+ { 0x15000000, "bne", I_BASE, CTRL, 1 },
+ { 0x15000000, "brlg", I_BASE, CTRL, 1 }, /* same as bne */
+ { 0x16000000, "ble", I_BASE, CTRL, 1 },
+ { 0x16000000, "brle", I_BASE, CTRL, 1 }, /* same as ble */
+ { 0x17000000, "bo", I_BASE, CTRL, 1 },
+ { 0x17000000, "bt", I_BASE, CTRL, 1 }, /* same as bo */
+ { 0x17000000, "bro", I_BASE, CTRL, 1 }, /* same as bo */
+ { 0x18000000, "faultno", I_BASE, CTRL, 0 },
+ { 0x18000000, "faultf", I_BASE, CTRL, 0 }, /*same as faultno*/
+ { 0x19000000, "faultg", I_BASE, CTRL, 0 },
+ { 0x1a000000, "faulte", I_BASE, CTRL, 0 },
+ { 0x1b000000, "faultge", I_BASE, CTRL, 0 },
+ { 0x1c000000, "faultl", I_BASE, CTRL, 0 },
+ { 0x1d000000, "faultne", I_BASE, CTRL, 0 },
+ { 0x1e000000, "faultle", I_BASE, CTRL, 0 },
+ { 0x1f000000, "faulto", I_BASE, CTRL, 0 },
+ { 0x1f000000, "faultt", I_BASE, CTRL, 0 }, /* syn for faulto */
+
+ { 0x01000000, "syscall", I_CASIM,CTRL, 0 },
+
+ /* If a COBR (or COJ) has 3 operands, the last one is always a
+ * displacement and does not appear explicitly in the table.
+ */
+
+ { 0x20000000, "testno", I_BASE, COBR, 1, R },
+ { 0x21000000, "testg", I_BASE, COBR, 1, R },
+ { 0x22000000, "teste", I_BASE, COBR, 1, R },
+ { 0x23000000, "testge", I_BASE, COBR, 1, R },
+ { 0x24000000, "testl", I_BASE, COBR, 1, R },
+ { 0x25000000, "testne", I_BASE, COBR, 1, R },
+ { 0x26000000, "testle", I_BASE, COBR, 1, R },
+ { 0x27000000, "testo", I_BASE, COBR, 1, R },
+ { 0x30000000, "bbc", I_BASE, COBR, 3, RL, RS },
+ { 0x31000000, "cmpobg", I_BASE, COBR, 3, RL, RS },
+ { 0x32000000, "cmpobe", I_BASE, COBR, 3, RL, RS },
+ { 0x33000000, "cmpobge", I_BASE, COBR, 3, RL, RS },
+ { 0x34000000, "cmpobl", I_BASE, COBR, 3, RL, RS },
+ { 0x35000000, "cmpobne", I_BASE, COBR, 3, RL, RS },
+ { 0x36000000, "cmpoble", I_BASE, COBR, 3, RL, RS },
+ { 0x37000000, "bbs", I_BASE, COBR, 3, RL, RS },
+ { 0x38000000, "cmpibno", I_BASE, COBR, 3, RL, RS },
+ { 0x39000000, "cmpibg", I_BASE, COBR, 3, RL, RS },
+ { 0x3a000000, "cmpibe", I_BASE, COBR, 3, RL, RS },
+ { 0x3b000000, "cmpibge", I_BASE, COBR, 3, RL, RS },
+ { 0x3c000000, "cmpibl", I_BASE, COBR, 3, RL, RS },
+ { 0x3d000000, "cmpibne", I_BASE, COBR, 3, RL, RS },
+ { 0x3e000000, "cmpible", I_BASE, COBR, 3, RL, RS },
+ { 0x3f000000, "cmpibo", I_BASE, COBR, 3, RL, RS },
+ { 0x31000000, "cmpojg", I_BASE, COJ, 3, RL, RS },
+ { 0x32000000, "cmpoje", I_BASE, COJ, 3, RL, RS },
+ { 0x33000000, "cmpojge", I_BASE, COJ, 3, RL, RS },
+ { 0x34000000, "cmpojl", I_BASE, COJ, 3, RL, RS },
+ { 0x35000000, "cmpojne", I_BASE, COJ, 3, RL, RS },
+ { 0x36000000, "cmpojle", I_BASE, COJ, 3, RL, RS },
+ { 0x38000000, "cmpijno", I_BASE, COJ, 3, RL, RS },
+ { 0x39000000, "cmpijg", I_BASE, COJ, 3, RL, RS },
+ { 0x3a000000, "cmpije", I_BASE, COJ, 3, RL, RS },
+ { 0x3b000000, "cmpijge", I_BASE, COJ, 3, RL, RS },
+ { 0x3c000000, "cmpijl", I_BASE, COJ, 3, RL, RS },
+ { 0x3d000000, "cmpijne", I_BASE, COJ, 3, RL, RS },
+ { 0x3e000000, "cmpijle", I_BASE, COJ, 3, RL, RS },
+ { 0x3f000000, "cmpijo", I_BASE, COJ, 3, RL, RS },
+
+ { 0x80000000, "ldob", I_BASE, MEM1, 2, M, R },
+ { 0x82000000, "stob", I_BASE, MEM1, 2, R , M },
+ { 0x84000000, "bx", I_BASE, MEM1, 1, M },
+ { 0x85000000, "balx", I_BASE, MEM1, 2, M, R },
+ { 0x86000000, "callx", I_BASE, MEM1, 1, M },
+ { 0x88000000, "ldos", I_BASE, MEM2, 2, M, R },
+ { 0x8a000000, "stos", I_BASE, MEM2, 2, R , M },
+ { 0x8c000000, "lda", I_BASE, MEM1, 2, M, R },
+ { 0x90000000, "ld", I_BASE, MEM4, 2, M, R },
+ { 0x92000000, "st", I_BASE, MEM4, 2, R , M },
+ { 0x98000000, "ldl", I_BASE, MEM8, 2, M, R2 },
+ { 0x9a000000, "stl", I_BASE, MEM8, 2, R2 ,M },
+ { 0xa0000000, "ldt", I_BASE, MEM12, 2, M, R4 },
+ { 0xa2000000, "stt", I_BASE, MEM12, 2, R4 ,M },
+ { 0xb0000000, "ldq", I_BASE, MEM16, 2, M, R4 },
+ { 0xb2000000, "stq", I_BASE, MEM16, 2, R4 ,M },
+ { 0xc0000000, "ldib", I_BASE, MEM1, 2, M, R },
+ { 0xc2000000, "stib", I_BASE, MEM1, 2, R , M },
+ { 0xc8000000, "ldis", I_BASE, MEM2, 2, M, R },
+ { 0xca000000, "stis", I_BASE, MEM2, 2, R , M },
+
+ { R_3(0x580), "notbit", I_BASE, REG, 3, RSL,RSL,RS },
+ { R_3(0x581), "and", I_BASE, REG, 3, RSL,RSL,RS },
+ { R_3(0x582), "andnot", I_BASE, REG, 3, RSL,RSL,RS },
+ { R_3(0x583), "setbit", I_BASE, REG, 3, RSL,RSL,RS },
+ { R_3(0x584), "notand", I_BASE, REG, 3, RSL,RSL,RS },
+ { R_3(0x586), "xor", I_BASE, REG, 3, RSL,RSL,RS },
+ { R_3(0x587), "or", I_BASE, REG, 3, RSL,RSL,RS },
+ { R_3(0x588), "nor", I_BASE, REG, 3, RSL,RSL,RS },
+ { R_3(0x589), "xnor", I_BASE, REG, 3, RSL,RSL,RS },
+ { R_2D(0x58a), "not", I_BASE, REG, 2, RSL,RS },
+ { R_3(0x58b), "ornot", I_BASE, REG, 3, RSL,RSL,RS },
+ { R_3(0x58c), "clrbit", I_BASE, REG, 3, RSL,RSL,RS },
+ { R_3(0x58d), "notor", I_BASE, REG, 3, RSL,RSL,RS },
+ { R_3(0x58e), "nand", I_BASE, REG, 3, RSL,RSL,RS },
+ { R_3(0x58f), "alterbit", I_BASE, REG, 3, RSL,RSL,RS },
+ { R_3(0x590), "addo", I_BASE, REG, 3, RSL,RSL,RS },
+ { R_3(0x591), "addi", I_BASE, REG, 3, RSL,RSL,RS },
+ { R_3(0x592), "subo", I_BASE, REG, 3, RSL,RSL,RS },
+ { R_3(0x593), "subi", I_BASE, REG, 3, RSL,RSL,RS },
+ { R_3(0x598), "shro", I_BASE, REG, 3, RSL,RSL,RS },
+ { R_3(0x59a), "shrdi", I_BASE, REG, 3, RSL,RSL,RS },
+ { R_3(0x59b), "shri", I_BASE, REG, 3, RSL,RSL,RS },
+ { R_3(0x59c), "shlo", I_BASE, REG, 3, RSL,RSL,RS },
+ { R_3(0x59d), "rotate", I_BASE, REG, 3, RSL,RSL,RS },
+ { R_3(0x59e), "shli", I_BASE, REG, 3, RSL,RSL,RS },
+ { R_2(0x5a0), "cmpo", I_BASE, REG, 2, RSL,RSL },
+ { R_2(0x5a1), "cmpi", I_BASE, REG, 2, RSL,RSL },
+ { R_2(0x5a2), "concmpo", I_BASE, REG, 2, RSL,RSL },
+ { R_2(0x5a3), "concmpi", I_BASE, REG, 2, RSL,RSL },
+ { R_3(0x5a4), "cmpinco", I_BASE, REG, 3, RSL,RSL,RS },
+ { R_3(0x5a5), "cmpinci", I_BASE, REG, 3, RSL,RSL,RS },
+ { R_3(0x5a6), "cmpdeco", I_BASE, REG, 3, RSL,RSL,RS },
+ { R_3(0x5a7), "cmpdeci", I_BASE, REG, 3, RSL,RSL,RS },
+ { R_2(0x5ac), "scanbyte", I_BASE, REG, 2, RSL,RSL },
+ { R_2(0x5ae), "chkbit", I_BASE, REG, 2, RSL,RSL },
+ { R_3(0x5b0), "addc", I_BASE, REG, 3, RSL,RSL,RS },
+ { R_3(0x5b2), "subc", I_BASE, REG, 3, RSL,RSL,RS },
+ { R_2D(0x5cc), "mov", I_BASE, REG, 2, RSL,RS },
+ { R_2D(0x5dc), "movl", I_BASE, REG, 2, RL2,R2 },
+ { R_2D(0x5ec), "movt", I_BASE, REG, 2, RL4,R4 },
+ { R_2D(0x5fc), "movq", I_BASE, REG, 2, RL4,R4 },
+ { R_3(0x610), "atmod", I_BASE, REG, 3, RS, RSL,R },
+ { R_3(0x612), "atadd", I_BASE, REG, 3, RS, RSL,RS },
+ { R_2D(0x640), "spanbit", I_BASE, REG, 2, RSL,RS },
+ { R_2D(0x641), "scanbit", I_BASE, REG, 2, RSL,RS },
+ { R_3(0x645), "modac", I_BASE, REG, 3, RSL,RSL,RS },
+ { R_3(0x650), "modify", I_BASE, REG, 3, RSL,RSL,R },
+ { R_3(0x651), "extract", I_BASE, REG, 3, RSL,RSL,R },
+ { R_3(0x654), "modtc", I_BASE, REG, 3, RSL,RSL,RS },
+ { R_3(0x655), "modpc", I_BASE, REG, 3, RSL,RSL,R },
+ { R_1(0x660), "calls", I_BASE, REG, 1, RSL },
+ { R_0(0x66b), "mark", I_BASE, REG, 0, },
+ { R_0(0x66c), "fmark", I_BASE, REG, 0, },
+ { R_0(0x66d), "flushreg", I_BASE, REG, 0, },
+ { R_0(0x66f), "syncf", I_BASE, REG, 0, },
+ { R_3(0x670), "emul", I_BASE, REG, 3, RSL,RSL,R2 },
+ { R_3(0x671), "ediv", I_BASE, REG, 3, RSL,RL2,RS },
+ { R_2D(0x672), "cvtadr", I_CASIM,REG, 2, RL, R2 },
+ { R_3(0x701), "mulo", I_BASE, REG, 3, RSL,RSL,RS },
+ { R_3(0x708), "remo", I_BASE, REG, 3, RSL,RSL,RS },
+ { R_3(0x70b), "divo", I_BASE, REG, 3, RSL,RSL,RS },
+ { R_3(0x741), "muli", I_BASE, REG, 3, RSL,RSL,RS },
+ { R_3(0x748), "remi", I_BASE, REG, 3, RSL,RSL,RS },
+ { R_3(0x749), "modi", I_BASE, REG, 3, RSL,RSL,RS },
+ { R_3(0x74b), "divi", I_BASE, REG, 3, RSL,RSL,RS },
+
+ /* Floating-point instructions */
+
+ { R_2D(0x674), "cvtir", I_FP, REG, 2, RL, F },
+ { R_2D(0x675), "cvtilr", I_FP, REG, 2, RL, F },
+ { R_3(0x676), "scalerl", I_FP, REG, 3, RL, FL2,F2 },
+ { R_3(0x677), "scaler", I_FP, REG, 3, RL, FL, F },
+ { R_3(0x680), "atanr", I_FP, REG, 3, FL, FL, F },
+ { R_3(0x681), "logepr", I_FP, REG, 3, FL, FL, F },
+ { R_3(0x682), "logr", I_FP, REG, 3, FL, FL, F },
+ { R_3(0x683), "remr", I_FP, REG, 3, FL, FL, F },
+ { R_2(0x684), "cmpor", I_FP, REG, 2, FL, FL },
+ { R_2(0x685), "cmpr", I_FP, REG, 2, FL, FL },
+ { R_2D(0x688), "sqrtr", I_FP, REG, 2, FL, F },
+ { R_2D(0x689), "expr", I_FP, REG, 2, FL, F },
+ { R_2D(0x68a), "logbnr", I_FP, REG, 2, FL, F },
+ { R_2D(0x68b), "roundr", I_FP, REG, 2, FL, F },
+ { R_2D(0x68c), "sinr", I_FP, REG, 2, FL, F },
+ { R_2D(0x68d), "cosr", I_FP, REG, 2, FL, F },
+ { R_2D(0x68e), "tanr", I_FP, REG, 2, FL, F },
+ { R_1(0x68f), "classr", I_FP, REG, 1, FL },
+ { R_3(0x690), "atanrl", I_FP, REG, 3, FL2,FL2,F2 },
+ { R_3(0x691), "logeprl", I_FP, REG, 3, FL2,FL2,F2 },
+ { R_3(0x692), "logrl", I_FP, REG, 3, FL2,FL2,F2 },
+ { R_3(0x693), "remrl", I_FP, REG, 3, FL2,FL2,F2 },
+ { R_2(0x694), "cmporl", I_FP, REG, 2, FL2,FL2 },
+ { R_2(0x695), "cmprl", I_FP, REG, 2, FL2,FL2 },
+ { R_2D(0x698), "sqrtrl", I_FP, REG, 2, FL2,F2 },
+ { R_2D(0x699), "exprl", I_FP, REG, 2, FL2,F2 },
+ { R_2D(0x69a), "logbnrl", I_FP, REG, 2, FL2,F2 },
+ { R_2D(0x69b), "roundrl", I_FP, REG, 2, FL2,F2 },
+ { R_2D(0x69c), "sinrl", I_FP, REG, 2, FL2,F2 },
+ { R_2D(0x69d), "cosrl", I_FP, REG, 2, FL2,F2 },
+ { R_2D(0x69e), "tanrl", I_FP, REG, 2, FL2,F2 },
+ { R_1(0x69f), "classrl", I_FP, REG, 1, FL2 },
+ { R_2D(0x6c0), "cvtri", I_FP, REG, 2, FL, R },
+ { R_2D(0x6c1), "cvtril", I_FP, REG, 2, FL, R2 },
+ { R_2D(0x6c2), "cvtzri", I_FP, REG, 2, FL, R },
+ { R_2D(0x6c3), "cvtzril", I_FP, REG, 2, FL, R2 },
+ { R_2D(0x6c9), "movr", I_FP, REG, 2, FL, F },
+ { R_2D(0x6d9), "movrl", I_FP, REG, 2, FL2,F2 },
+ { R_2D(0x6e1), "movre", I_FP, REG, 2, FL4,F4 },
+ { R_3(0x6e2), "cpysre", I_FP, REG, 3, FL4,FL4,F4 },
+ { R_3(0x6e3), "cpyrsre", I_FP, REG, 3, FL4,FL4,F4 },
+ { R_3(0x78b), "divr", I_FP, REG, 3, FL, FL, F },
+ { R_3(0x78c), "mulr", I_FP, REG, 3, FL, FL, F },
+ { R_3(0x78d), "subr", I_FP, REG, 3, FL, FL, F },
+ { R_3(0x78f), "addr", I_FP, REG, 3, FL, FL, F },
+ { R_3(0x79b), "divrl", I_FP, REG, 3, FL2,FL2,F2 },
+ { R_3(0x79c), "mulrl", I_FP, REG, 3, FL2,FL2,F2 },
+ { R_3(0x79d), "subrl", I_FP, REG, 3, FL2,FL2,F2 },
+ { R_3(0x79f), "addrl", I_FP, REG, 3, FL2,FL2,F2 },
+
+ /* These are the floating point branch instructions. Each actually
+ * generates 2 branch instructions: the first a CTRL instruction with
+ * the indicated opcode, and the second a 'bno'.
+ */
+
+ { 0x12000000, "brue", I_FP, FBRA, 1 },
+ { 0x11000000, "brug", I_FP, FBRA, 1 },
+ { 0x13000000, "bruge", I_FP, FBRA, 1 },
+ { 0x14000000, "brul", I_FP, FBRA, 1 },
+ { 0x16000000, "brule", I_FP, FBRA, 1 },
+ { 0x15000000, "brulg", I_FP, FBRA, 1 },
+
+
+ /* Decimal instructions */
+
+ { R_3(0x642), "daddc", I_DEC, REG, 3, RSL,RSL,RS },
+ { R_3(0x643), "dsubc", I_DEC, REG, 3, RSL,RSL,RS },
+ { R_2D(0x644), "dmovt", I_DEC, REG, 2, RSL,RS },
+
+
+ /* KX extensions */
+
+ { R_2(0x600), "synmov", I_KX, REG, 2, R, R },
+ { R_2(0x601), "synmovl", I_KX, REG, 2, R, R },
+ { R_2(0x602), "synmovq", I_KX, REG, 2, R, R },
+ { R_2D(0x615), "synld", I_KX, REG, 2, R, R },
+
+
+ /* MC extensions */
+
+ { R_3(0x603), "cmpstr", I_MIL, REG, 3, R, R, RL },
+ { R_3(0x604), "movqstr", I_MIL, REG, 3, R, R, RL },
+ { R_3(0x605), "movstr", I_MIL, REG, 3, R, R, RL },
+ { R_2D(0x613), "inspacc", I_MIL, REG, 2, R, R },
+ { R_2D(0x614), "ldphy", I_MIL, REG, 2, R, R },
+ { R_3(0x617), "fill", I_MIL, REG, 3, R, RL, RL },
+ { R_2D(0x646), "condrec", I_MIL, REG, 2, R, R },
+ { R_2D(0x656), "receive", I_MIL, REG, 2, R, R },
+ { R_3(0x662), "send", I_MIL, REG, 3, R, RL, R },
+ { R_1(0x663), "sendserv", I_MIL, REG, 1, R },
+ { R_1(0x664), "resumprcs", I_MIL, REG, 1, R },
+ { R_1(0x665), "schedprcs", I_MIL, REG, 1, R },
+ { R_0(0x666), "saveprcs", I_MIL, REG, 0, },
+ { R_1(0x668), "condwait", I_MIL, REG, 1, R },
+ { R_1(0x669), "wait", I_MIL, REG, 1, R },
+ { R_1(0x66a), "signal", I_MIL, REG, 1, R },
+ { R_1D(0x673), "ldtime", I_MIL, REG, 1, R2 },
+
+
+ /* CX extensions */
+
+ { R_3(0x5d8), "eshro", I_CX, REG, 3, RSL,RSL,RS },
+ { R_3(0x630), "sdma", I_CX, REG, 3, RSL,RSL,RL },
+ { R_3(0x631), "udma", I_CX, REG, 0 },
+ { R_3(0x659), "sysctl", I_CX, REG, 3, RSL,RSL,RL },
+
+
+ /* END OF TABLE */
+
+ { 0, NULL, 0, 0 }
+};
+
+ /* end of i960-opcode.h */
diff --git a/gnu/usr.bin/as/opcode/m68k.h b/gnu/usr.bin/as/opcode/m68k.h
new file mode 100644
index 0000000..65825fb
--- /dev/null
+++ b/gnu/usr.bin/as/opcode/m68k.h
@@ -0,0 +1,2003 @@
+/* Opcode table for m680[01234]0/m6888[12]/m68851.
+ Copyright (C) 1989, 1991 Free Software Foundation.
+
+This file is part of GDB, the GNU Debugger and GAS, the GNU Assembler.
+
+Both GDB and GAS are free software; you can redistribute and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 1, or (at your option)
+any later version.
+
+GDB and GAS are distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GDB or GAS; see the file COPYING. If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* These are used as bit flags for arch below. */
+
+enum m68k_architecture {
+ m68000 = 0x01,
+ m68008 = m68000, /* synonym for -m68000. otherwise unused. */
+ m68010 = 0x02,
+ m68020 = 0x04,
+ m68030 = 0x08,
+ m68040 = 0x10,
+ m68881 = 0x20,
+ m68882 = m68881, /* synonym for -m68881. otherwise unused. */
+ m68851 = 0x40,
+
+ /* handy aliases */
+ m68040up = m68040,
+ m68030up = (m68030 | m68040up),
+ m68020up = (m68020 | m68030up),
+ m68010up = (m68010 | m68020up),
+ m68000up = (m68000 | m68010up),
+
+ mfloat = (m68881 | m68882 | m68040),
+ mmmu = (m68851 | m68030 | m68040)
+}; /* enum m68k_architecture */
+
+ /* note that differences in addressing modes that aren't distinguished
+ in the following table are handled explicitly by gas. */
+
+struct m68k_opcode {
+ char *name;
+ unsigned long opcode;
+ unsigned long match;
+ char *args;
+ enum m68k_architecture arch;
+};
+
+/* We store four bytes of opcode for all opcodes because that
+ is the most any of them need. The actual length of an instruction
+ is always at least 2 bytes, and is as much longer as necessary to
+ hold the operands it has.
+
+ The match component is a mask saying which bits must match
+ particular opcode in order for an instruction to be an instance
+ of that opcode.
+
+ The args component is a string containing two characters
+ for each operand of the instruction. The first specifies
+ the kind of operand; the second, the place it is stored. */
+
+/* Kinds of operands:
+ D data register only. Stored as 3 bits.
+ A address register only. Stored as 3 bits.
+ a address register indirect only. Stored as 3 bits.
+ R either kind of register. Stored as 4 bits.
+ F floating point coprocessor register only. Stored as 3 bits.
+ O an offset (or width): immediate data 0-31 or data register.
+ Stored as 6 bits in special format for BF... insns.
+ + autoincrement only. Stored as 3 bits (number of the address register).
+ - autodecrement only. Stored as 3 bits (number of the address register).
+ Q quick immediate data. Stored as 3 bits.
+ This matches an immediate operand only when value is in range 1 .. 8.
+ M moveq immediate data. Stored as 8 bits.
+ This matches an immediate operand only when value is in range -128..127
+ T trap vector immediate data. Stored as 4 bits.
+
+ k K-factor for fmove.p instruction. Stored as a 7-bit constant or
+ a three bit register offset, depending on the field type.
+
+ # immediate data. Stored in special places (b, w or l)
+ which say how many bits to store.
+ ^ immediate data for floating point instructions. Special places
+ are offset by 2 bytes from '#'...
+ B pc-relative address, converted to an offset
+ that is treated as immediate data.
+ d displacement and register. Stores the register as 3 bits
+ and stores the displacement in the entire second word.
+
+ C the CCR. No need to store it; this is just for filtering validity.
+ S the SR. No need to store, just as with CCR.
+ U the USP. No need to store, just as with CCR.
+
+ I Coprocessor ID. Not printed if 1. The Coprocessor ID is always
+ extracted from the 'd' field of word one, which means that an extended
+ coprocessor opcode can be skipped using the 'i' place, if needed.
+
+ s System Control register for the floating point coprocessor.
+ S List of system control registers for floating point coprocessor.
+
+ J Misc register for movec instruction, stored in 'j' format.
+ Possible values:
+ 0x000 SFC Source Function Code reg [40, 30, 20, 10]
+ 0x001 DFC Data Function Code reg [40, 30, 20, 10]
+ 0x002 CACR Cache Control Register [40, 30, 20]
+ 0x800 USP User Stack Pointer [40, 30, 20, 10]
+ 0x801 VBR Vector Base reg [40, 30, 20, 10]
+ 0x802 CAAR Cache Address Register [ 30, 20]
+ 0x803 MSP Master Stack Pointer [40, 30, 20]
+ 0x804 ISP Interrupt Stack Pointer [40, 30, 20]
+ 0x003 TC MMU Translation Control [40]
+ 0x004 ITT0 Instruction Transparent
+ Translation reg 0 [40]
+ 0x005 ITT1 Instruction Transparent
+ Translation reg 1 [40]
+ 0x006 DTT0 Data Transparent
+ Translation reg 0 [40]
+ 0x007 DTT1 Data Transparent
+ Translation reg 1 [40]
+ 0x805 MMUSR MMU Status reg [40]
+ 0x806 URP User Root Pointer [40]
+ 0x807 SRP Supervisor Root Pointer [40]
+
+ L Register list of the type d0-d7/a0-a7 etc.
+ (New! Improved! Can also hold fp0-fp7, as well!)
+ The assembler tries to see if the registers match the insn by
+ looking at where the insn wants them stored.
+
+ l Register list like L, but with all the bits reversed.
+ Used for going the other way. . .
+
+ c cache identifier which may be "nc" for no cache, "ic"
+ for instruction cache, "dc" for data cache, or "bc"
+ for both caches. Used in cinv and cpush. Always
+ stored in position "d".
+
+ They are all stored as 6 bits using an address mode and a register number;
+ they differ in which addressing modes they match.
+
+ * all (modes 0-6,7.*)
+ ~ alterable memory (modes 2-6,7.0,7.1)(not 0,1,7.~)
+ % alterable (modes 0-6,7.0,7.1)(not 7.~)
+ ; data (modes 0,2-6,7.*)(not 1)
+ @ data, but not immediate (modes 0,2-6,7.? ? ?)(not 1,7.?) This may really be ;, the 68020 book says it is
+ ! control (modes 2,5,6,7.*-)(not 0,1,3,4,7.4)
+ & alterable control (modes 2,5,6,7.0,7.1)(not 0,1,7.? ? ?)
+ $ alterable data (modes 0,2-6,7.0,7.1)(not 1,7.~)
+ ? alterable control, or data register (modes 0,2,5,6,7.0,7.1)(not 1,3,4,7.~)
+ / control, or data register (modes 0,2,5,6,7.0,7.1,7.2,7.3)(not 1,3,4,7.4)
+*/
+
+/* JF: for the 68851 */
+/*
+ I didn't use much imagination in choosing the
+ following codes, so many of them aren't very
+ mnemonic. -rab
+
+ P pmmu register
+ Possible values:
+ 000 TC Translation Control reg
+ 100 CAL Current Access Level
+ 101 VAL Validate Access Level
+ 110 SCC Stack Change Control
+ 111 AC Access Control
+
+ W wide pmmu registers
+ Possible values:
+ 001 DRP Dma Root Pointer
+ 010 SRP Supervisor Root Pointer
+ 011 CRP Cpu Root Pointer
+
+ f function code register
+ 0 SFC
+ 1 DFC
+
+ V VAL register only
+
+ X BADx, BACx
+ 100 BAD Breakpoint Acknowledge Data
+ 101 BAC Breakpoint Acknowledge Control
+
+ Y PSR
+ Z PCSR
+
+ | memory (modes 2-6, 7.*)
+
+*/
+
+/* Places to put an operand, for non-general operands:
+ s source, low bits of first word.
+ d dest, shifted 9 in first word
+ 1 second word, shifted 12
+ 2 second word, shifted 6
+ 3 second word, shifted 0
+ 4 third word, shifted 12
+ 5 third word, shifted 6
+ 6 third word, shifted 0
+ 7 second word, shifted 7
+ 8 second word, shifted 10
+ D store in both place 1 and place 3; for divul and divsl.
+ B first word, low byte, for branch displacements
+ W second word (entire), for branch displacements
+ L second and third words (entire), for branch displacements (also overloaded for move16)
+ b second word, low byte
+ w second word (entire) [variable word/long branch offset for dbra]
+ l second and third word (entire)
+ g variable branch offset for bra and similar instructions.
+ The place to store depends on the magnitude of offset.
+ t store in both place 7 and place 8; for floating point operations
+ c branch offset for cpBcc operations.
+ The place to store is word two if bit six of word one is zero,
+ and words two and three if bit six of word one is one.
+ i Increment by two, to skip over coprocessor extended operands. Only
+ works with the 'I' format.
+ k Dynamic K-factor field. Bits 6-4 of word 2, used as a register number.
+ Also used for dynamic fmovem instruction.
+ C floating point coprocessor constant - 7 bits. Also used for static
+ K-factors...
+ j Movec register #, stored in 12 low bits of second word.
+
+ Places to put operand, for general operands:
+ d destination, shifted 6 bits in first word
+ b source, at low bit of first word, and immediate uses one byte
+ w source, at low bit of first word, and immediate uses two bytes
+ l source, at low bit of first word, and immediate uses four bytes
+ s source, at low bit of first word.
+ Used sometimes in contexts where immediate is not allowed anyway.
+ f single precision float, low bit of 1st word, immediate uses 4 bytes
+ F double precision float, low bit of 1st word, immediate uses 8 bytes
+ x extended precision float, low bit of 1st word, immediate uses 12 bytes
+ p packed float, low bit of 1st word, immediate uses 12 bytes
+*/
+
+#define one(x) ((x) << 16)
+#define two(x, y) (((x) << 16) + y)
+
+/*
+ *** DANGER WILL ROBINSON ***
+
+ The assembler requires that all instances of the same mnemonic must be
+ consecutive. If they aren't, the assembler will bomb at runtime
+ */
+struct m68k_opcode m68k_opcodes[] =
+{
+{"abcd", one(0140400), one(0170770), "DsDd", m68000up },
+{"abcd", one(0140410), one(0170770), "-s-d", m68000up },
+
+ /* Add instructions */
+{"addal", one(0150700), one(0170700), "*lAd", m68000up },
+{"addaw", one(0150300), one(0170700), "*wAd", m68000up },
+{"addib", one(0003000), one(0177700), "#b$b", m68000up },
+{"addil", one(0003200), one(0177700), "#l$l", m68000up },
+{"addiw", one(0003100), one(0177700), "#w$w", m68000up },
+{"addqb", one(0050000), one(0170700), "Qd$b", m68000up },
+{"addql", one(0050200), one(0170700), "Qd%l", m68000up },
+{"addqw", one(0050100), one(0170700), "Qd%w", m68000up },
+
+{"addb", one(0050000), one(0170700), "Qd$b", m68000up }, /* addq written as add */
+{"addb", one(0003000), one(0177700), "#b$b", m68000up }, /* addi written as add */
+{"addb", one(0150000), one(0170700), ";bDd", m68000up }, /* addb <ea>, Dd */
+{"addb", one(0150400), one(0170700), "Dd~b", m68000up }, /* addb Dd, <ea> */
+
+{"addw", one(0050100), one(0170700), "Qd%w", m68000up }, /* addq written as add */
+{"addw", one(0003100), one(0177700), "#w$w", m68000up }, /* addi written as add */
+{"addw", one(0150300), one(0170700), "*wAd", m68000up }, /* adda written as add */
+{"addw", one(0150100), one(0170700), "*wDd", m68000up }, /* addw <ea>, Dd */
+{"addw", one(0150500), one(0170700), "Dd~w", m68000up }, /* addw Dd, <ea> */
+
+{"addl", one(0050200), one(0170700), "Qd%l", m68000up }, /* addq written as add */
+{"addl", one(0003200), one(0177700), "#l$l", m68000up }, /* addi written as add */
+{"addl", one(0150700), one(0170700), "*lAd", m68000up }, /* adda written as add */
+{"addl", one(0150200), one(0170700), "*lDd", m68000up }, /* addl <ea>, Dd */
+{"addl", one(0150600), one(0170700), "Dd~l", m68000up }, /* addl Dd, <ea> */
+
+{"addxb", one(0150400), one(0170770), "DsDd", m68000up },
+{"addxb", one(0150410), one(0170770), "-s-d", m68000up },
+{"addxl", one(0150600), one(0170770), "DsDd", m68000up },
+{"addxl", one(0150610), one(0170770), "-s-d", m68000up },
+{"addxw", one(0150500), one(0170770), "DsDd", m68000up },
+{"addxw", one(0150510), one(0170770), "-s-d", m68000up },
+
+{"andib", one(0001000), one(0177700), "#b$b", m68000up },
+{"andib", one(0001074), one(0177777), "#bCb", m68000up }, /* andi to ccr */
+{"andiw", one(0001100), one(0177700), "#w$w", m68000up },
+{"andiw", one(0001174), one(0177777), "#wSw", m68000up }, /* andi to sr */
+{"andil", one(0001200), one(0177700), "#l$l", m68000up },
+
+{"andb", one(0001000), one(0177700), "#b$b", m68000up }, /* andi written as or */
+{"andb", one(0001074), one(0177777), "#bCb", m68000up }, /* andi to ccr */
+{"andb", one(0140000), one(0170700), ";bDd", m68000up }, /* memory to register */
+{"andb", one(0140400), one(0170700), "Dd~b", m68000up }, /* register to memory */
+{"andw", one(0001100), one(0177700), "#w$w", m68000up }, /* andi written as or */
+{"andw", one(0001174), one(0177777), "#wSw", m68000up }, /* andi to sr */
+{"andw", one(0140100), one(0170700), ";wDd", m68000up }, /* memory to register */
+{"andw", one(0140500), one(0170700), "Dd~w", m68000up }, /* register to memory */
+{"andl", one(0001200), one(0177700), "#l$l", m68000up }, /* andi written as or */
+{"andl", one(0140200), one(0170700), ";lDd", m68000up }, /* memory to register */
+{"andl", one(0140600), one(0170700), "Dd~l", m68000up }, /* register to memory */
+
+{"aslb", one(0160400), one(0170770), "QdDs", m68000up },
+{"aslb", one(0160440), one(0170770), "DdDs", m68000up },
+{"asll", one(0160600), one(0170770), "QdDs", m68000up },
+{"asll", one(0160640), one(0170770), "DdDs", m68000up },
+{"aslw", one(0160500), one(0170770), "QdDs", m68000up },
+{"aslw", one(0160540), one(0170770), "DdDs", m68000up },
+{"aslw", one(0160700), one(0177700), "~s", m68000up }, /* Shift memory */
+{"asrb", one(0160000), one(0170770), "QdDs", m68000up },
+{"asrb", one(0160040), one(0170770), "DdDs", m68000up },
+{"asrl", one(0160200), one(0170770), "QdDs", m68000up },
+{"asrl", one(0160240), one(0170770), "DdDs", m68000up },
+{"asrw", one(0160100), one(0170770), "QdDs", m68000up },
+{"asrw", one(0160140), one(0170770), "DdDs", m68000up },
+{"asrw", one(0160300), one(0177700), "~s", m68000up }, /* Shift memory */
+
+/* Fixed-size branches with 16-bit offsets */
+
+{"bhi", one(0061000), one(0177777), "BW", m68000up },
+{"bls", one(0061400), one(0177777), "BW", m68000up },
+{"bcc", one(0062000), one(0177777), "BW", m68000up },
+{"bcs", one(0062400), one(0177777), "BW", m68000up },
+{"bne", one(0063000), one(0177777), "BW", m68000up },
+{"beq", one(0063400), one(0177777), "BW", m68000up },
+{"bvc", one(0064000), one(0177777), "BW", m68000up },
+{"bvs", one(0064400), one(0177777), "BW", m68000up },
+{"bpl", one(0065000), one(0177777), "BW", m68000up },
+{"bmi", one(0065400), one(0177777), "BW", m68000up },
+{"bge", one(0066000), one(0177777), "BW", m68000up },
+{"blt", one(0066400), one(0177777), "BW", m68000up },
+{"bgt", one(0067000), one(0177777), "BW", m68000up },
+{"ble", one(0067400), one(0177777), "BW", m68000up },
+{"bra", one(0060000), one(0177777), "BW", m68000up },
+{"bsr", one(0060400), one(0177777), "BW", m68000up },
+
+/* Fixed-size branches with short (byte) offsets */
+
+{"bhis", one(0061000), one(0177400), "BB", m68000up },
+{"blss", one(0061400), one(0177400), "BB", m68000up },
+{"bccs", one(0062000), one(0177400), "BB", m68000up },
+{"bcss", one(0062400), one(0177400), "BB", m68000up },
+{"bnes", one(0063000), one(0177400), "BB", m68000up },
+{"beqs", one(0063400), one(0177400), "BB", m68000up },
+{"bvcs", one(0064000), one(0177400), "BB", m68000up },
+{"bvss", one(0064400), one(0177400), "BB", m68000up },
+{"bpls", one(0065000), one(0177400), "BB", m68000up },
+{"bmis", one(0065400), one(0177400), "BB", m68000up },
+{"bges", one(0066000), one(0177400), "BB", m68000up },
+{"blts", one(0066400), one(0177400), "BB", m68000up },
+{"bgts", one(0067000), one(0177400), "BB", m68000up },
+{"bles", one(0067400), one(0177400), "BB", m68000up },
+{"bras", one(0060000), one(0177400), "BB", m68000up },
+{"bsrs", one(0060400), one(0177400), "BB", m68000up },
+
+/* Fixed-size branches with long (32-bit) offsets */
+
+{"bhil", one(0061377), one(0177777), "BL", m68020up },
+{"blsl", one(0061777), one(0177777), "BL", m68020up },
+{"bccl", one(0062377), one(0177777), "BL", m68020up },
+{"bcsl", one(0062777), one(0177777), "BL", m68020up },
+{"bnel", one(0063377), one(0177777), "BL", m68020up },
+{"beql", one(0063777), one(0177777), "BL", m68020up },
+{"bvcl", one(0064377), one(0177777), "BL", m68020up },
+{"bvsl", one(0064777), one(0177777), "BL", m68020up },
+{"bpll", one(0065377), one(0177777), "BL", m68020up },
+{"bmil", one(0065777), one(0177777), "BL", m68020up },
+{"bgel", one(0066377), one(0177777), "BL", m68020up },
+{"bltl", one(0066777), one(0177777), "BL", m68020up },
+{"bgtl", one(0067377), one(0177777), "BL", m68020up },
+{"blel", one(0067777), one(0177777), "BL", m68020up },
+{"bral", one(0060377), one(0177777), "BL", m68020up },
+{"bsrl", one(0060777), one(0177777), "BL", m68020up },
+
+/* We now return you to our regularly scheduled instruction set */
+
+{"bchg", one(0000500), one(0170700), "Dd$s", m68000up },
+{"bchg", one(0004100), one(0177700), "#b$s", m68000up },
+{"bclr", one(0000600), one(0170700), "Dd$s", m68000up },
+{"bclr", one(0004200), one(0177700), "#b$s", m68000up },
+
+{"bfchg", two(0165300, 0), two(0177700, 0170000), "?sO2O3", m68020up },
+{"bfclr", two(0166300, 0), two(0177700, 0170000), "?sO2O3", m68020up },
+{"bfexts", two(0165700, 0), two(0177700, 0100000), "/sO2O3D1", m68020up },
+{"bfextu", two(0164700, 0), two(0177700, 0100000), "/sO2O3D1", m68020up },
+{"bfffo", two(0166700, 0), two(0177700, 0100000), "/sO2O3D1", m68020up },
+{"bfins", two(0167700, 0), two(0177700, 0100000), "D1?sO2O3", m68020up },
+{"bfset", two(0167300, 0), two(0177700, 0170000), "?sO2O3", m68020up },
+{"bftst", two(0164300, 0), two(0177700, 0170000), "/sO2O3", m68020up },
+{"bkpt", one(0044110), one(0177770), "Qs", m68020up },
+
+{"bset", one(0000700), one(0170700), "Dd$s", m68000up },
+{"bset", one(0004300), one(0177700), "#b$s", m68000up },
+{"btst", one(0000400), one(0170700), "Dd@s", m68000up },
+{"btst", one(0004000), one(0177700), "#b@s", m68000up },
+
+
+{"callm", one(0003300), one(0177700), "#b!s", m68020 },
+
+{"cas2l", two(0007374, 0), two(0177777, 0107070), "D3D6D2D5R1R4", m68020up }, /* JF FOO really a 3 word ins */
+{"cas2w", two(0006374, 0), two(0177777, 0107070), "D3D6D2D5R1R4", m68020up }, /* JF ditto */
+{"casb", two(0005300, 0), two(0177700, 0177070), "D3D2~s", m68020up },
+{"casl", two(0007300, 0), two(0177700, 0177070), "D3D2~s", m68020up },
+{"casw", two(0006300, 0), two(0177700, 0177070), "D3D2~s", m68020up },
+
+/* {"chk", one(0040600), one(0170700), ";wDd"}, JF FOO this looks wrong */
+{"chk2b", two(0000300, 0004000), two(0177700, 07777), "!sR1", m68020up },
+{"chk2l", two(0002300, 0004000), two(0177700, 07777), "!sR1", m68020up },
+{"chk2w", two(0001300, 0004000), two(0177700, 07777), "!sR1", m68020up },
+{"chkl", one(0040400), one(0170700), ";lDd", m68000up },
+{"chkw", one(0040600), one(0170700), ";wDd", m68000up },
+
+#define SCOPE_LINE (0x1 << 3)
+#define SCOPE_PAGE (0x2 << 3)
+#define SCOPE_ALL (0x3 << 3)
+
+{"cinva", one(0xf400|SCOPE_ALL), one(0xff20), "ce", m68040 },
+{"cinvl", one(0xf400|SCOPE_LINE), one(0xff20), "ceas", m68040 },
+{"cinvp", one(0xf400|SCOPE_PAGE), one(0xff20), "ceas", m68040 },
+
+{"cpusha", one(0xf420|SCOPE_ALL), one(0xff20), "ce", m68040 },
+{"cpushl", one(0xf420|SCOPE_LINE), one(0xff20), "ceas", m68040 },
+{"cpushp", one(0xf420|SCOPE_PAGE), one(0xff20), "ceas", m68040 },
+
+#undef SCOPE_LINE
+#undef SCOPE_PAGE
+#undef SCOPE_ALL
+
+{"clrb", one(0041000), one(0177700), "$s", m68000up },
+{"clrl", one(0041200), one(0177700), "$s", m68000up },
+{"clrw", one(0041100), one(0177700), "$s", m68000up },
+
+{"cmp2b", two(0000300, 0), two(0177700, 07777), "!sR1", m68020up },
+{"cmp2l", two(0002300, 0), two(0177700, 07777), "!sR1", m68020up },
+{"cmp2w", two(0001300, 0), two(0177700, 07777), "!sR1", m68020up },
+{"cmpal", one(0130700), one(0170700), "*lAd", m68000up },
+{"cmpaw", one(0130300), one(0170700), "*wAd", m68000up },
+{"cmpib", one(0006000), one(0177700), "#b;b", m68000up },
+{"cmpil", one(0006200), one(0177700), "#l;l", m68000up },
+{"cmpiw", one(0006100), one(0177700), "#w;w", m68000up },
+{"cmpb", one(0006000), one(0177700), "#b;b", m68000up }, /* cmpi written as cmp */
+{"cmpb", one(0130000), one(0170700), ";bDd", m68000up },
+{"cmpw", one(0006100), one(0177700), "#w;w", m68000up },
+{"cmpw", one(0130100), one(0170700), "*wDd", m68000up },
+{"cmpw", one(0130300), one(0170700), "*wAd", m68000up }, /* cmpa written as cmp */
+{"cmpl", one(0006200), one(0177700), "#l;l", m68000up },
+{"cmpl", one(0130200), one(0170700), "*lDd", m68000up },
+{"cmpl", one(0130700), one(0170700), "*lAd", m68000up },
+{"cmpmb", one(0130410), one(0170770), "+s+d", m68000up },
+{"cmpml", one(0130610), one(0170770), "+s+d", m68000up },
+{"cmpmw", one(0130510), one(0170770), "+s+d", m68000up },
+
+{"dbcc", one(0052310), one(0177770), "DsBw", m68000up },
+{"dbcs", one(0052710), one(0177770), "DsBw", m68000up },
+{"dbeq", one(0053710), one(0177770), "DsBw", m68000up },
+{"dbf", one(0050710), one(0177770), "DsBw", m68000up },
+{"dbge", one(0056310), one(0177770), "DsBw", m68000up },
+{"dbgt", one(0057310), one(0177770), "DsBw", m68000up },
+{"dbhi", one(0051310), one(0177770), "DsBw", m68000up },
+{"dble", one(0057710), one(0177770), "DsBw", m68000up },
+{"dbls", one(0051710), one(0177770), "DsBw", m68000up },
+{"dblt", one(0056710), one(0177770), "DsBw", m68000up },
+{"dbmi", one(0055710), one(0177770), "DsBw", m68000up },
+{"dbne", one(0053310), one(0177770), "DsBw", m68000up },
+{"dbpl", one(0055310), one(0177770), "DsBw", m68000up },
+{"dbra", one(0050710), one(0177770), "DsBw", m68000up },
+{"dbt", one(0050310), one(0177770), "DsBw", m68000up },
+{"dbvc", one(0054310), one(0177770), "DsBw", m68000up },
+{"dbvs", one(0054710), one(0177770), "DsBw", m68000up },
+
+{"divsl", two(0046100, 0006000), two(0177700, 0107770), ";lD3D1", m68020up },
+{"divsl", two(0046100, 0004000), two(0177700, 0107770), ";lDD", m68020up },
+{"divsll", two(0046100, 0004000), two(0177700, 0107770), ";lD3D1", m68020up },
+{"divsw", one(0100700), one(0170700), ";wDd", m68000up },
+{"divs", one(0100700), one(0170700), ";wDd", m68000up },
+{"divul", two(0046100, 0002000), two(0177700, 0107770), ";lD3D1", m68020up },
+{"divul", two(0046100, 0000000), two(0177700, 0107770), ";lDD", m68020up },
+{"divull", two(0046100, 0000000), two(0177700, 0107770), ";lD3D1", m68020up },
+{"divuw", one(0100300), one(0170700), ";wDd", m68000up },
+{"divu", one(0100300), one(0170700), ";wDd", m68000up },
+{"eorb", one(0005000), one(0177700), "#b$s", m68000up }, /* eori written as or */
+{"eorb", one(0005074), one(0177777), "#bCs", m68000up }, /* eori to ccr */
+{"eorb", one(0130400), one(0170700), "Dd$s", m68000up }, /* register to memory */
+{"eorib", one(0005000), one(0177700), "#b$s", m68000up },
+{"eorib", one(0005074), one(0177777), "#bCs", m68000up }, /* eori to ccr */
+{"eoril", one(0005200), one(0177700), "#l$s", m68000up },
+{"eoriw", one(0005100), one(0177700), "#w$s", m68000up },
+{"eoriw", one(0005174), one(0177777), "#wSs", m68000up }, /* eori to sr */
+{"eorl", one(0005200), one(0177700), "#l$s", m68000up },
+{"eorl", one(0130600), one(0170700), "Dd$s", m68000up },
+{"eorw", one(0005100), one(0177700), "#w$s", m68000up },
+{"eorw", one(0005174), one(0177777), "#wSs", m68000up }, /* eori to sr */
+{"eorw", one(0130500), one(0170700), "Dd$s", m68000up },
+
+{"exg", one(0140500), one(0170770), "DdDs", m68000up },
+{"exg", one(0140510), one(0170770), "AdAs", m68000up },
+{"exg", one(0140610), one(0170770), "DdAs", m68000up },
+{"exg", one(0140610), one(0170770), "AsDd", m68000up },
+
+{"extw", one(0044200), one(0177770), "Ds", m68000up },
+{"extl", one(0044300), one(0177770), "Ds", m68000up },
+{"extbl", one(0044700), one(0177770), "Ds", m68020up },
+{"extb.l", one(0044700), one(0177770), "Ds", m68020up }, /* Not sure we should support this one */
+
+/* float stuff starts here */
+{"fabsb", two(0xF000, 0x5818), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat },
+{"fabsd", two(0xF000, 0x5418), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat },
+{"fabsl", two(0xF000, 0x4018), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat },
+{"fabsp", two(0xF000, 0x4C18), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat },
+{"fabss", two(0xF000, 0x4418), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat },
+{"fabsw", two(0xF000, 0x5018), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat },
+{"fabsx", two(0xF000, 0x0018), two(0xF1C0, 0xE07F), "IiF8F7", mfloat },
+{"fabsx", two(0xF000, 0x4818), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat },
+{"fabsx", two(0xF000, 0x0018), two(0xF1C0, 0xE07F), "IiFt", mfloat },
+
+/* FIXME-NOW: The '040 book that I have claims that these should be
+ coded exactly like fadd. In fact, the table of opmodes calls them
+ fadd, fsadd, fdadd. That can't be right. If someone can give me the
+ right encoding, I'll fix it. By induction, I *think* the right
+ encoding is 38 & 3c, but I'm not sure.
+
+ in the mean time, if you know the encoding for the opmode field, you
+ can replace all of the "38),"'s and "3c),"'s below with the corrected
+ values and these guys should then just work. xoxorich. 31Aug91 */
+
+#ifdef comment
+{"fsabsb", two(0xF000, 0x5838), two(0xF1C0, 0xFC7F), "Ii;bF7", m68040 },
+{"fsabsd", two(0xF000, 0x5438), two(0xF1C0, 0xFC7F), "Ii;FF7", m68040 },
+{"fsabsl", two(0xF000, 0x4038), two(0xF1C0, 0xFC7F), "Ii;lF7", m68040 },
+{"fsabsp", two(0xF000, 0x4C38), two(0xF1C0, 0xFC7F), "Ii;pF7", m68040 },
+{"fsabss", two(0xF000, 0x4438), two(0xF1C0, 0xFC7F), "Ii;fF7", m68040 },
+{"fsabsw", two(0xF000, 0x5038), two(0xF1C0, 0xFC7F), "Ii;wF7", m68040 },
+{"fsabsx", two(0xF000, 0x0038), two(0xF1C0, 0xE07F), "IiF8F7", m68040 },
+{"fsabsx", two(0xF000, 0x4838), two(0xF1C0, 0xFC7F), "Ii;xF7", m68040 },
+{"fsabsx", two(0xF000, 0x0038), two(0xF1C0, 0xE07F), "IiFt", m68040 },
+
+{"fdabsb", two(0xF000, 0x583c), two(0xF1C0, 0xFC7F), "Ii;bF7", m68040},
+{"fdabsd", two(0xF000, 0x543c), two(0xF1C0, 0xFC7F), "Ii;FF7", m68040},
+{"fdabsl", two(0xF000, 0x403c), two(0xF1C0, 0xFC7F), "Ii;lF7", m68040},
+{"fdabsp", two(0xF000, 0x4C3c), two(0xF1C0, 0xFC7F), "Ii;pF7", m68040},
+{"fdabss", two(0xF000, 0x443c), two(0xF1C0, 0xFC7F), "Ii;fF7", m68040},
+{"fdabsw", two(0xF000, 0x503c), two(0xF1C0, 0xFC7F), "Ii;wF7", m68040},
+{"fdabsx", two(0xF000, 0x003c), two(0xF1C0, 0xE07F), "IiF8F7", m68040},
+{"fdabsx", two(0xF000, 0x483c), two(0xF1C0, 0xFC7F), "Ii;xF7", m68040},
+{"fdabsx", two(0xF000, 0x003c), two(0xF1C0, 0xE07F), "IiFt", m68040},
+#endif /* comment */
+
+{"facosb", two(0xF000, 0x581C), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat },
+{"facosd", two(0xF000, 0x541C), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat },
+{"facosl", two(0xF000, 0x401C), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat },
+{"facosp", two(0xF000, 0x4C1C), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat },
+{"facoss", two(0xF000, 0x441C), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat },
+{"facosw", two(0xF000, 0x501C), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat },
+{"facosx", two(0xF000, 0x001C), two(0xF1C0, 0xE07F), "IiF8F7", mfloat },
+{"facosx", two(0xF000, 0x481C), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat },
+{"facosx", two(0xF000, 0x001C), two(0xF1C0, 0xE07F), "IiFt", mfloat },
+
+{"faddb", two(0xF000, 0x5822), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat },
+{"faddd", two(0xF000, 0x5422), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat },
+{"faddl", two(0xF000, 0x4022), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat },
+{"faddp", two(0xF000, 0x4C22), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat },
+{"fadds", two(0xF000, 0x4422), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat },
+{"faddw", two(0xF000, 0x5022), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat },
+{"faddx", two(0xF000, 0x0022), two(0xF1C0, 0xE07F), "IiF8F7", mfloat },
+{"faddx", two(0xF000, 0x4822), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat },
+/* {"faddx", two(0xF000, 0x0022), two(0xF1C0, 0xE07F), "IiFt", mfloat }, JF removed */
+
+{"fsaddb", two(0xF000, 0x5832), two(0xF1C0, 0xFC7F), "Ii;bF7", m68040 },
+{"fsaddd", two(0xF000, 0x5432), two(0xF1C0, 0xFC7F), "Ii;FF7", m68040 },
+{"fsaddl", two(0xF000, 0x4032), two(0xF1C0, 0xFC7F), "Ii;lF7", m68040 },
+{"fsaddp", two(0xF000, 0x4C32), two(0xF1C0, 0xFC7F), "Ii;pF7", m68040 },
+{"fsadds", two(0xF000, 0x4432), two(0xF1C0, 0xFC7F), "Ii;fF7", m68040 },
+{"fsaddw", two(0xF000, 0x5032), two(0xF1C0, 0xFC7F), "Ii;wF7", m68040 },
+{"fsaddx", two(0xF000, 0x0032), two(0xF1C0, 0xE07F), "IiF8F7", m68040 },
+{"fsaddx", two(0xF000, 0x4832), two(0xF1C0, 0xFC7F), "Ii;xF7", m68040 },
+/* {"fsaddx", two(0xF000, 0x0032), two(0xF1C0, 0xE07F), "IiFt", m68040 }, JF removed */
+
+{"fdaddb", two(0xF000, 0x5836), two(0xF1C0, 0xFC7F), "Ii;bF7", m68040 },
+{"fdaddd", two(0xF000, 0x5436), two(0xF1C0, 0xFC7F), "Ii;FF7", m68040 },
+{"fdaddl", two(0xF000, 0x4036), two(0xF1C0, 0xFC7F), "Ii;lF7", m68040 },
+{"fdaddp", two(0xF000, 0x4C36), two(0xF1C0, 0xFC7F), "Ii;pF7", m68040 },
+{"fdadds", two(0xF000, 0x4436), two(0xF1C0, 0xFC7F), "Ii;fF7", m68040 },
+{"fdaddw", two(0xF000, 0x5036), two(0xF1C0, 0xFC7F), "Ii;wF7", m68040 },
+{"fdaddx", two(0xF000, 0x0036), two(0xF1C0, 0xE07F), "IiF8F7", m68040 },
+{"fdaddx", two(0xF000, 0x4836), two(0xF1C0, 0xFC7F), "Ii;xF7", m68040 },
+/* {"faddx", two(0xF000, 0x0036), two(0xF1C0, 0xE07F), "IiFt", m68040 }, JF removed */
+
+{"fasinb", two(0xF000, 0x580C), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat },
+{"fasind", two(0xF000, 0x540C), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat },
+{"fasinl", two(0xF000, 0x400C), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat },
+{"fasinp", two(0xF000, 0x4C0C), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat },
+{"fasins", two(0xF000, 0x440C), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat },
+{"fasinw", two(0xF000, 0x500C), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat },
+{"fasinx", two(0xF000, 0x000C), two(0xF1C0, 0xE07F), "IiF8F7", mfloat },
+{"fasinx", two(0xF000, 0x480C), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat },
+{"fasinx", two(0xF000, 0x000C), two(0xF1C0, 0xE07F), "IiFt", mfloat },
+
+{"fatanb", two(0xF000, 0x580A), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat },
+{"fatand", two(0xF000, 0x540A), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat },
+{"fatanl", two(0xF000, 0x400A), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat },
+{"fatanp", two(0xF000, 0x4C0A), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat },
+{"fatans", two(0xF000, 0x440A), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat },
+{"fatanw", two(0xF000, 0x500A), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat },
+{"fatanx", two(0xF000, 0x000A), two(0xF1C0, 0xE07F), "IiF8F7", mfloat },
+{"fatanx", two(0xF000, 0x480A), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat },
+{"fatanx", two(0xF000, 0x000A), two(0xF1C0, 0xE07F), "IiFt", mfloat },
+
+{"fatanhb", two(0xF000, 0x580D), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat },
+{"fatanhd", two(0xF000, 0x540D), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat },
+{"fatanhl", two(0xF000, 0x400D), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat },
+{"fatanhp", two(0xF000, 0x4C0D), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat },
+{"fatanhs", two(0xF000, 0x440D), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat },
+{"fatanhw", two(0xF000, 0x500D), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat },
+{"fatanhx", two(0xF000, 0x000D), two(0xF1C0, 0xE07F), "IiF8F7", mfloat },
+{"fatanhx", two(0xF000, 0x480D), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat },
+{"fatanhx", two(0xF000, 0x000D), two(0xF1C0, 0xE07F), "IiFt", mfloat },
+
+/* Fixed-size Float branches */
+
+{"fbeq", one(0xF081), one(0xF1BF), "IdBW", mfloat },
+{"fbf", one(0xF080), one(0xF1BF), "IdBW", mfloat },
+{"fbge", one(0xF093), one(0xF1BF), "IdBW", mfloat },
+{"fbgl", one(0xF096), one(0xF1BF), "IdBW", mfloat },
+{"fbgle", one(0xF097), one(0xF1BF), "IdBW", mfloat },
+{"fbgt", one(0xF092), one(0xF1BF), "IdBW", mfloat },
+{"fble", one(0xF095), one(0xF1BF), "IdBW", mfloat },
+{"fblt", one(0xF094), one(0xF1BF), "IdBW", mfloat },
+{"fbne", one(0xF08E), one(0xF1BF), "IdBW", mfloat },
+{"fbnge", one(0xF09C), one(0xF1BF), "IdBW", mfloat },
+{"fbngl", one(0xF099), one(0xF1BF), "IdBW", mfloat },
+{"fbngle", one(0xF098), one(0xF1BF), "IdBW", mfloat },
+{"fbngt", one(0xF09D), one(0xF1BF), "IdBW", mfloat },
+{"fbnle", one(0xF09A), one(0xF1BF), "IdBW", mfloat },
+{"fbnlt", one(0xF09B), one(0xF1BF), "IdBW", mfloat },
+{"fboge", one(0xF083), one(0xF1BF), "IdBW", mfloat },
+{"fbogl", one(0xF086), one(0xF1BF), "IdBW", mfloat },
+{"fbogt", one(0xF082), one(0xF1BF), "IdBW", mfloat },
+{"fbole", one(0xF085), one(0xF1BF), "IdBW", mfloat },
+{"fbolt", one(0xF084), one(0xF1BF), "IdBW", mfloat },
+{"fbor", one(0xF087), one(0xF1BF), "IdBW", mfloat },
+{"fbseq", one(0xF091), one(0xF1BF), "IdBW", mfloat },
+{"fbsf", one(0xF090), one(0xF1BF), "IdBW", mfloat },
+{"fbsne", one(0xF09E), one(0xF1BF), "IdBW", mfloat },
+{"fbst", one(0xF09F), one(0xF1BF), "IdBW", mfloat },
+{"fbt", one(0xF08F), one(0xF1BF), "IdBW", mfloat },
+{"fbueq", one(0xF089), one(0xF1BF), "IdBW", mfloat },
+{"fbuge", one(0xF08B), one(0xF1BF), "IdBW", mfloat },
+{"fbugt", one(0xF08A), one(0xF1BF), "IdBW", mfloat },
+{"fbule", one(0xF08D), one(0xF1BF), "IdBW", mfloat },
+{"fbult", one(0xF08C), one(0xF1BF), "IdBW", mfloat },
+{"fbun", one(0xF088), one(0xF1BF), "IdBW", mfloat },
+
+/* Float branches -- long (32-bit) displacements */
+
+{"fbeql", one(0xF081), one(0xF1BF), "IdBC", mfloat },
+{"fbfl", one(0xF080), one(0xF1BF), "IdBC", mfloat },
+{"fbgel", one(0xF093), one(0xF1BF), "IdBC", mfloat },
+{"fbgll", one(0xF096), one(0xF1BF), "IdBC", mfloat },
+{"fbglel", one(0xF097), one(0xF1BF), "IdBC", mfloat },
+{"fbgtl", one(0xF092), one(0xF1BF), "IdBC", mfloat },
+{"fblel", one(0xF095), one(0xF1BF), "IdBC", mfloat },
+{"fbltl", one(0xF094), one(0xF1BF), "IdBC", mfloat },
+{"fbnel", one(0xF08E), one(0xF1BF), "IdBC", mfloat },
+{"fbngel", one(0xF09C), one(0xF1BF), "IdBC", mfloat },
+{"fbngll", one(0xF099), one(0xF1BF), "IdBC", mfloat },
+{"fbnglel", one(0xF098), one(0xF1BF), "IdBC", mfloat },
+{"fbngtl", one(0xF09D), one(0xF1BF), "IdBC", mfloat },
+{"fbnlel", one(0xF09A), one(0xF1BF), "IdBC", mfloat },
+{"fbnltl", one(0xF09B), one(0xF1BF), "IdBC", mfloat },
+{"fbogel", one(0xF083), one(0xF1BF), "IdBC", mfloat },
+{"fbogll", one(0xF086), one(0xF1BF), "IdBC", mfloat },
+{"fbogtl", one(0xF082), one(0xF1BF), "IdBC", mfloat },
+{"fbolel", one(0xF085), one(0xF1BF), "IdBC", mfloat },
+{"fboltl", one(0xF084), one(0xF1BF), "IdBC", mfloat },
+{"fborl", one(0xF087), one(0xF1BF), "IdBC", mfloat },
+{"fbseql", one(0xF091), one(0xF1BF), "IdBC", mfloat },
+{"fbsfl", one(0xF090), one(0xF1BF), "IdBC", mfloat },
+{"fbsnel", one(0xF09E), one(0xF1BF), "IdBC", mfloat },
+{"fbstl", one(0xF09F), one(0xF1BF), "IdBC", mfloat },
+{"fbtl", one(0xF08F), one(0xF1BF), "IdBC", mfloat },
+{"fbueql", one(0xF089), one(0xF1BF), "IdBC", mfloat },
+{"fbugel", one(0xF08B), one(0xF1BF), "IdBC", mfloat },
+{"fbugtl", one(0xF08A), one(0xF1BF), "IdBC", mfloat },
+{"fbulel", one(0xF08D), one(0xF1BF), "IdBC", mfloat },
+{"fbultl", one(0xF08C), one(0xF1BF), "IdBC", mfloat },
+{"fbunl", one(0xF088), one(0xF1BF), "IdBC", mfloat },
+
+{"fcmpb", two(0xF000, 0x5838), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat },
+{"fcmpd", two(0xF000, 0x5438), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat },
+{"fcmpl", two(0xF000, 0x4038), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat },
+{"fcmpp", two(0xF000, 0x4C38), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat },
+{"fcmps", two(0xF000, 0x4438), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat },
+{"fcmpw", two(0xF000, 0x5038), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat },
+{"fcmpx", two(0xF000, 0x0038), two(0xF1C0, 0xE07F), "IiF8F7", mfloat },
+{"fcmpx", two(0xF000, 0x4838), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat },
+/* {"fcmpx", two(0xF000, 0x0038), two(0xF1C0, 0xE07F), "IiFt", mfloat }, JF removed */
+
+{"fcosb", two(0xF000, 0x581D), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat },
+{"fcosd", two(0xF000, 0x541D), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat },
+{"fcosl", two(0xF000, 0x401D), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat },
+{"fcosp", two(0xF000, 0x4C1D), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat },
+{"fcoss", two(0xF000, 0x441D), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat },
+{"fcosw", two(0xF000, 0x501D), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat },
+{"fcosx", two(0xF000, 0x001D), two(0xF1C0, 0xE07F), "IiF8F7", mfloat },
+{"fcosx", two(0xF000, 0x481D), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat },
+{"fcosx", two(0xF000, 0x001D), two(0xF1C0, 0xE07F), "IiFt", mfloat },
+
+{"fcoshb", two(0xF000, 0x5819), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat },
+{"fcoshd", two(0xF000, 0x5419), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat },
+{"fcoshl", two(0xF000, 0x4019), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat },
+{"fcoshp", two(0xF000, 0x4C19), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat },
+{"fcoshs", two(0xF000, 0x4419), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat },
+{"fcoshw", two(0xF000, 0x5019), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat },
+{"fcoshx", two(0xF000, 0x0019), two(0xF1C0, 0xE07F), "IiF8F7", mfloat },
+{"fcoshx", two(0xF000, 0x4819), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat },
+{"fcoshx", two(0xF000, 0x0019), two(0xF1C0, 0xE07F), "IiFt", mfloat },
+
+{"fdbeq", two(0xF048, 0x0001), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat },
+{"fdbf", two(0xF048, 0x0000), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat },
+{"fdbge", two(0xF048, 0x0013), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat },
+{"fdbgl", two(0xF048, 0x0016), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat },
+{"fdbgle", two(0xF048, 0x0017), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat },
+{"fdbgt", two(0xF048, 0x0012), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat },
+{"fdble", two(0xF048, 0x0015), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat },
+{"fdblt", two(0xF048, 0x0014), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat },
+{"fdbne", two(0xF048, 0x000E), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat },
+{"fdbnge", two(0xF048, 0x001C), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat },
+{"fdbngl", two(0xF048, 0x0019), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat },
+{"fdbngle", two(0xF048, 0x0018), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat },
+{"fdbngt", two(0xF048, 0x001D), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat },
+{"fdbnle", two(0xF048, 0x001A), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat },
+{"fdbnlt", two(0xF048, 0x001B), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat },
+{"fdboge", two(0xF048, 0x0003), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat },
+{"fdbogl", two(0xF048, 0x0006), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat },
+{"fdbogt", two(0xF048, 0x0002), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat },
+{"fdbole", two(0xF048, 0x0005), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat },
+{"fdbolt", two(0xF048, 0x0004), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat },
+{"fdbor", two(0xF048, 0x0007), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat },
+{"fdbseq", two(0xF048, 0x0011), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat },
+{"fdbsf", two(0xF048, 0x0010), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat },
+{"fdbsne", two(0xF048, 0x001E), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat },
+{"fdbst", two(0xF048, 0x001F), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat },
+{"fdbt", two(0xF048, 0x000F), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat },
+{"fdbueq", two(0xF048, 0x0009), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat },
+{"fdbuge", two(0xF048, 0x000B), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat },
+{"fdbugt", two(0xF048, 0x000A), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat },
+{"fdbule", two(0xF048, 0x000D), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat },
+{"fdbult", two(0xF048, 0x000C), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat },
+{"fdbun", two(0xF048, 0x0008), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat },
+
+{"fdivb", two(0xF000, 0x5820), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat },
+{"fdivd", two(0xF000, 0x5420), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat },
+{"fdivl", two(0xF000, 0x4020), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat },
+{"fdivp", two(0xF000, 0x4C20), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat },
+{"fdivs", two(0xF000, 0x4420), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat },
+{"fdivw", two(0xF000, 0x5020), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat },
+{"fdivx", two(0xF000, 0x0020), two(0xF1C0, 0xE07F), "IiF8F7", mfloat },
+{"fdivx", two(0xF000, 0x4820), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat },
+/* {"fdivx", two(0xF000, 0x0020), two(0xF1C0, 0xE07F), "IiFt", mfloat }, JF */
+
+{"fsdivb", two(0xF000, 0x5830), two(0xF1C0, 0xFC7F), "Ii;bF7", m68040 },
+{"fsdivd", two(0xF000, 0x5430), two(0xF1C0, 0xFC7F), "Ii;FF7", m68040 },
+{"fsdivl", two(0xF000, 0x4030), two(0xF1C0, 0xFC7F), "Ii;lF7", m68040 },
+{"fsdivp", two(0xF000, 0x4C30), two(0xF1C0, 0xFC7F), "Ii;pF7", m68040 },
+{"fsdivs", two(0xF000, 0x4430), two(0xF1C0, 0xFC7F), "Ii;fF7", m68040 },
+{"fsdivw", two(0xF000, 0x5030), two(0xF1C0, 0xFC7F), "Ii;wF7", m68040 },
+{"fsdivx", two(0xF000, 0x0030), two(0xF1C0, 0xE07F), "IiF8F7", m68040 },
+{"fsdivx", two(0xF000, 0x4830), two(0xF1C0, 0xFC7F), "Ii;xF7", m68040 },
+/* {"fsdivx", two(0xF000, 0x0030), two(0xF1C0, 0xE07F), "IiFt", m68040 }, JF */
+
+{"fddivb", two(0xF000, 0x5834), two(0xF1C0, 0xFC7F), "Ii;bF7", m68040 },
+{"fddivd", two(0xF000, 0x5434), two(0xF1C0, 0xFC7F), "Ii;FF7", m68040 },
+{"fddivl", two(0xF000, 0x4034), two(0xF1C0, 0xFC7F), "Ii;lF7", m68040 },
+{"fddivp", two(0xF000, 0x4C34), two(0xF1C0, 0xFC7F), "Ii;pF7", m68040 },
+{"fddivs", two(0xF000, 0x4434), two(0xF1C0, 0xFC7F), "Ii;fF7", m68040 },
+{"fddivw", two(0xF000, 0x5034), two(0xF1C0, 0xFC7F), "Ii;wF7", m68040 },
+{"fddivx", two(0xF000, 0x0034), two(0xF1C0, 0xE07F), "IiF8F7", m68040 },
+{"fddivx", two(0xF000, 0x4834), two(0xF1C0, 0xFC7F), "Ii;xF7", m68040 },
+/* {"fddivx", two(0xF000, 0x0034), two(0xF1C0, 0xE07F), "IiFt", m68040 }, JF */
+
+{"fetoxb", two(0xF000, 0x5810), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat },
+{"fetoxd", two(0xF000, 0x5410), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat },
+{"fetoxl", two(0xF000, 0x4010), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat },
+{"fetoxp", two(0xF000, 0x4C10), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat },
+{"fetoxs", two(0xF000, 0x4410), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat },
+{"fetoxw", two(0xF000, 0x5010), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat },
+{"fetoxx", two(0xF000, 0x0010), two(0xF1C0, 0xE07F), "IiF8F7", mfloat },
+{"fetoxx", two(0xF000, 0x4810), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat },
+{"fetoxx", two(0xF000, 0x0010), two(0xF1C0, 0xE07F), "IiFt", mfloat },
+
+{"fetoxm1b", two(0xF000, 0x5808), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat },
+{"fetoxm1d", two(0xF000, 0x5408), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat },
+{"fetoxm1l", two(0xF000, 0x4008), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat },
+{"fetoxm1p", two(0xF000, 0x4C08), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat },
+{"fetoxm1s", two(0xF000, 0x4408), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat },
+{"fetoxm1w", two(0xF000, 0x5008), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat },
+{"fetoxm1x", two(0xF000, 0x0008), two(0xF1C0, 0xE07F), "IiF8F7", mfloat },
+{"fetoxm1x", two(0xF000, 0x4808), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat },
+{"fetoxm1x", two(0xF000, 0x0008), two(0xF1C0, 0xE07F), "IiFt", mfloat },
+
+{"fgetexpb", two(0xF000, 0x581E), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat },
+{"fgetexpd", two(0xF000, 0x541E), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat },
+{"fgetexpl", two(0xF000, 0x401E), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat },
+{"fgetexpp", two(0xF000, 0x4C1E), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat },
+{"fgetexps", two(0xF000, 0x441E), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat },
+{"fgetexpw", two(0xF000, 0x501E), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat },
+{"fgetexpx", two(0xF000, 0x001E), two(0xF1C0, 0xE07F), "IiF8F7", mfloat },
+{"fgetexpx", two(0xF000, 0x481E), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat },
+{"fgetexpx", two(0xF000, 0x001E), two(0xF1C0, 0xE07F), "IiFt", mfloat },
+
+{"fgetmanb", two(0xF000, 0x581F), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat },
+{"fgetmand", two(0xF000, 0x541F), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat },
+{"fgetmanl", two(0xF000, 0x401F), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat },
+{"fgetmanp", two(0xF000, 0x4C1F), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat },
+{"fgetmans", two(0xF000, 0x441F), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat },
+{"fgetmanw", two(0xF000, 0x501F), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat },
+{"fgetmanx", two(0xF000, 0x001F), two(0xF1C0, 0xE07F), "IiF8F7", mfloat },
+{"fgetmanx", two(0xF000, 0x481F), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat },
+{"fgetmanx", two(0xF000, 0x001F), two(0xF1C0, 0xE07F), "IiFt", mfloat },
+
+{"fintb", two(0xF000, 0x5801), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat },
+{"fintd", two(0xF000, 0x5401), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat },
+{"fintl", two(0xF000, 0x4001), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat },
+{"fintp", two(0xF000, 0x4C01), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat },
+{"fints", two(0xF000, 0x4401), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat },
+{"fintw", two(0xF000, 0x5001), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat },
+{"fintx", two(0xF000, 0x0001), two(0xF1C0, 0xE07F), "IiF8F7", mfloat },
+{"fintx", two(0xF000, 0x4801), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat },
+{"fintx", two(0xF000, 0x0001), two(0xF1C0, 0xE07F), "IiFt", mfloat },
+
+{"fintrzb", two(0xF000, 0x5803), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat },
+{"fintrzd", two(0xF000, 0x5403), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat },
+{"fintrzl", two(0xF000, 0x4003), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat },
+{"fintrzp", two(0xF000, 0x4C03), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat },
+{"fintrzs", two(0xF000, 0x4403), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat },
+{"fintrzw", two(0xF000, 0x5003), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat },
+{"fintrzx", two(0xF000, 0x0003), two(0xF1C0, 0xE07F), "IiF8F7", mfloat },
+{"fintrzx", two(0xF000, 0x4803), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat },
+{"fintrzx", two(0xF000, 0x0003), two(0xF1C0, 0xE07F), "IiFt", mfloat },
+
+{"flog10b", two(0xF000, 0x5815), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat },
+{"flog10d", two(0xF000, 0x5415), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat },
+{"flog10l", two(0xF000, 0x4015), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat },
+{"flog10p", two(0xF000, 0x4C15), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat },
+{"flog10s", two(0xF000, 0x4415), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat },
+{"flog10w", two(0xF000, 0x5015), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat },
+{"flog10x", two(0xF000, 0x0015), two(0xF1C0, 0xE07F), "IiF8F7", mfloat },
+{"flog10x", two(0xF000, 0x4815), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat },
+{"flog10x", two(0xF000, 0x0015), two(0xF1C0, 0xE07F), "IiFt", mfloat },
+
+{"flog2b", two(0xF000, 0x5816), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat },
+{"flog2d", two(0xF000, 0x5416), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat },
+{"flog2l", two(0xF000, 0x4016), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat },
+{"flog2p", two(0xF000, 0x4C16), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat },
+{"flog2s", two(0xF000, 0x4416), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat },
+{"flog2w", two(0xF000, 0x5016), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat },
+{"flog2x", two(0xF000, 0x0016), two(0xF1C0, 0xE07F), "IiF8F7", mfloat },
+{"flog2x", two(0xF000, 0x4816), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat },
+{"flog2x", two(0xF000, 0x0016), two(0xF1C0, 0xE07F), "IiFt", mfloat },
+
+{"flognb", two(0xF000, 0x5814), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat },
+{"flognd", two(0xF000, 0x5414), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat },
+{"flognl", two(0xF000, 0x4014), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat },
+{"flognp", two(0xF000, 0x4C14), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat },
+{"flogns", two(0xF000, 0x4414), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat },
+{"flognw", two(0xF000, 0x5014), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat },
+{"flognx", two(0xF000, 0x0014), two(0xF1C0, 0xE07F), "IiF8F7", mfloat },
+{"flognx", two(0xF000, 0x4814), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat },
+{"flognx", two(0xF000, 0x0014), two(0xF1C0, 0xE07F), "IiFt", mfloat },
+
+{"flognp1b", two(0xF000, 0x5806), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat },
+{"flognp1d", two(0xF000, 0x5406), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat },
+{"flognp1l", two(0xF000, 0x4006), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat },
+{"flognp1p", two(0xF000, 0x4C06), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat },
+{"flognp1s", two(0xF000, 0x4406), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat },
+{"flognp1w", two(0xF000, 0x5006), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat },
+{"flognp1x", two(0xF000, 0x0006), two(0xF1C0, 0xE07F), "IiF8F7", mfloat },
+{"flognp1x", two(0xF000, 0x4806), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat },
+{"flognp1x", two(0xF000, 0x0006), two(0xF1C0, 0xE07F), "IiFt", mfloat },
+
+{"fmodb", two(0xF000, 0x5821), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat },
+{"fmodd", two(0xF000, 0x5421), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat },
+{"fmodl", two(0xF000, 0x4021), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat },
+{"fmodp", two(0xF000, 0x4C21), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat },
+{"fmods", two(0xF000, 0x4421), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat },
+{"fmodw", two(0xF000, 0x5021), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat },
+{"fmodx", two(0xF000, 0x0021), two(0xF1C0, 0xE07F), "IiF8F7", mfloat },
+{"fmodx", two(0xF000, 0x4821), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat },
+/* {"fmodx", two(0xF000, 0x0021), two(0xF1C0, 0xE07F), "IiFt", mfloat }, JF */
+
+{"fmoveb", two(0xF000, 0x5800), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat }, /* fmove from <ea> to fp<n> */
+{"fmoveb", two(0xF000, 0x7800), two(0xF1C0, 0xFC7F), "IiF7@b", mfloat }, /* fmove from fp<n> to <ea> */
+{"fmoved", two(0xF000, 0x5400), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat }, /* fmove from <ea> to fp<n> */
+{"fmoved", two(0xF000, 0x7400), two(0xF1C0, 0xFC7F), "IiF7@F", mfloat }, /* fmove from fp<n> to <ea> */
+{"fmovel", two(0xF000, 0x4000), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat }, /* fmove from <ea> to fp<n> */
+{"fmovel", two(0xF000, 0x6000), two(0xF1C0, 0xFC7F), "IiF7@l", mfloat }, /* fmove from fp<n> to <ea> */
+/* Warning: The addressing modes on these are probably not right:
+ esp, Areg direct is only allowed for FPI */
+ /* fmove.l from/to system control registers: */
+{"fmovel", two(0xF000, 0xA000), two(0xF1C0, 0xE3FF), "Iis8@s", mfloat },
+{"fmovel", two(0xF000, 0x8000), two(0xF1C0, 0xE3FF), "Ii*ls8", mfloat },
+
+/* {"fmovel", two(0xF000, 0xA000), two(0xF1C0, 0xE3FF), "Iis8@s", mfloat },
+{"fmovel", two(0xF000, 0x8000), two(0xF2C0, 0xE3FF), "Ii*ss8", mfloat }, */
+
+{"fmovep", two(0xF000, 0x4C00), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat }, /* fmove from <ea> to fp<n> */
+{"fmovep", two(0xF000, 0x6C00), two(0xF1C0, 0xFC00), "IiF7@pkC", mfloat }, /* fmove.p with k-factors: */
+{"fmovep", two(0xF000, 0x7C00), two(0xF1C0, 0xFC0F), "IiF7@pDk", mfloat }, /* fmove.p with k-factors: */
+
+{"fmoves", two(0xF000, 0x4400), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat }, /* fmove from <ea> to fp<n> */
+{"fmoves", two(0xF000, 0x6400), two(0xF1C0, 0xFC7F), "IiF7@f", mfloat }, /* fmove from fp<n> to <ea> */
+{"fmovew", two(0xF000, 0x5000), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat }, /* fmove from <ea> to fp<n> */
+{"fmovew", two(0xF000, 0x7000), two(0xF1C0, 0xFC7F), "IiF7@w", mfloat }, /* fmove from fp<n> to <ea> */
+{"fmovex", two(0xF000, 0x0000), two(0xF1C0, 0xE07F), "IiF8F7", mfloat }, /* fmove from <ea> to fp<n> */
+{"fmovex", two(0xF000, 0x4800), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat }, /* fmove from <ea> to fp<n> */
+{"fmovex", two(0xF000, 0x6800), two(0xF1C0, 0xFC7F), "IiF7@x", mfloat }, /* fmove from fp<n> to <ea> */
+/* JF removed {"fmovex", two(0xF000, 0x0000), two(0xF1C0, 0xE07F), "IiFt", mfloat }, / * fmove from <ea> to fp<n> */
+
+{"fsmoveb", two(0xF000, 0x5800), two(0xF1C0, 0xFC7F), "Ii;bF7", m68040 }, /* fmove from <ea> to fp<n> */
+{"fsmoved", two(0xF000, 0x5400), two(0xF1C0, 0xFC7F), "Ii;FF7", m68040 }, /* fmove from <ea> to fp<n> */
+{"fsmovel", two(0xF000, 0x4000), two(0xF1C0, 0xFC7F), "Ii;lF7", m68040 }, /* fmove from <ea> to fp<n> */
+{"fsmoves", two(0xF000, 0x4400), two(0xF1C0, 0xFC7F), "Ii;fF7", m68040 }, /* fmove from <ea> to fp<n> */
+{"fsmovew", two(0xF000, 0x5000), two(0xF1C0, 0xFC7F), "Ii;wF7", m68040 }, /* fmove from <ea> to fp<n> */
+{"fsmovex", two(0xF000, 0x0000), two(0xF1C0, 0xE07F), "IiF8F7", m68040 }, /* fmove from <ea> to fp<n> */
+{"fsmovex", two(0xF000, 0x4800), two(0xF1C0, 0xFC7F), "Ii;xF7", m68040 }, /* fmove from <ea> to fp<n> */
+/* JF removed {"fsmovex", two(0xF000, 0x0000), two(0xF1C0, 0xE07F), "IiFt", m68040 }, / * fmove from <ea> to fp<n> */
+
+{"fdmoveb", two(0xF000, 0x5800), two(0xF1C0, 0xFC7F), "Ii;bF7", m68040 }, /* fmove from <ea> to fp<n> */
+{"fdmoved", two(0xF000, 0x5400), two(0xF1C0, 0xFC7F), "Ii;FF7", m68040 }, /* fmove from <ea> to fp<n> */
+{"fdmovel", two(0xF000, 0x4000), two(0xF1C0, 0xFC7F), "Ii;lF7", m68040 }, /* fmove from <ea> to fp<n> */
+{"fdmoves", two(0xF000, 0x4400), two(0xF1C0, 0xFC7F), "Ii;fF7", m68040 }, /* fmove from <ea> to fp<n> */
+{"fdmovew", two(0xF000, 0x5000), two(0xF1C0, 0xFC7F), "Ii;wF7", m68040 }, /* fmove from <ea> to fp<n> */
+{"fdmovex", two(0xF000, 0x0000), two(0xF1C0, 0xE07F), "IiF8F7", m68040 }, /* fmove from <ea> to fp<n> */
+{"fdmovex", two(0xF000, 0x4800), two(0xF1C0, 0xFC7F), "Ii;xF7", m68040 }, /* fmove from <ea> to fp<n> */
+/* JF removed {"fdmovex", two(0xF000, 0x0000), two(0xF1C0, 0xE07F), "IiFt", m68040 }, / * fmove from <ea> to fp<n> */
+
+{"fmovecrx", two(0xF000, 0x5C00), two(0xF1FF, 0xFC00), "Ii#CF7", mfloat }, /* fmovecr.x #ccc, FPn */
+{"fmovecr", two(0xF000, 0x5C00), two(0xF1FF, 0xFC00), "Ii#CF7", mfloat },
+
+/* Other fmovemx. */
+{"fmovemx", two(0xF000, 0xF800), two(0xF1C0, 0xFF8F), "IiDk&s", mfloat }, /* reg to control, static and dynamic: */
+{"fmovemx", two(0xF000, 0xD800), two(0xF1C0, 0xFF8F), "Ii&sDk", mfloat }, /* from control to reg, static and dynamic: */
+
+{"fmovemx", two(0xF000, 0xF000), two(0xF1C0, 0xFF00), "Idl3&s", mfloat }, /* to control, static and dynamic: */
+{"fmovemx", two(0xF000, 0xF000), two(0xF1C0, 0xFF00), "Id#3&s", mfloat }, /* to control, static and dynamic: */
+
+{"fmovemx", two(0xF000, 0xD000), two(0xF1C0, 0xFF00), "Id&sl3", mfloat }, /* from control, static and dynamic: */
+{"fmovemx", two(0xF000, 0xD000), two(0xF1C0, 0xFF00), "Id&s#3", mfloat }, /* from control, static and dynamic: */
+
+{"fmovemx", two(0xF020, 0xE800), two(0xF1F8, 0xFF8F), "IiDk-s", mfloat }, /* reg to autodecrement, static and dynamic */
+{"fmovemx", two(0xF020, 0xE000), two(0xF1F8, 0xFF00), "IdL3-s", mfloat }, /* to autodecrement, static and dynamic */
+{"fmovemx", two(0xF020, 0xE000), two(0xF1F8, 0xFF00), "Id#3-s", mfloat }, /* to autodecrement, static and dynamic */
+
+{"fmovemx", two(0xF018, 0xD800), two(0xF1F8, 0xFF8F), "Ii+sDk", mfloat }, /* from autoinc to reg, static and dynamic: */
+{"fmovemx", two(0xF018, 0xD000), two(0xF1F8, 0xFF00), "Id+sl3", mfloat }, /* from autoincrement, static and dynamic: */
+{"fmovemx", two(0xF018, 0xD000), two(0xF1F8, 0xFF00), "Id+s#3", mfloat }, /* from autoincrement, static and dynamic: */
+
+{"fmoveml", two(0xF000, 0xA000), two(0xF1C0, 0xE3FF), "IiL8@s", mfloat },
+{"fmoveml", two(0xF000, 0xA000), two(0xF1C0, 0xE3FF), "Ii#8@s", mfloat },
+{"fmoveml", two(0xF000, 0xA000), two(0xF1C0, 0xE3FF), "Iis8@s", mfloat },
+
+{"fmoveml", two(0xF000, 0x8000), two(0xF2C0, 0xE3FF), "Ii*sL8", mfloat },
+{"fmoveml", two(0xF000, 0x8000), two(0xF1C0, 0xE3FF), "Ii*s#8", mfloat },
+{"fmoveml", two(0xF000, 0x8000), two(0xF1C0, 0xE3FF), "Ii*ss8", mfloat },
+
+/* fmovemx with register lists */
+{"fmovem", two(0xF020, 0xE000), two(0xF1F8, 0xFF00), "IdL3-s", mfloat }, /* to autodec, static & dynamic */
+{"fmovem", two(0xF000, 0xF000), two(0xF1C0, 0xFF00), "Idl3&s", mfloat }, /* to control, static and dynamic */
+{"fmovem", two(0xF018, 0xD000), two(0xF1F8, 0xFF00), "Id+sl3", mfloat }, /* from autoinc, static & dynamic */
+{"fmovem", two(0xF000, 0xD000), two(0xF1C0, 0xFF00), "Id&sl3", mfloat }, /* from control, static and dynamic */
+
+ /* Alternate mnemonics for GNU as and GNU CC */
+{"fmovem", two(0xF020, 0xE000), two(0xF1F8, 0xFF00), "Id#3-s", mfloat }, /* to autodecrement, static and dynamic */
+{"fmovem", two(0xF020, 0xE800), two(0xF1F8, 0xFF8F), "IiDk-s", mfloat }, /* to autodecrement, static and dynamic */
+
+{"fmovem", two(0xF000, 0xF000), two(0xF1C0, 0xFF00), "Id#3&s", mfloat }, /* to control, static and dynamic: */
+{"fmovem", two(0xF000, 0xF800), two(0xF1C0, 0xFF8F), "IiDk&s", mfloat }, /* to control, static and dynamic: */
+
+{"fmovem", two(0xF018, 0xD000), two(0xF1F8, 0xFF00), "Id+s#3", mfloat }, /* from autoincrement, static and dynamic: */
+{"fmovem", two(0xF018, 0xD800), two(0xF1F8, 0xFF8F), "Ii+sDk", mfloat }, /* from autoincrement, static and dynamic: */
+
+{"fmovem", two(0xF000, 0xD000), two(0xF1C0, 0xFF00), "Id&s#3", mfloat }, /* from control, static and dynamic: */
+{"fmovem", two(0xF000, 0xD800), two(0xF1C0, 0xFF8F), "Ii&sDk", mfloat }, /* from control, static and dynamic: */
+
+/* fmoveml a FP-control register */
+{"fmovem", two(0xF000, 0xA000), two(0xF1C0, 0xE3FF), "Iis8@s", mfloat },
+{"fmovem", two(0xF000, 0x8000), two(0xF1C0, 0xE3FF), "Ii*ss8", mfloat },
+
+/* fmoveml a FP-control reglist */
+{"fmovem", two(0xF000, 0xA000), two(0xF1C0, 0xE3FF), "IiL8@s", mfloat },
+{"fmovem", two(0xF000, 0x8000), two(0xF2C0, 0xE3FF), "Ii*sL8", mfloat },
+
+{"fmulb", two(0xF000, 0x5823), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat },
+{"fmuld", two(0xF000, 0x5423), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat },
+{"fmull", two(0xF000, 0x4023), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat },
+{"fmulp", two(0xF000, 0x4C23), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat },
+{"fmuls", two(0xF000, 0x4423), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat },
+{"fmulw", two(0xF000, 0x5023), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat },
+{"fmulx", two(0xF000, 0x0023), two(0xF1C0, 0xE07F), "IiF8F7", mfloat },
+{"fmulx", two(0xF000, 0x4823), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat },
+/* {"fmulx", two(0xF000, 0x0023), two(0xF1C0, 0xE07F), "IiFt", mfloat }, JF */
+
+{"fsmulb", two(0xF000, 0x5833), two(0xF1C0, 0xFC7F), "Ii;bF7", m68040 },
+{"fsmuld", two(0xF000, 0x5433), two(0xF1C0, 0xFC7F), "Ii;FF7", m68040 },
+{"fsmull", two(0xF000, 0x4033), two(0xF1C0, 0xFC7F), "Ii;lF7", m68040 },
+{"fsmulp", two(0xF000, 0x4C33), two(0xF1C0, 0xFC7F), "Ii;pF7", m68040 },
+{"fsmuls", two(0xF000, 0x4433), two(0xF1C0, 0xFC7F), "Ii;fF7", m68040 },
+{"fsmulw", two(0xF000, 0x5033), two(0xF1C0, 0xFC7F), "Ii;wF7", m68040 },
+{"fsmulx", two(0xF000, 0x0033), two(0xF1C0, 0xE07F), "IiF8F7", m68040 },
+{"fsmulx", two(0xF000, 0x4833), two(0xF1C0, 0xFC7F), "Ii;xF7", m68040 },
+/* {"fsmulx", two(0xF000, 0x0033), two(0xF1C0, 0xE07F), "IiFt", m68040 }, JF */
+
+{"fdmulb", two(0xF000, 0x5837), two(0xF1C0, 0xFC7F), "Ii;bF7", m68040 },
+{"fdmuld", two(0xF000, 0x5437), two(0xF1C0, 0xFC7F), "Ii;FF7", m68040 },
+{"fdmull", two(0xF000, 0x4037), two(0xF1C0, 0xFC7F), "Ii;lF7", m68040 },
+{"fdmulp", two(0xF000, 0x4C37), two(0xF1C0, 0xFC7F), "Ii;pF7", m68040 },
+{"fdmuls", two(0xF000, 0x4437), two(0xF1C0, 0xFC7F), "Ii;fF7", m68040 },
+{"fdmulw", two(0xF000, 0x5037), two(0xF1C0, 0xFC7F), "Ii;wF7", m68040 },
+{"fdmulx", two(0xF000, 0x0037), two(0xF1C0, 0xE07F), "IiF8F7", m68040 },
+{"fdmulx", two(0xF000, 0x4837), two(0xF1C0, 0xFC7F), "Ii;xF7", m68040 },
+/* {"dfmulx", two(0xF000, 0x0037), two(0xF1C0, 0xE07F), "IiFt", m68040 }, JF */
+
+{"fnegb", two(0xF000, 0x581A), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat },
+{"fnegd", two(0xF000, 0x541A), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat },
+{"fnegl", two(0xF000, 0x401A), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat },
+{"fnegp", two(0xF000, 0x4C1A), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat },
+{"fnegs", two(0xF000, 0x441A), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat },
+{"fnegw", two(0xF000, 0x501A), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat },
+{"fnegx", two(0xF000, 0x001A), two(0xF1C0, 0xE07F), "IiF8F7", mfloat },
+{"fnegx", two(0xF000, 0x481A), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat },
+{"fnegx", two(0xF000, 0x001A), two(0xF1C0, 0xE07F), "IiFt", mfloat },
+
+{"fsnegb", two(0xF000, 0x585A), two(0xF1C0, 0xFC7F), "Ii;bF7", m68040 },
+{"fsnegd", two(0xF000, 0x545A), two(0xF1C0, 0xFC7F), "Ii;FF7", m68040 },
+{"fsnegl", two(0xF000, 0x405A), two(0xF1C0, 0xFC7F), "Ii;lF7", m68040 },
+{"fsnegp", two(0xF000, 0x4C5A), two(0xF1C0, 0xFC7F), "Ii;pF7", m68040 },
+{"fsnegs", two(0xF000, 0x445A), two(0xF1C0, 0xFC7F), "Ii;fF7", m68040 },
+{"fsnegw", two(0xF000, 0x505A), two(0xF1C0, 0xFC7F), "Ii;wF7", m68040 },
+{"fsnegx", two(0xF000, 0x005A), two(0xF1C0, 0xE07F), "IiF8F7", m68040 },
+{"fsnegx", two(0xF000, 0x485A), two(0xF1C0, 0xFC7F), "Ii;xF7", m68040 },
+{"fsnegx", two(0xF000, 0x005A), two(0xF1C0, 0xE07F), "IiFt", m68040 },
+
+{"fdnegb", two(0xF000, 0x585E), two(0xF1C0, 0xFC7F), "Ii;bF7", m68040 },
+{"fdnegd", two(0xF000, 0x545E), two(0xF1C0, 0xFC7F), "Ii;FF7", m68040 },
+{"fdnegl", two(0xF000, 0x405E), two(0xF1C0, 0xFC7F), "Ii;lF7", m68040 },
+{"fdnegp", two(0xF000, 0x4C5E), two(0xF1C0, 0xFC7F), "Ii;pF7", m68040 },
+{"fdnegs", two(0xF000, 0x445E), two(0xF1C0, 0xFC7F), "Ii;fF7", m68040 },
+{"fdnegw", two(0xF000, 0x505E), two(0xF1C0, 0xFC7F), "Ii;wF7", m68040 },
+{"fdnegx", two(0xF000, 0x005E), two(0xF1C0, 0xE07F), "IiF8F7", m68040 },
+{"fdnegx", two(0xF000, 0x485E), two(0xF1C0, 0xFC7F), "Ii;xF7", m68040 },
+{"fdnegx", two(0xF000, 0x005E), two(0xF1C0, 0xE07F), "IiFt", m68040 },
+
+{"fnop", two(0xF280, 0x0000), two(0xFFFF, 0xFFFF), "Ii", mfloat },
+
+{"fremb", two(0xF000, 0x5825), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat },
+{"fremd", two(0xF000, 0x5425), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat },
+{"freml", two(0xF000, 0x4025), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat },
+{"fremp", two(0xF000, 0x4C25), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat },
+{"frems", two(0xF000, 0x4425), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat },
+{"fremw", two(0xF000, 0x5025), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat },
+{"fremx", two(0xF000, 0x0025), two(0xF1C0, 0xE07F), "IiF8F7", mfloat },
+{"fremx", two(0xF000, 0x4825), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat },
+/* {"fremx", two(0xF000, 0x0025), two(0xF1C0, 0xE07F), "IiFt", mfloat }, JF */
+
+{"frestore", one(0xF140), one(0xF1C0), "Id&s", mfloat },
+{"frestore", one(0xF158), one(0xF1F8), "Id+s", mfloat },
+{"fsave", one(0xF100), one(0xF1C0), "Id&s", mfloat },
+{"fsave", one(0xF120), one(0xF1F8), "Id-s", mfloat },
+
+{"fscaleb", two(0xF000, 0x5826), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat },
+{"fscaled", two(0xF000, 0x5426), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat },
+{"fscalel", two(0xF000, 0x4026), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat },
+{"fscalep", two(0xF000, 0x4C26), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat },
+{"fscales", two(0xF000, 0x4426), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat },
+{"fscalew", two(0xF000, 0x5026), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat },
+{"fscalex", two(0xF000, 0x0026), two(0xF1C0, 0xE07F), "IiF8F7", mfloat },
+{"fscalex", two(0xF000, 0x4826), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat },
+/* {"fscalex", two(0xF000, 0x0026), two(0xF1C0, 0xE07F), "IiFt", mfloat }, JF */
+
+/* $ is necessary to prevent the assembler from using PC-relative.
+ If @ were used, "label: fseq label" could produce "ftrapeq",
+ because "label" became "pc@label". */
+{"fseq", two(0xF040, 0x0001), two(0xF1C0, 0xFFFF), "Ii$s", mfloat },
+{"fsf", two(0xF040, 0x0000), two(0xF1C0, 0xFFFF), "Ii$s", mfloat },
+{"fsge", two(0xF040, 0x0013), two(0xF1C0, 0xFFFF), "Ii$s", mfloat },
+{"fsgl", two(0xF040, 0x0016), two(0xF1C0, 0xFFFF), "Ii$s", mfloat },
+{"fsgle", two(0xF040, 0x0017), two(0xF1C0, 0xFFFF), "Ii$s", mfloat },
+{"fsgt", two(0xF040, 0x0012), two(0xF1C0, 0xFFFF), "Ii$s", mfloat },
+{"fsle", two(0xF040, 0x0015), two(0xF1C0, 0xFFFF), "Ii$s", mfloat },
+{"fslt", two(0xF040, 0x0014), two(0xF1C0, 0xFFFF), "Ii$s", mfloat },
+{"fsne", two(0xF040, 0x000E), two(0xF1C0, 0xFFFF), "Ii$s", mfloat },
+{"fsnge", two(0xF040, 0x001C), two(0xF1C0, 0xFFFF), "Ii$s", mfloat },
+{"fsngl", two(0xF040, 0x0019), two(0xF1C0, 0xFFFF), "Ii$s", mfloat },
+{"fsngle", two(0xF040, 0x0018), two(0xF1C0, 0xFFFF), "Ii$s", mfloat },
+{"fsngt", two(0xF040, 0x001D), two(0xF1C0, 0xFFFF), "Ii$s", mfloat },
+{"fsnle", two(0xF040, 0x001A), two(0xF1C0, 0xFFFF), "Ii$s", mfloat },
+{"fsnlt", two(0xF040, 0x001B), two(0xF1C0, 0xFFFF), "Ii$s", mfloat },
+{"fsoge", two(0xF040, 0x0003), two(0xF1C0, 0xFFFF), "Ii$s", mfloat },
+{"fsogl", two(0xF040, 0x0006), two(0xF1C0, 0xFFFF), "Ii$s", mfloat },
+{"fsogt", two(0xF040, 0x0002), two(0xF1C0, 0xFFFF), "Ii$s", mfloat },
+{"fsole", two(0xF040, 0x0005), two(0xF1C0, 0xFFFF), "Ii$s", mfloat },
+{"fsolt", two(0xF040, 0x0004), two(0xF1C0, 0xFFFF), "Ii$s", mfloat },
+{"fsor", two(0xF040, 0x0007), two(0xF1C0, 0xFFFF), "Ii$s", mfloat },
+{"fsseq", two(0xF040, 0x0011), two(0xF1C0, 0xFFFF), "Ii$s", mfloat },
+{"fssf", two(0xF040, 0x0010), two(0xF1C0, 0xFFFF), "Ii$s", mfloat },
+{"fssne", two(0xF040, 0x001E), two(0xF1C0, 0xFFFF), "Ii$s", mfloat },
+{"fsst", two(0xF040, 0x001F), two(0xF1C0, 0xFFFF), "Ii$s", mfloat },
+{"fst", two(0xF040, 0x000F), two(0xF1C0, 0xFFFF), "Ii$s", mfloat },
+{"fsueq", two(0xF040, 0x0009), two(0xF1C0, 0xFFFF), "Ii$s", mfloat },
+{"fsuge", two(0xF040, 0x000B), two(0xF1C0, 0xFFFF), "Ii$s", mfloat },
+{"fsugt", two(0xF040, 0x000A), two(0xF1C0, 0xFFFF), "Ii$s", mfloat },
+{"fsule", two(0xF040, 0x000D), two(0xF1C0, 0xFFFF), "Ii$s", mfloat },
+{"fsult", two(0xF040, 0x000C), two(0xF1C0, 0xFFFF), "Ii$s", mfloat },
+{"fsun", two(0xF040, 0x0008), two(0xF1C0, 0xFFFF), "Ii$s", mfloat },
+
+{"fsgldivb", two(0xF000, 0x5824), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat },
+{"fsgldivd", two(0xF000, 0x5424), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat },
+{"fsgldivl", two(0xF000, 0x4024), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat },
+{"fsgldivp", two(0xF000, 0x4C24), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat },
+{"fsgldivs", two(0xF000, 0x4424), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat },
+{"fsgldivw", two(0xF000, 0x5024), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat },
+{"fsgldivx", two(0xF000, 0x0024), two(0xF1C0, 0xE07F), "IiF8F7", mfloat },
+{"fsgldivx", two(0xF000, 0x4824), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat },
+{"fsgldivx", two(0xF000, 0x0024), two(0xF1C0, 0xE07F), "IiFt", mfloat },
+
+{"fsglmulb", two(0xF000, 0x5827), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat },
+{"fsglmuld", two(0xF000, 0x5427), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat },
+{"fsglmull", two(0xF000, 0x4027), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat },
+{"fsglmulp", two(0xF000, 0x4C27), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat },
+{"fsglmuls", two(0xF000, 0x4427), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat },
+{"fsglmulw", two(0xF000, 0x5027), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat },
+{"fsglmulx", two(0xF000, 0x0027), two(0xF1C0, 0xE07F), "IiF8F7", mfloat },
+{"fsglmulx", two(0xF000, 0x4827), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat },
+{"fsglmulx", two(0xF000, 0x0027), two(0xF1C0, 0xE07F), "IiFt", mfloat },
+
+{"fsinb", two(0xF000, 0x580E), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat },
+{"fsind", two(0xF000, 0x540E), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat },
+{"fsinl", two(0xF000, 0x400E), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat },
+{"fsinp", two(0xF000, 0x4C0E), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat },
+{"fsins", two(0xF000, 0x440E), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat },
+{"fsinw", two(0xF000, 0x500E), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat },
+{"fsinx", two(0xF000, 0x000E), two(0xF1C0, 0xE07F), "IiF8F7", mfloat },
+{"fsinx", two(0xF000, 0x480E), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat },
+{"fsinx", two(0xF000, 0x000E), two(0xF1C0, 0xE07F), "IiFt", mfloat },
+
+{"fsinhb", two(0xF000, 0x5802), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat },
+{"fsinhd", two(0xF000, 0x5402), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat },
+{"fsinhl", two(0xF000, 0x4002), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat },
+{"fsinhp", two(0xF000, 0x4C02), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat },
+{"fsinhs", two(0xF000, 0x4402), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat },
+{"fsinhw", two(0xF000, 0x5002), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat },
+{"fsinhx", two(0xF000, 0x0002), two(0xF1C0, 0xE07F), "IiF8F7", mfloat },
+{"fsinhx", two(0xF000, 0x4802), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat },
+{"fsinhx", two(0xF000, 0x0002), two(0xF1C0, 0xE07F), "IiFt", mfloat },
+
+{"fsincosb", two(0xF000, 0x5830), two(0xF1C0, 0xFC78), "Ii;bF3F7", mfloat },
+{"fsincosd", two(0xF000, 0x5430), two(0xF1C0, 0xFC78), "Ii;FF3F7", mfloat },
+{"fsincosl", two(0xF000, 0x4030), two(0xF1C0, 0xFC78), "Ii;lF3F7", mfloat },
+{"fsincosp", two(0xF000, 0x4C30), two(0xF1C0, 0xFC78), "Ii;pF3F7", mfloat },
+{"fsincoss", two(0xF000, 0x4430), two(0xF1C0, 0xFC78), "Ii;fF3F7", mfloat },
+{"fsincosw", two(0xF000, 0x5030), two(0xF1C0, 0xFC78), "Ii;wF3F7", mfloat },
+{"fsincosx", two(0xF000, 0x0030), two(0xF1C0, 0xE078), "IiF8F3F7", mfloat },
+{"fsincosx", two(0xF000, 0x4830), two(0xF1C0, 0xFC78), "Ii;xF3F7", mfloat },
+
+{"fsqrtb", two(0xF000, 0x5804), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat },
+{"fsqrtd", two(0xF000, 0x5404), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat },
+{"fsqrtl", two(0xF000, 0x4004), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat },
+{"fsqrtp", two(0xF000, 0x4C04), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat },
+{"fsqrts", two(0xF000, 0x4404), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat },
+{"fsqrtw", two(0xF000, 0x5004), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat },
+{"fsqrtx", two(0xF000, 0x0004), two(0xF1C0, 0xE07F), "IiF8F7", mfloat },
+{"fsqrtx", two(0xF000, 0x4804), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat },
+{"fsqrtx", two(0xF000, 0x0004), two(0xF1C0, 0xE07F), "IiFt", mfloat },
+
+{"fssqrtb", two(0xF000, 0x5841), two(0xF1C0, 0xFC7F), "Ii;bF7", m68040 },
+{"fssqrtd", two(0xF000, 0x5441), two(0xF1C0, 0xFC7F), "Ii;FF7", m68040 },
+{"fssqrtl", two(0xF000, 0x4041), two(0xF1C0, 0xFC7F), "Ii;lF7", m68040 },
+{"fssqrtp", two(0xF000, 0x4C41), two(0xF1C0, 0xFC7F), "Ii;pF7", m68040 },
+{"fssqrts", two(0xF000, 0x4441), two(0xF1C0, 0xFC7F), "Ii;fF7", m68040 },
+{"fssqrtw", two(0xF000, 0x5041), two(0xF1C0, 0xFC7F), "Ii;wF7", m68040 },
+{"fssqrtx", two(0xF000, 0x0041), two(0xF1C0, 0xE07F), "IiF8F7", m68040 },
+{"fssqrtx", two(0xF000, 0x4841), two(0xF1C0, 0xFC7F), "Ii;xF7", m68040 },
+{"fssqrtx", two(0xF000, 0x0041), two(0xF1C0, 0xE07F), "IiFt", m68040 },
+
+{"fdsqrtb", two(0xF000, 0x5845), two(0xF1C0, 0xFC7F), "Ii;bF7", m68040 },
+{"fdsqrtd", two(0xF000, 0x5445), two(0xF1C0, 0xFC7F), "Ii;FF7", m68040 },
+{"fdsqrtl", two(0xF000, 0x4045), two(0xF1C0, 0xFC7F), "Ii;lF7", m68040 },
+{"fdsqrtp", two(0xF000, 0x4C45), two(0xF1C0, 0xFC7F), "Ii;pF7", m68040 },
+{"fdsqrts", two(0xF000, 0x4445), two(0xF1C0, 0xFC7F), "Ii;fF7", m68040 },
+{"fdsqrtw", two(0xF000, 0x5045), two(0xF1C0, 0xFC7F), "Ii;wF7", m68040 },
+{"fdsqrtx", two(0xF000, 0x0045), two(0xF1C0, 0xE07F), "IiF8F7", m68040 },
+{"fdsqrtx", two(0xF000, 0x4845), two(0xF1C0, 0xFC7F), "Ii;xF7", m68040 },
+{"fdsqrtx", two(0xF000, 0x0045), two(0xF1C0, 0xE07F), "IiFt", m68040 },
+
+{"fsubb", two(0xF000, 0x5828), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat },
+{"fsubd", two(0xF000, 0x5428), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat },
+{"fsubl", two(0xF000, 0x4028), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat },
+{"fsubp", two(0xF000, 0x4C28), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat },
+{"fsubs", two(0xF000, 0x4428), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat },
+{"fsubw", two(0xF000, 0x5028), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat },
+{"fsubx", two(0xF000, 0x0028), two(0xF1C0, 0xE07F), "IiF8F7", mfloat },
+{"fsubx", two(0xF000, 0x4828), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat },
+{"fsubx", two(0xF000, 0x0028), two(0xF1C0, 0xE07F), "IiFt", mfloat },
+
+{"fssubb", two(0xF000, 0x5838), two(0xF1C0, 0xFC7F), "Ii;bF7", m68040 },
+{"fssubd", two(0xF000, 0x5438), two(0xF1C0, 0xFC7F), "Ii;FF7", m68040 },
+{"fssubl", two(0xF000, 0x4038), two(0xF1C0, 0xFC7F), "Ii;lF7", m68040 },
+{"fssubp", two(0xF000, 0x4C38), two(0xF1C0, 0xFC7F), "Ii;pF7", m68040 },
+{"fssubs", two(0xF000, 0x4438), two(0xF1C0, 0xFC7F), "Ii;fF7", m68040 },
+{"fssubw", two(0xF000, 0x5038), two(0xF1C0, 0xFC7F), "Ii;wF7", m68040 },
+{"fssubx", two(0xF000, 0x0038), two(0xF1C0, 0xE07F), "IiF8F7", m68040 },
+{"fssubx", two(0xF000, 0x4838), two(0xF1C0, 0xFC7F), "Ii;xF7", m68040 },
+{"fssubx", two(0xF000, 0x0038), two(0xF1C0, 0xE07F), "IiFt", m68040 },
+
+{"fdsubb", two(0xF000, 0x583c), two(0xF1C0, 0xFC7F), "Ii;bF7", m68040 },
+{"fdsubd", two(0xF000, 0x543c), two(0xF1C0, 0xFC7F), "Ii;FF7", m68040 },
+{"fdsubl", two(0xF000, 0x403c), two(0xF1C0, 0xFC7F), "Ii;lF7", m68040 },
+{"fdsubp", two(0xF000, 0x4C3c), two(0xF1C0, 0xFC7F), "Ii;pF7", m68040 },
+{"fdsubs", two(0xF000, 0x443c), two(0xF1C0, 0xFC7F), "Ii;fF7", m68040 },
+{"fdsubw", two(0xF000, 0x503c), two(0xF1C0, 0xFC7F), "Ii;wF7", m68040 },
+{"fdsubx", two(0xF000, 0x003c), two(0xF1C0, 0xE07F), "IiF8F7", m68040 },
+{"fdsubx", two(0xF000, 0x483c), two(0xF1C0, 0xFC7F), "Ii;xF7", m68040 },
+{"fdsubx", two(0xF000, 0x003c), two(0xF1C0, 0xE07F), "IiFt", m68040 },
+
+{"ftanb", two(0xF000, 0x580F), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat },
+{"ftand", two(0xF000, 0x540F), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat },
+{"ftanl", two(0xF000, 0x400F), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat },
+{"ftanp", two(0xF000, 0x4C0F), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat },
+{"ftans", two(0xF000, 0x440F), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat },
+{"ftanw", two(0xF000, 0x500F), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat },
+{"ftanx", two(0xF000, 0x000F), two(0xF1C0, 0xE07F), "IiF8F7", mfloat },
+{"ftanx", two(0xF000, 0x480F), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat },
+{"ftanx", two(0xF000, 0x000F), two(0xF1C0, 0xE07F), "IiFt", mfloat },
+
+{"ftanhb", two(0xF000, 0x5809), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat },
+{"ftanhd", two(0xF000, 0x5409), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat },
+{"ftanhl", two(0xF000, 0x4009), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat },
+{"ftanhp", two(0xF000, 0x4C09), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat },
+{"ftanhs", two(0xF000, 0x4409), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat },
+{"ftanhw", two(0xF000, 0x5009), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat },
+{"ftanhx", two(0xF000, 0x0009), two(0xF1C0, 0xE07F), "IiF8F7", mfloat },
+{"ftanhx", two(0xF000, 0x4809), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat },
+{"ftanhx", two(0xF000, 0x0009), two(0xF1C0, 0xE07F), "IiFt", mfloat },
+
+{"ftentoxb", two(0xF000, 0x5812), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat },
+{"ftentoxd", two(0xF000, 0x5412), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat },
+{"ftentoxl", two(0xF000, 0x4012), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat },
+{"ftentoxp", two(0xF000, 0x4C12), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat },
+{"ftentoxs", two(0xF000, 0x4412), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat },
+{"ftentoxw", two(0xF000, 0x5012), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat },
+{"ftentoxx", two(0xF000, 0x0012), two(0xF1C0, 0xE07F), "IiF8F7", mfloat },
+{"ftentoxx", two(0xF000, 0x4812), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat },
+{"ftentoxx", two(0xF000, 0x0012), two(0xF1C0, 0xE07F), "IiFt", mfloat },
+
+{"ftrapeq", two(0xF07C, 0x0001), two(0xF1FF, 0xFFFF), "Ii", mfloat },
+{"ftrapf", two(0xF07C, 0x0000), two(0xF1FF, 0xFFFF), "Ii", mfloat },
+{"ftrapge", two(0xF07C, 0x0013), two(0xF1FF, 0xFFFF), "Ii", mfloat },
+{"ftrapgl", two(0xF07C, 0x0016), two(0xF1FF, 0xFFFF), "Ii", mfloat },
+{"ftrapgle", two(0xF07C, 0x0017), two(0xF1FF, 0xFFFF), "Ii", mfloat },
+{"ftrapgt", two(0xF07C, 0x0012), two(0xF1FF, 0xFFFF), "Ii", mfloat },
+{"ftraple", two(0xF07C, 0x0015), two(0xF1FF, 0xFFFF), "Ii", mfloat },
+{"ftraplt", two(0xF07C, 0x0014), two(0xF1FF, 0xFFFF), "Ii", mfloat },
+{"ftrapne", two(0xF07C, 0x000E), two(0xF1FF, 0xFFFF), "Ii", mfloat },
+{"ftrapnge", two(0xF07C, 0x001C), two(0xF1FF, 0xFFFF), "Ii", mfloat },
+{"ftrapngl", two(0xF07C, 0x0019), two(0xF1FF, 0xFFFF), "Ii", mfloat },
+{"ftrapngle", two(0xF07C, 0x0018), two(0xF1FF, 0xFFFF), "Ii", mfloat },
+{"ftrapngt", two(0xF07C, 0x001D), two(0xF1FF, 0xFFFF), "Ii", mfloat },
+{"ftrapnle", two(0xF07C, 0x001A), two(0xF1FF, 0xFFFF), "Ii", mfloat },
+{"ftrapnlt", two(0xF07C, 0x001B), two(0xF1FF, 0xFFFF), "Ii", mfloat },
+{"ftrapoge", two(0xF07C, 0x0003), two(0xF1FF, 0xFFFF), "Ii", mfloat },
+{"ftrapogl", two(0xF07C, 0x0006), two(0xF1FF, 0xFFFF), "Ii", mfloat },
+{"ftrapogt", two(0xF07C, 0x0002), two(0xF1FF, 0xFFFF), "Ii", mfloat },
+{"ftrapole", two(0xF07C, 0x0005), two(0xF1FF, 0xFFFF), "Ii", mfloat },
+{"ftrapolt", two(0xF07C, 0x0004), two(0xF1FF, 0xFFFF), "Ii", mfloat },
+{"ftrapor", two(0xF07C, 0x0007), two(0xF1FF, 0xFFFF), "Ii", mfloat },
+{"ftrapseq", two(0xF07C, 0x0011), two(0xF1FF, 0xFFFF), "Ii", mfloat },
+{"ftrapsf", two(0xF07C, 0x0010), two(0xF1FF, 0xFFFF), "Ii", mfloat },
+{"ftrapsne", two(0xF07C, 0x001E), two(0xF1FF, 0xFFFF), "Ii", mfloat },
+{"ftrapst", two(0xF07C, 0x001F), two(0xF1FF, 0xFFFF), "Ii", mfloat },
+{"ftrapt", two(0xF07C, 0x000F), two(0xF1FF, 0xFFFF), "Ii", mfloat },
+{"ftrapueq", two(0xF07C, 0x0009), two(0xF1FF, 0xFFFF), "Ii", mfloat },
+{"ftrapuge", two(0xF07C, 0x000B), two(0xF1FF, 0xFFFF), "Ii", mfloat },
+{"ftrapugt", two(0xF07C, 0x000A), two(0xF1FF, 0xFFFF), "Ii", mfloat },
+{"ftrapule", two(0xF07C, 0x000D), two(0xF1FF, 0xFFFF), "Ii", mfloat },
+{"ftrapult", two(0xF07C, 0x000C), two(0xF1FF, 0xFFFF), "Ii", mfloat },
+{"ftrapun", two(0xF07C, 0x0008), two(0xF1FF, 0xFFFF), "Ii", mfloat },
+
+{"ftrapeqw", two(0xF07A, 0x0001), two(0xF1FF, 0xFFFF), "Ii^w", mfloat },
+{"ftrapfw", two(0xF07A, 0x0000), two(0xF1FF, 0xFFFF), "Ii^w", mfloat },
+{"ftrapgew", two(0xF07A, 0x0013), two(0xF1FF, 0xFFFF), "Ii^w", mfloat },
+{"ftrapglw", two(0xF07A, 0x0016), two(0xF1FF, 0xFFFF), "Ii^w", mfloat },
+{"ftrapglew", two(0xF07A, 0x0017), two(0xF1FF, 0xFFFF), "Ii^w", mfloat },
+{"ftrapgtw", two(0xF07A, 0x0012), two(0xF1FF, 0xFFFF), "Ii^w", mfloat },
+{"ftraplew", two(0xF07A, 0x0015), two(0xF1FF, 0xFFFF), "Ii^w", mfloat },
+{"ftrapltw", two(0xF07A, 0x0014), two(0xF1FF, 0xFFFF), "Ii^w", mfloat },
+{"ftrapnew", two(0xF07A, 0x000E), two(0xF1FF, 0xFFFF), "Ii^w", mfloat },
+{"ftrapngew", two(0xF07A, 0x001C), two(0xF1FF, 0xFFFF), "Ii^w", mfloat },
+{"ftrapnglw", two(0xF07A, 0x0019), two(0xF1FF, 0xFFFF), "Ii^w", mfloat },
+{"ftrapnglew", two(0xF07A, 0x0018), two(0xF1FF, 0xFFFF), "Ii^w", mfloat },
+{"ftrapngtw", two(0xF07A, 0x001D), two(0xF1FF, 0xFFFF), "Ii^w", mfloat },
+{"ftrapnlew", two(0xF07A, 0x001A), two(0xF1FF, 0xFFFF), "Ii^w", mfloat },
+{"ftrapnltw", two(0xF07A, 0x001B), two(0xF1FF, 0xFFFF), "Ii^w", mfloat },
+{"ftrapogew", two(0xF07A, 0x0003), two(0xF1FF, 0xFFFF), "Ii^w", mfloat },
+{"ftrapoglw", two(0xF07A, 0x0006), two(0xF1FF, 0xFFFF), "Ii^w", mfloat },
+{"ftrapogtw", two(0xF07A, 0x0002), two(0xF1FF, 0xFFFF), "Ii^w", mfloat },
+{"ftrapolew", two(0xF07A, 0x0005), two(0xF1FF, 0xFFFF), "Ii^w", mfloat },
+{"ftrapoltw", two(0xF07A, 0x0004), two(0xF1FF, 0xFFFF), "Ii^w", mfloat },
+{"ftraporw", two(0xF07A, 0x0007), two(0xF1FF, 0xFFFF), "Ii^w", mfloat },
+{"ftrapseqw", two(0xF07A, 0x0011), two(0xF1FF, 0xFFFF), "Ii^w", mfloat },
+{"ftrapsfw", two(0xF07A, 0x0010), two(0xF1FF, 0xFFFF), "Ii^w", mfloat },
+{"ftrapsnew", two(0xF07A, 0x001E), two(0xF1FF, 0xFFFF), "Ii^w", mfloat },
+{"ftrapstw", two(0xF07A, 0x001F), two(0xF1FF, 0xFFFF), "Ii^w", mfloat },
+{"ftraptw", two(0xF07A, 0x000F), two(0xF1FF, 0xFFFF), "Ii^w", mfloat },
+{"ftrapueqw", two(0xF07A, 0x0009), two(0xF1FF, 0xFFFF), "Ii^w", mfloat },
+{"ftrapugew", two(0xF07A, 0x000B), two(0xF1FF, 0xFFFF), "Ii^w", mfloat },
+{"ftrapugtw", two(0xF07A, 0x000A), two(0xF1FF, 0xFFFF), "Ii^w", mfloat },
+{"ftrapulew", two(0xF07A, 0x000D), two(0xF1FF, 0xFFFF), "Ii^w", mfloat },
+{"ftrapultw", two(0xF07A, 0x000C), two(0xF1FF, 0xFFFF), "Ii^w", mfloat },
+{"ftrapunw", two(0xF07A, 0x0008), two(0xF1FF, 0xFFFF), "Ii^w", mfloat },
+
+{"ftrapeql", two(0xF07B, 0x0001), two(0xF1FF, 0xFFFF), "Ii^l", mfloat },
+{"ftrapfl", two(0xF07B, 0x0000), two(0xF1FF, 0xFFFF), "Ii^l", mfloat },
+{"ftrapgel", two(0xF07B, 0x0013), two(0xF1FF, 0xFFFF), "Ii^l", mfloat },
+{"ftrapgll", two(0xF07B, 0x0016), two(0xF1FF, 0xFFFF), "Ii^l", mfloat },
+{"ftrapglel", two(0xF07B, 0x0017), two(0xF1FF, 0xFFFF), "Ii^l", mfloat },
+{"ftrapgtl", two(0xF07B, 0x0012), two(0xF1FF, 0xFFFF), "Ii^l", mfloat },
+{"ftraplel", two(0xF07B, 0x0015), two(0xF1FF, 0xFFFF), "Ii^l", mfloat },
+{"ftrapltl", two(0xF07B, 0x0014), two(0xF1FF, 0xFFFF), "Ii^l", mfloat },
+{"ftrapnel", two(0xF07B, 0x000E), two(0xF1FF, 0xFFFF), "Ii^l", mfloat },
+{"ftrapngel", two(0xF07B, 0x001C), two(0xF1FF, 0xFFFF), "Ii^l", mfloat },
+{"ftrapngll", two(0xF07B, 0x0019), two(0xF1FF, 0xFFFF), "Ii^l", mfloat },
+{"ftrapnglel", two(0xF07B, 0x0018), two(0xF1FF, 0xFFFF), "Ii^l", mfloat },
+{"ftrapngtl", two(0xF07B, 0x001D), two(0xF1FF, 0xFFFF), "Ii^l", mfloat },
+{"ftrapnlel", two(0xF07B, 0x001A), two(0xF1FF, 0xFFFF), "Ii^l", mfloat },
+{"ftrapnltl", two(0xF07B, 0x001B), two(0xF1FF, 0xFFFF), "Ii^l", mfloat },
+{"ftrapogel", two(0xF07B, 0x0003), two(0xF1FF, 0xFFFF), "Ii^l", mfloat },
+{"ftrapogll", two(0xF07B, 0x0006), two(0xF1FF, 0xFFFF), "Ii^l", mfloat },
+{"ftrapogtl", two(0xF07B, 0x0002), two(0xF1FF, 0xFFFF), "Ii^l", mfloat },
+{"ftrapolel", two(0xF07B, 0x0005), two(0xF1FF, 0xFFFF), "Ii^l", mfloat },
+{"ftrapoltl", two(0xF07B, 0x0004), two(0xF1FF, 0xFFFF), "Ii^l", mfloat },
+{"ftraporl", two(0xF07B, 0x0007), two(0xF1FF, 0xFFFF), "Ii^l", mfloat },
+{"ftrapseql", two(0xF07B, 0x0011), two(0xF1FF, 0xFFFF), "Ii^l", mfloat },
+{"ftrapsfl", two(0xF07B, 0x0010), two(0xF1FF, 0xFFFF), "Ii^l", mfloat },
+{"ftrapsnel", two(0xF07B, 0x001E), two(0xF1FF, 0xFFFF), "Ii^l", mfloat },
+{"ftrapstl", two(0xF07B, 0x001F), two(0xF1FF, 0xFFFF), "Ii^l", mfloat },
+{"ftraptl", two(0xF07B, 0x000F), two(0xF1FF, 0xFFFF), "Ii^l", mfloat },
+{"ftrapueql", two(0xF07B, 0x0009), two(0xF1FF, 0xFFFF), "Ii^l", mfloat },
+{"ftrapugel", two(0xF07B, 0x000B), two(0xF1FF, 0xFFFF), "Ii^l", mfloat },
+{"ftrapugtl", two(0xF07B, 0x000A), two(0xF1FF, 0xFFFF), "Ii^l", mfloat },
+{"ftrapulel", two(0xF07B, 0x000D), two(0xF1FF, 0xFFFF), "Ii^l", mfloat },
+{"ftrapultl", two(0xF07B, 0x000C), two(0xF1FF, 0xFFFF), "Ii^l", mfloat },
+{"ftrapunl", two(0xF07B, 0x0008), two(0xF1FF, 0xFFFF), "Ii^l", mfloat },
+
+{"ftstb", two(0xF000, 0x583A), two(0xF1C0, 0xFC7F), "Ii;b", mfloat },
+{"ftstd", two(0xF000, 0x543A), two(0xF1C0, 0xFC7F), "Ii;F", mfloat },
+{"ftstl", two(0xF000, 0x403A), two(0xF1C0, 0xFC7F), "Ii;l", mfloat },
+{"ftstp", two(0xF000, 0x4C3A), two(0xF1C0, 0xFC7F), "Ii;p", mfloat },
+{"ftsts", two(0xF000, 0x443A), two(0xF1C0, 0xFC7F), "Ii;f", mfloat },
+{"ftstw", two(0xF000, 0x503A), two(0xF1C0, 0xFC7F), "Ii;w", mfloat },
+{"ftstx", two(0xF000, 0x003A), two(0xF1C0, 0xE07F), "IiF8", mfloat },
+{"ftstx", two(0xF000, 0x483A), two(0xF1C0, 0xFC7F), "Ii;x", mfloat },
+
+{"ftwotoxb", two(0xF000, 0x5811), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat },
+{"ftwotoxd", two(0xF000, 0x5411), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat },
+{"ftwotoxl", two(0xF000, 0x4011), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat },
+{"ftwotoxp", two(0xF000, 0x4C11), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat },
+{"ftwotoxs", two(0xF000, 0x4411), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat },
+{"ftwotoxw", two(0xF000, 0x5011), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat },
+{"ftwotoxx", two(0xF000, 0x0011), two(0xF1C0, 0xE07F), "IiF8F7", mfloat },
+{"ftwotoxx", two(0xF000, 0x4811), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat },
+{"ftwotoxx", two(0xF000, 0x0011), two(0xF1C0, 0xE07F), "IiFt", mfloat },
+
+/* Variable-sized float branches */
+
+{"fjeq", one(0xF081), one(0xF1FF), "IdBc", mfloat },
+{"fjf", one(0xF080), one(0xF1FF), "IdBc", mfloat },
+{"fjge", one(0xF093), one(0xF1FF), "IdBc", mfloat },
+{"fjgl", one(0xF096), one(0xF1FF), "IdBc", mfloat },
+{"fjgle", one(0xF097), one(0xF1FF), "IdBc", mfloat },
+{"fjgt", one(0xF092), one(0xF1FF), "IdBc", mfloat },
+{"fjle", one(0xF095), one(0xF1FF), "IdBc", mfloat },
+{"fjlt", one(0xF094), one(0xF1FF), "IdBc", mfloat },
+{"fjne", one(0xF08E), one(0xF1FF), "IdBc", mfloat },
+{"fjnge", one(0xF09C), one(0xF1FF), "IdBc", mfloat },
+{"fjngl", one(0xF099), one(0xF1FF), "IdBc", mfloat },
+{"fjngle", one(0xF098), one(0xF1FF), "IdBc", mfloat },
+{"fjngt", one(0xF09D), one(0xF1FF), "IdBc", mfloat },
+{"fjnle", one(0xF09A), one(0xF1FF), "IdBc", mfloat },
+{"fjnlt", one(0xF09B), one(0xF1FF), "IdBc", mfloat },
+{"fjoge", one(0xF083), one(0xF1FF), "IdBc", mfloat },
+{"fjogl", one(0xF086), one(0xF1FF), "IdBc", mfloat },
+{"fjogt", one(0xF082), one(0xF1FF), "IdBc", mfloat },
+{"fjole", one(0xF085), one(0xF1FF), "IdBc", mfloat },
+{"fjolt", one(0xF084), one(0xF1FF), "IdBc", mfloat },
+{"fjor", one(0xF087), one(0xF1FF), "IdBc", mfloat },
+{"fjseq", one(0xF091), one(0xF1FF), "IdBc", mfloat },
+{"fjsf", one(0xF090), one(0xF1FF), "IdBc", mfloat },
+{"fjsne", one(0xF09E), one(0xF1FF), "IdBc", mfloat },
+{"fjst", one(0xF09F), one(0xF1FF), "IdBc", mfloat },
+{"fjt", one(0xF08F), one(0xF1FF), "IdBc", mfloat },
+{"fjueq", one(0xF089), one(0xF1FF), "IdBc", mfloat },
+{"fjuge", one(0xF08B), one(0xF1FF), "IdBc", mfloat },
+{"fjugt", one(0xF08A), one(0xF1FF), "IdBc", mfloat },
+{"fjule", one(0xF08D), one(0xF1FF), "IdBc", mfloat },
+{"fjult", one(0xF08C), one(0xF1FF), "IdBc", mfloat },
+{"fjun", one(0xF088), one(0xF1FF), "IdBc", mfloat },
+/* float stuff ends here */
+
+{"illegal", one(0045374), one(0177777), "", m68000up },
+{"jmp", one(0047300), one(0177700), "!s", m68000up },
+{"jsr", one(0047200), one(0177700), "!s", m68000up },
+{"lea", one(0040700), one(0170700), "!sAd", m68000up },
+{"linkw", one(0047120), one(0177770), "As#w", m68000up },
+{"linkl", one(0044010), one(0177770), "As#l", m68020up },
+{"link", one(0047120), one(0177770), "As#w", m68000up },
+{"link", one(0044010), one(0177770), "As#l", m68020up },
+
+{"lslb", one(0160410), one(0170770), "QdDs", m68000up }, /* lsrb #Q, Ds */
+{"lslb", one(0160450), one(0170770), "DdDs", m68000up }, /* lsrb Dd, Ds */
+{"lslw", one(0160510), one(0170770), "QdDs", m68000up }, /* lsrb #Q, Ds */
+{"lslw", one(0160550), one(0170770), "DdDs", m68000up }, /* lsrb Dd, Ds */
+{"lslw", one(0161700), one(0177700), "~s", m68000up }, /* Shift memory */
+{"lsll", one(0160610), one(0170770), "QdDs", m68000up }, /* lsrb #Q, Ds */
+{"lsll", one(0160650), one(0170770), "DdDs", m68000up }, /* lsrb Dd, Ds */
+
+{"lsrb", one(0160010), one(0170770), "QdDs", m68000up }, /* lsrb #Q, Ds */
+{"lsrb", one(0160050), one(0170770), "DdDs", m68000up }, /* lsrb Dd, Ds */
+{"lsrl", one(0160210), one(0170770), "QdDs", m68000up }, /* lsrb #Q, Ds */
+{"lsrl", one(0160250), one(0170770), "DdDs", m68000up }, /* lsrb #Q, Ds */
+{"lsrw", one(0160110), one(0170770), "QdDs", m68000up }, /* lsrb #Q, Ds */
+{"lsrw", one(0160150), one(0170770), "DdDs", m68000up }, /* lsrb #Q, Ds */
+{"lsrw", one(0161300), one(0177700), "~s", m68000up }, /* Shift memory */
+
+{"moveal", one(0020100), one(0170700), "*lAd", m68000up },
+{"moveaw", one(0030100), one(0170700), "*wAd", m68000up },
+{"moveb", one(0010000), one(0170000), ";b$d", m68000up }, /* move */
+{"movel", one(0070000), one(0170400), "MsDd", m68000up }, /* moveq written as move */
+{"movel", one(0020000), one(0170000), "*l$d", m68000up },
+{"movel", one(0020100), one(0170700), "*lAd", m68000up },
+{"movel", one(0047140), one(0177770), "AsUd", m68000up }, /* move to USP */
+{"movel", one(0047150), one(0177770), "UdAs", m68000up }, /* move from USP */
+
+{"movec", one(0047173), one(0177777), "R1Jj", m68010up },
+{"movec", one(0047173), one(0177777), "R1#j", m68010up },
+{"movec", one(0047172), one(0177777), "JjR1", m68010up },
+{"movec", one(0047172), one(0177777), "#jR1", m68010up },
+
+/* JF added these next four for the assembler */
+{"moveml", one(0044300), one(0177700), "Lw&s", m68000up }, /* movem reg to mem. */
+{"moveml", one(0044340), one(0177770), "lw-s", m68000up }, /* movem reg to autodecrement. */
+{"moveml", one(0046300), one(0177700), "!sLw", m68000up }, /* movem mem to reg. */
+{"moveml", one(0046330), one(0177770), "+sLw", m68000up }, /* movem autoinc to reg. */
+
+{"moveml", one(0044300), one(0177700), "#w&s", m68000up }, /* movem reg to mem. */
+{"moveml", one(0044340), one(0177770), "#w-s", m68000up }, /* movem reg to autodecrement. */
+{"moveml", one(0046300), one(0177700), "!s#w", m68000up }, /* movem mem to reg. */
+{"moveml", one(0046330), one(0177770), "+s#w", m68000up }, /* movem autoinc to reg. */
+
+/* JF added these next four for the assembler */
+{"movemw", one(0044200), one(0177700), "Lw&s", m68000up }, /* movem reg to mem. */
+{"movemw", one(0044240), one(0177770), "lw-s", m68000up }, /* movem reg to autodecrement. */
+{"movemw", one(0046200), one(0177700), "!sLw", m68000up }, /* movem mem to reg. */
+{"movemw", one(0046230), one(0177770), "+sLw", m68000up }, /* movem autoinc to reg. */
+
+{"movemw", one(0044200), one(0177700), "#w&s", m68000up }, /* movem reg to mem. */
+{"movemw", one(0044240), one(0177770), "#w-s", m68000up }, /* movem reg to autodecrement. */
+{"movemw", one(0046200), one(0177700), "!s#w", m68000up }, /* movem mem to reg. */
+{"movemw", one(0046230), one(0177770), "+s#w", m68000up }, /* movem autoinc to reg. */
+
+{"movepl", one(0000510), one(0170770), "dsDd", m68000up }, /* memory to register */
+{"movepl", one(0000710), one(0170770), "Ddds", m68000up }, /* register to memory */
+{"movepw", one(0000410), one(0170770), "dsDd", m68000up }, /* memory to register */
+{"movepw", one(0000610), one(0170770), "Ddds", m68000up }, /* register to memory */
+{"moveq", one(0070000), one(0170400), "MsDd", m68000up },
+{"movew", one(0030000), one(0170000), "*w$d", m68000up },
+{"movew", one(0030100), one(0170700), "*wAd", m68000up }, /* movea, written as move */
+{"movew", one(0040300), one(0177700), "Ss$s", m68000up }, /* Move from sr */
+{"movew", one(0041300), one(0177700), "Cs$s", m68010up }, /* Move from ccr */
+{"movew", one(0042300), one(0177700), ";wCd", m68000up }, /* move to ccr */
+{"movew", one(0043300), one(0177700), ";wSd", m68000up }, /* move to sr */
+
+{"movesb", two(0007000, 0), two(0177700, 07777), "~sR1", m68010up }, /* moves from memory */
+{"movesb", two(0007000, 04000), two(0177700, 07777), "R1~s", m68010up }, /* moves to memory */
+{"movesl", two(0007200, 0), two(0177700, 07777), "~sR1", m68010up }, /* moves from memory */
+{"movesl", two(0007200, 04000), two(0177700, 07777), "R1~s", m68010up }, /* moves to memory */
+{"movesw", two(0007100, 0), two(0177700, 07777), "~sR1", m68010up }, /* moves from memory */
+{"movesw", two(0007100, 04000), two(0177700, 07777), "R1~s", m68010up }, /* moves to memory */
+
+{"move16", two(0xf620, 0x8000), two(0xfff8, 0x8fff), "+s+1", m68040 },
+{"move16", one(0xf600), one(0xfff8), "+s_L", m68040 },
+{"move16", one(0xf608), one(0xfff8), "_L+s", m68040 },
+{"move16", one(0xf610), one(0xfff8), "as_L", m68040 },
+{"move16", one(0xf618), one(0xfff8), "_Las", m68040 },
+
+{"mulsl", two(0046000, 004000), two(0177700, 0107770), ";lD1", m68020up },
+{"mulsl", two(0046000, 006000), two(0177700, 0107770), ";lD3D1", m68020up },
+{"mulsw", one(0140700), one(0170700), ";wDd", m68000up },
+{"muls", one(0140700), one(0170700), ";wDd", m68000up },
+{"mulul", two(0046000, 000000), two(0177700, 0107770), ";lD1", m68020up },
+{"mulul", two(0046000, 002000), two(0177700, 0107770), ";lD3D1", m68020up },
+{"muluw", one(0140300), one(0170700), ";wDd", m68000up },
+{"mulu", one(0140300), one(0170700), ";wDd", m68000up },
+{"nbcd", one(0044000), one(0177700), "$s", m68000up },
+{"negb", one(0042000), one(0177700), "$s", m68000up },
+{"negl", one(0042200), one(0177700), "$s", m68000up },
+{"negw", one(0042100), one(0177700), "$s", m68000up },
+{"negxb", one(0040000), one(0177700), "$s", m68000up },
+{"negxl", one(0040200), one(0177700), "$s", m68000up },
+{"negxw", one(0040100), one(0177700), "$s", m68000up },
+{"nop", one(0047161), one(0177777), "", m68000up },
+{"notb", one(0043000), one(0177700), "$s", m68000up },
+{"notl", one(0043200), one(0177700), "$s", m68000up },
+{"notw", one(0043100), one(0177700), "$s", m68000up },
+
+{"orb", one(0000000), one(0177700), "#b$s", m68000up }, /* ori written as or */
+{"orb", one(0000074), one(0177777), "#bCs", m68000up }, /* ori to ccr */
+{"orb", one(0100000), one(0170700), ";bDd", m68000up }, /* memory to register */
+{"orb", one(0100400), one(0170700), "Dd~s", m68000up }, /* register to memory */
+{"orib", one(0000000), one(0177700), "#b$s", m68000up },
+{"orib", one(0000074), one(0177777), "#bCs", m68000up }, /* ori to ccr */
+{"oril", one(0000200), one(0177700), "#l$s", m68000up },
+{"oriw", one(0000100), one(0177700), "#w$s", m68000up },
+{"oriw", one(0000174), one(0177777), "#wSs", m68000up }, /* ori to sr */
+{"orl", one(0000200), one(0177700), "#l$s", m68000up },
+{"orl", one(0100200), one(0170700), ";lDd", m68000up }, /* memory to register */
+{"orl", one(0100600), one(0170700), "Dd~s", m68000up }, /* register to memory */
+{"orw", one(0000100), one(0177700), "#w$s", m68000up },
+{"orw", one(0000174), one(0177777), "#wSs", m68000up }, /* ori to sr */
+{"orw", one(0100100), one(0170700), ";wDd", m68000up }, /* memory to register */
+{"orw", one(0100500), one(0170700), "Dd~s", m68000up }, /* register to memory */
+
+{"pack", one(0100500), one(0170770), "DsDd#w", m68020up }, /* pack Ds, Dd, #w */
+{"pack", one(0100510), one(0170770), "-s-d#w", m68020up }, /* pack -(As), -(Ad), #w */
+
+#ifndef NO_68851
+{"pbac", one(0xf0c7), one(0xffbf), "Bc", m68851 },
+{"pbacw", one(0xf087), one(0xffbf), "Bc", m68851 },
+{"pbas", one(0xf0c6), one(0xffbf), "Bc", m68851 },
+{"pbasw", one(0xf086), one(0xffbf), "Bc", m68851 },
+{"pbbc", one(0xf0c1), one(0xffbf), "Bc", m68851 },
+{"pbbcw", one(0xf081), one(0xffbf), "Bc", m68851 },
+{"pbbs", one(0xf0c0), one(0xffbf), "Bc", m68851 },
+{"pbbsw", one(0xf080), one(0xffbf), "Bc", m68851 },
+{"pbcc", one(0xf0cf), one(0xffbf), "Bc", m68851 },
+{"pbccw", one(0xf08f), one(0xffbf), "Bc", m68851 },
+{"pbcs", one(0xf0ce), one(0xffbf), "Bc", m68851 },
+{"pbcsw", one(0xf08e), one(0xffbf), "Bc", m68851 },
+{"pbgc", one(0xf0cd), one(0xffbf), "Bc", m68851 },
+{"pbgcw", one(0xf08d), one(0xffbf), "Bc", m68851 },
+{"pbgs", one(0xf0cc), one(0xffbf), "Bc", m68851 },
+{"pbgsw", one(0xf08c), one(0xffbf), "Bc", m68851 },
+{"pbic", one(0xf0cb), one(0xffbf), "Bc", m68851 },
+{"pbicw", one(0xf08b), one(0xffbf), "Bc", m68851 },
+{"pbis", one(0xf0ca), one(0xffbf), "Bc", m68851 },
+{"pbisw", one(0xf08a), one(0xffbf), "Bc", m68851 },
+{"pblc", one(0xf0c3), one(0xffbf), "Bc", m68851 },
+{"pblcw", one(0xf083), one(0xffbf), "Bc", m68851 },
+{"pbls", one(0xf0c2), one(0xffbf), "Bc", m68851 },
+{"pblsw", one(0xf082), one(0xffbf), "Bc", m68851 },
+{"pbsc", one(0xf0c5), one(0xffbf), "Bc", m68851 },
+{"pbscw", one(0xf085), one(0xffbf), "Bc", m68851 },
+{"pbss", one(0xf0c4), one(0xffbf), "Bc", m68851 },
+{"pbssw", one(0xf084), one(0xffbf), "Bc", m68851 },
+{"pbwc", one(0xf0c9), one(0xffbf), "Bc", m68851 },
+{"pbwcw", one(0xf089), one(0xffbf), "Bc", m68851 },
+{"pbws", one(0xf0c8), one(0xffbf), "Bc", m68851 },
+{"pbwsw", one(0xf088), one(0xffbf), "Bc", m68851 },
+
+{"pdbac", two(0xf048, 0x0007), two(0xfff8, 0xffff), "DsBw", m68851 },
+{"pdbas", two(0xf048, 0x0006), two(0xfff8, 0xffff), "DsBw", m68851 },
+{"pdbbc", two(0xf048, 0x0001), two(0xfff8, 0xffff), "DsBw", m68851 },
+{"pdbbs", two(0xf048, 0x0000), two(0xfff8, 0xffff), "DsBw", m68851 },
+{"pdbcc", two(0xf048, 0x000f), two(0xfff8, 0xffff), "DsBw", m68851 },
+{"pdbcs", two(0xf048, 0x000e), two(0xfff8, 0xffff), "DsBw", m68851 },
+{"pdbgc", two(0xf048, 0x000d), two(0xfff8, 0xffff), "DsBw", m68851 },
+{"pdbgs", two(0xf048, 0x000c), two(0xfff8, 0xffff), "DsBw", m68851 },
+{"pdbic", two(0xf048, 0x000b), two(0xfff8, 0xffff), "DsBw", m68851 },
+{"pdbis", two(0xf048, 0x000a), two(0xfff8, 0xffff), "DsBw", m68851 },
+{"pdblc", two(0xf048, 0x0003), two(0xfff8, 0xffff), "DsBw", m68851 },
+{"pdbls", two(0xf048, 0x0002), two(0xfff8, 0xffff), "DsBw", m68851 },
+{"pdbsc", two(0xf048, 0x0005), two(0xfff8, 0xffff), "DsBw", m68851 },
+{"pdbss", two(0xf048, 0x0004), two(0xfff8, 0xffff), "DsBw", m68851 },
+{"pdbwc", two(0xf048, 0x0009), two(0xfff8, 0xffff), "DsBw", m68851 },
+{"pdbws", two(0xf048, 0x0008), two(0xfff8, 0xffff), "DsBw", m68851 },
+#endif /* NO_68851 */
+
+{"pea", one(0044100), one(0177700), "!s", m68000up },
+
+#ifndef NO_68851
+{"pflusha", two(0xf000, 0x2400), two(0xffff, 0xffff), "", m68030 | m68851 },
+{"pflusha", one(0xf510), one(0xfff8), "", m68040 },
+
+{"pflush", two(0xf000, 0x3010), two(0xffc0, 0xfe10), "T3T9", m68030 | m68851 },
+{"pflush", two(0xf000, 0x3810), two(0xffc0, 0xfe10), "T3T9&s", m68030 | m68851 },
+{"pflush", two(0xf000, 0x3008), two(0xffc0, 0xfe18), "D3T9", m68030 | m68851 },
+{"pflush", two(0xf000, 0x3808), two(0xffc0, 0xfe18), "D3T9&s", m68030 | m68851 },
+{"pflush", two(0xf000, 0x3000), two(0xffc0, 0xfe1e), "f3T9", m68030 | m68851 },
+{"pflush", two(0xf000, 0x3800), two(0xffc0, 0xfe1e), "f3T9&s", m68030 | m68851 },
+{"pflush", one(0xf500), one(0xfff8), "As", m68040 },
+
+{"pflushan", one(0xf518), one(0xfff8), "", m68040 },
+{"pflushn", one(0xf508), one(0xfff8), "As", m68040 },
+
+{"pflushr", two(0xf000, 0xa000), two(0xffc0, 0xffff), "|s", m68851 },
+
+{"pflushs", two(0xf000, 0x3410), two(0xfff8, 0xfe10), "T3T9", m68851 },
+{"pflushs", two(0xf000, 0x3c10), two(0xfff8, 0xfe00), "T3T9&s", m68851 },
+{"pflushs", two(0xf000, 0x3408), two(0xfff8, 0xfe18), "D3T9", m68851 },
+{"pflushs", two(0xf000, 0x3c08), two(0xfff8, 0xfe18), "D3T9&s", m68851 },
+{"pflushs", two(0xf000, 0x3400), two(0xfff8, 0xfe1e), "f3T9", m68851 },
+{"pflushs", two(0xf000, 0x3c00), two(0xfff8, 0xfe1e), "f3T9&s", m68851 },
+
+{"ploadr", two(0xf000, 0x2210), two(0xffc0, 0xfff0), "T3&s", m68030 | m68851 },
+{"ploadr", two(0xf000, 0x2208), two(0xffc0, 0xfff8), "D3&s", m68030 | m68851 },
+{"ploadr", two(0xf000, 0x2200), two(0xffc0, 0xfffe), "f3&s", m68030 | m68851 },
+{"ploadw", two(0xf000, 0x2010), two(0xffc0, 0xfff0), "T3&s", m68030 | m68851 },
+{"ploadw", two(0xf000, 0x2008), two(0xffc0, 0xfff8), "D3&s", m68030 | m68851 },
+{"ploadw", two(0xf000, 0x2000), two(0xffc0, 0xfffe), "f3&s", m68030 | m68851 },
+
+/* TC, CRP, DRP, SRP, CAL, VAL, SCC, AC */
+{"pmove", two(0xf000, 0x4000), two(0xffc0, 0xe3ff), "*sP8", m68030 | m68851 },
+{"pmove", two(0xf000, 0x4200), two(0xffc0, 0xe3ff), "P8%s", m68030 | m68851 },
+{"pmove", two(0xf000, 0x4000), two(0xffc0, 0xe3ff), "|sW8", m68030 | m68851 },
+{"pmove", two(0xf000, 0x4200), two(0xffc0, 0xe3ff), "W8~s", m68030 | m68851 },
+
+/* BADx, BACx */
+{"pmove", two(0xf000, 0x6200), two(0xffc0, 0xe3e3), "*sX3", m68030 | m68851 },
+{"pmove", two(0xf000, 0x6000), two(0xffc0, 0xe3e3), "X3%s", m68030 | m68851 },
+
+/* PSR, PCSR */
+/* {"pmove", two(0xf000, 0x6100), two(oxffc0, oxffff), "*sZ8", m68030 | m68851 }, */
+{"pmove", two(0xf000, 0x6000), two(0xffc0, 0xffff), "*sY8", m68030 | m68851 },
+{"pmove", two(0xf000, 0x6200), two(0xffc0, 0xffff), "Y8%s", m68030 | m68851 },
+{"pmove", two(0xf000, 0x6600), two(0xffc0, 0xffff), "Z8%s", m68030 | m68851 },
+
+{"prestore", one(0xf140), one(0xffc0), "&s", m68851 },
+{"prestore", one(0xf158), one(0xfff8), "+s", m68851 },
+{"psave", one(0xf100), one(0xffc0), "&s", m68851 },
+{"psave", one(0xf100), one(0xffc0), "+s", m68851 },
+
+{"psac", two(0xf040, 0x0007), two(0xffc0, 0xffff), "@s", m68851 },
+{"psas", two(0xf040, 0x0006), two(0xffc0, 0xffff), "@s", m68851 },
+{"psbc", two(0xf040, 0x0001), two(0xffc0, 0xffff), "@s", m68851 },
+{"psbs", two(0xf040, 0x0000), two(0xffc0, 0xffff), "@s", m68851 },
+{"pscc", two(0xf040, 0x000f), two(0xffc0, 0xffff), "@s", m68851 },
+{"pscs", two(0xf040, 0x000e), two(0xffc0, 0xffff), "@s", m68851 },
+{"psgc", two(0xf040, 0x000d), two(0xffc0, 0xffff), "@s", m68851 },
+{"psgs", two(0xf040, 0x000c), two(0xffc0, 0xffff), "@s", m68851 },
+{"psic", two(0xf040, 0x000b), two(0xffc0, 0xffff), "@s", m68851 },
+{"psis", two(0xf040, 0x000a), two(0xffc0, 0xffff), "@s", m68851 },
+{"pslc", two(0xf040, 0x0003), two(0xffc0, 0xffff), "@s", m68851 },
+{"psls", two(0xf040, 0x0002), two(0xffc0, 0xffff), "@s", m68851 },
+{"pssc", two(0xf040, 0x0005), two(0xffc0, 0xffff), "@s", m68851 },
+{"psss", two(0xf040, 0x0004), two(0xffc0, 0xffff), "@s", m68851 },
+{"pswc", two(0xf040, 0x0009), two(0xffc0, 0xffff), "@s", m68851 },
+{"psws", two(0xf040, 0x0008), two(0xffc0, 0xffff), "@s", m68851 },
+
+{"ptestr", two(0xf000, 0x8210), two(0xffc0, 0xe3f0), "T3&sQ8", m68030 | m68851 },
+{"ptestr", two(0xf000, 0x8310), two(0xffc0, 0xe310), "T3&sQ8A9", m68030 | m68851 },
+{"ptestr", two(0xf000, 0x8208), two(0xffc0, 0xe3f8), "D3&sQ8", m68030 | m68851 },
+{"ptestr", two(0xf000, 0x8308), two(0xffc0, 0xe318), "D3&sQ8A9", m68030 | m68851 },
+{"ptestr", two(0xf000, 0x8200), two(0xffc0, 0xe3fe), "f3&sQ8", m68030 | m68851 },
+{"ptestr", two(0xf000, 0x8300), two(0xffc0, 0xe31e), "f3&sQ8A9", m68030 | m68851 },
+
+{"ptestr", one(0xf568), one(0xfff8), "As", m68040 },
+
+{"ptestw", two(0xf000, 0x8010), two(0xffc0, 0xe3f0), "T3&sQ8", m68030 | m68851 },
+{"ptestw", two(0xf000, 0x8110), two(0xffc0, 0xe310), "T3&sQ8A9", m68030 | m68851 },
+{"ptestw", two(0xf000, 0x8008), two(0xffc0, 0xe3f8), "D3&sQ8", m68030 | m68851 },
+{"ptestw", two(0xf000, 0x8108), two(0xffc0, 0xe318), "D3&sQ8A9", m68030 | m68851 },
+{"ptestw", two(0xf000, 0x8000), two(0xffc0, 0xe3fe), "f3&sQ8", m68030 | m68851 },
+{"ptestw", two(0xf000, 0x8100), two(0xffc0, 0xe31e), "f3&sQ8A9", m68030 | m68851 },
+
+{"ptestw", one(0xf548), one(0xfff8), "As", m68040 },
+
+{"ptrapacw", two(0xf07a, 0x0007), two(0xffff, 0xffff), "#w", m68851 },
+{"ptrapacl", two(0xf07b, 0x0007), two(0xffff, 0xffff), "#l", m68851 },
+{"ptrapac", two(0xf07c, 0x0007), two(0xffff, 0xffff), "", m68851 },
+
+{"ptrapasw", two(0xf07a, 0x0006), two(0xffff, 0xffff), "#w", m68851 },
+{"ptrapasl", two(0xf07b, 0x0006), two(0xffff, 0xffff), "#l", m68851 },
+{"ptrapas", two(0xf07c, 0x0006), two(0xffff, 0xffff), "", m68851 },
+
+{"ptrapbcw", two(0xf07a, 0x0001), two(0xffff, 0xffff), "#w", m68851 },
+{"ptrapbcl", two(0xf07b, 0x0001), two(0xffff, 0xffff), "#l", m68851 },
+{"ptrapbc", two(0xf07c, 0x0001), two(0xffff, 0xffff), "", m68851 },
+
+{"ptrapbsw", two(0xf07a, 0x0000), two(0xffff, 0xffff), "#w", m68851 },
+{"ptrapbsl", two(0xf07b, 0x0000), two(0xffff, 0xffff), "#l", m68851 },
+{"ptrapbs", two(0xf07c, 0x0000), two(0xffff, 0xffff), "", m68851 },
+
+{"ptrapccw", two(0xf07a, 0x000f), two(0xffff, 0xffff), "#w", m68851 },
+{"ptrapccl", two(0xf07b, 0x000f), two(0xffff, 0xffff), "#l", m68851 },
+{"ptrapcc", two(0xf07c, 0x000f), two(0xffff, 0xffff), "", m68851 },
+
+{"ptrapcsw", two(0xf07a, 0x000e), two(0xffff, 0xffff), "#w", m68851 },
+{"ptrapcsl", two(0xf07b, 0x000e), two(0xffff, 0xffff), "#l", m68851 },
+{"ptrapcs", two(0xf07c, 0x000e), two(0xffff, 0xffff), "", m68851 },
+
+{"ptrapgcw", two(0xf07a, 0x000d), two(0xffff, 0xffff), "#w", m68851 },
+{"ptrapgcl", two(0xf07b, 0x000d), two(0xffff, 0xffff), "#l", m68851 },
+{"ptrapgc", two(0xf07c, 0x000d), two(0xffff, 0xffff), "", m68851 },
+
+{"ptrapgsw", two(0xf07a, 0x000c), two(0xffff, 0xffff), "#w", m68851 },
+{"ptrapgsl", two(0xf07b, 0x000c), two(0xffff, 0xffff), "#l", m68851 },
+{"ptrapgs", two(0xf07c, 0x000c), two(0xffff, 0xffff), "", m68851 },
+
+{"ptrapicw", two(0xf07a, 0x000b), two(0xffff, 0xffff), "#w", m68851 },
+{"ptrapicl", two(0xf07b, 0x000b), two(0xffff, 0xffff), "#l", m68851 },
+{"ptrapic", two(0xf07c, 0x000b), two(0xffff, 0xffff), "", m68851 },
+
+{"ptrapisw", two(0xf07a, 0x000a), two(0xffff, 0xffff), "#w", m68851 },
+{"ptrapisl", two(0xf07b, 0x000a), two(0xffff, 0xffff), "#l", m68851 },
+{"ptrapis", two(0xf07c, 0x000a), two(0xffff, 0xffff), "", m68851 },
+
+{"ptraplcw", two(0xf07a, 0x0003), two(0xffff, 0xffff), "#w", m68851 },
+{"ptraplcl", two(0xf07b, 0x0003), two(0xffff, 0xffff), "#l", m68851 },
+{"ptraplc", two(0xf07c, 0x0003), two(0xffff, 0xffff), "", m68851 },
+
+{"ptraplsw", two(0xf07a, 0x0002), two(0xffff, 0xffff), "#w", m68851 },
+{"ptraplsl", two(0xf07b, 0x0002), two(0xffff, 0xffff), "#l", m68851 },
+{"ptrapls", two(0xf07c, 0x0002), two(0xffff, 0xffff), "", m68851 },
+
+{"ptrapscw", two(0xf07a, 0x0005), two(0xffff, 0xffff), "#w", m68851 },
+{"ptrapscl", two(0xf07b, 0x0005), two(0xffff, 0xffff), "#l", m68851 },
+{"ptrapsc", two(0xf07c, 0x0005), two(0xffff, 0xffff), "", m68851 },
+
+{"ptrapssw", two(0xf07a, 0x0004), two(0xffff, 0xffff), "#w", m68851 },
+{"ptrapssl", two(0xf07b, 0x0004), two(0xffff, 0xffff), "#l", m68851 },
+{"ptrapss", two(0xf07c, 0x0004), two(0xffff, 0xffff), "", m68851 },
+
+{"ptrapwcw", two(0xf07a, 0x0009), two(0xffff, 0xffff), "#w", m68851 },
+{"ptrapwcl", two(0xf07b, 0x0009), two(0xffff, 0xffff), "#l", m68851 },
+{"ptrapwc", two(0xf07c, 0x0009), two(0xffff, 0xffff), "", m68851 },
+
+{"ptrapwsw", two(0xf07a, 0x0008), two(0xffff, 0xffff), "#w", m68851 },
+{"ptrapwsl", two(0xf07b, 0x0008), two(0xffff, 0xffff), "#l", m68851 },
+{"ptrapws", two(0xf07c, 0x0008), two(0xffff, 0xffff), "", m68851 },
+
+{"pvalid", two(0xf000, 0x2800), two(0xffc0, 0xffff), "Vs&s", m68851 },
+{"pvalid", two(0xf000, 0x2c00), two(0xffc0, 0xfff8), "A3&s", m68851 },
+
+#endif /* NO_68851 */
+
+{"reset", one(0047160), one(0177777), "", m68000up },
+
+{"rolb", one(0160430), one(0170770), "QdDs", m68000up }, /* rorb #Q, Ds */
+{"rolb", one(0160470), one(0170770), "DdDs", m68000up }, /* rorb Dd, Ds */
+{"roll", one(0160630), one(0170770), "QdDs", m68000up }, /* rorb #Q, Ds */
+{"roll", one(0160670), one(0170770), "DdDs", m68000up }, /* rorb Dd, Ds */
+{"rolw", one(0160530), one(0170770), "QdDs", m68000up }, /* rorb #Q, Ds */
+{"rolw", one(0160570), one(0170770), "DdDs", m68000up }, /* rorb Dd, Ds */
+{"rolw", one(0163700), one(0177700), "~s", m68000up }, /* Rotate memory */
+{"rorb", one(0160030), one(0170770), "QdDs", m68000up }, /* rorb #Q, Ds */
+{"rorb", one(0160070), one(0170770), "DdDs", m68000up }, /* rorb Dd, Ds */
+{"rorl", one(0160230), one(0170770), "QdDs", m68000up }, /* rorb #Q, Ds */
+{"rorl", one(0160270), one(0170770), "DdDs", m68000up }, /* rorb Dd, Ds */
+{"rorw", one(0160130), one(0170770), "QdDs", m68000up }, /* rorb #Q, Ds */
+{"rorw", one(0160170), one(0170770), "DdDs", m68000up }, /* rorb Dd, Ds */
+{"rorw", one(0163300), one(0177700), "~s", m68000up }, /* Rotate memory */
+
+{"roxlb", one(0160420), one(0170770), "QdDs", m68000up }, /* roxrb #Q, Ds */
+{"roxlb", one(0160460), one(0170770), "DdDs", m68000up }, /* roxrb Dd, Ds */
+{"roxll", one(0160620), one(0170770), "QdDs", m68000up }, /* roxrb #Q, Ds */
+{"roxll", one(0160660), one(0170770), "DdDs", m68000up }, /* roxrb Dd, Ds */
+{"roxlw", one(0160520), one(0170770), "QdDs", m68000up }, /* roxrb #Q, Ds */
+{"roxlw", one(0160560), one(0170770), "DdDs", m68000up }, /* roxrb Dd, Ds */
+{"roxlw", one(0162700), one(0177700), "~s", m68000up }, /* Rotate memory */
+{"roxrb", one(0160020), one(0170770), "QdDs", m68000up }, /* roxrb #Q, Ds */
+{"roxrb", one(0160060), one(0170770), "DdDs", m68000up }, /* roxrb Dd, Ds */
+{"roxrl", one(0160220), one(0170770), "QdDs", m68000up }, /* roxrb #Q, Ds */
+{"roxrl", one(0160260), one(0170770), "DdDs", m68000up }, /* roxrb Dd, Ds */
+{"roxrw", one(0160120), one(0170770), "QdDs", m68000up }, /* roxrb #Q, Ds */
+{"roxrw", one(0160160), one(0170770), "DdDs", m68000up }, /* roxrb Dd, Ds */
+{"roxrw", one(0162300), one(0177700), "~s", m68000up }, /* Rotate memory */
+
+{"rtd", one(0047164), one(0177777), "#w", m68010up },
+{"rte", one(0047163), one(0177777), "", m68000up },
+{"rtm", one(0003300), one(0177760), "Rs", m68020 },
+{"rtr", one(0047167), one(0177777), "", m68000up },
+{"rts", one(0047165), one(0177777), "", m68000up },
+
+{"sbcd", one(0100400), one(0170770), "DsDd", m68000up },
+{"sbcd", one(0100410), one(0170770), "-s-d", m68000up },
+
+{"scc", one(0052300), one(0177700), "$s", m68000up },
+{"scs", one(0052700), one(0177700), "$s", m68000up },
+{"seq", one(0053700), one(0177700), "$s", m68000up },
+{"sf", one(0050700), one(0177700), "$s", m68000up },
+{"sge", one(0056300), one(0177700), "$s", m68000up },
+{"sfge", one(0056300), one(0177700), "$s", m68000up },
+{"sgt", one(0057300), one(0177700), "$s", m68000up },
+{"sfgt", one(0057300), one(0177700), "$s", m68000up },
+{"shi", one(0051300), one(0177700), "$s", m68000up },
+{"sle", one(0057700), one(0177700), "$s", m68000up },
+{"sfle", one(0057700), one(0177700), "$s", m68000up },
+{"sls", one(0051700), one(0177700), "$s", m68000up },
+{"slt", one(0056700), one(0177700), "$s", m68000up },
+{"sflt", one(0056700), one(0177700), "$s", m68000up },
+{"smi", one(0055700), one(0177700), "$s", m68000up },
+{"sne", one(0053300), one(0177700), "$s", m68000up },
+{"sfneq", one(0053300), one(0177700), "$s", m68000up },
+{"spl", one(0055300), one(0177700), "$s", m68000up },
+{"st", one(0050300), one(0177700), "$s", m68000up },
+{"svc", one(0054300), one(0177700), "$s", m68000up },
+{"svs", one(0054700), one(0177700), "$s", m68000up },
+
+{"stop", one(0047162), one(0177777), "#w", m68000up },
+
+{"subal", one(0110700), one(0170700), "*lAd", m68000up },
+{"subaw", one(0110300), one(0170700), "*wAd", m68000up },
+{"subb", one(0050400), one(0170700), "Qd%s", m68000up }, /* subq written as sub */
+{"subb", one(0002000), one(0177700), "#b$s", m68000up }, /* subi written as sub */
+{"subb", one(0110000), one(0170700), ";bDd", m68000up }, /* subb ? ?, Dd */
+{"subb", one(0110400), one(0170700), "Dd~s", m68000up }, /* subb Dd, ? ? */
+{"subib", one(0002000), one(0177700), "#b$s", m68000up },
+{"subil", one(0002200), one(0177700), "#l$s", m68000up },
+{"subiw", one(0002100), one(0177700), "#w$s", m68000up },
+{"subl", one(0050600), one(0170700), "Qd%s", m68000up },
+{"subl", one(0002200), one(0177700), "#l$s", m68000up },
+{"subl", one(0110700), one(0170700), "*lAd", m68000up },
+{"subl", one(0110200), one(0170700), "*lDd", m68000up },
+{"subl", one(0110600), one(0170700), "Dd~s", m68000up },
+{"subqb", one(0050400), one(0170700), "Qd%s", m68000up },
+{"subql", one(0050600), one(0170700), "Qd%s", m68000up },
+{"subqw", one(0050500), one(0170700), "Qd%s", m68000up },
+{"subw", one(0050500), one(0170700), "Qd%s", m68000up },
+{"subw", one(0002100), one(0177700), "#w$s", m68000up },
+{"subw", one(0110100), one(0170700), "*wDd", m68000up },
+{"subw", one(0110300), one(0170700), "*wAd", m68000up }, /* suba written as sub */
+{"subw", one(0110500), one(0170700), "Dd~s", m68000up },
+{"subxb", one(0110400), one(0170770), "DsDd", m68000up }, /* subxb Ds, Dd */
+{"subxb", one(0110410), one(0170770), "-s-d", m68000up }, /* subxb -(As), -(Ad) */
+{"subxl", one(0110600), one(0170770), "DsDd", m68000up },
+{"subxl", one(0110610), one(0170770), "-s-d", m68000up },
+{"subxw", one(0110500), one(0170770), "DsDd", m68000up },
+{"subxw", one(0110510), one(0170770), "-s-d", m68000up },
+
+{"swap", one(0044100), one(0177770), "Ds", m68000up },
+
+{"tas", one(0045300), one(0177700), "$s", m68000up },
+{"trap", one(0047100), one(0177760), "Ts", m68000up },
+
+{"trapcc", one(0052374), one(0177777), "", m68020up },
+{"trapcs", one(0052774), one(0177777), "", m68020up },
+{"trapeq", one(0053774), one(0177777), "", m68020up },
+{"trapf", one(0050774), one(0177777), "", m68020up },
+{"trapge", one(0056374), one(0177777), "", m68020up },
+{"trapgt", one(0057374), one(0177777), "", m68020up },
+{"traphi", one(0051374), one(0177777), "", m68020up },
+{"traple", one(0057774), one(0177777), "", m68020up },
+{"trapls", one(0051774), one(0177777), "", m68020up },
+{"traplt", one(0056774), one(0177777), "", m68020up },
+{"trapmi", one(0055774), one(0177777), "", m68020up },
+{"trapne", one(0053374), one(0177777), "", m68020up },
+{"trappl", one(0055374), one(0177777), "", m68020up },
+{"trapt", one(0050374), one(0177777), "", m68020up },
+{"trapvc", one(0054374), one(0177777), "", m68020up },
+{"trapvs", one(0054774), one(0177777), "", m68020up },
+
+{"trapcc.w", one(0052372), one(0177777), "", m68020up },
+{"trapcs.w", one(0052772), one(0177777), "", m68020up },
+{"trapeq.w", one(0053772), one(0177777), "", m68020up },
+{"trapf.w", one(0050772), one(0177777), "", m68020up },
+{"trapge.w", one(0056372), one(0177777), "", m68020up },
+{"trapgt.w", one(0057372), one(0177777), "", m68020up },
+{"traphi.w", one(0051372), one(0177777), "", m68020up },
+{"traple.w", one(0057772), one(0177777), "", m68020up },
+{"trapls.w", one(0051772), one(0177777), "", m68020up },
+{"traplt.w", one(0056772), one(0177777), "", m68020up },
+{"trapmi.w", one(0055772), one(0177777), "", m68020up },
+{"trapne.w", one(0053372), one(0177777), "", m68020up },
+{"trappl.w", one(0055372), one(0177777), "", m68020up },
+{"trapt.w", one(0050372), one(0177777), "", m68020up },
+{"trapvc.w", one(0054372), one(0177777), "", m68020up },
+{"trapvs.w", one(0054772), one(0177777), "", m68020up },
+
+{"trapcc.l", one(0052373), one(0177777), "", m68020up },
+{"trapcs.l", one(0052773), one(0177777), "", m68020up },
+{"trapeq.l", one(0053773), one(0177777), "", m68020up },
+{"trapf.l", one(0050773), one(0177777), "", m68020up },
+{"trapge.l", one(0056373), one(0177777), "", m68020up },
+{"trapgt.l", one(0057373), one(0177777), "", m68020up },
+{"traphi.l", one(0051373), one(0177777), "", m68020up },
+{"traple.l", one(0057773), one(0177777), "", m68020up },
+{"trapls.l", one(0051773), one(0177777), "", m68020up },
+{"traplt.l", one(0056773), one(0177777), "", m68020up },
+{"trapmi.l", one(0055773), one(0177777), "", m68020up },
+{"trapne.l", one(0053373), one(0177777), "", m68020up },
+{"trappl.l", one(0055373), one(0177777), "", m68020up },
+{"trapt.l", one(0050373), one(0177777), "", m68020up },
+{"trapvc.l", one(0054373), one(0177777), "", m68020up },
+{"trapvs.l", one(0054773), one(0177777), "", m68020up },
+
+{"trapv", one(0047166), one(0177777), "", m68000up },
+
+{"tstb", one(0045000), one(0177700), ";b", m68000up },
+{"tstw", one(0045100), one(0177700), "*w", m68000up },
+{"tstl", one(0045200), one(0177700), "*l", m68000up },
+
+{"unlk", one(0047130), one(0177770), "As", m68000up },
+{"unpk", one(0100600), one(0170770), "DsDd#w", m68020up },
+{"unpk", one(0100610), one(0170770), "-s-d#w", m68020up },
+
+/* Variable-sized branches */
+
+{"jbsr", one(0060400), one(0177400), "Bg", m68000up },
+{"jbsr", one(0047200), one(0177700), "!s", m68000up },
+#ifdef PIC
+{"jbsr", one(0060400), one(0177400), "Bg ", m68020up },
+#endif /* PIC */
+
+{"jra", one(0060000), one(0177400), "Bg", m68000up },
+{"jra", one(0047300), one(0177700), "!s", m68000up },
+#ifdef PIC
+{"jra", one(0060000), one(0177400), "Bg ", m68000up },
+#endif /* PIC */
+
+{"jhi", one(0061000), one(0177400), "Bg", m68000up },
+{"jls", one(0061400), one(0177400), "Bg", m68000up },
+{"jcc", one(0062000), one(0177400), "Bg", m68000up },
+{"jfnlt", one(0062000), one(0177400), "Bg", m68000up }, /* apparently a sun alias */
+{"jcs", one(0062400), one(0177400), "Bg", m68000up },
+{"jne", one(0063000), one(0177400), "Bg", m68000up },
+{"jeq", one(0063400), one(0177400), "Bg", m68000up },
+{"jfeq", one(0063400), one(0177400), "Bg", m68000up }, /* apparently a sun alias */
+{"jvc", one(0064000), one(0177400), "Bg", m68000up },
+{"jvs", one(0064400), one(0177400), "Bg", m68000up },
+{"jpl", one(0065000), one(0177400), "Bg", m68000up },
+{"jmi", one(0065400), one(0177400), "Bg", m68000up },
+{"jge", one(0066000), one(0177400), "Bg", m68000up },
+{"jlt", one(0066400), one(0177400), "Bg", m68000up },
+{"jgt", one(0067000), one(0177400), "Bg", m68000up },
+{"jle", one(0067400), one(0177400), "Bg", m68000up },
+{"jfngt", one(0067400), one(0177400), "Bg", m68000up }, /* apparently a sun alias */
+
+/* aliases */
+
+{"movql", one(0070000), one(0170400), "MsDd", m68000up },
+{"moveql", one(0070000), one(0170400), "MsDd", m68000up },
+{"moval", one(0020100), one(0170700), "*lAd", m68000up },
+{"movaw", one(0030100), one(0170700), "*wAd", m68000up },
+{"movb", one(0010000), one(0170000), ";b$d", m68000up }, /* mov */
+{"movl", one(0070000), one(0170400), "MsDd", m68000up }, /* movq written as mov */
+{"movl", one(0020000), one(0170000), "*l$d", m68000up },
+{"movl", one(0020100), one(0170700), "*lAd", m68000up },
+{"movl", one(0047140), one(0177770), "AsUd", m68000up }, /* mov to USP */
+{"movl", one(0047150), one(0177770), "UdAs", m68000up }, /* mov from USP */
+{"movc", one(0047173), one(0177777), "R1Jj", m68010up },
+{"movc", one(0047173), one(0177777), "R1#j", m68010up },
+{"movc", one(0047172), one(0177777), "JjR1", m68010up },
+{"movc", one(0047172), one(0177777), "#jR1", m68010up },
+{"movml", one(0044300), one(0177700), "#w&s", m68000up }, /* movm reg to mem. */
+{"movml", one(0044340), one(0177770), "#w-s", m68000up }, /* movm reg to autodecrement. */
+{"movml", one(0046300), one(0177700), "!s#w", m68000up }, /* movm mem to reg. */
+{"movml", one(0046330), one(0177770), "+s#w", m68000up }, /* movm autoinc to reg. */
+{"movml", one(0044300), one(0177700), "Lw&s", m68000up }, /* movm reg to mem. */
+{"movml", one(0044340), one(0177770), "lw-s", m68000up }, /* movm reg to autodecrement. */
+{"movml", one(0046300), one(0177700), "!sLw", m68000up }, /* movm mem to reg. */
+{"movml", one(0046330), one(0177770), "+sLw", m68000up }, /* movm autoinc to reg. */
+{"movmw", one(0044200), one(0177700), "#w&s", m68000up }, /* movm reg to mem. */
+{"movmw", one(0044240), one(0177770), "#w-s", m68000up }, /* movm reg to autodecrement. */
+{"movmw", one(0046200), one(0177700), "!s#w", m68000up }, /* movm mem to reg. */
+{"movmw", one(0046230), one(0177770), "+s#w", m68000up }, /* movm autoinc to reg. */
+{"movmw", one(0044200), one(0177700), "Lw&s", m68000up }, /* movm reg to mem. */
+{"movmw", one(0044240), one(0177770), "lw-s", m68000up }, /* movm reg to autodecrement. */
+{"movmw", one(0046200), one(0177700), "!sLw", m68000up }, /* movm mem to reg. */
+{"movmw", one(0046230), one(0177770), "+sLw", m68000up }, /* movm autoinc to reg. */
+{"movpl", one(0000510), one(0170770), "dsDd", m68000up }, /* memory to register */
+{"movpl", one(0000710), one(0170770), "Ddds", m68000up }, /* register to memory */
+{"movpw", one(0000410), one(0170770), "dsDd", m68000up }, /* memory to register */
+{"movpw", one(0000610), one(0170770), "Ddds", m68000up }, /* register to memory */
+{"movq", one(0070000), one(0170400), "MsDd", m68000up },
+{"movw", one(0030000), one(0170000), "*w$d", m68000up },
+{"movw", one(0030100), one(0170700), "*wAd", m68000up }, /* mova, written as mov */
+{"movw", one(0040300), one(0177700), "Ss$s", m68000up }, /* Move from sr */
+{"movw", one(0041300), one(0177700), "Cs$s", m68010up }, /* Move from ccr */
+{"movw", one(0042300), one(0177700), ";wCd", m68000up }, /* mov to ccr */
+{"movw", one(0043300), one(0177700), ";wSd", m68000up }, /* mov to sr */
+
+{"movsb", two(0007000, 0), two(0177700, 07777), "~sR1", m68010up },
+{"movsb", two(0007000, 04000), two(0177700, 07777), "R1~s", m68010up },
+{"movsl", two(0007200, 0), two(0177700, 07777), "~sR1", m68010up },
+{"movsl", two(0007200, 04000), two(0177700, 07777), "R1~s", m68010up },
+{"movsw", two(0007100, 0), two(0177700, 07777), "~sR1", m68010up },
+{"movsw", two(0007100, 04000), two(0177700, 07777), "R1~s", m68010up },
+
+};
+
+int numopcodes=sizeof(m68k_opcodes)/sizeof(m68k_opcodes[0]);
+
+struct m68k_opcode *endop = m68k_opcodes+sizeof(m68k_opcodes)/sizeof(m68k_opcodes[0]);
+
+/*
+ * Local Variables:
+ * fill-column: 131
+ * End:
+ */
+
+/* end of m68k-opcode.h */
diff --git a/gnu/usr.bin/as/opcode/m88k.h b/gnu/usr.bin/as/opcode/m88k.h
new file mode 100644
index 0000000..5f685b9
--- /dev/null
+++ b/gnu/usr.bin/as/opcode/m88k.h
@@ -0,0 +1,282 @@
+/* m88k-opcode.h -- Instruction information for the Motorola 88000
+ Contributed by Devon Bowen of Buffalo University
+ and Torbjorn Granlund of the Swedish Institute of Computer Science.
+ Copyright (C) 1989, 1990, 1991 Free Software Foundation, Inc.
+
+This file is part of GAS, the GNU Assembler.
+
+GAS is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 1, or (at your option)
+any later version.
+
+GAS is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GAS; see the file COPYING. If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#if !defined(__STDC__) && !defined(const)
+#define const
+#endif
+
+/*
+ Character codes for op_spec field below.
+ Reserved for direct matching: x , [ ]
+
+ d = GRF Destination register (21:5)
+ 1 = Source register 1 (16:5)
+ 2 = Source register 2 (0:5)
+ 3 = Both source registers (same value) (0:5 and 16:5)
+ I = IMM16 (0:16)
+ b = bit field spec. (0:10)
+ p = 16 bit pc displ. (0:16)
+ P = 26 bit pc displ. (0:26)
+ B = bb0/bb1 condition (21:5)
+ M = bcnd condition (21:5)
+ f = fcr (5:6)
+ c = cr (5:6)
+ V = VEC9 (0:9)
+ ? = Give warning for this insn/operand combination
+ */
+
+/* instruction descriptor structure */
+
+struct m88k_opcode
+{
+ unsigned int opcode;
+ char *name;
+ char *op_spec;
+};
+
+/* and introducing... the Motorola 88100 instruction sets... */
+
+/* These macros may seem silly, but they are in preparation
+ for future versions of the 88000 family. */
+
+#define _MC88100(OPCODE,MNEM,OP_SPEC) {OPCODE,MNEM,OP_SPEC},
+#define _MC88xxx(OPCODE,MNEM,OP_SPEC) {OPCODE,MNEM,OP_SPEC},
+
+/* Equal mnemonics must be adjacent.
+ More specific operand specification must go before more general.
+ For example, "d,1,2" must go before "d,1,I" as a register for s2
+ would otherwise be considered a variable name. */
+
+static struct m88k_opcode m88k_opcodes[] =
+{
+ /* Opcode Mnemonic Opspec */
+
+ _MC88xxx(0xf4007000, "add", "d,1,2")
+ _MC88xxx(0x70000000, "add", "d,1,I")
+ _MC88xxx(0xf4007200, "add.ci", "d,1,2")
+ _MC88xxx(0xf4007300, "add.cio", "d,1,2")
+ _MC88xxx(0xf4007100, "add.co", "d,1,2")
+ _MC88xxx(0xf4006000, "addu", "d,1,2")
+ _MC88xxx(0x60000000, "addu", "d,1,I")
+ _MC88xxx(0xf4006200, "addu.ci", "d,1,2")
+ _MC88xxx(0xf4006300, "addu.cio", "d,1,2")
+ _MC88xxx(0xf4006100, "addu.co", "d,1,2")
+ _MC88xxx(0xf4004000, "and", "d,1,2")
+ _MC88xxx(0x40000000, "and", "d,1,I")
+ _MC88xxx(0xf4004400, "and.c", "d,1,2")
+ _MC88xxx(0x44000000, "and.u", "d,1,I")
+ _MC88xxx(0xd0000000, "bb0", "B,1,p")
+ _MC88xxx(0xd4000000, "bb0.n", "B,1,p")
+ _MC88xxx(0xd8000000, "bb1", "B,1,p")
+ _MC88xxx(0xdc000000, "bb1.n", "B,1,p")
+ _MC88xxx(0xe8000000, "bcnd", "M,1,p")
+ _MC88xxx(0xec000000, "bcnd.n", "M,1,p")
+ _MC88xxx(0xc0000000, "br", "P")
+ _MC88xxx(0xc4000000, "br.n", "P")
+ _MC88xxx(0xc8000000, "bsr", "P")
+ _MC88xxx(0xcc000000, "bsr.n", "P")
+ _MC88xxx(0xf4008000, "clr", "d,1,2")
+ _MC88xxx(0xf0008000, "clr", "d,1,b")
+ _MC88xxx(0xf4007c00, "cmp", "d,1,2")
+ _MC88xxx(0x7c000000, "cmp", "d,1,I")
+ _MC88xxx(0xf4007800, "div", "d,1,2")
+ _MC88xxx(0x78000000, "div", "d,1,I")
+ _MC88xxx(0xf4007800, "divs", "d,1,2")
+ _MC88xxx(0x78000000, "divs", "d,1,I")
+ _MC88xxx(0xf4006800, "divu", "d,1,2")
+ _MC88xxx(0x68000000, "divu", "d,1,I")
+ _MC88xxx(0xf4009000, "ext", "d,1,2")
+ _MC88xxx(0xf0009000, "ext", "d,1,b")
+ _MC88xxx(0xf4009800, "extu", "d,1,2")
+ _MC88xxx(0xf0009800, "extu", "d,1,b")
+ _MC88xxx(0x84002800, "fadd.sss", "d,1,2")
+ _MC88xxx(0x84002880, "fadd.ssd", "d,1,2")
+ _MC88xxx(0x84002a00, "fadd.sds", "d,1,2")
+ _MC88xxx(0x84002a80, "fadd.sdd", "d,1,2")
+ _MC88xxx(0x84002820, "fadd.dss", "d,1,2")
+ _MC88xxx(0x840028a0, "fadd.dsd", "d,1,2")
+ _MC88xxx(0x84002a20, "fadd.dds", "d,1,2")
+ _MC88xxx(0x84002aa0, "fadd.ddd", "d,1,2")
+ _MC88xxx(0x84003a80, "fcmp.sdd", "d,1,2")
+ _MC88xxx(0x84003a00, "fcmp.sds", "d,1,2")
+ _MC88xxx(0x84003880, "fcmp.ssd", "d,1,2")
+ _MC88xxx(0x84003800, "fcmp.sss", "d,1,2")
+ _MC88xxx(0x84007000, "fdiv.sss", "d,1,2")
+ _MC88xxx(0x84007080, "fdiv.ssd", "d,1,2")
+ _MC88xxx(0x84007200, "fdiv.sds", "d,1,2")
+ _MC88xxx(0x84007280, "fdiv.sdd", "d,1,2")
+ _MC88xxx(0x84007020, "fdiv.dss", "d,1,2")
+ _MC88xxx(0x840070a0, "fdiv.dsd", "d,1,2")
+ _MC88xxx(0x84007220, "fdiv.dds", "d,1,2")
+ _MC88xxx(0x840072a0, "fdiv.ddd", "d,1,2")
+ _MC88xxx(0xf400ec00, "ff0", "d,2")
+ _MC88xxx(0xf400e800, "ff1", "d,2")
+ _MC88xxx(0x80004800, "fldcr", "d,f")
+ _MC88xxx(0x84002020, "flt.ds", "d,2")
+ _MC88xxx(0x84002000, "flt.ss", "d,2")
+ _MC88xxx(0x84000000, "fmul.sss", "d,1,2")
+ _MC88xxx(0x84000080, "fmul.ssd", "d,1,2")
+ _MC88xxx(0x84000200, "fmul.sds", "d,1,2")
+ _MC88xxx(0x84000280, "fmul.sdd", "d,1,2")
+ _MC88xxx(0x84000020, "fmul.dss", "d,1,2")
+ _MC88xxx(0x840000a0, "fmul.dsd", "d,1,2")
+ _MC88xxx(0x84000220, "fmul.dds", "d,1,2")
+ _MC88xxx(0x840002a0, "fmul.ddd", "d,1,2")
+ _MC88xxx(0x80008800, "fstcr", "3,f")
+ _MC88xxx(0x84003000, "fsub.sss", "d,1,2")
+ _MC88xxx(0x84003080, "fsub.ssd", "d,1,2")
+ _MC88xxx(0x84003200, "fsub.sds", "d,1,2")
+ _MC88xxx(0x84003280, "fsub.sdd", "d,1,2")
+ _MC88xxx(0x84003020, "fsub.dss", "d,1,2")
+ _MC88xxx(0x840030a0, "fsub.dsd", "d,1,2")
+ _MC88xxx(0x84003220, "fsub.dds", "d,1,2")
+ _MC88xxx(0x840032a0, "fsub.ddd", "d,1,2")
+ _MC88xxx(0x8000c800, "fxcr", "d,3,f")
+ _MC88xxx(0x8400fc01, "illop1", "")
+ _MC88xxx(0x8400fc02, "illop2", "")
+ _MC88xxx(0x8400fc03, "illop3", "")
+ _MC88xxx(0x84004880, "int.sd", "d,2")
+ _MC88xxx(0x84004800, "int.ss", "d,2")
+ _MC88xxx(0xf400c000, "jmp", "2")
+ _MC88xxx(0xf400c400, "jmp.n", "2")
+ _MC88xxx(0xf400c800, "jsr", "2")
+ _MC88xxx(0xf400cc00, "jsr.n", "2")
+ _MC88xxx(0xf4001400, "ld", "d,1,2")
+ _MC88xxx(0xf4001600, "ld", "d,1[2]")
+ _MC88xxx(0x14000000, "ld", "d,1,I")
+ _MC88xxx(0xf4001e00, "ld.b", "d,1[2]")
+ _MC88xxx(0xf4001c00, "ld.b", "d,1,2")
+ _MC88xxx(0x1c000000, "ld.b", "d,1,I")
+ _MC88xxx(0xf4001d00, "ld.b.usr", "d,1,2")
+ _MC88xxx(0xf4001f00, "ld.b.usr", "d,1[2]")
+ _MC88xxx(0xf4000e00, "ld.bu", "d,1[2]")
+ _MC88xxx(0xf4000c00, "ld.bu", "d,1,2")
+ _MC88xxx(0x0c000000, "ld.bu", "d,1,I")
+ _MC88xxx(0xf4000d00, "ld.bu.usr", "d,1,2")
+ _MC88xxx(0xf4000f00, "ld.bu.usr", "d,1[2]")
+ _MC88xxx(0xf4001200, "ld.d", "d,1[2]")
+ _MC88xxx(0xf4001000, "ld.d", "d,1,2")
+ _MC88xxx(0x10000000, "ld.d", "d,1,I")
+ _MC88xxx(0xf4001100, "ld.d.usr", "d,1,2")
+ _MC88xxx(0xf4001300, "ld.d.usr", "d,1[2]")
+ _MC88xxx(0xf4001a00, "ld.h", "d,1[2]")
+ _MC88xxx(0xf4001800, "ld.h", "d,1,2")
+ _MC88xxx(0x18000000, "ld.h", "d,1,I")
+ _MC88xxx(0xf4001900, "ld.h.usr", "d,1,2")
+ _MC88xxx(0xf4001b00, "ld.h.usr", "d,1[2]")
+ _MC88xxx(0xf4000a00, "ld.hu", "d,1[2]")
+ _MC88xxx(0xf4000800, "ld.hu", "d,1,2")
+ _MC88xxx(0x08000000, "ld.hu", "d,1,I")
+ _MC88xxx(0xf4000900, "ld.hu.usr", "d,1,2")
+ _MC88xxx(0xf4000b00, "ld.hu.usr", "d,1[2]")
+ _MC88xxx(0xf4001500, "ld.usr", "d,1,2")
+ _MC88xxx(0xf4001700, "ld.usr", "d,1[2]")
+ _MC88xxx(0xf4003600, "lda", "d,1[2]")
+ _MC88xxx(0xf4006000, "lda", "?d,1,2") /* Output addu */
+ _MC88xxx(0x60000000, "lda", "?d,1,I") /* Output addu */
+ _MC88xxx(0xf4006000, "lda.b", "?d,1[2]") /* Output addu */
+ _MC88xxx(0xf4006000, "lda.b", "?d,1,2") /* Output addu */
+ _MC88xxx(0x60000000, "lda.b", "?d,1,I") /* Output addu */
+ _MC88xxx(0xf4003200, "lda.d", "d,1[2]")
+ _MC88xxx(0xf4006000, "lda.d", "?d,1,2") /* Output addu */
+ _MC88xxx(0x60000000, "lda.d", "?d,1,I") /* Output addu */
+ _MC88xxx(0xf4003a00, "lda.h", "d,1[2]")
+ _MC88xxx(0xf4006000, "lda.h", "?d,1,2") /* Output addu */
+ _MC88xxx(0x60000000, "lda.h", "?d,1,I") /* Output addu */
+ _MC88xxx(0x80004000, "ldcr", "d,c")
+ _MC88xxx(0xf400a000, "mak", "d,1,2")
+ _MC88xxx(0xf000a000, "mak", "d,1,b")
+ _MC88xxx(0x48000000, "mask", "d,1,I")
+ _MC88xxx(0x4c000000, "mask.u", "d,1,I")
+ _MC88xxx(0xf4006c00, "mul", "d,1,2")
+ _MC88xxx(0x6c000000, "mul", "d,1,I")
+ _MC88xxx(0xf4006c00, "mulu", "d,1,2") /* synonym for mul */
+ _MC88xxx(0x6c000000, "mulu", "d,1,I") /* synonym for mul */
+ _MC88xxx(0x84005080, "nint.sd", "d,2")
+ _MC88xxx(0x84005000, "nint.ss", "d,2")
+ _MC88xxx(0xf4005800, "or", "d,1,2")
+ _MC88xxx(0x58000000, "or", "d,1,I")
+ _MC88xxx(0xf4005c00, "or.c", "d,1,2")
+ _MC88xxx(0x5c000000, "or.u", "d,1,I")
+ _MC88xxx(0xf000a800, "rot", "d,1,b")
+ _MC88xxx(0xf400a800, "rot", "d,1,2")
+ _MC88xxx(0xf400fc00, "rte", "")
+ _MC88xxx(0xf4008800, "set", "d,1,2")
+ _MC88xxx(0xf0008800, "set", "d,1,b")
+ _MC88xxx(0xf4002600, "st", "d,1[2]")
+ _MC88xxx(0xf4002400, "st", "d,1,2")
+ _MC88xxx(0x24000000, "st", "d,1,I")
+ _MC88xxx(0xf4002e00, "st.b", "d,1[2]")
+ _MC88xxx(0xf4002c00, "st.b", "d,1,2")
+ _MC88xxx(0x2c000000, "st.b", "d,1,I")
+ _MC88xxx(0xf4002d00, "st.b.usr", "d,1,2")
+ _MC88xxx(0xf4002f00, "st.b.usr", "d,1[2]")
+ _MC88xxx(0xf4002200, "st.d", "d,1[2]")
+ _MC88xxx(0xf4002000, "st.d", "d,1,2")
+ _MC88xxx(0x20000000, "st.d", "d,1,I")
+ _MC88xxx(0xf4002100, "st.d.usr", "d,1,2")
+ _MC88xxx(0xf4002300, "st.d.usr", "d,1[2]")
+ _MC88xxx(0xf4002a00, "st.h", "d,1[2]")
+ _MC88xxx(0xf4002800, "st.h", "d,1,2")
+ _MC88xxx(0x28000000, "st.h", "d,1,I")
+ _MC88xxx(0xf4002900, "st.h.usr", "d,1,2")
+ _MC88xxx(0xf4002b00, "st.h.usr", "d,1[2]")
+ _MC88xxx(0xf4002500, "st.usr", "d,1,2")
+ _MC88xxx(0xf4002700, "st.usr", "d,1[2]")
+ _MC88xxx(0x80008000, "stcr", "3,c")
+ _MC88xxx(0xf4007400, "sub", "d,1,2")
+ _MC88xxx(0x74000000, "sub", "d,1,I")
+ _MC88xxx(0xf4007600, "sub.ci", "d,1,2")
+ _MC88xxx(0xf4007700, "sub.cio", "d,1,2")
+ _MC88xxx(0xf4007500, "sub.co", "d,1,2")
+ _MC88xxx(0xf4006400, "subu", "d,1,2")
+ _MC88xxx(0x64000000, "subu", "d,1,I")
+ _MC88xxx(0xf4006600, "subu.ci", "d,1,2")
+ _MC88xxx(0xf4006700, "subu.cio", "d,1,2")
+ _MC88xxx(0xf4006500, "subu.co", "d,1,2")
+ _MC88xxx(0xf000d000, "tb0", "B,1,V")
+ _MC88xxx(0xf000d800, "tb1", "B,1,V")
+ _MC88xxx(0xf400f800, "tbnd", "1,2")
+ _MC88xxx(0xf8000000, "tbnd", "1,I")
+ _MC88xxx(0xf000e800, "tcnd", "M,1,V")
+ _MC88xxx(0x84005880, "trnc.sd", "d,2")
+ _MC88xxx(0x84005800, "trnc.ss", "d,2")
+ _MC88xxx(0x8000c000, "xcr", "d,1,c")
+ _MC88xxx(0xf4000600, "xmem", "d,1[2]")
+ _MC88xxx(0xf4000400, "xmem", "d,1,2")
+ _MC88100(0x04000000, "xmem", "?d,1,I")
+ _MC88xxx(0xf4000200, "xmem.bu", "d,1[2]")
+ _MC88xxx(0xf4000000, "xmem.bu", "d,1,2")
+ _MC88100(0x00000000, "xmem.bu", "?d,1,I")
+ _MC88xxx(0xf4000300, "xmem.bu.usr", "d,1[2]")
+ _MC88xxx(0xf4000100, "xmem.bu.usr", "d,1,2")
+ _MC88100(0x00000100, "xmem.bu.usr", "?d,1,I")
+ _MC88xxx(0xf4000700, "xmem.usr", "d,1[2]")
+ _MC88xxx(0xf4000500, "xmem.usr", "d,1,2")
+ _MC88100(0x04000100, "xmem.usr", "?d,1,I")
+ _MC88xxx(0xf4005000, "xor", "d,1,2")
+ _MC88xxx(0x50000000, "xor", "d,1,I")
+ _MC88xxx(0xf4005400, "xor.c", "d,1,2")
+ _MC88xxx(0x54000000, "xor.u", "d,1,I")
+ _MC88xxx(0x00000000, "", 0)
+};
+
+#define NUMOPCODES ((sizeof m88k_opcodes)/(sizeof m88k_opcodes[0]))
diff --git a/gnu/usr.bin/as/opcode/mips.h b/gnu/usr.bin/as/opcode/mips.h
new file mode 100644
index 0000000..796ed47
--- /dev/null
+++ b/gnu/usr.bin/as/opcode/mips.h
@@ -0,0 +1,363 @@
+/* Mips opcde list for GDB, the GNU debugger.
+ Copyright (C) 1989 Free Software Foundation, Inc.
+ Contributed by Nobuyuki Hikichi(hikichi@sra.junet)
+ Made to work for little-endian machines, and debugged
+ by Per Bothner (bothner@cs.wisc.edu).
+ Many fixes contributed by Frank Yellin (fy@lucid.com).
+
+This file is part of GDB.
+
+GDB is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 1, or (at your option)
+any later version.
+
+GDB is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GDB; see the file COPYING. If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#if BITS_BIG_ENDIAN
+#define BIT_FIELDS_2(a,b) a;b;
+#define BIT_FIELDS_4(a,b,c,d) a;b;c;d;
+#define BIT_FIELDS_6(a,b,c,d,e,f) a;b;c;d;e;f;
+#else
+#define BIT_FIELDS_2(a,b) b;a;
+#define BIT_FIELDS_4(a,b,c,d) d;c;b;a;
+#define BIT_FIELDS_6(a,b,c,d,e,f) f;e;d;c;b;a;
+#endif
+
+struct op_i_fmt
+{
+BIT_FIELDS_4(
+ unsigned op : 6,
+ unsigned rs : 5,
+ unsigned rt : 5,
+ unsigned immediate : 16)
+};
+
+struct op_j_fmt
+{
+BIT_FIELDS_2(
+ unsigned op : 6,
+ unsigned target : 26)
+};
+
+struct op_r_fmt
+{
+BIT_FIELDS_6(
+ unsigned op : 6,
+ unsigned rs : 5,
+ unsigned rt : 5,
+ unsigned rd : 5,
+ unsigned shamt : 5,
+ unsigned funct : 6)
+};
+
+
+struct fop_i_fmt
+{
+BIT_FIELDS_4(
+ unsigned op : 6,
+ unsigned rs : 5,
+ unsigned rt : 5,
+ unsigned immediate : 16)
+};
+
+struct op_b_fmt
+{
+BIT_FIELDS_4(
+ unsigned op : 6,
+ unsigned rs : 5,
+ unsigned rt : 5,
+ short delta : 16)
+};
+
+struct fop_r_fmt
+{
+BIT_FIELDS_6(
+ unsigned op : 6,
+ unsigned fmt : 5,
+ unsigned ft : 5,
+ unsigned fs : 5,
+ unsigned fd : 5,
+ unsigned funct : 6)
+};
+
+struct mips_opcode
+{
+ char *name;
+ unsigned long opcode;
+ unsigned long match;
+ char *args;
+ int bdelay; /* Nonzero if delayed branch. */
+};
+
+/* args format;
+
+ "s" rs: source register specifier
+ "t" rt: target register
+ "i" immediate
+ "a" target address
+ "c" branch condition
+ "d" rd: destination register specifier
+ "h" shamt: shift amount
+ "f" funct: function field
+
+ for fpu
+ "S" fs source 1 register
+ "T" ft source 2 register
+ "D" distination register
+*/
+
+#define one(x) (x << 26)
+#define op_func(x, y) ((x << 26) | y)
+#define op_cond(x, y) ((x << 26) | (y << 16))
+#define op_rs_func(x, y, z) ((x << 26) | (y << 21) | z)
+#define op_rs_b11(x, y, z) ((x << 26) | (y << 21) | z)
+#define op_o16(x, y) ((x << 26) | (y << 16))
+#define op_bc(x, y, z) ((x << 26) | (y << 21) | (z << 16))
+
+struct mips_opcode mips_opcodes[] =
+{
+/* These first opcodes are special cases of the ones in the comments */
+ {"nop", 0, 0xffffffff, /*li*/ "", 0},
+ {"li", op_bc(9,0,0), op_bc(0x3f,31,0), /*addiu*/ "t,j", 0},
+ {"b", one(4), 0xffff0000, /*beq*/ "b", 1},
+ {"move", op_func(0, 33), op_cond(0x3f,31)|0x7ff,/*addu*/ "d,s", 0},
+
+ {"sll", op_func(0, 0), op_func(0x3f, 0x3f), "d,t,h", 0},
+ {"srl", op_func(0, 2), op_func(0x3f, 0x3f), "d,t,h", 0},
+ {"sra", op_func(0, 3), op_func(0x3f, 0x3f), "d,t,h", 0},
+ {"sllv", op_func(0, 4), op_func(0x3f, 0x7ff), "d,t,s", 0},
+ {"srlv", op_func(0, 6), op_func(0x3f, 0x7ff), "d,t,s", 0},
+ {"srav", op_func(0, 7), op_func(0x3f, 0x7ff), "d,t,s", 0},
+ {"jr", op_func(0, 8), op_func(0x3f, 0x1fffff), "s", 1},
+ {"jalr", op_func(0, 9), op_func(0x3f, 0x1f07ff), "d,s", 1},
+ {"syscall", op_func(0, 12), op_func(0x3f, 0x3f), "", 0},
+ {"break", op_func(0, 13), op_func(0x3f, 0x3f), "", 0},
+ {"mfhi", op_func(0, 16), op_func(0x3f, 0x03ff07ff), "d", 0},
+ {"mthi", op_func(0, 17), op_func(0x3f, 0x1fffff), "s", 0},
+ {"mflo", op_func(0, 18), op_func(0x3f, 0x03ff07ff), "d", 0},
+ {"mtlo", op_func(0, 19), op_func(0x3f, 0x1fffff), "s", 0},
+ {"mult", op_func(0, 24), op_func(0x3f, 0xffff), "s,t", 0},
+ {"multu", op_func(0, 25), op_func(0x3f, 0xffff), "s,t", 0},
+ {"div", op_func(0, 26), op_func(0x3f, 0xffff), "s,t", 0},
+ {"divu", op_func(0, 27), op_func(0x3f, 0xffff), "s,t", 0},
+ {"add", op_func(0, 32), op_func(0x3f, 0x7ff), "d,s,t", 0},
+ {"addu", op_func(0, 33), op_func(0x3f, 0x7ff), "d,s,t", 0},
+ {"sub", op_func(0, 34), op_func(0x3f, 0x7ff), "d,s,t", 0},
+ {"subu", op_func(0, 35), op_func(0x3f, 0x7ff), "d,s,t", 0},
+ {"and", op_func(0, 36), op_func(0x3f, 0x7ff), "d,s,t", 0},
+ {"or", op_func(0, 37), op_func(0x3f, 0x7ff), "d,s,t", 0},
+ {"xor", op_func(0, 38), op_func(0x3f, 0x7ff), "d,s,t", 0},
+ {"nor", op_func(0, 39), op_func(0x3f, 0x7ff), "d,s,t", 0},
+ {"slt", op_func(0, 42), op_func(0x3f, 0x7ff), "d,s,t", 0},
+ {"sltu", op_func(0, 43), op_func(0x3f, 0x7ff), "d,s,t", 0},
+
+ {"bltz", op_cond (1, 0), op_cond(0x3f, 0x1f), "s,b", 1},
+ {"bgez", op_cond (1, 1), op_cond(0x3f, 0x1f), "s,b", 1},
+ {"bltzal", op_cond (1, 16),op_cond(0x3f, 0x1f), "s,b", 1},
+ {"bgezal", op_cond (1, 17),op_cond(0x3f, 0x1f), "s,b", 1},
+
+
+ {"j", one(2), one(0x3f), "a", 1},
+ {"jal", one(3), one(0x3f), "a", 1},
+ {"beq", one(4), one(0x3f), "s,t,b", 1},
+ {"bne", one(5), one(0x3f), "s,t,b", 1},
+ {"blez", one(6), one(0x3f) | 0x1f0000, "s,b", 1},
+ {"bgtz", one(7), one(0x3f) | 0x1f0000, "s,b", 1},
+ {"addi", one(8), one(0x3f), "t,s,j", 0},
+ {"addiu", one(9), one(0x3f), "t,s,j", 0},
+ {"slti", one(10), one(0x3f), "t,s,j", 0},
+ {"sltiu", one(11), one(0x3f), "t,s,j", 0},
+ {"andi", one(12), one(0x3f), "t,s,i", 0},
+ {"ori", one(13), one(0x3f), "t,s,i", 0},
+ {"xori", one(14), one(0x3f), "t,s,i", 0},
+ /* rs field is don't care field? */
+ {"lui", one(15), one(0x3f), "t,i", 0},
+
+/* co processor 0 instruction */
+ {"mfc0", op_rs_b11 (16, 0, 0), op_rs_b11(0x3f, 0x1f, 0x1ffff), "t,d", 0},
+ {"cfc0", op_rs_b11 (16, 2, 0), op_rs_b11(0x3f, 0x1f, 0x1ffff), "t,d", 0},
+ {"mtc0", op_rs_b11 (16, 4, 0), op_rs_b11(0x3f, 0x1f, 0x1ffff), "t,d", 0},
+ {"ctc0", op_rs_b11 (16, 6, 0), op_rs_b11(0x3f, 0x1f, 0x1ffff), "t,d", 0},
+
+ {"bc0f", op_o16(16, 0x100), op_o16(0x3f, 0x3ff), "b", 1},
+ {"bc0f", op_o16(16, 0x180), op_o16(0x3f, 0x3ff), "b", 1},
+ {"bc0t", op_o16(16, 0x101), op_o16(0x3f, 0x3ff), "b", 1},
+ {"bc0t", op_o16(16, 0x181), op_o16(0x3f, 0x3ff), "b", 1},
+
+ {"tlbr", op_rs_func(16, 0x10, 1), ~0, "", 0},
+ {"tlbwi", op_rs_func(16, 0x10, 2), ~0, "", 0},
+ {"tlbwr", op_rs_func(16, 0x10, 6), ~0, "", 0},
+ {"tlbp", op_rs_func(16, 0x10, 8), ~0, "", 0},
+ {"rfe", op_rs_func(16, 0x10, 16), ~0, "", 0},
+
+ {"mfc1", op_rs_b11 (17, 0, 0), op_rs_b11(0x3f, 0x1f, 0),"t,S", 0},
+ {"cfc1", op_rs_b11 (17, 2, 0), op_rs_b11(0x3f, 0x1f, 0),"t,S", 0},
+ {"mtc1", op_rs_b11 (17, 4, 0), op_rs_b11(0x3f, 0x1f, 0),"t,S", 0},
+ {"ctc1", op_rs_b11 (17, 6, 0), op_rs_b11(0x3f, 0x1f, 0),"t,S", 0},
+
+ {"bc1f", op_o16(17, 0x100), op_o16(0x3f, 0x3ff), "b", 1},
+ {"bc1f", op_o16(17, 0x180), op_o16(0x3f, 0x3ff), "b", 1},
+ {"bc1t", op_o16(17, 0x101), op_o16(0x3f, 0x3ff), "b", 1},
+ {"bc1t", op_o16(17, 0x181), op_o16(0x3f, 0x3ff), "b", 1},
+
+/* fpu instruction */
+ {"add.s", op_rs_func(17, 0x10, 0),
+ op_rs_func(0x3f, 0x1f, 0x3f), "D,S,T", 0},
+ {"add.d", op_rs_func(17, 0x11, 0),
+ op_rs_func(0x3f, 0x1f, 0x3f), "D,S,T", 0},
+ {"sub.s", op_rs_func(17, 0x10, 1),
+ op_rs_func(0x3f, 0x1f, 0x3f), "D,S,T", 0},
+ {"sub.d", op_rs_func(17, 0x11, 1),
+ op_rs_func(0x3f, 0x1f, 0x3f), "D,S,T", 0},
+ {"mul.s", op_rs_func(17, 0x10, 2),
+ op_rs_func(0x3f, 0x1f, 0x3f), "D,S,T", 0},
+ {"mul.d", op_rs_func(17, 0x11, 2),
+ op_rs_func(0x3f, 0x1f, 0x3f), "D,S,T", 0},
+ {"div.s", op_rs_func(17, 0x10, 3),
+ op_rs_func(0x3f, 0x1f, 0x3f), "D,S,T", 0},
+ {"div.d", op_rs_func(17, 0x11, 3),
+ op_rs_func(0x3f, 0x1f, 0x3f), "D,S,T", 0},
+ {"abs.s", op_rs_func(17, 0x10, 5),
+ op_rs_func(0x3f, 0x1f, 0x1f003f), "D,S", 0},
+ {"abs.d", op_rs_func(17, 0x11, 5),
+ op_rs_func(0x3f, 0x1f, 0x1f003f), "D,S", 0},
+ {"mov.s", op_rs_func(17, 0x10, 6),
+ op_rs_func(0x3f, 0x1f, 0x1f003f), "D,S", 0},
+ {"mov.d", op_rs_func(17, 0x11, 6),
+ op_rs_func(0x3f, 0x1f, 0x1f003f), "D,S", 0},
+ {"neg.s", op_rs_func(17, 0x10, 7),
+ op_rs_func(0x3f, 0x1f, 0x1f003f), "D,S", 0},
+ {"neg.d", op_rs_func(17, 0x11, 7),
+ op_rs_func(0x3f, 0x1f, 0x1f003f), "D,S", 0},
+ {"cvt.s.s", op_rs_func(17, 0x10, 32),
+ op_rs_func(0x3f, 0x1f, 0x1f003f), "D,S", 0},
+ {"cvt.s.d", op_rs_func(17, 0x11, 32),
+ op_rs_func(0x3f, 0x1f, 0x1f003f), "D,S", 0},
+ {"cvt.s.w", op_rs_func(17, 0x14, 32),
+ op_rs_func(0x3f, 0x1f, 0x1f003f), "D,S", 0},
+ {"cvt.d.s", op_rs_func(17, 0x10, 33),
+ op_rs_func(0x3f, 0x1f, 0x1f003f), "D,S", 0},
+ {"cvt.d.d", op_rs_func(17, 0x11, 33),
+ op_rs_func(0x3f, 0x1f, 0x1f003f), "D,S", 0},
+ {"cvt.d.w", op_rs_func(17, 0x14, 33),
+ op_rs_func(0x3f, 0x1f, 0x1f003f), "D,S", 0},
+ {"cvt.w.s", op_rs_func(17, 0x10, 36),
+ op_rs_func(0x3f, 0x1f, 0x1f003f), "D,S", 0},
+ {"cvt.w.d", op_rs_func(17, 0x11, 36),
+ op_rs_func(0x3f, 0x1f, 0x1f003f), "D,S", 0},
+ {"c.f.s", op_rs_func(17, 0x10, 48),
+ op_rs_func(0x3f, 0x1f, 0x7ff), "S,T", 0},
+ {"c.f.d", op_rs_func(17, 0x11, 48),
+ op_rs_func(0x3f, 0x1f, 0x7ff), "S,T", 0},
+ {"c.un.s", op_rs_func(17, 0x10, 49),
+ op_rs_func(0x3f, 0x1f, 0x7ff), "S,T", 0},
+ {"c.un.d", op_rs_func(17, 0x11, 49),
+ op_rs_func(0x3f, 0x1f, 0x7ff), "S,T", 0},
+ {"c.eq.s", op_rs_func(17, 0x10, 50),
+ op_rs_func(0x3f, 0x1f, 0x7ff), "S,T", 0},
+ {"c.eq.d", op_rs_func(17, 0x11, 50),
+ op_rs_func(0x3f, 0x1f, 0x7ff), "S,T", 0},
+ {"c.ueq.s", op_rs_func(17, 0x10, 51),
+ op_rs_func(0x3f, 0x1f, 0x7ff), "S,T", 0},
+ {"c.ueq.d", op_rs_func(17, 0x11, 51),
+ op_rs_func(0x3f, 0x1f, 0x7ff), "S,T", 0},
+ {"c.olt.s", op_rs_func(17, 0x10, 52),
+ op_rs_func(0x3f, 0x1f, 0x7ff), "S,T", 0},
+ {"c.olt.d", op_rs_func(17, 0x11, 52),
+ op_rs_func(0x3f, 0x1f, 0x7ff), "S,T", 0},
+ {"c.ult.s", op_rs_func(17, 0x10, 53),
+ op_rs_func(0x3f, 0x1f, 0x7ff), "S,T", 0},
+ {"c.ult.d", op_rs_func(17, 0x11, 53),
+ op_rs_func(0x3f, 0x1f, 0x7ff), "S,T", 0},
+ {"c.ole.s", op_rs_func(17, 0x10, 54),
+ op_rs_func(0x3f, 0x1f, 0x7ff), "S,T", 0},
+ {"c.ole.d", op_rs_func(17, 0x11, 54),
+ op_rs_func(0x3f, 0x1f, 0x7ff), "S,T", 0},
+ {"c.ule.s", op_rs_func(17, 0x10, 55),
+ op_rs_func(0x3f, 0x1f, 0x7ff), "S,T", 0},
+ {"c.ule.d", op_rs_func(17, 0x11, 55),
+ op_rs_func(0x3f, 0x1f, 0x7ff), "S,T", 0},
+ {"c.sf.s", op_rs_func(17, 0x10, 56),
+ op_rs_func(0x3f, 0x1f, 0x7ff), "S,T", 0},
+ {"c.sf.d", op_rs_func(17, 0x11, 56),
+ op_rs_func(0x3f, 0x1f, 0x7ff), "S,T", 0},
+ {"c.ngle.s", op_rs_func(17, 0x10, 57),
+ op_rs_func(0x3f, 0x1f, 0x7ff), "S,T", 0},
+ {"c.ngle.d", op_rs_func(17, 0x11, 57),
+ op_rs_func(0x3f, 0x1f, 0x7ff), "S,T", 0},
+ {"c.seq.s", op_rs_func(17, 0x10, 58),
+ op_rs_func(0x3f, 0x1f, 0x7ff), "S,T", 0},
+ {"c.seq.d", op_rs_func(17, 0x11, 58),
+ op_rs_func(0x3f, 0x1f, 0x7ff), "S,T", 0},
+ {"c.ngl.s", op_rs_func(17, 0x10, 59),
+ op_rs_func(0x3f, 0x1f, 0x7ff), "S,T", 0},
+ {"c.ngl.d", op_rs_func(17, 0x11, 59),
+ op_rs_func(0x3f, 0x1f, 0x7ff), "S,T", 0},
+ {"c.lt.s", op_rs_func(17, 0x10, 60),
+ op_rs_func(0x3f, 0x1f, 0x7ff), "S,T", 0},
+ {"c.lt.d", op_rs_func(17, 0x11, 60),
+ op_rs_func(0x3f, 0x1f, 0x7ff), "S,T", 0},
+ {"c.nge.s", op_rs_func(17, 0x10, 61),
+ op_rs_func(0x3f, 0x1f, 0x7ff), "S,T", 0},
+ {"c.nge.d", op_rs_func(17, 0x11, 61),
+ op_rs_func(0x3f, 0x1f, 0x7ff), "S,T", 0},
+ {"c.le.s", op_rs_func(17, 0x10, 62),
+ op_rs_func(0x3f, 0x1f, 0x7ff), "S,T", 0},
+ {"c.le.d", op_rs_func(17, 0x11, 62),
+ op_rs_func(0x3f, 0x1f, 0x7ff), "S,T", 0},
+ {"c.ngt.s", op_rs_func(17, 0x10, 63),
+ op_rs_func(0x3f, 0x1f, 0x7ff), "S,T", 0},
+ {"c.ngt.d", op_rs_func(17, 0x11, 63),
+ op_rs_func(0x3f, 0x1f, 0x7ff), "S,T", 0},
+
+/* co processor 2 instruction */
+ {"mfc2", op_rs_b11 (18, 0, 0), op_rs_b11(0x3f, 0x1f, 0x1ffff), "t,d", 0},
+ {"cfc2", op_rs_b11 (18, 2, 0), op_rs_b11(0x3f, 0x1f, 0x1ffff), "t,d", 0},
+ {"mtc2", op_rs_b11 (18, 4, 0), op_rs_b11(0x3f, 0x1f, 0x1ffff), "t,d", 0},
+ {"ctc2", op_rs_b11 (18, 6, 0), op_rs_b11(0x3f, 0x1f, 0x1ffff), "t,d", 0},
+ {"bc2f", op_o16(18, 0x100), op_o16(0x3f, 0x3ff), "b", 1},
+ {"bc2f", op_o16(18, 0x180), op_o16(0x3f, 0x3ff), "b", 1},
+ {"bc2f", op_o16(18, 0x101), op_o16(0x3f, 0x3ff), "b", 1},
+ {"bc2t", op_o16(18, 0x181), op_o16(0x3f, 0x3ff), "b", 1},
+
+/* co processor 3 instruction */
+ {"mtc3", op_rs_b11 (19, 0, 0), op_rs_b11(0x3f, 0x1f, 0x1ffff), "t,d", 0},
+ {"cfc3", op_rs_b11 (19, 2, 0), op_rs_b11(0x3f, 0x1f, 0x1ffff), "t,d", 0},
+ {"mtc3", op_rs_b11 (19, 4, 0), op_rs_b11(0x3f, 0x1f, 0x1ffff), "t,d", 0},
+ {"ctc3", op_rs_b11 (19, 6, 0), op_rs_b11(0x3f, 0x1f, 0x1ffff), "t,d", 0},
+ {"bc3f", op_o16(19, 0x100), op_o16(0x3f, 0x3ff), "b", 1},
+ {"bc3f", op_o16(19, 0x180), op_o16(0x3f, 0x3ff), "b", 1},
+ {"bc3t", op_o16(19, 0x101), op_o16(0x3f, 0x3ff), "b", 1},
+ {"bc3t", op_o16(19, 0x181), op_o16(0x3f, 0x3ff), "b", 1},
+
+ {"lb", one(32), one(0x3f), "t,j(s)", 0},
+ {"lh", one(33), one(0x3f), "t,j(s)", 0},
+ {"lwl", one(34), one(0x3f), "t,j(s)", 0},
+ {"lw", one(35), one(0x3f), "t,j(s)", 0},
+ {"lbu", one(36), one(0x3f), "t,j(s)", 0},
+ {"lhu", one(37), one(0x3f), "t,j(s)", 0},
+ {"lwr", one(38), one(0x3f), "t,j(s)", 0},
+ {"sb", one(40), one(0x3f), "t,j(s)", 0},
+ {"sh", one(41), one(0x3f), "t,j(s)", 0},
+ {"swl", one(42), one(0x3f), "t,j(s)", 0},
+ {"swr", one(46), one(0x3f), "t,j(s)", 0},
+ {"sw", one(43), one(0x3f), "t,j(s)", 0},
+ {"lwc0", one(48), one(0x3f), "t,j(s)", 0},
+/* for fpu */
+ {"lwc1", one(49), one(0x3f), "T,j(s)", 0},
+ {"lwc2", one(50), one(0x3f), "t,j(s)", 0},
+ {"lwc3", one(51), one(0x3f), "t,j(s)", 0},
+ {"swc0", one(56), one(0x3f), "t,j(s)", 0},
+/* for fpu */
+ {"swc1", one(57), one(0x3f), "T,j(s)", 0},
+ {"swc2", one(58), one(0x3f), "t,j(s)", 0},
+ {"swc3", one(59), one(0x3f), "t,j(s)", 0},
+};
diff --git a/gnu/usr.bin/as/opcode/np1.h b/gnu/usr.bin/as/opcode/np1.h
new file mode 100644
index 0000000..6546825
--- /dev/null
+++ b/gnu/usr.bin/as/opcode/np1.h
@@ -0,0 +1,422 @@
+/* Print GOULD NPL instructions for GDB, the GNU debugger.
+ Copyright (C) 1986, 1987, 1989 Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+GDB is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 1, or (at your option)
+any later version.
+
+GDB is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GDB; see the file COPYING. If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+struct gld_opcode
+{
+ char *name;
+ unsigned long opcode;
+ unsigned long mask;
+ char *args;
+ int length;
+};
+
+/* We store four bytes of opcode for all opcodes because that
+ is the most any of them need. The actual length of an instruction
+ is always at least 2 bytes, and at most four. The length of the
+ instruction is based on the opcode.
+
+ The mask component is a mask saying which bits must match
+ particular opcode in order for an instruction to be an instance
+ of that opcode.
+
+ The args component is a string containing characters
+ that are used to format the arguments to the instruction. */
+
+/* Kinds of operands:
+ r Register in first field
+ R Register in second field
+ b Base register in first field
+ B Base register in second field
+ v Vector register in first field
+ V Vector register in first field
+ A Optional address register (base register)
+ X Optional index register
+ I Immediate data (16bits signed)
+ O Offset field (16bits signed)
+ h Offset field (15bits signed)
+ d Offset field (14bits signed)
+ S Shift count field
+
+ any other characters are printed as is...
+*/
+
+/* The assembler requires that this array be sorted as follows:
+ all instances of the same mnemonic must be consecutive.
+ All instances of the same mnemonic with the same number of operands
+ must be consecutive.
+ */
+struct gld_opcode gld_opcodes[] =
+{
+{ "lb", 0xb4080000, 0xfc080000, "r,xOA,X", 4 },
+{ "lnb", 0xb8080000, 0xfc080000, "r,xOA,X", 4 },
+{ "lbs", 0xec080000, 0xfc080000, "r,xOA,X", 4 },
+{ "lh", 0xb4000001, 0xfc080001, "r,xOA,X", 4 },
+{ "lnh", 0xb8000001, 0xfc080001, "r,xOA,X", 4 },
+{ "lw", 0xb4000000, 0xfc080000, "r,xOA,X", 4 },
+{ "lnw", 0xb8000000, 0xfc080000, "r,xOA,X", 4 },
+{ "ld", 0xb4000002, 0xfc080002, "r,xOA,X", 4 },
+{ "lnd", 0xb8000002, 0xfc080002, "r,xOA,X", 4 },
+{ "li", 0xf8000000, 0xfc7f0000, "r,I", 4 },
+{ "lpa", 0x50080000, 0xfc080000, "r,xOA,X", 4 },
+{ "la", 0x50000000, 0xfc080000, "r,xOA,X", 4 },
+{ "labr", 0x58080000, 0xfc080000, "b,xOA,X", 4 },
+{ "lbp", 0x90080000, 0xfc080000, "r,xOA,X", 4 },
+{ "lhp", 0x90000001, 0xfc080001, "r,xOA,X", 4 },
+{ "lwp", 0x90000000, 0xfc080000, "r,xOA,X", 4 },
+{ "ldp", 0x90000002, 0xfc080002, "r,xOA,X", 4 },
+{ "suabr", 0x58000000, 0xfc080000, "b,xOA,X", 4 },
+{ "lf", 0xbc000000, 0xfc080000, "r,xOA,X", 4 },
+{ "lfbr", 0xbc080000, 0xfc080000, "b,xOA,X", 4 },
+{ "lwbr", 0x5c000000, 0xfc080000, "b,xOA,X", 4 },
+{ "stb", 0xd4080000, 0xfc080000, "r,xOA,X", 4 },
+{ "sth", 0xd4000001, 0xfc080001, "r,xOA,X", 4 },
+{ "stw", 0xd4000000, 0xfc080000, "r,xOA,X", 4 },
+{ "std", 0xd4000002, 0xfc080002, "r,xOA,X", 4 },
+{ "stf", 0xdc000000, 0xfc080000, "r,xOA,X", 4 },
+{ "stfbr", 0xdc080000, 0xfc080000, "b,xOA,X", 4 },
+{ "stwbr", 0x54000000, 0xfc080000, "b,xOA,X", 4 },
+{ "zmb", 0xd8080000, 0xfc080000, "r,xOA,X", 4 },
+{ "zmh", 0xd8000001, 0xfc080001, "r,xOA,X", 4 },
+{ "zmw", 0xd8000000, 0xfc080000, "r,xOA,X", 4 },
+{ "zmd", 0xd8000002, 0xfc080002, "r,xOA,X", 4 },
+{ "stbp", 0x94080000, 0xfc080000, "r,xOA,X", 4 },
+{ "sthp", 0x94000001, 0xfc080001, "r,xOA,X", 4 },
+{ "stwp", 0x94000000, 0xfc080000, "r,xOA,X", 4 },
+{ "stdp", 0x94000002, 0xfc080002, "r,xOA,X", 4 },
+{ "lil", 0xf80b0000, 0xfc7f0000, "r,D", 4 },
+{ "lwsl1", 0xec000000, 0xfc080000, "r,xOA,X", 4 },
+{ "lwsl2", 0xfc000000, 0xfc080000, "r,xOA,X", 4 },
+{ "lwsl3", 0xfc080000, 0xfc080000, "r,xOA,X", 4 },
+
+{ "lvb", 0xb0080000, 0xfc080000, "v,xOA,X", 4 },
+{ "lvh", 0xb0000001, 0xfc080001, "v,xOA,X", 4 },
+{ "lvw", 0xb0000000, 0xfc080000, "v,xOA,X", 4 },
+{ "lvd", 0xb0000002, 0xfc080002, "v,xOA,X", 4 },
+{ "liv", 0x3c040000, 0xfc0f0000, "v,R", 2 },
+{ "livf", 0x3c080000, 0xfc0f0000, "v,R", 2 },
+{ "stvb", 0xd0080000, 0xfc080000, "v,xOA,X", 4 },
+{ "stvh", 0xd0000001, 0xfc080001, "v,xOA,X", 4 },
+{ "stvw", 0xd0000000, 0xfc080000, "v,xOA,X", 4 },
+{ "stvd", 0xd0000002, 0xfc080002, "v,xOA,X", 4 },
+
+{ "trr", 0x2c000000, 0xfc0f0000, "r,R", 2 },
+{ "trn", 0x2c040000, 0xfc0f0000, "r,R", 2 },
+{ "trnd", 0x2c0c0000, 0xfc0f0000, "r,R", 2 },
+{ "trabs", 0x2c010000, 0xfc0f0000, "r,R", 2 },
+{ "trabsd", 0x2c090000, 0xfc0f0000, "r,R", 2 },
+{ "trc", 0x2c030000, 0xfc0f0000, "r,R", 2 },
+{ "xcr", 0x28040000, 0xfc0f0000, "r,R", 2 },
+{ "cxcr", 0x2c060000, 0xfc0f0000, "r,R", 2 },
+{ "cxcrd", 0x2c0e0000, 0xfc0f0000, "r,R", 2 },
+{ "tbrr", 0x2c020000, 0xfc0f0000, "r,B", 2 },
+{ "trbr", 0x28030000, 0xfc0f0000, "b,R", 2 },
+{ "xcbr", 0x28020000, 0xfc0f0000, "b,B", 2 },
+{ "tbrbr", 0x28010000, 0xfc0f0000, "b,B", 2 },
+
+{ "trvv", 0x28050000, 0xfc0f0000, "v,V", 2 },
+{ "trvvn", 0x2c050000, 0xfc0f0000, "v,V", 2 },
+{ "trvvnd", 0x2c0d0000, 0xfc0f0000, "v,V", 2 },
+{ "trvab", 0x2c070000, 0xfc0f0000, "v,V", 2 },
+{ "trvabd", 0x2c0f0000, 0xfc0f0000, "v,V", 2 },
+{ "cmpv", 0x14060000, 0xfc0f0000, "v,V", 2 },
+{ "expv", 0x14070000, 0xfc0f0000, "v,V", 2 },
+{ "mrvvlt", 0x10030000, 0xfc0f0000, "v,V", 2 },
+{ "mrvvle", 0x10040000, 0xfc0f0000, "v,V", 2 },
+{ "mrvvgt", 0x14030000, 0xfc0f0000, "v,V", 2 },
+{ "mrvvge", 0x14040000, 0xfc0f0000, "v,V", 2 },
+{ "mrvveq", 0x10050000, 0xfc0f0000, "v,V", 2 },
+{ "mrvvne", 0x10050000, 0xfc0f0000, "v,V", 2 },
+{ "mrvrlt", 0x100d0000, 0xfc0f0000, "v,R", 2 },
+{ "mrvrle", 0x100e0000, 0xfc0f0000, "v,R", 2 },
+{ "mrvrgt", 0x140d0000, 0xfc0f0000, "v,R", 2 },
+{ "mrvrge", 0x140e0000, 0xfc0f0000, "v,R", 2 },
+{ "mrvreq", 0x100f0000, 0xfc0f0000, "v,R", 2 },
+{ "mrvrne", 0x140f0000, 0xfc0f0000, "v,R", 2 },
+{ "trvr", 0x140b0000, 0xfc0f0000, "r,V", 2 },
+{ "trrv", 0x140c0000, 0xfc0f0000, "v,R", 2 },
+
+{ "bu", 0x40000000, 0xff880000, "xOA,X", 4 },
+{ "bns", 0x70080000, 0xff880000, "xOA,X", 4 },
+{ "bnco", 0x70880000, 0xff880000, "xOA,X", 4 },
+{ "bge", 0x71080000, 0xff880000, "xOA,X", 4 },
+{ "bne", 0x71880000, 0xff880000, "xOA,X", 4 },
+{ "bunge", 0x72080000, 0xff880000, "xOA,X", 4 },
+{ "bunle", 0x72880000, 0xff880000, "xOA,X", 4 },
+{ "bgt", 0x73080000, 0xff880000, "xOA,X", 4 },
+{ "bnany", 0x73880000, 0xff880000, "xOA,X", 4 },
+{ "bs" , 0x70000000, 0xff880000, "xOA,X", 4 },
+{ "bco", 0x70800000, 0xff880000, "xOA,X", 4 },
+{ "blt", 0x71000000, 0xff880000, "xOA,X", 4 },
+{ "beq", 0x71800000, 0xff880000, "xOA,X", 4 },
+{ "buge", 0x72000000, 0xff880000, "xOA,X", 4 },
+{ "bult", 0x72800000, 0xff880000, "xOA,X", 4 },
+{ "ble", 0x73000000, 0xff880000, "xOA,X", 4 },
+{ "bany", 0x73800000, 0xff880000, "xOA,X", 4 },
+{ "brlnk", 0x44000000, 0xfc080000, "r,xOA,X", 4 },
+{ "bib", 0x48000000, 0xfc080000, "r,xOA,X", 4 },
+{ "bih", 0x48080000, 0xfc080000, "r,xOA,X", 4 },
+{ "biw", 0x4c000000, 0xfc080000, "r,xOA,X", 4 },
+{ "bid", 0x4c080000, 0xfc080000, "r,xOA,X", 4 },
+{ "bivb", 0x60000000, 0xfc080000, "r,xOA,X", 4 },
+{ "bivh", 0x60080000, 0xfc080000, "r,xOA,X", 4 },
+{ "bivw", 0x64000000, 0xfc080000, "r,xOA,X", 4 },
+{ "bivd", 0x64080000, 0xfc080000, "r,xOA,X", 4 },
+{ "bvsb", 0x68000000, 0xfc080000, "r,xOA,X", 4 },
+{ "bvsh", 0x68080000, 0xfc080000, "r,xOA,X", 4 },
+{ "bvsw", 0x6c000000, 0xfc080000, "r,xOA,X", 4 },
+{ "bvsd", 0x6c080000, 0xfc080000, "r,xOA,X", 4 },
+
+{ "camb", 0x80080000, 0xfc080000, "r,xOA,X", 4 },
+{ "camh", 0x80000001, 0xfc080001, "r,xOA,X", 4 },
+{ "camw", 0x80000000, 0xfc080000, "r,xOA,X", 4 },
+{ "camd", 0x80000002, 0xfc080002, "r,xOA,X", 4 },
+{ "car", 0x10000000, 0xfc0f0000, "r,R", 2 },
+{ "card", 0x14000000, 0xfc0f0000, "r,R", 2 },
+{ "ci", 0xf8050000, 0xfc7f0000, "r,I", 4 },
+{ "chkbnd", 0x5c080000, 0xfc080000, "r,xOA,X", 4 },
+
+{ "cavv", 0x10010000, 0xfc0f0000, "v,V", 2 },
+{ "cavr", 0x10020000, 0xfc0f0000, "v,R", 2 },
+{ "cavvd", 0x10090000, 0xfc0f0000, "v,V", 2 },
+{ "cavrd", 0x100b0000, 0xfc0f0000, "v,R", 2 },
+
+{ "anmb", 0x84080000, 0xfc080000, "r,xOA,X", 4 },
+{ "anmh", 0x84000001, 0xfc080001, "r,xOA,X", 4 },
+{ "anmw", 0x84000000, 0xfc080000, "r,xOA,X", 4 },
+{ "anmd", 0x84000002, 0xfc080002, "r,xOA,X", 4 },
+{ "anr", 0x04000000, 0xfc0f0000, "r,R", 2 },
+{ "ani", 0xf8080000, 0xfc7f0000, "r,I", 4 },
+{ "ormb", 0xb8080000, 0xfc080000, "r,xOA,X", 4 },
+{ "ormh", 0xb8000001, 0xfc080001, "r,xOA,X", 4 },
+{ "ormw", 0xb8000000, 0xfc080000, "r,xOA,X", 4 },
+{ "ormd", 0xb8000002, 0xfc080002, "r,xOA,X", 4 },
+{ "orr", 0x08000000, 0xfc0f0000, "r,R", 2 },
+{ "oi", 0xf8090000, 0xfc7f0000, "r,I", 4 },
+{ "eomb", 0x8c080000, 0xfc080000, "r,xOA,X", 4 },
+{ "eomh", 0x8c000001, 0xfc080001, "r,xOA,X", 4 },
+{ "eomw", 0x8c000000, 0xfc080000, "r,xOA,X", 4 },
+{ "eomd", 0x8c000002, 0xfc080002, "r,xOA,X", 4 },
+{ "eor", 0x0c000000, 0xfc0f0000, "r,R", 2 },
+{ "eoi", 0xf80a0000, 0xfc7f0000, "r,I", 4 },
+
+{ "anvv", 0x04010000, 0xfc0f0000, "v,V", 2 },
+{ "anvr", 0x04020000, 0xfc0f0000, "v,R", 2 },
+{ "orvv", 0x08010000, 0xfc0f0000, "v,V", 2 },
+{ "orvr", 0x08020000, 0xfc0f0000, "v,R", 2 },
+{ "eovv", 0x0c010000, 0xfc0f0000, "v,V", 2 },
+{ "eovr", 0x0c020000, 0xfc0f0000, "v,R", 2 },
+
+{ "sacz", 0x100c0000, 0xfc0f0000, "r,R", 2 },
+{ "sla", 0x1c400000, 0xfc600000, "r,S", 2 },
+{ "sll", 0x1c600000, 0xfc600000, "r,S", 2 },
+{ "slc", 0x24400000, 0xfc600000, "r,S", 2 },
+{ "slad", 0x20400000, 0xfc600000, "r,S", 2 },
+{ "slld", 0x20600000, 0xfc600000, "r,S", 2 },
+{ "sra", 0x1c000000, 0xfc600000, "r,S", 2 },
+{ "srl", 0x1c200000, 0xfc600000, "r,S", 2 },
+{ "src", 0x24000000, 0xfc600000, "r,S", 2 },
+{ "srad", 0x20000000, 0xfc600000, "r,S", 2 },
+{ "srld", 0x20200000, 0xfc600000, "r,S", 2 },
+{ "sda", 0x3c030000, 0xfc0f0000, "r,R", 2 },
+{ "sdl", 0x3c020000, 0xfc0f0000, "r,R", 2 },
+{ "sdc", 0x3c010000, 0xfc0f0000, "r,R", 2 },
+{ "sdad", 0x3c0b0000, 0xfc0f0000, "r,R", 2 },
+{ "sdld", 0x3c0a0000, 0xfc0f0000, "r,R", 2 },
+
+{ "svda", 0x3c070000, 0xfc0f0000, "v,R", 2 },
+{ "svdl", 0x3c060000, 0xfc0f0000, "v,R", 2 },
+{ "svdc", 0x3c050000, 0xfc0f0000, "v,R", 2 },
+{ "svdad", 0x3c0e0000, 0xfc0f0000, "v,R", 2 },
+{ "svdld", 0x3c0d0000, 0xfc0f0000, "v,R", 2 },
+
+{ "sbm", 0xac080000, 0xfc080000, "f,xOA,X", 4 },
+{ "zbm", 0xac000000, 0xfc080000, "f,xOA,X", 4 },
+{ "tbm", 0xa8080000, 0xfc080000, "f,xOA,X", 4 },
+{ "incmb", 0xa0000000, 0xfc080000, "xOA,X", 4 },
+{ "incmh", 0xa0080000, 0xfc080000, "xOA,X", 4 },
+{ "incmw", 0xa4000000, 0xfc080000, "xOA,X", 4 },
+{ "incmd", 0xa4080000, 0xfc080000, "xOA,X", 4 },
+{ "sbmd", 0x7c080000, 0xfc080000, "r,xOA,X", 4 },
+{ "zbmd", 0x7c000000, 0xfc080000, "r,xOA,X", 4 },
+{ "tbmd", 0x78080000, 0xfc080000, "r,xOA,X", 4 },
+
+{ "ssm", 0x9c080000, 0xfc080000, "f,xOA,X", 4 },
+{ "zsm", 0x9c000000, 0xfc080000, "f,xOA,X", 4 },
+{ "tsm", 0x98080000, 0xfc080000, "f,xOA,X", 4 },
+
+{ "admb", 0xc8080000, 0xfc080000, "r,xOA,X", 4 },
+{ "admh", 0xc8000001, 0xfc080001, "r,xOA,X", 4 },
+{ "admw", 0xc8000000, 0xfc080000, "r,xOA,X", 4 },
+{ "admd", 0xc8000002, 0xfc080002, "r,xOA,X", 4 },
+{ "adr", 0x38000000, 0xfc0f0000, "r,R", 2 },
+{ "armb", 0xe8080000, 0xfc080000, "r,xOA,X", 4 },
+{ "armh", 0xe8000001, 0xfc080001, "r,xOA,X", 4 },
+{ "armw", 0xe8000000, 0xfc080000, "r,xOA,X", 4 },
+{ "armd", 0xe8000002, 0xfc080002, "r,xOA,X", 4 },
+{ "adi", 0xf8010000, 0xfc0f0000, "r,I", 4 },
+{ "sumb", 0xcc080000, 0xfc080000, "r,xOA,X", 4 },
+{ "sumh", 0xcc000001, 0xfc080001, "r,xOA,X", 4 },
+{ "sumw", 0xcc000000, 0xfc080000, "r,xOA,X", 4 },
+{ "sumd", 0xcc000002, 0xfc080002, "r,xOA,X", 4 },
+{ "sur", 0x3c000000, 0xfc0f0000, "r,R", 2 },
+{ "sui", 0xf8020000, 0xfc0f0000, "r,I", 4 },
+{ "mpmb", 0xc0080000, 0xfc080000, "r,xOA,X", 4 },
+{ "mpmh", 0xc0000001, 0xfc080001, "r,xOA,X", 4 },
+{ "mpmw", 0xc0000000, 0xfc080000, "r,xOA,X", 4 },
+{ "mpr", 0x38020000, 0xfc0f0000, "r,R", 2 },
+{ "mprd", 0x3c0f0000, 0xfc0f0000, "r,R", 2 },
+{ "mpi", 0xf8030000, 0xfc0f0000, "r,I", 4 },
+{ "dvmb", 0xc4080000, 0xfc080000, "r,xOA,X", 4 },
+{ "dvmh", 0xc4000001, 0xfc080001, "r,xOA,X", 4 },
+{ "dvmw", 0xc4000000, 0xfc080000, "r,xOA,X", 4 },
+{ "dvr", 0x380a0000, 0xfc0f0000, "r,R", 2 },
+{ "dvi", 0xf8040000, 0xfc0f0000, "r,I", 4 },
+{ "exs", 0x38080000, 0xfc0f0000, "r,R", 2 },
+
+{ "advv", 0x30000000, 0xfc0f0000, "v,V", 2 },
+{ "advvd", 0x30080000, 0xfc0f0000, "v,V", 2 },
+{ "adrv", 0x34000000, 0xfc0f0000, "v,R", 2 },
+{ "adrvd", 0x34080000, 0xfc0f0000, "v,R", 2 },
+{ "suvv", 0x30010000, 0xfc0f0000, "v,V", 2 },
+{ "suvvd", 0x30090000, 0xfc0f0000, "v,V", 2 },
+{ "surv", 0x34010000, 0xfc0f0000, "v,R", 2 },
+{ "survd", 0x34090000, 0xfc0f0000, "v,R", 2 },
+{ "mpvv", 0x30020000, 0xfc0f0000, "v,V", 2 },
+{ "mprv", 0x34020000, 0xfc0f0000, "v,R", 2 },
+
+{ "adfw", 0xe0080000, 0xfc080000, "r,xOA,X", 4 },
+{ "adfd", 0xe0080002, 0xfc080002, "r,xOA,X", 4 },
+{ "adrfw", 0x38010000, 0xfc0f0000, "r,R", 2 },
+{ "adrfd", 0x38090000, 0xfc0f0000, "r,R", 2 },
+{ "surfw", 0xe0000000, 0xfc080000, "r,xOA,X", 4 },
+{ "surfd", 0xe0000002, 0xfc080002, "r,xOA,X", 4 },
+{ "surfw", 0x38030000, 0xfc0f0000, "r,R", 2 },
+{ "surfd", 0x380b0000, 0xfc0f0000, "r,R", 2 },
+{ "mpfw", 0xe4080000, 0xfc080000, "r,xOA,X", 4 },
+{ "mpfd", 0xe4080002, 0xfc080002, "r,xOA,X", 4 },
+{ "mprfw", 0x38060000, 0xfc0f0000, "r,R", 2 },
+{ "mprfd", 0x380e0000, 0xfc0f0000, "r,R", 2 },
+{ "rfw", 0xe4000000, 0xfc080000, "r,xOA,X", 4 },
+{ "rfd", 0xe4000002, 0xfc080002, "r,xOA,X", 4 },
+{ "rrfw", 0x0c0e0000, 0xfc0f0000, "r", 2 },
+{ "rrfd", 0x0c0f0000, 0xfc0f0000, "r", 2 },
+
+{ "advvfw", 0x30040000, 0xfc0f0000, "v,V", 2 },
+{ "advvfd", 0x300c0000, 0xfc0f0000, "v,V", 2 },
+{ "adrvfw", 0x34040000, 0xfc0f0000, "v,R", 2 },
+{ "adrvfd", 0x340c0000, 0xfc0f0000, "v,R", 2 },
+{ "suvvfw", 0x30050000, 0xfc0f0000, "v,V", 2 },
+{ "suvvfd", 0x300d0000, 0xfc0f0000, "v,V", 2 },
+{ "survfw", 0x34050000, 0xfc0f0000, "v,R", 2 },
+{ "survfd", 0x340d0000, 0xfc0f0000, "v,R", 2 },
+{ "mpvvfw", 0x30060000, 0xfc0f0000, "v,V", 2 },
+{ "mpvvfd", 0x300e0000, 0xfc0f0000, "v,V", 2 },
+{ "mprvfw", 0x34060000, 0xfc0f0000, "v,R", 2 },
+{ "mprvfd", 0x340e0000, 0xfc0f0000, "v,R", 2 },
+{ "rvfw", 0x30070000, 0xfc0f0000, "v", 2 },
+{ "rvfd", 0x300f0000, 0xfc0f0000, "v", 2 },
+
+{ "fltw", 0x38070000, 0xfc0f0000, "r,R", 2 },
+{ "fltd", 0x380f0000, 0xfc0f0000, "r,R", 2 },
+{ "fixw", 0x38050000, 0xfc0f0000, "r,R", 2 },
+{ "fixd", 0x380d0000, 0xfc0f0000, "r,R", 2 },
+{ "cfpds", 0x3c090000, 0xfc0f0000, "r,R", 2 },
+
+{ "fltvw", 0x080d0000, 0xfc0f0000, "v,V", 2 },
+{ "fltvd", 0x080f0000, 0xfc0f0000, "v,V", 2 },
+{ "fixvw", 0x080c0000, 0xfc0f0000, "v,V", 2 },
+{ "fixvd", 0x080e0000, 0xfc0f0000, "v,V", 2 },
+{ "cfpvds", 0x0c0d0000, 0xfc0f0000, "v,V", 2 },
+
+{ "orvrn", 0x000a0000, 0xfc0f0000, "r,V", 2 },
+{ "andvrn", 0x00080000, 0xfc0f0000, "r,V", 2 },
+{ "frsteq", 0x04090000, 0xfc0f0000, "r,V", 2 },
+{ "sigma", 0x0c080000, 0xfc0f0000, "r,V", 2 },
+{ "sigmad", 0x0c0a0000, 0xfc0f0000, "r,V", 2 },
+{ "sigmf", 0x08080000, 0xfc0f0000, "r,V", 2 },
+{ "sigmfd", 0x080a0000, 0xfc0f0000, "r,V", 2 },
+{ "prodf", 0x04080000, 0xfc0f0000, "r,V", 2 },
+{ "prodfd", 0x040a0000, 0xfc0f0000, "r,V", 2 },
+{ "maxv", 0x10080000, 0xfc0f0000, "r,V", 2 },
+{ "maxvd", 0x100a0000, 0xfc0f0000, "r,V", 2 },
+{ "minv", 0x14080000, 0xfc0f0000, "r,V", 2 },
+{ "minvd", 0x140a0000, 0xfc0f0000, "r,V", 2 },
+
+{ "lpsd", 0xf0000000, 0xfc080000, "xOA,X", 4 },
+{ "ldc", 0xf0080000, 0xfc080000, "xOA,X", 4 },
+{ "spm", 0x040c0000, 0xfc0f0000, "r", 2 },
+{ "rpm", 0x040d0000, 0xfc0f0000, "r", 2 },
+{ "tritr", 0x00070000, 0xfc0f0000, "r", 2 },
+{ "trrit", 0x00060000, 0xfc0f0000, "r", 2 },
+{ "rpswt", 0x04080000, 0xfc0f0000, "r", 2 },
+{ "exr", 0xf8070000, 0xfc0f0000, "", 4 },
+{ "halt", 0x00000000, 0xfc0f0000, "", 2 },
+{ "wait", 0x00010000, 0xfc0f0000, "", 2 },
+{ "nop", 0x00020000, 0xfc0f0000, "", 2 },
+{ "eiae", 0x00030000, 0xfc0f0000, "", 2 },
+{ "efae", 0x000d0000, 0xfc0f0000, "", 2 },
+{ "diae", 0x000e0000, 0xfc0f0000, "", 2 },
+{ "dfae", 0x000f0000, 0xfc0f0000, "", 2 },
+{ "spvc", 0xf8060000, 0xfc0f0000, "r,T,N", 4 },
+{ "rdsts", 0x00090000, 0xfc0f0000, "r", 2 },
+{ "setcpu", 0x000c0000, 0xfc0f0000, "r", 2 },
+{ "cmc", 0x000b0000, 0xfc0f0000, "r", 2 },
+{ "trrcu", 0x00040000, 0xfc0f0000, "r", 2 },
+{ "attnio", 0x00050000, 0xfc0f0000, "", 2 },
+{ "fudit", 0x28080000, 0xfc0f0000, "", 2 },
+{ "break", 0x28090000, 0xfc0f0000, "", 2 },
+{ "frzss", 0x280a0000, 0xfc0f0000, "", 2 },
+{ "ripi", 0x04040000, 0xfc0f0000, "r,R", 2 },
+{ "xcp", 0x04050000, 0xfc0f0000, "r", 2 },
+{ "block", 0x04060000, 0xfc0f0000, "", 2 },
+{ "unblock", 0x04070000, 0xfc0f0000, "", 2 },
+{ "trsc", 0x08060000, 0xfc0f0000, "r,R", 2 },
+{ "tscr", 0x08070000, 0xfc0f0000, "r,R", 2 },
+{ "fq", 0x04080000, 0xfc0f0000, "r", 2 },
+{ "flupte", 0x2c080000, 0xfc0f0000, "r", 2 },
+{ "rviu", 0x040f0000, 0xfc0f0000, "", 2 },
+{ "ldel", 0x280c0000, 0xfc0f0000, "r,R", 2 },
+{ "ldu", 0x280d0000, 0xfc0f0000, "r,R", 2 },
+{ "stdecc", 0x280b0000, 0xfc0f0000, "r,R", 2 },
+{ "trpc", 0x08040000, 0xfc0f0000, "r", 2 },
+{ "tpcr", 0x08050000, 0xfc0f0000, "r", 2 },
+{ "ghalt", 0x0c050000, 0xfc0f0000, "r", 2 },
+{ "grun", 0x0c040000, 0xfc0f0000, "", 2 },
+{ "tmpr", 0x2c0a0000, 0xfc0f0000, "r,R", 2 },
+{ "trmp", 0x2c0b0000, 0xfc0f0000, "r,R", 2 },
+
+{ "trrve", 0x28060000, 0xfc0f0000, "r", 2 },
+{ "trver", 0x28070000, 0xfc0f0000, "r", 2 },
+{ "trvlr", 0x280f0000, 0xfc0f0000, "r", 2 },
+
+{ "linkfl", 0x18000000, 0xfc0f0000, "r,R", 2 },
+{ "linkbl", 0x18020000, 0xfc0f0000, "r,R", 2 },
+{ "linkfp", 0x18010000, 0xfc0f0000, "r,R", 2 },
+{ "linkbp", 0x18030000, 0xfc0f0000, "r,R", 2 },
+{ "linkpl", 0x18040000, 0xfc0f0000, "r,R", 2 },
+{ "ulinkl", 0x18080000, 0xfc0f0000, "r,R", 2 },
+{ "ulinkp", 0x18090000, 0xfc0f0000, "r,R", 2 },
+{ "ulinktl", 0x180a0000, 0xfc0f0000, "r,R", 2 },
+{ "ulinktp", 0x180b0000, 0xfc0f0000, "r,R", 2 },
+};
+
+int numopcodes = sizeof(gld_opcodes) / sizeof(gld_opcodes[0]);
+
+struct gld_opcode *endop = gld_opcodes + sizeof(gld_opcodes) /
+ sizeof(gld_opcodes[0]);
diff --git a/gnu/usr.bin/as/opcode/ns32k.h b/gnu/usr.bin/as/opcode/ns32k.h
new file mode 100644
index 0000000..e513e64
--- /dev/null
+++ b/gnu/usr.bin/as/opcode/ns32k.h
@@ -0,0 +1,491 @@
+/* ns32k-opcode.h -- Opcode table for National Semi 32k processor
+ Copyright (C) 1987 Free Software Foundation, Inc.
+
+This file is part of GAS, the GNU Assembler.
+
+GAS is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 1, or (at your option)
+any later version.
+
+GAS is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GAS; see the file COPYING. If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+
+#ifdef TE_SEQUENT
+#define DEF_MODEC 20
+#define DEF_MODEL 21
+#endif
+
+#ifndef DEF_MODEC
+#define DEF_MODEC 20
+#endif
+
+#ifndef DEF_MODEL
+#define DEF_MODEL 20
+#endif
+/*
+ After deciding the instruction entry (via hash.c) the instruction parser
+ will try to match the operands after the instruction to the required set
+ given in the entry operandfield. Every operand will result in a change in
+ the opcode or the addition of data to the opcode.
+ The operands in the source instruction are checked for inconsistent
+ semantics.
+
+ F : 32 bit float general form
+ L : 64 bit float "
+ B : byte "
+ W : word "
+ D : double-word "
+ Q : quad-word "
+ A : double-word gen-address-form ie no regs allowed
+ d : displacement
+ b : displacement - pc relative addressing acb
+ p : displacement - pc relative addressing br bcond bsr cxp
+ q : quick
+ i : immediate (8 bits)
+ This is not a standard ns32k operandtype, it is used to build
+ instructions like svc arg1,arg2
+ Svc is the instruction SuperVisorCall and is sometimes used to
+ call OS-routines from usermode. Some args might be handy!
+ r : register number (3 bits)
+ O : setcfg instruction optionslist
+ C : cinv instruction optionslist
+ S : stringinstruction optionslist
+ U : registerlist save,enter
+ u : registerlist restore,exit
+ M : mmu register
+ P : cpu register
+ g : 3:rd operand of inss or exts instruction
+ G : 4:th operand of inss or exts instruction
+ Those operands are encoded in the same byte.
+ This byte is placed last in the instruction.
+ f : operand of sfsr
+ H : sequent-hack for bsr (Warning)
+
+column 1 instructions
+ 2 number of bits in opcode.
+ 3 number of bits in opcode explicitly
+ determined by the instruction type.
+ 4 opcodeseed, the number we build our opcode
+ from.
+ 5 operandtypes, used by operandparser.
+ 6 size in bytes of immediate
+*/
+struct ns32k_opcode {
+ char *name;
+ unsigned char opcode_id_size; /* not used by the assembler */
+ unsigned char opcode_size;
+ unsigned long opcode_seed;
+ char *operands;
+ unsigned char im_size; /* not used by dissassembler */
+ char *default_args; /* default to those args when none given */
+ char default_modec; /* default to this addr-mode when ambigous
+ ie when the argument of a general addr-mode
+ is a plain constant */
+ char default_model; /* is a plain label */
+};
+
+#ifdef comment
+/* This section was from the gdb version of this file. */
+
+#ifndef ns32k_opcodeT
+#define ns32k_opcodeT int
+#endif /* no ns32k_opcodeT */
+
+struct not_wot /* ns32k opcode table: wot to do with this */
+ /* particular opcode */
+{
+ int obits; /* number of opcode bits */
+ int ibits; /* number of instruction bits */
+ ns32k_opcodeT code; /* op-code (may be > 8 bits!) */
+ char *args; /* how to compile said opcode */
+};
+
+struct not /* ns32k opcode text */
+{
+ char * name; /* opcode name: lowercase string [key] */
+ struct not_wot detail; /* rest of opcode table [datum] */
+};
+
+/* Instructions look like this:
+
+ basic instruction--1, 2, or 3 bytes
+ index byte for operand A, if operand A is indexed--1 byte
+ index byte for operand B, if operand B is indexed--1 byte
+ addressing extension for operand A
+ addressing extension for operand B
+ implied operands
+
+ Operand A is the operand listed first in the following opcode table.
+ Operand B is the operand listed second in the following opcode table.
+ All instructions have at most 2 general operands, so this is enough.
+ The implied operands are associated with operands other than A and B.
+
+ Each operand has a digit and a letter.
+
+ The digit gives the position in the assembly language. The letter,
+ one of the following, tells us what kind of operand it is. */
+
+/* F : 32 bit float
+ * L : 64 bit float
+ * B : byte
+ * W : word
+ * D : double-word
+ * Q : quad-word
+ * d : displacement
+ * q : quick
+ * i : immediate (8 bits)
+ * r : register number (3 bits)
+ * p : displacement - pc relative addressing
+*/
+
+
+#endif /* comment */
+
+static const struct ns32k_opcode ns32k_opcodes[]=
+{
+ { "absf", 14,24, 0x35be, "1F2F", 4, "", DEF_MODEC,DEF_MODEL },
+ { "absl", 14,24, 0x34be, "1L2L", 8, "", DEF_MODEC,DEF_MODEL },
+ { "absb", 14,24, 0x304e, "1B2B", 1, "", DEF_MODEC,DEF_MODEL },
+ { "absw", 14,24, 0x314e, "1W2W", 2, "", DEF_MODEC,DEF_MODEL },
+ { "absd", 14,24, 0x334e, "1D2D", 4, "", DEF_MODEC,DEF_MODEL },
+ { "acbb", 7,16, 0x4c, "2B1q3p", 1, "", DEF_MODEC,DEF_MODEL },
+ { "acbw", 7,16, 0x4d, "2W1q3p", 2, "", DEF_MODEC,DEF_MODEL },
+ { "acbd", 7,16, 0x4f, "2D1q3p", 4, "", DEF_MODEC,DEF_MODEL },
+ { "addf", 14,24, 0x01be, "1F2F", 4, "", DEF_MODEC,DEF_MODEL },
+ { "addl", 14,24, 0x00be, "1L2L", 8, "", DEF_MODEC,DEF_MODEL },
+ { "addb", 6,16, 0x00, "1B2B", 1, "", DEF_MODEC,DEF_MODEL },
+ { "addw", 6,16, 0x01, "1W2W", 2, "", DEF_MODEC,DEF_MODEL },
+ { "addd", 6,16, 0x03, "1D2D", 4, "", DEF_MODEC,DEF_MODEL },
+ { "addcb", 6,16, 0x10, "1B2B", 1, "", DEF_MODEC,DEF_MODEL },
+ { "addcw", 6,16, 0x11, "1W2W", 2, "", DEF_MODEC,DEF_MODEL },
+ { "addcd", 6,16, 0x13, "1D2D", 4, "", DEF_MODEC,DEF_MODEL },
+ { "addpb", 14,24, 0x3c4e, "1B2B", 1, "", DEF_MODEC,DEF_MODEL },
+ { "addpw", 14,24, 0x3d4e, "1W2W", 2, "", DEF_MODEC,DEF_MODEL },
+ { "addpd", 14,24, 0x3f4e, "1D2D", 4, "", DEF_MODEC,DEF_MODEL },
+ { "addqb", 7,16, 0x0c, "2B1q", 1, "", DEF_MODEC,DEF_MODEL },
+ { "addqw", 7,16, 0x0d, "2W1q", 2, "", DEF_MODEC,DEF_MODEL },
+ { "addqd", 7,16, 0x0f, "2D1q", 4, "", DEF_MODEC,DEF_MODEL },
+ { "addr", 6,16, 0x27, "1A2D", 4, "", 21,21 },
+ { "adjspb", 11,16, 0x057c, "1B", 1, "", DEF_MODEC,DEF_MODEL },
+ { "adjspw", 11,16, 0x057d, "1W", 2, "", DEF_MODEC,DEF_MODEL },
+ { "adjspd", 11,16, 0x057f, "1D", 4, "", DEF_MODEC,DEF_MODEL },
+ { "andb", 6,16, 0x28, "1B2B", 1, "", DEF_MODEC,DEF_MODEL },
+ { "andw", 6,16, 0x29, "1W2W", 2, "", DEF_MODEC,DEF_MODEL },
+ { "andd", 6,16, 0x2b, "1D2D", 4, "", DEF_MODEC,DEF_MODEL },
+ { "ashb", 14,24, 0x044e, "1B2B", 1, "", DEF_MODEC,DEF_MODEL },
+ { "ashw", 14,24, 0x054e, "1B2W", 1, "", DEF_MODEC,DEF_MODEL },
+ { "ashd", 14,24, 0x074e, "1B2D", 1, "", DEF_MODEC,DEF_MODEL },
+ { "beq", 8,8, 0x0a, "1p", 0, "", 21,21 },
+ { "bne", 8,8, 0x1a, "1p", 0, "", 21,21 },
+ { "bcs", 8,8, 0x2a, "1p", 0, "", 21,21 },
+ { "bcc", 8,8, 0x3a, "1p", 0, "", 21,21 },
+ { "bhi", 8,8, 0x4a, "1p", 0, "", 21,21 },
+ { "bls", 8,8, 0x5a, "1p", 0, "", 21,21 },
+ { "bgt", 8,8, 0x6a, "1p", 0, "", 21,21 },
+ { "ble", 8,8, 0x7a, "1p", 0, "", 21,21 },
+ { "bfs", 8,8, 0x8a, "1p", 0, "", 21,21 },
+ { "bfc", 8,8, 0x9a, "1p", 0, "", 21,21 },
+ { "blo", 8,8, 0xaa, "1p", 0, "", 21,21 },
+ { "bhs", 8,8, 0xba, "1p", 0, "", 21,21 },
+ { "blt", 8,8, 0xca, "1p", 0, "", 21,21 },
+ { "bge", 8,8, 0xda, "1p", 0, "", 21,21 },
+ { "but", 8,8, 0xea, "1p", 0, "", 21,21 },
+ { "buf", 8,8, 0xfa, "1p", 0, "", 21,21 },
+ { "bicb", 6,16, 0x08, "1B2B", 1, "", DEF_MODEC,DEF_MODEL },
+ { "bicw", 6,16, 0x09, "1W2W", 2, "", DEF_MODEC,DEF_MODEL },
+ { "bicd", 6,16, 0x0b, "1D2D", 4, "", DEF_MODEC,DEF_MODEL },
+ { "bicpsrb", 11,16, 0x17c, "1B", 1, "", DEF_MODEC,DEF_MODEL },
+ { "bicpsrw", 11,16, 0x17d, "1W", 2, "", DEF_MODEC,DEF_MODEL },
+ { "bispsrb", 11,16, 0x37c, "1B", 1, "", DEF_MODEC,DEF_MODEL },
+ { "bispsrw", 11,16, 0x37d, "1W", 2, "", DEF_MODEC,DEF_MODEL },
+ { "bpt", 8,8, 0xf2, "", 0, "", DEF_MODEC,DEF_MODEL },
+ { "br", 8,8, 0xea, "1p", 0, "", 21,21 },
+#ifdef TE_SEQUENT
+ { "bsr", 8,8, 0x02, "1H", 0, "", 21,21 },
+#else
+ { "bsr", 8,8, 0x02, "1p", 0, "", 21,21 },
+#endif
+ { "caseb", 11,16, 0x77c, "1B", 1, "", DEF_MODEC,DEF_MODEL },
+ { "casew", 11,16, 0x77d, "1W", 2, "", DEF_MODEC,DEF_MODEL },
+ { "cased", 11,16, 0x77f, "1D", 4, "", DEF_MODEC,DEF_MODEL },
+ { "cbitb", 14,24, 0x084e, "1B2D", 1, "", DEF_MODEC,DEF_MODEL },
+ { "cbitw", 14,24, 0x094e, "1W2D", 2, "", DEF_MODEC,DEF_MODEL },
+ { "cbitd", 14,24, 0x0b4e, "1D2D", 4, "", DEF_MODEC,DEF_MODEL },
+ { "cbitib", 14,24, 0x0c4e, "1B2D", 1, "", DEF_MODEC,DEF_MODEL },
+ { "cbitiw", 14,24, 0x0d4e, "1W2D", 2, "", DEF_MODEC,DEF_MODEL },
+ { "cbitid", 14,24, 0x0f4e, "1D2D", 4, "", DEF_MODEC,DEF_MODEL },
+ { "checkb", 11,24, 0x0ee, "2A3B1r", 1, "", DEF_MODEC,DEF_MODEL },
+ { "checkw", 11,24, 0x1ee, "2A3W1r", 2, "", DEF_MODEC,DEF_MODEL },
+ { "checkd", 11,24, 0x3ee, "2A3D1r", 4, "", DEF_MODEC,DEF_MODEL },
+ { "cinv", 14,24, 0x271e, "2D1C", 4, "", DEF_MODEC,DEF_MODEL },
+ { "cmpf", 14,24, 0x09be, "1F2F", 4, "", DEF_MODEC,DEF_MODEL },
+ { "cmpl", 14,24, 0x08be, "1L2L", 8, "", DEF_MODEC,DEF_MODEL },
+ { "cmpb", 6,16, 0x04, "1B2B", 1, "", DEF_MODEC,DEF_MODEL },
+ { "cmpw", 6,16, 0x05, "1W2W", 2, "", DEF_MODEC,DEF_MODEL },
+ { "cmpd", 6,16, 0x07, "1D2D", 4, "", DEF_MODEC,DEF_MODEL },
+ { "cmpmb", 14,24, 0x04ce, "1A2A3b", 1, "", DEF_MODEC,DEF_MODEL },
+ { "cmpmw", 14,24, 0x05ce, "1A2A3b", 2, "", DEF_MODEC,DEF_MODEL },
+ { "cmpmd", 14,24, 0x07ce, "1A2A3b", 4, "", DEF_MODEC,DEF_MODEL },
+ { "cmpqb", 7,16, 0x1c, "2B1q", 1, "", DEF_MODEC,DEF_MODEL },
+ { "cmpqw", 7,16, 0x1d, "2W1q", 2, "", DEF_MODEC,DEF_MODEL },
+ { "cmpqd", 7,16, 0x1f, "2D1q", 4, "", DEF_MODEC,DEF_MODEL },
+ { "cmpsb", 16,24, 0x040e, "1S", 0, "[]", DEF_MODEC,DEF_MODEL },
+ { "cmpsw", 16,24, 0x050e, "1S", 0, "[]", DEF_MODEC,DEF_MODEL },
+ { "cmpsd", 16,24, 0x070e, "1S", 0, "[]", DEF_MODEC,DEF_MODEL },
+ { "cmpst", 16,24, 0x840e, "1S", 0, "[]", DEF_MODEC,DEF_MODEL },
+ { "comb", 14,24, 0x344e, "1B2B", 1, "", DEF_MODEC,DEF_MODEL },
+ { "comw", 14,24, 0x354e, "1W2W", 2, "", DEF_MODEC,DEF_MODEL },
+ { "comd", 14,24, 0x374e, "1D2D", 4, "", DEF_MODEC,DEF_MODEL },
+ { "cvtp", 11,24, 0x036e, "2A3D1r", 4, "", DEF_MODEC,DEF_MODEL },
+ { "cxp", 8,8, 0x22, "1p", 0, "", 21,21 },
+ { "cxpd", 11,16, 0x07f, "1A", 4, "", DEF_MODEC,DEF_MODEL },
+ { "deib", 14,24, 0x2cce, "1B2W", 1, "", DEF_MODEC,DEF_MODEL },
+ { "deiw", 14,24, 0x2dce, "1W2D", 2, "", DEF_MODEC,DEF_MODEL },
+ { "deid", 14,24, 0x2fce, "1D2Q", 4, "", DEF_MODEC,DEF_MODEL },
+ { "dia", 8,8, 0xc2, "", 1, "", DEF_MODEC,DEF_MODEL },
+ { "divf", 14,24, 0x21be, "1F2F", 4, "", DEF_MODEC,DEF_MODEL },
+ { "divl", 14,24, 0x20be, "1L2L", 8, "", DEF_MODEC,DEF_MODEL },
+ { "divb", 14,24, 0x3cce, "1B2B", 1, "", DEF_MODEC,DEF_MODEL },
+ { "divw", 14,24, 0x3dce, "1W2W", 2, "", DEF_MODEC,DEF_MODEL },
+ { "divd", 14,24, 0x3fce, "1D2D", 4, "", DEF_MODEC,DEF_MODEL },
+ { "enter", 8,8, 0x82, "1U2d", 0, "", DEF_MODEC,DEF_MODEL },
+ { "exit", 8,8, 0x92, "1u", 0, "", DEF_MODEC,DEF_MODEL },
+ { "extb", 11,24, 0x02e, "2D3B1r4d", 1, "", DEF_MODEC,DEF_MODEL },
+ { "extw", 11,24, 0x12e, "2D3W1r4d", 2, "", DEF_MODEC,DEF_MODEL },
+ { "extd", 11,24, 0x32e, "2D3D1r4d", 4, "", DEF_MODEC,DEF_MODEL },
+ { "extsb", 14,24, 0x0cce, "1D2B3g4G", 1, "", DEF_MODEC,DEF_MODEL },
+ { "extsw", 14,24, 0x0dce, "1D2W3g4G", 2, "", DEF_MODEC,DEF_MODEL },
+ { "extsd", 14,24, 0x0fce, "1D2D3g4G", 4, "", DEF_MODEC,DEF_MODEL },
+ { "ffsb", 14,24, 0x046e, "1B2B", 1, "", DEF_MODEC,DEF_MODEL },
+ { "ffsw", 14,24, 0x056e, "1W2B", 2, "", DEF_MODEC,DEF_MODEL },
+ { "ffsd", 14,24, 0x076e, "1D2B", 4, "", DEF_MODEC,DEF_MODEL },
+ { "flag", 8,8, 0xd2, "", 0, "", DEF_MODEC,DEF_MODEL },
+ { "floorfb", 14,24, 0x3c3e, "1F2B", 4, "", DEF_MODEC,DEF_MODEL },
+ { "floorfw", 14,24, 0x3d3e, "1F2W", 4, "", DEF_MODEC,DEF_MODEL },
+ { "floorfd", 14,24, 0x3f3e, "1F2D", 4, "", DEF_MODEC,DEF_MODEL },
+ { "floorlb", 14,24, 0x383e, "1L2B", 8, "", DEF_MODEC,DEF_MODEL },
+ { "floorlw", 14,24, 0x393e, "1L2W", 8, "", DEF_MODEC,DEF_MODEL },
+ { "floorld", 14,24, 0x3b3e, "1L2D", 8, "", DEF_MODEC,DEF_MODEL },
+ { "ibitb", 14,24, 0x384e, "1B2D", 1, "", DEF_MODEC,DEF_MODEL },
+ { "ibitw", 14,24, 0x394e, "1W2D", 2, "", DEF_MODEC,DEF_MODEL },
+ { "ibitd", 14,24, 0x3b4e, "1D2D", 4, "", DEF_MODEC,DEF_MODEL },
+ { "indexb", 11,24, 0x42e, "2B3B1r", 1, "", DEF_MODEC,DEF_MODEL },
+ { "indexw", 11,24, 0x52e, "2W3W1r", 2, "", DEF_MODEC,DEF_MODEL },
+ { "indexd", 11,24, 0x72e, "2D3D1r", 4, "", DEF_MODEC,DEF_MODEL },
+ { "insb", 11,24, 0x0ae, "2B3B1r4d", 1, "", DEF_MODEC,DEF_MODEL },
+ { "insw", 11,24, 0x1ae, "2W3W1r4d", 2, "", DEF_MODEC,DEF_MODEL },
+ { "insd", 11,24, 0x3ae, "2D3D1r4d", 4, "", DEF_MODEC,DEF_MODEL },
+ { "inssb", 14,24, 0x08ce, "1B2D3g4G", 1, "", DEF_MODEC,DEF_MODEL },
+ { "inssw", 14,24, 0x09ce, "1W2D3g4G", 2, "", DEF_MODEC,DEF_MODEL },
+ { "inssd", 14,24, 0x0bce, "1D2D3g4G", 4, "", DEF_MODEC,DEF_MODEL },
+ { "jsr", 11,16, 0x67f, "1A", 4, "", 21,21 },
+ { "jump", 11,16, 0x27f, "1A", 4, "", 21,21 },
+ { "lfsr", 19,24, 0x00f3e,"1D", 4, "", DEF_MODEC,DEF_MODEL },
+ { "lmr", 15,24, 0x0b1e, "2D1M", 4, "", DEF_MODEC,DEF_MODEL },
+ { "lprb", 7,16, 0x6c, "2B1P", 1, "", DEF_MODEC,DEF_MODEL },
+ { "lprw", 7,16, 0x6d, "2W1P", 2, "", DEF_MODEC,DEF_MODEL },
+ { "lprd", 7,16, 0x6f, "2D1P", 4, "", DEF_MODEC,DEF_MODEL },
+ { "lshb", 14,24, 0x144e, "1B2B", 1, "", DEF_MODEC,DEF_MODEL },
+ { "lshw", 14,24, 0x154e, "1B2W", 1, "", DEF_MODEC,DEF_MODEL },
+ { "lshd", 14,24, 0x174e, "1B2D", 1, "", DEF_MODEC,DEF_MODEL },
+ { "meib", 14,24, 0x24ce, "1B2W", 1, "", DEF_MODEC,DEF_MODEL },
+ { "meiw", 14,24, 0x25ce, "1W2D", 2, "", DEF_MODEC,DEF_MODEL },
+ { "meid", 14,24, 0x27ce, "1D2Q", 4, "", DEF_MODEC,DEF_MODEL },
+ { "modb", 14,24, 0x38ce, "1B2B", 1, "", DEF_MODEC,DEF_MODEL },
+ { "modw", 14,24, 0x39ce, "1W2W", 2, "", DEF_MODEC,DEF_MODEL },
+ { "modd", 14,24, 0x3bce, "1D2D", 4, "", DEF_MODEC,DEF_MODEL },
+ { "movf", 14,24, 0x05be, "1F2F", 4, "", DEF_MODEC,DEF_MODEL },
+ { "movl", 14,24, 0x04be, "1L2L", 8, "", DEF_MODEC,DEF_MODEL },
+ { "movb", 6,16, 0x14, "1B2B", 1, "", DEF_MODEC,DEF_MODEL },
+ { "movw", 6,16, 0x15, "1W2W", 2, "", DEF_MODEC,DEF_MODEL },
+ { "movd", 6,16, 0x17, "1D2D", 4, "", DEF_MODEC,DEF_MODEL },
+ { "movbf", 14,24, 0x043e, "1B2F", 1, "", DEF_MODEC,DEF_MODEL },
+ { "movwf", 14,24, 0x053e, "1W2F", 2, "", DEF_MODEC,DEF_MODEL },
+ { "movdf", 14,24, 0x073e, "1D2F", 4, "", DEF_MODEC,DEF_MODEL },
+ { "movbl", 14,24, 0x003e, "1B2L", 1, "", DEF_MODEC,DEF_MODEL },
+ { "movwl", 14,24, 0x013e, "1W2L", 2, "", DEF_MODEC,DEF_MODEL },
+ { "movdl", 14,24, 0x033e, "1D2L", 4, "", DEF_MODEC,DEF_MODEL },
+ { "movfl", 14,24, 0x1b3e, "1F2L", 4, "", DEF_MODEC,DEF_MODEL },
+ { "movlf", 14,24, 0x163e, "1L2F", 8, "", DEF_MODEC,DEF_MODEL },
+ { "movmb", 14,24, 0x00ce, "1A2A3b", 1, "", DEF_MODEC,DEF_MODEL },
+ { "movmw", 14,24, 0x01ce, "1A2A3b", 2, "", DEF_MODEC,DEF_MODEL },
+ { "movmd", 14,24, 0x03ce, "1A2A3b", 4, "", DEF_MODEC,DEF_MODEL },
+ { "movqb", 7,16, 0x5c, "2B1q", 1, "", DEF_MODEC,DEF_MODEL },
+ { "movqw", 7,16, 0x5d, "2B1q", 2, "", DEF_MODEC,DEF_MODEL },
+ { "movqd", 7,16, 0x5f, "2B1q", 4, "", DEF_MODEC,DEF_MODEL },
+ { "movsb", 16,24, 0x000e, "1S", 0, "[]", DEF_MODEC,DEF_MODEL },
+ { "movsw", 16,24, 0x010e, "1S", 0, "[]", DEF_MODEC,DEF_MODEL },
+ { "movsd", 16,24, 0x030e, "1S", 0, "[]", DEF_MODEC,DEF_MODEL },
+ { "movst", 16,24, 0x800e, "1S", 0, "[]", DEF_MODEC,DEF_MODEL },
+ { "movsub", 14,24, 0x0cae, "1A2A", 1, "", DEF_MODEC,DEF_MODEL },
+ { "movsuw", 14,24, 0x0dae, "1A2A", 2, "", DEF_MODEC,DEF_MODEL },
+ { "movsud", 14,24, 0x0fae, "1A2A", 4, "", DEF_MODEC,DEF_MODEL },
+ { "movusb", 14,24, 0x1cae, "1A2A", 1, "", DEF_MODEC,DEF_MODEL },
+ { "movusw", 14,24, 0x1dae, "1A2A", 2, "", DEF_MODEC,DEF_MODEL },
+ { "movusd", 14,24, 0x1fae, "1A2A", 4, "", DEF_MODEC,DEF_MODEL },
+ { "movxbd", 14,24, 0x1cce, "1B2D", 1, "", DEF_MODEC,DEF_MODEL },
+ { "movxwd", 14,24, 0x1dce, "1W2D", 2, "", DEF_MODEC,DEF_MODEL },
+ { "movxbw", 14,24, 0x10ce, "1B2W", 1, "", DEF_MODEC,DEF_MODEL },
+ { "movzbd", 14,24, 0x18ce, "1B2D", 1, "", DEF_MODEC,DEF_MODEL },
+ { "movzwd", 14,24, 0x19ce, "1W2D", 2, "", DEF_MODEC,DEF_MODEL },
+ { "movzbw", 14,24, 0x14ce, "1B2W", 1, "", DEF_MODEC,DEF_MODEL },
+ { "mulf", 14,24, 0x31be, "1F2F", 4, "", DEF_MODEC,DEF_MODEL },
+ { "mull", 14,24, 0x30be, "1L2L", 8, "", DEF_MODEC,DEF_MODEL },
+ { "mulb", 14,24, 0x20ce, "1B2B", 1, "", DEF_MODEC,DEF_MODEL },
+ { "mulw", 14,24, 0x21ce, "1W2W", 2, "", DEF_MODEC,DEF_MODEL },
+ { "muld", 14,24, 0x23ce, "1D2D", 4, "", DEF_MODEC,DEF_MODEL },
+ { "negf", 14,24, 0x15be, "1F2F", 4, "", DEF_MODEC,DEF_MODEL },
+ { "negl", 14,24, 0x14be, "1L2L", 8, "", DEF_MODEC,DEF_MODEL },
+ { "negb", 14,24, 0x204e, "1B2B", 1, "", DEF_MODEC,DEF_MODEL },
+ { "negw", 14,24, 0x214e, "1W2W", 2, "", DEF_MODEC,DEF_MODEL },
+ { "negd", 14,24, 0x234e, "1D2D", 4, "", DEF_MODEC,DEF_MODEL },
+ { "nop", 8,8, 0xa2, "", 0, "", DEF_MODEC,DEF_MODEL },
+ { "notb", 14,24, 0x244e, "1B2B", 1, "", DEF_MODEC,DEF_MODEL },
+ { "notw", 14,24, 0x254e, "1W2W", 2, "", DEF_MODEC,DEF_MODEL },
+ { "notd", 14,24, 0x274e, "1D2D", 4, "", DEF_MODEC,DEF_MODEL },
+ { "orb", 6,16, 0x18, "1B2B", 1, "", DEF_MODEC,DEF_MODEL },
+ { "orw", 6,16, 0x19, "1W2W", 2, "", DEF_MODEC,DEF_MODEL },
+ { "ord", 6,16, 0x1b, "1D2D", 4, "", DEF_MODEC,DEF_MODEL },
+ { "quob", 14,24, 0x30ce, "1B2B", 1, "", DEF_MODEC,DEF_MODEL },
+ { "quow", 14,24, 0x31ce, "1W2W", 2, "", DEF_MODEC,DEF_MODEL },
+ { "quod", 14,24, 0x33ce, "1D2D", 4, "", DEF_MODEC,DEF_MODEL },
+ { "rdval", 19,24, 0x0031e,"1A", 4, "", DEF_MODEC,DEF_MODEL },
+ { "remb", 14,24, 0x34ce, "1B2B", 1, "", DEF_MODEC,DEF_MODEL },
+ { "remw", 14,24, 0x35ce, "1W2W", 2, "", DEF_MODEC,DEF_MODEL },
+ { "remd", 14,24, 0x37ce, "1D2D", 4, "", DEF_MODEC,DEF_MODEL },
+ { "restore", 8,8, 0x72, "1u", 0, "", DEF_MODEC,DEF_MODEL },
+ { "ret", 8,8, 0x12, "1d", 0, "", DEF_MODEC,DEF_MODEL },
+ { "reti", 8,8, 0x52, "", 0, "", DEF_MODEC,DEF_MODEL },
+ { "rett", 8,8, 0x42, "1d", 0, "", DEF_MODEC,DEF_MODEL },
+ { "rotb", 14,24, 0x004e, "1B2B", 1, "", DEF_MODEC,DEF_MODEL },
+ { "rotw", 14,24, 0x014e, "1B2W", 1, "", DEF_MODEC,DEF_MODEL },
+ { "rotd", 14,24, 0x034e, "1B2D", 1, "", DEF_MODEC,DEF_MODEL },
+ { "roundfb", 14,24, 0x243e, "1F2B", 4, "", DEF_MODEC,DEF_MODEL },
+ { "roundfw", 14,24, 0x253e, "1F2W", 4, "", DEF_MODEC,DEF_MODEL },
+ { "roundfd", 14,24, 0x273e, "1F2D", 4, "", DEF_MODEC,DEF_MODEL },
+ { "roundlb", 14,24, 0x203e, "1L2B", 8, "", DEF_MODEC,DEF_MODEL },
+ { "roundlw", 14,24, 0x213e, "1L2W", 8, "", DEF_MODEC,DEF_MODEL },
+ { "roundld", 14,24, 0x233e, "1L2D", 8, "", DEF_MODEC,DEF_MODEL },
+ { "rxp", 8,8, 0x32, "1d", 0, "", DEF_MODEC,DEF_MODEL },
+ { "seqb", 11,16, 0x3c, "1B", 0, "", DEF_MODEC,DEF_MODEL },
+ { "seqw", 11,16, 0x3d, "1W", 0, "", DEF_MODEC,DEF_MODEL },
+ { "seqd", 11,16, 0x3f, "1D", 0, "", DEF_MODEC,DEF_MODEL },
+ { "sneb", 11,16, 0xbc, "1B", 0, "", DEF_MODEC,DEF_MODEL },
+ { "snew", 11,16, 0xbd, "1W", 0, "", DEF_MODEC,DEF_MODEL },
+ { "sned", 11,16, 0xbf, "1D", 0, "", DEF_MODEC,DEF_MODEL },
+ { "scsb", 11,16, 0x13c, "1B", 0, "", DEF_MODEC,DEF_MODEL },
+ { "scsw", 11,16, 0x13d, "1W", 0, "", DEF_MODEC,DEF_MODEL },
+ { "scsd", 11,16, 0x13f, "1D", 0, "", DEF_MODEC,DEF_MODEL },
+ { "sccb", 11,16, 0x1bc, "1B", 0, "", DEF_MODEC,DEF_MODEL },
+ { "sccw", 11,16, 0x1bd, "1W", 0, "", DEF_MODEC,DEF_MODEL },
+ { "sccd", 11,16, 0x1bf, "1D", 0, "", DEF_MODEC,DEF_MODEL },
+ { "shib", 11,16, 0x23c, "1B", 0, "", DEF_MODEC,DEF_MODEL },
+ { "shiw", 11,16, 0x23d, "1W", 0, "", DEF_MODEC,DEF_MODEL },
+ { "shid", 11,16, 0x23f, "1D", 0, "", DEF_MODEC,DEF_MODEL },
+ { "slsb", 11,16, 0x2bc, "1B", 0, "", DEF_MODEC,DEF_MODEL },
+ { "slsw", 11,16, 0x2bd, "1W", 0, "", DEF_MODEC,DEF_MODEL },
+ { "slsd", 11,16, 0x2bf, "1D", 0, "", DEF_MODEC,DEF_MODEL },
+ { "sgtb", 11,16, 0x33c, "1B", 0, "", DEF_MODEC,DEF_MODEL },
+ { "sgtw", 11,16, 0x33d, "1W", 0, "", DEF_MODEC,DEF_MODEL },
+ { "sgtd", 11,16, 0x33f, "1D", 0, "", DEF_MODEC,DEF_MODEL },
+ { "sleb", 11,16, 0x3bc, "1B", 0, "", DEF_MODEC,DEF_MODEL },
+ { "slew", 11,16, 0x3bd, "1W", 0, "", DEF_MODEC,DEF_MODEL },
+ { "sled", 11,16, 0x3bf, "1D", 0, "", DEF_MODEC,DEF_MODEL },
+ { "sfsb", 11,16, 0x43c, "1B", 0, "", DEF_MODEC,DEF_MODEL },
+ { "sfsw", 11,16, 0x43d, "1W", 0, "", DEF_MODEC,DEF_MODEL },
+ { "sfsd", 11,16, 0x43f, "1D", 0, "", DEF_MODEC,DEF_MODEL },
+ { "sfcb", 11,16, 0x4bc, "1B", 0, "", DEF_MODEC,DEF_MODEL },
+ { "sfcw", 11,16, 0x4bd, "1W", 0, "", DEF_MODEC,DEF_MODEL },
+ { "sfcd", 11,16, 0x4bf, "1D", 0, "", DEF_MODEC,DEF_MODEL },
+ { "slob", 11,16, 0x53c, "1B", 0, "", DEF_MODEC,DEF_MODEL },
+ { "slow", 11,16, 0x53d, "1W", 0, "", DEF_MODEC,DEF_MODEL },
+ { "slod", 11,16, 0x53f, "1D", 0, "", DEF_MODEC,DEF_MODEL },
+ { "shsb", 11,16, 0x5bc, "1B", 0, "", DEF_MODEC,DEF_MODEL },
+ { "shsw", 11,16, 0x5bd, "1W", 0, "", DEF_MODEC,DEF_MODEL },
+ { "shsd", 11,16, 0x5bf, "1D", 0, "", DEF_MODEC,DEF_MODEL },
+ { "sltb", 11,16, 0x63c, "1B", 0, "", DEF_MODEC,DEF_MODEL },
+ { "sltw", 11,16, 0x63d, "1W", 0, "", DEF_MODEC,DEF_MODEL },
+ { "sltd", 11,16, 0x63f, "1D", 0, "", DEF_MODEC,DEF_MODEL },
+ { "sgeb", 11,16, 0x6bc, "1B", 0, "", DEF_MODEC,DEF_MODEL },
+ { "sgew", 11,16, 0x6bd, "1W", 0, "", DEF_MODEC,DEF_MODEL },
+ { "sged", 11,16, 0x6bf, "1D", 0, "", DEF_MODEC,DEF_MODEL },
+ { "sutb", 11,16, 0x73c, "1B", 0, "", DEF_MODEC,DEF_MODEL },
+ { "sutw", 11,16, 0x73d, "1W", 0, "", DEF_MODEC,DEF_MODEL },
+ { "sutd", 11,16, 0x73f, "1D", 0, "", DEF_MODEC,DEF_MODEL },
+ { "sufb", 11,16, 0x7bc, "1B", 0, "", DEF_MODEC,DEF_MODEL },
+ { "sufw", 11,16, 0x7bd, "1W", 0, "", DEF_MODEC,DEF_MODEL },
+ { "sufd", 11,16, 0x7bf, "1D", 0, "", DEF_MODEC,DEF_MODEL },
+ { "save", 8,8, 0x62, "1U", 0, "", DEF_MODEC,DEF_MODEL },
+ { "sbitb", 14,24, 0x184e, "1B2A", 1, "", DEF_MODEC,DEF_MODEL },
+ { "sbitw", 14,24, 0x194e, "1W2A", 2, "", DEF_MODEC,DEF_MODEL },
+ { "sbitd", 14,24, 0x1b4e, "1D2A", 4, "", DEF_MODEC,DEF_MODEL },
+ { "sbitib", 14,24, 0x1c4e, "1B2A", 1, "", DEF_MODEC,DEF_MODEL },
+ { "sbitiw", 14,24, 0x1d4e, "1W2A", 2, "", DEF_MODEC,DEF_MODEL },
+ { "sbitid", 14,24, 0x1f4e, "1D2A", 4, "", DEF_MODEC,DEF_MODEL },
+ { "setcfg", 15,24, 0x0b0e, "1O", 0, "", DEF_MODEC,DEF_MODEL },
+ { "sfsr", 14,24, 0x373e, "1f", 0, "", DEF_MODEC,DEF_MODEL },
+ { "skpsb", 16,24, 0x0c0e, "1S", 0, "[]", DEF_MODEC,DEF_MODEL },
+ { "skpsw", 16,24, 0x0d0e, "1S", 0, "[]", DEF_MODEC,DEF_MODEL },
+ { "skpsd", 16,24, 0x0f0e, "1S", 0, "[]", DEF_MODEC,DEF_MODEL },
+ { "skpst", 16,24, 0x8c0e, "1S", 0, "[]", DEF_MODEC,DEF_MODEL },
+ { "smr", 15,24, 0x0f1e, "2D1M", 4, "", DEF_MODEC,DEF_MODEL },
+ { "sprb", 7,16, 0x2c, "2B1P", 1, "", DEF_MODEC,DEF_MODEL },
+ { "sprw", 7,16, 0x2d, "2W1P", 2, "", DEF_MODEC,DEF_MODEL },
+ { "sprd", 7,16, 0x2f, "2D1P", 4, "", DEF_MODEC,DEF_MODEL },
+ { "subf", 14,24, 0x11be, "1F2F", 4, "", DEF_MODEC,DEF_MODEL },
+ { "subl", 14,24, 0x10be, "1L2L", 8, "", DEF_MODEC,DEF_MODEL },
+ { "subb", 6,16, 0x20, "1B2B", 1, "", DEF_MODEC,DEF_MODEL },
+ { "subw", 6,16, 0x21, "1W2W", 2, "", DEF_MODEC,DEF_MODEL },
+ { "subd", 6,16, 0x23, "1D2D", 4, "", DEF_MODEC,DEF_MODEL },
+ { "subcb", 6,16, 0x30, "1B2B", 1, "", DEF_MODEC,DEF_MODEL },
+ { "subcw", 6,16, 0x31, "1W2W", 2, "", DEF_MODEC,DEF_MODEL },
+ { "subcd", 6,16, 0x33, "1D2D", 4, "", DEF_MODEC,DEF_MODEL },
+ { "subpb", 14,24, 0x2c4e, "1B2B", 1, "", DEF_MODEC,DEF_MODEL },
+ { "subpw", 14,24, 0x2d4e, "1W2W", 2, "", DEF_MODEC,DEF_MODEL },
+ { "subpd", 14,24, 0x2f4e, "1D2D", 4, "", DEF_MODEC,DEF_MODEL },
+#ifdef NS32K_SVC_IMMED_OPERANDS
+ { "svc", 8,8, 0xe2, "2i1i", 1, "", DEF_MODEC,DEF_MODEL }, /* not really, but unix uses it */
+#else
+ { "svc", 8,8, 0xe2, "", 0, "", DEF_MODEC,DEF_MODEL },
+#endif
+ { "tbitb", 6,16, 0x34, "1B2A", 1, "", DEF_MODEC,DEF_MODEL },
+ { "tbitw", 6,16, 0x35, "1W2A", 2, "", DEF_MODEC,DEF_MODEL },
+ { "tbitd", 6,16, 0x37, "1D2A", 4, "", DEF_MODEC,DEF_MODEL },
+ { "truncfb", 14,24, 0x2c3e, "1F2B", 4, "", DEF_MODEC,DEF_MODEL },
+ { "truncfw", 14,24, 0x2d3e, "1F2W", 4, "", DEF_MODEC,DEF_MODEL },
+ { "truncfd", 14,24, 0x2f3e, "1F2D", 4, "", DEF_MODEC,DEF_MODEL },
+ { "trunclb", 14,24, 0x283e, "1L2B", 8, "", DEF_MODEC,DEF_MODEL },
+ { "trunclw", 14,24, 0x293e, "1L2W", 8, "", DEF_MODEC,DEF_MODEL },
+ { "truncld", 14,24, 0x2b3e, "1L2D", 8, "", DEF_MODEC,DEF_MODEL },
+ { "wait", 8,8, 0xb2, "", 0, "", DEF_MODEC,DEF_MODEL },
+ { "wrval", 19,24, 0x0071e,"1A", 0, "", DEF_MODEC,DEF_MODEL },
+ { "xorb", 6,16, 0x38, "1B2B", 1, "", DEF_MODEC,DEF_MODEL },
+ { "xorw", 6,16, 0x39, "1W2W", 2, "", DEF_MODEC,DEF_MODEL },
+ { "xord", 6,16, 0x3b, "1D2D", 4, "", DEF_MODEC,DEF_MODEL },
+#if defined(NS32381) /* I'm not too sure of these */
+ { "dotf", 14,24, 0x0dfe, "1F2F", 4, "", DEF_MODEC,DEF_MODEL },
+ { "dotl", 14,24, 0x0cfe, "1L2L", 8, "", DEF_MODEC,DEF_MODEL },
+ { "logbf", 14,24, 0x15fe, "1F2F", 4, "", DEF_MODEC,DEF_MODEL },
+ { "logbl", 14,24, 0x14fe, "1L2L", 8, "", DEF_MODEC,DEF_MODEL },
+ { "polyf", 14,24, 0x09fe, "1F2F", 4, "", DEF_MODEC,DEF_MODEL },
+ { "polyl", 14,24, 0x08fe, "1L2L", 8, "", DEF_MODEC,DEF_MODEL },
+ { "scalbf", 14,24, 0x11fe, "1F2F", 4, "", DEF_MODEC,DEF_MODEL },
+ { "scalbl", 14,24, 0x10fe, "1L2L", 8, "", DEF_MODEC,DEF_MODEL },
+#endif
+};
+
+static const int numopcodes=sizeof(ns32k_opcodes)/sizeof(ns32k_opcodes[0]);
+
+static const struct ns32k_opcode *endop = ns32k_opcodes+sizeof(ns32k_opcodes)/sizeof(ns32k_opcodes[0]);
+
+#define MAX_ARGS 4
+#define ARG_LEN 50
+
diff --git a/gnu/usr.bin/as/opcode/pn.h b/gnu/usr.bin/as/opcode/pn.h
new file mode 100644
index 0000000..fde4764
--- /dev/null
+++ b/gnu/usr.bin/as/opcode/pn.h
@@ -0,0 +1,282 @@
+/* Print GOULD PN (PowerNode) instructions for GDB, the GNU debugger.
+ Copyright (C) 1986, 1987, 1989 Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+GDB is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 1, or (at your option)
+any later version.
+
+GDB is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GDB; see the file COPYING. If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+struct gld_opcode
+{
+ char *name;
+ unsigned long opcode;
+ unsigned long mask;
+ char *args;
+ int length;
+};
+
+/* We store four bytes of opcode for all opcodes because that
+ is the most any of them need. The actual length of an instruction
+ is always at least 2 bytes, and at most four. The length of the
+ instruction is based on the opcode.
+
+ The mask component is a mask saying which bits must match
+ particular opcode in order for an instruction to be an instance
+ of that opcode.
+
+ The args component is a string containing characters
+ that are used to format the arguments to the instruction. */
+
+/* Kinds of operands:
+ r Register in first field
+ R Register in second field
+ b Base register in first field
+ B Base register in second field
+ v Vector register in first field
+ V Vector register in first field
+ A Optional address register (base register)
+ X Optional index register
+ I Immediate data (16bits signed)
+ O Offset field (16bits signed)
+ h Offset field (15bits signed)
+ d Offset field (14bits signed)
+ S Shift count field
+
+ any other characters are printed as is...
+*/
+
+/* The assembler requires that this array be sorted as follows:
+ all instances of the same mnemonic must be consecutive.
+ All instances of the same mnemonic with the same number of operands
+ must be consecutive.
+ */
+struct gld_opcode gld_opcodes[] =
+{
+{ "abm", 0xa0080000, 0xfc080000, "f,xOA,X", 4 },
+{ "abr", 0x18080000, 0xfc0c0000, "r,f", 2 },
+{ "aci", 0xfc770000, 0xfc7f8000, "r,I", 4 },
+{ "adfd", 0xe0080002, 0xfc080002, "r,xOA,X", 4 },
+{ "adfw", 0xe0080000, 0xfc080000, "r,xOA,X", 4 },
+{ "adi", 0xc8010000, 0xfc7f0000, "r,I", 4 },
+{ "admb", 0xb8080000, 0xfc080000, "r,xOA,X", 4 },
+{ "admd", 0xb8000002, 0xfc080002, "r,xOA,X", 4 },
+{ "admh", 0xb8000001, 0xfc080001, "r,xOA,X", 4 },
+{ "admw", 0xb8000000, 0xfc080000, "r,xOA,X", 4 },
+{ "adr", 0x38000000, 0xfc0f0000, "r,R", 2 },
+{ "adrfd", 0x38090000, 0xfc0f0000, "r,R", 2 },
+{ "adrfw", 0x38010000, 0xfc0f0000, "r,R", 2 },
+{ "adrm", 0x38080000, 0xfc0f0000, "r,R", 2 },
+{ "ai", 0xfc030000, 0xfc07ffff, "I", 4 },
+{ "anmb", 0x84080000, 0xfc080000, "r,xOA,X", 4 },
+{ "anmd", 0x84000002, 0xfc080002, "r,xOA,X", 4 },
+{ "anmh", 0x84000001, 0xfc080001, "r,xOA,X", 4 },
+{ "anmw", 0x84000000, 0xfc080000, "r,xOA,X", 4 },
+{ "anr", 0x04000000, 0xfc0f0000, "r,R", 2 },
+{ "armb", 0xe8080000, 0xfc080000, "r,xOA,X", 4 },
+{ "armd", 0xe8000002, 0xfc080002, "r,xOA,X", 4 },
+{ "armh", 0xe8000001, 0xfc080001, "r,xOA,X", 4 },
+{ "armw", 0xe8000000, 0xfc080000, "r,xOA,X", 4 },
+{ "bcf", 0xf0000000, 0xfc080000, "I,xOA,X", 4 },
+{ "bct", 0xec000000, 0xfc080000, "I,xOA,X", 4 },
+{ "bei", 0x00060000, 0xffff0000, "", 2 },
+{ "bft", 0xf0000000, 0xff880000, "xOA,X", 4 },
+{ "bib", 0xf4000000, 0xfc780000, "r,xOA", 4 },
+{ "bid", 0xf4600000, 0xfc780000, "r,xOA", 4 },
+{ "bih", 0xf4200000, 0xfc780000, "r,xOA", 4 },
+{ "biw", 0xf4400000, 0xfc780000, "r,xOA", 4 },
+{ "bl", 0xf8800000, 0xff880000, "xOA,X", 4 },
+{ "bsub", 0x5c080000, 0xff8f0000, "", 2 },
+{ "bsubm", 0x28080000, 0xfc080000, "", 4 },
+{ "bu", 0xec000000, 0xff880000, "xOA,X", 4 },
+{ "call", 0x28080000, 0xfc0f0000, "", 2 },
+{ "callm", 0x5c080000, 0xff880000, "", 4 },
+{ "camb", 0x90080000, 0xfc080000, "r,xOA,X", 4 },
+{ "camd", 0x90000002, 0xfc080002, "r,xOA,X", 4 },
+{ "camh", 0x90000001, 0xfc080001, "r,xOA,X", 4 },
+{ "camw", 0x90000000, 0xfc080000, "r.xOA,X", 4 },
+{ "car", 0x10000000, 0xfc0f0000, "r,R", 2 },
+{ "cd", 0xfc060000, 0xfc070000, "r,f", 4 },
+{ "cea", 0x000f0000, 0xffff0000, "", 2 },
+{ "ci", 0xc8050000, 0xfc7f0000, "r,I", 4 },
+{ "cmc", 0x040a0000, 0xfc7f0000, "r", 2 },
+{ "cmmb", 0x94080000, 0xfc080000, "r,xOA,X", 4 },
+{ "cmmd", 0x94000002, 0xfc080002, "r,xOA,X", 4 },
+{ "cmmh", 0x94000001, 0xfc080001, "r,xOA,X", 4 },
+{ "cmmw", 0x94000000, 0xfc080000, "r,xOA,X", 4 },
+{ "cmr", 0x14000000, 0xfc0f0000, "r,R", 2 },
+{ "daci", 0xfc7f0000, 0xfc7f8000, "r,I", 4 },
+{ "dae", 0x000e0000, 0xffff0000, "", 2 },
+{ "dai", 0xfc040000, 0xfc07ffff, "I", 4 },
+{ "dci", 0xfc6f0000, 0xfc7f8000, "r,I", 4 },
+{ "di", 0xfc010000, 0xfc07ffff, "I", 4 },
+{ "dvfd", 0xe4000002, 0xfc080002, "r,xOA,X", 4 },
+{ "dvfw", 0xe4000000, 0xfc080000, "r,xOA,X", 4 },
+{ "dvi", 0xc8040000, 0xfc7f0000, "r,I", 4 },
+{ "dvmb", 0xc4080000, 0xfc080000, "r,xOA,X", 4 },
+{ "dvmh", 0xc4000001, 0xfc080001, "r,xOA,X", 4 },
+{ "dvmw", 0xc4000000, 0xfc080000, "r,xOA,X", 4 },
+{ "dvr", 0x380a0000, 0xfc0f0000, "r,R", 2 },
+{ "dvrfd", 0x380c0000, 0xfc0f0000, "r,R", 4 },
+{ "dvrfw", 0x38040000, 0xfc0f0000, "r,xOA,X", 4 },
+{ "eae", 0x00080000, 0xffff0000, "", 2 },
+{ "eci", 0xfc670000, 0xfc7f8080, "r,I", 4 },
+{ "ecwcs", 0xfc4f0000, 0xfc7f8000, "", 4 },
+{ "ei", 0xfc000000, 0xfc07ffff, "I", 4 },
+{ "eomb", 0x8c080000, 0xfc080000, "r,xOA,X", 4 },
+{ "eomd", 0x8c000002, 0xfc080002, "r,xOA,X", 4 },
+{ "eomh", 0x8c000001, 0xfc080001, "r,xOA,X", 4 },
+{ "eomw", 0x8c000000, 0xfc080000, "r,xOA,X", 4 },
+{ "eor", 0x0c000000, 0xfc0f0000, "r,R", 2 },
+{ "eorm", 0x0c080000, 0xfc0f0000, "r,R", 2 },
+{ "es", 0x00040000, 0xfc7f0000, "r", 2 },
+{ "exm", 0xa8000000, 0xff880000, "xOA,X", 4 },
+{ "exr", 0xc8070000, 0xfc7f0000, "r", 2 },
+{ "exrr", 0xc8070002, 0xfc7f0002, "r", 2 },
+{ "fixd", 0x380d0000, 0xfc0f0000, "r,R", 2 },
+{ "fixw", 0x38050000, 0xfc0f0000, "r,R", 2 },
+{ "fltd", 0x380f0000, 0xfc0f0000, "r,R", 2 },
+{ "fltw", 0x38070000, 0xfc0f0000, "r,R", 2 },
+{ "grio", 0xfc3f0000, 0xfc7f8000, "r,I", 4 },
+{ "halt", 0x00000000, 0xffff0000, "", 2 },
+{ "hio", 0xfc370000, 0xfc7f8000, "r,I", 4 },
+{ "jwcs", 0xfa080000, 0xff880000, "xOA,X", 4 },
+{ "la", 0x50000000, 0xfc000000, "r,xOA,X", 4 },
+{ "labr", 0x58080000, 0xfc080000, "b,xOA,X", 4 },
+{ "lb", 0xac080000, 0xfc080000, "r,xOA,X", 4 },
+{ "lcs", 0x00030000, 0xfc7f0000, "r", 2 },
+{ "ld", 0xac000002, 0xfc080002, "r,xOA,X", 4 },
+{ "lear", 0x80000000, 0xfc080000, "r,xOA,X", 4 },
+{ "lf", 0xcc000000, 0xfc080000, "r,xOA,X", 4 },
+{ "lfbr", 0xcc080000, 0xfc080000, "b,xOA,X", 4 },
+{ "lh", 0xac000001, 0xfc080001, "r,xOA,X", 4 },
+{ "li", 0xc8000000, 0xfc7f0000, "r,I", 4 },
+{ "lmap", 0x2c070000, 0xfc7f0000, "r", 2 },
+{ "lmb", 0xb0080000, 0xfc080000, "r,xOA,X", 4 },
+{ "lmd", 0xb0000002, 0xfc080002, "r,xOA,X", 4 },
+{ "lmh", 0xb0000001, 0xfc080001, "r,xOA,X", 4 },
+{ "lmw", 0xb0000000, 0xfc080000, "r,xOA,X", 4 },
+{ "lnb", 0xb4080000, 0xfc080000, "r,xOA,X", 4 },
+{ "lnd", 0xb4000002, 0xfc080002, "r,xOA,X", 4 },
+{ "lnh", 0xb4000001, 0xfc080001, "r,xOA,X", 4 },
+{ "lnw", 0xb4000000, 0xfc080000, "r,xOA,X", 4 },
+{ "lpsd", 0xf9800000, 0xff880000, "r,xOA,X", 4 },
+{ "lpsdcm", 0xfa800000, 0xff880000, "r,xOA,X", 4 },
+{ "lw", 0xac000000, 0xfc080000, "r,xOA,X", 4 },
+{ "lwbr", 0x5c000000, 0xfc080000, "b,xOA,X", 4 },
+{ "mpfd", 0xe4080002, 0xfc080002, "r,xOA,X", 4 },
+{ "mpfw", 0xe4080000, 0xfc080000, "r,xOA,X", 4 },
+{ "mpi", 0xc8030000, 0xfc7f0000, "r,I", 4 },
+{ "mpmb", 0xc0080000, 0xfc080000, "r,xOA,X", 4 },
+{ "mpmh", 0xc0000001, 0xfc080001, "r,xOA,X", 4 },
+{ "mpmw", 0xc0000000, 0xfc080000, "r,xOA,X", 4 },
+{ "mpr", 0x38020000, 0xfc0f0000, "r,R", 2 },
+{ "mprfd", 0x380e0000, 0xfc0f0000, "r,R", 2 },
+{ "mprfw", 0x38060000, 0xfc0f0000, "r,R", 2 },
+{ "nop", 0x00020000, 0xffff0000, "", 2 },
+{ "ormb", 0x88080000, 0xfc080000, "r,xOA,X", 4 },
+{ "ormd", 0x88000002, 0xfc080002, "r,xOA,X", 4 },
+{ "ormh", 0x88000001, 0xfc080001, "r,xOA,X", 4 },
+{ "ormw", 0x88000000, 0xfc080000, "r,xOA,X", 4 },
+{ "orr", 0x08000000, 0xfc0f0000, "r,R", 2 },
+{ "orrm", 0x08080000, 0xfc0f0000, "r,R", 2 },
+{ "rdsts", 0x00090000, 0xfc7f0000, "r", 2 },
+{ "return", 0x280e0000, 0xfc7f0000, "", 2 },
+{ "ri", 0xfc020000, 0xfc07ffff, "I", 4 },
+{ "rnd", 0x00050000, 0xfc7f0000, "r", 2 },
+{ "rpswt", 0x040b0000, 0xfc7f0000, "r", 2 },
+{ "rschnl", 0xfc2f0000, 0xfc7f8000, "r,I", 4 },
+{ "rsctl", 0xfc470000, 0xfc7f8000, "r,I", 4 },
+{ "rwcs", 0x000b0000, 0xfc0f0000, "r,R", 2 },
+{ "sacz", 0x10080000, 0xfc0f0000, "r,R", 2 },
+{ "sbm", 0x98080000, 0xfc080000, "f,xOA,X", 4 },
+{ "sbr", 0x18000000, 0xfc0c0000, "r,f", 4 },
+{ "sea", 0x000d0000, 0xffff0000, "", 2 },
+{ "setcpu", 0x2c090000, 0xfc7f0000, "r", 2 },
+{ "sio", 0xfc170000, 0xfc7f8000, "r,I", 4 },
+{ "sipu", 0x000a0000, 0xffff0000, "", 2 },
+{ "sla", 0x1c400000, 0xfc600000, "r,S", 2 },
+{ "slad", 0x20400000, 0xfc600000, "r,S", 2 },
+{ "slc", 0x24400000, 0xfc600000, "r,S", 2 },
+{ "sll", 0x1c600000, 0xfc600000, "r,S", 2 },
+{ "slld", 0x20600000, 0xfc600000, "r,S", 2 },
+{ "smc", 0x04070000, 0xfc070000, "", 2 },
+{ "sra", 0x1c000000, 0xfc600000, "r,S", 2 },
+{ "srad", 0x20000000, 0xfc600000, "r,S", 2 },
+{ "src", 0x24000000, 0xfc600000, "r,S", 2 },
+{ "srl", 0x1c200000, 0xfc600000, "r,S", 2 },
+{ "srld", 0x20200000, 0xfc600000, "r,S", 2 },
+{ "stb", 0xd4080000, 0xfc080000, "r,xOA,X", 4 },
+{ "std", 0xd4000002, 0xfc080002, "r,xOA,X", 4 },
+{ "stf", 0xdc000000, 0xfc080000, "r,xOA,X", 4 },
+{ "stfbr", 0x54000000, 0xfc080000, "b,xOA,X", 4 },
+{ "sth", 0xd4000001, 0xfc080001, "r,xOA,X", 4 },
+{ "stmb", 0xd8080000, 0xfc080000, "r,xOA,X", 4 },
+{ "stmd", 0xd8000002, 0xfc080002, "r,xOA,X", 4 },
+{ "stmh", 0xd8000001, 0xfc080001, "r,xOA,X", 4 },
+{ "stmw", 0xd8000000, 0xfc080000, "r,xOA,X", 4 },
+{ "stpio", 0xfc270000, 0xfc7f8000, "r,I", 4 },
+{ "stw", 0xd4000000, 0xfc080000, "r,xOA,X", 4 },
+{ "stwbr", 0x54000000, 0xfc080000, "b,xOA,X", 4 },
+{ "suabr", 0x58000000, 0xfc080000, "b,xOA,X", 4 },
+{ "sufd", 0xe0000002, 0xfc080002, "r,xOA,X", 4 },
+{ "sufw", 0xe0000000, 0xfc080000, "r,xOA,X", 4 },
+{ "sui", 0xc8020000, 0xfc7f0000, "r,I", 4 },
+{ "sumb", 0xbc080000, 0xfc080000, "r,xOA,X", 4 },
+{ "sumd", 0xbc000002, 0xfc080002, "r,xOA,X", 4 },
+{ "sumh", 0xbc000001, 0xfc080001, "r,xOA,X", 4 },
+{ "sumw", 0xbc000000, 0xfc080000, "r,xOA,X", 4 },
+{ "sur", 0x3c000000, 0xfc0f0000, "r,R", 2 },
+{ "surfd", 0x380b0000, 0xfc0f0000, "r,xOA,X", 4 },
+{ "surfw", 0x38030000, 0xfc0f0000, "r,R", 2 },
+{ "surm", 0x3c080000, 0xfc0f0000, "r,R", 2 },
+{ "svc", 0xc8060000, 0xffff0000, "", 4 },
+{ "tbm", 0xa4080000, 0xfc080000, "f,xOA,X", 4 },
+{ "tbr", 0x180c0000, 0xfc0c0000, "r,f", 2 },
+{ "tbrr", 0x2c020000, 0xfc0f0000, "r,B", 2 },
+{ "tccr", 0x28040000, 0xfc7f0000, "", 2 },
+{ "td", 0xfc050000, 0xfc070000, "r,f", 4 },
+{ "tio", 0xfc1f0000, 0xfc7f8000, "r,I", 4 },
+{ "tmapr", 0x2c0a0000, 0xfc0f0000, "r,R", 2 },
+{ "tpcbr", 0x280c0000, 0xfc7f0000, "r", 2 },
+{ "trbr", 0x2c010000, 0xfc0f0000, "b,R", 2 },
+{ "trc", 0x2c030000, 0xfc0f0000, "r,R", 2 },
+{ "trcc", 0x28050000, 0xfc7f0000, "", 2 },
+{ "trcm", 0x2c0b0000, 0xfc0f0000, "r,R", 2 },
+{ "trn", 0x2c040000, 0xfc0f0000, "r,R", 2 },
+{ "trnm", 0x2c0c0000, 0xfc0f0000, "r,R", 2 },
+{ "trr", 0x2c000000, 0xfc0f0000, "r,R", 2 },
+{ "trrm", 0x2c080000, 0xfc0f0000, "r,R", 2 },
+{ "trsc", 0x2c0e0000, 0xfc0f0000, "r,R", 2 },
+{ "trsw", 0x28000000, 0xfc7f0000, "r", 2 },
+{ "tscr", 0x2c0f0000, 0xfc0f0000, "r,R", 2 },
+{ "uei", 0x00070000, 0xffff0000, "", 2 },
+{ "wait", 0x00010000, 0xffff0000, "", 2 },
+{ "wcwcs", 0xfc5f0000, 0xfc7f8000, "", 4 },
+{ "wwcs", 0x000c0000, 0xfc0f0000, "r,R", 2 },
+{ "xcbr", 0x28020000, 0xfc0f0000, "b,B", 2 },
+{ "xcr", 0x2c050000, 0xfc0f0000, "r,R", 2 },
+{ "xcrm", 0x2c0d0000, 0xfc0f0000, "r,R", 2 },
+{ "zbm", 0x9c080000, 0xfc080000, "f,xOA,X", 4 },
+{ "zbr", 0x18040000, 0xfc0c0000, "r,f", 2 },
+{ "zmb", 0xf8080000, 0xfc080000, "r,xOA,X", 4 },
+{ "zmd", 0xf8000002, 0xfc080002, "r,xOA,X", 4 },
+{ "zmh", 0xf8000001, 0xfc080001, "r,xOA,X", 4 },
+{ "zmw", 0xf8000000, 0xfc080000, "r,xOA,X", 4 },
+{ "zr", 0x0c000000, 0xfc0f0000, "r", 2 },
+};
+
+int numopcodes = sizeof(gld_opcodes) / sizeof(gld_opcodes[0]);
+
+struct gld_opcode *endop = gld_opcodes + sizeof(gld_opcodes) /
+ sizeof(gld_opcodes[0]);
diff --git a/gnu/usr.bin/as/opcode/pyr.h b/gnu/usr.bin/as/opcode/pyr.h
new file mode 100644
index 0000000..ea5d84a
--- /dev/null
+++ b/gnu/usr.bin/as/opcode/pyr.h
@@ -0,0 +1,287 @@
+/* pyramid.opcode.h -- gdb initial attempt. */
+
+/* pyramid opcode table: wot to do with this
+ particular opcode */
+
+struct pyr_datum
+{
+ char nargs;
+ char * args; /* how to compile said opcode */
+ unsigned long mask; /* Bit vector: which operand modes are valid
+ for this opcode */
+ unsigned char code; /* op-code (always 6(?) bits */
+};
+
+typedef struct pyr_insn_format {
+ unsigned int mode :4;
+ unsigned int operator :8;
+ unsigned int index_scale :2;
+ unsigned int index_reg :6;
+ unsigned int operand_1 :6;
+ unsigned int operand_2:6;
+} pyr_insn_format;
+
+
+/* We store four bytes of opcode for all opcodes.
+ Pyramid is sufficiently RISCy that:
+ - insns are always an integral number of words;
+ - the length of any insn can be told from the first word of
+ the insn. (ie, if there are zero, one, or two words of
+ immediate operand/offset).
+
+
+ The args component is a string containing two characters for each
+ operand of the instruction. The first specifies the kind of operand;
+ the second, the place it is stored. */
+
+/* Kinds of operands:
+ mask assembler syntax description
+ 0x0001: movw Rn,Rn register to register
+ 0x0002: movw K,Rn quick immediate to register
+ 0x0004: movw I,Rn long immediate to register
+ 0x0008: movw (Rn),Rn register indirect to register
+ movw (Rn)[x],Rn register indirect to register
+ 0x0010: movw I(Rn),Rn offset register indirect to register
+ movw I(Rn)[x],Rn offset register indirect, indexed, to register
+
+ 0x0020: movw Rn,(Rn) register to register indirect
+ 0x0040: movw K,(Rn) quick immediate to register indirect
+ 0x0080: movw I,(Rn) long immediate to register indirect
+ 0x0100: movw (Rn),(Rn) register indirect to-register indirect
+ 0x0100: movw (Rn),(Rn) register indirect to-register indirect
+ 0x0200: movw I(Rn),(Rn) register indirect+offset to register indirect
+ 0x0200: movw I(Rn),(Rn) register indirect+offset to register indirect
+
+ 0x0400: movw Rn,I(Rn) register to register indirect+offset
+ 0x0800: movw K,I(Rn) quick immediate to register indirect+offset
+ 0x1000: movw I,I(Rn) long immediate to register indirect+offset
+ 0x1000: movw (Rn),I(Rn) register indirect to-register indirect+offset
+ 0x1000: movw I(Rn),I(Rn) register indirect+offset to register indirect
+ +offset
+ 0x0000: (irregular) ???
+
+
+ Each insn has a four-bit field encoding the type(s) of its operands.
+*/
+
+/* Some common combinations
+ */
+
+/* the first 5,(0x1|0x2|0x4|0x8|0x10) ie (1|2|4|8|16), ie ( 32 -1)*/
+#define GEN_TO_REG (31)
+
+#define UNKNOWN ((unsigned long)-1)
+#define ANY (GEN_TO_REG | (GEN_TO_REG << 5) | (GEN_TO_REG << 15))
+
+#define CONVERT (1|8|0x10|0x20|0x200)
+
+#define K_TO_REG (2)
+#define I_TO_REG (4)
+#define NOTK_TO_REG (GEN_TO_REG & ~K_TO_REG)
+#define NOTI_TO_REG (GEN_TO_REG & ~I_TO_REG)
+
+/* The assembler requires that this array be sorted as follows:
+ all instances of the same mnemonic must be consecutive.
+ All instances of the same mnemonic with the same number of operands
+ must be consecutive.
+ */
+
+struct pyr_opcode /* pyr opcode text */
+{
+ char * name; /* opcode name: lowercase string [key] */
+ struct pyr_datum datum; /* rest of opcode table [datum] */
+};
+
+#define pyr_how args
+#define pyr_nargs nargs
+#define pyr_mask mask
+#define pyr_name name
+
+struct pyr_opcode pyr_opcodes[] =
+{
+ {"movb", { 2, "", UNKNOWN, 0x11}, },
+ {"movh", { 2, "", UNKNOWN, 0x12} },
+ {"movw", { 2, "", ANY, 0x10} },
+ {"movl", { 2, "", ANY, 0x13} },
+ {"mnegw", { 2, "", (0x1|0x8|0x10), 0x14} },
+ {"mnegf", { 2, "", 0x1, 0x15} },
+ {"mnegd", { 2, "", 0x1, 0x16} },
+ {"mcomw", { 2, "", (0x1|0x8|0x10), 0x17} },
+ {"mabsw", { 2, "", (0x1|0x8|0x10), 0x18} },
+ {"mabsf", { 2, "", 0x1, 0x19} },
+ {"mabsd", { 2, "", 0x1, 0x1a} },
+ {"mtstw", { 2, "", (0x1|0x8|0x10), 0x1c} },
+ {"mtstf", { 2, "", 0x1, 0x1d} },
+ {"mtstd", { 2, "", 0x1, 0x1e} },
+ {"mova", { 2, "", 0x8|0x10, 0x1f} },
+ {"movzbw", { 2, "", (0x1|0x8|0x10), 0x20} },
+ {"movzhw", { 2, "", (0x1|0x8|0x10), 0x21} },
+ /* 2 insns out of order here */
+ {"movbl", { 2, "", 1, 0x4f} },
+ {"filbl", { 2, "", 1, 0x4e} },
+
+ {"cvtbw", { 2, "", CONVERT, 0x22} },
+ {"cvthw", { 2, "", CONVERT, 0x23} },
+ {"cvtwb", { 2, "", CONVERT, 0x24} },
+ {"cvtwh", { 2, "", CONVERT, 0x25} },
+ {"cvtwf", { 2, "", CONVERT, 0x26} },
+ {"cvtwd", { 2, "", CONVERT, 0x27} },
+ {"cvtfw", { 2, "", CONVERT, 0x28} },
+ {"cvtfd", { 2, "", CONVERT, 0x29} },
+ {"cvtdw", { 2, "", CONVERT, 0x2a} },
+ {"cvtdf", { 2, "", CONVERT, 0x2b} },
+
+ {"addw", { 2, "", GEN_TO_REG, 0x40} },
+ {"addwc", { 2, "", GEN_TO_REG, 0x41} },
+ {"subw", { 2, "", GEN_TO_REG, 0x42} },
+ {"subwb", { 2, "", GEN_TO_REG, 0x43} },
+ {"rsubw", { 2, "", GEN_TO_REG, 0x44} },
+ {"mulw", { 2, "", GEN_TO_REG, 0x45} },
+ {"emul", { 2, "", GEN_TO_REG, 0x47} },
+ {"umulw", { 2, "", GEN_TO_REG, 0x46} },
+ {"divw", { 2, "", GEN_TO_REG, 0x48} },
+ {"ediv", { 2, "", GEN_TO_REG, 0x4a} },
+ {"rdivw", { 2, "", GEN_TO_REG, 0x4b} },
+ {"udivw", { 2, "", GEN_TO_REG, 0x49} },
+ {"modw", { 2, "", GEN_TO_REG, 0x4c} },
+ {"umodw", { 2, "", GEN_TO_REG, 0x4d} },
+
+
+ {"addf", { 2, "", 1, 0x50} },
+ {"addd", { 2, "", 1, 0x51} },
+ {"subf", { 2, "", 1, 0x52} },
+ {"subd", { 2, "", 1, 0x53} },
+ {"mulf", { 2, "", 1, 0x56} },
+ {"muld", { 2, "", 1, 0x57} },
+ {"divf", { 2, "", 1, 0x58} },
+ {"divd", { 2, "", 1, 0x59} },
+
+
+ {"cmpb", { 2, "", UNKNOWN, 0x61} },
+ {"cmph", { 2, "", UNKNOWN, 0x62} },
+ {"cmpw", { 2, "", UNKNOWN, 0x60} },
+ {"ucmpb", { 2, "", UNKNOWN, 0x66} },
+ /* WHY no "ucmph"??? */
+ {"ucmpw", { 2, "", UNKNOWN, 0x65} },
+ {"xchw", { 2, "", UNKNOWN, 0x0f} },
+
+
+ {"andw", { 2, "", GEN_TO_REG, 0x30} },
+ {"orw", { 2, "", GEN_TO_REG, 0x31} },
+ {"xorw", { 2, "", GEN_TO_REG, 0x32} },
+ {"bicw", { 2, "", GEN_TO_REG, 0x33} },
+ {"lshlw", { 2, "", GEN_TO_REG, 0x38} },
+ {"ashlw", { 2, "", GEN_TO_REG, 0x3a} },
+ {"ashll", { 2, "", GEN_TO_REG, 0x3c} },
+ {"ashrw", { 2, "", GEN_TO_REG, 0x3b} },
+ {"ashrl", { 2, "", GEN_TO_REG, 0x3d} },
+ {"rotlw", { 2, "", GEN_TO_REG, 0x3e} },
+ {"rotrw", { 2, "", GEN_TO_REG, 0x3f} },
+
+ /* push and pop insns are "going away next release". */
+ {"pushw", { 2, "", GEN_TO_REG, 0x0c} },
+ {"popw", { 2, "", (0x1|0x8|0x10), 0x0d} },
+ {"pusha", { 2, "", (0x8|0x10), 0x0e} },
+
+ {"bitsw", { 2, "", UNKNOWN, 0x35} },
+ {"bitcw", { 2, "", UNKNOWN, 0x36} },
+ /* some kind of ibra/dbra insns??*/
+ {"icmpw", { 2, "", UNKNOWN, 0x67} },
+ {"dcmpw", { 2, "", (1|4|0x20|0x80|0x400|0x1000), 0x69} },/*FIXME*/
+ {"acmpw", { 2, "", 1, 0x6b} },
+
+ /* Call is written as a 1-op insn, but is always (dis)assembled as a 2-op
+ insn with a 2nd op of tr14. The assembler will have to grok this. */
+ {"call", { 2, "", GEN_TO_REG, 0x04} },
+ {"call", { 1, "", GEN_TO_REG, 0x04} },
+
+ {"callk", { 1, "", UNKNOWN, 0x06} },/* system call?*/
+ /* Ret is usually written as a 0-op insn, but gets disassembled as a
+ 1-op insn. The operand is always tr15. */
+ {"ret", { 0, "", UNKNOWN, 0x09} },
+ {"ret", { 1, "", UNKNOWN, 0x09} },
+ {"adsf", { 2, "", (1|2|4), 0x08} },
+ {"retd", { 2, "", UNKNOWN, 0x0a} },
+ {"btc", { 2, "", UNKNOWN, 0x01} },
+ {"bfc", { 2, "", UNKNOWN, 0x02} },
+ /* Careful: halt is 0x00000000. Jump must have some other (mode?)bit set?? */
+ {"jump", { 1, "", UNKNOWN, 0x00} },
+ {"btp", { 2, "", UNKNOWN, 0xf00} },
+ /* read control-stack pointer is another 1-or-2 operand insn. */
+ {"rcsp", { 2, "", UNKNOWN, 0x01f} },
+ {"rcsp", { 1, "", UNKNOWN, 0x01f} }
+};
+
+/* end: pyramid.opcode.h */
+/* One day I will have to take the time to find out what operands
+ are valid for these insns, and guess at what they mean.
+
+ I can't imagine what the "I???" insns (iglob, etc) do.
+
+ the arithmetic-sounding insns ending in "p" sound awfully like BCD
+ arithmetic insns:
+ dshlp -> Decimal SHift Left Packed
+ dshrp -> Decimal SHift Right Packed
+ and cvtlp would be convert long to packed.
+ I have no idea how the operands are interpreted; but having them be
+ a long register with (address, length) of an in-memory packed BCD operand
+ would not be surprising.
+ They are unlikely to be a packed bcd string: 64 bits of long give
+ is only 15 digits+sign, which isn't enough for COBOL.
+ */
+#if 0
+ {"wcsp", { 2, "", UNKNOWN, 0x00} }, /*write csp?*/
+ /* The OSx Operating System Porting Guide claims SSL does things
+ with tr12 (a register reserved to it) to do with static block-structure
+ references. SSL=Set Static Link? It's "Going away next release". */
+ {"ssl", { 2, "", UNKNOWN, 0x00} },
+ {"ccmps", { 2, "", UNKNOWN, 0x00} },
+ {"lcd", { 2, "", UNKNOWN, 0x00} },
+ {"uemul", { 2, "", UNKNOWN, 0x00} }, /*unsigned emul*/
+ {"srf", { 2, "", UNKNOWN, 0x00} }, /*Gidget time???*/
+ {"mnegp", { 2, "", UNKNOWN, 0x00} }, /move-neg phys?*/
+ {"ldp", { 2, "", UNKNOWN, 0x00} }, /*load phys?*/
+ {"ldti", { 2, "", UNKNOWN, 0x00} },
+ {"ldb", { 2, "", UNKNOWN, 0x00} },
+ {"stp", { 2, "", UNKNOWN, 0x00} },
+ {"stti", { 2, "", UNKNOWN, 0x00} },
+ {"stb", { 2, "", UNKNOWN, 0x00} },
+ {"stu", { 2, "", UNKNOWN, 0x00} },
+ {"addp", { 2, "", UNKNOWN, 0x00} },
+ {"subp", { 2, "", UNKNOWN, 0x00} },
+ {"mulp", { 2, "", UNKNOWN, 0x00} },
+ {"divp", { 2, "", UNKNOWN, 0x00} },
+ {"dshlp", { 2, "", UNKNOWN, 0x00} }, /* dec shl packed? */
+ {"dshrp", { 2, "", UNKNOWN, 0x00} }, /* dec shr packed? */
+ {"movs", { 2, "", UNKNOWN, 0x00} }, /*move (string?)?*/
+ {"cmpp", { 2, "", UNKNOWN, 0x00} }, /* cmp phys?*/
+ {"cmps", { 2, "", UNKNOWN, 0x00} }, /* cmp (string?)?*/
+ {"cvtlp", { 2, "", UNKNOWN, 0x00} }, /* cvt long to p??*/
+ {"cvtpl", { 2, "", UNKNOWN, 0x00} }, /* cvt p to l??*/
+ {"dintr", { 2, "", UNKNOWN, 0x00} }, /* ?? intr ?*/
+ {"rphysw", { 2, "", UNKNOWN, 0x00} }, /* read phys word?*/
+ {"wphysw", { 2, "", UNKNOWN, 0x00} }, /* write phys word?*/
+ {"cmovs", { 2, "", UNKNOWN, 0x00} },
+ {"rsubw", { 2, "", UNKNOWN, 0x00} },
+ {"bicpsw", { 2, "", UNKNOWN, 0x00} }, /* clr bit in psw? */
+ {"bispsw", { 2, "", UNKNOWN, 0x00} }, /* set bit in psw? */
+ {"eio", { 2, "", UNKNOWN, 0x00} }, /* ?? ?io ? */
+ {"callp", { 2, "", UNKNOWN, 0x00} }, /* call phys?*/
+ {"callr", { 2, "", UNKNOWN, 0x00} },
+ {"lpcxt", { 2, "", UNKNOWN, 0x00} }, /*load proc context*/
+ {"rei", { 2, "", UNKNOWN, 0x00} }, /*ret from intrpt*/
+ {"rport", { 2, "", UNKNOWN, 0x00} }, /*read-port?*/
+ {"rtod", { 2, "", UNKNOWN, 0x00} }, /*read-time-of-day?*/
+ {"ssi", { 2, "", UNKNOWN, 0x00} },
+ {"vtpa", { 2, "", UNKNOWN, 0x00} }, /*virt-to-phys-addr?*/
+ {"wicl", { 2, "", UNKNOWN, 0x00} }, /* write icl ? */
+ {"wport", { 2, "", UNKNOWN, 0x00} }, /*write-port?*/
+ {"wtod", { 2, "", UNKNOWN, 0x00} }, /*write-time-of-day?*/
+ {"flic", { 2, "", UNKNOWN, 0x00} },
+ {"iglob", { 2, "", UNKNOWN, 0x00} }, /* I global? */
+ {"iphys", { 2, "", UNKNOWN, 0x00} }, /* I physical? */
+ {"ipid", { 2, "", UNKNOWN, 0x00} }, /* I pid? */
+ {"ivect", { 2, "", UNKNOWN, 0x00} }, /* I vector? */
+ {"lamst", { 2, "", UNKNOWN, 0x00} },
+ {"tio", { 2, "", UNKNOWN, 0x00} },
+#endif
diff --git a/gnu/usr.bin/as/opcode/sparc.h b/gnu/usr.bin/as/opcode/sparc.h
new file mode 100644
index 0000000..7921cf5
--- /dev/null
+++ b/gnu/usr.bin/as/opcode/sparc.h
@@ -0,0 +1,885 @@
+
+/* Table of opcodes for the sparc.
+ Copyright 1989, 1991, 1992 Free Software Foundation, Inc.
+
+This file is part of GAS, the GNU Assembler, GDB, the GNU debugger, and
+the GNU Binutils.
+
+GAS/GDB is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GAS/GDB is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GAS or GDB; see the file COPYING. If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/*
+ * $Id: sparc.h,v 1.2 1994/12/23 22:37:45 nate Exp $
+ */
+
+ /* FIXME-someday: perhaps the ,a's and such should be embedded in the
+ instruction's name rather than the args. This would make gas faster, pinsn
+ slower, but would mess up some macros a bit. xoxorich. */
+
+#if !defined(__STDC__) && !defined(const)
+#define const
+#endif
+
+/*
+ * Structure of an opcode table entry.
+ */
+enum sparc_architecture {
+ v6 = 0,
+ v7,
+ v8,
+};
+
+static const char *architecture_pname[] = {
+ "v6",
+ "v7",
+ "v8",
+ NULL,
+};
+
+struct sparc_opcode {
+ const char *name;
+ unsigned long match; /* Bits that must be set. */
+ unsigned long lose; /* Bits that must not be set. */
+ const char *args;
+ /* This was called "delayed" in versions before the flags. */
+ char flags;
+ enum sparc_architecture architecture;
+};
+
+#define F_DELAYED 1 /* Delayed branch */
+#define F_ALIAS 2 /* Alias for a "real" instruction */
+
+/*
+
+All sparc opcodes are 32 bits, except for the `set' instruction (really a
+macro), which is 64 bits. It is handled as a special case.
+
+The match component is a mask saying which bits must match a particular
+opcode in order for an instruction to be an instance of that opcode.
+
+The args component is a string containing one character for each operand of the
+instruction.
+
+Kinds of operands:
+ # Number used by optimizer. It is ignored.
+ 1 rs1 register.
+ 2 rs2 register.
+ d rd register.
+ e frs1 floating point register.
+ v frs1 floating point register (double/even).
+ V frs1 floating point register (quad/multiple of 4).
+ f frs2 floating point register.
+ B frs2 floating point register (double/even).
+ R frs2 floating point register (quad/multiple of 4).
+ g frsd floating point register.
+ H frsd floating point register (double/even).
+ J frsd floating point register (quad/multiple of 4).
+ b crs1 coprocessor register
+ c crs2 coprocessor register
+ D crsd coprocessor register
+ m alternate space register (asr) in rd
+ M alternate space register (asr) in rs1
+ h 22 high bits.
+ i 13 bit Immediate.
+ n 22 bit immediate.
+ l 22 bit PC relative immediate.
+ L 30 bit PC relative immediate.
+ a Annul. The annul bit is set.
+ A Alternate address space. Stored as 8 bits.
+ C Coprocessor state register.
+ F floating point state register.
+ p Processor state register.
+ q Floating point queue.
+ r Single register that is both rs1 and rsd.
+ Q Coprocessor queue.
+ S Special case.
+ x Single register that is both rs2 and rsd.
+ t Trap base register.
+ w Window invalid mask register.
+ y Y register.
+
+The following chars are unused: (note: ,[] are used as punctuation)
+[oOX3450]
+
+*/
+
+/* The order of the opcodes in this table is significant:
+
+ * The assembler requires that all instances of the same mnemonic must
+ be consecutive. If they aren't, the assembler will bomb at runtime.
+
+ * The disassembler should not care about the order of the opcodes.
+
+*/
+
+#define OP2(x) (((x)&0x7) << 22) /* op2 field of format2 insns */
+#define OP3(x) (((x)&0x3f) << 19) /* op3 field of format3 insns */
+#define OP(x) (((x)&0x3) << 30) /* op field of all insns */
+#define OPF(x) (((x)&0x1ff) << 5) /* opf field of float insns */
+#define F3F(x, y, z) (OP(x) | OP3(y) | OPF(z)) /* format3 float insns */
+#define F3I(x) (((x)&0x1) << 13) /* immediate field of format 3 insns */
+#define F2(x, y) (OP(x) | OP2(y)) /* format 2 insns */
+#define F3(x, y, z) (OP(x) | OP3(y) | F3I(z)) /* format3 insns */
+#define F1(x) (OP(x))
+#define DISP30(x) ((x)&0x3fffffff)
+#define ASI(x) (((x)&0xff) << 5) /* asi field of format3 insns */
+#define RS2(x) ((x)&0x1f) /* rs2 field */
+#define SIMM13(x) ((x)&0x1fff) /* simm13 field */
+#define RD(x) (((x)&0x1f) << 25) /* destination register field */
+#define RS1(x) (((x)&0x1f) << 14) /* rs1 field */
+#define ASI_RS2(x) (SIMM13(x))
+
+#define ANNUL (1<<29)
+#define IMMED F3I(1)
+#define RD_G0 RD(~0)
+#define RS1_G0 RS1(~0)
+#define RS2_G0 RS2(~0)
+
+#define COND(x) (((x)&0xf)<<25)
+
+#define CONDA (COND(0x8))
+#define CONDCC (COND(0xd))
+#define CONDCS (COND(0x5))
+#define CONDE (COND(0x1))
+#define CONDG (COND(0xa))
+#define CONDGE (COND(0xb))
+#define CONDGU (COND(0xc))
+#define CONDL (COND(0x3))
+#define CONDLE (COND(0x2))
+#define CONDLEU (COND(0x4))
+#define CONDN (COND(0x0))
+#define CONDNE (COND(0x9))
+#define CONDNEG (COND(0x6))
+#define CONDPOS (COND(0xe))
+#define CONDVC (COND(0xf))
+#define CONDVS (COND(0x7))
+
+#define CONDNZ CONDNE
+#define CONDZ CONDE
+#define CONDGEU CONDCC
+#define CONDLU CONDCS
+
+#define FCONDA (COND(0x8))
+#define FCONDE (COND(0x9))
+#define FCONDG (COND(0x6))
+#define FCONDGE (COND(0xb))
+#define FCONDL (COND(0x4))
+#define FCONDLE (COND(0xd))
+#define FCONDLG (COND(0x2))
+#define FCONDN (COND(0x0))
+#define FCONDNE (COND(0x1))
+#define FCONDO (COND(0xf))
+#define FCONDU (COND(0x7))
+#define FCONDUE (COND(0xa))
+#define FCONDUG (COND(0x5))
+#define FCONDUGE (COND(0xc))
+#define FCONDUL (COND(0x3))
+#define FCONDULE (COND(0xe))
+
+#define FCONDNZ FCONDNE
+#define FCONDZ FCONDE
+
+
+static const struct sparc_opcode sparc_opcodes[] = {
+
+{ "ld", F3(3, 0x00, 0), F3(~3, ~0x00, ~0), "[1+2],d", 0, v6 },
+{ "ld", F3(3, 0x00, 0), F3(~3, ~0x00, ~0)|RS2_G0, "[1],d", 0, v6 }, /* ld [rs1+%g0],d */
+{ "ld", F3(3, 0x00, 1), F3(~3, ~0x00, ~1), "[1+i],d", 0, v6 },
+{ "ld", F3(3, 0x00, 1), F3(~3, ~0x00, ~1), "[i+1],d", 0, v6 },
+{ "ld", F3(3, 0x00, 1), F3(~3, ~0x00, ~1)|RS1_G0, "[i],d", 0, v6 },
+{ "ld", F3(3, 0x00, 1), F3(~3, ~0x00, ~1)|SIMM13(~0), "[1],d", 0, v6 }, /* ld [rs1+0],d */
+{ "ld", F3(3, 0x20, 0), F3(~3, ~0x20, ~0), "[1+2],g", 0, v6 },
+{ "ld", F3(3, 0x20, 0), F3(~3, ~0x20, ~0)|RS2_G0, "[1],g", 0, v6 }, /* ld [rs1+%g0],d */
+{ "ld", F3(3, 0x20, 1), F3(~3, ~0x20, ~1), "[1+i],g", 0, v6 },
+{ "ld", F3(3, 0x20, 1), F3(~3, ~0x20, ~1), "[i+1],g", 0, v6 },
+{ "ld", F3(3, 0x20, 1), F3(~3, ~0x20, ~1)|RS1_G0, "[i],g", 0, v6 },
+{ "ld", F3(3, 0x20, 1), F3(~3, ~0x20, ~1)|SIMM13(~0), "[1],g", 0, v6 }, /* ld [rs1+0],d */
+{ "ld", F3(3, 0x21, 0), F3(~3, ~0x21, ~0), "[1+2],F", 0, v6 },
+{ "ld", F3(3, 0x21, 0), F3(~3, ~0x21, ~0)|RS2_G0, "[1],F", 0, v6 }, /* ld [rs1+%g0],d */
+{ "ld", F3(3, 0x21, 1), F3(~3, ~0x21, ~1), "[1+i],F", 0, v6 },
+{ "ld", F3(3, 0x21, 1), F3(~3, ~0x21, ~1), "[i+1],F", 0, v6 },
+{ "ld", F3(3, 0x21, 1), F3(~3, ~0x21, ~1)|RS1_G0, "[i],F", 0, v6 },
+{ "ld", F3(3, 0x21, 1), F3(~3, ~0x21, ~1)|SIMM13(~0), "[1],F", 0, v6 }, /* ld [rs1+0],d */
+{ "ld", F3(3, 0x30, 0), F3(~3, ~0x30, ~0), "[1+2],D", 0, v6 },
+{ "ld", F3(3, 0x30, 0), F3(~3, ~0x30, ~0)|RS2_G0, "[1],D", 0, v6 }, /* ld [rs1+%g0],d */
+{ "ld", F3(3, 0x30, 1), F3(~3, ~0x30, ~1), "[1+i],D", 0, v6 },
+{ "ld", F3(3, 0x30, 1), F3(~3, ~0x30, ~1), "[i+1],D", 0, v6 },
+{ "ld", F3(3, 0x30, 1), F3(~3, ~0x30, ~1)|RS1_G0, "[i],D", 0, v6 },
+{ "ld", F3(3, 0x30, 1), F3(~3, ~0x30, ~1)|SIMM13(~0), "[1],D", 0, v6 }, /* ld [rs1+0],d */
+{ "ld", F3(3, 0x31, 0), F3(~3, ~0x31, ~0), "[1+2],C", 0, v6 },
+{ "ld", F3(3, 0x31, 0), F3(~3, ~0x31, ~0)|RS2_G0, "[1],C", 0, v6 }, /* ld [rs1+%g0],d */
+{ "ld", F3(3, 0x31, 1), F3(~3, ~0x31, ~1), "[1+i],C", 0, v6 },
+{ "ld", F3(3, 0x31, 1), F3(~3, ~0x31, ~1), "[i+1],C", 0, v6 },
+{ "ld", F3(3, 0x31, 1), F3(~3, ~0x31, ~1)|RS1_G0, "[i],C", 0, v6 },
+{ "ld", F3(3, 0x31, 1), F3(~3, ~0x31, ~1)|SIMM13(~0), "[1],C", 0, v6 }, /* ld [rs1+0],d */
+
+
+
+{ "lda", F3(3, 0x10, 0), F3(~3, ~0x10, ~0), "[1+2]A,d", 0, v6 },
+{ "lda", F3(3, 0x10, 0), F3(~3, ~0x10, ~0)|RS2_G0, "[1]A,d", 0, v6 }, /* lda [rs1+%g0],d */
+
+{ "ldd", F3(3, 0x03, 0), F3(~3, ~0x03, ~0)|ASI(~0), "[1+2],d", 0, v6 },
+{ "ldd", F3(3, 0x03, 0), F3(~3, ~0x03, ~0)|ASI_RS2(~0), "[1],d", 0, v6 }, /* ldd [rs1+%g0],d */
+{ "ldd", F3(3, 0x03, 1), F3(~3, ~0x03, ~1), "[1+i],d", 0, v6 },
+{ "ldd", F3(3, 0x03, 1), F3(~3, ~0x03, ~1), "[i+1],d", 0, v6 },
+{ "ldd", F3(3, 0x03, 1), F3(~3, ~0x03, ~1)|RS1_G0, "[i],d", 0, v6 },
+{ "ldd", F3(3, 0x03, 1), F3(~3, ~0x03, ~1)|SIMM13(~0), "[1],d", 0, v6 }, /* ldd [rs1+0],d */
+{ "ldd", F3(3, 0x23, 0), F3(~3, ~0x23, ~0)|ASI(~0), "[1+2],g", 0, v6 },
+{ "ldd", F3(3, 0x23, 0), F3(~3, ~0x23, ~0)|ASI_RS2(~0), "[1],g", 0, v6 }, /* ldd [rs1+%g0],d */
+{ "ldd", F3(3, 0x23, 1), F3(~3, ~0x23, ~1), "[1+i],g", 0, v6 },
+{ "ldd", F3(3, 0x23, 1), F3(~3, ~0x23, ~1), "[i+1],g", 0, v6 },
+{ "ldd", F3(3, 0x23, 1), F3(~3, ~0x23, ~1)|RS1_G0, "[i],g", 0, v6 },
+{ "ldd", F3(3, 0x23, 1), F3(~3, ~0x23, ~1)|SIMM13(~0), "[1],g", 0, v6 }, /* ldd [rs1+0],d */
+{ "ldd", F3(3, 0x33, 0), F3(~3, ~0x33, ~0)|ASI(~0), "[1+2],D", 0, v6 },
+{ "ldd", F3(3, 0x33, 0), F3(~3, ~0x33, ~0)|ASI_RS2(~0), "[1],D", 0, v6 }, /* ldd [rs1+%g0],d */
+{ "ldd", F3(3, 0x33, 1), F3(~3, ~0x33, ~1), "[1+i],D", 0, v6 },
+{ "ldd", F3(3, 0x33, 1), F3(~3, ~0x33, ~1), "[i+1],D", 0, v6 },
+{ "ldd", F3(3, 0x33, 1), F3(~3, ~0x33, ~1)|RS1_G0, "[i],D", 0, v6 },
+{ "ldd", F3(3, 0x33, 1), F3(~3, ~0x33, ~1)|SIMM13(~0), "[1],D", 0, v6 }, /* ldd [rs1+0],d */
+{ "ldsb", F3(3, 0x09, 0), F3(~3, ~0x09, ~0)|ASI(~0), "[1+2],d", 0, v6 },
+{ "ldsb", F3(3, 0x09, 0), F3(~3, ~0x09, ~0)|ASI_RS2(~0), "[1],d", 0, v6 }, /* ldsb [rs1+%g0],d */
+{ "ldsb", F3(3, 0x09, 1), F3(~3, ~0x09, ~1), "[1+i],d", 0, v6 },
+{ "ldsb", F3(3, 0x09, 1), F3(~3, ~0x09, ~1), "[i+1],d", 0, v6 },
+{ "ldsb", F3(3, 0x09, 1), F3(~3, ~0x09, ~1)|RS1_G0, "[i],d", 0, v6 },
+{ "ldsb", F3(3, 0x09, 1), F3(~3, ~0x09, ~1)|SIMM13(~0), "[1],d", 0, v6 }, /* ldsb [rs1+0],d */
+{ "ldsh", F3(3, 0x0a, 0), F3(~3, ~0x0a, ~0)|ASI_RS2(~0), "[1],d", 0, v6 }, /* ldsh [rs1+%g0],d */
+{ "ldsh", F3(3, 0x0a, 0), F3(~3, ~0x0a, ~0)|ASI(~0), "[1+2],d", 0, v6 },
+{ "ldsh", F3(3, 0x0a, 1), F3(~3, ~0x0a, ~1), "[1+i],d", 0, v6 },
+{ "ldsh", F3(3, 0x0a, 1), F3(~3, ~0x0a, ~1), "[i+1],d", 0, v6 },
+{ "ldsh", F3(3, 0x0a, 1), F3(~3, ~0x0a, ~1)|RS1_G0, "[i],d", 0, v6 },
+{ "ldsh", F3(3, 0x0a, 1), F3(~3, ~0x0a, ~1)|SIMM13(~0), "[1],d", 0, v6 }, /* ldsh [rs1+0],d */
+{ "ldstub", F3(3, 0x0d, 0), F3(~3, ~0x0d, ~0)|ASI(~0), "[1+2],d", 0, v6 },
+{ "ldstub", F3(3, 0x0d, 0), F3(~3, ~0x0d, ~0)|ASI_RS2(~0), "[1],d", 0, v6 }, /* ldstub [rs1+%g0],d */
+{ "ldstub", F3(3, 0x0d, 1), F3(~3, ~0x0d, ~1), "[1+i],d", 0, v6 },
+{ "ldstub", F3(3, 0x0d, 1), F3(~3, ~0x0d, ~1), "[i+1],d", 0, v6 },
+{ "ldstub", F3(3, 0x0d, 1), F3(~3, ~0x0d, ~1)|RS1_G0, "[i],d", 0, v6 },
+{ "ldub", F3(3, 0x01, 0), F3(~3, ~0x01, ~0)|ASI(~0), "[1+2],d", 0, v6 },
+{ "ldub", F3(3, 0x01, 0), F3(~3, ~0x01, ~0)|ASI_RS2(~0), "[1],d", 0, v6 }, /* ldub [rs1+%g0],d */
+{ "ldub", F3(3, 0x01, 1), F3(~3, ~0x01, ~1), "[1+i],d", 0, v6 },
+{ "ldub", F3(3, 0x01, 1), F3(~3, ~0x01, ~1), "[i+1],d", 0, v6 },
+{ "ldub", F3(3, 0x01, 1), F3(~3, ~0x01, ~1)|RS1_G0, "[i],d", 0, v6 },
+{ "ldub", F3(3, 0x01, 1), F3(~3, ~0x01, ~1)|SIMM13(~0), "[1],d", 0, v6 }, /* ldub [rs1+0],d */
+{ "lduh", F3(3, 0x02, 0), F3(~3, ~0x02, ~0)|ASI(~0), "[1+2],d", 0, v6 },
+{ "lduh", F3(3, 0x02, 0), F3(~3, ~0x02, ~0)|ASI_RS2(~0), "[1],d", 0, v6 }, /* lduh [rs1+%g0],d */
+{ "lduh", F3(3, 0x02, 1), F3(~3, ~0x02, ~1), "[1+i],d", 0, v6 },
+{ "lduh", F3(3, 0x02, 1), F3(~3, ~0x02, ~1), "[i+1],d", 0, v6 },
+{ "lduh", F3(3, 0x02, 1), F3(~3, ~0x02, ~1)|RS1_G0, "[i],d", 0, v6 },
+{ "lduh", F3(3, 0x02, 1), F3(~3, ~0x02, ~1)|SIMM13(~0), "[1],d", 0, v6 }, /* lduh [rs1+0],d */
+
+
+{ "ldda", F3(3, 0x13, 0), F3(~3, ~0x13, ~0), "[1+2]A,d", 0, v6 },
+{ "ldda", F3(3, 0x13, 0), F3(~3, ~0x13, ~0)|RS2_G0, "[1]A,d", 0, v6 }, /* ldda [rs1+%g0],d */
+{ "ldsba", F3(3, 0x19, 0), F3(~3, ~0x19, ~0), "[1+2]A,d", 0, v6 },
+{ "ldsba", F3(3, 0x19, 0), F3(~3, ~0x19, ~0)|RS2_G0, "[1]A,d", 0, v6 }, /* ldsba [rs1+%g0],d */
+{ "ldsha", F3(3, 0x1a, 0), F3(~3, ~0x1a, ~0), "[1+2]A,d", 0, v6 },
+{ "ldsha", F3(3, 0x1a, 0), F3(~3, ~0x1a, ~0)|RS2_G0, "[1]A,d", 0, v6 }, /* ldsha [rs1+%g0],d */
+{ "ldstuba", F3(3, 0x1d, 0), F3(~3, ~0x1d, ~0), "[1+2]A,d", 0, v6 },
+{ "ldstuba", F3(3, 0x1d, 0), F3(~3, ~0x1d, ~0)|RS2_G0, "[1]A,d", 0, v6 }, /* ldstuba [rs1+%g0],d */
+{ "lduba", F3(3, 0x11, 0), F3(~3, ~0x11, ~0), "[1+2]A,d", 0, v6 },
+{ "lduba", F3(3, 0x11, 0), F3(~3, ~0x11, ~0)|RS2_G0, "[1]A,d", 0, v6 }, /* lduba [rs1+%g0],d */
+{ "lduha", F3(3, 0x12, 0), F3(~3, ~0x12, ~0), "[1+2]A,d", 0, v6 },
+{ "lduha", F3(3, 0x12, 0), F3(~3, ~0x12, ~0)|RS2_G0, "[1]A,d", 0, v6 }, /* lduha [rs1+%g0],d */
+
+{ "st", F3(3, 0x04, 0), F3(~3, ~0x04, ~0)|ASI(~0), "d,[1+2]", 0, v6 },
+{ "st", F3(3, 0x04, 0), F3(~3, ~0x04, ~0)|ASI_RS2(~0), "d,[1]", 0, v6 }, /* st d,[rs1+%g0] */
+{ "st", F3(3, 0x04, 1), F3(~3, ~0x04, ~1), "d,[1+i]", 0, v6 },
+{ "st", F3(3, 0x04, 1), F3(~3, ~0x04, ~1), "d,[i+1]", 0, v6 },
+{ "st", F3(3, 0x04, 1), F3(~3, ~0x04, ~1)|RS1_G0, "d,[i]", 0, v6 },
+{ "st", F3(3, 0x04, 1), F3(~3, ~0x04, ~1)|SIMM13(~0), "d,[1]", 0, v6 }, /* st d,[rs1+0] */
+{ "st", F3(3, 0x24, 0), F3(~3, ~0x24, ~0)|ASI(~0), "g,[1+2]", 0, v6 },
+{ "st", F3(3, 0x24, 0), F3(~3, ~0x24, ~0)|ASI_RS2(~0), "g,[1]", 0, v6 }, /* st d[rs1+%g0] */
+{ "st", F3(3, 0x24, 1), F3(~3, ~0x24, ~1), "g,[1+i]", 0, v6 },
+{ "st", F3(3, 0x24, 1), F3(~3, ~0x24, ~1), "g,[i+1]", 0, v6 },
+{ "st", F3(3, 0x24, 1), F3(~3, ~0x24, ~1)|RS1_G0, "g,[i]", 0, v6 },
+{ "st", F3(3, 0x24, 1), F3(~3, ~0x24, ~1)|SIMM13(~0), "g,[1]", 0, v6 }, /* st d,[rs1+0] */
+{ "st", F3(3, 0x34, 0), F3(~3, ~0x34, ~0)|ASI(~0), "D,[1+2]", 0, v6 },
+{ "st", F3(3, 0x34, 0), F3(~3, ~0x34, ~0)|ASI_RS2(~0), "D,[1]", 0, v6 }, /* st d,[rs1+%g0] */
+{ "st", F3(3, 0x34, 1), F3(~3, ~0x34, ~1), "D,[1+i]", 0, v6 },
+{ "st", F3(3, 0x34, 1), F3(~3, ~0x34, ~1), "D,[i+1]", 0, v6 },
+{ "st", F3(3, 0x34, 1), F3(~3, ~0x34, ~1)|RS1_G0, "D,[i]", 0, v6 },
+{ "st", F3(3, 0x34, 1), F3(~3, ~0x34, ~1)|SIMM13(~0), "D,[1]", 0, v6 }, /* st d,[rs1+0] */
+{ "st", F3(3, 0x35, 0), F3(~3, ~0x35, ~0)|ASI(~0), "C,[1+2]", 0, v6 },
+{ "st", F3(3, 0x35, 0), F3(~3, ~0x35, ~0)|ASI_RS2(~0), "C,[1]", 0, v6 }, /* st d,[rs1+%g0] */
+{ "st", F3(3, 0x35, 1), F3(~3, ~0x35, ~1), "C,[1+i]", 0, v6 },
+{ "st", F3(3, 0x35, 1), F3(~3, ~0x35, ~1), "C,[i+1]", 0, v6 },
+{ "st", F3(3, 0x35, 1), F3(~3, ~0x35, ~1)|RS1_G0, "C,[i]", 0, v6 },
+{ "st", F3(3, 0x35, 1), F3(~3, ~0x35, ~1)|SIMM13(~0), "C,[1]", 0, v6 }, /* st d,[rs1+0] */
+
+{ "st", F3(3, 0x25, 0), F3(~3, ~0x25, ~0)|RD_G0|ASI(~0), "F,[1+2]", 0, v6 },
+{ "st", F3(3, 0x25, 0), F3(~3, ~0x25, ~0)|RD_G0|ASI_RS2(~0), "F,[1]", 0, v6 }, /* st d,[rs1+%g0] */
+{ "st", F3(3, 0x25, 1), F3(~3, ~0x25, ~1)|RD_G0, "F,[1+i]", 0, v6 },
+{ "st", F3(3, 0x25, 1), F3(~3, ~0x25, ~1)|RD_G0, "F,[i+1]", 0, v6 },
+{ "st", F3(3, 0x25, 1), F3(~3, ~0x25, ~1)|RD_G0|RS1_G0, "F,[i]", 0, v6 },
+{ "st", F3(3, 0x25, 1), F3(~3, ~0x25, ~1)|SIMM13(~0), "F,[1]", 0, v6 }, /* st d,[rs1+0] */
+
+
+
+
+{ "sta", F3(3, 0x14, 0), F3(~3, ~0x14, ~0), "d,[1+2]A", 0, v6 },
+{ "sta", F3(3, 0x14, 0), F3(~3, ~0x14, ~0)|RS2(~0), "d,[1]A", 0, v6 }, /* sta d,[rs1+%g0] */
+
+
+
+
+{ "stb", F3(3, 0x05, 0), F3(~3, ~0x05, ~0)|ASI(~0), "d,[1+2]", 0, v6 },
+{ "stb", F3(3, 0x05, 0), F3(~3, ~0x05, ~0)|ASI_RS2(~0), "d,[1]", 0, v6 }, /* stb d,[rs1+%g0] */
+{ "stb", F3(3, 0x05, 1), F3(~3, ~0x05, ~1), "d,[1+i]", 0, v6 },
+{ "stb", F3(3, 0x05, 1), F3(~3, ~0x05, ~1), "d,[i+1]", 0, v6 },
+{ "stb", F3(3, 0x05, 1), F3(~3, ~0x05, ~1)|RS1_G0, "d,[i]", 0, v6 },
+{ "stb", F3(3, 0x05, 1), F3(~3, ~0x05, ~1)|SIMM13(~0), "d,[1]", 0, v6 }, /* stb d,[rs1+0] */
+
+
+
+{ "stba", F3(3, 0x15, 0), F3(~3, ~0x15, ~0), "d,[1+2]A", 0, v6 },
+{ "stba", F3(3, 0x15, 0), F3(~3, ~0x15, ~0)|RS2(~0), "d,[1]A", 0, v6 }, /* stba d,[rs1+%g0] */
+
+
+
+{ "std", F3(3, 0x07, 0), F3(~3, ~0x07, ~0)|ASI(~0), "d,[1+2]", 0, v6 },
+{ "std", F3(3, 0x07, 0), F3(~3, ~0x07, ~0)|ASI_RS2(~0), "d,[1]", 0, v6 }, /* std d,[rs1+%g0] */
+{ "std", F3(3, 0x07, 1), F3(~3, ~0x07, ~1), "d,[1+i]", 0, v6 },
+{ "std", F3(3, 0x07, 1), F3(~3, ~0x07, ~1), "d,[i+1]", 0, v6 },
+{ "std", F3(3, 0x07, 1), F3(~3, ~0x07, ~1)|RS1_G0, "d,[i]", 0, v6 },
+{ "std", F3(3, 0x07, 1), F3(~3, ~0x07, ~1)|SIMM13(~0), "d,[1]", 0, v6 }, /* std d,[rs1+0] */
+{ "std", F3(3, 0x26, 0), F3(~3, ~0x26, ~0)|ASI(~0), "q,[1+2]", 0, v6 },
+{ "std", F3(3, 0x26, 0), F3(~3, ~0x26, ~0)|ASI_RS2(~0), "q,[1]", 0, v6 }, /* std d,[rs1+%g0] */
+{ "std", F3(3, 0x26, 1), F3(~3, ~0x26, ~1), "q,[1+i]", 0, v6 },
+{ "std", F3(3, 0x26, 1), F3(~3, ~0x26, ~1), "q,[i+1]", 0, v6 },
+{ "std", F3(3, 0x26, 1), F3(~3, ~0x26, ~1)|RS1_G0, "q,[i]", 0, v6 },
+{ "std", F3(3, 0x26, 1), F3(~3, ~0x26, ~1)|SIMM13(~0), "q,[1]", 0, v6 }, /* std d,[rs1+0] */
+{ "std", F3(3, 0x27, 0), F3(~3, ~0x27, ~0)|ASI(~0), "g,[1+2]", 0, v6 },
+{ "std", F3(3, 0x27, 0), F3(~3, ~0x27, ~0)|ASI_RS2(~0), "g,[1]", 0, v6 }, /* std d,[rs1+%g0] */
+{ "std", F3(3, 0x27, 1), F3(~3, ~0x27, ~1), "g,[1+i]", 0, v6 },
+{ "std", F3(3, 0x27, 1), F3(~3, ~0x27, ~1), "g,[i+1]", 0, v6 },
+{ "std", F3(3, 0x27, 1), F3(~3, ~0x27, ~1)|RS1_G0, "g,[i]", 0, v6 },
+{ "std", F3(3, 0x27, 1), F3(~3, ~0x27, ~1)|SIMM13(~0), "g,[1]", 0, v6 }, /* std d,[rs1+0] */
+{ "std", F3(3, 0x36, 0), F3(~3, ~0x36, ~0)|ASI(~0), "Q,[1+2]", 0, v6 },
+{ "std", F3(3, 0x36, 0), F3(~3, ~0x36, ~0)|ASI_RS2(~0), "Q,[1]", 0, v6 }, /* std d,[rs1+%g0] */
+{ "std", F3(3, 0x36, 1), F3(~3, ~0x36, ~1), "Q,[1+i]", 0, v6 },
+{ "std", F3(3, 0x36, 1), F3(~3, ~0x36, ~1), "Q,[i+1]", 0, v6 },
+{ "std", F3(3, 0x36, 1), F3(~3, ~0x36, ~1)|RS1_G0, "Q,[i]", 0, v6 },
+{ "std", F3(3, 0x36, 1), F3(~3, ~0x36, ~1)|SIMM13(~0), "Q,[1]", 0, v6 }, /* std d,[rs1+0] */
+{ "std", F3(3, 0x37, 0), F3(~3, ~0x37, ~0)|ASI(~0), "D,[1+2]", 0, v6 },
+{ "std", F3(3, 0x37, 0), F3(~3, ~0x37, ~0)|ASI_RS2(~0), "D,[1]", 0, v6 }, /* std d,[rs1+%g0] */
+{ "std", F3(3, 0x37, 1), F3(~3, ~0x37, ~1), "D,[1+i]", 0, v6 },
+{ "std", F3(3, 0x37, 1), F3(~3, ~0x37, ~1), "D,[i+1]", 0, v6 },
+{ "std", F3(3, 0x37, 1), F3(~3, ~0x37, ~1)|RS1_G0, "D,[i]", 0, v6 },
+{ "std", F3(3, 0x37, 1), F3(~3, ~0x37, ~1)|SIMM13(~0), "D,[1]", 0, v6 }, /* std d,[rs1+0] */
+
+{ "stda", F3(3, 0x17, 0), F3(~3, ~0x17, ~0), "d,[1+2]A", 0, v6 },
+{ "stda", F3(3, 0x17, 0), F3(~3, ~0x17, ~0)|RS2(~0), "d,[1]A", 0, v6 }, /* stda d,[rs1+%g0] */
+
+{ "sth", F3(3, 0x06, 0), F3(~3, ~0x06, ~0)|ASI(~0), "d,[1+2]", 0, v6 },
+{ "sth", F3(3, 0x06, 0), F3(~3, ~0x06, ~0)|ASI_RS2(~0), "d,[1]", 0, v6 }, /* sth d,[rs1+%g0] */
+{ "sth", F3(3, 0x06, 1), F3(~3, ~0x06, ~1), "d,[1+i]", 0, v6 },
+{ "sth", F3(3, 0x06, 1), F3(~3, ~0x06, ~1), "d,[i+1]", 0, v6 },
+{ "sth", F3(3, 0x06, 1), F3(~3, ~0x06, ~1)|RS1_G0, "d,[i]", 0, v6 },
+{ "sth", F3(3, 0x06, 1), F3(~3, ~0x06, ~1)|SIMM13(~0), "d,[1]", 0, v6 }, /* sth d,[+] */
+
+
+
+{ "stha", F3(3, 0x16, 0), F3(~3, ~0x16, ~0), "d,[1+2]A", 0, v6 },
+{ "stha", F3(3, 0x16, 0), F3(~3, ~0x16, ~0)|RS2(~0), "d,[1]A", 0, v6 }, /* stha ,[+%] */
+
+
+
+
+
+{ "swap", F3(3, 0x0f, 0), F3(~3, ~0x0f, ~0)|ASI(~0), "[1+2],d", 0, v7 },
+{ "swap", F3(3, 0x0f, 0), F3(~3, ~0x0f, ~0)|ASI_RS2(~0), "[1],d", 0, v7 }, /* swap [rs1+%g0],d */
+{ "swap", F3(3, 0x0f, 1), F3(~3, ~0x0f, ~1), "[1+i],d", 0, v7 },
+{ "swap", F3(3, 0x0f, 1), F3(~3, ~0x0f, ~1), "[i+1],d", 0, v7 },
+{ "swap", F3(3, 0x0f, 1), F3(~3, ~0x0f, ~1)|RS1_G0, "[i],d", 0, v7 },
+{ "swap", F3(3, 0x0f, 1), F3(~3, ~0x0f, ~1)|SIMM13(~0), "[1],d", 0, v7 }, /* swap [rs1+0],d */
+
+{ "swapa", F3(3, 0x1f, 0), F3(~3, ~0x1f, ~0), "[1+2]A,d", 0, v7 },
+{ "swapa", F3(3, 0x1f, 0), F3(~3, ~0x1f, ~0)|RS2(~0), "[1]A,d", 0, v7 }, /* swapa [rs1+%g0],d */
+
+{ "restore", F3(2, 0x3d, 0), F3(~2, ~0x3d, ~0)|ASI(~0), "1,2,d", 0, v6 },
+{ "restore", F3(2, 0x3d, 0), F3(~2, ~0x3d, ~0)|RD_G0|RS1_G0|ASI_RS2(~0), "", 0, v6 }, /* restore %g0,%g0,%g0 */
+{ "restore", F3(2, 0x3d, 1), F3(~2, ~0x3d, ~1), "1,i,d", 0, v6 },
+{ "restore", F3(2, 0x3d, 1), F3(~2, ~0x3d, ~1)|RD_G0|RS1_G0|SIMM13(~0), "", 0, v6 }, /* restore %g0,0,%g0 */
+
+{ "rett", F3(2, 0x39, 0), F3(~2, ~0x39, ~0)|RD_G0|ASI(~0), "1+2", F_DELAYED, v6 }, /* rett rs1+rs2 */
+{ "rett", F3(2, 0x39, 0), F3(~2, ~0x39, ~0)|RD_G0|ASI_RS2(~0), "1", F_DELAYED, v6 }, /* rett rs1,%g0 */
+{ "rett", F3(2, 0x39, 1), F3(~2, ~0x39, ~1)|RD_G0, "1+i", F_DELAYED, v6 }, /* rett rs1+X */
+{ "rett", F3(2, 0x39, 1), F3(~2, ~0x39, ~1)|RD_G0, "i+1", F_DELAYED, v6 }, /* rett X+rs1 */
+{ "rett", F3(2, 0x39, 1), F3(~2, ~0x39, ~1)|RD_G0|RS1_G0,"i", F_DELAYED, v6 }, /* rett X+rs1 */
+{ "rett", F3(2, 0x39, 1), F3(~2, ~0x39, ~1)|RD_G0|RS1_G0, "i", F_DELAYED, v6 }, /* rett X */
+{ "rett", F3(2, 0x39, 1), F3(~2, ~0x39, ~1)|RD_G0|SIMM13(~0), "1", F_DELAYED, v6 }, /* rett rs1+0 */
+
+{ "save", F3(2, 0x3c, 0), F3(~2, ~0x3c, ~0)|ASI(~0), "1,2,d", 0, v6 },
+{ "save", F3(2, 0x3c, 1), F3(~2, ~0x3c, ~1), "1,i,d", 0, v6 },
+
+{ "ret", F3(2, 0x38, 1)|RS1(0x1f)|SIMM13(8), F3(~2, ~0x38, ~1)|SIMM13(~8), "", F_DELAYED, v6 }, /* jmpl %i7+8,%g0 */
+{ "retl", F3(2, 0x38, 1)|RS1(0x0f)|SIMM13(8), F3(~2, ~0x38, ~1)|RS1(~0x0f)|SIMM13(~8), "", F_DELAYED, v6 }, /* jmpl %o7+8,%g0 */
+
+{ "jmpl", F3(2, 0x38, 0), F3(~2, ~0x38, ~0)|ASI(~0), "1+2,d", F_DELAYED, v6 },
+{ "jmpl", F3(2, 0x38, 0), F3(~2, ~0x38, ~0)|ASI_RS2(~0), "1,d", F_DELAYED, v6 }, /* jmpl rs1+%g0,d */
+{ "jmpl", F3(2, 0x38, 1), F3(~2, ~0x38, ~1)|SIMM13(~0), "1,d", F_DELAYED, v6 }, /* jmpl rs1+0,d */
+{ "jmpl", F3(2, 0x38, 1), F3(~2, ~0x38, ~1)|RS1_G0, "i,d", F_DELAYED, v6 }, /* jmpl %g0+i,d */
+{ "jmpl", F3(2, 0x38, 1), F3(~2, ~0x38, ~1), "1+i,d", F_DELAYED, v6 },
+{ "jmpl", F3(2, 0x38, 1), F3(~2, ~0x38, ~1), "i+1,d", F_DELAYED, v6 },
+{ "jmpl", F3(2, 0x38, 1), F3(~2, ~0x38, ~1)|RS1_G0, "i,d", F_DELAYED, v6 },
+
+ /* The 1<<12 is a long story. It is necessary. For more info, please contact rich@cygnus.com */
+{ "sll", F3(2, 0x25, 0), F3(~2, ~0x25, ~0)|(1<<12)|ASI(~0), "1,2,d", 0, v6 },
+{ "sll", F3(2, 0x25, 1), F3(~2, ~0x25, ~1)|(1<<12), "1,i,d", 0, v6 },
+{ "sra", F3(2, 0x27, 0), F3(~2, ~0x27, ~0)|(1<<12)|ASI(~0), "1,2,d", 0, v6 },
+{ "sra", F3(2, 0x27, 1), F3(~2, ~0x27, ~1)|(1<<12), "1,i,d", 0, v6 },
+{ "srl", F3(2, 0x26, 0), F3(~2, ~0x26, ~0)|(1<<12)|ASI(~0), "1,2,d", 0, v6 },
+{ "srl", F3(2, 0x26, 1), F3(~2, ~0x26, ~1)|(1<<12), "1,i,d", 0, v6 },
+
+
+
+{ "mulscc", F3(2, 0x24, 0), F3(~2, ~0x24, ~0)|ASI(~0), "1,2,d", 0, v6 },
+{ "mulscc", F3(2, 0x24, 1), F3(~2, ~0x24, ~1), "1,i,d", 0, v6 },
+
+{ "clr", F3(2, 0x02, 0), F3(~2, ~0x02, ~0)|RD_G0|RS1_G0|ASI_RS2(~0), "d", F_ALIAS, v6 }, /* or %g0,%g0,d */
+{ "clr", F3(2, 0x02, 1), F3(~2, ~0x02, ~1)|RS1_G0|SIMM13(~0), "d", F_ALIAS, v6 }, /* or %g0,0,d */
+{ "clr", F3(3, 0x04, 0), F3(~3, ~0x04, ~0)|RD_G0|ASI(~0), "[1+2]", F_ALIAS, v6 },
+{ "clr", F3(3, 0x04, 0), F3(~3, ~0x04, ~0)|RD_G0|ASI_RS2(~0), "[1]", F_ALIAS, v6 }, /* st %g0,[rs1+%g0] */
+{ "clr", F3(3, 0x04, 1), F3(~3, ~0x04, ~1)|RD_G0, "[1+i]", F_ALIAS, v6 },
+{ "clr", F3(3, 0x04, 1), F3(~3, ~0x04, ~1)|RD_G0, "[i+1]", F_ALIAS, v6 },
+{ "clr", F3(3, 0x04, 1), F3(~3, ~0x04, ~1)|RD_G0|RS1_G0, "[i]", F_ALIAS, v6 },
+{ "clr", F3(3, 0x04, 1), F3(~3, ~0x04, ~1)|RD_G0|SIMM13(~0), "[1]", F_ALIAS, v6 }, /* st %g0,[rs1+0] */
+
+{ "clrb", F3(3, 0x05, 0), F3(~3, ~0x05, ~0)|RD_G0|ASI(~0), "[1+2]", F_ALIAS, v6 },
+{ "clrb", F3(3, 0x05, 0), F3(~3, ~0x05, ~0)|RD_G0|ASI_RS2(~0), "[1]", F_ALIAS, v6 }, /* stb %g0,[rs1+%g0] */
+{ "clrb", F3(3, 0x05, 1), F3(~3, ~0x05, ~1)|RD_G0, "[1+i]", F_ALIAS, v6 },
+{ "clrb", F3(3, 0x05, 1), F3(~3, ~0x05, ~1)|RD_G0, "[i+1]", F_ALIAS, v6 },
+{ "clrb", F3(3, 0x05, 1), F3(~3, ~0x05, ~1)|RD_G0|RS1_G0, "[i]", F_ALIAS, v6 },
+
+{ "clrh", F3(3, 0x06, 0), F3(~3, ~0x06, ~0)|RD_G0|ASI(~0), "[1+2]", F_ALIAS, v6 },
+{ "clrh", F3(3, 0x06, 0), F3(~3, ~0x06, ~0)|RD_G0|ASI_RS2(~0), "[1]", F_ALIAS, v6 }, /* sth %g0,[rs1+%g0] */
+{ "clrh", F3(3, 0x06, 1), F3(~3, ~0x06, ~1)|RD_G0, "[1+i]", F_ALIAS, v6 },
+{ "clrh", F3(3, 0x06, 1), F3(~3, ~0x06, ~1)|RD_G0, "[i+1]", F_ALIAS, v6 },
+{ "clrh", F3(3, 0x06, 1), F3(~3, ~0x06, ~1)|RD_G0|RS1_G0, "[i]", F_ALIAS, v6 },
+
+{ "orcc", F3(2, 0x12, 0), F3(~2, ~0x12, ~0)|ASI(~0), "1,2,d", 0, v6 },
+{ "orcc", F3(2, 0x12, 1), F3(~2, ~0x12, ~1), "1,i,d", 0, v6 },
+{ "orcc", F3(2, 0x12, 1), F3(~2, ~0x12, ~1), "i,1,d", 0, v6 },
+
+{ "orncc", F3(2, 0x16, 0), F3(~2, ~0x16, ~0)|ASI(~0), "1,2,d", 0, v6 },
+{ "orncc", F3(2, 0x16, 1), F3(~2, ~0x16, ~1), "1,i,d", 0, v6 },
+{ "orncc", F3(2, 0x16, 1), F3(~2, ~0x16, ~1), "i,1,d", 0, v6 },
+
+{ "orn", F3(2, 0x06, 0), F3(~2, ~0x06, ~0)|ASI(~0), "1,2,d", 0, v6 },
+{ "orn", F3(2, 0x06, 1), F3(~2, ~0x06, ~1), "1,i,d", 0, v6 },
+{ "orn", F3(2, 0x06, 1), F3(~2, ~0x06, ~1), "i,1,d", 0, v6 },
+
+{ "tst", F3(2, 0x12, 0), F3(~2, ~0x12, ~0)|RD_G0|ASI_RS2(~0), "1", 0, v6 }, /* orcc rs1, %g0, %g0 */
+{ "tst", F3(2, 0x12, 0), F3(~2, ~0x12, ~0)|RD_G0|RS1_G0|ASI(~0), "2", 0, v6 }, /* orcc %g0, rs2, %g0 */
+{ "tst", F3(2, 0x12, 1), F3(~2, ~0x12, ~1)|RD_G0|SIMM13(~0), "1", 0, v6 }, /* orcc rs1, 0, %g0 */
+
+{ "wr", F3(2, 0x30, 0), F3(~2, ~0x30, ~0)|ASI(~0), "1,2,m", 0, v8 }, /* wr r,r,%asrX */
+{ "wr", F3(2, 0x30, 0), F3(~2, ~0x30, ~0)|RD_G0|ASI(~0), "1,2,y", 0, v6 }, /* wr r,r,%y */
+{ "wr", F3(2, 0x30, 1), F3(~2, ~0x30, ~1), "1,i,m", 0, v8 }, /* wr r,i,%asrX */
+{ "wr", F3(2, 0x30, 1), F3(~2, ~0x30, ~1)|RD_G0, "1,i,y", 0, v6 }, /* wr r,i,%y */
+{ "wr", F3(2, 0x31, 0), F3(~2, ~0x31, ~0)|RD_G0|ASI(~0), "1,2,p", 0, v6 }, /* wr r,r,%psr */
+{ "wr", F3(2, 0x31, 1), F3(~2, ~0x31, ~1)|RD_G0, "1,i,p", 0, v6 }, /* wr r,i,%psr */
+{ "wr", F3(2, 0x32, 0), F3(~2, ~0x32, ~0)|RD_G0|ASI(~0), "1,2,w", 0, v6 }, /* wr r,r,%wim */
+{ "wr", F3(2, 0x32, 1), F3(~2, ~0x32, ~1)|RD_G0, "1,i,w", 0, v6 }, /* wr r,i,%wim */
+{ "wr", F3(2, 0x33, 0), F3(~2, ~0x33, ~0)|RD_G0|ASI(~0), "1,2,t", 0, v6 }, /* wr r,r,%tbr */
+{ "wr", F3(2, 0x33, 1), F3(~2, ~0x33, ~1)|RD_G0, "1,i,t", 0, v6 }, /* wr r,i,%tbr */
+
+
+{ "rd", F3(2, 0x28, 0), F3(~2, ~0x28, ~0)|SIMM13(~0), "M,d", 0, v8 }, /* rd %asr1,r */
+{ "rd", F3(2, 0x28, 0), F3(~2, ~0x28, ~0)|RS1_G0|SIMM13(~0), "y,d", 0, v6 }, /* rd %y,r */
+{ "rd", F3(2, 0x2b, 0), F3(~2, ~0x2b, ~0)|RS1_G0|SIMM13(~0), "t,d", 0, v6 }, /* rd %tbr,r */
+
+{ "rd", F3(2, 0x29, 0), F3(~2, ~0x29, ~0)|RS1_G0|SIMM13(~0), "p,d", 0, v6 }, /* rd %psr,r */
+{ "rd", F3(2, 0x2a, 0), F3(~2, ~0x2a, ~0)|RS1_G0|SIMM13(~0), "w,d", 0, v6 }, /* rd %wim,r */
+
+{ "mov", F3(2, 0x30, 0), F3(~2, ~0x30, ~0)|ASI(~0), "1,2,m", F_ALIAS, v8 }, /* wr r,r,%asrX */
+{ "mov", F3(2, 0x30, 0), F3(~2, ~0x30, ~0)|RD_G0|ASI(~0), "1,2,y", F_ALIAS, v6 }, /* wr r,r,%y */
+{ "mov", F3(2, 0x30, 1), F3(~2, ~0x30, ~1), "1,i,m", F_ALIAS, v8 }, /* wr r,i,%asrX */
+{ "mov", F3(2, 0x30, 1), F3(~2, ~0x30, ~1)|RD_G0, "1,i,y", F_ALIAS, v6 }, /* wr r,i,%y */
+{ "mov", F3(2, 0x31, 0), F3(~2, ~0x31, ~0)|RD_G0|ASI(~0), "1,2,p", F_ALIAS, v6 }, /* wr r,r,%psr */
+{ "mov", F3(2, 0x31, 1), F3(~2, ~0x31, ~1)|RD_G0, "1,i,p", F_ALIAS, v6 }, /* wr r,i,%psr */
+{ "mov", F3(2, 0x32, 0), F3(~2, ~0x32, ~0)|RD_G0|ASI(~0), "1,2,w", F_ALIAS, v6 }, /* wr r,r,%wim */
+{ "mov", F3(2, 0x32, 1), F3(~2, ~0x32, ~1)|RD_G0, "1,i,w", F_ALIAS, v6 }, /* wr r,i,%wim */
+{ "mov", F3(2, 0x33, 0), F3(~2, ~0x33, ~0)|RD_G0|ASI(~0), "1,2,t", F_ALIAS, v6 }, /* wr r,r,%tbr */
+{ "mov", F3(2, 0x33, 1), F3(~2, ~0x33, ~1)|RD_G0, "1,i,t", F_ALIAS, v6 }, /* wr r,i,%tbr */
+
+{ "mov", F3(2, 0x28, 0), F3(~2, ~0x28, ~0)|SIMM13(~0), "M,d", F_ALIAS, v8 }, /* rd %asr1,r */
+{ "mov", F3(2, 0x28, 0), F3(~2, ~0x28, ~0)|RS1_G0|SIMM13(~0), "y,d", F_ALIAS, v6 }, /* rd %y,r */
+{ "mov", F3(2, 0x29, 0), F3(~2, ~0x29, ~0)|RS1_G0|SIMM13(~0), "p,d", F_ALIAS, v6 }, /* rd %psr,r */
+{ "mov", F3(2, 0x2a, 0), F3(~2, ~0x2a, ~0)|RS1_G0|SIMM13(~0), "w,d", F_ALIAS, v6 }, /* rd %wim,r */
+{ "mov", F3(2, 0x2b, 0), F3(~2, ~0x2b, ~0)|RS1_G0|SIMM13(~0), "t,d", F_ALIAS, v6 }, /* rd %tbr,r */
+
+{ "mov", F3(2, 0x30, 0), F3(~2, ~0x30, ~0)|ASI_RS2(~0), "1,y", F_ALIAS, v6 }, /* wr rs1,%g0,%y */
+{ "mov", F3(2, 0x30, 1), F3(~2, ~0x30, ~1), "i,y", F_ALIAS, v6 },
+{ "mov", F3(2, 0x30, 1), F3(~2, ~0x30, ~1)|SIMM13(~0), "1,y", F_ALIAS, v6 }, /* wr rs1,0,%y */
+{ "mov", F3(2, 0x31, 0), F3(~2, ~0x31, ~0)|ASI_RS2(~0), "1,p", F_ALIAS, v6 }, /* wr rs1,%g0,%psr */
+{ "mov", F3(2, 0x31, 1), F3(~2, ~0x31, ~1), "i,p", F_ALIAS, v6 },
+{ "mov", F3(2, 0x31, 1), F3(~2, ~0x31, ~1)|SIMM13(~0), "1,p", F_ALIAS, v6 }, /* wr rs1,0,%psr */
+{ "mov", F3(2, 0x32, 0), F3(~2, ~0x32, ~0)|ASI_RS2(~0), "1,w", F_ALIAS, v6 }, /* wr rs1,%g0,%wim */
+{ "mov", F3(2, 0x32, 1), F3(~2, ~0x32, ~1), "i,w", F_ALIAS, v6 },
+{ "mov", F3(2, 0x32, 1), F3(~2, ~0x32, ~1)|SIMM13(~0), "1,w", F_ALIAS, v6 }, /* wr rs1,0,%wim */
+{ "mov", F3(2, 0x33, 0), F3(~2, ~0x33, ~0)|ASI_RS2(~0), "1,t", F_ALIAS, v6 }, /* wr rs1,%g0,%tbr */
+{ "mov", F3(2, 0x33, 1), F3(~2, ~0x33, ~1), "i,t", F_ALIAS, v6 },
+{ "mov", F3(2, 0x33, 1), F3(~2, ~0x33, ~1)|SIMM13(~0), "1,t", F_ALIAS, v6 }, /* wr rs1,0,%tbr */
+
+{ "mov", F3(2, 0x02, 0), F3(~2, ~0x02, ~0)|RS1_G0|ASI(~0), "2,d", 0, v6 }, /* or %g0,rs2,d */
+{ "mov", F3(2, 0x02, 1), F3(~2, ~0x02, ~1)|RS1_G0, "i,d", 0, v6 }, /* or %g0,i,d */
+{ "mov", F3(2, 0x02, 0), F3(~2, ~0x02, ~0)|ASI_RS2(~0), "1,d", 0, v6 }, /* or rs1,%g0,d */
+{ "mov", F3(2, 0x02, 1), F3(~2, ~0x02, ~1)|SIMM13(~0), "1,d", 0, v6 }, /* or rs1,0,d */
+
+{ "or", F3(2, 0x02, 0), F3(~2, ~0x02, ~0)|ASI(~0), "1,2,d", 0, v6 },
+{ "or", F3(2, 0x02, 1), F3(~2, ~0x02, ~1), "1,i,d", 0, v6 },
+{ "or", F3(2, 0x02, 1), F3(~2, ~0x02, ~1), "i,1,d", 0, v6 },
+
+{ "bset", F3(2, 0x02, 0), F3(~2, ~0x02, ~0)|ASI(~0), "2,r", F_ALIAS, v6 }, /* or rd,rs2,rd */
+{ "bset", F3(2, 0x02, 1), F3(~2, ~0x02, ~1), "i,r", F_ALIAS, v6 }, /* or rd,i,rd */
+
+{ "andn", F3(2, 0x05, 0), F3(~2, ~0x05, ~0)|ASI(~0), "1,2,d", 0, v6 },
+{ "andn", F3(2, 0x05, 1), F3(~2, ~0x05, ~1), "1,i,d", 0, v6 },
+{ "andn", F3(2, 0x05, 1), F3(~2, ~0x05, ~1), "i,1,d", 0, v6 },
+
+{ "andncc", F3(2, 0x15, 0), F3(~2, ~0x15, ~0)|ASI(~0), "1,2,d", 0, v6 },
+{ "andncc", F3(2, 0x15, 1), F3(~2, ~0x15, ~1), "1,i,d", 0, v6 },
+{ "andncc", F3(2, 0x15, 1), F3(~2, ~0x15, ~1), "i,1,d", 0, v6 },
+
+{ "bclr", F3(2, 0x05, 0), F3(~2, ~0x05, ~0)|ASI(~0), "2,r", F_ALIAS, v6 }, /* andn rd,rs2,rd */
+{ "bclr", F3(2, 0x05, 1), F3(~2, ~0x05, ~1), "i,r", F_ALIAS, v6 }, /* andn rd,i,rd */
+
+{ "cmp", F3(2, 0x14, 0), F3(~2, ~0x14, ~0)|RD_G0|ASI(~0), "1,2", 0, v6 }, /* subcc rs1,rs2,%g0 */
+{ "cmp", F3(2, 0x14, 1), F3(~2, ~0x14, ~1)|RD_G0, "1,i", 0, v6 }, /* subcc rs1,i,%g0 */
+
+{ "sub", F3(2, 0x04, 0), F3(~2, ~0x04, ~0)|ASI(~0), "1,2,d", 0, v6 },
+{ "sub", F3(2, 0x04, 1), F3(~2, ~0x04, ~1), "1,i,d", 0, v6 },
+
+{ "subcc", F3(2, 0x14, 0), F3(~2, ~0x14, ~0)|ASI(~0), "1,2,d", 0, v6 },
+{ "subcc", F3(2, 0x14, 1), F3(~2, ~0x14, ~1), "1,i,d", 0, v6 },
+
+{ "subx", F3(2, 0x0c, 0), F3(~2, ~0x0c, ~0)|ASI(~0), "1,2,d", 0, v6 },
+{ "subx", F3(2, 0x0c, 1), F3(~2, ~0x0c, ~1), "1,i,d", 0, v6 },
+
+{ "subxcc", F3(2, 0x1c, 0), F3(~2, ~0x1c, ~0)|ASI(~0), "1,2,d", 0, v6 },
+{ "subxcc", F3(2, 0x1c, 1), F3(~2, ~0x1c, ~1), "1,i,d", 0, v6 },
+
+{ "and", F3(2, 0x01, 0), F3(~2, ~0x01, ~0)|ASI(~0), "1,2,d", 0, v6 },
+{ "and", F3(2, 0x01, 1), F3(~2, ~0x01, ~1), "1,i,d", 0, v6 },
+{ "and", F3(2, 0x01, 1), F3(~2, ~0x01, ~1), "i,1,d", 0, v6 },
+
+{ "andcc", F3(2, 0x11, 0), F3(~2, ~0x11, ~0)|ASI(~0), "1,2,d", 0, v6 },
+{ "andcc", F3(2, 0x11, 1), F3(~2, ~0x11, ~1), "1,i,d", 0, v6 },
+{ "andcc", F3(2, 0x11, 1), F3(~2, ~0x11, ~1), "i,1,d", 0, v6 },
+
+{ "dec", F3(2, 0x04, 1)|SIMM13(0x1), F3(~2, ~0x04, ~1)|SIMM13(~0x0001), "r", F_ALIAS, v6 }, /* sub rd,1,rd */
+{ "dec", F3(2, 0x04, 1), F3(~2, ~0x04, ~1), "i,r", F_ALIAS, v6 }, /* sub rd,i,rd */
+{ "deccc", F3(2, 0x14, 1)|SIMM13(0x1), F3(~2, ~0x14, ~1)|SIMM13(~0x0001), "r", F_ALIAS, v6 }, /* subcc rd,1,rd */
+{ "deccc", F3(2, 0x14, 1), F3(~2, ~0x14, ~1), "i,r", F_ALIAS, v6 }, /* subcc rd,i,rd */
+{ "inc", F3(2, 0x00, 1)|SIMM13(0x1), F3(~2, ~0x00, ~1)|SIMM13(~0x0001), "r", F_ALIAS, v6 }, /* add rs1,1,rsd */
+{ "inc", F3(2, 0x00, 1), F3(~2, ~0x00, ~1), "i,r", F_ALIAS, v6 }, /* add rs1,i,rsd */
+{ "inccc", F3(2, 0x10, 1)|SIMM13(0x1), F3(~2, ~0x10, ~1)|SIMM13(~0x0001), "r", F_ALIAS, v6 }, /* addcc rd,1,rd */
+{ "inccc", F3(2, 0x10, 1), F3(~2, ~0x10, ~1), "i,r", F_ALIAS, v6 }, /* addcc rd,i,rd */
+
+{ "btst", F3(2, 0x11, 0), F3(~2, ~0x11, ~0)|RD_G0|ASI(~0), "1,2", F_ALIAS, v6 }, /* andcc rs1,rs2,%g0 */
+{ "btst", F3(2, 0x11, 1), F3(~2, ~0x11, ~1)|RD_G0, "i,1", F_ALIAS, v6 }, /* andcc rs1,i,%g0 */
+
+{ "neg", F3(2, 0x04, 0), F3(~2, ~0x04, ~0)|RS1_G0|ASI(~0), "2,d", F_ALIAS, v6 }, /* sub %g0,rs2,rd */
+{ "neg", F3(2, 0x04, 0), F3(~2, ~0x04, ~0)|RS1_G0|ASI(~0), "x", F_ALIAS, v6 }, /* sub %g0,rd,rd */
+
+{ "add", F3(2, 0x00, 0), F3(~2, ~0x00, ~0)|ASI(~0), "1,2,d", 0, v6 },
+{ "add", F3(2, 0x00, 1), F3(~2, ~0x00, ~1), "1,i,d", 0, v6 },
+{ "add", F3(2, 0x00, 1), F3(~2, ~0x00, ~1), "i,1,d", 0, v6 },
+{ "addcc", F3(2, 0x10, 0), F3(~2, ~0x10, ~0)|ASI(~0), "1,2,d", 0, v6 },
+{ "addcc", F3(2, 0x10, 1), F3(~2, ~0x10, ~1), "1,i,d", 0, v6 },
+{ "addcc", F3(2, 0x10, 1), F3(~2, ~0x10, ~1), "i,1,d", 0, v6 },
+{ "addx", F3(2, 0x08, 0), F3(~2, ~0x08, ~0)|ASI(~0), "1,2,d", 0, v6 },
+{ "addx", F3(2, 0x08, 1), F3(~2, ~0x08, ~1), "1,i,d", 0, v6 },
+{ "addx", F3(2, 0x08, 1), F3(~2, ~0x08, ~1), "i,1,d", 0, v6 },
+{ "addxcc", F3(2, 0x18, 0), F3(~2, ~0x18, ~0)|ASI(~0), "1,2,d", 0, v6 },
+{ "addxcc", F3(2, 0x18, 1), F3(~2, ~0x18, ~1), "1,i,d", 0, v6 },
+{ "addxcc", F3(2, 0x18, 1), F3(~2, ~0x18, ~1), "i,1,d", 0, v6 },
+
+{ "smul", F3(2, 0x0b, 0), F3(~2, ~0x0b, ~0)|ASI(~0), "1,2,d", 0, v8 },
+{ "smul", F3(2, 0x0b, 1), F3(~2, ~0x0b, ~1), "1,i,d", 0, v8 },
+{ "smul", F3(2, 0x0b, 1), F3(~2, ~0x0b, ~1), "i,1,d", 0, v8 },
+{ "smulcc", F3(2, 0x1b, 0), F3(~2, ~0x1b, ~0)|ASI(~0), "1,2,d", 0, v8 },
+{ "smulcc", F3(2, 0x1b, 1), F3(~2, ~0x1b, ~1), "1,i,d", 0, v8 },
+{ "smulcc", F3(2, 0x1b, 1), F3(~2, ~0x1b, ~1), "i,1,d", 0, v8 },
+{ "umul", F3(2, 0x0a, 0), F3(~2, ~0x0a, ~0)|ASI(~0), "1,2,d", 0, v8 },
+{ "umul", F3(2, 0x0a, 1), F3(~2, ~0x0a, ~1), "1,i,d", 0, v8 },
+{ "umul", F3(2, 0x0a, 1), F3(~2, ~0x0a, ~1), "i,1,d", 0, v8 },
+{ "umulcc", F3(2, 0x1a, 0), F3(~2, ~0x1a, ~0)|ASI(~0), "1,2,d", 0, v8 },
+{ "umulcc", F3(2, 0x1a, 1), F3(~2, ~0x1a, ~1), "1,i,d", 0, v8 },
+{ "umulcc", F3(2, 0x1a, 1), F3(~2, ~0x1a, ~1), "i,1,d", 0, v8 },
+{ "sdiv", F3(2, 0x0f, 0), F3(~2, ~0x0f, ~0)|ASI(~0), "1,2,d", 0, v8 },
+{ "sdiv", F3(2, 0x0f, 1), F3(~2, ~0x0f, ~1), "1,i,d", 0, v8 },
+{ "sdiv", F3(2, 0x0f, 1), F3(~2, ~0x0f, ~1), "i,1,d", 0, v8 },
+{ "sdivcc", F3(2, 0x1f, 0), F3(~2, ~0x1f, ~0)|ASI(~0), "1,2,d", 0, v8 },
+{ "sdivcc", F3(2, 0x1f, 1), F3(~2, ~0x1f, ~1), "1,i,d", 0, v8 },
+{ "sdivcc", F3(2, 0x1f, 1), F3(~2, ~0x1f, ~1), "i,1,d", 0, v8 },
+{ "udiv", F3(2, 0x0e, 0), F3(~2, ~0x0e, ~0)|ASI(~0), "1,2,d", 0, v8 },
+{ "udiv", F3(2, 0x0e, 1), F3(~2, ~0x0e, ~1), "1,i,d", 0, v8 },
+{ "udiv", F3(2, 0x0e, 1), F3(~2, ~0x0e, ~1), "i,1,d", 0, v8 },
+{ "udivcc", F3(2, 0x1e, 0), F3(~2, ~0x1e, ~0)|ASI(~0), "1,2,d", 0, v8 },
+{ "udivcc", F3(2, 0x1e, 1), F3(~2, ~0x1e, ~1), "1,i,d", 0, v8 },
+{ "udivcc", F3(2, 0x1e, 1), F3(~2, ~0x1e, ~1), "i,1,d", 0, v8 },
+
+{ "call", F1(0x1), F1(~0x1), "L", F_DELAYED, v6 },
+{ "call", F1(0x1), F1(~0x1), "L,#", F_DELAYED, v6 },
+{ "call", F3(2, 0x38, 0)|RD(0xf), F3(~2, ~0x38, ~0)|RD(~0xf)|ASI_RS2(~0), "1", F_DELAYED, v6 }, /* jmpl rs1+%g0, %o7 */
+{ "call", F3(2, 0x38, 0)|RD(0xf), F3(~2, ~0x38, ~0)|RD(~0xf)|ASI_RS2(~0), "1,#", F_DELAYED, v6 },
+
+{ "call", F3(2, 0x38, 0)|RD(0xf), F3(~2, ~0x38, ~0)|RD(~0xf),
+"1+2", F_DELAYED, v6 }, /* jmpl rs1+rs2,%o7 */
+{ "call", F3(2, 0x38, 0)|RD(0xf), F3(~2, ~0x38, ~0)|RD(~0xf),
+"1+2,#", F_DELAYED, v6 }, /* jmpl rs1+rs2,%o7 */
+
+{ "call", F3(2, 0x38, 1)|RD(0xf), F3(~2, ~0x38, ~1)|RD(~0xf),
+"1+i", F_DELAYED, v6 }, /* jmpl rs1+i,%o7 */
+{ "call", F3(2, 0x38, 1)|RD(0xf), F3(~2, ~0x38, ~1)|RD(~0xf),
+"1+i,#", F_DELAYED, v6 }, /* jmpl rs1+i,%o7 */
+{ "call", F3(2, 0x38, 1)|RD(0xf), F3(~2, ~0x38, ~1)|RD(~0xf),
+"i+1", F_DELAYED, v6 }, /* jmpl i+rs1,%o7 */
+{ "call", F3(2, 0x38, 1)|RD(0xf), F3(~2, ~0x38, ~1)|RD(~0xf),
+"i+1,#", F_DELAYED, v6 }, /* jmpl i+rs1,%o7 */
+
+/* Conditional instructions.
+
+ Because this part of the table was such a mess earlier, I have
+ macrofied it so that all the branches and traps are generated from
+ a single-line description of each condition value. John Gilmore. */
+
+/* Define branches -- one annulled, one without, etc. */
+#define br(opcode, mask, lose, flags) \
+ { opcode, (mask)|ANNUL, (lose), ",a l", (flags), v6 }, \
+ { opcode, (mask) , (lose)|ANNUL, "l", (flags), v6 }
+
+
+/* Define four traps: reg+reg, reg + immediate, immediate alone, reg alone. */
+#define tr(opcode, mask, lose, flags) \
+ { opcode, (mask)|IMMED, (lose)|RS1_G0, "i", (flags), v6 }, /* %g0 + imm */ \
+ { opcode, (mask)|IMMED, (lose), "1+i", (flags), v6 }, /* rs1 + imm */ \
+ { opcode, (mask), IMMED|(lose), "1+2", (flags), v6 }, /* rs1 + rs2 */ \
+ { opcode, (mask), IMMED|(lose)|RS2_G0, "1", (flags), v6 } /* rs1 + %g0 */
+
+/* Define both branches and traps based on condition mask */
+#define cond(bop, top, mask, flags) \
+ br(bop, F2(0, 2)|(mask), F2(~0, ~2)|((~mask)&COND(~0)), F_DELAYED|(flags)), \
+ tr(top, F3(2, 0x3a, 0)|(mask), F3(~2, ~0x3a, 0)|((~mask)&COND(~0)), (flags))
+
+/* Define all the conditions, all the branches, all the traps. */
+
+cond ("b", "t", CONDA, 0),
+cond ("ba", "ta", CONDA, F_ALIAS), /* for nothing */
+cond ("bcc", "tcc", CONDCC, 0),
+cond ("bcs", "tcs", CONDCS, 0),
+cond ("be", "te", CONDE, 0),
+cond ("beq", "teq", CONDE, F_ALIAS), /* for be */
+cond ("bg", "tg", CONDG, 0),
+cond ("bgt", "tgt", CONDG, F_ALIAS),
+cond ("bge", "tge", CONDGE, 0),
+cond ("bgeu", "tgeu", CONDGEU, F_ALIAS), /* for cc */
+cond ("bgu", "tgu", CONDGU, 0),
+cond ("bl", "tl", CONDL, 0),
+cond ("blt", "tlt", CONDL, F_ALIAS),
+cond ("ble", "tle", CONDLE, 0),
+cond ("bleu", "tleu", CONDLEU, 0),
+cond ("blu", "tlu", CONDLU, F_ALIAS), /* for cs */
+cond ("bn", "tn", CONDN, 0),
+cond ("bne", "tne", CONDNE, 0),
+cond ("bneg", "tneg", CONDNEG, 0),
+cond ("bnz", "tnz", CONDNZ, F_ALIAS), /* for ne */
+cond ("bpos", "tpos", CONDPOS, 0),
+cond ("bvc", "tvc", CONDVC, 0),
+cond ("bvs", "tvs", CONDVS, 0),
+cond ("bz", "tz", CONDZ, F_ALIAS), /* for e */
+
+#undef cond
+#undef br
+#undef tr
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#define brfc(opcode, mask, lose, flags) \
+ { opcode, (mask), ANNUL|(lose), "l", flags|F_DELAYED, v6 }, \
+ { opcode, (mask)|ANNUL, (lose), ",a l", flags|F_DELAYED, v6 }
+
+
+#define condfc(fop, cop, mask, flags) \
+ brfc(fop, F2(0, 6)|COND(mask), F2(~0, ~6)|COND(~(mask)), flags), \
+ brfc(cop, F2(0, 7)|COND(mask), F2(~0, ~7)|COND(~(mask)), flags) \
+
+condfc("fb", "cb", 0x8, 0),
+condfc("fba", "cba", 0x8, F_ALIAS),
+condfc("fbe", "cb0", 0x9, 0),
+condfc("fbg", "cb2", 0x6, 0),
+condfc("fbge", "cb02", 0xb, 0),
+condfc("fbl", "cb1", 0x4, 0),
+condfc("fble", "cb01", 0xd, 0),
+condfc("fblg", "cb12", 0x2, 0),
+condfc("fbn", "cbn", 0x0, 0),
+condfc("fbne", "cb123", 0x1, 0),
+condfc("fbo", "cb012", 0xf, 0),
+condfc("fbu", "cb3", 0x7, 0),
+condfc("fbue", "cb03", 0xa, 0),
+condfc("fbug", "cb23", 0x5, 0),
+condfc("fbuge", "cb023", 0xc, 0),
+condfc("fbul", "cb13", 0x3, 0),
+condfc("fbule", "cb013", 0xe, 0),
+
+#undef condfc
+#undef brfc
+
+{ "jmp", F3(2, 0x38, 0), F3(~2, ~0x38, ~0)|RD_G0|ASI(~0), "1+2", F_DELAYED, v6 }, /* jmpl rs1+rs2,%g0 */
+{ "jmp", F3(2, 0x38, 0), F3(~2, ~0x38, ~0)|RD_G0|ASI_RS2(~0), "1", F_DELAYED, v6 }, /* jmpl rs1+%g0,%g0 */
+{ "jmp", F3(2, 0x38, 1), F3(~2, ~0x38, ~1)|RD_G0, "1+i", F_DELAYED, v6 }, /* jmpl rs1+i,%g0 */
+{ "jmp", F3(2, 0x38, 1), F3(~2, ~0x38, ~1)|RD_G0, "i+1", F_DELAYED, v6 }, /* jmpl i+rs1,%g0 */
+{ "jmp", F3(2, 0x38, 1), F3(~2, ~0x38, ~1)|RD_G0|RS1_G0, "i", F_DELAYED, v6 }, /* jmpl %g0+i,%g0 */
+
+{ "nop", F2(0, 4), 0xfeffffff, "", 0, v6 }, /* sethi 0, %g0 */
+
+{ "set", F2(0x0, 0x4), F2(~0x0, ~0x4), "Sh,d", F_ALIAS, v6 },
+
+{ "sethi", F2(0x0, 0x4), F2(~0x0, ~0x4), "h,d", 0, v6 },
+
+{ "taddcc", F3(2, 0x20, 0), F3(~2, ~0x20, ~0)|ASI(~0), "1,2,d", 0, v6 },
+{ "taddcc", F3(2, 0x20, 1), F3(~2, ~0x20, ~1), "1,i,d", 0, v6 },
+{ "taddcc", F3(2, 0x20, 1), F3(~2, ~0x20, ~1), "i,1,d", 0, v6 },
+{ "taddcctv", F3(2, 0x22, 0), F3(~2, ~0x22, ~0)|ASI(~0), "1,2,d", 0, v6 },
+{ "taddcctv", F3(2, 0x22, 1), F3(~2, ~0x22, ~1), "1,i,d", 0, v6 },
+{ "taddcctv", F3(2, 0x22, 1), F3(~2, ~0x22, ~1), "i,1,d", 0, v6 },
+
+{ "tsubcc", F3(2, 0x21, 0), F3(~2, ~0x21, ~0)|ASI(~0), "1,2,d", 0, v6 },
+{ "tsubcc", F3(2, 0x21, 1), F3(~2, ~0x21, ~1), "1,i,d", 0, v6 },
+{ "tsubcctv", F3(2, 0x23, 0), F3(~2, ~0x23, ~0)|ASI(~0), "1,2,d", 0, v6 },
+{ "tsubcctv", F3(2, 0x23, 1), F3(~2, ~0x23, ~1), "1,i,d", 0, v6 },
+
+{ "unimp", F2(0x0, 0x0), 0xffc00000, "n", 0, v6 },
+
+{ "iflush", F3(2, 0x3b, 0), F3(~2, ~0x3b, ~0)|ASI(~0), "1+2", 0, v6 },
+{ "iflush", F3(2, 0x3b, 1), F3(~2, ~0x3b, ~1), "1+i", 0, v6 },
+{ "iflush", F3(2, 0x3b, 1), F3(~2, ~0x3b, ~1), "i+1", 0, v6 },
+{ "iflush", F3(2, 0x3b, 1), F3(~2, ~0x3b, ~1)|RS1_G0, "i", 0, v6 },
+
+{ "xnor", F3(2, 0x07, 0), F3(~2, ~0x07, ~0)|ASI(~0), "1,2,d", 0, v6 },
+{ "xnor", F3(2, 0x07, 1), F3(~2, ~0x07, ~1), "1,i,d", 0, v6 },
+{ "xnor", F3(2, 0x07, 1), F3(~2, ~0x07, ~1), "i,1,d", 0, v6 },
+{ "xnorcc", F3(2, 0x17, 0), F3(~2, ~0x17, ~0)|ASI(~0), "1,2,d", 0, v6 },
+{ "xnorcc", F3(2, 0x17, 1), F3(~2, ~0x17, ~1), "1,i,d", 0, v6 },
+{ "xnorcc", F3(2, 0x17, 1), F3(~2, ~0x17, ~1), "i,1,d", 0, v6 },
+{ "xor", F3(2, 0x03, 0), F3(~2, ~0x03, ~0)|ASI(~0), "1,2,d", 0, v6 },
+{ "xor", F3(2, 0x03, 1), F3(~2, ~0x03, ~1), "1,i,d", 0, v6 },
+{ "xor", F3(2, 0x03, 1), F3(~2, ~0x03, ~1), "i,1,d", 0, v6 },
+{ "xorcc", F3(2, 0x13, 0), F3(~2, ~0x13, ~0)|ASI(~0), "1,2,d", 0, v6 },
+{ "xorcc", F3(2, 0x13, 1), F3(~2, ~0x13, ~1), "1,i,d", 0, v6 },
+{ "xorcc", F3(2, 0x13, 1), F3(~2, ~0x13, ~1), "i,1,d", 0, v6 },
+
+{ "not", F3(2, 0x07, 0), F3(~2, ~0x07, ~0)|ASI(~0), "1,d", F_ALIAS, v6 }, /* xnor rs1,%0,rd */
+{ "not", F3(2, 0x07, 0), F3(~2, ~0x07, ~0)|ASI(~0), "r", F_ALIAS, v6 }, /* xnor rd,%0,rd */
+
+{ "btog", F3(2, 0x03, 0), F3(~2, ~0x03, ~0)|ASI(~0), "2,r", F_ALIAS, v6 }, /* xor rd,rs2,rd */
+{ "btog", F3(2, 0x03, 1), F3(~2, ~0x03, ~1), "i,r", F_ALIAS, v6 }, /* xor rd,i,rd */
+
+{ "fpop1", F3F(2, 0x34, 0), F3F(~2, ~0x34, ~1), "[1+2],d", 0, v6 },
+{ "fpop2", F3F(2, 0x35, 0), F3F(~2, ~0x35, ~1), "[1+2],d", 0, v6 },
+
+/* float-start */
+{ "fdtoi", F3F(2, 0x34, 0x0d2), F3F(~2, ~0x34, ~0x0d2)|RS1_G0, "B,g", 0, v6 },
+{ "fstoi", F3F(2, 0x34, 0x0d1), F3F(~2, ~0x34, ~0x0d1)|RS1_G0, "f,g", 0, v6 },
+
+ /* all of these conversions are confused and probably wrong. */
+{ "fitod", F3F(2, 0x34, 0x0c8), F3F(~2, ~0x34, ~0x0c8)|RS1_G0, "f,H", 0, v6 },
+{ "fitos", F3F(2, 0x34, 0x0c4), F3F(~2, ~0x34, ~0x0c4)|RS1_G0, "f,g", 0, v6 },
+
+{ "fitoq", F3F(2, 0x34, 0x0cc), F3F(~2, ~0x34, ~0x0cc)|RS1_G0, "f,J", 0, v8 },
+
+
+{ "fdtoq", F3F(2, 0x34, 0x0ce), F3F(~2, ~0x34, ~0x0ce)|RS1_G0, "B,J", 0, v8 },
+{ "fdtos", F3F(2, 0x34, 0x0c6), F3F(~2, ~0x34, ~0x0c6)|RS1_G0, "B,g", 0, v6 },
+{ "fqtod", F3F(2, 0x34, 0x0cb), F3F(~2, ~0x34, ~0x0cb)|RS1_G0, "R,H", 0, v8 },
+{ "fqtos", F3F(2, 0x34, 0x0c7), F3F(~2, ~0x34, ~0x0c7)|RS1_G0, "R,g", 0, v8 },
+{ "fstod", F3F(2, 0x34, 0x0c9), F3F(~2, ~0x34, ~0x0c9)|RS1_G0, "f,H", 0, v6 },
+{ "fstoq", F3F(2, 0x34, 0x0cd), F3F(~2, ~0x34, ~0x0cd)|RS1_G0, "f,J", 0, v8 },
+
+
+
+
+
+{ "fqtoi", F3F(2, 0x34, 0x0d3), F3F(~2, ~0x34, ~0x0d3)|RS1_G0, "R,g", 0, v8 },
+
+
+{ "fdivd", F3F(2, 0x34, 0x04e), F3F(~2, ~0x34, ~0x04e), "v,B,H", 0, v6 },
+{ "fdivq", F3F(2, 0x34, 0x04f), F3F(~2, ~0x34, ~0x04f), "V,R,J", 0, v8 },
+{ "fdivs", F3F(2, 0x34, 0x04d), F3F(~2, ~0x34, ~0x04d), "e,f,g", 0, v6 },
+{ "fmuld", F3F(2, 0x34, 0x04a), F3F(~2, ~0x34, ~0x04a), "v,B,H", 0, v6 },
+{ "fmulq", F3F(2, 0x34, 0x04b), F3F(~2, ~0x34, ~0x04b), "V,R,J", 0, v8 },
+{ "fmuls", F3F(2, 0x34, 0x049), F3F(~2, ~0x34, ~0x049), "e,f,g", 0, v6 },
+
+{ "fdmulq", F3F(2, 0x34, 0x06e), F3F(~2, ~0x34, ~0x06e), "v,B,J", 0, v8 },
+{ "fsmuld", F3F(2, 0x34, 0x069), F3F(~2, ~0x34, ~0x069), "e,f,H", 0, v8 },
+
+{ "fsqrtd", F3F(2, 0x34, 0x02a), F3F(~2, ~0x34, ~0x02a)|RS1_G0, "B,H", 0, v7 },
+{ "fsqrtq", F3F(2, 0x34, 0x02b), F3F(~2, ~0x34, ~0x02b)|RS1_G0, "R,J", 0, v8 },
+{ "fsqrts", F3F(2, 0x34, 0x029), F3F(~2, ~0x34, ~0x029)|RS1_G0, "f,g", 0, v7 },
+
+{ "fabsq", F3F(2, 0x34, 0x00b), F3F(~2, ~0x34, ~0x00b)|RS1_G0, "R,J", 0, v6 },
+{ "fabss", F3F(2, 0x34, 0x009), F3F(~2, ~0x34, ~0x009)|RS1_G0, "f,g", 0, v6 },
+{ "fmovq", F3F(2, 0x34, 0x003), F3F(~2, ~0x34, ~0x003)|RS1_G0, "R,J", 0, v6 },
+{ "fmovs", F3F(2, 0x34, 0x001), F3F(~2, ~0x34, ~0x001)|RS1_G0, "f,g", 0, v6 },
+{ "fnegq", F3F(2, 0x34, 0x007), F3F(~2, ~0x34, ~0x007)|RS1_G0, "R,J", 0, v6 },
+{ "fnegs", F3F(2, 0x34, 0x005), F3F(~2, ~0x34, ~0x005)|RS1_G0, "f,g", 0, v6 },
+
+
+{ "faddd", F3F(2, 0x34, 0x042), F3F(~2, ~0x34, ~0x042), "v,B,H", 0, v6 },
+{ "faddq", F3F(2, 0x34, 0x043), F3F(~2, ~0x34, ~0x043), "V,R,J", 0, v8 },
+{ "fadds", F3F(2, 0x34, 0x041), F3F(~2, ~0x34, ~0x041), "e,f,g", 0, v6 },
+{ "fsubd", F3F(2, 0x34, 0x046), F3F(~2, ~0x34, ~0x046), "v,B,H", 0, v6 },
+{ "fsubq", F3F(2, 0x34, 0x047), F3F(~2, ~0x34, ~0x047), "V,R,J", 0, v8 },
+{ "fsubs", F3F(2, 0x34, 0x045), F3F(~2, ~0x34, ~0x045), "e,f,g", 0, v6 },
+
+#define CMPFCC(x) (((x)&0x3)<<25)
+
+{ "fcmpd", F3F(2, 0x35, 0x052), F3F(~2, ~0x35, ~0x052)|RS1_G0, "v,B", 0, v6 },
+{ "fcmped", F3F(2, 0x35, 0x056), F3F(~2, ~0x35, ~0x056)|RS1_G0, "v,B", 0, v6 },
+{ "fcmpeq", F3F(2, 0x34, 0x057), F3F(~2, ~0x34, ~0x057), "V,R", 0, v8 },
+{ "fcmpes", F3F(2, 0x35, 0x055), F3F(~2, ~0x35, ~0x055)|RS1_G0, "e,f", 0, v6 },
+{ "fcmpq", F3F(2, 0x34, 0x053), F3F(~2, ~0x34, ~0x053), "V,R", 0, v8 },
+{ "fcmps", F3F(2, 0x35, 0x051), F3F(~2, ~0x35, ~0x051)|RS1_G0, "e,f", 0, v6 },
+
+{ "cpop1", F3(2, 0x36, 0), F3(~2, ~0x36, ~1), "[1+2],d", 0, v6 },
+{ "cpop2", F3(2, 0x37, 0), F3(~2, ~0x37, ~1), "[1+2],d", 0, v6 },
+
+
+
+};
+
+#define NUMOPCODES ((sizeof sparc_opcodes)/(sizeof sparc_opcodes[0]))
+
+/*
+ * Local Variables:
+ * fill-column: 131
+ * comment-column: 0
+ * End:
+ */
+
+/* end of sparc-opcode.h */
diff --git a/gnu/usr.bin/as/opcode/tahoe.h b/gnu/usr.bin/as/opcode/tahoe.h
new file mode 100644
index 0000000..72b0082
--- /dev/null
+++ b/gnu/usr.bin/as/opcode/tahoe.h
@@ -0,0 +1,247 @@
+/* tahoe-opcode.h - tahoe-specific
+ * Not part of GAS yet
+ *
+ * Ported by the State University of New York at Buffalo by the Distributed
+ * Computer Systems Lab, Department of Computer Science, 1991. (And by Dale
+ * Wiles who was unemployed at the time.)
+ */
+
+struct tot_wot /* tahoe opcode table: wot to do with this */
+ /* particular opcode */
+{
+ char *args; /* how to compile said opcode */
+ tahoe_opcodeT code; /* The opcode. */
+};
+
+struct tot /* tahoe opcode text */
+{
+ char *name; /* opcode name: lowercase string [key] */
+ struct tot_wot detail; /* rest of opcode table [datum] */
+};
+
+static struct tot
+totstrs[] =
+{
+{ "halt", {"", 0x00 } },
+{ "sinf", {"", 0x05 } },
+{ "ldf", {"rl", 0x06 } },
+{ "ldd", {"rq", 0x07 } },
+{ "addb2", {"rbmb", 0x08 } },
+{ "movb", {"rbwb", 0x09 } },
+{ "addw2", {"rwmw", 0x0a } },
+{ "movw", {"rwww", 0x0b } },
+{ "addl2", {"rlml", 0x0c } },
+{ "movl", {"rlwl", 0x0d } },
+{ "bbs", {"rlvlbw", 0x0e } },
+{ "nop", {"", 0x10 } },
+{ "brb", {"bb", 0x11 } },
+{ "brw", {"bw", 0x13 } },
+{ "cosf", {"", 0x15 } },
+{ "lnf", {"rl", 0x16 } },
+{ "lnd", {"rq", 0x17 } },
+{ "addb3", {"rbrbwb", 0x18 } },
+ /* cmpb is wrong in the "offical" (what a joke!) text. It's not "rbwb" */
+{ "cmpb", {"rbrb", 0x19 } },
+{ "addw3", {"rwrwww", 0x1a } },
+ /* cmpw is wrong in the "offical" text. It's not "rwww" */
+{ "cmpw", {"rwrw", 0x1b } },
+{ "addl3", {"rlrlwl", 0x1c } },
+ /* cmpl is wrong in the "offical" text. It's not "rlwl" */
+{ "cmpl", {"rlrl", 0x1d } },
+{ "bbc", {"rlvlbw", 0x1e } },
+{ "rei", {"", 0x20 } },
+{ "bneq", {"bb", 0x21 } },
+{ "bnequ", {"bb", 0x21 } },
+{ "cvtwl", {"rwwl", 0x23 } },
+{ "stf", {"wl", 0x26 } },
+{ "std", {"wq", 0x27 } },
+{ "subb2", {"rbmb", 0x28 } },
+{ "mcomb", {"rbwb", 0x29 } },
+{ "subw2", {"rwmw", 0x2a } },
+{ "mcomw", {"rwww", 0x2b } },
+{ "subl2", {"rlml", 0x2c } },
+{ "mcoml", {"rlwl", 0x2d } },
+{ "emul", {"rlrlrlwq", 0x2e } },
+{ "aoblss", {"rlmlbw", 0x2f } },
+{ "bpt", {"", 0x30 } },
+{ "beql", {"bb", 0x31 } },
+{ "beqlu", {"bb", 0x31 } },
+{ "cvtwb", {"rwwb", 0x33 } },
+{ "logf", {"", 0x35 } },
+{ "cmpf", {"rl", 0x36 } },
+{ "cmpd", {"rq", 0x37 } },
+{ "subb3", {"rbrbwb", 0x38 } },
+{ "bitb", {"rbrb", 0x39 } },
+{ "subw3", {"rwrwww", 0x3a } },
+{ "bitw", {"rwrw", 0x3b } },
+{ "subl3", {"rlrlwl", 0x3c } },
+{ "bitl", {"rlrl", 0x3d } },
+{ "ediv", {"rlrqwlwl", 0x3e } },
+{ "aobleq", {"rlmlbw", 0x3f } },
+{ "ret", {"", 0x40 } },
+{ "bgtr", {"bb", 0x41 } },
+{ "sqrtf", {"", 0x45 } },
+{ "cmpf2", {"rlrl", 0x46 } },
+{ "cmpd2", {"rqrq", 0x47 } },
+{ "shll", {"rbrlwl", 0x48 } },
+{ "clrb", {"wb", 0x49 } },
+{ "shlq", {"rbrqwq", 0x4a } },
+{ "clrw", {"ww", 0x4b } },
+{ "mull2", {"rlml", 0x4c } },
+{ "clrl", {"wl", 0x4d } },
+{ "shal", {"rbrlwl", 0x4e } },
+{ "bleq", {"bb", 0x51 } },
+{ "expf", {"", 0x55 } },
+{ "tstf", {"", 0x56 } },
+{ "tstd", {"", 0x57 } },
+{ "shrl", {"rbrlwl", 0x58 } },
+{ "tstb", {"rb", 0x59 } },
+{ "shrq", {"rbrqwq", 0x5a } },
+{ "tstw", {"rw", 0x5b } },
+{ "mull3", {"rlrlwl", 0x5c } },
+{ "tstl", {"rl", 0x5d } },
+{ "shar", {"rbrlwl", 0x5e } },
+{ "bbssi", {"rlmlbw", 0x5f } },
+{ "ldpctx", {"", 0x60 } },
+{ "pushd", {"", 0x67 } },
+{ "incb", {"mb", 0x69 } },
+{ "incw", {"mw", 0x6b } },
+{ "divl2", {"rlml", 0x6c } },
+{ "incl", {"ml", 0x6d } },
+{ "cvtlb", {"rlwb", 0x6f } },
+{ "svpctx", {"", 0x70 } },
+{ "jmp", {"ab", 0x71 } },
+{ "cvlf", {"rl", 0x76 } },
+{ "cvld", {"rl", 0x77 } },
+{ "decb", {"mb", 0x79 } },
+{ "decw", {"mw", 0x7b } },
+{ "divl3", {"rlrlwl", 0x7c } },
+{ "decl", {"ml", 0x7d } },
+{ "cvtlw", {"rlww", 0x7f } },
+{ "bgeq", {"bb", 0x81 } },
+{ "movs2", {"abab", 0x82 } },
+{ "cvfl", {"wl", 0x86 } },
+{ "cvdl", {"wl", 0x87 } },
+{ "orb2", {"rbmb", 0x88 } },
+{ "cvtbl", {"rbwl", 0x89 } },
+{ "orw2", {"rwmw", 0x8a } },
+{ "bispsw", {"rw", 0x8b } },
+{ "orl2", {"rlml", 0x8c } },
+{ "adwc", {"rlml", 0x8d } },
+{ "adda", {"rlml", 0x8e } },
+{ "blss", {"bb", 0x91 } },
+{ "cmps2", {"abab", 0x92 } },
+{ "ldfd", {"rl", 0x97 } },
+{ "orb3", {"rbrbwb", 0x98 } },
+{ "cvtbw", {"rbww", 0x99 } },
+{ "orw3", {"rwrwww", 0x9a } },
+{ "bicpsw", {"rw", 0x9b } },
+{ "orl3", {"rlrlwl", 0x9c } },
+{ "sbwc", {"rlml", 0x9d } },
+{ "suba", {"rlml", 0x9e } },
+{ "bgtru", {"bb", 0xa1 } },
+{ "cvdf", {"", 0xa6 } },
+{ "andb2", {"rbmb", 0xa8 } },
+{ "movzbl", {"rbwl", 0xa9 } },
+{ "andw2", {"rwmw", 0xaa } },
+{ "loadr", {"rwal", 0xab } },
+{ "andl2", {"rlml", 0xac } },
+{ "mtpr", {"rlrl", 0xad } },
+{ "ffs", {"rlwl", 0xae } },
+{ "blequ", {"bb", 0xb1 } },
+{ "negf", {"", 0xb6 } },
+{ "negd", {"", 0xb7 } },
+{ "andb3", {"rbrbwb", 0xb8 } },
+{ "movzbw", {"rbww", 0xb9 } },
+{ "andw3", {"rwrwww", 0xba } },
+{ "storer", {"rwal", 0xbb } },
+{ "andl3", {"rlrlwl", 0xbc } },
+{ "mfpr", {"rlwl", 0xbd } },
+{ "ffc", {"rlwl", 0xbe } },
+{ "calls", {"rbab", 0xbf } },
+{ "prober", {"rbabrl", 0xc0 } },
+{ "bvc", {"bb", 0xc1 } },
+{ "movs3", {"ababrw", 0xc2 } },
+{ "movzwl", {"rwwl", 0xc3 } },
+{ "addf", {"rl", 0xc6 } },
+{ "addd", {"rq", 0xc7 } },
+{ "xorb2", {"rbmb", 0xc8 } },
+{ "movob", {"rbwb", 0xc9 } },
+{ "xorw2", {"rwmw", 0xca } },
+{ "movow", {"rwww", 0xcb } },
+{ "xorl2", {"rlml", 0xcc } },
+{ "movpsl", {"wl", 0xcd } },
+{ "kcall", {"rw", 0xcf } },
+{ "probew", {"rbabrl", 0xd0 } },
+{ "bvs", {"bb", 0xd1 } },
+{ "cmps3", {"ababrw", 0xd2 } },
+{ "subf", {"rq", 0xd6 } },
+{ "subd", {"rq", 0xd7 } },
+{ "xorb3", {"rbrbwb", 0xd8 } },
+{ "pushb", {"rb", 0xd9 } },
+{ "xorw3", {"rwrwww", 0xda } },
+{ "pushw", {"rw", 0xdb } },
+{ "xorl3", {"rlrlwl", 0xdc } },
+{ "pushl", {"rl", 0xdd } },
+{ "insque", {"abab", 0xe0 } },
+{ "bcs", {"bb", 0xe1 } },
+{ "bgequ", {"bb", 0xe1 } },
+{ "mulf", {"rq", 0xe6 } },
+{ "muld", {"rq", 0xe7 } },
+{ "mnegb", {"rbwb", 0xe8 } },
+{ "movab", {"abwl", 0xe9 } },
+{ "mnegw", {"rwww", 0xea } },
+{ "movaw", {"awwl", 0xeb } },
+{ "mnegl", {"rlwl", 0xec } },
+{ "moval", {"alwl", 0xed } },
+{ "remque", {"ab", 0xf0 } },
+{ "bcc", {"bb", 0xf1 } },
+{ "blssu", {"bb", 0xf1 } },
+{ "divf", {"rq", 0xf6 } },
+{ "divd", {"rq", 0xf7 } },
+ /* movblk is really "alalrw" but 'as' won't accept it,
+ 'cc' and 'gcc' also produce code this way. */
+{ "movblk", {"", 0xf8 } },
+{ "pushab", {"ab", 0xf9 } },
+{ "pushaw", {"aw", 0xfb } },
+{ "casel", {"rlrlrl", 0xfc } },
+{ "pushal", {"al", 0xfd } },
+{ "callf", {"rbab", 0xfe } },
+{ "", "" } /* empty is end sentinel */
+};
+
+/* These are synthetic instructions, where the assembler will munge
+ the addressings modes for you. */
+static struct tot
+synthetic_totstrs[] =
+{
+{ "jr", {"b-", 0x11 } },
+{ "jbr", {"b-", 0x11 } },
+
+{ "jneq", {"b?", 0x21 } },
+{ "jnequ", {"b?", 0x21 } },
+{ "jeql", {"b?", 0x31 } },
+{ "jeqlu", {"b?", 0x31 } },
+{ "jgtr", {"b?", 0x41 } },
+{ "jleq", {"b?", 0x51 } },
+{ "jgeq", {"b?", 0x81 } },
+{ "jlss", {"b?", 0x91 } },
+{ "jgtru", {"b?", 0xa1 } },
+{ "jlequ", {"b?", 0xb1 } },
+{ "jvc", {"b?", 0xc1 } },
+{ "jvs", {"b?", 0xd1 } },
+{ "jcs", {"b?", 0xe1 } },
+{ "jgequ", {"b?", 0xe1 } },
+{ "jcc", {"b?", 0xf1 } },
+{ "jlssu", {"b?", 0xf1 } },
+
+{ "jbs", {"rlvlb!", 0x0e } },
+{ "jbc", {"rlvlb!", 0x1e } },
+
+{ "aojlss", {"rlmlb:", 0x2f } },
+{ "jaoblss", {"rlmlb:", 0x2f } },
+{ "aojleq", {"rlmlb:", 0x3f } },
+{ "jaobleq", {"rlmlb:", 0x3f } },
+{ "jbssi", {"rlmlb:", 0x5f } },
+ { "", "" } /* empty is end sentinel */
+};
diff --git a/gnu/usr.bin/as/opcode/vax.h b/gnu/usr.bin/as/opcode/vax.h
new file mode 100644
index 0000000..d604e3f
--- /dev/null
+++ b/gnu/usr.bin/as/opcode/vax.h
@@ -0,0 +1,382 @@
+/* Vax opcde list.
+ Copyright (C) 1989, Free Software Foundation, Inc.
+
+This file is part of GDB and GAS.
+
+GDB and GAS are free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 1, or (at your option)
+any later version.
+
+GDB and GAS are distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GDB or GAS; see the file COPYING. If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#ifndef vax_opcodeT
+#define vax_opcodeT int
+#endif /* no vax_opcodeT */
+
+struct vot_wot /* vax opcode table: wot to do with this */
+ /* particular opcode */
+{
+ char * args; /* how to compile said opcode */
+ vax_opcodeT code; /* op-code (may be > 8 bits!) */
+};
+
+struct vot /* vax opcode text */
+{
+ char * name; /* opcode name: lowercase string [key] */
+ struct vot_wot detail; /* rest of opcode table [datum] */
+};
+
+#define vot_how args
+#define vot_code code
+#define vot_detail detail
+#define vot_name name
+
+static const struct vot
+votstrs[] =
+{
+{ "halt", {"", 0x00 } },
+{ "nop", {"", 0x01 } },
+{ "rei", {"", 0x02 } },
+{ "bpt", {"", 0x03 } },
+{ "ret", {"", 0x04 } },
+{ "rsb", {"", 0x05 } },
+{ "ldpctx", {"", 0x06 } },
+{ "svpctx", {"", 0x07 } },
+{ "cvtps", {"rwabrwab", 0x08 } },
+{ "cvtsp", {"rwabrwab", 0x09 } },
+{ "index", {"rlrlrlrlrlwl", 0x0a } },
+{ "crc", {"abrlrwab", 0x0b } },
+{ "prober", {"rbrwab", 0x0c } },
+{ "probew", {"rbrwab", 0x0d } },
+{ "insque", {"abab", 0x0e } },
+{ "remque", {"abwl", 0x0f } },
+{ "bsbb", {"bb", 0x10 } },
+{ "brb", {"bb", 0x11 } },
+{ "bneq", {"bb", 0x12 } },
+{ "bnequ", {"bb", 0x12 } },
+{ "beql", {"bb", 0x13 } },
+{ "beqlu", {"bb", 0x13 } },
+{ "bgtr", {"bb", 0x14 } },
+{ "bleq", {"bb", 0x15 } },
+{ "jsb", {"ab", 0x16 } },
+{ "jmp", {"ab", 0x17 } },
+{ "bgeq", {"bb", 0x18 } },
+{ "blss", {"bb", 0x19 } },
+{ "bgtru", {"bb", 0x1a } },
+{ "blequ", {"bb", 0x1b } },
+{ "bvc", {"bb", 0x1c } },
+{ "bvs", {"bb", 0x1d } },
+{ "bcc", {"bb", 0x1e } },
+{ "bgequ", {"bb", 0x1e } },
+{ "blssu", {"bb", 0x1f } },
+{ "bcs", {"bb", 0x1f } },
+{ "addp4", {"rwabrwab", 0x20 } },
+{ "addp6", {"rwabrwabrwab", 0x21 } },
+{ "subp4", {"rwabrwab", 0x22 } },
+{ "subp6", {"rwabrwabrwab", 0x23 } },
+{ "cvtpt", {"rwababrwab", 0x24 } },
+{ "mulp", {"rwabrwabrwab", 0x25 } },
+{ "cvttp", {"rwababrwab", 0x26 } },
+{ "divp", {"rwabrwabrwab", 0x27 } },
+{ "movc3", {"rwabab", 0x28 } },
+{ "cmpc3", {"rwabab", 0x29 } },
+{ "scanc", {"rwababrb", 0x2a } },
+{ "spanc", {"rwababrb", 0x2b } },
+{ "movc5", {"rwabrbrwab", 0x2c } },
+{ "cmpc5", {"rwabrbrwab", 0x2d } },
+{ "movtc", {"rwabrbabrwab", 0x2e } },
+{ "movtuc", {"rwabrbabrwab", 0x2f } },
+{ "bsbw", {"bw", 0x30 } },
+{ "brw", {"bw", 0x31 } },
+{ "cvtwl", {"rwwl", 0x32 } },
+{ "cvtwb", {"rwwb", 0x33 } },
+{ "movp", {"rwabab", 0x34 } },
+{ "cmpp3", {"rwabab", 0x35 } },
+{ "cvtpl", {"rwabwl", 0x36 } },
+{ "cmpp4", {"rwabrwab", 0x37 } },
+{ "editpc", {"rwababab", 0x38 } },
+{ "matchc", {"rwabrwab", 0x39 } },
+{ "locc", {"rbrwab", 0x3a } },
+{ "skpc", {"rbrwab", 0x3b } },
+{ "movzwl", {"rwwl", 0x3c } },
+{ "acbw", {"rwrwmwbw", 0x3d } },
+{ "movaw", {"awwl", 0x3e } },
+{ "pushaw", {"aw", 0x3f } },
+{ "addf2", {"rfmf", 0x40 } },
+{ "addf3", {"rfrfwf", 0x41 } },
+{ "subf2", {"rfmf", 0x42 } },
+{ "subf3", {"rfrfwf", 0x43 } },
+{ "mulf2", {"rfmf", 0x44 } },
+{ "mulf3", {"rfrfwf", 0x45 } },
+{ "divf2", {"rfmf", 0x46 } },
+{ "divf3", {"rfrfwf", 0x47 } },
+{ "cvtfb", {"rfwb", 0x48 } },
+{ "cvtfw", {"rfww", 0x49 } },
+{ "cvtfl", {"rfwl", 0x4a } },
+{ "cvtrfl", {"rfwl", 0x4b } },
+{ "cvtbf", {"rbwf", 0x4c } },
+{ "cvtwf", {"rwwf", 0x4d } },
+{ "cvtlf", {"rlwf", 0x4e } },
+{ "acbf", {"rfrfmfbw", 0x4f } },
+{ "movf", {"rfwf", 0x50 } },
+{ "cmpf", {"rfrf", 0x51 } },
+{ "mnegf", {"rfwf", 0x52 } },
+{ "tstf", {"rf", 0x53 } },
+{ "emodf", {"rfrbrfwlwf", 0x54 } },
+{ "polyf", {"rfrwab", 0x55 } },
+{ "cvtfd", {"rfwd", 0x56 } },
+ /* opcode 57 is not defined yet */
+{ "adawi", {"rwmw", 0x58 } },
+ /* opcode 59 is not defined yet */
+ /* opcode 5a is not defined yet */
+ /* opcode 5b is not defined yet */
+{ "insqhi", {"abaq", 0x5c } },
+{ "insqti", {"abaq", 0x5d } },
+{ "remqhi", {"aqwl", 0x5e } },
+{ "remqti", {"aqwl", 0x5f } },
+{ "addd2", {"rdmd", 0x60 } },
+{ "addd3", {"rdrdwd", 0x61 } },
+{ "subd2", {"rdmd", 0x62 } },
+{ "subd3", {"rdrdwd", 0x63 } },
+{ "muld2", {"rdmd", 0x64 } },
+{ "muld3", {"rdrdwd", 0x65 } },
+{ "divd2", {"rdmd", 0x66 } },
+{ "divd3", {"rdrdwd", 0x67 } },
+{ "cvtdb", {"rdwb", 0x68 } },
+{ "cvtdw", {"rdww", 0x69 } },
+{ "cvtdl", {"rdwl", 0x6a } },
+{ "cvtrdl", {"rdwl", 0x6b } },
+{ "cvtbd", {"rbwd", 0x6c } },
+{ "cvtwd", {"rwwd", 0x6d } },
+{ "cvtld", {"rlwd", 0x6e } },
+{ "acbd", {"rdrdmdbw", 0x6f } },
+{ "movd", {"rdwd", 0x70 } },
+{ "cmpd", {"rdrd", 0x71 } },
+{ "mnegd", {"rdwd", 0x72 } },
+{ "tstd", {"rd", 0x73 } },
+{ "emodd", {"rdrbrdwlwd", 0x74 } },
+{ "polyd", {"rdrwab", 0x75 } },
+{ "cvtdf", {"rdwf", 0x76 } },
+ /* opcode 77 is not defined yet */
+{ "ashl", {"rbrlwl", 0x78 } },
+{ "ashq", {"rbrqwq", 0x79 } },
+{ "emul", {"rlrlrlwq", 0x7a } },
+{ "ediv", {"rlrqwlwl", 0x7b } },
+{ "clrd", {"wd", 0x7c } },
+{ "clrg", {"wg", 0x7c } },
+{ "clrq", {"wd", 0x7c } },
+{ "movq", {"rqwq", 0x7d } },
+{ "movaq", {"aqwl", 0x7e } },
+{ "movad", {"adwl", 0x7e } },
+{ "pushaq", {"aq", 0x7f } },
+{ "pushad", {"ad", 0x7f } },
+{ "addb2", {"rbmb", 0x80 } },
+{ "addb3", {"rbrbwb", 0x81 } },
+{ "subb2", {"rbmb", 0x82 } },
+{ "subb3", {"rbrbwb", 0x83 } },
+{ "mulb2", {"rbmb", 0x84 } },
+{ "mulb3", {"rbrbwb", 0x85 } },
+{ "divb2", {"rbmb", 0x86 } },
+{ "divb3", {"rbrbwb", 0x87 } },
+{ "bisb2", {"rbmb", 0x88 } },
+{ "bisb3", {"rbrbwb", 0x89 } },
+{ "bicb2", {"rbmb", 0x8a } },
+{ "bicb3", {"rbrbwb", 0x8b } },
+{ "xorb2", {"rbmb", 0x8c } },
+{ "xorb3", {"rbrbwb", 0x8d } },
+{ "mnegb", {"rbwb", 0x8e } },
+{ "caseb", {"rbrbrb", 0x8f } },
+{ "movb", {"rbwb", 0x90 } },
+{ "cmpb", {"rbrb", 0x91 } },
+{ "mcomb", {"rbwb", 0x92 } },
+{ "bitb", {"rbrb", 0x93 } },
+{ "clrb", {"wb", 0x94 } },
+{ "tstb", {"rb", 0x95 } },
+{ "incb", {"mb", 0x96 } },
+{ "decb", {"mb", 0x97 } },
+{ "cvtbl", {"rbwl", 0x98 } },
+{ "cvtbw", {"rbww", 0x99 } },
+{ "movzbl", {"rbwl", 0x9a } },
+{ "movzbw", {"rbww", 0x9b } },
+{ "rotl", {"rbrlwl", 0x9c } },
+{ "acbb", {"rbrbmbbw", 0x9d } },
+{ "movab", {"abwl", 0x9e } },
+{ "pushab", {"ab", 0x9f } },
+{ "addw2", {"rwmw", 0xa0 } },
+{ "addw3", {"rwrwww", 0xa1 } },
+{ "subw2", {"rwmw", 0xa2 } },
+{ "subw3", {"rwrwww", 0xa3 } },
+{ "mulw2", {"rwmw", 0xa4 } },
+{ "mulw3", {"rwrwww", 0xa5 } },
+{ "divw2", {"rwmw", 0xa6 } },
+{ "divw3", {"rwrwww", 0xa7 } },
+{ "bisw2", {"rwmw", 0xa8 } },
+{ "bisw3", {"rwrwww", 0xa9 } },
+{ "bicw2", {"rwmw", 0xaa } },
+{ "bicw3", {"rwrwww", 0xab } },
+{ "xorw2", {"rwmw", 0xac } },
+{ "xorw3", {"rwrwww", 0xad } },
+{ "mnegw", {"rwww", 0xae } },
+{ "casew", {"rwrwrw", 0xaf } },
+{ "movw", {"rwww", 0xb0 } },
+{ "cmpw", {"rwrw", 0xb1 } },
+{ "mcomw", {"rwww", 0xb2 } },
+{ "bitw", {"rwrw", 0xb3 } },
+{ "clrw", {"ww", 0xb4 } },
+{ "tstw", {"rw", 0xb5 } },
+{ "incw", {"mw", 0xb6 } },
+{ "decw", {"mw", 0xb7 } },
+{ "bispsw", {"rw", 0xb8 } },
+{ "bicpsw", {"rw", 0xb9 } },
+{ "popr", {"rw", 0xba } },
+{ "pushr", {"rw", 0xbb } },
+{ "chmk", {"rw", 0xbc } },
+{ "chme", {"rw", 0xbd } },
+{ "chms", {"rw", 0xbe } },
+{ "chmu", {"rw", 0xbf } },
+{ "addl2", {"rlml", 0xc0 } },
+{ "addl3", {"rlrlwl", 0xc1 } },
+{ "subl2", {"rlml", 0xc2 } },
+{ "subl3", {"rlrlwl", 0xc3 } },
+{ "mull2", {"rlml", 0xc4 } },
+{ "mull3", {"rlrlwl", 0xc5 } },
+{ "divl2", {"rlml", 0xc6 } },
+{ "divl3", {"rlrlwl", 0xc7 } },
+{ "bisl2", {"rlml", 0xc8 } },
+{ "bisl3", {"rlrlwl", 0xc9 } },
+{ "bicl2", {"rlml", 0xca } },
+{ "bicl3", {"rlrlwl", 0xcb } },
+{ "xorl2", {"rlml", 0xcc } },
+{ "xorl3", {"rlrlwl", 0xcd } },
+{ "mnegl", {"rlwl", 0xce } },
+{ "casel", {"rlrlrl", 0xcf } },
+{ "movl", {"rlwl", 0xd0 } },
+{ "cmpl", {"rlrl", 0xd1 } },
+{ "mcoml", {"rlwl", 0xd2 } },
+{ "bitl", {"rlrl", 0xd3 } },
+{ "clrf", {"wf", 0xd4 } },
+{ "clrl", {"wl", 0xd4 } },
+{ "tstl", {"rl", 0xd5 } },
+{ "incl", {"ml", 0xd6 } },
+{ "decl", {"ml", 0xd7 } },
+{ "adwc", {"rlml", 0xd8 } },
+{ "sbwc", {"rlml", 0xd9 } },
+{ "mtpr", {"rlrl", 0xda } },
+{ "mfpr", {"rlwl", 0xdb } },
+{ "movpsl", {"wl", 0xdc } },
+{ "pushl", {"rl", 0xdd } },
+{ "moval", {"alwl", 0xde } },
+{ "movaf", {"afwl", 0xde } },
+{ "pushal", {"al", 0xdf } },
+{ "pushaf", {"af", 0xdf } },
+{ "bbs", {"rlabbb", 0xe0 } },
+{ "bbc", {"rlabbb", 0xe1 } },
+{ "bbss", {"rlabbb", 0xe2 } },
+{ "bbcs", {"rlabbb", 0xe3 } },
+{ "bbsc", {"rlabbb", 0xe4 } },
+{ "bbcc", {"rlabbb", 0xe5 } },
+{ "bbssi", {"rlabbb", 0xe6 } },
+{ "bbcci", {"rlabbb", 0xe7 } },
+{ "blbs", {"rlbb", 0xe8 } },
+{ "blbc", {"rlbb", 0xe9 } },
+{ "ffs", {"rlrbvbwl", 0xea } },
+{ "ffc", {"rlrbvbwl", 0xeb } },
+{ "cmpv", {"rlrbvbrl", 0xec } },
+{ "cmpzv", {"rlrbvbrl", 0xed } },
+{ "extv", {"rlrbvbwl", 0xee } },
+{ "extzv", {"rlrbvbwl", 0xef } },
+{ "insv", {"rlrlrbvb", 0xf0 } },
+{ "acbl", {"rlrlmlbw", 0xf1 } },
+{ "aoblss", {"rlmlbb", 0xf2 } },
+{ "aobleq", {"rlmlbb", 0xf3 } },
+{ "sobgeq", {"mlbb", 0xf4 } },
+{ "sobgtr", {"mlbb", 0xf5 } },
+{ "cvtlb", {"rlwb", 0xf6 } },
+{ "cvtlw", {"rlww", 0xf7 } },
+{ "ashp", {"rbrwabrbrwab", 0xf8 } },
+{ "cvtlp", {"rlrwab", 0xf9 } },
+{ "callg", {"abab", 0xfa } },
+{ "calls", {"rlab", 0xfb } },
+{ "xfc", {"", 0xfc } },
+ /* undefined opcodes here */
+{ "cvtdh", {"rdwh", 0x32fd } },
+{ "cvtgf", {"rgwh", 0x33fd } },
+{ "addg2", {"rgmg", 0x40fd } },
+{ "addg3", {"rgrgwg", 0x41fd } },
+{ "subg2", {"rgmg", 0x42fd } },
+{ "subg3", {"rgrgwg", 0x43fd } },
+{ "mulg2", {"rgmg", 0x44fd } },
+{ "mulg3", {"rgrgwg", 0x45fd } },
+{ "divg2", {"rgmg", 0x46fd } },
+{ "divg3", {"rgrgwg", 0x47fd } },
+{ "cvtgb", {"rgwb", 0x48fd } },
+{ "cvtgw", {"rgww", 0x49fd } },
+{ "cvtgl", {"rgwl", 0x4afd } },
+{ "cvtrgl", {"rgwl", 0x4bfd } },
+{ "cvtbg", {"rbwg", 0x4cfd } },
+{ "cvtwg", {"rwwg", 0x4dfd } },
+{ "cvtlg", {"rlwg", 0x4efd } },
+{ "acbg", {"rgrgmgbw", 0x4ffd } },
+{ "movg", {"rgwg", 0x50fd } },
+{ "cmpg", {"rgrg", 0x51fd } },
+{ "mnegg", {"rgwg", 0x52fd } },
+{ "tstg", {"rg", 0x53fd } },
+{ "emodg", {"rgrwrgwlwg", 0x54fd } },
+{ "polyg", {"rgrwab", 0x55fd } },
+{ "cvtgh", {"rgwh", 0x56fd } },
+ /* undefined opcodes here */
+{ "addh2", {"rhmh", 0x60fd } },
+{ "addh3", {"rhrhwh", 0x61fd } },
+{ "subh2", {"rhmh", 0x62fd } },
+{ "subh3", {"rhrhwh", 0x63fd } },
+{ "mulh2", {"rhmh", 0x64fd } },
+{ "mulh3", {"rhrhwh", 0x65fd } },
+{ "divh2", {"rhmh", 0x66fd } },
+{ "divh3", {"rhrhwh", 0x67fd } },
+{ "cvthb", {"rhwb", 0x68fd } },
+{ "cvthw", {"rhww", 0x69fd } },
+{ "cvthl", {"rhwl", 0x6afd } },
+{ "cvtrhl", {"rhwl", 0x6bfd } },
+{ "cvtbh", {"rbwh", 0x6cfd } },
+{ "cvtwh", {"rwwh", 0x6dfd } },
+{ "cvtlh", {"rlwh", 0x6efd } },
+{ "acbh", {"rhrhmhbw", 0x6ffd } },
+{ "movh", {"rhwh", 0x70fd } },
+{ "cmph", {"rhrh", 0x71fd } },
+{ "mnegh", {"rhwh", 0x72fd } },
+{ "tsth", {"rh", 0x73fd } },
+{ "emodh", {"rhrwrhwlwh", 0x74fd } },
+{ "polyh", {"rhrwab", 0x75fd } },
+{ "cvthg", {"rhwg", 0x76fd } },
+ /* undefined opcodes here */
+{ "clrh", {"wh", 0x7cfd } },
+{ "clro", {"wo", 0x7cfd } },
+{ "movo", {"rowo", 0x7dfd } },
+{ "movah", {"ahwl", 0x7efd } },
+{ "movao", {"aowl", 0x7efd } },
+{ "pushah", {"ah", 0x7ffd } },
+{ "pushao", {"ao", 0x7ffd } },
+ /* undefined opcodes here */
+{ "cvtfh", {"rfwh", 0x98fd } },
+{ "cvtfg", {"rfwg", 0x99fd } },
+ /* undefined opcodes here */
+{ "cvthf", {"rhwf", 0xf6fd } },
+{ "cvthd", {"rhwd", 0xf7fd } },
+ /* undefined opcodes here */
+{ "bugl", {"rl", 0xfdff } },
+{ "bugw", {"rw", 0xfeff } },
+ /* undefined opcodes here */
+
+{ "" , "" } /* empty is end sentinel */
+
+}; /* votstrs */
+
+/* end: vax.opcode.h */
diff --git a/gnu/usr.bin/as/output-file.c b/gnu/usr.bin/as/output-file.c
new file mode 100644
index 0000000..1a8683b
--- /dev/null
+++ b/gnu/usr.bin/as/output-file.c
@@ -0,0 +1,122 @@
+/* output-file.c - Deal with the output file
+ Copyright (C) 1987, 1990, 1991, 1992 Free Software Foundation, Inc.
+
+ This file is part of GAS, the GNU Assembler.
+
+ GAS is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GAS is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GAS; see the file COPYING. If not, write to
+ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/*
+ * Confines all details of emitting object bytes to this module.
+ * All O/S specific crocks should live here.
+ * What we lose in "efficiency" we gain in modularity.
+ * Note we don't need to #include the "as.h" file. No common coupling!
+ */
+
+/* note that we do need config info. xoxorich. */
+
+#ifndef lint
+static char rcsid[] = "$Id: output-file.c,v 1.2 1993/11/03 00:52:08 paul Exp $";
+#endif
+
+#include <stdio.h>
+
+#include "as.h"
+
+#include "output-file.h"
+#ifdef BFD_HEADERS
+#include "bfd.h"
+bfd *stdoutput;
+void output_file_create(name)
+char *name;
+{
+ if (name[0] == '-' && name[1] == '\0') {
+ as_perror("FATAL: Can't open a bfd on stdout %s ", name);
+ }
+ else if ( ! (stdoutput = bfd_openw( name, TARGET_FORMAT )) )
+ {
+ as_perror ("FATAL: Can't create %s", name);
+ exit(42);
+ }
+ bfd_set_format(stdoutput, bfd_object);
+}
+/* output_file_create() */
+
+
+void output_file_close(filename)
+char *filename;
+{
+ /* Close the bfd without getting bfd to write out anything by itself */
+ if ( bfd_close_all_done( stdoutput ) == 0 )
+ {
+ as_perror ("FATAL: Can't close %s\n", filename);
+ exit(42);
+ }
+ stdoutput = NULL; /* Trust nobody! */
+} /* output_file_close() */
+
+void output_file_append(where, length, filename)
+char *where;
+long length;
+char *filename;
+{
+ abort(); /* Never do this */
+}
+
+#else
+
+static FILE *stdoutput;
+
+void output_file_create(name)
+char *name;
+{
+ if (name[0] == '-' && name[1] == '\0')
+ stdoutput=stdout;
+ else if (!(stdoutput = fopen(name, "wb"))) {
+ as_perror("FATAL: Can't create %s", name);
+ exit(42);
+ }
+} /* output_file_create() */
+
+
+
+void output_file_close(filename)
+char *filename;
+{
+ if (EOF == fclose(stdoutput)) {
+ as_perror ("FATAL: Can't close %s", filename);
+ exit(42);
+ }
+ stdoutput = NULL; /* Trust nobody! */
+} /* output_file_close() */
+
+void output_file_append(where, length, filename)
+char *where;
+long length;
+char *filename;
+{
+
+ for (; length; length--, where++) {
+ (void) putc(*where, stdoutput);
+ if (ferror(stdoutput))
+ /* if ( EOF == (putc( *where, stdoutput )) ) */
+ {
+ as_perror("Failed to emit an object byte", filename);
+ as_fatal("Can't continue");
+ }
+ }
+} /* output_file_append() */
+#endif
+
+/* end of output-file.c */
diff --git a/gnu/usr.bin/as/output-file.h b/gnu/usr.bin/as/output-file.h
new file mode 100644
index 0000000..37878ab
--- /dev/null
+++ b/gnu/usr.bin/as/output-file.h
@@ -0,0 +1,40 @@
+/* This file is output-file.h
+
+ Copyright (C) 1987-1992 Free Software Foundation, Inc.
+
+ This file is part of GAS, the GNU Assembler.
+
+ GAS is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GAS is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GAS; see the file COPYING. If not, write to
+ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+/*
+ * $Id: output-file.h,v 1.1 1993/11/03 00:52:10 paul Exp $
+ */
+
+
+#ifdef __STDC__
+
+void output_file_append(char *where, long length, char *filename);
+void output_file_close(char *filename);
+void output_file_create(char *name);
+
+#else /* __STDC__ */
+
+void output_file_append();
+void output_file_close();
+void output_file_create();
+
+#endif /* __STDC__ */
+
+
+/* end of output-file.h */
diff --git a/gnu/usr.bin/as/read.c b/gnu/usr.bin/as/read.c
new file mode 100644
index 0000000..c9bcbca
--- /dev/null
+++ b/gnu/usr.bin/as/read.c
@@ -0,0 +1,2386 @@
+/* read.c - read a source file -
+
+ Copyright (C) 1986, 1987, 1990, 1991, 1992 Free Software Foundation, Inc.
+
+ This file is part of GAS, the GNU Assembler.
+
+ GAS is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GAS is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GAS; see the file COPYING. If not, write to
+ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#ifndef lint
+static char rcsid[] = "$Id: read.c,v 1.5 1994/12/23 22:36:15 nate Exp $";
+#endif
+
+#define MASK_CHAR (0xFF) /* If your chars aren't 8 bits, you will
+ change this a bit. But then, GNU isn't
+ spozed to run on your machine anyway.
+ (RMS is so shortsighted sometimes.)
+ */
+
+#define MAXIMUM_NUMBER_OF_CHARS_FOR_FLOAT (16)
+/* This is the largest known floating point */
+/* format (for now). It will grow when we */
+/* do 4361 style flonums. */
+
+
+/* Routines that read assembler source text to build spagetti in memory. */
+/* Another group of these functions is in the as-expr.c module */
+
+#include "as.h"
+
+#include "obstack.h"
+
+char *input_line_pointer; /*->next char of source file to parse. */
+
+#ifndef NOP_OPCODE
+# define NOP_OPCODE 0x00
+#endif
+
+#if BITS_PER_CHAR != 8
+The following table is indexed by [ (char) ] and will break if
+ a char does not have exactly 256 states (hopefully 0:255!) !
+#endif
+
+#ifdef ALLOW_ATSIGN
+#define AT 2
+#else
+#define AT 0
+#endif
+
+#ifndef PIC
+ const
+#endif
+ char /* used by is_... macros. our ctype[] */
+ lex_type[256] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* @ABCDEFGHIJKLMNO */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* PQRSTUVWXYZ[\]^_ */
+ 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, /* _!"#$%&'()*+,-./ */
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, /* 0123456789:;<=>? */
+ AT, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, /* @ABCDEFGHIJKLMNO */
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 3, /* PQRSTUVWXYZ[\]^_ */
+ 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, /* `abcdefghijklmno */
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, /* pqrstuvwxyz{|}~. */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ };
+
+
+/*
+ * In: a character.
+ * Out: 1 if this character ends a line.
+ */
+#define _ (0)
+char is_end_of_line[256] = {
+#ifdef CR_EOL
+ _, _, _, _, _, _, _, _, _, _,99, _, _, 99, _, _,/* @abcdefghijklmno */
+#else
+ _, _, _, _, _, _, _, _, _, _,99, _, _, _, _, _, /* @abcdefghijklmno */
+#endif
+ _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, /* */
+ _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, /* */
+ _, _, _, _, _, _, _, _, _, _, _,99, _, _, _, _, /* 0123456789:;<=>? */
+ _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, /* */
+ _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, /* */
+ _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, /* */
+ _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, /* */
+ _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, /* */
+ _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, /* */
+ _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, /* */
+ _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, /* */
+ _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _ /* */
+ };
+#undef _
+
+/* Functions private to this file. */
+
+extern const char line_comment_chars[];
+const char line_separator_chars[1];
+
+static char *buffer; /* 1st char of each buffer of lines is here. */
+static char *buffer_limit; /*->1 + last char in buffer. */
+
+static char *bignum_low; /* Lowest char of bignum. */
+static char *bignum_limit; /* 1st illegal address of bignum. */
+static char *bignum_high; /* Highest char of bignum. */
+/* May point to (bignum_start-1). */
+/* Never >= bignum_limit. */
+static char *old_buffer = 0; /* JF a hack */
+static char *old_input;
+static char *old_limit;
+
+/* Variables for handling include file directory list. */
+
+char **include_dirs; /* List of pointers to directories to
+ search for .include's */
+int include_dir_count; /* How many are in the list */
+int include_dir_maxlen = 1; /* Length of longest in list */
+
+#ifndef WORKING_DOT_WORD
+struct broken_word *broken_words;
+int new_broken_words = 0;
+#endif
+
+#if __STDC__ == 1
+
+static char *demand_copy_string(int *lenP);
+int is_it_end_of_statement(void);
+unsigned int next_char_of_string(void);
+static segT get_known_segmented_expression(expressionS *expP);
+static void grow_bignum(void);
+static void pobegin(void);
+void stringer(int append_zero);
+
+#else /* __STDC__ */
+
+static char *demand_copy_string();
+int is_it_end_of_statement();
+unsigned int next_char_of_string();
+static segT get_known_segmented_expression();
+static void grow_bignum();
+static void pobegin();
+void stringer();
+
+#endif /* not __STDC__ */
+
+extern int listing;
+
+
+void
+ read_begin()
+{
+ const char *p;
+
+ pobegin();
+ obj_read_begin_hook();
+
+ obstack_begin(&notes, 5000);
+ obstack_begin(&cond_obstack, 960);
+
+#define BIGNUM_BEGIN_SIZE (16)
+ bignum_low = xmalloc((long)BIGNUM_BEGIN_SIZE);
+ bignum_limit = bignum_low + BIGNUM_BEGIN_SIZE;
+
+ /* Use machine dependent syntax */
+ for (p = line_separator_chars; *p; p++)
+ is_end_of_line[*p] = 1;
+ /* Use more. FIXME-SOMEDAY. */
+}
+
+/* set up pseudo-op tables */
+
+struct hash_control *
+ po_hash = NULL; /* use before set up: NULL->address error */
+
+static const pseudo_typeS
+ potable[] =
+{
+ { "abort", s_abort, 0 },
+ { "align", s_align_ptwo, 0 },
+ { "ascii", stringer, 0 },
+ { "asciz", stringer, 1 },
+ /* block */
+ { "byte", cons, 1 },
+ { "comm", s_comm, 0 },
+ { "data", s_data, 0 },
+ /* dim */
+ { "double", float_cons, 'd' },
+ /* dsect */
+#ifdef NO_LISTING
+ { "eject", s_ignore, 0 }, /* Formfeed listing */
+#else
+ { "eject", listing_eject, 0 }, /* Formfeed listing */
+#endif /* NO_LISTING */
+ { "else", s_else, 0 },
+ { "end", s_end, 0 },
+ { "endif", s_endif, 0 },
+ /* endef */
+ { "equ", s_set, 0 },
+ /* err */
+ /* extend */
+ { "extern", s_ignore, 0 }, /* We treat all undef as ext */
+ { "appline", s_app_line, 0 },
+ { "appfile", s_app_file, 1 },
+ { "file", s_app_file, 0 },
+ { "fill", s_fill, 0 },
+ { "float", float_cons, 'f' },
+ { "global", s_globl, 0 },
+ { "globl", s_globl, 0 },
+ { "hword", cons, 2 },
+ { "if", s_if, 0 },
+ { "ifdef", s_ifdef, 0 },
+ { "ifeqs", s_ifeqs, 0 },
+ { "ifndef", s_ifdef, 1 },
+ { "ifnes", s_ifeqs, 1 },
+ { "ifnotdef", s_ifdef, 1 },
+ { "include", s_include, 0 },
+ { "int", cons, 4 },
+ { "lcomm", s_lcomm, 0 },
+#ifdef NO_LISTING
+ { "lflags", s_ignore, 0 }, /* Listing flags */
+ { "list", s_ignore, 1 }, /* Turn listing on */
+#else
+ { "lflags", listing_flags, 0 }, /* Listing flags */
+ { "list", listing_list, 1 }, /* Turn listing on */
+#endif /* NO_LISTING */
+ { "long", cons, 4 },
+ { "lsym", s_lsym, 0 },
+#ifdef NO_LISTING
+ { "nolist", s_ignore, 0 }, /* Turn listing off */
+#else
+ { "nolist", listing_list, 0 }, /* Turn listing off */
+#endif /* NO_LISTING */
+ { "octa", big_cons, 16 },
+ { "org", s_org, 0 },
+#ifdef NO_LISTING
+ { "psize", s_ignore, 0 }, /* set paper size */
+#else
+ { "psize", listing_psize, 0 }, /* set paper size */
+#endif /* NO_LISTING */
+ /* print */
+ { "quad", big_cons, 8 },
+#ifdef NO_LISTING
+ { "sbttl", s_ignore, 1 }, /* Subtitle of listing */
+#else
+ { "sbttl", listing_title, 1 }, /* Subtitle of listing */
+#endif /* NO_LISTING */
+ /* scl */
+ /* sect */
+#ifndef TC_M88K
+ { "set", s_set, 0 },
+#endif /* TC_M88K */
+ { "short", cons, 2 },
+ { "single", float_cons, 'f' },
+ /* size */
+ { "space", s_space, 0 },
+ /* tag */
+ { "text", s_text, 0 },
+#ifdef NO_LISTING
+ { "title", s_ignore, 0 }, /* Listing title */
+#else
+ { "title", listing_title, 0 }, /* Listing title */
+#endif /* NO_LISTING */
+ /* type */
+ /* use */
+ /* val */
+ { "word", cons, 2 },
+ { NULL} /* end sentinel */
+};
+
+static void pobegin() {
+ char *errtxt; /* error text */
+ const pseudo_typeS * pop;
+
+ po_hash = hash_new();
+
+ /* Do the target-specific pseudo ops. */
+ for (pop = md_pseudo_table; pop->poc_name; pop++) {
+ errtxt = hash_insert(po_hash, pop->poc_name, (char *)pop);
+ if (errtxt && *errtxt) {
+ as_fatal("error constructing md pseudo-op table");
+ } /* on error */
+ } /* for each op */
+
+ /* Now object specific. Skip any that were in the target table. */
+ for (pop = obj_pseudo_table; pop->poc_name; pop++) {
+ errtxt = hash_insert(po_hash, pop->poc_name, (char *) pop);
+ if (errtxt && *errtxt) {
+ if (!strcmp(errtxt, "exists")) {
+#ifdef DIE_ON_OVERRIDES
+ as_fatal("pseudo op \".%s\" overridden.\n", pop->poc_name);
+#endif /* DIE_ON_OVERRIDES */
+ continue; /* OK if target table overrides. */
+ } else {
+ as_fatal("error constructing obj pseudo-op table");
+ } /* if overridden */
+ } /* on error */
+ } /* for each op */
+
+ /* Now portable ones. Skip any that we've seen already. */
+ for (pop = potable; pop->poc_name; pop++) {
+ errtxt = hash_insert(po_hash, pop->poc_name, (char *) pop);
+ if (errtxt && *errtxt) {
+ if (!strcmp (errtxt, "exists")) {
+#ifdef DIE_ON_OVERRIDES
+ as_fatal("pseudo op \".%s\" overridden.\n", pop->poc_name);
+#endif /* DIE_ON_OVERRIDES */
+ continue; /* OK if target table overrides. */
+ } else {
+ as_fatal("error constructing obj pseudo-op table");
+ } /* if overridden */
+ } /* on error */
+ } /* for each op */
+
+ return;
+} /* pobegin() */
+
+#define HANDLE_CONDITIONAL_ASSEMBLY() \
+ if (ignore_input ()) \
+{ \
+ while (! is_end_of_line[*input_line_pointer++]) \
+ if (input_line_pointer == buffer_limit) \
+ break; \
+ continue; \
+ }
+
+
+/* read_a_source_file()
+ *
+ * We read the file, putting things into a web that
+ * represents what we have been reading.
+ */
+void read_a_source_file(name)
+char *name;
+{
+ register char c;
+ register char * s; /* string of symbol, '\0' appended */
+ register int temp;
+ pseudo_typeS *pop = NULL;
+
+ buffer = input_scrub_new_file(name);
+
+ listing_file(name);
+ listing_newline("");
+
+ while ((buffer_limit = input_scrub_next_buffer(&input_line_pointer)) != 0) { /* We have another line to parse. */
+ know(buffer_limit[-1] == '\n'); /* Must have a sentinel. */
+ contin: /* JF this goto is my fault I admit it. Someone brave please re-write
+ the whole input section here? Pleeze??? */
+ while (input_line_pointer < buffer_limit) { /* We have more of this buffer to parse. */
+
+ /*
+ * We now have input_line_pointer->1st char of next line.
+ * If input_line_pointer[-1] == '\n' then we just
+ * scanned another line: so bump line counters.
+ */
+ if (input_line_pointer[-1] == '\n') {
+ bump_line_counters();
+ } /* just passed a newline */
+
+
+
+ /*
+ * We are at the begining of a line, or similar place.
+ * We expect a well-formed assembler statement.
+ * A "symbol-name:" is a statement.
+ *
+ * Depending on what compiler is used, the order of these tests
+ * may vary to catch most common case 1st.
+ * Each test is independent of all other tests at the (top) level.
+ * PLEASE make a compiler that doesn't use this assembler.
+ * It is crufty to waste a compiler's time encoding things for this
+ * assembler, which then wastes more time decoding it.
+ * (And communicating via (linear) files is silly!
+ * If you must pass stuff, please pass a tree!)
+ */
+ if ((c = *input_line_pointer++) == '\t' || c == ' ' || c == '\f' || c == 0) {
+ c = *input_line_pointer++;
+ }
+ know(c != ' '); /* No further leading whitespace. */
+ LISTING_NEWLINE();
+ /*
+ * C is the 1st significant character.
+ * Input_line_pointer points after that character.
+ */
+ if (is_name_beginner(c)) { /* want user-defined label or pseudo/opcode */
+ HANDLE_CONDITIONAL_ASSEMBLY();
+
+ s = input_line_pointer - 1;
+ c = get_symbol_end(); /* name's delimiter */
+ /*
+ * C is character after symbol.
+ * That character's place in the input line is now '\0'.
+ * S points to the beginning of the symbol.
+ * [In case of pseudo-op, s->'.'.]
+ * Input_line_pointer->'\0' where c was.
+ */
+ if (c == ':') {
+ colon(s); /* user-defined label */
+ * input_line_pointer ++ = ':'; /* Put ':' back for error messages' sake. */
+ /* Input_line_pointer->after ':'. */
+ SKIP_WHITESPACE();
+
+
+ } else if (c == '=' || input_line_pointer[1] == '=') { /* JF deal with FOO=BAR */
+ equals(s);
+ demand_empty_rest_of_line();
+ } else { /* expect pseudo-op or machine instruction */
+ if (*s == '.'
+#ifdef NO_DOT_PSEUDOS
+ || (pop= (pseudo_typeS *) hash_find(po_hash, s))
+#endif
+ ) {
+ /*
+ * PSEUDO - OP.
+ *
+ * WARNING: c has next char, which may be end-of-line.
+ * We lookup the pseudo-op table with s+1 because we
+ * already know that the pseudo-op begins with a '.'.
+ */
+
+#ifdef NO_DOT_PSEUDOS
+ if (*s == '.')
+#endif
+ pop = (pseudo_typeS *) hash_find(po_hash, s+1);
+
+ /* Print the error msg now, while we still can */
+ if (!pop) {
+ as_bad("Unknown pseudo-op: `%s'",s);
+ *input_line_pointer = c;
+ s_ignore(0);
+ break;
+ }
+
+ /* Put it back for error messages etc. */
+ *input_line_pointer = c;
+ /* The following skip of whitespace is compulsory. */
+ /* A well shaped space is sometimes all that separates keyword from operands. */
+ if (c == ' ' || c == '\t') {
+ input_line_pointer++;
+ } /* Skip seperator after keyword. */
+ /*
+ * Input_line is restored.
+ * Input_line_pointer->1st non-blank char
+ * after pseudo-operation.
+ */
+ if (!pop) {
+ ignore_rest_of_line();
+ break;
+ } else {
+ (*pop->poc_handler)(pop->poc_val);
+ } /* if we have one */
+ } else { /* machine instruction */
+ /* WARNING: c has char, which may be end-of-line. */
+ /* Also: input_line_pointer->`\0` where c was. */
+ * input_line_pointer = c;
+ while (!is_end_of_line[*input_line_pointer]) {
+ input_line_pointer++;
+ }
+ c = *input_line_pointer;
+ *input_line_pointer = '\0';
+ md_assemble(s); /* Assemble 1 instruction. */
+ *input_line_pointer++ = c;
+ /* We resume loop AFTER the end-of-line from this instruction */
+ } /* if (*s == '.') */
+
+ } /* if c == ':' */
+ continue;
+ } /* if (is_name_beginner(c) */
+
+
+ if (is_end_of_line[c]) {
+ continue;
+ } /* empty statement */
+
+
+ if (isdigit(c)) { /* local label ("4:") */
+ HANDLE_CONDITIONAL_ASSEMBLY ();
+
+ temp = c - '0';
+#ifdef LOCAL_LABELS_DOLLAR
+ if (*input_line_pointer == '$')
+ input_line_pointer++;
+#endif
+ if (*input_line_pointer++ == ':') {
+ local_colon (temp);
+ } else {
+ as_bad("Spurious digit %d.", temp);
+ input_line_pointer -- ;
+ ignore_rest_of_line();
+ }
+ continue;
+ } /* local label ("4:") */
+
+ if (c && strchr(line_comment_chars, c)) { /* Its a comment. Better say APP or NO_APP */
+ char *ends;
+ char *new_buf;
+ char *new_tmp;
+ int new_length;
+ char *tmp_buf = 0;
+ extern char *scrub_string, *scrub_last_string;
+
+ bump_line_counters();
+ s = input_line_pointer;
+ if (strncmp(s,"APP\n",4))
+ continue; /* We ignore it */
+ s += 4;
+
+ ends = strstr(s,"#NO_APP\n");
+
+ if (!ends) {
+ int tmp_len;
+ int num;
+
+ /* The end of the #APP wasn't in this buffer. We
+ keep reading in buffers until we find the #NO_APP
+ that goes with this #APP There is one. The specs
+ guarentee it... */
+ tmp_len = buffer_limit - s;
+ tmp_buf = xmalloc(tmp_len);
+ memcpy(tmp_buf, s, tmp_len);
+ do {
+ new_tmp = input_scrub_next_buffer(&buffer);
+ if (!new_tmp)
+ break;
+ else
+ buffer_limit = new_tmp;
+ input_line_pointer = buffer;
+ ends = strstr(buffer,"#NO_APP\n");
+ if (ends)
+ num = ends - buffer;
+ else
+ num = buffer_limit - buffer;
+
+ tmp_buf = xrealloc(tmp_buf, tmp_len + num);
+ memcpy(tmp_buf + tmp_len, buffer, num);
+ tmp_len += num;
+ } while (!ends);
+
+ input_line_pointer = ends ? ends + 8 : NULL;
+
+ s = tmp_buf;
+ ends = s + tmp_len;
+
+ } else {
+ input_line_pointer = ends + 8;
+ }
+ new_buf=xmalloc(100);
+ new_length=100;
+ new_tmp=new_buf;
+
+ scrub_string = s;
+ scrub_last_string = ends;
+ for (;;) {
+ int ch;
+
+ ch = do_scrub_next_char(scrub_from_string, scrub_to_string);
+ if (ch == EOF) break;
+ *new_tmp++ = ch;
+ if (new_tmp == new_buf + new_length) {
+ new_buf = xrealloc(new_buf, new_length + 100);
+ new_tmp = new_buf + new_length;
+ new_length += 100;
+ }
+ }
+
+ if (tmp_buf)
+ free(tmp_buf);
+ old_buffer = buffer;
+ old_input = input_line_pointer;
+ old_limit = buffer_limit;
+ buffer = new_buf;
+ input_line_pointer = new_buf;
+ buffer_limit = new_tmp;
+ continue;
+ }
+
+ HANDLE_CONDITIONAL_ASSEMBLY();
+
+ /* as_warn("Junk character %d.",c); Now done by ignore_rest */
+ input_line_pointer--; /* Report unknown char as ignored. */
+ ignore_rest_of_line();
+ } /* while (input_line_pointer<buffer_limit) */
+ if (old_buffer) {
+ bump_line_counters();
+ if (old_input != 0) {
+ buffer=old_buffer;
+ input_line_pointer=old_input;
+ buffer_limit=old_limit;
+ old_buffer = 0;
+ goto contin;
+ }
+ }
+ } /* while (more buffers to scan) */
+ input_scrub_close(); /* Close the input file */
+
+} /* read_a_source_file() */
+
+void s_abort() {
+ as_fatal(".abort detected. Abandoning ship.");
+} /* s_abort() */
+
+/* For machines where ".align 4" means align to a 4 byte boundary. */
+void s_align_bytes(arg)
+int arg;
+{
+ register unsigned int temp;
+ register long temp_fill;
+ unsigned int i = 0;
+ unsigned long max_alignment = 1 << 15;
+
+ if (is_end_of_line[*input_line_pointer])
+ temp = arg; /* Default value from pseudo-op table */
+ else
+ temp = get_absolute_expression();
+
+ if (temp > max_alignment) {
+ as_bad("Alignment too large: %d. assumed.", temp = max_alignment);
+ }
+
+ /*
+ * For the sparc, `.align (1<<n)' actually means `.align n'
+ * so we have to convert it.
+ */
+ if (temp != 0) {
+ for (i = 0; (temp & 1) == 0; temp >>= 1, ++i)
+ ;
+ }
+ if (temp != 1)
+ as_bad("Alignment not a power of 2");
+
+ temp = i;
+ if (*input_line_pointer == ',') {
+ input_line_pointer ++;
+ temp_fill = get_absolute_expression();
+ } else {
+ temp_fill = NOP_OPCODE;
+ }
+ /* Only make a frag if we HAVE to... */
+ if (temp && ! need_pass_2)
+ frag_align(temp, (int)temp_fill);
+
+ demand_empty_rest_of_line();
+} /* s_align_bytes() */
+
+/* For machines where ".align 4" means align to 2**4 boundary. */
+void s_align_ptwo() {
+ register int temp;
+ register long temp_fill;
+ long max_alignment = 15;
+
+ temp = get_absolute_expression();
+ if (temp > max_alignment)
+ as_bad("Alignment too large: %d. assumed.", temp = max_alignment);
+ else if (temp < 0) {
+ as_bad("Alignment negative. 0 assumed.");
+ temp = 0;
+ }
+ if (*input_line_pointer == ',') {
+ input_line_pointer ++;
+ temp_fill = get_absolute_expression();
+ } else
+ temp_fill = NOP_OPCODE;
+ /* Only make a frag if we HAVE to... */
+ if (temp && ! need_pass_2)
+ frag_align (temp, (int)temp_fill);
+
+ record_alignment(now_seg, temp);
+
+ demand_empty_rest_of_line();
+} /* s_align_ptwo() */
+
+void s_comm() {
+ register char *name;
+ register char c;
+ register char *p;
+ register int temp;
+ register symbolS *symbolP;
+
+ name = input_line_pointer;
+ c = get_symbol_end();
+ /* just after name is now '\0' */
+ p = input_line_pointer;
+ *p = c;
+ SKIP_WHITESPACE();
+ if (*input_line_pointer != ',') {
+ as_bad("Expected comma after symbol-name: rest of line ignored.");
+ ignore_rest_of_line();
+ return;
+ }
+ input_line_pointer ++; /* skip ',' */
+ if ((temp = get_absolute_expression()) < 0) {
+ as_warn(".COMMon length (%d.) <0! Ignored.", temp);
+ ignore_rest_of_line();
+ return;
+ }
+ *p = 0;
+ symbolP = symbol_find_or_make(name);
+ *p = c;
+ if (S_IS_DEFINED(symbolP)) {
+ as_bad("Ignoring attempt to re-define symbol");
+ ignore_rest_of_line();
+ return;
+ }
+ if (S_GET_VALUE(symbolP)) {
+ if (S_GET_VALUE(symbolP) != temp)
+ as_bad("Length of .comm \"%s\" is already %d. Not changed to %d.",
+ S_GET_NAME(symbolP),
+ S_GET_VALUE(symbolP),
+ temp);
+ } else {
+ S_SET_VALUE(symbolP, temp);
+ S_SET_EXTERNAL(symbolP);
+ }
+#ifdef OBJ_VMS
+ if ( (!temp) || !flagseen['1'])
+ S_GET_OTHER(symbolP) = const_flag;
+#endif /* not OBJ_VMS */
+ know(symbolP->sy_frag == &zero_address_frag);
+ demand_empty_rest_of_line();
+} /* s_comm() */
+
+void
+ s_data()
+{
+ register int temp;
+
+ temp = get_absolute_expression();
+#ifdef MANY_SEGMENTS
+ subseg_new (SEG_E1, (subsegT)temp);
+#else
+ subseg_new (SEG_DATA, (subsegT)temp);
+#endif
+
+#ifdef OBJ_VMS
+ const_flag = 0;
+#endif /* not OBJ_VMS */
+ demand_empty_rest_of_line();
+}
+
+/* Handle the .appfile pseudo-op. This is automatically generated by
+ do_scrub_next_char when a preprocessor # line comment is seen with
+ a file name. This default definition may be overridden by the
+ object or CPU specific pseudo-ops. This function is also the
+ default definition for .file; the APPFILE argument is 1 for
+ .appfile, 0 for .file. */
+
+void s_app_file(appfile)
+ int appfile;
+{
+ register char *s;
+ int length;
+
+ /* Some assemblers tolerate immediately following '"' */
+ if ((s = demand_copy_string(&length)) != 0) {
+ /* If this is a fake .appfile, a fake newline was inserted
+ * into the buffer. Passing -2 to new_logical_line tells it
+ * to account for it.
+ */
+ new_logical_line (s, appfile ? -2 : -1);
+ demand_empty_rest_of_line();
+#ifdef LISTING
+ if (listing)
+ listing_source_file (s);
+#endif
+ }
+#ifdef OBJ_COFF
+ c_dot_file_symbol(s);
+#endif /* OBJ_COFF */
+} /* s_app_file() */
+
+/* Handle the .appline pseudo-op. This is automatically generated by
+ do_scrub_next_char when a preprocessor # line comment is seen.
+ This default definition may be overridden by the object or CPU
+ specific pseudo-ops. */
+
+void
+s_app_line (ignore)
+ int ignore;
+{
+ int l;
+
+ /* The given number is that of the next line. */
+ l = get_absolute_expression () - 1;
+ new_logical_line ((char *) NULL, l);
+#ifdef LISTING
+ if (listing)
+ listing_source_line (l);
+#endif
+ demand_empty_rest_of_line ();
+}
+
+void s_fill() {
+ long temp_repeat;
+ long temp_size;
+ register long temp_fill;
+ char *p;
+
+ if (get_absolute_expression_and_terminator(& temp_repeat) != ',') {
+ input_line_pointer --; /* Backup over what was not a ','. */
+ as_bad("Expect comma after rep-size in .fill:");
+ ignore_rest_of_line();
+ return;
+ }
+ if (get_absolute_expression_and_terminator(& temp_size) != ',') {
+ input_line_pointer --; /* Backup over what was not a ','. */
+ as_bad("Expected comma after size in .fill");
+ ignore_rest_of_line();
+ return;
+ }
+ /*
+ * This is to be compatible with BSD 4.2 AS, not for any rational reason.
+ */
+#define BSD_FILL_SIZE_CROCK_8 (8)
+ if (temp_size > BSD_FILL_SIZE_CROCK_8) {
+ as_bad(".fill size clamped to %d.", BSD_FILL_SIZE_CROCK_8);
+ temp_size = BSD_FILL_SIZE_CROCK_8 ;
+ } if (temp_size < 0) {
+ as_warn("Size negative: .fill ignored.");
+ temp_size = 0;
+ } else if (temp_repeat <= 0) {
+ as_warn("Repeat < 0, .fill ignored");
+ temp_size = 0;
+ }
+ temp_fill = get_absolute_expression();
+ if (temp_size && !need_pass_2) {
+ p = frag_var(rs_fill, (int)temp_size, (int)temp_size, (relax_substateT)0, (symbolS *)0, temp_repeat, (char *)0);
+ memset(p, '\0', (int) temp_size);
+ /*
+ * The magic number BSD_FILL_SIZE_CROCK_4 is from BSD 4.2 VAX flavoured AS.
+ * The following bizzare behaviour is to be compatible with above.
+ * I guess they tried to take up to 8 bytes from a 4-byte expression
+ * and they forgot to sign extend. Un*x Sux.
+ */
+#define BSD_FILL_SIZE_CROCK_4 (4)
+ md_number_to_chars (p, temp_fill, temp_size > BSD_FILL_SIZE_CROCK_4 ? BSD_FILL_SIZE_CROCK_4 : (int)temp_size);
+ /*
+ * Note: .fill (),0 emits no frag (since we are asked to .fill 0 bytes)
+ * but emits no error message because it seems a legal thing to do.
+ * It is a degenerate case of .fill but could be emitted by a compiler.
+ */
+ }
+ demand_empty_rest_of_line();
+}
+
+void s_globl() {
+ register char *name;
+ register int c;
+ register symbolS * symbolP;
+
+ do {
+ name = input_line_pointer;
+ c = get_symbol_end();
+ symbolP = symbol_find_or_make(name);
+ * input_line_pointer = c;
+ SKIP_WHITESPACE();
+ S_SET_EXTERNAL(symbolP);
+ if (c == ',') {
+ input_line_pointer++;
+ SKIP_WHITESPACE();
+ if (*input_line_pointer == '\n')
+ c='\n';
+ }
+ } while (c == ',');
+ demand_empty_rest_of_line();
+} /* s_globl() */
+
+void s_lcomm(needs_align)
+int needs_align; /* 1 if this was a ".bss" directive, which may require
+ * a 3rd argument (alignment).
+ * 0 if it was an ".lcomm" (2 args only)
+ */
+{
+ register char *name;
+ register char c;
+ register char *p;
+ register int temp;
+ register symbolS * symbolP;
+ const int max_alignment = 15;
+ int align = 0;
+
+ name = input_line_pointer;
+ c = get_symbol_end();
+ p = input_line_pointer;
+ *p = c;
+ SKIP_WHITESPACE();
+ if (*input_line_pointer != ',') {
+ as_bad("Expected comma after name");
+ ignore_rest_of_line();
+ return;
+ }
+
+ ++input_line_pointer;
+
+ if (*input_line_pointer == '\n') {
+ as_bad("Missing size expression");
+ return;
+ }
+
+ if ((temp = get_absolute_expression()) < 0) {
+ as_warn("BSS length (%d.) <0! Ignored.", temp);
+ ignore_rest_of_line();
+ return;
+ }
+
+ if (needs_align) {
+ align = 0;
+ SKIP_WHITESPACE();
+ if (*input_line_pointer != ',') {
+ as_bad("Expected comma after size");
+ ignore_rest_of_line();
+ return;
+ }
+ input_line_pointer++;
+ SKIP_WHITESPACE();
+ if (*input_line_pointer == '\n') {
+ as_bad("Missing alignment");
+ return;
+ }
+ align = get_absolute_expression();
+ if (align > max_alignment){
+ align = max_alignment;
+ as_warn("Alignment too large: %d. assumed.", align);
+ } else if (align < 0) {
+ align = 0;
+ as_warn("Alignment negative. 0 assumed.");
+ }
+#ifdef MANY_SEGMENTS
+#define SEG_BSS SEG_E2
+ record_alignment(SEG_E2, align);
+#else
+ record_alignment(SEG_BSS, align);
+#endif
+ } /* if needs align */
+
+ *p = 0;
+ symbolP = symbol_find_or_make(name);
+ *p = c;
+
+ if (
+#if defined(OBJ_AOUT) | defined(OBJ_BOUT)
+ S_GET_OTHER(symbolP) == 0 &&
+ S_GET_DESC(symbolP) == 0 &&
+#endif /* OBJ_AOUT or OBJ_BOUT */
+ (((S_GET_SEGMENT(symbolP) == SEG_BSS) && (S_GET_VALUE(symbolP) == local_bss_counter))
+ || (!S_IS_DEFINED(symbolP) && S_GET_VALUE(symbolP) == 0))) {
+ if (needs_align){
+ /* Align */
+ align = ~ ((~0) << align); /* Convert to a mask */
+ local_bss_counter =
+ (local_bss_counter + align) & (~align);
+ }
+
+ S_SET_VALUE(symbolP, local_bss_counter);
+ S_SET_SEGMENT(symbolP, SEG_BSS);
+#ifdef OBJ_COFF
+ /* The symbol may already have been created with a preceding
+ * ".globl" directive -- be careful not to step on storage
+ * class in that case. Otherwise, set it to static.
+ */
+ if (S_GET_STORAGE_CLASS(symbolP) != C_EXT){
+ S_SET_STORAGE_CLASS(symbolP, C_STAT);
+ }
+#endif /* OBJ_COFF */
+ symbolP->sy_frag = &bss_address_frag;
+ local_bss_counter += temp;
+ } else {
+ as_bad("Ignoring attempt to re-define symbol from %d. to %d.",
+ S_GET_VALUE(symbolP), local_bss_counter);
+ }
+ demand_empty_rest_of_line();
+
+ return;
+} /* s_lcomm() */
+
+void
+ s_long()
+{
+ cons(4);
+}
+
+void
+ s_int()
+{
+ cons(4);
+}
+
+void s_lsym() {
+ register char *name;
+ register char c;
+ register char *p;
+ register segT segment;
+ expressionS exp;
+ register symbolS *symbolP;
+
+ /* we permit ANY defined expression: BSD4.2 demands constants */
+ name = input_line_pointer;
+ c = get_symbol_end();
+ p = input_line_pointer;
+ *p = c;
+ SKIP_WHITESPACE();
+ if (* input_line_pointer != ',') {
+ *p = 0;
+ as_bad("Expected comma after name \"%s\"", name);
+ *p = c;
+ ignore_rest_of_line();
+ return;
+ }
+ input_line_pointer ++;
+ segment = expression(& exp);
+ if (segment != SEG_ABSOLUTE
+#ifdef MANY_SEGMENTS
+ && ! ( segment >= SEG_E0 && segment <= SEG_UNKNOWN)
+#else
+ && segment != SEG_DATA
+ && segment != SEG_TEXT
+ && segment != SEG_BSS
+#endif
+ && segment != SEG_REGISTER) {
+ as_bad("Bad expression: %s", segment_name(segment));
+ ignore_rest_of_line();
+ return;
+ }
+ *p = 0;
+ symbolP = symbol_find_or_make(name);
+
+ /* FIXME-SOON I pulled a (&& symbolP->sy_other == 0
+ && symbolP->sy_desc == 0) out of this test
+ because coff doesn't have those fields, and I
+ can't see when they'd ever be tripped. I don't
+ think I understand why they were here so I may
+ have introduced a bug. As recently as 1.37 didn't
+ have this test anyway. xoxorich. */
+
+ if (S_GET_SEGMENT(symbolP) == SEG_UNKNOWN
+ && S_GET_VALUE(symbolP) == 0) {
+ /* The name might be an undefined .global symbol; be
+ sure to keep the "external" bit. */
+ S_SET_SEGMENT(symbolP, segment);
+ S_SET_VALUE(symbolP, (valueT)(exp.X_add_number));
+ } else {
+ as_bad("Symbol %s already defined", name);
+ }
+ *p = c;
+ demand_empty_rest_of_line();
+} /* s_lsym() */
+
+void s_org() {
+ register segT segment;
+ expressionS exp;
+ register long temp_fill;
+ register char *p;
+ /*
+ * Don't believe the documentation of BSD 4.2 AS.
+ * There is no such thing as a sub-segment-relative origin.
+ * Any absolute origin is given a warning, then assumed to be segment-relative.
+ * Any segmented origin expression ("foo+42") had better be in the right
+ * segment or the .org is ignored.
+ *
+ * BSD 4.2 AS warns if you try to .org backwards. We cannot because we
+ * never know sub-segment sizes when we are reading code.
+ * BSD will crash trying to emit -ve numbers of filler bytes in certain
+ * .orgs. We don't crash, but see as-write for that code.
+ */
+ /*
+ * Don't make frag if need_pass_2 == 1.
+ */
+ segment = get_known_segmented_expression(&exp);
+ if (*input_line_pointer == ',') {
+ input_line_pointer ++;
+ temp_fill = get_absolute_expression();
+ } else
+ temp_fill = 0;
+ if (! need_pass_2) {
+ if (segment != now_seg && segment != SEG_ABSOLUTE)
+ as_bad("Invalid segment \"%s\". Segment \"%s\" assumed.",
+ segment_name(segment), segment_name(now_seg));
+ p = frag_var (rs_org, 1, 1, (relax_substateT)0, exp.X_add_symbol,
+ exp.X_add_number, (char *)0);
+ * p = temp_fill;
+ } /* if (ok to make frag) */
+ demand_empty_rest_of_line();
+} /* s_org() */
+
+void s_set() {
+ register char *name;
+ register char delim;
+ register char *end_name;
+ register symbolS *symbolP;
+
+ /*
+ * Especial apologies for the random logic:
+ * this just grew, and could be parsed much more simply!
+ * Dean in haste.
+ */
+ name = input_line_pointer;
+ delim = get_symbol_end();
+ end_name = input_line_pointer;
+ *end_name = delim;
+ SKIP_WHITESPACE();
+
+ if (*input_line_pointer != ',') {
+ *end_name = 0;
+ as_bad("Expected comma after name \"%s\"", name);
+ *end_name = delim;
+ ignore_rest_of_line();
+ return;
+ }
+
+ input_line_pointer ++;
+ *end_name = 0;
+
+ if (name[0] == '.' && name[1] == '\0') {
+ /* Turn '. = mumble' into a .org mumble */
+ register segT segment;
+ expressionS exp;
+ register char *ptr;
+
+ segment = get_known_segmented_expression(& exp);
+
+ if (!need_pass_2) {
+ if (segment != now_seg && segment != SEG_ABSOLUTE)
+ as_bad("Invalid segment \"%s\". Segment \"%s\" assumed.",
+ segment_name(segment),
+ segment_name (now_seg));
+ ptr = frag_var(rs_org, 1, 1, (relax_substateT)0, exp.X_add_symbol,
+ exp.X_add_number, (char *)0);
+ *ptr= 0;
+ } /* if (ok to make frag) */
+
+ *end_name = delim;
+ return;
+ }
+
+ if ((symbolP = symbol_find(name)) == NULL
+ && (symbolP = md_undefined_symbol(name)) == NULL) {
+ symbolP = symbol_new(name,
+ SEG_UNKNOWN,
+ 0,
+ &zero_address_frag);
+#ifdef OBJ_COFF
+ /* "set" symbols are local unless otherwise specified. */
+ SF_SET_LOCAL(symbolP);
+#endif /* OBJ_COFF */
+
+ } /* make a new symbol */
+
+ symbol_table_insert(symbolP);
+
+ *end_name = delim;
+ pseudo_set(symbolP);
+ demand_empty_rest_of_line();
+} /* s_set() */
+
+void s_size() {
+ register char *name;
+ register char c;
+ register char *p;
+ register int temp;
+ register symbolS *symbolP;
+ expressionS *exp;
+ segT seg;
+
+ SKIP_WHITESPACE();
+ name = input_line_pointer;
+ c = get_symbol_end();
+ /* just after name is now '\0' */
+ p = input_line_pointer;
+ *p = c;
+ SKIP_WHITESPACE();
+ if (*input_line_pointer != ',') {
+ as_bad("Expected comma after symbol-name: rest of line ignored.");
+ ignore_rest_of_line();
+ return;
+ }
+ input_line_pointer ++; /* skip ',' */
+ if ((exp = (expressionS *)malloc(sizeof(expressionS))) == NULL) {
+ as_bad("Virtual memory exhausted");
+ return;
+ }
+ switch (get_known_segmented_expression(exp)) {
+ case SEG_ABSOLUTE:
+ break;
+ case SEG_DIFFERENCE:
+ if (exp->X_add_symbol == NULL || exp->X_subtract_symbol == NULL
+ || S_GET_SEGMENT(exp->X_add_symbol) !=
+ S_GET_SEGMENT(exp->X_subtract_symbol)) {
+ as_bad("Illegal .size expression");
+ ignore_rest_of_line();
+ return;
+ }
+ break;
+ default:
+ as_bad("Illegal .size expression");
+ ignore_rest_of_line();
+ return;
+ }
+ *p = 0;
+ symbolP = symbol_find_or_make(name);
+ *p = c;
+ if (symbolP->sy_sizexp) {
+ as_warn("\"%s\" already has a size", S_GET_NAME(symbolP));
+ } else
+ symbolP->sy_sizexp = (void *)exp;
+
+ demand_empty_rest_of_line();
+} /* s_size() */
+
+void s_type() {
+ register char *name, *type;
+ register char c, c1;
+ register char *p;
+ register symbolS *symbolP;
+ int aux;
+
+ SKIP_WHITESPACE();
+ name = input_line_pointer;
+ c = get_symbol_end();
+ /* just after name is now '\0' */
+ p = input_line_pointer;
+ *p = c;
+ SKIP_WHITESPACE();
+ if (*input_line_pointer != ',') {
+ as_bad("Expected comma after symbol-name: rest of line ignored.");
+ ignore_rest_of_line();
+ return;
+ }
+ input_line_pointer ++; /* skip ',' */
+ SKIP_WHITESPACE();
+ if (*input_line_pointer != TYPE_OPERAND_FMT) {
+ as_bad("Expected `%c' as start of operand: rest of line ignored.", TYPE_OPERAND_FMT);
+ ignore_rest_of_line();
+ return;
+ }
+ input_line_pointer ++; /* skip '@' */
+ type = input_line_pointer;
+ c1 = get_symbol_end();
+ if (strcmp(type, "function") == 0) {
+ aux = AUX_FUNC;
+ } else if (strcmp(type, "object") == 0) {
+ aux = AUX_OBJECT;
+ } else {
+ as_warn("Unrecognized .type operand: \"%s\": rest of line ignored.",
+ type);
+ ignore_rest_of_line();
+ return;
+ }
+ *input_line_pointer = c1;
+
+ *p = 0;
+ symbolP = symbol_find_or_make(name);
+ *p = c;
+
+ if (symbolP->sy_aux && symbolP->sy_aux != aux) {
+ as_bad("Type of \"%s\" is already %d. Not changed to %d.",
+ S_GET_NAME(symbolP), symbolP->sy_aux, aux);
+ } else
+ symbolP->sy_aux = aux;
+
+ demand_empty_rest_of_line();
+} /* s_type() */
+
+void s_space() {
+ long temp_repeat;
+ register long temp_fill;
+ register char *p;
+
+ /* Just like .fill, but temp_size = 1 */
+ if (get_absolute_expression_and_terminator(& temp_repeat) == ',') {
+ temp_fill = get_absolute_expression();
+ } else {
+ input_line_pointer --; /* Backup over what was not a ','. */
+ temp_fill = 0;
+ }
+ if (temp_repeat <= 0) {
+ as_warn("Repeat < 0, .space ignored");
+ ignore_rest_of_line();
+ return;
+ }
+ if (! need_pass_2) {
+ p = frag_var (rs_fill, 1, 1, (relax_substateT)0, (symbolS *)0,
+ temp_repeat, (char *)0);
+ * p = temp_fill;
+ }
+ demand_empty_rest_of_line();
+} /* s_space() */
+
+void
+ s_text()
+{
+ register int temp;
+
+ temp = get_absolute_expression();
+#ifdef MANY_SEGMENTS
+ subseg_new (SEG_E0, (subsegT)temp);
+#else
+ subseg_new (SEG_TEXT, (subsegT)temp);
+#endif
+ demand_empty_rest_of_line();
+} /* s_text() */
+
+
+/*(JF was static, but can't be if machine dependent pseudo-ops are to use it */
+
+void demand_empty_rest_of_line() {
+ SKIP_WHITESPACE();
+ if (is_end_of_line[*input_line_pointer]) {
+ input_line_pointer++;
+ } else {
+ ignore_rest_of_line();
+ }
+ /* Return having already swallowed end-of-line. */
+} /* Return pointing just after end-of-line. */
+
+void
+ ignore_rest_of_line() /* For suspect lines: gives warning. */
+{
+ if (!is_end_of_line[*input_line_pointer])
+ {
+ if (isprint(*input_line_pointer))
+ as_bad("Rest of line ignored. First ignored character is `%c'.",
+ *input_line_pointer);
+ else
+ as_bad("Rest of line ignored. First ignored character valued 0x%x.",
+ *input_line_pointer);
+ while (input_line_pointer < buffer_limit
+ && !is_end_of_line[*input_line_pointer])
+ {
+ input_line_pointer ++;
+ }
+ }
+ input_line_pointer ++; /* Return pointing just after end-of-line. */
+ know(is_end_of_line[input_line_pointer[-1]]);
+}
+
+/*
+ * pseudo_set()
+ *
+ * In: Pointer to a symbol.
+ * Input_line_pointer->expression.
+ *
+ * Out: Input_line_pointer->just after any whitespace after expression.
+ * Tried to set symbol to value of expression.
+ * Will change symbols type, value, and frag;
+ * May set need_pass_2 == 1.
+ */
+void
+ pseudo_set (symbolP)
+symbolS * symbolP;
+{
+ expressionS exp;
+ register segT segment;
+#if defined(OBJ_AOUT) | defined(OBJ_BOUT)
+ int ext;
+#endif /* OBJ_AOUT or OBJ_BOUT */
+
+ know(symbolP); /* NULL pointer is logic error. */
+#if defined(OBJ_AOUT) | defined(OBJ_BOUT)
+ ext=S_IS_EXTERNAL(symbolP);
+#endif /* OBJ_AOUT or OBJ_BOUT */
+
+ if ((segment = expression(& exp)) == SEG_ABSENT)
+ {
+ as_bad("Missing expression: absolute 0 assumed");
+ exp.X_seg = SEG_ABSOLUTE;
+ exp.X_add_number = 0;
+ }
+
+ switch (segment)
+ {
+ case SEG_BIG:
+ as_bad("%s number invalid. Absolute 0 assumed.",
+ exp.X_add_number > 0 ? "Bignum" : "Floating-Point");
+ S_SET_SEGMENT(symbolP, SEG_ABSOLUTE);
+#if defined(OBJ_AOUT) | defined(OBJ_BOUT)
+ ext ? S_SET_EXTERNAL(symbolP) :
+ S_CLEAR_EXTERNAL(symbolP);
+#endif /* OBJ_AOUT or OBJ_BOUT */
+ S_SET_VALUE(symbolP, 0);
+ symbolP->sy_frag = & zero_address_frag;
+ break;
+
+ case SEG_ABSENT:
+ as_warn("No expression: Using absolute 0");
+ S_SET_SEGMENT(symbolP, SEG_ABSOLUTE);
+#if defined(OBJ_AOUT) | defined(OBJ_BOUT)
+ ext ? S_SET_EXTERNAL(symbolP) :
+ S_CLEAR_EXTERNAL(symbolP);
+#endif /* OBJ_AOUT or OBJ_BOUT */
+ S_SET_VALUE(symbolP, 0);
+ symbolP->sy_frag = & zero_address_frag;
+ break;
+
+ case SEG_DIFFERENCE:
+ if (exp.X_add_symbol && exp.X_subtract_symbol
+ && (S_GET_SEGMENT(exp.X_add_symbol) ==
+ S_GET_SEGMENT(exp.X_subtract_symbol))) {
+ if (exp.X_add_symbol->sy_frag != exp.X_subtract_symbol->sy_frag) {
+ as_bad("Unknown expression: symbols %s and %s are in different frags.",
+ S_GET_NAME(exp.X_add_symbol), S_GET_NAME(exp.X_subtract_symbol));
+ need_pass_2++;
+ }
+ exp.X_add_number+=S_GET_VALUE(exp.X_add_symbol) -
+ S_GET_VALUE(exp.X_subtract_symbol);
+ } else
+ as_bad("Complex expression. Absolute segment assumed.");
+ case SEG_ABSOLUTE:
+ S_SET_SEGMENT(symbolP, SEG_ABSOLUTE);
+#if defined(OBJ_AOUT) | defined(OBJ_BOUT)
+ ext ? S_SET_EXTERNAL(symbolP) :
+ S_CLEAR_EXTERNAL(symbolP);
+#endif /* OBJ_AOUT or OBJ_BOUT */
+ S_SET_VALUE(symbolP, exp.X_add_number);
+ symbolP->sy_frag = & zero_address_frag;
+ break;
+
+ default:
+#ifdef MANY_SEGMENTS
+ S_SET_SEGMENT(symbolP, segment);
+#else
+ switch (segment) {
+ case SEG_DATA: S_SET_SEGMENT(symbolP, SEG_DATA); break;
+ case SEG_TEXT: S_SET_SEGMENT(symbolP, SEG_TEXT); break;
+ case SEG_BSS: S_SET_SEGMENT(symbolP, SEG_BSS); break;
+ default: as_fatal("failed sanity check.");
+ } /* switch on segment */
+#endif
+#if defined(OBJ_AOUT) | defined(OBJ_BOUT)
+ if (ext) {
+ S_SET_EXTERNAL(symbolP);
+ } else {
+ S_CLEAR_EXTERNAL(symbolP);
+ } /* if external */
+#endif /* OBJ_AOUT or OBJ_BOUT */
+
+ S_SET_VALUE(symbolP, exp.X_add_number + S_GET_VALUE(exp.X_add_symbol));
+ symbolP->sy_frag = exp.X_add_symbol->sy_frag;
+ break;
+
+ case SEG_PASS1: /* Not an error. Just try another pass. */
+ symbolP->sy_forward=exp.X_add_symbol;
+ as_bad("Unknown expression");
+ know(need_pass_2 == 1);
+ break;
+
+ case SEG_UNKNOWN:
+ symbolP->sy_forward=exp.X_add_symbol;
+ /* as_warn("unknown symbol"); */
+ /* need_pass_2 = 1; */
+ break;
+
+
+
+ }
+}
+
+/*
+ * cons()
+ *
+ * CONStruct more frag of .bytes, or .words etc.
+ * Should need_pass_2 be 1 then emit no frag(s).
+ * This understands EXPRESSIONS, as opposed to big_cons().
+ *
+ * Bug (?)
+ *
+ * This has a split personality. We use expression() to read the
+ * value. We can detect if the value won't fit in a byte or word.
+ * But we can't detect if expression() discarded significant digits
+ * in the case of a long. Not worth the crocks required to fix it.
+ */
+
+/* worker to do .byte etc statements */
+/* clobbers input_line_pointer, checks */
+/* end-of-line. */
+void cons(nbytes)
+register unsigned int nbytes; /* 1=.byte, 2=.word, 4=.long */
+{
+ register char c;
+ register long mask; /* High-order bits we will left-truncate, */
+ /* but includes sign bit also. */
+ register long get; /* what we get */
+ register long use; /* get after truncation. */
+ register long unmask; /* what bits we will store */
+ register char * p;
+ register segT segment;
+ expressionS exp;
+
+ /*
+ * Input_line_pointer->1st char after pseudo-op-code and could legally
+ * be a end-of-line. (Or, less legally an eof - which we cope with.)
+ */
+ /* JF << of >= number of bits in the object is undefined. In particular
+ SPARC (Sun 4) has problems */
+
+ if (nbytes >= sizeof(long)) {
+ mask = 0;
+ } else {
+ mask = ~0 << (BITS_PER_CHAR * nbytes); /* Don't store these bits. */
+ } /* bigger than a long */
+
+ unmask = ~mask; /* Do store these bits. */
+
+#ifdef NEVER
+ "Do this mod if you want every overflow check to assume SIGNED 2's complement data.";
+ mask = ~ (unmask >> 1); /* Includes sign bit now. */
+#endif
+
+ /*
+ * The following awkward logic is to parse ZERO or more expressions,
+ * comma seperated. Recall an expression includes its leading &
+ * trailing blanks. We fake a leading ',' if there is (supposed to
+ * be) a 1st expression, and keep demanding 1 expression for each ','.
+ */
+ if (is_it_end_of_statement()) {
+ c = 0; /* Skip loop. */
+ input_line_pointer++; /* Matches end-of-loop 'correction'. */
+ } else {
+ c = ',';
+ } /* if the end else fake it */
+
+ /* Do loop. */
+ while (c == ',') {
+#ifdef WANT_BITFIELDS
+ unsigned int bits_available = BITS_PER_CHAR * nbytes;
+ /* used for error messages and rescanning */
+ char *hold = input_line_pointer;
+#endif /* WANT_BITFIELDS */
+
+ /* At least scan over the expression. */
+ segment = expression(&exp);
+
+#ifdef WANT_BITFIELDS
+ /* Some other assemblers, (eg, asm960), allow
+ bitfields after ".byte" as w:x,y:z, where w and
+ y are bitwidths and x and y are values. They
+ then pack them all together. We do a little
+ better in that we allow them in words, longs,
+ etc. and we'll pack them in target byte order
+ for you.
+
+ The rules are: pack least significat bit first,
+ if a field doesn't entirely fit, put it in the
+ next unit. Overflowing the bitfield is
+ explicitly *not* even a warning. The bitwidth
+ should be considered a "mask".
+
+ FIXME-SOMEDAY: If this is considered generally
+ useful, this logic should probably be reworked.
+ xoxorich. */
+
+ if (*input_line_pointer == ':') { /* bitfields */
+ long value = 0;
+
+ for (;;) {
+ unsigned long width;
+
+ if (*input_line_pointer != ':') {
+ input_line_pointer = hold;
+ break;
+ } /* next piece is not a bitfield */
+
+ /* In the general case, we can't allow
+ full expressions with symbol
+ differences and such. The relocation
+ entries for symbols not defined in this
+ assembly would require arbitrary field
+ widths, positions, and masks which most
+ of our current object formats don't
+ support.
+
+ In the specific case where a symbol
+ *is* defined in this assembly, we
+ *could* build fixups and track it, but
+ this could lead to confusion for the
+ backends. I'm lazy. I'll take any
+ SEG_ABSOLUTE. I think that means that
+ you can use a previous .set or
+ .equ type symbol. xoxorich. */
+
+ if (segment == SEG_ABSENT) {
+ as_warn("Using a bit field width of zero.");
+ exp.X_add_number = 0;
+ segment = SEG_ABSOLUTE;
+ } /* implied zero width bitfield */
+
+ if (segment != SEG_ABSOLUTE) {
+ *input_line_pointer = '\0';
+ as_bad("Field width \"%s\" too complex for a bitfield.\n", hold);
+ *input_line_pointer = ':';
+ demand_empty_rest_of_line();
+ return;
+ } /* too complex */
+
+ if ((width = exp.X_add_number) > (BITS_PER_CHAR * nbytes)) {
+ as_warn("Field width %d too big to fit in %d bytes: truncated to %d bits.",
+ width, nbytes, (BITS_PER_CHAR * nbytes));
+ width = BITS_PER_CHAR * nbytes;
+ } /* too big */
+
+ if (width > bits_available) {
+ /* FIXME-SOMEDAY: backing up and
+ reparsing is wasteful */
+ input_line_pointer = hold;
+ exp.X_add_number = value;
+ break;
+ } /* won't fit */
+
+ hold = ++input_line_pointer; /* skip ':' */
+
+ if ((segment = expression(&exp)) != SEG_ABSOLUTE) {
+ char cache = *input_line_pointer;
+
+ *input_line_pointer = '\0';
+ as_bad("Field value \"%s\" too complex for a bitfield.\n", hold);
+ *input_line_pointer = cache;
+ demand_empty_rest_of_line();
+ return;
+ } /* too complex */
+
+ value |= (~(-1 << width) & exp.X_add_number)
+ << ((BITS_PER_CHAR * nbytes) - bits_available);
+
+ if ((bits_available -= width) == 0
+ || is_it_end_of_statement()
+ || *input_line_pointer != ',') {
+ break;
+ } /* all the bitfields we're gonna get */
+
+ hold = ++input_line_pointer;
+ segment = expression(&exp);
+ } /* forever loop */
+
+ exp.X_add_number = value;
+ segment = SEG_ABSOLUTE;
+ } /* if looks like a bitfield */
+#endif /* WANT_BITFIELDS */
+
+ if (!need_pass_2) { /* Still worthwhile making frags. */
+
+ /* Don't call this if we are going to junk this pass anyway! */
+ know(segment != SEG_PASS1);
+
+ if (segment == SEG_DIFFERENCE && exp.X_add_symbol == NULL) {
+ as_bad("Subtracting symbol \"%s\"(segment\"%s\") is too hard. Absolute segment assumed.",
+ S_GET_NAME(exp.X_subtract_symbol),
+ segment_name(S_GET_SEGMENT(exp.X_subtract_symbol)));
+ segment = SEG_ABSOLUTE;
+ /* Leave exp.X_add_number alone. */
+ }
+
+ p = frag_more(nbytes);
+
+ switch (segment) {
+ case SEG_BIG:
+ as_bad("%s number invalid. Absolute 0 assumed.",
+ exp.X_add_number > 0 ? "Bignum" : "Floating-Point");
+ md_number_to_chars (p, (long)0, nbytes);
+ break;
+
+ case SEG_ABSENT:
+ as_warn("0 assumed for missing expression");
+ exp.X_add_number = 0;
+ know(exp.X_add_symbol == NULL);
+ /* fall into SEG_ABSOLUTE */
+ case SEG_ABSOLUTE:
+ get = exp.X_add_number;
+ use = get & unmask;
+ if ((get & mask) && (get & mask) != mask)
+ { /* Leading bits contain both 0s & 1s. */
+ as_warn("Value 0x%x truncated to 0x%x.", get, use);
+ }
+ md_number_to_chars (p, use, nbytes); /* put bytes in right order. */
+ break;
+
+ case SEG_DIFFERENCE:
+#ifndef WORKING_DOT_WORD
+ if (nbytes == 2) {
+ struct broken_word *x;
+
+ x = (struct broken_word *) xmalloc(sizeof(struct broken_word));
+ x->next_broken_word = broken_words;
+ broken_words = x;
+ x->frag = frag_now;
+ x->word_goes_here = p;
+ x->dispfrag = 0;
+ x->add = exp.X_add_symbol;
+ x->sub = exp.X_subtract_symbol;
+ x->addnum = exp.X_add_number;
+ x->added = 0;
+ new_broken_words++;
+ break;
+ }
+ /* Else Fall through into... */
+#endif
+ default:
+ case SEG_UNKNOWN:
+#ifdef TC_NS32K
+ fix_new_ns32k(frag_now, p - frag_now->fr_literal, nbytes,
+ exp.X_add_symbol, exp.X_subtract_symbol,
+ exp.X_add_number, 0, 0, 2, 0, 0, RELOC_32);
+#else
+#ifdef PIC
+ fix_new(frag_now, p - frag_now->fr_literal, nbytes,
+ exp.X_add_symbol, exp.X_subtract_symbol,
+ exp.X_add_number, 0, RELOC_32,
+ exp.X_got_symbol);
+#else
+ fix_new(frag_now, p - frag_now->fr_literal, nbytes,
+ exp.X_add_symbol, exp.X_subtract_symbol,
+ exp.X_add_number, 0, RELOC_32);
+#endif
+#endif /* TC_NS32K */
+ break;
+ } /* switch (segment) */
+ } /* if (!need_pass_2) */
+ c = *input_line_pointer++;
+ } /* while (c == ',') */
+ input_line_pointer--; /* Put terminator back into stream. */
+ demand_empty_rest_of_line();
+} /* cons() */
+
+/*
+ * big_cons()
+ *
+ * CONStruct more frag(s) of .quads, or .octa etc.
+ * Makes 0 or more new frags.
+ * If need_pass_2 == 1, generate no frag.
+ * This understands only bignums, not expressions. Cons() understands
+ * expressions.
+ *
+ * Constants recognised are '0...'(octal) '0x...'(hex) '...'(decimal).
+ *
+ * This creates objects with struct obstack_control objs, destroying
+ * any context objs held about a partially completed object. Beware!
+ *
+ *
+ * I think it sucks to have 2 different types of integers, with 2
+ * routines to read them, store them etc.
+ * It would be nicer to permit bignums in expressions and only
+ * complain if the result overflowed. However, due to "efficiency"...
+ */
+/* worker to do .quad etc statements */
+/* clobbers input_line_pointer, checks */
+/* end-of-line. */
+/* 8=.quad 16=.octa ... */
+
+void big_cons(nbytes)
+register int nbytes;
+{
+ register char c; /* input_line_pointer->c. */
+ register int radix;
+ register long length; /* Number of chars in an object. */
+ register int digit; /* Value of 1 digit. */
+ register int carry; /* For multi-precision arithmetic. */
+ register int work; /* For multi-precision arithmetic. */
+ register char * p; /* For multi-precision arithmetic. */
+
+ extern const char hex_value[]; /* In hex_value.c. */
+
+ /*
+ * The following awkward logic is to parse ZERO or more strings,
+ * comma seperated. Recall an expression includes its leading &
+ * trailing blanks. We fake a leading ',' if there is (supposed to
+ * be) a 1st expression, and keep demanding 1 expression for each ','.
+ */
+ if (is_it_end_of_statement())
+ {
+ c = 0; /* Skip loop. */
+ }
+ else
+ {
+ c = ','; /* Do loop. */
+ -- input_line_pointer;
+ }
+ while (c == ',')
+ {
+ ++ input_line_pointer;
+ SKIP_WHITESPACE();
+ c = * input_line_pointer;
+ /* C contains 1st non-blank character of what we hope is a number. */
+ if (c == '0')
+ {
+ c = * ++ input_line_pointer;
+ if (c == 'x' || c == 'X')
+ {
+ c = * ++ input_line_pointer;
+ radix = 16;
+ }
+ else
+ {
+ radix = 8;
+ }
+ }
+ else
+ {
+ radix = 10;
+ }
+ /*
+ * This feature (?) is here to stop people worrying about
+ * mysterious zero constants: which is what they get when
+ * they completely omit digits.
+ */
+ if (hex_value[c] >= radix) {
+ as_bad("Missing digits. 0 assumed.");
+ }
+ bignum_high = bignum_low - 1; /* Start constant with 0 chars. */
+ for (; (digit = hex_value[c]) < radix; c = *++input_line_pointer)
+ {
+ /* Multiply existing number by radix, then add digit. */
+ carry = digit;
+ for (p=bignum_low; p <= bignum_high; p++)
+ {
+ work = (*p & MASK_CHAR) * radix + carry;
+ *p = work & MASK_CHAR;
+ carry = work >> BITS_PER_CHAR;
+ }
+ if (carry)
+ {
+ grow_bignum();
+ * bignum_high = carry & MASK_CHAR;
+ know((carry & ~ MASK_CHAR) == 0);
+ }
+ }
+ length = bignum_high - bignum_low + 1;
+ if (length > nbytes)
+ {
+ as_warn("Most significant bits truncated in integer constant.");
+ }
+ else
+ {
+ register long leading_zeroes;
+
+ for (leading_zeroes = nbytes - length;
+ leading_zeroes;
+ leading_zeroes --)
+ {
+ grow_bignum();
+ * bignum_high = 0;
+ }
+ }
+ if (! need_pass_2)
+ {
+ p = frag_more (nbytes);
+ memcpy(p, bignum_low, (int) nbytes);
+ }
+ /* C contains character after number. */
+ SKIP_WHITESPACE();
+ c = *input_line_pointer;
+ /* C contains 1st non-blank character after number. */
+ }
+ demand_empty_rest_of_line();
+} /* big_cons() */
+
+/* Extend bignum by 1 char. */
+static void grow_bignum() {
+ register long length;
+
+ bignum_high ++;
+ if (bignum_high >= bignum_limit)
+ {
+ length = bignum_limit - bignum_low;
+ bignum_low = xrealloc(bignum_low, length + length);
+ bignum_high = bignum_low + length;
+ bignum_limit = bignum_low + length + length;
+ }
+} /* grow_bignum(); */
+
+/*
+ * float_cons()
+ *
+ * CONStruct some more frag chars of .floats .ffloats etc.
+ * Makes 0 or more new frags.
+ * If need_pass_2 == 1, no frags are emitted.
+ * This understands only floating literals, not expressions. Sorry.
+ *
+ * A floating constant is defined by atof_generic(), except it is preceded
+ * by 0d 0f 0g or 0h. After observing the STRANGE way my BSD AS does its
+ * reading, I decided to be incompatible. This always tries to give you
+ * rounded bits to the precision of the pseudo-op. Former AS did premature
+ * truncatation, restored noisy bits instead of trailing 0s AND gave you
+ * a choice of 2 flavours of noise according to which of 2 floating-point
+ * scanners you directed AS to use.
+ *
+ * In: input_line_pointer->whitespace before, or '0' of flonum.
+ *
+ */
+
+void /* JF was static, but can't be if VAX.C is goning to use it */
+ float_cons(float_type) /* Worker to do .float etc statements. */
+/* Clobbers input_line-pointer, checks end-of-line. */
+register int float_type; /* 'f':.ffloat ... 'F':.float ... */
+{
+ register char * p;
+ register char c;
+ int length; /* Number of chars in an object. */
+ register char * err; /* Error from scanning floating literal. */
+ char temp[MAXIMUM_NUMBER_OF_CHARS_FOR_FLOAT];
+
+ /*
+ * The following awkward logic is to parse ZERO or more strings,
+ * comma seperated. Recall an expression includes its leading &
+ * trailing blanks. We fake a leading ',' if there is (supposed to
+ * be) a 1st expression, and keep demanding 1 expression for each ','.
+ */
+ if (is_it_end_of_statement())
+ {
+ c = 0; /* Skip loop. */
+ ++ input_line_pointer; /*->past termintor. */
+ }
+ else
+ {
+ c = ','; /* Do loop. */
+ }
+ while (c == ',') {
+ /* input_line_pointer->1st char of a flonum (we hope!). */
+ SKIP_WHITESPACE();
+ /* Skip any 0{letter} that may be present. Don't even check if the
+ * letter is legal. Someone may invent a "z" format and this routine
+ * has no use for such information. Lusers beware: you get
+ * diagnostics if your input is ill-conditioned.
+ */
+
+ if (input_line_pointer[0] == '0' && isalpha(input_line_pointer[1]))
+ input_line_pointer+=2;
+
+ err = md_atof (float_type, temp, &length);
+ know(length <= MAXIMUM_NUMBER_OF_CHARS_FOR_FLOAT);
+ know(length > 0);
+ if (* err) {
+ as_bad("Bad floating literal: %s", err);
+ ignore_rest_of_line();
+ /* Input_line_pointer->just after end-of-line. */
+ c = 0; /* Break out of loop. */
+ } else {
+ if (! need_pass_2) {
+ p = frag_more (length);
+ memcpy(p, temp, length);
+ }
+ SKIP_WHITESPACE();
+ c = *input_line_pointer++;
+ /* C contains 1st non-white character after number. */
+ /* input_line_pointer->just after terminator (c). */
+ }
+ }
+ --input_line_pointer; /*->terminator (is not ','). */
+ demand_empty_rest_of_line();
+} /* float_cons() */
+
+/*
+ * stringer() Worker to do .ascii etc statements. Checks end-of-line.
+ *
+ * We read 0 or more ',' seperated, double-quoted strings.
+ *
+ * Caller should have checked need_pass_2 is FALSE because we don't check it.
+ */
+
+void stringer(append_zero)
+int append_zero; /* 0: don't append '\0', else 1 */
+{
+ unsigned int c;
+
+ /*
+ * The following awkward logic is to parse ZERO or more strings,
+ * comma seperated. Recall a string expression includes spaces
+ * before the opening '\"' and spaces after the closing '\"'.
+ * We fake a leading ',' if there is (supposed to be)
+ * a 1st, expression. We keep demanding expressions for each
+ * ','.
+ */
+ if (is_it_end_of_statement()) {
+ c = 0; /* Skip loop. */
+ ++ input_line_pointer; /* Compensate for end of loop. */
+ } else {
+ c = ','; /* Do loop. */
+ }
+
+ while (c == ',' || c == '<' || c == '"' || ('0' <= c && c <= '9')) {
+ int i;
+
+ SKIP_WHITESPACE();
+ switch (*input_line_pointer) {
+ case '\"':
+ ++input_line_pointer; /* ->1st char of string. */
+ while (is_a_char(c = next_char_of_string())) {
+ FRAG_APPEND_1_CHAR(c);
+ }
+ if (append_zero) {
+ FRAG_APPEND_1_CHAR(0);
+ }
+ know(input_line_pointer[-1] == '\"');
+ break;
+
+ case '<':
+ input_line_pointer++;
+ c = get_single_number();
+ FRAG_APPEND_1_CHAR(c);
+ if (*input_line_pointer != '>') {
+ as_bad("Expected <nn>");
+ }
+ input_line_pointer++;
+ break;
+
+ case ',':
+ input_line_pointer++;
+ break;
+
+ default:
+ i = get_absolute_expression();
+ FRAG_APPEND_1_CHAR(i);
+ break;
+ } /* switch on next char */
+
+ SKIP_WHITESPACE();
+ c = *input_line_pointer;
+ }
+
+ demand_empty_rest_of_line();
+} /* stringer() */
+
+/* FIXME-SOMEDAY: I had trouble here on characters with the
+ high bits set. We'll probably also have trouble with
+ multibyte chars, wide chars, etc. Also be careful about
+ returning values bigger than 1 byte. xoxorich. */
+
+unsigned int next_char_of_string() {
+ register unsigned int c;
+
+ c = *input_line_pointer++ & CHAR_MASK;
+ switch (c) {
+ case '\"':
+ c = NOT_A_CHAR;
+ break;
+
+ case '\\':
+ switch (c = *input_line_pointer++) {
+ case 'b':
+ c = '\b';
+ break;
+
+ case 'f':
+ c = '\f';
+ break;
+
+ case 'n':
+ c = '\n';
+ break;
+
+ case 'r':
+ c = '\r';
+ break;
+
+ case 't':
+ c = '\t';
+ break;
+
+#ifdef BACKSLASH_V
+ case 'v':
+ c = '\013';
+ break;
+#endif
+
+ case '\\':
+ case '"':
+ break; /* As itself. */
+
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9': {
+ long number;
+
+ for (number = 0; isdigit(c); c = *input_line_pointer++) {
+ number = number * 8 + c - '0';
+ }
+ c = number & 0xff;
+ }
+ --input_line_pointer;
+ break;
+
+ case '\n':
+ /* To be compatible with BSD 4.2 as: give the luser a linefeed!! */
+ as_warn("Unterminated string: Newline inserted.");
+ c = '\n';
+ break;
+
+ default:
+
+#ifdef ONLY_STANDARD_ESCAPES
+ as_bad("Bad escaped character in string, '?' assumed");
+ c = '?';
+#endif /* ONLY_STANDARD_ESCAPES */
+
+ break;
+ } /* switch on escaped char */
+ break;
+
+ default:
+ break;
+ } /* switch on char */
+ return(c);
+} /* next_char_of_string() */
+
+static segT
+ get_segmented_expression (expP)
+register expressionS * expP;
+{
+ register segT retval;
+
+ if ((retval = expression(expP)) == SEG_PASS1 || retval == SEG_ABSENT || retval == SEG_BIG)
+ {
+ as_bad("Expected address expression: absolute 0 assumed");
+ retval = expP->X_seg = SEG_ABSOLUTE;
+ expP->X_add_number = 0;
+ expP->X_add_symbol = expP->X_subtract_symbol = 0;
+ }
+ return (retval); /* SEG_ ABSOLUTE,UNKNOWN,DATA,TEXT,BSS */
+}
+
+static segT get_known_segmented_expression(expP)
+register expressionS *expP;
+{
+ register segT retval;
+ register char * name1;
+ register char * name2;
+
+ if ((retval = get_segmented_expression (expP)) == SEG_UNKNOWN)
+ {
+ name1 = expP->X_add_symbol ? S_GET_NAME(expP->X_add_symbol) : "";
+ name2 = expP->X_subtract_symbol ?
+ S_GET_NAME(expP->X_subtract_symbol) :
+ "";
+ if (name1 && name2)
+ {
+ as_warn("Symbols \"%s\" \"%s\" are undefined: absolute 0 assumed.",
+ name1, name2);
+ }
+ else
+ {
+ as_warn("Symbol \"%s\" undefined: absolute 0 assumed.",
+ name1 ? name1 : name2);
+ }
+ retval = expP->X_seg = SEG_ABSOLUTE;
+ expP->X_add_number = 0;
+ expP->X_add_symbol = expP->X_subtract_symbol = NULL;
+ }
+#ifndef MANY_SEGMENTS
+ know(retval == SEG_ABSOLUTE || retval == SEG_DATA || retval == SEG_TEXT || retval == SEG_BSS || retval == SEG_DIFFERENCE);
+#endif
+ return (retval);
+
+} /* get_known_segmented_expression() */
+
+
+
+/* static */ long /* JF was static, but can't be if the MD pseudos are to use it */
+ get_absolute_expression()
+{
+ expressionS exp;
+ register segT s;
+
+ if ((s = expression(&exp)) != SEG_ABSOLUTE) {
+ if (s != SEG_ABSENT) {
+ as_bad("Bad Absolute Expression, absolute 0 assumed.");
+ }
+ exp.X_add_number = 0;
+ }
+ return(exp.X_add_number);
+} /* get_absolute_expression() */
+
+char /* return terminator */
+ get_absolute_expression_and_terminator(val_pointer)
+long * val_pointer; /* return value of expression */
+{
+ *val_pointer = get_absolute_expression();
+ return (*input_line_pointer++);
+}
+
+/*
+ * demand_copy_C_string()
+ *
+ * Like demand_copy_string, but return NULL if the string contains any '\0's.
+ * Give a warning if that happens.
+ */
+char *
+ demand_copy_C_string (len_pointer)
+int *len_pointer;
+{
+ register char *s;
+
+ if ((s = demand_copy_string(len_pointer)) != 0) {
+ register int len;
+
+ for (len = *len_pointer;
+ len > 0;
+ len--) {
+ if (*s == 0) {
+ s = 0;
+ len = 1;
+ *len_pointer = 0;
+ as_bad("This string may not contain \'\\0\'");
+ }
+ }
+ }
+ return(s);
+}
+
+/*
+ * demand_copy_string()
+ *
+ * Demand string, but return a safe (=private) copy of the string.
+ * Return NULL if we can't read a string here.
+ */
+static char *demand_copy_string(lenP)
+int *lenP;
+{
+ register unsigned int c;
+ register int len;
+ char *retval;
+
+ len = 0;
+ SKIP_WHITESPACE();
+ if (*input_line_pointer == '\"') {
+ input_line_pointer++; /* Skip opening quote. */
+
+ while (is_a_char(c = next_char_of_string())) {
+ obstack_1grow(&notes, c);
+ len ++;
+ }
+ /* JF this next line is so demand_copy_C_string will return a null
+ termanated string. */
+ obstack_1grow(&notes,'\0');
+ retval=obstack_finish(&notes);
+ } else {
+ as_warn("Missing string");
+ retval = NULL;
+ ignore_rest_of_line();
+ }
+ *lenP = len;
+ return(retval);
+} /* demand_copy_string() */
+
+/*
+ * is_it_end_of_statement()
+ *
+ * In: Input_line_pointer->next character.
+ *
+ * Do: Skip input_line_pointer over all whitespace.
+ *
+ * Out: 1 if input_line_pointer->end-of-line.
+ */
+int is_it_end_of_statement() {
+ SKIP_WHITESPACE();
+ return(is_end_of_line[*input_line_pointer]);
+} /* is_it_end_of_statement() */
+
+void equals(sym_name)
+char *sym_name;
+{
+ register symbolS *symbolP; /* symbol we are working with */
+
+ input_line_pointer++;
+ if (*input_line_pointer == '=')
+ input_line_pointer++;
+
+ while (*input_line_pointer == ' ' || *input_line_pointer == '\t')
+ input_line_pointer++;
+
+ if (sym_name[0] == '.' && sym_name[1] == '\0') {
+ /* Turn '. = mumble' into a .org mumble */
+ register segT segment;
+ expressionS exp;
+ register char *p;
+
+ segment = get_known_segmented_expression(& exp);
+ if (! need_pass_2) {
+ if (segment != now_seg && segment != SEG_ABSOLUTE)
+ as_warn("Illegal segment \"%s\". Segment \"%s\" assumed.",
+ segment_name(segment),
+ segment_name(now_seg));
+ p = frag_var(rs_org, 1, 1, (relax_substateT)0, exp.X_add_symbol,
+ exp.X_add_number, (char *)0);
+ * p = 0;
+ } /* if (ok to make frag) */
+ } else {
+ symbolP=symbol_find_or_make(sym_name);
+ pseudo_set(symbolP);
+ }
+} /* equals() */
+
+/* .include -- include a file at this point. */
+
+/* ARGSUSED */
+void s_include(arg)
+int arg;
+{
+ char *newbuf;
+ char *filename;
+ int i;
+ FILE *try;
+ char *path;
+
+ filename = demand_copy_string(&i);
+ demand_empty_rest_of_line();
+ path = xmalloc(i + include_dir_maxlen + 5 /* slop */);
+ for (i = 0; i < include_dir_count; i++) {
+ strcpy(path, include_dirs[i]);
+ strcat(path, "/");
+ strcat(path, filename);
+ if (0 != (try = fopen(path, "r")))
+ {
+ fclose (try);
+ goto gotit;
+ }
+ }
+ free(path);
+ path = filename;
+ gotit:
+ /* malloc Storage leak when file is found on path. FIXME-SOMEDAY. */
+ newbuf = input_scrub_include_file (path, input_line_pointer);
+ buffer_limit = input_scrub_next_buffer (&input_line_pointer);
+} /* s_include() */
+
+void add_include_dir(path)
+char *path;
+{
+ int i;
+
+ if (include_dir_count == 0)
+ {
+ include_dirs = (char **)xmalloc (2 * sizeof (*include_dirs));
+ include_dirs[0] = "."; /* Current dir */
+ include_dir_count = 2;
+ }
+ else
+ {
+ include_dir_count++;
+ include_dirs = (char **) realloc(include_dirs,
+ include_dir_count*sizeof (*include_dirs));
+ }
+
+ include_dirs[include_dir_count-1] = path; /* New one */
+
+ i = strlen (path);
+ if (i > include_dir_maxlen)
+ include_dir_maxlen = i;
+} /* add_include_dir() */
+
+void s_ignore(arg)
+int arg;
+{
+ while (!is_end_of_line[*input_line_pointer]) {
+ ++input_line_pointer;
+ }
+ ++input_line_pointer;
+
+ return;
+} /* s_ignore() */
+
+/*
+ * Local Variables:
+ * comment-column: 0
+ * fill-column: 131
+ * End:
+ */
+
+/* end of read.c */
diff --git a/gnu/usr.bin/as/read.h b/gnu/usr.bin/as/read.h
new file mode 100644
index 0000000..9b29582
--- /dev/null
+++ b/gnu/usr.bin/as/read.h
@@ -0,0 +1,156 @@
+/* read.h - of read.c
+
+ Copyright (C) 1986, 1990, 1992 Free Software Foundation, Inc.
+
+ This file is part of GAS, the GNU Assembler.
+
+ GAS is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GAS is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GAS; see the file COPYING. If not, write to
+ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+/*
+ * $Id: read.h,v 1.4 1994/12/23 22:36:17 nate Exp $
+ */
+
+
+extern char *input_line_pointer; /* -> char we are parsing now. */
+
+#define PERMIT_WHITESPACE /* Define to make whitespace be allowed in */
+/* many syntactically unnecessary places. */
+/* Normally undefined. For compatibility */
+/* with ancient GNU cc. */
+/* #undef PERMIT_WHITESPACE */
+
+#ifdef PERMIT_WHITESPACE
+#define SKIP_WHITESPACE() {if (* input_line_pointer == ' ') ++ input_line_pointer;}
+#else
+#define SKIP_WHITESPACE() know(*input_line_pointer != ' ' )
+#endif
+
+
+#define LEX_NAME (1) /* may continue a name */
+#define LEX_BEGIN_NAME (2) /* may begin a name */
+
+#define is_name_beginner(c) ( lex_type[c] & LEX_BEGIN_NAME )
+#define is_part_of_name(c) ( lex_type[c] & LEX_NAME )
+
+#ifndef is_a_char
+#define CHAR_MASK (0xff)
+#define NOT_A_CHAR (CHAR_MASK+1)
+#define is_a_char(c) (((unsigned)(c)) <= CHAR_MASK)
+#endif /* is_a_char() */
+
+#ifdef PIC
+/* We change some of the entries in lex_type on some archs */
+extern char lex_type[];
+#else
+extern const char lex_type[];
+#endif
+extern char is_end_of_line[];
+
+/* These are initialized by the CPU specific target files (tc-*.c). */
+extern const char comment_chars[];
+extern const char line_comment_chars[];
+extern const char line_separator_chars[];
+
+#if __STDC__ == 1
+
+char *demand_copy_C_string(int *len_pointer);
+char get_absolute_expression_and_terminator(long *val_pointer);
+long get_absolute_expression(void);
+void add_include_dir(char *path);
+void big_cons(int nbytes);
+void cons(unsigned int nbytes);
+void demand_empty_rest_of_line(void);
+void equals(char *sym_name);
+void float_cons(int float_type);
+void ignore_rest_of_line(void);
+void pseudo_set(symbolS *symbolP);
+void read_a_source_file(char *name);
+void read_begin(void);
+void s_abort(void);
+void s_align_bytes(int arg);
+void s_align_ptwo(void);
+void s_app_file(int);
+void s_app_line(int);
+void s_comm(void);
+void s_data(void);
+void s_else(int arg);
+void s_end(int arg);
+void s_endif(int arg);
+void s_fill(void);
+void s_globl(void);
+void s_if(int arg);
+void s_ifdef(int arg);
+void s_ifeqs(int arg);
+void s_ignore(int arg);
+void s_include(int arg);
+void s_lcomm(int needs_align);
+void s_lsym(void);
+void s_org(void);
+void s_set(void);
+void s_size(void);
+void s_space(void);
+void s_text(void);
+void s_type(void);
+
+#else /* not __STDC__ */
+
+char *demand_copy_C_string();
+char get_absolute_expression_and_terminator();
+long get_absolute_expression();
+void add_include_dir();
+void big_cons();
+void cons();
+void demand_empty_rest_of_line();
+void equals();
+void float_cons();
+void ignore_rest_of_line();
+void pseudo_set();
+void read_a_source_file();
+void read_begin();
+void s_abort();
+void s_align_bytes();
+void s_align_ptwo();
+void s_app_file();
+void s_app_line();
+void s_comm();
+void s_data();
+void s_else();
+void s_end();
+void s_endif();
+void s_fill();
+void s_globl();
+void s_if();
+void s_ifdef();
+void s_ifeqs();
+void s_ignore();
+void s_include();
+void s_lcomm();
+void s_lsym();
+void s_org();
+void s_set();
+void s_size();
+void s_space();
+void s_text();
+void s_type();
+
+#endif /* not __STDC__ */
+
+/*
+ * Local Variables:
+ * comment-column: 0
+ * fill-column: 131
+ * End:
+ */
+
+/* end of read.h */
diff --git a/gnu/usr.bin/as/struc-symbol.h b/gnu/usr.bin/as/struc-symbol.h
new file mode 100644
index 0000000..5c405e4
--- /dev/null
+++ b/gnu/usr.bin/as/struc-symbol.h
@@ -0,0 +1,130 @@
+/* struct_symbol.h - Internal symbol structure
+ Copyright (C) 1987, 1992 Free Software Foundation, Inc.
+
+ This file is part of GAS, the GNU Assembler.
+
+ GAS is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GAS is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ oYou should have received a copy of the GNU General Public License
+ along with GAS; see the file COPYING. If not, write to
+ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+/*
+ * $Id: struc-symbol.h,v 1.4 1994/12/23 22:36:20 nate Exp $
+ */
+
+
+#ifndef __struc_symbol_h__
+#define __struc_symbol_h__
+
+struct symbol /* our version of an nlist node */
+{
+ obj_symbol_type sy_symbol; /* what we write in .o file (if permitted) */
+ unsigned long sy_name_offset; /* 4-origin position of sy_name in symbols */
+ /* part of object file. */
+ /* 0 for (nameless) .stabd symbols. */
+ /* Not used until write_object_file() time. */
+ long sy_number; /* 24 bit symbol number. */
+ /* Symbol numbers start at 0 and are */
+ /* unsigned. */
+ struct symbol *sy_next; /* forward chain, or NULL */
+#ifdef SYMBOLS_NEED_BACKPOINTERS
+ struct symbol *sy_previous; /* backward chain, or NULL */
+#endif /* SYMBOLS_NEED_BACKPOINTERS */
+ struct frag *sy_frag; /* NULL or -> frag this symbol attaches to. */
+ struct symbol *sy_forward; /* value is really that of this other symbol */
+ /* We will probably want to add a sy_segment here soon. */
+
+#ifdef PIC
+ /* Force symbol into symbol table, even if local */
+ int sy_forceout;
+#endif
+ /* Size of symbol as given by the .size directive */
+ void *sy_sizexp; /* (expressionS *) */
+
+ /* Auxiliary type information as given by the .type directive */
+ int sy_aux;
+#define AUX_OBJECT 1
+#define AUX_FUNC 2
+};
+
+typedef struct symbol symbolS;
+
+#ifdef PIC
+symbolS *GOT_symbol; /* Pre-defined "__GLOBAL_OFFSET_TABLE" */
+int got_referenced;
+#endif
+
+typedef unsigned valueT; /* The type of n_value. Helps casting. */
+
+#ifndef WORKING_DOT_WORD
+struct broken_word {
+ struct broken_word *next_broken_word;/* One of these strucs per .word x-y */
+ fragS *frag; /* Which frag its in */
+ char *word_goes_here;/* Where in the frag it is */
+ fragS *dispfrag; /* where to add the break */
+ symbolS *add; /* symbol_x */
+ symbolS *sub; /* - symbol_y */
+ long addnum; /* + addnum */
+ int added; /* nasty thing happend yet? */
+ /* 1: added and has a long-jump */
+ /* 2: added but uses someone elses long-jump */
+ struct broken_word *use_jump; /* points to broken_word with a similar
+ long-jump */
+};
+extern struct broken_word *broken_words;
+#endif /* ndef WORKING_DOT_WORD */
+
+#define SEGMENT_TO_SYMBOL_TYPE(seg) (seg_N_TYPE[(int) (seg)])
+extern const short seg_N_TYPE[]; /* subseg.c */
+
+#ifdef SYMBOLS_NEED_BACKPOINTERS
+#if __STDC__ == 1
+
+void symbol_clear_list_pointers(symbolS *symbolP);
+void symbol_insert(symbolS *addme, symbolS *target, symbolS **rootP, symbolS **lastP);
+void symbol_remove(symbolS *symbolP, symbolS **rootP, symbolS **lastP);
+void verify_symbol_chain(symbolS *rootP, symbolS *lastP);
+
+#else /* not __STDC__ */
+
+void symbol_clear_list_pointers();
+void symbol_insert();
+void symbol_remove();
+void verify_symbol_chain();
+
+#endif /* not __STDC__ */
+
+#define symbol_previous(s) ((s)->sy_previous)
+
+#else /* SYMBOLS_NEED_BACKPOINTERS */
+
+#define symbol_clear_list_pointers(clearme) {clearme->sy_next = NULL;}
+
+#endif /* SYMBOLS_NEED_BACKPOINTERS */
+
+#if __STDC__ == 1
+void symbol_append(symbolS *addme, symbolS *target, symbolS **rootP, symbolS **lastP);
+#else /* not __STDC__ */
+void symbol_append();
+#endif /* not __STDC__ */
+
+#define symbol_next(s) ((s)->sy_next)
+
+#endif /* __struc_symbol_h__ */
+
+/*
+ * Local Variables:
+ * comment-column: 0
+ * fill-column: 131
+ * End:
+ */
+
+/* end of struc-symbol.h */
diff --git a/gnu/usr.bin/as/subsegs.c b/gnu/usr.bin/as/subsegs.c
new file mode 100644
index 0000000..2089809
--- /dev/null
+++ b/gnu/usr.bin/as/subsegs.c
@@ -0,0 +1,311 @@
+/* subsegs.c - subsegments -
+ Copyright (C) 1987, 1990, 1991, 1992 Free Software Foundation, Inc.
+
+ This file is part of GAS, the GNU Assembler.
+
+ GAS is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GAS is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GAS; see the file COPYING. If not, write to
+ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/*
+ * Segments & sub-segments.
+ */
+
+#ifndef lint
+static char rcsid[] = "$Id: subsegs.c,v 1.3 1995/03/02 20:29:18 nate Exp $";
+#endif
+
+#include "as.h"
+
+#include "subsegs.h"
+#include "obstack.h"
+
+#ifdef MANY_SEGMENTS
+segment_info_type segment_info[SEG_MAXIMUM_ORDINAL];
+
+frchainS* frchain_root,
+ * frchain_now;
+
+#else
+frchainS* frchain_root,
+ * frchain_now, /* Commented in "subsegs.h". */
+ * data0_frchainP;
+
+#endif
+char * const /* in: segT out: char* */
+ seg_name[] = {
+ "absolute",
+#ifdef MANY_SEGMENTS
+ "e0","e1","e2","e3","e4","e5","e6","e7","e8","e9",
+#else
+ "text",
+ "data",
+ "bss",
+#endif
+ "unknown",
+ "absent",
+ "pass1",
+ "ASSEMBLER-INTERNAL-LOGIC-ERROR!",
+ "bignum/flonum",
+ "difference",
+ "debug",
+ "transfert vector preload",
+ "transfert vector postload",
+ "register",
+ "",
+ }; /* Used by error reporters, dumpers etc. */
+
+
+void
+ subsegs_begin()
+{
+ /* Check table(s) seg_name[], seg_N_TYPE[] is in correct order */
+#ifdef MANY_SEGMENTS
+#else
+ know(SEG_ABSOLUTE == 0);
+ know(SEG_TEXT == 1);
+ know(SEG_DATA == 2);
+ know(SEG_BSS == 3);
+ know(SEG_UNKNOWN == 4);
+ know(SEG_ABSENT == 5);
+ know(SEG_PASS1 == 6);
+ know(SEG_GOOF == 7);
+ know(SEG_BIG == 8);
+ know(SEG_DIFFERENCE == 9);
+ know(SEG_DEBUG == 10);
+ know(SEG_NTV == 11);
+ know(SEG_PTV == 12);
+ know(SEG_REGISTER == 13);
+ know(SEG_MAXIMUM_ORDINAL == SEG_REGISTER );
+ /* know(segment_name(SEG_MAXIMUM_ORDINAL + 1)[0] == 0);*/
+#endif
+
+ obstack_begin(&frags, 5000);
+ frchain_root = NULL;
+ frchain_now = NULL; /* Warn new_subseg() that we are booting. */
+ /* Fake up 1st frag. */
+ /* It won't be used=> is ok if obstack... */
+ /* pads the end of it for alignment. */
+ frag_now=(fragS *)obstack_alloc(&frags,SIZEOF_STRUCT_FRAG);
+ memset(frag_now, SIZEOF_STRUCT_FRAG, 0);
+ /* This 1st frag will not be in any frchain. */
+ /* We simply give subseg_new somewhere to scribble. */
+ now_subseg = 42; /* Lie for 1st call to subseg_new. */
+#ifdef MANY_SEGMENTS
+ {
+ int i;
+ for (i = SEG_E0; i < SEG_UNKNOWN; i++) {
+ subseg_new(i, 0);
+ segment_info[i].frchainP = frchain_now;
+ }
+ }
+#else
+ subseg_new(SEG_DATA, 0); /* .data 0 */
+ data0_frchainP = frchain_now;
+#endif
+
+}
+
+/*
+ * subseg_change()
+ *
+ * Change the subsegment we are in, BUT DO NOT MAKE A NEW FRAG for the
+ * subsegment. If we are already in the correct subsegment, change nothing.
+ * This is used eg as a worker for subseg_new [which does make a new frag_now]
+ * and for changing segments after we have read the source. We construct eg
+ * fixSs even after the source file is read, so we do have to keep the
+ * segment context correct.
+ */
+void
+ subseg_change (seg, subseg)
+register segT seg;
+register int subseg;
+{
+ now_seg = seg;
+ now_subseg = subseg;
+#ifdef MANY_SEGMENTS
+ seg_fix_rootP = &segment_info[seg].fix_root;
+ seg_fix_tailP = &segment_info[seg].fix_tail;
+#else
+ if (seg == SEG_DATA) {
+ seg_fix_rootP = &data_fix_root;
+ seg_fix_tailP = &data_fix_tail;
+ } else if (seg == SEG_BSS) {
+ seg_fix_rootP = &bss_fix_root;
+ seg_fix_tailP = &bss_fix_tail;
+ } else {
+ know (seg == SEG_TEXT);
+ seg_fix_rootP = &text_fix_root;
+ seg_fix_tailP = &text_fix_tail;
+ }
+#endif
+}
+
+/*
+ * subseg_new()
+ *
+ * If you attempt to change to the current subsegment, nothing happens.
+ *
+ * In: segT, subsegT code for new subsegment.
+ * frag_now -> incomplete frag for current subsegment.
+ * If frag_now == NULL, then there is no old, incomplete frag, so
+ * the old frag is not closed off.
+ *
+ * Out: now_subseg, now_seg updated.
+ * Frchain_now points to the (possibly new) struct frchain for this
+ * sub-segment.
+ * Frchain_root updated if needed.
+ */
+
+void
+ subseg_new (seg, subseg) /* begin assembly for a new sub-segment */
+register segT seg; /* SEG_DATA or SEG_TEXT */
+register subsegT subseg;
+{
+ long tmp; /* JF for obstack alignment hacking */
+#ifndef MANY_SEGMENTS
+ know(seg == SEG_DATA || seg == SEG_TEXT || seg == SEG_BSS);
+#endif
+ if (seg != now_seg || subseg != now_subseg)
+ { /* we just changed sub-segments */
+ register frchainS * frcP; /* crawl frchain chain */
+ register frchainS** lastPP; /* address of last pointer */
+ frchainS *newP; /* address of new frchain */
+ register fragS *former_last_fragP;
+ register fragS *new_fragP;
+
+ if (frag_now) /* If not bootstrapping. */
+ {
+ frag_now->fr_fix = obstack_next_free(& frags) - frag_now->fr_literal;
+ frag_wane(frag_now); /* Close off any frag in old subseg. */
+ }
+ /*
+ * It would be nice to keep an obstack for each subsegment, if we swap
+ * subsegments a lot. Hence we would have much fewer frag_wanes().
+ */
+ {
+
+ obstack_finish( &frags);
+ /*
+ * If we don't do the above, the next object we put on obstack frags
+ * will appear to start at the fr_literal of the current frag.
+ * Also, above ensures that the next object will begin on a
+ * address that is aligned correctly for the engine that runs
+ * this program.
+ */
+ }
+ subseg_change (seg, (int)subseg);
+ /*
+ * Attempt to find or make a frchain for that sub seg.
+ * Crawl along chain of frchainSs, begins @ frchain_root.
+ * If we need to make a frchainS, link it into correct
+ * position of chain rooted in frchain_root.
+ */
+ for (frcP = * (lastPP = & frchain_root);
+ frcP
+ && (int)(frcP->frch_seg) <= (int)seg;
+ frcP = * ( lastPP = & frcP->frch_next)
+ )
+ {
+ if ( (int)(frcP->frch_seg) == (int)seg
+ && frcP->frch_subseg >= subseg)
+ {
+ break;
+ }
+ }
+ /*
+ * frcP: Address of the 1st frchainS in correct segment with
+ * frch_subseg >= subseg.
+ * We want to either use this frchainS, or we want
+ * to insert a new frchainS just before it.
+ *
+ * If frcP == NULL, then we are at the end of the chain
+ * of frchainS-s. A NULL frcP means we fell off the end
+ * of the chain looking for a
+ * frch_subseg >= subseg, so we
+ * must make a new frchainS.
+ *
+ * If we ever maintain a pointer to
+ * the last frchainS in the chain, we change that pointer
+ * ONLY when frcP == NULL.
+ *
+ * lastPP: Address of the pointer with value frcP;
+ * Never NULL.
+ * May point to frchain_root.
+ *
+ */
+ if ( ! frcP
+ || ( (int)(frcP->frch_seg) > (int)seg
+ || frcP->frch_subseg > subseg)) /* Kinky logic only works with 2 segments. */
+ {
+ /*
+ * This should be the only code that creates a frchainS.
+ */
+ newP=(frchainS *)obstack_alloc(&frags,sizeof(frchainS));
+ memset(newP, sizeof(frchainS), 0);
+ /* This begines on a good boundary */
+ /* because a obstack_done() preceeded it. */
+ /* It implies an obstack_done(), so we */
+ /* expect the next object allocated to */
+ /* begin on a correct boundary. */
+ *lastPP = newP;
+ newP->frch_next = frcP; /* perhaps NULL */
+ (frcP = newP)->frch_subseg = subseg;
+ newP->frch_seg = seg;
+ newP->frch_last = NULL;
+ }
+ /*
+ * Here with frcP->ing to the frchainS for subseg.
+ */
+ frchain_now = frcP;
+ /*
+ * Make a fresh frag for the subsegment.
+ */
+ /* We expect this to happen on a correct */
+ /* boundary since it was proceeded by a */
+ /* obstack_done(). */
+ tmp=obstack_alignment_mask(&frags); /* JF disable alignment */
+ obstack_alignment_mask(&frags)=0;
+ frag_now=(fragS *)obstack_alloc(&frags,SIZEOF_STRUCT_FRAG);
+ obstack_alignment_mask(&frags)=tmp;
+ /* know(frags.obstack_c_next_free == frag_now->fr_literal); */
+ /* But we want any more chars to come */
+ /* immediately after the structure we just made. */
+ new_fragP = frag_now;
+ new_fragP->fr_next = NULL;
+ /*
+ * Append new frag to current frchain.
+ */
+ former_last_fragP = frcP->frch_last;
+ if (former_last_fragP)
+ {
+ know( former_last_fragP->fr_next == NULL );
+ know( frchain_now->frch_root );
+ former_last_fragP->fr_next = new_fragP;
+ }
+ else
+ {
+ frcP->frch_root = new_fragP;
+ }
+ frcP->frch_last = new_fragP;
+ } /* if (changing subsegments) */
+} /* subseg_new() */
+
+/*
+ * Local Variables:
+ * comment-column: 0
+ * fill-column: 131
+ * End:
+ */
+
+/* end of subsegs.c */
diff --git a/gnu/usr.bin/as/subsegs.h b/gnu/usr.bin/as/subsegs.h
new file mode 100644
index 0000000..9d1482a
--- /dev/null
+++ b/gnu/usr.bin/as/subsegs.h
@@ -0,0 +1,93 @@
+/* subsegs.h -> subsegs.c
+
+ Copyright (C) 1987, 1992 Free Software Foundation, Inc.
+
+ This file is part of GAS, the GNU Assembler.
+
+ GAS is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GAS is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GAS; see the file COPYING. If not, write to
+ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+/*
+ * $Id: subsegs.h,v 1.2 1993/11/03 00:52:20 paul Exp $
+ */
+
+
+/*
+ * For every sub-segment the user mentions in the ASsembler program,
+ * we make one struct frchain. Each sub-segment has exactly one struct frchain
+ * and vice versa.
+ *
+ * Struct frchain's are forward chained (in ascending order of sub-segment
+ * code number). The chain runs through frch_next of each subsegment.
+ * This makes it hard to find a subsegment's frags
+ * if programmer uses a lot of them. Most programs only use text0 and
+ * data0, so they don't suffer. At least this way:
+ * (1) There are no "arbitrary" restrictions on how many subsegments
+ * can be programmed;
+ * (2) Subsegments' frchain-s are (later) chained together in the order in
+ * which they are emitted for object file viz text then data.
+ *
+ * From each struct frchain dangles a chain of struct frags. The frags
+ * represent code fragments, for that sub-segment, forward chained.
+ */
+
+struct frchain /* control building of a frag chain */
+{ /* FRCH = FRagment CHain control */
+ struct frag * frch_root; /* 1st struct frag in chain, or NULL */
+ struct frag * frch_last; /* last struct frag in chain, or NULL */
+ struct frchain * frch_next; /* next in chain of struct frchain-s */
+ segT frch_seg; /* SEG_TEXT or SEG_DATA. */
+ subsegT frch_subseg; /* subsegment number of this chain */
+};
+
+typedef struct frchain frchainS;
+
+extern frchainS * frchain_root; /* NULL means no frchains yet. */
+/* all subsegments' chains hang off here */
+
+extern frchainS * frchain_now;
+/* Frchain we are assembling into now */
+/* That is, the current segment's frag */
+/* chain, even if it contains no (complete) */
+/* frags. */
+
+
+#ifdef MANY_SEGMENTS
+typedef struct
+{
+ frchainS *frchainP;
+ int hadone;
+ int user_stuff;
+ /* struct frag *frag_root;*/
+ /* struct frag *last_frag;*/
+ fixS *fix_root;
+ fixS *fix_tail;
+ struct internal_scnhdr scnhdr;
+ symbolS *dot;
+
+ struct lineno_list *lineno_list_head;
+ struct lineno_list *lineno_list_tail;
+
+} segment_info_type;
+segment_info_type segment_info[];
+#else
+extern frchainS * data0_frchainP;
+extern frchainS * bss0_frchainP;
+/* Sentinel for frchain crawling. */
+/* Points to the 1st data-segment frchain. */
+/* (Which is pointed to by the last text- */
+/* segment frchain.) */
+
+#endif
+
+/* end of subsegs.h */
diff --git a/gnu/usr.bin/as/symbols.c b/gnu/usr.bin/as/symbols.c
new file mode 100644
index 0000000..44c71d4
--- /dev/null
+++ b/gnu/usr.bin/as/symbols.c
@@ -0,0 +1,658 @@
+/* symbols.c -symbol table-
+
+ Copyright (C) 1987, 1990, 1991, 1992 Free Software Foundation, Inc.
+
+ This file is part of GAS, the GNU Assembler.
+
+ GAS is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GAS is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GAS; see the file COPYING. If not, write to
+ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#ifndef lint
+static char rcsid[] = "$Id: symbols.c,v 1.2 1993/11/03 00:52:22 paul Exp $";
+#endif
+
+#include "as.h"
+
+#include "obstack.h" /* For "symbols.h" */
+#include "subsegs.h"
+
+#ifndef WORKING_DOT_WORD
+extern int new_broken_words;
+#endif
+
+static
+ struct hash_control *
+ sy_hash; /* symbol-name => struct symbol pointer */
+
+/* Below are commented in "symbols.h". */
+unsigned int local_bss_counter;
+symbolS * symbol_rootP;
+symbolS * symbol_lastP;
+symbolS abs_symbol;
+
+symbolS* dot_text_symbol;
+symbolS* dot_data_symbol;
+symbolS* dot_bss_symbol;
+
+struct obstack notes;
+
+/*
+ * Un*x idea of local labels. They are made by "n:" where n
+ * is any decimal digit. Refer to them with
+ * "nb" for previous (backward) n:
+ * or "nf" for next (forward) n:.
+ *
+ * Like Un*x AS, we have one set of local label counters for entire assembly,
+ * not one set per (sub)segment like in most assemblers. This implies that
+ * one can refer to a label in another segment, and indeed some crufty
+ * compilers have done just that.
+ *
+ * I document the symbol names here to save duplicating words elsewhere.
+ * The mth occurence of label n: is turned into the symbol "Ln^Am" where
+ * n is a digit and m is a decimal number. "L" makes it a label discarded
+ * unless debugging and "^A"('\1') ensures no ordinary symbol SHOULD get the
+ * same name as a local label symbol. The first "4:" is "L4^A1" - the m
+ * numbers begin at 1.
+ */
+
+typedef short unsigned int
+ local_label_countT;
+
+static local_label_countT
+ local_label_counter[10];
+
+static /* Returned to caller, then copied. */
+ char symbol_name_build[12]; /* used for created names ("4f") */
+
+#ifdef LOCAL_LABELS_DOLLAR
+int local_label_defined[10];
+#endif
+
+
+void
+ symbol_begin()
+{
+ symbol_lastP = NULL;
+ symbol_rootP = NULL; /* In case we have 0 symbols (!!) */
+ sy_hash = hash_new();
+ memset((char *)(& abs_symbol), '\0', sizeof(abs_symbol));
+ S_SET_SEGMENT(&abs_symbol, SEG_ABSOLUTE); /* Can't initialise a union. Sigh. */
+ memset((char *)(local_label_counter), '\0', sizeof(local_label_counter) );
+ local_bss_counter = 0;
+}
+
+/*
+ * local_label_name()
+ *
+ * Caller must copy returned name: we re-use the area for the next name.
+ */
+
+char * /* Return local label name. */
+ local_label_name(n, augend)
+register int n; /* we just saw "n:", "nf" or "nb" : n a digit */
+register int augend; /* 0 for nb, 1 for n:, nf */
+{
+ register char * p;
+ register char * q;
+ char symbol_name_temporary[10]; /* build up a number, BACKWARDS */
+
+ know( n >= 0 );
+ know( augend == 0 || augend == 1 );
+ p = symbol_name_build;
+ * p ++ = 1; /* ^A */
+ * p ++ = 'L';
+ * p ++ = n + '0'; /* Make into ASCII */
+ n = local_label_counter[ n ] + augend;
+ /* version number of this local label */
+ /*
+ * Next code just does sprintf( {}, "%d", n);
+ * It is more elegant to do the next part recursively, but a procedure
+ * call for each digit emitted is considered too costly.
+ */
+ q = symbol_name_temporary;
+ for (*q++=0; n; q++) /* emits NOTHING if n starts as 0 */
+ {
+ know(n>0); /* We expect n > 0 always */
+ *q = n % 10 + '0';
+ n /= 10;
+ }
+ while (( * p ++ = * -- q ) != '\0') ;;
+
+ /* The label, as a '\0' ended string, starts at symbol_name_build. */
+ return(symbol_name_build);
+} /* local_label_name() */
+
+
+void local_colon (n)
+int n; /* just saw "n:" */
+{
+ local_label_counter[n] ++;
+#ifdef LOCAL_LABELS_DOLLAR
+ local_label_defined[n]=1;
+#endif
+ colon (local_label_name (n, 0));
+}
+
+/*
+ * symbol_new()
+ *
+ * Return a pointer to a new symbol.
+ * Die if we can't make a new symbol.
+ * Fill in the symbol's values.
+ * Add symbol to end of symbol chain.
+ *
+ *
+ * Please always call this to create a new symbol.
+ *
+ * Changes since 1985: Symbol names may not contain '\0'. Sigh.
+ * 2nd argument is now a SEG rather than a TYPE. The mapping between
+ * segments and types is mostly encapsulated herein (actually, we inherit it
+ * from macros in struc-symbol.h).
+ */
+
+symbolS *symbol_new(name, segment, value, frag)
+char *name; /* It is copied, the caller can destroy/modify */
+segT segment; /* Segment identifier (SEG_<something>) */
+long value; /* Symbol value */
+fragS *frag; /* Associated fragment */
+{
+ unsigned int name_length;
+ char *preserved_copy_of_name;
+ symbolS *symbolP;
+
+ name_length = strlen(name) + 1; /* +1 for \0 */
+ obstack_grow(&notes, name, name_length);
+ preserved_copy_of_name = obstack_finish(&notes);
+ symbolP = (symbolS *) obstack_alloc(&notes, sizeof(symbolS));
+
+ /* symbol must be born in some fixed state. This seems as good as any. */
+ memset(symbolP, 0, sizeof(symbolS));
+
+#ifdef STRIP_UNDERSCORE
+ S_SET_NAME(symbolP, (*preserved_copy_of_name == '_'
+ ? preserved_copy_of_name + 1
+ : preserved_copy_of_name));
+#else /* STRIP_UNDERSCORE */
+ S_SET_NAME(symbolP, preserved_copy_of_name);
+#endif /* STRIP_UNDERSCORE */
+
+ S_SET_SEGMENT(symbolP, segment);
+ S_SET_VALUE(symbolP, value);
+ /* symbol_clear_list_pointers(symbolP); uneeded if symbol is born zeroed. */
+
+ symbolP->sy_frag = frag;
+ /* krm: uneeded if symbol is born zeroed.
+ symbolP->sy_forward = NULL; */ /* JF */
+ symbolP->sy_number = ~0;
+ symbolP->sy_name_offset = ~0;
+
+ /*
+ * Link to end of symbol chain.
+ */
+ symbol_append(symbolP, symbol_lastP, &symbol_rootP, &symbol_lastP);
+
+ obj_symbol_new_hook(symbolP);
+
+#ifdef DEBUG
+ /* verify_symbol_chain(symbol_rootP, symbol_lastP); */
+#endif /* DEBUG */
+
+ return(symbolP);
+} /* symbol_new() */
+
+
+/*
+ * colon()
+ *
+ * We have just seen "<name>:".
+ * Creates a struct symbol unless it already exists.
+ *
+ * Gripes if we are redefining a symbol incompatibly (and ignores it).
+ *
+ */
+void colon(sym_name) /* just seen "x:" - rattle symbols & frags */
+register char * sym_name; /* symbol name, as a cannonical string */
+/* We copy this string: OK to alter later. */
+{
+ register symbolS * symbolP; /* symbol we are working with */
+
+#ifdef LOCAL_LABELS_DOLLAR
+ /* Sun local labels go out of scope whenever a non-local symbol is defined. */
+
+ if (*sym_name != 'L')
+ memset((void *) local_label_defined, '\0', sizeof(local_label_defined));
+#endif
+
+#ifndef WORKING_DOT_WORD
+ if (new_broken_words) {
+ struct broken_word *a;
+ int possible_bytes;
+ fragS *frag_tmp;
+ char *frag_opcode;
+
+ extern const md_short_jump_size;
+ extern const md_long_jump_size;
+ possible_bytes=md_short_jump_size + new_broken_words * md_long_jump_size;
+
+ frag_tmp=frag_now;
+ frag_opcode=frag_var(rs_broken_word,
+ possible_bytes,
+ possible_bytes,
+ (relax_substateT) 0,
+ (symbolS *) broken_words,
+ 0L,
+ NULL);
+
+ /* We want to store the pointer to where to insert the jump table in the
+ fr_opcode of the rs_broken_word frag. This requires a little hackery */
+ while (frag_tmp && (frag_tmp->fr_type != rs_broken_word || frag_tmp->fr_opcode))
+ frag_tmp=frag_tmp->fr_next;
+ know(frag_tmp);
+ frag_tmp->fr_opcode=frag_opcode;
+ new_broken_words = 0;
+
+ for (a=broken_words;a && a->dispfrag == 0;a=a->next_broken_word)
+ a->dispfrag=frag_tmp;
+ }
+#endif
+ if ((symbolP = symbol_find(sym_name)) != 0) {
+#ifdef OBJ_VMS
+ /*
+ * If the new symbol is .comm AND it has a size of zero,
+ * we ignore it (i.e. the old symbol overrides it)
+ */
+ if ((SEGMENT_TO_SYMBOL_TYPE((int) now_seg) == (N_UNDF | N_EXT)) &&
+ ((obstack_next_free(& frags) - frag_now->fr_literal) == 0))
+ return;
+ /*
+ * If the old symbol is .comm and it has a size of zero,
+ * we override it with the new symbol value.
+ */
+ if (S_IS_EXTERNAL(symbolP) && S_IS_DEFINED(symbolP)
+ && (S_GET_VALUE(symbolP) == 0)) {
+ symbolP->sy_frag = frag_now;
+ S_GET_OTHER(symbolP) = const_flag;
+ S_SET_VALUE(symbolP, obstack_next_free(& frags) - frag_now->fr_literal);
+ symbolP->sy_symbol.n_type |=
+ SEGMENT_TO_SYMBOL_TYPE((int) now_seg); /* keep N_EXT bit */
+ return;
+ }
+#endif /* OBJ_VMS */
+ /*
+ * Now check for undefined symbols
+ */
+ if (!S_IS_DEFINED(symbolP)) {
+ if (S_GET_VALUE(symbolP) == 0) {
+ symbolP->sy_frag = frag_now;
+#ifdef OBJ_VMS
+ S_GET_OTHER(symbolP) = const_flag;
+#endif
+ S_SET_VALUE(symbolP, obstack_next_free(&frags) - frag_now->fr_literal);
+ S_SET_SEGMENT(symbolP, now_seg);
+#ifdef N_UNDF
+ know(N_UNDF == 0);
+#endif /* if we have one, it better be zero. */
+
+ } else {
+ /*
+ * There are still several cases to check:
+ * A .comm/.lcomm symbol being redefined as
+ * initialized data is OK
+ * A .comm/.lcomm symbol being redefined with
+ * a larger size is also OK
+ *
+ * This only used to be allowed on VMS gas, but Sun cc
+ * on the sparc also depends on it.
+ */
+ /* char New_Type = SEGMENT_TO_SYMBOL_TYPE((int) now_seg); */
+#ifdef MANY_SEGMENTS
+#define SEG_BSS SEG_E2
+#define SEG_DATA SEG_E1
+#endif
+
+ if (((!S_IS_DEBUG(symbolP) && !S_IS_DEFINED(symbolP) && S_IS_EXTERNAL(symbolP))
+ || (S_GET_SEGMENT(symbolP) == SEG_BSS))
+ && ((now_seg == SEG_DATA)
+ || (now_seg == S_GET_SEGMENT(symbolP)))) {
+ /*
+ * Select which of the 2 cases this is
+ */
+ if (now_seg != SEG_DATA) {
+ /*
+ * New .comm for prev .comm symbol.
+ * If the new size is larger we just
+ * change its value. If the new size
+ * is smaller, we ignore this symbol
+ */
+ if (S_GET_VALUE(symbolP)
+ < ((unsigned) (obstack_next_free(& frags) - frag_now->fr_literal))) {
+ S_SET_VALUE(symbolP,
+ obstack_next_free(& frags) -
+ frag_now->fr_literal);
+ }
+ } else {
+ /*
+ * It is a .comm/.lcomm being converted
+ * to initialized data.
+ */
+ symbolP->sy_frag = frag_now;
+#ifdef OBJ_VMS
+ S_GET_OTHER(symbolP) = const_flag;
+#endif /* OBJ_VMS */
+ S_SET_VALUE(symbolP, obstack_next_free(& frags) - frag_now->fr_literal);
+ S_SET_SEGMENT(symbolP, now_seg); /* keep N_EXT bit */
+ }
+ } else {
+#ifdef OBJ_COFF
+ as_fatal("Symbol \"%s\" is already defined as \"%s\"/%d.",
+ sym_name,
+ segment_name(S_GET_SEGMENT(symbolP)),
+ S_GET_VALUE(symbolP));
+#else /* OBJ_COFF */
+ as_fatal("Symbol \"%s\" is already defined as \"%s\"/%d.%d.%d.",
+ sym_name,
+ segment_name(S_GET_SEGMENT(symbolP)),
+ S_GET_OTHER(symbolP), S_GET_DESC(symbolP),
+ S_GET_VALUE(symbolP));
+#endif /* OBJ_COFF */
+ }
+ } /* if the undefined symbol has no value */
+ } else
+ {
+ /* Don't blow up if the definition is the same */
+ if (!(frag_now == symbolP->sy_frag
+ && S_GET_VALUE(symbolP) == obstack_next_free(&frags) - frag_now->fr_literal
+ && S_GET_SEGMENT(symbolP) == now_seg) )
+ as_fatal("Symbol %s already defined.", sym_name);
+ } /* if this symbol is not yet defined */
+
+ } else {
+ symbolP = symbol_new(sym_name,
+ now_seg,
+ (valueT)(obstack_next_free(&frags)-frag_now->fr_literal),
+ frag_now);
+#ifdef OBJ_VMS
+ S_SET_OTHER(symbolP, const_flag);
+#endif /* OBJ_VMS */
+
+ symbol_table_insert(symbolP);
+ } /* if we have seen this symbol before */
+
+ return;
+} /* colon() */
+
+
+/*
+ * symbol_table_insert()
+ *
+ * Die if we can't insert the symbol.
+ *
+ */
+
+void symbol_table_insert(symbolP)
+symbolS *symbolP;
+{
+ register char *error_string;
+
+ know(symbolP);
+ know(S_GET_NAME(symbolP));
+
+ if (*(error_string = hash_jam(sy_hash, S_GET_NAME(symbolP), (char *)symbolP))) {
+ as_fatal("Inserting \"%s\" into symbol table failed: %s",
+ S_GET_NAME(symbolP), error_string);
+ } /* on error */
+} /* symbol_table_insert() */
+
+/*
+ * symbol_find_or_make()
+ *
+ * If a symbol name does not exist, create it as undefined, and insert
+ * it into the symbol table. Return a pointer to it.
+ */
+symbolS *symbol_find_or_make(name)
+char *name;
+{
+ register symbolS *symbolP;
+
+ symbolP = symbol_find(name);
+
+ if (symbolP == NULL) {
+ symbolP = symbol_make(name);
+
+ symbol_table_insert(symbolP);
+ } /* if symbol wasn't found */
+
+ return(symbolP);
+} /* symbol_find_or_make() */
+
+symbolS *symbol_make(name)
+char *name;
+{
+ symbolS *symbolP;
+
+ /* Let the machine description default it, e.g. for register names. */
+ symbolP = md_undefined_symbol(name);
+
+ if (!symbolP) {
+ symbolP = symbol_new(name,
+ SEG_UNKNOWN,
+ 0,
+ &zero_address_frag);
+ } /* if md didn't build us a symbol */
+
+ return(symbolP);
+} /* symbol_make() */
+
+/*
+ * symbol_find()
+ *
+ * Implement symbol table lookup.
+ * In: A symbol's name as a string: '\0' can't be part of a symbol name.
+ * Out: NULL if the name was not in the symbol table, else the address
+ * of a struct symbol associated with that name.
+ */
+
+symbolS *symbol_find(name)
+char *name;
+{
+#ifdef STRIP_UNDERSCORE
+ return(symbol_find_base(name, 1));
+#else /* STRIP_UNDERSCORE */
+ return(symbol_find_base(name, 0));
+#endif /* STRIP_UNDERSCORE */
+} /* symbol_find() */
+
+symbolS *symbol_find_base(name, strip_underscore)
+char *name;
+int strip_underscore;
+{
+ if (strip_underscore && *name == '_') name++;
+ return ( (symbolS *) hash_find( sy_hash, name ));
+}
+
+/*
+ * Once upon a time, symbols were kept in a singly linked list. At
+ * least coff needs to be able to rearrange them from time to time, for
+ * which a doubly linked list is much more convenient. Loic did these
+ * as macros which seemed dangerous to me so they're now functions.
+ * xoxorich.
+ */
+
+/* Link symbol ADDME after symbol TARGET in the chain. */
+void symbol_append(addme, target, rootPP, lastPP)
+symbolS *addme;
+symbolS *target;
+symbolS **rootPP;
+symbolS **lastPP;
+{
+ if (target == NULL) {
+ know(*rootPP == NULL);
+ know(*lastPP == NULL);
+ *rootPP = addme;
+ *lastPP = addme;
+ return;
+ } /* if the list is empty */
+
+ if (target->sy_next != NULL) {
+#ifdef SYMBOLS_NEED_BACKPOINTERS
+ target->sy_next->sy_previous = addme;
+#endif /* SYMBOLS_NEED_BACKPOINTERS */
+ } else {
+ know(*lastPP == target);
+ *lastPP = addme;
+ } /* if we have a next */
+
+ addme->sy_next = target->sy_next;
+ target->sy_next = addme;
+
+#ifdef SYMBOLS_NEED_BACKPOINTERS
+ addme->sy_previous = target;
+#endif /* SYMBOLS_NEED_BACKPOINTERS */
+
+#ifdef DEBUG
+ /* verify_symbol_chain(*rootPP, *lastPP); */
+#endif /* DEBUG */
+
+ return;
+} /* symbol_append() */
+
+#ifdef SYMBOLS_NEED_BACKPOINTERS
+/* Remove SYMBOLP from the list. */
+void symbol_remove(symbolP, rootPP, lastPP)
+symbolS *symbolP;
+symbolS **rootPP;
+symbolS **lastPP;
+{
+ if (symbolP == *rootPP) {
+ *rootPP = symbolP->sy_next;
+ } /* if it was the root */
+
+ if (symbolP == *lastPP) {
+ *lastPP = symbolP->sy_previous;
+ } /* if it was the tail */
+
+ if (symbolP->sy_next != NULL) {
+ symbolP->sy_next->sy_previous = symbolP->sy_previous;
+ } /* if not last */
+
+ if (symbolP->sy_previous != NULL) {
+ symbolP->sy_previous->sy_next = symbolP->sy_next;
+ } /* if not first */
+
+#ifdef DEBUG
+ verify_symbol_chain(*rootPP, *lastPP);
+#endif /* DEBUG */
+
+ return;
+} /* symbol_remove() */
+
+/* Set the chain pointers of SYMBOL to null. */
+void symbol_clear_list_pointers(symbolP)
+symbolS *symbolP;
+{
+ symbolP->sy_next = NULL;
+ symbolP->sy_previous = NULL;
+} /* symbol_clear_list_pointers() */
+
+/* Link symbol ADDME before symbol TARGET in the chain. */
+void symbol_insert(addme, target, rootPP, lastPP)
+symbolS *addme;
+symbolS *target;
+symbolS **rootPP;
+symbolS **lastPP;
+{
+ if (target->sy_previous != NULL) {
+ target->sy_previous->sy_next = addme;
+ } else {
+ know(*rootPP == target);
+ *rootPP = addme;
+ } /* if not first */
+
+ addme->sy_previous = target->sy_previous;
+ target->sy_previous = addme;
+ addme->sy_next = target;
+
+#ifdef DEBUG
+ verify_symbol_chain(*rootPP, *lastPP);
+#endif /* DEBUG */
+
+ return;
+} /* symbol_insert() */
+#endif /* SYMBOLS_NEED_BACKPOINTERS */
+
+void verify_symbol_chain(rootP, lastP)
+symbolS *rootP;
+symbolS *lastP;
+{
+ symbolS *symbolP = rootP;
+
+ if (symbolP == NULL) {
+ return;
+ } /* empty chain */
+
+ for ( ; symbol_next(symbolP) != NULL; symbolP = symbol_next(symbolP)) {
+#ifdef SYMBOLS_NEED_BACKPOINTERS
+ /*$if (symbolP->sy_previous) {
+ know(symbolP->sy_previous->sy_next == symbolP);
+ } else {
+ know(symbolP == rootP);
+ }$*/ /* both directions */
+ know(symbolP->sy_next->sy_previous == symbolP);
+#else /* SYMBOLS_NEED_BACKPOINTERS */
+ ;
+#endif /* SYMBOLS_NEED_BACKPOINTERS */
+ } /* verify pointers */
+
+ know(lastP == symbolP);
+
+ return;
+} /* verify_symbol_chain() */
+
+
+/*
+ * decode name that may have been generated by local_label_name() above. If
+ * the name wasn't generated by local_label_name(), then return it unaltered.
+ * This is used for error messages.
+ */
+
+char *decode_local_label_name(s)
+char *s;
+{
+ char *symbol_decode;
+ int label_number;
+ /* int label_version; */
+ char *message_format = "\"%d\" (instance number %s of a local label)";
+
+ if (s[0] != 'L'
+ || s[2] != 1) {
+ return(s);
+ } /* not a local_label_name() generated name. */
+
+ label_number = s[1] - '0';
+
+ (void) sprintf(symbol_decode = obstack_alloc(&notes, strlen(s + 3) + strlen(message_format) + 10),
+ message_format, label_number, s + 3);
+
+ return(symbol_decode);
+} /* decode_local_label_name() */
+
+
+/*
+ * Local Variables:
+ * comment-column: 0
+ * fill-column: 131
+ * End:
+ */
+
+/* end of symbols.c */
diff --git a/gnu/usr.bin/as/symbols.h b/gnu/usr.bin/as/symbols.h
new file mode 100644
index 0000000..0906e9d
--- /dev/null
+++ b/gnu/usr.bin/as/symbols.h
@@ -0,0 +1,82 @@
+/* symbols.h -
+
+ Copyright (C) 1987, 1990, 1992 Free Software Foundation, Inc.
+
+ This file is part of GAS, the GNU Assembler.
+
+ GAS is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GAS is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GAS; see the file COPYING. If not, write to
+ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+/*
+ * $Id: symbols.h,v 1.2 1993/11/03 00:52:23 paul Exp $
+ */
+
+
+extern struct obstack notes; /* eg FixS live here. */
+
+extern struct obstack cond_obstack; /* this is where we track .ifdef/.endif
+ (if we do that at all). */
+
+extern unsigned int local_bss_counter; /* Zeroed before a pass. */
+/* Only used by .lcomm directive. */
+
+extern symbolS *symbol_rootP; /* all the symbol nodes */
+extern symbolS *symbol_lastP; /* last struct symbol we made, or NULL */
+
+extern symbolS abs_symbol;
+
+extern symbolS *dot_text_symbol;
+extern symbolS *dot_data_symbol;
+extern symbolS *dot_bss_symbol;
+
+#if __STDC__ == 1
+
+char *decode_local_label_name(char *s);
+char *local_label_name(int n, int augend);
+symbolS *symbol_find(char *name);
+symbolS *symbol_find_base(char *name, int strip_underscore);
+symbolS *symbol_find_or_make(char *name);
+symbolS *symbol_make(char *name);
+symbolS *symbol_new(char *name, segT segment, long value, fragS *frag);
+void colon(char *sym_name);
+void local_colon(int n);
+void symbol_begin(void);
+void symbol_table_insert(symbolS *symbolP);
+void verify_symbol_chain(symbolS *rootP, symbolS *lastP);
+
+#else /* not __STDC__ */
+
+char *decode_local_label_name();
+char *local_label_name();
+symbolS *symbol_find();
+symbolS *symbol_find_base();
+symbolS *symbol_find_or_make();
+symbolS *symbol_make();
+symbolS *symbol_new();
+void colon();
+void local_colon();
+void symbol_begin();
+void symbol_table_insert();
+void verify_symbol_chain();
+
+#endif /* not __STDC__ */
+
+
+/*
+ * Local Variables:
+ * comment-column: 0
+ * fill-column: 131
+ * End:
+ */
+
+/* end of symbols.h */
diff --git a/gnu/usr.bin/as/tc.h b/gnu/usr.bin/as/tc.h
new file mode 100644
index 0000000..b75b0e2
--- /dev/null
+++ b/gnu/usr.bin/as/tc.h
@@ -0,0 +1,112 @@
+/* tc.h - target cpu dependent
+
+ Copyright (C) 1987, 1990, 1991, 1992 Free Software Foundation, Inc.
+
+ This file is part of GAS, the GNU Assembler.
+
+ GAS is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GAS is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GAS; see the file COPYING. If not, write to
+ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+/*
+ * $Id: tc.h,v 1.1 1993/11/03 00:52:25 paul Exp $
+ */
+
+
+/* In theory (mine, at least!) the machine dependent part of the assembler
+ should only have to include one file. This one. -- JF */
+
+extern const pseudo_typeS md_pseudo_table[];
+
+/* JF moved this here from as.h under the theory that nobody except MACHINE.c
+ and write.c care about it anyway. */
+
+typedef struct
+{
+ long rlx_forward; /* Forward reach. Signed number. > 0. */
+ long rlx_backward; /* Backward reach. Signed number. < 0. */
+ unsigned char rlx_length; /* Bytes length of this address. */
+ relax_substateT rlx_more; /* Next longer relax-state. */
+ /* 0 means there is no 'next' relax-state. */
+}
+relax_typeS;
+
+extern const relax_typeS md_relax_table[]; /* Define it in MACHINE.c */
+
+extern int md_reloc_size; /* Size of a relocation record */
+
+extern void (*md_emit_relocations)();
+
+#if __STDC__ == 1
+
+char *md_atof(int what_statement_type, char *literalP, int *sizeP);
+int md_estimate_size_before_relax(fragS *fragP, segT segment);
+int md_parse_option(char **argP, int *cntP, char ***vecP);
+long md_pcrel_from(fixS *fixP);
+long md_section_align(segT seg, long align);
+short tc_coff_fix2rtype(fixS *fixP);
+symbolS *md_undefined_symbol(char *name);
+void md_apply_fix(fixS *fixP, long val);
+void md_assemble(char *str);
+void md_begin(void);
+void md_convert_frag(object_headers *headers, fragS *fragP);
+void md_create_long_jump(char *ptr, long from_addr, long to_addr, fragS *frag, symbolS *to_symbol);
+void md_create_short_jump(char *ptr, long from_addr, long to_addr, fragS *frag, symbolS *to_symbol);
+void md_end(void);
+void md_number_to_chars(char *buf, long val, int n);
+void md_operand(expressionS *expressionP);
+
+#ifndef tc_crawl_symbol_chain
+void tc_crawl_symbol_chain(object_headers *headers);
+#endif /* tc_crawl_symbol_chain */
+
+#ifndef tc_headers_hook
+void tc_headers_hook(object_headers *headers);
+#endif /* tc_headers_hook */
+
+#else
+
+char *md_atof();
+int md_estimate_size_before_relax();
+int md_parse_option();
+long md_pcrel_from();
+long md_section_align();
+short tc_coff_fix2rtype();
+symbolS *md_undefined_symbol();
+void md_apply_fix();
+void md_assemble();
+void md_begin();
+void md_convert_frag();
+void md_create_long_jump();
+void md_create_short_jump();
+void md_end();
+void md_number_to_chars();
+void md_operand();
+
+#ifndef tc_headers_hook
+void tc_headers_hook();
+#endif /* tc_headers_hook */
+
+#ifndef tc_crawl_symbol_chain
+void tc_crawl_symbol_chain();
+#endif /* tc_crawl_symbol_chain */
+
+#endif /* __STDC_ */
+
+/*
+ * Local Variables:
+ * comment-column: 0
+ * fill-column: 131
+ * End:
+ */
+
+/* end of tc.h */
diff --git a/gnu/usr.bin/as/testscripts/doboth b/gnu/usr.bin/as/testscripts/doboth
new file mode 100755
index 0000000..6b46a03
--- /dev/null
+++ b/gnu/usr.bin/as/testscripts/doboth
@@ -0,0 +1,20 @@
+#!/bin/sh
+# $Id: doboth,v 1.1 1993/10/02 21:01:07 pk Exp $
+
+x=$1 ; shift
+y=$1 ; shift
+
+rm tmp.0 > /dev/null 2>&1
+ln -s $x tmp.0
+$* tmp.0 > tmp.1
+
+rm tmp.0
+ln -s $y tmp.0
+$* tmp.0 > tmp.2
+
+rm tmp.0
+
+diff -c tmp.1 tmp.2
+exit
+
+#eof
diff --git a/gnu/usr.bin/as/testscripts/doobjcmp b/gnu/usr.bin/as/testscripts/doobjcmp
new file mode 100755
index 0000000..6c90cf9
--- /dev/null
+++ b/gnu/usr.bin/as/testscripts/doobjcmp
@@ -0,0 +1,89 @@
+#!/bin/sh
+# $Id: doobjcmp,v 1.1 1993/10/02 21:01:08 pk Exp $
+# compare two object files, in depth.
+
+x=$1
+y=$2
+BOTH="$1 $2"
+
+
+# if they cmp, we're fine.
+if (cmp $BOTH > /dev/null)
+then
+ exit 0
+fi
+
+# otherwise, we must look closer.
+if (doboth $BOTH size)
+then
+ echo Sizes ok.
+else
+ echo Sizes differ:
+ size $BOTH
+# exit 1
+fi
+
+if (doboth $BOTH objdump +header)
+then
+ echo Headers ok.
+else
+ echo Header differences.
+# exit 1
+fi
+
+if (doboth $BOTH objdump +text > /dev/null)
+then
+ echo Text ok.
+else
+ echo Text differences.
+# doboth $BOTH objdump +text
+# exit 1
+fi
+
+if (doboth $BOTH objdump +data > /dev/null)
+then
+ echo Data ok.
+else
+ echo Data differences.
+# doboth $BOTH objdump +data
+# exit 1
+fi
+
+if (doboth $BOTH objdump +symbols > /dev/null)
+then
+ echo Symbols ok.
+else
+ echo -n Symbol differences...
+
+ if (doboth $BOTH dounsortsymbols)
+ then
+ echo but symbols are simply ordered differently.
+# echo Now what to do about relocs'?'
+# exit 1
+ else
+ echo and symbols differ in content.
+ exit 1
+ fi
+fi
+
+# of course, if there were symbol diffs, then the reloc symbol indexes
+# will be off.
+
+if (doboth $BOTH objdump -r > /dev/null)
+then
+ echo Reloc ok.
+else
+ echo -n Reloc differences...
+
+ if (doboth $BOTH dounsortreloc)
+ then
+ echo but relocs are simply ordered differently.
+ else
+ echo and relocs differ in content.
+ exit 1
+ fi
+fi
+
+exit
+
+# eof
diff --git a/gnu/usr.bin/as/testscripts/dostriptest b/gnu/usr.bin/as/testscripts/dostriptest
new file mode 100755
index 0000000..aa734c0
--- /dev/null
+++ b/gnu/usr.bin/as/testscripts/dostriptest
@@ -0,0 +1,15 @@
+#!/bin/sh
+# $Id: dostriptest,v 1.1 1993/10/02 21:01:09 pk Exp $
+
+x=striptest.xx.$$
+y=striptest.yy.$$
+
+cp $1 $x
+strip $x
+cp $2 $y
+strip $y
+
+doobjcmp $x $y
+exit
+
+#eof
diff --git a/gnu/usr.bin/as/testscripts/dotest b/gnu/usr.bin/as/testscripts/dotest
new file mode 100755
index 0000000..051ee11e
--- /dev/null
+++ b/gnu/usr.bin/as/testscripts/dotest
@@ -0,0 +1,44 @@
+#!/bin/sh
+# ad hoc debug tool
+# $Id: dotest,v 1.1 1993/10/02 21:01:10 pk Exp $
+
+x=$1
+y=$2
+
+xout=`basename $x`.xxx.$$
+yout=`basename $x`.yyy.$$
+
+mkdir $xout
+mkdir $yout
+
+for i in *.s
+do
+ echo Testing $i...
+ object=`basename $i .s`.o
+ $x $i -o $xout/$object
+ $y $i -o $yout/$object
+
+# if they cmp, we're ok. Otherwise we have to look closer.
+
+ if (cmp $xout/$object $yout/$object)
+ then
+ echo $i is ok.
+ else
+ if (doobjcmp $xout/$object $yout/$object)
+ then
+ echo Not the same but objcmp ok.
+ else
+ exit 1
+ fi
+ fi
+
+ echo
+done
+
+rm -rf $xout $yout
+
+exit 0
+
+# EOF
+
+
diff --git a/gnu/usr.bin/as/testscripts/dounsortreloc b/gnu/usr.bin/as/testscripts/dounsortreloc
new file mode 100755
index 0000000..0a4771c
--- /dev/null
+++ b/gnu/usr.bin/as/testscripts/dounsortreloc
@@ -0,0 +1,9 @@
+#!/bin/sh
+# $Id: dounsortreloc,v 1.1 1993/10/02 21:01:11 pk Exp $
+# objdump the reloc table, but strip off the headings and reloc
+# numbers and sort the result. Intended for use in comparing reloc
+# tables that may not be in the same order.
+
+objdump +reloc +omit-relocation-numbers +omit-symbol-numbers $1 \
+ | sort
+#eof
diff --git a/gnu/usr.bin/as/testscripts/dounsortsymbols b/gnu/usr.bin/as/testscripts/dounsortsymbols
new file mode 100755
index 0000000..2dc5acd
--- /dev/null
+++ b/gnu/usr.bin/as/testscripts/dounsortsymbols
@@ -0,0 +1,9 @@
+#!/bin/sh
+# $Id: dounsortsymbols,v 1.1 1993/10/02 21:01:12 pk Exp $
+# objdump the symbol table, but strip off the headings and symbol
+# numbers and sort the result. Intended for use in comparing symbol
+# tables that may not be in the same order.
+
+objdump +symbols +omit-symbol-numbers $1 \
+ | sort
+#eof
diff --git a/gnu/usr.bin/as/version.c b/gnu/usr.bin/as/version.c
new file mode 100644
index 0000000..c18109a
--- /dev/null
+++ b/gnu/usr.bin/as/version.c
@@ -0,0 +1,30 @@
+#if (__STDC__ == 1) || defined(const)
+const
+#endif
+
+/* DO NOT PUT COMMENTS ABOUT CHANGES IN THIS FILE.
+
+ This file exists only to define `version_string'.
+
+ Log changes in ChangeLog. The easiest way to do this is with
+ the Emacs command `add-change-log-entry'. If you don't use Emacs,
+ add entries of the form:
+
+ Thu Jan 1 00:00:00 1970 Dennis Ritchie (dmr at alice)
+
+ universe.c (temporal_reality): Began Time.
+ */
+
+#ifndef lint
+static char rcsid[] = "$Id: version.c,v 1.3 1994/02/14 21:18:05 nate Exp $";
+#endif
+
+char version_string[] = "GNU assembler version 1.92.3, FreeBSD $Revision: 1.3 $\n";
+
+#ifdef HO_VMS
+dummy3()
+{
+}
+#endif
+
+/* end of version.c */
diff --git a/gnu/usr.bin/as/write.c b/gnu/usr.bin/as/write.c
new file mode 100644
index 0000000..66906b0
--- /dev/null
+++ b/gnu/usr.bin/as/write.c
@@ -0,0 +1,1222 @@
+/* write.c - emit .o file
+
+ Copyright (C) 1986, 1987, 1990, 1991, 1992 Free Software Foundation, Inc.
+
+ This file is part of GAS, the GNU Assembler.
+
+ GAS is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GAS is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GAS; see the file COPYING. If not, write to
+ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* This thing should be set up to do byteordering correctly. But... */
+
+#ifndef lint
+static char rcsid[] = "$Id: write.c,v 1.6 1994/12/23 22:36:22 nate Exp $";
+#endif
+
+#include "as.h"
+#include "subsegs.h"
+#include "obstack.h"
+#include "output-file.h"
+
+/* The NOP_OPCODE is for the alignment fill value.
+ * fill it a nop instruction so that the disassembler does not choke
+ * on it
+ */
+#ifndef NOP_OPCODE
+#define NOP_OPCODE 0x00
+#endif
+
+#ifndef MANY_SEGMENTS
+static struct frag *text_frag_root;
+static struct frag *data_frag_root;
+
+static struct frag *text_last_frag; /* Last frag in segment. */
+static struct frag *data_last_frag; /* Last frag in segment. */
+#endif
+
+#ifndef WORKING_DOT_WORD
+extern const int md_short_jump_size;
+extern const int md_long_jump_size;
+#endif
+
+static object_headers headers;
+
+long string_byte_count;
+
+static char *the_object_file;
+
+char *next_object_file_charP; /* Tracks object file bytes. */
+
+/* static long length; JF unused */ /* String length, including trailing '\0'. */
+
+
+#if __STDC__ == 1
+
+static int is_dnrange(struct frag *f1, struct frag *f2);
+static long fixup_segment(fixS *fixP, segT this_segment_type);
+static relax_addressT relax_align(relax_addressT address, long alignment);
+void relax_segment(struct frag *segment_frag_root, segT segment_type);
+
+#else
+
+static int is_dnrange();
+static long fixup_segment();
+static relax_addressT relax_align();
+void relax_segment();
+
+#endif /* not __STDC__ */
+
+/*
+ * fix_new()
+ *
+ * Create a fixS in obstack 'notes'.
+ */
+#ifdef PIC
+fixS *fix_new(frag, where, size, add_symbol, sub_symbol, offset, pcrel, r_type, got_symbol)
+#else
+fixS *fix_new(frag, where, size, add_symbol, sub_symbol, offset, pcrel, r_type)
+#endif
+fragS *frag; /* Which frag? */
+int where; /* Where in that frag? */
+short int size; /* 1, 2, or 4 usually. */
+symbolS *add_symbol; /* X_add_symbol. */
+symbolS *sub_symbol; /* X_subtract_symbol. */
+#ifdef PIC
+symbolS *got_symbol; /* X_got. */
+#endif
+long offset; /* X_add_number. */
+int pcrel; /* TRUE if PC-relative relocation. */
+enum reloc_type r_type; /* Relocation type */
+{
+ fixS *fixP;
+
+ fixP = (fixS *) obstack_alloc(&notes, sizeof(fixS));
+
+ fixP->fx_frag = frag;
+ fixP->fx_where = where;
+ fixP->fx_size = size;
+ fixP->fx_addsy = add_symbol;
+ fixP->fx_subsy = sub_symbol;
+#ifdef PIC
+ fixP->fx_gotsy = got_symbol;
+ if (got_symbol)
+ pcrel = 1;
+#endif
+ fixP->fx_offset = offset;
+ fixP->fx_pcrel = pcrel;
+ fixP->fx_r_type = r_type;
+
+ /* JF these 'cuz of the NS32K stuff */
+ fixP->fx_im_disp = 0;
+ fixP->fx_pcrel_adjust = 0;
+ fixP->fx_bsr = 0;
+ fixP->fx_bit_fixP = 0;
+
+ /* usually, we want relocs sorted numerically, but while
+ comparing to older versions of gas that have relocs
+ reverse sorted, it is convenient to have this compile
+ time option. xoxorich. */
+
+#ifdef REVERSE_SORT_RELOCS
+
+ fixP->fx_next = *seg_fix_rootP;
+ *seg_fix_rootP = fixP;
+
+#else /* REVERSE_SORT_RELOCS */
+
+ fixP->fx_next = NULL;
+
+ if (*seg_fix_tailP)
+ (*seg_fix_tailP)->fx_next = fixP;
+ else
+ *seg_fix_rootP = fixP;
+ *seg_fix_tailP = fixP;
+
+#endif /* REVERSE_SORT_RELOCS */
+
+ fixP->fx_callj = 0;
+ return(fixP);
+} /* fix_new() */
+
+#ifndef BFD
+void write_object_file()
+{
+ register struct frchain * frchainP; /* Track along all frchains. */
+ register fragS * fragP; /* Track along all frags. */
+ register struct frchain * next_frchainP;
+ register fragS * * prev_fragPP;
+ /* register char * name; */
+ /* symbolS *symbolP; */
+ /* register symbolS ** symbolPP; */
+ /* register fixS * fixP; JF unused */
+ unsigned int data_siz;
+
+ long object_file_size;
+
+#ifdef OBJ_VMS
+ /*
+ * Under VMS we try to be compatible with VAX-11 "C". Thus, we
+ * call a routine to check for the definition of the procedure
+ * "_main", and if so -- fix it up so that it can be program
+ * entry point.
+ */
+ VMS_Check_For_Main();
+#endif /* OBJ_VMS */
+ /*
+ * After every sub-segment, we fake an ".align ...". This conforms to BSD4.2
+ * brane-damage. We then fake ".fill 0" because that is the kind of frag
+ * that requires least thought. ".align" frags like to have a following
+ * frag since that makes calculating their intended length trivial.
+ */
+#ifndef SUB_SEGMENT_ALIGN
+#define SUB_SEGMENT_ALIGN (2)
+#endif
+ for (frchainP = frchain_root; frchainP; frchainP = frchainP->frch_next) {
+#ifdef OBJ_VMS
+ /*
+ * Under VAX/VMS, the linker (and PSECT specifications)
+ * take care of correctly aligning the segments.
+ * Doing the alignment here (on initialized data) can
+ * mess up the calculation of global data PSECT sizes.
+ */
+#undef SUB_SEGMENT_ALIGN
+#define SUB_SEGMENT_ALIGN ((frchainP->frch_seg != SEG_DATA) ? 2 : 0)
+#endif /* OBJ_VMS */
+ subseg_new (frchainP->frch_seg, frchainP->frch_subseg);
+ frag_align (SUB_SEGMENT_ALIGN, NOP_OPCODE);
+ /* frag_align will have left a new frag. */
+ /* Use this last frag for an empty ".fill". */
+ /*
+ * For this segment ...
+ * Create a last frag. Do not leave a "being filled in frag".
+ */
+ frag_wane (frag_now);
+ frag_now->fr_fix = 0;
+ know( frag_now->fr_next == NULL );
+ /* know(frags.obstack_c_base == frags.obstack_c_next_free); */
+ /* Above shows we haven't left a half-completed object on obstack. */
+ } /* walk the frag chain */
+
+ /*
+ * From now on, we don't care about sub-segments.
+ * Build one frag chain for each segment. Linked thru fr_next.
+ * We know that there is at least 1 text frchain & at least 1 data frchain.
+ */
+ prev_fragPP = &text_frag_root;
+ for (frchainP = frchain_root; frchainP; frchainP = next_frchainP) {
+ know( frchainP->frch_root );
+ *prev_fragPP = frchainP->frch_root;
+ prev_fragPP = & frchainP->frch_last->fr_next;
+
+ if (((next_frchainP = frchainP->frch_next) == NULL)
+ || next_frchainP == data0_frchainP) {
+ prev_fragPP = &data_frag_root;
+ if (next_frchainP) {
+ text_last_frag = frchainP->frch_last;
+ } else {
+ data_last_frag = frchainP->frch_last;
+ }
+ }
+ } /* walk the frag chain */
+
+ /*
+ * We have two segments. If user gave -R flag, then we must put the
+ * data frags into the text segment. Do this before relaxing so
+ * we know to take advantage of -R and make shorter addresses.
+ */
+ if (flagseen[ 'R' ]) {
+ fixS *tmp;
+
+ text_last_frag->fr_next = data_frag_root;
+ text_last_frag = data_last_frag;
+ data_last_frag = NULL;
+ data_frag_root = NULL;
+ if (text_fix_root) {
+ for (tmp = text_fix_root; tmp->fx_next; tmp = tmp->fx_next) ;;
+ tmp->fx_next = data_fix_root;
+ } else
+ text_fix_root = data_fix_root;
+ data_fix_root = NULL;
+ }
+
+ relax_segment(text_frag_root, SEG_TEXT);
+ relax_segment(data_frag_root, SEG_DATA);
+ /*
+ * Now the addresses of frags are correct within the segment.
+ */
+
+ know(text_last_frag->fr_type == rs_fill && text_last_frag->fr_offset == 0);
+ H_SET_TEXT_SIZE(&headers, text_last_frag->fr_address);
+ text_last_frag->fr_address = H_GET_TEXT_SIZE(&headers);
+
+ /*
+ * Join the 2 segments into 1 huge segment.
+ * To do this, re-compute every rn_address in the SEG_DATA frags.
+ * Then join the data frags after the text frags.
+ *
+ * Determine a_data [length of data segment].
+ */
+ if (data_frag_root) {
+ register relax_addressT slide;
+
+ know((text_last_frag->fr_type == rs_fill) && (text_last_frag->fr_offset == 0));
+
+ H_SET_DATA_SIZE(&headers, data_last_frag->fr_address);
+ data_last_frag->fr_address = H_GET_DATA_SIZE(&headers);
+ slide = H_GET_TEXT_SIZE(&headers); /* & in file of the data segment. */
+
+ for (fragP = data_frag_root; fragP; fragP = fragP->fr_next) {
+ fragP->fr_address += slide;
+ } /* for each data frag */
+
+ know(text_last_frag != 0);
+ text_last_frag->fr_next = data_frag_root;
+ } else {
+ H_SET_DATA_SIZE(&headers,0);
+ data_siz = 0;
+ }
+
+ bss_address_frag.fr_address = (H_GET_TEXT_SIZE(&headers) +
+ H_GET_DATA_SIZE(&headers));
+
+ H_SET_BSS_SIZE(&headers,local_bss_counter);
+
+ /*
+ *
+ * Crawl the symbol chain.
+ *
+ * For each symbol whose value depends on a frag, take the address of
+ * that frag and subsume it into the value of the symbol.
+ * After this, there is just one way to lookup a symbol value.
+ * Values are left in their final state for object file emission.
+ * We adjust the values of 'L' local symbols, even if we do
+ * not intend to emit them to the object file, because their values
+ * are needed for fix-ups.
+ *
+ * Unless we saw a -L flag, remove all symbols that begin with 'L'
+ * from the symbol chain. (They are still pointed to by the fixes.)
+ *
+ * Count the remaining symbols.
+ * Assign a symbol number to each symbol.
+ * Count the number of string-table chars we will emit.
+ * Put this info into the headers as appropriate.
+ *
+ */
+ know(zero_address_frag.fr_address == 0);
+ string_byte_count = sizeof(string_byte_count);
+
+ obj_crawl_symbol_chain(&headers);
+
+ if (string_byte_count == sizeof(string_byte_count)) {
+ string_byte_count = 0;
+ } /* if no strings, then no count. */
+
+ H_SET_STRING_SIZE(&headers, string_byte_count);
+
+ /*
+ * Addresses of frags now reflect addresses we use in the object file.
+ * Symbol values are correct.
+ * Scan the frags, converting any ".org"s and ".align"s to ".fill"s.
+ * Also converting any machine-dependent frags using md_convert_frag();
+ */
+ subseg_change(SEG_TEXT, 0);
+
+ for (fragP = text_frag_root; fragP; fragP = fragP->fr_next) {
+ switch (fragP->fr_type) {
+ case rs_align:
+ case rs_org:
+ fragP->fr_type = rs_fill;
+ know(fragP->fr_var == 1);
+ know(fragP->fr_next != NULL);
+
+ fragP->fr_offset = (fragP->fr_next->fr_address
+ - fragP->fr_address
+ - fragP->fr_fix);
+ break;
+
+ case rs_fill:
+ break;
+
+ case rs_machine_dependent:
+ md_convert_frag(&headers, fragP);
+
+ know((fragP->fr_next == NULL) || ((fragP->fr_next->fr_address - fragP->fr_address) == fragP->fr_fix));
+
+ /*
+ * After md_convert_frag, we make the frag into a ".space 0".
+ * Md_convert_frag() should set up any fixSs and constants
+ * required.
+ */
+ frag_wane(fragP);
+ break;
+
+#ifndef WORKING_DOT_WORD
+ case rs_broken_word: {
+ struct broken_word *lie;
+
+ if (fragP->fr_subtype) {
+ fragP->fr_fix+=md_short_jump_size;
+ for (lie=(struct broken_word *)(fragP->fr_symbol);lie && lie->dispfrag == fragP;lie=lie->next_broken_word)
+ if (lie->added == 1)
+ fragP->fr_fix+=md_long_jump_size;
+ }
+ frag_wane(fragP);
+ }
+ break;
+#endif
+
+ default:
+ BAD_CASE( fragP->fr_type );
+ break;
+ } /* switch (fr_type) */
+
+ know((fragP->fr_next == NULL)
+ || ((fragP->fr_next->fr_address - fragP->fr_address)
+ == (fragP->fr_fix + (fragP->fr_offset * fragP->fr_var))));
+ } /* for each frag. */
+
+#ifndef WORKING_DOT_WORD
+ {
+ struct broken_word *lie;
+ struct broken_word **prevP;
+
+ prevP = &broken_words;
+ for (lie = broken_words; lie; lie = lie->next_broken_word)
+ if (!lie->added) {
+#ifdef TC_NS32K
+ fix_new_ns32k(lie->frag,
+ lie->word_goes_here - lie->frag->fr_literal,
+ 2,
+ lie->add,
+ lie->sub,
+ lie->addnum,
+ 0, 0, 2, 0, 0, NO_RELOC);
+#else /* TC_NS32K */
+#ifdef PIC
+ fix_new(lie->frag, lie->word_goes_here - lie->frag->fr_literal,
+ 2, lie->add,
+ lie->sub, lie->addnum,
+ 0, NO_RELOC, (symbolS *)0);
+#else
+ fix_new(lie->frag, lie->word_goes_here - lie->frag->fr_literal,
+ 2, lie->add,
+ lie->sub, lie->addnum,
+ 0, NO_RELOC);
+#endif
+#endif /* TC_NS32K */
+ /* md_number_to_chars(lie->word_goes_here,
+ S_GET_VALUE(lie->add)
+ + lie->addnum
+ - S_GET_VALUE(lie->sub),
+ 2); */
+ *prevP = lie->next_broken_word;
+ } else
+ prevP = &(lie->next_broken_word);
+
+ for (lie = broken_words; lie;) {
+ struct broken_word *untruth;
+ char *table_ptr;
+ long table_addr;
+ long from_addr,
+ to_addr;
+ int n,
+ m;
+
+ fragP = lie->dispfrag;
+
+ /* Find out how many broken_words go here */
+ n=0;
+ for (untruth = lie; untruth && untruth->dispfrag == fragP; untruth = untruth->next_broken_word)
+ if (untruth->added == 1)
+ n++;
+
+ table_ptr = lie->dispfrag->fr_opcode;
+ table_addr = lie->dispfrag->fr_address + (table_ptr - lie->dispfrag->fr_literal);
+ /* Create the jump around the long jumps */
+ /* This is a short jump from table_ptr+0 to table_ptr+n*long_jump_size */
+ from_addr = table_addr;
+ to_addr = table_addr + md_short_jump_size + n * md_long_jump_size;
+ md_create_short_jump(table_ptr, from_addr, to_addr, lie->dispfrag, lie->add);
+ table_ptr += md_short_jump_size;
+ table_addr += md_short_jump_size;
+
+ for (m = 0; lie && lie->dispfrag == fragP; m++, lie = lie->next_broken_word) {
+ if (lie->added == 2)
+ continue;
+ /* Patch the jump table */
+ /* This is the offset from ??? to table_ptr+0 */
+ to_addr = table_addr
+ - S_GET_VALUE(lie->sub);
+ md_number_to_chars(lie->word_goes_here, to_addr, 2);
+ for (untruth = lie->next_broken_word;
+ untruth && untruth->dispfrag == fragP;
+ untruth = untruth->next_broken_word) {
+ if (untruth->use_jump == lie)
+ md_number_to_chars(untruth->word_goes_here, to_addr, 2);
+ }
+
+ /* Install the long jump */
+ /* this is a long jump from table_ptr+0 to the final target */
+ from_addr = table_addr;
+ to_addr = S_GET_VALUE(lie->add) + lie->addnum;
+ md_create_long_jump(table_ptr, from_addr, to_addr, lie->dispfrag, lie->add);
+ table_ptr += md_long_jump_size;
+ table_addr += md_long_jump_size;
+ }
+ }
+ }
+#endif /* not WORKING_DOT_WORD */
+
+#ifndef OBJ_VMS
+ { /* not vms */
+ /*
+ * Scan every FixS performing fixups. We had to wait until now to do
+ * this because md_convert_frag() may have made some fixSs.
+ */
+
+ H_SET_RELOCATION_SIZE(&headers,
+ md_reloc_size * fixup_segment(text_fix_root, SEG_TEXT),
+ md_reloc_size * fixup_segment(data_fix_root, SEG_DATA));
+
+
+ obj_pre_write_hook(&headers);
+
+ if ((had_warnings() && flagseen['Z'])
+ || had_errors() > 0) {
+ if (flagseen['Z']) {
+ as_warn("%d error%s, %d warning%s, generating bad object file.\n",
+ had_errors(), had_errors() == 1 ? "" : "s",
+ had_warnings(), had_warnings() == 1 ? "" : "s");
+ } else {
+ as_fatal("%d error%s, %d warning%s, no object file generated.\n",
+ had_errors(), had_errors() == 1 ? "" : "s",
+ had_warnings(), had_warnings() == 1 ? "" : "s");
+ } /* on want output */
+ } /* on error condition */
+
+ object_file_size = H_GET_FILE_SIZE(&headers);
+ next_object_file_charP = the_object_file = xmalloc(object_file_size);
+
+ output_file_create(out_file_name);
+
+ obj_header_append(&next_object_file_charP, &headers);
+
+ know((next_object_file_charP - the_object_file) == H_GET_HEADER_SIZE(&headers));
+
+ /*
+ * Emit code.
+ */
+ for (fragP = text_frag_root; fragP; fragP = fragP->fr_next) {
+ register long count;
+ register char *fill_literal;
+ register long fill_size;
+
+ know(fragP->fr_type == rs_fill);
+ append(&next_object_file_charP, fragP->fr_literal, (unsigned long) fragP->fr_fix);
+ fill_literal = fragP->fr_literal + fragP->fr_fix;
+ fill_size = fragP->fr_var;
+ know(fragP->fr_offset >= 0);
+
+ for (count = fragP->fr_offset; count; count--) {
+ append(&next_object_file_charP, fill_literal, (unsigned long) fill_size);
+ } /* for each */
+
+ } /* for each code frag. */
+
+ know((next_object_file_charP - the_object_file) == (H_GET_HEADER_SIZE(&headers) + H_GET_TEXT_SIZE(&headers) + H_GET_DATA_SIZE(&headers)));
+
+ /*
+ * Emit relocations.
+ */
+ obj_emit_relocations(&next_object_file_charP, text_fix_root, (relax_addressT)0);
+ know((next_object_file_charP - the_object_file) == (H_GET_HEADER_SIZE(&headers) + H_GET_TEXT_SIZE(&headers) + H_GET_DATA_SIZE(&headers) + H_GET_TEXT_RELOCATION_SIZE(&headers)));
+#ifdef TC_I960
+ /* Make addresses in data relocation directives relative to beginning of
+ * first data fragment, not end of last text fragment: alignment of the
+ * start of the data segment may place a gap between the segments.
+ */
+ obj_emit_relocations(&next_object_file_charP, data_fix_root, data0_frchainP->frch_root->fr_address);
+#else /* TC_I960 */
+ obj_emit_relocations(&next_object_file_charP, data_fix_root, text_last_frag->fr_address);
+#endif /* TC_I960 */
+
+ know((next_object_file_charP - the_object_file) == (H_GET_HEADER_SIZE(&headers) + H_GET_TEXT_SIZE(&headers) + H_GET_DATA_SIZE(&headers) + H_GET_TEXT_RELOCATION_SIZE(&headers) + H_GET_DATA_RELOCATION_SIZE(&headers)));
+
+ /*
+ * Emit line number entries.
+ */
+ OBJ_EMIT_LINENO(&next_object_file_charP, lineno_rootP, the_object_file);
+ know((next_object_file_charP - the_object_file) == (H_GET_HEADER_SIZE(&headers) + H_GET_TEXT_SIZE(&headers) + H_GET_DATA_SIZE(&headers) + H_GET_TEXT_RELOCATION_SIZE(&headers) + H_GET_DATA_RELOCATION_SIZE(&headers) + H_GET_LINENO_SIZE(&headers)));
+
+ /*
+ * Emit symbols.
+ */
+ obj_emit_symbols(&next_object_file_charP, symbol_rootP);
+ know((next_object_file_charP - the_object_file) == (H_GET_HEADER_SIZE(&headers) + H_GET_TEXT_SIZE(&headers) + H_GET_DATA_SIZE(&headers) + H_GET_TEXT_RELOCATION_SIZE(&headers) + H_GET_DATA_RELOCATION_SIZE(&headers) + H_GET_LINENO_SIZE(&headers) + H_GET_SYMBOL_TABLE_SIZE(&headers)));
+
+ /*
+ * Emit strings.
+ */
+
+ if (string_byte_count > 0) {
+ obj_emit_strings(&next_object_file_charP);
+ } /* only if we have a string table */
+
+ /* know((next_object_file_charP - the_object_file) == (H_GET_HEADER_SIZE(&headers) + H_GET_TEXT_SIZE(&headers) + H_GET_DATA_SIZE(&headers) + H_GET_TEXT_RELOCATION_SIZE(&headers) + H_GET_DATA_RELOCATION_SIZE(&headers) + H_GET_LINENO_SIZE(&headers) + H_GET_SYMBOL_TABLE_SIZE(&headers) + H_GET_STRING_SIZE(&headers)));
+ */
+ /* know(next_object_file_charP == the_object_file + object_file_size);*/
+
+#ifdef BFD_HEADERS
+ bfd_seek(stdoutput, 0, 0);
+ bfd_write(the_object_file, 1, object_file_size, stdoutput);
+#else
+
+ /* Write the data to the file */
+ output_file_append(the_object_file, object_file_size, out_file_name);
+#endif
+
+ output_file_close(out_file_name);
+ } /* non vms output */
+#else /* OBJ_VMS */
+ /*
+ * Now do the VMS-dependent part of writing the object file
+ */
+ VMS_write_object_file(H_GET_TEXT_SIZE(&headers), H_GET_DATA_SIZE(&headers),
+ text_frag_root, data_frag_root);
+#endif /* OBJ_VMS */
+} /* write_object_file() */
+#else
+#endif
+
+/*
+ * relax_segment()
+ *
+ * Now we have a segment, not a crowd of sub-segments, we can make fr_address
+ * values.
+ *
+ * Relax the frags.
+ *
+ * After this, all frags in this segment have addresses that are correct
+ * within the segment. Since segments live in different file addresses,
+ * these frag addresses may not be the same as final object-file addresses.
+ */
+
+
+
+void relax_segment(segment_frag_root, segment)
+struct frag * segment_frag_root;
+segT segment; /* SEG_DATA or SEG_TEXT */
+{
+ register struct frag * fragP;
+ register relax_addressT address;
+ /* register relax_addressT old_address; JF unused */
+ /* register relax_addressT new_address; JF unused */
+#ifndef MANY_SEGMENTS
+ know(segment == SEG_DATA || segment == SEG_TEXT);
+#endif
+ /* In case md_estimate_size_before_relax() wants to make fixSs. */
+ subseg_change(segment, 0);
+
+ /*
+ * For each frag in segment: count and store (a 1st guess of) fr_address.
+ */
+ address = 0;
+ for (fragP = segment_frag_root; fragP; fragP = fragP->fr_next) {
+ fragP->fr_address = address;
+ address += fragP->fr_fix;
+
+ switch (fragP->fr_type) {
+ case rs_fill:
+ address += fragP->fr_offset * fragP->fr_var ;
+ break;
+
+ case rs_align:
+ address += relax_align(address, fragP->fr_offset);
+ break;
+
+ case rs_org:
+ /*
+ * Assume .org is nugatory. It will grow with 1st relax.
+ */
+ break;
+
+ case rs_machine_dependent:
+ address += md_estimate_size_before_relax(fragP, segment);
+ break;
+
+#ifndef WORKING_DOT_WORD
+ /* Broken words don't concern us yet */
+ case rs_broken_word:
+ break;
+#endif
+
+ default:
+ BAD_CASE(fragP->fr_type);
+ break;
+ } /* switch (fr_type) */
+ } /* for each frag in the segment */
+
+ /*
+ * Do relax().
+ */
+ {
+ register long stretch; /* May be any size, 0 or negative. */
+ /* Cumulative number of addresses we have */
+ /* relaxed this pass. */
+ /* We may have relaxed more than one address. */
+ register long stretched; /* Have we stretched on this pass? */
+ /* This is 'cuz stretch may be zero, when,
+ in fact some piece of code grew, and
+ another shrank. If a branch instruction
+ doesn't fit anymore, we could be scrod */
+
+ do {
+ stretch = stretched = 0;
+ for (fragP = segment_frag_root; fragP; fragP = fragP->fr_next) {
+ register long growth = 0;
+ register unsigned long was_address;
+ register long offset;
+ register symbolS *symbolP;
+ register long target;
+ register long after;
+ register long aim;
+
+ was_address = fragP->fr_address;
+ address = fragP->fr_address += stretch;
+ symbolP = fragP->fr_symbol;
+ offset = fragP->fr_offset;
+
+ switch (fragP->fr_type) {
+ case rs_fill: /* .fill never relaxes. */
+ growth = 0;
+ break;
+
+#ifndef WORKING_DOT_WORD
+ /* JF: This is RMS's idea. I do *NOT* want to be blamed
+ for it I do not want to write it. I do not want to have
+ anything to do with it. This is not the proper way to
+ implement this misfeature. */
+ case rs_broken_word: {
+ struct broken_word *lie;
+ struct broken_word *untruth;
+
+ /* Yes this is ugly (storing the broken_word pointer
+ in the symbol slot). Still, this whole chunk of
+ code is ugly, and I don't feel like doing anything
+ about it. Think of it as stubbornness in action */
+ growth=0;
+ for (lie=(struct broken_word *)(fragP->fr_symbol);
+ lie && lie->dispfrag == fragP;
+ lie=lie->next_broken_word) {
+
+ if (lie->added)
+ continue;
+
+ offset = lie->add->sy_frag->fr_address+ S_GET_VALUE(lie->add) + lie->addnum -
+ (lie->sub->sy_frag->fr_address+ S_GET_VALUE(lie->sub));
+ if (offset <= -32768 || offset >= 32767) {
+ if (flagseen['K'])
+ as_warn(".word %s-%s+%ld didn't fit",
+ S_GET_NAME(lie->add),
+ S_GET_NAME(lie->sub),
+ lie->addnum);
+ lie->added=1;
+ if (fragP->fr_subtype == 0) {
+ fragP->fr_subtype++;
+ growth+=md_short_jump_size;
+ }
+ for (untruth=lie->next_broken_word;untruth && untruth->dispfrag == lie->dispfrag;untruth=untruth->next_broken_word)
+ if ((untruth->add->sy_frag == lie->add->sy_frag)
+ && S_GET_VALUE(untruth->add) == S_GET_VALUE(lie->add)) {
+ untruth->added=2;
+ untruth->use_jump=lie;
+ }
+ growth += md_long_jump_size;
+ }
+ }
+
+ break;
+ } /* case rs_broken_word */
+#endif
+ case rs_align:
+ growth = relax_align((relax_addressT) (address + fragP->fr_fix), offset)
+ - relax_align((relax_addressT) (was_address + fragP->fr_fix), offset);
+ break;
+
+ case rs_org:
+ target = offset;
+
+ if (symbolP) {
+#ifdef MANY_SEGMENTS
+#else
+ know((S_GET_SEGMENT(symbolP) == SEG_ABSOLUTE) || (S_GET_SEGMENT(symbolP) == SEG_DATA) || (S_GET_SEGMENT(symbolP) == SEG_TEXT));
+ know(symbolP->sy_frag);
+ know(!(S_GET_SEGMENT(symbolP) == SEG_ABSOLUTE) || (symbolP->sy_frag == &zero_address_frag));
+#endif
+ target += S_GET_VALUE(symbolP)
+ + symbolP->sy_frag->fr_address;
+ } /* if we have a symbol */
+
+ know(fragP->fr_next);
+ after = fragP->fr_next->fr_address;
+ growth = ((target - after ) > 0) ? (target - after) : 0;
+ /* Growth may be -ve, but variable part */
+ /* of frag cannot have < 0 chars. */
+ /* That is, we can't .org backwards. */
+
+ growth -= stretch; /* This is an absolute growth factor */
+ break;
+
+ case rs_machine_dependent: {
+ register const relax_typeS * this_type;
+ register const relax_typeS * start_type;
+ register relax_substateT next_state;
+ register relax_substateT this_state;
+
+ start_type = this_type = md_relax_table + (this_state = fragP->fr_subtype);
+ target = offset;
+
+ if (symbolP) {
+#ifndef MANY_SEGMENTS
+ know((S_GET_SEGMENT(symbolP) == SEG_ABSOLUTE) || (S_GET_SEGMENT(symbolP) == SEG_DATA) || (S_GET_SEGMENT(symbolP) == SEG_TEXT));
+#endif
+ know(symbolP->sy_frag);
+ know(!(S_GET_SEGMENT(symbolP) == SEG_ABSOLUTE) || symbolP->sy_frag == &zero_address_frag );
+ target +=
+ S_GET_VALUE(symbolP)
+ + symbolP->sy_frag->fr_address;
+
+ /* If frag has yet to be reached on this pass,
+ assume it will move by STRETCH just as we did.
+ If this is not so, it will be because some frag
+ between grows, and that will force another pass. */
+
+ /* JF was just address */
+ /* JF also added is_dnrange hack */
+ /* There's gotta be a better/faster/etc way
+ to do this... */
+ /* gnu@cygnus.com: I changed this from > to >=
+ because I ran into a zero-length frag (fr_fix=0)
+ which was created when the obstack needed a new
+ chunk JUST AFTER the opcode of a branch. Since
+ fr_fix is zero, fr_address of this frag is the same
+ as fr_address of the next frag. This
+ zero-length frag was variable and jumped to .+2
+ (in the next frag), but since the > comparison
+ below failed (the two were =, not >), "stretch"
+ was not added to the target. Stretch was 178, so
+ the offset appeared to be .-176 instead, which did
+ not fit into a byte branch, so the assembler
+ relaxed the branch to a word. This didn't compare
+ with what happened when the same source file was
+ assembled on other machines, which is how I found it.
+ You might want to think about what other places have
+ trouble with zero length frags... */
+
+ if (symbolP->sy_frag->fr_address >= was_address
+ && is_dnrange(fragP,symbolP->sy_frag)) {
+ target += stretch;
+ } /* */
+
+ } /* if there's a symbol attached */
+
+ aim = target - address - fragP->fr_fix;
+ /* The displacement is affected by the instruction size
+ * for the 32k architecture. I think we ought to be able
+ * to add fragP->fr_pcrel_adjust in all cases (it should be
+ * zero if not used), but just in case it breaks something
+ * else we'll put this inside #ifdef NS32K ... #endif
+ */
+#ifdef TC_NS32K
+ aim += fragP->fr_pcrel_adjust;
+#endif /* TC_NS32K */
+
+ if (aim < 0) {
+ /* Look backwards. */
+ for (next_state = this_type->rlx_more; next_state; ) {
+ if (aim >= this_type->rlx_backward) {
+ next_state = 0;
+ } else { /* Grow to next state. */
+ this_type = md_relax_table + (this_state = next_state);
+ next_state = this_type->rlx_more;
+ }
+ }
+ } else {
+#ifdef DONTDEF
+ /* JF these next few lines of code are for the mc68020 which can't handle short
+ offsets of zero in branch instructions. What a kludge! */
+ if (aim == 0 && this_state == (1<<2+0)) { /* FOO hard encoded from m.c */
+ aim=this_type->rlx_forward+1; /* Force relaxation into word mode */
+ }
+#endif
+#ifdef M68K_AIM_KLUDGE
+ M68K_AIM_KLUDGE(aim, this_state, this_type);
+#endif
+ /* JF end of 68020 code */
+ /* Look forwards. */
+ for (next_state = this_type->rlx_more; next_state; ) {
+ if (aim <= this_type->rlx_forward) {
+ next_state = 0;
+ } else { /* Grow to next state. */
+ this_type = md_relax_table + (this_state = next_state);
+ next_state = this_type->rlx_more;
+ }
+ }
+ }
+
+ if ((growth = this_type->rlx_length - start_type->rlx_length) != 0)
+ fragP->fr_subtype = this_state;
+
+ break;
+ } /* case rs_machine_dependent */
+
+ default:
+ BAD_CASE( fragP->fr_type );
+ break;
+ }
+ if (growth) {
+ stretch += growth;
+ stretched++;
+ }
+ } /* For each frag in the segment. */
+ } while (stretched); /* Until nothing further to relax. */
+ } /* do_relax */
+
+ /*
+ * We now have valid fr_address'es for each frag.
+ */
+
+ /*
+ * All fr_address's are correct, relative to their own segment.
+ * We have made all the fixS we will ever make.
+ */
+} /* relax_segment() */
+
+/*
+ * Relax_align. Advance location counter to next address that has 'alignment'
+ * lowest order bits all 0s.
+ */
+
+/* How many addresses does the .align take? */
+static relax_addressT relax_align(address, alignment)
+register relax_addressT address; /* Address now. */
+register long alignment; /* Alignment (binary). */
+{
+ relax_addressT mask;
+ relax_addressT new_address;
+
+ mask = ~ ( (~0) << alignment );
+ new_address = (address + mask) & (~ mask);
+ return (new_address - address);
+} /* relax_align() */
+
+/* fixup_segment()
+
+ Go through all the fixS's in a segment and see which ones can be
+ handled now. (These consist of fixS where we have since discovered
+ the value of a symbol, or the address of the frag involved.)
+ For each one, call md_apply_fix to put the fix into the frag data.
+
+ Result is a count of how many relocation structs will be needed to
+ handle the remaining fixS's that we couldn't completely handle here.
+ These will be output later by emit_relocations(). */
+
+static long fixup_segment(fixP, this_segment_type)
+register fixS *fixP;
+segT this_segment_type; /* N_TYPE bits for segment. */
+{
+ register long seg_reloc_count;
+ register symbolS *add_symbolP;
+ register symbolS *sub_symbolP;
+ register long add_number;
+ register int size;
+ register char *place;
+ register long where;
+ register char pcrel;
+ register fragS *fragP;
+ register segT add_symbol_segment = SEG_ABSOLUTE;
+
+ /* FIXME: remove this line */ /* fixS *orig = fixP; */
+ seg_reloc_count = 0;
+
+ for ( ; fixP; fixP = fixP->fx_next) {
+ fragP = fixP->fx_frag;
+ know(fragP);
+ where = fixP->fx_where;
+ place = fragP->fr_literal + where;
+ size = fixP->fx_size;
+ add_symbolP = fixP->fx_addsy;
+#ifdef TC_I960
+ if (fixP->fx_callj && TC_S_IS_CALLNAME(add_symbolP)) {
+ /* Relocation should be done via the
+ associated 'bal' entry point
+ symbol. */
+
+ if (!TC_S_IS_BALNAME(tc_get_bal_of_call(add_symbolP))) {
+ as_bad("No 'bal' entry point for leafproc %s",
+ S_GET_NAME(add_symbolP));
+ continue;
+ }
+ fixP->fx_addsy = add_symbolP = tc_get_bal_of_call(add_symbolP);
+ } /* callj relocation */
+#endif
+ sub_symbolP = fixP->fx_subsy;
+ add_number = fixP->fx_offset;
+ pcrel = fixP->fx_pcrel;
+
+ if (add_symbolP) {
+ add_symbol_segment = S_GET_SEGMENT(add_symbolP);
+ } /* if there is an addend */
+
+ if (sub_symbolP) {
+ if (!add_symbolP) {
+ /* Its just -sym */
+ if (S_GET_SEGMENT(sub_symbolP) != SEG_ABSOLUTE) {
+ as_bad("Negative of non-absolute symbol %s", S_GET_NAME(sub_symbolP));
+ } /* not absolute */
+
+ add_number -= S_GET_VALUE(sub_symbolP);
+
+ /* if sub_symbol is in the same segment that add_symbol
+ and add_symbol is either in DATA, TEXT, BSS or ABSOLUTE */
+ } else if ((S_GET_SEGMENT(sub_symbolP) == add_symbol_segment)
+ && (SEG_NORMAL(add_symbol_segment)
+ || (add_symbol_segment == SEG_ABSOLUTE))) {
+ /* Difference of 2 symbols from same segment. */
+ /* Can't make difference of 2 undefineds: 'value' means */
+ /* something different for N_UNDF. */
+#ifdef TC_I960
+ /* Makes no sense to use the difference of 2 arbitrary symbols
+ * as the target of a call instruction.
+ */
+ if (fixP->fx_callj) {
+ as_bad("callj to difference of 2 symbols");
+ }
+#endif /* TC_I960 */
+#ifdef PIC
+ if (flagseen['k'] &&
+ S_IS_EXTERNAL(add_symbolP)) {
+ as_bad("Can't reduce difference of external symbols in PIC code");
+ }
+#endif
+ add_number += S_GET_VALUE(add_symbolP) -
+ S_GET_VALUE(sub_symbolP);
+
+ add_symbolP = NULL;
+ fixP->fx_addsy = NULL;
+ } else {
+ /* Different segments in subtraction. */
+ know(!(S_IS_EXTERNAL(sub_symbolP) && (S_GET_SEGMENT(sub_symbolP) == SEG_ABSOLUTE)));
+
+ if ((S_GET_SEGMENT(sub_symbolP) == SEG_ABSOLUTE)) {
+ add_number -= S_GET_VALUE(sub_symbolP);
+ } else {
+ as_bad("Can't emit reloc {- %s-seg symbol \"%s\"} @ file address %d.",
+ segment_name(S_GET_SEGMENT(sub_symbolP)),
+ S_GET_NAME(sub_symbolP), fragP->fr_address + where);
+ } /* if absolute */
+ }
+ } /* if sub_symbolP */
+
+#ifdef PIC
+ /*
+ * Bring _GLOBAL_OFFSET_TABLE_ forward, now we've had the
+ * chance to collapse any accompanying symbols into a number.
+ * This is the sequel of the hack in expr.c to parse operands
+ * of the form `_GLOBAL_OFFSET_TABLE_+(L1-L2)'. Note that
+ * _GLOBAL_OFFSET_TABLE_ can only be an "add symbol".
+ */
+ if (add_symbolP == NULL && fixP->fx_gotsy != NULL) {
+ add_symbolP = fixP->fx_addsy = fixP->fx_gotsy;
+ add_symbol_segment = S_GET_SEGMENT(add_symbolP);
+ }
+#endif
+
+ if (add_symbolP) {
+ if (add_symbol_segment == this_segment_type && pcrel) {
+ /*
+ * This fixup was made when the symbol's segment was
+ * SEG_UNKNOWN, but it is now in the local segment.
+ * So we know how to do the address without relocation.
+ */
+#ifdef TC_I960
+ /* reloc_callj() may replace a 'call' with a 'calls' or a 'bal',
+ * in which cases it modifies *fixP as appropriate. In the case
+ * of a 'calls', no further work is required, and *fixP has been
+ * set up to make the rest of the code below a no-op.
+ */
+ reloc_callj(fixP);
+#endif /* TC_I960 */
+
+ add_number += S_GET_VALUE(add_symbolP);
+ add_number -= md_pcrel_from(fixP);
+ pcrel = 0; /* Lie. Don't want further pcrel processing. */
+ fixP->fx_addsy = NULL; /* No relocations please. */
+ } else {
+ switch (add_symbol_segment) {
+ case SEG_ABSOLUTE:
+#ifdef TC_I960
+ reloc_callj(fixP); /* See comment about reloc_callj() above*/
+#endif /* TC_I960 */
+ add_number += S_GET_VALUE(add_symbolP);
+ fixP->fx_addsy = NULL;
+ add_symbolP = NULL;
+ break;
+ default:
+ seg_reloc_count ++;
+#ifdef PIC
+ /*
+ * Do not fixup refs to global data
+ * even if defined here.
+ */
+ if (!flagseen['k'] ||
+#ifdef TC_NS32K
+ fixP->fx_pcrel ||
+#endif
+ (fixP->fx_r_type != RELOC_GLOB_DAT &&
+#ifdef TC_I386
+/* XXX - This must be rationalized */
+ fixP->fx_r_type != RELOC_GOT &&
+ fixP->fx_r_type != RELOC_GOTOFF &&
+#endif
+ (fixP->fx_r_type != RELOC_32 ||
+ !S_IS_EXTERNAL(add_symbolP))))
+#endif
+ add_number += S_GET_VALUE(add_symbolP);
+ break;
+
+ case SEG_UNKNOWN:
+#ifdef TC_I960
+ if ((int)fixP->fx_bit_fixP == 13) {
+ /* This is a COBR instruction. They have only a
+ * 13-bit displacement and are only to be used
+ * for local branches: flag as error, don't generate
+ * relocation.
+ */
+ as_bad("can't use COBR format with external label");
+ fixP->fx_addsy = NULL; /* No relocations please. */
+ continue;
+ } /* COBR */
+#endif /* TC_I960 */
+
+#ifdef OBJ_COFF
+#ifdef TE_I386AIX
+ if (S_IS_COMMON(add_symbolP))
+ add_number += S_GET_VALUE(add_symbolP);
+#endif /* TE_I386AIX */
+#endif /* OBJ_COFF */
+ ++seg_reloc_count;
+
+ break;
+
+
+ } /* switch on symbol seg */
+ } /* if not in local seg */
+ } /* if there was a + symbol */
+
+ if (pcrel) {
+ add_number -= md_pcrel_from(fixP);
+ if (add_symbolP == 0) {
+ fixP->fx_addsy = & abs_symbol;
+ ++seg_reloc_count;
+ } /* if there's an add_symbol */
+ } /* if pcrel */
+
+ if (!fixP->fx_bit_fixP) {
+ if ((size == 1 &&
+ (add_number& ~0xFF) && (add_number & ~0xFF != (-1 & ~0xFF))) ||
+ (size == 2 &&
+ (add_number& ~0xFFFF) && (add_number & ~0xFFFF != (-1 & ~0xFFFF)))) {
+ as_bad("Value of %d too large for field of %d bytes at 0x%x",
+ add_number, size, fragP->fr_address + where);
+ } /* generic error checking */
+ } /* not a bit fix */
+
+ md_apply_fix(fixP, add_number);
+ } /* For each fixS in this segment. */
+
+#ifdef OBJ_COFF
+#ifdef TC_I960
+ {
+ fixS *topP = fixP;
+
+ /* two relocs per callj under coff. */
+ for (fixP = topP; fixP; fixP = fixP->fx_next) {
+ if (fixP->fx_callj && fixP->fx_addsy != 0) {
+ ++seg_reloc_count;
+ } /* if callj and not already fixed. */
+ } /* for each fix */
+ }
+#endif /* TC_I960 */
+
+#endif /* OBJ_COFF */
+ return(seg_reloc_count);
+} /* fixup_segment() */
+
+
+static int is_dnrange(f1,f2)
+struct frag *f1;
+struct frag *f2;
+{
+ while (f1) {
+ if (f1->fr_next == f2)
+ return 1;
+ f1=f1->fr_next;
+ }
+ return 0;
+} /* is_dnrange() */
+
+/* Append a string onto another string, bumping the pointer along. */
+void
+ append (charPP, fromP, length)
+char **charPP;
+char *fromP;
+unsigned long length;
+{
+ if (length) { /* Don't trust memcpy() of 0 chars. */
+ memcpy(*charPP, fromP, (int) length);
+ *charPP += length;
+ }
+}
+
+int section_alignment[SEG_MAXIMUM_ORDINAL];
+
+/*
+ * This routine records the largest alignment seen for each segment.
+ * If the beginning of the segment is aligned on the worst-case
+ * boundary, all of the other alignments within it will work. At
+ * least one object format really uses this info.
+ */
+void record_alignment(seg, align)
+segT seg; /* Segment to which alignment pertains */
+int align; /* Alignment, as a power of 2
+ * (e.g., 1 => 2-byte boundary, 2 => 4-byte boundary, etc.)
+ */
+{
+
+ if ( align > section_alignment[(int) seg] ){
+ section_alignment[(int) seg] = align;
+ } /* if highest yet */
+
+ return;
+} /* record_alignment() */
+
+/*
+ * Local Variables:
+ * comment-column: 0
+ * fill-column: 131
+ * End:
+ */
+
+/* end of write.c */
diff --git a/gnu/usr.bin/as/write.h b/gnu/usr.bin/as/write.h
new file mode 100644
index 0000000..8b51880
--- /dev/null
+++ b/gnu/usr.bin/as/write.h
@@ -0,0 +1,120 @@
+/* write.h
+
+ Copyright (C) 1987, 1992 Free Software Foundation, Inc.
+
+ This file is part of GAS, the GNU Assembler.
+
+ GAS is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GAS is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GAS; see the file COPYING. If not, write to
+ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+/*
+ * write.h,v 1.3 1993/10/02 20:58:02 pk Exp
+ */
+
+
+#ifndef TC_I960
+#ifdef hpux
+#define EXEC_MACHINE_TYPE HP9000S200_ID
+#endif
+#endif /* TC_I960 */
+
+#ifndef LOCAL_LABEL
+#ifdef DOT_LABEL_PREFIX
+#define LOCAL_LABEL(name) (name[0] == '.' \
+ && (name[1] == 'L' || name[1] == '.'))
+#else /* not defined DOT_LABEL_PREFIX */
+#define LOCAL_LABEL(name) (name[0] == 'L')
+#endif /* not defined DOT_LABEL_PREFIX */
+#endif /* LOCAL_LABEL */
+
+#define S_LOCAL_NAME(s) (LOCAL_LABEL(S_GET_NAME(s)))
+
+#include "bit_fix.h"
+
+/*
+ * FixSs may be built up in any order.
+ */
+
+struct fix {
+ fragS *fx_frag; /* Which frag? */
+ long fx_where; /* Where is the 1st byte to fix up? */
+ symbolS *fx_addsy; /* NULL or Symbol whose value we add in. */
+ symbolS *fx_subsy; /* NULL or Symbol whose value we subtract. */
+#ifdef PIC
+ symbolS *fx_gotsy; /* NULL or __GLOBAL_OFFSET_TABLE_ . */
+#endif
+ long fx_offset; /* Absolute number we add in. */
+ struct fix *fx_next; /* NULL or -> next fixS. */
+ short int fx_size; /* How many bytes are involved? */
+ char fx_pcrel; /* TRUE: pc-relative. */
+ char fx_pcrel_adjust; /* pc-relative offset adjust */
+ char fx_im_disp; /* TRUE: value is a displacement */
+ bit_fixS *fx_bit_fixP; /* IF NULL no bitfix's to do */
+ char fx_bsr; /* sequent-hack */
+ enum reloc_type fx_r_type; /* Sparc hacks */
+ char fx_callj; /* TRUE if target is a 'callj' (used by i960) */
+ long fx_addnumber;
+};
+
+typedef struct fix fixS;
+
+COMMON char *next_object_file_charP;
+
+#ifndef MANY_SEGMENTS
+COMMON fixS *text_fix_root, *text_fix_tail; /* Chains fixSs. */
+COMMON fixS *data_fix_root, *data_fix_tail; /* Chains fixSs. */
+COMMON fixS *bss_fix_root, *bss_fix_tail; /* Chains fixSs. */
+#endif
+COMMON fixS **seg_fix_rootP, **seg_fix_tailP; /* -> one of above. */
+extern long string_byte_count;
+extern int section_alignment[];
+
+#if __STDC__ == 1
+
+bit_fixS *bit_fix_new(int size, int offset, long base_type, long base_adj, long min, long max, long add);
+void append(char **charPP, char *fromP, unsigned long length);
+void record_alignment(segT seg, int align);
+void write_object_file(void);
+
+fixS *fix_new(fragS *frag,
+ int where,
+ int size,
+ symbolS *add_symbol,
+ symbolS *sub_symbol,
+ long offset,
+ int pcrel,
+ enum reloc_type r_type
+#ifdef PIC
+ ,symbolS *got_symbol);
+#else
+ );
+#endif
+
+#else /* not __STDC__ */
+
+bit_fixS *bit_fix_new();
+fixS *fix_new();
+void append();
+void record_alignment();
+void write_object_file();
+
+#endif /* not __STDC__ */
+
+/*
+ * Local Variables:
+ * comment-column: 0
+ * fill-column: 131
+ * End:
+ */
+
+/* end of write.h */
diff --git a/gnu/usr.bin/as/xmalloc.c b/gnu/usr.bin/as/xmalloc.c
new file mode 100644
index 0000000..4ecb289
--- /dev/null
+++ b/gnu/usr.bin/as/xmalloc.c
@@ -0,0 +1,75 @@
+/* xmalloc.c - get memory or bust
+
+ Copyright (C) 1987, 1990, 1991, 1992 Free Software Foundation, Inc.
+
+ This file is part of GAS, the GNU Assembler.
+
+ GAS is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GAS is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GAS; see the file COPYING. If not, write to
+ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/*
+ NAME
+ xmalloc() - get memory or bust
+ INDEX
+ xmalloc() uses malloc()
+
+ SYNOPSIS
+ char * my_memory;
+
+ my_memory = xmalloc(42); / * my_memory gets address of 42 chars * /
+
+ DESCRIPTION
+
+ Use xmalloc() as an "error-free" malloc(). It does almost the same job.
+ When it cannot honour your request for memory it BOMBS your program
+ with a "virtual memory exceeded" message. Malloc() returns NULL and
+ does not bomb your program.
+
+ SEE ALSO
+ malloc()
+
+ */
+
+#ifndef lint
+static char rcsid[] = "$Id: xmalloc.c,v 1.2 1993/11/03 00:52:32 paul Exp $";
+#endif
+
+#include <stdio.h>
+
+#if __STDC__ == 1
+#include <stdlib.h>
+#else
+#ifdef USG
+#include <malloc.h>
+#else
+char * malloc();
+#endif /* USG */
+#endif /* not __STDC__ */
+
+#define error as_fatal
+
+char * xmalloc(n)
+long n;
+{
+ char * retval;
+ void error();
+
+ if ((retval = malloc ((unsigned)n)) == NULL)
+ {
+ error("virtual memory exceeded");
+ }
+ return (retval);
+}
+
+/* end of xmalloc.c */
diff --git a/gnu/usr.bin/as/xrealloc.c b/gnu/usr.bin/as/xrealloc.c
new file mode 100644
index 0000000..8b2db16
--- /dev/null
+++ b/gnu/usr.bin/as/xrealloc.c
@@ -0,0 +1,74 @@
+/* xrealloc.c - new memory or bust
+
+ Copyright (C) 1987, 1990, 1991, 1992 Free Software Foundation, Inc.
+
+ This file is part of GAS, the GNU Assembler.
+
+ GAS is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GAS is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GAS; see the file COPYING. If not, write to
+ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+
+/*
+
+ NAME
+ xrealloc () - get more memory or bust
+ INDEX
+ xrealloc () uses realloc ()
+ SYNOPSIS
+ char *my_memory;
+
+ my_memory = xrealloc (my_memory, 42);
+ / * my_memory gets (perhaps new) address of 42 chars * /
+
+ DESCRIPTION
+
+ Use xrealloc () as an "error-free" realloc ().It does almost the same
+ job. When it cannot honour your request for memory it BOMBS your
+ program with a "virtual memory exceeded" message. Realloc() returns
+ NULL and does not bomb your program.
+
+ SEE ALSO
+ realloc ()
+ */
+
+#ifndef lint
+static char rcsid[] = "$Id: xrealloc.c,v 1.2 1993/11/03 00:52:34 paul Exp $";
+#endif
+
+
+#if __STDC__ == 1
+#include <stdlib.h>
+#else
+#ifdef USG
+#include <malloc.h>
+#else
+char *realloc ();
+#endif /* USG */
+#endif /* not __STDC__ */
+
+#define error as_fatal
+
+char *
+ xrealloc (ptr, n)
+register char *ptr;
+long n;
+{
+ void error();
+
+ if ((ptr = realloc (ptr, (unsigned)n)) == 0)
+ error ("virtual memory exceeded");
+ return (ptr);
+}
+
+/* end of xrealloc.c */
diff --git a/gnu/usr.bin/awk/ACKNOWLEDGMENT b/gnu/usr.bin/awk/ACKNOWLEDGMENT
index b6c3b0b..cb4021f 100644
--- a/gnu/usr.bin/awk/ACKNOWLEDGMENT
+++ b/gnu/usr.bin/awk/ACKNOWLEDGMENT
@@ -8,12 +8,16 @@ platforms and providing a great deal of feedback. They are:
Hal Peterson <hrp@pecan.cray.com> (Cray)
Pat Rankin <gawk.rankin@EQL.Caltech.Edu> (VMS)
- Michal Jaegermann <NTOMCZAK@vm.ucs.UAlberta.CA> (Atari, NeXT, DEC 3100)
+ Michal Jaegermann <michal@gortel.phys.UAlberta.CA> (Atari, NeXT, DEC 3100)
Mike Lijewski <mjlx@eagle.cnsf.cornell.edu> (IBM RS6000)
- Scott Deifik <scottd@amgen.com> (MSDOS 2.14)
+ Scott Deifik <scottd@amgen.com> (MSDOS 2.14 and 2.15)
Kent Williams (MSDOS 2.11)
Conrad Kwok (MSDOS earlier versions)
Scott Garfinkle (MSDOS earlier versions)
+ Kai Uwe Rommel <rommel@ars.muc.de> (OS/2)
+ Darrel Hankerson <hankedr@mail.auburn.edu> (OS/2)
+ Mark Moraes <Mark-Moraes@deshaw.com> (Code Center, Purify)
+ Kaveh Ghazi <ghazi@noc.rutgers.edu> (Lots of Unix variants)
Last, but far from least, we would like to thank Brian Kernighan who
has helped to clear up many dark corners of the language and provided a
diff --git a/gnu/usr.bin/awk/FUTURES b/gnu/usr.bin/awk/FUTURES
index b096560..6250584 100644
--- a/gnu/usr.bin/awk/FUTURES
+++ b/gnu/usr.bin/awk/FUTURES
@@ -1,14 +1,26 @@
This file lists future projects and enhancements for gawk. Items are listed
in roughly the order they will be done for a given release. This file is
-mainly for use by the developers to help keep themselves on track, please
+mainly for use by the developer(s) to help keep themselves on track, please
don't bug us too much about schedules or what all this really means.
+(An `x' indicates that some progress has been made, but that the feature is
+not complete yet.)
+
For 2.16
========
-David:
- Move to autoconf-based configure system.
+x Move to autoconf-based configure system.
+
+x Research awk `fflush' function.
+
+x Generalize IGNORECASE
+ any value makes it work, not just numeric non-zero
+ make it apply to *all* string comparisons
+
+x Fix FILENAME to have an initial value of "", not "-"
- Allow RS to be a regexp.
+In 2.17
+=======
+x Allow RS to be a regexp.
RT variable to hold text of record terminator
@@ -16,46 +28,24 @@ David:
Feedback alloca.s changes to FSF
- Extensible hashing in memory of awk arrays
+x Split() with null string as third arg to split up strings
- Split() with null string as third arg to split up strings
-
- Analogously, setting FS="" would split the input record into individual
+x Analogously, setting FS="" would split the input record into individual
characters.
-Arnold:
- Generalize IGNORECASE
- any value makes it work, not just numeric non-zero
- make it apply to *all* string comparisons
-
- Fix FILENAME to have an initial value of "", not "-"
-
- Clean up code by isolating system-specific functions in separate files.
+x Clean up code by isolating system-specific functions in separate files.
Undertake significant directory reorganization.
- Extensive manual cleanup:
+x Extensive manual cleanup:
Use of texinfo 2.0 features
Lots more examples
Document all of the above.
-In 2.17
-=======
-David:
-
- Incorporate newer dfa.c and regex.c (go to POSIX regexps)
+x Go to POSIX regexps
Make regex + dfa less dependant on gawk header file includes
- General sub functions:
- edit(line, pat, sub) and gedit(line, pat, sub)
- that return the substituted strings and allow \1 etc. in the sub string.
-
-Arnold:
- DBM storage of awk arrays. Try to allow multiple dbm packages
-
- ? Have strftime() pay attention to the value of ENVIRON["TZ"]
-
Additional manual features:
Document posix regexps
Document use of dbm arrays
@@ -67,19 +57,26 @@ Arnold:
For 2.18
========
+ DBM storage of awk arrays. Try to allow multiple dbm packages
-Arnold:
+ General sub functions:
+ edit(line, pat, sub) and gedit(line, pat, sub)
+ that return the substituted strings and allow \1 etc. in the sub
+ string.
+
+ ? Have strftime() pay attention to the value of ENVIRON["TZ"]
+
+For 2.19
+========
Add chdir and stat built-in functions.
Add function pointers as valid variable types.
Add an `ftw' built-in function that takes a function pointer.
-David:
-
Do an optimization pass over parse tree?
-For 2.19 or later:
+For 2.20 or later:
==================
Add variables similar to C's __FILE__ and __LINE__ for better diagnostics
from within awk programs.
@@ -101,7 +98,7 @@ Make awk '/foo/' files... run at egrep speeds
Do a reference card
-Allow OFMT to be other than a floating point format.
+Allow OFMT and CONVFMT to be other than a floating point format.
Allow redefining of builtin functions?
diff --git a/gnu/usr.bin/awk/LIMITATIONS b/gnu/usr.bin/awk/LIMITATIONS
index 5877197..64eab85 100644
--- a/gnu/usr.bin/awk/LIMITATIONS
+++ b/gnu/usr.bin/awk/LIMITATIONS
@@ -12,3 +12,5 @@ Characters in a character class: 2^(# of bits per byte)
# of pipe redirections: min(# of processes per user, # of open files)
double-precision floating point
Length of source line: unlimited
+Number of input records in one file: MAX_LONG
+Number of input records total: MAX_LONG
diff --git a/gnu/usr.bin/awk/Makefile b/gnu/usr.bin/awk/Makefile
index fdca82c..1fa87cc 100644
--- a/gnu/usr.bin/awk/Makefile
+++ b/gnu/usr.bin/awk/Makefile
@@ -1,13 +1,13 @@
-PROG= awk
-SRCS= main.c eval.c builtin.c msg.c iop.c io.c field.c array.c \
- node.c version.c re.c awk.c regex.c dfa.c \
- getopt.c getopt1.c
-CFLAGS+= -DGAWK
-LDADD= -lm
-DPADD= ${LIBM}
-CLEANFILES+= awk.c y.tab.h
+PROG= awk
+SRCS= main.c eval.c builtin.c msg.c iop.c io.c field.c getopt1.c \
+ getopt.c array.c \
+ node.c version.c re.c awk.c dfa.c
+CFLAGS+=-I${.CURDIR} -DGAWK
+CLEANFILES+=awk.c y.tab.h
-MAN1= awk.0
+SUBDIR+= doc
+
+DPADD+= ${LIBGNUREGEX} ${LIBM}
+LDADD+= -lgnuregex -lm
.include <bsd.prog.mk>
-.include "../../usr.bin/Makefile.inc"
diff --git a/gnu/usr.bin/awk/NEWS b/gnu/usr.bin/awk/NEWS
index 6711373..4df69e7 100644
--- a/gnu/usr.bin/awk/NEWS
+++ b/gnu/usr.bin/awk/NEWS
@@ -1,5 +1,191 @@
+Changes from 2.15.4 to 2.15.5
+-----------------------------
+
+FUTURES file updated and re-arranged some with more rational schedule.
+
+Many prototypes handled better for ANSI C in protos.h.
+
+getopt.c updated somewhat.
+
+test/Makefile now removes junk directory, `bardargtest' renamed `badargs.'
+
+Bug fix in iop.c for RS = "". Eat trailing newlines off of record separator.
+
+Bug fix in Makefile.bsd44, use leading tab in actions.
+
+Fix in field.c:set_FS for FS == "\\" and IGNORECASE != 0.
+
+Config files updated or added:
+ cray60, DEC OSF/1 2.0, Utek, sgi405, next21, next30, atari/config.h,
+ sco.
+
+Fix in io.c for ENFILE as well as EMFILE, update decl of groupset to
+include OSF/1.
+
+Rationalized printing as integers if numbers are outside the range of a long.
+Changes to node.c:force_string and builtin.c.
+
+Made internal NF, NR, and FNR variables longs instead of ints.
+
+Add LIMITS_H_MISSING stuff to config.in and awk.h, and default defs for
+INT_MAX and LONG_MAX, if no limits.h file. Add a standard decl of
+the time() function for __STDC__. From ghazi@noc.rutgers.edu.
+
+Fix tree_eval in awk.h and r_tree_eval in eval.c to deal better with
+function parameters, particularly ones that are arrays.
+
+Fix eval.c to print out array names of arrays used in scalar contexts.
+
+Fix eval.c in interpret to zero out source and sourceline initially. This
+does a better job of providing source file and line number information.
+
+Fix to re_parse_field in field.c to not use isspace when RS = "", but rather
+to explicitly look for blank and tab.
+
+Fix to sc_parse_field in field.c to catch the case of the FS character at the
+end of a record.
+
+Lots of miscellanious bug fixes for memory leaks, courtesy Mark Moraes,
+also fixes for arrays.
+
+io.c fixed to warn about lack of explicit closes if --lint.
+
+Updated missing/strftime.c to match posted strftime 6.2.
+
+Bug fix in builtin.c, in case of non-match in sub_common.
+
+Updated constant used for division in builtin.c:do_rand for DEC Alpha
+and CRAY Y-MP.
+
+POSIXLY_CORRECT in the environment turns on --posix (fixed in main.c).
+
+Updated srandom prototype and calls in builtin.c.
+
+Fix awk.y to enforce posix semantics of unary +: result is numeric.
+
+Fix array.c to not rearrange the hash chain upon finding an index in
+the array. This messed things up in cases like:
+ for (index1 in array) {
+ blah
+ if (index2 in array) # blew away the for
+ stuff
+ }
+
+Fixed spelling errors in the man page.
+
+Fixes in awk.y so that
+ gawk '' /path/to/file
+will work without core dumping or finding parse errors.
+
+Fix main.c so that --lint will fuss about an empty program.
+Yet another fix for argument parsing in the case of unrecognized options.
+
+Bug fix in dfa.c to not attempt to free null pointers.
+
+Bug fix in builtin.c to only use DEFAULT_G_PRECISION for %g or %G.
+
+Bug fix in field.c to achieve call by value semantics for split.
+
+Changes from 2.15.3 to 2.15.4
+-----------------------------
+
+Lots of lint fixes, and do_sprintf made mostly ANSI C compatible.
+
+Man page updated and edited.
+
+Copyrights updated.
+
+Arrays now grow dynamically, initially scaling up by an order of magnitude
+ and then doubling, up to ~ 64K. This should keep gawk's performance
+ graceful under heavy load.
+
+New `delete array' feature added. Only documented in the man page.
+
+Switched to dfa and regex suites from grep-2.0. These offer the ability to
+ move to POSIX regexps in the next release.
+
+Disabled GNU regex ops.
+
+Research awk -m option now recognized. It does nothing in gawk, since gawk
+ has no static limits. Only documented in the man page.
+
+New bionic (faster, better, stronger than before) hashing function.
+
+Bug fix in argument handling. `gawk -X' now notices there was no program.
+ Additional bug fixes to make --compat and --lint work again.
+
+Many changes for systems where sizeof(int) != sizeof(void *).
+
+Add explicit alloca(0) in io.c to recover space from C alloca.
+
+Fixed file descriptor leak in io.c.
+
+The --version option now follows the GNU coding standards and exits.
+
+Fixed several prototypes in protos.h.
+
+Several tests updated. On Solaris, warn that the out? tests will fail.
+
+Configuration files for SunOS with cc and Solaris 2.x added.
+
+Improved error messages in awk.y on gawk extensions if do_unix or do_compat.
+
+INSTALL file added.
+
+Fixed Atari Makefile and several VMS specific changes.
+
+Better conversion of numbers to strings on systems with broken sprintfs.
+
+Changes from 2.15.2 to 2.15.3
+-----------------------------
+
+Increased HASHSIZE to a decent number, 127 was way too small.
+
+FILENAME is now the null string in a BEGIN rule.
+
+Argument processing fixed for invalid options and missing arguments.
+
+This version will build on VMS. This included a fix to close all files
+ and pipes opened with redirections before closing stdout and stderr.
+
+More getpgrp() defines.
+
+Changes for BSD44: <sys/param.h> in io.c and Makefile.bsd44.
+
+All directories in the distribution are now writable.
+
+Separated LDFLAGS and CFLAGS in Makefile. CFLAGS can now be overridden by
+ user.
+
+Make dist now builds compressed archives ending in .gz and runs doschk.
+
+Amiga port.
+
+New getopt.c fixes Alpha OSF/1 problem.
+
+Make clean now removes possible test output.
+
+Improved algorithm for multiple adjacent string concatenations leads to
+ performance improvements.
+
+Fix nasty bug whereby command-line assignments, both with -v and at run time,
+ could create variables with syntactically illegal names.
+
+Fix obscure bug in printf with %0 flag and filling.
+
+Add a lint check for substr if provided length exceeds remaining characters
+ in string.
+
+Update atari support.
+
+PC support enhanced to include support for both DOS and OS/2. (Lots more
+ #ifdefs. Sigh.)
+
+Config files for Hitachi Unix and OSF/1, courtesy of Yoko Morishita
+ (morisita@sra.co.jp)
+
Changes from 2.15.1 to 2.15.2
----------------------------
+-----------------------------
Additions to the FUTURES file.
@@ -11,7 +197,6 @@ Clean up the distribution generation in Makefile.in: the info files are
now included, the distributed files are marked read-only and patched
distributions are now unpacked in a directory named with the patch level.
-
Changes from 2.15 to 2.15.1
---------------------------
@@ -161,7 +346,7 @@ Added code to do better diagnoses of weird or null file names.
Allow continue outside of a loop, unless in strict posix mode. Lint option
will issue warning.
-New missing/strftime.c. There has been one chage that affects gawk. Posix
+New missing/strftime.c. There has been one change that affects gawk. Posix
now defines a %V conversion so the vms conversion has been changed to %v.
If this version is used with gawk -Wlint and they use %V in a call to
strftime, they'll get a warning.
@@ -189,7 +374,7 @@ Fixed a couple of bugs for reference to $0 when $0 is "" -- particularly in
Fixed premature freeing in construct "$0 = $0".
Removed the call to wait_any() in gawk_popen(), since on at least some systems,
- if gawk's input was from a pipe, the predecssor process in the pipe was a
+ if gawk's input was from a pipe, the predecessor process in the pipe was a
child of gawk and this caused a deadlock.
Regexp can (once again) match a newline, if given explicitly.
@@ -215,7 +400,7 @@ Fixed bug when NF is set by user -- fields_arr must be expanded if necessary
Fixed several bugs in [g]sub() for no match found or the match is 0-length.
-Fixed bug where in gsub() a pattern anchorred at the beginning would still
+Fixed bug where in gsub() a pattern anchored at the beginning would still
substitute throughout the string.
make test does not assume the . is in PATH.
@@ -235,7 +420,7 @@ Fixed hanging of pipe redirection to getline
Fixed coredump on access to $0 inside BEGIN block.
Fixed treatment of RS = "". It now parses the fields correctly and strips
- leading whitspace from a record if FS is a space.
+ leading whitespace from a record if FS is a space.
Fixed faking of /dev/stdin.
@@ -279,7 +464,7 @@ Update to config/bsd43.
Added config/apollo, config/msc60, config/cray2-50, config/interactive2.2
-sgi33.cc added for compilation using cc ratther than gcc.
+sgi33.cc added for compilation using cc rather than gcc.
Ultrix41 now propagates to config.h properly -- as part of a general
mechanism in configure for kludges -- #define anything from a config file
@@ -600,7 +785,7 @@ Fixed bug in output flushing introduced a few patches back. This caused
Changes from 2.12.22 to 2.12.23
-------------------------------
-Accidently left config/cray2-60 out of last patch.
+Accidentally left config/cray2-60 out of last patch.
Added some missing dependencies to Makefile.
@@ -750,7 +935,7 @@ Changes from 2.12.14 to 2.12.15
-------------------------------
Changed config/* to a condensed form that can be used with mkconf to generate
- a config.h from config.h-dist -- much easier to maintain. Please chaeck
+ a config.h from config.h-dist -- much easier to maintain. Please check
carefully against what you had before for a particular system and report
any problems. vms.h remains separate since the stuff at the bottom
didn't quite fit the mkconf model -- hopefully cleared up later.
@@ -1102,7 +1287,7 @@ Changes from 2.11beta to 2.11.1 (production)
Went from "beta" to production status!!!
Now flushes stdout before closing pipes or redirected files to
-synchonize output.
+synchronize output.
MS-DOS changes added in.
@@ -1217,7 +1402,7 @@ Cleaned up and fixed close_redir().
Fixed an obscure bug to do with redirection. Intermingled ">" and ">>"
redirects did not output in a predictable order.
-Improved handling of output bufferring: now all print[f]s redirected to a tty
+Improved handling of output buffering: now all print[f]s redirected to a tty
or pipe are flushed immediately and non-redirected output to a tty is flushed
before the next input record is read.
diff --git a/gnu/usr.bin/awk/PORTS b/gnu/usr.bin/awk/PORTS
index 95e133f..5087a43 100644
--- a/gnu/usr.bin/awk/PORTS
+++ b/gnu/usr.bin/awk/PORTS
@@ -18,15 +18,18 @@ OpenVMS AXP V1.0
MSDOS - Microsoft C 5.1, compiles and runs very simple testing
BSD 4.4alpha
-From: ghazi@caip.rutgers.edu (Kaveh R. Ghazi):
+From: ghazi@noc.rutgers.edu (Kaveh R. Ghazi):
arch configured as:
---- --------------
+Dec Alpha OSF 1.3 osf1
Hpux 9.0 hpux8x
NeXTStep 2.0 next20
-Sgi Irix 4.0.5 (/bin/cc) sgi405.cc (new file)
+Sgi Irix 4.0.5 (/bin/cc) sgi405.cc
Stardent Titan 1500 OSv2.5 sysv3
Stardent Vistra (i860) SVR4 sysv4
-SunOS 4.1.2 sunos41
+Solaris 2.3 solaris2.cc
+SunOS 4.1.3 sunos41
Tektronix XD88 (UTekV 3.2e) sysv3
+Tektronix 4300 (UTek 4.0) utek
Ultrix 4.2 ultrix41
diff --git a/gnu/usr.bin/awk/PROBLEMS b/gnu/usr.bin/awk/PROBLEMS
index 3b7c514..a436180 100644
--- a/gnu/usr.bin/awk/PROBLEMS
+++ b/gnu/usr.bin/awk/PROBLEMS
@@ -3,4 +3,8 @@ Hopefully they will all be fixed in the next major release of gawk.
Please keep in mind that the code is still undergoing significant evolution.
-1. Gawk's printf is probably still not POSIX compliant.
+1. The interactions with the lexer and yyerror need reworking. It is possible
+ to get line numbers that are one line off if --compat or --posix is
+ true and either `next file' or `delete array' are used.
+
+ Really the whole lexical analysis stuff needs reworking.
diff --git a/gnu/usr.bin/awk/README b/gnu/usr.bin/awk/README
index f4bd3df..90ed9c2 100644
--- a/gnu/usr.bin/awk/README
+++ b/gnu/usr.bin/awk/README
@@ -1,8 +1,7 @@
README:
-This is GNU Awk 2.15. It should be upwardly compatible with the
-System V Release 4 awk. It is almost completely compliant with draft 11.3
-of POSIX 1003.2.
+This is GNU Awk 2.15. It should be upwardly compatible with the System
+V Release 4 awk. It is almost completely compliant with POSIX 1003.2.
This release adds new features -- see NEWS for details.
@@ -10,7 +9,7 @@ See the installation instructions, below.
Known problems are given in the PROBLEMS file. Work to be done is
described briefly in the FUTURES file. Verified ports are listed in
-the PORTS file. Changes in this version are summarized in the CHANGES file.
+the PORTS file. Changes in this version are summarized in the NEWS file.
Please read the LIMITATIONS and ACKNOWLEDGMENT files.
Read the file POSIX for a discussion of how the standard says comparisons
@@ -28,6 +27,8 @@ INSTALLATION:
Check whether there is a system-specific README file for your system.
+A quick overview of the installation process is in the file INSTALL.
+
Makefile.in may need some tailoring. The only changes necessary should
be to change installation targets or to change compiler flags.
The changes to make in Makefile.in are commented and should be obvious.
@@ -54,10 +55,12 @@ proceed.
The next release will use the FSF autoconfig program, so we are no longer
soliciting new config files.
-If you have an MS-DOS system, use the stuff in the pc directory.
+If you have an MS-DOS or OS/2 system, use the stuff in the pc directory.
For an Atari there is an atari directory and similarly one for VMS.
Chapter 16 of The GAWK Manual discusses configuration in detail.
+(However, it does not discuss OS/2 configuration, see README.pc for
+the details. The manual is being massively revised for 2.16.)
After successful compilation, do 'make test' to run a small test
suite. There should be no output from the 'cmp' invocations except in
@@ -67,7 +70,7 @@ problem.
PRINTING THE MANUAL
-The 'support' directory contains texinfo.tex 2.65, which will be necessary
+The 'support' directory contains texinfo.tex 2.115, which will be necessary
for printing the manual, and the texindex.c program from the texinfo
distribution which is also necessary. See the makefile for the steps needed
to get a DVI file from the manual.
@@ -91,7 +94,7 @@ INTERNET: david@cs.dal.ca
Arnold Robbins
1736 Reindeer Drive
-Atlanta, GA, 30329, USA
+Atlanta, GA, 30329-3528, USA
INTERNET: arnold@skeeve.atl.ga.us
UUCP: { gatech, emory, emoryu1 }!skeeve!arnold
@@ -113,4 +116,10 @@ VMS:
Atari ST:
Michal Jaegermann
- NTOMCZAK@vm.ucs.UAlberta.CA (e-mail only)
+ michal@gortel.phys.ualberta.ca (e-mail only)
+
+OS/2:
+ Kai Uwe Rommel
+ rommel@ars.muc.de (e-mail only)
+ Darrel Hankerson
+ hankedr@mail.auburn.edu (e-mail only)
diff --git a/gnu/usr.bin/awk/array.c b/gnu/usr.bin/awk/array.c
index 59be340..9166c4e 100644
--- a/gnu/usr.bin/awk/array.c
+++ b/gnu/usr.bin/awk/array.c
@@ -2,30 +2,45 @@
* array.c - routines for associative arrays.
*/
-/*
- * Copyright (C) 1986, 1988, 1989, 1991, 1992 the Free Software Foundation, Inc.
- *
+/*
+ * Copyright (C) 1986, 1988, 1989, 1991, 1992, 1993 the Free Software Foundation, Inc.
+ *
* This file is part of GAWK, the GNU implementation of the
* AWK Progamming Language.
- *
+ *
* GAWK is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
- *
+ *
* GAWK is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
- *
+ *
* You should have received a copy of the GNU General Public License
* along with GAWK; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
+/*
+ * Tree walks (``for (iggy in foo)'') and array deletions use expensive
+ * linear searching. So what we do is start out with small arrays and
+ * grow them as needed, so that our arrays are hopefully small enough,
+ * most of the time, that they're pretty full and we're not looking at
+ * wasted space.
+ *
+ * The decision is made to grow the array if the average chain length is
+ * ``too big''. This is defined as the total number of entries in the table
+ * divided by the size of the array being greater than some constant.
+ */
+
+#define AVG_CHAIN_MAX 10 /* don't want to linear search more than this */
+
#include "awk.h"
static NODE *assoc_find P((NODE *symbol, NODE *subs, int hash1));
+static void grow_table P((NODE *symbol));
NODE *
concat_exp(tree)
@@ -34,9 +49,9 @@ register NODE *tree;
register NODE *r;
char *str;
char *s;
- unsigned len;
+ size_t len;
int offset;
- int subseplen;
+ size_t subseplen;
char *subsep;
if (tree->type != Node_expression_list)
@@ -84,7 +99,7 @@ NODE *symbol;
if (symbol->var_array == 0)
return;
- for (i = 0; i < HASHSIZE; i++) {
+ for (i = 0; i < symbol->array_size; i++) {
for (bucket = symbol->var_array[i]; bucket; bucket = next) {
next = bucket->ahnext;
unref(bucket->ahname);
@@ -93,17 +108,26 @@ NODE *symbol;
}
symbol->var_array[i] = 0;
}
+ free(symbol->var_array);
+ symbol->var_array = NULL;
+ symbol->array_size = symbol->table_size = 0;
+ symbol->flags &= ~ARRAYMAXED;
}
/*
* calculate the hash function of the string in subs
*/
unsigned int
-hash(s, len)
-register char *s;
-register int len;
+hash(s, len, hsize)
+register const char *s;
+register size_t len;
+unsigned long hsize;
{
- register unsigned long h = 0, g;
+ register unsigned long h = 0;
+
+#ifdef this_is_really_slow
+
+ register unsigned long g;
while (len--) {
h = (h << 4) + *s++;
@@ -113,10 +137,84 @@ register int len;
h = h ^ g;
}
}
- if (h < HASHSIZE)
- return h;
- else
- return h%HASHSIZE;
+
+#else /* this_is_really_slow */
+/*
+ * This is INCREDIBLY ugly, but fast. We break the string up into 8 byte
+ * units. On the first time through the loop we get the "leftover bytes"
+ * (strlen % 8). On every other iteration, we perform 8 HASHC's so we handle
+ * all 8 bytes. Essentially, this saves us 7 cmp & branch instructions. If
+ * this routine is heavily used enough, it's worth the ugly coding.
+ *
+ * OZ's original sdbm hash, copied from Margo Seltzers db package.
+ *
+ */
+
+/* Even more speed: */
+/* #define HASHC h = *s++ + 65599 * h */
+/* Because 65599 = pow(2,6) + pow(2,16) - 1 we multiply by shifts */
+#define HASHC htmp = (h << 6); \
+ h = *s++ + htmp + (htmp << 10) - h
+
+ unsigned long htmp;
+
+ h = 0;
+
+#if defined(VAXC)
+/*
+ * [This was an implementation of "Duff's Device", but it has been
+ * redone, separating the switch for extra iterations from the loop.
+ * This is necessary because the DEC VAX-C compiler is STOOPID.]
+ */
+ switch (len & (8 - 1)) {
+ case 7: HASHC;
+ case 6: HASHC;
+ case 5: HASHC;
+ case 4: HASHC;
+ case 3: HASHC;
+ case 2: HASHC;
+ case 1: HASHC;
+ default: break;
+ }
+
+ if (len > (8 - 1)) {
+ register size_t loop = len >> 3;
+ do {
+ HASHC;
+ HASHC;
+ HASHC;
+ HASHC;
+ HASHC;
+ HASHC;
+ HASHC;
+ HASHC;
+ } while (--loop);
+ }
+#else /* !VAXC */
+ /* "Duff's Device" for those who can handle it */
+ if (len > 0) {
+ register size_t loop = (len + 8 - 1) >> 3;
+
+ switch (len & (8 - 1)) {
+ case 0:
+ do { /* All fall throughs */
+ HASHC;
+ case 7: HASHC;
+ case 6: HASHC;
+ case 5: HASHC;
+ case 4: HASHC;
+ case 3: HASHC;
+ case 2: HASHC;
+ case 1: HASHC;
+ } while (--loop);
+ }
+ }
+#endif /* !VAXC */
+#endif /* this_is_really_slow - not */
+
+ if (h >= hsize)
+ h %= hsize;
+ return h;
}
/*
@@ -132,11 +230,19 @@ int hash1;
for (bucket = symbol->var_array[hash1]; bucket; bucket = bucket->ahnext) {
if (cmp_nodes(bucket->ahname, subs) == 0) {
+#if 0
+ /*
+ * Disable this code for now. It screws things up if we have
+ * a ``for (iggy in foo)'' in progress. Interestingly enough,
+ * this was not a problem in 2.15.3, only in 2.15.4. I'm not
+ * sure why it works in 2.15.3.
+ */
if (prev) { /* move found to front of chain */
prev->ahnext = bucket->ahnext;
bucket->ahnext = symbol->var_array[hash1];
symbol->var_array[hash1] = bucket;
}
+#endif
return bucket;
} else
prev = bucket; /* save previous list entry */
@@ -145,7 +251,7 @@ int hash1;
}
/*
- * test whether the array element symbol[subs] exists or not
+ * test whether the array element symbol[subs] exists or not
*/
int
in_array(symbol, subs)
@@ -158,7 +264,7 @@ NODE *symbol, *subs;
if (symbol->var_array == 0)
return 0;
subs = concat_exp(subs); /* concat_exp returns a string node */
- hash1 = hash(subs->stptr, subs->stlen);
+ hash1 = hash(subs->stptr, subs->stlen, (unsigned long) symbol->array_size);
if (assoc_find(symbol, subs, hash1) == NULL) {
free_temp(subs);
return 0;
@@ -170,10 +276,10 @@ NODE *symbol, *subs;
/*
* SYMBOL is the address of the node (or other pointer) being dereferenced.
- * SUBS is a number or string used as the subscript.
+ * SUBS is a number or string used as the subscript.
*
* Find SYMBOL[SUBS] in the assoc array. Install it with value "" if it
- * isn't there. Returns a pointer ala get_lhs to where its value is stored
+ * isn't there. Returns a pointer ala get_lhs to where its value is stored
*/
NODE **
assoc_lookup(symbol, subs)
@@ -183,17 +289,17 @@ NODE *symbol, *subs;
register NODE *bucket;
(void) force_string(subs);
- hash1 = hash(subs->stptr, subs->stlen);
-
- if (symbol->var_array == 0) { /* this table really should grow
- * dynamically */
- unsigned size;
- size = sizeof(NODE *) * HASHSIZE;
- emalloc(symbol->var_array, NODE **, size, "assoc_lookup");
- memset((char *)symbol->var_array, 0, size);
+ if (symbol->var_array == 0) {
symbol->type = Node_var_array;
+ symbol->array_size = symbol->table_size = 0; /* sanity */
+ symbol->flags &= ~ARRAYMAXED;
+ grow_table(symbol);
+ hash1 = hash(subs->stptr, subs->stlen,
+ (unsigned long) symbol->array_size);
} else {
+ hash1 = hash(subs->stptr, subs->stlen,
+ (unsigned long) symbol->array_size);
bucket = assoc_find(symbol, subs, hash1);
if (bucket != NULL) {
free_temp(subs);
@@ -205,6 +311,17 @@ NODE *symbol, *subs;
if (do_lint && subs->stlen == 0)
warning("subscript of array `%s' is null string",
symbol->vname);
+
+ /* first see if we would need to grow the array, before installing */
+ symbol->table_size++;
+ if ((symbol->flags & ARRAYMAXED) == 0
+ && symbol->table_size/symbol->array_size > AVG_CHAIN_MAX) {
+ grow_table(symbol);
+ /* have to recompute hash value for new size */
+ hash1 = hash(subs->stptr, subs->stlen,
+ (unsigned long) symbol->array_size);
+ }
+
getnode(bucket);
bucket->type = Node_ahash;
if (subs->flags & TEMP)
@@ -240,7 +357,7 @@ NODE *symbol, *tree;
if (symbol->var_array == 0)
return;
subs = concat_exp(tree); /* concat_exp returns string node */
- hash1 = hash(subs->stptr, subs->stlen);
+ hash1 = hash(subs->stptr, subs->stlen, (unsigned long) symbol->array_size);
last = NULL;
for (bucket = symbol->var_array[hash1]; bucket; last = bucket, bucket = bucket->ahnext)
@@ -256,6 +373,15 @@ NODE *symbol, *tree;
unref(bucket->ahname);
unref(bucket->ahvalue);
freenode(bucket);
+ symbol->table_size--;
+ if (symbol->table_size <= 0) {
+ memset(symbol->var_array, '\0',
+ sizeof(NODE *) * symbol->array_size);
+ symbol->table_size = symbol->array_size = 0;
+ symbol->flags &= ~ARRAYMAXED;
+ free((char *) symbol->var_array);
+ symbol->var_array = NULL;
+ }
}
void
@@ -263,31 +389,127 @@ assoc_scan(symbol, lookat)
NODE *symbol;
struct search *lookat;
{
- if (!symbol->var_array) {
- lookat->retval = NULL;
- return;
- }
- lookat->arr_ptr = symbol->var_array;
- lookat->arr_end = lookat->arr_ptr + HASHSIZE; /* added */
- lookat->bucket = symbol->var_array[0];
- assoc_next(lookat);
+ lookat->sym = symbol;
+ lookat->idx = 0;
+ lookat->bucket = NULL;
+ lookat->retval = NULL;
+ if (symbol->var_array != NULL)
+ assoc_next(lookat);
}
void
assoc_next(lookat)
struct search *lookat;
{
- while (lookat->arr_ptr < lookat->arr_end) {
- if (lookat->bucket != 0) {
- lookat->retval = lookat->bucket->ahname;
- lookat->bucket = lookat->bucket->ahnext;
+ register NODE *symbol = lookat->sym;
+
+ if (symbol == NULL)
+ fatal("null symbol in assoc_next");
+ if (symbol->var_array == NULL || lookat->idx > symbol->array_size) {
+ lookat->retval = NULL;
+ return;
+ }
+ /*
+ * This is theoretically unsafe. The element bucket might have
+ * been freed if the body of the scan did a delete on the next
+ * element of the bucket. The only way to do that is by array
+ * reference, which is unlikely. Basically, if the user is doing
+ * anything other than an operation on the current element of an
+ * assoc array while walking through it sequentially, all bets are
+ * off. (The safe way is to register all search structs on an
+ * array with the array, and update all of them on a delete or
+ * insert)
+ */
+ if (lookat->bucket != NULL) {
+ lookat->retval = lookat->bucket->ahname;
+ lookat->bucket = lookat->bucket->ahnext;
+ return;
+ }
+ for (; lookat->idx < symbol->array_size; lookat->idx++) {
+ NODE *bucket;
+
+ if ((bucket = symbol->var_array[lookat->idx]) != NULL) {
+ lookat->retval = bucket->ahname;
+ lookat->bucket = bucket->ahnext;
+ lookat->idx++;
return;
}
- lookat->arr_ptr++;
- if (lookat->arr_ptr < lookat->arr_end)
- lookat->bucket = *(lookat->arr_ptr);
- else
- lookat->retval = NULL;
}
+ lookat->retval = NULL;
+ lookat->bucket = NULL;
return;
}
+
+/* grow_table --- grow a hash table */
+
+static void
+grow_table(symbol)
+NODE *symbol;
+{
+ NODE **old, **new, *chain, *next;
+ int i, j;
+ unsigned long hash1;
+ unsigned long oldsize, newsize;
+ /*
+ * This is an array of primes. We grow the table by an order of
+ * magnitude each time (not just doubling) so that growing is a
+ * rare operation. We expect, on average, that it won't happen
+ * more than twice. The final size is also chosen to be small
+ * enough so that MS-DOG mallocs can handle it. When things are
+ * very large (> 8K), we just double more or less, instead of
+ * just jumping from 8K to 64K.
+ */
+ static long sizes[] = { 13, 127, 1021, 8191, 16381, 32749, 65497 };
+
+ /* find next biggest hash size */
+ oldsize = symbol->array_size;
+ newsize = 0;
+ for (i = 0, j = sizeof(sizes)/sizeof(sizes[0]); i < j; i++) {
+ if (oldsize < sizes[i]) {
+ newsize = sizes[i];
+ break;
+ }
+ }
+
+ if (newsize == oldsize) { /* table already at max (!) */
+ symbol->flags |= ARRAYMAXED;
+ return;
+ }
+
+ /* allocate new table */
+ emalloc(new, NODE **, newsize * sizeof(NODE *), "grow_table");
+ memset(new, '\0', newsize * sizeof(NODE *));
+
+ /* brand new hash table, set things up and return */
+ if (symbol->var_array == NULL) {
+ symbol->table_size = 0;
+ goto done;
+ }
+
+ /* old hash table there, move stuff to new, free old */
+ old = symbol->var_array;
+ for (i = 0; i < oldsize; i++) {
+ if (old[i] == NULL)
+ continue;
+
+ for (chain = old[i]; chain != NULL; chain = next) {
+ next = chain->ahnext;
+ hash1 = hash(chain->ahname->stptr,
+ chain->ahname->stlen, newsize);
+
+ /* remove from old list, add to new */
+ chain->ahnext = new[hash1];
+ new[hash1] = chain;
+
+ }
+ }
+ free(old);
+
+done:
+ /*
+ * note that symbol->table_size does not change if an old array,
+ * and is explicitly set to 0 if a new one.
+ */
+ symbol->var_array = new;
+ symbol->array_size = newsize;
+}
diff --git a/gnu/usr.bin/awk/awk.1 b/gnu/usr.bin/awk/awk.1
index 0338485..1b58bec 100644
--- a/gnu/usr.bin/awk/awk.1
+++ b/gnu/usr.bin/awk/awk.1
@@ -1,11 +1,11 @@
.ds PX \s-1POSIX\s+1
.ds UX \s-1UNIX\s+1
.ds AN \s-1ANSI\s+1
-.TH GAWK 1 "Apr 15 1993" "Free Software Foundation" "Utility Commands"
+.TH AWK 1 "Apr 18 1994" "Free Software Foundation" "Utility Commands"
.SH NAME
-gawk \- pattern scanning and processing language
+awk \- GNU awk pattern scanning and processing language
.SH SYNOPSIS
-.B gawk
+.B awk
[ POSIX or GNU style options ]
.B \-f
.I program-file
@@ -13,7 +13,7 @@ gawk \- pattern scanning and processing language
.B \-\^\-
] file .\^.\^.
.br
-.B gawk
+.B awk
[ POSIX or GNU style options ]
[
.B \-\^\-
@@ -35,7 +35,7 @@ of \*(UX
also provides some GNU-specific extensions.
.PP
The command line consists of options to
-.I gawk
+.I awk
itself, the AWK program text (if not supplied via the
.B \-f
or
@@ -57,7 +57,7 @@ for \*(PX mandated features. Other implementations of the AWK language
are likely to only accept the traditional one letter options.
.PP
Following the \*(PX standard,
-.IR gawk -specific
+.IR awk -specific
options are supplied via arguments to the
.B \-W
option. Multiple
@@ -71,6 +71,11 @@ option.
Each
.B \-W
option has a corresponding GNU style long option, as detailed below.
+Arguments to GNU style long options are either joined with the option
+by an
+.B =
+sign, with no intervening spaces, or they may be provided in the
+next command line argument.
.PP
.I Gawk
accepts the following options.
@@ -114,6 +119,26 @@ Multiple
(or
.BR \-\^\-file )
options may be used.
+.TP
+.PD 0
+.BI \-mf= NNN
+.TP
+.BI \-mr= NNN
+Set various memory limits to the value
+.IR NNN .
+The
+.B f
+flag sets the maximum number of fields, and the
+.B r
+flag sets the maximum record size. These two flags and the
+.B \-m
+option are from the AT&T Bell Labs research version of \*(UX
+.IR awk .
+They are ignored by
+.IR awk ,
+since
+.I awk
+has no pre-defined limits.
.TP \w'\fB\-\^\-copyright\fR'u+1n
.PD 0
.B "\-W compat"
@@ -123,7 +148,7 @@ options may be used.
Run in
.I compatibility
mode. In compatibility mode,
-.I gawk
+.I awk
behaves identically to \*(UX
.IR awk ;
none of the GNU-specific extensions are recognized.
@@ -158,6 +183,8 @@ the error output.
.B \-\^\-usage
Print a relatively short summary of the available options on
the error output.
+Per the GNU Coding Standards, these options cause an immediate,
+successful exit.
.TP
.PD 0
.B "\-W lint"
@@ -241,13 +268,15 @@ will be recognized in the same argument.
.PD
.B \-\^\-version
Print version information for this particular copy of
-.I gawk
+.I awk
on the error output.
This is useful mainly for knowing if the current copy of
-.I gawk
+.I awk
on your system
is up to date with respect to whatever the Free Software Foundation
is distributing.
+Per the GNU Coding Standards, these options cause an immediate,
+successful exit.
.TP
.B \-\^\-
Signal the end of options. This is useful to allow further arguments to the
@@ -255,7 +284,13 @@ AWK program itself to start with a ``\-''.
This is mainly for consistency with the argument parsing convention used
by most other \*(PX programs.
.PP
-Any other options are flagged as illegal, but are otherwise ignored.
+In compatibility mode,
+any other options are flagged as illegal, but are otherwise ignored.
+In normal operation, as long as program text has been supplied, unknown
+options are passed on to the AWK program in the
+.B ARGV
+array for processing. This is particularly useful for running AWK
+programs via the ``#!'' executable interpreter mechanism.
.SH AWK PROGRAM EXECUTION
.PP
An AWK program consists of a sequence of pattern-action statements
@@ -270,23 +305,23 @@ and optional function definitions.
.I Gawk
first reads the program source from the
.IR program-file (s)
-if specified, or from the first non-option argument on the command line.
+if specified,
+from arguments to
+.BR "\-W source=" ,
+or from the first non-option argument on the command line.
The
.B \-f
-option may be used multiple times on the command line.
+and
+.B "\-W source="
+options may be used multiple times on the command line.
.I Gawk
will read the program text as if all the
.IR program-file s
+and command line source texts
had been concatenated together. This is useful for building libraries
of AWK functions, without having to include them in each new AWK
-program that uses them. To use a library function in a file from a
-program typed in on the command line, specify
-.B /dev/tty
-as one of the
-.IR program-file s,
-type your program, and end it with a
-.B ^D
-(control-d).
+program that uses them. It also provides the ability to mix library
+functions with command line programs.
.PP
The environment variable
.B AWKPATH
@@ -302,12 +337,14 @@ option contains a ``/'' character, no path search is performed.
.I Gawk
executes AWK programs in the following order.
First,
-.I gawk
-compiles the program into an internal form.
-Next, all variable assignments specified via the
+all variable assignments specified via the
.B \-v
-option are performed. Then,
-.I gawk
+option are performed.
+Next,
+.I awk
+compiles the program into an internal form.
+Then,
+.I awk
executes the code in the
.B BEGIN
block(s) (if any),
@@ -316,7 +353,7 @@ each file named in the
.B ARGV
array.
If there are no files named on the command line,
-.I gawk
+.I awk
reads the standard input.
.PP
If a filename on the command line has the form
@@ -337,11 +374,11 @@ a single data file.
If the value of a particular element of
.B ARGV
is empty (\fB""\fR),
-.I gawk
+.I awk
skips over it.
.PP
For each line in the input,
-.I gawk
+.I awk
tests to see if it matches any
.I pattern
in the AWK program.
@@ -351,7 +388,7 @@ is executed.
The patterns are tested in the order they occur in the program.
.PP
Finally, after all the input is exhausted,
-.I gawk
+.I awk
executes the code in the
.B END
block(s) (if any).
@@ -359,14 +396,14 @@ block(s) (if any).
AWK variables are dynamic; they come into existence when they are
first used. Their values are either floating-point numbers or strings,
or both,
-depending upon how they are used. AWK also has one dimension
-arrays; multiply dimensioned arrays may be simulated.
+depending upon how they are used. AWK also has one dimensional
+arrays; arrays with multiple dimensions may be simulated.
Several pre-defined variables are set as a program
runs; these will be described as needed and summarized below.
.SS Fields
.PP
As each input line is read,
-.I gawk
+.I awk
splits the line into
.IR fields ,
using the value of the
@@ -392,7 +429,7 @@ If the
.B FIELDWIDTHS
variable is set to a space separated list of numbers, each field is
expected to have fixed width, and
-.I gawk
+.I awk
will split up the record using the specified widths. The value of
.B FS
is ignored.
@@ -435,6 +472,7 @@ cause the value of
.B $0
to be recomputed, with the fields being separated by the value of
.BR OFS .
+References to negative numbered fields cause a fatal error.
.SS Built-in Variables
.PP
AWK's built-in variables are:
@@ -442,7 +480,7 @@ AWK's built-in variables are:
.TP \w'\fBFIELDWIDTHS\fR'u+1n
.B ARGC
The number of command line arguments (does not include options to
-.IR gawk ,
+.IR awk ,
or the program source).
.TP
.B ARGIND
@@ -468,12 +506,12 @@ The array is indexed by the environment variables, each element being
the value of that variable (e.g., \fBENVIRON["HOME"]\fP might be
.BR /u/arnold ).
Changing this array does not affect the environment seen by programs which
-.I gawk
+.I awk
spawns via redirection or the
.B system()
function.
(This may change in a future version of
-.IR gawk .)
+.IR awk .)
.\" but don't hold your breath...
.TP
.B ERRNO
@@ -482,7 +520,7 @@ If a system error occurs either doing a redirection for
during a read for
.BR getline ,
or during a
-.BR close ,
+.BR close() ,
then
.B ERRNO
will contain
@@ -490,14 +528,14 @@ a string describing the error.
.TP
.B FIELDWIDTHS
A white-space separated list of fieldwidths. When set,
-.I gawk
+.I awk
parses the input into fields of fixed width, instead of using the
value of the
.B FS
variable as the field separator.
The fixed field width facility is still experimental; expect the
semantics to change as
-.I gawk
+.I awk
evolves over time.
.TP
.B FILENAME
@@ -505,6 +543,11 @@ The name of the current input file.
If no files are specified on the command line, the value of
.B FILENAME
is ``\-''.
+However,
+.B FILENAME
+is undefined inside the
+.B BEGIN
+block.
.TP
.B FNR
The input record number in the current input file.
@@ -562,7 +605,7 @@ The input record separator, by default a newline.
is exceptional in that only the first character of its string
value is used for separating records.
(This will probably change in a future release of
-.IR gawk .)
+.IR awk .)
If
.B RS
is set to the null string, then records are separated by
@@ -644,6 +687,9 @@ loop to iterate over all the elements of an array.
An element may be deleted from an array using the
.B delete
statement.
+The
+.B delete
+statement may also be used to delete the entire contents of an array.
.SS Variable Typing And Conversion
.PP
Variables and fields
@@ -680,7 +726,7 @@ b = a ""
.PP
the variable
.B b
-has a value of \fB"12"\fR and not \fB"12.00"\fR.
+has a string value of \fB"12"\fR and not \fB"12.00"\fR.
.PP
.I Gawk
performs comparisons as follows:
@@ -693,7 +739,7 @@ Two strings are compared, of course, as strings.
According to the \*(PX standard, even if two strings are
numeric strings, a numeric comparison is performed. However, this is
clearly incorrect, and
-.I gawk
+.I awk
does not do this.
.PP
Uninitialized variables have the numeric value 0 and the string value ""
@@ -809,7 +855,8 @@ the third. Only one of the second and third patterns is evaluated.
.PP
The
.IB pattern1 ", " pattern2
-form of an expression is called a range pattern.
+form of an expression is called a
+.IR "range pattern" .
It matches all input records starting with a line that matches
.IR pattern1 ,
and continuing until a record that matches
@@ -982,6 +1029,7 @@ as follows:
\fBbreak\fR
\fBcontinue\fR
\fBdelete \fIarray\^\fB[\^\fIindex\^\fB]\fR
+\fBdelete \fIarray\^\fR
\fBexit\fR [ \fIexpression\fR ]
\fB{ \fIstatements \fB}
.fi
@@ -1046,10 +1094,20 @@ Prints the current record.
.TP
.BI print " expr-list"
Prints expressions.
+Each expression is separated by the value of the
+.B OFS
+variable. The output record is terminated with the value of the
+.B ORS
+variable.
.TP
.BI print " expr-list" " >" file
Prints expressions on
.IR file .
+Each expression is separated by the value of the
+.B OFS
+variable. The output record is terminated with the value of the
+.B ORS
+variable.
.TP
.BI printf " fmt, expr-list"
Format and print.
@@ -1078,8 +1136,9 @@ In a similar fashion,
.IB command " | getline"
pipes into
.BR getline .
-.BR Getline
-will return 0 on end of file, and \-1 on an error.
+The
+.BR getline
+command will return 0 on end of file, and \-1 on an error.
.SS The \fIprintf\fP\^ Statement
.PP
The AWK versions of the
@@ -1153,6 +1212,7 @@ The expression should be left-justified within its field.
The field should be padded to this width. If the number has a leading
zero, then the field will be padded with zeros.
Otherwise it is padded with blanks.
+This applies even to the non-numeric output formats.
.TP
.BI . prec
A number indicating the maximum width of strings or digits to the right
@@ -1186,13 +1246,13 @@ into a file,
or via
.B getline
from a file,
-.I gawk
+.I awk
recognizes certain special filenames internally. These filenames
allow access to open file descriptors inherited from
-.IR gawk 's
+.IR awk 's
parent process (usually the shell).
Other special filenames provide access information about the running
-.B gawk
+.B awk
process.
The filenames are:
.TP \w'\fB/dev/stdout\fR'u+1n
@@ -1229,7 +1289,7 @@ is the value of the
system call.
If there are any additional fields, they are the group IDs returned by
.IR getgroups (2).
-(Multiple groups may not be supported on all systems.)
+Multiple groups may not be supported on all systems.
.TP
.B /dev/stdin
The standard input.
@@ -1360,6 +1420,9 @@ and returns the number of fields. If
is omitted,
.B FS
is used instead.
+The array
+.I a
+is cleared first.
.TP
.BI sprintf( fmt , " expr-list" )
prints
@@ -1405,7 +1468,7 @@ Non-alphabetic characters are left unchanged.
.PP
Since one of the primary uses of AWK programs is processing log files
that contain time stamp information,
-.I gawk
+.I awk
provides the following two functions for obtaining time stamps and
formatting them.
.PP
@@ -1433,11 +1496,11 @@ guaranteed to be available.
A public-domain version of
.IR strftime (3)
and a man page for it are shipped with
-.IR gawk ;
+.IR awk ;
if that version was used to build
-.IR gawk ,
+.IR awk ,
then all of the conversions described in that man page are available to
-.IR gawk.
+.IR awk.
.SS String Constants
.PP
String constants in AWK are sequences of characters enclosed
@@ -1477,11 +1540,11 @@ the
As in \*(AN C, all following hexadecimal digits are considered part of
the escape sequence.
(This feature should tell us something about language design by committee.)
-E.g., "\ex1B" is the \s-1ASCII\s+1 \s-1ESC\s+1 (escape) character.
+E.g., \fB"\ex1B"\fR is the \s-1ASCII\s+1 \s-1ESC\s+1 (escape) character.
.TP
.BI \e ddd
The character represented by the 1-, 2-, or 3-digit sequence of octal
-digits. E.g. "\e033" is the \s-1ASCII\s+1 \s-1ESC\s+1 (escape) character.
+digits. E.g. \fB"\e033"\fR is the \s-1ASCII\s+1 \s-1ESC\s+1 (escape) character.
.TP
.BI \e c
The literal character
@@ -1562,7 +1625,15 @@ Concatenate and line number (a variation on a theme):
.ft R
.fi
.SH SEE ALSO
-.IR egrep (1)
+.IR egrep (1),
+.IR getpid (2),
+.IR getppid (2),
+.IR getpgrp (2),
+.IR getuid (2),
+.IR geteuid (2),
+.IR getgid (2),
+.IR getegid (2),
+.IR getgroups (2)
.PP
.IR "The AWK Programming Language" ,
Alfred V. Aho, Brian W. Kernighan, Peter J. Weinberger,
@@ -1572,12 +1643,12 @@ Addison-Wesley, 1988. ISBN 0-201-07981-X.
Edition 0.15, published by the Free Software Foundation, 1993.
.SH POSIX COMPATIBILITY
A primary goal for
-.I gawk
+.I awk
is compatibility with the \*(PX standard, as well as with the
latest version of \*(UX
.IR awk .
To this end,
-.I gawk
+.I awk
incorporates the following user visible
features which are not described in the AWK book,
but are part of
@@ -1600,7 +1671,7 @@ block was run. Applications came to depend on this ``feature.''
When
.I awk
was changed to match its documentation, this option was added to
-accomodate applications that depended upon the old behavior.
+accommodate applications that depended upon the old behavior.
(This feature was agreed upon by both the AT&T and GNU developers.)
.PP
The
@@ -1608,9 +1679,13 @@ The
option for implementation specific features is from the \*(PX standard.
.PP
When processing arguments,
-.I gawk
+.I awk
uses the special option ``\fB\-\^\-\fP'' to signal the end of
-arguments, and warns about, but otherwise ignores, undefined options.
+arguments.
+In compatibility mode, it will warn about, but otherwise ignore,
+undefined options.
+In normal operation, such arguments are passed on to the AWK program for
+it to process.
.PP
The AWK book does not define the return value of
.BR srand() .
@@ -1621,7 +1696,7 @@ has it return the seed it was using, to allow keeping track
of random number sequences. Therefore
.B srand()
in
-.I gawk
+.I awk
also returns its current seed.
.PP
Other new features are:
@@ -1636,7 +1711,7 @@ array; the
and
.BR \ev
escape sequences (done originally in
-.I gawk
+.I awk
and fed back into AT&T's); the
.B tolower()
and
@@ -1651,13 +1726,13 @@ has some extensions to \*(PX
They are described in this section. All the extensions described here
can be disabled by
invoking
-.I gawk
+.I awk
with the
.B "\-W compat"
option.
.PP
The following features of
-.I gawk
+.I awk
are not available in
\*(PX
.IR awk .
@@ -1706,6 +1781,11 @@ environment variable is not special.
The use of
.B "next file"
to abandon processing of the current input file.
+.TP
+\(bu
+The use of
+.BI delete " array"
+to delete the entire contents of an array.
.RE
.PP
The AWK book does not define the return value of the
@@ -1720,7 +1800,7 @@ or
when closing a file or pipe, respectively.
.PP
When
-.I gawk
+.I awk
is invoked with the
.B "\-W compat"
option,
@@ -1733,12 +1813,12 @@ option is ``t'', then
will be set to the tab character.
Since this is a rather ugly special case, it is not the default behavior.
This behavior also does not occur if
-.B \-Wposix
+.B "\-W posix"
has been specified.
.ig
.PP
If
-.I gawk
+.I awk
was compiled for debugging, it will
accept the following additional options:
.TP
@@ -1753,13 +1833,13 @@ or
.IR bison (1)
debugging output during program parsing.
This option should only be of interest to the
-.I gawk
+.I awk
maintainers, and may not even be compiled into
-.IR gawk .
+.IR awk .
..
.SH HISTORICAL FEATURES
There are two features of historical AWK implementations that
-.I gawk
+.I awk
supports.
First, it is possible to call the
.B length()
@@ -1783,9 +1863,9 @@ a = length($0)
.RE
.PP
This feature is marked as ``deprecated'' in the \*(PX standard, and
-.I gawk
+.I awk
will issue a warning about its use if
-.B \-Wlint
+.B "\-W lint"
is specified on the command line.
.PP
The other feature is the use of the
@@ -1801,8 +1881,21 @@ equivalent to the
statement.
.I Gawk
will support this usage if
-.B \-Wposix
+.B "\-W posix"
has not been specified.
+.SH ENVIRONMENT VARIABLES
+If
+.B POSIXLY_CORRECT
+exists in the environment, then
+.I awk
+behaves exactly as if
+.B \-\-posix
+had been specified on the command line.
+If
+.B \-\-lint
+has been specified,
+.I awk
+will issue a warning message to this effect.
.SH BUGS
The
.B \-F
@@ -1817,9 +1910,9 @@ and the associated
and
.B /dev/stderr
files, you may get different output from
-.I gawk
+.I awk
than you would get on a system without those files. When
-.I gawk
+.I awk
interprets these files internally, it synchronizes output to the standard
output with output to
.BR /dev/stdout ,
@@ -1828,11 +1921,11 @@ open files.
Caveat Emptor.
.SH VERSION INFORMATION
This man page documents
-.IR gawk ,
+.IR awk ,
version 2.15.
.PP
Starting with the 2.15 version of
-.IR gawk ,
+.IR awk ,
the
.BR \-c ,
.BR \-V ,
@@ -1844,6 +1937,7 @@ the
and
.B \-e
options of the 2.11 version are no longer recognized.
+This fact will not even be documented in the manual page for version 2.16.
.SH AUTHORS
The original version of \*(UX
.I awk
@@ -1867,6 +1961,8 @@ compatible with the new version of \*(UX
The initial DOS port was done by Conrad Kwok and Scott Garfinkle.
Scott Deifik is the current DOS maintainer. Pat Rankin did the
port to VMS, and Michal Jaegermann did the port to the Atari ST.
+The port to OS/2 was done by Kai Uwe Rommel, with contributions and
+help from Darrel Hankerson.
.SH ACKNOWLEDGEMENTS
Brian Kernighan of Bell Labs
provided valuable assistance during testing and debugging.
diff --git a/gnu/usr.bin/awk/awk.h b/gnu/usr.bin/awk/awk.h
index ca3997f..453a724 100644
--- a/gnu/usr.bin/awk/awk.h
+++ b/gnu/usr.bin/awk/awk.h
@@ -1,37 +1,41 @@
/*
- * awk.h -- Definitions for gawk.
+ * awk.h -- Definitions for gawk.
*/
-/*
- * Copyright (C) 1986, 1988, 1989, 1991, 1992 the Free Software Foundation, Inc.
- *
+/*
+ * Copyright (C) 1986, 1988, 1989, 1991, 1992, 1993 the Free Software Foundation, Inc.
+ *
* This file is part of GAWK, the GNU implementation of the
* AWK Progamming Language.
- *
+ *
* GAWK is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
- *
+ *
* GAWK is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
- *
+ *
* You should have received a copy of the GNU General Public License
* along with GAWK; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/* ------------------------------ Includes ------------------------------ */
+#include "config.h"
+
#include <stdio.h>
+#ifndef LIMITS_H_MISSING
#include <limits.h>
+#endif
#include <ctype.h>
#include <setjmp.h>
#include <varargs.h>
#include <time.h>
#include <errno.h>
-#if !defined(errno) && !defined(MSDOS)
+#if !defined(errno) && !defined(MSDOS) && !defined(OS2)
extern int errno;
#endif
#ifdef __GNU_LIBRARY__
@@ -42,6 +46,10 @@ extern int errno;
/* ----------------- System dependencies (with more includes) -----------*/
+#if defined(__FreeBSD__)
+# include <floatingpoint.h>
+#endif
+
#if !defined(VMS) || (!defined(VAXC) && !defined(__DECC))
#include <sys/types.h>
#include <sys/stat.h>
@@ -53,8 +61,6 @@ extern int errno;
#include <signal.h>
-#include "config.h"
-
#ifdef __STDC__
#define P(s) s
#define MALLOC_ARG_T size_t
@@ -88,7 +94,7 @@ typedef unsigned int size_t;
#if defined(atarist) || defined(VMS)
#include <unixlib.h>
#else /* atarist || VMS */
-#ifndef MSDOS
+#if !defined(MSDOS) && !defined(_MSC_VER)
#include <unistd.h>
#endif /* MSDOS */
#endif /* atarist || VMS */
@@ -111,7 +117,11 @@ extern char *alloca();
#endif
#else /* not sparc */
#if !defined(alloca) && !defined(ALLOCA_PROTO)
+#if defined(_MSC_VER)
+#include <malloc.h>
+#else
extern char *alloca();
+#endif /* _MSC_VER */
#endif
#endif /* sparc */
#endif /* __GNUC__ */
@@ -150,7 +160,7 @@ extern FILE *popen P((const char *,const char *));
extern int pclose P((FILE *));
extern void vms_arg_fixup P((int *,char ***));
/* some things not in STDC_HEADERS */
-extern int gnu_strftime P((char *,size_t,const char *,const struct tm *));
+extern size_t gnu_strftime P((char *,size_t,const char *,const struct tm *));
extern int unlink P((const char *));
extern int getopt P((int,char **,char *));
extern int isatty P((int));
@@ -158,22 +168,17 @@ extern int isatty P((int));
extern int fileno P((FILE *));
#endif
extern int close(), dup(), dup2(), fstat(), read(), stat();
+extern int getpgrp P((void));
#endif /*VMS*/
-#ifdef MSDOS
-#include <io.h>
-extern FILE *popen P((char *, char *));
-extern int pclose P((FILE *));
-#endif
-
#define GNU_REGEX
#ifdef GNU_REGEX
-#include "regex.h"
+#include "gnuregex.h"
#include "dfa.h"
typedef struct Regexp {
struct re_pattern_buffer pat;
struct re_registers regs;
- struct regexp dfareg;
+ struct dfa dfareg;
int dfa;
} Regexp;
#define RESTART(rp,s) (rp)->regs.start[0]
@@ -184,6 +189,9 @@ typedef struct Regexp {
#ifdef atarist
#define read _text_read /* we do not want all these CR's to mess our input */
extern int _text_read (int, char *, int);
+#ifndef __MINT__
+#undef NGROUPS_MAX
+#endif /* __MINT__ */
#endif
#ifndef DEFPATH
@@ -194,6 +202,8 @@ extern int _text_read (int, char *, int);
#define ENVSEP ':'
#endif
+extern double double_to_int P((double d));
+
/* ------------------ Constants, Structures, Typedefs ------------------ */
#define AWKNUM double
@@ -296,7 +306,7 @@ typedef enum {
/*
* boolean test of membership in array lnode is string-valued
- * expression rnode is array name
+ * expression rnode is array name
*/
Node_in_array,
@@ -331,6 +341,7 @@ typedef struct exp_node {
union {
struct exp_node *lptr;
char *param_name;
+ long ll;
} l;
union {
struct exp_node *rptr;
@@ -343,6 +354,7 @@ typedef struct exp_node {
union {
char *name;
struct exp_node *extra;
+ long xl;
} x;
short number;
unsigned char reflags;
@@ -362,7 +374,7 @@ typedef struct exp_node {
struct {
struct exp_node *next;
char *name;
- int length;
+ size_t length;
struct exp_node *value;
} hash;
#define hnext sub.hash.next
@@ -388,8 +400,8 @@ typedef struct exp_node {
# define NUM 32 /* numeric value is current */
# define NUMBER 64 /* assigned as number */
# define MAYBE_NUM 128 /* user input: if NUMERIC then
- * a NUMBER
- */
+ * a NUMBER */
+# define ARRAYMAXED 256 /* array is at max size */
char *vname; /* variable's name */
} NODE;
@@ -422,6 +434,8 @@ typedef struct exp_node {
#define var_value lnode
#define var_array sub.nodep.r.av
+#define array_size sub.nodep.l.ll
+#define table_size sub.nodep.x.xl
#define condpair lnode
#define triggered sub.nodep.r.r_ent
@@ -429,8 +443,6 @@ typedef struct exp_node {
#ifdef DONTDEF
int primes[] = {31, 61, 127, 257, 509, 1021, 2053, 4099, 8191, 16381};
#endif
-/* a quick profile suggests that the following is a good value */
-#define HASHSIZE 127
typedef struct for_loop_header {
NODE *init;
@@ -440,8 +452,8 @@ typedef struct for_loop_header {
/* for "for(iggy in foo) {" */
struct search {
- NODE **arr_ptr;
- NODE **arr_end;
+ NODE *sym;
+ size_t idx;
NODE *bucket;
NODE *retval;
};
@@ -499,13 +511,25 @@ struct src {
/* Return means return from a function call; leave value in ret_node */
#define TAG_RETURN 3
-#define HUGE INT_MAX
+#ifndef INT_MAX
+#define INT_MAX (~(1 << (sizeof (int) * 8 - 1)))
+#endif
+#ifndef LONG_MAX
+#define LONG_MAX (~(1 << (sizeof (long) * 8 - 1)))
+#endif
+#ifndef ULONG_MAX
+#define ULONG_MAX (~(unsigned long)0)
+#endif
+#ifndef LONG_MIN
+#define LONG_MIN (-LONG_MAX - 1)
+#endif
+#define HUGE INT_MAX
/* -------------------------- External variables -------------------------- */
/* gawk builtin variables */
-extern int NF;
-extern int NR;
-extern int FNR;
+extern long NF;
+extern long NR;
+extern long FNR;
extern int IGNORECASE;
extern char *RS;
extern char *OFS;
@@ -558,17 +582,20 @@ extern int in_end_rule;
#ifdef DEBUG
#define tree_eval(t) r_tree_eval(t)
+#define get_lhs(p, a) r_get_lhs((p), (a))
+#undef freenode
#else
-#define tree_eval(t) (_t = (t),(_t) == NULL ? Nnull_string : \
- ((_t)->type == Node_val ? (_t) : \
- ((_t)->type == Node_var ? (_t)->var_value : \
- ((_t)->type == Node_param_list ? \
- (stack_ptr[(_t)->param_cnt])->var_value : \
- r_tree_eval((_t))))))
+#define get_lhs(p, a) ((p)->type == Node_var ? (&(p)->var_value) : \
+ r_get_lhs((p), (a)))
+#define tree_eval(t) (_t = (t),_t == NULL ? Nnull_string : \
+ (_t->type == Node_param_list ? r_tree_eval(_t) : \
+ (_t->type == Node_val ? _t : \
+ (_t->type == Node_var ? _t->var_value : \
+ r_tree_eval(_t)))))
#endif
-#define make_number(x) mk_number((x), (MALLOC|NUM|NUMBER))
-#define tmp_number(x) mk_number((x), (MALLOC|TEMP|NUM|NUMBER))
+#define make_number(x) mk_number((x), (unsigned int)(MALLOC|NUM|NUMBER))
+#define tmp_number(x) mk_number((x), (unsigned int)(MALLOC|TEMP|NUM|NUMBER))
#define free_temp(n) do {if ((n)->flags&TEMP) { unref(n); }} while (0)
#define make_string(s,l) make_str_node((s), SZTC (l),0)
@@ -620,7 +647,7 @@ extern double _msc51bug;
/* array.c */
extern NODE *concat_exp P((NODE *tree));
extern void assoc_clear P((NODE *symbol));
-extern unsigned int hash P((char *s, int len));
+extern unsigned int hash P((const char *s, size_t len, unsigned long hsize));
extern int in_array P((NODE *symbol, NODE *subs));
extern NODE **assoc_lookup P((NODE *symbol, NODE *subs));
extern void do_delete P((NODE *symbol, NODE *tree));
@@ -631,7 +658,7 @@ extern char *tokexpand P((void));
extern char nextc P((void));
extern NODE *node P((NODE *left, NODETYPE op, NODE *right));
extern NODE *install P((char *name, NODE *value));
-extern NODE *lookup P((char *name));
+extern NODE *lookup P((const char *name));
extern NODE *variable P((char *name, int can_free));
extern int yyparse P((void));
/* builtin.c */
@@ -663,7 +690,7 @@ extern NODE *do_sub P((NODE *tree));
extern int interpret P((NODE *volatile tree));
extern NODE *r_tree_eval P((NODE *tree));
extern int cmp_nodes P((NODE *t1, NODE *t2));
-extern NODE **get_lhs P((NODE *ptr, Func_ptr *assign));
+extern NODE **r_get_lhs P((NODE *ptr, Func_ptr *assign));
extern void set_IGNORECASE P((void));
void set_OFS P((void));
void set_ORS P((void));
@@ -687,8 +714,8 @@ extern struct redirect *redirect P((NODE *tree, int *errflg));
extern NODE *do_close P((NODE *tree));
extern int flush_io P((void));
extern int close_io P((void));
-extern int devopen P((char *name, char *mode));
-extern int pathopen P((char *file));
+extern int devopen P((const char *name, const char *mode));
+extern int pathopen P((const char *file));
extern NODE *do_getline P((NODE *tree));
extern void do_nextfile P((void));
/* iop.c */
@@ -702,13 +729,12 @@ extern void load_environ P((void));
extern char *arg_assign P((char *arg));
extern SIGTYPE catchsig P((int sig, int code));
/* msg.c */
-#ifdef MSDOS
-extern void err P((char *s, char *emsg, char *va_list, ...));
-extern void msg P((char *va_alist, ...));
-extern void warning P((char *va_alist, ...));
-extern void fatal P((char *va_alist, ...));
+extern void err P((const char *s, const char *emsg, va_list argp));
+#if _MSC_VER == 510
+extern void msg P((va_list va_alist, ...));
+extern void warning P((va_list va_alist, ...));
+extern void fatal P((va_list va_alist, ...));
#else
-extern void err ();
extern void msg ();
extern void warning ();
extern void fatal ();
@@ -727,8 +753,9 @@ extern void freenode P((NODE *it));
extern void unref P((NODE *tmp));
extern int parse_escape P((char **string_ptr));
/* re.c */
-extern Regexp *make_regexp P((char *s, int len, int ignorecase, int dfa));
-extern int research P((Regexp *rp, char *str, int start, int len, int need_start));
+extern Regexp *make_regexp P((char *s, size_t len, int ignorecase, int dfa));
+extern int research P((Regexp *rp, char *str, int start,
+ size_t len, int need_start));
extern void refree P((Regexp *rp));
extern void reg_error P((const char *s));
extern Regexp *re_update P((NODE *t));
diff --git a/gnu/usr.bin/awk/awk.y b/gnu/usr.bin/awk/awk.y
index 6e87f1c..175cea9 100644
--- a/gnu/usr.bin/awk/awk.y
+++ b/gnu/usr.bin/awk/awk.y
@@ -3,7 +3,7 @@
*/
/*
- * Copyright (C) 1986, 1988, 1989, 1991, 1992 the Free Software Foundation, Inc.
+ * Copyright (C) 1986, 1988, 1989, 1991, 1992, 1993 the Free Software Foundation, Inc.
*
* This file is part of GAWK, the GNU implementation of the
* AWK Progamming Language.
@@ -56,9 +56,10 @@ static char *thisline = NULL;
#define YYDEBUG_LEXER_TEXT (lexeme)
static int param_counter;
static char *tokstart = NULL;
-static char *token = NULL;
+static char *tok = NULL;
static char *tokend;
+#define HASHSIZE 1021 /* this constant only used here */
NODE *variables[HASHSIZE];
extern char *source;
@@ -116,6 +117,7 @@ extern NODE *end_block;
%left LEX_GETLINE
%nonassoc LEX_IN
%left FUNC_CALL LEX_BUILTIN LEX_LENGTH
+%nonassoc ','
%nonassoc MATCHOP
%nonassoc RELOP '<' '>' '|' APPEND_OP
%left CONCAT_OP
@@ -161,6 +163,7 @@ program
}
| error { $$ = NULL; }
| program error { $$ = NULL; }
+ | /* empty */ { $$ = NULL; }
;
rule
@@ -276,7 +279,7 @@ function_body
pattern
: exp
{ $$ = $1; }
- | exp comma exp
+ | exp ',' exp
{ $$ = mkrangenode ( node($1, Node_cond_pair, $3) ); }
;
@@ -290,7 +293,7 @@ regexp
REGEXP '/'
{
NODE *n;
- int len;
+ size_t len;
getnode(n);
n->type = Node_regex;
@@ -385,10 +388,19 @@ statement
if ($2 && $2 == lookup("file")) {
if (do_lint)
warning("`next file' is a gawk extension");
- else if (do_unix || do_posix)
- yyerror("`next file' is a gawk extension");
- else if (! io_allowed)
- yyerror("`next file' used in BEGIN or END action");
+ if (do_unix || do_posix) {
+ /*
+ * can't use yyerror, since may have overshot
+ * the source line
+ */
+ errcount++;
+ msg("`next file' is a gawk extension");
+ }
+ if (! io_allowed) {
+ /* same thing */
+ errcount++;
+ msg("`next file' used in BEGIN or END action");
+ }
type = Node_K_nextfile;
} else {
if (! io_allowed)
@@ -405,6 +417,20 @@ statement
{ $$ = node ($3, Node_K_return, (NODE *)NULL); }
| LEX_DELETE NAME '[' expression_list ']' statement_term
{ $$ = node (variable($2,1), Node_K_delete, $4); }
+ | LEX_DELETE NAME statement_term
+ {
+ if (do_lint)
+ warning("`delete array' is a gawk extension");
+ if (do_unix || do_posix) {
+ /*
+ * can't use yyerror, since may have overshot
+ * the source line
+ */
+ errcount++;
+ msg("`delete array' is a gawk extension");
+ }
+ $$ = node (variable($2,1), Node_K_delete, (NODE *) NULL);
+ }
| exp statement_term
{ $$ = $1; }
;
@@ -693,7 +719,11 @@ non_post_simp_exp
$$ = node ($2, Node_unary_minus, (NODE *)NULL);
}
| '+' simp_exp %prec UNARY
- { $$ = $2; }
+ {
+ /* was: $$ = $2 */
+ /* POSIX semantics: force a conversion to numeric type */
+ $$ = node (make_number(0.0), Node_plus, $2);
+ }
;
opt_variable
@@ -745,7 +775,7 @@ comma : ',' opt_nls { yyerrok; }
%%
struct token {
- char *operator; /* text to match */
+ const char *operator; /* text to match */
NODETYPE value; /* node type */
int class; /* lexical class */
unsigned flags; /* # of args. allowed and compatability */
@@ -819,14 +849,15 @@ yyerror(va_alist)
va_dcl
{
va_list args;
- char *mesg = NULL;
+ const char *mesg = NULL;
register char *bp, *cp;
char *scan;
char buf[120];
+ static char end_of_file_line[] = "(END OF FILE)";
errcount++;
/* Find the current line in the input file */
- if (lexptr) {
+ if (lexptr && lexeme) {
if (!thisline) {
cp = lexeme;
if (*cp == '\n') {
@@ -834,7 +865,7 @@ va_dcl
mesg = "unexpected newline";
}
for ( ; cp != lexptr_begin && *cp != '\n'; --cp)
- ;
+ continue;
if (*cp == '\n')
cp++;
thisline = cp;
@@ -844,8 +875,8 @@ va_dcl
while (bp < lexend && *bp && *bp != '\n')
bp++;
} else {
- thisline = "(END OF FILE)";
- bp = thisline + 13;
+ thisline = end_of_file_line;
+ bp = thisline + strlen(thisline);
}
msg("%.*s", (int) (bp - thisline), thisline);
bp = buf;
@@ -882,12 +913,22 @@ get_src_buf()
static int did_newline = 0;
# define SLOP 128 /* enough space to hold most source lines */
+again:
if (nextfile > numfiles)
return NULL;
if (srcfiles[nextfile].stype == CMDLINE) {
if (len == 0) {
len = strlen(srcfiles[nextfile].val);
+ if (len == 0) {
+ /*
+ * Yet Another Special case:
+ * gawk '' /path/name
+ * Sigh.
+ */
+ ++nextfile;
+ goto again;
+ }
sourceline = 1;
lexptr = lexptr_begin = srcfiles[nextfile].val;
lexend = lexptr + len;
@@ -973,6 +1014,7 @@ get_src_buf()
if (n == 0) {
samefile = 0;
nextfile++;
+ *lexeme = '\0';
len = 0;
return get_src_buf();
}
@@ -981,7 +1023,7 @@ get_src_buf()
return buf;
}
-#define tokadd(x) (*token++ = (x), token == tokend ? tokexpand() : token)
+#define tokadd(x) (*tok++ = (x), tok == tokend ? tokexpand() : tok)
char *
tokexpand()
@@ -989,15 +1031,15 @@ tokexpand()
static int toksize = 60;
int tokoffset;
- tokoffset = token - tokstart;
+ tokoffset = tok - tokstart;
toksize *= 2;
if (tokstart)
erealloc(tokstart, char *, toksize, "tokexpand");
else
emalloc(tokstart, char *, toksize, "tokexpand");
tokend = tokstart + toksize;
- token = tokstart + tokoffset;
- return token;
+ tok = tokstart + tokoffset;
+ return tok;
}
#if DEBUG
@@ -1036,13 +1078,23 @@ yylex()
if (!nextc())
return 0;
pushback();
+#ifdef OS2
+ /*
+ * added for OS/2's extproc feature of cmd.exe
+ * (like #! in BSD sh)
+ */
+ if (strncasecmp(lexptr, "extproc ", 8) == 0) {
+ while (*lexptr && *lexptr != '\n')
+ lexptr++;
+ }
+#endif
lexeme = lexptr;
thisline = NULL;
if (want_regexp) {
int in_brack = 0;
want_regexp = 0;
- token = tokstart;
+ tok = tokstart;
while ((c = nextc()) != 0) {
switch (c) {
case '[':
@@ -1079,11 +1131,11 @@ yylex()
}
retry:
while ((c = nextc()) == ' ' || c == '\t')
- ;
+ continue;
lexeme = lexptr ? lexptr - 1 : lexptr;
thisline = NULL;
- token = tokstart;
+ tok = tokstart;
yylval.nodetypeval = Node_illegal;
switch (c) {
@@ -1104,18 +1156,28 @@ retry:
case '\\':
#ifdef RELAXED_CONTINUATION
- if (!do_unix) { /* strip trailing white-space and/or comment */
- while ((c = nextc()) == ' ' || c == '\t') continue;
+ /*
+ * This code puports to allow comments and/or whitespace
+ * after the `\' at the end of a line used for continuation.
+ * Use it at your own risk. We think it's a bad idea, which
+ * is why it's not on by default.
+ */
+ if (!do_unix) {
+ /* strip trailing white-space and/or comment */
+ while ((c = nextc()) == ' ' || c == '\t')
+ continue;
if (c == '#')
- while ((c = nextc()) != '\n') if (!c) break;
+ while ((c = nextc()) != '\n')
+ if (c == '\0')
+ break;
pushback();
}
-#endif /*RELAXED_CONTINUATION*/
+#endif /* RELAXED_CONTINUATION */
if (nextc() == '\n') {
sourceline++;
goto retry;
} else
- yyerror("inappropriate use of backslash");
+ yyerror("backslash not last character on line");
break;
case '$':
@@ -1296,7 +1358,7 @@ retry:
tokadd(c);
}
yylval.nodeval = make_str_node(tokstart,
- token - tokstart, esc_seen ? SCAN : 0);
+ tok - tokstart, esc_seen ? SCAN : 0);
yylval.nodeval->flags |= PERM;
return YSTRING;
@@ -1384,7 +1446,7 @@ retry:
break;
if (c == '#') {
while ((c = nextc()) != '\n' && c != '\0')
- ;
+ continue;
if (c == '\0')
break;
}
@@ -1410,7 +1472,7 @@ retry:
break;
if (c == '#') {
while ((c = nextc()) != '\n' && c != '\0')
- ;
+ continue;
if (c == '\0')
break;
}
@@ -1432,14 +1494,14 @@ retry:
yyerror("Invalid char '%c' in expression\n", c);
/* it's some type of name-type-thing. Find its length */
- token = tokstart;
+ tok = tokstart;
while (is_identchar(c)) {
tokadd(c);
c = nextc();
}
tokadd('\0');
- emalloc(tokkey, char *, token - tokstart, "yylex");
- memcpy(tokkey, tokstart, token - tokstart);
+ emalloc(tokkey, char *, tok - tokstart, "yylex");
+ memcpy(tokkey, tokstart, tok - tokstart);
pushback();
/* See if it is a special token. */
@@ -1478,6 +1540,7 @@ retry:
else
yylval.nodetypeval = tokentab[mid].value;
+ free(tokkey);
return tokentab[mid].class;
}
}
@@ -1638,10 +1701,11 @@ char *name;
NODE *value;
{
register NODE *hp;
- register int len, bucket;
+ register size_t len;
+ register int bucket;
len = strlen(name);
- bucket = hash(name, len);
+ bucket = hash(name, len, (unsigned long) HASHSIZE);
getnode(hp);
hp->type = Node_hashnode;
hp->hnext = variables[bucket];
@@ -1656,13 +1720,13 @@ NODE *value;
/* find the most recent hash node for name installed by install */
NODE *
lookup(name)
-char *name;
+const char *name;
{
register NODE *bucket;
- register int len;
+ register size_t len;
len = strlen(name);
- bucket = variables[hash(name, len)];
+ bucket = variables[hash(name, len, (unsigned long) HASHSIZE)];
while (bucket) {
if (bucket->hlength == len && STREQN(bucket->hname, name, len))
return bucket->hvalue;
@@ -1721,12 +1785,12 @@ NODE *np;
int freeit;
{
register NODE *bucket, **save;
- register int len;
+ register size_t len;
char *name;
name = np->param;
len = strlen(name);
- save = &(variables[hash(name, len)]);
+ save = &(variables[hash(name, len, (unsigned long) HASHSIZE)]);
for (bucket = *save; bucket; bucket = bucket->hnext) {
if (len == bucket->hlength && STREQN(bucket->hname, name, len)) {
*save = bucket->hnext;
diff --git a/gnu/usr.bin/awk/builtin.c b/gnu/usr.bin/awk/builtin.c
index 9d5e3b3..a9267cb 100644
--- a/gnu/usr.bin/awk/builtin.c
+++ b/gnu/usr.bin/awk/builtin.c
@@ -1,23 +1,23 @@
/*
- * builtin.c - Builtin functions and various utility procedures
+ * builtin.c - Builtin functions and various utility procedures
*/
-/*
- * Copyright (C) 1986, 1988, 1989, 1991, 1992 the Free Software Foundation, Inc.
- *
+/*
+ * Copyright (C) 1986, 1988, 1989, 1991, 1992, 1993 the Free Software Foundation, Inc.
+ *
* This file is part of GAWK, the GNU implementation of the
* AWK Progamming Language.
- *
+ *
* GAWK is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
- *
+ *
* GAWK is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
- *
+ *
* You should have received a copy of the GNU General Public License
* along with GAWK; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
@@ -26,9 +26,8 @@
#include "awk.h"
-
#ifndef SRANDOM_PROTO
-extern void srandom P((int seed));
+extern void srandom P((unsigned int seed));
#endif
#ifndef linux
extern char *initstate P((unsigned seed, char *state, int n));
@@ -40,10 +39,7 @@ extern NODE **fields_arr;
extern int output_is_tty;
static NODE *sub_common P((NODE *tree, int global));
-
-#ifdef GFMT_WORKAROUND
-char *gfmt P((double g, int prec, char *buf));
-#endif
+NODE *format_tree P((const char *, int, NODE *));
#ifdef _CRAY
/* Work around a problem in conversion of doubles to exact integers. */
@@ -63,12 +59,35 @@ double (*Log)() = log;
#define Ceil(n) ceil(n)
#endif
+#define DEFAULT_G_PRECISION 6
+
+#ifdef GFMT_WORKAROUND
+/* semi-temporary hack, mostly to gracefully handle VMS */
+static void sgfmt P((char *buf, const char *format, int alt,
+ int fwidth, int precision, double value));
+#endif /* GFMT_WORKAROUND */
+
+/*
+ * On the alpha, LONG_MAX is too big for doing rand().
+ * On the Cray (Y-MP, anyway), ints and longs are 64 bits, but
+ * random() does things in terms of 32 bits. So we have to chop
+ * LONG_MAX down.
+ */
+#if (defined(__alpha) && defined(__osf__)) || defined(_CRAY)
+#define GAWK_RANDOM_MAX (LONG_MAX & 0x7fffffff)
+#else
+#define GAWK_RANDOM_MAX LONG_MAX
+#endif
+
+static void efwrite P((const void *ptr, size_t size, size_t count, FILE *fp,
+ const char *from, struct redirect *rp,int flush));
+
static void
efwrite(ptr, size, count, fp, from, rp, flush)
-void *ptr;
-unsigned size, count;
+const void *ptr;
+size_t size, count;
FILE *fp;
-char *from;
+const char *from;
struct redirect *rp;
int flush;
{
@@ -117,7 +136,7 @@ NODE *tree;
{
NODE *s1, *s2;
register char *p1, *p2;
- register int l1, l2;
+ register size_t l1, l2;
long ret;
@@ -160,21 +179,30 @@ NODE *tree;
return tmp_number((AWKNUM) ret);
}
+double
+double_to_int(d)
+double d;
+{
+ double floor P((double));
+ double ceil P((double));
+
+ if (d >= 0)
+ d = Floor(d);
+ else
+ d = Ceil(d);
+ return d;
+}
+
NODE *
do_int(tree)
NODE *tree;
{
NODE *tmp;
- double floor P((double));
- double ceil P((double));
double d;
tmp = tree_eval(tree->lnode);
d = force_number(tmp);
- if (d >= 0)
- d = Floor(d);
- else
- d = Ceil(d);
+ d = double_to_int(d);
free_temp(tmp);
return tmp_number((AWKNUM) d);
}
@@ -184,7 +212,7 @@ do_length(tree)
NODE *tree;
{
NODE *tmp;
- int len;
+ size_t len;
tmp = tree_eval(tree->lnode);
len = force_string(tmp)->stlen;
@@ -211,34 +239,61 @@ NODE *tree;
return tmp_number((AWKNUM) d);
}
-/* %e and %f formats are not properly implemented. Someone should fix them */
-/* Actually, this whole thing should be reimplemented. */
+/*
+ * format_tree() formats nodes of a tree, starting with a left node,
+ * and accordingly to a fmt_string providing a format like in
+ * printf family from C library. Returns a string node which value
+ * is a formatted string. Called by sprintf function.
+ *
+ * It is one of the uglier parts of gawk. Thanks to Michal Jaegermann
+ * for taming this beast and making it compatible with ANSI C.
+ */
NODE *
-do_sprintf(tree)
-NODE *tree;
+format_tree(fmt_string, n0, carg)
+const char *fmt_string;
+int n0;
+register NODE *carg;
{
+/* copy 'l' bytes from 's' to 'obufout' checking for space in the process */
+/* difference of pointers should be of ptrdiff_t type, but let us be kind */
#define bchunk(s,l) if(l) {\
while((l)>ofre) {\
- erealloc(obuf, char *, osiz*2, "do_sprintf");\
+ long olen = obufout - obuf;\
+ erealloc(obuf, char *, osiz*2, "format_tree");\
ofre+=osiz;\
osiz*=2;\
+ obufout = obuf + olen;\
}\
- memcpy(obuf+olen,s,(l));\
- olen+=(l);\
+ memcpy(obufout,s,(size_t)(l));\
+ obufout+=(l);\
ofre-=(l);\
}
+/* copy one byte from 's' to 'obufout' checking for space in the process */
+#define bchunk_one(s) {\
+ if(ofre <= 0) {\
+ long olen = obufout - obuf;\
+ erealloc(obuf, char *, osiz*2, "format_tree");\
+ ofre+=osiz;\
+ osiz*=2;\
+ obufout = obuf + olen;\
+ }\
+ *obufout++ = *s;\
+ --ofre;\
+ }
/* Is there space for something L big in the buffer? */
#define chksize(l) if((l)>ofre) {\
- erealloc(obuf, char *, osiz*2, "do_sprintf");\
+ long olen = obufout - obuf;\
+ erealloc(obuf, char *, osiz*2, "format_tree");\
+ obufout = obuf + olen;\
ofre+=osiz;\
osiz*=2;\
}
/*
* Get the next arg to be formatted. If we've run out of args,
- * return "" (Null string)
+ * return "" (Null string)
*/
#define parse_next_arg() {\
if(!carg) { toofew = 1; break; }\
@@ -250,15 +305,14 @@ NODE *tree;
NODE *r;
int toofew = 0;
- char *obuf;
- int osiz, ofre, olen;
- static char chbuf[] = "0123456789abcdef";
- static char sp[] = " ";
- char *s0, *s1;
- int n0;
- NODE *sfmt, *arg;
- register NODE *carg;
- long fw, prec, lj, alt, big;
+ char *obuf, *obufout;
+ size_t osiz, ofre;
+ char *chbuf;
+ const char *s0, *s1;
+ int cs1;
+ NODE *arg;
+ long fw, prec;
+ int lj, alt, big, have_prec;
long *cur;
long val;
#ifdef sun386 /* Can't cast unsigned (int/long) from ptr->value */
@@ -266,26 +320,26 @@ NODE *tree;
#endif
unsigned long uval;
int sgn;
- int base;
+ int base = 0;
char cpbuf[30]; /* if we have numbers bigger than 30 */
char *cend = &cpbuf[30];/* chars, we lose, but seems unlikely */
char *cp;
char *fill;
double tmpval;
- char *pr_str;
- int ucasehex = 0;
char signchar = 0;
- int len;
-
+ size_t len;
+ static char sp[] = " ";
+ static char zero_string[] = "0";
+ static char lchbuf[] = "0123456789abcdef";
+ static char Uchbuf[] = "0123456789ABCDEF";
- emalloc(obuf, char *, 120, "do_sprintf");
+ emalloc(obuf, char *, 120, "format_tree");
+ obufout = obuf;
osiz = 120;
ofre = osiz - 1;
- olen = 0;
- sfmt = tree_eval(tree->lnode);
- sfmt = force_string(sfmt);
- carg = tree->rnode;
- for (s0 = s1 = sfmt->stptr, n0 = sfmt->stlen; n0-- > 0;) {
+
+ s0 = s1 = fmt_string;
+ while (n0-- > 0) {
if (*s1 != '%') {
s1++;
continue;
@@ -295,24 +349,31 @@ NODE *tree;
cur = &fw;
fw = 0;
prec = 0;
+ have_prec = 0;
lj = alt = big = 0;
fill = sp;
cp = cend;
+ chbuf = lchbuf;
s1++;
retry:
--n0;
- switch (*s1++) {
+ switch (cs1 = *s1++) {
+ case (-1): /* dummy case to allow for checking */
+check_pos:
+ if (cur != &fw)
+ break; /* reject as a valid format */
+ goto retry;
case '%':
- bchunk("%", 1);
+ bchunk_one("%");
s0 = s1;
break;
case '0':
- if (fill != sp || lj)
- goto lose;
+ if (lj)
+ goto retry;
if (cur == &fw)
- fill = "0"; /* FALL through */
+ fill = zero_string; /* FALL through */
case '1':
case '2':
case '3':
@@ -323,289 +384,259 @@ retry:
case '8':
case '9':
if (cur == 0)
- goto lose;
- *cur = s1[-1] - '0';
+ /* goto lose; */
+ break;
+ if (prec >= 0)
+ *cur = cs1 - '0';
+ /* with a negative precision *cur is already set */
+ /* to -1, so it will remain negative, but we have */
+ /* to "eat" precision digits in any case */
while (n0 > 0 && *s1 >= '0' && *s1 <= '9') {
--n0;
*cur = *cur * 10 + *s1++ - '0';
}
+ if (prec < 0) /* negative precision is discarded */
+ have_prec = 0;
+ if (cur == &prec)
+ cur = 0;
goto retry;
case '*':
if (cur == 0)
- goto lose;
+ /* goto lose; */
+ break;
parse_next_arg();
*cur = force_number(arg);
free_temp(arg);
+ if (cur == &prec)
+ cur = 0;
goto retry;
case ' ': /* print ' ' or '-' */
+ /* 'space' flag is ignored */
+ /* if '+' already present */
+ if (signchar != 0)
+ goto check_pos;
+ /* FALL THROUGH */
case '+': /* print '+' or '-' */
- signchar = *(s1-1);
- goto retry;
+ signchar = cs1;
+ goto check_pos;
case '-':
- if (lj || fill != sp)
- goto lose;
- lj++;
- goto retry;
+ if (prec < 0)
+ break;
+ if (cur == &prec) {
+ prec = -1;
+ goto retry;
+ }
+ fill = sp; /* if left justified then other */
+ lj++; /* filling is ignored */
+ goto check_pos;
case '.':
if (cur != &fw)
- goto lose;
+ break;
cur = &prec;
+ have_prec++;
goto retry;
case '#':
- if (alt)
- goto lose;
alt++;
- goto retry;
+ goto check_pos;
case 'l':
if (big)
- goto lose;
+ break;
big++;
- goto retry;
+ goto check_pos;
case 'c':
parse_next_arg();
if (arg->flags & NUMBER) {
#ifdef sun386
- tmp_uval = arg->numbr;
+ tmp_uval = arg->numbr;
uval= (unsigned long) tmp_uval;
#else
uval = (unsigned long) arg->numbr;
#endif
cpbuf[0] = uval;
prec = 1;
- pr_str = cpbuf;
- goto dopr_string;
+ cp = cpbuf;
+ goto pr_tail;
}
- if (! prec)
+ if (have_prec == 0)
prec = 1;
else if (prec > arg->stlen)
prec = arg->stlen;
- pr_str = arg->stptr;
- goto dopr_string;
+ cp = arg->stptr;
+ goto pr_tail;
case 's':
parse_next_arg();
arg = force_string(arg);
- if (!prec || prec > arg->stlen)
+ if (have_prec == 0 || prec > arg->stlen)
prec = arg->stlen;
- pr_str = arg->stptr;
-
- dopr_string:
- if (fw > prec && !lj) {
- while (fw > prec) {
- bchunk(sp, 1);
- fw--;
- }
- }
- bchunk(pr_str, (int) prec);
- if (fw > prec) {
- while (fw > prec) {
- bchunk(sp, 1);
- fw--;
- }
- }
- s0 = s1;
- free_temp(arg);
- break;
+ cp = arg->stptr;
+ goto pr_tail;
case 'd':
case 'i':
parse_next_arg();
- val = (long) force_number(arg);
- free_temp(arg);
+ tmpval = force_number(arg);
+ if (tmpval > LONG_MAX || tmpval < LONG_MIN) {
+ /* out of range - emergency use of %g format */
+ cs1 = 'g';
+ goto format_float;
+ }
+ val = (long) tmpval;
+
if (val < 0) {
sgn = 1;
- val = -val;
- } else
+ if (val > LONG_MIN)
+ uval = (unsigned long) -val;
+ else
+ uval = (unsigned long)(-(LONG_MIN + 1))
+ + (unsigned long)1;
+ } else {
sgn = 0;
+ uval = (unsigned long) val;
+ }
do {
- *--cp = '0' + val % 10;
- val /= 10;
- } while (val);
+ *--cp = (char) ('0' + uval % 10);
+ uval /= 10;
+ } while (uval);
if (sgn)
*--cp = '-';
else if (signchar)
*--cp = signchar;
+ if (have_prec != 0) /* ignore '0' flag if */
+ fill = sp; /* precision given */
if (prec > fw)
fw = prec;
prec = cend - cp;
- if (fw > prec && !lj) {
- if (fill != sp && (*cp == '-' || signchar)) {
- bchunk(cp, 1);
- cp++;
- prec--;
- fw--;
- }
- while (fw > prec) {
- bchunk(fill, 1);
- fw--;
- }
+ if (fw > prec && ! lj && fill != sp
+ && (*cp == '-' || signchar)) {
+ bchunk_one(cp);
+ cp++;
+ prec--;
+ fw--;
}
- bchunk(cp, (int) prec);
- if (fw > prec) {
- while (fw > prec) {
- bchunk(fill, 1);
- fw--;
- }
- }
- s0 = s1;
- break;
- case 'u':
- base = 10;
- goto pr_unsigned;
- case 'o':
- base = 8;
- goto pr_unsigned;
+ goto pr_tail;
case 'X':
- ucasehex = 1;
+ chbuf = Uchbuf; /* FALL THROUGH */
case 'x':
- base = 16;
- goto pr_unsigned;
- pr_unsigned:
+ base += 6; /* FALL THROUGH */
+ case 'u':
+ base += 2; /* FALL THROUGH */
+ case 'o':
+ base += 8;
parse_next_arg();
- uval = (unsigned long) force_number(arg);
- free_temp(arg);
+ tmpval = force_number(arg);
+ if (tmpval > ULONG_MAX || tmpval < LONG_MIN) {
+ /* out of range - emergency use of %g format */
+ cs1 = 'g';
+ goto format_float;
+ }
+ uval = (unsigned long)tmpval;
+ if (have_prec != 0) /* ignore '0' flag if */
+ fill = sp; /* precision given */
do {
*--cp = chbuf[uval % base];
- if (ucasehex && isalpha(*cp))
- *cp = toupper(*cp);
uval /= base;
} while (uval);
- if (alt && (base == 8 || base == 16)) {
+ if (alt) {
if (base == 16) {
- if (ucasehex)
- *--cp = 'X';
- else
- *--cp = 'x';
- }
- *--cp = '0';
+ *--cp = cs1;
+ *--cp = '0';
+ if (fill != sp) {
+ bchunk(cp, 2);
+ cp += 2;
+ fw -= 2;
+ }
+ } else if (base == 8)
+ *--cp = '0';
}
+ base = 0;
prec = cend - cp;
- if (fw > prec && !lj) {
+ pr_tail:
+ if (! lj) {
while (fw > prec) {
- bchunk(fill, 1);
+ bchunk_one(fill);
fw--;
}
}
bchunk(cp, (int) prec);
- if (fw > prec) {
- while (fw > prec) {
- bchunk(fill, 1);
- fw--;
- }
+ while (fw > prec) {
+ bchunk_one(fill);
+ fw--;
}
s0 = s1;
+ free_temp(arg);
break;
case 'g':
+ case 'G':
+ case 'e':
+ case 'f':
+ case 'E':
parse_next_arg();
tmpval = force_number(arg);
+ format_float:
free_temp(arg);
+ if (have_prec == 0)
+ prec = DEFAULT_G_PRECISION;
chksize(fw + prec + 9); /* 9==slop */
cp = cpbuf;
*cp++ = '%';
if (lj)
*cp++ = '-';
+ if (signchar)
+ *cp++ = signchar;
+ if (alt)
+ *cp++ = '#';
if (fill != sp)
*cp++ = '0';
+ cp = strcpy(cp, "*.*") + 3;
+ *cp++ = cs1;
+ *cp = '\0';
#ifndef GFMT_WORKAROUND
- if (cur != &fw) {
- (void) strcpy(cp, "*.*g");
- (void) sprintf(obuf + olen, cpbuf, (int) fw, (int) prec, (double) tmpval);
- } else {
- (void) strcpy(cp, "*g");
- (void) sprintf(obuf + olen, cpbuf, (int) fw, (double) tmpval);
- }
+ (void) sprintf(obufout, cpbuf,
+ (int) fw, (int) prec, (double) tmpval);
#else /* GFMT_WORKAROUND */
- {
- char *gptr, gbuf[120];
-#define DEFAULT_G_PRECISION 6
- if (fw + prec + 9 > sizeof gbuf) { /* 9==slop */
- emalloc(gptr, char *, fw+prec+9, "do_sprintf(gfmt)");
- } else
- gptr = gbuf;
- (void) gfmt((double) tmpval, cur != &fw ?
- (int) prec : DEFAULT_G_PRECISION, gptr);
- *cp++ = '*', *cp++ = 's', *cp = '\0';
- (void) sprintf(obuf + olen, cpbuf, (int) fw, gptr);
- if (fill != sp && *gptr == ' ') {
- char *p = gptr;
- do { *p++ = '0'; } while (*p == ' ');
- }
- if (gptr != gbuf) free(gptr);
- }
+ if (cs1 == 'g' || cs1 == 'G')
+ sgfmt(obufout, cpbuf, (int) alt,
+ (int) fw, (int) prec, (double) tmpval);
+ else
+ (void) sprintf(obufout, cpbuf,
+ (int) fw, (int) prec, (double) tmpval);
#endif /* GFMT_WORKAROUND */
- len = strlen(obuf + olen);
- ofre -= len;
- olen += len;
- s0 = s1;
- break;
-
- case 'f':
- parse_next_arg();
- tmpval = force_number(arg);
- free_temp(arg);
- chksize(fw + prec + 9); /* 9==slop */
-
- cp = cpbuf;
- *cp++ = '%';
- if (lj)
- *cp++ = '-';
- if (fill != sp)
- *cp++ = '0';
- if (cur != &fw) {
- (void) strcpy(cp, "*.*f");
- (void) sprintf(obuf + olen, cpbuf, (int) fw, (int) prec, (double) tmpval);
- } else {
- (void) strcpy(cp, "*f");
- (void) sprintf(obuf + olen, cpbuf, (int) fw, (double) tmpval);
- }
- len = strlen(obuf + olen);
+ len = strlen(obufout);
ofre -= len;
- olen += len;
+ obufout += len;
s0 = s1;
break;
- case 'e':
- parse_next_arg();
- tmpval = force_number(arg);
- free_temp(arg);
- chksize(fw + prec + 9); /* 9==slop */
- cp = cpbuf;
- *cp++ = '%';
- if (lj)
- *cp++ = '-';
- if (fill != sp)
- *cp++ = '0';
- if (cur != &fw) {
- (void) strcpy(cp, "*.*e");
- (void) sprintf(obuf + olen, cpbuf, (int) fw, (int) prec, (double) tmpval);
- } else {
- (void) strcpy(cp, "*e");
- (void) sprintf(obuf + olen, cpbuf, (int) fw, (double) tmpval);
- }
- len = strlen(obuf + olen);
- ofre -= len;
- olen += len;
- s0 = s1;
- break;
-
default:
- lose:
break;
}
if (toofew)
fatal("%s\n\t%s\n\t%*s%s",
"not enough arguments to satisfy format string",
- sfmt->stptr, s1 - sfmt->stptr - 2, "",
+ fmt_string, s1 - fmt_string - 2, "",
"^ ran out for this one"
);
}
if (do_lint && carg != NULL)
warning("too many arguments supplied for format string");
bchunk(s0, s1 - s0);
- free_temp(sfmt);
- r = make_str_node(obuf, olen, ALREADY_MALLOCED);
+ r = make_str_node(obuf, obufout - obuf, ALREADY_MALLOCED);
r->flags |= TEMP;
return r;
}
+NODE *
+do_sprintf(tree)
+NODE *tree;
+{
+ NODE *r;
+ NODE *sfmt = force_string(tree_eval(tree->lnode));
+
+ r = format_tree(sfmt->stptr, sfmt->stlen, tree->rnode);
+ free_temp(sfmt);
+ return r;
+}
+
+
void
do_printf(tree)
register NODE *tree;
@@ -654,6 +685,7 @@ NODE *tree;
NODE *r;
register int indx;
size_t length;
+ int is_long;
t1 = tree_eval(tree->lnode);
t2 = tree_eval(tree->rnode->lnode);
@@ -669,12 +701,16 @@ NODE *tree;
t1 = force_string(t1);
if (indx < 0)
indx = 0;
- if (indx >= t1->stlen || length <= 0) {
+ if (indx >= t1->stlen || (long) length <= 0) {
free_temp(t1);
return Nnull_string;
}
- if (indx + length > t1->stlen || LONG_MAX - indx < length)
+ if ((is_long = (indx + length > t1->stlen)) || LONG_MAX - indx < length) {
length = t1->stlen - indx;
+ if (do_lint && is_long)
+ warning("substr: length %d at position %d exceeds length of first argument",
+ length, indx+1);
+ }
r = tmp_string(t1->stptr + indx, length);
free_temp(t1);
return r;
@@ -688,7 +724,6 @@ NODE *tree;
struct tm *tm;
time_t fclock;
char buf[100];
- int ret;
t1 = force_string(tree_eval(tree->lnode));
@@ -701,9 +736,7 @@ NODE *tree;
}
tm = localtime(&fclock);
- ret = strftime(buf, 100, t1->stptr, tm);
-
- return tmp_string(buf, ret);
+ return tmp_string(buf, strftime(buf, 100, t1->stptr, tm));
}
NODE *
@@ -723,19 +756,44 @@ NODE *tree;
NODE *tmp;
int ret = 0;
char *cmd;
+ char save;
- (void) flush_io (); /* so output is synchronous with gawk's */
+ (void) flush_io (); /* so output is synchronous with gawk's */
tmp = tree_eval(tree->lnode);
cmd = force_string(tmp)->stptr;
+
if (cmd && *cmd) {
+ /* insure arg to system is zero-terminated */
+
+ /*
+ * From: David Trueman <emory!cs.dal.ca!david>
+ * To: arnold@cc.gatech.edu (Arnold Robbins)
+ * Date: Wed, 3 Nov 1993 12:49:41 -0400
+ *
+ * It may not be necessary to save the character, but
+ * I'm not sure. It would normally be the field
+ * separator. If the parse has not yet gone beyond
+ * that, it could mess up (although I doubt it). If
+ * FIELDWIDTHS is being used, it might be the first
+ * character of the next field. Unless someone wants
+ * to check it out exhaustively, I suggest saving it
+ * for now...
+ */
+ save = cmd[tmp->stlen];
+ cmd[tmp->stlen] = '\0';
+
ret = system(cmd);
ret = (ret >> 8) & 0xff;
+
+ cmd[tmp->stlen] = save;
}
free_temp(tmp);
return tmp_number((AWKNUM) ret);
}
-void
+extern NODE **fmt_list; /* declared in eval.c */
+
+void
do_print(tree)
register NODE *tree;
{
@@ -763,10 +821,18 @@ register NODE *tree;
if (OFMTidx == CONVFMTidx)
(void) force_string(t1);
else {
+#ifndef GFMT_WORKAROUND
char buf[100];
- sprintf(buf, OFMT, t1->numbr);
+ (void) sprintf(buf, OFMT, t1->numbr);
+ free_temp(t1);
t1 = tmp_string(buf, strlen(buf));
+#else /* GFMT_WORKAROUND */
+ free_temp(t1);
+ t1 = format_tree(OFMT,
+ fmt_list[OFMTidx]->stlen,
+ tree);
+#endif /* GFMT_WORKAROUND */
}
}
efwrite(t1->stptr, sizeof(char), t1->stlen, fp, "print", rp, 0);
@@ -775,12 +841,13 @@ register NODE *tree;
if (tree) {
s = OFS;
if (OFSlen)
- efwrite(s, sizeof(char), OFSlen, fp, "print", rp, 0);
+ efwrite(s, sizeof(char), (size_t)OFSlen,
+ fp, "print", rp, 0);
}
}
s = ORS;
if (ORSlen)
- efwrite(s, sizeof(char), ORSlen, fp, "print", rp, 1);
+ efwrite(s, sizeof(char), (size_t)ORSlen, fp, "print", rp, 1);
}
NODE *
@@ -863,7 +930,7 @@ NODE *tree;
}
static int firstrand = 1;
-static char state[256];
+static char state[512];
/* ARGSUSED */
NODE *
@@ -875,7 +942,7 @@ NODE *tree;
srandom(1);
firstrand = 0;
}
- return tmp_number((AWKNUM) random() / LONG_MAX);
+ return tmp_number((AWKNUM) random() / GAWK_RANDOM_MAX);
}
NODE *
@@ -892,10 +959,10 @@ NODE *tree;
(void) setstate(state);
if (!tree)
- srandom((int) (save_seed = (long) time((time_t *) 0)));
+ srandom((unsigned int) (save_seed = (long) time((time_t *) 0)));
else {
tmp = tree_eval(tree->lnode);
- srandom((int) (save_seed = (long) force_number(tmp)));
+ srandom((unsigned int) (save_seed = (long) force_number(tmp)));
free_temp(tmp);
}
firstrand = 0;
@@ -938,15 +1005,15 @@ int global;
register char *scan;
register char *bp, *cp;
char *buf;
- int buflen;
+ size_t buflen;
register char *matchend;
- register int len;
+ register size_t len;
char *matchstart;
char *text;
- int textlen;
+ size_t textlen;
char *repl;
char *replend;
- int repllen;
+ size_t repllen;
int sofar;
int ampersands;
int matches = 0;
@@ -970,9 +1037,9 @@ int global;
/* do the search early to avoid work on non-match */
if (research(rp, t->stptr, 0, t->stlen, 1) == -1 ||
- (RESTART(rp, t->stptr) > t->stlen) && (matches = 1)) {
+ RESTART(rp, t->stptr) > t->stlen) {
free_temp(t);
- return tmp_number((AWKNUM) matches);
+ return tmp_number((AWKNUM) 0.0);
}
if (tmp->type == Node_val)
@@ -1001,13 +1068,15 @@ int global;
repl = s->stptr;
replend = repl + s->stlen;
repllen = replend - repl;
- emalloc(buf, char *, buflen, "do_sub");
+ emalloc(buf, char *, buflen + 2, "do_sub");
+ buf[buflen] = '\0';
+ buf[buflen + 1] = '\0';
ampersands = 0;
for (scan = repl; scan < replend; scan++) {
if (*scan == '&') {
repllen--;
ampersands++;
- } else if (*scan == '\\' && (*(scan+1) == '&' || *(scan+1) == '\\')) {
+ } else if (*scan == '\\' && *(scan+1) == '&') {
repllen--;
scan++;
}
@@ -1021,12 +1090,12 @@ int global;
/*
* create the result, copying in parts of the original
- * string
+ * string
*/
len = matchstart - text + repllen
+ ampersands * (matchend - matchstart);
sofar = bp - buf;
- while (buflen - sofar - len - 1 < 0) {
+ while ((long)(buflen - sofar - len - 1) < 0) {
buflen *= 2;
erealloc(buf, char *, buflen, "do_sub");
bp = buf + sofar;
@@ -1037,18 +1106,20 @@ int global;
if (*scan == '&')
for (cp = matchstart; cp < matchend; cp++)
*bp++ = *cp;
- else if (*scan == '\\' && (*(scan+1) == '&' || *(scan+1) == '\\')) {
+ else if (*scan == '\\' && *(scan+1) == '&') {
scan++;
*bp++ = *scan;
} else
*bp++ = *scan;
+
+ /* catch the case of gsub(//, "blah", whatever), i.e. empty regexp */
if (global && matchstart == matchend && matchend < text + textlen) {
*bp++ = *matchend;
matchend++;
}
textlen = text + textlen - matchend;
text = matchend;
- if (!global || textlen <= 0 ||
+ if (!global || (long)textlen <= 0 ||
research(rp, t->stptr, text-t->stptr, textlen, 1) == -1)
break;
}
@@ -1060,6 +1131,7 @@ int global;
}
for (scan = matchend; scan < text + textlen; scan++)
*bp++ = *scan;
+ *bp = '\0';
textlen = bp - buf;
free(t->stptr);
t->stptr = buf;
@@ -1093,41 +1165,75 @@ NODE *tree;
}
#ifdef GFMT_WORKAROUND
- /*
- * printf's %g format [can't rely on gcvt()]
- * caveat: don't use as argument to *printf()!
- */
-char *
-gfmt(g, prec, buf)
-double g; /* value to format */
-int prec; /* indicates desired significant digits, not decimal places */
+/*
+ * printf's %g format [can't rely on gcvt()]
+ * caveat: don't use as argument to *printf()!
+ * 'format' string HAS to be of "<flags>*.*g" kind, or we bomb!
+ */
+static void
+sgfmt(buf, format, alt, fwidth, prec, g)
char *buf; /* return buffer; assumed big enough to hold result */
+const char *format;
+int alt; /* use alternate form flag */
+int fwidth; /* field width in a format */
+int prec; /* indicates desired significant digits, not decimal places */
+double g; /* value to format */
{
- if (g == 0.0) {
- (void) strcpy(buf, "0"); /* easy special case */
- } else {
- register char *d, *e, *p;
-
- /* start with 'e' format (it'll provide nice exponent) */
- if (prec < 1) prec = 1; /* at least 1 significant digit */
- (void) sprintf(buf, "%.*e", prec - 1, g);
- if ((e = strchr(buf, 'e')) != 0) { /* find exponent */
- int exp = atoi(e+1); /* fetch exponent */
- if (exp >= -4 && exp < prec) { /* per K&R2, B1.2 */
- /* switch to 'f' format and re-do */
- prec -= (exp + 1); /* decimal precision */
- (void) sprintf(buf, "%.*f", prec, g);
- e = buf + strlen(buf);
- }
- if ((d = strchr(buf, '.')) != 0) {
- /* remove trailing zeroes and decimal point */
- for (p = e; p > d && *--p == '0'; ) continue;
- if (*p == '.') --p;
- if (++p < e) /* copy exponent and NUL */
- while ((*p++ = *e++) != '\0') continue;
- }
+ char dform[40];
+ register char *gpos;
+ register char *d, *e, *p;
+ int again = 0;
+
+ strncpy(dform, format, sizeof dform - 1);
+ dform[sizeof dform - 1] = '\0';
+ gpos = strrchr(dform, '.');
+
+ if (g == 0.0 && alt == 0) { /* easy special case */
+ *gpos++ = 'd';
+ *gpos = '\0';
+ (void) sprintf(buf, dform, fwidth, 0);
+ return;
+ }
+ gpos += 2; /* advance to location of 'g' in the format */
+
+ if (prec <= 0) /* negative precision is ignored */
+ prec = (prec < 0 ? DEFAULT_G_PRECISION : 1);
+
+ if (*gpos == 'G')
+ again = 1;
+ /* start with 'e' format (it'll provide nice exponent) */
+ *gpos = 'e';
+ prec -= 1;
+ (void) sprintf(buf, dform, fwidth, prec, g);
+ if ((e = strrchr(buf, 'e')) != NULL) { /* find exponent */
+ int exp = atoi(e+1); /* fetch exponent */
+ if (exp >= -4 && exp <= prec) { /* per K&R2, B1.2 */
+ /* switch to 'f' format and re-do */
+ *gpos = 'f';
+ prec -= exp; /* decimal precision */
+ (void) sprintf(buf, dform, fwidth, prec, g);
+ e = buf + strlen(buf);
+ while (*--e == ' ')
+ continue;
+ e += 1;
+ }
+ else if (again != 0)
+ *gpos = 'E';
+
+ /* if 'alt' in force, then trailing zeros are not removed */
+ if (alt == 0 && (d = strrchr(buf, '.')) != NULL) {
+ /* throw away an excess of precision */
+ for (p = e; p > d && *--p == '0'; )
+ prec -= 1;
+ if (d == p)
+ prec -= 1;
+ if (prec < 0)
+ prec = 0;
+ /* and do that once again */
+ again = 1;
}
+ if (again != 0)
+ (void) sprintf(buf, dform, fwidth, prec, g);
}
- return buf;
}
#endif /* GFMT_WORKAROUND */
diff --git a/gnu/usr.bin/awk/config.h b/gnu/usr.bin/awk/config.h
index 8c20953..601f483 100644
--- a/gnu/usr.bin/awk/config.h
+++ b/gnu/usr.bin/awk/config.h
@@ -4,22 +4,22 @@
* For generic 4.4 alpha
*/
-/*
- * Copyright (C) 1991, 1992 the Free Software Foundation, Inc.
- *
+/*
+ * Copyright (C) 1991, 1992, 1993 the Free Software Foundation, Inc.
+ *
* This file is part of GAWK, the GNU implementation of the
* AWK Progamming Language.
- *
+ *
* GAWK is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
- *
+ *
* GAWK is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
- *
+ *
* You should have received a copy of the GNU General Public License
* along with GAWK; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
@@ -92,6 +92,13 @@
*/
#define HAVE_UNDERSCORE_SETJMP 1
+/*
+ * LIMITS_H_MISSING
+ *
+ * You don't have a <limits.h> include file.
+ */
+/* #define LIMITS_H_MISSING 1 */
+
/***********************************************/
/* Missing library subroutines or system calls */
/***********************************************/
@@ -147,7 +154,7 @@
* Your system does not have the strtod() routine for converting
* strings to double precision floating point values.
*/
-/* #define STRTOD_MISSING 1 */
+/* #define STRTOD_MISSING 1 */
/*
* STRFTIME_MISSING
@@ -177,6 +184,15 @@
/* #define TZNAME_MISSING 1 */
/*
+ * TM_ZONE_MISSING
+ *
+ * Your "struct tm" is missing the tm_zone field.
+ * If this is the case *and* strftime() is missing *and* tzname is missing,
+ * define this.
+ */
+/* #define TM_ZONE_MISSING 1 */
+
+/*
* STDC_HEADERS
*
* If your system does have ANSI compliant header files that
@@ -269,4 +285,22 @@
*/
#define SRANDOM_PROTO 1
+/*
+ * getpgrp() in sysvr4 and POSIX takes no argument
+ */
+/* #define GETPGRP_NOARG 0 */
+
+/*
+ * define const to nothing if not __STDC__
+ */
+#ifndef __STDC__
+#define const
+#endif
+
+/* If svr4 and not gcc */
+/* #define SVR4 0 */
+#ifdef SVR4
+#define __svr4__ 1
+#endif
+
/* anything that follows is for system-specific short-term kludges */
diff --git a/gnu/usr.bin/awk/dfa.c b/gnu/usr.bin/awk/dfa.c
index 5293c75..397027f 100644
--- a/gnu/usr.bin/awk/dfa.c
+++ b/gnu/usr.bin/awk/dfa.c
@@ -1,182 +1,132 @@
-/* dfa.c - determinisitic extended regexp routines for GNU
+/* dfa.c - deterministic extended regexp routines for GNU
Copyright (C) 1988 Free Software Foundation, Inc.
- Written June, 1988 by Mike Haertel
- Modified July, 1988 by Arthur David Olson
- to assist BMG speedups
-
- NO WARRANTY
-
- BECAUSE THIS PROGRAM IS LICENSED FREE OF CHARGE, WE PROVIDE ABSOLUTELY
-NO WARRANTY, TO THE EXTENT PERMITTED BY APPLICABLE STATE LAW. EXCEPT
-WHEN OTHERWISE STATED IN WRITING, FREE SOFTWARE FOUNDATION, INC,
-RICHARD M. STALLMAN AND/OR OTHER PARTIES PROVIDE THIS PROGRAM "AS IS"
-WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
-BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
-FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY
-AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE
-DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR
-CORRECTION.
-
- IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW WILL RICHARD M.
-STALLMAN, THE FREE SOFTWARE FOUNDATION, INC., AND/OR ANY OTHER PARTY
-WHO MAY MODIFY AND REDISTRIBUTE THIS PROGRAM AS PERMITTED BELOW, BE
-LIABLE TO YOU FOR DAMAGES, INCLUDING ANY LOST PROFITS, LOST MONIES, OR
-OTHER SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
-USE OR INABILITY TO USE (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR
-DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY THIRD PARTIES OR
-A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS) THIS
-PROGRAM, EVEN IF YOU HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH
-DAMAGES, OR FOR ANY CLAIM BY ANY OTHER PARTY.
-
- GENERAL PUBLIC LICENSE TO COPY
-
- 1. You may copy and distribute verbatim copies of this source file
-as you receive it, in any medium, provided that you conspicuously and
-appropriately publish on each copy a valid copyright notice "Copyright
- (C) 1988 Free Software Foundation, Inc."; and include following the
-copyright notice a verbatim copy of the above disclaimer of warranty
-and of this License. You may charge a distribution fee for the
-physical act of transferring a copy.
-
- 2. You may modify your copy or copies of this source file or
-any portion of it, and copy and distribute such modifications under
-the terms of Paragraph 1 above, provided that you also do the following:
-
- a) cause the modified files to carry prominent notices stating
- that you changed the files and the date of any change; and
-
- b) cause the whole of any work that you distribute or publish,
- that in whole or in part contains or is a derivative of this
- program or any part thereof, to be licensed at no charge to all
- third parties on terms identical to those contained in this
- License Agreement (except that you may choose to grant more extensive
- warranty protection to some or all third parties, at your option).
-
- c) You may charge a distribution fee for the physical act of
- transferring a copy, and you may at your option offer warranty
- protection in exchange for a fee.
-
-Mere aggregation of another unrelated program with this program (or its
-derivative) on a volume of a storage or distribution medium does not bring
-the other program under the scope of these terms.
-
- 3. You may copy and distribute this program or any portion of it in
-compiled, executable or object code form under the terms of Paragraphs
-1 and 2 above provided that you do the following:
-
- a) accompany it with the complete corresponding machine-readable
- source code, which must be distributed under the terms of
- Paragraphs 1 and 2 above; or,
-
- b) accompany it with a written offer, valid for at least three
- years, to give any third party free (except for a nominal
- shipping charge) a complete machine-readable copy of the
- corresponding source code, to be distributed under the terms of
- Paragraphs 1 and 2 above; or,
-
- c) accompany it with the information you received as to where the
- corresponding source code may be obtained. (This alternative is
- allowed only for noncommercial distribution and only if you
- received the program in object code or executable form alone.)
-
-For an executable file, complete source code means all the source code for
-all modules it contains; but, as a special exception, it need not include
-source code for modules which are standard libraries that accompany the
-operating system on which the executable file runs.
-
- 4. You may not copy, sublicense, distribute or transfer this program
-except as expressly provided under this License Agreement. Any attempt
-otherwise to copy, sublicense, distribute or transfer this program is void and
-your rights to use the program under this License agreement shall be
-automatically terminated. However, parties who have received computer
-software programs from you with this License Agreement will not have
-their licenses terminated so long as such parties remain in full compliance.
-
- 5. If you wish to incorporate parts of this program into other free
-programs whose distribution conditions are different, write to the Free
-Software Foundation at 675 Mass Ave, Cambridge, MA 02139. We have not yet
-worked out a simple rule that can be stated here, but we will often permit
-this. We will be guided by the two goals of preserving the free status of
-all derivatives our free software and of promoting the sharing and reuse of
-software.
-
-
-In other words, you are welcome to use, share and improve this program.
-You are forbidden to forbid anyone else to use, share and improve
-what you give them. Help stamp out software-hoarding! */
-
-#include "awk.h"
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* Written June, 1988 by Mike Haertel
+ Modified July, 1988 by Arthur David Olson to assist BMG speedups */
+
#include <assert.h>
+#include <ctype.h>
+#include <stdio.h>
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef STDC_HEADERS
+#include <stdlib.h>
+#else
+#include <sys/types.h>
+extern char *calloc(), *malloc(), *realloc();
+extern void free();
+#endif
-#ifdef setbit /* surprise - setbit and clrbit are macros on NeXT */
-#undef setbit
+#if defined(HAVE_STRING_H) || defined(STDC_HEADERS)
+#include <string.h>
+#undef index
+#define index strchr
+#else
+#include <strings.h>
#endif
-#ifdef clrbit
-#undef clrbit
+
+#ifndef DEBUG /* use the same approach as regex.c */
+#undef assert
+#define assert(e)
+#endif /* DEBUG */
+
+#ifndef isgraph
+#define isgraph(C) (isprint(C) && !isspace(C))
#endif
+#define ISALPHA(C) isalpha(C)
+#define ISUPPER(C) isupper(C)
+#define ISLOWER(C) islower(C)
+#define ISDIGIT(C) isdigit(C)
+#define ISXDIGIT(C) isxdigit(C)
+#define ISSPACE(C) isspace(C)
+#define ISPUNCT(C) ispunct(C)
+#define ISALNUM(C) isalnum(C)
+#define ISPRINT(C) isprint(C)
+#define ISGRAPH(C) isgraph(C)
+#define ISCNTRL(C) iscntrl(C)
+
+#include "gnuregex.h"
+#include "dfa.h"
+
#ifdef __STDC__
typedef void *ptr_t;
#else
typedef char *ptr_t;
+#ifndef const
+#define const
+#endif
#endif
-typedef struct {
- char ** in;
- char * left;
- char * right;
- char * is;
-} must;
+static void dfamust _RE_ARGS((struct dfa *dfa));
-static ptr_t xcalloc P((int n, size_t s));
-static ptr_t xmalloc P((size_t n));
-static ptr_t xrealloc P((ptr_t p, size_t n));
-static int tstbit P((int b, _charset c));
-static void setbit P((int b, _charset c));
-static void clrbit P((int b, _charset c));
-static void copyset P((const _charset src, _charset dst));
-static void zeroset P((_charset s));
-static void notset P((_charset s));
-static int equal P((const _charset s1, const _charset s2));
-static int charset_index P((const _charset s));
-static _token lex P((void));
-static void addtok P((_token t));
-static void atom P((void));
-static void closure P((void));
-static void branch P((void));
-static void regexp P((void));
-static void copy P((const _position_set *src, _position_set *dst));
-static void insert P((_position p, _position_set *s));
-static void merge P((_position_set *s1, _position_set *s2, _position_set *m));
-static void delete P((_position p, _position_set *s));
-static int state_index P((struct regexp *r, _position_set *s,
+static ptr_t xcalloc _RE_ARGS((size_t n, size_t s));
+static ptr_t xmalloc _RE_ARGS((size_t n));
+static ptr_t xrealloc _RE_ARGS((ptr_t p, size_t n));
+#ifdef DEBUG
+static void prtok _RE_ARGS((token t));
+#endif
+static int tstbit _RE_ARGS((int b, charclass c));
+static void setbit _RE_ARGS((int b, charclass c));
+static void clrbit _RE_ARGS((int b, charclass c));
+static void copyset _RE_ARGS((charclass src, charclass dst));
+static void zeroset _RE_ARGS((charclass s));
+static void notset _RE_ARGS((charclass s));
+static int equal _RE_ARGS((charclass s1, charclass s2));
+static int charclass_index _RE_ARGS((charclass s));
+static int looking_at _RE_ARGS((const char *s));
+static token lex _RE_ARGS((void));
+static void addtok _RE_ARGS((token t));
+static void atom _RE_ARGS((void));
+static int nsubtoks _RE_ARGS((int tindex));
+static void copytoks _RE_ARGS((int tindex, int ntokens));
+static void closure _RE_ARGS((void));
+static void branch _RE_ARGS((void));
+static void regexp _RE_ARGS((int toplevel));
+static void copy _RE_ARGS((position_set *src, position_set *dst));
+static void insert _RE_ARGS((position p, position_set *s));
+static void merge _RE_ARGS((position_set *s1, position_set *s2, position_set *m));
+static void delete _RE_ARGS((position p, position_set *s));
+static int state_index _RE_ARGS((struct dfa *d, position_set *s,
int newline, int letter));
-static void epsclosure P((_position_set *s, struct regexp *r));
-static void build_state P((int s, struct regexp *r));
-static void build_state_zero P((struct regexp *r));
-static char *icatalloc P((char *old, const char *new));
-static char *icpyalloc P((const char *string));
-static char *istrstr P((char *lookin, char *lookfor));
-static void ifree P((char *cp));
-static void freelist P((char **cpp));
-static char **enlist P((char **cpp, char *new, size_t len));
-static char **comsubs P((char *left, char *right));
-static char **addlists P((char **old, char **new));
-static char **inboth P((char **left, char **right));
-static void resetmust P((must *mp));
-static void regmust P((struct regexp *r));
-
-#undef P
+static void build_state _RE_ARGS((int s, struct dfa *d));
+static void build_state_zero _RE_ARGS((struct dfa *d));
+static char *icatalloc _RE_ARGS((char *old, char *new));
+static char *icpyalloc _RE_ARGS((char *string));
+static char *istrstr _RE_ARGS((char *lookin, char *lookfor));
+static void ifree _RE_ARGS((char *cp));
+static void freelist _RE_ARGS((char **cpp));
+static char **enlist _RE_ARGS((char **cpp, char *new, size_t len));
+static char **comsubs _RE_ARGS((char *left, char *right));
+static char **addlists _RE_ARGS((char **old, char **new));
+static char **inboth _RE_ARGS((char **left, char **right));
static ptr_t
xcalloc(n, s)
- int n;
+ size_t n;
size_t s;
{
ptr_t r = calloc(n, s);
- if (NULL == r)
- reg_error("Memory exhausted"); /* reg_error does not return */
+ if (!r)
+ dfaerror("Memory exhausted");
return r;
}
@@ -187,8 +137,8 @@ xmalloc(n)
ptr_t r = malloc(n);
assert(n != 0);
- if (NULL == r)
- reg_error("Memory exhausted");
+ if (!r)
+ dfaerror("Memory exhausted");
return r;
}
@@ -200,13 +150,12 @@ xrealloc(p, n)
ptr_t r = realloc(p, n);
assert(n != 0);
- if (NULL == r)
- reg_error("Memory exhausted");
+ if (!r)
+ dfaerror("Memory exhausted");
return r;
}
-#define CALLOC(p, t, n) ((p) = (t *) xcalloc((n), sizeof (t)))
-#undef MALLOC
+#define CALLOC(p, t, n) ((p) = (t *) xcalloc((size_t)(n), sizeof (t)))
#define MALLOC(p, t, n) ((p) = (t *) xmalloc((n) * sizeof (t)))
#define REALLOC(p, t, n) ((p) = (t *) xrealloc((ptr_t) (p), (n) * sizeof (t)))
@@ -218,13 +167,52 @@ xrealloc(p, n)
(nalloc) *= 2; \
REALLOC(p, t, nalloc); \
}
-
-/* Stuff pertaining to charsets. */
+
+#ifdef DEBUG
+
+static void
+prtok(t)
+ token t;
+{
+ char *s;
+
+ if (t < 0)
+ fprintf(stderr, "END");
+ else if (t < NOTCHAR)
+ fprintf(stderr, "%c", t);
+ else
+ {
+ switch (t)
+ {
+ case EMPTY: s = "EMPTY"; break;
+ case BACKREF: s = "BACKREF"; break;
+ case BEGLINE: s = "BEGLINE"; break;
+ case ENDLINE: s = "ENDLINE"; break;
+ case BEGWORD: s = "BEGWORD"; break;
+ case ENDWORD: s = "ENDWORD"; break;
+ case LIMWORD: s = "LIMWORD"; break;
+ case NOTLIMWORD: s = "NOTLIMWORD"; break;
+ case QMARK: s = "QMARK"; break;
+ case STAR: s = "STAR"; break;
+ case PLUS: s = "PLUS"; break;
+ case CAT: s = "CAT"; break;
+ case OR: s = "OR"; break;
+ case ORTOP: s = "ORTOP"; break;
+ case LPAREN: s = "LPAREN"; break;
+ case RPAREN: s = "RPAREN"; break;
+ default: s = "CSET"; break;
+ }
+ fprintf(stderr, "%s", s);
+ }
+}
+#endif /* DEBUG */
+
+/* Stuff pertaining to charclasses. */
static int
tstbit(b, c)
int b;
- _charset c;
+ charclass c;
{
return c[b / INTBITS] & 1 << b % INTBITS;
}
@@ -232,7 +220,7 @@ tstbit(b, c)
static void
setbit(b, c)
int b;
- _charset c;
+ charclass c;
{
c[b / INTBITS] |= 1 << b % INTBITS;
}
@@ -240,84 +228,84 @@ setbit(b, c)
static void
clrbit(b, c)
int b;
- _charset c;
+ charclass c;
{
c[b / INTBITS] &= ~(1 << b % INTBITS);
}
static void
copyset(src, dst)
- const _charset src;
- _charset dst;
+ charclass src;
+ charclass dst;
{
int i;
- for (i = 0; i < _CHARSET_INTS; ++i)
+ for (i = 0; i < CHARCLASS_INTS; ++i)
dst[i] = src[i];
}
static void
zeroset(s)
- _charset s;
+ charclass s;
{
int i;
- for (i = 0; i < _CHARSET_INTS; ++i)
+ for (i = 0; i < CHARCLASS_INTS; ++i)
s[i] = 0;
}
static void
notset(s)
- _charset s;
+ charclass s;
{
int i;
- for (i = 0; i < _CHARSET_INTS; ++i)
+ for (i = 0; i < CHARCLASS_INTS; ++i)
s[i] = ~s[i];
}
static int
equal(s1, s2)
- const _charset s1;
- const _charset s2;
+ charclass s1;
+ charclass s2;
{
int i;
- for (i = 0; i < _CHARSET_INTS; ++i)
+ for (i = 0; i < CHARCLASS_INTS; ++i)
if (s1[i] != s2[i])
return 0;
return 1;
}
-
-/* A pointer to the current regexp is kept here during parsing. */
-static struct regexp *reg;
-/* Find the index of charset s in reg->charsets, or allocate a new charset. */
+/* A pointer to the current dfa is kept here during parsing. */
+static struct dfa *dfa;
+
+/* Find the index of charclass s in dfa->charclasses, or allocate a new charclass. */
static int
-charset_index(s)
- const _charset s;
+charclass_index(s)
+ charclass s;
{
int i;
- for (i = 0; i < reg->cindex; ++i)
- if (equal(s, reg->charsets[i]))
+ for (i = 0; i < dfa->cindex; ++i)
+ if (equal(s, dfa->charclasses[i]))
return i;
- REALLOC_IF_NECESSARY(reg->charsets, _charset, reg->calloc, reg->cindex);
- ++reg->cindex;
- copyset(s, reg->charsets[i]);
+ REALLOC_IF_NECESSARY(dfa->charclasses, charclass, dfa->calloc, dfa->cindex);
+ ++dfa->cindex;
+ copyset(s, dfa->charclasses[i]);
return i;
}
/* Syntax bits controlling the behavior of the lexical analyzer. */
-static syntax_bits, syntax_bits_set;
+static reg_syntax_t syntax_bits, syntax_bits_set;
/* Flag for case-folding letters into sets. */
-static case_fold;
+static int case_fold;
/* Entry point to set syntax options. */
void
-regsyntax(bits, fold)
- long bits;
+dfasyntax(bits, fold)
+ reg_syntax_t bits;
int fold;
{
syntax_bits_set = 1;
@@ -325,63 +313,136 @@ regsyntax(bits, fold)
case_fold = fold;
}
-/* Lexical analyzer. */
-static const char *lexstart; /* Pointer to beginning of input string. */
-static const char *lexptr; /* Pointer to next input character. */
+/* Lexical analyzer. All the dross that deals with the obnoxious
+ GNU Regex syntax bits is located here. The poor, suffering
+ reader is referred to the GNU Regex documentation for the
+ meaning of the @#%!@#%^!@ syntax bits. */
+
+static char *lexstart; /* Pointer to beginning of input string. */
+static char *lexptr; /* Pointer to next input character. */
static lexleft; /* Number of characters remaining. */
-static caret_allowed; /* True if backward context allows ^
- (meaningful only if RE_CONTEXT_INDEP_OPS
- is turned off). */
-static closure_allowed; /* True if backward context allows closures
- (meaningful only if RE_CONTEXT_INDEP_OPS
- is turned off). */
+static token lasttok; /* Previous token returned; initially END. */
+static int laststart; /* True if we're separated from beginning or (, |
+ only by zero-width characters. */
+static int parens; /* Count of outstanding left parens. */
+static int minrep, maxrep; /* Repeat counts for {m,n}. */
/* Note that characters become unsigned here. */
#define FETCH(c, eoferr) \
{ \
if (! lexleft) \
- if (eoferr != NULL) \
- reg_error(eoferr); \
+ if (eoferr != 0) \
+ dfaerror(eoferr); \
else \
- return _END; \
+ return lasttok = END; \
(c) = (unsigned char) *lexptr++; \
--lexleft; \
}
-static _token
+#ifdef __STDC__
+#define FUNC(F, P) static int F(int c) { return P(c); }
+#else
+#define FUNC(F, P) static int F(c) int c; { return P(c); }
+#endif
+
+FUNC(is_alpha, ISALPHA)
+FUNC(is_upper, ISUPPER)
+FUNC(is_lower, ISLOWER)
+FUNC(is_digit, ISDIGIT)
+FUNC(is_xdigit, ISXDIGIT)
+FUNC(is_space, ISSPACE)
+FUNC(is_punct, ISPUNCT)
+FUNC(is_alnum, ISALNUM)
+FUNC(is_print, ISPRINT)
+FUNC(is_graph, ISGRAPH)
+FUNC(is_cntrl, ISCNTRL)
+
+/* The following list maps the names of the Posix named character classes
+ to predicate functions that determine whether a given character is in
+ the class. The leading [ has already been eaten by the lexical analyzer. */
+static struct {
+ const char *name;
+ int (*pred) _RE_ARGS((int));
+} prednames[] = {
+ { ":alpha:]", is_alpha },
+ { ":upper:]", is_upper },
+ { ":lower:]", is_lower },
+ { ":digit:]", is_digit },
+ { ":xdigit:]", is_xdigit },
+ { ":space:]", is_space },
+ { ":punct:]", is_punct },
+ { ":alnum:]", is_alnum },
+ { ":print:]", is_print },
+ { ":graph:]", is_graph },
+ { ":cntrl:]", is_cntrl },
+ { 0 }
+};
+
+static int
+looking_at(s)
+ const char *s;
+{
+ size_t len;
+
+ len = strlen(s);
+ if (lexleft < len)
+ return 0;
+ return strncmp(s, lexptr, len) == 0;
+}
+
+static token
lex()
{
- _token c, c2;
- int invert;
- _charset cset;
+ token c, c1, c2;
+ int backslash = 0, invert;
+ charclass ccl;
+ int i;
- FETCH(c, (char *) 0);
- switch (c)
+ /* Basic plan: We fetch a character. If it's a backslash,
+ we set the backslash flag and go through the loop again.
+ On the plus side, this avoids having a duplicate of the
+ main switch inside the backslash case. On the minus side,
+ it means that just about every case begins with
+ "if (backslash) ...". */
+ for (i = 0; i < 2; ++i)
{
- case '^':
- if (! (syntax_bits & RE_CONTEXT_INDEP_OPS)
- && (!caret_allowed ||
- ((syntax_bits & RE_TIGHT_VBAR) && lexptr - 1 != lexstart)))
- goto normal_char;
- caret_allowed = 0;
- return syntax_bits & RE_TIGHT_VBAR ? _ALLBEGLINE : _BEGLINE;
-
- case '$':
- if (syntax_bits & RE_CONTEXT_INDEP_OPS || !lexleft
- || (! (syntax_bits & RE_TIGHT_VBAR)
- && ((syntax_bits & RE_NO_BK_PARENS
- ? lexleft > 0 && *lexptr == ')'
- : lexleft > 1 && *lexptr == '\\' && lexptr[1] == ')')
- || (syntax_bits & RE_NO_BK_VBAR
- ? lexleft > 0 && *lexptr == '|'
- : lexleft > 1 && *lexptr == '\\' && lexptr[1] == '|'))))
- return syntax_bits & RE_TIGHT_VBAR ? _ALLENDLINE : _ENDLINE;
- goto normal_char;
-
- case '\\':
- FETCH(c, "Unfinished \\ quote");
+ FETCH(c, 0);
switch (c)
{
+ case '\\':
+ if (backslash)
+ goto normal_char;
+ if (lexleft == 0)
+ dfaerror("Unfinished \\ escape");
+ backslash = 1;
+ break;
+
+ case '^':
+ if (backslash)
+ goto normal_char;
+ if (syntax_bits & RE_CONTEXT_INDEP_ANCHORS
+ || lasttok == END
+ || lasttok == LPAREN
+ || lasttok == OR)
+ return lasttok = BEGLINE;
+ goto normal_char;
+
+ case '$':
+ if (backslash)
+ goto normal_char;
+ if (syntax_bits & RE_CONTEXT_INDEP_ANCHORS
+ || lexleft == 0
+ || (syntax_bits & RE_NO_BK_PARENS
+ ? lexleft > 0 && *lexptr == ')'
+ : lexleft > 1 && lexptr[0] == '\\' && lexptr[1] == ')')
+ || (syntax_bits & RE_NO_BK_VBAR
+ ? lexleft > 0 && *lexptr == '|'
+ : lexleft > 1 && lexptr[0] == '\\' && lexptr[1] == '|')
+ || ((syntax_bits & RE_NEWLINE_ALT)
+ && lexleft > 0 && *lexptr == '\n'))
+ return lasttok = ENDLINE;
+ goto normal_char;
+
case '1':
case '2':
case '3':
@@ -391,236 +452,315 @@ lex()
case '7':
case '8':
case '9':
- caret_allowed = 0;
- closure_allowed = 1;
- return _BACKREF;
+ if (backslash && !(syntax_bits & RE_NO_BK_REFS))
+ {
+ laststart = 0;
+ return lasttok = BACKREF;
+ }
+ goto normal_char;
case '<':
- caret_allowed = 0;
- return _BEGWORD;
+ if (syntax_bits & RE_NO_GNU_OPS)
+ goto normal_char;
+ if (backslash)
+ return lasttok = BEGWORD;
+ goto normal_char;
case '>':
- caret_allowed = 0;
- return _ENDWORD;
+ if (syntax_bits & RE_NO_GNU_OPS)
+ goto normal_char;
+ if (backslash)
+ return lasttok = ENDWORD;
+ goto normal_char;
case 'b':
- caret_allowed = 0;
- return _LIMWORD;
+ if (syntax_bits & RE_NO_GNU_OPS)
+ goto normal_char;
+ if (backslash)
+ return lasttok = LIMWORD;
+ goto normal_char;
case 'B':
- caret_allowed = 0;
- return _NOTLIMWORD;
-
- case 'w':
- case 'W':
- zeroset(cset);
- for (c2 = 0; c2 < _NOTCHAR; ++c2)
- if (ISALNUM(c2))
- setbit(c2, cset);
- if (c == 'W')
- notset(cset);
- caret_allowed = 0;
- closure_allowed = 1;
- return _SET + charset_index(cset);
+ if (syntax_bits & RE_NO_GNU_OPS)
+ goto normal_char;
+ if (backslash)
+ return lasttok = NOTLIMWORD;
+ goto normal_char;
case '?':
- if (syntax_bits & RE_BK_PLUS_QM)
- goto qmark;
- goto normal_char;
+ if (syntax_bits & RE_LIMITED_OPS)
+ goto normal_char;
+ if (backslash != ((syntax_bits & RE_BK_PLUS_QM) != 0))
+ goto normal_char;
+ if (!(syntax_bits & RE_CONTEXT_INDEP_OPS) && laststart)
+ goto normal_char;
+ return lasttok = QMARK;
+
+ case '*':
+ if (backslash)
+ goto normal_char;
+ if (!(syntax_bits & RE_CONTEXT_INDEP_OPS) && laststart)
+ goto normal_char;
+ return lasttok = STAR;
case '+':
- if (syntax_bits & RE_BK_PLUS_QM)
- goto plus;
- goto normal_char;
+ if (syntax_bits & RE_LIMITED_OPS)
+ goto normal_char;
+ if (backslash != ((syntax_bits & RE_BK_PLUS_QM) != 0))
+ goto normal_char;
+ if (!(syntax_bits & RE_CONTEXT_INDEP_OPS) && laststart)
+ goto normal_char;
+ return lasttok = PLUS;
+
+ case '{':
+ if (!(syntax_bits & RE_INTERVALS))
+ goto normal_char;
+ if (backslash != ((syntax_bits & RE_NO_BK_BRACES) == 0))
+ goto normal_char;
+ minrep = maxrep = 0;
+ /* Cases:
+ {M} - exact count
+ {M,} - minimum count, maximum is infinity
+ {,M} - 0 through M
+ {M,N} - M through N */
+ FETCH(c, "unfinished repeat count");
+ if (ISDIGIT(c))
+ {
+ minrep = c - '0';
+ for (;;)
+ {
+ FETCH(c, "unfinished repeat count");
+ if (!ISDIGIT(c))
+ break;
+ minrep = 10 * minrep + c - '0';
+ }
+ }
+ else if (c != ',')
+ dfaerror("malformed repeat count");
+ if (c == ',')
+ for (;;)
+ {
+ FETCH(c, "unfinished repeat count");
+ if (!ISDIGIT(c))
+ break;
+ maxrep = 10 * maxrep + c - '0';
+ }
+ else
+ maxrep = minrep;
+ if (!(syntax_bits & RE_NO_BK_BRACES))
+ {
+ if (c != '\\')
+ dfaerror("malformed repeat count");
+ FETCH(c, "unfinished repeat count");
+ }
+ if (c != '}')
+ dfaerror("malformed repeat count");
+ laststart = 0;
+ return lasttok = REPMN;
case '|':
- if (! (syntax_bits & RE_NO_BK_VBAR))
- goto or;
- goto normal_char;
+ if (syntax_bits & RE_LIMITED_OPS)
+ goto normal_char;
+ if (backslash != ((syntax_bits & RE_NO_BK_VBAR) == 0))
+ goto normal_char;
+ laststart = 1;
+ return lasttok = OR;
+
+ case '\n':
+ if (syntax_bits & RE_LIMITED_OPS
+ || backslash
+ || !(syntax_bits & RE_NEWLINE_ALT))
+ goto normal_char;
+ laststart = 1;
+ return lasttok = OR;
case '(':
- if (! (syntax_bits & RE_NO_BK_PARENS))
- goto lparen;
- goto normal_char;
+ if (backslash != ((syntax_bits & RE_NO_BK_PARENS) == 0))
+ goto normal_char;
+ ++parens;
+ laststart = 1;
+ return lasttok = LPAREN;
case ')':
- if (! (syntax_bits & RE_NO_BK_PARENS))
- goto rparen;
- goto normal_char;
-
- default:
- goto normal_char;
- }
+ if (backslash != ((syntax_bits & RE_NO_BK_PARENS) == 0))
+ goto normal_char;
+ if (parens == 0 && syntax_bits & RE_UNMATCHED_RIGHT_PAREN_ORD)
+ goto normal_char;
+ --parens;
+ laststart = 0;
+ return lasttok = RPAREN;
+
+ case '.':
+ if (backslash)
+ goto normal_char;
+ zeroset(ccl);
+ notset(ccl);
+ if (!(syntax_bits & RE_DOT_NEWLINE))
+ clrbit('\n', ccl);
+ if (syntax_bits & RE_DOT_NOT_NULL)
+ clrbit('\0', ccl);
+ laststart = 0;
+ return lasttok = CSET + charclass_index(ccl);
- case '?':
- if (syntax_bits & RE_BK_PLUS_QM)
- goto normal_char;
- qmark:
- if (! (syntax_bits & RE_CONTEXT_INDEP_OPS) && !closure_allowed)
- goto normal_char;
- return _QMARK;
-
- case '*':
- if (! (syntax_bits & RE_CONTEXT_INDEP_OPS) && !closure_allowed)
- goto normal_char;
- return _STAR;
-
- case '+':
- if (syntax_bits & RE_BK_PLUS_QM)
- goto normal_char;
- plus:
- if (! (syntax_bits & RE_CONTEXT_INDEP_OPS) && !closure_allowed)
- goto normal_char;
- return _PLUS;
-
- case '|':
- if (! (syntax_bits & RE_NO_BK_VBAR))
- goto normal_char;
- or:
- caret_allowed = 1;
- closure_allowed = 0;
- return _OR;
-
- case '\n':
- if (! (syntax_bits & RE_NEWLINE_OR))
- goto normal_char;
- goto or;
-
- case '(':
- if (! (syntax_bits & RE_NO_BK_PARENS))
- goto normal_char;
- lparen:
- caret_allowed = 1;
- closure_allowed = 0;
- return _LPAREN;
-
- case ')':
- if (! (syntax_bits & RE_NO_BK_PARENS))
- goto normal_char;
- rparen:
- caret_allowed = 0;
- closure_allowed = 1;
- return _RPAREN;
-
- case '.':
- zeroset(cset);
- notset(cset);
- clrbit('\n', cset);
- caret_allowed = 0;
- closure_allowed = 1;
- return _SET + charset_index(cset);
-
- case '[':
- zeroset(cset);
- FETCH(c, "Unbalanced [");
- if (c == '^')
- {
+ case 'w':
+ case 'W':
+ if (!backslash || (syntax_bits & RE_NO_GNU_OPS))
+ goto normal_char;
+ zeroset(ccl);
+ for (c2 = 0; c2 < NOTCHAR; ++c2)
+ if (ISALNUM(c2))
+ setbit(c2, ccl);
+ if (c == 'W')
+ notset(ccl);
+ laststart = 0;
+ return lasttok = CSET + charclass_index(ccl);
+
+ case '[':
+ if (backslash)
+ goto normal_char;
+ zeroset(ccl);
FETCH(c, "Unbalanced [");
- invert = 1;
- }
- else
- invert = 0;
- do
- {
- FETCH(c2, "Unbalanced [");
- if ((syntax_bits & RE_AWK_CLASS_HACK) && c == '\\')
+ if (c == '^')
{
- c = c2;
- FETCH(c2, "Unbalanced [");
+ FETCH(c, "Unbalanced [");
+ invert = 1;
}
- if (c2 == '-')
+ else
+ invert = 0;
+ do
{
- FETCH(c2, "Unbalanced [");
- if (c2 == ']' && (syntax_bits & RE_AWK_CLASS_HACK))
+ /* Nobody ever said this had to be fast. :-)
+ Note that if we're looking at some other [:...:]
+ construct, we just treat it as a bunch of ordinary
+ characters. We can do this because we assume
+ regex has checked for syntax errors before
+ dfa is ever called. */
+ if (c == '[' && (syntax_bits & RE_CHAR_CLASSES))
+ for (c1 = 0; prednames[c1].name; ++c1)
+ if (looking_at(prednames[c1].name))
+ {
+ for (c2 = 0; c2 < NOTCHAR; ++c2)
+ if ((*prednames[c1].pred)(c2))
+ setbit(c2, ccl);
+ lexptr += strlen(prednames[c1].name);
+ lexleft -= strlen(prednames[c1].name);
+ FETCH(c1, "Unbalanced [");
+ goto skip;
+ }
+ if (c == '\\' && (syntax_bits & RE_BACKSLASH_ESCAPE_IN_LISTS))
+ FETCH(c, "Unbalanced [");
+ FETCH(c1, "Unbalanced [");
+ if (c1 == '-')
{
- setbit(c, cset);
- setbit('-', cset);
- break;
- }
+ FETCH(c2, "Unbalanced [");
+ if (c2 == ']')
+ {
+ /* In the case [x-], the - is an ordinary hyphen,
+ which is left in c1, the lookahead character. */
+ --lexptr;
+ ++lexleft;
+ c2 = c;
+ }
+ else
+ {
+ if (c2 == '\\'
+ && (syntax_bits & RE_BACKSLASH_ESCAPE_IN_LISTS))
+ FETCH(c2, "Unbalanced [");
+ FETCH(c1, "Unbalanced [");
+ }
+ }
+ else
+ c2 = c;
while (c <= c2)
- setbit(c++, cset);
- FETCH(c, "Unbalanced [");
+ {
+ setbit(c, ccl);
+ if (case_fold)
+ if (ISUPPER(c))
+ setbit(tolower(c), ccl);
+ else if (ISLOWER(c))
+ setbit(toupper(c), ccl);
+ ++c;
+ }
+ skip:
+ ;
}
- else
+ while ((c = c1) != ']');
+ if (invert)
{
- setbit(c, cset);
- c = c2;
+ notset(ccl);
+ if (syntax_bits & RE_HAT_LISTS_NOT_NEWLINE)
+ clrbit('\n', ccl);
}
- }
- while (c != ']');
- if (invert)
- notset(cset);
- caret_allowed = 0;
- closure_allowed = 1;
- return _SET + charset_index(cset);
+ laststart = 0;
+ return lasttok = CSET + charclass_index(ccl);
- default:
- normal_char:
- caret_allowed = 0;
- closure_allowed = 1;
- if (case_fold && ISALPHA(c))
- {
- zeroset(cset);
- if (isupper(c))
- c = tolower(c);
- setbit(c, cset);
- setbit(toupper(c), cset);
- return _SET + charset_index(cset);
+ default:
+ normal_char:
+ laststart = 0;
+ if (case_fold && ISALPHA(c))
+ {
+ zeroset(ccl);
+ setbit(c, ccl);
+ if (isupper(c))
+ setbit(tolower(c), ccl);
+ else
+ setbit(toupper(c), ccl);
+ return lasttok = CSET + charclass_index(ccl);
+ }
+ return c;
}
- return c;
}
+
+ /* The above loop should consume at most a backslash
+ and some other character. */
+ abort();
}
-
+
/* Recursive descent parser for regular expressions. */
-static _token tok; /* Lookahead token. */
+static token tok; /* Lookahead token. */
static depth; /* Current depth of a hypothetical stack
holding deferred productions. This is
used to determine the depth that will be
required of the real stack later on in
- reganalyze(). */
+ dfaanalyze(). */
/* Add the given token to the parse tree, maintaining the depth count and
updating the maximum depth if necessary. */
static void
addtok(t)
- _token t;
+ token t;
{
- REALLOC_IF_NECESSARY(reg->tokens, _token, reg->talloc, reg->tindex);
- reg->tokens[reg->tindex++] = t;
+ REALLOC_IF_NECESSARY(dfa->tokens, token, dfa->talloc, dfa->tindex);
+ dfa->tokens[dfa->tindex++] = t;
switch (t)
{
- case _QMARK:
- case _STAR:
- case _PLUS:
+ case QMARK:
+ case STAR:
+ case PLUS:
break;
- case _CAT:
- case _OR:
+ case CAT:
+ case OR:
+ case ORTOP:
--depth;
break;
default:
- ++reg->nleaves;
- case _EMPTY:
+ ++dfa->nleaves;
+ case EMPTY:
++depth;
break;
}
- if (depth > reg->depth)
- reg->depth = depth;
+ if (depth > dfa->depth)
+ dfa->depth = depth;
}
/* The grammar understood by the parser is as follows.
- start:
- regexp
- _ALLBEGLINE regexp
- regexp _ALLENDLINE
- _ALLBEGLINE regexp _ALLENDLINE
-
regexp:
- regexp _OR branch
+ regexp OR branch
branch
branch:
@@ -628,144 +768,187 @@ addtok(t)
closure
closure:
- closure _QMARK
- closure _STAR
- closure _PLUS
+ closure QMARK
+ closure STAR
+ closure PLUS
atom
atom:
<normal character>
- _SET
- _BACKREF
- _BEGLINE
- _ENDLINE
- _BEGWORD
- _ENDWORD
- _LIMWORD
- _NOTLIMWORD
+ CSET
+ BACKREF
+ BEGLINE
+ ENDLINE
+ BEGWORD
+ ENDWORD
+ LIMWORD
+ NOTLIMWORD
<empty>
The parser builds a parse tree in postfix form in an array of tokens. */
-#ifdef __STDC__
-static void regexp(void);
-#else
-static void regexp();
-#endif
-
static void
atom()
{
- if (tok >= 0 && (tok < _NOTCHAR || tok >= _SET || tok == _BACKREF
- || tok == _BEGLINE || tok == _ENDLINE || tok == _BEGWORD
- || tok == _ENDWORD || tok == _LIMWORD || tok == _NOTLIMWORD))
+ if ((tok >= 0 && tok < NOTCHAR) || tok >= CSET || tok == BACKREF
+ || tok == BEGLINE || tok == ENDLINE || tok == BEGWORD
+ || tok == ENDWORD || tok == LIMWORD || tok == NOTLIMWORD)
{
addtok(tok);
tok = lex();
}
- else if (tok == _LPAREN)
+ else if (tok == LPAREN)
{
tok = lex();
- regexp();
- if (tok != _RPAREN)
- reg_error("Unbalanced (");
+ regexp(0);
+ if (tok != RPAREN)
+ dfaerror("Unbalanced (");
tok = lex();
}
else
- addtok(_EMPTY);
+ addtok(EMPTY);
+}
+
+/* Return the number of tokens in the given subexpression. */
+static int
+nsubtoks(tindex)
+int tindex;
+{
+ int ntoks1;
+
+ switch (dfa->tokens[tindex - 1])
+ {
+ default:
+ return 1;
+ case QMARK:
+ case STAR:
+ case PLUS:
+ return 1 + nsubtoks(tindex - 1);
+ case CAT:
+ case OR:
+ case ORTOP:
+ ntoks1 = nsubtoks(tindex - 1);
+ return 1 + ntoks1 + nsubtoks(tindex - 1 - ntoks1);
+ }
+}
+
+/* Copy the given subexpression to the top of the tree. */
+static void
+copytoks(tindex, ntokens)
+ int tindex, ntokens;
+{
+ int i;
+
+ for (i = 0; i < ntokens; ++i)
+ addtok(dfa->tokens[tindex + i]);
}
static void
closure()
{
+ int tindex, ntokens, i;
+
atom();
- while (tok == _QMARK || tok == _STAR || tok == _PLUS)
- {
- addtok(tok);
- tok = lex();
- }
+ while (tok == QMARK || tok == STAR || tok == PLUS || tok == REPMN)
+ if (tok == REPMN)
+ {
+ ntokens = nsubtoks(dfa->tindex);
+ tindex = dfa->tindex - ntokens;
+ if (maxrep == 0)
+ addtok(PLUS);
+ if (minrep == 0)
+ addtok(QMARK);
+ for (i = 1; i < minrep; ++i)
+ {
+ copytoks(tindex, ntokens);
+ addtok(CAT);
+ }
+ for (; i < maxrep; ++i)
+ {
+ copytoks(tindex, ntokens);
+ addtok(QMARK);
+ addtok(CAT);
+ }
+ tok = lex();
+ }
+ else
+ {
+ addtok(tok);
+ tok = lex();
+ }
}
static void
branch()
{
closure();
- while (tok != _RPAREN && tok != _OR && tok != _ALLENDLINE && tok >= 0)
+ while (tok != RPAREN && tok != OR && tok >= 0)
{
closure();
- addtok(_CAT);
+ addtok(CAT);
}
}
static void
-regexp()
+regexp(toplevel)
+ int toplevel;
{
branch();
- while (tok == _OR)
+ while (tok == OR)
{
tok = lex();
branch();
- addtok(_OR);
+ if (toplevel)
+ addtok(ORTOP);
+ else
+ addtok(OR);
}
}
/* Main entry point for the parser. S is a string to be parsed, len is the
- length of the string, so s can include NUL characters. R is a pointer to
- the struct regexp to parse into. */
+ length of the string, so s can include NUL characters. D is a pointer to
+ the struct dfa to parse into. */
void
-regparse(s, len, r)
- const char *s;
+dfaparse(s, len, d)
+ char *s;
size_t len;
- struct regexp *r;
+ struct dfa *d;
+
{
- reg = r;
+ dfa = d;
lexstart = lexptr = s;
lexleft = len;
- caret_allowed = 1;
- closure_allowed = 0;
+ lasttok = END;
+ laststart = 1;
+ parens = 0;
if (! syntax_bits_set)
- reg_error("No syntax specified");
+ dfaerror("No syntax specified");
tok = lex();
- depth = r->depth;
+ depth = d->depth;
- if (tok == _ALLBEGLINE)
- {
- addtok(_BEGLINE);
- tok = lex();
- regexp();
- addtok(_CAT);
- }
- else
- regexp();
-
- if (tok == _ALLENDLINE)
- {
- addtok(_ENDLINE);
- addtok(_CAT);
- tok = lex();
- }
+ regexp(1);
- if (tok != _END)
- reg_error("Unbalanced )");
+ if (tok != END)
+ dfaerror("Unbalanced )");
- addtok(_END - r->nregexps);
- addtok(_CAT);
+ addtok(END - d->nregexps);
+ addtok(CAT);
- if (r->nregexps)
- addtok(_OR);
+ if (d->nregexps)
+ addtok(ORTOP);
- ++r->nregexps;
+ ++d->nregexps;
}
-
+
/* Some primitives for operating on sets of positions. */
/* Copy one set to another; the destination must be large enough. */
static void
copy(src, dst)
- const _position_set *src;
- _position_set *dst;
+ position_set *src;
+ position_set *dst;
{
int i;
@@ -780,14 +963,14 @@ copy(src, dst)
S->elems must point to an array large enough to hold the resulting set. */
static void
insert(p, s)
- _position p;
- _position_set *s;
+ position p;
+ position_set *s;
{
int i;
- _position t1, t2;
+ position t1, t2;
for (i = 0; i < s->nelem && p.index < s->elems[i].index; ++i)
- ;
+ continue;
if (i < s->nelem && p.index == s->elems[i].index)
s->elems[i].constraint |= p.constraint;
else
@@ -807,9 +990,9 @@ insert(p, s)
the positions of both sets were inserted into an initially empty set. */
static void
merge(s1, s2, m)
- _position_set *s1;
- _position_set *s2;
- _position_set *m;
+ position_set *s1;
+ position_set *s2;
+ position_set *m;
{
int i = 0, j = 0;
@@ -833,8 +1016,8 @@ merge(s1, s2, m)
/* Delete a position from a set. */
static void
delete(p, s)
- _position p;
- _position_set *s;
+ position p;
+ position_set *s;
{
int i;
@@ -845,19 +1028,19 @@ delete(p, s)
for (--s->nelem; i < s->nelem; ++i)
s->elems[i] = s->elems[i + 1];
}
-
+
/* Find the index of the state corresponding to the given position set with
the given preceding context, or create a new state if there is no such
state. Newline and letter tell whether we got here on a newline or
letter, respectively. */
static int
-state_index(r, s, newline, letter)
- struct regexp *r;
- _position_set *s;
+state_index(d, s, newline, letter)
+ struct dfa *d;
+ position_set *s;
int newline;
int letter;
{
- int lhash = 0;
+ int hash = 0;
int constraint;
int i, j;
@@ -865,78 +1048,80 @@ state_index(r, s, newline, letter)
letter = letter ? 1 : 0;
for (i = 0; i < s->nelem; ++i)
- lhash ^= s->elems[i].index + s->elems[i].constraint;
+ hash ^= s->elems[i].index + s->elems[i].constraint;
/* Try to find a state that exactly matches the proposed one. */
- for (i = 0; i < r->sindex; ++i)
+ for (i = 0; i < d->sindex; ++i)
{
- if (lhash != r->states[i].hash || s->nelem != r->states[i].elems.nelem
- || newline != r->states[i].newline || letter != r->states[i].letter)
+ if (hash != d->states[i].hash || s->nelem != d->states[i].elems.nelem
+ || newline != d->states[i].newline || letter != d->states[i].letter)
continue;
for (j = 0; j < s->nelem; ++j)
if (s->elems[j].constraint
- != r->states[i].elems.elems[j].constraint
- || s->elems[j].index != r->states[i].elems.elems[j].index)
+ != d->states[i].elems.elems[j].constraint
+ || s->elems[j].index != d->states[i].elems.elems[j].index)
break;
if (j == s->nelem)
return i;
}
/* We'll have to create a new state. */
- REALLOC_IF_NECESSARY(r->states, _dfa_state, r->salloc, r->sindex);
- r->states[i].hash = lhash;
- MALLOC(r->states[i].elems.elems, _position, s->nelem);
- copy(s, &r->states[i].elems);
- r->states[i].newline = newline;
- r->states[i].letter = letter;
- r->states[i].backref = 0;
- r->states[i].constraint = 0;
- r->states[i].first_end = 0;
+ REALLOC_IF_NECESSARY(d->states, dfa_state, d->salloc, d->sindex);
+ d->states[i].hash = hash;
+ MALLOC(d->states[i].elems.elems, position, s->nelem);
+ copy(s, &d->states[i].elems);
+ d->states[i].newline = newline;
+ d->states[i].letter = letter;
+ d->states[i].backref = 0;
+ d->states[i].constraint = 0;
+ d->states[i].first_end = 0;
for (j = 0; j < s->nelem; ++j)
- if (r->tokens[s->elems[j].index] < 0)
+ if (d->tokens[s->elems[j].index] < 0)
{
constraint = s->elems[j].constraint;
- if (_SUCCEEDS_IN_CONTEXT(constraint, newline, 0, letter, 0)
- || _SUCCEEDS_IN_CONTEXT(constraint, newline, 0, letter, 1)
- || _SUCCEEDS_IN_CONTEXT(constraint, newline, 1, letter, 0)
- || _SUCCEEDS_IN_CONTEXT(constraint, newline, 1, letter, 1))
- r->states[i].constraint |= constraint;
- if (! r->states[i].first_end)
- r->states[i].first_end = r->tokens[s->elems[j].index];
+ if (SUCCEEDS_IN_CONTEXT(constraint, newline, 0, letter, 0)
+ || SUCCEEDS_IN_CONTEXT(constraint, newline, 0, letter, 1)
+ || SUCCEEDS_IN_CONTEXT(constraint, newline, 1, letter, 0)
+ || SUCCEEDS_IN_CONTEXT(constraint, newline, 1, letter, 1))
+ d->states[i].constraint |= constraint;
+ if (! d->states[i].first_end)
+ d->states[i].first_end = d->tokens[s->elems[j].index];
}
- else if (r->tokens[s->elems[j].index] == _BACKREF)
+ else if (d->tokens[s->elems[j].index] == BACKREF)
{
- r->states[i].constraint = _NO_CONSTRAINT;
- r->states[i].backref = 1;
+ d->states[i].constraint = NO_CONSTRAINT;
+ d->states[i].backref = 1;
}
- ++r->sindex;
+ ++d->sindex;
return i;
}
-
+
/* Find the epsilon closure of a set of positions. If any position of the set
contains a symbol that matches the empty string in some context, replace
that position with the elements of its follow labeled with an appropriate
constraint. Repeat exhaustively until no funny positions are left.
S->elems must be large enough to hold the result. */
+static void epsclosure _RE_ARGS((position_set *s, struct dfa *d));
+
static void
-epsclosure(s, r)
- _position_set *s;
- struct regexp *r;
+epsclosure(s, d)
+ position_set *s;
+ struct dfa *d;
{
int i, j;
int *visited;
- _position p, old;
+ position p, old;
- MALLOC(visited, int, r->tindex);
- for (i = 0; i < r->tindex; ++i)
+ MALLOC(visited, int, d->tindex);
+ for (i = 0; i < d->tindex; ++i)
visited[i] = 0;
for (i = 0; i < s->nelem; ++i)
- if (r->tokens[s->elems[i].index] >= _NOTCHAR
- && r->tokens[s->elems[i].index] != _BACKREF
- && r->tokens[s->elems[i].index] < _SET)
+ if (d->tokens[s->elems[i].index] >= NOTCHAR
+ && d->tokens[s->elems[i].index] != BACKREF
+ && d->tokens[s->elems[i].index] < CSET)
{
old = s->elems[i];
p.constraint = old.constraint;
@@ -947,32 +1132,32 @@ epsclosure(s, r)
continue;
}
visited[old.index] = 1;
- switch (r->tokens[old.index])
+ switch (d->tokens[old.index])
{
- case _BEGLINE:
- p.constraint &= _BEGLINE_CONSTRAINT;
+ case BEGLINE:
+ p.constraint &= BEGLINE_CONSTRAINT;
break;
- case _ENDLINE:
- p.constraint &= _ENDLINE_CONSTRAINT;
+ case ENDLINE:
+ p.constraint &= ENDLINE_CONSTRAINT;
break;
- case _BEGWORD:
- p.constraint &= _BEGWORD_CONSTRAINT;
+ case BEGWORD:
+ p.constraint &= BEGWORD_CONSTRAINT;
break;
- case _ENDWORD:
- p.constraint &= _ENDWORD_CONSTRAINT;
+ case ENDWORD:
+ p.constraint &= ENDWORD_CONSTRAINT;
break;
- case _LIMWORD:
- p.constraint &= _ENDWORD_CONSTRAINT;
+ case LIMWORD:
+ p.constraint &= LIMWORD_CONSTRAINT;
break;
- case _NOTLIMWORD:
- p.constraint &= _NOTLIMWORD_CONSTRAINT;
+ case NOTLIMWORD:
+ p.constraint &= NOTLIMWORD_CONSTRAINT;
break;
default:
break;
}
- for (j = 0; j < r->follows[old.index].nelem; ++j)
+ for (j = 0; j < d->follows[old.index].nelem; ++j)
{
- p.index = r->follows[old.index].elems[j].index;
+ p.index = d->follows[old.index].elems[j].index;
insert(p, s);
}
/* Force rescan to start at the beginning. */
@@ -981,41 +1166,41 @@ epsclosure(s, r)
free(visited);
}
-
+
/* Perform bottom-up analysis on the parse tree, computing various functions.
Note that at this point, we're pretending constructs like \< are real
characters rather than constraints on what can follow them.
Nullable: A node is nullable if it is at the root of a regexp that can
match the empty string.
- * _EMPTY leaves are nullable.
+ * EMPTY leaves are nullable.
* No other leaf is nullable.
- * A _QMARK or _STAR node is nullable.
- * A _PLUS node is nullable if its argument is nullable.
- * A _CAT node is nullable if both its arguments are nullable.
- * An _OR node is nullable if either argument is nullable.
+ * A QMARK or STAR node is nullable.
+ * A PLUS node is nullable if its argument is nullable.
+ * A CAT node is nullable if both its arguments are nullable.
+ * An OR node is nullable if either argument is nullable.
Firstpos: The firstpos of a node is the set of positions (nonempty leaves)
that could correspond to the first character of a string matching the
regexp rooted at the given node.
- * _EMPTY leaves have empty firstpos.
+ * EMPTY leaves have empty firstpos.
* The firstpos of a nonempty leaf is that leaf itself.
- * The firstpos of a _QMARK, _STAR, or _PLUS node is the firstpos of its
+ * The firstpos of a QMARK, STAR, or PLUS node is the firstpos of its
argument.
- * The firstpos of a _CAT node is the firstpos of the left argument, union
+ * The firstpos of a CAT node is the firstpos of the left argument, union
the firstpos of the right if the left argument is nullable.
- * The firstpos of an _OR node is the union of firstpos of each argument.
+ * The firstpos of an OR node is the union of firstpos of each argument.
Lastpos: The lastpos of a node is the set of positions that could
correspond to the last character of a string matching the regexp at
the given node.
- * _EMPTY leaves have empty lastpos.
+ * EMPTY leaves have empty lastpos.
* The lastpos of a nonempty leaf is that leaf itself.
- * The lastpos of a _QMARK, _STAR, or _PLUS node is the lastpos of its
+ * The lastpos of a QMARK, STAR, or PLUS node is the lastpos of its
argument.
- * The lastpos of a _CAT node is the lastpos of its right argument, union
+ * The lastpos of a CAT node is the lastpos of its right argument, union
the lastpos of the left if the right argument is nullable.
- * The lastpos of an _OR node is the union of the lastpos of each argument.
+ * The lastpos of an OR node is the union of the lastpos of each argument.
Follow: The follow of a position is the set of positions that could
correspond to the character following a character matching the node in
@@ -1024,9 +1209,9 @@ epsclosure(s, r)
Later, if we find that a special symbol is in a follow set, we will
replace it with the elements of its follow, labeled with an appropriate
constraint.
- * Every node in the firstpos of the argument of a _STAR or _PLUS node is in
+ * Every node in the firstpos of the argument of a STAR or PLUS node is in
the follow of every node in the lastpos.
- * Every node in the firstpos of the second argument of a _CAT node is in
+ * Every node in the firstpos of the second argument of a CAT node is in
the follow of every node in the lastpos of the first argument.
Because of the postfix representation of the parse tree, the depth-first
@@ -1035,48 +1220,61 @@ epsclosure(s, r)
scheme; the number of elements in each set deeper in the stack can be
used to determine the address of a particular set's array. */
void
-reganalyze(r, searchflag)
- struct regexp *r;
+dfaanalyze(d, searchflag)
+ struct dfa *d;
int searchflag;
{
int *nullable; /* Nullable stack. */
int *nfirstpos; /* Element count stack for firstpos sets. */
- _position *firstpos; /* Array where firstpos elements are stored. */
+ position *firstpos; /* Array where firstpos elements are stored. */
int *nlastpos; /* Element count stack for lastpos sets. */
- _position *lastpos; /* Array where lastpos elements are stored. */
+ position *lastpos; /* Array where lastpos elements are stored. */
int *nalloc; /* Sizes of arrays allocated to follow sets. */
- _position_set tmp; /* Temporary set for merging sets. */
- _position_set merged; /* Result of merging sets. */
+ position_set tmp; /* Temporary set for merging sets. */
+ position_set merged; /* Result of merging sets. */
int wants_newline; /* True if some position wants newline info. */
int *o_nullable;
int *o_nfirst, *o_nlast;
- _position *o_firstpos, *o_lastpos;
+ position *o_firstpos, *o_lastpos;
int i, j;
- _position *pos;
+ position *pos;
+
+#ifdef DEBUG
+ fprintf(stderr, "dfaanalyze:\n");
+ for (i = 0; i < d->tindex; ++i)
+ {
+ fprintf(stderr, " %d:", i);
+ prtok(d->tokens[i]);
+ }
+ putc('\n', stderr);
+#endif
- r->searchflag = searchflag;
+ d->searchflag = searchflag;
- MALLOC(nullable, int, r->depth);
+ MALLOC(nullable, int, d->depth);
o_nullable = nullable;
- MALLOC(nfirstpos, int, r->depth);
+ MALLOC(nfirstpos, int, d->depth);
o_nfirst = nfirstpos;
- MALLOC(firstpos, _position, r->nleaves);
- o_firstpos = firstpos, firstpos += r->nleaves;
- MALLOC(nlastpos, int, r->depth);
+ MALLOC(firstpos, position, d->nleaves);
+ o_firstpos = firstpos, firstpos += d->nleaves;
+ MALLOC(nlastpos, int, d->depth);
o_nlast = nlastpos;
- MALLOC(lastpos, _position, r->nleaves);
- o_lastpos = lastpos, lastpos += r->nleaves;
- MALLOC(nalloc, int, r->tindex);
- for (i = 0; i < r->tindex; ++i)
+ MALLOC(lastpos, position, d->nleaves);
+ o_lastpos = lastpos, lastpos += d->nleaves;
+ MALLOC(nalloc, int, d->tindex);
+ for (i = 0; i < d->tindex; ++i)
nalloc[i] = 0;
- MALLOC(merged.elems, _position, r->nleaves);
+ MALLOC(merged.elems, position, d->nleaves);
- CALLOC(r->follows, _position_set, r->tindex);
+ CALLOC(d->follows, position_set, d->tindex);
- for (i = 0; i < r->tindex; ++i)
- switch (r->tokens[i])
+ for (i = 0; i < d->tindex; ++i)
+#ifdef DEBUG
+ { /* Nonsyntactic #ifdef goo... */
+#endif
+ switch (d->tokens[i])
{
- case _EMPTY:
+ case EMPTY:
/* The empty set is nullable. */
*nullable++ = 1;
@@ -1084,8 +1282,8 @@ reganalyze(r, searchflag)
*nfirstpos++ = *nlastpos++ = 0;
break;
- case _STAR:
- case _PLUS:
+ case STAR:
+ case PLUS:
/* Every element in the firstpos of the argument is in the follow
of every element in the lastpos. */
tmp.nelem = nfirstpos[-1];
@@ -1093,19 +1291,19 @@ reganalyze(r, searchflag)
pos = lastpos;
for (j = 0; j < nlastpos[-1]; ++j)
{
- merge(&tmp, &r->follows[pos[j].index], &merged);
- REALLOC_IF_NECESSARY(r->follows[pos[j].index].elems, _position,
+ merge(&tmp, &d->follows[pos[j].index], &merged);
+ REALLOC_IF_NECESSARY(d->follows[pos[j].index].elems, position,
nalloc[pos[j].index], merged.nelem - 1);
- copy(&merged, &r->follows[pos[j].index]);
+ copy(&merged, &d->follows[pos[j].index]);
}
- case _QMARK:
- /* A _QMARK or _STAR node is automatically nullable. */
- if (r->tokens[i] != _PLUS)
+ case QMARK:
+ /* A QMARK or STAR node is automatically nullable. */
+ if (d->tokens[i] != PLUS)
nullable[-1] = 1;
break;
- case _CAT:
+ case CAT:
/* Every element in the firstpos of the second argument is in the
follow of every element in the lastpos of the first argument. */
tmp.nelem = nfirstpos[-1];
@@ -1113,13 +1311,13 @@ reganalyze(r, searchflag)
pos = lastpos + nlastpos[-1];
for (j = 0; j < nlastpos[-2]; ++j)
{
- merge(&tmp, &r->follows[pos[j].index], &merged);
- REALLOC_IF_NECESSARY(r->follows[pos[j].index].elems, _position,
+ merge(&tmp, &d->follows[pos[j].index], &merged);
+ REALLOC_IF_NECESSARY(d->follows[pos[j].index].elems, position,
nalloc[pos[j].index], merged.nelem - 1);
- copy(&merged, &r->follows[pos[j].index]);
+ copy(&merged, &d->follows[pos[j].index]);
}
- /* The firstpos of a _CAT node is the firstpos of the first argument,
+ /* The firstpos of a CAT node is the firstpos of the first argument,
union that of the second argument if the first is nullable. */
if (nullable[-2])
nfirstpos[-2] += nfirstpos[-1];
@@ -1127,7 +1325,7 @@ reganalyze(r, searchflag)
firstpos += nfirstpos[-1];
--nfirstpos;
- /* The lastpos of a _CAT node is the lastpos of the second argument,
+ /* The lastpos of a CAT node is the lastpos of the second argument,
union that of the first argument if the second is nullable. */
if (nullable[-1])
nlastpos[-2] += nlastpos[-1];
@@ -1141,12 +1339,13 @@ reganalyze(r, searchflag)
}
--nlastpos;
- /* A _CAT node is nullable if both arguments are nullable. */
+ /* A CAT node is nullable if both arguments are nullable. */
nullable[-2] = nullable[-1] && nullable[-2];
--nullable;
break;
- case _OR:
+ case OR:
+ case ORTOP:
/* The firstpos is the union of the firstpos of each argument. */
nfirstpos[-2] += nfirstpos[-1];
--nfirstpos;
@@ -1155,7 +1354,7 @@ reganalyze(r, searchflag)
nlastpos[-2] += nlastpos[-1];
--nlastpos;
- /* An _OR node is nullable if either argument is nullable. */
+ /* An OR node is nullable if either argument is nullable. */
nullable[-2] = nullable[-1] || nullable[-2];
--nullable;
break;
@@ -1166,31 +1365,63 @@ reganalyze(r, searchflag)
an "epsilon closure" effectively makes them nullable later.
Backreferences have to get a real position so we can detect
transitions on them later. But they are nullable. */
- *nullable++ = r->tokens[i] == _BACKREF;
+ *nullable++ = d->tokens[i] == BACKREF;
/* This position is in its own firstpos and lastpos. */
*nfirstpos++ = *nlastpos++ = 1;
--firstpos, --lastpos;
firstpos->index = lastpos->index = i;
- firstpos->constraint = lastpos->constraint = _NO_CONSTRAINT;
+ firstpos->constraint = lastpos->constraint = NO_CONSTRAINT;
/* Allocate the follow set for this position. */
nalloc[i] = 1;
- MALLOC(r->follows[i].elems, _position, nalloc[i]);
+ MALLOC(d->follows[i].elems, position, nalloc[i]);
break;
}
+#ifdef DEBUG
+ /* ... balance the above nonsyntactic #ifdef goo... */
+ fprintf(stderr, "node %d:", i);
+ prtok(d->tokens[i]);
+ putc('\n', stderr);
+ fprintf(stderr, nullable[-1] ? " nullable: yes\n" : " nullable: no\n");
+ fprintf(stderr, " firstpos:");
+ for (j = nfirstpos[-1] - 1; j >= 0; --j)
+ {
+ fprintf(stderr, " %d:", firstpos[j].index);
+ prtok(d->tokens[firstpos[j].index]);
+ }
+ fprintf(stderr, "\n lastpos:");
+ for (j = nlastpos[-1] - 1; j >= 0; --j)
+ {
+ fprintf(stderr, " %d:", lastpos[j].index);
+ prtok(d->tokens[lastpos[j].index]);
+ }
+ putc('\n', stderr);
+ }
+#endif
/* For each follow set that is the follow set of a real position, replace
it with its epsilon closure. */
- for (i = 0; i < r->tindex; ++i)
- if (r->tokens[i] < _NOTCHAR || r->tokens[i] == _BACKREF
- || r->tokens[i] >= _SET)
+ for (i = 0; i < d->tindex; ++i)
+ if (d->tokens[i] < NOTCHAR || d->tokens[i] == BACKREF
+ || d->tokens[i] >= CSET)
{
- copy(&r->follows[i], &merged);
- epsclosure(&merged, r);
- if (r->follows[i].nelem < merged.nelem)
- REALLOC(r->follows[i].elems, _position, merged.nelem);
- copy(&merged, &r->follows[i]);
+#ifdef DEBUG
+ fprintf(stderr, "follows(%d:", i);
+ prtok(d->tokens[i]);
+ fprintf(stderr, "):");
+ for (j = d->follows[i].nelem - 1; j >= 0; --j)
+ {
+ fprintf(stderr, " %d:", d->follows[i].elems[j].index);
+ prtok(d->tokens[d->follows[i].elems[j].index]);
+ }
+ putc('\n', stderr);
+#endif
+ copy(&d->follows[i], &merged);
+ epsclosure(&merged, d);
+ if (d->follows[i].nelem < merged.nelem)
+ REALLOC(d->follows[i].elems, position, merged.nelem);
+ copy(&merged, &d->follows[i]);
}
/* Get the epsilon closure of the firstpos of the regexp. The result will
@@ -1198,19 +1429,19 @@ reganalyze(r, searchflag)
merged.nelem = 0;
for (i = 0; i < nfirstpos[-1]; ++i)
insert(firstpos[i], &merged);
- epsclosure(&merged, r);
+ epsclosure(&merged, d);
/* Check if any of the positions of state 0 will want newline context. */
wants_newline = 0;
for (i = 0; i < merged.nelem; ++i)
- if (_PREV_NEWLINE_DEPENDENT(merged.elems[i].constraint))
+ if (PREV_NEWLINE_DEPENDENT(merged.elems[i].constraint))
wants_newline = 1;
/* Build the initial state. */
- r->salloc = 1;
- r->sindex = 0;
- MALLOC(r->states, _dfa_state, r->salloc);
- state_index(r, &merged, wants_newline, 0);
+ d->salloc = 1;
+ d->sindex = 0;
+ MALLOC(d->states, dfa_state, d->salloc);
+ state_index(d, &merged, wants_newline, 0);
free(o_nullable);
free(o_nfirst);
@@ -1220,8 +1451,8 @@ reganalyze(r, searchflag)
free(nalloc);
free(merged.elems);
}
-
-/* Find, for each character, the transition out of state s of r, and store
+
+/* Find, for each character, the transition out of state s of d, and store
it in the appropriate slot of trans.
We divide the positions of s into groups (positions can appear in more
@@ -1252,25 +1483,25 @@ reganalyze(r, searchflag)
create a new group labeled with the characters of C and insert this
position in that group. */
void
-regstate(s, r, trans)
+dfastate(s, d, trans)
int s;
- struct regexp *r;
+ struct dfa *d;
int trans[];
{
- _position_set grps[_NOTCHAR]; /* As many as will ever be needed. */
- _charset labels[_NOTCHAR]; /* Labels corresponding to the groups. */
+ position_set grps[NOTCHAR]; /* As many as will ever be needed. */
+ charclass labels[NOTCHAR]; /* Labels corresponding to the groups. */
int ngrps = 0; /* Number of groups actually used. */
- _position pos; /* Current position being considered. */
- _charset matches; /* Set of matching characters. */
+ position pos; /* Current position being considered. */
+ charclass matches; /* Set of matching characters. */
int matchesf; /* True if matches is nonempty. */
- _charset intersect; /* Intersection with some label set. */
+ charclass intersect; /* Intersection with some label set. */
int intersectf; /* True if intersect is nonempty. */
- _charset leftovers; /* Stuff in the label that didn't match. */
+ charclass leftovers; /* Stuff in the label that didn't match. */
int leftoversf; /* True if leftovers is nonempty. */
- static _charset letters; /* Set of characters considered letters. */
- static _charset newline; /* Set of characters that aren't newline. */
- _position_set follows; /* Union of the follows of some group. */
- _position_set tmp; /* Temporary space for merging sets. */
+ static charclass letters; /* Set of characters considered letters. */
+ static charclass newline; /* Set of characters that aren't newline. */
+ position_set follows; /* Union of the follows of some group. */
+ position_set tmp; /* Temporary space for merging sets. */
int state; /* New state. */
int wants_newline; /* New state wants to know newline context. */
int state_newline; /* New state on a newline transition. */
@@ -1283,7 +1514,7 @@ regstate(s, r, trans)
if (! initialized)
{
initialized = 1;
- for (i = 0; i < _NOTCHAR; ++i)
+ for (i = 0; i < NOTCHAR; ++i)
if (ISALNUM(i))
setbit(i, letters);
setbit('\n', newline);
@@ -1291,40 +1522,40 @@ regstate(s, r, trans)
zeroset(matches);
- for (i = 0; i < r->states[s].elems.nelem; ++i)
+ for (i = 0; i < d->states[s].elems.nelem; ++i)
{
- pos = r->states[s].elems.elems[i];
- if (r->tokens[pos.index] >= 0 && r->tokens[pos.index] < _NOTCHAR)
- setbit(r->tokens[pos.index], matches);
- else if (r->tokens[pos.index] >= _SET)
- copyset(r->charsets[r->tokens[pos.index] - _SET], matches);
+ pos = d->states[s].elems.elems[i];
+ if (d->tokens[pos.index] >= 0 && d->tokens[pos.index] < NOTCHAR)
+ setbit(d->tokens[pos.index], matches);
+ else if (d->tokens[pos.index] >= CSET)
+ copyset(d->charclasses[d->tokens[pos.index] - CSET], matches);
else
continue;
- /* Some characters may need to be climinated from matches because
+ /* Some characters may need to be eliminated from matches because
they fail in the current context. */
- if (pos.constraint != 0xff)
+ if (pos.constraint != 0xFF)
{
- if (! _MATCHES_NEWLINE_CONTEXT(pos.constraint,
- r->states[s].newline, 1))
+ if (! MATCHES_NEWLINE_CONTEXT(pos.constraint,
+ d->states[s].newline, 1))
clrbit('\n', matches);
- if (! _MATCHES_NEWLINE_CONTEXT(pos.constraint,
- r->states[s].newline, 0))
- for (j = 0; j < _CHARSET_INTS; ++j)
+ if (! MATCHES_NEWLINE_CONTEXT(pos.constraint,
+ d->states[s].newline, 0))
+ for (j = 0; j < CHARCLASS_INTS; ++j)
matches[j] &= newline[j];
- if (! _MATCHES_LETTER_CONTEXT(pos.constraint,
- r->states[s].letter, 1))
- for (j = 0; j < _CHARSET_INTS; ++j)
+ if (! MATCHES_LETTER_CONTEXT(pos.constraint,
+ d->states[s].letter, 1))
+ for (j = 0; j < CHARCLASS_INTS; ++j)
matches[j] &= ~letters[j];
- if (! _MATCHES_LETTER_CONTEXT(pos.constraint,
- r->states[s].letter, 0))
- for (j = 0; j < _CHARSET_INTS; ++j)
+ if (! MATCHES_LETTER_CONTEXT(pos.constraint,
+ d->states[s].letter, 0))
+ for (j = 0; j < CHARCLASS_INTS; ++j)
matches[j] &= letters[j];
/* If there are no characters left, there's no point in going on. */
- for (j = 0; j < _CHARSET_INTS && !matches[j]; ++j)
- ;
- if (j == _CHARSET_INTS)
+ for (j = 0; j < CHARCLASS_INTS && !matches[j]; ++j)
+ continue;
+ if (j == CHARCLASS_INTS)
continue;
}
@@ -1333,27 +1564,27 @@ regstate(s, r, trans)
/* If matches contains a single character only, and the current
group's label doesn't contain that character, go on to the
next group. */
- if (r->tokens[pos.index] >= 0 && r->tokens[pos.index] < _NOTCHAR
- && !tstbit(r->tokens[pos.index], labels[j]))
+ if (d->tokens[pos.index] >= 0 && d->tokens[pos.index] < NOTCHAR
+ && !tstbit(d->tokens[pos.index], labels[j]))
continue;
/* Check if this group's label has a nonempty intersection with
matches. */
intersectf = 0;
- for (k = 0; k < _CHARSET_INTS; ++k)
- (intersect[k] = matches[k] & labels[j][k]) ? intersectf = 1 : 0;
+ for (k = 0; k < CHARCLASS_INTS; ++k)
+ (intersect[k] = matches[k] & labels[j][k]) ? (intersectf = 1) : 0;
if (! intersectf)
continue;
/* It does; now find the set differences both ways. */
leftoversf = matchesf = 0;
- for (k = 0; k < _CHARSET_INTS; ++k)
+ for (k = 0; k < CHARCLASS_INTS; ++k)
{
/* Even an optimizing compiler can't know this for sure. */
int match = matches[k], label = labels[j][k];
- (leftovers[k] = ~match & label) ? leftoversf = 1 : 0;
- (matches[k] = match & ~label) ? matchesf = 1 : 0;
+ (leftovers[k] = ~match & label) ? (leftoversf = 1) : 0;
+ (matches[k] = match & ~label) ? (matchesf = 1) : 0;
}
/* If there were leftovers, create a new group labeled with them. */
@@ -1361,7 +1592,7 @@ regstate(s, r, trans)
{
copyset(leftovers, labels[ngrps]);
copyset(intersect, labels[j]);
- MALLOC(grps[ngrps].elems, _position, r->nleaves);
+ MALLOC(grps[ngrps].elems, position, d->nleaves);
copy(&grps[j], &grps[ngrps]);
++ngrps;
}
@@ -1382,46 +1613,50 @@ regstate(s, r, trans)
{
copyset(matches, labels[ngrps]);
zeroset(matches);
- MALLOC(grps[ngrps].elems, _position, r->nleaves);
+ MALLOC(grps[ngrps].elems, position, d->nleaves);
grps[ngrps].nelem = 1;
grps[ngrps].elems[0] = pos;
++ngrps;
}
}
- MALLOC(follows.elems, _position, r->nleaves);
- MALLOC(tmp.elems, _position, r->nleaves);
+ MALLOC(follows.elems, position, d->nleaves);
+ MALLOC(tmp.elems, position, d->nleaves);
/* If we are a searching matcher, the default transition is to a state
containing the positions of state 0, otherwise the default transition
is to fail miserably. */
- if (r->searchflag)
+ if (d->searchflag)
{
wants_newline = 0;
wants_letter = 0;
- for (i = 0; i < r->states[0].elems.nelem; ++i)
+ for (i = 0; i < d->states[0].elems.nelem; ++i)
{
- if (_PREV_NEWLINE_DEPENDENT(r->states[0].elems.elems[i].constraint))
+ if (PREV_NEWLINE_DEPENDENT(d->states[0].elems.elems[i].constraint))
wants_newline = 1;
- if (_PREV_LETTER_DEPENDENT(r->states[0].elems.elems[i].constraint))
+ if (PREV_LETTER_DEPENDENT(d->states[0].elems.elems[i].constraint))
wants_letter = 1;
}
- copy(&r->states[0].elems, &follows);
- state = state_index(r, &follows, 0, 0);
+ copy(&d->states[0].elems, &follows);
+ state = state_index(d, &follows, 0, 0);
if (wants_newline)
- state_newline = state_index(r, &follows, 1, 0);
+ state_newline = state_index(d, &follows, 1, 0);
else
state_newline = state;
if (wants_letter)
- state_letter = state_index(r, &follows, 0, 1);
+ state_letter = state_index(d, &follows, 0, 1);
else
state_letter = state;
- for (i = 0; i < _NOTCHAR; ++i)
- trans[i] = (ISALNUM(i)) ? state_letter : state ;
- trans['\n'] = state_newline;
+ for (i = 0; i < NOTCHAR; ++i)
+ if (i == '\n')
+ trans[i] = state_newline;
+ else if (ISALNUM(i))
+ trans[i] = state_letter;
+ else
+ trans[i] = state;
}
else
- for (i = 0; i < _NOTCHAR; ++i)
+ for (i = 0; i < NOTCHAR; ++i)
trans[i] = -1;
for (i = 0; i < ngrps; ++i)
@@ -1431,44 +1666,44 @@ regstate(s, r, trans)
/* Find the union of the follows of the positions of the group.
This is a hideously inefficient loop. Fix it someday. */
for (j = 0; j < grps[i].nelem; ++j)
- for (k = 0; k < r->follows[grps[i].elems[j].index].nelem; ++k)
- insert(r->follows[grps[i].elems[j].index].elems[k], &follows);
+ for (k = 0; k < d->follows[grps[i].elems[j].index].nelem; ++k)
+ insert(d->follows[grps[i].elems[j].index].elems[k], &follows);
/* If we are building a searching matcher, throw in the positions
of state 0 as well. */
- if (r->searchflag)
- for (j = 0; j < r->states[0].elems.nelem; ++j)
- insert(r->states[0].elems.elems[j], &follows);
+ if (d->searchflag)
+ for (j = 0; j < d->states[0].elems.nelem; ++j)
+ insert(d->states[0].elems.elems[j], &follows);
/* Find out if the new state will want any context information. */
wants_newline = 0;
if (tstbit('\n', labels[i]))
for (j = 0; j < follows.nelem; ++j)
- if (_PREV_NEWLINE_DEPENDENT(follows.elems[j].constraint))
+ if (PREV_NEWLINE_DEPENDENT(follows.elems[j].constraint))
wants_newline = 1;
wants_letter = 0;
- for (j = 0; j < _CHARSET_INTS; ++j)
+ for (j = 0; j < CHARCLASS_INTS; ++j)
if (labels[i][j] & letters[j])
break;
- if (j < _CHARSET_INTS)
+ if (j < CHARCLASS_INTS)
for (j = 0; j < follows.nelem; ++j)
- if (_PREV_LETTER_DEPENDENT(follows.elems[j].constraint))
+ if (PREV_LETTER_DEPENDENT(follows.elems[j].constraint))
wants_letter = 1;
/* Find the state(s) corresponding to the union of the follows. */
- state = state_index(r, &follows, 0, 0);
+ state = state_index(d, &follows, 0, 0);
if (wants_newline)
- state_newline = state_index(r, &follows, 1, 0);
+ state_newline = state_index(d, &follows, 1, 0);
else
state_newline = state;
if (wants_letter)
- state_letter = state_index(r, &follows, 0, 1);
+ state_letter = state_index(d, &follows, 0, 1);
else
state_letter = state;
/* Set the transitions for each character in the current label. */
- for (j = 0; j < _CHARSET_INTS; ++j)
+ for (j = 0; j < CHARCLASS_INTS; ++j)
for (k = 0; k < INTBITS; ++k)
if (labels[i][j] & 1 << k)
{
@@ -1478,7 +1713,7 @@ regstate(s, r, trans)
trans[c] = state_newline;
else if (ISALNUM(c))
trans[c] = state_letter;
- else if (c < _NOTCHAR)
+ else if (c < NOTCHAR)
trans[c] = state;
}
}
@@ -1488,18 +1723,18 @@ regstate(s, r, trans)
free(follows.elems);
free(tmp.elems);
}
-
-/* Some routines for manipulating a compiled regexp's transition tables.
+
+/* Some routines for manipulating a compiled dfa's transition tables.
Each state may or may not have a transition table; if it does, and it
- is a non-accepting state, then r->trans[state] points to its table.
- If it is an accepting state then r->fails[state] points to its table.
- If it has no table at all, then r->trans[state] is NULL.
+ is a non-accepting state, then d->trans[state] points to its table.
+ If it is an accepting state then d->fails[state] points to its table.
+ If it has no table at all, then d->trans[state] is NULL.
TODO: Improve this comment, get rid of the unnecessary redundancy. */
static void
-build_state(s, r)
+build_state(s, d)
int s;
- struct regexp *r;
+ struct dfa *d;
{
int *trans; /* The new transition table. */
int i;
@@ -1508,87 +1743,87 @@ build_state(s, r)
exist at once. 1024 is arbitrary. The idea is that the frequently
used transition tables will be quickly rebuilt, whereas the ones that
were only needed once or twice will be cleared away. */
- if (r->trcount >= 1024)
+ if (d->trcount >= 1024)
{
- for (i = 0; i < r->tralloc; ++i)
- if (r->trans[i])
+ for (i = 0; i < d->tralloc; ++i)
+ if (d->trans[i])
{
- free((ptr_t) r->trans[i]);
- r->trans[i] = NULL;
+ free((ptr_t) d->trans[i]);
+ d->trans[i] = NULL;
}
- else if (r->fails[i])
+ else if (d->fails[i])
{
- free((ptr_t) r->fails[i]);
- r->fails[i] = NULL;
+ free((ptr_t) d->fails[i]);
+ d->fails[i] = NULL;
}
- r->trcount = 0;
+ d->trcount = 0;
}
- ++r->trcount;
+ ++d->trcount;
/* Set up the success bits for this state. */
- r->success[s] = 0;
- if (ACCEPTS_IN_CONTEXT(r->states[s].newline, 1, r->states[s].letter, 0,
- s, *r))
- r->success[s] |= 4;
- if (ACCEPTS_IN_CONTEXT(r->states[s].newline, 0, r->states[s].letter, 1,
- s, *r))
- r->success[s] |= 2;
- if (ACCEPTS_IN_CONTEXT(r->states[s].newline, 0, r->states[s].letter, 0,
- s, *r))
- r->success[s] |= 1;
-
- MALLOC(trans, int, _NOTCHAR);
- regstate(s, r, trans);
+ d->success[s] = 0;
+ if (ACCEPTS_IN_CONTEXT(d->states[s].newline, 1, d->states[s].letter, 0,
+ s, *d))
+ d->success[s] |= 4;
+ if (ACCEPTS_IN_CONTEXT(d->states[s].newline, 0, d->states[s].letter, 1,
+ s, *d))
+ d->success[s] |= 2;
+ if (ACCEPTS_IN_CONTEXT(d->states[s].newline, 0, d->states[s].letter, 0,
+ s, *d))
+ d->success[s] |= 1;
+
+ MALLOC(trans, int, NOTCHAR);
+ dfastate(s, d, trans);
/* Now go through the new transition table, and make sure that the trans
and fail arrays are allocated large enough to hold a pointer for the
largest state mentioned in the table. */
- for (i = 0; i < _NOTCHAR; ++i)
- if (trans[i] >= r->tralloc)
+ for (i = 0; i < NOTCHAR; ++i)
+ if (trans[i] >= d->tralloc)
{
- int oldalloc = r->tralloc;
-
- while (trans[i] >= r->tralloc)
- r->tralloc *= 2;
- REALLOC(r->realtrans, int *, r->tralloc + 1);
- r->trans = r->realtrans + 1;
- REALLOC(r->fails, int *, r->tralloc);
- REALLOC(r->success, int, r->tralloc);
- REALLOC(r->newlines, int, r->tralloc);
- while (oldalloc < r->tralloc)
+ int oldalloc = d->tralloc;
+
+ while (trans[i] >= d->tralloc)
+ d->tralloc *= 2;
+ REALLOC(d->realtrans, int *, d->tralloc + 1);
+ d->trans = d->realtrans + 1;
+ REALLOC(d->fails, int *, d->tralloc);
+ REALLOC(d->success, int, d->tralloc);
+ REALLOC(d->newlines, int, d->tralloc);
+ while (oldalloc < d->tralloc)
{
- r->trans[oldalloc] = NULL;
- r->fails[oldalloc++] = NULL;
+ d->trans[oldalloc] = NULL;
+ d->fails[oldalloc++] = NULL;
}
}
/* Keep the newline transition in a special place so we can use it as
a sentinel. */
- r->newlines[s] = trans['\n'];
+ d->newlines[s] = trans['\n'];
trans['\n'] = -1;
- if (ACCEPTING(s, *r))
- r->fails[s] = trans;
+ if (ACCEPTING(s, *d))
+ d->fails[s] = trans;
else
- r->trans[s] = trans;
+ d->trans[s] = trans;
}
static void
-build_state_zero(r)
- struct regexp *r;
+build_state_zero(d)
+ struct dfa *d;
{
- r->tralloc = 1;
- r->trcount = 0;
- CALLOC(r->realtrans, int *, r->tralloc + 1);
- r->trans = r->realtrans + 1;
- CALLOC(r->fails, int *, r->tralloc);
- MALLOC(r->success, int, r->tralloc);
- MALLOC(r->newlines, int, r->tralloc);
- build_state(0, r);
+ d->tralloc = 1;
+ d->trcount = 0;
+ CALLOC(d->realtrans, int *, d->tralloc + 1);
+ d->trans = d->realtrans + 1;
+ CALLOC(d->fails, int *, d->tralloc);
+ MALLOC(d->success, int, d->tralloc);
+ MALLOC(d->newlines, int, d->tralloc);
+ build_state(0, d);
}
-
-/* Search through a buffer looking for a match to the given struct regexp.
+
+/* Search through a buffer looking for a match to the given struct dfa.
Find the first occurrence of a string matching the regexp in the buffer,
and the shortest possible version thereof. Return a pointer to the first
character after the match, or NULL if none is found. Begin points to
@@ -1602,8 +1837,8 @@ build_state_zero(r)
match needs to be verified by a backtracking matcher. Otherwise
we store a 0 in *backref. */
char *
-regexecute(r, begin, end, newline, count, backref)
- struct regexp *r;
+dfaexec(d, begin, end, newline, count, backref)
+ struct dfa *d;
char *begin;
char *end;
int newline;
@@ -1612,9 +1847,9 @@ regexecute(r, begin, end, newline, count, backref)
{
register s, s1, tmp; /* Current state. */
register unsigned char *p; /* Current input character. */
- register **trans, *t; /* Copy of r->trans so it can be optimized
+ register **trans, *t; /* Copy of d->trans so it can be optimized
into a register. */
- static sbit[_NOTCHAR]; /* Table for anding with r->success. */
+ static sbit[NOTCHAR]; /* Table for anding with d->success. */
static sbit_init;
if (! sbit_init)
@@ -1622,41 +1857,54 @@ regexecute(r, begin, end, newline, count, backref)
int i;
sbit_init = 1;
- for (i = 0; i < _NOTCHAR; ++i)
- sbit[i] = (ISALNUM(i)) ? 2 : 1;
- sbit['\n'] = 4;
+ for (i = 0; i < NOTCHAR; ++i)
+ if (i == '\n')
+ sbit[i] = 4;
+ else if (ISALNUM(i))
+ sbit[i] = 2;
+ else
+ sbit[i] = 1;
}
- if (! r->tralloc)
- build_state_zero(r);
+ if (! d->tralloc)
+ build_state_zero(d);
s = s1 = 0;
p = (unsigned char *) begin;
- trans = r->trans;
+ trans = d->trans;
*end = '\n';
for (;;)
{
- while ((t = trans[s]) != 0) { /* hand-optimized loop */
- s1 = t[*p++];
- if ((t = trans[s1]) == 0) {
- tmp = s ; s = s1 ; s1 = tmp ; /* swap */
- break;
- }
- s = t[*p++];
- }
+ /* The dreaded inner loop. */
+ if ((t = trans[s]) != 0)
+ do
+ {
+ s1 = t[*p++];
+ if (! (t = trans[s1]))
+ goto last_was_s;
+ s = t[*p++];
+ }
+ while ((t = trans[s]) != 0);
+ goto last_was_s1;
+ last_was_s:
+ tmp = s, s = s1, s1 = tmp;
+ last_was_s1:
- if (s >= 0 && p <= (unsigned char *) end && r->fails[s])
+ if (s >= 0 && p <= (unsigned char *) end && d->fails[s])
{
- if (r->success[s] & sbit[*p])
+ if (d->success[s] & sbit[*p])
{
if (backref)
- *backref = (r->states[s].backref != 0);
+ if (d->states[s].backref)
+ *backref = 1;
+ else
+ *backref = 0;
return (char *) p;
}
s1 = s;
- s = r->fails[s][*p++];
+ s = d->fails[s][*p++];
continue;
}
@@ -1665,627 +1913,662 @@ regexecute(r, begin, end, newline, count, backref)
++*count;
/* Check if we've run off the end of the buffer. */
- if ((char *) p >= end)
+ if ((char *) p > end)
return NULL;
if (s >= 0)
{
- build_state(s, r);
- trans = r->trans;
+ build_state(s, d);
+ trans = d->trans;
continue;
}
if (p[-1] == '\n' && newline)
{
- s = r->newlines[s1];
+ s = d->newlines[s1];
continue;
}
s = 0;
}
}
-
-/* Initialize the components of a regexp that the other routines don't
+
+/* Initialize the components of a dfa that the other routines don't
initialize for themselves. */
void
-reginit(r)
- struct regexp *r;
+dfainit(d)
+ struct dfa *d;
{
- r->calloc = 1;
- MALLOC(r->charsets, _charset, r->calloc);
- r->cindex = 0;
+ d->calloc = 1;
+ MALLOC(d->charclasses, charclass, d->calloc);
+ d->cindex = 0;
- r->talloc = 1;
- MALLOC(r->tokens, _token, r->talloc);
- r->tindex = r->depth = r->nleaves = r->nregexps = 0;
+ d->talloc = 1;
+ MALLOC(d->tokens, token, d->talloc);
+ d->tindex = d->depth = d->nleaves = d->nregexps = 0;
- r->searchflag = 0;
- r->tralloc = 0;
+ d->searchflag = 0;
+ d->tralloc = 0;
+
+ d->musts = 0;
}
/* Parse and analyze a single string of the given length. */
void
-regcompile(s, len, r, searchflag)
- const char *s;
+dfacomp(s, len, d, searchflag)
+ char *s;
size_t len;
- struct regexp *r;
+ struct dfa *d;
int searchflag;
{
- if (case_fold) /* dummy folding in service of regmust() */
+ if (case_fold) /* dummy folding in service of dfamust() */
{
- char *regcopy;
+ char *lcopy;
int i;
- regcopy = malloc(len);
- if (!regcopy)
- reg_error("out of memory");
-
- /* This is a complete kludge and could potentially break
- \<letter> escapes . . . */
+ lcopy = malloc(len);
+ if (!lcopy)
+ dfaerror("out of memory");
+
+ /* This is a kludge. */
case_fold = 0;
for (i = 0; i < len; ++i)
if (ISUPPER(s[i]))
- regcopy[i] = tolower(s[i]);
+ lcopy[i] = tolower(s[i]);
else
- regcopy[i] = s[i];
-
- reginit(r);
- r->mustn = 0;
- r->must[0] = '\0';
- regparse(regcopy, len, r);
- free(regcopy);
- regmust(r);
- reganalyze(r, searchflag);
+ lcopy[i] = s[i];
+
+ dfainit(d);
+ dfaparse(lcopy, len, d);
+ free(lcopy);
+ dfamust(d);
+ d->cindex = d->tindex = d->depth = d->nleaves = d->nregexps = 0;
case_fold = 1;
- reginit(r);
- regparse(s, len, r);
- reganalyze(r, searchflag);
+ dfaparse(s, len, d);
+ dfaanalyze(d, searchflag);
}
else
{
- reginit(r);
- regparse(s, len, r);
- regmust(r);
- reganalyze(r, searchflag);
+ dfainit(d);
+ dfaparse(s, len, d);
+ dfamust(d);
+ dfaanalyze(d, searchflag);
}
}
-/* Free the storage held by the components of a regexp. */
+/* Free the storage held by the components of a dfa. */
void
-reg_free(r)
- struct regexp *r;
+dfafree(d)
+ struct dfa *d;
{
int i;
-
- free((ptr_t) r->charsets);
- free((ptr_t) r->tokens);
- for (i = 0; i < r->sindex; ++i)
- free((ptr_t) r->states[i].elems.elems);
- free((ptr_t) r->states);
- for (i = 0; i < r->tindex; ++i)
- if (r->follows[i].elems)
- free((ptr_t) r->follows[i].elems);
- free((ptr_t) r->follows);
- for (i = 0; i < r->tralloc; ++i)
- if (r->trans[i])
- free((ptr_t) r->trans[i]);
- else if (r->fails[i])
- free((ptr_t) r->fails[i]);
- if (r->realtrans)
- free((ptr_t) r->realtrans);
- if (r->fails)
- free((ptr_t) r->fails);
- if (r->newlines)
- free((ptr_t) r->newlines);
+ struct dfamust *dm, *ndm;
+
+ free((ptr_t) d->charclasses);
+ free((ptr_t) d->tokens);
+ for (i = 0; i < d->sindex; ++i)
+ free((ptr_t) d->states[i].elems.elems);
+ free((ptr_t) d->states);
+ for (i = 0; i < d->tindex; ++i)
+ if (d->follows[i].elems)
+ free((ptr_t) d->follows[i].elems);
+ free((ptr_t) d->follows);
+ for (i = 0; i < d->tralloc; ++i)
+ if (d->trans[i])
+ free((ptr_t) d->trans[i]);
+ else if (d->fails[i])
+ free((ptr_t) d->fails[i]);
+ if (d->realtrans) free((ptr_t) d->realtrans);
+ if (d->fails) free((ptr_t) d->fails);
+ if (d->newlines) free((ptr_t) d->newlines);
+ for (dm = d->musts; dm; dm = ndm)
+ {
+ ndm = dm->next;
+ free(dm->must);
+ free((ptr_t) dm);
+ }
}
-/*
-Having found the postfix representation of the regular expression,
-try to find a long sequence of characters that must appear in any line
-containing the r.e.
-Finding a "longest" sequence is beyond the scope here;
-we take an easy way out and hope for the best.
-(Take "(ab|a)b"--please.)
-
-We do a bottom-up calculation of sequences of characters that must appear
-in matches of r.e.'s represented by trees rooted at the nodes of the postfix
-representation:
+/* Having found the postfix representation of the regular expression,
+ try to find a long sequence of characters that must appear in any line
+ containing the r.e.
+ Finding a "longest" sequence is beyond the scope here;
+ we take an easy way out and hope for the best.
+ (Take "(ab|a)b"--please.)
+
+ We do a bottom-up calculation of sequences of characters that must appear
+ in matches of r.e.'s represented by trees rooted at the nodes of the postfix
+ representation:
sequences that must appear at the left of the match ("left")
sequences that must appear at the right of the match ("right")
lists of sequences that must appear somewhere in the match ("in")
sequences that must constitute the match ("is")
-When we get to the root of the tree, we use one of the longest of its
-calculated "in" sequences as our answer. The sequence we find is returned in
-r->must (where "r" is the single argument passed to "regmust");
-the length of the sequence is returned in r->mustn.
-The sequences calculated for the various types of node (in pseudo ANSI c)
-are shown below. "p" is the operand of unary operators (and the left-hand
-operand of binary operators); "q" is the right-hand operand of binary operators
-.
-"ZERO" means "a zero-length sequence" below.
+ When we get to the root of the tree, we use one of the longest of its
+ calculated "in" sequences as our answer. The sequence we find is returned in
+ d->must (where "d" is the single argument passed to "dfamust");
+ the length of the sequence is returned in d->mustn.
+
+ The sequences calculated for the various types of node (in pseudo ANSI c)
+ are shown below. "p" is the operand of unary operators (and the left-hand
+ operand of binary operators); "q" is the right-hand operand of binary
+ operators.
+
+ "ZERO" means "a zero-length sequence" below.
-Type left right is in
----- ---- ----- -- --
-char c # c # c # c # c
+ Type left right is in
+ ---- ---- ----- -- --
+ char c # c # c # c # c
-SET ZERO ZERO ZERO ZERO
+ CSET ZERO ZERO ZERO ZERO
-STAR ZERO ZERO ZERO ZERO
+ STAR ZERO ZERO ZERO ZERO
-QMARK ZERO ZERO ZERO ZERO
+ QMARK ZERO ZERO ZERO ZERO
-PLUS p->left p->right ZERO p->in
+ PLUS p->left p->right ZERO p->in
-CAT (p->is==ZERO)? (q->is==ZERO)? (p->is!=ZERO && p->in plus
- p->left : q->right : q->is!=ZERO) ? q->in plus
- p->is##q->left p->right##q->is p->is##q->is : p->right##q->left
- ZERO
+ CAT (p->is==ZERO)? (q->is==ZERO)? (p->is!=ZERO && p->in plus
+ p->left : q->right : q->is!=ZERO) ? q->in plus
+ p->is##q->left p->right##q->is p->is##q->is : p->right##q->left
+ ZERO
-OR longest common longest common (do p->is and substrings common to
- leading trailing q->is have same p->in and q->in
- (sub)sequence (sub)sequence length and
- of p->left of p->right content) ?
- and q->left and q->right p->is : NULL
+ OR longest common longest common (do p->is and substrings common to
+ leading trailing q->is have same p->in and q->in
+ (sub)sequence (sub)sequence length and
+ of p->left of p->right content) ?
+ and q->left and q->right p->is : NULL
-If there's anything else we recognize in the tree, all four sequences get set
-to zero-length sequences. If there's something we don't recognize in the tree,
-we just return a zero-length sequence.
+ If there's anything else we recognize in the tree, all four sequences get set
+ to zero-length sequences. If there's something we don't recognize in the tree,
+ we just return a zero-length sequence.
-Break ties in favor of infrequent letters (choosing 'zzz' in preference to
-'aaa')?
+ Break ties in favor of infrequent letters (choosing 'zzz' in preference to
+ 'aaa')?
-And. . .is it here or someplace that we might ponder "optimizations" such as
+ And. . .is it here or someplace that we might ponder "optimizations" such as
egrep 'psi|epsilon' -> egrep 'psi'
egrep 'pepsi|epsilon' -> egrep 'epsi'
(Yes, we now find "epsi" as a "string
that must occur", but we might also
- simplify the *entire* r.e. being sought
-)
+ simplify the *entire* r.e. being sought)
grep '[c]' -> grep 'c'
grep '(ab|a)b' -> grep 'ab'
grep 'ab*' -> grep 'a'
grep 'a*b' -> grep 'b'
-There are several issues:
- Is optimization easy (enough)?
- Does optimization actually accomplish anything,
- or is the automaton you get from "psi|epsilon" (for example)
- the same as the one you get from "psi" (for example)?
+ There are several issues:
- Are optimizable r.e.'s likely to be used in real-life situations
- (something like 'ab*' is probably unlikely; something like is
- 'psi|epsilon' is likelier)?
-*/
+ Is optimization easy (enough)?
+
+ Does optimization actually accomplish anything,
+ or is the automaton you get from "psi|epsilon" (for example)
+ the same as the one you get from "psi" (for example)?
+
+ Are optimizable r.e.'s likely to be used in real-life situations
+ (something like 'ab*' is probably unlikely; something like is
+ 'psi|epsilon' is likelier)? */
static char *
icatalloc(old, new)
-char * old;
-const char * new;
+ char *old;
+ char *new;
{
- register char * result;
- register int oldsize, newsize;
-
- newsize = (new == NULL) ? 0 : strlen(new);
- if (old == NULL)
- oldsize = 0;
- else if (newsize == 0)
- return old;
- else oldsize = strlen(old);
- if (old == NULL)
- result = (char *) malloc(newsize + 1);
- else result = (char *) realloc((void *) old, oldsize + newsize + 1);
- if (result != NULL && new != NULL)
- (void) strcpy(result + oldsize, new);
- return result;
+ char *result;
+ size_t oldsize, newsize;
+
+ newsize = (new == NULL) ? 0 : strlen(new);
+ if (old == NULL)
+ oldsize = 0;
+ else if (newsize == 0)
+ return old;
+ else oldsize = strlen(old);
+ if (old == NULL)
+ result = (char *) malloc(newsize + 1);
+ else
+ result = (char *) realloc((void *) old, oldsize + newsize + 1);
+ if (result != NULL && new != NULL)
+ (void) strcpy(result + oldsize, new);
+ return result;
}
static char *
icpyalloc(string)
-const char * string;
+ char *string;
{
- return icatalloc((char *) NULL, string);
+ return icatalloc((char *) NULL, string);
}
static char *
istrstr(lookin, lookfor)
-char * lookin;
-register char * lookfor;
+ char *lookin;
+ char *lookfor;
{
- register char * cp;
- register int len;
-
- len = strlen(lookfor);
- for (cp = lookin; *cp != '\0'; ++cp)
- if (strncmp(cp, lookfor, len) == 0)
- return cp;
- return NULL;
+ char *cp;
+ size_t len;
+
+ len = strlen(lookfor);
+ for (cp = lookin; *cp != '\0'; ++cp)
+ if (strncmp(cp, lookfor, len) == 0)
+ return cp;
+ return NULL;
}
static void
ifree(cp)
-char * cp;
+ char *cp;
{
- if (cp != NULL)
- free(cp);
+ if (cp != NULL)
+ free(cp);
}
static void
freelist(cpp)
-register char ** cpp;
+ char **cpp;
{
- register int i;
+ int i;
- if (cpp == NULL)
- return;
- for (i = 0; cpp[i] != NULL; ++i) {
- free(cpp[i]);
- cpp[i] = NULL;
- }
+ if (cpp == NULL)
+ return;
+ for (i = 0; cpp[i] != NULL; ++i)
+ {
+ free(cpp[i]);
+ cpp[i] = NULL;
+ }
}
static char **
enlist(cpp, new, len)
-register char ** cpp;
-register char * new;
-#ifdef __STDC__
-size_t len;
-#else
-int len;
-#endif
+ char **cpp;
+ char *new;
+ size_t len;
{
- register int i, j;
+ int i, j;
- if (cpp == NULL)
- return NULL;
- if ((new = icpyalloc(new)) == NULL) {
- freelist(cpp);
- return NULL;
- }
- new[len] = '\0';
- /*
- ** Is there already something in the list that's new (or longer)?
- */
- for (i = 0; cpp[i] != NULL; ++i)
- if (istrstr(cpp[i], new) != NULL) {
- free(new);
- return cpp;
- }
- /*
- ** Eliminate any obsoleted strings.
- */
- j = 0;
- while (cpp[j] != NULL)
- if (istrstr(new, cpp[j]) == NULL)
- ++j;
- else {
- free(cpp[j]);
- if (--i == j)
- break;
- cpp[j] = cpp[i];
- }
- /*
- ** Add the new string.
- */
- cpp = (char **) realloc((char *) cpp, (i + 2) * sizeof *cpp);
- if (cpp == NULL)
- return NULL;
- cpp[i] = new;
- cpp[i + 1] = NULL;
+ if (cpp == NULL)
+ return NULL;
+ if ((new = icpyalloc(new)) == NULL)
+ {
+ freelist(cpp);
+ return NULL;
+ }
+ new[len] = '\0';
+ /* Is there already something in the list that's new (or longer)? */
+ for (i = 0; cpp[i] != NULL; ++i)
+ if (istrstr(cpp[i], new) != NULL)
+ {
+ free(new);
return cpp;
+ }
+ /* Eliminate any obsoleted strings. */
+ j = 0;
+ while (cpp[j] != NULL)
+ if (istrstr(new, cpp[j]) == NULL)
+ ++j;
+ else
+ {
+ free(cpp[j]);
+ if (--i == j)
+ break;
+ cpp[j] = cpp[i];
+ cpp[i] = NULL;
+ }
+ /* Add the new string. */
+ cpp = (char **) realloc((char *) cpp, (i + 2) * sizeof *cpp);
+ if (cpp == NULL)
+ return NULL;
+ cpp[i] = new;
+ cpp[i + 1] = NULL;
+ return cpp;
}
-/*
-** Given pointers to two strings,
-** return a pointer to an allocated list of their distinct common substrings.
-** Return NULL if something seems wild.
-*/
-
+/* Given pointers to two strings, return a pointer to an allocated
+ list of their distinct common substrings. Return NULL if something
+ seems wild. */
static char **
comsubs(left, right)
-char * left;
-char * right;
+ char *left;
+ char *right;
{
- register char ** cpp;
- register char * lcp;
- register char * rcp;
- register int i, len;
-
- if (left == NULL || right == NULL)
- return NULL;
- cpp = (char **) malloc(sizeof *cpp);
- if (cpp == NULL)
- return NULL;
- cpp[0] = NULL;
- for (lcp = left; *lcp != '\0'; ++lcp) {
- len = 0;
- rcp = strchr(right, *lcp);
- while (rcp != NULL) {
- for (i = 1; lcp[i] != '\0' && lcp[i] == rcp[i]; ++i)
- ;
- if (i > len)
- len = i;
- rcp = strchr(rcp + 1, *lcp);
- }
- if (len == 0)
- continue;
-#ifdef __STDC__
- if ((cpp = enlist(cpp, lcp, (size_t)len)) == NULL)
-#else
- if ((cpp = enlist(cpp, lcp, len)) == NULL)
-#endif
- break;
+ char **cpp;
+ char *lcp;
+ char *rcp;
+ size_t i, len;
+
+ if (left == NULL || right == NULL)
+ return NULL;
+ cpp = (char **) malloc(sizeof *cpp);
+ if (cpp == NULL)
+ return NULL;
+ cpp[0] = NULL;
+ for (lcp = left; *lcp != '\0'; ++lcp)
+ {
+ len = 0;
+ rcp = index(right, *lcp);
+ while (rcp != NULL)
+ {
+ for (i = 1; lcp[i] != '\0' && lcp[i] == rcp[i]; ++i)
+ continue;
+ if (i > len)
+ len = i;
+ rcp = index(rcp + 1, *lcp);
}
- return cpp;
+ if (len == 0)
+ continue;
+ if ((cpp = enlist(cpp, lcp, len)) == NULL)
+ break;
+ }
+ return cpp;
}
static char **
addlists(old, new)
-char ** old;
-char ** new;
+char **old;
+char **new;
{
- register int i;
-
- if (old == NULL || new == NULL)
- return NULL;
- for (i = 0; new[i] != NULL; ++i) {
- old = enlist(old, new[i], strlen(new[i]));
- if (old == NULL)
- break;
- }
- return old;
-}
+ int i;
-/*
-** Given two lists of substrings,
-** return a new list giving substrings common to both.
-*/
+ if (old == NULL || new == NULL)
+ return NULL;
+ for (i = 0; new[i] != NULL; ++i)
+ {
+ old = enlist(old, new[i], strlen(new[i]));
+ if (old == NULL)
+ break;
+ }
+ return old;
+}
+/* Given two lists of substrings, return a new list giving substrings
+ common to both. */
static char **
inboth(left, right)
-char ** left;
-char ** right;
+ char **left;
+ char **right;
{
- register char ** both;
- register char ** temp;
- register int lnum, rnum;
-
- if (left == NULL || right == NULL)
- return NULL;
- both = (char **) malloc(sizeof *both);
- if (both == NULL)
- return NULL;
- both[0] = NULL;
- for (lnum = 0; left[lnum] != NULL; ++lnum) {
- for (rnum = 0; right[rnum] != NULL; ++rnum) {
- temp = comsubs(left[lnum], right[rnum]);
- if (temp == NULL) {
- freelist(both);
- return NULL;
- }
- both = addlists(both, temp);
- freelist(temp);
- if (both == NULL)
- return NULL;
- }
+ char **both;
+ char **temp;
+ int lnum, rnum;
+
+ if (left == NULL || right == NULL)
+ return NULL;
+ both = (char **) malloc(sizeof *both);
+ if (both == NULL)
+ return NULL;
+ both[0] = NULL;
+ for (lnum = 0; left[lnum] != NULL; ++lnum)
+ {
+ for (rnum = 0; right[rnum] != NULL; ++rnum)
+ {
+ temp = comsubs(left[lnum], right[rnum]);
+ if (temp == NULL)
+ {
+ freelist(both);
+ return NULL;
+ }
+ both = addlists(both, temp);
+ freelist(temp);
+ if (both == NULL)
+ return NULL;
}
- return both;
+ }
+ return both;
}
-/*
-typedef struct {
- char ** in;
- char * left;
- char * right;
- char * is;
+typedef struct
+{
+ char **in;
+ char *left;
+ char *right;
+ char *is;
} must;
- */
+
static void
resetmust(mp)
-register must * mp;
+must *mp;
{
- mp->left[0] = mp->right[0] = mp->is[0] = '\0';
- freelist(mp->in);
+ mp->left[0] = mp->right[0] = mp->is[0] = '\0';
+ freelist(mp->in);
}
static void
-regmust(r)
-register struct regexp * r;
+dfamust(dfa)
+struct dfa *dfa;
{
- register must * musts;
- register must * mp;
- register char * result = "";
- register int ri;
- register int i;
- register _token t;
- static must must0;
-
- reg->mustn = 0;
- reg->must[0] = '\0';
- musts = (must *) malloc((reg->tindex + 1) * sizeof *musts);
- if (musts == NULL)
- return;
- mp = musts;
- for (i = 0; i <= reg->tindex; ++i)
- mp[i] = must0;
- for (i = 0; i <= reg->tindex; ++i) {
- mp[i].in = (char **) malloc(sizeof *mp[i].in);
- mp[i].left = malloc(2);
- mp[i].right = malloc(2);
- mp[i].is = malloc(2);
- if (mp[i].in == NULL || mp[i].left == NULL ||
- mp[i].right == NULL || mp[i].is == NULL)
- goto done;
- mp[i].left[0] = mp[i].right[0] = mp[i].is[0] = '\0';
- mp[i].in[0] = NULL;
- }
- for (ri = 0; ri < reg->tindex; ++ri) {
- switch (t = reg->tokens[ri]) {
- case _ALLBEGLINE:
- case _ALLENDLINE:
- case _LPAREN:
- case _RPAREN:
- goto done; /* "cannot happen" */
- case _EMPTY:
- case _BEGLINE:
- case _ENDLINE:
- case _BEGWORD:
- case _ENDWORD:
- case _LIMWORD:
- case _NOTLIMWORD:
- case _BACKREF:
- resetmust(mp);
- break;
- case _STAR:
- case _QMARK:
- if (mp <= musts)
- goto done; /* "cannot happen" */
- --mp;
- resetmust(mp);
- break;
- case _OR:
- if (mp < &musts[2])
- goto done; /* "cannot happen" */
- {
- register char ** new;
- register must * lmp;
- register must * rmp;
- register int j, ln, rn, n;
-
- rmp = --mp;
- lmp = --mp;
- /* Guaranteed to be. Unlikely, but. . . */
- if (strcmp(lmp->is, rmp->is) != 0)
- lmp->is[0] = '\0';
- /* Left side--easy */
- i = 0;
- while (lmp->left[i] != '\0' &&
- lmp->left[i] == rmp->left[i])
- ++i;
- lmp->left[i] = '\0';
- /* Right side */
- ln = strlen(lmp->right);
- rn = strlen(rmp->right);
- n = ln;
- if (n > rn)
- n = rn;
- for (i = 0; i < n; ++i)
- if (lmp->right[ln - i - 1] !=
- rmp->right[rn - i - 1])
- break;
- for (j = 0; j < i; ++j)
- lmp->right[j] =
- lmp->right[(ln - i) + j];
- lmp->right[j] = '\0';
- new = inboth(lmp->in, rmp->in);
- if (new == NULL)
- goto done;
- freelist(lmp->in);
- free((char *) lmp->in);
- lmp->in = new;
- }
- break;
- case _PLUS:
- if (mp <= musts)
- goto done; /* "cannot happen" */
- --mp;
- mp->is[0] = '\0';
- break;
- case _END:
- if (mp != &musts[1])
- goto done; /* "cannot happen" */
- for (i = 0; musts[0].in[i] != NULL; ++i)
- if (strlen(musts[0].in[i]) > strlen(result))
- result = musts[0].in[i];
- goto done;
- case _CAT:
- if (mp < &musts[2])
- goto done; /* "cannot happen" */
- {
- register must * lmp;
- register must * rmp;
-
- rmp = --mp;
- lmp = --mp;
- /*
- ** In. Everything in left, plus everything in
- ** right, plus catenation of
- ** left's right and right's left.
- */
- lmp->in = addlists(lmp->in, rmp->in);
- if (lmp->in == NULL)
- goto done;
- if (lmp->right[0] != '\0' &&
- rmp->left[0] != '\0') {
- register char * tp;
-
- tp = icpyalloc(lmp->right);
- if (tp == NULL)
- goto done;
- tp = icatalloc(tp, rmp->left);
- if (tp == NULL)
- goto done;
- lmp->in = enlist(lmp->in, tp,
- strlen(tp));
- free(tp);
- if (lmp->in == NULL)
- goto done;
- }
- /* Left-hand */
- if (lmp->is[0] != '\0') {
- lmp->left = icatalloc(lmp->left,
- rmp->left);
- if (lmp->left == NULL)
- goto done;
- }
- /* Right-hand */
- if (rmp->is[0] == '\0')
- lmp->right[0] = '\0';
- lmp->right = icatalloc(lmp->right, rmp->right);
- if (lmp->right == NULL)
- goto done;
- /* Guaranteed to be */
- if (lmp->is[0] != '\0' && rmp->is[0] != '\0') {
- lmp->is = icatalloc(lmp->is, rmp->is);
- if (lmp->is == NULL)
- goto done;
- }
- }
- break;
- default:
- if (t < _END) {
- /* "cannot happen" */
- goto done;
- } else if (t == '\0') {
- /* not on *my* shift */
- goto done;
- } else if (t >= _SET) {
- /* easy enough */
- resetmust(mp);
- } else {
- /* plain character */
- resetmust(mp);
- mp->is[0] = mp->left[0] = mp->right[0] = t;
- mp->is[1] = mp->left[1] = mp->right[1] = '\0';
- mp->in = enlist(mp->in, mp->is, 1);
- if (mp->in == NULL)
- goto done;
- }
- break;
- }
- ++mp;
- }
-done:
- (void) strncpy(reg->must, result, MUST_MAX - 1);
- reg->must[MUST_MAX - 1] = '\0';
- reg->mustn = strlen(reg->must);
- mp = musts;
- for (i = 0; i <= reg->tindex; ++i) {
- freelist(mp[i].in);
- ifree((char *) mp[i].in);
- ifree(mp[i].left);
- ifree(mp[i].right);
- ifree(mp[i].is);
+ must *musts;
+ must *mp;
+ char *result;
+ int ri;
+ int i;
+ int exact;
+ token t;
+ static must must0;
+ struct dfamust *dm;
+ static char empty_string[] = "";
+
+ result = empty_string;
+ exact = 0;
+ musts = (must *) malloc((dfa->tindex + 1) * sizeof *musts);
+ if (musts == NULL)
+ return;
+ mp = musts;
+ for (i = 0; i <= dfa->tindex; ++i)
+ mp[i] = must0;
+ for (i = 0; i <= dfa->tindex; ++i)
+ {
+ mp[i].in = (char **) malloc(sizeof *mp[i].in);
+ mp[i].left = malloc(2);
+ mp[i].right = malloc(2);
+ mp[i].is = malloc(2);
+ if (mp[i].in == NULL || mp[i].left == NULL ||
+ mp[i].right == NULL || mp[i].is == NULL)
+ goto done;
+ mp[i].left[0] = mp[i].right[0] = mp[i].is[0] = '\0';
+ mp[i].in[0] = NULL;
+ }
+#ifdef DEBUG
+ fprintf(stderr, "dfamust:\n");
+ for (i = 0; i < dfa->tindex; ++i)
+ {
+ fprintf(stderr, " %d:", i);
+ prtok(dfa->tokens[i]);
+ }
+ putc('\n', stderr);
+#endif
+ for (ri = 0; ri < dfa->tindex; ++ri)
+ {
+ switch (t = dfa->tokens[ri])
+ {
+ case LPAREN:
+ case RPAREN:
+ goto done; /* "cannot happen" */
+ case EMPTY:
+ case BEGLINE:
+ case ENDLINE:
+ case BEGWORD:
+ case ENDWORD:
+ case LIMWORD:
+ case NOTLIMWORD:
+ case BACKREF:
+ resetmust(mp);
+ break;
+ case STAR:
+ case QMARK:
+ if (mp <= musts)
+ goto done; /* "cannot happen" */
+ --mp;
+ resetmust(mp);
+ break;
+ case OR:
+ case ORTOP:
+ if (mp < &musts[2])
+ goto done; /* "cannot happen" */
+ {
+ char **new;
+ must *lmp;
+ must *rmp;
+ int j, ln, rn, n;
+
+ rmp = --mp;
+ lmp = --mp;
+ /* Guaranteed to be. Unlikely, but. . . */
+ if (strcmp(lmp->is, rmp->is) != 0)
+ lmp->is[0] = '\0';
+ /* Left side--easy */
+ i = 0;
+ while (lmp->left[i] != '\0' && lmp->left[i] == rmp->left[i])
+ ++i;
+ lmp->left[i] = '\0';
+ /* Right side */
+ ln = strlen(lmp->right);
+ rn = strlen(rmp->right);
+ n = ln;
+ if (n > rn)
+ n = rn;
+ for (i = 0; i < n; ++i)
+ if (lmp->right[ln - i - 1] != rmp->right[rn - i - 1])
+ break;
+ for (j = 0; j < i; ++j)
+ lmp->right[j] = lmp->right[(ln - i) + j];
+ lmp->right[j] = '\0';
+ new = inboth(lmp->in, rmp->in);
+ if (new == NULL)
+ goto done;
+ freelist(lmp->in);
+ free((char *) lmp->in);
+ lmp->in = new;
+ }
+ break;
+ case PLUS:
+ if (mp <= musts)
+ goto done; /* "cannot happen" */
+ --mp;
+ mp->is[0] = '\0';
+ break;
+ case END:
+ if (mp != &musts[1])
+ goto done; /* "cannot happen" */
+ for (i = 0; musts[0].in[i] != NULL; ++i)
+ if (strlen(musts[0].in[i]) > strlen(result))
+ result = musts[0].in[i];
+ if (strcmp(result, musts[0].is) == 0)
+ exact = 1;
+ goto done;
+ case CAT:
+ if (mp < &musts[2])
+ goto done; /* "cannot happen" */
+ {
+ must *lmp;
+ must *rmp;
+
+ rmp = --mp;
+ lmp = --mp;
+ /* In. Everything in left, plus everything in
+ right, plus catenation of
+ left's right and right's left. */
+ lmp->in = addlists(lmp->in, rmp->in);
+ if (lmp->in == NULL)
+ goto done;
+ if (lmp->right[0] != '\0' &&
+ rmp->left[0] != '\0')
+ {
+ char *tp;
+
+ tp = icpyalloc(lmp->right);
+ if (tp == NULL)
+ goto done;
+ tp = icatalloc(tp, rmp->left);
+ if (tp == NULL)
+ goto done;
+ lmp->in = enlist(lmp->in, tp,
+ strlen(tp));
+ free(tp);
+ if (lmp->in == NULL)
+ goto done;
+ }
+ /* Left-hand */
+ if (lmp->is[0] != '\0')
+ {
+ lmp->left = icatalloc(lmp->left,
+ rmp->left);
+ if (lmp->left == NULL)
+ goto done;
+ }
+ /* Right-hand */
+ if (rmp->is[0] == '\0')
+ lmp->right[0] = '\0';
+ lmp->right = icatalloc(lmp->right, rmp->right);
+ if (lmp->right == NULL)
+ goto done;
+ /* Guaranteed to be */
+ if (lmp->is[0] != '\0' && rmp->is[0] != '\0')
+ {
+ lmp->is = icatalloc(lmp->is, rmp->is);
+ if (lmp->is == NULL)
+ goto done;
+ }
+ else
+ lmp->is[0] = '\0';
+ }
+ break;
+ default:
+ if (t < END)
+ {
+ /* "cannot happen" */
+ goto done;
+ }
+ else if (t == '\0')
+ {
+ /* not on *my* shift */
+ goto done;
+ }
+ else if (t >= CSET)
+ {
+ /* easy enough */
+ resetmust(mp);
+ }
+ else
+ {
+ /* plain character */
+ resetmust(mp);
+ mp->is[0] = mp->left[0] = mp->right[0] = t;
+ mp->is[1] = mp->left[1] = mp->right[1] = '\0';
+ mp->in = enlist(mp->in, mp->is, (size_t)1);
+ if (mp->in == NULL)
+ goto done;
+ }
+ break;
}
- free((char *) mp);
+#ifdef DEBUG
+ fprintf(stderr, " node: %d:", ri);
+ prtok(dfa->tokens[ri]);
+ fprintf(stderr, "\n in:");
+ for (i = 0; mp->in[i]; ++i)
+ fprintf(stderr, " \"%s\"", mp->in[i]);
+ fprintf(stderr, "\n is: \"%s\"\n", mp->is);
+ fprintf(stderr, " left: \"%s\"\n", mp->left);
+ fprintf(stderr, " right: \"%s\"\n", mp->right);
+#endif
+ ++mp;
+ }
+ done:
+ if (strlen(result))
+ {
+ dm = (struct dfamust *) malloc(sizeof (struct dfamust));
+ dm->exact = exact;
+ dm->must = malloc(strlen(result) + 1);
+ strcpy(dm->must, result);
+ dm->next = dfa->musts;
+ dfa->musts = dm;
+ }
+ mp = musts;
+ for (i = 0; i <= dfa->tindex; ++i)
+ {
+ freelist(mp[i].in);
+ ifree((char *) mp[i].in);
+ ifree(mp[i].left);
+ ifree(mp[i].right);
+ ifree(mp[i].is);
+ }
+ free((char *) mp);
}
diff --git a/gnu/usr.bin/awk/dfa.h b/gnu/usr.bin/awk/dfa.h
index 65fc495..cc27d7a 100644
--- a/gnu/usr.bin/awk/dfa.h
+++ b/gnu/usr.bin/awk/dfa.h
@@ -1,318 +1,130 @@
/* dfa.h - declarations for GNU deterministic regexp compiler
Copyright (C) 1988 Free Software Foundation, Inc.
- Written June, 1988 by Mike Haertel
-
- NO WARRANTY
-
- BECAUSE THIS PROGRAM IS LICENSED FREE OF CHARGE, WE PROVIDE ABSOLUTELY
-NO WARRANTY, TO THE EXTENT PERMITTED BY APPLICABLE STATE LAW. EXCEPT
-WHEN OTHERWISE STATED IN WRITING, FREE SOFTWARE FOUNDATION, INC,
-RICHARD M. STALLMAN AND/OR OTHER PARTIES PROVIDE THIS PROGRAM "AS IS"
-WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
-BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
-FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY
-AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE
-DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR
-CORRECTION.
-
- IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW WILL RICHARD M.
-STALLMAN, THE FREE SOFTWARE FOUNDATION, INC., AND/OR ANY OTHER PARTY
-WHO MAY MODIFY AND REDISTRIBUTE THIS PROGRAM AS PERMITTED BELOW, BE
-LIABLE TO YOU FOR DAMAGES, INCLUDING ANY LOST PROFITS, LOST MONIES, OR
-OTHER SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
-USE OR INABILITY TO USE (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR
-DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY THIRD PARTIES OR
-A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS) THIS
-PROGRAM, EVEN IF YOU HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH
-DAMAGES, OR FOR ANY CLAIM BY ANY OTHER PARTY.
-
- GENERAL PUBLIC LICENSE TO COPY
-
- 1. You may copy and distribute verbatim copies of this source file
-as you receive it, in any medium, provided that you conspicuously and
-appropriately publish on each copy a valid copyright notice "Copyright
- (C) 1988 Free Software Foundation, Inc."; and include following the
-copyright notice a verbatim copy of the above disclaimer of warranty
-and of this License. You may charge a distribution fee for the
-physical act of transferring a copy.
-
- 2. You may modify your copy or copies of this source file or
-any portion of it, and copy and distribute such modifications under
-the terms of Paragraph 1 above, provided that you also do the following:
-
- a) cause the modified files to carry prominent notices stating
- that you changed the files and the date of any change; and
-
- b) cause the whole of any work that you distribute or publish,
- that in whole or in part contains or is a derivative of this
- program or any part thereof, to be licensed at no charge to all
- third parties on terms identical to those contained in this
- License Agreement (except that you may choose to grant more extensive
- warranty protection to some or all third parties, at your option).
-
- c) You may charge a distribution fee for the physical act of
- transferring a copy, and you may at your option offer warranty
- protection in exchange for a fee.
-
-Mere aggregation of another unrelated program with this program (or its
-derivative) on a volume of a storage or distribution medium does not bring
-the other program under the scope of these terms.
-
- 3. You may copy and distribute this program or any portion of it in
-compiled, executable or object code form under the terms of Paragraphs
-1 and 2 above provided that you do the following:
-
- a) accompany it with the complete corresponding machine-readable
- source code, which must be distributed under the terms of
- Paragraphs 1 and 2 above; or,
-
- b) accompany it with a written offer, valid for at least three
- years, to give any third party free (except for a nominal
- shipping charge) a complete machine-readable copy of the
- corresponding source code, to be distributed under the terms of
- Paragraphs 1 and 2 above; or,
-
- c) accompany it with the information you received as to where the
- corresponding source code may be obtained. (This alternative is
- allowed only for noncommercial distribution and only if you
- received the program in object code or executable form alone.)
-
-For an executable file, complete source code means all the source code for
-all modules it contains; but, as a special exception, it need not include
-source code for modules which are standard libraries that accompany the
-operating system on which the executable file runs.
-
- 4. You may not copy, sublicense, distribute or transfer this program
-except as expressly provided under this License Agreement. Any attempt
-otherwise to copy, sublicense, distribute or transfer this program is void and
-your rights to use the program under this License agreement shall be
-automatically terminated. However, parties who have received computer
-software programs from you with this License Agreement will not have
-their licenses terminated so long as such parties remain in full compliance.
-
- 5. If you wish to incorporate parts of this program into other free
-programs whose distribution conditions are different, write to the Free
-Software Foundation at 675 Mass Ave, Cambridge, MA 02139. We have not yet
-worked out a simple rule that can be stated here, but we will often permit
-this. We will be guided by the two goals of preserving the free status of
-all derivatives our free software and of promoting the sharing and reuse of
-software.
-
-
-In other words, you are welcome to use, share and improve this program.
-You are forbidden to forbid anyone else to use, share and improve
-what you give them. Help stamp out software-hoarding! */
-
-#ifdef __STDC__
-#ifdef SOMEDAY
-#define ISALNUM(c) isalnum(c)
-#define ISALPHA(c) isalpha(c)
-#define ISUPPER(c) isupper(c)
-#else
-#define ISALNUM(c) (isascii(c) && isalnum(c))
-#define ISALPHA(c) (isascii(c) && isalpha(c))
-#define ISUPPER(c) (isascii(c) && isupper(c))
-#endif
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
-#else /* ! __STDC__ */
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
-#define const
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
-#define ISALNUM(c) (isascii(c) && isalnum(c))
-#define ISALPHA(c) (isascii(c) && isalpha(c))
-#define ISUPPER(c) (isascii(c) && isupper(c))
+/* Written June, 1988 by Mike Haertel */
-#endif /* ! __STDC__ */
-
-/* 1 means plain parentheses serve as grouping, and backslash
- parentheses are needed for literal searching.
- 0 means backslash-parentheses are grouping, and plain parentheses
- are for literal searching. */
-#define RE_NO_BK_PARENS 1L
-
-/* 1 means plain | serves as the "or"-operator, and \| is a literal.
- 0 means \| serves as the "or"-operator, and | is a literal. */
-#define RE_NO_BK_VBAR (1L << 1)
-
-/* 0 means plain + or ? serves as an operator, and \+, \? are literals.
- 1 means \+, \? are operators and plain +, ? are literals. */
-#define RE_BK_PLUS_QM (1L << 2)
-
-/* 1 means | binds tighter than ^ or $.
- 0 means the contrary. */
-#define RE_TIGHT_VBAR (1L << 3)
-
-/* 1 means treat \n as an _OR operator
- 0 means treat it as a normal character */
-#define RE_NEWLINE_OR (1L << 4)
-
-/* 0 means that a special characters (such as *, ^, and $) always have
- their special meaning regardless of the surrounding context.
- 1 means that special characters may act as normal characters in some
- contexts. Specifically, this applies to:
- ^ - only special at the beginning, or after ( or |
- $ - only special at the end, or before ) or |
- *, +, ? - only special when not after the beginning, (, or | */
-#define RE_CONTEXT_INDEP_OPS (1L << 5)
-
-/* 1 means that \ in a character class escapes the next character (typically
- a hyphen. It also is overloaded to mean that hyphen at the end of the range
- is allowable and means that the hyphen is to be taken literally. */
-#define RE_AWK_CLASS_HACK (1L << 6)
-
-/* Now define combinations of bits for the standard possibilities. */
-#ifdef notdef
-#define RE_SYNTAX_AWK (RE_NO_BK_PARENS | RE_NO_BK_VBAR | RE_CONTEXT_INDEP_OPS)
-#define RE_SYNTAX_EGREP (RE_SYNTAX_AWK | RE_NEWLINE_OR)
-#define RE_SYNTAX_GREP (RE_BK_PLUS_QM | RE_NEWLINE_OR)
-#define RE_SYNTAX_EMACS 0
-#endif
-
-/* The NULL pointer. */
-#ifndef NULL
-#define NULL 0
-#endif
+/* FIXME:
+ 2. We should not export so much of the DFA internals.
+ In addition to clobbering modularity, we eat up valuable
+ name space. */
/* Number of bits in an unsigned char. */
-#ifndef CHARBITS
#define CHARBITS 8
-#endif
/* First integer value that is greater than any character code. */
-#define _NOTCHAR (1 << CHARBITS)
+#define NOTCHAR (1 << CHARBITS)
/* INTBITS need not be exact, just a lower bound. */
-#ifndef INTBITS
#define INTBITS (CHARBITS * sizeof (int))
-#endif
/* Number of ints required to hold a bit for every character. */
-#define _CHARSET_INTS ((_NOTCHAR + INTBITS - 1) / INTBITS)
+#define CHARCLASS_INTS ((NOTCHAR + INTBITS - 1) / INTBITS)
/* Sets of unsigned characters are stored as bit vectors in arrays of ints. */
-typedef int _charset[_CHARSET_INTS];
+typedef int charclass[CHARCLASS_INTS];
/* The regexp is parsed into an array of tokens in postfix form. Some tokens
are operators and others are terminal symbols. Most (but not all) of these
codes are returned by the lexical analyzer. */
-#ifdef __STDC__
typedef enum
{
- _END = -1, /* _END is a terminal symbol that matches the
- end of input; any value of _END or less in
+ END = -1, /* END is a terminal symbol that matches the
+ end of input; any value of END or less in
the parse tree is such a symbol. Accepting
states of the DFA are those that would have
- a transition on _END. */
+ a transition on END. */
/* Ordinary character values are terminal symbols that match themselves. */
- _EMPTY = _NOTCHAR, /* _EMPTY is a terminal symbol that matches
+ EMPTY = NOTCHAR, /* EMPTY is a terminal symbol that matches
the empty string. */
- _BACKREF, /* _BACKREF is generated by \<digit>; it
+ BACKREF, /* BACKREF is generated by \<digit>; it
it not completely handled. If the scanner
detects a transition on backref, it returns
a kind of "semi-success" indicating that
the match will have to be verified with
a backtracking matcher. */
- _BEGLINE, /* _BEGLINE is a terminal symbol that matches
+ BEGLINE, /* BEGLINE is a terminal symbol that matches
the empty string if it is at the beginning
of a line. */
- _ALLBEGLINE, /* _ALLBEGLINE is a terminal symbol that
- matches the empty string if it is at the
- beginning of a line; _ALLBEGLINE applies
- to the entire regexp and can only occur
- as the first token thereof. _ALLBEGLINE
- never appears in the parse tree; a _BEGLINE
- is prepended with _CAT to the entire
- regexp instead. */
-
- _ENDLINE, /* _ENDLINE is a terminal symbol that matches
+ ENDLINE, /* ENDLINE is a terminal symbol that matches
the empty string if it is at the end of
a line. */
- _ALLENDLINE, /* _ALLENDLINE is to _ENDLINE as _ALLBEGLINE
- is to _BEGLINE. */
-
- _BEGWORD, /* _BEGWORD is a terminal symbol that matches
+ BEGWORD, /* BEGWORD is a terminal symbol that matches
the empty string if it is at the beginning
of a word. */
- _ENDWORD, /* _ENDWORD is a terminal symbol that matches
+ ENDWORD, /* ENDWORD is a terminal symbol that matches
the empty string if it is at the end of
a word. */
- _LIMWORD, /* _LIMWORD is a terminal symbol that matches
+ LIMWORD, /* LIMWORD is a terminal symbol that matches
the empty string if it is at the beginning
or the end of a word. */
- _NOTLIMWORD, /* _NOTLIMWORD is a terminal symbol that
+ NOTLIMWORD, /* NOTLIMWORD is a terminal symbol that
matches the empty string if it is not at
the beginning or end of a word. */
- _QMARK, /* _QMARK is an operator of one argument that
+ QMARK, /* QMARK is an operator of one argument that
matches zero or one occurences of its
argument. */
- _STAR, /* _STAR is an operator of one argument that
+ STAR, /* STAR is an operator of one argument that
matches the Kleene closure (zero or more
occurrences) of its argument. */
- _PLUS, /* _PLUS is an operator of one argument that
+ PLUS, /* PLUS is an operator of one argument that
matches the positive closure (one or more
occurrences) of its argument. */
- _CAT, /* _CAT is an operator of two arguments that
+ REPMN, /* REPMN is a lexical token corresponding
+ to the {m,n} construct. REPMN never
+ appears in the compiled token vector. */
+
+ CAT, /* CAT is an operator of two arguments that
matches the concatenation of its
- arguments. _CAT is never returned by the
+ arguments. CAT is never returned by the
lexical analyzer. */
- _OR, /* _OR is an operator of two arguments that
+ OR, /* OR is an operator of two arguments that
matches either of its arguments. */
- _LPAREN, /* _LPAREN never appears in the parse tree,
+ ORTOP, /* OR at the toplevel in the parse tree.
+ This is used for a boyer-moore heuristic. */
+
+ LPAREN, /* LPAREN never appears in the parse tree,
it is only a lexeme. */
- _RPAREN, /* _RPAREN never appears in the parse tree. */
+ RPAREN, /* RPAREN never appears in the parse tree. */
- _SET /* _SET and (and any value greater) is a
+ CSET /* CSET and (and any value greater) is a
terminal symbol that matches any of a
class of characters. */
-} _token;
+} token;
-#else /* ! __STDC__ */
-
-typedef short _token;
-
-#define _END -1
-#define _EMPTY _NOTCHAR
-#define _BACKREF (_EMPTY + 1)
-#define _BEGLINE (_EMPTY + 2)
-#define _ALLBEGLINE (_EMPTY + 3)
-#define _ENDLINE (_EMPTY + 4)
-#define _ALLENDLINE (_EMPTY + 5)
-#define _BEGWORD (_EMPTY + 6)
-#define _ENDWORD (_EMPTY + 7)
-#define _LIMWORD (_EMPTY + 8)
-#define _NOTLIMWORD (_EMPTY + 9)
-#define _QMARK (_EMPTY + 10)
-#define _STAR (_EMPTY + 11)
-#define _PLUS (_EMPTY + 12)
-#define _CAT (_EMPTY + 13)
-#define _OR (_EMPTY + 14)
-#define _LPAREN (_EMPTY + 15)
-#define _RPAREN (_EMPTY + 16)
-#define _SET (_EMPTY + 17)
-
-#endif /* ! __STDC__ */
-
-/* Sets are stored in an array in the compiled regexp; the index of the
- array corresponding to a given set token is given by _SET_INDEX(t). */
-#define _SET_INDEX(t) ((t) - _SET)
+/* Sets are stored in an array in the compiled dfa; the index of the
+ array corresponding to a given set token is given by SET_INDEX(t). */
+#define SET_INDEX(t) ((t) - CSET)
/* Sometimes characters can only be matched depending on the surrounding
context. Such context decisions depend on what the previous character
@@ -332,36 +144,36 @@ typedef short _token;
Word-constituent characters are those that satisfy isalnum().
- The macro _SUCCEEDS_IN_CONTEXT determines whether a a given constraint
+ The macro SUCCEEDS_IN_CONTEXT determines whether a a given constraint
succeeds in a particular context. Prevn is true if the previous character
was a newline, currn is true if the lookahead character is a newline.
Prevl and currl similarly depend upon whether the previous and current
characters are word-constituent letters. */
-#define _MATCHES_NEWLINE_CONTEXT(constraint, prevn, currn) \
- ((constraint) & (1 << (((prevn) ? 2 : 0) + ((currn) ? 1 : 0) + 4)))
-#define _MATCHES_LETTER_CONTEXT(constraint, prevl, currl) \
- ((constraint) & (1 << (((prevl) ? 2 : 0) + ((currl) ? 1 : 0))))
-#define _SUCCEEDS_IN_CONTEXT(constraint, prevn, currn, prevl, currl) \
- (_MATCHES_NEWLINE_CONTEXT(constraint, prevn, currn) \
- && _MATCHES_LETTER_CONTEXT(constraint, prevl, currl))
+#define MATCHES_NEWLINE_CONTEXT(constraint, prevn, currn) \
+ ((constraint) & 1 << (((prevn) ? 2 : 0) + ((currn) ? 1 : 0) + 4))
+#define MATCHES_LETTER_CONTEXT(constraint, prevl, currl) \
+ ((constraint) & 1 << (((prevl) ? 2 : 0) + ((currl) ? 1 : 0)))
+#define SUCCEEDS_IN_CONTEXT(constraint, prevn, currn, prevl, currl) \
+ (MATCHES_NEWLINE_CONTEXT(constraint, prevn, currn) \
+ && MATCHES_LETTER_CONTEXT(constraint, prevl, currl))
/* The following macros give information about what a constraint depends on. */
-#define _PREV_NEWLINE_DEPENDENT(constraint) \
+#define PREV_NEWLINE_DEPENDENT(constraint) \
(((constraint) & 0xc0) >> 2 != ((constraint) & 0x30))
-#define _PREV_LETTER_DEPENDENT(constraint) \
+#define PREV_LETTER_DEPENDENT(constraint) \
(((constraint) & 0x0c) >> 2 != ((constraint) & 0x03))
/* Tokens that match the empty string subject to some constraint actually
work by applying that constraint to determine what may follow them,
taking into account what has gone before. The following values are
the constraints corresponding to the special tokens previously defined. */
-#define _NO_CONSTRAINT 0xff
-#define _BEGLINE_CONSTRAINT 0xcf
-#define _ENDLINE_CONSTRAINT 0xaf
-#define _BEGWORD_CONSTRAINT 0xf2
-#define _ENDWORD_CONSTRAINT 0xf4
-#define _LIMWORD_CONSTRAINT 0xf6
-#define _NOTLIMWORD_CONSTRAINT 0xf9
+#define NO_CONSTRAINT 0xff
+#define BEGLINE_CONSTRAINT 0xcf
+#define ENDLINE_CONSTRAINT 0xaf
+#define BEGWORD_CONSTRAINT 0xf2
+#define ENDWORD_CONSTRAINT 0xf4
+#define LIMWORD_CONSTRAINT 0xf6
+#define NOTLIMWORD_CONSTRAINT 0xf9
/* States of the recognizer correspond to sets of positions in the parse
tree, together with the constraints under which they may be matched.
@@ -371,44 +183,48 @@ typedef struct
{
unsigned index; /* Index into the parse array. */
unsigned constraint; /* Constraint for matching this position. */
-} _position;
+} position;
/* Sets of positions are stored as arrays. */
typedef struct
{
- _position *elems; /* Elements of this position set. */
+ position *elems; /* Elements of this position set. */
int nelem; /* Number of elements in this set. */
-} _position_set;
+} position_set;
-/* A state of the regexp consists of a set of positions, some flags,
+/* A state of the dfa consists of a set of positions, some flags,
and the token value of the lowest-numbered position of the state that
- contains an _END token. */
+ contains an END token. */
typedef struct
{
int hash; /* Hash of the positions of this state. */
- _position_set elems; /* Positions this state could match. */
+ position_set elems; /* Positions this state could match. */
char newline; /* True if previous state matched newline. */
char letter; /* True if previous state matched a letter. */
char backref; /* True if this state matches a \<digit>. */
unsigned char constraint; /* Constraint for this state to accept. */
- int first_end; /* Token value of the first _END in elems. */
-} _dfa_state;
+ int first_end; /* Token value of the first END in elems. */
+} dfa_state;
-/* If an r.e. is at most MUST_MAX characters long, we look for a string which
- must appear in it; whatever's found is dropped into the struct reg. */
-
-#define MUST_MAX 50
+/* Element of a list of strings, at least one of which is known to
+ appear in any R.E. matching the DFA. */
+struct dfamust
+{
+ int exact;
+ char *must;
+ struct dfamust *next;
+};
/* A compiled regular expression. */
-struct regexp
+struct dfa
{
/* Stuff built by the scanner. */
- _charset *charsets; /* Array of character sets for _SET tokens. */
- int cindex; /* Index for adding new charsets. */
- int calloc; /* Number of charsets currently allocated. */
+ charclass *charclasses; /* Array of character sets for CSET tokens. */
+ int cindex; /* Index for adding new charclasses. */
+ int calloc; /* Number of charclasses currently allocated. */
/* Stuff built by the parser. */
- _token *tokens; /* Postfix parse array. */
+ token *tokens; /* Postfix parse array. */
int tindex; /* Index for adding new tokens. */
int talloc; /* Number of tokens currently allocated. */
int depth; /* Depth required of an evaluation stack
@@ -416,15 +232,15 @@ struct regexp
parse tree. */
int nleaves; /* Number of leaves on the parse tree. */
int nregexps; /* Count of parallel regexps being built
- with regparse(). */
+ with dfaparse(). */
/* Stuff owned by the state builder. */
- _dfa_state *states; /* States of the regexp. */
+ dfa_state *states; /* States of the dfa. */
int sindex; /* Index for adding new states. */
int salloc; /* Number of states currently allocated. */
/* Stuff built by the structure analyzer. */
- _position_set *follows; /* Array of follow sets, indexed by position
+ position_set *follows; /* Array of follow sets, indexed by position
index. The follow of a position is the set
of positions containing characters that
could conceivably follow a character
@@ -454,7 +270,7 @@ struct regexp
int **fails; /* Transition tables after failing to accept
on a state that potentially could do so. */
int *success; /* Table of acceptance conditions used in
- regexecute and computed in build_state. */
+ dfaexec and computed in build_state. */
int *newlines; /* Transitions on newlines. The entry for a
newline in any transition table is always
-1 so we can count lines without wasting
@@ -462,40 +278,41 @@ struct regexp
newline is stored separately and handled
as a special case. Newline is also used
as a sentinel at the end of the buffer. */
- char must[MUST_MAX];
- int mustn;
+ struct dfamust *musts; /* List of strings, at least one of which
+ is known to appear in any r.e. matching
+ the dfa. */
};
-/* Some macros for user access to regexp internals. */
+/* Some macros for user access to dfa internals. */
/* ACCEPTING returns true if s could possibly be an accepting state of r. */
#define ACCEPTING(s, r) ((r).states[s].constraint)
/* ACCEPTS_IN_CONTEXT returns true if the given state accepts in the
specified context. */
-#define ACCEPTS_IN_CONTEXT(prevn, currn, prevl, currl, state, reg) \
- _SUCCEEDS_IN_CONTEXT((reg).states[state].constraint, \
+#define ACCEPTS_IN_CONTEXT(prevn, currn, prevl, currl, state, dfa) \
+ SUCCEEDS_IN_CONTEXT((dfa).states[state].constraint, \
prevn, currn, prevl, currl)
/* FIRST_MATCHING_REGEXP returns the index number of the first of parallel
regexps that a given state could accept. Parallel regexps are numbered
starting at 1. */
-#define FIRST_MATCHING_REGEXP(state, reg) (-(reg).states[state].first_end)
+#define FIRST_MATCHING_REGEXP(state, dfa) (-(dfa).states[state].first_end)
/* Entry points. */
#ifdef __STDC__
-/* Regsyntax() takes two arguments; the first sets the syntax bits described
+/* dfasyntax() takes two arguments; the first sets the syntax bits described
earlier in this file, and the second sets the case-folding flag. */
-extern void regsyntax(long, int);
+extern void dfasyntax(reg_syntax_t, int);
-/* Compile the given string of the given length into the given struct regexp.
+/* Compile the given string of the given length into the given struct dfa.
Final argument is a flag specifying whether to build a searching or an
exact matcher. */
-extern void regcompile(const char *, size_t, struct regexp *, int);
+extern void dfacomp(char *, size_t, struct dfa *, int);
-/* Execute the given struct regexp on the buffer of characters. The
+/* Execute the given struct dfa on the buffer of characters. The
first char * points to the beginning, and the second points to the
first character after the end of the buffer, which must be a writable
place so a sentinel end-of-buffer marker can be stored there. The
@@ -507,37 +324,37 @@ extern void regcompile(const char *, size_t, struct regexp *, int);
order to verify backreferencing; otherwise the flag will be cleared.
Returns NULL if no match is found, or a pointer to the first
character after the first & shortest matching string in the buffer. */
-extern char *regexecute(struct regexp *, char *, char *, int, int *, int *);
+extern char *dfaexec(struct dfa *, char *, char *, int, int *, int *);
-/* Free the storage held by the components of a struct regexp. */
-extern void reg_free(struct regexp *);
+/* Free the storage held by the components of a struct dfa. */
+extern void dfafree(struct dfa *);
/* Entry points for people who know what they're doing. */
-/* Initialize the components of a struct regexp. */
-extern void reginit(struct regexp *);
+/* Initialize the components of a struct dfa. */
+extern void dfainit(struct dfa *);
-/* Incrementally parse a string of given length into a struct regexp. */
-extern void regparse(const char *, size_t, struct regexp *);
+/* Incrementally parse a string of given length into a struct dfa. */
+extern void dfaparse(char *, size_t, struct dfa *);
/* Analyze a parsed regexp; second argument tells whether to build a searching
or an exact matcher. */
-extern void reganalyze(struct regexp *, int);
+extern void dfaanalyze(struct dfa *, int);
/* Compute, for each possible character, the transitions out of a given
state, storing them in an array of integers. */
-extern void regstate(int, struct regexp *, int []);
+extern void dfastate(int, struct dfa *, int []);
/* Error handling. */
-/* Regerror() is called by the regexp routines whenever an error occurs. It
+/* dfaerror() is called by the regexp routines whenever an error occurs. It
takes a single argument, a NUL-terminated string describing the error.
- The default reg_error() prints the error message to stderr and exits.
- The user can provide a different reg_free() if so desired. */
-extern void reg_error(const char *);
+ The default dfaerror() prints the error message to stderr and exits.
+ The user can provide a different dfafree() if so desired. */
+extern void dfaerror(const char *);
#else /* ! __STDC__ */
-extern void regsyntax(), regcompile(), reg_free(), reginit(), regparse();
-extern void reganalyze(), regstate(), reg_error();
-extern char *regexecute();
-#endif
+extern void dfasyntax(), dfacomp(), dfafree(), dfainit(), dfaparse();
+extern void dfaanalyze(), dfastate(), dfaerror();
+extern char *dfaexec();
+#endif /* ! __STDC__ */
diff --git a/gnu/usr.bin/awk/doc/Makefile b/gnu/usr.bin/awk/doc/Makefile
new file mode 100644
index 0000000..10d3d7d
--- /dev/null
+++ b/gnu/usr.bin/awk/doc/Makefile
@@ -0,0 +1,3 @@
+INFO = gawk
+
+.include <bsd.info.mk>
diff --git a/gnu/usr.bin/awk/doc/gawk.texi b/gnu/usr.bin/awk/doc/gawk.texi
new file mode 100644
index 0000000..b280262
--- /dev/null
+++ b/gnu/usr.bin/awk/doc/gawk.texi
@@ -0,0 +1,11270 @@
+\input texinfo @c -*-texinfo-*-
+@c %**start of header (This is for running Texinfo on a region.)
+@setfilename gawk.info
+@settitle The GAWK Manual
+@c @smallbook
+@c %**end of header (This is for running Texinfo on a region.)
+
+@ifinfo
+@synindex fn cp
+@synindex vr cp
+@end ifinfo
+@iftex
+@syncodeindex fn cp
+@syncodeindex vr cp
+@end iftex
+
+@c If "finalout" is commented out, the printed output will show
+@c black boxes that mark lines that are too long. Thus, it is
+@c unwise to comment it out when running a master in case there are
+@c overfulls which are deemed okay.
+
+@iftex
+@finalout
+@end iftex
+
+@c ===> NOTE! <==
+@c Determine the edition number in *four* places by hand:
+@c 1. First ifinfo section 2. title page 3. copyright page 4. top node
+@c To find the locations, search for !!set
+
+@ifinfo
+This file documents @code{awk}, a program that you can use to select
+particular records in a file and perform operations upon them.
+
+This is Edition 0.15 of @cite{The GAWK Manual}, @*
+for the 2.15 version of the GNU implementation @*
+of AWK.
+
+Copyright (C) 1989, 1991, 1992, 1993 Free Software Foundation, Inc.
+
+Permission is granted to make and distribute verbatim copies of
+this manual provided the copyright notice and this permission notice
+are preserved on all copies.
+
+@ignore
+Permission is granted to process this file through TeX and print the
+results, provided the printed document carries copying permission
+notice identical to this one except for the removal of this paragraph
+(this paragraph not being relevant to the printed manual).
+
+@end ignore
+Permission is granted to copy and distribute modified versions of this
+manual under the conditions for verbatim copying, provided that the entire
+resulting derived work is distributed under the terms of a permission
+notice identical to this one.
+
+Permission is granted to copy and distribute translations of this manual
+into another language, under the above conditions for modified versions,
+except that this permission notice may be stated in a translation approved
+by the Foundation.
+@end ifinfo
+
+@setchapternewpage odd
+
+@c !!set edition, date, version
+@titlepage
+@title The GAWK Manual
+@subtitle Edition 0.15
+@subtitle April 1993
+@author Diane Barlow Close
+@author Arnold D. Robbins
+@author Paul H. Rubin
+@author Richard Stallman
+
+@c Include the Distribution inside the titlepage environment so
+@c that headings are turned off. Headings on and off do not work.
+
+@page
+@vskip 0pt plus 1filll
+Copyright @copyright{} 1989, 1991, 1992, 1993 Free Software Foundation, Inc.
+@sp 2
+
+@c !!set edition, date, version
+This is Edition 0.15 of @cite{The GAWK Manual}, @*
+for the 2.15 version of the GNU implementation @*
+of AWK.
+
+@sp 2
+Published by the Free Software Foundation @*
+675 Massachusetts Avenue @*
+Cambridge, MA 02139 USA @*
+Printed copies are available for $20 each.
+
+Permission is granted to make and distribute verbatim copies of
+this manual provided the copyright notice and this permission notice
+are preserved on all copies.
+
+Permission is granted to copy and distribute modified versions of this
+manual under the conditions for verbatim copying, provided that the entire
+resulting derived work is distributed under the terms of a permission
+notice identical to this one.
+
+Permission is granted to copy and distribute translations of this manual
+into another language, under the above conditions for modified versions,
+except that this permission notice may be stated in a translation approved
+by the Foundation.
+@end titlepage
+
+@ifinfo
+@node Top, Preface, (dir), (dir)
+@comment node-name, next, previous, up
+@top General Introduction
+@c Preface or Licensing nodes should come right after the Top
+@c node, in `unnumbered' sections, then the chapter, `What is gawk'.
+
+This file documents @code{awk}, a program that you can use to select
+particular records in a file and perform operations upon them.
+
+@c !!set edition, date, version
+This is Edition 0.15 of @cite{The GAWK Manual}, @*
+for the 2.15 version of the GNU implementation @*
+of AWK.
+
+@end ifinfo
+
+@menu
+* Preface:: What you can do with @code{awk}; brief history
+ and acknowledgements.
+* Copying:: Your right to copy and distribute @code{gawk}.
+* This Manual:: Using this manual.
+ Includes sample input files that you can use.
+* Getting Started:: A basic introduction to using @code{awk}.
+ How to run an @code{awk} program.
+ Command line syntax.
+* Reading Files:: How to read files and manipulate fields.
+* Printing:: How to print using @code{awk}. Describes the
+ @code{print} and @code{printf} statements.
+ Also describes redirection of output.
+* One-liners:: Short, sample @code{awk} programs.
+* Patterns:: The various types of patterns
+ explained in detail.
+* Actions:: The various types of actions are
+ introduced here. Describes
+ expressions and the various operators in
+ detail. Also describes comparison expressions.
+* Expressions:: Expressions are the basic building
+ blocks of statements.
+* Statements:: The various control statements are
+ described in detail.
+* Arrays:: The description and use of arrays.
+ Also includes array-oriented control
+ statements.
+* Built-in:: The built-in functions are summarized here.
+* User-defined:: User-defined functions are described in detail.
+* Built-in Variables:: Built-in Variables
+* Command Line:: How to run @code{gawk}.
+* Language History:: The evolution of the @code{awk} language.
+* Installation:: Installing @code{gawk} under
+ various operating systems.
+* Gawk Summary:: @code{gawk} Options and Language Summary.
+* Sample Program:: A sample @code{awk} program with a
+ complete explanation.
+* Bugs:: Reporting Problems and Bugs.
+* Notes:: Something about the
+ implementation of @code{gawk}.
+* Glossary:: An explanation of some unfamiliar terms.
+* Index::
+@end menu
+
+@node Preface, Copying, Top, Top
+@comment node-name, next, previous, up
+@unnumbered Preface
+
+@iftex
+@cindex what is @code{awk}
+@end iftex
+If you are like many computer users, you would frequently like to make
+changes in various text files wherever certain patterns appear, or
+extract data from parts of certain lines while discarding the rest. To
+write a program to do this in a language such as C or Pascal is a
+time-consuming inconvenience that may take many lines of code. The job
+may be easier with @code{awk}.
+
+The @code{awk} utility interprets a special-purpose programming language
+that makes it possible to handle simple data-reformatting jobs easily
+with just a few lines of code.
+
+The GNU implementation of @code{awk} is called @code{gawk}; it is fully
+upward compatible with the System V Release 4 version of
+@code{awk}. @code{gawk} is also upward compatible with the @sc{posix}
+(draft) specification of the @code{awk} language. This means that all
+properly written @code{awk} programs should work with @code{gawk}.
+Thus, we usually don't distinguish between @code{gawk} and other @code{awk}
+implementations in this manual.@refill
+
+@cindex uses of @code{awk}
+This manual teaches you what @code{awk} does and how you can use
+@code{awk} effectively. You should already be familiar with basic
+system commands such as @code{ls}. Using @code{awk} you can: @refill
+
+@itemize @bullet
+@item
+manage small, personal databases
+
+@item
+generate reports
+
+@item
+validate data
+@item
+produce indexes, and perform other document preparation tasks
+
+@item
+even experiment with algorithms that can be adapted later to other computer
+languages
+@end itemize
+
+@iftex
+This manual has the difficult task of being both tutorial and reference.
+If you are a novice, feel free to skip over details that seem too complex.
+You should also ignore the many cross references; they are for the
+expert user, and for the on-line Info version of the manual.
+@end iftex
+
+@menu
+* History:: The history of @code{gawk} and
+ @code{awk}. Acknowledgements.
+@end menu
+
+@node History, , Preface, Preface
+@comment node-name, next, previous, up
+@unnumberedsec History of @code{awk} and @code{gawk}
+
+@cindex acronym
+@cindex history of @code{awk}
+The name @code{awk} comes from the initials of its designers: Alfred V.
+Aho, Peter J. Weinberger, and Brian W. Kernighan. The original version of
+@code{awk} was written in 1977. In 1985 a new version made the programming
+language more powerful, introducing user-defined functions, multiple input
+streams, and computed regular expressions.
+This new version became generally available with System V Release 3.1.
+The version in System V Release 4 added some new features and also cleaned
+up the behavior in some of the ``dark corners'' of the language.
+The specification for @code{awk} in the @sc{posix} Command Language
+and Utilities standard further clarified the language based on feedback
+from both the @code{gawk} designers, and the original @code{awk}
+designers.@refill
+
+The GNU implementation, @code{gawk}, was written in 1986 by Paul Rubin
+and Jay Fenlason, with advice from Richard Stallman. John Woods
+contributed parts of the code as well. In 1988 and 1989, David Trueman, with
+help from Arnold Robbins, thoroughly reworked @code{gawk} for compatibility
+with the newer @code{awk}. Current development (1992) focuses on bug fixes,
+performance improvements, and standards compliance.
+
+We need to thank many people for their assistance in producing this
+manual. Jay Fenlason contributed many ideas and sample programs. Richard
+Mlynarik and Robert J. Chassell gave helpful comments on early drafts of this
+manual. The paper @cite{A Supplemental Document for @code{awk}} by John W.
+Pierce of the Chemistry Department at UC San Diego, pinpointed several
+issues relevant both to @code{awk} implementation and to this manual, that
+would otherwise have escaped us. David Trueman, Pat Rankin, and Michal
+Jaegermann also contributed sections of the manual.@refill
+
+The following people provided many helpful comments on this edition of
+the manual: Rick Adams, Michael Brennan, Rich Burridge, Diane Close,
+Christopher (``Topher'') Eliot, Michael Lijewski, Pat Rankin, Miriam Robbins,
+and Michal Jaegermann. Robert J. Chassell provided much valuable advice on
+the use of Texinfo.
+
+Finally, we would like to thank Brian Kernighan of Bell Labs for invaluable
+assistance during the testing and debugging of @code{gawk}, and for
+help in clarifying numerous points about the language.@refill
+
+@node Copying, This Manual, Preface, Top
+@unnumbered GNU GENERAL PUBLIC LICENSE
+@center Version 2, June 1991
+
+@display
+Copyright @copyright{} 1989, 1991 Free Software Foundation, Inc.
+675 Mass Ave, Cambridge, MA 02139, USA
+
+Everyone is permitted to copy and distribute verbatim copies
+of this license document, but changing it is not allowed.
+@end display
+
+@c fakenode --- for prepinfo
+@unnumberedsec Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software---to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+@iftex
+@c fakenode --- for prepinfo
+@unnumberedsec TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+@end iftex
+@ifinfo
+@center TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+@end ifinfo
+
+@enumerate
+@item
+This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The ``Program'', below,
+refers to any such program or work, and a ``work based on the Program''
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term ``modification''.) Each licensee is addressed as ``you''.
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+@item
+You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+@item
+You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+@enumerate a
+@item
+You must cause the modified files to carry prominent notices
+stating that you changed the files and the date of any change.
+
+@item
+You must cause any work that you distribute or publish, that in
+whole or in part contains or is derived from the Program or any
+part thereof, to be licensed as a whole at no charge to all third
+parties under the terms of this License.
+
+@item
+If the modified program normally reads commands interactively
+when run, you must cause it, when started running for such
+interactive use in the most ordinary way, to print or display an
+announcement including an appropriate copyright notice and a
+notice that there is no warranty (or else, saying that you provide
+a warranty) and that users may redistribute the program under
+these conditions, and telling the user how to view a copy of this
+License. (Exception: if the Program itself is interactive but
+does not normally print such an announcement, your work based on
+the Program is not required to print an announcement.)
+@end enumerate
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+@item
+You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+@enumerate a
+@item
+Accompany it with the complete corresponding machine-readable
+source code, which must be distributed under the terms of Sections
+1 and 2 above on a medium customarily used for software interchange; or,
+
+@item
+Accompany it with a written offer, valid for at least three
+years, to give any third party, for a charge no more than your
+cost of physically performing source distribution, a complete
+machine-readable copy of the corresponding source code, to be
+distributed under the terms of Sections 1 and 2 above on a medium
+customarily used for software interchange; or,
+
+@item
+Accompany it with the information you received as to the offer
+to distribute corresponding source code. (This alternative is
+allowed only for noncommercial distribution and only if you
+received the program in object code or executable form with such
+an offer, in accord with Subsection b above.)
+@end enumerate
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+@item
+You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+@item
+You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+@item
+Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+@item
+If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+@item
+If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+@item
+The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and ``any
+later version'', you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+@item
+If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+@iftex
+@c fakenode --- for prepinfo
+@heading NO WARRANTY
+@end iftex
+@ifinfo
+@center NO WARRANTY
+@end ifinfo
+
+@item
+BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM ``AS IS'' WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+@item
+IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+@end enumerate
+
+@iftex
+@c fakenode --- for prepinfo
+@heading END OF TERMS AND CONDITIONS
+@end iftex
+@ifinfo
+@center END OF TERMS AND CONDITIONS
+@end ifinfo
+
+@page
+@c fakenode --- for prepinfo
+@unnumberedsec How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the ``copyright'' line and a pointer to where the full notice is found.
+
+@smallexample
+@var{one line to give the program's name and a brief idea of what it does.}
+Copyright (C) 19@var{yy} @var{name of author}
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+@end smallexample
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+@smallexample
+Gnomovision version 69, Copyright (C) 19@var{yy} @var{name of author}
+Gnomovision comes with ABSOLUTELY NO WARRANTY; for details
+type `show w'.
+This is free software, and you are welcome to redistribute it
+under certain conditions; type `show c' for details.
+@end smallexample
+
+The hypothetical commands @samp{show w} and @samp{show c} should show
+the appropriate parts of the General Public License. Of course, the
+commands you use may be called something other than @samp{show w} and
+@samp{show c}; they could even be mouse-clicks or menu items---whatever
+suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a ``copyright disclaimer'' for the program, if
+necessary. Here is a sample; alter the names:
+
+@smallexample
+Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+`Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+@var{signature of Ty Coon}, 1 April 1989
+Ty Coon, President of Vice
+@end smallexample
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
+
+@node This Manual, Getting Started, Copying, Top
+@chapter Using this Manual
+@cindex manual, using this
+@cindex using this manual
+@cindex language, @code{awk}
+@cindex program, @code{awk}
+@cindex @code{awk} language
+@cindex @code{awk} program
+
+The term @code{awk} refers to a particular program, and to the language you
+use to tell this program what to do. When we need to be careful, we call
+the program ``the @code{awk} utility'' and the language ``the @code{awk}
+language.'' The term @code{gawk} refers to a version of @code{awk} developed
+as part the GNU project. The purpose of this manual is to explain
+both the
+@code{awk} language and how to run the @code{awk} utility.@refill
+
+While concentrating on the features of @code{gawk}, the manual will also
+attempt to describe important differences between @code{gawk} and other
+@code{awk} implementations. In particular, any features that are not
+in the @sc{posix} standard for @code{awk} will be noted. @refill
+
+The term @dfn{@code{awk} program} refers to a program written by you in
+the @code{awk} programming language.@refill
+
+@xref{Getting Started, ,Getting Started with @code{awk}}, for the bare
+essentials you need to know to start using @code{awk}.
+
+Some useful ``one-liners'' are included to give you a feel for the
+@code{awk} language (@pxref{One-liners, ,Useful ``One-liners''}).
+
+@ignore
+@strong{I deleted four paragraphs here because they would confuse the
+beginner more than help him. They mention terms such as ``field,''
+``pattern,'' ``action,'' ``built-in function'' which the beginner
+doesn't know.}
+
+@strong{If you can find a way to introduce several of these concepts here,
+enough to give the reader a map of what is to follow, that might
+be useful. I'm not sure that can be done without taking up more
+space than ought to be used here. There may be no way to win.}
+
+@strong{ADR: I'd like to tackle this in phase 2 of my editing.}
+@end ignore
+
+A sample @code{awk} program has been provided for you
+(@pxref{Sample Program}).@refill
+
+If you find terms that you aren't familiar with, try looking them
+up in the glossary (@pxref{Glossary}).@refill
+
+The entire @code{awk} language is summarized for quick reference in
+@ref{Gawk Summary, ,@code{gawk} Summary}. Look there if you just need
+to refresh your memory about a particular feature.@refill
+
+Most of the time complete @code{awk} programs are used as examples, but in
+some of the more advanced sections, only the part of the @code{awk} program
+that illustrates the concept being described is shown.@refill
+
+@menu
+* Sample Data Files:: Sample data files for use in the @code{awk}
+ programs illustrated in this manual.
+@end menu
+
+@node Sample Data Files, , This Manual, This Manual
+@section Data Files for the Examples
+
+@cindex input file, sample
+@cindex sample input file
+@cindex @file{BBS-list} file
+Many of the examples in this manual take their input from two sample
+data files. The first, called @file{BBS-list}, represents a list of
+computer bulletin board systems together with information about those systems.
+The second data file, called @file{inventory-shipped}, contains
+information about shipments on a monthly basis. Each line of these
+files is one @dfn{record}.
+
+In the file @file{BBS-list}, each record contains the name of a computer
+bulletin board, its phone number, the board's baud rate, and a code for
+the number of hours it is operational. An @samp{A} in the last column
+means the board operates 24 hours a day. A @samp{B} in the last
+column means the board operates evening and weekend hours, only. A
+@samp{C} means the board operates only on weekends.
+
+@example
+aardvark 555-5553 1200/300 B
+alpo-net 555-3412 2400/1200/300 A
+barfly 555-7685 1200/300 A
+bites 555-1675 2400/1200/300 A
+camelot 555-0542 300 C
+core 555-2912 1200/300 C
+fooey 555-1234 2400/1200/300 B
+foot 555-6699 1200/300 B
+macfoo 555-6480 1200/300 A
+sdace 555-3430 2400/1200/300 A
+sabafoo 555-2127 1200/300 C
+@end example
+
+@cindex @file{inventory-shipped} file
+The second data file, called @file{inventory-shipped}, represents
+information about shipments during the year.
+Each record contains the month of the year, the number
+of green crates shipped, the number of red boxes shipped, the number of
+orange bags shipped, and the number of blue packages shipped,
+respectively. There are 16 entries, covering the 12 months of one year
+and 4 months of the next year.@refill
+
+@example
+Jan 13 25 15 115
+Feb 15 32 24 226
+Mar 15 24 34 228
+Apr 31 52 63 420
+May 16 34 29 208
+Jun 31 42 75 492
+Jul 24 34 67 436
+Aug 15 34 47 316
+Sep 13 55 37 277
+Oct 29 54 68 525
+Nov 20 87 82 577
+Dec 17 35 61 401
+
+Jan 21 36 64 620
+Feb 26 58 80 652
+Mar 24 75 70 495
+Apr 21 70 74 514
+@end example
+
+@ifinfo
+If you are reading this in GNU Emacs using Info, you can copy the regions
+of text showing these sample files into your own test files. This way you
+can try out the examples shown in the remainder of this document. You do
+this by using the command @kbd{M-x write-region} to copy text from the Info
+file into a file for use with @code{awk}
+(@xref{Misc File Ops, , , emacs, GNU Emacs Manual},
+for more information). Using this information, create your own
+@file{BBS-list} and @file{inventory-shipped} files, and practice what you
+learn in this manual.
+@end ifinfo
+
+@node Getting Started, Reading Files, This Manual, Top
+@chapter Getting Started with @code{awk}
+@cindex script, definition of
+@cindex rule, definition of
+@cindex program, definition of
+@cindex basic function of @code{gawk}
+
+The basic function of @code{awk} is to search files for lines (or other
+units of text) that contain certain patterns. When a line matches one
+of the patterns, @code{awk} performs specified actions on that line.
+@code{awk} keeps processing input lines in this way until the end of the
+input file is reached.@refill
+
+When you run @code{awk}, you specify an @code{awk} @dfn{program} which
+tells @code{awk} what to do. The program consists of a series of
+@dfn{rules}. (It may also contain @dfn{function definitions}, but that
+is an advanced feature, so we will ignore it for now.
+@xref{User-defined, ,User-defined Functions}.) Each rule specifies one
+pattern to search for, and one action to perform when that pattern is found.
+
+Syntactically, a rule consists of a pattern followed by an action. The
+action is enclosed in curly braces to separate it from the pattern.
+Rules are usually separated by newlines. Therefore, an @code{awk}
+program looks like this:
+
+@example
+@var{pattern} @{ @var{action} @}
+@var{pattern} @{ @var{action} @}
+@dots{}
+@end example
+
+@menu
+* Very Simple:: A very simple example.
+* Two Rules:: A less simple one-line example with two rules.
+* More Complex:: A more complex example.
+* Running gawk:: How to run @code{gawk} programs;
+ includes command line syntax.
+* Comments:: Adding documentation to @code{gawk} programs.
+* Statements/Lines:: Subdividing or combining statements into lines.
+* When:: When to use @code{gawk} and
+ when to use other things.
+@end menu
+
+@node Very Simple, Two Rules, Getting Started, Getting Started
+@section A Very Simple Example
+
+@cindex @samp{print $0}
+The following command runs a simple @code{awk} program that searches the
+input file @file{BBS-list} for the string of characters: @samp{foo}. (A
+string of characters is usually called, a @dfn{string}.
+The term @dfn{string} is perhaps based on similar usage in English, such
+as ``a string of pearls,'' or, ``a string of cars in a train.'')
+
+@example
+awk '/foo/ @{ print $0 @}' BBS-list
+@end example
+
+@noindent
+When lines containing @samp{foo} are found, they are printed, because
+@w{@samp{print $0}} means print the current line. (Just @samp{print} by
+itself means the same thing, so we could have written that
+instead.)
+
+You will notice that slashes, @samp{/}, surround the string @samp{foo}
+in the actual @code{awk} program. The slashes indicate that @samp{foo}
+is a pattern to search for. This type of pattern is called a
+@dfn{regular expression}, and is covered in more detail later
+(@pxref{Regexp, ,Regular Expressions as Patterns}). There are
+single-quotes around the @code{awk} program so that the shell won't
+interpret any of it as special shell characters.@refill
+
+Here is what this program prints:
+
+@example
+@group
+fooey 555-1234 2400/1200/300 B
+foot 555-6699 1200/300 B
+macfoo 555-6480 1200/300 A
+sabafoo 555-2127 1200/300 C
+@end group
+@end example
+
+@cindex action, default
+@cindex pattern, default
+@cindex default action
+@cindex default pattern
+In an @code{awk} rule, either the pattern or the action can be omitted,
+but not both. If the pattern is omitted, then the action is performed
+for @emph{every} input line. If the action is omitted, the default
+action is to print all lines that match the pattern.
+
+Thus, we could leave out the action (the @code{print} statement and the curly
+braces) in the above example, and the result would be the same: all
+lines matching the pattern @samp{foo} would be printed. By comparison,
+omitting the @code{print} statement but retaining the curly braces makes an
+empty action that does nothing; then no lines would be printed.
+
+@node Two Rules, More Complex, Very Simple, Getting Started
+@section An Example with Two Rules
+@cindex how @code{awk} works
+
+The @code{awk} utility reads the input files one line at a
+time. For each line, @code{awk} tries the patterns of each of the rules.
+If several patterns match then several actions are run, in the order in
+which they appear in the @code{awk} program. If no patterns match, then
+no actions are run.
+
+After processing all the rules (perhaps none) that match the line,
+@code{awk} reads the next line (however,
+@pxref{Next Statement, ,The @code{next} Statement}). This continues
+until the end of the file is reached.@refill
+
+For example, the @code{awk} program:
+
+@example
+/12/ @{ print $0 @}
+/21/ @{ print $0 @}
+@end example
+
+@noindent
+contains two rules. The first rule has the string @samp{12} as the
+pattern and @samp{print $0} as the action. The second rule has the
+string @samp{21} as the pattern and also has @samp{print $0} as the
+action. Each rule's action is enclosed in its own pair of braces.
+
+This @code{awk} program prints every line that contains the string
+@samp{12} @emph{or} the string @samp{21}. If a line contains both
+strings, it is printed twice, once by each rule.
+
+If we run this program on our two sample data files, @file{BBS-list} and
+@file{inventory-shipped}, as shown here:
+
+@example
+awk '/12/ @{ print $0 @}
+ /21/ @{ print $0 @}' BBS-list inventory-shipped
+@end example
+
+@noindent
+we get the following output:
+
+@example
+aardvark 555-5553 1200/300 B
+alpo-net 555-3412 2400/1200/300 A
+barfly 555-7685 1200/300 A
+bites 555-1675 2400/1200/300 A
+core 555-2912 1200/300 C
+fooey 555-1234 2400/1200/300 B
+foot 555-6699 1200/300 B
+macfoo 555-6480 1200/300 A
+sdace 555-3430 2400/1200/300 A
+sabafoo 555-2127 1200/300 C
+sabafoo 555-2127 1200/300 C
+Jan 21 36 64 620
+Apr 21 70 74 514
+@end example
+
+@noindent
+Note how the line in @file{BBS-list} beginning with @samp{sabafoo}
+was printed twice, once for each rule.
+
+@node More Complex, Running gawk, Two Rules, Getting Started
+@comment node-name, next, previous, up
+@section A More Complex Example
+
+Here is an example to give you an idea of what typical @code{awk}
+programs do. This example shows how @code{awk} can be used to
+summarize, select, and rearrange the output of another utility. It uses
+features that haven't been covered yet, so don't worry if you don't
+understand all the details.
+
+@example
+ls -l | awk '$5 == "Nov" @{ sum += $4 @}
+ END @{ print sum @}'
+@end example
+
+This command prints the total number of bytes in all the files in the
+current directory that were last modified in November (of any year).
+(In the C shell you would need to type a semicolon and then a backslash
+at the end of the first line; in a @sc{posix}-compliant shell, such as the
+Bourne shell or the Bourne-Again shell, you can type the example as shown.)
+
+The @w{@samp{ls -l}} part of this example is a command that gives you a
+listing of the files in a directory, including file size and date.
+Its output looks like this:@refill
+
+@example
+-rw-r--r-- 1 close 1933 Nov 7 13:05 Makefile
+-rw-r--r-- 1 close 10809 Nov 7 13:03 gawk.h
+-rw-r--r-- 1 close 983 Apr 13 12:14 gawk.tab.h
+-rw-r--r-- 1 close 31869 Jun 15 12:20 gawk.y
+-rw-r--r-- 1 close 22414 Nov 7 13:03 gawk1.c
+-rw-r--r-- 1 close 37455 Nov 7 13:03 gawk2.c
+-rw-r--r-- 1 close 27511 Dec 9 13:07 gawk3.c
+-rw-r--r-- 1 close 7989 Nov 7 13:03 gawk4.c
+@end example
+
+@noindent
+The first field contains read-write permissions, the second field contains
+the number of links to the file, and the third field identifies the owner of
+the file. The fourth field contains the size of the file in bytes. The
+fifth, sixth, and seventh fields contain the month, day, and time,
+respectively, that the file was last modified. Finally, the eighth field
+contains the name of the file.
+
+The @code{$5 == "Nov"} in our @code{awk} program is an expression that
+tests whether the fifth field of the output from @w{@samp{ls -l}}
+matches the string @samp{Nov}. Each time a line has the string
+@samp{Nov} in its fifth field, the action @samp{@{ sum += $4 @}} is
+performed. This adds the fourth field (the file size) to the variable
+@code{sum}. As a result, when @code{awk} has finished reading all the
+input lines, @code{sum} is the sum of the sizes of files whose
+lines matched the pattern. (This works because @code{awk} variables
+are automatically initialized to zero.)@refill
+
+After the last line of output from @code{ls} has been processed, the
+@code{END} rule is executed, and the value of @code{sum} is
+printed. In this example, the value of @code{sum} would be 80600.@refill
+
+These more advanced @code{awk} techniques are covered in later sections
+(@pxref{Actions, ,Overview of Actions}). Before you can move on to more
+advanced @code{awk} programming, you have to know how @code{awk} interprets
+your input and displays your output. By manipulating fields and using
+@code{print} statements, you can produce some very useful and spectacular
+looking reports.@refill
+
+@node Running gawk, Comments, More Complex, Getting Started
+@section How to Run @code{awk} Programs
+
+@ignore
+Date: Mon, 26 Aug 91 09:48:10 +0200
+From: gatech!vsoc07.cern.ch!matheys (Jean-Pol Matheys (CERN - ECP Division))
+To: uunet.UU.NET!skeeve!arnold
+Subject: RE: status check
+
+The introduction of Chapter 2 (i.e. before 2.1) should include
+the whole of section 2.4 - it's better to tell people how to run awk programs
+before giving any examples
+
+ADR --- he's right. but for now, don't do this because the rest of the
+chapter would need some rewriting.
+@end ignore
+
+@cindex command line formats
+@cindex running @code{awk} programs
+There are several ways to run an @code{awk} program. If the program is
+short, it is easiest to include it in the command that runs @code{awk},
+like this:
+
+@example
+awk '@var{program}' @var{input-file1} @var{input-file2} @dots{}
+@end example
+
+@noindent
+where @var{program} consists of a series of patterns and actions, as
+described earlier.
+
+When the program is long, it is usually more convenient to put it in a file
+and run it with a command like this:
+
+@example
+awk -f @var{program-file} @var{input-file1} @var{input-file2} @dots{}
+@end example
+
+@menu
+* One-shot:: Running a short throw-away @code{awk} program.
+* Read Terminal:: Using no input files (input from
+ terminal instead).
+* Long:: Putting permanent @code{awk} programs in files.
+* Executable Scripts:: Making self-contained @code{awk} programs.
+@end menu
+
+@node One-shot, Read Terminal, Running gawk, Running gawk
+@subsection One-shot Throw-away @code{awk} Programs
+
+Once you are familiar with @code{awk}, you will often type simple
+programs at the moment you want to use them. Then you can write the
+program as the first argument of the @code{awk} command, like this:
+
+@example
+awk '@var{program}' @var{input-file1} @var{input-file2} @dots{}
+@end example
+
+@noindent
+where @var{program} consists of a series of @var{patterns} and
+@var{actions}, as described earlier.
+
+@cindex single quotes, why needed
+This command format instructs the shell to start @code{awk} and use the
+@var{program} to process records in the input file(s). There are single
+quotes around @var{program} so that the shell doesn't interpret any
+@code{awk} characters as special shell characters. They also cause the
+shell to treat all of @var{program} as a single argument for
+@code{awk} and allow @var{program} to be more than one line long.@refill
+
+This format is also useful for running short or medium-sized @code{awk}
+programs from shell scripts, because it avoids the need for a separate
+file for the @code{awk} program. A self-contained shell script is more
+reliable since there are no other files to misplace.
+
+@node Read Terminal, Long, One-shot, Running gawk
+@subsection Running @code{awk} without Input Files
+
+@cindex standard input
+@cindex input, standard
+You can also run @code{awk} without any input files. If you type the
+command line:@refill
+
+@example
+awk '@var{program}'
+@end example
+
+@noindent
+then @code{awk} applies the @var{program} to the @dfn{standard input},
+which usually means whatever you type on the terminal. This continues
+until you indicate end-of-file by typing @kbd{Control-d}.
+
+For example, if you execute this command:
+
+@example
+awk '/th/'
+@end example
+
+@noindent
+whatever you type next is taken as data for that @code{awk}
+program. If you go on to type the following data:
+
+@example
+Kathy
+Ben
+Tom
+Beth
+Seth
+Karen
+Thomas
+@kbd{Control-d}
+@end example
+
+@noindent
+then @code{awk} prints this output:
+
+@example
+Kathy
+Beth
+Seth
+@end example
+
+@noindent
+@cindex case sensitivity
+@cindex pattern, case sensitive
+as matching the pattern @samp{th}. Notice that it did not recognize
+@samp{Thomas} as matching the pattern. The @code{awk} language is
+@dfn{case sensitive}, and matches patterns exactly. (However, you can
+override this with the variable @code{IGNORECASE}.
+@xref{Case-sensitivity, ,Case-sensitivity in Matching}.)
+
+@node Long, Executable Scripts, Read Terminal, Running gawk
+@subsection Running Long Programs
+
+@cindex running long programs
+@cindex @samp{-f} option
+@cindex program file
+@cindex file, @code{awk} program
+Sometimes your @code{awk} programs can be very long. In this case it is
+more convenient to put the program into a separate file. To tell
+@code{awk} to use that file for its program, you type:@refill
+
+@example
+awk -f @var{source-file} @var{input-file1} @var{input-file2} @dots{}
+@end example
+
+The @samp{-f} instructs the @code{awk} utility to get the @code{awk} program
+from the file @var{source-file}. Any file name can be used for
+@var{source-file}. For example, you could put the program:@refill
+
+@example
+/th/
+@end example
+
+@noindent
+into the file @file{th-prog}. Then this command:
+
+@example
+awk -f th-prog
+@end example
+
+@noindent
+does the same thing as this one:
+
+@example
+awk '/th/'
+@end example
+
+@noindent
+which was explained earlier (@pxref{Read Terminal, ,Running @code{awk} without Input Files}).
+Note that you don't usually need single quotes around the file name that you
+specify with @samp{-f}, because most file names don't contain any of the shell's
+special characters. Notice that in @file{th-prog}, the @code{awk}
+program did not have single quotes around it. The quotes are only needed
+for programs that are provided on the @code{awk} command line.
+
+If you want to identify your @code{awk} program files clearly as such,
+you can add the extension @file{.awk} to the file name. This doesn't
+affect the execution of the @code{awk} program, but it does make
+``housekeeping'' easier.
+
+@node Executable Scripts, , Long, Running gawk
+@c node-name, next, previous, up
+@subsection Executable @code{awk} Programs
+@cindex executable scripts
+@cindex scripts, executable
+@cindex self contained programs
+@cindex program, self contained
+@cindex @samp{#!}
+
+Once you have learned @code{awk}, you may want to write self-contained
+@code{awk} scripts, using the @samp{#!} script mechanism. You can do
+this on many Unix systems @footnote{The @samp{#!} mechanism works on
+Unix systems derived from Berkeley Unix, System V Release 4, and some System
+V Release 3 systems.} (and someday on GNU).@refill
+
+For example, you could create a text file named @file{hello}, containing
+the following (where @samp{BEGIN} is a feature we have not yet
+discussed):
+
+@example
+#! /bin/awk -f
+
+# a sample awk program
+BEGIN @{ print "hello, world" @}
+@end example
+
+@noindent
+After making this file executable (with the @code{chmod} command), you
+can simply type:
+
+@example
+hello
+@end example
+
+@noindent
+at the shell, and the system will arrange to run @code{awk} @footnote{The
+line beginning with @samp{#!} lists the full pathname of an interpreter
+to be run, and an optional initial command line argument to pass to that
+interpreter. The operating system then runs the interpreter with the given
+argument and the full argument list of the executed program. The first argument
+in the list is the full pathname of the @code{awk} program. The rest of the
+argument list will either be options to @code{awk}, or data files,
+or both.} as if you had typed:@refill
+
+@example
+awk -f hello
+@end example
+
+@noindent
+Self-contained @code{awk} scripts are useful when you want to write a
+program which users can invoke without knowing that the program is
+written in @code{awk}.
+
+@cindex shell scripts
+@cindex scripts, shell
+If your system does not support the @samp{#!} mechanism, you can get a
+similar effect using a regular shell script. It would look something
+like this:
+
+@example
+: The colon makes sure this script is executed by the Bourne shell.
+awk '@var{program}' "$@@"
+@end example
+
+Using this technique, it is @emph{vital} to enclose the @var{program} in
+single quotes to protect it from interpretation by the shell. If you
+omit the quotes, only a shell wizard can predict the results.
+
+The @samp{"$@@"} causes the shell to forward all the command line
+arguments to the @code{awk} program, without interpretation. The first
+line, which starts with a colon, is used so that this shell script will
+work even if invoked by a user who uses the C shell.
+@c Someday: (See @cite{The Bourne Again Shell}, by ??.)
+
+@node Comments, Statements/Lines, Running gawk, Getting Started
+@section Comments in @code{awk} Programs
+@cindex @samp{#}
+@cindex comments
+@cindex use of comments
+@cindex documenting @code{awk} programs
+@cindex programs, documenting
+
+A @dfn{comment} is some text that is included in a program for the sake
+of human readers, and that is not really part of the program. Comments
+can explain what the program does, and how it works. Nearly all
+programming languages have provisions for comments, because programs are
+typically hard to understand without their extra help.
+
+In the @code{awk} language, a comment starts with the sharp sign
+character, @samp{#}, and continues to the end of the line. The
+@code{awk} language ignores the rest of a line following a sharp sign.
+For example, we could have put the following into @file{th-prog}:@refill
+
+@smallexample
+# This program finds records containing the pattern @samp{th}. This is how
+# you continue comments on additional lines.
+/th/
+@end smallexample
+
+You can put comment lines into keyboard-composed throw-away @code{awk}
+programs also, but this usually isn't very useful; the purpose of a
+comment is to help you or another person understand the program at
+a later time.@refill
+
+@node Statements/Lines, When, Comments, Getting Started
+@section @code{awk} Statements versus Lines
+
+Most often, each line in an @code{awk} program is a separate statement or
+separate rule, like this:
+
+@example
+awk '/12/ @{ print $0 @}
+ /21/ @{ print $0 @}' BBS-list inventory-shipped
+@end example
+
+But sometimes statements can be more than one line, and lines can
+contain several statements. You can split a statement into multiple
+lines by inserting a newline after any of the following:@refill
+
+@example
+, @{ ? : || && do else
+@end example
+
+@noindent
+A newline at any other point is considered the end of the statement.
+(Splitting lines after @samp{?} and @samp{:} is a minor @code{gawk}
+extension. The @samp{?} and @samp{:} referred to here is the
+three operand conditional expression described in
+@ref{Conditional Exp, ,Conditional Expressions}.)@refill
+
+@cindex backslash continuation
+@cindex continuation of lines
+If you would like to split a single statement into two lines at a point
+where a newline would terminate it, you can @dfn{continue} it by ending the
+first line with a backslash character, @samp{\}. This is allowed
+absolutely anywhere in the statement, even in the middle of a string or
+regular expression. For example:
+
+@example
+awk '/This program is too long, so continue it\
+ on the next line/ @{ print $1 @}'
+@end example
+
+@noindent
+We have generally not used backslash continuation in the sample programs in
+this manual. Since in @code{gawk} there is no limit on the length of a line,
+it is never strictly necessary; it just makes programs prettier. We have
+preferred to make them even more pretty by keeping the statements short.
+Backslash continuation is most useful when your @code{awk} program is in a
+separate source file, instead of typed in on the command line. You should
+also note that many @code{awk} implementations are more picky about where
+you may use backslash continuation. For maximal portability of your @code{awk}
+programs, it is best not to split your lines in the middle of a regular
+expression or a string.@refill
+
+@strong{Warning: backslash continuation does not work as described above
+with the C shell.} Continuation with backslash works for @code{awk}
+programs in files, and also for one-shot programs @emph{provided} you
+are using a @sc{posix}-compliant shell, such as the Bourne shell or the
+Bourne-again shell. But the C shell used on Berkeley Unix behaves
+differently! There, you must use two backslashes in a row, followed by
+a newline.@refill
+
+@cindex multiple statements on one line
+When @code{awk} statements within one rule are short, you might want to put
+more than one of them on a line. You do this by separating the statements
+with a semicolon, @samp{;}.
+This also applies to the rules themselves.
+Thus, the previous program could have been written:@refill
+
+@example
+/12/ @{ print $0 @} ; /21/ @{ print $0 @}
+@end example
+
+@noindent
+@strong{Note:} the requirement that rules on the same line must be
+separated with a semicolon is a recent change in the @code{awk}
+language; it was done for consistency with the treatment of statements
+within an action.
+
+@node When, , Statements/Lines, Getting Started
+@section When to Use @code{awk}
+
+@cindex when to use @code{awk}
+@cindex applications of @code{awk}
+You might wonder how @code{awk} might be useful for you. Using additional
+utility programs, more advanced patterns, field separators, arithmetic
+statements, and other selection criteria, you can produce much more
+complex output. The @code{awk} language is very useful for producing
+reports from large amounts of raw data, such as summarizing information
+from the output of other utility programs like @code{ls}.
+(@xref{More Complex, ,A More Complex Example}.)
+
+Programs written with @code{awk} are usually much smaller than they would
+be in other languages. This makes @code{awk} programs easy to compose and
+use. Often @code{awk} programs can be quickly composed at your terminal,
+used once, and thrown away. Since @code{awk} programs are interpreted, you
+can avoid the usually lengthy edit-compile-test-debug cycle of software
+development.
+
+Complex programs have been written in @code{awk}, including a complete
+retargetable assembler for 8-bit microprocessors (@pxref{Glossary}, for
+more information) and a microcode assembler for a special purpose Prolog
+computer. However, @code{awk}'s capabilities are strained by tasks of
+such complexity.
+
+If you find yourself writing @code{awk} scripts of more than, say, a few
+hundred lines, you might consider using a different programming
+language. Emacs Lisp is a good choice if you need sophisticated string
+or pattern matching capabilities. The shell is also good at string and
+pattern matching; in addition, it allows powerful use of the system
+utilities. More conventional languages, such as C, C++, and Lisp, offer
+better facilities for system programming and for managing the complexity
+of large programs. Programs in these languages may require more lines
+of source code than the equivalent @code{awk} programs, but they are
+easier to maintain and usually run more efficiently.@refill
+
+@node Reading Files, Printing, Getting Started, Top
+@chapter Reading Input Files
+
+@cindex reading files
+@cindex input
+@cindex standard input
+@vindex FILENAME
+In the typical @code{awk} program, all input is read either from the
+standard input (by default the keyboard, but often a pipe from another
+command) or from files whose names you specify on the @code{awk} command
+line. If you specify input files, @code{awk} reads them in order, reading
+all the data from one before going on to the next. The name of the current
+input file can be found in the built-in variable @code{FILENAME}
+(@pxref{Built-in Variables}).@refill
+
+The input is read in units called records, and processed by the
+rules one record at a time. By default, each record is one line. Each
+record is split automatically into fields, to make it more
+convenient for a rule to work on its parts.
+
+On rare occasions you will need to use the @code{getline} command,
+which can do explicit input from any number of files
+(@pxref{Getline, ,Explicit Input with @code{getline}}).@refill
+
+@menu
+* Records:: Controlling how data is split into records.
+* Fields:: An introduction to fields.
+* Non-Constant Fields:: Non-constant Field Numbers.
+* Changing Fields:: Changing the Contents of a Field.
+* Field Separators:: The field separator and how to change it.
+* Constant Size:: Reading constant width data.
+* Multiple Line:: Reading multi-line records.
+* Getline:: Reading files under explicit program control
+ using the @code{getline} function.
+* Close Input:: Closing an input file (so you can read from
+ the beginning once more).
+@end menu
+
+@node Records, Fields, Reading Files, Reading Files
+@section How Input is Split into Records
+
+@cindex record separator
+The @code{awk} language divides its input into records and fields.
+Records are separated by a character called the @dfn{record separator}.
+By default, the record separator is the newline character, defining
+a record to be a single line of text.@refill
+
+@iftex
+@cindex changing the record separator
+@end iftex
+@vindex RS
+Sometimes you may want to use a different character to separate your
+records. You can use a different character by changing the built-in
+variable @code{RS}. The value of @code{RS} is a string that says how
+to separate records; the default value is @code{"\n"}, the string containing
+just a newline character. This is why records are, by default, single lines.
+
+@code{RS} can have any string as its value, but only the first character
+of the string is used as the record separator. The other characters are
+ignored. @code{RS} is exceptional in this regard; @code{awk} uses the
+full value of all its other built-in variables.@refill
+
+@ignore
+Someday this should be true!
+
+The value of @code{RS} is not limited to a one-character string. It can
+be any regular expression (@pxref{Regexp, ,Regular Expressions as Patterns}).
+In general, each record
+ends at the next string that matches the regular expression; the next
+record starts at the end of the matching string. This general rule is
+actually at work in the usual case, where @code{RS} contains just a
+newline: a record ends at the beginning of the next matching string (the
+next newline in the input) and the following record starts just after
+the end of this string (at the first character of the following line).
+The newline, since it matches @code{RS}, is not part of either record.@refill
+@end ignore
+
+You can change the value of @code{RS} in the @code{awk} program with the
+assignment operator, @samp{=} (@pxref{Assignment Ops, ,Assignment Expressions}).
+The new record-separator character should be enclosed in quotation marks to make
+a string constant. Often the right time to do this is at the beginning
+of execution, before any input has been processed, so that the very
+first record will be read with the proper separator. To do this, use
+the special @code{BEGIN} pattern
+(@pxref{BEGIN/END, ,@code{BEGIN} and @code{END} Special Patterns}). For
+example:@refill
+
+@example
+awk 'BEGIN @{ RS = "/" @} ; @{ print $0 @}' BBS-list
+@end example
+
+@noindent
+changes the value of @code{RS} to @code{"/"}, before reading any input.
+This is a string whose first character is a slash; as a result, records
+are separated by slashes. Then the input file is read, and the second
+rule in the @code{awk} program (the action with no pattern) prints each
+record. Since each @code{print} statement adds a newline at the end of
+its output, the effect of this @code{awk} program is to copy the input
+with each slash changed to a newline.
+
+Another way to change the record separator is on the command line,
+using the variable-assignment feature
+(@pxref{Command Line, ,Invoking @code{awk}}).@refill
+
+@example
+awk '@{ print $0 @}' RS="/" BBS-list
+@end example
+
+@noindent
+This sets @code{RS} to @samp{/} before processing @file{BBS-list}.
+
+Reaching the end of an input file terminates the current input record,
+even if the last character in the file is not the character in @code{RS}.
+
+@ignore
+@c merge the preceding paragraph and this stuff into one paragraph
+@c and put it in an `expert info' section.
+This produces correct behavior in the vast majority of cases, although
+the following (extreme) pipeline prints a surprising @samp{1}. (There
+is one field, consisting of a newline.)
+
+@example
+echo | awk 'BEGIN @{ RS = "a" @} ; @{ print NF @}'
+@end example
+
+@end ignore
+
+The empty string, @code{""} (a string of no characters), has a special meaning
+as the value of @code{RS}: it means that records are separated only
+by blank lines. @xref{Multiple Line, ,Multiple-Line Records}, for more details.
+
+@cindex number of records, @code{NR} or @code{FNR}
+@vindex NR
+@vindex FNR
+The @code{awk} utility keeps track of the number of records that have
+been read so far from the current input file. This value is stored in a
+built-in variable called @code{FNR}. It is reset to zero when a new
+file is started. Another built-in variable, @code{NR}, is the total
+number of input records read so far from all files. It starts at zero
+but is never automatically reset to zero.
+
+If you change the value of @code{RS} in the middle of an @code{awk} run,
+the new value is used to delimit subsequent records, but the record
+currently being processed (and records already processed) are not
+affected.
+
+@node Fields, Non-Constant Fields, Records, Reading Files
+@section Examining Fields
+
+@cindex examining fields
+@cindex fields
+@cindex accessing fields
+When @code{awk} reads an input record, the record is
+automatically separated or @dfn{parsed} by the interpreter into chunks
+called @dfn{fields}. By default, fields are separated by whitespace,
+like words in a line.
+Whitespace in @code{awk} means any string of one or more spaces and/or
+tabs; other characters such as newline, formfeed, and so on, that are
+considered whitespace by other languages are @emph{not} considered
+whitespace by @code{awk}.@refill
+
+The purpose of fields is to make it more convenient for you to refer to
+these pieces of the record. You don't have to use them---you can
+operate on the whole record if you wish---but fields are what make
+simple @code{awk} programs so powerful.
+
+@cindex @code{$} (field operator)
+@cindex operators, @code{$}
+To refer to a field in an @code{awk} program, you use a dollar-sign,
+@samp{$}, followed by the number of the field you want. Thus, @code{$1}
+refers to the first field, @code{$2} to the second, and so on. For
+example, suppose the following is a line of input:@refill
+
+@example
+This seems like a pretty nice example.
+@end example
+
+@noindent
+Here the first field, or @code{$1}, is @samp{This}; the second field, or
+@code{$2}, is @samp{seems}; and so on. Note that the last field,
+@code{$7}, is @samp{example.}. Because there is no space between the
+@samp{e} and the @samp{.}, the period is considered part of the seventh
+field.@refill
+
+No matter how many fields there are, the last field in a record can be
+represented by @code{$NF}. So, in the example above, @code{$NF} would
+be the same as @code{$7}, which is @samp{example.}. Why this works is
+explained below (@pxref{Non-Constant Fields, ,Non-constant Field Numbers}).
+If you try to refer to a field beyond the last one, such as @code{$8}
+when the record has only 7 fields, you get the empty string.@refill
+
+@vindex NF
+@cindex number of fields, @code{NF}
+Plain @code{NF}, with no @samp{$}, is a built-in variable whose value
+is the number of fields in the current record.
+
+@code{$0}, which looks like an attempt to refer to the zeroth field, is
+a special case: it represents the whole input record. This is what you
+would use if you weren't interested in fields.
+
+Here are some more examples:
+
+@example
+awk '$1 ~ /foo/ @{ print $0 @}' BBS-list
+@end example
+
+@noindent
+This example prints each record in the file @file{BBS-list} whose first
+field contains the string @samp{foo}. The operator @samp{~} is called a
+@dfn{matching operator} (@pxref{Comparison Ops, ,Comparison Expressions});
+it tests whether a string (here, the field @code{$1}) matches a given regular
+expression.@refill
+
+By contrast, the following example:
+
+@example
+awk '/foo/ @{ print $1, $NF @}' BBS-list
+@end example
+
+@noindent
+looks for @samp{foo} in @emph{the entire record} and prints the first
+field and the last field for each input record containing a
+match.@refill
+
+@node Non-Constant Fields, Changing Fields, Fields, Reading Files
+@section Non-constant Field Numbers
+
+The number of a field does not need to be a constant. Any expression in
+the @code{awk} language can be used after a @samp{$} to refer to a
+field. The value of the expression specifies the field number. If the
+value is a string, rather than a number, it is converted to a number.
+Consider this example:@refill
+
+@example
+awk '@{ print $NR @}'
+@end example
+
+@noindent
+Recall that @code{NR} is the number of records read so far: 1 in the
+first record, 2 in the second, etc. So this example prints the first
+field of the first record, the second field of the second record, and so
+on. For the twentieth record, field number 20 is printed; most likely,
+the record has fewer than 20 fields, so this prints a blank line.
+
+Here is another example of using expressions as field numbers:
+
+@example
+awk '@{ print $(2*2) @}' BBS-list
+@end example
+
+The @code{awk} language must evaluate the expression @code{(2*2)} and use
+its value as the number of the field to print. The @samp{*} sign
+represents multiplication, so the expression @code{2*2} evaluates to 4.
+The parentheses are used so that the multiplication is done before the
+@samp{$} operation; they are necessary whenever there is a binary
+operator in the field-number expression. This example, then, prints the
+hours of operation (the fourth field) for every line of the file
+@file{BBS-list}.@refill
+
+If the field number you compute is zero, you get the entire record.
+Thus, @code{$(2-2)} has the same value as @code{$0}. Negative field
+numbers are not allowed.
+
+The number of fields in the current record is stored in the built-in
+variable @code{NF} (@pxref{Built-in Variables}). The expression
+@code{$NF} is not a special feature: it is the direct consequence of
+evaluating @code{NF} and using its value as a field number.
+
+@node Changing Fields, Field Separators, Non-Constant Fields, Reading Files
+@section Changing the Contents of a Field
+
+@cindex field, changing contents of
+@cindex changing contents of a field
+@cindex assignment to fields
+You can change the contents of a field as seen by @code{awk} within an
+@code{awk} program; this changes what @code{awk} perceives as the
+current input record. (The actual input is untouched: @code{awk} never
+modifies the input file.)
+
+Consider this example:
+
+@smallexample
+awk '@{ $3 = $2 - 10; print $2, $3 @}' inventory-shipped
+@end smallexample
+
+@noindent
+The @samp{-} sign represents subtraction, so this program reassigns
+field three, @code{$3}, to be the value of field two minus ten,
+@code{$2 - 10}. (@xref{Arithmetic Ops, ,Arithmetic Operators}.)
+Then field two, and the new value for field three, are printed.
+
+In order for this to work, the text in field @code{$2} must make sense
+as a number; the string of characters must be converted to a number in
+order for the computer to do arithmetic on it. The number resulting
+from the subtraction is converted back to a string of characters which
+then becomes field three.
+@xref{Conversion, ,Conversion of Strings and Numbers}.@refill
+
+When you change the value of a field (as perceived by @code{awk}), the
+text of the input record is recalculated to contain the new field where
+the old one was. Therefore, @code{$0} changes to reflect the altered
+field. Thus,
+
+@smallexample
+awk '@{ $2 = $2 - 10; print $0 @}' inventory-shipped
+@end smallexample
+
+@noindent
+prints a copy of the input file, with 10 subtracted from the second
+field of each line.
+
+You can also assign contents to fields that are out of range. For
+example:
+
+@smallexample
+awk '@{ $6 = ($5 + $4 + $3 + $2) ; print $6 @}' inventory-shipped
+@end smallexample
+
+@noindent
+We've just created @code{$6}, whose value is the sum of fields
+@code{$2}, @code{$3}, @code{$4}, and @code{$5}. The @samp{+} sign
+represents addition. For the file @file{inventory-shipped}, @code{$6}
+represents the total number of parcels shipped for a particular month.
+
+Creating a new field changes the internal @code{awk} copy of the current
+input record---the value of @code{$0}. Thus, if you do @samp{print $0}
+after adding a field, the record printed includes the new field, with
+the appropriate number of field separators between it and the previously
+existing fields.
+
+This recomputation affects and is affected by several features not yet
+discussed, in particular, the @dfn{output field separator}, @code{OFS},
+which is used to separate the fields (@pxref{Output Separators}), and
+@code{NF} (the number of fields; @pxref{Fields, ,Examining Fields}).
+For example, the value of @code{NF} is set to the number of the highest
+field you create.@refill
+
+Note, however, that merely @emph{referencing} an out-of-range field
+does @emph{not} change the value of either @code{$0} or @code{NF}.
+Referencing an out-of-range field merely produces a null string. For
+example:@refill
+
+@smallexample
+if ($(NF+1) != "")
+ print "can't happen"
+else
+ print "everything is normal"
+@end smallexample
+
+@noindent
+should print @samp{everything is normal}, because @code{NF+1} is certain
+to be out of range. (@xref{If Statement, ,The @code{if} Statement},
+for more information about @code{awk}'s @code{if-else} statements.)@refill
+
+It is important to note that assigning to a field will change the
+value of @code{$0}, but will not change the value of @code{NF},
+even when you assign the null string to a field. For example:
+
+@smallexample
+echo a b c d | awk '@{ OFS = ":"; $2 = "" ; print ; print NF @}'
+@end smallexample
+
+@noindent
+prints
+
+@smallexample
+a::c:d
+4
+@end smallexample
+
+@noindent
+The field is still there, it just has an empty value. You can tell
+because there are two colons in a row.
+
+@node Field Separators, Constant Size, Changing Fields, Reading Files
+@section Specifying how Fields are Separated
+@vindex FS
+@cindex fields, separating
+@cindex field separator, @code{FS}
+@cindex @samp{-F} option
+
+(This section is rather long; it describes one of the most fundamental
+operations in @code{awk}. If you are a novice with @code{awk}, we
+recommend that you re-read this section after you have studied the
+section on regular expressions, @ref{Regexp, ,Regular Expressions as Patterns}.)
+
+The way @code{awk} splits an input record into fields is controlled by
+the @dfn{field separator}, which is a single character or a regular
+expression. @code{awk} scans the input record for matches for the
+separator; the fields themselves are the text between the matches. For
+example, if the field separator is @samp{oo}, then the following line:
+
+@smallexample
+moo goo gai pan
+@end smallexample
+
+@noindent
+would be split into three fields: @samp{m}, @samp{@ g} and @samp{@ gai@
+pan}.
+
+The field separator is represented by the built-in variable @code{FS}.
+Shell programmers take note! @code{awk} does not use the name @code{IFS}
+which is used by the shell.@refill
+
+You can change the value of @code{FS} in the @code{awk} program with the
+assignment operator, @samp{=} (@pxref{Assignment Ops, ,Assignment Expressions}).
+Often the right time to do this is at the beginning of execution,
+before any input has been processed, so that the very first record
+will be read with the proper separator. To do this, use the special
+@code{BEGIN} pattern
+(@pxref{BEGIN/END, ,@code{BEGIN} and @code{END} Special Patterns}).
+For example, here we set the value of @code{FS} to the string
+@code{","}:@refill
+
+@smallexample
+awk 'BEGIN @{ FS = "," @} ; @{ print $2 @}'
+@end smallexample
+
+@noindent
+Given the input line,
+
+@smallexample
+John Q. Smith, 29 Oak St., Walamazoo, MI 42139
+@end smallexample
+
+@noindent
+this @code{awk} program extracts the string @samp{@ 29 Oak St.}.
+
+@cindex field separator, choice of
+@cindex regular expressions as field separators
+Sometimes your input data will contain separator characters that don't
+separate fields the way you thought they would. For instance, the
+person's name in the example we've been using might have a title or
+suffix attached, such as @samp{John Q. Smith, LXIX}. From input
+containing such a name:
+
+@smallexample
+John Q. Smith, LXIX, 29 Oak St., Walamazoo, MI 42139
+@end smallexample
+
+@noindent
+the previous sample program would extract @samp{@ LXIX}, instead of
+@samp{@ 29 Oak St.}. If you were expecting the program to print the
+address, you would be surprised. So choose your data layout and
+separator characters carefully to prevent such problems.
+
+As you know, by default, fields are separated by whitespace sequences
+(spaces and tabs), not by single spaces: two spaces in a row do not
+delimit an empty field. The default value of the field separator is a
+string @w{@code{" "}} containing a single space. If this value were
+interpreted in the usual way, each space character would separate
+fields, so two spaces in a row would make an empty field between them.
+The reason this does not happen is that a single space as the value of
+@code{FS} is a special case: it is taken to specify the default manner
+of delimiting fields.
+
+If @code{FS} is any other single character, such as @code{","}, then
+each occurrence of that character separates two fields. Two consecutive
+occurrences delimit an empty field. If the character occurs at the
+beginning or the end of the line, that too delimits an empty field. The
+space character is the only single character which does not follow these
+rules.
+
+More generally, the value of @code{FS} may be a string containing any
+regular expression. Then each match in the record for the regular
+expression separates fields. For example, the assignment:@refill
+
+@smallexample
+FS = ", \t"
+@end smallexample
+
+@noindent
+makes every area of an input line that consists of a comma followed by a
+space and a tab, into a field separator. (@samp{\t} stands for a
+tab.)@refill
+
+For a less trivial example of a regular expression, suppose you want
+single spaces to separate fields the way single commas were used above.
+You can set @code{FS} to @w{@code{"[@ ]"}}. This regular expression
+matches a single space and nothing else.
+
+@c the following index entry is an overfull hbox. --mew 30jan1992
+@cindex field separator: on command line
+@cindex command line, setting @code{FS} on
+@code{FS} can be set on the command line. You use the @samp{-F} argument to
+do so. For example:
+
+@smallexample
+awk -F, '@var{program}' @var{input-files}
+@end smallexample
+
+@noindent
+sets @code{FS} to be the @samp{,} character. Notice that the argument uses
+a capital @samp{F}. Contrast this with @samp{-f}, which specifies a file
+containing an @code{awk} program. Case is significant in command options:
+the @samp{-F} and @samp{-f} options have nothing to do with each other.
+You can use both options at the same time to set the @code{FS} argument
+@emph{and} get an @code{awk} program from a file.@refill
+
+@c begin expert info
+The value used for the argument to @samp{-F} is processed in exactly the
+same way as assignments to the built-in variable @code{FS}. This means that
+if the field separator contains special characters, they must be escaped
+appropriately. For example, to use a @samp{\} as the field separator, you
+would have to type:
+
+@smallexample
+# same as FS = "\\"
+awk -F\\\\ '@dots{}' files @dots{}
+@end smallexample
+
+@noindent
+Since @samp{\} is used for quoting in the shell, @code{awk} will see
+@samp{-F\\}. Then @code{awk} processes the @samp{\\} for escape
+characters (@pxref{Constants, ,Constant Expressions}), finally yielding
+a single @samp{\} to be used for the field separator.
+@c end expert info
+
+As a special case, in compatibility mode
+(@pxref{Command Line, ,Invoking @code{awk}}), if the
+argument to @samp{-F} is @samp{t}, then @code{FS} is set to the tab
+character. (This is because if you type @samp{-F\t}, without the quotes,
+at the shell, the @samp{\} gets deleted, so @code{awk} figures that you
+really want your fields to be separated with tabs, and not @samp{t}s.
+Use @samp{-v FS="t"} on the command line if you really do want to separate
+your fields with @samp{t}s.)@refill
+
+For example, let's use an @code{awk} program file called @file{baud.awk}
+that contains the pattern @code{/300/}, and the action @samp{print $1}.
+Here is the program:
+
+@smallexample
+/300/ @{ print $1 @}
+@end smallexample
+
+Let's also set @code{FS} to be the @samp{-} character, and run the
+program on the file @file{BBS-list}. The following command prints a
+list of the names of the bulletin boards that operate at 300 baud and
+the first three digits of their phone numbers:@refill
+
+@smallexample
+awk -F- -f baud.awk BBS-list
+@end smallexample
+
+@noindent
+It produces this output:
+
+@smallexample
+aardvark 555
+alpo
+barfly 555
+bites 555
+camelot 555
+core 555
+fooey 555
+foot 555
+macfoo 555
+sdace 555
+sabafoo 555
+@end smallexample
+
+@noindent
+Note the second line of output. If you check the original file, you will
+see that the second line looked like this:
+
+@smallexample
+alpo-net 555-3412 2400/1200/300 A
+@end smallexample
+
+The @samp{-} as part of the system's name was used as the field
+separator, instead of the @samp{-} in the phone number that was
+originally intended. This demonstrates why you have to be careful in
+choosing your field and record separators.
+
+The following program searches the system password file, and prints
+the entries for users who have no password:
+
+@smallexample
+awk -F: '$2 == ""' /etc/passwd
+@end smallexample
+
+@noindent
+Here we use the @samp{-F} option on the command line to set the field
+separator. Note that fields in @file{/etc/passwd} are separated by
+colons. The second field represents a user's encrypted password, but if
+the field is empty, that user has no password.
+
+@c begin expert info
+According to the @sc{posix} standard, @code{awk} is supposed to behave
+as if each record is split into fields at the time that it is read.
+In particular, this means that you can change the value of @code{FS}
+after a record is read, but before any of the fields are referenced.
+The value of the fields (i.e. how they were split) should reflect the
+old value of @code{FS}, not the new one.
+
+However, many implementations of @code{awk} do not do this. Instead,
+they defer splitting the fields until a field reference actually happens,
+using the @emph{current} value of @code{FS}! This behavior can be difficult
+to diagnose. The following example illustrates the results of the two methods.
+(The @code{sed} command prints just the first line of @file{/etc/passwd}.)
+
+@smallexample
+sed 1q /etc/passwd | awk '@{ FS = ":" ; print $1 @}'
+@end smallexample
+
+@noindent
+will usually print
+
+@smallexample
+root
+@end smallexample
+
+@noindent
+on an incorrect implementation of @code{awk}, while @code{gawk}
+will print something like
+
+@smallexample
+root:nSijPlPhZZwgE:0:0:Root:/:
+@end smallexample
+@c end expert info
+
+@c begin expert info
+There is an important difference between the two cases of @samp{FS = @w{" "}}
+(a single blank) and @samp{FS = @w{"[ \t]+"}} (which is a regular expression
+matching one or more blanks or tabs). For both values of @code{FS}, fields
+are separated by runs of blanks and/or tabs. However, when the value of
+@code{FS} is @code{" "}, @code{awk} will strip leading and trailing whitespace
+from the record, and then decide where the fields are.
+
+For example, the following expression prints @samp{b}:
+
+@smallexample
+echo ' a b c d ' | awk '@{ print $2 @}'
+@end smallexample
+
+@noindent
+However, the following prints @samp{a}:
+
+@smallexample
+echo ' a b c d ' | awk 'BEGIN @{ FS = "[ \t]+" @} ; @{ print $2 @}'
+@end smallexample
+
+@noindent
+In this case, the first field is null.
+
+The stripping of leading and trailing whitespace also comes into
+play whenever @code{$0} is recomputed. For instance, this pipeline
+
+@smallexample
+echo ' a b c d' | awk '@{ print; $2 = $2; print @}'
+@end smallexample
+
+@noindent
+produces this output:
+
+@smallexample
+ a b c d
+a b c d
+@end smallexample
+
+@noindent
+The first @code{print} statement prints the record as it was read,
+with leading whitespace intact. The assignment to @code{$2} rebuilds
+@code{$0} by concatenating @code{$1} through @code{$NF} together,
+separated by the value of @code{OFS}. Since the leading whitespace
+was ignored when finding @code{$1}, it is not part of the new @code{$0}.
+Finally, the last @code{print} statement prints the new @code{$0}.
+@c end expert info
+
+The following table summarizes how fields are split, based on the
+value of @code{FS}.
+
+@table @code
+@item FS == " "
+Fields are separated by runs of whitespace. Leading and trailing
+whitespace are ignored. This is the default.
+
+@item FS == @var{any single character}
+Fields are separated by each occurrence of the character. Multiple
+successive occurrences delimit empty fields, as do leading and
+trailing occurrences.
+
+@item FS == @var{regexp}
+Fields are separated by occurrences of characters that match @var{regexp}.
+Leading and trailing matches of @var{regexp} delimit empty fields.
+@end table
+
+@node Constant Size, Multiple Line, Field Separators, Reading Files
+@section Reading Fixed-width Data
+
+(This section discusses an advanced, experimental feature. If you are
+a novice @code{awk} user, you may wish to skip it on the first reading.)
+
+@code{gawk} 2.13 introduced a new facility for dealing with fixed-width fields
+with no distinctive field separator. Data of this nature arises typically
+in one of at least two ways: the input for old FORTRAN programs where
+numbers are run together, and the output of programs that did not anticipate
+the use of their output as input for other programs.
+
+An example of the latter is a table where all the columns are lined up by
+the use of a variable number of spaces and @emph{empty fields are just
+spaces}. Clearly, @code{awk}'s normal field splitting based on @code{FS}
+will not work well in this case. (Although a portable @code{awk} program
+can use a series of @code{substr} calls on @code{$0}, this is awkward and
+inefficient for a large number of fields.)@refill
+
+The splitting of an input record into fixed-width fields is specified by
+assigning a string containing space-separated numbers to the built-in
+variable @code{FIELDWIDTHS}. Each number specifies the width of the field
+@emph{including} columns between fields. If you want to ignore the columns
+between fields, you can specify the width as a separate field that is
+subsequently ignored.
+
+The following data is the output of the @code{w} utility. It is useful
+to illustrate the use of @code{FIELDWIDTHS}.
+
+@smallexample
+ 10:06pm up 21 days, 14:04, 23 users
+User tty login@ idle JCPU PCPU what
+hzuo ttyV0 8:58pm 9 5 vi p24.tex
+hzang ttyV3 6:37pm 50 -csh
+eklye ttyV5 9:53pm 7 1 em thes.tex
+dportein ttyV6 8:17pm 1:47 -csh
+gierd ttyD3 10:00pm 1 elm
+dave ttyD4 9:47pm 4 4 w
+brent ttyp0 26Jun91 4:46 26:46 4:41 bash
+dave ttyq4 26Jun9115days 46 46 wnewmail
+@end smallexample
+
+The following program takes the above input, converts the idle time to
+number of seconds and prints out the first two fields and the calculated
+idle time. (This program uses a number of @code{awk} features that
+haven't been introduced yet.)@refill
+
+@smallexample
+BEGIN @{ FIELDWIDTHS = "9 6 10 6 7 7 35" @}
+NR > 2 @{
+ idle = $4
+ sub(/^ */, "", idle) # strip leading spaces
+ if (idle == "") idle = 0
+ if (idle ~ /:/) @{ split(idle, t, ":"); idle = t[1] * 60 + t[2] @}
+ if (idle ~ /days/) @{ idle *= 24 * 60 * 60 @}
+
+ print $1, $2, idle
+@}
+@end smallexample
+
+Here is the result of running the program on the data:
+
+@smallexample
+hzuo ttyV0 0
+hzang ttyV3 50
+eklye ttyV5 0
+dportein ttyV6 107
+gierd ttyD3 1
+dave ttyD4 0
+brent ttyp0 286
+dave ttyq4 1296000
+@end smallexample
+
+Another (possibly more practical) example of fixed-width input data
+would be the input from a deck of balloting cards. In some parts of
+the United States, voters make their choices by punching holes in computer
+cards. These cards are then processed to count the votes for any particular
+candidate or on any particular issue. Since a voter may choose not to
+vote on some issue, any column on the card may be empty. An @code{awk}
+program for processing such data could use the @code{FIELDWIDTHS} feature
+to simplify reading the data.@refill
+
+@c of course, getting gawk to run on a system with card readers is
+@c another story!
+
+This feature is still experimental, and will likely evolve over time.
+
+@node Multiple Line, Getline, Constant Size, Reading Files
+@section Multiple-Line Records
+
+@cindex multiple line records
+@cindex input, multiple line records
+@cindex reading files, multiple line records
+@cindex records, multiple line
+In some data bases, a single line cannot conveniently hold all the
+information in one entry. In such cases, you can use multi-line
+records.
+
+The first step in doing this is to choose your data format: when records
+are not defined as single lines, how do you want to define them?
+What should separate records?
+
+One technique is to use an unusual character or string to separate
+records. For example, you could use the formfeed character (written
+@code{\f} in @code{awk}, as in C) to separate them, making each record
+a page of the file. To do this, just set the variable @code{RS} to
+@code{"\f"} (a string containing the formfeed character). Any
+other character could equally well be used, as long as it won't be part
+of the data in a record.@refill
+
+@ignore
+Another technique is to have blank lines separate records. The string
+@code{"^\n+"} is a regular expression that matches any sequence of
+newlines starting at the beginning of a line---in other words, it
+matches a sequence of blank lines. If you set @code{RS} to this string,
+a record always ends at the first blank line encountered. In
+addition, a regular expression always matches the longest possible
+sequence when there is a choice. So the next record doesn't start until
+the first nonblank line that follows---no matter how many blank lines
+appear in a row, they are considered one record-separator.
+@end ignore
+
+Another technique is to have blank lines separate records. By a special
+dispensation, a null string as the value of @code{RS} indicates that
+records are separated by one or more blank lines. If you set @code{RS}
+to the null string, a record always ends at the first blank line
+encountered. And the next record doesn't start until the first nonblank
+line that follows---no matter how many blank lines appear in a row, they
+are considered one record-separator. (End of file is also considered
+a record separator.)@refill
+@c !!! This use of `end of file' is confusing. Needs to be clarified.
+
+The second step is to separate the fields in the record. One way to do
+this is to put each field on a separate line: to do this, just set the
+variable @code{FS} to the string @code{"\n"}. (This simple regular
+expression matches a single newline.)
+
+Another way to separate fields is to divide each of the lines into fields
+in the normal manner. This happens by default as a result of a special
+feature: when @code{RS} is set to the null string, the newline character
+@emph{always} acts as a field separator. This is in addition to whatever
+field separations result from @code{FS}.
+
+The original motivation for this special exception was probably so that
+you get useful behavior in the default case (i.e., @w{@code{FS == " "}}).
+This feature can be a problem if you really don't want the
+newline character to separate fields, since there is no way to
+prevent it. However, you can work around this by using the @code{split}
+function to break up the record manually
+(@pxref{String Functions, ,Built-in Functions for String Manipulation}).@refill
+
+@ignore
+Here are two ways to use records separated by blank lines and break each
+line into fields normally:
+
+@example
+awk 'BEGIN @{ RS = ""; FS = "[ \t\n]+" @} @{ print $1 @}' BBS-list
+
+@exdent @r{or}
+
+awk 'BEGIN @{ RS = "^\n+"; FS = "[ \t\n]+" @} @{ print $1 @}' BBS-list
+@end example
+@end ignore
+
+@ignore
+Here is how to use records separated by blank lines and break each
+line into fields normally:
+
+@example
+awk 'BEGIN @{ RS = ""; FS = "[ \t\n]+" @} ; @{ print $1 @}' BBS-list
+@end example
+@end ignore
+
+@node Getline, Close Input, Multiple Line, Reading Files
+@section Explicit Input with @code{getline}
+
+@findex getline
+@cindex input, explicit
+@cindex explicit input
+@cindex input, @code{getline} command
+@cindex reading files, @code{getline} command
+So far we have been getting our input files from @code{awk}'s main
+input stream---either the standard input (usually your terminal) or the
+files specified on the command line. The @code{awk} language has a
+special built-in command called @code{getline} that
+can be used to read input under your explicit control.@refill
+
+This command is quite complex and should @emph{not} be used by
+beginners. It is covered here because this is the chapter on input.
+The examples that follow the explanation of the @code{getline} command
+include material that has not been covered yet. Therefore, come back
+and study the @code{getline} command @emph{after} you have reviewed the
+rest of this manual and have a good knowledge of how @code{awk} works.
+
+@vindex ERRNO
+@cindex differences: @code{gawk} and @code{awk}
+@code{getline} returns 1 if it finds a record, and 0 if the end of the
+file is encountered. If there is some error in getting a record, such
+as a file that cannot be opened, then @code{getline} returns @minus{}1.
+In this case, @code{gawk} sets the variable @code{ERRNO} to a string
+describing the error that occurred.
+
+In the following examples, @var{command} stands for a string value that
+represents a shell command.
+
+@table @code
+@item getline
+The @code{getline} command can be used without arguments to read input
+from the current input file. All it does in this case is read the next
+input record and split it up into fields. This is useful if you've
+finished processing the current record, but you want to do some special
+processing @emph{right now} on the next record. Here's an
+example:@refill
+
+@example
+awk '@{
+ if (t = index($0, "/*")) @{
+ if (t > 1)
+ tmp = substr($0, 1, t - 1)
+ else
+ tmp = ""
+ u = index(substr($0, t + 2), "*/")
+ while (u == 0) @{
+ getline
+ t = -1
+ u = index($0, "*/")
+ @}
+ if (u <= length($0) - 2)
+ $0 = tmp substr($0, t + u + 3)
+ else
+ $0 = tmp
+ @}
+ print $0
+@}'
+@end example
+
+This @code{awk} program deletes all C-style comments, @samp{/* @dots{}
+*/}, from the input. By replacing the @samp{print $0} with other
+statements, you could perform more complicated processing on the
+decommented input, like searching for matches of a regular
+expression. (This program has a subtle problem---can you spot it?)
+
+@c the program to remove comments doesn't work if one
+@c comment ends and another begins on the same line. (Your
+@c idea for restart would be useful here). --- brennan@boeing.com
+
+This form of the @code{getline} command sets @code{NF} (the number of
+fields; @pxref{Fields, ,Examining Fields}), @code{NR} (the number of
+records read so far; @pxref{Records, ,How Input is Split into Records}),
+@code{FNR} (the number of records read from this input file), and the
+value of @code{$0}.
+
+@strong{Note:} the new value of @code{$0} is used in testing
+the patterns of any subsequent rules. The original value
+of @code{$0} that triggered the rule which executed @code{getline}
+is lost. By contrast, the @code{next} statement reads a new record
+but immediately begins processing it normally, starting with the first
+rule in the program. @xref{Next Statement, ,The @code{next} Statement}.
+
+@item getline @var{var}
+This form of @code{getline} reads a record into the variable @var{var}.
+This is useful when you want your program to read the next record from
+the current input file, but you don't want to subject the record to the
+normal input processing.
+
+For example, suppose the next line is a comment, or a special string,
+and you want to read it, but you must make certain that it won't trigger
+any rules. This version of @code{getline} allows you to read that line
+and store it in a variable so that the main
+read-a-line-and-check-each-rule loop of @code{awk} never sees it.
+
+The following example swaps every two lines of input. For example, given:
+
+@example
+wan
+tew
+free
+phore
+@end example
+
+@noindent
+it outputs:
+
+@example
+tew
+wan
+phore
+free
+@end example
+
+@noindent
+Here's the program:
+
+@example
+@group
+awk '@{
+ if ((getline tmp) > 0) @{
+ print tmp
+ print $0
+ @} else
+ print $0
+@}'
+@end group
+@end example
+
+The @code{getline} function used in this way sets only the variables
+@code{NR} and @code{FNR} (and of course, @var{var}). The record is not
+split into fields, so the values of the fields (including @code{$0}) and
+the value of @code{NF} do not change.@refill
+
+@item getline < @var{file}
+@cindex input redirection
+@cindex redirection of input
+This form of the @code{getline} function takes its input from the file
+@var{file}. Here @var{file} is a string-valued expression that
+specifies the file name. @samp{< @var{file}} is called a @dfn{redirection}
+since it directs input to come from a different place.
+
+This form is useful if you want to read your input from a particular
+file, instead of from the main input stream. For example, the following
+program reads its input record from the file @file{foo.input} when it
+encounters a first field with a value equal to 10 in the current input
+file.@refill
+
+@example
+awk '@{
+ if ($1 == 10) @{
+ getline < "foo.input"
+ print
+ @} else
+ print
+@}'
+@end example
+
+Since the main input stream is not used, the values of @code{NR} and
+@code{FNR} are not changed. But the record read is split into fields in
+the normal manner, so the values of @code{$0} and other fields are
+changed. So is the value of @code{NF}.
+
+This does not cause the record to be tested against all the patterns
+in the @code{awk} program, in the way that would happen if the record
+were read normally by the main processing loop of @code{awk}. However
+the new record is tested against any subsequent rules, just as when
+@code{getline} is used without a redirection.
+
+@item getline @var{var} < @var{file}
+This form of the @code{getline} function takes its input from the file
+@var{file} and puts it in the variable @var{var}. As above, @var{file}
+is a string-valued expression that specifies the file from which to read.
+
+In this version of @code{getline}, none of the built-in variables are
+changed, and the record is not split into fields. The only variable
+changed is @var{var}.
+
+For example, the following program copies all the input files to the
+output, except for records that say @w{@samp{@@include @var{filename}}}.
+Such a record is replaced by the contents of the file
+@var{filename}.@refill
+
+@example
+awk '@{
+ if (NF == 2 && $1 == "@@include") @{
+ while ((getline line < $2) > 0)
+ print line
+ close($2)
+ @} else
+ print
+@}'
+@end example
+
+Note here how the name of the extra input file is not built into
+the program; it is taken from the data, from the second field on
+the @samp{@@include} line.@refill
+
+The @code{close} function is called to ensure that if two identical
+@samp{@@include} lines appear in the input, the entire specified file is
+included twice. @xref{Close Input, ,Closing Input Files and Pipes}.@refill
+
+One deficiency of this program is that it does not process nested
+@samp{@@include} statements the way a true macro preprocessor would.
+
+@item @var{command} | getline
+You can @dfn{pipe} the output of a command into @code{getline}. A pipe is
+simply a way to link the output of one program to the input of another. In
+this case, the string @var{command} is run as a shell command and its output
+is piped into @code{awk} to be used as input. This form of @code{getline}
+reads one record from the pipe.
+
+For example, the following program copies input to output, except for lines
+that begin with @samp{@@execute}, which are replaced by the output produced by
+running the rest of the line as a shell command:
+
+@example
+awk '@{
+ if ($1 == "@@execute") @{
+ tmp = substr($0, 10)
+ while ((tmp | getline) > 0)
+ print
+ close(tmp)
+ @} else
+ print
+@}'
+@end example
+
+@noindent
+The @code{close} function is called to ensure that if two identical
+@samp{@@execute} lines appear in the input, the command is run for
+each one. @xref{Close Input, ,Closing Input Files and Pipes}.
+
+Given the input:
+
+@example
+foo
+bar
+baz
+@@execute who
+bletch
+@end example
+
+@noindent
+the program might produce:
+
+@example
+foo
+bar
+baz
+hack ttyv0 Jul 13 14:22
+hack ttyp0 Jul 13 14:23 (gnu:0)
+hack ttyp1 Jul 13 14:23 (gnu:0)
+hack ttyp2 Jul 13 14:23 (gnu:0)
+hack ttyp3 Jul 13 14:23 (gnu:0)
+bletch
+@end example
+
+@noindent
+Notice that this program ran the command @code{who} and printed the result.
+(If you try this program yourself, you will get different results, showing
+you who is logged in on your system.)
+
+This variation of @code{getline} splits the record into fields, sets the
+value of @code{NF} and recomputes the value of @code{$0}. The values of
+@code{NR} and @code{FNR} are not changed.
+
+@item @var{command} | getline @var{var}
+The output of the command @var{command} is sent through a pipe to
+@code{getline} and into the variable @var{var}. For example, the
+following program reads the current date and time into the variable
+@code{current_time}, using the @code{date} utility, and then
+prints it.@refill
+
+@example
+awk 'BEGIN @{
+ "date" | getline current_time
+ close("date")
+ print "Report printed on " current_time
+@}'
+@end example
+
+In this version of @code{getline}, none of the built-in variables are
+changed, and the record is not split into fields.
+@end table
+
+@node Close Input, , Getline, Reading Files
+@section Closing Input Files and Pipes
+@cindex closing input files and pipes
+@findex close
+
+If the same file name or the same shell command is used with
+@code{getline} more than once during the execution of an @code{awk}
+program, the file is opened (or the command is executed) only the first time.
+At that time, the first record of input is read from that file or command.
+The next time the same file or command is used in @code{getline}, another
+record is read from it, and so on.
+
+This implies that if you want to start reading the same file again from
+the beginning, or if you want to rerun a shell command (rather than
+reading more output from the command), you must take special steps.
+What you must do is use the @code{close} function, as follows:
+
+@example
+close(@var{filename})
+@end example
+
+@noindent
+or
+
+@example
+close(@var{command})
+@end example
+
+The argument @var{filename} or @var{command} can be any expression. Its
+value must exactly equal the string that was used to open the file or
+start the command---for example, if you open a pipe with this:
+
+@example
+"sort -r names" | getline foo
+@end example
+
+@noindent
+then you must close it with this:
+
+@example
+close("sort -r names")
+@end example
+
+Once this function call is executed, the next @code{getline} from that
+file or command will reopen the file or rerun the command.
+
+@iftex
+@vindex ERRNO
+@cindex differences: @code{gawk} and @code{awk}
+@end iftex
+@code{close} returns a value of zero if the close succeeded.
+Otherwise, the value will be non-zero.
+In this case, @code{gawk} sets the variable @code{ERRNO} to a string
+describing the error that occurred.
+
+@node Printing, One-liners, Reading Files, Top
+@chapter Printing Output
+
+@cindex printing
+@cindex output
+One of the most common things that actions do is to output or @dfn{print}
+some or all of the input. For simple output, use the @code{print}
+statement. For fancier formatting use the @code{printf} statement.
+Both are described in this chapter.
+
+@menu
+* Print:: The @code{print} statement.
+* Print Examples:: Simple examples of @code{print} statements.
+* Output Separators:: The output separators and how to change them.
+* OFMT:: Controlling Numeric Output With @code{print}.
+* Printf:: The @code{printf} statement.
+* Redirection:: How to redirect output to multiple
+ files and pipes.
+* Special Files:: File name interpretation in @code{gawk}.
+ @code{gawk} allows access to
+ inherited file descriptors.
+@end menu
+
+@node Print, Print Examples, Printing, Printing
+@section The @code{print} Statement
+@cindex @code{print} statement
+
+The @code{print} statement does output with simple, standardized
+formatting. You specify only the strings or numbers to be printed, in a
+list separated by commas. They are output, separated by single spaces,
+followed by a newline. The statement looks like this:
+
+@example
+print @var{item1}, @var{item2}, @dots{}
+@end example
+
+@noindent
+The entire list of items may optionally be enclosed in parentheses. The
+parentheses are necessary if any of the item expressions uses a
+relational operator; otherwise it could be confused with a redirection
+(@pxref{Redirection, ,Redirecting Output of @code{print} and @code{printf}}).
+The relational operators are @samp{==},
+@samp{!=}, @samp{<}, @samp{>}, @samp{>=}, @samp{<=}, @samp{~} and
+@samp{!~} (@pxref{Comparison Ops, ,Comparison Expressions}).@refill
+
+The items printed can be constant strings or numbers, fields of the
+current record (such as @code{$1}), variables, or any @code{awk}
+expressions. The @code{print} statement is completely general for
+computing @emph{what} values to print. With two exceptions,
+you cannot specify @emph{how} to print them---how many
+columns, whether to use exponential notation or not, and so on.
+(@xref{Output Separators}, and
+@ref{OFMT, ,Controlling Numeric Output with @code{print}}.)
+For that, you need the @code{printf} statement
+(@pxref{Printf, ,Using @code{printf} Statements for Fancier Printing}).@refill
+
+The simple statement @samp{print} with no items is equivalent to
+@samp{print $0}: it prints the entire current record. To print a blank
+line, use @samp{print ""}, where @code{""} is the null, or empty,
+string.
+
+To print a fixed piece of text, use a string constant such as
+@w{@code{"Hello there"}} as one item. If you forget to use the
+double-quote characters, your text will be taken as an @code{awk}
+expression, and you will probably get an error. Keep in mind that a
+space is printed between any two items.
+
+Most often, each @code{print} statement makes one line of output. But it
+isn't limited to one line. If an item value is a string that contains a
+newline, the newline is output along with the rest of the string. A
+single @code{print} can make any number of lines this way.
+
+@node Print Examples, Output Separators, Print, Printing
+@section Examples of @code{print} Statements
+
+Here is an example of printing a string that contains embedded newlines:
+
+@example
+awk 'BEGIN @{ print "line one\nline two\nline three" @}'
+@end example
+
+@noindent
+produces output like this:
+
+@example
+line one
+line two
+line three
+@end example
+
+Here is an example that prints the first two fields of each input record,
+with a space between them:
+
+@example
+awk '@{ print $1, $2 @}' inventory-shipped
+@end example
+
+@noindent
+Its output looks like this:
+
+@example
+Jan 13
+Feb 15
+Mar 15
+@dots{}
+@end example
+
+A common mistake in using the @code{print} statement is to omit the comma
+between two items. This often has the effect of making the items run
+together in the output, with no space. The reason for this is that
+juxtaposing two string expressions in @code{awk} means to concatenate
+them. For example, without the comma:
+
+@example
+awk '@{ print $1 $2 @}' inventory-shipped
+@end example
+
+@noindent
+prints:
+
+@example
+@group
+Jan13
+Feb15
+Mar15
+@dots{}
+@end group
+@end example
+
+Neither example's output makes much sense to someone unfamiliar with the
+file @file{inventory-shipped}. A heading line at the beginning would make
+it clearer. Let's add some headings to our table of months (@code{$1}) and
+green crates shipped (@code{$2}). We do this using the @code{BEGIN} pattern
+(@pxref{BEGIN/END, ,@code{BEGIN} and @code{END} Special Patterns}) to force the headings to be printed only once:
+
+@example
+awk 'BEGIN @{ print "Month Crates"
+ print "----- ------" @}
+ @{ print $1, $2 @}' inventory-shipped
+@end example
+
+@noindent
+Did you already guess what happens? This program prints the following:
+
+@example
+@group
+Month Crates
+----- ------
+Jan 13
+Feb 15
+Mar 15
+@dots{}
+@end group
+@end example
+
+@noindent
+The headings and the table data don't line up! We can fix this by printing
+some spaces between the two fields:
+
+@example
+awk 'BEGIN @{ print "Month Crates"
+ print "----- ------" @}
+ @{ print $1, " ", $2 @}' inventory-shipped
+@end example
+
+You can imagine that this way of lining up columns can get pretty
+complicated when you have many columns to fix. Counting spaces for two
+or three columns can be simple, but more than this and you can get
+``lost'' quite easily. This is why the @code{printf} statement was
+created (@pxref{Printf, ,Using @code{printf} Statements for Fancier Printing});
+one of its specialties is lining up columns of data.@refill
+
+@node Output Separators, OFMT, Print Examples, Printing
+@section Output Separators
+
+@cindex output field separator, @code{OFS}
+@vindex OFS
+@vindex ORS
+@cindex output record separator, @code{ORS}
+As mentioned previously, a @code{print} statement contains a list
+of items, separated by commas. In the output, the items are normally
+separated by single spaces. But they do not have to be spaces; a
+single space is only the default. You can specify any string of
+characters to use as the @dfn{output field separator} by setting the
+built-in variable @code{OFS}. The initial value of this variable
+is the string @w{@code{" "}}, that is, just a single space.@refill
+
+The output from an entire @code{print} statement is called an
+@dfn{output record}. Each @code{print} statement outputs one output
+record and then outputs a string called the @dfn{output record separator}.
+The built-in variable @code{ORS} specifies this string. The initial
+value of the variable is the string @code{"\n"} containing a newline
+character; thus, normally each @code{print} statement makes a separate line.
+
+You can change how output fields and records are separated by assigning
+new values to the variables @code{OFS} and/or @code{ORS}. The usual
+place to do this is in the @code{BEGIN} rule
+(@pxref{BEGIN/END, ,@code{BEGIN} and @code{END} Special Patterns}), so
+that it happens before any input is processed. You may also do this
+with assignments on the command line, before the names of your input
+files.@refill
+
+The following example prints the first and second fields of each input
+record separated by a semicolon, with a blank line added after each
+line:@refill
+
+@example
+@group
+awk 'BEGIN @{ OFS = ";"; ORS = "\n\n" @}
+ @{ print $1, $2 @}' BBS-list
+@end group
+@end example
+
+If the value of @code{ORS} does not contain a newline, all your output
+will be run together on a single line, unless you output newlines some
+other way.
+
+@node OFMT, Printf, Output Separators, Printing
+@section Controlling Numeric Output with @code{print}
+@vindex OFMT
+When you use the @code{print} statement to print numeric values,
+@code{awk} internally converts the number to a string of characters,
+and prints that string. @code{awk} uses the @code{sprintf} function
+to do this conversion. For now, it suffices to say that the @code{sprintf}
+function accepts a @dfn{format specification} that tells it how to format
+numbers (or strings), and that there are a number of different ways that
+numbers can be formatted. The different format specifications are discussed
+more fully in
+@ref{Printf, ,Using @code{printf} Statements for Fancier Printing}.@refill
+
+The built-in variable @code{OFMT} contains the default format specification
+that @code{print} uses with @code{sprintf} when it wants to convert a
+number to a string for printing. By supplying different format specifications
+as the value of @code{OFMT}, you can change how @code{print} will print
+your numbers. As a brief example:
+
+@example
+@group
+awk 'BEGIN @{ OFMT = "%d" # print numbers as integers
+ print 17.23 @}'
+@end group
+@end example
+
+@noindent
+will print @samp{17}.
+
+@node Printf, Redirection, OFMT, Printing
+@section Using @code{printf} Statements for Fancier Printing
+@cindex formatted output
+@cindex output, formatted
+
+If you want more precise control over the output format than
+@code{print} gives you, use @code{printf}. With @code{printf} you can
+specify the width to use for each item, and you can specify various
+stylistic choices for numbers (such as what radix to use, whether to
+print an exponent, whether to print a sign, and how many digits to print
+after the decimal point). You do this by specifying a string, called
+the @dfn{format string}, which controls how and where to print the other
+arguments.
+
+@menu
+* Basic Printf:: Syntax of the @code{printf} statement.
+* Control Letters:: Format-control letters.
+* Format Modifiers:: Format-specification modifiers.
+* Printf Examples:: Several examples.
+@end menu
+
+@node Basic Printf, Control Letters, Printf, Printf
+@subsection Introduction to the @code{printf} Statement
+
+@cindex @code{printf} statement, syntax of
+The @code{printf} statement looks like this:@refill
+
+@example
+printf @var{format}, @var{item1}, @var{item2}, @dots{}
+@end example
+
+@noindent
+The entire list of arguments may optionally be enclosed in parentheses. The
+parentheses are necessary if any of the item expressions uses a
+relational operator; otherwise it could be confused with a redirection
+(@pxref{Redirection, ,Redirecting Output of @code{print} and @code{printf}}).
+The relational operators are @samp{==},
+@samp{!=}, @samp{<}, @samp{>}, @samp{>=}, @samp{<=}, @samp{~} and
+@samp{!~} (@pxref{Comparison Ops, ,Comparison Expressions}).@refill
+
+@cindex format string
+The difference between @code{printf} and @code{print} is the argument
+@var{format}. This is an expression whose value is taken as a string; it
+specifies how to output each of the other arguments. It is called
+the @dfn{format string}.
+
+The format string is the same as in the @sc{ansi} C library function
+@code{printf}. Most of @var{format} is text to be output verbatim.
+Scattered among this text are @dfn{format specifiers}, one per item.
+Each format specifier says to output the next item at that place in the
+format.@refill
+
+The @code{printf} statement does not automatically append a newline to its
+output. It outputs only what the format specifies. So if you want
+a newline, you must include one in the format. The output separator
+variables @code{OFS} and @code{ORS} have no effect on @code{printf}
+statements.@refill
+
+@node Control Letters, Format Modifiers, Basic Printf, Printf
+@subsection Format-Control Letters
+@cindex @code{printf}, format-control characters
+@cindex format specifier
+
+A format specifier starts with the character @samp{%} and ends with a
+@dfn{format-control letter}; it tells the @code{printf} statement how
+to output one item. (If you actually want to output a @samp{%}, write
+@samp{%%}.) The format-control letter specifies what kind of value to
+print. The rest of the format specifier is made up of optional
+@dfn{modifiers} which are parameters such as the field width to use.@refill
+
+Here is a list of the format-control letters:
+
+@table @samp
+@item c
+This prints a number as an ASCII character. Thus, @samp{printf "%c",
+65} outputs the letter @samp{A}. The output for a string value is
+the first character of the string.
+
+@item d
+This prints a decimal integer.
+
+@item i
+This also prints a decimal integer.
+
+@item e
+This prints a number in scientific (exponential) notation.
+For example,
+
+@example
+printf "%4.3e", 1950
+@end example
+
+@noindent
+prints @samp{1.950e+03}, with a total of four significant figures of
+which three follow the decimal point. The @samp{4.3} are @dfn{modifiers},
+discussed below.
+
+@item f
+This prints a number in floating point notation.
+
+@item g
+This prints a number in either scientific notation or floating point
+notation, whichever uses fewer characters.
+@ignore
+From: gatech!ames!elroy!cit-vax!EQL.Caltech.Edu!rankin (Pat Rankin)
+
+In the description of printf formats (p.43), the information for %g
+is incorrect (mainly, it's too much of an oversimplification). It's
+wrong in the AWK book too, and in the gawk man page. I suggested to
+David Trueman before 2.13 was released that the latter be revised, so
+that it matched gawk's behavior (rather than trying to change gawk to
+match the docs ;-). The documented description is nice and simple, but
+it doesn't match the actual underlying behavior of %g in the various C
+run-time libraries that gawk relies on. The precision value for g format
+is different than for f and e formats, so it's inaccurate to say 'g' is
+the shorter of 'e' or 'f'. For 'g', precision represents the number of
+significant digits rather than the number of decimal places, and it has
+special rules about how to format numbers with range between 10E-1 and
+10E-4. All in all, it's pretty messy, and I had to add that clumsy
+GFMT_WORKAROUND code because the VMS run-time library doesn't conform to
+the ANSI-C specifications.
+@end ignore
+
+@item o
+This prints an unsigned octal integer.
+
+@item s
+This prints a string.
+
+@item x
+This prints an unsigned hexadecimal integer.
+
+@item X
+This prints an unsigned hexadecimal integer. However, for the values 10
+through 15, it uses the letters @samp{A} through @samp{F} instead of
+@samp{a} through @samp{f}.
+
+@item %
+This isn't really a format-control letter, but it does have a meaning
+when used after a @samp{%}: the sequence @samp{%%} outputs one
+@samp{%}. It does not consume an argument.
+@end table
+
+@node Format Modifiers, Printf Examples, Control Letters, Printf
+@subsection Modifiers for @code{printf} Formats
+
+@cindex @code{printf}, modifiers
+@cindex modifiers (in format specifiers)
+A format specification can also include @dfn{modifiers} that can control
+how much of the item's value is printed and how much space it gets. The
+modifiers come between the @samp{%} and the format-control letter. Here
+are the possible modifiers, in the order in which they may appear:
+
+@table @samp
+@item -
+The minus sign, used before the width modifier, says to left-justify
+the argument within its specified width. Normally the argument
+is printed right-justified in the specified width. Thus,
+
+@example
+printf "%-4s", "foo"
+@end example
+
+@noindent
+prints @samp{foo }.
+
+@item @var{width}
+This is a number representing the desired width of a field. Inserting any
+number between the @samp{%} sign and the format control character forces the
+field to be expanded to this width. The default way to do this is to
+pad with spaces on the left. For example,
+
+@example
+printf "%4s", "foo"
+@end example
+
+@noindent
+prints @samp{ foo}.
+
+The value of @var{width} is a minimum width, not a maximum. If the item
+value requires more than @var{width} characters, it can be as wide as
+necessary. Thus,
+
+@example
+printf "%4s", "foobar"
+@end example
+
+@noindent
+prints @samp{foobar}.
+
+Preceding the @var{width} with a minus sign causes the output to be
+padded with spaces on the right, instead of on the left.
+
+@item .@var{prec}
+This is a number that specifies the precision to use when printing.
+This specifies the number of digits you want printed to the right of the
+decimal point. For a string, it specifies the maximum number of
+characters from the string that should be printed.
+@end table
+
+The C library @code{printf}'s dynamic @var{width} and @var{prec}
+capability (for example, @code{"%*.*s"}) is supported. Instead of
+supplying explicit @var{width} and/or @var{prec} values in the format
+string, you pass them in the argument list. For example:@refill
+
+@example
+w = 5
+p = 3
+s = "abcdefg"
+printf "<%*.*s>\n", w, p, s
+@end example
+
+@noindent
+is exactly equivalent to
+
+@example
+s = "abcdefg"
+printf "<%5.3s>\n", s
+@end example
+
+@noindent
+Both programs output @samp{@w{<@bullet{}@bullet{}abc>}}. (We have
+used the bullet symbol ``@bullet{}'' to represent a space, to clearly
+show you that there are two spaces in the output.)@refill
+
+Earlier versions of @code{awk} did not support this capability. You may
+simulate it by using concatenation to build up the format string,
+like so:@refill
+
+@example
+w = 5
+p = 3
+s = "abcdefg"
+printf "<%" w "." p "s>\n", s
+@end example
+
+@noindent
+This is not particularly easy to read, however.
+
+@node Printf Examples, , Format Modifiers, Printf
+@subsection Examples of Using @code{printf}
+
+Here is how to use @code{printf} to make an aligned table:
+
+@example
+awk '@{ printf "%-10s %s\n", $1, $2 @}' BBS-list
+@end example
+
+@noindent
+prints the names of bulletin boards (@code{$1}) of the file
+@file{BBS-list} as a string of 10 characters, left justified. It also
+prints the phone numbers (@code{$2}) afterward on the line. This
+produces an aligned two-column table of names and phone numbers:@refill
+
+@example
+@group
+aardvark 555-5553
+alpo-net 555-3412
+barfly 555-7685
+bites 555-1675
+camelot 555-0542
+core 555-2912
+fooey 555-1234
+foot 555-6699
+macfoo 555-6480
+sdace 555-3430
+sabafoo 555-2127
+@end group
+@end example
+
+Did you notice that we did not specify that the phone numbers be printed
+as numbers? They had to be printed as strings because the numbers are
+separated by a dash. This dash would be interpreted as a minus sign if
+we had tried to print the phone numbers as numbers. This would have led
+to some pretty confusing results.
+
+We did not specify a width for the phone numbers because they are the
+last things on their lines. We don't need to put spaces after them.
+
+We could make our table look even nicer by adding headings to the tops
+of the columns. To do this, use the @code{BEGIN} pattern
+(@pxref{BEGIN/END, ,@code{BEGIN} and @code{END} Special Patterns})
+to force the header to be printed only once, at the beginning of
+the @code{awk} program:@refill
+
+@example
+@group
+awk 'BEGIN @{ print "Name Number"
+ print "---- ------" @}
+ @{ printf "%-10s %s\n", $1, $2 @}' BBS-list
+@end group
+@end example
+
+Did you notice that we mixed @code{print} and @code{printf} statements in
+the above example? We could have used just @code{printf} statements to get
+the same results:
+
+@example
+@group
+awk 'BEGIN @{ printf "%-10s %s\n", "Name", "Number"
+ printf "%-10s %s\n", "----", "------" @}
+ @{ printf "%-10s %s\n", $1, $2 @}' BBS-list
+@end group
+@end example
+
+@noindent
+By outputting each column heading with the same format specification
+used for the elements of the column, we have made sure that the headings
+are aligned just like the columns.
+
+The fact that the same format specification is used three times can be
+emphasized by storing it in a variable, like this:
+
+@example
+awk 'BEGIN @{ format = "%-10s %s\n"
+ printf format, "Name", "Number"
+ printf format, "----", "------" @}
+ @{ printf format, $1, $2 @}' BBS-list
+@end example
+
+See if you can use the @code{printf} statement to line up the headings and
+table data for our @file{inventory-shipped} example covered earlier in the
+section on the @code{print} statement
+(@pxref{Print, ,The @code{print} Statement}).@refill
+
+@node Redirection, Special Files, Printf, Printing
+@section Redirecting Output of @code{print} and @code{printf}
+
+@cindex output redirection
+@cindex redirection of output
+So far we have been dealing only with output that prints to the standard
+output, usually your terminal. Both @code{print} and @code{printf} can
+also send their output to other places.
+This is called @dfn{redirection}.@refill
+
+A redirection appears after the @code{print} or @code{printf} statement.
+Redirections in @code{awk} are written just like redirections in shell
+commands, except that they are written inside the @code{awk} program.
+
+@menu
+* File/Pipe Redirection:: Redirecting Output to Files and Pipes.
+* Close Output:: How to close output files and pipes.
+@end menu
+
+@node File/Pipe Redirection, Close Output, Redirection, Redirection
+@subsection Redirecting Output to Files and Pipes
+
+Here are the three forms of output redirection. They are all shown for
+the @code{print} statement, but they work identically for @code{printf}
+also.@refill
+
+@table @code
+@item print @var{items} > @var{output-file}
+This type of redirection prints the items onto the output file
+@var{output-file}. The file name @var{output-file} can be any
+expression. Its value is changed to a string and then used as a
+file name (@pxref{Expressions, ,Expressions as Action Statements}).@refill
+
+When this type of redirection is used, the @var{output-file} is erased
+before the first output is written to it. Subsequent writes do not
+erase @var{output-file}, but append to it. If @var{output-file} does
+not exist, then it is created.@refill
+
+For example, here is how one @code{awk} program can write a list of
+BBS names to a file @file{name-list} and a list of phone numbers to a
+file @file{phone-list}. Each output file contains one name or number
+per line.
+
+@smallexample
+awk '@{ print $2 > "phone-list"
+ print $1 > "name-list" @}' BBS-list
+@end smallexample
+
+@item print @var{items} >> @var{output-file}
+This type of redirection prints the items onto the output file
+@var{output-file}. The difference between this and the
+single-@samp{>} redirection is that the old contents (if any) of
+@var{output-file} are not erased. Instead, the @code{awk} output is
+appended to the file.
+
+@cindex pipes for output
+@cindex output, piping
+@item print @var{items} | @var{command}
+It is also possible to send output through a @dfn{pipe} instead of into a
+file. This type of redirection opens a pipe to @var{command} and writes
+the values of @var{items} through this pipe, to another process created
+to execute @var{command}.@refill
+
+The redirection argument @var{command} is actually an @code{awk}
+expression. Its value is converted to a string, whose contents give the
+shell command to be run.
+
+For example, this produces two files, one unsorted list of BBS names
+and one list sorted in reverse alphabetical order:
+
+@smallexample
+awk '@{ print $1 > "names.unsorted"
+ print $1 | "sort -r > names.sorted" @}' BBS-list
+@end smallexample
+
+Here the unsorted list is written with an ordinary redirection while
+the sorted list is written by piping through the @code{sort} utility.
+
+Here is an example that uses redirection to mail a message to a mailing
+list @samp{bug-system}. This might be useful when trouble is encountered
+in an @code{awk} script run periodically for system maintenance.
+
+@smallexample
+report = "mail bug-system"
+print "Awk script failed:", $0 | report
+print "at record number", FNR, "of", FILENAME | report
+close(report)
+@end smallexample
+
+We call the @code{close} function here because it's a good idea to close
+the pipe as soon as all the intended output has been sent to it.
+@xref{Close Output, ,Closing Output Files and Pipes}, for more information
+on this. This example also illustrates the use of a variable to represent
+a @var{file} or @var{command}: it is not necessary to always
+use a string constant. Using a variable is generally a good idea,
+since @code{awk} requires you to spell the string value identically
+every time.
+@end table
+
+Redirecting output using @samp{>}, @samp{>>}, or @samp{|} asks the system
+to open a file or pipe only if the particular @var{file} or @var{command}
+you've specified has not already been written to by your program, or if
+it has been closed since it was last written to.@refill
+
+@node Close Output, , File/Pipe Redirection, Redirection
+@subsection Closing Output Files and Pipes
+@cindex closing output files and pipes
+@findex close
+
+When a file or pipe is opened, the file name or command associated with
+it is remembered by @code{awk} and subsequent writes to the same file or
+command are appended to the previous writes. The file or pipe stays
+open until @code{awk} exits. This is usually convenient.
+
+Sometimes there is a reason to close an output file or pipe earlier
+than that. To do this, use the @code{close} function, as follows:
+
+@example
+close(@var{filename})
+@end example
+
+@noindent
+or
+
+@example
+close(@var{command})
+@end example
+
+The argument @var{filename} or @var{command} can be any expression.
+Its value must exactly equal the string used to open the file or pipe
+to begin with---for example, if you open a pipe with this:
+
+@example
+print $1 | "sort -r > names.sorted"
+@end example
+
+@noindent
+then you must close it with this:
+
+@example
+close("sort -r > names.sorted")
+@end example
+
+Here are some reasons why you might need to close an output file:
+
+@itemize @bullet
+@item
+To write a file and read it back later on in the same @code{awk}
+program. Close the file when you are finished writing it; then
+you can start reading it with @code{getline}
+(@pxref{Getline, ,Explicit Input with @code{getline}}).@refill
+
+@item
+To write numerous files, successively, in the same @code{awk}
+program. If you don't close the files, eventually you may exceed a
+system limit on the number of open files in one process. So close
+each one when you are finished writing it.
+
+@item
+To make a command finish. When you redirect output through a pipe,
+the command reading the pipe normally continues to try to read input
+as long as the pipe is open. Often this means the command cannot
+really do its work until the pipe is closed. For example, if you
+redirect output to the @code{mail} program, the message is not
+actually sent until the pipe is closed.
+
+@item
+To run the same program a second time, with the same arguments.
+This is not the same thing as giving more input to the first run!
+
+For example, suppose you pipe output to the @code{mail} program. If you
+output several lines redirected to this pipe without closing it, they make
+a single message of several lines. By contrast, if you close the pipe
+after each line of output, then each line makes a separate message.
+@end itemize
+
+@iftex
+@vindex ERRNO
+@cindex differences: @code{gawk} and @code{awk}
+@end iftex
+@code{close} returns a value of zero if the close succeeded.
+Otherwise, the value will be non-zero.
+In this case, @code{gawk} sets the variable @code{ERRNO} to a string
+describing the error that occurred.
+
+@node Special Files, , Redirection, Printing
+@section Standard I/O Streams
+@cindex standard input
+@cindex standard output
+@cindex standard error output
+@cindex file descriptors
+
+Running programs conventionally have three input and output streams
+already available to them for reading and writing. These are known as
+the @dfn{standard input}, @dfn{standard output}, and @dfn{standard error
+output}. These streams are, by default, terminal input and output, but
+they are often redirected with the shell, via the @samp{<}, @samp{<<},
+@samp{>}, @samp{>>}, @samp{>&} and @samp{|} operators. Standard error
+is used only for writing error messages; the reason we have two separate
+streams, standard output and standard error, is so that they can be
+redirected separately.
+
+@iftex
+@cindex differences: @code{gawk} and @code{awk}
+@end iftex
+In other implementations of @code{awk}, the only way to write an error
+message to standard error in an @code{awk} program is as follows:
+
+@smallexample
+print "Serious error detected!\n" | "cat 1>&2"
+@end smallexample
+
+@noindent
+This works by opening a pipeline to a shell command which can access the
+standard error stream which it inherits from the @code{awk} process.
+This is far from elegant, and is also inefficient, since it requires a
+separate process. So people writing @code{awk} programs have often
+neglected to do this. Instead, they have sent the error messages to the
+terminal, like this:
+
+@smallexample
+@group
+NF != 4 @{
+ printf("line %d skipped: doesn't have 4 fields\n", FNR) > "/dev/tty"
+@}
+@end group
+@end smallexample
+
+@noindent
+This has the same effect most of the time, but not always: although the
+standard error stream is usually the terminal, it can be redirected, and
+when that happens, writing to the terminal is not correct. In fact, if
+@code{awk} is run from a background job, it may not have a terminal at all.
+Then opening @file{/dev/tty} will fail.
+
+@code{gawk} provides special file names for accessing the three standard
+streams. When you redirect input or output in @code{gawk}, if the file name
+matches one of these special names, then @code{gawk} directly uses the
+stream it stands for.
+
+@cindex @file{/dev/stdin}
+@cindex @file{/dev/stdout}
+@cindex @file{/dev/stderr}
+@cindex @file{/dev/fd/}
+@table @file
+@item /dev/stdin
+The standard input (file descriptor 0).
+
+@item /dev/stdout
+The standard output (file descriptor 1).
+
+@item /dev/stderr
+The standard error output (file descriptor 2).
+
+@item /dev/fd/@var{N}
+The file associated with file descriptor @var{N}. Such a file must have
+been opened by the program initiating the @code{awk} execution (typically
+the shell). Unless you take special pains, only descriptors 0, 1 and 2
+are available.
+@end table
+
+The file names @file{/dev/stdin}, @file{/dev/stdout}, and @file{/dev/stderr}
+are aliases for @file{/dev/fd/0}, @file{/dev/fd/1}, and @file{/dev/fd/2},
+respectively, but they are more self-explanatory.
+
+The proper way to write an error message in a @code{gawk} program
+is to use @file{/dev/stderr}, like this:
+
+@smallexample
+NF != 4 @{
+ printf("line %d skipped: doesn't have 4 fields\n", FNR) > "/dev/stderr"
+@}
+@end smallexample
+
+@code{gawk} also provides special file names that give access to information
+about the running @code{gawk} process. Each of these ``files'' provides
+a single record of information. To read them more than once, you must
+first close them with the @code{close} function
+(@pxref{Close Input, ,Closing Input Files and Pipes}).
+The filenames are:
+
+@cindex @file{/dev/pid}
+@cindex @file{/dev/pgrpid}
+@cindex @file{/dev/ppid}
+@cindex @file{/dev/user}
+@table @file
+@item /dev/pid
+Reading this file returns the process ID of the current process,
+in decimal, terminated with a newline.
+
+@item /dev/ppid
+Reading this file returns the parent process ID of the current process,
+in decimal, terminated with a newline.
+
+@item /dev/pgrpid
+Reading this file returns the process group ID of the current process,
+in decimal, terminated with a newline.
+
+@item /dev/user
+Reading this file returns a single record terminated with a newline.
+The fields are separated with blanks. The fields represent the
+following information:
+
+@table @code
+@item $1
+The value of the @code{getuid} system call.
+
+@item $2
+The value of the @code{geteuid} system call.
+
+@item $3
+The value of the @code{getgid} system call.
+
+@item $4
+The value of the @code{getegid} system call.
+@end table
+
+If there are any additional fields, they are the group IDs returned by
+@code{getgroups} system call.
+(Multiple groups may not be supported on all systems.)@refill
+@end table
+
+These special file names may be used on the command line as data
+files, as well as for I/O redirections within an @code{awk} program.
+They may not be used as source files with the @samp{-f} option.
+
+Recognition of these special file names is disabled if @code{gawk} is in
+compatibility mode (@pxref{Command Line, ,Invoking @code{awk}}).
+
+@quotation
+@strong{Caution}: Unless your system actually has a @file{/dev/fd} directory
+(or any of the other above listed special files),
+the interpretation of these file names is done by @code{gawk} itself.
+For example, using @samp{/dev/fd/4} for output will actually write on
+file descriptor 4, and not on a new file descriptor that was @code{dup}'ed
+from file descriptor 4. Most of the time this does not matter; however, it
+is important to @emph{not} close any of the files related to file descriptors
+0, 1, and 2. If you do close one of these files, unpredictable behavior
+will result.
+@end quotation
+
+@node One-liners, Patterns, Printing, Top
+@chapter Useful ``One-liners''
+
+@cindex one-liners
+Useful @code{awk} programs are often short, just a line or two. Here is a
+collection of useful, short programs to get you started. Some of these
+programs contain constructs that haven't been covered yet. The description
+of the program will give you a good idea of what is going on, but please
+read the rest of the manual to become an @code{awk} expert!
+
+@c Per suggestions from Michal Jaegermann
+@ifinfo
+Since you are reading this in Info, each line of the example code is
+enclosed in quotes, to represent text that you would type literally.
+The examples themselves represent shell commands that use single quotes
+to keep the shell from interpreting the contents of the program.
+When reading the examples, focus on the text between the open and close
+quotes.
+@end ifinfo
+
+@table @code
+@item awk '@{ if (NF > max) max = NF @}
+@itemx @ @ @ @ @ END @{ print max @}'
+This program prints the maximum number of fields on any input line.
+
+@item awk 'length($0) > 80'
+This program prints every line longer than 80 characters. The sole
+rule has a relational expression as its pattern, and has no action (so the
+default action, printing the record, is used).
+
+@item awk 'NF > 0'
+This program prints every line that has at least one field. This is an
+easy way to delete blank lines from a file (or rather, to create a new
+file similar to the old file but from which the blank lines have been
+deleted).
+
+@item awk '@{ if (NF > 0) print @}'
+This program also prints every line that has at least one field. Here we
+allow the rule to match every line, then decide in the action whether
+to print.
+
+@item awk@ 'BEGIN@ @{@ for (i = 1; i <= 7; i++)
+@itemx @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ print int(101 * rand()) @}'
+This program prints 7 random numbers from 0 to 100, inclusive.
+
+@item ls -l @var{files} | awk '@{ x += $4 @} ; END @{ print "total bytes: " x @}'
+This program prints the total number of bytes used by @var{files}.
+
+@item expand@ @var{file}@ |@ awk@ '@{ if (x < length()) x = length() @}
+@itemx @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ END @{ print "maximum line length is " x @}'
+This program prints the maximum line length of @var{file}. The input
+is piped through the @code{expand} program to change tabs into spaces,
+so the widths compared are actually the right-margin columns.
+
+@item awk 'BEGIN @{ FS = ":" @}
+@itemx @ @ @ @ @ @{ print $1 | "sort" @}' /etc/passwd
+This program prints a sorted list of the login names of all users.
+
+@item awk '@{ nlines++ @}
+@itemx @ @ @ @ @ END@ @{ print nlines @}'
+This programs counts lines in a file.
+
+@item awk 'END @{ print NR @}'
+This program also counts lines in a file, but lets @code{awk} do the work.
+
+@item awk '@{ print NR, $0 @}'
+This program adds line numbers to all its input files,
+similar to @samp{cat -n}.
+@end table
+
+@node Patterns, Actions, One-liners, Top
+@chapter Patterns
+@cindex pattern, definition of
+
+Patterns in @code{awk} control the execution of rules: a rule is
+executed when its pattern matches the current input record. This
+chapter tells all about how to write patterns.
+
+@menu
+* Kinds of Patterns:: A list of all kinds of patterns.
+ The following subsections describe
+ them in detail.
+* Regexp:: Regular expressions such as @samp{/foo/}.
+* Comparison Patterns:: Comparison expressions such as @code{$1 > 10}.
+* Boolean Patterns:: Combining comparison expressions.
+* Expression Patterns:: Any expression can be used as a pattern.
+* Ranges:: Pairs of patterns specify record ranges.
+* BEGIN/END:: Specifying initialization and cleanup rules.
+* Empty:: The empty pattern, which matches every record.
+@end menu
+
+@node Kinds of Patterns, Regexp, Patterns, Patterns
+@section Kinds of Patterns
+@cindex patterns, types of
+
+Here is a summary of the types of patterns supported in @code{awk}.
+@c At the next rewrite, check to see that this order matches the
+@c order in the text. It might not matter to a reader, but it's good
+@c style. Also, it might be nice to mention all the topics of sections
+@c that follow in this list; that way people can scan and know when to
+@c expect a specific topic. Specifically please also make an entry
+@c for Boolean operators as patterns in the right place. --mew
+
+@table @code
+@item /@var{regular expression}/
+A regular expression as a pattern. It matches when the text of the
+input record fits the regular expression.
+(@xref{Regexp, ,Regular Expressions as Patterns}.)@refill
+
+@item @var{expression}
+A single expression. It matches when its value, converted to a number,
+is nonzero (if a number) or nonnull (if a string).
+(@xref{Expression Patterns, ,Expressions as Patterns}.)@refill
+
+@item @var{pat1}, @var{pat2}
+A pair of patterns separated by a comma, specifying a range of records.
+(@xref{Ranges, ,Specifying Record Ranges with Patterns}.)
+
+@item BEGIN
+@itemx END
+Special patterns to supply start-up or clean-up information to
+@code{awk}. (@xref{BEGIN/END, ,@code{BEGIN} and @code{END} Special Patterns}.)
+
+@item @var{null}
+The empty pattern matches every input record.
+(@xref{Empty, ,The Empty Pattern}.)@refill
+@end table
+
+
+@node Regexp, Comparison Patterns, Kinds of Patterns, Patterns
+@section Regular Expressions as Patterns
+@cindex pattern, regular expressions
+@cindex regexp
+@cindex regular expressions as patterns
+
+A @dfn{regular expression}, or @dfn{regexp}, is a way of describing a
+class of strings. A regular expression enclosed in slashes (@samp{/})
+is an @code{awk} pattern that matches every input record whose text
+belongs to that class.
+
+The simplest regular expression is a sequence of letters, numbers, or
+both. Such a regexp matches any string that contains that sequence.
+Thus, the regexp @samp{foo} matches any string containing @samp{foo}.
+Therefore, the pattern @code{/foo/} matches any input record containing
+@samp{foo}. Other kinds of regexps let you specify more complicated
+classes of strings.
+
+@menu
+* Regexp Usage:: How to Use Regular Expressions
+* Regexp Operators:: Regular Expression Operators
+* Case-sensitivity:: How to do case-insensitive matching.
+@end menu
+
+@node Regexp Usage, Regexp Operators, Regexp, Regexp
+@subsection How to Use Regular Expressions
+
+A regular expression can be used as a pattern by enclosing it in
+slashes. Then the regular expression is matched against the
+entire text of each record. (Normally, it only needs
+to match some part of the text in order to succeed.) For example, this
+prints the second field of each record that contains @samp{foo} anywhere:
+
+@example
+awk '/foo/ @{ print $2 @}' BBS-list
+@end example
+
+@cindex regular expression matching operators
+@cindex string-matching operators
+@cindex operators, string-matching
+@cindex operators, regexp matching
+@cindex regexp search operators
+Regular expressions can also be used in comparison expressions. Then
+you can specify the string to match against; it need not be the entire
+current input record. These comparison expressions can be used as
+patterns or in @code{if}, @code{while}, @code{for}, and @code{do} statements.
+
+@table @code
+@item @var{exp} ~ /@var{regexp}/
+This is true if the expression @var{exp} (taken as a character string)
+is matched by @var{regexp}. The following example matches, or selects,
+all input records with the upper-case letter @samp{J} somewhere in the
+first field:@refill
+
+@example
+awk '$1 ~ /J/' inventory-shipped
+@end example
+
+So does this:
+
+@example
+awk '@{ if ($1 ~ /J/) print @}' inventory-shipped
+@end example
+
+@item @var{exp} !~ /@var{regexp}/
+This is true if the expression @var{exp} (taken as a character string)
+is @emph{not} matched by @var{regexp}. The following example matches,
+or selects, all input records whose first field @emph{does not} contain
+the upper-case letter @samp{J}:@refill
+
+@example
+awk '$1 !~ /J/' inventory-shipped
+@end example
+@end table
+
+@cindex computed regular expressions
+@cindex regular expressions, computed
+@cindex dynamic regular expressions
+The right hand side of a @samp{~} or @samp{!~} operator need not be a
+constant regexp (i.e., a string of characters between slashes). It may
+be any expression. The expression is evaluated, and converted if
+necessary to a string; the contents of the string are used as the
+regexp. A regexp that is computed in this way is called a @dfn{dynamic
+regexp}. For example:
+
+@example
+identifier_regexp = "[A-Za-z_][A-Za-z_0-9]+"
+$0 ~ identifier_regexp
+@end example
+
+@noindent
+sets @code{identifier_regexp} to a regexp that describes @code{awk}
+variable names, and tests if the input record matches this regexp.
+
+@node Regexp Operators, Case-sensitivity, Regexp Usage, Regexp
+@subsection Regular Expression Operators
+@cindex metacharacters
+@cindex regular expression metacharacters
+
+You can combine regular expressions with the following characters,
+called @dfn{regular expression operators}, or @dfn{metacharacters}, to
+increase the power and versatility of regular expressions.
+
+Here is a table of metacharacters. All characters not listed in the
+table stand for themselves.
+
+@table @code
+@item ^
+This matches the beginning of the string or the beginning of a line
+within the string. For example:
+
+@example
+^@@chapter
+@end example
+
+@noindent
+matches the @samp{@@chapter} at the beginning of a string, and can be used
+to identify chapter beginnings in Texinfo source files.
+
+@item $
+This is similar to @samp{^}, but it matches only at the end of a string
+or the end of a line within the string. For example:
+
+@example
+p$
+@end example
+
+@noindent
+matches a record that ends with a @samp{p}.
+
+@item .
+This matches any single character except a newline. For example:
+
+@example
+.P
+@end example
+
+@noindent
+matches any single character followed by a @samp{P} in a string. Using
+concatenation we can make regular expressions like @samp{U.A}, which
+matches any three-character sequence that begins with @samp{U} and ends
+with @samp{A}.
+
+@item [@dots{}]
+This is called a @dfn{character set}. It matches any one of the
+characters that are enclosed in the square brackets. For example:
+
+@example
+[MVX]
+@end example
+
+@noindent
+matches any one of the characters @samp{M}, @samp{V}, or @samp{X} in a
+string.@refill
+
+Ranges of characters are indicated by using a hyphen between the beginning
+and ending characters, and enclosing the whole thing in brackets. For
+example:@refill
+
+@example
+[0-9]
+@end example
+
+@noindent
+matches any digit.
+
+To include the character @samp{\}, @samp{]}, @samp{-} or @samp{^} in a
+character set, put a @samp{\} in front of it. For example:
+
+@example
+[d\]]
+@end example
+
+@noindent
+matches either @samp{d}, or @samp{]}.@refill
+
+This treatment of @samp{\} is compatible with other @code{awk}
+implementations, and is also mandated by the @sc{posix} Command Language
+and Utilities standard. The regular expressions in @code{awk} are a superset
+of the @sc{posix} specification for Extended Regular Expressions (EREs).
+@sc{posix} EREs are based on the regular expressions accepted by the
+traditional @code{egrep} utility.
+
+In @code{egrep} syntax, backslash is not syntactically special within
+square brackets. This means that special tricks have to be used to
+represent the characters @samp{]}, @samp{-} and @samp{^} as members of a
+character set.
+
+In @code{egrep} syntax, to match @samp{-}, write it as @samp{---},
+which is a range containing only @w{@samp{-}.} You may also give @samp{-}
+as the first or last character in the set. To match @samp{^}, put it
+anywhere except as the first character of a set. To match a @samp{]},
+make it the first character in the set. For example:@refill
+
+@example
+[]d^]
+@end example
+
+@noindent
+matches either @samp{]}, @samp{d} or @samp{^}.@refill
+
+@item [^ @dots{}]
+This is a @dfn{complemented character set}. The first character after
+the @samp{[} @emph{must} be a @samp{^}. It matches any characters
+@emph{except} those in the square brackets (or newline). For example:
+
+@example
+[^0-9]
+@end example
+
+@noindent
+matches any character that is not a digit.
+
+@item |
+This is the @dfn{alternation operator} and it is used to specify
+alternatives. For example:
+
+@example
+^P|[0-9]
+@end example
+
+@noindent
+matches any string that matches either @samp{^P} or @samp{[0-9]}. This
+means it matches any string that contains a digit or starts with @samp{P}.
+
+The alternation applies to the largest possible regexps on either side.
+@item (@dots{})
+Parentheses are used for grouping in regular expressions as in
+arithmetic. They can be used to concatenate regular expressions
+containing the alternation operator, @samp{|}.
+
+@item *
+This symbol means that the preceding regular expression is to be
+repeated as many times as possible to find a match. For example:
+
+@example
+ph*
+@end example
+
+@noindent
+applies the @samp{*} symbol to the preceding @samp{h} and looks for matches
+to one @samp{p} followed by any number of @samp{h}s. This will also match
+just @samp{p} if no @samp{h}s are present.
+
+The @samp{*} repeats the @emph{smallest} possible preceding expression.
+(Use parentheses if you wish to repeat a larger expression.) It finds
+as many repetitions as possible. For example:
+
+@example
+awk '/\(c[ad][ad]*r x\)/ @{ print @}' sample
+@end example
+
+@noindent
+prints every record in the input containing a string of the form
+@samp{(car x)}, @samp{(cdr x)}, @samp{(cadr x)}, and so on.@refill
+
+@item +
+This symbol is similar to @samp{*}, but the preceding expression must be
+matched at least once. This means that:
+
+@example
+wh+y
+@end example
+
+@noindent
+would match @samp{why} and @samp{whhy} but not @samp{wy}, whereas
+@samp{wh*y} would match all three of these strings. This is a simpler
+way of writing the last @samp{*} example:
+
+@example
+awk '/\(c[ad]+r x\)/ @{ print @}' sample
+@end example
+
+@item ?
+This symbol is similar to @samp{*}, but the preceding expression can be
+matched once or not at all. For example:
+
+@example
+fe?d
+@end example
+
+@noindent
+will match @samp{fed} and @samp{fd}, but nothing else.@refill
+
+@item \
+This is used to suppress the special meaning of a character when
+matching. For example:
+
+@example
+\$
+@end example
+
+@noindent
+matches the character @samp{$}.
+
+The escape sequences used for string constants
+(@pxref{Constants, ,Constant Expressions}) are
+valid in regular expressions as well; they are also introduced by a
+@samp{\}.@refill
+@end table
+
+In regular expressions, the @samp{*}, @samp{+}, and @samp{?} operators have
+the highest precedence, followed by concatenation, and finally by @samp{|}.
+As in arithmetic, parentheses can change how operators are grouped.@refill
+
+@node Case-sensitivity, , Regexp Operators, Regexp
+@subsection Case-sensitivity in Matching
+
+Case is normally significant in regular expressions, both when matching
+ordinary characters (i.e., not metacharacters), and inside character
+sets. Thus a @samp{w} in a regular expression matches only a lower case
+@samp{w} and not an upper case @samp{W}.
+
+The simplest way to do a case-independent match is to use a character
+set: @samp{[Ww]}. However, this can be cumbersome if you need to use it
+often; and it can make the regular expressions harder for humans to
+read. There are two other alternatives that you might prefer.
+
+One way to do a case-insensitive match at a particular point in the
+program is to convert the data to a single case, using the
+@code{tolower} or @code{toupper} built-in string functions (which we
+haven't discussed yet;
+@pxref{String Functions, ,Built-in Functions for String Manipulation}).
+For example:@refill
+
+@example
+tolower($1) ~ /foo/ @{ @dots{} @}
+@end example
+
+@noindent
+converts the first field to lower case before matching against it.
+
+Another method is to set the variable @code{IGNORECASE} to a nonzero
+value (@pxref{Built-in Variables}). When @code{IGNORECASE} is not zero,
+@emph{all} regexp operations ignore case. Changing the value of
+@code{IGNORECASE} dynamically controls the case sensitivity of your
+program as it runs. Case is significant by default because
+@code{IGNORECASE} (like most variables) is initialized to zero.
+
+@example
+x = "aB"
+if (x ~ /ab/) @dots{} # this test will fail
+
+IGNORECASE = 1
+if (x ~ /ab/) @dots{} # now it will succeed
+@end example
+
+In general, you cannot use @code{IGNORECASE} to make certain rules
+case-insensitive and other rules case-sensitive, because there is no way
+to set @code{IGNORECASE} just for the pattern of a particular rule. To
+do this, you must use character sets or @code{tolower}. However, one
+thing you can do only with @code{IGNORECASE} is turn case-sensitivity on
+or off dynamically for all the rules at once.@refill
+
+@code{IGNORECASE} can be set on the command line, or in a @code{BEGIN}
+rule. Setting @code{IGNORECASE} from the command line is a way to make
+a program case-insensitive without having to edit it.
+
+The value of @code{IGNORECASE} has no effect if @code{gawk} is in
+compatibility mode (@pxref{Command Line, ,Invoking @code{awk}}).
+Case is always significant in compatibility mode.@refill
+
+@node Comparison Patterns, Boolean Patterns, Regexp, Patterns
+@section Comparison Expressions as Patterns
+@cindex comparison expressions as patterns
+@cindex pattern, comparison expressions
+@cindex relational operators
+@cindex operators, relational
+
+@dfn{Comparison patterns} test relationships such as equality between
+two strings or numbers. They are a special case of expression patterns
+(@pxref{Expression Patterns, ,Expressions as Patterns}). They are written
+with @dfn{relational operators}, which are a superset of those in C.
+Here is a table of them:@refill
+
+@table @code
+@item @var{x} < @var{y}
+True if @var{x} is less than @var{y}.
+
+@item @var{x} <= @var{y}
+True if @var{x} is less than or equal to @var{y}.
+
+@item @var{x} > @var{y}
+True if @var{x} is greater than @var{y}.
+
+@item @var{x} >= @var{y}
+True if @var{x} is greater than or equal to @var{y}.
+
+@item @var{x} == @var{y}
+True if @var{x} is equal to @var{y}.
+
+@item @var{x} != @var{y}
+True if @var{x} is not equal to @var{y}.
+
+@item @var{x} ~ @var{y}
+True if @var{x} matches the regular expression described by @var{y}.
+
+@item @var{x} !~ @var{y}
+True if @var{x} does not match the regular expression described by @var{y}.
+@end table
+
+The operands of a relational operator are compared as numbers if they
+are both numbers. Otherwise they are converted to, and compared as,
+strings (@pxref{Conversion, ,Conversion of Strings and Numbers},
+for the detailed rules). Strings are compared by comparing the first
+character of each, then the second character of each,
+and so on, until there is a difference. If the two strings are equal until
+the shorter one runs out, the shorter one is considered to be less than the
+longer one. Thus, @code{"10"} is less than @code{"9"}, and @code{"abc"}
+is less than @code{"abcd"}.@refill
+
+The left operand of the @samp{~} and @samp{!~} operators is a string.
+The right operand is either a constant regular expression enclosed in
+slashes (@code{/@var{regexp}/}), or any expression, whose string value
+is used as a dynamic regular expression
+(@pxref{Regexp Usage, ,How to Use Regular Expressions}).@refill
+
+The following example prints the second field of each input record
+whose first field is precisely @samp{foo}.
+
+@example
+awk '$1 == "foo" @{ print $2 @}' BBS-list
+@end example
+
+@noindent
+Contrast this with the following regular expression match, which would
+accept any record with a first field that contains @samp{foo}:
+
+@example
+awk '$1 ~ "foo" @{ print $2 @}' BBS-list
+@end example
+
+@noindent
+or, equivalently, this one:
+
+@example
+awk '$1 ~ /foo/ @{ print $2 @}' BBS-list
+@end example
+
+@node Boolean Patterns, Expression Patterns, Comparison Patterns, Patterns
+@section Boolean Operators and Patterns
+@cindex patterns, boolean
+@cindex boolean patterns
+
+A @dfn{boolean pattern} is an expression which combines other patterns
+using the @dfn{boolean operators} ``or'' (@samp{||}), ``and''
+(@samp{&&}), and ``not'' (@samp{!}). Whether the boolean pattern
+matches an input record depends on whether its subpatterns match.
+
+For example, the following command prints all records in the input file
+@file{BBS-list} that contain both @samp{2400} and @samp{foo}.@refill
+
+@example
+awk '/2400/ && /foo/' BBS-list
+@end example
+
+The following command prints all records in the input file
+@file{BBS-list} that contain @emph{either} @samp{2400} or @samp{foo}, or
+both.@refill
+
+@example
+awk '/2400/ || /foo/' BBS-list
+@end example
+
+The following command prints all records in the input file
+@file{BBS-list} that do @emph{not} contain the string @samp{foo}.
+
+@example
+awk '! /foo/' BBS-list
+@end example
+
+Note that boolean patterns are a special case of expression patterns
+(@pxref{Expression Patterns, ,Expressions as Patterns}); they are
+expressions that use the boolean operators.
+@xref{Boolean Ops, ,Boolean Expressions}, for complete information
+on the boolean operators.@refill
+
+The subpatterns of a boolean pattern can be constant regular
+expressions, comparisons, or any other @code{awk} expressions. Range
+patterns are not expressions, so they cannot appear inside boolean
+patterns. Likewise, the special patterns @code{BEGIN} and @code{END},
+which never match any input record, are not expressions and cannot
+appear inside boolean patterns.
+
+@node Expression Patterns, Ranges, Boolean Patterns, Patterns
+@section Expressions as Patterns
+
+Any @code{awk} expression is also valid as an @code{awk} pattern.
+Then the pattern ``matches'' if the expression's value is nonzero (if a
+number) or nonnull (if a string).
+
+The expression is reevaluated each time the rule is tested against a new
+input record. If the expression uses fields such as @code{$1}, the
+value depends directly on the new input record's text; otherwise, it
+depends only on what has happened so far in the execution of the
+@code{awk} program, but that may still be useful.
+
+Comparison patterns are actually a special case of this. For
+example, the expression @code{$5 == "foo"} has the value 1 when the
+value of @code{$5} equals @code{"foo"}, and 0 otherwise; therefore, this
+expression as a pattern matches when the two values are equal.
+
+Boolean patterns are also special cases of expression patterns.
+
+A constant regexp as a pattern is also a special case of an expression
+pattern. @code{/foo/} as an expression has the value 1 if @samp{foo}
+appears in the current input record; thus, as a pattern, @code{/foo/}
+matches any record containing @samp{foo}.
+
+Other implementations of @code{awk} that are not yet @sc{posix} compliant
+are less general than @code{gawk}: they allow comparison expressions, and
+boolean combinations thereof (optionally with parentheses), but not
+necessarily other kinds of expressions.
+
+@node Ranges, BEGIN/END, Expression Patterns, Patterns
+@section Specifying Record Ranges with Patterns
+
+@cindex range pattern
+@cindex patterns, range
+A @dfn{range pattern} is made of two patterns separated by a comma, of
+the form @code{@var{begpat}, @var{endpat}}. It matches ranges of
+consecutive input records. The first pattern @var{begpat} controls
+where the range begins, and the second one @var{endpat} controls where
+it ends. For example,@refill
+
+@example
+awk '$1 == "on", $1 == "off"'
+@end example
+
+@noindent
+prints every record between @samp{on}/@samp{off} pairs, inclusive.
+
+A range pattern starts out by matching @var{begpat}
+against every input record; when a record matches @var{begpat}, the
+range pattern becomes @dfn{turned on}. The range pattern matches this
+record. As long as it stays turned on, it automatically matches every
+input record read. It also matches @var{endpat} against
+every input record; when that succeeds, the range pattern is turned
+off again for the following record. Now it goes back to checking
+@var{begpat} against each record.
+
+The record that turns on the range pattern and the one that turns it
+off both match the range pattern. If you don't want to operate on
+these records, you can write @code{if} statements in the rule's action
+to distinguish them.
+
+It is possible for a pattern to be turned both on and off by the same
+record, if both conditions are satisfied by that record. Then the action is
+executed for just that record.
+
+@node BEGIN/END, Empty, Ranges, Patterns
+@section @code{BEGIN} and @code{END} Special Patterns
+
+@cindex @code{BEGIN} special pattern
+@cindex patterns, @code{BEGIN}
+@cindex @code{END} special pattern
+@cindex patterns, @code{END}
+@code{BEGIN} and @code{END} are special patterns. They are not used to
+match input records. Rather, they are used for supplying start-up or
+clean-up information to your @code{awk} script. A @code{BEGIN} rule is
+executed, once, before the first input record has been read. An @code{END}
+rule is executed, once, after all the input has been read. For
+example:@refill
+
+@example
+awk 'BEGIN @{ print "Analysis of `foo'" @}
+ /foo/ @{ ++foobar @}
+ END @{ print "`foo' appears " foobar " times." @}' BBS-list
+@end example
+
+This program finds the number of records in the input file @file{BBS-list}
+that contain the string @samp{foo}. The @code{BEGIN} rule prints a title
+for the report. There is no need to use the @code{BEGIN} rule to
+initialize the counter @code{foobar} to zero, as @code{awk} does this
+for us automatically (@pxref{Variables}).
+
+The second rule increments the variable @code{foobar} every time a
+record containing the pattern @samp{foo} is read. The @code{END} rule
+prints the value of @code{foobar} at the end of the run.@refill
+
+The special patterns @code{BEGIN} and @code{END} cannot be used in ranges
+or with boolean operators (indeed, they cannot be used with any operators).
+
+An @code{awk} program may have multiple @code{BEGIN} and/or @code{END}
+rules. They are executed in the order they appear, all the @code{BEGIN}
+rules at start-up and all the @code{END} rules at termination.
+
+Multiple @code{BEGIN} and @code{END} sections are useful for writing
+library functions, since each library can have its own @code{BEGIN} or
+@code{END} rule to do its own initialization and/or cleanup. Note that
+the order in which library functions are named on the command line
+controls the order in which their @code{BEGIN} and @code{END} rules are
+executed. Therefore you have to be careful to write such rules in
+library files so that the order in which they are executed doesn't matter.
+@xref{Command Line, ,Invoking @code{awk}}, for more information on
+using library functions.
+
+If an @code{awk} program only has a @code{BEGIN} rule, and no other
+rules, then the program exits after the @code{BEGIN} rule has been run.
+(Older versions of @code{awk} used to keep reading and ignoring input
+until end of file was seen.) However, if an @code{END} rule exists as
+well, then the input will be read, even if there are no other rules in
+the program. This is necessary in case the @code{END} rule checks the
+@code{NR} variable.
+
+@code{BEGIN} and @code{END} rules must have actions; there is no default
+action for these rules since there is no current record when they run.
+
+@node Empty, , BEGIN/END, Patterns
+@comment node-name, next, previous, up
+@section The Empty Pattern
+
+@cindex empty pattern
+@cindex pattern, empty
+An empty pattern is considered to match @emph{every} input record. For
+example, the program:@refill
+
+@example
+awk '@{ print $1 @}' BBS-list
+@end example
+
+@noindent
+prints the first field of every record.
+
+@node Actions, Expressions, Patterns, Top
+@chapter Overview of Actions
+@cindex action, definition of
+@cindex curly braces
+@cindex action, curly braces
+@cindex action, separating statements
+
+An @code{awk} program or script consists of a series of
+rules and function definitions, interspersed. (Functions are
+described later. @xref{User-defined, ,User-defined Functions}.)
+
+A rule contains a pattern and an action, either of which may be
+omitted. The purpose of the @dfn{action} is to tell @code{awk} what to do
+once a match for the pattern is found. Thus, the entire program
+looks somewhat like this:
+
+@example
+@r{[}@var{pattern}@r{]} @r{[}@{ @var{action} @}@r{]}
+@r{[}@var{pattern}@r{]} @r{[}@{ @var{action} @}@r{]}
+@dots{}
+function @var{name} (@var{args}) @{ @dots{} @}
+@dots{}
+@end example
+
+An action consists of one or more @code{awk} @dfn{statements}, enclosed
+in curly braces (@samp{@{} and @samp{@}}). Each statement specifies one
+thing to be done. The statements are separated by newlines or
+semicolons.
+
+The curly braces around an action must be used even if the action
+contains only one statement, or even if it contains no statements at
+all. However, if you omit the action entirely, omit the curly braces as
+well. (An omitted action is equivalent to @samp{@{ print $0 @}}.)
+
+Here are the kinds of statements supported in @code{awk}:
+
+@itemize @bullet
+@item
+Expressions, which can call functions or assign values to variables
+(@pxref{Expressions, ,Expressions as Action Statements}). Executing
+this kind of statement simply computes the value of the expression and
+then ignores it. This is useful when the expression has side effects
+(@pxref{Assignment Ops, ,Assignment Expressions}).@refill
+
+@item
+Control statements, which specify the control flow of @code{awk}
+programs. The @code{awk} language gives you C-like constructs
+(@code{if}, @code{for}, @code{while}, and so on) as well as a few
+special ones (@pxref{Statements, ,Control Statements in Actions}).@refill
+
+@item
+Compound statements, which consist of one or more statements enclosed in
+curly braces. A compound statement is used in order to put several
+statements together in the body of an @code{if}, @code{while}, @code{do}
+or @code{for} statement.
+
+@item
+Input control, using the @code{getline} command
+(@pxref{Getline, ,Explicit Input with @code{getline}}), and the @code{next}
+statement (@pxref{Next Statement, ,The @code{next} Statement}).
+
+@item
+Output statements, @code{print} and @code{printf}.
+@xref{Printing, ,Printing Output}.@refill
+
+@item
+Deletion statements, for deleting array elements.
+@xref{Delete, ,The @code{delete} Statement}.@refill
+@end itemize
+
+@iftex
+The next two chapters cover in detail expressions and control
+statements, respectively. We go on to treat arrays and built-in
+functions, both of which are used in expressions. Then we proceed
+to discuss how to define your own functions.
+@end iftex
+
+@node Expressions, Statements, Actions, Top
+@chapter Expressions as Action Statements
+@cindex expression
+
+Expressions are the basic building block of @code{awk} actions. An
+expression evaluates to a value, which you can print, test, store in a
+variable or pass to a function. But beyond that, an expression can assign a new value to a variable
+or a field, with an assignment operator.
+
+An expression can serve as a statement on its own. Most other kinds of
+statements contain one or more expressions which specify data to be
+operated on. As in other languages, expressions in @code{awk} include
+variables, array references, constants, and function calls, as well as
+combinations of these with various operators.
+
+@menu
+* Constants:: String, numeric, and regexp constants.
+* Variables:: Variables give names to values for later use.
+* Arithmetic Ops:: Arithmetic operations (@samp{+}, @samp{-}, etc.)
+* Concatenation:: Concatenating strings.
+* Comparison Ops:: Comparison of numbers and strings
+ with @samp{<}, etc.
+* Boolean Ops:: Combining comparison expressions
+ using boolean operators
+ @samp{||} (``or''), @samp{&&} (``and'') and @samp{!} (``not'').
+
+* Assignment Ops:: Changing the value of a variable or a field.
+* Increment Ops:: Incrementing the numeric value of a variable.
+
+* Conversion:: The conversion of strings to numbers
+ and vice versa.
+* Values:: The whole truth about numbers and strings.
+* Conditional Exp:: Conditional expressions select
+ between two subexpressions under control
+ of a third subexpression.
+* Function Calls:: A function call is an expression.
+* Precedence:: How various operators nest.
+@end menu
+
+@node Constants, Variables, Expressions, Expressions
+@section Constant Expressions
+@cindex constants, types of
+@cindex string constants
+
+The simplest type of expression is the @dfn{constant}, which always has
+the same value. There are three types of constants: numeric constants,
+string constants, and regular expression constants.
+
+@cindex numeric constant
+@cindex numeric value
+A @dfn{numeric constant} stands for a number. This number can be an
+integer, a decimal fraction, or a number in scientific (exponential)
+notation. Note that all numeric values are represented within
+@code{awk} in double-precision floating point. Here are some examples
+of numeric constants, which all have the same value:
+
+@example
+105
+1.05e+2
+1050e-1
+@end example
+
+A string constant consists of a sequence of characters enclosed in
+double-quote marks. For example:
+
+@example
+"parrot"
+@end example
+
+@noindent
+@iftex
+@cindex differences between @code{gawk} and @code{awk}
+@end iftex
+represents the string whose contents are @samp{parrot}. Strings in
+@code{gawk} can be of any length and they can contain all the possible
+8-bit ASCII characters including ASCII NUL. Other @code{awk}
+implementations may have difficulty with some character codes.@refill
+
+@cindex escape sequence notation
+Some characters cannot be included literally in a string constant. You
+represent them instead with @dfn{escape sequences}, which are character
+sequences beginning with a backslash (@samp{\}).
+
+One use of an escape sequence is to include a double-quote character in
+a string constant. Since a plain double-quote would end the string, you
+must use @samp{\"} to represent a single double-quote character as a
+part of the string.
+The
+backslash character itself is another character that cannot be
+included normally; you write @samp{\\} to put one backslash in the
+string. Thus, the string whose contents are the two characters
+@samp{"\} must be written @code{"\"\\"}.
+
+Another use of backslash is to represent unprintable characters
+such as newline. While there is nothing to stop you from writing most
+of these characters directly in a string constant, they may look ugly.
+
+Here is a table of all the escape sequences used in @code{awk}:
+
+@table @code
+@item \\
+Represents a literal backslash, @samp{\}.
+
+@item \a
+Represents the ``alert'' character, control-g, ASCII code 7.
+
+@item \b
+Represents a backspace, control-h, ASCII code 8.
+
+@item \f
+Represents a formfeed, control-l, ASCII code 12.
+
+@item \n
+Represents a newline, control-j, ASCII code 10.
+
+@item \r
+Represents a carriage return, control-m, ASCII code 13.
+
+@item \t
+Represents a horizontal tab, control-i, ASCII code 9.
+
+@item \v
+Represents a vertical tab, control-k, ASCII code 11.
+
+@item \@var{nnn}
+Represents the octal value @var{nnn}, where @var{nnn} are one to three
+digits between 0 and 7. For example, the code for the ASCII ESC
+(escape) character is @samp{\033}.@refill
+
+@item \x@var{hh}@dots{}
+Represents the hexadecimal value @var{hh}, where @var{hh} are hexadecimal
+digits (@samp{0} through @samp{9} and either @samp{A} through @samp{F} or
+@samp{a} through @samp{f}). Like the same construct in @sc{ansi} C, the escape
+sequence continues until the first non-hexadecimal digit is seen. However,
+using more than two hexadecimal digits produces undefined results. (The
+@samp{\x} escape sequence is not allowed in @sc{posix} @code{awk}.)@refill
+@end table
+
+A @dfn{constant regexp} is a regular expression description enclosed in
+slashes, such as @code{/^beginning and end$/}. Most regexps used in
+@code{awk} programs are constant, but the @samp{~} and @samp{!~}
+operators can also match computed or ``dynamic'' regexps
+(@pxref{Regexp Usage, ,How to Use Regular Expressions}).@refill
+
+Constant regexps may be used like simple expressions. When a
+constant regexp is not on the right hand side of the @samp{~} or
+@samp{!~} operators, it has the same meaning as if it appeared
+in a pattern, i.e. @samp{($0 ~ /foo/)}
+(@pxref{Expression Patterns, ,Expressions as Patterns}).
+This means that the two code segments,@refill
+
+@example
+if ($0 ~ /barfly/ || $0 ~ /camelot/)
+ print "found"
+@end example
+
+@noindent
+and
+
+@example
+if (/barfly/ || /camelot/)
+ print "found"
+@end example
+
+@noindent
+are exactly equivalent. One rather bizarre consequence of this rule is
+that the following boolean expression is legal, but does not do what the user
+intended:@refill
+
+@example
+if (/foo/ ~ $1) print "found foo"
+@end example
+
+This code is ``obviously'' testing @code{$1} for a match against the regexp
+@code{/foo/}. But in fact, the expression @code{(/foo/ ~ $1)} actually means
+@code{(($0 ~ /foo/) ~ $1)}. In other words, first match the input record
+against the regexp @code{/foo/}. The result will be either a 0 or a 1,
+depending upon the success or failure of the match. Then match that result
+against the first field in the record.@refill
+
+Since it is unlikely that you would ever really wish to make this kind of
+test, @code{gawk} will issue a warning when it sees this construct in
+a program.@refill
+
+Another consequence of this rule is that the assignment statement
+
+@example
+matches = /foo/
+@end example
+
+@noindent
+will assign either 0 or 1 to the variable @code{matches}, depending
+upon the contents of the current input record.
+
+Constant regular expressions are also used as the first argument for
+the @code{sub} and @code{gsub} functions
+(@pxref{String Functions, ,Built-in Functions for String Manipulation}).@refill
+
+This feature of the language was never well documented until the
+@sc{posix} specification.
+
+You may be wondering, when is
+
+@example
+$1 ~ /foo/ @{ @dots{} @}
+@end example
+
+@noindent
+preferable to
+
+@example
+$1 ~ "foo" @{ @dots{} @}
+@end example
+
+Since the right-hand sides of both @samp{~} operators are constants,
+it is more efficient to use the @samp{/foo/} form: @code{awk} can note
+that you have supplied a regexp and store it internally in a form that
+makes pattern matching more efficient. In the second form, @code{awk}
+must first convert the string into this internal form, and then perform
+the pattern matching. The first form is also better style; it shows
+clearly that you intend a regexp match.
+
+@node Variables, Arithmetic Ops, Constants, Expressions
+@section Variables
+@cindex variables, user-defined
+@cindex user-defined variables
+@c there should be more than one subsection, ideally. Not a big deal.
+@c But usually there are supposed to be at least two. One way to get
+@c around this is to write the info in the subsection as the info in the
+@c section itself and not have any subsections.. --mew
+
+Variables let you give names to values and refer to them later. You have
+already seen variables in many of the examples. The name of a variable
+must be a sequence of letters, digits and underscores, but it may not begin
+with a digit. Case is significant in variable names; @code{a} and @code{A}
+are distinct variables.
+
+A variable name is a valid expression by itself; it represents the
+variable's current value. Variables are given new values with
+@dfn{assignment operators} and @dfn{increment operators}.
+@xref{Assignment Ops, ,Assignment Expressions}.
+
+A few variables have special built-in meanings, such as @code{FS}, the
+field separator, and @code{NF}, the number of fields in the current
+input record. @xref{Built-in Variables}, for a list of them. These
+built-in variables can be used and assigned just like all other
+variables, but their values are also used or changed automatically by
+@code{awk}. Each built-in variable's name is made entirely of upper case
+letters.
+
+Variables in @code{awk} can be assigned either numeric or string
+values. By default, variables are initialized to the null string, which
+is effectively zero if converted to a number. There is no need to
+``initialize'' each variable explicitly in @code{awk}, the way you would in C or most other traditional languages.
+
+@menu
+* Assignment Options:: Setting variables on the command line
+ and a summary of command line syntax.
+ This is an advanced method of input.
+@end menu
+
+@node Assignment Options, , Variables, Variables
+@subsection Assigning Variables on the Command Line
+
+You can set any @code{awk} variable by including a @dfn{variable assignment}
+among the arguments on the command line when you invoke @code{awk}
+(@pxref{Command Line, ,Invoking @code{awk}}). Such an assignment has
+this form:@refill
+
+@example
+@var{variable}=@var{text}
+@end example
+
+@noindent
+With it, you can set a variable either at the beginning of the
+@code{awk} run or in between input files.
+
+If you precede the assignment with the @samp{-v} option, like this:
+
+@example
+-v @var{variable}=@var{text}
+@end example
+
+@noindent
+then the variable is set at the very beginning, before even the
+@code{BEGIN} rules are run. The @samp{-v} option and its assignment
+must precede all the file name arguments, as well as the program text.
+
+Otherwise, the variable assignment is performed at a time determined by
+its position among the input file arguments: after the processing of the
+preceding input file argument. For example:
+
+@example
+awk '@{ print $n @}' n=4 inventory-shipped n=2 BBS-list
+@end example
+
+@noindent
+prints the value of field number @code{n} for all input records. Before
+the first file is read, the command line sets the variable @code{n}
+equal to 4. This causes the fourth field to be printed in lines from
+the file @file{inventory-shipped}. After the first file has finished,
+but before the second file is started, @code{n} is set to 2, so that the
+second field is printed in lines from @file{BBS-list}.
+
+Command line arguments are made available for explicit examination by
+the @code{awk} program in an array named @code{ARGV}
+(@pxref{Built-in Variables}).@refill
+
+@code{awk} processes the values of command line assignments for escape
+sequences (@pxref{Constants, ,Constant Expressions}).
+
+@node Arithmetic Ops, Concatenation, Variables, Expressions
+@section Arithmetic Operators
+@cindex arithmetic operators
+@cindex operators, arithmetic
+@cindex addition
+@cindex subtraction
+@cindex multiplication
+@cindex division
+@cindex remainder
+@cindex quotient
+@cindex exponentiation
+
+The @code{awk} language uses the common arithmetic operators when
+evaluating expressions. All of these arithmetic operators follow normal
+precedence rules, and work as you would expect them to. This example
+divides field three by field four, adds field two, stores the result
+into field one, and prints the resulting altered input record:
+
+@example
+awk '@{ $1 = $2 + $3 / $4; print @}' inventory-shipped
+@end example
+
+The arithmetic operators in @code{awk} are:
+
+@table @code
+@item @var{x} + @var{y}
+Addition.
+
+@item @var{x} - @var{y}
+Subtraction.
+
+@item - @var{x}
+Negation.
+
+@item + @var{x}
+Unary plus. No real effect on the expression.
+
+@item @var{x} * @var{y}
+Multiplication.
+
+@item @var{x} / @var{y}
+Division. Since all numbers in @code{awk} are double-precision
+floating point, the result is not rounded to an integer: @code{3 / 4}
+has the value 0.75.
+
+@item @var{x} % @var{y}
+@iftex
+@cindex differences between @code{gawk} and @code{awk}
+@end iftex
+Remainder. The quotient is rounded toward zero to an integer,
+multiplied by @var{y} and this result is subtracted from @var{x}.
+This operation is sometimes known as ``trunc-mod.'' The following
+relation always holds:
+
+@example
+b * int(a / b) + (a % b) == a
+@end example
+
+One possibly undesirable effect of this definition of remainder is that
+@code{@var{x} % @var{y}} is negative if @var{x} is negative. Thus,
+
+@example
+-17 % 8 = -1
+@end example
+
+In other @code{awk} implementations, the signedness of the remainder
+may be machine dependent.
+
+@item @var{x} ^ @var{y}
+@itemx @var{x} ** @var{y}
+Exponentiation: @var{x} raised to the @var{y} power. @code{2 ^ 3} has
+the value 8. The character sequence @samp{**} is equivalent to
+@samp{^}. (The @sc{posix} standard only specifies the use of @samp{^}
+for exponentiation.)
+@end table
+
+@node Concatenation, Comparison Ops, Arithmetic Ops, Expressions
+@section String Concatenation
+
+@cindex string operators
+@cindex operators, string
+@cindex concatenation
+There is only one string operation: concatenation. It does not have a
+specific operator to represent it. Instead, concatenation is performed by
+writing expressions next to one another, with no operator. For example:
+
+@example
+awk '@{ print "Field number one: " $1 @}' BBS-list
+@end example
+
+@noindent
+produces, for the first record in @file{BBS-list}:
+
+@example
+Field number one: aardvark
+@end example
+
+Without the space in the string constant after the @samp{:}, the line
+would run together. For example:
+
+@example
+awk '@{ print "Field number one:" $1 @}' BBS-list
+@end example
+
+@noindent
+produces, for the first record in @file{BBS-list}:
+
+@example
+Field number one:aardvark
+@end example
+
+Since string concatenation does not have an explicit operator, it is
+often necessary to insure that it happens where you want it to by
+enclosing the items to be concatenated in parentheses. For example, the
+following code fragment does not concatenate @code{file} and @code{name}
+as you might expect:
+
+@example
+file = "file"
+name = "name"
+print "something meaningful" > file name
+@end example
+
+@noindent
+It is necessary to use the following:
+
+@example
+print "something meaningful" > (file name)
+@end example
+
+We recommend you use parentheses around concatenation in all but the
+most common contexts (such as in the right-hand operand of @samp{=}).
+
+@ignore
+@code{gawk} actually now allows a concatenation on the right hand
+side of a @code{>} redirection, but other @code{awk}s don't. So for
+now we won't mention that fact.
+@end ignore
+
+@node Comparison Ops, Boolean Ops, Concatenation, Expressions
+@section Comparison Expressions
+@cindex comparison expressions
+@cindex expressions, comparison
+@cindex relational operators
+@cindex operators, relational
+@cindex regexp operators
+
+@dfn{Comparison expressions} compare strings or numbers for
+relationships such as equality. They are written using @dfn{relational
+operators}, which are a superset of those in C. Here is a table of
+them:
+
+@table @code
+@item @var{x} < @var{y}
+True if @var{x} is less than @var{y}.
+
+@item @var{x} <= @var{y}
+True if @var{x} is less than or equal to @var{y}.
+
+@item @var{x} > @var{y}
+True if @var{x} is greater than @var{y}.
+
+@item @var{x} >= @var{y}
+True if @var{x} is greater than or equal to @var{y}.
+
+@item @var{x} == @var{y}
+True if @var{x} is equal to @var{y}.
+
+@item @var{x} != @var{y}
+True if @var{x} is not equal to @var{y}.
+
+@item @var{x} ~ @var{y}
+True if the string @var{x} matches the regexp denoted by @var{y}.
+
+@item @var{x} !~ @var{y}
+True if the string @var{x} does not match the regexp denoted by @var{y}.
+
+@item @var{subscript} in @var{array}
+True if array @var{array} has an element with the subscript @var{subscript}.
+@end table
+
+Comparison expressions have the value 1 if true and 0 if false.
+
+The rules @code{gawk} uses for performing comparisons are based on those
+in draft 11.2 of the @sc{posix} standard. The @sc{posix} standard introduced
+the concept of a @dfn{numeric string}, which is simply a string that looks
+like a number, for example, @code{@w{" +2"}}.
+
+@vindex CONVFMT
+When performing a relational operation, @code{gawk} considers the type of an
+operand to be the type it received on its last @emph{assignment}, rather
+than the type of its last @emph{use}
+(@pxref{Values, ,Numeric and String Values}).
+This type is @emph{unknown} when the operand is from an ``external'' source:
+field variables, command line arguments, array elements resulting from a
+@code{split} operation, and the value of an @code{ENVIRON} element.
+In this case only, if the operand is a numeric string, then it is
+considered to be of both string type and numeric type. If at least one
+operand of a comparison is of string type only, then a string
+comparison is performed. Any numeric operand will be converted to a
+string using the value of @code{CONVFMT}
+(@pxref{Conversion, ,Conversion of Strings and Numbers}).
+If one operand of a comparison is numeric, and the other operand is
+either numeric or both numeric and string, then @code{gawk} does a
+numeric comparison. If both operands have both types, then the
+comparison is numeric. Strings are compared
+by comparing the first character of each, then the second character of each,
+and so on. Thus @code{"10"} is less than @code{"9"}. If there are two
+strings where one is a prefix of the other, the shorter string is less than
+the longer one. Thus @code{"abc"} is less than @code{"abcd"}.@refill
+
+Here are some sample expressions, how @code{gawk} compares them, and what
+the result of the comparison is.
+
+@table @code
+@item 1.5 <= 2.0
+numeric comparison (true)
+
+@item "abc" >= "xyz"
+string comparison (false)
+
+@item 1.5 != " +2"
+string comparison (true)
+
+@item "1e2" < "3"
+string comparison (true)
+
+@item a = 2; b = "2"
+@itemx a == b
+string comparison (true)
+@end table
+
+@example
+echo 1e2 3 | awk '@{ print ($1 < $2) ? "true" : "false" @}'
+@end example
+
+@noindent
+prints @samp{false} since both @code{$1} and @code{$2} are numeric
+strings and thus have both string and numeric types, thus dictating
+a numeric comparison.
+
+The purpose of the comparison rules and the use of numeric strings is
+to attempt to produce the behavior that is ``least surprising,'' while
+still ``doing the right thing.''
+
+String comparisons and regular expression comparisons are very different.
+For example,
+
+@example
+$1 == "foo"
+@end example
+
+@noindent
+has the value of 1, or is true, if the first field of the current input
+record is precisely @samp{foo}. By contrast,
+
+@example
+$1 ~ /foo/
+@end example
+
+@noindent
+has the value 1 if the first field contains @samp{foo}, such as @samp{foobar}.
+
+The right hand operand of the @samp{~} and @samp{!~} operators may be
+either a constant regexp (@code{/@dots{}/}), or it may be an ordinary
+expression, in which case the value of the expression as a string is a
+dynamic regexp (@pxref{Regexp Usage, ,How to Use Regular Expressions}).
+
+@cindex regexp as expression
+In very recent implementations of @code{awk}, a constant regular
+expression in slashes by itself is also an expression. The regexp
+@code{/@var{regexp}/} is an abbreviation for this comparison expression:
+
+@example
+$0 ~ /@var{regexp}/
+@end example
+
+In some contexts it may be necessary to write parentheses around the
+regexp to avoid confusing the @code{gawk} parser. For example,
+@code{(/x/ - /y/) > threshold} is not allowed, but @code{((/x/) - (/y/))
+> threshold} parses properly.
+
+One special place where @code{/foo/} is @emph{not} an abbreviation for
+@code{$0 ~ /foo/} is when it is the right-hand operand of @samp{~} or
+@samp{!~}! @xref{Constants, ,Constant Expressions}, where this is
+discussed in more detail.
+
+@node Boolean Ops, Assignment Ops, Comparison Ops, Expressions
+@section Boolean Expressions
+@cindex expressions, boolean
+@cindex boolean expressions
+@cindex operators, boolean
+@cindex boolean operators
+@cindex logical operations
+@cindex and operator
+@cindex or operator
+@cindex not operator
+
+A @dfn{boolean expression} is a combination of comparison expressions or
+matching expressions, using the boolean operators ``or''
+(@samp{||}), ``and'' (@samp{&&}), and ``not'' (@samp{!}), along with
+parentheses to control nesting. The truth of the boolean expression is
+computed by combining the truth values of the component expressions.
+
+Boolean expressions can be used wherever comparison and matching
+expressions can be used. They can be used in @code{if}, @code{while}
+@code{do} and @code{for} statements. They have numeric values (1 if true,
+0 if false), which come into play if the result of the boolean expression
+is stored in a variable, or used in arithmetic.@refill
+
+In addition, every boolean expression is also a valid boolean pattern, so
+you can use it as a pattern to control the execution of rules.
+
+Here are descriptions of the three boolean operators, with an example of
+each. It may be instructive to compare these examples with the
+analogous examples of boolean patterns
+(@pxref{Boolean Patterns, ,Boolean Operators and Patterns}), which
+use the same boolean operators in patterns instead of expressions.@refill
+
+@table @code
+@item @var{boolean1} && @var{boolean2}
+True if both @var{boolean1} and @var{boolean2} are true. For example,
+the following statement prints the current input record if it contains
+both @samp{2400} and @samp{foo}.@refill
+
+@smallexample
+if ($0 ~ /2400/ && $0 ~ /foo/) print
+@end smallexample
+
+The subexpression @var{boolean2} is evaluated only if @var{boolean1}
+is true. This can make a difference when @var{boolean2} contains
+expressions that have side effects: in the case of @code{$0 ~ /foo/ &&
+($2 == bar++)}, the variable @code{bar} is not incremented if there is
+no @samp{foo} in the record.
+
+@item @var{boolean1} || @var{boolean2}
+True if at least one of @var{boolean1} or @var{boolean2} is true.
+For example, the following command prints all records in the input
+file @file{BBS-list} that contain @emph{either} @samp{2400} or
+@samp{foo}, or both.@refill
+
+@smallexample
+awk '@{ if ($0 ~ /2400/ || $0 ~ /foo/) print @}' BBS-list
+@end smallexample
+
+The subexpression @var{boolean2} is evaluated only if @var{boolean1}
+is false. This can make a difference when @var{boolean2} contains
+expressions that have side effects.
+
+@item !@var{boolean}
+True if @var{boolean} is false. For example, the following program prints
+all records in the input file @file{BBS-list} that do @emph{not} contain the
+string @samp{foo}.
+
+@smallexample
+awk '@{ if (! ($0 ~ /foo/)) print @}' BBS-list
+@end smallexample
+@end table
+
+@node Assignment Ops, Increment Ops, Boolean Ops, Expressions
+@section Assignment Expressions
+@cindex assignment operators
+@cindex operators, assignment
+@cindex expressions, assignment
+
+An @dfn{assignment} is an expression that stores a new value into a
+variable. For example, let's assign the value 1 to the variable
+@code{z}:@refill
+
+@example
+z = 1
+@end example
+
+After this expression is executed, the variable @code{z} has the value 1.
+Whatever old value @code{z} had before the assignment is forgotten.
+
+Assignments can store string values also. For example, this would store
+the value @code{"this food is good"} in the variable @code{message}:
+
+@example
+thing = "food"
+predicate = "good"
+message = "this " thing " is " predicate
+@end example
+
+@noindent
+(This also illustrates concatenation of strings.)
+
+The @samp{=} sign is called an @dfn{assignment operator}. It is the
+simplest assignment operator because the value of the right-hand
+operand is stored unchanged.
+
+@cindex side effect
+Most operators (addition, concatenation, and so on) have no effect
+except to compute a value. If you ignore the value, you might as well
+not use the operator. An assignment operator is different; it does
+produce a value, but even if you ignore the value, the assignment still
+makes itself felt through the alteration of the variable. We call this
+a @dfn{side effect}.
+
+@cindex lvalue
+The left-hand operand of an assignment need not be a variable
+(@pxref{Variables}); it can also be a field
+(@pxref{Changing Fields, ,Changing the Contents of a Field}) or
+an array element (@pxref{Arrays, ,Arrays in @code{awk}}).
+These are all called @dfn{lvalues},
+which means they can appear on the left-hand side of an assignment operator.
+The right-hand operand may be any expression; it produces the new value
+which the assignment stores in the specified variable, field or array
+element.@refill
+
+It is important to note that variables do @emph{not} have permanent types.
+The type of a variable is simply the type of whatever value it happens
+to hold at the moment. In the following program fragment, the variable
+@code{foo} has a numeric value at first, and a string value later on:
+
+@example
+foo = 1
+print foo
+foo = "bar"
+print foo
+@end example
+
+@noindent
+When the second assignment gives @code{foo} a string value, the fact that
+it previously had a numeric value is forgotten.
+
+An assignment is an expression, so it has a value: the same value that
+is assigned. Thus, @code{z = 1} as an expression has the value 1.
+One consequence of this is that you can write multiple assignments together:
+
+@example
+x = y = z = 0
+@end example
+
+@noindent
+stores the value 0 in all three variables. It does this because the
+value of @code{z = 0}, which is 0, is stored into @code{y}, and then
+the value of @code{y = z = 0}, which is 0, is stored into @code{x}.
+
+You can use an assignment anywhere an expression is called for. For
+example, it is valid to write @code{x != (y = 1)} to set @code{y} to 1
+and then test whether @code{x} equals 1. But this style tends to make
+programs hard to read; except in a one-shot program, you should
+rewrite it to get rid of such nesting of assignments. This is never very
+hard.
+
+Aside from @samp{=}, there are several other assignment operators that
+do arithmetic with the old value of the variable. For example, the
+operator @samp{+=} computes a new value by adding the right-hand value
+to the old value of the variable. Thus, the following assignment adds
+5 to the value of @code{foo}:
+
+@example
+foo += 5
+@end example
+
+@noindent
+This is precisely equivalent to the following:
+
+@example
+foo = foo + 5
+@end example
+
+@noindent
+Use whichever one makes the meaning of your program clearer.
+
+Here is a table of the arithmetic assignment operators. In each
+case, the right-hand operand is an expression whose value is converted
+to a number.
+
+@table @code
+@item @var{lvalue} += @var{increment}
+Adds @var{increment} to the value of @var{lvalue} to make the new value
+of @var{lvalue}.
+
+@item @var{lvalue} -= @var{decrement}
+Subtracts @var{decrement} from the value of @var{lvalue}.
+
+@item @var{lvalue} *= @var{coefficient}
+Multiplies the value of @var{lvalue} by @var{coefficient}.
+
+@item @var{lvalue} /= @var{quotient}
+Divides the value of @var{lvalue} by @var{quotient}.
+
+@item @var{lvalue} %= @var{modulus}
+Sets @var{lvalue} to its remainder by @var{modulus}.
+
+@item @var{lvalue} ^= @var{power}
+@itemx @var{lvalue} **= @var{power}
+Raises @var{lvalue} to the power @var{power}.
+(Only the @code{^=} operator is specified by @sc{posix}.)
+@end table
+
+@ignore
+From: gatech!ames!elroy!cit-vax!EQL.Caltech.Edu!rankin (Pat Rankin)
+ In the discussion of assignment operators, it states that
+``foo += 5'' "is precisely equivalent to" ``foo = foo + 5'' (p.77). That
+may be true for simple variables, but it's not true for expressions with
+side effects, like array references. For proof, try
+ BEGIN {
+ foo[rand()] += 5; for (x in foo) print x, foo[x]
+ bar[rand()] = bar[rand()] + 5; for (x in bar) print x, bar[x]
+ }
+I suspect that the original statement is simply untrue--that '+=' is more
+efficient in all cases.
+
+ADR --- Try to add something about this here for the next go 'round.
+@end ignore
+
+@node Increment Ops, Conversion, Assignment Ops, Expressions
+@section Increment Operators
+
+@cindex increment operators
+@cindex operators, increment
+@dfn{Increment operators} increase or decrease the value of a variable
+by 1. You could do the same thing with an assignment operator, so
+the increment operators add no power to the @code{awk} language; but they
+are convenient abbreviations for something very common.
+
+The operator to add 1 is written @samp{++}. It can be used to increment
+a variable either before or after taking its value.
+
+To pre-increment a variable @var{v}, write @code{++@var{v}}. This adds
+1 to the value of @var{v} and that new value is also the value of this
+expression. The assignment expression @code{@var{v} += 1} is completely
+equivalent.
+
+Writing the @samp{++} after the variable specifies post-increment. This
+increments the variable value just the same; the difference is that the
+value of the increment expression itself is the variable's @emph{old}
+value. Thus, if @code{foo} has the value 4, then the expression @code{foo++}
+has the value 4, but it changes the value of @code{foo} to 5.
+
+The post-increment @code{foo++} is nearly equivalent to writing @code{(foo
++= 1) - 1}. It is not perfectly equivalent because all numbers in
+@code{awk} are floating point: in floating point, @code{foo + 1 - 1} does
+not necessarily equal @code{foo}. But the difference is minute as
+long as you stick to numbers that are fairly small (less than a trillion).
+
+Any lvalue can be incremented. Fields and array elements are incremented
+just like variables. (Use @samp{$(i++)} when you wish to do a field reference
+and a variable increment at the same time. The parentheses are necessary
+because of the precedence of the field reference operator, @samp{$}.)
+@c expert information in the last parenthetical remark
+
+The decrement operator @samp{--} works just like @samp{++} except that
+it subtracts 1 instead of adding. Like @samp{++}, it can be used before
+the lvalue to pre-decrement or after it to post-decrement.
+
+Here is a summary of increment and decrement expressions.
+
+@table @code
+@item ++@var{lvalue}
+This expression increments @var{lvalue} and the new value becomes the
+value of this expression.
+
+@item @var{lvalue}++
+This expression causes the contents of @var{lvalue} to be incremented.
+The value of the expression is the @emph{old} value of @var{lvalue}.
+
+@item --@var{lvalue}
+Like @code{++@var{lvalue}}, but instead of adding, it subtracts. It
+decrements @var{lvalue} and delivers the value that results.
+
+@item @var{lvalue}--
+Like @code{@var{lvalue}++}, but instead of adding, it subtracts. It
+decrements @var{lvalue}. The value of the expression is the @emph{old}
+value of @var{lvalue}.
+@end table
+
+@node Conversion, Values, Increment Ops, Expressions
+@section Conversion of Strings and Numbers
+
+@cindex conversion of strings and numbers
+Strings are converted to numbers, and numbers to strings, if the context
+of the @code{awk} program demands it. For example, if the value of
+either @code{foo} or @code{bar} in the expression @code{foo + bar}
+happens to be a string, it is converted to a number before the addition
+is performed. If numeric values appear in string concatenation, they
+are converted to strings. Consider this:@refill
+
+@example
+two = 2; three = 3
+print (two three) + 4
+@end example
+
+@noindent
+This eventually prints the (numeric) value 27. The numeric values of
+the variables @code{two} and @code{three} are converted to strings and
+concatenated together, and the resulting string is converted back to the
+number 23, to which 4 is then added.
+
+If, for some reason, you need to force a number to be converted to a
+string, concatenate the null string with that number. To force a string
+to be converted to a number, add zero to that string.
+
+A string is converted to a number by interpreting a numeric prefix
+of the string as numerals:
+@code{"2.5"} converts to 2.5, @code{"1e3"} converts to 1000, and @code{"25fix"}
+has a numeric value of 25.
+Strings that can't be interpreted as valid numbers are converted to
+zero.
+
+@vindex CONVFMT
+The exact manner in which numbers are converted into strings is controlled
+by the @code{awk} built-in variable @code{CONVFMT} (@pxref{Built-in Variables}).
+Numbers are converted using a special version of the @code{sprintf} function
+(@pxref{Built-in, ,Built-in Functions}) with @code{CONVFMT} as the format
+specifier.@refill
+
+@code{CONVFMT}'s default value is @code{"%.6g"}, which prints a value with
+at least six significant digits. For some applications you will want to
+change it to specify more precision. Double precision on most modern
+machines gives you 16 or 17 decimal digits of precision.
+
+Strange results can happen if you set @code{CONVFMT} to a string that doesn't
+tell @code{sprintf} how to format floating point numbers in a useful way.
+For example, if you forget the @samp{%} in the format, all numbers will be
+converted to the same constant string.@refill
+
+As a special case, if a number is an integer, then the result of converting
+it to a string is @emph{always} an integer, no matter what the value of
+@code{CONVFMT} may be. Given the following code fragment:
+
+@example
+CONVFMT = "%2.2f"
+a = 12
+b = a ""
+@end example
+
+@noindent
+@code{b} has the value @code{"12"}, not @code{"12.00"}.
+
+@ignore
+For the 2.14 version, describe the ``stickyness'' of conversions. Right now
+the manual assumes everywhere that variables are either numbers or strings;
+in fact both kinds of values may be valid. If both happen to be valid, a
+conversion isn't necessary and isn't done. Revising the manual to be
+consistent with this, though, is too big a job to tackle at the moment.
+
+7/92: This has sort of been done, only the section isn't completely right!
+ What to do?
+7/92: Pretty much fixed, at least for the short term, thanks to text
+ from David.
+@end ignore
+
+@vindex OFMT
+Prior to the @sc{posix} standard, @code{awk} specified that the value
+of @code{OFMT} was used for converting numbers to strings. @code{OFMT}
+specifies the output format to use when printing numbers with @code{print}.
+@code{CONVFMT} was introduced in order to separate the semantics of
+conversions from the semantics of printing. Both @code{CONVFMT} and
+@code{OFMT} have the same default value: @code{"%.6g"}. In the vast majority
+of cases, old @code{awk} programs will not change their behavior.
+However, this use of @code{OFMT} is something to keep in mind if you must
+port your program to other implementations of @code{awk}; we recommend
+that instead of changing your programs, you just port @code{gawk} itself!@refill
+
+@node Values, Conditional Exp, Conversion, Expressions
+@section Numeric and String Values
+@cindex conversion of strings and numbers
+
+Through most of this manual, we present @code{awk} values (such as constants,
+fields, or variables) as @emph{either} numbers @emph{or} strings. This is
+a convenient way to think about them, since typically they are used in only
+one way, or the other.
+
+In truth though, @code{awk} values can be @emph{both} string and
+numeric, at the same time. Internally, @code{awk} represents values
+with a string, a (floating point) number, and an indication that one,
+the other, or both representations of the value are valid.
+
+Keeping track of both kinds of values is important for execution
+efficiency: a variable can acquire a string value the first time it
+is used as a string, and then that string value can be used until the
+variable is assigned a new value. Thus, if a variable with only a numeric
+value is used in several concatenations in a row, it only has to be given
+a string representation once. The numeric value remains valid, so that
+no conversion back to a number is necessary if the variable is later used
+in an arithmetic expression.
+
+Tracking both kinds of values is also important for precise numerical
+calculations. Consider the following:
+
+@smallexample
+a = 123.321
+CONVFMT = "%3.1f"
+b = a " is a number"
+c = a + 1.654
+@end smallexample
+
+@noindent
+The variable @code{a} receives a string value in the concatenation and
+assignment to @code{b}. The string value of @code{a} is @code{"123.3"}.
+If the numeric value was lost when it was converted to a string, then the
+numeric use of @code{a} in the last statement would lose information.
+@code{c} would be assigned the value 124.954 instead of 124.975.
+Such errors accumulate rapidly, and very adversely affect numeric
+computations.@refill
+
+Once a numeric value acquires a corresponding string value, it stays valid
+until a new assignment is made. If @code{CONVFMT}
+(@pxref{Conversion, ,Conversion of Strings and Numbers}) changes in the
+meantime, the old string value will still be used. For example:@refill
+
+@smallexample
+BEGIN @{
+ CONVFMT = "%2.2f"
+ a = 123.456
+ b = a "" # force `a' to have string value too
+ printf "a = %s\n", a
+ CONVFMT = "%.6g"
+ printf "a = %s\n", a
+ a += 0 # make `a' numeric only again
+ printf "a = %s\n", a # use `a' as string
+@}
+@end smallexample
+
+@noindent
+This program prints @samp{a = 123.46} twice, and then prints
+@samp{a = 123.456}.
+
+@xref{Conversion, ,Conversion of Strings and Numbers}, for the rules that
+specify how string values are made from numeric values.
+
+@node Conditional Exp, Function Calls, Values, Expressions
+@section Conditional Expressions
+@cindex conditional expression
+@cindex expression, conditional
+
+A @dfn{conditional expression} is a special kind of expression with
+three operands. It allows you to use one expression's value to select
+one of two other expressions.
+
+The conditional expression looks the same as in the C language:
+
+@example
+@var{selector} ? @var{if-true-exp} : @var{if-false-exp}
+@end example
+
+@noindent
+There are three subexpressions. The first, @var{selector}, is always
+computed first. If it is ``true'' (not zero and not null) then
+@var{if-true-exp} is computed next and its value becomes the value of
+the whole expression. Otherwise, @var{if-false-exp} is computed next
+and its value becomes the value of the whole expression.@refill
+
+For example, this expression produces the absolute value of @code{x}:
+
+@example
+x > 0 ? x : -x
+@end example
+
+Each time the conditional expression is computed, exactly one of
+@var{if-true-exp} and @var{if-false-exp} is computed; the other is ignored.
+This is important when the expressions contain side effects. For example,
+this conditional expression examines element @code{i} of either array
+@code{a} or array @code{b}, and increments @code{i}.
+
+@example
+x == y ? a[i++] : b[i++]
+@end example
+
+@noindent
+This is guaranteed to increment @code{i} exactly once, because each time
+one or the other of the two increment expressions is executed,
+and the other is not.
+
+@node Function Calls, Precedence, Conditional Exp, Expressions
+@section Function Calls
+@cindex function call
+@cindex calling a function
+
+A @dfn{function} is a name for a particular calculation. Because it has
+a name, you can ask for it by name at any point in the program. For
+example, the function @code{sqrt} computes the square root of a number.
+
+A fixed set of functions are @dfn{built-in}, which means they are
+available in every @code{awk} program. The @code{sqrt} function is one
+of these. @xref{Built-in, ,Built-in Functions}, for a list of built-in
+functions and their descriptions. In addition, you can define your own
+functions in the program for use elsewhere in the same program.
+@xref{User-defined, ,User-defined Functions}, for how to do this.@refill
+
+@cindex arguments in function call
+The way to use a function is with a @dfn{function call} expression,
+which consists of the function name followed by a list of
+@dfn{arguments} in parentheses. The arguments are expressions which
+give the raw materials for the calculation that the function will do.
+When there is more than one argument, they are separated by commas. If
+there are no arguments, write just @samp{()} after the function name.
+Here are some examples:
+
+@example
+sqrt(x^2 + y^2) # @r{One argument}
+atan2(y, x) # @r{Two arguments}
+rand() # @r{No arguments}
+@end example
+
+@strong{Do not put any space between the function name and the
+open-parenthesis!} A user-defined function name looks just like the name of
+a variable, and space would make the expression look like concatenation
+of a variable with an expression inside parentheses. Space before the
+parenthesis is harmless with built-in functions, but it is best not to get
+into the habit of using space to avoid mistakes with user-defined
+functions.
+
+Each function expects a particular number of arguments. For example, the
+@code{sqrt} function must be called with a single argument, the number
+to take the square root of:
+
+@example
+sqrt(@var{argument})
+@end example
+
+Some of the built-in functions allow you to omit the final argument.
+If you do so, they use a reasonable default.
+@xref{Built-in, ,Built-in Functions}, for full details. If arguments
+are omitted in calls to user-defined functions, then those arguments are
+treated as local variables, initialized to the null string
+(@pxref{User-defined, ,User-defined Functions}).@refill
+
+Like every other expression, the function call has a value, which is
+computed by the function based on the arguments you give it. In this
+example, the value of @code{sqrt(@var{argument})} is the square root of the
+argument. A function can also have side effects, such as assigning the
+values of certain variables or doing I/O.
+
+Here is a command to read numbers, one number per line, and print the
+square root of each one:
+
+@example
+awk '@{ print "The square root of", $1, "is", sqrt($1) @}'
+@end example
+
+@node Precedence, , Function Calls, Expressions
+@section Operator Precedence (How Operators Nest)
+@cindex precedence
+@cindex operator precedence
+
+@dfn{Operator precedence} determines how operators are grouped, when
+different operators appear close by in one expression. For example,
+@samp{*} has higher precedence than @samp{+}; thus, @code{a + b * c}
+means to multiply @code{b} and @code{c}, and then add @code{a} to the
+product (i.e., @code{a + (b * c)}).
+
+You can overrule the precedence of the operators by using parentheses.
+You can think of the precedence rules as saying where the
+parentheses are assumed if you do not write parentheses yourself. In
+fact, it is wise to always use parentheses whenever you have an unusual
+combination of operators, because other people who read the program may
+not remember what the precedence is in this case. You might forget,
+too; then you could make a mistake. Explicit parentheses will help prevent
+any such mistake.
+
+When operators of equal precedence are used together, the leftmost
+operator groups first, except for the assignment, conditional and
+exponentiation operators, which group in the opposite order.
+Thus, @code{a - b + c} groups as @code{(a - b) + c};
+@code{a = b = c} groups as @code{a = (b = c)}.@refill
+
+The precedence of prefix unary operators does not matter as long as only
+unary operators are involved, because there is only one way to parse
+them---innermost first. Thus, @code{$++i} means @code{$(++i)} and
+@code{++$x} means @code{++($x)}. However, when another operator follows
+the operand, then the precedence of the unary operators can matter.
+Thus, @code{$x^2} means @code{($x)^2}, but @code{-x^2} means
+@code{-(x^2)}, because @samp{-} has lower precedence than @samp{^}
+while @samp{$} has higher precedence.
+
+Here is a table of the operators of @code{awk}, in order of increasing
+precedence:
+
+@table @asis
+@item assignment
+@samp{=}, @samp{+=}, @samp{-=}, @samp{*=}, @samp{/=}, @samp{%=},
+@samp{^=}, @samp{**=}. These operators group right-to-left.
+(The @samp{**=} operator is not specified by @sc{posix}.)
+
+@item conditional
+@samp{?:}. This operator groups right-to-left.
+
+@item logical ``or''.
+@samp{||}.
+
+@item logical ``and''.
+@samp{&&}.
+
+@item array membership
+@samp{in}.
+
+@item matching
+@samp{~}, @samp{!~}.
+
+@item relational, and redirection
+The relational operators and the redirections have the same precedence
+level. Characters such as @samp{>} serve both as relationals and as
+redirections; the context distinguishes between the two meanings.
+
+The relational operators are @samp{<}, @samp{<=}, @samp{==}, @samp{!=},
+@samp{>=} and @samp{>}.
+
+The I/O redirection operators are @samp{<}, @samp{>}, @samp{>>} and
+@samp{|}.
+
+Note that I/O redirection operators in @code{print} and @code{printf}
+statements belong to the statement level, not to expressions. The
+redirection does not produce an expression which could be the operand of
+another operator. As a result, it does not make sense to use a
+redirection operator near another operator of lower precedence, without
+parentheses. Such combinations, for example @samp{print foo > a ? b :
+c}, result in syntax errors.
+
+@item concatenation
+No special token is used to indicate concatenation.
+The operands are simply written side by side.
+
+@item add, subtract
+@samp{+}, @samp{-}.
+
+@item multiply, divide, mod
+@samp{*}, @samp{/}, @samp{%}.
+
+@item unary plus, minus, ``not''
+@samp{+}, @samp{-}, @samp{!}.
+
+@item exponentiation
+@samp{^}, @samp{**}. These operators group right-to-left.
+(The @samp{**} operator is not specified by @sc{posix}.)
+
+@item increment, decrement
+@samp{++}, @samp{--}.
+
+@item field
+@samp{$}.
+@end table
+
+@node Statements, Arrays, Expressions, Top
+@chapter Control Statements in Actions
+@cindex control statement
+
+@dfn{Control statements} such as @code{if}, @code{while}, and so on
+control the flow of execution in @code{awk} programs. Most of the
+control statements in @code{awk} are patterned on similar statements in
+C.
+
+All the control statements start with special keywords such as @code{if}
+and @code{while}, to distinguish them from simple expressions.
+
+Many control statements contain other statements; for example, the
+@code{if} statement contains another statement which may or may not be
+executed. The contained statement is called the @dfn{body}. If you
+want to include more than one statement in the body, group them into a
+single compound statement with curly braces, separating them with
+newlines or semicolons.
+
+@menu
+* If Statement:: Conditionally execute
+ some @code{awk} statements.
+* While Statement:: Loop until some condition is satisfied.
+* Do Statement:: Do specified action while looping until some
+ condition is satisfied.
+* For Statement:: Another looping statement, that provides
+ initialization and increment clauses.
+* Break Statement:: Immediately exit the innermost enclosing loop.
+* Continue Statement:: Skip to the end of the innermost
+ enclosing loop.
+* Next Statement:: Stop processing the current input record.
+* Next File Statement:: Stop processing the current file.
+* Exit Statement:: Stop execution of @code{awk}.
+@end menu
+
+@node If Statement, While Statement, Statements, Statements
+@section The @code{if} Statement
+
+@cindex @code{if} statement
+The @code{if}-@code{else} statement is @code{awk}'s decision-making
+statement. It looks like this:@refill
+
+@example
+if (@var{condition}) @var{then-body} @r{[}else @var{else-body}@r{]}
+@end example
+
+@noindent
+@var{condition} is an expression that controls what the rest of the
+statement will do. If @var{condition} is true, @var{then-body} is
+executed; otherwise, @var{else-body} is executed (assuming that the
+@code{else} clause is present). The @code{else} part of the statement is
+optional. The condition is considered false if its value is zero or
+the null string, and true otherwise.@refill
+
+Here is an example:
+
+@example
+if (x % 2 == 0)
+ print "x is even"
+else
+ print "x is odd"
+@end example
+
+In this example, if the expression @code{x % 2 == 0} is true (that is,
+the value of @code{x} is divisible by 2), then the first @code{print}
+statement is executed, otherwise the second @code{print} statement is
+performed.@refill
+
+If the @code{else} appears on the same line as @var{then-body}, and
+@var{then-body} is not a compound statement (i.e., not surrounded by
+curly braces), then a semicolon must separate @var{then-body} from
+@code{else}. To illustrate this, let's rewrite the previous example:
+
+@example
+awk '@{ if (x % 2 == 0) print "x is even"; else
+ print "x is odd" @}'
+@end example
+
+@noindent
+If you forget the @samp{;}, @code{awk} won't be able to parse the
+statement, and you will get a syntax error.
+
+We would not actually write this example this way, because a human
+reader might fail to see the @code{else} if it were not the first thing
+on its line.
+
+@node While Statement, Do Statement, If Statement, Statements
+@section The @code{while} Statement
+@cindex @code{while} statement
+@cindex loop
+@cindex body of a loop
+
+In programming, a @dfn{loop} means a part of a program that is (or at least can
+be) executed two or more times in succession.
+
+The @code{while} statement is the simplest looping statement in
+@code{awk}. It repeatedly executes a statement as long as a condition is
+true. It looks like this:
+
+@example
+while (@var{condition})
+ @var{body}
+@end example
+
+@noindent
+Here @var{body} is a statement that we call the @dfn{body} of the loop,
+and @var{condition} is an expression that controls how long the loop
+keeps running.
+
+The first thing the @code{while} statement does is test @var{condition}.
+If @var{condition} is true, it executes the statement @var{body}.
+(@var{condition} is true when the value
+is not zero and not a null string.) After @var{body} has been executed,
+@var{condition} is tested again, and if it is still true, @var{body} is
+executed again. This process repeats until @var{condition} is no longer
+true. If @var{condition} is initially false, the body of the loop is
+never executed.@refill
+
+This example prints the first three fields of each record, one per line.
+
+@example
+awk '@{ i = 1
+ while (i <= 3) @{
+ print $i
+ i++
+ @}
+@}'
+@end example
+
+@noindent
+Here the body of the loop is a compound statement enclosed in braces,
+containing two statements.
+
+The loop works like this: first, the value of @code{i} is set to 1.
+Then, the @code{while} tests whether @code{i} is less than or equal to
+three. This is the case when @code{i} equals one, so the @code{i}-th
+field is printed. Then the @code{i++} increments the value of @code{i}
+and the loop repeats. The loop terminates when @code{i} reaches 4.
+
+As you can see, a newline is not required between the condition and the
+body; but using one makes the program clearer unless the body is a
+compound statement or is very simple. The newline after the open-brace
+that begins the compound statement is not required either, but the
+program would be hard to read without it.
+
+@node Do Statement, For Statement, While Statement, Statements
+@section The @code{do}-@code{while} Statement
+
+The @code{do} loop is a variation of the @code{while} looping statement.
+The @code{do} loop executes the @var{body} once, then repeats @var{body}
+as long as @var{condition} is true. It looks like this:
+
+@example
+do
+ @var{body}
+while (@var{condition})
+@end example
+
+Even if @var{condition} is false at the start, @var{body} is executed at
+least once (and only once, unless executing @var{body} makes
+@var{condition} true). Contrast this with the corresponding
+@code{while} statement:
+
+@example
+while (@var{condition})
+ @var{body}
+@end example
+
+@noindent
+This statement does not execute @var{body} even once if @var{condition}
+is false to begin with.
+
+Here is an example of a @code{do} statement:
+
+@example
+awk '@{ i = 1
+ do @{
+ print $0
+ i++
+ @} while (i <= 10)
+@}'
+@end example
+
+@noindent
+prints each input record ten times. It isn't a very realistic example,
+since in this case an ordinary @code{while} would do just as well. But
+this reflects actual experience; there is only occasionally a real use
+for a @code{do} statement.@refill
+
+@node For Statement, Break Statement, Do Statement, Statements
+@section The @code{for} Statement
+@cindex @code{for} statement
+
+The @code{for} statement makes it more convenient to count iterations of a
+loop. The general form of the @code{for} statement looks like this:@refill
+
+@example
+for (@var{initialization}; @var{condition}; @var{increment})
+ @var{body}
+@end example
+
+@noindent
+This statement starts by executing @var{initialization}. Then, as long
+as @var{condition} is true, it repeatedly executes @var{body} and then
+@var{increment}. Typically @var{initialization} sets a variable to
+either zero or one, @var{increment} adds 1 to it, and @var{condition}
+compares it against the desired number of iterations.
+
+Here is an example of a @code{for} statement:
+
+@example
+@group
+awk '@{ for (i = 1; i <= 3; i++)
+ print $i
+@}'
+@end group
+@end example
+
+@noindent
+This prints the first three fields of each input record, one field per
+line.
+
+In the @code{for} statement, @var{body} stands for any statement, but
+@var{initialization}, @var{condition} and @var{increment} are just
+expressions. You cannot set more than one variable in the
+@var{initialization} part unless you use a multiple assignment statement
+such as @code{x = y = 0}, which is possible only if all the initial values
+are equal. (But you can initialize additional variables by writing
+their assignments as separate statements preceding the @code{for} loop.)
+
+The same is true of the @var{increment} part; to increment additional
+variables, you must write separate statements at the end of the loop.
+The C compound expression, using C's comma operator, would be useful in
+this context, but it is not supported in @code{awk}.
+
+Most often, @var{increment} is an increment expression, as in the
+example above. But this is not required; it can be any expression
+whatever. For example, this statement prints all the powers of 2
+between 1 and 100:
+
+@example
+for (i = 1; i <= 100; i *= 2)
+ print i
+@end example
+
+Any of the three expressions in the parentheses following the @code{for} may
+be omitted if there is nothing to be done there. Thus, @w{@samp{for (;x
+> 0;)}} is equivalent to @w{@samp{while (x > 0)}}. If the
+@var{condition} is omitted, it is treated as @var{true}, effectively
+yielding an @dfn{infinite loop} (i.e., a loop that will never
+terminate).@refill
+
+In most cases, a @code{for} loop is an abbreviation for a @code{while}
+loop, as shown here:
+
+@example
+@var{initialization}
+while (@var{condition}) @{
+ @var{body}
+ @var{increment}
+@}
+@end example
+
+@noindent
+The only exception is when the @code{continue} statement
+(@pxref{Continue Statement, ,The @code{continue} Statement}) is used
+inside the loop; changing a @code{for} statement to a @code{while}
+statement in this way can change the effect of the @code{continue}
+statement inside the loop.@refill
+
+There is an alternate version of the @code{for} loop, for iterating over
+all the indices of an array:
+
+@example
+for (i in array)
+ @var{do something with} array[i]
+@end example
+
+@noindent
+@xref{Arrays, ,Arrays in @code{awk}}, for more information on this
+version of the @code{for} loop.
+
+The @code{awk} language has a @code{for} statement in addition to a
+@code{while} statement because often a @code{for} loop is both less work to
+type and more natural to think of. Counting the number of iterations is
+very common in loops. It can be easier to think of this counting as part
+of looping rather than as something to do inside the loop.
+
+The next section has more complicated examples of @code{for} loops.
+
+@node Break Statement, Continue Statement, For Statement, Statements
+@section The @code{break} Statement
+@cindex @code{break} statement
+@cindex loops, exiting
+
+The @code{break} statement jumps out of the innermost @code{for},
+@code{while}, or @code{do}-@code{while} loop that encloses it. The
+following example finds the smallest divisor of any integer, and also
+identifies prime numbers:@refill
+
+@smallexample
+awk '# find smallest divisor of num
+ @{ num = $1
+ for (div = 2; div*div <= num; div++)
+ if (num % div == 0)
+ break
+ if (num % div == 0)
+ printf "Smallest divisor of %d is %d\n", num, div
+ else
+ printf "%d is prime\n", num @}'
+@end smallexample
+
+When the remainder is zero in the first @code{if} statement, @code{awk}
+immediately @dfn{breaks out} of the containing @code{for} loop. This means
+that @code{awk} proceeds immediately to the statement following the loop
+and continues processing. (This is very different from the @code{exit}
+statement which stops the entire @code{awk} program.
+@xref{Exit Statement, ,The @code{exit} Statement}.)@refill
+
+Here is another program equivalent to the previous one. It illustrates how
+the @var{condition} of a @code{for} or @code{while} could just as well be
+replaced with a @code{break} inside an @code{if}:
+
+@smallexample
+@group
+awk '# find smallest divisor of num
+ @{ num = $1
+ for (div = 2; ; div++) @{
+ if (num % div == 0) @{
+ printf "Smallest divisor of %d is %d\n", num, div
+ break
+ @}
+ if (div*div > num) @{
+ printf "%d is prime\n", num
+ break
+ @}
+ @}
+@}'
+@end group
+@end smallexample
+
+@node Continue Statement, Next Statement, Break Statement, Statements
+@section The @code{continue} Statement
+
+@cindex @code{continue} statement
+The @code{continue} statement, like @code{break}, is used only inside
+@code{for}, @code{while}, and @code{do}-@code{while} loops. It skips
+over the rest of the loop body, causing the next cycle around the loop
+to begin immediately. Contrast this with @code{break}, which jumps out
+of the loop altogether. Here is an example:@refill
+
+@example
+# print names that don't contain the string "ignore"
+
+# first, save the text of each line
+@{ names[NR] = $0 @}
+
+# print what we're interested in
+END @{
+ for (x in names) @{
+ if (names[x] ~ /ignore/)
+ continue
+ print names[x]
+ @}
+@}
+@end example
+
+If one of the input records contains the string @samp{ignore}, this
+example skips the print statement for that record, and continues back to
+the first statement in the loop.
+
+This is not a practical example of @code{continue}, since it would be
+just as easy to write the loop like this:
+
+@example
+for (x in names)
+ if (names[x] !~ /ignore/)
+ print names[x]
+@end example
+
+@ignore
+from brennan@boeing.com:
+
+page 90, section 9.6. The example is too artificial as
+the one line program
+
+ !/ignore/
+
+does the same thing.
+@end ignore
+@c ADR --- he's right, but don't worry about this for now
+
+The @code{continue} statement in a @code{for} loop directs @code{awk} to
+skip the rest of the body of the loop, and resume execution with the
+increment-expression of the @code{for} statement. The following program
+illustrates this fact:@refill
+
+@example
+awk 'BEGIN @{
+ for (x = 0; x <= 20; x++) @{
+ if (x == 5)
+ continue
+ printf ("%d ", x)
+ @}
+ print ""
+@}'
+@end example
+
+@noindent
+This program prints all the numbers from 0 to 20, except for 5, for
+which the @code{printf} is skipped. Since the increment @code{x++}
+is not skipped, @code{x} does not remain stuck at 5. Contrast the
+@code{for} loop above with the @code{while} loop:
+
+@example
+awk 'BEGIN @{
+ x = 0
+ while (x <= 20) @{
+ if (x == 5)
+ continue
+ printf ("%d ", x)
+ x++
+ @}
+ print ""
+@}'
+@end example
+
+@noindent
+This program loops forever once @code{x} gets to 5.
+
+As described above, the @code{continue} statement has no meaning when
+used outside the body of a loop. However, although it was never documented,
+historical implementations of @code{awk} have treated the @code{continue}
+statement outside of a loop as if it were a @code{next} statement
+(@pxref{Next Statement, ,The @code{next} Statement}).
+By default, @code{gawk} silently supports this usage. However, if
+@samp{-W posix} has been specified on the command line
+(@pxref{Command Line, ,Invoking @code{awk}}),
+it will be treated as an error, since the @sc{posix} standard specifies
+that @code{continue} should only be used inside the body of a loop.@refill
+
+@node Next Statement, Next File Statement, Continue Statement, Statements
+@section The @code{next} Statement
+@cindex @code{next} statement
+
+The @code{next} statement forces @code{awk} to immediately stop processing
+the current record and go on to the next record. This means that no
+further rules are executed for the current record. The rest of the
+current rule's action is not executed either.
+
+Contrast this with the effect of the @code{getline} function
+(@pxref{Getline, ,Explicit Input with @code{getline}}). That too causes
+@code{awk} to read the next record immediately, but it does not alter the
+flow of control in any way. So the rest of the current action executes
+with a new input record.
+
+At the highest level, @code{awk} program execution is a loop that reads
+an input record and then tests each rule's pattern against it. If you
+think of this loop as a @code{for} statement whose body contains the
+rules, then the @code{next} statement is analogous to a @code{continue}
+statement: it skips to the end of the body of this implicit loop, and
+executes the increment (which reads another record).
+
+For example, if your @code{awk} program works only on records with four
+fields, and you don't want it to fail when given bad input, you might
+use this rule near the beginning of the program:
+
+@smallexample
+NF != 4 @{
+ printf("line %d skipped: doesn't have 4 fields", FNR) > "/dev/stderr"
+ next
+@}
+@end smallexample
+
+@noindent
+so that the following rules will not see the bad record. The error
+message is redirected to the standard error output stream, as error
+messages should be. @xref{Special Files, ,Standard I/O Streams}.
+
+According to the @sc{posix} standard, the behavior is undefined if
+the @code{next} statement is used in a @code{BEGIN} or @code{END} rule.
+@code{gawk} will treat it as a syntax error.
+
+If the @code{next} statement causes the end of the input to be reached,
+then the code in the @code{END} rules, if any, will be executed.
+@xref{BEGIN/END, ,@code{BEGIN} and @code{END} Special Patterns}.
+
+@node Next File Statement, Exit Statement, Next Statement, Statements
+@section The @code{next file} Statement
+
+@cindex @code{next file} statement
+The @code{next file} statement is similar to the @code{next} statement.
+However, instead of abandoning processing of the current record, the
+@code{next file} statement instructs @code{awk} to stop processing the
+current data file.
+
+Upon execution of the @code{next file} statement, @code{FILENAME} is
+updated to the name of the next data file listed on the command line,
+@code{FNR} is reset to 1, and processing starts over with the first
+rule in the progam. @xref{Built-in Variables}.
+
+If the @code{next file} statement causes the end of the input to be reached,
+then the code in the @code{END} rules, if any, will be executed.
+@xref{BEGIN/END, ,@code{BEGIN} and @code{END} Special Patterns}.
+
+The @code{next file} statement is a @code{gawk} extension; it is not
+(currently) available in any other @code{awk} implementation. You can
+simulate its behavior by creating a library file named @file{nextfile.awk},
+with the following contents. (This sample program uses user-defined
+functions, a feature that has not been presented yet.
+@xref{User-defined, ,User-defined Functions},
+for more information.)@refill
+
+@smallexample
+# nextfile --- function to skip remaining records in current file
+
+# this should be read in before the "main" awk program
+
+function nextfile() @{ _abandon_ = FILENAME; next @}
+
+_abandon_ == FILENAME && FNR > 1 @{ next @}
+_abandon_ == FILENAME && FNR == 1 @{ _abandon_ = "" @}
+@end smallexample
+
+The @code{nextfile} function simply sets a ``private'' variable@footnote{Since
+all variables in @code{awk} are global, this program uses the common
+practice of prefixing the variable name with an underscore. In fact, it
+also suffixes the variable name with an underscore, as extra insurance
+against using a variable name that might be used in some other library
+file.} to the name of the current data file, and then retrieves the next
+record. Since this file is read before the main @code{awk} program,
+the rules that follows the function definition will be executed before the
+rules in the main program. The first rule continues to skip records as long as
+the name of the input file has not changed, and this is not the first
+record in the file. This rule is sufficient most of the time. But what if
+the @emph{same} data file is named twice in a row on the command line?
+This rule would not process the data file the second time. The second rule
+catches this case: If the data file name is what was being skipped, but
+@code{FNR} is 1, then this is the second time the file is being processed,
+and it should not be skipped.
+
+The @code{next file} statement would be useful if you have many data
+files to process, and due to the nature of the data, you expect that you
+would not want to process every record in the file. In order to move on to
+the next data file, you would have to continue scanning the unwanted
+records (as described above). The @code{next file} statement accomplishes
+this much more efficiently.
+
+@ignore
+Would it make sense down the road to nuke `next file' in favor of
+semantics that would make this work?
+
+ function nextfile() { ARGIND++ ; next }
+@end ignore
+
+@node Exit Statement, , Next File Statement, Statements
+@section The @code{exit} Statement
+
+@cindex @code{exit} statement
+The @code{exit} statement causes @code{awk} to immediately stop
+executing the current rule and to stop processing input; any remaining input
+is ignored.@refill
+
+If an @code{exit} statement is executed from a @code{BEGIN} rule the
+program stops processing everything immediately. No input records are
+read. However, if an @code{END} rule is present, it is executed
+(@pxref{BEGIN/END, ,@code{BEGIN} and @code{END} Special Patterns}).
+
+If @code{exit} is used as part of an @code{END} rule, it causes
+the program to stop immediately.
+
+An @code{exit} statement that is part of an ordinary rule (that is, not part
+of a @code{BEGIN} or @code{END} rule) stops the execution of any further
+automatic rules, but the @code{END} rule is executed if there is one.
+If you do not want the @code{END} rule to do its job in this case, you
+can set a variable to nonzero before the @code{exit} statement, and check
+that variable in the @code{END} rule.
+
+If an argument is supplied to @code{exit}, its value is used as the exit
+status code for the @code{awk} process. If no argument is supplied,
+@code{exit} returns status zero (success).@refill
+
+For example, let's say you've discovered an error condition you really
+don't know how to handle. Conventionally, programs report this by
+exiting with a nonzero status. Your @code{awk} program can do this
+using an @code{exit} statement with a nonzero argument. Here's an
+example of this:@refill
+
+@example
+@group
+BEGIN @{
+ if (("date" | getline date_now) < 0) @{
+ print "Can't get system date" > "/dev/stderr"
+ exit 4
+ @}
+@}
+@end group
+@end example
+
+@node Arrays, Built-in, Statements, Top
+@chapter Arrays in @code{awk}
+
+An @dfn{array} is a table of values, called @dfn{elements}. The
+elements of an array are distinguished by their indices. @dfn{Indices}
+may be either numbers or strings. Each array has a name, which looks
+like a variable name, but must not be in use as a variable name in the
+same @code{awk} program.
+
+@menu
+* Array Intro:: Introduction to Arrays
+* Reference to Elements:: How to examine one element of an array.
+* Assigning Elements:: How to change an element of an array.
+* Array Example:: Basic Example of an Array
+* Scanning an Array:: A variation of the @code{for} statement.
+ It loops through the indices of
+ an array's existing elements.
+* Delete:: The @code{delete} statement removes
+ an element from an array.
+* Numeric Array Subscripts:: How to use numbers as subscripts in @code{awk}.
+* Multi-dimensional:: Emulating multi-dimensional arrays in @code{awk}.
+* Multi-scanning:: Scanning multi-dimensional arrays.
+@end menu
+
+@node Array Intro, Reference to Elements, Arrays, Arrays
+@section Introduction to Arrays
+
+@cindex arrays
+The @code{awk} language has one-dimensional @dfn{arrays} for storing groups
+of related strings or numbers.
+
+Every @code{awk} array must have a name. Array names have the same
+syntax as variable names; any valid variable name would also be a valid
+array name. But you cannot use one name in both ways (as an array and
+as a variable) in one @code{awk} program.
+
+Arrays in @code{awk} superficially resemble arrays in other programming
+languages; but there are fundamental differences. In @code{awk}, you
+don't need to specify the size of an array before you start to use it.
+Additionally, any number or string in @code{awk} may be used as an
+array index.
+
+In most other languages, you have to @dfn{declare} an array and specify
+how many elements or components it contains. In such languages, the
+declaration causes a contiguous block of memory to be allocated for that
+many elements. An index in the array must be a positive integer; for
+example, the index 0 specifies the first element in the array, which is
+actually stored at the beginning of the block of memory. Index 1
+specifies the second element, which is stored in memory right after the
+first element, and so on. It is impossible to add more elements to the
+array, because it has room for only as many elements as you declared.
+
+A contiguous array of four elements might look like this,
+conceptually, if the element values are @code{8}, @code{"foo"},
+@code{""} and @code{30}:@refill
+
+@example
++---------+---------+--------+---------+
+| 8 | "foo" | "" | 30 | @r{value}
++---------+---------+--------+---------+
+ 0 1 2 3 @r{index}
+@end example
+
+@noindent
+Only the values are stored; the indices are implicit from the order of
+the values. @code{8} is the value at index 0, because @code{8} appears in the
+position with 0 elements before it.
+
+@cindex arrays, definition of
+@cindex associative arrays
+Arrays in @code{awk} are different: they are @dfn{associative}. This means
+that each array is a collection of pairs: an index, and its corresponding
+array element value:
+
+@example
+@r{Element} 4 @r{Value} 30
+@r{Element} 2 @r{Value} "foo"
+@r{Element} 1 @r{Value} 8
+@r{Element} 3 @r{Value} ""
+@end example
+
+@noindent
+We have shown the pairs in jumbled order because their order is irrelevant.
+
+One advantage of an associative array is that new pairs can be added
+at any time. For example, suppose we add to the above array a tenth element
+whose value is @w{@code{"number ten"}}. The result is this:
+
+@example
+@r{Element} 10 @r{Value} "number ten"
+@r{Element} 4 @r{Value} 30
+@r{Element} 2 @r{Value} "foo"
+@r{Element} 1 @r{Value} 8
+@r{Element} 3 @r{Value} ""
+@end example
+
+@noindent
+Now the array is @dfn{sparse} (i.e., some indices are missing): it has
+elements 1--4 and 10, but doesn't have elements 5, 6, 7, 8, or 9.@refill
+
+Another consequence of associative arrays is that the indices don't
+have to be positive integers. Any number, or even a string, can be
+an index. For example, here is an array which translates words from
+English into French:
+
+@example
+@r{Element} "dog" @r{Value} "chien"
+@r{Element} "cat" @r{Value} "chat"
+@r{Element} "one" @r{Value} "un"
+@r{Element} 1 @r{Value} "un"
+@end example
+
+@noindent
+Here we decided to translate the number 1 in both spelled-out and
+numeric form---thus illustrating that a single array can have both
+numbers and strings as indices.
+
+When @code{awk} creates an array for you, e.g., with the @code{split}
+built-in function,
+that array's indices are consecutive integers starting at 1.
+(@xref{String Functions, ,Built-in Functions for String Manipulation}.)
+
+@node Reference to Elements, Assigning Elements, Array Intro, Arrays
+@section Referring to an Array Element
+@cindex array reference
+@cindex element of array
+@cindex reference to array
+
+The principal way of using an array is to refer to one of its elements.
+An array reference is an expression which looks like this:
+
+@example
+@var{array}[@var{index}]
+@end example
+
+@noindent
+Here, @var{array} is the name of an array. The expression @var{index} is
+the index of the element of the array that you want.
+
+The value of the array reference is the current value of that array
+element. For example, @code{foo[4.3]} is an expression for the element
+of array @code{foo} at index 4.3.
+
+If you refer to an array element that has no recorded value, the value
+of the reference is @code{""}, the null string. This includes elements
+to which you have not assigned any value, and elements that have been
+deleted (@pxref{Delete, ,The @code{delete} Statement}). Such a reference
+automatically creates that array element, with the null string as its value.
+(In some cases, this is unfortunate, because it might waste memory inside
+@code{awk}).
+
+@cindex arrays, presence of elements
+You can find out if an element exists in an array at a certain index with
+the expression:
+
+@example
+@var{index} in @var{array}
+@end example
+
+@noindent
+This expression tests whether or not the particular index exists,
+without the side effect of creating that element if it is not present.
+The expression has the value 1 (true) if @code{@var{array}[@var{index}]}
+exists, and 0 (false) if it does not exist.@refill
+
+For example, to test whether the array @code{frequencies} contains the
+index @code{"2"}, you could write this statement:@refill
+
+@smallexample
+if ("2" in frequencies) print "Subscript \"2\" is present."
+@end smallexample
+
+Note that this is @emph{not} a test of whether or not the array
+@code{frequencies} contains an element whose @emph{value} is @code{"2"}.
+(There is no way to do that except to scan all the elements.) Also, this
+@emph{does not} create @code{frequencies["2"]}, while the following
+(incorrect) alternative would do so:@refill
+
+@smallexample
+if (frequencies["2"] != "") print "Subscript \"2\" is present."
+@end smallexample
+
+@node Assigning Elements, Array Example, Reference to Elements, Arrays
+@section Assigning Array Elements
+@cindex array assignment
+@cindex element assignment
+
+Array elements are lvalues: they can be assigned values just like
+@code{awk} variables:
+
+@example
+@var{array}[@var{subscript}] = @var{value}
+@end example
+
+@noindent
+Here @var{array} is the name of your array. The expression
+@var{subscript} is the index of the element of the array that you want
+to assign a value. The expression @var{value} is the value you are
+assigning to that element of the array.@refill
+
+@node Array Example, Scanning an Array, Assigning Elements, Arrays
+@section Basic Example of an Array
+
+The following program takes a list of lines, each beginning with a line
+number, and prints them out in order of line number. The line numbers are
+not in order, however, when they are first read: they are scrambled. This
+program sorts the lines by making an array using the line numbers as
+subscripts. It then prints out the lines in sorted order of their numbers.
+It is a very simple program, and gets confused if it encounters repeated
+numbers, gaps, or lines that don't begin with a number.@refill
+
+@example
+@{
+ if ($1 > max)
+ max = $1
+ arr[$1] = $0
+@}
+
+END @{
+ for (x = 1; x <= max; x++)
+ print arr[x]
+@}
+@end example
+
+The first rule keeps track of the largest line number seen so far;
+it also stores each line into the array @code{arr}, at an index that
+is the line's number.
+
+The second rule runs after all the input has been read, to print out
+all the lines.
+
+When this program is run with the following input:
+
+@example
+5 I am the Five man
+2 Who are you? The new number two!
+4 . . . And four on the floor
+1 Who is number one?
+3 I three you.
+@end example
+
+@noindent
+its output is this:
+
+@example
+1 Who is number one?
+2 Who are you? The new number two!
+3 I three you.
+4 . . . And four on the floor
+5 I am the Five man
+@end example
+
+If a line number is repeated, the last line with a given number overrides
+the others.
+
+Gaps in the line numbers can be handled with an easy improvement to the
+program's @code{END} rule:
+
+@example
+END @{
+ for (x = 1; x <= max; x++)
+ if (x in arr)
+ print arr[x]
+@}
+@end example
+
+@node Scanning an Array, Delete, Array Example, Arrays
+@section Scanning all Elements of an Array
+@cindex @code{for (x in @dots{})}
+@cindex arrays, special @code{for} statement
+@cindex scanning an array
+
+In programs that use arrays, often you need a loop that executes
+once for each element of an array. In other languages, where arrays are
+contiguous and indices are limited to positive integers, this is
+easy: the largest index is one less than the length of the array, and you can
+find all the valid indices by counting from zero up to that value. This
+technique won't do the job in @code{awk}, since any number or string
+may be an array index. So @code{awk} has a special kind of @code{for}
+statement for scanning an array:
+
+@example
+for (@var{var} in @var{array})
+ @var{body}
+@end example
+
+@noindent
+This loop executes @var{body} once for each different value that your
+program has previously used as an index in @var{array}, with the
+variable @var{var} set to that index.@refill
+
+Here is a program that uses this form of the @code{for} statement. The
+first rule scans the input records and notes which words appear (at
+least once) in the input, by storing a 1 into the array @code{used} with
+the word as index. The second rule scans the elements of @code{used} to
+find all the distinct words that appear in the input. It prints each
+word that is more than 10 characters long, and also prints the number of
+such words. @xref{Built-in, ,Built-in Functions}, for more information
+on the built-in function @code{length}.
+
+@smallexample
+# Record a 1 for each word that is used at least once.
+@{
+ for (i = 1; i <= NF; i++)
+ used[$i] = 1
+@}
+
+# Find number of distinct words more than 10 characters long.
+END @{
+ for (x in used)
+ if (length(x) > 10) @{
+ ++num_long_words
+ print x
+ @}
+ print num_long_words, "words longer than 10 characters"
+@}
+@end smallexample
+
+@noindent
+@xref{Sample Program}, for a more detailed example of this type.
+
+The order in which elements of the array are accessed by this statement
+is determined by the internal arrangement of the array elements within
+@code{awk} and cannot be controlled or changed. This can lead to
+problems if new elements are added to @var{array} by statements in
+@var{body}; you cannot predict whether or not the @code{for} loop will
+reach them. Similarly, changing @var{var} inside the loop can produce
+strange results. It is best to avoid such things.@refill
+
+@node Delete, Numeric Array Subscripts, Scanning an Array, Arrays
+@section The @code{delete} Statement
+@cindex @code{delete} statement
+@cindex deleting elements of arrays
+@cindex removing elements of arrays
+@cindex arrays, deleting an element
+
+You can remove an individual element of an array using the @code{delete}
+statement:
+
+@example
+delete @var{array}[@var{index}]
+@end example
+
+You can not refer to an array element after it has been deleted;
+it is as if you had never referred
+to it and had never given it any value. You can no longer obtain any
+value the element once had.
+
+Here is an example of deleting elements in an array:
+
+@example
+for (i in frequencies)
+ delete frequencies[i]
+@end example
+
+@noindent
+This example removes all the elements from the array @code{frequencies}.
+
+If you delete an element, a subsequent @code{for} statement to scan the array
+will not report that element, and the @code{in} operator to check for
+the presence of that element will return 0:
+
+@example
+delete foo[4]
+if (4 in foo)
+ print "This will never be printed"
+@end example
+
+It is not an error to delete an element which does not exist.
+
+@node Numeric Array Subscripts, Multi-dimensional, Delete, Arrays
+@section Using Numbers to Subscript Arrays
+
+An important aspect of arrays to remember is that array subscripts
+are @emph{always} strings. If you use a numeric value as a subscript,
+it will be converted to a string value before it is used for subscripting
+(@pxref{Conversion, ,Conversion of Strings and Numbers}).
+
+@cindex conversions, during subscripting
+@cindex numbers, used as subscripts
+@vindex CONVFMT
+This means that the value of the @code{CONVFMT} can potentially
+affect how your program accesses elements of an array. For example:
+
+@example
+a = b = 12.153
+data[a] = 1
+CONVFMT = "%2.2f"
+if (b in data)
+ printf "%s is in data", b
+else
+ printf "%s is not in data", b
+@end example
+
+@noindent
+should print @samp{12.15 is not in data}. The first statement gives
+both @code{a} and @code{b} the same numeric value. Assigning to
+@code{data[a]} first gives @code{a} the string value @code{"12.153"}
+(using the default conversion value of @code{CONVFMT}, @code{"%.6g"}),
+and then assigns 1 to @code{data["12.153"]}. The program then changes
+the value of @code{CONVFMT}. The test @samp{(b in data)} forces @code{b}
+to be converted to a string, this time @code{"12.15"}, since the value of
+@code{CONVFMT} only allows two significant digits. This test fails,
+since @code{"12.15"} is a different string from @code{"12.153"}.@refill
+
+According to the rules for conversions
+(@pxref{Conversion, ,Conversion of Strings and Numbers}), integer
+values are always converted to strings as integers, no matter what the
+value of @code{CONVFMT} may happen to be. So the usual case of@refill
+
+@example
+for (i = 1; i <= maxsub; i++)
+ @i{do something with} array[i]
+@end example
+
+@noindent
+will work, no matter what the value of @code{CONVFMT}.
+
+Like many things in @code{awk}, the majority of the time things work
+as you would expect them to work. But it is useful to have a precise
+knowledge of the actual rules, since sometimes they can have a subtle
+effect on your programs.
+
+@node Multi-dimensional, Multi-scanning, Numeric Array Subscripts, Arrays
+@section Multi-dimensional Arrays
+
+@c the following index entry is an overfull hbox. --mew 30jan1992
+@cindex subscripts in arrays
+@cindex arrays, multi-dimensional subscripts
+@cindex multi-dimensional subscripts
+A multi-dimensional array is an array in which an element is identified
+by a sequence of indices, not a single index. For example, a
+two-dimensional array requires two indices. The usual way (in most
+languages, including @code{awk}) to refer to an element of a
+two-dimensional array named @code{grid} is with
+@code{grid[@var{x},@var{y}]}.
+
+@vindex SUBSEP
+Multi-dimensional arrays are supported in @code{awk} through
+concatenation of indices into one string. What happens is that
+@code{awk} converts the indices into strings
+(@pxref{Conversion, ,Conversion of Strings and Numbers}) and
+concatenates them together, with a separator between them. This creates
+a single string that describes the values of the separate indices. The
+combined string is used as a single index into an ordinary,
+one-dimensional array. The separator used is the value of the built-in
+variable @code{SUBSEP}.@refill
+
+For example, suppose we evaluate the expression @code{foo[5,12]="value"}
+when the value of @code{SUBSEP} is @code{"@@"}. The numbers 5 and 12 are
+converted to strings and
+concatenated with an @samp{@@} between them, yielding @code{"5@@12"}; thus,
+the array element @code{foo["5@@12"]} is set to @code{"value"}.@refill
+
+Once the element's value is stored, @code{awk} has no record of whether
+it was stored with a single index or a sequence of indices. The two
+expressions @code{foo[5,12]} and @w{@code{foo[5 SUBSEP 12]}} always have
+the same value.
+
+The default value of @code{SUBSEP} is the string @code{"\034"},
+which contains a nonprinting character that is unlikely to appear in an
+@code{awk} program or in the input data.
+
+The usefulness of choosing an unlikely character comes from the fact
+that index values that contain a string matching @code{SUBSEP} lead to
+combined strings that are ambiguous. Suppose that @code{SUBSEP} were
+@code{"@@"}; then @w{@code{foo["a@@b", "c"]}} and @w{@code{foo["a",
+"b@@c"]}} would be indistinguishable because both would actually be
+stored as @code{foo["a@@b@@c"]}. Because @code{SUBSEP} is
+@code{"\034"}, such confusion can arise only when an index
+contains the character with ASCII code 034, which is a rare
+event.@refill
+
+You can test whether a particular index-sequence exists in a
+``multi-dimensional'' array with the same operator @code{in} used for single
+dimensional arrays. Instead of a single index as the left-hand operand,
+write the whole sequence of indices, separated by commas, in
+parentheses:@refill
+
+@example
+(@var{subscript1}, @var{subscript2}, @dots{}) in @var{array}
+@end example
+
+The following example treats its input as a two-dimensional array of
+fields; it rotates this array 90 degrees clockwise and prints the
+result. It assumes that all lines have the same number of
+elements.
+
+@example
+awk '@{
+ if (max_nf < NF)
+ max_nf = NF
+ max_nr = NR
+ for (x = 1; x <= NF; x++)
+ vector[x, NR] = $x
+@}
+
+END @{
+ for (x = 1; x <= max_nf; x++) @{
+ for (y = max_nr; y >= 1; --y)
+ printf("%s ", vector[x, y])
+ printf("\n")
+ @}
+@}'
+@end example
+
+@noindent
+When given the input:
+
+@example
+@group
+1 2 3 4 5 6
+2 3 4 5 6 1
+3 4 5 6 1 2
+4 5 6 1 2 3
+@end group
+@end example
+
+@noindent
+it produces:
+
+@example
+@group
+4 3 2 1
+5 4 3 2
+6 5 4 3
+1 6 5 4
+2 1 6 5
+3 2 1 6
+@end group
+@end example
+
+@node Multi-scanning, , Multi-dimensional, Arrays
+@section Scanning Multi-dimensional Arrays
+
+There is no special @code{for} statement for scanning a
+``multi-dimensional'' array; there cannot be one, because in truth there
+are no multi-dimensional arrays or elements; there is only a
+multi-dimensional @emph{way of accessing} an array.
+
+However, if your program has an array that is always accessed as
+multi-dimensional, you can get the effect of scanning it by combining
+the scanning @code{for} statement
+(@pxref{Scanning an Array, ,Scanning all Elements of an Array}) with the
+@code{split} built-in function
+(@pxref{String Functions, ,Built-in Functions for String Manipulation}).
+It works like this:@refill
+
+@example
+for (combined in @var{array}) @{
+ split(combined, separate, SUBSEP)
+ @dots{}
+@}
+@end example
+
+@noindent
+This finds each concatenated, combined index in the array, and splits it
+into the individual indices by breaking it apart where the value of
+@code{SUBSEP} appears. The split-out indices become the elements of
+the array @code{separate}.
+
+Thus, suppose you have previously stored in @code{@var{array}[1,
+"foo"]}; then an element with index @code{"1\034foo"} exists in
+@var{array}. (Recall that the default value of @code{SUBSEP} contains
+the character with code 034.) Sooner or later the @code{for} statement
+will find that index and do an iteration with @code{combined} set to
+@code{"1\034foo"}. Then the @code{split} function is called as
+follows:
+
+@example
+split("1\034foo", separate, "\034")
+@end example
+
+@noindent
+The result of this is to set @code{separate[1]} to 1 and @code{separate[2]}
+to @code{"foo"}. Presto, the original sequence of separate indices has
+been recovered.
+
+@node Built-in, User-defined, Arrays, Top
+@chapter Built-in Functions
+
+@cindex built-in functions
+@dfn{Built-in} functions are functions that are always available for
+your @code{awk} program to call. This chapter defines all the built-in
+functions in @code{awk}; some of them are mentioned in other sections,
+but they are summarized here for your convenience. (You can also define
+new functions yourself. @xref{User-defined, ,User-defined Functions}.)
+
+@menu
+* Calling Built-in:: How to call built-in functions.
+* Numeric Functions:: Functions that work with numbers,
+ including @code{int}, @code{sin} and @code{rand}.
+* String Functions:: Functions for string manipulation,
+ such as @code{split}, @code{match}, and @code{sprintf}.
+* I/O Functions:: Functions for files and shell commands.
+* Time Functions:: Functions for dealing with time stamps.
+@end menu
+
+@node Calling Built-in, Numeric Functions, Built-in, Built-in
+@section Calling Built-in Functions
+
+To call a built-in function, write the name of the function followed
+by arguments in parentheses. For example, @code{atan2(y + z, 1)}
+is a call to the function @code{atan2}, with two arguments.
+
+Whitespace is ignored between the built-in function name and the
+open-parenthesis, but we recommend that you avoid using whitespace
+there. User-defined functions do not permit whitespace in this way, and
+you will find it easier to avoid mistakes by following a simple
+convention which always works: no whitespace after a function name.
+
+Each built-in function accepts a certain number of arguments. In most
+cases, any extra arguments given to built-in functions are ignored. The
+defaults for omitted arguments vary from function to function and are
+described under the individual functions.
+
+When a function is called, expressions that create the function's actual
+parameters are evaluated completely before the function call is performed.
+For example, in the code fragment:
+
+@example
+i = 4
+j = sqrt(i++)
+@end example
+
+@noindent
+the variable @code{i} is set to 5 before @code{sqrt} is called
+with a value of 4 for its actual parameter.
+
+@node Numeric Functions, String Functions, Calling Built-in, Built-in
+@section Numeric Built-in Functions
+@c I didn't make all the examples small because a couple of them were
+@c short already. --mew 29jan1992
+
+Here is a full list of built-in functions that work with numbers:
+
+@table @code
+@item int(@var{x})
+This gives you the integer part of @var{x}, truncated toward 0. This
+produces the nearest integer to @var{x}, located between @var{x} and 0.
+
+For example, @code{int(3)} is 3, @code{int(3.9)} is 3, @code{int(-3.9)}
+is @minus{}3, and @code{int(-3)} is @minus{}3 as well.@refill
+
+@item sqrt(@var{x})
+This gives you the positive square root of @var{x}. It reports an error
+if @var{x} is negative. Thus, @code{sqrt(4)} is 2.@refill
+
+@item exp(@var{x})
+This gives you the exponential of @var{x}, or reports an error if
+@var{x} is out of range. The range of values @var{x} can have depends
+on your machine's floating point representation.@refill
+
+@item log(@var{x})
+This gives you the natural logarithm of @var{x}, if @var{x} is positive;
+otherwise, it reports an error.@refill
+
+@item sin(@var{x})
+This gives you the sine of @var{x}, with @var{x} in radians.
+
+@item cos(@var{x})
+This gives you the cosine of @var{x}, with @var{x} in radians.
+
+@item atan2(@var{y}, @var{x})
+This gives you the arctangent of @code{@var{y} / @var{x}} in radians.
+
+@item rand()
+This gives you a random number. The values of @code{rand} are
+uniformly-distributed between 0 and 1. The value is never 0 and never
+1.
+
+Often you want random integers instead. Here is a user-defined function
+you can use to obtain a random nonnegative integer less than @var{n}:
+
+@example
+function randint(n) @{
+ return int(n * rand())
+@}
+@end example
+
+@noindent
+The multiplication produces a random real number greater than 0 and less
+than @var{n}. We then make it an integer (using @code{int}) between 0
+and @code{@var{n} @minus{} 1}.
+
+Here is an example where a similar function is used to produce
+random integers between 1 and @var{n}. Note that this program will
+print a new random number for each input record.
+
+@smallexample
+awk '
+# Function to roll a simulated die.
+function roll(n) @{ return 1 + int(rand() * n) @}
+
+# Roll 3 six-sided dice and print total number of points.
+@{
+ printf("%d points\n", roll(6)+roll(6)+roll(6))
+@}'
+@end smallexample
+
+@strong{Note:} @code{rand} starts generating numbers from the same
+point, or @dfn{seed}, each time you run @code{awk}. This means that
+a program will produce the same results each time you run it.
+The numbers are random within one @code{awk} run, but predictable
+from run to run. This is convenient for debugging, but if you want
+a program to do different things each time it is used, you must change
+the seed to a value that will be different in each run. To do this,
+use @code{srand}.
+
+@item srand(@var{x})
+The function @code{srand} sets the starting point, or @dfn{seed},
+for generating random numbers to the value @var{x}.
+
+Each seed value leads to a particular sequence of ``random'' numbers.
+Thus, if you set the seed to the same value a second time, you will get
+the same sequence of ``random'' numbers again.
+
+If you omit the argument @var{x}, as in @code{srand()}, then the current
+date and time of day are used for a seed. This is the way to get random
+numbers that are truly unpredictable.
+
+The return value of @code{srand} is the previous seed. This makes it
+easy to keep track of the seeds for use in consistently reproducing
+sequences of random numbers.
+@end table
+
+@node String Functions, I/O Functions, Numeric Functions, Built-in
+@section Built-in Functions for String Manipulation
+
+The functions in this section look at or change the text of one or more
+strings.
+
+@table @code
+@item index(@var{in}, @var{find})
+@findex match
+This searches the string @var{in} for the first occurrence of the string
+@var{find}, and returns the position in characters where that occurrence
+begins in the string @var{in}. For example:@refill
+
+@smallexample
+awk 'BEGIN @{ print index("peanut", "an") @}'
+@end smallexample
+
+@noindent
+prints @samp{3}. If @var{find} is not found, @code{index} returns 0.
+(Remember that string indices in @code{awk} start at 1.)
+
+@item length(@var{string})
+@findex length
+This gives you the number of characters in @var{string}. If
+@var{string} is a number, the length of the digit string representing
+that number is returned. For example, @code{length("abcde")} is 5. By
+contrast, @code{length(15 * 35)} works out to 3. How? Well, 15 * 35 =
+525, and 525 is then converted to the string @samp{"525"}, which has
+three characters.
+
+If no argument is supplied, @code{length} returns the length of @code{$0}.
+
+In older versions of @code{awk}, you could call the @code{length} function
+without any parentheses. Doing so is marked as ``deprecated'' in the
+@sc{posix} standard. This means that while you can do this in your
+programs, it is a feature that can eventually be removed from a future
+version of the standard. Therefore, for maximal portability of your
+@code{awk} programs you should always supply the parentheses.
+
+@item match(@var{string}, @var{regexp})
+@findex match
+The @code{match} function searches the string, @var{string}, for the
+longest, leftmost substring matched by the regular expression,
+@var{regexp}. It returns the character position, or @dfn{index}, of
+where that substring begins (1, if it starts at the beginning of
+@var{string}). If no match if found, it returns 0.
+
+@vindex RSTART
+@vindex RLENGTH
+The @code{match} function sets the built-in variable @code{RSTART} to
+the index. It also sets the built-in variable @code{RLENGTH} to the
+length in characters of the matched substring. If no match is found,
+@code{RSTART} is set to 0, and @code{RLENGTH} to @minus{}1.
+
+For example:
+
+@smallexample
+awk '@{
+ if ($1 == "FIND")
+ regex = $2
+ else @{
+ where = match($0, regex)
+ if (where)
+ print "Match of", regex, "found at", where, "in", $0
+ @}
+@}'
+@end smallexample
+
+@noindent
+This program looks for lines that match the regular expression stored in
+the variable @code{regex}. This regular expression can be changed. If the
+first word on a line is @samp{FIND}, @code{regex} is changed to be the
+second word on that line. Therefore, given:
+
+@smallexample
+FIND fo*bar
+My program was a foobar
+But none of it would doobar
+FIND Melvin
+JF+KM
+This line is property of The Reality Engineering Co.
+This file created by Melvin.
+@end smallexample
+
+@noindent
+@code{awk} prints:
+
+@smallexample
+Match of fo*bar found at 18 in My program was a foobar
+Match of Melvin found at 26 in This file created by Melvin.
+@end smallexample
+
+@item split(@var{string}, @var{array}, @var{fieldsep})
+@findex split
+This divides @var{string} into pieces separated by @var{fieldsep},
+and stores the pieces in @var{array}. The first piece is stored in
+@code{@var{array}[1]}, the second piece in @code{@var{array}[2]}, and so
+forth. The string value of the third argument, @var{fieldsep}, is
+a regexp describing where to split @var{string} (much as @code{FS} can
+be a regexp describing where to split input records). If
+the @var{fieldsep} is omitted, the value of @code{FS} is used.
+@code{split} returns the number of elements created.@refill
+
+The @code{split} function, then, splits strings into pieces in a
+manner similar to the way input lines are split into fields. For example:
+
+@smallexample
+split("auto-da-fe", a, "-")
+@end smallexample
+
+@noindent
+splits the string @samp{auto-da-fe} into three fields using @samp{-} as the
+separator. It sets the contents of the array @code{a} as follows:
+
+@smallexample
+a[1] = "auto"
+a[2] = "da"
+a[3] = "fe"
+@end smallexample
+
+@noindent
+The value returned by this call to @code{split} is 3.
+
+As with input field-splitting, when the value of @var{fieldsep} is
+@code{" "}, leading and trailing whitespace is ignored, and the elements
+are separated by runs of whitespace.
+
+@item sprintf(@var{format}, @var{expression1},@dots{})
+@findex sprintf
+This returns (without printing) the string that @code{printf} would
+have printed out with the same arguments
+(@pxref{Printf, ,Using @code{printf} Statements for Fancier Printing}).
+For example:@refill
+
+@smallexample
+sprintf("pi = %.2f (approx.)", 22/7)
+@end smallexample
+
+@noindent
+returns the string @w{@code{"pi = 3.14 (approx.)"}}.
+
+@item sub(@var{regexp}, @var{replacement}, @var{target})
+@findex sub
+The @code{sub} function alters the value of @var{target}.
+It searches this value, which should be a string, for the
+leftmost substring matched by the regular expression, @var{regexp},
+extending this match as far as possible. Then the entire string is
+changed by replacing the matched text with @var{replacement}.
+The modified string becomes the new value of @var{target}.
+
+This function is peculiar because @var{target} is not simply
+used to compute a value, and not just any expression will do: it
+must be a variable, field or array reference, so that @code{sub} can
+store a modified value there. If this argument is omitted, then the
+default is to use and alter @code{$0}.
+
+For example:@refill
+
+@smallexample
+str = "water, water, everywhere"
+sub(/at/, "ith", str)
+@end smallexample
+
+@noindent
+sets @code{str} to @w{@code{"wither, water, everywhere"}}, by replacing the
+leftmost, longest occurrence of @samp{at} with @samp{ith}.
+
+The @code{sub} function returns the number of substitutions made (either
+one or zero).
+
+If the special character @samp{&} appears in @var{replacement}, it
+stands for the precise substring that was matched by @var{regexp}. (If
+the regexp can match more than one string, then this precise substring
+may vary.) For example:@refill
+
+@smallexample
+awk '@{ sub(/candidate/, "& and his wife"); print @}'
+@end smallexample
+
+@noindent
+changes the first occurrence of @samp{candidate} to @samp{candidate
+and his wife} on each input line.
+
+Here is another example:
+
+@smallexample
+awk 'BEGIN @{
+ str = "daabaaa"
+ sub(/a*/, "c&c", str)
+ print str
+@}'
+@end smallexample
+
+@noindent
+prints @samp{dcaacbaaa}. This show how @samp{&} can represent a non-constant
+string, and also illustrates the ``leftmost, longest'' rule.
+
+The effect of this special character (@samp{&}) can be turned off by putting a
+backslash before it in the string. As usual, to insert one backslash in
+the string, you must write two backslashes. Therefore, write @samp{\\&}
+in a string constant to include a literal @samp{&} in the replacement.
+For example, here is how to replace the first @samp{|} on each line with
+an @samp{&}:@refill
+
+@smallexample
+awk '@{ sub(/\|/, "\\&"); print @}'
+@end smallexample
+
+@strong{Note:} as mentioned above, the third argument to @code{sub} must
+be an lvalue. Some versions of @code{awk} allow the third argument to
+be an expression which is not an lvalue. In such a case, @code{sub}
+would still search for the pattern and return 0 or 1, but the result of
+the substitution (if any) would be thrown away because there is no place
+to put it. Such versions of @code{awk} accept expressions like
+this:@refill
+
+@smallexample
+sub(/USA/, "United States", "the USA and Canada")
+@end smallexample
+
+@noindent
+But that is considered erroneous in @code{gawk}.
+
+@item gsub(@var{regexp}, @var{replacement}, @var{target})
+@findex gsub
+This is similar to the @code{sub} function, except @code{gsub} replaces
+@emph{all} of the longest, leftmost, @emph{nonoverlapping} matching
+substrings it can find. The @samp{g} in @code{gsub} stands for
+``global,'' which means replace everywhere. For example:@refill
+
+@smallexample
+awk '@{ gsub(/Britain/, "United Kingdom"); print @}'
+@end smallexample
+
+@noindent
+replaces all occurrences of the string @samp{Britain} with @samp{United
+Kingdom} for all input records.@refill
+
+The @code{gsub} function returns the number of substitutions made. If
+the variable to be searched and altered, @var{target}, is
+omitted, then the entire input record, @code{$0}, is used.@refill
+
+As in @code{sub}, the characters @samp{&} and @samp{\} are special, and
+the third argument must be an lvalue.
+
+@item substr(@var{string}, @var{start}, @var{length})
+@findex substr
+This returns a @var{length}-character-long substring of @var{string},
+starting at character number @var{start}. The first character of a
+string is character number one. For example,
+@code{substr("washington", 5, 3)} returns @code{"ing"}.@refill
+
+If @var{length} is not present, this function returns the whole suffix of
+@var{string} that begins at character number @var{start}. For example,
+@code{substr("washington", 5)} returns @code{"ington"}. This is also
+the case if @var{length} is greater than the number of characters remaining
+in the string, counting from character number @var{start}.
+
+@item tolower(@var{string})
+@findex tolower
+This returns a copy of @var{string}, with each upper-case character
+in the string replaced with its corresponding lower-case character.
+Nonalphabetic characters are left unchanged. For example,
+@code{tolower("MiXeD cAsE 123")} returns @code{"mixed case 123"}.
+
+@item toupper(@var{string})
+@findex toupper
+This returns a copy of @var{string}, with each lower-case character
+in the string replaced with its corresponding upper-case character.
+Nonalphabetic characters are left unchanged. For example,
+@code{toupper("MiXeD cAsE 123")} returns @code{"MIXED CASE 123"}.
+@end table
+
+@node I/O Functions, Time Functions, String Functions, Built-in
+@section Built-in Functions for Input/Output
+
+@table @code
+@item close(@var{filename})
+Close the file @var{filename}, for input or output. The argument may
+alternatively be a shell command that was used for redirecting to or
+from a pipe; then the pipe is closed.
+
+@xref{Close Input, ,Closing Input Files and Pipes}, regarding closing
+input files and pipes. @xref{Close Output, ,Closing Output Files and Pipes},
+regarding closing output files and pipes.@refill
+
+@item system(@var{command})
+@findex system
+@c the following index entry is an overfull hbox. --mew 30jan1992
+@cindex interaction, @code{awk} and other programs
+The system function allows the user to execute operating system commands
+and then return to the @code{awk} program. The @code{system} function
+executes the command given by the string @var{command}. It returns, as
+its value, the status returned by the command that was executed.
+
+For example, if the following fragment of code is put in your @code{awk}
+program:
+
+@smallexample
+END @{
+ system("mail -s 'awk run done' operator < /dev/null")
+@}
+@end smallexample
+
+@noindent
+the system operator will be sent mail when the @code{awk} program
+finishes processing input and begins its end-of-input processing.
+
+Note that much the same result can be obtained by redirecting
+@code{print} or @code{printf} into a pipe. However, if your @code{awk}
+program is interactive, @code{system} is useful for cranking up large
+self-contained programs, such as a shell or an editor.@refill
+
+Some operating systems cannot implement the @code{system} function.
+@code{system} causes a fatal error if it is not supported.
+@end table
+
+@c fakenode --- for prepinfo
+@subheading Controlling Output Buffering with @code{system}
+@cindex flushing buffers
+@cindex buffers, flushing
+@cindex buffering output
+@cindex output, buffering
+
+Many utility programs will @dfn{buffer} their output; they save information
+to be written to a disk file or terminal in memory, until there is enough
+to be written in one operation. This is often more efficient than writing
+every little bit of information as soon as it is ready. However, sometimes
+it is necessary to force a program to @dfn{flush} its buffers; that is,
+write the information to its destination, even if a buffer is not full.
+You can do this from your @code{awk} program by calling @code{system}
+with a null string as its argument:
+
+@example
+system("") # flush output
+@end example
+
+@noindent
+@code{gawk} treats this use of the @code{system} function as a special
+case, and is smart enough not to run a shell (or other command
+interpreter) with the empty command. Therefore, with @code{gawk}, this
+idiom is not only useful, it is efficient. While this idiom should work
+with other @code{awk} implementations, it will not necessarily avoid
+starting an unnecessary shell.
+@ignore
+Need a better explanation, perhaps in a separate paragraph. Explain that
+for
+
+awk 'BEGIN { print "hi"
+ system("echo hello")
+ print "howdy" }'
+
+that the output had better be
+
+ hi
+ hello
+ howdy
+
+and not
+
+ hello
+ hi
+ howdy
+
+which it would be if awk did not flush its buffers before calling system.
+@end ignore
+
+@node Time Functions, , I/O Functions, Built-in
+@section Functions for Dealing with Time Stamps
+
+@cindex time stamps
+@cindex time of day
+A common use for @code{awk} programs is the processing of log files.
+Log files often contain time stamp information, indicating when a
+particular log record was written. Many programs log their time stamp
+in the form returned by the @code{time} system call, which is the
+number of seconds since a particular epoch. On @sc{posix} systems,
+it is the number of seconds since Midnight, January 1, 1970, @sc{utc}.
+
+In order to make it easier to process such log files, and to easily produce
+useful reports, @code{gawk} provides two functions for working with time
+stamps. Both of these are @code{gawk} extensions; they are not specified
+in the @sc{posix} standard, nor are they in any other known version
+of @code{awk}.
+
+@table @code
+@item systime()
+@findex systime
+This function returns the current time as the number of seconds since
+the system epoch. On @sc{posix} systems, this is the number of seconds
+since Midnight, January 1, 1970, @sc{utc}. It may be a different number on
+other systems.
+
+@item strftime(@var{format}, @var{timestamp})
+@findex strftime
+This function returns a string. It is similar to the function of the
+same name in the @sc{ansi} C standard library. The time specified by
+@var{timestamp} is used to produce a string, based on the contents
+of the @var{format} string.
+@end table
+
+The @code{systime} function allows you to compare a time stamp from a
+log file with the current time of day. In particular, it is easy to
+determine how long ago a particular record was logged. It also allows
+you to produce log records using the ``seconds since the epoch'' format.
+
+The @code{strftime} function allows you to easily turn a time stamp
+into human-readable information. It is similar in nature to the @code{sprintf}
+function, copying non-format specification characters verbatim to the
+returned string, and substituting date and time values for format
+specifications in the @var{format} string. If no @var{timestamp} argument
+is supplied, @code{gawk} will use the current time of day as the
+time stamp.@refill
+
+@code{strftime} is guaranteed by the @sc{ansi} C standard to support
+the following date format specifications:
+
+@table @code
+@item %a
+The locale's abbreviated weekday name.
+
+@item %A
+The locale's full weekday name.
+
+@item %b
+The locale's abbreviated month name.
+
+@item %B
+The locale's full month name.
+
+@item %c
+The locale's ``appropriate'' date and time representation.
+
+@item %d
+The day of the month as a decimal number (01--31).
+
+@item %H
+The hour (24-hour clock) as a decimal number (00--23).
+
+@item %I
+The hour (12-hour clock) as a decimal number (01--12).
+
+@item %j
+The day of the year as a decimal number (001--366).
+
+@item %m
+The month as a decimal number (01--12).
+
+@item %M
+The minute as a decimal number (00--59).
+
+@item %p
+The locale's equivalent of the AM/PM designations associated
+with a 12-hour clock.
+
+@item %S
+The second as a decimal number (00--61). (Occasionally there are
+minutes in a year with one or two leap seconds, which is why the
+seconds can go from 0 all the way to 61.)
+
+@item %U
+The week number of the year (the first Sunday as the first day of week 1)
+as a decimal number (00--53).
+
+@item %w
+The weekday as a decimal number (0--6). Sunday is day 0.
+
+@item %W
+The week number of the year (the first Monday as the first day of week 1)
+as a decimal number (00--53).
+
+@item %x
+The locale's ``appropriate'' date representation.
+
+@item %X
+The locale's ``appropriate'' time representation.
+
+@item %y
+The year without century as a decimal number (00--99).
+
+@item %Y
+The year with century as a decimal number.
+
+@item %Z
+The time zone name or abbreviation, or no characters if
+no time zone is determinable.
+
+@item %%
+A literal @samp{%}.
+@end table
+
+@c The parenthetical remark here should really be a footnote, but
+@c it gave formatting problems at the FSF. So for now put it in
+@c parentheses.
+If a conversion specifier is not one of the above, the behavior is
+undefined. (This is because the @sc{ansi} standard for C leaves the
+behavior of the C version of @code{strftime} undefined, and @code{gawk}
+will use the system's version of @code{strftime} if it's there.
+Typically, the conversion specifier will either not appear in the
+returned string, or it will appear literally.)
+
+Informally, a @dfn{locale} is the geographic place in which a program
+is meant to run. For example, a common way to abbreviate the date
+September 4, 1991 in the United States would be ``9/4/91''.
+In many countries in Europe, however, it would be abbreviated ``4.9.91''.
+Thus, the @samp{%x} specification in a @code{"US"} locale might produce
+@samp{9/4/91}, while in a @code{"EUROPE"} locale, it might produce
+@samp{4.9.91}. The @sc{ansi} C standard defines a default @code{"C"}
+locale, which is an environment that is typical of what most C programmers
+are used to.
+
+A public-domain C version of @code{strftime} is shipped with @code{gawk}
+for systems that are not yet fully @sc{ansi}-compliant. If that version is
+used to compile @code{gawk} (@pxref{Installation, ,Installing @code{gawk}}),
+then the following additional format specifications are available:@refill
+
+@table @code
+@item %D
+Equivalent to specifying @samp{%m/%d/%y}.
+
+@item %e
+The day of the month, padded with a blank if it is only one digit.
+
+@item %h
+Equivalent to @samp{%b}, above.
+
+@item %n
+A newline character (ASCII LF).
+
+@item %r
+Equivalent to specifying @samp{%I:%M:%S %p}.
+
+@item %R
+Equivalent to specifying @samp{%H:%M}.
+
+@item %T
+Equivalent to specifying @samp{%H:%M:%S}.
+
+@item %t
+A TAB character.
+
+@item %k
+is replaced by the hour (24-hour clock) as a decimal number (0-23).
+Single digit numbers are padded with a blank.
+
+@item %l
+is replaced by the hour (12-hour clock) as a decimal number (1-12).
+Single digit numbers are padded with a blank.
+
+@item %C
+The century, as a number between 00 and 99.
+
+@item %u
+is replaced by the weekday as a decimal number
+[1 (Monday)--7].
+
+@item %V
+is replaced by the week number of the year (the first Monday as the first
+day of week 1) as a decimal number (01--53).
+The method for determining the week number is as specified by ISO 8601
+(to wit: if the week containing January 1 has four or more days in the
+new year, then it is week 1, otherwise it is week 53 of the previous year
+and the next week is week 1).@refill
+
+@item %Ec %EC %Ex %Ey %EY %Od %Oe %OH %OI
+@itemx %Om %OM %OS %Ou %OU %OV %Ow %OW %Oy
+These are ``alternate representations'' for the specifications
+that use only the second letter (@samp{%c}, @samp{%C}, and so on).
+They are recognized, but their normal representations are used.
+(These facilitate compliance with the @sc{posix} @code{date}
+utility.)@refill
+
+@item %v
+The date in VMS format (e.g. 20-JUN-1991).
+@end table
+
+Here are two examples that use @code{strftime}. The first is an
+@code{awk} version of the C @code{ctime} function. (This is a
+user defined function, which we have not discussed yet.
+@xref{User-defined, ,User-defined Functions}, for more information.)
+
+@smallexample
+# ctime.awk
+#
+# awk version of C ctime(3) function
+
+function ctime(ts, format)
+@{
+ format = "%a %b %e %H:%M:%S %Z %Y"
+ if (ts == 0)
+ ts = systime() # use current time as default
+ return strftime(format, ts)
+@}
+@end smallexample
+
+This next example is an @code{awk} implementation of the @sc{posix}
+@code{date} utility. Normally, the @code{date} utility prints the
+current date and time of day in a well known format. However, if you
+provide an argument to it that begins with a @samp{+}, @code{date}
+will copy non-format specifier characters to the standard output, and
+will interpret the current time according to the format specifiers in
+the string. For example:
+
+@smallexample
+date '+Today is %A, %B %d, %Y.'
+@end smallexample
+
+@noindent
+might print
+
+@smallexample
+Today is Thursday, July 11, 1991.
+@end smallexample
+
+Here is the @code{awk} version of the @code{date} utility.
+
+@smallexample
+#! /usr/bin/gawk -f
+#
+# date --- implement the P1003.2 Draft 11 'date' command
+#
+# Bug: does not recognize the -u argument.
+
+BEGIN \
+@{
+ format = "%a %b %e %H:%M:%S %Z %Y"
+ exitval = 0
+
+ if (ARGC > 2)
+ exitval = 1
+ else if (ARGC == 2) @{
+ format = ARGV[1]
+ if (format ~ /^\+/)
+ format = substr(format, 2) # remove leading +
+ @}
+ print strftime(format)
+ exit exitval
+@}
+@end smallexample
+
+@node User-defined, Built-in Variables, Built-in, Top
+@chapter User-defined Functions
+
+@cindex user-defined functions
+@cindex functions, user-defined
+Complicated @code{awk} programs can often be simplified by defining
+your own functions. User-defined functions can be called just like
+built-in ones (@pxref{Function Calls}), but it is up to you to define
+them---to tell @code{awk} what they should do.
+
+@menu
+* Definition Syntax:: How to write definitions and what they mean.
+* Function Example:: An example function definition and
+ what it does.
+* Function Caveats:: Things to watch out for.
+* Return Statement:: Specifying the value a function returns.
+@end menu
+
+@node Definition Syntax, Function Example, User-defined, User-defined
+@section Syntax of Function Definitions
+@cindex defining functions
+@cindex function definition
+
+Definitions of functions can appear anywhere between the rules of the
+@code{awk} program. Thus, the general form of an @code{awk} program is
+extended to include sequences of rules @emph{and} user-defined function
+definitions.
+
+The definition of a function named @var{name} looks like this:
+
+@example
+function @var{name} (@var{parameter-list}) @{
+ @var{body-of-function}
+@}
+@end example
+
+@noindent
+@var{name} is the name of the function to be defined. A valid function
+name is like a valid variable name: a sequence of letters, digits and
+underscores, not starting with a digit. Functions share the same pool
+of names as variables and arrays.
+
+@var{parameter-list} is a list of the function's arguments and local
+variable names, separated by commas. When the function is called,
+the argument names are used to hold the argument values given in
+the call. The local variables are initialized to the null string.
+
+The @var{body-of-function} consists of @code{awk} statements. It is the
+most important part of the definition, because it says what the function
+should actually @emph{do}. The argument names exist to give the body a
+way to talk about the arguments; local variables, to give the body
+places to keep temporary values.
+
+Argument names are not distinguished syntactically from local variable
+names; instead, the number of arguments supplied when the function is
+called determines how many argument variables there are. Thus, if three
+argument values are given, the first three names in @var{parameter-list}
+are arguments, and the rest are local variables.
+
+It follows that if the number of arguments is not the same in all calls
+to the function, some of the names in @var{parameter-list} may be
+arguments on some occasions and local variables on others. Another
+way to think of this is that omitted arguments default to the
+null string.
+
+Usually when you write a function you know how many names you intend to
+use for arguments and how many you intend to use as locals. By
+convention, you should write an extra space between the arguments and
+the locals, so other people can follow how your function is
+supposed to be used.
+
+During execution of the function body, the arguments and local variable
+values hide or @dfn{shadow} any variables of the same names used in the
+rest of the program. The shadowed variables are not accessible in the
+function definition, because there is no way to name them while their
+names have been taken away for the local variables. All other variables
+used in the @code{awk} program can be referenced or set normally in the
+function definition.
+
+The arguments and local variables last only as long as the function body
+is executing. Once the body finishes, the shadowed variables come back.
+
+The function body can contain expressions which call functions. They
+can even call this function, either directly or by way of another
+function. When this happens, we say the function is @dfn{recursive}.
+
+There is no need in @code{awk} to put the definition of a function
+before all uses of the function. This is because @code{awk} reads the
+entire program before starting to execute any of it.
+
+In many @code{awk} implementations, the keyword @code{function} may be
+abbreviated @code{func}. However, @sc{posix} only specifies the use of
+the keyword @code{function}. This actually has some practical implications.
+If @code{gawk} is in @sc{posix}-compatibility mode
+(@pxref{Command Line, ,Invoking @code{awk}}), then the following
+statement will @emph{not} define a function:@refill
+
+@example
+func foo() @{ a = sqrt($1) ; print a @}
+@end example
+
+@noindent
+Instead it defines a rule that, for each record, concatenates the value
+of the variable @samp{func} with the return value of the function @samp{foo},
+and based on the truth value of the result, executes the corresponding action.
+This is probably not what was desired. (@code{awk} accepts this input as
+syntactically valid, since functions may be used before they are defined
+in @code{awk} programs.)
+
+@node Function Example, Function Caveats, Definition Syntax, User-defined
+@section Function Definition Example
+
+Here is an example of a user-defined function, called @code{myprint}, that
+takes a number and prints it in a specific format.
+
+@example
+function myprint(num)
+@{
+ printf "%6.3g\n", num
+@}
+@end example
+
+@noindent
+To illustrate, here is an @code{awk} rule which uses our @code{myprint}
+function:
+
+@example
+$3 > 0 @{ myprint($3) @}
+@end example
+
+@noindent
+This program prints, in our special format, all the third fields that
+contain a positive number in our input. Therefore, when given:
+
+@example
+ 1.2 3.4 5.6 7.8
+ 9.10 11.12 -13.14 15.16
+17.18 19.20 21.22 23.24
+@end example
+
+@noindent
+this program, using our function to format the results, prints:
+
+@example
+ 5.6
+ 21.2
+@end example
+
+Here is a rather contrived example of a recursive function. It prints a
+string backwards:
+
+@example
+function rev (str, len) @{
+ if (len == 0) @{
+ printf "\n"
+ return
+ @}
+ printf "%c", substr(str, len, 1)
+ rev(str, len - 1)
+@}
+@end example
+
+@node Function Caveats, Return Statement, Function Example, User-defined
+@section Calling User-defined Functions
+
+@dfn{Calling a function} means causing the function to run and do its job.
+A function call is an expression, and its value is the value returned by
+the function.
+
+A function call consists of the function name followed by the arguments
+in parentheses. What you write in the call for the arguments are
+@code{awk} expressions; each time the call is executed, these
+expressions are evaluated, and the values are the actual arguments. For
+example, here is a call to @code{foo} with three arguments (the first
+being a string concatenation):
+
+@example
+foo(x y, "lose", 4 * z)
+@end example
+
+@quotation
+@strong{Caution:} whitespace characters (spaces and tabs) are not allowed
+between the function name and the open-parenthesis of the argument list.
+If you write whitespace by mistake, @code{awk} might think that you mean
+to concatenate a variable with an expression in parentheses. However, it
+notices that you used a function name and not a variable name, and reports
+an error.
+@end quotation
+
+@cindex call by value
+When a function is called, it is given a @emph{copy} of the values of
+its arguments. This is called @dfn{call by value}. The caller may use
+a variable as the expression for the argument, but the called function
+does not know this: it only knows what value the argument had. For
+example, if you write this code:
+
+@example
+foo = "bar"
+z = myfunc(foo)
+@end example
+
+@noindent
+then you should not think of the argument to @code{myfunc} as being
+``the variable @code{foo}.'' Instead, think of the argument as the
+string value, @code{"bar"}.
+
+If the function @code{myfunc} alters the values of its local variables,
+this has no effect on any other variables. In particular, if @code{myfunc}
+does this:
+
+@example
+function myfunc (win) @{
+ print win
+ win = "zzz"
+ print win
+@}
+@end example
+
+@noindent
+to change its first argument variable @code{win}, this @emph{does not}
+change the value of @code{foo} in the caller. The role of @code{foo} in
+calling @code{myfunc} ended when its value, @code{"bar"}, was computed.
+If @code{win} also exists outside of @code{myfunc}, the function body
+cannot alter this outer value, because it is shadowed during the
+execution of @code{myfunc} and cannot be seen or changed from there.
+
+@cindex call by reference
+However, when arrays are the parameters to functions, they are @emph{not}
+copied. Instead, the array itself is made available for direct manipulation
+by the function. This is usually called @dfn{call by reference}.
+Changes made to an array parameter inside the body of a function @emph{are}
+visible outside that function.
+@ifinfo
+This can be @strong{very} dangerous if you do not watch what you are
+doing. For example:@refill
+@end ifinfo
+@iftex
+@emph{This can be very dangerous if you do not watch what you are
+doing.} For example:@refill
+@end iftex
+
+@example
+function changeit (array, ind, nvalue) @{
+ array[ind] = nvalue
+@}
+
+BEGIN @{
+ a[1] = 1 ; a[2] = 2 ; a[3] = 3
+ changeit(a, 2, "two")
+ printf "a[1] = %s, a[2] = %s, a[3] = %s\n", a[1], a[2], a[3]
+ @}
+@end example
+
+@noindent
+prints @samp{a[1] = 1, a[2] = two, a[3] = 3}, because calling
+@code{changeit} stores @code{"two"} in the second element of @code{a}.
+
+@node Return Statement, , Function Caveats, User-defined
+@section The @code{return} Statement
+@cindex @code{return} statement
+
+The body of a user-defined function can contain a @code{return} statement.
+This statement returns control to the rest of the @code{awk} program. It
+can also be used to return a value for use in the rest of the @code{awk}
+program. It looks like this:@refill
+
+@example
+return @var{expression}
+@end example
+
+The @var{expression} part is optional. If it is omitted, then the returned
+value is undefined and, therefore, unpredictable.
+
+A @code{return} statement with no value expression is assumed at the end of
+every function definition. So if control reaches the end of the function
+body, then the function returns an unpredictable value. @code{awk}
+will not warn you if you use the return value of such a function; you will
+simply get unpredictable or unexpected results.
+
+Here is an example of a user-defined function that returns a value
+for the largest number among the elements of an array:@refill
+
+@example
+@group
+function maxelt (vec, i, ret) @{
+ for (i in vec) @{
+ if (ret == "" || vec[i] > ret)
+ ret = vec[i]
+ @}
+ return ret
+@}
+@end group
+@end example
+
+@noindent
+You call @code{maxelt} with one argument, which is an array name. The local
+variables @code{i} and @code{ret} are not intended to be arguments;
+while there is nothing to stop you from passing two or three arguments
+to @code{maxelt}, the results would be strange. The extra space before
+@code{i} in the function parameter list is to indicate that @code{i} and
+@code{ret} are not supposed to be arguments. This is a convention which
+you should follow when you define functions.
+
+Here is a program that uses our @code{maxelt} function. It loads an
+array, calls @code{maxelt}, and then reports the maximum number in that
+array:@refill
+
+@example
+@group
+awk '
+function maxelt (vec, i, ret) @{
+ for (i in vec) @{
+ if (ret == "" || vec[i] > ret)
+ ret = vec[i]
+ @}
+ return ret
+@}
+@end group
+
+@group
+# Load all fields of each record into nums.
+@{
+ for(i = 1; i <= NF; i++)
+ nums[NR, i] = $i
+@}
+
+END @{
+ print maxelt(nums)
+@}'
+@end group
+@end example
+
+Given the following input:
+
+@example
+@group
+ 1 5 23 8 16
+44 3 5 2 8 26
+256 291 1396 2962 100
+-6 467 998 1101
+99385 11 0 225
+@end group
+@end example
+
+@noindent
+our program tells us (predictably) that:
+
+@example
+99385
+@end example
+
+@noindent
+is the largest number in our array.
+
+@node Built-in Variables, Command Line, User-defined, Top
+@chapter Built-in Variables
+@cindex built-in variables
+
+Most @code{awk} variables are available for you to use for your own
+purposes; they never change except when your program assigns values to
+them, and never affect anything except when your program examines them.
+
+A few variables have special built-in meanings. Some of them @code{awk}
+examines automatically, so that they enable you to tell @code{awk} how
+to do certain things. Others are set automatically by @code{awk}, so
+that they carry information from the internal workings of @code{awk} to
+your program.
+
+This chapter documents all the built-in variables of @code{gawk}. Most
+of them are also documented in the chapters where their areas of
+activity are described.
+
+@menu
+* User-modified:: Built-in variables that you change
+ to control @code{awk}.
+* Auto-set:: Built-in variables where @code{awk}
+ gives you information.
+@end menu
+
+@node User-modified, Auto-set, Built-in Variables, Built-in Variables
+@section Built-in Variables that Control @code{awk}
+@cindex built-in variables, user modifiable
+
+This is a list of the variables which you can change to control how
+@code{awk} does certain things.
+
+@table @code
+@iftex
+@vindex CONVFMT
+@end iftex
+@item CONVFMT
+This string is used by @code{awk} to control conversion of numbers to
+strings (@pxref{Conversion, ,Conversion of Strings and Numbers}).
+It works by being passed, in effect, as the first argument to the
+@code{sprintf} function. Its default value is @code{"%.6g"}.
+@code{CONVFMT} was introduced by the @sc{posix} standard.@refill
+
+@iftex
+@vindex FIELDWIDTHS
+@end iftex
+@item FIELDWIDTHS
+This is a space separated list of columns that tells @code{gawk}
+how to manage input with fixed, columnar boundaries. It is an
+experimental feature that is still evolving. Assigning to @code{FIELDWIDTHS}
+overrides the use of @code{FS} for field splitting.
+@xref{Constant Size, ,Reading Fixed-width Data}, for more information.@refill
+
+If @code{gawk} is in compatibility mode
+(@pxref{Command Line, ,Invoking @code{awk}}), then @code{FIELDWIDTHS}
+has no special meaning, and field splitting operations are done based
+exclusively on the value of @code{FS}.@refill
+
+@iftex
+@vindex FS
+@end iftex
+@item FS
+@code{FS} is the input field separator
+(@pxref{Field Separators, ,Specifying how Fields are Separated}).
+The value is a single-character string or a multi-character regular
+expression that matches the separations between fields in an input
+record.@refill
+
+The default value is @w{@code{" "}}, a string consisting of a single
+space. As a special exception, this value actually means that any
+sequence of spaces and tabs is a single separator. It also causes
+spaces and tabs at the beginning or end of a line to be ignored.
+
+You can set the value of @code{FS} on the command line using the
+@samp{-F} option:
+
+@example
+awk -F, '@var{program}' @var{input-files}
+@end example
+
+If @code{gawk} is using @code{FIELDWIDTHS} for field-splitting,
+assigning a value to @code{FS} will cause @code{gawk} to return to
+the normal, regexp-based, field splitting.
+
+@item IGNORECASE
+@iftex
+@vindex IGNORECASE
+@end iftex
+If @code{IGNORECASE} is nonzero, then @emph{all} regular expression
+matching is done in a case-independent fashion. In particular, regexp
+matching with @samp{~} and @samp{!~}, and the @code{gsub} @code{index},
+@code{match}, @code{split} and @code{sub} functions all ignore case when
+doing their particular regexp operations. @strong{Note:} since field
+splitting with the value of the @code{FS} variable is also a regular
+expression operation, that too is done with case ignored.
+@xref{Case-sensitivity, ,Case-sensitivity in Matching}.
+
+If @code{gawk} is in compatibility mode
+(@pxref{Command Line, ,Invoking @code{awk}}), then @code{IGNORECASE} has
+no special meaning, and regexp operations are always case-sensitive.@refill
+
+@item OFMT
+@iftex
+@vindex OFMT
+@end iftex
+This string is used by @code{awk} to control conversion of numbers to
+strings (@pxref{Conversion, ,Conversion of Strings and Numbers}) for
+printing with the @code{print} statement.
+It works by being passed, in effect, as the first argument to the
+@code{sprintf} function. Its default value is @code{"%.6g"}.
+Earlier versions of @code{awk} also used @code{OFMT} to specify the
+format for converting numbers to strings in general expressions; this
+has been taken over by @code{CONVFMT}.@refill
+
+@item OFS
+@iftex
+@vindex OFS
+@end iftex
+This is the output field separator (@pxref{Output Separators}). It is
+output between the fields output by a @code{print} statement. Its
+default value is @w{@code{" "}}, a string consisting of a single space.
+
+@item ORS
+@iftex
+@vindex ORS
+@end iftex
+This is the output record separator. It is output at the end of every
+@code{print} statement. Its default value is a string containing a
+single newline character, which could be written as @code{"\n"}.
+(@xref{Output Separators}.)@refill
+
+@item RS
+@iftex
+@vindex RS
+@end iftex
+This is @code{awk}'s input record separator. Its default value is a string
+containing a single newline character, which means that an input record
+consists of a single line of text.
+(@xref{Records, ,How Input is Split into Records}.)@refill
+
+@item SUBSEP
+@iftex
+@vindex SUBSEP
+@end iftex
+@code{SUBSEP} is the subscript separator. It has the default value of
+@code{"\034"}, and is used to separate the parts of the name of a
+multi-dimensional array. Thus, if you access @code{foo[12,3]}, it
+really accesses @code{foo["12\0343"]}
+(@pxref{Multi-dimensional, ,Multi-dimensional Arrays}).@refill
+@end table
+
+@node Auto-set, , User-modified, Built-in Variables
+@section Built-in Variables that Convey Information
+
+This is a list of the variables that are set automatically by @code{awk}
+on certain occasions so as to provide information to your program.
+
+@table @code
+@item ARGC
+@itemx ARGV
+@iftex
+@vindex ARGC
+@vindex ARGV
+@end iftex
+The command-line arguments available to @code{awk} programs are stored in
+an array called @code{ARGV}. @code{ARGC} is the number of command-line
+arguments present. @xref{Command Line, ,Invoking @code{awk}}.
+@code{ARGV} is indexed from zero to @w{@code{ARGC - 1}}. For example:@refill
+
+@example
+awk 'BEGIN @{
+ for (i = 0; i < ARGC; i++)
+ print ARGV[i]
+ @}' inventory-shipped BBS-list
+@end example
+
+@noindent
+In this example, @code{ARGV[0]} contains @code{"awk"}, @code{ARGV[1]}
+contains @code{"inventory-shipped"}, and @code{ARGV[2]} contains
+@code{"BBS-list"}. The value of @code{ARGC} is 3, one more than the
+index of the last element in @code{ARGV} since the elements are numbered
+from zero.@refill
+
+The names @code{ARGC} and @code{ARGV}, as well the convention of indexing
+the array from 0 to @w{@code{ARGC - 1}}, are derived from the C language's
+method of accessing command line arguments.@refill
+
+Notice that the @code{awk} program is not entered in @code{ARGV}. The
+other special command line options, with their arguments, are also not
+entered. But variable assignments on the command line @emph{are}
+treated as arguments, and do show up in the @code{ARGV} array.
+
+Your program can alter @code{ARGC} and the elements of @code{ARGV}.
+Each time @code{awk} reaches the end of an input file, it uses the next
+element of @code{ARGV} as the name of the next input file. By storing a
+different string there, your program can change which files are read.
+You can use @code{"-"} to represent the standard input. By storing
+additional elements and incrementing @code{ARGC} you can cause
+additional files to be read.
+
+If you decrease the value of @code{ARGC}, that eliminates input files
+from the end of the list. By recording the old value of @code{ARGC}
+elsewhere, your program can treat the eliminated arguments as
+something other than file names.
+
+To eliminate a file from the middle of the list, store the null string
+(@code{""}) into @code{ARGV} in place of the file's name. As a
+special feature, @code{awk} ignores file names that have been
+replaced with the null string.
+
+@ignore
+see getopt.awk in the examples...
+@end ignore
+
+@item ARGIND
+@vindex ARGIND
+The index in @code{ARGV} of the current file being processed.
+Every time @code{gawk} opens a new data file for processing, it sets
+@code{ARGIND} to the index in @code{ARGV} of the file name. Thus, the
+condition @samp{FILENAME == ARGV[ARGIND]} is always true.
+
+This variable is useful in file processing; it allows you to tell how far
+along you are in the list of data files, and to distinguish between
+multiple successive instances of the same filename on the command line.
+
+While you can change the value of @code{ARGIND} within your @code{awk}
+program, @code{gawk} will automatically set it to a new value when the
+next file is opened.
+
+This variable is a @code{gawk} extension; in other @code{awk} implementations
+it is not special.
+
+@item ENVIRON
+@vindex ENVIRON
+This is an array that contains the values of the environment. The array
+indices are the environment variable names; the values are the values of
+the particular environment variables. For example,
+@code{ENVIRON["HOME"]} might be @file{/u/close}. Changing this array
+does not affect the environment passed on to any programs that
+@code{awk} may spawn via redirection or the @code{system} function.
+(In a future version of @code{gawk}, it may do so.)
+
+Some operating systems may not have environment variables.
+On such systems, the array @code{ENVIRON} is empty.
+
+@item ERRNO
+@iftex
+@vindex ERRNO
+@end iftex
+If a system error occurs either doing a redirection for @code{getline},
+during a read for @code{getline}, or during a @code{close} operation,
+then @code{ERRNO} will contain a string describing the error.
+
+This variable is a @code{gawk} extension; in other @code{awk} implementations
+it is not special.
+
+@item FILENAME
+@iftex
+@vindex FILENAME
+@end iftex
+This is the name of the file that @code{awk} is currently reading.
+If @code{awk} is reading from the standard input (in other words,
+there are no files listed on the command line),
+@code{FILENAME} is set to @code{"-"}.
+@code{FILENAME} is changed each time a new file is read
+(@pxref{Reading Files, ,Reading Input Files}).@refill
+
+@item FNR
+@iftex
+@vindex FNR
+@end iftex
+@code{FNR} is the current record number in the current file. @code{FNR} is
+incremented each time a new record is read
+(@pxref{Getline, ,Explicit Input with @code{getline}}). It is reinitialized
+to 0 each time a new input file is started.@refill
+
+@item NF
+@iftex
+@vindex NF
+@end iftex
+@code{NF} is the number of fields in the current input record.
+@code{NF} is set each time a new record is read, when a new field is
+created, or when @code{$0} changes (@pxref{Fields, ,Examining Fields}).@refill
+
+@item NR
+@iftex
+@vindex NR
+@end iftex
+This is the number of input records @code{awk} has processed since
+the beginning of the program's execution.
+(@pxref{Records, ,How Input is Split into Records}).
+@code{NR} is set each time a new record is read.@refill
+
+@item RLENGTH
+@iftex
+@vindex RLENGTH
+@end iftex
+@code{RLENGTH} is the length of the substring matched by the
+@code{match} function
+(@pxref{String Functions, ,Built-in Functions for String Manipulation}).
+@code{RLENGTH} is set by invoking the @code{match} function. Its value
+is the length of the matched string, or @minus{}1 if no match was found.@refill
+
+@item RSTART
+@iftex
+@vindex RSTART
+@end iftex
+@code{RSTART} is the start-index in characters of the substring matched by the
+@code{match} function
+(@pxref{String Functions, ,Built-in Functions for String Manipulation}).
+@code{RSTART} is set by invoking the @code{match} function. Its value
+is the position of the string where the matched substring starts, or 0
+if no match was found.@refill
+@end table
+
+@node Command Line, Language History, Built-in Variables, Top
+@c node-name, next, previous, up
+@chapter Invoking @code{awk}
+@cindex command line
+@cindex invocation of @code{gawk}
+@cindex arguments, command line
+@cindex options, command line
+@cindex long options
+@cindex options, long
+
+There are two ways to run @code{awk}: with an explicit program, or with
+one or more program files. Here are templates for both of them; items
+enclosed in @samp{@r{[}@dots{}@r{]}} in these templates are optional.
+
+Besides traditional one-letter @sc{posix}-style options, @code{gawk} also
+supports GNU long named options.
+
+@example
+awk @r{[@var{POSIX or GNU style options}]} -f progfile @r{[@code{--}]} @var{file} @dots{}
+awk @r{[@var{POSIX or GNU style options}]} @r{[@code{--}]} '@var{program}' @var{file} @dots{}
+@end example
+
+@menu
+* Options:: Command line options and their meanings.
+* Other Arguments:: Input file names and variable assignments.
+* AWKPATH Variable:: Searching directories for @code{awk} programs.
+* Obsolete:: Obsolete Options and/or features.
+* Undocumented:: Undocumented Options and Features.
+@end menu
+
+@node Options, Other Arguments, Command Line, Command Line
+@section Command Line Options
+
+Options begin with a minus sign, and consist of a single character.
+GNU style long named options consist of two minus signs and
+a keyword that can be abbreviated if the abbreviation allows the option
+to be uniquely identified. If the option takes an argument, then the
+keyword is immediately followed by an equals sign (@samp{=}) and the
+argument's value. For brevity, the discussion below only refers to the
+traditional short options; however the long and short options are
+interchangeable in all contexts.
+
+Each long named option for @code{gawk} has a corresponding
+@sc{posix}-style option. The options and their meanings are as follows:
+
+@table @code
+@item -F @var{fs}
+@itemx --field-separator=@var{fs}
+@iftex
+@cindex @code{-F} option
+@end iftex
+@cindex @code{--field-separator} option
+Sets the @code{FS} variable to @var{fs}
+(@pxref{Field Separators, ,Specifying how Fields are Separated}).@refill
+
+@item -f @var{source-file}
+@itemx --file=@var{source-file}
+@iftex
+@cindex @code{-f} option
+@end iftex
+@cindex @code{--file} option
+Indicates that the @code{awk} program is to be found in @var{source-file}
+instead of in the first non-option argument.
+
+@item -v @var{var}=@var{val}
+@itemx --assign=@var{var}=@var{val}
+@cindex @samp{-v} option
+@cindex @code{--assign} option
+Sets the variable @var{var} to the value @var{val} @emph{before}
+execution of the program begins. Such variable values are available
+inside the @code{BEGIN} rule (see below for a fuller explanation).
+
+The @samp{-v} option can only set one variable, but you can use
+it more than once, setting another variable each time, like this:
+@samp{@w{-v foo=1} @w{-v bar=2}}.
+
+@item -W @var{gawk-opt}
+@cindex @samp{-W} option
+Following the @sc{posix} standard, options that are implementation
+specific are supplied as arguments to the @samp{-W} option. With @code{gawk},
+these arguments may be separated by commas, or quoted and separated by
+whitespace. Case is ignored when processing these options. These options
+also have corresponding GNU style long named options. The following
+@code{gawk}-specific options are available:
+
+@table @code
+@item -W compat
+@itemx --compat
+@cindex @code{--compat} option
+Specifies @dfn{compatibility mode}, in which the GNU extensions in
+@code{gawk} are disabled, so that @code{gawk} behaves just like Unix
+@code{awk}.
+@xref{POSIX/GNU, ,Extensions in @code{gawk} not in POSIX @code{awk}},
+which summarizes the extensions. Also see
+@ref{Compatibility Mode, ,Downward Compatibility and Debugging}.@refill
+
+@item -W copyleft
+@itemx -W copyright
+@itemx --copyleft
+@itemx --copyright
+@cindex @code{--copyleft} option
+@cindex @code{--copyright} option
+Print the short version of the General Public License.
+This option may disappear in a future version of @code{gawk}.
+
+@item -W help
+@itemx -W usage
+@itemx --help
+@itemx --usage
+@cindex @code{--help} option
+@cindex @code{--usage} option
+Print a ``usage'' message summarizing the short and long style options
+that @code{gawk} accepts, and then exit.
+
+@item -W lint
+@itemx --lint
+@cindex @code{--lint} option
+Provide warnings about constructs that are dubious or non-portable to
+other @code{awk} implementations.
+Some warnings are issued when @code{gawk} first reads your program. Others
+are issued at run-time, as your program executes.
+
+@item -W posix
+@itemx --posix
+@cindex @code{--posix} option
+Operate in strict @sc{posix} mode. This disables all @code{gawk}
+extensions (just like @code{-W compat}), and adds the following additional
+restrictions:
+
+@itemize @bullet{}
+@item
+@code{\x} escape sequences are not recognized
+(@pxref{Constants, ,Constant Expressions}).@refill
+
+@item
+The synonym @code{func} for the keyword @code{function} is not
+recognized (@pxref{Definition Syntax, ,Syntax of Function Definitions}).
+
+@item
+The operators @samp{**} and @samp{**=} cannot be used in
+place of @samp{^} and @samp{^=} (@pxref{Arithmetic Ops, ,Arithmetic Operators},
+and also @pxref{Assignment Ops, ,Assignment Expressions}).@refill
+
+@item
+Specifying @samp{-Ft} on the command line does not set the value
+of @code{FS} to be a single tab character
+(@pxref{Field Separators, ,Specifying how Fields are Separated}).@refill
+@end itemize
+
+Although you can supply both @samp{-W compat} and @samp{-W posix} on the
+command line, @samp{-W posix} will take precedence.
+
+@item -W source=@var{program-text}
+@itemx --source=@var{program-text}
+@cindex @code{--source} option
+Program source code is taken from the @var{program-text}. This option
+allows you to mix @code{awk} source code in files with program source
+code that you would enter on the command line. This is particularly useful
+when you have library functions that you wish to use from your command line
+programs (@pxref{AWKPATH Variable, ,The @code{AWKPATH} Environment Variable}).
+
+@item -W version
+@itemx --version
+@cindex @code{--version} option
+Prints version information for this particular copy of @code{gawk}.
+This is so you can determine if your copy of @code{gawk} is up to date
+with respect to whatever the Free Software Foundation is currently
+distributing. This option may disappear in a future version of @code{gawk}.
+@end table
+
+@item --
+Signals the end of the command line options. The following arguments
+are not treated as options even if they begin with @samp{-}. This
+interpretation of @samp{--} follows the @sc{posix} argument parsing
+conventions.
+
+This is useful if you have file names that start with @samp{-},
+or in shell scripts, if you have file names that will be specified
+by the user which could start with @samp{-}.
+@end table
+
+Any other options are flagged as invalid with a warning message, but
+are otherwise ignored.
+
+In compatibility mode, as a special case, if the value of @var{fs} supplied
+to the @samp{-F} option is @samp{t}, then @code{FS} is set to the tab
+character (@code{"\t"}). This is only true for @samp{-W compat}, and not
+for @samp{-W posix}
+(@pxref{Field Separators, ,Specifying how Fields are Separated}).@refill
+
+If the @samp{-f} option is @emph{not} used, then the first non-option
+command line argument is expected to be the program text.
+
+The @samp{-f} option may be used more than once on the command line.
+If it is, @code{awk} reads its program source from all of the named files, as
+if they had been concatenated together into one big file. This is
+useful for creating libraries of @code{awk} functions. Useful functions
+can be written once, and then retrieved from a standard place, instead
+of having to be included into each individual program. You can still
+type in a program at the terminal and use library functions, by specifying
+@samp{-f /dev/tty}. @code{awk} will read a file from the terminal
+to use as part of the @code{awk} program. After typing your program,
+type @kbd{Control-d} (the end-of-file character) to terminate it.
+(You may also use @samp{-f -} to read program source from the standard
+input, but then you will not be able to also use the standard input as a
+source of data.)
+
+Because it is clumsy using the standard @code{awk} mechanisms to mix source
+file and command line @code{awk} programs, @code{gawk} provides the
+@samp{--source} option. This does not require you to pre-empt the standard
+input for your source code, and allows you to easily mix command line
+and library source code
+(@pxref{AWKPATH Variable, ,The @code{AWKPATH} Environment Variable}).
+
+If no @samp{-f} or @samp{--source} option is specified, then @code{gawk}
+will use the first non-option command line argument as the text of the
+program source code.
+
+@node Other Arguments, AWKPATH Variable, Options, Command Line
+@section Other Command Line Arguments
+
+Any additional arguments on the command line are normally treated as
+input files to be processed in the order specified. However, an
+argument that has the form @code{@var{var}=@var{value}}, means to assign
+the value @var{value} to the variable @var{var}---it does not specify a
+file at all.
+
+@vindex ARGV
+All these arguments are made available to your @code{awk} program in the
+@code{ARGV} array (@pxref{Built-in Variables}). Command line options
+and the program text (if present) are omitted from the @code{ARGV}
+array. All other arguments, including variable assignments, are
+included.
+
+The distinction between file name arguments and variable-assignment
+arguments is made when @code{awk} is about to open the next input file.
+At that point in execution, it checks the ``file name'' to see whether
+it is really a variable assignment; if so, @code{awk} sets the variable
+instead of reading a file.
+
+Therefore, the variables actually receive the specified values after all
+previously specified files have been read. In particular, the values of
+variables assigned in this fashion are @emph{not} available inside a
+@code{BEGIN} rule
+(@pxref{BEGIN/END, ,@code{BEGIN} and @code{END} Special Patterns}),
+since such rules are run before @code{awk} begins scanning the argument list.
+The values given on the command line are processed for escape sequences
+(@pxref{Constants, ,Constant Expressions}).@refill
+
+In some earlier implementations of @code{awk}, when a variable assignment
+occurred before any file names, the assignment would happen @emph{before}
+the @code{BEGIN} rule was executed. Some applications came to depend
+upon this ``feature.'' When @code{awk} was changed to be more consistent,
+the @samp{-v} option was added to accommodate applications that depended
+upon this old behavior.
+
+The variable assignment feature is most useful for assigning to variables
+such as @code{RS}, @code{OFS}, and @code{ORS}, which control input and
+output formats, before scanning the data files. It is also useful for
+controlling state if multiple passes are needed over a data file. For
+example:@refill
+
+@cindex multiple passes over data
+@cindex passes, multiple
+@smallexample
+awk 'pass == 1 @{ @var{pass 1 stuff} @}
+ pass == 2 @{ @var{pass 2 stuff} @}' pass=1 datafile pass=2 datafile
+@end smallexample
+
+Given the variable assignment feature, the @samp{-F} option is not
+strictly necessary. It remains for historical compatibility.
+
+@node AWKPATH Variable, Obsolete, Other Arguments, Command Line
+@section The @code{AWKPATH} Environment Variable
+@cindex @code{AWKPATH} environment variable
+@cindex search path
+@cindex directory search
+@cindex path, search
+@iftex
+@cindex differences between @code{gawk} and @code{awk}
+@end iftex
+
+The previous section described how @code{awk} program files can be named
+on the command line with the @samp{-f} option. In some @code{awk}
+implementations, you must supply a precise path name for each program
+file, unless the file is in the current directory.
+
+But in @code{gawk}, if the file name supplied in the @samp{-f} option
+does not contain a @samp{/}, then @code{gawk} searches a list of
+directories (called the @dfn{search path}), one by one, looking for a
+file with the specified name.
+
+The search path is actually a string consisting of directory names
+separated by colons. @code{gawk} gets its search path from the
+@code{AWKPATH} environment variable. If that variable does not exist,
+@code{gawk} uses the default path, which is
+@samp{.:/usr/lib/awk:/usr/local/lib/awk}. (Programs written by
+system administrators should use an @code{AWKPATH} variable that
+does not include the current directory, @samp{.}.)@refill
+
+The search path feature is particularly useful for building up libraries
+of useful @code{awk} functions. The library files can be placed in a
+standard directory that is in the default path, and then specified on
+the command line with a short file name. Otherwise, the full file name
+would have to be typed for each file.
+
+By combining the @samp{--source} and @samp{-f} options, your command line
+@code{awk} programs can use facilities in @code{awk} library files.
+
+Path searching is not done if @code{gawk} is in compatibility mode.
+This is true for both @samp{-W compat} and @samp{-W posix}.
+@xref{Options, ,Command Line Options}.
+
+@strong{Note:} if you want files in the current directory to be found,
+you must include the current directory in the path, either by writing
+@file{.} as an entry in the path, or by writing a null entry in the
+path. (A null entry is indicated by starting or ending the path with a
+colon, or by placing two colons next to each other (@samp{::}).) If the
+current directory is not included in the path, then files cannot be
+found in the current directory. This path search mechanism is identical
+to the shell's.
+@c someday, @cite{The Bourne Again Shell}....
+
+@node Obsolete, Undocumented, AWKPATH Variable, Command Line
+@section Obsolete Options and/or Features
+
+@cindex deprecated options
+@cindex obsolete options
+@cindex deprecated features
+@cindex obsolete features
+This section describes features and/or command line options from the
+previous release of @code{gawk} that are either not available in the
+current version, or that are still supported but deprecated (meaning that
+they will @emph{not} be in the next release).
+
+@c update this section for each release!
+
+For version 2.15 of @code{gawk}, the following command line options
+from version 2.11.1 are no longer recognized.
+
+@table @samp
+@ignore
+@item -nostalgia
+Use @samp{-W nostalgia} instead.
+@end ignore
+
+@item -c
+Use @samp{-W compat} instead.
+
+@item -V
+Use @samp{-W version} instead.
+
+@item -C
+Use @samp{-W copyright} instead.
+
+@item -a
+@itemx -e
+These options produce an ``unrecognized option'' error message but have
+no effect on the execution of @code{gawk}. The @sc{posix} standard now
+specifies traditional @code{awk} regular expressions for the @code{awk} utility.
+@end table
+
+The public-domain version of @code{strftime} that is distributed with
+@code{gawk} changed for the 2.14 release. The @samp{%V} conversion specifier
+that used to generate the date in VMS format was changed to @samp{%v}.
+This is because the @sc{posix} standard for the @code{date} utility now
+specifies a @samp{%V} conversion specifier.
+@xref{Time Functions, ,Functions for Dealing with Time Stamps}, for details.
+
+@node Undocumented, , Obsolete, Command Line
+@section Undocumented Options and Features
+
+This section intentionally left blank.
+
+@c Read The Source, Luke!
+
+@ignore
+@c If these came out in the Info file or TeX manual, then they wouldn't
+@c be undocumented, would they?
+
+@code{gawk} has one undocumented option:
+
+@table @samp
+@item -W nostalgia
+Print the message @code{"awk: bailing out near line 1"} and dump core.
+This option was inspired by the common behavior of very early versions of
+Unix @code{awk}, and by a t--shirt.
+@end table
+
+Early versions of @code{awk} used to not require any separator (either
+a newline or @samp{;}) between the rules in @code{awk} programs. Thus,
+it was common to see one-line programs like:
+
+@example
+awk '@{ sum += $1 @} END @{ print sum @}'
+@end example
+
+@code{gawk} actually supports this, but it is purposely undocumented
+since it is considered bad style. The correct way to write such a program
+is either
+
+@example
+awk '@{ sum += $1 @} ; END @{ print sum @}'
+@end example
+
+@noindent
+or
+
+@example
+awk '@{ sum += $1 @}
+ END @{ print sum @}' data
+@end example
+
+@noindent
+@xref{Statements/Lines, ,@code{awk} Statements versus Lines}, for a fuller
+explanation.@refill
+
+As an accident of the implementation of the original Unix @code{awk}, if
+a built-in function used @code{$0} as its default argument, it was possible
+to call that function without the parentheses. In particular, it was
+common practice to use the @code{length} function in this fashion.
+For example, the pipeline:
+
+@example
+echo abcdef | awk '@{ print length @}'
+@end example
+
+@noindent
+would print @samp{6}.
+
+For backwards compatibility with old programs, @code{gawk} supports
+this usage, but only for the @code{length} function. New programs should
+@emph{not} call the @code{length} function this way. In particular,
+this usage will not be portable to other @sc{posix} compliant versions
+of @code{awk}. It is also poor style.
+
+@end ignore
+
+@node Language History, Installation, Command Line, Top
+@chapter The Evolution of the @code{awk} Language
+
+This manual describes the GNU implementation of @code{awk}, which is patterned
+after the @sc{posix} specification. Many @code{awk} users are only familiar
+with the original @code{awk} implementation in Version 7 Unix, which is also
+the basis for the version in Berkeley Unix (through 4.3--Reno). This chapter
+briefly describes the evolution of the @code{awk} language.
+
+@menu
+* V7/S5R3.1:: The major changes between V7 and
+ System V Release 3.1.
+* S5R4:: Minor changes between System V
+ Releases 3.1 and 4.
+* POSIX:: New features from the @sc{posix} standard.
+* POSIX/GNU:: The extensions in @code{gawk}
+ not in @sc{posix} @code{awk}.
+@end menu
+
+@node V7/S5R3.1, S5R4, Language History, Language History
+@section Major Changes between V7 and S5R3.1
+
+The @code{awk} language evolved considerably between the release of
+Version 7 Unix (1978) and the new version first made widely available in
+System V Release 3.1 (1987). This section summarizes the changes, with
+cross-references to further details.
+
+@itemize @bullet
+@item
+The requirement for @samp{;} to separate rules on a line
+(@pxref{Statements/Lines, ,@code{awk} Statements versus Lines}).
+
+@item
+User-defined functions, and the @code{return} statement
+(@pxref{User-defined, ,User-defined Functions}).
+
+@item
+The @code{delete} statement (@pxref{Delete, ,The @code{delete} Statement}).
+
+@item
+The @code{do}-@code{while} statement
+(@pxref{Do Statement, ,The @code{do}-@code{while} Statement}).@refill
+
+@item
+The built-in functions @code{atan2}, @code{cos}, @code{sin}, @code{rand} and
+@code{srand} (@pxref{Numeric Functions, ,Numeric Built-in Functions}).
+
+@item
+The built-in functions @code{gsub}, @code{sub}, and @code{match}
+(@pxref{String Functions, ,Built-in Functions for String Manipulation}).
+
+@item
+The built-in functions @code{close}, which closes an open file, and
+@code{system}, which allows the user to execute operating system
+commands (@pxref{I/O Functions, ,Built-in Functions for Input/Output}).@refill
+@c Does the above verbiage prevents an overfull hbox? --mew, rjc 24jan1992
+
+@item
+The @code{ARGC}, @code{ARGV}, @code{FNR}, @code{RLENGTH}, @code{RSTART},
+and @code{SUBSEP} built-in variables (@pxref{Built-in Variables}).
+
+@item
+The conditional expression using the operators @samp{?} and @samp{:}
+(@pxref{Conditional Exp, ,Conditional Expressions}).@refill
+
+@item
+The exponentiation operator @samp{^}
+(@pxref{Arithmetic Ops, ,Arithmetic Operators}) and its assignment operator
+form @samp{^=} (@pxref{Assignment Ops, ,Assignment Expressions}).@refill
+
+@item
+C-compatible operator precedence, which breaks some old @code{awk}
+programs (@pxref{Precedence, ,Operator Precedence (How Operators Nest)}).
+
+@item
+Regexps as the value of @code{FS}
+(@pxref{Field Separators, ,Specifying how Fields are Separated}), and as the
+third argument to the @code{split} function
+(@pxref{String Functions, ,Built-in Functions for String Manipulation}).@refill
+
+@item
+Dynamic regexps as operands of the @samp{~} and @samp{!~} operators
+(@pxref{Regexp Usage, ,How to Use Regular Expressions}).
+
+@item
+Escape sequences (@pxref{Constants, ,Constant Expressions}) in regexps.@refill
+
+@item
+The escape sequences @samp{\b}, @samp{\f}, and @samp{\r}
+(@pxref{Constants, ,Constant Expressions}).
+
+@item
+Redirection of input for the @code{getline} function
+(@pxref{Getline, ,Explicit Input with @code{getline}}).@refill
+
+@item
+Multiple @code{BEGIN} and @code{END} rules
+(@pxref{BEGIN/END, ,@code{BEGIN} and @code{END} Special Patterns}).@refill
+
+@item
+Simulated multi-dimensional arrays
+(@pxref{Multi-dimensional, ,Multi-dimensional Arrays}).@refill
+@end itemize
+
+@node S5R4, POSIX, V7/S5R3.1, Language History
+@section Changes between S5R3.1 and S5R4
+
+The System V Release 4 version of Unix @code{awk} added these features
+(some of which originated in @code{gawk}):
+
+@itemize @bullet
+@item
+The @code{ENVIRON} variable (@pxref{Built-in Variables}).
+
+@item
+Multiple @samp{-f} options on the command line
+(@pxref{Command Line, ,Invoking @code{awk}}).@refill
+
+@item
+The @samp{-v} option for assigning variables before program execution begins
+(@pxref{Command Line, ,Invoking @code{awk}}).@refill
+
+@item
+The @samp{--} option for terminating command line options.
+
+@item
+The @samp{\a}, @samp{\v}, and @samp{\x} escape sequences
+(@pxref{Constants, ,Constant Expressions}).@refill
+
+@item
+A defined return value for the @code{srand} built-in function
+(@pxref{Numeric Functions, ,Numeric Built-in Functions}).
+
+@item
+The @code{toupper} and @code{tolower} built-in string functions
+for case translation
+(@pxref{String Functions, ,Built-in Functions for String Manipulation}).@refill
+
+@item
+A cleaner specification for the @samp{%c} format-control letter in the
+@code{printf} function
+(@pxref{Printf, ,Using @code{printf} Statements for Fancier Printing}).@refill
+
+@item
+The ability to dynamically pass the field width and precision (@code{"%*.*d"})
+in the argument list of the @code{printf} function
+(@pxref{Printf, ,Using @code{printf} Statements for Fancier Printing}).@refill
+
+@item
+The use of constant regexps such as @code{/foo/} as expressions, where
+they are equivalent to use of the matching operator, as in @code{$0 ~
+/foo/} (@pxref{Constants, ,Constant Expressions}).
+@end itemize
+
+@node POSIX, POSIX/GNU, S5R4, Language History
+@section Changes between S5R4 and POSIX @code{awk}
+
+The @sc{posix} Command Language and Utilities standard for @code{awk}
+introduced the following changes into the language:
+
+@itemize @bullet{}
+@item
+The use of @samp{-W} for implementation-specific options.
+
+@item
+The use of @code{CONVFMT} for controlling the conversion of numbers
+to strings (@pxref{Conversion, ,Conversion of Strings and Numbers}).
+
+@item
+The concept of a numeric string, and tighter comparison rules to go
+with it (@pxref{Comparison Ops, ,Comparison Expressions}).
+
+@item
+More complete documentation of many of the previously undocumented
+features of the language.
+@end itemize
+
+@node POSIX/GNU, , POSIX, Language History
+@section Extensions in @code{gawk} not in POSIX @code{awk}
+
+The GNU implementation, @code{gawk}, adds these features:
+
+@itemize @bullet
+@item
+The @code{AWKPATH} environment variable for specifying a path search for
+the @samp{-f} command line option
+(@pxref{Command Line, ,Invoking @code{awk}}).@refill
+
+@item
+The various @code{gawk} specific features available via the @samp{-W}
+command line option (@pxref{Command Line, ,Invoking @code{awk}}).
+
+@item
+The @code{ARGIND} variable, that tracks the movement of @code{FILENAME}
+through @code{ARGV}. (@pxref{Built-in Variables}).
+
+@item
+The @code{ERRNO} variable, that contains the system error message when
+@code{getline} returns @minus{}1, or when @code{close} fails.
+(@pxref{Built-in Variables}).
+
+@item
+The @code{IGNORECASE} variable and its effects
+(@pxref{Case-sensitivity, ,Case-sensitivity in Matching}).@refill
+
+@item
+The @code{FIELDWIDTHS} variable and its effects
+(@pxref{Constant Size, ,Reading Fixed-width Data}).@refill
+
+@item
+The @code{next file} statement for skipping to the next data file
+(@pxref{Next File Statement, ,The @code{next file} Statement}).@refill
+
+@item
+The @code{systime} and @code{strftime} built-in functions for obtaining
+and printing time stamps
+(@pxref{Time Functions, ,Functions for Dealing with Time Stamps}).@refill
+
+@item
+The @file{/dev/stdin}, @file{/dev/stdout}, @file{/dev/stderr}, and
+@file{/dev/fd/@var{n}} file name interpretation
+(@pxref{Special Files, ,Standard I/O Streams}).@refill
+
+@item
+The @samp{-W compat} option to turn off these extensions
+(@pxref{Command Line, ,Invoking @code{awk}}).@refill
+
+@item
+The @samp{-W posix} option for full @sc{posix} compliance
+(@pxref{Command Line, ,Invoking @code{awk}}).@refill
+
+@end itemize
+
+@node Installation, Gawk Summary, Language History, Top
+@chapter Installing @code{gawk}
+
+This chapter provides instructions for installing @code{gawk} on the
+various platforms that are supported by the developers. The primary
+developers support Unix (and one day, GNU), while the other ports were
+contributed. The file @file{ACKNOWLEDGMENT} in the @code{gawk}
+distribution lists the electronic mail addresses of the people who did
+the respective ports.@refill
+
+@menu
+* Gawk Distribution:: What is in the @code{gawk} distribution.
+* Unix Installation:: Installing @code{gawk} under various versions
+ of Unix.
+* VMS Installation:: Installing @code{gawk} on VMS.
+* MS-DOS Installation:: Installing @code{gawk} on MS-DOS.
+* Atari Installation:: Installing @code{gawk} on the Atari ST.
+@end menu
+
+@node Gawk Distribution, Unix Installation, Installation, Installation
+@section The @code{gawk} Distribution
+
+This section first describes how to get and extract the @code{gawk}
+distribution, and then discusses what is in the various files and
+subdirectories.
+
+@menu
+* Extracting:: How to get and extract the distribution.
+* Distribution contents:: What is in the distribution.
+@end menu
+
+@node Extracting, Distribution contents, Gawk Distribution, Gawk Distribution
+@subsection Getting the @code{gawk} Distribution
+
+@cindex getting gawk
+@cindex anonymous ftp
+@cindex anonymous uucp
+@cindex ftp, anonymous
+@cindex uucp, anonymous
+@code{gawk} is distributed as a @code{tar} file compressed with the
+GNU Zip program, @code{gzip}. You can
+get it via anonymous @code{ftp} to the Internet host @code{prep.ai.mit.edu}.
+Like all GNU software, it will be archived at other well known systems,
+from which it will be possible to use some sort of anonymous @code{uucp} to
+obtain the distribution as well.
+You can also order @code{gawk} on tape or CD-ROM directly from the
+Free Software Foundation. (The address is on the copyright page.)
+Doing so directly contributes to the support of the foundation and to
+the production of more free software.
+
+Once you have the distribution (for example,
+@file{gawk-2.15.0.tar.z}), first use @code{gzip} to expand the
+file, and then use @code{tar} to extract it. You can use the following
+pipeline to produce the @code{gawk} distribution:
+
+@example
+# Under System V, add 'o' to the tar flags
+gzip -d -c gawk-2.15.0.tar.z | tar -xvpf -
+@end example
+
+@noindent
+This will create a directory named @file{gawk-2.15} in the current
+directory.
+
+The distribution file name is of the form @file{gawk-2.15.@var{n}.tar.Z}.
+The @var{n} represents a @dfn{patchlevel}, meaning that minor bugs have
+been fixed in the major release. The current patchlevel is 0, but when
+retrieving distributions, you should get the version with the highest
+patchlevel.@refill
+
+If you are not on a Unix system, you will need to make other arrangements
+for getting and extracting the @code{gawk} distribution. You should consult
+a local expert.
+
+@node Distribution contents, , Extracting, Gawk Distribution
+@subsection Contents of the @code{gawk} Distribution
+
+@code{gawk} has a number of C source files, documentation files,
+subdirectories and files related to the configuration process
+(@pxref{Unix Installation, ,Compiling and Installing @code{gawk} on Unix}),
+and several subdirectories related to different, non-Unix,
+operating systems.@refill
+
+@table @asis
+@item various @samp{.c}, @samp{.y}, and @samp{.h} files
+
+The C and YACC source files are the actual @code{gawk} source code.
+@end table
+
+@table @file
+@item README
+@itemx README.VMS
+@itemx README.dos
+@itemx README.rs6000
+@itemx README.ultrix
+Descriptive files: @file{README} for @code{gawk} under Unix, and the
+rest for the various hardware and software combinations.
+
+@item PORTS
+A list of systems to which @code{gawk} has been ported, and which
+have successfully run the test suite.
+
+@item ACKNOWLEDGMENT
+A list of the people who contributed major parts of the code or documentation.
+
+@item NEWS
+A list of changes to @code{gawk} since the last release or patch.
+
+@item COPYING
+The GNU General Public License.
+
+@item FUTURES
+A brief list of features and/or changes being contemplated for future
+releases, with some indication of the time frame for the feature, based
+on its difficulty.
+
+@item LIMITATIONS
+A list of those factors that limit @code{gawk}'s performance.
+Most of these depend on the hardware or operating system software, and
+are not limits in @code{gawk} itself.@refill
+
+@item PROBLEMS
+A file describing known problems with the current release.
+
+@item gawk.1
+The @code{troff} source for a manual page describing @code{gawk}.
+
+@item gawk.texinfo
+@ifinfo
+The @code{texinfo} source file for this Info file.
+It should be processed with @TeX{} to produce a printed manual, and
+with @code{makeinfo} to produce the Info file.@refill
+@end ifinfo
+@iftex
+The @code{texinfo} source file for this manual.
+It should be processed with @TeX{} to produce a printed manual, and
+with @code{makeinfo} to produce the Info file.@refill
+@end iftex
+
+@item Makefile.in
+@itemx config
+@itemx config.in
+@itemx configure
+@itemx missing
+@itemx mungeconf
+These files and subdirectories are used when configuring @code{gawk}
+for various Unix systems. They are explained in detail in
+@ref{Unix Installation, ,Compiling and Installing @code{gawk} on Unix}.@refill
+
+@item atari
+Files needed for building @code{gawk} on an Atari ST.
+@xref{Atari Installation, ,Installing @code{gawk} on the Atari ST}, for details.
+
+@item pc
+Files needed for building @code{gawk} under MS-DOS.
+@xref{MS-DOS Installation, ,Installing @code{gawk} on MS-DOS}, for details.
+
+@item vms
+Files needed for building @code{gawk} under VMS.
+@xref{VMS Installation, ,Compiling Installing and Running @code{gawk} on VMS}, for details.
+
+@item test
+Many interesting @code{awk} programs, provided as a test suite for
+@code{gawk}. You can use @samp{make test} from the top level @code{gawk}
+directory to run your version of @code{gawk} against the test suite.
+@c There are many programs here that are useful in their own right.
+If @code{gawk} successfully passes @samp{make test} then you can
+be confident of a successful port.@refill
+@end table
+
+@node Unix Installation, VMS Installation, Gawk Distribution, Installation
+@section Compiling and Installing @code{gawk} on Unix
+
+Often, you can compile and install @code{gawk} by typing only two
+commands. However, if you do not use a supported system, you may need
+to configure @code{gawk} for your system yourself.
+
+@menu
+* Quick Installation:: Compiling @code{gawk} on a
+ supported Unix version.
+* Configuration Philosophy:: How it's all supposed to work.
+* New Configurations:: What to do if there is no supplied
+ configuration for your system.
+@end menu
+
+@node Quick Installation, Configuration Philosophy, Unix Installation, Unix Installation
+@subsection Compiling @code{gawk} for a Supported Unix Version
+
+@cindex installation, unix
+After you have extracted the @code{gawk} distribution, @code{cd}
+to @file{gawk-2.15}. Look in the @file{config} subdirectory for a
+file that matches your hardware/software combination. In general,
+only the software is relevant; for example @code{sunos41} is used
+for SunOS 4.1, on both Sun 3 and Sun 4 hardware.@refill
+
+If you find such a file, run the command:
+
+@example
+# assume you have SunOS 4.1
+./configure sunos41
+@end example
+
+This produces a @file{Makefile} and @file{config.h} tailored to your
+system. You may wish to edit the @file{Makefile} to use a different
+C compiler, such as @code{gcc}, the GNU C compiler, if you have it.
+You may also wish to change the @code{CFLAGS} variable, which controls
+the command line options that are passed to the C compiler (such as
+optimization levels, or compiling for debugging).@refill
+
+After you have configured @file{Makefile} and @file{config.h}, type:
+
+@example
+make
+@end example
+
+@noindent
+and shortly thereafter, you should have an executable version of @code{gawk}.
+That's all there is to it!
+
+@node Configuration Philosophy, New Configurations, Quick Installation, Unix Installation
+@subsection The Configuration Process
+
+(This section is of interest only if you know something about using the
+C language and the Unix operating system.)
+
+The source code for @code{gawk} generally attempts to adhere to industry
+standards wherever possible. This means that @code{gawk} uses library
+routines that are specified by the @sc{ansi} C standard and by the @sc{posix}
+operating system interface standard. When using an @sc{ansi} C compiler,
+function prototypes are provided to help improve the compile-time checking.
+
+Many older Unix systems do not support all of either the @sc{ansi} or the
+@sc{posix} standards. The @file{missing} subdirectory in the @code{gawk}
+distribution contains replacement versions of those subroutines that are
+most likely to be missing.
+
+The @file{config.h} file that is created by the @code{configure} program
+contains definitions that describe features of the particular operating
+system where you are attempting to compile @code{gawk}. For the most
+part, it lists which standard subroutines are @emph{not} available.
+For example, if your system lacks the @samp{getopt} routine, then
+@samp{GETOPT_MISSING} would be defined.
+
+@file{config.h} also defines constants that describe facts about your
+variant of Unix. For example, there may not be an @samp{st_blksize}
+element in the @code{stat} structure. In this case @samp{BLKSIZE_MISSING}
+would be defined.
+
+Based on the list in @file{config.h} of standard subroutines that are
+missing, @file{missing.c} will do a @samp{#include} of the appropriate
+file(s) from the @file{missing} subdirectory.@refill
+
+Conditionally compiled code in the other source files relies on the
+other definitions in the @file{config.h} file.
+
+Besides creating @file{config.h}, @code{configure} produces a @file{Makefile}
+from @file{Makefile.in}. There are a number of lines in @file{Makefile.in}
+that are system or feature specific. For example, there is line that begins
+with @samp{##MAKE_ALLOCA_C##}. This is normally a comment line, since
+it starts with @samp{#}. If a configuration file has @samp{MAKE_ALLOCA_C}
+in it, then @code{configure} will delete the @samp{##MAKE_ALLOCA_C##}
+from the beginning of the line. This will enable the rules in the
+@file{Makefile} that use a C version of @samp{alloca}. There are several
+similar features that work in this fashion.@refill
+
+@node New Configurations, , Configuration Philosophy, Unix Installation
+@subsection Configuring @code{gawk} for a New System
+
+(This section is of interest only if you know something about using the
+C language and the Unix operating system, and if you have to install
+@code{gawk} on a system that is not supported by the @code{gawk} distribution.
+If you are a C or Unix novice, get help from a local expert.)
+
+If you need to configure @code{gawk} for a Unix system that is not
+supported in the distribution, first see
+@ref{Configuration Philosophy, ,The Configuration Process}.
+Then, copy @file{config.in} to @file{config.h}, and copy
+@file{Makefile.in} to @file{Makefile}.@refill
+
+Next, edit both files. Both files are liberally commented, and the
+necessary changes should be straightforward.
+
+While editing @file{config.h}, you need to determine what library
+routines you do or do not have by consulting your system documentation, or
+by perusing your actual libraries using the @code{ar} or @code{nm} utilities.
+In the worst case, simply do not define @emph{any} of the macros for missing
+subroutines. When you compile @code{gawk}, the final link-editing step
+will fail. The link editor will provide you with a list of unresolved external
+references---these are the missing subroutines. Edit @file{config.h} again
+and recompile, and you should be set.@refill
+
+Editing the @file{Makefile} should also be straightforward. Enable or
+disable the lines that begin with @samp{##MAKE_@var{whatever}##}, as
+appropriate. Select the correct C compiler and @code{CFLAGS} for it.
+Then run @code{make}.
+
+Getting a correct configuration is likely to be an iterative process.
+Do not be discouraged if it takes you several tries. If you have no
+luck whatsoever, please report your system type, and the steps you took.
+Once you do have a working configuration, please send it to the maintainers
+so that support for your system can be added to the official release.
+
+@xref{Bugs, ,Reporting Problems and Bugs}, for information on how to report
+problems in configuring @code{gawk}. You may also use the same mechanisms
+for sending in new configurations.@refill
+
+@node VMS Installation, MS-DOS Installation, Unix Installation, Installation
+@section Compiling, Installing, and Running @code{gawk} on VMS
+
+@c based on material from
+@c Pat Rankin <rankin@eql.caltech.edu>
+
+@cindex installation, vms
+This section describes how to compile and install @code{gawk} under VMS.
+
+@menu
+* VMS Compilation:: How to compile @code{gawk} under VMS.
+* VMS Installation Details:: How to install @code{gawk} under VMS.
+* VMS Running:: How to run @code{gawk} under VMS.
+* VMS POSIX:: Alternate instructions for VMS POSIX.
+@end menu
+
+@node VMS Compilation, VMS Installation Details, VMS Installation, VMS Installation
+@subsection Compiling @code{gawk} under VMS
+
+To compile @code{gawk} under VMS, there is a @code{DCL} command procedure that
+will issue all the necessary @code{CC} and @code{LINK} commands, and there is
+also a @file{Makefile} for use with the @code{MMS} utility. From the source
+directory, use either
+
+@smallexample
+$ @@[.VMS]VMSBUILD.COM
+@end smallexample
+
+@noindent
+or
+
+@smallexample
+$ MMS/DESCRIPTION=[.VMS]DECSRIP.MMS GAWK
+@end smallexample
+
+Depending upon which C compiler you are using, follow one of the sets
+of instructions in this table:
+
+@table @asis
+@item VAX C V3.x
+Use either @file{vmsbuild.com} or @file{descrip.mms} as is. These use
+@code{CC/OPTIMIZE=NOLINE}, which is essential for Version 3.0.
+
+@item VAX C V2.x
+You must have Version 2.3 or 2.4; older ones won't work. Edit either
+@file{vmsbuild.com} or @file{descrip.mms} according to the comments in them.
+For @file{vmsbuild.com}, this just entails removing two @samp{!} delimiters.
+Also edit @file{config.h} (which is a copy of file @file{[.config]vms-conf.h})
+and comment out or delete the two lines @samp{#define __STDC__ 0} and
+@samp{#define VAXC_BUILTINS} near the end.@refill
+
+@item GNU C
+Edit @file{vmsbuild.com} or @file{descrip.mms}; the changes are different
+from those for VAX C V2.x, but equally straightforward. No changes to
+@file{config.h} should be needed.
+
+@item DEC C
+Edit @file{vmsbuild.com} or @file{descrip.mms} according to their comments.
+No changes to @file{config.h} should be needed.
+@end table
+
+@code{gawk} 2.15 has been tested under VAX/VMS 5.5-1 using VAX C V3.2,
+GNU C 1.40 and 2.3. It should work without modifications for VMS V4.6 and up.
+
+@node VMS Installation Details, VMS Running, VMS Compilation, VMS Installation
+@subsection Installing @code{gawk} on VMS
+
+To install @code{gawk}, all you need is a ``foreign'' command, which is
+a @code{DCL} symbol whose value begins with a dollar sign.
+
+@smallexample
+$ GAWK :== $device:[directory]GAWK
+@end smallexample
+
+@noindent
+(Substitute the actual location of @code{gawk.exe} for
+@samp{device:[directory]}.) The symbol should be placed in the
+@file{login.com} of any user who wishes to run @code{gawk},
+so that it will be defined every time the user logs on.
+Alternatively, the symbol may be placed in the system-wide
+@file{sylogin.com} procedure, which will allow all users
+to run @code{gawk}.@refill
+
+Optionally, the help entry can be loaded into a VMS help library:
+
+@smallexample
+$ LIBRARY/HELP SYS$HELP:HELPLIB [.VMS]GAWK.HLP
+@end smallexample
+
+@noindent
+(You may want to substitute a site-specific help library rather than
+the standard VMS library @samp{HELPLIB}.) After loading the help text,
+
+@c this is so tiny, but `should' be smallexample for consistency sake...
+@c I didn't because it was so short. --mew 29jan1992
+@example
+$ HELP GAWK
+@end example
+
+@noindent
+will provide information about both the @code{gawk} implementation and the
+@code{awk} programming language.
+
+The logical name @samp{AWK_LIBRARY} can designate a default location
+for @code{awk} program files. For the @samp{-f} option, if the specified
+filename has no device or directory path information in it, @code{gawk}
+will look in the current directory first, then in the directory specified
+by the translation of @samp{AWK_LIBRARY} if the file was not found.
+If after searching in both directories, the file still is not found,
+then @code{gawk} appends the suffix @samp{.awk} to the filename and the
+file search will be re-tried. If @samp{AWK_LIBRARY} is not defined, that
+portion of the file search will fail benignly.@refill
+
+@node VMS Running, VMS POSIX, VMS Installation Details, VMS Installation
+@subsection Running @code{gawk} on VMS
+
+Command line parsing and quoting conventions are significantly different
+on VMS, so examples in this manual or from other sources often need minor
+changes. They @emph{are} minor though, and all @code{awk} programs
+should run correctly.
+
+Here are a couple of trivial tests:
+
+@smallexample
+$ gawk -- "BEGIN @{print ""Hello, World!""@}"
+$ gawk -"W" version ! could also be -"W version" or "-W version"
+@end smallexample
+
+@noindent
+Note that upper-case and mixed-case text must be quoted.
+
+The VMS port of @code{gawk} includes a @code{DCL}-style interface in addition
+to the original shell-style interface (see the help entry for details).
+One side-effect of dual command line parsing is that if there is only a
+single parameter (as in the quoted string program above), the command
+becomes ambiguous. To work around this, the normally optional @samp{--}
+flag is required to force Unix style rather than @code{DCL} parsing. If any
+other dash-type options (or multiple parameters such as data files to be
+processed) are present, there is no ambiguity and @samp{--} can be omitted.
+
+The default search path when looking for @code{awk} program files specified
+by the @samp{-f} option is @code{"SYS$DISK:[],AWK_LIBRARY:"}. The logical
+name @samp{AWKPATH} can be used to override this default. The format
+of @samp{AWKPATH} is a comma-separated list of directory specifications.
+When defining it, the value should be quoted so that it retains a single
+translation, and not a multi-translation @code{RMS} searchlist.
+
+@node VMS POSIX, , VMS Running, VMS Installation
+@subsection Building and using @code{gawk} under VMS POSIX
+
+Ignore the instructions above, although @file{vms/gawk.hlp} should still
+be made available in a help library. Make sure that the two scripts,
+@file{configure} and @file{mungeconf}, are executable; use @samp{chmod +x}
+on them if necessary. Then execute the following commands:
+
+@smallexample
+$ POSIX
+psx> configure vms-posix
+psx> make awktab.c gawk
+@end smallexample
+
+@noindent
+The first command will construct files @file{config.h} and @file{Makefile}
+out of templates. The second command will compile and link @code{gawk}.
+Due to a @code{make} bug in VMS POSIX V1.0 and V1.1,
+the file @file{awktab.c} must be given as an explicit target or it will
+not be built and the final link step will fail. Ignore the warning
+@samp{"Could not find lib m in lib list"}; it is harmless, caused by the
+explicit use of @samp{-lm} as a linker option which is not needed
+under VMS POSIX. Under V1.1 (but not V1.0) a problem with the @code{yacc}
+skeleton @file{/etc/yyparse.c} will cause a compiler warning for
+@file{awktab.c}, followed by a linker warning about compilation warnings
+in the resulting object module. These warnings can be ignored.@refill
+
+Once built, @code{gawk} will work like any other shell utility. Unlike
+the normal VMS port of @code{gawk}, no special command line manipulation is
+needed in the VMS POSIX environment.
+
+@node MS-DOS Installation, Atari Installation, VMS Installation, Installation
+@section Installing @code{gawk} on MS-DOS
+
+@cindex installation, ms-dos
+The first step is to get all the files in the @code{gawk} distribution
+onto your PC. Move all the files from the @file{pc} directory into
+the main directory where the other files are. Edit the file
+@file{make.bat} so that it will be an acceptable MS-DOS batch file.
+This means making sure that all lines are terminated with the ASCII
+carriage return and line feed characters.
+restrictions.
+
+@code{gawk} has only been compiled with version 5.1 of the Microsoft
+C compiler. The file @file{make.bat} from the @file{pc} directory
+assumes that you have this compiler.
+
+Copy the file @file{setargv.obj} from the library directory where it
+resides to the @code{gawk} source code directory.
+
+Run @file{make.bat}. This will compile @code{gawk} for you, and link it.
+That's all there is to it!
+
+@node Atari Installation, , MS-DOS Installation, Installation
+@section Installing @code{gawk} on the Atari ST
+
+@c based on material from
+@c Michal Jaegermann <ntomczak@vm.ucs.ualberta.ca>
+
+@cindex installation, atari
+This section assumes that you are running TOS. It applies to other Atari
+models (STe, TT) as well.
+
+In order to use @code{gawk}, you need to have a shell, either text or
+graphics, that does not map all the characters of a command line to
+upper case. Maintaining case distinction in option flags is very
+important (@pxref{Command Line, ,Invoking @code{awk}}). Popular shells
+like @code{gulam} or @code{gemini} will work, as will newer versions of
+@code{desktop}. Support for I/O redirection is necessary to make it easy
+to import @code{awk} programs from other environments. Pipes are nice to have,
+but not vital.
+
+If you have received an executable version of @code{gawk}, place it,
+as usual, anywhere in your @code{PATH} where your shell will find it.
+
+While executing, @code{gawk} creates a number of temporary files.
+@code{gawk} looks for either of the environment variables @code{TEMP}
+or @code{TMPDIR}, in that order. If either one is found, its value
+is assumed to be a directory for temporary files. This directory
+must exist, and if you can spare the memory, it is a good idea to
+put it on a @sc{ram} drive. If neither @code{TEMP} nor @code{TMPDIR}
+are found, then @code{gawk} uses the current directory for its
+temporary files.
+
+The ST version of @code{gawk} searches for its program files as
+described in @ref{AWKPATH Variable, ,The @code{AWKPATH} Environment Variable}.
+On the ST, the default value for the @code{AWKPATH} variable is
+@code{@w{".,c:\lib\awk,c:\gnu\lib\awk"}}.
+The search path can be modified by explicitly setting @code{AWKPATH} to
+whatever you wish. Note that colons cannot be used on the ST to separate
+elements in the @code{AWKPATH} variable, since they have another, reserved,
+meaning. Instead, you must use a comma to separate elements in the path.
+If you are recompiling @code{gawk} on the ST, then you can choose a new
+default search path, by setting the value of @samp{DEFPATH} in the file
+@file{...\config\atari}. You may choose a different separator character
+by setting the value of @samp{ENVSEP} in the same file. The new values will
+be used when creating the header file @file{config.h}.@refill
+
+@ignore
+As a last resort, small
+adjustments can be made directly on the executable version of @code{gawk}
+using a binary editor.@refill
+@end ignore
+
+Although @code{awk} allows great flexibility in doing I/O redirections
+from within a program, this facility should be used with care on the ST.
+In some circumstances the OS routines for file handle pool processing
+lose track of certain events, causing the computer to crash, and requiring
+a reboot. Often a warm reboot is sufficient. Fortunately, this happens
+infrequently, and in rather esoteric situations. In particular, avoid
+having one part of an @code{awk} program using @code{print}
+statements explicitly redirected to @code{"/dev/stdout"}, while other
+@code{print} statements use the default standard output, and a
+calling shell has redirected standard output to a file.@refill
+@c whew!
+
+When @code{gawk} is compiled with the ST version of @code{gcc} and its
+usual libraries, it will accept both @samp{/} and @samp{\} as path separators.
+While this is convenient, it should be remembered that this removes one,
+technically legal, character (@samp{/}) from your file names, and that
+it may create problems for external programs, called via the @code{system()}
+function, which may not support this convention. Whenever it is possible
+that a file created by @code{gawk} will be used by some other program,
+use only backslashes. Also remember that in @code{awk}, backslashes in
+strings have to be doubled in order to get literal backslashes.
+
+The initial port of @code{gawk} to the ST was done with @code{gcc}.
+If you wish to recompile @code{gawk} from scratch, you will need to use
+a compiler that accepts @sc{ansi} standard C (such as @code{gcc}, Turbo C,
+or Prospero C). If @code{sizeof(int) != @w{sizeof(int *)}}, the correctness
+of the generated code depends heavily on the fact that all function calls
+have function prototypes in the current scope. If your compiler does
+not accept function prototypes, you will probably have to add a
+number of casts to the code.@refill
+
+If you are using @code{gcc}, make sure that you have up-to-date libraries.
+Older versions have problems with some library functions (@code{atan2()},
+@code{strftime()}, the @samp{%g} conversion in @code{sprintf()}) which
+may affect the operation of @code{gawk}.
+
+In the @file{atari} subdirectory of the @code{gawk} distribution is
+a version of the @code{system()} function that has been tested with
+@code{gulam} and @code{msh}; it should work with other shells as well.
+With @code{gulam}, it passes the string to be executed without spawning
+an extra copy of a shell. It is possible to replace this version of
+@code{system()} with a similar function from a library or from some other
+source if that version would be a better choice for the shell you prefer.
+
+The files needed to recompile @code{gawk} on the ST can be found in
+the @file{atari} directory. The provided files and instructions below
+assume that you have the GNU C compiler (@code{gcc}), the @code{gulam} shell,
+and an ST version of @code{sed}. The @file{Makefile} is set up to use
+@file{byacc} as a @file{yacc} replacement. With a different set of tools some
+adjustments and/or editing will be needed.@refill
+
+@code{cd} to the @file{atari} directory. Copy @file{Makefile.st} to
+@file{makefile} in the source (parent) directory. Possibly adjust
+@file{../config/atari} to suit your system. Execute the script @file{mkconf.g}
+which will create the header file @file{../config.h}. Go back to the source
+directory. If you are not using @code{gcc}, check the file @file{missing.c}.
+It may be necessary to change forward slashes in the references to files
+from the @file{atari} subdirectory into backslashes. Type @code{make} and
+enjoy.@refill
+
+Compilation with @code{gcc} of some of the bigger modules, like
+@file{awk_tab.c}, may require a full four megabytes of memory. On smaller
+machines you would need to cut down on optimizations, or you would have to
+switch to another, less memory hungry, compiler.@refill
+
+@node Gawk Summary, Sample Program, Installation, Top
+@appendix @code{gawk} Summary
+
+This appendix provides a brief summary of the @code{gawk} command line and the
+@code{awk} language. It is designed to serve as ``quick reference.'' It is
+therefore terse, but complete.
+
+@menu
+* Command Line Summary:: Recapitulation of the command line.
+* Language Summary:: A terse review of the language.
+* Variables/Fields:: Variables, fields, and arrays.
+* Rules Summary:: Patterns and Actions, and their
+ component parts.
+* Functions Summary:: Defining and calling functions.
+* Historical Features:: Some undocumented but supported ``features''.
+@end menu
+
+@node Command Line Summary, Language Summary, Gawk Summary, Gawk Summary
+@appendixsec Command Line Options Summary
+
+The command line consists of options to @code{gawk} itself, the
+@code{awk} program text (if not supplied via the @samp{-f} option), and
+values to be made available in the @code{ARGC} and @code{ARGV}
+predefined @code{awk} variables:
+
+@example
+awk @r{[@var{POSIX or GNU style options}]} -f source-file @r{[@code{--}]} @var{file} @dots{}
+awk @r{[@var{POSIX or GNU style options}]} @r{[@code{--}]} '@var{program}' @var{file} @dots{}
+@end example
+
+The options that @code{gawk} accepts are:
+
+@table @code
+@item -F @var{fs}
+@itemx --field-separator=@var{fs}
+Use @var{fs} for the input field separator (the value of the @code{FS}
+predefined variable).
+
+@item -f @var{program-file}
+@itemx --file=@var{program-file}
+Read the @code{awk} program source from the file @var{program-file}, instead
+of from the first command line argument.
+
+@item -v @var{var}=@var{val}
+@itemx --assign=@var{var}=@var{val}
+Assign the variable @var{var} the value @var{val} before program execution
+begins.
+
+@item -W compat
+@itemx --compat
+Specifies compatibility mode, in which @code{gawk} extensions are turned
+off.
+
+@item -W copyleft
+@itemx -W copyright
+@itemx --copyleft
+@itemx --copyright
+Print the short version of the General Public License on the error
+output. This option may disappear in a future version of @code{gawk}.
+
+@item -W help
+@itemx -W usage
+@itemx --help
+@itemx --usage
+Print a relatively short summary of the available options on the error output.
+
+@item -W lint
+@itemx --lint
+Give warnings about dubious or non-portable @code{awk} constructs.
+
+@item -W posix
+@itemx --posix
+Specifies @sc{posix} compatibility mode, in which @code{gawk} extensions
+are turned off and additional restrictions apply.
+
+@item -W source=@var{program-text}
+@itemx --source=@var{program-text}
+Use @var{program-text} as @code{awk} program source code. This option allows
+mixing command line source code with source code from files, and is
+particularly useful for mixing command line programs with library functions.
+
+@item -W version
+@itemx --version
+Print version information for this particular copy of @code{gawk} on the error
+output. This option may disappear in a future version of @code{gawk}.
+
+@item --
+Signal the end of options. This is useful to allow further arguments to the
+@code{awk} program itself to start with a @samp{-}. This is mainly for
+consistency with the argument parsing conventions of @sc{posix}.
+@end table
+
+Any other options are flagged as invalid, but are otherwise ignored.
+@xref{Command Line, ,Invoking @code{awk}}, for more details.
+
+@node Language Summary, Variables/Fields, Command Line Summary, Gawk Summary
+@appendixsec Language Summary
+
+An @code{awk} program consists of a sequence of pattern-action statements
+and optional function definitions.
+
+@example
+@var{pattern} @{ @var{action statements} @}
+
+function @var{name}(@var{parameter list}) @{ @var{action statements} @}
+@end example
+
+@code{gawk} first reads the program source from the
+@var{program-file}(s) if specified, or from the first non-option
+argument on the command line. The @samp{-f} option may be used multiple
+times on the command line. @code{gawk} reads the program text from all
+the @var{program-file} files, effectively concatenating them in the
+order they are specified. This is useful for building libraries of
+@code{awk} functions, without having to include them in each new
+@code{awk} program that uses them. To use a library function in a file
+from a program typed in on the command line, specify @samp{-f /dev/tty};
+then type your program, and end it with a @kbd{Control-d}.
+@xref{Command Line, ,Invoking @code{awk}}.@refill
+
+The environment variable @code{AWKPATH} specifies a search path to use
+when finding source files named with the @samp{-f} option. The default
+path, which is
+@samp{.:/usr/lib/awk:/usr/local/lib/awk} is used if @code{AWKPATH} is not set.
+If a file name given to the @samp{-f} option contains a @samp{/} character,
+no path search is performed.
+@xref{AWKPATH Variable, ,The @code{AWKPATH} Environment Variable},
+for a full description of the @code{AWKPATH} environment variable.@refill
+
+@code{gawk} compiles the program into an internal form, and then proceeds to
+read each file named in the @code{ARGV} array. If there are no files named
+on the command line, @code{gawk} reads the standard input.
+
+If a ``file'' named on the command line has the form
+@samp{@var{var}=@var{val}}, it is treated as a variable assignment: the
+variable @var{var} is assigned the value @var{val}.
+If any of the files have a value that is the null string, that
+element in the list is skipped.@refill
+
+For each line in the input, @code{gawk} tests to see if it matches any
+@var{pattern} in the @code{awk} program. For each pattern that the line
+matches, the associated @var{action} is executed.
+
+@node Variables/Fields, Rules Summary, Language Summary, Gawk Summary
+@appendixsec Variables and Fields
+
+@code{awk} variables are dynamic; they come into existence when they are
+first used. Their values are either floating-point numbers or strings.
+@code{awk} also has one-dimension arrays; multiple-dimensional arrays
+may be simulated. There are several predefined variables that
+@code{awk} sets as a program runs; these are summarized below.
+
+@menu
+* Fields Summary:: Input field splitting.
+* Built-in Summary:: @code{awk}'s built-in variables.
+* Arrays Summary:: Using arrays.
+* Data Type Summary:: Values in @code{awk} are numbers or strings.
+@end menu
+
+@node Fields Summary, Built-in Summary, Variables/Fields, Variables/Fields
+@appendixsubsec Fields
+
+As each input line is read, @code{gawk} splits the line into
+@var{fields}, using the value of the @code{FS} variable as the field
+separator. If @code{FS} is a single character, fields are separated by
+that character. Otherwise, @code{FS} is expected to be a full regular
+expression. In the special case that @code{FS} is a single blank,
+fields are separated by runs of blanks and/or tabs. Note that the value
+of @code{IGNORECASE} (@pxref{Case-sensitivity, ,Case-sensitivity in Matching})
+also affects how fields are split when @code{FS} is a regular expression.@refill
+
+Each field in the input line may be referenced by its position, @code{$1},
+@code{$2}, and so on. @code{$0} is the whole line. The value of a field may
+be assigned to as well. Field numbers need not be constants:
+
+@example
+n = 5
+print $n
+@end example
+
+@noindent
+prints the fifth field in the input line. The variable @code{NF} is set to
+the total number of fields in the input line.
+
+References to nonexistent fields (i.e., fields after @code{$NF}) return
+the null-string. However, assigning to a nonexistent field (e.g.,
+@code{$(NF+2) = 5}) increases the value of @code{NF}, creates any
+intervening fields with the null string as their value, and causes the
+value of @code{$0} to be recomputed, with the fields being separated by
+the value of @code{OFS}.@refill
+
+@xref{Reading Files, ,Reading Input Files}, for a full description of the
+way @code{awk} defines and uses fields.
+
+@node Built-in Summary, Arrays Summary, Fields Summary, Variables/Fields
+@appendixsubsec Built-in Variables
+
+@code{awk}'s built-in variables are:
+
+@table @code
+@item ARGC
+The number of command line arguments (not including options or the
+@code{awk} program itself).
+
+@item ARGIND
+The index in @code{ARGV} of the current file being processed.
+It is always true that @samp{FILENAME == ARGV[ARGIND]}.
+
+@item ARGV
+The array of command line arguments. The array is indexed from 0 to
+@code{ARGC} @minus{} 1. Dynamically changing the contents of @code{ARGV}
+can control the files used for data.@refill
+
+@item CONVFMT
+The conversion format to use when converting numbers to strings.
+
+@item FIELDWIDTHS
+A space separated list of numbers describing the fixed-width input data.
+
+@item ENVIRON
+An array containing the values of the environment variables. The array
+is indexed by variable name, each element being the value of that
+variable. Thus, the environment variable @code{HOME} would be in
+@code{ENVIRON["HOME"]}. Its value might be @file{/u/close}.
+
+Changing this array does not affect the environment seen by programs
+which @code{gawk} spawns via redirection or the @code{system} function.
+(This may change in a future version of @code{gawk}.)
+
+Some operating systems do not have environment variables.
+The array @code{ENVIRON} is empty when running on these systems.
+
+@item ERRNO
+The system error message when an error occurs using @code{getline}
+or @code{close}.
+
+@item FILENAME
+The name of the current input file. If no files are specified on the command
+line, the value of @code{FILENAME} is @samp{-}.
+
+@item FNR
+The input record number in the current input file.
+
+@item FS
+The input field separator, a blank by default.
+
+@item IGNORECASE
+The case-sensitivity flag for regular expression operations. If
+@code{IGNORECASE} has a nonzero value, then pattern matching in rules,
+field splitting with @code{FS}, regular expression matching with
+@samp{~} and @samp{!~}, and the @code{gsub}, @code{index}, @code{match},
+@code{split} and @code{sub} predefined functions all ignore case
+when doing regular expression operations.@refill
+
+@item NF
+The number of fields in the current input record.
+
+@item NR
+The total number of input records seen so far.
+
+@item OFMT
+The output format for numbers for the @code{print} statement,
+@code{"%.6g"} by default.
+
+@item OFS
+The output field separator, a blank by default.
+
+@item ORS
+The output record separator, by default a newline.
+
+@item RS
+The input record separator, by default a newline. @code{RS} is exceptional
+in that only the first character of its string value is used for separating
+records. If @code{RS} is set to the null string, then records are separated by
+blank lines. When @code{RS} is set to the null string, then the newline
+character always acts as a field separator, in addition to whatever value
+@code{FS} may have.@refill
+
+@item RSTART
+The index of the first character matched by @code{match}; 0 if no match.
+
+@item RLENGTH
+The length of the string matched by @code{match}; @minus{}1 if no match.
+
+@item SUBSEP
+The string used to separate multiple subscripts in array elements, by
+default @code{"\034"}.
+@end table
+
+@xref{Built-in Variables}, for more information.
+
+@node Arrays Summary, Data Type Summary, Built-in Summary, Variables/Fields
+@appendixsubsec Arrays
+
+Arrays are subscripted with an expression between square brackets
+(@samp{[} and @samp{]}). Array subscripts are @emph{always} strings;
+numbers are converted to strings as necessary, following the standard
+conversion rules
+(@pxref{Conversion, ,Conversion of Strings and Numbers}).@refill
+
+If you use multiple expressions separated by commas inside the square
+brackets, then the array subscript is a string consisting of the
+concatenation of the individual subscript values, converted to strings,
+separated by the subscript separator (the value of @code{SUBSEP}).
+
+The special operator @code{in} may be used in an @code{if} or
+@code{while} statement to see if an array has an index consisting of a
+particular value.
+
+@example
+if (val in array)
+ print array[val]
+@end example
+
+If the array has multiple subscripts, use @code{(i, j, @dots{}) in array}
+to test for existence of an element.
+
+The @code{in} construct may also be used in a @code{for} loop to iterate
+over all the elements of an array.
+@xref{Scanning an Array, ,Scanning all Elements of an Array}.@refill
+
+An element may be deleted from an array using the @code{delete} statement.
+
+@xref{Arrays, ,Arrays in @code{awk}}, for more detailed information.
+
+@node Data Type Summary, , Arrays Summary, Variables/Fields
+@appendixsubsec Data Types
+
+The value of an @code{awk} expression is always either a number
+or a string.
+
+Certain contexts (such as arithmetic operators) require numeric
+values. They convert strings to numbers by interpreting the text
+of the string as a numeral. If the string does not look like a
+numeral, it converts to 0.
+
+Certain contexts (such as concatenation) require string values.
+They convert numbers to strings by effectively printing them
+with @code{sprintf}.
+@xref{Conversion, ,Conversion of Strings and Numbers}, for the details.@refill
+
+To force conversion of a string value to a number, simply add 0
+to it. If the value you start with is already a number, this
+does not change it.
+
+To force conversion of a numeric value to a string, concatenate it with
+the null string.
+
+The @code{awk} language defines comparisons as being done numerically if
+both operands are numeric, or if one is numeric and the other is a numeric
+string. Otherwise one or both operands are converted to strings and a
+string comparison is performed.
+
+Uninitialized variables have the string value @code{""} (the null, or
+empty, string). In contexts where a number is required, this is
+equivalent to 0.
+
+@xref{Variables}, for more information on variable naming and initialization;
+@pxref{Conversion, ,Conversion of Strings and Numbers}, for more information
+on how variable values are interpreted.@refill
+
+@node Rules Summary, Functions Summary, Variables/Fields, Gawk Summary
+@appendixsec Patterns and Actions
+
+@menu
+* Pattern Summary:: Quick overview of patterns.
+* Regexp Summary:: Quick overview of regular expressions.
+* Actions Summary:: Quick overview of actions.
+@end menu
+
+An @code{awk} program is mostly composed of rules, each consisting of a
+pattern followed by an action. The action is enclosed in @samp{@{} and
+@samp{@}}. Either the pattern may be missing, or the action may be
+missing, but, of course, not both. If the pattern is missing, the
+action is executed for every single line of input. A missing action is
+equivalent to this action,
+
+@example
+@{ print @}
+@end example
+
+@noindent
+which prints the entire line.
+
+Comments begin with the @samp{#} character, and continue until the end of the
+line. Blank lines may be used to separate statements. Normally, a statement
+ends with a newline, however, this is not the case for lines ending in a
+@samp{,}, @samp{@{}, @samp{?}, @samp{:}, @samp{&&}, or @samp{||}. Lines
+ending in @code{do} or @code{else} also have their statements automatically
+continued on the following line. In other cases, a line can be continued by
+ending it with a @samp{\}, in which case the newline is ignored.@refill
+
+Multiple statements may be put on one line by separating them with a @samp{;}.
+This applies to both the statements within the action part of a rule (the
+usual case), and to the rule statements.
+
+@xref{Comments, ,Comments in @code{awk} Programs}, for information on
+@code{awk}'s commenting convention;
+@pxref{Statements/Lines, ,@code{awk} Statements versus Lines}, for a
+description of the line continuation mechanism in @code{awk}.@refill
+
+@node Pattern Summary, Regexp Summary, Rules Summary, Rules Summary
+@appendixsubsec Patterns
+
+@code{awk} patterns may be one of the following:
+
+@example
+/@var{regular expression}/
+@var{relational expression}
+@var{pattern} && @var{pattern}
+@var{pattern} || @var{pattern}
+@var{pattern} ? @var{pattern} : @var{pattern}
+(@var{pattern})
+! @var{pattern}
+@var{pattern1}, @var{pattern2}
+BEGIN
+END
+@end example
+
+@code{BEGIN} and @code{END} are two special kinds of patterns that are not
+tested against the input. The action parts of all @code{BEGIN} rules are
+merged as if all the statements had been written in a single @code{BEGIN}
+rule. They are executed before any of the input is read. Similarly, all the
+@code{END} rules are merged, and executed when all the input is exhausted (or
+when an @code{exit} statement is executed). @code{BEGIN} and @code{END}
+patterns cannot be combined with other patterns in pattern expressions.
+@code{BEGIN} and @code{END} rules cannot have missing action parts.@refill
+
+For @samp{/@var{regular-expression}/} patterns, the associated statement is
+executed for each input line that matches the regular expression. Regular
+expressions are extensions of those in @code{egrep}, and are summarized below.
+
+A @var{relational expression} may use any of the operators defined below in
+the section on actions. These generally test whether certain fields match
+certain regular expressions.
+
+The @samp{&&}, @samp{||}, and @samp{!} operators are logical ``and,''
+logical ``or,'' and logical ``not,'' respectively, as in C. They do
+short-circuit evaluation, also as in C, and are used for combining more
+primitive pattern expressions. As in most languages, parentheses may be
+used to change the order of evaluation.
+
+The @samp{?:} operator is like the same operator in C. If the first
+pattern matches, then the second pattern is matched against the input
+record; otherwise, the third is matched. Only one of the second and
+third patterns is matched.
+
+The @samp{@var{pattern1}, @var{pattern2}} form of a pattern is called a
+range pattern. It matches all input lines starting with a line that
+matches @var{pattern1}, and continuing until a line that matches
+@var{pattern2}, inclusive. A range pattern cannot be used as an operand
+to any of the pattern operators.
+
+@xref{Patterns}, for a full description of the pattern part of @code{awk}
+rules.
+
+@node Regexp Summary, Actions Summary, Pattern Summary, Rules Summary
+@appendixsubsec Regular Expressions
+
+Regular expressions are the extended kind found in @code{egrep}.
+They are composed of characters as follows:
+
+@table @code
+@item @var{c}
+matches the character @var{c} (assuming @var{c} is a character with no
+special meaning in regexps).
+
+@item \@var{c}
+matches the literal character @var{c}.
+
+@item .
+matches any character except newline.
+
+@item ^
+matches the beginning of a line or a string.
+
+@item $
+matches the end of a line or a string.
+
+@item [@var{abc}@dots{}]
+matches any of the characters @var{abc}@dots{} (character class).
+
+@item [^@var{abc}@dots{}]
+matches any character except @var{abc}@dots{} and newline (negated
+character class).
+
+@item @var{r1}|@var{r2}
+matches either @var{r1} or @var{r2} (alternation).
+
+@item @var{r1r2}
+matches @var{r1}, and then @var{r2} (concatenation).
+
+@item @var{r}+
+matches one or more @var{r}'s.
+
+@item @var{r}*
+matches zero or more @var{r}'s.
+
+@item @var{r}?
+matches zero or one @var{r}'s.
+
+@item (@var{r})
+matches @var{r} (grouping).
+@end table
+
+@xref{Regexp, ,Regular Expressions as Patterns}, for a more detailed
+explanation of regular expressions.
+
+The escape sequences allowed in string constants are also valid in
+regular expressions (@pxref{Constants, ,Constant Expressions}).
+
+@node Actions Summary, , Regexp Summary, Rules Summary
+@appendixsubsec Actions
+
+Action statements are enclosed in braces, @samp{@{} and @samp{@}}.
+Action statements consist of the usual assignment, conditional, and looping
+statements found in most languages. The operators, control statements,
+and input/output statements available are patterned after those in C.
+
+@menu
+* Operator Summary:: @code{awk} operators.
+* Control Flow Summary:: The control statements.
+* I/O Summary:: The I/O statements.
+* Printf Summary:: A summary of @code{printf}.
+* Special File Summary:: Special file names interpreted internally.
+* Numeric Functions Summary:: Built-in numeric functions.
+* String Functions Summary:: Built-in string functions.
+* Time Functions Summary:: Built-in time functions.
+* String Constants Summary:: Escape sequences in strings.
+@end menu
+
+@node Operator Summary, Control Flow Summary, Actions Summary, Actions Summary
+@appendixsubsubsec Operators
+
+The operators in @code{awk}, in order of increasing precedence, are:
+
+@table @code
+@item = += -= *= /= %= ^=
+Assignment. Both absolute assignment (@code{@var{var}=@var{value}})
+and operator assignment (the other forms) are supported.
+
+@item ?:
+A conditional expression, as in C. This has the form @code{@var{expr1} ?
+@var{expr2} : @var{expr3}}. If @var{expr1} is true, the value of the
+expression is @var{expr2}; otherwise it is @var{expr3}. Only one of
+@var{expr2} and @var{expr3} is evaluated.@refill
+
+@item ||
+Logical ``or''.
+
+@item &&
+Logical ``and''.
+
+@item ~ !~
+Regular expression match, negated match.
+
+@item < <= > >= != ==
+The usual relational operators.
+
+@item @var{blank}
+String concatenation.
+
+@item + -
+Addition and subtraction.
+
+@item * / %
+Multiplication, division, and modulus.
+
+@item + - !
+Unary plus, unary minus, and logical negation.
+
+@item ^
+Exponentiation (@samp{**} may also be used, and @samp{**=} for the assignment
+operator, but they are not specified in the @sc{posix} standard).
+
+@item ++ --
+Increment and decrement, both prefix and postfix.
+
+@item $
+Field reference.
+@end table
+
+@xref{Expressions, ,Expressions as Action Statements}, for a full
+description of all the operators listed above.
+@xref{Fields, ,Examining Fields}, for a description of the field
+reference operator.@refill
+
+@node Control Flow Summary, I/O Summary, Operator Summary, Actions Summary
+@appendixsubsubsec Control Statements
+
+The control statements are as follows:
+
+@example
+if (@var{condition}) @var{statement} @r{[} else @var{statement} @r{]}
+while (@var{condition}) @var{statement}
+do @var{statement} while (@var{condition})
+for (@var{expr1}; @var{expr2}; @var{expr3}) @var{statement}
+for (@var{var} in @var{array}) @var{statement}
+break
+continue
+delete @var{array}[@var{index}]
+exit @r{[} @var{expression} @r{]}
+@{ @var{statements} @}
+@end example
+
+@xref{Statements, ,Control Statements in Actions}, for a full description
+of all the control statements listed above.
+
+@node I/O Summary, Printf Summary, Control Flow Summary, Actions Summary
+@appendixsubsubsec I/O Statements
+
+The input/output statements are as follows:
+
+@table @code
+@item getline
+Set @code{$0} from next input record; set @code{NF}, @code{NR}, @code{FNR}.
+
+@item getline <@var{file}
+Set @code{$0} from next record of @var{file}; set @code{NF}.
+
+@item getline @var{var}
+Set @var{var} from next input record; set @code{NF}, @code{FNR}.
+
+@item getline @var{var} <@var{file}
+Set @var{var} from next record of @var{file}.
+
+@item next
+Stop processing the current input record. The next input record is read and
+processing starts over with the first pattern in the @code{awk} program.
+If the end of the input data is reached, the @code{END} rule(s), if any,
+are executed.
+
+@item next file
+Stop processing the current input file. The next input record read comes
+from the next input file. @code{FILENAME} is updated, @code{FNR} is set to 1,
+and processing starts over with the first pattern in the @code{awk} program.
+If the end of the input data is reached, the @code{END} rule(s), if any,
+are executed.
+
+@item print
+Prints the current record.
+
+@item print @var{expr-list}
+Prints expressions.
+
+@item print @var{expr-list} > @var{file}
+Prints expressions on @var{file}.
+
+@item printf @var{fmt, expr-list}
+Format and print.
+
+@item printf @var{fmt, expr-list} > file
+Format and print on @var{file}.
+@end table
+
+Other input/output redirections are also allowed. For @code{print} and
+@code{printf}, @samp{>> @var{file}} appends output to the @var{file},
+and @samp{| @var{command}} writes on a pipe. In a similar fashion,
+@samp{@var{command} | getline} pipes input into @code{getline}.
+@code{getline} returns 0 on end of file, and @minus{}1 on an error.@refill
+
+@xref{Getline, ,Explicit Input with @code{getline}}, for a full description
+of the @code{getline} statement.
+@xref{Printing, ,Printing Output}, for a full description of @code{print} and
+@code{printf}. Finally, @pxref{Next Statement, ,The @code{next} Statement},
+for a description of how the @code{next} statement works.@refill
+
+@node Printf Summary, Special File Summary, I/O Summary, Actions Summary
+@appendixsubsubsec @code{printf} Summary
+
+The @code{awk} @code{printf} statement and @code{sprintf} function
+accept the following conversion specification formats:
+
+@table @code
+@item %c
+An ASCII character. If the argument used for @samp{%c} is numeric, it is
+treated as a character and printed. Otherwise, the argument is assumed to
+be a string, and the only first character of that string is printed.
+
+@item %d
+@itemx %i
+A decimal number (the integer part).
+
+@item %e
+A floating point number of the form
+@samp{@r{[}-@r{]}d.ddddddE@r{[}+-@r{]}dd}.@refill
+
+@item %f
+A floating point number of the form
+@r{[}@code{-}@r{]}@code{ddd.dddddd}.
+
+@item %g
+Use @samp{%e} or @samp{%f} conversion, whichever produces a shorter string,
+with nonsignificant zeros suppressed.
+
+@item %o
+An unsigned octal number (again, an integer).
+
+@item %s
+A character string.
+
+@item %x
+An unsigned hexadecimal number (an integer).
+
+@item %X
+Like @samp{%x}, except use @samp{A} through @samp{F} instead of @samp{a}
+through @samp{f} for decimal 10 through 15.@refill
+
+@item %%
+A single @samp{%} character; no argument is converted.
+@end table
+
+There are optional, additional parameters that may lie between the @samp{%}
+and the control letter:
+
+@table @code
+@item -
+The expression should be left-justified within its field.
+
+@item @var{width}
+The field should be padded to this width. If @var{width} has a leading zero,
+then the field is padded with zeros. Otherwise it is padded with blanks.
+
+@item .@var{prec}
+A number indicating the maximum width of strings or digits to the right
+of the decimal point.
+@end table
+
+Either or both of the @var{width} and @var{prec} values may be specified
+as @samp{*}. In that case, the particular value is taken from the argument
+list.
+
+@xref{Printf, ,Using @code{printf} Statements for Fancier Printing}, for
+examples and for a more detailed description.
+
+@node Special File Summary, Numeric Functions Summary, Printf Summary, Actions Summary
+@appendixsubsubsec Special File Names
+
+When doing I/O redirection from either @code{print} or @code{printf} into a
+file, or via @code{getline} from a file, @code{gawk} recognizes certain special
+file names internally. These file names allow access to open file descriptors
+inherited from @code{gawk}'s parent process (usually the shell). The
+file names are:
+
+@table @file
+@item /dev/stdin
+The standard input.
+
+@item /dev/stdout
+The standard output.
+
+@item /dev/stderr
+The standard error output.
+
+@item /dev/fd/@var{n}
+The file denoted by the open file descriptor @var{n}.
+@end table
+
+In addition the following files provide process related information
+about the running @code{gawk} program.
+
+@table @file
+@item /dev/pid
+Reading this file returns the process ID of the current process,
+in decimal, terminated with a newline.
+
+@item /dev/ppid
+Reading this file returns the parent process ID of the current process,
+in decimal, terminated with a newline.
+
+@item /dev/pgrpid
+Reading this file returns the process group ID of the current process,
+in decimal, terminated with a newline.
+
+@item /dev/user
+Reading this file returns a single record terminated with a newline.
+The fields are separated with blanks. The fields represent the
+following information:
+
+@table @code
+@item $1
+The value of the @code{getuid} system call.
+
+@item $2
+The value of the @code{geteuid} system call.
+
+@item $3
+The value of the @code{getgid} system call.
+
+@item $4
+The value of the @code{getegid} system call.
+@end table
+
+If there are any additional fields, they are the group IDs returned by
+@code{getgroups} system call.
+(Multiple groups may not be supported on all systems.)@refill
+@end table
+
+@noindent
+These file names may also be used on the command line to name data files.
+These file names are only recognized internally if you do not
+actually have files by these names on your system.
+
+@xref{Special Files, ,Standard I/O Streams}, for a longer description that
+provides the motivation for this feature.
+
+@node Numeric Functions Summary, String Functions Summary, Special File Summary, Actions Summary
+@appendixsubsubsec Numeric Functions
+
+@code{awk} has the following predefined arithmetic functions:
+
+@table @code
+@item atan2(@var{y}, @var{x})
+returns the arctangent of @var{y/x} in radians.
+
+@item cos(@var{expr})
+returns the cosine in radians.
+
+@item exp(@var{expr})
+the exponential function.
+
+@item int(@var{expr})
+truncates to integer.
+
+@item log(@var{expr})
+the natural logarithm function.
+
+@item rand()
+returns a random number between 0 and 1.
+
+@item sin(@var{expr})
+returns the sine in radians.
+
+@item sqrt(@var{expr})
+the square root function.
+
+@item srand(@var{expr})
+use @var{expr} as a new seed for the random number generator. If no @var{expr}
+is provided, the time of day is used. The return value is the previous
+seed for the random number generator.
+@end table
+
+@node String Functions Summary, Time Functions Summary, Numeric Functions Summary, Actions Summary
+@appendixsubsubsec String Functions
+
+@code{awk} has the following predefined string functions:
+
+@table @code
+@item gsub(@var{r}, @var{s}, @var{t})
+for each substring matching the regular expression @var{r} in the string
+@var{t}, substitute the string @var{s}, and return the number of substitutions.
+If @var{t} is not supplied, use @code{$0}.
+
+@item index(@var{s}, @var{t})
+returns the index of the string @var{t} in the string @var{s}, or 0 if
+@var{t} is not present.
+
+@item length(@var{s})
+returns the length of the string @var{s}. The length of @code{$0}
+is returned if no argument is supplied.
+
+@item match(@var{s}, @var{r})
+returns the position in @var{s} where the regular expression @var{r}
+occurs, or 0 if @var{r} is not present, and sets the values of @code{RSTART}
+and @code{RLENGTH}.
+
+@item split(@var{s}, @var{a}, @var{r})
+splits the string @var{s} into the array @var{a} on the regular expression
+@var{r}, and returns the number of fields. If @var{r} is omitted, @code{FS}
+is used instead.
+
+@item sprintf(@var{fmt}, @var{expr-list})
+prints @var{expr-list} according to @var{fmt}, and returns the resulting string.
+
+@item sub(@var{r}, @var{s}, @var{t})
+this is just like @code{gsub}, but only the first matching substring is
+replaced.
+
+@item substr(@var{s}, @var{i}, @var{n})
+returns the @var{n}-character substring of @var{s} starting at @var{i}.
+If @var{n} is omitted, the rest of @var{s} is used.
+
+@item tolower(@var{str})
+returns a copy of the string @var{str}, with all the upper-case characters in
+@var{str} translated to their corresponding lower-case counterparts.
+Nonalphabetic characters are left unchanged.
+
+@item toupper(@var{str})
+returns a copy of the string @var{str}, with all the lower-case characters in
+@var{str} translated to their corresponding upper-case counterparts.
+Nonalphabetic characters are left unchanged.
+
+@item system(@var{cmd-line})
+Execute the command @var{cmd-line}, and return the exit status.
+@end table
+
+@node Time Functions Summary, String Constants Summary, String Functions Summary, Actions Summary
+@appendixsubsubsec Built-in time functions
+
+The following two functions are available for getting the current
+time of day, and for formatting time stamps.
+
+@table @code
+@item systime()
+returns the current time of day as the number of seconds since a particular
+epoch (Midnight, January 1, 1970 @sc{utc}, on @sc{posix} systems).
+
+@item strftime(@var{format}, @var{timestamp})
+formats @var{timestamp} according to the specification in @var{format}.
+The current time of day is used if no @var{timestamp} is supplied.
+@xref{Time Functions, ,Functions for Dealing with Time Stamps}, for the
+details on the conversion specifiers that @code{strftime} accepts.@refill
+@end table
+
+@iftex
+@xref{Built-in, ,Built-in Functions}, for a description of all of
+@code{awk}'s built-in functions.
+@end iftex
+
+@node String Constants Summary, , Time Functions Summary, Actions Summary
+@appendixsubsubsec String Constants
+
+String constants in @code{awk} are sequences of characters enclosed
+between double quotes (@code{"}). Within strings, certain @dfn{escape sequences}
+are recognized, as in C. These are:
+
+@table @code
+@item \\
+A literal backslash.
+
+@item \a
+The ``alert'' character; usually the ASCII BEL character.
+
+@item \b
+Backspace.
+
+@item \f
+Formfeed.
+
+@item \n
+Newline.
+
+@item \r
+Carriage return.
+
+@item \t
+Horizontal tab.
+
+@item \v
+Vertical tab.
+
+@item \x@var{hex digits}
+The character represented by the string of hexadecimal digits following
+the @samp{\x}. As in @sc{ansi} C, all following hexadecimal digits are
+considered part of the escape sequence. (This feature should tell us
+something about language design by committee.) E.g., @code{"\x1B"} is a
+string containing the ASCII ESC (escape) character. (The @samp{\x}
+escape sequence is not in @sc{posix} @code{awk}.)
+
+@item \@var{ddd}
+The character represented by the 1-, 2-, or 3-digit sequence of octal
+digits. Thus, @code{"\033"} is also a string containing the ASCII ESC
+(escape) character.
+
+@item \@var{c}
+The literal character @var{c}.
+@end table
+
+The escape sequences may also be used inside constant regular expressions
+(e.g., the regexp @code{@w{/[@ \t\f\n\r\v]/}} matches whitespace
+characters).@refill
+
+@xref{Constants, ,Constant Expressions}.
+
+@node Functions Summary, Historical Features, Rules Summary, Gawk Summary
+@appendixsec Functions
+
+Functions in @code{awk} are defined as follows:
+
+@example
+function @var{name}(@var{parameter list}) @{ @var{statements} @}
+@end example
+
+Actual parameters supplied in the function call are used to instantiate
+the formal parameters declared in the function. Arrays are passed by
+reference, other variables are passed by value.
+
+If there are fewer arguments passed than there are names in @var{parameter-list},
+the extra names are given the null string as value. Extra names have the
+effect of local variables.
+
+The open-parenthesis in a function call of a user-defined function must
+immediately follow the function name, without any intervening white space.
+This is to avoid a syntactic ambiguity with the concatenation operator.
+
+The word @code{func} may be used in place of @code{function} (but not in
+@sc{posix} @code{awk}).
+
+Use the @code{return} statement to return a value from a function.
+
+@xref{User-defined, ,User-defined Functions}, for a more complete description.
+
+@node Historical Features, , Functions Summary, Gawk Summary
+@appendixsec Historical Features
+
+There are two features of historical @code{awk} implementations that
+@code{gawk} supports. First, it is possible to call the @code{length}
+built-in function not only with no arguments, but even without parentheses!
+
+@example
+a = length
+@end example
+
+@noindent
+is the same as either of
+
+@example
+a = length()
+a = length($0)
+@end example
+
+@noindent
+This feature is marked as ``deprecated'' in the @sc{posix} standard, and
+@code{gawk} will issue a warning about its use if @samp{-W lint} is
+specified on the command line.
+
+The other feature is the use of the @code{continue} statement outside the
+body of a @code{while}, @code{for}, or @code{do} loop. Traditional
+@code{awk} implementations have treated such usage as equivalent to the
+@code{next} statement. @code{gawk} will support this usage if @samp{-W posix}
+has not been specified.
+
+@node Sample Program, Bugs, Gawk Summary, Top
+@appendix Sample Program
+
+The following example is a complete @code{awk} program, which prints
+the number of occurrences of each word in its input. It illustrates the
+associative nature of @code{awk} arrays by using strings as subscripts. It
+also demonstrates the @samp{for @var{x} in @var{array}} construction.
+Finally, it shows how @code{awk} can be used in conjunction with other
+utility programs to do a useful task of some complexity with a minimum of
+effort. Some explanations follow the program listing.@refill
+
+@example
+awk '
+# Print list of word frequencies
+@{
+ for (i = 1; i <= NF; i++)
+ freq[$i]++
+@}
+
+END @{
+ for (word in freq)
+ printf "%s\t%d\n", word, freq[word]
+@}'
+@end example
+
+The first thing to notice about this program is that it has two rules. The
+first rule, because it has an empty pattern, is executed on every line of
+the input. It uses @code{awk}'s field-accessing mechanism
+(@pxref{Fields, ,Examining Fields}) to pick out the individual words from
+the line, and the built-in variable @code{NF} (@pxref{Built-in Variables})
+to know how many fields are available.@refill
+
+For each input word, an element of the array @code{freq} is incremented to
+reflect that the word has been seen an additional time.@refill
+
+The second rule, because it has the pattern @code{END}, is not executed
+until the input has been exhausted. It prints out the contents of the
+@code{freq} table that has been built up inside the first action.@refill
+
+Note that this program has several problems that would prevent it from being
+useful by itself on real text files:@refill
+
+@itemize @bullet
+@item
+Words are detected using the @code{awk} convention that fields are
+separated by whitespace and that other characters in the input (except
+newlines) don't have any special meaning to @code{awk}. This means that
+punctuation characters count as part of words.@refill
+
+@item
+The @code{awk} language considers upper and lower case characters to be
+distinct. Therefore, @samp{foo} and @samp{Foo} are not treated by this
+program as the same word. This is undesirable since in normal text, words
+are capitalized if they begin sentences, and a frequency analyzer should not
+be sensitive to that.@refill
+
+@item
+The output does not come out in any useful order. You're more likely to be
+interested in which words occur most frequently, or having an alphabetized
+table of how frequently each word occurs.@refill
+@end itemize
+
+The way to solve these problems is to use some of the more advanced
+features of the @code{awk} language. First, we use @code{tolower} to remove
+case distinctions. Next, we use @code{gsub} to remove punctuation
+characters. Finally, we use the system @code{sort} utility to process the
+output of the @code{awk} script. First, here is the new version of
+the program:@refill
+
+@example
+awk '
+# Print list of word frequencies
+@{
+ $0 = tolower($0) # remove case distinctions
+ gsub(/[^a-z0-9_ \t]/, "", $0) # remove punctuation
+ for (i = 1; i <= NF; i++)
+ freq[$i]++
+@}
+
+END @{
+ for (word in freq)
+ printf "%s\t%d\n", word, freq[word]
+@}'
+@end example
+
+Assuming we have saved this program in a file named @file{frequency.awk},
+and that the data is in @file{file1}, the following pipeline
+
+@example
+awk -f frequency.awk file1 | sort +1 -nr
+@end example
+
+@noindent
+produces a table of the words appearing in @file{file1} in order of
+decreasing frequency.
+
+The @code{awk} program suitably massages the data and produces a word
+frequency table, which is not ordered.
+
+The @code{awk} script's output is then sorted by the @code{sort} command and
+printed on the terminal. The options given to @code{sort} in this example
+specify to sort using the second field of each input line (skipping one field),
+that the sort keys should be treated as numeric quantities (otherwise
+@samp{15} would come before @samp{5}), and that the sorting should be done
+in descending (reverse) order.@refill
+
+We could have even done the @code{sort} from within the program, by
+changing the @code{END} action to:
+
+@example
+END @{
+ sort = "sort +1 -nr"
+ for (word in freq)
+ printf "%s\t%d\n", word, freq[word] | sort
+ close(sort)
+@}'
+@end example
+
+See the general operating system documentation for more information on how
+to use the @code{sort} command.@refill
+
+@ignore
+@strong{ADR: I have some more substantial programs courtesy of Rick Adams
+at UUNET. I am planning on incorporating those either in addition to or
+instead of this program.}
+
+@strong{I would also like to incorporate the general @code{translate}
+function that I have written.}
+
+@strong{I have a ton of other sample programs to include too.}
+@end ignore
+
+@node Bugs, Notes, Sample Program, Top
+@appendix Reporting Problems and Bugs
+
+@c This chapter stolen shamelessly from the GNU m4 manual.
+@c This chapter has been unshamelessly altered to emulate changes made to
+@c make.texi from whence it was originally shamelessly stolen! :-} --mew
+
+If you have problems with @code{gawk} or think that you have found a bug,
+please report it to the developers; we cannot promise to do anything
+but we might well want to fix it.
+
+Before reporting a bug, make sure you have actually found a real bug.
+Carefully reread the documentation and see if it really says you can do
+what you're trying to do. If it's not clear whether you should be able
+to do something or not, report that too; it's a bug in the documentation!
+
+Before reporting a bug or trying to fix it yourself, try to isolate it
+to the smallest possible @code{awk} program and input data file that
+reproduces the problem. Then send us the program and data file,
+some idea of what kind of Unix system you're using, and the exact results
+@code{gawk} gave you. Also say what you expected to occur; this will help
+us decide whether the problem was really in the documentation.
+
+Once you have a precise problem, send e-mail to (Internet)
+@samp{bug-gnu-utils@@prep.ai.mit.edu} or (UUCP)
+@samp{mit-eddie!prep.ai.mit.edu!bug-gnu-utils}. Please include the
+version number of @code{gawk} you are using. You can get this information
+with the command @samp{gawk -W version '@{@}' /dev/null}.
+You should send carbon copies of your mail to David Trueman at
+@samp{david@@cs.dal.ca}, and to Arnold Robbins, who can be reached at
+@samp{arnold@@skeeve.atl.ga.us}. David is most likely to fix code
+problems, while Arnold is most likely to fix documentation problems.@refill
+
+Non-bug suggestions are always welcome as well. If you have questions
+about things that are unclear in the documentation or are just obscure
+features, ask Arnold Robbins; he will try to help you out, although he
+may not have the time to fix the problem. You can send him electronic mail at the Internet address
+above.
+
+If you find bugs in one of the non-Unix ports of @code{gawk}, please send
+an electronic mail message to the person who maintains that port. They
+are listed below, and also in the @file{README} file in the @code{gawk}
+distribution. Information in the @code{README} file should be considered
+authoritative if it conflicts with this manual.
+
+The people maintaining the non-Unix ports of @code{gawk} are:
+
+@table @asis
+@item MS-DOS
+The port to MS-DOS is maintained by Scott Deifik.
+His electronic mail address is @samp{scottd@@amgen.com}.
+
+@item VMS
+The port to VAX VMS is maintained by Pat Rankin.
+His electronic mail address is @samp{rankin@@eql.caltech.edu}.
+
+@item Atari ST
+The port to the Atari ST is maintained by Michal Jaegermann.
+His electronic mail address is @samp{ntomczak@@vm.ucs.ualberta.ca}.
+
+@end table
+
+If your bug is also reproducible under Unix, please send copies of your
+report to the general GNU bug list, as well as to Arnold Robbins and David
+Trueman, at the addresses listed above.
+
+@node Notes, Glossary, Bugs, Top
+@appendix Implementation Notes
+
+This appendix contains information mainly of interest to implementors and
+maintainers of @code{gawk}. Everything in it applies specifically to
+@code{gawk}, and not to other implementations.
+
+@menu
+* Compatibility Mode:: How to disable certain @code{gawk} extensions.
+* Future Extensions:: New features we may implement soon.
+* Improvements:: Suggestions for improvements by volunteers.
+@end menu
+
+@node Compatibility Mode, Future Extensions, Notes, Notes
+@appendixsec Downward Compatibility and Debugging
+
+@xref{POSIX/GNU, ,Extensions in @code{gawk} not in POSIX @code{awk}},
+for a summary of the GNU extensions to the @code{awk} language and program.
+All of these features can be turned off by invoking @code{gawk} with the
+@samp{-W compat} option, or with the @samp{-W posix} option.@refill
+
+If @code{gawk} is compiled for debugging with @samp{-DDEBUG}, then there
+is one more option available on the command line:
+
+@table @samp
+@item -W parsedebug
+Print out the parse stack information as the program is being parsed.
+@end table
+
+This option is intended only for serious @code{gawk} developers,
+and not for the casual user. It probably has not even been compiled into
+your version of @code{gawk}, since it slows down execution.
+
+@node Future Extensions, Improvements, Compatibility Mode, Notes
+@appendixsec Probable Future Extensions
+
+This section briefly lists extensions that indicate the directions we are
+currently considering for @code{gawk}. The file @file{FUTURES} in the
+@code{gawk} distributions lists these extensions, as well as several others.
+
+@table @asis
+@item @code{RS} as a regexp
+The meaning of @code{RS} may be generalized along the lines of @code{FS}.
+
+@item Control of subprocess environment
+Changes made in @code{gawk} to the array @code{ENVIRON} may be
+propagated to subprocesses run by @code{gawk}.
+
+@item Databases
+It may be possible to map a GDBM/NDBM/SDBM file into an @code{awk} array.
+
+@item Single-character fields
+The null string, @code{""}, as a field separator, will cause field
+splitting and the @code{split} function to separate individual characters.
+Thus, @code{split(a, "abcd", "")} would yield @code{a[1] == "a"},
+@code{a[2] == "b"}, and so on.
+
+@item More @code{lint} warnings
+There are more things that could be checked for portability.
+
+@item @code{RECLEN} variable for fixed length records
+Along with @code{FIELDWIDTHS}, this would speed up the processing of
+fixed-length records.
+
+@item @code{RT} variable to hold the record terminator
+It is occasionally useful to have access to the actual string of
+characters that matched the @code{RS} variable. The @code{RT}
+variable would hold these characters.
+
+@item A @code{restart} keyword
+After modifying @code{$0}, @code{restart} would restart the pattern
+matching loop, without reading a new record from the input.
+
+@item A @samp{|&} redirection
+The @samp{|&} redirection, in place of @samp{|}, would open a two-way
+pipeline for communication with a sub-process (via @code{getline} and
+@code{print} and @code{printf}).
+
+@item @code{IGNORECASE} affecting all comparisons
+The effects of the @code{IGNORECASE} variable may be generalized to
+all string comparisons, and not just regular expression operations.
+
+@item A way to mix command line source code and library files
+There may be a new option that would make it possible to easily use library
+functions from a program entered on the command line.
+@c probably a @samp{-s} option...
+
+@item GNU-style long options
+We will add GNU-style long options
+to @code{gawk} for compatibility with other GNU programs.
+(For example, @samp{--field-separator=:} would be equivalent to
+@samp{-F:}.)@refill
+
+@c this is @emph{very} long term --- not worth including right now.
+@ignore
+@item The C Comma Operator
+We may add the C comma operator, which takes the form
+@code{@var{expr1},@var{expr2}}. The first expression is evaluated, and the
+result is thrown away. The value of the full expression is the value of
+@var{expr2}.@refill
+@end ignore
+@end table
+
+@node Improvements, , Future Extensions, Notes
+@appendixsec Suggestions for Improvements
+
+Here are some projects that would-be @code{gawk} hackers might like to take
+on. They vary in size from a few days to a few weeks of programming,
+depending on which one you choose and how fast a programmer you are. Please
+send any improvements you write to the maintainers at the GNU
+project.@refill
+
+@enumerate
+@item
+Compilation of @code{awk} programs: @code{gawk} uses a Bison (YACC-like)
+parser to convert the script given it into a syntax tree; the syntax
+tree is then executed by a simple recursive evaluator. This method incurs
+a lot of overhead, since the recursive evaluator performs many procedure
+calls to do even the simplest things.@refill
+
+It should be possible for @code{gawk} to convert the script's parse tree
+into a C program which the user would then compile, using the normal
+C compiler and a special @code{gawk} library to provide all the needed
+functions (regexps, fields, associative arrays, type coercion, and so
+on).@refill
+
+An easier possibility might be for an intermediate phase of @code{awk} to
+convert the parse tree into a linear byte code form like the one used
+in GNU Emacs Lisp. The recursive evaluator would then be replaced by
+a straight line byte code interpreter that would be intermediate in speed
+between running a compiled program and doing what @code{gawk} does
+now.@refill
+
+This may actually happen for the 3.0 version of @code{gawk}.
+
+@item
+An error message section has not been included in this version of the
+manual. Perhaps some nice beta testers will document some of the messages
+for the future.
+
+@item
+The programs in the test suite could use documenting in this manual.
+
+@item
+The programs and data files in the manual should be available in
+separate files to facilitate experimentation.
+
+@item
+See the @file{FUTURES} file for more ideas. Contact us if you would
+seriously like to tackle any of the items listed there.
+@end enumerate
+
+@node Glossary, Index, Notes, Top
+@appendix Glossary
+
+@table @asis
+@item Action
+A series of @code{awk} statements attached to a rule. If the rule's
+pattern matches an input record, the @code{awk} language executes the
+rule's action. Actions are always enclosed in curly braces.
+@xref{Actions, ,Overview of Actions}.@refill
+
+@item Amazing @code{awk} Assembler
+Henry Spencer at the University of Toronto wrote a retargetable assembler
+completely as @code{awk} scripts. It is thousands of lines long, including
+machine descriptions for several 8-bit microcomputers.
+@c It is distributed with @code{gawk} (as part of the test suite) and
+It is a good example of a
+program that would have been better written in another language.@refill
+
+@item @sc{ansi}
+The American National Standards Institute. This organization produces
+many standards, among them the standard for the C programming language.
+
+@item Assignment
+An @code{awk} expression that changes the value of some @code{awk}
+variable or data object. An object that you can assign to is called an
+@dfn{lvalue}. @xref{Assignment Ops, ,Assignment Expressions}.@refill
+
+@item @code{awk} Language
+The language in which @code{awk} programs are written.
+
+@item @code{awk} Program
+An @code{awk} program consists of a series of @dfn{patterns} and
+@dfn{actions}, collectively known as @dfn{rules}. For each input record
+given to the program, the program's rules are all processed in turn.
+@code{awk} programs may also contain function definitions.@refill
+
+@item @code{awk} Script
+Another name for an @code{awk} program.
+
+@item Built-in Function
+The @code{awk} language provides built-in functions that perform various
+numerical, time stamp related, and string computations. Examples are
+@code{sqrt} (for the square root of a number) and @code{substr} (for a
+substring of a string). @xref{Built-in, ,Built-in Functions}.@refill
+
+@item Built-in Variable
+@code{ARGC}, @code{ARGIND}, @code{ARGV}, @code{CONVFMT}, @code{ENVIRON},
+@code{ERRNO}, @code{FIELDWIDTHS}, @code{FILENAME}, @code{FNR}, @code{FS},
+@code{IGNORECASE}, @code{NF}, @code{NR}, @code{OFMT}, @code{OFS}, @code{ORS},
+@code{RLENGTH}, @code{RSTART}, @code{RS}, and @code{SUBSEP},
+are the variables that have special
+meaning to @code{awk}. Changing some of them affects @code{awk}'s running
+environment. @xref{Built-in Variables}.@refill
+
+@item Braces
+See ``Curly Braces.''
+
+@item C
+The system programming language that most GNU software is written in. The
+@code{awk} programming language has C-like syntax, and this manual
+points out similarities between @code{awk} and C when appropriate.@refill
+
+@item CHEM
+A preprocessor for @code{pic} that reads descriptions of molecules
+and produces @code{pic} input for drawing them. It was written by
+Brian Kernighan, and is available from @code{netlib@@research.att.com}.@refill
+
+@item Compound Statement
+A series of @code{awk} statements, enclosed in curly braces. Compound
+statements may be nested.
+@xref{Statements, ,Control Statements in Actions}.@refill
+
+@item Concatenation
+Concatenating two strings means sticking them together, one after another,
+giving a new string. For example, the string @samp{foo} concatenated with
+the string @samp{bar} gives the string @samp{foobar}.
+@xref{Concatenation, ,String Concatenation}.@refill
+
+@item Conditional Expression
+An expression using the @samp{?:} ternary operator, such as
+@code{@var{expr1} ? @var{expr2} : @var{expr3}}. The expression
+@var{expr1} is evaluated; if the result is true, the value of the whole
+expression is the value of @var{expr2} otherwise the value is
+@var{expr3}. In either case, only one of @var{expr2} and @var{expr3}
+is evaluated. @xref{Conditional Exp, ,Conditional Expressions}.@refill
+
+@item Constant Regular Expression
+A constant regular expression is a regular expression written within
+slashes, such as @samp{/foo/}. This regular expression is chosen
+when you write the @code{awk} program, and cannot be changed doing
+its execution. @xref{Regexp Usage, ,How to Use Regular Expressions}.
+
+@item Comparison Expression
+A relation that is either true or false, such as @code{(a < b)}.
+Comparison expressions are used in @code{if}, @code{while}, and @code{for}
+statements, and in patterns to select which input records to process.
+@xref{Comparison Ops, ,Comparison Expressions}.@refill
+
+@item Curly Braces
+The characters @samp{@{} and @samp{@}}. Curly braces are used in
+@code{awk} for delimiting actions, compound statements, and function
+bodies.@refill
+
+@item Data Objects
+These are numbers and strings of characters. Numbers are converted into
+strings and vice versa, as needed.
+@xref{Conversion, ,Conversion of Strings and Numbers}.@refill
+
+@item Dynamic Regular Expression
+A dynamic regular expression is a regular expression written as an
+ordinary expression. It could be a string constant, such as
+@code{"foo"}, but it may also be an expression whose value may vary.
+@xref{Regexp Usage, ,How to Use Regular Expressions}.
+
+@item Escape Sequences
+A special sequence of characters used for describing nonprinting
+characters, such as @samp{\n} for newline, or @samp{\033} for the ASCII
+ESC (escape) character. @xref{Constants, ,Constant Expressions}.
+
+@item Field
+When @code{awk} reads an input record, it splits the record into pieces
+separated by whitespace (or by a separator regexp which you can
+change by setting the built-in variable @code{FS}). Such pieces are
+called fields. If the pieces are of fixed length, you can use the built-in
+variable @code{FIELDWIDTHS} to describe their lengths.
+@xref{Records, ,How Input is Split into Records}.@refill
+
+@item Format
+Format strings are used to control the appearance of output in the
+@code{printf} statement. Also, data conversions from numbers to strings
+are controlled by the format string contained in the built-in variable
+@code{CONVFMT}. @xref{Control Letters, ,Format-Control Letters}.@refill
+
+@item Function
+A specialized group of statements often used to encapsulate general
+or program-specific tasks. @code{awk} has a number of built-in
+functions, and also allows you to define your own.
+@xref{Built-in, ,Built-in Functions}.
+Also, see @ref{User-defined, ,User-defined Functions}.@refill
+
+@item @code{gawk}
+The GNU implementation of @code{awk}.
+
+@item GNU
+``GNU's not Unix''. An on-going project of the Free Software Foundation
+to create a complete, freely distributable, @sc{posix}-compliant computing
+environment.
+
+@item Input Record
+A single chunk of data read in by @code{awk}. Usually, an @code{awk} input
+record consists of one line of text.
+@xref{Records, ,How Input is Split into Records}.@refill
+
+@item Keyword
+In the @code{awk} language, a keyword is a word that has special
+meaning. Keywords are reserved and may not be used as variable names.
+
+@code{awk}'s keywords are:
+@code{if},
+@code{else},
+@code{while},
+@code{do@dots{}while},
+@code{for},
+@code{for@dots{}in},
+@code{break},
+@code{continue},
+@code{delete},
+@code{next},
+@code{function},
+@code{func},
+and @code{exit}.@refill
+
+@item Lvalue
+An expression that can appear on the left side of an assignment
+operator. In most languages, lvalues can be variables or array
+elements. In @code{awk}, a field designator can also be used as an
+lvalue.@refill
+
+@item Number
+A numeric valued data object. The @code{gawk} implementation uses double
+precision floating point to represent numbers.@refill
+
+@item Pattern
+Patterns tell @code{awk} which input records are interesting to which
+rules.
+
+A pattern is an arbitrary conditional expression against which input is
+tested. If the condition is satisfied, the pattern is said to @dfn{match}
+the input record. A typical pattern might compare the input record against
+a regular expression. @xref{Patterns}.@refill
+
+@item @sc{posix}
+The name for a series of standards being developed by the @sc{ieee}
+that specify a Portable Operating System interface. The ``IX'' denotes
+the Unix heritage of these standards. The main standard of interest for
+@code{awk} users is P1003.2, the Command Language and Utilities standard.
+
+@item Range (of input lines)
+A sequence of consecutive lines from the input file. A pattern
+can specify ranges of input lines for @code{awk} to process, or it can
+specify single lines. @xref{Patterns}.@refill
+
+@item Recursion
+When a function calls itself, either directly or indirectly.
+If this isn't clear, refer to the entry for ``recursion.''
+
+@item Redirection
+Redirection means performing input from other than the standard input
+stream, or output to other than the standard output stream.
+
+You can redirect the output of the @code{print} and @code{printf} statements
+to a file or a system command, using the @samp{>}, @samp{>>}, and @samp{|}
+operators. You can redirect input to the @code{getline} statement using
+the @samp{<} and @samp{|} operators.
+@xref{Redirection, ,Redirecting Output of @code{print} and @code{printf}}.@refill
+
+@item Regular Expression
+See ``regexp.''
+
+@item Regexp
+Short for @dfn{regular expression}. A regexp is a pattern that denotes a
+set of strings, possibly an infinite set. For example, the regexp
+@samp{R.*xp} matches any string starting with the letter @samp{R}
+and ending with the letters @samp{xp}. In @code{awk}, regexps are
+used in patterns and in conditional expressions. Regexps may contain
+escape sequences. @xref{Regexp, ,Regular Expressions as Patterns}.@refill
+
+@item Rule
+A segment of an @code{awk} program, that specifies how to process single
+input records. A rule consists of a @dfn{pattern} and an @dfn{action}.
+@code{awk} reads an input record; then, for each rule, if the input record
+satisfies the rule's pattern, @code{awk} executes the rule's action.
+Otherwise, the rule does nothing for that input record.@refill
+
+@item Side Effect
+A side effect occurs when an expression has an effect aside from merely
+producing a value. Assignment expressions, increment expressions and
+function calls have side effects. @xref{Assignment Ops, ,Assignment Expressions}.
+
+@item Special File
+A file name interpreted internally by @code{gawk}, instead of being handed
+directly to the underlying operating system. For example, @file{/dev/stdin}.
+@xref{Special Files, ,Standard I/O Streams}.
+
+@item Stream Editor
+A program that reads records from an input stream and processes them one
+or more at a time. This is in contrast with batch programs, which may
+expect to read their input files in entirety before starting to do
+anything, and with interactive programs, which require input from the
+user.@refill
+
+@item String
+A datum consisting of a sequence of characters, such as @samp{I am a
+string}. Constant strings are written with double-quotes in the
+@code{awk} language, and may contain escape sequences.
+@xref{Constants, ,Constant Expressions}.
+
+@item Whitespace
+A sequence of blank or tab characters occurring inside an input record or a
+string.@refill
+@end table
+
+@node Index, , Glossary, Top
+@unnumbered Index
+@printindex cp
+
+@summarycontents
+@contents
+@bye
+
+Unresolved Issues:
+------------------
+1. From: ntomczak@vm.ucs.ualberta.ca (Michal Jaegermann)
+ Examples of usage tend to suggest that /../ and ".." delimiters
+ can be used for regular expressions, even if definition is consistently
+ using /../. I am not sure what the real rules are and in particular
+ what of the following is a bug and what is a feature:
+ # This program matches everything
+ '"\(" { print }'
+ # This one complains about mismatched parenthesis
+ '$0 ~ "\(" { print }'
+ # This one behaves in an expected manner
+ '/\(/ { print }'
+ You may also try to use "\(" as an argument to match() to see what
+ will happen.
+
+2. From ADR.
+
+ The posix (and original Unix!) notion of awk values as both number
+ and string values needs to be put into the manual. This involves
+ major and minor rewrites of most of the manual, but should help in
+ clarifying many of the weirder points of the language.
+
+3. From ADR.
+
+ The manual should be reorganized. Expressions should be introduced
+ early, building up to regexps as expressions, and from there to their
+ use as patterns and then in actions. Built-in vars should come earlier
+ in the manual too. The 'expert info' sections marked with comments
+ should get their own sections or subsections with nodes and titles.
+ The manual should be gone over thoroughly for indexing.
+
+4. From ADR.
+
+ Robert J. Chassell points out that awk programs should have some indication
+ of how to use them. It would be useful to perhaps have a "programming
+ style" section of the manual that would include this and other tips.
+
+5. From ADR in response to moraes@uunet.ca
+ (This would make the beginnings of a good "puzzles" section...)
+
+ Date: Mon, 2 Dec 91 10:08:05 EST
+ From: gatech!cc!arnold (Arnold Robbins)
+ To: cs.dal.ca!david, uunet.ca!moraes
+ Subject: redirecting to /dev/stderr
+ Cc: skeeve!arnold, boeing.com!brennan, research.att.com!bwk
+
+ In 2.13.3 the following program no longer dumps core:
+
+ BEGIN { print "hello" > /dev/stderr ; exit(1) }
+
+ Instead, it creates a file named `0' with the word `hello' in it. AWK
+ semantics strikes again. The meaning of the statement is
+
+ print "hello" > (($0 ~ /dev/) stderr)
+
+ /dev/ tests $0 for the pattern `dev'. This yields a 0. The variable stderr,
+ having never been used, has a null string in it. The concatenation yields
+ a string value of "0" which is used as the file name. Sigh.
+
+ I think with some more time I can come up with a decent fix, but it will
+ probably only print a diagnostic with -Wlint.
+
+ Arnold
+
diff --git a/gnu/usr.bin/awk/eval.c b/gnu/usr.bin/awk/eval.c
index f640f37..ccf4671 100644
--- a/gnu/usr.bin/awk/eval.c
+++ b/gnu/usr.bin/awk/eval.c
@@ -1,23 +1,23 @@
/*
- * eval.c - gawk parse tree interpreter
+ * eval.c - gawk parse tree interpreter
*/
-/*
- * Copyright (C) 1986, 1988, 1989, 1991, 1992 the Free Software Foundation, Inc.
- *
+/*
+ * Copyright (C) 1986, 1988, 1989, 1991, 1992, 1993 the Free Software Foundation, Inc.
+ *
* This file is part of GAWK, the GNU implementation of the
* AWK Progamming Language.
- *
+ *
* GAWK is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
- *
+ *
* GAWK is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
- *
+ *
* You should have received a copy of the GNU General Public License
* along with GAWK; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
@@ -122,7 +122,7 @@ char casetable[] = {
/*
* Tree is a bunch of rules to run. Returns zero if it hit an exit()
- * statement
+ * statement
*/
int
interpret(tree)
@@ -137,6 +137,10 @@ register NODE *volatile tree;
NODE *volatile stable_tree;
int volatile traverse = 1; /* True => loop thru tree (Node_rule_list) */
+ /* avoid false source indications */
+ source = NULL;
+ sourceline = 0;
+
if (tree == NULL)
return 1;
sourceline = tree->source_line;
@@ -318,7 +322,10 @@ register NODE *volatile tree;
break;
case Node_K_delete:
- do_delete(tree->lnode, tree->rnode);
+ if (tree->rnode != NULL)
+ do_delete(tree->lnode, tree->rnode);
+ else
+ assoc_clear(tree->lnode);
break;
case Node_K_next:
@@ -356,7 +363,7 @@ register NODE *volatile tree;
default:
/*
* Appears to be an expression statement. Throw away the
- * value.
+ * value.
*/
if (do_lint && tree->type == Node_var)
warning("statement has no effect");
@@ -378,7 +385,7 @@ register NODE *tree;
register int di;
AWKNUM x, x1, x2;
long lx;
-#ifdef CRAY
+#ifdef _CRAY
long lx2;
#endif
@@ -386,21 +393,25 @@ register NODE *tree;
if (tree == NULL)
return Nnull_string;
if (tree->type == Node_val) {
- if (tree->stref <= 0) cant_happen();
+ if ((char)tree->stref <= 0) cant_happen();
return tree;
}
if (tree->type == Node_var) {
- if (tree->var_value->stref <= 0) cant_happen();
+ if ((char)tree->var_value->stref <= 0) cant_happen();
return tree->var_value;
}
+#endif
+
if (tree->type == Node_param_list) {
- if (stack_ptr[tree->param_cnt] == NULL)
+ tree = stack_ptr[tree->param_cnt];
+ if (tree == NULL)
return Nnull_string;
- else
- return stack_ptr[tree->param_cnt]->var_value;
}
-#endif
+
switch (tree->type) {
+ case Node_var:
+ return tree->var_value;
+
case Node_and:
return tmp_number((AWKNUM) (eval_condition(tree->lnode)
&& eval_condition(tree->rnode)));
@@ -443,7 +454,7 @@ register NODE *tree;
return *lhs;
case Node_var_array:
- fatal("attempt to use an array in a scalar context");
+ fatal("attempt to use array `%s' in a scalar context", tree->vname);
case Node_unary_minus:
t1 = tree_eval(tree->subnode);
@@ -489,32 +500,52 @@ register NODE *tree;
case Node_concat:
{
#define STACKSIZE 10
- NODE *stack[STACKSIZE];
- register NODE **sp;
- register int len;
+ NODE *treelist[STACKSIZE+1];
+ NODE *strlist[STACKSIZE+1];
+ register NODE **treep;
+ register NODE **strp;
+ register size_t len;
char *str;
register char *dest;
- sp = stack;
- len = 0;
+ /*
+ * This is an efficiency hack for multiple adjacent string
+ * concatenations, to avoid recursion and string copies.
+ *
+ * Node_concat trees grow downward to the left, so
+ * descend to lowest (first) node, accumulating nodes
+ * to evaluate to strings as we go.
+ */
+ treep = treelist;
while (tree->type == Node_concat) {
- *sp = force_string(tree_eval(tree->lnode));
- tree = tree->rnode;
- len += (*sp)->stlen;
- if (++sp == &stack[STACKSIZE-2]) /* one more and NULL */
+ *treep++ = tree->rnode;
+ tree = tree->lnode;
+ if (treep == &treelist[STACKSIZE])
break;
}
- *sp = force_string(tree_eval(tree));
- len += (*sp)->stlen;
- *++sp = NULL;
+ *treep = tree;
+ /*
+ * Now, evaluate to strings in LIFO order, accumulating
+ * the string length, so we can do a single malloc at the
+ * end.
+ */
+ strp = strlist;
+ len = 0;
+ while (treep >= treelist) {
+ *strp = force_string(tree_eval(*treep--));
+ len += (*strp)->stlen;
+ strp++;
+ }
+ *strp = NULL;
emalloc(str, char *, len+2, "tree_eval");
+ str[len] = str[len+1] = '\0'; /* for good measure */
dest = str;
- sp = stack;
- while (*sp) {
- memcpy(dest, (*sp)->stptr, (*sp)->stlen);
- dest += (*sp)->stlen;
- free_temp(*sp);
- sp++;
+ strp = strlist;
+ while (*strp) {
+ memcpy(dest, (*strp)->stptr, (*strp)->stlen);
+ dest += (*strp)->stlen;
+ free_temp(*strp);
+ strp++;
}
r = make_str_node(str, len, ALREADY_MALLOCED);
r->flags |= TEMP;
@@ -629,7 +660,7 @@ register NODE *tree;
return tmp_number(x1 - x2);
case Node_var_array:
- fatal("attempt to use an array in a scalar context");
+ fatal("attempt to use array `%s' in a scalar context", tree->vname);
default:
fatal("illegal type (%d) in tree_eval", tree->type);
@@ -654,7 +685,7 @@ register NODE *tree;
* of a Node_cond_pair; whether we evaluate the lnode of that
* node or the rnode depends on the triggered word. More
* precisely: if we are not yet triggered, we tree_eval the
- * lnode; if that returns true, we set the triggered word.
+ * lnode; if that returns true, we set the triggered word.
* If we are triggered (not ELSE IF, note), we tree_eval the
* rnode, clear triggered if it succeeds, and perform our
* action (regardless of success or failure). We want to be
@@ -674,7 +705,7 @@ register NODE *tree;
/*
* Could just be J.random expression. in which case, null and 0 are
- * false, anything else is true
+ * false, anything else is true
*/
t1 = tree_eval(tree);
@@ -696,7 +727,7 @@ cmp_nodes(t1, t2)
register NODE *t1, *t2;
{
register int ret;
- register int len1, len2;
+ register size_t len1, len2;
if (t1 == t2)
return 0;
@@ -944,22 +975,26 @@ NODE *arg_list; /* Node_expression_list of calling args. */
if (arg->type == Node_param_list)
arg = stack_ptr[arg->param_cnt];
n = *sp++;
- if (arg->type == Node_var && n->type == Node_var_array) {
+ if ((arg->type == Node_var || arg->type == Node_var_array)
+ && n->type == Node_var_array) {
/* should we free arg->var_value ? */
arg->var_array = n->var_array;
arg->type = Node_var_array;
+ arg->array_size = n->array_size;
+ arg->table_size = n->table_size;
+ arg->flags = n->flags;
}
- unref(n->lnode);
+ /* n->lnode overlays the array size, don't unref it if array */
+ if (n->type != Node_var_array)
+ unref(n->lnode);
freenode(n);
count--;
}
while (count-- > 0) {
n = *sp++;
/* if n is an (local) array, all the elements should be freed */
- if (n->type == Node_var_array) {
+ if (n->type == Node_var_array)
assoc_clear(n);
- free(n->var_array);
- }
unref(n->lnode);
freenode(n);
}
@@ -981,11 +1016,11 @@ NODE *arg_list; /* Node_expression_list of calling args. */
/*
* This returns a POINTER to a node pointer. get_lhs(ptr) is the current
- * value of the var, or where to store the var's new value
+ * value of the var, or where to store the var's new value
*/
NODE **
-get_lhs(ptr, assign)
+r_get_lhs(ptr, assign)
register NODE *ptr;
Func_ptr *assign;
{
@@ -994,11 +1029,11 @@ Func_ptr *assign;
switch (ptr->type) {
case Node_var_array:
- fatal("attempt to use an array in a scalar context");
+ fatal("attempt to use array `%s' in a scalar context", ptr->vname);
case Node_var:
aptr = &(ptr->var_value);
#ifdef DEBUG
- if (ptr->var_value->stref <= 0)
+ if ((char)ptr->var_value->stref <= 0)
cant_happen();
#endif
break;
@@ -1170,7 +1205,7 @@ set_ORS()
ORS[ORSlen] = '\0';
}
-static NODE **fmt_list = NULL;
+NODE **fmt_list = NULL;
static int fmt_ok P((NODE *n));
static int fmt_index P((NODE *n));
diff --git a/gnu/usr.bin/awk/field.c b/gnu/usr.bin/awk/field.c
index d8f9a54..b1a709e 100644
--- a/gnu/usr.bin/awk/field.c
+++ b/gnu/usr.bin/awk/field.c
@@ -2,22 +2,22 @@
* field.c - routines for dealing with fields and record parsing
*/
-/*
- * Copyright (C) 1986, 1988, 1989, 1991, 1992 the Free Software Foundation, Inc.
- *
+/*
+ * Copyright (C) 1986, 1988, 1989, 1991, 1992, 1993 the Free Software Foundation, Inc.
+ *
* This file is part of GAWK, the GNU implementation of the
* AWK Progamming Language.
- *
+ *
* GAWK is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
- *
+ *
* GAWK is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
- *
+ *
* You should have received a copy of the GNU General Public License
* along with GAWK; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
@@ -25,26 +25,28 @@
#include "awk.h"
-static int (*parse_field) P((int, char **, int, NODE *,
- Regexp *, void (*)(), NODE *));
+typedef void (* Setfunc) P((int, char*, int, NODE *));
+
+static long (*parse_field) P((int, char **, int, NODE *,
+ Regexp *, Setfunc, NODE *));
static void rebuild_record P((void));
-static int re_parse_field P((int, char **, int, NODE *,
- Regexp *, void (*)(), NODE *));
-static int def_parse_field P((int, char **, int, NODE *,
- Regexp *, void (*)(), NODE *));
-static int sc_parse_field P((int, char **, int, NODE *,
- Regexp *, void (*)(), NODE *));
-static int fw_parse_field P((int, char **, int, NODE *,
- Regexp *, void (*)(), NODE *));
+static long re_parse_field P((int, char **, int, NODE *,
+ Regexp *, Setfunc, NODE *));
+static long def_parse_field P((int, char **, int, NODE *,
+ Regexp *, Setfunc, NODE *));
+static long sc_parse_field P((int, char **, int, NODE *,
+ Regexp *, Setfunc, NODE *));
+static long fw_parse_field P((int, char **, int, NODE *,
+ Regexp *, Setfunc, NODE *));
static void set_element P((int, char *, int, NODE *));
-static void grow_fields_arr P((int num));
+static void grow_fields_arr P((long num));
static void set_field P((int num, char *str, int len, NODE *dummy));
static Regexp *FS_regexp = NULL;
static char *parse_extent; /* marks where to restart parse of record */
-static int parse_high_water=0; /* field number that we have parsed so far */
-static int nf_high_water = 0; /* size of fields_arr */
+static long parse_high_water=0; /* field number that we have parsed so far */
+static long nf_high_water = 0; /* size of fields_arr */
static int resave_fs;
static NODE *save_FS; /* save current value of FS when line is read,
* to be used in deferred parsing
@@ -74,7 +76,7 @@ init_fields()
static void
grow_fields_arr(num)
-int num;
+long num;
{
register int t;
register NODE *n;
@@ -112,13 +114,13 @@ NODE *dummy; /* not used -- just to make interface same as set_element */
static void
rebuild_record()
{
- register int tlen;
+ register size_t tlen;
register NODE *tmp;
NODE *ofs;
char *ops;
register char *cops;
register NODE **ptr;
- register int ofslen;
+ register size_t ofslen;
tlen = 0;
ofs = force_string(OFS_node->var_value);
@@ -130,9 +132,9 @@ rebuild_record()
ptr--;
}
tlen += (NF - 1) * ofslen;
- if (tlen < 0)
+ if ((long)tlen < 0)
tlen = 0;
- emalloc(ops, char *, tlen + 2, "fix_fields");
+ emalloc(ops, char *, tlen + 2, "rebuild_record");
cops = ops;
ops[0] = '\0';
for (ptr = &fields_arr[1]; ptr <= &fields_arr[NF]; ptr++) {
@@ -204,7 +206,7 @@ set_NF()
{
register int i;
- NF = (int) force_number(NF_node->var_value);
+ NF = (long) force_number(NF_node->var_value);
if (NF > nf_high_water)
grow_fields_arr(NF);
for (i = parse_high_water + 1; i <= NF; i++) {
@@ -219,14 +221,14 @@ set_NF()
* via (*parse_field)(). This variation is for when FS is a regular
* expression -- either user-defined or because RS=="" and FS==" "
*/
-static int
+static long
re_parse_field(up_to, buf, len, fs, rp, set, n)
int up_to; /* parse only up to this field number */
char **buf; /* on input: string to parse; on output: point to start next */
int len;
NODE *fs;
Regexp *rp;
-void (*set) (); /* routine to set the value of the parsed field */
+Setfunc set; /* routine to set the value of the parsed field */
NODE *n;
{
register char *scan = *buf;
@@ -240,22 +242,23 @@ NODE *n;
return nf;
if (*RS == 0 && default_FS)
- while (scan < end && isspace(*scan))
+ while (scan < end && (*scan == ' ' || *scan == '\t' || *scan == '\n'))
scan++;
field = scan;
while (scan < end
- && research(rp, scan, 0, (int)(end - scan), 1) != -1
+ && research(rp, scan, 0, (end - scan), 1) != -1
&& nf < up_to) {
- if (REEND(rp, scan) == RESTART(rp, scan)) { /* null match */
+ if (REEND(rp, scan) == RESTART(rp, scan)) { /* null match */
scan++;
if (scan == end) {
- (*set)(++nf, field, scan - field, n);
+ (*set)(++nf, field, (int)(scan - field), n);
up_to = nf;
break;
}
continue;
}
- (*set)(++nf, field, scan + RESTART(rp, scan) - field, n);
+ (*set)(++nf, field,
+ (int)(scan + RESTART(rp, scan) - field), n);
scan += REEND(rp, scan);
field = scan;
if (scan == end) /* FS at end of record */
@@ -274,14 +277,14 @@ NODE *n;
* via (*parse_field)(). This variation is for when FS is a single space
* character.
*/
-static int
+static long
def_parse_field(up_to, buf, len, fs, rp, set, n)
int up_to; /* parse only up to this field number */
char **buf; /* on input: string to parse; on output: point to start next */
int len;
NODE *fs;
Regexp *rp;
-void (*set) (); /* routine to set the value of the parsed field */
+Setfunc set; /* routine to set the value of the parsed field */
NODE *n;
{
register char *scan = *buf;
@@ -302,7 +305,7 @@ NODE *n;
*end = ' '; /* sentinel character */
for (; nf < up_to; scan++) {
/*
- * special case: fs is single space, strip leading whitespace
+ * special case: fs is single space, strip leading whitespace
*/
while (scan < end && (*scan == ' ' || *scan == '\t'))
scan++;
@@ -328,14 +331,14 @@ NODE *n;
* via (*parse_field)(). This variation is for when FS is a single character
* other than space.
*/
-static int
+static long
sc_parse_field(up_to, buf, len, fs, rp, set, n)
int up_to; /* parse only up to this field number */
char **buf; /* on input: string to parse; on output: point to start next */
int len;
NODE *fs;
Regexp *rp;
-void (*set) (); /* routine to set the value of the parsed field */
+Setfunc set; /* routine to set the value of the parsed field */
NODE *n;
{
register char *scan = *buf;
@@ -360,14 +363,18 @@ NODE *n;
/* because it will be destroyed now: */
*end = fschar; /* sentinel character */
- for (; nf < up_to; scan++) {
+ for (; nf < up_to;) {
field = scan;
- while (*scan++ != fschar)
- ;
- scan--;
+ while (*scan != fschar)
+ scan++;
(*set)(++nf, field, (int)(scan - field), n);
if (scan == end)
break;
+ scan++;
+ if (scan == end) { /* FS at end of record */
+ (*set)(++nf, field, 0, n);
+ break;
+ }
}
/* everything done, restore original char at *end */
@@ -381,18 +388,18 @@ NODE *n;
* this is called both from get_field() and from do_split()
* via (*parse_field)(). This variation is for fields are fixed widths.
*/
-static int
+static long
fw_parse_field(up_to, buf, len, fs, rp, set, n)
int up_to; /* parse only up to this field number */
char **buf; /* on input: string to parse; on output: point to start next */
int len;
NODE *fs;
Regexp *rp;
-void (*set) (); /* routine to set the value of the parsed field */
+Setfunc set; /* routine to set the value of the parsed field */
NODE *n;
{
register char *scan = *buf;
- register int nf = parse_high_water;
+ register long nf = parse_high_water;
register char *end = scan + len;
if (up_to == HUGE)
@@ -459,7 +466,7 @@ Func_ptr *assign; /* this field is on the LHS of an assign */
save_FS, FS_regexp, set_field, (NODE *)NULL);
/*
- * if we reached the end of the record, set NF to the number of
+ * if we reached the end of the record, set NF to the number of
* fields so far. Note that requested might actually refer to
* a field that is beyond the end of the record, but we won't
* set NF to that value at this point, since this is only a
@@ -512,11 +519,21 @@ NODE *tree;
NODE *t1, *t2, *t3, *tmp;
NODE *fs;
char *s;
- int (*parseit)P((int, char **, int, NODE *,
- Regexp *, void (*)(), NODE *));
+ long (*parseit)P((int, char **, int, NODE *,
+ Regexp *, Setfunc, NODE *));
Regexp *rp = NULL;
- t1 = tree_eval(tree->lnode);
+
+ /*
+ * do dupnode(), to avoid problems like
+ * x = split(a[1], a, "blah")
+ * since we assoc_clear the array. gack.
+ * this also gives up complete call by value semantics.
+ */
+ tmp = tree_eval(tree->lnode);
+ t1 = dupnode(tmp);
+ free_temp(tmp);
+
t2 = tree->rnode->lnode;
t3 = tree->rnode->rnode->lnode;
@@ -549,7 +566,7 @@ NODE *tree;
s = t1->stptr;
tmp = tmp_number((AWKNUM) (*parseit)(HUGE, &s, (int)t1->stlen,
fs, rp, set_element, t2));
- free_temp(t1);
+ unref(t1);
free_temp(t3);
return tmp;
}
@@ -557,10 +574,16 @@ NODE *tree;
void
set_FS()
{
- NODE *tmp = NULL;
char buf[10];
NODE *fs;
+ /*
+ * If changing the way fields are split, obey least-suprise
+ * semantics, and force $0 to be split totally.
+ */
+ if (fields_arr != NULL)
+ (void) get_field(HUGE - 1, 0);
+
buf[0] = '\0';
default_FS = 0;
if (FS_regexp) {
@@ -586,6 +609,9 @@ set_FS()
else if (fs->stptr[0] != ' ' && fs->stlen == 1) {
if (IGNORECASE == 0)
parse_field = sc_parse_field;
+ else if (fs->stptr[0] == '\\')
+ /* yet another special case */
+ strcpy(buf, "[\\\\]");
else
sprintf(buf, "[%c]", fs->stptr[0]);
}
@@ -625,6 +651,13 @@ set_FIELDWIDTHS()
if (do_unix) /* quick and dirty, does the trick */
return;
+ /*
+ * If changing the way fields are split, obey least-suprise
+ * semantics, and force $0 to be split totally.
+ */
+ if (fields_arr != NULL)
+ (void) get_field(HUGE - 1, 0);
+
parse_field = fw_parse_field;
scan = force_string(FIELDWIDTHS_node->var_value)->stptr;
end = scan + 1;
diff --git a/gnu/usr.bin/awk/getopt.c b/gnu/usr.bin/awk/getopt.c
index bbf345c..fd142f5 100644
--- a/gnu/usr.bin/awk/getopt.c
+++ b/gnu/usr.bin/awk/getopt.c
@@ -3,44 +3,74 @@
"Keep this file name-space clean" means, talk to roland@gnu.ai.mit.edu
before changing it!
- Copyright (C) 1987, 88, 89, 90, 91, 1992 Free Software Foundation, Inc.
+ Copyright (C) 1987, 88, 89, 90, 91, 92, 93, 1994
+ Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify it
- under the terms of the GNU Library General Public License as published
- by the Free Software Foundation; either version 2, or (at your option)
- any later version.
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any
+ later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
- You should have received a copy of the GNU Library General Public
- License along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
-#ifdef GAWK
+#ifdef HAVE_CONFIG_H
+#if defined (emacs) || defined (CONFIG_BROKETS)
+/* We use <config.h> instead of "config.h" so that a compilation
+ using -I. -I$srcdir will use ./config.h rather than $srcdir/config.h
+ (which it would do because it found this file in $srcdir). */
+#include <config.h>
+#else
#include "config.h"
#endif
+#endif
+
+#ifndef __STDC__
+/* This is a separate conditional since some stdc systems
+ reject `defined (const)'. */
+#ifndef const
+#define const
+#endif
+#endif
+
+/* This tells Alpha OSF/1 not to define a getopt prototype in <stdio.h>. */
+#ifndef _NO_PROTO
+#define _NO_PROTO
+#endif
#include <stdio.h>
+/* Comment out all this code if we are using the GNU C Library, and are not
+ actually compiling the library itself. This code is part of the GNU C
+ Library, but also included in many other GNU distributions. Compiling
+ and linking in this code is a waste when using the GNU C library
+ (especially if it is a shared library). Rather than having every GNU
+ program understand `configure --with-gnu-libc' and omit the object files,
+ it is simpler to just do this in the source for each such file. */
+
+#if defined (_LIBC) || !defined (__GNU_LIBRARY__)
+
+
/* This needs to come after some library #include
to get __GNU_LIBRARY__ defined. */
-#ifdef __GNU_LIBRARY__
+#if defined(__GNU_LIBRARY__) || defined(STDC_HEADERS)
+/* Don't include stdlib.h for non-GNU C libraries because some of them
+ contain conflicting prototypes for getopt. */
#include <stdlib.h>
-#include <string.h>
-#endif /* GNU C library. */
-
-
-#ifndef __STDC__
-#define const
-#endif
+#else
+extern char *getenv ();
+#endif /* __GNU_LIBRARY || STDC_HEADERS */
/* If GETOPT_COMPAT is defined, `+' as well as `--' can introduce a
long-named option. Because this is not POSIX.2 compliant, it is
- being phased out. */
-#define GETOPT_COMPAT
+ being phased out. */
+/* #define GETOPT_COMPAT */
/* This version of `getopt' appears to the caller like standard Unix `getopt'
but it behaves differently for the user, since it allows the user
@@ -78,6 +108,7 @@ char *optarg = 0;
Otherwise, `optind' communicates from one call to the next
how much of ARGV has been scanned so far. */
+/* XXX 1003.2 says this must be 1 before any call. */
int optind = 0;
/* The next char to be scanned in the option-element
@@ -94,6 +125,12 @@ static char *nextchar;
int opterr = 1;
+/* Set to an option character which was unrecognized.
+ This must be initialized on some systems to avoid linking in the
+ system's own getopt implementation. */
+
+int optopt = '?';
+
/* Describe how to deal with options that follow non-option ARGV-elements.
If the caller did not specify anything,
@@ -128,41 +165,46 @@ static enum
REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER
} ordering;
-#ifdef __GNU_LIBRARY__
+#if defined(__GNU_LIBRARY__) || defined(STDC_HEADERS)
+/* We want to avoid inclusion of string.h with non-GNU libraries
+ because there are many ways it can cause trouble.
+ On some systems, it contains special magic macros that don't work
+ in GCC. */
#include <string.h>
#define my_index strchr
-#define my_bcopy(src, dst, n) memcpy ((dst), (src), (n))
#else
/* Avoid depending on library functions or files
whose names are inconsistent. */
-char *getenv ();
-
static char *
-my_index (string, chr)
- char *string;
+my_index (str, chr)
+ const char *str;
int chr;
{
- while (*string)
+ while (*str)
{
- if (*string == chr)
- return string;
- string++;
+ if (*str == chr)
+ return (char *) str;
+ str++;
}
return 0;
}
-static void
-my_bcopy (from, to, size)
- char *from, *to;
- int size;
-{
- int i;
- for (i = 0; i < size; i++)
- to[i] = from[i];
-}
-#endif /* GNU C library. */
+/* If using GCC, we can safely declare strlen this way.
+ If not using GCC, it is ok not to declare it.
+ (Supposedly there are some machines where it might get a warning,
+ but changing this conditional to __STDC__ is too risky.) */
+#ifdef __GNUC__
+#ifdef IN_GCC
+#include "gstddef.h"
+#else
+#include <stddef.h>
+#endif
+extern size_t strlen (const char *);
+#endif
+
+#endif /* __GNU_LIBRARY__ || STDC_HEADERS */
/* Handle permutation of arguments. */
@@ -186,17 +228,51 @@ static void
exchange (argv)
char **argv;
{
- int nonopts_size = (last_nonopt - first_nonopt) * sizeof (char *);
- char **temp = (char **) malloc (nonopts_size);
+ int bottom = first_nonopt;
+ int middle = last_nonopt;
+ int top = optind;
+ char *tem;
- /* Interchange the two blocks of data in ARGV. */
+ /* Exchange the shorter segment with the far end of the longer segment.
+ That puts the shorter segment into the right place.
+ It leaves the longer segment in the right place overall,
+ but it consists of two parts that need to be swapped next. */
- my_bcopy (&argv[first_nonopt], temp, nonopts_size);
- my_bcopy (&argv[last_nonopt], &argv[first_nonopt],
- (optind - last_nonopt) * sizeof (char *));
- my_bcopy (temp, &argv[first_nonopt + optind - last_nonopt], nonopts_size);
+ while (top > middle && middle > bottom)
+ {
+ if (top - middle > middle - bottom)
+ {
+ /* Bottom segment is the short one. */
+ int len = middle - bottom;
+ register int i;
- free(temp);
+ /* Swap it with the top part of the top segment. */
+ for (i = 0; i < len; i++)
+ {
+ tem = argv[bottom + i];
+ argv[bottom + i] = argv[top - (middle - bottom) + i];
+ argv[top - (middle - bottom) + i] = tem;
+ }
+ /* Exclude the moved bottom segment from further swapping. */
+ top -= len;
+ }
+ else
+ {
+ /* Top segment is the short one. */
+ int len = top - middle;
+ register int i;
+
+ /* Swap it with the bottom part of the bottom segment. */
+ for (i = 0; i < len; i++)
+ {
+ tem = argv[bottom + i];
+ argv[bottom + i] = argv[middle + i];
+ argv[middle + i] = tem;
+ }
+ /* Exclude the moved top segment from further swapping. */
+ bottom += len;
+ }
+ }
/* Update records for the slots the non-options now occupy. */
@@ -394,8 +470,7 @@ _getopt_internal (argc, argv, optstring, longopts, longind, long_only)
int exact = 0;
int ambig = 0;
const struct option *pfound = NULL;
- int indfound = 0;
- extern int strncmp();
+ int indfound;
while (*s && *s != '=')
s++;
@@ -441,7 +516,7 @@ _getopt_internal (argc, argv, optstring, longopts, longind, long_only)
if (*s)
{
/* Don't test has_arg with >, because some C compilers don't
- allow it to be used on enums. */
+ allow it to be used on enums. */
if (pfound->has_arg)
optarg = s + 1;
else
@@ -473,7 +548,7 @@ _getopt_internal (argc, argv, optstring, longopts, longind, long_only)
fprintf (stderr, "%s: option `%s' requires an argument\n",
argv[0], argv[optind - 1]);
nextchar += strlen (nextchar);
- return '?';
+ return optstring[0] == ':' ? ':' : '?';
}
}
nextchar += strlen (nextchar);
@@ -489,7 +564,7 @@ _getopt_internal (argc, argv, optstring, longopts, longind, long_only)
/* Can't find it as a long option. If this is not getopt_long_only,
or the option starts with '--' or is not a valid short
option, then it's an error.
- Otherwise interpret it as a short option. */
+ Otherwise interpret it as a short option. */
if (!long_only || argv[optind][1] == '-'
#ifdef GETOPT_COMPAT
|| argv[optind][0] == '+'
@@ -527,12 +602,18 @@ _getopt_internal (argc, argv, optstring, longopts, longind, long_only)
{
if (opterr)
{
+#if 0
if (c < 040 || c >= 0177)
fprintf (stderr, "%s: unrecognized option, character code 0%o\n",
argv[0], c);
else
fprintf (stderr, "%s: unrecognized option `-%c'\n", argv[0], c);
+#else
+ /* 1003.2 specifies the format of this message. */
+ fprintf (stderr, "%s: illegal option -- %c\n", argv[0], c);
+#endif
}
+ optopt = c;
return '?';
}
if (temp[1] == ':')
@@ -562,9 +643,21 @@ _getopt_internal (argc, argv, optstring, longopts, longind, long_only)
else if (optind == argc)
{
if (opterr)
- fprintf (stderr, "%s: option `-%c' requires an argument\n",
- argv[0], c);
- c = '?';
+ {
+#if 0
+ fprintf (stderr, "%s: option `-%c' requires an argument\n",
+ argv[0], c);
+#else
+ /* 1003.2 specifies the format of this message. */
+ fprintf (stderr, "%s: option requires an argument -- %c\n",
+ argv[0], c);
+#endif
+ }
+ optopt = c;
+ if (optstring[0] == ':')
+ c = ':';
+ else
+ c = '?';
}
else
/* We already incremented `optind' once;
@@ -588,6 +681,8 @@ getopt (argc, argv, optstring)
(int *) 0,
0);
}
+
+#endif /* _LIBC or not __GNU_LIBRARY__. */
#ifdef TEST
diff --git a/gnu/usr.bin/awk/getopt.h b/gnu/usr.bin/awk/getopt.h
index de02743..b0fc4ff 100644
--- a/gnu/usr.bin/awk/getopt.h
+++ b/gnu/usr.bin/awk/getopt.h
@@ -1,19 +1,19 @@
/* Declarations for getopt.
- Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
+ Copyright (C) 1989, 1990, 1991, 1992, 1993 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify it
- under the terms of the GNU Library General Public License as published
- by the Free Software Foundation; either version 2, or (at your option)
- any later version.
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any
+ later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
- You should have received a copy of the GNU Library General Public
- License along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
#ifndef _GETOPT_H
#define _GETOPT_H 1
@@ -49,6 +49,10 @@ extern int optind;
extern int opterr;
+/* Set to an option character which was unrecognized. */
+
+extern int optopt;
+
/* Describe the long-named options requested by the application.
The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector
of `struct option' terminated by an element containing a name which is
@@ -72,7 +76,7 @@ extern int opterr;
struct option
{
-#if __STDC__
+#ifdef __STDC__
const char *name;
#else
char *name;
@@ -86,14 +90,11 @@ struct option
/* Names for the values of the `has_arg' field of `struct option'. */
-enum _argtype
-{
- no_argument,
- required_argument,
- optional_argument
-};
+#define no_argument 0
+#define required_argument 1
+#define optional_argument 2
-#if __STDC__
+#ifdef __STDC__
#if defined(__GNU_LIBRARY__)
/* Many other libraries have conflicting prototypes for getopt, with
differences in the consts, in stdlib.h. To avoid compilation
diff --git a/gnu/usr.bin/awk/getopt1.c b/gnu/usr.bin/awk/getopt1.c
index e2127cd..7739b51 100644
--- a/gnu/usr.bin/awk/getopt1.c
+++ b/gnu/usr.bin/awk/getopt1.c
@@ -1,40 +1,64 @@
-/* Getopt for GNU.
- Copyright (C) 1987, 88, 89, 90, 91, 1992 Free Software Foundation, Inc.
-
-This file is part of the libiberty library.
-Libiberty is free software; you can redistribute it and/or
-modify it under the terms of the GNU Library General Public
-License as published by the Free Software Foundation; either
-version 2 of the License, or (at your option) any later version.
-
-Libiberty is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-Library General Public License for more details.
-
-You should have received a copy of the GNU Library General Public
-License along with libiberty; see the file COPYING.LIB. If
-not, write to the Free Software Foundation, Inc., 675 Mass Ave,
-Cambridge, MA 02139, USA. */
+/* getopt_long and getopt_long_only entry points for GNU getopt.
+ Copyright (C) 1987, 88, 89, 90, 91, 92, 1993
+ Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any
+ later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
-#ifdef LIBC
-/* For when compiled as part of the GNU C library. */
-#include <ansidecl.h>
+#ifdef HAVE_CONFIG_H
+#if defined (emacs) || defined (CONFIG_BROKETS)
+/* We use <config.h> instead of "config.h" so that a compilation
+ using -I. -I$srcdir will use ./config.h rather than $srcdir/config.h
+ (which it would do because it found this file in $srcdir). */
+#include <config.h>
+#else
+#include "config.h"
+#endif
#endif
#include "getopt.h"
#ifndef __STDC__
+/* This is a separate conditional since some stdc systems
+ reject `defined (const)'. */
+#ifndef const
#define const
#endif
+#endif
+
+#include <stdio.h>
+
+/* Comment out all this code if we are using the GNU C Library, and are not
+ actually compiling the library itself. This code is part of the GNU C
+ Library, but also included in many other GNU distributions. Compiling
+ and linking in this code is a waste when using the GNU C library
+ (especially if it is a shared library). Rather than having every GNU
+ program understand `configure --with-gnu-libc' and omit the object files,
+ it is simpler to just do this in the source for each such file. */
+
+#if defined (_LIBC) || !defined (__GNU_LIBRARY__)
-#if defined(STDC_HEADERS) || defined(__GNU_LIBRARY__) || defined (LIBC)
+
+/* This needs to come after some library #include
+ to get __GNU_LIBRARY__ defined. */
+#if defined(__GNU_LIBRARY__) || defined(OS2) || defined(MSDOS) || defined(atarist)
#include <stdlib.h>
-#else /* STDC_HEADERS or __GNU_LIBRARY__ */
+#else
char *getenv ();
-#endif /* STDC_HEADERS or __GNU_LIBRARY__ */
+#endif
-#if !defined (NULL)
+#ifndef NULL
#define NULL 0
#endif
@@ -52,9 +76,9 @@ getopt_long (argc, argv, options, long_options, opt_index)
/* Like getopt_long, but '-' as well as '--' can indicate a long option.
If an option that starts with '-' (not '--') doesn't match a long option,
but does match a short option, it is parsed as a short option
- instead. */
+ instead. */
-int
+int
getopt_long_only (argc, argv, options, long_options, opt_index)
int argc;
char *const *argv;
@@ -64,6 +88,9 @@ getopt_long_only (argc, argv, options, long_options, opt_index)
{
return _getopt_internal (argc, argv, options, long_options, opt_index, 1);
}
+
+
+#endif /* _LIBC or not __GNU_LIBRARY__. */
#ifdef TEST
diff --git a/gnu/usr.bin/awk/io.c b/gnu/usr.bin/awk/io.c
index 7004aed..7f92556 100644
--- a/gnu/usr.bin/awk/io.c
+++ b/gnu/usr.bin/awk/io.c
@@ -2,27 +2,30 @@
* io.c --- routines for dealing with input and output and records
*/
-/*
- * Copyright (C) 1986, 1988, 1989, 1991, 1992 the Free Software Foundation, Inc.
- *
+/*
+ * Copyright (C) 1986, 1988, 1989, 1991, 1992, 1993 the Free Software Foundation, Inc.
+ *
* This file is part of GAWK, the GNU implementation of the
* AWK Progamming Language.
- *
+ *
* GAWK is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
- *
+ *
* GAWK is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
- *
+ *
* You should have received a copy of the GNU General Public License
* along with GAWK; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
+#if !defined(VMS) && !defined(VMS_POSIX) && !defined(_MSC_VER)
+#include <sys/param.h>
+#endif
#include "awk.h"
#ifndef O_RDONLY
@@ -33,13 +36,17 @@
#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
#endif
+#ifndef ENFILE
+#define ENFILE EMFILE
+#endif
+
#ifndef atarist
#define INVALID_HANDLE (-1)
#else
#define INVALID_HANDLE (__SMALLEST_VALID_HANDLE - 1)
#endif
-#if defined(MSDOS) || defined(atarist)
+#if defined(MSDOS) || defined(OS2) || defined(atarist)
#define PIPES_SIMULATED
#endif
@@ -48,17 +55,34 @@ static int inrec P((IOBUF *iop));
static int iop_close P((IOBUF *iop));
struct redirect *redirect P((NODE *tree, int *errflg));
static void close_one P((void));
-static int close_redir P((struct redirect *rp));
+static int close_redir P((struct redirect *rp, int exitwarn));
#ifndef PIPES_SIMULATED
static int wait_any P((int interesting));
#endif
static IOBUF *gawk_popen P((char *cmd, struct redirect *rp));
-static IOBUF *iop_open P((char *file, char *how));
+static IOBUF *iop_open P((const char *file, const char *how));
static int gawk_pclose P((struct redirect *rp));
-static int do_pathopen P((char *file));
+static int do_pathopen P((const char *file));
+static int str2mode P((const char *mode));
+static void spec_setup P((IOBUF *iop, int len, int allocate));
+static int specfdopen P((IOBUF *iop, const char *name, const char *mode));
+static int pidopen P((IOBUF *iop, const char *name, const char *mode));
+static int useropen P((IOBUF *iop, const char *name, const char *mode));
extern FILE *fdopen();
+
+#if defined (MSDOS)
+#include "popen.h"
+#define popen(c,m) os_popen(c,m)
+#define pclose(f) os_pclose(f)
+#elif defined (OS2) /* OS/2, but not family mode */
+#if defined (_MSC_VER)
+#define popen(c,m) _popen(c,m)
+#define pclose(f) _pclose(f)
+#endif
+#else
extern FILE *popen();
+#endif
static struct redirect *red_head = NULL;
@@ -87,7 +111,6 @@ int skipping;
static int i = 1;
static int files = 0;
NODE *arg;
- int fd = INVALID_HANDLE;
static IOBUF *curfile = NULL;
if (skipping) {
@@ -121,8 +144,7 @@ int skipping;
/* NOTREACHED */
/* This is a kludge. */
unref(FILENAME_node->var_value);
- FILENAME_node->var_value =
- dupnode(arg);
+ FILENAME_node->var_value = dupnode(arg);
FNR = 0;
i++;
break;
@@ -131,8 +153,8 @@ int skipping;
if (files == 0) {
files++;
/* no args. -- use stdin */
- /* FILENAME is init'ed to "-" */
/* FNR is init'ed to 0 */
+ FILENAME_node->var_value = make_string("-", 1);
curfile = iop_alloc(fileno(stdin));
}
return curfile;
@@ -141,13 +163,13 @@ int skipping;
void
set_FNR()
{
- FNR = (int) FNR_node->var_value->numbr;
+ FNR = (long) FNR_node->var_value->numbr;
}
void
set_NR()
{
- NR = (int) NR_node->var_value->numbr;
+ NR = (long) NR_node->var_value->numbr;
}
/*
@@ -218,7 +240,7 @@ IOBUF *iop;
if ((fields_arr[0]->stptr >= iop->buf)
&& (fields_arr[0]->stptr < iop->end)) {
NODE *t;
-
+
t = make_string(fields_arr[0]->stptr,
fields_arr[0]->stlen);
unref(fields_arr[0]);
@@ -238,12 +260,15 @@ do_input()
IOBUF *iop;
extern int exiting;
- if (setjmp(filebuf) != 0) {
- }
+ (void) setjmp(filebuf);
+
while ((iop = nextfile(0)) != NULL) {
if (inrec(iop) == 0)
while (interpret(expression_value) && inrec(iop) == 0)
- ;
+ continue;
+ /* recover any space from C based alloca */
+ (void) alloca(0);
+
if (exiting)
break;
}
@@ -260,10 +285,10 @@ int *errflg;
register char *str;
int tflag = 0;
int outflag = 0;
- char *direction = "to";
- char *mode;
+ const char *direction = "to";
+ const char *mode;
int fd;
- char *what = NULL;
+ const char *what = NULL;
switch (tree->type) {
case Node_redirect_append:
@@ -376,15 +401,19 @@ int *errflg;
rp->fp = stdout;
else if (fd == fileno(stderr))
rp->fp = stderr;
- else
- rp->fp = fdopen(fd, mode);
- if (isatty(fd))
+ else {
+ rp->fp = fdopen(fd, (char *) mode);
+ /* don't leak file descriptors */
+ if (rp->fp == NULL)
+ close(fd);
+ }
+ if (rp->fp != NULL && isatty(fd))
rp->flag |= RED_NOBUF;
}
}
if (rp->fp == NULL && rp->iop == NULL) {
/* too many files open -- close one and try again */
- if (errno == EMFILE)
+ if (errno == EMFILE || errno == ENFILE)
close_one();
else {
/*
@@ -434,7 +463,7 @@ close_one()
}
if (rp == NULL)
/* surely this is the only reason ??? */
- fatal("too many pipes or input files open");
+ fatal("too many pipes or input files open");
}
NODE *
@@ -454,16 +483,18 @@ NODE *tree;
if (rp == NULL) /* no match */
return tmp_number((AWKNUM) 0.0);
fflush(stdout); /* synchronize regular output */
- tmp = tmp_number((AWKNUM)close_redir(rp));
+ tmp = tmp_number((AWKNUM)close_redir(rp, 0));
rp = NULL;
return tmp;
}
static int
-close_redir(rp)
+close_redir(rp, exitwarn)
register struct redirect *rp;
+int exitwarn;
{
int status = 0;
+ char *what;
if (rp == NULL)
return 0;
@@ -482,14 +513,19 @@ register struct redirect *rp;
rp->iop = NULL;
}
}
+
+ what = (rp->flag & RED_PIPE) ? "pipe" : "file";
+
+ if (exitwarn)
+ warning("no explicit close of %s \"%s\" provided",
+ what, rp->value);
+
/* SVR4 awk checks and warns about status of close */
if (status) {
char *s = strerror(errno);
- warning("failure status (%d) on %s close of \"%s\" (%s).",
- status,
- (rp->flag & RED_PIPE) ? "pipe" :
- "file", rp->value, s);
+ warning("failure status (%d) on %s close of \"%s\" (%s)",
+ status, what, rp->value, s);
if (! do_unix) {
/* set ERRNO too so that program can get at it */
@@ -544,20 +580,27 @@ close_io ()
int status = 0;
errno = 0;
- if (fclose(stdout)) {
+ for (rp = red_head; rp != NULL; rp = next) {
+ next = rp->next;
+ /* close_redir() will print a message if needed */
+ /* if do_lint, warn about lack of explicit close */
+ if (close_redir(rp, do_lint))
+ status++;
+ rp = NULL;
+ }
+ /*
+ * Some of the non-Unix os's have problems doing an fclose
+ * on stdout and stderr. Since we don't really need to close
+ * them, we just flush them, and do that across the board.
+ */
+ if (fflush(stdout)) {
warning("error writing standard output (%s).", strerror(errno));
status++;
}
- if (fclose(stderr)) {
+ if (fflush(stderr)) {
warning("error writing standard error (%s).", strerror(errno));
status++;
}
- for (rp = red_head; rp != NULL; rp = next) {
- next = rp->next;
- if (close_redir(rp))
- status++;
- rp = NULL;
- }
return status;
}
@@ -565,7 +608,7 @@ close_io ()
static int
str2mode(mode)
-char *mode;
+const char *mode;
{
int ret;
@@ -581,7 +624,9 @@ char *mode;
case 'a':
ret = O_WRONLY|O_APPEND|O_CREAT;
break;
+
default:
+ ret = 0; /* lint */
cant_happen();
}
return ret;
@@ -598,10 +643,11 @@ char *mode;
int
devopen(name, mode)
-char *name, *mode;
+const char *name, *mode;
{
int openfd = INVALID_HANDLE;
- char *cp, *ptr;
+ const char *cp;
+ char *ptr;
int flag = 0;
struct stat buf;
extern double strtod();
@@ -618,9 +664,9 @@ char *name, *mode;
if (STREQ(name, "-"))
openfd = fileno(stdin);
- else if (STREQN(name, "/dev/", 5) && stat(name, &buf) == -1) {
+ else if (STREQN(name, "/dev/", 5) && stat((char *) name, &buf) == -1) {
cp = name + 5;
-
+
if (STREQ(cp, "stdin") && (flag & O_RDONLY) == O_RDONLY)
openfd = fileno(stdin);
else if (STREQ(cp, "stdout") && (flag & O_WRONLY) == O_WRONLY)
@@ -638,7 +684,7 @@ char *name, *mode;
strictopen:
if (openfd == INVALID_HANDLE)
openfd = open(name, flag, 0666);
- if (openfd != INVALID_HANDLE && fstat(openfd, &buf) > 0)
+ if (openfd != INVALID_HANDLE && fstat(openfd, &buf) > 0)
if (S_ISDIR(buf.st_mode))
fatal("file `%s' is a directory", name);
return openfd;
@@ -647,7 +693,7 @@ strictopen:
/* spec_setup --- setup an IOBUF for a special internal file */
-void
+static void
spec_setup(iop, len, allocate)
IOBUF *iop;
int len;
@@ -674,10 +720,10 @@ int allocate;
/* specfdopen --- open a fd special file */
-int
+static int
specfdopen(iop, name, mode)
IOBUF *iop;
-char *name, *mode;
+const char *name, *mode;
{
int fd;
IOBUF *tp;
@@ -694,23 +740,43 @@ char *name, *mode;
return 0;
}
+/*
+ * Following mess will improve in 2.16; this is written to avoid
+ * long lines, avoid splitting #if with backslash, and avoid #elif
+ * to maximize portability.
+ */
+#ifndef GETPGRP_NOARG
+#if defined(__svr4__) || defined(BSD4_4) || defined(_POSIX_SOURCE)
+#define GETPGRP_NOARG
+#else
+#if defined(i860) || defined(_AIX) || defined(hpux) || defined(VMS)
+#define GETPGRP_NOARG
+#else
+#if defined(OS2) || defined(MSDOS) || defined(AMIGA) || defined(atarist)
+#define GETPGRP_NOARG
+#endif
+#endif
+#endif
+#endif
+
+#ifdef GETPGRP_NOARG
+#define getpgrp_ARG /* nothing */
+#else
+#define getpgrp_ARG getpid()
+#endif
+
/* pidopen --- "open" /dev/pid, /dev/ppid, and /dev/pgrpid */
-int
+static int
pidopen(iop, name, mode)
IOBUF *iop;
-char *name, *mode;
+const char *name, *mode;
{
char tbuf[BUFSIZ];
int i;
if (name[6] == 'g')
-/* following #if will improve in 2.16 */
-#if defined(__svr4__) || defined(i860) || defined(_AIX) || defined(BSD4_4) || defined(__386BSD__)
- sprintf(tbuf, "%d\n", getpgrp());
-#else
- sprintf(tbuf, "%d\n", getpgrp(getpid()));
-#endif
+ sprintf(tbuf, "%d\n", getpgrp( getpgrp_ARG ));
else if (name[6] == 'i')
sprintf(tbuf, "%d\n", getpid());
else
@@ -733,15 +799,19 @@ char *name, *mode;
* supplementary group set.
*/
-int
+static int
useropen(iop, name, mode)
IOBUF *iop;
-char *name, *mode;
+const char *name, *mode;
{
char tbuf[BUFSIZ], *cp;
int i;
#if defined(NGROUPS_MAX) && NGROUPS_MAX > 0
+#if defined(atarist) || defined(__svr4__) || defined(__osf__) || defined(__FreeBSD__)
+ gid_t groupset[NGROUPS_MAX];
+#else
int groupset[NGROUPS_MAX];
+#endif
int ngroups;
#endif
@@ -755,7 +825,7 @@ char *name, *mode;
for (i = 0; i < ngroups; i++) {
*cp++ = ' ';
- sprintf(cp, "%d", groupset[i]);
+ sprintf(cp, "%d", (int)groupset[i]);
cp += strlen(cp);
}
#endif
@@ -773,18 +843,16 @@ char *name, *mode;
static IOBUF *
iop_open(name, mode)
-char *name, *mode;
+const char *name, *mode;
{
int openfd = INVALID_HANDLE;
- char *cp, *ptr;
int flag = 0;
- int i;
struct stat buf;
IOBUF *iop;
static struct internal {
- char *name;
+ const char *name;
int compare;
- int (*fp)();
+ int (*fp) P((IOBUF*,const char *,const char *));
IOBUF iob;
} table[] = {
{ "/dev/fd/", 8, specfdopen },
@@ -805,12 +873,12 @@ char *name, *mode;
if (STREQ(name, "-"))
openfd = fileno(stdin);
- else if (STREQN(name, "/dev/", 5) && stat(name, &buf) == -1) {
+ else if (STREQN(name, "/dev/", 5) && stat((char *) name, &buf) == -1) {
int i;
for (i = 0; i < devcount; i++) {
if (STREQN(name, table[i].name, table[i].compare)) {
- IOBUF *iop = & table[i].iob;
+ iop = & table[i].iob;
if (iop->buf != NULL) {
spec_setup(iop, 0, 0);
@@ -829,7 +897,7 @@ char *name, *mode;
strictopen:
if (openfd == INVALID_HANDLE)
openfd = open(name, flag, 0666);
- if (openfd != INVALID_HANDLE && fstat(openfd, &buf) > 0)
+ if (openfd != INVALID_HANDLE && fstat(openfd, &buf) > 0)
if ((buf.st_mode & S_IFMT) == S_IFDIR)
fatal("file `%s' is a directory", name);
iop = iop_alloc(openfd);
@@ -939,8 +1007,9 @@ struct redirect *rp;
#else /* PIPES_SIMULATED */
/* use temporary file rather than pipe */
+ /* except if popen() provides real pipes too */
-#ifdef VMS
+#if defined(VMS) || defined(OS2) || defined (MSDOS)
static IOBUF *
gawk_popen(cmd, rp)
char *cmd;
@@ -958,7 +1027,7 @@ gawk_pclose(rp)
struct redirect *rp;
{
int rval, aval, fd = rp->iop->fd;
- FILE *kludge = fdopen(fd, "r"); /* pclose needs FILE* w/ right fileno */
+ FILE *kludge = fdopen(fd, (char *) "r"); /* pclose needs FILE* w/ right fileno */
rp->iop->fd = dup(fd); /* kludge to allow close() + pclose() */
rval = iop_close(rp->iop);
@@ -966,7 +1035,7 @@ struct redirect *rp;
aval = pclose(kludge);
return (rval < 0 ? rval : aval);
}
-#else /* VMS */
+#else /* VMS || OS2 || MSDOS */
static
struct {
@@ -1016,7 +1085,7 @@ struct redirect *rp;
free(pipes[cur].command);
return rval;
}
-#endif /* VMS */
+#endif /* VMS || OS2 || MSDOS */
#endif /* PIPES_SIMULATED */
@@ -1041,7 +1110,7 @@ NODE *tree;
rp = redirect(tree->rnode, &redir_error);
if (rp == NULL && redir_error) { /* failed redirect */
if (! do_unix) {
- char *s = strerror(redir_error);
+ s = strerror(redir_error);
unref(ERRNO_node->var_value);
ERRNO_node->var_value =
@@ -1056,7 +1125,7 @@ NODE *tree;
errcode = 0;
cnt = get_a_record(&s, iop, *RS, & errcode);
if (! do_unix && errcode != 0) {
- char *s = strerror(errcode);
+ s = strerror(errcode);
unref(ERRNO_node->var_value);
ERRNO_node->var_value = make_string(s, strlen(s));
@@ -1102,7 +1171,7 @@ NODE *tree;
int
pathopen (file)
-char *file;
+const char *file;
{
int fd = do_pathopen(file);
@@ -1134,12 +1203,12 @@ char *file;
static int
do_pathopen (file)
-char *file;
+const char *file;
{
- static char *savepath = DEFPATH; /* defined in config.h */
+ static const char *savepath = DEFPATH; /* defined in config.h */
static int first = 1;
- char *awkpath, *cp;
- char trypath[BUFSIZ];
+ const char *awkpath;
+ char *cp, trypath[BUFSIZ];
int fd;
if (STREQ(file, "-"))
@@ -1160,7 +1229,7 @@ char *file;
if (strchr(file, ':') != strchr(file, ']')
|| strchr(file, '>') != strchr(file, '/'))
#else /*!VMS*/
-#ifdef MSDOS
+#if defined(MSDOS) || defined(OS2)
if (strchr(file, '/') != strchr(file, '\\')
|| strchr(file, ':') != NULL)
#else
@@ -1169,6 +1238,12 @@ char *file;
#endif /*VMS*/
return (devopen(file, "r"));
+#if defined(MSDOS) || defined(OS2)
+ _searchenv(file, "AWKPATH", trypath);
+ if (trypath[0] == '\0')
+ _searchenv(file, "PATH", trypath);
+ return (trypath[0] == '\0') ? 0 : devopen(trypath, "r");
+#else
do {
trypath[0] = '\0';
/* this should take into account limits on size of trypath */
@@ -1180,7 +1255,7 @@ char *file;
#ifdef VMS
if (strchr(":]>/", *(cp-1)) == NULL)
#else
-#ifdef MSDOS
+#if defined(MSDOS) || defined(OS2)
if (strchr(":\\/", *(cp-1)) == NULL)
#else
if (*(cp-1) != '/')
@@ -1204,4 +1279,5 @@ char *file;
* Therefore try to open the file in the current directory.
*/
return (devopen(file, "r"));
+#endif
}
diff --git a/gnu/usr.bin/awk/iop.c b/gnu/usr.bin/awk/iop.c
index 0d7af12..6b6a03b 100644
--- a/gnu/usr.bin/awk/iop.c
+++ b/gnu/usr.bin/awk/iop.c
@@ -2,22 +2,22 @@
* iop.c - do i/o related things.
*/
-/*
- * Copyright (C) 1986, 1988, 1989, 1991, 1992 the Free Software Foundation, Inc.
- *
+/*
+ * Copyright (C) 1986, 1988, 1989, 1991, 1992, 1993 the Free Software Foundation, Inc.
+ *
* This file is part of GAWK, the GNU implementation of the
* AWK Progamming Language.
- *
+ *
* GAWK is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
- *
+ *
* GAWK is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
- *
+ *
* You should have received a copy of the GNU General Public License
* along with GAWK; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
@@ -62,7 +62,7 @@ int fd;
else if (fstat(fd, &stb) < 0)
return 8*512; /* conservative in case of DECnet access */
else
- return 24*512;
+ return 32*512;
#else
/*
@@ -146,17 +146,16 @@ int *errcode;
register char *bp = iop->off;
char *bufend;
char *start = iop->off; /* beginning of record */
- int saw_newline;
char rs;
- int eat_whitespace;
+ int saw_newline = 0, eat_whitespace = 0; /* used iff grRS==0 */
- if (iop->cnt == EOF) /* previous read hit EOF */
+ if (iop->cnt == EOF) { /* previous read hit EOF */
+ *out = NULL;
return EOF;
+ }
if (grRS == 0) { /* special case: grRS == "" */
rs = '\n';
- eat_whitespace = 0;
- saw_newline = 0;
} else
rs = (char) grRS;
@@ -181,9 +180,6 @@ int *errcode;
char *oldsplit = iop->buf + iop->secsiz;
long len; /* record length so far */
- if ((iop->flag & IOP_IS_INTERNAL) != 0)
- cant_happen();
-
len = bp - start;
if (len > iop->secsiz) {
/* expand secondary buffer */
@@ -245,7 +241,8 @@ int *errcode;
extern int default_FS;
if (default_FS && (bp == start || eat_whitespace)) {
- while (bp < iop->end && isspace(*bp))
+ while (bp < iop->end
+ && (*bp == ' ' || *bp == '\t' || *bp == '\n'))
bp++;
if (bp == iop->end) {
eat_whitespace = 1;
@@ -275,8 +272,10 @@ int *errcode;
iop->cnt = bp - start;
}
if (iop->cnt == EOF
- && (((iop->flag & IOP_IS_INTERNAL) != 0) || start == bp))
+ && (((iop->flag & IOP_IS_INTERNAL) != 0) || start == bp)) {
+ *out = NULL;
return EOF;
+ }
iop->off = bp;
bp--;
@@ -284,6 +283,10 @@ int *errcode;
bp++;
*bp = '\0';
if (grRS == 0) {
+ /* there could be more newlines left, clean 'em out now */
+ while (*(iop->off) == rs && iop->off <= iop->end)
+ (iop->off)++;
+
if (*--bp == rs)
*bp = '\0';
else
diff --git a/gnu/usr.bin/awk/main.c b/gnu/usr.bin/awk/main.c
index 77d0bf7..1f483bc 100644
--- a/gnu/usr.bin/awk/main.c
+++ b/gnu/usr.bin/awk/main.c
@@ -1,28 +1,31 @@
/*
- * main.c -- Expression tree constructors and main program for gawk.
+ * main.c -- Expression tree constructors and main program for gawk.
*/
-/*
- * Copyright (C) 1986, 1988, 1989, 1991, 1992 the Free Software Foundation, Inc.
- *
+/*
+ * Copyright (C) 1986, 1988, 1989, 1991, 1992, 1993 the Free Software Foundation, Inc.
+ *
* This file is part of GAWK, the GNU implementation of the
* AWK Progamming Language.
- *
+ *
* GAWK is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
- *
+ *
* GAWK is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
- *
+ *
* You should have received a copy of the GNU General Public License
* along with GAWK; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
+#ifdef __FreeBSD__
+#include <locale.h>
+#endif
#include "getopt.h"
#include "awk.h"
#include "patchlevel.h"
@@ -55,9 +58,9 @@ NODE *ENVIRON_node, *IGNORECASE_node;
NODE *ARGC_node, *ARGV_node, *ARGIND_node;
NODE *FIELDWIDTHS_node;
-int NF;
-int NR;
-int FNR;
+long NF;
+long NR;
+long FNR;
int IGNORECASE;
char *RS;
char *OFS;
@@ -67,7 +70,7 @@ char *CONVFMT;
/*
* The parse tree and field nodes are stored here. Parse_end is a dummy item
- * used to free up unneeded fields without freeing the program being run
+ * used to free up unneeded fields without freeing the program being run
*/
int errcount = 0; /* error counter, used by yyerror() */
@@ -134,10 +137,22 @@ char **argv;
{
int c;
char *scan;
+ /* the + on the front tells GNU getopt not to rearrange argv */
+ const char *optlist = "+F:f:v:W:m:";
+ int stopped_early = 0;
+ int old_optind;
extern int optind;
extern int opterr;
extern char *optarg;
- int i;
+
+#ifdef __FreeBSD__
+ (void) setlocale(LC_CTYPE, "");
+#endif
+#ifdef __EMX__
+ _response(&argc, &argv);
+ _wildcard(&argc, &argv);
+ setvbuf(stdout, NULL, _IOLBF, BUFSIZ);
+#endif
(void) signal(SIGFPE, (SIGTYPE (*) P((int))) catchsig);
(void) signal(SIGSEGV, (SIGTYPE (*) P((int))) catchsig);
@@ -165,10 +180,9 @@ char **argv;
Nnull_string->flags = (PERM|STR|STRING|NUM|NUMBER);
/* Set up the special variables */
-
/*
* Note that this must be done BEFORE arg parsing else -F
- * breaks horribly
+ * breaks horribly
*/
init_vars();
@@ -179,11 +193,16 @@ char **argv;
/* Tell the regex routines how they should work. . . */
resetup();
+#ifdef fpsetmask
+ fpsetmask(~0xff);
+#endif
/* we do error messages ourselves on invalid options */
opterr = 0;
- /* the + on the front tells GNU getopt not to rearrange argv */
- while ((c = getopt_long(argc, argv, "+F:f:v:W:", optab, NULL)) != EOF) {
+ /* option processing. ready, set, go! */
+ for (optopt = 0, old_optind = 1;
+ (c = getopt_long(argc, argv, optlist, optab, NULL)) != EOF;
+ optopt = 0, old_optind = optind) {
if (do_posix)
opterr = 1;
switch (c) {
@@ -215,6 +234,19 @@ char **argv;
pre_assign(optarg);
break;
+ case 'm':
+ /*
+ * Research awk extension.
+ * -mf=nnn set # fields, gawk ignores
+ * -mr=nnn set record length, ditto
+ */
+ if (do_lint)
+ warning("-m[fr] option irrelevant");
+ if ((optarg[0] != 'r' && optarg[0] != 'f')
+ || optarg[1] != '=')
+ warning("-m option usage: -m[fn]=nnn");
+ break;
+
case 'W': /* gawk specific options */
gawk_option(optarg);
break;
@@ -233,7 +265,7 @@ char **argv;
break;
case 's':
- if (strlen(optarg) == 0)
+ if (optarg[0] == '\0')
warning("empty argument to --source ignored");
else {
srcfiles[++numfiles].stype = CMDLINE;
@@ -247,6 +279,14 @@ char **argv;
break;
#endif
+ case 0:
+ /*
+ * getopt_long found an option that sets a variable
+ * instead of returning a letter. Do nothing, just
+ * cycle around for the next one.
+ */
+ break;
+
case '?':
default:
/*
@@ -254,9 +294,27 @@ char **argv;
* option stops argument processing so that it can
* go into ARGV for the awk program to see. This
* makes use of ``#! /bin/gawk -f'' easier.
+ *
+ * However, it's never simple. If optopt is set,
+ * an option that requires an argument didn't get the
+ * argument. We care because if opterr is 0, then
+ * getopt_long won't print the error message for us.
*/
- if (! do_posix)
+ if (! do_posix
+ && (optopt == 0 || strchr(optlist, optopt) == NULL)) {
+ /*
+ * can't just do optind--. In case of an
+ * option with >=2 letters, getopt_long
+ * won't have incremented optind.
+ */
+ optind = old_optind;
+ stopped_early = 1;
goto out;
+ } else if (optopt)
+ /* Use 1003.2 required message format */
+ fprintf (stderr,
+ "%s: option requires an argument -- %c\n",
+ myname, optopt);
/* else
let getopt print error message for us */
break;
@@ -267,6 +325,14 @@ out:
if (do_nostalgia)
nostalgia();
+ /* check for POSIXLY_CORRECT environment variable */
+ if (! do_posix && getenv("POSIXLY_CORRECT") != NULL) {
+ do_posix = 1;
+ if (do_lint)
+ warning(
+ "environment variable `POSIXLY_CORRECT' set: turning on --posix");
+ }
+
/* POSIX compliance also implies no Unix extensions either */
if (do_posix)
do_unix = 1;
@@ -278,7 +344,7 @@ out:
output_is_tty = 1;
/* No -f or --source options, use next arg */
if (numfiles == -1) {
- if (optind > argc - 1) /* no args left */
+ if (optind > argc - 1 || stopped_early) /* no args left or no program */
usage(1);
srcfiles[++numfiles].stype = CMDLINE;
srcfiles[numfiles].val = argv[optind];
@@ -294,6 +360,10 @@ out:
/* Set up the field variables */
init_fields();
+ if (do_lint && begin_block == NULL && expression_value == NULL
+ && end_block == NULL)
+ warning("no program");
+
if (begin_block) {
in_begin_rule = 1;
(void) interpret(begin_block);
@@ -318,25 +388,29 @@ static void
usage(exitval)
int exitval;
{
- char *opt1 = " -f progfile [--]";
- char *opt2 = " [--] 'program'";
- char *regops = " [POSIX or GNU style options]";
+ const char *opt1 = " -f progfile [--]";
+#if defined(MSDOS) || defined(OS2) || defined(VMS)
+ const char *opt2 = " [--] \"program\"";
+#else
+ const char *opt2 = " [--] 'program'";
+#endif
+ const char *regops = " [POSIX or GNU style options]";
- version();
- fprintf(stderr, "usage: %s%s%s file ...\n %s%s%s file ...\n",
+ fprintf(stderr, "Usage:\t%s%s%s file ...\n\t%s%s%s file ...\n",
myname, regops, opt1, myname, regops, opt2);
/* GNU long options info. Gack. */
- fputs("\nPOSIX options:\t\tGNU long options:\n", stderr);
+ fputs("POSIX options:\t\tGNU long options:\n", stderr);
fputs("\t-f progfile\t\t--file=progfile\n", stderr);
fputs("\t-F fs\t\t\t--field-separator=fs\n", stderr);
fputs("\t-v var=val\t\t--assign=var=val\n", stderr);
+ fputs("\t-m[fr]=val\n", stderr);
fputs("\t-W compat\t\t--compat\n", stderr);
fputs("\t-W copyleft\t\t--copyleft\n", stderr);
fputs("\t-W copyright\t\t--copyright\n", stderr);
fputs("\t-W help\t\t\t--help\n", stderr);
fputs("\t-W lint\t\t\t--lint\n", stderr);
-#if 0
+#ifdef NOSTALGIA
fputs("\t-W nostalgia\t\t--nostalgia\n", stderr);
#endif
#ifdef DEBUG
@@ -371,7 +445,6 @@ GNU General Public License for more details.\n\
along with this program; if not, write to the Free Software\n\
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\n";
- version();
fputs(blurb_part1, stderr);
fputs(blurb_part2, stderr);
fputs(blurb_part3, stderr);
@@ -383,7 +456,8 @@ cmdline_fs(str)
char *str;
{
register NODE **tmp;
- int len = strlen(str);
+ /* int len = strlen(str); *//* don't do that - we want to
+ avoid mismatched types */
tmp = get_lhs(FS_node, (Func_ptr *) 0);
unref(*tmp);
@@ -400,7 +474,7 @@ char *str;
if (do_unix && ! do_posix)
str[0] = '\t';
}
- *tmp = make_str_node(str, len, SCAN); /* do process escapes */
+ *tmp = make_str_node(str, strlen(str), SCAN); /* do process escapes */
set_FS();
}
@@ -432,9 +506,9 @@ char **argv;
*/
struct varinit {
NODE **spec;
- char *name;
+ const char *name;
NODETYPE type;
- char *strval;
+ const char *strval;
AWKNUM numval;
Func_ptr assign;
};
@@ -446,7 +520,7 @@ static struct varinit varinit[] = {
{&FS_node, "FS", Node_FS, " ", 0, 0 },
{&RS_node, "RS", Node_RS, "\n", 0, set_RS },
{&IGNORECASE_node, "IGNORECASE", Node_IGNORECASE, 0, 0, set_IGNORECASE },
-{&FILENAME_node, "FILENAME", Node_var, "-", 0, 0 },
+{&FILENAME_node, "FILENAME", Node_var, "", 0, 0 },
{&OFS_node, "OFS", Node_OFS, " ", 0, set_OFS },
{&ORS_node, "ORS", Node_ORS, "\n", 0, set_ORS },
{&OFMT_node, "OFMT", Node_OFMT, "%.6g", 0, set_OFMT },
@@ -465,9 +539,10 @@ init_vars()
register struct varinit *vp;
for (vp = varinit; vp->name; vp++) {
- *(vp->spec) = install(vp->name,
+ *(vp->spec) = install((char *) vp->name,
node(vp->strval == 0 ? make_number(vp->numval)
- : make_string(vp->strval, strlen(vp->strval)),
+ : make_string((char *) vp->strval,
+ strlen(vp->strval)),
vp->type, (NODE *) NULL));
if (vp->assign)
(*(vp->assign))();
@@ -477,14 +552,14 @@ init_vars()
void
load_environ()
{
-#if !defined(MSDOS) && !(defined(VMS) && defined(__DECC))
+#if !defined(MSDOS) && !defined(OS2) && !(defined(VMS) && defined(__DECC))
extern char **environ;
#endif
register char *var, *val;
NODE **aptr;
register int i;
- ENVIRON_node = install("ENVIRON",
+ ENVIRON_node = install("ENVIRON",
node(Nnull_string, Node_var, (NODE *) NULL));
for (i = 0; environ[i]; i++) {
static char nullstr[] = "";
@@ -510,7 +585,8 @@ char *
arg_assign(arg)
char *arg;
{
- char *cp;
+ char *cp, *cp2;
+ int badvar;
Func_ptr after_assign = NULL;
NODE *var;
NODE *it;
@@ -519,6 +595,19 @@ char *arg;
cp = strchr(arg, '=');
if (cp != NULL) {
*cp++ = '\0';
+ /* first check that the variable name has valid syntax */
+ badvar = 0;
+ if (! isalpha(arg[0]) && arg[0] != '_')
+ badvar = 1;
+ else
+ for (cp2 = arg+1; *cp2; cp2++)
+ if (! isalnum(*cp2) && *cp2 != '_') {
+ badvar = 1;
+ break;
+ }
+ if (badvar)
+ fatal("illegal name `%s' in variable assignment", arg);
+
/*
* Recent versions of nawk expand escapes inside assignments.
* This makes sense, so we do it too.
@@ -657,7 +746,7 @@ char *optstr;
if (strncasecmp(cp, "source=", 7) != 0)
goto unknown;
cp += 7;
- if (strlen(cp) == 0)
+ if (cp[0] == '\0')
warning("empty argument to -Wsource ignored");
else {
srcfiles[++numfiles].stype = CMDLINE;
@@ -689,40 +778,43 @@ static void
version()
{
fprintf(stderr, "%s, patchlevel %d\n", version_string, PATCHLEVEL);
+ /* per GNU coding standards, exit successfully, do nothing else */
+ exit(0);
}
-/* static */
+/* this mess will improve in 2.16 */
char *
gawk_name(filespec)
char *filespec;
{
- char *p;
-
+ char *p;
+
#ifdef VMS /* "device:[root.][directory.subdir]GAWK.EXE;n" -> "GAWK" */
- char *q;
+ char *q;
- p = strrchr(filespec, ']'); /* directory punctuation */
- q = strrchr(filespec, '>'); /* alternate <international> punct */
+ p = strrchr(filespec, ']'); /* directory punctuation */
+ q = strrchr(filespec, '>'); /* alternate <international> punct */
- if (p == NULL || q > p) p = q;
+ if (p == NULL || q > p) p = q;
p = strdup(p == NULL ? filespec : (p + 1));
if ((q = strrchr(p, '.')) != NULL) *q = '\0'; /* strip .typ;vers */
return p;
#endif /*VMS*/
-#if defined(MSDOS) || defined(atarist)
- char *q;
+#if defined(MSDOS) || defined(OS2) || defined(atarist)
+ char *q;
- p = filespec;
-
- if (q = strrchr(p, '\\'))
- p = q + 1;
- if (q = strchr(p, '.'))
- *q = '\0';
- strlwr(p);
+ for (p = filespec; (p = strchr(p, '\\')); *p = '/')
+ ;
+ p = filespec;
+ if ((q = strrchr(p, '/')))
+ p = q + 1;
+ if ((q = strchr(p, '.')))
+ *q = '\0';
+ strlwr(p);
- return (p == NULL ? filespec : p);
+ return (p == NULL ? filespec : p);
#endif /* MSDOS || atarist */
/* "path/name" -> "name" */
diff --git a/gnu/usr.bin/awk/msg.c b/gnu/usr.bin/awk/msg.c
index b60fe9d..4244fd3 100644
--- a/gnu/usr.bin/awk/msg.c
+++ b/gnu/usr.bin/awk/msg.c
@@ -2,22 +2,22 @@
* msg.c - routines for error messages
*/
-/*
- * Copyright (C) 1986, 1988, 1989, 1991, 1992 the Free Software Foundation, Inc.
- *
+/*
+ * Copyright (C) 1986, 1988, 1989, 1991, 1992, 1993 the Free Software Foundation, Inc.
+ *
* This file is part of GAWK, the GNU implementation of the
* AWK Progamming Language.
- *
+ *
* GAWK is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
- *
+ *
* GAWK is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
- *
+ *
* You should have received a copy of the GNU General Public License
* along with GAWK; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
@@ -31,8 +31,8 @@ char *source = NULL;
/* VARARGS2 */
void
err(s, emsg, argp)
-char *s;
-char *emsg;
+const char *s;
+const char *emsg;
va_list argp;
{
char *file;
@@ -49,9 +49,10 @@ va_list argp;
}
if (FNR) {
file = FILENAME_node->var_value->stptr;
+ (void) putc('(', stderr);
if (file)
- (void) fprintf(stderr, "(FILENAME=%s ", file);
- (void) fprintf(stderr, "FNR=%d) ", FNR);
+ (void) fprintf(stderr, "FILENAME=%s ", file);
+ (void) fprintf(stderr, "FNR=%ld) ", FNR);
}
(void) fprintf(stderr, s);
vfprintf(stderr, emsg, argp);
diff --git a/gnu/usr.bin/awk/node.c b/gnu/usr.bin/awk/node.c
index 65ecb0e..748028b 100644
--- a/gnu/usr.bin/awk/node.c
+++ b/gnu/usr.bin/awk/node.c
@@ -2,22 +2,22 @@
* node.c -- routines for node management
*/
-/*
- * Copyright (C) 1986, 1988, 1989, 1991, 1992 the Free Software Foundation, Inc.
- *
+/*
+ * Copyright (C) 1986, 1988, 1989, 1991, 1992, 1993 the Free Software Foundation, Inc.
+ *
* This file is part of GAWK, the GNU implementation of the
* AWK Progamming Language.
- *
+ *
* GAWK is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
- *
+ *
* GAWK is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
- *
+ *
* You should have received a copy of the GNU General Public License
* along with GAWK; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
@@ -35,7 +35,7 @@ register NODE *n;
register char *cpend;
char save;
char *ptr;
- unsigned int newflags = 0;
+ unsigned int newflags;
#ifdef DEBUG
if (n == NULL)
@@ -69,7 +69,8 @@ register NODE *n;
if (n->flags & MAYBE_NUM) {
newflags = NUMBER;
n->flags &= ~MAYBE_NUM;
- }
+ } else
+ newflags = 0;
if (cpend - cp == 1) {
if (isdigit(*cp)) {
n->numbr = (AWKNUM)(*cp - '0');
@@ -98,10 +99,10 @@ register NODE *n;
/*
* the following lookup table is used as an optimization in force_string
- * (more complicated) variations on this theme didn't seem to pay off, but
+ * (more complicated) variations on this theme didn't seem to pay off, but
* systematic testing might be in order at some point
*/
-static char *values[] = {
+static const char *values[] = {
"0",
"1",
"2",
@@ -121,7 +122,7 @@ register NODE *s;
{
char buf[128];
register char *sp = buf;
- register long num = 0;
+ double val;
#ifdef DEBUG
if (s == NULL) cant_happen();
@@ -131,26 +132,56 @@ register NODE *s;
if (s->stref != 0) ; /*cant_happen();*/
#endif
- /* avoids floating point exception in DOS*/
- if ( s->numbr <= LONG_MAX && s->numbr >= -LONG_MAX)
- num = (long)s->numbr;
- if ((AWKNUM) num == s->numbr) { /* integral value */
+ /* not an integral value, or out of range */
+ if ((val = double_to_int(s->numbr)) != s->numbr
+ || val < LONG_MIN || val > LONG_MAX) {
+#ifdef GFMT_WORKAROUND
+ NODE *dummy, *r;
+ unsigned short oflags;
+ extern NODE *format_tree P((const char *, int, NODE *));
+ extern NODE **fmt_list; /* declared in eval.c */
+
+ /* create dummy node for a sole use of format_tree */
+ getnode(dummy);
+ dummy->lnode = s;
+ dummy->rnode = NULL;
+ oflags = s->flags;
+ s->flags |= PERM; /* prevent from freeing by format_tree() */
+ r = format_tree(CONVFMT, fmt_list[CONVFMTidx]->stlen, dummy);
+ s->flags = oflags;
+ s->stfmt = (char)CONVFMTidx;
+ s->stlen = r->stlen;
+ s->stptr = r->stptr;
+ freenode(r); /* Do not free_temp(r)! We want */
+ freenode(dummy); /* to keep s->stptr == r->stpr. */
+
+ goto no_malloc;
+#else
+ /*
+ * no need for a "replacement" formatting by gawk,
+ * just use sprintf
+ */
+ sprintf(sp, CONVFMT, s->numbr);
+ s->stlen = strlen(sp);
+ s->stfmt = (char)CONVFMTidx;
+#endif /* GFMT_WORKAROUND */
+ } else {
+ /* integral value */
+ /* force conversion to long only once */
+ register long num = (long) val;
if (num < NVAL && num >= 0) {
- sp = values[num];
+ sp = (char *) values[num];
s->stlen = 1;
} else {
(void) sprintf(sp, "%ld", num);
s->stlen = strlen(sp);
}
s->stfmt = -1;
- } else {
- (void) sprintf(sp, CONVFMT, s->numbr);
- s->stlen = strlen(sp);
- s->stfmt = (char)CONVFMTidx;
}
- s->stref = 1;
emalloc(s->stptr, char *, s->stlen + 2, "force_string");
memcpy(s->stptr, sp, s->stlen+1);
+no_malloc:
+ s->stref = 1;
s->flags |= STR;
return s;
}
@@ -182,7 +213,8 @@ NODE *n;
if (n->type == Node_val && (n->flags & STR)) {
r->stref = 1;
emalloc(r->stptr, char *, r->stlen + 2, "dupnode");
- memcpy(r->stptr, n->stptr, r->stlen+1);
+ memcpy(r->stptr, n->stptr, r->stlen);
+ r->stptr[r->stlen] = '\0';
}
return r;
}
@@ -228,7 +260,7 @@ int flags;
memcpy(r->stptr, s, len);
}
r->stptr[len] = '\0';
-
+
if (flags & SCAN) { /* scan for escape sequences */
char *pf;
register char *ptm;
@@ -285,8 +317,10 @@ more_nodes()
/* get more nodes and initialize list */
emalloc(nextfree, NODE *, NODECHUNK * sizeof(NODE), "newnode");
- for (np = nextfree; np < &nextfree[NODECHUNK - 1]; np++)
+ for (np = nextfree; np < &nextfree[NODECHUNK - 1]; np++) {
+ np->flags = 0;
np->nextp = np + 1;
+ }
np->nextp = NULL;
np = nextfree;
nextfree = nextfree->nextp;
@@ -334,16 +368,16 @@ register NODE *tmp;
/*
* Parse a C escape sequence. STRING_PTR points to a variable containing a
* pointer to the string to parse. That pointer is updated past the
- * characters we use. The value of the escape sequence is returned.
+ * characters we use. The value of the escape sequence is returned.
*
* A negative value means the sequence \ newline was seen, which is supposed to
- * be equivalent to nothing at all.
+ * be equivalent to nothing at all.
*
* If \ is followed by a null character, we return a negative value and leave
- * the string pointer pointing at the null character.
+ * the string pointer pointing at the null character.
*
* If \ is followed by 000, we return 0 and leave the string pointer after the
- * zeros. A value of 0 does not mean end of string.
+ * zeros. A value of 0 does not mean end of string.
*
* Posix doesn't allow \x.
*/
diff --git a/gnu/usr.bin/awk/patchlevel.h b/gnu/usr.bin/awk/patchlevel.h
index c6161a1..c80ca15 100644
--- a/gnu/usr.bin/awk/patchlevel.h
+++ b/gnu/usr.bin/awk/patchlevel.h
@@ -1 +1 @@
-#define PATCHLEVEL 2
+#define PATCHLEVEL 5
diff --git a/gnu/usr.bin/awk/protos.h b/gnu/usr.bin/awk/protos.h
index 25af321..62e933a 100644
--- a/gnu/usr.bin/awk/protos.h
+++ b/gnu/usr.bin/awk/protos.h
@@ -2,22 +2,22 @@
* protos.h -- function prototypes for when the headers don't have them.
*/
-/*
- * Copyright (C) 1991, 1992, the Free Software Foundation, Inc.
- *
+/*
+ * Copyright (C) 1991, 1992, 1993 the Free Software Foundation, Inc.
+ *
* This file is part of GAWK, the GNU implementation of the
* AWK Progamming Language.
- *
+ *
* GAWK is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
- *
+ *
* GAWK is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
- *
+ *
* You should have received a copy of the GNU General Public License
* along with GAWK; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
@@ -32,14 +32,16 @@ extern aptr_t malloc P((MALLOC_ARG_T));
extern aptr_t realloc P((aptr_t, MALLOC_ARG_T));
extern aptr_t calloc P((MALLOC_ARG_T, MALLOC_ARG_T));
+#if !defined(sun) && !defined(__sun__)
extern void free P((aptr_t));
-extern char *getenv P((char *));
+#endif
+extern char *getenv P((const char *));
extern char *strcpy P((char *, const char *));
extern char *strcat P((char *, const char *));
-extern char *strncpy P((char *, const char *, int));
extern int strcmp P((const char *, const char *));
-extern int strncmp P((const char *, const char *, int));
+extern char *strncpy P((char *, const char *, size_t));
+extern int strncmp P((const char *, const char *, size_t));
#ifndef VMS
extern char *strerror P((int));
#else
@@ -48,22 +50,29 @@ extern char *strerror P((int,...));
extern char *strchr P((const char *, int));
extern char *strrchr P((const char *, int));
extern char *strstr P((const char *s1, const char *s2));
-extern int strlen P((const char *));
+extern size_t strlen P((const char *));
extern long strtol P((const char *, char **, int));
#if !defined(_MSC_VER) && !defined(__GNU_LIBRARY__)
-extern int strftime P((char *, int, const char *, const struct tm *));
+extern size_t strftime P((char *, size_t, const char *, const struct tm *));
#endif
+#ifdef __STDC__
extern time_t time P((time_t *));
+#else
+extern long time();
+#endif
extern aptr_t memset P((aptr_t, int, size_t));
extern aptr_t memcpy P((aptr_t, const aptr_t, size_t));
extern aptr_t memmove P((aptr_t, const aptr_t, size_t));
extern aptr_t memchr P((const aptr_t, int, size_t));
extern int memcmp P((const aptr_t, const aptr_t, size_t));
-/* extern int fprintf P((FILE *, char *, ...)); */
-extern int fprintf P(());
+extern int fprintf P((FILE *, const char *, ...));
#if !defined(MSDOS) && !defined(__GNU_LIBRARY__)
-extern int fwrite P((const char *, int, int, FILE *));
+#ifdef __STDC__
+extern size_t fwrite P((const aptr_t, size_t, size_t, FILE *));
+#else
+extern int fwrite();
+#endif
extern int fputs P((const char *, FILE *));
extern int unlink P((const char *));
#endif
@@ -75,7 +84,7 @@ extern void abort P(());
extern int isatty P((int));
extern void exit P((int));
extern int system P((const char *));
-extern int sscanf P((/* char *, char *, ... */));
+extern int sscanf P((const char *, const char *, ...));
#ifndef toupper
extern int toupper P((int));
#endif
@@ -84,32 +93,30 @@ extern int tolower P((int));
#endif
extern double pow P((double x, double y));
-extern double atof P((char *));
+extern double atof P((const char *));
extern double strtod P((const char *, char **));
extern int fstat P((int, struct stat *));
extern int stat P((const char *, struct stat *));
extern off_t lseek P((int, off_t, int));
extern int fseek P((FILE *, long, int));
extern int close P((int));
-extern int creat P(());
-extern int open P(());
+extern int creat P((const char *, mode_t));
+extern int open P((const char *, int, ...));
extern int pipe P((int *));
extern int dup P((int));
extern int dup2 P((int,int));
extern int fork P(());
extern int execl P((/* char *, char *, ... */));
+#ifndef __STDC__
extern int read P((int, char *, int));
+#endif
extern int wait P((int *));
extern void _exit P((int));
-#ifndef __STDC__
-extern long time P((long *));
-#endif
-
#ifdef NON_STD_SPRINTF
-extern char *sprintf();
+extern char *sprintf P((char *, const char*, ...));
#else
-extern int sprintf();
+extern int sprintf P((char *, const char*, ...));
#endif /* SPRINTF_INT */
#undef aptr_t
diff --git a/gnu/usr.bin/awk/re.c b/gnu/usr.bin/awk/re.c
index 495b096..5ee1c43 100644
--- a/gnu/usr.bin/awk/re.c
+++ b/gnu/usr.bin/awk/re.c
@@ -2,22 +2,22 @@
* re.c - compile regular expressions.
*/
-/*
- * Copyright (C) 1991, 1992 the Free Software Foundation, Inc.
- *
+/*
+ * Copyright (C) 1991, 1992, 1993 the Free Software Foundation, Inc.
+ *
* This file is part of GAWK, the GNU implementation of the
* AWK Progamming Language.
- *
+ *
* GAWK is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
- *
+ *
* GAWK is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
- *
+ *
* You should have received a copy of the GNU General Public License
* along with GAWK; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
@@ -30,12 +30,12 @@
Regexp *
make_regexp(s, len, ignorecase, dfa)
char *s;
-int len;
+size_t len;
int ignorecase;
int dfa;
{
Regexp *rp;
- char *err;
+ const char *rerr;
char *src = s;
char *temp;
char *end = s + len;
@@ -46,7 +46,7 @@ int dfa;
/* Build a copy of the string (in dest) with the
escaped characters translated, and generate the regex
- from that.
+ from that.
*/
emalloc(dest, char *, len + 2, "make_regexp");
temp = dest;
@@ -90,7 +90,7 @@ int dfa;
*dest = '\0' ; /* Only necessary if we print dest ? */
emalloc(rp, Regexp *, sizeof(*rp), "make_regexp");
memset((char *) rp, 0, sizeof(*rp));
- emalloc(rp->pat.buffer, char *, 16, "make_regexp");
+ emalloc(rp->pat.buffer, unsigned char *, 16, "make_regexp");
rp->pat.allocated = 16;
emalloc(rp->pat.fastmap, char *, 256, "make_regexp");
@@ -99,13 +99,14 @@ int dfa;
else
rp->pat.translate = NULL;
len = dest - temp;
- if ((err = re_compile_pattern(temp, (size_t) len, &(rp->pat))) != NULL)
- fatal("%s: /%s/", err, temp);
+ if ((rerr = re_compile_pattern(temp, len, &(rp->pat))) != NULL)
+ fatal("%s: /%s/", rerr, temp);
if (dfa && !ignorecase) {
- regcompile(temp, len, &(rp->dfareg), 1);
+ dfacomp(temp, len, &(rp->dfareg), 1);
rp->dfa = 1;
} else
rp->dfa = 0;
+
free(temp);
return rp;
}
@@ -115,24 +116,24 @@ research(rp, str, start, len, need_start)
Regexp *rp;
register char *str;
int start;
-register int len;
+register size_t len;
int need_start;
{
char *ret = str;
if (rp->dfa) {
- char save1;
- char save2;
+ char save;
int count = 0;
int try_backref;
- save1 = str[start+len];
- str[start+len] = '\n';
- save2 = str[start+len+1];
- ret = regexecute(&(rp->dfareg), str+start, str+start+len+1, 1,
+ /*
+ * dfa likes to stick a '\n' right after the matched
+ * text. So we just save and restore the character.
+ */
+ save = str[start+len];
+ ret = dfaexec(&(rp->dfareg), str+start, str+start+len, 1,
&count, &try_backref);
- str[start+len] = save1;
- str[start+len+1] = save2;
+ str[start+len] = save;
}
if (ret) {
if (need_start || rp->dfa == 0)
@@ -151,12 +152,12 @@ Regexp *rp;
free(rp->pat.buffer);
free(rp->pat.fastmap);
if (rp->dfa)
- reg_free(&(rp->dfareg));
+ dfafree(&(rp->dfareg));
free(rp);
}
void
-reg_error(s)
+dfaerror(s)
const char *s;
{
fatal(s);
@@ -194,7 +195,8 @@ NODE *t;
t->re_text = dupnode(t1);
free_temp(t1);
}
- t->re_reg = make_regexp(t->re_text->stptr, t->re_text->stlen, IGNORECASE, t->re_cnt);
+ t->re_reg = make_regexp(t->re_text->stptr, t->re_text->stlen,
+ IGNORECASE, t->re_cnt);
t->re_flags &= ~CASE;
t->re_flags |= IGNORECASE;
return t->re_reg;
@@ -203,6 +205,8 @@ NODE *t;
void
resetup()
{
- (void) re_set_syntax(RE_SYNTAX_AWK);
- regsyntax(RE_SYNTAX_AWK, 0);
+ reg_syntax_t syn = RE_SYNTAX_AWK;
+
+ (void) re_set_syntax(syn);
+ dfasyntax(syn, 0);
}
diff --git a/gnu/usr.bin/awk/regex.c b/gnu/usr.bin/awk/regex.c
deleted file mode 100644
index f4dd4c2..0000000
--- a/gnu/usr.bin/awk/regex.c
+++ /dev/null
@@ -1,2854 +0,0 @@
-/* Extended regular expression matching and search library.
- Copyright (C) 1985, 1989-90 Free Software Foundation, Inc.
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 1, or (at your option)
- any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
-
-
-/* To test, compile with -Dtest. This Dtestable feature turns this into
- a self-contained program which reads a pattern, describes how it
- compiles, then reads a string and searches for it.
-
- On the other hand, if you compile with both -Dtest and -Dcanned you
- can run some tests we've already thought of. */
-
-
-#ifdef emacs
-
-/* The `emacs' switch turns on certain special matching commands
- that make sense only in emacs. */
-
-#include "lisp.h"
-#include "buffer.h"
-#include "syntax.h"
-
-/* We write fatal error messages on standard error. */
-#include <stdio.h>
-
-/* isalpha(3) etc. are used for the character classes. */
-#include <ctype.h>
-
-#else /* not emacs */
-
-#include "awk.h"
-
-#define NO_ALLOCA /* try it out for now */
-#ifndef NO_ALLOCA
-/* Make alloca work the best possible way. */
-#ifdef __GNUC__
-#ifndef atarist
-#ifndef alloca
-#define alloca __builtin_alloca
-#endif
-#endif /* atarist */
-#else
-#if defined(sparc) && !defined(__GNUC__)
-#include <alloca.h>
-#else
-char *alloca ();
-#endif
-#endif /* __GNUC__ */
-
-#define FREE_AND_RETURN_VOID(stackb) return
-#define FREE_AND_RETURN(stackb,val) return(val)
-#define DOUBLE_STACK(stackx,stackb,len) \
- (stackx = (unsigned char **) alloca (2 * len \
- * sizeof (unsigned char *)),\
- /* Only copy what is in use. */ \
- (unsigned char **) memcpy (stackx, stackb, len * sizeof (char *)))
-#else /* NO_ALLOCA defined */
-#define FREE_AND_RETURN_VOID(stackb) free(stackb);return
-#define FREE_AND_RETURN(stackb,val) free(stackb);return(val)
-#define DOUBLE_STACK(stackx,stackb,len) \
- (unsigned char **) realloc (stackb, 2 * len * sizeof (unsigned char *))
-#endif /* NO_ALLOCA */
-
-static void store_jump P((char *, int, char *));
-static void insert_jump P((int, char *, char *, char *));
-static void store_jump_n P((char *, int, char *, unsigned));
-static void insert_jump_n P((int, char *, char *, char *, unsigned));
-static void insert_op_2 P((int, char *, char *, int, int ));
-static int memcmp_translate P((unsigned char *, unsigned char *,
- int, unsigned char *));
-long re_set_syntax P((long));
-
-/* Define the syntax stuff, so we can do the \<, \>, etc. */
-
-/* This must be nonzero for the wordchar and notwordchar pattern
- commands in re_match_2. */
-#ifndef Sword
-#define Sword 1
-#endif
-
-#define SYNTAX(c) re_syntax_table[c]
-
-
-#ifdef SYNTAX_TABLE
-
-char *re_syntax_table;
-
-#else /* not SYNTAX_TABLE */
-
-static char re_syntax_table[256];
-static void init_syntax_once P((void));
-
-
-static void
-init_syntax_once ()
-{
- register int c;
- static int done = 0;
-
- if (done)
- return;
-
- memset (re_syntax_table, 0, sizeof re_syntax_table);
-
- for (c = 'a'; c <= 'z'; c++)
- re_syntax_table[c] = Sword;
-
- for (c = 'A'; c <= 'Z'; c++)
- re_syntax_table[c] = Sword;
-
- for (c = '0'; c <= '9'; c++)
- re_syntax_table[c] = Sword;
-
- /* Add specific syntax for ISO Latin-1. */
- for (c = 0300; c <= 0377; c++)
- re_syntax_table[c] = Sword;
- re_syntax_table[0327] = 0;
- re_syntax_table[0367] = 0;
-
- done = 1;
-}
-
-#endif /* SYNTAX_TABLE */
-#undef P
-#endif /* emacs */
-
-
-/* Sequents are missing isgraph. */
-#ifndef isgraph
-#define isgraph(c) (isprint((c)) && !isspace((c)))
-#endif
-
-/* Get the interface, including the syntax bits. */
-#include "regex.h"
-
-
-/* These are the command codes that appear in compiled regular
- expressions, one per byte. Some command codes are followed by
- argument bytes. A command code can specify any interpretation
- whatsoever for its arguments. Zero-bytes may appear in the compiled
- regular expression.
-
- The value of `exactn' is needed in search.c (search_buffer) in emacs.
- So regex.h defines a symbol `RE_EXACTN_VALUE' to be 1; the value of
- `exactn' we use here must also be 1. */
-
-enum regexpcode
- {
- unused=0,
- exactn=1, /* Followed by one byte giving n, then by n literal bytes. */
- begline, /* Fail unless at beginning of line. */
- endline, /* Fail unless at end of line. */
- jump, /* Followed by two bytes giving relative address to jump to. */
- on_failure_jump, /* Followed by two bytes giving relative address of
- place to resume at in case of failure. */
- finalize_jump, /* Throw away latest failure point and then jump to
- address. */
- maybe_finalize_jump, /* Like jump but finalize if safe to do so.
- This is used to jump back to the beginning
- of a repeat. If the command that follows
- this jump is clearly incompatible with the
- one at the beginning of the repeat, such that
- we can be sure that there is no use backtracking
- out of repetitions already completed,
- then we finalize. */
- dummy_failure_jump, /* Jump, and push a dummy failure point. This
- failure point will be thrown away if an attempt
- is made to use it for a failure. A + construct
- makes this before the first repeat. Also
- use it as an intermediary kind of jump when
- compiling an or construct. */
- succeed_n, /* Used like on_failure_jump except has to succeed n times;
- then gets turned into an on_failure_jump. The relative
- address following it is useless until then. The
- address is followed by two bytes containing n. */
- jump_n, /* Similar to jump, but jump n times only; also the relative
- address following is in turn followed by yet two more bytes
- containing n. */
- set_number_at, /* Set the following relative location to the
- subsequent number. */
- anychar, /* Matches any (more or less) one character. */
- charset, /* Matches any one char belonging to specified set.
- First following byte is number of bitmap bytes.
- Then come bytes for a bitmap saying which chars are in.
- Bits in each byte are ordered low-bit-first.
- A character is in the set if its bit is 1.
- A character too large to have a bit in the map
- is automatically not in the set. */
- charset_not, /* Same parameters as charset, but match any character
- that is not one of those specified. */
- start_memory, /* Start remembering the text that is matched, for
- storing in a memory register. Followed by one
- byte containing the register number. Register numbers
- must be in the range 0 through RE_NREGS. */
- stop_memory, /* Stop remembering the text that is matched
- and store it in a memory register. Followed by
- one byte containing the register number. Register
- numbers must be in the range 0 through RE_NREGS. */
- duplicate, /* Match a duplicate of something remembered.
- Followed by one byte containing the index of the memory
- register. */
- before_dot, /* Succeeds if before point. */
- at_dot, /* Succeeds if at point. */
- after_dot, /* Succeeds if after point. */
- begbuf, /* Succeeds if at beginning of buffer. */
- endbuf, /* Succeeds if at end of buffer. */
- wordchar, /* Matches any word-constituent character. */
- notwordchar, /* Matches any char that is not a word-constituent. */
- wordbeg, /* Succeeds if at word beginning. */
- wordend, /* Succeeds if at word end. */
- wordbound, /* Succeeds if at a word boundary. */
- notwordbound,/* Succeeds if not at a word boundary. */
- syntaxspec, /* Matches any character whose syntax is specified.
- followed by a byte which contains a syntax code,
- e.g., Sword. */
- notsyntaxspec /* Matches any character whose syntax differs from
- that specified. */
- };
-
-
-/* Number of failure points to allocate space for initially,
- when matching. If this number is exceeded, more space is allocated,
- so it is not a hard limit. */
-
-#ifndef NFAILURES
-#define NFAILURES 80
-#endif
-
-#ifdef CHAR_UNSIGNED
-#define SIGN_EXTEND_CHAR(c) ((c)>(char)127?(c)-256:(c)) /* for IBM RT */
-#endif
-#ifndef SIGN_EXTEND_CHAR
-#define SIGN_EXTEND_CHAR(x) (x)
-#endif
-
-
-/* Store NUMBER in two contiguous bytes starting at DESTINATION. */
-#define STORE_NUMBER(destination, number) \
- { (destination)[0] = (number) & 0377; \
- (destination)[1] = (number) >> 8; }
-
-/* Same as STORE_NUMBER, except increment the destination pointer to
- the byte after where the number is stored. Watch out that values for
- DESTINATION such as p + 1 won't work, whereas p will. */
-#define STORE_NUMBER_AND_INCR(destination, number) \
- { STORE_NUMBER(destination, number); \
- (destination) += 2; }
-
-
-/* Put into DESTINATION a number stored in two contingous bytes starting
- at SOURCE. */
-#define EXTRACT_NUMBER(destination, source) \
- { (destination) = *(source) & 0377; \
- (destination) += SIGN_EXTEND_CHAR (*(char *)((source) + 1)) << 8; }
-
-/* Same as EXTRACT_NUMBER, except increment the pointer for source to
- point to second byte of SOURCE. Note that SOURCE has to be a value
- such as p, not, e.g., p + 1. */
-#define EXTRACT_NUMBER_AND_INCR(destination, source) \
- { EXTRACT_NUMBER (destination, source); \
- (source) += 2; }
-
-
-/* Specify the precise syntax of regexps for compilation. This provides
- for compatibility for various utilities which historically have
- different, incompatible syntaxes.
-
- The argument SYNTAX is a bit-mask comprised of the various bits
- defined in regex.h. */
-
-long
-re_set_syntax (syntax)
- long syntax;
-{
- long ret;
-
- ret = obscure_syntax;
- obscure_syntax = syntax;
- return ret;
-}
-
-/* Set by re_set_syntax to the current regexp syntax to recognize. */
-long obscure_syntax = 0;
-
-
-
-/* Macros for re_compile_pattern, which is found below these definitions. */
-
-#define CHAR_CLASS_MAX_LENGTH 6
-
-/* Fetch the next character in the uncompiled pattern, translating it if
- necessary. */
-#define PATFETCH(c) \
- {if (p == pend) goto end_of_pattern; \
- c = * (unsigned char *) p++; \
- if (translate) c = translate[c]; }
-
-/* Fetch the next character in the uncompiled pattern, with no
- translation. */
-#define PATFETCH_RAW(c) \
- {if (p == pend) goto end_of_pattern; \
- c = * (unsigned char *) p++; }
-
-#define PATUNFETCH p--
-
-
-/* If the buffer isn't allocated when it comes in, use this. */
-#define INIT_BUF_SIZE 28
-
-/* Make sure we have at least N more bytes of space in buffer. */
-#define GET_BUFFER_SPACE(n) \
- { \
- while (b - bufp->buffer + (n) >= bufp->allocated) \
- EXTEND_BUFFER; \
- }
-
-/* Make sure we have one more byte of buffer space and then add CH to it. */
-#define BUFPUSH(ch) \
- { \
- GET_BUFFER_SPACE (1); \
- *b++ = (char) (ch); \
- }
-
-/* Extend the buffer by twice its current size via reallociation and
- reset the pointers that pointed into the old allocation to point to
- the correct places in the new allocation. If extending the buffer
- results in it being larger than 1 << 16, then flag memory exhausted. */
-#define EXTEND_BUFFER \
- { char *old_buffer = bufp->buffer; \
- if (bufp->allocated == (1L<<16)) goto too_big; \
- bufp->allocated *= 2; \
- if (bufp->allocated > (1L<<16)) bufp->allocated = (1L<<16); \
- bufp->buffer = (char *) realloc (bufp->buffer, bufp->allocated); \
- if (bufp->buffer == 0) \
- goto memory_exhausted; \
- b = (b - old_buffer) + bufp->buffer; \
- if (fixup_jump) \
- fixup_jump = (fixup_jump - old_buffer) + bufp->buffer; \
- if (laststart) \
- laststart = (laststart - old_buffer) + bufp->buffer; \
- begalt = (begalt - old_buffer) + bufp->buffer; \
- if (pending_exact) \
- pending_exact = (pending_exact - old_buffer) + bufp->buffer; \
- }
-
-/* Set the bit for character C in a character set list. */
-#define SET_LIST_BIT(c) (b[(c) / BYTEWIDTH] |= 1 << ((c) % BYTEWIDTH))
-
-/* Get the next unsigned number in the uncompiled pattern. */
-#define GET_UNSIGNED_NUMBER(num) \
- { if (p != pend) \
- { \
- PATFETCH (c); \
- while (isdigit (c)) \
- { \
- if (num < 0) \
- num = 0; \
- num = num * 10 + c - '0'; \
- if (p == pend) \
- break; \
- PATFETCH (c); \
- } \
- } \
- }
-
-/* Subroutines for re_compile_pattern. */
-/* static void store_jump (), insert_jump (), store_jump_n (),
- insert_jump_n (), insert_op_2 (); */
-
-
-/* re_compile_pattern takes a regular-expression string
- and converts it into a buffer full of byte commands for matching.
-
- PATTERN is the address of the pattern string
- SIZE is the length of it.
- BUFP is a struct re_pattern_buffer * which points to the info
- on where to store the byte commands.
- This structure contains a char * which points to the
- actual space, which should have been obtained with malloc.
- re_compile_pattern may use realloc to grow the buffer space.
-
- The number of bytes of commands can be found out by looking in
- the `struct re_pattern_buffer' that bufp pointed to, after
- re_compile_pattern returns. */
-
-char *
-re_compile_pattern (pattern, size, bufp)
- char *pattern;
- size_t size;
- struct re_pattern_buffer *bufp;
-{
- register char *b = bufp->buffer;
- register char *p = pattern;
- char *pend = pattern + size;
- register unsigned c, c1;
- char *p0;
- unsigned char *translate = (unsigned char *) bufp->translate;
-
- /* Address of the count-byte of the most recently inserted `exactn'
- command. This makes it possible to tell whether a new exact-match
- character can be added to that command or requires a new `exactn'
- command. */
-
- char *pending_exact = 0;
-
- /* Address of the place where a forward-jump should go to the end of
- the containing expression. Each alternative of an `or', except the
- last, ends with a forward-jump of this sort. */
-
- char *fixup_jump = 0;
-
- /* Address of start of the most recently finished expression.
- This tells postfix * where to find the start of its operand. */
-
- char *laststart = 0;
-
- /* In processing a repeat, 1 means zero matches is allowed. */
-
- char zero_times_ok;
-
- /* In processing a repeat, 1 means many matches is allowed. */
-
- char many_times_ok;
-
- /* Address of beginning of regexp, or inside of last \(. */
-
- char *begalt = b;
-
- /* In processing an interval, at least this many matches must be made. */
- int lower_bound;
-
- /* In processing an interval, at most this many matches can be made. */
- int upper_bound;
-
- /* Place in pattern (i.e., the {) to which to go back if the interval
- is invalid. */
- char *beg_interval = 0;
-
- /* Stack of information saved by \( and restored by \).
- Four stack elements are pushed by each \(:
- First, the value of b.
- Second, the value of fixup_jump.
- Third, the value of regnum.
- Fourth, the value of begalt. */
-
- int stackb[40];
- int *stackp = stackb;
- int *stacke = stackb + 40;
- int *stackt;
-
- /* Counts \('s as they are encountered. Remembered for the matching \),
- where it becomes the register number to put in the stop_memory
- command. */
-
- int regnum = 1;
-
- bufp->fastmap_accurate = 0;
-
-#ifndef emacs
-#ifndef SYNTAX_TABLE
- /* Initialize the syntax table. */
- init_syntax_once();
-#endif
-#endif
-
- if (bufp->allocated == 0)
- {
- bufp->allocated = INIT_BUF_SIZE;
- if (bufp->buffer)
- /* EXTEND_BUFFER loses when bufp->allocated is 0. */
- bufp->buffer = (char *) realloc (bufp->buffer, INIT_BUF_SIZE);
- else
- /* Caller did not allocate a buffer. Do it for them. */
- bufp->buffer = (char *) malloc (INIT_BUF_SIZE);
- if (!bufp->buffer) goto memory_exhausted;
- begalt = b = bufp->buffer;
- }
-
- while (p != pend)
- {
- PATFETCH (c);
-
- switch (c)
- {
- case '$':
- {
- char *p1 = p;
- /* When testing what follows the $,
- look past the \-constructs that don't consume anything. */
- if (! (obscure_syntax & RE_CONTEXT_INDEP_OPS))
- while (p1 != pend)
- {
- if (*p1 == '\\' && p1 + 1 != pend
- && (p1[1] == '<' || p1[1] == '>'
- || p1[1] == '`' || p1[1] == '\''
-#ifdef emacs
- || p1[1] == '='
-#endif
- || p1[1] == 'b' || p1[1] == 'B'))
- p1 += 2;
- else
- break;
- }
- if (obscure_syntax & RE_TIGHT_VBAR)
- {
- if (! (obscure_syntax & RE_CONTEXT_INDEP_OPS) && p1 != pend)
- goto normal_char;
- /* Make operand of last vbar end before this `$'. */
- if (fixup_jump)
- store_jump (fixup_jump, jump, b);
- fixup_jump = 0;
- BUFPUSH (endline);
- break;
- }
- /* $ means succeed if at end of line, but only in special contexts.
- If validly in the middle of a pattern, it is a normal character. */
-
- if ((obscure_syntax & RE_CONTEXTUAL_INVALID_OPS) && p1 != pend)
- goto invalid_pattern;
- if (p1 == pend || *p1 == '\n'
- || (obscure_syntax & RE_CONTEXT_INDEP_OPS)
- || (obscure_syntax & RE_NO_BK_PARENS
- ? *p1 == ')'
- : *p1 == '\\' && p1[1] == ')')
- || (obscure_syntax & RE_NO_BK_VBAR
- ? *p1 == '|'
- : *p1 == '\\' && p1[1] == '|'))
- {
- BUFPUSH (endline);
- break;
- }
- goto normal_char;
- }
- case '^':
- /* ^ means succeed if at beg of line, but only if no preceding
- pattern. */
-
- if ((obscure_syntax & RE_CONTEXTUAL_INVALID_OPS) && laststart)
- goto invalid_pattern;
- if (laststart && p - 2 >= pattern && p[-2] != '\n'
- && !(obscure_syntax & RE_CONTEXT_INDEP_OPS))
- goto normal_char;
- if (obscure_syntax & RE_TIGHT_VBAR)
- {
- if (p != pattern + 1
- && ! (obscure_syntax & RE_CONTEXT_INDEP_OPS))
- goto normal_char;
- BUFPUSH (begline);
- begalt = b;
- }
- else
- BUFPUSH (begline);
- break;
-
- case '+':
- case '?':
- if ((obscure_syntax & RE_BK_PLUS_QM)
- || (obscure_syntax & RE_LIMITED_OPS))
- goto normal_char;
- handle_plus:
- case '*':
- /* If there is no previous pattern, char not special. */
- if (!laststart)
- {
- if (obscure_syntax & RE_CONTEXTUAL_INVALID_OPS)
- goto invalid_pattern;
- else if (! (obscure_syntax & RE_CONTEXT_INDEP_OPS))
- goto normal_char;
- }
- /* If there is a sequence of repetition chars,
- collapse it down to just one. */
- zero_times_ok = 0;
- many_times_ok = 0;
- while (1)
- {
- zero_times_ok |= c != '+';
- many_times_ok |= c != '?';
- if (p == pend)
- break;
- PATFETCH (c);
- if (c == '*')
- ;
- else if (!(obscure_syntax & RE_BK_PLUS_QM)
- && (c == '+' || c == '?'))
- ;
- else if ((obscure_syntax & RE_BK_PLUS_QM)
- && c == '\\')
- {
- /* int c1; */
- PATFETCH (c1);
- if (!(c1 == '+' || c1 == '?'))
- {
- PATUNFETCH;
- PATUNFETCH;
- break;
- }
- c = c1;
- }
- else
- {
- PATUNFETCH;
- break;
- }
- }
-
- /* Star, etc. applied to an empty pattern is equivalent
- to an empty pattern. */
- if (!laststart)
- break;
-
- /* Now we know whether or not zero matches is allowed
- and also whether or not two or more matches is allowed. */
- if (many_times_ok)
- {
- /* If more than one repetition is allowed, put in at the
- end a backward relative jump from b to before the next
- jump we're going to put in below (which jumps from
- laststart to after this jump). */
- GET_BUFFER_SPACE (3);
- store_jump (b, maybe_finalize_jump, laststart - 3);
- b += 3; /* Because store_jump put stuff here. */
- }
- /* On failure, jump from laststart to b + 3, which will be the
- end of the buffer after this jump is inserted. */
- GET_BUFFER_SPACE (3);
- insert_jump (on_failure_jump, laststart, b + 3, b);
- pending_exact = 0;
- b += 3;
- if (!zero_times_ok)
- {
- /* At least one repetition is required, so insert a
- dummy-failure before the initial on-failure-jump
- instruction of the loop. This effects a skip over that
- instruction the first time we hit that loop. */
- GET_BUFFER_SPACE (6);
- insert_jump (dummy_failure_jump, laststart, laststart + 6, b);
- b += 3;
- }
- break;
-
- case '.':
- laststart = b;
- BUFPUSH (anychar);
- break;
-
- case '[':
- if (p == pend)
- goto invalid_pattern;
- while (b - bufp->buffer
- > bufp->allocated - 3 - (1 << BYTEWIDTH) / BYTEWIDTH)
- EXTEND_BUFFER;
-
- laststart = b;
- if (*p == '^')
- {
- BUFPUSH (charset_not);
- p++;
- }
- else
- BUFPUSH (charset);
- p0 = p;
-
- BUFPUSH ((1 << BYTEWIDTH) / BYTEWIDTH);
- /* Clear the whole map */
- memset (b, 0, (1 << BYTEWIDTH) / BYTEWIDTH);
-
- if ((obscure_syntax & RE_HAT_NOT_NEWLINE) && b[-2] == charset_not)
- SET_LIST_BIT ('\n');
-
-
- /* Read in characters and ranges, setting map bits. */
- while (1)
- {
- /* Don't translate while fetching, in case it's a range bound.
- When we set the bit for the character, we translate it. */
- PATFETCH_RAW (c);
-
- /* If set, \ escapes characters when inside [...]. */
- if ((obscure_syntax & RE_AWK_CLASS_HACK) && c == '\\')
- {
- PATFETCH(c1);
- SET_LIST_BIT (c1);
- continue;
- }
- if (c == ']')
- {
- if (p == p0 + 1)
- {
- /* If this is an empty bracket expression. */
- if ((obscure_syntax & RE_NO_EMPTY_BRACKETS)
- && p == pend)
- goto invalid_pattern;
- }
- else
- /* Stop if this isn't merely a ] inside a bracket
- expression, but rather the end of a bracket
- expression. */
- break;
- }
- /* Get a range. */
- if (p[0] == '-' && p[1] != ']')
- {
- PATFETCH (c1);
- /* Don't translate the range bounds while fetching them. */
- PATFETCH_RAW (c1);
-
- if ((obscure_syntax & RE_NO_EMPTY_RANGES) && c > c1)
- goto invalid_pattern;
-
- if ((obscure_syntax & RE_NO_HYPHEN_RANGE_END)
- && c1 == '-' && *p != ']')
- goto invalid_pattern;
-
- while (c <= c1)
- {
- /* Translate each char that's in the range. */
- if (translate)
- SET_LIST_BIT (translate[c]);
- else
- SET_LIST_BIT (c);
- c++;
- }
- }
- else if ((obscure_syntax & RE_CHAR_CLASSES)
- && c == '[' && p[0] == ':')
- {
- /* Longest valid character class word has six characters. */
- char str[CHAR_CLASS_MAX_LENGTH];
- PATFETCH (c);
- c1 = 0;
- /* If no ] at end. */
- if (p == pend)
- goto invalid_pattern;
- while (1)
- {
- /* Don't translate the ``character class'' characters. */
- PATFETCH_RAW (c);
- if (c == ':' || c == ']' || p == pend
- || c1 == CHAR_CLASS_MAX_LENGTH)
- break;
- str[c1++] = c;
- }
- str[c1] = '\0';
- if (p == pend
- || c == ']' /* End of the bracket expression. */
- || p[0] != ']'
- || p + 1 == pend
- || (strcmp (str, "alpha") != 0
- && strcmp (str, "upper") != 0
- && strcmp (str, "lower") != 0
- && strcmp (str, "digit") != 0
- && strcmp (str, "alnum") != 0
- && strcmp (str, "xdigit") != 0
- && strcmp (str, "space") != 0
- && strcmp (str, "print") != 0
- && strcmp (str, "punct") != 0
- && strcmp (str, "graph") != 0
- && strcmp (str, "cntrl") != 0))
- {
- /* Undo the ending character, the letters, and leave
- the leading : and [ (but set bits for them). */
- c1++;
- while (c1--)
- PATUNFETCH;
- SET_LIST_BIT ('[');
- SET_LIST_BIT (':');
- }
- else
- {
- /* The ] at the end of the character class. */
- PATFETCH (c);
- if (c != ']')
- goto invalid_pattern;
- for (c = 0; c < (1 << BYTEWIDTH); c++)
- {
- if ((strcmp (str, "alpha") == 0 && isalpha (c))
- || (strcmp (str, "upper") == 0 && isupper (c))
- || (strcmp (str, "lower") == 0 && islower (c))
- || (strcmp (str, "digit") == 0 && isdigit (c))
- || (strcmp (str, "alnum") == 0 && isalnum (c))
- || (strcmp (str, "xdigit") == 0 && isxdigit (c))
- || (strcmp (str, "space") == 0 && isspace (c))
- || (strcmp (str, "print") == 0 && isprint (c))
- || (strcmp (str, "punct") == 0 && ispunct (c))
- || (strcmp (str, "graph") == 0 && isgraph (c))
- || (strcmp (str, "cntrl") == 0 && iscntrl (c)))
- SET_LIST_BIT (c);
- }
- }
- }
- else if (translate)
- SET_LIST_BIT (translate[c]);
- else
- SET_LIST_BIT (c);
- }
-
- /* Discard any character set/class bitmap bytes that are all
- 0 at the end of the map. Decrement the map-length byte too. */
- while ((int) b[-1] > 0 && b[b[-1] - 1] == 0)
- b[-1]--;
- b += b[-1];
- break;
-
- case '(':
- if (! (obscure_syntax & RE_NO_BK_PARENS))
- goto normal_char;
- else
- goto handle_open;
-
- case ')':
- if (! (obscure_syntax & RE_NO_BK_PARENS))
- goto normal_char;
- else
- goto handle_close;
-
- case '\n':
- if (! (obscure_syntax & RE_NEWLINE_OR))
- goto normal_char;
- else
- goto handle_bar;
-
- case '|':
- if ((obscure_syntax & RE_CONTEXTUAL_INVALID_OPS)
- && (! laststart || p == pend))
- goto invalid_pattern;
- else if (! (obscure_syntax & RE_NO_BK_VBAR))
- goto normal_char;
- else
- goto handle_bar;
-
- case '{':
- if (! ((obscure_syntax & RE_NO_BK_CURLY_BRACES)
- && (obscure_syntax & RE_INTERVALS)))
- goto normal_char;
- else
- goto handle_interval;
-
- case '\\':
- if (p == pend) goto invalid_pattern;
- PATFETCH_RAW (c);
- switch (c)
- {
- case '(':
- if (obscure_syntax & RE_NO_BK_PARENS)
- goto normal_backsl;
- handle_open:
- if (stackp == stacke) goto nesting_too_deep;
-
- /* Laststart should point to the start_memory that we are about
- to push (unless the pattern has RE_NREGS or more ('s). */
- *stackp++ = b - bufp->buffer;
- if (regnum < RE_NREGS)
- {
- BUFPUSH (start_memory);
- BUFPUSH (regnum);
- }
- *stackp++ = fixup_jump ? fixup_jump - bufp->buffer + 1 : 0;
- *stackp++ = regnum++;
- *stackp++ = begalt - bufp->buffer;
- fixup_jump = 0;
- laststart = 0;
- begalt = b;
- break;
-
- case ')':
- if (obscure_syntax & RE_NO_BK_PARENS)
- goto normal_backsl;
- handle_close:
- if (stackp == stackb) goto unmatched_close;
- begalt = *--stackp + bufp->buffer;
- if (fixup_jump)
- store_jump (fixup_jump, jump, b);
- if (stackp[-1] < RE_NREGS)
- {
- BUFPUSH (stop_memory);
- BUFPUSH (stackp[-1]);
- }
- stackp -= 2;
- fixup_jump = *stackp ? *stackp + bufp->buffer - 1 : 0;
- laststart = *--stackp + bufp->buffer;
- break;
-
- case '|':
- if ((obscure_syntax & RE_LIMITED_OPS)
- || (obscure_syntax & RE_NO_BK_VBAR))
- goto normal_backsl;
- handle_bar:
- if (obscure_syntax & RE_LIMITED_OPS)
- goto normal_char;
- /* Insert before the previous alternative a jump which
- jumps to this alternative if the former fails. */
- GET_BUFFER_SPACE (6);
- insert_jump (on_failure_jump, begalt, b + 6, b);
- pending_exact = 0;
- b += 3;
- /* The alternative before the previous alternative has a
- jump after it which gets executed if it gets matched.
- Adjust that jump so it will jump to the previous
- alternative's analogous jump (put in below, which in
- turn will jump to the next (if any) alternative's such
- jump, etc.). The last such jump jumps to the correct
- final destination. */
- if (fixup_jump)
- store_jump (fixup_jump, jump, b);
-
- /* Leave space for a jump after previous alternative---to be
- filled in later. */
- fixup_jump = b;
- b += 3;
-
- laststart = 0;
- begalt = b;
- break;
-
- case '{':
- if (! (obscure_syntax & RE_INTERVALS)
- /* Let \{ be a literal. */
- || ((obscure_syntax & RE_INTERVALS)
- && (obscure_syntax & RE_NO_BK_CURLY_BRACES))
- /* If it's the string "\{". */
- || (p - 2 == pattern && p == pend))
- goto normal_backsl;
- handle_interval:
- beg_interval = p - 1; /* The {. */
- /* If there is no previous pattern, this isn't an interval. */
- if (!laststart)
- {
- if (obscure_syntax & RE_CONTEXTUAL_INVALID_OPS)
- goto invalid_pattern;
- else
- goto normal_backsl;
- }
- /* It also isn't an interval if not preceded by an re
- matching a single character or subexpression, or if
- the current type of intervals can't handle back
- references and the previous thing is a back reference. */
- if (! (*laststart == anychar
- || *laststart == charset
- || *laststart == charset_not
- || *laststart == start_memory
- || (*laststart == exactn && laststart[1] == 1)
- || (! (obscure_syntax & RE_NO_BK_REFS)
- && *laststart == duplicate)))
- {
- if (obscure_syntax & RE_NO_BK_CURLY_BRACES)
- goto normal_char;
-
- /* Posix extended syntax is handled in previous
- statement; this is for Posix basic syntax. */
- if (obscure_syntax & RE_INTERVALS)
- goto invalid_pattern;
-
- goto normal_backsl;
- }
- lower_bound = -1; /* So can see if are set. */
- upper_bound = -1;
- GET_UNSIGNED_NUMBER (lower_bound);
- if (c == ',')
- {
- GET_UNSIGNED_NUMBER (upper_bound);
- if (upper_bound < 0)
- upper_bound = RE_DUP_MAX;
- }
- if (upper_bound < 0)
- upper_bound = lower_bound;
- if (! (obscure_syntax & RE_NO_BK_CURLY_BRACES))
- {
- if (c != '\\')
- goto invalid_pattern;
- PATFETCH (c);
- }
- if (c != '}' || lower_bound < 0 || upper_bound > RE_DUP_MAX
- || lower_bound > upper_bound
- || ((obscure_syntax & RE_NO_BK_CURLY_BRACES)
- && p != pend && *p == '{'))
- {
- if (obscure_syntax & RE_NO_BK_CURLY_BRACES)
- goto unfetch_interval;
- else
- goto invalid_pattern;
- }
-
- /* If upper_bound is zero, don't want to succeed at all;
- jump from laststart to b + 3, which will be the end of
- the buffer after this jump is inserted. */
-
- if (upper_bound == 0)
- {
- GET_BUFFER_SPACE (3);
- insert_jump (jump, laststart, b + 3, b);
- b += 3;
- }
-
- /* Otherwise, after lower_bound number of succeeds, jump
- to after the jump_n which will be inserted at the end
- of the buffer, and insert that jump_n. */
- else
- { /* Set to 5 if only one repetition is allowed and
- hence no jump_n is inserted at the current end of
- the buffer; then only space for the succeed_n is
- needed. Otherwise, need space for both the
- succeed_n and the jump_n. */
-
- unsigned slots_needed = upper_bound == 1 ? 5 : 10;
-
- GET_BUFFER_SPACE (slots_needed);
- /* Initialize the succeed_n to n, even though it will
- be set by its attendant set_number_at, because
- re_compile_fastmap will need to know it. Jump to
- what the end of buffer will be after inserting
- this succeed_n and possibly appending a jump_n. */
- insert_jump_n (succeed_n, laststart, b + slots_needed,
- b, lower_bound);
- b += 5; /* Just increment for the succeed_n here. */
-
- /* More than one repetition is allowed, so put in at
- the end of the buffer a backward jump from b to the
- succeed_n we put in above. By the time we've gotten
- to this jump when matching, we'll have matched once
- already, so jump back only upper_bound - 1 times. */
-
- if (upper_bound > 1)
- {
- store_jump_n (b, jump_n, laststart, upper_bound - 1);
- b += 5;
- /* When hit this when matching, reset the
- preceding jump_n's n to upper_bound - 1. */
- BUFPUSH (set_number_at);
- GET_BUFFER_SPACE (2);
- STORE_NUMBER_AND_INCR (b, -5);
- STORE_NUMBER_AND_INCR (b, upper_bound - 1);
- }
- /* When hit this when matching, set the succeed_n's n. */
- GET_BUFFER_SPACE (5);
- insert_op_2 (set_number_at, laststart, b, 5, lower_bound);
- b += 5;
- }
- pending_exact = 0;
- beg_interval = 0;
- break;
-
-
- unfetch_interval:
- /* If an invalid interval, match the characters as literals. */
- if (beg_interval)
- p = beg_interval;
- else
- {
- fprintf (stderr,
- "regex: no interval beginning to which to backtrack.\n");
- exit (1);
- }
-
- beg_interval = 0;
- PATFETCH (c); /* normal_char expects char in `c'. */
- goto normal_char;
- break;
-
-#ifdef emacs
- case '=':
- BUFPUSH (at_dot);
- break;
-
- case 's':
- laststart = b;
- BUFPUSH (syntaxspec);
- PATFETCH (c);
- BUFPUSH (syntax_spec_code[c]);
- break;
-
- case 'S':
- laststart = b;
- BUFPUSH (notsyntaxspec);
- PATFETCH (c);
- BUFPUSH (syntax_spec_code[c]);
- break;
-#endif /* emacs */
-
- case 'w':
- laststart = b;
- BUFPUSH (wordchar);
- break;
-
- case 'W':
- laststart = b;
- BUFPUSH (notwordchar);
- break;
-
- case '<':
- BUFPUSH (wordbeg);
- break;
-
- case '>':
- BUFPUSH (wordend);
- break;
-
- case 'b':
- BUFPUSH (wordbound);
- break;
-
- case 'B':
- BUFPUSH (notwordbound);
- break;
-
- case '`':
- BUFPUSH (begbuf);
- break;
-
- case '\'':
- BUFPUSH (endbuf);
- break;
-
- case '1':
- case '2':
- case '3':
- case '4':
- case '5':
- case '6':
- case '7':
- case '8':
- case '9':
- if (obscure_syntax & RE_NO_BK_REFS)
- goto normal_char;
- c1 = c - '0';
- if (c1 >= regnum)
- {
- if (obscure_syntax & RE_NO_EMPTY_BK_REF)
- goto invalid_pattern;
- else
- goto normal_char;
- }
- /* Can't back reference to a subexpression if inside of it. */
- for (stackt = stackp - 2; stackt > stackb; stackt -= 4)
- if (*stackt == c1)
- goto normal_char;
- laststart = b;
- BUFPUSH (duplicate);
- BUFPUSH (c1);
- break;
-
- case '+':
- case '?':
- if (obscure_syntax & RE_BK_PLUS_QM)
- goto handle_plus;
- else
- goto normal_backsl;
- break;
-
- default:
- normal_backsl:
- /* You might think it would be useful for \ to mean
- not to translate; but if we don't translate it
- it will never match anything. */
- if (translate) c = translate[c];
- goto normal_char;
- }
- break;
-
- default:
- normal_char: /* Expects the character in `c'. */
- if (!pending_exact || pending_exact + *pending_exact + 1 != b
- || *pending_exact == 0177 || *p == '*' || *p == '^'
- || ((obscure_syntax & RE_BK_PLUS_QM)
- ? *p == '\\' && (p[1] == '+' || p[1] == '?')
- : (*p == '+' || *p == '?'))
- || ((obscure_syntax & RE_INTERVALS)
- && ((obscure_syntax & RE_NO_BK_CURLY_BRACES)
- ? *p == '{'
- : (p[0] == '\\' && p[1] == '{'))))
- {
- laststart = b;
- BUFPUSH (exactn);
- pending_exact = b;
- BUFPUSH (0);
- }
- BUFPUSH (c);
- (*pending_exact)++;
- }
- }
-
- if (fixup_jump)
- store_jump (fixup_jump, jump, b);
-
- if (stackp != stackb) goto unmatched_open;
-
- bufp->used = b - bufp->buffer;
- return 0;
-
- invalid_pattern:
- return "Invalid regular expression";
-
- unmatched_open:
- return "Unmatched \\(";
-
- unmatched_close:
- return "Unmatched \\)";
-
- end_of_pattern:
- return "Premature end of regular expression";
-
- nesting_too_deep:
- return "Nesting too deep";
-
- too_big:
- return "Regular expression too big";
-
- memory_exhausted:
- return "Memory exhausted";
-}
-
-
-/* Store a jump of the form <OPCODE> <relative address>.
- Store in the location FROM a jump operation to jump to relative
- address FROM - TO. OPCODE is the opcode to store. */
-
-static void
-store_jump (from, opcode, to)
- char *from, *to;
- int opcode;
-{
- from[0] = (char)opcode;
- STORE_NUMBER(from + 1, to - (from + 3));
-}
-
-
-/* Open up space before char FROM, and insert there a jump to TO.
- CURRENT_END gives the end of the storage not in use, so we know
- how much data to copy up. OP is the opcode of the jump to insert.
-
- If you call this function, you must zero out pending_exact. */
-
-static void
-insert_jump (op, from, to, current_end)
- int op;
- char *from, *to, *current_end;
-{
- register char *pfrom = current_end; /* Copy from here... */
- register char *pto = current_end + 3; /* ...to here. */
-
- while (pfrom != from)
- *--pto = *--pfrom;
- store_jump (from, op, to);
-}
-
-
-/* Store a jump of the form <opcode> <relative address> <n> .
-
- Store in the location FROM a jump operation to jump to relative
- address FROM - TO. OPCODE is the opcode to store, N is a number the
- jump uses, say, to decide how many times to jump.
-
- If you call this function, you must zero out pending_exact. */
-
-static void
-store_jump_n (from, opcode, to, n)
- char *from, *to;
- int opcode;
- unsigned n;
-{
- from[0] = (char)opcode;
- STORE_NUMBER (from + 1, to - (from + 3));
- STORE_NUMBER (from + 3, n);
-}
-
-
-/* Similar to insert_jump, but handles a jump which needs an extra
- number to handle minimum and maximum cases. Open up space at
- location FROM, and insert there a jump to TO. CURRENT_END gives the
- end of the storage in use, so we know how much data to copy up. OP is
- the opcode of the jump to insert.
-
- If you call this function, you must zero out pending_exact. */
-
-static void
-insert_jump_n (op, from, to, current_end, n)
- int op;
- char *from, *to, *current_end;
- unsigned n;
-{
- register char *pfrom = current_end; /* Copy from here... */
- register char *pto = current_end + 5; /* ...to here. */
-
- while (pfrom != from)
- *--pto = *--pfrom;
- store_jump_n (from, op, to, n);
-}
-
-
-/* Open up space at location THERE, and insert operation OP followed by
- NUM_1 and NUM_2. CURRENT_END gives the end of the storage in use, so
- we know how much data to copy up.
-
- If you call this function, you must zero out pending_exact. */
-
-static void
-insert_op_2 (op, there, current_end, num_1, num_2)
- int op;
- char *there, *current_end;
- int num_1, num_2;
-{
- register char *pfrom = current_end; /* Copy from here... */
- register char *pto = current_end + 5; /* ...to here. */
-
- while (pfrom != there)
- *--pto = *--pfrom;
-
- there[0] = (char)op;
- STORE_NUMBER (there + 1, num_1);
- STORE_NUMBER (there + 3, num_2);
-}
-
-
-
-/* Given a pattern, compute a fastmap from it. The fastmap records
- which of the (1 << BYTEWIDTH) possible characters can start a string
- that matches the pattern. This fastmap is used by re_search to skip
- quickly over totally implausible text.
-
- The caller must supply the address of a (1 << BYTEWIDTH)-byte data
- area as bufp->fastmap.
- The other components of bufp describe the pattern to be used. */
-
-void
-re_compile_fastmap (bufp)
- struct re_pattern_buffer *bufp;
-{
- unsigned char *pattern = (unsigned char *) bufp->buffer;
- int size = bufp->used;
- register char *fastmap = bufp->fastmap;
- register unsigned char *p = pattern;
- register unsigned char *pend = pattern + size;
- register int j, k;
- unsigned char *translate = (unsigned char *) bufp->translate;
- unsigned is_a_succeed_n;
-
-#ifndef NO_ALLOCA
- unsigned char *stackb[NFAILURES];
- unsigned char **stackp = stackb;
-
-#else
- unsigned char **stackb;
- unsigned char **stackp;
- stackb = (unsigned char **) malloc (NFAILURES * sizeof (unsigned char *));
- stackp = stackb;
-
-#endif /* NO_ALLOCA */
- memset (fastmap, 0, (1 << BYTEWIDTH));
- bufp->fastmap_accurate = 1;
- bufp->can_be_null = 0;
-
- while (p)
- {
- is_a_succeed_n = 0;
- if (p == pend)
- {
- bufp->can_be_null = 1;
- break;
- }
-#ifdef SWITCH_ENUM_BUG
- switch ((int) ((enum regexpcode) *p++))
-#else
- switch ((enum regexpcode) *p++)
-#endif
- {
- case exactn:
- if (translate)
- fastmap[translate[p[1]]] = 1;
- else
- fastmap[p[1]] = 1;
- break;
-
- case begline:
- case before_dot:
- case at_dot:
- case after_dot:
- case begbuf:
- case endbuf:
- case wordbound:
- case notwordbound:
- case wordbeg:
- case wordend:
- continue;
-
- case endline:
- if (translate)
- fastmap[translate['\n']] = 1;
- else
- fastmap['\n'] = 1;
-
- if (bufp->can_be_null != 1)
- bufp->can_be_null = 2;
- break;
-
- case jump_n:
- case finalize_jump:
- case maybe_finalize_jump:
- case jump:
- case dummy_failure_jump:
- EXTRACT_NUMBER_AND_INCR (j, p);
- p += j;
- if (j > 0)
- continue;
- /* Jump backward reached implies we just went through
- the body of a loop and matched nothing.
- Opcode jumped to should be an on_failure_jump.
- Just treat it like an ordinary jump.
- For a * loop, it has pushed its failure point already;
- If so, discard that as redundant. */
-
- if ((enum regexpcode) *p != on_failure_jump
- && (enum regexpcode) *p != succeed_n)
- continue;
- p++;
- EXTRACT_NUMBER_AND_INCR (j, p);
- p += j;
- if (stackp != stackb && *stackp == p)
- stackp--;
- continue;
-
- case on_failure_jump:
- handle_on_failure_jump:
- EXTRACT_NUMBER_AND_INCR (j, p);
- *++stackp = p + j;
- if (is_a_succeed_n)
- EXTRACT_NUMBER_AND_INCR (k, p); /* Skip the n. */
- continue;
-
- case succeed_n:
- is_a_succeed_n = 1;
- /* Get to the number of times to succeed. */
- p += 2;
- /* Increment p past the n for when k != 0. */
- EXTRACT_NUMBER_AND_INCR (k, p);
- if (k == 0)
- {
- p -= 4;
- goto handle_on_failure_jump;
- }
- continue;
-
- case set_number_at:
- p += 4;
- continue;
-
- case start_memory:
- case stop_memory:
- p++;
- continue;
-
- case duplicate:
- bufp->can_be_null = 1;
- fastmap['\n'] = 1;
- case anychar:
- for (j = 0; j < (1 << BYTEWIDTH); j++)
- if (j != '\n')
- fastmap[j] = 1;
- if (bufp->can_be_null)
- {
- FREE_AND_RETURN_VOID(stackb);
- }
- /* Don't return; check the alternative paths
- so we can set can_be_null if appropriate. */
- break;
-
- case wordchar:
- for (j = 0; j < (1 << BYTEWIDTH); j++)
- if (SYNTAX (j) == Sword)
- fastmap[j] = 1;
- break;
-
- case notwordchar:
- for (j = 0; j < (1 << BYTEWIDTH); j++)
- if (SYNTAX (j) != Sword)
- fastmap[j] = 1;
- break;
-
-#ifdef emacs
- case syntaxspec:
- k = *p++;
- for (j = 0; j < (1 << BYTEWIDTH); j++)
- if (SYNTAX (j) == (enum syntaxcode) k)
- fastmap[j] = 1;
- break;
-
- case notsyntaxspec:
- k = *p++;
- for (j = 0; j < (1 << BYTEWIDTH); j++)
- if (SYNTAX (j) != (enum syntaxcode) k)
- fastmap[j] = 1;
- break;
-
-#else /* not emacs */
- case syntaxspec:
- case notsyntaxspec:
- break;
-#endif /* not emacs */
-
- case charset:
- for (j = *p++ * BYTEWIDTH - 1; j >= 0; j--)
- if (p[j / BYTEWIDTH] & (1 << (j % BYTEWIDTH)))
- {
- if (translate)
- fastmap[translate[j]] = 1;
- else
- fastmap[j] = 1;
- }
- break;
-
- case charset_not:
- /* Chars beyond end of map must be allowed */
- for (j = *p * BYTEWIDTH; j < (1 << BYTEWIDTH); j++)
- if (translate)
- fastmap[translate[j]] = 1;
- else
- fastmap[j] = 1;
-
- for (j = *p++ * BYTEWIDTH - 1; j >= 0; j--)
- if (!(p[j / BYTEWIDTH] & (1 << (j % BYTEWIDTH))))
- {
- if (translate)
- fastmap[translate[j]] = 1;
- else
- fastmap[j] = 1;
- }
- break;
-
- case unused: /* pacify gcc -Wall */
- break;
- }
-
- /* Get here means we have successfully found the possible starting
- characters of one path of the pattern. We need not follow this
- path any farther. Instead, look at the next alternative
- remembered in the stack. */
- if (stackp != stackb)
- p = *stackp--;
- else
- break;
- }
- FREE_AND_RETURN_VOID(stackb);
-}
-
-
-
-/* Like re_search_2, below, but only one string is specified, and
- doesn't let you say where to stop matching. */
-
-int
-re_search (pbufp, string, size, startpos, range, regs)
- struct re_pattern_buffer *pbufp;
- char *string;
- int size, startpos, range;
- struct re_registers *regs;
-{
- return re_search_2 (pbufp, (char *) 0, 0, string, size, startpos, range,
- regs, size);
-}
-
-
-/* Using the compiled pattern in PBUFP->buffer, first tries to match the
- virtual concatenation of STRING1 and STRING2, starting first at index
- STARTPOS, then at STARTPOS + 1, and so on. RANGE is the number of
- places to try before giving up. If RANGE is negative, it searches
- backwards, i.e., the starting positions tried are STARTPOS, STARTPOS
- - 1, etc. STRING1 and STRING2 are of SIZE1 and SIZE2, respectively.
- In REGS, return the indices of the virtual concatenation of STRING1
- and STRING2 that matched the entire PBUFP->buffer and its contained
- subexpressions. Do not consider matching one past the index MSTOP in
- the virtual concatenation of STRING1 and STRING2.
-
- The value returned is the position in the strings at which the match
- was found, or -1 if no match was found, or -2 if error (such as
- failure stack overflow). */
-
-int
-re_search_2 (pbufp, string1, size1, string2, size2, startpos, range,
- regs, mstop)
- struct re_pattern_buffer *pbufp;
- char *string1, *string2;
- int size1, size2;
- int startpos;
- register int range;
- struct re_registers *regs;
- int mstop;
-{
- register char *fastmap = pbufp->fastmap;
- register unsigned char *translate = (unsigned char *) pbufp->translate;
- int total_size = size1 + size2;
- int endpos = startpos + range;
- int val;
-
- /* Check for out-of-range starting position. */
- if (startpos < 0 || startpos > total_size)
- return -1;
-
- /* Fix up range if it would eventually take startpos outside of the
- virtual concatenation of string1 and string2. */
- if (endpos < -1)
- range = -1 - startpos;
- else if (endpos > total_size)
- range = total_size - startpos;
-
- /* Update the fastmap now if not correct already. */
- if (fastmap && !pbufp->fastmap_accurate)
- re_compile_fastmap (pbufp);
-
- /* If the search isn't to be a backwards one, don't waste time in a
- long search for a pattern that says it is anchored. */
- if (pbufp->used > 0 && (enum regexpcode) pbufp->buffer[0] == begbuf
- && range > 0)
- {
- if (startpos > 0)
- return -1;
- else
- range = 1;
- }
-
- while (1)
- {
- /* If a fastmap is supplied, skip quickly over characters that
- cannot possibly be the start of a match. Note, however, that
- if the pattern can possibly match the null string, we must
- test it at each starting point so that we take the first null
- string we get. */
-
- if (fastmap && startpos < total_size && pbufp->can_be_null != 1)
- {
- if (range > 0) /* Searching forwards. */
- {
- register int lim = 0;
- register unsigned char *p;
- int irange = range;
- if (startpos < size1 && startpos + range >= size1)
- lim = range - (size1 - startpos);
-
- p = ((unsigned char *)
- &(startpos >= size1 ? string2 - size1 : string1)[startpos]);
-
- while (range > lim && !fastmap[translate
- ? translate[*p++]
- : *p++])
- range--;
- startpos += irange - range;
- }
- else /* Searching backwards. */
- {
- register unsigned char c;
-
- if (string1 == 0 || startpos >= size1)
- c = string2[startpos - size1];
- else
- c = string1[startpos];
-
- c &= 0xff;
- if (translate ? !fastmap[translate[c]] : !fastmap[c])
- goto advance;
- }
- }
-
- if (range >= 0 && startpos == total_size
- && fastmap && pbufp->can_be_null == 0)
- return -1;
-
- val = re_match_2 (pbufp, string1, size1, string2, size2, startpos,
- regs, mstop);
- if (val >= 0)
- return startpos;
- if (val == -2)
- return -2;
-
-#ifndef NO_ALLOCA
-#ifdef C_ALLOCA
- alloca (0);
-#endif /* C_ALLOCA */
-
-#endif /* NO_ALLOCA */
- advance:
- if (!range)
- break;
- else if (range > 0)
- {
- range--;
- startpos++;
- }
- else
- {
- range++;
- startpos--;
- }
- }
- return -1;
-}
-
-
-
-#ifndef emacs /* emacs never uses this. */
-int
-re_match (pbufp, string, size, pos, regs)
- struct re_pattern_buffer *pbufp;
- char *string;
- int size, pos;
- struct re_registers *regs;
-{
- return re_match_2 (pbufp, (char *) 0, 0, string, size, pos, regs, size);
-}
-#endif /* not emacs */
-
-
-/* The following are used for re_match_2, defined below: */
-
-/* Roughly the maximum number of failure points on the stack. Would be
- exactly that if always pushed MAX_NUM_FAILURE_ITEMS each time we failed. */
-
-int re_max_failures = 2000;
-
-/* Routine used by re_match_2. */
-/* static int memcmp_translate (); *//* already declared */
-
-
-/* Structure and accessing macros used in re_match_2: */
-
-struct register_info
-{
- unsigned is_active : 1;
- unsigned matched_something : 1;
-};
-
-#define IS_ACTIVE(R) ((R).is_active)
-#define MATCHED_SOMETHING(R) ((R).matched_something)
-
-
-/* Macros used by re_match_2: */
-
-
-/* I.e., regstart, regend, and reg_info. */
-
-#define NUM_REG_ITEMS 3
-
-/* We push at most this many things on the stack whenever we
- fail. The `+ 2' refers to PATTERN_PLACE and STRING_PLACE, which are
- arguments to the PUSH_FAILURE_POINT macro. */
-
-#define MAX_NUM_FAILURE_ITEMS (RE_NREGS * NUM_REG_ITEMS + 2)
-
-
-/* We push this many things on the stack whenever we fail. */
-
-#define NUM_FAILURE_ITEMS (last_used_reg * NUM_REG_ITEMS + 2)
-
-
-/* This pushes most of the information about the current state we will want
- if we ever fail back to it. */
-
-#define PUSH_FAILURE_POINT(pattern_place, string_place) \
- { \
- long last_used_reg, this_reg; \
- \
- /* Find out how many registers are active or have been matched. \
- (Aside from register zero, which is only set at the end.) */ \
- for (last_used_reg = RE_NREGS - 1; last_used_reg > 0; last_used_reg--)\
- if (regstart[last_used_reg] != (unsigned char *)(-1L)) \
- break; \
- \
- if (stacke - stackp < NUM_FAILURE_ITEMS) \
- { \
- unsigned char **stackx; \
- unsigned int len = stacke - stackb; \
- if (len > re_max_failures * MAX_NUM_FAILURE_ITEMS) \
- { \
- FREE_AND_RETURN(stackb,(-2)); \
- } \
- \
- /* Roughly double the size of the stack. */ \
- stackx = DOUBLE_STACK(stackx,stackb,len); \
- /* Rearrange the pointers. */ \
- stackp = stackx + (stackp - stackb); \
- stackb = stackx; \
- stacke = stackb + 2 * len; \
- } \
- \
- /* Now push the info for each of those registers. */ \
- for (this_reg = 1; this_reg <= last_used_reg; this_reg++) \
- { \
- *stackp++ = regstart[this_reg]; \
- *stackp++ = regend[this_reg]; \
- *stackp++ = (unsigned char *) &reg_info[this_reg]; \
- } \
- \
- /* Push how many registers we saved. */ \
- *stackp++ = (unsigned char *) last_used_reg; \
- \
- *stackp++ = pattern_place; \
- *stackp++ = string_place; \
- }
-
-
-/* This pops what PUSH_FAILURE_POINT pushes. */
-
-#define POP_FAILURE_POINT() \
- { \
- int temp; \
- stackp -= 2; /* Remove failure points. */ \
- temp = (int) *--stackp; /* How many regs pushed. */ \
- temp *= NUM_REG_ITEMS; /* How much to take off the stack. */ \
- stackp -= temp; /* Remove the register info. */ \
- }
-
-
-#define MATCHING_IN_FIRST_STRING (dend == end_match_1)
-
-/* Is true if there is a first string and if PTR is pointing anywhere
- inside it or just past the end. */
-
-#define IS_IN_FIRST_STRING(ptr) \
- (size1 && string1 <= (ptr) && (ptr) <= string1 + size1)
-
-/* Call before fetching a character with *d. This switches over to
- string2 if necessary. */
-
-#define PREFETCH \
- while (d == dend) \
- { \
- /* end of string2 => fail. */ \
- if (dend == end_match_2) \
- goto fail; \
- /* end of string1 => advance to string2. */ \
- d = string2; \
- dend = end_match_2; \
- }
-
-
-/* Call this when have matched something; it sets `matched' flags for the
- registers corresponding to the subexpressions of which we currently
- are inside. */
-#define SET_REGS_MATCHED \
- { unsigned this_reg; \
- for (this_reg = 0; this_reg < RE_NREGS; this_reg++) \
- { \
- if (IS_ACTIVE(reg_info[this_reg])) \
- MATCHED_SOMETHING(reg_info[this_reg]) = 1; \
- else \
- MATCHED_SOMETHING(reg_info[this_reg]) = 0; \
- } \
- }
-
-/* Test if at very beginning or at very end of the virtual concatenation
- of string1 and string2. If there is only one string, we've put it in
- string2. */
-
-#define AT_STRINGS_BEG (d == (size1 ? string1 : string2) || !size2)
-#define AT_STRINGS_END (d == end2)
-
-#define AT_WORD_BOUNDARY \
- (AT_STRINGS_BEG || AT_STRINGS_END || IS_A_LETTER (d - 1) != IS_A_LETTER (d))
-
-/* We have two special cases to check for:
- 1) if we're past the end of string1, we have to look at the first
- character in string2;
- 2) if we're before the beginning of string2, we have to look at the
- last character in string1; we assume there is a string1, so use
- this in conjunction with AT_STRINGS_BEG. */
-#define IS_A_LETTER(d) \
- (SYNTAX ((d) == end1 ? *string2 : (d) == string2 - 1 ? *(end1 - 1) : *(d))\
- == Sword)
-
-
-/* Match the pattern described by PBUFP against the virtual
- concatenation of STRING1 and STRING2, which are of SIZE1 and SIZE2,
- respectively. Start the match at index POS in the virtual
- concatenation of STRING1 and STRING2. In REGS, return the indices of
- the virtual concatenation of STRING1 and STRING2 that matched the
- entire PBUFP->buffer and its contained subexpressions. Do not
- consider matching one past the index MSTOP in the virtual
- concatenation of STRING1 and STRING2.
-
- If pbufp->fastmap is nonzero, then it had better be up to date.
-
- The reason that the data to match are specified as two components
- which are to be regarded as concatenated is so this function can be
- used directly on the contents of an Emacs buffer.
-
- -1 is returned if there is no match. -2 is returned if there is an
- error (such as match stack overflow). Otherwise the value is the
- length of the substring which was matched. */
-
-int
-re_match_2 (pbufp, string1_arg, size1, string2_arg, size2, pos, regs, mstop)
- struct re_pattern_buffer *pbufp;
- char *string1_arg, *string2_arg;
- int size1, size2;
- int pos;
- struct re_registers *regs;
- int mstop;
-{
- register unsigned char *p = (unsigned char *) pbufp->buffer;
-
- /* Pointer to beyond end of buffer. */
- register unsigned char *pend = p + pbufp->used;
-
- unsigned char *string1 = (unsigned char *) string1_arg;
- unsigned char *string2 = (unsigned char *) string2_arg;
- unsigned char *end1; /* Just past end of first string. */
- unsigned char *end2; /* Just past end of second string. */
-
- /* Pointers into string1 and string2, just past the last characters in
- each to consider matching. */
- unsigned char *end_match_1, *end_match_2;
-
- register unsigned char *d, *dend;
- register int mcnt; /* Multipurpose. */
- unsigned char *translate = (unsigned char *) pbufp->translate;
- unsigned is_a_jump_n = 0;
-
- /* Failure point stack. Each place that can handle a failure further
- down the line pushes a failure point on this stack. It consists of
- restart, regend, and reg_info for all registers corresponding to the
- subexpressions we're currently inside, plus the number of such
- registers, and, finally, two char *'s. The first char * is where to
- resume scanning the pattern; the second one is where to resume
- scanning the strings. If the latter is zero, the failure point is a
- ``dummy''; if a failure happens and the failure point is a dummy, it
- gets discarded and the next next one is tried. */
-
-#ifndef NO_ALLOCA
- unsigned char *initial_stack[MAX_NUM_FAILURE_ITEMS * NFAILURES];
-#endif
- unsigned char **stackb;
- unsigned char **stackp;
- unsigned char **stacke;
-
-
- /* Information on the contents of registers. These are pointers into
- the input strings; they record just what was matched (on this
- attempt) by a subexpression part of the pattern, that is, the
- regnum-th regstart pointer points to where in the pattern we began
- matching and the regnum-th regend points to right after where we
- stopped matching the regnum-th subexpression. (The zeroth register
- keeps track of what the whole pattern matches.) */
-
- unsigned char *regstart[RE_NREGS];
- unsigned char *regend[RE_NREGS];
-
- /* The is_active field of reg_info helps us keep track of which (possibly
- nested) subexpressions we are currently in. The matched_something
- field of reg_info[reg_num] helps us tell whether or not we have
- matched any of the pattern so far this time through the reg_num-th
- subexpression. These two fields get reset each time through any
- loop their register is in. */
-
- struct register_info reg_info[RE_NREGS];
-
-
- /* The following record the register info as found in the above
- variables when we find a match better than any we've seen before.
- This happens as we backtrack through the failure points, which in
- turn happens only if we have not yet matched the entire string. */
-
- unsigned best_regs_set = 0;
- unsigned char *best_regstart[RE_NREGS];
- unsigned char *best_regend[RE_NREGS];
-
- /* Initialize the stack. */
-#ifdef NO_ALLOCA
- stackb = (unsigned char **) malloc (MAX_NUM_FAILURE_ITEMS * NFAILURES * sizeof (char *));
-#else
- stackb = initial_stack;
-#endif
- stackp = stackb;
- stacke = &stackb[MAX_NUM_FAILURE_ITEMS * NFAILURES];
-
-#ifdef DEBUG_REGEX
- fprintf (stderr, "Entering re_match_2(%s%s)\n", string1_arg, string2_arg);
-#endif
-
- /* Initialize subexpression text positions to -1 to mark ones that no
- \( or ( and \) or ) has been seen for. Also set all registers to
- inactive and mark them as not having matched anything or ever
- failed. */
- for (mcnt = 0; mcnt < RE_NREGS; mcnt++)
- {
- regstart[mcnt] = regend[mcnt] = (unsigned char *) (-1L);
- IS_ACTIVE (reg_info[mcnt]) = 0;
- MATCHED_SOMETHING (reg_info[mcnt]) = 0;
- }
-
- if (regs)
- for (mcnt = 0; mcnt < RE_NREGS; mcnt++)
- regs->start[mcnt] = regs->end[mcnt] = -1;
-
- /* Set up pointers to ends of strings.
- Don't allow the second string to be empty unless both are empty. */
- if (size2 == 0)
- {
- string2 = string1;
- size2 = size1;
- string1 = 0;
- size1 = 0;
- }
- end1 = string1 + size1;
- end2 = string2 + size2;
-
- /* Compute where to stop matching, within the two strings. */
- if (mstop <= size1)
- {
- end_match_1 = string1 + mstop;
- end_match_2 = string2;
- }
- else
- {
- end_match_1 = end1;
- end_match_2 = string2 + mstop - size1;
- }
-
- /* `p' scans through the pattern as `d' scans through the data. `dend'
- is the end of the input string that `d' points within. `d' is
- advanced into the following input string whenever necessary, but
- this happens before fetching; therefore, at the beginning of the
- loop, `d' can be pointing at the end of a string, but it cannot
- equal string2. */
-
- if (size1 != 0 && pos <= size1)
- d = string1 + pos, dend = end_match_1;
- else
- d = string2 + pos - size1, dend = end_match_2;
-
-
- /* This loops over pattern commands. It exits by returning from the
- function if match is complete, or it drops through if match fails
- at this starting point in the input data. */
-
- while (1)
- {
-#ifdef DEBUG_REGEX
- fprintf (stderr,
- "regex loop(%d): matching 0x%02d\n",
- p - (unsigned char *) pbufp->buffer,
- *p);
-#endif
- is_a_jump_n = 0;
- /* End of pattern means we might have succeeded. */
- if (p == pend)
- {
- /* If not end of string, try backtracking. Otherwise done. */
- if (d != end_match_2)
- {
- if (stackp != stackb)
- {
- /* More failure points to try. */
-
- unsigned in_same_string =
- IS_IN_FIRST_STRING (best_regend[0])
- == MATCHING_IN_FIRST_STRING;
-
- /* If exceeds best match so far, save it. */
- if (! best_regs_set
- || (in_same_string && d > best_regend[0])
- || (! in_same_string && ! MATCHING_IN_FIRST_STRING))
- {
- best_regs_set = 1;
- best_regend[0] = d; /* Never use regstart[0]. */
-
- for (mcnt = 1; mcnt < RE_NREGS; mcnt++)
- {
- best_regstart[mcnt] = regstart[mcnt];
- best_regend[mcnt] = regend[mcnt];
- }
- }
- goto fail;
- }
- /* If no failure points, don't restore garbage. */
- else if (best_regs_set)
- {
- restore_best_regs:
- /* Restore best match. */
- d = best_regend[0];
-
- for (mcnt = 0; mcnt < RE_NREGS; mcnt++)
- {
- regstart[mcnt] = best_regstart[mcnt];
- regend[mcnt] = best_regend[mcnt];
- }
- }
- }
-
- /* If caller wants register contents data back, convert it
- to indices. */
- if (regs)
- {
- regs->start[0] = pos;
- if (MATCHING_IN_FIRST_STRING)
- regs->end[0] = d - string1;
- else
- regs->end[0] = d - string2 + size1;
- for (mcnt = 1; mcnt < RE_NREGS; mcnt++)
- {
- if (regend[mcnt] == (unsigned char *)(-1L))
- {
- regs->start[mcnt] = -1;
- regs->end[mcnt] = -1;
- continue;
- }
- if (IS_IN_FIRST_STRING (regstart[mcnt]))
- regs->start[mcnt] = regstart[mcnt] - string1;
- else
- regs->start[mcnt] = regstart[mcnt] - string2 + size1;
-
- if (IS_IN_FIRST_STRING (regend[mcnt]))
- regs->end[mcnt] = regend[mcnt] - string1;
- else
- regs->end[mcnt] = regend[mcnt] - string2 + size1;
- }
- }
- FREE_AND_RETURN(stackb,
- (d - pos - (MATCHING_IN_FIRST_STRING ?
- string1 :
- string2 - size1)));
- }
-
- /* Otherwise match next pattern command. */
-#ifdef SWITCH_ENUM_BUG
- switch ((int) ((enum regexpcode) *p++))
-#else
- switch ((enum regexpcode) *p++)
-#endif
- {
-
- /* \( [or `(', as appropriate] is represented by start_memory,
- \) by stop_memory. Both of those commands are followed by
- a register number in the next byte. The text matched
- within the \( and \) is recorded under that number. */
- case start_memory:
- regstart[*p] = d;
- IS_ACTIVE (reg_info[*p]) = 1;
- MATCHED_SOMETHING (reg_info[*p]) = 0;
- p++;
- break;
-
- case stop_memory:
- regend[*p] = d;
- IS_ACTIVE (reg_info[*p]) = 0;
-
- /* If just failed to match something this time around with a sub-
- expression that's in a loop, try to force exit from the loop. */
- if ((! MATCHED_SOMETHING (reg_info[*p])
- || (enum regexpcode) p[-3] == start_memory)
- && (p + 1) != pend)
- {
- register unsigned char *p2 = p + 1;
- mcnt = 0;
- switch (*p2++)
- {
- case jump_n:
- is_a_jump_n = 1;
- case finalize_jump:
- case maybe_finalize_jump:
- case jump:
- case dummy_failure_jump:
- EXTRACT_NUMBER_AND_INCR (mcnt, p2);
- if (is_a_jump_n)
- p2 += 2;
- break;
- }
- p2 += mcnt;
-
- /* If the next operation is a jump backwards in the pattern
- to an on_failure_jump, exit from the loop by forcing a
- failure after pushing on the stack the on_failure_jump's
- jump in the pattern, and d. */
- if (mcnt < 0 && (enum regexpcode) *p2++ == on_failure_jump)
- {
- EXTRACT_NUMBER_AND_INCR (mcnt, p2);
- PUSH_FAILURE_POINT (p2 + mcnt, d);
- goto fail;
- }
- }
- p++;
- break;
-
- /* \<digit> has been turned into a `duplicate' command which is
- followed by the numeric value of <digit> as the register number. */
- case duplicate:
- {
- int regno = *p++; /* Get which register to match against */
- register unsigned char *d2, *dend2;
-
- /* Where in input to try to start matching. */
- d2 = regstart[regno];
-
- /* Where to stop matching; if both the place to start and
- the place to stop matching are in the same string, then
- set to the place to stop, otherwise, for now have to use
- the end of the first string. */
-
- dend2 = ((IS_IN_FIRST_STRING (regstart[regno])
- == IS_IN_FIRST_STRING (regend[regno]))
- ? regend[regno] : end_match_1);
- while (1)
- {
- /* If necessary, advance to next segment in register
- contents. */
- while (d2 == dend2)
- {
- if (dend2 == end_match_2) break;
- if (dend2 == regend[regno]) break;
- d2 = string2, dend2 = regend[regno]; /* end of string1 => advance to string2. */
- }
- /* At end of register contents => success */
- if (d2 == dend2) break;
-
- /* If necessary, advance to next segment in data. */
- PREFETCH;
-
- /* How many characters left in this segment to match. */
- mcnt = dend - d;
-
- /* Want how many consecutive characters we can match in
- one shot, so, if necessary, adjust the count. */
- if (mcnt > dend2 - d2)
- mcnt = dend2 - d2;
-
- /* Compare that many; failure if mismatch, else move
- past them. */
- if (translate
- ? memcmp_translate (d, d2, mcnt, translate)
- : memcmp ((char *)d, (char *)d2, mcnt))
- goto fail;
- d += mcnt, d2 += mcnt;
- }
- }
- break;
-
- case anychar:
- PREFETCH; /* Fetch a data character. */
- /* Match anything but a newline, maybe even a null. */
- if ((translate ? translate[*d] : *d) == '\n'
- || ((obscure_syntax & RE_DOT_NOT_NULL)
- && (translate ? translate[*d] : *d) == '\000'))
- goto fail;
- SET_REGS_MATCHED;
- d++;
- break;
-
- case charset:
- case charset_not:
- {
- int not = 0; /* Nonzero for charset_not. */
- register int c;
- if (*(p - 1) == (unsigned char) charset_not)
- not = 1;
-
- PREFETCH; /* Fetch a data character. */
-
- if (translate)
- c = translate[*d];
- else
- c = *d;
-
- if (c < *p * BYTEWIDTH
- && p[1 + c / BYTEWIDTH] & (1 << (c % BYTEWIDTH)))
- not = !not;
-
- p += 1 + *p;
-
- if (!not) goto fail;
- SET_REGS_MATCHED;
- d++;
- break;
- }
-
- case begline:
- if ((size1 != 0 && d == string1)
- || (size1 == 0 && size2 != 0 && d == string2)
- || (d && d[-1] == '\n')
- || (size1 == 0 && size2 == 0))
- break;
- else
- goto fail;
-
- case endline:
- if (d == end2
- || (d == end1 ? (size2 == 0 || *string2 == '\n') : *d == '\n'))
- break;
- goto fail;
-
- /* `or' constructs are handled by starting each alternative with
- an on_failure_jump that points to the start of the next
- alternative. Each alternative except the last ends with a
- jump to the joining point. (Actually, each jump except for
- the last one really jumps to the following jump, because
- tensioning the jumps is a hassle.) */
-
- /* The start of a stupid repeat has an on_failure_jump that points
- past the end of the repeat text. This makes a failure point so
- that on failure to match a repetition, matching restarts past
- as many repetitions have been found with no way to fail and
- look for another one. */
-
- /* A smart repeat is similar but loops back to the on_failure_jump
- so that each repetition makes another failure point. */
-
- case on_failure_jump:
- on_failure:
- EXTRACT_NUMBER_AND_INCR (mcnt, p);
- PUSH_FAILURE_POINT (p + mcnt, d);
- break;
-
- /* The end of a smart repeat has a maybe_finalize_jump back.
- Change it either to a finalize_jump or an ordinary jump. */
- case maybe_finalize_jump:
- EXTRACT_NUMBER_AND_INCR (mcnt, p);
- {
- register unsigned char *p2 = p;
- /* Compare what follows with the beginning of the repeat.
- If we can establish that there is nothing that they would
- both match, we can change to finalize_jump. */
- while (p2 + 1 != pend
- && (*p2 == (unsigned char) stop_memory
- || *p2 == (unsigned char) start_memory))
- p2 += 2; /* Skip over reg number. */
- if (p2 == pend)
- p[-3] = (unsigned char) finalize_jump;
- else if (*p2 == (unsigned char) exactn
- || *p2 == (unsigned char) endline)
- {
- register int c = *p2 == (unsigned char) endline ? '\n' : p2[2];
- register unsigned char *p1 = p + mcnt;
- /* p1[0] ... p1[2] are an on_failure_jump.
- Examine what follows that. */
- if (p1[3] == (unsigned char) exactn && p1[5] != c)
- p[-3] = (unsigned char) finalize_jump;
- else if (p1[3] == (unsigned char) charset
- || p1[3] == (unsigned char) charset_not)
- {
- int not = p1[3] == (unsigned char) charset_not;
- if (c < p1[4] * BYTEWIDTH
- && p1[5 + c / BYTEWIDTH] & (1 << (c % BYTEWIDTH)))
- not = !not;
- /* `not' is 1 if c would match. */
- /* That means it is not safe to finalize. */
- if (!not)
- p[-3] = (unsigned char) finalize_jump;
- }
- }
- }
- p -= 2; /* Point at relative address again. */
- if (p[-1] != (unsigned char) finalize_jump)
- {
- p[-1] = (unsigned char) jump;
- goto nofinalize;
- }
- /* Note fall through. */
-
- /* The end of a stupid repeat has a finalize_jump back to the
- start, where another failure point will be made which will
- point to after all the repetitions found so far. */
-
- /* Take off failure points put on by matching on_failure_jump
- because didn't fail. Also remove the register information
- put on by the on_failure_jump. */
- case finalize_jump:
- POP_FAILURE_POINT ();
- /* Note fall through. */
-
- /* Jump without taking off any failure points. */
- case jump:
- nofinalize:
- EXTRACT_NUMBER_AND_INCR (mcnt, p);
- p += mcnt;
- break;
-
- case dummy_failure_jump:
- /* Normally, the on_failure_jump pushes a failure point, which
- then gets popped at finalize_jump. We will end up at
- finalize_jump, also, and with a pattern of, say, `a+', we
- are skipping over the on_failure_jump, so we have to push
- something meaningless for finalize_jump to pop. */
- PUSH_FAILURE_POINT (0, 0);
- goto nofinalize;
-
-
- /* Have to succeed matching what follows at least n times. Then
- just handle like an on_failure_jump. */
- case succeed_n:
- EXTRACT_NUMBER (mcnt, p + 2);
- /* Originally, this is how many times we HAVE to succeed. */
- if (mcnt)
- {
- mcnt--;
- p += 2;
- STORE_NUMBER_AND_INCR (p, mcnt);
- }
- else if (mcnt == 0)
- {
- p[2] = unused;
- p[3] = unused;
- goto on_failure;
- }
- else
- {
- fprintf (stderr, "regex: the succeed_n's n is not set.\n");
- exit (1);
- }
- break;
-
- case jump_n:
- EXTRACT_NUMBER (mcnt, p + 2);
- /* Originally, this is how many times we CAN jump. */
- if (mcnt)
- {
- mcnt--;
- STORE_NUMBER(p + 2, mcnt);
- goto nofinalize; /* Do the jump without taking off
- any failure points. */
- }
- /* If don't have to jump any more, skip over the rest of command. */
- else
- p += 4;
- break;
-
- case set_number_at:
- {
- register unsigned char *p1;
-
- EXTRACT_NUMBER_AND_INCR (mcnt, p);
- p1 = p + mcnt;
- EXTRACT_NUMBER_AND_INCR (mcnt, p);
- STORE_NUMBER (p1, mcnt);
- break;
- }
-
- /* Ignore these. Used to ignore the n of succeed_n's which
- currently have n == 0. */
- case unused:
- break;
-
- case wordbound:
- if (AT_WORD_BOUNDARY)
- break;
- goto fail;
-
- case notwordbound:
- if (AT_WORD_BOUNDARY)
- goto fail;
- break;
-
- case wordbeg:
- if (IS_A_LETTER (d) && (!IS_A_LETTER (d - 1) || AT_STRINGS_BEG))
- break;
- goto fail;
-
- case wordend:
- /* Have to check if AT_STRINGS_BEG before looking at d - 1. */
- if (!AT_STRINGS_BEG && IS_A_LETTER (d - 1)
- && (!IS_A_LETTER (d) || AT_STRINGS_END))
- break;
- goto fail;
-
-#ifdef emacs
- case before_dot:
- if (PTR_CHAR_POS (d) >= point)
- goto fail;
- break;
-
- case at_dot:
- if (PTR_CHAR_POS (d) != point)
- goto fail;
- break;
-
- case after_dot:
- if (PTR_CHAR_POS (d) <= point)
- goto fail;
- break;
-
- case wordchar:
- mcnt = (int) Sword;
- goto matchsyntax;
-
- case syntaxspec:
- mcnt = *p++;
- matchsyntax:
- PREFETCH;
- if (SYNTAX (*d++) != (enum syntaxcode) mcnt) goto fail;
- SET_REGS_MATCHED;
- break;
-
- case notwordchar:
- mcnt = (int) Sword;
- goto matchnotsyntax;
-
- case notsyntaxspec:
- mcnt = *p++;
- matchnotsyntax:
- PREFETCH;
- if (SYNTAX (*d++) == (enum syntaxcode) mcnt) goto fail;
- SET_REGS_MATCHED;
- break;
-
-#else /* not emacs */
-
- case wordchar:
- PREFETCH;
- if (!IS_A_LETTER (d))
- goto fail;
- SET_REGS_MATCHED;
- break;
-
- case notwordchar:
- PREFETCH;
- if (IS_A_LETTER (d))
- goto fail;
- SET_REGS_MATCHED;
- break;
-
- case before_dot:
- case at_dot:
- case after_dot:
- case syntaxspec:
- case notsyntaxspec:
- break;
-
-#endif /* not emacs */
-
- case begbuf:
- if (AT_STRINGS_BEG)
- break;
- goto fail;
-
- case endbuf:
- if (AT_STRINGS_END)
- break;
- goto fail;
-
- case exactn:
- /* Match the next few pattern characters exactly.
- mcnt is how many characters to match. */
- mcnt = *p++;
- /* This is written out as an if-else so we don't waste time
- testing `translate' inside the loop. */
- if (translate)
- {
- do
- {
- PREFETCH;
- if (translate[*d++] != *p++) goto fail;
- }
- while (--mcnt);
- }
- else
- {
- do
- {
- PREFETCH;
- if (*d++ != *p++) goto fail;
- }
- while (--mcnt);
- }
- SET_REGS_MATCHED;
- break;
- }
- continue; /* Successfully executed one pattern command; keep going. */
-
- /* Jump here if any matching operation fails. */
- fail:
- if (stackp != stackb)
- /* A restart point is known. Restart there and pop it. */
- {
- short last_used_reg, this_reg;
-
- /* If this failure point is from a dummy_failure_point, just
- skip it. */
- if (!stackp[-2])
- {
- POP_FAILURE_POINT ();
- goto fail;
- }
-
- d = *--stackp;
- p = *--stackp;
- if (d >= string1 && d <= end1)
- dend = end_match_1;
- /* Restore register info. */
- last_used_reg = (long) *--stackp;
-
- /* Make the ones that weren't saved -1 or 0 again. */
- for (this_reg = RE_NREGS - 1; this_reg > last_used_reg; this_reg--)
- {
- regend[this_reg] = (unsigned char *) (-1L);
- regstart[this_reg] = (unsigned char *) (-1L);
- IS_ACTIVE (reg_info[this_reg]) = 0;
- MATCHED_SOMETHING (reg_info[this_reg]) = 0;
- }
-
- /* And restore the rest from the stack. */
- for ( ; this_reg > 0; this_reg--)
- {
- reg_info[this_reg] = *(struct register_info *) *--stackp;
- regend[this_reg] = *--stackp;
- regstart[this_reg] = *--stackp;
- }
- }
- else
- break; /* Matching at this starting point really fails. */
- }
-
- if (best_regs_set)
- goto restore_best_regs;
-
- FREE_AND_RETURN(stackb,(-1)); /* Failure to match. */
-}
-
-
-static int
-memcmp_translate (s1, s2, len, translate)
- unsigned char *s1, *s2;
- register int len;
- unsigned char *translate;
-{
- register unsigned char *p1 = s1, *p2 = s2;
- while (len)
- {
- if (translate [*p1++] != translate [*p2++]) return 1;
- len--;
- }
- return 0;
-}
-
-
-
-/* Entry points compatible with 4.2 BSD regex library. */
-
-#if !defined(emacs) && !defined(GAWK)
-
-static struct re_pattern_buffer re_comp_buf;
-
-char *
-re_comp (s)
- char *s;
-{
- if (!s)
- {
- if (!re_comp_buf.buffer)
- return "No previous regular expression";
- return 0;
- }
-
- if (!re_comp_buf.buffer)
- {
- if (!(re_comp_buf.buffer = (char *) malloc (200)))
- return "Memory exhausted";
- re_comp_buf.allocated = 200;
- if (!(re_comp_buf.fastmap = (char *) malloc (1 << BYTEWIDTH)))
- return "Memory exhausted";
- }
- return re_compile_pattern (s, strlen (s), &re_comp_buf);
-}
-
-int
-re_exec (s)
- char *s;
-{
- int len = strlen (s);
- return 0 <= re_search (&re_comp_buf, s, len, 0, len,
- (struct re_registers *) 0);
-}
-#endif /* not emacs && not GAWK */
-
-
-
-#ifdef test
-
-#ifdef atarist
-long _stksize = 2L; /* reserve memory for stack */
-#endif
-#include <stdio.h>
-
-/* Indexed by a character, gives the upper case equivalent of the
- character. */
-
-char upcase[0400] =
- { 000, 001, 002, 003, 004, 005, 006, 007,
- 010, 011, 012, 013, 014, 015, 016, 017,
- 020, 021, 022, 023, 024, 025, 026, 027,
- 030, 031, 032, 033, 034, 035, 036, 037,
- 040, 041, 042, 043, 044, 045, 046, 047,
- 050, 051, 052, 053, 054, 055, 056, 057,
- 060, 061, 062, 063, 064, 065, 066, 067,
- 070, 071, 072, 073, 074, 075, 076, 077,
- 0100, 0101, 0102, 0103, 0104, 0105, 0106, 0107,
- 0110, 0111, 0112, 0113, 0114, 0115, 0116, 0117,
- 0120, 0121, 0122, 0123, 0124, 0125, 0126, 0127,
- 0130, 0131, 0132, 0133, 0134, 0135, 0136, 0137,
- 0140, 0101, 0102, 0103, 0104, 0105, 0106, 0107,
- 0110, 0111, 0112, 0113, 0114, 0115, 0116, 0117,
- 0120, 0121, 0122, 0123, 0124, 0125, 0126, 0127,
- 0130, 0131, 0132, 0173, 0174, 0175, 0176, 0177,
- 0200, 0201, 0202, 0203, 0204, 0205, 0206, 0207,
- 0210, 0211, 0212, 0213, 0214, 0215, 0216, 0217,
- 0220, 0221, 0222, 0223, 0224, 0225, 0226, 0227,
- 0230, 0231, 0232, 0233, 0234, 0235, 0236, 0237,
- 0240, 0241, 0242, 0243, 0244, 0245, 0246, 0247,
- 0250, 0251, 0252, 0253, 0254, 0255, 0256, 0257,
- 0260, 0261, 0262, 0263, 0264, 0265, 0266, 0267,
- 0270, 0271, 0272, 0273, 0274, 0275, 0276, 0277,
- 0300, 0301, 0302, 0303, 0304, 0305, 0306, 0307,
- 0310, 0311, 0312, 0313, 0314, 0315, 0316, 0317,
- 0320, 0321, 0322, 0323, 0324, 0325, 0326, 0327,
- 0330, 0331, 0332, 0333, 0334, 0335, 0336, 0337,
- 0340, 0341, 0342, 0343, 0344, 0345, 0346, 0347,
- 0350, 0351, 0352, 0353, 0354, 0355, 0356, 0357,
- 0360, 0361, 0362, 0363, 0364, 0365, 0366, 0367,
- 0370, 0371, 0372, 0373, 0374, 0375, 0376, 0377
- };
-
-#ifdef canned
-
-#include "tests.h"
-
-typedef enum { extended_test, basic_test } test_type;
-
-/* Use this to run the tests we've thought of. */
-
-void
-main ()
-{
- test_type t = extended_test;
-
- if (t == basic_test)
- {
- printf ("Running basic tests:\n\n");
- test_posix_basic ();
- }
- else if (t == extended_test)
- {
- printf ("Running extended tests:\n\n");
- test_posix_extended ();
- }
-}
-
-#else /* not canned */
-
-/* Use this to run interactive tests. */
-
-void
-main (argc, argv)
- int argc;
- char **argv;
-{
- char pat[80];
- struct re_pattern_buffer buf;
- int i;
- char c;
- char fastmap[(1 << BYTEWIDTH)];
-
- /* Allow a command argument to specify the style of syntax. */
- if (argc > 1)
- obscure_syntax = atol (argv[1]);
-
- buf.allocated = 40;
- buf.buffer = (char *) malloc (buf.allocated);
- buf.fastmap = fastmap;
- buf.translate = upcase;
-
- while (1)
- {
- gets (pat);
-
- if (*pat)
- {
- re_compile_pattern (pat, strlen(pat), &buf);
-
- for (i = 0; i < buf.used; i++)
- printchar (buf.buffer[i]);
-
- putchar ('\n');
-
- printf ("%d allocated, %d used.\n", buf.allocated, buf.used);
-
- re_compile_fastmap (&buf);
- printf ("Allowed by fastmap: ");
- for (i = 0; i < (1 << BYTEWIDTH); i++)
- if (fastmap[i]) printchar (i);
- putchar ('\n');
- }
-
- gets (pat); /* Now read the string to match against */
-
- i = re_match (&buf, pat, strlen (pat), 0, 0);
- printf ("Match value %d.\n", i);
- }
-}
-
-#endif
-
-
-#ifdef NOTDEF
-print_buf (bufp)
- struct re_pattern_buffer *bufp;
-{
- int i;
-
- printf ("buf is :\n----------------\n");
- for (i = 0; i < bufp->used; i++)
- printchar (bufp->buffer[i]);
-
- printf ("\n%d allocated, %d used.\n", bufp->allocated, bufp->used);
-
- printf ("Allowed by fastmap: ");
- for (i = 0; i < (1 << BYTEWIDTH); i++)
- if (bufp->fastmap[i])
- printchar (i);
- printf ("\nAllowed by translate: ");
- if (bufp->translate)
- for (i = 0; i < (1 << BYTEWIDTH); i++)
- if (bufp->translate[i])
- printchar (i);
- printf ("\nfastmap is%s accurate\n", bufp->fastmap_accurate ? "" : "n't");
- printf ("can %s be null\n----------", bufp->can_be_null ? "" : "not");
-}
-#endif /* NOTDEF */
-
-printchar (c)
- char c;
-{
- if (c < 040 || c >= 0177)
- {
- putchar ('\\');
- putchar (((c >> 6) & 3) + '0');
- putchar (((c >> 3) & 7) + '0');
- putchar ((c & 7) + '0');
- }
- else
- putchar (c);
-}
-
-error (string)
- char *string;
-{
- puts (string);
- exit (1);
-}
-#endif /* test */
diff --git a/gnu/usr.bin/awk/regex.h b/gnu/usr.bin/awk/regex.h
deleted file mode 100644
index fce11c3..0000000
--- a/gnu/usr.bin/awk/regex.h
+++ /dev/null
@@ -1,260 +0,0 @@
-/* Definitions for data structures callers pass the regex library.
-
- Copyright (C) 1985, 1989-90 Free Software Foundation, Inc.
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 1, or (at your option)
- any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
-
-
-#ifndef __REGEXP_LIBRARY
-#define __REGEXP_LIBRARY
-
-/* Define number of parens for which we record the beginnings and ends.
- This affects how much space the `struct re_registers' type takes up. */
-#ifndef RE_NREGS
-#define RE_NREGS 10
-#endif
-
-#define BYTEWIDTH 8
-
-
-/* Maximum number of duplicates an interval can allow. */
-#ifndef RE_DUP_MAX
-#define RE_DUP_MAX ((1 << 15) - 1)
-#endif
-
-
-/* This defines the various regexp syntaxes. */
-extern long obscure_syntax;
-
-
-/* The following bits are used in the obscure_syntax variable to choose among
- alternative regexp syntaxes. */
-
-/* If this bit is set, plain parentheses serve as grouping, and backslash
- parentheses are needed for literal searching.
- If not set, backslash-parentheses are grouping, and plain parentheses
- are for literal searching. */
-#define RE_NO_BK_PARENS 1L
-
-/* If this bit is set, plain | serves as the `or'-operator, and \| is a
- literal.
- If not set, \| serves as the `or'-operator, and | is a literal. */
-#define RE_NO_BK_VBAR (1L << 1)
-
-/* If this bit is not set, plain + or ? serves as an operator, and \+, \? are
- literals.
- If set, \+, \? are operators and plain +, ? are literals. */
-#define RE_BK_PLUS_QM (1L << 2)
-
-/* If this bit is set, | binds tighter than ^ or $.
- If not set, the contrary. */
-#define RE_TIGHT_VBAR (1L << 3)
-
-/* If this bit is set, then treat newline as an OR operator.
- If not set, treat it as a normal character. */
-#define RE_NEWLINE_OR (1L << 4)
-
-/* If this bit is set, then special characters may act as normal
- characters in some contexts. Specifically, this applies to:
- ^ -- only special at the beginning, or after ( or |;
- $ -- only special at the end, or before ) or |;
- *, +, ? -- only special when not after the beginning, (, or |.
- If this bit is not set, special characters (such as *, ^, and $)
- always have their special meaning regardless of the surrounding
- context. */
-#define RE_CONTEXT_INDEP_OPS (1L << 5)
-
-/* If this bit is not set, then \ before anything inside [ and ] is taken as
- a real \.
- If set, then such a \ escapes the following character. This is a
- special case for awk. */
-#define RE_AWK_CLASS_HACK (1L << 6)
-
-/* If this bit is set, then \{ and \} or { and } serve as interval operators.
- If not set, then \{ and \} and { and } are treated as literals. */
-#define RE_INTERVALS (1L << 7)
-
-/* If this bit is not set, then \{ and \} serve as interval operators and
- { and } are literals.
- If set, then { and } serve as interval operators and \{ and \} are
- literals. */
-#define RE_NO_BK_CURLY_BRACES (1L << 8)
-
-/* If this bit is set, then character classes are supported; they are:
- [:alpha:], [:upper:], [:lower:], [:digit:], [:alnum:], [:xdigit:],
- [:space:], [:print:], [:punct:], [:graph:], and [:cntrl:].
- If not set, then character classes are not supported. */
-#define RE_CHAR_CLASSES (1L << 9)
-
-/* If this bit is set, then the dot re doesn't match a null byte.
- If not set, it does. */
-#define RE_DOT_NOT_NULL (1L << 10)
-
-/* If this bit is set, then [^...] doesn't match a newline.
- If not set, it does. */
-#define RE_HAT_NOT_NEWLINE (1L << 11)
-
-/* If this bit is set, back references are recognized.
- If not set, they aren't. */
-#define RE_NO_BK_REFS (1L << 12)
-
-/* If this bit is set, back references must refer to a preceding
- subexpression. If not set, a back reference to a nonexistent
- subexpression is treated as literal characters. */
-#define RE_NO_EMPTY_BK_REF (1L << 13)
-
-/* If this bit is set, bracket expressions can't be empty.
- If it is set, they can be empty. */
-#define RE_NO_EMPTY_BRACKETS (1L << 14)
-
-/* If this bit is set, then *, +, ? and { cannot be first in an re or
- immediately after a |, or a (. Furthermore, a | cannot be first or
- last in an re, or immediately follow another | or a (. Also, a ^
- cannot appear in a nonleading position and a $ cannot appear in a
- nontrailing position (outside of bracket expressions, that is). */
-#define RE_CONTEXTUAL_INVALID_OPS (1L << 15)
-
-/* If this bit is set, then +, ? and | aren't recognized as operators.
- If it's not, they are. */
-#define RE_LIMITED_OPS (1L << 16)
-
-/* If this bit is set, then an ending range point has to collate higher
- or equal to the starting range point.
- If it's not set, then when the ending range point collates higher
- than the starting range point, the range is just considered empty. */
-#define RE_NO_EMPTY_RANGES (1L << 17)
-
-/* If this bit is set, then a hyphen (-) can't be an ending range point.
- If it isn't, then it can. */
-#define RE_NO_HYPHEN_RANGE_END (1L << 18)
-
-
-/* Define combinations of bits for the standard possibilities. */
-#define RE_SYNTAX_POSIX_AWK (RE_NO_BK_PARENS | RE_NO_BK_VBAR \
- | RE_CONTEXT_INDEP_OPS)
-#define RE_SYNTAX_AWK (RE_NO_BK_PARENS | RE_NO_BK_VBAR | RE_AWK_CLASS_HACK)
-#define RE_SYNTAX_EGREP (RE_NO_BK_PARENS | RE_NO_BK_VBAR \
- | RE_CONTEXT_INDEP_OPS | RE_NEWLINE_OR)
-#define RE_SYNTAX_GREP (RE_BK_PLUS_QM | RE_NEWLINE_OR)
-#define RE_SYNTAX_EMACS 0
-#define RE_SYNTAX_POSIX_BASIC (RE_INTERVALS | RE_BK_PLUS_QM \
- | RE_CHAR_CLASSES | RE_DOT_NOT_NULL \
- | RE_HAT_NOT_NEWLINE | RE_NO_EMPTY_BK_REF \
- | RE_NO_EMPTY_BRACKETS | RE_LIMITED_OPS \
- | RE_NO_EMPTY_RANGES | RE_NO_HYPHEN_RANGE_END)
-
-#define RE_SYNTAX_POSIX_EXTENDED (RE_INTERVALS | RE_NO_BK_CURLY_BRACES \
- | RE_NO_BK_VBAR | RE_NO_BK_PARENS \
- | RE_HAT_NOT_NEWLINE | RE_CHAR_CLASSES \
- | RE_NO_EMPTY_BRACKETS | RE_CONTEXTUAL_INVALID_OPS \
- | RE_NO_BK_REFS | RE_NO_EMPTY_RANGES \
- | RE_NO_HYPHEN_RANGE_END)
-
-
-/* This data structure is used to represent a compiled pattern. */
-
-struct re_pattern_buffer
- {
- char *buffer; /* Space holding the compiled pattern commands. */
- long allocated; /* Size of space that `buffer' points to. */
- long used; /* Length of portion of buffer actually occupied */
- char *fastmap; /* Pointer to fastmap, if any, or zero if none. */
- /* re_search uses the fastmap, if there is one,
- to skip over totally implausible characters. */
- char *translate; /* Translate table to apply to all characters before
- comparing, or zero for no translation.
- The translation is applied to a pattern when it is
- compiled and to data when it is matched. */
- char fastmap_accurate;
- /* Set to zero when a new pattern is stored,
- set to one when the fastmap is updated from it. */
- char can_be_null; /* Set to one by compiling fastmap
- if this pattern might match the null string.
- It does not necessarily match the null string
- in that case, but if this is zero, it cannot.
- 2 as value means can match null string
- but at end of range or before a character
- listed in the fastmap. */
- };
-
-
-/* search.c (search_buffer) needs this one value. It is defined both in
- regex.c and here. */
-#define RE_EXACTN_VALUE 1
-
-
-/* Structure to store register contents data in.
-
- Pass the address of such a structure as an argument to re_match, etc.,
- if you want this information back.
-
- For i from 1 to RE_NREGS - 1, start[i] records the starting index in
- the string of where the ith subexpression matched, and end[i] records
- one after the ending index. start[0] and end[0] are analogous, for
- the entire pattern. */
-
-struct re_registers
- {
- int start[RE_NREGS];
- int end[RE_NREGS];
- };
-
-
-
-#ifdef __STDC__
-
-extern char *re_compile_pattern (char *, size_t, struct re_pattern_buffer *);
-/* Is this really advertised? */
-extern void re_compile_fastmap (struct re_pattern_buffer *);
-extern int re_search (struct re_pattern_buffer *, char*, int, int, int,
- struct re_registers *);
-extern int re_search_2 (struct re_pattern_buffer *, char *, int,
- char *, int, int, int,
- struct re_registers *, int);
-extern int re_match (struct re_pattern_buffer *, char *, int, int,
- struct re_registers *);
-extern int re_match_2 (struct re_pattern_buffer *, char *, int,
- char *, int, int, struct re_registers *, int);
-extern long re_set_syntax (long syntax);
-
-#ifndef GAWK
-/* 4.2 bsd compatibility. */
-extern char *re_comp (char *);
-extern int re_exec (char *);
-#endif
-
-#else /* !__STDC__ */
-
-extern char *re_compile_pattern ();
-/* Is this really advertised? */
-extern void re_compile_fastmap ();
-extern int re_search (), re_search_2 ();
-extern int re_match (), re_match_2 ();
-extern long re_set_syntax();
-
-#ifndef GAWK
-/* 4.2 bsd compatibility. */
-extern char *re_comp ();
-extern int re_exec ();
-#endif
-
-#endif /* __STDC__ */
-
-
-#ifdef SYNTAX_TABLE
-extern char *re_syntax_table;
-#endif
-
-#endif /* !__REGEXP_LIBRARY */
diff --git a/gnu/usr.bin/awk/version.c b/gnu/usr.bin/awk/version.c
index adea5fa..ffcd8e1 100644
--- a/gnu/usr.bin/awk/version.c
+++ b/gnu/usr.bin/awk/version.c
@@ -7,11 +7,11 @@ char *version_string = "@(#)Gnu Awk (gawk) 2.15";
the split char is ' '.
Added -v option to print version number
-
+
Fixed bug that caused rounding when printing large numbers */
/* 2.00beta Incorporated the functionality of the "new" awk as described
- the book (reference not handy). Extensively tested, but no
+ the book (reference not handy). Extensively tested, but no
doubt still buggy. Badly needs tuning and cleanup, in
particular in memory management which is currently almost
non-existent. */
@@ -42,5 +42,6 @@ char *version_string = "@(#)Gnu Awk (gawk) 2.15";
/* 2.14 Mostly bug fixes. */
/* 2.15 Bug fixes plus intermixing of command-line source and files,
- GNU long options, ARGIND, ERRNO and Plan 9 style /dev/ files. */
+ GNU long options, ARGIND, ERRNO and Plan 9 style /dev/ files.
+ `delete array'. OS/2 port added. */
diff --git a/gnu/usr.bin/bc/COPYING b/gnu/usr.bin/bc/COPYING
new file mode 100644
index 0000000..86cf81a
--- /dev/null
+++ b/gnu/usr.bin/bc/COPYING
@@ -0,0 +1,341 @@
+
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 675 Mass Ave, Cambridge, MA 02139, USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ Appendix: How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) 19yy <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) 19yy name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
+
diff --git a/gnu/usr.bin/bc/Makefile b/gnu/usr.bin/bc/Makefile
new file mode 100644
index 0000000..fac7437
--- /dev/null
+++ b/gnu/usr.bin/bc/Makefile
@@ -0,0 +1,6 @@
+PROG= bc
+SRCS= bc.c global.c scan.c util.c main.c number.c storage.c load.c execute.c
+MAN1= bc.1
+CFLAGS+= -D_POSIX_SOURCE -I$(.CURDIR)
+
+.include <bsd.prog.mk>
diff --git a/gnu/usr.bin/bc/bc.1 b/gnu/usr.bin/bc/bc.1
new file mode 100644
index 0000000..b387f92
--- /dev/null
+++ b/gnu/usr.bin/bc/bc.1
@@ -0,0 +1,730 @@
+.\"
+.\" bc.1 - the *roff document processor source for the bc manual
+.\"
+.\" This file is part of bc written for MINIX.
+.\" Copyright (C) 1991, 1992 Free Software Foundation, Inc.
+.\"
+.\" This program is free software; you can redistribute it and/or modify
+.\" it under the terms of the GNU General Public License as published by
+.\" the Free Software Foundation; either version 2 of the License , or
+.\" (at your option) any later version.
+.\"
+.\" This program is distributed in the hope that it will be useful,
+.\" but WITHOUT ANY WARRANTY; without even the implied warranty of
+.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+.\" GNU General Public License for more details.
+.\"
+.\" You should have received a copy of the GNU General Public License
+.\" along with this program; see the file COPYING. If not, write to
+.\" the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+.\"
+.\" You may contact the author by:
+.\" e-mail: phil@cs.wwu.edu
+.\" us-mail: Philip A. Nelson
+.\" Computer Science Department, 9062
+.\" Western Washington University
+.\" Bellingham, WA 98226-9062
+.\"
+.\"
+.TH bc 1 .\" "Command Manual" v1.02 "Feb 3, 1992"
+.SH NAME
+bc - An arbitrary precision calculator language
+.SH SYNTAX
+\fBbc\fR [ \fB-lws\fR ] [ \fI file ...\fR ]
+.SH VERSION
+This man page documents GNU bc version 1.02.
+.SH DESCRIPTION
+\fBbc\fR is a language that supports arbitrary precision numbers
+with interactive execution of statements. There are some similarities
+in the syntax to the C programming language.
+A standard math library is available by command line option.
+If requested, the math library is defined before processing any files.
+\fBbc\fR starts by processing code from all the files listed
+on the command line in the order listed. After all files have been
+processed, \fBbc\fR reads from the standard input. All code is
+executed as it is read. (If a file contains a command to halt the
+processor, \fBbc\fR will never read from the standard input.)
+.PP
+This version of \fBbc\fR contains several extensions beyond
+traditional \fBbc\fR implementations and the POSIX draft standard.
+Command line options can cause these extensions to print a warning
+or to be rejected. This
+document describes the language accepted by this processor.
+Extensions will be identified as such.
+.SS OPTIONS
+.IP -l
+Define the standard math library.
+.IP -w
+Give warnings for extensions to POSIX \fBbc\fR.
+.IP -s
+Process exactly the POSIX \fBbc\fR language.
+.SS NUMBERS
+The most basic element in \fBbc\fR is the number. Numbers are
+arbitrary precision numbers. This precision is both in the integer
+part and the fractional part. All numbers are represented internally
+in decimal and all computation is done in decimal. (This version
+truncates results from divide and multiply operations.) There are two
+attributes of numbers, the length and the scale. The length is the
+total number of significant decimal digits in a number and the scale
+is the total number of decimal digits after the decimal point. For
+example:
+.nf
+.RS
+ .000001 has a length of 6 and scale of 6.
+ 1935.000 has a length of 7 and a scale of 3.
+.RE
+.fi
+.SS VARIABLES
+Numbers are stored in two types of variables, simple variables and
+arrays. Both simple variables and array variables are named. Names
+begin with a letter followed by any number of letters, digits and
+underscores. All letters must be lower case. (Full alpha-numeric
+names are an extension. In POSIX \fBbc\fR all names are a single
+lower case letter.) The type of variable is clear by the context
+because all array variable names will be followed by brackets ([]).
+.PP
+There are four special variables, \fBscale, ibase, obase,\fR and
+\fBlast\fR. \fBscale\fR defines how some operations use digits after the
+decimal point. The default value of \fBscale\fR is 0. \fBibase\fR
+and \fBobase\fR define the conversion base for input and output
+numbers. The default for both input and output is base 10.
+\fBlast\fR (an extension) is a variable that has the value of the last
+printed number. These will be discussed in further detail where
+appropriate. All of these variables may have values assigned to them
+as well as used in expressions.
+.SS COMMENTS
+Comments in \fBbc\fR start with the characters \fB/*\fR and end with
+the characters \fB*/\fR. Comments may start anywhere and appear as a
+single space in the input. (This causes comments to delimit other
+input items. For example, a comment can not be found in the middle of
+a variable name.) Comments include any newlines (end of line) between
+the start and the end of the comment.
+.SS EXPRESSIONS
+The numbers are manipulated by expressions and statements. Since
+the language was designed to be interactive, statements and expressions
+are executed as soon as possible. There is no "main" program. Instead,
+code is executed as it is encountered. (Functions, discussed in
+detail later, are defined when encountered.)
+.PP
+A simple expression is just a constant. \fBbc\fR converts constants
+into internal decimal numbers using the current input base, specified
+by the variable \fBibase\fR. (There is an exception in functions.)
+The legal values of \fBibase\fR are 2 through 16 (F). Assigning a
+value outside this range to \fBibase\fR will result in a value of 2
+or 16. Input numbers may contain the characters 0-9 and A-F. (Note:
+They must be capitals. Lower case letters are variable names.)
+Single digit numbers always have the value of the digit regardless of
+the value of \fBibase\fR. (i.e. A = 10.) For multi-digit numbers,
+\fBbc\fR changes all input digits greater or equal to ibase to the
+value of \fBibase\fR-1. This makes the number \fBFFF\fR always be
+the largest 3 digit number of the input base.
+.PP
+Full expressions are similar to many other high level languages.
+Since there is only one kind of number, there are no rules for mixing
+types. Instead, there are rules on the scale of expressions. Every
+expression has a scale. This is derived from the scale of original
+numbers, the operation performed and in many cases, the value of the
+variable \fBscale\fR. Legal values of the variable \fBscale\fR are
+0 to the maximum number representable by a C integer.
+.PP
+In the following descriptions of legal expressions, "expr" refers to a
+complete expression and "var" refers to a simple or an array variable.
+A simple variable is just a
+.RS
+\fIname\fR
+.RE
+and an array variable is specified as
+.RS
+\fIname\fR[\fIexpr\fR]
+.RE
+Unless specifically
+mentioned the scale of the result is the maximum scale of the
+expressions involved.
+.IP "- expr"
+The result is the negation of the expression.
+.IP "++ var"
+The variable is incremented by one and the new value is the result of
+the expression.
+.IP "-- var"
+The variable
+is decremented by one and the new value is the result of the
+expression.
+.IP "var ++"
+ The result of the expression is the value of
+the variable and then the variable is incremented by one.
+.IP "var --"
+The result of the expression is the value of the variable and then
+the variable is decremented by one.
+.IP "expr + expr"
+The result of the expression is the sum of the two expressions.
+.IP "expr - expr"
+The result of the expression is the difference of the two expressions.
+.IP "expr * expr"
+The result of the expression is the product of the two expressions.
+.IP "expr / expr"
+The result of the expression is the quotient of the two expressions.
+The scale of the result is the value of the variable \fBscale\fR.
+.IP "expr % expr"
+The result of the expression is the "remainder" and it is computed in the
+following way. To compute a%b, first a/b is computed to \fBscale\fR
+digits. That result is used to compute a-(a/b)*b to the scale of the
+maximum of \fBscale\fR+scale(b) and scale(a). If \fBscale\fR is set
+to zero and both expressions are integers this expression is the
+integer remainder function.
+.IP "expr ^ expr"
+The result of the expression is the value of the first raised to the
+second. The second expression must be an integer. (If the second
+expression is not an integer, a warning is generated and the
+expression is truncated to get an integer value.) The scale of the
+result is \fBscale\fR if the exponent is negative. If the exponent
+is positive the scale of the result is the minimum of the scale of the
+first expression times the value of the exponent and the maximum of
+\fBscale\fR and the scale of the first expression. (e.g. scale(a^b)
+= min(scale(a)*b, max( \fBscale,\fR scale(a))).) It should be noted
+that expr^0 will always return the value of 1.
+.IP "( expr )"
+This alters the standard precedence to force the evaluation of the
+expression.
+.IP "var = expr"
+The variable is assigned the value of the expression.
+.IP "var <op>= expr"
+This is equivalent to "var = var <op> expr" with the exception that
+the "var" part is evaluated only once. This can make a difference if
+"var" is an array.
+.PP
+ Relational expressions are a special kind of expression
+that always evaluate to 0 or 1, 0 if the relation is false and 1 if
+the relation is true. These may appear in any legal expression.
+(POSIX bc requires that relational expressions are used only in if,
+while, and for statements and that only one relational test may be
+done in them.) The relational operators are
+.IP "expr1 < expr2"
+The result is 1 if expr1 is strictly less than expr2.
+.IP "expr1 <= expr2"
+The result is 1 if expr1 is less than or equal to expr2.
+.IP "expr1 > expr2"
+The result is 1 if expr1 is strictly greater than expr2.
+.IP "expr1 >= expr2"
+The result is 1 if expr1 is greater than or equal to expr2.
+.IP "expr1 == expr2"
+The result is 1 if expr1 is equal to expr2.
+.IP "expr1 != expr2"
+The result is 1 if expr1 is not equal to expr2.
+.PP
+Boolean operations are also legal. (POSIX \fBbc\fR does NOT have
+boolean operations). The result of all boolean operations are 0 and 1
+(for false and true) as in relational expressions. The boolean
+operators are:
+.IP "!expr"
+The result is 1 if expr is 0.
+.IP "expr && expr"
+The result is 1 if both expressions are non-zero.
+.IP "expr || expr"
+The result is 1 if either expression is non-zero.
+.PP
+The expression precedence is as follows: (lowest to highest)
+.nf
+.RS
+|| operator, left associative
+&& operator, left associative
+! operator, nonassociative
+Relational operators, left associative
+Assignment operator, right associative
++ and - operators, left associative
+*, / and % operators, left associative
+^ operator, right associative
+unary - operator, nonassociative
+++ and -- operators, nonassociative
+.RE
+.fi
+.PP
+This precedence was chosen so that POSIX compliant \fBbc\fR programs
+will run correctly. This will cause the use of the relational and
+logical operators to have some unusual behavior when used with
+assignment expressions. Consider the expression:
+.RS
+a = 3 < 5
+.RE
+.PP
+Most C programmers would assume this would assign the result of "3 <
+5" (the value 1) to the variable "a". What this does in \fBbc\fR is
+assign the value 3 to the variable "a" and then compare 3 to 5. It is
+best to use parenthesis when using relational and logical operators
+with the assignment operators.
+.PP
+There are a few more special expressions that are provided in \fBbc\fR.
+These have to do with user defined functions and standard
+functions. They all appear as "\fIname\fB(\fIparameters\fB)\fR".
+See the section on functions for user defined functions. The standard
+functions are:
+.IP "length ( expression )"
+The value of the length function is the number of significant digits in the
+expression.
+.IP "read ( )"
+The read function (an extension) will read a number from the standard
+input, regardless of where the function occurs. Beware, this can
+cause problems with the mixing of data and program in the standard input.
+The best use for this function is in a previously written program that
+needs input from the user, but never allows program code to be input
+from the user. The value of the read function is the number read from
+the standard input using the current value of the variable
+\fBibase\fR for the conversion base.
+.IP "scale ( expression )"
+The value of the scale function is the number of digits after the decimal
+point in the expression.
+.IP "sqrt ( expression )"
+The value of the sqrt function is the square root of the expression. If
+the expression is negative, a run time error is generated.
+.SS STATEMENTS
+Statements (as in most algebraic languages) provide the sequencing of
+expression evaluation. In \fBbc\fR statements are executed "as soon
+as possible." Execution happens when a newline in encountered and
+there is one or more complete statements. Due to this immediate
+execution, newlines are very important in \fBbc\fR. In fact, both a
+semicolon and a newline are used as statement separators. An
+improperly placed newline will cause a syntax error. Because newlines
+are statement separators, it is possible to hide a newline by using
+the backslash character. The sequence "\e<nl>", where <nl> is the
+newline appears to \fBbc\fR as whitespace instead of a newline. A
+statement list is a series of statements separated by semicolons and
+newlines. The following is a list of \fBbc\fR statements and what
+they do: (Things enclosed in brackets ([]) are optional parts of the
+statement.)
+.IP "expression"
+This statement does one of two things. If the expression starts with
+"<variable> <assignment> ...", it is considered to be an assignment
+statement. If the expression is not an assignment statement, the
+expression is evaluated and printed to the output. After the number
+is printed, a newline is printed. For example, "a=1" is an assignment
+statement and "(a=1)" is an expression that has an embedded
+assignment. All numbers that are printed are printed in the base
+specified by the variable \fBobase\fR. The legal values for \fB
+obase\fR are 2 through BC_BASE_MAX. (See the section LIMITS.) For
+bases 2 through 16, the usual method of writing numbers is used. For
+bases greater than 16, \fBbc\fR uses a multi-character digit method
+of printing the numbers where each higher base digit is printed as a
+base 10 number. The multi-character digits are separated by spaces.
+Each digit contains the number of characters required to represent the
+base ten value of "obase-1". Since numbers are of arbitrary
+precision, some numbers may not be printable on a single output line.
+These long numbers will be split across lines using the "\e" as the
+last character on a line. The maximum number of characters printed
+per line is 70. Due to the interactive nature of \fBbc\fR printing
+a number cause the side effect of assigning the printed value the the
+special variable \fBlast\fR. This allows the user to recover the
+last value printed without having to retype the expression that
+printed the number. Assigning to \fBlast\fR is legal and will
+overwrite the last printed value with the assigned value. The newly
+assigned value will remain until the next number is printed or another
+value is assigned to \fBlast\fR.
+.IP "string"
+The string is printed to the output. Strings start with a double quote
+character and contain all characters until the next double quote character.
+All characters are take literally, including any newline. No newline
+character is printed after the string.
+.IP "\fBprint\fR list"
+The print statement (an extension) provides another method of output.
+The "list" is a list of strings and expressions separated by commas.
+Each string or expression is printed in the order of the list. No
+terminating newline is printed. Expressions are evaluated and their
+value is printed and assigned the the variable \fBlast\fR. Strings
+in the print statement are printed to the output and may contain
+special characters. Special characters start with the backslash
+character (\e). The special characters recognized by \fBbc\fR are
+"b" (bell), "f" (form feed), "n" (newline), "r" (carriage return), "t"
+(tab), and "\e" (backslash). Any other character following the
+backslash will be ignored. This still does not allow the double quote
+character to be part of any string.
+.IP "{ statement_list }"
+This is the compound statement. It allows multiple statements to be
+grouped together for execution.
+.IP "\fBif\fR ( expression ) \fBthen\fR statement1 [\fBelse\fR statement2]"
+The if statement evaluates the expression and executes statement1 or
+statement2 depending on the value of the expression. If the expression
+is non-zero, statement1 is executed. If statement2 is present and
+the value of the expression is 0, then statement2 is executed. (The
+else clause is an extension.)
+.IP "\fBwhile\fR ( expression ) statement"
+The while statement will execute the statement while the expression
+is non-zero. It evaluates the expression before each execution of
+the statement. Termination of the loop is caused by a zero
+expression value or the execution of a break statement.
+.IP "\fBfor\fR ( [expression1] ; [expression2] ; [expression3] ) statement"
+The for statement controls repeated execution of the statement.
+Expression1 is evaluated before the loop. Expression2 is evaluated
+before each execution of the statement. If it is non-zero, the statement
+is evaluated. If it is zero, the loop is terminated. After each
+execution of the statement, expression3 is evaluated before the reevaluation
+of expression2. If expression1 or expression3 are missing, nothing is
+evaluated at the point they would be evaluated.
+If expression2 is missing, it is the same as substituting
+the value 1 for expression2. (The optional expressions are an
+extension. POSIX \fBbc\fR requires all three expressions.)
+The following is equivalent code for the for statement:
+.nf
+.RS
+expression1;
+while (expression2) {
+ statement;
+ expression3;
+}
+.RE
+.fi
+.IP "\fBbreak\fR"
+This statement causes a forced exit of the most recent enclosing while
+statement or for statement.
+.IP "\fBcontinue\fR"
+The continue statement (an extension) causes the most recent enclosing
+for statement to start the next iteration.
+.IP "\fBhalt\fR"
+The halt statement (an extension) is an executed statement that causes
+the \fBbc\fR processor to quit only when it is executed. For example,
+"if (0 == 1) halt" will not cause \fBbc\fR to terminate because the halt is
+not executed.
+.IP "\fBreturn\fR"
+Return the value 0 from a function. (See the section on functions.)
+.IP "\fBreturn\fR ( expression )"
+Return the value of the expression from a function. (See the section on
+functions.)
+.SS PSEUDO STATEMENTS
+These statements are not statements in the traditional sense. They are
+not executed statements. Their function is performed at "compile" time.
+.IP "\fBlimits\fR"
+Print the local limits enforced by the local version of \fBbc\fR. This
+is an extension.
+.IP "\fBquit\fR"
+When the quit statement is read, the \fBbc\fR processor
+is terminated, regardless of where the quit statement is found. For
+example, "if (0 == 1) quit" will cause \fBbc\fR to terminate.
+.IP "\fBwarranty\fR"
+Print a longer warranty notice. This is an extension.
+.SS FUNCTIONS
+Functions provide a method of defining a computation that can be executed
+later. Functions in
+.B bc
+always compute a value and return it to the caller. Function definitions
+are "dynamic" in the sense that a function is undefined until a definition
+is encountered in the input. That definition is then used until another
+definition function for the same name is encountered. The new definition
+then replaces the older definition. A function is defined as follows:
+.nf
+.RS
+\fBdefine \fIname \fB( \fIparameters \fB) { \fInewline
+\fI auto_list statement_list \fB}\fR
+.RE
+.fi
+A function call is just an expression of the form
+"\fIname\fB(\fIparameters\fB)\fR".
+.PP
+Parameters are numbers or arrays (an extension). In the function definition,
+zero or more parameters are defined by listing their names separated by
+commas. Numbers are only call by value parameters. Arrays are only
+call by variable. Arrays are specified in the parameter definition by
+the notation "\fIname\fB[]\fR". In the function call, actual parameters
+are full expressions for number parameters. The same notation is used
+for passing arrays as for defining array parameters. The named array is
+passed by variable to the function. Since function definitions are dynamic,
+parameter numbers and types are checked when a function is called. Any
+mismatch in number or types of parameters will cause a runtime error.
+A runtime error will also occur for the call to an undefined function.
+.PP
+The \fIauto_list\fR is an optional list of variables that are for
+"local" use. The syntax of the auto list (if present) is "\fBauto
+\fIname\fR, ... ;". (The semicolon is optional.) Each \fIname\fR is
+the name of an auto variable. Arrays may be specified by using the
+same notation as used in parameters. These variables have their
+values pushed onto a stack at the start of the function. The
+variables are then initialized to zero and used throughout the
+execution of the function. At function exit, these variables are
+popped so that the original value (at the time of the function call)
+of these variables are restored. The parameters are really auto
+variables that are initialized to a value provided in the function
+call. Auto variables are different than traditional local variables
+in the fact that if function A calls function B, B may access function
+A's auto variables by just using the same name, unless function B has
+called them auto variables. Due to the fact that auto variables and
+parameters are pushed onto a stack, \fBbc\fR supports recursive functions.
+.PP
+The function body is a list of \fBbc\fR statements. Again, statements
+are separated by semicolons or newlines. Return statements cause the
+termination of a function and the return of a value. There are two
+versions of the return statement. The first form, "\fBreturn\fR", returns
+the value 0 to the calling expression. The second form,
+"\fBreturn ( \fIexpression \fB)\fR", computes the value of the expression
+and returns that value to the calling expression. There is an implied
+"\fBreturn (0)\fR" at the end of every function. This allows a function
+to terminate and return 0 without an explicit return statement.
+.PP
+Functions also change the usage of the variable \fBibase\fR. All
+constants in the function body will be converted using the value of
+\fBibase\fR at the time of the function call. Changes of \fBibase\fR
+will be ignored during the execution of the function except for the
+standard function \fBread\fR, which will always use the current value
+of \fBibase\fR for conversion of numbers.
+.SS MATH LIBRARY
+If \fBbc\fR is invoked with the \fB-l\fR option, a math library is preloaded
+and the default scale is set to 20. The math functions will calculate their
+results to the scale set at the time of their call.
+The math library defines the following functions:
+.IP "s (\fIx\fR)"
+The sine of x in radians.
+.IP "c (\fIx\fR)"
+The cosine of x in radians.
+.IP "a (\fIx\fR)"
+The arctangent of x.
+.IP "l (\fIx\fR)"
+The natural logarithm of x.
+.IP "e (\fIx\fR)"
+The exponential function of raising e to the value x.
+.IP "j (\fIn,x\fR)"
+The bessel function of integer order n of x.
+.SS EXAMPLES
+In /bin/sh, the following will assign the value of "pi" to the shell
+variable \fBpi\fR.
+.RS
+\f(CW
+pi=$(echo "scale=10; 4*a(1)" | bc -l)
+\fR
+.RE
+.PP
+The following is the definition of the exponential function used in the
+math library. This function is written in POSIX \fBbc\fR.
+.nf
+.RS
+\f(CW
+scale = 20
+
+/* Uses the fact that e^x = (e^(x/2))^2
+ When x is small enough, we use the series:
+ e^x = 1 + x + x^2/2! + x^3/3! + ...
+*/
+
+define e(x) {
+ auto a, d, e, f, i, m, v, z
+
+ /* Check the sign of x. */
+ if (x<0) {
+ m = 1
+ x = -x
+ }
+
+ /* Precondition x. */
+ z = scale;
+ scale = 4 + z + .44*x;
+ while (x > 1) {
+ f += 1;
+ x /= 2;
+ }
+
+ /* Initialize the variables. */
+ v = 1+x
+ a = x
+ d = 1
+
+ for (i=2; 1; i++) {
+ e = (a *= x) / (d *= i)
+ if (e == 0) {
+ if (f>0) while (f--) v = v*v;
+ scale = z
+ if (m) return (1/v);
+ return (v/1);
+ }
+ v += e
+ }
+}
+\fR
+.RE
+.fi
+.PP
+The following is code that uses the extended features of \fBbc\fR to
+implement a simple program for calculating checkbook balances. This
+program is best kept in a file so that it can be used many times
+without having to retype it at every use.
+.nf
+.RS
+\f(CW
+scale=2
+print "\enCheck book program!\en"
+print " Remember, deposits are negative transactions.\en"
+print " Exit by a 0 transaction.\en\en"
+
+print "Initial balance? "; bal = read()
+bal /= 1
+print "\en"
+while (1) {
+ "current balance = "; bal
+ "transaction? "; trans = read()
+ if (trans == 0) break;
+ bal -= trans
+ bal /= 1
+}
+quit
+\fR
+.RE
+.fi
+.PP
+The following is the definition of the recursive factorial function.
+.nf
+.RS
+\f(CW
+define f (x) {
+ if (x <= 1) return (1);
+ return (f(x-1) * x);
+}
+\fR
+.RE
+.fi
+.SS DIFFERENCES
+This version of
+.B bc
+was implemented from the POSIX P1003.2/D11 draft and contains
+several differences and extensions relative to the draft and
+traditional implementations.
+It is not implemented in the traditional way using
+.I dc(1).
+This version is a single process which parses and runs a byte code
+translation of the program. There is an "undocumented" option (-c)
+that causes the program to output the byte code to
+the standard output instead of running it. It was mainly used for
+debugging the parser and preparing the math library.
+.PP
+A major source of differences is
+extensions, where a feature is extended to add more functionality and
+additions, where new features are added.
+The following is the list of differences and extensions.
+.IP LANG environment
+This version does not conform to the POSIX standard in the processing
+of the LANG environment variable and all environment variables starting
+with LC_.
+.IP names
+Traditional and POSIX
+.B bc
+have single letter names for functions, variables and arrays. They have
+been extended to be multi-character names that start with a letter and
+may contain letters, numbers and the underscore character.
+.IP Strings
+Strings are not allowed to contain NUL characters. POSIX says all characters
+must be included in strings.
+.IP last
+POSIX \fBbc\fR does not have a \fBlast\fR variable. Some implementations
+of \fBbc\fR use the period (.) in a similar way.
+.IP comparisons
+POSIX \fBbc\fR allows comparisons only in the if statement, the while
+statement, and the second expression of the for statement. Also, only
+one relational operation is allowed in each of those statements.
+.IP "if statement, else clause"
+POSIX \fBbc\fR does not have an else clause.
+.IP "for statement"
+POSIX \fBbc\fR requires all expressions to be present in the for statement.
+.IP "&&, ||, !"
+POSIX \fBbc\fR does not have the logical operators.
+.IP "read function"
+POSIX \fBbc\fR does not have a read function.
+.IP "print statement"
+POSIX \fBbc\fR does not have a print statement .
+.IP "continue statement"
+POSIX \fBbc\fR does not have a continue statement.
+.IP "array parameters"
+POSIX \fBbc\fR does not have array parameters. Other implementations
+of \fBbc\fR may have call by value array parameters.
+.IP "=+, =-, =*, =/, =%, =^"
+POSIX \fBbc\fR does not require these "old style" assignment operators to
+be defined. This version may allow these "old style" assignments. Use
+the limits statement to see if the installed version supports them. If
+it does support the "old style" assignment operators, the statement
+"a =- 1" will decrement \fBa\fR by 1 instead of setting \fBa\fR to the
+value -1.
+.IP "spaces in numbers"
+Other implementations of \fBbc\fR allow spaces in numbers. For example,
+"x=1 3" would assign the value 13 to the variable x. The same statement
+would cause a syntax error in this version of \fBbc\fR.
+.IP "errors and execution"
+This implementation varies from other implementations in terms of what
+code will be executed when syntax and other errors are found in the
+program. If a syntax error is found in a function definition, error
+recovery tries to find the beginning of a statement and continue to
+parse the function. Once a syntax error is found in the function, the
+function will not be callable and becomes undefined.
+Syntax errors in the interactive execution code will invalidate the
+current execution block. The execution block is terminated by an
+end of line that appears after a complete sequence of statements.
+For example,
+.nf
+.RS
+a = 1
+b = 2
+.RE
+.fi
+has two execution blocks and
+.nf
+.RS
+{ a = 1
+ b = 2 }
+.RE
+.fi
+has one execution block. Any runtime error will terminate the execution
+of the current execution block. A runtime warning will not terminate the
+current execution block.
+.IP "Interrupts"
+During an interactive session, the SIGINT signal (usually generated by
+the control-C character from the terminal) will cause execution of the
+current execution block to be interrupted. It will display a "runtime"
+error indicating which function was interrupted. After all runtime
+structures have been cleaned up, a message will be printed to notify the
+user that \fBbc\fR is ready for more input. All previously defined functions
+remain defined and the value of all non-auto variables are the value at
+the point of interruption. All auto variables and function parameters
+are removed during the
+clean up process. During a non-interactive
+session, the SIGINT signal will terminate the entire run of \fBbc\fR.
+.SS LIMITS
+The following are the limits currently in place for this
+.B bc
+processor. Some of them may have been changed by an installation.
+Use the limits statement to see the actual values.
+.IP BC_BASE_MAX
+The maximum output base is currently set at 999. The maximum input base
+is 16.
+.IP BC_DIM_MAX
+This is currently an arbitrary limit of 65535 as distributed. Your
+installation may be different.
+.IP BC_SCALE_MAX
+The number of digits after the decimal point is limited to INT_MAX digits.
+Also, the number of digits before the decimal point is limited to INT_MAX
+digits.
+.IP BC_STRING_MAX
+The limit on the number of characters in a string is INT_MAX characters.
+.IP exponent
+The value of the exponent in the raise operation (^) is limited to LONG_MAX.
+.IP multiply
+The multiply routine may yield incorrect results if a number
+has more than LONG_MAX / 90 total digits. For 32 bit longs, this number is
+23,860,929 digits.
+.IP "code size"
+Each function and the "main" program are limited to 10240 bytes of
+compiled byte code each. This limit (BC_MAX_SEGS) can be easily changed
+to have more than 10 segments of 1024 bytes.
+.IP "variable names"
+The current limit on the number of unique names is 32767 for each of
+simple variables, arrays and functions.
+.SH FILES
+In most installations, \fBbc\fR is completely self-contained.
+Where executable size is of importance or the C compiler does
+not deal with very long strings, \fBbc\fR will read
+the standard math library from the file /usr/local/lib/libmath.b.
+(The actual location may vary. It may be /lib/libmath.b.)
+.SH DIAGNOSTICS
+If any file on the command line can not be opened, \fBbc\fR will report
+that the file is unavailable and terminate. Also, there are compile
+and run time diagnostics that should be self-explanatory.
+.SH BUGS
+Error recovery is not very good yet.
+.SH AUTHOR
+.nf
+Philip A. Nelson
+phil@cs.wwu.edu
+.fi
+.SH ACKNOWLEDGEMENTS
+The author would like to thank Steve Sommars (sesv@iwtsf.att.com) for
+his extensive help in testing the implementation. Many great suggestions
+were given. This is a much better product due to his involvement.
diff --git a/gnu/usr.bin/bc/bc.c b/gnu/usr.bin/bc/bc.c
new file mode 100644
index 0000000..b6308d0
--- /dev/null
+++ b/gnu/usr.bin/bc/bc.c
@@ -0,0 +1,1369 @@
+#ifndef lint
+static char yysccsid[] = "@(#)yaccpar 1.8 (Berkeley) 01/20/90";
+#endif
+#define YYBYACC 1
+#line 2 "bc.y"
+/* bc.y: The grammar for a POSIX compatable bc processor with some
+ extensions to the language. */
+
+/* This file is part of bc written for MINIX.
+ Copyright (C) 1991, 1992 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License , or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; see the file COPYING. If not, write to
+ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ You may contact the author by:
+ e-mail: phil@cs.wwu.edu
+ us-mail: Philip A. Nelson
+ Computer Science Department, 9062
+ Western Washington University
+ Bellingham, WA 98226-9062
+
+*************************************************************************/
+
+#include "bcdefs.h"
+#include "global.h"
+#include "proto.h"
+#line 38 "bc.y"
+typedef union {
+ char *s_value;
+ char c_value;
+ int i_value;
+ arg_list *a_value;
+ } YYSTYPE;
+#line 46 "y.tab.c"
+#define NEWLINE 257
+#define AND 258
+#define OR 259
+#define NOT 260
+#define STRING 261
+#define NAME 262
+#define NUMBER 263
+#define MUL_OP 264
+#define ASSIGN_OP 265
+#define REL_OP 266
+#define INCR_DECR 267
+#define Define 268
+#define Break 269
+#define Quit 270
+#define Length 271
+#define Return 272
+#define For 273
+#define If 274
+#define While 275
+#define Sqrt 276
+#define Else 277
+#define Scale 278
+#define Ibase 279
+#define Obase 280
+#define Auto 281
+#define Read 282
+#define Warranty 283
+#define Halt 284
+#define Last 285
+#define Continue 286
+#define Print 287
+#define Limits 288
+#define UNARY_MINUS 289
+#define YYERRCODE 256
+short yylhs[] = { -1,
+ 0, 0, 10, 10, 10, 11, 11, 11, 11, 12,
+ 12, 12, 12, 12, 12, 15, 15, 13, 13, 13,
+ 13, 13, 13, 13, 13, 13, 13, 16, 17, 18,
+ 19, 13, 20, 13, 22, 23, 13, 13, 25, 13,
+ 24, 24, 26, 26, 21, 27, 21, 28, 14, 5,
+ 5, 6, 6, 6, 7, 7, 7, 7, 8, 8,
+ 9, 9, 9, 9, 4, 4, 2, 2, 29, 1,
+ 30, 1, 31, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 3, 3, 3, 3, 3, 3,
+};
+short yylen[] = { 2,
+ 0, 2, 2, 1, 2, 0, 1, 3, 2, 0,
+ 1, 2, 3, 2, 3, 1, 2, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 4, 0, 0, 0,
+ 0, 13, 0, 7, 0, 0, 7, 3, 0, 3,
+ 1, 3, 1, 1, 0, 0, 3, 0, 12, 0,
+ 1, 0, 3, 3, 1, 3, 3, 5, 0, 1,
+ 1, 3, 3, 5, 0, 1, 0, 1, 0, 4,
+ 0, 4, 0, 4, 2, 3, 3, 3, 3, 3,
+ 2, 1, 1, 3, 4, 2, 2, 4, 4, 4,
+ 3, 1, 4, 1, 1, 1, 1,
+};
+short yydefred[] = { 1,
+ 0, 0, 0, 21, 0, 83, 0, 0, 22, 24,
+ 0, 0, 28, 0, 35, 0, 0, 94, 95, 0,
+ 18, 25, 97, 23, 39, 19, 0, 0, 0, 0,
+ 0, 2, 0, 16, 4, 7, 5, 17, 0, 0,
+ 0, 0, 96, 86, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 81, 0, 0, 0, 11, 71,
+ 73, 0, 0, 0, 0, 0, 69, 87, 3, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 91, 43, 0, 40, 0, 84,
+ 0, 0, 38, 0, 0, 0, 0, 0, 0, 0,
+ 0, 8, 0, 85, 0, 93, 0, 0, 0, 88,
+ 27, 0, 0, 33, 0, 89, 90, 0, 13, 15,
+ 0, 0, 0, 62, 0, 0, 0, 0, 0, 29,
+ 0, 0, 42, 0, 56, 0, 0, 0, 0, 0,
+ 64, 0, 0, 0, 46, 34, 37, 0, 48, 58,
+ 30, 0, 0, 0, 0, 47, 53, 54, 0, 0,
+ 0, 31, 49, 0, 32,
+};
+short yydgoto[] = { 1,
+ 30, 79, 31, 113, 108, 149, 109, 73, 74, 32,
+ 33, 58, 34, 35, 59, 48, 138, 155, 164, 131,
+ 146, 50, 132, 88, 54, 89, 152, 154, 101, 94,
+ 95,
+};
+short yysindex[] = { 0,
+ -7, 58, 212, 0, -22, 0, -233, -241, 0, 0,
+ -8, -5, 0, -4, 0, 2, 4, 0, 0, 9,
+ 0, 0, 0, 0, 0, 0, 212, 212, 91, 725,
+ -240, 0, -29, 0, 0, 0, 0, 0, 84, 245,
+ 212, -57, 0, 0, 10, 212, 212, 14, 212, 16,
+ 212, 212, 23, 156, 0, 549, 127, -52, 0, 0,
+ 0, 212, 212, 212, 212, 212, 0, 0, 0, 91,
+ -17, 725, 24, -3, 578, -205, 562, 725, 27, 212,
+ 606, 212, 669, 716, 0, 0, 725, 0, 19, 0,
+ 91, 127, 0, 212, 212, -36, -39, -91, -91, -36,
+ 212, 0, 166, 0, 277, 0, -21, 36, 40, 0,
+ 0, 725, 28, 0, 725, 0, 0, 156, 0, 0,
+ 84, 540, -39, 0, -9, 725, -2, -37, -174, 0,
+ 127, 48, 0, 346, 0, -167, 3, 212, -185, 127,
+ 0, -188, 6, 37, 0, 0, 0, -205, 0, 0,
+ 0, 127, -42, 91, 212, 0, 0, 0, -20, 54,
+ 26, 0, 0, 127, 0,
+};
+short yyrindex[] = { 0,
+ -16, 0, 0, 0, 409, 0, 0, 0, 0, 0,
+ 0, -58, 0, 0, 0, 0, 426, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, -50, 46,
+ 470, 0, 0, 0, 0, 0, 0, 0, 661, 56,
+ 0, 525, 0, 0, 0, 0, 59, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, -6,
+ 705, 7, 0, 60, 0, 61, 0, 63, 0, 49,
+ 0, 0, 0, 0, 0, 0, 17, 0, 78, 0,
+ -47, -45, 0, 0, 0, 537, 440, 620, 637, 594,
+ 0, 0, 0, 0, 0, 0, -33, 0, 66, 0,
+ 0, -19, 0, 0, 68, 0, 0, 0, 0, 0,
+ 667, 680, 508, 0, 705, 18, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, -31, 49, -44, 0,
+ 0, -40, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 1, 69, 0, 0, 0, 0, 0,
+ 13, 0, 0, 0, 0,
+};
+short yygindex[] = { 0,
+ 958, 0, 104, -118, 0, 0, -35, 0, 0, 0,
+ 0, -34, 22, 0, 15, 0, 0, 0, 0, 0,
+ 0, 0, 0, -1, 0, 0, 0, 0, 0, 0,
+ 0,
+};
+#define YYTABLESIZE 1113
+short yytable[] = { 52,
+ 26, 129, 66, 64, 52, 65, 92, 55, 10, 57,
+ 55, 12, 57, 14, 45, 36, 158, 40, 52, 144,
+ 45, 66, 40, 38, 67, 55, 68, 57, 42, 70,
+ 40, 46, 28, 41, 47, 49, 160, 27, 92, 66,
+ 105, 51, 6, 52, 43, 18, 19, 61, 53, 76,
+ 61, 23, 9, 80, 66, 82, 107, 66, 63, 10,
+ 44, 63, 118, 85, 104, 28, 26, 111, 41, 127,
+ 27, 12, 93, 103, 10, 44, 128, 12, 38, 14,
+ 45, 134, 52, 129, 102, 136, 130, 137, 140, 142,
+ 135, 145, 148, 143, 162, 151, 59, 28, 150, 67,
+ 60, 50, 27, 68, 20, 119, 51, 65, 36, 65,
+ 44, 0, 153, 120, 0, 29, 133, 0, 0, 159,
+ 0, 0, 0, 0, 0, 0, 64, 0, 65, 0,
+ 28, 0, 0, 0, 0, 27, 41, 0, 0, 0,
+ 0, 44, 0, 0, 0, 0, 0, 0, 29, 0,
+ 163, 0, 139, 0, 0, 0, 0, 0, 0, 0,
+ 0, 147, 0, 0, 0, 0, 28, 0, 0, 0,
+ 20, 27, 62, 156, 0, 119, 0, 66, 0, 0,
+ 29, 0, 0, 0, 0, 165, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 28, 0, 0, 26, 0,
+ 27, 0, 41, 0, 91, 28, 10, 0, 0, 12,
+ 27, 14, 45, 29, 157, 52, 52, 0, 26, 52,
+ 52, 52, 52, 55, 62, 57, 52, 69, 52, 52,
+ 52, 52, 52, 52, 52, 52, 161, 52, 52, 52,
+ 6, 52, 52, 52, 52, 52, 52, 52, 2, 29,
+ 9, 28, 3, 4, 5, 6, 27, 10, 124, 7,
+ 8, 9, 10, 11, 12, 13, 14, 15, 16, 12,
+ 17, 18, 19, 44, 20, 21, 22, 23, 24, 25,
+ 26, 57, 0, 0, 28, 3, 4, 5, 6, 27,
+ 0, 0, 7, 44, 9, 10, 11, 12, 13, 14,
+ 15, 16, 20, 17, 18, 19, 0, 20, 21, 22,
+ 23, 24, 25, 26, 37, 0, 28, 3, 4, 5,
+ 6, 27, 20, 0, 7, 0, 9, 10, 11, 12,
+ 13, 14, 15, 16, 41, 17, 18, 19, 0, 20,
+ 21, 22, 23, 24, 25, 26, 57, 62, 0, 63,
+ 3, 4, 5, 6, 41, 0, 0, 7, 0, 9,
+ 10, 11, 12, 13, 14, 15, 16, 0, 17, 18,
+ 19, 0, 20, 21, 22, 23, 24, 25, 26, 0,
+ 0, 0, 0, 0, 0, 28, 3, 4, 5, 6,
+ 27, 0, 0, 7, 0, 9, 10, 11, 12, 13,
+ 14, 15, 16, 0, 17, 18, 19, 0, 20, 21,
+ 22, 23, 24, 25, 26, 3, 86, 5, 6, 0,
+ 0, 0, 7, 0, 0, 3, 11, 5, 6, 0,
+ 0, 16, 7, 17, 18, 19, 11, 20, 141, 0,
+ 23, 16, 0, 17, 18, 19, 0, 20, 0, 92,
+ 23, 92, 92, 92, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 96, 92, 96, 96,
+ 96, 3, 0, 5, 6, 0, 0, 0, 7, 0,
+ 76, 0, 11, 76, 96, 0, 0, 16, 0, 17,
+ 18, 19, 0, 20, 0, 0, 23, 0, 76, 0,
+ 0, 92, 92, 0, 3, 0, 71, 6, 0, 0,
+ 82, 7, 82, 82, 82, 11, 0, 0, 96, 96,
+ 16, 0, 17, 18, 19, 0, 20, 0, 82, 23,
+ 0, 0, 76, 92, 0, 0, 3, 0, 125, 6,
+ 0, 0, 0, 7, 0, 0, 0, 11, 70, 0,
+ 96, 70, 16, 0, 17, 18, 19, 0, 20, 0,
+ 0, 23, 82, 82, 76, 92, 70, 92, 92, 92,
+ 0, 0, 0, 0, 0, 0, 0, 79, 0, 79,
+ 79, 79, 64, 92, 65, 0, 0, 0, 0, 90,
+ 0, 64, 0, 65, 82, 79, 0, 0, 0, 0,
+ 70, 0, 110, 0, 64, 3, 65, 5, 6, 0,
+ 0, 0, 7, 0, 0, 0, 11, 92, 92, 0,
+ 64, 16, 65, 17, 18, 19, 0, 20, 0, 79,
+ 23, 0, 70, 66, 80, 0, 80, 80, 80, 0,
+ 0, 0, 66, 0, 0, 0, 114, 0, 64, 92,
+ 65, 0, 80, 0, 0, 66, 0, 0, 0, 0,
+ 77, 79, 77, 77, 77, 92, 92, 92, 0, 0,
+ 106, 66, 92, 92, 92, 92, 0, 78, 77, 78,
+ 78, 78, 96, 96, 96, 92, 80, 0, 0, 96,
+ 96, 96, 96, 0, 0, 78, 76, 76, 76, 66,
+ 0, 75, 96, 0, 75, 76, 0, 72, 0, 116,
+ 72, 64, 77, 65, 0, 0, 76, 0, 80, 75,
+ 74, 0, 0, 74, 0, 72, 82, 82, 82, 78,
+ 0, 0, 0, 82, 0, 82, 0, 0, 74, 0,
+ 0, 0, 0, 0, 77, 92, 82, 92, 92, 92,
+ 0, 0, 0, 75, 0, 0, 117, 0, 64, 72,
+ 65, 78, 66, 0, 70, 70, 70, 64, 0, 65,
+ 0, 0, 74, 70, 0, 0, 0, 0, 0, 0,
+ 0, 92, 92, 92, 70, 75, 0, 0, 92, 0,
+ 92, 72, 0, 79, 79, 79, 0, 60, 92, 0,
+ 79, 92, 79, 62, 74, 63, 60, 61, 0, 66,
+ 0, 0, 62, 79, 63, 0, 0, 0, 66, 60,
+ 61, 0, 0, 0, 0, 62, 0, 63, 0, 0,
+ 0, 0, 0, 0, 0, 60, 61, 0, 0, 0,
+ 0, 62, 0, 63, 0, 0, 0, 0, 0, 0,
+ 80, 80, 80, 0, 0, 0, 0, 80, 0, 80,
+ 0, 0, 0, 60, 61, 0, 0, 0, 0, 62,
+ 80, 63, 0, 0, 0, 0, 77, 77, 77, 0,
+ 0, 0, 0, 0, 0, 77, 0, 0, 0, 0,
+ 0, 0, 0, 78, 78, 78, 77, 0, 0, 0,
+ 0, 0, 78, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 78, 0, 0, 0, 75, 75, 75,
+ 0, 0, 0, 72, 72, 72, 60, 61, 0, 0,
+ 0, 0, 62, 0, 63, 0, 74, 75, 74, 0,
+ 0, 0, 0, 72, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 74, 0, 0, 0,
+ 39, 0, 92, 92, 0, 0, 0, 0, 92, 92,
+ 92, 92, 0, 60, 61, 0, 0, 0, 0, 62,
+ 0, 63, 60, 61, 55, 56, 0, 0, 62, 0,
+ 63, 0, 0, 0, 0, 0, 0, 72, 75, 0,
+ 0, 0, 0, 77, 78, 0, 81, 0, 83, 84,
+ 0, 87, 0, 0, 0, 0, 0, 0, 0, 96,
+ 97, 98, 99, 100, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 112, 0, 115,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 121, 122, 0, 0, 0, 0, 0, 123, 0,
+ 75, 0, 126, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 87, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 75, 0, 0, 0, 112, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 112,
+};
+short yycheck[] = { 40,
+ 59, 44, 94, 43, 45, 45, 59, 41, 59, 41,
+ 44, 59, 44, 59, 59, 1, 59, 40, 59, 138,
+ 262, 41, 40, 2, 265, 59, 267, 59, 262, 59,
+ 40, 40, 40, 91, 40, 40, 155, 45, 59, 59,
+ 44, 40, 59, 40, 278, 279, 280, 41, 40, 40,
+ 44, 285, 59, 40, 94, 40, 262, 94, 41, 59,
+ 44, 44, 44, 41, 41, 40, 125, 41, 91, 91,
+ 45, 59, 125, 91, 125, 59, 41, 125, 57, 125,
+ 125, 91, 123, 44, 70, 123, 59, 262, 41, 257,
+ 93, 277, 281, 91, 41, 59, 41, 40, 93, 41,
+ 41, 41, 45, 41, 59, 91, 41, 59, 41, 41,
+ 7, -1, 148, 92, -1, 123, 118, -1, -1, 154,
+ -1, -1, -1, -1, -1, -1, 43, -1, 45, -1,
+ 40, -1, -1, -1, -1, 45, 59, -1, -1, -1,
+ -1, 125, -1, -1, -1, -1, -1, -1, 123, -1,
+ 125, -1, 131, -1, -1, -1, -1, -1, -1, -1,
+ -1, 140, -1, -1, -1, -1, 40, -1, -1, -1,
+ 125, 45, 264, 152, -1, 161, -1, 94, -1, -1,
+ 123, -1, -1, -1, -1, 164, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, 40, -1, -1, 257, -1,
+ 45, -1, 125, -1, 257, 40, 257, -1, -1, 257,
+ 45, 257, 257, 123, 257, 256, 257, -1, 277, 260,
+ 261, 262, 263, 257, 264, 257, 267, 257, 269, 270,
+ 271, 272, 273, 274, 275, 276, 257, 278, 279, 280,
+ 257, 282, 283, 284, 285, 286, 287, 288, 256, 123,
+ 257, 40, 260, 261, 262, 263, 45, 257, 93, 267,
+ 268, 269, 270, 271, 272, 273, 274, 275, 276, 257,
+ 278, 279, 280, 257, 282, 283, 284, 285, 286, 287,
+ 288, 256, -1, -1, 40, 260, 261, 262, 263, 45,
+ -1, -1, 267, 277, 269, 270, 271, 272, 273, 274,
+ 275, 276, 257, 278, 279, 280, -1, 282, 283, 284,
+ 285, 286, 287, 288, 257, -1, 40, 260, 261, 262,
+ 263, 45, 277, -1, 267, -1, 269, 270, 271, 272,
+ 273, 274, 275, 276, 257, 278, 279, 280, -1, 282,
+ 283, 284, 285, 286, 287, 288, 256, 264, -1, 266,
+ 260, 261, 262, 263, 277, -1, -1, 267, -1, 269,
+ 270, 271, 272, 273, 274, 275, 276, -1, 278, 279,
+ 280, -1, 282, 283, 284, 285, 286, 287, 288, -1,
+ -1, -1, -1, -1, -1, 40, 260, 261, 262, 263,
+ 45, -1, -1, 267, -1, 269, 270, 271, 272, 273,
+ 274, 275, 276, -1, 278, 279, 280, -1, 282, 283,
+ 284, 285, 286, 287, 288, 260, 261, 262, 263, -1,
+ -1, -1, 267, -1, -1, 260, 271, 262, 263, -1,
+ -1, 276, 267, 278, 279, 280, 271, 282, 93, -1,
+ 285, 276, -1, 278, 279, 280, -1, 282, -1, 41,
+ 285, 43, 44, 45, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, 41, 59, 43, 44,
+ 45, 260, -1, 262, 263, -1, -1, -1, 267, -1,
+ 41, -1, 271, 44, 59, -1, -1, 276, -1, 278,
+ 279, 280, -1, 282, -1, -1, 285, -1, 59, -1,
+ -1, 93, 94, -1, 260, -1, 262, 263, -1, -1,
+ 41, 267, 43, 44, 45, 271, -1, -1, 93, 94,
+ 276, -1, 278, 279, 280, -1, 282, -1, 59, 285,
+ -1, -1, 93, 125, -1, -1, 260, -1, 262, 263,
+ -1, -1, -1, 267, -1, -1, -1, 271, 41, -1,
+ 125, 44, 276, -1, 278, 279, 280, -1, 282, -1,
+ -1, 285, 93, 94, 125, 41, 59, 43, 44, 45,
+ -1, -1, -1, -1, -1, -1, -1, 41, -1, 43,
+ 44, 45, 43, 59, 45, -1, -1, -1, -1, 41,
+ -1, 43, -1, 45, 125, 59, -1, -1, -1, -1,
+ 93, -1, 41, -1, 43, 260, 45, 262, 263, -1,
+ -1, -1, 267, -1, -1, -1, 271, 93, 94, -1,
+ 43, 276, 45, 278, 279, 280, -1, 282, -1, 93,
+ 285, -1, 125, 94, 41, -1, 43, 44, 45, -1,
+ -1, -1, 94, -1, -1, -1, 41, -1, 43, 125,
+ 45, -1, 59, -1, -1, 94, -1, -1, -1, -1,
+ 41, 125, 43, 44, 45, 257, 258, 259, -1, -1,
+ 93, 94, 264, 265, 266, 267, -1, 41, 59, 43,
+ 44, 45, 257, 258, 259, 277, 93, -1, -1, 264,
+ 265, 266, 267, -1, -1, 59, 257, 258, 259, 94,
+ -1, 41, 277, -1, 44, 266, -1, 41, -1, 41,
+ 44, 43, 93, 45, -1, -1, 277, -1, 125, 59,
+ 41, -1, -1, 44, -1, 59, 257, 258, 259, 93,
+ -1, -1, -1, 264, -1, 266, -1, -1, 59, -1,
+ -1, -1, -1, -1, 125, 41, 277, 43, 44, 45,
+ -1, -1, -1, 93, -1, -1, 41, -1, 43, 93,
+ 45, 125, 94, -1, 257, 258, 259, 43, -1, 45,
+ -1, -1, 93, 266, -1, -1, -1, -1, -1, -1,
+ -1, 257, 258, 259, 277, 125, -1, -1, 264, -1,
+ 266, 125, -1, 257, 258, 259, -1, 258, 94, -1,
+ 264, 277, 266, 264, 125, 266, 258, 259, -1, 94,
+ -1, -1, 264, 277, 266, -1, -1, -1, 94, 258,
+ 259, -1, -1, -1, -1, 264, -1, 266, -1, -1,
+ -1, -1, -1, -1, -1, 258, 259, -1, -1, -1,
+ -1, 264, -1, 266, -1, -1, -1, -1, -1, -1,
+ 257, 258, 259, -1, -1, -1, -1, 264, -1, 266,
+ -1, -1, -1, 258, 259, -1, -1, -1, -1, 264,
+ 277, 266, -1, -1, -1, -1, 257, 258, 259, -1,
+ -1, -1, -1, -1, -1, 266, -1, -1, -1, -1,
+ -1, -1, -1, 257, 258, 259, 277, -1, -1, -1,
+ -1, -1, 266, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, 277, -1, -1, -1, 257, 258, 259,
+ -1, -1, -1, 257, 258, 259, 258, 259, -1, -1,
+ -1, -1, 264, -1, 266, -1, 257, 277, 259, -1,
+ -1, -1, -1, 277, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, 277, -1, -1, -1,
+ 3, -1, 258, 259, -1, -1, -1, -1, 264, 265,
+ 266, 267, -1, 258, 259, -1, -1, -1, -1, 264,
+ -1, 266, 258, 259, 27, 28, -1, -1, 264, -1,
+ 266, -1, -1, -1, -1, -1, -1, 40, 41, -1,
+ -1, -1, -1, 46, 47, -1, 49, -1, 51, 52,
+ -1, 54, -1, -1, -1, -1, -1, -1, -1, 62,
+ 63, 64, 65, 66, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, 80, -1, 82,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, 94, 95, -1, -1, -1, -1, -1, 101, -1,
+ 103, -1, 105, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, 118, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, 134, -1, -1, -1, 138, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, 155,
+};
+#define YYFINAL 1
+#ifndef YYDEBUG
+#define YYDEBUG 0
+#endif
+#define YYMAXTOKEN 289
+#if YYDEBUG
+char *yyname[] = {
+"end-of-file",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,"'('","')'",0,"'+'","','","'-'",0,0,0,0,0,0,0,0,0,0,0,0,0,"';'",0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,"'['",0,"']'","'^'",0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,"'{'",0,"'}'",0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,"NEWLINE","AND","OR","NOT","STRING","NAME","NUMBER","MUL_OP",
+"ASSIGN_OP","REL_OP","INCR_DECR","Define","Break","Quit","Length","Return",
+"For","If","While","Sqrt","Else","Scale","Ibase","Obase","Auto","Read",
+"Warranty","Halt","Last","Continue","Print","Limits","UNARY_MINUS",
+};
+char *yyrule[] = {
+"$accept : program",
+"program :",
+"program : program input_item",
+"input_item : semicolon_list NEWLINE",
+"input_item : function",
+"input_item : error NEWLINE",
+"semicolon_list :",
+"semicolon_list : statement_or_error",
+"semicolon_list : semicolon_list ';' statement_or_error",
+"semicolon_list : semicolon_list ';'",
+"statement_list :",
+"statement_list : statement_or_error",
+"statement_list : statement_list NEWLINE",
+"statement_list : statement_list NEWLINE statement_or_error",
+"statement_list : statement_list ';'",
+"statement_list : statement_list ';' statement",
+"statement_or_error : statement",
+"statement_or_error : error statement",
+"statement : Warranty",
+"statement : Limits",
+"statement : expression",
+"statement : STRING",
+"statement : Break",
+"statement : Continue",
+"statement : Quit",
+"statement : Halt",
+"statement : Return",
+"statement : Return '(' return_expression ')'",
+"$$1 :",
+"$$2 :",
+"$$3 :",
+"$$4 :",
+"statement : For $$1 '(' opt_expression ';' $$2 opt_expression ';' $$3 opt_expression ')' $$4 statement",
+"$$5 :",
+"statement : If '(' expression ')' $$5 statement opt_else",
+"$$6 :",
+"$$7 :",
+"statement : While $$6 '(' expression $$7 ')' statement",
+"statement : '{' statement_list '}'",
+"$$8 :",
+"statement : Print $$8 print_list",
+"print_list : print_element",
+"print_list : print_element ',' print_list",
+"print_element : STRING",
+"print_element : expression",
+"opt_else :",
+"$$9 :",
+"opt_else : Else $$9 statement",
+"$$10 :",
+"function : Define NAME '(' opt_parameter_list ')' '{' NEWLINE opt_auto_define_list $$10 statement_list NEWLINE '}'",
+"opt_parameter_list :",
+"opt_parameter_list : define_list",
+"opt_auto_define_list :",
+"opt_auto_define_list : Auto define_list NEWLINE",
+"opt_auto_define_list : Auto define_list ';'",
+"define_list : NAME",
+"define_list : NAME '[' ']'",
+"define_list : define_list ',' NAME",
+"define_list : define_list ',' NAME '[' ']'",
+"opt_argument_list :",
+"opt_argument_list : argument_list",
+"argument_list : expression",
+"argument_list : NAME '[' ']'",
+"argument_list : argument_list ',' expression",
+"argument_list : argument_list ',' NAME '[' ']'",
+"opt_expression :",
+"opt_expression : expression",
+"return_expression :",
+"return_expression : expression",
+"$$11 :",
+"expression : named_expression ASSIGN_OP $$11 expression",
+"$$12 :",
+"expression : expression AND $$12 expression",
+"$$13 :",
+"expression : expression OR $$13 expression",
+"expression : NOT expression",
+"expression : expression REL_OP expression",
+"expression : expression '+' expression",
+"expression : expression '-' expression",
+"expression : expression MUL_OP expression",
+"expression : expression '^' expression",
+"expression : '-' expression",
+"expression : named_expression",
+"expression : NUMBER",
+"expression : '(' expression ')'",
+"expression : NAME '(' opt_argument_list ')'",
+"expression : INCR_DECR named_expression",
+"expression : named_expression INCR_DECR",
+"expression : Length '(' expression ')'",
+"expression : Sqrt '(' expression ')'",
+"expression : Scale '(' expression ')'",
+"expression : Read '(' ')'",
+"named_expression : NAME",
+"named_expression : NAME '[' expression ']'",
+"named_expression : Ibase",
+"named_expression : Obase",
+"named_expression : Scale",
+"named_expression : Last",
+};
+#endif
+#define yyclearin (yychar=(-1))
+#define yyerrok (yyerrflag=0)
+#ifdef YYSTACKSIZE
+#ifndef YYMAXDEPTH
+#define YYMAXDEPTH YYSTACKSIZE
+#endif
+#else
+#ifdef YYMAXDEPTH
+#define YYSTACKSIZE YYMAXDEPTH
+#else
+#define YYSTACKSIZE 500
+#define YYMAXDEPTH 500
+#endif
+#endif
+int yydebug;
+int yynerrs;
+int yyerrflag;
+int yychar;
+short *yyssp;
+YYSTYPE *yyvsp;
+YYSTYPE yyval;
+YYSTYPE yylval;
+short yyss[YYSTACKSIZE];
+YYSTYPE yyvs[YYSTACKSIZE];
+#define yystacksize YYSTACKSIZE
+#define YYABORT goto yyabort
+#define YYACCEPT goto yyaccept
+#define YYERROR goto yyerrlab
+int
+yyparse()
+{
+ register int yym, yyn, yystate;
+#if YYDEBUG
+ register char *yys;
+ extern char *getenv();
+
+ if (yys = getenv("YYDEBUG"))
+ {
+ yyn = *yys;
+ if (yyn >= '0' && yyn <= '9')
+ yydebug = yyn - '0';
+ }
+#endif
+
+ yynerrs = 0;
+ yyerrflag = 0;
+ yychar = (-1);
+
+ yyssp = yyss;
+ yyvsp = yyvs;
+ *yyssp = yystate = 0;
+
+yyloop:
+ if (yyn = yydefred[yystate]) goto yyreduce;
+ if (yychar < 0)
+ {
+ if ((yychar = yylex()) < 0) yychar = 0;
+#if YYDEBUG
+ if (yydebug)
+ {
+ yys = 0;
+ if (yychar <= YYMAXTOKEN) yys = yyname[yychar];
+ if (!yys) yys = "illegal-symbol";
+ printf("yydebug: state %d, reading %d (%s)\n", yystate,
+ yychar, yys);
+ }
+#endif
+ }
+ if ((yyn = yysindex[yystate]) && (yyn += yychar) >= 0 &&
+ yyn <= YYTABLESIZE && yycheck[yyn] == yychar)
+ {
+#if YYDEBUG
+ if (yydebug)
+ printf("yydebug: state %d, shifting to state %d\n",
+ yystate, yytable[yyn]);
+#endif
+ if (yyssp >= yyss + yystacksize - 1)
+ {
+ goto yyoverflow;
+ }
+ *++yyssp = yystate = yytable[yyn];
+ *++yyvsp = yylval;
+ yychar = (-1);
+ if (yyerrflag > 0) --yyerrflag;
+ goto yyloop;
+ }
+ if ((yyn = yyrindex[yystate]) && (yyn += yychar) >= 0 &&
+ yyn <= YYTABLESIZE && yycheck[yyn] == yychar)
+ {
+ yyn = yytable[yyn];
+ goto yyreduce;
+ }
+ if (yyerrflag) goto yyinrecovery;
+#ifdef lint
+ goto yynewerror;
+#endif
+yynewerror:
+ yyerror("syntax error");
+#ifdef lint
+ goto yyerrlab;
+#endif
+yyerrlab:
+ ++yynerrs;
+yyinrecovery:
+ if (yyerrflag < 3)
+ {
+ yyerrflag = 3;
+ for (;;)
+ {
+ if ((yyn = yysindex[*yyssp]) && (yyn += YYERRCODE) >= 0 &&
+ yyn <= YYTABLESIZE && yycheck[yyn] == YYERRCODE)
+ {
+#if YYDEBUG
+ if (yydebug)
+ printf("yydebug: state %d, error recovery shifting\
+ to state %d\n", *yyssp, yytable[yyn]);
+#endif
+ if (yyssp >= yyss + yystacksize - 1)
+ {
+ goto yyoverflow;
+ }
+ *++yyssp = yystate = yytable[yyn];
+ *++yyvsp = yylval;
+ goto yyloop;
+ }
+ else
+ {
+#if YYDEBUG
+ if (yydebug)
+ printf("yydebug: error recovery discarding state %d\n",
+ *yyssp);
+#endif
+ if (yyssp <= yyss) goto yyabort;
+ --yyssp;
+ --yyvsp;
+ }
+ }
+ }
+ else
+ {
+ if (yychar == 0) goto yyabort;
+#if YYDEBUG
+ if (yydebug)
+ {
+ yys = 0;
+ if (yychar <= YYMAXTOKEN) yys = yyname[yychar];
+ if (!yys) yys = "illegal-symbol";
+ printf("yydebug: state %d, error recovery discards token %d (%s)\n",
+ yystate, yychar, yys);
+ }
+#endif
+ yychar = (-1);
+ goto yyloop;
+ }
+yyreduce:
+#if YYDEBUG
+ if (yydebug)
+ printf("yydebug: state %d, reducing by rule %d (%s)\n",
+ yystate, yyn, yyrule[yyn]);
+#endif
+ yym = yylen[yyn];
+ yyval = yyvsp[1-yym];
+ switch (yyn)
+ {
+case 1:
+#line 106 "bc.y"
+{
+ yyval.i_value = 0;
+ if (interactive)
+ {
+ printf ("%s\n", BC_VERSION);
+ welcome ();
+ }
+ }
+break;
+case 3:
+#line 117 "bc.y"
+{ run_code (); }
+break;
+case 4:
+#line 119 "bc.y"
+{ run_code (); }
+break;
+case 5:
+#line 121 "bc.y"
+{
+ yyerrok;
+ init_gen ();
+ }
+break;
+case 6:
+#line 127 "bc.y"
+{ yyval.i_value = 0; }
+break;
+case 10:
+#line 133 "bc.y"
+{ yyval.i_value = 0; }
+break;
+case 17:
+#line 142 "bc.y"
+{ yyval.i_value = yyvsp[0].i_value; }
+break;
+case 18:
+#line 145 "bc.y"
+{ warranty (""); }
+break;
+case 19:
+#line 147 "bc.y"
+{ limits (); }
+break;
+case 20:
+#line 149 "bc.y"
+{
+ if (yyvsp[0].i_value & 2)
+ warn ("comparison in expression");
+ if (yyvsp[0].i_value & 1)
+ generate ("W");
+ else
+ generate ("p");
+ }
+break;
+case 21:
+#line 158 "bc.y"
+{
+ yyval.i_value = 0;
+ generate ("w");
+ generate (yyvsp[0].s_value);
+ free (yyvsp[0].s_value);
+ }
+break;
+case 22:
+#line 165 "bc.y"
+{
+ if (break_label == 0)
+ yyerror ("Break outside a for/while");
+ else
+ {
+ sprintf (genstr, "J%1d:", break_label);
+ generate (genstr);
+ }
+ }
+break;
+case 23:
+#line 175 "bc.y"
+{
+ warn ("Continue statement");
+ if (continue_label == 0)
+ yyerror ("Continue outside a for");
+ else
+ {
+ sprintf (genstr, "J%1d:", continue_label);
+ generate (genstr);
+ }
+ }
+break;
+case 24:
+#line 186 "bc.y"
+{ exit (0); }
+break;
+case 25:
+#line 188 "bc.y"
+{ generate ("h"); }
+break;
+case 26:
+#line 190 "bc.y"
+{ generate ("0R"); }
+break;
+case 27:
+#line 192 "bc.y"
+{ generate ("R"); }
+break;
+case 28:
+#line 194 "bc.y"
+{
+ yyvsp[0].i_value = break_label;
+ break_label = next_label++;
+ }
+break;
+case 29:
+#line 199 "bc.y"
+{
+ if (yyvsp[-1].i_value > 1)
+ warn ("Comparison in first for expression");
+ yyvsp[-1].i_value = next_label++;
+ if (yyvsp[-1].i_value < 0)
+ sprintf (genstr, "N%1d:", yyvsp[-1].i_value);
+ else
+ sprintf (genstr, "pN%1d:", yyvsp[-1].i_value);
+ generate (genstr);
+ }
+break;
+case 30:
+#line 210 "bc.y"
+{
+ if (yyvsp[-1].i_value < 0) generate ("1");
+ yyvsp[-1].i_value = next_label++;
+ sprintf (genstr, "B%1d:J%1d:", yyvsp[-1].i_value, break_label);
+ generate (genstr);
+ yyval.i_value = continue_label;
+ continue_label = next_label++;
+ sprintf (genstr, "N%1d:", continue_label);
+ generate (genstr);
+ }
+break;
+case 31:
+#line 221 "bc.y"
+{
+ if (yyvsp[-1].i_value > 1)
+ warn ("Comparison in third for expression");
+ if (yyvsp[-1].i_value < 0)
+ sprintf (genstr, "J%1d:N%1d:", yyvsp[-7].i_value, yyvsp[-4].i_value);
+ else
+ sprintf (genstr, "pJ%1d:N%1d:", yyvsp[-7].i_value, yyvsp[-4].i_value);
+ generate (genstr);
+ }
+break;
+case 32:
+#line 231 "bc.y"
+{
+ sprintf (genstr, "J%1d:N%1d:",
+ continue_label, break_label);
+ generate (genstr);
+ break_label = yyvsp[-12].i_value;
+ continue_label = yyvsp[-4].i_value;
+ }
+break;
+case 33:
+#line 239 "bc.y"
+{
+ yyvsp[-1].i_value = if_label;
+ if_label = next_label++;
+ sprintf (genstr, "Z%1d:", if_label);
+ generate (genstr);
+ }
+break;
+case 34:
+#line 246 "bc.y"
+{
+ sprintf (genstr, "N%1d:", if_label);
+ generate (genstr);
+ if_label = yyvsp[-4].i_value;
+ }
+break;
+case 35:
+#line 252 "bc.y"
+{
+ yyvsp[0].i_value = next_label++;
+ sprintf (genstr, "N%1d:", yyvsp[0].i_value);
+ generate (genstr);
+ }
+break;
+case 36:
+#line 258 "bc.y"
+{
+ yyvsp[0].i_value = break_label;
+ break_label = next_label++;
+ sprintf (genstr, "Z%1d:", break_label);
+ generate (genstr);
+ }
+break;
+case 37:
+#line 265 "bc.y"
+{
+ sprintf (genstr, "J%1d:N%1d:", yyvsp[-6].i_value, break_label);
+ generate (genstr);
+ break_label = yyvsp[-3].i_value;
+ }
+break;
+case 38:
+#line 271 "bc.y"
+{ yyval.i_value = 0; }
+break;
+case 39:
+#line 273 "bc.y"
+{ warn ("print statement"); }
+break;
+case 43:
+#line 280 "bc.y"
+{
+ generate ("O");
+ generate (yyvsp[0].s_value);
+ free (yyvsp[0].s_value);
+ }
+break;
+case 44:
+#line 286 "bc.y"
+{ generate ("P"); }
+break;
+case 46:
+#line 290 "bc.y"
+{
+ warn ("else clause in if statement");
+ yyvsp[0].i_value = next_label++;
+ sprintf (genstr, "J%d:N%1d:", yyvsp[0].i_value, if_label);
+ generate (genstr);
+ if_label = yyvsp[0].i_value;
+ }
+break;
+case 48:
+#line 300 "bc.y"
+{
+ /* Check auto list against parameter list? */
+ check_params (yyvsp[-4].a_value,yyvsp[0].a_value);
+ sprintf (genstr, "F%d,%s.%s[", lookup(yyvsp[-6].s_value,FUNCT),
+ arg_str (yyvsp[-4].a_value,TRUE), arg_str (yyvsp[0].a_value,TRUE));
+ generate (genstr);
+ free_args (yyvsp[-4].a_value);
+ free_args (yyvsp[0].a_value);
+ yyvsp[-7].i_value = next_label;
+ next_label = 0;
+ }
+break;
+case 49:
+#line 312 "bc.y"
+{
+ generate ("0R]");
+ next_label = yyvsp[-11].i_value;
+ }
+break;
+case 50:
+#line 318 "bc.y"
+{ yyval.a_value = NULL; }
+break;
+case 52:
+#line 322 "bc.y"
+{ yyval.a_value = NULL; }
+break;
+case 53:
+#line 324 "bc.y"
+{ yyval.a_value = yyvsp[-1].a_value; }
+break;
+case 54:
+#line 326 "bc.y"
+{ yyval.a_value = yyvsp[-1].a_value; }
+break;
+case 55:
+#line 329 "bc.y"
+{ yyval.a_value = nextarg (NULL, lookup (yyvsp[0].s_value,SIMPLE)); }
+break;
+case 56:
+#line 331 "bc.y"
+{ yyval.a_value = nextarg (NULL, lookup (yyvsp[-2].s_value,ARRAY)); }
+break;
+case 57:
+#line 333 "bc.y"
+{ yyval.a_value = nextarg (yyvsp[-2].a_value, lookup (yyvsp[0].s_value,SIMPLE)); }
+break;
+case 58:
+#line 335 "bc.y"
+{ yyval.a_value = nextarg (yyvsp[-4].a_value, lookup (yyvsp[-2].s_value,ARRAY)); }
+break;
+case 59:
+#line 338 "bc.y"
+{ yyval.a_value = NULL; }
+break;
+case 61:
+#line 342 "bc.y"
+{
+ if (yyvsp[0].i_value > 1) warn ("comparison in argument");
+ yyval.a_value = nextarg (NULL,0);
+ }
+break;
+case 62:
+#line 347 "bc.y"
+{
+ sprintf (genstr, "K%d:", -lookup (yyvsp[-2].s_value,ARRAY));
+ generate (genstr);
+ yyval.a_value = nextarg (NULL,1);
+ }
+break;
+case 63:
+#line 353 "bc.y"
+{
+ if (yyvsp[0].i_value > 1) warn ("comparison in argument");
+ yyval.a_value = nextarg (yyvsp[-2].a_value,0);
+ }
+break;
+case 64:
+#line 358 "bc.y"
+{
+ sprintf (genstr, "K%d:", -lookup (yyvsp[-2].s_value,ARRAY));
+ generate (genstr);
+ yyval.a_value = nextarg (yyvsp[-4].a_value,1);
+ }
+break;
+case 65:
+#line 365 "bc.y"
+{
+ yyval.i_value = -1;
+ warn ("Missing expression in for statement");
+ }
+break;
+case 67:
+#line 372 "bc.y"
+{
+ yyval.i_value = 0;
+ generate ("0");
+ }
+break;
+case 68:
+#line 377 "bc.y"
+{
+ if (yyvsp[0].i_value > 1)
+ warn ("comparison in return expresion");
+ }
+break;
+case 69:
+#line 383 "bc.y"
+{
+ if (yyvsp[0].c_value != '=')
+ {
+ if (yyvsp[-1].i_value < 0)
+ sprintf (genstr, "DL%d:", -yyvsp[-1].i_value);
+ else
+ sprintf (genstr, "l%d:", yyvsp[-1].i_value);
+ generate (genstr);
+ }
+ }
+break;
+case 70:
+#line 394 "bc.y"
+{
+ if (yyvsp[0].i_value > 1) warn("comparison in assignment");
+ if (yyvsp[-2].c_value != '=')
+ {
+ sprintf (genstr, "%c", yyvsp[-2].c_value);
+ generate (genstr);
+ }
+ if (yyvsp[-3].i_value < 0)
+ sprintf (genstr, "S%d:", -yyvsp[-3].i_value);
+ else
+ sprintf (genstr, "s%d:", yyvsp[-3].i_value);
+ generate (genstr);
+ yyval.i_value = 0;
+ }
+break;
+case 71:
+#line 410 "bc.y"
+{
+ warn("&& operator");
+ yyvsp[0].i_value = next_label++;
+ sprintf (genstr, "DZ%d:p", yyvsp[0].i_value);
+ generate (genstr);
+ }
+break;
+case 72:
+#line 417 "bc.y"
+{
+ sprintf (genstr, "DZ%d:p1N%d:", yyvsp[-2].i_value, yyvsp[-2].i_value);
+ generate (genstr);
+ yyval.i_value = yyvsp[-3].i_value | yyvsp[0].i_value;
+ }
+break;
+case 73:
+#line 423 "bc.y"
+{
+ warn("|| operator");
+ yyvsp[0].i_value = next_label++;
+ sprintf (genstr, "B%d:", yyvsp[0].i_value);
+ generate (genstr);
+ }
+break;
+case 74:
+#line 430 "bc.y"
+{
+ int tmplab;
+ tmplab = next_label++;
+ sprintf (genstr, "B%d:0J%d:N%d:1N%d:",
+ yyvsp[-2].i_value, tmplab, yyvsp[-2].i_value, tmplab);
+ generate (genstr);
+ yyval.i_value = yyvsp[-3].i_value | yyvsp[0].i_value;
+ }
+break;
+case 75:
+#line 439 "bc.y"
+{
+ yyval.i_value = yyvsp[0].i_value;
+ warn("! operator");
+ generate ("!");
+ }
+break;
+case 76:
+#line 445 "bc.y"
+{
+ yyval.i_value = 3;
+ switch (*(yyvsp[-1].s_value))
+ {
+ case '=':
+ generate ("=");
+ break;
+
+ case '!':
+ generate ("#");
+ break;
+
+ case '<':
+ if (yyvsp[-1].s_value[1] == '=')
+ generate ("{");
+ else
+ generate ("<");
+ break;
+
+ case '>':
+ if (yyvsp[-1].s_value[1] == '=')
+ generate ("}");
+ else
+ generate (">");
+ break;
+ }
+ }
+break;
+case 77:
+#line 473 "bc.y"
+{
+ generate ("+");
+ yyval.i_value = yyvsp[-2].i_value | yyvsp[0].i_value;
+ }
+break;
+case 78:
+#line 478 "bc.y"
+{
+ generate ("-");
+ yyval.i_value = yyvsp[-2].i_value | yyvsp[0].i_value;
+ }
+break;
+case 79:
+#line 483 "bc.y"
+{
+ genstr[0] = yyvsp[-1].c_value;
+ genstr[1] = 0;
+ generate (genstr);
+ yyval.i_value = yyvsp[-2].i_value | yyvsp[0].i_value;
+ }
+break;
+case 80:
+#line 490 "bc.y"
+{
+ generate ("^");
+ yyval.i_value = yyvsp[-2].i_value | yyvsp[0].i_value;
+ }
+break;
+case 81:
+#line 495 "bc.y"
+{
+ generate ("n");
+ yyval.i_value = yyvsp[0].i_value;
+ }
+break;
+case 82:
+#line 500 "bc.y"
+{
+ yyval.i_value = 1;
+ if (yyvsp[0].i_value < 0)
+ sprintf (genstr, "L%d:", -yyvsp[0].i_value);
+ else
+ sprintf (genstr, "l%d:", yyvsp[0].i_value);
+ generate (genstr);
+ }
+break;
+case 83:
+#line 509 "bc.y"
+{
+ int len = strlen(yyvsp[0].s_value);
+ yyval.i_value = 1;
+ if (len == 1 && *yyvsp[0].s_value == '0')
+ generate ("0");
+ else if (len == 1 && *yyvsp[0].s_value == '1')
+ generate ("1");
+ else
+ {
+ generate ("K");
+ generate (yyvsp[0].s_value);
+ generate (":");
+ }
+ free (yyvsp[0].s_value);
+ }
+break;
+case 84:
+#line 525 "bc.y"
+{ yyval.i_value = yyvsp[-1].i_value | 1; }
+break;
+case 85:
+#line 527 "bc.y"
+{
+ yyval.i_value = 1;
+ if (yyvsp[-1].a_value != NULL)
+ {
+ sprintf (genstr, "C%d,%s:",
+ lookup (yyvsp[-3].s_value,FUNCT),
+ arg_str (yyvsp[-1].a_value,FALSE));
+ free_args (yyvsp[-1].a_value);
+ }
+ else
+ {
+ sprintf (genstr, "C%d:", lookup (yyvsp[-3].s_value,FUNCT));
+ }
+ generate (genstr);
+ }
+break;
+case 86:
+#line 543 "bc.y"
+{
+ yyval.i_value = 1;
+ if (yyvsp[0].i_value < 0)
+ {
+ if (yyvsp[-1].c_value == '+')
+ sprintf (genstr, "DA%d:L%d:", -yyvsp[0].i_value, -yyvsp[0].i_value);
+ else
+ sprintf (genstr, "DM%d:L%d:", -yyvsp[0].i_value, -yyvsp[0].i_value);
+ }
+ else
+ {
+ if (yyvsp[-1].c_value == '+')
+ sprintf (genstr, "i%d:l%d:", yyvsp[0].i_value, yyvsp[0].i_value);
+ else
+ sprintf (genstr, "d%d:l%d:", yyvsp[0].i_value, yyvsp[0].i_value);
+ }
+ generate (genstr);
+ }
+break;
+case 87:
+#line 562 "bc.y"
+{
+ yyval.i_value = 1;
+ if (yyvsp[-1].i_value < 0)
+ {
+ sprintf (genstr, "DL%d:x", -yyvsp[-1].i_value);
+ generate (genstr);
+ if (yyvsp[0].c_value == '+')
+ sprintf (genstr, "A%d:", -yyvsp[-1].i_value);
+ else
+ sprintf (genstr, "M%d:", -yyvsp[-1].i_value);
+ }
+ else
+ {
+ sprintf (genstr, "l%d:", yyvsp[-1].i_value);
+ generate (genstr);
+ if (yyvsp[0].c_value == '+')
+ sprintf (genstr, "i%d:", yyvsp[-1].i_value);
+ else
+ sprintf (genstr, "d%d:", yyvsp[-1].i_value);
+ }
+ generate (genstr);
+ }
+break;
+case 88:
+#line 585 "bc.y"
+{ generate ("cL"); yyval.i_value = 1;}
+break;
+case 89:
+#line 587 "bc.y"
+{ generate ("cR"); yyval.i_value = 1;}
+break;
+case 90:
+#line 589 "bc.y"
+{ generate ("cS"); yyval.i_value = 1;}
+break;
+case 91:
+#line 591 "bc.y"
+{
+ warn ("read function");
+ generate ("cI"); yyval.i_value = 1;
+ }
+break;
+case 92:
+#line 597 "bc.y"
+{ yyval.i_value = lookup(yyvsp[0].s_value,SIMPLE); }
+break;
+case 93:
+#line 599 "bc.y"
+{
+ if (yyvsp[-1].i_value > 1) warn("comparison in subscript");
+ yyval.i_value = lookup(yyvsp[-3].s_value,ARRAY);
+ }
+break;
+case 94:
+#line 604 "bc.y"
+{ yyval.i_value = 0; }
+break;
+case 95:
+#line 606 "bc.y"
+{ yyval.i_value = 1; }
+break;
+case 96:
+#line 608 "bc.y"
+{ yyval.i_value = 2; }
+break;
+case 97:
+#line 610 "bc.y"
+{ yyval.i_value = 3; }
+break;
+#line 1314 "y.tab.c"
+ }
+ yyssp -= yym;
+ yystate = *yyssp;
+ yyvsp -= yym;
+ yym = yylhs[yyn];
+ if (yystate == 0 && yym == 0)
+ {
+#if YYDEBUG
+ if (yydebug)
+ printf("yydebug: after reduction, shifting from state 0 to\
+ state %d\n", YYFINAL);
+#endif
+ yystate = YYFINAL;
+ *++yyssp = YYFINAL;
+ *++yyvsp = yyval;
+ if (yychar < 0)
+ {
+ if ((yychar = yylex()) < 0) yychar = 0;
+#if YYDEBUG
+ if (yydebug)
+ {
+ yys = 0;
+ if (yychar <= YYMAXTOKEN) yys = yyname[yychar];
+ if (!yys) yys = "illegal-symbol";
+ printf("yydebug: state %d, reading %d (%s)\n",
+ YYFINAL, yychar, yys);
+ }
+#endif
+ }
+ if (yychar == 0) goto yyaccept;
+ goto yyloop;
+ }
+ if ((yyn = yygindex[yym]) && (yyn += yystate) >= 0 &&
+ yyn <= YYTABLESIZE && yycheck[yyn] == yystate)
+ yystate = yytable[yyn];
+ else
+ yystate = yydgoto[yym];
+#if YYDEBUG
+ if (yydebug)
+ printf("yydebug: after reduction, shifting from state %d \
+to state %d\n", *yyssp, yystate);
+#endif
+ if (yyssp >= yyss + yystacksize - 1)
+ {
+ goto yyoverflow;
+ }
+ *++yyssp = yystate;
+ *++yyvsp = yyval;
+ goto yyloop;
+yyoverflow:
+ yyerror("yacc stack overflow");
+yyabort:
+ return (1);
+yyaccept:
+ return (0);
+}
diff --git a/gnu/usr.bin/bc/bcdefs.h b/gnu/usr.bin/bc/bcdefs.h
new file mode 100644
index 0000000..0f2c5e1
--- /dev/null
+++ b/gnu/usr.bin/bc/bcdefs.h
@@ -0,0 +1,154 @@
+/* bcdefs.h: The single file to include all constants and type definitions. */
+
+/* This file is part of bc written for MINIX.
+ Copyright (C) 1991, 1992 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License , or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; see the file COPYING. If not, write to
+ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ You may contact the author by:
+ e-mail: phil@cs.wwu.edu
+ us-mail: Philip A. Nelson
+ Computer Science Department, 9062
+ Western Washington University
+ Bellingham, WA 98226-9062
+
+*************************************************************************/
+
+/* Include the configuration file. */
+#include "config.h"
+
+/* Standard includes for all files. */
+#include <stdio.h>
+#include <sys/types.h>
+#include <ctype.h>
+#ifdef STRINGS_H
+#include <strings.h>
+#else
+#include <string.h>
+#endif
+#ifndef NO_LIMITS
+#include <limits.h>
+#endif
+
+/* Include the other definitions. */
+#include "const.h"
+#include "number.h"
+
+
+/* These definitions define all the structures used in
+ code and data storage. This includes the representation of
+ labels. The "guiding" principle is to make structures that
+ take a minimum of space when unused but can be built to contain
+ the full structures. */
+
+/* Labels are first. Labels are generated sequentially in functions
+ and full code. They just "point" to a single bye in the code. The
+ "address" is the byte number. The byte number is used to get an
+ actual character pointer. */
+
+typedef struct bc_label_group
+ {
+ long l_adrs [ BC_LABEL_GROUP ];
+ struct bc_label_group *l_next;
+ } bc_label_group;
+
+
+/* Each function has its own code segments and labels. There can be
+ no jumps between functions so labels are unique to a function. */
+
+typedef struct arg_list
+ {
+ int av_name;
+ struct arg_list *next;
+ } arg_list;
+
+typedef struct
+ {
+ char f_defined; /* Is this function defined yet. */
+ char *f_body[BC_MAX_SEGS];
+ int f_code_size;
+ bc_label_group *f_label;
+ arg_list *f_params;
+ arg_list *f_autos;
+ } bc_function;
+
+/* Code addresses. */
+typedef struct {
+ int pc_func;
+ int pc_addr;
+ } program_counter;
+
+
+/* Variables are "pushable" (auto) and thus we need a stack mechanism.
+ This is built into the variable record. */
+
+typedef struct bc_var
+ {
+ bc_num v_value;
+ struct bc_var *v_next;
+ } bc_var;
+
+
+/* bc arrays can also be "auto" variables and thus need the same
+ kind of stacking mechanisms. */
+
+typedef struct bc_array_node
+ {
+ union
+ {
+ bc_num n_num [NODE_SIZE];
+ struct bc_array_node *n_down [NODE_SIZE];
+ } n_items;
+ } bc_array_node;
+
+typedef struct bc_array
+ {
+ bc_array_node *a_tree;
+ short a_depth;
+ } bc_array;
+
+typedef struct bc_var_array
+ {
+ bc_array *a_value;
+ char a_param;
+ struct bc_var_array *a_next;
+ } bc_var_array;
+
+
+/* For the stacks, execution and function, we need records to allow
+ for arbitrary size. */
+
+typedef struct estack_rec {
+ bc_num s_num;
+ struct estack_rec *s_next;
+} estack_rec;
+
+typedef struct fstack_rec {
+ int s_val;
+ struct fstack_rec *s_next;
+} fstack_rec;
+
+
+/* The following are for the name tree. */
+
+typedef struct id_rec {
+ char *id; /* The program name. */
+ /* A name == 0 => nothing assigned yet. */
+ int a_name; /* The array variable name (number). */
+ int f_name; /* The function name (number). */
+ int v_name; /* The variable name (number). */
+ short balance; /* For the balanced tree. */
+ struct id_rec *left, *right; /* Tree pointers. */
+} id_rec;
diff --git a/gnu/usr.bin/bc/config.h b/gnu/usr.bin/bc/config.h
new file mode 100644
index 0000000..a9bd0be
--- /dev/null
+++ b/gnu/usr.bin/bc/config.h
@@ -0,0 +1,4 @@
+/* config.h */
+#ifndef __STDC__
+#define VARARGS
+#endif
diff --git a/gnu/usr.bin/bc/const.h b/gnu/usr.bin/bc/const.h
new file mode 100644
index 0000000..a4ab2ac
--- /dev/null
+++ b/gnu/usr.bin/bc/const.h
@@ -0,0 +1,87 @@
+/* const.h: Constants for bc. */
+
+/* This file is part of bc written for MINIX.
+ Copyright (C) 1991, 1992 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License , or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; see the file COPYING. If not, write to
+ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ You may contact the author by:
+ e-mail: phil@cs.wwu.edu
+ us-mail: Philip A. Nelson
+ Computer Science Department, 9062
+ Western Washington University
+ Bellingham, WA 98226-9062
+
+*************************************************************************/
+
+
+/* Define INT_MAX and LONG_MAX if not defined. Assuming 32 bits... */
+
+#ifdef NO_LIMITS
+#define INT_MAX 0x7FFFFFFF
+#define LONG_MAX 0x7FFFFFFF
+#endif
+
+
+/* Define constants in some reasonable size. The next 4 constants are
+ POSIX constants. */
+#if !defined(_POSIX_SOURCE)
+#define BC_BASE_MAX INT_MAX
+#define BC_SCALE_MAX INT_MAX
+#define BC_STRING_MAX INT_MAX
+
+/* Definitions for arrays. */
+
+#define BC_DIM_MAX 65535 /* this should be NODE_SIZE^NODE_DEPTH-1 */
+#endif
+
+#define NODE_SIZE 16 /* Must be a power of 2. */
+#define NODE_MASK 0xf /* Must be NODE_SIZE-1. */
+#define NODE_SHIFT 4 /* Number of 1 bits in NODE_MASK. */
+#define NODE_DEPTH 4
+
+
+/* Other BC limits defined but not part of POSIX. */
+
+#define BC_LABEL_GROUP 64
+#define BC_LABEL_LOG 6
+#define BC_MAX_SEGS 16 /* Code segments. */
+#define BC_SEG_SIZE 1024
+#define BC_SEG_LOG 10
+
+/* Maximum number of variables, arrays and functions and the
+ allocation increment for the dynamic arrays. */
+
+#define MAX_STORE 32767
+#define STORE_INCR 32
+
+/* Other interesting constants. */
+
+#define FALSE 0
+#define TRUE 1
+#define SIMPLE 0
+#define ARRAY 1
+#define FUNCT 2
+#define EXTERN extern
+#ifdef __STDC__
+#define CONST const
+#define VOID void
+#else
+#define CONST
+#define VOID
+#endif
+
+/* Include the version definition. */
+#include "version.h"
diff --git a/gnu/usr.bin/bc/execute.c b/gnu/usr.bin/bc/execute.c
new file mode 100644
index 0000000..a2f0e00
--- /dev/null
+++ b/gnu/usr.bin/bc/execute.c
@@ -0,0 +1,783 @@
+/* execute.c - run a bc program. */
+
+/* This file is part of bc written for MINIX.
+ Copyright (C) 1991, 1992 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License , or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; see the file COPYING. If not, write to
+ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ You may contact the author by:
+ e-mail: phil@cs.wwu.edu
+ us-mail: Philip A. Nelson
+ Computer Science Department, 9062
+ Western Washington University
+ Bellingham, WA 98226-9062
+
+*************************************************************************/
+
+#include "bcdefs.h"
+#include <signal.h>
+#include "global.h"
+#include "proto.h"
+
+
+/* The SIGINT interrupt handling routine. */
+
+int had_sigint;
+
+void
+stop_execution (sig)
+ int sig;
+{
+ had_sigint = TRUE;
+ printf ("\n");
+ rt_error ("interrupted execution");
+}
+
+
+/* Get the current byte and advance the PC counter. */
+
+unsigned char
+byte (pc)
+ program_counter *pc;
+{
+ int seg, offset;
+
+ seg = pc->pc_addr >> BC_SEG_LOG;
+ offset = pc->pc_addr++ % BC_SEG_SIZE;
+ return (functions[pc->pc_func].f_body[seg][offset]);
+}
+
+
+/* The routine that actually runs the machine. */
+
+void
+execute ()
+{
+ int label_num, l_gp, l_off;
+ bc_label_group *gp;
+
+ char inst, ch;
+ int new_func;
+ int var_name;
+
+ int const_base;
+
+ bc_num temp_num;
+ arg_list *auto_list;
+
+ /* Initialize this run... */
+ pc.pc_func = 0;
+ pc.pc_addr = 0;
+ runtime_error = FALSE;
+ init_num (&temp_num);
+
+ /* Set up the interrupt mechanism for an interactive session. */
+ if (interactive)
+ {
+ signal (SIGINT, stop_execution);
+ had_sigint = FALSE;
+ }
+
+ while (pc.pc_addr < functions[pc.pc_func].f_code_size && !runtime_error)
+ {
+ inst = byte(&pc);
+
+#if DEBUG > 3
+ { /* Print out address and the stack before each instruction.*/
+ int depth; estack_rec *temp = ex_stack;
+
+ printf ("func=%d addr=%d inst=%c\n",pc.pc_func, pc.pc_addr, inst);
+ if (temp == NULL) printf ("empty stack.\n", inst);
+ else
+ {
+ depth = 1;
+ while (temp != NULL)
+ {
+ printf (" %d = ", depth);
+ out_num (temp->s_num, 10, out_char);
+ depth++;
+ temp = temp->s_next;
+ }
+ }
+ }
+#endif
+
+ switch ( inst )
+ {
+
+ case 'A' : /* increment array variable (Add one). */
+ var_name = byte(&pc);
+ if ((var_name & 0x80) != 0)
+ var_name = ((var_name << 8) & 0x7f) + byte(&pc);
+ incr_array (var_name);
+ break;
+
+ case 'B' : /* Branch to a label if TOS != 0. Remove value on TOS. */
+ case 'Z' : /* Branch to a label if TOS == 0. Remove value on TOS. */
+ c_code = !is_zero (ex_stack->s_num);
+ pop ();
+ case 'J' : /* Jump to a label. */
+ label_num = byte(&pc); /* Low order bits first. */
+ label_num += byte(&pc) << 8;
+ if (inst == 'J' || (inst == 'B' && c_code)
+ || (inst == 'Z' && !c_code)) {
+ gp = functions[pc.pc_func].f_label;
+ l_gp = label_num >> BC_LABEL_LOG;
+ l_off = label_num % BC_LABEL_GROUP;
+ while (l_gp-- > 0) gp = gp->l_next;
+ pc.pc_addr = gp->l_adrs[l_off];
+ }
+ break;
+
+ case 'C' : /* Call a function. */
+ /* Get the function number. */
+ new_func = byte(&pc);
+ if ((new_func & 0x80) != 0)
+ new_func = ((new_func << 8) & 0x7f) + byte(&pc);
+
+ /* Check to make sure it is defined. */
+ if (!functions[new_func].f_defined)
+ {
+ rt_error ("Function %s not defined.", f_names[new_func]);
+ break;
+ }
+
+ /* Check and push parameters. */
+ process_params (&pc, new_func);
+
+ /* Push auto variables. */
+ for (auto_list = functions[new_func].f_autos;
+ auto_list != NULL;
+ auto_list = auto_list->next)
+ auto_var (auto_list->av_name);
+
+ /* Push pc and ibase. */
+ fpush (pc.pc_func);
+ fpush (pc.pc_addr);
+ fpush (i_base);
+
+ /* Reset pc to start of function. */
+ pc.pc_func = new_func;
+ pc.pc_addr = 0;
+ break;
+
+ case 'D' : /* Duplicate top of stack */
+ push_copy (ex_stack->s_num);
+ break;
+
+ case 'K' : /* Push a constant */
+ /* Get the input base and convert it to a bc number. */
+ if (pc.pc_func == 0)
+ const_base = i_base;
+ else
+ const_base = fn_stack->s_val;
+ if (const_base == 10)
+ push_b10_const (&pc);
+ else
+ push_constant (prog_char, const_base);
+ break;
+
+ case 'L' : /* load array variable */
+ var_name = byte(&pc);
+ if ((var_name & 0x80) != 0)
+ var_name = ((var_name << 8) & 0x7f) + byte(&pc);
+ load_array (var_name);
+ break;
+
+ case 'M' : /* decrement array variable (Minus!) */
+ var_name = byte(&pc);
+ if ((var_name & 0x80) != 0)
+ var_name = ((var_name << 8) & 0x7f) + byte(&pc);
+ decr_array (var_name);
+ break;
+
+ case 'O' : /* Write a string to the output with processing. */
+ while ((ch = byte(&pc)) != '"')
+ if (ch != '\\')
+ out_char (ch);
+ else
+ {
+ ch = byte(&pc);
+ if (ch == '"') break;
+ switch (ch)
+ {
+ case 'n': out_char ('\n'); break;
+ case 't': out_char ('\t'); break;
+ case 'r': out_char ('\r'); break;
+ case 'b': out_char (007); break;
+ case 'f': out_char ('\f'); break;
+ case '\\': out_char ('\\'); break;
+ default: break;
+ }
+ }
+ if (interactive) fflush (stdout);
+ break;
+
+ case 'R' : /* Return from function */
+ if (pc.pc_func != 0)
+ {
+ /* "Pop" autos and parameters. */
+ pop_vars(functions[pc.pc_func].f_autos);
+ pop_vars(functions[pc.pc_func].f_params);
+ /* reset the pc. */
+ fpop ();
+ pc.pc_addr = fpop ();
+ pc.pc_func = fpop ();
+ }
+ else
+ rt_error ("Return from main program.");
+ break;
+
+ case 'S' : /* store array variable */
+ var_name = byte(&pc);
+ if ((var_name & 0x80) != 0)
+ var_name = ((var_name << 8) & 0x7f) + byte(&pc);
+ store_array (var_name);
+ break;
+
+ case 'T' : /* Test tos for zero */
+ c_code = is_zero (ex_stack->s_num);
+ assign (c_code);
+ break;
+
+ case 'W' : /* Write the value on the top of the stack. */
+ case 'P' : /* Write the value on the top of the stack. No newline. */
+ out_num (ex_stack->s_num, o_base, out_char);
+ if (inst == 'W') out_char ('\n');
+ store_var (3); /* Special variable "last". */
+ if (interactive) fflush (stdout);
+ break;
+
+ case 'c' : /* Call special function. */
+ new_func = byte(&pc);
+
+ switch (new_func)
+ {
+ case 'L': /* Length function. */
+ /* For the number 0.xxxx, 0 is not significant. */
+ if (ex_stack->s_num->n_len == 1 &&
+ ex_stack->s_num->n_scale != 0 &&
+ ex_stack->s_num->n_value[0] == 0 )
+ int2num (&ex_stack->s_num, ex_stack->s_num->n_scale);
+ else
+ int2num (&ex_stack->s_num, ex_stack->s_num->n_len
+ + ex_stack->s_num->n_scale);
+ break;
+
+ case 'S': /* Scale function. */
+ int2num (&ex_stack->s_num, ex_stack->s_num->n_scale);
+ break;
+
+ case 'R': /* Square Root function. */
+ if (!bc_sqrt (&ex_stack->s_num, scale))
+ rt_error ("Square root of a negative number");
+ break;
+
+ case 'I': /* Read function. */
+ push_constant (input_char, i_base);
+ break;
+ }
+ break;
+
+ case 'd' : /* Decrement number */
+ var_name = byte(&pc);
+ if ((var_name & 0x80) != 0)
+ var_name = ((var_name << 8) & 0x7f) + byte(&pc);
+ decr_var (var_name);
+ break;
+
+ case 'h' : /* Halt the machine. */
+ exit (0);
+
+ case 'i' : /* increment number */
+ var_name = byte(&pc);
+ if ((var_name & 0x80) != 0)
+ var_name = ((var_name << 8) & 0x7f) + byte(&pc);
+ incr_var (var_name);
+ break;
+
+ case 'l' : /* load variable */
+ var_name = byte(&pc);
+ if ((var_name & 0x80) != 0)
+ var_name = ((var_name << 8) & 0x7f) + byte(&pc);
+ load_var (var_name);
+ break;
+
+ case 'n' : /* Negate top of stack. */
+ bc_sub (_zero_, ex_stack->s_num, &ex_stack->s_num);
+ break;
+
+ case 'p' : /* Pop the execution stack. */
+ pop ();
+ break;
+
+ case 's' : /* store variable */
+ var_name = byte(&pc);
+ if ((var_name & 0x80) != 0)
+ var_name = ((var_name << 8) & 0x7f) + byte(&pc);
+ store_var (var_name);
+ break;
+
+ case 'w' : /* Write a string to the output. */
+ while ((ch = byte(&pc)) != '"') out_char (ch);
+ if (interactive) fflush (stdout);
+ break;
+
+ case 'x' : /* Exchange Top of Stack with the one under the tos. */
+ if (check_stack(2)) {
+ bc_num temp = ex_stack->s_num;
+ ex_stack->s_num = ex_stack->s_next->s_num;
+ ex_stack->s_next->s_num = temp;
+ }
+ break;
+
+ case '0' : /* Load Constant 0. */
+ push_copy (_zero_);
+ break;
+
+ case '1' : /* Load Constant 0. */
+ push_copy (_one_);
+ break;
+
+ case '!' : /* Negate the boolean value on top of the stack. */
+ c_code = is_zero (ex_stack->s_num);
+ assign (c_code);
+ break;
+
+ case '&' : /* compare greater than */
+ if (check_stack(2))
+ {
+ c_code = !is_zero (ex_stack->s_next->s_num)
+ && !is_zero (ex_stack->s_num);
+ pop ();
+ assign (c_code);
+ }
+ break;
+
+ case '|' : /* compare greater than */
+ if (check_stack(2))
+ {
+ c_code = !is_zero (ex_stack->s_next->s_num)
+ || !is_zero (ex_stack->s_num);
+ pop ();
+ assign (c_code);
+ }
+ break;
+
+ case '+' : /* add */
+ if (check_stack(2))
+ {
+ bc_add (ex_stack->s_next->s_num, ex_stack->s_num, &temp_num);
+ pop();
+ pop();
+ push_num (temp_num);
+ init_num (&temp_num);
+ }
+ break;
+
+ case '-' : /* subtract */
+ if (check_stack(2))
+ {
+ bc_sub (ex_stack->s_next->s_num, ex_stack->s_num, &temp_num);
+ pop();
+ pop();
+ push_num (temp_num);
+ init_num (&temp_num);
+ }
+ break;
+
+ case '*' : /* multiply */
+ if (check_stack(2))
+ {
+ bc_multiply (ex_stack->s_next->s_num, ex_stack->s_num,
+ &temp_num, scale);
+ pop();
+ pop();
+ push_num (temp_num);
+ init_num (&temp_num);
+ }
+ break;
+
+ case '/' : /* divide */
+ if (check_stack(2))
+ {
+ if (bc_divide (ex_stack->s_next->s_num,
+ ex_stack->s_num, &temp_num, scale) == 0)
+ {
+ pop();
+ pop();
+ push_num (temp_num);
+ init_num (&temp_num);
+ }
+ else
+ rt_error ("Divide by zero");
+ }
+ break;
+
+ case '%' : /* remainder */
+ if (check_stack(2))
+ {
+ if (is_zero (ex_stack->s_num))
+ rt_error ("Modulo by zero");
+ else
+ {
+ bc_modulo (ex_stack->s_next->s_num,
+ ex_stack->s_num, &temp_num, scale);
+ pop();
+ pop();
+ push_num (temp_num);
+ init_num (&temp_num);
+ }
+ }
+ break;
+
+ case '^' : /* raise */
+ if (check_stack(2))
+ {
+ bc_raise (ex_stack->s_next->s_num,
+ ex_stack->s_num, &temp_num, scale);
+ if (is_zero (ex_stack->s_next->s_num) && is_neg (ex_stack->s_num))
+ rt_error ("divide by zero");
+ pop();
+ pop();
+ push_num (temp_num);
+ init_num (&temp_num);
+ }
+ break;
+
+ case '=' : /* compare equal */
+ if (check_stack(2))
+ {
+ c_code = bc_compare (ex_stack->s_next->s_num,
+ ex_stack->s_num) == 0;
+ pop ();
+ assign (c_code);
+ }
+ break;
+
+ case '#' : /* compare not equal */
+ if (check_stack(2))
+ {
+ c_code = bc_compare (ex_stack->s_next->s_num,
+ ex_stack->s_num) != 0;
+ pop ();
+ assign (c_code);
+ }
+ break;
+
+ case '<' : /* compare less than */
+ if (check_stack(2))
+ {
+ c_code = bc_compare (ex_stack->s_next->s_num,
+ ex_stack->s_num) == -1;
+ pop ();
+ assign (c_code);
+ }
+ break;
+
+ case '{' : /* compare less than or equal */
+ if (check_stack(2))
+ {
+ c_code = bc_compare (ex_stack->s_next->s_num,
+ ex_stack->s_num) <= 0;
+ pop ();
+ assign (c_code);
+ }
+ break;
+
+ case '>' : /* compare greater than */
+ if (check_stack(2))
+ {
+ c_code = bc_compare (ex_stack->s_next->s_num,
+ ex_stack->s_num) == 1;
+ pop ();
+ assign (c_code);
+ }
+ break;
+
+ case '}' : /* compare greater than or equal */
+ if (check_stack(2))
+ {
+ c_code = bc_compare (ex_stack->s_next->s_num,
+ ex_stack->s_num) >= 0;
+ pop ();
+ assign (c_code);
+ }
+ break;
+
+ default : /* error! */
+ rt_error ("bad instruction: inst=%c", inst);
+ }
+ }
+
+ /* Clean up the function stack and pop all autos/parameters. */
+ while (pc.pc_func != 0)
+ {
+ pop_vars(functions[pc.pc_func].f_autos);
+ pop_vars(functions[pc.pc_func].f_params);
+ fpop ();
+ pc.pc_addr = fpop ();
+ pc.pc_func = fpop ();
+ }
+
+ /* Clean up the execution stack. */
+ while (ex_stack != NULL) pop();
+
+ /* Clean up the interrupt stuff. */
+ if (interactive)
+ {
+ signal (SIGINT, use_quit);
+ if (had_sigint)
+ printf ("Interruption completed.\n");
+ }
+}
+
+
+/* Prog_char gets another byte from the program. It is used for
+ conversion of text constants in the code to numbers. */
+
+char
+prog_char ()
+{
+ return byte(&pc);
+}
+
+
+/* Read a character from the standard input. This function is used
+ by the "read" function. */
+
+char
+input_char ()
+{
+ char in_ch;
+
+ /* Get a character from the standard input for the read function. */
+ in_ch = getchar();
+
+ /* Check for a \ quoted newline. */
+ if (in_ch == '\\')
+ {
+ in_ch = getchar();
+ if (in_ch == '\n')
+ in_ch = getchar();
+ }
+
+ /* Classify and preprocess the input character. */
+ if (isdigit(in_ch))
+ return (in_ch - '0');
+ if (in_ch >= 'A' && in_ch <= 'F')
+ return (in_ch + 10 - 'A');
+ if (in_ch >= 'a' && in_ch <= 'f')
+ return (in_ch + 10 - 'a');
+ if (in_ch == '.' || in_ch == '+' || in_ch == '-')
+ return (in_ch);
+ if (in_ch <= ' ')
+ return (' ');
+
+ return (':');
+}
+
+
+/* Push_constant converts a sequence of input characters as returned
+ by IN_CHAR into a number. The number is pushed onto the execution
+ stack. The number is converted as a number in base CONV_BASE. */
+
+void
+push_constant (in_char, conv_base)
+ char (*in_char)(VOID);
+ int conv_base;
+{
+ int digits;
+ bc_num build, temp, result, mult, divisor;
+ char in_ch, first_ch;
+ char negative;
+
+ /* Initialize all bc numbers */
+ init_num (&temp);
+ init_num (&result);
+ init_num (&mult);
+ build = copy_num (_zero_);
+ negative = FALSE;
+
+ /* The conversion base. */
+ int2num (&mult, conv_base);
+
+ /* Get things ready. */
+ in_ch = in_char();
+ while (in_ch == ' ')
+ in_ch = in_char();
+
+ if (in_ch == '+')
+ in_ch = in_char();
+ else
+ if (in_ch == '-')
+ {
+ negative = TRUE;
+ in_ch = in_char();
+ }
+
+ /* Check for the special case of a single digit. */
+ if (in_ch < 16)
+ {
+ first_ch = in_ch;
+ in_ch = in_char();
+ if (in_ch < 16 && first_ch >= conv_base)
+ first_ch = conv_base - 1;
+ int2num (&build, (int) first_ch);
+ }
+
+ /* Convert the integer part. */
+ while (in_ch < 16)
+ {
+ if (in_ch < 16 && in_ch >= conv_base) in_ch = conv_base-1;
+ bc_multiply (build, mult, &result, 0);
+ int2num (&temp, (int) in_ch);
+ bc_add (result, temp, &build);
+ in_ch = in_char();
+ }
+ if (in_ch == '.')
+ {
+ in_ch = in_char();
+ if (in_ch >= conv_base) in_ch = conv_base-1;
+ free_num (&result);
+ free_num (&temp);
+ divisor = copy_num (_one_);
+ result = copy_num (_zero_);
+ digits = 0;
+ while (in_ch < 16)
+ {
+ bc_multiply (result, mult, &result, 0);
+ int2num (&temp, (int) in_ch);
+ bc_add (result, temp, &result);
+ bc_multiply (divisor, mult, &divisor, 0);
+ digits++;
+ in_ch = in_char();
+ if (in_ch < 16 && in_ch >= conv_base) in_ch = conv_base-1;
+ }
+ bc_divide (result, divisor, &result, digits);
+ bc_add (build, result, &build);
+ }
+
+ /* Final work. */
+ if (negative)
+ bc_sub (_zero_, build, &build);
+
+ push_num (build);
+ free_num (&temp);
+ free_num (&result);
+ free_num (&mult);
+}
+
+
+/* When converting base 10 constants from the program, we use this
+ more efficient way to convert them to numbers. PC tells where
+ the constant starts and is expected to be advanced to after
+ the constant. */
+
+void
+push_b10_const (pc)
+ program_counter *pc;
+{
+ bc_num build;
+ program_counter look_pc;
+ int kdigits, kscale;
+ char inchar;
+ char *ptr;
+
+ /* Count the digits and get things ready. */
+ look_pc = *pc;
+ kdigits = 0;
+ kscale = 0;
+ inchar = byte (&look_pc);
+ while (inchar != '.' && inchar != ':')
+ {
+ kdigits++;
+ inchar = byte(&look_pc);
+ }
+ if (inchar == '.' )
+ {
+ inchar = byte(&look_pc);
+ while (inchar != ':')
+ {
+ kscale++;
+ inchar = byte(&look_pc);
+ }
+ }
+
+ /* Get the first character again and move the pc. */
+ inchar = byte(pc);
+
+ /* Secial cases of 0, 1, and A-F single inputs. */
+ if (kdigits == 1 && kscale == 0)
+ {
+ if (inchar == 0)
+ {
+ push_copy (_zero_);
+ inchar = byte(pc);
+ return;
+ }
+ if (inchar == 1) {
+ push_copy (_one_);
+ inchar = byte(pc);
+ return;
+ }
+ if (inchar > 9)
+ {
+ init_num (&build);
+ int2num (&build, inchar);
+ push_num (build);
+ inchar = byte(pc);
+ return;
+ }
+ }
+
+ /* Build the new number. */
+ if (kdigits == 0)
+ {
+ build = new_num (1,kscale);
+ ptr = build->n_value;
+ *ptr++ = 0;
+ }
+ else
+ {
+ build = new_num (kdigits,kscale);
+ ptr = build->n_value;
+ }
+
+ while (inchar != ':')
+ {
+ if (inchar != '.')
+ if (inchar > 9)
+ *ptr++ = 9;
+ else
+ *ptr++ = inchar;
+ inchar = byte(pc);
+ }
+ push_num (build);
+}
+
+
+/* Put the correct value on the stack for C_CODE. Frees TOS num. */
+
+void
+assign (c_code)
+ char c_code;
+{
+ free_num (&ex_stack->s_num);
+ if (c_code)
+ ex_stack->s_num = copy_num (_one_);
+ else
+ ex_stack->s_num = copy_num (_zero_);
+}
diff --git a/gnu/usr.bin/bc/global.c b/gnu/usr.bin/bc/global.c
new file mode 100644
index 0000000..b00a989
--- /dev/null
+++ b/gnu/usr.bin/bc/global.c
@@ -0,0 +1,42 @@
+/* global.c: This defines the global variables. */
+
+/* This file is part of bc written for MINIX.
+ Copyright (C) 1991, 1992 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License , or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; see the file COPYING. If not, write to
+ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ You may contact the author by:
+ e-mail: phil@cs.wwu.edu
+ us-mail: Philip A. Nelson
+ Computer Science Department, 9062
+ Western Washington University
+ Bellingham, WA 98226-9062
+
+*************************************************************************/
+
+#include "bcdefs.h"
+
+/* Since we want to define them here, we use the following define. */
+#undef EXTERN
+#define EXTERN
+
+/* Define all the global variables for bc. */
+#include "global.h"
+
+#ifndef BC_MATH_FILE
+CONST char libmath[] =
+#include "math.h"
+;
+#endif
diff --git a/gnu/usr.bin/bc/global.h b/gnu/usr.bin/bc/global.h
new file mode 100644
index 0000000..550afb1
--- /dev/null
+++ b/gnu/usr.bin/bc/global.h
@@ -0,0 +1,108 @@
+/* global.h: The global variables for bc. */
+
+/* This file is part of bc written for MINIX.
+ Copyright (C) 1991, 1992 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License , or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; see the file COPYING. If not, write to
+ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ You may contact the author by:
+ e-mail: phil@cs.wwu.edu
+ us-mail: Philip A. Nelson
+ Computer Science Department, 9062
+ Western Washington University
+ Bellingham, WA 98226-9062
+
+*************************************************************************/
+
+
+/* For the current "break level" and if statements. */
+EXTERN int break_label;
+EXTERN int if_label;
+EXTERN int continue_label;
+
+/* Label numbers. */
+EXTERN int next_label;
+
+/* Used for "code" generation. */
+EXTERN char genstr[80];
+EXTERN int out_count;
+EXTERN char did_gen;
+
+/* Interactive and other flags. */
+EXTERN char interactive;
+EXTERN char compile_only;
+EXTERN char use_math;
+EXTERN char warn_not_std;
+EXTERN char std_only;
+
+/* global variables for the bc machine. All will be dynamic in size.*/
+/* Function storage. main is (0) and functions (1-f_count) */
+
+EXTERN bc_function *functions;
+EXTERN char **f_names;
+EXTERN int f_count;
+
+/* Variable stoarge and reverse names. */
+
+EXTERN bc_var **variables;
+EXTERN char **v_names;
+EXTERN int v_count;
+
+/* Array Variable storage and reverse names. */
+
+EXTERN bc_var_array **arrays;
+EXTERN char **a_names;
+EXTERN int a_count;
+
+/* Execution stack. */
+EXTERN estack_rec *ex_stack;
+
+/* Function return stack. */
+EXTERN fstack_rec *fn_stack;
+
+/* Other "storage". */
+EXTERN int i_base;
+EXTERN int o_base;
+EXTERN int scale;
+EXTERN char c_code;
+EXTERN int out_col;
+EXTERN char runtime_error;
+EXTERN program_counter pc;
+
+/* Input Line numbers and other error information. */
+EXTERN int line_no;
+EXTERN int had_error;
+
+/* For larger identifiers, a tree, and how many "storage" locations
+ have been allocated. */
+
+EXTERN int next_array;
+EXTERN int next_func;
+EXTERN int next_var;
+
+EXTERN id_rec *name_tree;
+
+/* For error message production */
+EXTERN char **g_argv;
+EXTERN int g_argc;
+EXTERN char is_std_in;
+
+/* defined in number.c */
+extern bc_num _zero_;
+extern bc_num _one_;
+
+/* For use with getopt. Do not declare them here.*/
+extern int optind;
+
diff --git a/gnu/usr.bin/bc/libmath.b b/gnu/usr.bin/bc/libmath.b
new file mode 100644
index 0000000..30d9532
--- /dev/null
+++ b/gnu/usr.bin/bc/libmath.b
@@ -0,0 +1,255 @@
+/* libmath.b for bc for minix. */
+
+/* This file is part of bc written for MINIX.
+ Copyright (C) 1991, 1992 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License , or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; see the file COPYING. If not, write to
+ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ You may contact the author by:
+ e-mail: phil@cs.wwu.edu
+ us-mail: Philip A. Nelson
+ Computer Science Department, 9062
+ Western Washington University
+ Bellingham, WA 98226-9062
+
+*************************************************************************/
+
+
+scale = 20
+
+/* Uses the fact that e^x = (e^(x/2))^2
+ When x is small enough, we use the series:
+ e^x = 1 + x + x^2/2! + x^3/3! + ...
+*/
+
+define e(x) {
+ auto a, d, e, f, i, m, v, z
+
+ /* Check the sign of x. */
+ if (x<0) {
+ m = 1
+ x = -x
+ }
+
+ /* Precondition x. */
+ z = scale;
+ scale = 4 + z + .44*x;
+ while (x > 1) {
+ f += 1;
+ x /= 2;
+ }
+
+ /* Initialize the variables. */
+ v = 1+x
+ a = x
+ d = 1
+
+ for (i=2; 1; i++) {
+ e = (a *= x) / (d *= i)
+ if (e == 0) {
+ if (f>0) while (f--) v = v*v;
+ scale = z
+ if (m) return (1/v);
+ return (v/1);
+ }
+ v += e
+ }
+}
+
+/* Natural log. Uses the fact that ln(x^2) = 2*ln(x)
+ The series used is:
+ ln(x) = 2(a+a^3/3+a^5/5+...) where a=(x-1)/(x+1)
+*/
+
+define l(x) {
+ auto e, f, i, m, n, v, z
+
+ /* return something for the special case. */
+ if (x <= 0) return (1 - 10^scale)
+
+ /* Precondition x to make .5 < x < 2.0. */
+ z = scale;
+ scale += 4;
+ f = 2;
+ i=0
+ while (x >= 2) { /* for large numbers */
+ f *= 2;
+ x = sqrt(x);
+ }
+ while (x <= .5) { /* for small numbers */
+ f *= 2;
+ x = sqrt(x);
+ }
+
+ /* Set up the loop. */
+ v = n = (x-1)/(x+1)
+ m = n*n
+
+ /* Sum the series. */
+ for (i=3; 1; i+=2) {
+ e = (n *= m) / i
+ if (e == 0) {
+ v = f*v
+ scale = z
+ return (v/1)
+ }
+ v += e
+ }
+}
+
+/* Sin(x) uses the standard series:
+ sin(x) = x - x^3/3! + x^5/5! - x^7/7! ... */
+
+define s(x) {
+ auto e, i, m, n, s, v, z
+
+ /* precondition x. */
+ z = scale
+ scale = 1.1*z + 1;
+ v = a(1)
+ if (x < 0) {
+ m = 1;
+ x = -x;
+ }
+ scale = 0
+ n = (x / v + 2 )/4
+ x = x - 4*n*v
+ if (n%2) x = -x
+
+ /* Do the loop. */
+ scale = z + 2;
+ v = e = x
+ s = -x*x
+ for (i=3; 1; i+=2) {
+ e *= s/(i*(i-1))
+ if (e == 0) {
+ scale = z
+ if (m) return (-v/1);
+ return (v/1);
+ }
+ v += e
+ }
+}
+
+/* Cosine : cos(x) = sin(x+pi/2) */
+define c(x) {
+ auto v;
+ scale += 1;
+ v = s(x+a(1)*2);
+ scale -= 1;
+ return (v/1);
+}
+
+/* Arctan: Using the formula:
+ atan(x) = atan(c) + atan((x-c)/(1+xc)) for a small c (.2 here)
+ For under .2, use the series:
+ atan(x) = x - x^3/3 + x^5/5 - x^7/7 + ... */
+
+define a(x) {
+ auto a, e, f, i, m, n, s, v, z
+
+ /* Special case and for fast answers */
+ if (x==1) {
+ if (scale <= 25) return (.7853981633974483096156608/1)
+ if (scale <= 40) return (.7853981633974483096156608458198757210492/1)
+ if (scale <= 60) \
+ return (.785398163397448309615660845819875721049292349843776455243736/1)
+ }
+ if (x==.2) {
+ if (scale <= 25) return (.1973955598498807583700497/1)
+ if (scale <= 40) return (.1973955598498807583700497651947902934475/1)
+ if (scale <= 60) \
+ return (.197395559849880758370049765194790293447585103787852101517688/1)
+ }
+
+ /* Negative x? */
+ if (x<0) {
+ m = 1;
+ x = -x;
+ }
+
+ /* Save the scale. */
+ z = scale;
+
+ /* Note: a and f are known to be zero due to being auto vars. */
+ /* Calculate atan of a known number. */
+ if (x > .2) {
+ scale = z+4;
+ a = a(.2);
+ }
+
+ /* Precondition x. */
+ scale = z+2;
+ while (x > .2) {
+ f += 1;
+ x = (x-.2) / (1+x*.2);
+ }
+
+ /* Initialize the series. */
+ v = n = x;
+ s = -x*x;
+
+ /* Calculate the series. */
+ for (i=3; 1; i+=2) {
+ e = (n *= s) / i;
+ if (e == 0) {
+ scale = z;
+ if (m) return ((f*a+v)/-1);
+ return ((f*a+v)/1);
+ }
+ v += e
+ }
+}
+
+
+/* Bessel function of integer order. Uses the following:
+ j(-n,x) = (-1)^n*j(n,x)
+ j(n,x) = x^n/(2^n*n!) * (1 - x^2/(2^2*1!*(n+1)) + x^4/(2^4*2!*(n+1)*(n+2))
+ - x^6/(2^6*3!*(n+1)*(n+2)*(n+3)) .... )
+*/
+define j(n,x) {
+ auto a, d, e, f, i, m, s, v, z
+
+ /* Make n an integer and check for negative n. */
+ z = scale;
+ scale = 0;
+ n = n/1;
+ if (n<0) {
+ n = -n;
+ if (n%2 == 1) m = 1;
+ }
+
+ /* Compute the factor of x^n/(2^n*n!) */
+ f = 1;
+ for (i=2; i<=n; i++) f = f*i;
+ scale = 1.5*z;
+ f = x^n / 2^n / f;
+
+ /* Initialize the loop .*/
+ v = e = 1;
+ s = -x*x/4
+ scale = 1.5*z
+
+ /* The Loop.... */
+ for (i=1; 1; i++) {
+ e = e * s / i / (n+i);
+ if (e == 0) {
+ scale = z
+ if (m) return (-f*v/1);
+ return (f*v/1);
+ }
+ v += e;
+ }
+}
diff --git a/gnu/usr.bin/bc/load.c b/gnu/usr.bin/bc/load.c
new file mode 100644
index 0000000..144ae0e
--- /dev/null
+++ b/gnu/usr.bin/bc/load.c
@@ -0,0 +1,333 @@
+/* load.c: This code "loads" code into the code segments. */
+
+/* This file is part of bc written for MINIX.
+ Copyright (C) 1991, 1992 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License , or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; see the file COPYING. If not, write to
+ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ You may contact the author by:
+ e-mail: phil@cs.wwu.edu
+ us-mail: Philip A. Nelson
+ Computer Science Department, 9062
+ Western Washington University
+ Bellingham, WA 98226-9062
+
+*************************************************************************/
+
+#include "bcdefs.h"
+#include "global.h"
+#include "proto.h"
+
+/* Load variables. */
+
+program_counter load_adr;
+char load_str;
+char load_const;
+
+/* Initialize the load sequence. */
+void
+init_load ()
+{
+ clear_func(0);
+ load_adr.pc_func = 0;
+ load_adr.pc_addr = 0;
+ load_str = FALSE;
+ load_const = FALSE;
+}
+
+/* addbyte adds one BYTE to the current code segment. */
+void
+addbyte (byte)
+ char byte;
+{
+ int seg, offset, func;
+
+ /* If there was an error, don't continue. */
+ if (had_error) return;
+
+ /* Calculate the segment and offset. */
+ seg = load_adr.pc_addr >> BC_SEG_LOG;
+ offset = load_adr.pc_addr++ % BC_SEG_SIZE;
+ func = load_adr.pc_func;
+
+ if (seg >= BC_MAX_SEGS)
+ {
+ yyerror ("Function too big.");
+ return;
+ }
+
+ if (functions[func].f_body[seg] == NULL)
+ functions[func].f_body[seg] = (char *) bc_malloc (BC_SEG_SIZE);
+
+ /* Store the byte. */
+ functions[func].f_body[seg][offset] = byte;
+ functions[func].f_code_size++;
+}
+
+
+/* Define a label LAB to be the current program counter. */
+
+void
+def_label (lab)
+ long lab;
+{
+ bc_label_group *temp;
+ int group, offset, func;
+
+ /* Get things ready. */
+ group = lab >> BC_LABEL_LOG;
+ offset = lab % BC_LABEL_GROUP;
+ func = load_adr.pc_func;
+
+ /* Make sure there is at least one label group. */
+ if (functions[func].f_label == NULL)
+ {
+ functions[func].f_label =
+ (bc_label_group *) bc_malloc (sizeof(bc_label_group));
+ functions[func].f_label->l_next = NULL;
+ }
+
+ /* Add the label group. */
+ temp = functions[func].f_label;
+ while (group > 0)
+ {
+ if (temp->l_next == NULL)
+ {
+ temp->l_next = (bc_label_group *) bc_malloc (sizeof(bc_label_group));
+ temp->l_next->l_next = NULL;
+ }
+ temp = temp->l_next;
+ group --;
+ }
+
+ /* Define it! */
+ temp->l_adrs [offset] = load_adr.pc_addr;
+}
+
+/* Several instructions have integers in the code. They
+ are all known to be legal longs. So, no error code
+ is added. STR is the pointer to the load string and
+ must be moved to the last non-digit character. */
+
+long
+long_val (str)
+ char **str;
+{ int val = 0;
+ char neg = FALSE;
+
+ if (**str == '-')
+ {
+ neg = TRUE;
+ (*str)++;
+ }
+ while (isdigit(**str))
+ val = val*10 + *(*str)++ - '0';
+
+ if (neg)
+ return -val;
+ else
+ return val;
+}
+
+
+/* load_code loads the CODE into the machine. */
+
+void
+load_code (code)
+ char *code;
+{
+ char *str;
+ long ap_name; /* auto or parameter name. */
+ long label_no;
+ long vaf_name; /* variable, array or function number. */
+ long func;
+ program_counter save_adr;
+
+ /* Initialize. */
+ str = code;
+
+ /* Scan the code. */
+ while (*str != 0)
+ {
+ /* If there was an error, don't continue. */
+ if (had_error) return;
+
+ if (load_str)
+ {
+ if (*str == '"') load_str = FALSE;
+ addbyte (*str++);
+ }
+ else
+ if (load_const)
+ {
+ if (*str == '\n')
+ str++;
+ else
+ {
+ if (*str == ':')
+ {
+ load_const = FALSE;
+ addbyte (*str++);
+ }
+ else
+ if (*str == '.')
+ addbyte (*str++);
+ else
+ if (*str >= 'A')
+ addbyte (*str++ + 10 - 'A');
+ else
+ addbyte (*str++ - '0');
+ }
+ }
+ else
+ {
+ switch (*str)
+ {
+
+ case '"': /* Starts a string. */
+ load_str = TRUE;
+ break;
+
+ case 'N': /* A label */
+ str++;
+ label_no = long_val (&str);
+ def_label (label_no);
+ break;
+
+ case 'B': /* Branch to label. */
+ case 'J': /* Jump to label. */
+ case 'Z': /* Branch Zero to label. */
+ addbyte(*str++);
+ label_no = long_val (&str);
+ if (label_no > 65535L)
+ { /* Better message? */
+ fprintf (stderr,"Program too big.\n");
+ exit(1);
+ }
+ addbyte ( (char) label_no & 0xFF);
+ addbyte ( (char) label_no >> 8);
+ break;
+
+ case 'F': /* A function, get the name and initialize it. */
+ str++;
+ func = long_val (&str);
+ clear_func (func);
+#if DEBUG > 2
+ printf ("Loading function number %d\n", func);
+#endif
+ /* get the parameters */
+ while (*str++ != '.')
+ {
+ if (*str == '.')
+ {
+ str++;
+ break;
+ }
+ ap_name = long_val (&str);
+#if DEBUG > 2
+ printf ("parameter number %d\n", ap_name);
+#endif
+ functions[(int)func].f_params =
+ nextarg (functions[(int)func].f_params, ap_name);
+ }
+
+ /* get the auto vars */
+ while (*str != '[')
+ {
+ if (*str == ',') str++;
+ ap_name = long_val (&str);
+#if DEBUG > 2
+ printf ("auto number %d\n", ap_name);
+#endif
+ functions[(int)func].f_autos =
+ nextarg (functions[(int)func].f_autos, ap_name);
+ }
+ save_adr = load_adr;
+ load_adr.pc_func = func;
+ load_adr.pc_addr = 0;
+ break;
+
+ case ']': /* A function end */
+ functions[load_adr.pc_func].f_defined = TRUE;
+ load_adr = save_adr;
+ break;
+
+ case 'C': /* Call a function. */
+ addbyte (*str++);
+ func = long_val (&str);
+ if (func < 128)
+ addbyte ( (char) func);
+ else
+ {
+ addbyte ((func >> 8) & 0xff | 0x80);
+ addbyte (func & 0xff);
+ }
+ if (*str == ',') str++;
+ while (*str != ':')
+ addbyte (*str++);
+ addbyte (':');
+ break;
+
+ case 'c': /* Call a special function. */
+ addbyte (*str++);
+ addbyte (*str);
+ break;
+
+ case 'K': /* A constant.... may have an "F" in it. */
+ addbyte (*str);
+ load_const = TRUE;
+ break;
+
+ case 'd': /* Decrement. */
+ case 'i': /* Increment. */
+ case 'l': /* Load. */
+ case 's': /* Store. */
+ case 'A': /* Array Increment */
+ case 'M': /* Array Decrement */
+ case 'L': /* Array Load */
+ case 'S': /* Array Store */
+ addbyte (*str++);
+ vaf_name = long_val (&str);
+ if (vaf_name < 128)
+ addbyte (vaf_name);
+ else
+ {
+ addbyte ((vaf_name >> 8) & 0xff | 0x80);
+ addbyte (vaf_name & 0xff);
+ }
+ break;
+
+ case '@': /* A command! */
+ switch (*(++str))
+ {
+ case 'i':
+ init_load ();
+ break;
+ case 'r':
+ execute ();
+ break;
+ }
+ break;
+
+ case '\n': /* Ignore the newlines */
+ break;
+
+ default: /* Anything else */
+ addbyte (*str);
+ }
+ str++;
+ }
+ }
+}
diff --git a/gnu/usr.bin/bc/main.c b/gnu/usr.bin/bc/main.c
new file mode 100644
index 0000000..ed8643a
--- /dev/null
+++ b/gnu/usr.bin/bc/main.c
@@ -0,0 +1,204 @@
+/* main.c: The main program for bc. */
+
+/* This file is part of bc written for MINIX.
+ Copyright (C) 1991, 1992 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License , or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; see the file COPYING. If not, write to
+ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ You may contact the author by:
+ e-mail: phil@cs.wwu.edu
+ us-mail: Philip A. Nelson
+ Computer Science Department, 9062
+ Western Washington University
+ Bellingham, WA 98226-9062
+
+*************************************************************************/
+
+#include "bcdefs.h"
+#include <signal.h>
+#include "global.h"
+#include "proto.h"
+
+/* Variables for processing multiple files. */
+char first_file;
+extern FILE *yyin;
+
+
+/* The main program for bc. */
+int
+main (argc, argv)
+ int argc;
+ char *argv[];
+{
+ int ch;
+
+ /* Initialize many variables. */
+ compile_only = FALSE;
+ use_math = FALSE;
+ warn_not_std = FALSE;
+ std_only = FALSE;
+ if (isatty(0) && isatty(1))
+ interactive = TRUE;
+ else
+ interactive = FALSE;
+
+ /* Parse the command line */
+ ch = getopt (argc, argv, "lcisvw");
+ while (ch != EOF)
+ {
+ switch (ch)
+ {
+ case 'c': /* compile only */
+ compile_only = TRUE;
+ break;
+ case 'l': /* math lib */
+ use_math = TRUE;
+ break;
+ case 'i': /* force interactive */
+ interactive = TRUE;
+ break;
+ case 'w': /* Non standard features give warnings. */
+ warn_not_std = TRUE;
+ break;
+ case 's': /* Non standard features give errors. */
+ std_only = TRUE;
+ break;
+ case 'v': /* Print the version. */
+ printf ("%s\n", BC_VERSION);
+ break;
+ }
+ ch = getopt (argc, argv, "lcisvw");
+ }
+
+ /* Initialize the machine. */
+ init_storage();
+ init_load();
+
+ /* Set up interrupts to print a message. */
+ if (interactive)
+ signal (SIGINT, use_quit);
+
+ /* Initialize the front end. */
+ init_tree();
+ init_gen ();
+ g_argv = argv;
+ g_argc = argc;
+ is_std_in = FALSE;
+ first_file = TRUE;
+ if (!open_new_file ())
+ exit (1);
+
+ /* Do the parse. */
+ yyparse ();
+
+ /* End the compile only output with a newline. */
+ if (compile_only)
+ printf ("\n");
+
+ exit (0);
+}
+
+
+/* This is the function that opens all the files.
+ It returns TRUE if the file was opened, otherwise
+ it returns FALSE. */
+
+int
+open_new_file ()
+{
+ FILE *new_file;
+
+ /* Set the line number. */
+ line_no = 1;
+
+ /* Check to see if we are done. */
+ if (is_std_in) return (FALSE);
+
+ /* Open the other files. */
+ if (use_math && first_file)
+ {
+#ifdef BC_MATH_FILE
+ /* Make the first file be the math library. */
+ new_file = fopen (BC_MATH_FILE, "r");
+ use_math = FALSE;
+ if (new_file != NULL)
+ {
+ new_yy_file (new_file);
+ return TRUE;
+ }
+ else
+ {
+ fprintf (stderr, "Math Library unavailable.\n");
+ exit (1);
+ }
+#else
+ /* Load the code from a precompiled version of the math libarary. */
+ extern char libmath[];
+ char tmp;
+ /* These MUST be in the order of first mention of each function.
+ That is why "a" comes before "c" even though "a" is defined after
+ after "c". "a" is used in "s"! */
+ tmp = lookup ("e", FUNCT);
+ tmp = lookup ("l", FUNCT);
+ tmp = lookup ("s", FUNCT);
+ tmp = lookup ("a", FUNCT);
+ tmp = lookup ("c", FUNCT);
+ tmp = lookup ("j", FUNCT);
+ load_code (libmath);
+#endif
+ }
+
+ /* One of the argv values. */
+ while (optind < g_argc)
+ {
+ new_file = fopen (g_argv[optind], "r");
+ if (new_file != NULL)
+ {
+ new_yy_file (new_file);
+ optind++;
+ return TRUE;
+ }
+ fprintf (stderr, "File %s is unavailable.\n", g_argv[optind++]);
+ exit (1);
+ }
+
+ /* If we fall through to here, we should return stdin. */
+ new_yy_file (stdin);
+ is_std_in = TRUE;
+ return TRUE;
+}
+
+
+/* Set yyin to the new file. */
+
+void
+new_yy_file (file)
+ FILE *file;
+{
+ if (!first_file) fclose (yyin);
+ yyin = file;
+ first_file = FALSE;
+}
+
+
+/* Message to use quit. */
+
+void
+use_quit (sig)
+ int sig;
+{
+ printf ("\n(interrupt) use quit to exit.\n");
+ signal (SIGINT, use_quit);
+}
diff --git a/gnu/usr.bin/bc/math.h b/gnu/usr.bin/bc/math.h
new file mode 100644
index 0000000..a1fc146
--- /dev/null
+++ b/gnu/usr.bin/bc/math.h
@@ -0,0 +1,40 @@
+"@iK20:s2:p@r\
+@iF1,4.5,6,7,8,9,10,11,12[l4:0<Z0:1s10:pl4:ns4:pN0:l2:s12:pK4\
+:l12:+K.44:l4:*+s2:pN1:l4:1>Z2:l8:1+s8:pl4:K2:/s4:pJ1:N2:1l4:\
++s11:pl4:s5:p1s6:pK2:s9:pN4:1B5:J3:N6:l9:i9:pJ4:N5:l5:l4:*s5:\
+l6:l9:*s6:/s7:pl7:0=Z7:l8:0>Z8:N9:l8:d8:Z10:l11:l11:*s11:pJ9:N10:\
+N8:l12:s2:pl10:Z11:1l11:/RN11:l11:1/RN7:l11:l7:+s11:pJ6:N3:0R]\
+@r\
+@iF2,4.7,8,9,10,13,11,12[l4:0{Z0:1K10:l2:^-RN0:l2:s12:pl2:K4:\
++s2:pK2:s8:p0s9:pN1:l4:K2:}Z2:l8:K2:*s8:pl4:cRs4:pJ1:N2:N3:l4:\
+K.5:{Z4:l8:K2:*s8:pl4:cRs4:pJ3:N4:l4:1-l4:1+/s13:s11:pl13:l13:\
+*s10:pK3:s9:pN6:1B7:J5:N8:l9:K2:+s9:pJ6:N7:l13:l10:*s13:l9:/s7:\
+pl7:0=Z9:l8:l11:*s11:pl12:s2:pl11:1/RN9:l11:l7:+s11:pJ8:N5:0R]\
+@r\
+@iF3,4.7,9,10,13,14,11,12[l2:s12:pK1.1:l12:*1+s2:p1C4,0:s11:p\
+l4:0<Z0:1s10:pl4:ns4:pN0:0s2:pl4:l11:/K2:+K4:/s13:pl4:K4:l13:\
+*l11:*-s4:pl13:K2:%Z1:l4:ns4:pN1:l12:K2:+s2:pl4:s7:s11:pl4:nl4:\
+*s14:pK3:s9:pN3:1B4:J2:N5:l9:K2:+s9:pJ3:N4:l7:l14:l9:l9:1-*/*\
+s7:pl7:0=Z6:l12:s2:pl10:Z7:l11:n1/RN7:l11:1/RN6:l11:l7:+s11:p\
+J5:N2:0R]@r\
+@iF5,4.11[l2:1+s2:pl4:1C4,0:K2:*+C3,0:s11:pl2:1-s2:pl11:1/R0R]\
+@r\
+@iF4,4.5,7,8,9,10,13,14,11,12[l4:1=Z0:l2:K25:{Z1:K.7853981633974483096156608\
+:1/RN1:l2:K40:{Z2:K.7853981633974483096156608458198757210492:\
+1/RN2:l2:K60:{Z3:K.785398163397448309615660845819875721049292349843776455243736\
+:1/RN3:N0:l4:K.2:=Z4:l2:K25:{Z5:K.1973955598498807583700497:1\
+/RN5:l2:K40:{Z6:K.1973955598498807583700497651947902934475:1/\
+RN6:l2:K60:{Z7:K.197395559849880758370049765194790293447585103787852101517688\
+:1/RN7:N4:l4:0<Z8:1s10:pl4:ns4:pN8:l2:s12:pl4:K.2:>Z9:l12:K4:\
++s2:pK.2:C4,0:s5:pN9:l12:K2:+s2:pN10:l4:K.2:>Z11:l8:1+s8:pl4:\
+K.2:-1l4:K.2:*+/s4:pJ10:N11:l4:s13:s11:pl4:nl4:*s14:pK3:s9:pN13:\
+1B14:J12:N15:l9:K2:+s9:pJ13:N14:l13:l14:*s13:l9:/s7:pl7:0=Z16:\
+l12:s2:pl10:Z17:l8:l5:*l11:+1n/RN17:l8:l5:*l11:+1/RN16:l11:l7:\
++s11:pJ15:N12:0R]@r\
+@iF6,13,4.5,6,7,8,9,10,14,11,12[l2:s12:p0s2:pl13:1/s13:pl13:0\
+<Z0:l13:ns13:pl13:K2:%1=Z1:1s10:pN1:N0:1s8:pK2:s9:pN3:l9:l13:\
+{B4:J2:N5:l9:i9:pJ3:N4:l8:l9:*s8:pJ5:N2:K1.5:l12:*s2:pl4:l13:\
+^K2:l13:^/l8:/s8:p1s7:s11:pl4:nl4:*K4:/s14:pK1.5:l12:*s2:p1s9:\
+pN7:1B8:J6:N9:l9:i9:pJ7:N8:l7:l14:*l9:/l13:l9:+/s7:pl7:0=Z10:\
+l12:s2:pl10:Z11:l8:nl11:*1/RN11:l8:l11:*1/RN10:l11:l7:+s11:pJ9:N6:\
+0R]@r"
diff --git a/gnu/usr.bin/bc/number.c b/gnu/usr.bin/bc/number.c
new file mode 100644
index 0000000..336ad11
--- /dev/null
+++ b/gnu/usr.bin/bc/number.c
@@ -0,0 +1,1405 @@
+/* number.c: Implements arbitrary precision numbers. */
+
+/* This file is part of bc written for MINIX.
+ Copyright (C) 1991, 1992 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License , or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; see the file COPYING. If not, write to
+ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ You may contact the author by:
+ e-mail: phil@cs.wwu.edu
+ us-mail: Philip A. Nelson
+ Computer Science Department, 9062
+ Western Washington University
+ Bellingham, WA 98226-9062
+
+*************************************************************************/
+
+#include "bcdefs.h"
+#include "proto.h"
+
+/* Storage used for special numbers. */
+bc_num _zero_;
+bc_num _one_;
+bc_num _two_;
+
+
+/* "Frees" a bc_num NUM. Actually decreases reference count and only
+ frees the storage if reference count is zero. */
+
+void
+free_num (num)
+ bc_num *num;
+{
+ if (*num == NULL) return;
+ (*num)->n_refs--;
+ if ((*num)->n_refs == 0) free(*num);
+ *num = NULL;
+}
+
+
+/* new_num allocates a number and sets fields to known values. */
+
+bc_num
+new_num (length, scale)
+ int length, scale;
+{
+ bc_num temp;
+
+ temp = (bc_num) malloc (sizeof(bc_struct)+length+scale);
+ if (temp == NULL) out_of_memory ();
+ temp->n_sign = PLUS;
+ temp->n_len = length;
+ temp->n_scale = scale;
+ temp->n_refs = 1;
+ temp->n_value[0] = 0;
+ return temp;
+}
+
+
+/* Intitialize the number package! */
+
+void
+init_numbers ()
+{
+ _zero_ = new_num (1,0);
+ _one_ = new_num (1,0);
+ _one_->n_value[0] = 1;
+ _two_ = new_num (1,0);
+ _two_->n_value[0] = 2;
+}
+
+
+/* Make a copy of a number! Just increments the reference count! */
+
+bc_num
+copy_num (num)
+ bc_num num;
+{
+ num->n_refs++;
+ return num;
+}
+
+
+/* Initialize a number NUM by making it a copy of zero. */
+
+void
+init_num (num)
+ bc_num *num;
+{
+ *num = copy_num (_zero_);
+}
+
+
+/* Convert an integer VAL to a bc number NUM. */
+
+void
+int2num (num, val)
+ bc_num *num;
+ int val;
+{
+ char buffer[30];
+ char *bptr, *vptr;
+ int ix = 1;
+ char neg = 0;
+
+ /* Sign. */
+ if (val < 0)
+ {
+ neg = 1;
+ val = -val;
+ }
+
+ /* Get things going. */
+ bptr = buffer;
+ *bptr++ = val % 10;
+ val = val / 10;
+
+ /* Extract remaining digits. */
+ while (val != 0)
+ {
+ *bptr++ = val % 10;
+ val = val / 10;
+ ix++; /* Count the digits. */
+ }
+
+ /* Make the number. */
+ free_num (num);
+ *num = new_num (ix, 0);
+ if (neg) (*num)->n_sign = MINUS;
+
+ /* Assign the digits. */
+ vptr = (*num)->n_value;
+ while (ix-- > 0)
+ *vptr++ = *--bptr;
+}
+
+
+/* Convert a number NUM to a long. The function returns only the integer
+ part of the number. For numbers that are too large to represent as
+ a long, this function returns a zero. This can be detected by checking
+ the NUM for zero after having a zero returned. */
+
+long
+num2long (num)
+ bc_num num;
+{
+ long val;
+ char *nptr;
+ int index;
+
+ /* Extract the int value, ignore the fraction. */
+ val = 0;
+ nptr = num->n_value;
+ for (index=num->n_len; (index>0) && (val<=(LONG_MAX/10)); index--)
+ val = val*10 + *nptr++;
+
+ /* Check for overflow. If overflow, return zero. */
+ if (index>0) val = 0;
+ if (val < 0) val = 0;
+
+ /* Return the value. */
+ if (num->n_sign == PLUS)
+ return (val);
+ else
+ return (-val);
+}
+
+
+/* The following are some math routines for numbers. */
+_PROTOTYPE(static int _do_compare, (bc_num n1, bc_num n2, int use_sign,
+ int ignore_last));
+_PROTOTYPE(static void _rm_leading_zeros, (bc_num num));
+_PROTOTYPE(static bc_num _do_add, (bc_num n1, bc_num n2));
+_PROTOTYPE(static bc_num _do_sub, (bc_num n1, bc_num n2));
+_PROTOTYPE(static void _one_mult, (unsigned char *num, int size, int digit,
+ unsigned char *result));
+
+
+
+/* Compare two bc numbers. Return value is 0 if equal, -1 if N1 is less
+ than N2 and +1 if N1 is greater than N2. If USE_SIGN is false, just
+ compare the magnitudes. */
+
+static int
+_do_compare (n1, n2, use_sign, ignore_last)
+ bc_num n1, n2;
+ int use_sign;
+ int ignore_last;
+{
+ char *n1ptr, *n2ptr;
+ int count;
+
+ /* First, compare signs. */
+ if (use_sign && n1->n_sign != n2->n_sign)
+ {
+ if (n1->n_sign == PLUS)
+ return (1); /* Positive N1 > Negative N2 */
+ else
+ return (-1); /* Negative N1 < Positive N1 */
+ }
+
+ /* Now compare the magnitude. */
+ if (n1->n_len != n2->n_len)
+ {
+ if (n1->n_len > n2->n_len)
+ {
+ /* Magnitude of n1 > n2. */
+ if (!use_sign || n1->n_sign == PLUS)
+ return (1);
+ else
+ return (-1);
+ }
+ else
+ {
+ /* Magnitude of n1 < n2. */
+ if (!use_sign || n1->n_sign == PLUS)
+ return (-1);
+ else
+ return (1);
+ }
+ }
+
+ /* If we get here, they have the same number of integer digits.
+ check the integer part and the equal length part of the fraction. */
+ count = n1->n_len + MIN (n1->n_scale, n2->n_scale);
+ n1ptr = n1->n_value;
+ n2ptr = n2->n_value;
+
+ while ((count > 0) && (*n1ptr == *n2ptr))
+ {
+ n1ptr++;
+ n2ptr++;
+ count--;
+ }
+ if (ignore_last && count == 1 && n1->n_scale == n2->n_scale)
+ return (0);
+ if (count != 0)
+ {
+ if (*n1ptr > *n2ptr)
+ {
+ /* Magnitude of n1 > n2. */
+ if (!use_sign || n1->n_sign == PLUS)
+ return (1);
+ else
+ return (-1);
+ }
+ else
+ {
+ /* Magnitude of n1 < n2. */
+ if (!use_sign || n1->n_sign == PLUS)
+ return (-1);
+ else
+ return (1);
+ }
+ }
+
+ /* They are equal up to the last part of the equal part of the fraction. */
+ if (n1->n_scale != n2->n_scale)
+ if (n1->n_scale > n2->n_scale)
+ {
+ for (count = n1->n_scale-n2->n_scale; count>0; count--)
+ if (*n1ptr++ != 0)
+ {
+ /* Magnitude of n1 > n2. */
+ if (!use_sign || n1->n_sign == PLUS)
+ return (1);
+ else
+ return (-1);
+ }
+ }
+ else
+ {
+ for (count = n2->n_scale-n1->n_scale; count>0; count--)
+ if (*n2ptr++ != 0)
+ {
+ /* Magnitude of n1 < n2. */
+ if (!use_sign || n1->n_sign == PLUS)
+ return (-1);
+ else
+ return (1);
+ }
+ }
+
+ /* They must be equal! */
+ return (0);
+}
+
+
+/* This is the "user callable" routine to compare numbers N1 and N2. */
+
+int
+bc_compare (n1, n2)
+ bc_num n1, n2;
+{
+ return _do_compare (n1, n2, TRUE, FALSE);
+}
+
+
+/* In some places we need to check if the number NUM is zero. */
+
+char
+is_zero (num)
+ bc_num num;
+{
+ int count;
+ char *nptr;
+
+ /* Quick check. */
+ if (num == _zero_) return TRUE;
+
+ /* Initialize */
+ count = num->n_len + num->n_scale;
+ nptr = num->n_value;
+
+ /* The check */
+ while ((count > 0) && (*nptr++ == 0)) count--;
+
+ if (count != 0)
+ return FALSE;
+ else
+ return TRUE;
+}
+
+
+/* In some places we need to check if the number is negative. */
+
+char
+is_neg (num)
+ bc_num num;
+{
+ return num->n_sign == MINUS;
+}
+
+
+/* For many things, we may have leading zeros in a number NUM.
+ _rm_leading_zeros just moves the data to the correct
+ place and adjusts the length. */
+
+static void
+_rm_leading_zeros (num)
+ bc_num num;
+{
+ int bytes;
+ char *dst, *src;
+
+ /* Do a quick check to see if we need to do it. */
+ if (*num->n_value != 0) return;
+
+ /* The first digit is 0, find the first non-zero digit in the 10's or
+ greater place. */
+ bytes = num->n_len;
+ src = num->n_value;
+ while (bytes > 1 && *src == 0) src++, bytes--;
+ num->n_len = bytes;
+ bytes += num->n_scale;
+ dst = num->n_value;
+ while (bytes-- > 0) *dst++ = *src++;
+
+}
+
+
+/* Perform addition: N1 is added to N2 and the value is
+ returned. The signs of N1 and N2 are ignored. */
+
+static bc_num
+_do_add (n1, n2)
+ bc_num n1, n2;
+{
+ bc_num sum;
+ int sum_scale, sum_digits;
+ char *n1ptr, *n2ptr, *sumptr;
+ int carry, n1bytes, n2bytes;
+
+ /* Prepare sum. */
+ sum_scale = MAX (n1->n_scale, n2->n_scale);
+ sum_digits = MAX (n1->n_len, n2->n_len) + 1;
+ sum = new_num (sum_digits,sum_scale);
+
+ /* Start with the fraction part. Initialize the pointers. */
+ n1bytes = n1->n_scale;
+ n2bytes = n2->n_scale;
+ n1ptr = (char *) (n1->n_value + n1->n_len + n1bytes - 1);
+ n2ptr = (char *) (n2->n_value + n2->n_len + n2bytes - 1);
+ sumptr = (char *) (sum->n_value + sum_scale + sum_digits - 1);
+
+ /* Add the fraction part. First copy the longer fraction.*/
+ if (n1bytes != n2bytes)
+ {
+ if (n1bytes > n2bytes)
+ while (n1bytes>n2bytes)
+ { *sumptr-- = *n1ptr--; n1bytes--;}
+ else
+ while (n2bytes>n1bytes)
+ { *sumptr-- = *n2ptr--; n2bytes--;}
+ }
+
+ /* Now add the remaining fraction part and equal size integer parts. */
+ n1bytes += n1->n_len;
+ n2bytes += n2->n_len;
+ carry = 0;
+ while ((n1bytes > 0) && (n2bytes > 0))
+ {
+ *sumptr = *n1ptr-- + *n2ptr-- + carry;
+ if (*sumptr > 9)
+ {
+ carry = 1;
+ *sumptr -= 10;
+ }
+ else
+ carry = 0;
+ sumptr--;
+ n1bytes--;
+ n2bytes--;
+ }
+
+ /* Now add carry the longer integer part. */
+ if (n1bytes == 0)
+ { n1bytes = n2bytes; n1ptr = n2ptr; }
+ while (n1bytes-- > 0)
+ {
+ *sumptr = *n1ptr-- + carry;
+ if (*sumptr > 9)
+ {
+ carry = 1;
+ *sumptr -= 10;
+ }
+ else
+ carry = 0;
+ sumptr--;
+ }
+
+ /* Set final carry. */
+ if (carry == 1)
+ *sumptr += 1;
+
+ /* Adjust sum and return. */
+ _rm_leading_zeros (sum);
+ return sum;
+}
+
+
+/* Perform subtraction: N2 is subtracted from N1 and the value is
+ returned. The signs of N1 and N2 are ignored. Also, N1 is
+ assumed to be larger than N2. */
+
+static bc_num
+_do_sub (n1, n2)
+ bc_num n1, n2;
+{
+ bc_num diff;
+ int diff_scale, diff_len;
+ int min_scale, min_len;
+ char *n1ptr, *n2ptr, *diffptr;
+ int borrow, count, val;
+
+ /* Allocate temporary storage. */
+ diff_len = MAX (n1->n_len, n2->n_len);
+ diff_scale = MAX (n1->n_scale, n2->n_scale);
+ min_len = MIN (n1->n_len, n2->n_len);
+ min_scale = MIN (n1->n_scale, n2->n_scale);
+ diff = new_num (diff_len, diff_scale);
+
+ /* Initialize the subtract. */
+ n1ptr = (char *) (n1->n_value + n1->n_len + n1->n_scale -1);
+ n2ptr = (char *) (n2->n_value + n2->n_len + n2->n_scale -1);
+ diffptr = (char *) (diff->n_value + diff_len + diff_scale -1);
+
+ /* Subtract the numbers. */
+ borrow = 0;
+
+ /* Take care of the longer scaled number. */
+ if (n1->n_scale != min_scale)
+ {
+ /* n1 has the longer scale */
+ for (count = n1->n_scale - min_scale; count > 0; count--)
+ *diffptr-- = *n1ptr--;
+ }
+ else
+ {
+ /* n2 has the longer scale */
+ for (count = n2->n_scale - min_scale; count > 0; count--)
+ {
+ val = - *n2ptr-- - borrow;
+ if (val < 0)
+ {
+ val += 10;
+ borrow = 1;
+ }
+ else
+ borrow = 0;
+ *diffptr-- = val;
+ }
+ }
+
+ /* Now do the equal length scale and integer parts. */
+
+ for (count = 0; count < min_len + min_scale; count++)
+ {
+ val = *n1ptr-- - *n2ptr-- - borrow;
+ if (val < 0)
+ {
+ val += 10;
+ borrow = 1;
+ }
+ else
+ borrow = 0;
+ *diffptr-- = val;
+ }
+
+ /* If n1 has more digits then n2, we now do that subtract. */
+ if (diff_len != min_len)
+ {
+ for (count = diff_len - min_len; count > 0; count--)
+ {
+ val = *n1ptr-- - borrow;
+ if (val < 0)
+ {
+ val += 10;
+ borrow = 1;
+ }
+ else
+ borrow = 0;
+ *diffptr-- = val;
+ }
+ }
+
+ /* Clean up and return. */
+ _rm_leading_zeros (diff);
+ return diff;
+}
+
+
+/* Here is the full add routine that takes care of negative numbers.
+ N1 is added to N2 and the result placed into RESULT. */
+
+void
+bc_add ( n1, n2, result)
+ bc_num n1, n2, *result;
+{
+ bc_num sum;
+ int cmp_res;
+
+ if (n1->n_sign == n2->n_sign)
+ {
+ sum = _do_add (n1, n2);
+ sum->n_sign = n1->n_sign;
+ }
+ else
+ {
+ /* subtraction must be done. */
+ cmp_res = _do_compare (n1, n2, FALSE, FALSE); /* Compare magnitudes. */
+ switch (cmp_res)
+ {
+ case -1:
+ /* n1 is less than n2, subtract n1 from n2. */
+ sum = _do_sub (n2, n1);
+ sum->n_sign = n2->n_sign;
+ break;
+ case 0:
+ /* They are equal! return zero! */
+ sum = copy_num (_zero_);
+ break;
+ case 1:
+ /* n2 is less than n1, subtract n2 from n1. */
+ sum = _do_sub (n1, n2);
+ sum->n_sign = n1->n_sign;
+ }
+ }
+
+ /* Clean up and return. */
+ free_num (result);
+ *result = sum;
+}
+
+
+/* Here is the full subtract routine that takes care of negative numbers.
+ N2 is subtracted from N1 and the result placed in RESULT. */
+
+void
+bc_sub ( n1, n2, result)
+ bc_num n1, n2, *result;
+{
+ bc_num diff;
+ int cmp_res;
+
+ if (n1->n_sign != n2->n_sign)
+ {
+ diff = _do_add (n1, n2);
+ diff->n_sign = n1->n_sign;
+ }
+ else
+ {
+ /* subtraction must be done. */
+ cmp_res = _do_compare (n1, n2, FALSE, FALSE); /* Compare magnitudes. */
+ switch (cmp_res)
+ {
+ case -1:
+ /* n1 is less than n2, subtract n1 from n2. */
+ diff = _do_sub (n2, n1);
+ diff->n_sign = (n2->n_sign == PLUS ? MINUS : PLUS);
+ break;
+ case 0:
+ /* They are equal! return zero! */
+ diff = copy_num (_zero_);
+ break;
+ case 1:
+ /* n2 is less than n1, subtract n2 from n1. */
+ diff = _do_sub (n1, n2);
+ diff->n_sign = n1->n_sign;
+ break;
+ }
+ }
+
+ /* Clean up and return. */
+ free_num (result);
+ *result = diff;
+}
+
+
+/* The multiply routine. N2 time N1 is put int PROD with the scale of
+ the result being MIN(N2 scale+N1 scale, MAX (SCALE, N2 scale, N1 scale)).
+ */
+
+void
+bc_multiply (n1, n2, prod, scale)
+ bc_num n1, n2, *prod;
+ int scale;
+{
+ bc_num pval; /* For the working storage. */
+ char *n1ptr, *n2ptr, *pvptr; /* Work pointers. */
+ char *n1end, *n2end; /* To the end of n1 and n2. */
+
+ int indx;
+ int len1, len2, total_digits;
+ long sum;
+ int full_scale, prod_scale;
+ int toss;
+
+ /* Initialize things. */
+ len1 = n1->n_len + n1->n_scale;
+ len2 = n2->n_len + n2->n_scale;
+ total_digits = len1 + len2;
+ full_scale = n1->n_scale + n2->n_scale;
+ prod_scale = MIN(full_scale,MAX(scale,MAX(n1->n_scale,n2->n_scale)));
+ toss = full_scale - prod_scale;
+ pval = new_num (total_digits-full_scale, prod_scale);
+ pval->n_sign = ( n1->n_sign == n2->n_sign ? PLUS : MINUS );
+ n1end = (char *) (n1->n_value + len1 - 1);
+ n2end = (char *) (n2->n_value + len2 - 1);
+ pvptr = (char *) (pval->n_value + total_digits - toss - 1);
+ sum = 0;
+
+ /* Here are the loops... */
+ for (indx = 0; indx < toss; indx++)
+ {
+ n1ptr = (char *) (n1end - MAX(0, indx-len2+1));
+ n2ptr = (char *) (n2end - MIN(indx, len2-1));
+ while ((n1ptr >= n1->n_value) && (n2ptr <= n2end))
+ sum += *n1ptr-- * *n2ptr++;
+ sum = sum / 10;
+ }
+ for ( ; indx < total_digits-1; indx++)
+ {
+ n1ptr = (char *) (n1end - MAX(0, indx-len2+1));
+ n2ptr = (char *) (n2end - MIN(indx, len2-1));
+ while ((n1ptr >= n1->n_value) && (n2ptr <= n2end))
+ sum += *n1ptr-- * *n2ptr++;
+ *pvptr-- = sum % 10;
+ sum = sum / 10;
+ }
+ *pvptr-- = sum;
+
+ /* Assign to prod and clean up the number. */
+ free_num (prod);
+ *prod = pval;
+ _rm_leading_zeros (*prod);
+ if (is_zero (*prod))
+ (*prod)->n_sign = PLUS;
+}
+
+
+/* Some utility routines for the divide: First a one digit multiply.
+ NUM (with SIZE digits) is multiplied by DIGIT and the result is
+ placed into RESULT. It is written so that NUM and RESULT can be
+ the same pointers. */
+
+static void
+_one_mult (num, size, digit, result)
+ unsigned char *num;
+ int size, digit;
+ unsigned char *result;
+{
+ int carry, value;
+ unsigned char *nptr, *rptr;
+
+ if (digit == 0)
+ memset (result, 0, size);
+ else
+ {
+ if (digit == 1)
+ memcpy (result, num, size);
+ else
+ {
+ /* Initialize */
+ nptr = (unsigned char *) (num+size-1);
+ rptr = (unsigned char *) (result+size-1);
+ carry = 0;
+
+ while (size-- > 0)
+ {
+ value = *nptr-- * digit + carry;
+ *rptr-- = value % 10;
+ carry = value / 10;
+ }
+
+ if (carry != 0) *rptr = carry;
+ }
+ }
+}
+
+
+/* The full division routine. This computes N1 / N2. It returns
+ 0 if the division is ok and the result is in QUOT. The number of
+ digits after the decimal point is SCALE. It returns -1 if division
+ by zero is tried. The algorithm is found in Knuth Vol 2. p237. */
+
+int
+bc_divide (n1, n2, quot, scale)
+ bc_num n1, n2, *quot;
+ int scale;
+{
+ bc_num qval;
+ unsigned char *num1, *num2;
+ unsigned char *ptr1, *ptr2, *n2ptr, *qptr;
+ int scale1, val;
+ unsigned int len1, len2, scale2, qdigits, extra, count;
+ unsigned int qdig, qguess, borrow, carry;
+ unsigned char *mval;
+ char zero;
+ unsigned int norm;
+
+ /* Test for divide by zero. */
+ if (is_zero (n2)) return -1;
+
+ /* Test for divide by 1. If it is we must truncate. */
+ if (n2->n_scale == 0)
+ {
+ if (n2->n_len == 1 && *n2->n_value == 1)
+ {
+ qval = new_num (n1->n_len, scale);
+ qval->n_sign = (n1->n_sign == n2->n_sign ? PLUS : MINUS);
+ memset (&qval->n_value[n1->n_len],0,scale);
+ memcpy (qval->n_value, n1->n_value,
+ n1->n_len + MIN(n1->n_scale,scale));
+ free_num (quot);
+ *quot = qval;
+ }
+ }
+
+ /* Set up the divide. Move the decimal point on n1 by n2's scale.
+ Remember, zeros on the end of num2 are wasted effort for dividing. */
+ scale2 = n2->n_scale;
+ n2ptr = (unsigned char *) n2->n_value+n2->n_len+scale2-1;
+ while ((scale2 > 0) && (*n2ptr-- == 0)) scale2--;
+
+ len1 = n1->n_len + scale2;
+ scale1 = n1->n_scale - scale2;
+ if (scale1 < scale)
+ extra = scale - scale1;
+ else
+ extra = 0;
+ num1 = (unsigned char *) malloc (n1->n_len+n1->n_scale+extra+2);
+ if (num1 == NULL) out_of_memory();
+ memset (num1, 0, n1->n_len+n1->n_scale+extra+2);
+ memcpy (num1+1, n1->n_value, n1->n_len+n1->n_scale);
+
+ len2 = n2->n_len + scale2;
+ num2 = (unsigned char *) malloc (len2+1);
+ if (num2 == NULL) out_of_memory();
+ memcpy (num2, n2->n_value, len2);
+ *(num2+len2) = 0;
+ n2ptr = num2;
+ while (*n2ptr == 0)
+ {
+ n2ptr++;
+ len2--;
+ }
+
+ /* Calculate the number of quotient digits. */
+ if (len2 > len1+scale)
+ {
+ qdigits = scale+1;
+ zero = TRUE;
+ }
+ else
+ {
+ zero = FALSE;
+ if (len2>len1)
+ qdigits = scale+1; /* One for the zero integer part. */
+ else
+ qdigits = len1-len2+scale+1;
+ }
+
+ /* Allocate and zero the storage for the quotient. */
+ qval = new_num (qdigits-scale,scale);
+ memset (qval->n_value, 0, qdigits);
+
+ /* Allocate storage for the temporary storage mval. */
+ mval = (unsigned char *) malloc (len2+1);
+ if (mval == NULL) out_of_memory ();
+
+ /* Now for the full divide algorithm. */
+ if (!zero)
+ {
+ /* Normalize */
+ norm = 10 / ((int)*n2ptr + 1);
+ if (norm != 1)
+ {
+ _one_mult (num1, len1+scale1+extra+1, norm, num1);
+ _one_mult (n2ptr, len2, norm, n2ptr);
+ }
+
+ /* Initialize divide loop. */
+ qdig = 0;
+ if (len2 > len1)
+ qptr = (unsigned char *) qval->n_value+len2-len1;
+ else
+ qptr = (unsigned char *) qval->n_value;
+
+ /* Loop */
+ while (qdig <= len1+scale-len2)
+ {
+ /* Calculate the quotient digit guess. */
+ if (*n2ptr == num1[qdig])
+ qguess = 9;
+ else
+ qguess = (num1[qdig]*10 + num1[qdig+1]) / *n2ptr;
+
+ /* Test qguess. */
+ if (n2ptr[1]*qguess >
+ (num1[qdig]*10 + num1[qdig+1] - *n2ptr*qguess)*10
+ + num1[qdig+2])
+ {
+ qguess--;
+ /* And again. */
+ if (n2ptr[1]*qguess >
+ (num1[qdig]*10 + num1[qdig+1] - *n2ptr*qguess)*10
+ + num1[qdig+2])
+ qguess--;
+ }
+
+ /* Multiply and subtract. */
+ borrow = 0;
+ if (qguess != 0)
+ {
+ *mval = 0;
+ _one_mult (n2ptr, len2, qguess, mval+1);
+ ptr1 = (unsigned char *) num1+qdig+len2;
+ ptr2 = (unsigned char *) mval+len2;
+ for (count = 0; count < len2+1; count++)
+ {
+ val = (int) *ptr1 - (int) *ptr2-- - borrow;
+ if (val < 0)
+ {
+ val += 10;
+ borrow = 1;
+ }
+ else
+ borrow = 0;
+ *ptr1-- = val;
+ }
+ }
+
+ /* Test for negative result. */
+ if (borrow == 1)
+ {
+ qguess--;
+ ptr1 = (unsigned char *) num1+qdig+len2;
+ ptr2 = (unsigned char *) n2ptr+len2-1;
+ carry = 0;
+ for (count = 0; count < len2; count++)
+ {
+ val = (int) *ptr1 + (int) *ptr2-- + carry;
+ if (val > 9)
+ {
+ val -= 10;
+ carry = 1;
+ }
+ else
+ carry = 0;
+ *ptr1-- = val;
+ }
+ if (carry == 1) *ptr1 = (*ptr1 + 1) % 10;
+ }
+
+ /* We now know the quotient digit. */
+ *qptr++ = qguess;
+ qdig++;
+ }
+ }
+
+ /* Clean up and return the number. */
+ qval->n_sign = ( n1->n_sign == n2->n_sign ? PLUS : MINUS );
+ if (is_zero (qval)) qval->n_sign = PLUS;
+ _rm_leading_zeros (qval);
+ free_num (quot);
+ *quot = qval;
+
+ /* Clean up temporary storage. */
+ free (mval);
+ free (num1);
+ free (num2);
+
+ return 0; /* Everything is OK. */
+}
+
+
+/* Modulo for numbers. This computes NUM1 % NUM2 and puts the
+ result in RESULT. */
+
+int
+bc_modulo (num1, num2, result, scale)
+ bc_num num1, num2, *result;
+ int scale;
+{
+ bc_num temp;
+ int rscale;
+
+ /* Check for correct numbers. */
+ if (is_zero (num2)) return -1;
+
+ /* Calculate final scale. */
+ rscale = MAX (num1->n_scale, num2->n_scale+scale);
+ init_num (&temp);
+
+ /* Calculate it. */
+ bc_divide (num1, num2, &temp, scale);
+ bc_multiply (temp, num2, &temp, rscale);
+ bc_sub (num1, temp, result);
+ free_num (&temp);
+
+ return 0; /* Everything is OK. */
+}
+
+
+/* Raise NUM1 to the NUM2 power. The result is placed in RESULT.
+ Maximum exponent is LONG_MAX. If a NUM2 is not an integer,
+ only the integer part is used. */
+
+void
+bc_raise (num1, num2, result, scale)
+ bc_num num1, num2, *result;
+ int scale;
+{
+ bc_num temp, power;
+ long exponent;
+ int rscale;
+ char neg;
+
+ /* Check the exponent for scale digits and convert to a long. */
+ if (num2->n_scale != 0)
+ rt_warn ("non-zero scale in exponent");
+ exponent = num2long (num2);
+ if (exponent == 0 && (num2->n_len > 1 || num2->n_value[0] != 0))
+ rt_error ("exponent too large in raise");
+
+ /* Special case if exponent is a zero. */
+ if (exponent == 0)
+ {
+ free_num (result);
+ *result = copy_num (_one_);
+ return;
+ }
+
+ /* Other initializations. */
+ if (exponent < 0)
+ {
+ neg = TRUE;
+ exponent = -exponent;
+ rscale = scale;
+ }
+ else
+ {
+ neg = FALSE;
+ rscale = MIN (num1->n_scale*exponent, MAX(scale, num1->n_scale));
+ }
+ temp = copy_num (_one_);
+ power = copy_num (num1);
+
+ /* Do the calculation. */
+ while (exponent != 0)
+ {
+ if (exponent & 1 != 0)
+ bc_multiply (temp, power, &temp, rscale);
+ bc_multiply (power, power, &power, rscale);
+ exponent = exponent >> 1;
+ }
+
+ /* Assign the value. */
+ if (neg)
+ {
+ bc_divide (_one_, temp, result, rscale);
+ free_num (&temp);
+ }
+ else
+ {
+ free_num (result);
+ *result = temp;
+ }
+ free_num (&power);
+}
+
+
+/* Take the square root NUM and return it in NUM with SCALE digits
+ after the decimal place. */
+
+int
+bc_sqrt (num, scale)
+ bc_num *num;
+ int scale;
+{
+ int rscale, cmp_res, done;
+ int cscale;
+ bc_num guess, guess1, point5;
+
+ /* Initial checks. */
+ cmp_res = bc_compare (*num, _zero_);
+ if (cmp_res < 0)
+ return 0; /* error */
+ else
+ {
+ if (cmp_res == 0)
+ {
+ free_num (num);
+ *num = copy_num (_zero_);
+ return 1;
+ }
+ }
+ cmp_res = bc_compare (*num, _one_);
+ if (cmp_res == 0)
+ {
+ free_num (num);
+ *num = copy_num (_one_);
+ return 1;
+ }
+
+ /* Initialize the variables. */
+ rscale = MAX (scale, (*num)->n_scale);
+ cscale = rscale + 2;
+ init_num (&guess);
+ init_num (&guess1);
+ point5 = new_num (1,1);
+ point5->n_value[1] = 5;
+
+
+ /* Calculate the initial guess. */
+ if (cmp_res < 0)
+ /* The number is between 0 and 1. Guess should start at 1. */
+ guess = copy_num (_one_);
+ else
+ {
+ /* The number is greater than 1. Guess should start at 10^(exp/2). */
+ int2num (&guess,10);
+ int2num (&guess1,(*num)->n_len);
+ bc_multiply (guess1, point5, &guess1, rscale);
+ guess1->n_scale = 0;
+ bc_raise (guess, guess1, &guess, rscale);
+ free_num (&guess1);
+ }
+
+ /* Find the square root using Newton's algorithm. */
+ done = FALSE;
+ while (!done)
+ {
+ free_num (&guess1);
+ guess1 = copy_num (guess);
+ bc_divide (*num,guess,&guess,cscale);
+ bc_add (guess,guess1,&guess);
+ bc_multiply (guess,point5,&guess,cscale);
+ cmp_res = _do_compare (guess,guess1,FALSE,TRUE);
+ if (cmp_res == 0) done = TRUE;
+ }
+
+ /* Assign the number and clean up. */
+ free_num (num);
+ bc_divide (guess,_one_,num,rscale);
+ free_num (&guess);
+ free_num (&guess1);
+ free_num (&point5);
+ return 1;
+}
+
+
+/* The following routines provide output for bcd numbers package
+ using the rules of POSIX bc for output. */
+
+/* This structure is used for saving digits in the conversion process. */
+typedef struct stk_rec {
+ long digit;
+ struct stk_rec *next;
+} stk_rec;
+
+/* The reference string for digits. */
+char ref_str[] = "0123456789ABCDEF";
+
+
+/* A special output routine for "multi-character digits." Exactly
+ SIZE characters must be output for the value VAL. If SPACE is
+ non-zero, we must output one space before the number. OUT_CHAR
+ is the actual routine for writing the characters. */
+
+void
+out_long (val, size, space, out_char)
+ long val;
+ int size, space;
+#ifdef __STDC__
+ void (*out_char)(int);
+#else
+ void (*out_char)();
+#endif
+{
+ char digits[40];
+ int len, ix;
+
+ if (space) (*out_char) (' ');
+ sprintf (digits, "%ld", val);
+ len = strlen (digits);
+ while (size > len)
+ {
+ (*out_char) ('0');
+ size--;
+ }
+ for (ix=0; ix < len; ix++)
+ (*out_char) (digits[ix]);
+}
+
+/* Output of a bcd number. NUM is written in base O_BASE using OUT_CHAR
+ as the routine to do the actual output of the characters. */
+
+void
+out_num (num, o_base, out_char)
+ bc_num num;
+ int o_base;
+#ifdef __STDC__
+ void (*out_char)(int);
+#else
+ void (*out_char)();
+#endif
+{
+ char *nptr;
+ int index, fdigit, pre_space;
+ stk_rec *digits, *temp;
+ bc_num int_part, frac_part, base, cur_dig, t_num, max_o_digit;
+
+ /* The negative sign if needed. */
+ if (num->n_sign == MINUS) (*out_char) ('-');
+
+ /* Output the number. */
+ if (is_zero (num))
+ (*out_char) ('0');
+ else
+ if (o_base == 10)
+ {
+ /* The number is in base 10, do it the fast way. */
+ nptr = num->n_value;
+ if (num->n_len > 1 || *nptr != 0)
+ for (index=num->n_len; index>0; index--)
+ (*out_char) (BCD_CHAR(*nptr++));
+ else
+ nptr++;
+
+ /* Now the fraction. */
+ if (num->n_scale > 0)
+ {
+ (*out_char) ('.');
+ for (index=0; index<num->n_scale; index++)
+ (*out_char) (BCD_CHAR(*nptr++));
+ }
+ }
+ else
+ {
+ /* The number is some other base. */
+ digits = NULL;
+ init_num (&int_part);
+ bc_divide (num, _one_, &int_part, 0);
+ init_num (&frac_part);
+ init_num (&cur_dig);
+ init_num (&base);
+ bc_sub (num, int_part, &frac_part);
+ int2num (&base, o_base);
+ init_num (&max_o_digit);
+ int2num (&max_o_digit, o_base-1);
+
+
+ /* Get the digits of the integer part and push them on a stack. */
+ while (!is_zero (int_part))
+ {
+ bc_modulo (int_part, base, &cur_dig, 0);
+ temp = (stk_rec *) malloc (sizeof(stk_rec));
+ if (temp == NULL) out_of_memory();
+ temp->digit = num2long (cur_dig);
+ temp->next = digits;
+ digits = temp;
+ bc_divide (int_part, base, &int_part, 0);
+ }
+
+ /* Print the digits on the stack. */
+ if (digits != NULL)
+ {
+ /* Output the digits. */
+ while (digits != NULL)
+ {
+ temp = digits;
+ digits = digits->next;
+ if (o_base <= 16)
+ (*out_char) (ref_str[ (int) temp->digit]);
+ else
+ out_long (temp->digit, max_o_digit->n_len, 1, out_char);
+ free (temp);
+ }
+ }
+
+ /* Get and print the digits of the fraction part. */
+ if (num->n_scale > 0)
+ {
+ (*out_char) ('.');
+ pre_space = 0;
+ t_num = copy_num (_one_);
+ while (t_num->n_len <= num->n_scale) {
+ bc_multiply (frac_part, base, &frac_part, num->n_scale);
+ fdigit = num2long (frac_part);
+ int2num (&int_part, fdigit);
+ bc_sub (frac_part, int_part, &frac_part);
+ if (o_base <= 16)
+ (*out_char) (ref_str[fdigit]);
+ else {
+ out_long (fdigit, max_o_digit->n_len, pre_space, out_char);
+ pre_space = 1;
+ }
+ bc_multiply (t_num, base, &t_num, 0);
+ }
+ }
+
+ /* Clean up. */
+ free_num (&int_part);
+ free_num (&frac_part);
+ free_num (&base);
+ free_num (&cur_dig);
+ }
+}
+
+
+#if DEBUG > 0
+
+/* Debugging procedures. Some are just so one can call them from the
+ debugger. */
+
+/* p_n prints the number NUM in base 10. */
+
+void
+p_n (num)
+ bc_num num;
+{
+ out_num (num, 10, out_char);
+ return 0;
+}
+
+
+/* p_b prints a character array as if it was a string of bcd digits. */
+void
+p_v (name, num, len)
+ char *name;
+ unsigned char *num;
+ int len;
+{
+ int i;
+ printf ("%s=", name);
+ for (i=0; i<len; i++) printf ("%c",BCD_CHAR(num[i]));
+ printf ("\n");
+}
+
+
+/* Convert strings to bc numbers. Base 10 only.*/
+
+void
+str2num (num, str, scale)
+ bc_num *num;
+ char *str;
+ int scale;
+{
+ int digits, strscale;
+ char *ptr, *nptr;
+ char zero_int;
+
+ /* Prepare num. */
+ free_num (num);
+
+ /* Check for valid number and count digits. */
+ ptr = str;
+ digits = 0;
+ strscale = 0;
+ zero_int = FALSE;
+ if ( (*ptr == '+') || (*ptr == '-')) ptr++; /* Sign */
+ while (*ptr == '0') ptr++; /* Skip leading zeros. */
+ while (isdigit(*ptr)) ptr++, digits++; /* digits */
+ if (*ptr == '.') ptr++; /* decimal point */
+ while (isdigit(*ptr)) ptr++, strscale++; /* digits */
+ if ((*ptr != '\0') || (digits+strscale == 0))
+ {
+ *num = copy_num (_zero_);
+ return;
+ }
+
+ /* Adjust numbers and allocate storage and initialize fields. */
+ strscale = MIN(strscale, scale);
+ if (digits == 0)
+ {
+ zero_int = TRUE;
+ digits = 1;
+ }
+ *num = new_num (digits, strscale);
+
+ /* Build the whole number. */
+ ptr = str;
+ if (*ptr == '-')
+ {
+ (*num)->n_sign = MINUS;
+ ptr++;
+ }
+ else
+ {
+ (*num)->n_sign = PLUS;
+ if (*ptr == '+') ptr++;
+ }
+ while (*ptr == '0') ptr++; /* Skip leading zeros. */
+ nptr = (*num)->n_value;
+ if (zero_int)
+ {
+ *nptr++ = 0;
+ digits = 0;
+ }
+ for (;digits > 0; digits--)
+ *nptr++ = CH_VAL(*ptr++);
+
+
+ /* Build the fractional part. */
+ if (strscale > 0)
+ {
+ ptr++; /* skip the decimal point! */
+ for (;strscale > 0; strscale--)
+ *nptr++ = CH_VAL(*ptr++);
+ }
+}
+
+/* Convert a numbers to a string. Base 10 only.*/
+
+char
+*num2str (num)
+ bc_num num;
+{
+ char *str, *sptr;
+ char *nptr;
+ int index, signch;
+
+ /* Allocate the string memory. */
+ signch = ( num->n_sign == PLUS ? 0 : 1 ); /* Number of sign chars. */
+ if (num->n_scale > 0)
+ str = (char *) malloc (num->n_len + num->n_scale + 2 + signch);
+ else
+ str = (char *) malloc (num->n_len + 1 + signch);
+ if (str == NULL) out_of_memory();
+
+ /* The negative sign if needed. */
+ sptr = str;
+ if (signch) *sptr++ = '-';
+
+ /* Load the whole number. */
+ nptr = num->n_value;
+ for (index=num->n_len; index>0; index--)
+ *sptr++ = BCD_CHAR(*nptr++);
+
+ /* Now the fraction. */
+ if (num->n_scale > 0)
+ {
+ *sptr++ = '.';
+ for (index=0; index<num->n_scale; index++)
+ *sptr++ = BCD_CHAR(*nptr++);
+ }
+
+ /* Terminate the string and return it! */
+ *sptr = '\0';
+ return (str);
+}
+#endif
diff --git a/gnu/usr.bin/bc/number.h b/gnu/usr.bin/bc/number.h
new file mode 100644
index 0000000..79a340f
--- /dev/null
+++ b/gnu/usr.bin/bc/number.h
@@ -0,0 +1,60 @@
+/* number.h: Arbitrary precision numbers header file. */
+
+/* This file is part of bc written for MINIX.
+ Copyright (C) 1991, 1992 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License , or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; see the file COPYING. If not, write to
+ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ You may contact the author by:
+ e-mail: phil@cs.wwu.edu
+ us-mail: Philip A. Nelson
+ Computer Science Department, 9062
+ Western Washington University
+ Bellingham, WA 98226-9062
+
+*************************************************************************/
+
+
+typedef enum {PLUS, MINUS} sign;
+
+typedef struct
+ {
+ sign n_sign;
+ int n_len; /* The number of digits before the decimal point. */
+ int n_scale; /* The number of digits after the decimal point. */
+ int n_refs; /* The number of pointers to this number. */
+ char n_value[1]; /* The storage. Not zero char terminated. It is
+ allocated with all other fields. */
+ } bc_struct;
+
+typedef bc_struct *bc_num;
+
+/* Some useful macros and constants. */
+
+#define CH_VAL(c) (c - '0')
+#define BCD_CHAR(d) (d + '0')
+
+#ifdef MIN
+#undef MIN
+#undef MAX
+#endif
+#define MAX(a,b) (a>b?a:b)
+#define MIN(a,b) (a>b?b:a)
+#define ODD(a) (a&1)
+
+#ifndef TRUE
+#define TRUE 1
+#define FALSE 0
+#endif
diff --git a/gnu/usr.bin/bc/proto.h b/gnu/usr.bin/bc/proto.h
new file mode 100644
index 0000000..f2aa490
--- /dev/null
+++ b/gnu/usr.bin/bc/proto.h
@@ -0,0 +1,165 @@
+/* proto.h: Prototype function definitions for "external" functions. */
+
+/* This file is part of bc written for MINIX.
+ Copyright (C) 1991, 1992 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License , or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; see the file COPYING. If not, write to
+ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ You may contact the author by:
+ e-mail: phil@cs.wwu.edu
+ us-mail: Philip A. Nelson
+ Computer Science Department, 9062
+ Western Washington University
+ Bellingham, WA 98226-9062
+
+*************************************************************************/
+
+/* For the pc version using k&r ACK. (minix1.5 and earlier.) */
+#ifdef SHORTNAMES
+#define init_numbers i_numbers
+#define push_constant push__constant
+#define load_const in_load_const
+#define yy_get_next_buffer yyget_next_buffer
+#define yy_init_buffer yyinit_buffer
+#define yy_last_accepting_state yylast_accepting_state
+#define arglist1 arg1list
+#endif
+
+/* Include the standard library header files. */
+#ifndef NO_UNISTD
+#include <unistd.h>
+#endif
+#ifndef NO_STDLIB
+#ifdef __STDC__
+#include <stdlib.h>
+#endif
+#endif
+
+/* Define the _PROTOTYPE macro if it is needed. */
+
+#ifndef _PROTOTYPE
+#ifdef __STDC__
+#define _PROTOTYPE(func, args) func args
+#else
+#define _PROTOTYPE(func, args) func()
+#endif
+#endif
+
+/* From execute.c */
+_PROTOTYPE(void stop_execution, (int));
+_PROTOTYPE(unsigned char byte, (program_counter *pc));
+_PROTOTYPE(void execute, (void));
+_PROTOTYPE(char prog_char, (void));
+_PROTOTYPE(char input_char, (void));
+_PROTOTYPE(void push_constant, (char (*in_char)(void), int conv_base));
+_PROTOTYPE(void push_b10_const, (program_counter *pc));
+_PROTOTYPE(void assign, (int c_code));
+
+/* From util.c */
+_PROTOTYPE(char *strcopyof, (char *str));
+_PROTOTYPE(arg_list *nextarg, (arg_list *args, int val));
+_PROTOTYPE(char *arg_str, (arg_list *args, int));
+_PROTOTYPE(void free_args, (arg_list *args));
+_PROTOTYPE(void check_params, (arg_list *params, arg_list *autos));
+_PROTOTYPE(void init_gen, (void));
+_PROTOTYPE(void generate, (char *str));
+_PROTOTYPE(void run_code, (void));
+_PROTOTYPE(void out_char, (int ch));
+_PROTOTYPE(id_rec *find_id, (id_rec *tree, char *id));
+_PROTOTYPE(int insert_id_rec, (id_rec **root, id_rec *new_id));
+_PROTOTYPE(void init_tree, (void));
+_PROTOTYPE(int lookup, (char *name, int namekind));
+_PROTOTYPE(char *bc_malloc, (int));
+_PROTOTYPE(void out_of_memory, (void));
+_PROTOTYPE(void welcome, (void));
+_PROTOTYPE(void warranty, (char *));
+_PROTOTYPE(void limits, (void));
+_PROTOTYPE(void yyerror, (char *str ,...));
+_PROTOTYPE(void warn, (char *mesg ,...));
+_PROTOTYPE(void rt_error, (char *mesg ,...));
+_PROTOTYPE(void rt_warn, (char *mesg ,...));
+
+/* From load.c */
+_PROTOTYPE(void init_load, (void));
+_PROTOTYPE(void addbyte, (int byte));
+_PROTOTYPE(void def_label, (long lab));
+_PROTOTYPE(long long_val, (char **str));
+_PROTOTYPE(void load_code, (char *code));
+
+/* From main.c */
+_PROTOTYPE(int main, (int argc , char *argv []));
+_PROTOTYPE(int open_new_file, (void));
+_PROTOTYPE(void new_yy_file, (FILE *file));
+_PROTOTYPE(void use_quit, (int));
+
+/* From number.c */
+_PROTOTYPE(void free_num, (bc_num *num));
+_PROTOTYPE(bc_num new_num, (int length, int scale));
+_PROTOTYPE(void init_numbers, (void));
+_PROTOTYPE(bc_num copy_num, (bc_num num));
+_PROTOTYPE(void init_num, (bc_num *num));
+_PROTOTYPE(void str2num, (bc_num *num, char *str, int scale));
+_PROTOTYPE(char *num2str, (bc_num num));
+_PROTOTYPE(void int2num, (bc_num *num, int val));
+_PROTOTYPE(long num2long, (bc_num num));
+_PROTOTYPE(int bc_compare, (bc_num n1, bc_num n2));
+_PROTOTYPE(char is_zero, (bc_num num));
+_PROTOTYPE(char is_neg, (bc_num num));
+_PROTOTYPE(void bc_add, (bc_num n1, bc_num n2, bc_num *result));
+_PROTOTYPE(void bc_sub, (bc_num n1, bc_num n2, bc_num *result));
+_PROTOTYPE(void bc_multiply, (bc_num n1, bc_num n2, bc_num *prod, int scale));
+_PROTOTYPE(int bc_divide, (bc_num n1, bc_num n2, bc_num *quot, int scale));
+_PROTOTYPE(int bc_modulo, (bc_num num1, bc_num num2, bc_num *result, int scale));
+_PROTOTYPE(void bc_raise, (bc_num num1, bc_num num2, bc_num *result, int scale));
+_PROTOTYPE(int bc_sqrt, (bc_num *num, int scale));
+_PROTOTYPE(void out_long, (long val, int size, int space,
+ void (*out_char)(int)));
+_PROTOTYPE(void out_num, (bc_num num, int o_base, void (* out_char)(int)));
+
+
+/* From storage.c */
+_PROTOTYPE(void init_storage, (void));
+_PROTOTYPE(void more_functions, (void));
+_PROTOTYPE(void more_variables, (void));
+_PROTOTYPE(void more_arrays, (void));
+_PROTOTYPE(void clear_func, (int func ));
+_PROTOTYPE(int fpop, (void));
+_PROTOTYPE(void fpush, (int val ));
+_PROTOTYPE(void pop, (void));
+_PROTOTYPE(void push_copy, (bc_num num ));
+_PROTOTYPE(void push_num, (bc_num num ));
+_PROTOTYPE(char check_stack, (int depth ));
+_PROTOTYPE(bc_var *get_var, (int var_name ));
+_PROTOTYPE(bc_num *get_array_num, (int var_index, long index ));
+_PROTOTYPE(void store_var, (int var_name ));
+_PROTOTYPE(void store_array, (int var_name ));
+_PROTOTYPE(void load_var, (int var_name ));
+_PROTOTYPE(void load_array, (int var_name ));
+_PROTOTYPE(void decr_var, (int var_name ));
+_PROTOTYPE(void decr_array, (int var_name ));
+_PROTOTYPE(void incr_var, (int var_name ));
+_PROTOTYPE(void incr_array, (int var_name ));
+_PROTOTYPE(void auto_var, (int name ));
+_PROTOTYPE(void free_a_tree, (bc_array_node *root, int depth ));
+_PROTOTYPE(void pop_vars, (arg_list *list ));
+_PROTOTYPE(void process_params, (program_counter *pc, int func ));
+
+/* For the scanner and parser.... */
+_PROTOTYPE(int yyparse, (void));
+_PROTOTYPE(int yylex, (void));
+
+/* Other things... */
+_PROTOTYPE (int getopt, (int, char *[], CONST char *));
+
diff --git a/gnu/usr.bin/bc/scan.c b/gnu/usr.bin/bc/scan.c
new file mode 100644
index 0000000..6bff451
--- /dev/null
+++ b/gnu/usr.bin/bc/scan.c
@@ -0,0 +1,1368 @@
+/* A lexical scanner generated by flex */
+
+/* scanner skeleton version:
+ * $Header: /home/ncvs/src/gnu/usr.bin/bc/scan.c,v 1.1.1.1 1993/06/19 00:26:18 paul Exp $
+ */
+
+#define FLEX_SCANNER
+
+#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 <osfcn.h>
+
+/* use prototypes in function declarations */
+#define YY_USE_PROTOS
+
+/* the "const" storage-class-modifier is valid */
+#define YY_USE_CONST
+
+#else /* ! __cplusplus */
+
+#ifdef __STDC__
+
+#ifdef __GNUC__
+#include <stddef.h>
+void *malloc( size_t );
+void free( void* );
+#else
+#include <stdlib.h>
+#endif /* __GNUC__ */
+
+#define YY_USE_PROTOS
+#define YY_USE_CONST
+
+#endif /* __STDC__ */
+#endif /* ! __cplusplus */
+
+
+#ifdef __TURBOC__
+#define YY_USE_CONST
+#endif
+
+
+#ifndef YY_USE_CONST
+#define const
+#endif
+
+
+#ifdef YY_USE_PROTOS
+#define YY_PROTO(proto) proto
+#else
+#define YY_PROTO(proto) ()
+/* we can't get here if it's an ANSI C compiler, or a C++ compiler,
+ * so it's got to be a K&R compiler, and therefore there's no standard
+ * place from which to include these definitions
+ */
+/* char *malloc();
+int free(); */
+int read();
+#endif
+
+
+/* amount of stuff to slurp up with each read */
+#ifndef YY_READ_BUF_SIZE
+#define YY_READ_BUF_SIZE 8192
+#endif
+
+/* returned upon end-of-file */
+#define YY_END_TOK 0
+
+/* copy whatever the last rule matched to the standard output */
+
+/* cast to (char *) is because for 8-bit chars, yytext is (unsigned char *) */
+/* this used to be an fputs(), but since the string might contain NUL's,
+ * we now use fwrite()
+ */
+#define ECHO (void) fwrite( (char *) yytext, yyleng, 1, yyout )
+
+/* gets input and stuffs it into "buf". number of characters read, or YY_NULL,
+ * is returned in "result".
+ */
+#define YY_INPUT(buf,result,max_size) \
+ if ( (result = read( fileno(yyin), (char *) buf, max_size )) < 0 ) \
+ YY_FATAL_ERROR( "read() in flex scanner failed" );
+#define YY_NULL 0
+
+/* 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.
+ */
+#define yyterminate() return ( YY_NULL )
+
+/* report a fatal error */
+
+/* The funky do-while is used to turn this macro definition into
+ * a single C statement (which needs a semi-colon terminator).
+ * This avoids problems with code like:
+ *
+ * if ( something_happens )
+ * YY_FATAL_ERROR( "oops, the something happened" );
+ * else
+ * everything_okay();
+ *
+ * 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 YY_FATAL_ERROR() call.
+ */
+
+#define YY_FATAL_ERROR(msg) \
+ do \
+ { \
+ (void) fputs( msg, stderr ); \
+ (void) putc( '\n', stderr ); \
+ exit( 1 ); \
+ } \
+ while ( 0 )
+
+/* default yywrap function - always treat EOF as an EOF */
+#define yywrap() 1
+
+/* 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 *
+
+/* 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 \
+ do \
+ { \
+ yy_init_buffer( yy_current_buffer, yyin ); \
+ yy_load_buffer_state(); \
+ } \
+ while ( 0 )
+
+/* default declaration of generated scanner - a define so the user can
+ * easily add parameters
+ */
+#define YY_DECL int yylex YY_PROTO(( void ))
+
+/* code executed at the end of each rule */
+#define YY_BREAK break;
+
+#define YY_END_OF_BUFFER_CHAR 0
+
+#ifndef YY_BUF_SIZE
+#define YY_BUF_SIZE (YY_READ_BUF_SIZE * 2) /* size of default input buffer */
+#endif
+
+typedef struct yy_buffer_state *YY_BUFFER_STATE;
+
+#define YY_CHAR unsigned char
+# line 1 "scan.l"
+#define INITIAL 0
+# line 2 "scan.l"
+/* scan.l: the (f)lex description file for the scanner. */
+
+/* This file is part of bc written for MINIX.
+ Copyright (C) 1991, 1992 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License , or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; see the file COPYING. If not, write to
+ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ You may contact the author by:
+ e-mail: phil@cs.wwu.edu
+ us-mail: Philip A. Nelson
+ Computer Science Department, 9062
+ Western Washington University
+ Bellingham, WA 98226-9062
+
+*************************************************************************/
+
+#include "bcdefs.h"
+#include "y.tab.h"
+#include "global.h"
+#include "proto.h"
+
+/* Using flex, we can ask for a smaller input buffer. With lex, this
+ does nothing! */
+
+#ifdef SMALL_BUF
+#undef YY_READ_BUF_SIZE
+#define YY_READ_BUF_SIZE 512
+#endif
+
+/* We want to define our own yywrap. */
+#undef yywrap
+_PROTOTYPE(int yywrap, (void));
+
+/* MINIX returns from read with < 0 if SIGINT is encountered.
+ In flex, we can redefine YY_INPUT to the following. In lex, this
+ does nothing! */
+#include <errno.h>
+#undef YY_INPUT
+#define YY_INPUT(buf,result,max_size) \
+ while ( (result = read( fileno(yyin), (char *) buf, max_size )) < 0 ) \
+ if (errno != EINTR) \
+ YY_FATAL_ERROR( "read() in flex scanner failed" );
+
+# line 60 "scan.l"
+
+/* done after the current pattern has been matched and before the
+ * corresponding action - sets up yytext
+ */
+#define YY_DO_BEFORE_ACTION \
+ yytext = yy_bp; \
+ yyleng = yy_cp - yy_bp; \
+ yy_hold_char = *yy_cp; \
+ *yy_cp = '\0'; \
+ yy_c_buf_p = yy_cp;
+
+#define EOB_ACT_CONTINUE_SCAN 0
+#define EOB_ACT_END_OF_FILE 1
+#define EOB_ACT_LAST_MATCH 2
+
+/* 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_c_buf_p = yy_cp = yy_bp + n; \
+ YY_DO_BEFORE_ACTION; /* set up yytext again */ \
+ } \
+ while ( 0 )
+
+#define unput(c) yyunput( c, yytext )
+
+
+struct yy_buffer_state
+ {
+ FILE *yy_input_file;
+
+ YY_CHAR *yy_ch_buf; /* input buffer */
+ YY_CHAR *yy_buf_pos; /* current position in input buffer */
+
+ /* size of input buffer in bytes, not including room for EOB characters*/
+ int yy_buf_size;
+
+ /* number of characters read into yy_ch_buf, not including EOB characters */
+ int yy_n_chars;
+
+ int yy_eof_status; /* whether we've seen an EOF on this buffer */
+#define EOF_NOT_SEEN 0
+ /* "pending" happens when the EOF has been seen but there's still
+ * some text process
+ */
+#define EOF_PENDING 1
+#define EOF_DONE 2
+ };
+
+static YY_BUFFER_STATE yy_current_buffer;
+
+/* 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 YY_CHAR yy_hold_char;
+
+static int yy_n_chars; /* number of characters read into yy_ch_buf */
+
+
+
+#ifndef YY_USER_ACTION
+#define YY_USER_ACTION
+#endif
+
+#ifndef YY_USER_INIT
+#define YY_USER_INIT
+#endif
+
+extern YY_CHAR *yytext;
+extern int yyleng;
+extern FILE *yyin, *yyout;
+
+YY_CHAR *yytext;
+int yyleng;
+
+FILE *yyin = (FILE *) 0, *yyout = (FILE *) 0;
+
+#define YY_END_OF_BUFFER 40
+typedef int yy_state_type;
+static const short int yy_accept[144] =
+ { 0,
+ 0, 0, 40, 38, 33, 31, 25, 38, 26, 38,
+ 22, 26, 22, 22, 38, 26, 37, 29, 27, 29,
+ 38, 22, 35, 35, 35, 35, 35, 35, 35, 35,
+ 35, 35, 35, 35, 35, 35, 35, 35, 38, 33,
+ 29, 0, 36, 27, 23, 30, 37, 0, 34, 37,
+ 37, 0, 28, 32, 35, 35, 35, 35, 35, 35,
+ 35, 35, 35, 7, 35, 35, 35, 35, 35, 35,
+ 35, 35, 35, 35, 35, 24, 37, 0, 0, 37,
+ 0, 35, 35, 35, 35, 35, 6, 35, 35, 35,
+ 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+
+ 35, 13, 35, 35, 35, 14, 16, 35, 17, 35,
+ 35, 35, 35, 3, 15, 35, 35, 9, 35, 35,
+ 2, 35, 35, 11, 35, 35, 12, 20, 35, 10,
+ 35, 8, 35, 1, 4, 21, 5, 35, 35, 35,
+ 19, 18, 0
+ } ;
+
+static const YY_CHAR yy_ec[256] =
+ { 0,
+ 1, 1, 1, 1, 1, 1, 1, 1, 2, 3,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 2, 4, 5, 1, 1, 6, 7, 1, 8,
+ 9, 10, 11, 12, 13, 14, 15, 16, 16, 16,
+ 16, 16, 16, 16, 16, 16, 16, 1, 17, 18,
+ 19, 20, 1, 1, 21, 21, 21, 21, 21, 21,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 22, 23, 24, 25, 26, 1, 27, 28, 29, 30,
+
+ 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
+ 41, 42, 43, 44, 45, 46, 47, 36, 48, 36,
+ 49, 36, 50, 51, 52, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 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 const YY_CHAR yy_meta[53] =
+ { 0,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 2, 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, 1,
+ 1, 1
+ } ;
+
+static const short int yy_base[146] =
+ { 0,
+ 0, 0, 193, 194, 190, 194, 172, 185, 170, 181,
+ 194, 168, 42, 41, 41, 46, 52, 167, 61, 166,
+ 181, 164, 135, 137, 139, 148, 140, 136, 0, 149,
+ 27, 50, 147, 130, 126, 141, 40, 36, 120, 168,
+ 194, 164, 194, 194, 194, 194, 66, 165, 194, 72,
+ 76, 164, 194, 194, 0, 120, 134, 124, 131, 117,
+ 117, 122, 132, 0, 113, 117, 117, 128, 119, 118,
+ 52, 125, 107, 106, 114, 194, 80, 145, 84, 88,
+ 144, 105, 118, 98, 108, 111, 0, 95, 95, 93,
+ 105, 102, 91, 95, 88, 103, 85, 93, 84, 85,
+
+ 90, 0, 90, 91, 85, 0, 0, 93, 0, 77,
+ 76, 90, 74, 0, 0, 75, 87, 0, 90, 85,
+ 0, 75, 83, 0, 76, 63, 0, 0, 66, 0,
+ 62, 0, 47, 0, 0, 0, 0, 45, 53, 29,
+ 0, 0, 194, 111, 56
+ } ;
+
+static const short int yy_def[146] =
+ { 0,
+ 143, 1, 143, 143, 143, 143, 143, 144, 143, 143,
+ 143, 143, 143, 143, 143, 143, 143, 143, 143, 143,
+ 143, 143, 145, 145, 145, 145, 145, 145, 145, 145,
+ 145, 145, 145, 145, 145, 145, 145, 145, 143, 143,
+ 143, 144, 143, 143, 143, 143, 143, 143, 143, 143,
+ 143, 143, 143, 143, 145, 145, 145, 145, 145, 145,
+ 145, 145, 145, 145, 145, 145, 145, 145, 145, 145,
+ 145, 145, 145, 145, 145, 143, 143, 143, 143, 143,
+ 143, 145, 145, 145, 145, 145, 145, 145, 145, 145,
+ 145, 145, 145, 145, 145, 145, 145, 145, 145, 145,
+
+ 145, 145, 145, 145, 145, 145, 145, 145, 145, 145,
+ 145, 145, 145, 145, 145, 145, 145, 145, 145, 145,
+ 145, 145, 145, 145, 145, 145, 145, 145, 145, 145,
+ 145, 145, 145, 145, 145, 145, 145, 145, 145, 145,
+ 145, 145, 0, 143, 143
+ } ;
+
+static const short int yy_nxt[247] =
+ { 0,
+ 4, 5, 6, 7, 8, 9, 10, 11, 11, 12,
+ 13, 11, 14, 15, 16, 17, 11, 18, 19, 20,
+ 17, 11, 21, 11, 22, 4, 23, 24, 25, 26,
+ 27, 28, 29, 30, 31, 29, 29, 32, 29, 29,
+ 33, 34, 35, 36, 37, 29, 29, 38, 29, 11,
+ 39, 11, 46, 46, 63, 49, 47, 55, 64, 44,
+ 44, 47, 74, 48, 44, 50, 53, 51, 72, 75,
+ 53, 53, 51, 53, 52, 53, 65, 142, 96, 41,
+ 66, 77, 73, 141, 67, 53, 77, 80, 78, 50,
+ 140, 51, 80, 139, 81, 77, 51, 97, 52, 47,
+
+ 77, 138, 78, 80, 47, 137, 48, 136, 80, 135,
+ 81, 42, 42, 134, 133, 132, 131, 130, 129, 128,
+ 127, 126, 125, 124, 123, 122, 121, 120, 119, 118,
+ 117, 116, 115, 114, 113, 112, 111, 110, 109, 108,
+ 107, 106, 105, 104, 103, 102, 80, 77, 101, 100,
+ 99, 98, 95, 94, 93, 92, 91, 90, 89, 88,
+ 87, 86, 85, 84, 83, 82, 51, 79, 43, 40,
+ 76, 71, 70, 69, 68, 62, 61, 60, 59, 58,
+ 57, 56, 44, 54, 41, 41, 44, 45, 44, 43,
+ 41, 40, 143, 3, 143, 143, 143, 143, 143, 143,
+
+ 143, 143, 143, 143, 143, 143, 143, 143, 143, 143,
+ 143, 143, 143, 143, 143, 143, 143, 143, 143, 143,
+ 143, 143, 143, 143, 143, 143, 143, 143, 143, 143,
+ 143, 143, 143, 143, 143, 143, 143, 143, 143, 143,
+ 143, 143, 143, 143, 143, 143
+ } ;
+
+static const short int yy_chk[247] =
+ { 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, 13, 14, 31, 16, 15, 145, 31, 14,
+ 13, 15, 38, 15, 16, 17, 19, 17, 37, 38,
+ 19, 19, 17, 19, 17, 19, 32, 140, 71, 19,
+ 32, 47, 37, 139, 32, 19, 47, 50, 47, 51,
+ 138, 51, 50, 133, 50, 77, 51, 71, 51, 79,
+
+ 77, 131, 77, 80, 79, 129, 79, 126, 80, 125,
+ 80, 144, 144, 123, 122, 120, 119, 117, 116, 113,
+ 112, 111, 110, 108, 105, 104, 103, 101, 100, 99,
+ 98, 97, 96, 95, 94, 93, 92, 91, 90, 89,
+ 88, 86, 85, 84, 83, 82, 81, 78, 75, 74,
+ 73, 72, 70, 69, 68, 67, 66, 65, 63, 62,
+ 61, 60, 59, 58, 57, 56, 52, 48, 42, 40,
+ 39, 36, 35, 34, 33, 30, 28, 27, 26, 25,
+ 24, 23, 22, 21, 20, 18, 12, 10, 9, 8,
+ 7, 5, 3, 143, 143, 143, 143, 143, 143, 143,
+
+ 143, 143, 143, 143, 143, 143, 143, 143, 143, 143,
+ 143, 143, 143, 143, 143, 143, 143, 143, 143, 143,
+ 143, 143, 143, 143, 143, 143, 143, 143, 143, 143,
+ 143, 143, 143, 143, 143, 143, 143, 143, 143, 143,
+ 143, 143, 143, 143, 143, 143
+ } ;
+
+static yy_state_type yy_last_accepting_state;
+static YY_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
+
+/* these variables are all declared out here so that section 3 code can
+ * manipulate them
+ */
+/* points to current character in buffer */
+static YY_CHAR *yy_c_buf_p = (YY_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;
+
+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 yyunput YY_PROTO(( YY_CHAR c, YY_CHAR *buf_ptr ));
+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 ));
+
+#define yy_new_buffer yy_create_buffer
+
+#ifdef __cplusplus
+static int yyinput YY_PROTO(( void ));
+#else
+static int input YY_PROTO(( void ));
+#endif
+
+YY_DECL
+ {
+ register yy_state_type yy_current_state;
+ register YY_CHAR *yy_cp, *yy_bp;
+ register int yy_act;
+
+
+
+ if ( yy_init )
+ {
+ YY_USER_INIT;
+
+ if ( ! yy_start )
+ yy_start = 1; /* first start state */
+
+ if ( ! yyin )
+ yyin = stdin;
+
+ if ( ! yyout )
+ yyout = stdout;
+
+ if ( yy_current_buffer )
+ yy_init_buffer( yy_current_buffer, yyin );
+ else
+ yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE );
+
+ yy_load_buffer_state();
+
+ yy_init = 0;
+ }
+
+ 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_match:
+ do
+ {
+ register YY_CHAR yy_c = yy_ec[*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 = yy_def[yy_current_state];
+ if ( yy_current_state >= 144 )
+ yy_c = yy_meta[yy_c];
+ }
+ yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c];
+ ++yy_cp;
+ }
+ while ( yy_base[yy_current_state] != 194 );
+
+yy_find_action:
+ yy_act = yy_accept[yy_current_state];
+
+ YY_DO_BEFORE_ACTION;
+ YY_USER_ACTION;
+
+do_action: /* this label is used only to access EOF actions */
+
+
+ switch ( yy_act )
+ {
+ case 0: /* must backtrack */
+ /* 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:
+# line 61 "scan.l"
+return(Define);
+ YY_BREAK
+case 2:
+# line 62 "scan.l"
+return(Break);
+ YY_BREAK
+case 3:
+# line 63 "scan.l"
+return(Quit);
+ YY_BREAK
+case 4:
+# line 64 "scan.l"
+return(Length);
+ YY_BREAK
+case 5:
+# line 65 "scan.l"
+return(Return);
+ YY_BREAK
+case 6:
+# line 66 "scan.l"
+return(For);
+ YY_BREAK
+case 7:
+# line 67 "scan.l"
+return(If);
+ YY_BREAK
+case 8:
+# line 68 "scan.l"
+return(While);
+ YY_BREAK
+case 9:
+# line 69 "scan.l"
+return(Sqrt);
+ YY_BREAK
+case 10:
+# line 70 "scan.l"
+return(Scale);
+ YY_BREAK
+case 11:
+# line 71 "scan.l"
+return(Ibase);
+ YY_BREAK
+case 12:
+# line 72 "scan.l"
+return(Obase);
+ YY_BREAK
+case 13:
+# line 73 "scan.l"
+return(Auto);
+ YY_BREAK
+case 14:
+# line 74 "scan.l"
+return(Else);
+ YY_BREAK
+case 15:
+# line 75 "scan.l"
+return(Read);
+ YY_BREAK
+case 16:
+# line 76 "scan.l"
+return(Halt);
+ YY_BREAK
+case 17:
+# line 77 "scan.l"
+return(Last);
+ YY_BREAK
+case 18:
+# line 78 "scan.l"
+return(Warranty);
+ YY_BREAK
+case 19:
+# line 79 "scan.l"
+return(Continue);
+ YY_BREAK
+case 20:
+# line 80 "scan.l"
+return(Print);
+ YY_BREAK
+case 21:
+# line 81 "scan.l"
+return(Limits);
+ YY_BREAK
+case 22:
+# line 82 "scan.l"
+{ yylval.c_value = yytext[0];
+ return((int)yytext[0]); }
+ YY_BREAK
+case 23:
+# line 84 "scan.l"
+{ return(AND); }
+ YY_BREAK
+case 24:
+# line 85 "scan.l"
+{ return(OR); }
+ YY_BREAK
+case 25:
+# line 86 "scan.l"
+{ return(NOT); }
+ YY_BREAK
+case 26:
+# line 87 "scan.l"
+{ yylval.c_value = yytext[0]; return(MUL_OP); }
+ YY_BREAK
+case 27:
+# line 88 "scan.l"
+{ yylval.c_value = yytext[0]; return(ASSIGN_OP); }
+ YY_BREAK
+case 28:
+# line 89 "scan.l"
+{
+#ifdef OLD_EQ_OP
+ char warn_save;
+ warn_save = warn_not_std;
+ warn_not_std = TRUE;
+ warn ("Old fashioned =<op>");
+ warn_not_std = warn_save;
+ yylval.c_value = yytext[1];
+#else
+ yylval.c_value = '=';
+ yyless (1);
+#endif
+ return(ASSIGN_OP);
+ }
+ YY_BREAK
+case 29:
+# line 103 "scan.l"
+{ yylval.s_value = strcopyof(yytext); return(REL_OP); }
+ YY_BREAK
+case 30:
+# line 104 "scan.l"
+{ yylval.c_value = yytext[0]; return(INCR_DECR); }
+ YY_BREAK
+case 31:
+# line 105 "scan.l"
+{ line_no++; return(NEWLINE); }
+ YY_BREAK
+case 32:
+# line 106 "scan.l"
+{ line_no++; /* ignore a "quoted" newline */ }
+ YY_BREAK
+case 33:
+# line 107 "scan.l"
+{ /* ignore spaces and tabs */ }
+ YY_BREAK
+case 34:
+# line 108 "scan.l"
+{
+ int c;
+
+ for (;;)
+ {
+ while ( ((c=input()) != '*') && (c != EOF))
+ /* eat it */
+ if (c == '\n') line_no++;
+ if (c == '*')
+ {
+ while ( (c=input()) == '*') /* eat it*/;
+ if (c == '/') break; /* at end of comment */
+ if (c == '\n') line_no++;
+ }
+ if (c == EOF)
+ {
+ fprintf (stderr,"EOF encountered in a comment.\n");
+ break;
+ }
+ }
+ }
+ YY_BREAK
+case 35:
+# line 129 "scan.l"
+{ yylval.s_value = strcopyof(yytext); return(NAME); }
+ YY_BREAK
+case 36:
+# line 130 "scan.l"
+{
+ unsigned char *look;
+ int count = 0;
+ yylval.s_value = strcopyof(yytext);
+ for (look = yytext; *look != 0; look++)
+ {
+ if (*look == '\n') line_no++;
+ if (*look == '"') count++;
+ }
+ if (count != 2) yyerror ("NUL character in string.");
+ return(STRING);
+ }
+ YY_BREAK
+case 37:
+# line 142 "scan.l"
+{
+ unsigned char *src, *dst;
+ int len;
+ /* remove a trailing decimal point. */
+ len = strlen(yytext);
+ if (yytext[len-1] == '.')
+ yytext[len-1] = 0;
+ /* remove leading zeros. */
+ src = yytext;
+ dst = yytext;
+ while (*src == '0') src++;
+ if (*src == 0) src--;
+ /* Copy strings removing the newlines. */
+ while (*src != 0)
+ {
+ if (*src == '\\')
+ {
+ src++; src++;
+ line_no++;
+ }
+ else
+ *dst++ = *src++;
+ }
+ *dst = 0;
+ yylval.s_value = strcopyof(yytext);
+ return(NUMBER);
+ }
+ YY_BREAK
+case 38:
+# line 169 "scan.l"
+{
+ if (yytext[0] < ' ')
+ yyerror ("illegal character: ^%c",yytext[0] + '@');
+ else
+ if (yytext[0] > '~')
+ yyerror ("illegal character: \\%3d", (int) yytext[0]);
+ else
+ yyerror ("illegal character: %s",yytext);
+ }
+ YY_BREAK
+case 39:
+# line 178 "scan.l"
+ECHO;
+ YY_BREAK
+case YY_STATE_EOF(INITIAL):
+ yyterminate();
+
+ case YY_END_OF_BUFFER:
+ {
+ /* amount of text matched not including the EOB char */
+ int yy_amount_of_matched_text = yy_cp - yytext - 1;
+
+ /* undo the effects of YY_DO_BEFORE_ACTION */
+ *yy_cp = yy_hold_char;
+
+ /* 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 yyinput().
+ */
+ 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 + 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 + 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
+ {
+ 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 + YY_MORE_ADJ;
+
+ yy_act = YY_STATE_EOF((yy_start - 1) / 2);
+ 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 + yy_amount_of_matched_text;
+
+ yy_current_state = yy_get_previous_state();
+
+ yy_cp = yy_c_buf_p;
+ yy_bp = yytext + 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 + YY_MORE_ADJ;
+ goto yy_find_action;
+ }
+ break;
+ }
+
+ default:
+#ifdef FLEX_DEBUG
+ printf( "action # %d\n", yy_act );
+#endif
+ YY_FATAL_ERROR(
+ "fatal flex scanner internal error--no action found" );
+ }
+ }
+ }
+
+
+/* yy_get_next_buffer - try to read in a new buffer
+ *
+ * synopsis
+ * int yy_get_next_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 YY_CHAR *dest = yy_current_buffer->yy_ch_buf;
+ register YY_CHAR *source = yytext - 1; /* copy prev. char, too */
+ 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" );
+
+ /* try to read more data */
+
+ /* first move last chars to start of buffer */
+ number_to_move = yy_c_buf_p - yytext;
+
+ for ( i = 0; i < number_to_move; ++i )
+ *(dest++) = *(source++);
+
+ if ( yy_current_buffer->yy_eof_status != EOF_NOT_SEEN )
+ /* don't do the read, it's not guaranteed to return an EOF,
+ * just force an EOF
+ */
+ yy_n_chars = 0;
+
+ else
+ {
+ int num_to_read = yy_current_buffer->yy_buf_size - number_to_move - 1;
+
+ if ( num_to_read > YY_READ_BUF_SIZE )
+ num_to_read = YY_READ_BUF_SIZE;
+
+ else if ( num_to_read <= 0 )
+ YY_FATAL_ERROR( "fatal error - scanner input buffer overflow" );
+
+ /* read in more data */
+ YY_INPUT( (&yy_current_buffer->yy_ch_buf[number_to_move]),
+ yy_n_chars, num_to_read );
+ }
+
+ if ( yy_n_chars == 0 )
+ {
+ if ( number_to_move == 1 )
+ {
+ ret_val = EOB_ACT_END_OF_FILE;
+ yy_current_buffer->yy_eof_status = EOF_DONE;
+ }
+
+ else
+ {
+ ret_val = EOB_ACT_LAST_MATCH;
+ yy_current_buffer->yy_eof_status = 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 begins at the second character in yy_ch_buf; the first
+ * character is the one which preceded it before reading in the latest
+ * buffer; it needs to be kept around in case it's a newline, so
+ * yy_get_previous_state() will have with '^' rules active
+ */
+
+ yytext = &yy_current_buffer->yy_ch_buf[1];
+
+ return ( ret_val );
+ }
+
+
+/* yy_get_previous_state - get the state just before the EOB char was reached
+ *
+ * synopsis
+ * yy_state_type yy_get_previous_state();
+ */
+
+static yy_state_type yy_get_previous_state()
+
+ {
+ register yy_state_type yy_current_state;
+ register YY_CHAR *yy_cp;
+
+ yy_current_state = yy_start;
+
+ for ( yy_cp = yytext + YY_MORE_ADJ; yy_cp < yy_c_buf_p; ++yy_cp )
+ {
+ register YY_CHAR yy_c = (*yy_cp ? yy_ec[*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 = yy_def[yy_current_state];
+ if ( yy_current_state >= 144 )
+ yy_c = yy_meta[yy_c];
+ }
+ yy_current_state = yy_nxt[yy_base[yy_current_state] + 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( register yy_state_type yy_current_state )
+#else
+static yy_state_type yy_try_NUL_trans( yy_current_state )
+register yy_state_type yy_current_state;
+#endif
+
+ {
+ register int yy_is_jam;
+ register YY_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 = yy_def[yy_current_state];
+ if ( yy_current_state >= 144 )
+ yy_c = yy_meta[yy_c];
+ }
+ yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c];
+ yy_is_jam = (yy_current_state == 143);
+
+ return ( yy_is_jam ? 0 : yy_current_state );
+ }
+
+
+#ifdef YY_USE_PROTOS
+static void yyunput( YY_CHAR c, register YY_CHAR *yy_bp )
+#else
+static void yyunput( c, yy_bp )
+YY_CHAR c;
+register YY_CHAR *yy_bp;
+#endif
+
+ {
+ register YY_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 */
+ register int number_to_move = yy_n_chars + 2; /* +2 for EOB chars */
+ register YY_CHAR *dest =
+ &yy_current_buffer->yy_ch_buf[yy_current_buffer->yy_buf_size + 2];
+ register YY_CHAR *source =
+ &yy_current_buffer->yy_ch_buf[number_to_move];
+
+ while ( source > yy_current_buffer->yy_ch_buf )
+ *--dest = *--source;
+
+ yy_cp += dest - source;
+ yy_bp += dest - source;
+ 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" );
+ }
+
+ if ( yy_cp > yy_bp && yy_cp[-1] == '\n' )
+ yy_cp[-2] = '\n';
+
+ *--yy_cp = c;
+
+ /* note: the formal parameter *must* be called "yy_bp" for this
+ * macro to now work correctly
+ */
+ YY_DO_BEFORE_ACTION; /* set up yytext again */
+ }
+
+
+#ifdef __cplusplus
+static int yyinput()
+#else
+static int input()
+#endif
+
+ {
+ int c;
+ YY_CHAR *yy_cp = yy_c_buf_p;
+
+ *yy_cp = 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 */
+ yytext = yy_c_buf_p;
+ ++yy_c_buf_p;
+
+ switch ( yy_get_next_buffer() )
+ {
+ case EOB_ACT_END_OF_FILE:
+ {
+ if ( yywrap() )
+ {
+ yy_c_buf_p = yytext + YY_MORE_ADJ;
+ return ( EOF );
+ }
+
+ YY_NEW_FILE;
+
+#ifdef __cplusplus
+ return ( yyinput() );
+#else
+ return ( input() );
+#endif
+ }
+ break;
+
+ case EOB_ACT_CONTINUE_SCAN:
+ yy_c_buf_p = yytext + YY_MORE_ADJ;
+ break;
+
+ case EOB_ACT_LAST_MATCH:
+#ifdef __cplusplus
+ YY_FATAL_ERROR( "unexpected last match in yyinput()" );
+#else
+ YY_FATAL_ERROR( "unexpected last match in input()" );
+#endif
+ }
+ }
+ }
+
+ c = *yy_c_buf_p;
+ yy_hold_char = *++yy_c_buf_p;
+
+ return ( c );
+ }
+
+
+#ifdef YY_USE_PROTOS
+void yyrestart( FILE *input_file )
+#else
+void yyrestart( input_file )
+FILE *input_file;
+#endif
+
+ {
+ 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 = 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) malloc( 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 = (YY_CHAR *) malloc( (unsigned) (b->yy_buf_size + 2) );
+
+ if ( ! b->yy_ch_buf )
+ YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" );
+
+ 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 == yy_current_buffer )
+ yy_current_buffer = (YY_BUFFER_STATE) 0;
+
+ free( (char *) b->yy_ch_buf );
+ free( (char *) b );
+ }
+
+
+#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
+
+ {
+ b->yy_input_file = file;
+
+ /* we put in the '\n' and start reading from [1] so that an
+ * initial match-at-newline will be true.
+ */
+
+ b->yy_ch_buf[0] = '\n';
+ b->yy_n_chars = 1;
+
+ /* 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[1] = YY_END_OF_BUFFER_CHAR;
+ b->yy_ch_buf[2] = YY_END_OF_BUFFER_CHAR;
+
+ b->yy_buf_pos = &b->yy_ch_buf[1];
+
+ b->yy_eof_status = EOF_NOT_SEEN;
+ }
+# line 178 "scan.l"
+
+
+
+
+/* This is the way to get multiple files input into lex. */
+
+int
+yywrap()
+{
+ if (!open_new_file ()) return (1); /* EOF on standard in. */
+ return (0); /* We have more input. */
+}
diff --git a/gnu/usr.bin/bc/storage.c b/gnu/usr.bin/bc/storage.c
new file mode 100644
index 0000000..18ddb93
--- /dev/null
+++ b/gnu/usr.bin/bc/storage.c
@@ -0,0 +1,967 @@
+/* storage.c: Code and data storage manipulations. This includes labels. */
+
+/* This file is part of bc written for MINIX.
+ Copyright (C) 1991, 1992 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License , or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; see the file COPYING. If not, write to
+ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ You may contact the author by:
+ e-mail: phil@cs.wwu.edu
+ us-mail: Philip A. Nelson
+ Computer Science Department, 9062
+ Western Washington University
+ Bellingham, WA 98226-9062
+
+*************************************************************************/
+
+#include "bcdefs.h"
+#include "global.h"
+#include "proto.h"
+
+
+/* Initialize the storage at the beginning of the run. */
+
+void
+init_storage ()
+{
+
+ /* Functions: we start with none and ask for more. */
+ f_count = 0;
+ more_functions ();
+ f_names[0] = "(main)";
+
+ /* Variables. */
+ v_count = 0;
+ more_variables ();
+
+ /* Arrays. */
+ a_count = 0;
+ more_arrays ();
+
+ /* Other things... */
+ ex_stack = NULL;
+ fn_stack = NULL;
+ i_base = 10;
+ o_base = 10;
+ scale = 0;
+ c_code = FALSE;
+ init_numbers();
+}
+
+/* Three functions for increasing the number of functions, variables, or
+ arrays that are needed. This adds another 32 of the requested object. */
+
+void
+more_functions (VOID)
+{
+ int old_count;
+ int indx1, indx2;
+ bc_function *old_f;
+ bc_function *f;
+ char **old_names;
+
+ /* Save old information. */
+ old_count = f_count;
+ old_f = functions;
+ old_names = f_names;
+
+ /* Add a fixed amount and allocate new space. */
+ f_count += STORE_INCR;
+ functions = (bc_function *) bc_malloc (f_count*sizeof (bc_function));
+ f_names = (char **) bc_malloc (f_count*sizeof (char *));
+
+ /* Copy old ones. */
+ for (indx1 = 0; indx1 < old_count; indx1++)
+ {
+ functions[indx1] = old_f[indx1];
+ f_names[indx1] = old_names[indx1];
+ }
+
+ /* Initialize the new ones. */
+ for (; indx1 < f_count; indx1++)
+ {
+ f = &functions[indx1];
+ f->f_defined = FALSE;
+ for (indx2 = 0; indx2 < BC_MAX_SEGS; indx2++)
+ f->f_body [indx2] = NULL;
+ f->f_code_size = 0;
+ f->f_label = NULL;
+ f->f_autos = NULL;
+ f->f_params = NULL;
+ }
+
+ /* Free the old elements. */
+ if (old_count != 0)
+ {
+ free (old_f);
+ free (old_names);
+ }
+}
+
+void
+more_variables ()
+{
+ int indx;
+ int old_count;
+ bc_var **old_var;
+ char **old_names;
+
+ /* Save the old values. */
+ old_count = v_count;
+ old_var = variables;
+ old_names = v_names;
+
+ /* Increment by a fixed amount and allocate. */
+ v_count += STORE_INCR;
+ variables = (bc_var **) bc_malloc (v_count*sizeof(bc_var *));
+ v_names = (char **) bc_malloc (v_count*sizeof(char *));
+
+ /* Copy the old variables. */
+ for (indx = 3; indx < old_count; indx++)
+ variables[indx] = old_var[indx];
+
+ /* Initialize the new elements. */
+ for (; indx < v_count; indx++)
+ variables[indx] = NULL;
+
+ /* Free the old elements. */
+ if (old_count != 0)
+ {
+ free (old_var);
+ free (old_names);
+ }
+}
+
+void
+more_arrays ()
+{
+ int indx;
+ int old_count;
+ bc_var_array **old_ary;
+ char **old_names;
+
+ /* Save the old values. */
+ old_count = a_count;
+ old_ary = arrays;
+ old_names = a_names;
+
+ /* Increment by a fixed amount and allocate. */
+ a_count += STORE_INCR;
+ arrays = (bc_var_array **) bc_malloc (a_count*sizeof(bc_var_array *));
+ a_names = (char **) bc_malloc (a_count*sizeof(char *));
+
+ /* Copy the old arrays. */
+ for (indx = 1; indx < old_count; indx++)
+ arrays[indx] = old_ary[indx];
+
+
+ /* Initialize the new elements. */
+ for (; indx < v_count; indx++)
+ arrays[indx] = NULL;
+
+ /* Free the old elements. */
+ if (old_count != 0)
+ {
+ free (old_ary);
+ free (old_names);
+ }
+}
+
+
+/* clear_func clears out function FUNC and makes it ready to redefine. */
+
+void
+clear_func (func)
+ char func;
+{
+ bc_function *f;
+ int indx;
+ bc_label_group *lg;
+
+ /* Set the pointer to the function. */
+ f = &functions[func];
+ f->f_defined = FALSE;
+
+ /* Clear the code segments. */
+ for (indx = 0; indx < BC_MAX_SEGS; indx++)
+ {
+ if (f->f_body[indx] != NULL)
+ {
+ free (f->f_body[indx]);
+ f->f_body[indx] = NULL;
+ }
+ }
+
+ f->f_code_size = 0;
+ if (f->f_autos != NULL)
+ {
+ free_args (f->f_autos);
+ f->f_autos = NULL;
+ }
+ if (f->f_params != NULL)
+ {
+ free_args (f->f_params);
+ f->f_params = NULL;
+ }
+ while (f->f_label != NULL)
+ {
+ lg = f->f_label->l_next;
+ free (f->f_label);
+ f->f_label = lg;
+ }
+}
+
+
+/* Pop the function execution stack and return the top. */
+
+int
+fpop()
+{
+ fstack_rec *temp;
+ int retval;
+
+ if (fn_stack != NULL)
+ {
+ temp = fn_stack;
+ fn_stack = temp->s_next;
+ retval = temp->s_val;
+ free (temp);
+ }
+ return (retval);
+}
+
+
+/* Push VAL on to the function stack. */
+
+void
+fpush (val)
+ int val;
+{
+ fstack_rec *temp;
+
+ temp = (fstack_rec *) bc_malloc (sizeof (fstack_rec));
+ temp->s_next = fn_stack;
+ temp->s_val = val;
+ fn_stack = temp;
+}
+
+
+/* Pop and discard the top element of the regular execution stack. */
+
+void
+pop ()
+{
+ estack_rec *temp;
+
+ if (ex_stack != NULL)
+ {
+ temp = ex_stack;
+ ex_stack = temp->s_next;
+ free_num (&temp->s_num);
+ free (temp);
+ }
+}
+
+
+/* Push a copy of NUM on to the regular execution stack. */
+
+void
+push_copy (num)
+ bc_num num;
+{
+ estack_rec *temp;
+
+ temp = (estack_rec *) bc_malloc (sizeof (estack_rec));
+ temp->s_num = copy_num (num);
+ temp->s_next = ex_stack;
+ ex_stack = temp;
+}
+
+
+/* Push NUM on to the regular execution stack. Do NOT push a copy. */
+
+void
+push_num (num)
+ bc_num num;
+{
+ estack_rec *temp;
+
+ temp = (estack_rec *) bc_malloc (sizeof (estack_rec));
+ temp->s_num = num;
+ temp->s_next = ex_stack;
+ ex_stack = temp;
+}
+
+
+/* Make sure the ex_stack has at least DEPTH elements on it.
+ Return TRUE if it has at least DEPTH elements, otherwise
+ return FALSE. */
+
+char
+check_stack (depth)
+ int depth;
+{
+ estack_rec *temp;
+
+ temp = ex_stack;
+ while ((temp != NULL) && (depth > 0))
+ {
+ temp = temp->s_next;
+ depth--;
+ }
+ if (depth > 0)
+ {
+ rt_error ("Stack error.");
+ return FALSE;
+ }
+ return TRUE;
+}
+
+
+/* The following routines manipulate simple variables and
+ array variables. */
+
+/* get_var returns a pointer to the variable VAR_NAME. If one does not
+ exist, one is created. */
+
+bc_var *
+get_var (var_name)
+ int var_name;
+{
+ bc_var *var_ptr;
+
+ var_ptr = variables[var_name];
+ if (var_ptr == NULL)
+ {
+ var_ptr = variables[var_name] = (bc_var *) bc_malloc (sizeof (bc_var));
+ init_num (&var_ptr->v_value);
+ }
+ return var_ptr;
+}
+
+
+/* get_array_num returns the address of the bc_num in the array
+ structure. If more structure is requried to get to the index,
+ this routine does the work to create that structure. VAR_INDEX
+ is a zero based index into the arrays storage array. INDEX is
+ the index into the bc array. */
+
+bc_num *
+get_array_num (var_index, index)
+ int var_index;
+ long index;
+{
+ bc_var_array *ary_ptr;
+ bc_array *a_var;
+ bc_array_node *temp;
+ int log, ix, ix1;
+ int sub [NODE_DEPTH];
+
+ /* Get the array entry. */
+ ary_ptr = arrays[var_index];
+ if (ary_ptr == NULL)
+ {
+ ary_ptr = arrays[var_index] =
+ (bc_var_array *) bc_malloc (sizeof (bc_var_array));
+ ary_ptr->a_value = NULL;
+ ary_ptr->a_next = NULL;
+ ary_ptr->a_param = FALSE;
+ }
+
+ a_var = ary_ptr->a_value;
+ if (a_var == NULL) {
+ a_var = ary_ptr->a_value = (bc_array *) bc_malloc (sizeof (bc_array));
+ a_var->a_tree = NULL;
+ a_var->a_depth = 0;
+ }
+
+ /* Get the index variable. */
+ sub[0] = index & NODE_MASK;
+ ix = index >> NODE_SHIFT;
+ log = 1;
+ while (ix > 0 || log < a_var->a_depth)
+ {
+ sub[log] = ix & NODE_MASK;
+ ix >>= NODE_SHIFT;
+ log++;
+ }
+
+ /* Build any tree that is necessary. */
+ while (log > a_var->a_depth)
+ {
+ temp = (bc_array_node *) bc_malloc (sizeof(bc_array_node));
+ if (a_var->a_depth != 0)
+ {
+ temp->n_items.n_down[0] = a_var->a_tree;
+ for (ix=1; ix < NODE_SIZE; ix++)
+ temp->n_items.n_down[ix] = NULL;
+ }
+ else
+ {
+ for (ix=0; ix < NODE_SIZE; ix++)
+ temp->n_items.n_num[ix] = copy_num(_zero_);
+ }
+ a_var->a_tree = temp;
+ a_var->a_depth++;
+ }
+
+ /* Find the indexed variable. */
+ temp = a_var->a_tree;
+ while ( log-- > 1)
+ {
+ ix1 = sub[log];
+ if (temp->n_items.n_down[ix1] == NULL)
+ {
+ temp->n_items.n_down[ix1] =
+ (bc_array_node *) bc_malloc (sizeof(bc_array_node));
+ temp = temp->n_items.n_down[ix1];
+ if (log > 1)
+ for (ix=0; ix < NODE_SIZE; ix++)
+ temp->n_items.n_down[ix] = NULL;
+ else
+ for (ix=0; ix < NODE_SIZE; ix++)
+ temp->n_items.n_num[ix] = copy_num(_zero_);
+ }
+ else
+ temp = temp->n_items.n_down[ix1];
+ }
+
+ /* Return the address of the indexed variable. */
+ return &(temp->n_items.n_num[sub[0]]);
+}
+
+
+/* Store the top of the execution stack into VAR_NAME.
+ This includes the special variables ibase, obase, and scale. */
+
+void
+store_var (var_name)
+ int var_name;
+{
+ bc_var *var_ptr;
+ long temp;
+ char toobig;
+
+ if (var_name > 2)
+ {
+ /* It is a simple variable. */
+ var_ptr = get_var (var_name);
+ if (var_ptr != NULL)
+ {
+ free_num(&var_ptr->v_value);
+ var_ptr->v_value = copy_num (ex_stack->s_num);
+ }
+ }
+ else
+ {
+ /* It is a special variable... */
+ toobig = FALSE;
+ if (is_neg (ex_stack->s_num))
+ {
+ switch (var_name)
+ {
+ case 0:
+ rt_warn ("negative ibase, set to 2");
+ temp = 2;
+ break;
+ case 1:
+ rt_warn ("negative obase, set to 2");
+ temp = 2;
+ break;
+ case 2:
+ rt_warn ("negative scale, set to 0");
+ temp = 0;
+ break;
+ }
+ }
+ else
+ {
+ temp = num2long (ex_stack->s_num);
+ if (!is_zero (ex_stack->s_num) && temp == 0)
+ toobig = TRUE;
+ }
+ switch (var_name)
+ {
+ case 0:
+ if (temp < 2 && !toobig)
+ {
+ i_base = 2;
+ rt_warn ("ibase too small, set to 2");
+ }
+ else
+ if (temp > 16 || toobig)
+ {
+ i_base = 16;
+ rt_warn ("ibase too large, set to 16");
+ }
+ else
+ i_base = (int) temp;
+ break;
+
+ case 1:
+ if (temp < 2 && !toobig)
+ {
+ o_base = 2;
+ rt_warn ("obase too small, set to 2");
+ }
+ else
+ if (temp > BC_BASE_MAX || toobig)
+ {
+ o_base = BC_BASE_MAX;
+ rt_warn ("obase too large, set to %d", BC_BASE_MAX);
+ }
+ else
+ o_base = (int) temp;
+ break;
+
+ case 2:
+ /* WARNING: The following if statement may generate a compiler
+ warning if INT_MAX == LONG_MAX. This is NOT a problem. */
+ if (temp > BC_SCALE_MAX || toobig )
+ {
+ scale = BC_SCALE_MAX;
+ rt_warn ("scale too large, set to %d", BC_SCALE_MAX);
+ }
+ else
+ scale = (int) temp;
+ }
+ }
+}
+
+
+/* Store the top of the execution stack into array VAR_NAME.
+ VAR_NAME is the name of an array, and the next to the top
+ of stack for the index into the array. */
+
+void
+store_array (var_name)
+ int var_name;
+{
+ bc_num *num_ptr;
+ long index;
+
+ if (!check_stack(2)) return;
+ index = num2long (ex_stack->s_next->s_num);
+ if (index < 0 || index > BC_DIM_MAX ||
+ (index == 0 && !is_zero(ex_stack->s_next->s_num)))
+ rt_error ("Array %s subscript out of bounds.", a_names[var_name]);
+ else
+ {
+ num_ptr = get_array_num (var_name, index);
+ if (num_ptr != NULL)
+ {
+ free_num (num_ptr);
+ *num_ptr = copy_num (ex_stack->s_num);
+ free_num (&ex_stack->s_next->s_num);
+ ex_stack->s_next->s_num = ex_stack->s_num;
+ init_num (&ex_stack->s_num);
+ pop();
+ }
+ }
+}
+
+
+/* Load a copy of VAR_NAME on to the execution stack. This includes
+ the special variables ibase, obase and scale. */
+
+void
+load_var (var_name)
+ int var_name;
+{
+ bc_var *var_ptr;
+
+ switch (var_name)
+ {
+
+ case 0:
+ /* Special variable ibase. */
+ push_copy (_zero_);
+ int2num (&ex_stack->s_num, i_base);
+ break;
+
+ case 1:
+ /* Special variable obase. */
+ push_copy (_zero_);
+ int2num (&ex_stack->s_num, o_base);
+ break;
+
+ case 2:
+ /* Special variable scale. */
+ push_copy (_zero_);
+ int2num (&ex_stack->s_num, scale);
+ break;
+
+ default:
+ /* It is a simple variable. */
+ var_ptr = variables[var_name];
+ if (var_ptr != NULL)
+ push_copy (var_ptr->v_value);
+ else
+ push_copy (_zero_);
+ }
+}
+
+
+/* Load a copy of VAR_NAME on to the execution stack. This includes
+ the special variables ibase, obase and scale. */
+
+void
+load_array (var_name)
+ int var_name;
+{
+ bc_num *num_ptr;
+ long index;
+
+ if (!check_stack(1)) return;
+ index = num2long (ex_stack->s_num);
+ if (index < 0 || index > BC_DIM_MAX ||
+ (index == 0 && !is_zero(ex_stack->s_num)))
+ rt_error ("Array %s subscript out of bounds.", a_names[var_name]);
+ else
+ {
+ num_ptr = get_array_num (var_name, index);
+ if (num_ptr != NULL)
+ {
+ pop();
+ push_copy (*num_ptr);
+ }
+ }
+}
+
+
+/* Decrement VAR_NAME by one. This includes the special variables
+ ibase, obase, and scale. */
+
+void
+decr_var (var_name)
+ int var_name;
+{
+ bc_var *var_ptr;
+
+ switch (var_name)
+ {
+
+ case 0: /* ibase */
+ if (i_base > 2)
+ i_base--;
+ else
+ rt_warn ("ibase too small in --");
+ break;
+
+ case 1: /* obase */
+ if (o_base > 2)
+ o_base--;
+ else
+ rt_warn ("obase too small in --");
+ break;
+
+ case 2: /* scale */
+ if (scale > 0)
+ scale--;
+ else
+ rt_warn ("scale can not be negative in -- ");
+ break;
+
+ default: /* It is a simple variable. */
+ var_ptr = get_var (var_name);
+ if (var_ptr != NULL)
+ bc_sub (var_ptr->v_value,_one_,&var_ptr->v_value);
+ }
+}
+
+
+/* Decrement VAR_NAME by one. VAR_NAME is an array, and the top of
+ the execution stack is the index and it is popped off the stack. */
+
+void
+decr_array (var_name)
+ char var_name;
+{
+ bc_num *num_ptr;
+ long index;
+
+ /* It is an array variable. */
+ if (!check_stack (1)) return;
+ index = num2long (ex_stack->s_num);
+ if (index < 0 || index > BC_DIM_MAX ||
+ (index == 0 && !is_zero (ex_stack->s_num)))
+ rt_error ("Array %s subscript out of bounds.", a_names[var_name]);
+ else
+ {
+ num_ptr = get_array_num (var_name, index);
+ if (num_ptr != NULL)
+ {
+ pop ();
+ bc_sub (*num_ptr, _one_, num_ptr);
+ }
+ }
+}
+
+
+/* Increment VAR_NAME by one. This includes the special variables
+ ibase, obase, and scale. */
+
+void
+incr_var (var_name)
+ int var_name;
+{
+ bc_var *var_ptr;
+
+ switch (var_name)
+ {
+
+ case 0: /* ibase */
+ if (i_base < 16)
+ i_base++;
+ else
+ rt_warn ("ibase too big in ++");
+ break;
+
+ case 1: /* obase */
+ if (o_base < BC_BASE_MAX)
+ o_base++;
+ else
+ rt_warn ("obase too big in ++");
+ break;
+
+ case 2:
+ if (scale < BC_SCALE_MAX)
+ scale++;
+ else
+ rt_warn ("Scale too big in ++");
+ break;
+
+ default: /* It is a simple variable. */
+ var_ptr = get_var (var_name);
+ if (var_ptr != NULL)
+ bc_add (var_ptr->v_value, _one_, &var_ptr->v_value);
+
+ }
+}
+
+
+/* Increment VAR_NAME by one. VAR_NAME is an array and top of
+ execution stack is the index and is popped off the stack. */
+
+void
+incr_array (var_name)
+ int var_name;
+{
+ bc_num *num_ptr;
+ long index;
+
+ if (!check_stack (1)) return;
+ index = num2long (ex_stack->s_num);
+ if (index < 0 || index > BC_DIM_MAX ||
+ (index == 0 && !is_zero (ex_stack->s_num)))
+ rt_error ("Array %s subscript out of bounds.", a_names[var_name]);
+ else
+ {
+ num_ptr = get_array_num (var_name, index);
+ if (num_ptr != NULL)
+ {
+ pop ();
+ bc_add (*num_ptr, _one_, num_ptr);
+ }
+ }
+}
+
+
+/* Routines for processing autos variables and parameters. */
+
+/* NAME is an auto variable that needs to be pushed on its stack. */
+
+void
+auto_var (name)
+ int name;
+{
+ bc_var *v_temp;
+ bc_var_array *a_temp;
+ int ix;
+
+ if (name > 0)
+ {
+ /* A simple variable. */
+ ix = name;
+ v_temp = (bc_var *) bc_malloc (sizeof (bc_var));
+ v_temp->v_next = variables[ix];
+ init_num (&v_temp->v_value);
+ variables[ix] = v_temp;
+ }
+ else
+ {
+ /* An array variable. */
+ ix = -name;
+ a_temp = (bc_var_array *) bc_malloc (sizeof (bc_var_array));
+ a_temp->a_next = arrays[ix];
+ a_temp->a_value = NULL;
+ a_temp->a_param = FALSE;
+ arrays[ix] = a_temp;
+ }
+}
+
+
+/* Free_a_tree frees everything associated with an array variable tree.
+ This is used when popping an array variable off its auto stack. */
+
+void
+free_a_tree ( root, depth )
+ bc_array_node *root;
+ int depth;
+{
+ int ix;
+
+ if (root != NULL)
+ {
+ if (depth > 1)
+ for (ix = 0; ix < NODE_SIZE; ix++)
+ free_a_tree (root->n_items.n_down[ix], depth-1);
+ else
+ for (ix = 0; ix < NODE_SIZE; ix++)
+ free_num ( &(root->n_items.n_num[ix]));
+ free (root);
+ }
+}
+
+
+/* LIST is an NULL terminated list of varible names that need to be
+ popped off their auto stacks. */
+
+void
+pop_vars (list)
+ arg_list *list;
+{
+ bc_var *v_temp;
+ bc_var_array *a_temp;
+ int ix;
+
+ while (list != NULL)
+ {
+ ix = list->av_name;
+ if (ix > 0)
+ {
+ /* A simple variable. */
+ v_temp = variables[ix];
+ if (v_temp != NULL)
+ {
+ variables[ix] = v_temp->v_next;
+ free_num (&v_temp->v_value);
+ free (v_temp);
+ }
+ }
+ else
+ {
+ /* An array variable. */
+ ix = -ix;
+ a_temp = arrays[ix];
+ if (a_temp != NULL)
+ {
+ arrays[ix] = a_temp->a_next;
+ if (!a_temp->a_param && a_temp->a_value != NULL)
+ {
+ free_a_tree (a_temp->a_value->a_tree,
+ a_temp->a_value->a_depth);
+ free (a_temp->a_value);
+ }
+ free (a_temp);
+ }
+ }
+ list = list->next;
+ }
+}
+
+
+/* A call is being made to FUNC. The call types are at PC. Process
+ the parameters by doing an auto on the parameter variable and then
+ store the value at the new variable or put a pointer the the array
+ variable. */
+
+void
+process_params (pc, func)
+ program_counter *pc;
+ int func;
+{
+ char ch;
+ arg_list *params;
+ char warned = FALSE;
+ int ix, ix1;
+ bc_var *v_temp;
+ bc_var_array *a_src, *a_dest;
+ bc_num *n_temp;
+
+ /* Get the parameter names from the function. */
+ params = functions[func].f_params;
+
+ while ((ch = byte(pc)) != ':')
+ {
+ if (params != NULL)
+ {
+ if ((ch == '0') && params->av_name > 0)
+ {
+ /* A simple variable. */
+ ix = params->av_name;
+ v_temp = (bc_var *) bc_malloc (sizeof(bc_var));
+ v_temp->v_next = variables[ix];
+ v_temp->v_value = ex_stack->s_num;
+ init_num (&ex_stack->s_num);
+ variables[ix] = v_temp;
+ }
+ else
+ if ((ch == '1') && (params->av_name < 0))
+ {
+ /* The variables is an array variable. */
+
+ /* Compute source index and make sure some structure exists. */
+ ix = (int) num2long (ex_stack->s_num);
+ n_temp = get_array_num (ix, 0);
+
+ /* Push a new array and Compute Destination index */
+ auto_var (params->av_name);
+ ix1 = -params->av_name;
+
+ /* Set up the correct pointers in the structure. */
+ if (ix == ix1)
+ a_src = arrays[ix]->a_next;
+ else
+ a_src = arrays[ix];
+ a_dest = arrays[ix1];
+ a_dest->a_param = TRUE;
+ a_dest->a_value = a_src->a_value;
+ }
+ else
+ {
+ if (params->av_name < 0)
+ rt_error ("Parameter type mismatch parameter %s.",
+ a_names[-params->av_name]);
+ else
+ rt_error ("Parameter type mismatch, parameter %s.",
+ v_names[params->av_name]);
+ params++;
+ }
+ pop ();
+ }
+ else
+ {
+ if (!warned)
+ {
+ rt_error ("Parameter number mismatch");
+ warned = TRUE;
+ }
+ }
+ params = params->next;
+ }
+ if (params != NULL)
+ rt_error ("Parameter number mismatch");
+}
diff --git a/gnu/usr.bin/bc/util.c b/gnu/usr.bin/bc/util.c
new file mode 100644
index 0000000..5a01803
--- /dev/null
+++ b/gnu/usr.bin/bc/util.c
@@ -0,0 +1,794 @@
+/* util.c: Utility routines for bc. */
+
+/* This file is part of bc written for MINIX.
+ Copyright (C) 1991, 1992 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License , or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; see the file COPYING. If not, write to
+ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ You may contact the author by:
+ e-mail: phil@cs.wwu.edu
+ us-mail: Philip A. Nelson
+ Computer Science Department, 9062
+ Western Washington University
+ Bellingham, WA 98226-9062
+
+*************************************************************************/
+
+
+#include "bcdefs.h"
+#ifndef VARARGS
+#include <stdarg.h>
+#else
+#include <varargs.h>
+#endif
+#include "global.h"
+#include "proto.h"
+
+
+/* strcopyof mallocs new memory and copies a string to to the new
+ memory. */
+
+char *
+strcopyof (str)
+ char *str;
+{
+ char *temp;
+
+ temp = (char *) bc_malloc (strlen (str)+1);
+ return (strcpy (temp,str));
+}
+
+
+/* nextarg adds another value to the list of arguments. */
+
+arg_list *
+nextarg (args, val)
+ arg_list *args;
+ char val;
+{ arg_list *temp;
+
+ temp = (arg_list *) bc_malloc (sizeof (arg_list));
+ temp->av_name = val;
+ temp->next = args;
+
+ return (temp);
+}
+
+
+/* For generate, we must produce a string in the form
+ "val,val,...,val". We also need a couple of static variables
+ for retaining old generated strings. It also uses a recursive
+ function that builds the string. */
+
+static char *arglist1 = NULL, *arglist2 = NULL;
+
+
+/* make_arg_str does the actual construction of the argument string.
+ ARGS is the pointer to the list and LEN is the maximum number of
+ characters needed. 1 char is the minimum needed. COMMAS tells
+ if each number should be seperated by commas.*/
+
+_PROTOTYPE (static char *make_arg_str, (arg_list *args, int len, int commas));
+
+static char *
+make_arg_str (args, len, commas)
+ arg_list *args;
+ int len;
+ int commas;
+{
+ char *temp;
+ char sval[20];
+
+ /* Recursive call. */
+ if (args != NULL)
+ temp = make_arg_str (args->next, len+11, commas);
+ else
+ {
+ temp = (char *) bc_malloc (len);
+ *temp = 0;
+ return temp;
+ }
+
+ /* Add the current number to the end of the string. */
+ if (len != 1 && commas)
+ sprintf (sval, "%d,", args->av_name);
+ else
+ sprintf (sval, "%d", args->av_name);
+ temp = strcat (temp, sval);
+ return (temp);
+}
+
+char *
+arg_str (args, commas)
+ arg_list *args;
+ int commas;
+{
+ if (arglist2 != NULL)
+ free (arglist2);
+ arglist2 = arglist1;
+ arglist1 = make_arg_str (args, 1, commas);
+ return (arglist1);
+}
+
+
+/* free_args frees an argument list ARGS. */
+
+void
+free_args (args)
+ arg_list *args;
+{
+ arg_list *temp;
+
+ temp = args;
+ while (temp != NULL)
+ {
+ args = args->next;
+ free (temp);
+ temp = args;
+ }
+}
+
+
+/* Check for valid parameter (PARAMS) and auto (AUTOS) lists.
+ There must be no duplicates any where. Also, this is where
+ warnings are generated for array parameters. */
+
+void
+check_params ( params, autos )
+ arg_list *params, *autos;
+{
+ arg_list *tmp1, *tmp2;
+
+ /* Check for duplicate parameters. */
+ if (params != NULL)
+ {
+ tmp1 = params;
+ while (tmp1 != NULL)
+ {
+ tmp2 = tmp1->next;
+ while (tmp2 != NULL)
+ {
+ if (tmp2->av_name == tmp1->av_name)
+ yyerror ("duplicate parameter names");
+ tmp2 = tmp2->next;
+ }
+ if (tmp1->av_name < 0)
+ warn ("Array parameter");
+ tmp1 = tmp1->next;
+ }
+ }
+
+ /* Check for duplicate autos. */
+ if (autos != NULL)
+ {
+ tmp1 = autos;
+ while (tmp1 != NULL)
+ {
+ tmp2 = tmp1->next;
+ while (tmp2 != NULL)
+ {
+ if (tmp2->av_name == tmp1->av_name)
+ yyerror ("duplicate auto variable names");
+ tmp2 = tmp2->next;
+ }
+ tmp1 = tmp1->next;
+ }
+ }
+
+ /* Check for duplicate between parameters and autos. */
+ if ((params != NULL) && (autos != NULL))
+ {
+ tmp1 = params;
+ while (tmp1 != NULL)
+ {
+ tmp2 = autos;
+ while (tmp2 != NULL)
+ {
+ if (tmp2->av_name == tmp1->av_name)
+ yyerror ("variable in both parameter and auto lists");
+ tmp2 = tmp2->next;
+ }
+ tmp1 = tmp1->next;
+ }
+ }
+}
+
+
+/* Initialize the code generator the parser. */
+
+void
+init_gen ()
+{
+ /* Get things ready. */
+ break_label = 0;
+ continue_label = 0;
+ next_label = 1;
+ out_count = 2;
+ if (compile_only)
+ printf ("@i");
+ else
+ init_load ();
+ had_error = FALSE;
+ did_gen = FALSE;
+}
+
+
+/* generate code STR for the machine. */
+
+void
+generate (str)
+ char *str;
+{
+ did_gen = TRUE;
+ if (compile_only)
+ {
+ printf ("%s",str);
+ out_count += strlen(str);
+ if (out_count > 60)
+ {
+ printf ("\n");
+ out_count = 0;
+ }
+ }
+ else
+ load_code (str);
+}
+
+
+/* Execute the current code as loaded. */
+
+void
+run_code()
+{
+ /* If no compile errors run the current code. */
+ if (!had_error && did_gen)
+ {
+ if (compile_only)
+ {
+ printf ("@r\n");
+ out_count = 0;
+ }
+ else
+ execute ();
+ }
+
+ /* Reinitialize the code generation and machine. */
+ if (did_gen)
+ init_gen();
+ else
+ had_error = FALSE;
+}
+
+
+/* Output routines: Write a character CH to the standard output.
+ It keeps track of the number of characters output and may
+ break the output with a "\<cr>". */
+
+void
+out_char (ch)
+ char ch;
+{
+ if (ch == '\n')
+ {
+ out_col = 0;
+ putchar ('\n');
+ }
+ else
+ {
+ out_col++;
+ if (out_col == 70)
+ {
+ putchar ('\\');
+ putchar ('\n');
+ out_col = 1;
+ }
+ putchar (ch);
+ }
+}
+
+
+/* The following are "Symbol Table" routines for the parser. */
+
+/* find_id returns a pointer to node in TREE that has the correct
+ ID. If there is no node in TREE with ID, NULL is returned. */
+
+id_rec *
+find_id (tree, id)
+ id_rec *tree;
+ char *id;
+{
+ int cmp_result;
+
+ /* Check for an empty tree. */
+ if (tree == NULL)
+ return NULL;
+
+ /* Recursively search the tree. */
+ cmp_result = strcmp (id, tree->id);
+ if (cmp_result == 0)
+ return tree; /* This is the item. */
+ else if (cmp_result < 0)
+ return find_id (tree->left, id);
+ else
+ return find_id (tree->right, id);
+}
+
+
+/* insert_id_rec inserts a NEW_ID rec into the tree whose ROOT is
+ provided. insert_id_rec returns TRUE if the tree height from
+ ROOT down is increased otherwise it returns FALSE. This is a
+ recursive balanced binary tree insertion algorithm. */
+
+int insert_id_rec (root, new_id)
+ id_rec **root;
+ id_rec *new_id;
+{
+ id_rec *A, *B;
+
+ /* If root is NULL, this where it is to be inserted. */
+ if (*root == NULL)
+ {
+ *root = new_id;
+ new_id->left = NULL;
+ new_id->right = NULL;
+ new_id->balance = 0;
+ return (TRUE);
+ }
+
+ /* We need to search for a leaf. */
+ if (strcmp (new_id->id, (*root)->id) < 0)
+ {
+ /* Insert it on the left. */
+ if (insert_id_rec (&((*root)->left), new_id))
+ {
+ /* The height increased. */
+ (*root)->balance --;
+
+ switch ((*root)->balance)
+ {
+ case 0: /* no height increase. */
+ return (FALSE);
+ case -1: /* height increase. */
+ return (FALSE);
+ case -2: /* we need to do a rebalancing act. */
+ A = *root;
+ B = (*root)->left;
+ if (B->balance <= 0)
+ {
+ /* Single Rotate. */
+ A->left = B->right;
+ B->right = A;
+ *root = B;
+ A->balance = 0;
+ B->balance = 0;
+ }
+ else
+ {
+ /* Double Rotate. */
+ *root = B->right;
+ B->right = (*root)->left;
+ A->left = (*root)->right;
+ (*root)->left = B;
+ (*root)->right = A;
+ switch ((*root)->balance)
+ {
+ case -1:
+ A->balance = 1;
+ B->balance = 0;
+ break;
+ case 0:
+ A->balance = 0;
+ B->balance = 0;
+ break;
+ case 1:
+ A->balance = 0;
+ B->balance = -1;
+ break;
+ }
+ (*root)->balance = 0;
+ }
+ }
+ }
+ }
+ else
+ {
+ /* Insert it on the right. */
+ if (insert_id_rec (&((*root)->right), new_id))
+ {
+ /* The height increased. */
+ (*root)->balance ++;
+ switch ((*root)->balance)
+ {
+ case 0: /* no height increase. */
+ return (FALSE);
+ case 1: /* height increase. */
+ return (FALSE);
+ case 2: /* we need to do a rebalancing act. */
+ A = *root;
+ B = (*root)->right;
+ if (B->balance >= 0)
+ {
+ /* Single Rotate. */
+ A->right = B->left;
+ B->left = A;
+ *root = B;
+ A->balance = 0;
+ B->balance = 0;
+ }
+ else
+ {
+ /* Double Rotate. */
+ *root = B->left;
+ B->left = (*root)->right;
+ A->right = (*root)->left;
+ (*root)->left = A;
+ (*root)->right = B;
+ switch ((*root)->balance)
+ {
+ case -1:
+ A->balance = 0;
+ B->balance = 1;
+ break;
+ case 0:
+ A->balance = 0;
+ B->balance = 0;
+ break;
+ case 1:
+ A->balance = -1;
+ B->balance = 0;
+ break;
+ }
+ (*root)->balance = 0;
+ }
+ }
+ }
+ }
+
+ /* If we fall through to here, the tree did not grow in height. */
+ return (FALSE);
+}
+
+
+/* Initialize variables for the symbol table tree. */
+
+void
+init_tree()
+{
+ name_tree = NULL;
+ next_array = 1;
+ next_func = 1;
+ next_var = 4; /* 0 => ibase, 1 => obase, 2 => scale, 3 => last. */
+}
+
+
+/* Lookup routines for symbol table names. */
+
+int
+lookup (name, namekind)
+ char *name;
+ int namekind;
+{
+ id_rec *id;
+
+ /* Warn about non-standard name. */
+ if (strlen(name) != 1)
+ warn ("multiple letter name - %s", name);
+
+ /* Look for the id. */
+ id = find_id (name_tree, name);
+ if (id == NULL)
+ {
+ /* We need to make a new item. */
+ id = (id_rec *) bc_malloc (sizeof (id_rec));
+ id->id = strcopyof (name);
+ id->a_name = 0;
+ id->f_name = 0;
+ id->v_name = 0;
+ insert_id_rec (&name_tree, id);
+ }
+
+ /* Return the correct value. */
+ switch (namekind)
+ {
+
+ case ARRAY:
+ /* ARRAY variable numbers are returned as negative numbers. */
+ if (id->a_name != 0)
+ {
+ free (name);
+ return (-id->a_name);
+ }
+ id->a_name = next_array++;
+ a_names[id->a_name] = name;
+ if (id->a_name < MAX_STORE)
+ {
+ if (id->a_name >= a_count)
+ more_arrays ();
+ return (-id->a_name);
+ }
+ yyerror ("Too many array variables");
+ exit (1);
+
+ case FUNCT:
+ if (id->f_name != 0)
+ {
+ free(name);
+ return (id->f_name);
+ }
+ id->f_name = next_func++;
+ f_names[id->f_name] = name;
+ if (id->f_name < MAX_STORE)
+ {
+ if (id->f_name >= f_count)
+ more_functions ();
+ return (id->f_name);
+ }
+ yyerror ("Too many functions");
+ exit (1);
+
+ case SIMPLE:
+ if (id->v_name != 0)
+ {
+ free(name);
+ return (id->v_name);
+ }
+ id->v_name = next_var++;
+ v_names[id->v_name - 1] = name;
+ if (id->v_name <= MAX_STORE)
+ {
+ if (id->v_name >= v_count)
+ more_variables ();
+ return (id->v_name);
+ }
+ yyerror ("Too many variables");
+ exit (1);
+ }
+}
+
+
+/* Print the welcome banner. */
+
+void
+welcome()
+{
+ printf ("This is free software with ABSOLUTELY NO WARRANTY.\n");
+ printf ("For details type `warranty'. \n");
+}
+
+
+/* Print out the warranty information. */
+
+void
+warranty(prefix)
+ char *prefix;
+{
+ printf ("\n%s%s\n\n", prefix, BC_VERSION);
+ printf ("%s%s%s%s%s%s%s%s%s%s%s",
+" This program is free software; you can redistribute it and/or modify\n",
+" it under the terms of the GNU General Public License as published by\n",
+" the Free Software Foundation; either version 2 of the License , or\n",
+" (at your option) any later version.\n\n",
+" This program is distributed in the hope that it will be useful,\n",
+" but WITHOUT ANY WARRANTY; without even the implied warranty of\n",
+" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n",
+" GNU General Public License for more details.\n\n",
+" You should have received a copy of the GNU General Public License\n",
+" along with this program. If not, write to the Free Software\n",
+" Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.\n\n");
+}
+
+/* Print out the limits of this program. */
+
+void
+limits()
+{
+ printf ("BC_BASE_MAX = %d\n", BC_BASE_MAX);
+ printf ("BC_DIM_MAX = %ld\n", (long) BC_DIM_MAX);
+ printf ("BC_SCALE_MAX = %d\n", BC_SCALE_MAX);
+ printf ("BC_STRING_MAX = %d\n", BC_STRING_MAX);
+ printf ("MAX Exponent = %ld\n", (long) LONG_MAX);
+ printf ("MAX code = %ld\n", (long) BC_MAX_SEGS * (long) BC_SEG_SIZE);
+ printf ("multiply digits = %ld\n", (long) LONG_MAX / (long) 90);
+ printf ("Number of vars = %ld\n", (long) MAX_STORE);
+#ifdef OLD_EQ_OP
+ printf ("Old assignment operatiors are valid. (=-, =+, ...)\n");
+#endif
+}
+
+/* bc_malloc will check the return value so all other places do not
+ have to do it! SIZE is the number of types to allocate. */
+
+char *
+bc_malloc (size)
+ int size;
+{
+ char *ptr;
+
+ ptr = (char *) malloc (size);
+ if (ptr == NULL)
+ out_of_memory ();
+
+ return ptr;
+}
+
+
+/* The following routines are error routines for various problems. */
+
+/* Malloc could not get enought memory. */
+
+void
+out_of_memory()
+{
+ fprintf (stderr, "Fatal error: Out of memory for malloc.\n");
+ exit (1);
+}
+
+
+
+/* The standard yyerror routine. Built with variable number of argumnets. */
+
+#ifndef VARARGS
+#ifdef __STDC__
+void
+yyerror (char *str, ...)
+#else
+void
+yyerror (str)
+ char *str;
+#endif
+#else
+void
+yyerror (str, va_alist)
+ char *str;
+#endif
+{
+ char *name;
+ va_list args;
+
+#ifndef VARARGS
+ va_start (args, str);
+#else
+ va_start (args);
+#endif
+ if (is_std_in)
+ name = "(standard_in)";
+ else
+ name = g_argv[optind-1];
+ fprintf (stderr,"%s %d: ",name,line_no);
+ vfprintf (stderr, str, args);
+ fprintf (stderr, "\n");
+ had_error = TRUE;
+ va_end (args);
+}
+
+
+/* The routine to produce warnings about non-standard features
+ found during parsing. */
+
+#ifndef VARARGS
+#ifdef __STDC__
+void
+warn (char *mesg, ...)
+#else
+void
+warn (mesg)
+ char *mesg;
+#endif
+#else
+void
+warn (mesg, va_alist)
+ char *mesg;
+#endif
+{
+ char *name;
+ va_list args;
+
+#ifndef VARARGS
+ va_start (args, mesg);
+#else
+ va_start (args);
+#endif
+ if (std_only)
+ {
+ if (is_std_in)
+ name = "(standard_in)";
+ else
+ name = g_argv[optind-1];
+ fprintf (stderr,"%s %d: ",name,line_no);
+ vfprintf (stderr, mesg, args);
+ fprintf (stderr, "\n");
+ had_error = TRUE;
+ }
+ else
+ if (warn_not_std)
+ {
+ if (is_std_in)
+ name = "(standard_in)";
+ else
+ name = g_argv[optind-1];
+ fprintf (stderr,"%s %d: (Warning) ",name,line_no);
+ vfprintf (stderr, mesg, args);
+ fprintf (stderr, "\n");
+ }
+ va_end (args);
+}
+
+/* Runtime error will print a message and stop the machine. */
+
+#ifndef VARARGS
+#ifdef __STDC__
+void
+rt_error (char *mesg, ...)
+#else
+void
+rt_error (mesg)
+ char *mesg;
+#endif
+#else
+void
+rt_error (mesg, va_alist)
+ char *mesg;
+#endif
+{
+ va_list args;
+ char error_mesg [255];
+
+#ifndef VARARGS
+ va_start (args, mesg);
+#else
+ va_start (args);
+#endif
+ vsprintf (error_mesg, mesg, args);
+ va_end (args);
+
+ fprintf (stderr, "Runtime error (func=%s, adr=%d): %s\n",
+ f_names[pc.pc_func], pc.pc_addr, error_mesg);
+ runtime_error = TRUE;
+}
+
+
+/* A runtime warning tells of some action taken by the processor that
+ may change the program execution but was not enough of a problem
+ to stop the execution. */
+
+#ifndef VARARGS
+#ifdef __STDC__
+void
+rt_warn (char *mesg, ...)
+#else
+void
+rt_warn (mesg)
+ char *mesg;
+#endif
+#else
+void
+rt_warn (mesg, va_alist)
+ char *mesg;
+#endif
+{
+ va_list args;
+ char error_mesg [255];
+
+#ifndef VARARGS
+ va_start (args, mesg);
+#else
+ va_start (args);
+#endif
+ vsprintf (error_mesg, mesg, args);
+ va_end (args);
+
+ fprintf (stderr, "Runtime warning (func=%s, adr=%d): %s\n",
+ f_names[pc.pc_func], pc.pc_addr, error_mesg);
+}
diff --git a/gnu/usr.bin/bc/version.h b/gnu/usr.bin/bc/version.h
new file mode 100644
index 0000000..6b3f909
--- /dev/null
+++ b/gnu/usr.bin/bc/version.h
@@ -0,0 +1,3 @@
+#define BC_VERSION \
+ "bc 1.02 (Mar 3, 92) Copyright (C) 1991, 1992 Free Software Foundation, Inc."
+
diff --git a/gnu/usr.bin/bc/y.tab.h b/gnu/usr.bin/bc/y.tab.h
new file mode 100644
index 0000000..9e65a2f
--- /dev/null
+++ b/gnu/usr.bin/bc/y.tab.h
@@ -0,0 +1,40 @@
+#define NEWLINE 257
+#define AND 258
+#define OR 259
+#define NOT 260
+#define STRING 261
+#define NAME 262
+#define NUMBER 263
+#define MUL_OP 264
+#define ASSIGN_OP 265
+#define REL_OP 266
+#define INCR_DECR 267
+#define Define 268
+#define Break 269
+#define Quit 270
+#define Length 271
+#define Return 272
+#define For 273
+#define If 274
+#define While 275
+#define Sqrt 276
+#define Else 277
+#define Scale 278
+#define Ibase 279
+#define Obase 280
+#define Auto 281
+#define Read 282
+#define Warranty 283
+#define Halt 284
+#define Last 285
+#define Continue 286
+#define Print 287
+#define Limits 288
+#define UNARY_MINUS 289
+typedef union {
+ char *s_value;
+ char c_value;
+ int i_value;
+ arg_list *a_value;
+ } YYSTYPE;
+extern YYSTYPE yylval;
diff --git a/gnu/usr.bin/binutils/gdb/Makefile b/gnu/usr.bin/binutils/gdb/Makefile
new file mode 100644
index 0000000..68a86ae
--- /dev/null
+++ b/gnu/usr.bin/binutils/gdb/Makefile
@@ -0,0 +1,75 @@
+PROG = gdb
+BINDIR= /usr/bin
+CLEANFILES+= y.tab.h c-exp.tab.c ch-exp.tab.c m2-exp.tab.c
+SRCS = annotate.c blockframe.c breakpoint.c buildsym.c c-lang.c \
+ c-typeprint.c c-valprint.c ch-lang.c ch-typeprint.c \
+ ch-valprint.c coffread.c command.c complaints.c copying.c core.c \
+ coredep.c corelow.c cp-valprint.c \
+ dcache.c dbxread.c demangle.c disassemble.c dis-buf.c dwarfread.c \
+ elfread.c environ.c eval.c exec.c expprint.c \
+ findvar.c fork-child.c freebsd-nat.c gdbtypes.c i386-dis.c \
+ i386-pinsn.c i386-tdep.c infcmd.c inflow.c infptrace.c \
+ infrun.c inftarg.c init.c kcorelow.c language.c \
+ m2-lang.c m2-typeprint.c m2-valprint.c main.c maint.c \
+ mem-break.c minsyms.c objfiles.c parse.c \
+ printcmd.c remote.c remote-utils.c solib.c source.c \
+ stabsread.c stack.c symfile.c symmisc.c \
+ symtab.c target.c thread.c top.c \
+ typeprint.c utils.c valarith.c valops.c \
+ valprint.c values.c version.c serial.c ser-unix.c mdebugread.c\
+ c-exp.tab.c ch-exp.tab.c m2-exp.tab.c compat_que.c
+
+c-exp.tab.c: $(.CURDIR)/c-exp.y
+ yacc -d -p c_ $(.CURDIR)/c-exp.y
+ sed -e '/extern.*malloc/d' -e '/extern.*realloc/d' -e '/extern.*free/d' \
+ -e '/include.*malloc.h/d' -e 's/malloc/xmalloc/g' \
+ -e 's/realloc/xrealloc/g' < y.tab.c > c-exp.new
+ rm y.tab.c
+ mv c-exp.new ./c-exp.tab.c
+
+ch-exp.tab.c: $(.CURDIR)/ch-exp.y
+ yacc -d -p ch_ $(.CURDIR)/ch-exp.y
+ sed -e '/extern.*malloc/d' -e '/extern.*realloc/d' -e '/extern.*free/d' \
+ -e '/include.*malloc.h/d' -e 's/malloc/xmalloc/g' \
+ -e 's/realloc/xrealloc/g' < y.tab.c > ch-exp.new
+ rm y.tab.c
+ mv ch-exp.new ./ch-exp.tab.c
+
+m2-exp.tab.c: $(.CURDIR)/m2-exp.y
+ yacc -d -p m2_ $(.CURDIR)/m2-exp.y
+ sed -e '/extern.*malloc/d' -e '/extern.*realloc/d' -e '/extern.*free/d' \
+ -e '/include.*malloc.h/d' -e 's/malloc/xmalloc/g' \
+ -e 's/realloc/xrealloc/g' < y.tab.c > m2-exp.new
+ rm y.tab.c
+ mv m2-exp.new ./m2-exp.tab.c
+
+
+CFLAGS+= -I$(.CURDIR)/. -I${DESTDIR}/usr/include/readline -I$(.CURDIR)/../bfd
+DPADD+= ${LIBREADLINE} ${LIBTERMCAP} ${LIBGNUREGEX}
+LDADD+= -lreadline -ltermcap -lgnuregex
+
+.if exists(${.CURDIR}/../libiberty/obj)
+LDADD+= -L${.CURDIR}/../libiberty/obj -liberty
+DPADD+= ${.CURDIR}/../libiberty/obj/libiberty.a
+.else
+LDADD+= -L${.CURDIR}/../libiberty/ -liberty
+DPADD+= ${.CURDIR}/../libiberty/libiberty.a
+.endif
+
+.if exists(${.CURDIR}/../bfd/obj)
+LDADD+= -L${.CURDIR}/../bfd/obj -lbfd
+DPADD+= ${.CURDIR}/../bfd/obj/libbfd.a
+.else
+LDADD+= -L${.CURDIR}/../bfd/ -lbfd
+DPADD+= ${.CURDIR}/../bfd/libbfd.a
+.endif
+
+.if exists(${.CURDIR}/../mmalloc/obj)
+LDADD+= -L${.CURDIR}/../mmalloc/obj -lmmalloc
+DPADD+= ${.CURDIR}/../mmalloc/obj/libmmalloc.a
+.else
+LDADD+= -L${.CURDIR}/../mmalloc/ -lmmalloc
+DPADD+= ${.CURDIR}/../mmalloc/libmmalloc.a
+.endif
+
+.include <bsd.prog.mk>
diff --git a/gnu/usr.bin/binutils/gdb/gdb.1 b/gnu/usr.bin/binutils/gdb/gdb.1
new file mode 100644
index 0000000..0245ec8
--- /dev/null
+++ b/gnu/usr.bin/binutils/gdb/gdb.1
@@ -0,0 +1,390 @@
+.\" Copyright (c) 1991 Free Software Foundation
+.\" See section COPYING for conditions for redistribution
+.\" $Id: gdb.1,v 1.2 1994/12/30 23:25:45 jkh Exp $
+.TH gdb 1 "4nov1991" "GNU Tools" "GNU Tools"
+.SH NAME
+gdb \- The GNU Debugger
+.SH SYNOPSIS
+.na
+.TP
+.B gdb
+.RB "[\|" \-help "\|]"
+.RB "[\|" \-nx "\|]"
+.RB "[\|" \-q "\|]"
+.RB "[\|" \-k "\|]"
+.RB "[\|" \-w "\|]"
+.RB "[\|" \-batch "\|]"
+.RB "[\|" \-cd=\c
+.I dir\c
+\|]
+.RB "[\|" \-f "\|]"
+.RB "[\|" "\-b\ "\c
+.IR bps "\|]"
+.RB "[\|" "\-tty="\c
+.IR dev "\|]"
+.RB "[\|" "\-s "\c
+.I symfile\c
+\&\|]
+.RB "[\|" "\-e "\c
+.I prog\c
+\&\|]
+.RB "[\|" "\-se "\c
+.I prog\c
+\&\|]
+.RB "[\|" "\-c "\c
+.I core\c
+\&\|]
+.RB "[\|" "\-x "\c
+.I cmds\c
+\&\|]
+.RB "[\|" "\-d "\c
+.I dir\c
+\&\|]
+.RB "[\|" \c
+.I prog\c
+.RB "[\|" \c
+.IR core \||\| procID\c
+\&\|]\&\|]
+.ad b
+.SH DESCRIPTION
+The purpose of a debugger such as GDB is to allow you to see what is
+going on ``inside'' another program while it executes\(em\&or what another
+program was doing at the moment it crashed.
+
+GDB can do four main kinds of things (plus other things in support of
+these) to help you catch bugs in the act:
+
+.TP
+\ \ \ \(bu
+Start your program, specifying anything that might affect its behavior.
+
+.TP
+\ \ \ \(bu
+Make your program stop on specified conditions.
+
+.TP
+\ \ \ \(bu
+Examine what has happened, when your program has stopped.
+
+.TP
+\ \ \ \(bu
+Change things in your program, so you can experiment with correcting the
+effects of one bug and go on to learn about another.
+.PP
+
+You can use GDB to debug programs written in C, C++, and Modula-2.
+Fortran support will be added when a GNU Fortran compiler is ready.
+
+GDB is invoked with the shell command \c
+.B gdb\c
+\&. Once started, it reads
+commands from the terminal until you tell it to exit with the GDB
+command \c
+.B quit\c
+\&. You can get online help from \c
+.B gdb\c
+\& itself
+by using the command \c
+.B help\c
+\&.
+
+You can run \c
+.B gdb\c
+\& with no arguments or options; but the most
+usual way to start GDB is with one argument or two, specifying an
+executable program as the argument:
+.sp
+.br
+gdb\ program
+.br
+.sp
+
+You can also start with both an executable program and a core file specified:
+.sp
+.br
+gdb\ program\ core
+.br
+.sp
+
+You can, instead, specify a process ID as a second argument, if you want
+to debug a running process:
+.sp
+.br
+gdb\ program\ 1234
+.br
+.sp
+
+would attach GDB to process \c
+.B 1234\c
+\& (unless you also have a file
+named `\|\c
+.B 1234\c
+\&\|'; GDB does check for a core file first).
+
+Here are some of the most frequently needed GDB commands:
+.TP
+.B break \fR[\|\fIfile\fB:\fR\|]\fIfunction
+\&
+Set a breakpoint at \c
+.I function\c
+\& (in \c
+.I file\c
+\&).
+.TP
+.B run \fR[\|\fIarglist\fR\|]
+Start your program (with \c
+.I arglist\c
+\&, if specified).
+.TP
+.B bt
+Backtrace: display the program stack.
+.TP
+.BI print " expr"\c
+\&
+Display the value of an expression.
+.TP
+.B c
+Continue running your program (after stopping, e.g. at a breakpoint).
+.TP
+.B next
+Execute next program line (after stopping); step \c
+.I over\c
+\& any
+function calls in the line.
+.TP
+.B step
+Execute next program line (after stopping); step \c
+.I into\c
+\& any
+function calls in the line.
+.TP
+.B help \fR[\|\fIname\fR\|]
+Show information about GDB command \c
+.I name\c
+\&, or general information
+about using GDB.
+.TP
+.B quit
+Exit from GDB.
+.PP
+For full details on GDB, see \c
+.I
+Using GDB: A Guide to the GNU Source-Level Debugger\c
+\&, by Richard M. Stallman and Roland H. Pesch. The same text is available online
+as the \c
+.B gdb\c
+\& entry in the \c
+.B info\c
+\& program.
+.SH OPTIONS
+Any arguments other than options specify an executable
+file and core file (or process ID); that is, the first argument
+encountered with no
+associated option flag is equivalent to a `\|\c
+.B \-se\c
+\&\|' option, and the
+second, if any, is equivalent to a `\|\c
+.B \-c\c
+\&\|' option if it's the name of a file. Many options have
+both long and short forms; both are shown here. The long forms are also
+recognized if you truncate them, so long as enough of the option is
+present to be unambiguous. (If you prefer, you can flag option
+arguments with `\|\c
+.B +\c
+\&\|' rather than `\|\c
+.B \-\c
+\&\|', though we illustrate the
+more usual convention.)
+
+All the options and command line arguments you give are processed
+in sequential order. The order makes a difference when the
+`\|\c
+.B \-x\c
+\&\|' option is used.
+
+.TP
+.B \-help
+.TP
+.B \-h
+List all options, with brief explanations.
+
+.TP
+.BI "\-symbols=" "file"\c
+.TP
+.BI "\-s " "file"\c
+\&
+Read symbol table from file \c
+.I file\c
+\&.
+
+.TP
+.BI "\-exec=" "file"\c
+.TP
+.BI "\-e " "file"\c
+\&
+Use file \c
+.I file\c
+\& as the executable file to execute when
+appropriate, and for examining pure data in conjunction with a core
+dump.
+
+.TP
+.BI "\-se=" "file"\c
+\&
+Read symbol table from file \c
+.I file\c
+\& and use it as the executable
+file.
+
+.TP
+.BI "\-core=" "file"\c
+.TP
+.BI "\-c " "file"\c
+\&
+Use file \c
+.I file\c
+\& as a core dump to examine.
+
+.TP
+.BI "\-command=" "file"\c
+.TP
+.BI "\-x " "file"\c
+\&
+Execute GDB commands from file \c
+.I file\c
+\&.
+
+.TP
+.BI "\-directory=" "directory"\c
+.TP
+.BI "\-d " "directory"\c
+\&
+Add \c
+.I directory\c
+\& to the path to search for source files.
+.PP
+
+.TP
+.B \-nx
+.TP
+.B \-n
+Do not execute commands from any `\|\c
+.B .gdbinit\c
+\&\|' initialization files.
+Normally, the commands in these files are executed after all the
+command options and arguments have been processed.
+
+
+.TP
+.B \-quiet
+.TP
+.B \-q
+``Quiet''. Do not print the introductory and copyright messages. These
+messages are also suppressed in batch mode.
+
+.TP
+.B \-kernel
+.TP
+.B \-k
+Puts GDB into kernel debugging mode. If no executable file is specified then
+/kernel is used. If no core file is specified then /dev/mem is
+used. Crash dumps can be examined by specifying both an executable and
+a core file.
+
+.TP
+.B \-wcore
+.TP
+.B \-w
+This flag is only effective when debugging a "live" kernel. It makes the
+core file (/dev/mem) writable so that kernel variables can be changed
+during a debugging session. Use this with caution !
+
+.TP
+.B \-batch
+Run in batch mode. Exit with status \c
+.B 0\c
+\& after processing all the command
+files specified with `\|\c
+.B \-x\c
+\&\|' (and `\|\c
+.B .gdbinit\c
+\&\|', if not inhibited).
+Exit with nonzero status if an error occurs in executing the GDB
+commands in the command files.
+
+Batch mode may be useful for running GDB as a filter, for example to
+download and run a program on another computer; in order to make this
+more useful, the message
+.sp
+.br
+Program\ exited\ normally.
+.br
+.sp
+
+(which is ordinarily issued whenever a program running under GDB control
+terminates) is not issued when running in batch mode.
+
+.TP
+.BI "\-cd=" "directory"\c
+\&
+Run GDB using \c
+.I directory\c
+\& as its working directory,
+instead of the current directory.
+
+.TP
+.B \-fullname
+.TP
+.B \-f
+Emacs sets this option when it runs GDB as a subprocess. It tells GDB
+to output the full file name and line number in a standard,
+recognizable fashion each time a stack frame is displayed (which
+includes each time the program stops). This recognizable format looks
+like two `\|\c
+.B \032\c
+\&\|' characters, followed by the file name, line number
+and character position separated by colons, and a newline. The
+Emacs-to-GDB interface program uses the two `\|\c
+.B \032\c
+\&\|' characters as
+a signal to display the source code for the frame.
+
+.TP
+.BI "\-b " "bps"\c
+\&
+Set the line speed (baud rate or bits per second) of any serial
+interface used by GDB for remote debugging.
+
+.TP
+.BI "\-tty=" "device"\c
+\&
+Run using \c
+.I device\c
+\& for your program's standard input and output.
+.PP
+
+.SH "SEE ALSO"
+.RB "`\|" gdb "\|'"
+entry in
+.B info\c
+\&;
+.I
+Using GDB: A Guide to the GNU Source-Level Debugger\c
+, Richard M. Stallman and Roland H. Pesch, July 1991.
+.SH COPYING
+Copyright (c) 1991 Free Software Foundation, Inc.
+.PP
+Permission is granted to make and distribute verbatim copies of
+this manual provided the copyright notice and this permission notice
+are preserved on all copies.
+.PP
+Permission is granted to copy and distribute modified versions of this
+manual under the conditions for verbatim copying, provided that the
+entire resulting derived work is distributed under the terms of a
+permission notice identical to this one.
+.PP
+Permission is granted to copy and distribute translations of this
+manual into another language, under the above conditions for modified
+versions, except that this permission notice may be included in
+translations approved by the Free Software Foundation instead of in
+the original English.
diff --git a/gnu/usr.bin/binutils/gdb/i386/freebsd-nat.c b/gnu/usr.bin/binutils/gdb/i386/freebsd-nat.c
new file mode 100644
index 0000000..90b3236
--- /dev/null
+++ b/gnu/usr.bin/binutils/gdb/i386/freebsd-nat.c
@@ -0,0 +1,619 @@
+/* Native-dependent code for BSD Unix running on i386's, for GDB.
+ Copyright 1988, 1989, 1991, 1992 Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ $Id: freebsd-nat.c,v 1.6 1995/05/09 13:59:22 rgrimes Exp $
+*/
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <signal.h>
+#include <sys/user.h>
+#include <machine/reg.h>
+#include <machine/frame.h>
+#include <sys/ptrace.h>
+
+#include "defs.h"
+
+/* this table must line up with REGISTER_NAMES in tm-i386v.h */
+/* symbols like 'tEAX' come from <machine/reg.h> */
+static int tregmap[] =
+{
+ tEAX, tECX, tEDX, tEBX,
+ tESP, tEBP, tESI, tEDI,
+ tEIP, tEFLAGS, tCS, tSS,
+ tDS, tES, tSS, tSS, /* lies: no fs or gs */
+};
+
+/* blockend is the value of u.u_ar0, and points to the
+ place where ES is stored. */
+
+int
+i386_register_u_addr (blockend, regnum)
+ int blockend;
+ int regnum;
+{
+ return (blockend + 4 * tregmap[regnum]);
+}
+
+
+#define fpstate save87
+#define U_FPSTATE(u) u.u_pcb.pcb_savefpu
+
+static void
+i387_to_double (from, to)
+ char *from;
+ char *to;
+{
+ long *lp;
+ /* push extended mode on 387 stack, then pop in double mode
+ *
+ * first, set exception masks so no error is generated -
+ * number will be rounded to inf or 0, if necessary
+ */
+ asm ("pushl %eax"); /* grab a stack slot */
+ asm ("fstcw (%esp)"); /* get 387 control word */
+ asm ("movl (%esp),%eax"); /* save old value */
+ asm ("orl $0x3f,%eax"); /* mask all exceptions */
+ asm ("pushl %eax");
+ asm ("fldcw (%esp)"); /* load new value into 387 */
+
+ asm ("movl 8(%ebp),%eax");
+ asm ("fldt (%eax)"); /* push extended number on 387 stack */
+ asm ("fwait");
+ asm ("movl 12(%ebp),%eax");
+ asm ("fstpl (%eax)"); /* pop double */
+ asm ("fwait");
+
+ asm ("popl %eax"); /* flush modified control word */
+ asm ("fnclex"); /* clear exceptions */
+ asm ("fldcw (%esp)"); /* restore original control word */
+ asm ("popl %eax"); /* flush saved copy */
+}
+
+#if 0
+static void
+double_to_i387 (from, to)
+ char *from;
+ char *to;
+{
+ /* push double mode on 387 stack, then pop in extended mode
+ * no errors are possible because every 64-bit pattern
+ * can be converted to an extended
+ */
+ asm ("movl 8(%ebp),%eax");
+ asm ("fldl (%eax)");
+ asm ("fwait");
+ asm ("movl 12(%ebp),%eax");
+ asm ("fstpt (%eax)");
+ asm ("fwait");
+}
+#endif
+
+struct env387
+{
+ unsigned short control;
+ unsigned short r0;
+ unsigned short status;
+ unsigned short r1;
+ unsigned short tag;
+ unsigned short r2;
+ unsigned long eip;
+ unsigned short code_seg;
+ unsigned short opcode;
+ unsigned long operand;
+ unsigned short operand_seg;
+ unsigned short r3;
+ unsigned char regs[8][10];
+};
+
+/* static */ void
+print_387_control_word (control)
+unsigned int control;
+{
+ printf ("control 0x%04x: ", control);
+ printf ("compute to ");
+ switch ((control >> 8) & 3)
+ {
+ case 0: printf ("24 bits; "); break;
+ case 1: printf ("(bad); "); break;
+ case 2: printf ("53 bits; "); break;
+ case 3: printf ("64 bits; "); break;
+ }
+ printf ("round ");
+ switch ((control >> 10) & 3)
+ {
+ case 0: printf ("NEAREST; "); break;
+ case 1: printf ("DOWN; "); break;
+ case 2: printf ("UP; "); break;
+ case 3: printf ("CHOP; "); break;
+ }
+ if (control & 0x3f)
+ {
+ printf ("mask:");
+ if (control & 0x0001) printf (" INVALID");
+ if (control & 0x0002) printf (" DENORM");
+ if (control & 0x0004) printf (" DIVZ");
+ if (control & 0x0008) printf (" OVERF");
+ if (control & 0x0010) printf (" UNDERF");
+ if (control & 0x0020) printf (" LOS");
+ printf (";");
+ }
+ printf ("\n");
+ if (control & 0xe080) printf ("warning: reserved bits on 0x%x\n",
+ control & 0xe080);
+}
+
+/* static */ void
+print_387_status_word (status)
+ unsigned int status;
+{
+ printf ("status 0x%04x: ", status);
+ if (status & 0xff)
+ {
+ printf ("exceptions:");
+ if (status & 0x0001) printf (" INVALID");
+ if (status & 0x0002) printf (" DENORM");
+ if (status & 0x0004) printf (" DIVZ");
+ if (status & 0x0008) printf (" OVERF");
+ if (status & 0x0010) printf (" UNDERF");
+ if (status & 0x0020) printf (" LOS");
+ if (status & 0x0040) printf (" FPSTACK");
+ printf ("; ");
+ }
+ printf ("flags: %d%d%d%d; ",
+ (status & 0x4000) != 0,
+ (status & 0x0400) != 0,
+ (status & 0x0200) != 0,
+ (status & 0x0100) != 0);
+
+ printf ("top %d\n", (status >> 11) & 7);
+}
+
+static void
+print_387_status (status, ep)
+ unsigned short status;
+ struct env387 *ep;
+{
+ int i;
+ int bothstatus;
+ int top;
+ int fpreg;
+ unsigned char *p;
+
+ bothstatus = ((status != 0) && (ep->status != 0));
+ if (status != 0)
+ {
+ if (bothstatus)
+ printf ("u: ");
+ print_387_status_word ((unsigned int)status);
+ }
+
+ if (ep->status != 0)
+ {
+ if (bothstatus)
+ printf ("e: ");
+ print_387_status_word ((unsigned int)ep->status);
+ }
+
+ print_387_control_word ((unsigned int)ep->control);
+ printf ("opcode 0x%x; ", ep->opcode);
+ printf ("pc 0x%x:0x%x; ", ep->code_seg, ep->eip);
+ printf ("operand 0x%x:0x%x\n", ep->operand_seg, ep->operand);
+
+ top = (ep->status >> 11) & 7;
+
+ printf (" regno tag msb lsb value\n");
+ for (fpreg = 7; fpreg >= 0; fpreg--)
+ {
+ int st_regno;
+ double val;
+
+ /* The physical regno `fpreg' is only relevant as an index into the
+ * tag word. Logical `%st' numbers are required for indexing ep->regs.
+ */
+ st_regno = (fpreg + 8 - top) & 7;
+
+ printf ("%%st(%d) %s ", st_regno, fpreg == top ? "=>" : " ");
+
+ switch ((ep->tag >> (fpreg * 2)) & 3)
+ {
+ case 0: printf ("valid "); break;
+ case 1: printf ("zero "); break;
+ case 2: printf ("trap "); break;
+ case 3: printf ("empty "); break;
+ }
+ for (i = 9; i >= 0; i--)
+ printf ("%02x", ep->regs[st_regno][i]);
+
+ i387_to_double (ep->regs[st_regno], (char *)&val);
+ printf (" %g\n", val);
+ }
+}
+
+void
+i386_float_info ()
+{
+ struct user u; /* just for address computations */
+ int i;
+ /* fpstate defined in <sys/user.h> */
+ struct fpstate *fpstatep;
+ char buf[sizeof (struct fpstate) + 2 * sizeof (int)];
+ unsigned int uaddr;
+ char fpvalid;
+ unsigned int rounded_addr;
+ unsigned int rounded_size;
+ /*extern int corechan;*/
+ int skip;
+ extern int inferior_pid;
+
+ uaddr = (char *)&U_FPSTATE(u) - (char *)&u;
+ if (inferior_pid)
+ {
+ int *ip;
+
+ rounded_addr = uaddr & -sizeof (int);
+ rounded_size = (((uaddr + sizeof (struct fpstate)) - uaddr) +
+ sizeof (int) - 1) / sizeof (int);
+ skip = uaddr - rounded_addr;
+
+ ip = (int *)buf;
+ for (i = 0; i < rounded_size; i++)
+ {
+ *ip++ = ptrace (PT_READ_U, inferior_pid, (caddr_t)rounded_addr, 0);
+ rounded_addr += sizeof (int);
+ }
+ }
+ else
+ {
+#if 1
+ printf("float info: can't do a core file (yet)\n");
+ return;
+#else
+ if (lseek (corechan, uaddr, 0) < 0)
+ perror_with_name ("seek on core file");
+ if (myread (corechan, buf, sizeof (struct fpstate)) < 0)
+ perror_with_name ("read from core file");
+ skip = 0;
+#endif
+ }
+
+ fpstatep = (struct fpstate *)(buf + skip);
+ print_387_status (fpstatep->sv_ex_sw, (struct env387 *)fpstatep);
+}
+
+#ifdef SETUP_ARBITRARY_FRAME
+FRAME
+setup_arbitrary_frame (numargs, args)
+int numargs;
+unsigned int *args;
+{
+ if (numargs > 2)
+ error ("Too many args in frame specification");
+ return create_new_frame ((CORE_ADDR)args[0], (CORE_ADDR)args[1]);
+}
+#endif
+
+#ifdef KERNEL_DEBUG
+#include <sys/proc.h>
+#include <sys/stat.h>
+#include <sys/fcntl.h>
+#include <unistd.h>
+
+#include <vm/vm.h>
+#include <vm/vm_param.h>
+
+#include <machine/vmparam.h>
+#include <machine/pcb.h>
+
+#define KERNOFF ((unsigned)KERNBASE)
+#define INKERNEL(x) ((x) >= KERNOFF)
+
+static CORE_ADDR sbr;
+static CORE_ADDR curpcb;
+static CORE_ADDR kstack;
+static int found_pcb;
+static int devmem;
+static int kfd;
+static struct pcb pcb;
+int read_pcb (int, CORE_ADDR);
+static CORE_ADDR kvtophys (int, CORE_ADDR);
+static physrd(int, u_int, char*, int);
+
+extern CORE_ADDR ksym_lookup(const char *);
+
+/* substitutes for the stuff in libkvm which doesn't work */
+/* most of this was taken from the old kgdb */
+
+/* we don't need all this stuff, but the call should look the same */
+kvm_open (efile, cfile, sfile, perm, errout)
+char *efile;
+char *cfile;
+char *sfile; /* makes this kvm_open more compatible to the one in libkvm */
+int perm;
+char *errout; /* makes this kvm_open more compatible to the one in libkvm */
+{
+ struct stat stb;
+ CORE_ADDR addr;
+ int cfd;
+
+ if ((cfd = open(cfile, perm, 0)) < 0)
+ return (cfd);
+
+ fstat(cfd, &stb);
+ if ((stb.st_mode & S_IFMT) == S_IFCHR && stb.st_rdev == makedev(2, 0)) {
+ devmem = 1;
+ kfd = open ("/dev/kmem", perm, 0);
+ }
+
+ physrd(cfd, ksym_lookup("IdlePTD") - KERNOFF, (char*)&sbr, sizeof sbr);
+ printf("IdlePTD %x\n", sbr);
+ curpcb = ksym_lookup("curpcb") - KERNOFF;
+ physrd(cfd, curpcb, (char*)&curpcb, sizeof curpcb);
+ kstack = ksym_lookup("kstack");
+
+ found_pcb = 1; /* for vtophys */
+ if (!devmem)
+ read_pcb(cfd, ksym_lookup("dumppcb") - KERNOFF);
+ else
+ read_pcb(cfd, kvtophys(cfd, kstack));
+
+ return (cfd);
+}
+
+kvm_close (fd)
+{
+ return (close (fd));
+}
+
+kvm_write(core_kd, memaddr, myaddr, len)
+CORE_ADDR memaddr;
+char *myaddr;
+{
+ int cc;
+
+ if (devmem) {
+ if (kfd > 0) {
+ /*
+ * Just like kvm_read, only we write.
+ */
+ errno = 0;
+ if (lseek(kfd, (off_t)memaddr, 0) < 0 && errno != 0) {
+ error("kvm_write:invalid address (%x)", memaddr);
+ return (0);
+ }
+ cc = write(kfd, myaddr, len);
+ if (cc < 0) {
+ error("kvm_write:write failed");
+ return (0);
+ } else if (cc < len)
+ error("kvm_write:short write");
+ return (cc);
+ } else
+ return (0);
+ } else {
+ printf("kvm_write not implemented for dead kernels\n");
+ return (0);
+ }
+ /* NOTREACHED */
+}
+
+kvm_read(core_kd, memaddr, myaddr, len)
+CORE_ADDR memaddr;
+char *myaddr;
+{
+ return (kernel_core_file_hook (core_kd, memaddr, myaddr, len));
+}
+
+kvm_uread(core_kd, p, memaddr, myaddr, len)
+register struct proc *p;
+CORE_ADDR memaddr;
+char *myaddr;
+{
+ register char *cp;
+ char procfile[MAXPATHLEN];
+ ssize_t amount;
+ int fd;
+
+ if (devmem) {
+ cp = myaddr;
+
+ sprintf(procfile, "/proc/%d/mem", p->p_pid);
+ fd = open(procfile, O_RDONLY, 0);
+
+ if (fd < 0) {
+ error("cannot open %s", procfile);
+ close(fd);
+ return (0);
+ }
+
+ while (len > 0) {
+ if (lseek(fd, memaddr, 0) == -1 && errno != 0) {
+ error("invalid address (%x) in %s",
+ memaddr, procfile);
+ break;
+ }
+ amount = read(fd, cp, len);
+ if (amount < 0) {
+ error("error reading %s", procfile);
+ break;
+ }
+ cp += amount;
+ memaddr += amount;
+ len -= amount;
+ }
+
+ close(fd);
+ return (ssize_t)(cp - myaddr);
+ } else {
+ return (kernel_core_file_hook (core_kd, memaddr, myaddr, len));
+ }
+}
+
+static
+physrd(cfd, addr, dat, len)
+u_int addr;
+char *dat;
+{
+ if (lseek(cfd, (off_t)addr, L_SET) == -1)
+ return (-1);
+ return (read(cfd, dat, len));
+}
+
+static CORE_ADDR
+kvtophys (fd, addr)
+CORE_ADDR addr;
+{
+ CORE_ADDR v;
+ struct pte pte;
+ static CORE_ADDR PTD = -1;
+ CORE_ADDR current_ptd;
+
+ /*
+ * If we're looking at the kernel stack,
+ * munge the address to refer to the user space mapping instead;
+ * that way we get the requested process's kstack, not the running one.
+ */
+ if (addr >= kstack && addr < kstack + ctob(UPAGES))
+ addr = (addr - kstack) + curpcb;
+
+ /*
+ * We may no longer have a linear system page table...
+ *
+ * Here's the scoop. IdlePTD contains the physical address
+ * of a page table directory that always maps the kernel.
+ * IdlePTD is in memory that is mapped 1-to-1, so we can
+ * find it easily given its 'virtual' address from ksym_lookup().
+ * For hysterical reasons, the value of IdlePTD is stored in sbr.
+ *
+ * To look up a kernel address, we first convert it to a 1st-level
+ * address and look it up in IdlePTD. This gives us the physical
+ * address of a page table page; we extract the 2nd-level part of
+ * VA and read the 2nd-level pte. Finally, we add the offset part
+ * of the VA into the physical address from the pte and return it.
+ *
+ * User addresses are a little more complicated. If we don't have
+ * a current PCB from read_pcb(), we use PTD, which is the (fixed)
+ * virtual address of the current ptd. Since it's NOT in 1-to-1
+ * kernel space, we must look it up using IdlePTD. If we do have
+ * a pcb, we get the ptd from pcb_ptd.
+ */
+
+ if (INKERNEL(addr))
+ current_ptd = sbr;
+ else if (found_pcb == 0) {
+ if (PTD == -1)
+ PTD = kvtophys(fd, ksym_lookup("PTD"));
+ current_ptd = PTD;
+ } else
+ current_ptd = pcb.pcb_ptd;
+
+ /*
+ * Read the first-level page table (ptd).
+ */
+ v = current_ptd + ((unsigned)addr >> PD_SHIFT) * sizeof pte;
+ if (physrd(fd, v, (char *)&pte, sizeof pte) < 0 || pte.pg_v == 0)
+ return (~0);
+
+ /*
+ * Read the second-level page table.
+ */
+ v = i386_ptob(pte.pg_pfnum) + ((addr&PT_MASK) >> PG_SHIFT) * sizeof pte;
+ if (physrd(fd, v, (char *) &pte, sizeof(pte)) < 0 || pte.pg_v == 0)
+ return (~0);
+
+ addr = i386_ptob(pte.pg_pfnum) + (addr & PGOFSET);
+#if 0
+ printf("vtophys(%x) -> %x\n", oldaddr, addr);
+#endif
+ return (addr);
+}
+
+read_pcb (fd, uaddr)
+CORE_ADDR uaddr;
+{
+ int i;
+ int *pcb_regs = (int *)&pcb;
+ int eip;
+
+ if (physrd(fd, uaddr, (char *)&pcb, sizeof pcb) < 0) {
+ error("cannot read pcb at %x\n", uaddr);
+ return (-1);
+ }
+ printf("current pcb at %x\n", uaddr);
+
+ /*
+ * get the register values out of the sys pcb and
+ * store them where `read_register' will find them.
+ */
+ for (i = 0; i < 8; ++i)
+ supply_register(i, &pcb_regs[i+10]);
+ supply_register(8, &pcb_regs[8]); /* eip */
+ supply_register(9, &pcb_regs[9]); /* eflags */
+ for (i = 10; i < 13; ++i) /* cs, ss, ds */
+ supply_register(i, &pcb_regs[i+9]);
+ supply_register(13, &pcb_regs[18]); /* es */
+ for (i = 14; i < 16; ++i) /* fs, gs */
+ supply_register(i, &pcb_regs[i+8]);
+
+#if 0 /* doesn't work ??? */
+ /* Hmm... */
+ if (target_read_memory(pcb_regs[5+10]+4, &eip, sizeof eip, 0))
+ error("Cannot read PC.");
+ supply_register(8, &eip); /* eip */
+#endif
+
+ /* XXX 80387 registers? */
+}
+
+/*
+ * read len bytes from kernel virtual address 'addr' into local
+ * buffer 'buf'. Return numbert of bytes if read ok, 0 otherwise. On read
+ * errors, portion of buffer not read is zeroed.
+ */
+kernel_core_file_hook(fd, addr, buf, len)
+ CORE_ADDR addr;
+ char *buf;
+ int len;
+{
+ int i;
+ CORE_ADDR paddr;
+ register char *cp;
+ int cc;
+
+ cp = buf;
+
+ while (len > 0) {
+ paddr = kvtophys(fd, addr);
+ if (paddr == ~0) {
+ bzero(buf, len);
+ break;
+ }
+ /* we can't read across a page boundary */
+ i = min(len, NBPG - (addr & PGOFSET));
+ if ((cc = physrd(fd, paddr, cp, i)) <= 0) {
+ bzero(cp, len);
+ return (cp - buf);
+ }
+ cp += cc;
+ addr += cc;
+ len -= cc;
+ }
+ return (cp - buf);
+}
+#endif /* KERNEL_DEBUG */
diff --git a/gnu/usr.bin/binutils/gdb/i386/nm.h b/gnu/usr.bin/binutils/gdb/i386/nm.h
new file mode 100644
index 0000000..ec85bd8
--- /dev/null
+++ b/gnu/usr.bin/binutils/gdb/i386/nm.h
@@ -0,0 +1,100 @@
+/* Native-dependent definitions for Intel 386 running BSD Unix, for GDB.
+ Copyright 1986, 1987, 1989, 1992 Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#ifndef NM_FREEBSD_H
+#define NM_FREEBSD_H
+
+/* Be shared lib aware */
+#include "solib.h"
+
+/* This is the amount to subtract from u.u_ar0
+ to get the offset in the core file of the register values. */
+
+#include <machine/vmparam.h>
+#define KERNEL_U_ADDR USRSTACK
+
+/* #undef FLOAT_INFO */ /* No float info yet */
+#define FLOAT_INFO extern void i386_float_info (); \
+ i386_float_info ()
+
+#define REGISTER_U_ADDR(addr, blockend, regno) \
+ (addr) = i386_register_u_addr ((blockend),(regno));
+
+extern int
+i386_register_u_addr PARAMS ((int, int));
+
+#define PTRACE_ARG3_TYPE char*
+#define ATTACH_DETACH
+#define KERNEL_DEBUG
+
+/* make structure definitions match up with those expected in solib.c */
+
+#define link_object sod
+#define lo_name sod_name
+#define lo_library sod_library
+#define lo_unused sod_reserved
+#define lo_major sod_major
+#define lo_minor sod_minor
+#define lo_next sod_next
+
+#define link_map so_map
+#define lm_addr som_addr
+#define lm_name som_path
+#define lm_next som_next
+#define lm_lop som_sod
+#define lm_lob som_sodbase
+#define lm_rwt som_write
+#define lm_ld som_dynamic
+#define lm_lpd som_spd
+
+#define link_dynamic_2 section_dispatch_table
+#define ld_loaded sdt_loaded
+#define ld_need sdt_sods
+#define ld_rules sdt_filler1
+#define ld_got sdt_got
+#define ld_plt sdt_plt
+#define ld_rel sdt_rel
+#define ld_hash sdt_hash
+#define ld_stab sdt_nzlist
+#define ld_stab_hash sdt_filler2
+#define ld_buckets sdt_buckets
+#define ld_symbols sdt_strings
+#define ld_symb_size sdt_str_sz
+#define ld_text sdt_text_sz
+#define ld_plt_sz sdt_plt_sz
+
+#define rtc_symb rt_symbol
+#define rtc_sp rt_sp
+#define rtc_next rt_next
+
+#define ld_debug so_debug
+#define ldd_version dd_version
+#define ldd_in_debugger dd_in_debugger
+#define ldd_sym_loaded dd_sym_loaded
+#define ldd_bp_addr dd_bpt_addr
+#define ldd_bp_inst dd_bpt_shadow
+#define ldd_cp dd_cc
+
+#define link_dynamic _dynamic
+#define ld_version d_version
+#define ldd d_debug
+#define ld_un d_un
+#define ld_2 d_sdt
+
+#endif /* NM_FREEBSD_H */
diff --git a/gnu/usr.bin/binutils/gdb/i386/tm.h b/gnu/usr.bin/binutils/gdb/i386/tm.h
new file mode 100644
index 0000000..1c90483
--- /dev/null
+++ b/gnu/usr.bin/binutils/gdb/i386/tm.h
@@ -0,0 +1,90 @@
+/* Macro definitions for i386 running under BSD Unix.
+ Copyright 1986, 1987, 1989, 1991, 1992, 1993 Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#ifndef _FREEBSD_TM_H_
+#define _FREEBSD_TM_H_
+/* Override number of expected traps from sysv. */
+#define START_INFERIOR_TRAPS_EXPECTED 2
+
+/* Most definitions from sysv could be used. */
+#include "tm-i386v.h"
+
+/* 386BSD cannot handle the segment registers. */
+/* BSDI can't handle them either. */
+/* FreeBSD cannot handle %fs or %gs. */
+#undef NUM_REGS
+#ifdef __FreeBSD__
+#define NUM_REGS 14
+#else
+#define NUM_REGS 10
+#endif
+
+/* On 386 bsd, sigtramp is above the user stack and immediately below
+ the user area. Using constants here allows for cross debugging.
+ These are tested for BSDI but should work on 386BSD. */
+#define SIGTRAMP_START 0xfdbfdfc0
+#define SIGTRAMP_END 0xfdbfe000
+
+/* The following redefines make backtracing through sigtramp work.
+ They manufacture a fake sigtramp frame and obtain the saved pc in sigtramp
+ from the sigcontext structure which is pushed by the kernel on the
+ user stack, along with a pointer to it. */
+
+/* FRAME_CHAIN takes a frame's nominal address and produces the frame's
+ chain-pointer.
+ In the case of the i386, the frame's nominal address
+ is the address of a 4-byte word containing the calling frame's address. */
+#undef FRAME_CHAIN
+#define FRAME_CHAIN(thisframe) \
+ (thisframe->signal_handler_caller \
+ ? thisframe->frame \
+ : (!inside_entry_file ((thisframe)->pc) \
+ ? read_memory_integer ((thisframe)->frame, 4) \
+ : 0))
+
+/* A macro that tells us whether the function invocation represented
+ by FI does not have a frame on the stack associated with it. If it
+ does not, FRAMELESS is set to 1, else 0. */
+#undef FRAMELESS_FUNCTION_INVOCATION
+#define FRAMELESS_FUNCTION_INVOCATION(FI, FRAMELESS) \
+ do { \
+ if ((FI)->signal_handler_caller) \
+ (FRAMELESS) = 0; \
+ else \
+ (FRAMELESS) = frameless_look_for_prologue(FI); \
+ } while (0)
+
+/* Saved Pc. Get it from sigcontext if within sigtramp. */
+
+/* Offset to saved PC in sigcontext, from <sys/signal.h>. */
+#define SIGCONTEXT_PC_OFFSET 20
+
+#undef FRAME_SAVED_PC
+#define FRAME_SAVED_PC(FRAME) \
+ (((FRAME)->signal_handler_caller \
+ ? sigtramp_saved_pc (FRAME) \
+ : read_memory_integer ((FRAME)->frame + 4, 4)) \
+ )
+
+#undef SETUP_ARBITRARY_FRAME
+#include "frame.h"
+extern FRAME setup_arbitrary_frame ();
+#define SETUP_ARBITRARY_FRAME setup_arbitrary_frame
+
+#endif /* _FREEBSD_TM_H_ */
diff --git a/gnu/usr.bin/binutils/gdb/i386/version.c b/gnu/usr.bin/binutils/gdb/i386/version.c
new file mode 100644
index 0000000..43f63d2
--- /dev/null
+++ b/gnu/usr.bin/binutils/gdb/i386/version.c
@@ -0,0 +1,3 @@
+char *version = "4.13";
+char *host_name = "i386-unknown-freebsd";
+char *target_name = "i386-unknown-freebsd";
diff --git a/gnu/usr.bin/binutils/gdb/i386/xm.h b/gnu/usr.bin/binutils/gdb/i386/xm.h
new file mode 100644
index 0000000..6a71227
--- /dev/null
+++ b/gnu/usr.bin/binutils/gdb/i386/xm.h
@@ -0,0 +1,29 @@
+/* Host-dependent definitions for Intel 386 running BSD Unix, for GDB.
+ Copyright 1986, 1987, 1989, 1992 Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#define HOST_BYTE_ORDER LITTLE_ENDIAN
+
+#include <machine/limits.h> /* for INT_MIN, to avoid "INT_MIN
+ redefined" warnings from defs.h */
+
+/* psignal() is in <signal.h>. */
+
+#define PSIGNAL_IN_SIGNAL_H
+
+#define HAVE_TERMIOS
diff --git a/gnu/usr.bin/cc/Makefile b/gnu/usr.bin/cc/Makefile
index 74e88b8..8be131e 100644
--- a/gnu/usr.bin/cc/Makefile
+++ b/gnu/usr.bin/cc/Makefile
@@ -1,8 +1,8 @@
#
-# $FreeBSD$
+# $Id: Makefile,v 1.4 1994/11/15 04:51:20 phk Exp $
#
-PGMDIR= cc_int cpp cc1 cc cc1plus c++ libgcc
+PGMDIR= cc_int cpp cc1 cc cc1plus c++ f77 libgcc doc
SUBDIR= $(PGMDIR)
.include <bsd.subdir.mk>
diff --git a/gnu/usr.bin/cc/Makefile.inc b/gnu/usr.bin/cc/Makefile.inc
index 95525cb..16d12bf 100644
--- a/gnu/usr.bin/cc/Makefile.inc
+++ b/gnu/usr.bin/cc/Makefile.inc
@@ -1,11 +1,30 @@
#
-# $FreeBSD$
+# $Id: Makefile.inc,v 1.12 1995/03/10 19:39:32 davidg Exp $
#
CFLAGS+= -I${.CURDIR} -I${.CURDIR}/../include
CFLAGS+= -Dbsd4_4
CFLAGS+= -DGCC_INCLUDE_DIR=\"FOO\"
-CFLAGS+= -DDEFAULT_TARGET_VERSION=\"2.6.0\"
+CFLAGS+= -DTOOL_INCLUDE_DIR=\"FOO\"
+CFLAGS+= -DGPLUSPLUS_INCLUDE_DIR=\"FOO\"
+CFLAGS+= -DDEFAULT_TARGET_VERSION=\"2.6.3\"
CFLAGS+= -DDEFAULT_TARGET_MACHINE=\"i386--freebsd\"
-CFLAGS+= -DMD_EXEC_PREFIX=\"/usr/libexec/\"
-CFLAGS+= -DSTANDARD_STARTFILE_PREFIX=\"/usr/lib\"
+CFLAGS+= -DSTANDARD_EXEC_PREFIX=\"/usr/libexec/\"
+CFLAGS+= -DSTANDARD_STARTFILE_PREFIX=\"/usr/lib/\"
+CFLAGS+= -DHAVE_PUTENV
+CFLAGS+= -DGCC_NAME=\"cc\"
+CFLAGS+= -DLINK_LIBGCC_SPECIAL_1
+
+.if exists(${.CURDIR}/../cc_int/obj)
+LIBDESTDIR= ${.CURDIR}/../cc_int/obj
+.else
+LIBDESTDIR= ${.CURDIR}/../cc_int
+.endif
+
+# XXX LDDESTDIR isn't a directory and there is no standard name for the dir
+LDDESTDIR= -L${LIBDESTDIR}
+.if defined(SHARED_LIBCC_INT)
+LIBCC_INT= ${LIBDESTDIR}/libcc_int.so.263.0
+.else
+LIBCC_INT= ${LIBDESTDIR}/libcc_int.a
+.endif
diff --git a/gnu/usr.bin/cc/README b/gnu/usr.bin/cc/README
index 01303ea..e47729a 100644
--- a/gnu/usr.bin/cc/README
+++ b/gnu/usr.bin/cc/README
@@ -1,5 +1,5 @@
-$FreeBSD$
+$Id$
This directory contains gcc in a form that uses "bmake" makefiles.
This is not the place you want to start, if you want to hack gcc.
diff --git a/gnu/usr.bin/cc/c++/Makefile b/gnu/usr.bin/cc/c++/Makefile
index 71fb59e..5557c62 100644
--- a/gnu/usr.bin/cc/c++/Makefile
+++ b/gnu/usr.bin/cc/c++/Makefile
@@ -1,13 +1,11 @@
#
-# $FreeBSD$
+# $Id$
#
PROG = c++
SRCS = g++.c
BINDIR= /usr/bin
+LINKS= ${BINDIR}/c++ ${BINDIR}/g++
NOMAN= 1
-LDDESTDIR+= -L${.CURDIR}/../cc_int/obj
-LDDESTDIR+= -L${.CURDIR}/../cc_int
-LDADD+= -lcc_int
.include <bsd.prog.mk>
diff --git a/gnu/usr.bin/cc/c++/g++.c b/gnu/usr.bin/cc/c++/g++.c
index fcd1029..0991b35 100644
--- a/gnu/usr.bin/cc/c++/g++.c
+++ b/gnu/usr.bin/cc/c++/g++.c
@@ -40,6 +40,7 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
#include <stdio.h>
#include <sys/types.h>
#include <sys/file.h> /* May get R_OK, etc. on some systems. */
+#include <errno.h>
/* Defined to the name of the compiler; if using a cross compiler, the
Makefile should compile this file with the proper name
@@ -78,8 +79,12 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
#endif
#endif
-extern int errno, sys_nerr;
-#if defined(bsd4_4) || defined(__NetBSD__)
+#ifndef errno
+extern int errno;
+#endif
+
+extern int sys_nerr;
+#if defined(bsd4_4) || defined(__NetBSD__) || defined(__FreeBSD__)
extern const char *const sys_errlist[];
#else
extern char *sys_errlist[];
@@ -253,7 +258,7 @@ choose_temp_base ()
base = choose_temp_base_try ("/usr/tmp", base);
base = choose_temp_base_try ("/tmp", base);
- /* If all else fails, use the current directory! */
+ /* If all else fails, use the current directory! */
if (base == (char *)0)
base = "./";
@@ -320,7 +325,7 @@ run_dos (program, argv)
i = system (scmd);
remove (rf);
-
+
if (i == -1)
perror_exec (program);
}
@@ -373,7 +378,7 @@ main (argc, argv)
programname = p;
if (argc == 1)
- fatal ("No input files specified.\n");
+ fatal ("No input files specified");
#ifndef __MSDOS__
/* We do a little magic to find out where the main gcc executable
@@ -390,7 +395,7 @@ main (argc, argv)
#endif
args = (int *) malloc (argc * sizeof (int));
- bzero (args, argc * sizeof (int));
+ bzero ((char *) args, argc * sizeof (int));
for (i = 1; i < argc; i++)
{
@@ -420,7 +425,7 @@ main (argc, argv)
if (argc == 2)
{
/* If they only gave us `-v', don't try to link
- in libg++. */
+ in libg++. */
added--;
library = NULL;
}
@@ -431,7 +436,7 @@ main (argc, argv)
&& (char *)strchr ("bBVDUoeTuIYmLiA", argv[i][1]) != NULL)
|| strcmp (argv[i], "-Tdata") == 0))
quote = argv[i];
- else if (((argv[i][2] == '\0'
+ else if (library != NULL && ((argv[i][2] == '\0'
&& (char *) strchr ("cSEM", argv[i][1]) != NULL)
|| strcmp (argv[i], "-MM") == 0))
{
@@ -446,10 +451,13 @@ main (argc, argv)
}
else
{
- int len;
+ int len;
if (saw_speclang)
- continue;
+ {
+ saw_speclang = 0;
+ continue;
+ }
/* If the filename ends in .c or .i, put options around it.
But not if a specified -x option is currently active. */
diff --git a/gnu/usr.bin/cc/cc/Makefile b/gnu/usr.bin/cc/cc/Makefile
index c6f0112..6ac463f 100644
--- a/gnu/usr.bin/cc/cc/Makefile
+++ b/gnu/usr.bin/cc/cc/Makefile
@@ -1,18 +1,13 @@
#
-# $FreeBSD$
+# $Id: Makefile,v 1.8 1994/12/26 19:15:19 ats Exp $
#
PROG = cc
SRCS = gcc.c
BINDIR= /usr/bin
-MLINKS+=cc.1 gcc.1
-MLINKS+=cc.1 c++.1
-MLINKS+=cc.1 g++.1
-LDDESTDIR+= -L${.CURDIR}/../cc_int/obj
-LDDESTDIR+= -L${.CURDIR}/../cc_int
-LDADD+= -lcc_int
-
-afterinstall:
- cd $(DESTDIR)$(BINDIR) ; rm gcc ; ln -s cc gcc
+.PATH: ${.CURDIR}/../cc_int
+SRCS+= obstack.c version.c
+LINKS= ${BINDIR}/cc ${BINDIR}/gcc
+MLINKS= cc.1 gcc.1 cc.1 c++.1 cc.1 g++.1
.include <bsd.prog.mk>
diff --git a/gnu/usr.bin/cc/cc/cc.1 b/gnu/usr.bin/cc/cc/cc.1
index 223115c..7eca1bb 100644
--- a/gnu/usr.bin/cc/cc/cc.1
+++ b/gnu/usr.bin/cc/cc/cc.1
@@ -20,7 +20,7 @@
.if n .sp
.if t .sp 0.4
..
-.Id $Id: gcc.1,v 1.4 1993/10/13 23:19:12 pesch Exp $
+.Id $Id: cc.1,v 1.3 1995/12/26 01:34:18 bde Exp $
.TH GCC 1 "\*(Dt" "GNU Tools" "GNU Tools"
.SH NAME
gcc, g++ \- GNU project C and C++ Compiler (v2.6)
@@ -438,7 +438,17 @@ in the following sections.
\-m486
\-mno\-486
\-msoft\-float
+\-mrtd
+\-mregparm
+\-msvr3\-shlib
+\-mno\-ieee\-fp
\-mno\-fp\-ret\-in\-387
+\-mfancy\-math\-387
+\-mno\-wide\-multiply
+\-mdebug\-addr
+\-mno\-move
+\-mprofiler\-epilogue
+\-reg\-alloc=LIST
.Sp
.I HPPA Options
.br
@@ -3490,6 +3500,7 @@ assembler files (with a `\|\c
These `\|\c
.B \-m\c
\&\|' options are defined for the Intel 80386 family of computers:
+.TP
.B \-m486
.TP
.B \-mno\-486
@@ -3526,6 +3537,11 @@ The option `\|\c
.B \-mno-fp-ret-in-387\c
\&\|' causes such values to be returned
in ordinary CPU registers instead.
+.TP
+.B \-mprofiler-epilogue
+.TP
+.B \-mno-profiler-epilogue
+Generate extra code to write profile information for function exits.
.PP
These `\|\c
.B \-m\c
@@ -4061,7 +4077,7 @@ if available, else
.B /tmp\c
\&).
.SH "SEE ALSO"
-cpp(1), as(1), ld(1), gdb(1), adb(1), dbx(1), sdb(1).
+cpp(1), as(1), ld(1), gdb(1).
.br
.RB "`\|" gcc "\|', `\|" cpp \|',
.RB "`\|" as "\|', `\|" ld \|',
diff --git a/gnu/usr.bin/cc/cc/gcc.c b/gnu/usr.bin/cc/cc/gcc.c
index 4f877ec..152c579 100644
--- a/gnu/usr.bin/cc/cc/gcc.c
+++ b/gnu/usr.bin/cc/cc/gcc.c
@@ -31,10 +31,17 @@ Once it knows which kind of compilation to perform, the procedure for
compilation is specified by a string called a "spec". */
#include <sys/types.h>
+#include <sys/wait.h>
#include <ctype.h>
#include <signal.h>
#include <sys/stat.h>
+#include <errno.h>
+
+#ifndef WINNT
#include <sys/file.h> /* May get R_OK, etc. on some systems. */
+#else
+#include <process.h>
+#endif
#include "config.h"
#include "obstack.h"
@@ -44,6 +51,9 @@ compilation is specified by a string called a "spec". */
#include <varargs.h>
#endif
#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
/* Include multi-lib information. */
#include "multilib.h"
@@ -54,6 +64,19 @@ compilation is specified by a string called a "spec". */
#define X_OK 1
#endif
+#ifndef WIFSIGNALED
+#define WIFSIGNALED(S) (((S) & 0xff) != 0 && ((S) & 0xff) != 0x7f)
+#endif
+#ifndef WTERMSIG
+#define WTERMSIG(S) ((S) & 0x7f)
+#endif
+#ifndef WIFEXITED
+#define WIFEXITED(S) (((S) & 0xff) == 0)
+#endif
+#ifndef WEXITSTATUS
+#define WEXITSTATUS(S) (((S) & 0xff00) >> 8)
+#endif
+
/* Add prototype support. */
#ifndef PROTO
#if defined (USE_PROTOTYPES) ? USE_PROTOTYPES : defined (__STDC__)
@@ -81,6 +104,11 @@ compilation is specified by a string called a "spec". */
#define NULL 0
#endif
+/* Define O_RDONLY if the system hasn't defined it for us. */
+#ifndef O_RDONLY
+#define O_RDONLY 0
+#endif
+
#ifndef GENERIC_PTR
#if defined (USE_PROTOTYPES) ? USE_PROTOTYPES : defined (__STDC__)
#define GENERIC_PTR void *
@@ -125,14 +153,24 @@ compilation is specified by a string called a "spec". */
#define PATH_SEPARATOR ':'
#endif
+#ifndef DIR_SEPARATOR
+#define DIR_SEPARATOR '/'
+#endif
+
+static char dir_separator_str[] = {DIR_SEPARATOR, 0};
+
#define obstack_chunk_alloc xmalloc
#define obstack_chunk_free free
extern void free ();
extern char *getenv ();
-extern int errno, sys_nerr;
-#if defined(bsd4_4) || defined(__NetBSD__)
+#ifndef errno
+extern int errno;
+#endif
+
+extern int sys_nerr;
+#if defined(bsd4_4) || defined(__NetBSD__) || defined (__FreeBSD__)
extern const char *const sys_errlist[];
#else
extern char *sys_errlist[];
@@ -229,7 +267,11 @@ static void choose_temp_base PROTO((void));
static int check_live_switch PROTO((int, int));
static char *handle_braces PROTO((char *));
static char *save_string PROTO((char *, int));
-static char *concat PROTO((char *, char *, char *));
+static char *concat PROTO((char *, char *));
+static char *concat3 PROTO((char *, char *, char *));
+static char *concat4 PROTO((char *, char *, char *, char *));
+static char *concat6 PROTO((char *, char *, char *, char *, char *, \
+ char *));
static int do_spec PROTO((char *));
static int do_spec_1 PROTO((char *, int, char *));
static char *find_file PROTO((char *));
@@ -310,6 +352,7 @@ or with constant text in a single argument.
%x{OPTION} Accumulate an option for %X.
%X Output the accumulated linker options specified by compilations.
%Y Output the accumulated assembler options specified by compilations.
+ %Z Output the accumulated preprocessor options specified by compilations.
%v1 Substitute the major version number of GCC.
(For version 2.5.n, this is 2.)
%v2 Substitute the minor version number of GCC.
@@ -319,7 +362,7 @@ or with constant text in a single argument.
%A process ASM_FINAL_SPEC as a spec. A capital A is actually
used here. This can be used to run a post-processor after the
assembler has done it's job.
- %D Dump out a -L option for each directory in startfile_prefix.
+ %D Dump out a -L option for each directory in startfile_prefixes.
If multilib_dir is set, extra entries are generated with it affixed.
%l process LINK_SPEC as a spec.
%L process LIB_SPEC as a spec.
@@ -425,7 +468,7 @@ proper position among the other output files. */
/* config.h can define STARTFILE_SPEC to override the default crt0 files. */
#ifndef STARTFILE_SPEC
#define STARTFILE_SPEC \
- "%{pg:gcrt0.o%s}%{!pg:%{p:mcrt0.o%s}%{!p:crt0.o%s}}"
+ "%{!shared:%{pg:gcrt0.o%s}%{!pg:%{p:mcrt0.o%s}%{!p:crt0.o%s}}}"
#endif
/* config.h can define SWITCHES_NEED_SPACES to control passing -o and -L.
@@ -535,7 +578,7 @@ static struct compiler default_compilers[] =
%{!undef:%{!ansi:%p} %P} %{trigraphs} \
%c %{O*:%{!O0:-D__OPTIMIZE__}} %{traditional} %{ftraditional:-traditional}\
%{traditional-cpp:-traditional}\
- %{g*} %{W*} %{w} %{pedantic*} %{H} %{d*} %C %{D*} %{U*} %{i*}\
+ %{g*} %{W*} %{w} %{pedantic*} %{H} %{d*} %C %{D*} %{U*} %{i*} %Z\
%i %{!M:%{!MM:%{!E:%{!pipe:%g.i}}}}%{E:%W{o*}}%{M:%W{o*}}%{MM:%W{o*}} |\n",
"%{!M:%{!MM:%{!E:cc1 %{!pipe:%g.i} %1 \
%{!Q:-quiet} -dumpbase %b.c %{d*} %{m*} %{a}\
@@ -556,7 +599,7 @@ static struct compiler default_compilers[] =
%{!undef:%{!ansi:%p} %P} %{trigraphs}\
%c %{O*:%{!O0:-D__OPTIMIZE__}} %{traditional} %{ftraditional:-traditional}\
%{traditional-cpp:-traditional}\
- %{g*} %{W*} %{w} %{pedantic*} %{H} %{d*} %C %{D*} %{U*} %{i*}\
+ %{g*} %{W*} %{w} %{pedantic*} %{H} %{d*} %C %{D*} %{U*} %{i*} %Z\
%i %W{o*}}\
%{!E:%e-E required when input is from standard input}"},
{".m", "@objective-c"},
@@ -569,7 +612,7 @@ static struct compiler default_compilers[] =
%{!undef:%{!ansi:%p} %P} %{trigraphs}\
%c %{O*:%{!O0:-D__OPTIMIZE__}} %{traditional} %{ftraditional:-traditional}\
%{traditional-cpp:-traditional}\
- %{g*} %{W*} %{w} %{pedantic*} %{H} %{d*} %C %{D*} %{U*} %{i*}\
+ %{g*} %{W*} %{w} %{pedantic*} %{H} %{d*} %C %{D*} %{U*} %{i*} %Z\
%i %{!M:%{!MM:%{!E:%{!pipe:%g.i}}}}%{E:%W{o*}}%{M:%W{o*}}%{MM:%W{o*}} |\n",
"%{!M:%{!MM:%{!E:cc1obj %{!pipe:%g.i} %1 \
%{!Q:-quiet} -dumpbase %b.m %{d*} %{m*} %{a}\
@@ -593,11 +636,12 @@ static struct compiler default_compilers[] =
%{!undef:%{!ansi:%p} %P} %{trigraphs}\
%c %{O*:%{!O0:-D__OPTIMIZE__}} %{traditional} %{ftraditional:-traditional}\
%{traditional-cpp:-traditional}\
- %{g*} %{W*} %{w} %{pedantic*} %{H} %{d*} %C %{D*} %{U*} %{i*}\
+ %{g*} %{W*} %{w} %{pedantic*} %{H} %{d*} %C %{D*} %{U*} %{i*} %Z\
%i %W{o*}"},
{".cc", "@c++"},
{".cxx", "@c++"},
{".cpp", "@c++"},
+ {".c++", "@c++"},
{".C", "@c++"},
{"@c++",
"cpp -lang-c++ %{nostdinc*} %{C} %{v} %{A*} %{I*} %{P} %I\
@@ -607,7 +651,7 @@ static struct compiler default_compilers[] =
%{ansi:-trigraphs -$ -D__STRICT_ANSI__} %{!undef:%{!ansi:%p} %P}\
%c %{O*:%{!O0:-D__OPTIMIZE__}} %{traditional} %{ftraditional:-traditional}\
%{traditional-cpp:-traditional} %{trigraphs}\
- %{g*} %{W*} %{w} %{pedantic*} %{H} %{d*} %C %{D*} %{U*} %{i*}\
+ %{g*} %{W*} %{w} %{pedantic*} %{H} %{d*} %C %{D*} %{U*} %{i*} %Z\
%i %{!M:%{!MM:%{!E:%{!pipe:%g.ii}}}}%{E:%W{o*}}%{M:%W{o*}}%{MM:%W{o*}} |\n",
"%{!M:%{!MM:%{!E:cc1plus %{!pipe:%g.ii} %1 %2\
%{!Q:-quiet} -dumpbase %b.cc %{d*} %{m*} %{a}\
@@ -654,7 +698,7 @@ static struct compiler default_compilers[] =
-undef -$ %{!undef:%p %P} -D__ASSEMBLER__ \
%c %{O*:%{!O0:-D__OPTIMIZE__}} %{traditional} %{ftraditional:-traditional}\
%{traditional-cpp:-traditional}\
- %{g*} %{W*} %{w} %{pedantic*} %{H} %{d*} %C %{D*} %{U*} %{i*}\
+ %{g*} %{W*} %{w} %{pedantic*} %{H} %{d*} %C %{D*} %{U*} %{i*} %Z\
%i %{!M:%{!MM:%{!E:%{!pipe:%g.s}}}}%{E:%W{o*}}%{M:%W{o*}}%{MM:%W{o*}} |\n",
"%{!M:%{!MM:%{!E:%{!S:as %{R} %{j} %{J} %{h} %{d2} %a %Y\
%{c:%W{o*}%{!o*:-o %w%b.o}}%{!c:-o %d%w%u.o}\
@@ -671,6 +715,35 @@ static struct compiler default_compilers[] =
%{!S:%{!gnatc:%{!gnats:as %{R} %{j} %{J} %{h} %{d2} %a %Y\
%{c:%W{o*}%{!o*:-o %w%b.o}}\
%{!c:-o %d%w%u.o} %{!pipe:%g.s} %A\n}}}}}} "},
+/***** ljo's Fortran rule *****/
+ {".f", "@f2c"},
+ {"@f2c",
+ "f2c %{checksubscripts:-C} %{I2} %{onetrip} %{honorcase:-U} %{u} %{w}\
+ %{ANSIC:-A} %{a} %{C++}\
+ %{c} %{E} %{ec} %{ext} %{f} %{72} %{g} %{h} %{i2} %{kr}\
+ %{P} %{p} %{r} %{r8} %{s} %{w8} %{z} %{N*}\
+ %i %{!pipe: -o %g.c} %{pipe:-o -}|\n",
+ "cpp -lang-c %{nostdinc*} %{C} %{v} %{A*} %{I*} %{P} %I\
+ %{C:%{!E:%eGNU C does not support -C without using -E}}\
+ %{M} %{MM} %{MD:-MD %b.d} %{MMD:-MMD %b.d} %{MG}\
+ -undef -D__GNUC__=%v1 -D__GNUC_MINOR__=%v2\
+ %{ansi:-trigraphs -$ -D__STRICT_ANSI__}\
+ %{!undef:%{!ansi:%p} %P} %{trigraphs} \
+ %c %{O*:%{!O0:-D__OPTIMIZE__}} %{traditional} %{ftraditional:-traditional}\
+ %{traditional-cpp:-traditional}\
+ %{g*} %{W*} %{w} %{pedantic*} %{H} %{d*} %C %{D*} %{U*} %{i*}\
+ %{pipe:-} %{!pipe:%g.c} %{!M:%{!MM:%{!E:%{!pipe:%g.i}}}}%{E:%W{o*}}%{M:%W{o*}}%{MM:%W{o*}} |\n",
+ "%{!M:%{!MM:%{!E:cc1 %{!pipe:%g.i} %1 \
+ %{!Q:-quiet} -dumpbase %b.c %{d*} %{m*} %{a}\
+ %{g*} %{O*} %{W*} %{w} %{pedantic*} %{ansi} \
+ %{traditional} %{v:-version} %{pg:-p} %{p} %{f*}\
+ %{aux-info*}\
+ %{pg:%{fomit-frame-pointer:%e-pg and -fomit-frame-pointer are incompatible}}\
+ %{S:%W{o*}%{!o*:-o %b.s}}%{!S:-o %{|!pipe:%g.s}} |\n\
+ %{!S:as %{R} %{j} %{J} %{h} %{d2} %a %Y\
+ %{c:%W{o*}%{!o*:-o %w%b.o}}%{!c:-o %d%w%u.o}\
+ %{!pipe:%g.s} %A\n }}}}"},
+/***** End of ljo's Fortran rule *****/
/* Mark end of table */
{0, 0}
};
@@ -717,16 +790,22 @@ static char *link_command_spec = "\
#endif
/* A vector of options to give to the linker.
- These options are accumulated by -Xlinker and -Wl,
+ These options are accumulated by %x,
and substituted into the linker command with %X. */
static int n_linker_options;
static char **linker_options;
/* A vector of options to give to the assembler.
These options are accumulated by -Wa,
- and substituted into the assembler command with %X. */
+ and substituted into the assembler command with %Y. */
static int n_assembler_options;
static char **assembler_options;
+
+/* A vector of options to give to the preprocessor.
+ These options are accumulated by -Wp,
+ and substituted into the preprocessor command with %Z. */
+static int n_preprocessor_options;
+static char **preprocessor_options;
/* Define how to map long options into short ones. */
@@ -741,7 +820,7 @@ struct option_map
a => argument required.
o => argument optional.
j => join argument to equivalent, making one word.
- * => allow other text after NAME as an argument. */
+ * => require other text after NAME as an argument. */
char *arg_info;
};
@@ -750,76 +829,74 @@ struct option_map
struct option_map option_map[] =
{
- {"--profile-blocks", "-a", 0},
- {"--target", "-b", "a"},
+ {"--all-warnings", "-Wall", 0},
+ {"--ansi", "-ansi", 0},
+ {"--assemble", "-S", 0},
+ {"--assert", "-A", "a"},
+ {"--comments", "-C", 0},
{"--compile", "-c", 0},
+ {"--debug", "-g", "oj"},
+ {"--define-macro", "-D", "a"},
+ {"--dependencies", "-M", 0},
{"--dump", "-d", "a"},
+ {"--dumpbase", "-dumpbase", "a"},
{"--entry", "-e", 0},
- {"--debug", "-g", "oj"},
- {"--include", "-include", "a"},
+ {"--extra-warnings", "-W", 0},
+ {"--for-assembler", "-Wa", "a"},
+ {"--for-linker", "-Xlinker", "a"},
+ {"--force-link", "-u", "a"},
{"--imacros", "-imacros", "a"},
- {"--include-prefix", "-iprefix", "a"},
+ {"--include", "-include", "a"},
+ {"--include-barrier", "-I-", 0},
+ {"--include-directory", "-I", "a"},
{"--include-directory-after", "-idirafter", "a"},
+ {"--include-prefix", "-iprefix", "a"},
{"--include-with-prefix", "-iwithprefix", "a"},
{"--include-with-prefix-before", "-iwithprefixbefore", "a"},
{"--include-with-prefix-after", "-iwithprefix", "a"},
- {"--machine-", "-m", "*j"},
+ {"--language", "-x", "a"},
+ {"--library-directory", "-L", "a"},
{"--machine", "-m", "aj"},
+ {"--machine-", "-m", "*j"},
+ {"--no-line-commands", "-P", 0},
+ {"--no-precompiled-includes", "-noprecomp", 0},
{"--no-standard-includes", "-nostdinc", 0},
{"--no-standard-libraries", "-nostdlib", 0},
- {"--no-precompiled-includes", "-noprecomp", 0},
- {"--output", "-o", "a"},
- {"--profile", "-p", 0},
- {"--quiet", "-q", 0},
- {"--silent", "-q", 0},
- {"--force-link", "-u", "a"},
- {"--verbose", "-v", 0},
- {"--version", "-dumpversion", 0},
{"--no-warnings", "-w", 0},
- {"--language", "-x", "a"},
-
- {"--assert", "-A", "a"},
- {"--prefix", "-B", "a"},
- {"--comments", "-C", 0},
- {"--define-macro", "-D", "a"},
- {"--preprocess", "-E", 0},
- {"--trace-includes", "-H", 0},
- {"--include-directory", "-I", "a"},
- {"--include-barrier", "-I-", 0},
- {"--library-directory", "-L", "a"},
- {"--dependencies", "-M", 0},
- {"--user-dependencies", "-MM", 0},
- {"--write-dependencies", "-MD", 0},
- {"--write-user-dependencies", "-MMD", 0},
- {"--print-missing-file-dependencies", "-MG", 0},
{"--optimize", "-O", "oj"},
- {"--no-line-commands", "-P", 0},
- {"--assemble", "-S", 0},
- {"--undefine-macro", "-U", "a"},
- {"--use-version", "-V", "a"},
- {"--for-assembler", "-Wa", "a"},
- {"--extra-warnings", "-W", 0},
- {"--all-warnings", "-Wall", 0},
- {"--warn-", "-W", "*j"},
- {"--for-linker", "-Xlinker", "a"},
-
- {"--ansi", "-ansi", 0},
- {"--traditional", "-traditional", 0},
- {"--traditional-cpp", "-traditional-cpp", 0},
- {"--trigraphs", "-trigraphs", 0},
- {"--pipe", "-pipe", 0},
- {"--dumpbase", "-dumpbase", "a"},
+ {"--output", "-o", "a"},
{"--pedantic", "-pedantic", 0},
{"--pedantic-errors", "-pedantic-errors", 0},
- {"--save-temps", "-save-temps", 0},
- {"--print-libgcc-file-name", "-print-libgcc-file-name", 0},
+ {"--pipe", "-pipe", 0},
+ {"--prefix", "-B", "a"},
+ {"--preprocess", "-E", 0},
{"--print-file-name", "-print-file-name=", "aj"},
- {"--print-prog-name", "-print-prog-name=", "aj"},
+ {"--print-libgcc-file-name", "-print-libgcc-file-name", 0},
+ {"--print-missing-file-dependencies", "-MG", 0},
{"--print-multi-lib", "-print-multi-lib", 0},
{"--print-multi-directory", "-print-multi-directory", 0},
- {"--static", "-static", 0},
+ {"--print-prog-name", "-print-prog-name=", "aj"},
+ {"--profile", "-p", 0},
+ {"--profile-blocks", "-a", 0},
+ {"--quiet", "-q", 0},
+ {"--save-temps", "-save-temps", 0},
{"--shared", "-shared", 0},
+ {"--silent", "-q", 0},
+ {"--static", "-static", 0},
{"--symbolic", "-symbolic", 0},
+ {"--target", "-b", "a"},
+ {"--trace-includes", "-H", 0},
+ {"--traditional", "-traditional", 0},
+ {"--traditional-cpp", "-traditional-cpp", 0},
+ {"--trigraphs", "-trigraphs", 0},
+ {"--undefine-macro", "-U", "a"},
+ {"--use-version", "-V", "a"},
+ {"--user-dependencies", "-MM", 0},
+ {"--verbose", "-v", 0},
+ {"--version", "-dumpversion", 0},
+ {"--warn-", "-W", "*j"},
+ {"--write-dependencies", "-MD", 0},
+ {"--write-user-dependencies", "-MMD", 0},
{"--", "-f", "*j"}
};
@@ -832,7 +909,7 @@ translate_options (argcp, argvp)
int *argcp;
char ***argvp;
{
- int i, j;
+ int i, j, k;
int argc = *argcp;
char **argv = *argvp;
char **newv = (char **) xmalloc ((argc + 2) * 2 * sizeof (char *));
@@ -850,49 +927,74 @@ translate_options (argcp, argvp)
for (j = 0; j < sizeof (option_map) / sizeof (option_map[0]); j++)
{
int optlen = strlen (option_map[j].name);
- int complen = strlen (argv[i]);
+ int arglen = strlen (argv[i]);
+ int complen = arglen > optlen ? optlen : arglen;
char *arginfo = option_map[j].arg_info;
if (arginfo == 0)
arginfo = "";
- if (complen > optlen)
- complen = optlen;
+
if (!strncmp (argv[i], option_map[j].name, complen))
{
- int extra = strlen (argv[i]) > optlen;
char *arg = 0;
- if (extra)
+ if (arglen < optlen)
+ {
+ for (k = j + 1;
+ k < sizeof (option_map) / sizeof (option_map[0]);
+ k++)
+ if (strlen (option_map[k].name) >= arglen
+ && !strncmp (argv[i], option_map[k].name, arglen))
+ {
+ error ("Ambiguous abbreviation %s", argv[i]);
+ break;
+ }
+
+ if (k != sizeof (option_map) / sizeof (option_map[0]))
+ break;
+ }
+
+ if (arglen > optlen)
{
/* If the option has an argument, accept that. */
if (argv[i][optlen] == '=')
arg = argv[i] + optlen + 1;
- /* If this mapping allows extra text at end of name,
+
+ /* If this mapping requires extra text at end of name,
accept that as "argument". */
else if (index (arginfo, '*') != 0)
arg = argv[i] + optlen;
+
/* Otherwise, extra text at end means mismatch.
Try other mappings. */
else
continue;
}
+
else if (index (arginfo, '*') != 0)
- error ("Incomplete `%s' option", option_map[j].name);
+ {
+ error ("Incomplete `%s' option", option_map[j].name);
+ break;
+ }
/* Handle arguments. */
- if (index (arginfo, 'o') != 0)
+ if (index (arginfo, 'a') != 0)
{
if (arg == 0)
{
if (i + 1 == argc)
- error ("Missing argument to `%s' option",
- option_map[j].name);
+ {
+ error ("Missing argument to `%s' option",
+ option_map[j].name);
+ break;
+ }
+
arg = argv[++i];
}
}
else if (index (arginfo, '*') != 0)
;
- else if (index (arginfo, 'a') == 0)
+ else if (index (arginfo, 'o') == 0)
{
if (arg != 0)
error ("Extraneous argument to `%s' option",
@@ -902,8 +1004,7 @@ translate_options (argcp, argvp)
/* Store the translation as one argv elt or as two. */
if (arg != 0 && index (arginfo, 'j') != 0)
- newv[newindex++] = concat (option_map[j].equivalent,
- arg, "");
+ newv[newindex++] = concat (option_map[j].equivalent, arg);
else if (arg != 0)
{
newv[newindex++] = option_map[j].equivalent;
@@ -917,6 +1018,7 @@ translate_options (argcp, argvp)
}
i++;
}
+
/* Handle old-fashioned options--just copy them through,
with their arguments. */
else if (argv[i][0] == '-')
@@ -982,7 +1084,7 @@ read_specs (filename)
fprintf (stderr, "Reading specs from %s\n", filename);
/* Open and stat the file. */
- desc = open (filename, 0, 0);
+ desc = open (filename, O_RDONLY, 0);
if (desc < 0)
pfatal_with_name (filename);
if (stat (filename, &statbuf) < 0)
@@ -1142,7 +1244,7 @@ set_spec (name, spec)
old_spec = sl->spec;
if (name && spec[0] == '+' && isspace (spec[1]))
- sl->spec = concat (old_spec, spec + 1, "");
+ sl->spec = concat (old_spec, spec + 1);
else
sl->spec = save_string (spec, strlen (spec));
@@ -1237,15 +1339,15 @@ struct path_prefix
/* List of prefixes to try when looking for executables. */
-static struct path_prefix exec_prefix = { 0, 0, "exec" };
+static struct path_prefix exec_prefixes = { 0, 0, "exec" };
/* List of prefixes to try when looking for startup (crt0) files. */
-static struct path_prefix startfile_prefix = { 0, 0, "startfile" };
+static struct path_prefix startfile_prefixes = { 0, 0, "startfile" };
/* List of prefixes to try when looking for include files. */
-static struct path_prefix include_prefix = { 0, 0, "include" };
+static struct path_prefix include_prefixes = { 0, 0, "include" };
/* Suffix to attach to directories searched for commands.
This looks like `MACHINE/VERSION/'. */
@@ -1495,18 +1597,21 @@ choose_temp_base ()
base = choose_temp_base_try (P_tmpdir, base);
#endif
- base = choose_temp_base_try ("/usr/tmp", base);
- base = choose_temp_base_try ("/tmp", base);
+ base = choose_temp_base_try (concat4 (dir_separator_str, "usr",
+ dir_separator_str, "tmp"),
+ base);
+ base = choose_temp_base_try (concat (dir_separator_str, "tmp"), base);
- /* If all else fails, use the current directory! */
- if (base == (char *)0)
- base = "./";
+ /* If all else fails, use the current directory! */
+ if (base == (char *)0) base = concat(".", dir_separator_str);
len = strlen (base);
- temp_filename = xmalloc (len + sizeof("/ccXXXXXX") + 1);
+ temp_filename = xmalloc (len + strlen (concat (dir_separator_str,
+ "ccXXXXXX")) + 1);
strcpy (temp_filename, base);
- if (len > 0 && temp_filename[len-1] != '/')
- temp_filename[len++] = '/';
+ if (len > 0 && temp_filename[len-1] != '/'
+ && temp_filename[len-1] != DIR_SEPARATOR)
+ temp_filename[len++] = DIR_SEPARATOR;
strcpy (temp_filename + len, "ccXXXXXX");
mktemp (temp_filename);
@@ -1537,7 +1642,6 @@ putenv (str)
char **envp;
int num_envs = 0;
int name_len = 1;
- int str_len = strlen (str);
char *p = str;
int ch;
@@ -1595,7 +1699,7 @@ putenv_from_prefixes (paths, env_var)
{
if (!first_time)
obstack_1grow (&collect_obstack, PATH_SEPARATOR);
-
+
first_time = FALSE;
obstack_grow (&collect_obstack, pprefix->prefix, len);
obstack_grow (&collect_obstack, machine_suffix, suffix_len);
@@ -1607,7 +1711,7 @@ putenv_from_prefixes (paths, env_var)
{
if (!first_time)
obstack_1grow (&collect_obstack, PATH_SEPARATOR);
-
+
first_time = FALSE;
obstack_grow (&collect_obstack, pprefix->prefix, len);
obstack_grow (&collect_obstack, just_machine_suffix,
@@ -1650,7 +1754,7 @@ find_a_file (pprefix, name, mode)
/* Determine the filename to execute (special case for absolute paths). */
- if (*name == '/')
+ if (*name == '/' || *name == DIR_SEPARATOR)
{
if (access (name, mode))
{
@@ -1870,13 +1974,9 @@ static int last_pipe_input;
NOT_LAST is nonzero if this is not the last subcommand
(i.e. its output should be piped to the next one.) */
-#ifndef OS2
#ifdef __MSDOS__
-/* Declare these to avoid compilation error. They won't be called. */
-int execv(const char *a, const char **b){}
-int execvp(const char *a, const char **b){}
-
+#include <process.h>
static int
pexecute (search_flag, program, argv, not_last)
int search_flag;
@@ -1884,6 +1984,9 @@ pexecute (search_flag, program, argv, not_last)
char *argv[];
int not_last;
{
+#ifdef __GO32__
+ int i = (search_flag ? spawnv : spawnvp) (1, program, argv);
+#else
char *scmd, *rf;
FILE *argfile;
int i, el = search_flag ? 0 : 4;
@@ -1912,17 +2015,19 @@ pexecute (search_flag, program, argv, not_last)
i = system (scmd);
remove (rf);
-
+#endif
+
if (i == -1)
{
perror_exec (program);
return MIN_FATAL_STATUS << 8;
}
-
return i << 8;
}
-#else /* not __MSDOS__ */
+#endif
+
+#if !defined(__MSDOS__) && !defined(OS2) && !defined(WINNT)
static int
pexecute (search_flag, program, argv, not_last)
@@ -2012,8 +2117,54 @@ pexecute (search_flag, program, argv, not_last)
}
}
-#endif /* not __MSDOS__ */
-#else /* not OS2 */
+#endif /* not __MSDOS__ and not OS2 */
+
+#if defined(OS2) || defined(WINNT)
+
+#ifdef WINNT
+
+char **
+fix_argv (argvec)
+ char **argvec
+{
+ int i;
+
+ for (i = 1; argvec[i] != 0; i++)
+ {
+ int len, j;
+ char *temp, *newtemp;
+
+ temp = argvec[i];
+ len = strlen (temp);
+ for (j = 0; j < len; j++)
+ {
+ if (temp[j] == '"')
+ {
+ newtemp = xmalloc (len + 2);
+ strncpy (newtemp, temp, j);
+ newtemp [j] = '\\';
+ strncpy (&newtemp [j+1], &temp [j], len-j);
+ newtemp [len+1] = 0;
+ free (temp);
+ temp = newtemp;
+ len++;
+ j++;
+ }
+ }
+
+ argvec[i] = temp;
+ }
+
+ return argvec;
+}
+
+#define FIX_ARGV(a) fix_argv(a)
+
+#else
+
+#define FIX_ARGV(a) a
+
+#endif /* OS2 or WINNT */
static int
pexecute (search_flag, program, argv, not_last)
@@ -2022,9 +2173,10 @@ pexecute (search_flag, program, argv, not_last)
char *argv[];
int not_last;
{
- return (search_flag ? spawnv : spawnvp) (1, program, argv);
+ return (search_flag ? spawnv : spawnvp) (1, program, FIX_ARGV (argv));
}
-#endif /* not OS2 */
+#endif /* OS2 or WINNT */
+
/* Execute the command specified by the arguments on the current line of spec.
When using pipes, this includes several piped-together commands
@@ -2062,7 +2214,7 @@ execute ()
commands[0].prog = argbuf[0]; /* first command. */
commands[0].argv = &argbuf[0];
- string = find_a_file (&exec_prefix, commands[0].prog, X_OK);
+ string = find_a_file (&exec_prefixes, commands[0].prog, X_OK);
if (string)
commands[0].argv[0] = string;
@@ -2075,7 +2227,7 @@ execute ()
argbuf[i] = 0; /* termination of command args. */
commands[n_commands].prog = argbuf[i + 1];
commands[n_commands].argv = &argbuf[i + 1];
- string = find_a_file (&exec_prefix, commands[n_commands].prog, X_OK);
+ string = find_a_file (&exec_prefixes, commands[n_commands].prog, X_OK);
if (string)
commands[n_commands].argv[0] = string;
n_commands++;
@@ -2145,8 +2297,12 @@ execute ()
#ifdef __MSDOS__
status = pid = commands[i].pid;
#else
+#ifdef WINNT
+ pid = cwait (&status, commands[i].pid, WAIT_CHILD);
+#else
pid = wait (&status);
#endif
+#endif
if (pid < 0)
abort ();
@@ -2157,13 +2313,15 @@ execute ()
if (commands[j].pid == pid)
prog = commands[j].prog;
- if ((status & 0x7F) != 0)
+ if (WIFSIGNALED (status))
{
fatal ("Internal compiler error: program %s got fatal signal %d",
- prog, (status & 0x7F));
+ prog, WTERMSIG (status));
signal_count++;
+ ret_code = -1;
}
- if (((status & 0xFF00) >> 8) >= MIN_FATAL_STATUS)
+ else if (WIFEXITED (status)
+ && WEXITSTATUS (status) >= MIN_FATAL_STATUS)
ret_code = -1;
}
}
@@ -2244,8 +2402,8 @@ process_command (argc, argv)
if (gcc_exec_prefix)
{
- add_prefix (&exec_prefix, gcc_exec_prefix, 0, 0, NULL_PTR);
- add_prefix (&startfile_prefix, gcc_exec_prefix, 0, 0, NULL_PTR);
+ add_prefix (&exec_prefixes, gcc_exec_prefix, 0, 0, NULL_PTR);
+ add_prefix (&startfile_prefixes, gcc_exec_prefix, 0, 0, NULL_PTR);
}
/* COMPILER_PATH and LIBRARY_PATH have values
@@ -2264,17 +2422,15 @@ process_command (argc, argv)
{
strncpy (nstore, startp, endp-startp);
if (endp == startp)
+ strcpy (nstore, concat (".", dir_separator_str));
+ else if (endp[-1] != '/' && endp[-1] != DIR_SEPARATOR)
{
- strcpy (nstore, "./");
- }
- else if (endp[-1] != '/')
- {
- nstore[endp-startp] = '/';
+ nstore[endp-startp] = DIR_SEPARATOR;
nstore[endp-startp+1] = 0;
}
else
nstore[endp-startp] = 0;
- add_prefix (&exec_prefix, nstore, 0, 0, NULL_PTR);
+ add_prefix (&exec_prefixes, nstore, 0, 0, NULL_PTR);
if (*endp == 0)
break;
endp = startp = endp + 1;
@@ -2285,7 +2441,7 @@ process_command (argc, argv)
}
temp = getenv ("LIBRARY_PATH");
- if (temp)
+ if (temp && ! cross_compile)
{
char *startp, *endp;
char *nstore = (char *) alloca (strlen (temp) + 3);
@@ -2297,17 +2453,15 @@ process_command (argc, argv)
{
strncpy (nstore, startp, endp-startp);
if (endp == startp)
+ strcpy (nstore, concat (".", dir_separator_str));
+ else if (endp[-1] != '/' && endp[-1] != DIR_SEPARATOR)
{
- strcpy (nstore, "./");
- }
- else if (endp[-1] != '/')
- {
- nstore[endp-startp] = '/';
+ nstore[endp-startp] = DIR_SEPARATOR;
nstore[endp-startp+1] = 0;
}
else
nstore[endp-startp] = 0;
- add_prefix (&startfile_prefix, nstore, 0, 0, NULL_PTR);
+ add_prefix (&startfile_prefixes, nstore, 0, 0, NULL_PTR);
if (*endp == 0)
break;
endp = startp = endp + 1;
@@ -2319,7 +2473,7 @@ process_command (argc, argv)
/* Use LPATH like LIBRARY_PATH (for the CMU build program). */
temp = getenv ("LPATH");
- if (temp)
+ if (temp && ! cross_compile)
{
char *startp, *endp;
char *nstore = (char *) alloca (strlen (temp) + 3);
@@ -2331,17 +2485,15 @@ process_command (argc, argv)
{
strncpy (nstore, startp, endp-startp);
if (endp == startp)
+ strcpy (nstore, concat (".", dir_separator_str));
+ else if (endp[-1] != '/' && endp[-1] != DIR_SEPARATOR)
{
- strcpy (nstore, "./");
- }
- else if (endp[-1] != '/')
- {
- nstore[endp-startp] = '/';
+ nstore[endp-startp] = DIR_SEPARATOR;
nstore[endp-startp+1] = 0;
}
else
nstore[endp-startp] = 0;
- add_prefix (&startfile_prefix, nstore, 0, 0, NULL_PTR);
+ add_prefix (&startfile_prefixes, nstore, 0, 0, NULL_PTR);
if (*endp == 0)
break;
endp = startp = endp + 1;
@@ -2384,6 +2536,11 @@ process_command (argc, argv)
printf ("%s\n", version_string);
exit (0);
}
+ else if (! strcmp (argv[i], "-dumpmachine"))
+ {
+ printf ("%s\n", spec_machine);
+ exit (0);
+ }
else if (! strcmp (argv[i], "-print-libgcc-file-name"))
print_file_name = "libgcc.a";
else if (! strncmp (argv[i], "-print-file-name=", 17))
@@ -2394,54 +2551,6 @@ process_command (argc, argv)
print_multi_lib = 1;
else if (! strcmp (argv[i], "-print-multi-directory"))
print_multi_directory = 1;
- else if (! strcmp (argv[i], "-Xlinker"))
- {
- /* Pass the argument of this option to the linker when we link. */
-
- if (i + 1 == argc)
- fatal ("argument to `-Xlinker' is missing");
-
- n_linker_options++;
- if (!linker_options)
- linker_options
- = (char **) xmalloc (n_linker_options * sizeof (char **));
- else
- linker_options
- = (char **) xrealloc (linker_options,
- n_linker_options * sizeof (char **));
-
- linker_options[n_linker_options - 1] = argv[++i];
- }
- else if (! strncmp (argv[i], "-Wl,", 4))
- {
- int prev, j;
- /* Pass the rest of this option to the linker when we link. */
-
- n_linker_options++;
- if (!linker_options)
- linker_options
- = (char **) xmalloc (n_linker_options * sizeof (char **));
- else
- linker_options
- = (char **) xrealloc (linker_options,
- n_linker_options * sizeof (char **));
-
- /* Split the argument at commas. */
- prev = 4;
- for (j = 4; argv[i][j]; j++)
- if (argv[i][j] == ',')
- {
- linker_options[n_linker_options - 1]
- = save_string (argv[i] + prev, j - prev);
- n_linker_options++;
- linker_options
- = (char **) xrealloc (linker_options,
- n_linker_options * sizeof (char **));
- prev = j + 1;
- }
- /* Record the part after the last comma. */
- linker_options[n_linker_options - 1] = argv[i] + prev;
- }
else if (! strncmp (argv[i], "-Wa,", 4))
{
int prev, j;
@@ -2472,10 +2581,57 @@ process_command (argc, argv)
/* Record the part after the last comma. */
assembler_options[n_assembler_options - 1] = argv[i] + prev;
}
+ else if (! strncmp (argv[i], "-Wp,", 4))
+ {
+ int prev, j;
+ /* Pass the rest of this option to the preprocessor. */
+
+ n_preprocessor_options++;
+ if (!preprocessor_options)
+ preprocessor_options
+ = (char **) xmalloc (n_preprocessor_options * sizeof (char **));
+ else
+ preprocessor_options
+ = (char **) xrealloc (preprocessor_options,
+ n_preprocessor_options * sizeof (char **));
+
+ /* Split the argument at commas. */
+ prev = 4;
+ for (j = 4; argv[i][j]; j++)
+ if (argv[i][j] == ',')
+ {
+ preprocessor_options[n_preprocessor_options - 1]
+ = save_string (argv[i] + prev, j - prev);
+ n_preprocessor_options++;
+ preprocessor_options
+ = (char **) xrealloc (preprocessor_options,
+ n_preprocessor_options * sizeof (char **));
+ prev = j + 1;
+ }
+ /* Record the part after the last comma. */
+ preprocessor_options[n_preprocessor_options - 1] = argv[i] + prev;
+ }
else if (argv[i][0] == '+' && argv[i][1] == 'e')
/* The +e options to the C++ front-end. */
n_switches++;
- else if (argv[i][0] == '-' && argv[i][1] != 0 && argv[i][1] != 'l')
+ else if (strncmp (argv[i], "-Wl,", 4) == 0)
+ {
+ int j;
+ /* Split the argument at commas. */
+ for (j = 3; argv[i][j]; j++)
+ n_infiles += (argv[i][j] == ',');
+ }
+ else if (strcmp (argv[i], "-Xlinker") == 0)
+ {
+ if (i + 1 == argc)
+ fatal ("argument to `-Xlinker' is missing");
+
+ n_infiles++;
+ i++;
+ }
+ else if (strncmp (argv[i], "-l", 2) == 0)
+ n_infiles++;
+ else if (argv[i][0] == '-' && argv[i][1] != 0)
{
register char *p = &argv[i][1];
register int c = *p;
@@ -2501,21 +2657,34 @@ process_command (argc, argv)
value = argv[++i];
else
value = p + 1;
- add_prefix (&exec_prefix, value, 1, 0, temp);
- add_prefix (&startfile_prefix, value, 1, 0, temp);
- add_prefix (&include_prefix, concat (value, "include", ""),
+ add_prefix (&exec_prefixes, value, 1, 0, temp);
+ add_prefix (&startfile_prefixes, value, 1, 0, temp);
+ add_prefix (&include_prefixes, concat (value, "include"),
1, 0, 0);
/* As a kludge, if the arg is "[foo/]stageN/", just add
- "[foo/]stageN/../include" to the include prefix. */
+ "[foo/]include" to the include prefix. */
{
int len = strlen (value);
- if ((len == 7 || (len > 7 && value[len - 8] == '/'))
+ if ((len == 7
+ || (len > 7
+ && (value[len - 8] == '/'
+ || value[len - 8] == DIR_SEPARATOR)))
&& strncmp (value + len - 7, "stage", 5) == 0
&& isdigit (value[len - 2])
- && value[len - 1] == '/')
- add_prefix (&include_prefix,
- concat (value, "../include", ""), 1, 0, 0);
+ && (value[len - 1] == '/'
+ || value[len - 1] == DIR_SEPARATOR))
+ {
+ if (len == 7)
+ add_prefix (&include_prefixes, "include", 1, 0, 0);
+ else
+ {
+ char *string = xmalloc (len + 1);
+ strncpy (string, value, len-7);
+ strcat (string, "include");
+ add_prefix (&include_prefixes, string, 1, 0, 0);
+ }
+ }
}
}
break;
@@ -2565,46 +2734,42 @@ process_command (argc, argv)
(such as cpp) rather than those of the host system. */
/* Use 2 as fourth arg meaning try just the machine as a suffix,
as well as trying the machine and the version. */
- add_prefix (&exec_prefix, standard_exec_prefix, 0, 2, NULL_PTR);
- add_prefix (&exec_prefix, standard_exec_prefix_1, 0, 2, NULL_PTR);
+ add_prefix (&exec_prefixes, "/usr/libexec/", 0, 0, NULL_PTR);
+ add_prefix (&exec_prefixes, "/usr/bin/", 0, 0, NULL_PTR);
- add_prefix (&startfile_prefix, standard_exec_prefix, 0, 1, NULL_PTR);
- add_prefix (&startfile_prefix, standard_exec_prefix_1, 0, 1, NULL_PTR);
+ tooldir_prefix = concat3 (tooldir_base_prefix, spec_machine,
+ dir_separator_str);
- tooldir_prefix = concat (tooldir_base_prefix, spec_machine, "/");
-
- /* If tooldir is relative, base it on exec_prefix. A relative
+ /* If tooldir is relative, base it on exec_prefixes. A relative
tooldir lets us move the installed tree as a unit.
If GCC_EXEC_PREFIX is defined, then we want to add two relative
directories, so that we can search both the user specified directory
and the standard place. */
- if (*tooldir_prefix != '/')
+ if (*tooldir_prefix != '/' && *tooldir_prefix != DIR_SEPARATOR)
{
if (gcc_exec_prefix)
{
char *gcc_exec_tooldir_prefix
- = concat (concat (gcc_exec_prefix, spec_machine, "/"),
- concat (spec_version, "/", tooldir_prefix),
- "");
+ = concat6 (gcc_exec_prefix, spec_machine, dir_separator_str,
+ spec_version, dir_separator_str, tooldir_prefix);
- add_prefix (&exec_prefix, concat (gcc_exec_tooldir_prefix, "bin", "/"),
+ add_prefix (&exec_prefixes,
+ concat3 (gcc_exec_tooldir_prefix, "bin",
+ dir_separator_str),
0, 0, NULL_PTR);
- add_prefix (&startfile_prefix, concat (gcc_exec_tooldir_prefix, "lib", "/"),
+ add_prefix (&startfile_prefixes,
+ concat3 (gcc_exec_tooldir_prefix, "lib",
+ dir_separator_str),
0, 0, NULL_PTR);
}
- tooldir_prefix = concat (concat (standard_exec_prefix, spec_machine, "/"),
- concat (spec_version, "/", tooldir_prefix),
- "");
+ tooldir_prefix = concat6 (standard_exec_prefix, spec_machine,
+ dir_separator_str, spec_version,
+ dir_separator_str, tooldir_prefix);
}
- add_prefix (&exec_prefix, concat (tooldir_prefix, "bin", "/"),
- 0, 0, NULL_PTR);
- add_prefix (&startfile_prefix, concat (tooldir_prefix, "lib", "/"),
- 0, 0, NULL_PTR);
-
/* More prefixes are enabled in main, after we read the specs file
and determine whether this is cross-compilation or not. */
@@ -2625,11 +2790,9 @@ process_command (argc, argv)
for (i = 1; i < argc; i++)
{
/* Just skip the switches that were handled by the preceding loop. */
- if (!strcmp (argv[i], "-Xlinker"))
- i++;
- else if (! strncmp (argv[i], "-Wl,", 4))
+ if (! strncmp (argv[i], "-Wa,", 4))
;
- else if (! strncmp (argv[i], "-Wa,", 4))
+ else if (! strncmp (argv[i], "-Wp,", 4))
;
else if (! strcmp (argv[i], "-print-libgcc-file-name"))
;
@@ -2654,7 +2817,34 @@ process_command (argc, argv)
switches[n_switches].valid = 0;
n_switches++;
}
- else if (argv[i][0] == '-' && argv[i][1] != 0 && argv[i][1] != 'l')
+ else if (strncmp (argv[i], "-Wl,", 4) == 0)
+ {
+ int prev, j;
+ /* Split the argument at commas. */
+ prev = 4;
+ for (j = 4; argv[i][j]; j++)
+ if (argv[i][j] == ',')
+ {
+ infiles[n_infiles].language = spec_lang;
+ infiles[n_infiles++].name
+ = save_string (argv[i] + prev, j - prev);
+ prev = j + 1;
+ }
+ /* Record the part after the last comma. */
+ infiles[n_infiles].language = spec_lang;
+ infiles[n_infiles++].name = argv[i] + prev;
+ }
+ else if (strcmp (argv[i], "-Xlinker") == 0)
+ {
+ infiles[n_infiles].language = spec_lang;
+ infiles[n_infiles++].name = argv[++i];
+ }
+ else if (strncmp (argv[i], "-l", 2) == 0)
+ {
+ infiles[n_infiles].language = spec_lang;
+ infiles[n_infiles++].name = argv[i];
+ }
+ else if (argv[i][0] == '-' && argv[i][1] != 0)
{
register char *p = &argv[i][1];
register int c = *p;
@@ -2727,9 +2917,7 @@ process_command (argc, argv)
}
else
{
- if ((argv[i][0] != '-' || argv[i][1] != 'l')
- && strcmp (argv[i], "-")
- && access (argv[i], R_OK) < 0)
+ if (strcmp (argv[i], "-") != 0 && access (argv[i], R_OK) < 0)
{
perror_with_name (argv[i]);
error_count++;
@@ -2755,9 +2943,9 @@ process_command (argc, argv)
+ strlen (spec_machine) + 3);
strcpy (temp, gcc_exec_prefix);
strcat (temp, spec_machine);
- strcat (temp, "/");
+ strcat (temp, dir_separator_str);
strcat (temp, spec_version);
- strcat (temp, "/");
+ strcat (temp, dir_separator_str);
gcc_exec_prefix = temp;
}
}
@@ -2969,7 +3157,7 @@ do_spec_1 (spec, inswitch, soft_matched_part)
that we search for startfiles. */
case 'D':
{
- struct prefix_list *pl = startfile_prefix.plist;
+ struct prefix_list *pl = startfile_prefixes.plist;
int bufsize = 100;
char *buffer = (char *) xmalloc (bufsize);
int idx;
@@ -2982,7 +3170,7 @@ do_spec_1 (spec, inswitch, soft_matched_part)
/* Relative directories always come from -B,
and it is better not to use them for searching
at run time. In particular, stage1 loses */
- if (pl->prefix[0] != '/')
+ if (pl->prefix[0] != '/' && pl->prefix[0] != DIR_SEPARATOR)
continue;
#endif
/* Try subdirectory if there is one. */
@@ -3039,7 +3227,8 @@ do_spec_1 (spec, inswitch, soft_matched_part)
buffer = (char *) xrealloc (buffer, bufsize);
strcpy (buffer, machine_suffix);
idx = strlen (buffer);
- if (buffer[idx - 1] == '/')
+ if (buffer[idx - 1] == '/'
+ || buffer[idx - 1] == DIR_SEPARATOR)
buffer[idx - 1] = 0;
do_spec_1 (buffer, 1, NULL_PTR);
/* Make this a separate argument. */
@@ -3060,7 +3249,8 @@ do_spec_1 (spec, inswitch, soft_matched_part)
buffer = (char *) xrealloc (buffer, bufsize);
strcpy (buffer, pl->prefix);
idx = strlen (buffer);
- if (buffer[idx - 1] == '/')
+ if (buffer[idx - 1] == '/'
+ || buffer[idx - 1] == DIR_SEPARATOR)
buffer[idx - 1] = 0;
do_spec_1 (buffer, 1, NULL_PTR);
/* Make this a separate argument. */
@@ -3158,7 +3348,7 @@ do_spec_1 (spec, inswitch, soft_matched_part)
case 'I':
{
- struct prefix_list *pl = include_prefix.plist;
+ struct prefix_list *pl = include_prefixes.plist;
if (gcc_exec_prefix)
{
@@ -3247,8 +3437,7 @@ do_spec_1 (spec, inswitch, soft_matched_part)
}
break;
- /* Dump out the options accumulated previously using %x,
- -Xlinker and -Wl,. */
+ /* Dump out the options accumulated previously using %x. */
case 'X':
for (i = 0; i < n_linker_options; i++)
{
@@ -3268,6 +3457,16 @@ do_spec_1 (spec, inswitch, soft_matched_part)
}
break;
+ /* Dump out the options accumulated previously using -Wp,. */
+ case 'Z':
+ for (i = 0; i < n_preprocessor_options; i++)
+ {
+ do_spec_1 (preprocessor_options[i], 1, NULL_PTR);
+ /* Make each accumulated option a separate argument. */
+ do_spec_1 (" ", 0, NULL_PTR);
+ }
+ break;
+
/* Here are digits and numbers that just process
a certain constant string as a spec. */
@@ -3576,7 +3775,7 @@ do_spec_1 (spec, inswitch, soft_matched_part)
{
int c1 = *p++; /* Select first or second version number. */
char *v = compiler_version;
- char *q, *copy;
+ char *q;
/* If desired, advance to second version number. */
if (c1 == '2')
{
@@ -3928,10 +4127,10 @@ find_file (name)
try = (char *) alloca (strlen (multilib_dir) + strlen (name) + 2);
strcpy (try, multilib_dir);
- strcat (try, "/");
+ strcat (try, dir_separator_str);
strcat (try, name);
- newname = find_a_file (&startfile_prefix, try, R_OK);
+ newname = find_a_file (&startfile_prefixes, try, R_OK);
/* If we don't find it in the multi library dir, then fall
through and look for it in the normal places. */
@@ -3939,7 +4138,7 @@ find_file (name)
return newname;
}
- newname = find_a_file (&startfile_prefix, name, R_OK);
+ newname = find_a_file (&startfile_prefixes, name, R_OK);
return newname ? newname : name;
}
@@ -3971,15 +4170,20 @@ is_directory (path1, path2, linker)
bcopy (path1, path, len1);
bcopy (path2, path + len1, len2);
cp = path + len1 + len2;
- if (cp[-1] != '/')
- *cp++ = '/';
+ if (cp[-1] != '/' && cp[-1] != DIR_SEPARATOR)
+ *cp++ = DIR_SEPARATOR;
*cp++ = '.';
*cp = '\0';
/* Exclude directories that the linker is known to search. */
if (linker
- && ((cp - path == 6 && strcmp (path, "/lib/.") == 0)
- || (cp - path == 10 && strcmp (path, "/usr/lib/.") == 0)))
+ && ((cp - path == 6
+ && strcmp (path, concat4 (dir_separator_str, "lib",
+ dir_separator_str, ".")) == 0)
+ || (cp - path == 10
+ && strcmp (path, concat6 (dir_separator_str, "usr",
+ dir_separator_str, "lib",
+ dir_separator_str, ".")) == 0)))
return 0;
return (stat (path, &st) >= 0 && S_ISDIR (st.st_mode));
@@ -4013,7 +4217,7 @@ main (argc, argv)
char *p;
p = argv[0] + strlen (argv[0]);
- while (p != argv[0] && p[-1] != '/') --p;
+ while (p != argv[0] && p[-1] != '/' && p[-1] != DIR_SEPARATOR) --p;
programname = p;
if (signal (SIGINT, SIG_IGN) != SIG_IGN)
@@ -4062,10 +4266,7 @@ main (argc, argv)
/* Read specs from a file if there is one. */
- machine_suffix = concat (spec_machine, "/", concat (spec_version, "/", ""));
- just_machine_suffix = concat (spec_machine, "/", "");
-
- specs_file = find_a_file (&startfile_prefix, "specs", R_OK);
+ specs_file = find_a_file (&startfile_prefixes, "specs", R_OK);
/* Read the specs file unless it is a default one. */
if (specs_file != 0 && strcmp (specs_file, "specs"))
read_specs (specs_file);
@@ -4077,47 +4278,39 @@ main (argc, argv)
if (!cross_compile)
{
#ifdef MD_EXEC_PREFIX
- add_prefix (&exec_prefix, md_exec_prefix, 0, 0, NULL_PTR);
- add_prefix (&startfile_prefix, md_exec_prefix, 0, 0, NULL_PTR);
+ add_prefix (&exec_prefixes, md_exec_prefix, 0, 0, NULL_PTR);
+ add_prefix (&startfile_prefixes, md_exec_prefix, 0, 0, NULL_PTR);
#endif
#ifdef MD_STARTFILE_PREFIX
- add_prefix (&startfile_prefix, md_startfile_prefix, 0, 0, NULL_PTR);
+ add_prefix (&startfile_prefixes, md_startfile_prefix, 0, 0, NULL_PTR);
#endif
#ifdef MD_STARTFILE_PREFIX_1
- add_prefix (&startfile_prefix, md_startfile_prefix_1, 0, 0, NULL_PTR);
+ add_prefix (&startfile_prefixes, md_startfile_prefix_1, 0, 0, NULL_PTR);
#endif
/* If standard_startfile_prefix is relative, base it on
standard_exec_prefix. This lets us move the installed tree
as a unit. If GCC_EXEC_PREFIX is defined, base
standard_startfile_prefix on that as well. */
- if (*standard_startfile_prefix == '/')
- add_prefix (&startfile_prefix, standard_startfile_prefix, 0, 0,
+ if (*standard_startfile_prefix == '/'
+ || *standard_startfile_prefix == DIR_SEPARATOR)
+ add_prefix (&startfile_prefixes, standard_startfile_prefix, 0, 0,
NULL_PTR);
else
{
if (gcc_exec_prefix)
- add_prefix (&startfile_prefix,
- concat (gcc_exec_prefix,
- standard_startfile_prefix,
- ""),
+ add_prefix (&startfile_prefixes,
+ concat (gcc_exec_prefix, standard_startfile_prefix),
0, 0, NULL_PTR);
- add_prefix (&startfile_prefix,
- concat (standard_exec_prefix,
- machine_suffix,
- standard_startfile_prefix),
+ add_prefix (&startfile_prefixes,
+ concat3 (standard_exec_prefix,
+ machine_suffix,
+ standard_startfile_prefix),
0, 0, NULL_PTR);
- }
-
- add_prefix (&startfile_prefix, standard_startfile_prefix_1, 0, 0,
- NULL_PTR);
- add_prefix (&startfile_prefix, standard_startfile_prefix_2, 0, 0,
- NULL_PTR);
-#if 0 /* Can cause surprises, and one can use -B./ instead. */
- add_prefix (&startfile_prefix, "./", 0, 1, NULL_PTR);
-#endif
+ }
+
}
/* Now we have the specs.
@@ -4145,7 +4338,7 @@ main (argc, argv)
if (print_prog_name)
{
- char *newname = find_a_file (&exec_prefix, print_prog_name, X_OK);
+ char *newname = find_a_file (&exec_prefixes, print_prog_name, X_OK);
printf ("%s\n", (newname ? newname : print_prog_name));
exit (0);
}
@@ -4173,7 +4366,7 @@ main (argc, argv)
}
if (n_infiles == 0)
- fatal ("No input files");
+ fatal ("No input files specified");
/* Make a place to record the compiler output file names
that correspond to the input files. */
@@ -4215,7 +4408,7 @@ main (argc, argv)
input_basename = input_filename;
for (p = input_filename; *p; p++)
- if (*p == '/')
+ if (*p == '/' || *p == DIR_SEPARATOR)
input_basename = p + 1;
/* Find a suffix starting with the last period,
@@ -4280,8 +4473,8 @@ main (argc, argv)
/* Rebuild the COMPILER_PATH and LIBRARY_PATH environment variables
for collect. */
- putenv_from_prefixes (&exec_prefix, "COMPILER_PATH=");
- putenv_from_prefixes (&startfile_prefix, "LIBRARY_PATH=");
+ putenv_from_prefixes (&exec_prefixes, "COMPILER_PATH=");
+ putenv_from_prefixes (&startfile_prefixes, "LIBRARY_PATH=");
/* Build COLLECT_GCC_OPTIONS to have all of the options specified to
the compiler. */
@@ -4316,8 +4509,8 @@ main (argc, argv)
}
/* Warn if a -B option was specified but the prefix was never used. */
- unused_prefix_warnings (&exec_prefix);
- unused_prefix_warnings (&startfile_prefix);
+ unused_prefix_warnings (&exec_prefixes);
+ unused_prefix_warnings (&startfile_prefixes);
/* If options said don't run linker,
complain about input files to be given to the linker. */
@@ -4374,8 +4567,16 @@ lookup_compiler (name, length, language)
||
(strlen (cp->suffix) < length
/* See if the suffix matches the end of NAME. */
+#ifdef OS2
+ && (!strcmp (cp->suffix,
+ name + length - strlen (cp->suffix))
+ || !strpbrk (cp->suffix, "ABCDEFGHIJKLMNOPQRSTUVWXYZ")
+ && !strcasecmp (cp->suffix,
+ name + length - strlen (cp->suffix)))))
+#else
&& !strcmp (cp->suffix,
name + length - strlen (cp->suffix))))
+#endif
{
if (cp->spec[0][0] == '@')
{
@@ -4420,24 +4621,45 @@ xrealloc (ptr, size)
return value;
}
-/* Return a newly-allocated string whose contents concatenate those of s1, s2, s3. */
+/* Return a newly-allocated string whose contents concatenate those of s1, s2 */
static char *
-concat (s1, s2, s3)
- char *s1, *s2, *s3;
+concat (s1, s2)
+ char *s1, *s2;
{
- int len1 = strlen (s1), len2 = strlen (s2), len3 = strlen (s3);
- char *result = xmalloc (len1 + len2 + len3 + 1);
+ int len1 = strlen (s1);
+ int len2 = strlen (s2);
+ char *result = xmalloc (len1 + len2 + 1);
strcpy (result, s1);
strcpy (result + len1, s2);
- strcpy (result + len1 + len2, s3);
- *(result + len1 + len2 + len3) = 0;
+ *(result + len1 + len2) = 0;
return result;
}
static char *
+concat3 (s1, s2, s3)
+ char *s1, *s2, *s3;
+{
+ return concat (concat (s1, s2), s3);
+}
+
+static char *
+concat4 (s1, s2, s3, s4)
+ char *s1, *s2, *s3, *s4;
+{
+ return concat (concat (s1, s2), concat (s3, s4));
+}
+
+static char *
+concat6 (s1, s2, s3, s4, s5, s6)
+ char *s1, *s2, *s3, *s4, *s5, *s6;
+{
+ return concat3 (concat (s1, s2), concat (s3, s4), concat (s5, s6));
+}
+
+static char *
save_string (s, len)
char *s;
int len;
@@ -4456,7 +4678,7 @@ pfatal_with_name (name)
char *s;
if (errno < sys_nerr)
- s = concat ("%s: ", sys_errlist[errno], "");
+ s = concat ("%s: ", sys_errlist[errno]);
else
s = "cannot open %s";
fatal (s, name);
@@ -4469,7 +4691,7 @@ perror_with_name (name)
char *s;
if (errno < sys_nerr)
- s = concat ("%s: ", sys_errlist[errno], "");
+ s = concat ("%s: ", sys_errlist[errno]);
else
s = "cannot open %s";
error (s, name);
@@ -4482,8 +4704,7 @@ perror_exec (name)
char *s;
if (errno < sys_nerr)
- s = concat ("installation problem, cannot exec %s: ",
- sys_errlist[errno], "");
+ s = concat ("installation problem, cannot exec %s: ", sys_errlist[errno]);
else
s = "installation problem, cannot exec %s";
error (s, name);
@@ -4803,7 +5024,7 @@ set_multilib_dir ()
}
++p;
- }
+ }
}
/* Print out the multiple library subdirectory selection
diff --git a/gnu/usr.bin/cc/cc1/Makefile b/gnu/usr.bin/cc/cc1/Makefile
index 667e454..0266f86 100644
--- a/gnu/usr.bin/cc/cc1/Makefile
+++ b/gnu/usr.bin/cc/cc1/Makefile
@@ -1,13 +1,13 @@
#
-# $FreeBSD$
+# $Id: Makefile,v 1.6 1995/09/22 14:14:21 phk Exp $
#
PROG = cc1
SRCS = c-aux-info.c c-convert.c c-decl.c c-iterate.c c-lang.c c-lex.c c-parse.c c-pragma.c c-typeck.c
BINDIR= /usr/libexec
NOMAN= 1
-LDDESTDIR+= -L${.CURDIR}/../cc_int/obj
-LDDESTDIR+= -L${.CURDIR}/../cc_int
-LDADD+= -lcc_int
+NOSHARED= true
+DPADD+= ${LIBCC_INT}
+LDADD+= -lcc_int
.include <bsd.prog.mk>
diff --git a/gnu/usr.bin/cc/cc1/c-aux-info.c b/gnu/usr.bin/cc/cc1/c-aux-info.c
index 0e7df9b..669e39f 100644
--- a/gnu/usr.bin/cc/cc1/c-aux-info.c
+++ b/gnu/usr.bin/cc/cc1/c-aux-info.c
@@ -474,7 +474,7 @@ gen_type (ret_val, t, style)
case TYPE_DECL:
data_type = IDENTIFIER_POINTER (DECL_NAME (t));
break;
-
+
case INTEGER_TYPE:
data_type = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (t)));
/* Normally, `unsigned' is part of the deal. Not so if it comes
diff --git a/gnu/usr.bin/cc/cc1/c-decl.c b/gnu/usr.bin/cc/cc1/c-decl.c
index c1a8dc9..afdd1d6 100644
--- a/gnu/usr.bin/cc/cc1/c-decl.c
+++ b/gnu/usr.bin/cc/cc1/c-decl.c
@@ -348,7 +348,7 @@ struct binding_level
/* Nonzero means make a BLOCK if this level has any subblocks. */
char keep_if_subblocks;
- /* Number of decls in `names' that have incomplete
+ /* Number of decls in `names' that have incomplete
structure or union types. */
int n_incomplete;
@@ -359,7 +359,7 @@ struct binding_level
};
#define NULL_BINDING_LEVEL (struct binding_level *) NULL
-
+
/* The binding level currently in effect. */
static struct binding_level *current_binding_level;
@@ -388,7 +388,7 @@ static int keep_next_level_flag;
if it has subblocks. */
static int keep_next_if_subblocks;
-
+
/* The chain of outer levels of label scopes.
This uses the same data structure used for binding levels,
but it works differently: each link in the chain records
@@ -540,7 +540,7 @@ int dollars_in_ident = DOLLARS_IN_IDENTIFIERS > 1;
/* Decode the string P as a language-specific option for C.
Return 1 if it is recognized (and handle it);
return 0 if not recognized. */
-
+
int
c_decode_option (p)
char *p;
@@ -756,7 +756,7 @@ print_lang_identifier (file, node, indent)
/* Hook called at end of compilation to assume 1 elt
for a top-level array decl that wasn't complete before. */
-
+
void
finish_incomplete_decl (decl)
tree decl;
@@ -1212,7 +1212,7 @@ pop_label_level ()
DECL_NAME (TREE_VALUE (link)));
}
else if (warn_unused && !TREE_USED (TREE_VALUE (link)))
- warning_with_decl (TREE_VALUE (link),
+ warning_with_decl (TREE_VALUE (link),
"label `%s' defined but not used");
IDENTIFIER_LABEL_VALUE (DECL_NAME (TREE_VALUE (link))) = 0;
@@ -1303,6 +1303,7 @@ duplicate_decls (newdecl, olddecl)
&& DECL_INITIAL (newdecl) != 0);
tree oldtype = TREE_TYPE (olddecl);
tree newtype = TREE_TYPE (newdecl);
+ char *errmsg = 0;
if (TREE_CODE (newtype) == ERROR_MARK
|| TREE_CODE (oldtype) == ERROR_MARK)
@@ -1394,7 +1395,7 @@ duplicate_decls (newdecl, olddecl)
tree newtype
= build_function_type (newreturntype,
TYPE_ARG_TYPES (TREE_TYPE (olddecl)));
-
+
types_match = comptypes (TREE_TYPE (newdecl), newtype);
if (types_match)
TREE_TYPE (olddecl) = newtype;
@@ -1413,10 +1414,10 @@ duplicate_decls (newdecl, olddecl)
the return type of olddecl's function type. */
tree newtype
= build_function_type (TREE_TYPE (TREE_TYPE (olddecl)),
- tree_cons (NULL_TREE,
+ tree_cons (NULL_TREE,
TREE_VALUE (TYPE_ARG_TYPES (TREE_TYPE (newdecl))),
TREE_CHAIN (TYPE_ARG_TYPES (TREE_TYPE (olddecl)))));
-
+
types_match = comptypes (TREE_TYPE (newdecl), newtype);
if (types_match)
TREE_TYPE (olddecl) = newtype;
@@ -1528,7 +1529,7 @@ duplicate_decls (newdecl, olddecl)
}
else
{
- char *errmsg = redeclaration_error_message (newdecl, olddecl);
+ errmsg = redeclaration_error_message (newdecl, olddecl);
if (errmsg)
{
error_with_decl (newdecl, errmsg);
@@ -1625,7 +1626,7 @@ duplicate_decls (newdecl, olddecl)
}
/* Optionally warn about more than one declaration for the same name. */
- if (warn_redundant_decls && DECL_SOURCE_LINE (olddecl) != 0
+ if (errmsg == 0 && warn_redundant_decls && DECL_SOURCE_LINE (olddecl) != 0
/* Dont warn about a function declaration
followed by a definition. */
&& !(TREE_CODE (newdecl) == FUNCTION_DECL && DECL_INITIAL (newdecl) != 0
@@ -1655,7 +1656,7 @@ duplicate_decls (newdecl, olddecl)
push_obstacks_nochange ();
end_temporary_allocation ();
}
-
+
/* Merge the data types specified in the two decls. */
if (TREE_CODE (newdecl) != FUNCTION_DECL || !DECL_BUILT_IN (olddecl))
TREE_TYPE (newdecl)
@@ -1697,11 +1698,16 @@ duplicate_decls (newdecl, olddecl)
make_var_volatile (newdecl);
}
- /* Keep source location of definition rather than declaration. */
- if (DECL_INITIAL (newdecl) == 0 && DECL_INITIAL (olddecl) != 0)
+ /* Keep source location of definition rather than declaration.
+ Likewise, keep decl at outer scope. */
+ if ((DECL_INITIAL (newdecl) == 0 && DECL_INITIAL (olddecl) != 0)
+ || (DECL_CONTEXT (newdecl) != 0 && DECL_CONTEXT (olddecl) == 0))
{
DECL_SOURCE_LINE (newdecl) = DECL_SOURCE_LINE (olddecl);
DECL_SOURCE_FILE (newdecl) = DECL_SOURCE_FILE (olddecl);
+
+ if (DECL_CONTEXT (olddecl) == 0)
+ DECL_CONTEXT (newdecl) = 0;
}
/* Merge the unused-warning information. */
@@ -2037,7 +2043,7 @@ pushdecl (x)
if (b == global_binding_level)
{
/* Install a global value. */
-
+
/* If the first global decl has external linkage,
warn if we later see static one. */
if (IDENTIFIER_GLOBAL_VALUE (name) == 0 && TREE_PUBLIC (x))
@@ -2439,6 +2445,21 @@ shadow_label (name)
if (decl != 0)
{
+ register tree dup;
+
+ /* Check to make sure that the label hasn't already been declared
+ at this label scope */
+ for (dup = named_labels; dup; dup = TREE_CHAIN (dup))
+ if (TREE_VALUE (dup) == decl)
+ {
+ error ("duplicate label declaration `%s'",
+ IDENTIFIER_POINTER (name));
+ error_with_decl (TREE_VALUE (dup),
+ "this is a previous declaration");
+ /* Just use the previous declaration. */
+ return lookup_label (name);
+ }
+
shadowed_labels = tree_cons (NULL_TREE, decl, shadowed_labels);
IDENTIFIER_LABEL_VALUE (name) = decl = 0;
}
@@ -2972,14 +2993,14 @@ init_decl_processing ()
BUILT_IN_CONSTANT_P, NULL_PTR);
builtin_function ("__builtin_return_address",
- build_function_type (ptr_type_node,
+ build_function_type (ptr_type_node,
tree_cons (NULL_TREE,
unsigned_type_node,
endlink)),
BUILT_IN_RETURN_ADDRESS, NULL_PTR);
builtin_function ("__builtin_frame_address",
- build_function_type (ptr_type_node,
+ build_function_type (ptr_type_node,
tree_cons (NULL_TREE,
unsigned_type_node,
endlink)),
@@ -3078,11 +3099,11 @@ init_decl_processing ()
BUILT_IN_STRCPY, "strcpy");
builtin_function ("__builtin_strlen", strlen_ftype,
BUILT_IN_STRLEN, "strlen");
- builtin_function ("__builtin_fsqrt", double_ftype_double,
+ builtin_function ("__builtin_fsqrt", double_ftype_double,
BUILT_IN_FSQRT, "sqrt");
- builtin_function ("__builtin_sin", double_ftype_double,
+ builtin_function ("__builtin_sin", double_ftype_double,
BUILT_IN_SIN, "sin");
- builtin_function ("__builtin_cos", double_ftype_double,
+ builtin_function ("__builtin_cos", double_ftype_double,
BUILT_IN_COS, "cos");
/* In an ANSI C program, it is okay to supply built-in meanings
@@ -3673,7 +3694,7 @@ finish_decl (decl, init, asmspec_tree)
references to it. */
/* This test used to include TREE_STATIC, but this won't be set
for function level initializers. */
- if (TREE_READONLY (decl))
+ if (TREE_READONLY (decl) || ITERATOR_P (decl))
{
preserve_initializer ();
/* Hack? Set the permanent bit for something that is permanent,
@@ -4494,7 +4515,7 @@ grokdeclarator (declarator, declspecs, decl_context, initialized)
/* Omit the arg types if -traditional, since the arg types
and the list links might not be permanent. */
type = build_function_type (type,
- flag_traditional
+ flag_traditional
? NULL_TREE : arg_types);
#endif
/* ANSI seems to say that `const int foo ();'
@@ -5418,7 +5439,7 @@ finish_struct (t, fieldlist)
#endif
}
}
- else
+ else if (TREE_TYPE (x) != error_mark_node)
{
int min_align = (DECL_PACKED (x) ? BITS_PER_UNIT
: TYPE_ALIGN (TREE_TYPE (x)));
@@ -5438,7 +5459,7 @@ finish_struct (t, fieldlist)
else
{
register tree y = fieldlist;
-
+
while (1)
{
if (DECL_NAME (y) == DECL_NAME (TREE_CHAIN (x)))
@@ -5646,37 +5667,6 @@ start_enum (name)
return enumtype;
}
-/* Return the minimum number of bits needed to represent VALUE in a
- signed or unsigned type, UNSIGNEDP says which. */
-
-static int
-min_precision (value, unsignedp)
- tree value;
- int unsignedp;
-{
- int log;
-
- /* If the value is negative, compute its negative minus 1. The latter
- adjustment is because the absolute value of the largest negative value
- is one larger than the largest positive value. This is equivalent to
- a bit-wise negation, so use that operation instead. */
-
- if (tree_int_cst_sgn (value) < 0)
- value = fold (build1 (BIT_NOT_EXPR, TREE_TYPE (value), value));
-
- /* Return the number of bits needed, taking into account the fact
- that we need one more bit for a signed than unsigned type. */
-
- if (integer_zerop (value))
- log = 0;
- else if (TREE_INT_CST_HIGH (value) != 0)
- log = HOST_BITS_PER_WIDE_INT + floor_log2 (TREE_INT_CST_HIGH (value));
- else
- log = floor_log2 (TREE_INT_CST_LOW (value));
-
- return log + 1 + ! unsignedp;
-}
-
/* After processing and defining all the values of an enumeration type,
install their decls in the enumeration type and finish it off.
ENUMTYPE is the type object and VALUES a list of decl-value pairs.
@@ -5868,6 +5858,7 @@ start_function (declspecs, declarator, nested)
{
tree decl1, old_decl;
tree restype;
+ int old_immediate_size_expand = immediate_size_expand;
current_function_returns_value = 0; /* Assume, until we see it does. */
current_function_returns_null = 0;
@@ -5877,6 +5868,9 @@ start_function (declspecs, declarator, nested)
named_labels = 0;
shadowed_labels = 0;
+ /* Don't expand any sizes in the return type of the function. */
+ immediate_size_expand = 0;
+
decl1 = grokdeclarator (declarator, declspecs, FUNCDEF, 1);
/* If the declarator is not suitable for a function definition,
@@ -5922,6 +5916,11 @@ start_function (declspecs, declarator, nested)
current_function_prototype_line = DECL_SOURCE_LINE (old_decl);
}
+ /* If there is no explicit declaration, look for any out-of-scope implicit
+ declarations. */
+ if (old_decl == 0)
+ old_decl = IDENTIFIER_IMPLICIT_DECL (DECL_NAME (decl1));
+
/* Optionally warn of old-fashioned def with no previous prototype. */
if (warn_strict_prototypes
&& TYPE_ARG_TYPES (TREE_TYPE (decl1)) == 0
@@ -5937,7 +5936,7 @@ start_function (declspecs, declarator, nested)
if the function has already been used. */
else if (warn_missing_prototypes
&& old_decl != 0 && TREE_USED (old_decl)
- && !(old_decl != 0 && TYPE_ARG_TYPES (TREE_TYPE (old_decl)) != 0))
+ && TYPE_ARG_TYPES (TREE_TYPE (old_decl)) == 0)
warning_with_decl (decl1,
"`%s' was used with no prototype before its definition");
/* Optionally warn of any global def with no previous declaration. */
@@ -5949,7 +5948,8 @@ start_function (declspecs, declarator, nested)
/* Optionally warn of any def with no previous declaration
if the function has already been used. */
else if (warn_missing_declarations
- && old_decl != 0 && TREE_USED (old_decl))
+ && old_decl != 0 && TREE_USED (old_decl)
+ && old_decl == IDENTIFIER_IMPLICIT_DECL (DECL_NAME (decl1)))
warning_with_decl (decl1,
"`%s' was used with no declaration before its definition");
@@ -6006,6 +6006,8 @@ start_function (declspecs, declarator, nested)
if (TREE_ADDRESSABLE (DECL_ASSEMBLER_NAME (current_function_decl)))
TREE_ADDRESSABLE (current_function_decl) = 1;
+ immediate_size_expand = old_immediate_size_expand;
+
return 1;
}
@@ -6575,7 +6577,7 @@ combine_parm_decls (specparms, parmlist, void_at_end)
types = saveable_tree_cons (NULL_TREE, TREE_TYPE (parm), types);
}
}
-
+
if (void_at_end)
return saveable_tree_cons (parmdecls, nonparms,
nreverse (saveable_tree_cons (NULL_TREE, void_type_node, types)));
diff --git a/gnu/usr.bin/cc/cc1/c-iterate.c b/gnu/usr.bin/cc/cc1/c-iterate.c
index 99f9a79..14d4bab 100644
--- a/gnu/usr.bin/cc/cc1/c-iterate.c
+++ b/gnu/usr.bin/cc/cc1/c-iterate.c
@@ -67,7 +67,7 @@ static char *ixp_firstobj;
The sublevel list is not changed at this point.
-- On "})" the list for the current level is appended to the sublevel
- list.
+ list.
-- On ";" sublevel lists are appended to the current level lists.
The reason is this: if they have not been superseded by the
@@ -155,7 +155,7 @@ iterator_expand (stmt)
}
-static void
+static void
expand_stmt_with_iterators_1 (stmt, iter_list)
tree stmt, iter_list;
{
@@ -254,7 +254,7 @@ collect_iterators (exp, list)
case RTL_EXPR:
return list;
}
-
+
for (i = 0; i < num_args; i++)
list = collect_iterators (TREE_OPERAND (exp, i), list);
return list;
@@ -363,7 +363,7 @@ static void
isn_append (x, y)
struct iter_stack_node *x, *y;
{
- if (x->first == 0)
+ if (x->first == 0)
return;
if (y->first == 0)
@@ -408,7 +408,7 @@ void
push_iterator_stack ()
{
struct iter_stack_node *new_top
- = (struct iter_stack_node*)
+ = (struct iter_stack_node*)
obstack_alloc (&ixp_obstack, sizeof (struct iter_stack_node));
new_top->first = 0;
@@ -442,7 +442,7 @@ add_ixpansion (idecl, pro_start, pro_end, epi_start, epi_end)
rtx pro_start, pro_end, epi_start, epi_end;
{
struct ixpansion* newix;
-
+
/* Do nothing if we are not inside "({...})",
as in that case this expansion can't need subsequent RTL modification. */
if (iter_stack == 0)
@@ -490,18 +490,18 @@ delete_ixpansion (idecl)
for (insn = NEXT_INSN (ix->ixprologue_start);
insn != ix->ixprologue_end;
- insn = NEXT_INSN (insn))
+ insn = NEXT_INSN (insn))
delete_insn (insn);
for (insn = NEXT_INSN (ix->ixepilogue_start);
insn != ix->ixepilogue_end;
- insn = NEXT_INSN (insn))
+ insn = NEXT_INSN (insn))
delete_insn (insn);
}
/* Delete this ixpansion from sublevel_ixpansions. */
if (previx)
previx->next = ix->next;
- else
+ else
sublevel_ixpansions.first = ix->next;
if (sublevel_ixpansions.last == ix)
sublevel_ixpansions.last = previx;
@@ -563,7 +563,7 @@ pixl (head)
fprintf (stderr, "> ");
if (head == 0)
fprintf (stderr, "(empty)");
-
+
for (current=head; current; current = next)
{
tree node = current->ixdecl;
diff --git a/gnu/usr.bin/cc/cc1/c-lang.c b/gnu/usr.bin/cc/cc1/c-lang.c
index 8b46b3c..eb3ce7b 100644
--- a/gnu/usr.bin/cc/cc1/c-lang.c
+++ b/gnu/usr.bin/cc/cc1/c-lang.c
@@ -25,7 +25,7 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
/* Each of the functions defined here
is an alternative to a function in objc-actions.c. */
-
+
int
lang_decode_option (p)
char *p;
diff --git a/gnu/usr.bin/cc/cc1/c-lex.c b/gnu/usr.bin/cc/cc1/c-lex.c
index 17d50be..6806b6f 100644
--- a/gnu/usr.bin/cc/cc1/c-lex.c
+++ b/gnu/usr.bin/cc/cc1/c-lex.c
@@ -137,7 +137,7 @@ remember_protocol_qualifiers ()
else if (wordlist[i].rid == RID_BYCOPY)
wordlist[i].name = "bycopy";
else if (wordlist[i].rid == RID_ONEWAY)
- wordlist[i].name = "oneway";
+ wordlist[i].name = "oneway";
}
void
@@ -878,7 +878,7 @@ struct try_type
char long_long_flag;
};
-struct try_type type_sequence[] =
+struct try_type type_sequence[] =
{
{ &integer_type_node, 0, 0, 0},
{ &unsigned_type_node, 1, 0, 0},
@@ -1073,7 +1073,7 @@ yylex ()
&& TREE_CODE (DECL_INITIAL (lastiddecl)) == STRING_CST)
{
tree stringval = DECL_INITIAL (lastiddecl);
-
+
/* Copy the string value so that we won't clobber anything
if we put something in the TREE_CHAIN of this one. */
yylval.ttype = build_string (TREE_STRING_LENGTH (stringval),
@@ -1525,7 +1525,7 @@ yylex ()
<< (i * HOST_BITS_PER_CHAR));
low |= (HOST_WIDE_INT) parts[i] << (i * HOST_BITS_PER_CHAR);
}
-
+
yylval.ttype = build_int_2 (low, high);
TREE_TYPE (yylval.ttype) = long_long_unsigned_type_node;
diff --git a/gnu/usr.bin/cc/cc1/c-parse.c b/gnu/usr.bin/cc/cc1/c-parse.c
index 5120144..19b7718 100644
--- a/gnu/usr.bin/cc/cc1/c-parse.c
+++ b/gnu/usr.bin/cc/cc1/c-parse.c
@@ -395,9 +395,9 @@ static const short yyrline[] = { 0,
1576, 1585, 1590, 1595, 1600, 1604, 1608, 1619, 1626, 1633,
1640, 1651, 1655, 1658, 1663, 1686, 1720, 1745, 1774, 1789,
1800, 1804, 1808, 1811, 1816, 1818, 1821, 1823, 1827, 1832,
- 1835, 1841, 1846, 1851, 1853, 1862, 1863, 1869, 1871, 1876,
- 1878, 1882, 1885, 1891, 1894, 1896, 1898, 1900, 1907, 1912,
- 1917, 1919, 1928, 1931, 1936, 1939
+ 1835, 1841, 1846, 1851, 1853, 1862, 1863, 1869, 1871, 1881,
+ 1883, 1887, 1890, 1896, 1899, 1901, 1903, 1905, 1912, 1917,
+ 1922, 1924, 1933, 1936, 1941, 1944
};
static const char * const yytname[] = { "$","error","$illegal.","IDENTIFIER",
@@ -2940,7 +2940,7 @@ case 308:
break;}
case 309:
#line 1550 "c-parse.y"
-{
+{
/* Start the loop. Doing this after parsing
all the expressions ensures we will end the loop. */
expand_start_loop_continue_elsewhere (1);
@@ -3072,7 +3072,7 @@ case 325:
#line 1665 "c-parse.y"
{
/* The value returned by this action is */
- /* 1 if everything is OK */
+ /* 1 if everything is OK */
/* 0 in case of error or already bound iterator */
yyval.itype = 0;
@@ -3252,60 +3252,65 @@ case 348:
case 349:
#line 1872 "c-parse.y"
{ yyval.ttype = get_parm_info (0);
- if (pedantic)
- pedwarn ("ANSI C requires a named argument before `...'");
+ /* Gcc used to allow this as an extension. However, it does
+ not work for all targets, and thus has been disabled.
+ Also, since func (...) and func () are indistinguishable,
+ it caused problems with the code in expand_builtin which
+ tries to verify that BUILT_IN_NEXT_ARG is being used
+ correctly. */
+ error ("ANSI C requires a named argument before `...'");
;
break;}
case 350:
-#line 1877 "c-parse.y"
+#line 1882 "c-parse.y"
{ yyval.ttype = get_parm_info (1); ;
break;}
case 351:
-#line 1879 "c-parse.y"
+#line 1884 "c-parse.y"
{ yyval.ttype = get_parm_info (0); ;
break;}
case 352:
-#line 1884 "c-parse.y"
+#line 1889 "c-parse.y"
{ push_parm_decl (yyvsp[0].ttype); ;
break;}
case 353:
-#line 1886 "c-parse.y"
+#line 1891 "c-parse.y"
{ push_parm_decl (yyvsp[0].ttype); ;
break;}
case 354:
-#line 1893 "c-parse.y"
+#line 1898 "c-parse.y"
{ yyval.ttype = build_tree_list (yyvsp[-1].ttype, yyvsp[0].ttype) ; ;
break;}
case 355:
-#line 1895 "c-parse.y"
+#line 1900 "c-parse.y"
{ yyval.ttype = build_tree_list (yyvsp[-1].ttype, yyvsp[0].ttype) ; ;
break;}
case 356:
-#line 1897 "c-parse.y"
+#line 1902 "c-parse.y"
{ yyval.ttype = build_tree_list (yyvsp[-1].ttype, yyvsp[0].ttype); ;
break;}
case 357:
-#line 1899 "c-parse.y"
+#line 1904 "c-parse.y"
{ yyval.ttype = build_tree_list (yyvsp[-1].ttype, yyvsp[0].ttype) ; ;
break;}
case 358:
-#line 1901 "c-parse.y"
+#line 1906 "c-parse.y"
{ yyval.ttype = build_tree_list (yyvsp[-1].ttype, yyvsp[0].ttype); ;
break;}
case 359:
-#line 1908 "c-parse.y"
+#line 1913 "c-parse.y"
{ pushlevel (0);
clear_parm_order ();
declare_parm_level (1); ;
break;}
case 360:
-#line 1912 "c-parse.y"
+#line 1917 "c-parse.y"
{ yyval.ttype = yyvsp[0].ttype;
parmlist_tags_warning ();
poplevel (0, 0, 0); ;
break;}
case 362:
-#line 1920 "c-parse.y"
+#line 1925 "c-parse.y"
{ tree t;
for (t = yyvsp[-1].ttype; t; t = TREE_CHAIN (t))
if (TREE_VALUE (t) == NULL_TREE)
@@ -3313,19 +3318,19 @@ case 362:
yyval.ttype = tree_cons (NULL_TREE, NULL_TREE, yyvsp[-1].ttype); ;
break;}
case 363:
-#line 1930 "c-parse.y"
+#line 1935 "c-parse.y"
{ yyval.ttype = build_tree_list (NULL_TREE, yyvsp[0].ttype); ;
break;}
case 364:
-#line 1932 "c-parse.y"
+#line 1937 "c-parse.y"
{ yyval.ttype = chainon (yyvsp[-2].ttype, build_tree_list (NULL_TREE, yyvsp[0].ttype)); ;
break;}
case 365:
-#line 1938 "c-parse.y"
+#line 1943 "c-parse.y"
{ yyval.ttype = build_tree_list (NULL_TREE, yyvsp[0].ttype); ;
break;}
case 366:
-#line 1940 "c-parse.y"
+#line 1945 "c-parse.y"
{ yyval.ttype = chainon (yyvsp[-2].ttype, build_tree_list (NULL_TREE, yyvsp[0].ttype)); ;
break;}
}
@@ -3526,5 +3531,5 @@ yyerrhandle:
yystate = yyn;
goto yynewstate;
}
-#line 1943 "c-parse.y"
+#line 1948 "c-parse.y"
diff --git a/gnu/usr.bin/cc/cc1/c-typeck.c b/gnu/usr.bin/cc/cc1/c-typeck.c
index d5283c6..edb9ae4 100644
--- a/gnu/usr.bin/cc/cc1/c-typeck.c
+++ b/gnu/usr.bin/cc/cc1/c-typeck.c
@@ -210,7 +210,7 @@ common_type (t1, t2)
{
/* Pick the longest list, and hang on the other
list. */
-
+
if (list_length (a1) < list_length (a2))
attributes = a2, a2 = a1;
@@ -387,7 +387,7 @@ common_type (t1, t2)
TREE_VALUE (n) = TREE_VALUE (p1);
goto parm_done;
}
-
+
/* Given wait (union {union wait *u; int *i} *)
and wait (union wait *),
prefer union wait * as type of parm. */
@@ -450,7 +450,7 @@ comptypes (type1, type2)
if (t1 == t2 || TREE_CODE (t1) == ERROR_MARK || TREE_CODE (t2) == ERROR_MARK)
return 1;
- /* Treat an enum type as the integer type of the same width and
+ /* Treat an enum type as the integer type of the same width and
signedness. */
if (TREE_CODE (t1) == ENUMERAL_TYPE)
@@ -566,7 +566,7 @@ comp_target_types (ttl, ttr)
/* Return 1 if two function types F1 and F2 are compatible.
If either type specifies no argument types,
the other must specify a fixed number of self-promoting arg types.
- Otherwise, if one type specifies only the number of arguments,
+ Otherwise, if one type specifies only the number of arguments,
the other must specify that number of self-promoting arg types.
Otherwise, the argument types must match. */
@@ -655,7 +655,8 @@ type_lists_compatible_p (args1, args2)
/* Allow wait (union {union wait *u; int *i} *)
and wait (union wait *) to be compatible. */
if (TREE_CODE (TREE_VALUE (args1)) == UNION_TYPE
- && TYPE_NAME (TREE_VALUE (args1)) == 0
+ && (TYPE_NAME (TREE_VALUE (args1)) == 0
+ || TYPE_TRANSPARENT_UNION (TREE_VALUE (args1)))
&& TREE_CODE (TYPE_SIZE (TREE_VALUE (args1))) == INTEGER_CST
&& tree_int_cst_equal (TYPE_SIZE (TREE_VALUE (args1)),
TYPE_SIZE (TREE_VALUE (args2))))
@@ -669,7 +670,8 @@ type_lists_compatible_p (args1, args2)
return 0;
}
else if (TREE_CODE (TREE_VALUE (args2)) == UNION_TYPE
- && TYPE_NAME (TREE_VALUE (args2)) == 0
+ && (TYPE_NAME (TREE_VALUE (args2)) == 0
+ || TYPE_TRANSPARENT_UNION (TREE_VALUE (args2)))
&& TREE_CODE (TYPE_SIZE (TREE_VALUE (args2))) == INTEGER_CST
&& tree_int_cst_equal (TYPE_SIZE (TREE_VALUE (args2)),
TYPE_SIZE (TREE_VALUE (args1))))
@@ -789,13 +791,13 @@ signed_or_unsigned_type (unsignedp, type)
return type;
if (TYPE_PRECISION (type) == TYPE_PRECISION (signed_char_type_node))
return unsignedp ? unsigned_char_type_node : signed_char_type_node;
- if (TYPE_PRECISION (type) == TYPE_PRECISION (integer_type_node))
+ if (TYPE_PRECISION (type) == TYPE_PRECISION (integer_type_node))
return unsignedp ? unsigned_type_node : integer_type_node;
- if (TYPE_PRECISION (type) == TYPE_PRECISION (short_integer_type_node))
+ if (TYPE_PRECISION (type) == TYPE_PRECISION (short_integer_type_node))
return unsignedp ? short_unsigned_type_node : short_integer_type_node;
- if (TYPE_PRECISION (type) == TYPE_PRECISION (long_integer_type_node))
+ if (TYPE_PRECISION (type) == TYPE_PRECISION (long_integer_type_node))
return unsignedp ? long_unsigned_type_node : long_integer_type_node;
- if (TYPE_PRECISION (type) == TYPE_PRECISION (long_long_integer_type_node))
+ if (TYPE_PRECISION (type) == TYPE_PRECISION (long_long_integer_type_node))
return (unsignedp ? long_long_unsigned_type_node
: long_long_integer_type_node);
return type;
@@ -831,7 +833,7 @@ c_sizeof (type)
}
/* Convert in case a char is more than one unit. */
- t = size_binop (CEIL_DIV_EXPR, TYPE_SIZE (type),
+ t = size_binop (CEIL_DIV_EXPR, TYPE_SIZE (type),
size_int (TYPE_PRECISION (char_type_node)));
/* size_binop does not put the constant in range, so do it now. */
if (TREE_CODE (t) == INTEGER_CST && force_fit_type (t, 0))
@@ -854,7 +856,7 @@ c_sizeof_nowarn (type)
return size_int (0);
/* Convert in case a char is more than one unit. */
- t = size_binop (CEIL_DIV_EXPR, TYPE_SIZE (type),
+ t = size_binop (CEIL_DIV_EXPR, TYPE_SIZE (type),
size_int (TYPE_PRECISION (char_type_node)));
force_fit_type (t, 0);
return t;
@@ -882,7 +884,7 @@ c_size_in_bytes (type)
}
/* Convert in case a char is more than one unit. */
- t = size_binop (CEIL_DIV_EXPR, TYPE_SIZE (type),
+ t = size_binop (CEIL_DIV_EXPR, TYPE_SIZE (type),
size_int (BITS_PER_UNIT));
force_fit_type (t, 0);
return t;
@@ -917,7 +919,7 @@ c_alignof_expr (expr)
{
if (TREE_CODE (expr) == VAR_DECL)
return size_int (DECL_ALIGN (expr) / BITS_PER_UNIT);
-
+
if (TREE_CODE (expr) == COMPONENT_REF
&& DECL_BIT_FIELD (TREE_OPERAND (expr, 1)))
{
@@ -927,13 +929,13 @@ c_alignof_expr (expr)
else if (TREE_CODE (expr) == COMPONENT_REF
&& TREE_CODE (TREE_OPERAND (expr, 1)) == FIELD_DECL)
return size_int (DECL_ALIGN (TREE_OPERAND (expr, 1)) / BITS_PER_UNIT);
-
+
if (TREE_CODE (expr) == INDIRECT_REF)
{
tree t = TREE_OPERAND (expr, 0);
tree best = t;
int bestalign = TYPE_ALIGN (TREE_TYPE (TREE_TYPE (t)));
-
+
while (TREE_CODE (t) == NOP_EXPR
&& TREE_CODE (TREE_TYPE (TREE_OPERAND (t, 0))) == POINTER_TYPE)
{
@@ -990,8 +992,11 @@ default_conversion (exp)
/* Constants can be used directly unless they're not loadable. */
if (TREE_CODE (exp) == CONST_DECL)
exp = DECL_INITIAL (exp);
- /* Replace a nonvolatile const static variable with its value. */
- else if (optimize && TREE_CODE (exp) == VAR_DECL)
+
+ /* Replace a nonvolatile const static variable with its value unless
+ it is an array, in which case we must be sure that taking the
+ address of the array produces consistent results. */
+ else if (optimize && TREE_CODE (exp) == VAR_DECL && code != ARRAY_TYPE)
{
exp = decl_constant_value (exp);
type = TREE_TYPE (exp);
@@ -1107,7 +1112,7 @@ default_conversion (exp)
If this component name is found indirectly within an anonymous union,
store in *INDIRECT the component which directly contains
that anonymous union. Otherwise, set *INDIRECT to 0. */
-
+
static tree
lookup_field (type, component, indirect)
tree type, component;
@@ -1433,7 +1438,7 @@ build_array_ref (array, index)
TREE_THIS_VOLATILE (rval)
|= (TYPE_VOLATILE (TREE_TYPE (TREE_TYPE (array)))
/* This was added by rms on 16 Nov 91.
- It fixes vol struct foo *a; a->elts[1]
+ It fixes vol struct foo *a; a->elts[1]
in an inline function.
Hope it doesn't break something else. */
| TREE_THIS_VOLATILE (array));
@@ -1630,37 +1635,28 @@ convert_arguments (typelist, values, name, fundecl)
}
else
{
-#if 0 /* This turns out not to win--there's no way to write a prototype
- for a function whose arg type is a union with no tag. */
- /* Nameless union automatically casts the types it contains. */
- if (TREE_CODE (type) == UNION_TYPE && TYPE_NAME (type) == 0)
- {
- tree field;
-
- for (field = TYPE_FIELDS (type); field;
- field = TREE_CHAIN (field))
- if (comptypes (TYPE_MAIN_VARIANT (TREE_TYPE (field)),
- TYPE_MAIN_VARIANT (TREE_TYPE (val))))
- break;
-
- if (field)
- val = build1 (CONVERT_EXPR, type, val);
- }
-#endif
-
/* Optionally warn about conversions that
differ from the default conversions. */
if (warn_conversion)
{
int formal_prec = TYPE_PRECISION (type);
- if (TREE_CODE (type) != REAL_TYPE
+ if (INTEGRAL_TYPE_P (type)
&& TREE_CODE (TREE_TYPE (val)) == REAL_TYPE)
warn_for_assignment ("%s as integer rather than floating due to prototype", (char *) 0, name, parmnum + 1);
+ else if (TREE_CODE (type) == COMPLEX_TYPE
+ && TREE_CODE (TREE_TYPE (val)) == REAL_TYPE)
+ warn_for_assignment ("%s as complex rather than floating due to prototype", (char *) 0, name, parmnum + 1);
else if (TREE_CODE (type) == REAL_TYPE
- && TREE_CODE (TREE_TYPE (val)) != REAL_TYPE)
+ && INTEGRAL_TYPE_P (TREE_TYPE (val)))
warn_for_assignment ("%s as floating rather than integer due to prototype", (char *) 0, name, parmnum + 1);
else if (TREE_CODE (type) == REAL_TYPE
+ && TREE_CODE (TREE_TYPE (val)) == COMPLEX_TYPE)
+ warn_for_assignment ("%s as floating rather than complex due to prototype", (char *) 0, name, parmnum + 1);
+ /* ??? At some point, messages should be written about
+ conversions between complex types, but that's too messy
+ to do now. */
+ else if (TREE_CODE (type) == REAL_TYPE
&& TREE_CODE (TREE_TYPE (val)) == REAL_TYPE)
{
/* Warn if any argument is passed as `float',
@@ -1669,10 +1665,8 @@ convert_arguments (typelist, values, name, fundecl)
warn_for_assignment ("%s as `float' rather than `double' due to prototype", (char *) 0, name, parmnum + 1);
}
/* Detect integer changing in width or signedness. */
- else if ((TREE_CODE (type) == INTEGER_TYPE
- || TREE_CODE (type) == ENUMERAL_TYPE)
- && (TREE_CODE (TREE_TYPE (val)) == INTEGER_TYPE
- || TREE_CODE (TREE_TYPE (val)) == ENUMERAL_TYPE))
+ else if (INTEGRAL_TYPE_P (type)
+ && INTEGRAL_TYPE_P (TREE_TYPE (val)))
{
tree would_have_been = default_conversion (val);
tree type1 = TREE_TYPE (would_have_been);
@@ -1723,10 +1717,10 @@ convert_arguments (typelist, values, name, fundecl)
}
}
- parmval = convert_for_assignment (type, val,
+ parmval = convert_for_assignment (type, val,
(char *)0, /* arg passing */
fundecl, name, parmnum + 1);
-
+
#ifdef PROMOTE_PROTOTYPES
if ((TREE_CODE (type) == INTEGER_TYPE
|| TREE_CODE (type) == ENUMERAL_TYPE)
@@ -2240,7 +2234,7 @@ build_binary_op (code, orig_op0, orig_op1, convert_p)
{
if (! comp_target_types (type0, type1))
pedwarn ("comparison of distinct pointer types lacks a cast");
- else if (pedantic
+ else if (pedantic
&& TREE_CODE (TREE_TYPE (type0)) == FUNCTION_TYPE)
pedwarn ("ANSI C forbids ordered comparisons of pointers to functions");
result_type = common_type (type0, type1);
@@ -2261,7 +2255,7 @@ build_binary_op (code, orig_op0, orig_op1, convert_p)
else if ((TYPE_SIZE (TREE_TYPE (type0)) != 0)
!= (TYPE_SIZE (TREE_TYPE (type1)) != 0))
pedwarn ("comparison of complete and incomplete pointers");
- else if (pedantic
+ else if (pedantic
&& TREE_CODE (TREE_TYPE (type0)) == FUNCTION_TYPE)
pedwarn ("ANSI C forbids ordered comparisons of pointers to functions");
result_type = integer_type_node;
@@ -2430,7 +2424,7 @@ build_binary_op (code, orig_op0, orig_op1, convert_p)
pass the copies by reference, then copy them back afterward. */
tree xop0 = op0, xop1 = op1, xresult_type = result_type;
enum tree_code xresultcode = resultcode;
- tree val
+ tree val
= shorten_compare (&xop0, &xop1, &xresult_type, &xresultcode);
if (val != 0)
return val;
@@ -2443,7 +2437,7 @@ build_binary_op (code, orig_op0, orig_op1, convert_p)
tree op1_type = TREE_TYPE (orig_op1);
int op0_unsigned = TREE_UNSIGNED (op0_type);
int op1_unsigned = TREE_UNSIGNED (op1_type);
-
+
/* Give warnings for comparisons between signed and unsigned
quantities that will fail. Do not warn if the signed quantity
is an unsuffixed integer literal (or some static constant
@@ -2490,9 +2484,9 @@ build_binary_op (code, orig_op0, orig_op1, convert_p)
if (! converted)
{
if (TREE_TYPE (op0) != result_type)
- op0 = convert (result_type, op0);
+ op0 = convert (result_type, op0);
if (TREE_TYPE (op1) != result_type)
- op1 = convert (result_type, op1);
+ op1 = convert (result_type, op1);
}
{
@@ -2736,7 +2730,7 @@ build_unary_op (code, xarg, noconvert)
return fold (build1 (IMAGPART_EXPR, TREE_TYPE (TREE_TYPE (arg)), arg));
else
return convert (TREE_TYPE (arg), integer_zero_node);
-
+
case PREINCREMENT_EXPR:
case POSTINCREMENT_EXPR:
case PREDECREMENT_EXPR:
@@ -2798,7 +2792,7 @@ build_unary_op (code, xarg, noconvert)
((code == PREINCREMENT_EXPR
|| code == POSTINCREMENT_EXPR)
? "increment" : "decrement"));
- inc = c_sizeof_nowarn (TREE_TYPE (result_type));
+ inc = c_size_in_bytes (TREE_TYPE (result_type));
}
else
inc = integer_one_node;
@@ -2859,7 +2853,7 @@ build_unary_op (code, xarg, noconvert)
/* Report a read-only lvalue. */
if (TREE_READONLY (arg))
- readonly_warning (arg,
+ readonly_warning (arg,
((code == PREINCREMENT_EXPR
|| code == POSTINCREMENT_EXPR)
? "increment" : "decrement"));
@@ -3084,7 +3078,7 @@ lvalue_or_else (ref, string)
but which we can accept as lvalues.
If ARG is not a kind of expression we can handle, return zero. */
-
+
static tree
unary_complex_lvalue (code, arg)
enum tree_code code;
@@ -3211,6 +3205,18 @@ mark_addressable (exp)
IDENTIFIER_POINTER (DECL_NAME (x)));
return 0;
}
+
+ /* If we are making this addressable due to its having
+ volatile components, give a different error message. Also
+ handle the case of an unnamed parameter by not trying
+ to give the name. */
+
+ else if (C_TYPE_FIELDS_VOLATILE (TREE_TYPE (x)))
+ {
+ error ("cannot put object with volatile field into register");
+ return 0;
+ }
+
pedwarn ("address of register variable `%s' requested",
IDENTIFIER_POINTER (DECL_NAME (x)));
}
@@ -3286,7 +3292,7 @@ build_conditional_expr (ifexp, op1, op2)
code1 = TREE_CODE (type1);
type2 = TREE_TYPE (op2);
code2 = TREE_CODE (type2);
-
+
/* Quickly detect the usual case where op1 and op2 have the same type
after promotion. */
if (TYPE_MAIN_VARIANT (type1) == TYPE_MAIN_VARIANT (type2))
@@ -3385,7 +3391,7 @@ build_conditional_expr (ifexp, op1, op2)
op1 = convert_and_check (result_type, op1);
if (result_type != TREE_TYPE (op2))
op2 = convert_and_check (result_type, op2);
-
+
#if 0
if (code1 == RECORD_TYPE || code1 == UNION_TYPE)
{
@@ -3422,7 +3428,7 @@ build_conditional_expr (ifexp, op1, op2)
}
}
#endif /* 0 */
-
+
if (TREE_CODE (ifexp) == INTEGER_CST)
return pedantic_non_lvalue (integer_zerop (ifexp) ? op2 : op1);
@@ -3488,7 +3494,7 @@ build_c_cast (type, expr)
tree expr;
{
register tree value = expr;
-
+
if (type == error_mark_node || expr == error_mark_node)
return error_mark_node;
type = TYPE_MAIN_VARIANT (type);
@@ -3686,7 +3692,7 @@ build_modify_expr (lhs, modifycode, rhs)
return error_mark_node;
return build (COMPOUND_EXPR, lhstype,
TREE_OPERAND (lhs, 0), newrhs);
-
+
/* Handle (a ? b : c) used as an "lvalue". */
case COND_EXPR:
pedantic_lvalue_warning (COND_EXPR);
@@ -3868,14 +3874,15 @@ convert_for_assignment (type, rhs, errtype, fundecl, funname, parmnum)
/* Arithmetic types all interconvert, and enum is treated like int. */
if ((codel == INTEGER_TYPE || codel == REAL_TYPE || codel == ENUMERAL_TYPE
|| codel == COMPLEX_TYPE)
- &&
- (coder == INTEGER_TYPE || coder == REAL_TYPE || coder == ENUMERAL_TYPE
- || coder == COMPLEX_TYPE))
+ && (coder == INTEGER_TYPE || coder == REAL_TYPE || coder == ENUMERAL_TYPE
+ || coder == COMPLEX_TYPE))
return convert_and_check (type, rhs);
+
/* Conversion to a union from its member types. */
else if (codel == UNION_TYPE)
{
tree memb_types;
+
for (memb_types = TYPE_FIELDS (type); memb_types;
memb_types = TREE_CHAIN (memb_types))
{
@@ -3886,6 +3893,7 @@ convert_for_assignment (type, rhs, errtype, fundecl, funname, parmnum)
pedwarn ("ANSI C prohibits argument conversion to union type");
return build1 (NOP_EXPR, type, rhs);
}
+
else if (coder == POINTER_TYPE
&& TREE_CODE (TREE_TYPE (memb_types)) == POINTER_TYPE)
{
@@ -3895,44 +3903,59 @@ convert_for_assignment (type, rhs, errtype, fundecl, funname, parmnum)
/* Any non-function converts to a [const][volatile] void *
and vice versa; otherwise, targets must be the same.
- Meanwhile, the lhs target must have all the qualifiers of the rhs. */
+ Meanwhile, the lhs target must have all the qualifiers of
+ the rhs. */
if (TYPE_MAIN_VARIANT (ttl) == void_type_node
|| TYPE_MAIN_VARIANT (ttr) == void_type_node
|| comp_target_types (memb_type, rhstype))
{
- /* Const and volatile mean something different for function types,
- so the usual warnings are not appropriate. */
+ /* Const and volatile mean something different for function
+ types, so the usual warnings are not appropriate. */
if (TREE_CODE (ttr) != FUNCTION_TYPE
|| TREE_CODE (ttl) != FUNCTION_TYPE)
{
if (! TYPE_READONLY (ttl) && TYPE_READONLY (ttr))
warn_for_assignment ("%s discards `const' from pointer target type",
- get_spelling (errtype), funname, parmnum);
+ get_spelling (errtype), funname,
+ parmnum);
if (! TYPE_VOLATILE (ttl) && TYPE_VOLATILE (ttr))
warn_for_assignment ("%s discards `volatile' from pointer target type",
- get_spelling (errtype), funname, parmnum);
+ get_spelling (errtype), funname,
+ parmnum);
}
else
{
- /* Because const and volatile on functions are restrictions
- that say the function will not do certain things,
- it is okay to use a const or volatile function
- where an ordinary one is wanted, but not vice-versa. */
+ /* Because const and volatile on functions are
+ restrictions that say the function will not do
+ certain things, it is okay to use a const or volatile
+ function where an ordinary one is wanted, but not
+ vice-versa. */
if (TYPE_READONLY (ttl) && ! TYPE_READONLY (ttr))
warn_for_assignment ("%s makes `const *' function pointer from non-const",
- get_spelling (errtype), funname, parmnum);
+ get_spelling (errtype), funname,
+ parmnum);
if (TYPE_VOLATILE (ttl) && ! TYPE_VOLATILE (ttr))
warn_for_assignment ("%s makes `volatile *' function pointer from non-volatile",
- get_spelling (errtype), funname, parmnum);
+ get_spelling (errtype), funname,
+ parmnum);
}
+
if (pedantic
&& !(fundecl != 0 && DECL_IN_SYSTEM_HEADER (fundecl)))
pedwarn ("ANSI C prohibits argument conversion to union type");
return build1 (NOP_EXPR, type, rhs);
}
}
+
+ /* Can convert integer zero to any pointer type. */
+ else if (TREE_CODE (TREE_TYPE (memb_types)) == POINTER_TYPE
+ && (integer_zerop (rhs)
+ || (TREE_CODE (rhs) == NOP_EXPR
+ && integer_zerop (TREE_OPERAND (rhs, 0)))))
+ return build1 (NOP_EXPR, type, null_pointer_node);
}
}
+
/* Conversions among pointers */
else if (codel == POINTER_TYPE && coder == POINTER_TYPE)
{
@@ -4030,7 +4053,7 @@ convert_for_assignment (type, rhs, errtype, fundecl, funname, parmnum)
if (funname)
{
tree selector = maybe_building_objc_message_expr ();
-
+
if (selector && parmnum > 2)
error ("incompatible type for argument %d of `%s'",
parmnum - 2, IDENTIFIER_POINTER (selector));
@@ -4067,7 +4090,7 @@ warn_for_assignment (msg, opname, function, argnum)
if (opname == 0)
{
tree selector = maybe_building_objc_message_expr ();
-
+
if (selector && argnum > 2)
{
function = selector;
@@ -4113,7 +4136,7 @@ initializer_constant_valid_p (value, endtype)
return
initializer_constant_valid_p (TREE_VALUE (CONSTRUCTOR_ELTS (value)),
endtype);
-
+
return TREE_STATIC (value) ? null_pointer_node : 0;
case INTEGER_CST:
@@ -4384,7 +4407,7 @@ push_string (string)
static void
push_member_name (decl)
tree decl;
-
+
{
char *string
= DECL_NAME (decl) ? IDENTIFIER_POINTER (DECL_NAME (decl)) : "<anonymous>";
@@ -5155,8 +5178,8 @@ push_init_level (implicit)
/* Structure elements may require alignment. Do this now
if necessary for the subaggregate. */
- if (constructor_incremental && TREE_CODE (constructor_type) == RECORD_TYPE
- && constructor_fields)
+ if (constructor_incremental && constructor_type != 0
+ && TREE_CODE (constructor_type) == RECORD_TYPE && constructor_fields)
{
/* Advance to offset of this element. */
if (! tree_int_cst_equal (constructor_bit_index,
@@ -5308,7 +5331,7 @@ check_init_type_bitfields (type)
check_init_type_bitfields (TREE_TYPE (type));
}
-/* At the end of an implicit or explicit brace level,
+/* At the end of an implicit or explicit brace level,
finish up that level of constructor.
If we were outputting the elements as they are read, return 0
from inner levels (process_init_element ignores that),
@@ -5350,7 +5373,7 @@ pop_init_level (implicit)
#endif
/* Pad out the end of the structure. */
-
+
if (p->replacement_value)
{
/* If this closes a superfluous brace pair,
@@ -5497,7 +5520,7 @@ pop_init_level (implicit)
resume_momentary (momentary);
}
-
+
constructor_type = p->type;
constructor_fields = p->fields;
constructor_index = p->index;
@@ -5806,7 +5829,7 @@ output_pending_init_elements (all)
If we find an element that should be output now,
output it. Otherwise, set NEXT to the element
that comes first among those still pending. */
-
+
next = 0;
for (tail = constructor_pending_elts; tail;
tail = TREE_CHAIN (tail))
@@ -6020,6 +6043,7 @@ process_init_element (value)
/* Otherwise, if we have come to a subaggregate,
and we don't have an element of its type, push into it. */
else if (value != 0 && !constructor_no_implicit
+ && value != error_mark_node
&& TYPE_MAIN_VARIANT (TREE_TYPE (value)) != fieldtype
&& (fieldcode == RECORD_TYPE || fieldcode == ARRAY_TYPE
|| fieldcode == UNION_TYPE))
@@ -6083,6 +6107,7 @@ process_init_element (value)
/* Otherwise, if we have come to a subaggregate,
and we don't have an element of its type, push into it. */
else if (value != 0 && !constructor_no_implicit
+ && value != error_mark_node
&& TYPE_MAIN_VARIANT (TREE_TYPE (value)) != fieldtype
&& (fieldcode == RECORD_TYPE || fieldcode == ARRAY_TYPE
|| fieldcode == UNION_TYPE))
@@ -6126,6 +6151,7 @@ process_init_element (value)
/* Otherwise, if we have come to a subaggregate,
and we don't have an element of its type, push into it. */
else if (value != 0 && !constructor_no_implicit
+ && value != error_mark_node
&& TYPE_MAIN_VARIANT (TREE_TYPE (value)) != elttype
&& (eltcode == RECORD_TYPE || eltcode == ARRAY_TYPE
|| eltcode == UNION_TYPE))
@@ -6142,6 +6168,10 @@ process_init_element (value)
break;
}
+ /* In the case of [LO .. HI] = VALUE, only evaluate VALUE once. */
+ if (constructor_range_end)
+ value = save_expr (value);
+
/* Now output the actual element.
Ordinarily, output once.
If there is a range, repeat it till we advance past the range. */
diff --git a/gnu/usr.bin/cc/cc1plus/Makefile b/gnu/usr.bin/cc/cc1plus/Makefile
index a03330d..5bdeb0a 100644
--- a/gnu/usr.bin/cc/cc1plus/Makefile
+++ b/gnu/usr.bin/cc/cc1plus/Makefile
@@ -1,13 +1,13 @@
#
-# $FreeBSD$
+# $Id: Makefile,v 1.6 1995/09/22 14:14:26 phk Exp $
#
PROG = cc1plus
SRCS = call.c class.c cvt.c decl.c decl2.c edsel.c errfn.c error.c except.c expr.c gc.c init.c lex.c method.c parse.c pt.c ptree.c search.c sig.c spew.c tree.c typeck.c typeck2.c xref.c
BINDIR= /usr/libexec
NOMAN= 1
-LDDESTDIR+= -L${.CURDIR}/../cc_int/obj
-LDDESTDIR+= -L${.CURDIR}/../cc_int
-LDADD+= -lcc_int
+NOSHARED= makes_it_smaller_faster
+DPADD+= ${LIBCC_INT}
+LDADD+= -lcc_int
.include <bsd.prog.mk>
diff --git a/gnu/usr.bin/cc/cc1plus/call.c b/gnu/usr.bin/cc/cc1plus/call.c
index 3392a7a..54fb184 100644
--- a/gnu/usr.bin/cc/cc1plus/call.c
+++ b/gnu/usr.bin/cc/cc1plus/call.c
@@ -331,7 +331,7 @@ convert_harshness (type, parmtype, parm)
}
else
h.code = STD_CODE;
-
+
return h;
}
else if (coder == REAL_TYPE)
@@ -351,7 +351,7 @@ convert_harshness (type, parmtype, parm)
h.code = PROMO_CODE;
else
h.code = STD_CODE;
-
+
return h;
}
else if (INTEGRAL_CODE_P (coder))
@@ -525,13 +525,6 @@ convert_harshness (type, parmtype, parm)
else
penalty = 2;
- if (TREE_UNSIGNED (ttl) ^ TREE_UNSIGNED (intype))
- {
- ttl = unsigned_type (ttl);
- intype = unsigned_type (intype);
- penalty += 2;
- }
-
ttr = intype;
/* If the initializer is not an lvalue, then it does not
@@ -551,6 +544,13 @@ convert_harshness (type, parmtype, parm)
return h;
}
+ if (TREE_UNSIGNED (ttl) ^ TREE_UNSIGNED (intype))
+ {
+ ttl = unsigned_type (ttl);
+ ttr = intype = unsigned_type (intype);
+ penalty += 2;
+ }
+
if (ttl == ttr)
{
if (penalty > 2)
@@ -700,11 +700,17 @@ compute_conversion_costs (function, tta_in, cp, arglen)
int strike_index = 0, win;
struct harshness_code lose;
+ extern int cp_silent;
#ifdef GATHER_STATISTICS
n_compute_conversion_costs++;
#endif
+#ifndef DEBUG_MATCHING
+ /* We don't emit any warnings or errors while trying out each candidate. */
+ cp_silent = 1;
+#endif
+
cp->function = function;
cp->arg = tta ? TREE_VALUE (tta) : NULL_TREE;
cp->u.bad_arg = 0; /* optimistic! */
@@ -712,7 +718,7 @@ compute_conversion_costs (function, tta_in, cp, arglen)
cp->h.code = 0;
cp->h.distance = 0;
cp->h.int_penalty = 0;
- bzero (cp->harshness,
+ bzero ((char *) cp->harshness,
(cp->h_len + 1) * sizeof (struct harshness_code));
while (ttf && tta)
@@ -723,7 +729,7 @@ compute_conversion_costs (function, tta_in, cp, arglen)
break;
if (type_unknown_p (TREE_VALUE (tta)))
- {
+ {
/* Must perform some instantiation here. */
tree rhs = TREE_VALUE (tta);
tree lhstype = TREE_VALUE (ttf);
@@ -812,6 +818,7 @@ compute_conversion_costs (function, tta_in, cp, arglen)
{
cp->h.code = EVIL_CODE;
cp->u.bad_arg = -1;
+ cp_silent = 0;
return;
}
else
@@ -833,6 +840,7 @@ compute_conversion_costs (function, tta_in, cp, arglen)
{
cp->h.code = EVIL_CODE;
cp->u.bad_arg = -2;
+ cp_silent = 0;
return;
}
/* Store index of first default. */
@@ -855,6 +863,7 @@ compute_conversion_costs (function, tta_in, cp, arglen)
if (dont_convert_types)
{
cp->h.code = EVIL_CODE;
+ cp_silent = 0;
return;
}
@@ -1002,6 +1011,7 @@ compute_conversion_costs (function, tta_in, cp, arglen)
cp->h.code |= ELLIPSIS_CODE;
if (user_strikes)
cp->h.code |= USER_CODE;
+ cp_silent = 0;
#ifdef DEBUG_MATCHING
cp_error ("final eval %s", print_harshness (&cp->h));
#endif
@@ -1332,7 +1342,7 @@ resolve_scope_to_name (outer_type, inner_stuff)
/* We first try to look for a nesting in our current class context,
then try any enclosing classes. */
tree type = current_class_type;
-
+
while (type && (TREE_CODE (type) == RECORD_TYPE
|| TREE_CODE (type) == UNION_TYPE))
{
@@ -1405,7 +1415,7 @@ build_scoped_method_call (exp, scopes, name, parms)
a pointer to a base class to be `stolen',
we need not protect the derived->base conversion
that happens here.
-
+
@@ But we do have to check access privileges later. */
tree basename = resolve_scope_to_name (NULL_TREE, scopes);
tree basetype, binfo, decl;
@@ -1428,11 +1438,11 @@ build_scoped_method_call (exp, scopes, name, parms)
if (type != basetype)
cp_error ("type of `%E' does not match destructor type `%T' (type was `%T')",
exp, basetype, type);
- name = IDENTIFIER_TYPE_VALUE (TREE_OPERAND (name, 0));
- if (basetype != name)
- cp_error ("qualified type `%T' does not match destructor type `%T'",
+ name = TREE_OPERAND (name, 0);
+ if (basetype != get_type_value (name))
+ cp_error ("qualified type `%T' does not match destructor name `~%T'",
basetype, name);
- return void_zero_node;
+ return convert (void_type_node, exp);
}
if (! is_aggr_typedef (basename, 1))
@@ -1460,16 +1470,17 @@ build_scoped_method_call (exp, scopes, name, parms)
{
/* Explicit call to destructor. */
name = TREE_OPERAND (name, 0);
- if (name != constructor_name (TREE_TYPE (decl)))
+ if (! (name == constructor_name (TREE_TYPE (decl))
+ || TREE_TYPE (decl) == get_type_value (name)))
{
cp_error
- ("qualified type `%T' does not match destructor type `%T'",
+ ("qualified type `%T' does not match destructor name `~%T'",
TREE_TYPE (decl), name);
return error_mark_node;
}
if (! TYPE_HAS_DESTRUCTOR (TREE_TYPE (decl)))
- return void_zero_node;
-
+ return convert (void_type_node, exp);
+
return build_delete (TREE_TYPE (decl), decl, integer_two_node,
LOOKUP_NORMAL|LOOKUP_NONVIRTUAL|LOOKUP_DESTRUCTOR,
0);
@@ -1604,23 +1615,19 @@ build_method_call (instance, name, parms, basetype_path, flags)
if (parms)
error ("destructors take no parameters");
basetype = TREE_TYPE (instance);
- if (IS_AGGR_TYPE (basetype))
- {
- if (name == constructor_name (basetype))
- goto huzzah;
- }
- else
+ if (TREE_CODE (basetype) == REFERENCE_TYPE)
+ basetype = TREE_TYPE (basetype);
+ if (! ((IS_AGGR_TYPE (basetype)
+ && name == constructor_name (basetype))
+ || basetype == get_type_value (name)))
{
- if (basetype == get_type_value (name))
- goto huzzah;
+ cp_error ("destructor name `~%D' does not match type `%T' of expression",
+ name, basetype);
+ return convert (void_type_node, instance);
}
- cp_error ("destructor name `~%D' does not match type `%T' of expression",
- name, basetype);
- return void_zero_node;
- huzzah:
if (! TYPE_HAS_DESTRUCTOR (basetype))
- return void_zero_node;
+ return convert (void_type_node, instance);
instance = default_conversion (instance);
instance_ptr = build_unary_op (ADDR_EXPR, instance, 0);
return build_delete (build_pointer_type (basetype),
@@ -1630,7 +1637,7 @@ build_method_call (instance, name, parms, basetype_path, flags)
{
char *xref_name;
-
+
/* Initialize name for error reporting. */
if (IDENTIFIER_OPNAME_P (name) && ! IDENTIFIER_TYPENAME_P (name))
{
@@ -1806,7 +1813,11 @@ build_method_call (instance, name, parms, basetype_path, flags)
}
else
{
- if (TREE_CODE (instance) != CALL_EXPR)
+ if (TREE_CODE (instance) != CALL_EXPR
+#ifdef PCC_STATIC_STRUCT_RETURN
+ && TREE_CODE (instance) != RTL_EXPR
+#endif
+ )
my_friendly_abort (125);
if (TYPE_NEEDS_CONSTRUCTING (basetype))
instance = build_cplus_new (basetype, instance, 0);
@@ -1897,6 +1908,8 @@ build_method_call (instance, name, parms, basetype_path, flags)
{
TREE_VALUE (parm) = build_unary_op (ADDR_EXPR, TREE_VALUE (parm), 0);
}
+#if 0
+ /* This breaks reference-to-array parameters. */
if (TREE_CODE (t) == ARRAY_TYPE)
{
/* Perform the conversion from ARRAY_TYPE to POINTER_TYPE in place.
@@ -1904,6 +1917,7 @@ build_method_call (instance, name, parms, basetype_path, flags)
TREE_VALUE (parm) = default_conversion (TREE_VALUE (parm));
t = TREE_TYPE (TREE_VALUE (parm));
}
+#endif
if (t == error_mark_node)
return error_mark_node;
last = build_tree_list (NULL_TREE, t);
@@ -1932,7 +1946,9 @@ build_method_call (instance, name, parms, basetype_path, flags)
{
constp = 0;
volatilep = 0;
- parms = tree_cons (NULL_TREE, build1 (NOP_EXPR, TYPE_POINTER_TO (basetype), integer_zero_node), parms);
+ parms = tree_cons (NULL_TREE,
+ build1 (NOP_EXPR, TYPE_POINTER_TO (basetype),
+ integer_zero_node), parms);
}
else
{
@@ -1945,6 +1961,10 @@ build_method_call (instance, name, parms, basetype_path, flags)
TREE_CALLS_NEW (instance_ptr) = 1;
instance = build_indirect_ref (instance_ptr, NULL_PTR);
+#if 0
+ /* This breaks initialization of a reference from a new
+ expression of a different type. And it doesn't appear to
+ serve its original purpose any more, either. jason 10/12/94 */
/* If it's a default argument initialized from a ctor, what we get
from instance_ptr will match the arglist for the FUNCTION_DECL
of the constructor. */
@@ -1953,6 +1973,7 @@ build_method_call (instance, name, parms, basetype_path, flags)
&& TREE_CALLS_NEW (TREE_VALUE (TREE_OPERAND (TREE_VALUE (parms), 1))))
parms = build_tree_list (NULL_TREE, instance_ptr);
else
+#endif
parms = tree_cons (NULL_TREE, instance_ptr, parms);
}
}
@@ -1976,18 +1997,18 @@ build_method_call (instance, name, parms, basetype_path, flags)
tmp = TYPE_BINFO (basetype);
else
tmp = get_binfo (IDENTIFIER_TYPE_VALUE (name), basetype, 0);
-
+
if (tmp != NULL_TREE)
{
name_kind = "constructor";
-
+
if (TYPE_USES_VIRTUAL_BASECLASSES (basetype)
&& ! (flags & LOOKUP_HAS_IN_CHARGE))
{
/* Constructors called for initialization
only are never in charge. */
tree tmplist;
-
+
flags |= LOOKUP_HAS_IN_CHARGE;
tmplist = tree_cons (NULL_TREE, integer_zero_node,
TREE_CHAIN (parms));
@@ -2002,7 +2023,7 @@ build_method_call (instance, name, parms, basetype_path, flags)
}
else
name_kind = "method";
-
+
if (basetype_path == NULL_TREE
|| BINFO_TYPE (basetype_path) != TYPE_MAIN_VARIANT (basetype))
basetype_path = TYPE_BINFO (basetype);
@@ -2012,6 +2033,7 @@ build_method_call (instance, name, parms, basetype_path, flags)
return error_mark_node;
+#if 0
/* Now, go look for this method name. We do not find destructors here.
Putting `void_list_node' on the end of the parmtypes
@@ -2021,6 +2043,7 @@ build_method_call (instance, name, parms, basetype_path, flags)
1 + (name == constructor_name (save_basetype)
|| name == constructor_name_full (save_basetype)));
TREE_CHAIN (last) = NULL_TREE;
+#endif
for (pass = 0; pass < 2; pass++)
{
@@ -2040,7 +2063,7 @@ build_method_call (instance, name, parms, basetype_path, flags)
candidates
= (struct candidate *) alloca ((ever_seen+1)
* sizeof (struct candidate));
- bzero (candidates, (ever_seen + 1) * sizeof (struct candidate));
+ bzero ((char *) candidates, (ever_seen + 1) * sizeof (struct candidate));
cp = candidates;
len = list_length (parms);
ever_seen = 0;
@@ -2062,7 +2085,7 @@ build_method_call (instance, name, parms, basetype_path, flags)
{
tree new_type;
parm = build_indirect_ref (parm, "friendifying parms (compiler error)");
- new_type = c_build_type_variant (TREE_TYPE (parm), constp,
+ new_type = cp_build_type_variant (TREE_TYPE (parm), constp,
volatilep);
new_type = build_reference_type (new_type);
parm = convert (new_type, parm);
@@ -2102,7 +2125,7 @@ build_method_call (instance, name, parms, basetype_path, flags)
match any methods. Since we have verified that the is
some method vaguely matching this one (in name at least),
silently return.
-
+
Don't stop for friends, however. */
basetype_path = TREE_PURPOSE (baselink);
@@ -2147,9 +2170,11 @@ build_method_call (instance, name, parms, basetype_path, flags)
&& ! DECL_STATIC_FUNCTION_P (function))
continue;
+#if 0
if (pass == 0
&& DECL_ASSEMBLER_NAME (function) == method_name)
goto found;
+#endif
if (pass > 0)
{
@@ -2221,7 +2246,7 @@ build_method_call (instance, name, parms, basetype_path, flags)
if ((flags & (LOOKUP_SPECULATIVELY|LOOKUP_COMPLAIN))
== LOOKUP_SPECULATIVELY)
return NULL_TREE;
-
+
TREE_CHAIN (last) = void_list_node;
if (flags & LOOKUP_GLOBAL)
cp_error ("no global or member function `%D(%A)' defined",
@@ -2244,6 +2269,7 @@ build_method_call (instance, name, parms, basetype_path, flags)
if (cp - candidates > 1)
{
int n_candidates = cp - candidates;
+ extern int warn_synth;
TREE_VALUE (parms) = instance_ptr;
cp = ideal_candidate (save_basetype, candidates,
n_candidates, parms, len);
@@ -2251,14 +2277,25 @@ build_method_call (instance, name, parms, basetype_path, flags)
{
if (flags & LOOKUP_COMPLAIN)
{
- cp_error ("call of overloaded %s `%D' is ambiguous",
- name_kind, name);
+ TREE_CHAIN (last) = void_list_node;
+ cp_error ("call of overloaded %s `%D(%A)' is ambiguous",
+ name_kind, name, TREE_CHAIN (parmtypes));
print_n_candidates (candidates, n_candidates);
}
return error_mark_node;
}
if (cp->h.code & EVIL_CODE)
return error_mark_node;
+ if (warn_synth
+ && DECL_NAME (cp->function) == ansi_opname[MODIFY_EXPR]
+ && DECL_ARTIFICIAL (cp->function)
+ && n_candidates == 2)
+ {
+ cp_warning ("using synthesized `%#D' for copy assignment",
+ cp->function);
+ cp_warning_at (" where cfront would use `%#D'",
+ candidates->function);
+ }
}
else if (cp[-1].h.code & EVIL_CODE)
{
@@ -2355,7 +2392,7 @@ build_method_call (instance, name, parms, basetype_path, flags)
{
if (flags & LOOKUP_COMPLAIN)
{
- cp_error_at ("%s `%+#D' is %s", name_kind, function,
+ cp_error_at ("%s `%+#D' is %s", name_kind, function,
TREE_PRIVATE (function) ? "private"
: "from private base class");
error ("within this context");
@@ -2579,7 +2616,7 @@ build_method_call (instance, name, parms, basetype_path, flags)
{
int is_constructor;
-
+
if (TREE_CODE (function) == FUNCTION_DECL)
{
is_constructor = DECL_CONSTRUCTOR_P (function);
@@ -2664,7 +2701,11 @@ build_overload_call_real (fnname, parms, flags, final_cp, buildxxx)
final_cp->h.code = EVIL_CODE;
return error_mark_node;
}
- if (TREE_CODE (t) == ARRAY_TYPE || TREE_CODE (t) == OFFSET_TYPE)
+ if (TREE_CODE (t) == OFFSET_TYPE)
+#if 0
+ /* This breaks reference-to-array parameters. */
+ || TREE_CODE (t) == ARRAY_TYPE
+#endif
{
/* Perform the conversion from ARRAY_TYPE to POINTER_TYPE in place.
Also convert OFFSET_TYPE entities to their normal selves.
@@ -2688,7 +2729,7 @@ build_overload_call_real (fnname, parms, flags, final_cp, buildxxx)
else if (TREE_CODE (fnname) == FUNCTION_DECL)
fnname = DECL_NAME (functions);
}
- else
+ else
functions = lookup_name_nonclass (fnname);
if (functions == NULL_TREE)
@@ -2721,7 +2762,7 @@ build_overload_call_real (fnname, parms, flags, final_cp, buildxxx)
{
if (flags & LOOKUP_SPECULATIVELY)
return NULL_TREE;
-
+
if (flags & LOOKUP_COMPLAIN)
cp_error ("function `%D' declared overloaded, but no instances of that function declared",
TREE_PURPOSE (functions));
@@ -2731,14 +2772,14 @@ build_overload_call_real (fnname, parms, flags, final_cp, buildxxx)
}
length = count_functions (functions);
-
+
if (final_cp)
candidates = final_cp;
else
{
candidates
= (struct candidate *)alloca ((length+1) * sizeof (struct candidate));
- bzero (candidates, (length + 1) * sizeof (struct candidate));
+ bzero ((char *) candidates, (length + 1) * sizeof (struct candidate));
}
cp = candidates;
@@ -2882,7 +2923,7 @@ build_overload_call_real (fnname, parms, flags, final_cp, buildxxx)
if (flags & LOOKUP_SPECULATIVELY)
return NULL_TREE;
-
+
if (flags & LOOKUP_COMPLAIN)
report_type_mismatch (cp, parms, "function",
decl_as_string (cp->function, 1));
diff --git a/gnu/usr.bin/cc/cc1plus/class.c b/gnu/usr.bin/cc/cc1plus/class.c
index e715c89..b0d815b 100644
--- a/gnu/usr.bin/cc/cc1plus/class.c
+++ b/gnu/usr.bin/cc/cc1plus/class.c
@@ -136,7 +136,7 @@ complete_type_p (expr)
expr = TREE_OPERAND (expr, 0);
continue;
- case CALL_EXPR:
+ case CALL_EXPR:
if (! TREE_HAS_CONSTRUCTOR (expr))
break;
/* fall through... */
@@ -479,7 +479,7 @@ build_vfn_ref (ptr_to_instptr, instance, idx)
aref = build_array_ref (vtbl, idx);
/* Save the intermediate result in a SAVE_EXPR so we don't have to
- compute each component of the virtual function pointer twice. */
+ compute each component of the virtual function pointer twice. */
if (!building_cleanup && TREE_CODE (aref) == INDIRECT_REF)
TREE_OPERAND (aref, 0) = save_expr (TREE_OPERAND (aref, 0));
@@ -942,7 +942,7 @@ add_method (type, fields, method)
* sizeof (char *)
+ len * sizeof (tree));
tmp_vec = (tree) obstack_base (ob);
- bcopy (method_vec, tmp_vec,
+ bcopy ((char *) method_vec, (char *) tmp_vec,
(sizeof (struct tree_common)
+ tree_code_length[(int) TREE_VEC] * sizeof (char *)
+ (len-1) * sizeof (tree)));
@@ -992,20 +992,18 @@ add_method (type, fields, method)
not duplicates, they are just anonymous fields. This happens
when we have unnamed bitfields, for example. */
static tree
-delete_duplicate_fields_1 (field, field_ptr, fields)
- tree field, *field_ptr, fields;
+delete_duplicate_fields_1 (field, fields)
+ tree field, fields;
{
tree x;
- tree prev = field_ptr ? *field_ptr : 0;
+ tree prev = 0;
if (DECL_NAME (field) == 0)
{
if (TREE_CODE (TREE_TYPE (field)) != UNION_TYPE)
return fields;
for (x = TYPE_FIELDS (TREE_TYPE (field)); x; x = TREE_CHAIN (x))
- fields = delete_duplicate_fields_1 (x, field_ptr, fields);
- if (prev)
- TREE_CHAIN (prev) = fields;
+ fields = delete_duplicate_fields_1 (x, fields);
return fields;
}
else
@@ -1017,7 +1015,7 @@ delete_duplicate_fields_1 (field, field_ptr, fields)
if (TREE_CODE (TREE_TYPE (x)) != UNION_TYPE)
continue;
TYPE_FIELDS (TREE_TYPE (x))
- = delete_duplicate_fields_1 (field, (tree *)0, TYPE_FIELDS (TREE_TYPE (x)));
+ = delete_duplicate_fields_1 (field, TYPE_FIELDS (TREE_TYPE (x)));
if (TYPE_FIELDS (TREE_TYPE (x)) == 0)
{
if (prev == 0)
@@ -1039,7 +1037,7 @@ delete_duplicate_fields_1 (field, field_ptr, fields)
x);
else if (TREE_CODE (field) == TYPE_DECL
&& TREE_CODE (x) == TYPE_DECL)
- cp_error_at ("duplicate class scope type `%D'", x);
+ cp_error_at ("duplicate nested type `%D'", x);
else if (TREE_CODE (field) == TYPE_DECL
|| TREE_CODE (x) == TYPE_DECL)
cp_error_at ("duplicate field `%D' (as type and non-type)",
@@ -1063,7 +1061,7 @@ delete_duplicate_fields (fields)
{
tree x;
for (x = fields; x && TREE_CHAIN (x); x = TREE_CHAIN (x))
- TREE_CHAIN (x) = delete_duplicate_fields_1 (x, &x, TREE_CHAIN (x));
+ TREE_CHAIN (x) = delete_duplicate_fields_1 (x, TREE_CHAIN (x));
}
/* Change the access of FDECL to ACCESS in T.
@@ -1121,10 +1119,14 @@ get_vfield_offset (binfo)
BINFO_OFFSET (binfo));
}
-/* Get the offset to the start of the original binfo that we derived this
- binfo from. */
-tree get_derived_offset (binfo)
- tree binfo;
+/* Get the offset to the start of the original binfo that we derived
+ this binfo from. If we find TYPE first, return the offset only
+ that far. The shortened search is useful because the this pointer
+ on method calling is expected to point to a DECL_CONTEXT (fndecl)
+ object, and not a baseclass of it. */
+static tree
+get_derived_offset (binfo, type)
+ tree binfo, type;
{
tree offset1 = get_vfield_offset (TYPE_BINFO (BINFO_TYPE (binfo)));
tree offset2;
@@ -1133,6 +1135,8 @@ tree get_derived_offset (binfo)
&& (i=CLASSTYPE_VFIELD_PARENT (BINFO_TYPE (binfo))) != -1)
{
tree binfos = BINFO_BASETYPES (binfo);
+ if (BINFO_TYPE (binfo) == type)
+ break;
binfo = TREE_VEC_ELT (binfos, i);
}
offset2 = get_vfield_offset (TYPE_BINFO (BINFO_TYPE (binfo)));
@@ -1340,7 +1344,7 @@ finish_base_struct (t, b, t_binfo)
tree binfos = BINFO_BASETYPES (t_binfo);
int i, n_baseclasses = binfos ? TREE_VEC_LENGTH (binfos) : 0;
int first_vfn_base_index = -1;
- bzero (b, sizeof (struct base_info));
+ bzero ((char *) b, sizeof (struct base_info));
for (i = 0; i < n_baseclasses; i++)
{
@@ -1567,7 +1571,7 @@ finish_base_struct (t, b, t_binfo)
b->cant_synth_copy_ctor = 1;
}
}
- }
+ }
{
tree vfields;
@@ -1682,8 +1686,8 @@ finish_struct_bits (t, max_has_virtual)
tree *tmp;
int i;
- bzero (first_conversions, sizeof (first_conversions));
- bzero (last_conversions, sizeof (last_conversions));
+ bzero ((char *) first_conversions, sizeof (first_conversions));
+ bzero ((char *) last_conversions, sizeof (last_conversions));
for (tmp = &TREE_VEC_ELT (method_vec, 1);
tmp != TREE_VEC_END (method_vec); tmp += 1)
{
@@ -1811,7 +1815,7 @@ finish_struct_methods (t, fn_fields, nonprivate_method)
{
tree parmtypes = FUNCTION_ARG_CHAIN (fn_fields);
tree parmtype = parmtypes ? TREE_VALUE (parmtypes) : void_type_node;
-
+
if (TREE_CODE (parmtype) == REFERENCE_TYPE
&& TYPE_MAIN_VARIANT (TREE_TYPE (parmtype)) == t)
{
@@ -1830,8 +1834,7 @@ finish_struct_methods (t, fn_fields, nonprivate_method)
{
tree parmtype = TREE_VALUE (FUNCTION_ARG_CHAIN (fn_fields));
- if (TREE_CODE (parmtype) == REFERENCE_TYPE
- && TYPE_MAIN_VARIANT (TREE_TYPE (parmtype)) == t)
+ if (copy_assignment_arg_p (parmtype, DECL_VIRTUAL_P (fn_fields)))
{
if (TREE_PROTECTED (fn_fields))
TYPE_HAS_NONPUBLIC_ASSIGN_REF (t) = 1;
@@ -1938,8 +1941,8 @@ finish_struct_methods (t, fn_fields, nonprivate_method)
&& CLASSTYPE_FRIEND_CLASSES (t) == NULL_TREE
&& DECL_FRIENDLIST (TYPE_NAME (t)) == NULL_TREE
&& warn_ctor_dtor_privacy)
- warning ("class `%s' only defines a private destructor and has no friends",
- TYPE_NAME_STRING (t));
+ cp_warning ("`%#T' only defines a private destructor and has no friends",
+ t);
break;
}
}
@@ -2037,14 +2040,14 @@ duplicate_tag_error (t)
* This used to be in finish_struct, but it turns out that the
* TREE_CHAIN is used by dbxout_type_methods and perhaps some other things...
*/
- if (CLASSTYPE_METHOD_VEC(t))
+ if (CLASSTYPE_METHOD_VEC(t))
{
tree tv = CLASSTYPE_METHOD_VEC(t);
int i, len = TREE_VEC_LENGTH (tv);
for (i = 0; i < len; i++)
{
tree unchain = TREE_VEC_ELT (tv, i);
- while (unchain != NULL_TREE)
+ while (unchain != NULL_TREE)
{
TREE_CHAIN (unchain) = NULL_TREE;
unchain = DECL_CHAIN(unchain);
@@ -2060,7 +2063,7 @@ duplicate_tag_error (t)
int interface_only = CLASSTYPE_INTERFACE_ONLY (t);
int interface_unknown = CLASSTYPE_INTERFACE_UNKNOWN (t);
- bzero (TYPE_LANG_SPECIFIC (t), sizeof (struct lang_type));
+ bzero ((char *) TYPE_LANG_SPECIFIC (t), sizeof (struct lang_type));
BINFO_BASETYPES(binfo) = NULL_TREE;
CLASSTYPE_AS_LIST (t) = as_list;
@@ -2151,13 +2154,93 @@ overrides (fndecl, base_fndecl)
return 0;
}
+static tree
+get_class_offset_1 (parent, binfo, context, t, fndecl)
+ tree parent, binfo, context, t, fndecl;
+{
+ tree binfos = BINFO_BASETYPES (binfo);
+ int i, n_baselinks = binfos ? TREE_VEC_LENGTH (binfos) : 0;
+ tree rval = NULL_TREE;
+
+ if (binfo == parent)
+ return error_mark_node;
+
+ for (i = 0; i < n_baselinks; i++)
+ {
+ tree base_binfo = TREE_VEC_ELT (binfos, i);
+ tree nrval;
+
+ if (TREE_VIA_VIRTUAL (base_binfo))
+ base_binfo = binfo_member (BINFO_TYPE (base_binfo),
+ CLASSTYPE_VBASECLASSES (t));
+ nrval = get_class_offset_1 (parent, base_binfo, context, t, fndecl);
+ /* See if we have a new value */
+ if (nrval && (nrval != error_mark_node || rval==0))
+ {
+ /* Only compare if we have two offsets */
+ if (rval && rval != error_mark_node
+ && ! tree_int_cst_equal (nrval, rval))
+ {
+ /* Only give error if the two offsets are different */
+ error ("every virtual function must have a unique final overrider");
+ cp_error (" found two (or more) `%T' class subobjects in `%T'", context, t);
+ cp_error (" with virtual `%D' from virtual base class", fndecl);
+ return rval;
+ }
+ rval = nrval;
+ }
+
+ if (rval && BINFO_TYPE (binfo) == context)
+ {
+ my_friendly_assert (rval == error_mark_node
+ || tree_int_cst_equal (rval, BINFO_OFFSET (binfo)), 999);
+ rval = BINFO_OFFSET (binfo);
+ }
+ }
+ return rval;
+}
+
+/* Get the offset to the CONTEXT subobject that is related to the
+ given BINFO. */
+static tree
+get_class_offset (context, t, binfo, fndecl)
+ tree context, t, binfo, fndecl;
+{
+ tree first_binfo = binfo;
+ tree offset;
+ int i;
+
+ if (context == t)
+ return integer_zero_node;
+
+ if (BINFO_TYPE (binfo) == context)
+ return BINFO_OFFSET (binfo);
+
+ /* Check less derived binfos first. */
+ while (BINFO_BASETYPES (binfo)
+ && (i=CLASSTYPE_VFIELD_PARENT (BINFO_TYPE (binfo))) != -1)
+ {
+ tree binfos = BINFO_BASETYPES (binfo);
+ binfo = TREE_VEC_ELT (binfos, i);
+ if (BINFO_TYPE (binfo) == context)
+ return BINFO_OFFSET (binfo);
+ }
+
+ /* Ok, not found in the less derived binfos, now check the more
+ derived binfos. */
+ offset = get_class_offset_1 (first_binfo, TYPE_BINFO (t), context, t, fndecl);
+ if (offset==0 || TREE_CODE (offset) != INTEGER_CST)
+ my_friendly_abort (999); /* we have to find it. */
+ return offset;
+}
+
static void
modify_one_vtable (binfo, t, fndecl, pfn)
tree binfo, t, fndecl, pfn;
{
tree virtuals = BINFO_VIRTUALS (binfo);
unsigned HOST_WIDE_INT n;
-
+
n = 0;
/* Skip initial vtable length field and RTTI fake object. */
for (; virtuals && n < 1 + flag_dossier; n++)
@@ -2174,16 +2257,7 @@ modify_one_vtable (binfo, t, fndecl, pfn)
tree vfield = CLASSTYPE_VFIELD (t);
tree this_offset;
- offset = integer_zero_node;
- if (context != t && TYPE_USES_COMPLEX_INHERITANCE (t))
- {
- offset = virtual_offset (context, CLASSTYPE_VBASECLASSES (t), offset);
- if (offset == NULL_TREE)
- {
- tree binfo = get_binfo (context, t, 0);
- offset = BINFO_OFFSET (binfo);
- }
- }
+ offset = get_class_offset (context, t, binfo, fndecl);
/* Find the right offset for the this pointer based on the
base class we just found. We have to take into
@@ -2193,7 +2267,7 @@ modify_one_vtable (binfo, t, fndecl, pfn)
Also, we want just the delta bewteen the most base class
that we derived this vfield from and us. */
base_offset = size_binop (PLUS_EXPR,
- get_derived_offset (binfo),
+ get_derived_offset (binfo, DECL_CONTEXT (current_fndecl)),
BINFO_OFFSET (binfo));
this_offset = size_binop (MINUS_EXPR, offset, base_offset);
@@ -2270,7 +2344,7 @@ fixup_vtable_deltas (binfo, t)
{
tree virtuals = BINFO_VIRTUALS (binfo);
unsigned HOST_WIDE_INT n;
-
+
n = 0;
/* Skip initial vtable length field and RTTI fake object. */
for (; virtuals && n < 1 + flag_dossier; n++)
@@ -2288,16 +2362,7 @@ fixup_vtable_deltas (binfo, t)
tree vfield = CLASSTYPE_VFIELD (t);
tree this_offset;
- offset = integer_zero_node;
- if (context != t && TYPE_USES_COMPLEX_INHERITANCE (t))
- {
- offset = virtual_offset (context, CLASSTYPE_VBASECLASSES (t), offset);
- if (offset == NULL_TREE)
- {
- tree binfo = get_binfo (context, t, 0);
- offset = BINFO_OFFSET (binfo);
- }
- }
+ offset = get_class_offset (context, t, binfo, fndecl);
/* Find the right offset for the this pointer based on the
base class we just found. We have to take into
@@ -2307,7 +2372,7 @@ fixup_vtable_deltas (binfo, t)
Also, we want just the delta bewteen the most base class
that we derived this vfield from and us. */
base_offset = size_binop (PLUS_EXPR,
- get_derived_offset (binfo),
+ get_derived_offset (binfo, DECL_CONTEXT (fndecl)),
BINFO_OFFSET (binfo));
this_offset = size_binop (MINUS_EXPR, offset, base_offset);
@@ -2387,7 +2452,7 @@ modify_all_vtables (t, fndecl, vfn)
/* Here, we already know that they match in every respect.
All we have to check is where they had their declarations. */
-static int
+static int
strictly_overrides (fndecl1, fndecl2)
tree fndecl1, fndecl2;
{
@@ -2486,7 +2551,7 @@ override_one_vtable (binfo, old, t)
else if (choose == NEITHER)
{
TREE_VALUE (virtuals) = TREE_VALUE (old_virtuals);
- }
+ }
}
else
{
@@ -2512,7 +2577,7 @@ override_one_vtable (binfo, old, t)
vfn = build1 (ADDR_EXPR, vfunc_ptr_type_node, fndecl);
TREE_CONSTANT (vfn) = 1;
-
+
/* We can use integer_zero_node, as we will will core dump
if this is used anyway. */
TREE_VALUE (virtuals) = build_vtable_entry (integer_zero_node, vfn);
@@ -2675,7 +2740,7 @@ finish_struct (t, list_of_fieldlists, warn_anon)
#endif
{
extern int lineno;
-
+
DECL_SOURCE_FILE (name) = input_filename;
/* For TYPE_DECL that are not typedefs (those marked with a line
number of zero, we don't want to mark them as real typedefs.
@@ -2684,6 +2749,7 @@ finish_struct (t, list_of_fieldlists, warn_anon)
will fill in the right line number. (mrs) */
if (DECL_SOURCE_LINE (name))
DECL_SOURCE_LINE (name) = lineno;
+ CLASSTYPE_SOURCE_LINE (t) = lineno;
}
name = DECL_NAME (name);
}
@@ -2713,18 +2779,15 @@ finish_struct (t, list_of_fieldlists, warn_anon)
TYPE_SIZE (t) = NULL_TREE;
CLASSTYPE_GOT_SEMICOLON (t) = 0;
- /* A signature type will contain the fields of the signature table.
- Therefore, it's not only an interface. */
- if (IS_SIGNATURE (t))
- {
- CLASSTYPE_INTERFACE_ONLY (t) = 0;
- SET_CLASSTYPE_INTERFACE_KNOWN (t);
- }
- else
+#if 0
+ /* This is in general too late to do this. I moved the main case up to
+ left_curly, what else needs to move? */
+ if (! IS_SIGNATURE (t))
{
- CLASSTYPE_INTERFACE_ONLY (t) = interface_only;
- SET_CLASSTYPE_INTERFACE_UNKNOWN_X (t, interface_unknown);
+ my_friendly_assert (CLASSTYPE_INTERFACE_ONLY (t) == interface_only, 999);
+ my_friendly_assert (CLASSTYPE_INTERFACE_KNOWN (t) == ! interface_unknown, 999);
}
+#endif
if (flag_dossier)
build_t_desc (t, 0);
@@ -2787,14 +2850,15 @@ finish_struct (t, list_of_fieldlists, warn_anon)
needs_virtual_dtor = 0;
}
+#if 0
+ /* Both of these should be done before now. */
if (write_virtuals == 3 && CLASSTYPE_INTERFACE_KNOWN (t)
&& ! IS_SIGNATURE (t))
{
- CLASSTYPE_INTERFACE_ONLY (t) = interface_only;
- CLASSTYPE_VTABLE_NEEDS_WRITING (t) = ! interface_only;
+ my_friendly_assert (CLASSTYPE_INTERFACE_ONLY (t) == interface_only, 999);
+ my_friendly_assert (CLASSTYPE_VTABLE_NEEDS_WRITING (t) == ! interface_only, 999);
}
- else if (IS_SIGNATURE (t))
- CLASSTYPE_VTABLE_NEEDS_WRITING (t) = 0;
+#endif
/* The three of these are approximations which may later be
modified. Needed at this point to make add_virtual_function
@@ -2951,9 +3015,12 @@ finish_struct (t, list_of_fieldlists, warn_anon)
TREE_TYPE (x) = build_pointer_type (TREE_TYPE (x));
}
+ if (DECL_NAME (x) == constructor_name (t))
+ cant_have_default_ctor = cant_synth_copy_ctor = 1;
+
if (TREE_TYPE (x) == error_mark_node)
continue;
-
+
if (! fields)
fields = x;
last_x = x;
@@ -2971,7 +3038,7 @@ finish_struct (t, list_of_fieldlists, warn_anon)
if (TREE_CODE (t) == UNION_TYPE)
/* Unions cannot have static members. */
cp_error_at ("field `%D' declared static in union", x);
-
+
continue;
}
@@ -3129,11 +3196,11 @@ finish_struct (t, list_of_fieldlists, warn_anon)
make it through without complaint. */
if (CLASSTYPE_ABSTRACT_VIRTUALS (type))
abstract_virtuals_error (x, type);
-
+
/* Don't let signatures make it through either. */
if (IS_SIGNATURE (type))
signature_error (x, type);
-
+
if (code == UNION_TYPE)
{
char *fie = NULL;
@@ -3217,12 +3284,14 @@ finish_struct (t, list_of_fieldlists, warn_anon)
CLASSTYPE_REF_FIELDS_NEED_INIT (t) = ref_sans_init;
CLASSTYPE_ABSTRACT_VIRTUALS (t) = abstract_virtuals;
+ /* Synthesize any needed methods. Note that methods will be synthesized
+ for anonymous unions; grok_x_components undoes that. */
+
if (TYPE_NEEDS_DESTRUCTOR (t) && !TYPE_HAS_DESTRUCTOR (t)
&& !IS_SIGNATURE (t))
{
/* Here we must cons up a destructor on the fly. */
- tree dtor = cons_up_default_function (t, name, fields,
- needs_virtual_dtor != 0);
+ tree dtor = cons_up_default_function (t, name, needs_virtual_dtor != 0);
/* If we couldn't make it work, then pretend we didn't need it. */
if (dtor == void_type_node)
@@ -3251,9 +3320,6 @@ finish_struct (t, list_of_fieldlists, warn_anon)
TYPE_NEEDS_DESTRUCTOR (t) |= TYPE_HAS_DESTRUCTOR (t);
- /* Synthesize any needed methods. Note that methods will be synthesized
- for anonymous unions; grok_x_components undoes that. */
-
if (! fn_fields)
nonprivate_method = 1;
@@ -3271,7 +3337,7 @@ finish_struct (t, list_of_fieldlists, warn_anon)
if (! TYPE_HAS_CONSTRUCTOR (t) && ! cant_have_default_ctor
&& ! IS_SIGNATURE (t))
{
- tree default_fn = cons_up_default_function (t, name, fields, 2);
+ tree default_fn = cons_up_default_function (t, name, 2);
TREE_CHAIN (default_fn) = fn_fields;
fn_fields = default_fn;
}
@@ -3282,9 +3348,8 @@ finish_struct (t, list_of_fieldlists, warn_anon)
{
/* ARM 12.18: You get either X(X&) or X(const X&), but
not both. --Chip */
- tree default_fn =
- cons_up_default_function (t, name, fields,
- cant_have_const_ctor ? 4 : 3);
+ tree default_fn = cons_up_default_function (t, name,
+ 3 + cant_have_const_ctor);
TREE_CHAIN (default_fn) = fn_fields;
fn_fields = default_fn;
}
@@ -3298,9 +3363,8 @@ finish_struct (t, list_of_fieldlists, warn_anon)
if (! TYPE_HAS_ASSIGN_REF (t) && ! cant_synth_asn_ref
&& ! IS_SIGNATURE (t))
{
- tree default_fn =
- cons_up_default_function (t, name, fields,
- no_const_asn_ref ? 6 : 5);
+ tree default_fn = cons_up_default_function (t, name,
+ 5 + no_const_asn_ref);
TREE_CHAIN (default_fn) = fn_fields;
fn_fields = default_fn;
}
@@ -3343,7 +3407,7 @@ finish_struct (t, list_of_fieldlists, warn_anon)
{
int n_methods = method_vec ? TREE_VEC_LENGTH (method_vec) : 0;
-
+
for (access_decls = nreverse (access_decls); access_decls;
access_decls = TREE_CHAIN (access_decls))
{
@@ -3351,7 +3415,7 @@ finish_struct (t, list_of_fieldlists, warn_anon)
tree flist = NULL_TREE;
tree name;
enum access_type access = (enum access_type)TREE_PURPOSE(access_decls);
- int i = 0;
+ int i = TREE_VEC_ELT (method_vec, 0) ? 0 : 1;
tree tmp;
if (TREE_CODE (fdecl) == TREE_LIST)
@@ -3374,7 +3438,7 @@ finish_struct (t, list_of_fieldlists, warn_anon)
if (! fdecl)
continue;
-
+
for (tmp = fields; tmp; tmp = TREE_CHAIN (tmp))
if (DECL_NAME (tmp) == name)
{
@@ -3386,7 +3450,7 @@ finish_struct (t, list_of_fieldlists, warn_anon)
if (!fdecl)
continue;
-
+
/* Make type T see field decl FDECL with access ACCESS.*/
if (flist)
{
@@ -3401,7 +3465,7 @@ finish_struct (t, list_of_fieldlists, warn_anon)
else
alter_access (t, fdecl, access);
}
-
+
}
if (vfield == NULL_TREE && has_virtual)
@@ -3459,6 +3523,27 @@ finish_struct (t, list_of_fieldlists, warn_anon)
/* Delete all duplicate fields from the fields */
delete_duplicate_fields (fields);
+ /* Catch function/field name conflict. We don't need to do this for a
+ signature, since it can only contain the fields constructed in
+ append_signature_fields. */
+ if (! IS_SIGNATURE (t))
+ {
+ int n_methods = method_vec ? TREE_VEC_LENGTH (method_vec) : 0;
+ for (x = fields; x; x = TREE_CHAIN (x))
+ {
+ tree name = DECL_NAME (x);
+ int i = /*TREE_VEC_ELT (method_vec, 0) ? 0 : */ 1;
+ for (; i < n_methods; ++i)
+ if (DECL_NAME (TREE_VEC_ELT (method_vec, i)) == name)
+ {
+ cp_error_at ("data member `%#D' conflicts with", x);
+ cp_error_at ("function member `%#D'",
+ TREE_VEC_ELT (method_vec, i));
+ break;
+ }
+ }
+ }
+
/* Now we have the final fieldlist for the data fields. Record it,
then lay out the structure or union (including the fields). */
@@ -3498,6 +3583,9 @@ finish_struct (t, list_of_fieldlists, warn_anon)
tree uelt = TYPE_FIELDS (TREE_TYPE (field));
for (; uelt; uelt = TREE_CHAIN (uelt))
{
+ if (TREE_CODE (uelt) != FIELD_DECL)
+ continue;
+
DECL_FIELD_CONTEXT (uelt) = DECL_FIELD_CONTEXT (field);
DECL_FIELD_BITPOS (uelt) = DECL_FIELD_BITPOS (field);
}
@@ -3552,6 +3640,9 @@ finish_struct (t, list_of_fieldlists, warn_anon)
tree uelt = TYPE_FIELDS (TREE_TYPE (field));
for (; uelt; uelt = TREE_CHAIN (uelt))
{
+ if (TREE_CODE (uelt) != FIELD_DECL)
+ continue;
+
DECL_FIELD_CONTEXT (uelt) = DECL_FIELD_CONTEXT (field);
DECL_FIELD_BITPOS (uelt) = DECL_FIELD_BITPOS (field);
}
@@ -3655,7 +3746,7 @@ finish_struct (t, list_of_fieldlists, warn_anon)
= size_binop (PLUS_EXPR, offset, DECL_FIELD_BITPOS (vfield));
CLASSTYPE_VFIELD (t) = vfield;
}
-
+
#ifdef NOTQUITE
cp_warning ("Doing hard virtuals for %T...", t);
#endif
@@ -4282,7 +4373,7 @@ pushclass (type, modify)
if (flag_cadillac)
cadillac_push_class (type);
}
-
+
/* Get out of the current class scope. If we were in a class scope
previously, that is the one popped to. The flag MODIFY tells whether
the current scope declarations needs to be modified as a result of
@@ -4402,7 +4493,7 @@ push_nested_class (type, modify)
if (type == error_mark_node || ! IS_AGGR_TYPE (type))
return;
-
+
context = DECL_CONTEXT (TYPE_NAME (type));
if (context && TREE_CODE (context) == RECORD_TYPE)
@@ -4456,7 +4547,7 @@ push_lang_context (name)
if (flag_cadillac)
cadillac_push_lang (name);
}
-
+
/* Get out of the current language scope. */
void
pop_lang_context ()
@@ -4634,11 +4725,42 @@ instantiate_type (lhstype, rhs, complain)
{
elem = get_first_fn (rhs);
while (elem)
- if (TREE_TYPE (elem) != lhstype)
+ if (! comptypes (lhstype, TREE_TYPE (elem), 1))
elem = DECL_CHAIN (elem);
else
return elem;
- /* No exact match found, look for a compatible function. */
+
+ /* No exact match found, look for a compatible template. */
+ {
+ tree save_elem = 0;
+ for (elem = get_first_fn (rhs); elem; elem = DECL_CHAIN (elem))
+ if (TREE_CODE (elem) == TEMPLATE_DECL)
+ {
+ int n = TREE_VEC_LENGTH (DECL_TEMPLATE_PARMS (elem));
+ tree *t = (tree *) alloca (sizeof (tree) * n);
+ int i, d;
+ i = type_unification (DECL_TEMPLATE_PARMS (elem), t,
+ TYPE_ARG_TYPES (TREE_TYPE (elem)),
+ TYPE_ARG_TYPES (lhstype), &d, 0);
+ if (i == 0)
+ {
+ if (save_elem)
+ {
+ cp_error ("ambiguous template instantiation converting to `%#T'", lhstype);
+ return error_mark_node;
+ }
+ save_elem = instantiate_template (elem, t);
+ /* Check the return type. */
+ if (! comptypes (TREE_TYPE (lhstype),
+ TREE_TYPE (TREE_TYPE (save_elem)), 1))
+ save_elem = 0;
+ }
+ }
+ if (save_elem)
+ return save_elem;
+ }
+
+ /* No match found, look for a compatible function. */
elem = get_first_fn (rhs);
while (elem && ! comp_target_types (lhstype, TREE_TYPE (elem), 1))
elem = DECL_CHAIN (elem);
@@ -4660,18 +4782,6 @@ instantiate_type (lhstype, rhs, complain)
}
return error_mark_node;
}
- if (TREE_CODE (save_elem) == TEMPLATE_DECL)
- {
- int ntparms = TREE_VEC_LENGTH
- (DECL_TEMPLATE_PARMS (save_elem));
- tree *targs = (tree *) alloca (sizeof (tree) * ntparms);
- int i, dummy;
- i = type_unification
- (DECL_TEMPLATE_PARMS (save_elem), targs,
- TYPE_ARG_TYPES (TREE_TYPE (save_elem)),
- TYPE_ARG_TYPES (lhstype), &dummy, 0);
- save_elem = instantiate_template (save_elem, targs);
- }
return save_elem;
}
if (complain)
@@ -4852,7 +4962,7 @@ instantiate_type (lhstype, rhs, complain)
TREE_TYPE (rhs) = lhstype;
return rhs;
-
+
case ADDR_EXPR:
if (TYPE_PTRMEMFUNC_P (lhstype))
lhstype = TYPE_PTRMEMFUNC_FN_TYPE (lhstype);
@@ -4864,12 +4974,14 @@ instantiate_type (lhstype, rhs, complain)
}
TREE_TYPE (rhs) = lhstype;
lhstype = TREE_TYPE (lhstype);
- TREE_OPERAND (rhs, 0)
- = instantiate_type (lhstype, TREE_OPERAND (rhs, 0), complain);
- if (TREE_OPERAND (rhs, 0) == error_mark_node)
- return error_mark_node;
-
- mark_addressable (TREE_OPERAND (rhs, 0));
+ {
+ tree fn = instantiate_type (lhstype, TREE_OPERAND (rhs, 0), complain);
+ if (fn == error_mark_node)
+ return error_mark_node;
+ mark_addressable (fn);
+ TREE_OPERAND (rhs, 0) = fn;
+ TREE_CONSTANT (rhs) = staticp (fn);
+ }
return rhs;
case ENTRY_VALUE_EXPR:
diff --git a/gnu/usr.bin/cc/cc1plus/cp-tree.h b/gnu/usr.bin/cc/cc1plus/cp-tree.h
index 80fd832..5e3ccbc 100644
--- a/gnu/usr.bin/cc/cc1plus/cp-tree.h
+++ b/gnu/usr.bin/cc/cc1plus/cp-tree.h
@@ -502,8 +502,12 @@ struct lang_type
union tree_node *signature;
union tree_node *signature_pointer_to;
union tree_node *signature_reference_to;
+
+ int linenum;
};
+#define CLASSTYPE_SOURCE_LINE(NODE) (TYPE_LANG_SPECIFIC(NODE)->linenum)
+
/* Indicates whether or not (and how) a template was expanded for this class.
0=no information yet/non-template class
1=implicit template instantiation
@@ -774,7 +778,7 @@ struct lang_type
#define TYPE_HAS_DEFAULT_CONSTRUCTOR(NODE) (TYPE_LANG_SPECIFIC(NODE)->type_flags.has_default_ctor)
/* Nonzero means the type declared a ctor as private or protected. We
- use this to make sure we don't try to generate a copy ctor for a
+ use this to make sure we don't try to generate a copy ctor for a
class that has a member of type NODE. */
#define TYPE_HAS_NONPUBLIC_CTOR(NODE) (TYPE_LANG_SPECIFIC(NODE)->type_flags.has_nonpublic_ctor)
@@ -1010,7 +1014,7 @@ struct lang_decl
#define SHARED_MEMBER_P(NODE) \
(TREE_CODE (NODE) == VAR_DECL || TREE_CODE (NODE) == TYPE_DECL \
|| TREE_CODE (NODE) == CONST_DECL)
-
+
/* Nonzero for FUNCTION_DECL means that this decl is a member function
(static or non-static). */
#define DECL_FUNCTION_MEMBER_P(NODE) \
@@ -1355,7 +1359,7 @@ extern void check_function_format PROTO((tree, tree, tree));
/* Print an error message for invalid operands to arith operation CODE.
NOP_EXPR is used as a special case (see truthvalue_conversion). */
extern void binary_op_error PROTO((enum tree_code));
-extern tree c_build_type_variant PROTO((tree, int, int));
+extern tree cp_build_type_variant PROTO((tree, int, int));
extern void c_expand_expr_stmt PROTO((tree));
/* Validate the expression after `case' and apply default promotions. */
extern tree check_case_value PROTO((tree));
@@ -1627,7 +1631,7 @@ extern int current_function_parms_stored;
#define VPTR_NAME_P(ID_NODE) (IDENTIFIER_POINTER (ID_NODE)[0] == JOINER \
&& IDENTIFIER_POINTER (ID_NODE)[1] == 'v')
#define DESTRUCTOR_NAME_P(ID_NODE) (IDENTIFIER_POINTER (ID_NODE)[1] == JOINER \
- && IDENTIFIER_POINTER (ID_NODE)[2] == '_')
+ && IDENTIFIER_POINTER (ID_NODE)[2] == '_')
#define VTABLE_NAME_P(ID_NODE) (IDENTIFIER_POINTER (ID_NODE)[1] == 'v' \
&& IDENTIFIER_POINTER (ID_NODE)[2] == 't' \
@@ -2011,7 +2015,7 @@ extern void expand_end_all_catch PROTO((void));
extern void start_catch_block PROTO((tree, tree));
extern void end_catch_block PROTO((void));
extern void expand_throw PROTO((tree));
-extern void build_exception_table PROTO((void));
+extern int build_exception_table PROTO((void));
extern tree build_throw PROTO((tree));
extern void init_exception_processing PROTO((void));
@@ -2091,7 +2095,7 @@ extern void reinit_parse_for_method PROTO((int, tree));
#if 0
extern void reinit_parse_for_block PROTO((int, struct obstack *, int));
#endif
-extern tree cons_up_default_function PROTO((tree, tree, tree, int));
+extern tree cons_up_default_function PROTO((tree, tree, int));
extern void check_for_missing_semicolon PROTO((tree));
extern void note_got_semicolon PROTO((tree));
extern void note_list_got_semicolon PROTO((tree));
@@ -2141,6 +2145,7 @@ extern void clear_anon_parm_name PROTO((void));
extern void do_inline_function_hair PROTO((tree, tree));
/* skip report_type_mismatch */
extern char *build_overload_name PROTO((tree, int, int));
+extern tree build_static_name PROTO((tree, tree));
extern tree cplus_exception_name PROTO((tree));
extern tree build_decl_overload PROTO((tree, tree, int));
extern tree build_typename_overload PROTO((tree));
@@ -2254,7 +2259,6 @@ extern tree copy_binfo PROTO((tree));
extern tree binfo_value PROTO((tree, tree));
extern tree reverse_path PROTO((tree));
extern tree virtual_member PROTO((tree, tree));
-extern tree virtual_offset PROTO((tree, tree, tree));
extern void debug_binfo PROTO((tree));
extern int decl_list_length PROTO((tree));
extern int count_functions PROTO((tree));
@@ -2360,7 +2364,7 @@ extern void GNU_xref_end PROTO((int));
extern void GNU_xref_file PROTO((char *));
extern void GNU_xref_start_scope PROTO((HOST_WIDE_INT));
extern void GNU_xref_end_scope PROTO((HOST_WIDE_INT, HOST_WIDE_INT, int, int, int));
-extern void GNU_xref_def PROTO((tree, char *));
+extern void GNU_xref_ref PROTO((tree, char *));
extern void GNU_xref_decl PROTO((tree, tree));
extern void GNU_xref_call PROTO((tree, char *));
extern void GNU_xref_function PROTO((tree, tree));
diff --git a/gnu/usr.bin/cc/cc1plus/cvt.c b/gnu/usr.bin/cc/cc1plus/cvt.c
index cb8d968..444ba27 100644
--- a/gnu/usr.bin/cc/cc1plus/cvt.c
+++ b/gnu/usr.bin/cc/cc1plus/cvt.c
@@ -112,7 +112,7 @@ cp_convert_to_pointer (type, expr)
{
register tree intype = TREE_TYPE (expr);
register enum tree_code form = TREE_CODE (intype);
-
+
if (form == POINTER_TYPE)
{
intype = TYPE_MAIN_VARIANT (intype);
@@ -214,7 +214,7 @@ convert_to_pointer_force (type, expr)
{
register tree intype = TREE_TYPE (expr);
register enum tree_code form = TREE_CODE (intype);
-
+
if (integer_zerop (expr))
{
if (type == TREE_TYPE (null_pointer_node))
@@ -304,7 +304,7 @@ build_up_reference (type, arg, flags, checkconst)
/* Pass along const and volatile down into the type. */
if (TYPE_READONLY (type) || TYPE_VOLATILE (type))
- target_type = c_build_type_variant (target_type, TYPE_READONLY (type),
+ target_type = cp_build_type_variant (target_type, TYPE_READONLY (type),
TYPE_VOLATILE (type));
targ = arg;
if (TREE_CODE (targ) == SAVE_EXPR)
@@ -425,10 +425,11 @@ build_up_reference (type, arg, flags, checkconst)
break;
case PARM_DECL:
+#if 0
if (targ == current_class_decl)
{
error ("address of `this' not available");
-#if 0
+/* #if 0 */
/* This code makes the following core dump the compiler on a sun4,
if the code below is used.
@@ -465,16 +466,18 @@ build_up_reference (type, arg, flags, checkconst)
TREE_ADDRESSABLE (targ) = 1; /* so compiler doesn't die later */
put_var_into_stack (targ);
break;
-#else
+/* #else */
return error_mark_node;
-#endif
+/* #endif */
}
+#endif
/* Fall through. */
case VAR_DECL:
case CONST_DECL:
- if (DECL_REGISTER (targ) && !TREE_ADDRESSABLE (targ))
- warning ("address needed to build reference for `%s', which is declared `register'",
- IDENTIFIER_POINTER (DECL_NAME (targ)));
+ if (DECL_REGISTER (targ) && !TREE_ADDRESSABLE (targ)
+ && !DECL_ARTIFICIAL (targ))
+ cp_warning ("address needed to build reference for `%D', which is declared `register'",
+ targ);
else if (staticp (targ))
literal_flag = 1;
@@ -491,6 +494,8 @@ build_up_reference (type, arg, flags, checkconst)
return rval;
}
+ case PREINCREMENT_EXPR:
+ case PREDECREMENT_EXPR:
case MODIFY_EXPR:
case INIT_EXPR:
{
@@ -624,14 +629,14 @@ convert_to_reference (reftype, expr, convtype, flags, decl)
{
tree ttl = TREE_TYPE (reftype);
tree ttr;
-
+
if (form == REFERENCE_TYPE)
ttr = TREE_TYPE (TREE_TYPE (expr));
else
{
int r = TREE_READONLY (expr);
int v = TREE_THIS_VOLATILE (expr);
- ttr = c_build_type_variant (TREE_TYPE (expr), r, v);
+ ttr = cp_build_type_variant (TREE_TYPE (expr), r, v);
}
if (! lvalue_p (expr) &&
@@ -658,10 +663,12 @@ convert_to_reference (reftype, expr, convtype, flags, decl)
if (form == REFERENCE_TYPE)
{
- rval = copy_node (expr);
- TREE_TYPE (rval) = build_pointer_type (TREE_TYPE (TREE_TYPE (expr)));
- rval = cp_convert (build_pointer_type (TREE_TYPE (reftype)), rval,
+ tree type = TREE_TYPE (expr);
+ tree tmp = copy_node (expr);
+ TREE_TYPE (tmp) = build_pointer_type (TREE_TYPE (TREE_TYPE (expr)));
+ rval = cp_convert (build_pointer_type (TREE_TYPE (reftype)), tmp,
convtype, flags);
+ TREE_TYPE (tmp) = type;
TREE_TYPE (rval) = reftype;
return rval;
}
@@ -693,7 +700,7 @@ convert_to_reference (reftype, expr, convtype, flags, decl)
&& (comptypes (TREE_TYPE (intype), type, -1)))
cp_warning ("casting `%T' to `%T' does not dereference pointer",
intype, reftype);
-
+
rval = build_unary_op (ADDR_EXPR, expr, 0);
if (rval != error_mark_node)
rval = convert_force (build_pointer_type (TREE_TYPE (reftype)), rval);
@@ -704,7 +711,7 @@ convert_to_reference (reftype, expr, convtype, flags, decl)
{
tree rval_as_conversion = NULL_TREE;
tree rval_as_ctor = NULL_TREE;
-
+
if (IS_AGGR_TYPE (intype)
&& (rval = build_type_conversion (CONVERT_EXPR, type, expr, 1)))
{
@@ -713,7 +720,7 @@ convert_to_reference (reftype, expr, convtype, flags, decl)
rval_as_conversion = build_up_reference (reftype, rval, flags, 1);
}
-
+
/* Definitely need to go through a constructor here. */
if (TYPE_HAS_CONSTRUCTOR (type)
&& ! CLASSTYPE_ABSTRACT_VIRTUALS (type)
@@ -771,7 +778,7 @@ convert_to_reference (reftype, expr, convtype, flags, decl)
rval = convert (type, expr);
if (rval == error_mark_node)
return error_mark_node;
-
+
rval = build_up_reference (reftype, rval, flags, 1);
}
@@ -1183,7 +1190,7 @@ cp_convert (type, expr, convtype, flags)
/* Trivial conversion: cv-qualifiers do not matter on rvalues. */
if (TYPE_MAIN_VARIANT (type) == TYPE_MAIN_VARIANT (TREE_TYPE (e)))
return fold (build1 (NOP_EXPR, type, e));
-
+
if (code == VOID_TYPE && (convtype & CONV_STATIC))
return build1 (CONVERT_EXPR, type, e);
@@ -1206,6 +1213,9 @@ cp_convert (type, expr, convtype, flags)
else if (TREE_CODE (TREE_TYPE (e)) == REFERENCE_TYPE)
e = convert_from_reference (e);
+ if (TREE_CODE (e) == OFFSET_REF)
+ e = resolve_offset_ref (e);
+
if (TREE_READONLY_DECL_P (e))
e = decl_constant_value (e);
@@ -1223,18 +1233,13 @@ cp_convert (type, expr, convtype, flags)
if (flag_pedantic_errors)
return error_mark_node;
}
- if (form == OFFSET_TYPE)
- cp_error_at ("pointer-to-member expression object not composed with type `%D' object",
- TYPE_NAME (TYPE_OFFSET_BASETYPE (intype)));
- else if (IS_AGGR_TYPE (intype))
+ if (IS_AGGR_TYPE (intype))
{
tree rval;
rval = build_type_conversion (CONVERT_EXPR, type, e, 1);
- if (rval) return rval;
- if (code == BOOLEAN_TYPE)
- cp_error ("`%#T' used where a `bool' was expected", intype);
- else
- cp_error ("`%#T' used where an `int' was expected", intype);
+ if (rval)
+ return rval;
+ cp_error ("`%#T' used where a `%T' was expected", intype, type);
return error_mark_node;
}
if (code == BOOLEAN_TYPE)
@@ -1280,12 +1285,9 @@ cp_convert (type, expr, convtype, flags)
if (IS_AGGR_TYPE_CODE (code))
{
tree dtype = TREE_TYPE (e);
+ tree ctor = NULL_TREE;
+ tree conversion = NULL_TREE;
- if (TREE_CODE (dtype) == REFERENCE_TYPE)
- {
- e = convert_from_reference (e);
- dtype = TREE_TYPE (e);
- }
dtype = TYPE_MAIN_VARIANT (dtype);
/* Conversion of object pointers or signature pointers/references
@@ -1318,87 +1320,77 @@ cp_convert (type, expr, convtype, flags)
There may be some ambiguity between using a constructor
vs. using a type conversion operator when both apply. */
- else if (IS_AGGR_TYPE (dtype))
- {
- tree binfo;
-
- tree conversion;
-
- if (! DERIVED_FROM_P (type, dtype) && TYPE_HAS_CONVERSION (dtype))
- conversion = build_type_conversion (CONVERT_EXPR, type, e, 1);
- else
- conversion = NULL_TREE;
-
- if (TYPE_HAS_CONSTRUCTOR (type))
- {
- tree rval = build_method_call (NULL_TREE, constructor_name_full (type),
- build_tree_list (NULL_TREE, e),
- TYPE_BINFO (type),
- conversion ? LOOKUP_NO_CONVERSION : 0);
+ if (IS_AGGR_TYPE (dtype) && ! DERIVED_FROM_P (type, dtype)
+ && TYPE_HAS_CONVERSION (dtype))
+ conversion = build_type_conversion (CONVERT_EXPR, type, e, 1);
- if (rval != error_mark_node)
- {
- if (conversion)
- {
- error ("both constructor and type conversion operator apply");
- return error_mark_node;
- }
- /* call to constructor successful. */
- rval = build_cplus_new (type, rval, 1);
- return rval;
- }
- }
- /* Type conversion successful/applies. */
- if (conversion)
- {
- if (conversion == error_mark_node)
- error ("ambiguous pointer conversion");
- return conversion;
- }
+ if (conversion == error_mark_node)
+ {
+ error ("ambiguous pointer conversion");
+ return conversion;
+ }
- /* now try normal C++ assignment semantics. */
- binfo = TYPE_BINFO (dtype);
- if (BINFO_TYPE (binfo) == type
- || (binfo = get_binfo (type, dtype, 1)))
- {
- if (binfo == error_mark_node)
- return error_mark_node;
- }
- if (binfo != NULL_TREE)
- {
- if (lvalue_p (e))
- {
- e = build_unary_op (ADDR_EXPR, e, 0);
+ if (TYPE_HAS_CONSTRUCTOR (type))
+ ctor = build_method_call (NULL_TREE, constructor_name_full (type),
+ build_tree_list (NULL_TREE, e),
+ TYPE_BINFO (type),
+ LOOKUP_NORMAL | LOOKUP_SPECULATIVELY
+ | (conversion ? LOOKUP_NO_CONVERSION : 0));
- if (! BINFO_OFFSET_ZEROP (binfo))
- e = build (PLUS_EXPR, TYPE_POINTER_TO (type),
- e, BINFO_OFFSET (binfo));
- return build1 (INDIRECT_REF, type, e);
- }
+ if (ctor == error_mark_node)
+ {
+ cp_error ("in conversion to type `%T'", type);
+ return error_mark_node;
+ }
- sorry ("addressable aggregates");
- return error_mark_node;
- }
- error ("conversion between incompatible aggregate types requested");
+ if (conversion && ctor)
+ {
+ error ("both constructor and type conversion operator apply");
return error_mark_node;
}
- /* conversion from non-aggregate to aggregate type requires
- constructor. */
- else if (TYPE_HAS_CONSTRUCTOR (type))
+ else if (conversion)
+ return conversion;
+ else if (ctor)
{
- tree rval;
- tree init = build_method_call (NULL_TREE, constructor_name_full (type),
- build_tree_list (NULL_TREE, e),
- TYPE_BINFO (type), LOOKUP_NORMAL);
- if (init == error_mark_node)
+ if (current_function_decl)
+ /* We can't pass 1 to the with_cleanup_p arg here, because that
+ screws up passing classes by value. */
+ ctor = build_cplus_new (type, ctor, 0);
+ else
{
- cp_error ("in conversion to type `%T'", type);
- return error_mark_node;
+ register tree parm = TREE_OPERAND (ctor, 1);
+
+ /* Initializers for static variables and parameters
+ have to handle doing the initialization and
+ cleanup themselves. */
+ my_friendly_assert (TREE_CODE (ctor) == CALL_EXPR, 322);
+#if 0
+ /* The following assertion fails in cases where we
+ are initializing a static member variable of a
+ particular instance of a template class with a
+ call to a constructor of the given instance, as
+ in:
+
+ TMPL<int> object = TMPL<int>();
+
+ Curiously, the assertion does not fail if we do
+ the same thing for a static member of a
+ non-template class, as in:
+
+ T object = T();
+
+ I can't see why we should care here whether or not
+ the initializer expression involves a call to
+ `new', so for the time being, it seems best to
+ just avoid doing this assertion. */
+ my_friendly_assert (TREE_CALLS_NEW (TREE_VALUE (parm)),
+ 323);
+#endif
+ TREE_VALUE (parm) = NULL_TREE;
+ ctor = build_indirect_ref (ctor, NULL_PTR);
+ TREE_HAS_CONSTRUCTOR (ctor) = 1;
}
- /* We can't pass 1 to the with_cleanup_p arg here, because that
- screws up passing classes by value. */
- rval = build_cplus_new (type, init, 0);
- return rval;
+ return ctor;
}
}
@@ -2021,11 +2013,16 @@ type_promotes_to (type)
wider. */
else if (TREE_CODE (type) == ENUMERAL_TYPE
|| type == wchar_type_node)
- type = type_for_size
- (MAX (TYPE_PRECISION (type), TYPE_PRECISION (integer_type_node)),
- (flag_traditional
- || (TYPE_PRECISION (type) >= TYPE_PRECISION (integer_type_node)))
- && TREE_UNSIGNED (type));
+ {
+ int precision = MAX (TYPE_PRECISION (type),
+ TYPE_PRECISION (integer_type_node));
+ tree totype = type_for_size (precision, 0);
+ if (TREE_UNSIGNED (type)
+ && ! int_fits_type_p (TYPE_MAX_VALUE (type), totype))
+ type = type_for_size (precision, 1);
+ else
+ type = totype;
+ }
else if (C_PROMOTING_INTEGER_TYPE_P (type))
{
/* Traditionally, unsignedness is preserved in default promotions.
@@ -2040,5 +2037,5 @@ type_promotes_to (type)
else if (type == float_type_node)
type = double_type_node;
- return c_build_type_variant (type, constp, volatilep);
+ return cp_build_type_variant (type, constp, volatilep);
}
diff --git a/gnu/usr.bin/cc/cc1plus/decl.c b/gnu/usr.bin/cc/cc1plus/decl.c
index 0690340..2df750e 100644
--- a/gnu/usr.bin/cc/cc1plus/decl.c
+++ b/gnu/usr.bin/cc/cc1plus/decl.c
@@ -50,7 +50,7 @@ extern int current_class_depth;
extern tree cleanups_this_call;
/* Stack of places to restore the search obstack back to. */
-
+
/* Obstack used for remembering local class declarations (like
enums and static (const) members. */
#include "stack.h"
@@ -127,7 +127,7 @@ static tree lookup_nested_type PROTO((tree, tree));
static char *redeclaration_error_message PROTO((tree, tree));
static void grok_op_properties PROTO((tree, int, int));
-tree define_function
+tree define_function
PROTO((char *, tree, enum built_in_function, void (*)(), char *));
/* a node which has tree code ERROR_MARK, and whose type is itself.
@@ -162,6 +162,8 @@ tree wchar_type_node;
tree signed_wchar_type_node;
tree unsigned_wchar_type_node;
+tree wchar_decl_node;
+
tree float_type_node;
tree double_type_node;
tree long_double_type_node;
@@ -401,6 +403,11 @@ extern int flag_short_double;
extern int flag_no_builtin;
+/* Nonzero means don't recognize the non-ANSI builtin functions.
+ -ansi sets this. */
+
+extern int flag_no_nonansi_builtin;
+
/* Nonzero means disable GNU extensions. */
extern int flag_ansi;
@@ -477,7 +484,7 @@ push_decl_level (stack, obstack)
* Off to the side, may be the class_binding_level. This exists
* only to catch class-local declarations. It is otherwise
* nonexistent.
- *
+ *
* Also there may be binding levels that catch cleanups that
* must be run when exceptions occur.
*/
@@ -527,7 +534,7 @@ struct binding_level
/* The binding level which this one is contained in (inherits from). */
struct binding_level *level_chain;
- /* Number of decls in `names' that have incomplete
+ /* Number of decls in `names' that have incomplete
structure or union types. */
unsigned short n_incomplete;
@@ -568,7 +575,7 @@ struct binding_level
};
#define NULL_BINDING_LEVEL ((struct binding_level *) NULL)
-
+
/* The (non-class) binding level currently in effect. */
static struct binding_level *current_binding_level;
@@ -1198,7 +1205,7 @@ poplevel_class (force)
tree shadowed;
my_friendly_assert (level != 0, 354);
-
+
decl_stack = pop_stack_level (decl_stack);
for (shadowed = level->shadowed; shadowed; shadowed = TREE_CHAIN (shadowed))
IDENTIFIER_LOCAL_VALUE (TREE_PURPOSE (shadowed)) = TREE_VALUE (shadowed);
@@ -1268,7 +1275,7 @@ print_binding_level (lvl)
/* We can probably fit 3 names to a line? */
for (t = lvl->names; t; t = TREE_CHAIN (t))
{
- if (no_print_functions && (TREE_CODE(t) == FUNCTION_DECL))
+ if (no_print_functions && (TREE_CODE(t) == FUNCTION_DECL))
continue;
if (no_print_builtins
&& (TREE_CODE(t) == TYPE_DECL)
@@ -1445,7 +1452,7 @@ push_to_top_level ()
if (b == global_binding_level)
continue;
-
+
for (t = b->names; t; t = TREE_CHAIN (t))
{
tree binding, t1, t2 = t;
@@ -1459,7 +1466,7 @@ push_to_top_level ()
for (t1 = old_bindings; t1; t1 = TREE_CHAIN (t1))
if (TREE_VEC_ELT (t1, 0) == id)
goto skip_it;
-
+
binding = make_tree_vec (4);
if (id)
{
@@ -1565,7 +1572,7 @@ pop_from_top_level ()
}
/* Push a definition of struct, union or enum tag "name".
- into binding_level "b". "type" should be the type node,
+ into binding_level "b". "type" should be the type node,
We assume that the tag "name" is not already defined.
Note that the definition may really be just a forward reference.
@@ -1720,7 +1727,7 @@ pushtag (name, type, globalize)
/* Record the identifier as the type's name if it has none. */
if (TYPE_NAME (type) == NULL_TREE)
TYPE_NAME (type) = name;
-
+
/* Do C++ gratuitous typedefing. */
if (IDENTIFIER_TYPE_VALUE (name) != type
&& (TREE_CODE (type) != RECORD_TYPE
@@ -1729,7 +1736,7 @@ pushtag (name, type, globalize)
{
register tree d;
int newdecl = 0;
-
+
if (b->parm_flag != 2
|| TYPE_SIZE (current_class_type) != NULL_TREE)
{
@@ -1743,6 +1750,7 @@ pushtag (name, type, globalize)
#else
d = build_decl (TYPE_DECL, name, type);
#endif
+ SET_DECL_ARTIFICIAL (d);
#ifdef DWARF_DEBUGGING_INFO
if (write_symbols == DWARF_DEBUG)
{
@@ -1778,6 +1786,7 @@ pushtag (name, type, globalize)
/* Make nested declarations go into class-level scope. */
newdecl = 1;
d = build_decl (TYPE_DECL, name, type);
+ SET_DECL_ARTIFICIAL (d);
#ifdef DWARF_DEBUGGING_INFO
if (write_symbols == DWARF_DEBUG)
{
@@ -1978,14 +1987,14 @@ decls_match (newdecl, olddecl)
if (TREE_VEC_LENGTH (oldargs) != len)
return 0;
-
+
for (i = 0; i < len; i++)
{
- tree newarg = TREE_VEC_ELT (newargs, i);
- tree oldarg = TREE_VEC_ELT (oldargs, i);
+ tree newarg = TREE_VALUE (TREE_VEC_ELT (newargs, i));
+ tree oldarg = TREE_VALUE (TREE_VEC_ELT (oldargs, i));
if (TREE_CODE (newarg) != TREE_CODE (oldarg))
return 0;
- else if (TREE_CODE (newarg) == IDENTIFIER_NODE)
+ else if (TREE_CODE (newarg) == TYPE_DECL)
/* continue */;
else if (! comptypes (TREE_TYPE (newarg), TREE_TYPE (oldarg), 1))
return 0;
@@ -2104,6 +2113,7 @@ duplicate_decls (newdecl, olddecl)
after implicit decl. */
;
else if (TREE_CODE (olddecl) == FUNCTION_DECL
+ && DECL_ARTIFICIAL (olddecl)
&& (DECL_BUILT_IN (olddecl) || DECL_BUILT_IN_NONANSI (olddecl)))
{
/* If you declare a built-in or predefined function name as static,
@@ -2152,7 +2162,7 @@ duplicate_decls (newdecl, olddecl)
&& TREE_CODE (newdecl) == TEMPLATE_DECL
&& ! DECL_TEMPLATE_IS_CLASS (newdecl)))
return 0;
-
+
cp_error ("`%#D' redeclared as different kind of symbol", newdecl);
if (TREE_CODE (olddecl) == TREE_LIST)
olddecl = TREE_VALUE (olddecl);
@@ -2188,9 +2198,8 @@ duplicate_decls (newdecl, olddecl)
newdecl);
cp_error_at ("previous declaration `%#D' here", olddecl);
}
-
- if (compparms (TYPE_ARG_TYPES (TREE_TYPE (newdecl)),
- TYPE_ARG_TYPES (TREE_TYPE (olddecl)), 2))
+ else if (compparms (TYPE_ARG_TYPES (TREE_TYPE (newdecl)),
+ TYPE_ARG_TYPES (TREE_TYPE (olddecl)), 2))
{
cp_error ("new declaration `%#D'", newdecl);
cp_error_at ("ambiguates old declaration `%#D'", olddecl);
@@ -2199,16 +2208,21 @@ duplicate_decls (newdecl, olddecl)
return 0;
}
+ if (olddecl == wchar_decl_node)
+ {
+ if (pedantic && ! DECL_IN_SYSTEM_HEADER (newdecl))
+ cp_pedwarn ("redeclaration of wchar_t as `%T'",
+ TREE_TYPE (newdecl));
+
+ /* Throw away the redeclaration. */
+ return 1;
+ }
+
/* Already complained about this, so don't do so again. */
else if (current_class_type == NULL_TREE
|| IDENTIFIER_ERROR_LOCUS (DECL_ASSEMBLER_NAME (newdecl)) != current_class_type)
{
- /* Since we're doing this before finish_struct can set the
- line number on NEWDECL, we just do a regular error here. */
- if (DECL_SOURCE_LINE (newdecl) == 0)
- cp_error ("conflicting types for `%#D'", newdecl);
- else
- cp_error_at ("conflicting types for `%#D'", newdecl);
+ cp_error ("conflicting types for `%#D'", newdecl);
cp_error_at ("previous declaration as `%#D'", olddecl);
}
}
@@ -2521,12 +2535,15 @@ duplicate_decls (newdecl, olddecl)
DECL_TEMPLATE_MEMBERS (newdecl) = DECL_TEMPLATE_MEMBERS (olddecl);
DECL_TEMPLATE_INSTANTIATIONS (newdecl)
= DECL_TEMPLATE_INSTANTIATIONS (olddecl);
+ if (DECL_CHAIN (newdecl) == NULL_TREE)
+ DECL_CHAIN (newdecl) = DECL_CHAIN (olddecl);
}
-
+
/* Now preserve various other info from the definition. */
TREE_ADDRESSABLE (newdecl) = TREE_ADDRESSABLE (olddecl);
TREE_ASM_WRITTEN (newdecl) = TREE_ASM_WRITTEN (olddecl);
DECL_COMMON (newdecl) = DECL_COMMON (olddecl);
+ DECL_ASSEMBLER_NAME (newdecl) = DECL_ASSEMBLER_NAME (olddecl);
/* Don't really know how much of the language-specific
values we should copy from old to new. */
@@ -2678,7 +2695,8 @@ pushdecl (x)
/* don't do anything just yet */;
else if (TREE_CODE (t) != TREE_CODE (x))
{
- if (TREE_CODE (t) == TYPE_DECL || TREE_CODE (x) == TYPE_DECL)
+ if ((TREE_CODE (t) == TYPE_DECL && DECL_ARTIFICIAL (t))
+ || (TREE_CODE (x) == TYPE_DECL && DECL_ARTIFICIAL (x)))
{
/* We do nothing special here, because C++ does such nasty
things with TYPE_DECLs. Instead, just let the TYPE_DECL
@@ -2782,7 +2800,7 @@ pushdecl (x)
We get warnings about inline functions where they are defined.
We get warnings about other functions from push_overloaded_decl.
-
+
Avoid duplicate warnings where they are used. */
if (TREE_PUBLIC (x) && TREE_CODE (x) != FUNCTION_DECL)
{
@@ -3255,7 +3273,7 @@ push_overloaded_decl (decl, forgettable)
else if (is_overloaded_fn (old))
{
tree tmp;
-
+
for (tmp = get_first_fn (old); tmp; tmp = DECL_CHAIN (tmp))
if (decl == tmp || duplicate_decls (decl, tmp))
return tmp;
@@ -3381,7 +3399,7 @@ redeclaration_error_message (newdecl, olddecl)
if (TREE_CODE (TREE_TYPE (newdecl)) == METHOD_TYPE)
t1 = TREE_CHAIN (t1), t2 = TREE_CHAIN (t2);
-
+
for (; t1; t1 = TREE_CHAIN (t1), t2 = TREE_CHAIN (t2))
if (TREE_PURPOSE (t1) && TREE_PURPOSE (t2))
return "duplicate default arguments given for `%#D'";
@@ -3693,7 +3711,7 @@ lookup_tag (form, name, binding_level, thislevel_only)
&& !(form != ENUMERAL_TYPE
&& (code == TEMPLATE_DECL
|| code == UNINSTANTIATED_P_TYPE)))
-
+
{
/* Definition isn't the kind we were looking for. */
cp_error ("`%#D' redeclared as %C", TREE_VALUE (tail),
@@ -3889,10 +3907,12 @@ lookup_name_real (name, prefer_type, nonclass)
yylex = 1;
prefer_type = looking_for_typename;
-
+
if (got_scope != NULL_TREE)
{
- if (got_scope == void_type_node)
+ if (got_scope == error_mark_node)
+ return error_mark_node;
+ else if (got_scope == void_type_node)
val = IDENTIFIER_GLOBAL_VALUE (name);
else if (TREE_CODE (got_scope) == TEMPLATE_TYPE_PARM
/* TFIXME -- don't do this for UPTs in new model. */
@@ -3935,7 +3955,7 @@ lookup_name_real (name, prefer_type, nonclass)
goto done;
}
}
-
+
if (current_binding_level != global_binding_level
&& IDENTIFIER_LOCAL_VALUE (name))
val = IDENTIFIER_LOCAL_VALUE (name);
@@ -4084,7 +4104,7 @@ record_builtin_type (rid_index, name, type)
tname = get_identifier (name);
TYPE_BUILT_IN (type) = 1;
-
+
if (tname)
{
#if 0 /* not yet, should get fixed properly later */
@@ -4520,14 +4540,14 @@ init_decl_processing ()
builtin_return_address_fndecl =
builtin_function ("__builtin_return_address",
- build_function_type (ptr_type_node,
+ build_function_type (ptr_type_node,
tree_cons (NULL_TREE,
unsigned_type_node,
endlink)),
BUILT_IN_RETURN_ADDRESS, NULL_PTR);
builtin_function ("__builtin_frame_address",
- build_function_type (ptr_type_node,
+ build_function_type (ptr_type_node,
tree_cons (NULL_TREE,
unsigned_type_node,
endlink)),
@@ -4540,14 +4560,29 @@ init_decl_processing ()
sizetype,
endlink)),
BUILT_IN_ALLOCA, "alloca");
-#if 0
- builtin_function ("alloca",
- build_function_type (ptr_type_node,
- tree_cons (NULL_TREE,
- sizetype,
- endlink)),
- BUILT_IN_ALLOCA, NULL_PTR);
-#endif
+ /* Define alloca, ffs as builtins.
+ Declare _exit just to mark it as volatile. */
+ if (! flag_no_builtin && !flag_no_nonansi_builtin)
+ {
+ temp = builtin_function ("alloca",
+ build_function_type (ptr_type_node,
+ tree_cons (NULL_TREE,
+ sizetype,
+ endlink)),
+ BUILT_IN_ALLOCA, NULL_PTR);
+ /* Suppress error if redefined as a non-function. */
+ DECL_BUILT_IN_NONANSI (temp) = 1;
+ temp = builtin_function ("ffs", int_ftype_int, BUILT_IN_FFS, NULL_PTR);
+ /* Suppress error if redefined as a non-function. */
+ DECL_BUILT_IN_NONANSI (temp) = 1;
+ temp = builtin_function ("_exit", build_function_type (void_type_node,
+ int_endlink),
+ NOT_BUILT_IN, NULL_PTR);
+ TREE_THIS_VOLATILE (temp) = 1;
+ TREE_SIDE_EFFECTS (temp) = 1;
+ /* Suppress error if redefined as a non-function. */
+ DECL_BUILT_IN_NONANSI (temp) = 1;
+ }
builtin_function ("__builtin_abs", int_ftype_int,
BUILT_IN_ABS, NULL_PTR);
@@ -4559,9 +4594,9 @@ init_decl_processing ()
BUILT_IN_FFS, NULL_PTR);
builtin_function ("__builtin_fsqrt", double_ftype_double,
BUILT_IN_FSQRT, NULL_PTR);
- builtin_function ("__builtin_sin", double_ftype_double,
+ builtin_function ("__builtin_sin", double_ftype_double,
BUILT_IN_SIN, "sin");
- builtin_function ("__builtin_cos", double_ftype_double,
+ builtin_function ("__builtin_cos", double_ftype_double,
BUILT_IN_COS, "cos");
builtin_function ("__builtin_saveregs",
build_function_type (ptr_type_node, NULL_TREE),
@@ -4647,6 +4682,23 @@ init_decl_processing ()
builtin_function ("strlen", sizet_ftype_string, BUILT_IN_STRLEN, NULL_PTR);
builtin_function ("sin", double_ftype_double, BUILT_IN_SIN, NULL_PTR);
builtin_function ("cos", double_ftype_double, BUILT_IN_COS, NULL_PTR);
+
+ /* Declare these functions volatile
+ to avoid spurious "control drops through" warnings. */
+ temp = builtin_function ("abort",
+ build_function_type (void_type_node, endlink),
+ NOT_BUILT_IN, NULL_PTR);
+ TREE_THIS_VOLATILE (temp) = 1;
+ TREE_SIDE_EFFECTS (temp) = 1;
+ /* Well, these are actually ANSI, but we can't set DECL_BUILT_IN on
+ them... */
+ DECL_BUILT_IN_NONANSI (temp) = 1;
+ temp = builtin_function ("exit", build_function_type (void_type_node,
+ int_endlink),
+ NOT_BUILT_IN, NULL_PTR);
+ TREE_THIS_VOLATILE (temp) = 1;
+ TREE_SIDE_EFFECTS (temp) = 1;
+ DECL_BUILT_IN_NONANSI (temp) = 1;
}
#if 0
@@ -4708,6 +4760,11 @@ init_decl_processing ()
: signed_wchar_type_node;
record_builtin_type (RID_WCHAR, "__wchar_t", wchar_type_node);
+ /* Artificial declaration of wchar_t -- can be bashed */
+ wchar_decl_node = build_decl (TYPE_DECL, get_identifier ("wchar_t"),
+ wchar_type_node);
+ pushdecl (wchar_decl_node);
+
/* This is for wide string constants. */
wchar_array_type_node
= build_array_type (wchar_type_node, array_domain_type);
@@ -4758,7 +4815,7 @@ init_decl_processing ()
vtbl_type_node
= build_array_type (vtable_entry_type, NULL_TREE);
layout_type (vtbl_type_node);
- vtbl_type_node = c_build_type_variant (vtbl_type_node, 1, 0);
+ vtbl_type_node = cp_build_type_variant (vtbl_type_node, 1, 0);
record_builtin_type (RID_MAX, NULL_PTR, vtbl_type_node);
/* Simplify life by making a "sigtable_entry_type". Give its
@@ -4928,7 +4985,7 @@ init_decl_processing ()
NOT_BUILT_IN);
abort_fndecl
- = define_function ("abort",
+ = define_function ("__pure_virtual",
build_function_type (void_type_node, void_list_node),
NOT_BUILT_IN, 0, 0);
@@ -5010,7 +5067,6 @@ shadow_tag (declspecs)
tree declspecs;
{
int found_tag = 0;
- int warned = 0;
tree ob_modifier = NULL_TREE;
register tree link;
register enum tree_code code, ok_code = ERROR_MARK;
@@ -5023,41 +5079,14 @@ shadow_tag (declspecs)
code = TREE_CODE (value);
if (IS_AGGR_TYPE_CODE (code) || code == ENUMERAL_TYPE)
{
- register tree name = TYPE_NAME (value);
+ my_friendly_assert (TYPE_NAME (value) != NULL_TREE, 261);
if (code == ENUMERAL_TYPE && TYPE_SIZE (value) == 0)
cp_error ("forward declaration of `%#T'", value);
- if (name == NULL_TREE)
- name = lookup_tag_reverse (value, NULL_TREE);
-
- if (name && TREE_CODE (name) == TYPE_DECL)
- name = DECL_NAME (name);
-
- t = lookup_tag (code, name, inner_binding_level, 1);
-
- if (t == NULL_TREE)
- {
- push_obstacks (&permanent_obstack, &permanent_obstack);
- if (IS_AGGR_TYPE_CODE (code))
- t = make_lang_type (code);
- else
- t = make_node (code);
- pushtag (name, t, 0);
- pop_obstacks ();
- ok_code = code;
- }
- else if (name != NULL_TREE || code == ENUMERAL_TYPE)
- ok_code = code;
-
- if (ok_code != ERROR_MARK)
- found_tag++;
- else
- {
- if (!warned)
- pedwarn ("useless keyword or type name in declaration");
- warned = 1;
- }
+ t = value;
+ ok_code = code;
+ found_tag++;
}
else if (value == ridpointers[(int) RID_STATIC]
|| value == ridpointers[(int) RID_EXTERN]
@@ -5097,32 +5126,9 @@ shadow_tag (declspecs)
cp_error ("`%D' can only be specified for objects and functions",
ob_modifier);
- if (ok_code == RECORD_TYPE
- && found_tag == 1
- && TYPE_LANG_SPECIFIC (t)
- && CLASSTYPE_DECLARED_EXCEPTION (t))
- {
- if (TYPE_SIZE (t))
- cp_error ("redeclaration of exception `%T'", t);
- else
- {
- tree ename, decl;
-
- push_obstacks (&permanent_obstack, &permanent_obstack);
-
- pushclass (t, 0);
-
- ename = TYPE_NAME (t);
- if (TREE_CODE (ename) == TYPE_DECL)
- ename = DECL_NAME (ename);
- decl = build_lang_field_decl (VAR_DECL, ename, t);
-
- pop_obstacks ();
- }
- }
- else if (found_tag == 0)
+ if (found_tag == 0)
pedwarn ("abstract declarator used as declaration");
- else if (!warned && found_tag > 1)
+ else if (found_tag > 1)
pedwarn ("multiple types in one declaration");
}
}
@@ -5232,7 +5238,7 @@ start_decl (declarator, declspecs, initialized, raises)
if (TREE_CODE (TREE_TYPE (decl)) == METHOD_TYPE)
{
tree t = TREE_TYPE (decl);
-
+
t = TYPE_METHOD_BASETYPE (t); /* type method belongs to */
if (TREE_CODE (t) != UNINSTANTIATED_P_TYPE)
{
@@ -5255,8 +5261,7 @@ start_decl (declarator, declspecs, initialized, raises)
if (interface_unknown && flag_external_templates
&& ! DECL_IN_SYSTEM_HEADER (decl))
warn_if_unknown_interface ();
- TREE_PUBLIC (d) = TREE_PUBLIC (decl) =
- flag_external_templates && !interface_unknown;
+ TREE_PUBLIC (d) = TREE_PUBLIC (decl);
TREE_STATIC (d) = TREE_STATIC (decl);
DECL_EXTERNAL (d) = (DECL_EXTERNAL (decl)
&& !(context && !DECL_THIS_EXTERN (decl)));
@@ -5365,7 +5370,7 @@ start_decl (declarator, declspecs, initialized, raises)
else if (duplicate_decls (decl, field))
decl = field;
}
-
+
/* If it was not explicitly declared `extern',
revoke any previous claims of DECL_EXTERNAL. */
if (DECL_THIS_EXTERN (decl) == 0)
@@ -5378,14 +5383,14 @@ start_decl (declarator, declspecs, initialized, raises)
/* Add this decl to the current binding level, but not if it
comes from another scope, e.g. a static member variable.
TEM may equal DECL or it may be a previous decl of the same name. */
-
+
if ((TREE_CODE (decl) != PARM_DECL && DECL_CONTEXT (decl) != NULL_TREE)
|| (TREE_CODE (decl) == TEMPLATE_DECL && !global_bindings_p ())
|| TREE_CODE (type) == LANG_TYPE)
tem = decl;
else
tem = pushdecl (decl);
-
+
/* Tell the back-end to use or not use .common as appropriate. If we say
-fconserve-space, we want this to save space, at the expense of wrong
semantics. If we say -fno-conserve-space, we want this to produce
@@ -5433,7 +5438,7 @@ start_decl (declarator, declspecs, initialized, raises)
{
#if 0
tree tmpl = UPT_TEMPLATE (type);
-
+
fprintf (stderr, "%s:%d: adding ", __FILE__, __LINE__);
print_node_brief (stderr, "", DECL_NAME (tem), 0);
fprintf (stderr, " to class %s\n",
@@ -5714,6 +5719,14 @@ finish_decl (decl, init, asmspec_tree, need_pop)
type = TREE_TYPE (decl);
+ if (type == error_mark_node)
+ {
+ if (current_binding_level == global_binding_level && temporary)
+ end_temporary_allocation ();
+
+ return;
+ }
+
was_incomplete = (DECL_SIZE (decl) == NULL_TREE);
/* Take care of TYPE_DECLs up front. */
@@ -5792,7 +5805,7 @@ finish_decl (decl, init, asmspec_tree, need_pop)
{
/* This must override the asm specifier which was placed
by grokclassfn. Lay this out fresh.
-
+
@@ Should emit an error if this redefines an asm-specified
@@ name, or if we have already used the function's name. */
DECL_RTL (TREE_TYPE (decl)) = NULL_RTX;
@@ -5808,6 +5821,10 @@ finish_decl (decl, init, asmspec_tree, need_pop)
else if (TREE_CODE (type) == REFERENCE_TYPE
|| (TYPE_LANG_SPECIFIC (type) && IS_SIGNATURE_REFERENCE (type)))
{
+ if (TREE_STATIC (decl))
+ make_decl_rtl (decl, NULL_PTR,
+ current_binding_level == global_binding_level
+ || pseudo_global_level_p ());
grok_reference_init (decl, type, init, &cleanup);
init = NULL_TREE;
}
@@ -6217,7 +6234,7 @@ finish_decl (decl, init, asmspec_tree, need_pop)
while (parmtypes && parmtypes != void_list_node)
{
/* The default value for the parameter in parmtypes is
- stored in the TREE_PURPOSE of the TREE_LIST. */
+ stored in the TREE_PURPOSE of the TREE_LIST. */
if (TREE_PURPOSE (parmtypes))
{
tree fnname, fndecl;
@@ -6315,9 +6332,11 @@ finish_decl (decl, init, asmspec_tree, need_pop)
expand_aggr_init (decl, init, 0);
}
- /* Set this to 0 so we can tell whether an aggregate
- which was initialized was ever used. */
- if (TYPE_NEEDS_CONSTRUCTING (type))
+ /* Set this to 0 so we can tell whether an aggregate which
+ was initialized was ever used. Don't do this if it has a
+ destructor, so we don't complain about the 'resource
+ allocation is initialization' idiom. */
+ if (TYPE_NEEDS_CONSTRUCTING (type) && cleanup == NULL_TREE)
TREE_USED (decl) = 0;
/* Store the cleanup, if there was one. */
@@ -6792,6 +6811,7 @@ grokvardecl (type, declarator, specbits, initialized)
decl = build_lang_field_decl (VAR_DECL, declarator, type);
DECL_CONTEXT (decl) = basetype;
DECL_CLASS_CONTEXT (decl) = basetype;
+ DECL_ASSEMBLER_NAME (decl) = build_static_name (basetype, declarator);
}
else
decl = build_decl (VAR_DECL, declarator, type);
@@ -6857,6 +6877,8 @@ build_ptrmemfunc_type (type)
/* Let the front-end know this is a pointer to member function. */
TYPE_PTRMEMFUNC_FLAG(t) = 1;
+ /* and not really an aggregate. */
+ IS_AGGR_TYPE (t) = 0;
fields[0] = build_lang_field_decl (FIELD_DECL, delta_identifier,
delta_type_node);
@@ -7091,7 +7113,11 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, raises)
dname = decl;
decl = NULL_TREE;
- if (IDENTIFIER_OPNAME_P (dname))
+ if (! IDENTIFIER_OPNAME_P (dname)
+ /* Linux headers use '__op'. Arrgh. */
+ || IDENTIFIER_TYPENAME_P (dname) && ! TREE_TYPE (dname))
+ name = IDENTIFIER_POINTER (dname);
+ else
{
if (IDENTIFIER_TYPENAME_P (dname))
{
@@ -7102,8 +7128,6 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, raises)
}
name = operator_name_string (dname);
}
- else
- name = IDENTIFIER_POINTER (dname);
break;
case RECORD_TYPE:
@@ -7281,7 +7305,7 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, raises)
goto found;
}
- for (i = (int) RID_FIRST_MODIFIER; i < (int) RID_MAX; i++)
+ for (i = (int) RID_FIRST_MODIFIER; i <= (int) RID_LAST_MODIFIER; i++)
{
if (ridpointers[i] == id)
{
@@ -7521,10 +7545,13 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, raises)
volatilep = !! RIDBIT_SETP (RID_VOLATILE, specbits) + TYPE_VOLATILE (type);
staticp = 0;
inlinep = !! RIDBIT_SETP (RID_INLINE, specbits);
+#if 0
+ /* This sort of redundancy is blessed in a footnote to the Sep 94 WP. */
if (constp > 1)
warning ("duplicate `const'");
if (volatilep > 1)
warning ("duplicate `volatile'");
+#endif
virtualp = RIDBIT_SETP (RID_VIRTUAL, specbits);
if (RIDBIT_SETP (RID_STATIC, specbits))
@@ -7667,10 +7694,10 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, raises)
register tree scanner;
register tree previous_declspec;
tree loc_typedecl;
-
+
if (initialized)
error ("typedef declaration includes an initializer");
-
+
/* To process a class-local typedef declaration, we descend down
the chain of declspecs looking for the `typedef' spec. When
we find it, we replace it with `static', and then recursively
@@ -7688,39 +7715,41 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, raises)
break;
}
- if (scanner == IDENTIFIER_AS_LIST (ridpointers [(int) RID_TYPEDEF]))
- {
- if (previous_declspec)
- TREE_CHAIN (previous_declspec)
- = IDENTIFIER_AS_LIST (ridpointers [(int) RID_STATIC]);
- else
- declspecs
- = IDENTIFIER_AS_LIST (ridpointers [(int) RID_STATIC]);
- }
+ if (previous_declspec)
+ TREE_CHAIN (previous_declspec) = TREE_CHAIN (scanner);
else
- TREE_VALUE (scanner) = ridpointers[(int) RID_STATIC];
+ declspecs = TREE_CHAIN (scanner);
+
+ declspecs = tree_cons (NULL_TREE, ridpointers[(int) RID_STATIC],
+ declspecs);
/* In the recursive call to grokdeclarator we need to know
whether we are working on a signature-local typedef. */
if (IS_SIGNATURE (current_class_type))
SIGNATURE_GROKKING_TYPEDEF (current_class_type) = 1;
-
+
loc_typedecl =
grokdeclarator (declarator, declspecs, FIELD, 0, NULL_TREE);
-
+
+ if (previous_declspec)
+ TREE_CHAIN (previous_declspec) = scanner;
+
if (loc_typedecl != error_mark_node)
{
register int i = sizeof (struct lang_decl_flags) / sizeof (int);
register int *pi;
-
+
TREE_SET_CODE (loc_typedecl, TYPE_DECL);
-
+ /* This is the same field as DECL_ARGUMENTS, which is set for
+ function typedefs by the above grokdeclarator. */
+ DECL_NESTED_TYPENAME (loc_typedecl) = 0;
+
pi = (int *) permalloc (sizeof (struct lang_decl_flags));
while (i > 0)
pi[--i] = 0;
DECL_LANG_SPECIFIC (loc_typedecl) = (struct lang_decl *) pi;
}
-
+
if (IS_SIGNATURE (current_class_type))
{
SIGNATURE_GROKKING_TYPEDEF (current_class_type) = 0;
@@ -7983,7 +8012,7 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, raises)
type = build_cplus_array_type (type, itype);
if (constp || volatilep)
- type = c_build_type_variant (type, constp, volatilep);
+ type = cp_build_type_variant (type, constp, volatilep);
ctype = NULL_TREE;
}
@@ -7992,6 +8021,9 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, raises)
case CALL_EXPR:
{
tree arg_types;
+ int funcdecl_p;
+ tree inner_parms = TREE_OPERAND (declarator, 1);
+ tree inner_decl = TREE_OPERAND (declarator, 0);
/* Declaring a function type.
Make sure we have a valid type for the function to return. */
@@ -8005,7 +8037,7 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, raises)
if (constp || volatilep)
{
- type = c_build_type_variant (type, constp, volatilep);
+ type = cp_build_type_variant (type, constp, volatilep);
if (IS_AGGR_TYPE (type))
build_pointer_type (type);
constp = 0;
@@ -8026,8 +8058,17 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, raises)
type = integer_type_node;
}
+ if (inner_decl && TREE_CODE (inner_decl) == SCOPE_REF)
+ inner_decl = TREE_OPERAND (inner_decl, 1);
+
+ /* Say it's a definition only for the CALL_EXPR
+ closest to the identifier. */
+ funcdecl_p =
+ inner_decl && TREE_CODE (inner_decl) == IDENTIFIER_NODE;
+
if (ctype == NULL_TREE
&& decl_context == FIELD
+ && funcdecl_p
&& (friendp == 0 || dname == current_class_name))
ctype = current_class_type;
@@ -8100,7 +8141,7 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, raises)
{
error ("constructor not allowed in signature");
return void_type_node;
- }
+ }
else if (decl_context == FIELD)
{
if (! member_function_or_else (ctype, current_class_type,
@@ -8141,27 +8182,12 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, raises)
/* Construct the function type and go to the next
inner layer of declarator. */
- {
- int funcdef_p;
- tree inner_parms = TREE_OPERAND (declarator, 1);
- tree inner_decl = TREE_OPERAND (declarator, 0);
-
- declarator = TREE_OPERAND (declarator, 0);
-
- if (inner_decl && TREE_CODE (inner_decl) == SCOPE_REF)
- inner_decl = TREE_OPERAND (inner_decl, 1);
-
- /* Say it's a definition only for the CALL_EXPR
- closest to the identifier. */
- funcdef_p =
- (inner_decl && TREE_CODE (inner_decl) == IDENTIFIER_NODE)
- ? funcdef_flag : 0;
+ declarator = TREE_OPERAND (declarator, 0);
- /* FIXME: This is where default args should be fully
- processed. */
+ /* FIXME: This is where default args should be fully
+ processed. */
- arg_types = grokparms (inner_parms, funcdef_p);
- }
+ arg_types = grokparms (inner_parms, funcdecl_p ? funcdef_flag : 0);
if (declarator)
{
@@ -8216,7 +8242,7 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, raises)
signature pointer/reference itself. */
if (! IS_SIGNATURE (type))
{
- type = c_build_type_variant (type, constp, volatilep);
+ type = cp_build_type_variant (type, constp, volatilep);
if (IS_AGGR_TYPE (type))
build_pointer_type (type);
constp = 0;
@@ -8511,7 +8537,7 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, raises)
/* Note that the grammar rejects storage classes
in typenames, fields or parameters. */
if (constp || volatilep)
- type = c_build_type_variant (type, constp, volatilep);
+ type = cp_build_type_variant (type, constp, volatilep);
/* If the user declares "struct {...} foo" then `foo' will have
an anonymous name. Fill that name in now. Nothing can
@@ -8599,8 +8625,8 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, raises)
if (constp || volatilep)
if (IS_SIGNATURE (type))
error ("`const' or `volatile' specified with signature type");
- else
- type = c_build_type_variant (type, constp, volatilep);
+ else
+ type = cp_build_type_variant (type, constp, volatilep);
/* Special case: "friend class foo" looks like a TYPENAME context. */
if (friendp)
@@ -8682,7 +8708,7 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, raises)
{
/* Transfer const-ness of array into that of type pointed to. */
type = build_pointer_type
- (c_build_type_variant (TREE_TYPE (type), constp, volatilep));
+ (cp_build_type_variant (TREE_TYPE (type), constp, volatilep));
volatilep = constp = 0;
}
else if (TREE_CODE (type) == FUNCTION_TYPE)
@@ -8815,7 +8841,7 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, raises)
&& TREE_TYPE (TREE_VALUE (declspecs)) == type)
error (" in instantiation of template `%s'",
TYPE_NAME_STRING (current_class_type));
-
+
type = error_mark_node;
decl = NULL_TREE;
}
@@ -8843,7 +8869,7 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, raises)
last_function_parms, flags, quals);
if (t && funcdef_flag)
return t;
-
+
return void_type_node;
}
}
@@ -8937,7 +8963,7 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, raises)
else
pedwarn ("storage class `inline' invalid for function `%s' declared out of global scope", name);
}
-
+
if (ctype == NULL_TREE)
{
if (virtualp)
@@ -8961,14 +8987,10 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, raises)
type = build_cplus_method_type (build_type_variant (ctype, constp, volatilep),
TREE_TYPE (type), TYPE_ARG_TYPES (type));
- /* Record presence of `static'. In C++, `inline' is like `static'.
- Methods of classes should be public, unless we're dropping them
- into some other file, so we don't clear TREE_PUBLIC for them. */
+ /* Record presence of `static'. In C++, `inline' is like `static'. */
publicp
- = ((ctype
- && CLASSTYPE_INTERFACE_KNOWN (ctype))
- || !(RIDBIT_SETP (RID_STATIC, specbits)
- || RIDBIT_SETP (RID_INLINE, specbits)));
+ = !(RIDBIT_SETP (RID_STATIC, specbits)
+ || RIDBIT_SETP (RID_INLINE, specbits));
decl = grokfndecl (ctype, type, original_name,
virtualp, flags, quals,
@@ -8989,7 +9011,7 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, raises)
declaring main to be static. */
if (TREE_CODE (type) == METHOD_TYPE)
{
- cp_error_at ("cannot declare member function `%D' to have static linkage", decl);
+ cp_pedwarn ("cannot declare member function `%D' to have static linkage", decl);
illegal_static = 1;
}
else if (! ctype
@@ -9536,7 +9558,7 @@ grok_op_properties (decl, virtualp, friendp)
doesn't look at the class declaration to find out if it's static. */
if (methodp)
revert_static_member_fn (&decl, NULL, NULL);
-
+
/* Take care of function decl if we had syntax errors. */
if (argtypes == NULL_TREE)
TREE_TYPE (decl) =
@@ -9551,7 +9573,7 @@ grok_op_properties (decl, virtualp, friendp)
{
if (methodp)
revert_static_member_fn (&decl, NULL, NULL);
-
+
if (argtypes == NULL_TREE)
TREE_TYPE (decl) =
build_function_type (void_type_node,
@@ -9607,7 +9629,7 @@ grok_op_properties (decl, virtualp, friendp)
;
}
}
-
+
if (name == ansi_opname[(int) CALL_EXPR]
|| name == ansi_opname[(int) METHOD_CALL_EXPR])
return; /* no restrictions on args */
@@ -9666,7 +9688,7 @@ grok_op_properties (decl, virtualp, friendp)
pedwarn ("ANSI C++ prohibits overloading operator ?:");
if (list_length (argtypes) != 4)
cp_error ("`%D' must take exactly three arguments", decl);
- }
+ }
else if (ambi_op_p (name))
{
if (list_length (argtypes) == 2)
@@ -9772,10 +9794,10 @@ xref_defn_tag (code_type_node, name, binfo)
n1 = DECL_NESTED_TYPENAME(n1);
else
n1 = current_class_name;
-
+
buf = (char *) alloca (4 + IDENTIFIER_LENGTH (n1)
+ IDENTIFIER_LENGTH (name));
-
+
sprintf (buf, "%s::%s", IDENTIFIER_POINTER (n1),
IDENTIFIER_POINTER (name));
ncp = get_identifier (buf);
@@ -9791,6 +9813,7 @@ xref_defn_tag (code_type_node, name, binfo)
if (! ANON_AGGRNAME_P (name))
{
register tree type_decl = build_decl (TYPE_DECL, ncp, rv);
+ SET_DECL_ARTIFICIAL (type_decl);
#ifdef DWARF_DEBUGGING_INFO
/* Mark the TYPE_DECL node created just above as a gratuitous one
so that dwarfout.c will know not to generate a TAG_typedef DIE
@@ -9939,48 +9962,21 @@ xref_tag (code_type_node, name, binfo, globalize)
}
else
{
- extern tree pending_vtables;
struct binding_level *old_b = class_binding_level;
- int needs_writing;
ref = make_lang_type (code);
- /* A signature type will contain the fields of the signature
- table. Therefore, it's not only an interface. */
if (tag_code == signature_type)
{
SET_SIGNATURE (ref);
+ /* Since a signature type will be turned into the type
+ of signature tables, it's not only an interface. */
CLASSTYPE_INTERFACE_ONLY (ref) = 0;
- CLASSTYPE_INTERFACE_UNKNOWN (ref) = 0;
+ SET_CLASSTYPE_INTERFACE_KNOWN (ref);
+ /* A signature doesn't have a vtable. */
+ CLASSTYPE_VTABLE_NEEDS_WRITING (ref) = 0;
}
- /* Record how to set the access of this class's
- virtual functions. If write_virtuals == 2 or 3, then
- inline virtuals are ``extern inline''. */
- switch (write_virtuals)
- {
- case 0:
- case 1:
- needs_writing = 1;
- break;
- case 2:
- needs_writing = !! value_member (name, pending_vtables);
- break;
- case 3:
- needs_writing = ! CLASSTYPE_INTERFACE_ONLY (ref)
- && CLASSTYPE_INTERFACE_KNOWN (ref);
- break;
- default:
- needs_writing = 0;
- }
-
- /* Signatures don't have a vtable. As long as we don't have default
- implementations, they behave as if `write_virtuals' were 3. */
- if (tag_code == signature_type)
- CLASSTYPE_VTABLE_NEEDS_WRITING (ref) = 0;
- else
- CLASSTYPE_VTABLE_NEEDS_WRITING (ref) = needs_writing;
-
#ifdef NONNESTED_CLASSES
/* Class types don't nest the way enums do. */
class_binding_level = (struct binding_level *)0;
@@ -10099,15 +10095,16 @@ xref_tag (code_type_node, name, binfo, globalize)
derived classes. (Each BINFO record describing an
individual inheritance contains flags which say what
the `accessibility' of that particular inheritance is.) */
-
+
base_binfo = make_binfo (integer_zero_node, basetype,
TYPE_BINFO_VTABLE (basetype),
TYPE_BINFO_VIRTUALS (basetype), NULL_TREE);
-
+
TREE_VEC_ELT (binfos, i) = base_binfo;
TREE_VIA_PUBLIC (base_binfo) = via_public;
TREE_VIA_PROTECTED (base_binfo) = via_protected;
TREE_VIA_VIRTUAL (base_binfo) = via_virtual;
+ BINFO_INHERITANCE_CHAIN (base_binfo) = TYPE_BINFO (ref);
SET_CLASSTYPE_MARKED (basetype);
#if 0
@@ -10209,6 +10206,7 @@ start_enum (name)
TREE_ADDRESSABLE (b->tags) = 1;
current_local_enum = NULL_TREE;
+#if 0 /* This stuff gets cleared in finish_enum anyway. */
if (TYPE_VALUES (enumtype) != NULL_TREE)
/* Completely replace its old definition.
The old enumerators remain defined, however. */
@@ -10221,7 +10219,8 @@ start_enum (name)
TYPE_PRECISION (enumtype) = TYPE_PRECISION (integer_type_node);
TYPE_SIZE (enumtype) = NULL_TREE;
- fixup_unsigned_type (enumtype);
+ fixup_signed_type (enumtype);
+#endif
/* We copy this value because enumerated type constants
are really of the type of the enumerator, not integer_type_node. */
@@ -10241,84 +10240,89 @@ tree
finish_enum (enumtype, values)
register tree enumtype, values;
{
- register tree pair, tem;
- register HOST_WIDE_INT maxvalue = 0;
- register HOST_WIDE_INT minvalue = 0;
- register HOST_WIDE_INT i;
-
+ register tree minnode, maxnode;
/* Calculate the maximum value of any enumerator in this type. */
if (values)
{
- /* Speed up the main loop by performing some precalculations */
+ register tree pair;
+ register tree value = DECL_INITIAL (TREE_VALUE (values));
- HOST_WIDE_INT value;
+ /* Speed up the main loop by performing some precalculations */
TREE_TYPE (TREE_VALUE (values)) = enumtype;
- TREE_TYPE (DECL_INITIAL (TREE_VALUE (values))) = enumtype;
- TREE_VALUE (values) = DECL_INITIAL (TREE_VALUE (values));
- value = TREE_INT_CST_LOW (TREE_VALUE (values));
- minvalue = maxvalue = value;
-
+ TREE_TYPE (value) = enumtype;
+ TREE_VALUE (values) = value;
+ minnode = maxnode = value;
+
for (pair = TREE_CHAIN (values); pair; pair = TREE_CHAIN (pair))
{
+ value = DECL_INITIAL (TREE_VALUE (pair));
TREE_TYPE (TREE_VALUE (pair)) = enumtype;
- TREE_TYPE (DECL_INITIAL (TREE_VALUE (pair))) = enumtype;
- TREE_VALUE (pair) = DECL_INITIAL (TREE_VALUE (pair));
- value = TREE_INT_CST_LOW (TREE_VALUE (pair));
- if (value > maxvalue)
- maxvalue = value;
- else if (value < minvalue)
- minvalue = value;
+ TREE_TYPE (value) = enumtype;
+ TREE_VALUE (pair) = value;
+ if (tree_int_cst_lt (maxnode, value))
+ maxnode = value;
+ else if (tree_int_cst_lt (value, minnode))
+ minnode = value;
}
}
+ else
+ maxnode = minnode = integer_zero_node;
TYPE_VALUES (enumtype) = values;
- if (flag_short_enums)
- {
- /* Determine the precision this type needs, lay it out, and define
- it. */
-
- /* First reset precision */
- TYPE_PRECISION (enumtype) = 0;
-
- for (i = maxvalue; i; i >>= 1)
- TYPE_PRECISION (enumtype)++;
-
- if (!TYPE_PRECISION (enumtype))
- TYPE_PRECISION (enumtype) = 1;
-
- /* Cancel the laying out previously done for the enum type,
- so that fixup_unsigned_type will do it over. */
- TYPE_SIZE (enumtype) = NULL_TREE;
+ {
+ int unsignedp = tree_int_cst_sgn (minnode) >= 0;
+ int lowprec = min_precision (minnode, unsignedp);
+ int highprec = min_precision (maxnode, unsignedp);
+ int precision = MAX (lowprec, highprec);
+
+ if (! flag_short_enums && precision < TYPE_PRECISION (integer_type_node))
+ precision = TYPE_PRECISION (integer_type_node);
+
+
+ /*
+ * The following code is unnecessary since the function
+ * type_promotes_to deals correctly with promotion of enums of
+ * underlying unsigned types to signed integer types.
+ * Moreover, it causes an enum bitfield to require one more bit of
+ * storage than defined by the ANSI/ISO C++ resolution section r.7.2
+ * which defines the range of an enum.
+ */
+#if 0
+ /* Unlike the C frontend, we prefer signed types. */
+ if (unsignedp && int_fits_type_p (maxnode, type_for_size (precision, 0)))
+ unsignedp = 0;
+#endif
+ TYPE_PRECISION (enumtype) = precision;
+ TYPE_SIZE (enumtype) = NULL_TREE;
+ if (unsignedp)
fixup_unsigned_type (enumtype);
- }
-
- TREE_INT_CST_LOW (TYPE_MAX_VALUE (enumtype)) = maxvalue;
+ else
+ fixup_signed_type (enumtype);
+ }
- /* An enum can have some negative values; then it is signed. */
- if (minvalue < 0)
- {
- TREE_INT_CST_LOW (TYPE_MIN_VALUE (enumtype)) = minvalue;
- TREE_INT_CST_HIGH (TYPE_MIN_VALUE (enumtype)) = -1;
- TREE_UNSIGNED (enumtype) = 0;
- }
if (flag_cadillac)
cadillac_finish_enum (enumtype);
- /* Fix up all variant types of this enum type. */
- for (tem = TYPE_MAIN_VARIANT (enumtype); tem; tem = TYPE_NEXT_VARIANT (tem))
- {
- TYPE_VALUES (tem) = TYPE_VALUES (enumtype);
- TYPE_MIN_VALUE (tem) = TYPE_MIN_VALUE (enumtype);
- TYPE_MAX_VALUE (tem) = TYPE_MAX_VALUE (enumtype);
- TYPE_SIZE (tem) = TYPE_SIZE (enumtype);
- TYPE_MODE (tem) = TYPE_MODE (enumtype);
- TYPE_PRECISION (tem) = TYPE_PRECISION (enumtype);
- TYPE_ALIGN (tem) = TYPE_ALIGN (enumtype);
- TREE_UNSIGNED (tem) = TREE_UNSIGNED (enumtype);
- }
+ {
+ register tree tem;
+
+ /* Fix up all variant types of this enum type. */
+ for (tem = TYPE_MAIN_VARIANT (enumtype); tem;
+ tem = TYPE_NEXT_VARIANT (tem))
+ {
+ TYPE_VALUES (tem) = TYPE_VALUES (enumtype);
+ TYPE_MIN_VALUE (tem) = TYPE_MIN_VALUE (enumtype);
+ TYPE_MAX_VALUE (tem) = TYPE_MAX_VALUE (enumtype);
+ TYPE_SIZE (tem) = TYPE_SIZE (enumtype);
+ TYPE_MODE (tem) = TYPE_MODE (enumtype);
+ TYPE_PRECISION (tem) = TYPE_PRECISION (enumtype);
+ TYPE_ALIGN (tem) = TYPE_ALIGN (enumtype);
+ TREE_UNSIGNED (tem) = TREE_UNSIGNED (enumtype);
+ }
+ }
/* Finish debugging output for this type. */
#if 0
@@ -10426,7 +10430,7 @@ build_enumerator (name, value)
enum_next_value = build_binary_op_nodefault (PLUS_EXPR, value,
integer_one_node, PLUS_EXPR);
enum_overflow = tree_int_cst_lt (enum_next_value, value);
-
+
if (enum_next_value == integer_one_node)
enum_next_value = copy_node (enum_next_value);
@@ -10439,10 +10443,10 @@ grok_enum_decls (type, decl)
tree type, decl;
{
tree d = current_local_enum;
-
+
if (d == NULL_TREE)
return decl;
-
+
while (1)
{
TREE_TYPE (d) = type;
@@ -10456,7 +10460,7 @@ grok_enum_decls (type, decl)
decl = current_local_enum;
current_local_enum = NULL_TREE;
-
+
return decl;
}
@@ -10678,15 +10682,14 @@ start_function (declspecs, declarator, raises, pre_parsed_p)
/* If this function belongs to an interface, it is public.
If it belongs to someone else's interface, it is also external.
It doesn't matter whether it's inline or not. */
- if (interface_unknown == 0)
+ if (interface_unknown == 0
+ && ! TREE_PUBLIC (decl1))
{
TREE_PUBLIC (decl1) = 1;
DECL_EXTERNAL (decl1)
= (interface_only
|| (DECL_INLINE (decl1) && ! flag_implement_inlines));
}
- else if (DECL_EXPLICIT_INSTANTIATION (decl1))
- /* PUBLIC and EXTERNAL set by do_*_instantiation */;
else
{
/* This is a definition, not a reference.
@@ -10695,7 +10698,10 @@ start_function (declspecs, declarator, raises, pre_parsed_p)
defining how to inline. So set DECL_EXTERNAL in that case. */
DECL_EXTERNAL (decl1) = current_extern_inline;
- DECL_DEFER_OUTPUT (decl1) = DECL_INLINE (decl1);
+ DECL_DEFER_OUTPUT (decl1)
+ = DECL_INLINE (decl1) && ! TREE_PUBLIC (decl1)
+ && (DECL_FUNCTION_MEMBER_P (decl1)
+ || DECL_TEMPLATE_INSTANTIATION (decl1));
}
if (ctype != NULL_TREE && DECL_STATIC_FUNCTION_P (decl1))
@@ -10882,7 +10888,7 @@ store_parm_decls ()
A parameter is assumed not to have any side effects.
If this should change for any reason, then this
will have to wrap the bashed reference type in a save_expr.
-
+
Also, if the parameter type is declared to be an X
and there is an X(X&) constructor, we cannot lay it
into the stack (any more), so we make this parameter
@@ -11023,59 +11029,6 @@ store_return_init (return_id, init)
}
}
-#if 0
-/* Generate code for default X() constructor. */
-static void
-build_default_constructor (fndecl)
- tree fndecl;
-{
- int i = CLASSTYPE_N_BASECLASSES (current_class_type);
- tree parm = TREE_CHAIN (DECL_ARGUMENTS (fndecl));
- tree fields = TYPE_FIELDS (current_class_type);
- tree binfos = TYPE_BINFO_BASETYPES (current_class_type);
-
- if (TYPE_USES_VIRTUAL_BASECLASSES (current_class_type))
- parm = TREE_CHAIN (parm);
- parm = DECL_REFERENCE_SLOT (parm);
-
- while (--i >= 0)
- {
- tree basetype = TREE_VEC_ELT (binfos, i);
- if (TYPE_HAS_INIT_REF (basetype))
- {
- tree name = TYPE_NAME (basetype);
- if (TREE_CODE (name) == TYPE_DECL)
- name = DECL_NAME (name);
- current_base_init_list = tree_cons (name, parm, current_base_init_list);
- }
- }
- for (; fields; fields = TREE_CHAIN (fields))
- {
- tree name, init;
- if (TREE_STATIC (fields))
- continue;
- if (TREE_CODE (fields) != FIELD_DECL)
- continue;
- if (DECL_NAME (fields))
- {
- if (VFIELD_NAME_P (DECL_NAME (fields)))
- continue;
- if (VBASE_NAME_P (DECL_NAME (fields)))
- continue;
-
- /* True for duplicate members. */
- if (IDENTIFIER_CLASS_VALUE (DECL_NAME (fields)) != fields)
- continue;
- }
-
- init = build (COMPONENT_REF, TREE_TYPE (fields), parm, fields);
- init = build_tree_list (NULL_TREE, init);
-
- current_member_init_list
- = tree_cons (DECL_NAME (fields), init, current_member_init_list);
- }
-}
-#endif
/* Finish up a function declaration and compile that function
all the way to assembler language output. The free the storage
@@ -11119,7 +11072,7 @@ finish_function (lineno, call_poplevel)
store_parm_decls ();
}
- if (write_symbols != NO_DEBUG && TREE_CODE (fntype) != METHOD_TYPE)
+ if (write_symbols != NO_DEBUG /*&& TREE_CODE (fntype) != METHOD_TYPE*/)
{
tree ttype = target_type (fntype);
tree parmdecl;
@@ -11529,20 +11482,19 @@ finish_function (lineno, call_poplevel)
/* So we can tell if jump_optimize sets it to 1. */
can_reach_end = 0;
- /* ??? Compensate for Sun brain damage in dealing with data segments
- of PIC code. */
- if (flag_pic
- && (DECL_CONSTRUCTOR_P (fndecl)
- || DESTRUCTOR_NAME_P (DECL_ASSEMBLER_NAME (fndecl)))
- && CLASSTYPE_NEEDS_VIRTUAL_REINIT (TYPE_METHOD_BASETYPE (fntype)))
- DECL_INLINE (fndecl) = 0;
-
if (DECL_EXTERNAL (fndecl)
/* This function is just along for the ride. If we can make
it inline, that's great. Otherwise, just punt it. */
&& (DECL_INLINE (fndecl) == 0
|| flag_no_inline
- || function_cannot_inline_p (fndecl)))
+ || function_cannot_inline_p (fndecl)
+ /* ??? Compensate for Sun brain damage in dealing with
+ data segments of PIC code. */
+ || (flag_pic
+ && (DECL_CONSTRUCTOR_P (fndecl)
+ || DESTRUCTOR_NAME_P (DECL_ASSEMBLER_NAME (fndecl)))
+ && CLASSTYPE_NEEDS_VIRTUAL_REINIT (TYPE_METHOD_BASETYPE (fntype)))))
+
{
extern int rtl_dump_and_exit;
int old_rtl_dump_and_exit = rtl_dump_and_exit;
@@ -11564,8 +11516,8 @@ finish_function (lineno, call_poplevel)
rest_of_compilation (fndecl);
}
- if (DECL_INLINE (fndecl)
- && !TREE_ASM_WRITTEN (fndecl) && DECL_FUNCTION_MEMBER_P (fndecl))
+ if (DECL_INLINE (fndecl) && !TREE_ASM_WRITTEN (fndecl)
+ && DECL_DEFER_OUTPUT (fndecl))
{
mark_inline_for_output (fndecl);
}
@@ -11723,7 +11675,7 @@ start_method (declspecs, declarator, raises)
/* Make a place for the parms */
pushlevel (0);
current_binding_level->parm_flag = 1;
-
+
DECL_IN_AGGR_P (fndecl) = 1;
return fndecl;
}
@@ -11974,7 +11926,7 @@ finish_stmt ()
{
extern struct nesting *cond_stack, *loop_stack, *case_stack;
-
+
if (current_function_assigns_this
|| ! current_function_just_assigned_this)
return;
diff --git a/gnu/usr.bin/cc/cc1plus/decl2.c b/gnu/usr.bin/cc/cc1plus/decl2.c
index 2b9f8a7..0feef74 100644
--- a/gnu/usr.bin/cc/cc1plus/decl2.c
+++ b/gnu/usr.bin/cc/cc1plus/decl2.c
@@ -84,6 +84,11 @@ int flag_no_asm;
int flag_no_builtin;
+/* Nonzero means don't recognize the non-ANSI builtin functions.
+ -ansi sets this. */
+
+int flag_no_nonansi_builtin;
+
/* Nonzero means do some things the same way PCC does. */
int flag_traditional;
@@ -207,6 +212,12 @@ int warn_nonvdtor;
/* Non-zero means warn when a function is declared extern and later inline. */
int warn_extern_inline;
+/* Non-zero means warn when the compiler will reorder code. */
+int warn_reorder;
+
+/* Non-zero means warn when sysnthesis behavior differs from Cfront's. */
+int warn_synth;
+
/* Nonzero means `$' can be in an identifier.
See cccp.c for reasons why this breaks some obscure ANSI C programs. */
@@ -229,7 +240,7 @@ int flag_labels_ok;
and to print them when we are done. */
int flag_detailed_statistics;
-/* C++ specific flags. */
+/* C++ specific flags. */
/* Nonzero for -fall-virtual: make every member function (except
constructors) lay down in the virtual function table. Calls
can then either go through the virtual function table or not,
@@ -320,6 +331,9 @@ int flag_huge_objects;
definitions. */
int flag_conserve_space;
+/* Nonzero if we want to obey access control semantics. */
+int flag_access_control = 1;
+
/* Table of language-dependent -f options.
STRING is the option name. VARIABLE is the address of the variable.
ON_VALUE is the value to store in VARIABLE
@@ -361,13 +375,15 @@ static struct { char *string; int *variable; int on_value;} lang_f_options[] =
{"conserve-space", &flag_conserve_space, 1},
{"vtable-thunks", &flag_vtable_thunks, 1},
{"short-temps", &flag_short_temps, 1},
+ {"access-control", &flag_access_control, 1},
+ {"nonansi-builtins", &flag_no_nonansi_builtin, 0}
};
/* Decode the string P as a language-specific option.
Return 1 if it is recognized (and handle it);
return 0 if not recognized. */
-int
+int
lang_decode_option (p)
char *p;
{
@@ -447,6 +463,10 @@ lang_decode_option (p)
flag_alt_external_templates = 0;
found = 1;
}
+ else if (!strcmp (p, "ansi-overloading"))
+ {
+ warning ("-fansi-overloading is no longer meaningful");
+ }
else for (j = 0;
!found && j < sizeof (lang_f_options) / sizeof (lang_f_options[0]);
j++)
@@ -511,6 +531,10 @@ lang_decode_option (p)
warn_nonvdtor = setting;
else if (!strcmp (p, "extern-inline"))
warn_extern_inline = setting;
+ else if (!strcmp (p, "reorder"))
+ warn_reorder = setting;
+ else if (!strcmp (p, "synth"))
+ warn_synth = setting;
else if (!strcmp (p, "comment"))
; /* cpp handles this one. */
else if (!strcmp (p, "comments"))
@@ -537,6 +561,7 @@ lang_decode_option (p)
if (warn_uninitialized != 1)
warn_uninitialized = (setting ? 2 : 0);
warn_template_debugging = setting;
+ warn_reorder = setting;
}
else if (!strcmp (p, "overloaded-virtual"))
@@ -544,7 +569,8 @@ lang_decode_option (p)
else return 0;
}
else if (!strcmp (p, "-ansi"))
- flag_no_asm = 1, dollars_in_ident = 0, flag_ansi = 1;
+ flag_no_asm = 1, dollars_in_ident = 0, flag_no_nonansi_builtin = 1,
+ flag_ansi = 1;
#ifdef SPEW_DEBUG
/* Undocumented, only ever used when you're invoking cc1plus by hand, since
it's probably safe to assume no sane person would ever want to use this
@@ -683,7 +709,7 @@ grok_x_components (specs, components)
tcode = signature_type_node;
else if (CLASSTYPE_DECLARED_EXCEPTION(t))
tcode = exception_type_node;
-
+
t = xref_defn_tag(tcode, TYPE_IDENTIFIER(t), NULL_TREE);
if (TYPE_CONTEXT(t))
CLASSTYPE_NO_GLOBALIZE(t) = 1;
@@ -983,7 +1009,7 @@ grok_array_decl (array_expr, index_exp)
if (TYPE_LANG_SPECIFIC (type)
&& TYPE_OVERLOADS_ARRAY_REF (type))
return build_opfncall (ARRAY_REF, LOOKUP_NORMAL,
- array_expr, index_exp, NULL_TREE);
+ array_expr, index_exp, NULL_TREE);
/* Otherwise, create an ARRAY_REF for a pointer or array type. */
if (TREE_CODE (type) == POINTER_TYPE
@@ -1000,17 +1026,14 @@ grok_array_decl (array_expr, index_exp)
|| TREE_CODE (type) == REFERENCE_TYPE)
type = TREE_TYPE (type);
- if (TYPE_LANG_SPECIFIC (type)
- && TYPE_OVERLOADS_ARRAY_REF (type))
- error ("array expression backwards");
- else if (TREE_CODE (type) == POINTER_TYPE
- || TREE_CODE (type) == ARRAY_TYPE)
+ if (TREE_CODE (type) == POINTER_TYPE
+ || TREE_CODE (type) == ARRAY_TYPE)
return build_array_ref (index_exp, array_expr);
- else
- error("`[]' applied to non-pointer type");
- /* We gave an error, so give an error. Huh? */
- return error_mark_node;
+ /* The expression E1[E2] is identical (by definition) to *((E1)+(E2)). */
+ return build_indirect_ref (build_binary_op (PLUS_EXPR, array_expr,
+ index_exp, 1),
+ "array indexing");
}
/* Given the cast expression EXP, checking out its validity. Either return
@@ -1057,18 +1080,27 @@ delete_sanity (exp, size, doing_vec, use_global_delete)
return build1 (NOP_EXPR, void_type_node, t);
}
- /* You can't delete a pointer to constant. */
- if (code == POINTER_TYPE && TREE_READONLY (TREE_TYPE (type)))
+ if (code == POINTER_TYPE)
{
- error ("`const *' cannot be deleted");
- return error_mark_node;
+ /* You can't delete a pointer to constant. */
+ if (TREE_READONLY (TREE_TYPE (type)))
+ {
+ error ("`const *' cannot be deleted");
+ return error_mark_node;
+ }
+ /* You also can't delete functions. */
+ if (TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE)
+ {
+ error ("cannot delete a function");
+ return error_mark_node;
+ }
}
#if 0
/* If the type has no destructor, then we should build a regular
delete, instead of a vector delete. Otherwise, we would end
up passing a bogus offset into __builtin_delete, which is
- not expecting it. */
+ not expecting it. */
if (doing_vec
&& TREE_CODE (type) == POINTER_TYPE
&& !TYPE_HAS_DESTRUCTOR (TREE_TYPE (type)))
@@ -1128,13 +1160,13 @@ check_classfn (ctype, cname, function)
}
if (methods != end)
- cp_error ("argument list for `%D' does not match any in class `%T'",
- fn_name, ctype);
+ cp_error ("argument list for `%#D' does not match any in class `%T'",
+ function, ctype);
else
{
methods = 0;
- cp_error ("no `%D' member function declared in class `%T'",
- fn_name, ctype);
+ cp_error ("no `%#D' member function declared in class `%T'",
+ function, ctype);
}
/* If we did not find the method in the class, add it to
@@ -1258,7 +1290,7 @@ grokfield (declarator, declspecs, raises, init, asmspec_tree)
else
init = digest_init (TREE_TYPE (value), init, (tree *)0);
}
-
+
if (TREE_CODE (init) == CONST_DECL)
init = DECL_INITIAL (init);
else if (TREE_READONLY_DECL_P (init))
@@ -1301,19 +1333,10 @@ grokfield (declarator, declspecs, raises, init, asmspec_tree)
/* current_class_type can be NULL_TREE in case of error. */
if (asmspec == 0 && current_class_type)
{
- tree name;
- char *buf, *buf2;
-
- buf2 = build_overload_name (current_class_type, 1, 1);
- buf = (char *)alloca (IDENTIFIER_LENGTH (DECL_NAME (value))
- + sizeof (STATIC_NAME_FORMAT)
- + strlen (buf2));
- sprintf (buf, STATIC_NAME_FORMAT, buf2,
- IDENTIFIER_POINTER (DECL_NAME (value)));
- name = get_identifier (buf);
TREE_PUBLIC (value) = 1;
DECL_INITIAL (value) = error_mark_node;
- DECL_ASSEMBLER_NAME (value) = name;
+ DECL_ASSEMBLER_NAME (value)
+ = build_static_name (current_class_type, DECL_NAME (value));
}
pending_statics = perm_tree_cons (NULL_TREE, value, pending_statics);
@@ -1366,9 +1389,11 @@ grokfield (declarator, declspecs, raises, init, asmspec_tree)
if (DECL_FRIEND_P (value))
return void_type_node;
+#if 0 /* Just because a fn is declared doesn't mean we'll try to define it. */
if (current_function_decl && ! IS_SIGNATURE (current_class_type))
cp_error ("method `%#D' of local class must be defined in class body",
value);
+#endif
DECL_IN_AGGR_P (value) = 1;
return value;
@@ -1645,21 +1670,21 @@ grokoptypename (declspecs, declarator)
virtual void f () = 0;
int g ();
};
-
+
class D1 : B
{
public:
int d1;
// error, no f ();
};
-
+
class D2 : B
{
public:
int d2;
void f ();
};
-
+
class D3 : B
{
public:
@@ -1704,7 +1729,7 @@ grok_function_init (decl, init)
/* Mark this function as being "defined". */
DECL_INITIAL (decl) = error_mark_node;
/* pure virtual destructors must be defined. */
- /* pure virtual needs to be defined (as abort) only when put in
+ /* pure virtual needs to be defined (as abort) only when put in
vtbl. For wellformed call, it should be itself. pr4737 */
if (!DESTRUCTOR_NAME_P (DECL_ASSEMBLER_NAME (decl)))
{
@@ -2067,9 +2092,13 @@ finish_anon_union (anon_union_decl)
return;
}
- while (field)
+ for (; field; field = TREE_CHAIN (field))
{
- tree decl = build_decl (VAR_DECL, DECL_NAME (field), TREE_TYPE (field));
+ tree decl;
+ if (TREE_CODE (field) != FIELD_DECL)
+ continue;
+
+ decl = build_decl (VAR_DECL, DECL_NAME (field), TREE_TYPE (field));
/* tell `pushdecl' that this is not tentative. */
DECL_INITIAL (decl) = error_mark_node;
TREE_PUBLIC (decl) = public_p;
@@ -2096,12 +2125,19 @@ finish_anon_union (anon_union_decl)
TREE_PURPOSE of the following TREE_LIST. */
elems = tree_cons (NULL_TREE, decl, elems);
TREE_TYPE (elems) = type;
- field = TREE_CHAIN (field);
}
if (static_p)
{
- make_decl_rtl (main_decl, 0, global_bindings_p ());
- DECL_RTL (anon_union_decl) = DECL_RTL (main_decl);
+ if (main_decl)
+ {
+ make_decl_rtl (main_decl, 0, global_bindings_p ());
+ DECL_RTL (anon_union_decl) = DECL_RTL (main_decl);
+ }
+ else
+ {
+ warning ("anonymous union with no members");
+ return;
+ }
}
/* The following call assumes that there are never any cleanups
@@ -2369,7 +2405,7 @@ import_export_template (type)
CLASSTYPE_VTABLE_NEEDS_WRITING (type) = 0;
}
}
-
+
static void
finish_vtable_vardecl (prev, vars)
tree prev, vars;
@@ -2522,6 +2558,37 @@ walk_sigtables (typedecl_fn, vardecl_fn)
}
}
+/* Determines the proper settings of TREE_PUBLIC and DECL_EXTERNAL for an
+ inline function at end-of-file. */
+
+void
+import_export_inline (decl)
+ tree decl;
+{
+ if (TREE_PUBLIC (decl))
+ return;
+
+ /* If an explicit instantiation doesn't have TREE_PUBLIC set, it was with
+ 'extern'. */
+ if (DECL_EXPLICIT_INSTANTIATION (decl)
+ || (DECL_IMPLICIT_INSTANTIATION (decl) && ! flag_implicit_templates))
+ {
+ TREE_PUBLIC (decl) = 1;
+ DECL_EXTERNAL (decl) = 1;
+ }
+ else if (DECL_FUNCTION_MEMBER_P (decl))
+ {
+ tree ctype = DECL_CLASS_CONTEXT (decl);
+ if (CLASSTYPE_INTERFACE_KNOWN (ctype))
+ {
+ TREE_PUBLIC (decl) = 1;
+ DECL_EXTERNAL (decl)
+ = (CLASSTYPE_INTERFACE_ONLY (ctype)
+ || (DECL_INLINE (decl) && ! flag_implement_inlines));
+ }
+ }
+}
+
extern int parse_time, varconst_time;
#define TIMEVAR(VAR, BODY) \
@@ -2541,8 +2608,7 @@ finish_file ()
tree fnname;
tree vars = static_aggregates;
int needs_cleaning = 0, needs_messing_up = 0;
-
- build_exception_table ();
+ int have_exception_handlers = build_exception_table ();
if (flag_detailed_statistics)
dump_tree_statistics ();
@@ -2636,7 +2702,7 @@ finish_file ()
mess_up:
/* Must do this while we think we are at the top level. */
vars = nreverse (static_aggregates);
- if (vars != NULL_TREE)
+ if (vars != NULL_TREE || have_exception_handlers)
{
fnname = get_file_function_name ('I');
start_function (void_list_node, build_parse_node (CALL_EXPR, fnname, void_list_node, NULL_TREE), 0, 0);
@@ -2648,6 +2714,9 @@ finish_file ()
push_momentary ();
expand_start_bindings (0);
+ if (have_exception_handlers)
+ register_exception_table ();
+
while (vars)
{
tree decl = TREE_VALUE (vars);
@@ -2712,7 +2781,6 @@ finish_file ()
}
}
if (IS_AGGR_TYPE (TREE_TYPE (decl))
- || init == 0
|| TREE_CODE (TREE_TYPE (decl)) == ARRAY_TYPE)
expand_aggr_init (decl, init, 0);
else if (TREE_CODE (init) == TREE_VEC)
@@ -2828,24 +2896,12 @@ finish_file ()
0; don't crash. */
if (TREE_ASM_WRITTEN (decl) || DECL_SAVED_INSNS (decl) == 0)
continue;
- if (DECL_FUNCTION_MEMBER_P (decl) && !TREE_PUBLIC (decl))
- {
- tree ctype = DECL_CLASS_CONTEXT (decl);
- if (CLASSTYPE_INTERFACE_KNOWN (ctype))
- {
- TREE_PUBLIC (decl) = 1;
- DECL_EXTERNAL (decl)
- = (CLASSTYPE_INTERFACE_ONLY (ctype)
- || (DECL_INLINE (decl) && ! flag_implement_inlines));
- }
- }
+ import_export_inline (decl);
if (TREE_PUBLIC (decl)
|| TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (decl))
|| flag_keep_inline_functions)
{
- if (DECL_EXTERNAL (decl)
- || (DECL_IMPLICIT_INSTANTIATION (decl)
- && ! flag_implicit_templates))
+ if (DECL_EXTERNAL (decl))
assemble_external (decl);
else
{
@@ -2872,9 +2928,7 @@ finish_file ()
if (TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (decl))
&& ! TREE_ASM_WRITTEN (decl))
{
- if (DECL_EXTERNAL (decl)
- || (DECL_IMPLICIT_INSTANTIATION (decl)
- && ! flag_implicit_templates))
+ if (DECL_EXTERNAL (decl))
assemble_external (decl);
else
{
@@ -2950,7 +3004,7 @@ reparse_absdcl_as_casts (decl, expr)
tree decl, expr;
{
tree type;
-
+
if (TREE_CODE (expr) == CONSTRUCTOR)
{
type = groktypename (TREE_VALUE (TREE_OPERAND (decl, 1)));
@@ -3034,7 +3088,7 @@ finish_decl_parsing (decl)
tree decl;
{
extern int current_class_depth;
-
+
switch (TREE_CODE (decl))
{
case IDENTIFIER_NODE:
diff --git a/gnu/usr.bin/cc/cc1plus/edsel.c b/gnu/usr.bin/cc/cc1plus/edsel.c
index 78b2637..aacb443 100644
--- a/gnu/usr.bin/cc/cc1plus/edsel.c
+++ b/gnu/usr.bin/cc/cc1plus/edsel.c
@@ -198,7 +198,7 @@ init_cadillac ()
case EWOULDBLOCK:
sleep (5);
return;
-
+
case 0:
fatal ("init_cadillac: EOF on connection to kernel, exiting\n");
break;
diff --git a/gnu/usr.bin/cc/cc1plus/errfn.c b/gnu/usr.bin/cc/cc1plus/errfn.c
index 1b345fd..0a5d1e5 100644
--- a/gnu/usr.bin/cc/cc1plus/errfn.c
+++ b/gnu/usr.bin/cc/cc1plus/errfn.c
@@ -17,7 +17,7 @@ GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GNU CC; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
-
+
#include "config.h"
#include "tree.h"
#include <ctype.h>
@@ -30,6 +30,11 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
typedef char* cp_printer PROTO((HOST_WIDE_INT, int));
extern cp_printer * cp_printers[256];
+/* Whether or not we should try to be quiet for errors and warnings; this is
+ used to avoid being too talkative about problems with tentative choices
+ when we're computing the conversion costs for a method call. */
+int cp_silent = 0;
+
typedef void errorfn (); /* deliberately vague */
extern char* cp_file_of PROTO((tree));
@@ -59,13 +64,13 @@ cp_thing (errfn, atarg1, format, arglist)
ARGSINIT
fmt = STRDUP(format);
-
+
for (f = fmt, arg = 0; *f; ++f)
{
cp_printer * function;
int alternate;
int maybe_here;
-
+
/* ignore text */
if (*f != '%') continue;
@@ -119,7 +124,7 @@ cp_thing (errfn, atarg1, format, arglist)
char *p;
if (arg >= NARGS) abort ();
-
+
if (maybe_here && atarg1)
atarg = args[arg];
@@ -150,7 +155,8 @@ cp_error (format, arglist)
arglist_dcl
{
extern errorfn error;
- cp_thing (error, 0, format, arglist);
+ if (! cp_silent)
+ cp_thing (error, 0, format, arglist);
}
void
@@ -159,7 +165,8 @@ cp_warning (format, arglist)
arglist_dcl
{
extern errorfn warning;
- cp_thing (warning, 0, format, arglist);
+ if (! cp_silent)
+ cp_thing (warning, 0, format, arglist);
}
void
@@ -168,7 +175,8 @@ cp_pedwarn (format, arglist)
arglist_dcl
{
extern errorfn pedwarn;
- cp_thing (pedwarn, 0, format, arglist);
+ if (! cp_silent)
+ cp_thing (pedwarn, 0, format, arglist);
}
void
@@ -177,7 +185,8 @@ cp_compiler_error (format, arglist)
arglist_dcl
{
extern errorfn compiler_error;
- cp_thing (compiler_error, 0, format, arglist);
+ if (! cp_silent)
+ cp_thing (compiler_error, 0, format, arglist);
}
void
@@ -195,7 +204,8 @@ cp_error_at (format, arglist)
arglist_dcl
{
extern errorfn error_with_file_and_line;
- cp_thing (error_with_file_and_line, 1, format, arglist);
+ if (! cp_silent)
+ cp_thing (error_with_file_and_line, 1, format, arglist);
}
void
@@ -204,7 +214,8 @@ cp_warning_at (format, arglist)
arglist_dcl
{
extern errorfn warning_with_file_and_line;
- cp_thing (warning_with_file_and_line, 1, format, arglist);
+ if (! cp_silent)
+ cp_thing (warning_with_file_and_line, 1, format, arglist);
}
void
@@ -213,5 +224,6 @@ cp_pedwarn_at (format, arglist)
arglist_dcl
{
extern errorfn pedwarn_with_file_and_line;
- cp_thing (pedwarn_with_file_and_line, 1, format, arglist);
+ if (! cp_silent)
+ cp_thing (pedwarn_with_file_and_line, 1, format, arglist);
}
diff --git a/gnu/usr.bin/cc/cc1plus/error.c b/gnu/usr.bin/cc/cc1plus/error.c
index f431f6a..cf48533 100644
--- a/gnu/usr.bin/cc/cc1plus/error.c
+++ b/gnu/usr.bin/cc/cc1plus/error.c
@@ -37,7 +37,7 @@ typedef char* cp_printer ();
#define _ (cp_printer *) 0
cp_printer * cp_printers[256] =
-{
+{
/*0 1 2 3 4 5 6 7 8 9 A B C D E F */
_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, /* 0x00 */
_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, /* 0x10 */
@@ -104,6 +104,8 @@ dump_readonly_or_volatile (t, p)
if (p == before) OB_PUTC (' ');
if (TYPE_READONLY (t))
OB_PUTS ("const");
+ if (TYPE_READONLY (t) && TYPE_VOLATILE (t))
+ OB_PUTC (' ');
if (TYPE_VOLATILE (t))
OB_PUTS ("volatile");
if (p == after) OB_PUTC (' ');
@@ -122,7 +124,7 @@ dump_type (t, v)
{
if (t == NULL_TREE)
return;
-
+
if (TYPE_PTRMEMFUNC_P (t))
goto offset_type;
@@ -263,7 +265,7 @@ dump_aggr_type (t, v)
OB_PUTCP (variety);
OB_PUTC (' ');
}
-
+
name = TYPE_NAME (t);
if (DECL_CONTEXT (name))
@@ -312,13 +314,13 @@ dump_type_prefix (t, v)
t = TYPE_PTRMEMFUNC_FN_TYPE (t);
goto offset_type;
}
-
+
switch (TREE_CODE (t))
{
case POINTER_TYPE:
{
tree sub = TREE_TYPE (t);
-
+
dump_type_prefix (sub, v);
/* A tree for a member pointer looks like pointer to offset,
so let the OFFSET_TYPE case handle it. */
@@ -330,7 +332,7 @@ dump_type_prefix (t, v)
case FUNCTION_TYPE:
case METHOD_TYPE:
break;
-
+
case ARRAY_TYPE:
OB_PUTC2 (' ', '(');
break;
@@ -340,7 +342,7 @@ dump_type_prefix (t, v)
if (! (TYPE_READONLY (sub) || TYPE_VOLATILE (sub)))
break;
/* But we do want "char *const *" */
-
+
default:
OB_PUTC (' ');
}
@@ -423,7 +425,7 @@ dump_type_prefix (t, v)
case VOID_TYPE:
dump_type (t, v);
break;
-
+
default:
sorry ("`%s' not supported by dump_type_prefix",
tree_code_name[(int) TREE_CODE (t)]);
@@ -477,7 +479,7 @@ dump_type_suffix (t, v)
OB_PUTC (']');
dump_type_suffix (TREE_TYPE (t), v);
break;
-
+
case ENUMERAL_TYPE:
case ERROR_MARK:
case IDENTIFIER_NODE:
@@ -545,7 +547,7 @@ dump_global_iord (t)
OB_PUTS ("destructors");
else
my_friendly_abort (352);
-
+
OB_PUTS (" for ");
OB_PUTCP (input_filename);
OB_PUTC (')');
@@ -569,7 +571,8 @@ dump_decl (t, v)
{
/* Don't say 'typedef class A' */
tree type = TREE_TYPE (t);
- if (IS_AGGR_TYPE (type) && ! TYPE_PTRMEMFUNC_P (type)
+ if (((IS_AGGR_TYPE (type) && ! TYPE_PTRMEMFUNC_P (type))
+ || TREE_CODE (type) == ENUMERAL_TYPE)
&& type == TYPE_MAIN_VARIANT (type))
{
dump_type (type, v);
@@ -580,7 +583,7 @@ dump_decl (t, v)
OB_PUTS ("typedef ");
goto general;
break;
-
+
case VAR_DECL:
if (VTABLE_NAME_P (DECL_NAME (t)))
{
@@ -666,21 +669,31 @@ dump_decl (t, v)
case TEMPLATE_DECL:
{
tree args = DECL_TEMPLATE_PARMS (t);
- int i, len = TREE_VEC_LENGTH (args);
+ int i, len = args ? TREE_VEC_LENGTH (args) : 0;
OB_PUTS ("template <");
for (i = 0; i < len; i++)
{
tree arg = TREE_VEC_ELT (args, i);
- if (TREE_CODE (arg) == IDENTIFIER_NODE)
+ tree defval = TREE_PURPOSE (arg);
+ arg = TREE_VALUE (arg);
+ if (TREE_CODE (arg) == TYPE_DECL)
{
OB_PUTS ("class ");
- OB_PUTID (arg);
+ OB_PUTID (DECL_NAME (arg));
}
else
dump_decl (arg, 1);
+
+ if (defval)
+ {
+ OB_PUTS (" = ");
+ dump_decl (defval, 1);
+ }
+
OB_PUTC2 (',', ' ');
}
- OB_UNPUT (2);
+ if (len != 0)
+ OB_UNPUT (2);
OB_PUTC2 ('>', ' ');
if (DECL_TEMPLATE_IS_CLASS (t))
@@ -740,12 +753,12 @@ dump_function_decl (t, v)
cname = TREE_TYPE (TREE_VALUE (parmtypes));
v = (v > 0);
-
+
if (v)
{
if (DECL_STATIC_FUNCTION_P (t))
OB_PUTS ("static ");
-
+
if (! IDENTIFIER_TYPENAME_P (name)
&& ! DECL_CONSTRUCTOR_P (t)
&& ! DESTRUCTOR_NAME_P (name))
@@ -768,9 +781,9 @@ dump_function_decl (t, v)
if (DESTRUCTOR_NAME_P (name))
parmtypes = TREE_CHAIN (parmtypes);
-
+
dump_function_name (t);
-
+
OB_PUTC ('(');
if (parmtypes)
@@ -1020,7 +1033,7 @@ dump_expr (t, nop)
{
tree fn = TREE_OPERAND (t, 0);
tree args = TREE_OPERAND (t, 1);
-
+
if (TREE_CODE (fn) == ADDR_EXPR)
fn = TREE_OPERAND (fn, 0);
@@ -1179,7 +1192,7 @@ dump_expr (t, nop)
while (TREE_CODE (next) == POINTER_TYPE)
next = TREE_TYPE (next);
-
+
if (TREE_CODE (next) == FUNCTION_TYPE)
{
if (!nop) OB_PUTC ('(');
@@ -1219,6 +1232,14 @@ dump_expr (t, nop)
break;
}
+ case TREE_LIST:
+ if (TREE_VALUE (t) && TREE_CODE (TREE_VALUE (t)) == FUNCTION_DECL)
+ {
+ OB_PUTID (DECL_NAME (TREE_VALUE (t)));
+ break;
+ }
+ /* else fall through */
+
/* This list is incomplete, but should suffice for now.
It is very important that `sorry' does not call
`report_error_function'. That could cause an infinite loop. */
@@ -1331,12 +1352,26 @@ int
cp_line_of (t)
tree t;
{
+ int line = 0;
if (TREE_CODE (t) == PARM_DECL)
- return DECL_SOURCE_LINE (DECL_CONTEXT (t));
- else if (TREE_CODE_CLASS (TREE_CODE (t)) == 't')
- return DECL_SOURCE_LINE (TYPE_NAME (t));
+ line = DECL_SOURCE_LINE (DECL_CONTEXT (t));
+ if (TREE_CODE (t) == TYPE_DECL && DECL_ARTIFICIAL (t))
+ t = TREE_TYPE (t);
+
+ if (TREE_CODE_CLASS (TREE_CODE (t)) == 't')
+ {
+ if (IS_AGGR_TYPE (t))
+ line = CLASSTYPE_SOURCE_LINE (t);
+ else
+ line = DECL_SOURCE_LINE (TYPE_NAME (t));
+ }
else
- return DECL_SOURCE_LINE (t);
+ line = DECL_SOURCE_LINE (t);
+
+ if (line == 0)
+ return lineno;
+
+ return line;
}
char *
@@ -1387,7 +1422,7 @@ op_as_string (p, v)
if (p == 0)
return "{unknown}";
-
+
strcpy (buf + 9, opname_tab [p]);
return buf;
}
diff --git a/gnu/usr.bin/cc/cc1plus/except.c b/gnu/usr.bin/cc/cc1plus/except.c
index dc91b9d..ce875a6 100644
--- a/gnu/usr.bin/cc/cc1plus/except.c
+++ b/gnu/usr.bin/cc/cc1plus/except.c
@@ -59,11 +59,6 @@ sorry_no_eh ()
}
void
-build_exception_table ()
-{
-}
-
-void
expand_exception_blocks ()
{
}
@@ -180,32 +175,12 @@ output_exception_table_entry (file, start_label, end_label, eh_label)
{
char label[100];
- fprintf (file, "\t%s\t ", ASM_LONG);
- if (GET_CODE (start_label) == CODE_LABEL)
- {
- ASM_GENERATE_INTERNAL_LABEL (label, "L", CODE_LABEL_NUMBER (start_label));
- assemble_name (file, label);
- }
- else if (GET_CODE (start_label) == SYMBOL_REF)
- {
- fprintf (stderr, "YYYYYYYYYEEEEEEEESSSSSSSSSSSS!!!!!!!!!!\n");
- assemble_name (file, XSTR (start_label, 0));
- }
- putc ('\n', file);
-
- fprintf (file, "\t%s\t ", ASM_LONG);
- ASM_GENERATE_INTERNAL_LABEL (label, "L", CODE_LABEL_NUMBER (end_label));
- assemble_name (file, label);
- putc ('\n', file);
-
- fprintf (file, "\t%s\t ", ASM_LONG);
- ASM_GENERATE_INTERNAL_LABEL (label, "L", CODE_LABEL_NUMBER (eh_label));
- assemble_name (file, label);
- putc ('\n', file);
-
+ assemble_integer (start_label, BITS_PER_WORD/BITS_PER_UNIT, 1);
+ assemble_integer (end_label, BITS_PER_WORD/BITS_PER_UNIT, 1);
+ assemble_integer (eh_label, BITS_PER_WORD/BITS_PER_UNIT, 1);
putc ('\n', file); /* blank line */
}
-
+
static void
easy_expand_asm (str)
char *str;
@@ -394,7 +369,7 @@ exception_section ()
popped and set to be the last insn, and the first and last insns
of the catch block just generated can be enqueue'd for output at
a later time.
-
+
Next we must insure that when the catch block is executed, all
finalizations for the matching try block have been completed. If
any of those finalizations throw an exception, we must call
@@ -410,7 +385,7 @@ exception_section ()
the catch block which basically wraps all the "catch (...) {...}"
statements in a big if/then/else construct that matches the
correct block to call.
-
+
===================================================================== */
extern rtx emit_insn PROTO((rtx));
@@ -617,7 +592,7 @@ push_rtl_perm ()
{
extern struct obstack permanent_obstack;
extern struct obstack *rtl_obstack;
-
+
saved_rtl_obstack = rtl_obstack;
rtl_obstack = &permanent_obstack;
}
@@ -628,7 +603,7 @@ pop_rtl_from_perm ()
{
extern struct obstack permanent_obstack;
extern struct obstack *rtl_obstack;
-
+
rtl_obstack = saved_rtl_obstack;
}
@@ -879,7 +854,7 @@ start_protect ()
emit_label (push_eh_entry (&ehstack));
}
}
-
+
/* call this to end a block of unwind protection. the finalization tree is
the finalization which needs to be run in order to cleanly unwind through
this level of protection. (ie: call this when a scope is exited)*/
@@ -967,7 +942,7 @@ expand_start_all_catch ()
label = gen_label_rtx ();
/* The label for the exception handling block we will save. */
emit_label (label);
-
+
push_label_entry (&caught_return_label_stack, label);
/* Remember where we started. */
@@ -998,7 +973,7 @@ expand_start_all_catch ()
label = gen_label_rtx ();
emit_jump (label);
#endif
-
+
/* All this should be out of line, and saved back in the exception handler
block area. */
#if 1
@@ -1050,7 +1025,7 @@ expand_end_all_catch ()
pop_label_entry (&caught_return_label_stack);
push_except_stmts (&exceptstack, catchstart, catchend);
-
+
/* Here we fall through into the continuation code. */
}
@@ -1145,7 +1120,7 @@ expand_start_catch_block (declspecs, declarator)
init_type = build_reference_type (init_type);
init = convert_from_reference (save_expr (make_tree (init_type, saved_throw_value)));
-
+
/* Do we need the below two lines? */
/* Let `finish_decl' know that this initializer is ok. */
DECL_INITIAL (decl) = init;
@@ -1161,13 +1136,12 @@ expand_start_catch_block (declspecs, declarator)
else
type = NULL_TREE;
- false_label_rtx = gen_label_rtx ();
- push_label_entry (&false_label_stack, false_label_rtx);
-
- /* This is saved for the exception table. */
+ /* These are saved for the exception table. */
push_rtl_perm ();
+ false_label_rtx = gen_label_rtx ();
protect_label_rtx = gen_label_rtx ();
pop_rtl_from_perm ();
+ push_label_entry (&false_label_stack, false_label_rtx);
push_label_entry (&false_label_stack, protect_label_rtx);
if (type)
@@ -1246,7 +1220,7 @@ void expand_end_catch_block ()
/* Cleanup the EH paramater. */
expand_end_bindings (decls = getdecls (), decls != NULL_TREE, 0);
-
+
/* label we emit to jump to if this catch block didn't match. */
emit_label (end_protect_label_rtx = pop_label_entry (&false_label_stack));
@@ -1436,39 +1410,62 @@ expand_throw (exp)
emit_jump (throw_label);
}
+/* end of: my-cp-except.c */
+#endif
-/* output the exception table */
-void
+
+/* Output the exception table.
+ Return the number of handlers. */
+int
build_exception_table ()
{
+ int count = 0;
+#ifdef TRY_NEW_EH
extern FILE *asm_out_file;
struct ehEntry *entry;
+ tree eh_node_decl;
if (! doing_eh (0))
- return;
-
- exception_section ();
-
- /* Beginning marker for table. */
- fprintf (asm_out_file, " .global ___EXCEPTION_TABLE__\n");
- fprintf (asm_out_file, " .align 4\n");
- fprintf (asm_out_file, "___EXCEPTION_TABLE__:\n");
- fprintf (asm_out_file, " .word 0, 0, 0\n");
+ return 0;
- while (entry = dequeue_eh_entry (&eh_table_output_queue)) {
+ while (entry = dequeue_eh_entry (&eh_table_output_queue))
+ {
+ if (count == 0)
+ {
+ exception_section ();
+
+ /* Beginning marker for table. */
+ ASM_OUTPUT_ALIGN (asm_out_file, 2);
+ ASM_OUTPUT_LABEL (asm_out_file, "__EXCEPTION_TABLE__");
+ fprintf (asm_out_file, " .word 0, 0, 0\n");
+ }
+ count++;
output_exception_table_entry (asm_out_file,
- entry->start_label, entry->end_label, entry->exception_handler_label);
+ entry->start_label, entry->end_label,
+ entry->exception_handler_label);
}
- /* Ending marker for table. */
- fprintf (asm_out_file, " .global ___EXCEPTION_END__\n");
- fprintf (asm_out_file, "___EXCEPTION_END__:\n");
- fprintf (asm_out_file, " .word -1, -1, -1\n");
-}
+ if (count)
+ {
+ /* Ending marker for table. */
+ ASM_OUTPUT_LABEL (asm_out_file, "__EXCEPTION_END__");
+ fprintf (asm_out_file, " .word -1, -1, -1\n");
+ }
-/* end of: my-cp-except.c */
-#endif
+#endif /* TRY_NEW_EH */
+ return count;
+}
+void
+register_exception_table ()
+{
+#ifdef TRY_NEW_EH
+ emit_library_call (gen_rtx (SYMBOL_REF, Pmode, "__register_exceptions"), 0,
+ VOIDmode, 1,
+ gen_rtx (SYMBOL_REF, Pmode, "__EXCEPTION_TABLE__"),
+ Pmode);
+#endif /* TRY_NEW_EH */
+}
/* Build a throw expression. */
tree
diff --git a/gnu/usr.bin/cc/cc1plus/expr.c b/gnu/usr.bin/cc/cc1plus/expr.c
index c2213d5..1d9054b 100644
--- a/gnu/usr.bin/cc/cc1plus/expr.c
+++ b/gnu/usr.bin/cc/cc1plus/expr.c
@@ -99,7 +99,7 @@ cplus_expand_expr (exp, target, tmode, modifier)
as is building the call which will perform the
initialization. It is left here to show the choices that
exist for C++. */
-
+
if (TREE_CODE (func) == ADDR_EXPR
&& TREE_CODE (TREE_OPERAND (func, 0)) == FUNCTION_DECL
&& DECL_CONSTRUCTOR_P (TREE_OPERAND (func, 0)))
@@ -148,9 +148,16 @@ cplus_expand_expr (exp, target, tmode, modifier)
{
if (pcc_struct_return)
{
+ extern int flag_access_control;
+ int old_ac = flag_access_control;
+
tree init = build (RTL_EXPR, type, 0, return_target);
TREE_ADDRESSABLE (init) = 1;
+
+ flag_access_control = 0;
expand_aggr_init (slot, init, 0);
+ flag_access_control = old_ac;
+
if (TYPE_NEEDS_DESTRUCTOR (type))
{
init = build (RTL_EXPR, build_reference_type (type), 0,
diff --git a/gnu/usr.bin/cc/cc1plus/gc.c b/gnu/usr.bin/cc/cc1plus/gc.c
index 9db4d62..a9087fc 100644
--- a/gnu/usr.bin/cc/cc1plus/gc.c
+++ b/gnu/usr.bin/cc/cc1plus/gc.c
@@ -117,7 +117,7 @@ type_needs_gc_entry (type)
}
/* Predicate that returns non-zero iff FROM is safe from the GC.
-
+
If TO is nonzero, it means we know that FROM is being stored
in TO, which make make it safe. */
int
@@ -290,7 +290,7 @@ build_static_gc_entry (decl, type)
else
{
/* Not yet implemented.
-
+
Cons up a static variable that holds address and length info
and add that to ___ARR_LIST__. */
my_friendly_abort (43);
@@ -432,7 +432,7 @@ build_typeid (exp)
return error_mark_node;
type = TREE_TYPE (exp);
-
+
/* if b is an instance of B, typeid(b) == typeid(B). Do this before
reference trickiness. */
if (TREE_CODE (exp) == VAR_DECL && TREE_CODE (type) == RECORD_TYPE)
@@ -446,7 +446,7 @@ build_typeid (exp)
if (TREE_CODE (type) == REFERENCE_TYPE && TYPE_VIRTUAL_P (TREE_TYPE (type)))
{
/* build reference to Type_info from vtable. */
-
+
sorry ("finding Type_info for an object");
return error_mark_node;
}
@@ -462,12 +462,12 @@ get_typeid (type)
{
if (type == error_mark_node)
return error_mark_node;
-
+
/* Is it useful (and/or correct) to have different typeids for `T &'
and `T'? */
if (TREE_CODE (type) == REFERENCE_TYPE)
type = TREE_TYPE (type);
-
+
/* build reference to static Type_info */
#if 1
sorry ("finding Type_info for a type");
@@ -480,7 +480,7 @@ get_typeid (type)
/* ... */
-#endif
+#endif
}
/* Execute a dynamic cast, as described in section 5.2.6 of the 9/93 working
@@ -496,7 +496,7 @@ build_dynamic_cast (type, expr)
if (type == error_mark_node || expr == error_mark_node)
return error_mark_node;
-
+
switch (tc)
{
case POINTER_TYPE:
@@ -520,7 +520,7 @@ build_dynamic_cast (type, expr)
exprtype = build_reference_type (exprtype);
ec = REFERENCE_TYPE;
}
-
+
/* the TREE_CODE of exprtype must match that of type. */
if (ec != tc)
{
@@ -583,15 +583,15 @@ build_dynamic_cast (type, expr)
{
cp_warning ("dynamic_cast of `%E' to `%#T' can never succeed",
expr, type);
- retval = build_int_2 (0, 0);
- TREE_TYPE (retval) = type;
+ retval = build_int_2 (0, 0);
+ TREE_TYPE (retval) = type;
return retval;
}
}
/* Build run-time conversion. */
sorry ("run-time type conversion");
- retval = build_int_2 (0, 0);
- TREE_TYPE (retval) = type;
+ retval = build_int_2 (0, 0);
+ TREE_TYPE (retval) = type;
return retval;
}
}
diff --git a/gnu/usr.bin/cc/cc1plus/hash.h b/gnu/usr.bin/cc/cc1plus/hash.h
index 8453c4b..8b55696 100644
--- a/gnu/usr.bin/cc/cc1plus/hash.h
+++ b/gnu/usr.bin/cc/cc1plus/hash.h
@@ -63,29 +63,29 @@ is_reserved_word (str, len)
{
static struct resword wordlist[] =
{
- {"",}, {"",}, {"",}, {"",},
+ {"",}, {"",}, {"",}, {"",},
{"else", ELSE, NORID,},
- {"",},
+ {"",},
{"delete", DELETE, NORID,},
{"double", TYPESPEC, RID_DOUBLE,},
{"true", CXX_TRUE, NORID,},
{"__asm__", GCC_ASM_KEYWORD, NORID},
{"typeid", TYPEID, NORID,},
- {"",},
+ {"",},
{"this", THIS, NORID,},
- {"",},
+ {"",},
{"try", TRY, NORID,},
- {"",}, {"",}, {"",}, {"",},
+ {"",}, {"",}, {"",}, {"",},
{"do", DO, NORID,},
- {"",},
+ {"",},
{"static_cast", STATIC_CAST, NORID,},
{"template", TEMPLATE, RID_TEMPLATE,},
{"protected", VISSPEC, RID_PROTECTED,},
- {"",},
+ {"",},
{"__classof__", CLASSOF, NORID},
- {"",},
+ {"",},
{"__headof__", HEADOF, NORID},
- {"",},
+ {"",},
{"bool", TYPESPEC, RID_BOOL,},
{"__const__", TYPE_QUAL, RID_CONST},
{"__volatile", TYPE_QUAL, RID_VOLATILE},
@@ -98,7 +98,7 @@ is_reserved_word (str, len)
{"sizeof", SIZEOF, NORID,},
{"short", TYPESPEC, RID_SHORT,},
{"typeof", TYPEOF, NORID,},
- {"",},
+ {"",},
{"int", TYPESPEC, RID_INT,},
{"__signed", TYPESPEC, RID_SIGNED},
{"private", VISSPEC, RID_PRIVATE,},
@@ -116,17 +116,17 @@ is_reserved_word (str, len)
{"switch", SWITCH, NORID,},
{"__label__", LABEL, NORID},
{"__extension__", EXTENSION, NORID},
- {"",},
+ {"",},
{"__asm", GCC_ASM_KEYWORD, NORID},
{"for", FOR, NORID,},
{"__typeof", TYPEOF, NORID},
{"__alignof__", ALIGNOF, NORID},
- {"",},
+ {"",},
{"case", CASE, NORID,},
{"virtual", SCSPEC, RID_VIRTUAL,},
{"if", IF, NORID,},
{"while", WHILE, NORID,},
- {"",},
+ {"",},
{"class", AGGR, RID_CLASS,},
{"typedef", SCSPEC, RID_TYPEDEF,},
{"const", TYPE_QUAL, RID_CONST,},
@@ -136,11 +136,11 @@ is_reserved_word (str, len)
{"inline", SCSPEC, RID_INLINE,},
{"throw", THROW, NORID,},
{"unsigned", TYPESPEC, RID_UNSIGNED,},
- {"",},
+ {"",},
{"headof", HEADOF, NORID,},
- {"",},
+ {"",},
{"goto", GOTO, NORID,},
- {"",}, {"",},
+ {"",}, {"",},
{"public", VISSPEC, RID_PUBLIC,},
{"signature", AGGR, RID_SIGNATURE /* Extension */,},
{"volatile", TYPE_QUAL, RID_VOLATILE,},
@@ -149,35 +149,35 @@ is_reserved_word (str, len)
{"__inline__", SCSPEC, RID_INLINE},
{"__alignof", ALIGNOF, NORID},
{"asm", ASM_KEYWORD, NORID,},
- {"",},
+ {"",},
{"new", NEW, NORID,},
- {"",},
+ {"",},
{"mutable", SCSPEC, RID_MUTABLE,},
{"union", AGGR, RID_UNION,},
{"operator", OPERATOR, NORID,},
{"register", SCSPEC, RID_REGISTER,},
- {"",}, {"",},
+ {"",}, {"",},
{"__wchar_t", TYPESPEC, RID_WCHAR /* Unique to ANSI C++ */,},
- {"",},
+ {"",},
{"long", TYPESPEC, RID_LONG,},
- {"",}, {"",}, {"",},
+ {"",}, {"",}, {"",},
{"continue", CONTINUE, NORID,},
{"return", RETURN, NORID,},
{"enum", ENUM, NORID,},
- {"",}, {"",},
+ {"",}, {"",},
{"dynamic_cast", DYNAMIC_CAST, NORID,},
- {"",}, {"",},
+ {"",}, {"",},
{"reinterpret_cast", REINTERPRET_CAST, NORID,},
- {"",}, {"",}, {"",}, {"",},
+ {"",}, {"",}, {"",}, {"",},
{"char", TYPESPEC, RID_CHAR,},
- {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",},
+ {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",},
{"classof", CLASSOF, NORID,},
- {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",},
+ {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",},
{"const_cast", CONST_CAST, NORID,},
- {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",},
- {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",},
- {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",},
- {"",}, {"",}, {"",}, {"",}, {"",},
+ {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",},
+ {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",},
+ {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",},
+ {"",}, {"",}, {"",}, {"",}, {"",},
{"catch", CATCH, NORID,},
};
diff --git a/gnu/usr.bin/cc/cc1plus/init.c b/gnu/usr.bin/cc/cc1plus/init.c
index 5e5d580..afc3831 100644
--- a/gnu/usr.bin/cc/cc1plus/init.c
+++ b/gnu/usr.bin/cc/cc1plus/init.c
@@ -217,6 +217,7 @@ perform_member_init (member, name, init, explicit)
expand_expr_stmt (build_modify_expr (decl, INIT_EXPR, init));
}
}
+ expand_cleanups_to (NULL_TREE);
if (flag_handle_exceptions && TYPE_NEEDS_DESTRUCTOR (type))
cp_warning ("caution, member `%D' may not be destroyed in the presense of an exception during construction", member);
}
@@ -226,15 +227,19 @@ static tree
sort_member_init (t)
tree t;
{
+ extern int warn_reorder;
tree x, member, name, field, init;
tree init_list = NULL_TREE;
tree fields_to_unmark = NULL_TREE;
int found;
+ int last_pos = 0;
+ tree last_field;
for (member = TYPE_FIELDS (t); member ; member = TREE_CHAIN (member))
{
+ int pos;
found = 0;
- for (x = current_member_init_list ; x ; x = TREE_CHAIN (x))
+ for (x = current_member_init_list, pos = 0; x; x = TREE_CHAIN (x), ++pos)
{
/* If we cleared this out, then pay no attention to it. */
if (TREE_PURPOSE (x) == NULL_TREE)
@@ -264,6 +269,17 @@ sort_member_init (t)
field);
continue;
}
+ else
+ {
+ if (pos < last_pos && warn_reorder)
+ {
+ cp_warning_at ("member initializers for `%#D'", last_field);
+ cp_warning_at (" and `%#D'", field);
+ warning (" will be re-ordered to match declaration order");
+ }
+ last_pos = pos;
+ last_field = field;
+ }
init_list = chainon (init_list,
build_tree_list (name, TREE_VALUE (x)));
@@ -356,7 +372,7 @@ sort_member_init (t)
Note that emit_base_init does *not* initialize virtual base
classes. That is done specially, elsewhere. */
-
+
void
emit_base_init (t, immediately)
tree t;
@@ -500,9 +516,10 @@ emit_base_init (t, immediately)
continue;
member = convert_pointer_to (binfo, current_class_decl);
- expand_aggr_init_1 (t_binfo, 0,
+ expand_aggr_init_1 (binfo, 0,
build_indirect_ref (member, NULL_PTR), init,
- BINFO_OFFSET_ZEROP (binfo), LOOKUP_COMPLAIN);
+ BINFO_OFFSET_ZEROP (binfo), LOOKUP_NORMAL);
+ expand_cleanups_to (NULL_TREE);
}
if (pass == 0)
@@ -568,9 +585,10 @@ emit_base_init (t, immediately)
current_class_decl, BINFO_OFFSET (base_binfo));
ref = build_indirect_ref (base, NULL_PTR);
- expand_aggr_init_1 (t_binfo, 0, ref, NULL_TREE,
+ expand_aggr_init_1 (base_binfo, 0, ref, NULL_TREE,
BINFO_OFFSET_ZEROP (base_binfo),
- LOOKUP_COMPLAIN);
+ LOOKUP_NORMAL);
+ expand_cleanups_to (NULL_TREE);
}
}
CLEAR_BINFO_BASEINIT_MARKED (base_binfo);
@@ -655,11 +673,6 @@ emit_base_init (t, immediately)
current_member_init_list = NULL_TREE;
- /* It is possible for the initializers to need cleanups.
- Expand those cleanups now that all the initialization
- has been done. */
- expand_cleanups_to (NULL_TREE);
-
if (! immediately)
{
extern rtx base_init_insns;
@@ -734,6 +747,7 @@ expand_aggr_vbase_init_1 (binfo, exp, addr, init_list)
/* Call constructors, but don't set up vtables. */
expand_aggr_init_1 (binfo, exp, ref, init, 0,
LOOKUP_COMPLAIN|LOOKUP_SPECULATIVELY);
+ expand_cleanups_to (NULL_TREE);
CLEAR_BINFO_VBASE_INIT_MARKED (binfo);
}
@@ -825,7 +839,7 @@ do_member_init (s_id, name, init)
TYPE is the type for which the initialization is being performed.
FIELD must be a member of TYPE, or the base type from which FIELD
comes must not need a constructor.
-
+
MEMBER_NAME is the name of the member. */
static int
@@ -1117,7 +1131,11 @@ expand_aggr_init (exp, init, alias_this)
int was_const_elts = TYPE_READONLY (TREE_TYPE (type));
tree itype = init ? TREE_TYPE (init) : NULL_TREE;
if (was_const_elts)
- TREE_TYPE (exp) = TYPE_MAIN_VARIANT (type);
+ {
+ TREE_TYPE (exp) = TYPE_MAIN_VARIANT (type);
+ if (init)
+ TREE_TYPE (init) = TYPE_MAIN_VARIANT (itype);
+ }
if (init && TREE_TYPE (init) == NULL_TREE)
{
/* Handle bad initializers like:
@@ -1139,7 +1157,8 @@ expand_aggr_init (exp, init, alias_this)
init && comptypes (TREE_TYPE (init), TREE_TYPE (exp), 1));
TREE_READONLY (exp) = was_const;
TREE_TYPE (exp) = type;
- if (init) TREE_TYPE (init) = itype;
+ if (init)
+ TREE_TYPE (init) = itype;
return;
}
@@ -1187,6 +1206,7 @@ expand_default_init (binfo, true_exp, exp, type, init, alias_this, flags)
else if (TREE_CODE (init) == INDIRECT_REF && TREE_HAS_CONSTRUCTOR (init))
{
rval = convert_for_initialization (exp, type, init, 0, 0, 0, 0);
+ TREE_USED (rval) = 1;
expand_expr_stmt (rval);
return;
}
@@ -1392,7 +1412,7 @@ expand_aggr_init_1 (binfo, true_exp, exp, init, alias_this, flags)
separately from the object being initialized. */
if (TREE_CODE (init) == TARGET_EXPR)
{
- if (init_type == type)
+ if (TYPE_MAIN_VARIANT (init_type) == TYPE_MAIN_VARIANT (type))
{
if (TREE_CODE (exp) == VAR_DECL
|| TREE_CODE (exp) == RESULT_DECL)
@@ -1790,7 +1810,7 @@ get_type_value (name)
else
return NULL_TREE;
}
-
+
/* This code could just as well go in `class.c', but is placed here for
modularity. */
@@ -1966,12 +1986,6 @@ build_offset_ref (cname, name)
name, NULL_TREE, 1);
#endif
- fnfields = lookup_fnfields (TYPE_BINFO (type), name, 1);
- fields = lookup_field (type, name, 0, 0);
-
- if (fields == error_mark_node || fnfields == error_mark_node)
- return error_mark_node;
-
if (current_class_type == 0
|| get_base_distance (type, current_class_type, 0, &basetypes) == -1)
{
@@ -1986,6 +2000,12 @@ build_offset_ref (cname, name)
else
decl = C_C_D;
+ fnfields = lookup_fnfields (basetypes, name, 1);
+ fields = lookup_field (basetypes, name, 0, 0);
+
+ if (fields == error_mark_node || fnfields == error_mark_node)
+ return error_mark_node;
+
/* A lot of this logic is now handled in lookup_field and
lookup_fnfield. */
if (fnfields)
@@ -2018,7 +2038,6 @@ build_offset_ref (cname, name)
{
extern int flag_save_memoized_contexts;
- /* This does not handle access checking yet. */
if (DECL_CHAIN (t) == NULL_TREE || dtor)
{
enum access_type access;
@@ -2245,7 +2264,7 @@ resolve_offset_ref (exp)
basetype = DECL_CONTEXT (member);
base = current_class_decl;
-
+
if (get_base_distance (basetype, TREE_TYPE (TREE_TYPE (base)), 0, &basetype_path) < 0)
{
error_not_base_type (basetype, TREE_TYPE (TREE_TYPE (base)));
@@ -2287,9 +2306,11 @@ resolve_offset_ref (exp)
{
basetype = TYPE_OFFSET_BASETYPE (TREE_TYPE (member));
addr = convert_pointer_to (basetype, addr);
- member = convert (ptr_type_node, build_unary_op (ADDR_EXPR, member, 0));
+ member = convert (ptrdiff_type_node,
+ build_unary_op (ADDR_EXPR, member, 0));
return build1 (INDIRECT_REF, type,
- build (PLUS_EXPR, ptr_type_node, addr, member));
+ build (PLUS_EXPR, build_pointer_type (type),
+ addr, member));
}
else if (TYPE_PTRMEMFUNC_P (TREE_TYPE (member)))
{
@@ -2398,12 +2419,12 @@ is_friend (type, supplicant)
{
if (type == supplicant)
return 1;
-
+
list = CLASSTYPE_FRIEND_CLASSES (TREE_TYPE (TYPE_NAME (type)));
for (; list ; list = TREE_CHAIN (list))
if (supplicant == TREE_VALUE (list))
return 1;
- }
+ }
{
tree context = declp ? DECL_CLASS_CONTEXT (supplicant)
@@ -2993,7 +3014,7 @@ build_new (placement, decl, init, use_global_new)
pedwarn ("const and volatile types cannot be created with operator new");
type = true_type = TYPE_MAIN_VARIANT (type);
}
-
+
/* If our base type is an array, then make sure we know how many elements
it has. */
while (TREE_CODE (true_type) == ARRAY_TYPE)
@@ -3137,14 +3158,14 @@ build_new (placement, decl, init, use_global_new)
{
tree tmp = rval;
-
+
if (TREE_CODE (TREE_TYPE (tmp)) == POINTER_TYPE)
tmp = build_indirect_ref (tmp, NULL_PTR);
-
+
newrval = build_method_call (tmp, constructor_name_full (true_type),
init, NULL_TREE, flags);
}
-
+
if (newrval)
{
rval = newrval;
@@ -3261,7 +3282,7 @@ build_new (placement, decl, init, use_global_new)
build_tree_list (NULL_TREE, rval))));
}
- return save_expr (rval);
+ return rval;
}
/* `expand_vec_init' performs initialization of a vector of aggregate
diff --git a/gnu/usr.bin/cc/cc1plus/lex.c b/gnu/usr.bin/cc/cc1plus/lex.c
index 5edf659..c3189f7 100644
--- a/gnu/usr.bin/cc/cc1plus/lex.c
+++ b/gnu/usr.bin/cc/cc1plus/lex.c
@@ -75,6 +75,12 @@ void yyerror ();
struct obstack inline_text_obstack;
static char *inline_text_firstobj;
+/* This obstack is used to hold information about methods to be
+ synthesized. It should go away when synthesized methods are handled
+ properly (i.e. only when needed). */
+struct obstack synth_obstack;
+static char *synth_firstobj;
+
int end_of_file;
/* Pending language change.
@@ -166,7 +172,7 @@ make_pointer_declarator (type_quals, target)
We return an ADDR_EXPR whose "contents" are TARGET
and whose type is the modifier list. */
-
+
tree
make_reference_declarator (type_quals, target)
tree type_quals, target;
@@ -564,6 +570,8 @@ init_lex ()
init_error ();
gcc_obstack_init (&inline_text_obstack);
inline_text_firstobj = (char *) obstack_alloc (&inline_text_obstack, 0);
+ gcc_obstack_init (&synth_obstack);
+ synth_firstobj = (char *) obstack_alloc (&synth_obstack, 0);
/* Start it at 0, because check_newline is called at the very beginning
and will increment it to 1. */
@@ -905,7 +913,7 @@ print_parse_statistics ()
int i;
int maxlen = REDUCE_LENGTH;
unsigned *sorted;
-
+
if (reduce_count[-1] == 0)
return;
@@ -960,15 +968,6 @@ set_yydebug (value)
#endif
}
-#ifdef SPEW_DEBUG
-const char *
-debug_yytranslate (value)
- int value;
-{
- return yytname[YYTRANSLATE (value)];
-}
-
-#endif
/* Functions and data structures for #pragma interface.
@@ -1007,7 +1006,7 @@ extract_interface_info ()
if (flag_alt_external_templates)
{
struct tinst_level *til = tinst_for_decl ();
-
+
if (til)
fileinfo = get_time_identifier (til->file);
}
@@ -1095,30 +1094,72 @@ set_vardecl_interface_info (prev, vars)
void
do_pending_inlines ()
{
- struct pending_inline *prev = 0, *tail;
struct pending_inline *t;
/* Oops, we're still dealing with the last batch. */
if (yychar == PRE_PARSED_FUNCTION_DECL)
return;
-
+
/* Reverse the pending inline functions, since
they were cons'd instead of appended. */
-
- for (t = pending_inlines; t; t = tail)
- {
- t->deja_vu = 1;
- tail = t->next;
- t->next = prev;
- prev = t;
- }
- /* Reset to zero so that if the inline functions we are currently
- processing define inline functions of their own, that is handled
- correctly. ??? This hasn't been checked in a while. */
- pending_inlines = 0;
-
+ {
+ struct pending_inline *prev = 0, *tail, *bottom = 0;
+ t = pending_inlines;
+ pending_inlines = 0;
+
+ for (; t; t = tail)
+ {
+ tail = t->next;
+ t->next = prev;
+ t->deja_vu = 1;
+ prev = t;
+ }
+
+ /* This kludge should go away when synthesized methods are handled
+ properly, i.e. only when needed. */
+ for (t = prev; t; t = t->next)
+ {
+ if (t->lineno <= 0)
+ {
+ tree f = t->fndecl;
+ DECL_PENDING_INLINE_INFO (f) = 0;
+ interface_unknown = t->interface == 1;
+ interface_only = t->interface == 0;
+ switch (- t->lineno)
+ {
+ case 0: case 1:
+ build_dtor (f); break;
+ case 2:
+ build_default_constructor (f); break;
+ case 3: case 4:
+ build_copy_constructor (f); break;
+ case 5: case 6:
+ build_assign_ref (f); break;
+ default:
+ ;
+ }
+ if (tail)
+ tail->next = t->next;
+ else
+ prev = t->next;
+ if (! bottom)
+ bottom = t;
+ }
+ else
+ tail = t;
+ }
+ if (bottom)
+ {
+ obstack_free (&synth_obstack, bottom);
+ extract_interface_info ();
+ }
+ t = prev;
+ }
+
+ if (t == 0)
+ return;
+
/* Now start processing the first inline function. */
- t = prev;
my_friendly_assert ((t->parm_vec == NULL_TREE) == (t->bindings == NULL_TREE),
226);
if (t->parm_vec)
@@ -1440,7 +1481,7 @@ store_pending_inline (decl, t)
char *free_to = t->buf;
t->buf = (char *) obstack_copy (&permanent_obstack, t->buf,
t->len + 1);
- t = (struct pending_inline *) obstack_copy (&permanent_obstack,
+ t = (struct pending_inline *) obstack_copy (&permanent_obstack,
(char *)t, sizeof (*t));
obstack_free (&inline_text_obstack, free_to);
}
@@ -1550,7 +1591,7 @@ reinit_parse_for_block (yychar, obstackp, is_template)
}
else
c = getch ();
-
+
while (c != EOF)
{
int this_lineno = lineno;
@@ -1660,8 +1701,8 @@ reinit_parse_for_block (yychar, obstackp, is_template)
When KIND == 6, build default operator = (X&). */
tree
-cons_up_default_function (type, name, fields, kind)
- tree type, name, fields;
+cons_up_default_function (type, name, kind)
+ tree type, name;
int kind;
{
extern tree void_list_node;
@@ -1685,14 +1726,6 @@ cons_up_default_function (type, name, fields, kind)
case 2:
/* Default constructor. */
args = void_list_node;
- {
- if (declspecs)
- declspecs = decl_tree_cons (NULL_TREE,
- ridpointers [(int) RID_INLINE],
- declspecs);
- else
- declspecs = build_decl_list (NULL_TREE, ridpointers [(int) RID_INLINE]);
- }
break;
case 3:
@@ -1700,16 +1733,12 @@ cons_up_default_function (type, name, fields, kind)
/* Fall through... */
case 4:
/* According to ARM $12.8, the default copy ctor will be declared, but
- not defined, unless it's needed. So we mark this as `inline'; that
- way, if it's never used it won't be emitted. */
- declspecs = build_decl_list (NULL_TREE, ridpointers [(int) RID_INLINE]);
-
+ not defined, unless it's needed. */
argtype = build_reference_type (type);
args = tree_cons (NULL_TREE,
build_tree_list (hash_tree_chain (argtype, NULL_TREE),
get_identifier ("_ctor_arg")),
void_list_node);
- default_copy_constructor_body (&func_buf, &func_len, type, fields);
break;
case 5:
@@ -1717,11 +1746,7 @@ cons_up_default_function (type, name, fields, kind)
/* Fall through... */
case 6:
retref = 1;
- declspecs =
- decl_tree_cons (NULL_TREE, name,
- decl_tree_cons (NULL_TREE,
- ridpointers [(int) RID_INLINE],
- NULL_TREE));
+ declspecs = build_decl_list (NULL_TREE, name);
name = ansi_opname [(int) MODIFY_EXPR];
@@ -1730,19 +1755,14 @@ cons_up_default_function (type, name, fields, kind)
build_tree_list (hash_tree_chain (argtype, NULL_TREE),
get_identifier ("_ctor_arg")),
void_list_node);
- default_assign_ref_body (&func_buf, &func_len, type, fields);
break;
default:
my_friendly_abort (59);
}
- if (!func_buf)
- {
- func_len = 2;
- func_buf = obstack_alloc (&inline_text_obstack, func_len);
- strcpy (func_buf, "{}");
- }
+ declspecs = decl_tree_cons (NULL_TREE, ridpointers [(int) RID_INLINE],
+ declspecs);
TREE_PARMLIST (args) = 1;
@@ -1750,53 +1770,28 @@ cons_up_default_function (type, name, fields, kind)
tree declarator = build_parse_node (CALL_EXPR, name, args, NULL_TREE);
if (retref)
declarator = build_parse_node (ADDR_EXPR, declarator);
-
- fn = start_method (declspecs, declarator, NULL_TREE);
+
+ fn = grokfield (declarator, declspecs, NULL_TREE, NULL_TREE, NULL_TREE);
}
-
+
if (fn == void_type_node)
return fn;
- current_base_init_list = NULL_TREE;
- current_member_init_list = NULL_TREE;
+ if (CLASSTYPE_TEMPLATE_INSTANTIATION (type))
+ SET_DECL_IMPLICIT_INSTANTIATION (fn);
+ /* This kludge should go away when synthesized methods are handled
+ properly, i.e. only when needed. */
{
struct pending_inline *t;
-
- t = (struct pending_inline *) obstack_alloc (&inline_text_obstack,
- sizeof (struct pending_inline));
- t->lineno = lineno;
-
-#if 1
- t->filename = input_filename;
-#else /* This breaks; why? */
-#define MGMSG "(synthetic code at) "
- t->filename = obstack_alloc (&inline_text_obstack,
- strlen (input_filename) + sizeof (MGMSG) + 1);
- strcpy (t->filename, MGMSG);
- strcat (t->filename, input_filename);
-#endif
- t->token = YYEMPTY;
- t->token_value = 0;
- t->buf = func_buf;
- t->len = func_len;
- t->can_free = 1;
- t->deja_vu = 0;
- if (interface_unknown && processing_template_defn && flag_external_templates && ! DECL_IN_SYSTEM_HEADER (fn))
- warn_if_unknown_interface ();
+ t = (struct pending_inline *)
+ obstack_alloc (&synth_obstack, sizeof (struct pending_inline));
+ t->lineno = -kind;
+ t->can_free = 0;
t->interface = (interface_unknown ? 1 : (interface_only ? 0 : 2));
store_pending_inline (fn, t);
- if (interface_unknown)
- TREE_PUBLIC (fn) = 0;
- else
- {
- TREE_PUBLIC (fn) = 1;
- DECL_EXTERNAL (fn) = interface_only;
- }
}
- finish_method (fn);
-
#ifdef DEBUG_DEFAULT_FUNCTIONS
{ char *fn_type = NULL;
tree t = name;
@@ -1818,14 +1813,13 @@ cons_up_default_function (type, name, fields, kind)
}
#endif /* DEBUG_DEFAULT_FUNCTIONS */
- DECL_CLASS_CONTEXT (fn) = TYPE_MAIN_VARIANT (type);
-
/* Show that this function was generated by the compiler. */
SET_DECL_ARTIFICIAL (fn);
-
+
return fn;
}
+#if 0
/* Used by default_copy_constructor_body. For the anonymous union
in TYPE, return the member that is at least as large as the rest
of the members, so we can copy it. */
@@ -1908,7 +1902,7 @@ default_assign_ref_body (bufp, lenp, type, fields)
}
else
tbuf = "{}";
-
+
*lenp = strlen (tbuf);
*bufp = obstack_alloc (&inline_text_obstack, *lenp + 1);
strcpy (*bufp, tbuf);
@@ -2171,6 +2165,7 @@ default_copy_constructor_body (bufp, lenp, type, fields)
strcpy (*bufp, prologue.object_base);
strcat (*bufp, "{}");
}
+#endif
/* Heuristic to tell whether the user is missing a semicolon
after a struct or enum declaration. Emit an error message
@@ -2182,17 +2177,17 @@ check_for_missing_semicolon (type)
if (yychar < 0)
yychar = yylex ();
- if (yychar > 255
- && yychar != SCSPEC
- && yychar != IDENTIFIER
- && yychar != TYPENAME)
+ if ((yychar > 255
+ && yychar != SCSPEC
+ && yychar != IDENTIFIER
+ && yychar != TYPENAME)
+ || end_of_file)
{
if (ANON_AGGRNAME_P (TYPE_IDENTIFIER (type)))
error ("semicolon missing after %s declaration",
TREE_CODE (type) == ENUMERAL_TYPE ? "enum" : "struct");
else
- error ("semicolon missing after declaration of `%s'",
- TYPE_NAME_STRING (type));
+ cp_error ("semicolon missing after declaration of `%T'", type);
shadow_tag (build_tree_list (0, type));
}
/* Could probably also hack cases where class { ... } f (); appears. */
@@ -2756,7 +2751,7 @@ linenum:
strcpy (input_filename, TREE_STRING_POINTER (yylval.ttype));
lineno = l;
GNU_xref_file (input_filename);
-
+
if (main_input_filename == 0)
{
struct impl_files *ifiles = impl_file_chain;
@@ -2875,7 +2870,7 @@ linenum:
if (c_header_level && --c_header_level == 0)
{
if (entering_c_header)
- warning ("Badly nested C headers from preprocessor");
+ warning ("badly nested C headers from preprocessor");
--pending_lang_change;
}
if (flag_cadillac)
@@ -3163,7 +3158,7 @@ do_identifier (token)
&& TYPE_BEING_DEFINED (current_class_type)
&& ! IDENTIFIER_CLASS_VALUE (token))
pushdecl_class_level (id);
-
+
if (!id || id == error_mark_node)
{
if (id == error_mark_node && current_class_type != NULL_TREE)
@@ -3259,7 +3254,7 @@ struct try_type
char long_long_flag;
};
-struct try_type type_sequence[] =
+struct try_type type_sequence[] =
{
{ &integer_type_node, 0, 0, 0},
{ &unsigned_type_node, 1, 0, 0},
@@ -3446,7 +3441,7 @@ real_yylex ()
{
/* We are looking at a string. Complain
if the token before the string is no `extern'.
-
+
Could cheat some memory by placing this string
on the temporary_, instead of the saveable_
obstack. */
@@ -3960,8 +3955,8 @@ real_yylex ()
<< (i * HOST_BITS_PER_CHAR));
low |= (HOST_WIDE_INT) parts[i] << (i * HOST_BITS_PER_CHAR);
}
-
-
+
+
yylval.ttype = build_int_2 (low, high);
TREE_TYPE (yylval.ttype) = long_long_unsigned_type_node;
@@ -3988,7 +3983,7 @@ real_yylex ()
if (flag_traditional && type == long_unsigned_type_node
&& !spec_unsigned)
type = long_integer_type_node;
-
+
if (type == 0)
{
type = long_long_integer_type_node;
@@ -4023,7 +4018,7 @@ real_yylex ()
if (!flag_traditional && type == long_unsigned_type_node
&& !spec_unsigned)
type = long_integer_type_node;
-
+
if (other_type != 0 && other_type != type)
{
if (flag_traditional)
@@ -4203,12 +4198,12 @@ real_yylex ()
|| ((result >> (num_bits - 1)) & 1) == 0)
yylval.ttype
= build_int_2 (result & ((unsigned HOST_WIDE_INT) ~0
- >> (HOST_BITS_PER_INT - num_bits)),
+ >> (HOST_BITS_PER_WIDE_INT - num_bits)),
0);
else
yylval.ttype
= build_int_2 (result | ~((unsigned HOST_WIDE_INT) ~0
- >> (HOST_BITS_PER_INT - num_bits)),
+ >> (HOST_BITS_PER_WIDE_INT - num_bits)),
-1);
if (num_chars<=1)
TREE_TYPE (yylval.ttype) = char_type_node;
diff --git a/gnu/usr.bin/cc/cc1plus/lex.h b/gnu/usr.bin/cc/cc1plus/lex.h
index 3da4635..291b9cd 100644
--- a/gnu/usr.bin/cc/cc1plus/lex.h
+++ b/gnu/usr.bin/cc/cc1plus/lex.h
@@ -58,14 +58,16 @@ enum rid
RID_VOLATILE,
RID_FRIEND,
RID_VIRTUAL,
+ RID_SIGNED,
+ RID_AUTO,
+ RID_MUTABLE,
+
+ /* This is where grokdeclarator ends its search when setting the specbits. */
+
RID_PUBLIC,
RID_PRIVATE,
RID_PROTECTED,
- RID_SIGNED,
RID_EXCEPTION,
- RID_RAISES,
- RID_AUTO,
- RID_MUTABLE,
RID_TEMPLATE,
RID_SIGNATURE,
/* Before adding enough to get up to 64, the RIDBIT_* macros
@@ -76,6 +78,7 @@ enum rid
#define NORID RID_UNUSED
#define RID_FIRST_MODIFIER RID_EXTERN
+#define RID_LAST_MODIFIER RID_MUTABLE
/* The type that can represent all values of RIDBIT. */
/* We assume that we can stick in at least 32 bits into this. */
diff --git a/gnu/usr.bin/cc/cc1plus/method.c b/gnu/usr.bin/cc/cc1plus/method.c
index f64a16a..e7fbdad 100644
--- a/gnu/usr.bin/cc/cc1plus/method.c
+++ b/gnu/usr.bin/cc/cc1plus/method.c
@@ -4,7 +4,7 @@
Contributed by Michael Tiemann (tiemann@cygnus.com)
This file is part of GNU CC.
-
+
GNU CC is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
@@ -313,6 +313,7 @@ flush_repeats (type)
OB_PUTC ('_');
}
+static int numeric_outputed_need_bar;
static void build_overload_identifier ();
static void
@@ -463,9 +464,9 @@ build_overload_identifier (name)
icat (nparms);
for (i = 0; i < nparms; i++)
{
- tree parm = TREE_VEC_ELT (parmlist, i);
+ tree parm = TREE_VALUE (TREE_VEC_ELT (parmlist, i));
tree arg = TREE_VEC_ELT (arglist, i);
- if (TREE_CODE (parm) == IDENTIFIER_NODE)
+ if (TREE_CODE (parm) == TYPE_DECL)
{
/* This parameter is a type. */
OB_PUTC ('Z');
@@ -476,11 +477,17 @@ build_overload_identifier (name)
/* It's a PARM_DECL. */
build_overload_name (TREE_TYPE (parm), 0, 0);
build_overload_value (parm, arg);
+ numeric_outputed_need_bar = 1;
}
}
}
else
{
+ if (numeric_outputed_need_bar)
+ {
+ OB_PUTC ('_');
+ numeric_outputed_need_bar = 0;
+ }
icat (IDENTIFIER_LENGTH (name));
OB_PUTID (name);
}
@@ -507,6 +514,7 @@ build_overload_name (parmtypes, begin, end)
tree parmtype;
if (begin) OB_INIT ();
+ numeric_outputed_need_bar = 0;
if ((just_one = (TREE_CODE (parmtypes) != TREE_LIST)))
{
@@ -772,6 +780,7 @@ build_overload_name (parmtypes, begin, end)
icat (i);
if (i > 9)
OB_PUTC ('_');
+ numeric_outputed_need_bar = 0;
build_overload_nested_name (TYPE_NAME (parmtype));
}
else
@@ -817,6 +826,18 @@ build_overload_name (parmtypes, begin, end)
if (end) OB_FINISH ();
return (char *)obstack_base (&scratch_obstack);
}
+
+tree
+build_static_name (basetype, name)
+ tree basetype, name;
+{
+ char *basename = build_overload_name (basetype, 1, 1);
+ char *buf = (char *) alloca (IDENTIFIER_LENGTH (name)
+ + sizeof (STATIC_NAME_FORMAT)
+ + strlen (basename));
+ sprintf (buf, STATIC_NAME_FORMAT, basename, IDENTIFIER_POINTER (name));
+ return get_identifier (buf);
+}
/* Generate an identifier that encodes the (ANSI) exception TYPE. */
@@ -852,18 +873,17 @@ build_decl_overload (dname, parms, for_method)
/* member operators new and delete look like methods at this point. */
if (! for_method && parms != NULL_TREE && TREE_CODE (parms) == TREE_LIST)
{
- if (TREE_VALUE (parms) == sizetype
- && TREE_CHAIN (parms) == void_list_node)
+ if (dname == ansi_opname[(int) DELETE_EXPR])
+ return get_identifier ("__builtin_delete");
+ else if (dname == ansi_opname[(int) VEC_DELETE_EXPR])
+ return get_identifier ("__builtin_vec_delete");
+ else if (TREE_CHAIN (parms) == void_list_node)
{
if (dname == ansi_opname[(int) NEW_EXPR])
return get_identifier ("__builtin_new");
else if (dname == ansi_opname[(int) VEC_NEW_EXPR])
return get_identifier ("__builtin_vec_new");
}
- else if (dname == ansi_opname[(int) DELETE_EXPR])
- return get_identifier ("__builtin_delete");
- else if (dname == ansi_opname[(int) VEC_DELETE_EXPR])
- return get_identifier ("__builtin_vec_delete");
}
OB_INIT ();
@@ -1461,11 +1481,13 @@ hack_identifier (value, name, yychar)
if (really_overloaded_fn (value))
{
tree t = get_first_fn (value);
- while (t)
+ for (; t; t = DECL_CHAIN (t))
{
+ if (TREE_CODE (t) == TEMPLATE_DECL)
+ continue;
+
assemble_external (t);
TREE_USED (t) = 1;
- t = DECL_CHAIN (t);
}
}
else if (TREE_CODE (value) == TREE_LIST)
@@ -1843,10 +1865,10 @@ emit_thunk (thunk_fndecl)
else
entry_parm = gen_rtx (MEM, TYPE_MODE (passed_type),
gen_rtx (PLUS, Pmode,
- internal_arg_pointer,
+ internal_arg_pointer,
offset_rtx));
}
-
+
this_rtx = entry_parm;
}
@@ -1946,3 +1968,204 @@ emit_thunk (thunk_fndecl)
decl_printable_name = save_decl_printable_name;
current_function_decl = 0;
}
+
+/* Code for synthesizing methods which have default semantics defined. */
+
+void
+build_default_constructor (fndecl)
+ tree fndecl;
+{
+ start_function (NULL_TREE, fndecl, NULL_TREE, 1);
+ store_parm_decls ();
+ setup_vtbl_ptr ();
+ finish_function (lineno, 0);
+}
+
+/* For the anonymous union in TYPE, return the member that is at least as
+ large as the rest of the members, so we can copy it. */
+static tree
+largest_union_member (type)
+ tree type;
+{
+ tree f, type_size = TYPE_SIZE (type);
+
+ for (f = TYPE_FIELDS (type); f; f = TREE_CHAIN (f))
+ if (simple_cst_equal (DECL_SIZE (f), type_size))
+ return f;
+
+ /* We should always find one. */
+ my_friendly_abort (323);
+ return NULL_TREE;
+}
+
+/* Generate code for default X(X&) constructor. */
+void
+build_copy_constructor (fndecl)
+ tree fndecl;
+{
+ tree parm = TREE_CHAIN (DECL_ARGUMENTS (fndecl));
+ tree t;
+
+ start_function (NULL_TREE, fndecl, NULL_TREE, 1);
+ store_parm_decls ();
+ clear_last_expr ();
+ push_momentary ();
+
+ if (TYPE_USES_VIRTUAL_BASECLASSES (current_class_type))
+ parm = TREE_CHAIN (parm);
+ parm = convert_from_reference (parm);
+
+ if (! TYPE_HAS_COMPLEX_INIT_REF (current_class_type))
+ {
+ t = build (INIT_EXPR, void_type_node, C_C_D, parm);
+ TREE_SIDE_EFFECTS (t) = 1;
+ cplus_expand_expr_stmt (t);
+ }
+ else
+ {
+ tree fields = TYPE_FIELDS (current_class_type);
+ int n_bases = CLASSTYPE_N_BASECLASSES (current_class_type);
+ tree binfos = TYPE_BINFO_BASETYPES (current_class_type);
+ int i;
+
+ for (t = CLASSTYPE_VBASECLASSES (current_class_type); t;
+ t = TREE_CHAIN (t))
+ {
+ tree basetype = BINFO_TYPE (t);
+ tree p = convert (build_reference_type (basetype), parm);
+ p = convert_from_reference (p);
+ current_base_init_list = tree_cons (TYPE_NESTED_NAME (basetype),
+ p, current_base_init_list);
+ }
+
+ for (i = 0; i < n_bases; ++i)
+ {
+ tree p, basetype = TREE_VEC_ELT (binfos, i);
+ if (TREE_VIA_VIRTUAL (basetype))
+ continue;
+
+ basetype = BINFO_TYPE (basetype);
+ p = convert (build_reference_type (basetype), parm);
+ p = convert_from_reference (p);
+ current_base_init_list = tree_cons (TYPE_NESTED_NAME (basetype),
+ p, current_base_init_list);
+ }
+ for (; fields; fields = TREE_CHAIN (fields))
+ {
+ tree name, init, t;
+ if (TREE_CODE (fields) != FIELD_DECL)
+ continue;
+ if (DECL_NAME (fields))
+ {
+ if (VFIELD_NAME_P (DECL_NAME (fields)))
+ continue;
+ if (VBASE_NAME_P (DECL_NAME (fields)))
+ continue;
+
+ /* True for duplicate members. */
+ if (IDENTIFIER_CLASS_VALUE (DECL_NAME (fields)) != fields)
+ continue;
+ }
+ else if ((t = TREE_TYPE (fields)) != NULL_TREE
+ && TREE_CODE (t) == UNION_TYPE
+ && ANON_AGGRNAME_P (TYPE_IDENTIFIER (t))
+ && TYPE_FIELDS (t) != NULL_TREE)
+ fields = largest_union_member (t);
+ else
+ continue;
+
+ init = build (COMPONENT_REF, TREE_TYPE (fields), parm, fields);
+ init = build_tree_list (NULL_TREE, init);
+
+ current_member_init_list
+ = tree_cons (DECL_NAME (fields), init, current_member_init_list);
+ }
+ current_member_init_list = nreverse (current_member_init_list);
+ setup_vtbl_ptr ();
+ }
+
+ pop_momentary ();
+ finish_function (lineno, 0);
+}
+
+void
+build_assign_ref (fndecl)
+ tree fndecl;
+{
+ tree parm = TREE_CHAIN (DECL_ARGUMENTS (fndecl));
+
+ start_function (NULL_TREE, fndecl, NULL_TREE, 1);
+ store_parm_decls ();
+ push_momentary ();
+
+ parm = convert_from_reference (parm);
+
+ if (! TYPE_HAS_COMPLEX_ASSIGN_REF (current_class_type))
+ {
+ tree t = build (MODIFY_EXPR, void_type_node, C_C_D, parm);
+ TREE_SIDE_EFFECTS (t) = 1;
+ cplus_expand_expr_stmt (t);
+ }
+ else
+ {
+ tree fields = TYPE_FIELDS (current_class_type);
+ int n_bases = CLASSTYPE_N_BASECLASSES (current_class_type);
+ tree binfos = TYPE_BINFO_BASETYPES (current_class_type);
+ int i;
+
+ for (i = 0; i < n_bases; ++i)
+ {
+ tree basetype = BINFO_TYPE (TREE_VEC_ELT (binfos, i));
+ if (TYPE_HAS_ASSIGN_REF (basetype))
+ {
+ tree p = convert (build_reference_type (basetype), parm);
+ p = convert_from_reference (p);
+ p = build_member_call (TYPE_NESTED_NAME (basetype),
+ ansi_opname [MODIFY_EXPR],
+ build_tree_list (NULL_TREE, p));
+ expand_expr_stmt (p);
+ }
+ }
+ for (; fields; fields = TREE_CHAIN (fields))
+ {
+ tree comp, init, t;
+ if (TREE_CODE (fields) != FIELD_DECL)
+ continue;
+ if (DECL_NAME (fields))
+ {
+ if (VFIELD_NAME_P (DECL_NAME (fields)))
+ continue;
+ if (VBASE_NAME_P (DECL_NAME (fields)))
+ continue;
+
+ /* True for duplicate members. */
+ if (IDENTIFIER_CLASS_VALUE (DECL_NAME (fields)) != fields)
+ continue;
+ }
+ else if ((t = TREE_TYPE (fields)) != NULL_TREE
+ && TREE_CODE (t) == UNION_TYPE
+ && ANON_AGGRNAME_P (TYPE_IDENTIFIER (t))
+ && TYPE_FIELDS (t) != NULL_TREE)
+ fields = largest_union_member (t);
+ else
+ continue;
+
+ comp = build (COMPONENT_REF, TREE_TYPE (fields), C_C_D, fields);
+ init = build (COMPONENT_REF, TREE_TYPE (fields), parm, fields);
+
+ expand_expr_stmt (build_modify_expr (comp, NOP_EXPR, init));
+ }
+ }
+ c_expand_return (C_C_D);
+ pop_momentary ();
+ finish_function (lineno, 0);
+}
+
+void
+build_dtor (fndecl)
+ tree fndecl;
+{
+ start_function (NULL_TREE, fndecl, NULL_TREE, 1);
+ store_parm_decls ();
+ finish_function (lineno, 0);
+}
diff --git a/gnu/usr.bin/cc/cc1plus/parse.c b/gnu/usr.bin/cc/cc1plus/parse.c
index fb8c2e15..3f717b8 100644
--- a/gnu/usr.bin/cc/cc1plus/parse.c
+++ b/gnu/usr.bin/cc/cc1plus/parse.c
@@ -150,7 +150,7 @@ empty_parms ()
#line 108 "parse.y"
typedef union {long itype; tree ttype; char *strtype; enum tree_code code; } YYSTYPE;
-#line 276 "parse.y"
+#line 277 "parse.y"
/* List of types and structure classes of the current declaration. */
static tree current_declspecs;
@@ -190,11 +190,11 @@ typedef
-#define YYFINAL 1346
+#define YYFINAL 1350
#define YYFLAG -32768
#define YYNTBASE 106
-#define YYTRANSLATE(x) ((unsigned)(x) <= 336 ? yytranslate[x] : 336)
+#define YYTRANSLATE(x) ((unsigned)(x) <= 336 ? yytranslate[x] : 338)
static const char yytranslate[] = { 0,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
@@ -237,408 +237,411 @@ static const char yytranslate[] = { 0,
static const short yyprhs[] = { 0,
0, 1, 3, 4, 7, 10, 11, 12, 14, 16,
17, 20, 22, 24, 26, 28, 34, 39, 43, 48,
- 53, 55, 56, 62, 64, 68, 71, 76, 78, 82,
- 84, 88, 89, 95, 96, 102, 103, 109, 110, 116,
- 120, 124, 131, 139, 144, 148, 152, 154, 156, 158,
- 160, 162, 165, 169, 173, 177, 181, 184, 187, 190,
- 193, 196, 198, 202, 207, 211, 217, 222, 226, 230,
- 233, 237, 241, 244, 246, 253, 258, 262, 266, 269,
- 272, 274, 278, 283, 286, 290, 291, 292, 294, 298,
- 301, 305, 307, 312, 315, 320, 323, 328, 331, 333,
- 335, 337, 339, 341, 343, 345, 347, 351, 355, 360,
- 365, 369, 374, 379, 380, 382, 386, 388, 390, 391,
- 398, 399, 401, 402, 405, 407, 409, 411, 413, 415,
- 417, 419, 421, 425, 427, 431, 432, 434, 436, 437,
- 446, 448, 451, 456, 461, 463, 467, 471, 475, 479,
- 481, 483, 485, 486, 490, 493, 496, 499, 502, 505,
- 508, 513, 516, 521, 524, 528, 532, 537, 542, 548,
- 554, 561, 564, 569, 575, 579, 583, 587, 589, 593,
- 596, 600, 605, 607, 610, 616, 618, 623, 628, 633,
- 635, 639, 643, 647, 651, 655, 659, 663, 667, 671,
- 675, 679, 683, 687, 691, 695, 699, 703, 707, 711,
- 717, 721, 725, 727, 730, 734, 736, 738, 740, 742,
- 744, 746, 748, 751, 754, 756, 758, 760, 762, 764,
- 766, 768, 772, 776, 777, 782, 783, 790, 793, 798,
- 801, 804, 806, 811, 813, 821, 829, 837, 845, 850,
- 855, 858, 861, 863, 868, 871, 874, 877, 883, 887,
- 893, 897, 902, 909, 911, 914, 916, 919, 921, 923,
- 925, 928, 929, 932, 935, 939, 943, 947, 951, 955,
- 958, 961, 963, 965, 967, 970, 973, 976, 979, 981,
- 983, 985, 987, 990, 993, 997, 1001, 1006, 1008, 1011,
- 1014, 1016, 1018, 1021, 1024, 1026, 1029, 1032, 1036, 1038,
- 1041, 1043, 1045, 1047, 1052, 1057, 1062, 1067, 1069, 1071,
- 1073, 1075, 1079, 1081, 1085, 1087, 1091, 1092, 1097, 1098,
- 1106, 1111, 1112, 1120, 1125, 1126, 1134, 1139, 1140, 1148,
- 1153, 1154, 1156, 1158, 1161, 1168, 1170, 1174, 1175, 1177,
- 1182, 1189, 1194, 1196, 1198, 1200, 1202, 1204, 1208, 1210,
- 1213, 1217, 1222, 1224, 1226, 1230, 1235, 1242, 1246, 1252,
- 1253, 1261, 1266, 1267, 1274, 1278, 1281, 1284, 1289, 1291,
- 1292, 1294, 1295, 1297, 1299, 1302, 1305, 1308, 1311, 1315,
- 1318, 1321, 1324, 1328, 1332, 1334, 1337, 1338, 1339, 1343,
- 1347, 1350, 1352, 1354, 1355, 1357, 1360, 1362, 1366, 1368,
- 1371, 1373, 1378, 1383, 1385, 1387, 1390, 1393, 1395, 1396,
- 1398, 1403, 1407, 1409, 1412, 1415, 1418, 1421, 1424, 1427,
- 1430, 1433, 1438, 1441, 1443, 1449, 1453, 1454, 1456, 1460,
- 1461, 1463, 1467, 1469, 1471, 1473, 1475, 1480, 1487, 1492,
- 1497, 1504, 1509, 1513, 1518, 1525, 1530, 1535, 1542, 1547,
- 1551, 1553, 1557, 1559, 1563, 1566, 1568, 1575, 1576, 1579,
- 1581, 1584, 1585, 1588, 1592, 1596, 1599, 1602, 1606, 1608,
- 1610, 1612, 1615, 1621, 1627, 1631, 1637, 1642, 1646, 1650,
- 1653, 1655, 1659, 1663, 1666, 1669, 1673, 1675, 1679, 1683,
- 1686, 1689, 1693, 1695, 1701, 1707, 1711, 1717, 1721, 1725,
- 1730, 1734, 1737, 1740, 1742, 1745, 1750, 1755, 1758, 1760,
- 1762, 1764, 1767, 1770, 1773, 1775, 1778, 1780, 1783, 1786,
- 1790, 1792, 1796, 1799, 1803, 1806, 1809, 1813, 1815, 1819,
- 1824, 1828, 1831, 1834, 1836, 1840, 1843, 1846, 1848, 1851,
- 1855, 1857, 1861, 1863, 1869, 1873, 1878, 1882, 1887, 1890,
- 1893, 1897, 1900, 1902, 1904, 1907, 1910, 1913, 1914, 1915,
- 1917, 1919, 1922, 1926, 1928, 1931, 1935, 1941, 1948, 1954,
- 1955, 1956, 1963, 1965, 1968, 1970, 1972, 1974, 1977, 1978,
- 1983, 1985, 1986, 1987, 1994, 1995, 1996, 2004, 2005, 2006,
- 2007, 2018, 2019, 2020, 2021, 2032, 2033, 2041, 2042, 2048,
- 2049, 2057, 2058, 2063, 2066, 2069, 2072, 2076, 2083, 2092,
- 2103, 2116, 2121, 2125, 2128, 2131, 2133, 2135, 2136, 2137,
- 2145, 2147, 2150, 2153, 2154, 2155, 2161, 2163, 2165, 2169,
- 2173, 2176, 2179, 2183, 2188, 2193, 2197, 2202, 2209, 2216,
- 2217, 2219, 2220, 2222, 2224, 2225, 2227, 2229, 2233, 2238,
- 2240, 2244, 2245, 2247, 2249, 2251, 2254, 2257, 2260, 2262,
- 2264, 2267, 2270, 2273, 2276, 2278, 2282, 2285, 2290, 2293,
- 2298, 2301, 2304, 2307, 2310, 2313, 2316, 2318, 2321, 2323,
- 2325, 2326, 2327, 2329, 2330, 2335, 2337, 2339, 2343, 2344,
- 2348, 2352, 2356, 2358, 2361, 2364, 2367, 2370, 2373, 2376,
- 2379, 2382, 2385, 2388, 2391, 2394, 2397, 2400, 2403, 2406,
- 2409, 2412, 2415, 2418, 2421, 2424, 2427, 2431, 2434, 2437,
- 2440, 2443, 2447, 2450, 2453, 2458, 2463, 2467
+ 53, 55, 56, 62, 64, 68, 70, 73, 75, 79,
+ 81, 85, 87, 91, 92, 98, 99, 105, 106, 112,
+ 113, 119, 123, 127, 134, 142, 147, 151, 155, 157,
+ 159, 161, 163, 165, 168, 172, 176, 180, 184, 187,
+ 190, 193, 196, 199, 201, 205, 210, 214, 220, 225,
+ 229, 233, 236, 240, 244, 247, 249, 256, 261, 265,
+ 269, 272, 275, 277, 281, 286, 289, 293, 294, 295,
+ 297, 301, 304, 308, 310, 315, 318, 323, 326, 331,
+ 334, 336, 338, 340, 342, 344, 346, 348, 350, 354,
+ 358, 363, 368, 372, 377, 381, 386, 387, 389, 393,
+ 395, 397, 398, 405, 406, 408, 409, 412, 414, 416,
+ 418, 420, 422, 424, 426, 428, 432, 434, 438, 439,
+ 441, 443, 444, 453, 455, 458, 463, 468, 470, 474,
+ 478, 482, 486, 488, 490, 492, 493, 497, 500, 503,
+ 506, 509, 512, 515, 520, 523, 528, 531, 535, 539,
+ 544, 549, 555, 561, 568, 571, 576, 582, 586, 590,
+ 594, 596, 600, 603, 607, 612, 614, 617, 623, 625,
+ 630, 635, 640, 642, 646, 650, 654, 658, 662, 666,
+ 670, 674, 678, 682, 686, 690, 694, 698, 702, 706,
+ 710, 714, 718, 724, 728, 732, 734, 737, 741, 743,
+ 745, 747, 749, 751, 753, 755, 758, 761, 763, 765,
+ 767, 769, 771, 773, 775, 779, 783, 784, 789, 790,
+ 797, 800, 805, 808, 811, 813, 818, 820, 828, 836,
+ 844, 852, 857, 862, 865, 868, 870, 875, 878, 881,
+ 884, 890, 894, 900, 904, 909, 916, 918, 921, 923,
+ 926, 928, 930, 932, 935, 936, 939, 942, 946, 950,
+ 954, 958, 962, 965, 968, 970, 972, 974, 977, 980,
+ 983, 986, 988, 990, 992, 994, 997, 1000, 1004, 1008,
+ 1013, 1015, 1018, 1021, 1023, 1025, 1028, 1031, 1033, 1036,
+ 1039, 1043, 1045, 1048, 1050, 1052, 1054, 1059, 1064, 1069,
+ 1074, 1076, 1078, 1080, 1082, 1086, 1088, 1092, 1094, 1098,
+ 1099, 1104, 1105, 1113, 1118, 1119, 1127, 1132, 1133, 1141,
+ 1146, 1147, 1155, 1160, 1161, 1163, 1165, 1168, 1175, 1177,
+ 1181, 1182, 1184, 1189, 1196, 1201, 1203, 1205, 1207, 1209,
+ 1211, 1215, 1217, 1220, 1224, 1229, 1231, 1233, 1237, 1242,
+ 1249, 1253, 1259, 1260, 1268, 1273, 1274, 1281, 1285, 1288,
+ 1291, 1296, 1298, 1299, 1301, 1302, 1304, 1306, 1309, 1312,
+ 1315, 1318, 1322, 1325, 1328, 1331, 1335, 1339, 1341, 1344,
+ 1345, 1346, 1350, 1354, 1357, 1359, 1361, 1362, 1364, 1367,
+ 1369, 1373, 1375, 1378, 1380, 1385, 1390, 1392, 1394, 1397,
+ 1400, 1402, 1403, 1405, 1410, 1414, 1416, 1419, 1422, 1425,
+ 1428, 1431, 1434, 1437, 1440, 1445, 1448, 1450, 1456, 1460,
+ 1461, 1463, 1467, 1468, 1470, 1474, 1476, 1478, 1480, 1482,
+ 1487, 1494, 1499, 1504, 1511, 1516, 1520, 1525, 1532, 1537,
+ 1542, 1549, 1554, 1558, 1560, 1564, 1566, 1570, 1573, 1575,
+ 1582, 1583, 1586, 1588, 1591, 1592, 1595, 1599, 1603, 1606,
+ 1609, 1613, 1615, 1617, 1619, 1622, 1628, 1634, 1638, 1644,
+ 1649, 1653, 1657, 1660, 1662, 1666, 1670, 1673, 1676, 1680,
+ 1682, 1686, 1690, 1693, 1696, 1700, 1702, 1708, 1714, 1718,
+ 1724, 1728, 1732, 1737, 1741, 1744, 1747, 1749, 1752, 1757,
+ 1762, 1765, 1767, 1769, 1771, 1774, 1777, 1780, 1782, 1785,
+ 1787, 1790, 1793, 1797, 1799, 1803, 1806, 1810, 1813, 1816,
+ 1820, 1822, 1826, 1831, 1835, 1838, 1841, 1843, 1847, 1850,
+ 1853, 1855, 1858, 1862, 1864, 1868, 1870, 1876, 1880, 1885,
+ 1889, 1894, 1897, 1900, 1904, 1907, 1909, 1911, 1914, 1917,
+ 1920, 1921, 1922, 1924, 1926, 1929, 1933, 1935, 1938, 1942,
+ 1948, 1955, 1961, 1962, 1963, 1970, 1972, 1975, 1977, 1979,
+ 1981, 1984, 1985, 1990, 1992, 1993, 1994, 2001, 2002, 2003,
+ 2011, 2012, 2013, 2014, 2025, 2026, 2027, 2028, 2039, 2040,
+ 2048, 2049, 2055, 2056, 2064, 2065, 2070, 2073, 2076, 2079,
+ 2083, 2090, 2099, 2110, 2123, 2128, 2132, 2135, 2138, 2140,
+ 2142, 2143, 2144, 2152, 2154, 2157, 2160, 2161, 2162, 2168,
+ 2170, 2172, 2176, 2180, 2183, 2186, 2189, 2193, 2198, 2203,
+ 2207, 2212, 2219, 2226, 2227, 2229, 2230, 2232, 2234, 2235,
+ 2237, 2239, 2243, 2248, 2250, 2254, 2255, 2257, 2259, 2261,
+ 2264, 2267, 2270, 2272, 2274, 2277, 2280, 2283, 2286, 2288,
+ 2292, 2295, 2298, 2303, 2306, 2309, 2312, 2315, 2318, 2321,
+ 2323, 2326, 2328, 2332, 2334, 2336, 2337, 2338, 2340, 2341,
+ 2346, 2348, 2350, 2354, 2355, 2359, 2363, 2367, 2369, 2372,
+ 2375, 2378, 2381, 2384, 2387, 2390, 2393, 2396, 2399, 2402,
+ 2405, 2408, 2411, 2414, 2417, 2420, 2423, 2426, 2429, 2432,
+ 2435, 2438, 2442, 2445, 2448, 2451, 2454, 2458, 2461, 2464,
+ 2469, 2474, 2478
};
static const short yyrhs[] = { -1,
107, 0, 0, 108, 112, 0, 107, 112, 0, 0,
- 0, 25, 0, 26, 0, 0, 113, 114, 0, 129,
- 0, 128, 0, 122, 0, 120, 0, 111, 88, 179,
+ 0, 25, 0, 26, 0, 0, 113, 114, 0, 130,
+ 0, 129, 0, 123, 0, 121, 0, 111, 88, 180,
102, 56, 0, 115, 54, 107, 103, 0, 115, 54,
- 103, 0, 115, 109, 129, 110, 0, 115, 109, 128,
+ 103, 0, 115, 109, 130, 110, 0, 115, 109, 129,
110, 0, 95, 0, 0, 45, 69, 117, 118, 70,
- 0, 119, 0, 118, 55, 119, 0, 220, 138, 0,
- 220, 140, 60, 232, 0, 327, 0, 39, 121, 56,
- 0, 3, 0, 121, 55, 3, 0, 0, 116, 222,
- 54, 123, 56, 0, 0, 116, 223, 54, 124, 56,
- 0, 0, 116, 222, 60, 125, 56, 0, 0, 116,
- 223, 60, 126, 56, 0, 116, 222, 56, 0, 116,
- 223, 56, 0, 116, 258, 330, 197, 206, 127, 0,
- 116, 186, 183, 330, 197, 206, 127, 0, 116, 189,
- 258, 127, 0, 116, 1, 103, 0, 116, 1, 56,
- 0, 54, 0, 60, 0, 56, 0, 58, 0, 23,
- 0, 196, 56, 0, 189, 195, 56, 0, 189, 258,
- 56, 0, 186, 194, 56, 0, 186, 183, 56, 0,
- 189, 56, 0, 141, 56, 0, 186, 56, 0, 1,
- 56, 0, 1, 103, 0, 56, 0, 130, 134, 282,
- 0, 130, 133, 134, 282, 0, 130, 180, 282, 0,
- 130, 133, 56, 180, 282, 0, 130, 133, 180, 282,
- 0, 186, 183, 1, 0, 189, 258, 1, 0, 258,
- 1, 0, 186, 183, 330, 0, 189, 258, 330, 0,
- 258, 330, 0, 94, 0, 186, 88, 322, 102, 250,
- 330, 0, 186, 44, 250, 330, 0, 186, 183, 330,
- 0, 189, 258, 330, 0, 258, 330, 0, 23, 3,
- 0, 132, 0, 132, 58, 213, 0, 132, 88, 160,
- 102, 0, 132, 44, 0, 60, 135, 136, 0, 0,
- 0, 137, 0, 136, 55, 137, 0, 136, 1, 0,
- 88, 160, 102, 0, 44, 0, 139, 88, 160, 102,
- 0, 139, 44, 0, 268, 88, 160, 102, 0, 268,
- 44, 0, 262, 88, 160, 102, 0, 262, 44, 0,
- 3, 0, 4, 0, 53, 0, 3, 0, 53, 0,
- 99, 0, 98, 0, 100, 0, 45, 221, 149, 0,
- 45, 186, 183, 0, 5, 45, 221, 149, 0, 5,
- 45, 186, 183, 0, 143, 144, 149, 0, 53, 69,
- 145, 70, 0, 4, 69, 145, 70, 0, 0, 146,
- 0, 145, 55, 146, 0, 185, 0, 168, 0, 0,
- 97, 229, 148, 234, 235, 103, 0, 0, 147, 0,
- 0, 147, 150, 0, 74, 0, 73, 0, 81, 0,
- 82, 0, 104, 0, 159, 0, 168, 0, 44, 0,
- 88, 152, 102, 0, 44, 0, 88, 156, 102, 0,
- 0, 156, 0, 1, 0, 0, 311, 183, 330, 197,
- 206, 58, 157, 213, 0, 152, 0, 54, 103, 0,
- 54, 279, 276, 103, 0, 54, 279, 1, 103, 0,
- 289, 0, 168, 55, 168, 0, 168, 55, 1, 0,
- 159, 55, 168, 0, 159, 55, 1, 0, 168, 0,
- 159, 0, 173, 0, 0, 33, 162, 166, 0, 75,
- 166, 0, 65, 166, 0, 83, 166, 0, 151, 166,
- 0, 62, 138, 0, 11, 161, 0, 11, 88, 185,
- 102, 0, 28, 161, 0, 28, 88, 185, 102, 0,
- 176, 249, 0, 176, 249, 164, 0, 176, 163, 249,
- 0, 176, 163, 249, 164, 0, 176, 88, 185, 102,
- 0, 176, 88, 185, 102, 164, 0, 176, 163, 88,
- 185, 102, 0, 176, 163, 88, 185, 102, 164, 0,
- 177, 166, 0, 177, 89, 105, 166, 0, 177, 89,
- 152, 105, 166, 0, 88, 160, 102, 0, 54, 160,
- 103, 0, 88, 160, 102, 0, 44, 0, 88, 192,
- 102, 0, 58, 213, 0, 88, 185, 102, 0, 165,
- 88, 185, 102, 0, 167, 0, 165, 167, 0, 165,
- 54, 214, 218, 103, 0, 161, 0, 29, 88, 152,
- 102, 0, 30, 88, 152, 102, 0, 30, 88, 4,
- 102, 0, 166, 0, 168, 78, 168, 0, 168, 79,
- 168, 0, 168, 73, 168, 0, 168, 74, 168, 0,
- 168, 75, 168, 0, 168, 76, 168, 0, 168, 77,
- 168, 0, 168, 71, 168, 0, 168, 72, 168, 0,
- 168, 68, 168, 0, 168, 69, 168, 0, 168, 70,
- 168, 0, 168, 67, 168, 0, 168, 66, 168, 0,
- 168, 65, 168, 0, 168, 63, 168, 0, 168, 64,
- 168, 0, 168, 62, 168, 0, 168, 61, 168, 0,
- 168, 59, 317, 60, 168, 0, 168, 58, 168, 0,
- 168, 57, 168, 0, 92, 0, 92, 168, 0, 83,
- 328, 138, 0, 335, 0, 3, 0, 53, 0, 169,
- 0, 4, 0, 169, 0, 262, 0, 75, 171, 0,
- 65, 171, 0, 260, 0, 169, 0, 262, 0, 169,
- 0, 8, 0, 178, 0, 179, 0, 88, 152, 102,
- 0, 88, 1, 102, 0, 0, 88, 174, 283, 102,
- 0, 0, 173, 88, 160, 102, 175, 150, 0, 173,
- 44, 0, 173, 89, 152, 105, 0, 173, 81, 0,
- 173, 82, 0, 40, 0, 7, 88, 160, 102, 0,
- 264, 0, 47, 69, 185, 70, 88, 152, 102, 0,
- 48, 69, 185, 70, 88, 152, 102, 0, 49, 69,
- 185, 70, 88, 152, 102, 0, 50, 69, 185, 70,
- 88, 152, 102, 0, 46, 88, 152, 102, 0, 46,
- 88, 185, 102, 0, 271, 3, 0, 271, 335, 0,
- 263, 0, 263, 88, 160, 102, 0, 263, 44, 0,
- 181, 170, 0, 181, 261, 0, 181, 170, 88, 160,
- 102, 0, 181, 170, 44, 0, 181, 261, 88, 160,
- 102, 0, 181, 261, 44, 0, 181, 83, 6, 44,
- 0, 181, 6, 51, 83, 6, 44, 0, 38, 0,
- 271, 38, 0, 37, 0, 271, 177, 0, 42, 0,
- 43, 0, 9, 0, 179, 9, 0, 0, 173, 87,
- 0, 173, 86, 0, 192, 183, 56, 0, 186, 183,
- 56, 0, 192, 194, 56, 0, 186, 194, 56, 0,
- 189, 195, 56, 0, 186, 56, 0, 189, 56, 0,
- 254, 0, 258, 0, 44, 0, 184, 44, 0, 190,
- 274, 0, 251, 274, 0, 192, 274, 0, 190, 0,
- 251, 0, 190, 0, 187, 0, 189, 192, 0, 192,
- 188, 0, 189, 192, 188, 0, 189, 192, 191, 0,
- 189, 192, 191, 188, 0, 5, 0, 188, 193, 0,
- 188, 5, 0, 251, 0, 5, 0, 189, 7, 0,
- 189, 5, 0, 192, 0, 251, 192, 0, 192, 191,
- 0, 251, 192, 191, 0, 193, 0, 191, 193, 0,
- 215, 0, 6, 0, 268, 0, 27, 88, 152, 102,
- 0, 27, 88, 185, 102, 0, 31, 88, 152, 102,
- 0, 31, 88, 185, 102, 0, 6, 0, 7, 0,
- 215, 0, 198, 0, 194, 55, 200, 0, 202, 0,
- 195, 55, 200, 0, 204, 0, 196, 55, 200, 0,
- 0, 111, 88, 179, 102, 0, 0, 183, 330, 197,
- 206, 58, 199, 213, 0, 183, 330, 197, 206, 0,
- 0, 183, 330, 197, 206, 58, 201, 213, 0, 183,
- 330, 197, 206, 0, 0, 258, 330, 197, 206, 58,
- 203, 213, 0, 258, 330, 197, 206, 0, 0, 258,
- 330, 197, 206, 58, 205, 213, 0, 258, 330, 197,
- 206, 0, 0, 207, 0, 208, 0, 207, 208, 0,
- 32, 88, 88, 209, 102, 102, 0, 210, 0, 209,
- 55, 210, 0, 0, 211, 0, 211, 88, 3, 102,
- 0, 211, 88, 3, 55, 160, 102, 0, 211, 88,
- 160, 102, 0, 138, 0, 5, 0, 6, 0, 7,
- 0, 138, 0, 212, 55, 138, 0, 168, 0, 54,
- 103, 0, 54, 214, 103, 0, 54, 214, 55, 103,
- 0, 1, 0, 213, 0, 214, 55, 213, 0, 89,
- 168, 105, 213, 0, 214, 55, 19, 168, 60, 213,
- 0, 138, 60, 213, 0, 214, 55, 138, 60, 213,
- 0, 0, 12, 138, 54, 216, 247, 219, 103, 0,
- 12, 138, 54, 103, 0, 0, 12, 54, 217, 247,
- 219, 103, 0, 12, 54, 103, 0, 12, 138, 0,
- 12, 269, 0, 228, 234, 235, 103, 0, 228, 0,
- 0, 55, 0, 0, 55, 0, 35, 0, 220, 5,
- 0, 220, 6, 0, 220, 7, 0, 220, 35, 0,
- 220, 143, 56, 0, 220, 138, 0, 220, 269, 0,
- 220, 142, 0, 220, 143, 54, 0, 220, 143, 60,
- 0, 221, 0, 220, 140, 0, 0, 0, 222, 224,
- 229, 0, 223, 225, 229, 0, 220, 54, 0, 227,
- 0, 226, 0, 0, 60, 0, 60, 230, 0, 231,
- 0, 230, 55, 231, 0, 232, 0, 233, 232, 0,
- 268, 0, 31, 88, 152, 102, 0, 31, 88, 185,
- 102, 0, 36, 0, 5, 0, 233, 36, 0, 233,
- 5, 0, 54, 0, 0, 236, 0, 235, 36, 60,
- 236, 0, 235, 36, 60, 0, 237, 0, 236, 237,
- 0, 236, 56, 0, 238, 56, 0, 238, 103, 0,
- 131, 60, 0, 131, 54, 0, 186, 239, 0, 189,
- 240, 0, 258, 330, 197, 206, 0, 60, 168, 0,
- 1, 0, 186, 88, 322, 102, 250, 0, 186, 44,
- 250, 0, 0, 241, 0, 239, 55, 242, 0, 0,
- 244, 0, 240, 55, 246, 0, 243, 0, 244, 0,
- 245, 0, 246, 0, 254, 330, 197, 206, 0, 254,
- 330, 197, 206, 58, 213, 0, 4, 60, 168, 206,
- 0, 258, 330, 197, 206, 0, 258, 330, 197, 206,
- 58, 213, 0, 3, 60, 168, 206, 0, 60, 168,
- 206, 0, 254, 330, 197, 206, 0, 254, 330, 197,
- 206, 58, 213, 0, 4, 60, 168, 206, 0, 258,
- 330, 197, 206, 0, 258, 330, 197, 206, 58, 213,
- 0, 3, 60, 168, 206, 0, 60, 168, 206, 0,
- 248, 0, 247, 55, 248, 0, 138, 0, 138, 58,
- 168, 0, 311, 272, 0, 311, 0, 88, 185, 102,
- 89, 152, 105, 0, 0, 250, 7, 0, 7, 0,
- 251, 7, 0, 0, 253, 152, 0, 75, 251, 254,
- 0, 65, 251, 254, 0, 75, 254, 0, 65, 254,
- 0, 270, 250, 254, 0, 257, 0, 265, 0, 256,
- 0, 266, 265, 0, 257, 88, 160, 102, 250, 0,
- 257, 88, 322, 102, 250, 0, 257, 44, 250, 0,
- 257, 88, 1, 102, 250, 0, 257, 89, 252, 105,
- 0, 257, 89, 105, 0, 88, 254, 102, 0, 266,
- 265, 0, 265, 0, 75, 251, 258, 0, 65, 251,
- 258, 0, 75, 258, 0, 65, 258, 0, 270, 250,
- 258, 0, 172, 0, 75, 251, 258, 0, 65, 251,
- 258, 0, 75, 259, 0, 65, 259, 0, 270, 250,
- 258, 0, 260, 0, 172, 88, 160, 102, 250, 0,
- 172, 88, 322, 102, 250, 0, 172, 44, 250, 0,
- 172, 88, 1, 102, 250, 0, 88, 171, 102, 0,
- 88, 259, 102, 0, 172, 89, 252, 105, 0, 172,
- 89, 105, 0, 266, 170, 0, 266, 169, 0, 262,
- 0, 271, 262, 0, 192, 88, 160, 102, 0, 192,
- 88, 171, 102, 0, 192, 184, 0, 4, 0, 142,
- 0, 267, 0, 266, 267, 0, 4, 51, 0, 142,
- 51, 0, 255, 0, 271, 255, 0, 256, 0, 271,
- 255, 0, 266, 75, 0, 271, 266, 75, 0, 51,
- 0, 75, 250, 272, 0, 75, 250, 0, 65, 250,
- 272, 0, 65, 250, 0, 270, 250, 0, 270, 250,
- 272, 0, 273, 0, 89, 152, 105, 0, 273, 89,
- 252, 105, 0, 75, 251, 274, 0, 75, 274, 0,
- 75, 251, 0, 75, 0, 65, 251, 274, 0, 65,
- 274, 0, 65, 251, 0, 65, 0, 270, 250, 0,
- 270, 250, 274, 0, 275, 0, 88, 274, 102, 0,
- 85, 0, 275, 88, 322, 102, 250, 0, 275, 44,
- 250, 0, 275, 89, 252, 105, 0, 275, 89, 105,
- 0, 88, 323, 102, 250, 0, 165, 250, 0, 184,
- 250, 0, 89, 252, 105, 0, 89, 105, 0, 288,
- 0, 277, 0, 276, 288, 0, 276, 277, 0, 1,
- 56, 0, 0, 0, 280, 0, 281, 0, 280, 281,
- 0, 34, 212, 56, 0, 283, 0, 1, 283, 0,
- 54, 278, 103, 0, 54, 278, 279, 276, 103, 0,
- 54, 278, 279, 276, 1, 103, 0, 54, 278, 279,
- 1, 103, 0, 0, 0, 13, 285, 278, 154, 286,
- 287, 0, 283, 0, 278, 289, 0, 283, 0, 289,
- 0, 182, 0, 152, 56, 0, 0, 284, 14, 290,
- 287, 0, 284, 0, 0, 0, 15, 291, 278, 154,
- 292, 158, 0, 0, 0, 16, 293, 287, 15, 294,
- 153, 56, 0, 0, 0, 0, 314, 295, 278, 155,
- 56, 296, 317, 102, 297, 158, 0, 0, 0, 0,
- 315, 298, 278, 155, 56, 299, 317, 102, 300, 158,
- 0, 0, 18, 278, 88, 156, 102, 301, 287, 0,
- 0, 19, 168, 60, 302, 288, 0, 0, 19, 168,
- 10, 168, 60, 303, 288, 0, 0, 20, 60, 304,
- 288, 0, 21, 56, 0, 22, 56, 0, 23, 56,
- 0, 23, 152, 56, 0, 111, 316, 88, 179, 102,
- 56, 0, 111, 316, 88, 179, 60, 318, 102, 56,
- 0, 111, 316, 88, 179, 60, 318, 60, 318, 102,
- 56, 0, 111, 316, 88, 179, 60, 318, 60, 318,
- 60, 321, 102, 56, 0, 24, 75, 152, 56, 0,
- 24, 138, 56, 0, 313, 288, 0, 313, 103, 0,
- 56, 0, 305, 0, 0, 0, 90, 54, 278, 306,
- 308, 307, 309, 0, 103, 0, 276, 103, 0, 1,
- 103, 0, 0, 0, 309, 91, 310, 312, 283, 0,
- 190, 0, 251, 0, 88, 10, 102, 0, 88, 327,
- 102, 0, 3, 60, 0, 53, 60, 0, 17, 88,
- 56, 0, 17, 88, 152, 56, 0, 17, 88, 54,
- 103, 0, 17, 88, 182, 0, 17, 88, 1, 56,
- 0, 17, 88, 54, 278, 276, 103, 0, 17, 88,
- 54, 278, 1, 103, 0, 0, 7, 0, 0, 152,
- 0, 1, 0, 0, 319, 0, 320, 0, 319, 55,
- 320, 0, 9, 88, 152, 102, 0, 9, 0, 321,
- 55, 9, 0, 0, 323, 0, 185, 0, 324, 0,
- 325, 10, 0, 324, 10, 0, 185, 10, 0, 10,
- 0, 93, 0, 324, 93, 0, 185, 93, 0, 324,
- 60, 0, 185, 60, 0, 326, 0, 327, 58, 213,
- 0, 325, 327, 0, 325, 327, 58, 213, 0, 325,
- 329, 0, 325, 329, 58, 213, 0, 324, 55, 0,
- 185, 55, 0, 187, 183, 0, 190, 183, 0, 192,
- 183, 0, 187, 274, 0, 187, 0, 189, 258, 0,
- 326, 0, 185, 0, 0, 0, 258, 0, 0, 92,
- 88, 332, 102, 0, 185, 0, 331, 0, 332, 55,
- 331, 0, 0, 75, 250, 333, 0, 65, 250, 333,
- 0, 270, 250, 333, 0, 41, 0, 334, 75, 0,
- 334, 76, 0, 334, 77, 0, 334, 73, 0, 334,
- 74, 0, 334, 65, 0, 334, 63, 0, 334, 64,
- 0, 334, 83, 0, 334, 55, 0, 334, 68, 0,
- 334, 69, 0, 334, 70, 0, 334, 67, 0, 334,
- 57, 0, 334, 58, 0, 334, 71, 0, 334, 72,
- 0, 334, 81, 0, 334, 82, 0, 334, 62, 0,
- 334, 61, 0, 334, 104, 0, 334, 59, 60, 0,
- 334, 66, 0, 334, 86, 0, 334, 78, 0, 334,
- 44, 0, 334, 89, 105, 0, 334, 38, 0, 334,
- 37, 0, 334, 38, 89, 105, 0, 334, 37, 89,
- 105, 0, 334, 311, 333, 0, 334, 1, 0
+ 0, 120, 0, 118, 55, 120, 0, 221, 0, 221,
+ 139, 0, 119, 0, 119, 58, 193, 0, 328, 0,
+ 39, 122, 56, 0, 3, 0, 122, 55, 3, 0,
+ 0, 116, 223, 54, 124, 56, 0, 0, 116, 224,
+ 54, 125, 56, 0, 0, 116, 223, 60, 126, 56,
+ 0, 0, 116, 224, 60, 127, 56, 0, 116, 223,
+ 56, 0, 116, 224, 56, 0, 116, 259, 332, 198,
+ 207, 128, 0, 116, 187, 184, 332, 198, 207, 128,
+ 0, 116, 190, 259, 128, 0, 116, 1, 103, 0,
+ 116, 1, 56, 0, 54, 0, 60, 0, 56, 0,
+ 58, 0, 23, 0, 197, 56, 0, 190, 196, 56,
+ 0, 190, 259, 56, 0, 187, 195, 56, 0, 187,
+ 184, 56, 0, 190, 56, 0, 142, 56, 0, 187,
+ 56, 0, 1, 56, 0, 1, 103, 0, 56, 0,
+ 131, 135, 283, 0, 131, 134, 135, 283, 0, 131,
+ 181, 283, 0, 131, 134, 56, 181, 283, 0, 131,
+ 134, 181, 283, 0, 187, 184, 1, 0, 190, 259,
+ 1, 0, 259, 1, 0, 187, 184, 332, 0, 190,
+ 259, 332, 0, 259, 332, 0, 94, 0, 187, 88,
+ 323, 102, 251, 332, 0, 187, 44, 251, 332, 0,
+ 187, 184, 332, 0, 190, 259, 332, 0, 259, 332,
+ 0, 23, 3, 0, 133, 0, 133, 58, 214, 0,
+ 133, 88, 161, 102, 0, 133, 44, 0, 60, 136,
+ 137, 0, 0, 0, 138, 0, 137, 55, 138, 0,
+ 137, 1, 0, 88, 161, 102, 0, 44, 0, 140,
+ 88, 161, 102, 0, 140, 44, 0, 269, 88, 161,
+ 102, 0, 269, 44, 0, 263, 88, 161, 102, 0,
+ 263, 44, 0, 3, 0, 4, 0, 53, 0, 3,
+ 0, 53, 0, 99, 0, 98, 0, 100, 0, 45,
+ 222, 150, 0, 45, 187, 184, 0, 5, 45, 222,
+ 150, 0, 5, 45, 187, 184, 0, 144, 145, 150,
+ 0, 53, 69, 146, 70, 0, 53, 69, 70, 0,
+ 4, 69, 146, 70, 0, 0, 147, 0, 146, 55,
+ 147, 0, 186, 0, 169, 0, 0, 97, 230, 149,
+ 235, 236, 103, 0, 0, 148, 0, 0, 148, 151,
+ 0, 74, 0, 73, 0, 81, 0, 82, 0, 104,
+ 0, 160, 0, 169, 0, 44, 0, 88, 153, 102,
+ 0, 44, 0, 88, 157, 102, 0, 0, 157, 0,
+ 1, 0, 0, 312, 184, 332, 198, 207, 58, 158,
+ 214, 0, 153, 0, 54, 103, 0, 54, 280, 277,
+ 103, 0, 54, 280, 1, 103, 0, 290, 0, 169,
+ 55, 169, 0, 169, 55, 1, 0, 160, 55, 169,
+ 0, 160, 55, 1, 0, 169, 0, 160, 0, 174,
+ 0, 0, 33, 163, 167, 0, 75, 167, 0, 65,
+ 167, 0, 83, 167, 0, 152, 167, 0, 62, 139,
+ 0, 11, 162, 0, 11, 88, 186, 102, 0, 28,
+ 162, 0, 28, 88, 186, 102, 0, 177, 250, 0,
+ 177, 250, 165, 0, 177, 164, 250, 0, 177, 164,
+ 250, 165, 0, 177, 88, 186, 102, 0, 177, 88,
+ 186, 102, 165, 0, 177, 164, 88, 186, 102, 0,
+ 177, 164, 88, 186, 102, 165, 0, 178, 167, 0,
+ 178, 89, 105, 167, 0, 178, 89, 153, 105, 167,
+ 0, 88, 161, 102, 0, 54, 161, 103, 0, 88,
+ 161, 102, 0, 44, 0, 88, 193, 102, 0, 58,
+ 214, 0, 88, 186, 102, 0, 166, 88, 186, 102,
+ 0, 168, 0, 166, 168, 0, 166, 54, 215, 219,
+ 103, 0, 162, 0, 29, 88, 153, 102, 0, 30,
+ 88, 153, 102, 0, 30, 88, 4, 102, 0, 167,
+ 0, 169, 78, 169, 0, 169, 79, 169, 0, 169,
+ 73, 169, 0, 169, 74, 169, 0, 169, 75, 169,
+ 0, 169, 76, 169, 0, 169, 77, 169, 0, 169,
+ 71, 169, 0, 169, 72, 169, 0, 169, 68, 169,
+ 0, 169, 69, 169, 0, 169, 70, 169, 0, 169,
+ 67, 169, 0, 169, 66, 169, 0, 169, 65, 169,
+ 0, 169, 63, 169, 0, 169, 64, 169, 0, 169,
+ 62, 169, 0, 169, 61, 169, 0, 169, 59, 318,
+ 60, 169, 0, 169, 58, 169, 0, 169, 57, 169,
+ 0, 92, 0, 92, 169, 0, 83, 330, 139, 0,
+ 337, 0, 3, 0, 53, 0, 170, 0, 4, 0,
+ 170, 0, 263, 0, 75, 172, 0, 65, 172, 0,
+ 261, 0, 170, 0, 263, 0, 170, 0, 8, 0,
+ 179, 0, 180, 0, 88, 153, 102, 0, 88, 1,
+ 102, 0, 0, 88, 175, 284, 102, 0, 0, 174,
+ 88, 161, 102, 176, 151, 0, 174, 44, 0, 174,
+ 89, 153, 105, 0, 174, 81, 0, 174, 82, 0,
+ 40, 0, 7, 88, 161, 102, 0, 265, 0, 47,
+ 69, 186, 70, 88, 153, 102, 0, 48, 69, 186,
+ 70, 88, 153, 102, 0, 49, 69, 186, 70, 88,
+ 153, 102, 0, 50, 69, 186, 70, 88, 153, 102,
+ 0, 46, 88, 153, 102, 0, 46, 88, 186, 102,
+ 0, 272, 3, 0, 272, 337, 0, 264, 0, 264,
+ 88, 161, 102, 0, 264, 44, 0, 182, 171, 0,
+ 182, 262, 0, 182, 171, 88, 161, 102, 0, 182,
+ 171, 44, 0, 182, 262, 88, 161, 102, 0, 182,
+ 262, 44, 0, 182, 83, 6, 44, 0, 182, 6,
+ 51, 83, 6, 44, 0, 38, 0, 272, 38, 0,
+ 37, 0, 272, 178, 0, 42, 0, 43, 0, 9,
+ 0, 180, 9, 0, 0, 174, 87, 0, 174, 86,
+ 0, 193, 184, 56, 0, 187, 184, 56, 0, 193,
+ 195, 56, 0, 187, 195, 56, 0, 190, 196, 56,
+ 0, 187, 56, 0, 190, 56, 0, 255, 0, 259,
+ 0, 44, 0, 185, 44, 0, 191, 275, 0, 252,
+ 275, 0, 193, 275, 0, 191, 0, 252, 0, 191,
+ 0, 188, 0, 190, 193, 0, 193, 189, 0, 190,
+ 193, 189, 0, 190, 193, 192, 0, 190, 193, 192,
+ 189, 0, 5, 0, 189, 194, 0, 189, 5, 0,
+ 252, 0, 5, 0, 190, 7, 0, 190, 5, 0,
+ 193, 0, 252, 193, 0, 193, 192, 0, 252, 193,
+ 192, 0, 194, 0, 192, 194, 0, 216, 0, 6,
+ 0, 269, 0, 27, 88, 153, 102, 0, 27, 88,
+ 186, 102, 0, 31, 88, 153, 102, 0, 31, 88,
+ 186, 102, 0, 6, 0, 7, 0, 216, 0, 199,
+ 0, 195, 55, 201, 0, 203, 0, 196, 55, 201,
+ 0, 205, 0, 197, 55, 201, 0, 0, 111, 88,
+ 180, 102, 0, 0, 184, 332, 198, 207, 58, 200,
+ 214, 0, 184, 332, 198, 207, 0, 0, 184, 332,
+ 198, 207, 58, 202, 214, 0, 184, 332, 198, 207,
+ 0, 0, 259, 332, 198, 207, 58, 204, 214, 0,
+ 259, 332, 198, 207, 0, 0, 259, 332, 198, 207,
+ 58, 206, 214, 0, 259, 332, 198, 207, 0, 0,
+ 208, 0, 209, 0, 208, 209, 0, 32, 88, 88,
+ 210, 102, 102, 0, 211, 0, 210, 55, 211, 0,
+ 0, 212, 0, 212, 88, 3, 102, 0, 212, 88,
+ 3, 55, 161, 102, 0, 212, 88, 161, 102, 0,
+ 139, 0, 5, 0, 6, 0, 7, 0, 139, 0,
+ 213, 55, 139, 0, 169, 0, 54, 103, 0, 54,
+ 215, 103, 0, 54, 215, 55, 103, 0, 1, 0,
+ 214, 0, 215, 55, 214, 0, 89, 169, 105, 214,
+ 0, 215, 55, 19, 169, 60, 214, 0, 139, 60,
+ 214, 0, 215, 55, 139, 60, 214, 0, 0, 12,
+ 139, 54, 217, 248, 220, 103, 0, 12, 139, 54,
+ 103, 0, 0, 12, 54, 218, 248, 220, 103, 0,
+ 12, 54, 103, 0, 12, 139, 0, 12, 270, 0,
+ 229, 235, 236, 103, 0, 229, 0, 0, 55, 0,
+ 0, 55, 0, 35, 0, 221, 5, 0, 221, 6,
+ 0, 221, 7, 0, 221, 35, 0, 221, 144, 56,
+ 0, 221, 139, 0, 221, 270, 0, 221, 143, 0,
+ 221, 144, 54, 0, 221, 144, 60, 0, 222, 0,
+ 221, 141, 0, 0, 0, 223, 225, 230, 0, 224,
+ 226, 230, 0, 221, 54, 0, 228, 0, 227, 0,
+ 0, 60, 0, 60, 231, 0, 232, 0, 231, 55,
+ 232, 0, 233, 0, 234, 233, 0, 269, 0, 31,
+ 88, 153, 102, 0, 31, 88, 186, 102, 0, 36,
+ 0, 5, 0, 234, 36, 0, 234, 5, 0, 54,
+ 0, 0, 237, 0, 236, 36, 60, 237, 0, 236,
+ 36, 60, 0, 238, 0, 237, 238, 0, 237, 56,
+ 0, 239, 56, 0, 239, 103, 0, 132, 60, 0,
+ 132, 54, 0, 187, 240, 0, 190, 241, 0, 259,
+ 332, 198, 207, 0, 60, 169, 0, 1, 0, 187,
+ 88, 323, 102, 251, 0, 187, 44, 251, 0, 0,
+ 242, 0, 240, 55, 243, 0, 0, 245, 0, 241,
+ 55, 247, 0, 244, 0, 245, 0, 246, 0, 247,
+ 0, 255, 332, 198, 207, 0, 255, 332, 198, 207,
+ 58, 214, 0, 4, 60, 169, 207, 0, 259, 332,
+ 198, 207, 0, 259, 332, 198, 207, 58, 214, 0,
+ 3, 60, 169, 207, 0, 60, 169, 207, 0, 255,
+ 332, 198, 207, 0, 255, 332, 198, 207, 58, 214,
+ 0, 4, 60, 169, 207, 0, 259, 332, 198, 207,
+ 0, 259, 332, 198, 207, 58, 214, 0, 3, 60,
+ 169, 207, 0, 60, 169, 207, 0, 249, 0, 248,
+ 55, 249, 0, 139, 0, 139, 58, 169, 0, 312,
+ 273, 0, 312, 0, 88, 186, 102, 89, 153, 105,
+ 0, 0, 251, 7, 0, 7, 0, 252, 7, 0,
+ 0, 254, 153, 0, 75, 252, 255, 0, 65, 252,
+ 255, 0, 75, 255, 0, 65, 255, 0, 271, 251,
+ 255, 0, 258, 0, 266, 0, 257, 0, 267, 266,
+ 0, 258, 88, 161, 102, 251, 0, 258, 88, 323,
+ 102, 251, 0, 258, 44, 251, 0, 258, 88, 1,
+ 102, 251, 0, 258, 89, 253, 105, 0, 258, 89,
+ 105, 0, 88, 255, 102, 0, 267, 266, 0, 266,
+ 0, 75, 252, 259, 0, 65, 252, 259, 0, 75,
+ 259, 0, 65, 259, 0, 271, 251, 259, 0, 173,
+ 0, 75, 252, 259, 0, 65, 252, 259, 0, 75,
+ 260, 0, 65, 260, 0, 271, 251, 259, 0, 261,
+ 0, 173, 88, 161, 102, 251, 0, 173, 88, 323,
+ 102, 251, 0, 173, 44, 251, 0, 173, 88, 1,
+ 102, 251, 0, 88, 172, 102, 0, 88, 260, 102,
+ 0, 173, 89, 253, 105, 0, 173, 89, 105, 0,
+ 267, 171, 0, 267, 170, 0, 263, 0, 272, 263,
+ 0, 193, 88, 161, 102, 0, 193, 88, 172, 102,
+ 0, 193, 185, 0, 4, 0, 143, 0, 268, 0,
+ 267, 268, 0, 4, 51, 0, 143, 51, 0, 256,
+ 0, 272, 256, 0, 257, 0, 272, 256, 0, 267,
+ 75, 0, 272, 267, 75, 0, 51, 0, 75, 251,
+ 273, 0, 75, 251, 0, 65, 251, 273, 0, 65,
+ 251, 0, 271, 251, 0, 271, 251, 273, 0, 274,
+ 0, 89, 153, 105, 0, 274, 89, 253, 105, 0,
+ 75, 252, 275, 0, 75, 275, 0, 75, 252, 0,
+ 75, 0, 65, 252, 275, 0, 65, 275, 0, 65,
+ 252, 0, 65, 0, 271, 251, 0, 271, 251, 275,
+ 0, 276, 0, 88, 275, 102, 0, 85, 0, 276,
+ 88, 323, 102, 251, 0, 276, 44, 251, 0, 276,
+ 89, 253, 105, 0, 276, 89, 105, 0, 88, 324,
+ 102, 251, 0, 166, 251, 0, 185, 251, 0, 89,
+ 253, 105, 0, 89, 105, 0, 289, 0, 278, 0,
+ 277, 289, 0, 277, 278, 0, 1, 56, 0, 0,
+ 0, 281, 0, 282, 0, 281, 282, 0, 34, 213,
+ 56, 0, 284, 0, 1, 284, 0, 54, 279, 103,
+ 0, 54, 279, 280, 277, 103, 0, 54, 279, 280,
+ 277, 1, 103, 0, 54, 279, 280, 1, 103, 0,
+ 0, 0, 13, 286, 279, 155, 287, 288, 0, 284,
+ 0, 279, 290, 0, 284, 0, 290, 0, 183, 0,
+ 153, 56, 0, 0, 285, 14, 291, 288, 0, 285,
+ 0, 0, 0, 15, 292, 279, 155, 293, 159, 0,
+ 0, 0, 16, 294, 288, 15, 295, 154, 56, 0,
+ 0, 0, 0, 315, 296, 279, 156, 56, 297, 318,
+ 102, 298, 159, 0, 0, 0, 0, 316, 299, 279,
+ 156, 56, 300, 318, 102, 301, 159, 0, 0, 18,
+ 279, 88, 157, 102, 302, 288, 0, 0, 19, 169,
+ 60, 303, 289, 0, 0, 19, 169, 10, 169, 60,
+ 304, 289, 0, 0, 20, 60, 305, 289, 0, 21,
+ 56, 0, 22, 56, 0, 23, 56, 0, 23, 153,
+ 56, 0, 111, 317, 88, 180, 102, 56, 0, 111,
+ 317, 88, 180, 60, 319, 102, 56, 0, 111, 317,
+ 88, 180, 60, 319, 60, 319, 102, 56, 0, 111,
+ 317, 88, 180, 60, 319, 60, 319, 60, 322, 102,
+ 56, 0, 24, 75, 153, 56, 0, 24, 139, 56,
+ 0, 314, 289, 0, 314, 103, 0, 56, 0, 306,
+ 0, 0, 0, 90, 54, 279, 307, 309, 308, 310,
+ 0, 103, 0, 277, 103, 0, 1, 103, 0, 0,
+ 0, 310, 91, 311, 313, 284, 0, 191, 0, 252,
+ 0, 88, 10, 102, 0, 88, 329, 102, 0, 3,
+ 60, 0, 53, 60, 0, 4, 60, 0, 17, 88,
+ 56, 0, 17, 88, 153, 56, 0, 17, 88, 54,
+ 103, 0, 17, 88, 183, 0, 17, 88, 1, 56,
+ 0, 17, 88, 54, 279, 277, 103, 0, 17, 88,
+ 54, 279, 1, 103, 0, 0, 7, 0, 0, 153,
+ 0, 1, 0, 0, 320, 0, 321, 0, 320, 55,
+ 321, 0, 9, 88, 153, 102, 0, 9, 0, 322,
+ 55, 9, 0, 0, 324, 0, 186, 0, 325, 0,
+ 326, 10, 0, 325, 10, 0, 186, 10, 0, 10,
+ 0, 93, 0, 325, 93, 0, 186, 93, 0, 325,
+ 60, 0, 186, 60, 0, 327, 0, 329, 58, 214,
+ 0, 326, 328, 0, 326, 331, 0, 326, 331, 58,
+ 214, 0, 325, 55, 0, 186, 55, 0, 188, 184,
+ 0, 191, 184, 0, 193, 184, 0, 188, 275, 0,
+ 188, 0, 190, 259, 0, 329, 0, 329, 58, 214,
+ 0, 327, 0, 186, 0, 0, 0, 259, 0, 0,
+ 92, 88, 334, 102, 0, 186, 0, 333, 0, 334,
+ 55, 333, 0, 0, 75, 251, 335, 0, 65, 251,
+ 335, 0, 271, 251, 335, 0, 41, 0, 336, 75,
+ 0, 336, 76, 0, 336, 77, 0, 336, 73, 0,
+ 336, 74, 0, 336, 65, 0, 336, 63, 0, 336,
+ 64, 0, 336, 83, 0, 336, 55, 0, 336, 68,
+ 0, 336, 69, 0, 336, 70, 0, 336, 67, 0,
+ 336, 57, 0, 336, 58, 0, 336, 71, 0, 336,
+ 72, 0, 336, 81, 0, 336, 82, 0, 336, 62,
+ 0, 336, 61, 0, 336, 104, 0, 336, 59, 60,
+ 0, 336, 66, 0, 336, 86, 0, 336, 78, 0,
+ 336, 44, 0, 336, 89, 105, 0, 336, 38, 0,
+ 336, 37, 0, 336, 38, 89, 105, 0, 336, 37,
+ 89, 105, 0, 336, 312, 335, 0, 336, 1, 0
};
#endif
#if YYDEBUG != 0
static const short yyrline[] = { 0,
- 291, 292, 306, 308, 309, 313, 318, 322, 324, 327,
- 330, 334, 337, 339, 341, 342, 345, 347, 349, 352,
- 357, 362, 365, 369, 372, 376, 392, 401, 404, 409,
- 411, 415, 421, 421, 424, 424, 427, 427, 442, 442,
- 447, 452, 469, 492, 502, 503, 506, 507, 508, 509,
- 510, 513, 516, 519, 524, 529, 535, 537, 538, 557,
- 558, 559, 562, 576, 589, 592, 595, 598, 600, 602,
- 606, 612, 617, 622, 629, 640, 647, 649, 651, 655,
- 663, 665, 667, 669, 673, 686, 709, 712, 714, 715,
- 718, 724, 730, 732, 734, 736, 739, 743, 749, 751,
- 752, 755, 757, 760, 762, 763, 766, 769, 771, 773,
- 777, 782, 785, 789, 794, 797, 801, 804, 807, 841,
- 857, 860, 864, 867, 871, 873, 875, 877, 879, 883,
- 885, 888, 893, 897, 902, 906, 909, 910, 914, 933,
- 940, 943, 946, 948, 950, 954, 958, 961, 963, 967,
- 970, 973, 982, 985, 988, 990, 992, 994, 1001, 1012,
- 1032, 1034, 1036, 1041, 1043, 1045, 1047, 1049, 1052, 1054,
- 1056, 1059, 1061, 1065, 1071, 1074, 1081, 1084, 1086, 1094,
- 1103, 1109, 1115, 1117, 1119, 1132, 1134, 1136, 1138, 1155,
- 1158, 1160, 1162, 1164, 1166, 1168, 1170, 1172, 1174, 1176,
- 1178, 1180, 1182, 1184, 1186, 1188, 1190, 1192, 1194, 1196,
- 1198, 1200, 1207, 1209, 1226, 1229, 1230, 1231, 1234, 1236,
- 1239, 1241, 1242, 1244, 1248, 1250, 1251, 1256, 1276, 1277,
- 1278, 1280, 1282, 1284, 1292, 1313, 1318, 1325, 1332, 1334,
- 1343, 1348, 1371, 1415, 1416, 1419, 1422, 1425, 1428, 1430,
- 1433, 1472, 1479, 1481, 1483, 1485, 1487, 1489, 1504, 1519,
- 1530, 1542, 1549, 1598, 1600, 1604, 1606, 1610, 1613, 1618,
- 1620, 1624, 1637, 1638, 1644, 1655, 1663, 1669, 1674, 1676,
- 1681, 1688, 1690, 1694, 1698, 1704, 1707, 1709, 1711, 1713,
- 1721, 1723, 1725, 1728, 1730, 1732, 1734, 1739, 1745, 1747,
- 1758, 1761, 1763, 1766, 1781, 1784, 1786, 1788, 1792, 1795,
- 1803, 1804, 1805, 1806, 1810, 1814, 1828, 1846, 1847, 1848,
- 1851, 1853, 1856, 1858, 1861, 1863, 1866, 1869, 1873, 1890,
- 1892, 1910, 1916, 1917, 1923, 1931, 1933, 1942, 1950, 1952,
- 1963, 1966, 1970, 1973, 1977, 1982, 1985, 1989, 1992, 1994,
- 1996, 1998, 2005, 2007, 2008, 2009, 2013, 2016, 2020, 2022,
- 2025, 2028, 2031, 2037, 2040, 2043, 2045, 2047, 2049, 2053,
- 2057, 2061, 2064, 2067, 2071, 2074, 2076, 2080, 2131, 2146,
- 2148, 2151, 2153, 2157, 2158, 2160, 2162, 2164, 2168, 2177,
- 2180, 2182, 2184, 2190, 2192, 2195, 2200, 2203, 2206, 2215,
- 2226, 2231, 2231, 2233, 2236, 2238, 2242, 2244, 2248, 2276,
- 2307, 2309, 2331, 2355, 2357, 2361, 2387, 2396, 2424, 2427,
- 2434, 2445, 2454, 2458, 2471, 2474, 2476, 2481, 2483, 2487,
- 2495, 2499, 2502, 2504, 2515, 2520, 2528, 2531, 2532, 2543,
- 2546, 2547, 2558, 2560, 2563, 2565, 2568, 2573, 2577, 2583,
- 2588, 2592, 2596, 2602, 2606, 2609, 2614, 2618, 2621, 2624,
- 2633, 2635, 2639, 2642, 2647, 2650, 2654, 2663, 2666, 2670,
- 2673, 2681, 2683, 2688, 2691, 2693, 2695, 2697, 2701, 2704,
- 2718, 2721, 2726, 2729, 2731, 2733, 2735, 2737, 2739, 2741,
- 2745, 2751, 2754, 2756, 2758, 2760, 2764, 2767, 2770, 2772,
- 2774, 2776, 2780, 2783, 2786, 2788, 2790, 2792, 2794, 2796,
- 2798, 2802, 2808, 2814, 2816, 2820, 2823, 2825, 2829, 2831,
- 2834, 2836, 2842, 2845, 2859, 2861, 2865, 2867, 2871, 2874,
- 2880, 2886, 2889, 2891, 2893, 2895, 2899, 2903, 2907, 2910,
- 2915, 2918, 2920, 2922, 2924, 2926, 2928, 2930, 2932, 2936,
- 2940, 2944, 2948, 2949, 2951, 2953, 2955, 2957, 2959, 2961,
- 2963, 2965, 2973, 2975, 2976, 2977, 2980, 2987, 2997, 2999,
- 3004, 3006, 3009, 3023, 3026, 3029, 3033, 3037, 3041, 3047,
- 3050, 3054, 3056, 3059, 3065, 3068, 3071, 3074, 3087, 3090,
- 3095, 3101, 3106, 3109, 3114, 3118, 3121, 3127, 3132, 3135,
- 3140, 3149, 3153, 3156, 3162, 3172, 3179, 3185, 3210, 3210,
- 3242, 3242, 3258, 3258, 3262, 3266, 3269, 3274, 3281, 3290,
- 3299, 3308, 3311, 3317, 3319, 3323, 3325, 3328, 3332, 3335,
- 3338, 3346, 3350, 3356, 3358, 3360, 3364, 3366, 3369, 3382,
- 3387, 3395, 3399, 3402, 3404, 3408, 3411, 3413, 3415, 3421,
- 3425, 3429, 3432, 3433, 3439, 3441, 3444, 3446, 3450, 3455,
- 3458, 3468, 3475, 3476, 3483, 3489, 3494, 3498, 3503, 3510,
- 3514, 3518, 3523, 3534, 3548, 3551, 3553, 3555, 3557, 3559,
- 3563, 3565, 3573, 3590, 3592, 3594, 3596, 3598, 3602, 3604,
- 3607, 3629, 3635, 3642, 3645, 3649, 3654, 3656, 3663, 3666,
- 3668, 3670, 3676, 3680, 3683, 3685, 3687, 3689, 3691, 3693,
- 3695, 3697, 3699, 3701, 3703, 3705, 3707, 3709, 3711, 3713,
- 3715, 3717, 3719, 3721, 3723, 3725, 3727, 3729, 3731, 3733,
- 3735, 3737, 3739, 3741, 3743, 3745, 3748, 3750
+ 292, 293, 307, 309, 310, 314, 319, 323, 325, 328,
+ 331, 335, 338, 340, 342, 343, 346, 348, 350, 353,
+ 358, 363, 366, 370, 373, 377, 387, 391, 401, 403,
+ 406, 411, 413, 417, 423, 423, 426, 426, 429, 429,
+ 444, 444, 449, 454, 471, 494, 504, 505, 508, 509,
+ 510, 511, 512, 515, 518, 521, 526, 531, 537, 539,
+ 540, 559, 560, 561, 564, 578, 591, 594, 597, 600,
+ 602, 604, 608, 614, 619, 624, 631, 642, 649, 651,
+ 653, 657, 665, 667, 669, 671, 675, 688, 711, 714,
+ 716, 717, 720, 726, 732, 734, 736, 738, 741, 745,
+ 751, 753, 754, 757, 759, 762, 764, 765, 768, 771,
+ 773, 775, 779, 784, 787, 789, 793, 798, 801, 805,
+ 808, 811, 845, 861, 864, 868, 871, 875, 877, 879,
+ 881, 883, 887, 889, 892, 897, 902, 907, 912, 915,
+ 918, 922, 941, 948, 951, 954, 956, 958, 962, 966,
+ 969, 971, 975, 978, 981, 990, 993, 996, 998, 1000,
+ 1002, 1009, 1020, 1040, 1042, 1044, 1049, 1051, 1053, 1055,
+ 1057, 1060, 1062, 1064, 1067, 1069, 1073, 1079, 1082, 1089,
+ 1092, 1094, 1102, 1111, 1117, 1123, 1125, 1127, 1140, 1142,
+ 1144, 1146, 1163, 1166, 1168, 1170, 1172, 1174, 1176, 1178,
+ 1180, 1182, 1184, 1186, 1188, 1190, 1192, 1194, 1196, 1198,
+ 1200, 1202, 1204, 1206, 1208, 1215, 1217, 1234, 1237, 1238,
+ 1239, 1242, 1244, 1247, 1249, 1250, 1252, 1256, 1258, 1259,
+ 1264, 1284, 1285, 1286, 1288, 1290, 1292, 1300, 1321, 1326,
+ 1333, 1340, 1342, 1351, 1356, 1379, 1423, 1424, 1427, 1430,
+ 1433, 1436, 1438, 1441, 1480, 1487, 1489, 1491, 1493, 1495,
+ 1497, 1512, 1527, 1538, 1550, 1557, 1606, 1608, 1612, 1614,
+ 1618, 1621, 1626, 1628, 1632, 1645, 1646, 1652, 1663, 1671,
+ 1677, 1682, 1684, 1689, 1696, 1698, 1702, 1706, 1712, 1715,
+ 1717, 1719, 1721, 1729, 1731, 1733, 1736, 1738, 1740, 1742,
+ 1747, 1753, 1755, 1766, 1769, 1771, 1774, 1789, 1792, 1794,
+ 1796, 1800, 1803, 1811, 1812, 1813, 1814, 1818, 1822, 1836,
+ 1854, 1855, 1856, 1859, 1861, 1864, 1866, 1869, 1871, 1874,
+ 1877, 1881, 1898, 1900, 1918, 1924, 1925, 1931, 1939, 1941,
+ 1950, 1958, 1960, 1971, 1974, 1978, 1981, 1985, 1990, 1993,
+ 1997, 2000, 2002, 2004, 2006, 2013, 2015, 2016, 2017, 2021,
+ 2024, 2028, 2030, 2033, 2036, 2039, 2045, 2048, 2051, 2053,
+ 2055, 2057, 2061, 2065, 2069, 2072, 2075, 2079, 2082, 2084,
+ 2088, 2139, 2154, 2156, 2159, 2161, 2165, 2166, 2168, 2170,
+ 2172, 2176, 2185, 2188, 2190, 2192, 2198, 2200, 2203, 2208,
+ 2211, 2214, 2223, 2234, 2239, 2239, 2241, 2244, 2246, 2250,
+ 2252, 2256, 2284, 2315, 2317, 2339, 2363, 2365, 2369, 2395,
+ 2404, 2466, 2469, 2476, 2487, 2496, 2500, 2513, 2516, 2518,
+ 2523, 2525, 2529, 2537, 2541, 2544, 2546, 2557, 2562, 2570,
+ 2573, 2574, 2585, 2588, 2589, 2600, 2602, 2605, 2607, 2610,
+ 2615, 2619, 2625, 2630, 2634, 2638, 2644, 2648, 2651, 2656,
+ 2660, 2663, 2666, 2675, 2677, 2681, 2684, 2689, 2692, 2696,
+ 2705, 2708, 2712, 2715, 2723, 2725, 2730, 2733, 2735, 2737,
+ 2739, 2743, 2746, 2760, 2763, 2768, 2771, 2773, 2775, 2777,
+ 2779, 2781, 2783, 2787, 2793, 2796, 2798, 2800, 2802, 2806,
+ 2809, 2812, 2814, 2816, 2818, 2822, 2825, 2828, 2830, 2832,
+ 2834, 2836, 2838, 2840, 2844, 2850, 2856, 2858, 2862, 2865,
+ 2867, 2871, 2873, 2876, 2878, 2884, 2887, 2901, 2903, 2907,
+ 2909, 2913, 2916, 2922, 2928, 2931, 2933, 2935, 2937, 2941,
+ 2945, 2949, 2952, 2957, 2960, 2962, 2964, 2966, 2968, 2970,
+ 2972, 2974, 2978, 2982, 2986, 2990, 2991, 2993, 2995, 2997,
+ 2999, 3001, 3003, 3005, 3007, 3015, 3017, 3018, 3019, 3022,
+ 3029, 3039, 3041, 3046, 3048, 3051, 3065, 3068, 3071, 3075,
+ 3079, 3083, 3089, 3092, 3096, 3098, 3101, 3107, 3110, 3113,
+ 3116, 3129, 3132, 3137, 3143, 3148, 3151, 3156, 3160, 3163,
+ 3169, 3174, 3177, 3182, 3191, 3195, 3198, 3204, 3214, 3221,
+ 3227, 3252, 3252, 3284, 3284, 3300, 3300, 3304, 3308, 3311,
+ 3316, 3323, 3332, 3341, 3350, 3353, 3359, 3361, 3365, 3367,
+ 3370, 3374, 3377, 3380, 3388, 3392, 3398, 3400, 3402, 3406,
+ 3408, 3411, 3424, 3429, 3437, 3439, 3443, 3446, 3448, 3452,
+ 3455, 3457, 3459, 3465, 3469, 3473, 3476, 3477, 3483, 3485,
+ 3488, 3490, 3494, 3499, 3502, 3512, 3519, 3520, 3527, 3533,
+ 3538, 3542, 3547, 3554, 3558, 3562, 3567, 3578, 3592, 3595,
+ 3597, 3599, 3601, 3605, 3607, 3615, 3632, 3634, 3636, 3638,
+ 3640, 3644, 3647, 3651, 3653, 3656, 3678, 3684, 3691, 3694,
+ 3698, 3703, 3705, 3712, 3715, 3717, 3719, 3725, 3729, 3732,
+ 3734, 3736, 3738, 3740, 3742, 3744, 3746, 3748, 3750, 3752,
+ 3754, 3756, 3758, 3760, 3762, 3764, 3766, 3768, 3770, 3772,
+ 3774, 3776, 3778, 3780, 3782, 3784, 3786, 3788, 3790, 3792,
+ 3794, 3797, 3799
};
static const char * const yytname[] = { "$","error","$illegal.","IDENTIFIER",
@@ -656,1437 +659,1389 @@ static const char * const yytname[] = { "$","error","$illegal.","IDENTIFIER",
"ALL","PRE_PARSED_CLASS_DECL","TYPENAME_DEFN","IDENTIFIER_DEFN","PTYPENAME_DEFN",
"END_OF_SAVED_INPUT","')'","'}'","'!'","']'","program","extdefs","@1",".hush_warning",
".warning_ok","asm_keyword","lang_extdef","@2","extdef","extern_lang_string",
-"template_header","@3","template_parm_list","template_parm","overloaddef","ov_identifiers",
-"template_def","@4","@5","@6","@7","fn_tmpl_end","datadef","fndef","fn.def1",
-"fn.def2","return_id","return_init","base_init",".set_base_init","member_init_list",
-"member_init","identifier","notype_identifier","identifier_defn","explicit_instantiation",
-"template_type","template_type_name","tmpl.2","template_arg_list","template_arg",
-"template_instantiate_once","@8","template_instantiation","template_instantiate_some",
-"unop","expr","paren_expr_or_null","paren_cond_or_null","xcond","condition",
-"@9","already_scoped_stmt","nontrivial_exprlist","nonnull_exprlist","unary_expr",
-"@10","new_placement","new_initializer","regcast_or_absdcl","cast_expr","sub_cast_expr",
-"expr_no_commas","notype_unqualified_id","unqualified_id","expr_or_declarator",
-"direct_notype_declarator","primary","@11","@12","new","delete","boolean.literal",
-"string","nodecls","object","decl","declarator","fcast_or_absdcl","type_id",
-"typed_declspecs","typed_declspecs1","reserved_declspecs","declmods","typed_typespecs",
-"reserved_typespecquals","typespec","typespecqual_reserved","initdecls","notype_initdecls",
-"nomods_initdecls","maybeasm","initdcl0","@13","initdcl","@14","notype_initdcl0",
-"@15","nomods_initdcl0","@16","maybe_attribute","attributes","attribute","attribute_list",
-"attrib","any_word","identifiers_or_typenames","init","initlist","structsp",
-"@17","@18","maybecomma","maybecomma_warn","aggr","specialization","named_class_head_sans_basetype",
-"named_class_head_sans_basetype_defn","do_xref","do_xref_defn","named_class_head",
-"unnamed_class_head","class_head","maybe_base_class_list","base_class_list",
-"base_class","base_class.1","base_class_access_list","left_curly","opt.component_decl_list",
-"component_decl_list","component_decl","component_decl_1","components","notype_components",
-"component_declarator0","component_declarator","after_type_component_declarator0",
-"notype_component_declarator0","after_type_component_declarator","notype_component_declarator",
-"enumlist","enumerator","new_type_id","type_quals","nonempty_type_quals","nonmomentary_expr",
-"@19","after_type_declarator","qualified_type_name","nested_type","direct_after_type_declarator",
-"notype_declarator","complex_notype_declarator","complex_direct_notype_declarator",
-"qualified_id","notype_qualified_id","overqualified_id","functional_cast","type_name",
-"nested_name_specifier","nested_name_specifier_1","complete_type_name","complex_type_name",
-"ptr_to_mem","global_scope","new_declarator","direct_new_declarator","absdcl",
-"direct_abstract_declarator","stmts","errstmt",".pushlevel","maybe_label_decls",
-"label_decls","label_decl","compstmt_or_error","compstmt","simple_if","@20",
-"@21","implicitly_scoped_stmt","stmt","simple_stmt","@22","@23","@24","@25",
-"@26","@27","@28","@29","@30","@31","@32","@33","@34","@35","@36","try_block",
-"@37","@38","ansi_try_stmts","handler_seq","@39","type_specifier_seq","handler_args",
-"label_colon","forhead.1","forhead.2","maybe_type_qual","xexpr","asm_operands",
-"nonnull_asm_operands","asm_operand","asm_clobbers","parmlist","complex_parmlist",
-"parms","parms_comma","named_parm","parm","see_typename","bad_parm","maybe_raises",
-"ansi_raise_identifier","ansi_raise_identifiers","conversion_declarator","operator",
-"operator_name",""
+"template_header","@3","template_parm_list","template_type_parm","template_parm",
+"overloaddef","ov_identifiers","template_def","@4","@5","@6","@7","fn_tmpl_end",
+"datadef","fndef","fn.def1","fn.def2","return_id","return_init","base_init",
+".set_base_init","member_init_list","member_init","identifier","notype_identifier",
+"identifier_defn","explicit_instantiation","template_type","template_type_name",
+"tmpl.2","template_arg_list","template_arg","template_instantiate_once","@8",
+"template_instantiation","template_instantiate_some","unop","expr","paren_expr_or_null",
+"paren_cond_or_null","xcond","condition","@9","already_scoped_stmt","nontrivial_exprlist",
+"nonnull_exprlist","unary_expr","@10","new_placement","new_initializer","regcast_or_absdcl",
+"cast_expr","sub_cast_expr","expr_no_commas","notype_unqualified_id","unqualified_id",
+"expr_or_declarator","direct_notype_declarator","primary","@11","@12","new",
+"delete","boolean.literal","string","nodecls","object","decl","declarator","fcast_or_absdcl",
+"type_id","typed_declspecs","typed_declspecs1","reserved_declspecs","declmods",
+"typed_typespecs","reserved_typespecquals","typespec","typespecqual_reserved",
+"initdecls","notype_initdecls","nomods_initdecls","maybeasm","initdcl0","@13",
+"initdcl","@14","notype_initdcl0","@15","nomods_initdcl0","@16","maybe_attribute",
+"attributes","attribute","attribute_list","attrib","any_word","identifiers_or_typenames",
+"init","initlist","structsp","@17","@18","maybecomma","maybecomma_warn","aggr",
+"specialization","named_class_head_sans_basetype","named_class_head_sans_basetype_defn",
+"do_xref","do_xref_defn","named_class_head","unnamed_class_head","class_head",
+"maybe_base_class_list","base_class_list","base_class","base_class.1","base_class_access_list",
+"left_curly","opt.component_decl_list","component_decl_list","component_decl",
+"component_decl_1","components","notype_components","component_declarator0",
+"component_declarator","after_type_component_declarator0","notype_component_declarator0",
+"after_type_component_declarator","notype_component_declarator","enumlist","enumerator",
+"new_type_id","type_quals","nonempty_type_quals","nonmomentary_expr","@19","after_type_declarator",
+"qualified_type_name","nested_type","direct_after_type_declarator","notype_declarator",
+"complex_notype_declarator","complex_direct_notype_declarator","qualified_id",
+"notype_qualified_id","overqualified_id","functional_cast","type_name","nested_name_specifier",
+"nested_name_specifier_1","complete_type_name","complex_type_name","ptr_to_mem",
+"global_scope","new_declarator","direct_new_declarator","absdcl","direct_abstract_declarator",
+"stmts","errstmt",".pushlevel","maybe_label_decls","label_decls","label_decl",
+"compstmt_or_error","compstmt","simple_if","@20","@21","implicitly_scoped_stmt",
+"stmt","simple_stmt","@22","@23","@24","@25","@26","@27","@28","@29","@30","@31",
+"@32","@33","@34","@35","@36","try_block","@37","@38","ansi_try_stmts","handler_seq",
+"@39","type_specifier_seq","handler_args","label_colon","forhead.1","forhead.2",
+"maybe_type_qual","xexpr","asm_operands","nonnull_asm_operands","asm_operand",
+"asm_clobbers","parmlist","complex_parmlist","parms","parms_comma","named_parm",
+"full_parm","parm","see_typename","bad_parm","maybe_raises","ansi_raise_identifier",
+"ansi_raise_identifiers","conversion_declarator","operator","operator_name",
+""
};
#endif
static const short yyr1[] = { 0,
106, 106, 108, 107, 107, 109, 110, 111, 111, 113,
112, 114, 114, 114, 114, 114, 114, 114, 114, 114,
- 115, 117, 116, 118, 118, 119, 119, 119, 120, 121,
- 121, 123, 122, 124, 122, 125, 122, 126, 122, 122,
- 122, 122, 122, 122, 122, 122, 127, 127, 127, 127,
- 127, 128, 128, 128, 128, 128, 128, 128, 128, 128,
- 128, 128, 129, 129, 129, 129, 129, 129, 129, 129,
- 130, 130, 130, 130, 131, 131, 131, 131, 131, 132,
- 133, 133, 133, 133, 134, 135, 136, 136, 136, 136,
- 137, 137, 137, 137, 137, 137, 137, 137, 138, 138,
- 138, 139, 139, 140, 140, 140, 141, 141, 141, 141,
- 142, 143, 143, 144, 145, 145, 146, 146, 148, 147,
- 149, 149, 150, 150, 151, 151, 151, 151, 151, 152,
- 152, 153, 153, 154, 154, 155, 155, 155, 157, 156,
- 156, 158, 158, 158, 158, 159, 159, 159, 159, 160,
- 160, 161, 162, 161, 161, 161, 161, 161, 161, 161,
- 161, 161, 161, 161, 161, 161, 161, 161, 161, 161,
- 161, 161, 161, 161, 163, 163, 164, 164, 164, 164,
- 165, 165, 166, 166, 166, 167, 167, 167, 167, 168,
- 168, 168, 168, 168, 168, 168, 168, 168, 168, 168,
- 168, 168, 168, 168, 168, 168, 168, 168, 168, 168,
- 168, 168, 168, 168, 169, 169, 169, 169, 170, 170,
- 171, 171, 171, 171, 172, 172, 172, 173, 173, 173,
- 173, 173, 173, 174, 173, 175, 173, 173, 173, 173,
- 173, 173, 173, 173, 173, 173, 173, 173, 173, 173,
- 173, 173, 173, 173, 173, 173, 173, 173, 173, 173,
- 173, 173, 173, 176, 176, 177, 177, 178, 178, 179,
- 179, 180, 181, 181, 182, 182, 182, 182, 182, 182,
- 182, 183, 183, 184, 184, 185, 185, 185, 185, 185,
- 186, 186, 187, 187, 187, 187, 187, 188, 188, 188,
- 189, 189, 189, 189, 190, 190, 190, 190, 191, 191,
- 192, 192, 192, 192, 192, 192, 192, 193, 193, 193,
- 194, 194, 195, 195, 196, 196, 197, 197, 199, 198,
- 198, 201, 200, 200, 203, 202, 202, 205, 204, 204,
- 206, 206, 207, 207, 208, 209, 209, 210, 210, 210,
- 210, 210, 211, 211, 211, 211, 212, 212, 213, 213,
- 213, 213, 213, 214, 214, 214, 214, 214, 214, 216,
- 215, 215, 217, 215, 215, 215, 215, 215, 215, 218,
- 218, 219, 219, 220, 220, 220, 220, 220, 221, 222,
- 222, 222, 222, 222, 222, 223, 224, 225, 226, 226,
- 227, 228, 228, 229, 229, 229, 230, 230, 231, 231,
- 232, 232, 232, 233, 233, 233, 233, 234, 235, 235,
- 235, 235, 236, 236, 236, 237, 237, 237, 237, 238,
- 238, 238, 238, 238, 238, 238, 239, 239, 239, 240,
- 240, 240, 241, 241, 242, 242, 243, 243, 243, 244,
- 244, 244, 244, 245, 245, 245, 246, 246, 246, 246,
- 247, 247, 248, 248, 249, 249, 249, 250, 250, 251,
- 251, 253, 252, 254, 254, 254, 254, 254, 254, 255,
- 255, 256, 257, 257, 257, 257, 257, 257, 257, 257,
- 257, 258, 258, 258, 258, 258, 258, 259, 259, 259,
- 259, 259, 259, 260, 260, 260, 260, 260, 260, 260,
- 260, 261, 262, 263, 263, 264, 264, 264, 265, 265,
- 266, 266, 267, 267, 268, 268, 269, 269, 270, 270,
- 271, 272, 272, 272, 272, 272, 272, 272, 273, 273,
- 274, 274, 274, 274, 274, 274, 274, 274, 274, 274,
- 274, 275, 275, 275, 275, 275, 275, 275, 275, 275,
- 275, 275, 276, 276, 276, 276, 277, 278, 279, 279,
- 280, 280, 281, 282, 282, 283, 283, 283, 283, 285,
- 286, 284, 287, 287, 288, 288, 289, 289, 290, 289,
- 289, 291, 292, 289, 293, 294, 289, 295, 296, 297,
- 289, 298, 299, 300, 289, 301, 289, 302, 289, 303,
- 289, 304, 289, 289, 289, 289, 289, 289, 289, 289,
- 289, 289, 289, 289, 289, 289, 289, 306, 307, 305,
- 308, 308, 308, 309, 310, 309, 311, 311, 312, 312,
- 313, 313, 314, 314, 314, 315, 315, 315, 315, 316,
- 316, 317, 317, 317, 318, 318, 319, 319, 320, 321,
- 321, 322, 322, 322, 323, 323, 323, 323, 323, 323,
- 323, 323, 323, 323, 324, 324, 324, 324, 324, 324,
- 325, 325, 326, 326, 326, 326, 326, 326, 327, 327,
- 328, 329, 329, 330, 330, 331, 332, 332, 333, 333,
- 333, 333, 334, 335, 335, 335, 335, 335, 335, 335,
- 335, 335, 335, 335, 335, 335, 335, 335, 335, 335,
- 335, 335, 335, 335, 335, 335, 335, 335, 335, 335,
- 335, 335, 335, 335, 335, 335, 335, 335
+ 115, 117, 116, 118, 118, 119, 119, 120, 120, 120,
+ 121, 122, 122, 124, 123, 125, 123, 126, 123, 127,
+ 123, 123, 123, 123, 123, 123, 123, 123, 128, 128,
+ 128, 128, 128, 129, 129, 129, 129, 129, 129, 129,
+ 129, 129, 129, 129, 130, 130, 130, 130, 130, 130,
+ 130, 130, 131, 131, 131, 131, 132, 132, 132, 132,
+ 132, 133, 134, 134, 134, 134, 135, 136, 137, 137,
+ 137, 137, 138, 138, 138, 138, 138, 138, 138, 138,
+ 139, 139, 139, 140, 140, 141, 141, 141, 142, 142,
+ 142, 142, 143, 144, 144, 144, 145, 146, 146, 147,
+ 147, 149, 148, 150, 150, 151, 151, 152, 152, 152,
+ 152, 152, 153, 153, 154, 154, 155, 155, 156, 156,
+ 156, 158, 157, 157, 159, 159, 159, 159, 160, 160,
+ 160, 160, 161, 161, 162, 163, 162, 162, 162, 162,
+ 162, 162, 162, 162, 162, 162, 162, 162, 162, 162,
+ 162, 162, 162, 162, 162, 162, 162, 164, 164, 165,
+ 165, 165, 165, 166, 166, 167, 167, 167, 168, 168,
+ 168, 168, 169, 169, 169, 169, 169, 169, 169, 169,
+ 169, 169, 169, 169, 169, 169, 169, 169, 169, 169,
+ 169, 169, 169, 169, 169, 169, 169, 170, 170, 170,
+ 170, 171, 171, 172, 172, 172, 172, 173, 173, 173,
+ 174, 174, 174, 174, 174, 174, 175, 174, 176, 174,
+ 174, 174, 174, 174, 174, 174, 174, 174, 174, 174,
+ 174, 174, 174, 174, 174, 174, 174, 174, 174, 174,
+ 174, 174, 174, 174, 174, 174, 177, 177, 178, 178,
+ 179, 179, 180, 180, 181, 182, 182, 183, 183, 183,
+ 183, 183, 183, 183, 184, 184, 185, 185, 186, 186,
+ 186, 186, 186, 187, 187, 188, 188, 188, 188, 188,
+ 189, 189, 189, 190, 190, 190, 190, 191, 191, 191,
+ 191, 192, 192, 193, 193, 193, 193, 193, 193, 193,
+ 194, 194, 194, 195, 195, 196, 196, 197, 197, 198,
+ 198, 200, 199, 199, 202, 201, 201, 204, 203, 203,
+ 206, 205, 205, 207, 207, 208, 208, 209, 210, 210,
+ 211, 211, 211, 211, 211, 212, 212, 212, 212, 213,
+ 213, 214, 214, 214, 214, 214, 215, 215, 215, 215,
+ 215, 215, 217, 216, 216, 218, 216, 216, 216, 216,
+ 216, 216, 219, 219, 220, 220, 221, 221, 221, 221,
+ 221, 222, 223, 223, 223, 223, 223, 223, 224, 225,
+ 226, 227, 227, 228, 229, 229, 230, 230, 230, 231,
+ 231, 232, 232, 233, 233, 233, 234, 234, 234, 234,
+ 235, 236, 236, 236, 236, 237, 237, 237, 238, 238,
+ 238, 238, 239, 239, 239, 239, 239, 239, 239, 240,
+ 240, 240, 241, 241, 241, 242, 242, 243, 243, 244,
+ 244, 244, 245, 245, 245, 245, 246, 246, 246, 247,
+ 247, 247, 247, 248, 248, 249, 249, 250, 250, 250,
+ 251, 251, 252, 252, 254, 253, 255, 255, 255, 255,
+ 255, 255, 256, 256, 257, 258, 258, 258, 258, 258,
+ 258, 258, 258, 258, 259, 259, 259, 259, 259, 259,
+ 260, 260, 260, 260, 260, 260, 261, 261, 261, 261,
+ 261, 261, 261, 261, 262, 263, 264, 264, 265, 265,
+ 265, 266, 266, 267, 267, 268, 268, 269, 269, 270,
+ 270, 271, 271, 272, 273, 273, 273, 273, 273, 273,
+ 273, 274, 274, 275, 275, 275, 275, 275, 275, 275,
+ 275, 275, 275, 275, 276, 276, 276, 276, 276, 276,
+ 276, 276, 276, 276, 276, 277, 277, 277, 277, 278,
+ 279, 280, 280, 281, 281, 282, 283, 283, 284, 284,
+ 284, 284, 286, 287, 285, 288, 288, 289, 289, 290,
+ 290, 291, 290, 290, 292, 293, 290, 294, 295, 290,
+ 296, 297, 298, 290, 299, 300, 301, 290, 302, 290,
+ 303, 290, 304, 290, 305, 290, 290, 290, 290, 290,
+ 290, 290, 290, 290, 290, 290, 290, 290, 290, 290,
+ 307, 308, 306, 309, 309, 309, 310, 311, 310, 312,
+ 312, 313, 313, 314, 314, 314, 315, 315, 315, 316,
+ 316, 316, 316, 317, 317, 318, 318, 318, 319, 319,
+ 320, 320, 321, 322, 322, 323, 323, 323, 324, 324,
+ 324, 324, 324, 324, 324, 324, 324, 324, 325, 325,
+ 325, 325, 325, 326, 326, 327, 327, 327, 327, 327,
+ 327, 328, 328, 329, 329, 330, 331, 331, 332, 332,
+ 333, 334, 334, 335, 335, 335, 335, 336, 337, 337,
+ 337, 337, 337, 337, 337, 337, 337, 337, 337, 337,
+ 337, 337, 337, 337, 337, 337, 337, 337, 337, 337,
+ 337, 337, 337, 337, 337, 337, 337, 337, 337, 337,
+ 337, 337, 337
};
static const short yyr2[] = { 0,
0, 1, 0, 2, 2, 0, 0, 1, 1, 0,
2, 1, 1, 1, 1, 5, 4, 3, 4, 4,
- 1, 0, 5, 1, 3, 2, 4, 1, 3, 1,
- 3, 0, 5, 0, 5, 0, 5, 0, 5, 3,
- 3, 6, 7, 4, 3, 3, 1, 1, 1, 1,
- 1, 2, 3, 3, 3, 3, 2, 2, 2, 2,
- 2, 1, 3, 4, 3, 5, 4, 3, 3, 2,
- 3, 3, 2, 1, 6, 4, 3, 3, 2, 2,
- 1, 3, 4, 2, 3, 0, 0, 1, 3, 2,
- 3, 1, 4, 2, 4, 2, 4, 2, 1, 1,
- 1, 1, 1, 1, 1, 1, 3, 3, 4, 4,
- 3, 4, 4, 0, 1, 3, 1, 1, 0, 6,
- 0, 1, 0, 2, 1, 1, 1, 1, 1, 1,
- 1, 1, 3, 1, 3, 0, 1, 1, 0, 8,
- 1, 2, 4, 4, 1, 3, 3, 3, 3, 1,
- 1, 1, 0, 3, 2, 2, 2, 2, 2, 2,
- 4, 2, 4, 2, 3, 3, 4, 4, 5, 5,
- 6, 2, 4, 5, 3, 3, 3, 1, 3, 2,
- 3, 4, 1, 2, 5, 1, 4, 4, 4, 1,
+ 1, 0, 5, 1, 3, 1, 2, 1, 3, 1,
+ 3, 1, 3, 0, 5, 0, 5, 0, 5, 0,
+ 5, 3, 3, 6, 7, 4, 3, 3, 1, 1,
+ 1, 1, 1, 2, 3, 3, 3, 3, 2, 2,
+ 2, 2, 2, 1, 3, 4, 3, 5, 4, 3,
+ 3, 2, 3, 3, 2, 1, 6, 4, 3, 3,
+ 2, 2, 1, 3, 4, 2, 3, 0, 0, 1,
+ 3, 2, 3, 1, 4, 2, 4, 2, 4, 2,
+ 1, 1, 1, 1, 1, 1, 1, 1, 3, 3,
+ 4, 4, 3, 4, 3, 4, 0, 1, 3, 1,
+ 1, 0, 6, 0, 1, 0, 2, 1, 1, 1,
+ 1, 1, 1, 1, 1, 3, 1, 3, 0, 1,
+ 1, 0, 8, 1, 2, 4, 4, 1, 3, 3,
+ 3, 3, 1, 1, 1, 0, 3, 2, 2, 2,
+ 2, 2, 2, 4, 2, 4, 2, 3, 3, 4,
+ 4, 5, 5, 6, 2, 4, 5, 3, 3, 3,
+ 1, 3, 2, 3, 4, 1, 2, 5, 1, 4,
+ 4, 4, 1, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 5,
- 3, 3, 1, 2, 3, 1, 1, 1, 1, 1,
- 1, 1, 2, 2, 1, 1, 1, 1, 1, 1,
- 1, 3, 3, 0, 4, 0, 6, 2, 4, 2,
- 2, 1, 4, 1, 7, 7, 7, 7, 4, 4,
- 2, 2, 1, 4, 2, 2, 2, 5, 3, 5,
- 3, 4, 6, 1, 2, 1, 2, 1, 1, 1,
- 2, 0, 2, 2, 3, 3, 3, 3, 3, 2,
- 2, 1, 1, 1, 2, 2, 2, 2, 1, 1,
- 1, 1, 2, 2, 3, 3, 4, 1, 2, 2,
- 1, 1, 2, 2, 1, 2, 2, 3, 1, 2,
- 1, 1, 1, 4, 4, 4, 4, 1, 1, 1,
- 1, 3, 1, 3, 1, 3, 0, 4, 0, 7,
+ 3, 3, 5, 3, 3, 1, 2, 3, 1, 1,
+ 1, 1, 1, 1, 1, 2, 2, 1, 1, 1,
+ 1, 1, 1, 1, 3, 3, 0, 4, 0, 6,
+ 2, 4, 2, 2, 1, 4, 1, 7, 7, 7,
+ 7, 4, 4, 2, 2, 1, 4, 2, 2, 2,
+ 5, 3, 5, 3, 4, 6, 1, 2, 1, 2,
+ 1, 1, 1, 2, 0, 2, 2, 3, 3, 3,
+ 3, 3, 2, 2, 1, 1, 1, 2, 2, 2,
+ 2, 1, 1, 1, 1, 2, 2, 3, 3, 4,
+ 1, 2, 2, 1, 1, 2, 2, 1, 2, 2,
+ 3, 1, 2, 1, 1, 1, 4, 4, 4, 4,
+ 1, 1, 1, 1, 3, 1, 3, 1, 3, 0,
4, 0, 7, 4, 0, 7, 4, 0, 7, 4,
- 0, 1, 1, 2, 6, 1, 3, 0, 1, 4,
- 6, 4, 1, 1, 1, 1, 1, 3, 1, 2,
- 3, 4, 1, 1, 3, 4, 6, 3, 5, 0,
- 7, 4, 0, 6, 3, 2, 2, 4, 1, 0,
- 1, 0, 1, 1, 2, 2, 2, 2, 3, 2,
- 2, 2, 3, 3, 1, 2, 0, 0, 3, 3,
- 2, 1, 1, 0, 1, 2, 1, 3, 1, 2,
- 1, 4, 4, 1, 1, 2, 2, 1, 0, 1,
- 4, 3, 1, 2, 2, 2, 2, 2, 2, 2,
- 2, 4, 2, 1, 5, 3, 0, 1, 3, 0,
- 1, 3, 1, 1, 1, 1, 4, 6, 4, 4,
- 6, 4, 3, 4, 6, 4, 4, 6, 4, 3,
- 1, 3, 1, 3, 2, 1, 6, 0, 2, 1,
- 2, 0, 2, 3, 3, 2, 2, 3, 1, 1,
- 1, 2, 5, 5, 3, 5, 4, 3, 3, 2,
- 1, 3, 3, 2, 2, 3, 1, 3, 3, 2,
- 2, 3, 1, 5, 5, 3, 5, 3, 3, 4,
- 3, 2, 2, 1, 2, 4, 4, 2, 1, 1,
- 1, 2, 2, 2, 1, 2, 1, 2, 2, 3,
- 1, 3, 2, 3, 2, 2, 3, 1, 3, 4,
- 3, 2, 2, 1, 3, 2, 2, 1, 2, 3,
- 1, 3, 1, 5, 3, 4, 3, 4, 2, 2,
- 3, 2, 1, 1, 2, 2, 2, 0, 0, 1,
- 1, 2, 3, 1, 2, 3, 5, 6, 5, 0,
- 0, 6, 1, 2, 1, 1, 1, 2, 0, 4,
- 1, 0, 0, 6, 0, 0, 7, 0, 0, 0,
- 10, 0, 0, 0, 10, 0, 7, 0, 5, 0,
- 7, 0, 4, 2, 2, 2, 3, 6, 8, 10,
- 12, 4, 3, 2, 2, 1, 1, 0, 0, 7,
- 1, 2, 2, 0, 0, 5, 1, 1, 3, 3,
- 2, 2, 3, 4, 4, 3, 4, 6, 6, 0,
- 1, 0, 1, 1, 0, 1, 1, 3, 4, 1,
- 3, 0, 1, 1, 1, 2, 2, 2, 1, 1,
- 2, 2, 2, 2, 1, 3, 2, 4, 2, 4,
- 2, 2, 2, 2, 2, 2, 1, 2, 1, 1,
- 0, 0, 1, 0, 4, 1, 1, 3, 0, 3,
- 3, 3, 1, 2, 2, 2, 2, 2, 2, 2,
+ 0, 7, 4, 0, 1, 1, 2, 6, 1, 3,
+ 0, 1, 4, 6, 4, 1, 1, 1, 1, 1,
+ 3, 1, 2, 3, 4, 1, 1, 3, 4, 6,
+ 3, 5, 0, 7, 4, 0, 6, 3, 2, 2,
+ 4, 1, 0, 1, 0, 1, 1, 2, 2, 2,
+ 2, 3, 2, 2, 2, 3, 3, 1, 2, 0,
+ 0, 3, 3, 2, 1, 1, 0, 1, 2, 1,
+ 3, 1, 2, 1, 4, 4, 1, 1, 2, 2,
+ 1, 0, 1, 4, 3, 1, 2, 2, 2, 2,
+ 2, 2, 2, 2, 4, 2, 1, 5, 3, 0,
+ 1, 3, 0, 1, 3, 1, 1, 1, 1, 4,
+ 6, 4, 4, 6, 4, 3, 4, 6, 4, 4,
+ 6, 4, 3, 1, 3, 1, 3, 2, 1, 6,
+ 0, 2, 1, 2, 0, 2, 3, 3, 2, 2,
+ 3, 1, 1, 1, 2, 5, 5, 3, 5, 4,
+ 3, 3, 2, 1, 3, 3, 2, 2, 3, 1,
+ 3, 3, 2, 2, 3, 1, 5, 5, 3, 5,
+ 3, 3, 4, 3, 2, 2, 1, 2, 4, 4,
+ 2, 1, 1, 1, 2, 2, 2, 1, 2, 1,
+ 2, 2, 3, 1, 3, 2, 3, 2, 2, 3,
+ 1, 3, 4, 3, 2, 2, 1, 3, 2, 2,
+ 1, 2, 3, 1, 3, 1, 5, 3, 4, 3,
+ 4, 2, 2, 3, 2, 1, 1, 2, 2, 2,
+ 0, 0, 1, 1, 2, 3, 1, 2, 3, 5,
+ 6, 5, 0, 0, 6, 1, 2, 1, 1, 1,
+ 2, 0, 4, 1, 0, 0, 6, 0, 0, 7,
+ 0, 0, 0, 10, 0, 0, 0, 10, 0, 7,
+ 0, 5, 0, 7, 0, 4, 2, 2, 2, 3,
+ 6, 8, 10, 12, 4, 3, 2, 2, 1, 1,
+ 0, 0, 7, 1, 2, 2, 0, 0, 5, 1,
+ 1, 3, 3, 2, 2, 2, 3, 4, 4, 3,
+ 4, 6, 6, 0, 1, 0, 1, 1, 0, 1,
+ 1, 3, 4, 1, 3, 0, 1, 1, 1, 2,
+ 2, 2, 1, 1, 2, 2, 2, 2, 1, 3,
+ 2, 2, 4, 2, 2, 2, 2, 2, 2, 1,
+ 2, 1, 3, 1, 1, 0, 0, 1, 0, 4,
+ 1, 1, 3, 0, 3, 3, 3, 1, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 3, 2, 2, 2,
- 2, 3, 2, 2, 4, 4, 3, 2
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 3, 2, 2, 2, 2, 3, 2, 2, 4,
+ 4, 3, 2
};
static const short yydefact[] = { 3,
- 10, 10, 5, 0, 4, 0, 217, 519, 302, 312,
- 470, 0, 8, 9, 0, 0, 384, 0, 703, 0,
- 531, 218, 62, 0, 0, 691, 0, 74, 21, 0,
- 11, 6, 0, 15, 14, 13, 12, 272, 0, 520,
- 114, 226, 497, 0, 292, 0, 291, 305, 0, 325,
- 311, 0, 395, 397, 398, 403, 402, 379, 301, 525,
- 481, 0, 225, 227, 480, 0, 521, 313, 468, 0,
- 0, 216, 60, 61, 523, 0, 0, 99, 100, 101,
- 373, 376, 0, 527, 0, 377, 0, 0, 0, 30,
- 0, 302, 0, 22, 0, 0, 395, 0, 0, 0,
- 0, 495, 0, 0, 0, 494, 0, 0, 0, 226,
- 0, 0, 0, 225, 227, 468, 0, 3, 0, 0,
- 0, 0, 397, 398, 694, 0, 86, 81, 272, 0,
- 0, 58, 524, 121, 468, 0, 472, 59, 0, 0,
- 0, 0, 0, 321, 282, 479, 283, 491, 0, 468,
- 304, 303, 57, 293, 0, 323, 0, 298, 318, 319,
- 294, 307, 309, 320, 0, 52, 385, 386, 387, 388,
- 401, 105, 104, 106, 390, 396, 392, 114, 391, 404,
- 404, 418, 0, 471, 306, 70, 0, 73, 529, 513,
- 482, 522, 0, 526, 0, 738, 734, 733, 731, 713,
- 718, 719, 0, 725, 724, 710, 711, 709, 728, 717,
- 714, 715, 716, 720, 721, 707, 708, 704, 705, 706,
- 730, 722, 723, 712, 729, 0, 726, 637, 305, 638,
- 699, 470, 229, 270, 0, 0, 0, 0, 153, 266,
- 264, 242, 268, 269, 0, 0, 0, 0, 0, 0,
- 0, 126, 125, 0, 127, 128, 0, 0, 213, 129,
- 0, 115, 0, 186, 0, 190, 183, 118, 228, 152,
- 0, 0, 230, 231, 0, 117, 289, 305, 290, 514,
- 253, 244, 0, 0, 0, 395, 375, 0, 370, 528,
- 0, 130, 131, 0, 0, 0, 0, 29, 0, 108,
- 404, 122, 107, 0, 493, 0, 492, 100, 101, 215,
- 224, 0, 501, 223, 0, 500, 508, 509, 0, 0,
- 18, 10, 0, 7, 7, 46, 45, 694, 0, 32,
- 40, 36, 34, 41, 38, 327, 80, 87, 84, 0,
- 0, 272, 0, 0, 0, 568, 63, 574, 65, 111,
- 506, 0, 669, 670, 151, 0, 150, 664, 687, 0,
- 289, 305, 290, 0, 663, 665, 692, 675, 0, 511,
- 0, 0, 0, 477, 0, 476, 0, 0, 0, 468,
- 68, 56, 71, 0, 55, 468, 0, 472, 490, 0,
- 295, 296, 0, 53, 69, 54, 72, 300, 299, 310,
- 694, 326, 393, 389, 394, 405, 399, 400, 434, 0,
- 0, 437, 440, 0, 0, 423, 0, 694, 308, 0,
- 0, 341, 469, 496, 530, 0, 0, 727, 732, 468,
- 468, 0, 468, 737, 0, 0, 0, 160, 0, 0,
- 162, 0, 0, 0, 0, 0, 0, 0, 0, 159,
- 156, 155, 157, 0, 0, 0, 0, 214, 0, 113,
- 158, 0, 0, 184, 0, 0, 0, 0, 0, 0,
+ 10, 10, 5, 0, 4, 0, 220, 522, 305, 315,
+ 473, 0, 8, 9, 0, 0, 387, 0, 708, 0,
+ 534, 221, 64, 0, 0, 696, 0, 76, 21, 0,
+ 11, 6, 0, 15, 14, 13, 12, 275, 0, 523,
+ 117, 229, 500, 0, 295, 0, 294, 308, 0, 328,
+ 314, 0, 398, 400, 401, 406, 405, 382, 304, 528,
+ 484, 0, 228, 230, 483, 0, 524, 316, 471, 0,
+ 0, 219, 62, 63, 526, 0, 0, 101, 102, 103,
+ 376, 379, 0, 530, 0, 380, 0, 0, 0, 32,
+ 0, 305, 0, 22, 0, 0, 398, 0, 0, 0,
+ 0, 498, 0, 0, 0, 497, 0, 0, 0, 229,
+ 0, 0, 0, 228, 230, 471, 0, 3, 0, 0,
+ 0, 0, 400, 401, 699, 0, 88, 83, 275, 0,
+ 0, 60, 527, 124, 471, 0, 475, 61, 0, 0,
+ 0, 0, 0, 324, 285, 482, 286, 494, 0, 471,
+ 307, 306, 59, 296, 0, 326, 0, 301, 321, 322,
+ 297, 310, 312, 323, 0, 54, 388, 389, 390, 391,
+ 404, 107, 106, 108, 393, 399, 395, 117, 394, 407,
+ 407, 421, 0, 474, 309, 72, 0, 75, 532, 516,
+ 485, 525, 0, 529, 0, 743, 739, 738, 736, 718,
+ 723, 724, 0, 730, 729, 715, 716, 714, 733, 722,
+ 719, 720, 721, 725, 726, 712, 713, 709, 710, 711,
+ 735, 727, 728, 717, 734, 0, 731, 640, 308, 641,
+ 704, 473, 232, 273, 0, 0, 0, 0, 156, 269,
+ 267, 245, 271, 272, 0, 0, 0, 0, 0, 0,
+ 0, 129, 128, 0, 130, 131, 0, 0, 216, 132,
+ 0, 118, 0, 189, 0, 193, 186, 121, 231, 155,
+ 0, 0, 233, 234, 0, 120, 292, 308, 293, 517,
+ 256, 247, 0, 0, 0, 398, 378, 0, 373, 531,
+ 0, 133, 134, 0, 0, 0, 0, 31, 0, 110,
+ 407, 125, 109, 115, 0, 496, 0, 495, 102, 103,
+ 218, 227, 0, 504, 226, 0, 503, 511, 512, 0,
+ 0, 18, 10, 0, 7, 7, 48, 47, 699, 0,
+ 34, 42, 38, 36, 43, 40, 330, 82, 89, 86,
+ 0, 0, 275, 0, 0, 0, 571, 65, 577, 67,
+ 113, 509, 0, 673, 674, 154, 0, 153, 668, 690,
+ 0, 292, 308, 293, 0, 667, 669, 697, 679, 0,
+ 514, 0, 0, 0, 480, 0, 479, 0, 0, 0,
+ 471, 70, 58, 73, 0, 57, 471, 0, 475, 493,
+ 0, 298, 299, 0, 55, 71, 56, 74, 303, 302,
+ 313, 699, 329, 396, 392, 397, 408, 402, 403, 437,
+ 0, 0, 440, 443, 0, 0, 426, 0, 699, 311,
+ 0, 0, 344, 472, 499, 533, 0, 0, 732, 737,
+ 471, 471, 0, 471, 742, 0, 0, 0, 163, 0,
+ 0, 165, 0, 0, 0, 0, 0, 0, 0, 0,
+ 162, 159, 158, 160, 0, 0, 0, 0, 217, 0,
+ 116, 161, 0, 0, 187, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 238, 240, 241, 274,
- 273, 0, 0, 0, 0, 0, 164, 466, 0, 172,
- 271, 220, 0, 691, 219, 256, 257, 0, 284, 548,
- 544, 553, 0, 472, 468, 468, 468, 286, 551, 0,
- 518, 288, 0, 287, 255, 0, 251, 265, 267, 515,
- 0, 252, 110, 109, 463, 382, 461, 372, 0, 314,
- 0, 0, 315, 316, 317, 31, 0, 24, 690, 305,
- 0, 689, 28, 119, 112, 499, 498, 502, 0, 17,
- 20, 19, 327, 51, 47, 49, 50, 48, 44, 0,
- 0, 0, 0, 341, 102, 92, 103, 0, 85, 88,
- 0, 0, 0, 363, 0, 359, 82, 0, 0, 64,
- 67, 575, 569, 468, 468, 668, 682, 674, 672, 548,
- 544, 0, 683, 468, 686, 688, 684, 0, 685, 468,
- 667, 681, 673, 671, 666, 693, 677, 679, 0, 510,
- 473, 475, 474, 0, 0, 489, 0, 341, 322, 485,
- 0, 0, 0, 488, 0, 478, 297, 324, 341, 327,
- 415, 0, 414, 406, 407, 409, 0, 411, 433, 429,
- 428, 217, 519, 468, 0, 662, 694, 430, 438, 443,
- 444, 694, 694, 431, 441, 694, 0, 378, 425, 424,
- 426, 427, 327, 696, 305, 697, 0, 0, 0, 340,
- 342, 343, 736, 735, 699, 699, 699, 0, 0, 0,
- 518, 0, 0, 519, 0, 154, 0, 0, 0, 0,
- 0, 0, 233, 232, 0, 181, 116, 217, 519, 218,
- 0, 0, 364, 380, 0, 212, 211, 654, 653, 0,
- 209, 208, 206, 207, 205, 204, 203, 200, 201, 202,
- 198, 199, 193, 194, 195, 196, 197, 191, 192, 0,
- 0, 0, 0, 0, 0, 166, 178, 0, 0, 165,
- 468, 468, 0, 468, 465, 538, 0, 0, 0, 0,
- 259, 0, 261, 0, 512, 547, 546, 543, 542, 690,
- 0, 0, 562, 0, 0, 559, 285, 560, 549, 468,
- 662, 472, 548, 544, 0, 0, 468, 228, 0, 514,
- 0, 0, 0, 383, 0, 382, 149, 148, 147, 146,
- 0, 23, 390, 396, 0, 16, 341, 33, 37, 35,
- 39, 0, 0, 90, 0, 94, 0, 98, 0, 96,
- 0, 360, 0, 83, 66, 0, 576, 0, 570, 571,
- 507, 504, 547, 543, 548, 544, 480, 0, 468, 549,
- 548, 544, 0, 228, 0, 514, 505, 0, 0, 676,
- 331, 468, 468, 468, 487, 337, 341, 0, 0, 417,
- 416, 410, 0, 0, 436, 341, 0, 77, 0, 327,
- 327, 0, 327, 0, 341, 0, 695, 0, 0, 338,
- 344, 701, 700, 702, 243, 161, 0, 0, 163, 187,
- 189, 188, 249, 250, 0, 0, 0, 0, 235, 0,
- 0, 0, 0, 182, 0, 236, 239, 176, 175, 168,
- 0, 167, 180, 0, 0, 535, 533, 0, 536, 472,
- 173, 0, 0, 262, 0, 0, 545, 541, 552, 468,
- 561, 550, 555, 0, 557, 0, 548, 544, 516, 517,
- 0, 254, 464, 462, 374, 0, 25, 0, 0, 0,
- 42, 91, 89, 0, 0, 0, 0, 361, 357, 0,
- 0, 217, 580, 592, 595, 0, 568, 0, 0, 0,
- 0, 0, 0, 218, 626, 0, 650, 0, 587, 0,
- 0, 305, 0, 564, 585, 591, 563, 586, 627, 0,
- 598, 602, 572, 547, 543, 482, 549, 517, 678, 680,
- 329, 486, 483, 484, 335, 334, 0, 0, 408, 341,
- 341, 76, 453, 468, 217, 519, 0, 439, 445, 446,
- 694, 694, 341, 341, 442, 0, 432, 698, 328, 348,
- 0, 0, 0, 0, 0, 0, 368, 0, 0, 365,
- 185, 210, 123, 0, 169, 170, 177, 179, 534, 532,
- 539, 537, 0, 174, 0, 258, 260, 558, 468, 556,
- 371, 27, 0, 43, 93, 97, 95, 362, 0, 573,
- 567, 579, 641, 568, 568, 568, 0, 0, 0, 612,
- 614, 615, 616, 0, 0, 0, 642, 568, 651, 0,
- 588, 280, 694, 0, 281, 0, 694, 0, 694, 0,
- 0, 577, 566, 565, 589, 625, 624, 568, 568, 0,
- 0, 332, 412, 413, 452, 449, 435, 0, 0, 341,
- 327, 327, 447, 450, 354, 355, 356, 353, 0, 346,
- 349, 339, 0, 0, 0, 0, 366, 0, 0, 123,
- 237, 0, 171, 540, 263, 554, 120, 358, 0, 0,
- 0, 583, 0, 0, 568, 643, 0, 646, 0, 0,
- 608, 0, 617, 0, 623, 628, 0, 276, 327, 278,
- 279, 327, 0, 0, 0, 275, 277, 578, 568, 0,
- 0, 330, 336, 0, 75, 341, 341, 460, 341, 341,
- 0, 0, 348, 0, 0, 245, 246, 247, 248, 0,
- 369, 124, 467, 134, 0, 581, 593, 584, 596, 647,
- 645, 0, 644, 141, 0, 305, 0, 0, 0, 613,
- 622, 0, 0, 590, 138, 0, 137, 0, 333, 459,
- 456, 454, 457, 448, 451, 347, 345, 217, 0, 367,
- 0, 568, 0, 0, 0, 0, 606, 694, 610, 609,
- 0, 631, 0, 629, 655, 0, 599, 603, 0, 0,
- 0, 350, 352, 135, 582, 569, 594, 145, 132, 0,
- 0, 649, 0, 648, 568, 327, 0, 633, 632, 634,
- 0, 0, 656, 657, 618, 0, 0, 455, 458, 0,
- 142, 0, 0, 597, 607, 341, 611, 630, 0, 655,
- 0, 0, 0, 0, 351, 0, 0, 133, 0, 635,
- 0, 0, 619, 658, 600, 604, 144, 143, 139, 0,
- 659, 0, 0, 0, 0, 0, 0, 0, 660, 0,
- 620, 601, 605, 140, 0, 0, 636, 0, 0, 639,
- 640, 661, 621, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 241, 243, 244,
+ 277, 276, 0, 0, 0, 0, 0, 167, 469, 0,
+ 175, 274, 223, 0, 696, 222, 259, 260, 0, 287,
+ 551, 547, 556, 0, 475, 471, 471, 471, 289, 554,
+ 0, 521, 291, 0, 290, 258, 0, 254, 268, 270,
+ 518, 0, 255, 112, 111, 466, 385, 464, 375, 0,
+ 317, 0, 0, 318, 319, 320, 33, 0, 28, 24,
+ 695, 308, 26, 694, 30, 692, 122, 114, 502, 501,
+ 505, 0, 17, 20, 19, 330, 53, 49, 51, 52,
+ 50, 46, 0, 0, 0, 0, 344, 104, 94, 105,
+ 0, 87, 90, 0, 0, 0, 366, 0, 362, 84,
+ 0, 0, 66, 69, 578, 572, 471, 471, 672, 685,
+ 678, 676, 551, 547, 0, 686, 471, 689, 691, 687,
+ 0, 688, 471, 671, 684, 677, 675, 670, 698, 681,
+ 682, 0, 513, 476, 478, 477, 0, 0, 492, 0,
+ 344, 325, 488, 0, 0, 0, 491, 0, 481, 300,
+ 327, 344, 330, 418, 0, 417, 409, 410, 412, 0,
+ 414, 436, 432, 431, 220, 522, 471, 0, 666, 699,
+ 433, 441, 446, 447, 699, 699, 434, 444, 699, 0,
+ 381, 428, 427, 429, 430, 330, 701, 308, 702, 0,
+ 0, 0, 343, 345, 346, 741, 740, 704, 704, 704,
+ 0, 0, 0, 521, 0, 0, 522, 0, 157, 0,
+ 0, 0, 0, 0, 0, 236, 235, 0, 184, 119,
+ 220, 522, 221, 0, 0, 367, 383, 0, 215, 214,
+ 658, 657, 0, 212, 211, 209, 210, 208, 207, 206,
+ 203, 204, 205, 201, 202, 196, 197, 198, 199, 200,
+ 194, 195, 0, 0, 0, 0, 0, 0, 169, 181,
+ 0, 0, 168, 471, 471, 0, 471, 468, 541, 0,
+ 0, 0, 0, 262, 0, 264, 0, 515, 550, 549,
+ 546, 545, 695, 0, 0, 565, 0, 0, 562, 288,
+ 563, 552, 471, 666, 475, 551, 547, 0, 0, 471,
+ 231, 0, 517, 0, 0, 0, 386, 0, 385, 152,
+ 151, 150, 149, 0, 23, 0, 393, 0, 0, 16,
+ 344, 35, 39, 37, 41, 0, 0, 92, 0, 96,
+ 0, 100, 0, 98, 0, 363, 0, 85, 68, 0,
+ 579, 0, 573, 574, 510, 507, 550, 546, 551, 547,
+ 483, 0, 471, 552, 551, 547, 0, 231, 0, 517,
+ 508, 0, 680, 334, 471, 471, 471, 490, 340, 344,
+ 0, 0, 420, 419, 413, 0, 0, 439, 344, 0,
+ 79, 0, 330, 330, 0, 330, 0, 344, 0, 700,
+ 0, 0, 341, 347, 706, 705, 707, 246, 164, 0,
+ 0, 166, 190, 192, 191, 252, 253, 0, 0, 0,
+ 0, 238, 0, 0, 0, 0, 185, 0, 239, 242,
+ 179, 178, 171, 0, 170, 183, 0, 0, 538, 536,
+ 0, 539, 475, 176, 0, 0, 265, 0, 0, 548,
+ 544, 555, 471, 564, 553, 558, 0, 560, 0, 551,
+ 547, 519, 520, 0, 257, 467, 465, 377, 0, 25,
+ 29, 693, 0, 0, 44, 93, 91, 0, 0, 0,
+ 0, 364, 360, 0, 0, 220, 522, 583, 595, 598,
+ 0, 571, 0, 0, 0, 0, 0, 0, 221, 629,
+ 0, 654, 0, 590, 0, 0, 308, 0, 567, 588,
+ 594, 566, 589, 630, 0, 601, 605, 575, 550, 546,
+ 485, 552, 520, 683, 332, 489, 486, 487, 338, 337,
+ 0, 0, 411, 344, 344, 78, 456, 471, 220, 522,
+ 0, 442, 448, 449, 699, 699, 344, 344, 445, 0,
+ 435, 703, 331, 351, 0, 0, 0, 0, 0, 0,
+ 371, 0, 0, 368, 188, 213, 126, 0, 172, 173,
+ 180, 182, 537, 535, 542, 540, 0, 177, 0, 261,
+ 263, 561, 471, 559, 374, 0, 45, 95, 99, 97,
+ 365, 0, 576, 570, 582, 644, 646, 571, 571, 571,
+ 0, 0, 0, 615, 617, 618, 619, 0, 0, 0,
+ 645, 571, 655, 0, 591, 283, 699, 0, 284, 0,
+ 699, 0, 699, 0, 0, 580, 569, 568, 592, 628,
+ 627, 571, 571, 0, 0, 335, 415, 416, 455, 452,
+ 438, 0, 0, 344, 330, 330, 450, 453, 357, 358,
+ 359, 356, 0, 349, 352, 342, 0, 0, 0, 0,
+ 369, 0, 0, 126, 240, 0, 174, 543, 266, 557,
+ 123, 361, 0, 0, 0, 586, 0, 0, 571, 647,
+ 0, 650, 0, 0, 611, 0, 620, 0, 626, 631,
+ 0, 279, 330, 281, 282, 330, 0, 0, 0, 278,
+ 280, 581, 571, 0, 0, 333, 339, 0, 77, 344,
+ 344, 463, 344, 344, 0, 0, 351, 0, 0, 248,
+ 249, 250, 251, 0, 372, 127, 470, 137, 0, 584,
+ 596, 587, 599, 651, 649, 0, 648, 144, 0, 308,
+ 0, 0, 0, 616, 625, 0, 0, 593, 141, 0,
+ 140, 0, 336, 462, 459, 457, 460, 451, 454, 350,
+ 348, 220, 0, 370, 0, 571, 0, 0, 0, 0,
+ 609, 699, 613, 612, 0, 634, 0, 632, 659, 0,
+ 602, 606, 0, 0, 0, 353, 355, 138, 585, 572,
+ 597, 148, 135, 0, 0, 653, 0, 652, 571, 330,
+ 0, 636, 635, 637, 0, 0, 660, 661, 621, 0,
+ 0, 458, 461, 0, 145, 0, 0, 600, 610, 344,
+ 614, 633, 0, 659, 0, 0, 0, 0, 354, 0,
+ 0, 136, 0, 638, 0, 0, 622, 662, 603, 607,
+ 147, 146, 142, 0, 663, 0, 0, 0, 0, 0,
+ 0, 0, 664, 0, 623, 604, 608, 143, 0, 0,
+ 639, 0, 0, 642, 643, 665, 624, 0, 0, 0
};
-static const short yydefgoto[] = { 1344,
- 1, 2, 119, 561, 977, 3, 4, 31, 32, 33,
- 299, 547, 548, 34, 91, 35, 570, 572, 571, 573,
- 569, 36, 37, 38, 411, 128, 129, 130, 338, 579,
- 580, 535, 581, 176, 39, 40, 41, 134, 261, 262,
- 302, 805, 303, 1141, 263, 978, 1271, 1206, 1226, 1227,
- 1326, 1267, 292, 786, 264, 444, 496, 750, 265, 266,
- 267, 293, 269, 506, 311, 43, 270, 456, 1043, 271,
- 272, 273, 274, 131, 275, 979, 401, 516, 770, 980,
- 45, 161, 981, 47, 162, 439, 163, 143, 155, 49,
- 628, 144, 1110, 402, 1184, 156, 1111, 50, 1031, 680,
- 681, 682, 1129, 1130, 1131, 960, 713, 714, 51, 539,
- 288, 903, 795, 52, 53, 54, 55, 180, 181, 56,
- 57, 58, 407, 644, 645, 646, 647, 183, 414, 415,
- 416, 417, 658, 664, 659, 1018, 660, 661, 1019, 1020,
- 536, 537, 497, 776, 59, 371, 372, 145, 60, 61,
- 146, 147, 113, 63, 507, 280, 281, 282, 65, 283,
- 67, 68, 179, 69, 284, 755, 756, 767, 519, 983,
- 984, 1151, 828, 829, 830, 347, 985, 986, 1074, 1242,
- 1153, 987, 988, 1179, 1075, 1243, 1076, 1244, 1108, 1286,
- 1324, 1109, 1287, 1325, 1275, 1219, 1277, 1162, 989, 1222,
- 1280, 1254, 1298, 1320, 1217, 1328, 990, 991, 992, 1090,
- 720, 1282, 1283, 1284, 1330, 364, 772, 366, 367, 368,
- 369, 107, 618, 1169, 676, 677, 434, 71, 72
+static const short yydefgoto[] = { 1348,
+ 1, 2, 119, 564, 982, 3, 4, 31, 32, 33,
+ 299, 548, 549, 550, 34, 91, 35, 573, 575, 574,
+ 576, 572, 36, 37, 38, 412, 128, 129, 130, 339,
+ 582, 583, 536, 584, 176, 39, 40, 41, 134, 261,
+ 262, 302, 809, 303, 1145, 263, 983, 1275, 1210, 1230,
+ 1231, 1330, 1271, 292, 789, 264, 445, 497, 753, 265,
+ 266, 267, 293, 269, 507, 312, 43, 270, 457, 1047,
+ 271, 272, 273, 274, 131, 275, 984, 402, 517, 773,
+ 985, 45, 161, 986, 47, 162, 440, 163, 143, 155,
+ 49, 631, 144, 1114, 403, 1188, 156, 1115, 50, 1035,
+ 683, 684, 685, 1133, 1134, 1135, 964, 716, 717, 51,
+ 540, 288, 906, 798, 52, 53, 54, 55, 180, 181,
+ 56, 57, 58, 408, 647, 648, 649, 650, 183, 415,
+ 416, 417, 418, 661, 667, 662, 1022, 663, 664, 1023,
+ 1024, 537, 538, 498, 779, 59, 372, 373, 145, 60,
+ 61, 146, 147, 113, 63, 508, 280, 281, 282, 65,
+ 283, 67, 68, 179, 69, 284, 758, 759, 770, 520,
+ 988, 989, 1155, 832, 833, 834, 348, 990, 991, 1078,
+ 1246, 1157, 992, 993, 1183, 1079, 1247, 1080, 1248, 1112,
+ 1290, 1328, 1113, 1291, 1329, 1279, 1223, 1281, 1166, 994,
+ 1226, 1284, 1258, 1302, 1324, 1221, 1332, 995, 996, 997,
+ 1094, 723, 1286, 1287, 1288, 1334, 365, 775, 367, 368,
+ 369, 555, 370, 107, 621, 1173, 679, 680, 435, 71,
+ 72
};
-static const short yypact[] = { 71,
- 88,-32768,-32768, 2859,-32768, 188,-32768, 266, 64,-32768,
--32768, 555,-32768,-32768, 140, 146,-32768, 235,-32768, 1989,
--32768, 237,-32768, 1666, 1666,-32768, 1814,-32768,-32768, 222,
--32768, 285, 3383,-32768,-32768,-32768,-32768, 201, 286, 315,
--32768,-32768, 80, 1865,-32768, 4890,-32768, 846, 619,-32768,
--32768, 142,-32768,-32768,-32768,-32768,-32768, 316, 1575,-32768,
--32768, 675,-32768,-32768,-32768, 347,-32768,-32768,-32768, 215,
- 3638,-32768,-32768,-32768,-32768, 8393, 4228,-32768, 266, 237,
- 284, 340, 315,-32768, 215,-32768, 215, 8393, 8393,-32768,
- 623,-32768, 237,-32768, 2940, 4475, 399, 215, 8393, 266,
- 2258,-32768, 410, 245, 2258,-32768, 420, 2904, 2904, 296,
- 325, 80, 331, 345, 348,-32768, 444, 361, 2291, 262,
- 2940, 9527, 664, 847, 375, 475,-32768, 382, 149, 119,
- 119,-32768,-32768, 387,-32768, 6095, 390,-32768, 3062, 3062,
- 4178, 1327, 637,-32768,-32768, 242,-32768,-32768, 347,-32768,
--32768,-32768,-32768, 846, 688,-32768, 1462,-32768,-32768,-32768,
- 959, 730,-32768,-32768, 2940,-32768,-32768,-32768,-32768,-32768,
--32768,-32768,-32768,-32768,-32768,-32768, 315, 871,-32768, 443,
- 443,-32768, 2169,-32768, 730,-32768, 469, 861,-32768,-32768,
--32768,-32768, 3286,-32768, 155,-32768, 419, 499,-32768,-32768,
--32768,-32768, 463,-32768,-32768,-32768,-32768,-32768,-32768,-32768,
+static const short yypact[] = { 203,
+ 236,-32768,-32768, 1874,-32768, 85,-32768, 55, 300,-32768,
+-32768, 590,-32768,-32768, -23, 252,-32768, 365,-32768, 1493,
+-32768, 355,-32768, 963, 963,-32768, 2214,-32768,-32768, 349,
+-32768, 429, 3939,-32768,-32768,-32768,-32768, 279, 435, 443,
+-32768,-32768, 396, 1052,-32768, 9215,-32768, 704, 30,-32768,
+-32768, 698,-32768,-32768,-32768,-32768,-32768, 488, 1610,-32768,
+-32768, 410,-32768,-32768,-32768, 397,-32768,-32768,-32768, 89,
+ 6309,-32768,-32768,-32768,-32768, 8124, 2133,-32768, 55, 355,
+ 461, 515, 443,-32768, 89,-32768, 89, 8124, 8124,-32768,
+ 363,-32768, 355,-32768, 3239, 4205, 230, 89, 7950, 55,
+ 2347,-32768, 484, 103, 2347,-32768, 92, 2356, 2356, 479,
+ 501, 396, 514, 519, 540,-32768, 629, 555, 2912, 144,
+ 3239, 9396, 593, 706, 572, 666,-32768, 149, 306, 57,
+ 57,-32768,-32768, 575,-32768, 4662, 589,-32768, 3833, 3833,
+ 3542, 1266, 393,-32768,-32768, 408,-32768,-32768, 397,-32768,
+-32768,-32768,-32768, 704, 536,-32768, 1285,-32768,-32768,-32768,
+ 907, 654,-32768,-32768, 3239,-32768,-32768,-32768,-32768,-32768,
+-32768,-32768,-32768,-32768,-32768,-32768, 443, 719,-32768, 617,
+ 617,-32768, 2447,-32768, 654,-32768, 608, 875,-32768,-32768,
+-32768,-32768, 4014,-32768, 56,-32768, 609, 647,-32768,-32768,
+-32768,-32768, 683,-32768,-32768,-32768,-32768,-32768,-32768,-32768,
-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,
--32768,-32768,-32768,-32768,-32768, 485,-32768,-32768, 730, 1575,
- 342, 504,-32768,-32768, 3906, 9334, 542, 573,-32768,-32768,
--32768,-32768,-32768,-32768, 577, 588, 616, 643, 646, 420,
- 9085,-32768,-32768, 9085,-32768,-32768, 9085, 6659, 4696,-32768,
- 41,-32768, 9085,-32768, 8480,-32768,-32768, 9696,-32768, 898,
- 3155, 8563,-32768, 678, 713,-32768, 1174, 2042, 3006,-32768,
- 157,-32768, 393, 808, 2940, 399,-32768, 420, 622,-32768,
- 630, 666, 9604, 647, 656, 674, 780,-32768, 4228,-32768,
- 443,-32768,-32768, 282,-32768, 195,-32768,-32768,-32768,-32768,
--32768, 2258,-32768,-32768, 2258,-32768,-32768,-32768, 3286, 42,
--32768, 686, 4228,-32768,-32768,-32768,-32768, 375, 732,-32768,
--32768,-32768,-32768,-32768,-32768, 589,-32768, 209,-32768, 6749,
- 8650,-32768, 119, 119, 745,-32768,-32768,-32768,-32768,-32768,
- 803, 721,-32768,-32768, 666, 726, 9604, 74, 2165, 9527,
- 2165, 3271, 3772, 742,-32768, 143, 9420, 763, 776,-32768,
- 749, 8650, 3372,-32768, 3372,-32768, 3542, 3542, 748,-32768,
--32768,-32768, 861, 2940,-32768,-32768, 6197, 751,-32768, 4114,
- 959, 846, 2940,-32768,-32768,-32768, 861,-32768,-32768,-32768,
- 375,-32768,-32768,-32768,-32768, 764,-32768,-32768,-32768, 8650,
- 39, 1890, 9437, 72, 1839,-32768, 269, 375, 730, 3218,
- 759, 832,-32768,-32768,-32768, 794, 801,-32768,-32768,-32768,
--32768, 229,-32768,-32768, 8650, 504, 6659,-32768, 191, 6659,
--32768, 8650, 8737, 9085, 8393, 3218, 3218, 3218, 3218,-32768,
--32768,-32768,-32768, 767, 790, 745, 812,-32768, 8393,-32768,
--32768, 2485, 6659,-32768, 8650, 8650, 6839, 8650, 8650, 8650,
- 8650, 8650, 8650, 8650, 8650, 8650, 8650, 8650, 8650, 8650,
- 8650, 8650, 8650, 8650, 8650, 8650,-32768,-32768,-32768,-32768,
--32768, 8650, 8650, 8650, 8393, 997, 558, 225, 7388,-32768,
--32768, 266, 873, 920,-32768, 477, 543, 631,-32768, 99,
- 99,-32768, 3482, 817, 848, 894,-32768,-32768, 539, 7863,
- 1305,-32768, 252,-32768,-32768, 8650,-32768,-32768,-32768,-32768,
- 174,-32768,-32768,-32768, 893, 905,-32768,-32768, 420,-32768,
- 7211, 7301,-32768,-32768,-32768,-32768, 320,-32768,-32768, 4012,
- 142,-32768,-32768,-32768,-32768,-32768,-32768,-32768, 897,-32768,
--32768,-32768, 589,-32768,-32768,-32768,-32768,-32768,-32768, 907,
- 927, 939, 942, 832,-32768,-32768, 237, 8650, 945,-32768,
- 559, 563, 567,-32768, 6299, 9673,-32768, 906, 119,-32768,
--32768,-32768, 36,-32768,-32768,-32768,-32768,-32768,-32768, 2346,
- 2346, 3148,-32768,-32768,-32768,-32768,-32768, 7954,-32768,-32768,
--32768,-32768,-32768,-32768,-32768,-32768, 944, 949, 6749,-32768,
--32768,-32768,-32768, 3372, 3372,-32768, 4114, 832,-32768, 803,
- 908, 912, 913,-32768, 911,-32768, 959,-32768, 832, 589,
--32768, 930,-32768, 962,-32768,-32768, 916,-32768, 9673,-32768,
--32768, 961, 639,-32768, 8650, 4879, 375, 970,-32768,-32768,
--32768, 594, 596, 971,-32768, 375, 969,-32768,-32768,-32768,
--32768,-32768, 535,-32768, 4103,-32768, 210, 444, 943, 976,
- 832,-32768,-32768,-32768, 424, 424, 424, 933, 934, 8824,
- 894, 935, 938, 141, 940,-32768, 950, 951, 974, 975,
- 985, 986,-32768,-32768, 955,-32768,-32768, 998, 849, 509,
- 8650, 1003,-32768, 991, 968, 9673, 9673,-32768,-32768, 1004,
- 9714, 9731, 9747, 4614, 4486, 2373, 3583, 1046, 1046, 1046,
- 1055, 1055, 800, 800, 540, 540, 540,-32768,-32768, 973,
- 966, 977, 980, 984, 3218, 558,-32768, 6749, 8650,-32768,
--32768,-32768, 8650,-32768,-32768, 983, 9085, 982, 995, 1035,
--32768, 8650,-32768, 8650,-32768, 467,-32768, 467,-32768, 70,
- 989, 990,-32768, 988, 3218, 803,-32768, 803, 719,-32768,
- 1540, 993, 8045, 8045, 5119, 994, 8480, 296, 1000, 348,
- 808, 1001, 8650, 420, 996, 905,-32768, 9673,-32768, 9673,
- 4228,-32768, 428, 1040, 316,-32768, 832,-32768,-32768,-32768,
--32768, 732, 1005,-32768, 209,-32768, 8650,-32768, 8650,-32768,
- 8650,-32768, 24,-32768,-32768, 420,-32768, 5723, 1071,-32768,
- 803, 803, 2634, 2634, 2729, 2729,-32768, 347,-32768, 2804,
- 8132, 8132, 5993, 317, 1007, 412, 803, 6749, 6749,-32768,
- 1048,-32768,-32768,-32768,-32768, 1052, 832, 8393, 764,-32768,
--32768,-32768, 8650, 8650, 68, 9579, 1009,-32768, 1369, 589,
- 589, 2412, 731, 2580, 832, 3218,-32768, 60, 1025,-32768,
--32768,-32768,-32768,-32768,-32768,-32768, 9168, 9168,-32768,-32768,
--32768,-32768,-32768,-32768, 1027, 1038, 1047, 1053,-32768, 9555,
- 6749, 6389, 1033,-32768, 8650,-32768,-32768,-32768,-32768, 536,
- 1041,-32768,-32768, 1042, 265, 273, 273, 1049, 273,-32768,
--32768, 9085, 1139,-32768, 1044, 1051,-32768,-32768,-32768,-32768,
--32768,-32768, 803, 1056,-32768, 1050, 8219, 8219,-32768,-32768,
- 821,-32768, 9673,-32768,-32768, 1057,-32768, 435, 2169, 732,
--32768,-32768,-32768, 1059, 1061, 1063, 6479,-32768,-32768, 705,
- 354, 1099,-32768,-32768,-32768, 1084,-32768, 8650, 1114, 1119,
- 1120, 8306, 329, 524,-32768, 1127, 1177, 1129,-32768, 4142,
- 9510, 2148, 5029,-32768,-32768, 1178,-32768,-32768,-32768, 7491,
--32768,-32768,-32768, 2634, 2634,-32768, 2804, 1719,-32768,-32768,
--32768, 803, 803, 803,-32768, 1130, 1089, 1092,-32768, 9579,
- 9579,-32768,-32768,-32768, 1136, 899, 8650,-32768,-32768,-32768,
- 375, 375, 832, 832,-32768, 1978,-32768,-32768,-32768, 569,
- 6749, 8650, 8650, 8650, 8650, 6749,-32768, 8650, 1137,-32768,
--32768, 4942, 387, 8650,-32768, 536,-32768,-32768,-32768,-32768,
--32768,-32768, 1094,-32768, 1159,-32768,-32768, 803,-32768,-32768,
--32768,-32768, 83,-32768,-32768,-32768,-32768,-32768, 420,-32768,
--32768,-32768,-32768,-32768,-32768, 745, 6569, 1117, 5185,-32768,
--32768,-32768,-32768, 1151, 8650, 1152,-32768,-32768,-32768, 1122,
--32768,-32768, 31, 750,-32768, 787, 375, 8911, 34, 900,
- 362,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768, 6749,
- 6749,-32768,-32768,-32768,-32768,-32768, 68, 8650, 8650, 9579,
- 589, 589, 1153, 1154,-32768,-32768,-32768,-32768, 330,-32768,
- 1126,-32768, 1113, 1115, 1121, 1131,-32768, 9627, 6749, 387,
--32768, 1111,-32768,-32768,-32768, 803,-32768,-32768, 582, 582,
- 7773,-32768, 1204, 1165, 1138,-32768, 1166,-32768, 8393, 8650,
--32768, 7593,-32768, 1168,-32768,-32768, 444,-32768, 589,-32768,
--32768, 589, 9251, 9251, 6929,-32768,-32768,-32768, 745, 7019,
- 7019,-32768,-32768, 6749,-32768, 9579, 9579,-32768, 832, 832,
- 6749, 6749, 569, 1142, 8998,-32768,-32768,-32768,-32768, 6749,
--32768,-32768,-32768,-32768, 8393,-32768,-32768,-32768,-32768,-32768,
--32768, 5813,-32768,-32768, 1144, 257, 2940, 9650, 7593,-32768,
--32768, 5271, 53,-32768,-32768, 1176,-32768, 1191,-32768,-32768,
--32768, 1190, 1192,-32768,-32768,-32768,-32768, 380, 1149,-32768,
- 1156, 745, 7683, 585, 423, 5411,-32768, 375,-32768,-32768,
- 434,-32768, 5515,-32768, 1245, 1208,-32768,-32768, 6749, 6749,
- 8650,-32768,-32768,-32768,-32768, 48,-32768,-32768,-32768, 8650,
- 1209,-32768, 1213,-32768, 745, 589, 7593,-32768,-32768,-32768,
- 1183, 8, 1217,-32768,-32768, 7109, 7109,-32768,-32768, 1173,
--32768, 5903, 1184,-32768,-32768, 832,-32768, 1187, 8650, 1245,
- 1223, 1245, 1188, 1189,-32768, 498, 5619,-32768, 1222,-32768,
- 1195, 239,-32768,-32768,-32768,-32768,-32768,-32768,-32768, 1201,
--32768, 1283, 1237, 7683, 7683, 6749, 4122, 745,-32768, 436,
--32768,-32768,-32768,-32768, 1196, 1199,-32768, 1294, 1248,-32768,
--32768,-32768,-32768, 1306, 1307,-32768
+-32768,-32768,-32768,-32768,-32768, 601,-32768,-32768, 654, 1610,
+ 351, 657,-32768,-32768, 3117, 9065, 660, 662,-32768,-32768,
+-32768,-32768,-32768,-32768, 665, 690, 692, 699, 703, 92,
+ 8816,-32768,-32768, 8816,-32768,-32768, 8816, 6393, 9148,-32768,
+ 29,-32768, 8816,-32768, 8211,-32768,-32768, 9444,-32768, 1334,
+ 2712, 8294,-32768, 767, 557,-32768, 160, 2819, 9439,-32768,
+ 266,-32768, 579, 809, 3239, 230,-32768, 92, 685,-32768,
+ 684, 738, 9497, 693, 697, 701, 808,-32768, 2133,-32768,
+ 617,-32768,-32768,-32768, 154,-32768, 139,-32768,-32768,-32768,
+-32768,-32768, 2347,-32768,-32768, 2347,-32768,-32768,-32768, 4014,
+ 50,-32768, 711, 2133,-32768,-32768,-32768,-32768, 572, 766,
+-32768,-32768,-32768,-32768,-32768,-32768, 656,-32768, 254,-32768,
+ 6483, 8381,-32768, 57, 57, 765,-32768,-32768,-32768,-32768,
+-32768, 818, 730,-32768,-32768, 738, 735, 9497, 328, 1775,
+ 9396, 1775, 4904, 4548, 737,-32768, 72, 9289, 763, 787,
+-32768, 746, 8381, 4250,-32768, 4250,-32768, 4314, 4314, 753,
+-32768,-32768,-32768, 875, 3239,-32768,-32768, 5854, 752,-32768,
+ 4433, 907, 704, 3239,-32768,-32768,-32768, 875,-32768,-32768,
+-32768, 572,-32768,-32768,-32768,-32768, 1191,-32768,-32768,-32768,
+ 8381, 156, 1389, 9306, 54, 2311,-32768, 167, 572, 654,
+ 2569, 771, 831,-32768,-32768,-32768, 773, 777,-32768,-32768,
+-32768,-32768, 169,-32768,-32768, 8381, 657, 6393,-32768, 381,
+ 6393,-32768, 8381, 8468, 8816, 8124, 2569, 2569, 2569, 2569,
+-32768,-32768,-32768,-32768, 782, 784, 765, 793,-32768, 8124,
+-32768,-32768, 3487, 6393,-32768, 8381, 8381, 3006, 8381, 8381,
+ 8381, 8381, 8381, 8381, 8381, 8381, 8381, 8381, 8381, 8381,
+ 8381, 8381, 8381, 8381, 8381, 8381, 8381,-32768,-32768,-32768,
+-32768,-32768, 8381, 8381, 8381, 8124, 3398, 497, 109, 7032,
+-32768,-32768, 55, 848, 896,-32768, 387, 415, 592,-32768,
+ 388, 388,-32768, 3838, 798, 817, 864,-32768,-32768, 412,
+ 7507, 1099,-32768, 251,-32768,-32768, 8381,-32768,-32768,-32768,
+-32768, 597,-32768,-32768,-32768, 851, 855,-32768,-32768, 92,
+-32768, 6855, 6945,-32768,-32768,-32768,-32768, 419, 859,-32768,
+-32768, 9200, 698,-32768,-32768, 862,-32768,-32768,-32768,-32768,
+-32768, 865,-32768,-32768,-32768, 656,-32768,-32768,-32768,-32768,
+-32768,-32768, 866, 868, 869, 870, 831,-32768,-32768, 355,
+ 8381, 877,-32768, 434, 438, 462,-32768, 5956, 9590,-32768,
+ 836, 57,-32768,-32768,-32768, 20,-32768,-32768,-32768,-32768,
+-32768,-32768, 1506, 1506, 3333,-32768,-32768,-32768,-32768,-32768,
+ 7598,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,
+ 887, 6483,-32768,-32768,-32768,-32768, 4250, 4250,-32768, 4433,
+ 831,-32768, 818, 849, 856, 861,-32768, 863,-32768, 907,
+-32768, 831, 656,-32768, 881,-32768, 899,-32768,-32768, 1243,
+-32768, 9590,-32768,-32768, 912, 146,-32768, 8381, 2808, 572,
+ 921,-32768,-32768,-32768, 368, 407, 922,-32768, 572, 920,
+-32768,-32768,-32768,-32768,-32768, 551,-32768, 4154,-32768, 187,
+ 629, 897, 926, 831,-32768,-32768,-32768, 505, 505, 505,
+ 885, 886, 8555, 864, 895, 900, 248, 901,-32768, 906,
+ 909, 919, 942, 943, 945,-32768,-32768, 918,-32768,-32768,
+ 962, 553, 136, 8381, 969,-32768, 968, 928, 9590, 9590,
+-32768,-32768, 973, 9629, 4583, 9645, 9660, 5903, 6801, 3406,
+ 1324, 1324, 1324, 1664, 1664, 814, 814, 640, 640, 640,
+-32768,-32768, 932, 934, 940, 935, 946, 2569, 497,-32768,
+ 6483, 8381,-32768,-32768,-32768, 8381,-32768,-32768, 955, 8816,
+ 944, 964, 1008,-32768, 8381,-32768, 8381,-32768, 890,-32768,
+ 890,-32768, 65, 951, 952,-32768, 953, 2569, 818,-32768,
+ 818, 2046,-32768, 1065, 957, 7689, 7689, 4811, 966, 8211,
+ 479, 972, 540, 809, 974, 8381, 92, 961, 855,-32768,
+ 9590,-32768, 9590, 2133,-32768, 664, 520, 6483, 488,-32768,
+ 831,-32768,-32768,-32768,-32768, 766, 978,-32768, 254,-32768,
+ 8381,-32768, 8381,-32768, 8381,-32768, 9,-32768,-32768, 92,
+-32768, 5584, 1032,-32768, 818, 818, 2757, 2757, 3282, 3282,
+-32768, 397,-32768, 3954, 7776, 7776, 5016, 174, 979, 244,
+ 818, 6483,-32768, 1030,-32768,-32768,-32768,-32768, 1037, 831,
+ 8124, 1191,-32768,-32768,-32768, 8381, 8381, 74, 9521, 995,
+-32768, 2416, 656, 656, 3185, 603, 3228, 831, 2569,-32768,
+ 52, 1011,-32768,-32768,-32768,-32768,-32768,-32768,-32768, 8899,
+ 8899,-32768,-32768,-32768,-32768,-32768,-32768, 1013, 1014, 1019,
+ 1022,-32768, 9472, 6483, 6046, 1009,-32768, 8381,-32768,-32768,
+-32768,-32768, 143, 1012,-32768,-32768, 1017, 75, 278, 278,
+ 1006, 278,-32768,-32768, 8816, 1107,-32768, 1018, 1020,-32768,
+-32768,-32768,-32768,-32768,-32768, 818, 1023,-32768, 1010, 7863,
+ 7863,-32768,-32768, 584,-32768, 9590,-32768,-32768, 1021,-32768,
+-32768,-32768, 2447, 766,-32768,-32768,-32768, 1024, 1026, 1036,
+ 6136,-32768,-32768, 668, 231, 1061, 567,-32768,-32768,-32768,
+ 1046,-32768, 8381, 1079, 1085, 1088, 8037, 73, 476,-32768,
+ 1093, 1139, 1094,-32768, 1971, 9379, 2582, 3725,-32768,-32768,
+ 1135,-32768,-32768,-32768, 7135,-32768,-32768,-32768, 2757, 2757,
+-32768, 3954, 1989,-32768,-32768, 818, 818, 818,-32768, 1095,
+ 1053, 1054,-32768, 9521, 9521,-32768,-32768,-32768, 1103, 661,
+ 8381,-32768,-32768,-32768, 572, 572, 831, 831,-32768, 2607,
+-32768,-32768,-32768, 801, 6483, 8381, 8381, 8381, 8381, 6483,
+-32768, 8381, 1104,-32768,-32768, 9611, 575, 8381,-32768, 143,
+-32768,-32768,-32768,-32768,-32768,-32768, 1062,-32768, 1122,-32768,
+-32768, 818,-32768,-32768,-32768, 66,-32768,-32768,-32768,-32768,
+-32768, 92,-32768,-32768,-32768,-32768,-32768,-32768,-32768, 765,
+ 6226, 1082, 5075,-32768,-32768,-32768,-32768, 1115, 8381, 1121,
+-32768,-32768,-32768, 1090,-32768,-32768, 238, 672,-32768, 772,
+ 572, 8642, 459, 774, 258,-32768,-32768,-32768,-32768,-32768,
+-32768,-32768,-32768, 6483, 6483,-32768,-32768,-32768,-32768,-32768,
+ 74, 8381, 8381, 9521, 656, 656, 1124, 1126,-32768,-32768,
+-32768,-32768, 269,-32768, 1091,-32768, 1084, 1087, 1097, 1098,
+-32768, 9544, 6483, 575,-32768, 1089,-32768,-32768,-32768, 818,
+-32768,-32768, 509, 509, 7417,-32768, 1175, 1137, 1100,-32768,
+ 1141,-32768, 8124, 8381,-32768, 7237,-32768, 1146,-32768,-32768,
+ 629,-32768, 656,-32768,-32768, 656, 8982, 8982, 6573,-32768,
+-32768,-32768, 765, 6663, 6663,-32768,-32768, 6483,-32768, 9521,
+ 9521,-32768, 831, 831, 6483, 6483, 801, 1102, 8729,-32768,
+-32768,-32768,-32768, 6483,-32768,-32768,-32768,-32768, 8124,-32768,
+-32768,-32768,-32768,-32768,-32768, 5674,-32768,-32768, 1109, 234,
+ 3239, 9567, 7237,-32768,-32768, 5168, 48,-32768,-32768, 1149,
+-32768, 1150,-32768,-32768,-32768, 1160, 1163,-32768,-32768,-32768,
+-32768, 282, 1123,-32768, 1127, 765, 7327, 518, 295, 5272,
+-32768, 572,-32768,-32768, 296,-32768, 5376,-32768, 1214, 1168,
+-32768,-32768, 6483, 6483, 8381,-32768,-32768,-32768,-32768, 37,
+-32768,-32768,-32768, 8381, 1176,-32768, 1177,-32768, 765, 656,
+ 7237,-32768,-32768,-32768, 1147, 201, 1181,-32768,-32768, 6753,
+ 6753,-32768,-32768, 1143,-32768, 5764, 1148,-32768,-32768, 831,
+-32768, 1158, 8381, 1214, 1183, 1214, 1151, 1152,-32768, 317,
+ 5480,-32768, 1198,-32768, 1156, 246,-32768,-32768,-32768,-32768,
+-32768,-32768,-32768, 1153,-32768, 1254, 1208, 7327, 7327, 6483,
+ 1355, 765,-32768, 353,-32768,-32768,-32768,-32768, 1167, 1170,
+-32768, 1271, 1219,-32768,-32768,-32768,-32768, 1281, 1282,-32768
};
static const short yypgoto[] = {-32768,
- 1193,-32768,-32768, 992, 18, 1303,-32768,-32768,-32768,-32768,
--32768,-32768, 513,-32768,-32768,-32768,-32768,-32768,-32768,-32768,
- -756, 1200, 1202,-32768,-32768,-32768,-32768, 1181,-32768,-32768,
- 503, 0,-32768, 771,-32768, 3899, -26,-32768, 1226, 867,
- -998,-32768, -84, 187,-32768, 196,-32768, 179, 150, -1074,
--32768, -350, 929, 118, 753,-32768,-32768, -703, 2564, 926,
- -251, 2283, 2895, 822, 618, 425,-32768,-32768,-32768,-32768,
- -248,-32768, -108, -83,-32768, 255, 17, -273, 82, 21,
- -121, -120, -3, 1868, 46, 1413, -98, -418, 352,-32768,
- -160,-32768,-32768, 207,-32768,-32768,-32768,-32768,-32768, 66,
--32768, 653,-32768, 144,-32768,-32768, 394, 756, 29,-32768,
--32768,-32768, 546, -261, 37, 1302, 1310,-32768,-32768,-32768,
--32768,-32768, -116,-32768, 479, -614,-32768, 531, 395, 471,
- -409,-32768,-32768,-32768,-32768,-32768,-32768, 941,-32768, 474,
- 809, 553, 860, 1539, 1625, -357,-32768, 2462, -63, 20,
--32768, 4399, -90, 441,-32768, 3481,-32768,-32768, 4001, -4,
- 154, -311, 1345, 3650, 789, -169,-32768, 4093,-32768, -1136,
- -924, -335, 92,-32768, 532, -92, -128,-32768,-32768,-32768,
- -1121, -930, -1102,-32768,-32768,-32768,-32768,-32768,-32768,-32768,
+ 1165,-32768,-32768, 958, 7, 1283,-32768,-32768,-32768,-32768,
+-32768,-32768,-32768, 486,-32768,-32768,-32768,-32768,-32768,-32768,
+-32768, -773, 1169, 1174,-32768,-32768,-32768,-32768, 1166,-32768,
+-32768, 478, 126,-32768,-32768,-32768, 4325, -30,-32768, 1204,
+ 844, -998,-32768, -96, 162,-32768, 171,-32768, 153, 124,
+ -980,-32768, -480, 242, 564, 630,-32768,-32768, -722, 3685,
+ 1316, -262, 2309, 2833, 804, 159, 431,-32768,-32768,-32768,
+-32768, -278,-32768, -110, -90,-32768, 233, 34, -210, 83,
+ 11, -91, -121, -3, 1446, -82, 1348, -127, -674, 329,
+-32768, -186,-32768,-32768, 180,-32768,-32768,-32768,-32768,-32768,
+ 1092,-32768, 634,-32768, 122,-32768,-32768, 821, 742, 14,
+-32768,-32768,-32768, 526, -285, 12, 1299, 1300,-32768,-32768,
+-32768,-32768,-32768, -131,-32768, 473, 686,-32768, 533, 394,
+ 469, -411,-32768,-32768,-32768,-32768,-32768,-32768, 939,-32768,
+ 482, 829, 573, 857, 1683, 1544, -371,-32768, 1375, 0,
+ 1,-32768, 4129, -99, 646,-32768, 3274,-32768,-32768, 3935,
+ -4, 198, -327, 1336, 3574, 852, -188,-32768, 1912,-32768,
+ -1147, -942, -321, 101,-32768, 539, -106, -94,-32768,-32768,
+-32768, -1132, -932, -1108,-32768,-32768,-32768,-32768,-32768,-32768,
-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,
--32768,-32768,-32768,-32768, -24,-32768,-32768,-32768,-32768,-32768,
- -281, 67,-32768, 76,-32768, -343, -132,-32768,-32768, -289,
- -286,-32768,-32768, 40, 490,-32768, -18,-32768, -247
+-32768,-32768,-32768,-32768,-32768, -43,-32768,-32768,-32768,-32768,
+-32768, -421, 70,-32768, 69,-32768, -369, -132,-32768,-32768,
+ -258, 1015, -247,-32768,-32768, 60, 500,-32768, 127,-32768,
+ -260
};
-#define YYLAST 9826
+#define YYLAST 9739
static const short yytable[] = { 66,
- 46, 348, 348, 365, 521, 670, 194, 85, 320, 552,
- 593, 82, 553, 464, 359, 85, 96, 313, 316, 103,
- 103, 30, 103, 290, 44, 178, 583, 422, 66, 122,
- 635, 84, 862, 391, 194, 529, 532, 551, 349, 149,
- 95, 66, 912, 633, 1140, 344, 231, 85, 1208, 350,
- 501, 175, 1104, 121, 85, 951, 97, 1224, 1103, 1107,
- 142, 501, 399, 400, 408, 195, 85, 1300, 501, 826,
- -1, 84, 85, 96, 423, 1246, 164, 552, 957, 596,
- 617, 826, 85, 596, 1215, 1253, 1168, -2, 521, 1176,
- 149, 85, 650, 85, 648, 459, 103, 285, 651, 306,
- 103, 188, 100, 103, 103, 11, 310, 667, 77, 1301,
- 460, 300, 1255, 286, 66, 46, 149, 66, 667, 345,
- 1265, -694, 187, 135, 597, 187, 958, -694, 597, 598,
- 1241, -690, 360, 598, 149, 149, 149, 328, 827, 44,
- 1268, 1140, 509, 559, 78, 79, 167, 168, 169, 21,
- 1291, 93, 611, 1295, 1256, 1307, 774, 276, 8, 187,
- 149, 1029, 599, 510, 336, 691, 599, 136, 137, 294,
- 296, 706, 346, 511, 668, 574, 170, 359, 66, 413,
- 276, 383, 164, 512, 554, 1147, 513, 514, 103, 164,
- 164, 75, 21, 1064, 80, 171, 397, 612, 100, 392,
- 525, 534, 613, 412, 342, 421, 1045, 93, 127, 76,
- 240, 575, 8, 164, 348, 348, 592, 358, 8, 192,
- 194, 1268, 1268, 126, 21, 85, 432, 88, 100, 425,
- 419, 1220, 100, 89, 509, 614, 639, 90, 192, 172,
- 173, 174, 891, 73, 526, 359, 498, 93, 100, 450,
- 590, 591, 576, 356, 365, 8, 192, 164, 589, 21,
- 127, 577, 159, 160, 876, 359, 85, 93, 12, 425,
- 508, 637, 432, 432, 523, 21, 100, 93, 690, 423,
- 149, 93, 529, 291, 295, 386, 313, 316, 1250, 751,
- 74, 17, 399, 400, 85, 360, 578, 93, 1322, 752,
- 509, 533, 192, 189, 93, 99, 164, 103, 509, 117,
- 103, 877, 867, 753, 103, 1104, 75, 326, 85, 96,
- 400, 1103, 1104, 21, 671, 93, 189, 705, 1103, 387,
- 388, 78, 308, 1062, 76, 648, 459, 751, 118, 457,
- 1323, 132, 1143, 95, 690, 100, 1297, 752, 192, 7,
- 8, 555, 690, 421, 149, 66, 149, 149, 523, 97,
- -226, 753, 66, 360, 327, 133, 1048, 563, 149, 182,
- 149, 672, 149, 149, 801, 603, 1104, 607, 609, 149,
- 549, 309, 1103, 360, 1193, 149, 287, 19, 149, 802,
- 164, 359, 21, 289, 93, 7, 8, -221, 359, 22,
- 421, 85, 807, 1085, -226, -226, 430, 149, 66, 1071,
- 66, 413, 7, 100, 421, 85, 431, 1071, -221, 164,
- 164, 189, 78, 308, 936, 339, 317, 100, 657, 26,
- 423, 1194, 318, 19, 1261, 412, 192, 934, 8, 340,
- 640, 85, 85, 85, 85, 22, -503, 164, 549, -222,
- 19, 112, 234, 455, -121, -227, 1072, 673, 588, 192,
- 348, 712, 22, 321, 1178, 642, 187, 114, 358, 341,
- 100, 498, 309, 184, 21, 26, 93, 337, 1071, 857,
- 359, 1262, -26, 301, 189, 21, 359, 93, 430, 1071,
- 1338, 85, 26, 432, 370, 301, 825, -26, 431, -227,
- -227, 674, 406, 583, 632, 432, 432, 426, 523, 360,
- 509, 552, 875, -222, 553, 66, 360, 21, 689, 93,
- 761, 692, 428, 365, 178, 1272, 698, 699, 700, 701,
- 702, 510, 112, 112, 359, 464, 1278, 1339, 399, 551,
- 276, 511, 529, 532, 715, 149, 85, 648, 114, 114,
- 803, 512, 688, 1071, 513, 514, 420, 78, 79, 13,
- 14, 1094, 1053, 1100, 762, 112, 609, 621, -101, 878,
- 84, 78, 308, 1125, 1126, 1127, 744, 99, 164, 747,
- 421, 114, 780, 1087, 712, 192, 763, 427, -79, 429,
- 629, 435, 99, 748, -79, 149, 149, 838, 360, 638,
- 1317, 747, 816, 838, 360, 21, 818, 80, 81, 740,
- 820, 742, 743, 13, 14, 748, 670, 485, 486, 149,
- 149, 309, 149, 749, 1044, 1204, 781, 782, 1269, 442,
- 764, 1078, 455, 7, 502, 455, 648, 693, 695, 812,
- 697, 691, 85, 792, 111, 749, 817, -282, 365, -283,
- 819, 838, 360, -282, 821, -283, 446, 421, 455, 359,
- 443, 192, 719, 359, 445, 164, 882, 883, 884, 1205,
- 432, 19, 1270, 165, 166, 186, 192, 297, 298, 359,
- 432, 432, 432, 22, 447, 187, 501, 187, 741, 75,
- 421, 384, 385, 851, 758, 813, 868, -694, 864, -694,
- -694, 870, 871, 164, 856, 873, -694, 76, 691, 1023,
- 1024, 448, 1024, 26, 449, 7, 502, 330, 503, 331,
- 541, 359, 100, 332, 538, 423, 314, 194, -694, -694,
- -694, 540, -694, 587, -694, 159, 160, 358, 1149, 1150,
- 85, 12, 393, 394, 313, 316, 1049, 1050, 543, 1052,
- 313, 316, 1166, 19, 564, 13, 14, 544, 111, 1069,
- 1070, 432, 509, 432, 17, 22, 187, 8, 641, 21,
- 85, 93, 1180, 1181, 432, 545, 85, 360, 66, 66,
- 66, 360, 546, 510, -78, 565, 941, 566, 560, 567,
- -78, 568, 70, 511, 642, 504, 85, 360, 346, 643,
- 87, 112, 112, 512, 384, 1170, 513, 514, 98, 423,
- 527, 8, 104, 104, 21, 104, 93, 114, 114, 1212,
- -689, 70, 594, 7, 8, 959, 911, 595, 149, 149,
- 149, 149, 104, 619, 70, 149, 838, 838, 838, 360,
- 87, 393, 1171, 610, 240, 528, 678, 98, 19, 626,
- 158, 159, 160, 620, 85, 634, 715, 12, 21, 98,
- 93, 19, 358, 679, 149, 98, 914, 103, 703, 66,
- 413, 85, 950, 22, 482, 483, 484, 485, 486, 925,
- 17, 926, 549, 104, 98, 13, 14, 421, 421, 104,
- 421, 704, -327, 104, 412, 425, 104, 104, 683, 75,
- 333, 1039, 334, 26, 1012, 684, 335, 70, -100, 104,
- 70, 432, 432, 706, 432, -327, -327, 76, -327, 8,
- 860, 773, 1006, 759, 403, 760, 404, 104, 104, 104,
- 405, 1013, 66, 66, 954, 775, 955, 777, 956, 1008,
- 1027, 487, 691, 85, 66, 413, 642, 1152, 918, 75,
- 793, 861, 806, 104, 384, 1177, 1039, 674, 1119, 794,
- 1189, 1190, 808, 398, 159, 160, 21, 76, 93, 412,
- 12, 70, 1086, 1332, 1333, 149, 66, 149, 488, 489,
- 455, 104, 809, 490, 491, 492, 493, 438, 441, 149,
- 149, 192, 149, 17, 810, 314, 1093, 811, 1099, 815,
- 8, 848, 10, 11, 1303, 1304, 849, 824, 12, 852,
- 164, 639, 850, 853, 854, 855, 859, 858, 98, 104,
- 863, 66, 413, 15, 869, 872, 112, 16, 874, 1128,
- 879, 17, 112, 880, 885, 886, 889, 552, 455, 890,
- 1336, 892, 114, 895, 896, 902, 412, 21, 114, 93,
- 1152, 893, 894, 1007, 897, 898, 899, -99, 1223, 98,
- 1121, 1122, 901, 905, 355, 104, 104, 70, 1148, 904,
- 907, 920, 531, 104, 906, 1115, 1116, 923, 924, 908,
- 112, 909, 313, 316, 745, 910, 922, 98, 1123, 1124,
- 929, 930, 931, 838, 192, 939, 114, 935, 945, 948,
- 104, 940, 942, 104, 826, 1001, 952, 104, 998, 1005,
- 1014, 98, 1030, 1152, 1032, 1296, 478, 479, 480, 481,
- 482, 483, 484, 485, 486, 1033, 98, 480, 481, 482,
- 483, 484, 485, 486, 1034, 1041, 1172, 789, 421, 421,
- 1035, 913, 1046, 1047, 1055, 1056, 1152, 104, 70, 104,
- 104, 70, 1057, 1051, 1060, 70, 1185, 1059, 1073, 1061,
- 1065, 104, 1066, 104, 1067, 104, 104, 1084, 838, 838,
- 838, 1077, 104, 1080, 1081, 1082, 451, 100, 104, 452,
- 1088, 104, 453, 1089, 1091, 1188, 421, 1112, 461, 421,
- 1113, 1105, 1128, 1114, 98, 1118, 1139, 500, 1144, 1337,
- 104, 70, 1145, 70, 1159, 359, 1163, 1165, 98, 1167,
- 1191, 1192, 149, 1195, 1196, 1203, 1197, 509, 1209, 111,
- 1210, 1213, 1198, 1221, 21, 845, 93, 1133, 1134, 1135,
- 1136, 1257, 1199, 1248, 98, 98, 98, 98, 510, 1142,
- 1211, 999, 1000, 1237, 164, 1247, 1258, 1259, 511, 1260,
- 1263, 1230, 1231, 1281, 1232, 1233, 457, 1264, 512, 112,
- 112, 513, 514, 1285, 1294, 112, 112, 112, 1071, 355,
- 1299, 1302, 1157, 111, 1305, 114, 114, 1310, 1313, 1319,
- 1164, 114, 114, 114, 98, 1308, 104, 1276, 1327, 1315,
- 1316, 1329, 1331, 421, 1037, 1040, 1321, 1340, 104, 104,
- 1341, 70, 1342, 1343, 5, 1345, 1346, 789, 791, 343,
- 322, -468, 1239, 947, -468, 355, 562, 953, 324, 531,
- 325, 804, 85, 360, 304, 707, 1202, 381, 1207, 765,
- 1228, 1158, 1096, 881, 123, 949, 1236, 1009, 104, 87,
- 823, 946, 124, 1063, 1026, 1025, 944, 796, 777, -694,
- 1040, -694, -694, 665, 1214, 746, 86, 1292, -694, -468,
- 993, 1309, -468, 355, -468, 1028, 1312, 0, 0, 696,
- 455, 1015, 1016, 0, -468, 1214, 1214, 1314, 1290, 0,
- -694, -694, 382, 0, -694, 0, -694, 0, 104, 104,
- 70, 0, -468, -468, 0, 0, 791, -468, 0, 0,
- 1214, 314, 0, 0, 0, 0, -468, 0, 549, 19,
- 0, 0, 104, 104, 0, 104, 48, 0, 187, 21,
- 355, 22, 355, 355, 1132, 0, 0, 0, 1017, 1137,
- 0, 0, 48, 139, 0, 98, 0, 0, 0, 0,
- 0, 0, 0, 140, 70, 48, 0, 0, 355, 0,
- 0, 26, 0, 314, 355, 0, 141, 0, 154, 314,
- 111, 0, 395, 104, 0, 1293, 0, 0, 0, 0,
- 0, 185, 0, 104, 104, 104, 0, 0, 0, 0,
- 0, 719, 719, 229, -694, 0, -694, -694, 278, 48,
- 0, 0, 0, -694, 1311, 0, 0, 0, 0, 0,
- 278, 278, 0, 1182, 1183, 314, 355, 0, 154, 0,
- 0, 278, 0, 0, 0, -694, -694, 396, 0, -694,
- 0, -694, 112, 0, 0, 0, 0, 0, 0, 0,
- 0, 48, 1201, 98, 154, 0, 355, 0, 114, 0,
- 0, 0, 0, 8, 92, 10, 11, 0, 362, 353,
- 0, 12, 0, 187, 104, 0, 104, 0, 0, 0,
- 0, 0, 0, 98, 0, 0, 15, 104, 0, 98,
- 16, 791, 791, 791, 17, 0, 0, 1229, 8, 531,
- 10, 184, 0, 0, 1234, 1235, 12, 0, 0, 98,
- 21, 0, 93, 1240, 0, 48, 0, 112, 112, 112,
- 0, 15, 0, 98, 0, 16, 0, 193, 0, 17,
- 0, 0, 0, 114, 114, 114, 0, 0, 355, 0,
- 0, 104, 104, 104, 104, 21, 0, 93, 104, 791,
- 791, 791, 354, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 185, 0, 0, 0, 0, 98, 101, 105,
- 0, 0, 1288, 1289, 319, 0, 0, 104, 0, 0,
- 104, 0, 70, 0, 98, 0, 0, 0, 7, 100,
- 278, 0, 11, 351, 0, 0, 0, 355, 0, 0,
- 0, 0, 921, 229, 0, 0, 0, 0, 390, 0,
- 355, 185, 355, 0, 0, 230, 0, 0, 0, 0,
- 279, 0, 0, 0, 104, 104, 19, 104, 451, 452,
- 0, 550, 279, 279, 0, 845, 21, 0, 22, 1334,
- 0, 0, 0, 279, 0, 791, 791, 0, -508, 0,
- 24, 0, 312, 315, 0, 48, 98, 70, 0, 0,
- 25, 0, 0, -508, -508, 355, 0, 355, 26, 355,
- -508, 0, 0, 27, 0, 0, 0, 0, 0, 0,
- 363, 0, -508, 373, 375, 0, 451, 452, 104, 70,
- 104, 0, 154, -508, -508, 185, -508, 0, -508, 550,
- 0, 0, 104, 104, 0, 104, 0, 0, 0, 0,
- 0, 314, 111, 0, 0, 0, 0, 0, 0, 362,
- 0, 0, 0, 0, 0, 0, -508, -508, 0, 0,
- -508, -508, 451, 452, 70, 0, 7, 100, 0, 0,
- -508, 0, 0, 0, 0, 154, 0, 48, 0, 0,
- 0, 0, 675, 0, 0, 0, 0, 0, 0, 409,
- 0, 7, 8, 92, 10, 11, 0, 1054, 0, 278,
- 12, 0, 278, 0, 19, 0, 0, 278, 675, 675,
- 675, 675, 451, 452, 21, 15, 22, 7, 8, 16,
- 0, 278, 0, 17, -420, 278, 0, 0, 108, 19,
- 0, 0, 279, 0, 0, 0, 791, 0, 109, 21,
- 0, 22, 652, 653, 669, 230, 26, 0, 410, 0,
- 0, 27, 0, 24, 0, 19, 0, 278, 229, 0,
- 0, 0, 0, 25, 0, 21, 0, 22, 627, 0,
- 138, 26, 0, 363, 630, 550, 27, 0, 0, 139,
- 19, 0, 362, 654, 0, 0, 0, 0, 228, 140,
- 21, -420, 22, 277, 0, 0, 0, 26, 0, 655,
- 0, 0, 141, 0, 139, 277, 277, 0, 0, 0,
- 0, 791, 791, 791, 140, 0, 277, 0, 685, 686,
- 0, 687, 26, 0, 0, 0, 0, 656, 409, 0,
- 7, 8, 92, 10, 11, 0, 0, 0, 0, 12,
- 0, 363, 8, 92, 10, 11, 0, 0, 0, 0,
- 12, 624, 625, 361, 15, 104, 0, 0, 16, 0,
- 0, 363, 17, -421, 550, 15, 0, 0, 19, 16,
- 362, 0, 0, 17, 0, 0, 355, 0, 21, 0,
- 22, 0, 0, 669, 0, 0, 0, 410, 0, 21,
- 0, 93, 24, 0, 279, 100, 0, 159, 160, 0,
- 0, 0, 25, 12, 778, 779, 0, 94, 0, 778,
- 26, 279, 0, 0, 279, 27, 0, 0, 550, 279,
- 279, 279, 279, 279, 0, 0, 17, 0, 0, 0,
- -421, 0, 0, 279, 0, 509, 0, 279, 0, 0,
- 0, 0, 21, 0, 93, 0, 0, 0, 451, 452,
- 0, 0, 0, 0, 0, 0, 510, 0, 0, 0,
- 0, 0, 0, 0, 0, 98, 511, 0, 0, 279,
- 230, 0, 0, 355, 0, 277, 512, 0, 0, 520,
- 514, 0, 831, 832, 766, 768, 0, 363, 228, 0,
- 0, 0, 840, 0, 363, 0, 0, 0, 847, 0,
- 7, 8, 158, 159, 160, 0, 0, 675, 0, 12,
- 0, 915, 0, 0, 0, 0, 361, 7, 8, 409,
- 0, 7, 8, 92, 10, 11, 0, 0, 0, 0,
- 12, 0, 17, 0, 0, 0, 0, 675, 19, 355,
- 0, 509, 865, 550, 0, 15, 0, 362, 21, 16,
- 22, 0, 0, 17, -419, 19, 0, 0, 509, 19,
- 0, 0, 139, 550, 0, 21, 0, 22, 0, 21,
- 0, 22, 140, 0, 833, 834, 363, 0, 410, 600,
- 26, 0, 363, 24, 361, 1098, 0, 0, 0, 601,
- 982, 0, 0, 25, 0, 0, 0, 26, 0, 512,
- 0, 26, 602, 514, 361, 362, 27, 0, 0, 0,
- 7, 100, 0, 0, 184, 0, 0, 0, 0, 0,
- 278, -419, 0, 0, 0, 0, 0, 0, 0, 0,
- 363, 0, 0, 0, 0, 0, 48, 277, 675, 916,
- 917, 6, 919, 7, 8, 9, 10, 11, 19, 0,
- 0, 0, 12, 0, 277, 0, 0, 277, 21, 0,
- 22, 0, 277, 277, 277, 277, 277, 15, 933, 0,
- 0, 16, 24, 0, 0, 17, 277, 0, 0, 0,
- 277, 19, 25, 0, 0, 323, 0, 0, 0, 0,
- 26, 21, 0, 22, 0, 27, 23, 0, 7, 8,
- 0, 0, 11, 0, 0, 24, 0, 0, 268, 0,
- 0, 48, 277, 228, 0, 25, 0, 0, 0, 279,
- 0, 0, 0, 26, 0, 0, 0, 997, 27, 0,
- 361, 268, 0, 0, 28, 0, 19, 361, 0, 509,
- 1002, 1003, 1004, 154, 0, 982, 21, 0, 22, 279,
- 0, 0, 982, 0, 0, 363, 0, 766, 768, 363,
- 600, 0, 0, 0, 1015, 100, 0, 0, 357, 0,
- 601, 0, 0, 0, 0, 363, 0, 0, 26, 0,
- 512, 0, 0, 602, 514, 0, 0, 0, 48, 474,
- 475, 476, 477, 478, 479, 480, 481, 482, 483, 484,
- 485, 486, 19, 0, 0, 0, 0, 0, 0, 994,
- 995, 0, 21, 0, 22, 994, 995, 363, 1058, 361,
- 0, 1017, 0, 0, 0, 361, 24, 0, 0, 0,
- 0, 0, 279, 0, 0, 584, 25, 708, 709, 982,
- 10, 436, 233, 234, 26, 235, 12, 0, 0, 27,
- 279, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 15, 236, 237, 238, 16, 0, 239, 0, 17,
- 0, 240, 241, 361, 242, 19, 243, 244, 0, 0,
- 245, 246, 247, 248, 249, 21, 0, 710, 585, 0,
- 0, 458, 0, 0, 0, 0, 250, 0, 0, 251,
- 0, 0, 1117, 0, 0, 0, 0, 252, 253, 254,
- 0, 766, 768, 982, 0, 255, 256, 257, 0, 0,
- 0, 1216, 258, 711, 982, 0, 259, 0, 0, 0,
- 409, 0, 7, 8, 92, 10, 11, 278, 260, 0,
- 0, 12, 1216, 1216, 0, 0, 0, 1146, 0, 0,
- 374, 376, 379, 0, 0, 0, 15, 0, 0, 0,
- 16, 0, 277, 0, 17, -422, 0, 1216, 0, 0,
- 19, 0, 586, 357, 982, 0, 0, 0, 0, 0,
- 21, 982, 22, 0, 982, 0, 7, 8, 0, 410,
- 184, 0, 277, 0, 24, 0, 0, 0, 361, 0,
- 0, 0, 361, 0, 25, 982, 0, 0, 982, 0,
- 0, 0, 26, 0, 0, 982, 0, 27, 361, 357,
- 0, 0, 0, 0, 19, 0, 0, 509, 0, 0,
- 0, 0, -422, 0, 21, 0, 22, 0, 0, 982,
- 0, 0, 649, 0, 0, 0, 0, 0, 600, 0,
- 0, 0, 0, 0, 982, 0, 0, 0, 601, 0,
- 361, 0, 0, 0, 0, 0, 26, 357, 512, 982,
- 0, 602, 514, 0, 0, 277, 0, 0, 0, 0,
- 0, 7, 8, 0, 0, 11, 982, 982, 0, 550,
- 0, 268, 0, 277, 586, 0, 0, 716, 717, 0,
- 721, 722, 723, 724, 725, 726, 727, 728, 729, 730,
- 731, 732, 733, 734, 735, 736, 737, 738, 739, 19,
- 0, 0, 509, 0, 357, 0, 357, 357, 0, 21,
- 0, 22, 0, 230, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 835, 0, 0, 0, 624, 625, 279,
- 0, 0, 357, 836, 230, 230, 7, 8, 357, 0,
- 423, 26, 0, 512, 0, 0, 602, 514, 0, 0,
- 0, 0, 0, 798, 800, 0, 0, 0, 0, 230,
- 0, 0, 0, 0, 622, 0, 623, 0, 374, 376,
- 515, 515, 515, 0, 19, 0, 0, 509, 0, 0,
- 0, 636, 0, 0, 21, 0, 22, 0, 0, 6,
- 357, 7, 8, 9, 10, 11, 0, 586, 600, 0,
- 12, 0, 0, 662, 0, 0, 0, 0, 601, 0,
- 0, 0, 0, 13, 14, 15, 26, 0, 512, 16,
- 357, 602, 514, 17, 0, 0, 0, 18, 42, 19,
- 0, 586, 0, 20, 0, 0, 7, 100, 0, 21,
- 11, 22, 0, 0, 23, 0, 0, 0, 42, 42,
- 0, 110, 515, 24, 515, 515, 515, 42, 0, 0,
- 0, 0, 0, 25, 0, 0, 0, 866, 42, 0,
- 42, 26, 7, 8, 19, 0, 27, 0, 0, 0,
- 0, 363, 28, 29, 21, 0, 22, 0, 0, 0,
- 190, 0, 0, 0, 0, 0, 0, 0, 108, 0,
- 0, 0, 357, 0, 0, 0, 0, 0, 109, 0,
- 19, 0, 0, 0, 0, 0, 26, 0, 0, 42,
- 21, 27, 22, 900, 0, 42, 0, 190, 0, 42,
- 0, 0, 110, 110, 139, 0, 0, 0, 0, 8,
- 0, 10, 184, 42, 140, 42, 42, 12, 0, 0,
- 0, 0, 26, 0, 0, 0, 228, 141, 0, 0,
- 586, 357, 15, 42, 42, 110, 16, 0, 0, 0,
- 17, 0, 277, 190, 357, 0, 357, 228, 228, 509,
- 0, 0, 0, 0, 0, 0, 21, 0, 93, 42,
- 0, 374, 376, 379, 7, 8, 0, 0, 11, 379,
- 510, 0, 228, 515, 515, 943, 515, 42, 0, 0,
- 511, 0, 0, 787, 0, 622, 623, 42, 636, 0,
- 512, 0, 0, 513, 514, 0, 0, 0, 0, 357,
- 0, 357, 19, 357, 0, 0, 0, 0, 0, 0,
- 0, 0, 21, 515, 22, 0, 0, 379, 0, 0,
- 0, 0, 0, 0, 0, 0, 139, 0, 0, 0,
- 586, 586, 0, 0, 0, 0, 140, 0, 0, 0,
- 0, 0, 0, 0, 26, 1010, 1011, 0, 0, 141,
- 7, 8, 92, 10, 11, 0, 0, 353, 8, 12,
- 10, 11, 0, 515, 515, 515, 12, 0, 0, 505,
- 0, 787, 0, 0, 15, 0, 0, 190, 16, 42,
- 0, 15, 17, 586, 586, 16, 0, 1042, 19, 17,
- 0, 509, 0, 0, 361, 0, 0, 0, 21, 0,
- 22, 0, 0, 0, 0, 21, 42, 93, 494, 42,
- 0, 0, 835, 42, 0, 0, 0, 0, 0, 0,
- 0, 8, 836, 10, 11, 0, 0, 0, 0, 12,
- 26, 0, 512, 0, 0, 602, 514, 0, 515, 586,
- 354, 0, 495, 0, 15, 0, 0, 0, 16, 0,
- 1079, 0, 17, 42, 42, 42, 42, 0, 0, 0,
- 0, 42, 0, 0, 0, 0, 0, 42, 21, 42,
- 93, 110, 110, 7, 8, 158, 159, 160, 42, 0,
- 0, 0, 12, 0, 42, 0, 0, 42, 7, 100,
- 0, 0, 423, 0, 622, 623, 374, 376, 0, 1120,
- 0, 636, 374, 376, 379, 17, 42, 42, 0, 42,
- 0, 19, 0, 586, 509, 0, 0, 0, 586, 0,
- 1138, 21, 0, 22, 0, 0, 19, 0, 0, 515,
- 1021, 515, 0, 0, 0, 600, 21, 0, 22, 0,
- 0, 0, 515, 0, 0, 601, 787, 787, 787, 0,
- 24, 0, 0, 26, 0, 512, 0, 0, 608, 514,
- 25, 0, 0, 0, 0, 0, 0, 0, 26, 0,
- 0, 0, 0, 27, 7, 8, 0, 0, 184, 0,
- 357, 0, 0, 120, 0, 7, 8, 92, 10, 11,
- 0, 0, 586, 586, 12, 0, 515, 515, 515, 515,
- 1186, 1187, 505, 515, 787, 787, 787, 0, 0, 15,
- 0, 0, 19, 16, 788, 0, 0, 17, 0, 0,
- 0, 586, 21, 19, 22, 0, 0, 0, 0, 0,
- 0, 0, 0, 21, 0, 22, 139, 0, 0, 0,
- 0, 0, 1218, 0, 42, 0, 140, 24, 0, 0,
- 0, 0, 0, 0, 26, 622, 623, 25, 636, 141,
- 0, 0, 0, 0, 0, 26, 586, 0, 0, 0,
- 27, 0, 0, 586, 586, 0, 0, 357, 0, 0,
- 0, 0, 586, 0, 64, 8, 92, 10, 11, 0,
- 0, 353, 0, 12, 42, 42, 110, 0, 0, 0,
- 787, 787, 844, 0, 64, 64, 0, 115, 15, 0,
- 0, 0, 16, 64, 0, 0, 17, 0, 42, 42,
- 0, 42, 0, 0, 64, 509, 64, 0, 0, 0,
- 0, 0, 21, 0, 93, 0, 0, 0, 0, 0,
- 0, 586, 586, 357, 7, 8, 510, 0, 11, 0,
- 110, 0, 0, 0, 0, 0, 511, 515, 515, 379,
- 515, 0, 0, 0, 0, 0, 512, 0, 0, 513,
- 514, 0, 0, 0, 354, 64, 0, 0, 0, 0,
- 0, 64, 19, 0, 788, 64, 0, 0, 115, 115,
- 0, 0, 21, 0, 22, 0, 0, 0, 0, 64,
- 0, 64, 64, 0, 0, 0, 377, 0, 586, 0,
- 0, 0, 0, 0, 0, 0, 378, 0, 0, 64,
- 64, 115, 0, 0, 26, 0, 0, 0, 0, 141,
- 0, 0, 0, 0, 374, 376, 379, 0, 196, 0,
- 0, 8, 0, 10, 11, 64, 0, 0, 0, 12,
- 475, 476, 477, 478, 479, 480, 481, 482, 483, 484,
- 485, 486, 0, 64, 15, 0, 0, 0, 16, 0,
- 0, 0, 17, 64, 197, 198, 116, 788, 788, 0,
- 0, 199, 0, 0, 0, 0, 0, 0, 21, 0,
- 93, 0, 200, 150, 201, 202, 203, 0, 204, 205,
- 206, 207, 208, 209, 210, 211, 212, 213, 214, 215,
- 216, 217, 218, 219, 220, 221, 0, 0, 222, 223,
- 224, 0, 0, 225, 0, 0, 226, 42, 42, 110,
- 110, 0, 190, 0, 42, 844, 844, 844, 0, 0,
- 0, 227, 0, 0, 150, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 116, 116, 0,
- 0, 0, 0, 42, 530, 64, 42, 0, 42, 0,
- 150, 0, 0, 0, -301, 8, -301, 10, 184, 0,
- 0, 788, 788, 12, 0, 0, 0, 0, 150, 150,
- 380, 0, 64, 0, 0, 64, 0, 0, 15, 64,
- 0, 0, 16, 0, 0, 0, 17, 0, 0, 0,
- 0, 0, -301, 0, 150, 509, 0, 0, 582, 0,
- 0, 0, 21, 0, 93, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 190, 510, 0, 0, 64,
- 64, 64, 64, 42, 0, 0, 511, 64, 0, 0,
- 0, 0, 0, 64, -301, 64, 512, 115, 115, 513,
- 514, 0, 0, 0, 64, 0, 0, 0, 0, 0,
- 64, 0, 0, 64, 42, 42, 42, 0, 0, 0,
- 433, 0, 0, 0, 0, 0, 0, 0, 42, 42,
- 0, 42, 64, 64, 0, 64, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 7, 8,
- 83, 10, 436, 233, 234, 0, 235, 12, 0, 0,
- 42, 0, 83, 83, 0, 83, 517, 517, 517, 0,
- 0, 0, 15, 236, 150, 0, 16, 0, 239, 0,
+ 46, 423, 465, 366, 673, 530, 321, 85, 314, 317,
+ 30, 586, 84, 553, 44, 85, 96, 638, 636, 103,
+ 103, 178, 103, 533, 350, 596, 915, 231, 66, 122,
+ 95, 97, 392, 400, 401, 349, 349, 351, 345, 149,
+ 554, 66, 955, 121, 360, 1107, 1212, 85, 1144, 409,
+ 1228, 556, 84, 830, 85, 1108, 502, 346, 502, 8,
+ 502, 164, 1111, 961, 88, 195, 85, 522, 1250, 194,
+ 830, 393, 85, 96, 599, 78, 309, 142, 1257, 651,
+ 424, 614, 85, 460, 165, 166, 290, 285, 286, 670,
+ 149, 85, 8, 85, 78, 309, 103, 194, 461, 307,
+ 103, 670, 420, 103, 103, 75, 100, 1259, 93, 554,
+ 347, 962, 100, 1269, 66, 46, 149, 66, 510, 600,
+ 556, 188, 831, 76, 601, 310, 615, -699, 300, 44,
+ 426, 616, 361, -699, 149, 149, 149, 82, 1272, 1295,
+ 73, 93, 100, 777, 310, 1144, 1299, 1089, 1311, 1260,
+ 577, 562, 522, 1033, 329, 93, 671, 602, 276, 21,
+ 149, 93, 693, 100, 617, 187, 709, 164, 1151, 557,
+ 294, 296, 100, 754, 164, 164, 1052, 175, 66, 414,
+ 1067, 276, 1219, 755, 337, 111, 750, 74, 103, 535,
+ 1049, 93, 340, 413, 422, -103, 75, 756, 164, 327,
+ 751, 384, -1, 510, 99, 867, 341, 360, 460, 653,
+ 21, 642, 93, 426, 76, 654, 398, -229, 359, 1272,
+ 1272, 93, 674, 558, 511, 85, 433, 499, 1245, 694,
+ 752, 1048, 311, 1224, 512, -2, 342, 593, 594, 159,
+ 160, 879, 164, 189, 513, 12, 328, 514, 515, 349,
+ 349, 595, 592, 530, 8, 366, 578, 8, 291, 295,
+ 1304, -229, -229, 192, 400, 401, 85, 315, 17, 675,
+ 509, 640, 433, 433, 524, -224, 360, 510, 314, 317,
+ 149, 100, 192, 194, 424, -124, 1074, -230, 880, 870,
+ 1254, 164, 401, 1172, 85, 361, 360, 579, 75, 111,
+ 192, 126, 1305, 93, 21, 1326, 580, 1107, 103, 526,
+ 1098, 103, 1104, 1074, 1107, 103, 76, 1108, 534, 85,
+ 96, 693, 651, 1197, 1108, 189, 301, 1147, 21, 187,
+ 93, -230, -230, 1075, 95, 97, 1265, 599, 127, 89,
+ 458, 581, 754, 422, 77, -225, 192, 1327, 1301, 894,
+ 1074, 1074, 755, 527, 100, 149, 66, 149, 149, 524,
+ 1182, 343, 708, 66, 361, 127, 756, 90, 1107, 149,
+ 1198, 149, 1074, 149, 149, 451, 164, 356, 1108, 811,
+ 149, 551, 600, 1266, 361, -695, 149, 601, 566, 149,
+ 422, 100, 192, 606, 11, 610, 612, 1276, 1282, 7,
+ 8, 21, 85, 93, 422, 164, 164, 1342, 149, 66,
+ 186, 66, 414, 939, 937, 431, 85, 297, 298, 1321,
+ 602, -285, 360, 99, 510, 432, 413, -285, 456, 360,
+ 764, 510, -699, 164, -699, -699, 117, 19, 21, 135,
+ 93, -699, 85, 85, 85, 85, 660, 385, 386, 22,
+ 551, 387, 511, 499, 1343, 783, 860, 112, 766, 187,
+ -286, 643, 512, -699, -699, -699, -286, -699, 693, -699,
+ 359, 189, 513, 804, 765, 514, 515, 820, 676, 26,
+ 192, 822, 118, 136, 137, 829, 7, 100, 805, 878,
+ 132, 586, 85, 133, 433, 388, 389, 349, 187, 784,
+ 785, 187, 767, 677, 192, 824, 433, 433, 100, 524,
+ 361, 424, 400, 360, 1180, 530, 66, 361, 553, 360,
+ 692, 821, 178, 695, 19, 823, 366, 465, 701, 702,
+ 703, 704, 705, 533, 651, 1091, 22, 315, 112, 112,
+ 750, 182, 276, 624, 99, 554, 718, 149, 85, 825,
+ 187, 1057, 1208, 84, 751, 21, 556, 93, 189, 7,
+ 503, 1273, 504, 287, 632, 164, 26, 360, 289, 431,
+ 881, 112, 422, 641, -27, 13, 14, -27, 747, 432,
+ -224, 7, 8, 356, 752, 612, 7, 8, 715, -27,
+ 394, 395, 78, 79, 7, 503, 1209, 19, 149, 149,
+ 842, 361, 318, 75, -81, 1274, 842, 361, 456, 22,
+ -81, 456, -102, 696, 698, 319, 700, 75, 673, 19,
+ -506, 76, 149, 149, 19, 149, 1077, 13, 14, 356,
+ 192, 22, 19, 240, 456, 76, 22, 234, 722, 505,
+ 21, -225, 80, 81, 22, 85, 331, 21, 332, 422,
+ 1082, 366, 333, 164, 842, 361, -80, 322, 426, 159,
+ 160, 26, -80, 187, 744, 12, 26, 8, 338, 10,
+ 761, 301, 114, 433, 26, 12, 407, 356, 807, 792,
+ 13, 14, 422, 433, 433, 433, 1027, 1028, 17, 1028,
+ 15, 164, 360, 371, 16, 421, 360, 427, 17, 357,
+ 78, 79, 167, 168, 169, 430, 192, 694, 158, 159,
+ 160, 75, 360, 715, 21, 12, 93, 486, 487, 871,
+ 1123, 192, 1072, 1073, 873, 874, 385, 1174, 876, 76,
+ 1053, 1054, 170, 1056, 356, 428, 356, 356, 17, 314,
+ 317, 359, 429, 85, 436, 314, 317, 443, 21, 444,
+ 80, 171, 446, 114, 114, 360, 1153, 1154, 447, 334,
+ 448, 335, 356, 111, 433, 336, 433, 449, 356, 849,
+ 1170, 450, 404, 85, 405, 502, 694, 433, 406, 85,
+ 361, 66, 66, 66, 361, 541, 114, 539, 567, 944,
+ 1184, 1185, 542, 194, 544, 172, 173, 174, 545, 85,
+ 361, 85, 546, 78, 309, 1129, 1130, 1131, 112, 112,
+ 547, 528, 8, 563, 885, 886, 887, 111, 347, 568,
+ -694, 569, 356, 570, 424, 571, 394, 1175, 385, 1181,
+ 914, 597, 149, 149, 149, 149, 598, 1216, 613, 149,
+ 842, 842, 842, 361, 622, 240, 529, 1336, 1337, 19,
+ 623, 792, 356, 310, 629, 70, 637, 85, 681, 21,
+ 718, 93, 682, 87, 439, 442, 359, 149, 1307, 1308,
+ 103, 98, 66, 414, 85, 104, 104, 686, 104, 422,
+ 422, 687, 422, 706, 70, 707, 551, 413, 483, 484,
+ 485, 486, 487, 100, 709, 104, 184, 70, 762, 13,
+ 14, 763, 776, 87, 778, 591, -330, 780, 796, 797,
+ 98, 399, 159, 160, 433, 433, 806, 433, 12, 808,
+ 810, 812, 98, 813, 814, 815, 921, 1016, 98, -330,
+ -330, 819, -330, 510, 356, 66, 66, 828, 1193, 1194,
+ 21, 17, 93, 1012, 852, 315, 104, 98, 66, 414,
+ 855, 635, 104, 862, 511, 963, 104, 856, 456, 104,
+ 104, 677, 857, 413, 512, 7, 100, 858, 861, 11,
+ 70, 866, 104, 70, 513, 872, 875, 514, 515, 877,
+ 149, 66, 149, 883, 882, 1156, 888, 889, 898, 642,
+ 104, 104, 104, 356, 149, 149, 892, 149, 315, 691,
+ 164, 893, 895, 19, 315, 111, 356, 896, 356, 694,
+ 897, 899, 900, 21, 901, 22, 104, 456, 1097, 902,
+ 1103, -101, 905, 114, 114, 66, 414, 24, 904, 907,
+ 1043, 1011, 908, 909, 70, 112, 912, 25, 910, 192,
+ 413, 112, 911, 923, 104, 26, 926, 913, 925, 315,
+ 27, 927, 932, 933, 7, 8, 743, 934, 745, 746,
+ 1227, 938, 356, 948, 356, 830, 356, 942, 8, 92,
+ 10, 11, 554, 943, 354, 945, 12, 314, 317, 956,
+ 1003, 98, 104, 1340, 1125, 1126, 1043, 1005, 1156, 112,
+ 795, 15, 19, 1300, 1009, 16, 1018, 842, 1034, 17,
+ 1036, 1037, 21, 1090, 22, -471, 1038, 138, -471, 1039,
+ 1055, 1045, 1059, 1050, 1064, 21, 139, 93, 1051, 1060,
+ 1076, 1061, 98, 1065, 1063, 1068, 140, 1069, 104, 104,
+ 70, 422, 422, 1081, 26, 532, 104, 1070, 1084, 141,
+ 1085, 192, 780, 1086, 817, 1093, 1092, 1088, 1109, 1095,
+ 98, 1156, 1116, -471, 1117, 1118, -471, 355, -471, 1132,
+ 1176, 590, 1122, 1143, 104, 1149, 1148, 104, -471, 1163,
+ 1167, 104, 842, 842, 842, 98, 1169, 1171, 1199, 422,
+ 1189, 1195, 422, 1196, 1156, 1200, -471, -471, 1201, 1213,
+ 98, -471, 1214, 1207, 8, 644, 1217, 1152, 1202, 1203,
+ -471, 1225, 1215, 1241, 1261, 1262, 1137, 1138, 1139, 1140,
+ 1251, 104, 70, 104, 104, 70, 149, 1263, 1146, 70,
+ 1264, 645, 1285, 1289, 1267, 104, 646, 104, 1268, 104,
+ 104, 1298, 1074, 164, 1303, 1306, 104, 1341, 1317, 360,
+ 1331, 21, 104, 93, 1309, 104, 8, 863, 1314, 1312,
+ 114, 1161, 1319, 1320, 1252, 1323, 114, 1325, 98, 1168,
+ 849, 458, 1333, 1335, 104, 70, 382, 70, 1344, 112,
+ 112, 1345, 98, 645, 1347, 112, 112, 112, 864, 1346,
+ 1349, 1350, 323, 565, 5, 396, 422, 325, -699, 950,
+ -699, -699, 326, 21, 344, 93, 957, -699, 98, 98,
+ 98, 98, 305, 710, 114, 1206, 1211, -699, 1232, -699,
+ -699, 1280, 768, 1162, 1100, 917, -699, 884, 1240, -699,
+ -699, 383, 1132, -699, 949, -699, 85, 361, 928, 827,
+ 929, 123, 124, 1218, 1013, 865, 315, 111, -699, -699,
+ 397, 953, -699, 356, -699, 1030, 1066, 86, 98, 456,
+ 104, 48, 668, 749, 1218, 1218, 1029, 187, 8, 92,
+ 10, 11, 104, 104, 1339, 70, 12, 48, 799, 947,
+ 1296, 998, 794, 1316, 1318, 0, 187, 488, 1032, 1218,
+ 48, 15, 620, 532, 958, 16, 959, 0, 960, 17,
+ 0, 655, 656, 154, 479, 480, 481, 482, 483, 484,
+ 485, 486, 487, 104, 87, 21, 185, 93, 0, 0,
+ 0, 0, 0, 551, 489, 490, 0, 0, 229, 491,
+ 492, 493, 494, 278, 48, 0, 0, 0, 0, 19,
+ 0, 0, 657, 0, 0, 278, 278, 0, 0, 21,
+ 356, 22, 853, 154, 1297, 0, 278, 0, 658, 0,
+ 0, 0, 0, 139, 104, 104, 70, 0, 0, 0,
+ 722, 722, 794, 140, 0, 0, 48, 0, 0, 154,
+ 0, 26, 0, 1315, 0, 0, 659, 0, 104, 104,
+ 0, 104, 0, 363, 114, 114, 0, 0, 0, 0,
+ 114, 114, 114, 0, 0, 0, 8, 92, 10, 11,
+ 0, 98, 0, 0, 12, 0, 356, 0, 7, 8,
+ 70, 0, 11, 375, 377, 380, 228, 0, 0, 15,
+ 0, 277, 0, 16, 0, 0, 0, 17, 0, 104,
+ 48, 0, 112, 277, 277, 0, 0, 0, 0, 104,
+ 104, 104, 0, 21, 277, 93, 19, 0, 0, 510,
+ 0, 0, 0, 0, 0, 0, 21, 0, 22, 0,
+ 0, 94, 0, 0, 0, 0, 452, 101, 105, 453,
+ 603, 916, 454, 0, 0, 0, 0, 185, 462, 0,
+ 604, 362, 0, 0, 0, 0, 0, 501, 26, 0,
+ 513, 0, 0, 605, 515, 0, 0, 0, 0, 98,
+ 0, 0, 0, 0, 0, 278, 0, 112, 112, 112,
+ 0, 0, 0, 8, 230, 10, 184, 0, 229, 279,
+ 104, 12, 104, 0, 0, 0, 185, 0, 952, 98,
+ 0, 279, 279, 104, 0, 98, 15, 794, 794, 794,
+ 16, 0, 279, 0, 17, 532, 552, 0, 0, 0,
+ 0, 313, 316, 0, 0, 98, 0, 98, 0, 0,
+ 21, 0, 93, 0, 0, 0, 0, 0, 816, 0,
+ 98, 48, 1004, 0, 0, 0, 0, 0, 0, 364,
+ 0, 0, 374, 376, 0, 0, 0, 0, 104, 104,
+ 104, 104, 0, 0, 0, 104, 794, 794, 794, 0,
+ 0, 0, 0, 277, 0, 0, 0, 0, 154, 0,
+ 0, 185, 0, 98, 0, 552, 228, 0, 0, 0,
+ 0, 0, 854, 104, 1041, 1044, 104, 0, 70, 0,
+ 98, 0, 0, 859, 0, 363, 481, 482, 483, 484,
+ 485, 486, 487, 0, 362, 0, 0, 114, 625, 0,
+ 626, 193, 375, 377, 0, 0, 0, 0, 0, 0,
+ 699, 154, 1243, 48, 0, 639, 0, 0, 678, 0,
+ 104, 104, 0, 104, 0, 0, 0, 7, 8, 0,
+ 0, 1044, 0, 0, 0, 278, 0, 665, 278, 0,
+ 0, 794, 794, 278, 678, 678, 678, 678, 320, 0,
+ 0, 279, 0, 0, 70, 0, 0, 278, 0, 0,
+ 0, 278, 0, 362, 230, 19, 0, 352, 510, 0,
+ 0, 0, 114, 114, 114, 21, 0, 22, 1294, 0,
+ 0, 0, 391, 362, 0, 0, 104, 70, 104, 603,
+ 0, 0, 364, 278, 229, 0, 0, 0, 0, 604,
+ 104, 104, 0, 104, 0, 1136, 0, 26, 0, 513,
+ 1141, 552, 605, 515, 0, 0, 277, 0, 363, 0,
+ 0, 0, 0, 0, 6, 0, 7, 8, 9, 10,
+ 11, 70, 0, 277, 0, 12, 277, 0, 0, 0,
+ 0, 277, 277, 277, 277, 277, 0, 0, 13, 14,
+ 15, 0, 954, 0, 16, 277, 0, 0, 17, 277,
+ 0, 364, 18, 0, 19, 0, 0, 0, 20, 0,
+ 0, 627, 628, 0, 21, 0, 22, 0, 0, 23,
+ 0, 364, 0, 0, 1186, 1187, 0, 0, 24, 0,
+ 0, 277, 228, 0, 0, 0, 0, 0, 25, 0,
+ 0, 1010, 552, 794, 0, 0, 26, 0, 363, 362,
+ 1017, 27, 0, 1205, 279, 0, 362, 28, 29, 1031,
+ 0, 0, 0, 7, 8, 0, 0, 375, 377, 380,
+ 0, 279, 0, 0, 279, 380, 0, 0, 0, 279,
+ 279, 279, 279, 279, 0, 0, 0, 0, -511, 0,
+ 0, 625, 626, 279, 639, 0, 552, 279, 1233, 0,
+ 0, 19, 0, -511, -511, 1238, 1239, 0, 0, 0,
+ -511, 21, 0, 22, 1244, 0, 1096, 0, 794, 794,
+ 794, 0, -511, 380, 0, 139, 0, 0, 0, 279,
+ 230, 0, 0, -511, -511, 140, -511, 0, -511, 100,
+ 362, 0, 424, 26, 769, 771, 362, 364, 141, 0,
+ 0, 0, 0, 630, 364, 0, 0, 0, 0, 633,
+ 0, 0, 104, 0, 0, 924, -511, -511, 0, 0,
+ -511, -511, 0, 1292, 1293, 0, 0, 0, 0, 510,
+ -511, 0, 0, 0, 0, 678, 21, 0, 93, 918,
+ 0, 452, 453, 0, 362, 1119, 1120, 0, 0, 0,
+ 511, 0, 0, 688, 689, 0, 690, 0, 1127, 1128,
+ 512, 0, 0, 0, 0, 678, 0, 0, 0, 0,
+ 513, 552, 0, 514, 515, 363, 8, 92, 10, 11,
+ 0, 0, 0, 0, 12, 0, 837, 838, 364, 0,
+ 1338, 552, 0, 951, 364, 0, 0, 0, 0, 15,
+ 452, 453, 0, 16, 0, 0, 0, 17, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 987,
+ 0, 0, 98, 21, 0, 93, 0, 0, 519, 523,
+ 525, 0, 0, 277, 363, 0, 0, 0, 0, 781,
+ 782, 0, 364, 0, 781, 452, 453, 0, 278, 0,
+ 0, 625, 626, 375, 377, 1192, 7, 100, 639, 375,
+ 377, 380, 0, 277, 48, 0, 678, 0, 0, 362,
+ 0, 0, 0, 362, 0, 0, 0, 0, 0, 0,
+ 1058, 0, 0, 0, 0, 0, 1025, 0, 0, 362,
+ 0, 0, 0, 0, 19, 452, 453, 0, 0, 0,
+ 0, 0, 0, 0, 21, 0, 22, 0, 0, 0,
+ 0, 608, 0, 519, 523, 525, 0, 0, 108, 835,
+ 836, 1234, 1235, 0, 1236, 1237, 0, 0, 109, 844,
+ 0, 279, 362, 0, 0, 851, 26, 0, 0, 0,
+ 48, 27, 0, 0, 0, 0, 277, 0, 0, 0,
+ 0, 410, 0, 7, 8, 92, 10, 11, 0, 0,
+ 0, 279, 12, 0, 277, 0, 0, 364, 0, 769,
+ 771, 364, 0, 154, 0, 987, 0, 15, 0, 868,
+ 0, 16, 987, 0, 0, 17, -423, 364, 0, 7,
+ 100, 19, 0, 184, 0, 0, 0, 0, 7, 100,
+ 0, 21, 11, 22, 0, 0, 672, 0, 0, 0,
+ 411, 0, 0, 625, 626, 24, 639, 48, 0, 0,
+ 0, 0, 999, 1000, 268, 25, 0, 19, 999, 1000,
+ 364, 1313, 0, 26, 0, 0, 19, 21, 27, 22,
+ 0, 0, 0, 0, 279, 0, 21, 268, 22, 0,
+ 0, 24, 0, -423, 0, 0, 0, 0, 1019, 1020,
+ 108, 25, 279, 772, 0, 774, 0, 0, 987, 26,
+ 109, 0, 774, 0, 27, 0, 919, 920, 26, 922,
+ 0, 0, 0, 27, 358, 0, 0, 410, 0, 7,
+ 8, 92, 10, 11, 0, 0, 19, 0, 12, 0,
+ 0, 0, 0, 523, 0, 936, 21, 0, 22, 0,
+ 0, 0, 0, 15, 0, 1021, 380, 16, 0, 0,
+ 139, 17, -422, 769, 771, 0, 0, 19, 0, 0,
+ 140, 0, 452, 453, 0, 0, 0, 21, 26, 22,
+ 0, 0, 987, 141, 0, 0, 411, 0, 0, 0,
+ 1220, 24, 0, 987, 0, 772, 774, 0, 0, 0,
+ 0, 25, 774, 0, 0, 1002, 278, 0, 0, 26,
+ 0, 1220, 1220, 0, 27, 0, 0, 1006, 1007, 1008,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, -422,
+ 0, 375, 377, 380, 0, 0, 1220, 0, 0, 0,
+ 0, 0, 0, 987, 0, 0, 0, 459, 0, 0,
+ 987, 0, 8, 987, 10, 11, 0, 0, 0, 0,
+ 12, 0, 0, 0, 7, 8, 158, 159, 160, 523,
+ 0, 0, 0, 12, 987, 15, 0, 987, 0, 16,
+ 0, 0, 0, 17, 987, 0, 0, 410, 228, 7,
+ 8, 92, 10, 11, 0, 1062, 17, 0, 12, 21,
+ 0, 93, 19, 0, 277, 510, 0, 0, 987, 228,
+ 228, 0, 21, 15, 22, 0, 0, 16, 0, 0,
+ 0, 17, -424, 987, 0, 0, 139, 19, 0, 589,
+ 358, 0, 0, 0, 228, 0, 140, 21, 987, 22,
+ 0, 0, 672, 0, 26, 0, 411, 0, 0, 1102,
+ 0, 24, 0, 0, 0, 987, 987, 0, 552, 0,
+ 930, 25, 931, 0, 0, 0, 0, 0, 0, 26,
+ 0, 0, 0, 935, 27, 0, 358, 0, 772, 774,
+ 1121, 0, 0, 0, 0, 0, 230, 0, 0, -424,
+ 0, 0, 0, 0, 0, 8, 0, 10, 11, 652,
+ 627, 628, 279, 12, 0, 0, 0, 230, 230, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 15, 0,
+ 0, 0, 16, 0, 358, 1150, 17, 0, 930, 931,
+ 0, 772, 230, 0, 0, 935, 0, 772, 774, 7,
+ 8, 0, 21, 184, 93, 495, 0, 0, 268, 0,
+ 0, 589, 0, 0, 719, 720, 362, 724, 725, 726,
+ 727, 728, 729, 730, 731, 732, 733, 734, 735, 736,
+ 737, 738, 739, 740, 741, 742, 0, 19, 0, 496,
+ 510, 358, 0, 358, 358, 0, 0, 21, 0, 22,
+ 7, 8, 92, 10, 11, 0, 0, 354, 0, 12,
+ 0, 603, 100, 0, 159, 160, 0, 0, 0, 358,
+ 12, 604, 0, 0, 15, 358, 42, 0, 16, 26,
+ 0, 513, 17, 0, 605, 515, 0, 0, 19, 0,
+ 801, 803, 772, 17, 0, 0, 42, 42, 21, 110,
+ 22, 0, 510, 0, 0, 42, 0, 0, 0, 21,
+ 0, 93, 378, 0, 364, 0, 42, 0, 42, 0,
+ 0, 0, 379, 511, 0, 0, 0, 0, 0, 358,
+ 26, 0, 0, 512, 0, 141, 589, 0, 190, 0,
+ 355, 0, 0, 513, 0, 0, 521, 515, 0, 0,
+ 930, 931, 6, 935, 7, 8, 9, 10, 11, 358,
+ 0, 0, 0, 12, 0, 0, 0, 42, 0, 0,
+ 589, 0, 0, 42, 0, 190, 0, 42, 15, 0,
+ 110, 110, 16, 0, 0, 0, 17, 0, 0, 0,
+ 0, 42, 19, 42, 42, 0, 324, 0, 0, 0,
+ 0, 0, 21, 0, 22, 0, 869, 23, 0, 0,
+ 0, 42, 42, 110, 0, 0, 24, 0, 0, 0,
+ 0, 190, 0, 0, 0, 0, 25, 0, 0, 0,
+ 0, 0, 0, 0, 26, 0, 0, 42, 0, 27,
+ 0, 358, 0, 0, 0, 28, 721, 0, 7, 8,
+ 0, 10, 437, 233, 234, 42, 235, 12, 0, 0,
+ 0, 0, 903, 0, 0, 42, 0, 0, 0, 0,
+ 0, 0, 15, 236, 237, 238, 16, 0, 239, 0,
17, 0, 240, 241, 0, 242, 19, 243, 244, 0,
- 177, 245, 246, 247, 248, 249, 21, 0, 22, 0,
+ 0, 245, 246, 247, 248, 249, 21, 0, 22, 589,
+ 358, 0, 0, 0, 0, -656, 0, 250, 0, 0,
+ 251, 0, 0, 358, 0, 358, 0, 0, 252, 253,
+ 254, 0, 0, 0, 0, 0, 255, 256, 257, 0,
+ 0, 0, 0, 258, 0, 0, 0, 259, 0, 0,
+ 0, 0, 0, 0, 946, 0, 0, 506, 0, 260,
+ 0, 0, 0, 0, 0, 190, 589, 42, 0, 7,
+ 8, 0, 10, 437, 233, 234, 0, 235, 12, 358,
+ 0, 358, 0, 358, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 15, 236, 42, 0, 16, 42, 239,
+ 0, 17, 42, 240, 241, 0, 242, 19, 243, 244,
+ 589, 0, 245, 246, 247, 248, 249, 21, 0, 22,
+ 0, 0, 0, 0, 1014, 1015, 0, 0, 250, 0,
+ 0, 251, 0, 0, 0, 0, 0, 1019, 100, 252,
+ 253, 254, 42, 42, 42, 42, 0, 255, 256, 257,
+ 42, 0, 0, 0, 438, 0, 42, 0, 42, 0,
+ 110, 110, 589, 589, 0, 0, 1046, 42, 0, 0,
+ 260, 0, 0, 42, 0, 19, 42, 0, 410, 0,
+ 7, 8, 92, 10, 11, 21, 0, 22, 0, 12,
+ 0, 7, 8, 0, 1021, 42, 42, 0, 42, 24,
+ 0, 0, 0, 0, 15, 0, 0, 0, 16, 25,
+ 0, 0, 17, -425, 0, 0, 0, 26, 19, 589,
+ 0, 0, 27, 0, 0, 0, 0, 64, 21, 19,
+ 22, 1083, 0, 0, 7, 8, 0, 411, 11, 21,
+ 0, 22, 24, 0, 0, 0, 0, 64, 64, 0,
+ 115, 0, 25, 139, 0, 0, 64, 0, 0, 0,
+ 26, 0, 0, 140, 0, 27, 0, 64, 0, 64,
+ 0, 26, 19, 0, 0, 510, 141, 0, 0, 1124,
+ -425, 0, 21, 0, 22, 7, 8, 92, 10, 11,
+ 0, 506, 354, 589, 12, 0, 839, 0, 589, 0,
+ 1142, 0, 0, 791, 0, 0, 840, 0, 0, 15,
+ 0, 0, 0, 16, 26, 0, 513, 17, 64, 605,
+ 515, 0, 0, 19, 64, 0, 510, 0, 64, 0,
+ 0, 115, 115, 21, 42, 22, 0, 0, 0, 0,
+ 0, 0, 64, 0, 64, 64, 0, 839, 0, 0,
+ 0, 8, 0, 10, 11, 0, 0, 840, 0, 12,
+ 358, 0, 64, 64, 115, 26, 0, 513, 0, 0,
+ 605, 515, 589, 589, 15, 355, 0, 0, 16, 0,
+ 1190, 1191, 17, 0, 0, 42, 42, 110, 64, 0,
+ 0, 0, 0, 848, 0, 0, 0, 0, 21, 0,
+ 93, 589, 0, 0, 0, 0, 64, 0, 0, 42,
+ 42, 0, 42, 0, 0, 0, 64, 0, 0, 0,
+ 0, 0, 1222, 476, 477, 478, 479, 480, 481, 482,
+ 483, 484, 485, 486, 487, 748, 0, 587, 0, 711,
+ 712, 110, 10, 437, 233, 234, 589, 235, 12, 0,
+ 0, 0, 0, 589, 589, 0, 0, 358, 0, 0,
+ 0, 0, 589, 15, 236, 237, 238, 16, 0, 239,
+ 0, 17, 0, 240, 241, 791, 242, 19, 243, 244,
+ 0, 0, 245, 246, 247, 248, 249, 21, 0, 713,
+ 588, 0, 0, 0, 7, 8, 0, 0, 250, 0,
+ 0, 251, 0, 0, 0, 0, 0, 531, 64, 252,
+ 253, 254, 0, 0, 0, 0, 0, 255, 256, 257,
+ 0, 589, 589, 358, 258, 714, 0, 0, 259, 0,
+ 0, 0, 19, 0, 0, 0, 64, 0, 0, 64,
+ 260, 0, 21, 64, 22, 0, 0, 0, 0, 0,
+ 116, 0, 0, 0, 0, 0, 378, 0, 0, 0,
+ 0, 0, 585, 0, 0, 0, 379, 150, 791, 791,
+ 0, 0, 0, 0, 26, 0, 0, 0, 0, 141,
+ 0, 0, 0, 64, 64, 64, 64, 0, 589, 0,
+ 0, 64, 0, 0, 0, 0, 0, 64, 0, 64,
+ 0, 115, 115, 0, 0, 0, 0, 0, 64, 0,
+ 0, 0, 0, 0, 64, 0, 0, 64, 150, 42,
+ 42, 110, 110, 0, 190, 0, 42, 848, 848, 848,
+ 0, 116, 116, 0, 0, 0, 64, 64, 0, 64,
+ 0, 0, 0, 0, 150, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 42, 0, 0, 42, 0, 42,
+ 0, 0, 150, 150, 381, 0, 0, 0, 0, 0,
+ 0, 0, 791, 791, 0, 1105, 0, 966, 967, 92,
+ 10, 232, 233, 234, 0, 235, 12, 968, 150, 969,
+ 970, 971, 972, 973, 974, 975, 976, 977, 978, 13,
+ 14, 15, 236, 237, 238, 16, 0, 239, 0, 17,
+ 0, 240, 241, 0, 242, 19, 243, 244, 0, 0,
+ 245, 246, 247, 248, 249, 21, 190, 979, 347, 0,
+ 980, 0, 0, 0, 0, 42, 250, 0, 0, 251,
+ 0, 0, 0, 0, 793, 0, 0, 252, 253, 254,
+ 0, 0, 0, 0, 434, 255, 256, 257, 0, 0,
+ 0, 0, 258, 0, 981, 0, 259, 42, 42, 42,
+ 0, 0, 0, 0, 0, 64, 0, 1106, 260, 0,
+ 0, 42, 42, 0, 42, 7, 8, 0, 0, 11,
+ 0, 8, 92, 10, 11, 0, 0, 354, 0, 12,
+ 518, 518, 518, 0, 0, 0, 0, 0, 150, 0,
+ 0, 0, 42, 0, 15, 0, 0, 0, 16, 0,
+ 0, 0, 17, 19, 0, 0, 64, 64, 115, 0,
+ 0, 510, 0, 21, 850, 22, 0, 0, 21, 0,
+ 93, 0, 0, 0, 0, 0, 0, 139, 0, 0,
+ 64, 64, 511, 64, 0, 0, 0, 140, 0, 0,
+ 0, 0, 512, 0, 0, 26, 0, 0, 0, 0,
+ 141, 0, 513, 0, 0, 514, 515, 0, 0, 0,
+ 355, 0, 115, 607, 848, 607, 607, 518, 0, 120,
+ 0, 7, 8, 92, 10, 11, 0, 150, 0, 150,
+ 12, 381, 381, 0, 0, 0, 7, 8, 150, 0,
+ 424, 516, 516, 516, 150, 15, 793, 150, 0, 16,
+ 0, 0, 0, 17, 0, 0, 0, 0, 148, 19,
+ 0, 0, 0, 0, 0, 0, 150, 0, 0, 21,
+ 0, 22, 0, 0, 19, 0, 0, 510, 0, 0,
+ 191, 0, 0, 24, 21, 0, 22, 0, 0, 848,
+ 848, 848, 0, 25, 0, 0, 7, 100, 603, 191,
+ 424, 26, 0, 0, 0, 0, 27, 0, 604, 148,
+ 0, 0, 0, 0, 0, 0, 26, 0, 513, 0,
+ 0, 605, 515, 0, 516, 0, 516, 516, 516, 0,
+ 0, 0, 0, 42, 19, 148, 0, 0, 0, 793,
+ 793, 0, 0, 0, 21, 0, 22, 531, 0, 0,
+ 0, 0, 757, 148, 148, 148, 0, 0, 24, 0,
+ 0, 0, 0, 390, 518, 518, 0, 518, 25, 0,
+ 0, 0, 585, 0, 518, 0, 26, 0, 0, 148,
+ 0, 27, 0, 0, 0, 0, 0, 0, 0, 0,
+ 64, 64, 115, 115, 0, 0, 0, 64, 850, 850,
+ 850, 0, 0, 0, 0, 607, 0, 0, 0, 191,
+ 0, 0, 62, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 64, 0, 0, 64, 0,
+ 64, 0, 102, 106, 0, 0, 0, 100, 0, 159,
+ 160, 125, 0, 793, 793, 12, 0, 0, 0, 0,
+ 0, 0, 0, 0, 157, 0, 607, 607, 843, 0,
+ 0, 0, 0, 0, 843, 0, 0, 0, 17, 0,
+ 0, 0, 0, 0, 0, 516, 516, 510, 516, 0,
+ 150, 150, 0, 150, 21, 790, 93, 0, 8, 151,
+ 10, 152, 0, 0, 0, 0, 12, 191, 511, 148,
+ 0, 0, 0, 0, 0, 0, 64, 0, 512, 306,
+ 0, 15, 381, 308, 0, 16, 516, 0, 513, 17,
+ 0, 514, 515, 0, 0, 0, 0, 62, 0, 0,
+ 330, 518, 7, 8, 0, 21, 184, 93, 64, 64,
+ 64, 434, 434, 434, 0, 0, 0, 102, 106, 0,
+ 0, 0, 64, 64, 0, 64, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 516, 516, 516,
+ 19, 0, 0, 0, 148, 790, 148, 148, 0, 0,
+ 21, 0, 22, 64, 0, 0, 0, 0, 148, 0,
+ 148, 419, 148, 148, 139, 0, 7, 8, 0, 148,
+ 11, 425, 0, 0, 140, 148, 0, 0, 148, 0,
+ 0, 0, 26, 0, 0, 0, 83, 141, 0, 0,
+ 0, 0, 518, 0, 518, 0, 0, 148, 83, 83,
+ 0, 83, 0, 0, 19, 518, 0, 0, 0, 518,
+ 518, 518, 516, 0, 21, 0, 22, 0, 0, 0,
+ 0, 0, 0, 0, 0, 850, 177, 0, 378, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 379, 0,
+ 0, 0, 0, 0, 0, 0, 26, 0, 0, 0,
+ 0, 141, 0, 0, 0, 0, 0, 0, 0, 0,
+ 607, 607, 843, 843, 0, 0, 0, 607, 843, 843,
+ 843, 0, 0, 0, 0, 83, 0, 83, 83, 83,
+ 0, 0, 83, 83, 0, 7, 8, 0, 0, 424,
+ 0, 559, 0, 0, 560, 150, 0, 0, 561, 0,
+ 850, 850, 850, 516, 0, 516, 0, 0, 191, 0,
+ 0, 0, 0, 0, 0, 0, 516, 0, 0, 0,
+ 790, 790, 790, 19, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 21, 0, 22, 148, 0, 0, 609,
+ 0, 0, 757, 757, 64, 757, 619, 139, 0, 0,
+ 0, 0, 306, 0, 308, 0, 0, 140, 0, 0,
+ 0, 0, 0, 518, 518, 26, 0, 83, 0, 425,
+ 141, 516, 516, 516, 516, 0, 0, 0, 516, 790,
+ 790, 790, 0, 0, 0, 0, 0, 148, 148, 841,
+ 0, 666, 669, 0, 419, 841, 0, 0, 0, 0,
+ -304, 8, -304, 10, 184, 83, 0, 0, 150, 12,
+ 150, 148, 148, 0, 148, 0, 0, 0, 0, 0,
+ 0, 0, 607, 607, 15, 607, 0, 0, 16, 0,
+ 0, 0, 17, 0, 0, 0, 0, 0, -304, 0,
+ 0, 510, 0, 841, 0, 0, 0, 0, 21, 83,
+ 93, 83, 83, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 511, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 512, 0, 790, 790, 0, 0, 0, 0,
+ -304, 83, 513, 0, 0, 514, 515, 83, 0, 0,
+ 83, 0, 0, 0, 83, 471, 472, 473, 474, 475,
+ 476, 477, 478, 479, 480, 481, 482, 483, 484, 485,
+ 486, 487, 353, 0, 7, 8, 92, 10, 232, 233,
+ 234, 354, 235, 12, 0, 381, 0, 0, 0, 0,
+ 0, 0, 0, 516, 516, 0, 516, 0, 15, 236,
+ 237, 238, 16, 0, 239, 0, 17, 0, 240, 241,
+ 0, 242, 19, 243, 244, 0, 0, 245, 246, 247,
+ 248, 249, 21, 0, 22, 0, 0, 0, 0, 0,
+ 0, 0, 0, 250, 0, 0, 251, 0, 0, 0,
+ 0, 102, 106, 0, 252, 253, 254, 0, 0, 0,
+ 0, 0, 255, 256, 257, 0, 0, 0, 0, 258,
+ 381, 381, 381, 259, 355, 559, 560, 83, 561, 0,
+ 0, 0, 0, -666, 0, 260, 0, 0, 0, 0,
+ 0, 148, 148, 148, 148, 0, 1001, 0, 148, 841,
+ 841, 841, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 150, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 148, 0, 0, 0,
+ 0, 455, 0, 7, 8, 92, 10, 232, 233, 234,
+ 354, 235, 12, 83, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 83, 0, 83, 83, 15, 236, 237,
+ 238, 16, 0, 239, 0, 17, 0, 240, 241, 0,
+ 242, 19, 243, 244, 510, 0, 245, 246, 247, 248,
+ 249, 21, 0, 22, -237, 0, 0, 0, 0, 0,
+ 0, 0, 250, 0, 0, 940, 0, 177, 191, 0,
+ 0, 0, 0, 252, 253, 941, 0, 0, 0, 0,
+ 0, 255, 256, 257, 0, 513, 0, 0, 788, 515,
+ 0, 0, 259, 355, 0, 0, 7, 8, 158, 159,
+ 160, 0, 0, 0, 260, 12, 0, 0, 0, 148,
+ 0, 148, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 148, 148, 0, 148, 0, 17, 0,
+ 0, 0, 0, 0, 19, 0, 0, 510, 0, 0,
+ 0, 0, 0, 0, 21, 0, 22, 0, 0, 0,
+ 0, 0, 0, 0, 0, 306, 308, 0, 603, 0,
+ 0, 0, 425, 0, 0, 0, 0, 0, 604, 0,
+ 0, 0, 0, 0, 0, 0, 26, 0, 513, 0,
+ 0, 611, 515, 0, 0, 0, 0, 0, 0, 0,
+ 1026, 0, 83, 1026, 0, 419, 0, 0, 0, 0,
+ 0, 0, 83, 83, 83, 0, 455, 0, 7, 8,
+ 92, 10, 232, 233, 234, 354, 235, 12, 0, 0,
+ 0, 0, 0, 0, 0, 0, 841, 0, 0, 0,
+ 0, 0, 15, 236, 237, 238, 16, 0, 239, 0,
+ 17, 0, 240, 241, 0, 242, 19, 243, 244, 510,
+ 0, 245, 246, 247, 248, 249, 21, 0, 22, -237,
0, 0, 0, 0, 0, 0, 0, 250, 0, 0,
+ 845, 419, 0, 0, 1164, 0, 0, 0, 252, 253,
+ 846, 0, 0, 83, 0, 83, 255, 256, 257, 0,
+ 513, 0, 0, 847, 515, 0, 83, 259, 355, 0,
+ 0, 841, 841, 841, 1101, 0, 0, 0, 0, 260,
+ 0, 0, 0, 0, 0, 0, 0, 559, 560, 0,
+ 561, 466, 467, 468, 1165, 469, 470, 471, 472, 473,
+ 474, 475, 476, 477, 478, 479, 480, 481, 482, 483,
+ 484, 485, 486, 487, 0, 148, 0, 0, 419, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 1255, 0,
+ 966, 967, 92, 10, 232, 233, 234, 0, 235, 12,
+ 968, 0, 969, 970, 971, 972, 973, 974, 975, 976,
+ 977, 978, 13, 14, 15, 236, 237, 238, 16, 83,
+ 239, 0, 17, 0, 240, 241, 0, 242, 19, 243,
+ 244, 0, 0, 245, 246, 247, 248, 249, 21, 0,
+ 979, 347, 0, 980, 0, 0, 0, 0, 0, 250,
+ 0, 0, 251, 0, 0, 0, 0, 0, 0, 0,
+ 252, 253, 254, 83, 83, 0, 83, 0, 255, 256,
+ 257, 0, 0, 0, 0, 258, 0, 981, 0, 259,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 1256, 260, 1277, 0, 966, 967, 92, 10, 232, 233,
+ 234, 0, 235, 12, 968, 0, 969, 970, 971, 972,
+ 973, 974, 975, 976, 977, 978, 13, 14, 15, 236,
+ 237, 238, 16, 0, 239, 0, 17, 0, 240, 241,
+ 0, 242, 19, 243, 244, 0, 0, 245, 246, 247,
+ 248, 249, 21, 0, 979, 347, 0, 980, 0, 0,
+ 0, 0, 0, 250, 0, 0, 251, 0, 0, 0,
+ 0, 0, 0, 0, 252, 253, 254, 0, 0, 0,
+ 0, 0, 255, 256, 257, 0, 0, 0, 0, 258,
+ 0, 981, 0, 259, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 1278, 260, 1277, 0, 966, 967,
+ 92, 10, 232, 233, 234, 0, 235, 12, 968, 0,
+ 969, 970, 971, 972, 973, 974, 975, 976, 977, 978,
+ 13, 14, 15, 236, 237, 238, 16, 0, 239, 0,
+ 17, 0, 240, 241, 0, 242, 19, 243, 244, 0,
+ 0, 245, 246, 247, 248, 249, 21, 0, 979, 347,
+ 0, 980, 0, 0, 0, 0, 0, 250, 0, 0,
251, 0, 0, 0, 0, 0, 0, 0, 252, 253,
254, 0, 0, 0, 0, 0, 255, 256, 257, 0,
- 0, 0, 844, 437, 0, 0, 0, 0, 0, 83,
- 790, 83, 83, 83, 0, 0, 83, 83, 604, 260,
- 604, 604, 517, 0, 7, 8, 158, 159, 160, 0,
- 0, 0, 150, 12, 150, 0, 380, 380, 0, 0,
- 64, 0, 0, 150, 0, 0, 0, 0, 0, 150,
- 0, 0, 150, 0, 148, 0, 17, 0, 0, 0,
- 0, 0, 19, 0, 0, 509, 0, 0, 0, 0,
- 0, 150, 21, 0, 22, 0, 191, 844, 844, 844,
- 0, 0, 0, 0, 0, 0, 600, 0, 0, 0,
- 64, 64, 115, 0, 0, 191, 601, 0, 846, 0,
- 0, 83, 0, 0, 26, 148, 512, 0, 0, 602,
- 514, 0, 0, 0, 64, 64, 100, 64, 159, 160,
- 0, 42, 0, 0, 12, 0, 7, 8, 0, 0,
- 423, 148, 0, 0, 0, 8, 92, 10, 11, 83,
- 0, 1335, 0, 12, 0, 0, 115, 17, 0, 148,
- 148, 148, 0, 0, 7, 8, 509, 754, 15, 389,
- 0, 0, 16, 21, 19, 93, 17, 0, 0, 517,
- 517, 0, 517, 0, 21, 148, 22, 510, 0, 517,
- 790, 0, 21, 83, 93, 83, 83, 511, 139, 0,
- 7, 8, 19, 0, 0, 0, 0, 512, 140, 0,
- 513, 514, 21, 0, 22, 191, 26, 1092, 0, 604,
- 0, 141, 0, 0, 83, 0, 139, 0, 0, 0,
- 83, 0, 0, 83, 0, 0, 140, 83, 19, 0,
- 0, 0, 0, 0, 26, 0, 0, 0, 21, 141,
- 22, 8, 92, 10, 11, 0, 0, 0, 0, 12,
- 0, 0, 377, 0, 0, 0, 0, 0, 0, 604,
- 604, 839, 378, 0, 15, 0, 0, 839, 16, 0,
- 26, 0, 17, 790, 790, 141, 0, 0, 0, 0,
- 0, 530, 0, 150, 150, 0, 150, 0, 21, 0,
- 93, 0, 0, 191, 0, 148, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 582, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 380, 0, 0, 0, 0,
- 0, 0, 0, 64, 64, 115, 115, 0, 0, 0,
- 64, 846, 846, 846, 517, 0, 0, 0, 0, 0,
- 83, 0, 0, 0, 433, 433, 433, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 64,
- 0, 0, 64, 0, 64, 0, 0, 0, 0, 148,
- 0, 148, 148, 0, 0, 0, 0, 790, 790, 518,
- 522, 524, 0, 148, 0, 148, 0, 148, 148, 0,
- 0, 0, 0, 0, 148, 0, 0, 0, 0, 0,
- 148, 0, 0, 148, 0, 0, 83, 0, 0, 0,
- 0, 0, 62, 0, 0, 0, 83, 0, 83, 83,
- 0, 0, 148, 0, 0, 517, 0, 517, 0, 0,
- 0, 0, 102, 106, 0, 0, 0, 0, 517, 64,
- 0, 125, 517, 517, 517, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 157, 0, 0, 0, 0, 177,
- 0, 605, 0, 518, 522, 524, 0, 0, 0, 0,
- 64, 64, 64, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 64, 64, 0, 64, 8, 151,
- 10, 152, 604, 604, 839, 839, 12, 0, 0, 604,
- 839, 839, 839, 0, 0, 0, 0, 0, 0, 305,
- 0, 15, 0, 307, 0, 16, 64, 0, 0, 17,
- 0, 0, 0, 0, 0, 0, 0, 62, 150, 0,
- 329, 0, 0, 191, 0, 21, 0, 93, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 102, 106, 0,
+ 0, 0, 0, 258, 0, 981, 0, 259, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 1283, 260,
+ 1277, 0, 966, 967, 92, 10, 232, 233, 234, 0,
+ 235, 12, 968, 0, 969, 970, 971, 972, 973, 974,
+ 975, 976, 977, 978, 13, 14, 15, 236, 237, 238,
+ 16, 0, 239, 0, 17, 0, 240, 241, 0, 242,
+ 19, 243, 244, 0, 0, 245, 246, 247, 248, 249,
+ 21, 0, 979, 347, 0, 980, 0, 0, 0, 0,
+ 0, 250, 0, 0, 251, 0, 0, 0, 0, 0,
+ 0, 0, 252, 253, 254, 0, 0, 0, 0, 0,
+ 255, 256, 257, 0, 0, 0, 0, 258, 0, 981,
+ 0, 259, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 1322, 260, 965, 0, 966, 967, 92, 10,
+ 232, 233, 234, 0, 235, 12, 968, 0, 969, 970,
+ 971, 972, 973, 974, 975, 976, 977, 978, 13, 14,
+ 15, 236, 237, 238, 16, 0, 239, 0, 17, 0,
+ 240, 241, 0, 242, 19, 243, 244, 0, 0, 245,
+ 246, 247, 248, 249, 21, 0, 979, 347, 0, 980,
+ 0, 0, 0, 0, 0, 250, 0, 0, 251, 0,
+ 0, 0, 0, 0, 0, 0, 252, 253, 254, 0,
+ 0, 0, 0, 0, 255, 256, 257, 0, 0, 0,
+ 0, 258, 0, 981, 1249, 259, 966, 967, 92, 10,
+ 232, 233, 234, 0, 235, 12, 968, 260, 969, 970,
+ 971, 972, 973, 974, 975, 976, 977, 978, 13, 14,
+ 15, 236, 237, 238, 16, 0, 239, 0, 17, 0,
+ 240, 241, 0, 242, 19, 243, 244, 0, 0, 245,
+ 246, 247, 248, 249, 21, 0, 979, 347, 0, 980,
+ 0, 0, 0, 0, 0, 250, 0, 0, 251, 0,
+ 0, 0, 0, 0, 0, 0, 252, 253, 254, 0,
+ 0, 0, 0, 0, 255, 256, 257, 0, 0, 0,
+ 0, 258, 0, 981, 1310, 259, 966, 967, 92, 10,
+ 232, 233, 234, 0, 235, 12, 968, 260, 969, 970,
+ 971, 972, 973, 974, 975, 976, 977, 978, 13, 14,
+ 15, 236, 237, 238, 16, 0, 239, 0, 17, 0,
+ 240, 241, 0, 242, 19, 243, 244, 0, 0, 245,
+ 246, 247, 248, 249, 21, 0, 979, 347, 0, 980,
+ 0, 0, 0, 0, 0, 250, 0, 0, 251, 0,
+ 0, 0, 0, 0, 0, 0, 252, 253, 254, 0,
+ 0, 0, 0, 0, 255, 256, 257, 0, 0, 0,
+ 0, 258, 0, 981, 634, 259, 7, 8, 92, 10,
+ 232, 233, 234, 354, 235, 12, 0, 260, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 148, 473, 474, 475, 476, 477, 478, 479, 480, 481,
- 482, 483, 484, 485, 486, 754, 754, 0, 754, 0,
- 0, 0, 0, 83, 0, 0, 0, 0, 846, 0,
- 0, 418, 0, 83, 83, 83, 517, 517, 0, 0,
- 0, 424, 0, 0, 0, 0, 0, 0, 0, 0,
- 148, 148, 837, 769, 0, 771, 0, 0, 837, 0,
- 0, 0, 771, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 148, 148, 0, 148, 0, 150,
- 0, 150, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 522, 604, 604, 0, 604, 0, 0, 0,
- 0, 0, 0, 846, 846, 846, 837, 0, 0, 0,
- 0, 0, 0, 0, 83, 0, 83, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 83, 472, 473,
- 474, 475, 476, 477, 478, 479, 480, 481, 482, 483,
- 484, 485, 486, 769, 771, 0, 0, 64, 7, 8,
- 771, 10, 436, 233, 234, 0, 235, 12, 0, 0,
- 556, 0, 0, 557, 0, 0, 0, 558, 0, 0,
+ 15, 236, 237, 238, 16, 0, 239, 0, 17, 0,
+ 240, 241, 0, 242, 19, 243, 244, 0, 0, 245,
+ 246, 247, 248, 249, 21, 0, 22, 0, 0, 0,
+ 0, 0, 0, 0, 0, 250, 0, 0, 251, 0,
+ 0, 0, 0, 0, 0, 0, 252, 253, 254, 0,
+ 0, 0, 0, 0, 255, 256, 257, 0, 0, 0,
+ 0, 258, 0, 0, 0, 259, 355, 0, 0, 0,
+ 0, 0, 0, 0, 0, -666, 587, 260, 711, 712,
+ 0, 10, 437, 233, 234, 0, 235, 12, 474, 475,
+ 476, 477, 478, 479, 480, 481, 482, 483, 484, 485,
+ 486, 487, 15, 236, 237, 238, 16, 0, 239, 0,
+ 17, 0, 240, 241, 0, 242, 19, 243, 244, 0,
+ 0, 245, 246, 247, 248, 249, 21, 0, 713, 588,
+ 0, 0, 0, 0, 0, 0, 0, 250, 0, 0,
+ 251, 0, 0, 0, 0, 0, 0, 0, 252, 253,
+ 254, 0, 0, 0, 0, 0, 255, 256, 257, 0,
+ 0, 0, 0, 258, 714, 0, 587, 259, 711, 712,
+ 0, 10, 437, 233, 234, 0, 235, 12, 826, 260,
+ 0, 0, 0, 0, 1042, 0, 0, 0, 0, 0,
0, 0, 15, 236, 237, 238, 16, 0, 239, 0,
17, 0, 240, 241, 0, 242, 19, 243, 244, 0,
- 0, 245, 246, 247, 248, 249, 21, 380, 22, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 606, 0,
- 0, 0, 0, 0, 0, 616, 0, 522, 0, 0,
- 83, 305, 0, 307, 0, 0, 255, 256, 257, 0,
- 0, 0, 0, 258, 0, 0, 0, 259, 424, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 260,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 663, 666, 0, 418, 83, 83, 0, 83, 0, 0,
- 0, 0, 380, 380, 380, 0, 0, 0, 0, 0,
- 0, 0, 0, 148, 148, 148, 148, 0, 996, 0,
- 148, 837, 837, 837, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 927, 0,
- 928, 0, 0, 0, 0, 0, 150, 0, 0, 148,
- 0, 932, 0, 0, 0, 0, 769, 771, 0, 0,
- 0, 7, 8, 92, 10, 11, 0, 0, 353, 0,
- 12, 0, 7, 8, 151, 10, 152, 0, 0, 0,
- 0, 12, 0, 0, 0, 15, 0, 0, 0, 16,
- 0, 0, 0, 17, 0, 0, 15, 0, 0, 19,
- 16, 0, 0, 0, 17, 927, 928, 0, 769, 21,
- 19, 22, 932, 0, 769, 771, 0, 0, 0, 0,
- 21, 191, 22, 377, 0, 153, 0, 0, 0, 0,
- 0, 0, 0, 378, 24, 0, 0, 0, 0, 0,
- 0, 26, 0, 0, 25, 0, 141, 0, 0, 0,
- 0, 354, 26, 0, 0, 0, 0, 27, 0, 0,
- 148, 0, 148, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 148, 148, 0, 148, 102, 106,
- 467, 0, 468, 469, 470, 471, 472, 473, 474, 475,
- 476, 477, 478, 479, 480, 481, 482, 483, 484, 485,
- 486, 0, 556, 557, 0, 558, 0, 0, 0, 1101,
- 769, 962, 8, 92, 10, 232, 233, 234, 0, 235,
- 12, 963, 0, 964, 965, 966, 967, 968, 969, 970,
- 971, 972, 973, 13, 14, 15, 236, 237, 238, 16,
- 0, 239, 0, 17, 0, 240, 241, 0, 242, 19,
- 243, 244, 0, 0, 245, 246, 247, 248, 249, 21,
- 0, 974, 346, 0, 975, 0, 927, 928, 0, 932,
- 250, 0, 0, 251, 0, 0, 0, 0, 837, 0,
- 0, 252, 253, 254, 0, 0, 0, 0, 0, 255,
- 256, 257, 0, 0, 0, 0, 258, 0, 976, 454,
- 259, 7, 8, 92, 10, 232, 233, 234, 353, 235,
- 12, 1102, 260, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 15, 236, 237, 238, 16,
- 0, 239, 0, 17, 0, 240, 241, 0, 242, 19,
- 243, 244, 509, 0, 245, 246, 247, 248, 249, 21,
- 0, 22, -234, 837, 837, 837, 0, 0, 0, 0,
- 250, 0, 0, 937, 0, 0, 0, 0, 0, 0,
- 0, 252, 253, 938, 1160, 0, 0, 0, 0, 255,
- 256, 257, 0, 512, 0, 0, 785, 514, 0, 0,
- 259, 354, 0, 0, 0, 0, 0, 148, 0, 0,
- 0, 0, 260, 0, 0, 0, 0, 0, 0, 0,
- 0, 305, 307, 0, 0, 0, 0, 0, 424, 0,
- 0, 465, 466, 467, 1161, 468, 469, 470, 471, 472,
- 473, 474, 475, 476, 477, 478, 479, 480, 481, 482,
- 483, 484, 485, 486, 0, 0, 0, 1022, 0, 0,
- 1022, 1251, 418, 962, 8, 92, 10, 232, 233, 234,
- 0, 235, 12, 963, 0, 964, 965, 966, 967, 968,
- 969, 970, 971, 972, 973, 13, 14, 15, 236, 237,
- 238, 16, 0, 239, 0, 17, 0, 240, 241, 0,
- 242, 19, 243, 244, 0, 0, 245, 246, 247, 248,
- 249, 21, 0, 974, 346, 0, 975, 0, 0, 0,
- 0, 0, 250, 0, 0, 251, 0, 0, 0, 0,
- 0, 0, 0, 252, 253, 254, 0, 418, 0, 0,
- 0, 255, 256, 257, 0, 0, 0, 0, 258, 0,
- 976, 0, 259, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 1252, 260, 0, 0, 0, 0, 1097,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 556, 557, 0, 558, 0, 0, 0, 0,
+ 0, 245, 246, 247, 248, 249, 21, 0, 713, 588,
+ 0, 0, 0, 0, 0, 0, 0, 250, 0, 0,
+ 251, 0, 0, 0, 0, 0, 0, 0, 252, 253,
+ 254, 0, 0, 0, 0, 0, 255, 256, 257, 0,
+ 0, 0, 0, 258, 0, 0, 587, 259, 711, 712,
+ 0, 10, 437, 233, 234, 0, 235, 12, -384, 260,
+ 0, 0, 0, 0, 1042, 0, 0, 0, 0, 0,
+ 0, 0, 15, 236, 237, 238, 16, 0, 239, 0,
+ 17, 0, 240, 241, 0, 242, 19, 243, 244, 0,
+ 0, 245, 246, 247, 248, 249, 21, 0, 713, 588,
+ 0, 0, 0, 0, 0, 0, 0, 250, 0, 0,
+ 251, 0, 0, 0, 0, 0, 0, 0, 252, 253,
+ 254, 0, 0, 0, 0, 0, 255, 256, 257, 0,
+ 0, 0, 0, 258, 0, 0, 1158, 259, 7, 8,
+ 92, 10, 232, 233, 234, 0, 235, 12, 1071, 260,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 1273, 0, 962, 8, 92, 10, 232, 233, 234,
- 0, 235, 12, 963, 418, 964, 965, 966, 967, 968,
- 969, 970, 971, 972, 973, 13, 14, 15, 236, 237,
- 238, 16, 0, 239, 0, 17, 0, 240, 241, 0,
- 242, 19, 243, 244, 0, 0, 245, 246, 247, 248,
- 249, 21, 0, 974, 346, 0, 975, 0, 0, 0,
- 0, 0, 250, 0, 0, 251, 0, 0, 0, 0,
- 0, 0, 0, 252, 253, 254, 0, 0, 0, 0,
- 0, 255, 256, 257, 0, 0, 0, 0, 258, 0,
- 976, 0, 259, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 1274, 260, 1273, 0, 962, 8, 92,
- 10, 232, 233, 234, 0, 235, 12, 963, 0, 964,
- 965, 966, 967, 968, 969, 970, 971, 972, 973, 13,
- 14, 15, 236, 237, 238, 16, 0, 239, 0, 17,
- 0, 240, 241, 0, 242, 19, 243, 244, 0, 0,
- 245, 246, 247, 248, 249, 21, 0, 974, 346, 0,
- 975, 0, 0, 0, 0, 0, 250, 0, 0, 251,
- 0, 0, 0, 0, 0, 0, 0, 252, 253, 254,
- 0, 0, 0, 0, 0, 255, 256, 257, 0, 0,
- 0, 0, 258, 0, 976, 0, 259, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 1279, 260, 1273,
- 0, 962, 8, 92, 10, 232, 233, 234, 0, 235,
- 12, 963, 0, 964, 965, 966, 967, 968, 969, 970,
- 971, 972, 973, 13, 14, 15, 236, 237, 238, 16,
- 0, 239, 0, 17, 0, 240, 241, 0, 242, 19,
- 243, 244, 0, 0, 245, 246, 247, 248, 249, 21,
- 0, 974, 346, 0, 975, 0, 0, 0, 0, 0,
- 250, 0, 0, 251, 0, 0, 0, 0, 0, 0,
- 0, 252, 253, 254, 0, 0, 0, 0, 0, 255,
- 256, 257, 0, 0, 0, 0, 258, 0, 976, 0,
- 259, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 1318, 260, 961, 0, 962, 8, 92, 10, 232,
- 233, 234, 0, 235, 12, 963, 0, 964, 965, 966,
- 967, 968, 969, 970, 971, 972, 973, 13, 14, 15,
- 236, 237, 238, 16, 0, 239, 0, 17, 0, 240,
- 241, 0, 242, 19, 243, 244, 0, 0, 245, 246,
- 247, 248, 249, 21, 0, 974, 346, 0, 975, 0,
- 0, 0, 0, 0, 250, 0, 0, 251, 0, 0,
- 0, 0, 0, 0, 0, 252, 253, 254, 0, 0,
- 0, 0, 0, 255, 256, 257, 0, 0, 0, 0,
- 258, 0, 976, 1245, 259, 962, 8, 92, 10, 232,
- 233, 234, 0, 235, 12, 963, 260, 964, 965, 966,
- 967, 968, 969, 970, 971, 972, 973, 13, 14, 15,
+ 0, 0, 15, 236, 237, 238, 16, 0, 239, 0,
+ 17, 0, 240, 241, 0, 242, 19, 243, 244, 0,
+ 0, 245, 246, 247, 248, 249, 21, 0, 22, 1159,
+ 0, 1160, 0, 0, 0, 0, 0, 250, 0, 0,
+ 251, 0, 0, 0, 0, 0, 0, 0, 252, 253,
+ 254, 0, 0, 0, 0, 0, 255, 256, 257, 196,
+ 0, 0, 8, 258, 10, 11, 0, 259, 0, 0,
+ 12, 0, 0, 0, 0, 0, 0, 0, 0, 260,
+ 0, 0, 0, 0, 0, 15, 0, 0, 0, 16,
+ 0, 0, 0, 17, 0, 197, 198, 0, 0, 0,
+ 0, 0, 199, 0, 0, 0, 0, 0, 0, 21,
+ 0, 93, 0, 200, 0, 201, 202, 203, 0, 204,
+ 205, 206, 207, 208, 209, 210, 211, 212, 213, 214,
+ 215, 216, 217, 218, 219, 220, 221, 0, 0, 222,
+ 223, 224, 0, 455, 225, 7, 8, 226, 10, 232,
+ 233, 234, 0, 235, 12, 0, 0, 0, 0, 0,
+ 0, 0, 227, 0, 0, 0, 0, 0, 0, 15,
236, 237, 238, 16, 0, 239, 0, 17, 0, 240,
241, 0, 242, 19, 243, 244, 0, 0, 245, 246,
- 247, 248, 249, 21, 0, 974, 346, 0, 975, 0,
+ 247, 248, 249, 21, 0, 22, -237, 0, 0, 0,
0, 0, 0, 0, 250, 0, 0, 251, 0, 0,
0, 0, 0, 0, 0, 252, 253, 254, 0, 0,
0, 0, 0, 255, 256, 257, 0, 0, 0, 0,
- 258, 0, 976, 1306, 259, 962, 8, 92, 10, 232,
- 233, 234, 0, 235, 12, 963, 260, 964, 965, 966,
- 967, 968, 969, 970, 971, 972, 973, 13, 14, 15,
+ 258, 0, 0, 587, 259, 7, 8, 0, 10, 437,
+ 233, 234, 0, 235, 12, 0, 260, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 15,
236, 237, 238, 16, 0, 239, 0, 17, 0, 240,
241, 0, 242, 19, 243, 244, 0, 0, 245, 246,
- 247, 248, 249, 21, 0, 974, 346, 0, 975, 0,
+ 247, 248, 249, 21, 0, 22, 588, 0, 0, 0,
0, 0, 0, 0, 250, 0, 0, 251, 0, 0,
0, 0, 0, 0, 0, 252, 253, 254, 0, 0,
0, 0, 0, 255, 256, 257, 0, 0, 0, 0,
- 258, 0, 976, 454, 259, 7, 8, 92, 10, 232,
- 233, 234, 353, 235, 12, 0, 260, 0, 0, 0,
+ 258, 0, 0, 455, 259, 7, 8, 0, 10, 232,
+ 233, 234, 0, 235, 12, 0, 260, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 15,
236, 237, 238, 16, 0, 239, 0, 17, 0, 240,
- 241, 0, 242, 19, 243, 244, 509, 0, 245, 246,
- 247, 248, 249, 21, 0, 22, -234, 0, 0, 0,
- 0, 0, 0, 0, 250, 0, 0, 841, 0, 0,
- 0, 0, 0, 0, 0, 252, 253, 842, 0, 0,
- 0, 0, 0, 255, 256, 257, 0, 512, 0, 0,
- 843, 514, 0, 0, 259, 354, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 352, 260, 7, 8, 92,
- 10, 232, 233, 234, 353, 235, 12, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 15, 236, 237, 238, 16, 0, 239, 0, 17,
- 0, 240, 241, 0, 242, 19, 243, 244, 0, 0,
- 245, 246, 247, 248, 249, 21, 0, 22, 0, 0,
- 0, 0, 0, 0, 0, 0, 250, 0, 0, 251,
- 0, 0, 0, 0, 0, 0, 0, 252, 253, 254,
- 0, 0, 0, 0, 0, 255, 256, 257, 0, 0,
- 0, 0, 258, 0, 0, 0, 259, 354, 0, 0,
- 0, 0, 0, 0, 0, 0, -662, 631, 260, 7,
- 8, 92, 10, 232, 233, 234, 353, 235, 12, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 15, 236, 237, 238, 16, 0, 239,
- 0, 17, 0, 240, 241, 0, 242, 19, 243, 244,
- 0, 0, 245, 246, 247, 248, 249, 21, 0, 22,
- 0, 0, 0, 0, 0, 0, 0, 0, 250, 0,
- 0, 251, 0, 0, 0, 0, 0, 0, 0, 252,
- 253, 254, 0, 0, 0, 0, 0, 255, 256, 257,
- 0, 0, 0, 0, 258, 0, 0, 0, 259, 354,
- 0, 0, 0, 0, 0, 0, 0, 0, -662, 584,
- 260, 708, 709, 0, 10, 436, 233, 234, 0, 235,
- 12, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 15, 236, 237, 238, 16,
- 0, 239, 0, 17, 0, 240, 241, 0, 242, 19,
- 243, 244, 0, 0, 245, 246, 247, 248, 249, 21,
- 0, 710, 585, 0, 0, 0, 0, 0, 0, 0,
- 250, 0, 0, 251, 0, 0, 0, 0, 0, 0,
- 0, 252, 253, 254, 0, 0, 0, 0, 0, 255,
- 256, 257, 0, 0, 0, 0, 258, 711, 0, 584,
- 259, 708, 709, 0, 10, 436, 233, 234, 0, 235,
- 12, 822, 260, 0, 0, 0, 0, 1038, 0, 0,
- 0, 0, 0, 0, 0, 15, 236, 237, 238, 16,
- 0, 239, 0, 17, 0, 240, 241, 0, 242, 19,
- 243, 244, 0, 0, 245, 246, 247, 248, 249, 21,
- 0, 710, 585, 0, 0, 0, 0, 0, 0, 0,
- 250, 0, 0, 251, 0, 0, 0, 0, 0, 0,
- 0, 252, 253, 254, 0, 0, 0, 0, 0, 255,
- 256, 257, 0, 0, 0, 0, 258, 0, 0, 584,
- 259, 708, 709, 0, 10, 436, 233, 234, 0, 235,
- 12, -381, 260, 0, 0, 0, 0, 1038, 0, 0,
- 0, 0, 0, 0, 0, 15, 236, 237, 238, 16,
- 0, 239, 0, 17, 0, 240, 241, 0, 242, 19,
- 243, 244, 0, 0, 245, 246, 247, 248, 249, 21,
- 0, 710, 585, 0, 0, 0, 0, 0, 0, 0,
- 250, 0, 0, 251, 0, 0, 0, 0, 0, 0,
- 0, 252, 253, 254, 0, 0, 0, 0, 0, 255,
- 256, 257, 0, 0, 0, 0, 258, 0, 0, 1154,
- 259, 7, 8, 92, 10, 232, 233, 234, 0, 235,
- 12, 1068, 260, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 15, 236, 237, 238, 16,
- 0, 239, 0, 17, 0, 240, 241, 0, 242, 19,
- 243, 244, 0, 0, 245, 246, 247, 248, 249, 21,
- 0, 22, 1155, 0, 1156, 0, 0, 0, 0, 0,
- 250, 0, 0, 251, 0, 0, 0, 0, 0, 0,
- 0, 252, 253, 254, 0, 0, 0, 0, 0, 255,
- 256, 257, 0, 0, 0, 0, 258, 0, 0, 454,
- 259, 7, 8, 0, 10, 232, 233, 234, 0, 235,
- 12, 0, 260, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 15, 236, 237, 238, 16,
- 0, 239, 0, 17, 0, 240, 241, 0, 242, 19,
- 243, 244, 0, 0, 245, 246, 247, 248, 249, 21,
- 0, 22, -234, 0, 0, 0, 0, 0, 0, 0,
- 250, 0, 0, 251, 0, 0, 0, 0, 0, 0,
- 0, 252, 253, 254, 0, 0, 0, 0, 0, 255,
- 256, 257, 0, 0, 0, 0, 258, 0, 0, 584,
- 259, 7, 8, 0, 10, 436, 233, 234, 0, 235,
- 12, 0, 260, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 15, 236, 237, 238, 16,
- 0, 239, 0, 17, 0, 240, 241, 0, 242, 19,
- 243, 244, 0, 0, 245, 246, 247, 248, 249, 21,
- 0, 22, 585, 0, 0, 0, 0, 0, 0, 0,
- 250, 0, 0, 251, 0, 0, 0, 0, 0, 0,
- 0, 252, 253, 254, 0, 0, 0, 0, 0, 255,
- 256, 257, 0, 0, 0, 0, 258, 0, 0, 718,
- 259, 7, 8, 0, 10, 436, 233, 234, 0, 235,
- 12, 0, 260, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 15, 236, 237, 238, 16,
- 0, 239, 0, 17, 0, 240, 241, 0, 242, 19,
- 243, 244, 0, 0, 245, 246, 247, 248, 249, 21,
- 0, 22, 0, 0, 0, 0, 0, 0, -652, 0,
- 250, 0, 0, 251, 0, 0, 0, 0, 0, 0,
- 0, 252, 253, 254, 0, 0, 0, 0, 0, 255,
- 256, 257, 0, 0, 0, 0, 258, 0, 0, 454,
- 259, 7, 8, 0, 10, 232, 233, 234, 0, 235,
- 12, 0, 260, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 15, 236, 237, 238, 16,
- 0, 239, 0, 17, 0, 240, 241, 0, 242, 19,
- 243, 244, 0, 0, 245, 246, 247, 248, 249, 21,
- 0, 22, -234, 0, 0, 0, 0, 0, 0, 0,
- 250, 0, 0, 1173, 0, 0, 0, 0, 0, 0,
- 0, 252, 253, 1174, 0, 0, 0, 0, 0, 255,
- 256, 257, 0, 0, 0, 0, 1175, 0, 0, 1225,
- 259, 7, 8, 0, 10, 232, 233, 234, 0, 235,
- 12, 0, 260, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 15, 236, 237, 238, 16,
- 0, 239, 0, 17, 0, 240, 241, 0, 242, 19,
- 243, 244, 0, 0, 245, 246, 247, 248, 249, 21,
- 0, 22, 0, 0, -136, 0, 0, 0, 0, 0,
- 250, 0, 0, 251, 0, 0, 0, 0, 0, 0,
- 0, 252, 253, 254, 0, 0, 0, 0, 0, 255,
- 256, 257, 0, 0, 0, 0, 258, 0, 0, 718,
- 259, 7, 8, 0, 10, 436, 233, 234, 0, 235,
- 12, 0, 260, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 15, 236, 237, 238, 16,
- 0, 239, 0, 17, 0, 240, 241, 0, 242, 19,
- 243, 244, 0, 0, 245, 246, 247, 248, 249, 21,
- 0, 22, 0, 0, 0, 0, 0, 0, 0, 0,
- 250, 0, 0, 251, 0, 0, 0, 0, 0, 0,
- 0, 252, 253, 254, 0, 0, 0, 0, 0, 255,
- 256, 257, 0, 0, 0, 0, 258, 0, 0, 0,
- 259, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- -652, 797, 260, 7, 8, 0, 10, 436, 233, 234,
- 0, 235, 12, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 15, 236, 237,
- 238, 16, 0, 239, 0, 17, 0, 240, 241, 0,
- 242, 19, 243, 244, 0, 0, 245, 246, 247, 248,
- 249, 21, 0, 22, 0, 0, 0, 0, 0, 0,
- 0, 0, 250, 0, 0, 251, 0, 0, 0, 0,
- 0, 0, 0, 252, 253, 254, 0, 0, 0, 0,
- 0, 255, 256, 257, 0, 0, 0, 0, 258, 0,
- 0, 799, 259, 7, 8, 0, 10, 436, 233, 234,
- 0, 235, 12, 0, 260, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 15, 236, 237,
- 238, 16, 0, 239, 0, 17, 0, 240, 241, 0,
- 242, 19, 243, 244, 0, 0, 245, 246, 247, 248,
- 249, 21, 0, 22, 0, 0, 0, 0, 0, 0,
- 0, 0, 250, 0, 0, 251, 0, 0, 0, 0,
- 0, 0, 0, 252, 253, 254, 0, 0, 0, 0,
- 0, 255, 256, 257, 0, 0, 0, 0, 258, 0,
- 7, 8, 259, 10, 436, 233, 234, 0, 235, 12,
- 0, 0, 0, 0, 260, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 15, 236, 237, 238, 16, 0,
- 239, 0, 17, 0, 240, 241, 0, 242, 19, 243,
- 244, 0, 0, 245, 246, 247, 248, 249, 21, 0,
- 22, 0, 0, 0, 0, 0, 0, 0, 0, 250,
- 0, 0, 251, 0, 0, 0, 0, 0, 0, 0,
- 252, 253, 254, 0, 0, 0, 0, 0, 255, 256,
- 257, 0, 0, 0, 0, 258, 0, 0, 0, 259,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 260, 757, 962, 8, 92, 10, 232, 233, 234,
- 0, 235, 12, 963, 0, 964, 965, 966, 967, 968,
- 969, 970, 971, 972, 973, 13, 14, 15, 236, 237,
- 238, 16, 0, 239, 0, 17, 0, 240, 241, 0,
- 242, 19, 243, 244, 0, 0, 245, 246, 247, 248,
- 249, 21, 0, 974, 346, 0, 975, 0, 0, 0,
- 0, 0, 250, 0, 0, 251, 0, 0, 0, 0,
- 0, 0, 0, 252, 253, 254, 0, 0, 0, 0,
- 0, 255, 256, 257, 0, 0, 0, 0, 258, 0,
- 976, 0, 259, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 1106, 260, 962, 8, 92, 10, 232,
- 233, 234, 0, 235, 12, 963, 0, 964, 965, 966,
- 967, 968, 969, 970, 971, 972, 973, 13, 14, 15,
- 236, 237, 238, 16, 0, 239, 0, 17, 0, 240,
241, 0, 242, 19, 243, 244, 0, 0, 245, 246,
- 247, 248, 249, 21, 0, 974, 346, 0, 975, 0,
- 0, 0, 0, 0, 250, 0, 0, 251, 0, 0,
- 0, 0, 0, 0, 0, 252, 253, 254, 0, 0,
+ 247, 248, 249, 21, 0, 22, -237, 0, 0, 0,
+ 0, 0, 0, 0, 250, 0, 0, 1177, 0, 0,
+ 0, 0, 0, 0, 0, 252, 253, 1178, 0, 0,
0, 0, 0, 255, 256, 257, 0, 0, 0, 0,
- 258, 0, 976, 0, 259, 962, 8, 92, 10, 232,
- 233, 234, 0, 235, 12, 963, 260, 964, 965, 966,
- 967, 968, 969, 970, 971, 972, 973, 13, 14, 15,
+ 1179, 0, 0, 1229, 259, 7, 8, 0, 10, 232,
+ 233, 234, 0, 235, 12, 0, 260, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 15,
236, 237, 238, 16, 0, 239, 0, 17, 0, 240,
241, 0, 242, 19, 243, 244, 0, 0, 245, 246,
- 247, 248, 249, 21, 0, 974, 1266, 0, 975, 0,
+ 247, 248, 249, 21, 0, 22, 0, 0, -139, 0,
0, 0, 0, 0, 250, 0, 0, 251, 0, 0,
0, 0, 0, 0, 0, 252, 253, 254, 0, 0,
0, 0, 0, 255, 256, 257, 0, 0, 0, 0,
- 258, 0, 976, 0, 259, 962, 8, 92, 10, 232,
- 233, 234, 0, 235, 12, 963, 260, 964, 965, 966,
- 967, 968, 969, 970, 971, 972, 973, 13, 14, 15,
+ 258, 0, 0, 721, 259, 7, 8, 0, 10, 437,
+ 233, 234, 0, 235, 12, 0, 260, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 15,
236, 237, 238, 16, 0, 239, 0, 17, 0, 240,
241, 0, 242, 19, 243, 244, 0, 0, 245, 246,
- 247, 248, 249, 21, 0, 974, 0, 0, 975, 0,
+ 247, 248, 249, 21, 0, 22, 0, 0, 0, 0,
0, 0, 0, 0, 250, 0, 0, 251, 0, 0,
0, 0, 0, 0, 0, 252, 253, 254, 0, 0,
0, 0, 0, 255, 256, 257, 0, 0, 0, 0,
- 258, 0, 976, 0, 259, 7, 8, 92, 10, 232,
- 233, 234, 353, 235, 12, 0, 260, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 15,
- 236, 237, 238, 16, 0, 239, 0, 17, 0, 240,
- 241, 0, 242, 19, 243, 244, 509, 0, 245, 246,
- 247, 248, 249, 21, 0, 22, 0, 0, 0, 0,
- 0, 0, 0, 0, 250, 0, 0, 783, 0, 0,
- 0, 0, 0, 0, 0, 252, 253, 784, 0, 0,
- 0, 0, 0, 255, 256, 257, 0, 512, 0, 0,
- 785, 514, 0, 0, 259, 354, 7, 8, 92, 10,
- 232, 233, 234, 353, 235, 12, 260, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 15, 236, 237, 238, 16, 0, 239, 0, 17, 0,
- 240, 241, 0, 242, 19, 243, 244, 509, 0, 245,
- 246, 247, 248, 249, 21, 0, 22, 0, 0, 0,
- 0, 0, 0, 0, 0, 250, 0, 0, 841, 0,
- 0, 0, 0, 0, 0, 0, 252, 253, 842, 0,
- 0, 0, 0, 0, 255, 256, 257, 0, 512, 0,
- 0, 843, 514, 0, 0, 259, 354, 7, 8, 0,
- 10, 232, 233, 234, 0, 235, 12, 260, 0, 0,
+ 258, 0, 0, 0, 259, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, -656, 800, 260, 7, 8, 0,
+ 10, 437, 233, 234, 0, 235, 12, 475, 476, 477,
+ 478, 479, 480, 481, 482, 483, 484, 485, 486, 487,
+ 0, 15, 236, 237, 238, 16, 0, 239, 0, 17,
+ 0, 240, 241, 0, 242, 19, 243, 244, 0, 0,
+ 245, 246, 247, 248, 249, 21, 0, 22, 0, 0,
+ 0, 0, 0, 0, 0, 0, 250, 0, 0, 251,
+ 0, 0, 0, 0, 0, 0, 0, 252, 253, 254,
+ 0, 0, 0, 0, 0, 255, 256, 257, 0, 0,
+ 0, 0, 258, 0, 0, 802, 259, 7, 8, 0,
+ 10, 437, 233, 234, 0, 235, 12, 0, 260, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 15, 236, 237, 238, 16, 0, 239, 0, 17,
- 0, 240, 241, 0, 242, 19, 243, 244, 509, 0,
+ 0, 240, 241, 0, 242, 19, 243, 244, 0, 0,
245, 246, 247, 248, 249, 21, 0, 22, 0, 0,
- 0, 0, 0, 0, 0, 0, 250, 0, 0, 783,
- 0, 0, 0, 0, 0, 0, 0, 252, 253, 784,
- 0, 0, 0, 0, 0, 255, 256, 257, 0, 512,
- 0, 0, 785, 514, 7, 8, 0, 10, 232, 233,
+ 0, 0, 0, 0, 0, 0, 250, 0, 0, 251,
+ 0, 0, 0, 0, 0, 0, 0, 252, 253, 254,
+ 0, 0, 0, 0, 0, 255, 256, 257, 0, 0,
+ 0, 0, 258, 0, 7, 8, 259, 10, 437, 233,
234, 0, 235, 12, 0, 0, 0, 0, 260, 0,
0, 0, 0, 0, 0, 0, 0, 0, 15, 236,
237, 238, 16, 0, 239, 0, 17, 0, 240, 241,
- 0, 242, 19, 243, 244, 509, 0, 245, 246, 247,
+ 0, 242, 19, 243, 244, 0, 0, 245, 246, 247,
248, 249, 21, 0, 22, 0, 0, 0, 0, 0,
- 0, 0, 0, 250, 0, 0, 841, 0, 0, 0,
- 0, 0, 0, 0, 252, 253, 842, 0, 0, 0,
- 0, 0, 255, 256, 257, 0, 512, 0, 0, 843,
- 514, 7, 8, 0, 10, 232, 233, 234, 0, 235,
- 12, 0, 0, 0, 0, 260, 0, 0, 0, 0,
+ 0, 0, 0, 250, 0, 0, 251, 0, 0, 0,
+ 0, 0, 0, 0, 252, 253, 254, 0, 0, 0,
+ 0, 0, 255, 256, 257, 0, 0, 0, 0, 258,
+ 0, 0, 0, 259, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 260, 760, 966, 967, 92,
+ 10, 232, 233, 234, 0, 235, 12, 968, 0, 969,
+ 970, 971, 972, 973, 974, 975, 976, 977, 978, 13,
+ 14, 15, 236, 237, 238, 16, 0, 239, 0, 17,
+ 0, 240, 241, 0, 242, 19, 243, 244, 0, 0,
+ 245, 246, 247, 248, 249, 21, 0, 979, 347, 0,
+ 980, 0, 0, 0, 0, 0, 250, 0, 0, 251,
+ 0, 0, 0, 0, 0, 0, 0, 252, 253, 254,
+ 0, 0, 0, 0, 0, 255, 256, 257, 0, 0,
+ 0, 0, 258, 0, 981, 0, 259, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 1110, 260, 966,
+ 967, 92, 10, 232, 233, 234, 0, 235, 12, 968,
+ 0, 969, 970, 971, 972, 973, 974, 975, 976, 977,
+ 978, 13, 14, 15, 236, 237, 238, 16, 0, 239,
+ 0, 17, 0, 240, 241, 0, 242, 19, 243, 244,
+ 0, 0, 245, 246, 247, 248, 249, 21, 0, 979,
+ 347, 0, 980, 0, 0, 0, 0, 0, 250, 0,
+ 0, 251, 0, 0, 0, 0, 0, 0, 0, 252,
+ 253, 254, 0, 0, 0, 0, 0, 255, 256, 257,
+ 0, 0, 0, 0, 258, 0, 981, 0, 259, 966,
+ 967, 92, 10, 232, 233, 234, 0, 235, 12, 968,
+ 260, 969, 970, 971, 972, 973, 974, 975, 976, 977,
+ 978, 13, 14, 15, 236, 237, 238, 16, 0, 239,
+ 0, 17, 0, 240, 241, 0, 242, 19, 243, 244,
+ 0, 0, 245, 246, 247, 248, 249, 21, 0, 979,
+ 1270, 0, 980, 0, 0, 0, 0, 0, 250, 0,
+ 0, 251, 0, 0, 0, 0, 0, 0, 0, 252,
+ 253, 254, 0, 0, 0, 0, 0, 255, 256, 257,
+ 0, 0, 0, 0, 258, 0, 981, 0, 259, 966,
+ 967, 92, 10, 232, 233, 234, 0, 235, 12, 968,
+ 260, 969, 970, 971, 972, 973, 974, 975, 976, 977,
+ 978, 13, 14, 15, 236, 237, 238, 16, 0, 239,
+ 0, 17, 0, 240, 241, 0, 242, 19, 243, 244,
+ 0, 0, 245, 246, 247, 248, 249, 21, 0, 979,
+ 0, 0, 980, 0, 0, 0, 0, 0, 250, 0,
+ 0, 251, 0, 0, 0, 0, 0, 0, 0, 252,
+ 253, 254, 0, 0, 0, 0, 0, 255, 256, 257,
+ 0, 0, 0, 0, 258, 0, 981, 0, 259, 7,
+ 8, 92, 10, 232, 233, 234, 354, 235, 12, 0,
+ 260, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 15, 236, 237, 238, 16, 0, 239,
+ 0, 17, 0, 240, 241, 0, 242, 19, 243, 244,
+ 510, 0, 245, 246, 247, 248, 249, 21, 0, 22,
+ 0, 0, 0, 0, 0, 0, 0, 0, 250, 0,
+ 0, 786, 0, 0, 0, 0, 0, 0, 0, 252,
+ 253, 787, 0, 0, 0, 0, 0, 255, 256, 257,
+ 0, 513, 0, 0, 788, 515, 0, 0, 259, 355,
+ 7, 8, 92, 10, 232, 233, 234, 354, 235, 12,
+ 260, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 15, 236, 237, 238, 16, 0,
+ 239, 0, 17, 0, 240, 241, 0, 242, 19, 243,
+ 244, 510, 0, 245, 246, 247, 248, 249, 21, 0,
+ 22, 0, 0, 0, 0, 0, 0, 0, 0, 250,
+ 0, 0, 845, 0, 0, 0, 0, 0, 0, 0,
+ 252, 253, 846, 0, 0, 0, 0, 0, 255, 256,
+ 257, 0, 513, 0, 0, 847, 515, 0, 0, 259,
+ 355, 7, 8, 0, 10, 232, 233, 234, 0, 235,
+ 12, 260, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 15, 236, 237, 238, 16,
0, 239, 0, 17, 0, 240, 241, 0, 242, 19,
- 243, 244, 509, 0, 245, 246, 247, 248, 249, 21,
+ 243, 244, 510, 0, 245, 246, 247, 248, 249, 21,
0, 22, 0, 0, 0, 0, 0, 0, 0, 0,
- 250, 0, 0, 937, 0, 0, 0, 0, 0, 0,
- 0, 252, 253, 938, 0, 0, 0, 0, 0, 255,
- 256, 257, 0, 512, 0, 0, 785, 514, 7, 8,
- 0, 10, 436, 233, 234, 0, 235, 12, 0, 0,
+ 250, 0, 0, 786, 0, 0, 0, 0, 0, 0,
+ 0, 252, 253, 787, 0, 0, 0, 0, 0, 255,
+ 256, 257, 0, 513, 0, 0, 788, 515, 7, 8,
+ 0, 10, 232, 233, 234, 0, 235, 12, 0, 0,
0, 0, 260, 0, 0, 0, 0, 0, 0, 0,
0, 0, 15, 236, 237, 238, 16, 0, 239, 0,
- 17, 0, 240, 241, 0, 242, 19, 243, 244, 0,
+ 17, 0, 240, 241, 0, 242, 19, 243, 244, 510,
0, 245, 246, 247, 248, 249, 21, 0, 22, 0,
- 0, 1083, 0, 0, 0, 0, 0, 250, 0, 0,
- 251, 0, 0, 0, 0, 0, 0, 0, 252, 253,
- 254, 0, 0, 0, 0, 0, 255, 256, 257, 0,
- 0, 0, 0, 258, 0, 7, 8, 259, 10, 232,
+ 0, 0, 0, 0, 0, 0, 0, 250, 0, 0,
+ 845, 0, 0, 0, 0, 0, 0, 0, 252, 253,
+ 846, 0, 0, 0, 0, 0, 255, 256, 257, 0,
+ 513, 0, 0, 847, 515, 7, 8, 0, 10, 232,
233, 234, 0, 235, 12, 0, 0, 0, 0, 260,
0, 0, 0, 0, 0, 0, 0, 0, 0, 15,
236, 237, 238, 16, 0, 239, 0, 17, 0, 240,
- 241, 0, 242, 19, 243, 244, 0, 0, 245, 246,
+ 241, 0, 242, 19, 243, 244, 510, 0, 245, 246,
247, 248, 249, 21, 0, 22, 0, 0, 0, 0,
- 0, 0, 0, 0, 250, 0, 0, 251, 0, 0,
- 0, 0, 0, 0, 0, 252, 253, 254, 0, 0,
- 0, 0, 0, 255, 256, 257, 0, 0, 0, 0,
- 258, 0, 7, 8, 259, 10, 436, 233, 234, 0,
- 235, 12, 0, 0, 0, 0, 260, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 15, 236, 237, 238,
- 16, 0, 239, 0, 17, 0, 240, 241, 0, 242,
- 19, 243, 244, 0, 0, 245, 246, 247, 248, 249,
- 21, 0, 22, 462, 0, 0, 0, 0, 0, 0,
- 0, 250, 0, 0, 251, 0, 0, 0, 0, 0,
- 0, 0, 252, 253, 254, 0, 0, 0, 0, 0,
- 255, 256, 257, 0, 0, 7, 8, 463, 10, 436,
- 233, 234, 0, 235, 12, 0, 0, 0, 0, 0,
- 0, 0, 0, 260, 0, 0, 0, 0, 0, 15,
- 236, 237, 238, 16, 0, 239, 0, 17, 0, 240,
- 241, 0, 242, 19, 243, 244, 0, 0, 245, 246,
- 247, 248, 249, 21, 0, 22, 0, 0, 0, 0,
- 0, 0, 0, 0, 250, 0, 0, 251, 0, 0,
- 0, 0, 0, 0, 0, 252, 253, 254, 0, 0,
- 0, 0, 0, 255, 256, 257, 0, 0, 0, 0,
- 258, 499, 7, 8, 0, 10, 436, 233, 234, 0,
+ 0, 0, 0, 0, 250, 0, 0, 940, 0, 0,
+ 0, 0, 0, 0, 0, 252, 253, 941, 0, 0,
+ 0, 0, 0, 255, 256, 257, 0, 513, 0, 0,
+ 788, 515, 7, 8, 0, 10, 232, 233, 234, 0,
235, 12, 0, 0, 0, 0, 260, 0, 0, 0,
0, 0, 0, 0, 0, 0, 15, 236, 237, 238,
16, 0, 239, 0, 17, 0, 240, 241, 0, 242,
19, 243, 244, 0, 0, 245, 246, 247, 248, 249,
21, 0, 22, 0, 0, 0, 0, 0, 0, 0,
- 0, 250, 0, 0, 251, 0, 0, 0, 0, 0,
+ 0, 250, 0, 0, 251, 0, 0, 0, 0, 304,
0, 0, 252, 253, 254, 0, 0, 0, 0, 0,
255, 256, 257, 0, 0, 0, 0, 258, 0, 7,
- 694, 259, 10, 436, 233, 234, 0, 235, 12, 0,
+ 8, 259, 10, 437, 233, 234, 0, 235, 12, 0,
0, 0, 0, 260, 0, 0, 0, 0, 0, 0,
0, 0, 0, 15, 236, 237, 238, 16, 0, 239,
0, 17, 0, 240, 241, 0, 242, 19, 243, 244,
0, 0, 245, 246, 247, 248, 249, 21, 0, 22,
- 0, 0, 0, 0, 0, 0, 0, 0, 250, 0,
+ 0, 0, 1087, 0, 0, 0, 0, 0, 250, 0,
0, 251, 0, 0, 0, 0, 0, 0, 0, 252,
253, 254, 0, 0, 0, 0, 0, 255, 256, 257,
0, 0, 0, 0, 258, 0, 7, 8, 259, 10,
- 436, 233, 234, 0, 235, 12, 0, 0, 0, 0,
+ 232, 233, 234, 0, 235, 12, 0, 0, 0, 0,
260, 0, 0, 0, 0, 0, 0, 0, 0, 0,
15, 236, 237, 238, 16, 0, 239, 0, 17, 0,
240, 241, 0, 242, 19, 243, 244, 0, 0, 245,
246, 247, 248, 249, 21, 0, 22, 0, 0, 0,
- 0, 0, 0, 0, 0, 250, 0, 0, 887, 0,
- 0, 0, 0, 0, 0, 0, 252, 253, 888, 0,
+ 0, 0, 0, 0, 0, 250, 0, 0, 251, 0,
+ 0, 0, 0, 0, 0, 0, 252, 253, 254, 0,
+ 0, 0, 0, 0, 255, 256, 257, 0, 0, 0,
+ 0, 258, 0, 7, 8, 259, 10, 437, 233, 234,
+ 0, 235, 12, 0, 0, 0, 0, 260, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 15, 236, 237,
+ 238, 16, 0, 239, 0, 17, 0, 240, 241, 0,
+ 242, 19, 243, 244, 0, 0, 245, 246, 247, 248,
+ 249, 21, 0, 22, 463, 0, 0, 0, 0, 0,
+ 0, 0, 250, 0, 0, 251, 0, 0, 0, 0,
+ 0, 0, 0, 252, 253, 254, 0, 0, 0, 0,
+ 0, 255, 256, 257, 0, 0, 7, 8, 464, 10,
+ 437, 233, 234, 0, 235, 12, 0, 0, 0, 0,
+ 0, 0, 0, 0, 260, 0, 0, 0, 0, 0,
+ 15, 236, 237, 238, 16, 0, 239, 0, 17, 0,
+ 240, 241, 0, 242, 19, 243, 244, 0, 0, 245,
+ 246, 247, 248, 249, 21, 0, 22, 0, 0, 0,
+ 0, 0, 0, 0, 0, 250, 0, 0, 251, 0,
+ 0, 0, 0, 0, 0, 0, 252, 253, 254, 0,
0, 0, 0, 0, 255, 256, 257, 0, 0, 0,
- 0, 258, 0, 7, 8, 259, 10, 436, 233, 234,
+ 0, 258, 500, 7, 8, 0, 10, 437, 233, 234,
0, 235, 12, 0, 0, 0, 0, 260, 0, 0,
0, 0, 0, 0, 0, 0, 0, 15, 236, 237,
238, 16, 0, 239, 0, 17, 0, 240, 241, 0,
242, 19, 243, 244, 0, 0, 245, 246, 247, 248,
249, 21, 0, 22, 0, 0, 0, 0, 0, 0,
- 0, 0, 250, 0, 0, 1173, 0, 0, 0, 0,
- 0, 0, 0, 252, 253, 1174, 0, 0, 0, 0,
- 0, 255, 256, 257, 0, 0, 0, 0, 1175, 0,
- 1238, 8, 259, 10, 436, 233, 234, 0, 235, 12,
+ 0, 0, 250, 0, 0, 251, 0, 0, 0, 0,
+ 0, 0, 0, 252, 253, 254, 0, 0, 0, 0,
+ 0, 255, 256, 257, 0, 0, 0, 0, 258, 0,
+ 7, 697, 259, 10, 437, 233, 234, 0, 235, 12,
0, 0, 0, 0, 260, 0, 0, 0, 0, 0,
0, 0, 0, 0, 15, 236, 237, 238, 16, 0,
239, 0, 17, 0, 240, 241, 0, 242, 19, 243,
@@ -2095,907 +2050,898 @@ static const short yytable[] = { 66,
0, 0, 251, 0, 0, 0, 0, 0, 0, 0,
252, 253, 254, 0, 0, 0, 0, 0, 255, 256,
257, 0, 0, 0, 0, 258, 0, 7, 8, 259,
- 10, 436, 233, 234, 0, 235, 12, 0, 0, 0,
+ 10, 437, 233, 234, 0, 235, 12, 0, 0, 0,
0, 260, 0, 0, 0, 0, 0, 0, 0, 0,
0, 15, 236, 237, 238, 16, 0, 239, 0, 17,
0, 240, 241, 0, 242, 19, 243, 244, 0, 0,
245, 246, 247, 248, 249, 21, 0, 22, 0, 0,
+ 0, 0, 0, 0, 0, 0, 250, 0, 0, 890,
+ 0, 0, 0, 0, 0, 0, 0, 252, 253, 891,
+ 0, 0, 0, 0, 0, 255, 256, 257, 0, 0,
+ 0, 0, 258, 0, 7, 8, 259, 10, 437, 233,
+ 234, 0, 235, 12, 0, 0, 0, 0, 260, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 15, 236,
+ 237, 238, 16, 0, 239, 0, 17, 0, 240, 241,
+ 0, 242, 19, 243, 244, 0, 0, 245, 246, 247,
+ 248, 249, 21, 0, 22, 0, 0, 0, 0, 0,
+ 0, 0, 0, 250, 0, 0, 1177, 0, 0, 0,
+ 0, 0, 0, 0, 252, 253, 1178, 0, 0, 0,
+ 0, 0, 255, 256, 257, 0, 0, 0, 0, 1179,
+ 0, 1242, 8, 259, 10, 437, 233, 234, 0, 235,
+ 12, 0, 0, 0, 0, 260, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 15, 236, 237, 238, 16,
+ 0, 239, 0, 17, 0, 240, 241, 0, 242, 19,
+ 243, 244, 0, 0, 245, 246, 247, 248, 249, 21,
+ 0, 22, 0, 0, 0, 0, 0, 0, 0, 0,
+ 250, 0, 0, 251, 0, 0, 0, 0, 0, 0,
+ 0, 252, 253, 254, 0, 0, 0, 0, 0, 255,
+ 256, 257, 0, 0, 0, 0, 258, 0, 7, 8,
+ 259, 10, 437, 233, 234, 0, 235, 12, 0, 0,
+ 0, 0, 260, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 15, 236, 237, 238, 16, 0, 239, 0,
+ 17, 0, 240, 241, 0, 242, 19, 243, 244, 0,
+ 0, 245, 246, 247, 248, 249, 21, 0, 22, 0,
+ 0, 0, 0, 0, 0, 0, 0, 250, 0, 0,
+ 251, 0, 0, 0, 0, 0, 0, 0, 252, 253,
+ 254, 0, 0, 0, 0, 0, 255, 256, 257, 0,
+ 0, 7, 8, 258, 10, 437, 233, 234, 0, 235,
+ 12, 0, 0, 0, 0, 0, 0, 0, 0, 260,
+ 0, 0, 0, 0, 0, 15, 236, 237, 238, 16,
+ 0, 239, 0, 17, 0, 240, 241, 0, 242, 19,
+ 243, 244, 0, 0, 245, 246, 247, 248, 249, 21,
+ 0, 22, 0, 0, 0, 0, 0, 0, 0, 0,
+ 250, 0, 0, 890, 0, 0, 0, 0, 0, 0,
+ 0, 252, 253, 891, 0, 0, 0, 0, 0, 255,
+ 256, 257, 0, 0, 7, 8, 258, 10, 232, 233,
+ 234, 0, 235, 12, 0, 0, 0, 0, 0, 0,
+ 0, 0, 260, 0, 0, 0, 0, 0, 15, 236,
+ 237, 238, 16, 0, 239, 0, 17, 0, 240, 241,
+ 0, 242, 19, 243, 244, 0, 0, 245, 246, 247,
+ 248, 249, 21, 0, 22, 0, 0, 0, 0, 0,
+ 0, 0, 0, 250, 0, 0, 1177, 0, 0, 0,
+ 0, 0, 0, 0, 252, 253, 1178, 0, 0, 0,
+ 0, 0, 255, 256, 257, 0, 0, 7, 8, 1179,
+ 10, 437, 233, 234, 0, 235, 12, 0, 0, 0,
+ 0, 0, 0, 0, 0, 260, 0, 0, 0, 0,
+ 0, 15, 236, 0, 0, 16, 0, 239, 0, 17,
+ 0, 240, 241, 0, 242, 19, 243, 244, 0, 0,
+ 245, 246, 247, 248, 249, 21, 0, 22, 0, 0,
0, 0, 0, 0, 0, 0, 250, 0, 0, 251,
0, 0, 0, 0, 0, 0, 0, 252, 253, 254,
0, 0, 0, 0, 0, 255, 256, 257, 0, 0,
- 7, 8, 258, 10, 436, 233, 234, 0, 235, 12,
+ 7, 8, 441, 10, 437, 233, 234, 0, 235, 12,
0, 0, 0, 0, 0, 0, 0, 0, 260, 0,
0, 0, 0, 0, 15, 236, 237, 238, 16, 0,
239, 0, 17, 0, 240, 241, 0, 242, 19, 243,
244, 0, 0, 245, 246, 247, 248, 249, 21, 0,
- 22, 0, 0, 0, 0, 0, 0, 0, 0, 250,
- 0, 0, 887, 0, 0, 0, 0, 0, 0, 0,
- 252, 253, 888, 0, 0, 0, 0, 0, 255, 256,
- 257, 0, 0, 7, 8, 258, 10, 232, 233, 234,
- 0, 235, 12, 0, 0, 0, 0, 0, 0, 0,
- 0, 260, 0, 0, 0, 0, 0, 15, 236, 237,
- 238, 16, 0, 239, 0, 17, 0, 240, 241, 0,
- 242, 19, 243, 244, 0, 0, 245, 246, 247, 248,
- 249, 21, 0, 22, 0, 0, 0, 0, 0, 0,
- 0, 0, 250, 0, 0, 1173, 0, 0, 0, 0,
- 0, 0, 0, 252, 253, 1174, 0, 0, 0, 0,
- 0, 255, 256, 257, 0, 0, 7, 8, 1175, 10,
- 436, 233, 234, 0, 235, 12, 0, 0, 0, 0,
- 0, 0, 0, 0, 260, 0, 0, 0, 0, 0,
- 15, 236, 0, 0, 16, 0, 239, 0, 17, 0,
- 240, 241, 0, 242, 19, 243, 244, 0, 0, 245,
- 246, 247, 248, 249, 21, 0, 22, 0, 0, 0,
- 0, 0, 0, 0, 0, 250, 0, 0, 251, 0,
- 0, 0, 0, 0, 0, 0, 252, 253, 254, 0,
- 0, 0, 0, 0, 255, 256, 257, 0, 0, 0,
- 0, 440, 7, 8, 92, 10, 11, 0, 0, 615,
- 0, 12, 0, 0, 0, 0, 0, 260, 0, 652,
- 8, 151, 10, 152, 0, 0, 15, 0, 12, 0,
- 16, 0, 0, 0, 17, 0, 0, 0, 0, 0,
- 19, 0, 0, 15, 0, 0, 0, 16, 0, 0,
- 21, 17, 22, 0, 0, 0, 0, 19, 0, 0,
- 0, 0, 0, 0, 24, 0, 0, 21, 0, 22,
- 0, 0, 0, 0, 25, 0, 655, 0, 0, 0,
- 0, 24, 26, 0, 0, 0, 0, 27, 0, 0,
- 0, 25, 7, 8, 151, 10, 152, 0, 0, 26,
- 0, 12, 0, 0, 27, 0, 0, 0, 0, 7,
- 8, 151, 10, 152, 0, 0, 15, 0, 12, 0,
- 16, 0, 0, 0, 17, 0, 0, 0, 0, 0,
- 19, 0, 0, 15, 0, 0, 0, 16, 0, 0,
- 21, 17, 22, 0, 0, 1095, 0, 19, 0, 0,
- 0, 0, 0, 0, 24, 0, 0, 21, 0, 22,
- 0, 0, 0, 0, 25, 0, 0, 0, 0, 0,
- 0, 24, 26, 0, 0, 0, 0, 27, 0, 0,
- 0, 25, 0, 0, 0, 0, 0, 0, 0, 26,
- 679, 465, 466, 467, 27, 468, 469, 470, 471, 472,
- 473, 474, 475, 476, 477, 478, 479, 480, 481, 482,
- 483, 484, 485, 486, 0, 465, 466, 467, 0, 468,
- 469, 470, 471, 472, 473, 474, 475, 476, 477, 478,
- 479, 480, 481, 482, 483, 484, 485, 486, 542, 1036,
- 465, 466, 467, 0, 468, 469, 470, 471, 472, 473,
- 474, 475, 476, 477, 478, 479, 480, 481, 482, 483,
- 484, 485, 486, 465, 466, 467, 1200, 468, 469, 470,
- 471, 472, 473, 474, 475, 476, 477, 478, 479, 480,
- 481, 482, 483, 484, 485, 486, 465, 466, 467, 1249,
- 468, 469, 470, 471, 472, 473, 474, 475, 476, 477,
- 478, 479, 480, 481, 482, 483, 484, 485, 486, 465,
- 466, 467, 0, 468, 469, 470, 471, 472, 473, 474,
+ 22, 0, 7, 8, 158, 159, 160, 0, 0, 0,
+ 0, 12, 0, 0, 0, 0, 0, 7, 8, 151,
+ 10, 152, 0, 0, 0, 0, 12, 0, 255, 256,
+ 257, 0, 0, 0, 17, 258, 0, 0, 0, 259,
+ 19, 15, 0, 510, 0, 16, 0, 0, 0, 17,
+ 21, 260, 22, 0, 0, 19, 0, 0, 0, 0,
+ 0, 0, 0, 0, 603, 21, 0, 22, 0, 0,
+ 153, 0, 0, 0, 604, 0, 0, 0, 0, 24,
+ 0, 0, 26, 0, 513, 0, 0, 605, 515, 25,
+ 0, 7, 8, 92, 10, 11, 0, 26, 618, 0,
+ 12, 0, 27, 0, 0, 0, 0, 0, 655, 8,
+ 151, 10, 152, 0, 0, 15, 0, 12, 0, 16,
+ 0, 0, 0, 17, 0, 0, 0, 0, 0, 19,
+ 0, 0, 15, 0, 0, 0, 16, 0, 0, 21,
+ 17, 22, 0, 0, 0, 0, 19, 0, 0, 0,
+ 0, 0, 0, 24, 0, 0, 21, 0, 22, 0,
+ 0, 0, 0, 25, 0, 658, 0, 0, 0, 0,
+ 24, 26, 0, 0, 0, 0, 27, 0, 0, 0,
+ 25, 7, 8, 151, 10, 152, 0, 0, 26, 0,
+ 12, 0, 0, 27, 0, 0, 0, 0, 7, 8,
+ 151, 10, 152, 0, 0, 15, 0, 12, 0, 16,
+ 0, 0, 0, 17, 0, 0, 0, 0, 0, 19,
+ 0, 0, 15, 0, 0, 0, 16, 0, 0, 21,
+ 17, 22, 0, 0, 1099, 0, 19, 0, 0, 0,
+ 0, 0, 8, 24, 10, 184, 21, 0, 22, 0,
+ 12, 0, 0, 25, 0, 0, 0, 0, 0, 0,
+ 24, 26, 0, 0, 0, 15, 27, 0, 0, 16,
+ 25, 0, 0, 17, 0, 0, 0, 0, 26, 0,
+ 0, 0, 510, 27, 0, 0, 0, 0, 0, 21,
+ 0, 93, 0, 0, 0, 0, 0, 0, 0, 0,
+ 466, 467, 468, 511, 469, 470, 471, 472, 473, 474,
+ 475, 476, 477, 512, 479, 480, 481, 482, 483, 484,
+ 485, 486, 487, 513, 0, 0, 514, 515, 466, 467,
+ 468, 0, 469, 470, 471, 472, 473, 474, 475, 476,
+ 477, 478, 479, 480, 481, 482, 483, 484, 485, 486,
+ 487, 543, 682, 466, 467, 468, 0, 469, 470, 471,
+ 472, 473, 474, 475, 476, 477, 478, 479, 480, 481,
+ 482, 483, 484, 485, 486, 487, 1040, 466, 467, 468,
+ 0, 469, 470, 471, 472, 473, 474, 475, 476, 477,
+ 478, 479, 480, 481, 482, 483, 484, 485, 486, 487,
+ 466, 467, 468, 1204, 469, 470, 471, 472, 473, 474,
475, 476, 477, 478, 479, 480, 481, 482, 483, 484,
- 485, 486, 465, 466, 467, 0, 468, 469, 470, 471,
- 472, 473, 474, 475, 476, 0, 478, 479, 480, 481,
- 482, 483, 484, 485, 486, 469, 470, 471, 472, 473,
+ 485, 486, 487, 466, 467, 468, 1253, 469, 470, 471,
+ 472, 473, 474, 475, 476, 477, 478, 479, 480, 481,
+ 482, 483, 484, 485, 486, 487, 466, 467, 468, 0,
+ 469, 470, 471, 472, 473, 474, 475, 476, 477, 478,
+ 479, 480, 481, 482, 483, 484, 485, 486, 487, 468,
+ 0, 469, 470, 471, 472, 473, 474, 475, 476, 477,
+ 478, 479, 480, 481, 482, 483, 484, 485, 486, 487,
+ 470, 471, 472, 473, 474, 475, 476, 477, 478, 479,
+ 480, 481, 482, 483, 484, 485, 486, 487, 472, 473,
474, 475, 476, 477, 478, 479, 480, 481, 482, 483,
- 484, 485, 486, 470, 471, 472, 473, 474, 475, 476,
- 477, 478, 479, 480, 481, 482, 483, 484, 485, 486,
- 471, 472, 473, 474, 475, 476, 477, 478, 479, 480,
- 481, 482, 483, 484, 485, 486
+ 484, 485, 486, 487, 473, 474, 475, 476, 477, 478,
+ 479, 480, 481, 482, 483, 484, 485, 486, 487
};
static const short yycheck[] = { 4,
- 4, 130, 131, 136, 278, 415, 70, 12, 117, 299,
- 346, 12, 299, 265, 136, 20, 20, 108, 109, 24,
- 25, 4, 27, 87, 4, 52, 338, 188, 33, 33,
- 388, 12, 647, 154, 98, 284, 284, 299, 131, 44,
- 20, 46, 746, 387, 1043, 129, 71, 52, 1151, 134,
- 9, 52, 983, 33, 59, 812, 20, 1179, 983, 990,
- 44, 9, 161, 162, 181, 70, 71, 60, 9, 34,
- 0, 52, 77, 77, 7, 1212, 48, 367, 55, 10,
- 367, 34, 87, 10, 1159, 1222, 56, 0, 362, 56,
- 95, 96, 54, 98, 406, 55, 101, 77, 60, 104,
- 105, 62, 4, 108, 109, 7, 107, 36, 45, 102,
- 70, 95, 60, 77, 119, 119, 121, 122, 36, 1,
- 1242, 54, 92, 44, 55, 92, 103, 60, 55, 60,
- 1205, 58, 136, 60, 139, 140, 141, 121, 103, 119,
- 1243, 1140, 44, 102, 3, 4, 5, 6, 7, 51,
- 103, 53, 10, 1275, 102, 1292, 514, 76, 4, 92,
- 165, 102, 93, 65, 125, 439, 93, 88, 89, 88,
- 89, 102, 54, 75, 103, 336, 35, 299, 183, 183,
- 99, 142, 154, 85, 301, 103, 88, 89, 193, 161,
- 162, 51, 51, 950, 53, 54, 157, 55, 4, 154,
- 44, 286, 60, 183, 56, 188, 910, 53, 60, 69,
- 37, 3, 4, 185, 343, 344, 345, 136, 4, 66,
- 284, 1324, 1325, 23, 51, 230, 231, 88, 4, 75,
- 185, 1162, 4, 88, 44, 93, 397, 3, 85, 98,
- 99, 100, 102, 56, 88, 367, 271, 53, 4, 250,
- 343, 344, 44, 136, 387, 4, 103, 229, 342, 51,
- 60, 53, 6, 7, 55, 387, 271, 53, 12, 75,
- 275, 392, 277, 278, 279, 51, 4, 53, 88, 7,
- 285, 53, 531, 88, 89, 44, 377, 378, 1219, 65,
- 103, 35, 391, 392, 299, 299, 88, 53, 60, 75,
- 44, 285, 149, 75, 53, 69, 278, 312, 44, 88,
- 315, 102, 656, 89, 319, 1246, 51, 56, 323, 323,
- 419, 1246, 1253, 51, 56, 53, 75, 456, 1253, 88,
- 89, 3, 4, 948, 69, 647, 55, 65, 54, 258,
- 102, 56, 1046, 323, 88, 4, 1277, 75, 195, 3,
- 4, 70, 88, 336, 359, 360, 361, 362, 363, 323,
- 44, 89, 367, 367, 103, 51, 102, 328, 373, 54,
- 375, 103, 377, 378, 55, 359, 1307, 361, 362, 384,
- 299, 53, 1307, 387, 55, 390, 103, 41, 393, 70,
- 362, 513, 51, 54, 53, 3, 4, 102, 520, 53,
- 383, 406, 563, 75, 88, 89, 65, 412, 413, 56,
- 415, 415, 3, 4, 397, 420, 75, 56, 102, 391,
- 392, 75, 3, 4, 782, 44, 102, 4, 412, 83,
- 7, 102, 102, 41, 55, 415, 283, 781, 4, 58,
- 401, 446, 447, 448, 449, 53, 102, 419, 367, 102,
- 41, 27, 9, 258, 56, 44, 103, 418, 341, 306,
- 589, 462, 53, 103, 103, 31, 92, 27, 387, 88,
- 4, 496, 53, 7, 51, 83, 53, 3, 56, 640,
- 602, 102, 55, 97, 75, 51, 608, 53, 65, 56,
- 55, 496, 83, 498, 105, 97, 589, 70, 75, 88,
- 89, 420, 60, 815, 387, 510, 511, 89, 513, 513,
- 44, 801, 673, 102, 801, 520, 520, 51, 437, 53,
- 44, 440, 60, 656, 551, 103, 445, 446, 447, 448,
- 449, 65, 108, 109, 656, 787, 103, 102, 637, 801,
- 459, 75, 791, 791, 463, 550, 551, 859, 108, 109,
- 551, 85, 435, 56, 88, 89, 88, 3, 4, 25,
- 26, 980, 920, 982, 88, 141, 550, 372, 60, 678,
- 551, 3, 4, 5, 6, 7, 495, 69, 550, 44,
- 563, 141, 44, 60, 585, 432, 44, 89, 54, 105,
- 384, 88, 69, 58, 60, 600, 601, 602, 602, 393,
- 103, 44, 44, 608, 608, 51, 44, 53, 54, 492,
- 44, 494, 495, 25, 26, 58, 1026, 78, 79, 624,
- 625, 53, 627, 88, 89, 44, 88, 89, 44, 88,
- 88, 967, 437, 3, 4, 440, 948, 442, 443, 574,
- 445, 915, 647, 526, 27, 88, 88, 54, 781, 54,
- 88, 656, 656, 60, 88, 60, 69, 640, 463, 781,
- 88, 508, 467, 785, 88, 637, 685, 686, 687, 88,
- 675, 41, 88, 55, 56, 1, 523, 55, 56, 801,
- 685, 686, 687, 53, 69, 92, 9, 92, 493, 51,
- 673, 55, 56, 628, 499, 578, 657, 23, 60, 25,
- 26, 662, 663, 675, 639, 666, 32, 69, 982, 870,
- 871, 69, 873, 83, 69, 3, 4, 54, 6, 56,
- 55, 843, 4, 60, 103, 7, 109, 791, 54, 55,
- 56, 102, 58, 340, 60, 6, 7, 656, 1074, 1075,
- 745, 12, 55, 56, 835, 836, 916, 917, 102, 919,
- 841, 842, 1088, 41, 23, 25, 26, 102, 141, 55,
- 56, 766, 44, 768, 35, 53, 92, 4, 5, 51,
- 775, 53, 1108, 1109, 779, 102, 781, 781, 783, 784,
- 785, 785, 3, 65, 54, 54, 791, 56, 103, 58,
- 60, 60, 4, 75, 31, 83, 801, 801, 54, 36,
- 12, 377, 378, 85, 55, 56, 88, 89, 20, 7,
- 3, 4, 24, 25, 51, 27, 53, 377, 378, 1155,
- 58, 33, 102, 3, 4, 826, 745, 102, 833, 834,
- 835, 836, 44, 58, 46, 840, 841, 842, 843, 843,
- 52, 55, 56, 102, 37, 38, 88, 59, 41, 102,
- 5, 6, 7, 105, 859, 105, 775, 12, 51, 71,
- 53, 41, 781, 32, 869, 77, 749, 872, 102, 874,
- 874, 876, 807, 53, 75, 76, 77, 78, 79, 762,
- 35, 764, 801, 95, 96, 25, 26, 870, 871, 101,
- 873, 102, 32, 105, 874, 75, 108, 109, 105, 51,
- 54, 902, 56, 83, 865, 105, 60, 119, 60, 121,
- 122, 916, 917, 102, 919, 55, 56, 69, 58, 4,
- 5, 105, 857, 51, 54, 6, 56, 139, 140, 141,
- 60, 866, 937, 938, 817, 88, 819, 44, 821, 858,
- 875, 44, 1216, 948, 949, 949, 31, 1076, 753, 51,
- 58, 36, 56, 165, 55, 56, 957, 876, 60, 55,
- 1121, 1122, 56, 5, 6, 7, 51, 69, 53, 949,
- 12, 183, 973, 1324, 1325, 980, 981, 982, 81, 82,
- 785, 193, 56, 86, 87, 88, 89, 235, 236, 994,
- 995, 838, 997, 35, 56, 378, 980, 56, 982, 55,
- 4, 58, 6, 7, 1286, 1287, 58, 102, 12, 102,
- 982, 1172, 619, 102, 102, 105, 55, 88, 230, 231,
- 60, 1026, 1026, 27, 55, 55, 602, 31, 60, 1030,
- 88, 35, 608, 58, 102, 102, 102, 1327, 843, 102,
- 1327, 102, 602, 70, 70, 55, 1026, 51, 608, 53,
- 1179, 102, 102, 858, 70, 70, 102, 60, 1167, 271,
- 1021, 1022, 60, 60, 136, 277, 278, 279, 1069, 102,
- 105, 89, 284, 285, 102, 1010, 1011, 83, 44, 103,
- 656, 102, 1173, 1174, 88, 102, 105, 299, 1023, 1024,
- 102, 102, 105, 1098, 941, 102, 656, 105, 103, 60,
- 312, 102, 102, 315, 34, 58, 102, 319, 102, 58,
- 102, 323, 88, 1242, 88, 1276, 71, 72, 73, 74,
- 75, 76, 77, 78, 79, 88, 338, 73, 74, 75,
- 76, 77, 78, 79, 88, 103, 1097, 520, 1121, 1122,
- 88, 748, 102, 102, 6, 102, 1275, 359, 360, 361,
- 362, 363, 102, 105, 105, 367, 1117, 102, 60, 103,
- 102, 373, 102, 375, 102, 377, 378, 972, 1173, 1174,
- 1175, 88, 384, 60, 56, 56, 251, 4, 390, 254,
- 54, 393, 257, 7, 56, 1120, 1169, 58, 263, 1172,
- 102, 14, 1193, 102, 406, 60, 60, 272, 105, 1328,
- 412, 413, 44, 415, 88, 1327, 56, 56, 420, 88,
- 58, 58, 1217, 88, 102, 105, 102, 44, 15, 602,
- 56, 56, 102, 56, 51, 608, 53, 1032, 1033, 1034,
- 1035, 56, 102, 1217, 446, 447, 448, 449, 65, 1044,
- 103, 848, 849, 102, 1216, 102, 56, 58, 75, 58,
- 102, 1186, 1187, 9, 1189, 1190, 1175, 102, 85, 835,
- 836, 88, 89, 56, 56, 841, 842, 843, 56, 341,
- 88, 55, 1077, 656, 102, 835, 836, 91, 56, 58,
- 1085, 841, 842, 843, 496, 102, 498, 1248, 88, 102,
- 102, 9, 56, 1276, 901, 902, 102, 102, 510, 511,
- 102, 513, 9, 56, 2, 0, 0, 690, 520, 129,
- 118, 7, 1195, 801, 10, 387, 325, 815, 119, 531,
- 119, 551, 1327, 1327, 99, 459, 1140, 1, 1150, 508,
- 1181, 1077, 981, 681, 33, 805, 1193, 859, 550, 551,
- 585, 796, 33, 949, 874, 872, 794, 539, 44, 23,
- 957, 25, 26, 413, 1159, 496, 12, 1266, 32, 55,
- 829, 1296, 58, 435, 60, 876, 1300, -1, -1, 444,
- 1175, 3, 4, -1, 70, 1180, 1181, 1302, 1261, -1,
- 54, 55, 56, -1, 58, -1, 60, -1, 600, 601,
- 602, -1, 88, 89, -1, -1, 608, 93, -1, -1,
- 1205, 784, -1, -1, -1, -1, 102, -1, 1327, 41,
- -1, -1, 624, 625, -1, 627, 4, -1, 92, 51,
- 492, 53, 494, 495, 1031, -1, -1, -1, 60, 1036,
- -1, -1, 20, 65, -1, 647, -1, -1, -1, -1,
- -1, -1, -1, 75, 656, 33, -1, -1, 520, -1,
- -1, 83, -1, 836, 526, -1, 88, -1, 46, 842,
- 843, -1, 1, 675, -1, 1270, -1, -1, -1, -1,
- -1, 59, -1, 685, 686, 687, -1, -1, -1, -1,
- -1, 1286, 1287, 71, 23, -1, 25, 26, 76, 77,
- -1, -1, -1, 32, 1299, -1, -1, -1, -1, -1,
- 88, 89, -1, 1110, 1111, 888, 578, -1, 96, -1,
- -1, 99, -1, -1, -1, 54, 55, 56, -1, 58,
- -1, 60, 1098, -1, -1, -1, -1, -1, -1, -1,
- -1, 119, 1139, 745, 122, -1, 608, -1, 1098, -1,
- -1, -1, -1, 4, 5, 6, 7, -1, 136, 10,
- -1, 12, -1, 92, 766, -1, 768, -1, -1, -1,
- -1, -1, -1, 775, -1, -1, 27, 779, -1, 781,
- 31, 783, 784, 785, 35, -1, -1, 1184, 4, 791,
- 6, 7, -1, -1, 1191, 1192, 12, -1, -1, 801,
- 51, -1, 53, 1200, -1, 183, -1, 1173, 1174, 1175,
- -1, 27, -1, 815, -1, 31, -1, 69, -1, 35,
- -1, -1, -1, 1173, 1174, 1175, -1, -1, 690, -1,
- -1, 833, 834, 835, 836, 51, -1, 53, 840, 841,
- 842, 843, 93, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, 230, -1, -1, -1, -1, 859, 24, 25,
- -1, -1, 1259, 1260, 116, -1, -1, 869, -1, -1,
- 872, -1, 874, -1, 876, -1, -1, -1, 3, 4,
- 258, -1, 7, 135, -1, -1, -1, 749, -1, -1,
- -1, -1, 757, 271, -1, -1, -1, -1, 150, -1,
- 762, 279, 764, -1, -1, 71, -1, -1, -1, -1,
- 76, -1, -1, -1, 916, 917, 41, 919, 783, 784,
- -1, 299, 88, 89, -1, 1098, 51, -1, 53, 1326,
- -1, -1, -1, 99, -1, 937, 938, -1, 10, -1,
- 65, -1, 108, 109, -1, 323, 948, 949, -1, -1,
- 75, -1, -1, 25, 26, 817, -1, 819, 83, 821,
- 32, -1, -1, 88, -1, -1, -1, -1, -1, -1,
- 136, -1, 44, 139, 140, -1, 841, 842, 980, 981,
- 982, -1, 360, 55, 56, 363, 58, -1, 60, 367,
- -1, -1, 994, 995, -1, 997, -1, -1, -1, -1,
- -1, 1174, 1175, -1, -1, -1, -1, -1, -1, 387,
- -1, -1, -1, -1, -1, -1, 88, 89, -1, -1,
- 92, 93, 887, 888, 1026, -1, 3, 4, -1, -1,
- 102, -1, -1, -1, -1, 413, -1, 415, -1, -1,
- -1, -1, 420, -1, -1, -1, -1, -1, -1, 1,
- -1, 3, 4, 5, 6, 7, -1, 922, -1, 437,
- 12, -1, 440, -1, 41, -1, -1, 445, 446, 447,
- 448, 449, 937, 938, 51, 27, 53, 3, 4, 31,
- -1, 459, -1, 35, 36, 463, -1, -1, 65, 41,
- -1, -1, 258, -1, -1, -1, 1098, -1, 75, 51,
- -1, 53, 3, 4, 56, 271, 83, -1, 60, -1,
- -1, 88, -1, 65, -1, 41, -1, 495, 496, -1,
- -1, -1, -1, 75, -1, 51, -1, 53, 380, -1,
- 56, 83, -1, 299, 386, 513, 88, -1, -1, 65,
- 41, -1, 520, 44, -1, -1, -1, -1, 71, 75,
- 51, 103, 53, 76, -1, -1, -1, 83, -1, 60,
- -1, -1, 88, -1, 65, 88, 89, -1, -1, -1,
- -1, 1173, 1174, 1175, 75, -1, 99, -1, 430, 431,
- -1, 433, 83, -1, -1, -1, -1, 88, 1, -1,
- 3, 4, 5, 6, 7, -1, -1, -1, -1, 12,
- -1, 367, 4, 5, 6, 7, -1, -1, -1, -1,
- 12, 377, 378, 136, 27, 1217, -1, -1, 31, -1,
- -1, 387, 35, 36, 602, 27, -1, -1, 41, 31,
- 608, -1, -1, 35, -1, -1, 1098, -1, 51, -1,
- 53, -1, -1, 56, -1, -1, -1, 60, -1, 51,
- -1, 53, 65, -1, 420, 4, -1, 6, 7, -1,
- -1, -1, 75, 12, 516, 517, -1, 69, -1, 521,
- 83, 437, -1, -1, 440, 88, -1, -1, 656, 445,
- 446, 447, 448, 449, -1, -1, 35, -1, -1, -1,
- 103, -1, -1, 459, -1, 44, -1, 463, -1, -1,
- -1, -1, 51, -1, 53, -1, -1, -1, 1173, 1174,
- -1, -1, -1, -1, -1, -1, 65, -1, -1, -1,
- -1, -1, -1, -1, -1, 1327, 75, -1, -1, 495,
- 496, -1, -1, 1195, -1, 258, 85, -1, -1, 88,
- 89, -1, 594, 595, 510, 511, -1, 513, 271, -1,
- -1, -1, 604, -1, 520, -1, -1, -1, 610, -1,
- 3, 4, 5, 6, 7, -1, -1, 745, -1, 12,
- -1, 749, -1, -1, -1, -1, 299, 3, 4, 1,
- -1, 3, 4, 5, 6, 7, -1, -1, -1, -1,
- 12, -1, 35, -1, -1, -1, -1, 775, 41, 1261,
- -1, 44, 654, 781, -1, 27, -1, 785, 51, 31,
- 53, -1, -1, 35, 36, 41, -1, -1, 44, 41,
- -1, -1, 65, 801, -1, 51, -1, 53, -1, 51,
- -1, 53, 75, -1, 600, 601, 602, -1, 60, 65,
- 83, -1, 608, 65, 367, 88, -1, -1, -1, 75,
- 828, -1, -1, 75, -1, -1, -1, 83, -1, 85,
- -1, 83, 88, 89, 387, 843, 88, -1, -1, -1,
- 3, 4, -1, -1, 7, -1, -1, -1, -1, -1,
- 858, 103, -1, -1, -1, -1, -1, -1, -1, -1,
- 656, -1, -1, -1, -1, -1, 874, 420, 876, 751,
- 752, 1, 754, 3, 4, 5, 6, 7, 41, -1,
- -1, -1, 12, -1, 437, -1, -1, 440, 51, -1,
- 53, -1, 445, 446, 447, 448, 449, 27, 780, -1,
- -1, 31, 65, -1, -1, 35, 459, -1, -1, -1,
- 463, 41, 75, -1, -1, 45, -1, -1, -1, -1,
- 83, 51, -1, 53, -1, 88, 56, -1, 3, 4,
- -1, -1, 7, -1, -1, 65, -1, -1, 76, -1,
- -1, 949, 495, 496, -1, 75, -1, -1, -1, 745,
- -1, -1, -1, 83, -1, -1, -1, 839, 88, -1,
- 513, 99, -1, -1, 94, -1, 41, 520, -1, 44,
- 852, 853, 854, 981, -1, 983, 51, -1, 53, 775,
- -1, -1, 990, -1, -1, 781, -1, 783, 784, 785,
- 65, -1, -1, -1, 3, 4, -1, -1, 136, -1,
- 75, -1, -1, -1, -1, 801, -1, -1, 83, -1,
- 85, -1, -1, 88, 89, -1, -1, -1, 1026, 67,
+ 4, 188, 265, 136, 416, 284, 117, 12, 108, 109,
+ 4, 339, 12, 299, 4, 20, 20, 389, 388, 24,
+ 25, 52, 27, 284, 131, 347, 749, 71, 33, 33,
+ 20, 20, 154, 161, 162, 130, 131, 134, 129, 44,
+ 299, 46, 816, 33, 136, 988, 1155, 52, 1047, 181,
+ 1183, 299, 52, 34, 59, 988, 9, 1, 9, 4,
+ 9, 48, 995, 55, 88, 70, 71, 278, 1216, 70,
+ 34, 154, 77, 77, 10, 3, 4, 44, 1226, 407,
+ 7, 10, 87, 55, 55, 56, 87, 77, 77, 36,
+ 95, 96, 4, 98, 3, 4, 101, 98, 70, 104,
+ 105, 36, 185, 108, 109, 51, 4, 60, 53, 368,
+ 54, 103, 4, 1246, 119, 119, 121, 122, 44, 55,
+ 368, 62, 103, 69, 60, 53, 55, 54, 95, 119,
+ 75, 60, 136, 60, 139, 140, 141, 12, 1247, 103,
+ 56, 53, 4, 515, 53, 1144, 1279, 75, 1296, 102,
+ 337, 102, 363, 102, 121, 53, 103, 93, 76, 51,
+ 165, 53, 88, 4, 93, 92, 102, 154, 103, 301,
+ 88, 89, 4, 65, 161, 162, 102, 52, 183, 183,
+ 954, 99, 1163, 75, 125, 27, 44, 103, 193, 286,
+ 913, 53, 44, 183, 188, 60, 51, 89, 185, 56,
+ 58, 142, 0, 44, 69, 60, 58, 299, 55, 54,
+ 51, 398, 53, 75, 69, 60, 157, 44, 136, 1328,
+ 1329, 53, 56, 70, 65, 230, 231, 271, 1209, 440,
+ 88, 89, 107, 1166, 75, 0, 88, 344, 345, 6,
+ 7, 55, 229, 75, 85, 12, 103, 88, 89, 344,
+ 345, 346, 343, 532, 4, 388, 3, 4, 88, 89,
+ 60, 88, 89, 66, 392, 393, 271, 109, 35, 103,
+ 275, 393, 277, 278, 279, 102, 368, 44, 378, 379,
+ 285, 4, 85, 284, 7, 56, 56, 44, 102, 659,
+ 1223, 278, 420, 56, 299, 299, 388, 44, 51, 141,
+ 103, 23, 102, 53, 51, 60, 53, 1250, 313, 44,
+ 985, 316, 987, 56, 1257, 320, 69, 1250, 285, 324,
+ 324, 88, 650, 55, 1257, 75, 97, 1050, 51, 92,
+ 53, 88, 89, 103, 324, 324, 55, 10, 60, 88,
+ 258, 88, 65, 337, 45, 102, 149, 102, 1281, 102,
+ 56, 56, 75, 88, 4, 360, 361, 362, 363, 364,
+ 103, 56, 457, 368, 368, 60, 89, 3, 1311, 374,
+ 102, 376, 56, 378, 379, 250, 363, 136, 1311, 566,
+ 385, 299, 55, 102, 388, 58, 391, 60, 329, 394,
+ 384, 4, 195, 360, 7, 362, 363, 103, 103, 3,
+ 4, 51, 407, 53, 398, 392, 393, 55, 413, 414,
+ 1, 416, 416, 785, 784, 65, 421, 55, 56, 103,
+ 93, 54, 514, 69, 44, 75, 416, 60, 258, 521,
+ 44, 44, 23, 420, 25, 26, 88, 41, 51, 44,
+ 53, 32, 447, 448, 449, 450, 413, 55, 56, 53,
+ 368, 44, 65, 497, 102, 44, 643, 27, 44, 92,
+ 54, 402, 75, 54, 55, 56, 60, 58, 88, 60,
+ 388, 75, 85, 55, 88, 88, 89, 44, 419, 83,
+ 283, 44, 54, 88, 89, 592, 3, 4, 70, 676,
+ 56, 819, 497, 51, 499, 88, 89, 592, 92, 88,
+ 89, 92, 88, 421, 307, 44, 511, 512, 4, 514,
+ 514, 7, 640, 605, 56, 794, 521, 521, 804, 611,
+ 438, 88, 553, 441, 41, 88, 659, 790, 446, 447,
+ 448, 449, 450, 794, 862, 60, 53, 379, 108, 109,
+ 44, 54, 460, 373, 69, 804, 464, 552, 553, 88,
+ 92, 923, 44, 553, 58, 51, 804, 53, 75, 3,
+ 4, 44, 6, 103, 385, 552, 83, 659, 54, 65,
+ 681, 141, 566, 394, 55, 25, 26, 58, 496, 75,
+ 102, 3, 4, 342, 88, 552, 3, 4, 463, 70,
+ 55, 56, 3, 4, 3, 4, 88, 41, 603, 604,
+ 605, 605, 102, 51, 54, 88, 611, 611, 438, 53,
+ 60, 441, 60, 443, 444, 102, 446, 51, 1030, 41,
+ 102, 69, 627, 628, 41, 630, 60, 25, 26, 388,
+ 433, 53, 41, 37, 464, 69, 53, 9, 468, 83,
+ 51, 102, 53, 54, 53, 650, 54, 51, 56, 643,
+ 972, 784, 60, 640, 659, 659, 54, 103, 75, 6,
+ 7, 83, 60, 92, 494, 12, 83, 4, 3, 6,
+ 500, 97, 27, 678, 83, 12, 60, 436, 553, 521,
+ 25, 26, 676, 688, 689, 690, 873, 874, 35, 876,
+ 27, 678, 784, 105, 31, 88, 788, 89, 35, 136,
+ 3, 4, 5, 6, 7, 105, 509, 918, 5, 6,
+ 7, 51, 804, 588, 51, 12, 53, 78, 79, 660,
+ 60, 524, 55, 56, 665, 666, 55, 56, 669, 69,
+ 919, 920, 35, 922, 493, 89, 495, 496, 35, 839,
+ 840, 659, 60, 748, 88, 845, 846, 88, 51, 88,
+ 53, 54, 88, 108, 109, 847, 1078, 1079, 69, 54,
+ 69, 56, 521, 605, 769, 60, 771, 69, 527, 611,
+ 1092, 69, 54, 778, 56, 9, 987, 782, 60, 784,
+ 784, 786, 787, 788, 788, 102, 141, 103, 23, 794,
+ 1112, 1113, 55, 794, 102, 98, 99, 100, 102, 804,
+ 804, 806, 102, 3, 4, 5, 6, 7, 378, 379,
+ 3, 3, 4, 103, 688, 689, 690, 659, 54, 54,
+ 58, 56, 581, 58, 7, 60, 55, 56, 55, 56,
+ 748, 102, 837, 838, 839, 840, 102, 1159, 102, 844,
+ 845, 846, 847, 847, 58, 37, 38, 1328, 1329, 41,
+ 105, 693, 611, 53, 102, 4, 105, 862, 88, 51,
+ 778, 53, 32, 12, 235, 236, 784, 872, 1290, 1291,
+ 875, 20, 877, 877, 879, 24, 25, 105, 27, 873,
+ 874, 105, 876, 102, 33, 102, 804, 877, 75, 76,
+ 77, 78, 79, 4, 102, 44, 7, 46, 51, 25,
+ 26, 6, 105, 52, 88, 342, 32, 44, 58, 55,
+ 59, 5, 6, 7, 919, 920, 58, 922, 12, 58,
+ 56, 56, 71, 56, 56, 56, 756, 868, 77, 55,
+ 56, 55, 58, 44, 693, 940, 941, 102, 1125, 1126,
+ 51, 35, 53, 861, 58, 787, 95, 96, 953, 953,
+ 102, 388, 101, 55, 65, 830, 105, 102, 788, 108,
+ 109, 879, 102, 953, 75, 3, 4, 105, 88, 7,
+ 119, 60, 121, 122, 85, 55, 55, 88, 89, 60,
+ 985, 986, 987, 58, 88, 1080, 102, 102, 70, 1176,
+ 139, 140, 141, 752, 999, 1000, 102, 1002, 840, 436,
+ 987, 102, 102, 41, 846, 847, 765, 102, 767, 1220,
+ 102, 70, 70, 51, 70, 53, 165, 847, 985, 102,
+ 987, 60, 55, 378, 379, 1030, 1030, 65, 60, 102,
+ 905, 861, 60, 102, 183, 605, 102, 75, 105, 842,
+ 1030, 611, 103, 89, 193, 83, 83, 102, 105, 891,
+ 88, 44, 102, 102, 3, 4, 493, 105, 495, 496,
+ 1171, 105, 821, 103, 823, 34, 825, 102, 4, 5,
+ 6, 7, 1331, 102, 10, 102, 12, 1177, 1178, 102,
+ 102, 230, 231, 1331, 1025, 1026, 961, 58, 1183, 659,
+ 527, 27, 41, 1280, 58, 31, 102, 1102, 88, 35,
+ 88, 88, 51, 978, 53, 7, 88, 56, 10, 88,
+ 105, 103, 6, 102, 105, 51, 65, 53, 102, 102,
+ 60, 102, 271, 103, 102, 102, 75, 102, 277, 278,
+ 279, 1125, 1126, 88, 83, 284, 285, 102, 60, 88,
+ 56, 944, 44, 56, 581, 7, 54, 977, 14, 56,
+ 299, 1246, 58, 55, 102, 102, 58, 93, 60, 1034,
+ 1101, 341, 60, 60, 313, 44, 105, 316, 70, 88,
+ 56, 320, 1177, 1178, 1179, 324, 56, 88, 88, 1173,
+ 1121, 58, 1176, 58, 1279, 102, 88, 89, 102, 15,
+ 339, 93, 56, 105, 4, 5, 56, 1072, 102, 102,
+ 102, 56, 103, 102, 56, 56, 1036, 1037, 1038, 1039,
+ 102, 360, 361, 362, 363, 364, 1221, 58, 1048, 368,
+ 58, 31, 9, 56, 102, 374, 36, 376, 102, 378,
+ 379, 56, 56, 1220, 88, 55, 385, 1332, 56, 1331,
+ 88, 51, 391, 53, 102, 394, 4, 5, 91, 102,
+ 605, 1081, 102, 102, 1221, 58, 611, 102, 407, 1089,
+ 1102, 1179, 9, 56, 413, 414, 1, 416, 102, 839,
+ 840, 102, 421, 31, 56, 845, 846, 847, 36, 9,
+ 0, 0, 118, 326, 2, 1, 1280, 119, 23, 804,
+ 25, 26, 119, 51, 129, 53, 819, 32, 447, 448,
+ 449, 450, 99, 460, 659, 1144, 1154, 23, 1185, 25,
+ 26, 1252, 509, 1081, 986, 752, 32, 684, 1197, 54,
+ 55, 56, 1197, 58, 799, 60, 1331, 1331, 765, 588,
+ 767, 33, 33, 1163, 862, 650, 1178, 1179, 54, 55,
+ 56, 809, 58, 1102, 60, 877, 953, 12, 497, 1179,
+ 499, 4, 414, 497, 1184, 1185, 875, 92, 4, 5,
+ 6, 7, 511, 512, 10, 514, 12, 20, 540, 797,
+ 1270, 833, 521, 1304, 1306, -1, 92, 44, 879, 1209,
+ 33, 27, 368, 532, 821, 31, 823, -1, 825, 35,
+ -1, 3, 4, 46, 71, 72, 73, 74, 75, 76,
+ 77, 78, 79, 552, 553, 51, 59, 53, -1, -1,
+ -1, -1, -1, 1331, 81, 82, -1, -1, 71, 86,
+ 87, 88, 89, 76, 77, -1, -1, -1, -1, 41,
+ -1, -1, 44, -1, -1, 88, 89, -1, -1, 51,
+ 1199, 53, 622, 96, 1274, -1, 99, -1, 60, -1,
+ -1, -1, -1, 65, 603, 604, 605, -1, -1, -1,
+ 1290, 1291, 611, 75, -1, -1, 119, -1, -1, 122,
+ -1, 83, -1, 1303, -1, -1, 88, -1, 627, 628,
+ -1, 630, -1, 136, 839, 840, -1, -1, -1, -1,
+ 845, 846, 847, -1, -1, -1, 4, 5, 6, 7,
+ -1, 650, -1, -1, 12, -1, 1265, -1, 3, 4,
+ 659, -1, 7, 139, 140, 141, 71, -1, -1, 27,
+ -1, 76, -1, 31, -1, -1, -1, 35, -1, 678,
+ 183, -1, 1102, 88, 89, -1, -1, -1, -1, 688,
+ 689, 690, -1, 51, 99, 53, 41, -1, -1, 44,
+ -1, -1, -1, -1, -1, -1, 51, -1, 53, -1,
+ -1, 69, -1, -1, -1, -1, 251, 24, 25, 254,
+ 65, 751, 257, -1, -1, -1, -1, 230, 263, -1,
+ 75, 136, -1, -1, -1, -1, -1, 272, 83, -1,
+ 85, -1, -1, 88, 89, -1, -1, -1, -1, 748,
+ -1, -1, -1, -1, -1, 258, -1, 1177, 1178, 1179,
+ -1, -1, -1, 4, 71, 6, 7, -1, 271, 76,
+ 769, 12, 771, -1, -1, -1, 279, -1, 808, 778,
+ -1, 88, 89, 782, -1, 784, 27, 786, 787, 788,
+ 31, -1, 99, -1, 35, 794, 299, -1, -1, -1,
+ -1, 108, 109, -1, -1, 804, -1, 806, -1, -1,
+ 51, -1, 53, -1, -1, -1, -1, -1, 577, -1,
+ 819, 324, 852, -1, -1, -1, -1, -1, -1, 136,
+ -1, -1, 139, 140, -1, -1, -1, -1, 837, 838,
+ 839, 840, -1, -1, -1, 844, 845, 846, 847, -1,
+ -1, -1, -1, 258, -1, -1, -1, -1, 361, -1,
+ -1, 364, -1, 862, -1, 368, 271, -1, -1, -1,
+ -1, -1, 631, 872, 904, 905, 875, -1, 877, -1,
+ 879, -1, -1, 642, -1, 388, 73, 74, 75, 76,
+ 77, 78, 79, -1, 299, -1, -1, 1102, 374, -1,
+ 376, 69, 378, 379, -1, -1, -1, -1, -1, -1,
+ 445, 414, 1199, 416, -1, 391, -1, -1, 421, -1,
+ 919, 920, -1, 922, -1, -1, -1, 3, 4, -1,
+ -1, 961, -1, -1, -1, 438, -1, 413, 441, -1,
+ -1, 940, 941, 446, 447, 448, 449, 450, 116, -1,
+ -1, 258, -1, -1, 953, -1, -1, 460, -1, -1,
+ -1, 464, -1, 368, 271, 41, -1, 135, 44, -1,
+ -1, -1, 1177, 1178, 1179, 51, -1, 53, 1265, -1,
+ -1, -1, 150, 388, -1, -1, 985, 986, 987, 65,
+ -1, -1, 299, 496, 497, -1, -1, -1, -1, 75,
+ 999, 1000, -1, 1002, -1, 1035, -1, 83, -1, 85,
+ 1040, 514, 88, 89, -1, -1, 421, -1, 521, -1,
+ -1, -1, -1, -1, 1, -1, 3, 4, 5, 6,
+ 7, 1030, -1, 438, -1, 12, 441, -1, -1, -1,
+ -1, 446, 447, 448, 449, 450, -1, -1, 25, 26,
+ 27, -1, 811, -1, 31, 460, -1, -1, 35, 464,
+ -1, 368, 39, -1, 41, -1, -1, -1, 45, -1,
+ -1, 378, 379, -1, 51, -1, 53, -1, -1, 56,
+ -1, 388, -1, -1, 1114, 1115, -1, -1, 65, -1,
+ -1, 496, 497, -1, -1, -1, -1, -1, 75, -1,
+ -1, 860, 605, 1102, -1, -1, 83, -1, 611, 514,
+ 869, 88, -1, 1143, 421, -1, 521, 94, 95, 878,
+ -1, -1, -1, 3, 4, -1, -1, 603, 604, 605,
+ -1, 438, -1, -1, 441, 611, -1, -1, -1, 446,
+ 447, 448, 449, 450, -1, -1, -1, -1, 10, -1,
+ -1, 627, 628, 460, 630, -1, 659, 464, 1188, -1,
+ -1, 41, -1, 25, 26, 1195, 1196, -1, -1, -1,
+ 32, 51, -1, 53, 1204, -1, 56, -1, 1177, 1178,
+ 1179, -1, 44, 659, -1, 65, -1, -1, -1, 496,
+ 497, -1, -1, 55, 56, 75, 58, -1, 60, 4,
+ 605, -1, 7, 83, 511, 512, 611, 514, 88, -1,
+ -1, -1, -1, 381, 521, -1, -1, -1, -1, 387,
+ -1, -1, 1221, -1, -1, 760, 88, 89, -1, -1,
+ 92, 93, -1, 1263, 1264, -1, -1, -1, -1, 44,
+ 102, -1, -1, -1, -1, 748, 51, -1, 53, 752,
+ -1, 786, 787, -1, 659, 1014, 1015, -1, -1, -1,
+ 65, -1, -1, 431, 432, -1, 434, -1, 1027, 1028,
+ 75, -1, -1, -1, -1, 778, -1, -1, -1, -1,
+ 85, 784, -1, 88, 89, 788, 4, 5, 6, 7,
+ -1, -1, -1, -1, 12, -1, 603, 604, 605, -1,
+ 1330, 804, -1, 806, 611, -1, -1, -1, -1, 27,
+ 845, 846, -1, 31, -1, -1, -1, 35, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, 832,
+ -1, -1, 1331, 51, -1, 53, -1, -1, 277, 278,
+ 279, -1, -1, 748, 847, -1, -1, -1, -1, 517,
+ 518, -1, 659, -1, 522, 890, 891, -1, 861, -1,
+ -1, 837, 838, 839, 840, 1124, 3, 4, 844, 845,
+ 846, 847, -1, 778, 877, -1, 879, -1, -1, 784,
+ -1, -1, -1, 788, -1, -1, -1, -1, -1, -1,
+ 925, -1, -1, -1, -1, -1, 872, -1, -1, 804,
+ -1, -1, -1, -1, 41, 940, 941, -1, -1, -1,
+ -1, -1, -1, -1, 51, -1, 53, -1, -1, -1,
+ -1, 360, -1, 362, 363, 364, -1, -1, 65, 597,
+ 598, 1190, 1191, -1, 1193, 1194, -1, -1, 75, 607,
+ -1, 748, 847, -1, -1, 613, 83, -1, -1, -1,
+ 953, 88, -1, -1, -1, -1, 861, -1, -1, -1,
+ -1, 1, -1, 3, 4, 5, 6, 7, -1, -1,
+ -1, 778, 12, -1, 879, -1, -1, 784, -1, 786,
+ 787, 788, -1, 986, -1, 988, -1, 27, -1, 657,
+ -1, 31, 995, -1, -1, 35, 36, 804, -1, 3,
+ 4, 41, -1, 7, -1, -1, -1, -1, 3, 4,
+ -1, 51, 7, 53, -1, -1, 56, -1, -1, -1,
+ 60, -1, -1, 999, 1000, 65, 1002, 1030, -1, -1,
+ -1, -1, 839, 840, 76, 75, -1, 41, 845, 846,
+ 847, 1300, -1, 83, -1, -1, 41, 51, 88, 53,
+ -1, -1, -1, -1, 861, -1, 51, 99, 53, -1,
+ -1, 65, -1, 103, -1, -1, -1, -1, 3, 4,
+ 65, 75, 879, 512, -1, 514, -1, -1, 1081, 83,
+ 75, -1, 521, -1, 88, -1, 754, 755, 83, 757,
+ -1, -1, -1, 88, 136, -1, -1, 1, -1, 3,
+ 4, 5, 6, 7, -1, -1, 41, -1, 12, -1,
+ -1, -1, -1, 552, -1, 783, 51, -1, 53, -1,
+ -1, -1, -1, 27, -1, 60, 1102, 31, -1, -1,
+ 65, 35, 36, 940, 941, -1, -1, 41, -1, -1,
+ 75, -1, 1177, 1178, -1, -1, -1, 51, 83, 53,
+ -1, -1, 1155, 88, -1, -1, 60, -1, -1, -1,
+ 1163, 65, -1, 1166, -1, 604, 605, -1, -1, -1,
+ -1, 75, 611, -1, -1, 843, 1179, -1, -1, 83,
+ -1, 1184, 1185, -1, 88, -1, -1, 855, 856, 857,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, 103,
+ -1, 1177, 1178, 1179, -1, -1, 1209, -1, -1, -1,
+ -1, -1, -1, 1216, -1, -1, -1, 259, -1, -1,
+ 1223, -1, 4, 1226, 6, 7, -1, -1, -1, -1,
+ 12, -1, -1, -1, 3, 4, 5, 6, 7, 678,
+ -1, -1, -1, 12, 1247, 27, -1, 1250, -1, 31,
+ -1, -1, -1, 35, 1257, -1, -1, 1, 1163, 3,
+ 4, 5, 6, 7, -1, 933, 35, -1, 12, 51,
+ -1, 53, 41, -1, 1179, 44, -1, -1, 1281, 1184,
+ 1185, -1, 51, 27, 53, -1, -1, 31, -1, -1,
+ -1, 35, 36, 1296, -1, -1, 65, 41, -1, 341,
+ 342, -1, -1, -1, 1209, -1, 75, 51, 1311, 53,
+ -1, -1, 56, -1, 83, -1, 60, -1, -1, 88,
+ -1, 65, -1, -1, -1, 1328, 1329, -1, 1331, -1,
+ 769, 75, 771, -1, -1, -1, -1, -1, -1, 83,
+ -1, -1, -1, 782, 88, -1, 388, -1, 787, 788,
+ 1018, -1, -1, -1, -1, -1, 1163, -1, -1, 103,
+ -1, -1, -1, -1, -1, 4, -1, 6, 7, 411,
+ 1177, 1178, 1179, 12, -1, -1, -1, 1184, 1185, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, 27, -1,
+ -1, -1, 31, -1, 436, 1063, 35, -1, 837, 838,
+ -1, 840, 1209, -1, -1, 844, -1, 846, 847, 3,
+ 4, -1, 51, 7, 53, 54, -1, -1, 460, -1,
+ -1, 463, -1, -1, 466, 467, 1331, 469, 470, 471,
+ 472, 473, 474, 475, 476, 477, 478, 479, 480, 481,
+ 482, 483, 484, 485, 486, 487, -1, 41, -1, 88,
+ 44, 493, -1, 495, 496, -1, -1, 51, -1, 53,
+ 3, 4, 5, 6, 7, -1, -1, 10, -1, 12,
+ -1, 65, 4, -1, 6, 7, -1, -1, -1, 521,
+ 12, 75, -1, -1, 27, 527, 4, -1, 31, 83,
+ -1, 85, 35, -1, 88, 89, -1, -1, 41, -1,
+ 542, 543, 941, 35, -1, -1, 24, 25, 51, 27,
+ 53, -1, 44, -1, -1, 33, -1, -1, -1, 51,
+ -1, 53, 65, -1, 1331, -1, 44, -1, 46, -1,
+ -1, -1, 75, 65, -1, -1, -1, -1, -1, 581,
+ 83, -1, -1, 75, -1, 88, 588, -1, 66, -1,
+ 93, -1, -1, 85, -1, -1, 88, 89, -1, -1,
+ 999, 1000, 1, 1002, 3, 4, 5, 6, 7, 611,
+ -1, -1, -1, 12, -1, -1, -1, 95, -1, -1,
+ 622, -1, -1, 101, -1, 103, -1, 105, 27, -1,
+ 108, 109, 31, -1, -1, -1, 35, -1, -1, -1,
+ -1, 119, 41, 121, 122, -1, 45, -1, -1, -1,
+ -1, -1, 51, -1, 53, -1, 658, 56, -1, -1,
+ -1, 139, 140, 141, -1, -1, 65, -1, -1, -1,
+ -1, 149, -1, -1, -1, -1, 75, -1, -1, -1,
+ -1, -1, -1, -1, 83, -1, -1, 165, -1, 88,
+ -1, 693, -1, -1, -1, 94, 1, -1, 3, 4,
+ -1, 6, 7, 8, 9, 183, 11, 12, -1, -1,
+ -1, -1, 714, -1, -1, 193, -1, -1, -1, -1,
+ -1, -1, 27, 28, 29, 30, 31, -1, 33, -1,
+ 35, -1, 37, 38, -1, 40, 41, 42, 43, -1,
+ -1, 46, 47, 48, 49, 50, 51, -1, 53, 751,
+ 752, -1, -1, -1, -1, 60, -1, 62, -1, -1,
+ 65, -1, -1, 765, -1, 767, -1, -1, 73, 74,
+ 75, -1, -1, -1, -1, -1, 81, 82, 83, -1,
+ -1, -1, -1, 88, -1, -1, -1, 92, -1, -1,
+ -1, -1, -1, -1, 796, -1, -1, 275, -1, 104,
+ -1, -1, -1, -1, -1, 283, 808, 285, -1, 3,
+ 4, -1, 6, 7, 8, 9, -1, 11, 12, 821,
+ -1, 823, -1, 825, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, 27, 28, 313, -1, 31, 316, 33,
+ -1, 35, 320, 37, 38, -1, 40, 41, 42, 43,
+ 852, -1, 46, 47, 48, 49, 50, 51, -1, 53,
+ -1, -1, -1, -1, 866, 867, -1, -1, 62, -1,
+ -1, 65, -1, -1, -1, -1, -1, 3, 4, 73,
+ 74, 75, 360, 361, 362, 363, -1, 81, 82, 83,
+ 368, -1, -1, -1, 88, -1, 374, -1, 376, -1,
+ 378, 379, 904, 905, -1, -1, 908, 385, -1, -1,
+ 104, -1, -1, 391, -1, 41, 394, -1, 1, -1,
+ 3, 4, 5, 6, 7, 51, -1, 53, -1, 12,
+ -1, 3, 4, -1, 60, 413, 414, -1, 416, 65,
+ -1, -1, -1, -1, 27, -1, -1, -1, 31, 75,
+ -1, -1, 35, 36, -1, -1, -1, 83, 41, 961,
+ -1, -1, 88, -1, -1, -1, -1, 4, 51, 41,
+ 53, 973, -1, -1, 3, 4, -1, 60, 7, 51,
+ -1, 53, 65, -1, -1, -1, -1, 24, 25, -1,
+ 27, -1, 75, 65, -1, -1, 33, -1, -1, -1,
+ 83, -1, -1, 75, -1, 88, -1, 44, -1, 46,
+ -1, 83, 41, -1, -1, 44, 88, -1, -1, 1021,
+ 103, -1, 51, -1, 53, 3, 4, 5, 6, 7,
+ -1, 509, 10, 1035, 12, -1, 65, -1, 1040, -1,
+ 1042, -1, -1, 521, -1, -1, 75, -1, -1, 27,
+ -1, -1, -1, 31, 83, -1, 85, 35, 95, 88,
+ 89, -1, -1, 41, 101, -1, 44, -1, 105, -1,
+ -1, 108, 109, 51, 552, 53, -1, -1, -1, -1,
+ -1, -1, 119, -1, 121, 122, -1, 65, -1, -1,
+ -1, 4, -1, 6, 7, -1, -1, 75, -1, 12,
+ 1102, -1, 139, 140, 141, 83, -1, 85, -1, -1,
+ 88, 89, 1114, 1115, 27, 93, -1, -1, 31, -1,
+ 1122, 1123, 35, -1, -1, 603, 604, 605, 165, -1,
+ -1, -1, -1, 611, -1, -1, -1, -1, 51, -1,
+ 53, 1143, -1, -1, -1, -1, 183, -1, -1, 627,
+ 628, -1, 630, -1, -1, -1, 193, -1, -1, -1,
+ -1, -1, 1164, 68, 69, 70, 71, 72, 73, 74,
+ 75, 76, 77, 78, 79, 88, -1, 1, -1, 3,
+ 4, 659, 6, 7, 8, 9, 1188, 11, 12, -1,
+ -1, -1, -1, 1195, 1196, -1, -1, 1199, -1, -1,
+ -1, -1, 1204, 27, 28, 29, 30, 31, -1, 33,
+ -1, 35, -1, 37, 38, 693, 40, 41, 42, 43,
+ -1, -1, 46, 47, 48, 49, 50, 51, -1, 53,
+ 54, -1, -1, -1, 3, 4, -1, -1, 62, -1,
+ -1, 65, -1, -1, -1, -1, -1, 284, 285, 73,
+ 74, 75, -1, -1, -1, -1, -1, 81, 82, 83,
+ -1, 1263, 1264, 1265, 88, 89, -1, -1, 92, -1,
+ -1, -1, 41, -1, -1, -1, 313, -1, -1, 316,
+ 104, -1, 51, 320, 53, -1, -1, -1, -1, -1,
+ 27, -1, -1, -1, -1, -1, 65, -1, -1, -1,
+ -1, -1, 339, -1, -1, -1, 75, 44, 786, 787,
+ -1, -1, -1, -1, 83, -1, -1, -1, -1, 88,
+ -1, -1, -1, 360, 361, 362, 363, -1, 1330, -1,
+ -1, 368, -1, -1, -1, -1, -1, 374, -1, 376,
+ -1, 378, 379, -1, -1, -1, -1, -1, 385, -1,
+ -1, -1, -1, -1, 391, -1, -1, 394, 95, 837,
+ 838, 839, 840, -1, 842, -1, 844, 845, 846, 847,
+ -1, 108, 109, -1, -1, -1, 413, 414, -1, 416,
+ -1, -1, -1, -1, 121, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, 872, -1, -1, 875, -1, 877,
+ -1, -1, 139, 140, 141, -1, -1, -1, -1, -1,
+ -1, -1, 890, 891, -1, 1, -1, 3, 4, 5,
+ 6, 7, 8, 9, -1, 11, 12, 13, 165, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,
+ 26, 27, 28, 29, 30, 31, -1, 33, -1, 35,
+ -1, 37, 38, -1, 40, 41, 42, 43, -1, -1,
+ 46, 47, 48, 49, 50, 51, 944, 53, 54, -1,
+ 56, -1, -1, -1, -1, 953, 62, -1, -1, 65,
+ -1, -1, -1, -1, 521, -1, -1, 73, 74, 75,
+ -1, -1, -1, -1, 231, 81, 82, 83, -1, -1,
+ -1, -1, 88, -1, 90, -1, 92, 985, 986, 987,
+ -1, -1, -1, -1, -1, 552, -1, 103, 104, -1,
+ -1, 999, 1000, -1, 1002, 3, 4, -1, -1, 7,
+ -1, 4, 5, 6, 7, -1, -1, 10, -1, 12,
+ 277, 278, 279, -1, -1, -1, -1, -1, 285, -1,
+ -1, -1, 1030, -1, 27, -1, -1, -1, 31, -1,
+ -1, -1, 35, 41, -1, -1, 603, 604, 605, -1,
+ -1, 44, -1, 51, 611, 53, -1, -1, 51, -1,
+ 53, -1, -1, -1, -1, -1, -1, 65, -1, -1,
+ 627, 628, 65, 630, -1, -1, -1, 75, -1, -1,
+ -1, -1, 75, -1, -1, 83, -1, -1, -1, -1,
+ 88, -1, 85, -1, -1, 88, 89, -1, -1, -1,
+ 93, -1, 659, 360, 1102, 362, 363, 364, -1, 1,
+ -1, 3, 4, 5, 6, 7, -1, 374, -1, 376,
+ 12, 378, 379, -1, -1, -1, 3, 4, 385, -1,
+ 7, 277, 278, 279, 391, 27, 693, 394, -1, 31,
+ -1, -1, -1, 35, -1, -1, -1, -1, 44, 41,
+ -1, -1, -1, -1, -1, -1, 413, -1, -1, 51,
+ -1, 53, -1, -1, 41, -1, -1, 44, -1, -1,
+ 66, -1, -1, 65, 51, -1, 53, -1, -1, 1177,
+ 1178, 1179, -1, 75, -1, -1, 3, 4, 65, 85,
+ 7, 83, -1, -1, -1, -1, 88, -1, 75, 95,
+ -1, -1, -1, -1, -1, -1, 83, -1, 85, -1,
+ -1, 88, 89, -1, 360, -1, 362, 363, 364, -1,
+ -1, -1, -1, 1221, 41, 121, -1, -1, -1, 786,
+ 787, -1, -1, -1, 51, -1, 53, 794, -1, -1,
+ -1, -1, 499, 139, 140, 141, -1, -1, 65, -1,
+ -1, -1, -1, 149, 511, 512, -1, 514, 75, -1,
+ -1, -1, 819, -1, 521, -1, 83, -1, -1, 165,
+ -1, 88, -1, -1, -1, -1, -1, -1, -1, -1,
+ 837, 838, 839, 840, -1, -1, -1, 844, 845, 846,
+ 847, -1, -1, -1, -1, 552, -1, -1, -1, 195,
+ -1, -1, 4, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, 872, -1, -1, 875, -1,
+ 877, -1, 24, 25, -1, -1, -1, 4, -1, 6,
+ 7, 33, -1, 890, 891, 12, -1, -1, -1, -1,
+ -1, -1, -1, -1, 46, -1, 603, 604, 605, -1,
+ -1, -1, -1, -1, 611, -1, -1, -1, 35, -1,
+ -1, -1, -1, -1, -1, 511, 512, 44, 514, -1,
+ 627, 628, -1, 630, 51, 521, 53, -1, 4, 5,
+ 6, 7, -1, -1, -1, -1, 12, 283, 65, 285,
+ -1, -1, -1, -1, -1, -1, 953, -1, 75, 101,
+ -1, 27, 659, 105, -1, 31, 552, -1, 85, 35,
+ -1, 88, 89, -1, -1, -1, -1, 119, -1, -1,
+ 122, 678, 3, 4, -1, 51, 7, 53, 985, 986,
+ 987, 688, 689, 690, -1, -1, -1, 139, 140, -1,
+ -1, -1, 999, 1000, -1, 1002, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, 603, 604, 605,
+ 41, -1, -1, -1, 360, 611, 362, 363, -1, -1,
+ 51, -1, 53, 1030, -1, -1, -1, -1, 374, -1,
+ 376, 183, 378, 379, 65, -1, 3, 4, -1, 385,
+ 7, 193, -1, -1, 75, 391, -1, -1, 394, -1,
+ -1, -1, 83, -1, -1, -1, 12, 88, -1, -1,
+ -1, -1, 769, -1, 771, -1, -1, 413, 24, 25,
+ -1, 27, -1, -1, 41, 782, -1, -1, -1, 786,
+ 787, 788, 678, -1, 51, -1, 53, -1, -1, -1,
+ -1, -1, -1, -1, -1, 1102, 52, -1, 65, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, 75, -1,
+ -1, -1, -1, -1, -1, -1, 83, -1, -1, -1,
+ -1, 88, -1, -1, -1, -1, -1, -1, -1, -1,
+ 837, 838, 839, 840, -1, -1, -1, 844, 845, 846,
+ 847, -1, -1, -1, -1, 101, -1, 103, 104, 105,
+ -1, -1, 108, 109, -1, 3, 4, -1, -1, 7,
+ -1, 313, -1, -1, 316, 872, -1, -1, 320, -1,
+ 1177, 1178, 1179, 769, -1, 771, -1, -1, 524, -1,
+ -1, -1, -1, -1, -1, -1, 782, -1, -1, -1,
+ 786, 787, 788, 41, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, 51, -1, 53, 552, -1, -1, 361,
+ -1, -1, 919, 920, 1221, 922, 368, 65, -1, -1,
+ -1, -1, 374, -1, 376, -1, -1, 75, -1, -1,
+ -1, -1, -1, 940, 941, 83, -1, 193, -1, 391,
+ 88, 837, 838, 839, 840, -1, -1, -1, 844, 845,
+ 846, 847, -1, -1, -1, -1, -1, 603, 604, 605,
+ -1, 413, 414, -1, 416, 611, -1, -1, -1, -1,
+ 3, 4, 5, 6, 7, 231, -1, -1, 985, 12,
+ 987, 627, 628, -1, 630, -1, -1, -1, -1, -1,
+ -1, -1, 999, 1000, 27, 1002, -1, -1, 31, -1,
+ -1, -1, 35, -1, -1, -1, -1, -1, 41, -1,
+ -1, 44, -1, 659, -1, -1, -1, -1, 51, 275,
+ 53, 277, 278, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, 65, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, 75, -1, 940, 941, -1, -1, -1, -1,
+ 83, 307, 85, -1, -1, 88, 89, 313, -1, -1,
+ 316, -1, -1, -1, 320, 63, 64, 65, 66, 67,
68, 69, 70, 71, 72, 73, 74, 75, 76, 77,
- 78, 79, 41, -1, -1, -1, -1, -1, -1, 835,
- 836, -1, 51, -1, 53, 841, 842, 843, 930, 602,
- -1, 60, -1, -1, -1, 608, 65, -1, -1, -1,
- -1, -1, 858, -1, -1, 1, 75, 3, 4, 1077,
- 6, 7, 8, 9, 83, 11, 12, -1, -1, 88,
- 876, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, 27, 28, 29, 30, 31, -1, 33, -1, 35,
- -1, 37, 38, 656, 40, 41, 42, 43, -1, -1,
- 46, 47, 48, 49, 50, 51, -1, 53, 54, -1,
- -1, 259, -1, -1, -1, -1, 62, -1, -1, 65,
- -1, -1, 1014, -1, -1, -1, -1, 73, 74, 75,
- -1, 937, 938, 1151, -1, 81, 82, 83, -1, -1,
- -1, 1159, 88, 89, 1162, -1, 92, -1, -1, -1,
- 1, -1, 3, 4, 5, 6, 7, 1175, 104, -1,
- -1, 12, 1180, 1181, -1, -1, -1, 1059, -1, -1,
- 139, 140, 141, -1, -1, -1, 27, -1, -1, -1,
- 31, -1, 745, -1, 35, 36, -1, 1205, -1, -1,
- 41, -1, 340, 341, 1212, -1, -1, -1, -1, -1,
- 51, 1219, 53, -1, 1222, -1, 3, 4, -1, 60,
- 7, -1, 775, -1, 65, -1, -1, -1, 781, -1,
- -1, -1, 785, -1, 75, 1243, -1, -1, 1246, -1,
- -1, -1, 83, -1, -1, 1253, -1, 88, 801, 387,
+ 78, 79, 1, -1, 3, 4, 5, 6, 7, 8,
+ 9, 10, 11, 12, -1, 1102, -1, -1, -1, -1,
+ -1, -1, -1, 999, 1000, -1, 1002, -1, 27, 28,
+ 29, 30, 31, -1, 33, -1, 35, -1, 37, 38,
+ -1, 40, 41, 42, 43, -1, -1, 46, 47, 48,
+ 49, 50, 51, -1, 53, -1, -1, -1, -1, -1,
+ -1, -1, -1, 62, -1, -1, 65, -1, -1, -1,
+ -1, 603, 604, -1, 73, 74, 75, -1, -1, -1,
+ -1, -1, 81, 82, 83, -1, -1, -1, -1, 88,
+ 1177, 1178, 1179, 92, 93, 627, 628, 433, 630, -1,
+ -1, -1, -1, 102, -1, 104, -1, -1, -1, -1,
+ -1, 837, 838, 839, 840, -1, 842, -1, 844, 845,
+ 846, 847, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, 1221, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, 872, -1, -1, -1,
+ -1, 1, -1, 3, 4, 5, 6, 7, 8, 9,
+ 10, 11, 12, 499, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, 509, -1, 511, 512, 27, 28, 29,
+ 30, 31, -1, 33, -1, 35, -1, 37, 38, -1,
+ 40, 41, 42, 43, 44, -1, 46, 47, 48, 49,
+ 50, 51, -1, 53, 54, -1, -1, -1, -1, -1,
+ -1, -1, 62, -1, -1, 65, -1, 553, 944, -1,
+ -1, -1, -1, 73, 74, 75, -1, -1, -1, -1,
+ -1, 81, 82, 83, -1, 85, -1, -1, 88, 89,
+ -1, -1, 92, 93, -1, -1, 3, 4, 5, 6,
+ 7, -1, -1, -1, 104, 12, -1, -1, -1, 985,
+ -1, 987, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, 999, 1000, -1, 1002, -1, 35, -1,
-1, -1, -1, -1, 41, -1, -1, 44, -1, -1,
- -1, -1, 103, -1, 51, -1, 53, -1, -1, 1277,
- -1, -1, 410, -1, -1, -1, -1, -1, 65, -1,
- -1, -1, -1, -1, 1292, -1, -1, -1, 75, -1,
- 843, -1, -1, -1, -1, -1, 83, 435, 85, 1307,
- -1, 88, 89, -1, -1, 858, -1, -1, -1, -1,
- -1, 3, 4, -1, -1, 7, 1324, 1325, -1, 1327,
- -1, 459, -1, 876, 462, -1, -1, 465, 466, -1,
- 468, 469, 470, 471, 472, 473, 474, 475, 476, 477,
- 478, 479, 480, 481, 482, 483, 484, 485, 486, 41,
- -1, -1, 44, -1, 492, -1, 494, 495, -1, 51,
- -1, 53, -1, 1159, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, 65, -1, -1, -1, 1173, 1174, 1175,
- -1, -1, 520, 75, 1180, 1181, 3, 4, 526, -1,
- 7, 83, -1, 85, -1, -1, 88, 89, -1, -1,
- -1, -1, -1, 541, 542, -1, -1, -1, -1, 1205,
- -1, -1, -1, -1, 373, -1, 375, -1, 377, 378,
- 277, 278, 279, -1, 41, -1, -1, 44, -1, -1,
- -1, 390, -1, -1, 51, -1, 53, -1, -1, 1,
- 578, 3, 4, 5, 6, 7, -1, 585, 65, -1,
- 12, -1, -1, 412, -1, -1, -1, -1, 75, -1,
- -1, -1, -1, 25, 26, 27, 83, -1, 85, 31,
- 608, 88, 89, 35, -1, -1, -1, 39, 4, 41,
- -1, 619, -1, 45, -1, -1, 3, 4, -1, 51,
- 7, 53, -1, -1, 56, -1, -1, -1, 24, 25,
- -1, 27, 359, 65, 361, 362, 363, 33, -1, -1,
- -1, -1, -1, 75, -1, -1, -1, 655, 44, -1,
- 46, 83, 3, 4, 41, -1, 88, -1, -1, -1,
- -1, 1327, 94, 95, 51, -1, 53, -1, -1, -1,
- 66, -1, -1, -1, -1, -1, -1, -1, 65, -1,
- -1, -1, 690, -1, -1, -1, -1, -1, 75, -1,
- 41, -1, -1, -1, -1, -1, 83, -1, -1, 95,
- 51, 88, 53, 711, -1, 101, -1, 103, -1, 105,
- -1, -1, 108, 109, 65, -1, -1, -1, -1, 4,
- -1, 6, 7, 119, 75, 121, 122, 12, -1, -1,
- -1, -1, 83, -1, -1, -1, 1159, 88, -1, -1,
- 748, 749, 27, 139, 140, 141, 31, -1, -1, -1,
- 35, -1, 1175, 149, 762, -1, 764, 1180, 1181, 44,
- -1, -1, -1, -1, -1, -1, 51, -1, 53, 165,
- -1, 600, 601, 602, 3, 4, -1, -1, 7, 608,
- 65, -1, 1205, 510, 511, 793, 513, 183, -1, -1,
- 75, -1, -1, 520, -1, 624, 625, 193, 627, -1,
- 85, -1, -1, 88, 89, -1, -1, -1, -1, 817,
- -1, 819, 41, 821, -1, -1, -1, -1, -1, -1,
- -1, -1, 51, 550, 53, -1, -1, 656, -1, -1,
- -1, -1, -1, -1, -1, -1, 65, -1, -1, -1,
- 848, 849, -1, -1, -1, -1, 75, -1, -1, -1,
- -1, -1, -1, -1, 83, 863, 864, -1, -1, 88,
- 3, 4, 5, 6, 7, -1, -1, 10, 4, 12,
- 6, 7, -1, 600, 601, 602, 12, -1, -1, 275,
- -1, 608, -1, -1, 27, -1, -1, 283, 31, 285,
- -1, 27, 35, 901, 902, 31, -1, 905, 41, 35,
- -1, 44, -1, -1, 1327, -1, -1, -1, 51, -1,
- 53, -1, -1, -1, -1, 51, 312, 53, 54, 315,
- -1, -1, 65, 319, -1, -1, -1, -1, -1, -1,
- -1, 4, 75, 6, 7, -1, -1, -1, -1, 12,
- 83, -1, 85, -1, -1, 88, 89, -1, 675, 957,
- 93, -1, 88, -1, 27, -1, -1, -1, 31, -1,
- 968, -1, 35, 359, 360, 361, 362, -1, -1, -1,
- -1, 367, -1, -1, -1, -1, -1, 373, 51, 375,
- 53, 377, 378, 3, 4, 5, 6, 7, 384, -1,
- -1, -1, 12, -1, 390, -1, -1, 393, 3, 4,
- -1, -1, 7, -1, 833, 834, 835, 836, -1, 1017,
- -1, 840, 841, 842, 843, 35, 412, 413, -1, 415,
- -1, 41, -1, 1031, 44, -1, -1, -1, 1036, -1,
- 1038, 51, -1, 53, -1, -1, 41, -1, -1, 766,
- 869, 768, -1, -1, -1, 65, 51, -1, 53, -1,
- -1, -1, 779, -1, -1, 75, 783, 784, 785, -1,
- 65, -1, -1, 83, -1, 85, -1, -1, 88, 89,
- 75, -1, -1, -1, -1, -1, -1, -1, 83, -1,
- -1, -1, -1, 88, 3, 4, -1, -1, 7, -1,
- 1098, -1, -1, 1, -1, 3, 4, 5, 6, 7,
- -1, -1, 1110, 1111, 12, -1, 833, 834, 835, 836,
- 1118, 1119, 508, 840, 841, 842, 843, -1, -1, 27,
- -1, -1, 41, 31, 520, -1, -1, 35, -1, -1,
- -1, 1139, 51, 41, 53, -1, -1, -1, -1, -1,
- -1, -1, -1, 51, -1, 53, 65, -1, -1, -1,
- -1, -1, 1160, -1, 550, -1, 75, 65, -1, -1,
- -1, -1, -1, -1, 83, 994, 995, 75, 997, 88,
- -1, -1, -1, -1, -1, 83, 1184, -1, -1, -1,
- 88, -1, -1, 1191, 1192, -1, -1, 1195, -1, -1,
- -1, -1, 1200, -1, 4, 4, 5, 6, 7, -1,
- -1, 10, -1, 12, 600, 601, 602, -1, -1, -1,
- 937, 938, 608, -1, 24, 25, -1, 27, 27, -1,
- -1, -1, 31, 33, -1, -1, 35, -1, 624, 625,
- -1, 627, -1, -1, 44, 44, 46, -1, -1, -1,
- -1, -1, 51, -1, 53, -1, -1, -1, -1, -1,
- -1, 1259, 1260, 1261, 3, 4, 65, -1, 7, -1,
- 656, -1, -1, -1, -1, -1, 75, 994, 995, 1098,
- 997, -1, -1, -1, -1, -1, 85, -1, -1, 88,
- 89, -1, -1, -1, 93, 95, -1, -1, -1, -1,
- -1, 101, 41, -1, 690, 105, -1, -1, 108, 109,
- -1, -1, 51, -1, 53, -1, -1, -1, -1, 119,
- -1, 121, 122, -1, -1, -1, 65, -1, 1326, -1,
- -1, -1, -1, -1, -1, -1, 75, -1, -1, 139,
- 140, 141, -1, -1, 83, -1, -1, -1, -1, 88,
- -1, -1, -1, -1, 1173, 1174, 1175, -1, 1, -1,
- -1, 4, -1, 6, 7, 165, -1, -1, -1, 12,
+ -1, -1, -1, -1, 51, -1, 53, -1, -1, -1,
+ -1, -1, -1, -1, -1, 837, 838, -1, 65, -1,
+ -1, -1, 844, -1, -1, -1, -1, -1, 75, -1,
+ -1, -1, -1, -1, -1, -1, 83, -1, 85, -1,
+ -1, 88, 89, -1, -1, -1, -1, -1, -1, -1,
+ 872, -1, 678, 875, -1, 877, -1, -1, -1, -1,
+ -1, -1, 688, 689, 690, -1, 1, -1, 3, 4,
+ 5, 6, 7, 8, 9, 10, 11, 12, -1, -1,
+ -1, -1, -1, -1, -1, -1, 1102, -1, -1, -1,
+ -1, -1, 27, 28, 29, 30, 31, -1, 33, -1,
+ 35, -1, 37, 38, -1, 40, 41, 42, 43, 44,
+ -1, 46, 47, 48, 49, 50, 51, -1, 53, 54,
+ -1, -1, -1, -1, -1, -1, -1, 62, -1, -1,
+ 65, 953, -1, -1, 10, -1, -1, -1, 73, 74,
+ 75, -1, -1, 769, -1, 771, 81, 82, 83, -1,
+ 85, -1, -1, 88, 89, -1, 782, 92, 93, -1,
+ -1, 1177, 1178, 1179, 986, -1, -1, -1, -1, 104,
+ -1, -1, -1, -1, -1, -1, -1, 999, 1000, -1,
+ 1002, 57, 58, 59, 60, 61, 62, 63, 64, 65,
+ 66, 67, 68, 69, 70, 71, 72, 73, 74, 75,
+ 76, 77, 78, 79, -1, 1221, -1, -1, 1030, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, 1, -1,
+ 3, 4, 5, 6, 7, 8, 9, -1, 11, 12,
+ 13, -1, 15, 16, 17, 18, 19, 20, 21, 22,
+ 23, 24, 25, 26, 27, 28, 29, 30, 31, 875,
+ 33, -1, 35, -1, 37, 38, -1, 40, 41, 42,
+ 43, -1, -1, 46, 47, 48, 49, 50, 51, -1,
+ 53, 54, -1, 56, -1, -1, -1, -1, -1, 62,
+ -1, -1, 65, -1, -1, -1, -1, -1, -1, -1,
+ 73, 74, 75, 919, 920, -1, 922, -1, 81, 82,
+ 83, -1, -1, -1, -1, 88, -1, 90, -1, 92,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ 103, 104, 1, -1, 3, 4, 5, 6, 7, 8,
+ 9, -1, 11, 12, 13, -1, 15, 16, 17, 18,
+ 19, 20, 21, 22, 23, 24, 25, 26, 27, 28,
+ 29, 30, 31, -1, 33, -1, 35, -1, 37, 38,
+ -1, 40, 41, 42, 43, -1, -1, 46, 47, 48,
+ 49, 50, 51, -1, 53, 54, -1, 56, -1, -1,
+ -1, -1, -1, 62, -1, -1, 65, -1, -1, -1,
+ -1, -1, -1, -1, 73, 74, 75, -1, -1, -1,
+ -1, -1, 81, 82, 83, -1, -1, -1, -1, 88,
+ -1, 90, -1, 92, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, 103, 104, 1, -1, 3, 4,
+ 5, 6, 7, 8, 9, -1, 11, 12, 13, -1,
+ 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
+ 25, 26, 27, 28, 29, 30, 31, -1, 33, -1,
+ 35, -1, 37, 38, -1, 40, 41, 42, 43, -1,
+ -1, 46, 47, 48, 49, 50, 51, -1, 53, 54,
+ -1, 56, -1, -1, -1, -1, -1, 62, -1, -1,
+ 65, -1, -1, -1, -1, -1, -1, -1, 73, 74,
+ 75, -1, -1, -1, -1, -1, 81, 82, 83, -1,
+ -1, -1, -1, 88, -1, 90, -1, 92, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, 103, 104,
+ 1, -1, 3, 4, 5, 6, 7, 8, 9, -1,
+ 11, 12, 13, -1, 15, 16, 17, 18, 19, 20,
+ 21, 22, 23, 24, 25, 26, 27, 28, 29, 30,
+ 31, -1, 33, -1, 35, -1, 37, 38, -1, 40,
+ 41, 42, 43, -1, -1, 46, 47, 48, 49, 50,
+ 51, -1, 53, 54, -1, 56, -1, -1, -1, -1,
+ -1, 62, -1, -1, 65, -1, -1, -1, -1, -1,
+ -1, -1, 73, 74, 75, -1, -1, -1, -1, -1,
+ 81, 82, 83, -1, -1, -1, -1, 88, -1, 90,
+ -1, 92, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, 103, 104, 1, -1, 3, 4, 5, 6,
+ 7, 8, 9, -1, 11, 12, 13, -1, 15, 16,
+ 17, 18, 19, 20, 21, 22, 23, 24, 25, 26,
+ 27, 28, 29, 30, 31, -1, 33, -1, 35, -1,
+ 37, 38, -1, 40, 41, 42, 43, -1, -1, 46,
+ 47, 48, 49, 50, 51, -1, 53, 54, -1, 56,
+ -1, -1, -1, -1, -1, 62, -1, -1, 65, -1,
+ -1, -1, -1, -1, -1, -1, 73, 74, 75, -1,
+ -1, -1, -1, -1, 81, 82, 83, -1, -1, -1,
+ -1, 88, -1, 90, 1, 92, 3, 4, 5, 6,
+ 7, 8, 9, -1, 11, 12, 13, 104, 15, 16,
+ 17, 18, 19, 20, 21, 22, 23, 24, 25, 26,
+ 27, 28, 29, 30, 31, -1, 33, -1, 35, -1,
+ 37, 38, -1, 40, 41, 42, 43, -1, -1, 46,
+ 47, 48, 49, 50, 51, -1, 53, 54, -1, 56,
+ -1, -1, -1, -1, -1, 62, -1, -1, 65, -1,
+ -1, -1, -1, -1, -1, -1, 73, 74, 75, -1,
+ -1, -1, -1, -1, 81, 82, 83, -1, -1, -1,
+ -1, 88, -1, 90, 1, 92, 3, 4, 5, 6,
+ 7, 8, 9, -1, 11, 12, 13, 104, 15, 16,
+ 17, 18, 19, 20, 21, 22, 23, 24, 25, 26,
+ 27, 28, 29, 30, 31, -1, 33, -1, 35, -1,
+ 37, 38, -1, 40, 41, 42, 43, -1, -1, 46,
+ 47, 48, 49, 50, 51, -1, 53, 54, -1, 56,
+ -1, -1, -1, -1, -1, 62, -1, -1, 65, -1,
+ -1, -1, -1, -1, -1, -1, 73, 74, 75, -1,
+ -1, -1, -1, -1, 81, 82, 83, -1, -1, -1,
+ -1, 88, -1, 90, 1, 92, 3, 4, 5, 6,
+ 7, 8, 9, 10, 11, 12, -1, 104, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ 27, 28, 29, 30, 31, -1, 33, -1, 35, -1,
+ 37, 38, -1, 40, 41, 42, 43, -1, -1, 46,
+ 47, 48, 49, 50, 51, -1, 53, -1, -1, -1,
+ -1, -1, -1, -1, -1, 62, -1, -1, 65, -1,
+ -1, -1, -1, -1, -1, -1, 73, 74, 75, -1,
+ -1, -1, -1, -1, 81, 82, 83, -1, -1, -1,
+ -1, 88, -1, -1, -1, 92, 93, -1, -1, -1,
+ -1, -1, -1, -1, -1, 102, 1, 104, 3, 4,
+ -1, 6, 7, 8, 9, -1, 11, 12, 66, 67,
68, 69, 70, 71, 72, 73, 74, 75, 76, 77,
- 78, 79, -1, 183, 27, -1, -1, -1, 31, -1,
- -1, -1, 35, 193, 37, 38, 27, 783, 784, -1,
- -1, 44, -1, -1, -1, -1, -1, -1, 51, -1,
- 53, -1, 55, 44, 57, 58, 59, -1, 61, 62,
- 63, 64, 65, 66, 67, 68, 69, 70, 71, 72,
- 73, 74, 75, 76, 77, 78, -1, -1, 81, 82,
- 83, -1, -1, 86, -1, -1, 89, 833, 834, 835,
- 836, -1, 838, -1, 840, 841, 842, 843, -1, -1,
- -1, 104, -1, -1, 95, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, 108, 109, -1,
- -1, -1, -1, 869, 284, 285, 872, -1, 874, -1,
- 121, -1, -1, -1, 3, 4, 5, 6, 7, -1,
- -1, 887, 888, 12, -1, -1, -1, -1, 139, 140,
- 141, -1, 312, -1, -1, 315, -1, -1, 27, 319,
- -1, -1, 31, -1, -1, -1, 35, -1, -1, -1,
- -1, -1, 41, -1, 165, 44, -1, -1, 338, -1,
- -1, -1, 51, -1, 53, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, 941, 65, -1, -1, 359,
- 360, 361, 362, 949, -1, -1, 75, 367, -1, -1,
- -1, -1, -1, 373, 83, 375, 85, 377, 378, 88,
- 89, -1, -1, -1, 384, -1, -1, -1, -1, -1,
- 390, -1, -1, 393, 980, 981, 982, -1, -1, -1,
- 231, -1, -1, -1, -1, -1, -1, -1, 994, 995,
- -1, 997, 412, 413, -1, 415, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, 3, 4,
- 12, 6, 7, 8, 9, -1, 11, 12, -1, -1,
- 1026, -1, 24, 25, -1, 27, 277, 278, 279, -1,
- -1, -1, 27, 28, 285, -1, 31, -1, 33, -1,
+ 78, 79, 27, 28, 29, 30, 31, -1, 33, -1,
35, -1, 37, 38, -1, 40, 41, 42, 43, -1,
- 52, 46, 47, 48, 49, 50, 51, -1, 53, -1,
+ -1, 46, 47, 48, 49, 50, 51, -1, 53, 54,
-1, -1, -1, -1, -1, -1, -1, 62, -1, -1,
65, -1, -1, -1, -1, -1, -1, -1, 73, 74,
75, -1, -1, -1, -1, -1, 81, 82, 83, -1,
- -1, -1, 1098, 88, -1, -1, -1, -1, -1, 101,
- 520, 103, 104, 105, -1, -1, 108, 109, 359, 104,
- 361, 362, 363, -1, 3, 4, 5, 6, 7, -1,
- -1, -1, 373, 12, 375, -1, 377, 378, -1, -1,
- 550, -1, -1, 384, -1, -1, -1, -1, -1, 390,
- -1, -1, 393, -1, 44, -1, 35, -1, -1, -1,
- -1, -1, 41, -1, -1, 44, -1, -1, -1, -1,
- -1, 412, 51, -1, 53, -1, 66, 1173, 1174, 1175,
- -1, -1, -1, -1, -1, -1, 65, -1, -1, -1,
- 600, 601, 602, -1, -1, 85, 75, -1, 608, -1,
- -1, 193, -1, -1, 83, 95, 85, -1, -1, 88,
- 89, -1, -1, -1, 624, 625, 4, 627, 6, 7,
- -1, 1217, -1, -1, 12, -1, 3, 4, -1, -1,
- 7, 121, -1, -1, -1, 4, 5, 6, 7, 231,
- -1, 10, -1, 12, -1, -1, 656, 35, -1, 139,
- 140, 141, -1, -1, 3, 4, 44, 498, 27, 149,
- -1, -1, 31, 51, 41, 53, 35, -1, -1, 510,
- 511, -1, 513, -1, 51, 165, 53, 65, -1, 520,
- 690, -1, 51, 275, 53, 277, 278, 75, 65, -1,
- 3, 4, 41, -1, -1, -1, -1, 85, 75, -1,
- 88, 89, 51, -1, 53, 195, 83, 56, -1, 550,
- -1, 88, -1, -1, 306, -1, 65, -1, -1, -1,
- 312, -1, -1, 315, -1, -1, 75, 319, 41, -1,
- -1, -1, -1, -1, 83, -1, -1, -1, 51, 88,
- 53, 4, 5, 6, 7, -1, -1, -1, -1, 12,
- -1, -1, 65, -1, -1, -1, -1, -1, -1, 600,
- 601, 602, 75, -1, 27, -1, -1, 608, 31, -1,
- 83, -1, 35, 783, 784, 88, -1, -1, -1, -1,
- -1, 791, -1, 624, 625, -1, 627, -1, 51, -1,
- 53, -1, -1, 283, -1, 285, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, 815, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, 656, -1, -1, -1, -1,
- -1, -1, -1, 833, 834, 835, 836, -1, -1, -1,
- 840, 841, 842, 843, 675, -1, -1, -1, -1, -1,
- 432, -1, -1, -1, 685, 686, 687, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, 869,
- -1, -1, 872, -1, 874, -1, -1, -1, -1, 359,
- -1, 361, 362, -1, -1, -1, -1, 887, 888, 277,
- 278, 279, -1, 373, -1, 375, -1, 377, 378, -1,
- -1, -1, -1, -1, 384, -1, -1, -1, -1, -1,
- 390, -1, -1, 393, -1, -1, 498, -1, -1, -1,
- -1, -1, 4, -1, -1, -1, 508, -1, 510, 511,
- -1, -1, 412, -1, -1, 766, -1, 768, -1, -1,
- -1, -1, 24, 25, -1, -1, -1, -1, 779, 949,
- -1, 33, 783, 784, 785, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, 46, -1, -1, -1, -1, 551,
- -1, 359, -1, 361, 362, 363, -1, -1, -1, -1,
- 980, 981, 982, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, 994, 995, -1, 997, 4, 5,
- 6, 7, 833, 834, 835, 836, 12, -1, -1, 840,
- 841, 842, 843, -1, -1, -1, -1, -1, -1, 101,
- -1, 27, -1, 105, -1, 31, 1026, -1, -1, 35,
- -1, -1, -1, -1, -1, -1, -1, 119, 869, -1,
- 122, -1, -1, 523, -1, 51, -1, 53, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, 139, 140, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- 550, 66, 67, 68, 69, 70, 71, 72, 73, 74,
- 75, 76, 77, 78, 79, 916, 917, -1, 919, -1,
- -1, -1, -1, 675, -1, -1, -1, -1, 1098, -1,
- -1, 183, -1, 685, 686, 687, 937, 938, -1, -1,
- -1, 193, -1, -1, -1, -1, -1, -1, -1, -1,
- 600, 601, 602, 511, -1, 513, -1, -1, 608, -1,
- -1, -1, 520, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, 624, 625, -1, 627, -1, 980,
- -1, 982, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, 550, 994, 995, -1, 997, -1, -1, -1,
- -1, -1, -1, 1173, 1174, 1175, 656, -1, -1, -1,
- -1, -1, -1, -1, 766, -1, 768, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, 779, 65, 66,
- 67, 68, 69, 70, 71, 72, 73, 74, 75, 76,
- 77, 78, 79, 601, 602, -1, -1, 1217, 3, 4,
- 608, 6, 7, 8, 9, -1, 11, 12, -1, -1,
- 312, -1, -1, 315, -1, -1, -1, 319, -1, -1,
+ -1, -1, -1, 88, 89, -1, 1, 92, 3, 4,
+ -1, 6, 7, 8, 9, -1, 11, 12, 103, 104,
+ -1, -1, -1, -1, 19, -1, -1, -1, -1, -1,
-1, -1, 27, 28, 29, 30, 31, -1, 33, -1,
35, -1, 37, 38, -1, 40, 41, 42, 43, -1,
- -1, 46, 47, 48, 49, 50, 51, 1098, 53, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, 360, -1,
- -1, -1, -1, -1, -1, 367, -1, 675, -1, -1,
- 872, 373, -1, 375, -1, -1, 81, 82, 83, -1,
- -1, -1, -1, 88, -1, -1, -1, 92, 390, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, 104,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- 412, 413, -1, 415, 916, 917, -1, 919, -1, -1,
- -1, -1, 1173, 1174, 1175, -1, -1, -1, -1, -1,
- -1, -1, -1, 833, 834, 835, 836, -1, 838, -1,
- 840, 841, 842, 843, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, 766, -1,
- 768, -1, -1, -1, -1, -1, 1217, -1, -1, 869,
- -1, 779, -1, -1, -1, -1, 784, 785, -1, -1,
- -1, 3, 4, 5, 6, 7, -1, -1, 10, -1,
- 12, -1, 3, 4, 5, 6, 7, -1, -1, -1,
- -1, 12, -1, -1, -1, 27, -1, -1, -1, 31,
- -1, -1, -1, 35, -1, -1, 27, -1, -1, 41,
- 31, -1, -1, -1, 35, 833, 834, -1, 836, 51,
- 41, 53, 840, -1, 842, 843, -1, -1, -1, -1,
- 51, 941, 53, 65, -1, 56, -1, -1, -1, -1,
- -1, -1, -1, 75, 65, -1, -1, -1, -1, -1,
- -1, 83, -1, -1, 75, -1, 88, -1, -1, -1,
- -1, 93, 83, -1, -1, -1, -1, 88, -1, -1,
- 980, -1, 982, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, 994, 995, -1, 997, 600, 601,
- 59, -1, 61, 62, 63, 64, 65, 66, 67, 68,
- 69, 70, 71, 72, 73, 74, 75, 76, 77, 78,
- 79, -1, 624, 625, -1, 627, -1, -1, -1, 1,
- 938, 3, 4, 5, 6, 7, 8, 9, -1, 11,
- 12, 13, -1, 15, 16, 17, 18, 19, 20, 21,
- 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
- -1, 33, -1, 35, -1, 37, 38, -1, 40, 41,
- 42, 43, -1, -1, 46, 47, 48, 49, 50, 51,
- -1, 53, 54, -1, 56, -1, 994, 995, -1, 997,
- 62, -1, -1, 65, -1, -1, -1, -1, 1098, -1,
- -1, 73, 74, 75, -1, -1, -1, -1, -1, 81,
- 82, 83, -1, -1, -1, -1, 88, -1, 90, 1,
- 92, 3, 4, 5, 6, 7, 8, 9, 10, 11,
- 12, 103, 104, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, 27, 28, 29, 30, 31,
- -1, 33, -1, 35, -1, 37, 38, -1, 40, 41,
- 42, 43, 44, -1, 46, 47, 48, 49, 50, 51,
- -1, 53, 54, 1173, 1174, 1175, -1, -1, -1, -1,
- 62, -1, -1, 65, -1, -1, -1, -1, -1, -1,
- -1, 73, 74, 75, 10, -1, -1, -1, -1, 81,
- 82, 83, -1, 85, -1, -1, 88, 89, -1, -1,
- 92, 93, -1, -1, -1, -1, -1, 1217, -1, -1,
- -1, -1, 104, -1, -1, -1, -1, -1, -1, -1,
- -1, 833, 834, -1, -1, -1, -1, -1, 840, -1,
- -1, 57, 58, 59, 60, 61, 62, 63, 64, 65,
- 66, 67, 68, 69, 70, 71, 72, 73, 74, 75,
- 76, 77, 78, 79, -1, -1, -1, 869, -1, -1,
- 872, 1, 874, 3, 4, 5, 6, 7, 8, 9,
- -1, 11, 12, 13, -1, 15, 16, 17, 18, 19,
- 20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
- 30, 31, -1, 33, -1, 35, -1, 37, 38, -1,
- 40, 41, 42, 43, -1, -1, 46, 47, 48, 49,
- 50, 51, -1, 53, 54, -1, 56, -1, -1, -1,
- -1, -1, 62, -1, -1, 65, -1, -1, -1, -1,
- -1, -1, -1, 73, 74, 75, -1, 949, -1, -1,
- -1, 81, 82, 83, -1, -1, -1, -1, 88, -1,
- 90, -1, 92, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, 103, 104, -1, -1, -1, -1, 981,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, 994, 995, -1, 997, -1, -1, -1, -1,
+ -1, 46, 47, 48, 49, 50, 51, -1, 53, 54,
+ -1, -1, -1, -1, -1, -1, -1, 62, -1, -1,
+ 65, -1, -1, -1, -1, -1, -1, -1, 73, 74,
+ 75, -1, -1, -1, -1, -1, 81, 82, 83, -1,
+ -1, -1, -1, 88, -1, -1, 1, 92, 3, 4,
+ -1, 6, 7, 8, 9, -1, 11, 12, 103, 104,
+ -1, -1, -1, -1, 19, -1, -1, -1, -1, -1,
+ -1, -1, 27, 28, 29, 30, 31, -1, 33, -1,
+ 35, -1, 37, 38, -1, 40, 41, 42, 43, -1,
+ -1, 46, 47, 48, 49, 50, 51, -1, 53, 54,
+ -1, -1, -1, -1, -1, -1, -1, 62, -1, -1,
+ 65, -1, -1, -1, -1, -1, -1, -1, 73, 74,
+ 75, -1, -1, -1, -1, -1, 81, 82, 83, -1,
+ -1, -1, -1, 88, -1, -1, 1, 92, 3, 4,
+ 5, 6, 7, 8, 9, -1, 11, 12, 103, 104,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, 1, -1, 3, 4, 5, 6, 7, 8, 9,
- -1, 11, 12, 13, 1026, 15, 16, 17, 18, 19,
- 20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
- 30, 31, -1, 33, -1, 35, -1, 37, 38, -1,
- 40, 41, 42, 43, -1, -1, 46, 47, 48, 49,
- 50, 51, -1, 53, 54, -1, 56, -1, -1, -1,
- -1, -1, 62, -1, -1, 65, -1, -1, -1, -1,
- -1, -1, -1, 73, 74, 75, -1, -1, -1, -1,
- -1, 81, 82, 83, -1, -1, -1, -1, 88, -1,
- 90, -1, 92, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, 103, 104, 1, -1, 3, 4, 5,
- 6, 7, 8, 9, -1, 11, 12, 13, -1, 15,
- 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,
- 26, 27, 28, 29, 30, 31, -1, 33, -1, 35,
- -1, 37, 38, -1, 40, 41, 42, 43, -1, -1,
- 46, 47, 48, 49, 50, 51, -1, 53, 54, -1,
- 56, -1, -1, -1, -1, -1, 62, -1, -1, 65,
- -1, -1, -1, -1, -1, -1, -1, 73, 74, 75,
- -1, -1, -1, -1, -1, 81, 82, 83, -1, -1,
- -1, -1, 88, -1, 90, -1, 92, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, 103, 104, 1,
- -1, 3, 4, 5, 6, 7, 8, 9, -1, 11,
- 12, 13, -1, 15, 16, 17, 18, 19, 20, 21,
- 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
- -1, 33, -1, 35, -1, 37, 38, -1, 40, 41,
- 42, 43, -1, -1, 46, 47, 48, 49, 50, 51,
- -1, 53, 54, -1, 56, -1, -1, -1, -1, -1,
- 62, -1, -1, 65, -1, -1, -1, -1, -1, -1,
- -1, 73, 74, 75, -1, -1, -1, -1, -1, 81,
- 82, 83, -1, -1, -1, -1, 88, -1, 90, -1,
- 92, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, 103, 104, 1, -1, 3, 4, 5, 6, 7,
- 8, 9, -1, 11, 12, 13, -1, 15, 16, 17,
- 18, 19, 20, 21, 22, 23, 24, 25, 26, 27,
- 28, 29, 30, 31, -1, 33, -1, 35, -1, 37,
- 38, -1, 40, 41, 42, 43, -1, -1, 46, 47,
- 48, 49, 50, 51, -1, 53, 54, -1, 56, -1,
- -1, -1, -1, -1, 62, -1, -1, 65, -1, -1,
- -1, -1, -1, -1, -1, 73, 74, 75, -1, -1,
- -1, -1, -1, 81, 82, 83, -1, -1, -1, -1,
- 88, -1, 90, 1, 92, 3, 4, 5, 6, 7,
- 8, 9, -1, 11, 12, 13, 104, 15, 16, 17,
- 18, 19, 20, 21, 22, 23, 24, 25, 26, 27,
- 28, 29, 30, 31, -1, 33, -1, 35, -1, 37,
- 38, -1, 40, 41, 42, 43, -1, -1, 46, 47,
- 48, 49, 50, 51, -1, 53, 54, -1, 56, -1,
- -1, -1, -1, -1, 62, -1, -1, 65, -1, -1,
- -1, -1, -1, -1, -1, 73, 74, 75, -1, -1,
- -1, -1, -1, 81, 82, 83, -1, -1, -1, -1,
- 88, -1, 90, 1, 92, 3, 4, 5, 6, 7,
- 8, 9, -1, 11, 12, 13, 104, 15, 16, 17,
- 18, 19, 20, 21, 22, 23, 24, 25, 26, 27,
+ -1, -1, 27, 28, 29, 30, 31, -1, 33, -1,
+ 35, -1, 37, 38, -1, 40, 41, 42, 43, -1,
+ -1, 46, 47, 48, 49, 50, 51, -1, 53, 54,
+ -1, 56, -1, -1, -1, -1, -1, 62, -1, -1,
+ 65, -1, -1, -1, -1, -1, -1, -1, 73, 74,
+ 75, -1, -1, -1, -1, -1, 81, 82, 83, 1,
+ -1, -1, 4, 88, 6, 7, -1, 92, -1, -1,
+ 12, -1, -1, -1, -1, -1, -1, -1, -1, 104,
+ -1, -1, -1, -1, -1, 27, -1, -1, -1, 31,
+ -1, -1, -1, 35, -1, 37, 38, -1, -1, -1,
+ -1, -1, 44, -1, -1, -1, -1, -1, -1, 51,
+ -1, 53, -1, 55, -1, 57, 58, 59, -1, 61,
+ 62, 63, 64, 65, 66, 67, 68, 69, 70, 71,
+ 72, 73, 74, 75, 76, 77, 78, -1, -1, 81,
+ 82, 83, -1, 1, 86, 3, 4, 89, 6, 7,
+ 8, 9, -1, 11, 12, -1, -1, -1, -1, -1,
+ -1, -1, 104, -1, -1, -1, -1, -1, -1, 27,
28, 29, 30, 31, -1, 33, -1, 35, -1, 37,
38, -1, 40, 41, 42, 43, -1, -1, 46, 47,
- 48, 49, 50, 51, -1, 53, 54, -1, 56, -1,
+ 48, 49, 50, 51, -1, 53, 54, -1, -1, -1,
-1, -1, -1, -1, 62, -1, -1, 65, -1, -1,
-1, -1, -1, -1, -1, 73, 74, 75, -1, -1,
-1, -1, -1, 81, 82, 83, -1, -1, -1, -1,
- 88, -1, 90, 1, 92, 3, 4, 5, 6, 7,
- 8, 9, 10, 11, 12, -1, 104, -1, -1, -1,
+ 88, -1, -1, 1, 92, 3, 4, -1, 6, 7,
+ 8, 9, -1, 11, 12, -1, 104, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, 27,
28, 29, 30, 31, -1, 33, -1, 35, -1, 37,
- 38, -1, 40, 41, 42, 43, 44, -1, 46, 47,
- 48, 49, 50, 51, -1, 53, 54, -1, -1, -1,
- -1, -1, -1, -1, 62, -1, -1, 65, -1, -1,
- -1, -1, -1, -1, -1, 73, 74, 75, -1, -1,
- -1, -1, -1, 81, 82, 83, -1, 85, -1, -1,
- 88, 89, -1, -1, 92, 93, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, 1, 104, 3, 4, 5,
- 6, 7, 8, 9, 10, 11, 12, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, 27, 28, 29, 30, 31, -1, 33, -1, 35,
- -1, 37, 38, -1, 40, 41, 42, 43, -1, -1,
- 46, 47, 48, 49, 50, 51, -1, 53, -1, -1,
- -1, -1, -1, -1, -1, -1, 62, -1, -1, 65,
- -1, -1, -1, -1, -1, -1, -1, 73, 74, 75,
- -1, -1, -1, -1, -1, 81, 82, 83, -1, -1,
- -1, -1, 88, -1, -1, -1, 92, 93, -1, -1,
- -1, -1, -1, -1, -1, -1, 102, 1, 104, 3,
- 4, 5, 6, 7, 8, 9, 10, 11, 12, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, 27, 28, 29, 30, 31, -1, 33,
- -1, 35, -1, 37, 38, -1, 40, 41, 42, 43,
- -1, -1, 46, 47, 48, 49, 50, 51, -1, 53,
- -1, -1, -1, -1, -1, -1, -1, -1, 62, -1,
- -1, 65, -1, -1, -1, -1, -1, -1, -1, 73,
- 74, 75, -1, -1, -1, -1, -1, 81, 82, 83,
- -1, -1, -1, -1, 88, -1, -1, -1, 92, 93,
- -1, -1, -1, -1, -1, -1, -1, -1, 102, 1,
- 104, 3, 4, -1, 6, 7, 8, 9, -1, 11,
- 12, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, 27, 28, 29, 30, 31,
- -1, 33, -1, 35, -1, 37, 38, -1, 40, 41,
- 42, 43, -1, -1, 46, 47, 48, 49, 50, 51,
- -1, 53, 54, -1, -1, -1, -1, -1, -1, -1,
- 62, -1, -1, 65, -1, -1, -1, -1, -1, -1,
- -1, 73, 74, 75, -1, -1, -1, -1, -1, 81,
- 82, 83, -1, -1, -1, -1, 88, 89, -1, 1,
- 92, 3, 4, -1, 6, 7, 8, 9, -1, 11,
- 12, 103, 104, -1, -1, -1, -1, 19, -1, -1,
- -1, -1, -1, -1, -1, 27, 28, 29, 30, 31,
- -1, 33, -1, 35, -1, 37, 38, -1, 40, 41,
- 42, 43, -1, -1, 46, 47, 48, 49, 50, 51,
- -1, 53, 54, -1, -1, -1, -1, -1, -1, -1,
- 62, -1, -1, 65, -1, -1, -1, -1, -1, -1,
- -1, 73, 74, 75, -1, -1, -1, -1, -1, 81,
- 82, 83, -1, -1, -1, -1, 88, -1, -1, 1,
- 92, 3, 4, -1, 6, 7, 8, 9, -1, 11,
- 12, 103, 104, -1, -1, -1, -1, 19, -1, -1,
- -1, -1, -1, -1, -1, 27, 28, 29, 30, 31,
- -1, 33, -1, 35, -1, 37, 38, -1, 40, 41,
- 42, 43, -1, -1, 46, 47, 48, 49, 50, 51,
- -1, 53, 54, -1, -1, -1, -1, -1, -1, -1,
- 62, -1, -1, 65, -1, -1, -1, -1, -1, -1,
- -1, 73, 74, 75, -1, -1, -1, -1, -1, 81,
- 82, 83, -1, -1, -1, -1, 88, -1, -1, 1,
- 92, 3, 4, 5, 6, 7, 8, 9, -1, 11,
- 12, 103, 104, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, 27, 28, 29, 30, 31,
- -1, 33, -1, 35, -1, 37, 38, -1, 40, 41,
- 42, 43, -1, -1, 46, 47, 48, 49, 50, 51,
- -1, 53, 54, -1, 56, -1, -1, -1, -1, -1,
- 62, -1, -1, 65, -1, -1, -1, -1, -1, -1,
- -1, 73, 74, 75, -1, -1, -1, -1, -1, 81,
- 82, 83, -1, -1, -1, -1, 88, -1, -1, 1,
- 92, 3, 4, -1, 6, 7, 8, 9, -1, 11,
- 12, -1, 104, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, 27, 28, 29, 30, 31,
- -1, 33, -1, 35, -1, 37, 38, -1, 40, 41,
- 42, 43, -1, -1, 46, 47, 48, 49, 50, 51,
- -1, 53, 54, -1, -1, -1, -1, -1, -1, -1,
- 62, -1, -1, 65, -1, -1, -1, -1, -1, -1,
- -1, 73, 74, 75, -1, -1, -1, -1, -1, 81,
- 82, 83, -1, -1, -1, -1, 88, -1, -1, 1,
- 92, 3, 4, -1, 6, 7, 8, 9, -1, 11,
- 12, -1, 104, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, 27, 28, 29, 30, 31,
- -1, 33, -1, 35, -1, 37, 38, -1, 40, 41,
- 42, 43, -1, -1, 46, 47, 48, 49, 50, 51,
- -1, 53, 54, -1, -1, -1, -1, -1, -1, -1,
- 62, -1, -1, 65, -1, -1, -1, -1, -1, -1,
- -1, 73, 74, 75, -1, -1, -1, -1, -1, 81,
- 82, 83, -1, -1, -1, -1, 88, -1, -1, 1,
- 92, 3, 4, -1, 6, 7, 8, 9, -1, 11,
- 12, -1, 104, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, 27, 28, 29, 30, 31,
- -1, 33, -1, 35, -1, 37, 38, -1, 40, 41,
- 42, 43, -1, -1, 46, 47, 48, 49, 50, 51,
- -1, 53, -1, -1, -1, -1, -1, -1, 60, -1,
- 62, -1, -1, 65, -1, -1, -1, -1, -1, -1,
- -1, 73, 74, 75, -1, -1, -1, -1, -1, 81,
- 82, 83, -1, -1, -1, -1, 88, -1, -1, 1,
- 92, 3, 4, -1, 6, 7, 8, 9, -1, 11,
- 12, -1, 104, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, 27, 28, 29, 30, 31,
- -1, 33, -1, 35, -1, 37, 38, -1, 40, 41,
- 42, 43, -1, -1, 46, 47, 48, 49, 50, 51,
- -1, 53, 54, -1, -1, -1, -1, -1, -1, -1,
- 62, -1, -1, 65, -1, -1, -1, -1, -1, -1,
- -1, 73, 74, 75, -1, -1, -1, -1, -1, 81,
- 82, 83, -1, -1, -1, -1, 88, -1, -1, 1,
- 92, 3, 4, -1, 6, 7, 8, 9, -1, 11,
- 12, -1, 104, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, 27, 28, 29, 30, 31,
- -1, 33, -1, 35, -1, 37, 38, -1, 40, 41,
- 42, 43, -1, -1, 46, 47, 48, 49, 50, 51,
- -1, 53, -1, -1, 56, -1, -1, -1, -1, -1,
- 62, -1, -1, 65, -1, -1, -1, -1, -1, -1,
- -1, 73, 74, 75, -1, -1, -1, -1, -1, 81,
- 82, 83, -1, -1, -1, -1, 88, -1, -1, 1,
- 92, 3, 4, -1, 6, 7, 8, 9, -1, 11,
- 12, -1, 104, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, 27, 28, 29, 30, 31,
- -1, 33, -1, 35, -1, 37, 38, -1, 40, 41,
- 42, 43, -1, -1, 46, 47, 48, 49, 50, 51,
- -1, 53, -1, -1, -1, -1, -1, -1, -1, -1,
- 62, -1, -1, 65, -1, -1, -1, -1, -1, -1,
- -1, 73, 74, 75, -1, -1, -1, -1, -1, 81,
- 82, 83, -1, -1, -1, -1, 88, -1, -1, -1,
- 92, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- 102, 1, 104, 3, 4, -1, 6, 7, 8, 9,
- -1, 11, 12, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, 27, 28, 29,
- 30, 31, -1, 33, -1, 35, -1, 37, 38, -1,
- 40, 41, 42, 43, -1, -1, 46, 47, 48, 49,
- 50, 51, -1, 53, -1, -1, -1, -1, -1, -1,
- -1, -1, 62, -1, -1, 65, -1, -1, -1, -1,
- -1, -1, -1, 73, 74, 75, -1, -1, -1, -1,
- -1, 81, 82, 83, -1, -1, -1, -1, 88, -1,
- -1, 1, 92, 3, 4, -1, 6, 7, 8, 9,
- -1, 11, 12, -1, 104, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, 27, 28, 29,
- 30, 31, -1, 33, -1, 35, -1, 37, 38, -1,
- 40, 41, 42, 43, -1, -1, 46, 47, 48, 49,
- 50, 51, -1, 53, -1, -1, -1, -1, -1, -1,
- -1, -1, 62, -1, -1, 65, -1, -1, -1, -1,
- -1, -1, -1, 73, 74, 75, -1, -1, -1, -1,
- -1, 81, 82, 83, -1, -1, -1, -1, 88, -1,
- 3, 4, 92, 6, 7, 8, 9, -1, 11, 12,
- -1, -1, -1, -1, 104, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, 27, 28, 29, 30, 31, -1,
- 33, -1, 35, -1, 37, 38, -1, 40, 41, 42,
- 43, -1, -1, 46, 47, 48, 49, 50, 51, -1,
- 53, -1, -1, -1, -1, -1, -1, -1, -1, 62,
- -1, -1, 65, -1, -1, -1, -1, -1, -1, -1,
- 73, 74, 75, -1, -1, -1, -1, -1, 81, 82,
- 83, -1, -1, -1, -1, 88, -1, -1, -1, 92,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, 104, 105, 3, 4, 5, 6, 7, 8, 9,
- -1, 11, 12, 13, -1, 15, 16, 17, 18, 19,
- 20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
- 30, 31, -1, 33, -1, 35, -1, 37, 38, -1,
- 40, 41, 42, 43, -1, -1, 46, 47, 48, 49,
- 50, 51, -1, 53, 54, -1, 56, -1, -1, -1,
- -1, -1, 62, -1, -1, 65, -1, -1, -1, -1,
- -1, -1, -1, 73, 74, 75, -1, -1, -1, -1,
- -1, 81, 82, 83, -1, -1, -1, -1, 88, -1,
- 90, -1, 92, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, 103, 104, 3, 4, 5, 6, 7,
- 8, 9, -1, 11, 12, 13, -1, 15, 16, 17,
- 18, 19, 20, 21, 22, 23, 24, 25, 26, 27,
- 28, 29, 30, 31, -1, 33, -1, 35, -1, 37,
38, -1, 40, 41, 42, 43, -1, -1, 46, 47,
- 48, 49, 50, 51, -1, 53, 54, -1, 56, -1,
+ 48, 49, 50, 51, -1, 53, 54, -1, -1, -1,
-1, -1, -1, -1, 62, -1, -1, 65, -1, -1,
-1, -1, -1, -1, -1, 73, 74, 75, -1, -1,
-1, -1, -1, 81, 82, 83, -1, -1, -1, -1,
- 88, -1, 90, -1, 92, 3, 4, 5, 6, 7,
- 8, 9, -1, 11, 12, 13, 104, 15, 16, 17,
- 18, 19, 20, 21, 22, 23, 24, 25, 26, 27,
+ 88, -1, -1, 1, 92, 3, 4, -1, 6, 7,
+ 8, 9, -1, 11, 12, -1, 104, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, 27,
28, 29, 30, 31, -1, 33, -1, 35, -1, 37,
38, -1, 40, 41, 42, 43, -1, -1, 46, 47,
- 48, 49, 50, 51, -1, 53, 54, -1, 56, -1,
+ 48, 49, 50, 51, -1, 53, 54, -1, -1, -1,
-1, -1, -1, -1, 62, -1, -1, 65, -1, -1,
-1, -1, -1, -1, -1, 73, 74, 75, -1, -1,
-1, -1, -1, 81, 82, 83, -1, -1, -1, -1,
- 88, -1, 90, -1, 92, 3, 4, 5, 6, 7,
- 8, 9, -1, 11, 12, 13, 104, 15, 16, 17,
- 18, 19, 20, 21, 22, 23, 24, 25, 26, 27,
+ 88, -1, -1, 1, 92, 3, 4, -1, 6, 7,
+ 8, 9, -1, 11, 12, -1, 104, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, 27,
28, 29, 30, 31, -1, 33, -1, 35, -1, 37,
38, -1, 40, 41, 42, 43, -1, -1, 46, 47,
48, 49, 50, 51, -1, 53, -1, -1, 56, -1,
-1, -1, -1, -1, 62, -1, -1, 65, -1, -1,
-1, -1, -1, -1, -1, 73, 74, 75, -1, -1,
-1, -1, -1, 81, 82, 83, -1, -1, -1, -1,
- 88, -1, 90, -1, 92, 3, 4, 5, 6, 7,
- 8, 9, 10, 11, 12, -1, 104, -1, -1, -1,
+ 88, -1, -1, 1, 92, 3, 4, -1, 6, 7,
+ 8, 9, -1, 11, 12, -1, 104, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, 27,
28, 29, 30, 31, -1, 33, -1, 35, -1, 37,
- 38, -1, 40, 41, 42, 43, 44, -1, 46, 47,
+ 38, -1, 40, 41, 42, 43, -1, -1, 46, 47,
48, 49, 50, 51, -1, 53, -1, -1, -1, -1,
-1, -1, -1, -1, 62, -1, -1, 65, -1, -1,
-1, -1, -1, -1, -1, 73, 74, 75, -1, -1,
- -1, -1, -1, 81, 82, 83, -1, 85, -1, -1,
- 88, 89, -1, -1, 92, 93, 3, 4, 5, 6,
- 7, 8, 9, 10, 11, 12, 104, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- 27, 28, 29, 30, 31, -1, 33, -1, 35, -1,
- 37, 38, -1, 40, 41, 42, 43, 44, -1, 46,
- 47, 48, 49, 50, 51, -1, 53, -1, -1, -1,
- -1, -1, -1, -1, -1, 62, -1, -1, 65, -1,
- -1, -1, -1, -1, -1, -1, 73, 74, 75, -1,
- -1, -1, -1, -1, 81, 82, 83, -1, 85, -1,
- -1, 88, 89, -1, -1, 92, 93, 3, 4, -1,
- 6, 7, 8, 9, -1, 11, 12, 104, -1, -1,
+ -1, -1, -1, 81, 82, 83, -1, -1, -1, -1,
+ 88, -1, -1, -1, 92, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, 102, 1, 104, 3, 4, -1,
+ 6, 7, 8, 9, -1, 11, 12, 67, 68, 69,
+ 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
+ -1, 27, 28, 29, 30, 31, -1, 33, -1, 35,
+ -1, 37, 38, -1, 40, 41, 42, 43, -1, -1,
+ 46, 47, 48, 49, 50, 51, -1, 53, -1, -1,
+ -1, -1, -1, -1, -1, -1, 62, -1, -1, 65,
+ -1, -1, -1, -1, -1, -1, -1, 73, 74, 75,
+ -1, -1, -1, -1, -1, 81, 82, 83, -1, -1,
+ -1, -1, 88, -1, -1, 1, 92, 3, 4, -1,
+ 6, 7, 8, 9, -1, 11, 12, -1, 104, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, 27, 28, 29, 30, 31, -1, 33, -1, 35,
- -1, 37, 38, -1, 40, 41, 42, 43, 44, -1,
+ -1, 37, 38, -1, 40, 41, 42, 43, -1, -1,
46, 47, 48, 49, 50, 51, -1, 53, -1, -1,
-1, -1, -1, -1, -1, -1, 62, -1, -1, 65,
-1, -1, -1, -1, -1, -1, -1, 73, 74, 75,
- -1, -1, -1, -1, -1, 81, 82, 83, -1, 85,
- -1, -1, 88, 89, 3, 4, -1, 6, 7, 8,
+ -1, -1, -1, -1, -1, 81, 82, 83, -1, -1,
+ -1, -1, 88, -1, 3, 4, 92, 6, 7, 8,
9, -1, 11, 12, -1, -1, -1, -1, 104, -1,
-1, -1, -1, -1, -1, -1, -1, -1, 27, 28,
29, 30, 31, -1, 33, -1, 35, -1, 37, 38,
- -1, 40, 41, 42, 43, 44, -1, 46, 47, 48,
+ -1, 40, 41, 42, 43, -1, -1, 46, 47, 48,
49, 50, 51, -1, 53, -1, -1, -1, -1, -1,
-1, -1, -1, 62, -1, -1, 65, -1, -1, -1,
-1, -1, -1, -1, 73, 74, 75, -1, -1, -1,
- -1, -1, 81, 82, 83, -1, 85, -1, -1, 88,
- 89, 3, 4, -1, 6, 7, 8, 9, -1, 11,
- 12, -1, -1, -1, -1, 104, -1, -1, -1, -1,
+ -1, -1, 81, 82, 83, -1, -1, -1, -1, 88,
+ -1, -1, -1, 92, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, 104, 105, 3, 4, 5,
+ 6, 7, 8, 9, -1, 11, 12, 13, -1, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,
+ 26, 27, 28, 29, 30, 31, -1, 33, -1, 35,
+ -1, 37, 38, -1, 40, 41, 42, 43, -1, -1,
+ 46, 47, 48, 49, 50, 51, -1, 53, 54, -1,
+ 56, -1, -1, -1, -1, -1, 62, -1, -1, 65,
+ -1, -1, -1, -1, -1, -1, -1, 73, 74, 75,
+ -1, -1, -1, -1, -1, 81, 82, 83, -1, -1,
+ -1, -1, 88, -1, 90, -1, 92, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, 103, 104, 3,
+ 4, 5, 6, 7, 8, 9, -1, 11, 12, 13,
+ -1, 15, 16, 17, 18, 19, 20, 21, 22, 23,
+ 24, 25, 26, 27, 28, 29, 30, 31, -1, 33,
+ -1, 35, -1, 37, 38, -1, 40, 41, 42, 43,
+ -1, -1, 46, 47, 48, 49, 50, 51, -1, 53,
+ 54, -1, 56, -1, -1, -1, -1, -1, 62, -1,
+ -1, 65, -1, -1, -1, -1, -1, -1, -1, 73,
+ 74, 75, -1, -1, -1, -1, -1, 81, 82, 83,
+ -1, -1, -1, -1, 88, -1, 90, -1, 92, 3,
+ 4, 5, 6, 7, 8, 9, -1, 11, 12, 13,
+ 104, 15, 16, 17, 18, 19, 20, 21, 22, 23,
+ 24, 25, 26, 27, 28, 29, 30, 31, -1, 33,
+ -1, 35, -1, 37, 38, -1, 40, 41, 42, 43,
+ -1, -1, 46, 47, 48, 49, 50, 51, -1, 53,
+ 54, -1, 56, -1, -1, -1, -1, -1, 62, -1,
+ -1, 65, -1, -1, -1, -1, -1, -1, -1, 73,
+ 74, 75, -1, -1, -1, -1, -1, 81, 82, 83,
+ -1, -1, -1, -1, 88, -1, 90, -1, 92, 3,
+ 4, 5, 6, 7, 8, 9, -1, 11, 12, 13,
+ 104, 15, 16, 17, 18, 19, 20, 21, 22, 23,
+ 24, 25, 26, 27, 28, 29, 30, 31, -1, 33,
+ -1, 35, -1, 37, 38, -1, 40, 41, 42, 43,
+ -1, -1, 46, 47, 48, 49, 50, 51, -1, 53,
+ -1, -1, 56, -1, -1, -1, -1, -1, 62, -1,
+ -1, 65, -1, -1, -1, -1, -1, -1, -1, 73,
+ 74, 75, -1, -1, -1, -1, -1, 81, 82, 83,
+ -1, -1, -1, -1, 88, -1, 90, -1, 92, 3,
+ 4, 5, 6, 7, 8, 9, 10, 11, 12, -1,
+ 104, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, 27, 28, 29, 30, 31, -1, 33,
+ -1, 35, -1, 37, 38, -1, 40, 41, 42, 43,
+ 44, -1, 46, 47, 48, 49, 50, 51, -1, 53,
+ -1, -1, -1, -1, -1, -1, -1, -1, 62, -1,
+ -1, 65, -1, -1, -1, -1, -1, -1, -1, 73,
+ 74, 75, -1, -1, -1, -1, -1, 81, 82, 83,
+ -1, 85, -1, -1, 88, 89, -1, -1, 92, 93,
+ 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
+ 104, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, 27, 28, 29, 30, 31, -1,
+ 33, -1, 35, -1, 37, 38, -1, 40, 41, 42,
+ 43, 44, -1, 46, 47, 48, 49, 50, 51, -1,
+ 53, -1, -1, -1, -1, -1, -1, -1, -1, 62,
+ -1, -1, 65, -1, -1, -1, -1, -1, -1, -1,
+ 73, 74, 75, -1, -1, -1, -1, -1, 81, 82,
+ 83, -1, 85, -1, -1, 88, 89, -1, -1, 92,
+ 93, 3, 4, -1, 6, 7, 8, 9, -1, 11,
+ 12, 104, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, 27, 28, 29, 30, 31,
-1, 33, -1, 35, -1, 37, 38, -1, 40, 41,
42, 43, 44, -1, 46, 47, 48, 49, 50, 51,
@@ -3006,44 +2952,27 @@ static const short yycheck[] = { 4,
-1, 6, 7, 8, 9, -1, 11, 12, -1, -1,
-1, -1, 104, -1, -1, -1, -1, -1, -1, -1,
-1, -1, 27, 28, 29, 30, 31, -1, 33, -1,
- 35, -1, 37, 38, -1, 40, 41, 42, 43, -1,
+ 35, -1, 37, 38, -1, 40, 41, 42, 43, 44,
-1, 46, 47, 48, 49, 50, 51, -1, 53, -1,
- -1, 56, -1, -1, -1, -1, -1, 62, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, 62, -1, -1,
65, -1, -1, -1, -1, -1, -1, -1, 73, 74,
75, -1, -1, -1, -1, -1, 81, 82, 83, -1,
- -1, -1, -1, 88, -1, 3, 4, 92, 6, 7,
+ 85, -1, -1, 88, 89, 3, 4, -1, 6, 7,
8, 9, -1, 11, 12, -1, -1, -1, -1, 104,
-1, -1, -1, -1, -1, -1, -1, -1, -1, 27,
28, 29, 30, 31, -1, 33, -1, 35, -1, 37,
- 38, -1, 40, 41, 42, 43, -1, -1, 46, 47,
- 48, 49, 50, 51, -1, 53, -1, -1, -1, -1,
- -1, -1, -1, -1, 62, -1, -1, 65, -1, -1,
- -1, -1, -1, -1, -1, 73, 74, 75, -1, -1,
- -1, -1, -1, 81, 82, 83, -1, -1, -1, -1,
- 88, -1, 3, 4, 92, 6, 7, 8, 9, -1,
- 11, 12, -1, -1, -1, -1, 104, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, 27, 28, 29, 30,
- 31, -1, 33, -1, 35, -1, 37, 38, -1, 40,
- 41, 42, 43, -1, -1, 46, 47, 48, 49, 50,
- 51, -1, 53, 54, -1, -1, -1, -1, -1, -1,
- -1, 62, -1, -1, 65, -1, -1, -1, -1, -1,
- -1, -1, 73, 74, 75, -1, -1, -1, -1, -1,
- 81, 82, 83, -1, -1, 3, 4, 88, 6, 7,
- 8, 9, -1, 11, 12, -1, -1, -1, -1, -1,
- -1, -1, -1, 104, -1, -1, -1, -1, -1, 27,
- 28, 29, 30, 31, -1, 33, -1, 35, -1, 37,
- 38, -1, 40, 41, 42, 43, -1, -1, 46, 47,
+ 38, -1, 40, 41, 42, 43, 44, -1, 46, 47,
48, 49, 50, 51, -1, 53, -1, -1, -1, -1,
-1, -1, -1, -1, 62, -1, -1, 65, -1, -1,
-1, -1, -1, -1, -1, 73, 74, 75, -1, -1,
- -1, -1, -1, 81, 82, 83, -1, -1, -1, -1,
+ -1, -1, -1, 81, 82, 83, -1, 85, -1, -1,
88, 89, 3, 4, -1, 6, 7, 8, 9, -1,
11, 12, -1, -1, -1, -1, 104, -1, -1, -1,
-1, -1, -1, -1, -1, -1, 27, 28, 29, 30,
31, -1, 33, -1, 35, -1, 37, 38, -1, 40,
41, 42, 43, -1, -1, 46, 47, 48, 49, 50,
51, -1, 53, -1, -1, -1, -1, -1, -1, -1,
- -1, 62, -1, -1, 65, -1, -1, -1, -1, -1,
+ -1, 62, -1, -1, 65, -1, -1, -1, -1, 70,
-1, -1, 73, 74, 75, -1, -1, -1, -1, -1,
81, 82, 83, -1, -1, -1, -1, 88, -1, 3,
4, 92, 6, 7, 8, 9, -1, 11, 12, -1,
@@ -3051,7 +2980,7 @@ static const short yycheck[] = { 4,
-1, -1, -1, 27, 28, 29, 30, 31, -1, 33,
-1, 35, -1, 37, 38, -1, 40, 41, 42, 43,
-1, -1, 46, 47, 48, 49, 50, 51, -1, 53,
- -1, -1, -1, -1, -1, -1, -1, -1, 62, -1,
+ -1, -1, 56, -1, -1, -1, -1, -1, 62, -1,
-1, 65, -1, -1, -1, -1, -1, -1, -1, 73,
74, 75, -1, -1, -1, -1, -1, 81, 82, 83,
-1, -1, -1, -1, 88, -1, 3, 4, 92, 6,
@@ -3068,6 +2997,23 @@ static const short yycheck[] = { 4,
-1, -1, -1, -1, -1, -1, -1, 27, 28, 29,
30, 31, -1, 33, -1, 35, -1, 37, 38, -1,
40, 41, 42, 43, -1, -1, 46, 47, 48, 49,
+ 50, 51, -1, 53, 54, -1, -1, -1, -1, -1,
+ -1, -1, 62, -1, -1, 65, -1, -1, -1, -1,
+ -1, -1, -1, 73, 74, 75, -1, -1, -1, -1,
+ -1, 81, 82, 83, -1, -1, 3, 4, 88, 6,
+ 7, 8, 9, -1, 11, 12, -1, -1, -1, -1,
+ -1, -1, -1, -1, 104, -1, -1, -1, -1, -1,
+ 27, 28, 29, 30, 31, -1, 33, -1, 35, -1,
+ 37, 38, -1, 40, 41, 42, 43, -1, -1, 46,
+ 47, 48, 49, 50, 51, -1, 53, -1, -1, -1,
+ -1, -1, -1, -1, -1, 62, -1, -1, 65, -1,
+ -1, -1, -1, -1, -1, -1, 73, 74, 75, -1,
+ -1, -1, -1, -1, 81, 82, 83, -1, -1, -1,
+ -1, 88, 89, 3, 4, -1, 6, 7, 8, 9,
+ -1, 11, 12, -1, -1, -1, -1, 104, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, 27, 28, 29,
+ 30, 31, -1, 33, -1, 35, -1, 37, 38, -1,
+ 40, 41, 42, 43, -1, -1, 46, 47, 48, 49,
50, 51, -1, 53, -1, -1, -1, -1, -1, -1,
-1, -1, 62, -1, -1, 65, -1, -1, -1, -1,
-1, -1, -1, 73, 74, 75, -1, -1, -1, -1,
@@ -3089,72 +3035,116 @@ static const short yycheck[] = { 4,
-1, -1, -1, -1, -1, -1, 62, -1, -1, 65,
-1, -1, -1, -1, -1, -1, -1, 73, 74, 75,
-1, -1, -1, -1, -1, 81, 82, 83, -1, -1,
+ -1, -1, 88, -1, 3, 4, 92, 6, 7, 8,
+ 9, -1, 11, 12, -1, -1, -1, -1, 104, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, 27, 28,
+ 29, 30, 31, -1, 33, -1, 35, -1, 37, 38,
+ -1, 40, 41, 42, 43, -1, -1, 46, 47, 48,
+ 49, 50, 51, -1, 53, -1, -1, -1, -1, -1,
+ -1, -1, -1, 62, -1, -1, 65, -1, -1, -1,
+ -1, -1, -1, -1, 73, 74, 75, -1, -1, -1,
+ -1, -1, 81, 82, 83, -1, -1, -1, -1, 88,
+ -1, 3, 4, 92, 6, 7, 8, 9, -1, 11,
+ 12, -1, -1, -1, -1, 104, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, 27, 28, 29, 30, 31,
+ -1, 33, -1, 35, -1, 37, 38, -1, 40, 41,
+ 42, 43, -1, -1, 46, 47, 48, 49, 50, 51,
+ -1, 53, -1, -1, -1, -1, -1, -1, -1, -1,
+ 62, -1, -1, 65, -1, -1, -1, -1, -1, -1,
+ -1, 73, 74, 75, -1, -1, -1, -1, -1, 81,
+ 82, 83, -1, -1, -1, -1, 88, -1, 3, 4,
+ 92, 6, 7, 8, 9, -1, 11, 12, -1, -1,
+ -1, -1, 104, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, 27, 28, 29, 30, 31, -1, 33, -1,
+ 35, -1, 37, 38, -1, 40, 41, 42, 43, -1,
+ -1, 46, 47, 48, 49, 50, 51, -1, 53, -1,
+ -1, -1, -1, -1, -1, -1, -1, 62, -1, -1,
+ 65, -1, -1, -1, -1, -1, -1, -1, 73, 74,
+ 75, -1, -1, -1, -1, -1, 81, 82, 83, -1,
+ -1, 3, 4, 88, 6, 7, 8, 9, -1, 11,
+ 12, -1, -1, -1, -1, -1, -1, -1, -1, 104,
+ -1, -1, -1, -1, -1, 27, 28, 29, 30, 31,
+ -1, 33, -1, 35, -1, 37, 38, -1, 40, 41,
+ 42, 43, -1, -1, 46, 47, 48, 49, 50, 51,
+ -1, 53, -1, -1, -1, -1, -1, -1, -1, -1,
+ 62, -1, -1, 65, -1, -1, -1, -1, -1, -1,
+ -1, 73, 74, 75, -1, -1, -1, -1, -1, 81,
+ 82, 83, -1, -1, 3, 4, 88, 6, 7, 8,
+ 9, -1, 11, 12, -1, -1, -1, -1, -1, -1,
+ -1, -1, 104, -1, -1, -1, -1, -1, 27, 28,
+ 29, 30, 31, -1, 33, -1, 35, -1, 37, 38,
+ -1, 40, 41, 42, 43, -1, -1, 46, 47, 48,
+ 49, 50, 51, -1, 53, -1, -1, -1, -1, -1,
+ -1, -1, -1, 62, -1, -1, 65, -1, -1, -1,
+ -1, -1, -1, -1, 73, 74, 75, -1, -1, -1,
+ -1, -1, 81, 82, 83, -1, -1, 3, 4, 88,
+ 6, 7, 8, 9, -1, 11, 12, -1, -1, -1,
+ -1, -1, -1, -1, -1, 104, -1, -1, -1, -1,
+ -1, 27, 28, -1, -1, 31, -1, 33, -1, 35,
+ -1, 37, 38, -1, 40, 41, 42, 43, -1, -1,
+ 46, 47, 48, 49, 50, 51, -1, 53, -1, -1,
+ -1, -1, -1, -1, -1, -1, 62, -1, -1, 65,
+ -1, -1, -1, -1, -1, -1, -1, 73, 74, 75,
+ -1, -1, -1, -1, -1, 81, 82, 83, -1, -1,
3, 4, 88, 6, 7, 8, 9, -1, 11, 12,
-1, -1, -1, -1, -1, -1, -1, -1, 104, -1,
-1, -1, -1, -1, 27, 28, 29, 30, 31, -1,
33, -1, 35, -1, 37, 38, -1, 40, 41, 42,
43, -1, -1, 46, 47, 48, 49, 50, 51, -1,
- 53, -1, -1, -1, -1, -1, -1, -1, -1, 62,
- -1, -1, 65, -1, -1, -1, -1, -1, -1, -1,
- 73, 74, 75, -1, -1, -1, -1, -1, 81, 82,
- 83, -1, -1, 3, 4, 88, 6, 7, 8, 9,
- -1, 11, 12, -1, -1, -1, -1, -1, -1, -1,
- -1, 104, -1, -1, -1, -1, -1, 27, 28, 29,
- 30, 31, -1, 33, -1, 35, -1, 37, 38, -1,
- 40, 41, 42, 43, -1, -1, 46, 47, 48, 49,
- 50, 51, -1, 53, -1, -1, -1, -1, -1, -1,
- -1, -1, 62, -1, -1, 65, -1, -1, -1, -1,
- -1, -1, -1, 73, 74, 75, -1, -1, -1, -1,
- -1, 81, 82, 83, -1, -1, 3, 4, 88, 6,
- 7, 8, 9, -1, 11, 12, -1, -1, -1, -1,
- -1, -1, -1, -1, 104, -1, -1, -1, -1, -1,
- 27, 28, -1, -1, 31, -1, 33, -1, 35, -1,
- 37, 38, -1, 40, 41, 42, 43, -1, -1, 46,
- 47, 48, 49, 50, 51, -1, 53, -1, -1, -1,
- -1, -1, -1, -1, -1, 62, -1, -1, 65, -1,
- -1, -1, -1, -1, -1, -1, 73, 74, 75, -1,
- -1, -1, -1, -1, 81, 82, 83, -1, -1, -1,
- -1, 88, 3, 4, 5, 6, 7, -1, -1, 10,
- -1, 12, -1, -1, -1, -1, -1, 104, -1, 3,
- 4, 5, 6, 7, -1, -1, 27, -1, 12, -1,
- 31, -1, -1, -1, 35, -1, -1, -1, -1, -1,
- 41, -1, -1, 27, -1, -1, -1, 31, -1, -1,
- 51, 35, 53, -1, -1, -1, -1, 41, -1, -1,
- -1, -1, -1, -1, 65, -1, -1, 51, -1, 53,
- -1, -1, -1, -1, 75, -1, 60, -1, -1, -1,
- -1, 65, 83, -1, -1, -1, -1, 88, -1, -1,
- -1, 75, 3, 4, 5, 6, 7, -1, -1, 83,
- -1, 12, -1, -1, 88, -1, -1, -1, -1, 3,
- 4, 5, 6, 7, -1, -1, 27, -1, 12, -1,
- 31, -1, -1, -1, 35, -1, -1, -1, -1, -1,
- 41, -1, -1, 27, -1, -1, -1, 31, -1, -1,
- 51, 35, 53, -1, -1, 56, -1, 41, -1, -1,
- -1, -1, -1, -1, 65, -1, -1, 51, -1, 53,
- -1, -1, -1, -1, 75, -1, -1, -1, -1, -1,
- -1, 65, 83, -1, -1, -1, -1, 88, -1, -1,
- -1, 75, -1, -1, -1, -1, -1, -1, -1, 83,
- 32, 57, 58, 59, 88, 61, 62, 63, 64, 65,
- 66, 67, 68, 69, 70, 71, 72, 73, 74, 75,
- 76, 77, 78, 79, -1, 57, 58, 59, -1, 61,
- 62, 63, 64, 65, 66, 67, 68, 69, 70, 71,
- 72, 73, 74, 75, 76, 77, 78, 79, 55, 105,
- 57, 58, 59, -1, 61, 62, 63, 64, 65, 66,
+ 53, -1, 3, 4, 5, 6, 7, -1, -1, -1,
+ -1, 12, -1, -1, -1, -1, -1, 3, 4, 5,
+ 6, 7, -1, -1, -1, -1, 12, -1, 81, 82,
+ 83, -1, -1, -1, 35, 88, -1, -1, -1, 92,
+ 41, 27, -1, 44, -1, 31, -1, -1, -1, 35,
+ 51, 104, 53, -1, -1, 41, -1, -1, -1, -1,
+ -1, -1, -1, -1, 65, 51, -1, 53, -1, -1,
+ 56, -1, -1, -1, 75, -1, -1, -1, -1, 65,
+ -1, -1, 83, -1, 85, -1, -1, 88, 89, 75,
+ -1, 3, 4, 5, 6, 7, -1, 83, 10, -1,
+ 12, -1, 88, -1, -1, -1, -1, -1, 3, 4,
+ 5, 6, 7, -1, -1, 27, -1, 12, -1, 31,
+ -1, -1, -1, 35, -1, -1, -1, -1, -1, 41,
+ -1, -1, 27, -1, -1, -1, 31, -1, -1, 51,
+ 35, 53, -1, -1, -1, -1, 41, -1, -1, -1,
+ -1, -1, -1, 65, -1, -1, 51, -1, 53, -1,
+ -1, -1, -1, 75, -1, 60, -1, -1, -1, -1,
+ 65, 83, -1, -1, -1, -1, 88, -1, -1, -1,
+ 75, 3, 4, 5, 6, 7, -1, -1, 83, -1,
+ 12, -1, -1, 88, -1, -1, -1, -1, 3, 4,
+ 5, 6, 7, -1, -1, 27, -1, 12, -1, 31,
+ -1, -1, -1, 35, -1, -1, -1, -1, -1, 41,
+ -1, -1, 27, -1, -1, -1, 31, -1, -1, 51,
+ 35, 53, -1, -1, 56, -1, 41, -1, -1, -1,
+ -1, -1, 4, 65, 6, 7, 51, -1, 53, -1,
+ 12, -1, -1, 75, -1, -1, -1, -1, -1, -1,
+ 65, 83, -1, -1, -1, 27, 88, -1, -1, 31,
+ 75, -1, -1, 35, -1, -1, -1, -1, 83, -1,
+ -1, -1, 44, 88, -1, -1, -1, -1, -1, 51,
+ -1, 53, -1, -1, -1, -1, -1, -1, -1, -1,
+ 57, 58, 59, 65, 61, 62, 63, 64, 65, 66,
+ 67, 68, 69, 75, 71, 72, 73, 74, 75, 76,
+ 77, 78, 79, 85, -1, -1, 88, 89, 57, 58,
+ 59, -1, 61, 62, 63, 64, 65, 66, 67, 68,
+ 69, 70, 71, 72, 73, 74, 75, 76, 77, 78,
+ 79, 55, 32, 57, 58, 59, -1, 61, 62, 63,
+ 64, 65, 66, 67, 68, 69, 70, 71, 72, 73,
+ 74, 75, 76, 77, 78, 79, 105, 57, 58, 59,
+ -1, 61, 62, 63, 64, 65, 66, 67, 68, 69,
+ 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
+ 57, 58, 59, 60, 61, 62, 63, 64, 65, 66,
67, 68, 69, 70, 71, 72, 73, 74, 75, 76,
77, 78, 79, 57, 58, 59, 60, 61, 62, 63,
64, 65, 66, 67, 68, 69, 70, 71, 72, 73,
- 74, 75, 76, 77, 78, 79, 57, 58, 59, 60,
+ 74, 75, 76, 77, 78, 79, 57, 58, 59, -1,
61, 62, 63, 64, 65, 66, 67, 68, 69, 70,
- 71, 72, 73, 74, 75, 76, 77, 78, 79, 57,
- 58, 59, -1, 61, 62, 63, 64, 65, 66, 67,
- 68, 69, 70, 71, 72, 73, 74, 75, 76, 77,
- 78, 79, 57, 58, 59, -1, 61, 62, 63, 64,
- 65, 66, 67, 68, 69, -1, 71, 72, 73, 74,
- 75, 76, 77, 78, 79, 62, 63, 64, 65, 66,
- 67, 68, 69, 70, 71, 72, 73, 74, 75, 76,
- 77, 78, 79, 63, 64, 65, 66, 67, 68, 69,
+ 71, 72, 73, 74, 75, 76, 77, 78, 79, 59,
+ -1, 61, 62, 63, 64, 65, 66, 67, 68, 69,
70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
- 64, 65, 66, 67, 68, 69, 70, 71, 72, 73,
- 74, 75, 76, 77, 78, 79
+ 62, 63, 64, 65, 66, 67, 68, 69, 70, 71,
+ 72, 73, 74, 75, 76, 77, 78, 79, 64, 65,
+ 66, 67, 68, 69, 70, 71, 72, 73, 74, 75,
+ 76, 77, 78, 79, 65, 66, 67, 68, 69, 70,
+ 71, 72, 73, 74, 75, 76, 77, 78, 79
};
/* -*-C-*- Note some compilers choke on comments on `#line' lines. */
#line 3 "/usr/local/lib/bison.simple"
@@ -3339,23 +3329,8 @@ __yy_bcopy (char *from, char *to, int count)
#endif
#line 184 "/usr/local/lib/bison.simple"
-
-/* The user can define YYPARSE_PARAM as the name of an argument to be passed
- into yyparse. The argument should have type void *.
- It should actually point to an object.
- Grammar actions can access the variable by casting it
- to the proper pointer type. */
-
-#ifdef YYPARSE_PARAM
-#define YYPARSE_PARAM_DECL void *YYPARSE_PARAM;
-#else
-#define YYPARSE_PARAM
-#define YYPARSE_PARAM_DECL
-#endif
-
int
-yyparse(YYPARSE_PARAM)
- YYPARSE_PARAM_DECL
+yyparse()
{
register int yystate;
register int yyn;
@@ -3637,7 +3612,7 @@ yyreduce:
switch (yyn) {
case 2:
-#line 293 "parse.y"
+#line 294 "parse.y"
{
/* In case there were missing closebraces,
get us back to the global binding level. */
@@ -3647,138 +3622,140 @@ case 2:
;
break;}
case 3:
-#line 307 "parse.y"
+#line 308 "parse.y"
{ yyval.ttype = NULL_TREE; ;
break;}
case 4:
-#line 308 "parse.y"
+#line 309 "parse.y"
{ yyval.ttype = NULL_TREE; ;
break;}
case 5:
-#line 310 "parse.y"
+#line 311 "parse.y"
{ yyval.ttype = NULL_TREE; ;
break;}
case 6:
-#line 314 "parse.y"
+#line 315 "parse.y"
{ have_extern_spec = 1;
used_extern_spec = 0;
yyval.ttype = NULL_TREE; ;
break;}
case 7:
-#line 319 "parse.y"
+#line 320 "parse.y"
{ have_extern_spec = 0; ;
break;}
case 10:
-#line 328 "parse.y"
+#line 329 "parse.y"
{ if (pending_lang_change) do_pending_lang_change(); ;
break;}
case 11:
-#line 330 "parse.y"
+#line 331 "parse.y"
{ if (! global_bindings_p () && ! pseudo_global_level_p())
pop_everything (); ;
break;}
case 12:
-#line 336 "parse.y"
+#line 337 "parse.y"
{ if (pending_inlines) do_pending_inlines (); ;
break;}
case 13:
-#line 338 "parse.y"
+#line 339 "parse.y"
{ if (pending_inlines) do_pending_inlines (); ;
break;}
case 14:
-#line 340 "parse.y"
+#line 341 "parse.y"
{ if (pending_inlines) do_pending_inlines (); ;
break;}
case 16:
-#line 343 "parse.y"
+#line 344 "parse.y"
{ if (TREE_CHAIN (yyvsp[-2].ttype)) yyvsp[-2].ttype = combine_strings (yyvsp[-2].ttype);
assemble_asm (yyvsp[-2].ttype); ;
break;}
case 17:
-#line 346 "parse.y"
+#line 347 "parse.y"
{ pop_lang_context (); ;
break;}
case 18:
-#line 348 "parse.y"
+#line 349 "parse.y"
{ pop_lang_context (); ;
break;}
case 19:
-#line 350 "parse.y"
+#line 351 "parse.y"
{ if (pending_inlines) do_pending_inlines ();
pop_lang_context (); ;
break;}
case 20:
-#line 353 "parse.y"
+#line 354 "parse.y"
{ if (pending_inlines) do_pending_inlines ();
pop_lang_context (); ;
break;}
case 21:
-#line 359 "parse.y"
+#line 360 "parse.y"
{ push_lang_context (yyvsp[0].ttype); ;
break;}
case 22:
-#line 364 "parse.y"
+#line 365 "parse.y"
{ begin_template_parm_list (); ;
break;}
case 23:
-#line 366 "parse.y"
+#line 367 "parse.y"
{ yyval.ttype = end_template_parm_list (yyvsp[-1].ttype); ;
break;}
case 24:
-#line 371 "parse.y"
+#line 372 "parse.y"
{ yyval.ttype = process_template_parm (NULL_TREE, yyvsp[0].ttype); ;
break;}
case 25:
-#line 373 "parse.y"
+#line 374 "parse.y"
{ yyval.ttype = process_template_parm (yyvsp[-2].ttype, yyvsp[0].ttype); ;
break;}
case 26:
-#line 385 "parse.y"
+#line 379 "parse.y"
{
- if (yyvsp[-1].ttype == signature_type_node)
- sorry ("signature as template type parameter");
- else if (yyvsp[-1].ttype != class_type_node)
- error ("template type parameter must use keyword `class'");
yyval.ttype = build_tree_list (yyvsp[0].ttype, NULL_TREE);
+ ttpa:
+ if (TREE_PURPOSE (yyval.ttype) == signature_type_node)
+ sorry ("signature as template type parameter");
+ else if (TREE_PURPOSE (yyval.ttype) != class_type_node)
+ pedwarn ("template type parameters must use the keyword `class'");
;
break;}
case 27:
-#line 393 "parse.y"
-{
- if (yyvsp[-3].ttype == signature_type_node)
- sorry ("signature as template type parameter");
- else if (yyvsp[-3].ttype != class_type_node)
- error ("template type parameter must use keyword `class'");
- warning ("restricted template type parameters not yet implemented");
- yyval.ttype = build_tree_list (yyvsp[-2].ttype, yyvsp[0].ttype);
- ;
+#line 388 "parse.y"
+{ yyval.ttype = build_tree_list (yyvsp[-1].ttype, yyvsp[0].ttype); goto ttpa; ;
break;}
-case 29:
-#line 406 "parse.y"
-{ warning ("use of `overload' is an anachronism"); ;
+case 28:
+#line 400 "parse.y"
+{ yyval.ttype = build_tree_list (NULL_TREE, yyval.ttype); ;
break;}
-case 30:
-#line 410 "parse.y"
-{ declare_overloaded (yyvsp[0].ttype); ;
+case 29:
+#line 402 "parse.y"
+{ yyval.ttype = build_tree_list (yyvsp[0].ttype, yyval.ttype); ;
break;}
case 31:
+#line 408 "parse.y"
+{ warning ("use of `overload' is an anachronism"); ;
+ break;}
+case 32:
#line 412 "parse.y"
{ declare_overloaded (yyvsp[0].ttype); ;
break;}
-case 32:
-#line 419 "parse.y"
-{ yychar = '{'; goto template1; ;
+case 33:
+#line 414 "parse.y"
+{ declare_overloaded (yyvsp[0].ttype); ;
break;}
case 34:
-#line 422 "parse.y"
+#line 421 "parse.y"
{ yychar = '{'; goto template1; ;
break;}
case 36:
-#line 425 "parse.y"
-{ yychar = ':'; goto template1; ;
+#line 424 "parse.y"
+{ yychar = '{'; goto template1; ;
break;}
case 38:
-#line 428 "parse.y"
+#line 427 "parse.y"
+{ yychar = ':'; goto template1; ;
+ break;}
+case 40:
+#line 430 "parse.y"
{
yychar = ':';
template1:
@@ -3793,22 +3770,22 @@ case 38:
yychar = YYEMPTY;
;
break;}
-case 40:
-#line 443 "parse.y"
+case 42:
+#line 445 "parse.y"
{
end_template_decl (yyvsp[-2].ttype, yyvsp[-1].ttype, current_aggr, 0);
/* declare $2 as template name with $1 parm list */
;
break;}
-case 41:
-#line 448 "parse.y"
+case 43:
+#line 450 "parse.y"
{
end_template_decl (yyvsp[-2].ttype, yyvsp[-1].ttype, current_aggr, 0);
/* declare $2 as template name with $1 parm list */
;
break;}
-case 42:
-#line 455 "parse.y"
+case 44:
+#line 457 "parse.y"
{
tree d;
int momentary;
@@ -3824,8 +3801,8 @@ case 42:
resume_momentary (momentary);
;
break;}
-case 43:
-#line 472 "parse.y"
+case 45:
+#line 474 "parse.y"
{
tree d;
int momentary;
@@ -3847,8 +3824,8 @@ case 43:
resume_momentary (momentary);
;
break;}
-case 44:
-#line 493 "parse.y"
+case 46:
+#line 495 "parse.y"
{
int def = (yyvsp[0].itype != ';');
tree d = start_decl (yyvsp[-1].ttype, yyvsp[-2].ttype, 0, NULL_TREE);
@@ -3858,69 +3835,69 @@ case 44:
reinit_parse_for_template ((int) yyvsp[0].itype, yyvsp[-3].ttype, d);
;
break;}
-case 45:
-#line 502 "parse.y"
-{ end_template_decl (yyvsp[-2].ttype, 0, 0, 0); ;
- break;}
-case 46:
-#line 503 "parse.y"
-{ end_template_decl (yyvsp[-2].ttype, 0, 0, 0); ;
- break;}
case 47:
-#line 506 "parse.y"
-{ yyval.itype = '{'; ;
+#line 504 "parse.y"
+{ end_template_decl (yyvsp[-2].ttype, 0, 0, 0); ;
break;}
case 48:
-#line 507 "parse.y"
-{ yyval.itype = ':'; ;
+#line 505 "parse.y"
+{ end_template_decl (yyvsp[-2].ttype, 0, 0, 0); ;
break;}
case 49:
#line 508 "parse.y"
-{ yyval.itype = ';'; ;
+{ yyval.itype = '{'; ;
break;}
case 50:
#line 509 "parse.y"
-{ yyval.itype = '='; ;
+{ yyval.itype = ':'; ;
break;}
case 51:
#line 510 "parse.y"
-{ yyval.itype = RETURN; ;
+{ yyval.itype = ';'; ;
break;}
case 52:
-#line 515 "parse.y"
-{;
+#line 511 "parse.y"
+{ yyval.itype = '='; ;
break;}
case 53:
+#line 512 "parse.y"
+{ yyval.itype = RETURN; ;
+ break;}
+case 54:
#line 517 "parse.y"
{;
break;}
-case 54:
-#line 520 "parse.y"
+case 55:
+#line 519 "parse.y"
+{;
+ break;}
+case 56:
+#line 522 "parse.y"
{ tree d;
d = start_decl (yyvsp[-1].ttype, yyval.ttype, 0, NULL_TREE);
finish_decl (d, NULL_TREE, NULL_TREE, 0);
;
break;}
-case 55:
-#line 525 "parse.y"
+case 57:
+#line 527 "parse.y"
{
note_list_got_semicolon (yyval.ttype);
;
break;}
-case 56:
-#line 530 "parse.y"
+case 58:
+#line 532 "parse.y"
{ tree d;
d = start_decl (yyvsp[-1].ttype, yyval.ttype, 0, NULL_TREE);
finish_decl (d, NULL_TREE, NULL_TREE, 0);
note_list_got_semicolon (yyval.ttype);
;
break;}
-case 57:
-#line 536 "parse.y"
+case 59:
+#line 538 "parse.y"
{ pedwarn ("empty declaration"); ;
break;}
-case 59:
-#line 539 "parse.y"
+case 61:
+#line 541 "parse.y"
{
tree t = yyval.ttype;
shadow_tag (t);
@@ -3940,8 +3917,8 @@ case 59:
note_list_got_semicolon (yyval.ttype);
;
break;}
-case 63:
-#line 564 "parse.y"
+case 65:
+#line 566 "parse.y"
{
finish_function (lineno, 1);
/* finish_function performs these three statements:
@@ -3955,8 +3932,8 @@ case 63:
if (yyval.ttype) process_next_inline (yyval.ttype);
;
break;}
-case 64:
-#line 577 "parse.y"
+case 66:
+#line 579 "parse.y"
{
finish_function (lineno, 1);
/* finish_function performs these three statements:
@@ -3970,61 +3947,61 @@ case 64:
if (yyval.ttype) process_next_inline (yyval.ttype);
;
break;}
-case 65:
-#line 590 "parse.y"
+case 67:
+#line 592 "parse.y"
{ finish_function (lineno, 0);
if (yyval.ttype) process_next_inline (yyval.ttype); ;
break;}
-case 66:
-#line 593 "parse.y"
+case 68:
+#line 595 "parse.y"
{ finish_function (lineno, 0);
if (yyval.ttype) process_next_inline (yyval.ttype); ;
break;}
-case 67:
-#line 596 "parse.y"
+case 69:
+#line 598 "parse.y"
{ finish_function (lineno, 0);
if (yyval.ttype) process_next_inline (yyval.ttype); ;
break;}
-case 68:
-#line 599 "parse.y"
-{;
- break;}
-case 69:
+case 70:
#line 601 "parse.y"
{;
break;}
-case 70:
+case 71:
#line 603 "parse.y"
{;
break;}
-case 71:
-#line 608 "parse.y"
+case 72:
+#line 605 "parse.y"
+{;
+ break;}
+case 73:
+#line 610 "parse.y"
{ if (! start_function (yyval.ttype, yyvsp[-1].ttype, yyvsp[0].ttype, 0))
YYERROR1;
reinit_parse_for_function ();
yyval.ttype = NULL_TREE; ;
break;}
-case 72:
-#line 613 "parse.y"
+case 74:
+#line 615 "parse.y"
{ if (! start_function (yyval.ttype, yyvsp[-1].ttype, yyvsp[0].ttype, 0))
YYERROR1;
reinit_parse_for_function ();
yyval.ttype = NULL_TREE; ;
break;}
-case 73:
-#line 618 "parse.y"
+case 75:
+#line 620 "parse.y"
{ if (! start_function (NULL_TREE, yyval.ttype, yyvsp[0].ttype, 0))
YYERROR1;
reinit_parse_for_function ();
yyval.ttype = NULL_TREE; ;
break;}
-case 74:
-#line 623 "parse.y"
+case 76:
+#line 625 "parse.y"
{ start_function (NULL_TREE, TREE_VALUE (yyval.ttype), NULL_TREE, 1);
reinit_parse_for_function (); ;
break;}
-case 75:
-#line 631 "parse.y"
+case 77:
+#line 633 "parse.y"
{
yyval.ttype = build_parse_node (CALL_EXPR, TREE_VALUE (yyvsp[-5].ttype), yyvsp[-3].ttype, yyvsp[-1].ttype);
yyval.ttype = start_method (TREE_CHAIN (yyvsp[-5].ttype), yyval.ttype, yyvsp[0].ttype);
@@ -4035,8 +4012,8 @@ case 75:
yychar = YYLEX;
reinit_parse_for_method (yychar, yyval.ttype); ;
break;}
-case 76:
-#line 641 "parse.y"
+case 78:
+#line 643 "parse.y"
{
yyval.ttype = build_parse_node (CALL_EXPR, TREE_VALUE (yyvsp[-3].ttype),
empty_parms (), yyvsp[-1].ttype);
@@ -4044,44 +4021,44 @@ case 76:
goto rest_of_mdef;
;
break;}
-case 77:
-#line 648 "parse.y"
-{ yyval.ttype = start_method (yyval.ttype, yyvsp[-1].ttype, yyvsp[0].ttype); goto rest_of_mdef; ;
- break;}
-case 78:
+case 79:
#line 650 "parse.y"
{ yyval.ttype = start_method (yyval.ttype, yyvsp[-1].ttype, yyvsp[0].ttype); goto rest_of_mdef; ;
break;}
-case 79:
+case 80:
#line 652 "parse.y"
+{ yyval.ttype = start_method (yyval.ttype, yyvsp[-1].ttype, yyvsp[0].ttype); goto rest_of_mdef; ;
+ break;}
+case 81:
+#line 654 "parse.y"
{ yyval.ttype = start_method (NULL_TREE, yyval.ttype, yyvsp[0].ttype); goto rest_of_mdef; ;
break;}
-case 80:
-#line 656 "parse.y"
+case 82:
+#line 658 "parse.y"
{
if (! current_function_parms_stored)
store_parm_decls ();
yyval.ttype = yyvsp[0].ttype;
;
break;}
-case 81:
-#line 664 "parse.y"
+case 83:
+#line 666 "parse.y"
{ store_return_init (yyval.ttype, NULL_TREE); ;
break;}
-case 82:
-#line 666 "parse.y"
+case 84:
+#line 668 "parse.y"
{ store_return_init (yyval.ttype, yyvsp[0].ttype); ;
break;}
-case 83:
-#line 668 "parse.y"
+case 85:
+#line 670 "parse.y"
{ store_return_init (yyval.ttype, yyvsp[-1].ttype); ;
break;}
-case 84:
-#line 670 "parse.y"
+case 86:
+#line 672 "parse.y"
{ store_return_init (yyval.ttype, NULL_TREE); ;
break;}
-case 85:
-#line 675 "parse.y"
+case 87:
+#line 677 "parse.y"
{
if (yyvsp[0].itype == 0)
error ("no base initializers given following ':'");
@@ -4092,8 +4069,8 @@ case 85:
keep_next_level ();
;
break;}
-case 86:
-#line 688 "parse.y"
+case 88:
+#line 690 "parse.y"
{
if (! current_function_parms_stored)
store_parm_decls ();
@@ -4114,104 +4091,108 @@ case 86:
error ("only constructors take base initializers");
;
break;}
-case 87:
-#line 711 "parse.y"
+case 89:
+#line 713 "parse.y"
{ yyval.itype = 0; ;
break;}
-case 88:
-#line 713 "parse.y"
+case 90:
+#line 715 "parse.y"
{ yyval.itype = 1; ;
break;}
-case 91:
-#line 719 "parse.y"
+case 93:
+#line 721 "parse.y"
{
if (current_class_name && !flag_traditional)
pedwarn ("anachronistic old style base class initializer");
expand_member_init (C_C_D, NULL_TREE, yyvsp[-1].ttype);
;
break;}
-case 92:
-#line 725 "parse.y"
+case 94:
+#line 727 "parse.y"
{
if (current_class_name && !flag_traditional)
pedwarn ("anachronistic old style base class initializer");
expand_member_init (C_C_D, NULL_TREE, void_type_node);
;
break;}
-case 93:
-#line 731 "parse.y"
+case 95:
+#line 733 "parse.y"
{ expand_member_init (C_C_D, yyval.ttype, yyvsp[-1].ttype); ;
break;}
-case 94:
-#line 733 "parse.y"
+case 96:
+#line 735 "parse.y"
{ expand_member_init (C_C_D, yyval.ttype, void_type_node); ;
break;}
-case 95:
-#line 735 "parse.y"
+case 97:
+#line 737 "parse.y"
{ expand_member_init (C_C_D, yyval.ttype, yyvsp[-1].ttype); ;
break;}
-case 96:
-#line 737 "parse.y"
+case 98:
+#line 739 "parse.y"
{ expand_member_init (C_C_D, yyval.ttype, void_type_node); ;
break;}
-case 97:
-#line 740 "parse.y"
+case 99:
+#line 742 "parse.y"
{
do_member_init (OP0 (yyvsp[-3].ttype), OP1 (yyvsp[-3].ttype), yyvsp[-1].ttype);
;
break;}
-case 98:
-#line 744 "parse.y"
+case 100:
+#line 746 "parse.y"
{
do_member_init (OP0 (yyvsp[-1].ttype), OP1 (yyvsp[-1].ttype), void_type_node);
;
break;}
-case 107:
-#line 768 "parse.y"
+case 109:
+#line 770 "parse.y"
{ do_type_instantiation (yyvsp[0].ttype ? yyvsp[0].ttype : yyvsp[-1].ttype, NULL_TREE); ;
break;}
-case 108:
-#line 770 "parse.y"
+case 110:
+#line 772 "parse.y"
{ do_function_instantiation (yyvsp[-1].ttype, yyvsp[0].ttype, NULL_TREE); ;
break;}
-case 109:
-#line 772 "parse.y"
+case 111:
+#line 774 "parse.y"
{ do_type_instantiation (yyvsp[0].ttype ? yyvsp[0].ttype : yyvsp[-1].ttype, yyvsp[-3].ttype); ;
break;}
-case 110:
-#line 774 "parse.y"
+case 112:
+#line 776 "parse.y"
{ do_function_instantiation (yyvsp[-1].ttype, yyvsp[0].ttype, yyvsp[-3].ttype); ;
break;}
-case 111:
-#line 779 "parse.y"
+case 113:
+#line 781 "parse.y"
{ if (yyvsp[0].ttype) yyval.ttype = yyvsp[0].ttype; ;
break;}
-case 112:
-#line 784 "parse.y"
+case 114:
+#line 786 "parse.y"
{ yyval.ttype = lookup_template_class (yyval.ttype, yyvsp[-1].ttype, NULL_TREE); ;
break;}
-case 113:
-#line 786 "parse.y"
+case 115:
+#line 788 "parse.y"
+{ yyval.ttype = lookup_template_class (yyval.ttype, NULL_TREE, NULL_TREE); ;
+ break;}
+case 116:
+#line 790 "parse.y"
{ yyval.ttype = lookup_template_class (yyval.ttype, yyvsp[-1].ttype, NULL_TREE); ;
break;}
-case 114:
-#line 791 "parse.y"
+case 117:
+#line 795 "parse.y"
{ yyval.ttype = instantiate_class_template (yyvsp[0].ttype, 1); ;
break;}
-case 115:
-#line 796 "parse.y"
+case 118:
+#line 800 "parse.y"
{ yyval.ttype = build_tree_list (NULL_TREE, yyval.ttype); ;
break;}
-case 116:
-#line 798 "parse.y"
+case 119:
+#line 802 "parse.y"
{ yyval.ttype = chainon (yyval.ttype, build_tree_list (NULL_TREE, yyvsp[0].ttype)); ;
break;}
-case 117:
-#line 803 "parse.y"
+case 120:
+#line 807 "parse.y"
{ yyval.ttype = groktypename (yyval.ttype); ;
break;}
-case 119:
-#line 809 "parse.y"
+case 122:
+#line 813 "parse.y"
{
tree t, decl, tmpl;
@@ -4245,8 +4226,8 @@ case 119:
TYPE_BEING_DEFINED (t) = 0;
;
break;}
-case 120:
-#line 842 "parse.y"
+case 123:
+#line 846 "parse.y"
{
tree t = finish_struct (yyvsp[-3].ttype, yyvsp[-1].ttype, 0);
@@ -4261,76 +4242,83 @@ case 120:
CLASSTYPE_GOT_SEMICOLON (t) = 1;
;
break;}
-case 121:
-#line 859 "parse.y"
+case 124:
+#line 863 "parse.y"
{ yyval.ttype = NULL_TREE; ;
break;}
-case 122:
-#line 861 "parse.y"
+case 125:
+#line 865 "parse.y"
{ yyval.ttype = yyvsp[0].ttype; ;
break;}
-case 123:
-#line 866 "parse.y"
+case 126:
+#line 870 "parse.y"
{ yyval.ttype = NULL_TREE; /* never used from here... */;
break;}
-case 124:
-#line 868 "parse.y"
+case 127:
+#line 872 "parse.y"
{ yyval.ttype = yyvsp[-1].ttype; /*???*/ ;
break;}
-case 125:
-#line 872 "parse.y"
+case 128:
+#line 876 "parse.y"
{ yyval.code = NEGATE_EXPR; ;
break;}
-case 126:
-#line 874 "parse.y"
+case 129:
+#line 878 "parse.y"
{ yyval.code = CONVERT_EXPR; ;
break;}
-case 127:
-#line 876 "parse.y"
+case 130:
+#line 880 "parse.y"
{ yyval.code = PREINCREMENT_EXPR; ;
break;}
-case 128:
-#line 878 "parse.y"
+case 131:
+#line 882 "parse.y"
{ yyval.code = PREDECREMENT_EXPR; ;
break;}
-case 129:
-#line 880 "parse.y"
+case 132:
+#line 884 "parse.y"
{ yyval.code = TRUTH_NOT_EXPR; ;
break;}
-case 130:
-#line 884 "parse.y"
+case 133:
+#line 888 "parse.y"
{ yyval.ttype = build_x_compound_expr (yyval.ttype); ;
break;}
-case 132:
-#line 890 "parse.y"
+case 135:
+#line 894 "parse.y"
{ error ("ANSI C++ forbids an empty condition for `%s'",
cond_stmt_keyword);
yyval.ttype = integer_zero_node; ;
break;}
-case 133:
-#line 894 "parse.y"
-{ yyval.ttype = yyvsp[-1].ttype; ;
+case 136:
+#line 898 "parse.y"
+{ yyval.ttype = build1 (CLEANUP_POINT_EXPR, bool_type_node,
+ bool_truthvalue_conversion (yyvsp[-1].ttype)); ;
break;}
-case 134:
-#line 899 "parse.y"
+case 137:
+#line 904 "parse.y"
{ error ("ANSI C++ forbids an empty condition for `%s'",
cond_stmt_keyword);
yyval.ttype = integer_zero_node; ;
break;}
-case 135:
-#line 903 "parse.y"
-{ yyval.ttype = yyvsp[-1].ttype; ;
- break;}
-case 136:
+case 138:
#line 908 "parse.y"
-{ yyval.ttype = NULL_TREE; ;
+{ yyval.ttype = build1 (CLEANUP_POINT_EXPR, bool_type_node,
+ bool_truthvalue_conversion (yyvsp[-1].ttype)); ;
break;}
-case 138:
-#line 911 "parse.y"
+case 139:
+#line 914 "parse.y"
{ yyval.ttype = NULL_TREE; ;
break;}
-case 139:
+case 140:
#line 916 "parse.y"
+{ yyval.ttype = build1 (CLEANUP_POINT_EXPR, bool_type_node,
+ bool_truthvalue_conversion (yyval.ttype)); ;
+ break;}
+case 141:
+#line 919 "parse.y"
+{ yyval.ttype = NULL_TREE; ;
+ break;}
+case 142:
+#line 924 "parse.y"
{ {
tree d;
for (d = getdecls (); d; d = TREE_CHAIN (d))
@@ -4348,52 +4336,52 @@ case 139:
cplus_decl_attributes (yyval.ttype, yyvsp[-1].ttype);
;
break;}
-case 140:
-#line 933 "parse.y"
-{
+case 143:
+#line 941 "parse.y"
+{
finish_decl (yyvsp[-1].ttype, yyvsp[0].ttype, yyvsp[-3].ttype, 0);
resume_momentary (yyvsp[-2].itype);
- yyval.ttype = yyvsp[-1].ttype;
+ yyval.ttype = yyvsp[-1].ttype;
if (TREE_CODE (TREE_TYPE (yyval.ttype)) == ARRAY_TYPE)
- cp_error ("definition of array `%#D' in condition", yyval.ttype);
+ cp_error ("definition of array `%#D' in condition", yyval.ttype);
;
break;}
-case 142:
-#line 945 "parse.y"
+case 145:
+#line 953 "parse.y"
{ finish_stmt (); ;
break;}
-case 143:
-#line 947 "parse.y"
+case 146:
+#line 955 "parse.y"
{ finish_stmt (); ;
break;}
-case 144:
-#line 949 "parse.y"
+case 147:
+#line 957 "parse.y"
{ finish_stmt (); ;
break;}
-case 146:
-#line 956 "parse.y"
-{ yyval.ttype = tree_cons (NULL_TREE, yyval.ttype,
+case 149:
+#line 964 "parse.y"
+{ yyval.ttype = tree_cons (NULL_TREE, yyval.ttype,
build_tree_list (NULL_TREE, yyvsp[0].ttype)); ;
break;}
-case 147:
-#line 959 "parse.y"
-{ yyval.ttype = tree_cons (NULL_TREE, yyval.ttype,
+case 150:
+#line 967 "parse.y"
+{ yyval.ttype = tree_cons (NULL_TREE, yyval.ttype,
build_tree_list (NULL_TREE, error_mark_node)); ;
break;}
-case 148:
-#line 962 "parse.y"
+case 151:
+#line 970 "parse.y"
{ chainon (yyval.ttype, build_tree_list (NULL_TREE, yyvsp[0].ttype)); ;
break;}
-case 149:
-#line 964 "parse.y"
+case 152:
+#line 972 "parse.y"
{ chainon (yyval.ttype, build_tree_list (NULL_TREE, error_mark_node)); ;
break;}
-case 150:
-#line 969 "parse.y"
+case 153:
+#line 977 "parse.y"
{ yyval.ttype = build_tree_list (NULL_TREE, yyval.ttype); ;
break;}
-case 152:
-#line 975 "parse.y"
+case 155:
+#line 983 "parse.y"
{
#if 0
if (TREE_CODE (yyval.ttype) == TYPE_EXPR)
@@ -4401,38 +4389,38 @@ case 152:
#endif
;
break;}
-case 153:
-#line 983 "parse.y"
+case 156:
+#line 991 "parse.y"
{ yyvsp[0].itype = pedantic;
pedantic = 0; ;
break;}
-case 154:
-#line 986 "parse.y"
+case 157:
+#line 994 "parse.y"
{ yyval.ttype = yyvsp[0].ttype;
pedantic = yyvsp[-2].itype; ;
break;}
-case 155:
-#line 989 "parse.y"
+case 158:
+#line 997 "parse.y"
{ yyval.ttype = build_x_indirect_ref (yyvsp[0].ttype, "unary *"); ;
break;}
-case 156:
-#line 991 "parse.y"
+case 159:
+#line 999 "parse.y"
{ yyval.ttype = build_x_unary_op (ADDR_EXPR, yyvsp[0].ttype); ;
break;}
-case 157:
-#line 993 "parse.y"
+case 160:
+#line 1001 "parse.y"
{ yyval.ttype = build_x_unary_op (BIT_NOT_EXPR, yyvsp[0].ttype); ;
break;}
-case 158:
-#line 995 "parse.y"
+case 161:
+#line 1003 "parse.y"
{ yyval.ttype = build_x_unary_op (yyvsp[-1].code, yyvsp[0].ttype);
if (yyvsp[-1].code == NEGATE_EXPR && TREE_CODE (yyvsp[0].ttype) == INTEGER_CST)
TREE_NEGATED_INT (yyval.ttype) = 1;
overflow_warning (yyval.ttype);
;
break;}
-case 159:
-#line 1002 "parse.y"
+case 162:
+#line 1010 "parse.y"
{ tree label = lookup_label (yyvsp[0].ttype);
if (label == NULL_TREE)
yyval.ttype = null_pointer_node;
@@ -4444,8 +4432,8 @@ case 159:
}
;
break;}
-case 160:
-#line 1013 "parse.y"
+case 163:
+#line 1021 "parse.y"
{ if (TREE_CODE (yyvsp[0].ttype) == COMPONENT_REF
&& DECL_BIT_FIELD (TREE_OPERAND (yyvsp[0].ttype, 1)))
error ("sizeof applied to a bit-field");
@@ -4466,123 +4454,123 @@ case 160:
}
yyval.ttype = c_sizeof (TREE_TYPE (yyvsp[0].ttype)); ;
break;}
-case 161:
-#line 1033 "parse.y"
+case 164:
+#line 1041 "parse.y"
{ yyval.ttype = c_sizeof (groktypename (yyvsp[-1].ttype)); ;
break;}
-case 162:
-#line 1035 "parse.y"
+case 165:
+#line 1043 "parse.y"
{ yyval.ttype = grok_alignof (yyvsp[0].ttype); ;
break;}
-case 163:
-#line 1037 "parse.y"
+case 166:
+#line 1045 "parse.y"
{ yyval.ttype = c_alignof (groktypename (yyvsp[-1].ttype)); ;
break;}
-case 164:
-#line 1042 "parse.y"
+case 167:
+#line 1050 "parse.y"
{ yyval.ttype = build_new (NULL_TREE, yyvsp[0].ttype, NULL_TREE, yyvsp[-1].itype); ;
break;}
-case 165:
-#line 1044 "parse.y"
+case 168:
+#line 1052 "parse.y"
{ yyval.ttype = build_new (NULL_TREE, yyvsp[-1].ttype, yyvsp[0].ttype, yyvsp[-2].itype); ;
break;}
-case 166:
-#line 1046 "parse.y"
+case 169:
+#line 1054 "parse.y"
{ yyval.ttype = build_new (yyvsp[-1].ttype, yyvsp[0].ttype, NULL_TREE, yyvsp[-2].itype); ;
break;}
-case 167:
-#line 1048 "parse.y"
+case 170:
+#line 1056 "parse.y"
{ yyval.ttype = build_new (yyvsp[-2].ttype, yyvsp[-1].ttype, yyvsp[0].ttype, yyvsp[-3].itype); ;
break;}
-case 168:
-#line 1050 "parse.y"
+case 171:
+#line 1058 "parse.y"
{ yyval.ttype = build_new (NULL_TREE, groktypename(yyvsp[-1].ttype),
NULL_TREE, yyvsp[-3].itype); ;
break;}
-case 169:
-#line 1053 "parse.y"
+case 172:
+#line 1061 "parse.y"
{ yyval.ttype = build_new (NULL_TREE, groktypename(yyvsp[-2].ttype), yyvsp[0].ttype, yyvsp[-4].itype); ;
break;}
-case 170:
-#line 1055 "parse.y"
+case 173:
+#line 1063 "parse.y"
{ yyval.ttype = build_new (yyvsp[-3].ttype, groktypename(yyvsp[-1].ttype), NULL_TREE, yyvsp[-4].itype); ;
break;}
-case 171:
-#line 1057 "parse.y"
+case 174:
+#line 1065 "parse.y"
{ yyval.ttype = build_new (yyvsp[-4].ttype, groktypename(yyvsp[-2].ttype), yyvsp[0].ttype, yyvsp[-5].itype); ;
break;}
-case 172:
-#line 1060 "parse.y"
+case 175:
+#line 1068 "parse.y"
{ yyval.ttype = delete_sanity (yyvsp[0].ttype, NULL_TREE, 0, yyvsp[-1].itype); ;
break;}
-case 173:
-#line 1062 "parse.y"
+case 176:
+#line 1070 "parse.y"
{ yyval.ttype = delete_sanity (yyvsp[0].ttype, NULL_TREE, 1, yyvsp[-3].itype);
if (yychar == YYEMPTY)
yychar = YYLEX; ;
break;}
-case 174:
-#line 1066 "parse.y"
+case 177:
+#line 1074 "parse.y"
{ yyval.ttype = delete_sanity (yyvsp[0].ttype, yyvsp[-2].ttype, 2, yyvsp[-4].itype);
if (yychar == YYEMPTY)
yychar = YYLEX; ;
break;}
-case 175:
-#line 1073 "parse.y"
+case 178:
+#line 1081 "parse.y"
{ yyval.ttype = yyvsp[-1].ttype; ;
break;}
-case 176:
-#line 1075 "parse.y"
+case 179:
+#line 1083 "parse.y"
{
- yyval.ttype = yyvsp[-1].ttype;
+ yyval.ttype = yyvsp[-1].ttype;
pedwarn ("old style placement syntax, use () instead");
;
break;}
-case 177:
-#line 1083 "parse.y"
+case 180:
+#line 1091 "parse.y"
{ yyval.ttype = yyvsp[-1].ttype; ;
break;}
-case 178:
-#line 1085 "parse.y"
+case 181:
+#line 1093 "parse.y"
{ yyval.ttype = NULL_TREE; ;
break;}
-case 179:
-#line 1087 "parse.y"
+case 182:
+#line 1095 "parse.y"
{
cp_error ("`%T' is not a valid expression", yyvsp[-1].ttype);
yyval.ttype = error_mark_node;
;
break;}
-case 180:
-#line 1095 "parse.y"
+case 183:
+#line 1103 "parse.y"
{
if (flag_ansi)
pedwarn ("ANSI C++ forbids initialization of new expression with `='");
yyval.ttype = yyvsp[0].ttype;
;
break;}
-case 181:
-#line 1105 "parse.y"
+case 184:
+#line 1113 "parse.y"
{ yyvsp[-1].ttype = tree_cons (NULL_TREE, yyvsp[-1].ttype, void_list_node);
TREE_PARMLIST (yyvsp[-1].ttype) = 1;
- yyval.ttype = build_parse_node (CALL_EXPR, NULL_TREE, yyvsp[-1].ttype,
+ yyval.ttype = build_parse_node (CALL_EXPR, NULL_TREE, yyvsp[-1].ttype,
NULL_TREE); ;
break;}
-case 182:
-#line 1110 "parse.y"
+case 185:
+#line 1118 "parse.y"
{ yyvsp[-1].ttype = tree_cons (NULL_TREE, yyvsp[-1].ttype, void_list_node);
TREE_PARMLIST (yyvsp[-1].ttype) = 1;
yyval.ttype = build_parse_node (CALL_EXPR, yyval.ttype, yyvsp[-1].ttype, NULL_TREE); ;
break;}
-case 184:
-#line 1118 "parse.y"
+case 187:
+#line 1126 "parse.y"
{ yyval.ttype = reparse_absdcl_as_casts (yyval.ttype, yyvsp[0].ttype); ;
break;}
-case 185:
-#line 1120 "parse.y"
-{
+case 188:
+#line 1128 "parse.y"
+{
tree init = build_nt (CONSTRUCTOR, NULL_TREE,
- nreverse (yyvsp[-2].ttype));
+ nreverse (yyvsp[-2].ttype));
if (flag_ansi)
pedwarn ("ANSI C++ forbids constructor-expressions");
/* Indicate that this was a GNU C constructor expression. */
@@ -4591,16 +4579,16 @@ case 185:
yyval.ttype = reparse_absdcl_as_casts (yyval.ttype, init);
;
break;}
-case 187:
-#line 1135 "parse.y"
+case 190:
+#line 1143 "parse.y"
{ yyval.ttype = build_headof (yyvsp[-1].ttype); ;
break;}
-case 188:
-#line 1137 "parse.y"
+case 191:
+#line 1145 "parse.y"
{ yyval.ttype = build_classof (yyvsp[-1].ttype); ;
break;}
-case 189:
-#line 1139 "parse.y"
+case 192:
+#line 1147 "parse.y"
{ if (is_aggr_typedef (yyvsp[-1].ttype, 1))
{
tree type = IDENTIFIER_TYPE_VALUE (yyvsp[-1].ttype);
@@ -4616,92 +4604,92 @@ case 189:
yyval.ttype = error_mark_node;
;
break;}
-case 191:
-#line 1159 "parse.y"
-{ yyval.ttype = build_x_binary_op (MEMBER_REF, yyval.ttype, yyvsp[0].ttype); ;
- break;}
-case 192:
-#line 1161 "parse.y"
-{ yyval.ttype = build_m_component_ref (yyval.ttype, yyvsp[0].ttype); ;
- break;}
-case 193:
-#line 1163 "parse.y"
-{ yyval.ttype = build_x_binary_op (yyvsp[-1].code, yyval.ttype, yyvsp[0].ttype); ;
- break;}
case 194:
-#line 1165 "parse.y"
-{ yyval.ttype = build_x_binary_op (yyvsp[-1].code, yyval.ttype, yyvsp[0].ttype); ;
+#line 1167 "parse.y"
+{ yyval.ttype = build_x_binary_op (MEMBER_REF, yyval.ttype, yyvsp[0].ttype); ;
break;}
case 195:
-#line 1167 "parse.y"
-{ yyval.ttype = build_x_binary_op (yyvsp[-1].code, yyval.ttype, yyvsp[0].ttype); ;
+#line 1169 "parse.y"
+{ yyval.ttype = build_m_component_ref (yyval.ttype, yyvsp[0].ttype); ;
break;}
case 196:
-#line 1169 "parse.y"
+#line 1171 "parse.y"
{ yyval.ttype = build_x_binary_op (yyvsp[-1].code, yyval.ttype, yyvsp[0].ttype); ;
break;}
case 197:
-#line 1171 "parse.y"
+#line 1173 "parse.y"
{ yyval.ttype = build_x_binary_op (yyvsp[-1].code, yyval.ttype, yyvsp[0].ttype); ;
break;}
case 198:
-#line 1173 "parse.y"
+#line 1175 "parse.y"
{ yyval.ttype = build_x_binary_op (yyvsp[-1].code, yyval.ttype, yyvsp[0].ttype); ;
break;}
case 199:
-#line 1175 "parse.y"
+#line 1177 "parse.y"
{ yyval.ttype = build_x_binary_op (yyvsp[-1].code, yyval.ttype, yyvsp[0].ttype); ;
break;}
case 200:
-#line 1177 "parse.y"
+#line 1179 "parse.y"
{ yyval.ttype = build_x_binary_op (yyvsp[-1].code, yyval.ttype, yyvsp[0].ttype); ;
break;}
case 201:
-#line 1179 "parse.y"
-{ yyval.ttype = build_x_binary_op (LT_EXPR, yyval.ttype, yyvsp[0].ttype); ;
- break;}
-case 202:
#line 1181 "parse.y"
-{ yyval.ttype = build_x_binary_op (GT_EXPR, yyval.ttype, yyvsp[0].ttype); ;
+{ yyval.ttype = build_x_binary_op (yyvsp[-1].code, yyval.ttype, yyvsp[0].ttype); ;
break;}
-case 203:
+case 202:
#line 1183 "parse.y"
{ yyval.ttype = build_x_binary_op (yyvsp[-1].code, yyval.ttype, yyvsp[0].ttype); ;
break;}
-case 204:
+case 203:
#line 1185 "parse.y"
{ yyval.ttype = build_x_binary_op (yyvsp[-1].code, yyval.ttype, yyvsp[0].ttype); ;
break;}
-case 205:
+case 204:
#line 1187 "parse.y"
-{ yyval.ttype = build_x_binary_op (yyvsp[-1].code, yyval.ttype, yyvsp[0].ttype); ;
+{ yyval.ttype = build_x_binary_op (LT_EXPR, yyval.ttype, yyvsp[0].ttype); ;
break;}
-case 206:
+case 205:
#line 1189 "parse.y"
+{ yyval.ttype = build_x_binary_op (GT_EXPR, yyval.ttype, yyvsp[0].ttype); ;
+ break;}
+case 206:
+#line 1191 "parse.y"
{ yyval.ttype = build_x_binary_op (yyvsp[-1].code, yyval.ttype, yyvsp[0].ttype); ;
break;}
case 207:
-#line 1191 "parse.y"
+#line 1193 "parse.y"
{ yyval.ttype = build_x_binary_op (yyvsp[-1].code, yyval.ttype, yyvsp[0].ttype); ;
break;}
case 208:
-#line 1193 "parse.y"
-{ yyval.ttype = build_x_binary_op (TRUTH_ANDIF_EXPR, yyval.ttype, yyvsp[0].ttype); ;
+#line 1195 "parse.y"
+{ yyval.ttype = build_x_binary_op (yyvsp[-1].code, yyval.ttype, yyvsp[0].ttype); ;
break;}
case 209:
-#line 1195 "parse.y"
-{ yyval.ttype = build_x_binary_op (TRUTH_ORIF_EXPR, yyval.ttype, yyvsp[0].ttype); ;
+#line 1197 "parse.y"
+{ yyval.ttype = build_x_binary_op (yyvsp[-1].code, yyval.ttype, yyvsp[0].ttype); ;
break;}
case 210:
-#line 1197 "parse.y"
-{ yyval.ttype = build_x_conditional_expr (yyval.ttype, yyvsp[-2].ttype, yyvsp[0].ttype); ;
+#line 1199 "parse.y"
+{ yyval.ttype = build_x_binary_op (yyvsp[-1].code, yyval.ttype, yyvsp[0].ttype); ;
break;}
case 211:
-#line 1199 "parse.y"
-{ yyval.ttype = build_modify_expr (yyval.ttype, NOP_EXPR, yyvsp[0].ttype); ;
+#line 1201 "parse.y"
+{ yyval.ttype = build_x_binary_op (TRUTH_ANDIF_EXPR, yyval.ttype, yyvsp[0].ttype); ;
break;}
case 212:
-#line 1201 "parse.y"
+#line 1203 "parse.y"
+{ yyval.ttype = build_x_binary_op (TRUTH_ORIF_EXPR, yyval.ttype, yyvsp[0].ttype); ;
+ break;}
+case 213:
+#line 1205 "parse.y"
+{ yyval.ttype = build_x_conditional_expr (yyval.ttype, yyvsp[-2].ttype, yyvsp[0].ttype); ;
+ break;}
+case 214:
+#line 1207 "parse.y"
+{ yyval.ttype = build_modify_expr (yyval.ttype, NOP_EXPR, yyvsp[0].ttype); ;
+ break;}
+case 215:
+#line 1209 "parse.y"
{ register tree rval;
if ((rval = build_opfncall (MODIFY_EXPR, LOOKUP_NORMAL, yyval.ttype, yyvsp[0].ttype,
make_node (yyvsp[-1].code))))
@@ -4709,33 +4697,33 @@ case 212:
else
yyval.ttype = build_modify_expr (yyval.ttype, yyvsp[-1].code, yyvsp[0].ttype); ;
break;}
-case 213:
-#line 1208 "parse.y"
+case 216:
+#line 1216 "parse.y"
{ yyval.ttype = build_throw (NULL_TREE); ;
break;}
-case 214:
-#line 1210 "parse.y"
+case 217:
+#line 1218 "parse.y"
{ yyval.ttype = build_throw (yyvsp[0].ttype); ;
break;}
-case 215:
-#line 1228 "parse.y"
+case 218:
+#line 1236 "parse.y"
{ yyval.ttype = build_parse_node (BIT_NOT_EXPR, yyvsp[0].ttype); ;
break;}
-case 223:
-#line 1243 "parse.y"
+case 226:
+#line 1251 "parse.y"
{ yyval.ttype = build_parse_node (INDIRECT_REF, yyvsp[0].ttype); ;
break;}
-case 224:
-#line 1245 "parse.y"
+case 227:
+#line 1253 "parse.y"
{ yyval.ttype = build_parse_node (ADDR_EXPR, yyvsp[0].ttype); ;
break;}
-case 227:
-#line 1252 "parse.y"
+case 230:
+#line 1260 "parse.y"
{ push_nested_class (TREE_TYPE (OP0 (yyval.ttype)), 3);
TREE_COMPLEXITY (yyval.ttype) = current_class_depth; ;
break;}
-case 228:
-#line 1258 "parse.y"
+case 231:
+#line 1266 "parse.y"
{
if (TREE_CODE (yyval.ttype) == BIT_NOT_EXPR)
yyval.ttype = build_x_unary_op (BIT_NOT_EXPR, TREE_OPERAND (yyval.ttype, 0));
@@ -4755,20 +4743,20 @@ case 228:
yyval.ttype = do_identifier (yyval.ttype);
;
break;}
-case 231:
-#line 1279 "parse.y"
+case 234:
+#line 1287 "parse.y"
{ yyval.ttype = combine_strings (yyval.ttype); ;
break;}
-case 232:
-#line 1281 "parse.y"
+case 235:
+#line 1289 "parse.y"
{ yyval.ttype = yyvsp[-1].ttype; ;
break;}
-case 233:
-#line 1283 "parse.y"
+case 236:
+#line 1291 "parse.y"
{ yyval.ttype = error_mark_node; ;
break;}
-case 234:
-#line 1285 "parse.y"
+case 237:
+#line 1293 "parse.y"
{ if (current_function_decl == 0)
{
error ("braced-group within expression allowed only inside a function");
@@ -4777,8 +4765,8 @@ case 234:
keep_next_level ();
yyval.ttype = expand_start_stmt_expr (); ;
break;}
-case 235:
-#line 1293 "parse.y"
+case 238:
+#line 1301 "parse.y"
{ tree rtl_exp;
if (flag_ansi)
pedwarn ("ANSI C++ forbids braced-groups within expressions");
@@ -4800,16 +4788,16 @@ case 235:
yyval.ttype = yyvsp[-1].ttype;
;
break;}
-case 236:
-#line 1314 "parse.y"
+case 239:
+#line 1322 "parse.y"
{ /* [eichin:19911016.1902EST] */
- yyval.ttype = build_x_function_call (yyvsp[-3].ttype, yyvsp[-1].ttype, current_class_decl);
+ yyval.ttype = build_x_function_call (yyvsp[-3].ttype, yyvsp[-1].ttype, current_class_decl);
/* here we instantiate_class_template as needed... */
do_pending_templates ();
;
break;}
-case 237:
-#line 1318 "parse.y"
+case 240:
+#line 1326 "parse.y"
{
if (TREE_CODE (yyvsp[-1].ttype) == CALL_EXPR
&& TREE_TYPE (yyvsp[-1].ttype) != void_type_node)
@@ -4818,8 +4806,8 @@ case 237:
yyval.ttype = yyvsp[-1].ttype;
;
break;}
-case 238:
-#line 1326 "parse.y"
+case 241:
+#line 1334 "parse.y"
{
yyval.ttype = build_x_function_call (yyval.ttype, NULL_TREE, current_class_decl);
if (TREE_CODE (yyval.ttype) == CALL_EXPR
@@ -4827,12 +4815,12 @@ case 238:
yyval.ttype = require_complete_type (yyval.ttype);
;
break;}
-case 239:
-#line 1333 "parse.y"
+case 242:
+#line 1341 "parse.y"
{ yyval.ttype = grok_array_decl (yyval.ttype, yyvsp[-1].ttype); ;
break;}
-case 240:
-#line 1335 "parse.y"
+case 243:
+#line 1343 "parse.y"
{ /* If we get an OFFSET_REF, turn it into what it really
means (e.g., a COMPONENT_REF). This way if we've got,
say, a reference to a static member that's being operated
@@ -4842,14 +4830,14 @@ case 240:
yyval.ttype = resolve_offset_ref (yyval.ttype);
yyval.ttype = build_x_unary_op (POSTINCREMENT_EXPR, yyval.ttype); ;
break;}
-case 241:
-#line 1344 "parse.y"
+case 244:
+#line 1352 "parse.y"
{ if (TREE_CODE (yyval.ttype) == OFFSET_REF)
yyval.ttype = resolve_offset_ref (yyval.ttype);
yyval.ttype = build_x_unary_op (POSTDECREMENT_EXPR, yyval.ttype); ;
break;}
-case 242:
-#line 1349 "parse.y"
+case 245:
+#line 1357 "parse.y"
{ if (current_class_decl)
{
#ifdef WARNING_ABOUT_CCD
@@ -4873,8 +4861,8 @@ case 242:
}
;
break;}
-case 243:
-#line 1372 "parse.y"
+case 246:
+#line 1380 "parse.y"
{
tree type;
tree id = yyval.ttype;
@@ -4919,37 +4907,37 @@ case 243:
}
;
break;}
-case 245:
-#line 1417 "parse.y"
+case 248:
+#line 1425 "parse.y"
{ tree type = groktypename (yyvsp[-4].ttype);
yyval.ttype = build_dynamic_cast (type, yyvsp[-1].ttype); ;
break;}
-case 246:
-#line 1420 "parse.y"
+case 249:
+#line 1428 "parse.y"
{ tree type = groktypename (yyvsp[-4].ttype);
yyval.ttype = build_static_cast (type, yyvsp[-1].ttype); ;
break;}
-case 247:
-#line 1423 "parse.y"
+case 250:
+#line 1431 "parse.y"
{ tree type = groktypename (yyvsp[-4].ttype);
yyval.ttype = build_reinterpret_cast (type, yyvsp[-1].ttype); ;
break;}
-case 248:
-#line 1426 "parse.y"
+case 251:
+#line 1434 "parse.y"
{ tree type = groktypename (yyvsp[-4].ttype);
yyval.ttype = build_const_cast (type, yyvsp[-1].ttype); ;
break;}
-case 249:
-#line 1429 "parse.y"
+case 252:
+#line 1437 "parse.y"
{ yyval.ttype = build_typeid (yyvsp[-1].ttype); ;
break;}
-case 250:
-#line 1431 "parse.y"
+case 253:
+#line 1439 "parse.y"
{ tree type = groktypename (yyvsp[-1].ttype);
yyval.ttype = get_typeid (type); ;
break;}
-case 251:
-#line 1434 "parse.y"
+case 254:
+#line 1442 "parse.y"
{
do_scoped_id:
yyval.ttype = IDENTIFIER_GLOBAL_VALUE (yyvsp[0].ttype);
@@ -4989,8 +4977,8 @@ case 251:
;
break;}
-case 252:
-#line 1473 "parse.y"
+case 255:
+#line 1481 "parse.y"
{
got_scope = NULL_TREE;
if (TREE_CODE (yyvsp[0].ttype) == IDENTIFIER_NODE)
@@ -4998,28 +4986,28 @@ case 252:
yyval.ttype = yyvsp[0].ttype;
;
break;}
-case 253:
-#line 1480 "parse.y"
+case 256:
+#line 1488 "parse.y"
{ yyval.ttype = build_offset_ref (OP0 (yyval.ttype), OP1 (yyval.ttype)); ;
break;}
-case 254:
-#line 1482 "parse.y"
+case 257:
+#line 1490 "parse.y"
{ yyval.ttype = build_member_call (OP0 (yyval.ttype), OP1 (yyval.ttype), yyvsp[-1].ttype); ;
break;}
-case 255:
-#line 1484 "parse.y"
+case 258:
+#line 1492 "parse.y"
{ yyval.ttype = build_member_call (OP0 (yyval.ttype), OP1 (yyval.ttype), NULL_TREE); ;
break;}
-case 256:
-#line 1486 "parse.y"
+case 259:
+#line 1494 "parse.y"
{ yyval.ttype = build_component_ref (yyval.ttype, yyvsp[0].ttype, NULL_TREE, 1); ;
break;}
-case 257:
-#line 1488 "parse.y"
+case 260:
+#line 1496 "parse.y"
{ yyval.ttype = build_object_ref (yyval.ttype, OP0 (yyvsp[0].ttype), OP1 (yyvsp[0].ttype)); ;
break;}
-case 258:
-#line 1490 "parse.y"
+case 261:
+#line 1498 "parse.y"
{
#if 0
/* This is a future direction of this code, but because
@@ -5035,8 +5023,8 @@ case 258:
#endif
;
break;}
-case 259:
-#line 1505 "parse.y"
+case 262:
+#line 1513 "parse.y"
{
#if 0
/* This is a future direction of this code, but because
@@ -5052,8 +5040,8 @@ case 259:
#endif
;
break;}
-case 260:
-#line 1520 "parse.y"
+case 263:
+#line 1528 "parse.y"
{
if (IS_SIGNATURE (IDENTIFIER_TYPE_VALUE (OP0 (yyvsp[-3].ttype))))
{
@@ -5065,8 +5053,8 @@ case 260:
yyval.ttype = build_scoped_method_call (yyval.ttype, OP0 (yyvsp[-3].ttype), OP1 (yyvsp[-3].ttype), yyvsp[-1].ttype);
;
break;}
-case 261:
-#line 1531 "parse.y"
+case 264:
+#line 1539 "parse.y"
{
if (IS_SIGNATURE (IDENTIFIER_TYPE_VALUE (OP0 (yyvsp[-1].ttype))))
{
@@ -5078,56 +5066,56 @@ case 261:
yyval.ttype = build_scoped_method_call (yyval.ttype, OP0 (yyvsp[-1].ttype), OP1 (yyvsp[-1].ttype), NULL_TREE);
;
break;}
-case 262:
-#line 1543 "parse.y"
-{
- if (TREE_CODE (TREE_TYPE (yyvsp[-3].ttype))
+case 265:
+#line 1551 "parse.y"
+{
+ if (TREE_CODE (TREE_TYPE (yyvsp[-3].ttype))
!= TREE_CODE (TREE_TYPE (IDENTIFIER_GLOBAL_VALUE (yyvsp[-1].ttype))))
cp_error ("`%E' is not of type `%T'", yyvsp[-3].ttype, yyvsp[-1].ttype);
- yyval.ttype = void_zero_node;
+ yyval.ttype = convert (void_type_node, yyvsp[-3].ttype);
;
break;}
-case 263:
-#line 1550 "parse.y"
-{
+case 266:
+#line 1558 "parse.y"
+{
if (yyvsp[-4].ttype != yyvsp[-1].ttype)
cp_error ("destructor specifier `%T::~%T()' must have matching names", yyvsp[-4].ttype, yyvsp[-1].ttype);
if (TREE_CODE (TREE_TYPE (yyvsp[-5].ttype))
!= TREE_CODE (TREE_TYPE (IDENTIFIER_GLOBAL_VALUE (yyvsp[-4].ttype))))
cp_error ("`%E' is not of type `%T'", yyvsp[-5].ttype, yyvsp[-4].ttype);
- yyval.ttype = void_zero_node;
+ yyval.ttype = convert (void_type_node, yyvsp[-5].ttype);
;
break;}
-case 264:
-#line 1599 "parse.y"
+case 267:
+#line 1607 "parse.y"
{ yyval.itype = 0; ;
break;}
-case 265:
-#line 1601 "parse.y"
+case 268:
+#line 1609 "parse.y"
{ got_scope = NULL_TREE; yyval.itype = 1; ;
break;}
-case 266:
-#line 1605 "parse.y"
+case 269:
+#line 1613 "parse.y"
{ yyval.itype = 0; ;
break;}
-case 267:
-#line 1607 "parse.y"
+case 270:
+#line 1615 "parse.y"
{ got_scope = NULL_TREE; yyval.itype = 1; ;
break;}
-case 268:
-#line 1612 "parse.y"
+case 271:
+#line 1620 "parse.y"
{ yyval.ttype = true_node; ;
break;}
-case 269:
-#line 1614 "parse.y"
+case 272:
+#line 1622 "parse.y"
{ yyval.ttype = false_node; ;
break;}
-case 271:
-#line 1621 "parse.y"
+case 274:
+#line 1629 "parse.y"
{ yyval.ttype = chainon (yyval.ttype, yyvsp[0].ttype); ;
break;}
-case 272:
-#line 1626 "parse.y"
+case 275:
+#line 1634 "parse.y"
{
if (! current_function_parms_stored)
store_parm_decls ();
@@ -5138,14 +5126,14 @@ case 272:
keep_next_level ();
;
break;}
-case 274:
-#line 1639 "parse.y"
+case 277:
+#line 1647 "parse.y"
{
yyval.ttype = build_x_arrow (yyval.ttype);
;
break;}
-case 275:
-#line 1647 "parse.y"
+case 278:
+#line 1655 "parse.y"
{ tree d = get_decl_list (yyvsp[-2].ttype);
int yes = suspend_momentary ();
d = start_decl (yyvsp[-1].ttype, d, 0, NULL_TREE);
@@ -5155,8 +5143,8 @@ case 275:
note_got_semicolon (yyvsp[-2].ttype);
;
break;}
-case 276:
-#line 1656 "parse.y"
+case 279:
+#line 1664 "parse.y"
{ tree d = yyvsp[-2].ttype;
int yes = suspend_momentary ();
d = start_decl (yyvsp[-1].ttype, d, 0, NULL_TREE);
@@ -5165,164 +5153,164 @@ case 276:
note_list_got_semicolon (yyvsp[-2].ttype);
;
break;}
-case 277:
-#line 1664 "parse.y"
+case 280:
+#line 1672 "parse.y"
{
resume_momentary (yyvsp[-1].itype);
if (IS_AGGR_TYPE_CODE (TREE_CODE (yyvsp[-2].ttype)))
note_got_semicolon (yyvsp[-2].ttype);
;
break;}
-case 278:
-#line 1670 "parse.y"
+case 281:
+#line 1678 "parse.y"
{
resume_momentary (yyvsp[-1].itype);
note_list_got_semicolon (yyvsp[-2].ttype);
;
break;}
-case 279:
-#line 1675 "parse.y"
+case 282:
+#line 1683 "parse.y"
{ resume_momentary (yyvsp[-1].itype); ;
break;}
-case 280:
-#line 1677 "parse.y"
+case 283:
+#line 1685 "parse.y"
{
shadow_tag (yyvsp[-1].ttype);
note_list_got_semicolon (yyvsp[-1].ttype);
;
break;}
-case 281:
-#line 1682 "parse.y"
+case 284:
+#line 1690 "parse.y"
{ warning ("empty declaration"); ;
break;}
-case 284:
-#line 1696 "parse.y"
+case 287:
+#line 1704 "parse.y"
{ yyval.ttype = build_parse_node (CALL_EXPR, NULL_TREE, empty_parms (),
NULL_TREE); ;
break;}
-case 285:
-#line 1699 "parse.y"
-{ yyval.ttype = build_parse_node (CALL_EXPR, yyval.ttype, empty_parms (),
+case 288:
+#line 1707 "parse.y"
+{ yyval.ttype = build_parse_node (CALL_EXPR, yyval.ttype, empty_parms (),
NULL_TREE); ;
break;}
-case 286:
-#line 1706 "parse.y"
+case 289:
+#line 1714 "parse.y"
{ yyval.ttype = build_decl_list (yyval.ttype, yyvsp[0].ttype); ;
break;}
-case 287:
-#line 1708 "parse.y"
+case 290:
+#line 1716 "parse.y"
{ yyval.ttype = build_decl_list (yyval.ttype, yyvsp[0].ttype); ;
break;}
-case 288:
-#line 1710 "parse.y"
+case 291:
+#line 1718 "parse.y"
{ yyval.ttype = build_decl_list (get_decl_list (yyval.ttype), yyvsp[0].ttype); ;
break;}
-case 289:
-#line 1712 "parse.y"
+case 292:
+#line 1720 "parse.y"
{ yyval.ttype = build_decl_list (yyval.ttype, NULL_TREE); ;
break;}
-case 290:
-#line 1714 "parse.y"
+case 293:
+#line 1722 "parse.y"
{ yyval.ttype = build_decl_list (yyval.ttype, NULL_TREE); ;
break;}
-case 293:
-#line 1727 "parse.y"
+case 296:
+#line 1735 "parse.y"
{ yyval.ttype = decl_tree_cons (NULL_TREE, yyvsp[0].ttype, yyval.ttype); ;
break;}
-case 294:
-#line 1729 "parse.y"
+case 297:
+#line 1737 "parse.y"
{ yyval.ttype = decl_tree_cons (NULL_TREE, yyval.ttype, yyvsp[0].ttype); ;
break;}
-case 295:
-#line 1731 "parse.y"
+case 298:
+#line 1739 "parse.y"
{ yyval.ttype = decl_tree_cons (NULL_TREE, yyvsp[-1].ttype, chainon (yyvsp[0].ttype, yyval.ttype)); ;
break;}
-case 296:
-#line 1733 "parse.y"
+case 299:
+#line 1741 "parse.y"
{ yyval.ttype = decl_tree_cons (NULL_TREE, yyvsp[-1].ttype, chainon (yyvsp[0].ttype, yyval.ttype)); ;
break;}
-case 297:
-#line 1735 "parse.y"
-{ yyval.ttype = decl_tree_cons (NULL_TREE, yyvsp[-2].ttype,
+case 300:
+#line 1743 "parse.y"
+{ yyval.ttype = decl_tree_cons (NULL_TREE, yyvsp[-2].ttype,
chainon (yyvsp[-1].ttype, chainon (yyvsp[0].ttype, yyval.ttype))); ;
break;}
-case 298:
-#line 1741 "parse.y"
+case 301:
+#line 1749 "parse.y"
{ if (extra_warnings)
warning ("`%s' is not at beginning of declaration",
IDENTIFIER_POINTER (yyval.ttype));
yyval.ttype = build_decl_list (NULL_TREE, yyval.ttype); ;
break;}
-case 299:
-#line 1746 "parse.y"
+case 302:
+#line 1754 "parse.y"
{ yyval.ttype = decl_tree_cons (NULL_TREE, yyvsp[0].ttype, yyval.ttype); ;
break;}
-case 300:
-#line 1748 "parse.y"
+case 303:
+#line 1756 "parse.y"
{ if (extra_warnings)
warning ("`%s' is not at beginning of declaration",
IDENTIFIER_POINTER (yyvsp[0].ttype));
yyval.ttype = decl_tree_cons (NULL_TREE, yyvsp[0].ttype, yyval.ttype); ;
break;}
-case 301:
-#line 1760 "parse.y"
+case 304:
+#line 1768 "parse.y"
{ TREE_STATIC (yyval.ttype) = 1; ;
break;}
-case 302:
-#line 1762 "parse.y"
+case 305:
+#line 1770 "parse.y"
{ yyval.ttype = IDENTIFIER_AS_LIST (yyval.ttype); ;
break;}
-case 303:
-#line 1764 "parse.y"
+case 306:
+#line 1772 "parse.y"
{ yyval.ttype = decl_tree_cons (NULL_TREE, yyvsp[0].ttype, yyval.ttype);
TREE_STATIC (yyval.ttype) = 1; ;
break;}
-case 304:
-#line 1767 "parse.y"
+case 307:
+#line 1775 "parse.y"
{ if (extra_warnings && TREE_STATIC (yyval.ttype))
warning ("`%s' is not at beginning of declaration",
IDENTIFIER_POINTER (yyvsp[0].ttype));
yyval.ttype = decl_tree_cons (NULL_TREE, yyvsp[0].ttype, yyval.ttype);
TREE_STATIC (yyval.ttype) = TREE_STATIC (yyvsp[-1].ttype); ;
break;}
-case 305:
-#line 1783 "parse.y"
+case 308:
+#line 1791 "parse.y"
{ yyval.ttype = get_decl_list (yyval.ttype); ;
break;}
-case 306:
-#line 1785 "parse.y"
+case 309:
+#line 1793 "parse.y"
{ yyval.ttype = decl_tree_cons (NULL_TREE, yyvsp[0].ttype, yyval.ttype); ;
break;}
-case 307:
-#line 1787 "parse.y"
+case 310:
+#line 1795 "parse.y"
{ yyval.ttype = decl_tree_cons (NULL_TREE, yyval.ttype, yyvsp[0].ttype); ;
break;}
-case 308:
-#line 1789 "parse.y"
+case 311:
+#line 1797 "parse.y"
{ yyval.ttype = decl_tree_cons (NULL_TREE, yyvsp[-1].ttype, chainon (yyvsp[0].ttype, yyval.ttype)); ;
break;}
-case 309:
-#line 1794 "parse.y"
+case 312:
+#line 1802 "parse.y"
{ yyval.ttype = build_decl_list (NULL_TREE, yyval.ttype); ;
break;}
-case 310:
-#line 1796 "parse.y"
+case 313:
+#line 1804 "parse.y"
{ yyval.ttype = decl_tree_cons (NULL_TREE, yyvsp[0].ttype, yyval.ttype); ;
break;}
-case 314:
-#line 1807 "parse.y"
+case 317:
+#line 1815 "parse.y"
{ yyval.ttype = TREE_TYPE (yyvsp[-1].ttype);
if (flag_ansi)
pedwarn ("ANSI C++ forbids `typeof'"); ;
break;}
-case 315:
-#line 1811 "parse.y"
+case 318:
+#line 1819 "parse.y"
{ yyval.ttype = groktypename (yyvsp[-1].ttype);
if (flag_ansi)
pedwarn ("ANSI C++ forbids `typeof'"); ;
break;}
-case 316:
-#line 1815 "parse.y"
+case 319:
+#line 1823 "parse.y"
{ tree type = TREE_TYPE (yyvsp[-1].ttype);
if (IS_AGGR_TYPE (type))
@@ -5337,8 +5325,8 @@ case 316:
}
;
break;}
-case 317:
-#line 1829 "parse.y"
+case 320:
+#line 1837 "parse.y"
{ tree type = groktypename (yyvsp[-1].ttype);
if (IS_AGGR_TYPE (type))
@@ -5353,23 +5341,23 @@ case 317:
}
;
break;}
-case 327:
-#line 1868 "parse.y"
+case 330:
+#line 1876 "parse.y"
{ yyval.ttype = NULL_TREE; ;
break;}
-case 328:
-#line 1870 "parse.y"
+case 331:
+#line 1878 "parse.y"
{ if (TREE_CHAIN (yyvsp[-1].ttype)) yyvsp[-1].ttype = combine_strings (yyvsp[-1].ttype); yyval.ttype = yyvsp[-1].ttype; ;
break;}
-case 329:
-#line 1875 "parse.y"
+case 332:
+#line 1883 "parse.y"
{ current_declspecs = yyvsp[-5].ttype;
if (TREE_CODE (current_declspecs) != TREE_LIST)
current_declspecs = get_decl_list (current_declspecs);
if (have_extern_spec && !used_extern_spec)
{
current_declspecs = decl_tree_cons
- (NULL_TREE, get_identifier ("extern"),
+ (NULL_TREE, get_identifier ("extern"),
current_declspecs);
used_extern_spec = 1;
}
@@ -5377,13 +5365,13 @@ case 329:
yyval.ttype = start_decl (yyvsp[-4].ttype, current_declspecs, 1, yyvsp[-3].ttype);
cplus_decl_attributes (yyval.ttype, yyvsp[-1].ttype); ;
break;}
-case 330:
-#line 1890 "parse.y"
+case 333:
+#line 1898 "parse.y"
{ finish_decl (yyvsp[-1].ttype, yyvsp[0].ttype, yyvsp[-4].ttype, 0);
yyval.itype = yyvsp[-2].itype; ;
break;}
-case 331:
-#line 1893 "parse.y"
+case 334:
+#line 1901 "parse.y"
{ tree d;
current_declspecs = yyvsp[-4].ttype;
if (TREE_CODE (current_declspecs) != TREE_LIST)
@@ -5391,7 +5379,7 @@ case 331:
if (have_extern_spec && !used_extern_spec)
{
current_declspecs = decl_tree_cons
- (NULL_TREE, get_identifier ("extern"),
+ (NULL_TREE, get_identifier ("extern"),
current_declspecs);
used_extern_spec = 1;
}
@@ -5400,35 +5388,35 @@ case 331:
cplus_decl_attributes (d, yyvsp[0].ttype);
finish_decl (d, NULL_TREE, yyvsp[-1].ttype, 0); ;
break;}
-case 332:
-#line 1912 "parse.y"
+case 335:
+#line 1920 "parse.y"
{ yyval.ttype = start_decl (yyvsp[-4].ttype, current_declspecs, 1, yyvsp[-3].ttype);
cplus_decl_attributes (yyval.ttype, yyvsp[-1].ttype); ;
break;}
-case 333:
-#line 1916 "parse.y"
+case 336:
+#line 1924 "parse.y"
{ finish_decl (yyvsp[-1].ttype, yyvsp[0].ttype, yyvsp[-4].ttype, 0); ;
break;}
-case 334:
-#line 1918 "parse.y"
+case 337:
+#line 1926 "parse.y"
{ yyval.ttype = start_decl (yyvsp[-3].ttype, current_declspecs, 0, yyvsp[-2].ttype);
cplus_decl_attributes (yyval.ttype, yyvsp[0].ttype);
finish_decl (yyval.ttype, NULL_TREE, yyvsp[-1].ttype, 0); ;
break;}
-case 335:
-#line 1925 "parse.y"
+case 338:
+#line 1933 "parse.y"
{ current_declspecs = yyvsp[-5].ttype;
yyvsp[0].itype = suspend_momentary ();
yyval.ttype = start_decl (yyvsp[-4].ttype, current_declspecs, 1, yyvsp[-3].ttype);
cplus_decl_attributes (yyval.ttype, yyvsp[-1].ttype); ;
break;}
-case 336:
-#line 1931 "parse.y"
+case 339:
+#line 1939 "parse.y"
{ finish_decl (yyvsp[-1].ttype, yyvsp[0].ttype, yyvsp[-4].ttype, 0);
yyval.itype = yyvsp[-2].itype; ;
break;}
-case 337:
-#line 1934 "parse.y"
+case 340:
+#line 1942 "parse.y"
{ tree d;
current_declspecs = yyvsp[-4].ttype;
yyval.itype = suspend_momentary ();
@@ -5436,20 +5424,20 @@ case 337:
cplus_decl_attributes (d, yyvsp[0].ttype);
finish_decl (d, NULL_TREE, yyvsp[-1].ttype, 0); ;
break;}
-case 338:
-#line 1944 "parse.y"
+case 341:
+#line 1952 "parse.y"
{ current_declspecs = NULL_TREE;
yyvsp[0].itype = suspend_momentary ();
yyval.ttype = start_decl (yyvsp[-4].ttype, current_declspecs, 1, yyvsp[-3].ttype);
cplus_decl_attributes (yyval.ttype, yyvsp[-1].ttype); ;
break;}
-case 339:
-#line 1950 "parse.y"
+case 342:
+#line 1958 "parse.y"
{ finish_decl (yyvsp[-1].ttype, yyvsp[0].ttype, yyvsp[-4].ttype, 0);
yyval.itype = yyvsp[-2].itype; ;
break;}
-case 340:
-#line 1953 "parse.y"
+case 343:
+#line 1961 "parse.y"
{ tree d;
current_declspecs = NULL_TREE;
yyval.itype = suspend_momentary ();
@@ -5457,147 +5445,147 @@ case 340:
cplus_decl_attributes (d, yyvsp[0].ttype);
finish_decl (d, NULL_TREE, yyvsp[-1].ttype, 0); ;
break;}
-case 341:
-#line 1965 "parse.y"
+case 344:
+#line 1973 "parse.y"
{ yyval.ttype = NULL_TREE; ;
break;}
-case 342:
-#line 1967 "parse.y"
+case 345:
+#line 1975 "parse.y"
{ yyval.ttype = yyvsp[0].ttype; ;
break;}
-case 343:
-#line 1972 "parse.y"
+case 346:
+#line 1980 "parse.y"
{ yyval.ttype = yyvsp[0].ttype; ;
break;}
-case 344:
-#line 1974 "parse.y"
+case 347:
+#line 1982 "parse.y"
{ yyval.ttype = chainon (yyvsp[-1].ttype, yyvsp[0].ttype); ;
break;}
-case 345:
-#line 1979 "parse.y"
+case 348:
+#line 1987 "parse.y"
{ yyval.ttype = yyvsp[-2].ttype; ;
break;}
-case 346:
-#line 1984 "parse.y"
+case 349:
+#line 1992 "parse.y"
{ yyval.ttype = build_tree_list (NULL_TREE, yyvsp[0].ttype); ;
break;}
-case 347:
-#line 1986 "parse.y"
+case 350:
+#line 1994 "parse.y"
{ yyval.ttype = chainon (yyvsp[-2].ttype, build_tree_list (NULL_TREE, yyvsp[0].ttype)); ;
break;}
-case 348:
-#line 1991 "parse.y"
+case 351:
+#line 1999 "parse.y"
{ yyval.ttype = NULL_TREE; ;
break;}
-case 349:
-#line 1993 "parse.y"
+case 352:
+#line 2001 "parse.y"
{ yyval.ttype = yyvsp[0].ttype; ;
break;}
-case 350:
-#line 1995 "parse.y"
+case 353:
+#line 2003 "parse.y"
{ yyval.ttype = tree_cons (yyvsp[-3].ttype, NULL_TREE, build_tree_list (NULL_TREE, yyvsp[-1].ttype)); ;
break;}
-case 351:
-#line 1997 "parse.y"
+case 354:
+#line 2005 "parse.y"
{ yyval.ttype = tree_cons (yyvsp[-5].ttype, NULL_TREE, tree_cons (NULL_TREE, yyvsp[-3].ttype, yyvsp[-1].ttype)); ;
break;}
-case 352:
-#line 1999 "parse.y"
+case 355:
+#line 2007 "parse.y"
{ yyval.ttype = tree_cons (yyvsp[-3].ttype, NULL_TREE, yyvsp[-1].ttype); ;
break;}
-case 357:
-#line 2015 "parse.y"
+case 360:
+#line 2023 "parse.y"
{ yyval.ttype = build_tree_list (NULL_TREE, yyvsp[0].ttype); ;
break;}
-case 358:
-#line 2017 "parse.y"
+case 361:
+#line 2025 "parse.y"
{ yyval.ttype = chainon (yyvsp[-2].ttype, build_tree_list (NULL_TREE, yyvsp[0].ttype)); ;
break;}
-case 360:
-#line 2023 "parse.y"
+case 363:
+#line 2031 "parse.y"
{ yyval.ttype = build_nt (CONSTRUCTOR, NULL_TREE, NULL_TREE);
TREE_HAS_CONSTRUCTOR (yyval.ttype) = 1; ;
break;}
-case 361:
-#line 2026 "parse.y"
+case 364:
+#line 2034 "parse.y"
{ yyval.ttype = build_nt (CONSTRUCTOR, NULL_TREE, nreverse (yyvsp[-1].ttype));
TREE_HAS_CONSTRUCTOR (yyval.ttype) = 1; ;
break;}
-case 362:
-#line 2029 "parse.y"
+case 365:
+#line 2037 "parse.y"
{ yyval.ttype = build_nt (CONSTRUCTOR, NULL_TREE, nreverse (yyvsp[-2].ttype));
TREE_HAS_CONSTRUCTOR (yyval.ttype) = 1; ;
break;}
-case 363:
-#line 2032 "parse.y"
+case 366:
+#line 2040 "parse.y"
{ yyval.ttype = NULL_TREE; ;
break;}
-case 364:
-#line 2039 "parse.y"
+case 367:
+#line 2047 "parse.y"
{ yyval.ttype = build_tree_list (NULL_TREE, yyval.ttype); ;
break;}
-case 365:
-#line 2041 "parse.y"
+case 368:
+#line 2049 "parse.y"
{ yyval.ttype = tree_cons (NULL_TREE, yyvsp[0].ttype, yyval.ttype); ;
break;}
-case 366:
-#line 2044 "parse.y"
+case 369:
+#line 2052 "parse.y"
{ yyval.ttype = build_tree_list (yyvsp[-2].ttype, yyvsp[0].ttype); ;
break;}
-case 367:
-#line 2046 "parse.y"
+case 370:
+#line 2054 "parse.y"
{ yyval.ttype = tree_cons (yyvsp[-2].ttype, yyvsp[0].ttype, yyval.ttype); ;
break;}
-case 368:
-#line 2048 "parse.y"
+case 371:
+#line 2056 "parse.y"
{ yyval.ttype = build_tree_list (yyval.ttype, yyvsp[0].ttype); ;
break;}
-case 369:
-#line 2050 "parse.y"
+case 372:
+#line 2058 "parse.y"
{ yyval.ttype = tree_cons (yyvsp[-2].ttype, yyvsp[0].ttype, yyval.ttype); ;
break;}
-case 370:
-#line 2055 "parse.y"
+case 373:
+#line 2063 "parse.y"
{ yyvsp[0].itype = suspend_momentary ();
yyval.ttype = start_enum (yyvsp[-1].ttype); ;
break;}
-case 371:
-#line 2058 "parse.y"
+case 374:
+#line 2066 "parse.y"
{ yyval.ttype = finish_enum (yyvsp[-3].ttype, yyvsp[-2].ttype);
resume_momentary ((int) yyvsp[-4].itype);
check_for_missing_semicolon (yyvsp[-3].ttype); ;
break;}
-case 372:
-#line 2062 "parse.y"
+case 375:
+#line 2070 "parse.y"
{ yyval.ttype = finish_enum (start_enum (yyvsp[-2].ttype), NULL_TREE);
check_for_missing_semicolon (yyval.ttype); ;
break;}
-case 373:
-#line 2065 "parse.y"
+case 376:
+#line 2073 "parse.y"
{ yyvsp[0].itype = suspend_momentary ();
yyval.ttype = start_enum (make_anon_name ()); ;
break;}
-case 374:
-#line 2068 "parse.y"
+case 377:
+#line 2076 "parse.y"
{ yyval.ttype = finish_enum (yyvsp[-3].ttype, yyvsp[-2].ttype);
resume_momentary ((int) yyvsp[-5].itype);
check_for_missing_semicolon (yyvsp[-3].ttype); ;
break;}
-case 375:
-#line 2072 "parse.y"
+case 378:
+#line 2080 "parse.y"
{ yyval.ttype = finish_enum (start_enum (make_anon_name()), NULL_TREE);
check_for_missing_semicolon (yyval.ttype); ;
break;}
-case 376:
-#line 2075 "parse.y"
+case 379:
+#line 2083 "parse.y"
{ yyval.ttype = xref_tag (enum_type_node, yyvsp[0].ttype, NULL_TREE, 0); ;
break;}
-case 377:
-#line 2077 "parse.y"
+case 380:
+#line 2085 "parse.y"
{ yyval.ttype = xref_tag (enum_type_node, yyvsp[0].ttype, NULL_TREE, 0); ;
break;}
-case 378:
-#line 2081 "parse.y"
+case 381:
+#line 2089 "parse.y"
{
int semi;
tree id;
@@ -5649,8 +5637,8 @@ case 378:
if (! semi)
check_for_missing_semicolon (yyval.ttype); ;
break;}
-case 379:
-#line 2132 "parse.y"
+case 382:
+#line 2140 "parse.y"
{
#if 0
/* It's no longer clear what the following error is supposed to
@@ -5664,72 +5652,72 @@ case 379:
#endif
;
break;}
-case 383:
-#line 2154 "parse.y"
+case 386:
+#line 2162 "parse.y"
{ if (pedantic) pedwarn ("comma at end of enumerator list"); ;
break;}
-case 385:
-#line 2159 "parse.y"
+case 388:
+#line 2167 "parse.y"
{ error ("storage class specifier `%s' not allowed after struct or class", IDENTIFIER_POINTER (yyvsp[0].ttype)); ;
break;}
-case 386:
-#line 2161 "parse.y"
+case 389:
+#line 2169 "parse.y"
{ error ("type specifier `%s' not allowed after struct or class", IDENTIFIER_POINTER (yyvsp[0].ttype)); ;
break;}
-case 387:
-#line 2163 "parse.y"
+case 390:
+#line 2171 "parse.y"
{ error ("type qualifier `%s' not allowed after struct or class", IDENTIFIER_POINTER (yyvsp[0].ttype)); ;
break;}
-case 388:
-#line 2165 "parse.y"
+case 391:
+#line 2173 "parse.y"
{ error ("no body nor ';' separates two class, struct or union declarations"); ;
break;}
-case 389:
-#line 2170 "parse.y"
-{
- yyungetc (';', 1); current_aggr = yyval.ttype; yyval.ttype = yyvsp[-1].ttype;
+case 392:
+#line 2178 "parse.y"
+{
+ yyungetc (';', 1); current_aggr = yyval.ttype; yyval.ttype = yyvsp[-1].ttype;
if (yyvsp[-3].ttype == ridpointers[(int) RID_TEMPLATE])
instantiate_class_template (yyval.ttype, 2);
;
break;}
-case 390:
-#line 2179 "parse.y"
+case 393:
+#line 2187 "parse.y"
{ current_aggr = yyval.ttype; yyval.ttype = yyvsp[0].ttype; ;
break;}
-case 391:
-#line 2181 "parse.y"
+case 394:
+#line 2189 "parse.y"
{ current_aggr = yyval.ttype; yyval.ttype = yyvsp[0].ttype; ;
break;}
-case 392:
-#line 2183 "parse.y"
+case 395:
+#line 2191 "parse.y"
{ current_aggr = yyval.ttype; yyval.ttype = yyvsp[0].ttype; ;
break;}
-case 393:
-#line 2185 "parse.y"
+case 396:
+#line 2193 "parse.y"
{ yyungetc ('{', 1);
aggr2:
current_aggr = yyval.ttype;
yyval.ttype = yyvsp[-1].ttype;
overload_template_name (yyval.ttype, 0); ;
break;}
-case 394:
-#line 2191 "parse.y"
+case 397:
+#line 2199 "parse.y"
{ yyungetc (':', 1); goto aggr2; ;
break;}
-case 396:
-#line 2197 "parse.y"
+case 399:
+#line 2205 "parse.y"
{ current_aggr = yyval.ttype; yyval.ttype = yyvsp[0].ttype; ;
break;}
-case 397:
-#line 2201 "parse.y"
+case 400:
+#line 2209 "parse.y"
{ yyval.ttype = xref_tag (current_aggr, yyvsp[0].ttype, NULL_TREE, 1); ;
break;}
-case 398:
-#line 2204 "parse.y"
+case 401:
+#line 2212 "parse.y"
{ yyval.ttype = xref_defn_tag (current_aggr, yyvsp[0].ttype, NULL_TREE); ;
break;}
-case 399:
-#line 2209 "parse.y"
+case 402:
+#line 2217 "parse.y"
{
if (yyvsp[0].ttype)
yyval.ttype = xref_tag (current_aggr, yyvsp[-2].ttype, yyvsp[0].ttype, 1);
@@ -5737,8 +5725,8 @@ case 399:
yyval.ttype = yyvsp[-1].ttype;
;
break;}
-case 400:
-#line 2218 "parse.y"
+case 403:
+#line 2226 "parse.y"
{
if (yyvsp[0].ttype)
yyval.ttype = xref_defn_tag (current_aggr, yyvsp[-2].ttype, yyvsp[0].ttype);
@@ -5746,29 +5734,29 @@ case 400:
yyval.ttype = yyvsp[-1].ttype;
;
break;}
-case 401:
-#line 2227 "parse.y"
+case 404:
+#line 2235 "parse.y"
{ yyval.ttype = xref_tag (yyval.ttype, make_anon_name (), NULL_TREE, 0);
yyungetc ('{', 1); ;
break;}
-case 404:
-#line 2235 "parse.y"
+case 407:
+#line 2243 "parse.y"
{ yyval.ttype = NULL_TREE; ;
break;}
-case 405:
-#line 2237 "parse.y"
+case 408:
+#line 2245 "parse.y"
{ yyungetc(':', 1); yyval.ttype = NULL_TREE; ;
break;}
-case 406:
-#line 2239 "parse.y"
+case 409:
+#line 2247 "parse.y"
{ yyval.ttype = yyvsp[0].ttype; ;
break;}
-case 408:
-#line 2245 "parse.y"
+case 411:
+#line 2253 "parse.y"
{ yyval.ttype = chainon (yyval.ttype, yyvsp[0].ttype); ;
break;}
-case 409:
-#line 2250 "parse.y"
+case 412:
+#line 2258 "parse.y"
{
tree type;
do_base_class1:
@@ -5796,8 +5784,8 @@ case 409:
yyval.ttype = build_tree_list ((tree)access_default, yyval.ttype);
;
break;}
-case 410:
-#line 2277 "parse.y"
+case 413:
+#line 2285 "parse.y"
{
tree type;
do_base_class2:
@@ -5827,8 +5815,8 @@ case 410:
yyval.ttype = build_tree_list ((tree) yyval.ttype, yyvsp[0].ttype);
;
break;}
-case 412:
-#line 2310 "parse.y"
+case 415:
+#line 2318 "parse.y"
{
if (current_aggr == signature_type_node)
{
@@ -5851,8 +5839,8 @@ case 412:
}
;
break;}
-case 413:
-#line 2332 "parse.y"
+case 416:
+#line 2340 "parse.y"
{
if (current_aggr == signature_type_node)
{
@@ -5875,14 +5863,14 @@ case 413:
}
;
break;}
-case 415:
-#line 2358 "parse.y"
+case 418:
+#line 2366 "parse.y"
{ if (yyval.ttype != ridpointers[(int)RID_VIRTUAL])
sorry ("non-virtual access");
yyval.itype = access_default_virtual; ;
break;}
-case 416:
-#line 2362 "parse.y"
+case 419:
+#line 2370 "parse.y"
{ int err = 0;
if (yyvsp[0].itype == access_protected)
{
@@ -5909,8 +5897,8 @@ case 416:
}
;
break;}
-case 417:
-#line 2388 "parse.y"
+case 420:
+#line 2396 "parse.y"
{ if (yyvsp[0].ttype != ridpointers[(int)RID_VIRTUAL])
sorry ("non-virtual access");
if (yyval.itype == access_public)
@@ -5918,27 +5906,61 @@ case 417:
else if (yyval.itype == access_private)
yyval.itype = access_private_virtual; ;
break;}
-case 418:
-#line 2397 "parse.y"
-{ tree t;
+case 421:
+#line 2405 "parse.y"
+{ tree t = yyvsp[-1].ttype;
push_obstacks_nochange ();
end_temporary_allocation ();
- if (! IS_AGGR_TYPE (yyvsp[-1].ttype))
+ if (! IS_AGGR_TYPE (t))
{
- yyvsp[-1].ttype = make_lang_type (RECORD_TYPE);
- TYPE_NAME (yyvsp[-1].ttype) = get_identifier ("erroneous type");
+ t = yyvsp[-1].ttype = make_lang_type (RECORD_TYPE);
+ TYPE_NAME (t) = get_identifier ("erroneous type");
}
- if (TYPE_SIZE (yyvsp[-1].ttype))
- duplicate_tag_error (yyvsp[-1].ttype);
- if (TYPE_SIZE (yyvsp[-1].ttype) || TYPE_BEING_DEFINED (yyvsp[-1].ttype))
+ if (TYPE_SIZE (t))
+ duplicate_tag_error (t);
+ if (TYPE_SIZE (t) || TYPE_BEING_DEFINED (t))
{
- t = make_lang_type (TREE_CODE (yyvsp[-1].ttype));
+ t = make_lang_type (TREE_CODE (t));
pushtag (TYPE_IDENTIFIER (yyvsp[-1].ttype), t, 0);
yyvsp[-1].ttype = t;
}
- pushclass (yyvsp[-1].ttype, 0);
- TYPE_BEING_DEFINED (yyvsp[-1].ttype) = 1;
+ pushclass (t, 0);
+ TYPE_BEING_DEFINED (t) = 1;
+ /* Reset the interface data, at the earliest possible
+ moment, as it might have been set via a class foo;
+ before. */
+ /* Don't change signatures. */
+ if (! IS_SIGNATURE (t))
+ {
+ extern tree pending_vtables;
+ int needs_writing;
+ tree name = TYPE_IDENTIFIER (t);
+
+ CLASSTYPE_INTERFACE_ONLY (t) = interface_only;
+ SET_CLASSTYPE_INTERFACE_UNKNOWN_X (t, interface_unknown);
+
+ /* Record how to set the access of this class's
+ virtual functions. If write_virtuals == 2 or 3, then
+ inline virtuals are ``extern inline''. */
+ switch (write_virtuals)
+ {
+ case 0:
+ case 1:
+ needs_writing = 1;
+ break;
+ case 2:
+ needs_writing = !! value_member (name, pending_vtables);
+ break;
+ case 3:
+ needs_writing = ! CLASSTYPE_INTERFACE_ONLY (t)
+ && CLASSTYPE_INTERFACE_KNOWN (t);
+ break;
+ default:
+ needs_writing = 0;
+ }
+ CLASSTYPE_VTABLE_NEEDS_WRITING (t) = needs_writing;
+ }
#if 0
t = TYPE_IDENTIFIER (yyvsp[-1].ttype);
if (t && IDENTIFIER_TEMPLATE (t))
@@ -5946,12 +5968,12 @@ case 418:
#endif
;
break;}
-case 419:
-#line 2426 "parse.y"
+case 422:
+#line 2468 "parse.y"
{ yyval.ttype = NULL_TREE; ;
break;}
-case 420:
-#line 2428 "parse.y"
+case 423:
+#line 2470 "parse.y"
{
if (current_aggr == signature_type_node)
yyval.ttype = build_tree_list ((tree) access_public, yyval.ttype);
@@ -5959,8 +5981,8 @@ case 420:
yyval.ttype = build_tree_list ((tree) access_default, yyval.ttype);
;
break;}
-case 421:
-#line 2435 "parse.y"
+case 424:
+#line 2477 "parse.y"
{
tree visspec = (tree) yyvsp[-2].itype;
@@ -5972,20 +5994,20 @@ case 421:
yyval.ttype = chainon (yyval.ttype, build_tree_list (visspec, yyvsp[0].ttype));
;
break;}
-case 422:
-#line 2446 "parse.y"
+case 425:
+#line 2488 "parse.y"
{
if (current_aggr == signature_type_node)
error ("access specifier not allowed in signature");
;
break;}
-case 423:
-#line 2456 "parse.y"
-{ if (yyval.ttype == void_type_node) yyval.ttype = NULL_TREE;
+case 426:
+#line 2498 "parse.y"
+{ if (yyval.ttype == void_type_node) yyval.ttype = NULL_TREE;
;
break;}
-case 424:
-#line 2459 "parse.y"
+case 427:
+#line 2501 "parse.y"
{ /* In pushdecl, we created a reverse list of names
in this binding level. Make sure that the chain
of what we're trying to add isn't the item itself
@@ -5999,64 +6021,64 @@ case 424:
}
;
break;}
-case 427:
-#line 2477 "parse.y"
+case 430:
+#line 2519 "parse.y"
{ error ("missing ';' before right brace");
yyungetc ('}', 0); ;
break;}
-case 428:
-#line 2482 "parse.y"
+case 431:
+#line 2524 "parse.y"
{ yyval.ttype = finish_method (yyval.ttype); ;
break;}
-case 429:
-#line 2484 "parse.y"
+case 432:
+#line 2526 "parse.y"
{ yyval.ttype = finish_method (yyval.ttype); ;
break;}
-case 430:
-#line 2492 "parse.y"
+case 433:
+#line 2534 "parse.y"
{
yyval.ttype = grok_x_components (yyval.ttype, yyvsp[0].ttype);
;
break;}
-case 431:
-#line 2496 "parse.y"
-{
+case 434:
+#line 2538 "parse.y"
+{
yyval.ttype = grok_x_components (yyval.ttype, yyvsp[0].ttype);
;
break;}
-case 432:
-#line 2500 "parse.y"
+case 435:
+#line 2542 "parse.y"
{ yyval.ttype = grokfield (yyval.ttype, NULL_TREE, yyvsp[-2].ttype, NULL_TREE, yyvsp[-1].ttype);
cplus_decl_attributes (yyval.ttype, yyvsp[0].ttype); ;
break;}
-case 433:
-#line 2503 "parse.y"
+case 436:
+#line 2545 "parse.y"
{ yyval.ttype = grokbitfield (NULL_TREE, NULL_TREE, yyvsp[0].ttype); ;
break;}
-case 434:
-#line 2505 "parse.y"
+case 437:
+#line 2547 "parse.y"
{ yyval.ttype = NULL_TREE; ;
break;}
-case 435:
-#line 2516 "parse.y"
+case 438:
+#line 2558 "parse.y"
{ yyval.ttype = build_parse_node (CALL_EXPR, TREE_VALUE (yyvsp[-4].ttype),
yyvsp[-2].ttype, yyvsp[0].ttype);
yyval.ttype = grokfield (yyval.ttype, TREE_CHAIN (yyvsp[-4].ttype), NULL_TREE, NULL_TREE,
NULL_TREE); ;
break;}
-case 436:
-#line 2521 "parse.y"
+case 439:
+#line 2563 "parse.y"
{ yyval.ttype = build_parse_node (CALL_EXPR, TREE_VALUE (yyvsp[-2].ttype),
empty_parms (), yyvsp[0].ttype);
yyval.ttype = grokfield (yyval.ttype, TREE_CHAIN (yyvsp[-2].ttype), NULL_TREE, NULL_TREE,
NULL_TREE); ;
break;}
-case 437:
-#line 2530 "parse.y"
+case 440:
+#line 2572 "parse.y"
{ yyval.ttype = NULL_TREE; ;
break;}
-case 439:
-#line 2533 "parse.y"
+case 442:
+#line 2575 "parse.y"
{
/* In this context, void_type_node encodes
friends. They have been recorded elsewhere. */
@@ -6066,12 +6088,12 @@ case 439:
yyval.ttype = chainon (yyval.ttype, yyvsp[0].ttype);
;
break;}
-case 440:
-#line 2545 "parse.y"
+case 443:
+#line 2587 "parse.y"
{ yyval.ttype = NULL_TREE; ;
break;}
-case 442:
-#line 2548 "parse.y"
+case 445:
+#line 2590 "parse.y"
{
/* In this context, void_type_node encodes
friends. They have been recorded elsewhere. */
@@ -6081,105 +6103,105 @@ case 442:
yyval.ttype = chainon (yyval.ttype, yyvsp[0].ttype);
;
break;}
-case 447:
-#line 2570 "parse.y"
+case 450:
+#line 2612 "parse.y"
{ current_declspecs = yyvsp[-4].ttype;
yyval.ttype = grokfield (yyval.ttype, current_declspecs, yyvsp[-2].ttype, NULL_TREE, yyvsp[-1].ttype);
cplus_decl_attributes (yyval.ttype, yyvsp[0].ttype); ;
break;}
-case 448:
-#line 2574 "parse.y"
+case 451:
+#line 2616 "parse.y"
{ current_declspecs = yyvsp[-6].ttype;
yyval.ttype = grokfield (yyval.ttype, current_declspecs, yyvsp[-4].ttype, yyvsp[0].ttype, yyvsp[-3].ttype);
cplus_decl_attributes (yyval.ttype, yyvsp[-2].ttype); ;
break;}
-case 449:
-#line 2578 "parse.y"
+case 452:
+#line 2620 "parse.y"
{ current_declspecs = yyvsp[-4].ttype;
yyval.ttype = grokbitfield (yyval.ttype, current_declspecs, yyvsp[-1].ttype);
cplus_decl_attributes (yyval.ttype, yyvsp[0].ttype); ;
break;}
-case 450:
-#line 2585 "parse.y"
+case 453:
+#line 2627 "parse.y"
{ current_declspecs = yyvsp[-4].ttype;
yyval.ttype = grokfield (yyval.ttype, current_declspecs, yyvsp[-2].ttype, NULL_TREE, yyvsp[-1].ttype);
cplus_decl_attributes (yyval.ttype, yyvsp[0].ttype); ;
break;}
-case 451:
-#line 2589 "parse.y"
+case 454:
+#line 2631 "parse.y"
{ current_declspecs = yyvsp[-6].ttype;
yyval.ttype = grokfield (yyval.ttype, current_declspecs, yyvsp[-4].ttype, yyvsp[0].ttype, yyvsp[-3].ttype);
cplus_decl_attributes (yyval.ttype, yyvsp[-2].ttype); ;
break;}
-case 452:
-#line 2593 "parse.y"
+case 455:
+#line 2635 "parse.y"
{ current_declspecs = yyvsp[-4].ttype;
yyval.ttype = grokbitfield (yyval.ttype, current_declspecs, yyvsp[-1].ttype);
cplus_decl_attributes (yyval.ttype, yyvsp[0].ttype); ;
break;}
-case 453:
-#line 2597 "parse.y"
+case 456:
+#line 2639 "parse.y"
{ current_declspecs = yyvsp[-3].ttype;
yyval.ttype = grokbitfield (NULL_TREE, current_declspecs, yyvsp[-1].ttype);
cplus_decl_attributes (yyval.ttype, yyvsp[0].ttype); ;
break;}
-case 454:
-#line 2604 "parse.y"
+case 457:
+#line 2646 "parse.y"
{ yyval.ttype = grokfield (yyval.ttype, current_declspecs, yyvsp[-2].ttype, NULL_TREE, yyvsp[-1].ttype);
cplus_decl_attributes (yyval.ttype, yyvsp[0].ttype); ;
break;}
-case 455:
-#line 2607 "parse.y"
+case 458:
+#line 2649 "parse.y"
{ yyval.ttype = grokfield (yyval.ttype, current_declspecs, yyvsp[-4].ttype, yyvsp[0].ttype, yyvsp[-3].ttype);
cplus_decl_attributes (yyval.ttype, yyvsp[-2].ttype); ;
break;}
-case 456:
-#line 2610 "parse.y"
+case 459:
+#line 2652 "parse.y"
{ yyval.ttype = grokbitfield (yyval.ttype, current_declspecs, yyvsp[-1].ttype);
cplus_decl_attributes (yyval.ttype, yyvsp[0].ttype); ;
break;}
-case 457:
-#line 2616 "parse.y"
+case 460:
+#line 2658 "parse.y"
{ yyval.ttype = grokfield (yyval.ttype, current_declspecs, yyvsp[-2].ttype, NULL_TREE, yyvsp[-1].ttype);
cplus_decl_attributes (yyval.ttype, yyvsp[0].ttype); ;
break;}
-case 458:
-#line 2619 "parse.y"
+case 461:
+#line 2661 "parse.y"
{ yyval.ttype = grokfield (yyval.ttype, current_declspecs, yyvsp[-4].ttype, yyvsp[0].ttype, yyvsp[-3].ttype);
cplus_decl_attributes (yyval.ttype, yyvsp[-2].ttype); ;
break;}
-case 459:
-#line 2622 "parse.y"
+case 462:
+#line 2664 "parse.y"
{ yyval.ttype = grokbitfield (yyval.ttype, current_declspecs, yyvsp[-1].ttype);
cplus_decl_attributes (yyval.ttype, yyvsp[0].ttype); ;
break;}
-case 460:
-#line 2625 "parse.y"
+case 463:
+#line 2667 "parse.y"
{ yyval.ttype = grokbitfield (NULL_TREE, current_declspecs, yyvsp[-1].ttype);
cplus_decl_attributes (yyval.ttype, yyvsp[0].ttype); ;
break;}
-case 462:
-#line 2636 "parse.y"
+case 465:
+#line 2678 "parse.y"
{ TREE_CHAIN (yyvsp[0].ttype) = yyval.ttype; yyval.ttype = yyvsp[0].ttype; ;
break;}
-case 463:
-#line 2641 "parse.y"
+case 466:
+#line 2683 "parse.y"
{ yyval.ttype = build_enumerator (yyval.ttype, NULL_TREE); ;
break;}
-case 464:
-#line 2643 "parse.y"
+case 467:
+#line 2685 "parse.y"
{ yyval.ttype = build_enumerator (yyval.ttype, yyvsp[0].ttype); ;
break;}
-case 465:
-#line 2649 "parse.y"
+case 468:
+#line 2691 "parse.y"
{ yyval.ttype = build_decl_list (yyval.ttype, yyvsp[0].ttype); ;
break;}
-case 466:
-#line 2651 "parse.y"
+case 469:
+#line 2693 "parse.y"
{ yyval.ttype = build_decl_list (yyval.ttype, NULL_TREE); ;
break;}
-case 467:
-#line 2655 "parse.y"
+case 470:
+#line 2697 "parse.y"
{
if (flag_ansi)
pedwarn ("ANSI C++ forbids array dimensions with parenthesized type in new");
@@ -6187,54 +6209,54 @@ case 467:
yyval.ttype = build_decl_list (TREE_PURPOSE (yyvsp[-4].ttype), yyval.ttype);
;
break;}
-case 468:
-#line 2665 "parse.y"
+case 471:
+#line 2707 "parse.y"
{ yyval.ttype = NULL_TREE; ;
break;}
-case 469:
-#line 2667 "parse.y"
+case 472:
+#line 2709 "parse.y"
{ yyval.ttype = decl_tree_cons (NULL_TREE, yyvsp[0].ttype, yyval.ttype); ;
break;}
-case 470:
-#line 2672 "parse.y"
+case 473:
+#line 2714 "parse.y"
{ yyval.ttype = IDENTIFIER_AS_LIST (yyval.ttype); ;
break;}
-case 471:
-#line 2674 "parse.y"
+case 474:
+#line 2716 "parse.y"
{ yyval.ttype = decl_tree_cons (NULL_TREE, yyvsp[0].ttype, yyval.ttype); ;
break;}
-case 472:
-#line 2682 "parse.y"
+case 475:
+#line 2724 "parse.y"
{ yyval.itype = suspend_momentary (); ;
break;}
-case 473:
-#line 2683 "parse.y"
+case 476:
+#line 2725 "parse.y"
{ resume_momentary ((int) yyvsp[-1].itype); yyval.ttype = yyvsp[0].ttype; ;
break;}
-case 474:
-#line 2690 "parse.y"
+case 477:
+#line 2732 "parse.y"
{ yyval.ttype = make_pointer_declarator (yyvsp[-1].ttype, yyvsp[0].ttype); ;
break;}
-case 475:
-#line 2692 "parse.y"
+case 478:
+#line 2734 "parse.y"
{ yyval.ttype = make_reference_declarator (yyvsp[-1].ttype, yyvsp[0].ttype); ;
break;}
-case 476:
-#line 2694 "parse.y"
+case 479:
+#line 2736 "parse.y"
{ yyval.ttype = make_pointer_declarator (NULL_TREE, yyvsp[0].ttype); ;
break;}
-case 477:
-#line 2696 "parse.y"
+case 480:
+#line 2738 "parse.y"
{ yyval.ttype = make_reference_declarator (NULL_TREE, yyvsp[0].ttype); ;
break;}
-case 478:
-#line 2698 "parse.y"
+case 481:
+#line 2740 "parse.y"
{ tree arg = make_pointer_declarator (yyvsp[-1].ttype, yyvsp[0].ttype);
yyval.ttype = build_parse_node (SCOPE_REF, yyvsp[-2].ttype, arg);
;
break;}
-case 480:
-#line 2706 "parse.y"
+case 483:
+#line 2748 "parse.y"
{
/* Remember that this name has been used in the class
definition, as per [class.scope0] */
@@ -6248,313 +6270,313 @@ case 480:
}
;
break;}
-case 482:
-#line 2723 "parse.y"
+case 485:
+#line 2765 "parse.y"
{ yyval.ttype = yyvsp[0].ttype; ;
break;}
-case 483:
-#line 2728 "parse.y"
+case 486:
+#line 2770 "parse.y"
{ yyval.ttype = build_parse_node (CALL_EXPR, yyval.ttype, yyvsp[-2].ttype, yyvsp[0].ttype); ;
break;}
-case 484:
-#line 2730 "parse.y"
+case 487:
+#line 2772 "parse.y"
{ yyval.ttype = build_parse_node (CALL_EXPR, yyval.ttype, yyvsp[-2].ttype, yyvsp[0].ttype); ;
break;}
-case 485:
-#line 2732 "parse.y"
+case 488:
+#line 2774 "parse.y"
{ yyval.ttype = build_parse_node (CALL_EXPR, yyval.ttype, empty_parms (), yyvsp[0].ttype); ;
break;}
-case 486:
-#line 2734 "parse.y"
+case 489:
+#line 2776 "parse.y"
{ yyval.ttype = build_parse_node (CALL_EXPR, yyval.ttype, NULL_TREE, NULL_TREE); ;
break;}
-case 487:
-#line 2736 "parse.y"
+case 490:
+#line 2778 "parse.y"
{ yyval.ttype = build_parse_node (ARRAY_REF, yyval.ttype, yyvsp[-1].ttype); ;
break;}
-case 488:
-#line 2738 "parse.y"
+case 491:
+#line 2780 "parse.y"
{ yyval.ttype = build_parse_node (ARRAY_REF, yyval.ttype, NULL_TREE); ;
break;}
-case 489:
-#line 2740 "parse.y"
+case 492:
+#line 2782 "parse.y"
{ yyval.ttype = yyvsp[-1].ttype; ;
break;}
-case 490:
-#line 2742 "parse.y"
+case 493:
+#line 2784 "parse.y"
{ push_nested_class (TREE_TYPE (yyval.ttype), 3);
yyval.ttype = build_parse_node (SCOPE_REF, yyval.ttype, yyvsp[0].ttype);
TREE_COMPLEXITY (yyval.ttype) = current_class_depth; ;
break;}
-case 492:
-#line 2753 "parse.y"
+case 495:
+#line 2795 "parse.y"
{ yyval.ttype = make_pointer_declarator (yyvsp[-1].ttype, yyvsp[0].ttype); ;
break;}
-case 493:
-#line 2755 "parse.y"
+case 496:
+#line 2797 "parse.y"
{ yyval.ttype = make_reference_declarator (yyvsp[-1].ttype, yyvsp[0].ttype); ;
break;}
-case 494:
-#line 2757 "parse.y"
+case 497:
+#line 2799 "parse.y"
{ yyval.ttype = make_pointer_declarator (NULL_TREE, yyvsp[0].ttype); ;
break;}
-case 495:
-#line 2759 "parse.y"
+case 498:
+#line 2801 "parse.y"
{ yyval.ttype = make_reference_declarator (NULL_TREE, yyvsp[0].ttype); ;
break;}
-case 496:
-#line 2761 "parse.y"
+case 499:
+#line 2803 "parse.y"
{ tree arg = make_pointer_declarator (yyvsp[-1].ttype, yyvsp[0].ttype);
yyval.ttype = build_parse_node (SCOPE_REF, yyvsp[-2].ttype, arg);
;
break;}
-case 498:
-#line 2769 "parse.y"
+case 501:
+#line 2811 "parse.y"
{ yyval.ttype = make_pointer_declarator (yyvsp[-1].ttype, yyvsp[0].ttype); ;
break;}
-case 499:
-#line 2771 "parse.y"
+case 502:
+#line 2813 "parse.y"
{ yyval.ttype = make_reference_declarator (yyvsp[-1].ttype, yyvsp[0].ttype); ;
break;}
-case 500:
-#line 2773 "parse.y"
+case 503:
+#line 2815 "parse.y"
{ yyval.ttype = make_pointer_declarator (NULL_TREE, yyvsp[0].ttype); ;
break;}
-case 501:
-#line 2775 "parse.y"
+case 504:
+#line 2817 "parse.y"
{ yyval.ttype = make_reference_declarator (NULL_TREE, yyvsp[0].ttype); ;
break;}
-case 502:
-#line 2777 "parse.y"
+case 505:
+#line 2819 "parse.y"
{ tree arg = make_pointer_declarator (yyvsp[-1].ttype, yyvsp[0].ttype);
yyval.ttype = build_parse_node (SCOPE_REF, yyvsp[-2].ttype, arg);
;
break;}
-case 504:
-#line 2785 "parse.y"
+case 507:
+#line 2827 "parse.y"
{ yyval.ttype = build_parse_node (CALL_EXPR, yyval.ttype, yyvsp[-2].ttype, yyvsp[0].ttype); ;
break;}
-case 505:
-#line 2787 "parse.y"
+case 508:
+#line 2829 "parse.y"
{ yyval.ttype = build_parse_node (CALL_EXPR, yyval.ttype, yyvsp[-2].ttype, yyvsp[0].ttype); ;
break;}
-case 506:
-#line 2789 "parse.y"
+case 509:
+#line 2831 "parse.y"
{ yyval.ttype = build_parse_node (CALL_EXPR, yyval.ttype, empty_parms (), yyvsp[0].ttype); ;
break;}
-case 507:
-#line 2791 "parse.y"
+case 510:
+#line 2833 "parse.y"
{ yyval.ttype = build_parse_node (CALL_EXPR, yyval.ttype, NULL_TREE, NULL_TREE); ;
break;}
-case 508:
-#line 2793 "parse.y"
+case 511:
+#line 2835 "parse.y"
{ yyval.ttype = finish_decl_parsing (yyvsp[-1].ttype); ;
break;}
-case 509:
-#line 2795 "parse.y"
+case 512:
+#line 2837 "parse.y"
{ yyval.ttype = yyvsp[-1].ttype; ;
break;}
-case 510:
-#line 2797 "parse.y"
+case 513:
+#line 2839 "parse.y"
{ yyval.ttype = build_parse_node (ARRAY_REF, yyval.ttype, yyvsp[-1].ttype); ;
break;}
-case 511:
-#line 2799 "parse.y"
+case 514:
+#line 2841 "parse.y"
{ yyval.ttype = build_parse_node (ARRAY_REF, yyval.ttype, NULL_TREE); ;
break;}
-case 512:
-#line 2804 "parse.y"
+case 515:
+#line 2846 "parse.y"
{ got_scope = NULL_TREE;
yyval.ttype = build_parse_node (SCOPE_REF, yyval.ttype, yyvsp[0].ttype); ;
break;}
-case 513:
-#line 2810 "parse.y"
+case 516:
+#line 2852 "parse.y"
{ got_scope = NULL_TREE;
yyval.ttype = build_parse_node (SCOPE_REF, yyval.ttype, yyvsp[0].ttype); ;
break;}
-case 515:
-#line 2817 "parse.y"
+case 518:
+#line 2859 "parse.y"
{ yyval.ttype = yyvsp[0].ttype; ;
break;}
-case 516:
-#line 2822 "parse.y"
+case 519:
+#line 2864 "parse.y"
{ yyval.ttype = build_functional_cast (yyval.ttype, yyvsp[-1].ttype); ;
break;}
-case 517:
-#line 2824 "parse.y"
+case 520:
+#line 2866 "parse.y"
{ yyval.ttype = reparse_decl_as_expr (yyval.ttype, yyvsp[-1].ttype); ;
break;}
-case 518:
-#line 2826 "parse.y"
+case 521:
+#line 2868 "parse.y"
{ yyval.ttype = reparse_absdcl_as_expr (yyval.ttype, yyvsp[0].ttype); ;
break;}
-case 522:
-#line 2837 "parse.y"
+case 525:
+#line 2879 "parse.y"
{ yyval.ttype = yyvsp[0].ttype; ;
break;}
-case 523:
-#line 2844 "parse.y"
+case 526:
+#line 2886 "parse.y"
{ got_scope = TREE_TYPE (yyval.ttype); ;
break;}
-case 524:
-#line 2846 "parse.y"
+case 527:
+#line 2888 "parse.y"
{ got_scope = TREE_TYPE (yyval.ttype); ;
break;}
-case 526:
-#line 2862 "parse.y"
+case 529:
+#line 2904 "parse.y"
{ yyval.ttype = yyvsp[0].ttype; ;
break;}
-case 528:
-#line 2868 "parse.y"
+case 531:
+#line 2910 "parse.y"
{ yyval.ttype = yyvsp[0].ttype; ;
break;}
-case 529:
-#line 2873 "parse.y"
+case 532:
+#line 2915 "parse.y"
{ got_scope = NULL_TREE; ;
break;}
-case 530:
-#line 2875 "parse.y"
+case 533:
+#line 2917 "parse.y"
{ yyval.ttype = yyvsp[-1].ttype; got_scope = NULL_TREE; ;
break;}
-case 531:
-#line 2882 "parse.y"
+case 534:
+#line 2924 "parse.y"
{ got_scope = void_type_node; ;
break;}
-case 532:
-#line 2888 "parse.y"
+case 535:
+#line 2930 "parse.y"
{ yyval.ttype = make_pointer_declarator (yyvsp[-1].ttype, yyvsp[0].ttype); ;
break;}
-case 533:
-#line 2890 "parse.y"
+case 536:
+#line 2932 "parse.y"
{ yyval.ttype = make_pointer_declarator (yyvsp[0].ttype, NULL_TREE); ;
break;}
-case 534:
-#line 2892 "parse.y"
+case 537:
+#line 2934 "parse.y"
{ yyval.ttype = make_reference_declarator (yyvsp[-1].ttype, yyvsp[0].ttype); ;
break;}
-case 535:
-#line 2894 "parse.y"
+case 538:
+#line 2936 "parse.y"
{ yyval.ttype = make_reference_declarator (yyvsp[0].ttype, NULL_TREE); ;
break;}
-case 536:
-#line 2896 "parse.y"
+case 539:
+#line 2938 "parse.y"
{ tree arg = make_pointer_declarator (yyvsp[0].ttype, NULL_TREE);
yyval.ttype = build_parse_node (SCOPE_REF, yyvsp[-1].ttype, arg);
;
break;}
-case 537:
-#line 2900 "parse.y"
+case 540:
+#line 2942 "parse.y"
{ tree arg = make_pointer_declarator (yyvsp[-1].ttype, yyvsp[0].ttype);
yyval.ttype = build_parse_node (SCOPE_REF, yyvsp[-2].ttype, arg);
;
break;}
-case 539:
-#line 2909 "parse.y"
+case 542:
+#line 2951 "parse.y"
{ yyval.ttype = build_parse_node (ARRAY_REF, NULL_TREE, yyvsp[-1].ttype); ;
break;}
-case 540:
-#line 2911 "parse.y"
+case 543:
+#line 2953 "parse.y"
{ yyval.ttype = build_parse_node (ARRAY_REF, yyval.ttype, yyvsp[-1].ttype); ;
break;}
-case 541:
-#line 2917 "parse.y"
+case 544:
+#line 2959 "parse.y"
{ yyval.ttype = make_pointer_declarator (yyvsp[-1].ttype, yyvsp[0].ttype); ;
break;}
-case 542:
-#line 2919 "parse.y"
+case 545:
+#line 2961 "parse.y"
{ yyval.ttype = make_pointer_declarator (NULL_TREE, yyvsp[0].ttype); ;
break;}
-case 543:
-#line 2921 "parse.y"
+case 546:
+#line 2963 "parse.y"
{ yyval.ttype = make_pointer_declarator (yyvsp[0].ttype, NULL_TREE); ;
break;}
-case 544:
-#line 2923 "parse.y"
+case 547:
+#line 2965 "parse.y"
{ yyval.ttype = make_pointer_declarator (NULL_TREE, NULL_TREE); ;
break;}
-case 545:
-#line 2925 "parse.y"
+case 548:
+#line 2967 "parse.y"
{ yyval.ttype = make_reference_declarator (yyvsp[-1].ttype, yyvsp[0].ttype); ;
break;}
-case 546:
-#line 2927 "parse.y"
+case 549:
+#line 2969 "parse.y"
{ yyval.ttype = make_reference_declarator (NULL_TREE, yyvsp[0].ttype); ;
break;}
-case 547:
-#line 2929 "parse.y"
+case 550:
+#line 2971 "parse.y"
{ yyval.ttype = make_reference_declarator (yyvsp[0].ttype, NULL_TREE); ;
break;}
-case 548:
-#line 2931 "parse.y"
+case 551:
+#line 2973 "parse.y"
{ yyval.ttype = make_reference_declarator (NULL_TREE, NULL_TREE); ;
break;}
-case 549:
-#line 2933 "parse.y"
+case 552:
+#line 2975 "parse.y"
{ tree arg = make_pointer_declarator (yyvsp[0].ttype, NULL_TREE);
yyval.ttype = build_parse_node (SCOPE_REF, yyvsp[-1].ttype, arg);
;
break;}
-case 550:
-#line 2937 "parse.y"
+case 553:
+#line 2979 "parse.y"
{ tree arg = make_pointer_declarator (yyvsp[-1].ttype, yyvsp[0].ttype);
yyval.ttype = build_parse_node (SCOPE_REF, yyvsp[-2].ttype, arg);
;
break;}
-case 552:
-#line 2946 "parse.y"
+case 555:
+#line 2988 "parse.y"
{ yyval.ttype = yyvsp[-1].ttype; ;
break;}
-case 554:
-#line 2950 "parse.y"
+case 557:
+#line 2992 "parse.y"
{ yyval.ttype = build_parse_node (CALL_EXPR, yyval.ttype, yyvsp[-2].ttype, yyvsp[0].ttype); ;
break;}
-case 555:
-#line 2952 "parse.y"
+case 558:
+#line 2994 "parse.y"
{ yyval.ttype = build_parse_node (CALL_EXPR, yyval.ttype, empty_parms (), yyvsp[0].ttype); ;
break;}
-case 556:
-#line 2954 "parse.y"
+case 559:
+#line 2996 "parse.y"
{ yyval.ttype = build_parse_node (ARRAY_REF, yyval.ttype, yyvsp[-1].ttype); ;
break;}
-case 557:
-#line 2956 "parse.y"
+case 560:
+#line 2998 "parse.y"
{ yyval.ttype = build_parse_node (ARRAY_REF, yyval.ttype, NULL_TREE); ;
break;}
-case 558:
-#line 2958 "parse.y"
+case 561:
+#line 3000 "parse.y"
{ yyval.ttype = build_parse_node (CALL_EXPR, NULL_TREE, yyvsp[-2].ttype, yyvsp[0].ttype); ;
break;}
-case 559:
-#line 2960 "parse.y"
+case 562:
+#line 3002 "parse.y"
{ TREE_OPERAND (yyval.ttype, 2) = yyvsp[0].ttype; ;
break;}
-case 560:
-#line 2962 "parse.y"
+case 563:
+#line 3004 "parse.y"
{ TREE_OPERAND (yyval.ttype, 2) = yyvsp[0].ttype; ;
break;}
-case 561:
-#line 2964 "parse.y"
+case 564:
+#line 3006 "parse.y"
{ yyval.ttype = build_parse_node (ARRAY_REF, NULL_TREE, yyvsp[-1].ttype); ;
break;}
-case 562:
-#line 2966 "parse.y"
+case 565:
+#line 3008 "parse.y"
{ yyval.ttype = build_parse_node (ARRAY_REF, NULL_TREE, NULL_TREE); ;
break;}
-case 568:
-#line 2988 "parse.y"
+case 571:
+#line 3030 "parse.y"
{ emit_line_note (input_filename, lineno);
pushlevel (0);
clear_last_expr ();
push_momentary ();
expand_start_bindings (0); ;
break;}
-case 570:
-#line 3000 "parse.y"
+case 573:
+#line 3042 "parse.y"
{ if (flag_ansi)
pedwarn ("ANSI C++ forbids label declarations"); ;
break;}
-case 573:
-#line 3011 "parse.y"
+case 576:
+#line 3053 "parse.y"
{ tree link;
for (link = yyvsp[-1].ttype; link; link = TREE_CHAIN (link))
{
@@ -6564,63 +6586,63 @@ case 573:
}
;
break;}
-case 574:
-#line 3025 "parse.y"
+case 577:
+#line 3067 "parse.y"
{;
break;}
-case 576:
-#line 3030 "parse.y"
+case 579:
+#line 3072 "parse.y"
{ expand_end_bindings (getdecls (), kept_level_p(), 1);
yyval.ttype = poplevel (kept_level_p (), 1, 0);
pop_momentary (); ;
break;}
-case 577:
-#line 3034 "parse.y"
+case 580:
+#line 3076 "parse.y"
{ expand_end_bindings (getdecls (), kept_level_p(), 1);
yyval.ttype = poplevel (kept_level_p (), 1, 0);
pop_momentary (); ;
break;}
-case 578:
-#line 3038 "parse.y"
+case 581:
+#line 3080 "parse.y"
{ expand_end_bindings (getdecls (), kept_level_p(), 1);
yyval.ttype = poplevel (kept_level_p (), 0, 0);
pop_momentary (); ;
break;}
-case 579:
-#line 3042 "parse.y"
+case 582:
+#line 3084 "parse.y"
{ expand_end_bindings (getdecls (), kept_level_p(), 1);
yyval.ttype = poplevel (kept_level_p (), 0, 0);
pop_momentary (); ;
break;}
-case 580:
-#line 3049 "parse.y"
+case 583:
+#line 3091 "parse.y"
{ cond_stmt_keyword = "if"; ;
break;}
-case 581:
-#line 3051 "parse.y"
+case 584:
+#line 3093 "parse.y"
{ emit_line_note (input_filename, lineno);
- expand_start_cond (bool_truthvalue_conversion (yyvsp[0].ttype), 0); ;
+ expand_start_cond (yyvsp[0].ttype, 0); ;
break;}
-case 583:
-#line 3058 "parse.y"
+case 586:
+#line 3100 "parse.y"
{ finish_stmt (); ;
break;}
-case 584:
-#line 3060 "parse.y"
+case 587:
+#line 3102 "parse.y"
{ expand_end_bindings (getdecls (), kept_level_p (), 1);
yyval.ttype = poplevel (kept_level_p (), 1, 0);
pop_momentary (); ;
break;}
-case 585:
-#line 3067 "parse.y"
+case 588:
+#line 3109 "parse.y"
{ finish_stmt (); ;
break;}
-case 587:
-#line 3073 "parse.y"
+case 590:
+#line 3115 "parse.y"
{ finish_stmt (); ;
break;}
-case 588:
-#line 3075 "parse.y"
+case 591:
+#line 3117 "parse.y"
{
tree expr = yyvsp[-1].ttype;
emit_line_note (input_filename, lineno);
@@ -6634,82 +6656,82 @@ case 588:
clear_momentary ();
finish_stmt (); ;
break;}
-case 589:
-#line 3088 "parse.y"
+case 592:
+#line 3130 "parse.y"
{ expand_start_else (); ;
break;}
-case 590:
-#line 3090 "parse.y"
+case 593:
+#line 3132 "parse.y"
{ expand_end_cond ();
expand_end_bindings (getdecls (), kept_level_p (), 1);
poplevel (kept_level_p (), 1, 0);
pop_momentary ();
finish_stmt (); ;
break;}
-case 591:
-#line 3096 "parse.y"
+case 594:
+#line 3138 "parse.y"
{ expand_end_cond ();
expand_end_bindings (getdecls (), kept_level_p (), 1);
poplevel (kept_level_p (), 1, 0);
pop_momentary ();
finish_stmt (); ;
break;}
-case 592:
-#line 3102 "parse.y"
+case 595:
+#line 3144 "parse.y"
{ emit_nop ();
emit_line_note (input_filename, lineno);
expand_start_loop (1);
cond_stmt_keyword = "while"; ;
break;}
-case 593:
-#line 3107 "parse.y"
-{ expand_exit_loop_if_false (0, bool_truthvalue_conversion (yyvsp[0].ttype)); ;
+case 596:
+#line 3149 "parse.y"
+{ expand_exit_loop_if_false (0, yyvsp[0].ttype); ;
break;}
-case 594:
-#line 3109 "parse.y"
+case 597:
+#line 3151 "parse.y"
{ expand_end_bindings (getdecls (), kept_level_p (), 1);
poplevel (kept_level_p (), 1, 0);
pop_momentary ();
expand_end_loop ();
finish_stmt (); ;
break;}
-case 595:
-#line 3115 "parse.y"
+case 598:
+#line 3157 "parse.y"
{ emit_nop ();
emit_line_note (input_filename, lineno);
expand_start_loop_continue_elsewhere (1); ;
break;}
-case 596:
-#line 3119 "parse.y"
+case 599:
+#line 3161 "parse.y"
{ expand_loop_continue_here ();
cond_stmt_keyword = "do"; ;
break;}
-case 597:
-#line 3122 "parse.y"
+case 600:
+#line 3164 "parse.y"
{ emit_line_note (input_filename, lineno);
- expand_exit_loop_if_false (0, bool_truthvalue_conversion (yyvsp[-1].ttype));
+ expand_exit_loop_if_false (0, yyvsp[-1].ttype);
expand_end_loop ();
clear_momentary ();
finish_stmt (); ;
break;}
-case 598:
-#line 3128 "parse.y"
+case 601:
+#line 3170 "parse.y"
{ emit_nop ();
emit_line_note (input_filename, lineno);
if (yyvsp[0].ttype) cplus_expand_expr_stmt (yyvsp[0].ttype);
expand_start_loop_continue_elsewhere (1); ;
break;}
-case 599:
-#line 3133 "parse.y"
+case 602:
+#line 3175 "parse.y"
{ emit_line_note (input_filename, lineno);
- if (yyvsp[-1].ttype) expand_exit_loop_if_false (0, bool_truthvalue_conversion (yyvsp[-1].ttype)); ;
+ if (yyvsp[-1].ttype) expand_exit_loop_if_false (0, yyvsp[-1].ttype); ;
break;}
-case 600:
-#line 3138 "parse.y"
+case 603:
+#line 3180 "parse.y"
{ push_momentary (); ;
break;}
-case 601:
-#line 3140 "parse.y"
+case 604:
+#line 3182 "parse.y"
{ emit_line_note (input_filename, lineno);
expand_end_bindings (getdecls (), kept_level_p (), 1);
poplevel (kept_level_p (), 1, 0);
@@ -6720,24 +6742,24 @@ case 601:
expand_end_loop ();
finish_stmt (); ;
break;}
-case 602:
-#line 3150 "parse.y"
+case 605:
+#line 3192 "parse.y"
{ emit_nop ();
emit_line_note (input_filename, lineno);
expand_start_loop_continue_elsewhere (1); ;
break;}
-case 603:
-#line 3154 "parse.y"
+case 606:
+#line 3196 "parse.y"
{ emit_line_note (input_filename, lineno);
- if (yyvsp[-1].ttype) expand_exit_loop_if_false (0, bool_truthvalue_conversion (yyvsp[-1].ttype)); ;
+ if (yyvsp[-1].ttype) expand_exit_loop_if_false (0, yyvsp[-1].ttype); ;
break;}
-case 604:
-#line 3159 "parse.y"
+case 607:
+#line 3201 "parse.y"
{ push_momentary ();
yyvsp[0].itype = lineno; ;
break;}
-case 605:
-#line 3162 "parse.y"
+case 608:
+#line 3204 "parse.y"
{ emit_line_note (input_filename, (int) yyvsp[-2].itype);
expand_end_bindings (getdecls (), kept_level_p (), 1);
poplevel (kept_level_p (), 1, 0);
@@ -6749,16 +6771,16 @@ case 605:
finish_stmt ();
;
break;}
-case 606:
-#line 3173 "parse.y"
+case 609:
+#line 3215 "parse.y"
{ emit_line_note (input_filename, lineno);
- c_expand_start_case (yyvsp[-1].ttype);
+ c_expand_start_case (yyvsp[-1].ttype);
/* Don't let the tree nodes for $4 be discarded by
clear_momentary during the parsing of the next stmt. */
push_momentary (); ;
break;}
-case 607:
-#line 3179 "parse.y"
+case 610:
+#line 3221 "parse.y"
{ expand_end_case (yyvsp[-3].ttype);
pop_momentary ();
expand_end_bindings (getdecls (), kept_level_p (), 1);
@@ -6766,8 +6788,8 @@ case 607:
pop_momentary ();
finish_stmt (); ;
break;}
-case 608:
-#line 3186 "parse.y"
+case 611:
+#line 3228 "parse.y"
{ register tree value = check_cp_case_value (yyvsp[-1].ttype);
register tree label
= build_decl (LABEL_DECL, NULL_TREE, NULL_TREE);
@@ -6792,8 +6814,8 @@ case 608:
define_case_label (label);
;
break;}
-case 610:
-#line 3211 "parse.y"
+case 613:
+#line 3253 "parse.y"
{ register tree value1 = check_cp_case_value (yyvsp[-3].ttype);
register tree value2 = check_cp_case_value (yyvsp[-1].ttype);
register tree label
@@ -6825,8 +6847,8 @@ case 610:
define_case_label (label);
;
break;}
-case 612:
-#line 3243 "parse.y"
+case 615:
+#line 3285 "parse.y"
{
tree duplicate;
register tree label
@@ -6842,40 +6864,40 @@ case 612:
define_case_label (NULL_TREE);
;
break;}
-case 614:
-#line 3259 "parse.y"
+case 617:
+#line 3301 "parse.y"
{ emit_line_note (input_filename, lineno);
if ( ! expand_exit_something ())
error ("break statement not within loop or switch"); ;
break;}
-case 615:
-#line 3263 "parse.y"
+case 618:
+#line 3305 "parse.y"
{ emit_line_note (input_filename, lineno);
if (! expand_continue_loop (0))
error ("continue statement not within a loop"); ;
break;}
-case 616:
-#line 3267 "parse.y"
+case 619:
+#line 3309 "parse.y"
{ emit_line_note (input_filename, lineno);
c_expand_return (NULL_TREE); ;
break;}
-case 617:
-#line 3270 "parse.y"
+case 620:
+#line 3312 "parse.y"
{ emit_line_note (input_filename, lineno);
c_expand_return (yyvsp[-1].ttype);
finish_stmt ();
;
break;}
-case 618:
-#line 3275 "parse.y"
+case 621:
+#line 3317 "parse.y"
{ if (TREE_CHAIN (yyvsp[-2].ttype)) yyvsp[-2].ttype = combine_strings (yyvsp[-2].ttype);
emit_line_note (input_filename, lineno);
expand_asm (yyvsp[-2].ttype);
finish_stmt ();
;
break;}
-case 619:
-#line 3282 "parse.y"
+case 622:
+#line 3324 "parse.y"
{ if (TREE_CHAIN (yyvsp[-4].ttype)) yyvsp[-4].ttype = combine_strings (yyvsp[-4].ttype);
emit_line_note (input_filename, lineno);
c_expand_asm_operands (yyvsp[-4].ttype, yyvsp[-2].ttype, NULL_TREE, NULL_TREE,
@@ -6884,8 +6906,8 @@ case 619:
finish_stmt ();
;
break;}
-case 620:
-#line 3291 "parse.y"
+case 623:
+#line 3333 "parse.y"
{ if (TREE_CHAIN (yyvsp[-6].ttype)) yyvsp[-6].ttype = combine_strings (yyvsp[-6].ttype);
emit_line_note (input_filename, lineno);
c_expand_asm_operands (yyvsp[-6].ttype, yyvsp[-4].ttype, yyvsp[-2].ttype, NULL_TREE,
@@ -6894,8 +6916,8 @@ case 620:
finish_stmt ();
;
break;}
-case 621:
-#line 3301 "parse.y"
+case 624:
+#line 3343 "parse.y"
{ if (TREE_CHAIN (yyvsp[-8].ttype)) yyvsp[-8].ttype = combine_strings (yyvsp[-8].ttype);
emit_line_note (input_filename, lineno);
c_expand_asm_operands (yyvsp[-8].ttype, yyvsp[-6].ttype, yyvsp[-4].ttype, yyvsp[-2].ttype,
@@ -6904,83 +6926,83 @@ case 621:
finish_stmt ();
;
break;}
-case 622:
-#line 3309 "parse.y"
+case 625:
+#line 3351 "parse.y"
{ emit_line_note (input_filename, lineno);
expand_computed_goto (yyvsp[-1].ttype); ;
break;}
-case 623:
-#line 3312 "parse.y"
+case 626:
+#line 3354 "parse.y"
{ tree decl;
emit_line_note (input_filename, lineno);
decl = lookup_label (yyvsp[-1].ttype);
TREE_USED (decl) = 1;
expand_goto (decl); ;
break;}
-case 624:
-#line 3318 "parse.y"
+case 627:
+#line 3360 "parse.y"
{ finish_stmt (); ;
break;}
-case 625:
-#line 3320 "parse.y"
+case 628:
+#line 3362 "parse.y"
{ error ("label must be followed by statement");
yyungetc ('}', 0);
finish_stmt (); ;
break;}
-case 626:
-#line 3324 "parse.y"
+case 629:
+#line 3366 "parse.y"
{ finish_stmt (); ;
break;}
-case 628:
-#line 3330 "parse.y"
+case 631:
+#line 3372 "parse.y"
{ expand_start_try_stmts (); ;
break;}
-case 629:
-#line 3332 "parse.y"
+case 632:
+#line 3374 "parse.y"
{ expand_end_try_stmts ();
expand_start_all_catch (); ;
break;}
-case 630:
-#line 3335 "parse.y"
+case 633:
+#line 3377 "parse.y"
{ expand_end_all_catch (); ;
break;}
-case 631:
-#line 3343 "parse.y"
+case 634:
+#line 3385 "parse.y"
{ expand_end_bindings (0,1,1);
poplevel (2,0,0);
;
break;}
-case 632:
-#line 3347 "parse.y"
+case 635:
+#line 3389 "parse.y"
{ expand_end_bindings (0,1,1);
poplevel (2,0,0);
;
break;}
-case 633:
-#line 3351 "parse.y"
+case 636:
+#line 3393 "parse.y"
{ expand_end_bindings (0,1,1);
poplevel (2,0,0);
;
break;}
-case 635:
-#line 3359 "parse.y"
+case 638:
+#line 3401 "parse.y"
{ emit_line_note (input_filename, lineno); ;
break;}
-case 636:
-#line 3361 "parse.y"
+case 639:
+#line 3403 "parse.y"
{ expand_end_catch_block (); ;
break;}
-case 639:
-#line 3371 "parse.y"
+case 642:
+#line 3413 "parse.y"
{ expand_start_catch_block (NULL_TREE, NULL_TREE); ;
break;}
-case 640:
-#line 3383 "parse.y"
+case 643:
+#line 3425 "parse.y"
{ expand_start_catch_block (TREE_PURPOSE (yyvsp[-1].ttype),
TREE_VALUE (yyvsp[-1].ttype)); ;
break;}
-case 641:
-#line 3389 "parse.y"
+case 644:
+#line 3431 "parse.y"
{ tree label;
do_label:
label = define_label (input_filename, lineno, yyvsp[-1].ttype);
@@ -6988,77 +7010,81 @@ case 641:
expand_label (label);
;
break;}
-case 642:
-#line 3396 "parse.y"
+case 645:
+#line 3438 "parse.y"
{ goto do_label; ;
break;}
-case 643:
-#line 3401 "parse.y"
+case 646:
+#line 3440 "parse.y"
+{ goto do_label; ;
+ break;}
+case 647:
+#line 3445 "parse.y"
{ yyval.ttype = NULL_TREE; ;
break;}
-case 644:
-#line 3403 "parse.y"
+case 648:
+#line 3447 "parse.y"
{ yyval.ttype = yyvsp[-1].ttype; ;
break;}
-case 645:
-#line 3405 "parse.y"
+case 649:
+#line 3449 "parse.y"
{ yyval.ttype = NULL_TREE; ;
break;}
-case 646:
-#line 3410 "parse.y"
+case 650:
+#line 3454 "parse.y"
{ yyval.itype = 0; ;
break;}
-case 647:
-#line 3412 "parse.y"
+case 651:
+#line 3456 "parse.y"
{ yyval.itype = 0; ;
break;}
-case 648:
-#line 3414 "parse.y"
+case 652:
+#line 3458 "parse.y"
{ yyval.itype = 1; ;
break;}
-case 649:
-#line 3416 "parse.y"
+case 653:
+#line 3460 "parse.y"
{ yyval.itype = -1; ;
break;}
-case 650:
-#line 3423 "parse.y"
+case 654:
+#line 3467 "parse.y"
{ emit_line_note (input_filename, lineno);
yyval.ttype = NULL_TREE; ;
break;}
-case 651:
-#line 3426 "parse.y"
+case 655:
+#line 3470 "parse.y"
{ emit_line_note (input_filename, lineno); ;
break;}
-case 652:
-#line 3431 "parse.y"
+case 656:
+#line 3475 "parse.y"
{ yyval.ttype = NULL_TREE; ;
break;}
-case 654:
-#line 3434 "parse.y"
+case 658:
+#line 3478 "parse.y"
{ yyval.ttype = NULL_TREE; ;
break;}
-case 655:
-#line 3440 "parse.y"
+case 659:
+#line 3484 "parse.y"
{ yyval.ttype = NULL_TREE; ;
break;}
-case 658:
-#line 3447 "parse.y"
+case 662:
+#line 3491 "parse.y"
{ yyval.ttype = chainon (yyval.ttype, yyvsp[0].ttype); ;
break;}
-case 659:
-#line 3452 "parse.y"
+case 663:
+#line 3496 "parse.y"
{ yyval.ttype = build_tree_list (yyval.ttype, yyvsp[-1].ttype); ;
break;}
-case 660:
-#line 3457 "parse.y"
+case 664:
+#line 3501 "parse.y"
{ yyval.ttype = tree_cons (NULL_TREE, yyval.ttype, NULL_TREE); ;
break;}
-case 661:
-#line 3459 "parse.y"
+case 665:
+#line 3503 "parse.y"
{ yyval.ttype = tree_cons (NULL_TREE, yyvsp[0].ttype, yyval.ttype); ;
break;}
-case 662:
-#line 3469 "parse.y"
+case 666:
+#line 3513 "parse.y"
{
if (strict_prototype)
yyval.ttype = void_list_node;
@@ -7066,39 +7092,39 @@ case 662:
yyval.ttype = NULL_TREE;
;
break;}
-case 664:
-#line 3477 "parse.y"
+case 668:
+#line 3521 "parse.y"
{ yyval.ttype = tree_cons (NULL_TREE, yyval.ttype, void_list_node);
TREE_PARMLIST (yyval.ttype) = 1; ;
break;}
-case 665:
-#line 3485 "parse.y"
+case 669:
+#line 3529 "parse.y"
{
yyval.ttype = chainon (yyval.ttype, void_list_node);
TREE_PARMLIST (yyval.ttype) = 1;
;
break;}
-case 666:
-#line 3490 "parse.y"
+case 670:
+#line 3534 "parse.y"
{
TREE_PARMLIST (yyval.ttype) = 1;
;
break;}
-case 667:
-#line 3495 "parse.y"
+case 671:
+#line 3539 "parse.y"
{
TREE_PARMLIST (yyval.ttype) = 1;
;
break;}
-case 668:
-#line 3499 "parse.y"
+case 672:
+#line 3543 "parse.y"
{
- yyval.ttype = build_tree_list (NULL_TREE, yyval.ttype);
+ yyval.ttype = build_tree_list (NULL_TREE, yyval.ttype);
TREE_PARMLIST (yyval.ttype) = 1;
;
break;}
-case 669:
-#line 3504 "parse.y"
+case 673:
+#line 3548 "parse.y"
{
/* ARM $8.2.5 has this as a boxed-off comment. */
if (pedantic)
@@ -7106,27 +7132,27 @@ case 669:
yyval.ttype = NULL_TREE;
;
break;}
-case 670:
-#line 3511 "parse.y"
+case 674:
+#line 3555 "parse.y"
{
TREE_PARMLIST (yyval.ttype) = 1;
;
break;}
-case 671:
-#line 3515 "parse.y"
+case 675:
+#line 3559 "parse.y"
{
TREE_PARMLIST (yyval.ttype) = 1;
;
break;}
-case 672:
-#line 3519 "parse.y"
+case 676:
+#line 3563 "parse.y"
{
yyval.ttype = build_tree_list (NULL_TREE, yyval.ttype);
TREE_PARMLIST (yyval.ttype) = 1;
;
break;}
-case 673:
-#line 3524 "parse.y"
+case 677:
+#line 3568 "parse.y"
{
/* This helps us recover from really nasty
parse errors, for example, a missing right
@@ -7138,8 +7164,8 @@ case 673:
yychar = ')';
;
break;}
-case 674:
-#line 3535 "parse.y"
+case 678:
+#line 3579 "parse.y"
{
/* This helps us recover from really nasty
parse errors, for example, a missing right
@@ -7151,260 +7177,264 @@ case 674:
yychar = ')';
;
break;}
-case 675:
-#line 3550 "parse.y"
+case 679:
+#line 3594 "parse.y"
{ yyval.ttype = build_tree_list (NULL_TREE, yyval.ttype); ;
break;}
-case 676:
-#line 3552 "parse.y"
+case 680:
+#line 3596 "parse.y"
{ yyval.ttype = build_tree_list (yyvsp[0].ttype, yyval.ttype); ;
break;}
-case 677:
-#line 3554 "parse.y"
-{ yyval.ttype = chainon (yyval.ttype, build_tree_list (NULL_TREE, yyvsp[0].ttype)); ;
- break;}
-case 678:
-#line 3556 "parse.y"
-{ yyval.ttype = chainon (yyval.ttype, build_tree_list (yyvsp[0].ttype, yyvsp[-2].ttype)); ;
+case 681:
+#line 3598 "parse.y"
+{ yyval.ttype = chainon (yyval.ttype, yyvsp[0].ttype); ;
break;}
-case 679:
-#line 3558 "parse.y"
+case 682:
+#line 3600 "parse.y"
{ yyval.ttype = chainon (yyval.ttype, build_tree_list (NULL_TREE, yyvsp[0].ttype)); ;
break;}
-case 680:
-#line 3560 "parse.y"
+case 683:
+#line 3602 "parse.y"
{ yyval.ttype = chainon (yyval.ttype, build_tree_list (yyvsp[0].ttype, yyvsp[-2].ttype)); ;
break;}
-case 682:
-#line 3566 "parse.y"
+case 685:
+#line 3608 "parse.y"
{ yyval.ttype = build_tree_list (NULL_TREE, yyval.ttype); ;
break;}
-case 683:
-#line 3589 "parse.y"
+case 686:
+#line 3631 "parse.y"
{ yyval.ttype = build_tree_list (yyval.ttype, yyvsp[0].ttype); ;
break;}
-case 684:
-#line 3591 "parse.y"
+case 687:
+#line 3633 "parse.y"
{ yyval.ttype = build_tree_list (yyval.ttype, yyvsp[0].ttype); ;
break;}
-case 685:
-#line 3593 "parse.y"
+case 688:
+#line 3635 "parse.y"
{ yyval.ttype = build_tree_list (get_decl_list (yyval.ttype), yyvsp[0].ttype); ;
break;}
-case 686:
-#line 3595 "parse.y"
+case 689:
+#line 3637 "parse.y"
{ yyval.ttype = build_tree_list (yyval.ttype, yyvsp[0].ttype); ;
break;}
-case 687:
-#line 3597 "parse.y"
+case 690:
+#line 3639 "parse.y"
{ yyval.ttype = build_tree_list (yyval.ttype, NULL_TREE); ;
break;}
-case 688:
-#line 3599 "parse.y"
+case 691:
+#line 3641 "parse.y"
{ yyval.ttype = build_tree_list (yyval.ttype, yyvsp[0].ttype); ;
break;}
-case 691:
-#line 3608 "parse.y"
+case 692:
+#line 3646 "parse.y"
+{ yyval.ttype = build_tree_list (NULL_TREE, yyval.ttype); ;
+ break;}
+case 693:
+#line 3648 "parse.y"
+{ yyval.ttype = build_tree_list (yyvsp[0].ttype, yyval.ttype); ;
+ break;}
+case 696:
+#line 3657 "parse.y"
{ see_typename (); ;
break;}
-case 692:
-#line 3631 "parse.y"
+case 697:
+#line 3680 "parse.y"
{
warning ("type specifier omitted for parameter");
yyval.ttype = build_tree_list (TREE_PURPOSE (TREE_VALUE (yyvsp[-1].ttype)), NULL_TREE);
;
break;}
-case 693:
-#line 3636 "parse.y"
+case 698:
+#line 3685 "parse.y"
{
warning ("type specifier omitted for parameter");
yyval.ttype = build_tree_list (TREE_PURPOSE (TREE_VALUE (yyvsp[-2].ttype)), yyval.ttype);
;
break;}
-case 694:
-#line 3644 "parse.y"
+case 699:
+#line 3693 "parse.y"
{ yyval.ttype = NULL_TREE; ;
break;}
-case 695:
-#line 3646 "parse.y"
+case 700:
+#line 3695 "parse.y"
{ yyval.ttype = yyvsp[-1].ttype; ;
break;}
-case 696:
-#line 3651 "parse.y"
+case 701:
+#line 3700 "parse.y"
{ yyval.ttype = build_decl_list (NULL_TREE, yyval.ttype); ;
break;}
-case 698:
-#line 3657 "parse.y"
+case 703:
+#line 3706 "parse.y"
{
TREE_CHAIN (yyvsp[0].ttype) = yyval.ttype;
yyval.ttype = yyvsp[0].ttype;
;
break;}
-case 699:
-#line 3665 "parse.y"
+case 704:
+#line 3714 "parse.y"
{ yyval.ttype = NULL_TREE; ;
break;}
-case 700:
-#line 3667 "parse.y"
+case 705:
+#line 3716 "parse.y"
{ yyval.ttype = make_pointer_declarator (yyvsp[-1].ttype, yyvsp[0].ttype); ;
break;}
-case 701:
-#line 3669 "parse.y"
+case 706:
+#line 3718 "parse.y"
{ yyval.ttype = make_reference_declarator (yyvsp[-1].ttype, yyvsp[0].ttype); ;
break;}
-case 702:
-#line 3671 "parse.y"
+case 707:
+#line 3720 "parse.y"
{ tree arg = make_pointer_declarator (yyvsp[-1].ttype, yyvsp[0].ttype);
yyval.ttype = build_parse_node (SCOPE_REF, yyvsp[-2].ttype, arg);
;
break;}
-case 703:
-#line 3677 "parse.y"
+case 708:
+#line 3726 "parse.y"
{ got_scope = NULL_TREE; ;
break;}
-case 704:
-#line 3682 "parse.y"
+case 709:
+#line 3731 "parse.y"
{ yyval.ttype = ansi_opname[MULT_EXPR]; ;
break;}
-case 705:
-#line 3684 "parse.y"
+case 710:
+#line 3733 "parse.y"
{ yyval.ttype = ansi_opname[TRUNC_DIV_EXPR]; ;
break;}
-case 706:
-#line 3686 "parse.y"
+case 711:
+#line 3735 "parse.y"
{ yyval.ttype = ansi_opname[TRUNC_MOD_EXPR]; ;
break;}
-case 707:
-#line 3688 "parse.y"
+case 712:
+#line 3737 "parse.y"
{ yyval.ttype = ansi_opname[PLUS_EXPR]; ;
break;}
-case 708:
-#line 3690 "parse.y"
+case 713:
+#line 3739 "parse.y"
{ yyval.ttype = ansi_opname[MINUS_EXPR]; ;
break;}
-case 709:
-#line 3692 "parse.y"
+case 714:
+#line 3741 "parse.y"
{ yyval.ttype = ansi_opname[BIT_AND_EXPR]; ;
break;}
-case 710:
-#line 3694 "parse.y"
+case 715:
+#line 3743 "parse.y"
{ yyval.ttype = ansi_opname[BIT_IOR_EXPR]; ;
break;}
-case 711:
-#line 3696 "parse.y"
+case 716:
+#line 3745 "parse.y"
{ yyval.ttype = ansi_opname[BIT_XOR_EXPR]; ;
break;}
-case 712:
-#line 3698 "parse.y"
+case 717:
+#line 3747 "parse.y"
{ yyval.ttype = ansi_opname[BIT_NOT_EXPR]; ;
break;}
-case 713:
-#line 3700 "parse.y"
+case 718:
+#line 3749 "parse.y"
{ yyval.ttype = ansi_opname[COMPOUND_EXPR]; ;
break;}
-case 714:
-#line 3702 "parse.y"
+case 719:
+#line 3751 "parse.y"
{ yyval.ttype = ansi_opname[yyvsp[0].code]; ;
break;}
-case 715:
-#line 3704 "parse.y"
+case 720:
+#line 3753 "parse.y"
{ yyval.ttype = ansi_opname[LT_EXPR]; ;
break;}
-case 716:
-#line 3706 "parse.y"
+case 721:
+#line 3755 "parse.y"
{ yyval.ttype = ansi_opname[GT_EXPR]; ;
break;}
-case 717:
-#line 3708 "parse.y"
+case 722:
+#line 3757 "parse.y"
{ yyval.ttype = ansi_opname[yyvsp[0].code]; ;
break;}
-case 718:
-#line 3710 "parse.y"
+case 723:
+#line 3759 "parse.y"
{ yyval.ttype = ansi_assopname[yyvsp[0].code]; ;
break;}
-case 719:
-#line 3712 "parse.y"
+case 724:
+#line 3761 "parse.y"
{ yyval.ttype = ansi_opname [MODIFY_EXPR]; ;
break;}
-case 720:
-#line 3714 "parse.y"
+case 725:
+#line 3763 "parse.y"
{ yyval.ttype = ansi_opname[yyvsp[0].code]; ;
break;}
-case 721:
-#line 3716 "parse.y"
+case 726:
+#line 3765 "parse.y"
{ yyval.ttype = ansi_opname[yyvsp[0].code]; ;
break;}
-case 722:
-#line 3718 "parse.y"
+case 727:
+#line 3767 "parse.y"
{ yyval.ttype = ansi_opname[POSTINCREMENT_EXPR]; ;
break;}
-case 723:
-#line 3720 "parse.y"
+case 728:
+#line 3769 "parse.y"
{ yyval.ttype = ansi_opname[PREDECREMENT_EXPR]; ;
break;}
-case 724:
-#line 3722 "parse.y"
+case 729:
+#line 3771 "parse.y"
{ yyval.ttype = ansi_opname[TRUTH_ANDIF_EXPR]; ;
break;}
-case 725:
-#line 3724 "parse.y"
+case 730:
+#line 3773 "parse.y"
{ yyval.ttype = ansi_opname[TRUTH_ORIF_EXPR]; ;
break;}
-case 726:
-#line 3726 "parse.y"
+case 731:
+#line 3775 "parse.y"
{ yyval.ttype = ansi_opname[TRUTH_NOT_EXPR]; ;
break;}
-case 727:
-#line 3728 "parse.y"
+case 732:
+#line 3777 "parse.y"
{ yyval.ttype = ansi_opname[COND_EXPR]; ;
break;}
-case 728:
-#line 3730 "parse.y"
+case 733:
+#line 3779 "parse.y"
{ yyval.ttype = ansi_opname[yyvsp[0].code]; ;
break;}
-case 729:
-#line 3732 "parse.y"
+case 734:
+#line 3781 "parse.y"
{ yyval.ttype = ansi_opname[COMPONENT_REF]; ;
break;}
-case 730:
-#line 3734 "parse.y"
+case 735:
+#line 3783 "parse.y"
{ yyval.ttype = ansi_opname[MEMBER_REF]; ;
break;}
-case 731:
-#line 3736 "parse.y"
+case 736:
+#line 3785 "parse.y"
{ yyval.ttype = ansi_opname[CALL_EXPR]; ;
break;}
-case 732:
-#line 3738 "parse.y"
+case 737:
+#line 3787 "parse.y"
{ yyval.ttype = ansi_opname[ARRAY_REF]; ;
break;}
-case 733:
-#line 3740 "parse.y"
+case 738:
+#line 3789 "parse.y"
{ yyval.ttype = ansi_opname[NEW_EXPR]; ;
break;}
-case 734:
-#line 3742 "parse.y"
+case 739:
+#line 3791 "parse.y"
{ yyval.ttype = ansi_opname[DELETE_EXPR]; ;
break;}
-case 735:
-#line 3744 "parse.y"
+case 740:
+#line 3793 "parse.y"
{ yyval.ttype = ansi_opname[VEC_NEW_EXPR]; ;
break;}
-case 736:
-#line 3746 "parse.y"
+case 741:
+#line 3795 "parse.y"
{ yyval.ttype = ansi_opname[VEC_DELETE_EXPR]; ;
break;}
-case 737:
-#line 3749 "parse.y"
+case 742:
+#line 3798 "parse.y"
{ yyval.ttype = grokoptypename (yyvsp[-1].ttype, yyvsp[0].ttype); ;
break;}
-case 738:
-#line 3751 "parse.y"
+case 743:
+#line 3800 "parse.y"
{ yyval.ttype = ansi_opname[ERROR_MARK]; ;
break;}
}
/* the action file gets copied in in place of this dollarsign */
-#line 480 "/usr/local/lib/bison.simple"
+#line 465 "/usr/local/lib/bison.simple"
yyvsp -= yylen;
yyssp -= yylen;
@@ -7600,5 +7630,15 @@ yyerrhandle:
yystate = yyn;
goto yynewstate;
}
-#line 3754 "parse.y"
+#line 3803 "parse.y"
+
+#ifdef SPEW_DEBUG
+const char *
+debug_yytranslate (value)
+ int value;
+{
+ return yytname[YYTRANSLATE (value)];
+}
+
+#endif
diff --git a/gnu/usr.bin/cc/cc1plus/pt.c b/gnu/usr.bin/cc/cc1plus/pt.c
index c808cf4..73c34f5 100644
--- a/gnu/usr.bin/cc/cc1plus/pt.c
+++ b/gnu/usr.bin/cc/cc1plus/pt.c
@@ -81,18 +81,19 @@ process_template_parm (list, next)
{
tree parm;
tree decl = 0;
+ tree defval;
int is_type;
parm = next;
my_friendly_assert (TREE_CODE (parm) == TREE_LIST, 259);
- is_type = TREE_CODE (TREE_PURPOSE (parm)) == IDENTIFIER_NODE;
+ defval = TREE_PURPOSE (parm);
+ parm = TREE_VALUE (parm);
+ is_type = TREE_PURPOSE (parm) == class_type_node;
if (!is_type)
{
tree tinfo = 0;
- parm = TREE_PURPOSE (parm);
- my_friendly_assert (TREE_CODE (parm) == TREE_LIST, 260);
- parm = TREE_VALUE (parm);
+ my_friendly_assert (TREE_CODE (TREE_PURPOSE (parm)) == TREE_LIST, 260);
/* is a const-param */
- parm = grokdeclarator (TREE_VALUE (next), TREE_PURPOSE (next),
+ parm = grokdeclarator (TREE_VALUE (parm), TREE_PURPOSE (parm),
PARM, 0, NULL_TREE);
/* A template parameter is not modifiable. */
TREE_READONLY (parm) = 1;
@@ -117,11 +118,19 @@ process_template_parm (list, next)
else
{
tree t = make_node (TEMPLATE_TYPE_PARM);
- decl = build_decl (TYPE_DECL, TREE_PURPOSE (parm), t);
- TYPE_NAME (t) = decl;
- TREE_VALUE (parm) = t;
+ decl = build_decl (TYPE_DECL, TREE_VALUE (parm), t);
+ TYPE_MAIN_DECL (t) = decl;
+ parm = decl;
+ if (defval)
+ {
+ if (IDENTIFIER_HAS_TYPE_VALUE (defval))
+ defval = IDENTIFIER_TYPE_VALUE (defval);
+ else
+ defval = TREE_TYPE (IDENTIFIER_GLOBAL_VALUE (defval));
+ }
}
pushdecl (decl);
+ parm = build_tree_list (defval, parm);
return chainon (list, parm);
}
@@ -135,6 +144,7 @@ end_template_parm_list (parms)
tree parms;
{
int nparms = 0;
+ int saw_default = 0;
tree saved_parmlist;
tree parm;
for (parm = parms; parm; parm = TREE_CHAIN (parm))
@@ -143,13 +153,19 @@ end_template_parm_list (parms)
for (parm = parms, nparms = 0; parm; parm = TREE_CHAIN (parm), nparms++)
{
- tree p = parm;
- if (TREE_CODE (p) == TREE_LIST)
+ tree p = TREE_VALUE (parm);
+ if (TREE_PURPOSE (parm))
+ saw_default = 1;
+ else if (saw_default)
+ {
+ error ("if a default argument is given for one template parameter");
+ error ("default arguments must be given for all subsequent");
+ error ("parameters as well");
+ }
+
+ if (TREE_CODE (p) == TYPE_DECL)
{
- tree t = TREE_VALUE (p);
- TREE_VALUE (p) = NULL_TREE;
- p = TREE_PURPOSE (p);
- my_friendly_assert (TREE_CODE (p) == IDENTIFIER_NODE, 261);
+ tree t = TREE_TYPE (p);
TEMPLATE_TYPE_SET_INFO (t, saved_parmlist, nparms);
}
else
@@ -158,7 +174,7 @@ end_template_parm_list (parms)
DECL_INITIAL (p) = NULL_TREE;
TEMPLATE_CONST_SET_INFO (tinfo, saved_parmlist, nparms);
}
- TREE_VEC_ELT (saved_parmlist, nparms) = p;
+ TREE_VEC_ELT (saved_parmlist, nparms) = parm;
}
set_current_level_tags_transparency (1);
processing_template_decl++;
@@ -259,7 +275,7 @@ end_template_decl (d1, d2, is_class, defn)
/* So that duplicate_decls can do the right thing. */
if (defn)
DECL_INITIAL (decl) = error_mark_node;
-
+
/* If context of decl is non-null (i.e., method template), add it
to the appropriate class template, and pop the binding levels. */
if (! is_class && DECL_CONTEXT (DECL_TEMPLATE_RESULT (decl)) != NULL_TREE)
@@ -317,7 +333,7 @@ grok_template_type (tvec, type)
{
/* we are here for cases like const T* etc. */
grok_template_type (tvec, &TYPE_MAIN_VARIANT (*type));
- *type = c_build_type_variant (TYPE_MAIN_VARIANT (*type),
+ *type = cp_build_type_variant (TYPE_MAIN_VARIANT (*type),
TYPE_READONLY (*type),
TYPE_VOLATILE (*type));
}
@@ -331,16 +347,16 @@ grok_template_type (tvec, type)
case FUNCTION_TYPE:
{
tree p;
-
+
/* take care of function's return type first */
grok_template_type (tvec, &TREE_TYPE (*type));
-
+
/* take care of function's arguments */
for (p = TYPE_ARG_TYPES (*type); p; p = TREE_CHAIN (p))
grok_template_type (tvec, &TREE_VALUE (p));
return;
}
- default:
+ default:
break;
}
return;
@@ -354,51 +370,68 @@ coerce_template_parms (parms, arglist, in_decl)
tree parms, arglist;
tree in_decl;
{
- int nparms, i, lost = 0;
+ int nparms, nargs, i, lost = 0;
tree vec;
- if (TREE_CODE (arglist) == TREE_VEC)
- nparms = TREE_VEC_LENGTH (arglist);
+ if (arglist == NULL_TREE)
+ nargs = 0;
+ else if (TREE_CODE (arglist) == TREE_VEC)
+ nargs = TREE_VEC_LENGTH (arglist);
else
- nparms = list_length (arglist);
- if (nparms != TREE_VEC_LENGTH (parms))
+ nargs = list_length (arglist);
+
+ nparms = TREE_VEC_LENGTH (parms);
+
+ if (nargs > nparms
+ || (nargs < nparms
+ && TREE_PURPOSE (TREE_VEC_ELT (parms, nargs)) == NULL_TREE))
{
error ("incorrect number of parameters (%d, should be %d)",
- nparms, TREE_VEC_LENGTH (parms));
+ nargs, nparms);
if (in_decl)
cp_error_at ("in template expansion for decl `%D'", in_decl);
return error_mark_node;
}
- if (TREE_CODE (arglist) == TREE_VEC)
+ if (arglist && TREE_CODE (arglist) == TREE_VEC)
vec = copy_node (arglist);
else
{
vec = make_tree_vec (nparms);
for (i = 0; i < nparms; i++)
{
- tree arg = arglist;
- arglist = TREE_CHAIN (arglist);
- if (arg == error_mark_node)
- lost++;
+ tree arg;
+
+ if (arglist)
+ {
+ arg = arglist;
+ arglist = TREE_CHAIN (arglist);
+
+ if (arg == error_mark_node)
+ lost++;
+ else
+ arg = TREE_VALUE (arg);
+ }
else
- arg = TREE_VALUE (arg);
+ arg = TREE_PURPOSE (TREE_VEC_ELT (parms, i));
+
TREE_VEC_ELT (vec, i) = arg;
}
}
for (i = 0; i < nparms; i++)
{
tree arg = TREE_VEC_ELT (vec, i);
- tree parm = TREE_VEC_ELT (parms, i);
+ tree parm = TREE_VALUE (TREE_VEC_ELT (parms, i));
tree val = 0;
int is_type, requires_type;
is_type = TREE_CODE_CLASS (TREE_CODE (arg)) == 't';
- requires_type = TREE_CODE (parm) == IDENTIFIER_NODE;
+ requires_type = TREE_CODE (parm) == TYPE_DECL;
if (is_type != requires_type)
{
if (in_decl)
- cp_error_at ("type/value mismatch in template parameter list for `%D'", in_decl);
+ cp_error ("type/value mismatch in template parameter list for `%D'",
+ in_decl);
lost++;
TREE_VEC_ELT (vec, i) = error_mark_node;
continue;
@@ -415,7 +448,7 @@ coerce_template_parms (parms, arglist, in_decl)
{
grok_template_type (vec, &TREE_TYPE (parm));
val = digest_init (TREE_TYPE (parm), arg, (tree *) 0);
-
+
if (val == error_mark_node)
;
@@ -489,12 +522,13 @@ mangle_class_name_for_template (name, parms, arglist)
my_friendly_assert (nparms == TREE_VEC_LENGTH (arglist), 268);
for (i = 0; i < nparms; i++)
{
- tree parm = TREE_VEC_ELT (parms, i), arg = TREE_VEC_ELT (arglist, i);
+ tree parm = TREE_VALUE (TREE_VEC_ELT (parms, i));
+ tree arg = TREE_VEC_ELT (arglist, i);
if (i)
ccat (',');
- if (TREE_CODE (parm) == IDENTIFIER_NODE)
+ if (TREE_CODE (parm) == TYPE_DECL)
{
cat (type_as_string (arg, 0));
continue;
@@ -573,7 +607,7 @@ lookup_template_class (d1, arglist, in_decl)
}
parmlist = DECL_TEMPLATE_PARMS (template);
- arglist = coerce_template_parms (parmlist, arglist, in_decl);
+ arglist = coerce_template_parms (parmlist, arglist, template);
if (arglist == error_mark_node)
return error_mark_node;
if (uses_template_parms (arglist))
@@ -619,11 +653,11 @@ push_template_decls (parmlist, arglist, class_level)
for (i = 0; i < nparms; i++)
{
int requires_type, is_type;
- tree parm = TREE_VEC_ELT (parmlist, i);
+ tree parm = TREE_VALUE (TREE_VEC_ELT (parmlist, i));
tree arg = TREE_VEC_ELT (arglist, i);
tree decl = 0;
- requires_type = TREE_CODE (parm) == IDENTIFIER_NODE;
+ requires_type = TREE_CODE (parm) == TYPE_DECL;
is_type = TREE_CODE_CLASS (TREE_CODE (arg)) == 't';
if (is_type)
{
@@ -635,7 +669,7 @@ push_template_decls (parmlist, arglist, class_level)
}
decl = arg;
my_friendly_assert (TREE_CODE_CLASS (TREE_CODE (decl)) == 't', 273);
- decl = build_decl (TYPE_DECL, parm, decl);
+ decl = build_decl (TYPE_DECL, DECL_NAME (parm), decl);
}
else
{
@@ -864,23 +898,25 @@ instantiate_member_templates (classname)
&TREE_VEC_ELT (parmvec, 0));
type = IDENTIFIER_TYPE_VALUE (id);
my_friendly_assert (type != 0, 277);
- if (CLASSTYPE_INTERFACE_UNKNOWN (type))
- {
- DECL_EXTERNAL (t2) = 0;
- TREE_PUBLIC (t2) = 0;
- }
- else
+ if (flag_external_templates)
{
- DECL_EXTERNAL (t2) = CLASSTYPE_INTERFACE_ONLY (type);
- TREE_PUBLIC (t2) = 1;
+ if (CLASSTYPE_INTERFACE_UNKNOWN (type))
+ {
+ DECL_EXTERNAL (t2) = 0;
+ TREE_PUBLIC (t2) = 0;
+ }
+ else
+ {
+ DECL_EXTERNAL (t2) = CLASSTYPE_INTERFACE_ONLY (type);
+ TREE_PUBLIC (t2) = 1;
+ }
}
break;
case 1:
/* Failure. */
failure:
- cp_error ("type unification error instantiating %T::%D",
- classname, tdecl);
- cp_error_at ("for template declaration `%D'", tdecl);
+ cp_error_at ("type unification error instantiating `%D'", tdecl);
+ cp_error ("while instantiating members of `%T'", classname);
continue /* loop of members */;
default:
@@ -1074,21 +1110,17 @@ list_eq (t1, t2)
return list_eq (TREE_CHAIN (t1), TREE_CHAIN (t2));
}
-static tree
+static tree
lookup_nested_type_by_name (ctype, name)
tree ctype, name;
{
tree t;
- t = TREE_VALUE(CLASSTYPE_TAGS(ctype));
- while (t)
- {
- if (strcmp(IDENTIFIER_POINTER(name), IDENTIFIER_POINTER(TYPE_IDENTIFIER(t)))
- == 0)
- return t;
- else
- t = TREE_CHAIN(t);
- }
+ for (t = CLASSTYPE_TAGS (ctype); t; t = TREE_CHAIN (t))
+ {
+ if (name == TREE_PURPOSE (t))
+ return TREE_VALUE (t);
+ }
return NULL_TREE;
}
@@ -1125,7 +1157,7 @@ tsubst (t, args, nargs, in_decl)
&& type != integer_type_node
&& type != void_type_node
&& type != char_type_node)
- type = c_build_type_variant (tsubst (type, args, nargs, in_decl),
+ type = cp_build_type_variant (tsubst (type, args, nargs, in_decl),
TYPE_READONLY (type),
TYPE_VOLATILE (type));
switch (TREE_CODE (t))
@@ -1134,7 +1166,7 @@ tsubst (t, args, nargs, in_decl)
if (TYPE_PTRMEMFUNC_P (t))
return build_ptrmemfunc_type
(tsubst (TYPE_PTRMEMFUNC_FN_TYPE (t), args, nargs, in_decl));
-
+
/* else fall through */
case ERROR_MARK:
@@ -1162,9 +1194,12 @@ tsubst (t, args, nargs, in_decl)
tsubst (TYPE_MAX_VALUE (t), args, nargs, in_decl));
case TEMPLATE_TYPE_PARM:
- return c_build_type_variant (args[TEMPLATE_TYPE_IDX (t)],
- TYPE_READONLY (t),
- TYPE_VOLATILE (t));
+ {
+ tree arg = args[TEMPLATE_TYPE_IDX (t)];
+ return cp_build_type_variant
+ (arg, TYPE_READONLY (arg) || TYPE_READONLY (t),
+ TYPE_VOLATILE (arg) || TYPE_VOLATILE (t));
+ }
case TEMPLATE_CONST_PARM:
return args[TEMPLATE_CONST_IDX (t)];
@@ -1173,7 +1208,7 @@ tsubst (t, args, nargs, in_decl)
{
tree r;
tree fnargs, result;
-
+
if (type == TREE_TYPE (t)
&& (DECL_CONTEXT (t) == NULL_TREE
|| TREE_CODE_CLASS (TREE_CODE (DECL_CONTEXT (t))) != 't'))
@@ -1356,9 +1391,10 @@ tsubst (t, args, nargs, in_decl)
if (!got_it)
{
- r = build_decl_overload (r, TYPE_VALUES (type),
- DECL_CONTEXT (t) != NULL_TREE);
+ tree a = build_decl_overload (r, TYPE_VALUES (type),
+ DECL_CONTEXT (t) != NULL_TREE);
r = build_lang_decl (FUNCTION_DECL, r, type);
+ DECL_ASSEMBLER_NAME (r) = a;
}
else if (DECL_INLINE (r) && DECL_SAVED_INSNS (r))
{
@@ -1392,9 +1428,11 @@ tsubst (t, args, nargs, in_decl)
make_decl_rtl (r, NULL_PTR, 1);
DECL_ARGUMENTS (r) = fnargs;
DECL_RESULT (r) = result;
+#if 0
if (DECL_CONTEXT (t) == NULL_TREE
|| TREE_CODE_CLASS (TREE_CODE (DECL_CONTEXT (t))) != 't')
push_overloaded_decl_top_level (r, 0);
+#endif
return r;
}
@@ -1442,7 +1480,7 @@ tsubst (t, args, nargs, in_decl)
{
int len = TREE_VEC_LENGTH (t), need_new = 0, i;
tree *elts = (tree *) alloca (len * sizeof (tree));
- bzero (elts, len * sizeof (tree));
+ bzero ((char *) elts, len * sizeof (tree));
for (i = 0; i < len; i++)
{
@@ -1472,7 +1510,7 @@ tsubst (t, args, nargs, in_decl)
r = build_pointer_type (type);
else
r = build_reference_type (type);
- r = c_build_type_variant (r, TYPE_READONLY (t), TYPE_VOLATILE (t));
+ r = cp_build_type_variant (r, TYPE_READONLY (t), TYPE_VOLATILE (t));
/* Will this ever be needed for TYPE_..._TO values? */
layout_type (r);
return r;
@@ -1566,7 +1604,7 @@ tsubst (t, args, nargs, in_decl)
rt = IDENTIFIER_TYPE_VALUE (id);
/* kung: this part handles nested type in template definition */
-
+
if ( !ANON_AGGRNAME_P (DECL_NAME(TYPE_NAME(t))))
{
rt = search_nested_type_in_tmpl (rt, t);
@@ -1651,7 +1689,7 @@ instantiate_template (tmpl, targ_ptr)
DECL_ARGUMENTS (olddecl) = TREE_CHAIN (DECL_ARGUMENTS (olddecl));
DECL_ARGUMENTS (fndecl) = TREE_CHAIN (DECL_ARGUMENTS (fndecl));
}
-
+
t = DECL_TEMPLATE_INFO (tmpl);
/* If we have a preexisting version of this function, don't expand
@@ -1680,7 +1718,7 @@ instantiate_template (tmpl, targ_ptr)
input_filename = p->filename = t->filename;
extract_interface_info ();
-
+
if (interface_unknown && flag_external_templates && ! DECL_IN_SYSTEM_HEADER (tmpl))
warn_if_unknown_interface ();
if (interface_unknown || !flag_external_templates)
@@ -1781,6 +1819,7 @@ overload_template_name (id, classlevel)
|| TREE_CODE (t) == UNINSTANTIATED_P_TYPE, 286);
decl = build_decl (TYPE_DECL, template, t);
+ SET_DECL_ARTIFICIAL (decl);
#if 0 /* fix this later */
/* We don't want to call here if the work has already been done. */
@@ -1890,7 +1929,7 @@ reinit_parse_for_template (yychar, d1, d2)
if (!template_info)
{
template_info = (struct template_info *) permalloc (sizeof (struct template_info));
- bzero (template_info, sizeof (struct template_info));
+ bzero ((char *) template_info, sizeof (struct template_info));
DECL_TEMPLATE_INFO (d2) = template_info;
}
template_info->filename = input_filename;
@@ -1940,7 +1979,7 @@ type_unification (tparms, targs, parms, args, nsubsts, subr)
my_friendly_assert (ntparms > 0, 292);
if (!subr)
- bzero (targs, sizeof (tree) * ntparms);
+ bzero ((char *) targs, sizeof (tree) * ntparms);
while (parms
&& parms != void_list_node
@@ -1968,9 +2007,19 @@ type_unification (tparms, targs, parms, args, nsubsts, subr)
arg = TREE_TYPE (arg);
}
#endif
- if (TREE_CODE (arg) == FUNCTION_TYPE
- || TREE_CODE (arg) == METHOD_TYPE)
- arg = build_pointer_type (arg);
+ if (TREE_CODE (arg) == REFERENCE_TYPE)
+ arg = TREE_TYPE (arg);
+
+ if (TREE_CODE (parm) != REFERENCE_TYPE)
+ {
+ if (TREE_CODE (arg) == FUNCTION_TYPE
+ || TREE_CODE (arg) == METHOD_TYPE)
+ arg = build_pointer_type (arg);
+ else if (TREE_CODE (arg) == ARRAY_TYPE)
+ arg = build_pointer_type (TREE_TYPE (arg));
+ else
+ arg = TYPE_MAIN_VARIANT (arg);
+ }
switch (unify (tparms, targs, ntparms, parm, arg, nsubsts))
{
@@ -2021,9 +2070,6 @@ unify (tparms, targs, ntparms, parm, arg, nsubsts)
if (arg == parm)
return 0;
- if (TREE_CODE (arg) == REFERENCE_TYPE)
- arg = TREE_TYPE (arg);
-
switch (TREE_CODE (parm))
{
case TEMPLATE_TYPE_PARM:
@@ -2035,22 +2081,28 @@ unify (tparms, targs, ntparms, parm, arg, nsubsts)
return 1;
}
idx = TEMPLATE_TYPE_IDX (parm);
+#if 0
+ /* Template type parameters cannot contain cv-quals; i.e.
+ template <class T> void f (T& a, T& b) will not generate
+ void f (const int& a, const int& b). */
+ if (TYPE_READONLY (arg) > TYPE_READONLY (parm)
+ || TYPE_VOLATILE (arg) > TYPE_VOLATILE (parm))
+ return 1;
+ arg = TYPE_MAIN_VARIANT (arg);
+#else
+ {
+ int constp = TYPE_READONLY (arg) > TYPE_READONLY (parm);
+ int volatilep = TYPE_VOLATILE (arg) > TYPE_VOLATILE (parm);
+ arg = cp_build_type_variant (arg, constp, volatilep);
+ }
+#endif
/* Simple cases: Value already set, does match or doesn't. */
if (targs[idx] == arg)
return 0;
else if (targs[idx])
- {
- if (TYPE_MAIN_VARIANT (targs[idx]) == TYPE_MAIN_VARIANT (arg))
- /* allow different parms to have different cv-qualifiers */;
- else
- return 1;
- }
- /* Check for mixed types and values. */
- if (TREE_CODE (TREE_VEC_ELT (tparms, idx)) != IDENTIFIER_NODE)
return 1;
- /* Allow trivial conversions. */
- if (TYPE_READONLY (parm) < TYPE_READONLY (arg)
- || TYPE_VOLATILE (parm) < TYPE_VOLATILE (arg))
+ /* Check for mixed types and values. */
+ if (TREE_CODE (TREE_VALUE (TREE_VEC_ELT (tparms, idx))) != TYPE_DECL)
return 1;
targs[idx] = arg;
return 0;
@@ -2106,7 +2158,10 @@ unify (tparms, targs, ntparms, parm, arg, nsubsts)
case REAL_TYPE:
case INTEGER_TYPE:
- if (TREE_CODE (parm) == INTEGER_TYPE && TREE_CODE (arg) == INTEGER_TYPE)
+ if (TREE_CODE (arg) != TREE_CODE (parm))
+ return 1;
+
+ if (TREE_CODE (parm) == INTEGER_TYPE)
{
if (TYPE_MIN_VALUE (parm) && TYPE_MIN_VALUE (arg)
&& unify (tparms, targs, ntparms,
@@ -2247,6 +2302,10 @@ do_pending_expansions ()
else if (! flag_implicit_templates)
DECIDE (0);
+ if (i->interface == 1)
+ /* OK, it was an implicit instantiation. */
+ TREE_PUBLIC (t) = 0;
+
/* If it's a method, let the class type decide it.
@@ What if the method template is in a separate file?
Maybe both file contexts should be taken into account?
@@ -2316,7 +2375,7 @@ void
do_pending_templates ()
{
struct pending_template* t;
-
+
for ( t = pending_templates; t; t = t->next)
{
instantiate_class_template (t->id, 1);
@@ -2334,7 +2393,7 @@ add_pending_template (pt)
tree pt;
{
struct pending_template *p;
-
+
p = (struct pending_template *) malloc (sizeof (struct pending_template));
p->next = pending_templates;
pending_templates = p;
@@ -2377,16 +2436,20 @@ do_function_instantiation (declspecs, declarator, storage)
if (flag_external_templates)
return;
- if (DECL_EXPLICIT_INSTANTIATION (result) && ! DECL_EXTERNAL (result))
+ if (DECL_EXPLICIT_INSTANTIATION (result) && TREE_PUBLIC (result))
return;
SET_DECL_EXPLICIT_INSTANTIATION (result);
- TREE_PUBLIC (result) = 1;
if (storage == NULL_TREE)
- DECL_EXTERNAL (result) = DECL_INLINE (result) && ! flag_implement_inlines;
+ {
+ TREE_PUBLIC (result) = 1;
+ DECL_EXTERNAL (result) = (DECL_INLINE (result)
+ && ! flag_implement_inlines);
+ TREE_STATIC (result) = ! DECL_EXTERNAL (result);
+ }
else if (storage == ridpointers[(int) RID_EXTERN])
- DECL_EXTERNAL (result) = 1;
+ ;
else
cp_error ("storage class `%D' applied to template instantiation",
storage);
@@ -2399,12 +2462,11 @@ do_type_instantiation (name, storage)
tree t = TREE_TYPE (name);
int extern_p;
+ /* With -fexternal-templates, explicit instantiations are treated the same
+ as implicit ones. */
if (flag_external_templates)
return;
- if (CLASSTYPE_EXPLICIT_INSTANTIATION (t) && ! CLASSTYPE_INTERFACE_ONLY (t))
- return;
-
if (TYPE_SIZE (t) == NULL_TREE)
{
cp_error ("explicit instantiation of `%#T' before definition of template",
@@ -2423,30 +2485,69 @@ do_type_instantiation (name, storage)
extern_p = 0;
}
- SET_CLASSTYPE_EXPLICIT_INSTANTIATION (t);
- CLASSTYPE_VTABLE_NEEDS_WRITING (t) = ! extern_p;
- SET_CLASSTYPE_INTERFACE_KNOWN (t);
- CLASSTYPE_INTERFACE_ONLY (t) = extern_p;
- if (! extern_p)
+ /* We've already instantiated this. */
+ if (CLASSTYPE_EXPLICIT_INSTANTIATION (t) && CLASSTYPE_INTERFACE_KNOWN (t))
{
- CLASSTYPE_DEBUG_REQUESTED (t) = 1;
- TYPE_DECL_SUPPRESS_DEBUG (TYPE_NAME (t)) = 0;
- rest_of_type_compilation (t, 1);
+ if (! extern_p)
+ cp_pedwarn ("multiple explicit instantiation of `%#T'", t);
+ return;
+ }
+
+ if (! CLASSTYPE_TEMPLATE_SPECIALIZATION (t))
+ {
+ SET_CLASSTYPE_EXPLICIT_INSTANTIATION (t);
+ if (! extern_p)
+ {
+ SET_CLASSTYPE_INTERFACE_KNOWN (t);
+ CLASSTYPE_INTERFACE_ONLY (t) = 0;
+ CLASSTYPE_VTABLE_NEEDS_WRITING (t) = 1;
+ CLASSTYPE_DEBUG_REQUESTED (t) = 1;
+ TYPE_DECL_SUPPRESS_DEBUG (TYPE_NAME (t)) = 0;
+ rest_of_type_compilation (t, 1);
+ }
}
- /* this should really be done by instantiate_member_templates */
{
- tree method = TREE_VEC_ELT (CLASSTYPE_METHOD_VEC (t), 0);
- for (; method; method = TREE_CHAIN (method))
+ tree tmp;
+ /* Classes nested in template classes currently don't have an
+ IDENTIFIER_TEMPLATE--their out-of-line members are handled
+ by the enclosing template class. Note that there are name
+ conflict bugs with this approach. */
+ tmp = TYPE_IDENTIFIER (t);
+ if (IDENTIFIER_TEMPLATE (tmp))
+ instantiate_member_templates (tmp);
+
+ /* this should really be done by instantiate_member_templates */
+ tmp = TREE_VEC_ELT (CLASSTYPE_METHOD_VEC (t), 0);
+ for (; tmp; tmp = TREE_CHAIN (tmp))
{
- SET_DECL_EXPLICIT_INSTANTIATION (method);
- TREE_PUBLIC (method) = 1;
- DECL_EXTERNAL (method)
- = (extern_p || (DECL_INLINE (method) && ! flag_implement_inlines));
+ if (DECL_TEMPLATE_SPECIALIZATION (tmp)
+ || (DECL_USE_TEMPLATE (tmp) == 0
+ && CLASSTYPE_TEMPLATE_SPECIALIZATION (t)))
+ continue;
+
+ SET_DECL_EXPLICIT_INSTANTIATION (tmp);
+ if (! extern_p)
+ {
+ TREE_PUBLIC (tmp) = 1;
+ DECL_EXTERNAL (tmp) = (DECL_INLINE (tmp)
+ && ! flag_implement_inlines);
+ TREE_STATIC (tmp) = ! DECL_EXTERNAL (tmp);
+ }
}
- }
- /* and data member templates, too */
+#if 0
+ for (tmp = TYPE_FIELDS (t); tmp; tmp = TREE_CHAIN (tmp))
+ {
+ if (TREE_CODE (tmp) == VAR_DECL)
+ /* eventually do something */;
+ }
+#endif
+
+ for (tmp = CLASSTYPE_TAGS (t); tmp; tmp = TREE_CHAIN (tmp))
+ if (IS_AGGR_TYPE (TREE_VALUE (tmp)))
+ do_type_instantiation (TYPE_MAIN_DECL (TREE_VALUE (tmp)), storage);
+ }
}
tree
diff --git a/gnu/usr.bin/cc/cc1plus/search.c b/gnu/usr.bin/cc/cc1plus/search.c
index c4c6a4e..38d3f64 100644
--- a/gnu/usr.bin/cc/cc1plus/search.c
+++ b/gnu/usr.bin/cc/cc1plus/search.c
@@ -236,7 +236,7 @@ my_new_memoized_entry (chain)
struct memoized_entry *p =
(struct memoized_entry *)obstack_alloc (&type_obstack_entries,
sizeof (struct memoized_entry));
- bzero (p, sizeof (struct memoized_entry));
+ bzero ((char *) p, sizeof (struct memoized_entry));
MEMOIZED_CHAIN (p) = chain;
MEMOIZED_UID (p) = ++my_memoized_entry_counter;
return p;
@@ -424,7 +424,7 @@ get_binfo (parent, binfo, protect)
tree type;
int dist;
tree rval = NULL_TREE;
-
+
if (TREE_CODE (parent) == TREE_VEC)
parent = BINFO_TYPE (parent);
/* unions cannot participate in inheritance relationships */
@@ -441,7 +441,7 @@ get_binfo (parent, binfo, protect)
return NULL_TREE;
else
my_friendly_abort (90);
-
+
dist = get_base_distance (parent, binfo, protect, &rval);
if (dist == -3)
@@ -486,7 +486,7 @@ get_base_distance_recursive (binfo, depth, is_private, basetype_path, rval,
int same_object = (tree_int_cst_equal (BINFO_OFFSET (*new_binfo_ptr),
BINFO_OFFSET (binfo))
&& *via_virtual_ptr && via_virtual);
-
+
if (*via_virtual_ptr && via_virtual==0)
{
*rval_private_ptr = is_private;
@@ -768,6 +768,7 @@ compute_access (basetype_path, field)
tree types;
tree context;
int protected_ok, via_protected;
+ extern int flag_access_control;
#if 1
/* Replaces static decl above. */
tree previous_scope;
@@ -776,6 +777,9 @@ compute_access (basetype_path, field)
((TREE_CODE (field) == FUNCTION_DECL && DECL_STATIC_FUNCTION_P (field))
|| (TREE_CODE (field) != FUNCTION_DECL && TREE_STATIC (field)));
+ if (! flag_access_control)
+ return access_public;
+
/* The field lives in the current class. */
if (BINFO_TYPE (basetype_path) == current_class_type)
return access_public;
@@ -795,7 +799,7 @@ compute_access (basetype_path, field)
#endif
previous_scope = current_scope ();
-
+
context = DECL_CLASS_CONTEXT (field);
if (context == NULL_TREE)
context = DECL_CONTEXT (field);
@@ -1913,6 +1917,10 @@ get_matching_virtual (binfo, fndecl, dtorp)
if (IDENTIFIER_VIRTUAL_P (declarator) == 0)
return NULL_TREE;
+ baselink = get_virtuals_named_this (binfo);
+ if (baselink == NULL_TREE)
+ return NULL_TREE;
+
drettype = TREE_TYPE (TREE_TYPE (fndecl));
dtypes = TYPE_ARG_TYPES (TREE_TYPE (fndecl));
if (DECL_STATIC_FUNCTION_P (fndecl))
@@ -1920,8 +1928,7 @@ get_matching_virtual (binfo, fndecl, dtorp)
else
instptr_type = TREE_TYPE (TREE_VALUE (dtypes));
- for (baselink = get_virtuals_named_this (binfo);
- baselink; baselink = next_baselink (baselink))
+ for (; baselink; baselink = next_baselink (baselink))
{
for (tmp = TREE_VALUE (baselink); tmp; tmp = DECL_CHAIN (tmp))
{
@@ -1945,7 +1952,7 @@ get_matching_virtual (binfo, fndecl, dtorp)
&& ! comptypes (TREE_TYPE (TREE_TYPE (tmp)), drettype, 1))
{
cp_error ("conflicting return type specified for virtual function `%#D'", fndecl);
- cp_error ("overriding definition as `%#D'", tmp);
+ cp_error_at ("overriding definition as `%#D'", tmp);
SET_IDENTIFIER_ERROR_LOCUS (name, basetype);
}
break;
@@ -2019,7 +2026,7 @@ get_abstract_virtuals (type)
/* First get all from non-virtual bases. */
abstract_virtuals
= get_abstract_virtuals_1 (TYPE_BINFO (type), 1, abstract_virtuals);
-
+
for (vbases = CLASSTYPE_VBASECLASSES (type); vbases; vbases = TREE_CHAIN (vbases))
{
if (! BINFO_VIRTUALS (vbases))
@@ -2697,13 +2704,22 @@ free_mi_matrix ()
/* If we want debug info for a type TYPE, make sure all its base types
are also marked as being potentially interesting. This avoids
the problem of not writing any debug info for intermediate basetypes
- that have abstract virtual functions. */
+ that have abstract virtual functions. Also mark member types. */
void
note_debug_info_needed (type)
tree type;
{
+ tree field;
dfs_walk (TYPE_BINFO (type), dfs_debug_mark, dfs_debug_unmarkedp);
+ for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field))
+ {
+ tree ttype;
+ if (TREE_CODE (field) == FIELD_DECL
+ && IS_AGGR_TYPE (ttype = target_type (TREE_TYPE (field)))
+ && dfs_debug_unmarkedp (TYPE_BINFO (ttype)))
+ note_debug_info_needed (ttype);
+ }
}
/* Subroutines of push_class_decls (). */
@@ -2915,7 +2931,7 @@ dfs_pushdecls (binfo)
TREE_OVERLOADED (tmp) = DECL_OVERLOADED (*methods);
#endif
TREE_NONLOCAL_FLAG (tmp) = 1;
-
+
/* Put the new contents in our envelope. */
TREE_PURPOSE (class_value) = tmp;
}
@@ -2930,7 +2946,7 @@ dfs_pushdecls (binfo)
TREE_OVERLOADED (tmp) = DECL_OVERLOADED (*methods);
#endif
TREE_NONLOCAL_FLAG (tmp) = 1;
-
+
/* See comment above for a description of envelopes. */
closed_envelopes = tree_cons (tmp, class_value,
closed_envelopes);
diff --git a/gnu/usr.bin/cc/cc1plus/sig.c b/gnu/usr.bin/cc/cc1plus/sig.c
index 1426168..71a9705 100644
--- a/gnu/usr.bin/cc/cc1plus/sig.c
+++ b/gnu/usr.bin/cc/cc1plus/sig.c
@@ -177,8 +177,8 @@ build_signature_pointer_or_reference_type (to_type, constp, volatilep, refp)
}
else
{
- tree sig_tbl_type = c_build_type_variant (to_type, 1, 0);
-
+ tree sig_tbl_type = cp_build_type_variant (to_type, 1, 0);
+
sptr = build_lang_field_decl (FIELD_DECL,
get_identifier (SIGNATURE_SPTR_NAME),
build_pointer_type (sig_tbl_type));
@@ -308,7 +308,7 @@ build_member_function_pointer (member)
int namlen = IDENTIFIER_LENGTH (DECL_ASSEMBLER_NAME (member));
char *name;
tree entry;
-
+
name = (char *) alloca (namlen + sizeof (SIGNATURE_FIELD_NAME) + 2);
sprintf (name, SIGNATURE_FIELD_NAME_FORMAT, namstr);
@@ -348,7 +348,7 @@ append_signature_fields (list_of_fieldlists)
tree mfptr;
tree last_mfptr;
tree mfptr_list = NULL_TREE;
-
+
/* For signatures it should actually be only a list with one element. */
for (l = list_of_fieldlists; l; l = TREE_CHAIN (l))
{
@@ -563,7 +563,7 @@ build_signature_table_constructor (sig_ty, rhs)
last_rhs_field = rhs_field;
else
offset_p = 0;
-
+
tbl_entry = build_component_ref (rhs, DECL_NAME (rhs_field),
NULL_TREE, 1);
}
@@ -923,7 +923,7 @@ build_signature_method_call (basetype, instance, function, parms)
NULL_TREE, 1);
pfn = build_component_ref (tbl_entry, get_identifier (SIGTABLE_PFN_NAME),
NULL_TREE, 1);
- TREE_TYPE (pfn) = build_pointer_type (TREE_TYPE (function));
+ TREE_TYPE (pfn) = build_pointer_type (TREE_TYPE (function));
if (IS_DEFAULT_IMPLEMENTATION (function))
{
diff --git a/gnu/usr.bin/cc/cc1plus/spew.c b/gnu/usr.bin/cc/cc1plus/spew.c
index ea00ba2..6931ede 100644
--- a/gnu/usr.bin/cc/cc1plus/spew.c
+++ b/gnu/usr.bin/cc/cc1plus/spew.c
@@ -59,7 +59,7 @@ extern int end_of_file;
struct obstack token_obstack;
int first_token;
-
+
#ifdef SPEW_DEBUG
int spew_debug = 0;
static unsigned int yylex_ctr = 0;
@@ -202,8 +202,10 @@ shift_tokens (n)
* sizeof (struct token));
/* This move does not rely on the system being able to handle
overlapping moves. */
- bcopy (nth_token (0), tmp, old_token_count * sizeof (struct token));
- bcopy (tmp, nth_token (n), old_token_count * sizeof (struct token));
+ bcopy ((char *) nth_token (0), tmp,
+ old_token_count * sizeof (struct token));
+ bcopy (tmp, (char *) nth_token (n),
+ old_token_count * sizeof (struct token));
}
first_token = 0;
}
@@ -226,7 +228,7 @@ probe_obstack (h, obj, nlevels)
nlevels -= 1)
{
plp = lp->prev;
- lp = plp;
+ lp = plp;
}
return nlevels != 0 && lp != 0;
}
@@ -288,7 +290,7 @@ yylex()
case EMPTY:
/* This is a lexical no-op. */
consume_token ();
-#ifdef SPEW_DEBUG
+#ifdef SPEW_DEBUG
if (spew_debug)
debug_yychar (tmp_token.yychar);
#endif
@@ -364,7 +366,7 @@ yylex()
yylval = tmp_token.yylval;
yychar = tmp_token.yychar;
end_of_file = tmp_token.end_of_file;
-#ifdef SPEW_DEBUG
+#ifdef SPEW_DEBUG
if (spew_debug)
debug_yychar(yychar);
#endif
@@ -381,7 +383,7 @@ static int
do_aggr ()
{
int yc1, yc2;
-
+
scan_tokens (2);
yc1 = nth_token (1)->yychar;
if (yc1 != TYPENAME && yc1 != IDENTIFIER && yc1 != PTYPENAME)
@@ -412,9 +414,9 @@ do_aggr ()
my_friendly_abort (102);
}
return 0;
-}
-
-#ifdef SPEW_DEBUG
+}
+
+#ifdef SPEW_DEBUG
/* debug_yychar takes a yychar (token number) value and prints its name. */
static int
debug_yychar (yy)
@@ -422,9 +424,9 @@ debug_yychar (yy)
{
/* In parse.y: */
extern char *debug_yytranslate ();
-
+
int i;
-
+
if(yy<256) {
fprintf (stderr, "<%d: %c >\n", yy, yy);
return 0;
diff --git a/gnu/usr.bin/cc/cc1plus/tree.c b/gnu/usr.bin/cc/cc1plus/tree.c
index 88466b8..b0607f8 100644
--- a/gnu/usr.bin/cc/cc1plus/tree.c
+++ b/gnu/usr.bin/cc/cc1plus/tree.c
@@ -35,66 +35,75 @@ int
lvalue_p (ref)
tree ref;
{
- register enum tree_code code = TREE_CODE (ref);
+ if (! language_lvalue_valid (ref))
+ return 0;
+
+ if (TREE_CODE (TREE_TYPE (ref)) == REFERENCE_TYPE)
+ return 1;
+
+ if (ref == current_class_decl && flag_this_is_variable <= 0)
+ return 0;
- if (language_lvalue_valid (ref))
+ switch (TREE_CODE (ref))
{
- if (TREE_CODE (TREE_TYPE (ref)) == REFERENCE_TYPE)
+ /* preincrements and predecrements are valid lvals, provided
+ what they refer to are valid lvals. */
+ case PREINCREMENT_EXPR:
+ case PREDECREMENT_EXPR:
+ case COMPONENT_REF:
+ case SAVE_EXPR:
+ return lvalue_p (TREE_OPERAND (ref, 0));
+
+ case STRING_CST:
+ return 1;
+
+ case VAR_DECL:
+ if (TREE_READONLY (ref) && ! TREE_STATIC (ref)
+ && DECL_LANG_SPECIFIC (ref)
+ && DECL_IN_AGGR_P (ref))
+ return 0;
+ case INDIRECT_REF:
+ case ARRAY_REF:
+ case PARM_DECL:
+ case RESULT_DECL:
+ case ERROR_MARK:
+ if (TREE_CODE (TREE_TYPE (ref)) != FUNCTION_TYPE
+ && TREE_CODE (TREE_TYPE (ref)) != METHOD_TYPE)
return 1;
-
- switch (code)
- {
- /* preincrements and predecrements are valid lvals, provided
- what they refer to are valid lvals. */
- case PREINCREMENT_EXPR:
- case PREDECREMENT_EXPR:
- case COMPONENT_REF:
- case SAVE_EXPR:
- return lvalue_p (TREE_OPERAND (ref, 0));
-
- case STRING_CST:
- return 1;
-
- case VAR_DECL:
- if (TREE_READONLY (ref) && ! TREE_STATIC (ref)
- && DECL_LANG_SPECIFIC (ref)
- && DECL_IN_AGGR_P (ref))
- return 0;
- case INDIRECT_REF:
- case ARRAY_REF:
- case PARM_DECL:
- case RESULT_DECL:
- case ERROR_MARK:
- if (TREE_CODE (TREE_TYPE (ref)) != FUNCTION_TYPE
- && TREE_CODE (TREE_TYPE (ref)) != METHOD_TYPE)
- return 1;
- break;
+ break;
- case TARGET_EXPR:
- case WITH_CLEANUP_EXPR:
- return 1;
-
- /* A currently unresolved scope ref. */
- case SCOPE_REF:
- my_friendly_abort (103);
- case OFFSET_REF:
- if (TREE_CODE (TREE_OPERAND (ref, 1)) == FUNCTION_DECL)
- return 1;
- return lvalue_p (TREE_OPERAND (ref, 0))
- && lvalue_p (TREE_OPERAND (ref, 1));
- break;
+ case WITH_CLEANUP_EXPR:
+ return lvalue_p (TREE_OPERAND (ref, 0));
+
+ case TARGET_EXPR:
+ return 1;
- case COND_EXPR:
- return (lvalue_p (TREE_OPERAND (ref, 1))
- && lvalue_p (TREE_OPERAND (ref, 2)));
+ case CALL_EXPR:
+ if (TREE_ADDRESSABLE (TREE_TYPE (ref)))
+ return 1;
+ break;
- case MODIFY_EXPR:
- return 1;
+ /* A currently unresolved scope ref. */
+ case SCOPE_REF:
+ my_friendly_abort (103);
+ case OFFSET_REF:
+ if (TREE_CODE (TREE_OPERAND (ref, 1)) == FUNCTION_DECL)
+ return 1;
+ return lvalue_p (TREE_OPERAND (ref, 0))
+ && lvalue_p (TREE_OPERAND (ref, 1));
+ break;
- case COMPOUND_EXPR:
- return lvalue_p (TREE_OPERAND (ref, 1));
- }
+ case COND_EXPR:
+ return (lvalue_p (TREE_OPERAND (ref, 1))
+ && lvalue_p (TREE_OPERAND (ref, 2)));
+
+ case MODIFY_EXPR:
+ return 1;
+
+ case COMPOUND_EXPR:
+ return lvalue_p (TREE_OPERAND (ref, 1));
}
+
return 0;
}
@@ -221,12 +230,15 @@ break_out_calls (exp)
return exp;
case 'd': /* A decl node */
+#if 0 /* This is bogus. jason 9/21/94 */
+
t1 = break_out_calls (DECL_INITIAL (exp));
if (t1 != DECL_INITIAL (exp))
{
exp = copy_node (exp);
DECL_INITIAL (exp) = t1;
}
+#endif
return exp;
case 'b': /* A block node */
@@ -379,6 +391,40 @@ build_cplus_array_type (elt_type, index_type)
return t;
}
+/* Make a variant type in the proper way for C/C++, propagating qualifiers
+ down to the element type of an array. */
+
+tree
+cp_build_type_variant (type, constp, volatilep)
+ tree type;
+ int constp, volatilep;
+{
+ if (TREE_CODE (type) == ARRAY_TYPE)
+ {
+ tree real_main_variant = TYPE_MAIN_VARIANT (type);
+
+ push_obstacks (TYPE_OBSTACK (real_main_variant),
+ TYPE_OBSTACK (real_main_variant));
+ type = build_cplus_array_type (cp_build_type_variant (TREE_TYPE (type),
+ constp, volatilep),
+ TYPE_DOMAIN (type));
+
+ /* TYPE must be on same obstack as REAL_MAIN_VARIANT. If not,
+ make a copy. (TYPE might have come from the hash table and
+ REAL_MAIN_VARIANT might be in some function's obstack.) */
+
+ if (TYPE_OBSTACK (type) != TYPE_OBSTACK (real_main_variant))
+ {
+ type = copy_node (type);
+ TYPE_POINTER_TO (type) = TYPE_REFERENCE_TO (type) = 0;
+ }
+
+ TYPE_MAIN_VARIANT (type) = real_main_variant;
+ pop_obstacks ();
+ }
+ return build_type_variant (type, constp, volatilep);
+}
+
/* Add OFFSET to all base types of T.
OFFSET, which is a type offset, is number of bytes.
@@ -717,7 +763,7 @@ layout_basetypes (rec, binfos)
#if 0
/* bpk: Disabled this check until someone is willing to
claim it as theirs and explain exactly what circumstances
- warrant the warning. */
+ warrant the warning. */
if (warn_nonvdtor && TYPE_HAS_DESTRUCTOR (basetype)
&& DECL_VINDEX (TREE_VEC_ELT (CLASSTYPE_METHOD_VEC (basetype), 0)) == NULL_TREE)
{
@@ -1101,7 +1147,7 @@ make_binfo (offset, binfo, vtable, virtuals, chain)
BINFO_VPTR_FIELD (new_binfo) = NULL_TREE;
if (binfo && BINFO_BASETYPES (binfo) != NULL_TREE)
- BINFO_BASETYPES (new_binfo) = copy_node (BINFO_BASETYPES (binfo));
+ BINFO_BASETYPES (new_binfo) = copy_node (BINFO_BASETYPES (binfo));
return new_binfo;
}
@@ -1184,50 +1230,6 @@ virtual_member (elem, list)
return rval;
}
-/* Return the offset (as an INTEGER_CST) for ELEM in LIST.
- INITIAL_OFFSET is the value to add to the offset that ELEM's
- binfo entry in LIST provides.
-
- Returns NULL if ELEM does not have an binfo value in LIST. */
-
-tree
-virtual_offset (elem, list, initial_offset)
- tree elem;
- tree list;
- tree initial_offset;
-{
- tree vb, offset;
- tree rval, nval;
-
- for (vb = list; vb; vb = TREE_CHAIN (vb))
- if (elem == BINFO_TYPE (vb))
- return size_binop (PLUS_EXPR, initial_offset, BINFO_OFFSET (vb));
- rval = 0;
- for (vb = list; vb; vb = TREE_CHAIN (vb))
- {
- tree binfos = BINFO_BASETYPES (vb);
- int i;
-
- if (binfos == NULL_TREE)
- continue;
-
- for (i = TREE_VEC_LENGTH (binfos)-1; i >= 0; i--)
- {
- nval = binfo_value (elem, BINFO_TYPE (TREE_VEC_ELT (binfos, i)));
- if (nval)
- {
- if (rval && BINFO_OFFSET (nval) != BINFO_OFFSET (rval))
- my_friendly_abort (105);
- offset = BINFO_OFFSET (vb);
- rval = nval;
- }
- }
- }
- if (rval == NULL_TREE)
- return rval;
- return size_binop (PLUS_EXPR, offset, BINFO_OFFSET (rval));
-}
-
void
debug_binfo (elem)
tree elem;
@@ -1328,7 +1330,7 @@ is_overloaded_fn (x)
int
really_overloaded_fn (x)
tree x;
-{
+{
if (TREE_CODE (x) == TREE_LIST
&& (TREE_CODE (TREE_VALUE (x)) == FUNCTION_DECL
|| TREE_CODE (TREE_VALUE (x)) == TEMPLATE_DECL))
@@ -1345,7 +1347,7 @@ get_first_fn (from)
return from;
my_friendly_assert (TREE_CODE (from) == TREE_LIST, 9);
-
+
return TREE_VALUE (from);
}
@@ -1661,6 +1663,31 @@ make_deep_copy (t)
TREE_OPERAND (t, 0) = make_deep_copy (TREE_OPERAND (t, 0));
return t;
+ case POINTER_TYPE:
+ return build_pointer_type (make_deep_copy (TREE_TYPE (t)));
+ case REFERENCE_TYPE:
+ return build_reference_type (make_deep_copy (TREE_TYPE (t)));
+ case FUNCTION_TYPE:
+ return build_function_type (make_deep_copy (TREE_TYPE (t)),
+ make_deep_copy (TYPE_ARG_TYPES (t)));
+ case ARRAY_TYPE:
+ return build_array_type (make_deep_copy (TREE_TYPE (t)),
+ make_deep_copy (TYPE_DOMAIN (t)));
+ case OFFSET_TYPE:
+ return build_offset_type (make_deep_copy (TYPE_OFFSET_BASETYPE (t)),
+ make_deep_copy (TREE_TYPE (t)));
+ case METHOD_TYPE:
+ return build_method_type
+ (make_deep_copy (TYPE_METHOD_BASETYPE (t)),
+ build_function_type
+ (make_deep_copy (TREE_TYPE (t)),
+ make_deep_copy (TREE_CHAIN (TYPE_ARG_TYPES (t)))));
+ case RECORD_TYPE:
+ if (TYPE_PTRMEMFUNC_P (t))
+ return build_ptrmemfunc_type
+ (make_deep_copy (TYPE_PTRMEMFUNC_FN_TYPE (t)));
+ /* else fall through */
+
/* This list is incomplete, but should suffice for now.
It is very important that `sorry' does not call
`report_error_function'. That could cause an infinite loop. */
@@ -1738,7 +1765,7 @@ tree
array_type_nelts_top (type)
tree type;
{
- return fold (build (PLUS_EXPR, integer_type_node,
+ return fold (build (PLUS_EXPR, sizetype,
array_type_nelts (type),
integer_one_node));
}
@@ -1756,7 +1783,7 @@ array_type_nelts_total (type)
while (TREE_CODE (type) == ARRAY_TYPE)
{
tree n = array_type_nelts_top (type);
- sz = fold (build (MULT_EXPR, integer_type_node, sz, n));
+ sz = fold (build (MULT_EXPR, sizetype, sz, n));
type = TREE_TYPE (type);
}
return sz;
diff --git a/gnu/usr.bin/cc/cc1plus/typeck.c b/gnu/usr.bin/cc/cc1plus/typeck.c
index fe8e7ba..1c7b4f2 100644
--- a/gnu/usr.bin/cc/cc1plus/typeck.c
+++ b/gnu/usr.bin/cc/cc1plus/typeck.c
@@ -161,7 +161,7 @@ qualify_type (type, like)
int constflag = TYPE_READONLY (type) || TYPE_READONLY (like);
int volflag = TYPE_VOLATILE (type) || TYPE_VOLATILE (like);
/* @@ Must do member pointers here. */
- return c_build_type_variant (type, constflag, volflag);
+ return cp_build_type_variant (type, constflag, volflag);
}
/* Return the common type of two parameter lists.
@@ -289,7 +289,7 @@ common_type (t1, t2)
{
/* Pick the longest list, and hang on the other
list. */
-
+
if (list_length (a1) < list_length (a2))
attributes = a2, a2 = a1;
@@ -333,7 +333,7 @@ common_type (t1, t2)
return build_type_attribute_variant (t2, attributes);
/* Same precision. Prefer longs to ints even when same size. */
-
+
if (TYPE_MAIN_VARIANT (t1) == long_unsigned_type_node
|| TYPE_MAIN_VARIANT (t2) == long_unsigned_type_node)
return build_type_attribute_variant (long_unsigned_type_node,
@@ -372,7 +372,7 @@ common_type (t1, t2)
= TYPE_READONLY (TREE_TYPE (t1)) || TYPE_READONLY (TREE_TYPE (t2));
int volatilep
= TYPE_VOLATILE (TREE_TYPE (t1)) || TYPE_VOLATILE (TREE_TYPE (t2));
- target = c_build_type_variant (target, constp, volatilep);
+ target = cp_build_type_variant (target, constp, volatilep);
if (code1 == POINTER_TYPE)
t1 = build_pointer_type (target);
else
@@ -734,8 +734,6 @@ comp_target_types (ttl, ttr, nptrs)
ttr = TYPE_MAIN_VARIANT (ttr);
if (ttl == ttr)
return 1;
- if (TREE_CODE (ttr) == TEMPLATE_TYPE_PARM)
- return 1;
if (TREE_CODE (ttr) != TREE_CODE (ttl))
return 0;
@@ -813,12 +811,14 @@ common_base_type (tt1, tt2)
if (UNIQUELY_DERIVED_FROM_P (tt2, tt1))
return tt2;
+#if 0
/* If they share a virtual baseclass, that's good enough. */
for (tmp = CLASSTYPE_VBASECLASSES (tt1); tmp; tmp = TREE_CHAIN (tmp))
{
if (binfo_member (BINFO_TYPE (tmp), CLASSTYPE_VBASECLASSES (tt2)))
return BINFO_TYPE (tmp);
}
+#endif
/* Otherwise, try to find a unique baseclass of TT1
that is shared by TT2, and follow that down. */
@@ -904,6 +904,8 @@ compparms (parms1, parms2, strict)
return t2 == void_list_node && TREE_PURPOSE (t1);
return TREE_PURPOSE (t1) || TREE_PURPOSE (t2);
}
+#if 0
+ /* Default parms are not part of the type of a function. */
if (strict != 3 && TREE_PURPOSE (t1) && TREE_PURPOSE (t2))
{
int cmp = simple_cst_equal (TREE_PURPOSE (t1), TREE_PURPOSE (t2));
@@ -912,6 +914,7 @@ compparms (parms1, parms2, strict)
if (cmp == 0)
return 0;
}
+#endif
t1 = TREE_CHAIN (t1);
t2 = TREE_CHAIN (t2);
@@ -959,8 +962,6 @@ comp_target_parms (parms1, parms2, strict)
p2 = TREE_VALUE (t2);
if (p1 == p2)
continue;
- if (TREE_CODE (p2) == TEMPLATE_TYPE_PARM)
- continue;
if ((TREE_CODE (p1) == POINTER_TYPE && TREE_CODE (p2) == POINTER_TYPE)
|| (TREE_CODE (p1) == REFERENCE_TYPE && TREE_CODE (p2) == REFERENCE_TYPE))
@@ -970,9 +971,6 @@ comp_target_parms (parms1, parms2, strict)
== TYPE_MAIN_VARIANT (TREE_TYPE (p2))))
continue;
- if (TREE_CODE (TREE_TYPE (p2)) == TEMPLATE_TYPE_PARM)
- continue;
-
/* The following is wrong for contravariance,
but many programs depend on it. */
if (TREE_TYPE (p1) == void_type_node)
@@ -1119,13 +1117,13 @@ signed_or_unsigned_type (unsignedp, type)
return type;
if (TYPE_PRECISION (type) == TYPE_PRECISION (signed_char_type_node))
return unsignedp ? unsigned_char_type_node : signed_char_type_node;
- if (TYPE_PRECISION (type) == TYPE_PRECISION (integer_type_node))
+ if (TYPE_PRECISION (type) == TYPE_PRECISION (integer_type_node))
return unsignedp ? unsigned_type_node : integer_type_node;
- if (TYPE_PRECISION (type) == TYPE_PRECISION (short_integer_type_node))
+ if (TYPE_PRECISION (type) == TYPE_PRECISION (short_integer_type_node))
return unsignedp ? short_unsigned_type_node : short_integer_type_node;
- if (TYPE_PRECISION (type) == TYPE_PRECISION (long_integer_type_node))
+ if (TYPE_PRECISION (type) == TYPE_PRECISION (long_integer_type_node))
return unsignedp ? long_unsigned_type_node : long_integer_type_node;
- if (TYPE_PRECISION (type) == TYPE_PRECISION (long_long_integer_type_node))
+ if (TYPE_PRECISION (type) == TYPE_PRECISION (long_long_integer_type_node))
return (unsignedp ? long_long_unsigned_type_node
: long_long_integer_type_node);
return type;
@@ -1189,7 +1187,7 @@ c_sizeof (type)
}
/* Convert in case a char is more than one unit. */
- t = size_binop (CEIL_DIV_EXPR, TYPE_SIZE (type),
+ t = size_binop (CEIL_DIV_EXPR, TYPE_SIZE (type),
size_int (TYPE_PRECISION (char_type_node)));
/* size_binop does not put the constant in range, so do it now. */
if (TREE_CODE (t) == INTEGER_CST && force_fit_type (t, 0))
@@ -1223,7 +1221,7 @@ c_sizeof_nowarn (type)
}
/* Convert in case a char is more than one unit. */
- t = size_binop (CEIL_DIV_EXPR, TYPE_SIZE (type),
+ t = size_binop (CEIL_DIV_EXPR, TYPE_SIZE (type),
size_int (TYPE_PRECISION (char_type_node)));
force_fit_type (t, 0);
return t;
@@ -1308,7 +1306,7 @@ default_conversion (exp)
if (INTEGRAL_CODE_P (code))
{
tree t = type_promotes_to (type);
- if (t != TYPE_MAIN_VARIANT (type))
+ if (t != type)
return convert (t, exp);
}
if (flag_traditional
@@ -1380,7 +1378,7 @@ default_conversion (exp)
restype = TREE_TYPE (type);
if (TYPE_READONLY (type) || TYPE_VOLATILE (type)
|| constp || volatilep)
- restype = c_build_type_variant (restype,
+ restype = cp_build_type_variant (restype,
TYPE_READONLY (type) || constp,
TYPE_VOLATILE (type) || volatilep);
ptrtype = build_pointer_type (restype);
@@ -1410,8 +1408,19 @@ tree
build_object_ref (datum, basetype, field)
tree datum, basetype, field;
{
+ tree dtype;
if (datum == error_mark_node)
return error_mark_node;
+
+ dtype = TREE_TYPE (datum);
+ if (TREE_CODE (dtype) == REFERENCE_TYPE)
+ dtype = TREE_TYPE (dtype);
+ if (! IS_AGGR_TYPE_CODE (TREE_CODE (dtype)))
+ {
+ cp_error ("request for member `%T::%D' in expression of non-aggregate type `%T'",
+ basetype, field, dtype);
+ return error_mark_node;
+ }
else if (IS_SIGNATURE (IDENTIFIER_TYPE_VALUE (basetype)))
{
warning ("signature name in scope resolution ignored");
@@ -1524,8 +1533,7 @@ build_component_ref (datum, component, basetype_path, protect)
register tree field = NULL;
register tree ref;
- /* If DATUM is a COMPOUND_EXPR or COND_EXPR, move our reference inside it
- unless we are not to support things not strictly ANSI. */
+ /* If DATUM is a COMPOUND_EXPR or COND_EXPR, move our reference inside it. */
switch (TREE_CODE (datum))
{
case COMPOUND_EXPR:
@@ -1697,7 +1705,8 @@ build_component_ref (datum, component, basetype_path, protect)
datum = build_indirect_ref (addr, NULL_PTR);
my_friendly_assert (datum != error_mark_node, 311);
}
- ref = build (COMPONENT_REF, TREE_TYPE (field), break_out_cleanups (datum), field);
+ ref = fold (build (COMPONENT_REF, TREE_TYPE (field),
+ break_out_cleanups (datum), field));
if (TREE_READONLY (datum) || TREE_READONLY (field))
TREE_READONLY (ref) = 1;
@@ -1910,7 +1919,7 @@ build_array_ref (array, idx)
TREE_THIS_VOLATILE (rval)
|= (TYPE_VOLATILE (TREE_TYPE (TREE_TYPE (array)))
/* This was added by rms on 16 Nov 91.
- It fixes vol struct foo *a; a->elts[1]
+ It fixes vol struct foo *a; a->elts[1]
in an inline function.
Hope it doesn't break something else. */
| TREE_THIS_VOLATILE (array));
@@ -2208,10 +2217,10 @@ get_member_function_from_ptrfunc (instance_ptrptr, instance, function)
aref = save_expr (aref);
/* Save the intermediate result in a SAVE_EXPR so we don't have to
- compute each component of the virtual function pointer twice. */
+ compute each component of the virtual function pointer twice. */
if (/* !building_cleanup && */ TREE_CODE (aref) == INDIRECT_REF)
TREE_OPERAND (aref, 0) = save_expr (TREE_OPERAND (aref, 0));
-
+
delta = build (PLUS_EXPR, integer_type_node,
build_conditional_expr (e1, build_component_ref (aref, delta_identifier, 0, 0), integer_zero_node),
delta);
@@ -2356,7 +2365,7 @@ build_function_call_real (function, params, require_complete, flags)
/* C++ */
value_type = TREE_TYPE (fntype) ? TREE_TYPE (fntype) : void_type_node;
{
- register tree result =
+ register tree result =
build (CALL_EXPR, value_type,
function, coerced_params, NULL_TREE);
@@ -2377,7 +2386,7 @@ build_function_call (function, params)
{
return build_function_call_real (function, params, 1, LOOKUP_NORMAL);
}
-
+
tree
build_function_call_maybe (function, params)
tree function, params;
@@ -2400,7 +2409,7 @@ build_function_call_maybe (function, params)
NAME is an IDENTIFIER_NODE or 0. It is used only for error messages.
This is also where warnings about wrong number of args are generated.
-
+
Return a list of expressions for the parameters as converted.
Both VALUES and the returned value are chains of TREE_LIST nodes
@@ -2519,13 +2528,15 @@ convert_arguments (return_loc, typelist, values, fndecl, flags)
&& (type == 0 || TREE_CODE (type) != REFERENCE_TYPE))
val = TREE_OPERAND (val, 0);
- if ((type == 0 || TREE_CODE (type) != REFERENCE_TYPE)
- && (TREE_CODE (TREE_TYPE (val)) == ARRAY_TYPE
+ if (type == 0 || TREE_CODE (type) != REFERENCE_TYPE)
+ {
+ if (TREE_CODE (TREE_TYPE (val)) == ARRAY_TYPE
|| TREE_CODE (TREE_TYPE (val)) == FUNCTION_TYPE
- || TREE_CODE (TREE_TYPE (val)) == METHOD_TYPE))
- val = default_conversion (val);
+ || TREE_CODE (TREE_TYPE (val)) == METHOD_TYPE)
+ val = default_conversion (val);
- val = require_complete_type (val);
+ val = require_complete_type (val);
+ }
if (val == error_mark_node)
continue;
@@ -2544,7 +2555,8 @@ convert_arguments (return_loc, typelist, values, fndecl, flags)
}
else
{
-#ifdef PROMOTE_PROTOTYPES
+#if 0 && defined (PROMOTE_PROTOTYPES)
+ /* This breaks user-defined conversions. */
/* Rather than truncating and then reextending,
convert directly to int, if that's the type we will want. */
if (! flag_traditional
@@ -2607,7 +2619,7 @@ convert_arguments (return_loc, typelist, values, fndecl, flags)
/* See if there are default arguments that can be used */
if (TREE_PURPOSE (typetail))
{
- while (typetail != void_list_node)
+ for (; typetail != void_list_node; ++i)
{
tree type = TREE_VALUE (typetail);
tree val = TREE_PURPOSE (typetail);
@@ -2733,7 +2745,7 @@ build_binary_op (code, arg1, arg2, convert_p)
int convert_index = IS_AGGR_TYPE (type2);
/* Avoid being tripped up by things like (ARG1 != 0). */
tree types[2], try;
-
+
types[0] = type1; types[1] = type2;
if (code == TRUTH_ANDIF_EXPR || code == TRUTH_ORIF_EXPR)
try = build_type_conversion (code, bool_type_node,
@@ -2742,7 +2754,7 @@ build_binary_op (code, arg1, arg2, convert_p)
{
try = build_type_conversion (code, types[convert_index ^ 1],
args[convert_index], 1);
-
+
if (try == 0
&& args[1] == integer_zero_node
&& (code == NE_EXPR || code == EQ_EXPR))
@@ -2896,7 +2908,7 @@ build_binary_op_nodefault (code, orig_op0, orig_op1, error_code)
cp_warning ("division by zero in `%E / 0'", op0);
else if (TREE_CODE (op1) == REAL_CST && real_zerop (op1))
cp_warning ("division by zero in `%E / 0.'", op0);
-
+
if (!(code0 == INTEGER_TYPE && code1 == INTEGER_TYPE))
resultcode = RDIV_EXPR;
else
@@ -2951,7 +2963,7 @@ build_binary_op_nodefault (code, orig_op0, orig_op1, error_code)
cp_warning ("division by zero in `%E % 0'", op0);
else if (code1 == REAL_TYPE && real_zerop (op1))
cp_warning ("division by zero in `%E % 0.'", op0);
-
+
if (code0 == INTEGER_TYPE && code1 == INTEGER_TYPE)
{
/* Although it would be tempting to shorten always here, that loses
@@ -3247,6 +3259,7 @@ build_binary_op_nodefault (code, orig_op0, orig_op1, error_code)
case GE_EXPR:
case LT_EXPR:
case GT_EXPR:
+ result_type = bool_type_node;
if ((code0 == INTEGER_TYPE || code0 == REAL_TYPE)
&& (code1 == INTEGER_TYPE || code1 == REAL_TYPE))
short_compare = 1;
@@ -3261,7 +3274,7 @@ build_binary_op_nodefault (code, orig_op0, orig_op1, error_code)
TYPE_SIZE (TREE_TYPE (type0)) == 0 ? "in" : "",
TYPE_SIZE (TREE_TYPE (type1)) == 0 ? "in" : "",
type0, type1);
- else if (pedantic
+ else if (pedantic
&& TREE_CODE (TREE_TYPE (type0)) == FUNCTION_TYPE)
pedwarn ("ANSI C++ forbids ordered comparisons of pointers to functions");
}
@@ -3295,7 +3308,8 @@ build_binary_op_nodefault (code, orig_op0, orig_op1, error_code)
warning ("comparison between pointer and integer");
op0 = convert (TREE_TYPE (op1), op0);
}
- result_type = bool_type_node;
+ else
+ result_type = 0;
converted = 1;
break;
}
@@ -3424,7 +3438,7 @@ build_binary_op_nodefault (code, orig_op0, orig_op1, error_code)
pass the copies by reference, then copy them back afterward. */
tree xop0 = op0, xop1 = op1, xresult_type = result_type;
enum tree_code xresultcode = resultcode;
- tree val
+ tree val
= shorten_compare (&xop0, &xop1, &xresult_type, &xresultcode);
if (val != 0)
return convert (bool_type_node, val);
@@ -3463,7 +3477,7 @@ build_binary_op_nodefault (code, orig_op0, orig_op1, error_code)
primop0 = get_narrower (TREE_OPERAND (op0, 0), &unsignedp0);
if (TREE_CODE (primop1) == BIT_NOT_EXPR)
primop1 = get_narrower (TREE_OPERAND (op1, 0), &unsignedp1);
-
+
if (TREE_CODE (primop0) == INTEGER_CST
|| TREE_CODE (primop1) == INTEGER_CST)
{
@@ -3519,9 +3533,9 @@ build_binary_op_nodefault (code, orig_op0, orig_op1, error_code)
if (! converted)
{
if (TREE_TYPE (op0) != result_type)
- op0 = convert (result_type, op0);
+ op0 = convert (result_type, op0);
if (TREE_TYPE (op1) != result_type)
- op1 = convert (result_type, op1);
+ op1 = convert (result_type, op1);
}
{
@@ -3717,7 +3731,7 @@ build_component_addr (arg, argtype, msg)
}
else
/* This conversion is harmless. */
- rval = convert (argtype, rval);
+ rval = convert_force (argtype, rval);
if (! integer_zerop (DECL_FIELD_BITPOS (field)))
{
@@ -3730,7 +3744,7 @@ build_component_addr (arg, argtype, msg)
}
return rval;
}
-
+
/* Construct and perhaps optimize a tree representation
for a unary operation. CODE, a tree_code, specifies the operation
and XARG is the operand. */
@@ -3886,7 +3900,7 @@ build_unary_op (code, xarg, noconvert)
case NOP_EXPR:
break;
-
+
case PREINCREMENT_EXPR:
case POSTINCREMENT_EXPR:
case PREDECREMENT_EXPR:
@@ -3941,7 +3955,7 @@ build_unary_op (code, xarg, noconvert)
pedwarn ("ANSI C++ forbids %sing an enum",
(code == PREINCREMENT_EXPR || code == POSTINCREMENT_EXPR)
? "increment" : "decrement");
-
+
/* Compute the increment. */
if (typecode == POINTER_TYPE)
@@ -4088,42 +4102,16 @@ build_unary_op (code, xarg, noconvert)
if (TREE_CODE (arg) == TREE_LIST)
{
- /* Look at methods with only this name. */
- if (TREE_CODE (TREE_VALUE (arg)) == FUNCTION_DECL)
- {
- tree targ = TREE_VALUE (arg);
-
- /* If this function is unique, or it is a unique
- constructor, we can take its address easily. */
- if (DECL_CHAIN (targ) == NULL_TREE
- || (DESTRUCTOR_NAME_P (DECL_ASSEMBLER_NAME (targ))
- && DECL_CHAIN (DECL_CHAIN (targ)) == NULL_TREE))
- {
- if (DECL_CHAIN (targ))
- targ = DECL_CHAIN (targ);
- if (DECL_CLASS_CONTEXT (targ))
- targ = build (OFFSET_REF, TREE_TYPE (targ), C_C_D, targ);
-
- val = unary_complex_lvalue (ADDR_EXPR, targ);
- if (val)
- return val;
- }
-
- /* This possible setting of TREE_CONSTANT is what makes it possible
- with an initializer list to emit the entire thing in the data
- section, rather than a run-time initialization. */
- arg = build1 (ADDR_EXPR, unknown_type_node, arg);
- if (staticp (targ))
- TREE_CONSTANT (arg) = 1;
- return arg;
- }
+ if (TREE_CODE (TREE_VALUE (arg)) == FUNCTION_DECL
+ && DECL_CHAIN (TREE_VALUE (arg)) == NULL_TREE)
+ /* Unique overloaded non-member function. */
+ return build_unary_op (ADDR_EXPR, TREE_VALUE (arg), 0);
if (TREE_CHAIN (arg) == NULL_TREE
&& TREE_CODE (TREE_VALUE (arg)) == TREE_LIST
&& DECL_CHAIN (TREE_VALUE (TREE_VALUE (arg))) == NULL_TREE)
- {
- /* Unique overloaded member function. */
- return build_unary_op (ADDR_EXPR, TREE_VALUE (TREE_VALUE (arg)), 0);
- }
+ /* Unique overloaded member function. */
+ return build_unary_op (ADDR_EXPR, TREE_VALUE (TREE_VALUE (arg)),
+ 0);
return build1 (ADDR_EXPR, unknown_type_node, arg);
}
@@ -4165,7 +4153,7 @@ build_unary_op (code, xarg, noconvert)
|| TREE_CODE_CLASS (TREE_CODE (arg)) == 'r')
{
if (TREE_READONLY (arg) || TREE_THIS_VOLATILE (arg))
- argtype = c_build_type_variant (argtype,
+ argtype = cp_build_type_variant (argtype,
TREE_READONLY (arg),
TREE_THIS_VOLATILE (arg));
}
@@ -4235,7 +4223,7 @@ convert_sequence (conversions, arg)
but which we can accept as lvalues.
If ARG is not a kind of expression we can handle, return zero. */
-
+
tree
unary_complex_lvalue (code, arg)
enum tree_code code;
@@ -4320,7 +4308,7 @@ unary_complex_lvalue (code, arg)
}
return convert (build_pointer_type (TREE_TYPE (arg)),
- size_binop (EASY_DIV_EXPR,
+ size_binop (EASY_DIV_EXPR,
DECL_FIELD_BITPOS (t),
size_int (BITS_PER_UNIT)));
}
@@ -4488,7 +4476,7 @@ build_x_conditional_expr (ifexp, op1, op2)
rval = build_opfncall (COND_EXPR, LOOKUP_SPECULATIVELY, ifexp, op1, op2);
if (rval)
return build_opfncall (COND_EXPR, LOOKUP_NORMAL, ifexp, op1, op2);
-
+
return build_conditional_expr (ifexp, op1, op2);
}
@@ -4573,7 +4561,7 @@ build_conditional_expr (ifexp, op1, op2)
else if (TREE_READONLY_DECL_P (op2))
op2 = decl_constant_value (op2);
if (type1 != type2)
- type1 = c_build_type_variant
+ type1 = cp_build_type_variant
(type1,
TREE_READONLY (op1) || TREE_READONLY (op2),
TREE_THIS_VOLATILE (op1) || TREE_THIS_VOLATILE (op2));
@@ -4622,7 +4610,7 @@ build_conditional_expr (ifexp, op1, op2)
if (type1 == type2)
result_type = type1;
else
- result_type = c_build_type_variant
+ result_type = cp_build_type_variant
(type1,
TREE_READONLY (op1) || TREE_READONLY (op2),
TREE_THIS_VOLATILE (op1) || TREE_THIS_VOLATILE (op2));
@@ -4669,11 +4657,20 @@ build_conditional_expr (ifexp, op1, op2)
{
if (result_type == error_mark_node)
{
- message_2_types (error, "common base type of types `%s' and `%s' is ambiguous",
- TREE_TYPE (type1), TREE_TYPE (type2));
+ cp_error ("common base type of types `%T' and `%T' is ambiguous",
+ TREE_TYPE (type1), TREE_TYPE (type2));
result_type = ptr_type_node;
}
- else result_type = TYPE_POINTER_TO (result_type);
+ else
+ {
+ if (pedantic
+ && result_type != TREE_TYPE (type1)
+ && result_type != TREE_TYPE (type2))
+ cp_pedwarn ("`%T' and `%T' converted to `%T *' in conditional expression",
+ type1, type2, result_type);
+
+ result_type = TYPE_POINTER_TO (result_type);
+ }
}
else
{
@@ -4939,7 +4936,7 @@ build_c_cast (type, expr)
value = TREE_VALUE (value);
if (TREE_CODE (type) == VOID_TYPE)
- value = build1 (NOP_EXPR, type, value);
+ value = build1 (CONVERT_EXPR, type, value);
else if (TREE_TYPE (value) == NULL_TREE
|| type_unknown_p (value))
{
@@ -5002,6 +4999,9 @@ build_c_cast (type, expr)
warning ("cast to pointer from integer of different size");
#endif
+ if (TREE_READONLY_DECL_P (value))
+ value = decl_constant_value (value);
+
ovalue = value;
value = convert_force (type, value);
@@ -5326,13 +5326,13 @@ build_modify_expr (lhs, modifycode, rhs)
tree olhstype = lhstype;
tree olhs = lhs;
- /* Types that aren't fully specified cannot be used in assignments. */
- lhs = require_complete_type (lhs);
-
/* Avoid duplicate error messages from operands that had errors. */
if (TREE_CODE (lhs) == ERROR_MARK || TREE_CODE (rhs) == ERROR_MARK)
return error_mark_node;
+ /* Types that aren't fully specified cannot be used in assignments. */
+ lhs = require_complete_type (lhs);
+
/* Decide early if we are going to protect RHS from GC
before assigning it to LHS. */
if (type_needs_gc_entry (TREE_TYPE (rhs))
@@ -5388,9 +5388,9 @@ build_modify_expr (lhs, modifycode, rhs)
so the code to compute it is only emitted once. */
tree cond
= build_conditional_expr (TREE_OPERAND (lhs, 0),
- build_modify_expr (TREE_OPERAND (lhs, 1),
+ build_modify_expr (convert (TREE_TYPE (lhs), TREE_OPERAND (lhs, 1)),
modifycode, rhs),
- build_modify_expr (TREE_OPERAND (lhs, 2),
+ build_modify_expr (convert (TREE_TYPE (lhs), TREE_OPERAND (lhs, 2)),
modifycode, rhs));
if (TREE_CODE (cond) == ERROR_MARK)
return cond;
@@ -5684,7 +5684,7 @@ build_modify_expr (lhs, modifycode, rhs)
tree vbases = CLASSTYPE_VBASECLASSES (lhstype);
tree lhs_addr = build_unary_op (ADDR_EXPR, lhs, 0);
tree rhs_addr;
-
+
/* Memberwise assignment would cause NEWRHS to be
evaluated for every member that gets assigned.
By wrapping side-effecting exprs in a SAVE_EXPR,
@@ -5700,7 +5700,7 @@ build_modify_expr (lhs, modifycode, rhs)
will result in expand_expr expanding the call without knowing
that it should run the cleanup. */
newrhs = save_expr (break_out_cleanups (newrhs));
-
+
if (TREE_CODE (newrhs) == COND_EXPR)
rhs_addr = rationalize_conditional_expr (ADDR_EXPR, newrhs);
else
@@ -5763,10 +5763,12 @@ build_modify_expr (lhs, modifycode, rhs)
if (TREE_CODE (lhstype) == ARRAY_TYPE)
{
+ int from_array;
+
/* Allow array assignment in compiler-generated code. */
if ((pedantic || flag_ansi)
&& ! DECL_ARTIFICIAL (current_function_decl))
- pedwarn ("ANSI C++ forbids assignment between arrays");
+ pedwarn ("ANSI C++ forbids assignment of arrays");
/* Have to wrap this in RTL_EXPR for two cases:
in base or member initialization and if we
@@ -5782,8 +5784,10 @@ build_modify_expr (lhs, modifycode, rhs)
/* As a matter of principle, `start_sequence' should do this. */
emit_note (0, -1);
+ from_array = TREE_CODE (TREE_TYPE (newrhs)) == ARRAY_TYPE
+ ? 1 + (modifycode != INIT_EXPR): 0;
expand_vec_init (lhs, lhs, array_type_nelts (lhstype), newrhs,
- 1 + (modifycode != INIT_EXPR));
+ from_array);
do_pending_stack_adjust ();
@@ -5952,7 +5956,7 @@ get_delta_difference (from, to, force)
{
tree delta = integer_zero_node;
tree binfo;
-
+
if (to == from)
return delta;
@@ -6058,7 +6062,7 @@ build_ptrmemfunc (type, pfn, force)
delta = fold (size_binop (PLUS_EXPR, delta, ndelta));
delta2 = fold (size_binop (PLUS_EXPR, ndelta2, delta2));
e1 = fold (build (GT_EXPR, integer_type_node, index, integer_zero_node));
-
+
u = build_nt (CONSTRUCTOR, 0, tree_cons (delta2_identifier, delta2, NULL_TREE));
u = build_nt (CONSTRUCTOR, 0, tree_cons (NULL_TREE, delta,
tree_cons (NULL_TREE, index,
@@ -6101,12 +6105,15 @@ build_ptrmemfunc (type, pfn, force)
return digest_init (TYPE_GET_PTRMEMFUNC_TYPE (type), u, (tree*)0);
}
- if (TREE_CODE (pfn) == TREE_LIST)
+ if (TREE_CODE (pfn) == TREE_LIST
+ || (TREE_CODE (pfn) == ADDR_EXPR
+ && TREE_CODE (TREE_OPERAND (pfn, 0)) == TREE_LIST))
{
pfn = instantiate_type (type, pfn, 1);
if (pfn == error_mark_node)
return error_mark_node;
- pfn = build_unary_op (ADDR_EXPR, pfn, 0);
+ if (TREE_CODE (pfn) != ADDR_EXPR)
+ pfn = build_unary_op (ADDR_EXPR, pfn, 0);
}
/* Allow pointer to member conversions here. */
@@ -6445,7 +6452,8 @@ convert_for_assignment (type, rhs, errtype, fndecl, parmnum)
add_quals = 1;
left_const &= TYPE_READONLY (ttl);
- if (TREE_CODE (ttl) != POINTER_TYPE)
+ if (TREE_CODE (ttl) != POINTER_TYPE
+ || TREE_CODE (ttr) != POINTER_TYPE)
break;
}
unsigned_parity = TREE_UNSIGNED (ttl) - TREE_UNSIGNED (ttr);
@@ -6561,10 +6569,11 @@ convert_for_assignment (type, rhs, errtype, fndecl, parmnum)
}
return null_pointer_node;
}
- else if (codel == INTEGER_TYPE
+ else if ((codel == INTEGER_TYPE || codel == BOOLEAN_TYPE)
&& (coder == POINTER_TYPE
|| (coder == RECORD_TYPE
&& (IS_SIGNATURE_POINTER (rhstype)
+ || TYPE_PTRMEMFUNC_FLAG (rhstype)
|| IS_SIGNATURE_REFERENCE (rhstype)))))
{
if (fndecl)
@@ -6681,7 +6690,7 @@ convert_for_initialization (exp, type, rhs, flags, errtype, fndecl, parmnum)
/* We accept references to incomplete types, so we can
return here before checking if RHS is of complete type. */
-
+
if (codel == REFERENCE_TYPE)
{
/* This should eventually happen in convert_arguments. */
@@ -6700,7 +6709,7 @@ convert_for_initialization (exp, type, rhs, flags, errtype, fndecl, parmnum)
cp_error_at ("in passing argument %P of `%+D'", parmnum, fndecl);
}
return rhs;
- }
+ }
rhs = require_complete_type (rhs);
if (rhs == error_mark_node)
@@ -6717,7 +6726,8 @@ convert_for_initialization (exp, type, rhs, flags, errtype, fndecl, parmnum)
&& (IS_SIGNATURE_POINTER (type) || IS_SIGNATURE_REFERENCE (type)))
return build_signature_pointer_constructor (type, rhs);
- if (IS_AGGR_TYPE (type) && TYPE_NEEDS_CONSTRUCTING (type))
+ if (IS_AGGR_TYPE (type)
+ && (TYPE_NEEDS_CONSTRUCTING (type) || TREE_HAS_CONSTRUCTOR (rhs)))
{
if (TYPE_MAIN_VARIANT (type) == TYPE_MAIN_VARIANT (rhstype))
{
@@ -6732,6 +6742,8 @@ convert_for_initialization (exp, type, rhs, flags, errtype, fndecl, parmnum)
}
/* Handle the case of default parameter initialization and
initialization of static variables. */
+ else if (TREE_CODE (rhs) == TARGET_EXPR)
+ return rhs;
else if (TREE_CODE (rhs) == INDIRECT_REF && TREE_HAS_CONSTRUCTOR (rhs))
{
my_friendly_assert (TREE_CODE (TREE_OPERAND (rhs, 0)) == CALL_EXPR, 318);
@@ -6973,8 +6985,11 @@ c_expand_return (retval)
while (TREE_CODE (whats_returned) == NEW_EXPR
|| TREE_CODE (whats_returned) == TARGET_EXPR
|| TREE_CODE (whats_returned) == WITH_CLEANUP_EXPR)
- /* Get the target. */
- whats_returned = TREE_OPERAND (whats_returned, 0);
+ {
+ /* Get the target. */
+ whats_returned = TREE_OPERAND (whats_returned, 0);
+ warning ("returning reference to temporary");
+ }
}
if (TREE_CODE (whats_returned) == VAR_DECL && DECL_NAME (whats_returned))
@@ -6996,7 +7011,7 @@ c_expand_return (retval)
&& !TREE_STATIC (whats_returned))
cp_warning_at ("address of local variable `%D' returned", whats_returned);
}
-
+
/* Now deal with possible C++ hair:
(1) Compute the return value.
(2) If there are aggregate values with destructors which
@@ -7028,6 +7043,7 @@ c_expand_return (retval)
&& TREE_CODE (TREE_OPERAND (retval, 0)) == TARGET_EXPR)
retval = TREE_OPERAND (retval, 0);
expand_aggr_init (result, retval, 0);
+ expand_cleanups_to (NULL_TREE);
DECL_INITIAL (result) = NULL_TREE;
retval = 0;
}
@@ -7046,6 +7062,7 @@ c_expand_return (retval)
&& any_pending_cleanups (1))
{
retval = get_temp_regvar (valtype, retval);
+ expand_cleanups_to (NULL_TREE);
use_temp = obey_regdecls;
result = 0;
}
@@ -7071,7 +7088,10 @@ c_expand_return (retval)
{
/* Everything's great--RETVAL is in RESULT. */
if (original_result_rtx)
- store_expr (result, original_result_rtx, 0);
+ {
+ store_expr (result, original_result_rtx, 0);
+ expand_cleanups_to (NULL_TREE);
+ }
else if (retval && retval != result)
{
/* Clear this out so the later call to decl_function_context
@@ -7081,6 +7101,9 @@ c_expand_return (retval)
/* Here is where we finally get RETVAL into RESULT.
`expand_return' does the magic of protecting
RESULT from cleanups. */
+ retval = build1 (CLEANUP_POINT_EXPR, TREE_TYPE (result), retval);
+ /* This part _must_ come second, because expand_return looks for
+ the INIT_EXPR as the toplevel node only. :-( */
retval = build (INIT_EXPR, TREE_TYPE (result), result, retval);
TREE_SIDE_EFFECTS (retval) = 1;
expand_return (retval);
@@ -7190,7 +7213,8 @@ c_expand_start_case (exp)
exp = index;
}
- expand_start_case (1, exp, type, "switch statement");
+ expand_start_case (1, build1 (CLEANUP_POINT_EXPR, TREE_TYPE (exp), exp),
+ type, "switch statement");
return exp;
}
diff --git a/gnu/usr.bin/cc/cc1plus/typeck2.c b/gnu/usr.bin/cc/cc1plus/typeck2.c
index 871173f..ee722dd 100644
--- a/gnu/usr.bin/cc/cc1plus/typeck2.c
+++ b/gnu/usr.bin/cc/cc1plus/typeck2.c
@@ -141,7 +141,7 @@ readonly_error (arg, string, soft)
else if (TREE_CODE (arg) == RESULT_DECL)
(*fn) ("%s of read-only named return value `%s'",
string, lang_printable_name (arg));
- else
+ else
(*fn) ("%s of read-only location", string);
}
@@ -292,7 +292,7 @@ ack (s, v, v2)
HOST_WIDE_INT v2;
{
extern char * progname;
-
+
if (input_filename)
fprintf (stderr, "%s:%d: ", input_filename, lineno);
else
@@ -301,7 +301,7 @@ ack (s, v, v2)
fprintf (stderr, s, v, v2);
fprintf (stderr, "\n");
}
-
+
/* There are times when the compiler can get very confused, confused
to the point of giving up by aborting, simply because of previous
input errors. It is much better to have the user go back and
@@ -329,7 +329,7 @@ ack (s, v, v2)
silly. So instead, we just do the equivalent of a call to fatal in the
same situation (call exit). */
-/* First used: 0 (reserved), Last used: 360. Free: */
+/* First used: 0 (reserved), Last used: 360. Free: 261. */
static int abortcount = 0;
@@ -354,7 +354,7 @@ my_friendly_abort (i)
}
else
error ("confused by earlier errors, bailing out");
-
+
exit (34);
}
++abortcount;
@@ -560,7 +560,7 @@ store_init_value (decl, init)
else
{
/* We get here with code like `int a (2);' */
-
+
if (TREE_CHAIN (init) != NULL_TREE)
{
pedwarn ("initializer list being treated as compound expression");
@@ -599,6 +599,7 @@ store_init_value (decl, init)
))
return value;
+#if 0 /* No, that's C. jason 9/19/94 */
else
{
if (pedantic && TREE_CODE (value) == CONSTRUCTOR
@@ -613,6 +614,7 @@ store_init_value (decl, init)
pedwarn ("ANSI C++ forbids non-constant aggregate initializer expressions");
}
}
+#endif
DECL_INITIAL (decl) = value;
return NULL_TREE;
}
@@ -631,7 +633,7 @@ digest_init (type, init, tail)
tree type, init, *tail;
{
enum tree_code code = TREE_CODE (type);
- tree element = 0;
+ tree element = NULL_TREE;
tree old_tail_contents;
/* Nonzero if INIT is a braced grouping, which comes in as a CONSTRUCTOR
tree node which has no TREE_TYPE. */
@@ -659,8 +661,9 @@ digest_init (type, init, tail)
if (init && TYPE_PTRMEMFUNC_P (type)
&& ((TREE_CODE (init) == ADDR_EXPR
- && TREE_CODE (TREE_TYPE (init)) == POINTER_TYPE
- && TREE_CODE (TREE_TYPE (TREE_TYPE (init))) == METHOD_TYPE)
+ && ((TREE_CODE (TREE_TYPE (init)) == POINTER_TYPE
+ && TREE_CODE (TREE_TYPE (TREE_TYPE (init))) == METHOD_TYPE)
+ || TREE_CODE (TREE_OPERAND (init, 0)) == TREE_LIST))
|| TREE_CODE (init) == TREE_LIST
|| integer_zerop (init)
|| (TREE_TYPE (init) && TYPE_PTRMEMFUNC_P (TREE_TYPE (init)))))
@@ -903,7 +906,7 @@ process_init_constructor (type, init, elts)
{
error ("non-empty initializer for array of empty elements");
/* Just ignore what we were supposed to use. */
- tail1 = 0;
+ tail1 = NULL_TREE;
}
tail = tail1;
}
@@ -1151,7 +1154,9 @@ build_scoped_ref (datum, types)
if (TREE_CODE (types) == SCOPE_REF)
{
/* We have some work to do. */
- struct type_chain { tree type; struct type_chain *next; } *chain = 0, *head = 0, scratch;
+ struct type_chain
+ { tree type; struct type_chain *next; }
+ *chain = NULL, *head = NULL, scratch;
ref = build_unary_op (ADDR_EXPR, datum, 0);
while (TREE_CODE (types) == SCOPE_REF)
{
@@ -1273,7 +1278,7 @@ build_x_arrow (datum)
types_memoized);
}
last_rval = rval;
- }
+ }
if (TREE_CODE (TREE_TYPE (last_rval)) == REFERENCE_TYPE)
last_rval = convert_from_reference (last_rval);
}
@@ -1337,6 +1342,7 @@ build_m_component_ref (datum, component)
if (TREE_CODE (objtype) == REFERENCE_TYPE)
objtype = TREE_TYPE (objtype);
+ objtype = TYPE_MAIN_VARIANT (objtype);
if (! IS_AGGR_TYPE (objtype))
{
@@ -1344,7 +1350,7 @@ build_m_component_ref (datum, component)
cp_error ("which is of non-aggregate type `%T'", objtype);
return error_mark_node;
}
-
+
if (! comptypes (TYPE_METHOD_BASETYPE (type), objtype, 0))
{
cp_error ("member type `%T::' incompatible with object type `%T'",
@@ -1402,9 +1408,9 @@ build_functional_cast (exp, parms)
/* Prepare to evaluate as a call to a constructor. If this expression
is actually used, for example,
-
+
return X (arg1, arg2, ...);
-
+
then the slot being initialized will be filled in. */
if (name == NULL_TREE)
@@ -1455,14 +1461,14 @@ build_functional_cast (exp, parms)
/* The following assertion fails in cases where we are initializing
a static member variable of a particular instance of a template
class with a call to a constructor of the given instance, as in:
-
+
TMPL<int> object = TMPL<int>();
-
+
Curiously, the assertion does not fail if we do the same thing
for a static member of a non-template class, as in:
-
+
T object = T();
-
+
I can't see why we should care here whether or not the initializer
expression involves a call to `new', so for the time being, it
seems best to just avoid doing this assertion. */
@@ -1504,7 +1510,7 @@ enum_name_string (value, type)
#if 0
/* Print out a language-specific error message for
(Pascal) case or (C) switch statements.
- CODE tells what sort of message to print.
+ CODE tells what sort of message to print.
TYPE is the type of the switch index expression.
NEW is the new value that we were trying to add.
OLD is the old value that stopped us from adding it. */
diff --git a/gnu/usr.bin/cc/cc_int/Makefile b/gnu/usr.bin/cc/cc_int/Makefile
index 794d760..a7df2a3 100644
--- a/gnu/usr.bin/cc/cc_int/Makefile
+++ b/gnu/usr.bin/cc/cc_int/Makefile
@@ -1,12 +1,18 @@
#
-# $FreeBSD$
+# $Id: Makefile,v 1.7 1994/11/15 04:51:40 phk Exp $
#
SRCS = aux-output.c bc-emit.c bc-optab.c c-common.c caller-save.c calls.c combine.c convert.c cse.c dbxout.c dwarfout.c emit-rtl.c explow.c expmed.c expr.c final.c flow.c fold-const.c function.c getpwd.c global.c insn-attrtab.c insn-emit.c insn-extract.c insn-opinit.c insn-output.c insn-peep.c insn-recog.c integrate.c jump.c local-alloc.c loop.c obstack.c optabs.c print-rtl.c print-tree.c real.c recog.c reg-stack.c regclass.c reload.c reload1.c reorg.c rtl.c rtlanal.c sched.c sdbout.c stmt.c stor-layout.c stupid.c toplev.c tree.c unroll.c varasm.c version.c xcoffout.c
LIB = cc_int
-NOPROFILE= 1
+NOPROFILE= yes
+.if defined(SHARED_LIBCC_INT)
+INTERNALLIB=
+SHLIB_MAJOR=263
+SHLIB_MINOR=0
+.else
install:
@true
+.endif
.include <bsd.lib.mk>
diff --git a/gnu/usr.bin/cc/cc_int/aux-output.c b/gnu/usr.bin/cc/cc_int/aux-output.c
index bc498e0..d828f4e 100644
--- a/gnu/usr.bin/cc/cc_int/aux-output.c
+++ b/gnu/usr.bin/cc/cc_int/aux-output.c
@@ -1,5 +1,5 @@
-/* Subroutines for insn-output.c for Intel 80386.
- Copyright (C) 1988, 1992 Free Software Foundation, Inc.
+/* Subroutines for insn-output.c for Intel X86.
+ Copyright (C) 1988, 1992, 1994 Free Software Foundation, Inc.
This file is part of GNU CC.
@@ -66,7 +66,7 @@ enum reg_class regclass_map[FIRST_PSEUDO_REGISTER] =
SIREG, DIREG, INDEX_REGS, GENERAL_REGS,
/* FP registers */
FP_TOP_REG, FP_SECOND_REG, FLOAT_REGS, FLOAT_REGS,
- FLOAT_REGS, FLOAT_REGS, FLOAT_REGS, FLOAT_REGS,
+ FLOAT_REGS, FLOAT_REGS, FLOAT_REGS, FLOAT_REGS,
/* arg pointer */
INDEX_REGS
};
@@ -74,8 +74,151 @@ enum reg_class regclass_map[FIRST_PSEUDO_REGISTER] =
/* Test and compare insns in i386.md store the information needed to
generate branch and scc insns here. */
-struct rtx_def *i386_compare_op0, *i386_compare_op1;
+struct rtx_def *i386_compare_op0 = NULL_RTX;
+struct rtx_def *i386_compare_op1 = NULL_RTX;
struct rtx_def *(*i386_compare_gen)(), *(*i386_compare_gen_eq)();
+
+/* Register allocation order */
+char *i386_reg_alloc_order = (char *)0;
+static char regs_allocated[FIRST_PSEUDO_REGISTER];
+
+
+/* Sometimes certain combinations of command options do not make
+ sense on a particular target machine. You can define a macro
+ `OVERRIDE_OPTIONS' to take account of this. This macro, if
+ defined, is executed once just after all the command options have
+ been parsed.
+
+ Don't use this macro to turn on various extra optimizations for
+ `-O'. That is what `OPTIMIZATION_OPTIONS' is for. */
+
+void
+override_options ()
+{
+ int ch, i, regno;
+
+#ifdef SUBTARGET_OVERRIDE_OPTIONS
+ SUBTARGET_OVERRIDE_OPTIONS;
+#endif
+
+ /* Validate registers in register allocation order */
+ if (i386_reg_alloc_order)
+ {
+ for (i = 0; (ch = i386_reg_alloc_order[i]) != '\0'; i++)
+ {
+ switch (ch)
+ {
+ case 'a': regno = 0; break;
+ case 'd': regno = 1; break;
+ case 'c': regno = 2; break;
+ case 'b': regno = 3; break;
+ case 'S': regno = 4; break;
+ case 'D': regno = 5; break;
+ case 'B': regno = 6; break;
+
+ default: fatal ("Register '%c' is unknown", ch);
+ }
+
+ if (regs_allocated[regno])
+ fatal ("Register '%c' was already specified in the allocation order", ch);
+
+ regs_allocated[regno] = 1;
+ }
+ }
+}
+
+/* A C statement (sans semicolon) to choose the order in which to
+ allocate hard registers for pseudo-registers local to a basic
+ block.
+
+ Store the desired register order in the array `reg_alloc_order'.
+ Element 0 should be the register to allocate first; element 1, the
+ next register; and so on.
+
+ The macro body should not assume anything about the contents of
+ `reg_alloc_order' before execution of the macro.
+
+ On most machines, it is not necessary to define this macro. */
+
+void
+order_regs_for_local_alloc ()
+{
+ int i, ch, order, regno;
+
+ /* User specified the register allocation order */
+ if (i386_reg_alloc_order)
+ {
+ for (i = order = 0; (ch = i386_reg_alloc_order[i]) != '\0'; i++)
+ {
+ switch (ch)
+ {
+ case 'a': regno = 0; break;
+ case 'd': regno = 1; break;
+ case 'c': regno = 2; break;
+ case 'b': regno = 3; break;
+ case 'S': regno = 4; break;
+ case 'D': regno = 5; break;
+ case 'B': regno = 6; break;
+ }
+
+ reg_alloc_order[order++] = regno;
+ }
+
+ for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
+ {
+ if (!regs_allocated[i])
+ reg_alloc_order[order++] = i;
+ }
+ }
+
+ /* If users did not specify a register allocation order, favor eax
+ normally except if DImode variables are used, in which case
+ favor edx before eax, which seems to cause less spill register
+ not found messages. */
+ else
+ {
+ rtx insn;
+
+ for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
+ reg_alloc_order[i] = i;
+
+ if (optimize)
+ {
+ int use_dca = FALSE;
+
+ for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
+ {
+ if (GET_CODE (insn) == INSN)
+ {
+ rtx set = NULL_RTX;
+ rtx pattern = PATTERN (insn);
+
+ if (GET_CODE (pattern) == SET)
+ set = pattern;
+
+ else if ((GET_CODE (pattern) == PARALLEL
+ || GET_CODE (pattern) == SEQUENCE)
+ && GET_CODE (XVECEXP (pattern, 0, 0)) == SET)
+ set = XVECEXP (pattern, 0, 0);
+
+ if (set && GET_MODE (SET_SRC (set)) == DImode)
+ {
+ use_dca = TRUE;
+ break;
+ }
+ }
+ }
+
+ if (use_dca)
+ {
+ reg_alloc_order[0] = 1; /* edx */
+ reg_alloc_order[1] = 2; /* ecx */
+ reg_alloc_order[2] = 0; /* eax */
+ }
+ }
+ }
+}
+
/* Output an insn whose source is a 386 integer register. SRC is the
rtx for the register, and TEMPLATE is the op-code template. SRC may
@@ -235,6 +378,7 @@ find_addr_reg (addr)
abort ();
}
+
/* Output an insn to add the constant N to the register X. */
static void
@@ -243,19 +387,25 @@ asm_add (n, x)
rtx x;
{
rtx xops[2];
- xops[1] = x;
- if (n < 0)
+ xops[0] = x;
+
+ if (n == -1)
+ output_asm_insn (AS1 (dec%L0,%0), xops);
+ else if (n == 1)
+ output_asm_insn (AS1 (inc%L0,%0), xops);
+ else if (n < 0)
{
- xops[0] = GEN_INT (-n);
- output_asm_insn (AS2 (sub%L0,%0,%1), xops);
+ xops[1] = GEN_INT (-n);
+ output_asm_insn (AS2 (sub%L0,%1,%0), xops);
}
else if (n > 0)
{
- xops[0] = GEN_INT (n);
- output_asm_insn (AS2 (add%L0,%0,%1), xops);
+ xops[1] = GEN_INT (n);
+ output_asm_insn (AS2 (add%L0,%1,%0), xops);
}
}
+
/* Output assembler code to perform a doubleword move insn
with operands OPERANDS. */
@@ -378,7 +528,7 @@ output_move_double (operands)
middlehalf[0] = operands[0];
latehalf[0] = operands[0];
}
-
+
if (optype1 == REGOP)
{
middlehalf[1] = gen_rtx (REG, SImode, REGNO (operands[1]) + 1);
@@ -587,6 +737,199 @@ compadr:
return "";
}
+
+
+#define MAX_TMPS 2 /* max temporary registers used */
+
+/* Output the appropriate code to move push memory on the stack */
+
+char *
+output_move_pushmem (operands, insn, length, tmp_start, n_operands)
+ rtx operands[];
+ rtx insn;
+ int length;
+ int tmp_start;
+ int n_operands;
+{
+
+ struct {
+ char *load;
+ char *push;
+ rtx xops[2];
+ } tmp_info[MAX_TMPS];
+
+ rtx src = operands[1];
+ int max_tmps = 0;
+ int offset = 0;
+ int stack_p = reg_overlap_mentioned_p (stack_pointer_rtx, src);
+ int stack_offset = 0;
+ int i, num_tmps;
+ rtx xops[1];
+
+ if (!offsettable_memref_p (src))
+ fatal_insn ("Source is not offsettable", insn);
+
+ if ((length & 3) != 0)
+ fatal_insn ("Pushing non-word aligned size", insn);
+
+ /* Figure out which temporary registers we have available */
+ for (i = tmp_start; i < n_operands; i++)
+ {
+ if (GET_CODE (operands[i]) == REG)
+ {
+ if (reg_overlap_mentioned_p (operands[i], src))
+ continue;
+
+ tmp_info[ max_tmps++ ].xops[1] = operands[i];
+ if (max_tmps == MAX_TMPS)
+ break;
+ }
+ }
+
+ if (max_tmps == 0)
+ for (offset = length - 4; offset >= 0; offset -= 4)
+ {
+ xops[0] = adj_offsettable_operand (src, offset + stack_offset);
+ output_asm_insn (AS1(push%L0,%0), xops);
+ if (stack_p)
+ stack_offset += 4;
+ }
+
+ else
+ for (offset = length - 4; offset >= 0; )
+ {
+ for (num_tmps = 0; num_tmps < max_tmps && offset >= 0; num_tmps++)
+ {
+ tmp_info[num_tmps].load = AS2(mov%L0,%0,%1);
+ tmp_info[num_tmps].push = AS1(push%L0,%1);
+ tmp_info[num_tmps].xops[0] = adj_offsettable_operand (src, offset + stack_offset);
+ offset -= 4;
+ }
+
+ for (i = 0; i < num_tmps; i++)
+ output_asm_insn (tmp_info[i].load, tmp_info[i].xops);
+
+ for (i = 0; i < num_tmps; i++)
+ output_asm_insn (tmp_info[i].push, tmp_info[i].xops);
+
+ if (stack_p)
+ stack_offset += 4*num_tmps;
+ }
+
+ return "";
+}
+
+
+
+/* Output the appropriate code to move data between two memory locations */
+
+char *
+output_move_memory (operands, insn, length, tmp_start, n_operands)
+ rtx operands[];
+ rtx insn;
+ int length;
+ int tmp_start;
+ int n_operands;
+{
+ struct {
+ char *load;
+ char *store;
+ rtx xops[3];
+ } tmp_info[MAX_TMPS];
+
+ rtx dest = operands[0];
+ rtx src = operands[1];
+ rtx qi_tmp = NULL_RTX;
+ int max_tmps = 0;
+ int offset = 0;
+ int i, num_tmps;
+ rtx xops[3];
+
+ if (GET_CODE (dest) == MEM
+ && GET_CODE (XEXP (dest, 0)) == PRE_INC
+ && XEXP (XEXP (dest, 0), 0) == stack_pointer_rtx)
+ return output_move_pushmem (operands, insn, length, tmp_start, n_operands);
+
+ if (!offsettable_memref_p (src))
+ fatal_insn ("Source is not offsettable", insn);
+
+ if (!offsettable_memref_p (dest))
+ fatal_insn ("Destination is not offsettable", insn);
+
+ /* Figure out which temporary registers we have available */
+ for (i = tmp_start; i < n_operands; i++)
+ {
+ if (GET_CODE (operands[i]) == REG)
+ {
+ if ((length & 1) != 0 && !qi_tmp && QI_REG_P (operands[i]))
+ qi_tmp = operands[i];
+
+ if (reg_overlap_mentioned_p (operands[i], dest))
+ fatal_insn ("Temporary register overlaps the destination", insn);
+
+ if (reg_overlap_mentioned_p (operands[i], src))
+ fatal_insn ("Temporary register overlaps the source", insn);
+
+ tmp_info[ max_tmps++ ].xops[2] = operands[i];
+ if (max_tmps == MAX_TMPS)
+ break;
+ }
+ }
+
+ if (max_tmps == 0)
+ fatal_insn ("No scratch registers were found to do memory->memory moves", insn);
+
+ if ((length & 1) != 0)
+ {
+ if (!qi_tmp)
+ fatal_insn ("No byte register found when moving odd # of bytes.", insn);
+ }
+
+ while (length > 1)
+ {
+ for (num_tmps = 0; num_tmps < max_tmps; num_tmps++)
+ {
+ if (length >= 4)
+ {
+ tmp_info[num_tmps].load = AS2(mov%L0,%1,%2);
+ tmp_info[num_tmps].store = AS2(mov%L0,%2,%0);
+ tmp_info[num_tmps].xops[0] = adj_offsettable_operand (dest, offset);
+ tmp_info[num_tmps].xops[1] = adj_offsettable_operand (src, offset);
+ offset += 4;
+ length -= 4;
+ }
+ else if (length >= 2)
+ {
+ tmp_info[num_tmps].load = AS2(mov%W0,%1,%2);
+ tmp_info[num_tmps].store = AS2(mov%W0,%2,%0);
+ tmp_info[num_tmps].xops[0] = adj_offsettable_operand (dest, offset);
+ tmp_info[num_tmps].xops[1] = adj_offsettable_operand (src, offset);
+ offset += 2;
+ length -= 2;
+ }
+ else
+ break;
+ }
+
+ for (i = 0; i < num_tmps; i++)
+ output_asm_insn (tmp_info[i].load, tmp_info[i].xops);
+
+ for (i = 0; i < num_tmps; i++)
+ output_asm_insn (tmp_info[i].store, tmp_info[i].xops);
+ }
+
+ if (length == 1)
+ {
+ xops[0] = adj_offsettable_operand (dest, offset);
+ xops[1] = adj_offsettable_operand (src, offset);
+ xops[2] = qi_tmp;
+ output_asm_insn (AS2(mov%B0,%1,%2), xops);
+ output_asm_insn (AS2(mov%B0,%2,%0), xops);
+ }
+
+ return "";
+}
+
int
standard_80387_constant_p (x)
@@ -741,111 +1084,6 @@ symbolic_reference_mentioned_p (op)
return 0;
}
-/* Return a legitimate reference for ORIG (an address) using the
- register REG. If REG is 0, a new pseudo is generated.
-
- There are three types of references that must be handled:
-
- 1. Global data references must load the address from the GOT, via
- the PIC reg. An insn is emitted to do this load, and the reg is
- returned.
-
- 2. Static data references must compute the address as an offset
- from the GOT, whose base is in the PIC reg. An insn is emitted to
- compute the address into a reg, and the reg is returned. Static
- data objects have SYMBOL_REF_FLAG set to differentiate them from
- global data objects.
-
- 3. Constant pool addresses must be handled special. They are
- considered legitimate addresses, but only if not used with regs.
- When printed, the output routines know to print the reference with the
- PIC reg, even though the PIC reg doesn't appear in the RTL.
-
- GO_IF_LEGITIMATE_ADDRESS rejects symbolic references unless the PIC
- reg also appears in the address (except for constant pool references,
- noted above).
-
- "switch" statements also require special handling when generating
- PIC code. See comments by the `casesi' insn in i386.md for details. */
-
-rtx
-legitimize_pic_address (orig, reg)
- rtx orig;
- rtx reg;
-{
- rtx addr = orig;
- rtx new = orig;
-
- if (GET_CODE (addr) == SYMBOL_REF || GET_CODE (addr) == LABEL_REF)
- {
- if (GET_CODE (addr) == SYMBOL_REF && CONSTANT_POOL_ADDRESS_P (addr))
- reg = new = orig;
- else
- {
- if (reg == 0)
- reg = gen_reg_rtx (Pmode);
-
- if (GET_CODE (addr) == SYMBOL_REF && SYMBOL_REF_FLAG (addr))
- new = gen_rtx (PLUS, Pmode, pic_offset_table_rtx, orig);
- else
- new = gen_rtx (MEM, Pmode,
- gen_rtx (PLUS, Pmode,
- pic_offset_table_rtx, orig));
-
- emit_move_insn (reg, new);
- }
- current_function_uses_pic_offset_table = 1;
- return reg;
- }
- else if (GET_CODE (addr) == CONST || GET_CODE (addr) == PLUS)
- {
- rtx base;
-
- if (GET_CODE (addr) == CONST)
- {
- addr = XEXP (addr, 0);
- if (GET_CODE (addr) != PLUS)
- abort ();
- }
-
- if (XEXP (addr, 0) == pic_offset_table_rtx)
- return orig;
-
- if (reg == 0)
- reg = gen_reg_rtx (Pmode);
-
- base = legitimize_pic_address (XEXP (addr, 0), reg);
- addr = legitimize_pic_address (XEXP (addr, 1),
- base == reg ? NULL_RTX : reg);
-
- if (GET_CODE (addr) == CONST_INT)
- return plus_constant (base, INTVAL (addr));
-
- if (GET_CODE (addr) == PLUS && CONSTANT_P (XEXP (addr, 1)))
- {
- base = gen_rtx (PLUS, Pmode, base, XEXP (addr, 0));
- addr = XEXP (addr, 1);
- }
- return gen_rtx (PLUS, Pmode, base, addr);
- }
- return new;
-}
-
-/* Emit insns to move operands[1] into operands[0]. */
-
-void
-emit_pic_move (operands, mode)
- rtx *operands;
- enum machine_mode mode;
-{
- rtx temp = reload_in_progress ? operands[0] : gen_reg_rtx (Pmode);
-
- if (GET_CODE (operands[0]) == MEM && SYMBOLIC_CONST (operands[1]))
- operands[1] = (rtx) force_reg (SImode, operands[1]);
- else
- operands[1] = legitimize_pic_address (operands[1], temp);
-}
-
/* This function generates the assembly code for function entry.
FILE is an stdio stream to output the code to.
SIZE is an int: how many units of temporary storage to allocate. */
@@ -947,6 +1185,7 @@ simple_386_epilogue ()
return nregs == 0 || ! frame_pointer_needed;
}
+
/* This function generates the assembly code for function exit.
FILE is an stdio stream to output the code to.
SIZE is an int: how many units of temporary storage to deallocate. */
@@ -1025,7 +1264,7 @@ function_epilogue (file, size)
{
/* On i486, mov & pop is faster than "leave". */
- if (TARGET_486)
+ if (!TARGET_386)
{
xops[0] = frame_pointer_rtx;
output_asm_insn (AS2 (mov%L2,%0,%2), xops);
@@ -1064,6 +1303,527 @@ function_epilogue (file, size)
else
output_asm_insn ("ret", xops);
}
+
+
+/* GO_IF_LEGITIMATE_ADDRESS recognizes an RTL expression
+ that is a valid memory address for an instruction.
+ The MODE argument is the machine mode for the MEM expression
+ that wants to use this address.
+
+ On x86, legitimate addresses are:
+ base movl (base),reg
+ displacement movl disp,reg
+ base + displacement movl disp(base),reg
+ index + base movl (base,index),reg
+ (index + base) + displacement movl disp(base,index),reg
+ index*scale movl (,index,scale),reg
+ index*scale + disp movl disp(,index,scale),reg
+ index*scale + base movl (base,index,scale),reg
+ (index*scale + base) + disp movl disp(base,index,scale),reg
+
+ In each case, scale can be 1, 2, 4, 8. */
+
+/* This is exactly the same as print_operand_addr, except that
+ it recognizes addresses instead of printing them.
+
+ It only recognizes address in canonical form. LEGITIMIZE_ADDRESS should
+ convert common non-canonical forms to canonical form so that they will
+ be recognized. */
+
+#define ADDR_INVALID(msg,insn) \
+do { \
+ if (TARGET_DEBUG_ADDR) \
+ { \
+ fprintf (stderr, msg); \
+ debug_rtx (insn); \
+ } \
+} while (0)
+
+int
+legitimate_address_p (mode, addr, strict)
+ enum machine_mode mode;
+ register rtx addr;
+ int strict;
+{
+ rtx base = NULL_RTX;
+ rtx indx = NULL_RTX;
+ rtx scale = NULL_RTX;
+ rtx disp = NULL_RTX;
+
+ if (TARGET_DEBUG_ADDR)
+ {
+ fprintf (stderr,
+ "\n==========\nGO_IF_LEGITIMATE_ADDRESS, mode = %s, strict = %d\n",
+ GET_MODE_NAME (mode), strict);
+
+ debug_rtx (addr);
+ }
+
+ if (GET_CODE (addr) == REG || GET_CODE (addr) == SUBREG)
+ base = addr; /* base reg */
+
+ else if (GET_CODE (addr) == PLUS)
+ {
+ rtx op0 = XEXP (addr, 0);
+ rtx op1 = XEXP (addr, 1);
+ enum rtx_code code0 = GET_CODE (op0);
+ enum rtx_code code1 = GET_CODE (op1);
+
+ if (code0 == REG || code0 == SUBREG)
+ {
+ if (code1 == REG || code1 == SUBREG)
+ {
+ indx = op0; /* index + base */
+ base = op1;
+ }
+
+ else
+ {
+ base = op0; /* base + displacement */
+ disp = op1;
+ }
+ }
+
+ else if (code0 == MULT)
+ {
+ indx = XEXP (op0, 0);
+ scale = XEXP (op0, 1);
+
+ if (code1 == REG || code1 == SUBREG)
+ base = op1; /* index*scale + base */
+
+ else
+ disp = op1; /* index*scale + disp */
+ }
+
+ else if (code0 == PLUS && GET_CODE (XEXP (op0, 0)) == MULT)
+ {
+ indx = XEXP (XEXP (op0, 0), 0); /* index*scale + base + disp */
+ scale = XEXP (XEXP (op0, 0), 1);
+ base = XEXP (op0, 1);
+ disp = op1;
+ }
+
+ else if (code0 == PLUS)
+ {
+ indx = XEXP (op0, 0); /* index + base + disp */
+ base = XEXP (op0, 1);
+ disp = op1;
+ }
+
+ else
+ {
+ ADDR_INVALID ("PLUS subcode is not valid.\n", op0);
+ return FALSE;
+ }
+ }
+
+ else if (GET_CODE (addr) == MULT)
+ {
+ indx = XEXP (addr, 0); /* index*scale */
+ scale = XEXP (addr, 1);
+ }
+
+ else
+ disp = addr; /* displacement */
+
+ /* Allow arg pointer and stack pointer as index if there is not scaling */
+ if (base && indx && !scale
+ && (indx == arg_pointer_rtx || indx == stack_pointer_rtx))
+ {
+ rtx tmp = base;
+ base = indx;
+ indx = tmp;
+ }
+
+ /* Validate base register */
+ /* Don't allow SUBREG's here, it can lead to spill failures when the base
+ is one word out of a two word structure, which is represented internally
+ as a DImode int. */
+ if (base)
+ {
+ if (GET_CODE (base) != REG)
+ {
+ ADDR_INVALID ("Base is not a register.\n", base);
+ return FALSE;
+ }
+
+ if ((strict && !REG_OK_FOR_BASE_STRICT_P (base))
+ || (!strict && !REG_OK_FOR_BASE_NONSTRICT_P (base)))
+ {
+ ADDR_INVALID ("Base is not valid.\n", base);
+ return FALSE;
+ }
+ }
+
+ /* Validate index register */
+ /* Don't allow SUBREG's here, it can lead to spill failures when the index
+ is one word out of a two word structure, which is represented internally
+ as a DImode int. */
+ if (indx)
+ {
+ if (GET_CODE (indx) != REG)
+ {
+ ADDR_INVALID ("Index is not a register.\n", indx);
+ return FALSE;
+ }
+
+ if ((strict && !REG_OK_FOR_INDEX_STRICT_P (indx))
+ || (!strict && !REG_OK_FOR_INDEX_NONSTRICT_P (indx)))
+ {
+ ADDR_INVALID ("Index is not valid.\n", indx);
+ return FALSE;
+ }
+ }
+ else if (scale)
+ abort (); /* scale w/o index illegal */
+
+ /* Validate scale factor */
+ if (scale)
+ {
+ HOST_WIDE_INT value;
+
+ if (GET_CODE (scale) != CONST_INT)
+ {
+ ADDR_INVALID ("Scale is not valid.\n", scale);
+ return FALSE;
+ }
+
+ value = INTVAL (scale);
+ if (value != 1 && value != 2 && value != 4 && value != 8)
+ {
+ ADDR_INVALID ("Scale is not a good multiplier.\n", scale);
+ return FALSE;
+ }
+ }
+
+ /* Validate displacement */
+ if (disp)
+ {
+ if (!CONSTANT_ADDRESS_P (disp))
+ {
+ ADDR_INVALID ("Displacement is not valid.\n", disp);
+ return FALSE;
+ }
+
+ if (GET_CODE (disp) == CONST_DOUBLE)
+ {
+ ADDR_INVALID ("Displacement is a const_double.\n", disp);
+ return FALSE;
+ }
+
+ if (flag_pic && SYMBOLIC_CONST (disp) && base != pic_offset_table_rtx
+ && (indx != pic_offset_table_rtx || scale != NULL_RTX))
+ {
+ ADDR_INVALID ("Displacement is an invalid pic reference.\n", disp);
+ return FALSE;
+ }
+
+ if (HALF_PIC_P () && HALF_PIC_ADDRESS_P (disp)
+ && (base != NULL_RTX || indx != NULL_RTX))
+ {
+ ADDR_INVALID ("Displacement is an invalid half-pic reference.\n", disp);
+ return FALSE;
+ }
+ }
+
+ if (TARGET_DEBUG_ADDR)
+ fprintf (stderr, "Address is valid.\n");
+
+ /* Everything looks valid, return true */
+ return TRUE;
+}
+
+
+/* Return a legitimate reference for ORIG (an address) using the
+ register REG. If REG is 0, a new pseudo is generated.
+
+ There are three types of references that must be handled:
+
+ 1. Global data references must load the address from the GOT, via
+ the PIC reg. An insn is emitted to do this load, and the reg is
+ returned.
+
+ 2. Static data references must compute the address as an offset
+ from the GOT, whose base is in the PIC reg. An insn is emitted to
+ compute the address into a reg, and the reg is returned. Static
+ data objects have SYMBOL_REF_FLAG set to differentiate them from
+ global data objects.
+
+ 3. Constant pool addresses must be handled special. They are
+ considered legitimate addresses, but only if not used with regs.
+ When printed, the output routines know to print the reference with the
+ PIC reg, even though the PIC reg doesn't appear in the RTL.
+
+ GO_IF_LEGITIMATE_ADDRESS rejects symbolic references unless the PIC
+ reg also appears in the address (except for constant pool references,
+ noted above).
+
+ "switch" statements also require special handling when generating
+ PIC code. See comments by the `casesi' insn in i386.md for details. */
+
+rtx
+legitimize_pic_address (orig, reg)
+ rtx orig;
+ rtx reg;
+{
+ rtx addr = orig;
+ rtx new = orig;
+
+ if (GET_CODE (addr) == SYMBOL_REF || GET_CODE (addr) == LABEL_REF)
+ {
+ if (GET_CODE (addr) == SYMBOL_REF && CONSTANT_POOL_ADDRESS_P (addr))
+ reg = new = orig;
+ else
+ {
+ if (reg == 0)
+ reg = gen_reg_rtx (Pmode);
+
+ if ((GET_CODE (addr) == SYMBOL_REF && SYMBOL_REF_FLAG (addr))
+ || GET_CODE (addr) == LABEL_REF)
+ new = gen_rtx (PLUS, Pmode, pic_offset_table_rtx, orig);
+ else
+ new = gen_rtx (MEM, Pmode,
+ gen_rtx (PLUS, Pmode,
+ pic_offset_table_rtx, orig));
+
+ emit_move_insn (reg, new);
+ }
+ current_function_uses_pic_offset_table = 1;
+ return reg;
+ }
+ else if (GET_CODE (addr) == CONST || GET_CODE (addr) == PLUS)
+ {
+ rtx base;
+
+ if (GET_CODE (addr) == CONST)
+ {
+ addr = XEXP (addr, 0);
+ if (GET_CODE (addr) != PLUS)
+ abort ();
+ }
+
+ if (XEXP (addr, 0) == pic_offset_table_rtx)
+ return orig;
+
+ if (reg == 0)
+ reg = gen_reg_rtx (Pmode);
+
+ base = legitimize_pic_address (XEXP (addr, 0), reg);
+ addr = legitimize_pic_address (XEXP (addr, 1),
+ base == reg ? NULL_RTX : reg);
+
+ if (GET_CODE (addr) == CONST_INT)
+ return plus_constant (base, INTVAL (addr));
+
+ if (GET_CODE (addr) == PLUS && CONSTANT_P (XEXP (addr, 1)))
+ {
+ base = gen_rtx (PLUS, Pmode, base, XEXP (addr, 0));
+ addr = XEXP (addr, 1);
+ }
+ return gen_rtx (PLUS, Pmode, base, addr);
+ }
+ return new;
+}
+
+
+/* Emit insns to move operands[1] into operands[0]. */
+
+void
+emit_pic_move (operands, mode)
+ rtx *operands;
+ enum machine_mode mode;
+{
+ rtx temp = reload_in_progress ? operands[0] : gen_reg_rtx (Pmode);
+
+ if (GET_CODE (operands[0]) == MEM && SYMBOLIC_CONST (operands[1]))
+ operands[1] = (rtx) force_reg (SImode, operands[1]);
+ else
+ operands[1] = legitimize_pic_address (operands[1], temp);
+}
+
+
+/* Try machine-dependent ways of modifying an illegitimate address
+ to be legitimate. If we find one, return the new, valid address.
+ This macro is used in only one place: `memory_address' in explow.c.
+
+ OLDX is the address as it was before break_out_memory_refs was called.
+ In some cases it is useful to look at this to decide what needs to be done.
+
+ MODE and WIN are passed so that this macro can use
+ GO_IF_LEGITIMATE_ADDRESS.
+
+ It is always safe for this macro to do nothing. It exists to recognize
+ opportunities to optimize the output.
+
+ For the 80386, we handle X+REG by loading X into a register R and
+ using R+REG. R will go in a general reg and indexing will be used.
+ However, if REG is a broken-out memory address or multiplication,
+ nothing needs to be done because REG can certainly go in a general reg.
+
+ When -fpic is used, special handling is needed for symbolic references.
+ See comments by legitimize_pic_address in i386.c for details. */
+
+rtx
+legitimize_address (x, oldx, mode)
+ register rtx x;
+ register rtx oldx;
+ enum machine_mode mode;
+{
+ int changed = 0;
+ unsigned log;
+
+ if (TARGET_DEBUG_ADDR)
+ {
+ fprintf (stderr, "\n==========\nLEGITIMIZE_ADDRESS, mode = %s\n", GET_MODE_NAME (mode));
+ debug_rtx (x);
+ }
+
+ if (flag_pic && SYMBOLIC_CONST (x))
+ return legitimize_pic_address (x, 0);
+
+ /* Canonicalize shifts by 0, 1, 2, 3 into multiply */
+ if (GET_CODE (x) == ASHIFT
+ && GET_CODE (XEXP (x, 1)) == CONST_INT
+ && (log = (unsigned)exact_log2 (INTVAL (XEXP (x, 1)))) < 4)
+ {
+ changed = 1;
+ x = gen_rtx (MULT, Pmode,
+ force_reg (Pmode, XEXP (x, 0)),
+ GEN_INT (1 << log));
+ }
+
+ if (GET_CODE (x) == PLUS)
+ {
+ /* Canonicalize shifts by 0, 1, 2, 3 into multiply */
+ if (GET_CODE (XEXP (x, 0)) == ASHIFT
+ && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT
+ && (log = (unsigned)exact_log2 (INTVAL (XEXP (XEXP (x, 0), 1)))) < 4)
+ {
+ changed = 1;
+ XEXP (x, 0) = gen_rtx (MULT, Pmode,
+ force_reg (Pmode, XEXP (XEXP (x, 0), 0)),
+ GEN_INT (1 << log));
+ }
+
+ if (GET_CODE (XEXP (x, 1)) == ASHIFT
+ && GET_CODE (XEXP (XEXP (x, 1), 1)) == CONST_INT
+ && (log = (unsigned)exact_log2 (INTVAL (XEXP (XEXP (x, 1), 1)))) < 4)
+ {
+ changed = 1;
+ XEXP (x, 1) = gen_rtx (MULT, Pmode,
+ force_reg (Pmode, XEXP (XEXP (x, 1), 0)),
+ GEN_INT (1 << log));
+ }
+
+ /* Put multiply first if it isn't already */
+ if (GET_CODE (XEXP (x, 1)) == MULT)
+ {
+ rtx tmp = XEXP (x, 0);
+ XEXP (x, 0) = XEXP (x, 1);
+ XEXP (x, 1) = tmp;
+ changed = 1;
+ }
+
+ /* Canonicalize (plus (mult (reg) (const)) (plus (reg) (const)))
+ into (plus (plus (mult (reg) (const)) (reg)) (const)). This can be
+ created by virtual register instantiation, register elimination, and
+ similar optimizations. */
+ if (GET_CODE (XEXP (x, 0)) == MULT && GET_CODE (XEXP (x, 1)) == PLUS)
+ {
+ changed = 1;
+ x = gen_rtx (PLUS, Pmode,
+ gen_rtx (PLUS, Pmode, XEXP (x, 0), XEXP (XEXP (x, 1), 0)),
+ XEXP (XEXP (x, 1), 1));
+ }
+
+ /* Canonicalize (plus (plus (mult (reg) (const)) (plus (reg) (const))) const)
+ into (plus (plus (mult (reg) (const)) (reg)) (const)). */
+ else if (GET_CODE (x) == PLUS && GET_CODE (XEXP (x, 0)) == PLUS
+ && GET_CODE (XEXP (XEXP (x, 0), 0)) == MULT
+ && GET_CODE (XEXP (XEXP (x, 0), 1)) == PLUS
+ && CONSTANT_P (XEXP (x, 1)))
+ {
+ rtx constant, other;
+
+ if (GET_CODE (XEXP (x, 1)) == CONST_INT)
+ {
+ constant = XEXP (x, 1);
+ other = XEXP (XEXP (XEXP (x, 0), 1), 1);
+ }
+ else if (GET_CODE (XEXP (XEXP (XEXP (x, 0), 1), 1)) == CONST_INT)
+ {
+ constant = XEXP (XEXP (XEXP (x, 0), 1), 1);
+ other = XEXP (x, 1);
+ }
+ else
+ constant = 0;
+
+ if (constant)
+ {
+ changed = 1;
+ x = gen_rtx (PLUS, Pmode,
+ gen_rtx (PLUS, Pmode, XEXP (XEXP (x, 0), 0),
+ XEXP (XEXP (XEXP (x, 0), 1), 0)),
+ plus_constant (other, INTVAL (constant)));
+ }
+ }
+
+ if (changed && legitimate_address_p (mode, x, FALSE))
+ return x;
+
+ if (GET_CODE (XEXP (x, 0)) == MULT)
+ {
+ changed = 1;
+ XEXP (x, 0) = force_operand (XEXP (x, 0), 0);
+ }
+
+ if (GET_CODE (XEXP (x, 1)) == MULT)
+ {
+ changed = 1;
+ XEXP (x, 1) = force_operand (XEXP (x, 1), 0);
+ }
+
+ if (changed
+ && GET_CODE (XEXP (x, 1)) == REG
+ && GET_CODE (XEXP (x, 0)) == REG)
+ return x;
+
+ if (flag_pic && SYMBOLIC_CONST (XEXP (x, 1)))
+ {
+ changed = 1;
+ x = legitimize_pic_address (x, 0);
+ }
+
+ if (changed && legitimate_address_p (mode, x, FALSE))
+ return x;
+
+ if (GET_CODE (XEXP (x, 0)) == REG)
+ {
+ register rtx temp = gen_reg_rtx (Pmode);
+ register rtx val = force_operand (XEXP (x, 1), temp);
+ if (val != temp)
+ emit_move_insn (temp, val);
+
+ XEXP (x, 1) = temp;
+ return x;
+ }
+
+ else if (GET_CODE (XEXP (x, 1)) == REG)
+ {
+ register rtx temp = gen_reg_rtx (Pmode);
+ register rtx val = force_operand (XEXP (x, 0), temp);
+ if (val != temp)
+ emit_move_insn (temp, val);
+
+ XEXP (x, 0) = temp;
+ return x;
+ }
+ }
+
+ return x;
+}
+
/* Print an integer constant expression in assembler syntax. Addition
and subtraction are the only arithmetic that may appear in these
@@ -1102,7 +1862,9 @@ output_pic_addr_const (file, x, code)
fprintf (file, "@GOTOFF(%%ebx)");
else if (code == 'P')
fprintf (file, "@PLT");
- else if (GET_CODE (x) == LABEL_REF || ! SYMBOL_REF_FLAG (x))
+ else if (GET_CODE (x) == LABEL_REF)
+ fprintf (file, "@GOTOFF");
+ else if (! SYMBOL_REF_FLAG (x))
fprintf (file, "@GOT");
else
fprintf (file, "@GOTOFF");
@@ -1322,7 +2084,7 @@ print_operand (file, x, code)
REAL_VALUE_TO_DECIMAL (r, "%.22e", dstr);
fprintf (file, "%s", dstr);
}
- else
+ else
{
if (code != 'P')
{
@@ -1424,15 +2186,14 @@ print_operand_address (file, addr)
if (addr != 0)
{
- if (GET_CODE (addr) == LABEL_REF)
+ if (flag_pic)
+ output_pic_addr_const (file, addr, 0);
+
+ else if (GET_CODE (addr) == LABEL_REF)
output_asm_label (addr);
+
else
- {
- if (flag_pic)
- output_pic_addr_const (file, addr, 0);
- else
- output_addr_const (file, addr);
- }
+ output_addr_const (file, addr);
}
if (ireg != 0 && GET_CODE (ireg) == MULT)
@@ -1666,32 +2427,7 @@ binary_387_op (op, mode)
}
}
-/* Return 1 if this is a valid conversion operation on a 387.
- OP is the expression matched, and MODE is its mode. */
-
-int
-convert_387_op (op, mode)
- register rtx op;
- enum machine_mode mode;
-{
- if (mode != VOIDmode && mode != GET_MODE (op))
- return 0;
-
- switch (GET_CODE (op))
- {
- case FLOAT:
- return GET_MODE (XEXP (op, 0)) == SImode;
-
- case FLOAT_EXTEND:
- return ((mode == DFmode && GET_MODE (XEXP (op, 0)) == SFmode)
- || (mode == XFmode && GET_MODE (XEXP (op, 0)) == DFmode)
- || (mode == XFmode && GET_MODE (XEXP (op, 0)) == SFmode));
-
- default:
- return 0;
- }
-}
-
+
/* Return 1 if this is a valid shift or rotate operation on a 386.
OP is the expression matched, and MODE is its mode. */
@@ -1813,9 +2549,9 @@ output_387_binary_op (insn, operands)
return strcat (buf, AS2 (p,%2,%0));
if (STACK_TOP_P (operands[0]))
- return strcat (buf, AS2 (,%y2,%0));
+ return strcat (buf, AS2C (%y2,%0));
else
- return strcat (buf, AS2 (,%2,%0));
+ return strcat (buf, AS2C (%2,%0));
case MINUS:
case DIV:
@@ -1848,12 +2584,12 @@ output_387_binary_op (insn, operands)
if (STACK_TOP_P (operands[0]))
{
if (STACK_TOP_P (operands[1]))
- return strcat (buf, AS2 (,%y2,%0));
+ return strcat (buf, AS2C (%y2,%0));
else
return strcat (buf, AS2 (r,%y1,%0));
}
else if (STACK_TOP_P (operands[1]))
- return strcat (buf, AS2 (,%1,%0));
+ return strcat (buf, AS2C (%1,%0));
else
return strcat (buf, AS2 (r,%2,%0));
@@ -2083,7 +2819,7 @@ save_386_machine_status (p)
struct function *p;
{
p->machine = (struct machine_function *) xmalloc (sizeof i386_stack_locals);
- bcopy (i386_stack_locals, p->machine->i386_stack_locals,
+ bcopy ((char *) i386_stack_locals, (char *) p->machine->i386_stack_locals,
sizeof i386_stack_locals);
}
@@ -2091,7 +2827,7 @@ void
restore_386_machine_status (p)
struct function *p;
{
- bcopy (p->machine->i386_stack_locals, i386_stack_locals,
+ bcopy ((char *) p->machine->i386_stack_locals, (char *) i386_stack_locals,
sizeof i386_stack_locals);
free (p->machine);
}
diff --git a/gnu/usr.bin/cc/cc_int/bc-emit.c b/gnu/usr.bin/cc/cc_int/bc-emit.c
index b5d0c6c..296fdd9 100644
--- a/gnu/usr.bin/cc/cc_int/bc-emit.c
+++ b/gnu/usr.bin/cc/cc_int/bc-emit.c
@@ -145,14 +145,14 @@ bc_sym_write (file)
{
fprintf (file, "\n\t.comm ");
prsym (file, s->name);
- fprintf (file, ", %d\n", s->val);
+ fprintf (file, ", %lu\n", s->val);
}
}
else if (s->common)
{
fprintf (file, "\n\t.lcomm ");
prsym (file, s->name);
- fprintf (file, ", %d\n", s->val);
+ fprintf (file, ", %lu\n", s->val);
}
}
}
@@ -867,7 +867,7 @@ bc_emit_bytecode (bytecode)
char byte;
static int prev_lineno = -1;
- byte = bytecode;
+ byte = (char) bytecode;
#ifdef BCDEBUG_PRINT_CODE
if (lineno != prev_lineno)
@@ -971,7 +971,7 @@ bc_emit_trampoline (callinfo)
static int n;
sprintf (mylab, "*LB%d", n++);
-
+
BC_EMIT_TRAMPOLINE (trampoline, callinfo);
seg_defsym (bytecode, mylab);
diff --git a/gnu/usr.bin/cc/cc_int/bc-optab.c b/gnu/usr.bin/cc/cc_int/bc-optab.c
index b8ac57d..447e32c 100644
--- a/gnu/usr.bin/cc/cc_int/bc-optab.c
+++ b/gnu/usr.bin/cc/cc_int/bc-optab.c
@@ -634,7 +634,7 @@ bc_init_mode_to_code_map ()
for (mode = 0; mode < MAX_MACHINE_MODE + 1; mode++)
{
- signed_mode_to_code_map[mode] =
+ signed_mode_to_code_map[mode] =
unsigned_mode_to_code_map[mode] =
LAST_AND_UNUSED_TYPECODE;
}
@@ -699,7 +699,7 @@ bc_expand_binary_operation (optab, resulttype, arg0, arg1)
{
int i, besti, cost, bestcost;
enum typecode resultcode, arg0code, arg1code;
-
+
resultcode = preferred_typecode (TYPE_MODE (resulttype), TREE_UNSIGNED (resulttype));
arg0code = preferred_typecode (TYPE_MODE (TREE_TYPE (arg0)), TREE_UNSIGNED (resulttype));
arg1code = preferred_typecode (TYPE_MODE (TREE_TYPE (arg1)), TREE_UNSIGNED (resulttype));
@@ -740,7 +740,7 @@ bc_expand_unary_operation (optab, resulttype, arg0)
{
int i, besti, cost, bestcost;
enum typecode resultcode, arg0code;
-
+
resultcode = preferred_typecode (TYPE_MODE (resulttype), TREE_UNSIGNED (resulttype));
arg0code = preferred_typecode (TYPE_MODE (TREE_TYPE (arg0)), TREE_UNSIGNED (TREE_TYPE (arg0)));
diff --git a/gnu/usr.bin/cc/cc_int/c-common.c b/gnu/usr.bin/cc/cc_int/c-common.c
index f18c270..563c171 100644
--- a/gnu/usr.bin/cc/cc_int/c-common.c
+++ b/gnu/usr.bin/cc/cc_int/c-common.c
@@ -174,7 +174,7 @@ combine_strings (strings)
wide_flag = 1;
}
- /* Compute the number of elements, for the array type. */
+ /* Compute the number of elements, for the array type. */
nchars = wide_flag ? length / wchar_bytes : length;
/* Create the array type for the string constant.
@@ -215,7 +215,8 @@ decl_attributes (decl, attributes)
for (a = attributes; a; a = TREE_CHAIN (a))
if (!(name = TREE_VALUE (a)))
continue;
- else if (name == get_identifier ("packed"))
+ else if (name == get_identifier ("packed")
+ || name == get_identifier ("__packed__"))
{
if (TREE_CODE (decl) == FIELD_DECL)
DECL_PACKED (decl) = 1;
@@ -226,13 +227,15 @@ decl_attributes (decl, attributes)
}
else if (TREE_VALUE (a) == get_identifier ("noreturn")
- || TREE_VALUE (a) == get_identifier ("volatile"))
+ || TREE_VALUE (a) == get_identifier ("__noreturn__")
+ || TREE_VALUE (a) == get_identifier ("volatile")
+ || TREE_VALUE (a) == get_identifier ("__volatile__"))
{
if (TREE_CODE (decl) == FUNCTION_DECL)
TREE_THIS_VOLATILE (decl) = 1;
else if (TREE_CODE (type) == POINTER_TYPE
&& TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE)
- TREE_TYPE (decl) = type
+ TREE_TYPE (decl) = type
= build_pointer_type
(build_type_variant (TREE_TYPE (type),
TREE_READONLY (TREE_TYPE (type)), 1));
@@ -240,7 +243,8 @@ decl_attributes (decl, attributes)
warning_with_decl (decl, "`%s' attribute ignored",
IDENTIFIER_POINTER (TREE_VALUE (a)));
}
- else if (TREE_VALUE (a) == get_identifier ("const"))
+ else if (TREE_VALUE (a) == get_identifier ("const")
+ || TREE_VALUE (a) == get_identifier ("__const__"))
{
if (TREE_CODE (decl) == FUNCTION_DECL)
TREE_READONLY (decl) = 1;
@@ -253,11 +257,25 @@ decl_attributes (decl, attributes)
else
warning_with_decl (decl, "`const' attribute ignored");
}
+ else if (TREE_VALUE (a) == get_identifier ("transparent_union")
+ || TREE_VALUE (a) == get_identifier ("__transparent_union__"))
+ {
+ if (TREE_CODE (decl) == PARM_DECL
+ && TREE_CODE (type) == UNION_TYPE
+ && TYPE_MODE (type) == DECL_MODE (TYPE_FIELDS (type)))
+ DECL_TRANSPARENT_UNION (decl) = 1;
+ else if (TREE_CODE (decl) == TYPE_DECL
+ && TREE_CODE (type) == UNION_TYPE
+ && TYPE_MODE (type) == DECL_MODE (TYPE_FIELDS (type)))
+ TYPE_TRANSPARENT_UNION (type) = 1;
+ else
+ warning_with_decl (decl, "`transparent_union' attribute ignored");
+ }
else if (TREE_CODE (name) != TREE_LIST)
{
#ifdef VALID_MACHINE_ATTRIBUTE
if (VALID_MACHINE_ATTRIBUTE (type, new_attr, name))
- {
+ {
register tree atlist;
for (atlist = new_attr; atlist; atlist = TREE_CHAIN (atlist))
@@ -273,7 +291,8 @@ found_attr:;
IDENTIFIER_POINTER (name));
}
else if ( args = TREE_CHAIN(name),
- !strcmp (IDENTIFIER_POINTER (name = TREE_PURPOSE (name)), "mode")
+ (!strcmp (IDENTIFIER_POINTER (name = TREE_PURPOSE (name)), "mode")
+ || !strcmp (IDENTIFIER_POINTER (name), "__mode__"))
&& list_length (args) == 1
&& TREE_CODE (TREE_VALUE (args)) == IDENTIFIER_NODE)
{
@@ -300,7 +319,8 @@ found_attr:;
if (i == NUM_MACHINE_MODES)
error_with_decl (decl, "unknown machine mode `%s'", specified_name);
}
- else if (!strcmp (IDENTIFIER_POINTER (name), "section")
+ else if ((!strcmp (IDENTIFIER_POINTER (name), "section")
+ || !strcmp (IDENTIFIER_POINTER (name), "__section__"))
&& list_length (args) == 1
&& TREE_CODE (TREE_VALUE (args)) == STRING_CST)
{
@@ -327,7 +347,8 @@ found_attr:;
error_with_decl (decl, "section attributes are not supported for this target");
#endif
}
- else if (!strcmp (IDENTIFIER_POINTER (name), "aligned")
+ else if ((!strcmp (IDENTIFIER_POINTER (name), "aligned")
+ || !strcmp (IDENTIFIER_POINTER (name), "__aligned__"))
&& list_length (args) == 1
&& TREE_CODE (TREE_VALUE (args)) == INTEGER_CST)
{
@@ -348,7 +369,7 @@ found_attr:;
}
align = TREE_INT_CST_LOW (align_expr) * BITS_PER_UNIT;
-
+
if (exact_log2 (align) == -1)
error_with_decl (decl,
"requested alignment of `%s' is not a power of 2");
@@ -359,7 +380,8 @@ found_attr:;
else
DECL_ALIGN (decl) = align;
}
- else if (!strcmp (IDENTIFIER_POINTER (name), "format")
+ else if ((!strcmp (IDENTIFIER_POINTER (name), "format")
+ || !strcmp (IDENTIFIER_POINTER (name), "__format__"))
&& list_length (args) == 3
&& TREE_CODE (TREE_VALUE (args)) == IDENTIFIER_NODE
&& TREE_CODE (TREE_VALUE (TREE_CHAIN (args))) == INTEGER_CST
@@ -373,24 +395,26 @@ found_attr:;
int is_scan;
tree argument;
int arg_num;
-
+
if (TREE_CODE (decl) != FUNCTION_DECL)
{
error_with_decl (decl,
"argument format specified for non-function `%s'");
continue;
}
-
- if (!strcmp (IDENTIFIER_POINTER (format_type), "printf"))
+
+ if (!strcmp (IDENTIFIER_POINTER (format_type), "printf")
+ || !strcmp (IDENTIFIER_POINTER (format_type), "__printf__"))
is_scan = 0;
- else if (!strcmp (IDENTIFIER_POINTER (format_type), "scanf"))
+ else if (!strcmp (IDENTIFIER_POINTER (format_type), "scanf")
+ || !strcmp (IDENTIFIER_POINTER (format_type), "__scanf__"))
is_scan = 1;
else
{
error_with_decl (decl, "unrecognized format specifier for `%s'");
continue;
}
-
+
/* Strip any conversions from the string index and first arg number
and verify they are constants. */
while (TREE_CODE (format_num_expr) == NOP_EXPR
@@ -470,9 +494,11 @@ found_attr:;
#define T_I &integer_type_node
#define T_L &long_integer_type_node
+#define T_LL &long_long_integer_type_node
#define T_S &short_integer_type_node
#define T_UI &unsigned_type_node
#define T_UL &long_unsigned_type_node
+#define T_ULL &long_long_unsigned_type_node
#define T_US &short_unsigned_type_node
#define T_F &float_type_node
#define T_D &double_type_node
@@ -493,6 +519,9 @@ typedef struct {
/* Type of argument if length modifier `l' is used.
If NULL, then this modifier is not allowed. */
tree *llen;
+ /* Type of argument if length modifier `q' or `ll' is used.
+ If NULL, then this modifier is not allowed. */
+ tree *qlen;
/* Type of argument if length modifier `L' is used.
If NULL, then this modifier is not allowed. */
tree *bigllen;
@@ -501,32 +530,32 @@ typedef struct {
} format_char_info;
static format_char_info print_char_table[] = {
- { "di", 0, T_I, T_I, T_L, NULL, "-wp0 +" },
- { "oxX", 0, T_UI, T_UI, T_UL, NULL, "-wp0#" },
- { "u", 0, T_UI, T_UI, T_UL, NULL, "-wp0" },
+ { "di", 0, T_I, T_I, T_L, T_LL, T_LL, "-wp0 +" },
+ { "oxX", 0, T_UI, T_UI, T_UL, T_ULL, T_ULL, "-wp0#" },
+ { "u", 0, T_UI, T_UI, T_UL, T_ULL, T_ULL, "-wp0" },
/* Two GNU extensions. */
- { "Z", 0, T_ST, NULL, NULL, NULL, "-wp0" },
- { "m", 0, T_UI, T_UI, T_UL, NULL, "-wp" },
- { "feEgG", 0, T_D, NULL, NULL, T_LD, "-wp0 +#" },
- { "c", 0, T_I, NULL, T_W, NULL, "-w" },
- { "C", 0, T_W, NULL, NULL, NULL, "-w" },
- { "s", 1, T_C, NULL, T_W, NULL, "-wp" },
- { "S", 1, T_W, NULL, NULL, NULL, "-wp" },
- { "p", 1, T_V, NULL, NULL, NULL, "-w" },
- { "n", 1, T_I, T_S, T_L, NULL, "" },
+ { "Z", 0, T_ST, NULL, NULL, NULL, NULL, "-wp0" },
+ { "m", 0, T_UI, T_UI, T_UL, NULL, NULL, "-wp" },
+ { "feEgG", 0, T_D, NULL, NULL, NULL, T_LD, "-wp0 +#" },
+ { "c", 0, T_I, NULL, T_W, NULL, NULL, "-w" },
+ { "C", 0, T_W, NULL, NULL, NULL, NULL, "-w" },
+ { "s", 1, T_C, NULL, T_W, NULL, NULL, "-wp" },
+ { "S", 1, T_W, NULL, NULL, NULL, NULL, "-wp" },
+ { "p", 1, T_V, NULL, NULL, NULL, NULL, "-w" },
+ { "n", 1, T_I, T_S, T_L, T_LL, NULL, "" },
{ NULL }
};
static format_char_info scan_char_table[] = {
- { "di", 1, T_I, T_S, T_L, NULL, "*" },
- { "ouxX", 1, T_UI, T_US, T_UL, NULL, "*" },
- { "efgEG", 1, T_F, NULL, T_D, T_LD, "*" },
- { "sc", 1, T_C, NULL, T_W, NULL, "*a" },
- { "[", 1, T_C, NULL, NULL, NULL, "*a" },
- { "C", 1, T_W, NULL, NULL, NULL, "*" },
- { "S", 1, T_W, NULL, NULL, NULL, "*" },
- { "p", 2, T_V, NULL, NULL, NULL, "*" },
- { "n", 1, T_I, T_S, T_L, NULL, "" },
+ { "di", 1, T_I, T_S, T_L, T_LL, T_LL, "*" },
+ { "ouxX", 1, T_UI, T_US, T_UL, T_ULL, T_ULL, "*" },
+ { "efgEG", 1, T_F, NULL, T_D, NULL, T_LD, "*" },
+ { "sc", 1, T_C, NULL, T_W, NULL, NULL, "*a" },
+ { "[", 1, T_C, NULL, NULL, NULL, NULL, "*a" },
+ { "C", 1, T_W, NULL, NULL, NULL, NULL, "*" },
+ { "S", 1, T_W, NULL, NULL, NULL, NULL, "*" },
+ { "p", 2, T_V, NULL, NULL, NULL, NULL, "*" },
+ { "n", 1, T_I, T_S, T_L, T_LL, NULL, "" },
{ NULL }
};
@@ -783,7 +812,7 @@ check_format_info (info, params)
flag_chars[i++] = *format_chars++;
flag_chars[i] = 0;
}
- /* "If the space and + flags both appear,
+ /* "If the space and + flags both appear,
the space flag will be ignored." */
if (index (flag_chars, ' ') != 0
&& index (flag_chars, '+') != 0)
@@ -872,10 +901,13 @@ check_format_info (info, params)
}
}
}
- if (*format_chars == 'h' || *format_chars == 'l' || *format_chars == 'L')
+ if (*format_chars == 'h' || *format_chars == 'l' || *format_chars == 'q' ||
+ *format_chars == 'L')
length_char = *format_chars++;
else
length_char = 0;
+ if (length_char == 'l' && *format_chars == 'l')
+ length_char = 'q', format_chars++;
aflag = 0;
if (*format_chars == 'a')
{
@@ -981,6 +1013,7 @@ check_format_info (info, params)
default: wanted_type = fci->nolen ? *(fci->nolen) : 0; break;
case 'h': wanted_type = fci->hlen ? *(fci->hlen) : 0; break;
case 'l': wanted_type = fci->llen ? *(fci->llen) : 0; break;
+ case 'q': wanted_type = fci->qlen ? *(fci->qlen) : 0; break;
case 'L': wanted_type = fci->bigllen ? *(fci->bigllen) : 0; break;
}
if (wanted_type == 0)
@@ -1051,7 +1084,7 @@ check_format_info (info, params)
{
register char *this;
register char *that;
-
+
this = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (wanted_type)));
that = 0;
if (TREE_CODE (cur_type) != ERROR_MARK
@@ -1333,6 +1366,37 @@ type_for_mode (mode, unsignedp)
return 0;
}
+/* Return the minimum number of bits needed to represent VALUE in a
+ signed or unsigned type, UNSIGNEDP says which. */
+
+int
+min_precision (value, unsignedp)
+ tree value;
+ int unsignedp;
+{
+ int log;
+
+ /* If the value is negative, compute its negative minus 1. The latter
+ adjustment is because the absolute value of the largest negative value
+ is one larger than the largest positive value. This is equivalent to
+ a bit-wise negation, so use that operation instead. */
+
+ if (tree_int_cst_sgn (value) < 0)
+ value = fold (build1 (BIT_NOT_EXPR, TREE_TYPE (value), value));
+
+ /* Return the number of bits needed, taking into account the fact
+ that we need one more bit for a signed than unsigned type. */
+
+ if (integer_zerop (value))
+ log = 0;
+ else if (TREE_INT_CST_HIGH (value) != 0)
+ log = HOST_BITS_PER_WIDE_INT + floor_log2 (TREE_INT_CST_HIGH (value));
+ else
+ log = floor_log2 (TREE_INT_CST_LOW (value));
+
+ return log + 1 + ! unsignedp;
+}
+
/* Print an error message for invalid operands to arith operation CODE.
NOP_EXPR is used as a special case (see truthvalue_conversion). */
@@ -1444,9 +1508,11 @@ shorten_compare (op0_ptr, op1_ptr, restype_ptr, rescode_ptr)
real2 = TREE_CODE (TREE_TYPE (primop1)) == REAL_TYPE;
/* If first arg is constant, swap the args (changing operation
- so value is preserved), for canonicalization. */
+ so value is preserved), for canonicalization. Don't do this if
+ the second arg is 0. */
- if (TREE_CONSTANT (primop0))
+ if (TREE_CONSTANT (primop0)
+ && ! integer_zerop (primop1) && ! real_zerop (primop1))
{
register tree tem = primop0;
register int temi = unsignedp0;
@@ -1685,13 +1751,23 @@ shorten_compare (op0_ptr, op1_ptr, restype_ptr, rescode_ptr)
switch (code)
{
case GE_EXPR:
- if (extra_warnings)
+ /* All unsigned values are >= 0, so we warn if extra warnings
+ are requested. However, if OP0 is a constant that is
+ >= 0, the signedness of the comparison isn't an issue,
+ so suppress the warning. */
+ if (extra_warnings
+ && ! (TREE_CODE (primop0) == INTEGER_CST
+ && ! TREE_OVERFLOW (convert (signed_type (type),
+ primop0))))
warning ("unsigned value >= 0 is always 1");
value = integer_one_node;
break;
case LT_EXPR:
- if (extra_warnings)
+ if (extra_warnings
+ && ! (TREE_CODE (primop0) == INTEGER_CST
+ && ! TREE_OVERFLOW (convert (signed_type (type),
+ primop0))))
warning ("unsigned value < 0 is always 0");
value = integer_zero_node;
}
@@ -1822,7 +1898,7 @@ truthvalue_conversion (expr)
truthvalue_conversion (TREE_OPERAND (expr, 0)));
else
return truthvalue_conversion (TREE_OPERAND (expr, 0));
-
+
case COND_EXPR:
/* Distribute the conversion into the arms of a COND_EXPR. */
return fold (build (COND_EXPR, integer_type_node, TREE_OPERAND (expr, 0),
diff --git a/gnu/usr.bin/cc/cc_int/caller-save.c b/gnu/usr.bin/cc/cc_int/caller-save.c
index 5b09606..bcfe3c8 100644
--- a/gnu/usr.bin/cc/cc_int/caller-save.c
+++ b/gnu/usr.bin/cc/cc_int/caller-save.c
@@ -41,13 +41,13 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
register because it is live we first try to save in multi-register modes.
If that is not possible the save is done one register at a time. */
-static enum machine_mode
+static enum machine_mode
regno_save_mode[FIRST_PSEUDO_REGISTER][MAX_MOVE_MAX / MAX_UNITS_PER_WORD + 1];
/* For each hard register, a place on the stack where it can be saved,
if needed. */
-static rtx
+static rtx
regno_save_mem[FIRST_PSEUDO_REGISTER][MAX_MOVE_MAX / MAX_UNITS_PER_WORD + 1];
/* We will only make a register eligible for caller-save if it can be
@@ -56,9 +56,9 @@ static rtx
when we emit them, the addresses might not be valid, so they might not
be recognized. */
-static enum insn_code
+static enum insn_code
reg_save_code[FIRST_PSEUDO_REGISTER][MAX_MOVE_MAX / MAX_UNITS_PER_WORD + 1];
-static enum insn_code
+static enum insn_code
reg_restore_code[FIRST_PSEUDO_REGISTER][MAX_MOVE_MAX / MAX_UNITS_PER_WORD + 1];
/* Set of hard regs currently live (during scan of all insns). */
@@ -88,7 +88,7 @@ static int insert_save_restore PROTO((rtx, int, int,
Look at all the hard registers that are used by a call and for which
regclass.c has not already excluded from being used across a call.
- Ensure that we can find a mode to save the register and that there is a
+ Ensure that we can find a mode to save the register and that there is a
simple insn to save and restore the register. This latter check avoids
problems that would occur if we tried to save the MQ register of some
machines directly into memory. */
@@ -230,18 +230,18 @@ init_save_areas ()
We assume that our caller has set up the elimination table to the
worst (largest) possible offsets.
- Set *PCHANGED to 1 if we had to allocate some memory for the save area.
+ Set *PCHANGED to 1 if we had to allocate some memory for the save area.
Future work:
In the fallback case we should iterate backwards across all possible
- modes for the save, choosing the largest available one instead of
+ modes for the save, choosing the largest available one instead of
falling back to the smallest mode immediately. (eg TF -> DF -> SF).
We do not try to use "move multiple" instructions that exist
- on some machines (such as the 68k moveml). It could be a win to try
+ on some machines (such as the 68k moveml). It could be a win to try
and use them when possible. The hard part is doing it in a way that is
- machine independent since they might be saving non-consecutive
+ machine independent since they might be saving non-consecutive
registers. (imagine caller-saving d0,d1,a0,a1 on the 68k) */
int
@@ -263,13 +263,13 @@ setup_save_areas (pchanged)
if (reg_renumber[i] >= 0 && reg_n_calls_crossed[i] > 0)
{
int regno = reg_renumber[i];
- int endregno
+ int endregno
= regno + HARD_REGNO_NREGS (regno, GET_MODE (regno_reg_rtx[i]));
int nregs = endregno - regno;
for (j = 0; j < nregs; j++)
{
- if (call_used_regs[regno+j])
+ if (call_used_regs[regno+j])
SET_HARD_REG_BIT (hard_regs_used, regno+j);
}
}
@@ -319,10 +319,10 @@ setup_save_areas (pchanged)
{
/* This should not depend on WORDS_BIG_ENDIAN.
The order of words in regs is the same as in memory. */
- rtx temp = gen_rtx (MEM, regno_save_mode[i+k][1],
+ rtx temp = gen_rtx (MEM, regno_save_mode[i+k][1],
XEXP (regno_save_mem[i][j], 0));
- regno_save_mem[i+k][1]
+ regno_save_mem[i+k][1]
= adj_offsettable_operand (temp, k * UNITS_PER_WORD);
}
*pchanged = 1;
@@ -425,7 +425,7 @@ save_call_clobbered_regs (insn_mode)
test at this point because registers that die in a CALL_INSN
are not live across the call and likewise for registers that
are born in the CALL_INSN.
-
+
If registers are filled with parameters for this function,
and some of these are also being set by this function, then
they will not appear to die (no REG_DEAD note for them),
@@ -457,7 +457,7 @@ save_call_clobbered_regs (insn_mode)
/* It must not be set by this instruction. */
&& ! TEST_HARD_REG_BIT (this_call_sets, regno)
&& ! TEST_HARD_REG_BIT (hard_regs_saved, regno))
- regno += insert_save_restore (insn, 1, regno,
+ regno += insert_save_restore (insn, 1, regno,
insn_mode, 0);
/* Put the information for this CALL_INSN on top of what
@@ -555,7 +555,7 @@ clear_reg_live (reg)
CLEAR_HARD_REG_BIT (hard_regs_need_restore, i);
CLEAR_HARD_REG_BIT (hard_regs_saved, i);
}
-}
+}
/* If any register currently residing in the save area is referenced in X,
which is part of INSN, emit code to restore the register in front of INSN.
@@ -608,7 +608,7 @@ restore_referenced_regs (x, insn, insn_mode)
return;
}
-
+
fmt = GET_RTX_FORMAT (code);
for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
{
@@ -674,7 +674,7 @@ insert_save_restore (insn, save_p, regno, insn_mode, maxrestore)
int i, j, k;
int ok;
- /* See if we can save several registers with a single instruction.
+ /* See if we can save several registers with a single instruction.
Work backwards to the single register case. */
for (i = MOVE_MAX / UNITS_PER_WORD; i > 0; i--)
{
@@ -687,7 +687,7 @@ insert_save_restore (insn, save_p, regno, insn_mode, maxrestore)
|| TEST_HARD_REG_BIT (hard_regs_saved, regno + j))
ok = 0;
}
- else
+ else
continue;
/* Must do this one save at a time */
@@ -732,10 +732,10 @@ insert_save_restore (insn, save_p, regno, insn_mode, maxrestore)
/* Must do this one restore at a time */
if (! ok)
continue;
-
+
pat = gen_rtx (SET, VOIDmode,
- gen_rtx (REG, GET_MODE (regno_save_mem[regno][i]),
- regno),
+ gen_rtx (REG, GET_MODE (regno_save_mem[regno][i]),
+ regno),
regno_save_mem[regno][i]);
code = reg_restore_code[regno][i];
diff --git a/gnu/usr.bin/cc/cc_int/calls.c b/gnu/usr.bin/cc/cc_int/calls.c
index f035079..f567982 100644
--- a/gnu/usr.bin/cc/cc_int/calls.c
+++ b/gnu/usr.bin/cc/cc_int/calls.c
@@ -443,7 +443,8 @@ emit_call_1 (funexp, funtype, stack_size, struct_value_size, next_arg_reg,
{
if (!already_popped)
CALL_INSN_FUNCTION_USAGE (call_insn) =
- gen_rtx (EXPR_LIST, CLOBBER, stack_pointer_rtx,
+ gen_rtx (EXPR_LIST, VOIDmode,
+ gen_rtx (CLOBBER, VOIDmode, stack_pointer_rtx),
CALL_INSN_FUNCTION_USAGE (call_insn));
stack_size -= RETURN_POPS_ARGS (funtype, stack_size);
stack_size_rtx = GEN_INT (stack_size);
@@ -526,7 +527,7 @@ expand_call (exp, target, ignore)
/* Nonzero if this is an indirect function call. */
int current_call_is_indirect = 0;
- /* Nonzero if we must avoid push-insns in the args for this call.
+ /* Nonzero if we must avoid push-insns in the args for this call.
If stack space is allocated for register parameters, but not by the
caller, then it is preallocated in the fixed part of the stack frame.
So the entire argument block must then be preallocated (i.e., we
@@ -621,7 +622,7 @@ expand_call (exp, target, ignore)
}
}
- /* If we don't have specific function to call, see if we have a
+ /* If we don't have specific function to call, see if we have a
constant or `noreturn' function from the type. */
if (fndecl == 0)
{
@@ -667,9 +668,6 @@ expand_call (exp, target, ignore)
{
struct_value_size = int_size_in_bytes (TREE_TYPE (exp));
- if (struct_value_size < 0)
- abort ();
-
if (target && GET_CODE (target) == MEM)
structure_value_addr = XEXP (target, 0);
else
@@ -680,6 +678,9 @@ expand_call (exp, target, ignore)
specified. If we were to allocate space on the stack here,
we would have no way of knowing when to free it. */
+ if (struct_value_size < 0)
+ abort ();
+
structure_value_addr
= XEXP (assign_stack_temp (BLKmode, struct_value_size, 1), 0);
target = 0;
@@ -901,15 +902,18 @@ expand_call (exp, target, ignore)
as if it were an extra parameter. */
if (structure_value_addr && struct_value_rtx == 0)
{
+ /* If structure_value_addr is a REG other than
+ virtual_outgoing_args_rtx, we can use always use it. If it
+ is not a REG, we must always copy it into a register.
+ If it is virtual_outgoing_args_rtx, we must copy it to another
+ register in some cases. */
+ rtx temp = (GET_CODE (structure_value_addr) != REG
#ifdef ACCUMULATE_OUTGOING_ARGS
- /* If the stack will be adjusted, make sure the structure address
- does not refer to virtual_outgoing_args_rtx. */
- rtx temp = (stack_arg_under_construction
- ? copy_addr_to_reg (structure_value_addr)
- : force_reg (Pmode, structure_value_addr));
-#else
- rtx temp = force_reg (Pmode, structure_value_addr);
+ || (stack_arg_under_construction
+ && structure_value_addr == virtual_outgoing_args_rtx)
#endif
+ ? copy_addr_to_reg (structure_value_addr)
+ : structure_value_addr);
actparms
= tree_cons (error_mark_node,
@@ -979,6 +983,12 @@ expand_call (exp, target, ignore)
if (type == error_mark_node || TYPE_SIZE (type) == 0)
args[i].tree_value = integer_zero_node, type = integer_type_node;
+ /* If TYPE is a transparent union, pass things the way we would
+ pass the first field of the union. We have already verified that
+ the modes are the same. */
+ if (TYPE_TRANSPARENT_UNION (type))
+ type = TREE_TYPE (TYPE_FIELDS (type));
+
/* Decide where to pass this arg.
args[i].reg is nonzero if all or part is passed in registers.
@@ -1127,7 +1137,7 @@ expand_call (exp, target, ignore)
/ (PARM_BOUNDARY / BITS_PER_UNIT)
* (PARM_BOUNDARY / BITS_PER_UNIT));
#endif
-
+
/* Update ARGS_SIZE, the total stack space for args so far. */
args_size.constant += args[i].size.constant;
@@ -1159,7 +1169,7 @@ expand_call (exp, target, ignore)
reg_parm_stack_space = FINAL_REG_PARM_STACK_SPACE (args_size.constant,
args_size.var);
#endif
-
+
/* Compute the actual size of the argument block required. The variable
and constant sizes must be combined, the size may have to be rounded,
and there may be a minimum required size. */
@@ -1306,7 +1316,7 @@ expand_call (exp, target, ignore)
if (TYPE_MODE (TREE_TYPE (args[i].tree_value)) != args[i].mode)
args[i].value
- = convert_modes (args[i].mode,
+ = convert_modes (args[i].mode,
TYPE_MODE (TREE_TYPE (args[i].tree_value)),
args[i].value, args[i].unsignedp);
@@ -1343,98 +1353,103 @@ expand_call (exp, target, ignore)
}
argblock = push_block (ARGS_SIZE_RTX (args_size), 0, 0);
}
- else if (must_preallocate)
+ else
{
/* Note that we must go through the motions of allocating an argument
block even if the size is zero because we may be storing args
in the area reserved for register arguments, which may be part of
the stack frame. */
+
int needed = args_size.constant;
-#ifdef ACCUMULATE_OUTGOING_ARGS
/* Store the maximum argument space used. It will be pushed by the
- prologue.
-
- Since the stack pointer will never be pushed, it is possible for
- the evaluation of a parm to clobber something we have already
- written to the stack. Since most function calls on RISC machines
- do not use the stack, this is uncommon, but must work correctly.
-
- Therefore, we save any area of the stack that was already written
- and that we are using. Here we set up to do this by making a new
- stack usage map from the old one. The actual save will be done
- by store_one_arg.
-
- Another approach might be to try to reorder the argument
- evaluations to avoid this conflicting stack usage. */
+ prologue (if ACCUMULATE_OUTGOING_ARGS, or stack overflow checking). */
if (needed > current_function_outgoing_args_size)
current_function_outgoing_args_size = needed;
+ if (must_preallocate)
+ {
+#ifdef ACCUMULATE_OUTGOING_ARGS
+ /* Since the stack pointer will never be pushed, it is possible for
+ the evaluation of a parm to clobber something we have already
+ written to the stack. Since most function calls on RISC machines
+ do not use the stack, this is uncommon, but must work correctly.
+
+ Therefore, we save any area of the stack that was already written
+ and that we are using. Here we set up to do this by making a new
+ stack usage map from the old one. The actual save will be done
+ by store_one_arg.
+
+ Another approach might be to try to reorder the argument
+ evaluations to avoid this conflicting stack usage. */
+
#if defined(REG_PARM_STACK_SPACE) && ! defined(OUTGOING_REG_PARM_STACK_SPACE)
- /* Since we will be writing into the entire argument area, the
- map must be allocated for its entire size, not just the part that
- is the responsibility of the caller. */
- needed += reg_parm_stack_space;
+ /* Since we will be writing into the entire argument area, the
+ map must be allocated for its entire size, not just the part that
+ is the responsibility of the caller. */
+ needed += reg_parm_stack_space;
#endif
#ifdef ARGS_GROW_DOWNWARD
- highest_outgoing_arg_in_use = MAX (initial_highest_arg_in_use,
- needed + 1);
+ highest_outgoing_arg_in_use = MAX (initial_highest_arg_in_use,
+ needed + 1);
#else
- highest_outgoing_arg_in_use = MAX (initial_highest_arg_in_use, needed);
+ highest_outgoing_arg_in_use = MAX (initial_highest_arg_in_use,
+ needed);
#endif
- stack_usage_map = (char *) alloca (highest_outgoing_arg_in_use);
+ stack_usage_map = (char *) alloca (highest_outgoing_arg_in_use);
- if (initial_highest_arg_in_use)
- bcopy (initial_stack_usage_map, stack_usage_map,
- initial_highest_arg_in_use);
+ if (initial_highest_arg_in_use)
+ bcopy (initial_stack_usage_map, stack_usage_map,
+ initial_highest_arg_in_use);
- if (initial_highest_arg_in_use != highest_outgoing_arg_in_use)
- bzero (&stack_usage_map[initial_highest_arg_in_use],
- highest_outgoing_arg_in_use - initial_highest_arg_in_use);
- needed = 0;
+ if (initial_highest_arg_in_use != highest_outgoing_arg_in_use)
+ bzero (&stack_usage_map[initial_highest_arg_in_use],
+ highest_outgoing_arg_in_use - initial_highest_arg_in_use);
+ needed = 0;
- /* The address of the outgoing argument list must not be copied to a
- register here, because argblock would be left pointing to the
- wrong place after the call to allocate_dynamic_stack_space below. */
+ /* The address of the outgoing argument list must not be copied to a
+ register here, because argblock would be left pointing to the
+ wrong place after the call to allocate_dynamic_stack_space below.
+ */
- argblock = virtual_outgoing_args_rtx;
+ argblock = virtual_outgoing_args_rtx;
#else /* not ACCUMULATE_OUTGOING_ARGS */
- if (inhibit_defer_pop == 0)
- {
- /* Try to reuse some or all of the pending_stack_adjust
- to get this space. Maybe we can avoid any pushing. */
- if (needed > pending_stack_adjust)
+ if (inhibit_defer_pop == 0)
{
- needed -= pending_stack_adjust;
- pending_stack_adjust = 0;
+ /* Try to reuse some or all of the pending_stack_adjust
+ to get this space. Maybe we can avoid any pushing. */
+ if (needed > pending_stack_adjust)
+ {
+ needed -= pending_stack_adjust;
+ pending_stack_adjust = 0;
+ }
+ else
+ {
+ pending_stack_adjust -= needed;
+ needed = 0;
+ }
}
+ /* Special case this because overhead of `push_block' in this
+ case is non-trivial. */
+ if (needed == 0)
+ argblock = virtual_outgoing_args_rtx;
else
- {
- pending_stack_adjust -= needed;
- needed = 0;
- }
- }
- /* Special case this because overhead of `push_block' in this
- case is non-trivial. */
- if (needed == 0)
- argblock = virtual_outgoing_args_rtx;
- else
- argblock = push_block (GEN_INT (needed), 0, 0);
-
- /* We only really need to call `copy_to_reg' in the case where push
- insns are going to be used to pass ARGBLOCK to a function
- call in ARGS. In that case, the stack pointer changes value
- from the allocation point to the call point, and hence
- the value of VIRTUAL_OUTGOING_ARGS_RTX changes as well.
- But might as well always do it. */
- argblock = copy_to_reg (argblock);
+ argblock = push_block (GEN_INT (needed), 0, 0);
+
+ /* We only really need to call `copy_to_reg' in the case where push
+ insns are going to be used to pass ARGBLOCK to a function
+ call in ARGS. In that case, the stack pointer changes value
+ from the allocation point to the call point, and hence
+ the value of VIRTUAL_OUTGOING_ARGS_RTX changes as well.
+ But might as well always do it. */
+ argblock = copy_to_reg (argblock);
#endif /* not ACCUMULATE_OUTGOING_ARGS */
+ }
}
-
#ifdef ACCUMULATE_OUTGOING_ARGS
/* The save/restore code in store_one_arg handles all cases except one:
a constructor call (including a C function returning a BLKmode struct)
@@ -1475,7 +1490,7 @@ expand_call (exp, target, ignore)
/* If we preallocated stack space, compute the address of each argument.
- We need not ensure it is a valid memory address here; it will be
+ We need not ensure it is a valid memory address here; it will be
validized when it is used. */
if (argblock)
{
@@ -1514,7 +1529,7 @@ expand_call (exp, target, ignore)
args[i].stack_slot = gen_rtx (MEM, args[i].mode, addr);
}
}
-
+
#ifdef PUSH_ARGS_REVERSED
#ifdef STACK_BOUNDARY
/* If we push args individually in reverse order, perform stack alignment
@@ -1595,7 +1610,7 @@ expand_call (exp, target, ignore)
TYPE_MODE (TREE_TYPE (args[i].tree_value)),
args[i].value, args[i].unsignedp);
- /* If the value is expensive, and we are inside an appropriately
+ /* If the value is expensive, and we are inside an appropriately
short loop, put the value into a pseudo and then put the pseudo
into the hard reg.
@@ -1609,10 +1624,11 @@ expand_call (exp, target, ignore)
&& args[i].mode != BLKmode
&& rtx_cost (args[i].value, SET) > 2
#ifdef SMALL_REGISTER_CLASSES
- && (reg_parm_seen || preserve_subexpressions_p ()))
+ && (reg_parm_seen || preserve_subexpressions_p ())
#else
- && preserve_subexpressions_p ())
+ && preserve_subexpressions_p ()
#endif
+ )
args[i].value = copy_to_mode_reg (args[i].mode, args[i].value);
}
@@ -1653,7 +1669,7 @@ expand_call (exp, target, ignore)
stack_area = gen_rtx (MEM, save_mode,
memory_address (save_mode,
-
+
#ifdef ARGS_GROW_DOWNWARD
plus_constant (argblock,
- high_to_save)
@@ -1676,7 +1692,7 @@ expand_call (exp, target, ignore)
}
}
#endif
-
+
/* Now store (and compute if necessary) all non-register parms.
These come before register parms, since they can require block-moves,
@@ -1793,7 +1809,7 @@ expand_call (exp, target, ignore)
/* Now do the register loads required for any wholly-register parms or any
parms which are passed both on the stack and in a register. Their
- expressions were already evaluated.
+ expressions were already evaluated.
Mark all register-parms as living through the call, putting these USE
insns in the CALL_INSN_FUNCTION_USAGE field. */
@@ -1894,6 +1910,14 @@ expand_call (exp, target, ignore)
valreg = temp;
}
+ else if (is_const)
+ {
+ /* Otherwise, just write out the sequence without a note. */
+ rtx insns = get_insns ();
+
+ end_sequence ();
+ emit_insns (insns);
+ }
/* For calls to `setjmp', etc., inform flow.c it should complain
if nonvolatile values are live. */
@@ -2048,7 +2072,7 @@ expand_call (exp, target, ignore)
PARM_BOUNDARY / BITS_PER_UNIT);
}
#endif
-
+
/* If we saved any argument areas, restore them. */
for (i = 0; i < num_actuals; i++)
if (args[i].save_area)
@@ -2072,7 +2096,7 @@ expand_call (exp, target, ignore)
}
#endif
- /* If this was alloca, record the new stack level for nonlocal gotos.
+ /* If this was alloca, record the new stack level for nonlocal gotos.
Check for the handler slots since we might not have a save area
for non-local gotos. */
@@ -2193,7 +2217,7 @@ emit_library_call VPROTO((rtx orgfun, int no_queue, enum machine_mode outmode,
be viewed as just an efficiency improvement. */
rtx slot = assign_stack_temp (mode, GET_MODE_SIZE (mode), 0);
emit_move_insn (slot, val);
- val = XEXP (slot, 0);
+ val = force_operand (XEXP (slot, 0), NULL_RTX);
mode = Pmode;
}
#endif
@@ -2266,9 +2290,10 @@ emit_library_call VPROTO((rtx orgfun, int no_queue, enum machine_mode outmode,
#endif
#endif
-#ifdef ACCUMULATE_OUTGOING_ARGS
if (args_size.constant > current_function_outgoing_args_size)
current_function_outgoing_args_size = args_size.constant;
+
+#ifdef ACCUMULATE_OUTGOING_ARGS
args_size.constant = 0;
#endif
@@ -2613,9 +2638,10 @@ emit_library_call_value VPROTO((rtx orgfun, rtx value, int no_queue,
#endif
#endif
-#ifdef ACCUMULATE_OUTGOING_ARGS
if (args_size.constant > current_function_outgoing_args_size)
current_function_outgoing_args_size = args_size.constant;
+
+#ifdef ACCUMULATE_OUTGOING_ARGS
args_size.constant = 0;
#endif
@@ -2794,7 +2820,7 @@ target_for_arg (type, size, args_addr, offset)
or 0 on a machine where arguments are pushed individually.
MAY_BE_ALLOCA nonzero says this could be a call to `alloca'
- so must be careful about how the stack is used.
+ so must be careful about how the stack is used.
VARIABLE_SIZE nonzero says that this was a variable-sized outgoing
argument stack. This is used if ACCUMULATE_OUTGOING_ARGS to indicate
@@ -2901,7 +2927,7 @@ store_one_arg (arg, argblock, may_be_alloca, variable_size, fndecl,
if (arg->n_aligned_regs != 0)
reg = 0;
#endif
-
+
/* If this is being partially passed in a register, but multiple locations
are specified, we assume that the one partially used is the one that is
listed first. */
@@ -2968,7 +2994,7 @@ store_one_arg (arg, argblock, may_be_alloca, variable_size, fndecl,
/* Argument is a scalar, not entirely passed in registers.
(If part is passed in registers, arg->partial says how much
and emit_push_insn will take care of putting it there.)
-
+
Push it, and if its size is less than the
amount of space allocated to it,
also bump stack pointer by the additional space.
@@ -3032,7 +3058,7 @@ store_one_arg (arg, argblock, may_be_alloca, variable_size, fndecl,
/* Unless this is a partially-in-register argument, the argument is now
- in the stack.
+ in the stack.
??? Note that this can change arg->value from arg->stack to
arg->stack_slot and it matters when they are not the same.
@@ -3048,7 +3074,10 @@ store_one_arg (arg, argblock, may_be_alloca, variable_size, fndecl,
but PCC has one, so this will avoid some problems. */
emit_queue ();
- /* Free any temporary slots made in processing this argument. */
+ /* Free any temporary slots made in processing this argument. Show
+ that we might have taken the address of something and pushed that
+ as an operand. */
+ preserve_temp_slots (NULL_RTX);
free_temp_slots ();
pop_temp_slots ();
diff --git a/gnu/usr.bin/cc/cc_int/combine.c b/gnu/usr.bin/cc/cc_int/combine.c
index 990fa4d..268434e 100644
--- a/gnu/usr.bin/cc/cc_int/combine.c
+++ b/gnu/usr.bin/cc/cc_int/combine.c
@@ -57,7 +57,7 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
- there are extremely rare cases (see distribute_regnotes) when a
REG_DEAD note is lost
- a LOG_LINKS entry that refers to an insn with multiple SETs may be
- removed because there is no way to know which register it was
+ removed because there is no way to know which register it was
linking
To simplify substitution, we combine only when the earlier insn(s)
@@ -170,11 +170,6 @@ static int last_call_cuid;
static rtx subst_insn;
-/* If nonzero, this is the insn that should be presumed to be
- immediately in front of `subst_insn'. */
-
-static rtx subst_prev_insn;
-
/* This is the lowest CUID that `subst' is currently dealing with.
get_last_value will not return a value if the register was set at or
after this CUID. If not for this mechanism, we could get confused if
@@ -195,7 +190,7 @@ static HARD_REG_SET newpat_used_regs;
static rtx added_links_insn;
-/* This is the value of undobuf.num_undo when we started processing this
+/* This is the value of undobuf.num_undo when we started processing this
substitution. This will prevent gen_rtx_combine from re-used a piece
from the previous expression. Doing so can produce circular rtl
structures. */
@@ -503,7 +498,7 @@ combine_instructions (f, nregs)
/* Compute the mapping from uids to cuids.
Cuids are numbers assigned to insns, like uids,
- except that cuids increase monotonically through the code.
+ except that cuids increase monotonically through the code.
Scan all SETs and see if we can deduce anything about what
bits are known to be zero for some registers and how many copies
@@ -695,14 +690,14 @@ setup_incoming_promotions ()
/* Called via note_stores. If X is a pseudo that is used in more than
one basic block, is narrower that HOST_BITS_PER_WIDE_INT, and is being
set, record what bits are known zero. If we are clobbering X,
- ignore this "set" because the clobbered value won't be used.
+ ignore this "set" because the clobbered value won't be used.
If we are setting only a portion of X and we can't figure out what
portion, assume all bits will be used since we don't know what will
be happening.
Similarly, set how many bits of X are known to be copies of the sign bit
- at all locations in the function. This is the smallest number implied
+ at all locations in the function. This is the smallest number implied
by any set of X. */
static void
@@ -749,7 +744,7 @@ set_nonzero_bits_and_sign_copies (x, set)
constant that would appear negative in the mode of X,
sign-extend it for use in reg_nonzero_bits because some
machines (maybe most) will actually do the sign-extension
- and this is the conservative approach.
+ and this is the conservative approach.
??? For 2.5, try to tighten up the MD files in this regard
instead of this kludge. */
@@ -786,7 +781,7 @@ set_nonzero_bits_and_sign_copies (x, set)
Return 0 if the combination is not allowed for any reason.
- If the combination is allowed, *PDEST will be set to the single
+ If the combination is allowed, *PDEST will be set to the single
destination of INSN and *PSRC to the single source, and this function
will return 1. */
@@ -805,20 +800,20 @@ can_combine_p (insn, i3, pred, succ, pdest, psrc)
: next_active_insn (insn) == i3);
/* Can combine only if previous insn is a SET of a REG, a SUBREG or CC0.
- or a PARALLEL consisting of such a SET and CLOBBERs.
+ or a PARALLEL consisting of such a SET and CLOBBERs.
If INSN has CLOBBER parallel parts, ignore them for our processing.
By definition, these happen during the execution of the insn. When it
is merged with another insn, all bets are off. If they are, in fact,
needed and aren't also supplied in I3, they may be added by
- recog_for_combine. Otherwise, it won't match.
+ recog_for_combine. Otherwise, it won't match.
We can also ignore a SET whose SET_DEST is mentioned in a REG_UNUSED
note.
- Get the source and destination of INSN. If more than one, can't
+ Get the source and destination of INSN. If more than one, can't
combine. */
-
+
if (GET_CODE (PATTERN (insn)) == SET)
set = PATTERN (insn);
else if (GET_CODE (PATTERN (insn)) == PARALLEL
@@ -880,7 +875,11 @@ can_combine_p (insn, i3, pred, succ, pdest, psrc)
/* Can't merge a function call. */
|| GET_CODE (src) == CALL
/* Don't eliminate a function call argument. */
- || (GET_CODE (i3) == CALL_INSN && find_reg_fusage (i3, USE, dest))
+ || (GET_CODE (i3) == CALL_INSN
+ && (find_reg_fusage (i3, USE, dest)
+ || (GET_CODE (dest) == REG
+ && REGNO (dest) < FIRST_PSEUDO_REGISTER
+ && global_regs[REGNO (dest)])))
/* Don't substitute into an incremented register. */
|| FIND_REG_INC_NOTE (i3, dest)
|| (succ && FIND_REG_INC_NOTE (succ, dest))
@@ -1033,7 +1032,7 @@ can_combine_p (insn, i3, pred, succ, pdest, psrc)
(set (reg:DI 101) (reg:DI 100))])
Not only does this modify 100 (in which case it might still be valid
- if 100 were dead in I2), it sets 101 to the ORIGINAL value of 100.
+ if 100 were dead in I2), it sets 101 to the ORIGINAL value of 100.
We can also run into a problem if I2 sets a register that I1
uses and I1 gets directly substituted into I3 (not via I2). In that
@@ -1125,7 +1124,7 @@ combinable_i3pat (i3, loc, i2dest, i1dest, i1_not_in_src, pi3dest_killed)
return 0;
/* If DEST is used in I3, it is being killed in this insn,
- so record that for later.
+ so record that for later.
Never add REG_DEAD notes for the FRAME_POINTER_REGNUM or the
STACK_POINTER_REGNUM, since these are always considered to be
live. Similarly for ARG_POINTER_REGNUM if it is fixed. */
@@ -1164,13 +1163,13 @@ combinable_i3pat (i3, loc, i2dest, i1dest, i1_not_in_src, pi3dest_killed)
/* Try to combine the insns I1 and I2 into I3.
Here I1 and I2 appear earlier than I3.
I1 can be zero; then we combine just I2 into I3.
-
+
It we are combining three insns and the resulting insn is not recognized,
try splitting it into two insns. If that happens, I2 and I3 are retained
and I1 is pseudo-deleted by turning it into a NOTE. Otherwise, I1 and I2
are pseudo-deleted.
- Return 0 if the combination does not work. Then nothing is changed.
+ Return 0 if the combination does not work. Then nothing is changed.
If we did the combination, return the insn at which combine should
resume scanning. */
@@ -1203,6 +1202,8 @@ try_combine (i3, i2, i1)
rtx new_i3_notes, new_i2_notes;
/* Notes that we substituted I3 into I2 instead of the normal case. */
int i3_subst_into_i2 = 0;
+ /* Notes that I1, I2 or I3 is a MULT operation. */
+ int have_mult = 0;
int maxreg;
rtx temp;
@@ -1238,7 +1239,6 @@ try_combine (i3, i2, i1)
if (i1 && INSN_CUID (i1) > INSN_CUID (i2))
temp = i1, i1 = i2, i2 = temp;
- subst_prev_insn = 0;
added_links_insn = 0;
/* First check for one important special-case that the code below will
@@ -1308,7 +1308,7 @@ try_combine (i3, i2, i1)
/* Replace the dest in I2 with our dest and make the resulting
insn the new pattern for I3. Then skip to where we
validate the pattern. Everything was set up above. */
- SUBST (SET_DEST (XVECEXP (p2, 0, i)),
+ SUBST (SET_DEST (XVECEXP (p2, 0, i)),
SET_DEST (PATTERN (i3)));
newpat = p2;
@@ -1354,9 +1354,8 @@ try_combine (i3, i2, i1)
never appear in the insn stream so giving it the same INSN_UID
as I2 will not cause a problem. */
- subst_prev_insn = i1
- = gen_rtx (INSN, VOIDmode, INSN_UID (i2), 0, i2,
- XVECEXP (PATTERN (i2), 0, 1), -1, 0, 0);
+ i1 = gen_rtx (INSN, VOIDmode, INSN_UID (i2), 0, i2,
+ XVECEXP (PATTERN (i2), 0, 1), -1, 0, 0);
SUBST (PATTERN (i2), XVECEXP (PATTERN (i2), 0, 0));
SUBST (XEXP (SET_SRC (PATTERN (i2)), 0),
@@ -1392,6 +1391,15 @@ try_combine (i3, i2, i1)
return 0;
}
+ /* See if any of the insns is a MULT operation. Unless one is, we will
+ reject a combination that is, since it must be slower. Be conservative
+ here. */
+ if (GET_CODE (i2src) == MULT
+ || (i1 != 0 && GET_CODE (i1src) == MULT)
+ || (GET_CODE (PATTERN (i3)) == SET
+ && GET_CODE (SET_SRC (PATTERN (i3))) == MULT))
+ have_mult = 1;
+
/* If I3 has an inc, then give up if I1 or I2 uses the reg that is inc'd.
We used to do this EXCEPT in one case: I3 has a post-inc in an
output operand. However, that exception can give rise to insns like
@@ -1548,7 +1556,7 @@ try_combine (i3, i2, i1)
else
undobuf.other_insn = 0;
}
-#endif
+#endif
}
else
#endif
@@ -1601,7 +1609,11 @@ try_combine (i3, i2, i1)
really no reason to). */
|| max_reg_num () != maxreg
/* Fail if we couldn't do something and have a CLOBBER. */
- || GET_CODE (newpat) == CLOBBER)
+ || GET_CODE (newpat) == CLOBBER
+ /* Fail if this new pattern is a MULT and we didn't have one before
+ at the outer level. */
+ || (GET_CODE (newpat) == SET && GET_CODE (SET_SRC (newpat)) == MULT
+ && ! have_mult))
{
undo_all ();
return 0;
@@ -1698,7 +1710,7 @@ try_combine (i3, i2, i1)
/* If we were combining three insns and the result is a simple SET
with no ASM_OPERANDS that wasn't recognized, try to split it into two
- insns. There are two ways to do this. It can be split using a
+ insns. There are two ways to do this. It can be split using a
machine-specific method (like when you have an addition of a large
constant) or by combine in the function find_split_point. */
@@ -1804,13 +1816,14 @@ try_combine (i3, i2, i1)
&& ! reg_referenced_p (i2dest, newpat))
{
rtx newdest = i2dest;
+ enum rtx_code split_code = GET_CODE (*split);
+ enum machine_mode split_mode = GET_MODE (*split);
/* Get NEWDEST as a register in the proper mode. We have already
validated that we can do this. */
- if (GET_MODE (i2dest) != GET_MODE (*split)
- && GET_MODE (*split) != VOIDmode)
+ if (GET_MODE (i2dest) != split_mode && split_mode != VOIDmode)
{
- newdest = gen_rtx (REG, GET_MODE (*split), REGNO (i2dest));
+ newdest = gen_rtx (REG, split_mode, REGNO (i2dest));
if (REGNO (i2dest) >= FIRST_PSEUDO_REGISTER)
SUBST (regno_reg_rtx[REGNO (i2dest)], newdest);
@@ -1819,25 +1832,32 @@ try_combine (i3, i2, i1)
/* If *SPLIT is a (mult FOO (const_int pow2)), convert it to
an ASHIFT. This can occur if it was inside a PLUS and hence
appeared to be a memory address. This is a kludge. */
- if (GET_CODE (*split) == MULT
+ if (split_code == MULT
&& GET_CODE (XEXP (*split, 1)) == CONST_INT
&& (i = exact_log2 (INTVAL (XEXP (*split, 1)))) >= 0)
- SUBST (*split, gen_rtx_combine (ASHIFT, GET_MODE (*split),
- XEXP (*split, 0), GEN_INT (i)));
+ {
+ SUBST (*split, gen_rtx_combine (ASHIFT, split_mode,
+ XEXP (*split, 0), GEN_INT (i)));
+ /* Update split_code because we may not have a multiply
+ anymore. */
+ split_code = GET_CODE (*split);
+ }
#ifdef INSN_SCHEDULING
/* If *SPLIT is a paradoxical SUBREG, when we split it, it should
be written as a ZERO_EXTEND. */
- if (GET_CODE (*split) == SUBREG
- && GET_CODE (SUBREG_REG (*split)) == MEM)
- SUBST (*split, gen_rtx_combine (ZERO_EXTEND, GET_MODE (*split),
+ if (split_code == SUBREG && GET_CODE (SUBREG_REG (*split)) == MEM)
+ SUBST (*split, gen_rtx_combine (ZERO_EXTEND, split_mode,
XEXP (*split, 0)));
#endif
newi2pat = gen_rtx_combine (SET, VOIDmode, newdest, *split);
SUBST (*split, newdest);
i2_code_number = recog_for_combine (&newi2pat, i2, &new_i2_notes);
- if (i2_code_number >= 0)
+
+ /* If the split point was a MULT and we didn't have one before,
+ don't use one now. */
+ if (i2_code_number >= 0 && ! (split_code == MULT && ! have_mult))
insn_code_number = recog_for_combine (&newpat, i3, &new_i3_notes);
}
}
@@ -1940,7 +1960,7 @@ try_combine (i3, i2, i1)
}
}
}
-
+
/* Similarly, check for a case where we have a PARALLEL of two independent
SETs but we started with three insns. In this case, we can do the sets
as two separate insns. This case occurs when some SET allows two
@@ -2028,7 +2048,7 @@ try_combine (i3, i2, i1)
undobuf.other_insn, NULL_RTX, NULL_RTX, NULL_RTX);
}
- /* We now know that we can do this combination. Merge the insns and
+ /* We now know that we can do this combination. Merge the insns and
update the status of registers and LOG_LINKS. */
{
@@ -2159,7 +2179,7 @@ try_combine (i3, i2, i1)
/* Distribute any notes added to I2 or I3 by recog_for_combine. We
know these are REG_UNUSED and want them to go to the desired insn,
- so we always pass it as i3. We have not counted the notes in
+ so we always pass it as i3. We have not counted the notes in
reg_n_deaths yet, so we need to do so now. */
if (newi2pat && new_i2_notes)
@@ -2167,7 +2187,7 @@ try_combine (i3, i2, i1)
for (temp = new_i2_notes; temp; temp = XEXP (temp, 1))
if (GET_CODE (XEXP (temp, 0)) == REG)
reg_n_deaths[REGNO (XEXP (temp, 0))]++;
-
+
distribute_notes (new_i2_notes, i2, i2, NULL_RTX, NULL_RTX, NULL_RTX);
}
@@ -2176,7 +2196,7 @@ try_combine (i3, i2, i1)
for (temp = new_i3_notes; temp; temp = XEXP (temp, 1))
if (GET_CODE (XEXP (temp, 0)) == REG)
reg_n_deaths[REGNO (XEXP (temp, 0))]++;
-
+
distribute_notes (new_i3_notes, i3, i3, NULL_RTX, NULL_RTX, NULL_RTX);
}
@@ -2239,7 +2259,7 @@ try_combine (i3, i2, i1)
/* The insn that used to set this register doesn't exist, and
this life of the register may not exist either. See if one of
- I3's links points to an insn that sets I2DEST. If it does,
+ I3's links points to an insn that sets I2DEST. If it does,
that is now the last known value for I2DEST. If we don't update
this and I2 set the register to a value that depended on its old
contents, we will get confused. If this insn is used, thing
@@ -2295,7 +2315,7 @@ try_combine (i3, i2, i1)
if (newi2pat)
note_stores (newi2pat, set_nonzero_bits_and_sign_copies);
- /* If I3 is now an unconditional jump, ensure that it has a
+ /* If I3 is now an unconditional jump, ensure that it has a
BARRIER following it since it may have initially been a
conditional jump. It may also be the last nonnote insn. */
@@ -2329,7 +2349,7 @@ undo_all ()
*undobuf.undo[i].where.i = undobuf.undo[i].old_contents.i;
else
*undobuf.undo[i].where.r = undobuf.undo[i].old_contents.r;
-
+
}
obfree (undobuf.storage);
@@ -2433,7 +2453,7 @@ find_split_point (loc, insn)
return split;
}
}
-
+
/* If that didn't work, perhaps the first operand is complex and
needs to be computed separately, so make a split point there.
This will occur on machines that just support REG + CONST
@@ -2498,7 +2518,7 @@ find_split_point (loc, insn)
else
SUBST (SET_SRC (x),
gen_binary (IOR, mode,
- gen_binary (AND, mode, dest,
+ gen_binary (AND, mode, dest,
GEN_INT (~ (mask << pos)
& GET_MODE_MASK (mode))),
GEN_INT (src << pos)));
@@ -2708,7 +2728,7 @@ find_split_point (loc, insn)
the caller can tell whether the result is valid.
`n_occurrences' is incremented each time FROM is replaced.
-
+
IN_DEST is non-zero if we are processing the SET_DEST of a SET.
UNIQUE_COPY is non-zero if each substitution must be unique. We do this
@@ -2742,7 +2762,7 @@ subst (x, from, to, in_dest, unique_copy)
}
/* If X and FROM are the same register but different modes, they will
- not have been seen as equal above. However, flow.c will make a
+ not have been seen as equal above. However, flow.c will make a
LOG_LINKS entry for that case. If we do nothing, we will try to
rerecognize our original insn and, when it succeeds, we will
delete the feeding insn, which is incorrect.
@@ -2841,7 +2861,7 @@ subst (x, from, to, in_dest, unique_copy)
have gone inside a MEM, in which case we want to
simplify the address. We assume here that things that
are actually part of the destination have their inner
- parts in the first expression. This is true for SUBREG,
+ parts in the first expression. This is true for SUBREG,
STRICT_LOW_PART, and ZERO_EXTRACT, which are the only
things aside from REG and MEM that should appear in a
SET_DEST. */
@@ -2965,7 +2985,7 @@ simplify_rtx (x, op0_mode, last, in_dest)
SUBST (XEXP (x, 0), gen_binary (PLUS, mode, new, temp));
}
- /* If this is a simple operation applied to an IF_THEN_ELSE, try
+ /* If this is a simple operation applied to an IF_THEN_ELSE, try
applying it to the arms of the IF_THEN_ELSE. This often simplifies
things. Check for cases where both arms are testing the same
condition.
@@ -2996,7 +3016,7 @@ simplify_rtx (x, op0_mode, last, in_dest)
rtx cop1 = const0_rtx;
enum rtx_code cond_code = simplify_comparison (NE, &cond, &cop1);
- /* Simplify the alternative arms; this may collapse the true and
+ /* Simplify the alternative arms; this may collapse the true and
false arms to store-flag values. */
true = subst (true, pc_rtx, pc_rtx, 0, 0);
false = subst (false, pc_rtx, pc_rtx, 0, 0);
@@ -3022,7 +3042,7 @@ simplify_rtx (x, op0_mode, last, in_dest)
&& INTVAL (false) == - STORE_FLAG_VALUE
&& true == const0_rtx)
x = gen_unary (NEG, mode, mode,
- gen_binary (reverse_condition (cond_code),
+ gen_binary (reverse_condition (cond_code),
mode, cond, cop1));
else
return gen_rtx (IF_THEN_ELSE, mode,
@@ -3088,7 +3108,7 @@ simplify_rtx (x, op0_mode, last, in_dest)
rtx inner_op0 = XEXP (XEXP (x, 0), 1);
rtx inner_op1 = XEXP (x, 1);
rtx inner;
-
+
/* Make sure we pass the constant operand if any as the second
one if this is a commutative operation. */
if (CONSTANT_P (inner_op0) && GET_RTX_CLASS (code) == 'c')
@@ -3219,7 +3239,7 @@ simplify_rtx (x, op0_mode, last, in_dest)
if (temp)
return temp;
}
-
+
/* If we want a subreg of a constant, at offset 0,
take the low bits. On a little-endian machine, that's
always valid. On a big-endian machine, it's valid
@@ -3261,11 +3281,8 @@ simplify_rtx (x, op0_mode, last, in_dest)
&& (temp = simplify_unary_operation (NOT, mode,
XEXP (XEXP (x, 0), 1),
mode)) != 0)
- {
- SUBST (XEXP (XEXP (x, 0), 1), temp);
- return XEXP (x, 0);
- }
-
+ return gen_binary (XOR, mode, XEXP (XEXP (x, 0), 0), temp);
+
/* (not (ashift 1 X)) is (rotate ~1 X). We used to do this for operands
other than 1, but that is not valid. We could do a similar
simplification for (not (lshiftrt C X)) where C is just the sign bit,
@@ -3274,7 +3291,7 @@ simplify_rtx (x, op0_mode, last, in_dest)
&& XEXP (XEXP (x, 0), 0) == const1_rtx)
return gen_rtx (ROTATE, mode, gen_unary (NOT, mode, mode, const1_rtx),
XEXP (XEXP (x, 0), 1));
-
+
if (GET_CODE (XEXP (x, 0)) == SUBREG
&& subreg_lowpart_p (XEXP (x, 0))
&& (GET_MODE_SIZE (GET_MODE (XEXP (x, 0)))
@@ -3289,7 +3306,7 @@ simplify_rtx (x, op0_mode, last, in_dest)
XEXP (SUBREG_REG (XEXP (x, 0)), 1));
return gen_lowpart_for_combine (mode, x);
}
-
+
#if STORE_FLAG_VALUE == -1
/* (not (comparison foo bar)) can be done by reversing the comparison
code if valid. */
@@ -3340,7 +3357,7 @@ simplify_rtx (x, op0_mode, last, in_dest)
return gen_rtx_combine (GET_CODE (XEXP (x, 0)) == IOR ? AND : IOR,
mode, in1, in2);
- }
+ }
break;
case NEG:
@@ -3436,7 +3453,14 @@ simplify_rtx (x, op0_mode, last, in_dest)
&& GET_MODE (XEXP (XEXP (XEXP (x, 0), 0), 0)) == mode)
return gen_unary (GET_CODE (XEXP (x, 0)), mode, mode,
XEXP (XEXP (XEXP (x, 0), 0), 0));
- break;
+
+ /* (float_truncate:SF (subreg:DF (float_truncate:SF X) 0))
+ is (float_truncate:SF x). */
+ if (GET_CODE (XEXP (x, 0)) == SUBREG
+ && subreg_lowpart_p (XEXP (x, 0))
+ && GET_CODE (SUBREG_REG (XEXP (x, 0))) == FLOAT_TRUNCATE)
+ return SUBREG_REG (XEXP (x, 0));
+ break;
#ifdef HAVE_cc0
case COMPARE:
@@ -3749,13 +3773,13 @@ simplify_rtx (x, op0_mode, last, in_dest)
if (new_code != code)
return gen_rtx_combine (new_code, mode, op0, op1);
- /* Otherwise, keep this operation, but maybe change its operands.
+ /* Otherwise, keep this operation, but maybe change its operands.
This also converts (ne (compare FOO BAR) 0) to (ne FOO BAR). */
SUBST (XEXP (x, 0), op0);
SUBST (XEXP (x, 1), op1);
}
break;
-
+
case IF_THEN_ELSE:
return simplify_if_then_else (x);
@@ -3819,14 +3843,14 @@ simplify_rtx (x, op0_mode, last, in_dest)
case ROTATERT:
/* If this is a shift by a constant amount, simplify it. */
if (GET_CODE (XEXP (x, 1)) == CONST_INT)
- return simplify_shift_const (x, code, mode, XEXP (x, 0),
+ return simplify_shift_const (x, code, mode, XEXP (x, 0),
INTVAL (XEXP (x, 1)));
#ifdef SHIFT_COUNT_TRUNCATED
else if (SHIFT_COUNT_TRUNCATED && GET_CODE (XEXP (x, 1)) != REG)
SUBST (XEXP (x, 1),
force_to_mode (XEXP (x, 1), GET_MODE (x),
- ((HOST_WIDE_INT) 1
+ ((HOST_WIDE_INT) 1
<< exact_log2 (GET_MODE_BITSIZE (GET_MODE (x))))
- 1,
NULL_RTX, 0));
@@ -3856,7 +3880,7 @@ simplify_if_then_else (x)
/* Simplify storing of the truth value. */
if (comparison_p && true == const_true_rtx && false == const0_rtx)
return gen_binary (true_code, mode, XEXP (cond, 0), XEXP (cond, 1));
-
+
/* Also when the truth value has to be reversed. */
if (comparison_p && reversible_comparison_p (cond)
&& true == const0_rtx && false == const_true_rtx)
@@ -3922,7 +3946,7 @@ simplify_if_then_else (x)
the false arm is more complicated than the true arm. */
if (comparison_p && reversible_comparison_p (cond)
- && (true == pc_rtx
+ && (true == pc_rtx
|| (CONSTANT_P (true)
&& GET_CODE (false) != CONST_INT && false != pc_rtx)
|| true == const0_rtx
@@ -3990,7 +4014,7 @@ simplify_if_then_else (x)
case LTU:
return gen_binary (UMIN, mode, true, false);
}
-
+
#if STORE_FLAG_VALUE == 1 || STORE_FLAG_VALUE == -1
/* If we have (if_then_else COND (OP Z C1) Z) and OP is an identity when its
@@ -4093,7 +4117,7 @@ simplify_if_then_else (x)
extend_op = ZERO_EXTEND;
m = GET_MODE (XEXP (t, 0));
}
-
+
if (z)
{
temp = subst (gen_binary (true_code, m, cond_op0, cond_op1),
@@ -4288,7 +4312,7 @@ simplify_set (x)
/* If we have (set x (subreg:m1 (op:m2 ...) 0)) with OP being some operation,
and X being a REG or (subreg (reg)), we may be able to convert this to
- (set (subreg:m2 x) (op)).
+ (set (subreg:m2 x) (op)).
We can always do this if M1 is narrower than M2 because that means that
we only care about the low bits of the result.
@@ -4297,7 +4321,7 @@ simplify_set (x)
perform a narrower operation that requested since the high-order bits will
be undefined. On machine where it is defined, this transformation is safe
as long as M1 and M2 have the same number of words. */
-
+
if (GET_CODE (src) == SUBREG && subreg_lowpart_p (src)
&& GET_RTX_CLASS (GET_CODE (SUBREG_REG (src))) != 'o'
&& (((GET_MODE_SIZE (GET_MODE (src)) + (UNITS_PER_WORD - 1))
@@ -4354,6 +4378,7 @@ simplify_set (x)
&& GET_MODE_CLASS (GET_MODE (src)) == MODE_INT
&& (GET_CODE (XEXP (src, 0)) == EQ || GET_CODE (XEXP (src, 0)) == NE)
&& XEXP (XEXP (src, 0), 1) == const0_rtx
+ && GET_MODE (src) == GET_MODE (XEXP (XEXP (src, 0), 0))
&& (num_sign_bit_copies (XEXP (XEXP (src, 0), 0),
GET_MODE (XEXP (XEXP (src, 0), 0)))
== GET_MODE_BITSIZE (GET_MODE (XEXP (XEXP (src, 0), 0))))
@@ -4482,7 +4507,7 @@ simplify_logical (x, last)
For example, (and (ior A B) (not B)) can occur as the result of
expanding a bit field assignment. When we apply the distributive
law to this, we get (ior (and (A (not B))) (and (B (not B)))),
- which then simplifies to (and (A (not B))).
+ which then simplifies to (and (A (not B))).
If we have (and (ior A B) C), apply the distributive law and then
the inverse distributive law to see if things simplify. */
@@ -4511,7 +4536,7 @@ simplify_logical (x, last)
(gen_binary (XOR, mode,
gen_binary (IOR, mode, XEXP (op0, 0), XEXP (op1, 0)),
gen_binary (IOR, mode, XEXP (op0, 0), XEXP (op1, 1))));
-
+
else if (GET_CODE (op1) == NOT && GET_CODE (op0) == XOR)
return apply_distributive_law
(gen_binary (XOR, mode,
@@ -4678,7 +4703,7 @@ simplify_logical (x, last)
an AND operation, which is simpler, though only one operation.
The function expand_compound_operation is called with an rtx expression
- and will convert it to the appropriate shifts and AND operations,
+ and will convert it to the appropriate shifts and AND operations,
simplifying at each stage.
The function make_compound_operation is called to convert an expression
@@ -4718,7 +4743,7 @@ expand_compound_operation (x)
Reject MODEs bigger than a word, because we might not be able
to reference a two-register group starting with an arbitrary register
(and currently gen_lowpart might crash for a SUBREG). */
-
+
if (GET_MODE_SIZE (GET_MODE (XEXP (x, 0))) > UNITS_PER_WORD)
return x;
@@ -4772,7 +4797,7 @@ expand_compound_operation (x)
We must check for the case where the left shift would have a negative
count. This can happen in a case like (x >> 31) & 255 on machines
that can't shift by a constant. On those machines, we would first
- combine the shift with the AND to produce a variable-position
+ combine the shift with the AND to produce a variable-position
extraction. Then the constant of 31 would be substituted in to produce
a such a position. */
@@ -4795,7 +4820,7 @@ expand_compound_operation (x)
else
/* Any other cases we can't handle. */
return x;
-
+
/* If we couldn't do this for some reason, return the original
expression. */
@@ -4926,7 +4951,7 @@ expand_field_assignment (x)
code that understands the USE is this routine. If it is not removed,
it will cause the resulting insn not to match.
- UNSIGNEDP is non-zero for an unsigned reference and zero for a
+ UNSIGNEDP is non-zero for an unsigned reference and zero for a
signed reference.
IN_DEST is non-zero if this is a reference in the destination of a
@@ -5020,7 +5045,7 @@ make_extraction (mode, inner, pos, pos_rtx, len,
{
/* If INNER is a MEM, make a new MEM that encompasses just the desired
field. If the original and current mode are the same, we need not
- adjust the offset. Otherwise, we do if bytes big endian.
+ adjust the offset. Otherwise, we do if bytes big endian.
If INNER is not a MEM, get a piece consisting of the just the field
of interest (in this case POS must be 0). */
@@ -5061,7 +5086,7 @@ make_extraction (mode, inner, pos, pos_rtx, len,
: ((HOST_WIDE_INT) 1 << len) - 1,
NULL_RTX, 0);
- /* If this extraction is going into the destination of a SET,
+ /* If this extraction is going into the destination of a SET,
make a STRICT_LOW_PART unless we made a MEM. */
if (in_dest)
@@ -5174,7 +5199,7 @@ make_extraction (mode, inner, pos, pos_rtx, len,
/* The computations below will be correct if the machine is big
endian in both bits and bytes or little endian in bits and bytes.
If it is mixed, we must adjust. */
-
+
/* If bytes are big endian and we had a paradoxical SUBREG, we must
adjust OFFSET to compensate. */
#if BYTES_BIG_ENDIAN
@@ -5278,7 +5303,7 @@ extract_left_shift (x, count)
if (GET_CODE (XEXP (x,1)) == CONST_INT
&& (INTVAL (XEXP (x, 1)) & (((HOST_WIDE_INT) 1 << count)) - 1) == 0
&& (tem = extract_left_shift (XEXP (x, 0), count)) != 0)
- return gen_binary (code, mode, tem,
+ return gen_binary (code, mode, tem,
GEN_INT (INTVAL (XEXP (x, 1)) >> count));
break;
@@ -5490,7 +5515,7 @@ make_compound_operation (x, in_code)
If so, try to merge the shifts into a SIGN_EXTEND. We could
also do this for some cases of SIGN_EXTRACT, but it doesn't
seem worth the effort; the case checked for occurs on Alpha. */
-
+
if (GET_RTX_CLASS (GET_CODE (lhs)) != 'o'
&& ! (GET_CODE (lhs) == SUBREG
&& (GET_RTX_CLASS (GET_CODE (SUBREG_REG (lhs))) == 'o'))
@@ -5500,7 +5525,7 @@ make_compound_operation (x, in_code)
new = make_extraction (mode, make_compound_operation (new, next_code),
0, NULL_RTX, mode_width - INTVAL (rhs),
code == LSHIFTRT, 0, in_code == COMPARE);
-
+
break;
case SUBREG:
@@ -5580,7 +5605,7 @@ get_pos_from_mask (m, plen)
Return a possibly simplified expression, but always convert X to
MODE. If X is a CONST_INT, AND the CONST_INT with MASK.
- Also, if REG is non-zero and X is a register equal in value to REG,
+ Also, if REG is non-zero and X is a register equal in value to REG,
replace X with REG.
If JUST_SELECT is nonzero, don't optimize by noticing that bits in MASK
@@ -5654,7 +5679,7 @@ force_to_mode (x, mode, mask, reg, just_select)
if (width > 0 && width < HOST_BITS_PER_WIDE_INT
&& (cval & ((HOST_WIDE_INT) 1 << (width - 1))) != 0)
cval |= (HOST_WIDE_INT) -1 << width;
-
+
return GEN_INT (cval);
}
@@ -5828,7 +5853,7 @@ force_to_mode (x, mode, mask, reg, just_select)
if (GET_CODE (op1) == CONST_INT && (code == IOR || code == XOR)
&& (INTVAL (op1) & mask) != 0)
op1 = GEN_INT (INTVAL (op1) & mask);
-
+
if (op_mode != GET_MODE (x) || op0 != XEXP (x, 0) || op1 != XEXP (x, 1))
x = gen_binary (code, op_mode, op0, op1);
break;
@@ -5847,7 +5872,7 @@ force_to_mode (x, mode, mask, reg, just_select)
&& (nonzero_bits (XEXP (x, 1), GET_MODE (XEXP (x, 1)))
< (unsigned HOST_WIDE_INT) GET_MODE_BITSIZE (mode))))
break;
-
+
/* If the shift count is a constant and we can do arithmetic in
the mode of the shift, refine which bits we need. Otherwise, use the
conservative form of the mask. */
@@ -5986,7 +6011,7 @@ force_to_mode (x, mode, mask, reg, just_select)
INTVAL (temp), reg, next_select));
}
break;
-
+
case NEG:
/* If we just want the low-order bit, the NEG isn't needed since it
won't change the low-order bit. */
@@ -6133,8 +6158,8 @@ if_then_else_cond (x, ptrue, pfalse)
&& ! side_effects_p (x))
{
*ptrue = gen_binary (MULT, mode, op0, const_true_rtx);
- *pfalse = gen_binary (MULT, mode,
- (code == MINUS
+ *pfalse = gen_binary (MULT, mode,
+ (code == MINUS
? gen_unary (NEG, mode, mode, op1) : op1),
const_true_rtx);
return cond0;
@@ -6207,7 +6232,7 @@ if_then_else_cond (x, ptrue, pfalse)
|| ((cond0 = get_last_value (x)) != 0 && CONSTANT_P (cond0)))
;
- /* If X is known to be either 0 or -1, those are the true and
+ /* If X is known to be either 0 or -1, those are the true and
false values when testing X. */
else if (num_sign_bit_copies (x, mode) == size)
{
@@ -6354,7 +6379,7 @@ make_field_assignment (x)
else if (GET_CODE (src) == AND && GET_CODE (XEXP (src, 0)) == SUBREG
&& subreg_lowpart_p (XEXP (src, 0))
- && (GET_MODE_SIZE (GET_MODE (XEXP (src, 0)))
+ && (GET_MODE_SIZE (GET_MODE (XEXP (src, 0)))
< GET_MODE_SIZE (GET_MODE (SUBREG_REG (XEXP (src, 0)))))
&& GET_CODE (SUBREG_REG (XEXP (src, 0))) == ROTATE
&& INTVAL (XEXP (SUBREG_REG (XEXP (src, 0)), 0)) == -2
@@ -6415,7 +6440,7 @@ make_field_assignment (x)
/* The mode to use for the source is the mode of the assignment, or of
what is inside a possible STRICT_LOW_PART. */
- mode = (GET_CODE (assign) == STRICT_LOW_PART
+ mode = (GET_CODE (assign) == STRICT_LOW_PART
? GET_MODE (XEXP (assign, 0)) : GET_MODE (assign));
/* Shift OTHER right POS places and make it the source, restricting it
@@ -6601,7 +6626,7 @@ simplify_and_const_int (x, mode, varop, constop)
if (GET_CODE (varop) == NEG && nonzero_bits (XEXP (varop, 0), mode) == 1
&& (i = exact_log2 (constop)) >= 0)
return simplify_shift_const (NULL_RTX, ASHIFT, mode, XEXP (varop, 0), i);
-
+
/* If VAROP is an IOR or XOR, apply the AND to both branches of the IOR
or XOR, then try to apply the distributive law. This may eliminate
operations if either branch can be simplified because of the AND.
@@ -6688,7 +6713,7 @@ nonzero_bits (x, mode)
#ifndef WORD_REGISTER_OPERATIONS
/* If MODE is wider than X, but both are a single word for both the host
- and target machines, we can compute this from which bits of the
+ and target machines, we can compute this from which bits of the
object might be nonzero in its own mode, taking into account the fact
that on many CISC machines, accessing an object in a wider mode
causes the high-order bits to become undefined. So they are
@@ -6748,7 +6773,7 @@ nonzero_bits (x, mode)
constant that would appear negative in the mode of X,
sign-extend it for use in reg_nonzero_bits because some
machines (maybe most) will actually do the sign-extension
- and this is the conservative approach.
+ and this is the conservative approach.
??? For 2.5, try to tighten up the MD files in this regard
instead of this kludge. */
@@ -6874,8 +6899,10 @@ nonzero_bits (x, mode)
int width1 = floor_log2 (nz1) + 1;
int low0 = floor_log2 (nz0 & -nz0);
int low1 = floor_log2 (nz1 & -nz1);
- int op0_maybe_minusp = (nz0 & ((HOST_WIDE_INT) 1 << (mode_width - 1)));
- int op1_maybe_minusp = (nz1 & ((HOST_WIDE_INT) 1 << (mode_width - 1)));
+ HOST_WIDE_INT op0_maybe_minusp
+ = (nz0 & ((HOST_WIDE_INT) 1 << (mode_width - 1)));
+ HOST_WIDE_INT op1_maybe_minusp
+ = (nz1 & ((HOST_WIDE_INT) 1 << (mode_width - 1)));
int result_width = mode_width;
int result_low = 0;
@@ -7047,7 +7074,7 @@ num_sign_bit_copies (x, mode)
if (bitwidth < GET_MODE_BITSIZE (GET_MODE (x)))
return MAX (1, (num_sign_bit_copies (x, GET_MODE (x))
- (GET_MODE_BITSIZE (GET_MODE (x)) - bitwidth)));
-
+
#ifndef WORD_REGISTER_OPERATIONS
/* If this machine does not do all register operations on the entire
register and MODE is wider than the mode of X, we can say nothing
@@ -7128,7 +7155,7 @@ num_sign_bit_copies (x, mode)
return MAX (1, bitwidth - INTVAL (XEXP (x, 1)));
break;
- case SIGN_EXTEND:
+ case SIGN_EXTEND:
return (bitwidth - GET_MODE_BITSIZE (GET_MODE (XEXP (x, 0)))
+ num_sign_bit_copies (XEXP (x, 0), VOIDmode));
@@ -7197,7 +7224,7 @@ num_sign_bit_copies (x, mode)
num0 = num_sign_bit_copies (XEXP (x, 0), mode);
num1 = num_sign_bit_copies (XEXP (x, 1), mode);
return MAX (1, MIN (num0, num1) - 1);
-
+
case MULT:
/* The number of bits of the product is the sum of the number of
bits of both terms. However, unless one of the terms if known
@@ -7328,7 +7355,7 @@ extended_count (x, mode, unsignedp)
(with *POP0 being done last).
Return 1 if we can do the operation and update *POP0 and *PCONST0 with
- the resulting operation. *PCOMP_P is set to 1 if we would need to
+ the resulting operation. *PCOMP_P is set to 1 if we would need to
complement the innermost operand, otherwise it is unchanged.
MODE is the mode in which the operation will be done. No bits outside
@@ -7522,7 +7549,7 @@ simplify_shift_const (x, code, result_mode, varop, count)
Since these shifts are being produced by the compiler by combining
multiple operations, each of which are defined, we know what the
result is supposed to be. */
-
+
if (count > GET_MODE_BITSIZE (shift_mode) - 1)
{
if (code == ASHIFTRT)
@@ -7631,7 +7658,7 @@ simplify_shift_const (x, code, result_mode, varop, count)
new = XEXP (varop, 0);
#else
new = copy_rtx (XEXP (varop, 0));
- SUBST (XEXP (new, 0),
+ SUBST (XEXP (new, 0),
plus_constant (XEXP (new, 0),
count / BITS_PER_UNIT));
#endif
@@ -7686,7 +7713,7 @@ simplify_shift_const (x, code, result_mode, varop, count)
break;
case ASHIFTRT:
- /* If we are extracting just the sign bit of an arithmetic right
+ /* If we are extracting just the sign bit of an arithmetic right
shift, that shift is not needed. */
if (code == LSHIFTRT && count == GET_MODE_BITSIZE (result_mode) - 1)
{
@@ -7724,7 +7751,7 @@ simplify_shift_const (x, code, result_mode, varop, count)
- GET_MODE_BITSIZE (GET_MODE (varop))) == count)
{
/* C3 has the low-order C1 bits zero. */
-
+
mask = (GET_MODE_MASK (mode)
& ~ (((HOST_WIDE_INT) 1 << first_count) - 1));
@@ -7736,11 +7763,11 @@ simplify_shift_const (x, code, result_mode, varop, count)
code = ASHIFTRT;
continue;
}
-
+
/* If this was (ashiftrt (ashift foo C1) C2) and FOO has more
than C1 high-order bits equal to the sign bit, we can convert
this to either an ASHIFT or a ASHIFTRT depending on the
- two counts.
+ two counts.
We cannot do this if VAROP's mode is not SHIFT_MODE. */
@@ -7791,7 +7818,7 @@ simplify_shift_const (x, code, result_mode, varop, count)
break;
/* To compute the mask to apply after the shift, shift the
- nonzero bits of the inner shift the same way the
+ nonzero bits of the inner shift the same way the
outer shift will. */
mask_rtx = GEN_INT (nonzero_bits (varop, GET_MODE (varop)));
@@ -7799,7 +7826,7 @@ simplify_shift_const (x, code, result_mode, varop, count)
mask_rtx
= simplify_binary_operation (code, result_mode, mask_rtx,
GEN_INT (count));
-
+
/* Give up if we can't compute an outer operation to use. */
if (mask_rtx == 0
|| GET_CODE (mask_rtx) != CONST_INT
@@ -7816,7 +7843,7 @@ simplify_shift_const (x, code, result_mode, varop, count)
else
count -= first_count;
- /* If COUNT is positive, the new shift is usually CODE,
+ /* If COUNT is positive, the new shift is usually CODE,
except for the two exceptions below, in which case it is
FIRST_CODE. If the count is negative, FIRST_CODE should
always be used */
@@ -8112,7 +8139,7 @@ simplify_shift_const (x, code, result_mode, varop, count)
if (orig_code == LSHIFTRT && result_mode != shift_mode)
x = simplify_and_const_int (NULL_RTX, shift_mode, x,
GET_MODE_MASK (result_mode) >> orig_count);
-
+
/* Do the remainder of the processing in RESULT_MODE. */
x = gen_lowpart_for_combine (result_mode, x);
@@ -8139,7 +8166,7 @@ simplify_shift_const (x, code, result_mode, varop, count)
}
return x;
-}
+}
/* Like recog, but we receive the address of a pointer to a new pattern.
We try to match the rtx that the pointer points to.
@@ -8428,11 +8455,11 @@ gen_binary (code, mode, op0, op1)
|| (CONSTANT_P (op0) && GET_CODE (op1) != CONST_INT)))
tem = op0, op0 = op1, op1 = tem;
- if (GET_RTX_CLASS (code) == '<')
+ if (GET_RTX_CLASS (code) == '<')
{
enum machine_mode op_mode = GET_MODE (op0);
- /* Strip the COMPARE from (REL_OP (compare X Y) 0) to get
+ /* Strip the COMPARE from (REL_OP (compare X Y) 0) to get
just (REL_OP X Y). */
if (GET_CODE (op0) == COMPARE && op1 == const0_rtx)
{
@@ -8587,7 +8614,7 @@ simplify_comparison (code, pop0, pop1)
HOST_WIDE_INT c0 = INTVAL (XEXP (op0, 1));
HOST_WIDE_INT c1 = INTVAL (XEXP (op1, 1));
int changed = 0;
-
+
if (GET_CODE (inner_op0) == SUBREG && GET_CODE (inner_op1) == SUBREG
&& (GET_MODE_SIZE (GET_MODE (inner_op0))
> GET_MODE_SIZE (GET_MODE (SUBREG_REG (inner_op0))))
@@ -8618,6 +8645,7 @@ simplify_comparison (code, pop0, pop1)
{
op0 = gen_lowpart_for_combine (tmode, inner_op0);
op1 = gen_lowpart_for_combine (tmode, inner_op1);
+ code = unsigned_condition (code);
changed = 1;
break;
}
@@ -8637,7 +8665,7 @@ simplify_comparison (code, pop0, pop1)
else
break;
}
-
+
/* If the first operand is a constant, swap the operands and adjust the
comparison code appropriately. */
if (CONSTANT_P (op0))
@@ -8706,7 +8734,7 @@ simplify_comparison (code, pop0, pop1)
}
/* Do some canonicalizations based on the comparison code. We prefer
- comparisons against zero and then prefer equality comparisons.
+ comparisons against zero and then prefer equality comparisons.
If we can reduce the size of a constant, we will do that too. */
switch (code)
@@ -8819,6 +8847,7 @@ simplify_comparison (code, pop0, pop1)
{
const_op = 0, op1 = const0_rtx;
code = LT;
+ break;
}
else
break;
@@ -8862,7 +8891,7 @@ simplify_comparison (code, pop0, pop1)
case ZERO_EXTRACT:
/* If we are extracting a single bit from a variable position in
a constant that has only a single bit set and are comparing it
- with zero, we can convert this into an equality comparison
+ with zero, we can convert this into an equality comparison
between the position and the location of the single bit. We can't
do this if bit endian and we don't have an extzv since we then
can't know what mode to use for the endianness adjustment. */
@@ -8994,11 +9023,11 @@ simplify_comparison (code, pop0, pop1)
continue;
}
break;
-
+
case SIGN_EXTEND:
/* Can simplify (compare (zero/sign_extend FOO) CONST)
- to (compare FOO CONST) if CONST fits in FOO's mode and we
+ to (compare FOO CONST) if CONST fits in FOO's mode and we
are either testing inequality or have an unsigned comparison
with ZERO_EXTEND or a signed comparison with SIGN_EXTEND. */
if (! unsigned_comparison_p
@@ -9526,7 +9555,7 @@ update_table_tick (x)
return;
}
-
+
for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
/* Note that we can't have an "E" in values stored; see
get_last_value_validate. */
@@ -9559,7 +9588,7 @@ record_value_for_reg (reg, insn, value)
/* Set things up so get_last_value is allowed to see anything set up to
our insn. */
subst_low_cuid = INSN_CUID (insn);
- tem = get_last_value (reg);
+ tem = get_last_value (reg);
if (tem)
value = replace_rtx (copy_rtx (value), reg, tem);
@@ -9636,6 +9665,9 @@ static void
record_dead_and_set_regs_1 (dest, setter)
rtx dest, setter;
{
+ if (GET_CODE (dest) == SUBREG)
+ dest = SUBREG_REG (dest);
+
if (GET_CODE (dest) == REG)
{
/* If we are setting the whole register, we know its value. Otherwise
@@ -9811,15 +9843,10 @@ get_last_value (x)
{
rtx insn, set;
- /* If there is an insn that is supposed to be immediately
- in front of subst_insn, use it. */
- if (subst_prev_insn != 0)
- insn = subst_prev_insn;
- else
- for (insn = prev_nonnote_insn (subst_insn);
- insn && INSN_CUID (insn) >= subst_low_cuid;
- insn = prev_nonnote_insn (insn))
- ;
+ for (insn = prev_nonnote_insn (subst_insn);
+ insn && INSN_CUID (insn) >= subst_low_cuid;
+ insn = prev_nonnote_insn (insn))
+ ;
if (insn
&& (set = single_set (insn)) != 0
@@ -9873,7 +9900,7 @@ use_crosses_set_p (x, from_cuid)
register int regno = REGNO (x);
int endreg = regno + (regno < FIRST_PSEUDO_REGISTER
? HARD_REGNO_NREGS (regno, GET_MODE (x)) : 1);
-
+
#ifdef PUSH_ROUNDING
/* Don't allow uses of the stack pointer to be moved,
because we don't know whether the move crosses a push insn. */
@@ -9916,7 +9943,7 @@ static int reg_dead_flag;
/* Function called via note_stores from reg_dead_at_p.
- If DEST is within [reg_dead_rengno, reg_dead_endregno), set
+ If DEST is within [reg_dead_rengno, reg_dead_endregno), set
reg_dead_flag to 1 if X is a CLOBBER and to -1 it is a SET. */
static void
@@ -9930,7 +9957,7 @@ reg_dead_at_p_1 (dest, x)
return;
regno = REGNO (dest);
- endregno = regno + (regno < FIRST_PSEUDO_REGISTER
+ endregno = regno + (regno < FIRST_PSEUDO_REGISTER
? HARD_REGNO_NREGS (regno, GET_MODE (dest)) : 1);
if (reg_dead_endregno > regno && reg_dead_regno < endregno)
@@ -10126,7 +10153,7 @@ remove_death (regno, insn)
/* For each register (hardware or pseudo) used within expression X, if its
death is in an instruction with cuid between FROM_CUID (inclusive) and
TO_INSN (exclusive), put a REG_DEAD note for that register in the
- list headed by PNOTES.
+ list headed by PNOTES.
This is done when X is being merged by combination into TO_INSN. These
notes will then be distributed as needed. */
@@ -10295,7 +10322,7 @@ reg_bitfield_target_p (x, body)
return 1;
return 0;
-}
+}
/* Given a chain of REG_NOTES originally from FROM_INSN, try to place them
as appropriate. I3 and I2 are the insns resulting from the combination
@@ -10332,10 +10359,7 @@ distribute_notes (notes, from_insn, i3, i2, elim_i2, elim_i1)
switch (REG_NOTE_KIND (note))
{
case REG_UNUSED:
- /* If this note is from any insn other than i3, then we have no
- use for it, and must ignore it.
-
- Any clobbers for i3 may still exist, and so we must process
+ /* Any clobbers for i3 may still exist, and so we must process
REG_UNUSED notes from that insn.
Any clobbers from i2 or i1 can only exist if they were added by
@@ -10345,14 +10369,18 @@ distribute_notes (notes, from_insn, i3, i2, elim_i2, elim_i1)
if it is for the same register as the original i3 dest.
In that case, we will notice that the register is set in i3,
and then add a REG_UNUSED note for the destination of i3, which
- is wrong. */
- if (from_insn != i3)
- break;
+ is wrong. However, it is possible to have REG_UNUSED notes from
+ i2 or i1 for register which were both used and clobbered, so
+ we keep notes from i2 or i1 if they will turn into REG_DEAD
+ notes. */
/* If this register is set or clobbered in I3, put the note there
unless there is one already. */
- else if (reg_set_p (XEXP (note, 0), PATTERN (i3)))
+ if (reg_set_p (XEXP (note, 0), PATTERN (i3)))
{
+ if (from_insn != i3)
+ break;
+
if (! (GET_CODE (XEXP (note, 0)) == REG
? find_regno_note (i3, REG_UNUSED, REGNO (XEXP (note, 0)))
: find_reg_note (i3, REG_UNUSED, XEXP (note, 0))))
@@ -10468,11 +10496,11 @@ distribute_notes (notes, from_insn, i3, i2, elim_i2, elim_i1)
if (XEXP (note, 0) == elim_i2 || XEXP (note, 0) == elim_i1)
break;
- /* If the register is used in both I2 and I3 and it dies in I3,
+ /* If the register is used in both I2 and I3 and it dies in I3,
we might have added another reference to it. If reg_n_refs
- was 2, bump it to 3. This has to be correct since the
+ was 2, bump it to 3. This has to be correct since the
register must have been set somewhere. The reason this is
- done is because local-alloc.c treats 2 references as a
+ done is because local-alloc.c treats 2 references as a
special case. */
if (place == i3 && i2 != 0 && GET_CODE (XEXP (note, 0)) == REG
@@ -10500,7 +10528,7 @@ distribute_notes (notes, from_insn, i3, i2, elim_i2, elim_i1)
&& rtx_equal_p (XEXP (note, 0), SET_DEST (set)))
{
/* Move the notes and links of TEM elsewhere.
- This might delete other dead insns recursively.
+ This might delete other dead insns recursively.
First set the pattern to something that won't use
any register. */
@@ -10536,13 +10564,13 @@ distribute_notes (notes, from_insn, i3, i2, elim_i2, elim_i1)
}
/* If the register is set or already dead at PLACE, we needn't do
- anything with this note if it is still a REG_DEAD note.
+ anything with this note if it is still a REG_DEAD note.
Note that we cannot use just `dead_or_set_p' here since we can
convert an assignment to a register into a bit-field assignment.
- Therefore, we must also omit the note if the register is the
+ Therefore, we must also omit the note if the register is the
target of a bitfield assignment. */
-
+
if (place && REG_NOTE_KIND (note) == REG_DEAD)
{
int regno = REGNO (XEXP (note, 0));
@@ -10633,7 +10661,9 @@ distribute_notes (notes, from_insn, i3, i2, elim_i2, elim_i1)
{
rtx piece = gen_rtx (REG, reg_raw_mode[i], i);
- if (reg_referenced_p (piece, PATTERN (place))
+ if ((reg_referenced_p (piece, PATTERN (place))
+ || (GET_CODE (place) == CALL_INSN
+ && find_reg_fusage (place, USE, piece)))
&& ! dead_or_set_p (place, piece)
&& ! reg_bitfield_target_p (piece,
PATTERN (place)))
@@ -10697,7 +10727,7 @@ distribute_links (links)
/* If the insn that this link points to is a NOTE or isn't a single
set, ignore it. In the latter case, it isn't clear what we
- can do other than ignore the link, since we can't tell which
+ can do other than ignore the link, since we can't tell which
register it was for. Such links wouldn't be used by combine
anyway.
@@ -10761,7 +10791,7 @@ distribute_links (links)
/* Set added_links_insn to the earliest insn we added a
link to. */
- if (added_links_insn == 0
+ if (added_links_insn == 0
|| INSN_CUID (added_links_insn) > INSN_CUID (place))
added_links_insn = place;
}
diff --git a/gnu/usr.bin/cc/cc_int/convert.c b/gnu/usr.bin/cc/cc_int/convert.c
index 2cb5990..900f9c5 100644
--- a/gnu/usr.bin/cc/cc_int/convert.c
+++ b/gnu/usr.bin/cc/cc_int/convert.c
@@ -37,7 +37,7 @@ convert_to_pointer (type, expr)
{
register tree intype = TREE_TYPE (expr);
register enum tree_code form = TREE_CODE (intype);
-
+
if (integer_zerop (expr))
{
if (type == TREE_TYPE (null_pointer_node))
@@ -381,7 +381,7 @@ convert_to_integer (type, expr)
to push the narrowing down through the conditional. */
return fold (build (COND_EXPR, type,
TREE_OPERAND (expr, 0),
- convert (type, TREE_OPERAND (expr, 1)),
+ convert (type, TREE_OPERAND (expr, 1)),
convert (type, TREE_OPERAND (expr, 2))));
}
}
@@ -415,7 +415,7 @@ convert_to_complex (type, expr)
{
register enum tree_code form = TREE_CODE (TREE_TYPE (expr));
tree subtype = TREE_TYPE (type);
-
+
if (form == REAL_TYPE || form == INTEGER_TYPE || form == ENUMERAL_TYPE)
{
expr = convert (subtype, expr);
@@ -453,7 +453,7 @@ convert_to_complex (type, expr)
error ("pointer value used where a complex was expected");
else
error ("aggregate value used where a complex was expected");
-
+
return build (COMPLEX_EXPR, type,
convert (subtype, integer_zero_node),
convert (subtype, integer_zero_node));
diff --git a/gnu/usr.bin/cc/cc_int/cse.c b/gnu/usr.bin/cc/cc_int/cse.c
index b4947d0..89643e0 100644
--- a/gnu/usr.bin/cc/cc_int/cse.c
+++ b/gnu/usr.bin/cc/cc_int/cse.c
@@ -59,7 +59,7 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
is to keep it in a hash table.
Registers and "quantity numbers":
-
+
At the start of each basic block, all of the (hardware and pseudo)
registers used in the function are given distinct quantity
numbers to indicate their contents. During scan, when the code
@@ -91,7 +91,7 @@ Registers and "quantity numbers":
any mode, two REG expressions might be equivalent in the hash table
but not have the same quantity number if the quantity number of one
of the registers is not the same mode as those expressions.
-
+
Constants and quantity numbers
When a quantity has a known constant value, that value is stored
@@ -186,7 +186,7 @@ Related expressions:
is also entered. These are made to point at each other
so that it is possible to find out if there exists any
register equivalent to an expression related to a given expression. */
-
+
/* One plus largest register number used in this function. */
static int max_reg;
@@ -201,7 +201,7 @@ static int max_qty;
static int next_qty;
-/* Indexed by quantity number, gives the first (or last) (pseudo) register
+/* Indexed by quantity number, gives the first (or last) (pseudo) register
in the chain of registers that currently contain this quantity. */
static int *qty_first_reg;
@@ -296,7 +296,7 @@ static int *reg_tick;
static int *reg_in_table;
-/* A HARD_REG_SET containing all the hard registers for which there is
+/* A HARD_REG_SET containing all the hard registers for which there is
currently a REG expression in the hash table. Note the difference
from the above variables, which indicate if the REG is mentioned in some
expression in the table. */
@@ -500,7 +500,7 @@ static int n_elements_made;
static int max_elements_made;
-/* Surviving equivalence class when two equivalence classes are merged
+/* Surviving equivalence class when two equivalence classes are merged
by recording the effects of a jump in the last insn. Zero if the
last insn was not a conditional jump. */
@@ -618,7 +618,7 @@ static struct table_elt *insert PROTO((rtx, struct table_elt *, unsigned,
enum machine_mode));
static void merge_equiv_classes PROTO((struct table_elt *,
struct table_elt *));
-static void invalidate PROTO((rtx));
+static void invalidate PROTO((rtx, enum machine_mode));
static void remove_invalid_refs PROTO((int));
static void rehash_using_reg PROTO((rtx));
static void invalidate_memory PROTO((struct write_data *));
@@ -735,7 +735,7 @@ rtx_cost (x, outer_code)
return 2;
#ifdef RTX_COSTS
RTX_COSTS (x, code, outer_code);
-#endif
+#endif
CONST_COSTS (x, code, outer_code);
}
@@ -1096,7 +1096,7 @@ remove_from_table (elt, hash)
elt->first_same_value = 0;
/* Remove the table element from its equivalence class. */
-
+
{
register struct table_elt *prev = elt->prev_same_value;
register struct table_elt *next = elt->next_same_value;
@@ -1231,7 +1231,7 @@ lookup_as_function (x, code)
&& exp_equiv_p (p->exp, p->exp, 1, 0))
return p->exp;
}
-
+
return 0;
}
@@ -1459,14 +1459,17 @@ merge_equiv_classes (class1, class2)
hash_arg_in_memory = 0;
hash_arg_in_struct = 0;
hash = HASH (exp, mode);
-
+
if (GET_CODE (exp) == REG)
delete_reg_equiv (REGNO (exp));
-
+
remove_from_table (elt, hash);
if (insert_regs (exp, class1, 0))
- hash = HASH (exp, mode);
+ {
+ rehash_using_reg (exp);
+ hash = HASH (exp, mode);
+ }
new = insert (exp, class1, hash, mode);
new->in_memory = hash_arg_in_memory;
new->in_struct = hash_arg_in_struct;
@@ -1480,14 +1483,18 @@ merge_equiv_classes (class1, class2)
(because, when a memory reference with a varying address is stored in,
all memory references are removed by invalidate_memory
so specific invalidation is superfluous).
+ FULL_MODE, if not VOIDmode, indicates that this much should be invalidated
+ instead of just the amount indicated by the mode of X. This is only used
+ for bitfield stores into memory.
A nonvarying address may be just a register or just
a symbol reference, or it may be either of those plus
a numeric offset. */
static void
-invalidate (x)
+invalidate (x, full_mode)
rtx x;
+ enum machine_mode full_mode;
{
register int i;
register struct table_elt *p;
@@ -1562,7 +1569,7 @@ invalidate (x)
{
if (GET_CODE (SUBREG_REG (x)) != REG)
abort ();
- invalidate (SUBREG_REG (x));
+ invalidate (SUBREG_REG (x), VOIDmode);
return;
}
@@ -1573,7 +1580,10 @@ invalidate (x)
if (GET_CODE (x) != MEM)
abort ();
- set_nonvarying_address_components (XEXP (x, 0), GET_MODE_SIZE (GET_MODE (x)),
+ if (full_mode == VOIDmode)
+ full_mode = GET_MODE (x);
+
+ set_nonvarying_address_components (XEXP (x, 0), GET_MODE_SIZE (full_mode),
&base, &start, &end);
for (i = 0; i < NBUCKETS; i++)
@@ -1711,7 +1721,7 @@ invalidate_for_call ()
if (reg_tick[regno] >= 0)
reg_tick[regno]++;
- in_table |= TEST_HARD_REG_BIT (hard_regs_in_table, regno);
+ in_table |= (TEST_HARD_REG_BIT (hard_regs_in_table, regno) != 0);
}
/* In the case where we have no call-clobbered hard registers in the
@@ -1948,17 +1958,6 @@ canon_hash (x, mode)
if (fmt[i] == 'e')
{
rtx tem = XEXP (x, i);
- rtx tem1;
-
- /* If the operand is a REG that is equivalent to a constant, hash
- as if we were hashing the constant, since we will be comparing
- that way. */
- if (tem != 0 && GET_CODE (tem) == REG
- && REGNO_QTY_VALID_P (REGNO (tem))
- && qty_mode[reg_qty[REGNO (tem)]] == GET_MODE (tem)
- && (tem1 = qty_const[reg_qty[REGNO (tem)]]) != 0
- && CONSTANT_P (tem1))
- tem = tem1;
/* If we are about to do the last recursive call
needed at this level, change it into iteration.
@@ -2230,9 +2229,10 @@ refers_to_p (x, y)
set PBASE, PSTART, and PEND which correspond to the base of the address,
the starting offset, and ending offset respectively.
- ADDR is known to be a nonvarying address.
+ ADDR is known to be a nonvarying address. */
- cse_address_varies_p returns zero for nonvarying addresses. */
+/* ??? Despite what the comments say, this function is in fact frequently
+ passed varying addresses. This does not appear to cause any problems. */
static void
set_nonvarying_address_components (addr, size, pbase, pstart, pend)
@@ -2323,6 +2323,12 @@ set_nonvarying_address_components (addr, size, pbase, pstart, pend)
break;
}
+ if (GET_CODE (base) == CONST_INT)
+ {
+ start += INTVAL (base);
+ base = const0_rtx;
+ }
+
end = start + size;
/* Set the return values. */
@@ -2353,13 +2359,6 @@ refers_to_mem_p (x, base, start, end)
register enum rtx_code code;
register char *fmt;
- if (GET_CODE (base) == CONST_INT)
- {
- start += INTVAL (base);
- end += INTVAL (base);
- base = const0_rtx;
- }
-
repeat:
if (x == 0)
return 0;
@@ -2375,7 +2374,7 @@ refers_to_mem_p (x, base, start, end)
&mybase, &mystart, &myend);
- /* refers_to_mem_p is never called with varying addresses.
+ /* refers_to_mem_p is never called with varying addresses.
If the base addresses are not equal, there is no chance
of the memory addresses conflicting. */
if (! rtx_equal_p (mybase, base))
@@ -2588,7 +2587,7 @@ find_best_addr (insn, loc)
if (GET_CODE (addr) != REG
&& validate_change (insn, loc, fold_rtx (addr, insn), 0))
addr = *loc;
-
+
/* If this address is not in the hash table, we can't look for equivalences
of the whole address. Also, ignore if volatile. */
@@ -2634,7 +2633,7 @@ find_best_addr (insn, loc)
{
int best_addr_cost = ADDRESS_COST (*loc);
int best_rtx_cost = (elt->cost + 1) >> 1;
- struct table_elt *best_elt = elt;
+ struct table_elt *best_elt = elt;
found_better = 0;
for (p = elt->first_same_value; p; p = p->next_same_value)
@@ -2702,7 +2701,7 @@ find_best_addr (insn, loc)
{
int best_addr_cost = ADDRESS_COST (*loc);
int best_rtx_cost = (COST (*loc) + 1) >> 1;
- struct table_elt *best_elt = elt;
+ struct table_elt *best_elt = elt;
rtx best_rtx = *loc;
int count;
@@ -3086,7 +3085,7 @@ simplify_unary_operation (code, mode, op, op_mode)
/* We can do some operations on integer CONST_DOUBLEs. Also allow
for a DImode operation on a CONST_INT. */
- else if (GET_MODE (op) == VOIDmode && width == HOST_BITS_PER_INT * 2
+ else if (GET_MODE (op) == VOIDmode && width <= HOST_BITS_PER_INT * 2
&& (GET_CODE (op) == CONST_DOUBLE || GET_CODE (op) == CONST_INT))
{
HOST_WIDE_INT l1, h1, lv, hv;
@@ -3123,10 +3122,8 @@ simplify_unary_operation (code, mode, op, op_mode)
break;
case TRUNCATE:
- if (GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT)
- return GEN_INT (l1 & GET_MODE_MASK (mode));
- else
- return 0;
+ /* This is just a change-of-mode, so do nothing. */
+ lv = l1, hv = h1;
break;
case ZERO_EXTEND:
@@ -3220,7 +3217,10 @@ simplify_unary_operation (code, mode, op, op_mode)
set_float_handler (NULL_PTR);
return x;
}
- else if (GET_CODE (op) == CONST_DOUBLE && GET_MODE_CLASS (mode) == MODE_INT
+
+ else if (GET_CODE (op) == CONST_DOUBLE
+ && GET_MODE_CLASS (GET_MODE (op)) == MODE_FLOAT
+ && GET_MODE_CLASS (mode) == MODE_INT
&& width <= HOST_BITS_PER_WIDE_INT && width > 0)
{
REAL_VALUE_TYPE d;
@@ -3589,7 +3589,7 @@ simplify_binary_operation (code, mode, op0, op1)
}
/* If one of the operands is a PLUS or a MINUS, see if we can
- simplify this by the associative law.
+ simplify this by the associative law.
Don't use the associative law for floating point.
The inaccuracy makes it nonassociative,
and subtle programs can break if operations are associated. */
@@ -3617,7 +3617,7 @@ simplify_binary_operation (code, mode, op0, op1)
/* Do nothing here. */
#endif
break;
-
+
case MINUS:
/* None of these optimizations can be done for IEEE
floating point. */
@@ -3704,7 +3704,7 @@ simplify_binary_operation (code, mode, op0, op1)
return cse_gen_binary (PLUS, mode, op0, XEXP (op1, 0));
/* If one of the operands is a PLUS or a MINUS, see if we can
- simplify this by the associative law.
+ simplify this by the associative law.
Don't use the associative law for floating point.
The inaccuracy makes it nonassociative,
and subtle programs can break if operations are associated. */
@@ -3853,10 +3853,10 @@ simplify_binary_operation (code, mode, op0, op1)
{
#if defined (REAL_ARITHMETIC)
REAL_ARITHMETIC (d, rtx_to_tree_code (DIV), dconst1, d);
- return gen_rtx (MULT, mode, op0,
+ return gen_rtx (MULT, mode, op0,
CONST_DOUBLE_FROM_REAL_VALUE (d, mode));
#else
- return gen_rtx (MULT, mode, op0,
+ return gen_rtx (MULT, mode, op0,
CONST_DOUBLE_FROM_REAL_VALUE (1./d, mode));
#endif
}
@@ -3898,14 +3898,14 @@ simplify_binary_operation (code, mode, op0, op1)
break;
case SMIN:
- if (width <= HOST_BITS_PER_WIDE_INT && GET_CODE (op1) == CONST_INT
+ if (width <= HOST_BITS_PER_WIDE_INT && GET_CODE (op1) == CONST_INT
&& INTVAL (op1) == (HOST_WIDE_INT) 1 << (width -1)
&& ! side_effects_p (op0))
return op1;
else if (rtx_equal_p (op0, op1) && ! side_effects_p (op0))
return op0;
break;
-
+
case SMAX:
if (width <= HOST_BITS_PER_WIDE_INT && GET_CODE (op1) == CONST_INT
&& (INTVAL (op1)
@@ -3922,7 +3922,7 @@ simplify_binary_operation (code, mode, op0, op1)
else if (rtx_equal_p (op0, op1) && ! side_effects_p (op0))
return op0;
break;
-
+
case UMAX:
if (op1 == constm1_rtx && ! side_effects_p (op0))
return op1;
@@ -3933,7 +3933,7 @@ simplify_binary_operation (code, mode, op0, op1)
default:
abort ();
}
-
+
return 0;
}
@@ -4134,7 +4134,7 @@ simplify_plus_minus (code, mode, op0, op1)
int i, j;
bzero ((char *) ops, sizeof ops);
-
+
/* Set up the two operands and then expand them until nothing has been
changed. If we run out of room in our array, give up; this should
almost never happen. */
@@ -4287,7 +4287,7 @@ simplify_plus_minus (code, mode, op0, op1)
return negate ? gen_rtx (NEG, mode, result) : result;
}
-/* Make a binary operation by properly ordering the operands and
+/* Make a binary operation by properly ordering the operands and
seeing if the expression folds. */
static rtx
@@ -4394,7 +4394,7 @@ simplify_relational_operation (code, mode, op0, op1)
{
REAL_VALUE_TYPE d0, d1;
jmp_buf handler;
-
+
if (setjmp (handler))
return 0;
@@ -4428,7 +4428,7 @@ simplify_relational_operation (code, mode, op0, op1)
l0u = l0s = INTVAL (op0);
h0u = 0, h0s = l0s < 0 ? -1 : 0;
}
-
+
if (GET_CODE (op1) == CONST_DOUBLE)
{
l1u = l1s = CONST_DOUBLE_LOW (op1);
@@ -4637,7 +4637,7 @@ simplify_ternary_operation (code, mode, op0_mode, op0, op1, op2)
static rtx
fold_rtx (x, insn)
rtx x;
- rtx insn;
+ rtx insn;
{
register enum rtx_code code;
register enum machine_mode mode;
@@ -4773,7 +4773,7 @@ fold_rtx (x, insn)
extra bits will be. But we can find an equivalence for this SUBREG
by folding that operation is the narrow mode. This allows us to
fold arithmetic in narrow modes when the machine only supports
- word-sized arithmetic.
+ word-sized arithmetic.
Also look for a case where we have a SUBREG whose operand is the
same as our result. If both modes are smaller than a word, we
@@ -4846,7 +4846,7 @@ fold_rtx (x, insn)
if (op1)
op1 = equiv_constant (op1);
- /* If we are looking for the low SImode part of
+ /* If we are looking for the low SImode part of
(ashift:DI c (const_int 32)), it doesn't work
to compute that in SImode, because a 32-bit shift
in SImode is unpredictable. We know the value is 0. */
@@ -4856,7 +4856,7 @@ fold_rtx (x, insn)
&& INTVAL (op1) >= GET_MODE_BITSIZE (mode))
{
if (INTVAL (op1) < GET_MODE_BITSIZE (GET_MODE (elt->exp)))
-
+
/* If the count fits in the inner mode's width,
but exceeds the outer mode's width,
the value will get truncated to 0
@@ -4973,7 +4973,7 @@ fold_rtx (x, insn)
{
rtx label = XEXP (base, 0);
rtx table_insn = NEXT_INSN (label);
-
+
if (table_insn && GET_CODE (table_insn) == JUMP_INSN
&& GET_CODE (PATTERN (table_insn)) == ADDR_VEC)
{
@@ -5001,7 +5001,11 @@ fold_rtx (x, insn)
if (GET_MODE (table) != Pmode)
new = gen_rtx (TRUNCATE, GET_MODE (table), new);
- return new;
+ /* Indicate this is a constant. This isn't a
+ valid form of CONST, but it will only be used
+ to fold the next insns and then discarded, so
+ it should be safe. */
+ return gen_rtx (CONST, GET_MODE (new), new);
}
}
}
@@ -5174,15 +5178,28 @@ fold_rtx (x, insn)
switch (GET_RTX_CLASS (code))
{
case '1':
- /* We can't simplify extension ops unless we know the original mode. */
- if ((code == ZERO_EXTEND || code == SIGN_EXTEND)
- && mode_arg0 == VOIDmode)
- break;
- new = simplify_unary_operation (code, mode,
- const_arg0 ? const_arg0 : folded_arg0,
- mode_arg0);
+ {
+ int is_const = 0;
+
+ /* We can't simplify extension ops unless we know the
+ original mode. */
+ if ((code == ZERO_EXTEND || code == SIGN_EXTEND)
+ && mode_arg0 == VOIDmode)
+ break;
+
+ /* If we had a CONST, strip it off and put it back later if we
+ fold. */
+ if (const_arg0 != 0 && GET_CODE (const_arg0) == CONST)
+ is_const = 1, const_arg0 = XEXP (const_arg0, 0);
+
+ new = simplify_unary_operation (code, mode,
+ const_arg0 ? const_arg0 : folded_arg0,
+ mode_arg0);
+ if (new != 0 && is_const)
+ new = gen_rtx (CONST, mode, new);
+ }
break;
-
+
case '<':
/* See what items are actually being compared and set FOLDED_ARG[01]
to those values and CODE to the actual comparison code. If any are
@@ -5353,11 +5370,41 @@ fold_rtx (x, insn)
ADDR_DIFF_VEC table. */
if (const_arg1 && GET_CODE (const_arg1) == LABEL_REF)
{
- rtx y = lookup_as_function (folded_arg0, MINUS);
+ rtx y
+ = GET_CODE (folded_arg0) == MINUS ? folded_arg0
+ : lookup_as_function (folded_arg0, MINUS);
if (y != 0 && GET_CODE (XEXP (y, 1)) == LABEL_REF
&& XEXP (XEXP (y, 1), 0) == XEXP (const_arg1, 0))
return XEXP (y, 0);
+
+ /* Now try for a CONST of a MINUS like the above. */
+ if ((y = (GET_CODE (folded_arg0) == CONST ? folded_arg0
+ : lookup_as_function (folded_arg0, CONST))) != 0
+ && GET_CODE (XEXP (y, 0)) == MINUS
+ && GET_CODE (XEXP (XEXP (y, 0), 1)) == LABEL_REF
+ && XEXP (XEXP (XEXP (y, 0),1), 0) == XEXP (const_arg1, 0))
+ return XEXP (XEXP (y, 0), 0);
+ }
+
+ /* Likewise if the operands are in the other order. */
+ if (const_arg0 && GET_CODE (const_arg0) == LABEL_REF)
+ {
+ rtx y
+ = GET_CODE (folded_arg1) == MINUS ? folded_arg1
+ : lookup_as_function (folded_arg1, MINUS);
+
+ if (y != 0 && GET_CODE (XEXP (y, 1)) == LABEL_REF
+ && XEXP (XEXP (y, 1), 0) == XEXP (const_arg0, 0))
+ return XEXP (y, 0);
+
+ /* Now try for a CONST of a MINUS like the above. */
+ if ((y = (GET_CODE (folded_arg1) == CONST ? folded_arg1
+ : lookup_as_function (folded_arg1, CONST))) != 0
+ && GET_CODE (XEXP (y, 0)) == MINUS
+ && GET_CODE (XEXP (XEXP (y, 0), 1)) == LABEL_REF
+ && XEXP (XEXP (XEXP (y, 0),1), 0) == XEXP (const_arg0, 0))
+ return XEXP (XEXP (y, 0), 0);
}
/* If second operand is a register equivalent to a negative
@@ -5557,7 +5604,7 @@ equiv_constant (x)
/* Assuming that X is an rtx (e.g., MEM, REG or SUBREG) for a fixed-point
number, return an rtx (MEM, SUBREG, or CONST_INT) that refers to the
least-significant part of X.
- MODE specifies how big a part of X to return.
+ MODE specifies how big a part of X to return.
If the requested operation cannot be done, 0 is returned.
@@ -5604,7 +5651,7 @@ gen_lowpart_if_possible (mode, x)
branch. It will be zero if not.
In certain cases, this can cause us to add an equivalence. For example,
- if we are following the taken case of
+ if we are following the taken case of
if (i == 2)
we can add the fact that `i' and '2' are now equivalent.
@@ -5700,7 +5747,7 @@ record_jump_cond (code, mode, op0, op1, reversed_nonequality)
reversed_nonequality);
}
- /* Similarly, if this is an NE comparison, and either is a SUBREG
+ /* Similarly, if this is an NE comparison, and either is a SUBREG
making a smaller mode, we know the whole thing is also NE. */
/* Note that GET_MODE (op0) may not equal MODE;
@@ -5751,7 +5798,7 @@ record_jump_cond (code, mode, op0, op1, reversed_nonequality)
op1_hash = HASH (op1, mode);
op1_in_memory = hash_arg_in_memory;
op1_in_struct = hash_arg_in_struct;
-
+
if (do_not_record)
return;
@@ -5759,6 +5806,13 @@ record_jump_cond (code, mode, op0, op1, reversed_nonequality)
op0_elt = lookup (op0, op0_hash, mode);
op1_elt = lookup (op1, op1_hash, mode);
+ /* If both operands are already equivalent or if they are not in the
+ table but are identical, do nothing. */
+ if ((op0_elt != 0 && op1_elt != 0
+ && op0_elt->first_same_value == op1_elt->first_same_value)
+ || op0 == op1 || rtx_equal_p (op0, op1))
+ return;
+
/* If we aren't setting two things equal all we can do is save this
comparison. Similarly if this is floating-point. In the latter
case, OP1 might be zero and both -0.0 and 0.0 are equal to it.
@@ -5868,7 +5922,7 @@ record_jump_cond (code, mode, op0, op1, reversed_nonequality)
First simplify sources and addresses of all assignments
in the instruction, using previously-computed equivalents values.
Then install the new sources and destinations in the table
- of available values.
+ of available values.
If IN_LIBCALL_BLOCK is nonzero, don't record any equivalence made in
the insn. */
@@ -5891,9 +5945,9 @@ struct set
rtx inner_dest;
/* Place where the pointer to the INNER_DEST was found. */
rtx *inner_dest_loc;
- /* Nonzero if the SET_SRC is in memory. */
+ /* Nonzero if the SET_SRC is in memory. */
char src_in_memory;
- /* Nonzero if the SET_SRC is in a structure. */
+ /* Nonzero if the SET_SRC is in a structure. */
char src_in_struct;
/* Nonzero if the SET_SRC contains something
whose value cannot be predicted and understood. */
@@ -5945,7 +5999,7 @@ cse_insn (insn, in_libcall_block)
{
for (tem = CALL_INSN_FUNCTION_USAGE (insn); tem; tem = XEXP (tem, 1))
if (GET_CODE (XEXP (tem, 0)) == CLOBBER)
- invalidate (SET_DEST (XEXP (tem, 0)));
+ invalidate (SET_DEST (XEXP (tem, 0)), VOIDmode);
}
if (GET_CODE (x) == SET)
@@ -5976,7 +6030,7 @@ cse_insn (insn, in_libcall_block)
canon_reg (SET_SRC (x), insn);
apply_change_group ();
fold_rtx (SET_SRC (x), insn);
- invalidate (SET_DEST (x));
+ invalidate (SET_DEST (x), VOIDmode);
}
else
n_sets = 1;
@@ -6007,13 +6061,13 @@ cse_insn (insn, in_libcall_block)
if (GET_CODE (clobbered) == REG
|| GET_CODE (clobbered) == SUBREG)
- invalidate (clobbered);
+ invalidate (clobbered, VOIDmode);
else if (GET_CODE (clobbered) == STRICT_LOW_PART
|| GET_CODE (clobbered) == ZERO_EXTRACT)
- invalidate (XEXP (clobbered, 0));
+ invalidate (XEXP (clobbered, 0), GET_MODE (clobbered));
}
}
-
+
for (i = 0; i < lim; i++)
{
register rtx y = XVECEXP (x, 0, i);
@@ -6026,7 +6080,7 @@ cse_insn (insn, in_libcall_block)
canon_reg (SET_SRC (y), insn);
apply_change_group ();
fold_rtx (SET_SRC (y), insn);
- invalidate (SET_DEST (y));
+ invalidate (SET_DEST (y), VOIDmode);
}
else if (SET_DEST (y) == pc_rtx
&& GET_CODE (SET_SRC (y)) == LABEL_REF)
@@ -6137,7 +6191,7 @@ cse_insn (insn, in_libcall_block)
group and see if they all work. Note that this will cause some
canonicalizations that would have worked individually not to be applied
because some other canonicalization didn't work, but this should not
- occur often.
+ occur often.
The result of apply_change_group can be ignored; see canon_reg. */
@@ -6305,7 +6359,7 @@ cse_insn (insn, in_libcall_block)
if (src_const == 0
&& (CONSTANT_P (src_folded)
- /* Consider (minus (label_ref L1) (label_ref L2)) as
+ /* Consider (minus (label_ref L1) (label_ref L2)) as
"constant" here so we will record it. This allows us
to fold switch statements when an ADDR_DIFF_VEC is used. */
|| (GET_CODE (src_folded) == MINUS
@@ -6350,7 +6404,7 @@ cse_insn (insn, in_libcall_block)
{
if (elt->first_same_value
!= src_related_elt->first_same_value)
- /* This can occur when we previously saw a CONST
+ /* This can occur when we previously saw a CONST
involving a SYMBOL_REF and then see the SYMBOL_REF
twice. Merge the involved classes. */
merge_equiv_classes (elt, src_related_elt);
@@ -6442,7 +6496,7 @@ cse_insn (insn, in_libcall_block)
if it has, we can use a subreg of that. Many CISC machines
also have such operations, but this is only likely to be
beneficial these machines. */
-
+
if (flag_expensive_optimizations && src_related == 0
&& (GET_MODE_SIZE (mode) < UNITS_PER_WORD)
&& GET_MODE_CLASS (mode) == MODE_INT
@@ -6450,39 +6504,39 @@ cse_insn (insn, in_libcall_block)
&& LOAD_EXTEND_OP (mode) != NIL)
{
enum machine_mode tmode;
-
+
/* Set what we are trying to extend and the operation it might
have been extended with. */
PUT_CODE (memory_extend_rtx, LOAD_EXTEND_OP (mode));
XEXP (memory_extend_rtx, 0) = src;
-
+
for (tmode = GET_MODE_WIDER_MODE (mode);
GET_MODE_SIZE (tmode) <= UNITS_PER_WORD;
tmode = GET_MODE_WIDER_MODE (tmode))
{
struct table_elt *larger_elt;
-
+
PUT_MODE (memory_extend_rtx, tmode);
- larger_elt = lookup (memory_extend_rtx,
+ larger_elt = lookup (memory_extend_rtx,
HASH (memory_extend_rtx, tmode), tmode);
if (larger_elt == 0)
continue;
-
+
for (larger_elt = larger_elt->first_same_value;
larger_elt; larger_elt = larger_elt->next_same_value)
if (GET_CODE (larger_elt->exp) == REG)
{
- src_related = gen_lowpart_if_possible (mode,
+ src_related = gen_lowpart_if_possible (mode,
larger_elt->exp);
break;
}
-
+
if (src_related)
break;
}
}
#endif /* LOAD_EXTEND_OP */
-
+
if (src == src_folded)
src_folded = 0;
@@ -6570,7 +6624,7 @@ cse_insn (insn, in_libcall_block)
cheaper even though it looks more expensive. */
if (dest == pc_rtx && src_const && GET_CODE (src_const) == LABEL_REF)
src_folded = src_const, src_folded_cost = -1;
-
+
/* Terminate loop when replacement made. This must terminate since
the current contents will be tested and will always be valid. */
while (1)
@@ -6580,8 +6634,8 @@ cse_insn (insn, in_libcall_block)
/* Skip invalid entries. */
while (elt && GET_CODE (elt->exp) != REG
&& ! exp_equiv_p (elt->exp, elt->exp, 1, 0))
- elt = elt->next_same_value;
-
+ elt = elt->next_same_value;
+
if (elt) src_elt_cost = elt->cost;
/* Find cheapest and skip it for the next time. For items
@@ -6642,7 +6696,7 @@ cse_insn (insn, in_libcall_block)
cse_jumps_altered = 1;
break;
}
-
+
/* Look for a substitution that makes a valid insn. */
else if (validate_change (insn, &SET_SRC (sets[i].rtl), trial, 0))
{
@@ -6656,14 +6710,18 @@ cse_insn (insn, in_libcall_block)
break;
}
- /* If we previously found constant pool entries for
+ /* If we previously found constant pool entries for
constants and this is a constant, try making a
pool entry. Put it in src_folded unless we already have done
this since that is where it likely came from. */
else if (constant_pool_entries_cost
&& CONSTANT_P (trial)
- && (src_folded == 0 || GET_CODE (src_folded) != MEM)
+ && ! (GET_CODE (trial) == CONST
+ && GET_CODE (XEXP (trial, 0)) == TRUNCATE)
+ && (src_folded == 0
+ || (GET_CODE (src_folded) != MEM
+ && ! src_folded_force_flag))
&& GET_MODE_CLASS (mode) != MODE_CC)
{
src_folded_force_flag = 1;
@@ -6729,7 +6787,7 @@ cse_insn (insn, in_libcall_block)
&& GET_CODE (src_const) != REG)
{
tem = find_reg_note (insn, REG_EQUAL, NULL_RTX);
-
+
/* Record the actual constant value in a REG_EQUAL note, making
a new one if one does not already exist. */
if (tem)
@@ -6916,10 +6974,10 @@ cse_insn (insn, in_libcall_block)
{
if (GET_CODE (dest) == REG || GET_CODE (dest) == SUBREG
|| GET_CODE (dest) == MEM)
- invalidate (dest);
+ invalidate (dest, VOIDmode);
else if (GET_CODE (dest) == STRICT_LOW_PART
|| GET_CODE (dest) == ZERO_EXTRACT)
- invalidate (XEXP (dest, 0));
+ invalidate (XEXP (dest, 0), GET_MODE (dest));
sets[i].rtl = 0;
}
@@ -6965,7 +7023,10 @@ cse_insn (insn, in_libcall_block)
classp = 0;
}
if (insert_regs (src_eqv, classp, 0))
- src_eqv_hash = HASH (src_eqv, eqvmode);
+ {
+ rehash_using_reg (src_eqv);
+ src_eqv_hash = HASH (src_eqv, eqvmode);
+ }
elt = insert (src_eqv, classp, src_eqv_hash, eqvmode);
elt->in_memory = src_eqv_in_memory;
elt->in_struct = src_eqv_in_struct;
@@ -7012,7 +7073,10 @@ cse_insn (insn, in_libcall_block)
any of the src_elt's, because they would have failed to
match if not still valid. */
if (insert_regs (src, classp, 0))
- sets[i].src_hash = HASH (src, mode);
+ {
+ rehash_using_reg (src);
+ sets[i].src_hash = HASH (src, mode);
+ }
elt = insert (src, classp, sets[i].src_hash, mode);
elt->in_memory = sets[i].src_in_memory;
elt->in_struct = sets[i].src_in_struct;
@@ -7034,7 +7098,7 @@ cse_insn (insn, in_libcall_block)
invalidate_from_clobbers (&writes_memory, x);
- /* Some registers are invalidated by subroutine calls. Memory is
+ /* Some registers are invalidated by subroutine calls. Memory is
invalidated by non-constant calls. */
if (GET_CODE (insn) == CALL_INSN)
@@ -7054,18 +7118,21 @@ cse_insn (insn, in_libcall_block)
for (i = 0; i < n_sets; i++)
if (sets[i].rtl)
{
- register rtx dest = sets[i].inner_dest;
+ /* We can't use the inner dest, because the mode associated with
+ a ZERO_EXTRACT is significant. */
+ register rtx dest = SET_DEST (sets[i].rtl);
/* Needed for registers to remove the register from its
previous quantity's chain.
Needed for memory if this is a nonvarying address, unless
we have just done an invalidate_memory that covers even those. */
if (GET_CODE (dest) == REG || GET_CODE (dest) == SUBREG
- || (! writes_memory.all && ! cse_rtx_addr_varies_p (dest)))
- invalidate (dest);
+ || (GET_CODE (dest) == MEM && ! writes_memory.all
+ && ! cse_rtx_addr_varies_p (dest)))
+ invalidate (dest, VOIDmode);
else if (GET_CODE (dest) == STRICT_LOW_PART
|| GET_CODE (dest) == ZERO_EXTRACT)
- invalidate (XEXP (dest, 0));
+ invalidate (XEXP (dest, 0), GET_MODE (dest));
}
/* Make sure registers mentioned in destinations
@@ -7122,7 +7189,17 @@ cse_insn (insn, in_libcall_block)
|| in_libcall_block
/* If we didn't put a REG_EQUAL value or a source into the hash
table, there is no point is recording DEST. */
- || sets[i].src_elt == 0)
+ || sets[i].src_elt == 0
+ /* If DEST is a paradoxical SUBREG and SRC is a ZERO_EXTEND
+ or SIGN_EXTEND, don't record DEST since it can cause
+ some tracking to be wrong.
+
+ ??? Think about this more later. */
+ || (GET_CODE (dest) == SUBREG
+ && (GET_MODE_SIZE (GET_MODE (dest))
+ > GET_MODE_SIZE (GET_MODE (SUBREG_REG (dest))))
+ && (GET_CODE (sets[i].src) == SIGN_EXTEND
+ || GET_CODE (sets[i].src) == ZERO_EXTEND)))
continue;
/* STRICT_LOW_PART isn't part of the value BEING set,
@@ -7134,9 +7211,12 @@ cse_insn (insn, in_libcall_block)
if (GET_CODE (dest) == REG || GET_CODE (dest) == SUBREG)
/* Registers must also be inserted into chains for quantities. */
if (insert_regs (dest, sets[i].src_elt, 1))
- /* If `insert_regs' changes something, the hash code must be
- recalculated. */
- sets[i].dest_hash = HASH (dest, GET_MODE (dest));
+ {
+ /* If `insert_regs' changes something, the hash code must be
+ recalculated. */
+ rehash_using_reg (dest);
+ sets[i].dest_hash = HASH (dest, GET_MODE (dest));
+ }
elt = insert (dest, sets[i].src_elt,
sets[i].dest_hash, GET_MODE (dest));
@@ -7158,7 +7238,7 @@ cse_insn (insn, in_libcall_block)
However, BAR may have equivalences for which gen_lowpart_if_possible
will produce a simpler value than gen_lowpart_if_possible applied to
BAR (e.g., if BAR was ZERO_EXTENDed from M2), so we will scan all
- BAR's equivalences. If we don't get a simplified form, make
+ BAR's equivalences. If we don't get a simplified form, make
the SUBREG. It will not be used in an equivalence, but will
cause two similar assignments to be detected.
@@ -7200,13 +7280,16 @@ cse_insn (insn, in_libcall_block)
if (src_elt == 0)
{
if (insert_regs (new_src, classp, 0))
- src_hash = HASH (new_src, new_mode);
+ {
+ rehash_using_reg (new_src);
+ src_hash = HASH (new_src, new_mode);
+ }
src_elt = insert (new_src, classp, src_hash, new_mode);
src_elt->in_memory = elt->in_memory;
src_elt->in_struct = elt->in_struct;
}
else if (classp && classp != src_elt->first_same_value)
- /* Show that two things that we've seen before are
+ /* Show that two things that we've seen before are
actually the same. */
merge_equiv_classes (src_elt, classp);
@@ -7217,7 +7300,7 @@ cse_insn (insn, in_libcall_block)
/* Special handling for (set REG0 REG1)
where REG0 is the "cheapest", cheaper than REG1.
- After cse, REG1 will probably not be used in the sequel,
+ After cse, REG1 will probably not be used in the sequel,
so (if easily done) change this insn to (set REG1 REG0) and
replace REG1 with REG0 in the previous insn that computed their value.
Then REG1 will become a dead store and won't cloud the situation
@@ -7377,7 +7460,7 @@ invalidate_from_clobbers (w, x)
/* This should be *very* rare. */
if (TEST_HARD_REG_BIT (hard_regs_in_table, STACK_POINTER_REGNUM))
- invalidate (stack_pointer_rtx);
+ invalidate (stack_pointer_rtx, VOIDmode);
}
if (GET_CODE (x) == CLOBBER)
@@ -7387,10 +7470,10 @@ invalidate_from_clobbers (w, x)
{
if (GET_CODE (ref) == REG || GET_CODE (ref) == SUBREG
|| (GET_CODE (ref) == MEM && ! w->all))
- invalidate (ref);
+ invalidate (ref, VOIDmode);
else if (GET_CODE (ref) == STRICT_LOW_PART
|| GET_CODE (ref) == ZERO_EXTRACT)
- invalidate (XEXP (ref, 0));
+ invalidate (XEXP (ref, 0), GET_MODE (ref));
}
}
else if (GET_CODE (x) == PARALLEL)
@@ -7406,10 +7489,10 @@ invalidate_from_clobbers (w, x)
{
if (GET_CODE (ref) == REG || GET_CODE (ref) == SUBREG
|| (GET_CODE (ref) == MEM && !w->all))
- invalidate (ref);
+ invalidate (ref, VOIDmode);
else if (GET_CODE (ref) == STRICT_LOW_PART
|| GET_CODE (ref) == ZERO_EXTRACT)
- invalidate (XEXP (ref, 0));
+ invalidate (XEXP (ref, 0), GET_MODE (ref));
}
}
}
@@ -7537,11 +7620,12 @@ cse_around_loop (loop_start)
for (p = last_jump_equiv_class->first_same_value; p;
p = p->next_same_value)
if (GET_CODE (p->exp) == MEM || GET_CODE (p->exp) == REG
- || GET_CODE (p->exp) == SUBREG)
- invalidate (p->exp);
+ || (GET_CODE (p->exp) == SUBREG
+ && GET_CODE (SUBREG_REG (p->exp)) == REG))
+ invalidate (p->exp, VOIDmode);
else if (GET_CODE (p->exp) == STRICT_LOW_PART
|| GET_CODE (p->exp) == ZERO_EXTRACT)
- invalidate (XEXP (p->exp, 0));
+ invalidate (XEXP (p->exp, 0), GET_MODE (p->exp));
/* Process insns starting after LOOP_START until we hit a CALL_INSN or
a CODE_LABEL (we could handle a CALL_INSN, but it isn't worth it).
@@ -7600,10 +7684,10 @@ invalidate_skipped_set (dest, set)
if (GET_CODE (dest) == REG || GET_CODE (dest) == SUBREG
|| (! skipped_writes_memory.all && ! cse_rtx_addr_varies_p (dest)))
- invalidate (dest);
+ invalidate (dest, VOIDmode);
else if (GET_CODE (dest) == STRICT_LOW_PART
|| GET_CODE (dest) == ZERO_EXTRACT)
- invalidate (XEXP (dest, 0));
+ invalidate (XEXP (dest, 0), GET_MODE (dest));
}
/* Invalidate all insns from START up to the end of the function or the
@@ -7755,10 +7839,10 @@ cse_set_around_loop (x, insn, loop_start)
if (GET_CODE (SET_DEST (x)) == REG || GET_CODE (SET_DEST (x)) == SUBREG
|| (GET_CODE (SET_DEST (x)) == MEM && ! writes_memory.all
&& ! cse_rtx_addr_varies_p (SET_DEST (x))))
- invalidate (SET_DEST (x));
+ invalidate (SET_DEST (x), VOIDmode);
else if (GET_CODE (SET_DEST (x)) == STRICT_LOW_PART
|| GET_CODE (SET_DEST (x)) == ZERO_EXTRACT)
- invalidate (XEXP (SET_DEST (x), 0));
+ invalidate (XEXP (SET_DEST (x), 0), GET_MODE (SET_DEST (x)));
}
/* Find the end of INSN's basic block and return its range,
@@ -7840,7 +7924,7 @@ cse_end_of_basic_block (insn, data, follow_jumps, after_loop, skip_blocks)
nsets += XVECLEN (PATTERN (p), 0);
else if (GET_CODE (p) != NOTE)
nsets += 1;
-
+
/* Ignore insns made by CSE; they cannot affect the boundaries of
the basic block. */
@@ -7855,7 +7939,7 @@ cse_end_of_basic_block (insn, data, follow_jumps, after_loop, skip_blocks)
{
if (data->path[path_entry].status != NOT_TAKEN)
p = JUMP_LABEL (p);
-
+
/* Point to next entry in path, if any. */
path_entry++;
}
@@ -7940,7 +8024,7 @@ cse_end_of_basic_block (insn, data, follow_jumps, after_loop, skip_blocks)
for (tmp = NEXT_INSN (p); tmp && tmp != q; tmp = NEXT_INSN (tmp))
if (GET_CODE (tmp) == CODE_LABEL)
break;
-
+
if (tmp == q)
{
data->path[path_entry].branch = p;
@@ -8108,7 +8192,7 @@ cse_main (f, nregs, after_loop, file)
cse_basic_block_start = val.low_cuid;
cse_basic_block_end = val.high_cuid;
max_qty = val.nsets * 2;
-
+
if (file)
fprintf (file, ";; Processing block from %d to %d, %d sets.\n",
INSN_UID (insn), val.last ? INSN_UID (val.last) : 0,
@@ -8229,7 +8313,7 @@ cse_basic_block (from, to, next_branch, around_loop)
continue;
}
}
-
+
code = GET_CODE (insn);
if (GET_MODE (insn) == QImode)
PUT_MODE (insn, VOIDmode);
@@ -8272,7 +8356,7 @@ cse_basic_block (from, to, next_branch, around_loop)
/* Maybe TO was deleted because the jump is unconditional.
If so, there is nothing left in this basic block. */
/* ??? Perhaps it would be smarter to set TO
- to whatever follows this insn,
+ to whatever follows this insn,
and pretend the basic block had always ended here. */
if (INSN_DELETED_P (to))
break;
@@ -8352,9 +8436,9 @@ cse_basic_block (from, to, next_branch, around_loop)
/* Count the number of times registers are used (not set) in X.
COUNTS is an array in which we accumulate the count, INCR is how much
- we count each register usage.
+ we count each register usage.
- Don't count a usage of DEST, which is the SET_DEST of a SET which
+ Don't count a usage of DEST, which is the SET_DEST of a SET which
contains X in its SET_SRC. This is because such a SET does not
modify the liveness of DEST. */
diff --git a/gnu/usr.bin/cc/cc_int/dbxout.c b/gnu/usr.bin/cc/cc_int/dbxout.c
index d34497d..86f614c 100644
--- a/gnu/usr.bin/cc/cc_int/dbxout.c
+++ b/gnu/usr.bin/cc/cc_int/dbxout.c
@@ -440,7 +440,7 @@ dbxout_init (asm_file, input_file_name, syms)
/* Used to put `Ltext:' before the reference, but that loses on sun 4. */
fprintf (asmfile, "%s ", ASM_STABS_OP);
output_quoted_string (asmfile, input_file_name);
- fprintf (asmfile, ",%d,0,0,%s\n",
+ fprintf (asmfile, ",%d,0,0,%s\n",
N_SO, &ltext_label_name[1]);
text_section ();
ASM_OUTPUT_INTERNAL_LABEL (asmfile, "Ltext", 0);
@@ -526,7 +526,7 @@ dbxout_source_file (file, filename)
}
}
-/* Output a line number symbol entry into output stream FILE,
+/* Output a line number symbol entry into output stream FILE,
for source file FILENAME and line number LINENO. */
void
@@ -889,12 +889,12 @@ dbxout_range_type (type)
fprintf (asmfile, "%d", TYPE_SYMTAB_ADDRESS (integer_type_node));
}
if (TREE_CODE (TYPE_MIN_VALUE (type)) == INTEGER_CST)
- fprintf (asmfile, ";%d",
+ fprintf (asmfile, ";%d",
TREE_INT_CST_LOW (TYPE_MIN_VALUE (type)));
else
fprintf (asmfile, ";0");
if (TREE_CODE (TYPE_MAX_VALUE (type)) == INTEGER_CST)
- fprintf (asmfile, ";%d;",
+ fprintf (asmfile, ";%d;",
TREE_INT_CST_LOW (TYPE_MAX_VALUE (type)));
else
fprintf (asmfile, ";-1;");
@@ -1615,7 +1615,7 @@ dbxout_symbol (decl, local)
&& !TREE_ASM_WRITTEN (TYPE_NAME (type))
/* Distinguish the implicit typedefs of C++
from explicit ones that might be found in C. */
- && (!strcmp (lang_identify (), "cplusplus")
+ && (!strcmp (lang_identify (), "cplusplus")
/* The following line maybe unnecessary;
in 2.6, try removing it. */
|| DECL_SOURCE_LINE (decl) == 0))
@@ -1665,7 +1665,7 @@ dbxout_symbol (decl, local)
}
/* Don't output a tag if this is an incomplete type (TYPE_SIZE is
- zero). This prevents the sun4 Sun OS 4.x dbx from crashing. */
+ zero). This prevents the sun4 Sun OS 4.x dbx from crashing. */
if (tag_needed && TYPE_NAME (type) != 0 && TYPE_SIZE (type) != 0
&& !TREE_ASM_WRITTEN (TYPE_NAME (type)))
@@ -1787,7 +1787,7 @@ dbxout_symbol_location (decl, type, suffix, home)
/* Don't mention a variable at all
if it was completely optimized into nothingness.
-
+
If the decl was from an inline function, then it's rtl
is not identically the rtl that was used in this
particular compilation. */
@@ -1843,7 +1843,13 @@ dbxout_symbol_location (decl, type, suffix, home)
letter = decl_function_context (decl) ? 'V' : 'S';
- if (!DECL_INITIAL (decl))
+ /* This should be the same condition as in assemble_variable, but
+ we don't have access to dont_output_data here. So, instead,
+ we rely on the fact that error_mark_node initializers always
+ end up in bss for C++ and never end up in bss for C. */
+ if (DECL_INITIAL (decl) == 0
+ || (!strcmp (lang_identify (), "cplusplus")
+ && DECL_INITIAL (decl) == error_mark_node))
current_sym_code = N_LCSYM;
else if (DECL_IN_TEXT_SECTION (decl))
/* This is not quite right, but it's the closest
diff --git a/gnu/usr.bin/cc/cc_int/dwarfout.c b/gnu/usr.bin/cc/cc_int/dwarfout.c
index a48c9b97..c16f204 100644
--- a/gnu/usr.bin/cc/cc_int/dwarfout.c
+++ b/gnu/usr.bin/cc/cc_int/dwarfout.c
@@ -4006,7 +4006,7 @@ output_type (type, containing_scope)
end_sibling_chain ();
break;
- case ARRAY_TYPE:
+ case ARRAY_TYPE:
if (TYPE_STRING_FLAG (type) && TREE_CODE(TREE_TYPE(type)) == CHAR_TYPE)
{
output_type (TREE_TYPE (type), containing_scope);
@@ -4435,118 +4435,91 @@ output_decl (decl, containing_scope)
output_formal_types (TREE_TYPE (decl));
else
{
+ /* Generate DIEs to represent all known formal parameters */
+
register tree arg_decls = DECL_ARGUMENTS (decl);
+ register tree parm;
+
+ /* WARNING! Kludge zone ahead! Here we have a special
+ hack for svr4 SDB compatibility. Instead of passing the
+ current FUNCTION_DECL node as the second parameter (i.e.
+ the `containing_scope' parameter) to `output_decl' (as
+ we ought to) we instead pass a pointer to our own private
+ fake_containing_scope node. That node is a RECORD_TYPE
+ node which NO OTHER TYPE may ever actually be a member of.
+
+ This pointer will ultimately get passed into `output_type'
+ as its `containing_scope' parameter. `Output_type' will
+ then perform its part in the hack... i.e. it will pend
+ the type of the formal parameter onto the pending_types
+ list. Later on, when we are done generating the whole
+ sequence of formal parameter DIEs for this function
+ definition, we will un-pend all previously pended types
+ of formal parameters for this function definition.
+
+ This whole kludge prevents any type DIEs from being
+ mixed in with the formal parameter DIEs. That's good
+ because svr4 SDB believes that the list of formal
+ parameter DIEs for a function ends wherever the first
+ non-formal-parameter DIE appears. Thus, we have to
+ keep the formal parameter DIEs segregated. They must
+ all appear (consecutively) at the start of the list of
+ children for the DIE representing the function definition.
+ Then (and only then) may we output any additional DIEs
+ needed to represent the types of these formal parameters.
+ */
- {
- register tree last_arg;
+ /*
+ When generating DIEs, generate the unspecified_parameters
+ DIE instead if we come across the arg "__builtin_va_alist"
+ */
- last_arg = (arg_decls && TREE_CODE (arg_decls) != ERROR_MARK)
- ? tree_last (arg_decls)
- : NULL;
+ for (parm = arg_decls; parm; parm = TREE_CHAIN (parm))
+ if (TREE_CODE (parm) == PARM_DECL)
+ {
+ if (DECL_NAME(parm) &&
+ !strcmp(IDENTIFIER_POINTER(DECL_NAME(parm)),
+ "__builtin_va_alist") )
+ output_die (output_unspecified_parameters_die, decl);
+ else
+ output_decl (parm, fake_containing_scope);
+ }
- /* Generate DIEs to represent all known formal parameters, but
- don't do it if this looks like a varargs function. A given
- function is considered to be a varargs function if (and only
- if) its last named argument is named `__builtin_va_alist'. */
+ /*
+ Now that we have finished generating all of the DIEs to
+ represent the formal parameters themselves, force out
+ any DIEs needed to represent their types. We do this
+ simply by un-pending all previously pended types which
+ can legitimately go into the chain of children DIEs for
+ the current FUNCTION_DECL.
+ */
- if (! last_arg
- || ! DECL_NAME (last_arg)
- || strcmp (IDENTIFIER_POINTER (DECL_NAME (last_arg)),
- "__builtin_va_alist"))
- {
- register tree parm;
-
- /* WARNING! Kludge zone ahead! Here we have a special
- hack for svr4 SDB compatibility. Instead of passing the
- current FUNCTION_DECL node as the second parameter (i.e.
- the `containing_scope' parameter) to `output_decl' (as
- we ought to) we instead pass a pointer to our own private
- fake_containing_scope node. That node is a RECORD_TYPE
- node which NO OTHER TYPE may ever actually be a member of.
-
- This pointer will ultimately get passed into `output_type'
- as its `containing_scope' parameter. `Output_type' will
- then perform its part in the hack... i.e. it will pend
- the type of the formal parameter onto the pending_types
- list. Later on, when we are done generating the whole
- sequence of formal parameter DIEs for this function
- definition, we will un-pend all previously pended types
- of formal parameters for this function definition.
-
- This whole kludge prevents any type DIEs from being
- mixed in with the formal parameter DIEs. That's good
- because svr4 SDB believes that the list of formal
- parameter DIEs for a function ends wherever the first
- non-formal-parameter DIE appears. Thus, we have to
- keep the formal parameter DIEs segregated. They must
- all appear (consecutively) at the start of the list of
- children for the DIE representing the function definition.
- Then (and only then) may we output any additional DIEs
- needed to represent the types of these formal parameters.
- */
-
- for (parm = arg_decls; parm; parm = TREE_CHAIN (parm))
- if (TREE_CODE (parm) == PARM_DECL)
- output_decl (parm, fake_containing_scope);
-
- /* Now that we have finished generating all of the DIEs to
- represent the formal parameters themselves, force out
- any DIEs needed to represent their types. We do this
- simply by un-pending all previously pended types which
- can legitimately go into the chain of children DIEs for
- the current FUNCTION_DECL. */
-
- output_pending_types_for_scope (decl);
- }
- }
+ output_pending_types_for_scope (decl);
- /* Now try to decide if we should put an ellipsis at the end. */
+ /*
+ Decide whether we need a unspecified_parameters DIE at the end.
+ There are 2 more cases to do this for:
+ 1) the ansi ... declaration - this is detectable when the end
+ of the arg list is not a void_type_node
+ 2) an unprototyped function declaration (not a definition). This
+ just means that we have no info about the parameters at all.
+ */
{
- register int has_ellipsis = TRUE; /* default assumption */
register tree fn_arg_types = TYPE_ARG_TYPES (TREE_TYPE (decl));
if (fn_arg_types)
{
- /* This function declaration/definition was prototyped. */
-
- /* If the list of formal argument types ends with a
- void_type_node, then the formals list did *not* end
- with an ellipsis. */
-
- if (TREE_VALUE (tree_last (fn_arg_types)) == void_type_node)
- has_ellipsis = FALSE;
- }
- else
- {
- /* This function declaration/definition was not prototyped. */
-
- /* Note that all non-prototyped function *declarations* are
- assumed to represent varargs functions (until proven
- otherwise). */
-
- if (DECL_INITIAL (decl)) /* if this is a func definition */
- {
- if (!arg_decls)
- has_ellipsis = FALSE; /* no args == (void) */
- else
- {
- /* For a non-prototyped function definition which
- declares one or more formal parameters, if the name
- of the first formal parameter is *not*
- __builtin_va_alist then we must assume that this
- is *not* a varargs function. */
-
- if (DECL_NAME (arg_decls)
- && strcmp (IDENTIFIER_POINTER (DECL_NAME (arg_decls)),
- "__builtin_va_alist"))
- has_ellipsis = FALSE;
- }
- }
- }
-
- if (has_ellipsis)
- output_die (output_unspecified_parameters_die, decl);
+ /* this is the prototyped case, check for ... */
+ if (TREE_VALUE (tree_last (fn_arg_types)) != void_type_node)
+ output_die (output_unspecified_parameters_die, decl);
+ }
+ else
+ {
+ /* this is unprotoyped, check for undefined (just declaration) */
+ if (!DECL_INITIAL (decl))
+ output_die (output_unspecified_parameters_die, decl);
+ }
}
}
@@ -4870,7 +4843,7 @@ dwarfout_file_scope_decl (decl, set_finalizing)
ASM_OUTPUT_PUSH_SECTION (asm_out_file, ARANGES_SECTION);
ASM_OUTPUT_DWARF_ADDR (asm_out_file,
IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)));
- ASM_OUTPUT_DWARF_DATA4 (asm_out_file,
+ ASM_OUTPUT_DWARF_DATA4 (asm_out_file,
(unsigned) int_size_in_bytes (TREE_TYPE (decl)));
ASM_OUTPUT_POP_SECTION (asm_out_file);
}
@@ -5390,7 +5363,7 @@ dwarfout_init (asm_out_file, main_input_filename)
/* Output a starting label and an initial (compilation directory)
entry for the .debug_sfnames section. The starting label will be
referenced by the initial entry in the .debug_srcinfo section. */
-
+
fputc ('\n', asm_out_file);
ASM_OUTPUT_PUSH_SECTION (asm_out_file, SFNAMES_SECTION);
ASM_OUTPUT_LABEL (asm_out_file, SFNAMES_BEGIN_LABEL);
@@ -5404,20 +5377,20 @@ dwarfout_init (asm_out_file, main_input_filename)
pfatal_with_name ("getpwd");
len = strlen (pwd);
dirname = (char *) xmalloc (len + 2);
-
+
strcpy (dirname, pwd);
strcpy (dirname + len, "/");
ASM_OUTPUT_DWARF_STRING (asm_out_file, dirname);
free (dirname);
}
ASM_OUTPUT_POP_SECTION (asm_out_file);
-
+
if (debug_info_level >= DINFO_LEVEL_VERBOSE)
{
/* Output a starting label for the .debug_macinfo section. This
label will be referenced by the AT_mac_info attribute in the
TAG_compile_unit DIE. */
-
+
fputc ('\n', asm_out_file);
ASM_OUTPUT_PUSH_SECTION (asm_out_file, MACINFO_SECTION);
ASM_OUTPUT_LABEL (asm_out_file, MACINFO_BEGIN_LABEL);
@@ -5425,16 +5398,16 @@ dwarfout_init (asm_out_file, main_input_filename)
}
/* Generate the initial entry for the .line section. */
-
+
fputc ('\n', asm_out_file);
ASM_OUTPUT_PUSH_SECTION (asm_out_file, LINE_SECTION);
ASM_OUTPUT_LABEL (asm_out_file, LINE_BEGIN_LABEL);
ASM_OUTPUT_DWARF_DELTA4 (asm_out_file, LINE_END_LABEL, LINE_BEGIN_LABEL);
ASM_OUTPUT_DWARF_ADDR (asm_out_file, TEXT_BEGIN_LABEL);
ASM_OUTPUT_POP_SECTION (asm_out_file);
-
+
/* Generate the initial entry for the .debug_srcinfo section. */
-
+
fputc ('\n', asm_out_file);
ASM_OUTPUT_PUSH_SECTION (asm_out_file, SRCINFO_SECTION);
ASM_OUTPUT_LABEL (asm_out_file, SRCINFO_BEGIN_LABEL);
@@ -5448,16 +5421,16 @@ dwarfout_init (asm_out_file, main_input_filename)
ASM_OUTPUT_DWARF_DATA4 (asm_out_file, -1);
#endif
ASM_OUTPUT_POP_SECTION (asm_out_file);
-
+
/* Generate the initial entry for the .debug_pubnames section. */
-
+
fputc ('\n', asm_out_file);
ASM_OUTPUT_PUSH_SECTION (asm_out_file, PUBNAMES_SECTION);
ASM_OUTPUT_DWARF_ADDR (asm_out_file, DEBUG_BEGIN_LABEL);
ASM_OUTPUT_POP_SECTION (asm_out_file);
-
+
/* Generate the initial entry for the .debug_aranges section. */
-
+
fputc ('\n', asm_out_file);
ASM_OUTPUT_PUSH_SECTION (asm_out_file, ARANGES_SECTION);
ASM_OUTPUT_DWARF_ADDR (asm_out_file, DEBUG_BEGIN_LABEL);
@@ -5575,7 +5548,7 @@ dwarfout_finish ()
if (debug_info_level >= DINFO_LEVEL_NORMAL)
{
/* Output a terminating entry for the .line section. */
-
+
fputc ('\n', asm_out_file);
ASM_OUTPUT_PUSH_SECTION (asm_out_file, LINE_SECTION);
ASM_OUTPUT_LABEL (asm_out_file, LINE_LAST_ENTRY_LABEL);
@@ -5584,9 +5557,9 @@ dwarfout_finish ()
ASM_OUTPUT_DWARF_DELTA4 (asm_out_file, TEXT_END_LABEL, TEXT_BEGIN_LABEL);
ASM_OUTPUT_LABEL (asm_out_file, LINE_END_LABEL);
ASM_OUTPUT_POP_SECTION (asm_out_file);
-
+
/* Output a terminating entry for the .debug_srcinfo section. */
-
+
fputc ('\n', asm_out_file);
ASM_OUTPUT_PUSH_SECTION (asm_out_file, SRCINFO_SECTION);
ASM_OUTPUT_DWARF_DELTA4 (asm_out_file,
@@ -5597,7 +5570,7 @@ dwarfout_finish ()
if (debug_info_level >= DINFO_LEVEL_VERBOSE)
{
/* Output terminating entries for the .debug_macinfo section. */
-
+
dwarfout_resume_previous_source_file (0);
fputc ('\n', asm_out_file);
@@ -5606,15 +5579,15 @@ dwarfout_finish ()
ASM_OUTPUT_DWARF_STRING (asm_out_file, "");
ASM_OUTPUT_POP_SECTION (asm_out_file);
}
-
+
/* Generate the terminating entry for the .debug_pubnames section. */
-
+
fputc ('\n', asm_out_file);
ASM_OUTPUT_PUSH_SECTION (asm_out_file, PUBNAMES_SECTION);
ASM_OUTPUT_DWARF_DATA4 (asm_out_file, 0);
ASM_OUTPUT_DWARF_STRING (asm_out_file, "");
ASM_OUTPUT_POP_SECTION (asm_out_file);
-
+
/* Generate the terminating entries for the .debug_aranges section.
Note that we want to do this only *after* we have output the end
@@ -5628,7 +5601,7 @@ dwarfout_finish ()
entries at this late point in the assembly output, we skirt the
issue simply by avoiding forward-references.
*/
-
+
fputc ('\n', asm_out_file);
ASM_OUTPUT_PUSH_SECTION (asm_out_file, ARANGES_SECTION);
diff --git a/gnu/usr.bin/cc/cc_int/emit-rtl.c b/gnu/usr.bin/cc/cc_int/emit-rtl.c
index 3afcccb..9de163c 100644
--- a/gnu/usr.bin/cc/cc_int/emit-rtl.c
+++ b/gnu/usr.bin/cc/cc_int/emit-rtl.c
@@ -140,7 +140,7 @@ REAL_VALUE_TYPE dconstm1;
When to use frame_pointer_rtx and hard_frame_pointer_rtx is a little
tricky: until register elimination has taken place hard_frame_pointer_rtx
- should be used if it is being set, and frame_pointer_rtx otherwise. After
+ should be used if it is being set, and frame_pointer_rtx otherwise. After
register elimination hard_frame_pointer_rtx should always be used.
On machines where the two registers are same (most) then these are the
same.
@@ -173,7 +173,7 @@ static rtx const_int_rtx[MAX_SAVED_CONST_INT * 2 + 1];
/* The ends of the doubly-linked chain of rtl for the current function.
Both are reset to null at the start of rtl generation for the function.
-
+
start_sequence saves both of these on `sequence_stack' along with
`sequence_rtl_expr' and then starts a new, nested sequence of insns. */
@@ -552,7 +552,7 @@ get_first_label_num ()
/* Return a value representing some low-order bits of X, where the number
of low-order bits is given by MODE. Note that no conversion is done
- between floating-point and fixed-point values, rather, the bit
+ between floating-point and fixed-point values, rather, the bit
representation is returned.
This function handles the cases in common between gen_lowpart, below,
@@ -611,7 +611,7 @@ gen_lowpart_common (mode, x)
else if (GET_CODE (x) == REG)
{
/* If the register is not valid for MODE, return 0. If we don't
- do this, there is no way to fix up the resulting REG later.
+ do this, there is no way to fix up the resulting REG later.
But we do do this if the current REG is not valid for its
mode. This latter is a kludge, but is required due to the
way that parameters are passed on some machines, most
@@ -650,7 +650,7 @@ gen_lowpart_common (mode, x)
either a reasonable negative value or a reasonable unsigned value
for this mode. */
- if (GET_MODE_BITSIZE (mode) == 2 * HOST_BITS_PER_WIDE_INT)
+ if (GET_MODE_BITSIZE (mode) >= 2 * HOST_BITS_PER_WIDE_INT)
return x;
else if (GET_MODE_BITSIZE (mode) > HOST_BITS_PER_WIDE_INT)
return 0;
@@ -676,7 +676,7 @@ gen_lowpart_common (mode, x)
/* If X is an integral constant but we want it in floating-point, it
must be the case that we have a union of an integer and a floating-point
value. If the machine-parameters allow it, simulate that union here
- and return the result. The two-word and single-word cases are
+ and return the result. The two-word and single-word cases are
different. */
else if (((HOST_FLOAT_FORMAT == TARGET_FLOAT_FORMAT
@@ -875,7 +875,7 @@ gen_lowpart (mode, x)
abort ();
}
-/* Like `gen_lowpart', but refer to the most significant part.
+/* Like `gen_lowpart', but refer to the most significant part.
This is used to access the imaginary part of a complex number. */
rtx
@@ -1162,10 +1162,10 @@ operand_subword (op, i, validate_address, mode)
return GEN_INT (u.i);
}
#endif /* no REAL_ARITHMETIC */
-
+
/* The only remaining cases that we can handle are integers.
Convert to proper endianness now since these cases need it.
- At this point, i == 0 means the low-order word.
+ At this point, i == 0 means the low-order word.
We do not want to handle the case when BITS_PER_WORD <= HOST_BITS_PER_INT
in general. However, if OP is (const_int 0), we can just return
@@ -1176,7 +1176,7 @@ operand_subword (op, i, validate_address, mode)
if (GET_MODE_CLASS (mode) != MODE_INT
|| (GET_CODE (op) != CONST_INT && GET_CODE (op) != CONST_DOUBLE)
- || BITS_PER_WORD > HOST_BITS_PER_INT)
+ || BITS_PER_WORD > HOST_BITS_PER_WIDE_INT)
return 0;
if (WORDS_BIG_ENDIAN)
@@ -1202,7 +1202,7 @@ operand_subword (op, i, validate_address, mode)
the required subword, put OP into a register and try again. If that fails,
abort. We always validate the address in this case. It is not valid
to call this function after reload; it is mostly meant for RTL
- generation.
+ generation.
MODE is the mode of OP, in case it is CONST_INT. */
@@ -1289,7 +1289,7 @@ change_address (memref, mode, addr)
}
else
addr = memory_address (mode, addr);
-
+
new = gen_rtx (MEM, mode, addr);
MEM_VOLATILE_P (new) = MEM_VOLATILE_P (memref);
RTX_UNCHANGING_P (new) = RTX_UNCHANGING_P (memref);
@@ -2130,9 +2130,10 @@ add_insn (insn)
last_insn = insn;
}
-/* Add INSN into the doubly-linked list after insn AFTER. This should be the
- only function called to insert an insn once delay slots have been filled
- since only it knows how to update a SEQUENCE. */
+/* Add INSN into the doubly-linked list after insn AFTER. This and
+ the next should be the only functions called to insert an insn once
+ delay slots have been filled since only they know how to update a
+ SEQUENCE. */
void
add_insn_after (insn, after)
@@ -2140,6 +2141,9 @@ add_insn_after (insn, after)
{
rtx next = NEXT_INSN (after);
+ if (optimize && INSN_DELETED_P (after))
+ abort ();
+
NEXT_INSN (insn) = next;
PREV_INSN (insn) = after;
@@ -2157,7 +2161,13 @@ add_insn_after (insn, after)
/* Scan all pending sequences too. */
for (; stack; stack = stack->next)
if (after == stack->last)
- stack->last = insn;
+ {
+ stack->last = insn;
+ break;
+ }
+
+ if (stack == 0)
+ abort ();
}
NEXT_INSN (after) = insn;
@@ -2168,6 +2178,54 @@ add_insn_after (insn, after)
}
}
+/* Add INSN into the doubly-linked list before insn BEFORE. This and
+ the previous should be the only functions called to insert an insn once
+ delay slots have been filled since only they know how to update a
+ SEQUENCE. */
+
+void
+add_insn_before (insn, before)
+ rtx insn, before;
+{
+ rtx prev = PREV_INSN (before);
+
+ if (optimize && INSN_DELETED_P (before))
+ abort ();
+
+ PREV_INSN (insn) = prev;
+ NEXT_INSN (insn) = before;
+
+ if (prev)
+ {
+ NEXT_INSN (prev) = insn;
+ if (GET_CODE (prev) == INSN && GET_CODE (PATTERN (prev)) == SEQUENCE)
+ {
+ rtx sequence = PATTERN (prev);
+ NEXT_INSN (XVECEXP (sequence, 0, XVECLEN (sequence, 0) - 1)) = insn;
+ }
+ }
+ else if (first_insn == before)
+ first_insn = insn;
+ else
+ {
+ struct sequence_stack *stack = sequence_stack;
+ /* Scan all pending sequences too. */
+ for (; stack; stack = stack->next)
+ if (before == stack->first)
+ {
+ stack->first = insn;
+ break;
+ }
+
+ if (stack == 0)
+ abort ();
+ }
+
+ PREV_INSN (before) = insn;
+ if (GET_CODE (before) == INSN && GET_CODE (PATTERN (before)) == SEQUENCE)
+ PREV_INSN (XVECEXP (PATTERN (before), 0, 0)) = insn;
+}
+
/* Delete all insns made since FROM.
FROM becomes the new last instruction. */
@@ -2279,7 +2337,7 @@ emit_insn_before (pattern, before)
for (i = 0; i < XVECLEN (pattern, 0); i++)
{
insn = XVECEXP (pattern, 0, i);
- add_insn_after (insn, PREV_INSN (before));
+ add_insn_before (insn, before);
}
if (XVECLEN (pattern, 0) < SEQUENCE_RESULT_SIZE)
sequence_result[XVECLEN (pattern, 0)] = pattern;
@@ -2287,7 +2345,7 @@ emit_insn_before (pattern, before)
else
{
insn = make_insn_raw (pattern);
- add_insn_after (insn, PREV_INSN (before));
+ add_insn_before (insn, before);
}
return insn;
@@ -2307,7 +2365,7 @@ emit_jump_insn_before (pattern, before)
else
{
insn = make_jump_insn_raw (pattern);
- add_insn_after (insn, PREV_INSN (before));
+ add_insn_before (insn, before);
}
return insn;
@@ -2327,7 +2385,7 @@ emit_call_insn_before (pattern, before)
else
{
insn = make_call_insn_raw (pattern);
- add_insn_after (insn, PREV_INSN (before));
+ add_insn_before (insn, before);
PUT_CODE (insn, CALL_INSN);
}
@@ -2345,7 +2403,7 @@ emit_barrier_before (before)
INSN_UID (insn) = cur_insn_uid++;
- add_insn_after (insn, PREV_INSN (before));
+ add_insn_before (insn, before);
return insn;
}
@@ -2361,7 +2419,7 @@ emit_note_before (subtype, before)
NOTE_SOURCE_FILE (note) = 0;
NOTE_LINE_NUMBER (note) = subtype;
- add_insn_after (note, PREV_INSN (before));
+ add_insn_before (note, before);
return note;
}
@@ -2577,7 +2635,7 @@ emit_insns_before (insn, before)
while (insn)
{
rtx next = NEXT_INSN (insn);
- add_insn_after (insn, PREV_INSN (before));
+ add_insn_before (insn, before);
last = insn;
insn = next;
}
@@ -2856,7 +2914,7 @@ start_sequence ()
last_insn = 0;
}
-/* Similarly, but indicate that this sequence will be placed in
+/* Similarly, but indicate that this sequence will be placed in
T, an RTL_EXPR. */
void
@@ -3037,7 +3095,7 @@ restore_reg_data (first)
/* Don't duplicate the uids already in use. */
cur_insn_uid = max_uid + 1;
- /* If any regs are missing, make them up.
+ /* If any regs are missing, make them up.
??? word_mode is not necessarily the right mode. Most likely these REGs
are never used. At some point this should be checked. */
@@ -3163,11 +3221,11 @@ init_emit ()
regno_pointer_flag_length = LAST_VIRTUAL_REGISTER + 101;
- regno_pointer_flag
+ regno_pointer_flag
= (char *) oballoc (regno_pointer_flag_length);
bzero (regno_pointer_flag, regno_pointer_flag_length);
- regno_reg_rtx
+ regno_reg_rtx
= (rtx *) oballoc (regno_pointer_flag_length * sizeof (rtx));
bzero ((char *) regno_reg_rtx, regno_pointer_flag_length * sizeof (rtx));
@@ -3293,7 +3351,7 @@ init_emit_once (line_numbers)
hard_frame_pointer_rtx = frame_pointer_rtx;
else
hard_frame_pointer_rtx = gen_rtx (REG, Pmode, HARD_FRAME_POINTER_REGNUM);
-
+
if (FRAME_POINTER_REGNUM == ARG_POINTER_REGNUM)
arg_pointer_rtx = frame_pointer_rtx;
else if (HARD_FRAME_POINTER_REGNUM == ARG_POINTER_REGNUM)
diff --git a/gnu/usr.bin/cc/cc_int/explow.c b/gnu/usr.bin/cc/cc_int/explow.c
index b72e468..f32c5ad 100644
--- a/gnu/usr.bin/cc/cc_int/explow.c
+++ b/gnu/usr.bin/cc/cc_int/explow.c
@@ -101,7 +101,7 @@ plus_constant_wide (x, c)
Look for constant term in the sum and combine
with C. For an integer constant term, we make a combined
integer. For a constant term that is not an explicit integer,
- we cannot really combine, but group them together anyway.
+ we cannot really combine, but group them together anyway.
Use a recursive call in case the remaining operand is something
that we handle specially, such as a SYMBOL_REF. */
@@ -521,12 +521,12 @@ copy_to_reg (x)
rtx x;
{
register rtx temp = gen_reg_rtx (GET_MODE (x));
-
+
/* If not an operand, must be an address with PLUS and MULT so
- do the computation. */
+ do the computation. */
if (! general_operand (x, VOIDmode))
x = force_operand (x, temp);
-
+
if (x != temp)
emit_move_insn (temp, x);
@@ -552,9 +552,9 @@ copy_to_mode_reg (mode, x)
rtx x;
{
register rtx temp = gen_reg_rtx (mode);
-
+
/* If not an operand, must be an address with PLUS and MULT so
- do the computation. */
+ do the computation. */
if (! general_operand (x, VOIDmode))
x = force_operand (x, temp);
@@ -851,9 +851,9 @@ emit_stack_save (save_level, psave, after)
}
/* Restore the stack pointer for the purpose in SAVE_LEVEL. SA is the save
- area made by emit_stack_save. If it is zero, we have nothing to do.
+ area made by emit_stack_save. If it is zero, we have nothing to do.
- Put any emitted insns after insn AFTER, if nonzero, otherwise at
+ Put any emitted insns after insn AFTER, if nonzero, otherwise at
current position. */
void
@@ -938,7 +938,7 @@ allocate_dynamic_stack_space (size, target, known_align)
/* We will need to ensure that the address we return is aligned to
BIGGEST_ALIGNMENT. If STACK_DYNAMIC_OFFSET is defined, we don't
- always know its final value at this point in the compilation (it
+ always know its final value at this point in the compilation (it
might depend on the size of the outgoing parameter lists, for
example), so we must align the value to be returned in that case.
(Note that STACK_DYNAMIC_OFFSET will have a default non-zero value if
@@ -1074,7 +1074,7 @@ allocate_dynamic_stack_space (size, target, known_align)
NULL_RTX, 1);
}
#endif
-
+
/* Some systems require a particular insn to refer to the stack
to make the pages exist. */
#ifdef HAVE_probe
diff --git a/gnu/usr.bin/cc/cc_int/expmed.c b/gnu/usr.bin/cc/cc_int/expmed.c
index f3beae0..1b20377 100644
--- a/gnu/usr.bin/cc/cc_int/expmed.c
+++ b/gnu/usr.bin/cc/cc_int/expmed.c
@@ -43,7 +43,7 @@ static rtx extract_split_bit_field PROTO((rtx, int, int, int, int));
#define CEIL(x,y) (((x) + (y) - 1) / (y))
/* Non-zero means divides or modulus operations are relatively cheap for
- powers of two, so don't use branches; emit the operation instead.
+ powers of two, so don't use branches; emit the operation instead.
Usually, this will mean that the MD file will emit non-branch
sequences. */
@@ -299,7 +299,10 @@ store_bit_field (str_rtx, bitsize, bitnum, fieldmode, value, align, total_size)
/* Here we transfer the words of the field
in the order least significant first.
This is because the most significant word is the one which may
- be less than full. */
+ be less than full.
+ However, only do that if the value is not BLKmode. */
+
+ int backwards = WORDS_BIG_ENDIAN && fieldmode != BLKmode;
int nwords = (bitsize + (BITS_PER_WORD - 1)) / BITS_PER_WORD;
int i;
@@ -315,8 +318,8 @@ store_bit_field (str_rtx, bitsize, bitnum, fieldmode, value, align, total_size)
{
/* If I is 0, use the low-order word in both field and target;
if I is 1, use the next to lowest word; and so on. */
- int wordnum = (WORDS_BIG_ENDIAN ? nwords - i - 1 : i);
- int bit_offset = (WORDS_BIG_ENDIAN
+ int wordnum = (backwards ? nwords - i - 1 : i);
+ int bit_offset = (backwards
? MAX (bitsize - (i + 1) * BITS_PER_WORD, 0)
: i * BITS_PER_WORD);
store_bit_field (op0, MIN (BITS_PER_WORD,
@@ -369,7 +372,10 @@ store_bit_field (str_rtx, bitsize, bitnum, fieldmode, value, align, total_size)
&& !(bitsize == 1 && GET_CODE (value) == CONST_INT)
/* Ensure insv's size is wide enough for this field. */
&& (GET_MODE_BITSIZE (insn_operand_mode[(int) CODE_FOR_insv][3])
- >= bitsize))
+ >= bitsize)
+ && ! ((GET_CODE (op0) == REG || GET_CODE (op0) == SUBREG)
+ && (bitsize + bitpos
+ > GET_MODE_BITSIZE (insn_operand_mode[(int) CODE_FOR_insv][3]))))
{
int xbitpos = bitpos;
rtx value1;
@@ -415,7 +421,7 @@ store_bit_field (str_rtx, bitsize, bitnum, fieldmode, value, align, total_size)
/* Compute offset as multiple of this unit, counting in bytes. */
offset = (bitnum / unit) * GET_MODE_SIZE (bestmode);
bitpos = bitnum % unit;
- op0 = change_address (op0, bestmode,
+ op0 = change_address (op0, bestmode,
plus_constant (XEXP (op0, 0), offset));
/* Fetch that unit, store the bitfield in it, then store the unit. */
@@ -741,19 +747,13 @@ store_split_bit_field (op0, bitsize, bitpos, value, align)
>> (bitsize - bitsdone - thissize))
& (((HOST_WIDE_INT) 1 << thissize) - 1));
else
- {
- /* The args are chosen so that the last part
- includes the lsb. */
- int bit_offset = 0;
- /* If the value isn't in memory, then it must be right aligned
- if a register, so skip past the padding on the left. If it
- is in memory, then there is no padding on the left. */
- if (GET_CODE (value) != MEM)
- bit_offset = BITS_PER_WORD - bitsize;
- part = extract_fixed_bit_field (word_mode, value, 0, thissize,
- bit_offset + bitsdone,
- NULL_RTX, 1, align);
- }
+ /* The args are chosen so that the last part includes the lsb.
+ Give extract_bit_field the value it needs (with endianness
+ compensation) to fetch the piece we want. */
+ part = extract_fixed_bit_field (word_mode, value, 0, thissize,
+ GET_MODE_BITSIZE (GET_MODE (value))
+ - bitsize + bitsdone,
+ NULL_RTX, 1, align);
#else
/* Fetch successively more significant portions. */
if (GET_CODE (value) == CONST_INT)
@@ -849,7 +849,7 @@ extract_bit_field (str_rtx, bitsize, bitnum, unsignedp,
offset += SUBREG_WORD (op0);
op0 = SUBREG_REG (op0);
}
-
+
#if BYTES_BIG_ENDIAN
/* If OP0 is a register, BITPOS must count within a word.
But as we have it, it counts within whatever size OP0 now has.
@@ -896,7 +896,7 @@ extract_bit_field (str_rtx, bitsize, bitnum, unsignedp,
}
/* Handle fields bigger than a word. */
-
+
if (bitsize > BITS_PER_WORD)
{
/* Here we transfer the words of the field
@@ -943,7 +943,7 @@ extract_bit_field (str_rtx, bitsize, bitnum, unsignedp,
build_int_2 (GET_MODE_BITSIZE (mode) - bitsize, 0),
NULL_RTX, 0);
}
-
+
/* From here on we know the desired field is smaller than a word
so we can assume it is an integer. So we can safely extract it as one
size of integer, if necessary, and then truncate or extend
@@ -972,7 +972,10 @@ extract_bit_field (str_rtx, bitsize, bitnum, unsignedp,
#ifdef HAVE_extzv
if (HAVE_extzv
&& (GET_MODE_BITSIZE (insn_operand_mode[(int) CODE_FOR_extzv][0])
- >= bitsize))
+ >= bitsize)
+ && ! ((GET_CODE (op0) == REG || GET_CODE (op0) == SUBREG)
+ && (bitsize + bitpos
+ > GET_MODE_BITSIZE (insn_operand_mode[(int) CODE_FOR_extzv][0]))))
{
int xbitpos = bitpos, xoffset = offset;
rtx bitsize_rtx, bitpos_rtx;
@@ -1111,7 +1114,10 @@ extract_bit_field (str_rtx, bitsize, bitnum, unsignedp,
#ifdef HAVE_extv
if (HAVE_extv
&& (GET_MODE_BITSIZE (insn_operand_mode[(int) CODE_FOR_extv][0])
- >= bitsize))
+ >= bitsize)
+ && ! ((GET_CODE (op0) == REG || GET_CODE (op0) == SUBREG)
+ && (bitsize + bitpos
+ > GET_MODE_BITSIZE (insn_operand_mode[(int) CODE_FOR_extv][0]))))
{
int xbitpos = bitpos, xoffset = offset;
rtx bitsize_rtx, bitpos_rtx;
@@ -1232,7 +1238,7 @@ extract_bit_field (str_rtx, bitsize, bitnum, unsignedp,
target = extract_fixed_bit_field (tmode, op0, offset, bitsize,
bitpos, target, 0, align);
}
- }
+ }
else
extv_loses:
#endif
@@ -1416,7 +1422,7 @@ extract_fixed_bit_field (tmode, op0, offset, bitsize, bitpos,
}
return expand_shift (RSHIFT_EXPR, mode, op0,
- build_int_2 (GET_MODE_BITSIZE (mode) - bitsize, 0),
+ build_int_2 (GET_MODE_BITSIZE (mode) - bitsize, 0),
target, 0);
}
@@ -1440,7 +1446,7 @@ mask_rtx (mode, bitpos, bitsize, complement)
if (bitpos + bitsize < HOST_BITS_PER_WIDE_INT)
masklow &= ((unsigned HOST_WIDE_INT) -1
>> (HOST_BITS_PER_WIDE_INT - bitpos - bitsize));
-
+
if (bitpos <= HOST_BITS_PER_WIDE_INT)
maskhigh = -1;
else
@@ -1678,8 +1684,7 @@ expand_shift (code, mode, shifted, amount, target, unsignedp)
continue;
else if (methods == OPTAB_LIB_WIDEN)
{
- /* If we are rotating by a constant that is valid and
- we have been unable to open-code this by a rotation,
+ /* If we have been unable to open-code this by a rotation,
do it as the IOR of two shifts. I.e., to rotate A
by N bits, compute (A << N) | ((unsigned) A >> (C - N))
where C is the bitsize of A.
@@ -1691,25 +1696,25 @@ expand_shift (code, mode, shifted, amount, target, unsignedp)
this extremely unlikely lossage to avoid complicating the
code below. */
- if (GET_CODE (op1) == CONST_INT && INTVAL (op1) > 0
- && INTVAL (op1) < GET_MODE_BITSIZE (mode))
- {
- rtx subtarget = target == shifted ? 0 : target;
- rtx temp1;
- tree other_amount
- = build_int_2 (GET_MODE_BITSIZE (mode) - INTVAL (op1), 0);
-
- shifted = force_reg (mode, shifted);
-
- temp = expand_shift (left ? LSHIFT_EXPR : RSHIFT_EXPR,
- mode, shifted, amount, subtarget, 1);
- temp1 = expand_shift (left ? RSHIFT_EXPR : LSHIFT_EXPR,
- mode, shifted, other_amount, 0, 1);
- return expand_binop (mode, ior_optab, temp, temp1, target,
- unsignedp, methods);
- }
- else
- methods = OPTAB_LIB;
+ rtx subtarget = target == shifted ? 0 : target;
+ rtx temp1;
+ tree type = TREE_TYPE (amount);
+ tree new_amount = make_tree (type, op1);
+ tree other_amount
+ = fold (build (MINUS_EXPR, type,
+ convert (type,
+ build_int_2 (GET_MODE_BITSIZE (mode),
+ 0)),
+ amount));
+
+ shifted = force_reg (mode, shifted);
+
+ temp = expand_shift (left ? LSHIFT_EXPR : RSHIFT_EXPR,
+ mode, shifted, new_amount, subtarget, 1);
+ temp1 = expand_shift (left ? RSHIFT_EXPR : LSHIFT_EXPR,
+ mode, shifted, other_amount, 0, 1);
+ return expand_binop (mode, ior_optab, temp, temp1, target,
+ unsignedp, methods);
}
temp = expand_binop (mode,
@@ -1723,7 +1728,7 @@ expand_shift (code, mode, shifted, amount, target, unsignedp)
&& INTVAL (op1) > 0 && INTVAL (op1) < GET_MODE_BITSIZE (mode))
temp = expand_binop (mode,
left ? rotr_optab : rotl_optab,
- shifted,
+ shifted,
GEN_INT (GET_MODE_BITSIZE (mode)
- INTVAL (op1)),
target, unsignedp, methods);
@@ -1754,7 +1759,7 @@ expand_shift (code, mode, shifted, amount, target, unsignedp)
}
/* We used to try extzv here for logical right shifts, but that was
- only useful for one machine, the VAX, and caused poor code
+ only useful for one machine, the VAX, and caused poor code
generation there for lshrdi3, so the code was deleted and a
define_expand for lshrsi3 was added to vax.md. */
}
@@ -2053,23 +2058,31 @@ expand_mult (mode, op0, op1, target, unsignedp)
{
rtx const_op1 = op1;
+ /* synth_mult does an `unsigned int' multiply. As long as the mode is
+ less than or equal in size to `unsigned int' this doesn't matter.
+ If the mode is larger than `unsigned int', then synth_mult works only
+ if the constant value exactly fits in an `unsigned int' without any
+ truncation. This means that multiplying by negative values does
+ not work; results are off by 2^32 on a 32 bit machine. */
+
/* If we are multiplying in DImode, it may still be a win
to try to work with shifts and adds. */
if (GET_CODE (op1) == CONST_DOUBLE
&& GET_MODE_CLASS (GET_MODE (op1)) == MODE_INT
- && HOST_BITS_PER_INT <= BITS_PER_WORD)
- {
- if ((CONST_DOUBLE_HIGH (op1) == 0 && CONST_DOUBLE_LOW (op1) >= 0)
- || (CONST_DOUBLE_HIGH (op1) == -1 && CONST_DOUBLE_LOW (op1) < 0))
- const_op1 = GEN_INT (CONST_DOUBLE_LOW (op1));
- }
+ && HOST_BITS_PER_INT >= BITS_PER_WORD
+ && CONST_DOUBLE_HIGH (op1) == 0)
+ const_op1 = GEN_INT (CONST_DOUBLE_LOW (op1));
+ else if (HOST_BITS_PER_INT < GET_MODE_BITSIZE (mode)
+ && GET_CODE (op1) == CONST_INT
+ && INTVAL (op1) < 0)
+ const_op1 = 0;
/* We used to test optimize here, on the grounds that it's better to
produce a smaller program when -O is not used.
But this causes such a terrible slowdown sometimes
that it seems better to use synth_mult always. */
- if (GET_CODE (const_op1) == CONST_INT)
+ if (const_op1 && GET_CODE (const_op1) == CONST_INT)
{
struct algorithm alg;
struct algorithm alg2;
@@ -2087,13 +2100,20 @@ expand_mult (mode, op0, op1, target, unsignedp)
mult_cost = MIN (12 * add_cost, mult_cost);
synth_mult (&alg, val, mult_cost);
- synth_mult (&alg2, - val,
- (alg.cost < mult_cost ? alg.cost : mult_cost) - negate_cost);
- if (alg2.cost + negate_cost < alg.cost)
- alg = alg2, variant = negate_variant;
+
+ /* This works only if the inverted value actually fits in an
+ `unsigned int' */
+ if (HOST_BITS_PER_INT >= GET_MODE_BITSIZE (mode))
+ {
+ synth_mult (&alg2, - val,
+ (alg.cost < mult_cost ? alg.cost : mult_cost) - negate_cost);
+ if (alg2.cost + negate_cost < alg.cost)
+ alg = alg2, variant = negate_variant;
+ }
/* This proves very useful for division-by-constant. */
- synth_mult (&alg2, val - 1, (alg.cost < mult_cost ? alg.cost : mult_cost) - add_cost);
+ synth_mult (&alg2, val - 1,
+ (alg.cost < mult_cost ? alg.cost : mult_cost) - add_cost);
if (alg2.cost + add_cost < alg.cost)
alg = alg2, variant = add_variant;
@@ -2131,9 +2151,11 @@ expand_mult (mode, op0, op1, target, unsignedp)
int log = alg.log[opno];
int preserve = preserve_subexpressions_p ();
rtx shift_subtarget = preserve ? 0 : accum;
- rtx add_target = opno == alg.ops - 1 && target != 0 ? target : 0;
+ rtx add_target
+ = (opno == alg.ops - 1 && target != 0 && variant != add_variant
+ ? target : 0);
rtx accum_target = preserve ? 0 : accum;
-
+
switch (alg.op[opno])
{
case alg_shift:
@@ -2568,7 +2590,7 @@ expand_divmod (rem_flag, code, mode, op0, op1, target, unsignedp)
rtx quotient = 0, remainder = 0;
rtx last;
int size;
- rtx insn;
+ rtx insn, set;
optab optab1, optab2;
int op1_is_constant, op1_is_pow2;
@@ -2585,13 +2607,13 @@ expand_divmod (rem_flag, code, mode, op0, op1, target, unsignedp)
Second comes a switch statement with code specific for each rounding mode.
For some special operands this code emits all RTL for the desired
- operation, for other cases, it generates a quotient and stores it in
+ operation, for other cases, it generates only a quotient and stores it in
QUOTIENT. The case for trunc division/remainder might leave quotient = 0,
to indicate that it has not done anything.
- Last comes code that finishes the operation. If QUOTIENT is set an
- REM_FLAG, the remainder is computed as OP0 - QUOTIENT * OP1. If QUOTIENT
- is not set, it is computed using trunc rounding.
+ Last comes code that finishes the operation. If QUOTIENT is set and
+ REM_FLAG is set, the remainder is computed as OP0 - QUOTIENT * OP1. If
+ QUOTIENT is not set, it is computed using trunc rounding.
We try to generate special code for division and remainder when OP1 is a
constant. If |OP1| = 2**n we can use shifts and some other fast
@@ -2717,7 +2739,9 @@ expand_divmod (rem_flag, code, mode, op0, op1, target, unsignedp)
case TRUNC_DIV_EXPR:
if (op1_is_constant && HOST_BITS_PER_WIDE_INT >= size)
{
- if (unsignedp)
+ if (unsignedp
+ || (INTVAL (op1)
+ == (HOST_WIDE_INT) 1 << (GET_MODE_BITSIZE (compute_mode) - 1)))
{
unsigned HOST_WIDE_INT mh, ml;
int pre_shift, post_shift;
@@ -2813,10 +2837,13 @@ expand_divmod (rem_flag, code, mode, op0, op1, target, unsignedp)
}
insn = get_last_insn ();
- REG_NOTES (insn)
- = gen_rtx (EXPR_LIST, REG_EQUAL,
- gen_rtx (UDIV, compute_mode, op0, op1),
- REG_NOTES (insn));
+ if (insn != last
+ && (set = single_set (insn)) != 0
+ && SET_DEST (set) == quotient)
+ REG_NOTES (insn)
+ = gen_rtx (EXPR_LIST, REG_EQUAL,
+ gen_rtx (UDIV, compute_mode, op0, op1),
+ REG_NOTES (insn));
}
else /* TRUNC_DIV, signed */
{
@@ -2849,7 +2876,7 @@ expand_divmod (rem_flag, code, mode, op0, op1, target, unsignedp)
rtx t1;
t1 = copy_to_mode_reg (compute_mode, op0);
- emit_cmp_insn (t1, const0_rtx, GE,
+ emit_cmp_insn (t1, const0_rtx, GE,
NULL_RTX, compute_mode, 0, 0);
emit_jump_insn (gen_bge (label));
expand_inc (t1, GEN_INT (abs_d - 1));
@@ -2875,14 +2902,19 @@ expand_divmod (rem_flag, code, mode, op0, op1, target, unsignedp)
tquotient, 0);
}
+ /* We have computed OP0 / abs(OP1). If OP1 is negative, negate
+ the quotient. */
if (d < 0)
{
insn = get_last_insn ();
- REG_NOTES (insn)
- = gen_rtx (EXPR_LIST, REG_EQUAL,
- gen_rtx (DIV, compute_mode, op0,
- GEN_INT (abs_d)),
- REG_NOTES (insn));
+ if (insn != last
+ && (set = single_set (insn)) != 0
+ && SET_DEST (set) == quotient)
+ REG_NOTES (insn)
+ = gen_rtx (EXPR_LIST, REG_EQUAL,
+ gen_rtx (DIV, compute_mode, op0,
+ GEN_INT (abs_d)),
+ REG_NOTES (insn));
quotient = expand_unop (compute_mode, neg_optab,
quotient, quotient, 0);
@@ -2935,14 +2967,14 @@ expand_divmod (rem_flag, code, mode, op0, op1, target, unsignedp)
}
}
- if (quotient != 0)
- {
- insn = get_last_insn ();
- REG_NOTES (insn)
- = gen_rtx (EXPR_LIST, REG_EQUAL,
- gen_rtx (DIV, compute_mode, op0, op1),
- REG_NOTES (insn));
- }
+ insn = get_last_insn ();
+ if (insn != last
+ && (set = single_set (insn)) != 0
+ && SET_DEST (set) == quotient)
+ REG_NOTES (insn)
+ = gen_rtx (EXPR_LIST, REG_EQUAL,
+ gen_rtx (DIV, compute_mode, op0, op1),
+ REG_NOTES (insn));
}
break;
}
@@ -3218,6 +3250,44 @@ expand_divmod (rem_flag, code, mode, op0, op1, target, unsignedp)
}
else /* signed */
{
+ if (op1_is_constant && EXACT_POWER_OF_2_OR_ZERO_P (INTVAL (op1))
+ && INTVAL (op1) >= 0)
+ {
+ /* This is extremely similar to the code for the unsigned case
+ above. For 2.7 we should merge these variants, but for
+ 2.6.1 I don't want to touch the code for unsigned since that
+ get used in C. The signed case will only be used by other
+ languages (Ada). */
+
+ rtx t1, t2, t3;
+ unsigned HOST_WIDE_INT d = INTVAL (op1);
+ t1 = expand_shift (RSHIFT_EXPR, compute_mode, op0,
+ build_int_2 (floor_log2 (d), 0),
+ tquotient, 0);
+ t2 = expand_binop (compute_mode, and_optab, op0,
+ GEN_INT (d - 1),
+ NULL_RTX, 1, OPTAB_LIB_WIDEN);
+ t3 = gen_reg_rtx (compute_mode);
+ t3 = emit_store_flag (t3, NE, t2, const0_rtx,
+ compute_mode, 1, 1);
+ if (t3 == 0)
+ {
+ rtx lab;
+ lab = gen_label_rtx ();
+ emit_cmp_insn (t2, const0_rtx, EQ, NULL_RTX,
+ compute_mode, 0, 0);
+ emit_jump_insn (gen_beq (lab));
+ expand_inc (t1, const1_rtx);
+ emit_label (lab);
+ quotient = t1;
+ }
+ else
+ quotient = force_operand (gen_rtx (PLUS, compute_mode,
+ t1, t3),
+ tquotient);
+ break;
+ }
+
/* Try using an instruction that produces both the quotient and
remainder, using truncation. We can easily compensate the
quotient or remainder to get ceiling rounding, once we have the
@@ -3337,10 +3407,70 @@ expand_divmod (rem_flag, code, mode, op0, op1, target, unsignedp)
case ROUND_DIV_EXPR:
case ROUND_MOD_EXPR:
- /* The code that used to be here was wrong, and nothing really
- depends on it. */
- abort ();
- break;
+ if (unsignedp)
+ {
+ rtx tem;
+ rtx label;
+ label = gen_label_rtx ();
+ quotient = gen_reg_rtx (compute_mode);
+ remainder = gen_reg_rtx (compute_mode);
+ if (expand_twoval_binop (udivmod_optab, op0, op1, quotient, remainder, 1) == 0)
+ {
+ rtx tem;
+ quotient = expand_binop (compute_mode, udiv_optab, op0, op1,
+ quotient, 1, OPTAB_LIB_WIDEN);
+ tem = expand_mult (compute_mode, quotient, op1, NULL_RTX, 1);
+ remainder = expand_binop (compute_mode, sub_optab, op0, tem,
+ remainder, 1, OPTAB_LIB_WIDEN);
+ }
+ tem = plus_constant (op1, -1);
+ tem = expand_shift (RSHIFT_EXPR, compute_mode, tem,
+ build_int_2 (1, 0), NULL_RTX, 1);
+ emit_cmp_insn (remainder, tem, LEU, NULL_RTX, compute_mode, 0, 0);
+ emit_jump_insn (gen_bleu (label));
+ expand_inc (quotient, const1_rtx);
+ expand_dec (remainder, op1);
+ emit_label (label);
+ }
+ else
+ {
+ rtx abs_rem, abs_op1, tem, mask;
+ rtx label;
+ label = gen_label_rtx ();
+ quotient = gen_reg_rtx (compute_mode);
+ remainder = gen_reg_rtx (compute_mode);
+ if (expand_twoval_binop (sdivmod_optab, op0, op1, quotient, remainder, 0) == 0)
+ {
+ rtx tem;
+ quotient = expand_binop (compute_mode, sdiv_optab, op0, op1,
+ quotient, 0, OPTAB_LIB_WIDEN);
+ tem = expand_mult (compute_mode, quotient, op1, NULL_RTX, 0);
+ remainder = expand_binop (compute_mode, sub_optab, op0, tem,
+ remainder, 0, OPTAB_LIB_WIDEN);
+ }
+ abs_rem = expand_abs (compute_mode, remainder, NULL_RTX, 0, 0);
+ abs_op1 = expand_abs (compute_mode, op1, NULL_RTX, 0, 0);
+ tem = expand_shift (LSHIFT_EXPR, compute_mode, abs_rem,
+ build_int_2 (1, 0), NULL_RTX, 1);
+ emit_cmp_insn (tem, abs_op1, LTU, NULL_RTX, compute_mode, 0, 0);
+ emit_jump_insn (gen_bltu (label));
+ tem = expand_binop (compute_mode, xor_optab, op0, op1,
+ NULL_RTX, 0, OPTAB_WIDEN);
+ mask = expand_shift (RSHIFT_EXPR, compute_mode, tem,
+ build_int_2 (size - 1, 0), NULL_RTX, 0);
+ tem = expand_binop (compute_mode, xor_optab, mask, const1_rtx,
+ NULL_RTX, 0, OPTAB_WIDEN);
+ tem = expand_binop (compute_mode, sub_optab, tem, mask,
+ NULL_RTX, 0, OPTAB_WIDEN);
+ expand_inc (quotient, tem);
+ tem = expand_binop (compute_mode, xor_optab, mask, op1,
+ NULL_RTX, 0, OPTAB_WIDEN);
+ tem = expand_binop (compute_mode, sub_optab, tem, mask,
+ NULL_RTX, 0, OPTAB_WIDEN);
+ expand_dec (remainder, tem);
+ emit_label (label);
+ }
+ return gen_lowpart (mode, rem_flag ? remainder : quotient);
}
if (quotient == 0)
@@ -3450,39 +3580,39 @@ make_tree (type, x)
}
return t;
-
+
case PLUS:
return fold (build (PLUS_EXPR, type, make_tree (type, XEXP (x, 0)),
make_tree (type, XEXP (x, 1))));
-
+
case MINUS:
return fold (build (MINUS_EXPR, type, make_tree (type, XEXP (x, 0)),
make_tree (type, XEXP (x, 1))));
-
+
case NEG:
return fold (build1 (NEGATE_EXPR, type, make_tree (type, XEXP (x, 0))));
case MULT:
return fold (build (MULT_EXPR, type, make_tree (type, XEXP (x, 0)),
make_tree (type, XEXP (x, 1))));
-
+
case ASHIFT:
return fold (build (LSHIFT_EXPR, type, make_tree (type, XEXP (x, 0)),
make_tree (type, XEXP (x, 1))));
-
+
case LSHIFTRT:
return fold (convert (type,
build (RSHIFT_EXPR, unsigned_type (type),
make_tree (unsigned_type (type),
XEXP (x, 0)),
make_tree (type, XEXP (x, 1)))));
-
+
case ASHIFTRT:
return fold (convert (type,
build (RSHIFT_EXPR, signed_type (type),
make_tree (signed_type (type), XEXP (x, 0)),
make_tree (type, XEXP (x, 1)))));
-
+
case DIV:
if (TREE_CODE (type) != REAL_TYPE)
t = signed_type (type);
@@ -3572,7 +3702,7 @@ expand_and (op0, op1, target)
Return 0 if that cannot be done.
MODE is the mode to use for OP0 and OP1 should they be CONST_INTs. If
- it is VOIDmode, they cannot both be CONST_INT.
+ it is VOIDmode, they cannot both be CONST_INT.
UNSIGNEDP is for the case where we have to widen the operands
to perform the operation. It says to use zero-extension.
@@ -3614,7 +3744,7 @@ emit_store_flag (target, code, op0, op1, mode, unsignedp, normalizep)
code = swap_condition (code);
}
- /* For some comparisons with 1 and -1, we can convert this to
+ /* For some comparisons with 1 and -1, we can convert this to
comparisons with zero. This will often produce more opportunities for
store-flag insns. */
@@ -3655,7 +3785,7 @@ emit_store_flag (target, code, op0, op1, mode, unsignedp, normalizep)
&& GET_MODE_CLASS (mode) == MODE_INT
&& (normalizep || STORE_FLAG_VALUE == 1
|| (GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT
- && (STORE_FLAG_VALUE
+ && (STORE_FLAG_VALUE
== (HOST_WIDE_INT) 1 << (GET_MODE_BITSIZE (mode) - 1)))))
{
subtarget = target;
@@ -3710,7 +3840,7 @@ emit_store_flag (target, code, op0, op1, mode, unsignedp, normalizep)
: const_true_rtx);
/* If the code of COMPARISON doesn't match CODE, something is
- wrong; we can no longer be sure that we have the operation.
+ wrong; we can no longer be sure that we have the operation.
We could handle this case, but it should not happen. */
if (GET_CODE (comparison) != code)
@@ -3782,7 +3912,7 @@ emit_store_flag (target, code, op0, op1, mode, unsignedp, normalizep)
else
abort ();
- /* If we were converting to a smaller mode, do the
+ /* If we were converting to a smaller mode, do the
conversion now. */
if (target_mode != compare_mode)
{
@@ -3824,7 +3954,7 @@ emit_store_flag (target, code, op0, op1, mode, unsignedp, normalizep)
return tem;
}
- /* Some other cases we can do are EQ, NE, LE, and GT comparisons with
+ /* Some other cases we can do are EQ, NE, LE, and GT comparisons with
the constant zero. Reject all other comparisons at this point. Only
do LE and GT if branches are expensive since they are expensive on
2-operand machines. */
@@ -3886,14 +4016,14 @@ emit_store_flag (target, code, op0, op1, mode, unsignedp, normalizep)
tem = expand_binop (mode, sub_optab, tem, op0, subtarget, 0,
OPTAB_WIDEN);
}
-
+
if (code == EQ || code == NE)
{
/* For EQ or NE, one way to do the comparison is to apply an operation
that converts the operand into a positive number if it is non-zero
or zero if it was originally zero. Then, for EQ, we subtract 1 and
for NE we negate. This puts the result in the sign bit. Then we
- normalize with a shift, if needed.
+ normalize with a shift, if needed.
Two operations that can do the above actions are ABS and FFS, so try
them. If that doesn't work, and MODE is smaller than a full word,
diff --git a/gnu/usr.bin/cc/cc_int/expr.c b/gnu/usr.bin/cc/cc_int/expr.c
index e764986..70678c5 100644
--- a/gnu/usr.bin/cc/cc_int/expr.c
+++ b/gnu/usr.bin/cc/cc_int/expr.c
@@ -180,7 +180,7 @@ void bc_load_localaddr PROTO((rtx));
void bc_load_parmaddr PROTO((rtx));
static void preexpand_calls PROTO((tree));
static void do_jump_by_parts_greater PROTO((tree, int, rtx, rtx));
-static void do_jump_by_parts_greater_rtx PROTO((enum machine_mode, int, rtx, rtx, rtx, rtx));
+void do_jump_by_parts_greater_rtx PROTO((enum machine_mode, int, rtx, rtx, rtx, rtx));
static void do_jump_by_parts_equality PROTO((tree, rtx, rtx));
static void do_jump_by_parts_equality_rtx PROTO((rtx, rtx, rtx));
static void do_jump_for_compare PROTO((rtx, rtx, rtx));
@@ -242,7 +242,7 @@ bc_init_mode_to_opcode_maps ()
mode_to_const_map[mode] =
mode_to_load_map[mode] =
mode_to_store_map[mode] = neverneverland;
-
+
#define DEF_MODEMAP(SYM, CODE, UCODE, CONST, LOAD, STORE) \
mode_to_const_map[(int) SYM] = CONST; \
mode_to_load_map[(int) SYM] = LOAD; \
@@ -318,7 +318,7 @@ init_expr_once ()
end_sequence ();
}
-
+
/* This is run at the start of compiling a function. */
void
@@ -916,6 +916,12 @@ convert_move (to, from, unsignedp)
/* No special multiword conversion insn; do it by hand. */
start_sequence ();
+ /* Since we will turn this into a no conflict block, we must ensure
+ that the source does not overlap the target. */
+
+ if (reg_overlap_mentioned_p (to, from))
+ from = force_reg (from_mode, from);
+
/* Get a copy of FROM widened to a word, if necessary. */
if (GET_MODE_BITSIZE (from_mode) < BITS_PER_WORD)
lowpart_mode = word_mode;
@@ -1025,6 +1031,41 @@ convert_move (to, from, unsignedp)
}
}
+ if (to_mode == PDImode)
+ {
+ if (from_mode != DImode)
+ from = convert_to_mode (DImode, from, unsignedp);
+
+#ifdef HAVE_truncdipdi2
+ if (HAVE_truncdipdi2)
+ {
+ emit_unop_insn (CODE_FOR_truncdipdi2, to, from, UNKNOWN);
+ return;
+ }
+#endif /* HAVE_truncdipdi2 */
+ abort ();
+ }
+
+ if (from_mode == PDImode)
+ {
+ if (to_mode != DImode)
+ {
+ from = convert_to_mode (DImode, from, unsignedp);
+ from_mode = DImode;
+ }
+ else
+ {
+#ifdef HAVE_extendpdidi2
+ if (HAVE_extendpdidi2)
+ {
+ emit_unop_insn (CODE_FOR_extendpdidi2, to, from, UNKNOWN);
+ return;
+ }
+#endif /* HAVE_extendpdidi2 */
+ abort ();
+ }
+ }
+
/* Now follow all the conversions between integers
no more than a word long. */
@@ -1084,7 +1125,7 @@ convert_move (to, from, unsignedp)
}
}
- /* Support special truncate insns for certain modes. */
+ /* Support special truncate insns for certain modes. */
if (from_mode == DImode && to_mode == SImode)
{
@@ -1164,6 +1205,58 @@ convert_move (to, from, unsignedp)
return;
}
+ if (from_mode == TImode && to_mode == DImode)
+ {
+#ifdef HAVE_trunctidi2
+ if (HAVE_trunctidi2)
+ {
+ emit_unop_insn (CODE_FOR_trunctidi2, to, from, UNKNOWN);
+ return;
+ }
+#endif
+ convert_move (to, force_reg (from_mode, from), unsignedp);
+ return;
+ }
+
+ if (from_mode == TImode && to_mode == SImode)
+ {
+#ifdef HAVE_trunctisi2
+ if (HAVE_trunctisi2)
+ {
+ emit_unop_insn (CODE_FOR_trunctisi2, to, from, UNKNOWN);
+ return;
+ }
+#endif
+ convert_move (to, force_reg (from_mode, from), unsignedp);
+ return;
+ }
+
+ if (from_mode == TImode && to_mode == HImode)
+ {
+#ifdef HAVE_trunctihi2
+ if (HAVE_trunctihi2)
+ {
+ emit_unop_insn (CODE_FOR_trunctihi2, to, from, UNKNOWN);
+ return;
+ }
+#endif
+ convert_move (to, force_reg (from_mode, from), unsignedp);
+ return;
+ }
+
+ if (from_mode == TImode && to_mode == QImode)
+ {
+#ifdef HAVE_trunctiqi2
+ if (HAVE_trunctiqi2)
+ {
+ emit_unop_insn (CODE_FOR_trunctiqi2, to, from, UNKNOWN);
+ return;
+ }
+#endif
+ convert_move (to, force_reg (from_mode, from), unsignedp);
+ return;
+ }
+
/* Handle truncation of volatile memrefs, and so on;
the things that couldn't be truncated directly,
and for which there was no special instruction. */
@@ -1228,7 +1321,7 @@ convert_modes (mode, oldmode, x, unsignedp)
if (GET_MODE (x) != VOIDmode)
oldmode = GET_MODE (x);
-
+
if (mode == oldmode)
return x;
@@ -1543,7 +1636,10 @@ emit_block_move (x, y, size, align)
here because if SIZE is less than the mode mask, as it is
returned by the macro, it will definitely be less than the
actual mode mask. */
- && (unsigned HOST_WIDE_INT) INTVAL (size) <= GET_MODE_MASK (mode)
+ && ((GET_CODE (size) == CONST_INT
+ && ((unsigned HOST_WIDE_INT) INTVAL (size)
+ <= GET_MODE_MASK (mode)))
+ || GET_MODE_BITSIZE (mode) >= BITS_PER_WORD)
&& (insn_operand_predicate[(int) code][0] == 0
|| (*insn_operand_predicate[(int) code][0]) (x, BLKmode))
&& (insn_operand_predicate[(int) code][1] == 0
@@ -1603,6 +1699,9 @@ move_block_to_reg (regno, x, nregs, mode)
int i;
rtx pat, last;
+ if (nregs == 0)
+ return;
+
if (CONSTANT_P (x) && ! LEGITIMATE_CONSTANT_P (x))
x = validize_mem (force_const_mem (mode, x));
@@ -1823,8 +1922,6 @@ emit_move_insn_1 (x, y)
int stack = push_operand (x, GET_MODE (x));
rtx insns;
- start_sequence ();
-
/* If this is a stack, push the highpart first, so it
will be in the argument order.
@@ -1858,17 +1955,6 @@ emit_move_insn_1 (x, y)
(gen_imagpart (submode, x), gen_imagpart (submode, y)));
}
- insns = get_insns ();
- end_sequence ();
-
- /* If X is a CONCAT, we got insns like RD = RS, ID = IS,
- each with a separate pseudo as destination.
- It's not correct for flow to treat them as a unit. */
- if (GET_CODE (x) != CONCAT)
- emit_no_conflict_block (insns, x, y, NULL_RTX, NULL_RTX);
- else
- emit_insns (insns);
-
return get_last_insn ();
}
@@ -1879,8 +1965,17 @@ emit_move_insn_1 (x, y)
{
rtx last_insn = 0;
rtx insns;
-
- start_sequence ();
+
+#ifdef PUSH_ROUNDING
+
+ /* If X is a push on the stack, do the push now and replace
+ X with a reference to the stack pointer. */
+ if (push_operand (x, GET_MODE (x)))
+ {
+ anti_adjust_stack (GEN_INT (GET_MODE_SIZE (GET_MODE (x))));
+ x = change_address (x, VOIDmode, stack_pointer_rtx);
+ }
+#endif
for (i = 0;
i < (GET_MODE_SIZE (mode) + (UNITS_PER_WORD - 1)) / UNITS_PER_WORD;
@@ -1906,10 +2001,6 @@ emit_move_insn_1 (x, y)
last_insn = emit_move_insn (xpart, ypart);
}
- insns = get_insns ();
- end_sequence ();
- emit_no_conflict_block (insns, x, y, NULL_RTX, NULL_RTX);
-
return last_insn;
}
else
@@ -2041,7 +2132,7 @@ emit_push_insn (x, mode, type, size, align, partial, reg, extra,
int used = partial * UNITS_PER_WORD;
int offset = used % (PARM_BOUNDARY / BITS_PER_UNIT);
int skip;
-
+
if (size == 0)
abort ();
@@ -2724,6 +2815,7 @@ store_expr (exp, target, want_value)
The string constant may be shorter than the array.
So copy just the string's actual length, and clear the rest. */
rtx size;
+ rtx addr;
/* Get the size of the data type of the string,
which is actually the size of the target. */
@@ -2752,17 +2844,16 @@ store_expr (exp, target, want_value)
that we have to clear. */
if (GET_CODE (copy_size_rtx) == CONST_INT)
{
- temp = plus_constant (XEXP (target, 0),
+ addr = plus_constant (XEXP (target, 0),
TREE_STRING_LENGTH (exp));
- size = plus_constant (size,
- - TREE_STRING_LENGTH (exp));
+ size = plus_constant (size, - TREE_STRING_LENGTH (exp));
}
else
{
enum machine_mode size_mode = Pmode;
- temp = force_reg (Pmode, XEXP (target, 0));
- temp = expand_binop (size_mode, add_optab, temp,
+ addr = force_reg (Pmode, XEXP (target, 0));
+ addr = expand_binop (size_mode, add_optab, addr,
copy_size_rtx, NULL_RTX, 0,
OPTAB_LIB_WIDEN);
@@ -2779,13 +2870,14 @@ store_expr (exp, target, want_value)
if (size != const0_rtx)
{
#ifdef TARGET_MEM_FUNCTIONS
- emit_library_call (memset_libfunc, 0, VOIDmode, 3,
- temp, Pmode, const0_rtx, Pmode, size, Pmode);
+ emit_library_call (memset_libfunc, 0, VOIDmode, 3, addr,
+ Pmode, const0_rtx, Pmode, size, Pmode);
#else
emit_library_call (bzero_libfunc, 0, VOIDmode, 2,
- temp, Pmode, size, Pmode);
+ addr, Pmode, size, Pmode);
#endif
}
+
if (label)
emit_label (label);
}
@@ -2811,7 +2903,7 @@ store_expr (exp, target, want_value)
&& ! (GET_CODE (target) == REG
&& REGNO (target) < FIRST_PSEUDO_REGISTER))
return copy_to_reg (target);
-
+
else
return target;
}
@@ -3234,7 +3326,7 @@ get_inner_reference (exp, pbitsize, pbitpos, poffset, pmode,
*pbitsize = GET_MODE_BITSIZE (mode);
*punsignedp = TREE_UNSIGNED (TREE_TYPE (exp));
}
-
+
if (size_tree)
{
if (TREE_CODE (size_tree) != INTEGER_CST)
@@ -3426,7 +3518,7 @@ force_operand (value, target)
force_operand (XEXP (XEXP (value, 0), 1), 0),
target, 0, OPTAB_LIB_WIDEN);
}
-
+
tmp = force_operand (XEXP (value, 0), subtarget);
return expand_binop (GET_MODE (value), binoptab, tmp,
force_operand (op2, NULL_RTX),
@@ -3507,7 +3599,13 @@ safe_from_p (x, exp)
rtx exp_rtl = 0;
int i, nops;
- if (x == 0)
+ if (x == 0
+ /* If EXP has varying size, we MUST use a target since we currently
+ have no way of allocating temporaries of variable size. So we
+ assume here that something at a higher level has prevented a
+ clash. This is somewhat bogus, but the best we can do. */
+ || (TREE_TYPE (exp) != 0 && TYPE_SIZE (TREE_TYPE (exp)) != 0
+ && TREE_CODE (TYPE_SIZE (TREE_TYPE (exp))) != INTEGER_CST))
return 1;
/* If this is a subreg of a hard register, declare it unsafe, otherwise,
@@ -3941,8 +4039,8 @@ expand_expr (exp, target, tmode, modifier)
case REAL_CST:
/* If optimized, generate immediate CONST_DOUBLE
- which will be turned into memory by reload if necessary.
-
+ which will be turned into memory by reload if necessary.
+
We used to force a register so that loop.c could see it. But
this does not allow gen_* patterns to perform optimizations with
the constants. It also produces two insns in cases like "x = 1.0;".
@@ -4340,13 +4438,16 @@ expand_expr (exp, target, tmode, modifier)
}
/* Fold an expression like: "foo"[2].
- This is not done in fold so it won't happen inside &. */
+ This is not done in fold so it won't happen inside &.
+ Don't fold if this is for wide characters since it's too
+ difficult to do correctly and this is a very rare case. */
if (TREE_CODE (array) == STRING_CST
&& TREE_CODE (index) == INTEGER_CST
&& !TREE_INT_CST_HIGH (index)
&& (i = TREE_INT_CST_LOW (index)) < TREE_STRING_LENGTH (array)
- && GET_MODE_CLASS (mode) == MODE_INT)
+ && GET_MODE_CLASS (mode) == MODE_INT
+ && GET_MODE_SIZE (mode) == 1)
return GEN_INT (TREE_STRING_POINTER (array)[i]);
/* If this is a constant index into a constant array,
@@ -4369,7 +4470,7 @@ expand_expr (exp, target, tmode, modifier)
tmode, modifier);
}
}
-
+
else if (optimize >= 1
&& TREE_READONLY (array) && ! TREE_SIDE_EFFECTS (array)
&& TREE_CODE (array) == VAR_DECL && DECL_INITIAL (array)
@@ -4404,9 +4505,12 @@ expand_expr (exp, target, tmode, modifier)
case COMPONENT_REF:
case BIT_FIELD_REF:
/* If the operand is a CONSTRUCTOR, we can just extract the
- appropriate field if it is present. */
+ appropriate field if it is present. Don't do this if we have
+ already written the data since we want to refer to that copy
+ and varasm.c assumes that's what we'll do. */
if (code != ARRAY_REF
- && TREE_CODE (TREE_OPERAND (exp, 0)) == CONSTRUCTOR)
+ && TREE_CODE (TREE_OPERAND (exp, 0)) == CONSTRUCTOR
+ && TREE_CST_RTL (TREE_OPERAND (exp, 0)) == 0)
{
tree elt;
@@ -4912,7 +5016,7 @@ expand_expr (exp, target, tmode, modifier)
op0 = eliminate_constant_term (op0, &constant_term);
/* CONSTANT_TERM and XEXP (op1, 1) are known to be constant, so
- their sum should be a constant. Form it into OP1, since the
+ their sum should be a constant. Form it into OP1, since the
result we want will then be OP0 + OP1. */
temp = simplify_binary_operation (PLUS, mode, constant_term,
@@ -5132,70 +5236,8 @@ expand_expr (exp, target, tmode, modifier)
if (TREE_UNSIGNED (type))
return op0;
- /* First try to do it with a special abs instruction. */
- temp = expand_unop (mode, abs_optab, op0, target, 0);
- if (temp != 0)
- return temp;
-
- /* If this machine has expensive jumps, we can do integer absolute
- value of X as (((signed) x >> (W-1)) ^ x) - ((signed) x >> (W-1)),
- where W is the width of MODE. */
-
- if (GET_MODE_CLASS (mode) == MODE_INT && BRANCH_COST >= 2)
- {
- rtx extended = expand_shift (RSHIFT_EXPR, mode, op0,
- size_int (GET_MODE_BITSIZE (mode) - 1),
- NULL_RTX, 0);
-
- temp = expand_binop (mode, xor_optab, extended, op0, target, 0,
- OPTAB_LIB_WIDEN);
- if (temp != 0)
- temp = expand_binop (mode, sub_optab, temp, extended, target, 0,
- OPTAB_LIB_WIDEN);
-
- if (temp != 0)
- return temp;
- }
-
- /* If that does not win, use conditional jump and negate. */
- target = original_target;
- op1 = gen_label_rtx ();
- if (target == 0 || ! safe_from_p (target, TREE_OPERAND (exp, 0))
- || GET_MODE (target) != mode
- || (GET_CODE (target) == MEM && MEM_VOLATILE_P (target))
- || (GET_CODE (target) == REG
- && REGNO (target) < FIRST_PSEUDO_REGISTER))
- target = gen_reg_rtx (mode);
-
- emit_move_insn (target, op0);
- NO_DEFER_POP;
-
- /* If this mode is an integer too wide to compare properly,
- compare word by word. Rely on CSE to optimize constant cases. */
- if (GET_MODE_CLASS (mode) == MODE_INT && ! can_compare_p (mode))
- do_jump_by_parts_greater_rtx (mode, 0, target, const0_rtx,
- NULL_RTX, op1);
- else
- {
- temp = compare_from_rtx (target, CONST0_RTX (mode), GE, 0, mode,
- NULL_RTX, 0);
- if (temp == const1_rtx)
- return target;
- else if (temp != const0_rtx)
- {
- if (bcc_gen_fctn[(int) GET_CODE (temp)] != 0)
- emit_jump_insn ((*bcc_gen_fctn[(int) GET_CODE (temp)]) (op1));
- else
- abort ();
- }
- }
-
- op0 = expand_unop (mode, neg_optab, target, target, 0);
- if (op0 != target)
- emit_move_insn (target, op0);
- emit_label (op1);
- OK_DEFER_POP;
- return target;
+ return expand_abs (mode, op0, target, unsignedp,
+ safe_from_p (target, TREE_OPERAND (exp, 0)));
case MAX_EXPR:
case MIN_EXPR:
@@ -5443,14 +5485,16 @@ expand_expr (exp, target, tmode, modifier)
/* If we are not to produce a result, we have no target. Otherwise,
if a target was specified use it; it will not be used as an
- intermediate target unless it is safe. If no target, use a
+ intermediate target unless it is safe. If no target, use a
temporary. */
if (ignore)
temp = 0;
else if (original_target
&& safe_from_p (original_target, TREE_OPERAND (exp, 0))
- && GET_MODE (original_target) == mode)
+ && GET_MODE (original_target) == mode
+ && ! (GET_CODE (original_target) == MEM
+ && MEM_VOLATILE_P (original_target)))
temp = original_target;
else if (mode == BLKmode)
{
@@ -5498,8 +5542,7 @@ expand_expr (exp, target, tmode, modifier)
&& (TREE_CODE (binary_op) == PLUS_EXPR
|| TREE_CODE (binary_op) == MINUS_EXPR
|| TREE_CODE (binary_op) == BIT_IOR_EXPR
- || TREE_CODE (binary_op) == BIT_XOR_EXPR
- || TREE_CODE (binary_op) == BIT_AND_EXPR)
+ || TREE_CODE (binary_op) == BIT_XOR_EXPR)
&& integer_onep (TREE_OPERAND (binary_op, 1))
&& TREE_CODE_CLASS (TREE_CODE (TREE_OPERAND (exp, 0))) == '<')
{
@@ -5507,8 +5550,7 @@ expand_expr (exp, target, tmode, modifier)
optab boptab = (TREE_CODE (binary_op) == PLUS_EXPR ? add_optab
: TREE_CODE (binary_op) == MINUS_EXPR ? sub_optab
: TREE_CODE (binary_op) == BIT_IOR_EXPR ? ior_optab
- : TREE_CODE (binary_op) == BIT_XOR_EXPR ? xor_optab
- : and_optab);
+ : xor_optab);
/* If we had X ? A : A + 1, do this as A + (X == 0).
@@ -5536,7 +5578,7 @@ expand_expr (exp, target, tmode, modifier)
TREE_OPERAND (exp, 0)
= invert_truthvalue (TREE_OPERAND (exp, 0));
}
-
+
NO_DEFER_POP;
op0 = gen_label_rtx ();
@@ -5586,7 +5628,7 @@ expand_expr (exp, target, tmode, modifier)
#if 0
/* This is now done in jump.c and is better done there because it
produces shorter register lifetimes. */
-
+
/* Check for both possibilities either constants or variables
in registers (but not the same as the target!). If so, can
save branches by assigning one, branching, and assigning the
@@ -5732,7 +5774,8 @@ expand_expr (exp, target, tmode, modifier)
left_cleanups = integer_zero_node;
if (! right_cleanups)
right_cleanups = integer_zero_node;
- new_cleanups = build (COND_EXPR, void_type_node, cond,
+ new_cleanups = build (COND_EXPR, void_type_node,
+ truthvalue_conversion (cond),
left_cleanups, right_cleanups);
new_cleanups = fold (new_cleanups);
@@ -5828,7 +5871,7 @@ expand_expr (exp, target, tmode, modifier)
if (need_exception_region)
(*interim_eh_hook) (NULL_TREE);
-
+
return temp;
}
@@ -5969,7 +6012,10 @@ expand_expr (exp, target, tmode, modifier)
op0 = force_const_mem (TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0))),
op0);
else if (GET_CODE (op0) == MEM)
- temp = XEXP (op0, 0);
+ {
+ mark_temp_addr_taken (op0);
+ temp = XEXP (op0, 0);
+ }
else if (GET_CODE (op0) == REG || GET_CODE (op0) == SUBREG
|| GET_CODE (op0) == CONCAT)
@@ -5982,13 +6028,14 @@ expand_expr (exp, target, tmode, modifier)
= assign_stack_temp (inner_mode,
int_size_in_bytes (inner_type), 1);
+ mark_temp_addr_taken (memloc);
emit_move_insn (memloc, op0);
op0 = memloc;
}
if (GET_CODE (op0) != MEM)
abort ();
-
+
if (modifier == EXPAND_SUM || modifier == EXPAND_INITIALIZER)
return XEXP (op0, 0);
@@ -6048,36 +6095,38 @@ expand_expr (exp, target, tmode, modifier)
case REALPART_EXPR:
op0 = expand_expr (TREE_OPERAND (exp, 0), 0, VOIDmode, 0);
return gen_realpart (mode, op0);
-
+
case IMAGPART_EXPR:
op0 = expand_expr (TREE_OPERAND (exp, 0), 0, VOIDmode, 0);
return gen_imagpart (mode, op0);
case CONJ_EXPR:
{
+ enum machine_mode partmode = TYPE_MODE (TREE_TYPE (TREE_TYPE (exp)));
rtx imag_t;
rtx insns;
-
+
op0 = expand_expr (TREE_OPERAND (exp, 0), 0, VOIDmode, 0);
if (! target)
target = gen_reg_rtx (mode);
-
+
start_sequence ();
/* Store the realpart and the negated imagpart to target. */
- emit_move_insn (gen_realpart (mode, target), gen_realpart (mode, op0));
+ emit_move_insn (gen_realpart (partmode, target),
+ gen_realpart (partmode, op0));
- imag_t = gen_imagpart (mode, target);
- temp = expand_unop (mode, neg_optab,
- gen_imagpart (mode, op0), imag_t, 0);
+ imag_t = gen_imagpart (partmode, target);
+ temp = expand_unop (partmode, neg_optab,
+ gen_imagpart (partmode, op0), imag_t, 0);
if (temp != imag_t)
emit_move_insn (imag_t, temp);
insns = get_insns ();
end_sequence ();
- /* Conjugate should appear as a single unit
+ /* Conjugate should appear as a single unit
If TARGET is a CONCAT, we got insns like RD = RS, ID = - IS,
each with a separate pseudo as destination.
It's not correct for flow to treat them as a unit. */
@@ -6129,30 +6178,30 @@ bc_expand_expr (exp)
struct increment_operator *incroptab;
struct bc_label *lab, *lab1;
enum bytecode_opcode opcode;
-
-
+
+
code = TREE_CODE (exp);
-
+
switch (code)
{
case PARM_DECL:
-
+
if (DECL_RTL (exp) == 0)
{
error_with_decl (exp, "prior parameter's size depends on `%s'");
return;
}
-
+
bc_load_parmaddr (DECL_RTL (exp));
bc_load_memory (TREE_TYPE (exp), exp);
-
+
return;
-
+
case VAR_DECL:
-
+
if (DECL_RTL (exp) == 0)
abort ();
-
+
#if 0
if (BYTECODE_LABEL (DECL_RTL (exp)))
bc_load_externaddr (DECL_RTL (exp));
@@ -6164,12 +6213,12 @@ bc_expand_expr (exp)
BYTECODE_BC_LABEL (DECL_RTL (exp))->offset);
else
bc_load_localaddr (DECL_RTL (exp));
-
+
bc_load_memory (TREE_TYPE (exp), exp);
return;
-
+
case INTEGER_CST:
-
+
#ifdef DEBUG_PRINT_CODE
fprintf (stderr, " [%x]\n", TREE_INT_CST_LOW (exp));
#endif
@@ -6178,9 +6227,9 @@ bc_expand_expr (exp)
: TYPE_MODE (TREE_TYPE (exp)))],
(HOST_WIDE_INT) TREE_INT_CST_LOW (exp));
return;
-
+
case REAL_CST:
-
+
#if 0
#ifdef DEBUG_PRINT_CODE
fprintf (stderr, " [%g]\n", (double) TREE_INT_CST_LOW (exp));
@@ -6193,9 +6242,9 @@ bc_expand_expr (exp)
#endif
return;
-
+
case CALL_EXPR:
-
+
/* We build a call description vector describing the type of
the return value and of the arguments; this call vector,
together with a pointer to a location for the return value
@@ -6207,18 +6256,18 @@ bc_expand_expr (exp)
tree calldesc = 0, arg;
int nargs = 0, i;
rtx retval;
-
+
/* Push the evaluated args on the evaluation stack in reverse
order. Also make an entry for each arg in the calldesc
vector while we're at it. */
-
+
TREE_OPERAND (exp, 1) = nreverse (TREE_OPERAND (exp, 1));
-
+
for (arg = TREE_OPERAND (exp, 1); arg; arg = TREE_CHAIN (arg))
{
++nargs;
bc_expand_expr (TREE_VALUE (arg));
-
+
calldesc = tree_cons ((tree) 0,
size_in_bytes (TREE_TYPE (TREE_VALUE (arg))),
calldesc);
@@ -6226,50 +6275,50 @@ bc_expand_expr (exp)
bc_runtime_type_code (TREE_TYPE (TREE_VALUE (arg))),
calldesc);
}
-
+
TREE_OPERAND (exp, 1) = nreverse (TREE_OPERAND (exp, 1));
-
+
/* Allocate a location for the return value and push its
address on the evaluation stack. Also make an entry
at the front of the calldesc for the return value type. */
-
+
type = TREE_TYPE (TREE_TYPE (TREE_TYPE (TREE_OPERAND (exp, 0))));
retval = bc_allocate_local (int_size_in_bytes (type), TYPE_ALIGN (type));
bc_load_localaddr (retval);
-
+
calldesc = tree_cons ((tree) 0, size_in_bytes (type), calldesc);
calldesc = tree_cons ((tree) 0, bc_runtime_type_code (type), calldesc);
-
+
/* Prepend the argument count. */
calldesc = tree_cons ((tree) 0,
build_int_2 (nargs, 0),
calldesc);
-
+
/* Push the address of the call description vector on the stack. */
calldesc = build_nt (CONSTRUCTOR, (tree) 0, calldesc);
TREE_TYPE (calldesc) = build_array_type (integer_type_node,
build_index_type (build_int_2 (nargs * 2, 0)));
r = output_constant_def (calldesc);
bc_load_externaddr (r);
-
+
/* Push the address of the function to be called. */
bc_expand_expr (TREE_OPERAND (exp, 0));
-
+
/* Call the function, popping its address and the calldesc vector
address off the evaluation stack in the process. */
bc_emit_instruction (call);
-
+
/* Pop the arguments off the stack. */
bc_adjust_stack (nargs);
-
+
/* Load the return value onto the stack. */
bc_load_localaddr (retval);
bc_load_memory (type, TREE_OPERAND (exp, 0));
}
return;
-
+
case SAVE_EXPR:
-
+
if (!SAVE_EXPR_RTL (exp))
{
/* First time around: copy to local variable */
@@ -6277,7 +6326,7 @@ bc_expand_expr (exp)
TYPE_ALIGN (TREE_TYPE(exp)));
bc_expand_expr (TREE_OPERAND (exp, 0));
bc_emit_instruction (duplicate);
-
+
bc_load_localaddr (SAVE_EXPR_RTL (exp));
bc_store_memory (TREE_TYPE (exp), TREE_OPERAND (exp, 0));
}
@@ -6288,68 +6337,68 @@ bc_expand_expr (exp)
bc_load_memory (TREE_TYPE (exp), TREE_OPERAND (exp, 0));
}
return;
-
+
#if 0
/* FIXME: the XXXX_STMT codes have been removed in GCC2, but
how are they handled instead? */
case LET_STMT:
-
+
TREE_USED (exp) = 1;
bc_expand_expr (STMT_BODY (exp));
return;
#endif
-
+
case NOP_EXPR:
case CONVERT_EXPR:
-
+
bc_expand_expr (TREE_OPERAND (exp, 0));
bc_expand_conversion (TREE_TYPE (TREE_OPERAND (exp, 0)), TREE_TYPE (exp));
return;
-
+
case MODIFY_EXPR:
-
+
expand_assignment (TREE_OPERAND (exp, 0), TREE_OPERAND (exp, 1), 0, 0);
return;
-
+
case ADDR_EXPR:
-
+
bc_expand_address (TREE_OPERAND (exp, 0));
return;
-
+
case INDIRECT_REF:
-
+
bc_expand_expr (TREE_OPERAND (exp, 0));
bc_load_memory (TREE_TYPE (exp), TREE_OPERAND (exp, 0));
return;
-
+
case ARRAY_REF:
-
+
bc_expand_expr (bc_canonicalize_array_ref (exp));
return;
-
+
case COMPONENT_REF:
-
+
bc_expand_component_address (exp);
-
+
/* If we have a bitfield, generate a proper load */
bc_load_memory (TREE_TYPE (TREE_OPERAND (exp, 1)), TREE_OPERAND (exp, 1));
return;
-
+
case COMPOUND_EXPR:
-
+
bc_expand_expr (TREE_OPERAND (exp, 0));
bc_emit_instruction (drop);
bc_expand_expr (TREE_OPERAND (exp, 1));
return;
-
+
case COND_EXPR:
-
+
bc_expand_expr (TREE_OPERAND (exp, 0));
bc_expand_truth_conversion (TREE_TYPE (TREE_OPERAND (exp, 0)));
lab = bc_get_bytecode_label ();
bc_emit_bytecode (xjumpifnot);
bc_emit_bytecode_labelref (lab);
-
+
#ifdef DEBUG_PRINT_CODE
fputc ('\n', stderr);
#endif
@@ -6357,63 +6406,63 @@ bc_expand_expr (exp)
lab1 = bc_get_bytecode_label ();
bc_emit_bytecode (jump);
bc_emit_bytecode_labelref (lab1);
-
+
#ifdef DEBUG_PRINT_CODE
fputc ('\n', stderr);
#endif
-
+
bc_emit_bytecode_labeldef (lab);
bc_expand_expr (TREE_OPERAND (exp, 2));
bc_emit_bytecode_labeldef (lab1);
return;
-
+
case TRUTH_ANDIF_EXPR:
-
+
opcode = xjumpifnot;
goto andorif;
-
+
case TRUTH_ORIF_EXPR:
-
+
opcode = xjumpif;
goto andorif;
-
+
case PLUS_EXPR:
-
+
binoptab = optab_plus_expr;
goto binop;
-
+
case MINUS_EXPR:
-
+
binoptab = optab_minus_expr;
goto binop;
-
+
case MULT_EXPR:
-
+
binoptab = optab_mult_expr;
goto binop;
-
+
case TRUNC_DIV_EXPR:
case FLOOR_DIV_EXPR:
case CEIL_DIV_EXPR:
case ROUND_DIV_EXPR:
case EXACT_DIV_EXPR:
-
+
binoptab = optab_trunc_div_expr;
goto binop;
-
+
case TRUNC_MOD_EXPR:
case FLOOR_MOD_EXPR:
case CEIL_MOD_EXPR:
case ROUND_MOD_EXPR:
-
+
binoptab = optab_trunc_mod_expr;
goto binop;
-
+
case FIX_ROUND_EXPR:
case FIX_FLOOR_EXPR:
case FIX_CEIL_EXPR:
abort (); /* Not used for C. */
-
+
case FIX_TRUNC_EXPR:
case FLOAT_EXPR:
case MAX_EXPR:
@@ -6422,135 +6471,135 @@ bc_expand_expr (exp)
case LROTATE_EXPR:
case RROTATE_EXPR:
abort (); /* FIXME */
-
+
case RDIV_EXPR:
-
+
binoptab = optab_rdiv_expr;
goto binop;
-
+
case BIT_AND_EXPR:
-
+
binoptab = optab_bit_and_expr;
goto binop;
-
+
case BIT_IOR_EXPR:
-
+
binoptab = optab_bit_ior_expr;
goto binop;
-
+
case BIT_XOR_EXPR:
-
+
binoptab = optab_bit_xor_expr;
goto binop;
-
+
case LSHIFT_EXPR:
-
+
binoptab = optab_lshift_expr;
goto binop;
-
+
case RSHIFT_EXPR:
-
+
binoptab = optab_rshift_expr;
goto binop;
-
+
case TRUTH_AND_EXPR:
-
+
binoptab = optab_truth_and_expr;
goto binop;
-
+
case TRUTH_OR_EXPR:
-
+
binoptab = optab_truth_or_expr;
goto binop;
-
+
case LT_EXPR:
-
+
binoptab = optab_lt_expr;
goto binop;
-
+
case LE_EXPR:
-
+
binoptab = optab_le_expr;
goto binop;
-
+
case GE_EXPR:
-
+
binoptab = optab_ge_expr;
goto binop;
-
+
case GT_EXPR:
-
+
binoptab = optab_gt_expr;
goto binop;
-
+
case EQ_EXPR:
-
+
binoptab = optab_eq_expr;
goto binop;
-
+
case NE_EXPR:
-
+
binoptab = optab_ne_expr;
goto binop;
-
+
case NEGATE_EXPR:
-
+
unoptab = optab_negate_expr;
goto unop;
-
+
case BIT_NOT_EXPR:
-
+
unoptab = optab_bit_not_expr;
goto unop;
-
+
case TRUTH_NOT_EXPR:
-
+
unoptab = optab_truth_not_expr;
goto unop;
-
+
case PREDECREMENT_EXPR:
-
+
incroptab = optab_predecrement_expr;
goto increment;
-
+
case PREINCREMENT_EXPR:
-
+
incroptab = optab_preincrement_expr;
goto increment;
-
+
case POSTDECREMENT_EXPR:
-
+
incroptab = optab_postdecrement_expr;
goto increment;
-
+
case POSTINCREMENT_EXPR:
-
+
incroptab = optab_postincrement_expr;
goto increment;
-
+
case CONSTRUCTOR:
-
+
bc_expand_constructor (exp);
return;
-
+
case ERROR_MARK:
case RTL_EXPR:
-
+
return;
-
+
case BIND_EXPR:
{
tree vars = TREE_OPERAND (exp, 0);
int vars_need_expansion = 0;
-
+
/* Need to open a binding contour here because
if there are any cleanups they most be contained here. */
expand_start_bindings (0);
-
+
/* Mark the corresponding BLOCK for output. */
if (TREE_OPERAND (exp, 2) != 0)
TREE_USED (TREE_OPERAND (exp, 2)) = 1;
-
+
/* If VARS have not yet been expanded, expand them now. */
while (vars)
{
@@ -6562,65 +6611,65 @@ bc_expand_expr (exp)
expand_decl_init (vars);
vars = TREE_CHAIN (vars);
}
-
+
bc_expand_expr (TREE_OPERAND (exp, 1));
-
+
expand_end_bindings (TREE_OPERAND (exp, 0), 0, 0);
-
+
return;
}
}
-
+
abort ();
-
+
binop:
-
+
bc_expand_binary_operation (binoptab, TREE_TYPE (exp),
TREE_OPERAND (exp, 0), TREE_OPERAND (exp, 1));
return;
-
-
+
+
unop:
-
+
bc_expand_unary_operation (unoptab, TREE_TYPE (exp), TREE_OPERAND (exp, 0));
return;
-
-
+
+
andorif:
-
+
bc_expand_expr (TREE_OPERAND (exp, 0));
bc_expand_truth_conversion (TREE_TYPE (TREE_OPERAND (exp, 0)));
lab = bc_get_bytecode_label ();
-
+
bc_emit_instruction (duplicate);
bc_emit_bytecode (opcode);
bc_emit_bytecode_labelref (lab);
-
+
#ifdef DEBUG_PRINT_CODE
fputc ('\n', stderr);
#endif
-
+
bc_emit_instruction (drop);
-
+
bc_expand_expr (TREE_OPERAND (exp, 1));
bc_expand_truth_conversion (TREE_TYPE (TREE_OPERAND (exp, 1)));
bc_emit_bytecode_labeldef (lab);
return;
-
-
+
+
increment:
-
+
type = TREE_TYPE (TREE_OPERAND (exp, 0));
-
+
/* Push the quantum. */
bc_expand_expr (TREE_OPERAND (exp, 1));
-
+
/* Convert it to the lvalue's type. */
bc_expand_conversion (TREE_TYPE (TREE_OPERAND (exp, 1)), type);
-
+
/* Push the address of the lvalue */
bc_expand_expr (build1 (ADDR_EXPR, TYPE_POINTER_TO (type), TREE_OPERAND (exp, 0)));
-
+
/* Perform actual increment */
bc_expand_increment (incroptab, type);
return;
@@ -6836,6 +6885,9 @@ expand_builtin (exp, target, subtarget, mode, ignore)
case BUILT_IN_SIN:
case BUILT_IN_COS:
+ /* Treat these like sqrt, but only if the user asks for them. */
+ if (! flag_fast_math)
+ break;
case BUILT_IN_FSQRT:
/* If not optimizing, call the library function. */
if (! optimize)
@@ -6932,7 +6984,7 @@ expand_builtin (exp, target, subtarget, mode, ignore)
insns = get_insns ();
end_sequence ();
emit_insns (insns);
-
+
return target;
/* __builtin_apply_args returns block of memory allocated on
@@ -7232,7 +7284,7 @@ expand_builtin (exp, target, subtarget, mode, ignore)
}
else
{
- int count = TREE_INT_CST_LOW (TREE_VALUE (arglist));
+ int count = TREE_INT_CST_LOW (TREE_VALUE (arglist));
rtx tem = frame_pointer_rtx;
int i;
@@ -7589,7 +7641,7 @@ expand_builtin (exp, target, subtarget, mode, ignore)
}
else
return convert_to_mode (mode, result, 0);
- }
+ }
#else
case BUILT_IN_STRCMP:
case BUILT_IN_MEMCMP:
@@ -7629,11 +7681,11 @@ static enum machine_mode apply_result_mode[FIRST_PSEUDO_REGISTER];
used for calling a function. */
static int apply_args_reg_offset[FIRST_PSEUDO_REGISTER];
-/* Return the offset of register REGNO into the block returned by
+/* Return the offset of register REGNO into the block returned by
__builtin_apply_args. This is not declared static, since it is
needed in objc-act.c. */
-int
+int
apply_args_register_offset (regno)
int regno;
{
@@ -7784,7 +7836,7 @@ result_vector (savep, result)
enum machine_mode mode;
rtx reg, mem;
rtx *savevec = (rtx *) alloca (FIRST_PSEUDO_REGISTER * sizeof (rtx));
-
+
size = nelts = 0;
for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
if ((mode = apply_result_mode[regno]) != VOIDmode)
@@ -7792,7 +7844,7 @@ result_vector (savep, result)
align = GET_MODE_ALIGNMENT (mode) / BITS_PER_UNIT;
if (size % align != 0)
size = CEIL (size, align) * align;
- reg = gen_rtx (REG, mode, savep ? INCOMING_REGNO (regno) : regno);
+ reg = gen_rtx (REG, mode, savep ? regno : INCOMING_REGNO (regno));
mem = change_address (result, mode,
plus_constant (XEXP (result, 0), size));
savevec[nelts++] = (savep
@@ -8284,7 +8336,9 @@ preexpand_calls (exp)
/* Do nothing to built-in functions. */
if (TREE_CODE (TREE_OPERAND (exp, 0)) != ADDR_EXPR
|| TREE_CODE (TREE_OPERAND (TREE_OPERAND (exp, 0), 0)) != FUNCTION_DECL
- || ! DECL_BUILT_IN (TREE_OPERAND (TREE_OPERAND (exp, 0), 0)))
+ || ! DECL_BUILT_IN (TREE_OPERAND (TREE_OPERAND (exp, 0), 0))
+ /* Do nothing if the call returns a variable-sized object. */
+ || TREE_CODE (TYPE_SIZE (TREE_TYPE(exp))) != INTEGER_CST)
CALL_EXPR_RTL (exp) = expand_call (exp, NULL_RTX, 0);
return;
@@ -8371,8 +8425,9 @@ defer_cleanups_to (old_cleanups)
while (cleanups_this_call != old_cleanups)
{
(*interim_eh_hook) (TREE_VALUE (cleanups_this_call));
+ last = cleanups_this_call;
cleanups_this_call = TREE_CHAIN (cleanups_this_call);
- }
+ }
if (last)
{
@@ -8555,17 +8610,117 @@ do_jump (exp, if_false_label, if_true_label)
break;
case TRUTH_ANDIF_EXPR:
- if (if_false_label == 0)
- if_false_label = drop_through_label = gen_label_rtx ();
- do_jump (TREE_OPERAND (exp, 0), if_false_label, NULL_RTX);
- do_jump (TREE_OPERAND (exp, 1), if_false_label, if_true_label);
+ {
+ rtx seq1, seq2;
+ tree cleanups, old_cleanups;
+
+ if (if_false_label == 0)
+ if_false_label = drop_through_label = gen_label_rtx ();
+ start_sequence ();
+ do_jump (TREE_OPERAND (exp, 0), if_false_label, NULL_RTX);
+ seq1 = get_insns ();
+ end_sequence ();
+
+ old_cleanups = cleanups_this_call;
+ start_sequence ();
+ do_jump (TREE_OPERAND (exp, 1), if_false_label, if_true_label);
+ seq2 = get_insns ();
+ end_sequence ();
+
+ cleanups = defer_cleanups_to (old_cleanups);
+ if (cleanups)
+ {
+ rtx flag = gen_reg_rtx (word_mode);
+ tree new_cleanups;
+ tree cond;
+
+ /* Flag cleanups as not needed. */
+ emit_move_insn (flag, const0_rtx);
+ emit_insns (seq1);
+
+ /* Flag cleanups as needed. */
+ emit_move_insn (flag, const1_rtx);
+ emit_insns (seq2);
+
+ /* convert flag, which is an rtx, into a tree. */
+ cond = make_node (RTL_EXPR);
+ TREE_TYPE (cond) = integer_type_node;
+ RTL_EXPR_RTL (cond) = flag;
+ RTL_EXPR_SEQUENCE (cond) = NULL_RTX;
+
+ new_cleanups = build (COND_EXPR, void_type_node,
+ truthvalue_conversion (cond),
+ cleanups, integer_zero_node);
+ new_cleanups = fold (new_cleanups);
+
+ /* Now add in the conditionalized cleanups. */
+ cleanups_this_call
+ = tree_cons (NULL_TREE, new_cleanups, cleanups_this_call);
+ (*interim_eh_hook) (NULL_TREE);
+ }
+ else
+ {
+ emit_insns (seq1);
+ emit_insns (seq2);
+ }
+ }
break;
case TRUTH_ORIF_EXPR:
- if (if_true_label == 0)
- if_true_label = drop_through_label = gen_label_rtx ();
- do_jump (TREE_OPERAND (exp, 0), NULL_RTX, if_true_label);
- do_jump (TREE_OPERAND (exp, 1), if_false_label, if_true_label);
+ {
+ rtx seq1, seq2;
+ tree cleanups, old_cleanups;
+
+ if (if_true_label == 0)
+ if_true_label = drop_through_label = gen_label_rtx ();
+ start_sequence ();
+ do_jump (TREE_OPERAND (exp, 0), NULL_RTX, if_true_label);
+ seq1 = get_insns ();
+ end_sequence ();
+
+ old_cleanups = cleanups_this_call;
+ start_sequence ();
+ do_jump (TREE_OPERAND (exp, 1), if_false_label, if_true_label);
+ seq2 = get_insns ();
+ end_sequence ();
+
+ cleanups = defer_cleanups_to (old_cleanups);
+ if (cleanups)
+ {
+ rtx flag = gen_reg_rtx (word_mode);
+ tree new_cleanups;
+ tree cond;
+
+ /* Flag cleanups as not needed. */
+ emit_move_insn (flag, const0_rtx);
+ emit_insns (seq1);
+
+ /* Flag cleanups as needed. */
+ emit_move_insn (flag, const1_rtx);
+ emit_insns (seq2);
+
+ /* convert flag, which is an rtx, into a tree. */
+ cond = make_node (RTL_EXPR);
+ TREE_TYPE (cond) = integer_type_node;
+ RTL_EXPR_RTL (cond) = flag;
+ RTL_EXPR_SEQUENCE (cond) = NULL_RTX;
+
+ new_cleanups = build (COND_EXPR, void_type_node,
+ truthvalue_conversion (cond),
+ cleanups, integer_zero_node);
+ new_cleanups = fold (new_cleanups);
+
+ /* Now add in the conditionalized cleanups. */
+ cleanups_this_call
+ = tree_cons (NULL_TREE, new_cleanups, cleanups_this_call);
+ (*interim_eh_hook) (NULL_TREE);
+ }
+ else
+ {
+ emit_insns (seq1);
+ emit_insns (seq2);
+ }
+ }
break;
case COMPOUND_EXPR:
@@ -8640,7 +8795,7 @@ do_jump (exp, if_false_label, if_true_label)
do_jump (TREE_OPERAND (exp, 0), if_true_label, if_false_label);
else if (((GET_MODE_CLASS (TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0))))
== MODE_INT)
- &&
+ &&
!can_compare_p (TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0)))))
|| GET_MODE_CLASS (TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0)))) == MODE_COMPLEX_FLOAT
|| GET_MODE_CLASS (TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0)))) == MODE_COMPLEX_INT)
@@ -8654,7 +8809,7 @@ do_jump (exp, if_false_label, if_true_label)
do_jump (TREE_OPERAND (exp, 0), if_false_label, if_true_label);
else if (((GET_MODE_CLASS (TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0))))
== MODE_INT)
- &&
+ &&
!can_compare_p (TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0)))))
|| GET_MODE_CLASS (TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0)))) == MODE_COMPLEX_FLOAT
|| GET_MODE_CLASS (TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0)))) == MODE_COMPLEX_INT)
@@ -8829,7 +8984,7 @@ do_jump_by_parts_greater (exp, swap, if_false_label, if_true_label)
UNSIGNEDP says to do unsigned comparison.
Jump to IF_TRUE_LABEL if OP0 is greater, IF_FALSE_LABEL otherwise. */
-static void
+void
do_jump_by_parts_greater_rtx (mode, unsignedp, op0, op1, if_false_label, if_true_label)
enum machine_mode mode;
int unsignedp;
@@ -8980,9 +9135,6 @@ do_jump_for_compare (comparison, if_false_label, if_true_label)
rtx prev = get_last_insn ();
rtx branch = 0;
- if (prev != 0)
- prev = PREV_INSN (prev);
-
/* Output the branch with the opposite condition. Then try to invert
what is generated. If more than one insn is a branch, or if the
branch is not the last insn written, abort. If we can't invert
@@ -8990,20 +9142,23 @@ do_jump_for_compare (comparison, if_false_label, if_true_label)
emit a jump to the false label and define the true label. */
if (bcc_gen_fctn[(int) GET_CODE (comparison)] != 0)
- emit_jump_insn ((*bcc_gen_fctn[(int) GET_CODE (comparison)]) (if_false_label));
+ emit_jump_insn ((*bcc_gen_fctn[(int) GET_CODE (comparison)])(if_false_label));
else
abort ();
- /* Here we get the insn before what was just emitted.
- On some machines, emitting the branch can discard
- the previous compare insn and emit a replacement. */
+ /* Here we get the first insn that was just emitted. It used to be the
+ case that, on some machines, emitting the branch would discard
+ the previous compare insn and emit a replacement. This isn't
+ done anymore, but abort if we see that PREV is deleted. */
+
if (prev == 0)
- /* If there's only one preceding insn... */
insn = get_insns ();
+ else if (INSN_DELETED_P (prev))
+ abort ();
else
insn = NEXT_INSN (prev);
- for (insn = NEXT_INSN (insn); insn; insn = NEXT_INSN (insn))
+ for (; insn; insn = NEXT_INSN (insn))
if (GET_CODE (insn) == JUMP_INSN)
{
if (branch)
@@ -9119,7 +9274,7 @@ compare_from_rtx (op0, op1, code, unsignedp, mode, size, align)
unsignedp = 1;
}
#endif
-
+
emit_cmp_insn (op0, op1, code, size, mode, unsignedp, align);
return gen_rtx (code, VOIDmode, cc0_rtx, const0_rtx);
@@ -9323,7 +9478,7 @@ do_store_flag (exp, target, mode, only_cheap)
else
return 0;
}
-
+
preexpand_calls (exp);
if (subtarget == 0 || GET_CODE (subtarget) != REG
|| GET_MODE (subtarget) != operand_mode
@@ -9466,12 +9621,12 @@ bc_load_memory (type, decl)
tree type, decl;
{
enum bytecode_opcode opcode;
-
-
+
+
/* Bit fields are special. We only know about signed and
unsigned ints, and enums. The latter are treated as
signed integers. */
-
+
if (DECL_BIT_FIELD (decl))
if (TREE_CODE (type) == ENUMERAL_TYPE
|| TREE_CODE (type) == INTEGER_TYPE)
@@ -9488,9 +9643,9 @@ bc_load_memory (type, decl)
if (opcode == neverneverland)
abort ();
-
+
bc_emit_bytecode (opcode);
-
+
#ifdef DEBUG_PRINT_CODE
fputc ('\n', stderr);
#endif
@@ -9506,8 +9661,8 @@ bc_store_memory (type, decl)
tree type, decl;
{
enum bytecode_opcode opcode;
-
-
+
+
if (DECL_BIT_FIELD (decl))
{
if (TREE_CODE (type) == ENUMERAL_TYPE
@@ -9526,7 +9681,7 @@ bc_store_memory (type, decl)
are already on the stack; so we just put the size on level 1. For some
other languages, the size may be variable, this is why we don't encode
it as a storeBLK literal, but rather treat it as a full-fledged expression. */
-
+
bc_expand_expr (TYPE_SIZE (type));
opcode = storeBLK;
}
@@ -9537,7 +9692,7 @@ bc_store_memory (type, decl)
abort ();
bc_emit_bytecode (opcode);
-
+
#ifdef DEBUG_PRINT_CODE
fputc ('\n', stderr);
#endif
@@ -9801,7 +9956,7 @@ bc_expand_address (exp)
/* If packed, also return offset and size */
if (DECL_BIT_FIELD (TREE_OPERAND (exp, 0)))
-
+
bc_push_offset_and_size (TREE_INT_CST_LOW (DECL_FIELD_BITPOS (TREE_OPERAND (exp, 0))),
TREE_INT_CST_LOW (DECL_SIZE (TREE_OPERAND (exp, 0))));
@@ -9856,13 +10011,13 @@ bc_expand_address (exp)
if (DECL_BIT_FIELD (exp))
bc_push_offset_and_size (TREE_INT_CST_LOW (DECL_FIELD_BITPOS (exp)),
TREE_INT_CST_LOW (DECL_SIZE (exp)));
-
+
break;
case STRING_CST:
{
rtx r;
-
+
bc_emit_bytecode (constP);
r = output_constant_def (exp);
bc_emit_code_labelref (BYTECODE_LABEL (r), BYTECODE_BC_LABEL (r)->offset);
@@ -9948,11 +10103,11 @@ bc_expand_constructor (constr)
HOST_WIDE_INT ptroffs;
rtx constr_rtx;
-
+
/* Literal constructors are handled as constants, whereas
non-literals are evaluated and stored element by element
into the data segment. */
-
+
/* Allocate space in proper segment and push pointer to space on stack.
*/
@@ -9973,7 +10128,7 @@ bc_expand_constructor (constr)
bc_output_data_constructor (constr);
}
-
+
/* Add reference to pointer table and recall pointer to stack;
this code is common for both types of constructors: literals
and non-literals. */
@@ -9988,15 +10143,15 @@ bc_expand_constructor (constr)
/* At this point, we have the pointer to the structure on top of the stack.
Generate sequences of store_memory calls for the constructor. */
-
+
/* constructor type is structure */
if (TREE_CODE (TREE_TYPE (constr)) == RECORD_TYPE)
{
register tree elt;
-
+
/* If the constructor has fewer fields than the structure,
clear the whole structure first. */
-
+
if (list_length (CONSTRUCTOR_ELTS (constr))
!= list_length (TYPE_FIELDS (TREE_TYPE (constr))))
{
@@ -10004,10 +10159,10 @@ bc_expand_constructor (constr)
bc_emit_instruction (constSI, (HOST_WIDE_INT) int_size_in_bytes (TREE_TYPE (constr)));
bc_emit_instruction (clearBLK);
}
-
+
/* Store each element of the constructor into the corresponding
field of TARGET. */
-
+
for (elt = CONSTRUCTOR_ELTS (constr); elt; elt = TREE_CHAIN (elt))
{
register tree field = TREE_PURPOSE (elt);
@@ -10015,13 +10170,13 @@ bc_expand_constructor (constr)
int bitsize;
int bitpos;
int unsignedp;
-
+
bitsize = TREE_INT_CST_LOW (DECL_SIZE (field)) /* * DECL_SIZE_UNIT (field) */;
mode = DECL_MODE (field);
unsignedp = TREE_UNSIGNED (field);
bitpos = TREE_INT_CST_LOW (DECL_FIELD_BITPOS (field));
-
+
bc_store_field (elt, bitsize, bitpos, mode, TREE_VALUE (elt), TREE_TYPE (TREE_VALUE (elt)),
/* The alignment of TARGET is
at least what its type requires. */
@@ -10031,7 +10186,7 @@ bc_expand_constructor (constr)
}
}
else
-
+
/* Constructor type is array */
if (TREE_CODE (TREE_TYPE (constr)) == ARRAY_TYPE)
{
@@ -10041,21 +10196,21 @@ bc_expand_constructor (constr)
int minelt = TREE_INT_CST_LOW (TYPE_MIN_VALUE (domain));
int maxelt = TREE_INT_CST_LOW (TYPE_MAX_VALUE (domain));
tree elttype = TREE_TYPE (TREE_TYPE (constr));
-
+
/* If the constructor has fewer fields than the structure,
clear the whole structure first. */
-
+
if (list_length (CONSTRUCTOR_ELTS (constr)) < maxelt - minelt + 1)
{
bc_emit_instruction (duplicate);
bc_emit_instruction (constSI, (HOST_WIDE_INT) int_size_in_bytes (TREE_TYPE (constr)));
bc_emit_instruction (clearBLK);
}
-
-
+
+
/* Store each element of the constructor into the corresponding
element of TARGET, determined by counting the elements. */
-
+
for (elt = CONSTRUCTOR_ELTS (constr), i = 0;
elt;
elt = TREE_CHAIN (elt), i++)
@@ -10064,14 +10219,14 @@ bc_expand_constructor (constr)
int bitsize;
int bitpos;
int unsignedp;
-
+
mode = TYPE_MODE (elttype);
bitsize = GET_MODE_BITSIZE (mode);
unsignedp = TREE_UNSIGNED (elttype);
-
+
bitpos = (i * TREE_INT_CST_LOW (TYPE_SIZE (elttype))
/* * TYPE_SIZE_UNIT (elttype) */ );
-
+
bc_store_field (elt, bitsize, bitpos, mode,
TREE_VALUE (elt), TREE_TYPE (TREE_VALUE (elt)),
/* The alignment of TARGET is
@@ -10080,7 +10235,7 @@ bc_expand_constructor (constr)
TYPE_ALIGN (TREE_TYPE (constr)) / BITS_PER_UNIT,
int_size_in_bytes (TREE_TYPE (constr)));
}
-
+
}
}
@@ -10156,7 +10311,7 @@ bc_load_bit_field (offset, size, unsignedp)
/* Load: sign-extend if signed, else zero-extend */
bc_emit_instruction (unsignedp ? zxloadBI : sxloadBI);
-}
+}
/* Adjust interpreter stack by NLEVELS. Positive means drop NLEVELS
@@ -10172,16 +10327,16 @@ bc_adjust_stack (nlevels)
{
case 0:
break;
-
+
case 2:
bc_emit_instruction (drop);
-
+
case 1:
bc_emit_instruction (drop);
break;
-
+
default:
-
+
bc_emit_instruction (adjstackSI, (HOST_WIDE_INT) nlevels);
stack_depth -= nlevels;
}
diff --git a/gnu/usr.bin/cc/cc_int/final.c b/gnu/usr.bin/cc/cc_int/final.c
index 74d01e9..0bfc892 100644
--- a/gnu/usr.bin/cc/cc_int/final.c
+++ b/gnu/usr.bin/cc/cc_int/final.c
@@ -110,7 +110,7 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
#define IS_ASM_LOGICAL_LINE_SEPARATOR(C) ((C) == ';')
#endif
-/* Nonzero means this function is a leaf function, with no function calls.
+/* Nonzero means this function is a leaf function, with no function calls.
This variable exists to be examined in FUNCTION_PROLOGUE
and FUNCTION_EPILOGUE. Always zero, unless set by some action. */
int leaf_function;
@@ -333,6 +333,8 @@ end_final (filename)
ASM_OUTPUT_ALIGN (asm_out_file, align);
+ fprintf(asm_out_file,".stabs \"bbset\", 25, 0, 0, LPBX0\n");
+
ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "LPBX", 0);
/* zero word */
assemble_integer (const0_rtx, UNITS_PER_WORD, 1);
@@ -518,7 +520,7 @@ app_disable ()
}
}
-/* Return the number of slots filled in the current
+/* Return the number of slots filled in the current
delayed branch sequence (we don't count the insn needing the
delay slot). Zero if not in a delayed branch sequence. */
@@ -661,7 +663,7 @@ shorten_branches (first)
insn_addresses[uid] = insn_current_address;
insn_lengths[uid] = 0;
varying_length[uid] = 0;
-
+
if (GET_CODE (insn) == NOTE || GET_CODE (insn) == BARRIER
|| GET_CODE (insn) == CODE_LABEL)
continue;
@@ -709,7 +711,7 @@ shorten_branches (first)
* insn_default_length (inner_insn));
else
inner_length = insn_default_length (inner_insn);
-
+
insn_lengths[inner_uid] = inner_length;
if (const_delay_slots)
{
@@ -760,7 +762,7 @@ shorten_branches (first)
if (GET_CODE (insn) == INSN && GET_CODE (PATTERN (insn)) == SEQUENCE)
{
int i;
-
+
body = PATTERN (insn);
new_length = 0;
for (i = 0; i < XVECLEN (body, 0); i++)
@@ -824,9 +826,13 @@ asm_insn_count (body)
char *template;
int count = 1;
- for (template = decode_asm_operands (body, NULL_PTR, NULL_PTR,
- NULL_PTR, NULL_PTR);
- *template; template++)
+ if (GET_CODE (body) == ASM_INPUT)
+ template = XSTR (body, 0);
+ else
+ template = decode_asm_operands (body, NULL_PTR, NULL_PTR,
+ NULL_PTR, NULL_PTR);
+
+ for ( ; *template; template++)
if (IS_ASM_LOGICAL_LINE_SEPARATOR(*template) || *template == '\n')
count++;
@@ -866,7 +872,7 @@ final_start_function (first, file, optimize)
regs_ever_live[i] = 1;
}
#endif
-
+
/* Initial line number is supposed to be output
before the function's prologue and label
so that the function's address will not appear to be
@@ -886,7 +892,7 @@ final_start_function (first, file, optimize)
last_linenum = NOTE_LINE_NUMBER (first);
xcoffout_output_first_source_line (file, last_linenum);
}
-#endif
+#endif
else
output_source_line (file, first);
}
@@ -898,6 +904,8 @@ final_start_function (first, file, optimize)
/* The Sun386i and perhaps other machines don't work right
if the profiling code comes after the prologue. */
+ if (profile_block_flag)
+ add_bb (file);
#ifdef PROFILE_BEFORE_PROLOGUE
if (profile_flag)
profile_function (file);
@@ -1051,6 +1059,9 @@ final_end_function (first, file, optimize)
code to restore the stack frame and return to the caller. */
FUNCTION_EPILOGUE (file, get_frame_size ());
#endif
+ if (profile_block_flag)
+ add_bb (file);
+
#ifdef SDB_DEBUGGING_INFO
if (write_symbols == SDB_DEBUG)
@@ -1457,7 +1468,7 @@ final_scan_insn (insn, file, optimize, prescan, nopeepholes)
#ifdef ASM_OUTPUT_ALIGN_CODE
/* Don't litter the assembler output with needless alignments. A
BARRIER will be placed at the end of every function if HAVE_epilogue
- is true. */
+ is true. */
if (NEXT_INSN (insn))
ASM_OUTPUT_ALIGN_CODE (file);
#endif
@@ -1971,11 +1982,11 @@ final_scan_insn (insn, file, optimize, prescan, nopeepholes)
/* If we didn't split the insn, go away. */
if (new == insn && PATTERN (new) == body)
abort ();
-
+
new_block = 0;
return new;
}
-
+
if (prescan > 0)
break;
@@ -2420,7 +2431,7 @@ output_asm_insn (template, operands)
}
else
output_operand (operands[c], letter);
-
+
while ((c = *p) >= '0' && c <= '9') p++;
}
/* % followed by a digit outputs an operand the default way. */
@@ -2455,7 +2466,7 @@ output_asm_insn (template, operands)
if (debug_insn)
{
register int num = INSN_CODE (debug_insn);
- fprintf (asm_out_file, " %s %d %s",
+ fprintf (asm_out_file, " %s %d %s",
ASM_COMMENT_START, INSN_UID (debug_insn), insn_name[num]);
if (insn_n_alternatives[num] > 1)
fprintf (asm_out_file, "/%d", which_alternative + 1);
diff --git a/gnu/usr.bin/cc/cc_int/flow.c b/gnu/usr.bin/cc/cc_int/flow.c
index cc9fed9..09067de 100644
--- a/gnu/usr.bin/cc/cc_int/flow.c
+++ b/gnu/usr.bin/cc/cc_int/flow.c
@@ -57,7 +57,7 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
register. The bit is 1 if the register is live at the beginning
of the basic block.
- Two types of elements can be added to an insn's REG_NOTES.
+ Two types of elements can be added to an insn's REG_NOTES.
A REG_DEAD note is added to an insn's REG_NOTES for any register
that meets both of two conditions: The value in the register is not
needed in subsequent insns and the insn does not replace the value in
@@ -177,6 +177,12 @@ int *reg_basic_block;
int *reg_n_refs;
+/* Indexed by N; says whether a psuedo register N was ever used
+ within a SUBREG that changes the size of the reg. Some machines prohibit
+ such objects to be in certain (usually floating-point) registers. */
+
+char *reg_changes_size;
+
/* Indexed by N, gives number of places register N dies.
This information remains valid for the rest of the compilation
of the current function; it is used to control register allocation. */
@@ -285,7 +291,7 @@ static void mark_label_ref PROTO((rtx, rtx, int));
static void life_analysis PROTO((rtx, int));
void allocate_for_life_analysis PROTO((void));
static void init_regset_vector PROTO((regset *, regset, int, int));
-static void propagate_block PROTO((regset, rtx, rtx, int,
+static void propagate_block PROTO((regset, rtx, rtx, int,
regset, int));
static int insn_dead_p PROTO((rtx, regset, int));
static int libcall_dead_p PROTO((rtx, regset, rtx, rtx));
@@ -543,7 +549,7 @@ find_basic_blocks (f, nonlocal_label_list)
&& SET_DEST (pat) == pc_rtx
&& uses_reg_or_mem (SET_SRC (pat)))
computed_jump = 1;
-
+
if (computed_jump)
{
for (x = label_value_list; x; x = XEXP (x, 1))
@@ -602,6 +608,20 @@ find_basic_blocks (f, nonlocal_label_list)
}
}
+ /* ??? See if we have a "live" basic block that is not reachable.
+ This can happen if it is headed by a label that is preserved or
+ in one of the label lists, but no call or computed jump is in
+ the loop. It's not clear if we can delete the block or not,
+ but don't for now. However, we will mess up register status if
+ it remains unreachable, so add a fake reachability from the
+ previous block. */
+
+ for (i = 1; i < n_basic_blocks; i++)
+ if (block_live[i] && ! basic_block_drops_in[i]
+ && GET_CODE (basic_block_head[i]) == CODE_LABEL
+ && LABEL_REFS (basic_block_head[i]) == basic_block_head[i])
+ basic_block_drops_in[i] = 1;
+
/* Now delete the code for any basic blocks that can't be reached.
They can occur because jump_optimize does not recognize
unreachable loops as unreachable. */
@@ -874,14 +894,14 @@ life_analysis (f, nregs)
if (GET_CODE (tem) == USE
|| GET_CODE (tem) == CLOBBER)
continue;
-
+
if (GET_CODE (tem) != SET
|| GET_CODE (SET_DEST (tem)) != REG
|| GET_CODE (SET_SRC (tem)) != REG
|| REGNO (SET_DEST (tem)) != REGNO (SET_SRC (tem)))
break;
}
-
+
if (i == XVECLEN (PATTERN (insn), 0)
/* Insns carrying these notes are useful later on. */
&& ! find_reg_note (insn, REG_EQUAL, NULL_RTX))
@@ -951,7 +971,7 @@ life_analysis (f, nregs)
[HARD_FRAME_POINTER_REGNUM / REGSET_ELT_BITS]
|= (REGSET_ELT_TYPE) 1 << (HARD_FRAME_POINTER_REGNUM
% REGSET_ELT_BITS);
-#endif
+#endif
}
/* Mark all global registers as being live at the end of the function
@@ -1055,18 +1075,18 @@ life_analysis (f, nregs)
{
register rtx jump, head;
+
/* Update the basic_block_new_live_at_end's of the block
that falls through into this one (if any). */
head = basic_block_head[i];
- jump = PREV_INSN (head);
if (basic_block_drops_in[i])
{
- register int from_block = BLOCK_NUM (jump);
register int j;
for (j = 0; j < regset_size; j++)
- basic_block_new_live_at_end[from_block][j]
+ basic_block_new_live_at_end[i-1][j]
|= basic_block_live_at_start[i][j];
}
+
/* Update the basic_block_new_live_at_end's of
all the blocks that jump to this one. */
if (GET_CODE (head) == CODE_LABEL)
@@ -1183,6 +1203,9 @@ allocate_for_life_analysis ()
reg_n_deaths = (short *) oballoc (max_regno * sizeof (short));
bzero ((char *) reg_n_deaths, max_regno * sizeof (short));
+ reg_changes_size = (char *) oballoc (max_regno * sizeof (char));
+ bzero (reg_changes_size, max_regno * sizeof (char));;
+
reg_live_length = (int *) oballoc (max_regno * sizeof (int));
bzero ((char *) reg_live_length, max_regno * sizeof (int));
@@ -1340,7 +1363,7 @@ propagate_block (old, first, last, final, significant, bnum)
&& NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_BEG)
loop_depth--;
- /* If we have LOOP_DEPTH == 0, there has been a bookkeeping error.
+ /* If we have LOOP_DEPTH == 0, there has been a bookkeeping error.
Abort now rather than setting register status incorrectly. */
if (loop_depth == 0)
abort ();
@@ -1371,7 +1394,7 @@ propagate_block (old, first, last, final, significant, bnum)
= (insn_dead_p (PATTERN (insn), old, 0)
/* Don't delete something that refers to volatile storage! */
&& ! INSN_VOLATILE (insn));
- int libcall_is_dead
+ int libcall_is_dead
= (insn_is_dead && note != 0
&& libcall_dead_p (PATTERN (insn), old, note, insn));
@@ -1467,7 +1490,7 @@ propagate_block (old, first, last, final, significant, bnum)
mark_set_regs (old, dead, PATTERN (insn),
final ? insn : NULL_RTX, significant);
- /* If an insn doesn't use CC0, it becomes dead since we
+ /* If an insn doesn't use CC0, it becomes dead since we
assume that every insn clobbers it. So show it dead here;
mark_used_regs will set it live if it is referenced. */
cc0_live = 0;
@@ -1512,11 +1535,11 @@ propagate_block (old, first, last, final, significant, bnum)
/* Calls may also reference any of the global registers,
so they are made live. */
-
for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
if (global_regs[i])
- live[i / REGSET_ELT_BITS]
- |= ((REGSET_ELT_TYPE) 1 << (i % REGSET_ELT_BITS));
+ mark_used_regs (old, live,
+ gen_rtx (REG, reg_raw_mode[i], i),
+ final, insn);
/* Calls also clobber memory. */
last_mem_set = 0;
@@ -1614,7 +1637,7 @@ insn_dead_p (x, needed, call_ok)
if (GET_CODE (r) == CC0)
return ! cc0_live;
#endif
-
+
if (GET_CODE (r) == MEM && last_mem_set && ! MEM_VOLATILE_P (r)
&& rtx_equal_p (r, last_mem_set))
return 1;
@@ -1857,9 +1880,9 @@ mark_set_1 (needed, dead, x, insn, significant)
|| (GET_CODE (reg) == REG
&& last_mem_set != 0 && reg_overlap_mentioned_p (reg, last_mem_set)))
last_mem_set = 0;
-
+
if (GET_CODE (reg) == MEM && ! side_effects_p (reg)
- /* There are no REG_INC notes for SP, so we can't assume we'll see
+ /* There are no REG_INC notes for SP, so we can't assume we'll see
everything that invalidates it. To be safe, don't eliminate any
stores though SP; none of them should be redundant anyway. */
&& ! reg_mentioned_p (stack_pointer_rtx, reg))
@@ -1952,7 +1975,7 @@ mark_set_1 (needed, dead, x, insn, significant)
reg_n_sets[regno]++;
reg_n_refs[regno] += loop_depth;
-
+
/* The insns where a reg is live are normally counted
elsewhere, but we want the count to include the insn
where the reg is set, and the normal counting mechanism
@@ -2081,11 +2104,21 @@ find_auto_inc (needed, x, insn)
&& (use = find_use_as_address (PATTERN (insn), addr, offset),
use != 0 && use != (rtx) 1))
{
- int win = 0;
rtx q = SET_DEST (set);
+ enum rtx_code inc_code = (INTVAL (XEXP (y, 1)) == size
+ ? (offset ? PRE_INC : POST_INC)
+ : (offset ? PRE_DEC : POST_DEC));
if (dead_or_set_p (incr, addr))
- win = 1;
+ {
+ /* This is the simple case. Try to make the auto-inc. If
+ we can't, we are done. Otherwise, we will do any
+ needed updates below. */
+ if (! validate_change (insn, &XEXP (x, 0),
+ gen_rtx (inc_code, Pmode, addr),
+ 0))
+ return;
+ }
else if (GET_CODE (q) == REG
/* PREV_INSN used here to check the semi-open interval
[insn,incr). */
@@ -2113,17 +2146,28 @@ find_auto_inc (needed, x, insn)
BLOCK_NUM (temp) = BLOCK_NUM (insn);
}
+ /* If we can't make the auto-inc, or can't make the
+ replacement into Y, exit. There's no point in making
+ the change below if we can't do the auto-inc and doing
+ so is not correct in the pre-inc case. */
+
+ validate_change (insn, &XEXP (x, 0),
+ gen_rtx (inc_code, Pmode, q),
+ 1);
+ validate_change (incr, &XEXP (y, 0), q, 1);
+ if (! apply_change_group ())
+ return;
+
+ /* We now know we'll be doing this change, so emit the
+ new insn(s) and do the updates. */
emit_insns_before (insns, insn);
if (basic_block_head[BLOCK_NUM (insn)] == insn)
basic_block_head[BLOCK_NUM (insn)] = insns;
- XEXP (x, 0) = q;
- XEXP (y, 0) = q;
-
/* INCR will become a NOTE and INSN won't contain a
use of ADDR. If a use of ADDR was just placed in
- the insn before INSN, make that the next use.
+ the insn before INSN, make that the next use.
Otherwise, invalidate it. */
if (GET_CODE (PREV_INSN (insn)) == INSN
&& GET_CODE (PATTERN (PREV_INSN (insn))) == SET
@@ -2134,7 +2178,6 @@ find_auto_inc (needed, x, insn)
addr = q;
regno = REGNO (q);
- win = 1;
/* REGNO is now used in INCR which is below INSN, but
it previously wasn't live here. If we don't mark
@@ -2149,47 +2192,41 @@ find_auto_inc (needed, x, insn)
if (GET_CODE (temp) == CALL_INSN)
reg_n_calls_crossed[regno]++;
}
+ else
+ return;
+
+ /* If we haven't returned, it means we were able to make the
+ auto-inc, so update the status. First, record that this insn
+ has an implicit side effect. */
- if (win
- /* If we have found a suitable auto-increment, do
- POST_INC around the register here, and patch out the
- increment instruction that follows. */
- && validate_change (insn, &XEXP (x, 0),
- gen_rtx ((INTVAL (XEXP (y, 1)) == size
- ? (offset ? PRE_INC : POST_INC)
- : (offset ? PRE_DEC : POST_DEC)),
- Pmode, addr), 0))
+ REG_NOTES (insn)
+ = gen_rtx (EXPR_LIST, REG_INC, addr, REG_NOTES (insn));
+
+ /* Modify the old increment-insn to simply copy
+ the already-incremented value of our register. */
+ if (! validate_change (incr, &SET_SRC (set), addr, 0))
+ abort ();
+
+ /* If that makes it a no-op (copying the register into itself) delete
+ it so it won't appear to be a "use" and a "set" of this
+ register. */
+ if (SET_DEST (set) == addr)
{
- /* Record that this insn has an implicit side effect. */
- REG_NOTES (insn)
- = gen_rtx (EXPR_LIST, REG_INC, addr, REG_NOTES (insn));
-
- /* Modify the old increment-insn to simply copy
- the already-incremented value of our register. */
- SET_SRC (set) = addr;
- /* Indicate insn must be re-recognized. */
- INSN_CODE (incr) = -1;
-
- /* If that makes it a no-op (copying the register into itself)
- then delete it so it won't appear to be a "use" and a "set"
- of this register. */
- if (SET_DEST (set) == addr)
- {
- PUT_CODE (incr, NOTE);
- NOTE_LINE_NUMBER (incr) = NOTE_INSN_DELETED;
- NOTE_SOURCE_FILE (incr) = 0;
- }
+ PUT_CODE (incr, NOTE);
+ NOTE_LINE_NUMBER (incr) = NOTE_INSN_DELETED;
+ NOTE_SOURCE_FILE (incr) = 0;
+ }
- if (regno >= FIRST_PSEUDO_REGISTER)
- {
- /* Count an extra reference to the reg. When a reg is
- incremented, spilling it is worse, so we want to make
- that less likely. */
- reg_n_refs[regno] += loop_depth;
- /* Count the increment as a setting of the register,
- even though it isn't a SET in rtl. */
- reg_n_sets[regno]++;
- }
+ if (regno >= FIRST_PSEUDO_REGISTER)
+ {
+ /* Count an extra reference to the reg. When a reg is
+ incremented, spilling it is worse, so we want to make
+ that less likely. */
+ reg_n_refs[regno] += loop_depth;
+
+ /* Count the increment as a setting of the register,
+ even though it isn't a SET in rtl. */
+ reg_n_sets[regno]++;
}
}
}
@@ -2257,6 +2294,20 @@ mark_used_regs (needed, live, x, final, insn)
#endif
break;
+ case SUBREG:
+ if (GET_CODE (SUBREG_REG (x)) == REG
+ && REGNO (SUBREG_REG (x)) >= FIRST_PSEUDO_REGISTER
+ && (GET_MODE_SIZE (GET_MODE (x))
+ != GET_MODE_SIZE (GET_MODE (SUBREG_REG (x))))
+ && (INTEGRAL_MODE_P (GET_MODE (x))
+ || INTEGRAL_MODE_P (GET_MODE (SUBREG_REG (x)))))
+ reg_changes_size[REGNO (SUBREG_REG (x))] = 1;
+
+ /* While we're here, optimize this case. */
+ x = SUBREG_REG (x);
+
+ /* ... fall through ... */
+
case REG:
/* See a register other than being set
=> mark it as needed. */
@@ -2368,6 +2419,16 @@ mark_used_regs (needed, live, x, final, insn)
#endif
)
{
+ /* Check for the case where the register dying partially
+ overlaps the register set by this insn. */
+ if (regno < FIRST_PSEUDO_REGISTER
+ && HARD_REGNO_NREGS (regno, GET_MODE (x)) > 1)
+ {
+ int n = HARD_REGNO_NREGS (regno, GET_MODE (x));
+ while (--n >= 0)
+ some_needed |= dead_or_set_regno_p (insn, regno + n);
+ }
+
/* If none of the words in X is needed, make a REG_DEAD
note. Otherwise, we must make partial REG_DEAD notes. */
if (! some_needed)
@@ -2417,7 +2478,7 @@ mark_used_regs (needed, live, x, final, insn)
mark_used_regs (needed, live, SET_SRC (x), final, insn);
return;
}
-
+
/* Storing in STRICT_LOW_PART is like storing in a reg
in that this SET might be dead, so ignore it in TESTREG.
but in some other ways it is like using the reg.
@@ -2489,7 +2550,7 @@ mark_used_regs (needed, live, x, final, insn)
{
register char *fmt = GET_RTX_FORMAT (code);
register int i;
-
+
for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
{
if (fmt[i] == 'e')
diff --git a/gnu/usr.bin/cc/cc_int/fold-const.c b/gnu/usr.bin/cc/cc_int/fold-const.c
index 0417aab..10093f5 100644
--- a/gnu/usr.bin/cc/cc_int/fold-const.c
+++ b/gnu/usr.bin/cc/cc_int/fold-const.c
@@ -36,7 +36,7 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
size_int takes an integer value, and creates a tree constant
with type from `sizetype'. */
-
+
#include <stdio.h>
#include <setjmp.h>
#include "config.h"
@@ -334,7 +334,7 @@ lshift_double (l1, h1, count, prec, lv, hv, arith)
rshift_double (l1, h1, - count, prec, lv, hv, arith);
return;
}
-
+
if (count >= prec)
count = (unsigned HOST_WIDE_INT) count & prec;
@@ -496,7 +496,7 @@ div_and_round_double (code, uns,
abort ();
/* calculate quotient sign and convert operands to unsigned. */
- if (!uns)
+ if (!uns)
{
if (hnum < 0)
{
@@ -505,7 +505,7 @@ div_and_round_double (code, uns,
if (neg_double (lnum, hnum, &lnum, &hnum) && (lden & hden) == -1)
overflow = 1;
}
- if (hden < 0)
+ if (hden < 0)
{
quo_neg = ~ quo_neg;
neg_double (lden, hden, &lden, &hden);
@@ -534,7 +534,7 @@ div_and_round_double (code, uns,
bzero ((char *) num, sizeof num); /* to zero 9th element */
bzero ((char *) den, sizeof den);
- encode (num, lnum, hnum);
+ encode (num, lnum, hnum);
encode (den, lden, hden);
/* Special code for when the divisor < BASE. */
@@ -677,7 +677,7 @@ div_and_round_double (code, uns,
}
else return overflow;
break;
-
+
case ROUND_DIV_EXPR:
case ROUND_MOD_EXPR: /* round to closest integer */
{
@@ -760,7 +760,7 @@ target_isinf (x)
unsigned mantissa1 : 20;
unsigned exponent : 11;
unsigned sign : 1;
- } big_endian;
+ } big_endian;
} u;
u.d = dconstm1;
@@ -800,7 +800,7 @@ target_isnan (x)
unsigned mantissa1 : 20;
unsigned exponent : 11;
unsigned sign : 1;
- } big_endian;
+ } big_endian;
} u;
u.d = dconstm1;
@@ -840,7 +840,7 @@ target_negative (x)
unsigned mantissa1 : 20;
unsigned exponent : 11;
unsigned sign : 1;
- } big_endian;
+ } big_endian;
} u;
u.d = dconstm1;
@@ -1104,7 +1104,7 @@ const_binop (code, arg1, arg2, notrunc)
int1l += int2l-1;
return size_int (int1l / int2l);
}
- case ROUND_DIV_EXPR:
+ case ROUND_DIV_EXPR:
if (int2h == 0 && int2l == 1)
{
t = build_int_2 (int1l, int1h);
@@ -1123,7 +1123,7 @@ const_binop (code, arg1, arg2, notrunc)
t = build_int_2 (low, hi);
break;
- case TRUNC_MOD_EXPR: case ROUND_MOD_EXPR:
+ case TRUNC_MOD_EXPR: case ROUND_MOD_EXPR:
case FLOOR_MOD_EXPR: case CEIL_MOD_EXPR:
overflow = div_and_round_double (code, uns,
int1l, int1h, int2l, int2h,
@@ -1404,6 +1404,11 @@ fold_convert (t, arg1)
{
if (TREE_CODE (arg1) == INTEGER_CST)
{
+ /* If we would build a constant wider than GCC supports,
+ leave the conversion unfolded. */
+ if (TYPE_PRECISION (type) > 2 * HOST_BITS_PER_WIDE_INT)
+ return t;
+
/* Given an integer constant, make new constant with new type,
appropriately sign-extended or truncated. */
t = build_int_2 (TREE_INT_CST_LOW (arg1),
@@ -1743,11 +1748,11 @@ operand_equal_p (arg0, arg1, only_const)
}
/* Similar to operand_equal_p, but see if ARG0 might have been made by
- shorten_compare from ARG1 when ARG1 was being compared with OTHER.
+ shorten_compare from ARG1 when ARG1 was being compared with OTHER.
When in doubt, return 0. */
-static int
+static int
operand_equal_for_comparison_p (arg0, arg1, other)
tree arg0, arg1;
tree other;
@@ -1856,7 +1861,7 @@ twoval_comparison_p (arg, cval1, cval2, save_p)
&& twoval_comparison_p (TREE_OPERAND (arg, 2),
cval1, cval2, save_p));
return 0;
-
+
case '<':
/* First see if we can handle the first operand, then the second. For
the second operand, we know *CVAL1 can't be zero. It must be that
@@ -2242,13 +2247,13 @@ optimize_bit_field_compare (code, compare_type, lhs, rhs)
if (! const_p)
{
- rnmode = get_best_mode (rbitsize, rbitpos,
+ rnmode = get_best_mode (rbitsize, rbitpos,
TYPE_ALIGN (TREE_TYPE (rinner)), word_mode,
rvolatilep);
if (rnmode == VOIDmode)
return 0;
}
-
+
/* Compute the bit position and size for the new reference and our offset
within it. If the new reference is the same size as the original, we
won't optimize anything, so return zero. */
@@ -2299,7 +2304,7 @@ optimize_bit_field_compare (code, compare_type, lhs, rhs)
error case below. If we didn't, we might generate wrong code.
For unsigned fields, the constant shifted right by the field length should
- be all zero. For signed fields, the high-order bits should agree with
+ be all zero. For signed fields, the high-order bits should agree with
the sign bit. */
if (lunsignedp)
@@ -2392,7 +2397,7 @@ decode_field_reference (exp, pbitsize, pbitpos, pmode, punsignedp,
tree unsigned_type;
int precision;
- /* All the optimizations using this function assume integer fields.
+ /* All the optimizations using this function assume integer fields.
There are problems with FP fields since the type_for_size call
below can fail for, e.g., XFmode. */
if (! INTEGRAL_TYPE_P (TREE_TYPE (exp)))
@@ -2417,7 +2422,7 @@ decode_field_reference (exp, pbitsize, pbitpos, pmode, punsignedp,
punsignedp, pvolatilep);
if (inner == exp || *pbitsize < 0 || offset != 0)
return 0;
-
+
/* Compute the mask to access the bitfield. */
unsigned_type = type_for_size (*pbitsize, 1);
precision = TYPE_PRECISION (unsigned_type);
@@ -2453,7 +2458,7 @@ all_ones_mask_p (mask, size)
TREE_TYPE (tmask) = signed_type (type);
force_fit_type (tmask, 0);
return
- operand_equal_p (mask,
+ operand_equal_p (mask,
const_binop (RSHIFT_EXPR,
const_binop (LSHIFT_EXPR, tmask,
size_int (precision - size), 0),
@@ -2464,7 +2469,7 @@ all_ones_mask_p (mask, size)
/* Subroutine for fold_truthop: determine if an operand is simple enough
to be evaluated unconditionally. */
-static int
+static int
simple_operand_p (exp)
tree exp;
{
@@ -2645,7 +2650,7 @@ fold_truthop (code, truth_type, lhs, rhs)
{
/* If this is the "or" of two comparisons, we can do something if we
the comparisons are NE_EXPR. If this is the "and", we can do something
- if the comparisons are EQ_EXPR. I.e.,
+ if the comparisons are EQ_EXPR. I.e.,
(a->b == 2 && a->c == 4) can become (a->new == NEW).
WANTED_CODE is this operation code. For single bit fields, we can
@@ -2698,7 +2703,7 @@ fold_truthop (code, truth_type, lhs, rhs)
lr_arg = TREE_OPERAND (lhs, 1);
rl_arg = TREE_OPERAND (rhs, 0);
rr_arg = TREE_OPERAND (rhs, 1);
-
+
if (TREE_CODE (lr_arg) == INTEGER_CST
&& TREE_CODE (rr_arg) == INTEGER_CST
&& operand_equal_p (ll_arg, rl_arg, 0))
@@ -3000,7 +3005,7 @@ strip_compound_expr (t, s)
but we can constant-fold them if they have constant operands. */
tree
-fold (expr)
+fold (expr)
tree expr;
{
register tree t = expr;
@@ -3028,7 +3033,7 @@ fold (expr)
return DECL_INITIAL (t);
return t;
}
-
+
kind = TREE_CODE_CLASS (code);
if (code == NOP_EXPR || code == FLOAT_EXPR || code == CONVERT_EXPR)
{
@@ -3080,7 +3085,7 @@ fold (expr)
/* Strip any conversions that don't change the mode. */
STRIP_NOPS (op);
}
-
+
if (TREE_CODE (op) == COMPLEX_CST)
subop = TREE_REALPART (op);
else
@@ -3131,7 +3136,7 @@ fold (expr)
one of the operands is a comparison and the other is a comparison, a
BIT_AND_EXPR with the constant 1, or a truth value. In that case, the
code below would make the expression more complex. Change it to a
- TRUTH_{AND,OR}_EXPR. Likewise, convert a similar NE_EXPR to
+ TRUTH_{AND,OR}_EXPR. Likewise, convert a similar NE_EXPR to
TRUTH_XOR_EXPR and an EQ_EXPR to the inversion of a TRUTH_XOR_EXPR. */
if ((code == BIT_AND_EXPR || code == BIT_IOR_EXPR
@@ -3187,7 +3192,7 @@ fold (expr)
TREE_OPERAND (TREE_OPERAND (t, 2), 0)));
return t;
}
- else if (TREE_CODE_CLASS (TREE_CODE (arg0)) == '<')
+ else if (TREE_CODE_CLASS (TREE_CODE (arg0)) == '<')
return fold (build (COND_EXPR, type, arg0,
fold (build1 (code, type, integer_one_node)),
fold (build1 (code, type, integer_zero_node))));
@@ -3306,7 +3311,7 @@ fold (expr)
&& TREE_CODE (arg1) == COMPOUND_EXPR)
return build (COMPOUND_EXPR, type, TREE_OPERAND (arg1, 0),
fold (build (code, type, arg0, TREE_OPERAND (arg1, 1))));
-
+
switch (code)
{
case INTEGER_CST:
@@ -3325,7 +3330,7 @@ fold (expr)
case FIX_TRUNC_EXPR:
/* Other kinds of FIX are not handled properly by fold_convert. */
- /* In addition to the cases of two conversions in a row
+ /* In addition to the cases of two conversions in a row
handled below, if we are converting something to its own
type via an object of identical or wider precision, neither
conversion is needed. */
@@ -3346,7 +3351,7 @@ fold (expr)
and the outermost type is wider than the intermediate, or
- the initial type is a pointer type and the precisions of the
intermediate and final types differ, or
- - the final type is a pointer type and the precisions of the
+ - the final type is a pointer type and the precisions of the
initial and intermediate types differ. */
if ((TREE_CODE (TREE_OPERAND (t, 0)) == NOP_EXPR
|| TREE_CODE (TREE_OPERAND (t, 0)) == CONVERT_EXPR)
@@ -3420,6 +3425,15 @@ fold (expr)
return t;
#endif /* 0 */
+ case COMPONENT_REF:
+ if (TREE_CODE (arg0) == CONSTRUCTOR)
+ {
+ tree m = purpose_member (arg1, CONSTRUCTOR_ELTS (arg0));
+ if (m)
+ t = TREE_VALUE (m);
+ }
+ return t;
+
case RANGE_EXPR:
TREE_CONSTANT (t) = wins;
return t;
@@ -3596,7 +3610,7 @@ fold (expr)
/* If it is + and VAR==ARG1, return just CONST. */
if (code == PLUS_EXPR && operand_equal_p (var, arg1, 0))
return convert (TREE_TYPE (t), con);
-
+
/* If ARG0 is a constant, don't change things around;
instead keep all the constant computations together. */
@@ -3615,7 +3629,7 @@ fold (expr)
/* If it is - and VAR==ARG1, return just CONST. */
if (code == MINUS_EXPR && operand_equal_p (var, arg1, 0))
return convert (TREE_TYPE (t), con);
-
+
/* If ARG0 is a constant, don't change things around;
instead keep all the constant computations together. */
@@ -3727,14 +3741,14 @@ fold (expr)
return non_lvalue (convert (type, arg0));
}
- /* Fold &x - &x. This can happen from &x.foo - &x.
+ /* Fold &x - &x. This can happen from &x.foo - &x.
This is unsafe for certain floats even in non-IEEE formats.
In IEEE, it is unsafe because it does wrong for NaNs.
Also note that operand_equal_p is always false if an operand
is volatile. */
- if (operand_equal_p (arg0, arg1,
- FLOAT_TYPE_P (type) && ! flag_fast_math))
+ if ((! FLOAT_TYPE_P (type) || flag_fast_math)
+ && operand_equal_p (arg0, arg1, 0))
return convert (type, integer_zero_node);
goto associate;
@@ -3980,7 +3994,7 @@ fold (expr)
C3/C1 at the end of the operation. */
if (tree_int_cst_lt (c1, c3))
outer_div = const_binop (code, c3, c1, 0), c3 = c1;
-
+
/* The result is A * (C1/C3) + (C2/C3). */
t = fold (build (PLUS_EXPR, type,
fold (build (MULT_EXPR, type,
@@ -4350,7 +4364,7 @@ fold (expr)
&& TREE_UNSIGNED (TREE_TYPE (arg0))
&& TREE_CODE (arg1) == LSHIFT_EXPR
&& integer_onep (TREE_OPERAND (arg1, 0)))
- return build (code == LT_EXPR ? EQ_EXPR : NE_EXPR, type,
+ return build (code == LT_EXPR ? EQ_EXPR : NE_EXPR, type,
build (RSHIFT_EXPR, TREE_TYPE (arg0), arg0,
TREE_OPERAND (arg1, 1)),
convert (TREE_TYPE (arg0), integer_zero_node));
@@ -4815,7 +4829,7 @@ fold (expr)
if (integer_onep (TREE_OPERAND (t, 1))
&& integer_zerop (TREE_OPERAND (t, 2))
/* If we try to convert TREE_OPERAND (t, 0) to our type, the
- call to fold will try to move the conversion inside
+ call to fold will try to move the conversion inside
a COND, which will recurse. In that case, the COND_EXPR
is probably the best choice, so leave it alone. */
&& type == TREE_TYPE (arg0))
diff --git a/gnu/usr.bin/cc/cc_int/function.c b/gnu/usr.bin/cc/cc_int/function.c
index 9f33396..2718f6d 100644
--- a/gnu/usr.bin/cc/cc_int/function.c
+++ b/gnu/usr.bin/cc/cc_int/function.c
@@ -152,9 +152,8 @@ int current_function_args_size;
int current_function_pretend_args_size;
-/* # of bytes of outgoing arguments required to be pushed by the prologue.
- If this is non-zero, it means that ACCUMULATE_OUTGOING_ARGS was defined
- and no stack adjusts will be done on function calls. */
+/* # of bytes of outgoing arguments. If ACCUMULATE_OUTGOING_ARGS is
+ defined, the needed space is pushed by the prologue. */
int current_function_outgoing_args_size;
@@ -356,6 +355,8 @@ struct temp_slot
tree rtl_expr;
/* Non-zero if this temporary is currently in use. */
char in_use;
+ /* Non-zero if this temporary has its address taken. */
+ char addr_taken;
/* Nesting level at which this slot is being used. */
int level;
/* Non-zero if this should survive a call to free_temp_slots. */
@@ -406,7 +407,7 @@ struct fixup_replacement
rtx new;
struct fixup_replacement *next;
};
-
+
/* Forward declarations. */
static struct temp_slot *find_temp_slot_from_address PROTO((rtx));
@@ -461,7 +462,8 @@ find_function_data (decl)
since this function knows only about language-independent variables. */
void
-push_function_context ()
+push_function_context_to (toplevel)
+ int toplevel;
{
struct function *p = (struct function *) xmalloc (sizeof (struct function));
@@ -512,7 +514,7 @@ push_function_context ()
p->fixup_var_refs_queue = 0;
p->epilogue_delay_list = current_function_epilogue_delay_list;
- save_tree_status (p);
+ save_tree_status (p, toplevel);
save_storage_status (p);
save_emit_status (p);
init_emit ();
@@ -524,11 +526,18 @@ push_function_context ()
(*save_machine_status) (p);
}
+void
+push_function_context ()
+{
+ push_function_context_to (0);
+}
+
/* Restore the last saved context, at the end of a nested function.
This function is called from language-specific code. */
void
-pop_function_context ()
+pop_function_context_from (toplevel)
+ int toplevel;
{
struct function *p = outer_function_chain;
@@ -545,7 +554,8 @@ pop_function_context ()
current_function_calls_alloca = p->calls_alloca;
current_function_has_nonlocal_label = p->has_nonlocal_label;
current_function_has_nonlocal_goto = p->has_nonlocal_goto;
- current_function_contains_functions = 1;
+ if (! toplevel)
+ current_function_contains_functions = 1;
current_function_args_size = p->args_size;
current_function_pretend_args_size = p->pretend_args_size;
current_function_arg_offset_rtx = p->arg_offset_rtx;
@@ -577,8 +587,9 @@ pop_function_context ()
temp_slots = p->temp_slots;
temp_slot_level = p->temp_slot_level;
current_function_epilogue_delay_list = p->epilogue_delay_list;
+ reg_renumber = 0;
- restore_tree_status (p);
+ restore_tree_status (p, toplevel);
restore_storage_status (p);
restore_expr_status (p);
restore_emit_status (p);
@@ -602,6 +613,11 @@ pop_function_context ()
rtx_equal_function_value_matters = 1;
virtuals_instantiated = 0;
}
+
+void pop_function_context ()
+{
+ pop_function_context_from (0);
+}
/* Allocate fixed slots in the stack frame of the current function. */
@@ -621,7 +637,7 @@ get_frame_size ()
/* Allocate a stack slot of SIZE bytes and return a MEM rtx for it
with machine mode MODE.
-
+
ALIGN controls the amount of alignment for the address of the slot:
0 means according to MODE,
-1 means use BIGGEST_ALIGNMENT and round size to multiple of that,
@@ -784,6 +800,11 @@ assign_stack_temp (mode, size, keep)
{
struct temp_slot *p, *best_p = 0;
+ /* If SIZE is -1 it means that somebody tried to allocate a temporary
+ of a variable size. */
+ if (size == -1)
+ abort ();
+
/* First try to find an available, already-allocated temporary that is the
exact size we require. */
for (p = temp_slots; p; p = p->next)
@@ -812,12 +833,13 @@ assign_stack_temp (mode, size, keep)
if (best_p->size - rounded_size >= alignment)
{
p = (struct temp_slot *) oballoc (sizeof (struct temp_slot));
- p->in_use = 0;
+ p->in_use = p->addr_taken = 0;
p->size = best_p->size - rounded_size;
p->slot = gen_rtx (MEM, BLKmode,
plus_constant (XEXP (best_p->slot, 0),
rounded_size));
p->address = 0;
+ p->rtl_expr = 0;
p->next = temp_slots;
temp_slots = p;
@@ -830,7 +852,7 @@ assign_stack_temp (mode, size, keep)
p = best_p;
}
-
+
/* If we still didn't find one, make a new temporary. */
if (p == 0)
{
@@ -845,7 +867,9 @@ assign_stack_temp (mode, size, keep)
}
p->in_use = 1;
+ p->addr_taken = 0;
p->rtl_expr = sequence_rtl_expr;
+
if (keep == 2)
{
p->level = target_temp_slot_level;
@@ -916,7 +940,7 @@ combine_temp_slots ()
prev_p = p;
}
- /* Free all the RTL made by plus_constant. */
+ /* Free all the RTL made by plus_constant. */
rtx_free (free_pointer);
}
@@ -945,7 +969,7 @@ find_temp_slot_from_address (x)
return 0;
}
-
+
/* Indicate that NEW is an alternate way of refering to the temp slot
that previous was known by OLD. */
@@ -969,6 +993,28 @@ update_temp_slot_address (old, new)
}
}
+/* If X could be a reference to a temporary slot, mark the fact that its
+ adddress was taken. */
+
+void
+mark_temp_addr_taken (x)
+ rtx x;
+{
+ struct temp_slot *p;
+
+ if (x == 0)
+ return;
+
+ /* If X is not in memory or is at a constant address, it cannot be in
+ a temporary slot. */
+ if (GET_CODE (x) != MEM || CONSTANT_P (XEXP (x, 0)))
+ return;
+
+ p = find_temp_slot_from_address (XEXP (x, 0));
+ if (p != 0)
+ p->addr_taken = 1;
+}
+
/* If X could be a reference to a temporary slot, mark that slot as belonging
to the to one level higher. If X matched one of our slots, just mark that
one. Otherwise, we can't easily predict which it is, so upgrade all of
@@ -981,31 +1027,52 @@ void
preserve_temp_slots (x)
rtx x;
{
- struct temp_slot *p;
+ struct temp_slot *p = 0;
+ /* If there is no result, we still might have some objects whose address
+ were taken, so we need to make sure they stay around. */
if (x == 0)
- return;
+ {
+ for (p = temp_slots; p; p = p->next)
+ if (p->in_use && p->level == temp_slot_level && p->addr_taken)
+ p->level--;
+
+ return;
+ }
/* If X is a register that is being used as a pointer, see if we have
a temporary slot we know it points to. To be consistent with
the code below, we really should preserve all non-kept slots
if we can't find a match, but that seems to be much too costly. */
- if (GET_CODE (x) == REG && REGNO_POINTER_FLAG (REGNO (x))
- && (p = find_temp_slot_from_address (x)) != 0)
+ if (GET_CODE (x) == REG && REGNO_POINTER_FLAG (REGNO (x)))
+ p = find_temp_slot_from_address (x);
+
+ /* If X is not in memory or is at a constant address, it cannot be in
+ a temporary slot, but it can contain something whose address was
+ taken. */
+ if (p == 0 && (GET_CODE (x) != MEM || CONSTANT_P (XEXP (x, 0))))
{
- p->level--;
+ for (p = temp_slots; p; p = p->next)
+ if (p->in_use && p->level == temp_slot_level && p->addr_taken)
+ p->level--;
+
return;
}
-
- /* If X is not in memory or is at a constant address, it cannot be in
- a temporary slot. */
- if (GET_CODE (x) != MEM || CONSTANT_P (XEXP (x, 0)))
- return;
/* First see if we can find a match. */
- p = find_temp_slot_from_address (XEXP (x, 0));
+ if (p == 0)
+ p = find_temp_slot_from_address (XEXP (x, 0));
+
if (p != 0)
{
+ /* Move everything at our level whose address was taken to our new
+ level in case we used its address. */
+ struct temp_slot *q;
+
+ for (q = temp_slots; q; q = q->next)
+ if (q != p && q->addr_taken && q->level == p->level)
+ q->level--;
+
p->level--;
return;
}
@@ -1032,14 +1099,14 @@ preserve_rtl_expr_result (x)
if (x == 0 || GET_CODE (x) != MEM || CONSTANT_P (XEXP (x, 0)))
return;
- /* If we can find a match, move it to our level. */
- for (p = temp_slots; p; p = p->next)
- if (p->in_use && rtx_equal_p (x, p->slot))
- {
- p->level = temp_slot_level;
- p->rtl_expr = 0;
- return;
- }
+ /* If we can find a match, move it to our level unless it is already at
+ an upper level. */
+ p = find_temp_slot_from_address (XEXP (x, 0));
+ if (p != 0)
+ {
+ p->level = MIN (p->level, temp_slot_level);
+ p->rtl_expr = 0;
+ }
return;
}
@@ -1118,7 +1185,7 @@ put_var_into_stack (decl)
if (output_bytecode)
return;
-
+
context = decl_function_context (decl);
/* Get the current rtl used for this object and it's original mode. */
@@ -1411,7 +1478,7 @@ fixup_var_refs_insns (var, promoted_mode, unsignedp, insn, toplevel)
PATTERN (insn) = replace_rtx (PATTERN (insn),
call_dest, temp);
}
-
+
if (GET_CODE (insn) == CALL_INSN
&& GET_CODE (PATTERN (insn)) == SET)
call_dest = SET_DEST (PATTERN (insn));
@@ -1430,7 +1497,7 @@ fixup_var_refs_insns (var, promoted_mode, unsignedp, insn, toplevel)
a list of struct fixup_replacements. If fixup_var_refs_1
needs to allocate pseudos or replacement MEMs (for SUBREGs),
it will record them in this list.
-
+
If it allocated a pseudo for any replacement, we copy into
it here. */
@@ -1497,7 +1564,7 @@ fixup_var_refs_insns (var, promoted_mode, unsignedp, insn, toplevel)
}
/* VAR is a MEM that used to be a pseudo register with mode PROMOTED_MODE.
- See if the rtx expression at *LOC in INSN needs to be changed.
+ See if the rtx expression at *LOC in INSN needs to be changed.
REPLACEMENTS is a pointer to a list head that starts out zero, but may
contain a list of original rtx's and replacements. If we find that we need
@@ -1527,7 +1594,7 @@ fixup_var_refs_1 (var, promoted_mode, loc, insn, replacements)
case MEM:
if (var == x)
{
- /* If we already have a replacement, use it. Otherwise,
+ /* If we already have a replacement, use it. Otherwise,
try to fix up this address in case it is invalid. */
replacement = find_fixup_replacement (replacements, var);
@@ -1541,7 +1608,7 @@ fixup_var_refs_1 (var, promoted_mode, loc, insn, replacements)
/* Unless we are forcing memory to register or we changed the mode,
we can leave things the way they are if the insn is valid. */
-
+
INSN_CODE (insn) = -1;
if (! flag_force_mem && GET_MODE (x) == promoted_mode
&& recog_memoized (insn) >= 0)
@@ -1662,7 +1729,7 @@ fixup_var_refs_1 (var, promoted_mode, loc, insn, replacements)
return;
}
break;
-
+
case SUBREG:
if (SUBREG_REG (x) == var)
{
@@ -1679,7 +1746,7 @@ fixup_var_refs_1 (var, promoted_mode, loc, insn, replacements)
}
/* If this SUBREG makes VAR wider, it has become a paradoxical
- SUBREG with VAR in memory, but these aren't allowed at this
+ SUBREG with VAR in memory, but these aren't allowed at this
stage of the compilation. So load VAR into a pseudo and take
a SUBREG of that pseudo. */
if (GET_MODE_SIZE (GET_MODE (x)) > GET_MODE_SIZE (GET_MODE (var)))
@@ -1701,7 +1768,7 @@ fixup_var_refs_1 (var, promoted_mode, loc, insn, replacements)
*loc = replacement->new;
return;
}
-
+
replacement->new = *loc = fixup_memory_subreg (x, insn, 0);
INSN_CODE (insn) = -1;
@@ -1735,7 +1802,7 @@ fixup_var_refs_1 (var, promoted_mode, loc, insn, replacements)
insn);
break;
}
-
+
{
rtx dest = SET_DEST (x);
rtx src = SET_SRC (x);
@@ -1816,10 +1883,10 @@ fixup_var_refs_1 (var, promoted_mode, loc, insn, replacements)
INSN_CODE (insn) = -1;
XEXP (outerdest, 0) = newmem;
XEXP (outerdest, 2) = GEN_INT (pos);
-
+
if (recog_memoized (insn) >= 0)
return;
-
+
/* Otherwise, restore old position. XEXP (x, 0) will be
restored later. */
XEXP (outerdest, 2) = old_pos;
@@ -1883,7 +1950,7 @@ fixup_var_refs_1 (var, promoted_mode, loc, insn, replacements)
copy SET_SRC (x) to SET_DEST (x) in some way. So
we generate the move and see whether it requires more
than one insn. If it does, we emit those insns and
- delete INSN. Otherwise, we an just replace the pattern
+ delete INSN. Otherwise, we an just replace the pattern
of INSN; we have already verified above that INSN has
no other function that to do X. */
@@ -2031,7 +2098,7 @@ fixup_memory_subreg (x, insn, uncritical)
If X itself is a (SUBREG (MEM ...) ...), return the replacement expression.
Otherwise return X, with its contents possibly altered.
- If any insns must be emitted to compute NEWADDR, put them before INSN.
+ If any insns must be emitted to compute NEWADDR, put them before INSN.
UNCRITICAL is as in fixup_memory_subreg. */
@@ -2191,6 +2258,8 @@ optimize_bit_field (body, insn, equiv_mem)
and then for which byte of the word is wanted. */
register int offset = INTVAL (XEXP (bitfield, 2));
+ rtx insns;
+
/* Adjust OFFSET to count bits from low-address byte. */
#if BITS_BIG_ENDIAN != BYTES_BIG_ENDIAN
offset = (GET_MODE_BITSIZE (GET_MODE (XEXP (bitfield, 0)))
@@ -2209,8 +2278,12 @@ optimize_bit_field (body, insn, equiv_mem)
#endif
}
- memref = change_address (memref, mode,
+ start_sequence ();
+ memref = change_address (memref, mode,
plus_constant (XEXP (memref, 0), offset));
+ insns = get_insns ();
+ end_sequence ();
+ emit_insns_before (insns, insn);
/* Store this memory reference where
we found the bit field reference. */
@@ -2308,7 +2381,7 @@ static int out_arg_offset;
/* The bottom of the stack points to the actual arguments. If
REG_PARM_STACK_SPACE is defined, this includes the space for the register
parameters. However, if OUTGOING_REG_PARM_STACK space is not defined,
- stack space for register parameters is not pushed by the caller, but
+ stack space for register parameters is not pushed by the caller, but
rather part of the fixed stack areas and hence not included in
`current_function_outgoing_args_size'. Nevertheless, we must allow
for it when allocating stack dynamic objects. */
@@ -2396,7 +2469,7 @@ instantiate_decls (fndecl, valid_only)
for (decl = DECL_ARGUMENTS (fndecl); decl; decl = TREE_CHAIN (decl))
{
instantiate_decl (DECL_RTL (decl), int_size_in_bytes (TREE_TYPE (decl)),
- valid_only);
+ valid_only);
instantiate_decl (DECL_INCOMING_RTL (decl),
int_size_in_bytes (TREE_TYPE (decl)), valid_only);
}
@@ -2505,7 +2578,7 @@ instantiate_decl (x, size, valid_only)
is not valid.
Return 1 if we either had nothing to do or if we were able to do the
- needed replacement. Return 0 otherwise; we only return zero if
+ needed replacement. Return 0 otherwise; we only return zero if
EXTRA_INSNS is zero.
We first try some simple transformations to avoid the creation of extra
@@ -2717,12 +2790,12 @@ instantiate_virtual_regs_1 (loc, object, extra_insns)
/* Most cases of MEM that convert to valid addresses have already been
handled by our scan of regno_reg_rtx. The only special handling we
need here is to make a copy of the rtx to ensure it isn't being
- shared if we have to change it to a pseudo.
+ shared if we have to change it to a pseudo.
If the rtx is a simple reference to an address via a virtual register,
it can potentially be shared. In such cases, first try to make it
a valid address, which can also be shared. Otherwise, copy it and
- proceed normally.
+ proceed normally.
First check for common cases that need no processing. These are
usually due to instantiation already being done on a previous instance
@@ -3031,7 +3104,7 @@ assign_parms (fndecl, second_time)
tree fnargs = DECL_ARGUMENTS (fndecl);
/* This is used for the arg pointer when referring to stack args. */
rtx internal_arg_pointer;
- /* This is a dummy PARM_DECL that we used for the function result if
+ /* This is a dummy PARM_DECL that we used for the function result if
the function returns a structure. */
tree function_result_decl = 0;
int nparmregs = list_length (fnargs) + LAST_VIRTUAL_REGISTER + 1;
@@ -3092,7 +3165,7 @@ assign_parms (fndecl, second_time)
TREE_CHAIN (function_result_decl) = fnargs;
fnargs = function_result_decl;
}
-
+
parm_reg_stack_loc = (rtx *) oballoc (nparmregs * sizeof (rtx));
bzero ((char *) parm_reg_stack_loc, nparmregs * sizeof (rtx));
@@ -3150,6 +3223,13 @@ assign_parms (fndecl, second_time)
continue;
}
+ /* If the parm is to be passed as a transparent union, use the
+ type of the first field for the tests below. We have already
+ verified that the modes are the same. */
+ if (DECL_TRANSPARENT_UNION (parm)
+ || TYPE_TRANSPARENT_UNION (passed_type))
+ passed_type = TREE_TYPE (TYPE_FIELDS (passed_type));
+
/* See if this arg was passed by invisible reference. It is if
it is an object whose size depends on the contents of the
object itself or if the machine requires these objects be passed
@@ -3426,6 +3506,9 @@ assign_parms (fndecl, second_time)
else if (PARM_BOUNDARY % BITS_PER_WORD != 0)
abort ();
+ if (TREE_READONLY (parm))
+ RTX_UNCHANGING_P (stack_parm) = 1;
+
move_block_from_reg (REGNO (entry_parm),
validize_mem (stack_parm),
size_stored / UNITS_PER_WORD,
@@ -3562,7 +3645,7 @@ assign_parms (fndecl, second_time)
#endif /* FUNCTION_ARG_CALLEE_COPIES */
/* In any case, record the parm's desired stack location
- in case we later discover it must live in the stack.
+ in case we later discover it must live in the stack.
If it is a COMPLEX value, store the stack location for both
halves. */
@@ -3699,7 +3782,7 @@ assign_parms (fndecl, second_time)
DECL_RTL (parm) = stack_parm;
}
-
+
/* If this "parameter" was the place where we are receiving the
function's incoming structure pointer, set up the result. */
if (parm == function_result_decl)
@@ -3744,13 +3827,13 @@ assign_parms (fndecl, second_time)
current_function_args_size
= ((current_function_args_size + STACK_BYTES - 1)
/ STACK_BYTES) * STACK_BYTES;
-#endif
+#endif
#ifdef ARGS_GROW_DOWNWARD
current_function_arg_offset_rtx
= (stack_args_size.var == 0 ? GEN_INT (-stack_args_size.constant)
- : expand_expr (size_binop (MINUS_EXPR, stack_args_size.var,
- size_int (-stack_args_size.constant)),
+ : expand_expr (size_binop (MINUS_EXPR, stack_args_size.var,
+ size_int (-stack_args_size.constant)),
NULL_RTX, VOIDmode, 0));
#else
current_function_arg_offset_rtx = ARGS_SIZE_RTX (stack_args_size);
@@ -3839,7 +3922,7 @@ promoted_input_arg (regno, pmode, punsignedp)
initial offset is not affected by this rounding, while the size always
is and the starting offset may be. */
-/* offset_ptr will be negative for ARGS_GROW_DOWNWARD case;
+/* offset_ptr will be negative for ARGS_GROW_DOWNWARD case;
initial_offset_ptr is positive because locate_and_pad_parm's
callers pass in the total size of args so far as
initial_offset_ptr. arg_size_ptr is always positive.*/
@@ -3920,7 +4003,7 @@ locate_and_pad_parm (passed_mode, type, in_regs, fndecl,
else
{
arg_size_ptr->constant = (- initial_offset_ptr->constant -
- offset_ptr->constant);
+ offset_ptr->constant);
}
#else /* !ARGS_GROW_DOWNWARD */
pad_to_arg_alignment (initial_offset_ptr, boundary);
@@ -3953,14 +4036,14 @@ pad_to_arg_alignment (offset_ptr, boundary)
int boundary;
{
int boundary_in_bytes = boundary / BITS_PER_UNIT;
-
+
if (boundary > BITS_PER_UNIT)
{
if (offset_ptr->var)
{
offset_ptr->var =
#ifdef ARGS_GROW_DOWNWARD
- round_down
+ round_down
#else
round_up
#endif
@@ -4133,7 +4216,7 @@ lookup_static_chain (decl)
if (context == 0)
return 0;
-
+
/* We treat inline_function_decl as an alias for the current function
because that is the inline function whose vars, types, etc.
are being merged into the current function.
@@ -4251,7 +4334,9 @@ trampoline_address (function)
/* Find an existing trampoline and return it. */
for (link = trampoline_list; link; link = TREE_CHAIN (link))
if (TREE_PURPOSE (link) == function)
- return XEXP (RTL_EXPR_RTL (TREE_VALUE (link)), 0);
+ return
+ round_trampoline_addr (XEXP (RTL_EXPR_RTL (TREE_VALUE (link)), 0));
+
for (fp = outer_function_chain; fp; fp = fp->next)
for (link = fp->trampoline_list; link; link = TREE_CHAIN (link))
if (TREE_PURPOSE (link) == function)
@@ -4420,7 +4505,7 @@ reorder_blocks (block_vector, top_block, insns)
block = copy_node (block);
BLOCK_SUBBLOCKS (block) = 0;
TREE_ASM_WRITTEN (block) = 1;
- BLOCK_SUPERCONTEXT (block) = current_block;
+ BLOCK_SUPERCONTEXT (block) = current_block;
BLOCK_CHAIN (block) = BLOCK_SUBBLOCKS (current_block);
BLOCK_SUBBLOCKS (current_block) = block;
current_block = block;
@@ -4464,7 +4549,7 @@ all_blocks (block, vector)
tree *vector;
{
int n_blocks = 1;
- tree subblocks;
+ tree subblocks;
TREE_ASM_WRITTEN (block) = 0;
/* Record this block. */
@@ -4693,6 +4778,11 @@ mark_varargs ()
/* Expand a call to __main at the beginning of a possible main function. */
+#if defined(INIT_SECTION_ASM_OP) && !defined(INVOKE__main)
+#undef HAS_INIT_SECTION
+#define HAS_INIT_SECTION
+#endif
+
void
expand_main_function ()
{
@@ -4700,10 +4790,10 @@ expand_main_function ()
{
/* The zero below avoids a possible parse error */
0;
-#if !defined (INIT_SECTION_ASM_OP) || defined (INVOKE__main)
+#if !defined (HAS_INIT_SECTION)
emit_library_call (gen_rtx (SYMBOL_REF, Pmode, NAME__MAIN), 0,
VOIDmode, 0);
-#endif /* not INIT_SECTION_ASM_OP or INVOKE__main */
+#endif /* not HAS_INIT_SECTION */
}
}
@@ -4858,7 +4948,7 @@ expand_function_start (subr, parms_have_cleanups)
if (aggregate_value_p (DECL_RESULT (subr)))
{
/* Returning something that won't go in a register. */
- register rtx value_address;
+ register rtx value_address = 0;
#ifdef PCC_STATIC_STRUCT_RETURN
if (current_function_returns_pcc_struct)
@@ -4965,11 +5055,23 @@ expand_function_start (subr, parms_have_cleanups)
/* Fetch static chain values for containing functions. */
tem = decl_function_context (current_function_decl);
- /* If not doing stupid register allocation, then start off with the static
- chain pointer in a pseudo register. Otherwise, we use the stack
- address that was generated above. */
+ /* If not doing stupid register allocation copy the static chain
+ pointer into a psuedo. If we have small register classes, copy the
+ value from memory if static_chain_incoming_rtx is a REG. If we do
+ stupid register allocation, we use the stack address generated above. */
if (tem && ! obey_regdecls)
- last_ptr = copy_to_reg (static_chain_incoming_rtx);
+ {
+#ifdef SMALL_REGISTER_CLASSES
+ /* If the static chain originally came in a register, put it back
+ there, then move it out in the next insn. The reason for
+ this peculiar code is to satisfy function integration. */
+ if (GET_CODE (static_chain_incoming_rtx) == REG)
+ emit_move_insn (static_chain_incoming_rtx, last_ptr);
+#endif
+
+ last_ptr = copy_to_reg (static_chain_incoming_rtx);
+ }
+
context_display = 0;
while (tem)
{
@@ -5009,7 +5111,7 @@ expand_function_start (subr, parms_have_cleanups)
}
/* Generate RTL for the end of the current function.
- FILENAME and LINE are the current position in the source file.
+ FILENAME and LINE are the current position in the source file.
It is up to language-specific callers to do cleanups for parameters--
or else, supply 1 for END_BINDINGS and we will call expand_end_bindings. */
@@ -5036,7 +5138,9 @@ expand_function_end (filename, line, end_bindings)
on a machine that fails to restore the registers. */
if (NON_SAVING_SETJMP && current_function_calls_setjmp)
{
- setjmp_protect (DECL_INITIAL (current_function_decl));
+ if (DECL_INITIAL (current_function_decl) != error_mark_node)
+ setjmp_protect (DECL_INITIAL (current_function_decl));
+
setjmp_protect_args ();
}
#endif
diff --git a/gnu/usr.bin/cc/cc_int/getpwd.c b/gnu/usr.bin/cc/cc_int/getpwd.c
index 922a9ed..d939f39 100644
--- a/gnu/usr.bin/cc/cc_int/getpwd.c
+++ b/gnu/usr.bin/cc/cc_int/getpwd.c
@@ -14,16 +14,23 @@ extern int errno;
BSD systems) now provides getcwd as called for by POSIX. Allow for
the few exceptions to the general rule here. */
-#if !(defined (POSIX) || defined (USG) || defined (VMS))
+#if !(defined (POSIX) || defined (USG) || defined (VMS)) || defined (HAVE_GETWD)
#include <sys/param.h>
extern char *getwd ();
#define getcwd(buf,len) getwd(buf)
+#ifdef MAXPATHLEN
#define GUESSPATHLEN (MAXPATHLEN + 1)
+#else
+#define GUESSPATHLEN 100
+#endif
#else /* (defined (USG) || defined (VMS)) */
extern char *getcwd ();
/* We actually use this as a starting point, not a limit. */
#define GUESSPATHLEN 100
#endif /* (defined (USG) || defined (VMS)) */
+#ifdef WINNT
+#include <direct.h>
+#endif
char *getenv ();
char *xmalloc ();
diff --git a/gnu/usr.bin/cc/cc_int/global.c b/gnu/usr.bin/cc/cc_int/global.c
index 297e930..650fb5f 100644
--- a/gnu/usr.bin/cc/cc_int/global.c
+++ b/gnu/usr.bin/cc/cc_int/global.c
@@ -43,7 +43,7 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
1. count the pseudo-registers still needing allocation
and assign allocation-numbers (allocnos) to them.
- Set up tables reg_allocno and allocno_reg to map
+ Set up tables reg_allocno and allocno_reg to map
reg numbers to allocnos and vice versa.
max_allocno gets the number of allocnos in use.
@@ -446,6 +446,18 @@ global_alloc (file)
if (regs_ever_live[i])
local_reg_n_refs[i] = 0;
+ /* Likewise for regs used in a SCRATCH. */
+ for (i = 0; i < scratch_list_length; i++)
+ if (scratch_list[i])
+ {
+ int regno = REGNO (scratch_list[i]);
+ int lim = regno + HARD_REGNO_NREGS (regno, GET_MODE (scratch_list[i]));
+ int j;
+
+ for (j = regno; j < lim; j++)
+ local_reg_n_refs[j] = 0;
+ }
+
/* Allocate the space for the conflict and preference tables and
initialize them. */
@@ -456,17 +468,17 @@ global_alloc (file)
hard_reg_preferences
= (HARD_REG_SET *) alloca (max_allocno * sizeof (HARD_REG_SET));
bzero ((char *) hard_reg_preferences, max_allocno * sizeof (HARD_REG_SET));
-
+
hard_reg_copy_preferences
= (HARD_REG_SET *) alloca (max_allocno * sizeof (HARD_REG_SET));
bzero ((char *) hard_reg_copy_preferences,
max_allocno * sizeof (HARD_REG_SET));
-
+
hard_reg_full_preferences
= (HARD_REG_SET *) alloca (max_allocno * sizeof (HARD_REG_SET));
bzero ((char *) hard_reg_full_preferences,
max_allocno * sizeof (HARD_REG_SET));
-
+
regs_someone_prefers
= (HARD_REG_SET *) alloca (max_allocno * sizeof (HARD_REG_SET));
bzero ((char *) regs_someone_prefers, max_allocno * sizeof (HARD_REG_SET));
@@ -531,7 +543,7 @@ global_alloc (file)
}
qsort (allocno_order, max_allocno, sizeof (int), allocno_compare);
-
+
prune_preferences ();
if (file)
@@ -812,17 +824,17 @@ expand_preferences ()
/* Prune the preferences for global registers to exclude registers that cannot
be used.
-
+
Compute `regs_someone_prefers', which is a bitmask of the hard registers
that are preferred by conflicting registers of lower priority. If possible,
we will avoid using these registers. */
-
+
static void
prune_preferences ()
{
int i, j;
int allocno;
-
+
/* Scan least most important to most important.
For each allocno, remove from preferences registers that cannot be used,
either because of conflicts or register type. Then compute all registers
@@ -863,7 +875,7 @@ prune_preferences ()
if (allocno_size[allocno_order[j]] <= allocno_size[allocno])
AND_COMPL_HARD_REG_SET (temp,
hard_reg_full_preferences[allocno]);
-
+
IOR_HARD_REG_SET (regs_someone_prefers[allocno], temp);
}
}
@@ -923,6 +935,12 @@ find_reg (allocno, losers, alt_regs_p, accept_call_clobbered, retrying)
IOR_HARD_REG_SET (used1, hard_reg_conflicts[allocno]);
+#ifdef CLASS_CANNOT_CHANGE_SIZE
+ if (reg_changes_size[allocno_reg[allocno]])
+ IOR_HARD_REG_SET (used1,
+ reg_class_contents[(int) CLASS_CANNOT_CHANGE_SIZE]);
+#endif
+
/* Try each hard reg to see if it fits. Do this in two passes.
In the first pass, skip registers that are preferred by some other pseudo
to give it a better chance of getting one of those registers. Only if
@@ -932,7 +950,7 @@ find_reg (allocno, losers, alt_regs_p, accept_call_clobbered, retrying)
COPY_HARD_REG_SET (used, used1);
IOR_COMPL_HARD_REG_SET (used, regs_used_so_far);
IOR_HARD_REG_SET (used, regs_someone_prefers[allocno]);
-
+
best_reg = -1;
for (i = FIRST_PSEUDO_REGISTER, pass = 0;
pass <= 1 && i >= FIRST_PSEUDO_REGISTER;
@@ -974,7 +992,7 @@ find_reg (allocno, losers, alt_regs_p, accept_call_clobbered, retrying)
Remove from the preferred registers and conflicting registers. Note that
additional conflicts may have been added after `prune_preferences' was
- called.
+ called.
First do this for those register with copy preferences, then all
preferred registers. */
@@ -1051,7 +1069,7 @@ find_reg (allocno, losers, alt_regs_p, accept_call_clobbered, retrying)
}
no_prefs:
- /* If we haven't succeeded yet, try with caller-saves.
+ /* If we haven't succeeded yet, try with caller-saves.
We need not check to see if the current function has nonlocal
labels because we don't put any pseudos that are live over calls in
registers in that case. */
@@ -1097,27 +1115,42 @@ find_reg (allocno, losers, alt_regs_p, accept_call_clobbered, retrying)
/* Don't use a reg no good for this pseudo. */
&& ! TEST_HARD_REG_BIT (used2, regno)
&& HARD_REGNO_MODE_OK (regno, mode)
- && (((double) local_reg_n_refs[regno]
- / local_reg_live_length[regno])
- < ((double) allocno_n_refs[allocno]
- / allocno_live_length[allocno])))
+#ifdef CLASS_CANNOT_CHANGE_SIZE
+ && ! (reg_changes_size[allocno_reg[allocno]]
+ && (TEST_HARD_REG_BIT
+ (reg_class_contents[(int) CLASS_CANNOT_CHANGE_SIZE],
+ regno)))
+#endif
+ )
{
- /* Hard reg REGNO was used less in total by local regs
- than it would be used by this one allocno! */
- int k;
- for (k = 0; k < max_regno; k++)
- if (reg_renumber[k] >= 0)
- {
- int r = reg_renumber[k];
- int endregno
- = r + HARD_REGNO_NREGS (r, PSEUDO_REGNO_MODE (k));
+ /* We explicitly evaluate the divide results into temporary
+ variables so as to avoid excess precision problems that occur
+ on a i386-unknown-sysv4.2 (unixware) host. */
- if (regno >= r && regno < endregno)
- reg_renumber[k] = -1;
- }
+ double tmp1 = ((double) local_reg_n_refs[regno]
+ / local_reg_live_length[regno]);
+ double tmp2 = ((double) allocno_n_refs[allocno]
+ / allocno_live_length[allocno]);
+
+ if (tmp1 < tmp2)
+ {
+ /* Hard reg REGNO was used less in total by local regs
+ than it would be used by this one allocno! */
+ int k;
+ for (k = 0; k < max_regno; k++)
+ if (reg_renumber[k] >= 0)
+ {
+ int r = reg_renumber[k];
+ int endregno
+ = r + HARD_REGNO_NREGS (r, PSEUDO_REGNO_MODE (k));
- best_reg = regno;
- break;
+ if (regno >= r && regno < endregno)
+ reg_renumber[k] = -1;
+ }
+
+ best_reg = regno;
+ break;
+ }
}
}
}
@@ -1277,7 +1310,7 @@ record_conflicts (allocno_vec, len)
SETTER is 0 if this register was modified by an auto-increment (i.e.,
a REG_INC note was found for it).
- CLOBBERs are processed here by calling mark_reg_clobber. */
+ CLOBBERs are processed here by calling mark_reg_clobber. */
static void
mark_reg_store (orig_reg, setter)
@@ -1493,7 +1526,7 @@ mark_reg_live_nc (regno, mode)
that SRC is a register. If SRC or the first operand of SRC is a register,
try to set a preference. If one of the two is a hard register and the other
is a pseudo-register, mark the preference.
-
+
Note that we are not as aggressive as local-alloc in trying to tie a
pseudo-register to a hard register. */
@@ -1662,7 +1695,7 @@ dump_global_regs (file)
FILE *file;
{
register int i, j;
-
+
fprintf (file, ";; Register dispositions:\n");
for (i = FIRST_PSEUDO_REGISTER, j = 0; i < max_regno; i++)
if (reg_renumber[i] >= 0)
diff --git a/gnu/usr.bin/cc/cc_int/insn-emit.c b/gnu/usr.bin/cc/cc_int/insn-emit.c
index 01463d0..ee62202 100644
--- a/gnu/usr.bin/cc/cc_int/insn-emit.c
+++ b/gnu/usr.bin/cc/cc_int/insn-emit.c
@@ -659,6 +659,15 @@ gen_movsi (operand0, operand1)
if (flag_pic && SYMBOLIC_CONST (operands[1]))
emit_pic_move (operands, SImode);
+
+ /* Don't generate memory->memory moves, go through a register */
+ else if (TARGET_MOVE
+ && (reload_in_progress | reload_completed) == 0
+ && GET_CODE (operands[0]) == MEM
+ && GET_CODE (operands[1]) == MEM)
+ {
+ operands[1] = force_reg (SImode, operands[1]);
+ }
}
operand0 = operands[0];
operand1 = operands[1];
@@ -677,9 +686,32 @@ gen_movhi (operand0, operand1)
rtx operand0;
rtx operand1;
{
- return gen_rtx (SET, VOIDmode,
+ rtx operands[2];
+ rtx _val = 0;
+ start_sequence ();
+ operands[0] = operand0;
+ operands[1] = operand1;
+
+{
+ /* Don't generate memory->memory moves, go through a register */
+ if (TARGET_MOVE
+ && (reload_in_progress | reload_completed) == 0
+ && GET_CODE (operands[0]) == MEM
+ && GET_CODE (operands[1]) == MEM)
+ {
+ operands[1] = force_reg (HImode, operands[1]);
+ }
+}
+ operand0 = operands[0];
+ operand1 = operands[1];
+ emit_insn (gen_rtx (SET, VOIDmode,
operand0,
- operand1);
+ operand1));
+ _done:
+ _val = gen_sequence ();
+ _fail:
+ end_sequence ();
+ return _val;
}
rtx
@@ -687,10 +719,33 @@ gen_movstricthi (operand0, operand1)
rtx operand0;
rtx operand1;
{
- return gen_rtx (SET, VOIDmode,
+ rtx operands[2];
+ rtx _val = 0;
+ start_sequence ();
+ operands[0] = operand0;
+ operands[1] = operand1;
+
+{
+ /* Don't generate memory->memory moves, go through a register */
+ if (TARGET_MOVE
+ && (reload_in_progress | reload_completed) == 0
+ && GET_CODE (operands[0]) == MEM
+ && GET_CODE (operands[1]) == MEM)
+ {
+ operands[1] = force_reg (HImode, operands[1]);
+ }
+}
+ operand0 = operands[0];
+ operand1 = operands[1];
+ emit_insn (gen_rtx (SET, VOIDmode,
gen_rtx (STRICT_LOW_PART, VOIDmode,
operand0),
- operand1);
+ operand1));
+ _done:
+ _val = gen_sequence ();
+ _fail:
+ end_sequence ();
+ return _val;
}
rtx
@@ -698,9 +753,32 @@ gen_movqi (operand0, operand1)
rtx operand0;
rtx operand1;
{
- return gen_rtx (SET, VOIDmode,
+ rtx operands[2];
+ rtx _val = 0;
+ start_sequence ();
+ operands[0] = operand0;
+ operands[1] = operand1;
+
+{
+ /* Don't generate memory->memory moves, go through a register */
+ if (TARGET_MOVE
+ && (reload_in_progress | reload_completed) == 0
+ && GET_CODE (operands[0]) == MEM
+ && GET_CODE (operands[1]) == MEM)
+ {
+ operands[1] = force_reg (QImode, operands[1]);
+ }
+}
+ operand0 = operands[0];
+ operand1 = operands[1];
+ emit_insn (gen_rtx (SET, VOIDmode,
operand0,
- operand1);
+ operand1));
+ _done:
+ _val = gen_sequence ();
+ _fail:
+ end_sequence ();
+ return _val;
}
rtx
@@ -708,10 +786,33 @@ gen_movstrictqi (operand0, operand1)
rtx operand0;
rtx operand1;
{
- return gen_rtx (SET, VOIDmode,
+ rtx operands[2];
+ rtx _val = 0;
+ start_sequence ();
+ operands[0] = operand0;
+ operands[1] = operand1;
+
+{
+ /* Don't generate memory->memory moves, go through a register */
+ if (TARGET_MOVE
+ && (reload_in_progress | reload_completed) == 0
+ && GET_CODE (operands[0]) == MEM
+ && GET_CODE (operands[1]) == MEM)
+ {
+ operands[1] = force_reg (QImode, operands[1]);
+ }
+}
+ operand0 = operands[0];
+ operand1 = operands[1];
+ emit_insn (gen_rtx (SET, VOIDmode,
gen_rtx (STRICT_LOW_PART, VOIDmode,
operand0),
- operand1);
+ operand1));
+ _done:
+ _val = gen_sequence ();
+ _fail:
+ end_sequence ();
+ return _val;
}
rtx
@@ -719,13 +820,99 @@ gen_movsf (operand0, operand1)
rtx operand0;
rtx operand1;
{
+ rtx operands[2];
+ rtx _val = 0;
+ start_sequence ();
+ operands[0] = operand0;
+ operands[1] = operand1;
+
+{
+ /* Special case memory->memory moves and pushes */
+ if (TARGET_MOVE
+ && (reload_in_progress | reload_completed) == 0
+ && GET_CODE (operands[0]) == MEM
+ && (GET_CODE (operands[1]) == MEM || push_operand (operands[0], SFmode)))
+ {
+ rtx (*genfunc) PROTO((rtx, rtx)) = (push_operand (operands[0], SFmode))
+ ? gen_movsf_push
+ : gen_movsf_mem;
+
+ emit_insn ((*genfunc) (operands[0], operands[1]));
+ DONE;
+ }
+
+ /* If we are loading a floating point constant that isn't 0 or 1 into a register,
+ indicate we need the pic register loaded. This could be optimized into stores
+ of constants if the target eventually moves to memory, but better safe than
+ sorry. */
+ if (flag_pic
+ && GET_CODE (operands[0]) != MEM
+ && GET_CODE (operands[1]) == CONST_DOUBLE
+ && !standard_80387_constant_p (operands[1]))
+ {
+ current_function_uses_pic_offset_table = 1;
+ }
+}
+ operand0 = operands[0];
+ operand1 = operands[1];
+ emit_insn (gen_rtx (SET, VOIDmode,
+ operand0,
+ operand1));
+ _done:
+ _val = gen_sequence ();
+ _fail:
+ end_sequence ();
+ return _val;
+}
+
+rtx
+gen_movsf_push_nomove (operand0, operand1)
+ rtx operand0;
+ rtx operand1;
+{
return gen_rtx (SET, VOIDmode,
operand0,
operand1);
}
rtx
-gen_swapdf (operand0, operand1)
+gen_movsf_push (operand0, operand1)
+ rtx operand0;
+ rtx operand1;
+{
+ return gen_rtx (PARALLEL, VOIDmode, gen_rtvec (2,
+ gen_rtx (SET, VOIDmode,
+ operand0,
+ operand1),
+ gen_rtx (CLOBBER, VOIDmode,
+ gen_rtx (SCRATCH, SImode, 0))));
+}
+
+rtx
+gen_movsf_mem (operand0, operand1)
+ rtx operand0;
+ rtx operand1;
+{
+ return gen_rtx (PARALLEL, VOIDmode, gen_rtvec (2,
+ gen_rtx (SET, VOIDmode,
+ operand0,
+ operand1),
+ gen_rtx (CLOBBER, VOIDmode,
+ gen_rtx (SCRATCH, SImode, 0))));
+}
+
+rtx
+gen_movsf_normal (operand0, operand1)
+ rtx operand0;
+ rtx operand1;
+{
+ return gen_rtx (SET, VOIDmode,
+ operand0,
+ operand1);
+}
+
+rtx
+gen_swapsf (operand0, operand1)
rtx operand0;
rtx operand1;
{
@@ -743,13 +930,103 @@ gen_movdf (operand0, operand1)
rtx operand0;
rtx operand1;
{
+ rtx operands[2];
+ rtx _val = 0;
+ start_sequence ();
+ operands[0] = operand0;
+ operands[1] = operand1;
+
+{
+ /* Special case memory->memory moves and pushes */
+ if (TARGET_MOVE
+ && (reload_in_progress | reload_completed) == 0
+ && GET_CODE (operands[0]) == MEM
+ && (GET_CODE (operands[1]) == MEM || push_operand (operands[0], DFmode)))
+ {
+ rtx (*genfunc) PROTO((rtx, rtx)) = (push_operand (operands[0], DFmode))
+ ? gen_movdf_push
+ : gen_movdf_mem;
+
+ emit_insn ((*genfunc) (operands[0], operands[1]));
+ DONE;
+ }
+
+ /* If we are loading a floating point constant that isn't 0 or 1 into a register,
+ indicate we need the pic register loaded. This could be optimized into stores
+ of constants if the target eventually moves to memory, but better safe than
+ sorry. */
+ if (flag_pic
+ && GET_CODE (operands[0]) != MEM
+ && GET_CODE (operands[1]) == CONST_DOUBLE
+ && !standard_80387_constant_p (operands[1]))
+ {
+ current_function_uses_pic_offset_table = 1;
+ }
+}
+ operand0 = operands[0];
+ operand1 = operands[1];
+ emit_insn (gen_rtx (SET, VOIDmode,
+ operand0,
+ operand1));
+ _done:
+ _val = gen_sequence ();
+ _fail:
+ end_sequence ();
+ return _val;
+}
+
+rtx
+gen_movdf_push_nomove (operand0, operand1)
+ rtx operand0;
+ rtx operand1;
+{
return gen_rtx (SET, VOIDmode,
operand0,
operand1);
}
rtx
-gen_swapxf (operand0, operand1)
+gen_movdf_push (operand0, operand1)
+ rtx operand0;
+ rtx operand1;
+{
+ return gen_rtx (PARALLEL, VOIDmode, gen_rtvec (3,
+ gen_rtx (SET, VOIDmode,
+ operand0,
+ operand1),
+ gen_rtx (CLOBBER, VOIDmode,
+ gen_rtx (SCRATCH, SImode, 0)),
+ gen_rtx (CLOBBER, VOIDmode,
+ gen_rtx (SCRATCH, SImode, 0))));
+}
+
+rtx
+gen_movdf_mem (operand0, operand1)
+ rtx operand0;
+ rtx operand1;
+{
+ return gen_rtx (PARALLEL, VOIDmode, gen_rtvec (3,
+ gen_rtx (SET, VOIDmode,
+ operand0,
+ operand1),
+ gen_rtx (CLOBBER, VOIDmode,
+ gen_rtx (SCRATCH, SImode, 0)),
+ gen_rtx (CLOBBER, VOIDmode,
+ gen_rtx (SCRATCH, SImode, 0))));
+}
+
+rtx
+gen_movdf_normal (operand0, operand1)
+ rtx operand0;
+ rtx operand1;
+{
+ return gen_rtx (SET, VOIDmode,
+ operand0,
+ operand1);
+}
+
+rtx
+gen_swapdf (operand0, operand1)
rtx operand0;
rtx operand1;
{
@@ -767,13 +1044,93 @@ gen_movxf (operand0, operand1)
rtx operand0;
rtx operand1;
{
+ rtx operands[2];
+ rtx _val = 0;
+ start_sequence ();
+ operands[0] = operand0;
+ operands[1] = operand1;
+
+{
+ /* Special case memory->memory moves and pushes */
+ if (TARGET_MOVE
+ && (reload_in_progress | reload_completed) == 0
+ && GET_CODE (operands[0]) == MEM
+ && (GET_CODE (operands[1]) == MEM || push_operand (operands[0], XFmode)))
+ {
+ rtx (*genfunc) PROTO((rtx, rtx)) = (push_operand (operands[0], XFmode))
+ ? gen_movxf_push
+ : gen_movxf_mem;
+
+ emit_insn ((*genfunc) (operands[0], operands[1]));
+ DONE;
+ }
+
+ /* If we are loading a floating point constant that isn't 0 or 1 into a register,
+ indicate we need the pic register loaded. This could be optimized into stores
+ of constants if the target eventually moves to memory, but better safe than
+ sorry. */
+ if (flag_pic
+ && GET_CODE (operands[0]) != MEM
+ && GET_CODE (operands[1]) == CONST_DOUBLE
+ && !standard_80387_constant_p (operands[1]))
+ {
+ current_function_uses_pic_offset_table = 1;
+ }
+}
+ operand0 = operands[0];
+ operand1 = operands[1];
+ emit_insn (gen_rtx (SET, VOIDmode,
+ operand0,
+ operand1));
+ _done:
+ _val = gen_sequence ();
+ _fail:
+ end_sequence ();
+ return _val;
+}
+
+rtx
+gen_movxf_push_nomove (operand0, operand1)
+ rtx operand0;
+ rtx operand1;
+{
return gen_rtx (SET, VOIDmode,
operand0,
operand1);
}
rtx
-gen_movdi (operand0, operand1)
+gen_movxf_push (operand0, operand1)
+ rtx operand0;
+ rtx operand1;
+{
+ return gen_rtx (PARALLEL, VOIDmode, gen_rtvec (3,
+ gen_rtx (SET, VOIDmode,
+ operand0,
+ operand1),
+ gen_rtx (CLOBBER, VOIDmode,
+ gen_rtx (SCRATCH, SImode, 0)),
+ gen_rtx (CLOBBER, VOIDmode,
+ gen_rtx (SCRATCH, SImode, 0))));
+}
+
+rtx
+gen_movxf_mem (operand0, operand1)
+ rtx operand0;
+ rtx operand1;
+{
+ return gen_rtx (PARALLEL, VOIDmode, gen_rtvec (3,
+ gen_rtx (SET, VOIDmode,
+ operand0,
+ operand1),
+ gen_rtx (CLOBBER, VOIDmode,
+ gen_rtx (SCRATCH, SImode, 0)),
+ gen_rtx (CLOBBER, VOIDmode,
+ gen_rtx (SCRATCH, SImode, 0))));
+}
+
+rtx
+gen_movxf_normal (operand0, operand1)
rtx operand0;
rtx operand1;
{
@@ -783,6 +1140,35 @@ gen_movdi (operand0, operand1)
}
rtx
+gen_swapxf (operand0, operand1)
+ rtx operand0;
+ rtx operand1;
+{
+ return gen_rtx (PARALLEL, VOIDmode, gen_rtvec (2,
+ gen_rtx (SET, VOIDmode,
+ operand0,
+ operand1),
+ gen_rtx (SET, VOIDmode,
+ operand1,
+ operand0)));
+}
+
+rtx
+gen_movdi (operand0, operand1)
+ rtx operand0;
+ rtx operand1;
+{
+ return gen_rtx (PARALLEL, VOIDmode, gen_rtvec (3,
+ gen_rtx (SET, VOIDmode,
+ operand0,
+ operand1),
+ gen_rtx (CLOBBER, VOIDmode,
+ gen_rtx (SCRATCH, SImode, 0)),
+ gen_rtx (CLOBBER, VOIDmode,
+ gen_rtx (SCRATCH, SImode, 0))));
+}
+
+rtx
gen_zero_extendhisi2 (operand0, operand1)
rtx operand0;
rtx operand1;
@@ -1477,11 +1863,14 @@ gen_adddi3 (operand0, operand1, operand2)
rtx operand1;
rtx operand2;
{
- return gen_rtx (SET, VOIDmode,
+ return gen_rtx (PARALLEL, VOIDmode, gen_rtvec (2,
+ gen_rtx (SET, VOIDmode,
operand0,
gen_rtx (PLUS, DImode,
operand1,
- operand2));
+ operand2)),
+ gen_rtx (CLOBBER, VOIDmode,
+ gen_rtx (SCRATCH, SImode, 0))));
}
rtx
@@ -1524,6 +1913,16 @@ gen_addqi3 (operand0, operand1, operand2)
}
rtx
+gen_movsi_lea (operand0, operand1)
+ rtx operand0;
+ rtx operand1;
+{
+ return gen_rtx (SET, VOIDmode,
+ operand0,
+ operand1);
+}
+
+rtx
gen_addxf3 (operand0, operand1, operand2)
rtx operand0;
rtx operand1;
@@ -1568,11 +1967,14 @@ gen_subdi3 (operand0, operand1, operand2)
rtx operand1;
rtx operand2;
{
- return gen_rtx (SET, VOIDmode,
+ return gen_rtx (PARALLEL, VOIDmode, gen_rtvec (2,
+ gen_rtx (SET, VOIDmode,
operand0,
gen_rtx (MINUS, DImode,
operand1,
- operand2));
+ operand2)),
+ gen_rtx (CLOBBER, VOIDmode,
+ gen_rtx (SCRATCH, SImode, 0))));
}
rtx
@@ -1740,6 +2142,48 @@ gen_mulsidi3 (operand0, operand1, operand2)
}
rtx
+gen_umulsi3_highpart (operand0, operand1, operand2)
+ rtx operand0;
+ rtx operand1;
+ rtx operand2;
+{
+ return gen_rtx (PARALLEL, VOIDmode, gen_rtvec (2,
+ gen_rtx (SET, VOIDmode,
+ operand0,
+ gen_rtx (TRUNCATE, SImode,
+ gen_rtx (LSHIFTRT, DImode,
+ gen_rtx (MULT, DImode,
+ gen_rtx (ZERO_EXTEND, DImode,
+ operand1),
+ gen_rtx (ZERO_EXTEND, DImode,
+ operand2)),
+ GEN_INT (32)))),
+ gen_rtx (CLOBBER, VOIDmode,
+ gen_rtx (SCRATCH, SImode, 0))));
+}
+
+rtx
+gen_smulsi3_highpart (operand0, operand1, operand2)
+ rtx operand0;
+ rtx operand1;
+ rtx operand2;
+{
+ return gen_rtx (PARALLEL, VOIDmode, gen_rtvec (2,
+ gen_rtx (SET, VOIDmode,
+ operand0,
+ gen_rtx (TRUNCATE, SImode,
+ gen_rtx (LSHIFTRT, DImode,
+ gen_rtx (MULT, DImode,
+ gen_rtx (SIGN_EXTEND, DImode,
+ operand1),
+ gen_rtx (SIGN_EXTEND, DImode,
+ operand2)),
+ GEN_INT (32)))),
+ gen_rtx (CLOBBER, VOIDmode,
+ gen_rtx (SCRATCH, SImode, 0))));
+}
+
+rtx
gen_mulxf3 (operand0, operand1, operand2)
rtx operand0;
rtx operand1;
@@ -3554,21 +3998,23 @@ gen_untyped_call (operand0, operand1, operand2)
operands[2] = operand2;
{
- rtx addr;
+ int i;
- if (flag_pic)
- current_function_uses_pic_offset_table = 1;
+ emit_call_insn (gen_call (operands[0], const0_rtx, NULL, const0_rtx));
- /* With half-pic, force the address into a register. */
- addr = XEXP (operands[0], 0);
- if (GET_CODE (addr) != REG && HALF_PIC_P () && !CONSTANT_ADDRESS_P (addr))
- XEXP (operands[0], 0) = force_reg (Pmode, addr);
+ for (i = 0; i < XVECLEN (operands[2], 0); i++)
+ {
+ rtx set = XVECEXP (operands[2], 0, i);
+ emit_move_insn (SET_DEST (set), SET_SRC (set));
+ }
- operands[1] = change_address (operands[1], DImode, XEXP (operands[1], 0));
- if (! expander_call_insn_operand (operands[1], QImode))
- operands[1]
- = change_address (operands[1], VOIDmode,
- copy_to_mode_reg (Pmode, XEXP (operands[1], 0)));
+ /* The optimizer does not know that the call sets the function value
+ registers we stored in the result block. We avoid problems by
+ claiming that all hard registers are used and clobbered at this
+ point. */
+ emit_insn (gen_blockage ());
+
+ DONE;
}
operand0 = operands[0];
operand1 = operands[1];
@@ -3588,59 +4034,11 @@ gen_untyped_call (operand0, operand1, operand2)
}
rtx
-gen_untyped_return (operand0, operand1)
- rtx operand0;
- rtx operand1;
-{
- rtx operands[2];
- rtx _val = 0;
- start_sequence ();
- operands[0] = operand0;
- operands[1] = operand1;
-
-{
- rtx valreg1 = gen_rtx (REG, SImode, 0);
- rtx valreg2 = gen_rtx (REG, SImode, 1);
- rtx result = operands[0];
-
- /* Restore the FPU state. */
- emit_insn (gen_update_return (change_address (result, SImode,
- plus_constant (XEXP (result, 0),
- 8))));
-
- /* Reload the function value registers. */
- emit_move_insn (valreg1, change_address (result, SImode, XEXP (result, 0)));
- emit_move_insn (valreg2,
- change_address (result, SImode,
- plus_constant (XEXP (result, 0), 4)));
-
- /* Put USE insns before the return. */
- emit_insn (gen_rtx (USE, VOIDmode, valreg1));
- emit_insn (gen_rtx (USE, VOIDmode, valreg2));
-
- /* Construct the return. */
- expand_null_return ();
-
- DONE;
-}
- operand0 = operands[0];
- operand1 = operands[1];
- emit (operand0);
- emit (operand1);
- _done:
- _val = gen_sequence ();
- _fail:
- end_sequence ();
- return _val;
-}
-
-rtx
-gen_update_return (operand0)
- rtx operand0;
+gen_blockage ()
{
- return gen_rtx (UNSPEC, SImode,
+ return gen_rtx (UNSPEC_VOLATILE, VOIDmode,
gen_rtvec (1,
- operand0),
+ const0_rtx),
0);
}
@@ -3916,22 +4314,40 @@ add_clobbers (pattern, insn_code_number)
switch (insn_code_number)
{
- case 264:
- XVECEXP (pattern, 0, 1) = gen_rtx (CLOBBER, VOIDmode,
+ case 114:
+ case 113:
+ case 112:
+ XVECEXP (pattern, 0, 3) = gen_rtx (CLOBBER, VOIDmode,
gen_rtx (SCRATCH, SImode, 0));
break;
- case 95:
- case 94:
- case 93:
- XVECEXP (pattern, 0, 3) = gen_rtx (CLOBBER, VOIDmode,
+ case 108:
+ case 107:
+ case 106:
+ XVECEXP (pattern, 0, 4) = gen_rtx (CLOBBER, VOIDmode,
gen_rtx (SCRATCH, SImode, 0));
break;
- case 89:
- case 88:
- case 87:
- XVECEXP (pattern, 0, 4) = gen_rtx (CLOBBER, VOIDmode,
+ case 84:
+ case 83:
+ case 80:
+ case 79:
+ case 74:
+ case 73:
+ XVECEXP (pattern, 0, 1) = gen_rtx (CLOBBER, VOIDmode,
+ gen_rtx (SCRATCH, SImode, 0));
+ XVECEXP (pattern, 0, 2) = gen_rtx (CLOBBER, VOIDmode,
+ gen_rtx (SCRATCH, SImode, 0));
+ break;
+
+ case 285:
+ case 151:
+ case 150:
+ case 135:
+ case 127:
+ case 68:
+ case 67:
+ XVECEXP (pattern, 0, 1) = gen_rtx (CLOBBER, VOIDmode,
gen_rtx (SCRATCH, SImode, 0));
break;
diff --git a/gnu/usr.bin/cc/cc_int/insn-extract.c b/gnu/usr.bin/cc/cc_int/insn-extract.c
index 7f6f1a4..8e8730f 100644
--- a/gnu/usr.bin/cc/cc_int/insn-extract.c
+++ b/gnu/usr.bin/cc/cc_int/insn-extract.c
@@ -9,12 +9,6 @@ extern rtx recog_operand[];
extern rtx *recog_operand_loc[];
extern rtx *recog_dup_loc[];
extern char recog_dup_num[];
-extern
-#ifdef __GNUC__
-__volatile__
-#endif
-void fatal_insn_not_found ();
-
void
insn_extract (insn)
rtx insn;
@@ -27,7 +21,7 @@ insn_extract (insn)
case -1:
fatal_insn_not_found (insn);
- case 308:
+ case 326:
ro[0] = *(ro_loc[0] = &XEXP (XVECEXP (pat, 0, 0), 0));
ro[1] = *(ro_loc[1] = &XEXP (XVECEXP (XEXP (XVECEXP (pat, 0, 0), 1), 0, 0), 0));
ro[2] = *(ro_loc[2] = &XVECEXP (XEXP (XVECEXP (pat, 0, 0), 1), 0, 1));
@@ -36,38 +30,38 @@ insn_extract (insn)
recog_dup_num[0] = 1;
break;
- case 306:
- case 303:
- case 302:
- case 300:
- case 299:
+ case 324:
+ case 321:
+ case 320:
+ case 318:
+ case 317:
ro[0] = *(ro_loc[0] = &XEXP (pat, 0));
ro[1] = *(ro_loc[1] = &XEXP (XEXP (pat, 1), 0));
ro[2] = *(ro_loc[2] = &XEXP (XEXP (XEXP (pat, 1), 1), 0));
ro[3] = *(ro_loc[3] = &XEXP (pat, 1));
break;
- case 305:
- case 301:
- case 298:
- case 297:
- case 295:
+ case 323:
+ case 319:
+ case 316:
+ case 315:
+ case 313:
ro[0] = *(ro_loc[0] = &XEXP (pat, 0));
ro[1] = *(ro_loc[1] = &XEXP (XEXP (XEXP (pat, 1), 0), 0));
ro[2] = *(ro_loc[2] = &XEXP (XEXP (pat, 1), 1));
ro[3] = *(ro_loc[3] = &XEXP (pat, 1));
break;
- case 304:
- case 296:
- case 294:
+ case 322:
+ case 314:
+ case 312:
ro[0] = *(ro_loc[0] = &XEXP (pat, 0));
ro[1] = *(ro_loc[1] = &XEXP (XEXP (pat, 1), 0));
ro[2] = *(ro_loc[2] = &XEXP (XEXP (pat, 1), 1));
ro[3] = *(ro_loc[3] = &XEXP (pat, 1));
break;
- case 289:
+ case 307:
ro[0] = *(ro_loc[0] = &XEXP (XEXP (XEXP (XVECEXP (pat, 0, 0), 1), 0), 0));
ro[1] = *(ro_loc[1] = &XEXP (XEXP (XEXP (XVECEXP (pat, 0, 0), 1), 1), 0));
ro[2] = *(ro_loc[2] = &XEXP (XVECEXP (pat, 0, 1), 0));
@@ -80,7 +74,7 @@ insn_extract (insn)
recog_dup_num[2] = 0;
break;
- case 288:
+ case 306:
ro[0] = *(ro_loc[0] = &XEXP (XVECEXP (pat, 0, 0), 0));
ro[1] = *(ro_loc[1] = &XEXP (XEXP (XEXP (XVECEXP (pat, 0, 0), 1), 0), 0));
ro[2] = *(ro_loc[2] = &XEXP (XEXP (XEXP (XVECEXP (pat, 0, 0), 1), 1), 0));
@@ -94,7 +88,7 @@ insn_extract (insn)
recog_dup_num[2] = 1;
break;
- case 286:
+ case 304:
ro[0] = *(ro_loc[0] = &XEXP (XEXP (XVECEXP (pat, 0, 0), 0), 0));
ro[1] = *(ro_loc[1] = &XEXP (XEXP (XVECEXP (pat, 0, 0), 1), 0));
ro[2] = *(ro_loc[2] = &XEXP (XVECEXP (pat, 0, 1), 0));
@@ -106,33 +100,18 @@ insn_extract (insn)
recog_dup_num[1] = 0;
break;
- case 284:
- case 283:
- break;
-
- case 282:
- ro[0] = *(ro_loc[0] = &XVECEXP (pat, 0, 0));
- break;
-
- case 280:
- ro[0] = *(ro_loc[0] = &XEXP (XEXP (XVECEXP (pat, 0, 0), 0), 0));
- ro[1] = *(ro_loc[1] = &XVECEXP (pat, 0, 1));
- ro[2] = *(ro_loc[2] = &XVECEXP (pat, 0, 2));
- break;
-
- case 279:
- ro[0] = *(ro_loc[0] = &XEXP (XVECEXP (pat, 0, 0), 0));
- ro[1] = *(ro_loc[1] = &XVECEXP (pat, 0, 1));
- ro[2] = *(ro_loc[2] = &XVECEXP (pat, 0, 2));
+ case 302:
+ case 301:
+ case 300:
break;
- case 277:
+ case 298:
ro[0] = *(ro_loc[0] = &XEXP (pat, 0));
ro[1] = *(ro_loc[1] = &XEXP (XEXP (XEXP (pat, 1), 0), 0));
ro[2] = *(ro_loc[2] = &XEXP (XEXP (pat, 1), 1));
break;
- case 274:
+ case 295:
ro[0] = *(ro_loc[0] = &XEXP (XVECEXP (pat, 0, 0), 0));
ro[1] = *(ro_loc[1] = &XEXP (XEXP (XEXP (XVECEXP (pat, 0, 0), 1), 0), 0));
ro[2] = *(ro_loc[2] = &XEXP (XEXP (XVECEXP (pat, 0, 0), 1), 1));
@@ -141,7 +120,7 @@ insn_extract (insn)
ro[4] = *(ro_loc[4] = &XEXP (XEXP (XVECEXP (pat, 0, 1), 1), 1));
break;
- case 273:
+ case 294:
ro[0] = *(ro_loc[0] = &XEXP (XVECEXP (pat, 0, 0), 0));
ro[1] = *(ro_loc[1] = &XEXP (XEXP (XVECEXP (pat, 0, 0), 1), 0));
ro[2] = *(ro_loc[2] = &XEXP (XEXP (XVECEXP (pat, 0, 0), 1), 1));
@@ -150,7 +129,7 @@ insn_extract (insn)
ro[4] = *(ro_loc[4] = &XEXP (XEXP (XVECEXP (pat, 0, 1), 1), 1));
break;
- case 268:
+ case 289:
ro[0] = *(ro_loc[0] = &XEXP (XEXP (XVECEXP (pat, 0, 0), 0), 0));
ro[1] = *(ro_loc[1] = &XEXP (XVECEXP (pat, 0, 0), 1));
ro[2] = const0_rtx;
@@ -158,7 +137,7 @@ insn_extract (insn)
ro[3] = *(ro_loc[3] = &XEXP (XEXP (XVECEXP (pat, 0, 1), 1), 1));
break;
- case 267:
+ case 288:
ro[0] = *(ro_loc[0] = &XEXP (XVECEXP (pat, 0, 0), 0));
ro[1] = *(ro_loc[1] = &XEXP (XVECEXP (pat, 0, 0), 1));
ro[2] = const0_rtx;
@@ -166,85 +145,85 @@ insn_extract (insn)
ro[3] = *(ro_loc[3] = &XEXP (XEXP (XVECEXP (pat, 0, 1), 1), 1));
break;
- case 265:
+ case 286:
ro[0] = *(ro_loc[0] = &XEXP (XVECEXP (pat, 0, 0), 1));
ro[1] = *(ro_loc[1] = &XEXP (XEXP (XVECEXP (pat, 0, 1), 0), 0));
break;
- case 264:
+ case 285:
ro[0] = *(ro_loc[0] = &XEXP (XEXP (XEXP (XEXP (XEXP (XVECEXP (pat, 0, 0), 1), 1), 0), 0), 0));
ro[1] = *(ro_loc[1] = &XEXP (XEXP (XEXP (XEXP (XEXP (XVECEXP (pat, 0, 0), 1), 1), 0), 1), 0));
ro[2] = *(ro_loc[2] = &XEXP (XVECEXP (pat, 0, 1), 0));
break;
- case 261:
+ case 282:
ro[0] = *(ro_loc[0] = &XEXP (XEXP (pat, 1), 0));
break;
- case 260:
+ case 281:
+ case 280:
+ case 279:
+ case 278:
+ case 277:
+ case 276:
+ case 275:
+ case 274:
+ case 273:
+ case 272:
+ ro[0] = *(ro_loc[0] = &XEXP (XEXP (XEXP (pat, 1), 2), 0));
+ break;
+
+ case 271:
+ case 269:
+ case 267:
+ case 265:
+ case 263:
+ case 261:
case 259:
- case 258:
case 257:
- case 256:
case 255:
- case 254:
case 253:
- case 252:
- case 251:
- ro[0] = *(ro_loc[0] = &XEXP (XEXP (XEXP (pat, 1), 2), 0));
- break;
-
- case 250:
- case 248:
- case 246:
- case 244:
- case 242:
- case 240:
- case 238:
- case 236:
- case 234:
- case 232:
ro[0] = *(ro_loc[0] = &XEXP (XEXP (XEXP (pat, 1), 1), 0));
break;
- case 230:
- case 228:
- case 226:
- case 224:
- case 222:
- case 220:
- case 218:
- case 216:
- case 214:
- case 212:
+ case 251:
+ case 249:
+ case 247:
+ case 245:
+ case 243:
+ case 241:
+ case 239:
+ case 237:
+ case 235:
+ case 233:
ro[0] = *(ro_loc[0] = &XEXP (pat, 0));
break;
- case 210:
- case 209:
+ case 231:
+ case 230:
ro[0] = *(ro_loc[0] = &XEXP (XEXP (pat, 1), 0));
ro[1] = *(ro_loc[1] = &XEXP (XEXP (pat, 1), 1));
ro[2] = *(ro_loc[2] = &XEXP (XEXP (pat, 1), 2));
break;
- case 208:
+ case 229:
ro[0] = *(ro_loc[0] = &XEXP (XEXP (pat, 1), 0));
ro[1] = *(ro_loc[1] = &XEXP (XEXP (pat, 1), 2));
break;
- case 207:
+ case 228:
ro[0] = *(ro_loc[0] = &XEXP (pat, 0));
ro[1] = *(ro_loc[1] = &XEXP (XEXP (pat, 1), 0));
ro[2] = *(ro_loc[2] = &XEXP (XEXP (XEXP (pat, 1), 1), 1));
break;
- case 206:
+ case 227:
ro[0] = *(ro_loc[0] = &XEXP (pat, 0));
ro[1] = *(ro_loc[1] = &XEXP (XEXP (XEXP (pat, 1), 0), 1));
ro[2] = *(ro_loc[2] = &XEXP (XEXP (pat, 1), 1));
break;
- case 205:
+ case 226:
ro[0] = *(ro_loc[0] = &XEXP (XEXP (pat, 0), 0));
ro[1] = const0_rtx;
ro_loc[1] = &junk;
@@ -252,9 +231,9 @@ insn_extract (insn)
ro[3] = *(ro_loc[3] = &XEXP (pat, 1));
break;
- case 195:
- case 189:
- case 183:
+ case 216:
+ case 210:
+ case 204:
ro[0] = *(ro_loc[0] = &XEXP (XVECEXP (pat, 0, 0), 0));
ro[1] = *(ro_loc[1] = &XEXP (XEXP (XVECEXP (pat, 0, 0), 1), 0));
ro[2] = *(ro_loc[2] = &XEXP (XEXP (XVECEXP (pat, 0, 0), 1), 1));
@@ -262,37 +241,37 @@ insn_extract (insn)
recog_dup_num[0] = 2;
break;
- case 177:
- case 174:
+ case 198:
+ case 195:
ro[0] = *(ro_loc[0] = &XEXP (pat, 0));
ro[1] = *(ro_loc[1] = &XEXP (XVECEXP (XEXP (pat, 1), 0, 0), 0));
break;
- case 176:
- case 175:
- case 173:
- case 172:
+ case 197:
+ case 196:
+ case 194:
+ case 193:
ro[0] = *(ro_loc[0] = &XEXP (pat, 0));
ro[1] = *(ro_loc[1] = &XVECEXP (XEXP (pat, 1), 0, 0));
break;
- case 293:
- case 291:
- case 171:
- case 170:
- case 168:
- case 165:
- case 163:
- case 160:
- case 158:
+ case 311:
+ case 309:
+ case 192:
+ case 191:
+ case 189:
+ case 186:
+ case 184:
+ case 181:
+ case 179:
ro[0] = *(ro_loc[0] = &XEXP (pat, 0));
ro[1] = *(ro_loc[1] = &XEXP (XEXP (XEXP (pat, 1), 0), 0));
break;
- case 142:
- case 141:
- case 140:
- case 139:
+ case 163:
+ case 162:
+ case 161:
+ case 160:
ro[0] = *(ro_loc[0] = &XEXP (XVECEXP (pat, 0, 0), 0));
ro[1] = *(ro_loc[1] = &XEXP (XEXP (XVECEXP (pat, 0, 0), 1), 0));
ro[2] = *(ro_loc[2] = &XEXP (XEXP (XVECEXP (pat, 0, 0), 1), 1));
@@ -303,65 +282,79 @@ insn_extract (insn)
recog_dup_num[1] = 2;
break;
- case 130:
- case 129:
- case 128:
- case 127:
- ro[0] = *(ro_loc[0] = &XEXP (pat, 0));
- ro[1] = *(ro_loc[1] = &XEXP (XEXP (XEXP (pat, 1), 0), 0));
- ro[2] = *(ro_loc[2] = &XEXP (XEXP (XEXP (pat, 1), 1), 0));
- break;
-
- case 276:
- case 204:
- case 203:
- case 202:
- case 201:
- case 200:
- case 199:
- case 198:
- case 197:
- case 196:
- case 194:
- case 192:
- case 191:
- case 190:
- case 188:
- case 186:
- case 185:
- case 184:
- case 182:
case 151:
case 150:
+ ro[0] = *(ro_loc[0] = &XEXP (XVECEXP (pat, 0, 0), 0));
+ ro[1] = *(ro_loc[1] = &XEXP (XEXP (XEXP (XEXP (XEXP (XVECEXP (pat, 0, 0), 1), 0), 0), 0), 0));
+ ro[2] = *(ro_loc[2] = &XEXP (XEXP (XEXP (XEXP (XEXP (XVECEXP (pat, 0, 0), 1), 0), 0), 1), 0));
+ ro[3] = *(ro_loc[3] = &XEXP (XVECEXP (pat, 0, 1), 0));
+ break;
+
case 149:
case 148:
case 147:
case 146:
+ ro[0] = *(ro_loc[0] = &XEXP (pat, 0));
+ ro[1] = *(ro_loc[1] = &XEXP (XEXP (XEXP (pat, 1), 0), 0));
+ ro[2] = *(ro_loc[2] = &XEXP (XEXP (XEXP (pat, 1), 1), 0));
+ break;
+
+ case 297:
+ case 225:
+ case 224:
+ case 223:
+ case 222:
+ case 221:
+ case 220:
+ case 219:
+ case 218:
+ case 217:
+ case 215:
+ case 213:
+ case 212:
+ case 211:
+ case 209:
+ case 207:
+ case 206:
+ case 205:
+ case 203:
+ case 172:
+ case 171:
+ case 170:
+ case 169:
+ case 168:
+ case 167:
+ case 166:
+ case 165:
+ case 164:
+ case 156:
+ case 155:
case 145:
case 144:
case 143:
- case 135:
- case 134:
- case 126:
- case 125:
- case 124:
- case 123:
- case 119:
- case 118:
- case 117:
- case 116:
- case 111:
- case 110:
- case 109:
- case 108:
+ case 142:
+ case 138:
+ case 137:
+ case 136:
+ case 130:
+ case 129:
+ case 128:
ro[0] = *(ro_loc[0] = &XEXP (pat, 0));
ro[1] = *(ro_loc[1] = &XEXP (XEXP (pat, 1), 0));
ro[2] = *(ro_loc[2] = &XEXP (XEXP (pat, 1), 1));
break;
- case 95:
- case 94:
- case 93:
+ case 135:
+ case 127:
+ ro[0] = *(ro_loc[0] = &XEXP (XVECEXP (pat, 0, 0), 0));
+ ro[1] = *(ro_loc[1] = &XEXP (XEXP (XVECEXP (pat, 0, 0), 1), 0));
+ ro[2] = *(ro_loc[2] = &XEXP (XEXP (XVECEXP (pat, 0, 0), 1), 1));
+ ro[3] = *(ro_loc[3] = &XEXP (XVECEXP (pat, 0, 1), 0));
+ break;
+
+ case 114:
+ case 113:
+ case 112:
ro[0] = *(ro_loc[0] = &XEXP (XVECEXP (pat, 0, 0), 0));
ro[1] = *(ro_loc[1] = &XEXP (XEXP (XEXP (XVECEXP (pat, 0, 0), 1), 0), 0));
ro[2] = *(ro_loc[2] = &XEXP (XVECEXP (pat, 0, 1), 0));
@@ -369,9 +362,9 @@ insn_extract (insn)
ro[4] = *(ro_loc[4] = &XEXP (XVECEXP (pat, 0, 3), 0));
break;
- case 89:
- case 88:
- case 87:
+ case 108:
+ case 107:
+ case 106:
ro[0] = *(ro_loc[0] = &XEXP (XVECEXP (pat, 0, 0), 0));
ro[1] = *(ro_loc[1] = &XEXP (XEXP (XEXP (XVECEXP (pat, 0, 0), 1), 0), 0));
ro[2] = *(ro_loc[2] = &XEXP (XVECEXP (pat, 0, 2), 0));
@@ -381,53 +374,66 @@ insn_extract (insn)
recog_dup_num[0] = 1;
break;
- case 78:
+ case 97:
ro[0] = *(ro_loc[0] = &XEXP (XVECEXP (pat, 0, 0), 0));
ro[1] = *(ro_loc[1] = &XEXP (XEXP (XVECEXP (pat, 0, 0), 1), 0));
ro[2] = *(ro_loc[2] = &XEXP (XVECEXP (pat, 0, 1), 0));
break;
+ case 201:
+ case 200:
+ case 199:
+ case 190:
+ case 188:
+ case 187:
+ case 185:
+ case 183:
+ case 182:
case 180:
- case 179:
case 178:
- case 169:
- case 167:
- case 166:
- case 164:
- case 162:
- case 161:
- case 159:
- case 157:
- case 156:
- case 155:
- case 154:
- case 153:
- case 152:
- case 107:
- case 106:
- case 105:
- case 104:
- case 103:
- case 102:
+ case 177:
+ case 176:
+ case 175:
+ case 174:
+ case 173:
+ case 126:
+ case 125:
+ case 124:
+ case 123:
+ case 122:
+ case 121:
+ case 99:
+ case 98:
+ case 95:
+ case 94:
+ case 93:
+ case 92:
+ case 91:
+ case 90:
+ case 89:
+ case 88:
+ case 87:
+ case 86:
+ case 85:
+ ro[0] = *(ro_loc[0] = &XEXP (pat, 0));
+ ro[1] = *(ro_loc[1] = &XEXP (XEXP (pat, 1), 0));
+ break;
+
+ case 84:
+ case 83:
case 80:
case 79:
- case 76:
- case 75:
case 74:
case 73:
- case 72:
- case 71:
- case 70:
- case 69:
- case 68:
- case 67:
- case 66:
- ro[0] = *(ro_loc[0] = &XEXP (pat, 0));
- ro[1] = *(ro_loc[1] = &XEXP (XEXP (pat, 1), 0));
+ ro[0] = *(ro_loc[0] = &XEXP (XVECEXP (pat, 0, 0), 0));
+ ro[1] = *(ro_loc[1] = &XEXP (XVECEXP (pat, 0, 0), 1));
+ ro[2] = *(ro_loc[2] = &XEXP (XVECEXP (pat, 0, 1), 0));
+ ro[3] = *(ro_loc[3] = &XEXP (XVECEXP (pat, 0, 2), 0));
break;
- case 62:
- case 59:
+ case 82:
+ case 76:
+ case 70:
ro[0] = *(ro_loc[0] = &XEXP (XVECEXP (pat, 0, 0), 0));
ro[1] = *(ro_loc[1] = &XEXP (XVECEXP (pat, 0, 0), 1));
recog_dup_loc[0] = &XEXP (XVECEXP (pat, 0, 1), 0);
@@ -436,28 +442,38 @@ insn_extract (insn)
recog_dup_num[1] = 0;
break;
- case 271:
- case 55:
- case 52:
+ case 68:
+ case 67:
+ ro[0] = *(ro_loc[0] = &XEXP (XVECEXP (pat, 0, 0), 0));
+ ro[1] = *(ro_loc[1] = &XEXP (XVECEXP (pat, 0, 0), 1));
+ ro[2] = *(ro_loc[2] = &XEXP (XVECEXP (pat, 0, 1), 0));
+ break;
+
+ case 292:
+ case 64:
+ case 57:
ro[0] = *(ro_loc[0] = &XEXP (XEXP (pat, 0), 0));
ro[1] = *(ro_loc[1] = &XEXP (pat, 1));
break;
- case 270:
- case 112:
- case 65:
- case 64:
- case 63:
- case 61:
+ case 291:
+ case 131:
+ case 81:
+ case 78:
+ case 75:
+ case 72:
+ case 69:
+ case 66:
+ case 62:
case 60:
+ case 59:
case 58:
- case 57:
- case 56:
- case 54:
+ case 55:
case 53:
+ case 52:
case 51:
case 50:
- case 49:
+ case 48:
case 47:
case 46:
ro[0] = *(ro_loc[0] = &XEXP (pat, 0));
@@ -520,7 +536,7 @@ insn_extract (insn)
ro[1] = *(ro_loc[1] = &XEXP (XVECEXP (pat, 0, 1), 0));
break;
- case 262:
+ case 283:
case 4:
case 2:
case 0:
diff --git a/gnu/usr.bin/cc/cc_int/insn-opinit.c b/gnu/usr.bin/cc/cc_int/insn-opinit.c
index 8ad7929..18eda5f 100644
--- a/gnu/usr.bin/cc/cc_int/insn-opinit.c
+++ b/gnu/usr.bin/cc/cc_int/insn-opinit.c
@@ -109,8 +109,14 @@ init_all_optabs ()
smul_optab->handlers[(int) SImode].insn_code = CODE_FOR_mulsi3;
umul_widen_optab->handlers[(int) HImode].insn_code = CODE_FOR_umulqihi3;
smul_widen_optab->handlers[(int) HImode].insn_code = CODE_FOR_mulqihi3;
- umul_widen_optab->handlers[(int) DImode].insn_code = CODE_FOR_umulsidi3;
- smul_widen_optab->handlers[(int) DImode].insn_code = CODE_FOR_mulsidi3;
+ if (HAVE_umulsidi3)
+ umul_widen_optab->handlers[(int) DImode].insn_code = CODE_FOR_umulsidi3;
+ if (HAVE_mulsidi3)
+ smul_widen_optab->handlers[(int) DImode].insn_code = CODE_FOR_mulsidi3;
+ if (HAVE_umulsi3_highpart)
+ umul_highpart_optab->handlers[(int) SImode].insn_code = CODE_FOR_umulsi3_highpart;
+ if (HAVE_smulsi3_highpart)
+ smul_highpart_optab->handlers[(int) SImode].insn_code = CODE_FOR_smulsi3_highpart;
if (HAVE_mulxf3)
smul_optab->handlers[(int) XFmode].insn_code = CODE_FOR_mulxf3;
if (HAVE_muldf3)
diff --git a/gnu/usr.bin/cc/cc_int/insn-output.c b/gnu/usr.bin/cc/cc_int/insn-output.c
index b354cf4..65b0ec5 100644
--- a/gnu/usr.bin/cc/cc_int/insn-output.c
+++ b/gnu/usr.bin/cc/cc_int/insn-output.c
@@ -79,7 +79,7 @@ output_6 (operands, insn)
if (find_regno_note (insn, REG_DEAD, FIRST_STACK_REG))
output_asm_insn (AS1 (fstp,%y0), operands);
- return (char *) output_fp_cc0_set (insn);
+ return output_fp_cc0_set (insn);
}
}
@@ -98,7 +98,7 @@ output_8 (operands, insn)
if (find_regno_note (insn, REG_DEAD, FIRST_STACK_REG))
output_asm_insn (AS1 (fstp,%y0), operands);
- return (char *) output_fp_cc0_set (insn);
+ return output_fp_cc0_set (insn);
}
}
@@ -117,7 +117,7 @@ output_10 (operands, insn)
if (find_regno_note (insn, REG_DEAD, FIRST_STACK_REG))
output_asm_insn (AS1 (fstp,%y0), operands);
- return (char *) output_fp_cc0_set (insn);
+ return output_fp_cc0_set (insn);
}
}
@@ -174,7 +174,7 @@ output_18 (operands, insn)
rtx *operands;
rtx insn;
{
- return (char *) output_float_compare (insn, operands);
+ return output_float_compare (insn, operands);
}
static char *
@@ -182,7 +182,7 @@ output_19 (operands, insn)
rtx *operands;
rtx insn;
{
- return (char *) output_float_compare (insn, operands);
+ return output_float_compare (insn, operands);
}
static char *
@@ -190,7 +190,7 @@ output_20 (operands, insn)
rtx *operands;
rtx insn;
{
- return (char *) output_float_compare (insn, operands);
+ return output_float_compare (insn, operands);
}
static char *
@@ -198,7 +198,7 @@ output_21 (operands, insn)
rtx *operands;
rtx insn;
{
- return (char *) output_float_compare (insn, operands);
+ return output_float_compare (insn, operands);
}
static char *
@@ -206,7 +206,7 @@ output_22 (operands, insn)
rtx *operands;
rtx insn;
{
- return (char *) output_float_compare (insn, operands);
+ return output_float_compare (insn, operands);
}
static char *
@@ -214,7 +214,7 @@ output_23 (operands, insn)
rtx *operands;
rtx insn;
{
- return (char *) output_float_compare (insn, operands);
+ return output_float_compare (insn, operands);
}
static char *
@@ -222,7 +222,7 @@ output_24 (operands, insn)
rtx *operands;
rtx insn;
{
- return (char *) output_float_compare (insn, operands);
+ return output_float_compare (insn, operands);
}
static char *
@@ -230,7 +230,7 @@ output_25 (operands, insn)
rtx *operands;
rtx insn;
{
- return (char *) output_float_compare (insn, operands);
+ return output_float_compare (insn, operands);
}
static char *
@@ -238,7 +238,7 @@ output_26 (operands, insn)
rtx *operands;
rtx insn;
{
- return (char *) output_float_compare (insn, operands);
+ return output_float_compare (insn, operands);
}
static char *
@@ -246,7 +246,7 @@ output_27 (operands, insn)
rtx *operands;
rtx insn;
{
- return (char *) output_float_compare (insn, operands);
+ return output_float_compare (insn, operands);
}
static char *
@@ -254,7 +254,7 @@ output_28 (operands, insn)
rtx *operands;
rtx insn;
{
- return (char *) output_float_compare (insn, operands);
+ return output_float_compare (insn, operands);
}
static char *
@@ -262,7 +262,7 @@ output_29 (operands, insn)
rtx *operands;
rtx insn;
{
- return (char *) output_float_compare (insn, operands);
+ return output_float_compare (insn, operands);
}
static char *
@@ -270,7 +270,7 @@ output_30 (operands, insn)
rtx *operands;
rtx insn;
{
- return (char *) output_float_compare (insn, operands);
+ return output_float_compare (insn, operands);
}
static char *
@@ -278,7 +278,7 @@ output_31 (operands, insn)
rtx *operands;
rtx insn;
{
- return (char *) output_float_compare (insn, operands);
+ return output_float_compare (insn, operands);
}
static char *
@@ -286,7 +286,7 @@ output_32 (operands, insn)
rtx *operands;
rtx insn;
{
- return (char *) output_float_compare (insn, operands);
+ return output_float_compare (insn, operands);
}
static char *
@@ -294,7 +294,7 @@ output_33 (operands, insn)
rtx *operands;
rtx insn;
{
- return (char *) output_float_compare (insn, operands);
+ return output_float_compare (insn, operands);
}
static char *
@@ -414,7 +414,7 @@ output_45 (operands, insn)
}
static char *
-output_49 (operands, insn)
+output_50 (operands, insn)
rtx *operands;
rtx insn;
{
@@ -436,12 +436,15 @@ output_49 (operands, insn)
/* Fastest way to change a 0 to a 1. */
return AS1 (inc%L0,%0);
+ if (flag_pic && SYMBOLIC_CONST (operands[1]))
+ return AS2 (lea%L0,%a1,%0);
+
return AS2 (mov%L0,%1,%0);
}
}
static char *
-output_51 (operands, insn)
+output_55 (operands, insn)
rtx *operands;
rtx insn;
{
@@ -451,7 +454,7 @@ output_51 (operands, insn)
if (REG_P (operands[0]) && operands[1] == const0_rtx)
return AS2 (xor%L0,%k0,%k0);
- if (REG_P (operands[0]) && operands[1] == const1_rtx
+ if (REG_P (operands[0]) && operands[1] == const1_rtx
&& (link = find_reg_note (insn, REG_WAS_0, 0))
/* Make sure the insn that stored the 0 is still present. */
&& ! INSN_DELETED_P (XEXP (link, 0))
@@ -476,7 +479,7 @@ output_51 (operands, insn)
}
static char *
-output_52 (operands, insn)
+output_57 (operands, insn)
rtx *operands;
rtx insn;
{
@@ -503,7 +506,15 @@ output_52 (operands, insn)
}
static char *
-output_53 (operands, insn)
+output_58 (operands, insn)
+ rtx *operands;
+ rtx insn;
+{
+ return AS1 (push%W0,%1);
+}
+
+static char *
+output_59 (operands, insn)
rtx *operands;
rtx insn;
{
@@ -515,7 +526,19 @@ output_53 (operands, insn)
}
static char *
-output_54 (operands, insn)
+output_60 (operands, insn)
+ rtx *operands;
+ rtx insn;
+{
+
+{
+ operands[1] = gen_rtx (REG, HImode, REGNO (operands[1]));
+ return AS1 (push%W0,%1);
+}
+}
+
+static char *
+output_62 (operands, insn)
rtx *operands;
rtx insn;
{
@@ -546,7 +569,7 @@ output_54 (operands, insn)
}
static char *
-output_55 (operands, insn)
+output_64 (operands, insn)
rtx *operands;
rtx insn;
{
@@ -580,7 +603,7 @@ output_55 (operands, insn)
}
static char *
-output_56 (operands, insn)
+output_66 (operands, insn)
rtx *operands;
rtx insn;
{
@@ -610,7 +633,57 @@ output_56 (operands, insn)
}
static char *
-output_57 (operands, insn)
+output_67 (operands, insn)
+ rtx *operands;
+ rtx insn;
+{
+
+{
+ if (STACK_REG_P (operands[1]))
+ {
+ rtx xops[3];
+
+ if (! STACK_TOP_P (operands[1]))
+ abort ();
+
+ xops[0] = AT_SP (SFmode);
+ xops[1] = GEN_INT (4);
+ xops[2] = stack_pointer_rtx;
+
+ output_asm_insn (AS2 (sub%L2,%1,%2), xops);
+
+ if (find_regno_note (insn, REG_DEAD, FIRST_STACK_REG))
+ output_asm_insn (AS1 (fstp%S0,%0), xops);
+ else
+ output_asm_insn (AS1 (fst%S0,%0), xops);
+ RET;
+ }
+
+ else if (GET_CODE (operands[1]) != MEM || GET_CODE (operands[2]) != REG)
+ return AS1 (push%L1,%1);
+
+ else
+ {
+ output_asm_insn (AS2 (mov%L2,%1,%2), operands);
+ return AS1 (push%L2,%2);
+ }
+}
+}
+
+static char *
+output_68 (operands, insn)
+ rtx *operands;
+ rtx insn;
+{
+
+{
+ output_asm_insn (AS2 (mov%L2,%1,%2), operands);
+ return AS2 (mov%L0,%2,%0);
+}
+}
+
+static char *
+output_69 (operands, insn)
rtx *operands;
rtx insn;
{
@@ -655,19 +728,33 @@ output_57 (operands, insn)
/* Handle other kinds of reads to the 387 */
if (STACK_TOP_P (operands[0]) && GET_CODE (operands[1]) == CONST_DOUBLE)
- return (char *) output_move_const_single (operands);
+ return output_move_const_single (operands);
if (STACK_TOP_P (operands[0]))
return AS1 (fld%z1,%y1);
/* Handle all SFmode moves not involving the 387 */
- return (char *) singlemove_string (operands);
+ return singlemove_string (operands);
}
}
static char *
-output_58 (operands, insn)
+output_70 (operands, insn)
+ rtx *operands;
+ rtx insn;
+{
+
+{
+ if (STACK_TOP_P (operands[0]))
+ return AS1 (fxch,%1);
+ else
+ return AS1 (fxch,%0);
+}
+}
+
+static char *
+output_72 (operands, insn)
rtx *operands;
rtx insn;
{
@@ -691,26 +778,53 @@ output_58 (operands, insn)
RET;
}
else
- return (char *) output_move_double (operands);
+ return output_move_double (operands);
}
}
static char *
-output_59 (operands, insn)
+output_73 (operands, insn)
rtx *operands;
rtx insn;
{
{
- if (STACK_TOP_P (operands[0]))
- return AS1 (fxch,%1);
+ if (STACK_REG_P (operands[1]))
+ {
+ rtx xops[3];
+
+ xops[0] = AT_SP (SFmode);
+ xops[1] = GEN_INT (8);
+ xops[2] = stack_pointer_rtx;
+
+ output_asm_insn (AS2 (sub%L2,%1,%2), xops);
+
+ if (find_regno_note (insn, REG_DEAD, FIRST_STACK_REG))
+ output_asm_insn (AS1 (fstp%Q0,%0), xops);
+ else
+ output_asm_insn (AS1 (fst%Q0,%0), xops);
+
+ RET;
+ }
+
+ else if (GET_CODE (operands[1]) != MEM)
+ return output_move_double (operands);
+
else
- return AS1 (fxch,%0);
+ return output_move_pushmem (operands, insn, GET_MODE_SIZE (DFmode), 2, 4);
}
}
static char *
-output_60 (operands, insn)
+output_74 (operands, insn)
+ rtx *operands;
+ rtx insn;
+{
+ return output_move_memory (operands, insn, GET_MODE_SIZE (DFmode), 2, 4);
+}
+
+static char *
+output_75 (operands, insn)
rtx *operands;
rtx insn;
{
@@ -755,19 +869,33 @@ output_60 (operands, insn)
/* Handle other kinds of reads to the 387 */
if (STACK_TOP_P (operands[0]) && GET_CODE (operands[1]) == CONST_DOUBLE)
- return (char *) output_move_const_single (operands);
+ return output_move_const_single (operands);
if (STACK_TOP_P (operands[0]))
return AS1 (fld%z1,%y1);
/* Handle all DFmode moves not involving the 387 */
- return (char *) output_move_double (operands);
+ return output_move_double (operands);
}
}
static char *
-output_61 (operands, insn)
+output_76 (operands, insn)
+ rtx *operands;
+ rtx insn;
+{
+
+{
+ if (STACK_TOP_P (operands[0]))
+ return AS1 (fxch,%1);
+ else
+ return AS1 (fxch,%0);
+}
+}
+
+static char *
+output_78 (operands, insn)
rtx *operands;
rtx insn;
{
@@ -789,26 +917,52 @@ output_61 (operands, insn)
RET;
}
else
- return (char *) output_move_double (operands);
+ return output_move_double (operands);
}
}
static char *
-output_62 (operands, insn)
+output_79 (operands, insn)
rtx *operands;
rtx insn;
{
{
- if (STACK_TOP_P (operands[0]))
- return AS1 (fxch,%1);
+ if (STACK_REG_P (operands[1]))
+ {
+ rtx xops[3];
+
+ xops[0] = AT_SP (SFmode);
+ xops[1] = GEN_INT (12);
+ xops[2] = stack_pointer_rtx;
+
+ output_asm_insn (AS2 (sub%L2,%1,%2), xops);
+ output_asm_insn (AS1 (fstp%T0,%0), xops);
+ if (! find_regno_note (insn, REG_DEAD, FIRST_STACK_REG))
+ output_asm_insn (AS1 (fld%T0,%0), xops);
+
+ RET;
+ }
+
+ else if (GET_CODE (operands[1]) != MEM
+ || GET_CODE (operands[2]) != REG)
+ return output_move_double (operands);
+
else
- return AS1 (fxch,%0);
+ return output_move_pushmem (operands, insn, GET_MODE_SIZE (XFmode), 2, 4);
+}
}
+
+static char *
+output_80 (operands, insn)
+ rtx *operands;
+ rtx insn;
+{
+ return output_move_memory (operands, insn, GET_MODE_SIZE (XFmode), 2, 4);
}
static char *
-output_63 (operands, insn)
+output_81 (operands, insn)
rtx *operands;
rtx insn;
{
@@ -854,47 +1008,70 @@ output_63 (operands, insn)
/* Handle other kinds of reads to the 387 */
if (STACK_TOP_P (operands[0]) && GET_CODE (operands[1]) == CONST_DOUBLE)
- return (char *) output_move_const_single (operands);
+ return output_move_const_single (operands);
if (STACK_TOP_P (operands[0]))
return AS1 (fld%z1,%y1);
/* Handle all XFmode moves not involving the 387 */
- return (char *) output_move_double (operands);
+ return output_move_double (operands);
}
}
static char *
-output_64 (operands, insn)
+output_82 (operands, insn)
rtx *operands;
rtx insn;
{
{
- return (char *) output_move_double (operands);
+ if (STACK_TOP_P (operands[0]))
+ return AS1 (fxch,%1);
+ else
+ return AS1 (fxch,%0);
}
}
static char *
-output_65 (operands, insn)
+output_83 (operands, insn)
rtx *operands;
rtx insn;
{
{
- return (char *) output_move_double (operands);
+ if (GET_CODE (operands[1]) != MEM)
+ return output_move_double (operands);
+
+ else
+ return output_move_pushmem (operands, insn, GET_MODE_SIZE (DImode), 2, 4);
}
}
static char *
-output_66 (operands, insn)
+output_84 (operands, insn)
rtx *operands;
rtx insn;
{
{
- if ((TARGET_486 || REGNO (operands[0]) == 0)
+ rtx low[2], high[2], xop[6];
+
+ if (GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM)
+ return output_move_double (operands);
+ else
+ return output_move_memory (operands, insn, GET_MODE_SIZE (DImode), 2, 4);
+}
+}
+
+static char *
+output_85 (operands, insn)
+ rtx *operands;
+ rtx insn;
+{
+
+{
+ if ((!TARGET_386 || REGNO (operands[0]) == 0)
&& REG_P (operands[1]) && REGNO (operands[0]) == REGNO (operands[1]))
{
rtx xops[2];
@@ -913,13 +1090,13 @@ output_66 (operands, insn)
}
static char *
-output_67 (operands, insn)
+output_86 (operands, insn)
rtx *operands;
rtx insn;
{
{
- if ((TARGET_486 || REGNO (operands[0]) == 0)
+ if ((!TARGET_386 || REGNO (operands[0]) == 0)
&& REG_P (operands[1]) && REGNO (operands[0]) == REGNO (operands[1]))
{
rtx xops[2];
@@ -938,13 +1115,13 @@ output_67 (operands, insn)
}
static char *
-output_68 (operands, insn)
+output_87 (operands, insn)
rtx *operands;
rtx insn;
{
{
- if ((TARGET_486 || REGNO (operands[0]) == 0)
+ if ((!TARGET_386 || REGNO (operands[0]) == 0)
&& REG_P (operands[1]) && REGNO (operands[0]) == REGNO (operands[1]))
{
rtx xops[2];
@@ -963,7 +1140,7 @@ output_68 (operands, insn)
}
static char *
-output_69 (operands, insn)
+output_88 (operands, insn)
rtx *operands;
rtx insn;
{
@@ -975,7 +1152,7 @@ output_69 (operands, insn)
}
static char *
-output_70 (operands, insn)
+output_89 (operands, insn)
rtx *operands;
rtx insn;
{
@@ -1000,7 +1177,7 @@ output_70 (operands, insn)
}
static char *
-output_71 (operands, insn)
+output_90 (operands, insn)
rtx *operands;
rtx insn;
{
@@ -1023,7 +1200,7 @@ output_71 (operands, insn)
}
static char *
-output_72 (operands, insn)
+output_91 (operands, insn)
rtx *operands;
rtx insn;
{
@@ -1042,7 +1219,7 @@ output_72 (operands, insn)
}
static char *
-output_73 (operands, insn)
+output_92 (operands, insn)
rtx *operands;
rtx insn;
{
@@ -1057,7 +1234,7 @@ output_73 (operands, insn)
}
static char *
-output_74 (operands, insn)
+output_93 (operands, insn)
rtx *operands;
rtx insn;
{
@@ -1093,7 +1270,7 @@ output_74 (operands, insn)
}
static char *
-output_75 (operands, insn)
+output_94 (operands, insn)
rtx *operands;
rtx insn;
{
@@ -1129,7 +1306,7 @@ output_75 (operands, insn)
}
static char *
-output_76 (operands, insn)
+output_95 (operands, insn)
rtx *operands;
rtx insn;
{
@@ -1165,7 +1342,7 @@ output_76 (operands, insn)
}
static char *
-output_78 (operands, insn)
+output_97 (operands, insn)
rtx *operands;
rtx insn;
{
@@ -1191,7 +1368,7 @@ output_78 (operands, insn)
}
static char *
-output_79 (operands, insn)
+output_98 (operands, insn)
rtx *operands;
rtx insn;
{
@@ -1225,7 +1402,7 @@ output_79 (operands, insn)
}
static char *
-output_80 (operands, insn)
+output_99 (operands, insn)
rtx *operands;
rtx insn;
{
@@ -1259,55 +1436,55 @@ output_80 (operands, insn)
}
static char *
-output_87 (operands, insn)
+output_106 (operands, insn)
rtx *operands;
rtx insn;
{
- return (char *) output_fix_trunc (insn, operands);
+ return output_fix_trunc (insn, operands);
}
static char *
-output_88 (operands, insn)
+output_107 (operands, insn)
rtx *operands;
rtx insn;
{
- return (char *) output_fix_trunc (insn, operands);
+ return output_fix_trunc (insn, operands);
}
static char *
-output_89 (operands, insn)
+output_108 (operands, insn)
rtx *operands;
rtx insn;
{
- return (char *) output_fix_trunc (insn, operands);
+ return output_fix_trunc (insn, operands);
}
static char *
-output_93 (operands, insn)
+output_112 (operands, insn)
rtx *operands;
rtx insn;
{
- return (char *) output_fix_trunc (insn, operands);
+ return output_fix_trunc (insn, operands);
}
static char *
-output_94 (operands, insn)
+output_113 (operands, insn)
rtx *operands;
rtx insn;
{
- return (char *) output_fix_trunc (insn, operands);
+ return output_fix_trunc (insn, operands);
}
static char *
-output_95 (operands, insn)
+output_114 (operands, insn)
rtx *operands;
rtx insn;
{
- return (char *) output_fix_trunc (insn, operands);
+ return output_fix_trunc (insn, operands);
}
static char *
-output_102 (operands, insn)
+output_121 (operands, insn)
rtx *operands;
rtx insn;
{
@@ -1326,7 +1503,7 @@ output_102 (operands, insn)
}
static char *
-output_103 (operands, insn)
+output_122 (operands, insn)
rtx *operands;
rtx insn;
{
@@ -1345,7 +1522,7 @@ output_103 (operands, insn)
}
static char *
-output_104 (operands, insn)
+output_123 (operands, insn)
rtx *operands;
rtx insn;
{
@@ -1364,7 +1541,7 @@ output_104 (operands, insn)
}
static char *
-output_105 (operands, insn)
+output_124 (operands, insn)
rtx *operands;
rtx insn;
{
@@ -1383,7 +1560,7 @@ output_105 (operands, insn)
}
static char *
-output_106 (operands, insn)
+output_125 (operands, insn)
rtx *operands;
rtx insn;
{
@@ -1402,7 +1579,7 @@ output_106 (operands, insn)
}
static char *
-output_107 (operands, insn)
+output_126 (operands, insn)
rtx *operands;
rtx insn;
{
@@ -1421,31 +1598,80 @@ output_107 (operands, insn)
}
static char *
-output_108 (operands, insn)
+output_127 (operands, insn)
rtx *operands;
rtx insn;
{
{
- rtx low[3], high[3];
+ rtx low[3], high[3], xops[7], temp;
CC_STATUS_INIT;
+ if (rtx_equal_p (operands[0], operands[2]))
+ {
+ temp = operands[1];
+ operands[1] = operands[2];
+ operands[2] = temp;
+ }
+
split_di (operands, 3, low, high);
+ if (!rtx_equal_p (operands[0], operands[1]))
+ {
+ xops[0] = high[0];
+ xops[1] = low[0];
+ xops[2] = high[1];
+ xops[3] = low[1];
- if (GET_CODE (low[2]) != CONST_INT || INTVAL (low[2]) != 0)
+ if (GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM)
+ {
+ output_asm_insn (AS2 (mov%L1,%3,%1), xops);
+ output_asm_insn (AS2 (mov%L0,%2,%0), xops);
+ }
+ else
+ {
+ xops[4] = high[2];
+ xops[5] = low[2];
+ xops[6] = operands[3];
+ output_asm_insn (AS2 (mov%L6,%3,%6), xops);
+ output_asm_insn (AS2 (add%L6,%5,%6), xops);
+ output_asm_insn (AS2 (mov%L1,%6,%1), xops);
+ output_asm_insn (AS2 (mov%L6,%2,%6), xops);
+ output_asm_insn (AS2 (adc%L6,%4,%6), xops);
+ output_asm_insn (AS2 (mov%L0,%6,%0), xops);
+ RET;
+ }
+ }
+
+ if (GET_CODE (operands[3]) == REG && GET_CODE (operands[2]) != REG)
+ {
+ xops[0] = high[0];
+ xops[1] = low[0];
+ xops[2] = high[2];
+ xops[3] = low[2];
+ xops[4] = operands[3];
+
+ output_asm_insn (AS2 (mov%L4,%3,%4), xops);
+ output_asm_insn (AS2 (add%L1,%4,%1), xops);
+ output_asm_insn (AS2 (mov%L4,%2,%4), xops);
+ output_asm_insn (AS2 (adc%L0,%4,%0), xops);
+ }
+
+ else if (GET_CODE (low[2]) != CONST_INT || INTVAL (low[2]) != 0)
{
output_asm_insn (AS2 (add%L0,%2,%0), low);
output_asm_insn (AS2 (adc%L0,%2,%0), high);
}
+
else
output_asm_insn (AS2 (add%L0,%2,%0), high);
+
RET;
}
}
static char *
-output_109 (operands, insn)
+output_128 (operands, insn)
rtx *operands;
rtx insn;
{
@@ -1456,23 +1682,20 @@ output_109 (operands, insn)
if (REG_P (operands[2]) && REGNO (operands[0]) == REGNO (operands[2]))
return AS2 (add%L0,%1,%0);
- if (! TARGET_486 || ! REG_P (operands[2]))
- {
- CC_STATUS_INIT;
+ if (operands[2] == stack_pointer_rtx)
+ {
+ rtx temp;
- if (operands[2] == stack_pointer_rtx)
- {
- rtx temp;
+ temp = operands[1];
+ operands[1] = operands[2];
+ operands[2] = temp;
+ }
- temp = operands[1];
- operands[1] = operands[2];
- operands[2] = temp;
- }
- if (operands[2] != stack_pointer_rtx)
- {
- operands[1] = SET_SRC (PATTERN (insn));
- return AS2 (lea%L0,%a1,%0);
- }
+ if (operands[2] != stack_pointer_rtx)
+ {
+ CC_STATUS_INIT;
+ operands[1] = SET_SRC (PATTERN (insn));
+ return AS2 (lea%L0,%a1,%0);
}
output_asm_insn (AS2 (mov%L0,%1,%0), operands);
@@ -1489,7 +1712,7 @@ output_109 (operands, insn)
}
static char *
-output_110 (operands, insn)
+output_129 (operands, insn)
rtx *operands;
rtx insn;
{
@@ -1525,7 +1748,7 @@ output_110 (operands, insn)
}
static char *
-output_111 (operands, insn)
+output_130 (operands, insn)
rtx *operands;
rtx insn;
{
@@ -1544,7 +1767,7 @@ output_111 (operands, insn)
}
static char *
-output_112 (operands, insn)
+output_131 (operands, insn)
rtx *operands;
rtx insn;
{
@@ -1572,23 +1795,65 @@ output_112 (operands, insn)
}
static char *
-output_116 (operands, insn)
+output_135 (operands, insn)
rtx *operands;
rtx insn;
{
{
- rtx low[3], high[3];
+ rtx low[3], high[3], xops[7];
CC_STATUS_INIT;
split_di (operands, 3, low, high);
- if (GET_CODE (low[2]) != CONST_INT || INTVAL (low[2]) != 0)
+ if (!rtx_equal_p (operands[0], operands[1]))
+ {
+ xops[0] = high[0];
+ xops[1] = low[0];
+ xops[2] = high[1];
+ xops[3] = low[1];
+
+ if (GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM)
+ {
+ output_asm_insn (AS2 (mov%L1,%3,%1), xops);
+ output_asm_insn (AS2 (mov%L0,%2,%0), xops);
+ }
+ else
+ {
+ xops[4] = high[2];
+ xops[5] = low[2];
+ xops[6] = operands[3];
+ output_asm_insn (AS2 (mov%L6,%3,%6), xops);
+ output_asm_insn (AS2 (sub%L6,%5,%6), xops);
+ output_asm_insn (AS2 (mov%L1,%6,%1), xops);
+ output_asm_insn (AS2 (mov%L6,%2,%6), xops);
+ output_asm_insn (AS2 (sbb%L6,%4,%6), xops);
+ output_asm_insn (AS2 (mov%L0,%6,%0), xops);
+ RET;
+ }
+ }
+
+ if (GET_CODE (operands[3]) == REG)
+ {
+ xops[0] = high[0];
+ xops[1] = low[0];
+ xops[2] = high[2];
+ xops[3] = low[2];
+ xops[4] = operands[3];
+
+ output_asm_insn (AS2 (mov%L4,%3,%4), xops);
+ output_asm_insn (AS2 (sub%L1,%4,%1), xops);
+ output_asm_insn (AS2 (mov%L4,%2,%4), xops);
+ output_asm_insn (AS2 (sbb%L0,%4,%0), xops);
+ }
+
+ else if (GET_CODE (low[2]) != CONST_INT || INTVAL (low[2]) != 0)
{
output_asm_insn (AS2 (sub%L0,%2,%0), low);
output_asm_insn (AS2 (sbb%L0,%2,%0), high);
}
+
else
output_asm_insn (AS2 (sub%L0,%2,%0), high);
@@ -1597,7 +1862,7 @@ output_116 (operands, insn)
}
static char *
-output_117 (operands, insn)
+output_136 (operands, insn)
rtx *operands;
rtx insn;
{
@@ -1605,7 +1870,7 @@ output_117 (operands, insn)
}
static char *
-output_118 (operands, insn)
+output_137 (operands, insn)
rtx *operands;
rtx insn;
{
@@ -1613,7 +1878,7 @@ output_118 (operands, insn)
}
static char *
-output_119 (operands, insn)
+output_138 (operands, insn)
rtx *operands;
rtx insn;
{
@@ -1621,7 +1886,7 @@ output_119 (operands, insn)
}
static char *
-output_123 (operands, insn)
+output_142 (operands, insn)
rtx *operands;
rtx insn;
{
@@ -1629,7 +1894,7 @@ output_123 (operands, insn)
}
static char *
-output_124 (operands, insn)
+output_143 (operands, insn)
rtx *operands;
rtx insn;
{
@@ -1645,7 +1910,7 @@ output_124 (operands, insn)
}
static char *
-output_125 (operands, insn)
+output_144 (operands, insn)
rtx *operands;
rtx insn;
{
@@ -1653,7 +1918,7 @@ output_125 (operands, insn)
}
static char *
-output_126 (operands, insn)
+output_145 (operands, insn)
rtx *operands;
rtx insn;
{
@@ -1669,7 +1934,7 @@ output_126 (operands, insn)
}
static char *
-output_139 (operands, insn)
+output_160 (operands, insn)
rtx *operands;
rtx insn;
{
@@ -1685,7 +1950,7 @@ output_139 (operands, insn)
}
static char *
-output_141 (operands, insn)
+output_162 (operands, insn)
rtx *operands;
rtx insn;
{
@@ -1697,7 +1962,7 @@ output_141 (operands, insn)
}
static char *
-output_142 (operands, insn)
+output_163 (operands, insn)
rtx *operands;
rtx insn;
{
@@ -1709,7 +1974,7 @@ output_142 (operands, insn)
}
static char *
-output_143 (operands, insn)
+output_164 (operands, insn)
rtx *operands;
rtx insn;
{
@@ -1721,7 +1986,7 @@ output_143 (operands, insn)
if (INTVAL (operands[2]) == 0xffff && REG_P (operands[0])
&& (! REG_P (operands[1])
|| REGNO (operands[0]) != 0 || REGNO (operands[1]) != 0)
- && (! TARGET_486 || ! rtx_equal_p (operands[0], operands[1])))
+ && (TARGET_386 || ! rtx_equal_p (operands[0], operands[1])))
{
/* ??? tege: Should forget CC_STATUS only if we clobber a
remembered operand. Fix that later. */
@@ -1737,7 +2002,7 @@ output_143 (operands, insn)
&& !(REG_P (operands[1]) && NON_QI_REG_P (operands[1]))
&& (! REG_P (operands[1])
|| REGNO (operands[0]) != 0 || REGNO (operands[1]) != 0)
- && (! TARGET_486 || ! rtx_equal_p (operands[0], operands[1])))
+ && (TARGET_386 || ! rtx_equal_p (operands[0], operands[1])))
{
/* ??? tege: Should forget CC_STATUS only if we clobber a
remembered operand. Fix that later. */
@@ -1789,7 +2054,7 @@ output_143 (operands, insn)
}
static char *
-output_144 (operands, insn)
+output_165 (operands, insn)
rtx *operands;
rtx insn;
{
@@ -1836,7 +2101,7 @@ output_144 (operands, insn)
}
static char *
-output_145 (operands, insn)
+output_166 (operands, insn)
rtx *operands;
rtx insn;
{
@@ -1844,7 +2109,7 @@ output_145 (operands, insn)
}
static char *
-output_146 (operands, insn)
+output_167 (operands, insn)
rtx *operands;
rtx insn;
{
@@ -1881,7 +2146,7 @@ output_146 (operands, insn)
}
static char *
-output_147 (operands, insn)
+output_168 (operands, insn)
rtx *operands;
rtx insn;
{
@@ -1924,7 +2189,7 @@ output_147 (operands, insn)
}
static char *
-output_148 (operands, insn)
+output_169 (operands, insn)
rtx *operands;
rtx insn;
{
@@ -1932,7 +2197,7 @@ output_148 (operands, insn)
}
static char *
-output_149 (operands, insn)
+output_170 (operands, insn)
rtx *operands;
rtx insn;
{
@@ -1969,7 +2234,7 @@ output_149 (operands, insn)
}
static char *
-output_150 (operands, insn)
+output_171 (operands, insn)
rtx *operands;
rtx insn;
{
@@ -2012,7 +2277,7 @@ output_150 (operands, insn)
}
static char *
-output_151 (operands, insn)
+output_172 (operands, insn)
rtx *operands;
rtx insn;
{
@@ -2020,7 +2285,7 @@ output_151 (operands, insn)
}
static char *
-output_152 (operands, insn)
+output_173 (operands, insn)
rtx *operands;
rtx insn;
{
@@ -2042,7 +2307,7 @@ output_152 (operands, insn)
}
static char *
-output_182 (operands, insn)
+output_203 (operands, insn)
rtx *operands;
rtx insn;
{
@@ -2079,7 +2344,7 @@ output_182 (operands, insn)
}
static char *
-output_183 (operands, insn)
+output_204 (operands, insn)
rtx *operands;
rtx insn;
{
@@ -2114,7 +2379,7 @@ output_183 (operands, insn)
}
static char *
-output_184 (operands, insn)
+output_205 (operands, insn)
rtx *operands;
rtx insn;
{
@@ -2122,7 +2387,7 @@ output_184 (operands, insn)
{
if (REG_P (operands[0]) && REGNO (operands[0]) != REGNO (operands[1]))
{
- if (TARGET_486 && INTVAL (operands[2]) == 1)
+ if (!TARGET_386 && INTVAL (operands[2]) == 1)
{
output_asm_insn (AS2 (mov%L0,%1,%0), operands);
return AS2 (add%L0,%1,%0);
@@ -2153,7 +2418,7 @@ output_184 (operands, insn)
}
static char *
-output_185 (operands, insn)
+output_206 (operands, insn)
rtx *operands;
rtx insn;
{
@@ -2170,7 +2435,7 @@ output_185 (operands, insn)
}
static char *
-output_186 (operands, insn)
+output_207 (operands, insn)
rtx *operands;
rtx insn;
{
@@ -2187,7 +2452,7 @@ output_186 (operands, insn)
}
static char *
-output_188 (operands, insn)
+output_209 (operands, insn)
rtx *operands;
rtx insn;
{
@@ -2226,7 +2491,7 @@ output_188 (operands, insn)
}
static char *
-output_189 (operands, insn)
+output_210 (operands, insn)
rtx *operands;
rtx insn;
{
@@ -2261,7 +2526,7 @@ output_189 (operands, insn)
}
static char *
-output_190 (operands, insn)
+output_211 (operands, insn)
rtx *operands;
rtx insn;
{
@@ -2275,7 +2540,7 @@ output_190 (operands, insn)
}
static char *
-output_191 (operands, insn)
+output_212 (operands, insn)
rtx *operands;
rtx insn;
{
@@ -2289,7 +2554,7 @@ output_191 (operands, insn)
}
static char *
-output_192 (operands, insn)
+output_213 (operands, insn)
rtx *operands;
rtx insn;
{
@@ -2303,7 +2568,7 @@ output_192 (operands, insn)
}
static char *
-output_194 (operands, insn)
+output_215 (operands, insn)
rtx *operands;
rtx insn;
{
@@ -2341,7 +2606,7 @@ output_194 (operands, insn)
}
static char *
-output_195 (operands, insn)
+output_216 (operands, insn)
rtx *operands;
rtx insn;
{
@@ -2376,7 +2641,7 @@ output_195 (operands, insn)
}
static char *
-output_196 (operands, insn)
+output_217 (operands, insn)
rtx *operands;
rtx insn;
{
@@ -2390,7 +2655,7 @@ output_196 (operands, insn)
}
static char *
-output_197 (operands, insn)
+output_218 (operands, insn)
rtx *operands;
rtx insn;
{
@@ -2404,7 +2669,7 @@ output_197 (operands, insn)
}
static char *
-output_198 (operands, insn)
+output_219 (operands, insn)
rtx *operands;
rtx insn;
{
@@ -2418,7 +2683,7 @@ output_198 (operands, insn)
}
static char *
-output_199 (operands, insn)
+output_220 (operands, insn)
rtx *operands;
rtx insn;
{
@@ -2432,7 +2697,7 @@ output_199 (operands, insn)
}
static char *
-output_200 (operands, insn)
+output_221 (operands, insn)
rtx *operands;
rtx insn;
{
@@ -2446,7 +2711,7 @@ output_200 (operands, insn)
}
static char *
-output_201 (operands, insn)
+output_222 (operands, insn)
rtx *operands;
rtx insn;
{
@@ -2460,7 +2725,7 @@ output_201 (operands, insn)
}
static char *
-output_202 (operands, insn)
+output_223 (operands, insn)
rtx *operands;
rtx insn;
{
@@ -2474,7 +2739,7 @@ output_202 (operands, insn)
}
static char *
-output_203 (operands, insn)
+output_224 (operands, insn)
rtx *operands;
rtx insn;
{
@@ -2488,7 +2753,7 @@ output_203 (operands, insn)
}
static char *
-output_204 (operands, insn)
+output_225 (operands, insn)
rtx *operands;
rtx insn;
{
@@ -2502,7 +2767,7 @@ output_204 (operands, insn)
}
static char *
-output_205 (operands, insn)
+output_226 (operands, insn)
rtx *operands;
rtx insn;
{
@@ -2518,7 +2783,7 @@ output_205 (operands, insn)
}
static char *
-output_206 (operands, insn)
+output_227 (operands, insn)
rtx *operands;
rtx insn;
{
@@ -2531,7 +2796,7 @@ output_206 (operands, insn)
}
static char *
-output_207 (operands, insn)
+output_228 (operands, insn)
rtx *operands;
rtx insn;
{
@@ -2544,7 +2809,7 @@ output_207 (operands, insn)
}
static char *
-output_208 (operands, insn)
+output_229 (operands, insn)
rtx *operands;
rtx insn;
{
@@ -2556,7 +2821,7 @@ output_208 (operands, insn)
}
static char *
-output_209 (operands, insn)
+output_230 (operands, insn)
rtx *operands;
rtx insn;
{
@@ -2588,7 +2853,7 @@ output_209 (operands, insn)
}
static char *
-output_210 (operands, insn)
+output_231 (operands, insn)
rtx *operands;
rtx insn;
{
@@ -2646,7 +2911,7 @@ output_210 (operands, insn)
}
static char *
-output_212 (operands, insn)
+output_233 (operands, insn)
rtx *operands;
rtx insn;
{
@@ -2660,7 +2925,7 @@ output_212 (operands, insn)
}
static char *
-output_214 (operands, insn)
+output_235 (operands, insn)
rtx *operands;
rtx insn;
{
@@ -2675,7 +2940,7 @@ output_214 (operands, insn)
}
static char *
-output_216 (operands, insn)
+output_237 (operands, insn)
rtx *operands;
rtx insn;
{
@@ -2689,15 +2954,15 @@ output_216 (operands, insn)
}
static char *
-output_218 (operands, insn)
+output_239 (operands, insn)
rtx *operands;
rtx insn;
{
- return "seta %0";
+ return "seta %0";
}
static char *
-output_220 (operands, insn)
+output_241 (operands, insn)
rtx *operands;
rtx insn;
{
@@ -2711,15 +2976,15 @@ output_220 (operands, insn)
}
static char *
-output_222 (operands, insn)
+output_243 (operands, insn)
rtx *operands;
rtx insn;
{
- return "setb %0";
+ return "setb %0";
}
static char *
-output_224 (operands, insn)
+output_245 (operands, insn)
rtx *operands;
rtx insn;
{
@@ -2733,15 +2998,15 @@ output_224 (operands, insn)
}
static char *
-output_226 (operands, insn)
+output_247 (operands, insn)
rtx *operands;
rtx insn;
{
- return "setae %0";
+ return "setae %0";
}
static char *
-output_228 (operands, insn)
+output_249 (operands, insn)
rtx *operands;
rtx insn;
{
@@ -2755,15 +3020,15 @@ output_228 (operands, insn)
}
static char *
-output_230 (operands, insn)
+output_251 (operands, insn)
rtx *operands;
rtx insn;
{
- return "setbe %0";
+ return "setbe %0";
}
static char *
-output_232 (operands, insn)
+output_253 (operands, insn)
rtx *operands;
rtx insn;
{
@@ -2777,7 +3042,7 @@ output_232 (operands, insn)
}
static char *
-output_234 (operands, insn)
+output_255 (operands, insn)
rtx *operands;
rtx insn;
{
@@ -2791,7 +3056,7 @@ output_234 (operands, insn)
}
static char *
-output_236 (operands, insn)
+output_257 (operands, insn)
rtx *operands;
rtx insn;
{
@@ -2805,7 +3070,7 @@ output_236 (operands, insn)
}
static char *
-output_240 (operands, insn)
+output_261 (operands, insn)
rtx *operands;
rtx insn;
{
@@ -2819,7 +3084,7 @@ output_240 (operands, insn)
}
static char *
-output_244 (operands, insn)
+output_265 (operands, insn)
rtx *operands;
rtx insn;
{
@@ -2833,7 +3098,7 @@ output_244 (operands, insn)
}
static char *
-output_248 (operands, insn)
+output_269 (operands, insn)
rtx *operands;
rtx insn;
{
@@ -2847,7 +3112,7 @@ output_248 (operands, insn)
}
static char *
-output_251 (operands, insn)
+output_272 (operands, insn)
rtx *operands;
rtx insn;
{
@@ -2861,7 +3126,7 @@ output_251 (operands, insn)
}
static char *
-output_252 (operands, insn)
+output_273 (operands, insn)
rtx *operands;
rtx insn;
{
@@ -2875,7 +3140,7 @@ output_252 (operands, insn)
}
static char *
-output_253 (operands, insn)
+output_274 (operands, insn)
rtx *operands;
rtx insn;
{
@@ -2889,7 +3154,7 @@ output_253 (operands, insn)
}
static char *
-output_255 (operands, insn)
+output_276 (operands, insn)
rtx *operands;
rtx insn;
{
@@ -2903,7 +3168,7 @@ output_255 (operands, insn)
}
static char *
-output_257 (operands, insn)
+output_278 (operands, insn)
rtx *operands;
rtx insn;
{
@@ -2917,7 +3182,7 @@ output_257 (operands, insn)
}
static char *
-output_259 (operands, insn)
+output_280 (operands, insn)
rtx *operands;
rtx insn;
{
@@ -2931,7 +3196,7 @@ output_259 (operands, insn)
}
static char *
-output_262 (operands, insn)
+output_283 (operands, insn)
rtx *operands;
rtx insn;
{
@@ -2944,7 +3209,7 @@ output_262 (operands, insn)
}
static char *
-output_264 (operands, insn)
+output_285 (operands, insn)
rtx *operands;
rtx insn;
{
@@ -2966,7 +3231,7 @@ output_264 (operands, insn)
}
static char *
-output_265 (operands, insn)
+output_286 (operands, insn)
rtx *operands;
rtx insn;
{
@@ -2979,7 +3244,7 @@ output_265 (operands, insn)
}
static char *
-output_267 (operands, insn)
+output_288 (operands, insn)
rtx *operands;
rtx insn;
{
@@ -2997,7 +3262,7 @@ output_267 (operands, insn)
}
static char *
-output_270 (operands, insn)
+output_291 (operands, insn)
rtx *operands;
rtx insn;
{
@@ -3015,7 +3280,7 @@ output_270 (operands, insn)
}
static char *
-output_273 (operands, insn)
+output_294 (operands, insn)
rtx *operands;
rtx insn;
{
@@ -3035,7 +3300,7 @@ output_273 (operands, insn)
}
static char *
-output_276 (operands, insn)
+output_297 (operands, insn)
rtx *operands;
rtx insn;
{
@@ -3055,60 +3320,7 @@ output_276 (operands, insn)
}
static char *
-output_279 (operands, insn)
- rtx *operands;
- rtx insn;
-{
-
-{
- rtx addr = operands[1];
-
- if (GET_CODE (operands[0]) == MEM
- && ! CONSTANT_ADDRESS_P (XEXP (operands[0], 0)))
- {
- operands[0] = XEXP (operands[0], 0);
- output_asm_insn (AS1 (call,%*%0), operands);
- }
- else
- output_asm_insn (AS1 (call,%P0), operands);
-
- operands[2] = gen_rtx (REG, SImode, 0);
- output_asm_insn (AS2 (mov%L2,%2,%1), operands);
-
- operands[2] = gen_rtx (REG, SImode, 1);
- operands[1] = adj_offsettable_operand (addr, 4);
- output_asm_insn (AS2 (mov%L2,%2,%1), operands);
-
- operands[1] = adj_offsettable_operand (addr, 8);
- return AS1 (fnsave,%1);
-}
-}
-
-static char *
-output_280 (operands, insn)
- rtx *operands;
- rtx insn;
-{
-
-{
- rtx addr = operands[1];
-
- output_asm_insn (AS1 (call,%P0), operands);
-
- operands[2] = gen_rtx (REG, SImode, 0);
- output_asm_insn (AS2 (mov%L2,%2,%1), operands);
-
- operands[2] = gen_rtx (REG, SImode, 1);
- operands[1] = adj_offsettable_operand (addr, 4);
- output_asm_insn (AS2 (mov%L2,%2,%1), operands);
-
- operands[1] = adj_offsettable_operand (addr, 8);
- return AS1 (fnsave,%1);
-}
-}
-
-static char *
-output_283 (operands, insn)
+output_301 (operands, insn)
rtx *operands;
rtx insn;
{
@@ -3120,7 +3332,7 @@ output_283 (operands, insn)
}
static char *
-output_286 (operands, insn)
+output_304 (operands, insn)
rtx *operands;
rtx insn;
{
@@ -3155,7 +3367,7 @@ output_286 (operands, insn)
}
static char *
-output_288 (operands, insn)
+output_306 (operands, insn)
rtx *operands;
rtx insn;
{
@@ -3187,7 +3399,7 @@ output_288 (operands, insn)
}
static char *
-output_289 (operands, insn)
+output_307 (operands, insn)
rtx *operands;
rtx insn;
{
@@ -3207,7 +3419,7 @@ output_289 (operands, insn)
}
static char *
-output_291 (operands, insn)
+output_309 (operands, insn)
rtx *operands;
rtx insn;
{
@@ -3246,7 +3458,7 @@ output_291 (operands, insn)
}
static char *
-output_293 (operands, insn)
+output_311 (operands, insn)
rtx *operands;
rtx insn;
{
@@ -3284,111 +3496,111 @@ output_293 (operands, insn)
}
static char *
-output_294 (operands, insn)
+output_312 (operands, insn)
rtx *operands;
rtx insn;
{
- return (char *) output_387_binary_op (insn, operands);
+ return output_387_binary_op (insn, operands);
}
static char *
-output_295 (operands, insn)
+output_313 (operands, insn)
rtx *operands;
rtx insn;
{
- return (char *) output_387_binary_op (insn, operands);
+ return output_387_binary_op (insn, operands);
}
static char *
-output_296 (operands, insn)
+output_314 (operands, insn)
rtx *operands;
rtx insn;
{
- return (char *) output_387_binary_op (insn, operands);
+ return output_387_binary_op (insn, operands);
}
static char *
-output_297 (operands, insn)
+output_315 (operands, insn)
rtx *operands;
rtx insn;
{
- return (char *) output_387_binary_op (insn, operands);
+ return output_387_binary_op (insn, operands);
}
static char *
-output_298 (operands, insn)
+output_316 (operands, insn)
rtx *operands;
rtx insn;
{
- return (char *) output_387_binary_op (insn, operands);
+ return output_387_binary_op (insn, operands);
}
static char *
-output_299 (operands, insn)
+output_317 (operands, insn)
rtx *operands;
rtx insn;
{
- return (char *) output_387_binary_op (insn, operands);
+ return output_387_binary_op (insn, operands);
}
static char *
-output_300 (operands, insn)
+output_318 (operands, insn)
rtx *operands;
rtx insn;
{
- return (char *) output_387_binary_op (insn, operands);
+ return output_387_binary_op (insn, operands);
}
static char *
-output_301 (operands, insn)
+output_319 (operands, insn)
rtx *operands;
rtx insn;
{
- return (char *) output_387_binary_op (insn, operands);
+ return output_387_binary_op (insn, operands);
}
static char *
-output_302 (operands, insn)
+output_320 (operands, insn)
rtx *operands;
rtx insn;
{
- return (char *) output_387_binary_op (insn, operands);
+ return output_387_binary_op (insn, operands);
}
static char *
-output_303 (operands, insn)
+output_321 (operands, insn)
rtx *operands;
rtx insn;
{
- return (char *) output_387_binary_op (insn, operands);
+ return output_387_binary_op (insn, operands);
}
static char *
-output_304 (operands, insn)
+output_322 (operands, insn)
rtx *operands;
rtx insn;
{
- return (char *) output_387_binary_op (insn, operands);
+ return output_387_binary_op (insn, operands);
}
static char *
-output_305 (operands, insn)
+output_323 (operands, insn)
rtx *operands;
rtx insn;
{
- return (char *) output_387_binary_op (insn, operands);
+ return output_387_binary_op (insn, operands);
}
static char *
-output_306 (operands, insn)
+output_324 (operands, insn)
rtx *operands;
rtx insn;
{
- return (char *) output_387_binary_op (insn, operands);
+ return output_387_binary_op (insn, operands);
}
static char *
-output_308 (operands, insn)
+output_326 (operands, insn)
rtx *operands;
rtx insn;
{
@@ -3454,9 +3666,28 @@ char * const insn_template[] =
0,
"push%L0 %1",
"push%L0 %1",
+ "push%L0 %1",
0,
0,
"push%W0 %1",
+ "push%W0 %1",
+ "push%W0 %1",
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
0,
0,
0,
@@ -3537,6 +3768,8 @@ char * const insn_template[] =
"imul%B0 %2",
"mul%L0 %2",
"imul%L0 %2",
+ "mul%L0 %2",
+ "imul%L0 %2",
0,
0,
0,
@@ -3685,10 +3918,7 @@ char * const insn_template[] =
0,
"call %P1",
0,
- 0,
- 0,
- 0,
- "frstor %0",
+ "",
0,
"nop",
0,
@@ -3768,29 +3998,29 @@ char *(*const insn_outfun[])() =
0,
0,
0,
- output_49,
0,
- output_51,
- output_52,
- output_53,
- output_54,
+ output_50,
+ 0,
+ 0,
+ 0,
+ 0,
output_55,
- output_56,
+ 0,
output_57,
output_58,
output_59,
output_60,
- output_61,
+ 0,
output_62,
- output_63,
+ 0,
output_64,
- output_65,
+ 0,
output_66,
output_67,
output_68,
output_69,
output_70,
- output_71,
+ 0,
output_72,
output_73,
output_74,
@@ -3800,55 +4030,72 @@ char *(*const insn_outfun[])() =
output_78,
output_79,
output_80,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
+ output_81,
+ output_82,
+ output_83,
+ output_84,
+ output_85,
+ output_86,
output_87,
output_88,
output_89,
- 0,
- 0,
- 0,
+ output_90,
+ output_91,
+ output_92,
output_93,
output_94,
output_95,
0,
+ output_97,
+ output_98,
+ output_99,
+ 0,
0,
0,
0,
0,
0,
- output_102,
- output_103,
- output_104,
- output_105,
output_106,
output_107,
output_108,
- output_109,
- output_110,
- output_111,
+ 0,
+ 0,
+ 0,
output_112,
+ output_113,
+ output_114,
0,
0,
0,
- output_116,
- output_117,
- output_118,
- output_119,
0,
0,
0,
+ output_121,
+ output_122,
output_123,
output_124,
output_125,
output_126,
+ output_127,
+ output_128,
+ output_129,
+ output_130,
+ output_131,
0,
0,
0,
+ output_135,
+ output_136,
+ output_137,
+ output_138,
+ 0,
+ 0,
+ 0,
+ output_142,
+ output_143,
+ output_144,
+ output_145,
+ 0,
0,
0,
0,
@@ -3858,23 +4105,25 @@ char *(*const insn_outfun[])() =
0,
0,
0,
- output_139,
0,
- output_141,
- output_142,
- output_143,
- output_144,
- output_145,
- output_146,
- output_147,
- output_148,
- output_149,
- output_150,
- output_151,
- output_152,
0,
0,
0,
+ output_160,
+ 0,
+ output_162,
+ output_163,
+ output_164,
+ output_165,
+ output_166,
+ output_167,
+ output_168,
+ output_169,
+ output_170,
+ output_171,
+ output_172,
+ output_173,
+ 0,
0,
0,
0,
@@ -3901,133 +4150,132 @@ char *(*const insn_outfun[])() =
0,
0,
0,
- output_182,
- output_183,
- output_184,
- output_185,
- output_186,
0,
- output_188,
- output_189,
- output_190,
- output_191,
- output_192,
0,
- output_194,
- output_195,
- output_196,
- output_197,
- output_198,
- output_199,
- output_200,
- output_201,
- output_202,
output_203,
output_204,
output_205,
output_206,
output_207,
- output_208,
+ 0,
output_209,
output_210,
- 0,
+ output_211,
output_212,
+ output_213,
0,
- output_214,
- 0,
+ output_215,
output_216,
- 0,
+ output_217,
output_218,
- 0,
+ output_219,
output_220,
- 0,
+ output_221,
output_222,
- 0,
+ output_223,
output_224,
- 0,
+ output_225,
output_226,
- 0,
+ output_227,
output_228,
- 0,
+ output_229,
output_230,
+ output_231,
0,
- output_232,
- 0,
- output_234,
- 0,
- output_236,
- 0,
+ output_233,
0,
+ output_235,
0,
- output_240,
+ output_237,
0,
+ output_239,
0,
+ output_241,
0,
- output_244,
+ output_243,
0,
+ output_245,
0,
+ output_247,
0,
- output_248,
- 0,
+ output_249,
0,
output_251,
- output_252,
+ 0,
output_253,
0,
output_255,
0,
output_257,
0,
- output_259,
0,
0,
- output_262,
+ output_261,
+ 0,
+ 0,
0,
- output_264,
output_265,
0,
- output_267,
0,
0,
- output_270,
+ output_269,
0,
0,
+ output_272,
output_273,
- 0,
+ output_274,
0,
output_276,
0,
+ output_278,
0,
- output_279,
output_280,
0,
0,
output_283,
0,
- 0,
+ output_285,
output_286,
0,
output_288,
- output_289,
+ 0,
0,
output_291,
0,
- output_293,
+ 0,
output_294,
- output_295,
- output_296,
+ 0,
+ 0,
output_297,
- output_298,
- output_299,
- output_300,
+ 0,
+ 0,
+ 0,
output_301,
- output_302,
- output_303,
+ 0,
+ 0,
output_304,
- output_305,
- output_306,
0,
- output_308,
+ output_306,
+ output_307,
+ 0,
+ output_309,
+ 0,
+ output_311,
+ output_312,
+ output_313,
+ output_314,
+ output_315,
+ output_316,
+ output_317,
+ output_318,
+ output_319,
+ output_320,
+ output_321,
+ output_322,
+ output_323,
+ output_324,
+ 0,
+ output_326,
};
rtx (*const insn_gen_function[]) () =
@@ -4080,22 +4328,41 @@ rtx (*const insn_gen_function[]) () =
0,
0,
0,
+ 0,
gen_movsi,
0,
0,
+ 0,
+ 0,
gen_movhi,
+ 0,
gen_movstricthi,
0,
+ 0,
+ 0,
+ 0,
gen_movqi,
+ 0,
gen_movstrictqi,
0,
gen_movsf,
- 0,
- gen_swapdf,
+ gen_movsf_push_nomove,
+ gen_movsf_push,
+ gen_movsf_mem,
+ gen_movsf_normal,
+ gen_swapsf,
gen_movdf,
- 0,
- gen_swapxf,
+ gen_movdf_push_nomove,
+ gen_movdf_push,
+ gen_movdf_mem,
+ gen_movdf_normal,
+ gen_swapdf,
gen_movxf,
+ gen_movxf_push_nomove,
+ gen_movxf_push,
+ gen_movxf_mem,
+ gen_movxf_normal,
+ gen_swapxf,
0,
gen_movdi,
gen_zero_extendhisi2,
@@ -4144,7 +4411,7 @@ rtx (*const insn_gen_function[]) () =
gen_addsi3,
gen_addhi3,
gen_addqi3,
- 0,
+ gen_movsi_lea,
gen_addxf3,
gen_adddf3,
gen_addsf3,
@@ -4163,6 +4430,8 @@ rtx (*const insn_gen_function[]) () =
gen_mulqihi3,
gen_umulsidi3,
gen_mulsidi3,
+ gen_umulsi3_highpart,
+ gen_smulsi3_highpart,
gen_mulxf3,
gen_muldf3,
gen_mulsf3,
@@ -4311,10 +4580,7 @@ rtx (*const insn_gen_function[]) () =
0,
0,
gen_untyped_call,
- 0,
- 0,
- gen_untyped_return,
- gen_update_return,
+ gen_blockage,
gen_return,
gen_nop,
gen_movstrsi,
@@ -4391,25 +4657,44 @@ char *insn_name[] =
"cmpsf_ccfpeq+1",
"cmpsf_ccfpeq+2",
"cmpsf_ccfpeq+3",
+ "movsi-3",
"movsi-2",
"movsi-1",
"movsi",
"movsi+1",
+ "movsi+2",
+ "movhi-2",
"movhi-1",
"movhi",
+ "movhi+1",
"movstricthi",
"movstricthi+1",
+ "movstricthi+2",
+ "movqi-2",
+ "movqi-1",
"movqi",
+ "movqi+1",
"movstrictqi",
"movstrictqi+1",
"movsf",
- "movsf+1",
- "swapdf",
+ "movsf_push_nomove",
+ "movsf_push",
+ "movsf_mem",
+ "movsf_normal",
+ "swapsf",
"movdf",
- "movdf+1",
- "swapxf",
+ "movdf_push_nomove",
+ "movdf_push",
+ "movdf_mem",
+ "movdf_normal",
+ "swapdf",
"movxf",
- "movxf+1",
+ "movxf_push_nomove",
+ "movxf_push",
+ "movxf_mem",
+ "movxf_normal",
+ "swapxf",
+ "swapxf+1",
"movdi",
"zero_extendhisi2",
"zero_extendqihi2",
@@ -4457,7 +4742,7 @@ char *insn_name[] =
"addsi3",
"addhi3",
"addqi3",
- "addqi3+1",
+ "movsi_lea",
"addxf3",
"adddf3",
"addsf3",
@@ -4476,6 +4761,8 @@ char *insn_name[] =
"mulqihi3",
"umulsidi3",
"mulsidi3",
+ "umulsi3_highpart",
+ "smulsi3_highpart",
"mulxf3",
"muldf3",
"mulsf3",
@@ -4624,10 +4911,7 @@ char *insn_name[] =
"call_value+1",
"untyped_call-1",
"untyped_call",
- "untyped_call+1",
- "untyped_return-1",
- "untyped_return",
- "update_return",
+ "blockage",
"return",
"nop",
"movstrsi",
@@ -4726,6 +5010,25 @@ const int insn_n_operands[] =
2,
2,
2,
+ 3,
+ 3,
+ 2,
+ 2,
+ 2,
+ 2,
+ 4,
+ 4,
+ 2,
+ 2,
+ 2,
+ 2,
+ 4,
+ 4,
+ 2,
+ 2,
+ 4,
+ 4,
+ 2,
2,
2,
2,
@@ -4767,7 +5070,7 @@ const int insn_n_operands[] =
2,
2,
2,
- 3,
+ 4,
3,
3,
3,
@@ -4775,6 +5078,7 @@ const int insn_n_operands[] =
3,
3,
3,
+ 4,
3,
3,
3,
@@ -4789,7 +5093,8 @@ const int insn_n_operands[] =
3,
3,
3,
- 3,
+ 4,
+ 4,
3,
3,
3,
@@ -4938,10 +5243,7 @@ const int insn_n_operands[] =
3,
3,
3,
- 3,
- 3,
- 2,
- 1,
+ 0,
0,
0,
5,
@@ -5031,15 +5333,34 @@ const int insn_n_dups[] =
0,
0,
0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
2,
0,
0,
+ 0,
+ 0,
+ 0,
2,
0,
0,
0,
0,
0,
+ 2,
+ 0,
+ 0,
+ 0,
+ 0,
0,
0,
0,
@@ -5111,6 +5432,8 @@ const int insn_n_dups[] =
0,
0,
0,
+ 0,
+ 0,
2,
2,
2,
@@ -5254,9 +5577,6 @@ const int insn_n_dups[] =
0,
0,
0,
- 0,
- 0,
- 0,
2,
2,
3,
@@ -5333,24 +5653,43 @@ char *const insn_operand_constraint[][MAX_RECOG_OPERANDS] =
{ "%qm", "qi", },
{ "=<", "g", },
{ "=<", "ri", },
+ { "=<", "ri", },
{ "", "", },
{ "=g,r", "ri,m", },
{ "=<", "g", },
+ { "=<", "ri", },
+ { "=<", "ri", },
+ { "", "", },
{ "=g,r", "ri,m", },
+ { "", "", },
{ "+g,r", "ri,m", },
+ { "=<", "n", },
{ "=<", "q", },
+ { "=<", "q", },
+ { "", "", },
{ "=q,*r,qm", "*g,q,qn", },
+ { "", "", },
{ "+qm,q", "*qn,m", },
+ { "", "", },
{ "=<,<", "gF,f", },
+ { "=<,<,<,<", "rF,f,m,m", "=X,X,r,X", },
+ { "=m", "m", "=&r", },
{ "=*rfm,*rf,f,!*rm", "*rf,*rfm,fG,fF", },
- { "=<,<", "gF,f", },
{ "f", "f", },
- { "=*rfm,*rf,f,!*rm", "*rf,*rfm,fG,fF", },
+ { "", "", },
{ "=<,<", "gF,f", },
+ { "=<,<,<,<,<", "rF,f,o,o,o", "=X,X,&r,&r,X", "=X,X,&r,X,X", },
+ { "=o,o", "o,o", "=&r,&r", "=&r,X", },
+ { "=f,fm,!*rf,!*rm", "fmG,f,*rfm,*rfF", },
{ "f", "f", },
+ { "", "", },
+ { "=<,<", "gF,f", },
+ { "=<,<,<,<,<", "rF,f,o,o,o", "=X,X,&r,&r,X", "=X,X,&r,X,X", },
+ { "=o,o", "o,o", "=&r,&r", "=&r,X", },
{ "=f,fm,!*rf,!*rm", "fmG,f,*rfm,*rfF", },
- { "=<", "roiF", },
- { "=r,rm", "m,riF", },
+ { "f", "f", },
+ { "=<,<,<,<", "riF,o,o,o", "=X,&r,&r,X", "=X,&r,X,X", },
+ { "=o,o,r,rm", "o,o,m,riF", "=&r,&r,X,X", "=&r,X,X,X", },
{ "=r", "rm", },
{ "=r", "qm", },
{ "=r", "qm", },
@@ -5393,7 +5732,7 @@ char *const insn_operand_constraint[][MAX_RECOG_OPERANDS] =
{ "=f", "rm", },
{ "=f,f", "m,!*r", },
{ "=f", "rm", },
- { "=&r,ro", "%0,0", "o,riF", },
+ { "=&r,ro,o,&r,ro,o,&r,o,o,o", "%0,0,0,o,riF,o,or,riF,riF,o", "o,riF,o,0,0,0,oriF,riF,o,o", "=X,X,&r,X,X,&r,X,X,&r,&r", },
{ "=?r,rm,r", "%r,0,0", "ri,ri,rm", },
{ "=rm,r", "%0,0", "ri,rm", },
{ "=qm,q", "%0,0", "qn,qmn", },
@@ -5401,7 +5740,7 @@ char *const insn_operand_constraint[][MAX_RECOG_OPERANDS] =
{ "", "", "", },
{ "", "", "", },
{ "", "", "", },
- { "=&r,ro", "0,0", "o,riF", },
+ { "=&r,ro,&r,o,o", "0,0,roiF,riF,o", "o,riF,roiF,riF,o", "=X,X,X,X,&r", },
{ "=rm,r", "0,0", "ri,rm", },
{ "=rm,r", "0,0", "ri,rm", },
{ "=qm,q", "0,0", "qn,qmn", },
@@ -5416,6 +5755,8 @@ char *const insn_operand_constraint[][MAX_RECOG_OPERANDS] =
{ "=a", "%0", "qm", },
{ "=A", "%0", "rm", },
{ "=A", "%0", "rm", },
+ { "=d", "%a", "rm", "=a", },
+ { "=d", "%a", "rm", "=a", },
{ "", "", "", },
{ "", "", "", },
{ "", "", "", },
@@ -5564,10 +5905,7 @@ char *const insn_operand_constraint[][MAX_RECOG_OPERANDS] =
{ "=rf", "m", "g", },
{ "=rf", "", "g", },
{ "", "", "", },
- { "m", "o", "", },
- { "", "o", "", },
- { "", "", },
- { "m", },
+ { 0 },
{ 0 },
{ 0 },
{ "", "", "", "", "", },
@@ -5648,22 +5986,41 @@ const enum machine_mode insn_operand_mode[][MAX_RECOG_OPERANDS] =
{ SImode, SImode, },
{ SImode, SImode, },
{ SImode, SImode, },
+ { SImode, SImode, },
+ { HImode, HImode, },
{ HImode, HImode, },
{ HImode, HImode, },
{ HImode, HImode, },
+ { HImode, HImode, },
+ { HImode, HImode, },
+ { HImode, HImode, },
+ { QImode, QImode, },
+ { QImode, QImode, },
{ QImode, QImode, },
{ QImode, QImode, },
{ QImode, QImode, },
+ { QImode, QImode, },
+ { QImode, QImode, },
+ { SFmode, SFmode, },
{ SFmode, SFmode, },
+ { SFmode, SFmode, SImode, },
+ { SFmode, SFmode, SImode, },
{ SFmode, SFmode, },
+ { SFmode, SFmode, },
+ { DFmode, DFmode, },
{ DFmode, DFmode, },
+ { DFmode, DFmode, SImode, SImode, },
+ { DFmode, DFmode, SImode, SImode, },
{ DFmode, DFmode, },
{ DFmode, DFmode, },
{ XFmode, XFmode, },
{ XFmode, XFmode, },
+ { XFmode, XFmode, SImode, SImode, },
+ { XFmode, XFmode, SImode, SImode, },
{ XFmode, XFmode, },
- { DImode, DImode, },
- { DImode, DImode, },
+ { XFmode, XFmode, },
+ { DImode, DImode, SImode, SImode, },
+ { DImode, DImode, SImode, SImode, },
{ SImode, HImode, },
{ HImode, QImode, },
{ SImode, QImode, },
@@ -5706,7 +6063,7 @@ const enum machine_mode insn_operand_mode[][MAX_RECOG_OPERANDS] =
{ DFmode, SImode, },
{ XFmode, SImode, },
{ SFmode, SImode, },
- { DImode, DImode, DImode, },
+ { DImode, DImode, DImode, SImode, },
{ SImode, SImode, SImode, },
{ HImode, HImode, HImode, },
{ QImode, QImode, QImode, },
@@ -5714,7 +6071,7 @@ const enum machine_mode insn_operand_mode[][MAX_RECOG_OPERANDS] =
{ XFmode, XFmode, XFmode, },
{ DFmode, DFmode, DFmode, },
{ SFmode, SFmode, SFmode, },
- { DImode, DImode, DImode, },
+ { DImode, DImode, DImode, SImode, },
{ SImode, SImode, SImode, },
{ HImode, HImode, HImode, },
{ QImode, QImode, QImode, },
@@ -5729,6 +6086,8 @@ const enum machine_mode insn_operand_mode[][MAX_RECOG_OPERANDS] =
{ HImode, QImode, QImode, },
{ DImode, SImode, SImode, },
{ DImode, SImode, SImode, },
+ { SImode, SImode, SImode, SImode, },
+ { SImode, SImode, SImode, SImode, },
{ XFmode, XFmode, XFmode, },
{ DFmode, DFmode, DFmode, },
{ SFmode, SFmode, SFmode, },
@@ -5876,11 +6235,8 @@ const enum machine_mode insn_operand_mode[][MAX_RECOG_OPERANDS] =
{ VOIDmode, QImode, SImode, },
{ VOIDmode, QImode, SImode, },
{ VOIDmode, SImode, SImode, },
- { QImode, BLKmode, VOIDmode, },
- { QImode, DImode, VOIDmode, },
- { SImode, DImode, VOIDmode, },
- { BLKmode, VOIDmode, },
- { SImode, },
+ { VOIDmode, VOIDmode, VOIDmode, },
+ { VOIDmode },
{ VOIDmode },
{ VOIDmode },
{ BLKmode, BLKmode, SImode, SImode, SImode, },
@@ -5963,20 +6319,39 @@ const char insn_operand_strict_low[][MAX_RECOG_OPERANDS] =
{ 0, 0, },
{ 0, 0, },
{ 0, 0, },
+ { 0, 0, },
+ { 0, 0, },
+ { 0, 0, },
+ { 0, 0, },
{ 1, 0, },
+ { 1, 0, },
+ { 0, 0, },
+ { 0, 0, },
{ 0, 0, },
{ 0, 0, },
+ { 0, 0, },
+ { 1, 0, },
{ 1, 0, },
{ 0, 0, },
{ 0, 0, },
+ { 0, 0, 0, },
+ { 0, 0, 0, },
+ { 0, 0, },
{ 0, 0, },
{ 0, 0, },
{ 0, 0, },
+ { 0, 0, 0, 0, },
+ { 0, 0, 0, 0, },
+ { 0, 0, },
{ 0, 0, },
{ 0, 0, },
{ 0, 0, },
+ { 0, 0, 0, 0, },
+ { 0, 0, 0, 0, },
{ 0, 0, },
{ 0, 0, },
+ { 0, 0, 0, 0, },
+ { 0, 0, 0, 0, },
{ 0, 0, },
{ 0, 0, },
{ 0, 0, },
@@ -6019,7 +6394,7 @@ const char insn_operand_strict_low[][MAX_RECOG_OPERANDS] =
{ 0, 0, },
{ 0, 0, },
{ 0, 0, },
- { 0, 0, 0, },
+ { 0, 0, 0, 0, },
{ 0, 0, 0, },
{ 0, 0, 0, },
{ 0, 0, 0, },
@@ -6027,6 +6402,7 @@ const char insn_operand_strict_low[][MAX_RECOG_OPERANDS] =
{ 0, 0, 0, },
{ 0, 0, 0, },
{ 0, 0, 0, },
+ { 0, 0, 0, 0, },
{ 0, 0, 0, },
{ 0, 0, 0, },
{ 0, 0, 0, },
@@ -6041,7 +6417,8 @@ const char insn_operand_strict_low[][MAX_RECOG_OPERANDS] =
{ 0, 0, 0, },
{ 0, 0, 0, },
{ 0, 0, 0, },
- { 0, 0, 0, },
+ { 0, 0, 0, 0, },
+ { 0, 0, 0, 0, },
{ 0, 0, 0, },
{ 0, 0, 0, },
{ 0, 0, 0, },
@@ -6190,10 +6567,7 @@ const char insn_operand_strict_low[][MAX_RECOG_OPERANDS] =
{ 0, 0, 0, },
{ 0, 0, 0, },
{ 0, 0, 0, },
- { 0, 0, 0, },
- { 0, 0, 0, },
- { 0, 0, },
- { 0, },
+ { 0 },
{ 0 },
{ 0 },
{ 0, 0, 0, 0, 0, },
@@ -6228,12 +6602,12 @@ extern int scratch_operand ();
extern int general_operand ();
extern int VOIDmode_compare_op ();
extern int push_operand ();
+extern int nonmemory_operand ();
+extern int immediate_operand ();
extern int memory_operand ();
extern int address_operand ();
-extern int nonmemory_operand ();
extern int const_int_operand ();
extern int indirect_operand ();
-extern int immediate_operand ();
extern int call_insn_operand ();
extern int symbolic_operand ();
extern int binary_387_op ();
@@ -6287,25 +6661,44 @@ int (*const insn_operand_predicate[][MAX_RECOG_OPERANDS])() =
{ general_operand, general_operand, },
{ general_operand, general_operand, },
{ push_operand, general_operand, },
+ { push_operand, nonmemory_operand, },
{ push_operand, general_operand, },
{ general_operand, general_operand, },
{ general_operand, general_operand, },
{ push_operand, general_operand, },
+ { push_operand, nonmemory_operand, },
+ { push_operand, general_operand, },
+ { general_operand, general_operand, },
+ { general_operand, general_operand, },
+ { general_operand, general_operand, },
+ { general_operand, general_operand, },
+ { push_operand, immediate_operand, },
+ { push_operand, nonimmediate_operand, },
+ { push_operand, register_operand, },
{ general_operand, general_operand, },
{ general_operand, general_operand, },
- { push_operand, general_operand, },
{ general_operand, general_operand, },
{ general_operand, general_operand, },
- { push_operand, general_operand, },
{ general_operand, general_operand, },
{ push_operand, general_operand, },
+ { push_operand, general_operand, scratch_operand, },
+ { memory_operand, memory_operand, scratch_operand, },
+ { general_operand, general_operand, },
{ register_operand, register_operand, },
{ general_operand, general_operand, },
{ push_operand, general_operand, },
+ { push_operand, general_operand, scratch_operand, scratch_operand, },
+ { memory_operand, memory_operand, scratch_operand, scratch_operand, },
+ { general_operand, general_operand, },
{ register_operand, register_operand, },
{ general_operand, general_operand, },
{ push_operand, general_operand, },
+ { push_operand, general_operand, scratch_operand, scratch_operand, },
+ { memory_operand, memory_operand, scratch_operand, scratch_operand, },
{ general_operand, general_operand, },
+ { register_operand, register_operand, },
+ { push_operand, general_operand, scratch_operand, scratch_operand, },
+ { general_operand, general_operand, scratch_operand, scratch_operand, },
{ general_operand, nonimmediate_operand, },
{ general_operand, nonimmediate_operand, },
{ general_operand, nonimmediate_operand, },
@@ -6348,7 +6741,7 @@ int (*const insn_operand_predicate[][MAX_RECOG_OPERANDS])() =
{ register_operand, nonimmediate_operand, },
{ register_operand, general_operand, },
{ register_operand, nonimmediate_operand, },
- { general_operand, general_operand, general_operand, },
+ { general_operand, general_operand, general_operand, scratch_operand, },
{ general_operand, general_operand, general_operand, },
{ general_operand, general_operand, general_operand, },
{ general_operand, general_operand, general_operand, },
@@ -6356,7 +6749,7 @@ int (*const insn_operand_predicate[][MAX_RECOG_OPERANDS])() =
{ register_operand, nonimmediate_operand, nonimmediate_operand, },
{ register_operand, nonimmediate_operand, nonimmediate_operand, },
{ register_operand, nonimmediate_operand, nonimmediate_operand, },
- { general_operand, general_operand, general_operand, },
+ { general_operand, general_operand, general_operand, scratch_operand, },
{ general_operand, general_operand, general_operand, },
{ general_operand, general_operand, general_operand, },
{ general_operand, general_operand, general_operand, },
@@ -6371,6 +6764,8 @@ int (*const insn_operand_predicate[][MAX_RECOG_OPERANDS])() =
{ general_operand, nonimmediate_operand, nonimmediate_operand, },
{ register_operand, register_operand, nonimmediate_operand, },
{ register_operand, register_operand, nonimmediate_operand, },
+ { register_operand, register_operand, nonimmediate_operand, scratch_operand, },
+ { register_operand, register_operand, nonimmediate_operand, scratch_operand, },
{ register_operand, nonimmediate_operand, nonimmediate_operand, },
{ register_operand, nonimmediate_operand, nonimmediate_operand, },
{ register_operand, nonimmediate_operand, nonimmediate_operand, },
@@ -6518,11 +6913,8 @@ int (*const insn_operand_predicate[][MAX_RECOG_OPERANDS])() =
{ 0, indirect_operand, general_operand, },
{ 0, call_insn_operand, general_operand, },
{ 0, symbolic_operand, general_operand, },
- { indirect_operand, memory_operand, 0, },
- { call_insn_operand, memory_operand, 0, },
- { symbolic_operand, memory_operand, 0, },
- { memory_operand, 0, },
- { memory_operand, },
+ { 0, 0, 0, },
+ { 0 },
{ 0 },
{ 0 },
{ memory_operand, memory_operand, const_int_operand, const_int_operand, scratch_operand, },
@@ -6601,24 +6993,43 @@ const int insn_n_alternatives[] =
1,
1,
1,
+ 1,
0,
2,
1,
+ 1,
+ 1,
+ 0,
2,
+ 0,
2,
1,
+ 1,
+ 1,
+ 0,
3,
+ 0,
2,
+ 0,
2,
4,
- 2,
1,
4,
- 2,
1,
+ 0,
+ 2,
+ 5,
+ 2,
4,
1,
+ 0,
+ 2,
+ 5,
2,
+ 4,
+ 1,
+ 4,
+ 4,
1,
1,
1,
@@ -6661,7 +7072,7 @@ const int insn_n_alternatives[] =
1,
2,
1,
- 2,
+ 10,
3,
2,
2,
@@ -6669,7 +7080,7 @@ const int insn_n_alternatives[] =
0,
0,
0,
- 2,
+ 5,
2,
2,
2,
@@ -6684,6 +7095,8 @@ const int insn_n_alternatives[] =
1,
1,
1,
+ 1,
+ 1,
0,
0,
0,
@@ -6832,10 +7245,7 @@ const int insn_n_alternatives[] =
1,
1,
0,
- 1,
- 1,
0,
- 1,
0,
0,
0,
diff --git a/gnu/usr.bin/cc/cc_int/insn-recog.c b/gnu/usr.bin/cc/cc_int/insn-recog.c
index 293dd7e..c1179c4 100644
--- a/gnu/usr.bin/cc/cc_int/insn-recog.c
+++ b/gnu/usr.bin/cc/cc_int/insn-recog.c
@@ -58,99 +58,100 @@ recog_1 (x0, insn, pnum_clobbers)
switch (GET_CODE (x1))
{
case ZERO_EXTEND:
- goto L370;
+ goto L474;
case SIGN_EXTEND:
- goto L390;
+ goto L494;
case PLUS:
- goto L603;
+ goto L715;
case MINUS:
- goto L626;
+ goto L746;
case MULT:
- goto L660;
+ goto L780;
case AND:
- goto L747;
+ goto L913;
case IOR:
- goto L762;
+ goto L928;
case XOR:
- goto L777;
+ goto L943;
case NEG:
- goto L795;
+ goto L961;
case NOT:
- goto L904;
+ goto L1070;
case ASHIFT:
- goto L930;
+ goto L1096;
case ASHIFTRT:
- goto L958;
+ goto L1124;
case LSHIFTRT:
- goto L986;
+ goto L1152;
case ROTATE:
- goto L1001;
+ goto L1167;
case ROTATERT:
- goto L1016;
+ goto L1182;
}
}
if (general_operand (x1, HImode))
{
ro[1] = x1;
- return 51;
- }
+ if ((!TARGET_MOVE || GET_CODE (operands[0]) != MEM) || (GET_CODE (operands[1]) != MEM))
+ return 55;
+ }
goto ret0;
- L370:
+ L474:
x2 = XEXP (x1, 0);
if (nonimmediate_operand (x2, QImode))
{
ro[1] = x2;
- return 67;
+ return 86;
}
goto ret0;
- L390:
+ L494:
x2 = XEXP (x1, 0);
if (nonimmediate_operand (x2, QImode))
{
ro[1] = x2;
- return 72;
+ return 91;
}
goto ret0;
- L603:
+ L715:
x2 = XEXP (x1, 0);
if (general_operand (x2, HImode))
{
ro[1] = x2;
- goto L604;
+ goto L716;
}
goto ret0;
- L604:
+ L716:
x2 = XEXP (x1, 1);
if (general_operand (x2, HImode))
{
ro[2] = x2;
- return 110;
+ return 129;
}
goto ret0;
- L626:
+ L746:
x2 = XEXP (x1, 0);
if (general_operand (x2, HImode))
{
ro[1] = x2;
- goto L627;
+ goto L747;
}
goto ret0;
- L627:
+ L747:
x2 = XEXP (x1, 1);
if (general_operand (x2, HImode))
{
ro[2] = x2;
- return 118;
+ return 137;
}
goto ret0;
- L660:
+ L780:
x2 = XEXP (x1, 0);
switch (GET_MODE (x2))
{
@@ -158,239 +159,239 @@ recog_1 (x0, insn, pnum_clobbers)
switch (GET_CODE (x2))
{
case ZERO_EXTEND:
- goto L661;
+ goto L781;
case SIGN_EXTEND:
- goto L668;
+ goto L788;
}
}
if (general_operand (x2, HImode))
{
ro[1] = x2;
- goto L637;
+ goto L757;
}
goto ret0;
- L661:
+ L781:
x3 = XEXP (x2, 0);
if (nonimmediate_operand (x3, QImode))
{
ro[1] = x3;
- goto L662;
+ goto L782;
}
goto ret0;
- L662:
+ L782:
x2 = XEXP (x1, 1);
if (GET_MODE (x2) == HImode && GET_CODE (x2) == ZERO_EXTEND && 1)
- goto L663;
+ goto L783;
goto ret0;
- L663:
+ L783:
x3 = XEXP (x2, 0);
if (nonimmediate_operand (x3, QImode))
{
ro[2] = x3;
- return 127;
+ return 146;
}
goto ret0;
- L668:
+ L788:
x3 = XEXP (x2, 0);
if (nonimmediate_operand (x3, QImode))
{
ro[1] = x3;
- goto L669;
+ goto L789;
}
goto ret0;
- L669:
+ L789:
x2 = XEXP (x1, 1);
if (GET_MODE (x2) == HImode && GET_CODE (x2) == SIGN_EXTEND && 1)
- goto L670;
+ goto L790;
goto ret0;
- L670:
+ L790:
x3 = XEXP (x2, 0);
if (nonimmediate_operand (x3, QImode))
{
ro[2] = x3;
- return 128;
+ return 147;
}
goto ret0;
- L637:
+ L757:
x2 = XEXP (x1, 1);
if (general_operand (x2, HImode))
- goto L643;
+ goto L763;
goto ret0;
- L643:
+ L763:
ro[2] = x2;
if (GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) == 0x80)
- return 123;
- L644:
+ return 142;
+ L764:
ro[2] = x2;
- return 124;
+ return 143;
- L747:
+ L913:
x2 = XEXP (x1, 0);
if (general_operand (x2, HImode))
{
ro[1] = x2;
- goto L748;
+ goto L914;
}
goto ret0;
- L748:
+ L914:
x2 = XEXP (x1, 1);
if (general_operand (x2, HImode))
{
ro[2] = x2;
- return 144;
+ return 165;
}
goto ret0;
- L762:
+ L928:
x2 = XEXP (x1, 0);
if (general_operand (x2, HImode))
{
ro[1] = x2;
- goto L763;
+ goto L929;
}
goto ret0;
- L763:
+ L929:
x2 = XEXP (x1, 1);
if (general_operand (x2, HImode))
{
ro[2] = x2;
- return 147;
+ return 168;
}
goto ret0;
- L777:
+ L943:
x2 = XEXP (x1, 0);
if (general_operand (x2, HImode))
{
ro[1] = x2;
- goto L778;
+ goto L944;
}
goto ret0;
- L778:
+ L944:
x2 = XEXP (x1, 1);
if (general_operand (x2, HImode))
{
ro[2] = x2;
- return 150;
+ return 171;
}
goto ret0;
- L795:
+ L961:
x2 = XEXP (x1, 0);
if (general_operand (x2, HImode))
{
ro[1] = x2;
- return 154;
+ return 175;
}
goto ret0;
- L904:
+ L1070:
x2 = XEXP (x1, 0);
if (general_operand (x2, HImode))
{
ro[1] = x2;
- return 179;
+ return 200;
}
goto ret0;
- L930:
+ L1096:
x2 = XEXP (x1, 0);
if (general_operand (x2, HImode))
{
ro[1] = x2;
- goto L931;
+ goto L1097;
}
goto ret0;
- L931:
+ L1097:
x2 = XEXP (x1, 1);
if (nonmemory_operand (x2, HImode))
{
ro[2] = x2;
- return 185;
+ return 206;
}
goto ret0;
- L958:
+ L1124:
x2 = XEXP (x1, 0);
if (general_operand (x2, HImode))
{
ro[1] = x2;
- goto L959;
+ goto L1125;
}
goto ret0;
- L959:
+ L1125:
x2 = XEXP (x1, 1);
if (nonmemory_operand (x2, HImode))
{
ro[2] = x2;
- return 191;
+ return 212;
}
goto ret0;
- L986:
+ L1152:
x2 = XEXP (x1, 0);
if (general_operand (x2, HImode))
{
ro[1] = x2;
- goto L987;
+ goto L1153;
}
goto ret0;
- L987:
+ L1153:
x2 = XEXP (x1, 1);
if (nonmemory_operand (x2, HImode))
{
ro[2] = x2;
- return 197;
+ return 218;
}
goto ret0;
- L1001:
+ L1167:
x2 = XEXP (x1, 0);
if (general_operand (x2, HImode))
{
ro[1] = x2;
- goto L1002;
+ goto L1168;
}
goto ret0;
- L1002:
+ L1168:
x2 = XEXP (x1, 1);
if (nonmemory_operand (x2, HImode))
{
ro[2] = x2;
- return 200;
+ return 221;
}
goto ret0;
- L1016:
+ L1182:
x2 = XEXP (x1, 0);
if (general_operand (x2, HImode))
{
ro[1] = x2;
- goto L1017;
+ goto L1183;
}
goto ret0;
- L1017:
+ L1183:
x2 = XEXP (x1, 1);
if (nonmemory_operand (x2, HImode))
{
ro[2] = x2;
- return 203;
+ return 224;
}
goto ret0;
ret0: return -1;
@@ -468,7 +469,7 @@ recog_2 (x0, insn, pnum_clobbers)
case COMPARE:
goto L39;
case ZERO_EXTRACT:
- goto L1046;
+ goto L1212;
}
L61:
if (VOIDmode_compare_op (x1, VOIDmode))
@@ -563,7 +564,7 @@ recog_2 (x0, insn, pnum_clobbers)
}
goto L61;
- L1046:
+ L1212:
x2 = XEXP (x1, 0);
switch (GET_MODE (x2))
{
@@ -571,66 +572,66 @@ recog_2 (x0, insn, pnum_clobbers)
if (register_operand (x2, SImode))
{
ro[0] = x2;
- goto L1047;
+ goto L1213;
}
break;
case QImode:
if (general_operand (x2, QImode))
{
ro[0] = x2;
- goto L1059;
+ goto L1225;
}
}
goto L61;
- L1047:
+ L1213:
x2 = XEXP (x1, 1);
if (GET_CODE (x2) != CONST_INT)
{
goto L61;
}
if (XWINT (x2, 0) == 1 && 1)
- goto L1048;
- L1053:
+ goto L1214;
+ L1219:
ro[1] = x2;
- goto L1054;
+ goto L1220;
- L1048:
+ L1214:
x2 = XEXP (x1, 2);
if (general_operand (x2, SImode))
{
ro[1] = x2;
if (GET_CODE (operands[1]) != CONST_INT)
- return 208;
+ return 229;
}
x2 = XEXP (x1, 1);
- goto L1053;
+ goto L1219;
- L1054:
+ L1220:
x2 = XEXP (x1, 2);
if (GET_CODE (x2) == CONST_INT && 1)
{
ro[2] = x2;
- return 209;
+ return 230;
}
goto L61;
- L1059:
+ L1225:
x2 = XEXP (x1, 1);
if (GET_CODE (x2) == CONST_INT && 1)
{
ro[1] = x2;
- goto L1060;
+ goto L1226;
}
goto L61;
- L1060:
+ L1226:
x2 = XEXP (x1, 2);
if (GET_CODE (x2) == CONST_INT && 1)
{
ro[2] = x2;
if (GET_CODE (operands[0]) != MEM || ! MEM_VOLATILE_P (operands[0]))
- return 210;
+ return 231;
}
goto L61;
@@ -1079,477 +1080,477 @@ recog_3 (x0, insn, pnum_clobbers)
switch (GET_CODE (x2))
{
case EQ:
- goto L1115;
+ goto L1281;
case NE:
- goto L1124;
+ goto L1290;
case GT:
- goto L1133;
+ goto L1299;
case GTU:
- goto L1142;
+ goto L1308;
case LT:
- goto L1151;
+ goto L1317;
case LTU:
- goto L1160;
+ goto L1326;
case GE:
- goto L1169;
+ goto L1335;
case GEU:
- goto L1178;
+ goto L1344;
case LE:
- goto L1187;
+ goto L1353;
case LEU:
- goto L1196;
+ goto L1362;
}
goto ret0;
- L1115:
+ L1281:
x3 = XEXP (x2, 0);
if (GET_CODE (x3) == CC0 && 1)
- goto L1116;
+ goto L1282;
goto ret0;
- L1116:
+ L1282:
x3 = XEXP (x2, 1);
if (GET_CODE (x3) == CONST_INT && XWINT (x3, 0) == 0 && 1)
- goto L1117;
+ goto L1283;
goto ret0;
- L1117:
+ L1283:
x2 = XEXP (x1, 1);
switch (GET_CODE (x2))
{
case LABEL_REF:
- goto L1118;
+ goto L1284;
case PC:
- goto L1208;
+ goto L1374;
}
goto ret0;
- L1118:
+ L1284:
x3 = XEXP (x2, 0);
ro[0] = x3;
- goto L1119;
+ goto L1285;
- L1119:
+ L1285:
x2 = XEXP (x1, 2);
if (GET_CODE (x2) == PC && 1)
- return 232;
+ return 253;
goto ret0;
- L1208:
+ L1374:
x2 = XEXP (x1, 2);
if (GET_CODE (x2) == LABEL_REF && 1)
- goto L1209;
+ goto L1375;
goto ret0;
- L1209:
+ L1375:
x3 = XEXP (x2, 0);
ro[0] = x3;
- return 251;
+ return 272;
- L1124:
+ L1290:
x3 = XEXP (x2, 0);
if (GET_CODE (x3) == CC0 && 1)
- goto L1125;
+ goto L1291;
goto ret0;
- L1125:
+ L1291:
x3 = XEXP (x2, 1);
if (GET_CODE (x3) == CONST_INT && XWINT (x3, 0) == 0 && 1)
- goto L1126;
+ goto L1292;
goto ret0;
- L1126:
+ L1292:
x2 = XEXP (x1, 1);
switch (GET_CODE (x2))
{
case LABEL_REF:
- goto L1127;
+ goto L1293;
case PC:
- goto L1217;
+ goto L1383;
}
goto ret0;
- L1127:
+ L1293:
x3 = XEXP (x2, 0);
ro[0] = x3;
- goto L1128;
+ goto L1294;
- L1128:
+ L1294:
x2 = XEXP (x1, 2);
if (GET_CODE (x2) == PC && 1)
- return 234;
+ return 255;
goto ret0;
- L1217:
+ L1383:
x2 = XEXP (x1, 2);
if (GET_CODE (x2) == LABEL_REF && 1)
- goto L1218;
+ goto L1384;
goto ret0;
- L1218:
+ L1384:
x3 = XEXP (x2, 0);
ro[0] = x3;
- return 252;
+ return 273;
- L1133:
+ L1299:
x3 = XEXP (x2, 0);
if (GET_CODE (x3) == CC0 && 1)
- goto L1134;
+ goto L1300;
goto ret0;
- L1134:
+ L1300:
x3 = XEXP (x2, 1);
if (GET_CODE (x3) == CONST_INT && XWINT (x3, 0) == 0 && 1)
- goto L1135;
+ goto L1301;
goto ret0;
- L1135:
+ L1301:
x2 = XEXP (x1, 1);
switch (GET_CODE (x2))
{
case LABEL_REF:
- goto L1136;
+ goto L1302;
case PC:
- goto L1226;
+ goto L1392;
}
goto ret0;
- L1136:
+ L1302:
x3 = XEXP (x2, 0);
ro[0] = x3;
- goto L1137;
+ goto L1303;
- L1137:
+ L1303:
x2 = XEXP (x1, 2);
if (GET_CODE (x2) == PC && 1)
- return 236;
+ return 257;
goto ret0;
- L1226:
+ L1392:
x2 = XEXP (x1, 2);
if (GET_CODE (x2) == LABEL_REF && 1)
- goto L1227;
+ goto L1393;
goto ret0;
- L1227:
+ L1393:
x3 = XEXP (x2, 0);
ro[0] = x3;
- return 253;
+ return 274;
- L1142:
+ L1308:
x3 = XEXP (x2, 0);
if (GET_CODE (x3) == CC0 && 1)
- goto L1143;
+ goto L1309;
goto ret0;
- L1143:
+ L1309:
x3 = XEXP (x2, 1);
if (GET_CODE (x3) == CONST_INT && XWINT (x3, 0) == 0 && 1)
- goto L1144;
+ goto L1310;
goto ret0;
- L1144:
+ L1310:
x2 = XEXP (x1, 1);
switch (GET_CODE (x2))
{
case LABEL_REF:
- goto L1145;
+ goto L1311;
case PC:
- goto L1235;
+ goto L1401;
}
goto ret0;
- L1145:
+ L1311:
x3 = XEXP (x2, 0);
ro[0] = x3;
- goto L1146;
+ goto L1312;
- L1146:
+ L1312:
x2 = XEXP (x1, 2);
if (GET_CODE (x2) == PC && 1)
- return 238;
+ return 259;
goto ret0;
- L1235:
+ L1401:
x2 = XEXP (x1, 2);
if (GET_CODE (x2) == LABEL_REF && 1)
- goto L1236;
+ goto L1402;
goto ret0;
- L1236:
+ L1402:
x3 = XEXP (x2, 0);
ro[0] = x3;
- return 254;
+ return 275;
- L1151:
+ L1317:
x3 = XEXP (x2, 0);
if (GET_CODE (x3) == CC0 && 1)
- goto L1152;
+ goto L1318;
goto ret0;
- L1152:
+ L1318:
x3 = XEXP (x2, 1);
if (GET_CODE (x3) == CONST_INT && XWINT (x3, 0) == 0 && 1)
- goto L1153;
+ goto L1319;
goto ret0;
- L1153:
+ L1319:
x2 = XEXP (x1, 1);
switch (GET_CODE (x2))
{
case LABEL_REF:
- goto L1154;
+ goto L1320;
case PC:
- goto L1244;
+ goto L1410;
}
goto ret0;
- L1154:
+ L1320:
x3 = XEXP (x2, 0);
ro[0] = x3;
- goto L1155;
+ goto L1321;
- L1155:
+ L1321:
x2 = XEXP (x1, 2);
if (GET_CODE (x2) == PC && 1)
- return 240;
+ return 261;
goto ret0;
- L1244:
+ L1410:
x2 = XEXP (x1, 2);
if (GET_CODE (x2) == LABEL_REF && 1)
- goto L1245;
+ goto L1411;
goto ret0;
- L1245:
+ L1411:
x3 = XEXP (x2, 0);
ro[0] = x3;
- return 255;
+ return 276;
- L1160:
+ L1326:
x3 = XEXP (x2, 0);
if (GET_CODE (x3) == CC0 && 1)
- goto L1161;
+ goto L1327;
goto ret0;
- L1161:
+ L1327:
x3 = XEXP (x2, 1);
if (GET_CODE (x3) == CONST_INT && XWINT (x3, 0) == 0 && 1)
- goto L1162;
+ goto L1328;
goto ret0;
- L1162:
+ L1328:
x2 = XEXP (x1, 1);
switch (GET_CODE (x2))
{
case LABEL_REF:
- goto L1163;
+ goto L1329;
case PC:
- goto L1253;
+ goto L1419;
}
goto ret0;
- L1163:
+ L1329:
x3 = XEXP (x2, 0);
ro[0] = x3;
- goto L1164;
+ goto L1330;
- L1164:
+ L1330:
x2 = XEXP (x1, 2);
if (GET_CODE (x2) == PC && 1)
- return 242;
+ return 263;
goto ret0;
- L1253:
+ L1419:
x2 = XEXP (x1, 2);
if (GET_CODE (x2) == LABEL_REF && 1)
- goto L1254;
+ goto L1420;
goto ret0;
- L1254:
+ L1420:
x3 = XEXP (x2, 0);
ro[0] = x3;
- return 256;
+ return 277;
- L1169:
+ L1335:
x3 = XEXP (x2, 0);
if (GET_CODE (x3) == CC0 && 1)
- goto L1170;
+ goto L1336;
goto ret0;
- L1170:
+ L1336:
x3 = XEXP (x2, 1);
if (GET_CODE (x3) == CONST_INT && XWINT (x3, 0) == 0 && 1)
- goto L1171;
+ goto L1337;
goto ret0;
- L1171:
+ L1337:
x2 = XEXP (x1, 1);
switch (GET_CODE (x2))
{
case LABEL_REF:
- goto L1172;
+ goto L1338;
case PC:
- goto L1262;
+ goto L1428;
}
goto ret0;
- L1172:
+ L1338:
x3 = XEXP (x2, 0);
ro[0] = x3;
- goto L1173;
+ goto L1339;
- L1173:
+ L1339:
x2 = XEXP (x1, 2);
if (GET_CODE (x2) == PC && 1)
- return 244;
+ return 265;
goto ret0;
- L1262:
+ L1428:
x2 = XEXP (x1, 2);
if (GET_CODE (x2) == LABEL_REF && 1)
- goto L1263;
+ goto L1429;
goto ret0;
- L1263:
+ L1429:
x3 = XEXP (x2, 0);
ro[0] = x3;
- return 257;
+ return 278;
- L1178:
+ L1344:
x3 = XEXP (x2, 0);
if (GET_CODE (x3) == CC0 && 1)
- goto L1179;
+ goto L1345;
goto ret0;
- L1179:
+ L1345:
x3 = XEXP (x2, 1);
if (GET_CODE (x3) == CONST_INT && XWINT (x3, 0) == 0 && 1)
- goto L1180;
+ goto L1346;
goto ret0;
- L1180:
+ L1346:
x2 = XEXP (x1, 1);
switch (GET_CODE (x2))
{
case LABEL_REF:
- goto L1181;
+ goto L1347;
case PC:
- goto L1271;
+ goto L1437;
}
goto ret0;
- L1181:
+ L1347:
x3 = XEXP (x2, 0);
ro[0] = x3;
- goto L1182;
+ goto L1348;
- L1182:
+ L1348:
x2 = XEXP (x1, 2);
if (GET_CODE (x2) == PC && 1)
- return 246;
+ return 267;
goto ret0;
- L1271:
+ L1437:
x2 = XEXP (x1, 2);
if (GET_CODE (x2) == LABEL_REF && 1)
- goto L1272;
+ goto L1438;
goto ret0;
- L1272:
+ L1438:
x3 = XEXP (x2, 0);
ro[0] = x3;
- return 258;
+ return 279;
- L1187:
+ L1353:
x3 = XEXP (x2, 0);
if (GET_CODE (x3) == CC0 && 1)
- goto L1188;
+ goto L1354;
goto ret0;
- L1188:
+ L1354:
x3 = XEXP (x2, 1);
if (GET_CODE (x3) == CONST_INT && XWINT (x3, 0) == 0 && 1)
- goto L1189;
+ goto L1355;
goto ret0;
- L1189:
+ L1355:
x2 = XEXP (x1, 1);
switch (GET_CODE (x2))
{
case LABEL_REF:
- goto L1190;
+ goto L1356;
case PC:
- goto L1280;
+ goto L1446;
}
goto ret0;
- L1190:
+ L1356:
x3 = XEXP (x2, 0);
ro[0] = x3;
- goto L1191;
+ goto L1357;
- L1191:
+ L1357:
x2 = XEXP (x1, 2);
if (GET_CODE (x2) == PC && 1)
- return 248;
+ return 269;
goto ret0;
- L1280:
+ L1446:
x2 = XEXP (x1, 2);
if (GET_CODE (x2) == LABEL_REF && 1)
- goto L1281;
+ goto L1447;
goto ret0;
- L1281:
+ L1447:
x3 = XEXP (x2, 0);
ro[0] = x3;
- return 259;
+ return 280;
- L1196:
+ L1362:
x3 = XEXP (x2, 0);
if (GET_CODE (x3) == CC0 && 1)
- goto L1197;
+ goto L1363;
goto ret0;
- L1197:
+ L1363:
x3 = XEXP (x2, 1);
if (GET_CODE (x3) == CONST_INT && XWINT (x3, 0) == 0 && 1)
- goto L1198;
+ goto L1364;
goto ret0;
- L1198:
+ L1364:
x2 = XEXP (x1, 1);
switch (GET_CODE (x2))
{
case LABEL_REF:
- goto L1199;
+ goto L1365;
case PC:
- goto L1289;
+ goto L1455;
}
goto ret0;
- L1199:
+ L1365:
x3 = XEXP (x2, 0);
ro[0] = x3;
- goto L1200;
+ goto L1366;
- L1200:
+ L1366:
x2 = XEXP (x1, 2);
if (GET_CODE (x2) == PC && 1)
- return 250;
+ return 271;
goto ret0;
- L1289:
+ L1455:
x2 = XEXP (x1, 2);
if (GET_CODE (x2) == LABEL_REF && 1)
- goto L1290;
+ goto L1456;
goto ret0;
- L1290:
+ L1456:
x3 = XEXP (x2, 0);
ro[0] = x3;
- return 260;
+ return 281;
ret0: return -1;
}
@@ -1577,133 +1578,151 @@ recog_4 (x0, insn, pnum_clobbers)
}
break;
case ZERO_EXTRACT:
- goto L1025;
+ goto L1191;
}
- L303:
+ L304:
if (general_operand (x1, SImode))
{
ro[0] = x1;
- goto L365;
+ goto L469;
}
- L611:
+ L723:
if (register_operand (x1, SImode))
{
ro[0] = x1;
- goto L612;
+ goto L820;
}
- L619:
+ L739:
if (general_operand (x1, SImode))
{
ro[0] = x1;
- goto L620;
+ goto L740;
}
break;
case HImode:
if (GET_CODE (x1) == MEM && push_operand (x1, HImode))
{
ro[0] = x1;
- goto L307;
+ goto L308;
}
- L309:
+ L316:
if (general_operand (x1, HImode))
{
ro[0] = x1;
- goto L369;
+ goto L473;
}
break;
case QImode:
if (GET_CODE (x1) == MEM && push_operand (x1, QImode))
{
ro[0] = x1;
- goto L317;
+ goto L327;
}
- L319:
+ L332:
if (general_operand (x1, QImode))
{
ro[0] = x1;
- goto L607;
+ goto L719;
}
- L1062:
+ L1228:
if (register_operand (x1, QImode))
{
ro[0] = x1;
- goto L1063;
+ goto L1229;
}
break;
case SFmode:
if (GET_CODE (x1) == MEM && push_operand (x1, SFmode))
{
ro[0] = x1;
- goto L327;
+ goto L340;
+ }
+ L359:
+ if (memory_operand (x1, SFmode))
+ {
+ ro[0] = x1;
+ goto L360;
}
- L329:
+ L362:
if (general_operand (x1, SFmode))
{
ro[0] = x1;
- goto L416;
+ goto L520;
}
- L575:
+ L679:
if (register_operand (x1, SFmode))
{
ro[0] = x1;
- goto L576;
+ goto L680;
}
break;
case DFmode:
if (GET_CODE (x1) == MEM && push_operand (x1, DFmode))
{
ro[0] = x1;
- goto L333;
+ goto L373;
}
- L342:
- if (general_operand (x1, DFmode))
+ L396:
+ if (memory_operand (x1, DFmode))
{
ro[0] = x1;
goto L397;
}
- L571:
+ L399:
+ if (general_operand (x1, DFmode))
+ {
+ ro[0] = x1;
+ goto L501;
+ }
+ L675:
if (register_operand (x1, DFmode))
{
ro[0] = x1;
- goto L572;
+ goto L676;
}
break;
case XFmode:
if (GET_CODE (x1) == MEM && push_operand (x1, XFmode))
{
ro[0] = x1;
- goto L346;
+ goto L410;
}
- L355:
+ L433:
+ if (memory_operand (x1, XFmode))
+ {
+ ro[0] = x1;
+ goto L434;
+ }
+ L436:
if (general_operand (x1, XFmode))
{
ro[0] = x1;
- goto L401;
+ goto L505;
}
- L567:
+ L671:
if (register_operand (x1, XFmode))
{
ro[0] = x1;
- goto L568;
+ goto L672;
}
break;
case DImode:
if (GET_CODE (x1) == MEM && push_operand (x1, DImode))
{
ro[0] = x1;
- goto L359;
+ goto L455;
}
- L361:
+ L465:
if (general_operand (x1, DImode))
{
ro[0] = x1;
- goto L592;
+ goto L704;
}
- L376:
+ L480:
if (register_operand (x1, DImode))
{
ro[0] = x1;
- goto L377;
+ goto L481;
}
}
switch (GET_CODE (x1))
@@ -1711,49 +1730,49 @@ recog_4 (x0, insn, pnum_clobbers)
case CC0:
goto L2;
case STRICT_LOW_PART:
- goto L313;
+ goto L320;
case PC:
- goto L1314;
+ goto L1480;
}
- L1380:
+ L1546:
ro[0] = x1;
- goto L1381;
- L1460:
+ goto L1547;
+ L1613:
switch (GET_MODE (x1))
{
case SImode:
if (general_operand (x1, SImode))
{
ro[0] = x1;
- goto L1461;
+ goto L1614;
}
break;
case HImode:
if (general_operand (x1, HImode))
{
ro[0] = x1;
- goto L1467;
+ goto L1620;
}
break;
case DFmode:
if (register_operand (x1, DFmode))
{
ro[0] = x1;
- goto L1473;
+ goto L1626;
}
break;
case XFmode:
if (register_operand (x1, XFmode))
{
ro[0] = x1;
- goto L1484;
+ goto L1637;
}
break;
case SFmode:
if (register_operand (x1, SFmode))
{
ro[0] = x1;
- goto L1531;
+ goto L1684;
}
}
goto ret0;
@@ -1761,57 +1780,64 @@ recog_4 (x0, insn, pnum_clobbers)
L296:
x1 = XEXP (x0, 1);
if (general_operand (x1, SImode))
- goto L300;
- x1 = XEXP (x0, 0);
- goto L303;
-
- L300:
- ro[1] = x1;
- if (! TARGET_486)
- return 46;
- L301:
- ro[1] = x1;
- if (TARGET_486)
- return 47;
+ {
+ ro[1] = x1;
+ if (TARGET_386)
+ return 46;
+ }
+ L299:
+ if (nonmemory_operand (x1, SImode))
+ {
+ ro[1] = x1;
+ if (!TARGET_386 && TARGET_MOVE)
+ return 47;
+ }
+ L302:
+ if (general_operand (x1, SImode))
+ {
+ ro[1] = x1;
+ if (!TARGET_386 && !TARGET_MOVE)
+ return 48;
+ }
x1 = XEXP (x0, 0);
- goto L303;
+ goto L304;
- L1025:
+ L1191:
x2 = XEXP (x1, 0);
if (GET_MODE (x2) == SImode && general_operand (x2, SImode))
{
ro[0] = x2;
- goto L1026;
+ goto L1192;
}
- goto L1380;
+ goto L1546;
- L1026:
+ L1192:
x2 = XEXP (x1, 1);
if (GET_CODE (x2) == CONST_INT && XWINT (x2, 0) == 1 && 1)
- goto L1027;
- goto L1380;
+ goto L1193;
+ goto L1546;
- L1027:
+ L1193:
x2 = XEXP (x1, 2);
if (general_operand (x2, SImode))
{
ro[2] = x2;
- goto L1028;
+ goto L1194;
}
- goto L1380;
+ goto L1546;
- L1028:
+ L1194:
x1 = XEXP (x0, 1);
if (GET_CODE (x1) == CONST_INT && 1)
{
ro[3] = x1;
- if (! TARGET_486 && GET_CODE (operands[2]) != CONST_INT)
- return 205;
+ if (TARGET_386 && GET_CODE (operands[2]) != CONST_INT)
+ return 226;
}
x1 = XEXP (x0, 0);
- goto L1380;
+ goto L1546;
- L365:
+ L469:
x1 = XEXP (x0, 1);
switch (GET_MODE (x1))
{
@@ -1819,22 +1845,23 @@ recog_4 (x0, insn, pnum_clobbers)
switch (GET_CODE (x1))
{
case ZERO_EXTEND:
- goto L366;
+ goto L470;
case SIGN_EXTEND:
- goto L386;
+ goto L490;
case PLUS:
- goto L598;
+ goto L710;
}
}
if (general_operand (x1, SImode))
{
ro[1] = x1;
- return 49;
- }
+ if ((!TARGET_MOVE || GET_CODE (operands[0]) != MEM) || (GET_CODE (operands[1]) != MEM))
+ return 50;
+ }
x1 = XEXP (x0, 0);
- goto L611;
+ goto L723;
- L366:
+ L470:
x2 = XEXP (x1, 0);
switch (GET_MODE (x2))
{
@@ -1842,20 +1869,20 @@ recog_4 (x0, insn, pnum_clobbers)
if (nonimmediate_operand (x2, HImode))
{
ro[1] = x2;
- return 66;
+ return 85;
}
break;
case QImode:
if (nonimmediate_operand (x2, QImode))
{
ro[1] = x2;
- return 68;
+ return 87;
}
}
x1 = XEXP (x0, 0);
- goto L611;
+ goto L723;
- L386:
+ L490:
x2 = XEXP (x1, 0);
switch (GET_MODE (x2))
{
@@ -1863,387 +1890,528 @@ recog_4 (x0, insn, pnum_clobbers)
if (nonimmediate_operand (x2, HImode))
{
ro[1] = x2;
- return 71;
+ return 90;
}
break;
case QImode:
if (nonimmediate_operand (x2, QImode))
{
ro[1] = x2;
- return 73;
+ return 92;
}
}
x1 = XEXP (x0, 0);
- goto L611;
+ goto L723;
- L598:
+ L710:
x2 = XEXP (x1, 0);
if (general_operand (x2, SImode))
{
ro[1] = x2;
- goto L599;
+ goto L711;
}
x1 = XEXP (x0, 0);
- goto L611;
+ goto L723;
- L599:
+ L711:
x2 = XEXP (x1, 1);
if (general_operand (x2, SImode))
{
ro[2] = x2;
- return 109;
+ return 128;
}
x1 = XEXP (x0, 0);
- goto L611;
+ goto L723;
- L612:
+ L820:
x1 = XEXP (x0, 1);
+ if (GET_MODE (x1) == SImode && GET_CODE (x1) == TRUNCATE && 1)
+ goto L821;
if (address_operand (x1, QImode))
{
ro[1] = x1;
- return 112;
+ return 131;
}
x1 = XEXP (x0, 0);
- goto L619;
+ goto L739;
- L620:
+ L821:
+ x2 = XEXP (x1, 0);
+ if (GET_MODE (x2) == DImode && GET_CODE (x2) == LSHIFTRT && 1)
+ goto L822;
+ x1 = XEXP (x0, 0);
+ goto L739;
+
+ L822:
+ x3 = XEXP (x2, 0);
+ if (GET_MODE (x3) == DImode && GET_CODE (x3) == MULT && 1)
+ goto L823;
+ x1 = XEXP (x0, 0);
+ goto L739;
+
+ L823:
+ x4 = XEXP (x3, 0);
+ if (GET_MODE (x4) != DImode)
+ {
+ x1 = XEXP (x0, 0);
+ goto L739;
+ }
+ switch (GET_CODE (x4))
+ {
+ case ZERO_EXTEND:
+ goto L824;
+ case SIGN_EXTEND:
+ goto L847;
+ }
+ x1 = XEXP (x0, 0);
+ goto L739;
+
+ L824:
+ x5 = XEXP (x4, 0);
+ if (register_operand (x5, SImode))
+ {
+ ro[1] = x5;
+ goto L825;
+ }
+ x1 = XEXP (x0, 0);
+ goto L739;
+
+ L825:
+ x4 = XEXP (x3, 1);
+ if (GET_MODE (x4) == DImode && GET_CODE (x4) == ZERO_EXTEND && 1)
+ goto L826;
+ x1 = XEXP (x0, 0);
+ goto L739;
+
+ L826:
+ x5 = XEXP (x4, 0);
+ if (nonimmediate_operand (x5, SImode))
+ {
+ ro[2] = x5;
+ goto L827;
+ }
+ x1 = XEXP (x0, 0);
+ goto L739;
+
+ L827:
+ x3 = XEXP (x2, 1);
+ if (GET_CODE (x3) == CONST_INT && XWINT (x3, 0) == 32 && pnum_clobbers != 0 && 1)
+ if (TARGET_WIDE_MULTIPLY)
+ {
+ *pnum_clobbers = 1;
+ return 150;
+ }
+ x1 = XEXP (x0, 0);
+ goto L739;
+
+ L847:
+ x5 = XEXP (x4, 0);
+ if (register_operand (x5, SImode))
+ {
+ ro[1] = x5;
+ goto L848;
+ }
+ x1 = XEXP (x0, 0);
+ goto L739;
+
+ L848:
+ x4 = XEXP (x3, 1);
+ if (GET_MODE (x4) == DImode && GET_CODE (x4) == SIGN_EXTEND && 1)
+ goto L849;
+ x1 = XEXP (x0, 0);
+ goto L739;
+
+ L849:
+ x5 = XEXP (x4, 0);
+ if (nonimmediate_operand (x5, SImode))
+ {
+ ro[2] = x5;
+ goto L850;
+ }
+ x1 = XEXP (x0, 0);
+ goto L739;
+
+ L850:
+ x3 = XEXP (x2, 1);
+ if (GET_CODE (x3) == CONST_INT && XWINT (x3, 0) == 32 && pnum_clobbers != 0 && 1)
+ if (TARGET_WIDE_MULTIPLY)
+ {
+ *pnum_clobbers = 1;
+ return 151;
+ }
+ x1 = XEXP (x0, 0);
+ goto L739;
+
+ L740:
x1 = XEXP (x0, 1);
if (GET_MODE (x1) != SImode)
{
x1 = XEXP (x0, 0);
- goto L1380;
+ goto L1546;
}
switch (GET_CODE (x1))
{
case MINUS:
- goto L621;
+ goto L741;
case MULT:
- goto L648;
+ goto L768;
case AND:
- goto L742;
+ goto L908;
case IOR:
- goto L757;
+ goto L923;
case XOR:
- goto L1032;
+ goto L1198;
case NEG:
- goto L791;
+ goto L957;
case NOT:
- goto L900;
+ goto L1066;
case ASHIFT:
- goto L925;
+ goto L1091;
case ASHIFTRT:
- goto L953;
+ goto L1119;
case LSHIFTRT:
- goto L981;
+ goto L1147;
case ROTATE:
- goto L996;
+ goto L1162;
case ROTATERT:
- goto L1011;
+ goto L1177;
}
x1 = XEXP (x0, 0);
- goto L1380;
+ goto L1546;
- L621:
+ L741:
x2 = XEXP (x1, 0);
if (general_operand (x2, SImode))
{
ro[1] = x2;
- goto L622;
+ goto L742;
}
x1 = XEXP (x0, 0);
- goto L1380;
+ goto L1546;
- L622:
+ L742:
x2 = XEXP (x1, 1);
if (general_operand (x2, SImode))
{
ro[2] = x2;
- return 117;
+ return 136;
}
x1 = XEXP (x0, 0);
- goto L1380;
+ goto L1546;
- L648:
+ L768:
x2 = XEXP (x1, 0);
if (general_operand (x2, SImode))
{
ro[1] = x2;
- goto L649;
+ goto L769;
}
x1 = XEXP (x0, 0);
- goto L1380;
+ goto L1546;
- L649:
+ L769:
x2 = XEXP (x1, 1);
if (general_operand (x2, SImode))
- goto L655;
+ goto L775;
x1 = XEXP (x0, 0);
- goto L1380;
+ goto L1546;
- L655:
+ L775:
ro[2] = x2;
if (GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) == 0x80)
- return 125;
- L656:
+ return 144;
+ L776:
ro[2] = x2;
- return 126;
+ return 145;
- L742:
+ L908:
x2 = XEXP (x1, 0);
if (general_operand (x2, SImode))
{
ro[1] = x2;
- goto L743;
+ goto L909;
}
x1 = XEXP (x0, 0);
- goto L1380;
+ goto L1546;
- L743:
+ L909:
x2 = XEXP (x1, 1);
if (general_operand (x2, SImode))
{
ro[2] = x2;
- return 143;
+ return 164;
}
x1 = XEXP (x0, 0);
- goto L1380;
+ goto L1546;
- L757:
+ L923:
x2 = XEXP (x1, 0);
if (general_operand (x2, SImode))
{
ro[1] = x2;
- goto L758;
+ goto L924;
}
x1 = XEXP (x0, 0);
- goto L1380;
+ goto L1546;
- L758:
+ L924:
x2 = XEXP (x1, 1);
if (general_operand (x2, SImode))
{
ro[2] = x2;
- return 146;
+ return 167;
}
x1 = XEXP (x0, 0);
- goto L1380;
+ goto L1546;
- L1032:
+ L1198:
x2 = XEXP (x1, 0);
if (GET_MODE (x2) == SImode && GET_CODE (x2) == ASHIFT && 1)
- goto L1033;
+ goto L1199;
if (general_operand (x2, SImode))
{
ro[1] = x2;
- goto L1040;
+ goto L1206;
}
x1 = XEXP (x0, 0);
- goto L1380;
+ goto L1546;
- L1033:
+ L1199:
x3 = XEXP (x2, 0);
if (GET_CODE (x3) == CONST_INT && XWINT (x3, 0) == 1 && 1)
- goto L1034;
+ goto L1200;
x1 = XEXP (x0, 0);
- goto L1380;
+ goto L1546;
- L1034:
+ L1200:
x3 = XEXP (x2, 1);
if (general_operand (x3, SImode))
{
ro[1] = x3;
- goto L1035;
+ goto L1201;
}
x1 = XEXP (x0, 0);
- goto L1380;
+ goto L1546;
- L1035:
+ L1201:
x2 = XEXP (x1, 1);
if (general_operand (x2, SImode))
{
ro[2] = x2;
- if (! TARGET_486 && GET_CODE (operands[1]) != CONST_INT)
- return 206;
+ if (TARGET_386 && GET_CODE (operands[1]) != CONST_INT)
+ return 227;
}
x1 = XEXP (x0, 0);
- goto L1380;
+ goto L1546;
- L1040:
+ L1206:
x2 = XEXP (x1, 1);
if (GET_MODE (x2) == SImode && GET_CODE (x2) == ASHIFT && 1)
- goto L1041;
+ goto L1207;
if (general_operand (x2, SImode))
{
ro[2] = x2;
- return 149;
+ return 170;
}
x1 = XEXP (x0, 0);
- goto L1380;
+ goto L1546;
- L1041:
+ L1207:
x3 = XEXP (x2, 0);
if (GET_CODE (x3) == CONST_INT && XWINT (x3, 0) == 1 && 1)
- goto L1042;
+ goto L1208;
x1 = XEXP (x0, 0);
- goto L1380;
+ goto L1546;
- L1042:
+ L1208:
x3 = XEXP (x2, 1);
if (general_operand (x3, SImode))
{
ro[2] = x3;
- if (! TARGET_486 && GET_CODE (operands[2]) != CONST_INT)
- return 207;
+ if (TARGET_386 && GET_CODE (operands[2]) != CONST_INT)
+ return 228;
}
x1 = XEXP (x0, 0);
- goto L1380;
+ goto L1546;
- L791:
+ L957:
x2 = XEXP (x1, 0);
if (general_operand (x2, SImode))
{
ro[1] = x2;
- return 153;
+ return 174;
}
x1 = XEXP (x0, 0);
- goto L1380;
+ goto L1546;
- L900:
+ L1066:
x2 = XEXP (x1, 0);
if (general_operand (x2, SImode))
{
ro[1] = x2;
- return 178;
+ return 199;
}
x1 = XEXP (x0, 0);
- goto L1380;
+ goto L1546;
- L925:
+ L1091:
x2 = XEXP (x1, 0);
if (general_operand (x2, SImode))
{
ro[1] = x2;
- goto L926;
+ goto L1092;
}
x1 = XEXP (x0, 0);
- goto L1380;
+ goto L1546;
- L926:
+ L1092:
x2 = XEXP (x1, 1);
if (nonmemory_operand (x2, SImode))
{
ro[2] = x2;
- return 184;
+ return 205;
}
x1 = XEXP (x0, 0);
- goto L1380;
+ goto L1546;
- L953:
+ L1119:
x2 = XEXP (x1, 0);
if (general_operand (x2, SImode))
{
ro[1] = x2;
- goto L954;
+ goto L1120;
}
x1 = XEXP (x0, 0);
- goto L1380;
+ goto L1546;
- L954:
+ L1120:
x2 = XEXP (x1, 1);
if (nonmemory_operand (x2, SImode))
{
ro[2] = x2;
- return 190;
+ return 211;
}
x1 = XEXP (x0, 0);
- goto L1380;
+ goto L1546;
- L981:
+ L1147:
x2 = XEXP (x1, 0);
if (general_operand (x2, SImode))
{
ro[1] = x2;
- goto L982;
+ goto L1148;
}
x1 = XEXP (x0, 0);
- goto L1380;
+ goto L1546;
- L982:
+ L1148:
x2 = XEXP (x1, 1);
if (nonmemory_operand (x2, SImode))
{
ro[2] = x2;
- return 196;
+ return 217;
}
x1 = XEXP (x0, 0);
- goto L1380;
+ goto L1546;
- L996:
+ L1162:
x2 = XEXP (x1, 0);
if (general_operand (x2, SImode))
{
ro[1] = x2;
- goto L997;
+ goto L1163;
}
x1 = XEXP (x0, 0);
- goto L1380;
+ goto L1546;
- L997:
+ L1163:
x2 = XEXP (x1, 1);
if (nonmemory_operand (x2, SImode))
{
ro[2] = x2;
- return 199;
+ return 220;
}
x1 = XEXP (x0, 0);
- goto L1380;
+ goto L1546;
- L1011:
+ L1177:
x2 = XEXP (x1, 0);
if (general_operand (x2, SImode))
{
ro[1] = x2;
- goto L1012;
+ goto L1178;
}
x1 = XEXP (x0, 0);
- goto L1380;
+ goto L1546;
- L1012:
+ L1178:
x2 = XEXP (x1, 1);
if (nonmemory_operand (x2, SImode))
{
ro[2] = x2;
- return 202;
+ return 223;
}
x1 = XEXP (x0, 0);
- goto L1380;
+ goto L1546;
- L307:
+ L308:
x1 = XEXP (x0, 1);
if (general_operand (x1, HImode))
{
ro[1] = x1;
- return 50;
- }
+ if (TARGET_386)
+ return 51;
+ }
+ L311:
+ if (nonmemory_operand (x1, HImode))
+ {
+ ro[1] = x1;
+ if (!TARGET_386 && TARGET_MOVE)
+ return 52;
+ }
+ L314:
+ if (general_operand (x1, HImode))
+ {
+ ro[1] = x1;
+ if (!TARGET_386 && !TARGET_MOVE)
+ return 53;
+ }
x1 = XEXP (x0, 0);
- goto L309;
- L369:
+ goto L316;
+ L473:
tem = recog_1 (x0, insn, pnum_clobbers);
if (tem >= 0) return tem;
x1 = XEXP (x0, 0);
- goto L1380;
+ goto L1546;
- L317:
+ L327:
x1 = XEXP (x0, 1);
- if (general_operand (x1, QImode))
+ switch (GET_MODE (x1))
+ {
+ case QImode:
+ if (nonimmediate_operand (x1, QImode))
+ {
+ ro[1] = x1;
+ if (!TARGET_MOVE)
+ return 59;
+ }
+ L330:
+ if (register_operand (x1, QImode))
+ {
+ ro[1] = x1;
+ if (TARGET_MOVE)
+ return 60;
+ }
+ }
+ if (immediate_operand (x1, QImode))
{
ro[1] = x1;
- return 53;
+ return 58;
}
x1 = XEXP (x0, 0);
- goto L319;
+ goto L332;
- L607:
+ L719:
x1 = XEXP (x0, 1);
switch (GET_MODE (x1))
{
@@ -2251,536 +2419,560 @@ recog_4 (x0, insn, pnum_clobbers)
switch (GET_CODE (x1))
{
case PLUS:
- goto L608;
+ goto L720;
case MINUS:
- goto L631;
+ goto L751;
case DIV:
- goto L688;
+ goto L854;
case UDIV:
- goto L693;
+ goto L859;
case AND:
- goto L752;
+ goto L918;
case IOR:
- goto L767;
+ goto L933;
case XOR:
- goto L782;
+ goto L948;
case NEG:
- goto L799;
+ goto L965;
case NOT:
- goto L908;
+ goto L1074;
case ASHIFT:
- goto L935;
+ goto L1101;
case ASHIFTRT:
- goto L963;
+ goto L1129;
case LSHIFTRT:
- goto L991;
+ goto L1157;
case ROTATE:
- goto L1006;
+ goto L1172;
case ROTATERT:
- goto L1021;
+ goto L1187;
}
}
if (general_operand (x1, QImode))
{
ro[1] = x1;
- return 54;
- }
+ if ((!TARGET_MOVE || GET_CODE (operands[0]) != MEM) || (GET_CODE (operands[1]) != MEM))
+ return 62;
+ }
x1 = XEXP (x0, 0);
- goto L1062;
+ goto L1228;
- L608:
+ L720:
x2 = XEXP (x1, 0);
if (general_operand (x2, QImode))
{
ro[1] = x2;
- goto L609;
+ goto L721;
}
x1 = XEXP (x0, 0);
- goto L1062;
+ goto L1228;
- L609:
+ L721:
x2 = XEXP (x1, 1);
if (general_operand (x2, QImode))
{
ro[2] = x2;
- return 111;
+ return 130;
}
x1 = XEXP (x0, 0);
- goto L1062;
+ goto L1228;
- L631:
+ L751:
x2 = XEXP (x1, 0);
if (general_operand (x2, QImode))
{
ro[1] = x2;
- goto L632;
+ goto L752;
}
x1 = XEXP (x0, 0);
- goto L1062;
+ goto L1228;
- L632:
+ L752:
x2 = XEXP (x1, 1);
if (general_operand (x2, QImode))
{
ro[2] = x2;
- return 119;
+ return 138;
}
x1 = XEXP (x0, 0);
- goto L1062;
+ goto L1228;
- L688:
+ L854:
x2 = XEXP (x1, 0);
if (general_operand (x2, HImode))
{
ro[1] = x2;
- goto L689;
+ goto L855;
}
x1 = XEXP (x0, 0);
- goto L1062;
+ goto L1228;
- L689:
+ L855:
x2 = XEXP (x1, 1);
if (general_operand (x2, QImode))
{
ro[2] = x2;
- return 134;
+ return 155;
}
x1 = XEXP (x0, 0);
- goto L1062;
+ goto L1228;
- L693:
+ L859:
x2 = XEXP (x1, 0);
if (general_operand (x2, HImode))
{
ro[1] = x2;
- goto L694;
+ goto L860;
}
x1 = XEXP (x0, 0);
- goto L1062;
+ goto L1228;
- L694:
+ L860:
x2 = XEXP (x1, 1);
if (general_operand (x2, QImode))
{
ro[2] = x2;
- return 135;
+ return 156;
}
x1 = XEXP (x0, 0);
- goto L1062;
+ goto L1228;
- L752:
+ L918:
x2 = XEXP (x1, 0);
if (general_operand (x2, QImode))
{
ro[1] = x2;
- goto L753;
+ goto L919;
}
x1 = XEXP (x0, 0);
- goto L1062;
+ goto L1228;
- L753:
+ L919:
x2 = XEXP (x1, 1);
if (general_operand (x2, QImode))
{
ro[2] = x2;
- return 145;
+ return 166;
}
x1 = XEXP (x0, 0);
- goto L1062;
+ goto L1228;
- L767:
+ L933:
x2 = XEXP (x1, 0);
if (general_operand (x2, QImode))
{
ro[1] = x2;
- goto L768;
+ goto L934;
}
x1 = XEXP (x0, 0);
- goto L1062;
+ goto L1228;
- L768:
+ L934:
x2 = XEXP (x1, 1);
if (general_operand (x2, QImode))
{
ro[2] = x2;
- return 148;
+ return 169;
}
x1 = XEXP (x0, 0);
- goto L1062;
+ goto L1228;
- L782:
+ L948:
x2 = XEXP (x1, 0);
if (general_operand (x2, QImode))
{
ro[1] = x2;
- goto L783;
+ goto L949;
}
x1 = XEXP (x0, 0);
- goto L1062;
+ goto L1228;
- L783:
+ L949:
x2 = XEXP (x1, 1);
if (general_operand (x2, QImode))
{
ro[2] = x2;
- return 151;
+ return 172;
}
x1 = XEXP (x0, 0);
- goto L1062;
+ goto L1228;
- L799:
+ L965:
x2 = XEXP (x1, 0);
if (general_operand (x2, QImode))
{
ro[1] = x2;
- return 155;
+ return 176;
}
x1 = XEXP (x0, 0);
- goto L1062;
+ goto L1228;
- L908:
+ L1074:
x2 = XEXP (x1, 0);
if (general_operand (x2, QImode))
{
ro[1] = x2;
- return 180;
+ return 201;
}
x1 = XEXP (x0, 0);
- goto L1062;
+ goto L1228;
- L935:
+ L1101:
x2 = XEXP (x1, 0);
if (general_operand (x2, QImode))
{
ro[1] = x2;
- goto L936;
+ goto L1102;
}
x1 = XEXP (x0, 0);
- goto L1062;
+ goto L1228;
- L936:
+ L1102:
x2 = XEXP (x1, 1);
if (nonmemory_operand (x2, QImode))
{
ro[2] = x2;
- return 186;
+ return 207;
}
x1 = XEXP (x0, 0);
- goto L1062;
+ goto L1228;
- L963:
+ L1129:
x2 = XEXP (x1, 0);
if (general_operand (x2, QImode))
{
ro[1] = x2;
- goto L964;
+ goto L1130;
}
x1 = XEXP (x0, 0);
- goto L1062;
+ goto L1228;
- L964:
+ L1130:
x2 = XEXP (x1, 1);
if (nonmemory_operand (x2, QImode))
{
ro[2] = x2;
- return 192;
+ return 213;
}
x1 = XEXP (x0, 0);
- goto L1062;
+ goto L1228;
- L991:
+ L1157:
x2 = XEXP (x1, 0);
if (general_operand (x2, QImode))
{
ro[1] = x2;
- goto L992;
+ goto L1158;
}
x1 = XEXP (x0, 0);
- goto L1062;
+ goto L1228;
- L992:
+ L1158:
x2 = XEXP (x1, 1);
if (nonmemory_operand (x2, QImode))
{
ro[2] = x2;
- return 198;
+ return 219;
}
x1 = XEXP (x0, 0);
- goto L1062;
+ goto L1228;
- L1006:
+ L1172:
x2 = XEXP (x1, 0);
if (general_operand (x2, QImode))
{
ro[1] = x2;
- goto L1007;
+ goto L1173;
}
x1 = XEXP (x0, 0);
- goto L1062;
+ goto L1228;
- L1007:
+ L1173:
x2 = XEXP (x1, 1);
if (nonmemory_operand (x2, QImode))
{
ro[2] = x2;
- return 201;
+ return 222;
}
x1 = XEXP (x0, 0);
- goto L1062;
+ goto L1228;
- L1021:
+ L1187:
x2 = XEXP (x1, 0);
if (general_operand (x2, QImode))
{
ro[1] = x2;
- goto L1022;
+ goto L1188;
}
x1 = XEXP (x0, 0);
- goto L1062;
+ goto L1228;
- L1022:
+ L1188:
x2 = XEXP (x1, 1);
if (nonmemory_operand (x2, QImode))
{
ro[2] = x2;
- return 204;
+ return 225;
}
x1 = XEXP (x0, 0);
- goto L1062;
+ goto L1228;
- L1063:
+ L1229:
x1 = XEXP (x0, 1);
if (GET_MODE (x1) != QImode)
{
x1 = XEXP (x0, 0);
- goto L1380;
+ goto L1546;
}
switch (GET_CODE (x1))
{
case EQ:
- goto L1064;
+ goto L1230;
case NE:
- goto L1069;
+ goto L1235;
case GT:
- goto L1074;
+ goto L1240;
case GTU:
- goto L1079;
+ goto L1245;
case LT:
- goto L1084;
+ goto L1250;
case LTU:
- goto L1089;
+ goto L1255;
case GE:
- goto L1094;
+ goto L1260;
case GEU:
- goto L1099;
+ goto L1265;
case LE:
- goto L1104;
+ goto L1270;
case LEU:
- goto L1109;
+ goto L1275;
}
x1 = XEXP (x0, 0);
- goto L1380;
+ goto L1546;
- L1064:
+ L1230:
x2 = XEXP (x1, 0);
if (GET_CODE (x2) == CC0 && 1)
- goto L1065;
+ goto L1231;
x1 = XEXP (x0, 0);
- goto L1380;
+ goto L1546;
- L1065:
+ L1231:
x2 = XEXP (x1, 1);
if (GET_CODE (x2) == CONST_INT && XWINT (x2, 0) == 0 && 1)
- return 212;
+ return 233;
x1 = XEXP (x0, 0);
- goto L1380;
+ goto L1546;
- L1069:
+ L1235:
x2 = XEXP (x1, 0);
if (GET_CODE (x2) == CC0 && 1)
- goto L1070;
+ goto L1236;
x1 = XEXP (x0, 0);
- goto L1380;
+ goto L1546;
- L1070:
+ L1236:
x2 = XEXP (x1, 1);
if (GET_CODE (x2) == CONST_INT && XWINT (x2, 0) == 0 && 1)
- return 214;
+ return 235;
x1 = XEXP (x0, 0);
- goto L1380;
+ goto L1546;
- L1074:
+ L1240:
x2 = XEXP (x1, 0);
if (GET_CODE (x2) == CC0 && 1)
- goto L1075;
+ goto L1241;
x1 = XEXP (x0, 0);
- goto L1380;
+ goto L1546;
- L1075:
+ L1241:
x2 = XEXP (x1, 1);
if (GET_CODE (x2) == CONST_INT && XWINT (x2, 0) == 0 && 1)
- return 216;
+ return 237;
x1 = XEXP (x0, 0);
- goto L1380;
+ goto L1546;
- L1079:
+ L1245:
x2 = XEXP (x1, 0);
if (GET_CODE (x2) == CC0 && 1)
- goto L1080;
+ goto L1246;
x1 = XEXP (x0, 0);
- goto L1380;
+ goto L1546;
- L1080:
+ L1246:
x2 = XEXP (x1, 1);
if (GET_CODE (x2) == CONST_INT && XWINT (x2, 0) == 0 && 1)
- return 218;
+ return 239;
x1 = XEXP (x0, 0);
- goto L1380;
+ goto L1546;
- L1084:
+ L1250:
x2 = XEXP (x1, 0);
if (GET_CODE (x2) == CC0 && 1)
- goto L1085;
+ goto L1251;
x1 = XEXP (x0, 0);
- goto L1380;
+ goto L1546;
- L1085:
+ L1251:
x2 = XEXP (x1, 1);
if (GET_CODE (x2) == CONST_INT && XWINT (x2, 0) == 0 && 1)
- return 220;
+ return 241;
x1 = XEXP (x0, 0);
- goto L1380;
+ goto L1546;
- L1089:
+ L1255:
x2 = XEXP (x1, 0);
if (GET_CODE (x2) == CC0 && 1)
- goto L1090;
+ goto L1256;
x1 = XEXP (x0, 0);
- goto L1380;
+ goto L1546;
- L1090:
+ L1256:
x2 = XEXP (x1, 1);
if (GET_CODE (x2) == CONST_INT && XWINT (x2, 0) == 0 && 1)
- return 222;
+ return 243;
x1 = XEXP (x0, 0);
- goto L1380;
+ goto L1546;
- L1094:
+ L1260:
x2 = XEXP (x1, 0);
if (GET_CODE (x2) == CC0 && 1)
- goto L1095;
+ goto L1261;
x1 = XEXP (x0, 0);
- goto L1380;
+ goto L1546;
- L1095:
+ L1261:
x2 = XEXP (x1, 1);
if (GET_CODE (x2) == CONST_INT && XWINT (x2, 0) == 0 && 1)
- return 224;
+ return 245;
x1 = XEXP (x0, 0);
- goto L1380;
+ goto L1546;
- L1099:
+ L1265:
x2 = XEXP (x1, 0);
if (GET_CODE (x2) == CC0 && 1)
- goto L1100;
+ goto L1266;
x1 = XEXP (x0, 0);
- goto L1380;
+ goto L1546;
- L1100:
+ L1266:
x2 = XEXP (x1, 1);
if (GET_CODE (x2) == CONST_INT && XWINT (x2, 0) == 0 && 1)
- return 226;
+ return 247;
x1 = XEXP (x0, 0);
- goto L1380;
+ goto L1546;
- L1104:
+ L1270:
x2 = XEXP (x1, 0);
if (GET_CODE (x2) == CC0 && 1)
- goto L1105;
+ goto L1271;
x1 = XEXP (x0, 0);
- goto L1380;
+ goto L1546;
- L1105:
+ L1271:
x2 = XEXP (x1, 1);
if (GET_CODE (x2) == CONST_INT && XWINT (x2, 0) == 0 && 1)
- return 228;
+ return 249;
x1 = XEXP (x0, 0);
- goto L1380;
+ goto L1546;
- L1109:
+ L1275:
x2 = XEXP (x1, 0);
if (GET_CODE (x2) == CC0 && 1)
- goto L1110;
+ goto L1276;
x1 = XEXP (x0, 0);
- goto L1380;
+ goto L1546;
- L1110:
+ L1276:
x2 = XEXP (x1, 1);
if (GET_CODE (x2) == CONST_INT && XWINT (x2, 0) == 0 && 1)
- return 230;
+ return 251;
x1 = XEXP (x0, 0);
- goto L1380;
+ goto L1546;
- L327:
+ L340:
x1 = XEXP (x0, 1);
if (general_operand (x1, SFmode))
+ goto L350;
+ x1 = XEXP (x0, 0);
+ goto L359;
+
+ L350:
+ ro[1] = x1;
+ if (!TARGET_MOVE)
+ return 66;
+ L351:
+ if (pnum_clobbers != 0 && 1)
{
ro[1] = x1;
- return 56;
+ *pnum_clobbers = 1;
+ return 67;
}
x1 = XEXP (x0, 0);
- goto L329;
+ goto L359;
- L416:
+ L360:
+ x1 = XEXP (x0, 1);
+ if (pnum_clobbers != 0 && memory_operand (x1, SFmode))
+ {
+ ro[1] = x1;
+ *pnum_clobbers = 1;
+ return 68;
+ }
+ x1 = XEXP (x0, 0);
+ goto L362;
+
+ L520:
x1 = XEXP (x0, 1);
if (GET_MODE (x1) == SFmode && GET_CODE (x1) == FLOAT_TRUNCATE && 1)
- goto L417;
+ goto L521;
if (general_operand (x1, SFmode))
{
ro[1] = x1;
- return 57;
- }
+ if ((!TARGET_MOVE || GET_CODE (operands[0]) != MEM) || (GET_CODE (operands[1]) != MEM))
+ return 69;
+ }
x1 = XEXP (x0, 0);
- goto L575;
+ goto L679;
- L417:
+ L521:
x2 = XEXP (x1, 0);
if (register_operand (x2, XFmode))
{
ro[1] = x2;
if (TARGET_80387)
- return 79;
+ return 98;
}
x1 = XEXP (x0, 0);
- goto L575;
+ goto L679;
- L576:
+ L680:
x1 = XEXP (x0, 1);
if (GET_MODE (x1) != SFmode)
{
x1 = XEXP (x0, 0);
- goto L1380;
+ goto L1546;
}
switch (GET_CODE (x1))
{
case FLOAT:
- goto L577;
+ goto L681;
case NEG:
- goto L803;
+ goto L969;
case ABS:
- goto L825;
+ goto L991;
case SQRT:
- goto L847;
+ goto L1013;
case UNSPEC:
if (XINT (x1, 1) == 1 && XVECLEN (x1, 0) == 1 && 1)
- goto L878;
+ goto L1044;
if (XINT (x1, 1) == 2 && XVECLEN (x1, 0) == 1 && 1)
- goto L891;
+ goto L1057;
}
x1 = XEXP (x0, 0);
- goto L1380;
+ goto L1546;
- L577:
+ L681:
x2 = XEXP (x1, 0);
switch (GET_MODE (x2))
{
@@ -2789,7 +2981,7 @@ recog_4 (x0, insn, pnum_clobbers)
{
ro[1] = x2;
if (TARGET_80387)
- return 104;
+ return 123;
}
break;
case SImode:
@@ -2797,150 +2989,173 @@ recog_4 (x0, insn, pnum_clobbers)
{
ro[1] = x2;
if (TARGET_80387)
- return 107;
+ return 126;
}
}
x1 = XEXP (x0, 0);
- goto L1380;
+ goto L1546;
- L803:
+ L969:
x2 = XEXP (x1, 0);
if (general_operand (x2, SFmode))
{
ro[1] = x2;
if (TARGET_80387)
- return 156;
+ return 177;
}
x1 = XEXP (x0, 0);
- goto L1380;
+ goto L1546;
- L825:
+ L991:
x2 = XEXP (x1, 0);
if (general_operand (x2, SFmode))
{
ro[1] = x2;
if (TARGET_80387)
- return 161;
+ return 182;
}
x1 = XEXP (x0, 0);
- goto L1380;
+ goto L1546;
- L847:
+ L1013:
x2 = XEXP (x1, 0);
if (general_operand (x2, SFmode))
{
ro[1] = x2;
if (! TARGET_NO_FANCY_MATH_387 && TARGET_80387
&& (TARGET_IEEE_FP || flag_fast_math) )
- return 166;
+ return 187;
}
x1 = XEXP (x0, 0);
- goto L1380;
+ goto L1546;
- L878:
+ L1044:
x2 = XVECEXP (x1, 0, 0);
if (register_operand (x2, SFmode))
{
ro[1] = x2;
- if (! TARGET_NO_FANCY_MATH_387 && TARGET_80387
+ if (! TARGET_NO_FANCY_MATH_387 && TARGET_80387
&& (TARGET_IEEE_FP || flag_fast_math) )
- return 173;
+ return 194;
}
x1 = XEXP (x0, 0);
- goto L1380;
+ goto L1546;
- L891:
+ L1057:
x2 = XVECEXP (x1, 0, 0);
if (register_operand (x2, SFmode))
{
ro[1] = x2;
- if (! TARGET_NO_FANCY_MATH_387 && TARGET_80387
+ if (! TARGET_NO_FANCY_MATH_387 && TARGET_80387
&& (TARGET_IEEE_FP || flag_fast_math) )
- return 176;
+ return 197;
}
x1 = XEXP (x0, 0);
- goto L1380;
+ goto L1546;
- L333:
+ L373:
x1 = XEXP (x0, 1);
if (general_operand (x1, DFmode))
+ goto L385;
+ x1 = XEXP (x0, 0);
+ goto L396;
+
+ L385:
+ ro[1] = x1;
+ if (!TARGET_MOVE)
+ return 72;
+ L386:
+ if (pnum_clobbers != 0 && 1)
{
ro[1] = x1;
- return 58;
+ *pnum_clobbers = 2;
+ return 73;
}
x1 = XEXP (x0, 0);
- goto L342;
+ goto L396;
L397:
x1 = XEXP (x0, 1);
+ if (pnum_clobbers != 0 && memory_operand (x1, DFmode))
+ {
+ ro[1] = x1;
+ *pnum_clobbers = 2;
+ return 74;
+ }
+ x1 = XEXP (x0, 0);
+ goto L399;
+
+ L501:
+ x1 = XEXP (x0, 1);
switch (GET_MODE (x1))
{
case DFmode:
switch (GET_CODE (x1))
{
case FLOAT_EXTEND:
- goto L398;
+ goto L502;
case FLOAT_TRUNCATE:
- goto L421;
+ goto L525;
}
}
if (general_operand (x1, DFmode))
{
ro[1] = x1;
- return 60;
- }
+ if ((!TARGET_MOVE || GET_CODE (operands[0]) != MEM) || (GET_CODE (operands[1]) != MEM))
+ return 75;
+ }
x1 = XEXP (x0, 0);
- goto L571;
+ goto L675;
- L398:
+ L502:
x2 = XEXP (x1, 0);
if (general_operand (x2, SFmode))
{
ro[1] = x2;
if (TARGET_80387)
- return 74;
+ return 93;
}
x1 = XEXP (x0, 0);
- goto L571;
+ goto L675;
- L421:
+ L525:
x2 = XEXP (x1, 0);
if (register_operand (x2, XFmode))
{
ro[1] = x2;
if (TARGET_80387)
- return 80;
+ return 99;
}
x1 = XEXP (x0, 0);
- goto L571;
+ goto L675;
- L572:
+ L676:
x1 = XEXP (x0, 1);
if (GET_MODE (x1) != DFmode)
{
x1 = XEXP (x0, 0);
- goto L1380;
+ goto L1546;
}
switch (GET_CODE (x1))
{
case FLOAT:
- goto L573;
+ goto L677;
case NEG:
- goto L811;
+ goto L977;
case ABS:
- goto L833;
+ goto L999;
case SQRT:
- goto L855;
+ goto L1021;
case UNSPEC:
if (XINT (x1, 1) == 1 && XVECLEN (x1, 0) == 1 && 1)
- goto L882;
+ goto L1048;
if (XINT (x1, 1) == 2 && XVECLEN (x1, 0) == 1 && 1)
- goto L895;
+ goto L1061;
}
x1 = XEXP (x0, 0);
- goto L1380;
+ goto L1546;
- L573:
+ L677:
x2 = XEXP (x1, 0);
switch (GET_MODE (x2))
{
@@ -2949,7 +3164,7 @@ recog_4 (x0, insn, pnum_clobbers)
{
ro[1] = x2;
if (TARGET_80387)
- return 103;
+ return 122;
}
break;
case SImode:
@@ -2957,320 +3172,344 @@ recog_4 (x0, insn, pnum_clobbers)
{
ro[1] = x2;
if (TARGET_80387)
- return 105;
+ return 124;
}
}
x1 = XEXP (x0, 0);
- goto L1380;
+ goto L1546;
- L811:
+ L977:
x2 = XEXP (x1, 0);
if (GET_MODE (x2) == DFmode && GET_CODE (x2) == FLOAT_EXTEND && 1)
- goto L812;
+ goto L978;
if (general_operand (x2, DFmode))
{
ro[1] = x2;
if (TARGET_80387)
- return 157;
+ return 178;
}
x1 = XEXP (x0, 0);
- goto L1380;
+ goto L1546;
- L812:
+ L978:
x3 = XEXP (x2, 0);
if (general_operand (x3, SFmode))
{
ro[1] = x3;
if (TARGET_80387)
- return 158;
+ return 179;
}
x1 = XEXP (x0, 0);
- goto L1380;
+ goto L1546;
- L833:
+ L999:
x2 = XEXP (x1, 0);
if (GET_MODE (x2) == DFmode && GET_CODE (x2) == FLOAT_EXTEND && 1)
- goto L834;
+ goto L1000;
if (general_operand (x2, DFmode))
{
ro[1] = x2;
if (TARGET_80387)
- return 162;
+ return 183;
}
x1 = XEXP (x0, 0);
- goto L1380;
+ goto L1546;
- L834:
+ L1000:
x3 = XEXP (x2, 0);
if (general_operand (x3, SFmode))
{
ro[1] = x3;
if (TARGET_80387)
- return 163;
+ return 184;
}
x1 = XEXP (x0, 0);
- goto L1380;
+ goto L1546;
- L855:
+ L1021:
x2 = XEXP (x1, 0);
if (GET_MODE (x2) == DFmode && GET_CODE (x2) == FLOAT_EXTEND && 1)
- goto L856;
+ goto L1022;
if (general_operand (x2, DFmode))
{
ro[1] = x2;
if (! TARGET_NO_FANCY_MATH_387 && TARGET_80387
&& (TARGET_IEEE_FP || flag_fast_math) )
- return 167;
+ return 188;
}
x1 = XEXP (x0, 0);
- goto L1380;
+ goto L1546;
- L856:
+ L1022:
x3 = XEXP (x2, 0);
if (general_operand (x3, SFmode))
{
ro[1] = x3;
- if (! TARGET_NO_FANCY_MATH_387 && TARGET_80387
+ if (! TARGET_NO_FANCY_MATH_387 && TARGET_80387
&& (TARGET_IEEE_FP || flag_fast_math) )
- return 168;
+ return 189;
}
x1 = XEXP (x0, 0);
- goto L1380;
+ goto L1546;
- L882:
+ L1048:
x2 = XVECEXP (x1, 0, 0);
if (GET_MODE (x2) != DFmode)
{
x1 = XEXP (x0, 0);
- goto L1380;
+ goto L1546;
}
if (GET_CODE (x2) == FLOAT_EXTEND && 1)
- goto L883;
+ goto L1049;
if (register_operand (x2, DFmode))
{
ro[1] = x2;
- if (! TARGET_NO_FANCY_MATH_387 && TARGET_80387
+ if (! TARGET_NO_FANCY_MATH_387 && TARGET_80387
&& (TARGET_IEEE_FP || flag_fast_math) )
- return 172;
+ return 193;
}
x1 = XEXP (x0, 0);
- goto L1380;
+ goto L1546;
- L883:
+ L1049:
x3 = XEXP (x2, 0);
if (register_operand (x3, SFmode))
{
ro[1] = x3;
- if (! TARGET_NO_FANCY_MATH_387 && TARGET_80387
+ if (! TARGET_NO_FANCY_MATH_387 && TARGET_80387
&& (TARGET_IEEE_FP || flag_fast_math) )
- return 174;
+ return 195;
}
x1 = XEXP (x0, 0);
- goto L1380;
+ goto L1546;
- L895:
+ L1061:
x2 = XVECEXP (x1, 0, 0);
if (GET_MODE (x2) != DFmode)
{
x1 = XEXP (x0, 0);
- goto L1380;
+ goto L1546;
}
if (GET_CODE (x2) == FLOAT_EXTEND && 1)
- goto L896;
+ goto L1062;
if (register_operand (x2, DFmode))
{
ro[1] = x2;
- if (! TARGET_NO_FANCY_MATH_387 && TARGET_80387
+ if (! TARGET_NO_FANCY_MATH_387 && TARGET_80387
&& (TARGET_IEEE_FP || flag_fast_math) )
- return 175;
+ return 196;
}
x1 = XEXP (x0, 0);
- goto L1380;
+ goto L1546;
- L896:
+ L1062:
x3 = XEXP (x2, 0);
if (register_operand (x3, SFmode))
{
ro[1] = x3;
- if (! TARGET_NO_FANCY_MATH_387 && TARGET_80387
+ if (! TARGET_NO_FANCY_MATH_387 && TARGET_80387
&& (TARGET_IEEE_FP || flag_fast_math) )
- return 177;
+ return 198;
}
x1 = XEXP (x0, 0);
- goto L1380;
+ goto L1546;
- L346:
+ L410:
x1 = XEXP (x0, 1);
if (general_operand (x1, XFmode))
+ goto L422;
+ x1 = XEXP (x0, 0);
+ goto L433;
+
+ L422:
+ ro[1] = x1;
+ if (!TARGET_MOVE)
+ return 78;
+ L423:
+ if (pnum_clobbers != 0 && 1)
{
ro[1] = x1;
- return 61;
+ *pnum_clobbers = 2;
+ return 79;
}
x1 = XEXP (x0, 0);
- goto L355;
+ goto L433;
- L401:
+ L434:
+ x1 = XEXP (x0, 1);
+ if (pnum_clobbers != 0 && memory_operand (x1, XFmode))
+ {
+ ro[1] = x1;
+ *pnum_clobbers = 2;
+ return 80;
+ }
+ x1 = XEXP (x0, 0);
+ goto L436;
+
+ L505:
x1 = XEXP (x0, 1);
if (GET_MODE (x1) == XFmode && GET_CODE (x1) == FLOAT_EXTEND && 1)
- goto L402;
+ goto L506;
if (general_operand (x1, XFmode))
{
ro[1] = x1;
- return 63;
- }
+ if ((!TARGET_MOVE || GET_CODE (operands[0]) != MEM) || (GET_CODE (operands[1]) != MEM))
+ return 81;
+ }
x1 = XEXP (x0, 0);
- goto L567;
+ goto L671;
- L402:
+ L506:
x2 = XEXP (x1, 0);
if (general_operand (x2, DFmode))
{
ro[1] = x2;
if (TARGET_80387)
- return 75;
+ return 94;
}
- L406:
+ L510:
if (general_operand (x2, SFmode))
{
ro[1] = x2;
if (TARGET_80387)
- return 76;
+ return 95;
}
x1 = XEXP (x0, 0);
- goto L567;
+ goto L671;
- L568:
+ L672:
x1 = XEXP (x0, 1);
if (GET_MODE (x1) != XFmode)
{
x1 = XEXP (x0, 0);
- goto L1380;
+ goto L1546;
}
switch (GET_CODE (x1))
{
case FLOAT:
- goto L569;
+ goto L673;
case NEG:
- goto L820;
+ goto L986;
case ABS:
- goto L842;
+ goto L1008;
case SQRT:
- goto L864;
+ goto L1030;
}
x1 = XEXP (x0, 0);
- goto L1380;
+ goto L1546;
- L569:
+ L673:
x2 = XEXP (x1, 0);
if (general_operand (x2, DImode))
{
ro[1] = x2;
if (TARGET_80387)
- return 102;
+ return 121;
}
- L585:
+ L689:
if (general_operand (x2, SImode))
{
ro[1] = x2;
if (TARGET_80387)
- return 106;
+ return 125;
}
x1 = XEXP (x0, 0);
- goto L1380;
+ goto L1546;
- L820:
+ L986:
x2 = XEXP (x1, 0);
if (GET_MODE (x2) == XFmode && GET_CODE (x2) == FLOAT_EXTEND && 1)
- goto L821;
+ goto L987;
if (general_operand (x2, XFmode))
{
ro[1] = x2;
if (TARGET_80387)
- return 159;
+ return 180;
}
x1 = XEXP (x0, 0);
- goto L1380;
+ goto L1546;
- L821:
+ L987:
x3 = XEXP (x2, 0);
if (general_operand (x3, DFmode))
{
ro[1] = x3;
if (TARGET_80387)
- return 160;
+ return 181;
}
x1 = XEXP (x0, 0);
- goto L1380;
+ goto L1546;
- L842:
+ L1008:
x2 = XEXP (x1, 0);
if (GET_MODE (x2) == XFmode && GET_CODE (x2) == FLOAT_EXTEND && 1)
- goto L843;
+ goto L1009;
if (general_operand (x2, XFmode))
{
ro[1] = x2;
if (TARGET_80387)
- return 164;
+ return 185;
}
x1 = XEXP (x0, 0);
- goto L1380;
+ goto L1546;
- L843:
+ L1009:
x3 = XEXP (x2, 0);
if (general_operand (x3, DFmode))
{
ro[1] = x3;
if (TARGET_80387)
- return 165;
+ return 186;
}
x1 = XEXP (x0, 0);
- goto L1380;
+ goto L1546;
- L864:
+ L1030:
x2 = XEXP (x1, 0);
if (GET_MODE (x2) == XFmode && GET_CODE (x2) == FLOAT_EXTEND && 1)
- goto L865;
+ goto L1031;
if (general_operand (x2, XFmode))
{
ro[1] = x2;
- if (! TARGET_NO_FANCY_MATH_387 && TARGET_80387
+ if (! TARGET_NO_FANCY_MATH_387 && TARGET_80387
&& (TARGET_IEEE_FP || flag_fast_math) )
- return 169;
+ return 190;
}
x1 = XEXP (x0, 0);
- goto L1380;
+ goto L1546;
- L865:
+ L1031:
x3 = XEXP (x2, 0);
if (general_operand (x3, DFmode))
{
ro[1] = x3;
- if (! TARGET_NO_FANCY_MATH_387 && TARGET_80387
+ if (! TARGET_NO_FANCY_MATH_387 && TARGET_80387
&& (TARGET_IEEE_FP || flag_fast_math) )
- return 170;
+ return 191;
}
- L870:
+ L1036:
if (general_operand (x3, SFmode))
{
ro[1] = x3;
- if (! TARGET_NO_FANCY_MATH_387 && TARGET_80387
+ if (! TARGET_NO_FANCY_MATH_387 && TARGET_80387
&& (TARGET_IEEE_FP || flag_fast_math) )
- return 171;
+ return 192;
}
x1 = XEXP (x0, 0);
- goto L1380;
+ goto L1546;
- L359:
+ L455:
x1 = XEXP (x0, 1);
- if (general_operand (x1, DImode))
+ if (pnum_clobbers != 0 && general_operand (x1, DImode))
{
ro[1] = x1;
- return 64;
+ *pnum_clobbers = 2;
+ return 83;
}
x1 = XEXP (x0, 0);
- goto L361;
+ goto L465;
- L592:
+ L704:
x1 = XEXP (x0, 1);
switch (GET_MODE (x1))
{
@@ -3278,253 +3517,258 @@ recog_4 (x0, insn, pnum_clobbers)
switch (GET_CODE (x1))
{
case PLUS:
- goto L593;
+ goto L705;
case MINUS:
- goto L616;
+ goto L736;
case NEG:
- goto L787;
+ goto L953;
}
}
- if (general_operand (x1, DImode))
+ if (pnum_clobbers != 0 && general_operand (x1, DImode))
{
ro[1] = x1;
- return 65;
+ *pnum_clobbers = 2;
+ return 84;
}
x1 = XEXP (x0, 0);
- goto L376;
+ goto L480;
- L593:
+ L705:
x2 = XEXP (x1, 0);
if (general_operand (x2, DImode))
{
ro[1] = x2;
- goto L594;
+ goto L706;
}
x1 = XEXP (x0, 0);
- goto L376;
+ goto L480;
- L594:
+ L706:
x2 = XEXP (x1, 1);
- if (general_operand (x2, DImode))
+ if (pnum_clobbers != 0 && general_operand (x2, DImode))
{
ro[2] = x2;
- return 108;
+ *pnum_clobbers = 1;
+ return 127;
}
x1 = XEXP (x0, 0);
- goto L376;
+ goto L480;
- L616:
+ L736:
x2 = XEXP (x1, 0);
if (general_operand (x2, DImode))
{
ro[1] = x2;
- goto L617;
+ goto L737;
}
x1 = XEXP (x0, 0);
- goto L376;
+ goto L480;
- L617:
+ L737:
x2 = XEXP (x1, 1);
- if (general_operand (x2, DImode))
+ if (pnum_clobbers != 0 && general_operand (x2, DImode))
{
ro[2] = x2;
- return 116;
+ *pnum_clobbers = 1;
+ return 135;
}
x1 = XEXP (x0, 0);
- goto L376;
+ goto L480;
- L787:
+ L953:
x2 = XEXP (x1, 0);
if (general_operand (x2, DImode))
{
ro[1] = x2;
- return 152;
+ return 173;
}
x1 = XEXP (x0, 0);
- goto L376;
+ goto L480;
- L377:
+ L481:
x1 = XEXP (x0, 1);
if (GET_MODE (x1) != DImode)
{
x1 = XEXP (x0, 0);
- goto L1380;
+ goto L1546;
}
switch (GET_CODE (x1))
{
case ZERO_EXTEND:
- goto L378;
+ goto L482;
case SIGN_EXTEND:
- goto L382;
+ goto L486;
case MULT:
- goto L674;
+ goto L794;
case ASHIFT:
- goto L912;
+ goto L1078;
case ASHIFTRT:
- goto L940;
+ goto L1106;
case LSHIFTRT:
- goto L968;
+ goto L1134;
}
x1 = XEXP (x0, 0);
- goto L1380;
+ goto L1546;
- L378:
+ L482:
x2 = XEXP (x1, 0);
if (register_operand (x2, SImode))
{
ro[1] = x2;
- return 69;
+ return 88;
}
x1 = XEXP (x0, 0);
- goto L1380;
+ goto L1546;
- L382:
+ L486:
x2 = XEXP (x1, 0);
if (register_operand (x2, SImode))
{
ro[1] = x2;
- return 70;
+ return 89;
}
x1 = XEXP (x0, 0);
- goto L1380;
+ goto L1546;
- L674:
+ L794:
x2 = XEXP (x1, 0);
if (GET_MODE (x2) != DImode)
{
x1 = XEXP (x0, 0);
- goto L1380;
+ goto L1546;
}
switch (GET_CODE (x2))
{
case ZERO_EXTEND:
- goto L675;
+ goto L795;
case SIGN_EXTEND:
- goto L682;
+ goto L802;
}
x1 = XEXP (x0, 0);
- goto L1380;
+ goto L1546;
- L675:
+ L795:
x3 = XEXP (x2, 0);
if (register_operand (x3, SImode))
{
ro[1] = x3;
- goto L676;
+ goto L796;
}
x1 = XEXP (x0, 0);
- goto L1380;
+ goto L1546;
- L676:
+ L796:
x2 = XEXP (x1, 1);
if (GET_MODE (x2) == DImode && GET_CODE (x2) == ZERO_EXTEND && 1)
- goto L677;
+ goto L797;
x1 = XEXP (x0, 0);
- goto L1380;
+ goto L1546;
- L677:
+ L797:
x3 = XEXP (x2, 0);
if (nonimmediate_operand (x3, SImode))
{
ro[2] = x3;
- return 129;
- }
+ if (TARGET_WIDE_MULTIPLY)
+ return 148;
+ }
x1 = XEXP (x0, 0);
- goto L1380;
+ goto L1546;
- L682:
+ L802:
x3 = XEXP (x2, 0);
if (register_operand (x3, SImode))
{
ro[1] = x3;
- goto L683;
+ goto L803;
}
x1 = XEXP (x0, 0);
- goto L1380;
+ goto L1546;
- L683:
+ L803:
x2 = XEXP (x1, 1);
if (GET_MODE (x2) == DImode && GET_CODE (x2) == SIGN_EXTEND && 1)
- goto L684;
+ goto L804;
x1 = XEXP (x0, 0);
- goto L1380;
+ goto L1546;
- L684:
+ L804:
x3 = XEXP (x2, 0);
if (nonimmediate_operand (x3, SImode))
{
ro[2] = x3;
- return 130;
- }
+ if (TARGET_WIDE_MULTIPLY)
+ return 149;
+ }
x1 = XEXP (x0, 0);
- goto L1380;
+ goto L1546;
- L912:
+ L1078:
x2 = XEXP (x1, 0);
if (register_operand (x2, DImode))
{
ro[1] = x2;
- goto L913;
+ goto L1079;
}
x1 = XEXP (x0, 0);
- goto L1380;
+ goto L1546;
- L913:
+ L1079:
x2 = XEXP (x1, 1);
if (GET_CODE (x2) == CONST_INT && 1)
{
ro[2] = x2;
- return 182;
+ return 203;
}
x1 = XEXP (x0, 0);
- goto L1380;
+ goto L1546;
- L940:
+ L1106:
x2 = XEXP (x1, 0);
if (register_operand (x2, DImode))
{
ro[1] = x2;
- goto L941;
+ goto L1107;
}
x1 = XEXP (x0, 0);
- goto L1380;
+ goto L1546;
- L941:
+ L1107:
x2 = XEXP (x1, 1);
if (GET_CODE (x2) == CONST_INT && 1)
{
ro[2] = x2;
- return 188;
+ return 209;
}
x1 = XEXP (x0, 0);
- goto L1380;
+ goto L1546;
- L968:
+ L1134:
x2 = XEXP (x1, 0);
if (register_operand (x2, DImode))
{
ro[1] = x2;
- goto L969;
+ goto L1135;
}
x1 = XEXP (x0, 0);
- goto L1380;
+ goto L1546;
- L969:
+ L1135:
x2 = XEXP (x1, 1);
if (GET_CODE (x2) == CONST_INT && 1)
{
ro[2] = x2;
- return 194;
+ return 215;
}
x1 = XEXP (x0, 0);
- goto L1380;
+ goto L1546;
L2:
tem = recog_2 (x0, insn, pnum_clobbers);
if (tem >= 0) return tem;
x1 = XEXP (x0, 0);
- goto L1380;
+ goto L1546;
- L313:
+ L320:
x2 = XEXP (x1, 0);
switch (GET_MODE (x2))
{
@@ -3532,248 +3776,250 @@ recog_4 (x0, insn, pnum_clobbers)
if (general_operand (x2, HImode))
{
ro[0] = x2;
- goto L314;
+ goto L321;
}
break;
case QImode:
if (general_operand (x2, QImode))
{
ro[0] = x2;
- goto L324;
+ goto L337;
}
}
- goto L1380;
+ goto L1546;
- L314:
+ L321:
x1 = XEXP (x0, 1);
if (general_operand (x1, HImode))
{
ro[1] = x1;
- return 52;
- }
+ if ((!TARGET_MOVE || GET_CODE (operands[0]) != MEM) || (GET_CODE (operands[1]) != MEM))
+ return 57;
+ }
x1 = XEXP (x0, 0);
- goto L1380;
+ goto L1546;
- L324:
+ L337:
x1 = XEXP (x0, 1);
if (general_operand (x1, QImode))
{
ro[1] = x1;
- return 55;
- }
+ if ((!TARGET_MOVE || GET_CODE (operands[0]) != MEM) || (GET_CODE (operands[1]) != MEM))
+ return 64;
+ }
x1 = XEXP (x0, 0);
- goto L1380;
+ goto L1546;
- L1314:
+ L1480:
x1 = XEXP (x0, 1);
switch (GET_CODE (x1))
{
case MINUS:
if (GET_MODE (x1) == SImode && 1)
- goto L1315;
+ goto L1481;
break;
case IF_THEN_ELSE:
- goto L1114;
+ goto L1280;
case LABEL_REF:
- goto L1294;
+ goto L1460;
}
- L1297:
+ L1463:
if (general_operand (x1, SImode))
{
ro[0] = x1;
- return 262;
+ return 283;
}
x1 = XEXP (x0, 0);
- goto L1380;
+ goto L1546;
- L1315:
+ L1481:
x2 = XEXP (x1, 0);
if (GET_MODE (x2) == SImode && GET_CODE (x2) == REG && XINT (x2, 0) == 3 && 1)
- goto L1316;
+ goto L1482;
x1 = XEXP (x0, 0);
- goto L1380;
+ goto L1546;
- L1316:
+ L1482:
x2 = XEXP (x1, 1);
if (GET_MODE (x2) == SImode && GET_CODE (x2) == MEM && 1)
- goto L1317;
+ goto L1483;
x1 = XEXP (x0, 0);
- goto L1380;
+ goto L1546;
- L1317:
+ L1483:
x3 = XEXP (x2, 0);
if (GET_MODE (x3) == SImode && GET_CODE (x3) == PLUS && 1)
- goto L1318;
+ goto L1484;
x1 = XEXP (x0, 0);
- goto L1380;
+ goto L1546;
- L1318:
+ L1484:
x4 = XEXP (x3, 0);
if (GET_MODE (x4) == SImode && GET_CODE (x4) == MULT && 1)
- goto L1319;
+ goto L1485;
x1 = XEXP (x0, 0);
- goto L1380;
+ goto L1546;
- L1319:
+ L1485:
x5 = XEXP (x4, 0);
if (register_operand (x5, SImode))
{
ro[0] = x5;
- goto L1320;
+ goto L1486;
}
x1 = XEXP (x0, 0);
- goto L1380;
+ goto L1546;
- L1320:
+ L1486:
x5 = XEXP (x4, 1);
if (GET_CODE (x5) == CONST_INT && XWINT (x5, 0) == 4 && 1)
- goto L1321;
+ goto L1487;
x1 = XEXP (x0, 0);
- goto L1380;
+ goto L1546;
- L1321:
+ L1487:
x4 = XEXP (x3, 1);
if (GET_CODE (x4) == LABEL_REF && 1)
- goto L1322;
+ goto L1488;
x1 = XEXP (x0, 0);
- goto L1380;
+ goto L1546;
- L1322:
+ L1488:
x5 = XEXP (x4, 0);
if (pnum_clobbers != 0 && 1)
{
ro[1] = x5;
*pnum_clobbers = 1;
- return 264;
+ return 285;
}
x1 = XEXP (x0, 0);
- goto L1380;
- L1114:
+ goto L1546;
+ L1280:
tem = recog_3 (x0, insn, pnum_clobbers);
if (tem >= 0) return tem;
x1 = XEXP (x0, 0);
- goto L1380;
+ goto L1546;
- L1294:
+ L1460:
x2 = XEXP (x1, 0);
ro[0] = x2;
- return 261;
+ return 282;
- L1381:
+ L1547:
x1 = XEXP (x0, 1);
if (GET_CODE (x1) == CALL && 1)
- goto L1382;
+ goto L1548;
x1 = XEXP (x0, 0);
- goto L1460;
+ goto L1613;
- L1382:
+ L1548:
x2 = XEXP (x1, 0);
if (call_insn_operand (x2, QImode))
{
ro[1] = x2;
- goto L1383;
+ goto L1549;
}
- L1387:
+ L1553:
if (GET_MODE (x2) == QImode && GET_CODE (x2) == MEM && 1)
- goto L1388;
+ goto L1554;
x1 = XEXP (x0, 0);
- goto L1460;
+ goto L1613;
- L1383:
+ L1549:
x2 = XEXP (x1, 1);
if (general_operand (x2, SImode))
{
ro[2] = x2;
- return 276;
+ return 297;
}
x2 = XEXP (x1, 0);
- goto L1387;
+ goto L1553;
- L1388:
+ L1554:
x3 = XEXP (x2, 0);
if (symbolic_operand (x3, SImode))
{
ro[1] = x3;
- goto L1389;
+ goto L1555;
}
x1 = XEXP (x0, 0);
- goto L1460;
+ goto L1613;
- L1389:
+ L1555:
x2 = XEXP (x1, 1);
if (general_operand (x2, SImode))
{
ro[2] = x2;
if (!HALF_PIC_P ())
- return 277;
+ return 298;
}
x1 = XEXP (x0, 0);
- goto L1460;
+ goto L1613;
- L1461:
+ L1614:
x1 = XEXP (x0, 1);
if (GET_MODE (x1) == SImode && GET_CODE (x1) == PLUS && 1)
- goto L1462;
+ goto L1615;
goto ret0;
- L1462:
+ L1615:
x2 = XEXP (x1, 0);
if (GET_MODE (x2) == SImode && GET_CODE (x2) == FFS && 1)
- goto L1463;
+ goto L1616;
goto ret0;
- L1463:
+ L1616:
x3 = XEXP (x2, 0);
if (general_operand (x3, SImode))
{
ro[1] = x3;
- goto L1464;
+ goto L1617;
}
goto ret0;
- L1464:
+ L1617:
x2 = XEXP (x1, 1);
if (GET_CODE (x2) == CONST_INT && XWINT (x2, 0) == -1 && 1)
- return 291;
+ return 309;
goto ret0;
- L1467:
+ L1620:
x1 = XEXP (x0, 1);
if (GET_MODE (x1) == HImode && GET_CODE (x1) == PLUS && 1)
- goto L1468;
+ goto L1621;
goto ret0;
- L1468:
+ L1621:
x2 = XEXP (x1, 0);
if (GET_MODE (x2) == HImode && GET_CODE (x2) == FFS && 1)
- goto L1469;
+ goto L1622;
goto ret0;
- L1469:
+ L1622:
x3 = XEXP (x2, 0);
if (general_operand (x3, SImode))
{
ro[1] = x3;
- goto L1470;
+ goto L1623;
}
goto ret0;
- L1470:
+ L1623:
x2 = XEXP (x1, 1);
if (GET_CODE (x2) == CONST_INT && XWINT (x2, 0) == -1 && 1)
- return 293;
+ return 311;
goto ret0;
- L1473:
+ L1626:
x1 = XEXP (x0, 1);
if (binary_387_op (x1, DFmode))
{
ro[3] = x1;
- goto L1479;
+ goto L1632;
}
goto ret0;
- L1479:
+ L1632:
x2 = XEXP (x1, 0);
switch (GET_MODE (x2))
{
@@ -3781,119 +4027,119 @@ recog_4 (x0, insn, pnum_clobbers)
switch (GET_CODE (x2))
{
case FLOAT:
- goto L1480;
+ goto L1633;
case FLOAT_EXTEND:
- goto L1515;
+ goto L1668;
case SUBREG:
case REG:
case MEM:
if (nonimmediate_operand (x2, DFmode))
{
ro[1] = x2;
- goto L1475;
+ goto L1628;
}
}
}
- L1520:
+ L1673:
if (general_operand (x2, DFmode))
{
ro[1] = x2;
- goto L1521;
+ goto L1674;
}
goto ret0;
- L1480:
+ L1633:
x3 = XEXP (x2, 0);
if (general_operand (x3, SImode))
{
ro[1] = x3;
- goto L1481;
+ goto L1634;
}
goto ret0;
- L1481:
+ L1634:
x2 = XEXP (x1, 1);
if (general_operand (x2, DFmode))
{
ro[2] = x2;
if (TARGET_80387)
- return 295;
+ return 313;
}
goto ret0;
- L1515:
+ L1668:
x3 = XEXP (x2, 0);
if (general_operand (x3, SFmode))
{
ro[1] = x3;
- goto L1516;
+ goto L1669;
}
goto ret0;
- L1516:
+ L1669:
x2 = XEXP (x1, 1);
if (general_operand (x2, DFmode))
{
ro[2] = x2;
if (TARGET_80387)
- return 301;
+ return 319;
}
goto ret0;
- L1475:
+ L1628:
x2 = XEXP (x1, 1);
if (nonimmediate_operand (x2, DFmode))
{
ro[2] = x2;
if (TARGET_80387)
- return 294;
+ return 312;
}
x2 = XEXP (x1, 0);
- goto L1520;
+ goto L1673;
- L1521:
+ L1674:
x2 = XEXP (x1, 1);
if (GET_MODE (x2) != DFmode)
goto ret0;
switch (GET_CODE (x2))
{
case FLOAT:
- goto L1522;
+ goto L1675;
case FLOAT_EXTEND:
- goto L1528;
+ goto L1681;
}
goto ret0;
- L1522:
+ L1675:
x3 = XEXP (x2, 0);
if (general_operand (x3, SImode))
{
ro[2] = x3;
if (TARGET_80387)
- return 302;
+ return 320;
}
goto ret0;
- L1528:
+ L1681:
x3 = XEXP (x2, 0);
if (general_operand (x3, SFmode))
{
ro[2] = x3;
if (TARGET_80387)
- return 303;
+ return 321;
}
goto ret0;
- L1484:
+ L1637:
x1 = XEXP (x0, 1);
if (binary_387_op (x1, XFmode))
{
ro[3] = x1;
- goto L1490;
+ goto L1643;
}
goto ret0;
- L1490:
+ L1643:
x2 = XEXP (x1, 0);
switch (GET_MODE (x2))
{
@@ -3901,182 +4147,182 @@ recog_4 (x0, insn, pnum_clobbers)
switch (GET_CODE (x2))
{
case FLOAT:
- goto L1491;
+ goto L1644;
case FLOAT_EXTEND:
- goto L1497;
+ goto L1650;
case SUBREG:
case REG:
case MEM:
if (nonimmediate_operand (x2, XFmode))
{
ro[1] = x2;
- goto L1486;
+ goto L1639;
}
}
}
- L1502:
+ L1655:
if (general_operand (x2, XFmode))
{
ro[1] = x2;
- goto L1503;
+ goto L1656;
}
goto ret0;
- L1491:
+ L1644:
x3 = XEXP (x2, 0);
if (general_operand (x3, SImode))
{
ro[1] = x3;
- goto L1492;
+ goto L1645;
}
goto ret0;
- L1492:
+ L1645:
x2 = XEXP (x1, 1);
if (general_operand (x2, XFmode))
{
ro[2] = x2;
if (TARGET_80387)
- return 297;
+ return 315;
}
goto ret0;
- L1497:
+ L1650:
x3 = XEXP (x2, 0);
if (general_operand (x3, SFmode))
{
ro[1] = x3;
- goto L1498;
+ goto L1651;
}
goto ret0;
- L1498:
+ L1651:
x2 = XEXP (x1, 1);
if (general_operand (x2, XFmode))
{
ro[2] = x2;
if (TARGET_80387)
- return 298;
+ return 316;
}
goto ret0;
- L1486:
+ L1639:
x2 = XEXP (x1, 1);
if (nonimmediate_operand (x2, XFmode))
{
ro[2] = x2;
if (TARGET_80387)
- return 296;
+ return 314;
}
x2 = XEXP (x1, 0);
- goto L1502;
+ goto L1655;
- L1503:
+ L1656:
x2 = XEXP (x1, 1);
if (GET_MODE (x2) != XFmode)
goto ret0;
switch (GET_CODE (x2))
{
case FLOAT:
- goto L1504;
+ goto L1657;
case FLOAT_EXTEND:
- goto L1510;
+ goto L1663;
}
goto ret0;
- L1504:
+ L1657:
x3 = XEXP (x2, 0);
if (general_operand (x3, SImode))
{
ro[2] = x3;
if (TARGET_80387)
- return 299;
+ return 317;
}
goto ret0;
- L1510:
+ L1663:
x3 = XEXP (x2, 0);
if (general_operand (x3, SFmode))
{
ro[2] = x3;
if (TARGET_80387)
- return 300;
+ return 318;
}
goto ret0;
- L1531:
+ L1684:
x1 = XEXP (x0, 1);
if (binary_387_op (x1, SFmode))
{
ro[3] = x1;
- goto L1537;
+ goto L1690;
}
goto ret0;
- L1537:
+ L1690:
x2 = XEXP (x1, 0);
switch (GET_MODE (x2))
{
case SFmode:
if (GET_CODE (x2) == FLOAT && 1)
- goto L1538;
+ goto L1691;
if (nonimmediate_operand (x2, SFmode))
{
ro[1] = x2;
- goto L1533;
+ goto L1686;
}
}
- L1543:
+ L1696:
if (general_operand (x2, SFmode))
{
ro[1] = x2;
- goto L1544;
+ goto L1697;
}
goto ret0;
- L1538:
+ L1691:
x3 = XEXP (x2, 0);
if (general_operand (x3, SImode))
{
ro[1] = x3;
- goto L1539;
+ goto L1692;
}
goto ret0;
- L1539:
+ L1692:
x2 = XEXP (x1, 1);
if (general_operand (x2, SFmode))
{
ro[2] = x2;
if (TARGET_80387)
- return 305;
+ return 323;
}
goto ret0;
- L1533:
+ L1686:
x2 = XEXP (x1, 1);
if (nonimmediate_operand (x2, SFmode))
{
ro[2] = x2;
if (TARGET_80387)
- return 304;
+ return 322;
}
x2 = XEXP (x1, 0);
- goto L1543;
+ goto L1696;
- L1544:
+ L1697:
x2 = XEXP (x1, 1);
if (GET_MODE (x2) == SFmode && GET_CODE (x2) == FLOAT && 1)
- goto L1545;
+ goto L1698;
goto ret0;
- L1545:
+ L1698:
x3 = XEXP (x2, 0);
if (general_operand (x3, SImode))
{
ro[2] = x3;
if (TARGET_80387)
- return 306;
+ return 324;
}
goto ret0;
ret0: return -1;
@@ -4587,46 +4833,70 @@ recog_6 (x0, insn, pnum_clobbers)
x2 = XEXP (x1, 0);
switch (GET_MODE (x2))
{
+ case SFmode:
+ if (GET_CODE (x2) == MEM && push_operand (x2, SFmode))
+ {
+ ro[0] = x2;
+ goto L344;
+ }
+ L354:
+ if (memory_operand (x2, SFmode))
+ {
+ ro[0] = x2;
+ goto L355;
+ }
+ L366:
+ if (register_operand (x2, SFmode))
+ {
+ ro[0] = x2;
+ goto L367;
+ }
+ L513:
+ if (nonimmediate_operand (x2, SFmode))
+ {
+ ro[0] = x2;
+ goto L514;
+ }
+ break;
case DFmode:
if (register_operand (x2, DFmode))
{
ro[0] = x2;
- goto L337;
+ goto L404;
}
break;
case XFmode:
if (register_operand (x2, XFmode))
{
ro[0] = x2;
- goto L350;
+ goto L441;
}
break;
- case SFmode:
- if (nonimmediate_operand (x2, SFmode))
+ case DImode:
+ if (general_operand (x2, DImode))
{
ro[0] = x2;
- goto L410;
+ goto L697;
+ }
+ L1082:
+ if (register_operand (x2, DImode))
+ {
+ ro[0] = x2;
+ goto L1083;
}
break;
case SImode:
if (register_operand (x2, SImode))
{
ro[0] = x2;
- goto L698;
+ goto L808;
}
break;
case HImode:
if (register_operand (x2, HImode))
{
ro[0] = x2;
- goto L709;
- }
- break;
- case DImode:
- if (register_operand (x2, DImode))
- {
- ro[0] = x2;
- goto L917;
+ goto L875;
}
}
switch (GET_CODE (x2))
@@ -4634,536 +4904,864 @@ recog_6 (x0, insn, pnum_clobbers)
case CC0:
goto L12;
case PC:
- goto L1301;
+ goto L1467;
}
- L1358:
+ L1524:
ro[0] = x2;
- goto L1359;
- L1548:
+ goto L1525;
+ L1701:
if (register_operand (x2, SImode))
{
ro[0] = x2;
- goto L1549;
+ goto L1702;
}
goto ret0;
- L337:
+ L344:
x2 = XEXP (x1, 1);
- if (register_operand (x2, DFmode))
+ if (general_operand (x2, SFmode))
{
ro[1] = x2;
- goto L338;
+ goto L345;
}
x2 = XEXP (x1, 0);
- goto L1358;
+ goto L354;
- L338:
+ L345:
x1 = XVECEXP (x0, 0, 1);
- if (GET_CODE (x1) == SET && 1)
- goto L339;
+ if (GET_CODE (x1) == CLOBBER && 1)
+ goto L346;
x1 = XVECEXP (x0, 0, 0);
x2 = XEXP (x1, 0);
- goto L1358;
+ goto L354;
- L339:
+ L346:
x2 = XEXP (x1, 0);
- if (rtx_equal_p (x2, ro[1]) && 1)
- goto L340;
+ if (scratch_operand (x2, SImode))
+ {
+ ro[2] = x2;
+ return 67;
+ }
x1 = XVECEXP (x0, 0, 0);
x2 = XEXP (x1, 0);
- goto L1358;
+ goto L354;
- L340:
+ L355:
x2 = XEXP (x1, 1);
- if (rtx_equal_p (x2, ro[0]) && 1)
- return 59;
+ if (memory_operand (x2, SFmode))
+ {
+ ro[1] = x2;
+ goto L356;
+ }
+ x2 = XEXP (x1, 0);
+ goto L366;
+
+ L356:
+ x1 = XVECEXP (x0, 0, 1);
+ if (GET_CODE (x1) == CLOBBER && 1)
+ goto L357;
x1 = XVECEXP (x0, 0, 0);
x2 = XEXP (x1, 0);
- goto L1358;
+ goto L366;
- L350:
+ L357:
+ x2 = XEXP (x1, 0);
+ if (scratch_operand (x2, SImode))
+ {
+ ro[2] = x2;
+ return 68;
+ }
+ x1 = XVECEXP (x0, 0, 0);
+ x2 = XEXP (x1, 0);
+ goto L366;
+
+ L367:
x2 = XEXP (x1, 1);
- if (register_operand (x2, XFmode))
+ if (register_operand (x2, SFmode))
{
ro[1] = x2;
- goto L351;
+ goto L368;
}
x2 = XEXP (x1, 0);
- goto L1358;
+ goto L513;
- L351:
+ L368:
x1 = XVECEXP (x0, 0, 1);
if (GET_CODE (x1) == SET && 1)
- goto L352;
+ goto L369;
x1 = XVECEXP (x0, 0, 0);
x2 = XEXP (x1, 0);
- goto L1358;
+ goto L513;
- L352:
+ L369:
x2 = XEXP (x1, 0);
if (rtx_equal_p (x2, ro[1]) && 1)
- goto L353;
+ goto L370;
x1 = XVECEXP (x0, 0, 0);
x2 = XEXP (x1, 0);
- goto L1358;
+ goto L513;
- L353:
+ L370:
x2 = XEXP (x1, 1);
if (rtx_equal_p (x2, ro[0]) && 1)
- return 62;
+ return 70;
x1 = XVECEXP (x0, 0, 0);
x2 = XEXP (x1, 0);
- goto L1358;
+ goto L513;
- L410:
+ L514:
x2 = XEXP (x1, 1);
if (GET_MODE (x2) == SFmode && GET_CODE (x2) == FLOAT_TRUNCATE && 1)
- goto L411;
+ goto L515;
x2 = XEXP (x1, 0);
- goto L1358;
+ goto L1524;
- L411:
+ L515:
x3 = XEXP (x2, 0);
if (register_operand (x3, DFmode))
{
ro[1] = x3;
- goto L412;
+ goto L516;
}
x2 = XEXP (x1, 0);
- goto L1358;
+ goto L1524;
- L412:
+ L516:
x1 = XVECEXP (x0, 0, 1);
if (GET_CODE (x1) == CLOBBER && 1)
- goto L413;
+ goto L517;
x1 = XVECEXP (x0, 0, 0);
x2 = XEXP (x1, 0);
- goto L1358;
+ goto L1524;
- L413:
+ L517:
x2 = XEXP (x1, 0);
if (memory_operand (x2, SFmode))
{
ro[2] = x2;
if (TARGET_80387)
- return 78;
+ return 97;
}
x1 = XVECEXP (x0, 0, 0);
x2 = XEXP (x1, 0);
- goto L1358;
+ goto L1524;
- L698:
+ L404:
x2 = XEXP (x1, 1);
- if (GET_MODE (x2) != SImode)
+ if (register_operand (x2, DFmode))
+ {
+ ro[1] = x2;
+ goto L405;
+ }
+ x2 = XEXP (x1, 0);
+ goto L1524;
+
+ L405:
+ x1 = XVECEXP (x0, 0, 1);
+ if (GET_CODE (x1) == SET && 1)
+ goto L406;
+ x1 = XVECEXP (x0, 0, 0);
+ x2 = XEXP (x1, 0);
+ goto L1524;
+
+ L406:
+ x2 = XEXP (x1, 0);
+ if (rtx_equal_p (x2, ro[1]) && 1)
+ goto L407;
+ x1 = XVECEXP (x0, 0, 0);
+ x2 = XEXP (x1, 0);
+ goto L1524;
+
+ L407:
+ x2 = XEXP (x1, 1);
+ if (rtx_equal_p (x2, ro[0]) && 1)
+ return 76;
+ x1 = XVECEXP (x0, 0, 0);
+ x2 = XEXP (x1, 0);
+ goto L1524;
+
+ L441:
+ x2 = XEXP (x1, 1);
+ if (register_operand (x2, XFmode))
+ {
+ ro[1] = x2;
+ goto L442;
+ }
+ x2 = XEXP (x1, 0);
+ goto L1524;
+
+ L442:
+ x1 = XVECEXP (x0, 0, 1);
+ if (GET_CODE (x1) == SET && 1)
+ goto L443;
+ x1 = XVECEXP (x0, 0, 0);
+ x2 = XEXP (x1, 0);
+ goto L1524;
+
+ L443:
+ x2 = XEXP (x1, 0);
+ if (rtx_equal_p (x2, ro[1]) && 1)
+ goto L444;
+ x1 = XVECEXP (x0, 0, 0);
+ x2 = XEXP (x1, 0);
+ goto L1524;
+
+ L444:
+ x2 = XEXP (x1, 1);
+ if (rtx_equal_p (x2, ro[0]) && 1)
+ return 82;
+ x1 = XVECEXP (x0, 0, 0);
+ x2 = XEXP (x1, 0);
+ goto L1524;
+
+ L697:
+ x2 = XEXP (x1, 1);
+ if (GET_MODE (x2) != DImode)
{
x2 = XEXP (x1, 0);
- goto L1358;
+ goto L1082;
}
switch (GET_CODE (x2))
{
- case DIV:
- goto L699;
- case UDIV:
- goto L721;
+ case PLUS:
+ goto L698;
+ case MINUS:
+ goto L729;
}
x2 = XEXP (x1, 0);
- goto L1358;
+ goto L1082;
- L699:
+ L698:
x3 = XEXP (x2, 0);
- if (register_operand (x3, SImode))
+ if (general_operand (x3, DImode))
{
ro[1] = x3;
+ goto L699;
+ }
+ x2 = XEXP (x1, 0);
+ goto L1082;
+
+ L699:
+ x3 = XEXP (x2, 1);
+ if (general_operand (x3, DImode))
+ {
+ ro[2] = x3;
goto L700;
}
x2 = XEXP (x1, 0);
- goto L1358;
+ goto L1082;
L700:
+ x1 = XVECEXP (x0, 0, 1);
+ if (GET_CODE (x1) == CLOBBER && 1)
+ goto L701;
+ x1 = XVECEXP (x0, 0, 0);
+ x2 = XEXP (x1, 0);
+ goto L1082;
+
+ L701:
+ x2 = XEXP (x1, 0);
+ if (scratch_operand (x2, SImode))
+ {
+ ro[3] = x2;
+ return 127;
+ }
+ x1 = XVECEXP (x0, 0, 0);
+ x2 = XEXP (x1, 0);
+ goto L1082;
+
+ L729:
+ x3 = XEXP (x2, 0);
+ if (general_operand (x3, DImode))
+ {
+ ro[1] = x3;
+ goto L730;
+ }
+ x2 = XEXP (x1, 0);
+ goto L1082;
+
+ L730:
x3 = XEXP (x2, 1);
- if (general_operand (x3, SImode))
+ if (general_operand (x3, DImode))
{
ro[2] = x3;
- goto L701;
+ goto L731;
}
x2 = XEXP (x1, 0);
- goto L1358;
+ goto L1082;
- L701:
+ L731:
x1 = XVECEXP (x0, 0, 1);
- if (GET_CODE (x1) == SET && 1)
- goto L702;
+ if (GET_CODE (x1) == CLOBBER && 1)
+ goto L732;
x1 = XVECEXP (x0, 0, 0);
x2 = XEXP (x1, 0);
- goto L1358;
+ goto L1082;
- L702:
+ L732:
x2 = XEXP (x1, 0);
- if (register_operand (x2, SImode))
+ if (scratch_operand (x2, SImode))
{
ro[3] = x2;
- goto L703;
+ return 135;
}
x1 = XVECEXP (x0, 0, 0);
x2 = XEXP (x1, 0);
- goto L1358;
+ goto L1082;
- L703:
+ L1083:
x2 = XEXP (x1, 1);
- if (GET_MODE (x2) == SImode && GET_CODE (x2) == MOD && 1)
- goto L704;
- x1 = XVECEXP (x0, 0, 0);
+ if (GET_MODE (x2) != DImode)
+ {
+ x2 = XEXP (x1, 0);
+ goto L1524;
+ }
+ switch (GET_CODE (x2))
+ {
+ case ASHIFT:
+ goto L1084;
+ case ASHIFTRT:
+ goto L1112;
+ case LSHIFTRT:
+ goto L1140;
+ }
x2 = XEXP (x1, 0);
- goto L1358;
+ goto L1524;
- L704:
+ L1084:
x3 = XEXP (x2, 0);
- if (rtx_equal_p (x3, ro[1]) && 1)
- goto L705;
- x1 = XVECEXP (x0, 0, 0);
+ if (register_operand (x3, DImode))
+ {
+ ro[1] = x3;
+ goto L1085;
+ }
x2 = XEXP (x1, 0);
- goto L1358;
+ goto L1524;
- L705:
+ L1085:
x3 = XEXP (x2, 1);
- if (rtx_equal_p (x3, ro[2]) && 1)
- return 139;
+ if (register_operand (x3, QImode))
+ {
+ ro[2] = x3;
+ goto L1086;
+ }
+ x2 = XEXP (x1, 0);
+ goto L1524;
+
+ L1086:
+ x1 = XVECEXP (x0, 0, 1);
+ if (GET_CODE (x1) == CLOBBER && 1)
+ goto L1087;
x1 = XVECEXP (x0, 0, 0);
x2 = XEXP (x1, 0);
- goto L1358;
+ goto L1524;
- L721:
+ L1087:
+ x2 = XEXP (x1, 0);
+ if (rtx_equal_p (x2, ro[2]) && 1)
+ return 204;
+ x1 = XVECEXP (x0, 0, 0);
+ x2 = XEXP (x1, 0);
+ goto L1524;
+
+ L1112:
x3 = XEXP (x2, 0);
- if (register_operand (x3, SImode))
+ if (register_operand (x3, DImode))
{
ro[1] = x3;
- goto L722;
+ goto L1113;
}
x2 = XEXP (x1, 0);
- goto L1358;
+ goto L1524;
- L722:
+ L1113:
x3 = XEXP (x2, 1);
- if (general_operand (x3, SImode))
+ if (register_operand (x3, QImode))
{
ro[2] = x3;
- goto L723;
+ goto L1114;
}
x2 = XEXP (x1, 0);
- goto L1358;
+ goto L1524;
- L723:
+ L1114:
x1 = XVECEXP (x0, 0, 1);
- if (GET_CODE (x1) == SET && 1)
- goto L724;
+ if (GET_CODE (x1) == CLOBBER && 1)
+ goto L1115;
x1 = XVECEXP (x0, 0, 0);
x2 = XEXP (x1, 0);
- goto L1358;
+ goto L1524;
- L724:
+ L1115:
x2 = XEXP (x1, 0);
- if (register_operand (x2, SImode))
+ if (rtx_equal_p (x2, ro[2]) && 1)
+ return 210;
+ x1 = XVECEXP (x0, 0, 0);
+ x2 = XEXP (x1, 0);
+ goto L1524;
+
+ L1140:
+ x3 = XEXP (x2, 0);
+ if (register_operand (x3, DImode))
{
- ro[3] = x2;
- goto L725;
+ ro[1] = x3;
+ goto L1141;
}
- x1 = XVECEXP (x0, 0, 0);
x2 = XEXP (x1, 0);
- goto L1358;
+ goto L1524;
- L725:
- x2 = XEXP (x1, 1);
- if (GET_MODE (x2) == SImode && GET_CODE (x2) == UMOD && 1)
- goto L726;
- x1 = XVECEXP (x0, 0, 0);
+ L1141:
+ x3 = XEXP (x2, 1);
+ if (register_operand (x3, QImode))
+ {
+ ro[2] = x3;
+ goto L1142;
+ }
x2 = XEXP (x1, 0);
- goto L1358;
+ goto L1524;
- L726:
- x3 = XEXP (x2, 0);
- if (rtx_equal_p (x3, ro[1]) && 1)
- goto L727;
+ L1142:
+ x1 = XVECEXP (x0, 0, 1);
+ if (GET_CODE (x1) == CLOBBER && 1)
+ goto L1143;
x1 = XVECEXP (x0, 0, 0);
x2 = XEXP (x1, 0);
- goto L1358;
+ goto L1524;
- L727:
- x3 = XEXP (x2, 1);
- if (rtx_equal_p (x3, ro[2]) && 1)
- return 141;
+ L1143:
+ x2 = XEXP (x1, 0);
+ if (rtx_equal_p (x2, ro[2]) && 1)
+ return 216;
x1 = XVECEXP (x0, 0, 0);
x2 = XEXP (x1, 0);
- goto L1358;
+ goto L1524;
- L709:
+ L808:
x2 = XEXP (x1, 1);
- if (GET_MODE (x2) != HImode)
+ if (GET_MODE (x2) != SImode)
{
x2 = XEXP (x1, 0);
- goto L1358;
+ goto L1524;
}
switch (GET_CODE (x2))
{
+ case TRUNCATE:
+ goto L809;
case DIV:
- goto L710;
+ goto L865;
case UDIV:
- goto L732;
+ goto L887;
}
x2 = XEXP (x1, 0);
- goto L1358;
+ goto L1524;
- L710:
+ L809:
x3 = XEXP (x2, 0);
- if (register_operand (x3, HImode))
+ if (GET_MODE (x3) == DImode && GET_CODE (x3) == LSHIFTRT && 1)
+ goto L810;
+ x2 = XEXP (x1, 0);
+ goto L1524;
+
+ L810:
+ x4 = XEXP (x3, 0);
+ if (GET_MODE (x4) == DImode && GET_CODE (x4) == MULT && 1)
+ goto L811;
+ x2 = XEXP (x1, 0);
+ goto L1524;
+
+ L811:
+ x5 = XEXP (x4, 0);
+ if (GET_MODE (x5) != DImode)
+ {
+ x2 = XEXP (x1, 0);
+ goto L1524;
+ }
+ switch (GET_CODE (x5))
+ {
+ case ZERO_EXTEND:
+ goto L812;
+ case SIGN_EXTEND:
+ goto L835;
+ }
+ x2 = XEXP (x1, 0);
+ goto L1524;
+
+ L812:
+ x6 = XEXP (x5, 0);
+ if (register_operand (x6, SImode))
+ {
+ ro[1] = x6;
+ goto L813;
+ }
+ x2 = XEXP (x1, 0);
+ goto L1524;
+
+ L813:
+ x5 = XEXP (x4, 1);
+ if (GET_MODE (x5) == DImode && GET_CODE (x5) == ZERO_EXTEND && 1)
+ goto L814;
+ x2 = XEXP (x1, 0);
+ goto L1524;
+
+ L814:
+ x6 = XEXP (x5, 0);
+ if (nonimmediate_operand (x6, SImode))
+ {
+ ro[2] = x6;
+ goto L815;
+ }
+ x2 = XEXP (x1, 0);
+ goto L1524;
+
+ L815:
+ x4 = XEXP (x3, 1);
+ if (GET_CODE (x4) == CONST_INT && XWINT (x4, 0) == 32 && 1)
+ goto L816;
+ x2 = XEXP (x1, 0);
+ goto L1524;
+
+ L816:
+ x1 = XVECEXP (x0, 0, 1);
+ if (GET_CODE (x1) == CLOBBER && 1)
+ goto L817;
+ x1 = XVECEXP (x0, 0, 0);
+ x2 = XEXP (x1, 0);
+ goto L1524;
+
+ L817:
+ x2 = XEXP (x1, 0);
+ if (scratch_operand (x2, SImode))
+ {
+ ro[3] = x2;
+ if (TARGET_WIDE_MULTIPLY)
+ return 150;
+ }
+ x1 = XVECEXP (x0, 0, 0);
+ x2 = XEXP (x1, 0);
+ goto L1524;
+
+ L835:
+ x6 = XEXP (x5, 0);
+ if (register_operand (x6, SImode))
+ {
+ ro[1] = x6;
+ goto L836;
+ }
+ x2 = XEXP (x1, 0);
+ goto L1524;
+
+ L836:
+ x5 = XEXP (x4, 1);
+ if (GET_MODE (x5) == DImode && GET_CODE (x5) == SIGN_EXTEND && 1)
+ goto L837;
+ x2 = XEXP (x1, 0);
+ goto L1524;
+
+ L837:
+ x6 = XEXP (x5, 0);
+ if (nonimmediate_operand (x6, SImode))
+ {
+ ro[2] = x6;
+ goto L838;
+ }
+ x2 = XEXP (x1, 0);
+ goto L1524;
+
+ L838:
+ x4 = XEXP (x3, 1);
+ if (GET_CODE (x4) == CONST_INT && XWINT (x4, 0) == 32 && 1)
+ goto L839;
+ x2 = XEXP (x1, 0);
+ goto L1524;
+
+ L839:
+ x1 = XVECEXP (x0, 0, 1);
+ if (GET_CODE (x1) == CLOBBER && 1)
+ goto L840;
+ x1 = XVECEXP (x0, 0, 0);
+ x2 = XEXP (x1, 0);
+ goto L1524;
+
+ L840:
+ x2 = XEXP (x1, 0);
+ if (scratch_operand (x2, SImode))
+ {
+ ro[3] = x2;
+ if (TARGET_WIDE_MULTIPLY)
+ return 151;
+ }
+ x1 = XVECEXP (x0, 0, 0);
+ x2 = XEXP (x1, 0);
+ goto L1524;
+
+ L865:
+ x3 = XEXP (x2, 0);
+ if (register_operand (x3, SImode))
{
ro[1] = x3;
- goto L711;
+ goto L866;
}
x2 = XEXP (x1, 0);
- goto L1358;
+ goto L1524;
- L711:
+ L866:
x3 = XEXP (x2, 1);
- if (general_operand (x3, HImode))
+ if (general_operand (x3, SImode))
{
ro[2] = x3;
- goto L712;
+ goto L867;
}
x2 = XEXP (x1, 0);
- goto L1358;
+ goto L1524;
- L712:
+ L867:
x1 = XVECEXP (x0, 0, 1);
if (GET_CODE (x1) == SET && 1)
- goto L713;
+ goto L868;
x1 = XVECEXP (x0, 0, 0);
x2 = XEXP (x1, 0);
- goto L1358;
+ goto L1524;
- L713:
+ L868:
x2 = XEXP (x1, 0);
- if (register_operand (x2, HImode))
+ if (register_operand (x2, SImode))
{
ro[3] = x2;
- goto L714;
+ goto L869;
}
x1 = XVECEXP (x0, 0, 0);
x2 = XEXP (x1, 0);
- goto L1358;
+ goto L1524;
- L714:
+ L869:
x2 = XEXP (x1, 1);
- if (GET_MODE (x2) == HImode && GET_CODE (x2) == MOD && 1)
- goto L715;
+ if (GET_MODE (x2) == SImode && GET_CODE (x2) == MOD && 1)
+ goto L870;
x1 = XVECEXP (x0, 0, 0);
x2 = XEXP (x1, 0);
- goto L1358;
+ goto L1524;
- L715:
+ L870:
x3 = XEXP (x2, 0);
if (rtx_equal_p (x3, ro[1]) && 1)
- goto L716;
+ goto L871;
x1 = XVECEXP (x0, 0, 0);
x2 = XEXP (x1, 0);
- goto L1358;
+ goto L1524;
- L716:
+ L871:
x3 = XEXP (x2, 1);
if (rtx_equal_p (x3, ro[2]) && 1)
- return 140;
+ return 160;
x1 = XVECEXP (x0, 0, 0);
x2 = XEXP (x1, 0);
- goto L1358;
+ goto L1524;
- L732:
+ L887:
x3 = XEXP (x2, 0);
- if (register_operand (x3, HImode))
+ if (register_operand (x3, SImode))
{
ro[1] = x3;
- goto L733;
+ goto L888;
}
x2 = XEXP (x1, 0);
- goto L1358;
+ goto L1524;
- L733:
+ L888:
x3 = XEXP (x2, 1);
- if (general_operand (x3, HImode))
+ if (general_operand (x3, SImode))
{
ro[2] = x3;
- goto L734;
+ goto L889;
}
x2 = XEXP (x1, 0);
- goto L1358;
+ goto L1524;
- L734:
+ L889:
x1 = XVECEXP (x0, 0, 1);
if (GET_CODE (x1) == SET && 1)
- goto L735;
+ goto L890;
x1 = XVECEXP (x0, 0, 0);
x2 = XEXP (x1, 0);
- goto L1358;
+ goto L1524;
- L735:
+ L890:
x2 = XEXP (x1, 0);
- if (register_operand (x2, HImode))
+ if (register_operand (x2, SImode))
{
ro[3] = x2;
- goto L736;
+ goto L891;
}
x1 = XVECEXP (x0, 0, 0);
x2 = XEXP (x1, 0);
- goto L1358;
+ goto L1524;
- L736:
+ L891:
x2 = XEXP (x1, 1);
- if (GET_MODE (x2) == HImode && GET_CODE (x2) == UMOD && 1)
- goto L737;
+ if (GET_MODE (x2) == SImode && GET_CODE (x2) == UMOD && 1)
+ goto L892;
x1 = XVECEXP (x0, 0, 0);
x2 = XEXP (x1, 0);
- goto L1358;
+ goto L1524;
- L737:
+ L892:
x3 = XEXP (x2, 0);
if (rtx_equal_p (x3, ro[1]) && 1)
- goto L738;
+ goto L893;
x1 = XVECEXP (x0, 0, 0);
x2 = XEXP (x1, 0);
- goto L1358;
+ goto L1524;
- L738:
+ L893:
x3 = XEXP (x2, 1);
if (rtx_equal_p (x3, ro[2]) && 1)
- return 142;
+ return 162;
x1 = XVECEXP (x0, 0, 0);
x2 = XEXP (x1, 0);
- goto L1358;
+ goto L1524;
- L917:
+ L875:
x2 = XEXP (x1, 1);
- if (GET_MODE (x2) != DImode)
+ if (GET_MODE (x2) != HImode)
{
x2 = XEXP (x1, 0);
- goto L1358;
+ goto L1524;
}
switch (GET_CODE (x2))
{
- case ASHIFT:
- goto L918;
- case ASHIFTRT:
- goto L946;
- case LSHIFTRT:
- goto L974;
+ case DIV:
+ goto L876;
+ case UDIV:
+ goto L898;
}
x2 = XEXP (x1, 0);
- goto L1358;
+ goto L1524;
- L918:
+ L876:
x3 = XEXP (x2, 0);
- if (register_operand (x3, DImode))
+ if (register_operand (x3, HImode))
{
ro[1] = x3;
- goto L919;
+ goto L877;
}
x2 = XEXP (x1, 0);
- goto L1358;
+ goto L1524;
- L919:
+ L877:
x3 = XEXP (x2, 1);
- if (register_operand (x3, QImode))
+ if (general_operand (x3, HImode))
{
ro[2] = x3;
- goto L920;
+ goto L878;
}
x2 = XEXP (x1, 0);
- goto L1358;
+ goto L1524;
- L920:
+ L878:
x1 = XVECEXP (x0, 0, 1);
- if (GET_CODE (x1) == CLOBBER && 1)
- goto L921;
+ if (GET_CODE (x1) == SET && 1)
+ goto L879;
x1 = XVECEXP (x0, 0, 0);
x2 = XEXP (x1, 0);
- goto L1358;
+ goto L1524;
- L921:
- x2 = XEXP (x1, 0);
- if (rtx_equal_p (x2, ro[2]) && 1)
- return 183;
- x1 = XVECEXP (x0, 0, 0);
+ L879:
x2 = XEXP (x1, 0);
- goto L1358;
-
- L946:
- x3 = XEXP (x2, 0);
- if (register_operand (x3, DImode))
+ if (register_operand (x2, HImode))
{
- ro[1] = x3;
- goto L947;
+ ro[3] = x2;
+ goto L880;
}
+ x1 = XVECEXP (x0, 0, 0);
x2 = XEXP (x1, 0);
- goto L1358;
+ goto L1524;
- L947:
- x3 = XEXP (x2, 1);
- if (register_operand (x3, QImode))
- {
- ro[2] = x3;
- goto L948;
- }
+ L880:
+ x2 = XEXP (x1, 1);
+ if (GET_MODE (x2) == HImode && GET_CODE (x2) == MOD && 1)
+ goto L881;
+ x1 = XVECEXP (x0, 0, 0);
x2 = XEXP (x1, 0);
- goto L1358;
+ goto L1524;
- L948:
- x1 = XVECEXP (x0, 0, 1);
- if (GET_CODE (x1) == CLOBBER && 1)
- goto L949;
+ L881:
+ x3 = XEXP (x2, 0);
+ if (rtx_equal_p (x3, ro[1]) && 1)
+ goto L882;
x1 = XVECEXP (x0, 0, 0);
x2 = XEXP (x1, 0);
- goto L1358;
+ goto L1524;
- L949:
- x2 = XEXP (x1, 0);
- if (rtx_equal_p (x2, ro[2]) && 1)
- return 189;
+ L882:
+ x3 = XEXP (x2, 1);
+ if (rtx_equal_p (x3, ro[2]) && 1)
+ return 161;
x1 = XVECEXP (x0, 0, 0);
x2 = XEXP (x1, 0);
- goto L1358;
+ goto L1524;
- L974:
+ L898:
x3 = XEXP (x2, 0);
- if (register_operand (x3, DImode))
+ if (register_operand (x3, HImode))
{
ro[1] = x3;
- goto L975;
+ goto L899;
}
x2 = XEXP (x1, 0);
- goto L1358;
+ goto L1524;
- L975:
+ L899:
x3 = XEXP (x2, 1);
- if (register_operand (x3, QImode))
+ if (general_operand (x3, HImode))
{
ro[2] = x3;
- goto L976;
+ goto L900;
}
x2 = XEXP (x1, 0);
- goto L1358;
+ goto L1524;
- L976:
+ L900:
x1 = XVECEXP (x0, 0, 1);
- if (GET_CODE (x1) == CLOBBER && 1)
- goto L977;
+ if (GET_CODE (x1) == SET && 1)
+ goto L901;
x1 = XVECEXP (x0, 0, 0);
x2 = XEXP (x1, 0);
- goto L1358;
+ goto L1524;
- L977:
+ L901:
x2 = XEXP (x1, 0);
- if (rtx_equal_p (x2, ro[2]) && 1)
- return 195;
+ if (register_operand (x2, HImode))
+ {
+ ro[3] = x2;
+ goto L902;
+ }
+ x1 = XVECEXP (x0, 0, 0);
+ x2 = XEXP (x1, 0);
+ goto L1524;
+
+ L902:
+ x2 = XEXP (x1, 1);
+ if (GET_MODE (x2) == HImode && GET_CODE (x2) == UMOD && 1)
+ goto L903;
x1 = XVECEXP (x0, 0, 0);
x2 = XEXP (x1, 0);
- goto L1358;
+ goto L1524;
+
+ L903:
+ x3 = XEXP (x2, 0);
+ if (rtx_equal_p (x3, ro[1]) && 1)
+ goto L904;
+ x1 = XVECEXP (x0, 0, 0);
+ x2 = XEXP (x1, 0);
+ goto L1524;
+
+ L904:
+ x3 = XEXP (x2, 1);
+ if (rtx_equal_p (x3, ro[2]) && 1)
+ return 163;
+ x1 = XVECEXP (x0, 0, 0);
+ x2 = XEXP (x1, 0);
+ goto L1524;
L12:
x2 = XEXP (x1, 1);
@@ -5200,7 +5798,7 @@ recog_6 (x0, insn, pnum_clobbers)
if (GET_MODE (x2) == CCFPEQmode && GET_CODE (x2) == COMPARE && 1)
goto L128;
x2 = XEXP (x1, 0);
- goto L1358;
+ goto L1524;
L13:
x1 = XVECEXP (x0, 0, 1);
@@ -5292,7 +5890,7 @@ recog_6 (x0, insn, pnum_clobbers)
}
}
x2 = XEXP (x1, 0);
- goto L1358;
+ goto L1524;
L129:
x3 = XEXP (x2, 1);
@@ -5302,7 +5900,7 @@ recog_6 (x0, insn, pnum_clobbers)
goto L130;
}
x2 = XEXP (x1, 0);
- goto L1358;
+ goto L1524;
L130:
x1 = XVECEXP (x0, 0, 1);
@@ -5310,7 +5908,7 @@ recog_6 (x0, insn, pnum_clobbers)
goto L131;
x1 = XVECEXP (x0, 0, 0);
x2 = XEXP (x1, 0);
- goto L1358;
+ goto L1524;
L131:
x2 = XEXP (x1, 0);
@@ -5322,7 +5920,7 @@ recog_6 (x0, insn, pnum_clobbers)
}
x1 = XVECEXP (x0, 0, 0);
x2 = XEXP (x1, 0);
- goto L1358;
+ goto L1524;
L215:
x3 = XEXP (x2, 1);
@@ -5332,7 +5930,7 @@ recog_6 (x0, insn, pnum_clobbers)
goto L216;
}
x2 = XEXP (x1, 0);
- goto L1358;
+ goto L1524;
L216:
x1 = XVECEXP (x0, 0, 1);
@@ -5340,7 +5938,7 @@ recog_6 (x0, insn, pnum_clobbers)
goto L217;
x1 = XVECEXP (x0, 0, 0);
x2 = XEXP (x1, 0);
- goto L1358;
+ goto L1524;
L217:
x2 = XEXP (x1, 0);
@@ -5352,7 +5950,7 @@ recog_6 (x0, insn, pnum_clobbers)
}
x1 = XVECEXP (x0, 0, 0);
x2 = XEXP (x1, 0);
- goto L1358;
+ goto L1524;
L271:
x3 = XEXP (x2, 1);
@@ -5362,7 +5960,7 @@ recog_6 (x0, insn, pnum_clobbers)
goto L272;
}
x2 = XEXP (x1, 0);
- goto L1358;
+ goto L1524;
L272:
x1 = XVECEXP (x0, 0, 1);
@@ -5370,7 +5968,7 @@ recog_6 (x0, insn, pnum_clobbers)
goto L273;
x1 = XVECEXP (x0, 0, 0);
x2 = XEXP (x1, 0);
- goto L1358;
+ goto L1524;
L273:
x2 = XEXP (x1, 0);
@@ -5382,307 +5980,307 @@ recog_6 (x0, insn, pnum_clobbers)
}
x1 = XVECEXP (x0, 0, 0);
x2 = XEXP (x1, 0);
- goto L1358;
+ goto L1524;
- L1301:
+ L1467:
x2 = XEXP (x1, 1);
if (GET_MODE (x2) == SImode && GET_CODE (x2) == MINUS && 1)
- goto L1302;
+ goto L1468;
if (general_operand (x2, SImode))
{
ro[0] = x2;
- goto L1327;
+ goto L1493;
}
x2 = XEXP (x1, 0);
- goto L1358;
+ goto L1524;
- L1302:
+ L1468:
x3 = XEXP (x2, 0);
if (GET_MODE (x3) == SImode && GET_CODE (x3) == REG && XINT (x3, 0) == 3 && 1)
- goto L1303;
+ goto L1469;
x2 = XEXP (x1, 0);
- goto L1358;
+ goto L1524;
- L1303:
+ L1469:
x3 = XEXP (x2, 1);
if (GET_MODE (x3) == SImode && GET_CODE (x3) == MEM && 1)
- goto L1304;
+ goto L1470;
x2 = XEXP (x1, 0);
- goto L1358;
+ goto L1524;
- L1304:
+ L1470:
x4 = XEXP (x3, 0);
if (GET_MODE (x4) == SImode && GET_CODE (x4) == PLUS && 1)
- goto L1305;
+ goto L1471;
x2 = XEXP (x1, 0);
- goto L1358;
+ goto L1524;
- L1305:
+ L1471:
x5 = XEXP (x4, 0);
if (GET_MODE (x5) == SImode && GET_CODE (x5) == MULT && 1)
- goto L1306;
+ goto L1472;
x2 = XEXP (x1, 0);
- goto L1358;
+ goto L1524;
- L1306:
+ L1472:
x6 = XEXP (x5, 0);
if (register_operand (x6, SImode))
{
ro[0] = x6;
- goto L1307;
+ goto L1473;
}
x2 = XEXP (x1, 0);
- goto L1358;
+ goto L1524;
- L1307:
+ L1473:
x6 = XEXP (x5, 1);
if (GET_CODE (x6) == CONST_INT && XWINT (x6, 0) == 4 && 1)
- goto L1308;
+ goto L1474;
x2 = XEXP (x1, 0);
- goto L1358;
+ goto L1524;
- L1308:
+ L1474:
x5 = XEXP (x4, 1);
if (GET_CODE (x5) == LABEL_REF && 1)
- goto L1309;
+ goto L1475;
x2 = XEXP (x1, 0);
- goto L1358;
+ goto L1524;
- L1309:
+ L1475:
x6 = XEXP (x5, 0);
ro[1] = x6;
- goto L1310;
+ goto L1476;
- L1310:
+ L1476:
x1 = XVECEXP (x0, 0, 1);
if (GET_CODE (x1) == CLOBBER && 1)
- goto L1311;
+ goto L1477;
x1 = XVECEXP (x0, 0, 0);
x2 = XEXP (x1, 0);
- goto L1358;
+ goto L1524;
- L1311:
+ L1477:
x2 = XEXP (x1, 0);
if (scratch_operand (x2, SImode))
{
ro[2] = x2;
- return 264;
+ return 285;
}
x1 = XVECEXP (x0, 0, 0);
x2 = XEXP (x1, 0);
- goto L1358;
+ goto L1524;
- L1327:
+ L1493:
x1 = XVECEXP (x0, 0, 1);
if (GET_CODE (x1) == USE && 1)
- goto L1328;
+ goto L1494;
x1 = XVECEXP (x0, 0, 0);
x2 = XEXP (x1, 0);
- goto L1358;
+ goto L1524;
- L1328:
+ L1494:
x2 = XEXP (x1, 0);
if (GET_CODE (x2) == LABEL_REF && 1)
- goto L1329;
+ goto L1495;
x1 = XVECEXP (x0, 0, 0);
x2 = XEXP (x1, 0);
- goto L1358;
+ goto L1524;
- L1329:
+ L1495:
x3 = XEXP (x2, 0);
ro[1] = x3;
- return 265;
+ return 286;
- L1359:
+ L1525:
x2 = XEXP (x1, 1);
if (GET_CODE (x2) == CALL && 1)
- goto L1371;
+ goto L1537;
x2 = XEXP (x1, 0);
- goto L1548;
+ goto L1701;
- L1371:
+ L1537:
x3 = XEXP (x2, 0);
if (GET_MODE (x3) == QImode && GET_CODE (x3) == MEM && 1)
- goto L1372;
- L1360:
+ goto L1538;
+ L1526:
if (call_insn_operand (x3, QImode))
{
ro[1] = x3;
- goto L1361;
+ goto L1527;
}
x2 = XEXP (x1, 0);
- goto L1548;
+ goto L1701;
- L1372:
+ L1538:
x4 = XEXP (x3, 0);
if (symbolic_operand (x4, SImode))
{
ro[1] = x4;
- goto L1373;
+ goto L1539;
}
- goto L1360;
+ goto L1526;
- L1373:
+ L1539:
x3 = XEXP (x2, 1);
if (general_operand (x3, SImode))
{
ro[2] = x3;
- goto L1374;
+ goto L1540;
}
x3 = XEXP (x2, 0);
- goto L1360;
+ goto L1526;
- L1374:
+ L1540:
x1 = XVECEXP (x0, 0, 1);
if (GET_CODE (x1) == SET && 1)
- goto L1375;
+ goto L1541;
x1 = XVECEXP (x0, 0, 0);
x2 = XEXP (x1, 1);
x3 = XEXP (x2, 0);
- goto L1360;
+ goto L1526;
- L1375:
+ L1541:
x2 = XEXP (x1, 0);
if (GET_MODE (x2) == SImode && GET_CODE (x2) == REG && XINT (x2, 0) == 7 && 1)
- goto L1376;
+ goto L1542;
x1 = XVECEXP (x0, 0, 0);
x2 = XEXP (x1, 1);
x3 = XEXP (x2, 0);
- goto L1360;
+ goto L1526;
- L1376:
+ L1542:
x2 = XEXP (x1, 1);
if (GET_MODE (x2) == SImode && GET_CODE (x2) == PLUS && 1)
- goto L1377;
+ goto L1543;
x1 = XVECEXP (x0, 0, 0);
x2 = XEXP (x1, 1);
x3 = XEXP (x2, 0);
- goto L1360;
+ goto L1526;
- L1377:
+ L1543:
x3 = XEXP (x2, 0);
if (GET_MODE (x3) == SImode && GET_CODE (x3) == REG && XINT (x3, 0) == 7 && 1)
- goto L1378;
+ goto L1544;
x1 = XVECEXP (x0, 0, 0);
x2 = XEXP (x1, 1);
x3 = XEXP (x2, 0);
- goto L1360;
+ goto L1526;
- L1378:
+ L1544:
x3 = XEXP (x2, 1);
if (immediate_operand (x3, SImode))
{
ro[4] = x3;
if (!HALF_PIC_P ())
- return 274;
+ return 295;
}
x1 = XVECEXP (x0, 0, 0);
x2 = XEXP (x1, 1);
x3 = XEXP (x2, 0);
- goto L1360;
+ goto L1526;
- L1361:
+ L1527:
x3 = XEXP (x2, 1);
if (general_operand (x3, SImode))
{
ro[2] = x3;
- goto L1362;
+ goto L1528;
}
x2 = XEXP (x1, 0);
- goto L1548;
+ goto L1701;
- L1362:
+ L1528:
x1 = XVECEXP (x0, 0, 1);
if (GET_CODE (x1) == SET && 1)
- goto L1363;
+ goto L1529;
x1 = XVECEXP (x0, 0, 0);
x2 = XEXP (x1, 0);
- goto L1548;
+ goto L1701;
- L1363:
+ L1529:
x2 = XEXP (x1, 0);
if (GET_MODE (x2) == SImode && GET_CODE (x2) == REG && XINT (x2, 0) == 7 && 1)
- goto L1364;
+ goto L1530;
x1 = XVECEXP (x0, 0, 0);
x2 = XEXP (x1, 0);
- goto L1548;
+ goto L1701;
- L1364:
+ L1530:
x2 = XEXP (x1, 1);
if (GET_MODE (x2) == SImode && GET_CODE (x2) == PLUS && 1)
- goto L1365;
+ goto L1531;
x1 = XVECEXP (x0, 0, 0);
x2 = XEXP (x1, 0);
- goto L1548;
+ goto L1701;
- L1365:
+ L1531:
x3 = XEXP (x2, 0);
if (GET_MODE (x3) == SImode && GET_CODE (x3) == REG && XINT (x3, 0) == 7 && 1)
- goto L1366;
+ goto L1532;
x1 = XVECEXP (x0, 0, 0);
x2 = XEXP (x1, 0);
- goto L1548;
+ goto L1701;
- L1366:
+ L1532:
x3 = XEXP (x2, 1);
if (immediate_operand (x3, SImode))
{
ro[4] = x3;
- return 273;
+ return 294;
}
x1 = XVECEXP (x0, 0, 0);
x2 = XEXP (x1, 0);
- goto L1548;
+ goto L1701;
- L1549:
+ L1702:
x2 = XEXP (x1, 1);
if (GET_MODE (x2) == SImode && GET_CODE (x2) == UNSPEC && XINT (x2, 1) == 0 && XVECLEN (x2, 0) == 3 && 1)
- goto L1550;
+ goto L1703;
goto ret0;
- L1550:
+ L1703:
x3 = XVECEXP (x2, 0, 0);
if (GET_MODE (x3) == BLKmode && GET_CODE (x3) == MEM && 1)
- goto L1551;
+ goto L1704;
goto ret0;
- L1551:
+ L1704:
x4 = XEXP (x3, 0);
if (address_operand (x4, SImode))
{
ro[1] = x4;
- goto L1552;
+ goto L1705;
}
goto ret0;
- L1552:
+ L1705:
x3 = XVECEXP (x2, 0, 1);
if (register_operand (x3, QImode))
{
ro[2] = x3;
- goto L1553;
+ goto L1706;
}
goto ret0;
- L1553:
+ L1706:
x3 = XVECEXP (x2, 0, 2);
if (immediate_operand (x3, SImode))
{
ro[3] = x3;
- goto L1554;
+ goto L1707;
}
goto ret0;
- L1554:
+ L1707:
x1 = XVECEXP (x0, 0, 1);
if (GET_CODE (x1) == CLOBBER && 1)
- goto L1555;
+ goto L1708;
goto ret0;
- L1555:
+ L1708:
x2 = XEXP (x1, 0);
if (rtx_equal_p (x2, ro[1]) && 1)
- return 308;
+ return 326;
goto ret0;
ret0: return -1;
}
@@ -5701,86 +6299,561 @@ recog_7 (x0, insn, pnum_clobbers)
x2 = XEXP (x1, 0);
switch (GET_MODE (x2))
{
+ case DFmode:
+ if (GET_CODE (x2) == MEM && push_operand (x2, DFmode))
+ {
+ ro[0] = x2;
+ goto L377;
+ }
+ L389:
+ if (memory_operand (x2, DFmode))
+ {
+ ro[0] = x2;
+ goto L390;
+ }
+ break;
+ case XFmode:
+ if (GET_CODE (x2) == MEM && push_operand (x2, XFmode))
+ {
+ ro[0] = x2;
+ goto L414;
+ }
+ L426:
+ if (memory_operand (x2, XFmode))
+ {
+ ro[0] = x2;
+ goto L427;
+ }
+ break;
case DImode:
+ if (GET_CODE (x2) == MEM && push_operand (x2, DImode))
+ {
+ ro[0] = x2;
+ goto L448;
+ }
+ L458:
if (general_operand (x2, DImode))
{
ro[0] = x2;
- goto L439;
+ goto L459;
}
break;
case SImode:
if (general_operand (x2, SImode))
{
ro[0] = x2;
- goto L503;
+ goto L619;
}
}
goto ret0;
- L439:
+ L377:
+ x2 = XEXP (x1, 1);
+ if (general_operand (x2, DFmode))
+ {
+ ro[1] = x2;
+ goto L378;
+ }
+ x2 = XEXP (x1, 0);
+ goto L389;
+
+ L378:
+ x1 = XVECEXP (x0, 0, 1);
+ if (GET_CODE (x1) == CLOBBER && 1)
+ goto L379;
+ x1 = XVECEXP (x0, 0, 0);
+ x2 = XEXP (x1, 0);
+ goto L389;
+
+ L379:
+ x2 = XEXP (x1, 0);
+ if (scratch_operand (x2, SImode))
+ {
+ ro[2] = x2;
+ goto L380;
+ }
+ x1 = XVECEXP (x0, 0, 0);
+ x2 = XEXP (x1, 0);
+ goto L389;
+
+ L380:
+ x1 = XVECEXP (x0, 0, 2);
+ if (GET_CODE (x1) == CLOBBER && 1)
+ goto L381;
+ x1 = XVECEXP (x0, 0, 0);
+ x2 = XEXP (x1, 0);
+ goto L389;
+
+ L381:
+ x2 = XEXP (x1, 0);
+ if (scratch_operand (x2, SImode))
+ {
+ ro[3] = x2;
+ return 73;
+ }
+ x1 = XVECEXP (x0, 0, 0);
+ x2 = XEXP (x1, 0);
+ goto L389;
+
+ L390:
+ x2 = XEXP (x1, 1);
+ if (memory_operand (x2, DFmode))
+ {
+ ro[1] = x2;
+ goto L391;
+ }
+ goto ret0;
+
+ L391:
+ x1 = XVECEXP (x0, 0, 1);
+ if (GET_CODE (x1) == CLOBBER && 1)
+ goto L392;
+ goto ret0;
+
+ L392:
+ x2 = XEXP (x1, 0);
+ if (scratch_operand (x2, SImode))
+ {
+ ro[2] = x2;
+ goto L393;
+ }
+ goto ret0;
+
+ L393:
+ x1 = XVECEXP (x0, 0, 2);
+ if (GET_CODE (x1) == CLOBBER && 1)
+ goto L394;
+ goto ret0;
+
+ L394:
+ x2 = XEXP (x1, 0);
+ if (scratch_operand (x2, SImode))
+ {
+ ro[3] = x2;
+ return 74;
+ }
+ goto ret0;
+
+ L414:
+ x2 = XEXP (x1, 1);
+ if (general_operand (x2, XFmode))
+ {
+ ro[1] = x2;
+ goto L415;
+ }
+ x2 = XEXP (x1, 0);
+ goto L426;
+
+ L415:
+ x1 = XVECEXP (x0, 0, 1);
+ if (GET_CODE (x1) == CLOBBER && 1)
+ goto L416;
+ x1 = XVECEXP (x0, 0, 0);
+ x2 = XEXP (x1, 0);
+ goto L426;
+
+ L416:
+ x2 = XEXP (x1, 0);
+ if (scratch_operand (x2, SImode))
+ {
+ ro[2] = x2;
+ goto L417;
+ }
+ x1 = XVECEXP (x0, 0, 0);
+ x2 = XEXP (x1, 0);
+ goto L426;
+
+ L417:
+ x1 = XVECEXP (x0, 0, 2);
+ if (GET_CODE (x1) == CLOBBER && 1)
+ goto L418;
+ x1 = XVECEXP (x0, 0, 0);
+ x2 = XEXP (x1, 0);
+ goto L426;
+
+ L418:
+ x2 = XEXP (x1, 0);
+ if (scratch_operand (x2, SImode))
+ {
+ ro[3] = x2;
+ return 79;
+ }
+ x1 = XVECEXP (x0, 0, 0);
+ x2 = XEXP (x1, 0);
+ goto L426;
+
+ L427:
+ x2 = XEXP (x1, 1);
+ if (memory_operand (x2, XFmode))
+ {
+ ro[1] = x2;
+ goto L428;
+ }
+ goto ret0;
+
+ L428:
+ x1 = XVECEXP (x0, 0, 1);
+ if (GET_CODE (x1) == CLOBBER && 1)
+ goto L429;
+ goto ret0;
+
+ L429:
+ x2 = XEXP (x1, 0);
+ if (scratch_operand (x2, SImode))
+ {
+ ro[2] = x2;
+ goto L430;
+ }
+ goto ret0;
+
+ L430:
+ x1 = XVECEXP (x0, 0, 2);
+ if (GET_CODE (x1) == CLOBBER && 1)
+ goto L431;
+ goto ret0;
+
+ L431:
+ x2 = XEXP (x1, 0);
+ if (scratch_operand (x2, SImode))
+ {
+ ro[3] = x2;
+ return 80;
+ }
+ goto ret0;
+
+ L448:
+ x2 = XEXP (x1, 1);
+ if (general_operand (x2, DImode))
+ {
+ ro[1] = x2;
+ goto L449;
+ }
+ x2 = XEXP (x1, 0);
+ goto L458;
+
+ L449:
+ x1 = XVECEXP (x0, 0, 1);
+ if (GET_CODE (x1) == CLOBBER && 1)
+ goto L450;
+ x1 = XVECEXP (x0, 0, 0);
+ x2 = XEXP (x1, 0);
+ goto L458;
+
+ L450:
+ x2 = XEXP (x1, 0);
+ if (scratch_operand (x2, SImode))
+ {
+ ro[2] = x2;
+ goto L451;
+ }
+ x1 = XVECEXP (x0, 0, 0);
+ x2 = XEXP (x1, 0);
+ goto L458;
+
+ L451:
+ x1 = XVECEXP (x0, 0, 2);
+ if (GET_CODE (x1) == CLOBBER && 1)
+ goto L452;
+ x1 = XVECEXP (x0, 0, 0);
+ x2 = XEXP (x1, 0);
+ goto L458;
+
+ L452:
+ x2 = XEXP (x1, 0);
+ if (scratch_operand (x2, SImode))
+ {
+ ro[3] = x2;
+ return 83;
+ }
+ x1 = XVECEXP (x0, 0, 0);
+ x2 = XEXP (x1, 0);
+ goto L458;
+
+ L459:
+ x2 = XEXP (x1, 1);
+ if (general_operand (x2, DImode))
+ {
+ ro[1] = x2;
+ goto L460;
+ }
+ goto ret0;
+
+ L460:
+ x1 = XVECEXP (x0, 0, 1);
+ if (GET_CODE (x1) == CLOBBER && 1)
+ goto L461;
+ goto ret0;
+
+ L461:
+ x2 = XEXP (x1, 0);
+ if (scratch_operand (x2, SImode))
+ {
+ ro[2] = x2;
+ goto L462;
+ }
+ goto ret0;
+
+ L462:
+ x1 = XVECEXP (x0, 0, 2);
+ if (GET_CODE (x1) == CLOBBER && 1)
+ goto L463;
+ goto ret0;
+
+ L463:
+ x2 = XEXP (x1, 0);
+ if (scratch_operand (x2, SImode))
+ {
+ ro[3] = x2;
+ return 84;
+ }
+ goto ret0;
+
+ L619:
+ x2 = XEXP (x1, 1);
+ if (GET_MODE (x2) == SImode && GET_CODE (x2) == FIX && 1)
+ goto L620;
+ goto ret0;
+
+ L620:
+ x3 = XEXP (x2, 0);
+ if (GET_CODE (x3) != FIX)
+ goto ret0;
+ switch (GET_MODE (x3))
+ {
+ case XFmode:
+ goto L621;
+ case DFmode:
+ goto L643;
+ case SFmode:
+ goto L665;
+ }
+ goto ret0;
+
+ L621:
+ x4 = XEXP (x3, 0);
+ if (register_operand (x4, XFmode))
+ {
+ ro[1] = x4;
+ goto L622;
+ }
+ goto ret0;
+
+ L622:
+ x1 = XVECEXP (x0, 0, 1);
+ if (GET_CODE (x1) == CLOBBER && 1)
+ goto L623;
+ goto ret0;
+
+ L623:
+ x2 = XEXP (x1, 0);
+ if (memory_operand (x2, SImode))
+ {
+ ro[2] = x2;
+ goto L624;
+ }
+ goto ret0;
+
+ L624:
+ x1 = XVECEXP (x0, 0, 2);
+ if (GET_CODE (x1) == CLOBBER && 1)
+ goto L625;
+ goto ret0;
+
+ L625:
+ x2 = XEXP (x1, 0);
+ if (pnum_clobbers != 0 && memory_operand (x2, SImode))
+ {
+ ro[3] = x2;
+ if (TARGET_80387)
+ {
+ *pnum_clobbers = 1;
+ return 112;
+ }
+ }
+ goto ret0;
+
+ L643:
+ x4 = XEXP (x3, 0);
+ if (register_operand (x4, DFmode))
+ {
+ ro[1] = x4;
+ goto L644;
+ }
+ goto ret0;
+
+ L644:
+ x1 = XVECEXP (x0, 0, 1);
+ if (GET_CODE (x1) == CLOBBER && 1)
+ goto L645;
+ goto ret0;
+
+ L645:
+ x2 = XEXP (x1, 0);
+ if (memory_operand (x2, SImode))
+ {
+ ro[2] = x2;
+ goto L646;
+ }
+ goto ret0;
+
+ L646:
+ x1 = XVECEXP (x0, 0, 2);
+ if (GET_CODE (x1) == CLOBBER && 1)
+ goto L647;
+ goto ret0;
+
+ L647:
+ x2 = XEXP (x1, 0);
+ if (pnum_clobbers != 0 && memory_operand (x2, SImode))
+ {
+ ro[3] = x2;
+ if (TARGET_80387)
+ {
+ *pnum_clobbers = 1;
+ return 113;
+ }
+ }
+ goto ret0;
+
+ L665:
+ x4 = XEXP (x3, 0);
+ if (register_operand (x4, SFmode))
+ {
+ ro[1] = x4;
+ goto L666;
+ }
+ goto ret0;
+
+ L666:
+ x1 = XVECEXP (x0, 0, 1);
+ if (GET_CODE (x1) == CLOBBER && 1)
+ goto L667;
+ goto ret0;
+
+ L667:
+ x2 = XEXP (x1, 0);
+ if (memory_operand (x2, SImode))
+ {
+ ro[2] = x2;
+ goto L668;
+ }
+ goto ret0;
+
+ L668:
+ x1 = XVECEXP (x0, 0, 2);
+ if (GET_CODE (x1) == CLOBBER && 1)
+ goto L669;
+ goto ret0;
+
+ L669:
+ x2 = XEXP (x1, 0);
+ if (pnum_clobbers != 0 && memory_operand (x2, SImode))
+ {
+ ro[3] = x2;
+ if (TARGET_80387)
+ {
+ *pnum_clobbers = 1;
+ return 114;
+ }
+ }
+ goto ret0;
+ ret0: return -1;
+}
+
+int
+recog_8 (x0, insn, pnum_clobbers)
+ register rtx x0;
+ rtx insn;
+ int *pnum_clobbers;
+{
+ register rtx *ro = &recog_operand[0];
+ register rtx x1, x2, x3, x4, x5, x6;
+ int tem;
+
+ x1 = XVECEXP (x0, 0, 0);
+ x2 = XEXP (x1, 0);
+ switch (GET_MODE (x2))
+ {
+ case DImode:
+ if (general_operand (x2, DImode))
+ {
+ ro[0] = x2;
+ goto L543;
+ }
+ break;
+ case SImode:
+ if (general_operand (x2, SImode))
+ {
+ ro[0] = x2;
+ goto L607;
+ }
+ }
+ goto ret0;
+
+ L543:
x2 = XEXP (x1, 1);
if (GET_MODE (x2) == DImode && GET_CODE (x2) == FIX && 1)
- goto L440;
+ goto L544;
goto ret0;
- L440:
+ L544:
x3 = XEXP (x2, 0);
if (GET_CODE (x3) != FIX)
goto ret0;
switch (GET_MODE (x3))
{
case XFmode:
- goto L441;
+ goto L545;
case DFmode:
- goto L467;
+ goto L571;
case SFmode:
- goto L493;
+ goto L597;
}
goto ret0;
- L441:
+ L545:
x4 = XEXP (x3, 0);
if (register_operand (x4, XFmode))
{
ro[1] = x4;
- goto L442;
+ goto L546;
}
goto ret0;
- L442:
+ L546:
x1 = XVECEXP (x0, 0, 1);
if (GET_CODE (x1) == CLOBBER && 1)
- goto L443;
+ goto L547;
goto ret0;
- L443:
+ L547:
x2 = XEXP (x1, 0);
if (rtx_equal_p (x2, ro[1]) && 1)
- goto L444;
+ goto L548;
goto ret0;
- L444:
+ L548:
x1 = XVECEXP (x0, 0, 2);
if (GET_CODE (x1) == CLOBBER && 1)
- goto L445;
+ goto L549;
goto ret0;
- L445:
+ L549:
x2 = XEXP (x1, 0);
if (memory_operand (x2, SImode))
{
ro[2] = x2;
- goto L446;
+ goto L550;
}
goto ret0;
- L446:
+ L550:
x1 = XVECEXP (x0, 0, 3);
if (GET_CODE (x1) == CLOBBER && 1)
- goto L447;
+ goto L551;
goto ret0;
- L447:
+ L551:
x2 = XEXP (x1, 0);
if (pnum_clobbers != 0 && memory_operand (x2, SImode))
{
@@ -5788,54 +6861,54 @@ recog_7 (x0, insn, pnum_clobbers)
if (TARGET_80387)
{
*pnum_clobbers = 1;
- return 87;
+ return 106;
}
}
goto ret0;
- L467:
+ L571:
x4 = XEXP (x3, 0);
if (register_operand (x4, DFmode))
{
ro[1] = x4;
- goto L468;
+ goto L572;
}
goto ret0;
- L468:
+ L572:
x1 = XVECEXP (x0, 0, 1);
if (GET_CODE (x1) == CLOBBER && 1)
- goto L469;
+ goto L573;
goto ret0;
- L469:
+ L573:
x2 = XEXP (x1, 0);
if (rtx_equal_p (x2, ro[1]) && 1)
- goto L470;
+ goto L574;
goto ret0;
- L470:
+ L574:
x1 = XVECEXP (x0, 0, 2);
if (GET_CODE (x1) == CLOBBER && 1)
- goto L471;
+ goto L575;
goto ret0;
- L471:
+ L575:
x2 = XEXP (x1, 0);
if (memory_operand (x2, SImode))
{
ro[2] = x2;
- goto L472;
+ goto L576;
}
goto ret0;
- L472:
+ L576:
x1 = XVECEXP (x0, 0, 3);
if (GET_CODE (x1) == CLOBBER && 1)
- goto L473;
+ goto L577;
goto ret0;
- L473:
+ L577:
x2 = XEXP (x1, 0);
if (pnum_clobbers != 0 && memory_operand (x2, SImode))
{
@@ -5843,54 +6916,54 @@ recog_7 (x0, insn, pnum_clobbers)
if (TARGET_80387)
{
*pnum_clobbers = 1;
- return 88;
+ return 107;
}
}
goto ret0;
- L493:
+ L597:
x4 = XEXP (x3, 0);
if (register_operand (x4, SFmode))
{
ro[1] = x4;
- goto L494;
+ goto L598;
}
goto ret0;
- L494:
+ L598:
x1 = XVECEXP (x0, 0, 1);
if (GET_CODE (x1) == CLOBBER && 1)
- goto L495;
+ goto L599;
goto ret0;
- L495:
+ L599:
x2 = XEXP (x1, 0);
if (rtx_equal_p (x2, ro[1]) && 1)
- goto L496;
+ goto L600;
goto ret0;
- L496:
+ L600:
x1 = XVECEXP (x0, 0, 2);
if (GET_CODE (x1) == CLOBBER && 1)
- goto L497;
+ goto L601;
goto ret0;
- L497:
+ L601:
x2 = XEXP (x1, 0);
if (memory_operand (x2, SImode))
{
ro[2] = x2;
- goto L498;
+ goto L602;
}
goto ret0;
- L498:
+ L602:
x1 = XVECEXP (x0, 0, 3);
if (GET_CODE (x1) == CLOBBER && 1)
- goto L499;
+ goto L603;
goto ret0;
- L499:
+ L603:
x2 = XEXP (x1, 0);
if (pnum_clobbers != 0 && memory_operand (x2, SImode))
{
@@ -5898,194 +6971,194 @@ recog_7 (x0, insn, pnum_clobbers)
if (TARGET_80387)
{
*pnum_clobbers = 1;
- return 89;
+ return 108;
}
}
goto ret0;
- L503:
+ L607:
x2 = XEXP (x1, 1);
if (GET_MODE (x2) == SImode && GET_CODE (x2) == FIX && 1)
- goto L504;
+ goto L608;
goto ret0;
- L504:
+ L608:
x3 = XEXP (x2, 0);
if (GET_CODE (x3) != FIX)
goto ret0;
switch (GET_MODE (x3))
{
case XFmode:
- goto L505;
+ goto L609;
case DFmode:
- goto L527;
+ goto L631;
case SFmode:
- goto L549;
+ goto L653;
}
goto ret0;
- L505:
+ L609:
x4 = XEXP (x3, 0);
if (register_operand (x4, XFmode))
{
ro[1] = x4;
- goto L506;
+ goto L610;
}
goto ret0;
- L506:
+ L610:
x1 = XVECEXP (x0, 0, 1);
if (GET_CODE (x1) == CLOBBER && 1)
- goto L507;
+ goto L611;
goto ret0;
- L507:
+ L611:
x2 = XEXP (x1, 0);
if (memory_operand (x2, SImode))
{
ro[2] = x2;
- goto L508;
+ goto L612;
}
goto ret0;
- L508:
+ L612:
x1 = XVECEXP (x0, 0, 2);
if (GET_CODE (x1) == CLOBBER && 1)
- goto L509;
+ goto L613;
goto ret0;
- L509:
+ L613:
x2 = XEXP (x1, 0);
if (memory_operand (x2, SImode))
{
ro[3] = x2;
- goto L510;
+ goto L614;
}
goto ret0;
- L510:
+ L614:
x1 = XVECEXP (x0, 0, 3);
if (GET_CODE (x1) == CLOBBER && 1)
- goto L511;
+ goto L615;
goto ret0;
- L511:
+ L615:
x2 = XEXP (x1, 0);
if (scratch_operand (x2, SImode))
{
ro[4] = x2;
if (TARGET_80387)
- return 93;
+ return 112;
}
goto ret0;
- L527:
+ L631:
x4 = XEXP (x3, 0);
if (register_operand (x4, DFmode))
{
ro[1] = x4;
- goto L528;
+ goto L632;
}
goto ret0;
- L528:
+ L632:
x1 = XVECEXP (x0, 0, 1);
if (GET_CODE (x1) == CLOBBER && 1)
- goto L529;
+ goto L633;
goto ret0;
- L529:
+ L633:
x2 = XEXP (x1, 0);
if (memory_operand (x2, SImode))
{
ro[2] = x2;
- goto L530;
+ goto L634;
}
goto ret0;
- L530:
+ L634:
x1 = XVECEXP (x0, 0, 2);
if (GET_CODE (x1) == CLOBBER && 1)
- goto L531;
+ goto L635;
goto ret0;
- L531:
+ L635:
x2 = XEXP (x1, 0);
if (memory_operand (x2, SImode))
{
ro[3] = x2;
- goto L532;
+ goto L636;
}
goto ret0;
- L532:
+ L636:
x1 = XVECEXP (x0, 0, 3);
if (GET_CODE (x1) == CLOBBER && 1)
- goto L533;
+ goto L637;
goto ret0;
- L533:
+ L637:
x2 = XEXP (x1, 0);
if (scratch_operand (x2, SImode))
{
ro[4] = x2;
if (TARGET_80387)
- return 94;
+ return 113;
}
goto ret0;
- L549:
+ L653:
x4 = XEXP (x3, 0);
if (register_operand (x4, SFmode))
{
ro[1] = x4;
- goto L550;
+ goto L654;
}
goto ret0;
- L550:
+ L654:
x1 = XVECEXP (x0, 0, 1);
if (GET_CODE (x1) == CLOBBER && 1)
- goto L551;
+ goto L655;
goto ret0;
- L551:
+ L655:
x2 = XEXP (x1, 0);
if (memory_operand (x2, SImode))
{
ro[2] = x2;
- goto L552;
+ goto L656;
}
goto ret0;
- L552:
+ L656:
x1 = XVECEXP (x0, 0, 2);
if (GET_CODE (x1) == CLOBBER && 1)
- goto L553;
+ goto L657;
goto ret0;
- L553:
+ L657:
x2 = XEXP (x1, 0);
if (memory_operand (x2, SImode))
{
ro[3] = x2;
- goto L554;
+ goto L658;
}
goto ret0;
- L554:
+ L658:
x1 = XVECEXP (x0, 0, 3);
if (GET_CODE (x1) == CLOBBER && 1)
- goto L555;
+ goto L659;
goto ret0;
- L555:
+ L659:
x2 = XEXP (x1, 0);
if (scratch_operand (x2, SImode))
{
ro[4] = x2;
if (TARGET_80387)
- return 95;
+ return 114;
}
goto ret0;
ret0: return -1;
@@ -6101,45 +7174,36 @@ recog (x0, insn, pnum_clobbers)
register rtx x1, x2, x3, x4, x5, x6;
int tem;
- L1403:
+ L0:
switch (GET_CODE (x0))
{
- case UNSPEC:
- if (GET_MODE (x0) == SImode && XINT (x0, 1) == 0 && XVECLEN (x0, 0) == 1 && 1)
- goto L1404;
- break;
case SET:
goto L295;
case PARALLEL:
if (XVECLEN (x0, 0) == 2 && 1)
goto L10;
+ if (XVECLEN (x0, 0) == 3 && 1)
+ goto L375;
if (XVECLEN (x0, 0) == 5 && 1)
- goto L423;
+ goto L527;
if (XVECLEN (x0, 0) == 4 && 1)
- goto L437;
- if (XVECLEN (x0, 0) == 3 && 1)
- goto L513;
+ goto L541;
if (XVECLEN (x0, 0) == 6 && 1)
- goto L1408;
+ goto L1561;
break;
case CALL:
- goto L1350;
+ goto L1516;
+ case UNSPEC_VOLATILE:
+ if (XINT (x0, 1) == 0 && XVECLEN (x0, 0) == 1 && 1)
+ goto L1557;
+ break;
case RETURN:
if (simple_386_epilogue ())
- return 283;
+ return 301;
break;
case CONST_INT:
if (XWINT (x0, 0) == 0 && 1)
- return 284;
- }
- goto ret0;
-
- L1404:
- x1 = XVECEXP (x0, 0, 0);
- if (memory_operand (x1, SImode))
- {
- ro[0] = x1;
- return 282;
+ return 302;
}
goto ret0;
L295:
@@ -6150,976 +7214,752 @@ recog (x0, insn, pnum_clobbers)
switch (GET_CODE (x1))
{
case SET:
- goto L336;
+ goto L343;
case CALL:
- goto L1341;
+ goto L1507;
}
goto ret0;
- L336:
+ L343:
return recog_6 (x0, insn, pnum_clobbers);
- L1341:
+ L1507:
x2 = XEXP (x1, 0);
if (GET_MODE (x2) == QImode && GET_CODE (x2) == MEM && 1)
- goto L1342;
- L1332:
+ goto L1508;
+ L1498:
if (call_insn_operand (x2, QImode))
{
ro[0] = x2;
- goto L1333;
+ goto L1499;
}
goto ret0;
- L1342:
+ L1508:
x3 = XEXP (x2, 0);
if (symbolic_operand (x3, SImode))
{
ro[0] = x3;
- goto L1343;
+ goto L1509;
}
- goto L1332;
+ goto L1498;
- L1343:
+ L1509:
x2 = XEXP (x1, 1);
if (general_operand (x2, SImode))
{
ro[1] = x2;
- goto L1344;
+ goto L1510;
}
x2 = XEXP (x1, 0);
- goto L1332;
+ goto L1498;
- L1344:
+ L1510:
x1 = XVECEXP (x0, 0, 1);
if (GET_CODE (x1) == SET && 1)
- goto L1345;
+ goto L1511;
x1 = XVECEXP (x0, 0, 0);
x2 = XEXP (x1, 0);
- goto L1332;
+ goto L1498;
- L1345:
+ L1511:
x2 = XEXP (x1, 0);
if (GET_MODE (x2) == SImode && GET_CODE (x2) == REG && XINT (x2, 0) == 7 && 1)
- goto L1346;
+ goto L1512;
x1 = XVECEXP (x0, 0, 0);
x2 = XEXP (x1, 0);
- goto L1332;
+ goto L1498;
- L1346:
+ L1512:
x2 = XEXP (x1, 1);
if (GET_MODE (x2) == SImode && GET_CODE (x2) == PLUS && 1)
- goto L1347;
+ goto L1513;
x1 = XVECEXP (x0, 0, 0);
x2 = XEXP (x1, 0);
- goto L1332;
+ goto L1498;
- L1347:
+ L1513:
x3 = XEXP (x2, 0);
if (GET_MODE (x3) == SImode && GET_CODE (x3) == REG && XINT (x3, 0) == 7 && 1)
- goto L1348;
+ goto L1514;
x1 = XVECEXP (x0, 0, 0);
x2 = XEXP (x1, 0);
- goto L1332;
+ goto L1498;
- L1348:
+ L1514:
x3 = XEXP (x2, 1);
if (immediate_operand (x3, SImode))
{
ro[3] = x3;
if (!HALF_PIC_P ())
- return 268;
+ return 289;
}
x1 = XVECEXP (x0, 0, 0);
x2 = XEXP (x1, 0);
- goto L1332;
+ goto L1498;
- L1333:
+ L1499:
x2 = XEXP (x1, 1);
if (general_operand (x2, SImode))
{
ro[1] = x2;
- goto L1334;
+ goto L1500;
}
goto ret0;
- L1334:
+ L1500:
x1 = XVECEXP (x0, 0, 1);
if (GET_CODE (x1) == SET && 1)
- goto L1335;
+ goto L1501;
goto ret0;
- L1335:
+ L1501:
x2 = XEXP (x1, 0);
if (GET_MODE (x2) == SImode && GET_CODE (x2) == REG && XINT (x2, 0) == 7 && 1)
- goto L1336;
+ goto L1502;
goto ret0;
- L1336:
+ L1502:
x2 = XEXP (x1, 1);
if (GET_MODE (x2) == SImode && GET_CODE (x2) == PLUS && 1)
- goto L1337;
+ goto L1503;
goto ret0;
- L1337:
+ L1503:
x3 = XEXP (x2, 0);
if (GET_MODE (x3) == SImode && GET_CODE (x3) == REG && XINT (x3, 0) == 7 && 1)
- goto L1338;
+ goto L1504;
goto ret0;
- L1338:
+ L1504:
x3 = XEXP (x2, 1);
if (immediate_operand (x3, SImode))
{
ro[3] = x3;
- return 267;
+ return 288;
}
goto ret0;
- L423:
+ L375:
x1 = XVECEXP (x0, 0, 0);
if (GET_CODE (x1) == SET && 1)
- goto L424;
+ goto L376;
goto ret0;
+ L376:
+ return recog_7 (x0, insn, pnum_clobbers);
- L424:
+ L527:
+ x1 = XVECEXP (x0, 0, 0);
+ if (GET_CODE (x1) == SET && 1)
+ goto L528;
+ goto ret0;
+
+ L528:
x2 = XEXP (x1, 0);
if (GET_MODE (x2) == DImode && general_operand (x2, DImode))
{
ro[0] = x2;
- goto L425;
+ goto L529;
}
goto ret0;
- L425:
+ L529:
x2 = XEXP (x1, 1);
if (GET_MODE (x2) == DImode && GET_CODE (x2) == FIX && 1)
- goto L426;
+ goto L530;
goto ret0;
- L426:
+ L530:
x3 = XEXP (x2, 0);
if (GET_CODE (x3) != FIX)
goto ret0;
switch (GET_MODE (x3))
{
case XFmode:
- goto L427;
+ goto L531;
case DFmode:
- goto L453;
+ goto L557;
case SFmode:
- goto L479;
+ goto L583;
}
goto ret0;
- L427:
+ L531:
x4 = XEXP (x3, 0);
if (register_operand (x4, XFmode))
{
ro[1] = x4;
- goto L428;
+ goto L532;
}
goto ret0;
- L428:
+ L532:
x1 = XVECEXP (x0, 0, 1);
if (GET_CODE (x1) == CLOBBER && 1)
- goto L429;
+ goto L533;
goto ret0;
- L429:
+ L533:
x2 = XEXP (x1, 0);
if (rtx_equal_p (x2, ro[1]) && 1)
- goto L430;
+ goto L534;
goto ret0;
- L430:
+ L534:
x1 = XVECEXP (x0, 0, 2);
if (GET_CODE (x1) == CLOBBER && 1)
- goto L431;
+ goto L535;
goto ret0;
- L431:
+ L535:
x2 = XEXP (x1, 0);
if (memory_operand (x2, SImode))
{
ro[2] = x2;
- goto L432;
+ goto L536;
}
goto ret0;
- L432:
+ L536:
x1 = XVECEXP (x0, 0, 3);
if (GET_CODE (x1) == CLOBBER && 1)
- goto L433;
+ goto L537;
goto ret0;
- L433:
+ L537:
x2 = XEXP (x1, 0);
if (memory_operand (x2, SImode))
{
ro[3] = x2;
- goto L434;
+ goto L538;
}
goto ret0;
- L434:
+ L538:
x1 = XVECEXP (x0, 0, 4);
if (GET_CODE (x1) == CLOBBER && 1)
- goto L435;
+ goto L539;
goto ret0;
- L435:
+ L539:
x2 = XEXP (x1, 0);
if (scratch_operand (x2, SImode))
{
ro[4] = x2;
if (TARGET_80387)
- return 87;
+ return 106;
}
goto ret0;
- L453:
+ L557:
x4 = XEXP (x3, 0);
if (register_operand (x4, DFmode))
{
ro[1] = x4;
- goto L454;
+ goto L558;
}
goto ret0;
- L454:
+ L558:
x1 = XVECEXP (x0, 0, 1);
if (GET_CODE (x1) == CLOBBER && 1)
- goto L455;
+ goto L559;
goto ret0;
- L455:
+ L559:
x2 = XEXP (x1, 0);
if (rtx_equal_p (x2, ro[1]) && 1)
- goto L456;
+ goto L560;
goto ret0;
- L456:
+ L560:
x1 = XVECEXP (x0, 0, 2);
if (GET_CODE (x1) == CLOBBER && 1)
- goto L457;
+ goto L561;
goto ret0;
- L457:
+ L561:
x2 = XEXP (x1, 0);
if (memory_operand (x2, SImode))
{
ro[2] = x2;
- goto L458;
+ goto L562;
}
goto ret0;
- L458:
+ L562:
x1 = XVECEXP (x0, 0, 3);
if (GET_CODE (x1) == CLOBBER && 1)
- goto L459;
+ goto L563;
goto ret0;
- L459:
+ L563:
x2 = XEXP (x1, 0);
if (memory_operand (x2, SImode))
{
ro[3] = x2;
- goto L460;
+ goto L564;
}
goto ret0;
- L460:
+ L564:
x1 = XVECEXP (x0, 0, 4);
if (GET_CODE (x1) == CLOBBER && 1)
- goto L461;
+ goto L565;
goto ret0;
- L461:
+ L565:
x2 = XEXP (x1, 0);
if (scratch_operand (x2, SImode))
{
ro[4] = x2;
if (TARGET_80387)
- return 88;
+ return 107;
}
goto ret0;
- L479:
+ L583:
x4 = XEXP (x3, 0);
if (register_operand (x4, SFmode))
{
ro[1] = x4;
- goto L480;
+ goto L584;
}
goto ret0;
- L480:
+ L584:
x1 = XVECEXP (x0, 0, 1);
if (GET_CODE (x1) == CLOBBER && 1)
- goto L481;
+ goto L585;
goto ret0;
- L481:
+ L585:
x2 = XEXP (x1, 0);
if (rtx_equal_p (x2, ro[1]) && 1)
- goto L482;
+ goto L586;
goto ret0;
- L482:
+ L586:
x1 = XVECEXP (x0, 0, 2);
if (GET_CODE (x1) == CLOBBER && 1)
- goto L483;
+ goto L587;
goto ret0;
- L483:
+ L587:
x2 = XEXP (x1, 0);
if (memory_operand (x2, SImode))
{
ro[2] = x2;
- goto L484;
+ goto L588;
}
goto ret0;
- L484:
+ L588:
x1 = XVECEXP (x0, 0, 3);
if (GET_CODE (x1) == CLOBBER && 1)
- goto L485;
+ goto L589;
goto ret0;
- L485:
+ L589:
x2 = XEXP (x1, 0);
if (memory_operand (x2, SImode))
{
ro[3] = x2;
- goto L486;
+ goto L590;
}
goto ret0;
- L486:
+ L590:
x1 = XVECEXP (x0, 0, 4);
if (GET_CODE (x1) == CLOBBER && 1)
- goto L487;
+ goto L591;
goto ret0;
- L487:
+ L591:
x2 = XEXP (x1, 0);
if (scratch_operand (x2, SImode))
{
ro[4] = x2;
if (TARGET_80387)
- return 89;
+ return 108;
}
goto ret0;
- L437:
- x1 = XVECEXP (x0, 0, 0);
- if (GET_CODE (x1) == SET && 1)
- goto L438;
- goto ret0;
- L438:
- return recog_7 (x0, insn, pnum_clobbers);
-
- L513:
- x1 = XVECEXP (x0, 0, 0);
- switch (GET_CODE (x1))
- {
- case SET:
- goto L514;
- case CALL:
- goto L1398;
- }
- goto ret0;
-
- L514:
- x2 = XEXP (x1, 0);
- if (GET_MODE (x2) == SImode && general_operand (x2, SImode))
- {
- ro[0] = x2;
- goto L515;
- }
- goto ret0;
-
- L515:
- x2 = XEXP (x1, 1);
- if (GET_MODE (x2) == SImode && GET_CODE (x2) == FIX && 1)
- goto L516;
- goto ret0;
-
- L516:
- x3 = XEXP (x2, 0);
- if (GET_CODE (x3) != FIX)
- goto ret0;
- switch (GET_MODE (x3))
- {
- case XFmode:
- goto L517;
- case DFmode:
- goto L539;
- case SFmode:
- goto L561;
- }
- goto ret0;
-
- L517:
- x4 = XEXP (x3, 0);
- if (register_operand (x4, XFmode))
- {
- ro[1] = x4;
- goto L518;
- }
- goto ret0;
-
- L518:
- x1 = XVECEXP (x0, 0, 1);
- if (GET_CODE (x1) == CLOBBER && 1)
- goto L519;
- goto ret0;
-
- L519:
- x2 = XEXP (x1, 0);
- if (memory_operand (x2, SImode))
- {
- ro[2] = x2;
- goto L520;
- }
- goto ret0;
-
- L520:
- x1 = XVECEXP (x0, 0, 2);
- if (GET_CODE (x1) == CLOBBER && 1)
- goto L521;
- goto ret0;
-
- L521:
- x2 = XEXP (x1, 0);
- if (pnum_clobbers != 0 && memory_operand (x2, SImode))
- {
- ro[3] = x2;
- if (TARGET_80387)
- {
- *pnum_clobbers = 1;
- return 93;
- }
- }
- goto ret0;
-
- L539:
- x4 = XEXP (x3, 0);
- if (register_operand (x4, DFmode))
- {
- ro[1] = x4;
- goto L540;
- }
- goto ret0;
-
- L540:
- x1 = XVECEXP (x0, 0, 1);
- if (GET_CODE (x1) == CLOBBER && 1)
- goto L541;
- goto ret0;
-
L541:
- x2 = XEXP (x1, 0);
- if (memory_operand (x2, SImode))
- {
- ro[2] = x2;
- goto L542;
- }
- goto ret0;
-
- L542:
- x1 = XVECEXP (x0, 0, 2);
- if (GET_CODE (x1) == CLOBBER && 1)
- goto L543;
- goto ret0;
-
- L543:
- x2 = XEXP (x1, 0);
- if (pnum_clobbers != 0 && memory_operand (x2, SImode))
- {
- ro[3] = x2;
- if (TARGET_80387)
- {
- *pnum_clobbers = 1;
- return 94;
- }
- }
- goto ret0;
-
- L561:
- x4 = XEXP (x3, 0);
- if (register_operand (x4, SFmode))
- {
- ro[1] = x4;
- goto L562;
- }
- goto ret0;
-
- L562:
- x1 = XVECEXP (x0, 0, 1);
- if (GET_CODE (x1) == CLOBBER && 1)
- goto L563;
- goto ret0;
-
- L563:
- x2 = XEXP (x1, 0);
- if (memory_operand (x2, SImode))
- {
- ro[2] = x2;
- goto L564;
- }
- goto ret0;
-
- L564:
- x1 = XVECEXP (x0, 0, 2);
- if (GET_CODE (x1) == CLOBBER && 1)
- goto L565;
- goto ret0;
-
- L565:
- x2 = XEXP (x1, 0);
- if (pnum_clobbers != 0 && memory_operand (x2, SImode))
- {
- ro[3] = x2;
- if (TARGET_80387)
- {
- *pnum_clobbers = 1;
- return 95;
- }
- }
- goto ret0;
-
- L1398:
- x2 = XEXP (x1, 0);
- if (GET_MODE (x2) == QImode && GET_CODE (x2) == MEM && 1)
- goto L1399;
- L1392:
- if (call_insn_operand (x2, QImode))
- {
- ro[0] = x2;
- goto L1393;
- }
- goto ret0;
-
- L1399:
- x3 = XEXP (x2, 0);
- if (symbolic_operand (x3, SImode))
- {
- ro[0] = x3;
- goto L1400;
- }
- goto L1392;
-
- L1400:
- x2 = XEXP (x1, 1);
- if (GET_CODE (x2) == CONST_INT && XWINT (x2, 0) == 0 && 1)
- goto L1401;
- x2 = XEXP (x1, 0);
- goto L1392;
-
- L1401:
- x1 = XVECEXP (x0, 0, 1);
- if (memory_operand (x1, DImode))
- {
- ro[1] = x1;
- goto L1402;
- }
- x1 = XVECEXP (x0, 0, 0);
- x2 = XEXP (x1, 0);
- goto L1392;
-
- L1402:
- x1 = XVECEXP (x0, 0, 2);
- ro[2] = x1;
- if (!HALF_PIC_P ())
- return 280;
x1 = XVECEXP (x0, 0, 0);
- x2 = XEXP (x1, 0);
- goto L1392;
-
- L1393:
- x2 = XEXP (x1, 1);
- if (GET_CODE (x2) == CONST_INT && XWINT (x2, 0) == 0 && 1)
- goto L1394;
- goto ret0;
-
- L1394:
- x1 = XVECEXP (x0, 0, 1);
- if (memory_operand (x1, DImode))
- {
- ro[1] = x1;
- goto L1395;
- }
+ if (GET_CODE (x1) == SET && 1)
+ goto L542;
goto ret0;
+ L542:
+ return recog_8 (x0, insn, pnum_clobbers);
- L1395:
- x1 = XVECEXP (x0, 0, 2);
- ro[2] = x1;
- return 279;
-
- L1408:
+ L1561:
x1 = XVECEXP (x0, 0, 0);
if (GET_CODE (x1) == SET && 1)
- goto L1409;
+ goto L1562;
goto ret0;
- L1409:
+ L1562:
x2 = XEXP (x1, 0);
switch (GET_MODE (x2))
{
case BLKmode:
if (GET_CODE (x2) == MEM && 1)
- goto L1410;
+ goto L1563;
break;
case SImode:
if (general_operand (x2, SImode))
{
ro[0] = x2;
- goto L1426;
+ goto L1579;
}
}
if (GET_CODE (x2) == CC0 && 1)
- goto L1444;
+ goto L1597;
goto ret0;
- L1410:
+ L1563:
x3 = XEXP (x2, 0);
if (address_operand (x3, SImode))
{
ro[0] = x3;
- goto L1411;
+ goto L1564;
}
goto ret0;
- L1411:
+ L1564:
x2 = XEXP (x1, 1);
if (GET_MODE (x2) == BLKmode && GET_CODE (x2) == MEM && 1)
- goto L1412;
+ goto L1565;
goto ret0;
- L1412:
+ L1565:
x3 = XEXP (x2, 0);
if (address_operand (x3, SImode))
{
ro[1] = x3;
- goto L1413;
+ goto L1566;
}
goto ret0;
- L1413:
+ L1566:
x1 = XVECEXP (x0, 0, 1);
if (GET_CODE (x1) == USE && 1)
- goto L1414;
+ goto L1567;
goto ret0;
- L1414:
+ L1567:
x2 = XEXP (x1, 0);
if (GET_CODE (x2) == CONST_INT && 1)
{
ro[2] = x2;
- goto L1415;
+ goto L1568;
}
goto ret0;
- L1415:
+ L1568:
x1 = XVECEXP (x0, 0, 2);
if (GET_CODE (x1) == USE && 1)
- goto L1416;
+ goto L1569;
goto ret0;
- L1416:
+ L1569:
x2 = XEXP (x1, 0);
if (immediate_operand (x2, SImode))
{
ro[3] = x2;
- goto L1417;
+ goto L1570;
}
goto ret0;
- L1417:
+ L1570:
x1 = XVECEXP (x0, 0, 3);
if (GET_CODE (x1) == CLOBBER && 1)
- goto L1418;
+ goto L1571;
goto ret0;
- L1418:
+ L1571:
x2 = XEXP (x1, 0);
if (scratch_operand (x2, SImode))
{
ro[4] = x2;
- goto L1419;
+ goto L1572;
}
goto ret0;
- L1419:
+ L1572:
x1 = XVECEXP (x0, 0, 4);
if (GET_CODE (x1) == CLOBBER && 1)
- goto L1420;
+ goto L1573;
goto ret0;
- L1420:
+ L1573:
x2 = XEXP (x1, 0);
if (rtx_equal_p (x2, ro[0]) && 1)
- goto L1421;
+ goto L1574;
goto ret0;
- L1421:
+ L1574:
x1 = XVECEXP (x0, 0, 5);
if (GET_CODE (x1) == CLOBBER && 1)
- goto L1422;
+ goto L1575;
goto ret0;
- L1422:
+ L1575:
x2 = XEXP (x1, 0);
if (rtx_equal_p (x2, ro[1]) && 1)
- return 286;
+ return 304;
goto ret0;
- L1426:
+ L1579:
x2 = XEXP (x1, 1);
if (GET_MODE (x2) == SImode && GET_CODE (x2) == COMPARE && 1)
- goto L1427;
+ goto L1580;
goto ret0;
- L1427:
+ L1580:
x3 = XEXP (x2, 0);
if (GET_MODE (x3) == BLKmode && GET_CODE (x3) == MEM && 1)
- goto L1428;
+ goto L1581;
goto ret0;
- L1428:
+ L1581:
x4 = XEXP (x3, 0);
if (address_operand (x4, SImode))
{
ro[1] = x4;
- goto L1429;
+ goto L1582;
}
goto ret0;
- L1429:
+ L1582:
x3 = XEXP (x2, 1);
if (GET_MODE (x3) == BLKmode && GET_CODE (x3) == MEM && 1)
- goto L1430;
+ goto L1583;
goto ret0;
- L1430:
+ L1583:
x4 = XEXP (x3, 0);
if (address_operand (x4, SImode))
{
ro[2] = x4;
- goto L1431;
+ goto L1584;
}
goto ret0;
- L1431:
+ L1584:
x1 = XVECEXP (x0, 0, 1);
if (GET_CODE (x1) == USE && 1)
- goto L1432;
+ goto L1585;
goto ret0;
- L1432:
+ L1585:
x2 = XEXP (x1, 0);
if (register_operand (x2, SImode))
{
ro[3] = x2;
- goto L1433;
+ goto L1586;
}
goto ret0;
- L1433:
+ L1586:
x1 = XVECEXP (x0, 0, 2);
if (GET_CODE (x1) == USE && 1)
- goto L1434;
+ goto L1587;
goto ret0;
- L1434:
+ L1587:
x2 = XEXP (x1, 0);
if (immediate_operand (x2, SImode))
{
ro[4] = x2;
- goto L1435;
+ goto L1588;
}
goto ret0;
- L1435:
+ L1588:
x1 = XVECEXP (x0, 0, 3);
if (GET_CODE (x1) == CLOBBER && 1)
- goto L1436;
+ goto L1589;
goto ret0;
- L1436:
+ L1589:
x2 = XEXP (x1, 0);
if (rtx_equal_p (x2, ro[1]) && 1)
- goto L1437;
+ goto L1590;
goto ret0;
- L1437:
+ L1590:
x1 = XVECEXP (x0, 0, 4);
if (GET_CODE (x1) == CLOBBER && 1)
- goto L1438;
+ goto L1591;
goto ret0;
- L1438:
+ L1591:
x2 = XEXP (x1, 0);
if (rtx_equal_p (x2, ro[2]) && 1)
- goto L1439;
+ goto L1592;
goto ret0;
- L1439:
+ L1592:
x1 = XVECEXP (x0, 0, 5);
if (GET_CODE (x1) == CLOBBER && 1)
- goto L1440;
+ goto L1593;
goto ret0;
- L1440:
+ L1593:
x2 = XEXP (x1, 0);
if (rtx_equal_p (x2, ro[3]) && 1)
- return 288;
+ return 306;
goto ret0;
- L1444:
+ L1597:
x2 = XEXP (x1, 1);
if (GET_MODE (x2) == SImode && GET_CODE (x2) == COMPARE && 1)
- goto L1445;
+ goto L1598;
goto ret0;
- L1445:
+ L1598:
x3 = XEXP (x2, 0);
if (GET_MODE (x3) == BLKmode && GET_CODE (x3) == MEM && 1)
- goto L1446;
+ goto L1599;
goto ret0;
- L1446:
+ L1599:
x4 = XEXP (x3, 0);
if (address_operand (x4, SImode))
{
ro[0] = x4;
- goto L1447;
+ goto L1600;
}
goto ret0;
- L1447:
+ L1600:
x3 = XEXP (x2, 1);
if (GET_MODE (x3) == BLKmode && GET_CODE (x3) == MEM && 1)
- goto L1448;
+ goto L1601;
goto ret0;
- L1448:
+ L1601:
x4 = XEXP (x3, 0);
if (address_operand (x4, SImode))
{
ro[1] = x4;
- goto L1449;
+ goto L1602;
}
goto ret0;
- L1449:
+ L1602:
x1 = XVECEXP (x0, 0, 1);
if (GET_CODE (x1) == USE && 1)
- goto L1450;
+ goto L1603;
goto ret0;
- L1450:
+ L1603:
x2 = XEXP (x1, 0);
if (register_operand (x2, SImode))
{
ro[2] = x2;
- goto L1451;
+ goto L1604;
}
goto ret0;
- L1451:
+ L1604:
x1 = XVECEXP (x0, 0, 2);
if (GET_CODE (x1) == USE && 1)
- goto L1452;
+ goto L1605;
goto ret0;
- L1452:
+ L1605:
x2 = XEXP (x1, 0);
if (immediate_operand (x2, SImode))
{
ro[3] = x2;
- goto L1453;
+ goto L1606;
}
goto ret0;
- L1453:
+ L1606:
x1 = XVECEXP (x0, 0, 3);
if (GET_CODE (x1) == CLOBBER && 1)
- goto L1454;
+ goto L1607;
goto ret0;
- L1454:
+ L1607:
x2 = XEXP (x1, 0);
if (rtx_equal_p (x2, ro[0]) && 1)
- goto L1455;
+ goto L1608;
goto ret0;
- L1455:
+ L1608:
x1 = XVECEXP (x0, 0, 4);
if (GET_CODE (x1) == CLOBBER && 1)
- goto L1456;
+ goto L1609;
goto ret0;
- L1456:
+ L1609:
x2 = XEXP (x1, 0);
if (rtx_equal_p (x2, ro[1]) && 1)
- goto L1457;
+ goto L1610;
goto ret0;
- L1457:
+ L1610:
x1 = XVECEXP (x0, 0, 5);
if (GET_CODE (x1) == CLOBBER && 1)
- goto L1458;
+ goto L1611;
goto ret0;
- L1458:
+ L1611:
x2 = XEXP (x1, 0);
if (rtx_equal_p (x2, ro[2]) && 1)
- return 289;
+ return 307;
goto ret0;
- L1350:
+ L1516:
x1 = XEXP (x0, 0);
if (call_insn_operand (x1, QImode))
{
ro[0] = x1;
- goto L1351;
+ goto L1517;
}
- L1353:
+ L1519:
if (GET_MODE (x1) == QImode && GET_CODE (x1) == MEM && 1)
- goto L1354;
+ goto L1520;
goto ret0;
- L1351:
+ L1517:
x1 = XEXP (x0, 1);
if (general_operand (x1, SImode))
{
ro[1] = x1;
- return 270;
+ return 291;
}
x1 = XEXP (x0, 0);
- goto L1353;
+ goto L1519;
- L1354:
+ L1520:
x2 = XEXP (x1, 0);
if (symbolic_operand (x2, SImode))
{
ro[0] = x2;
- goto L1355;
+ goto L1521;
}
goto ret0;
- L1355:
+ L1521:
x1 = XEXP (x0, 1);
if (general_operand (x1, SImode))
{
ro[1] = x1;
if (!HALF_PIC_P ())
- return 271;
+ return 292;
}
goto ret0;
+
+ L1557:
+ x1 = XVECEXP (x0, 0, 0);
+ if (GET_CODE (x1) == CONST_INT && XWINT (x1, 0) == 0 && 1)
+ return 300;
+ goto ret0;
ret0: return -1;
}
diff --git a/gnu/usr.bin/cc/cc_int/integrate.c b/gnu/usr.bin/cc/cc_int/integrate.c
index 63b150d..7e9c2d5 100644
--- a/gnu/usr.bin/cc/cc_int/integrate.c
+++ b/gnu/usr.bin/cc/cc_int/integrate.c
@@ -134,10 +134,15 @@ function_cannot_inline_p (fndecl)
if (int_size_in_bytes (TREE_TYPE (TREE_TYPE (fndecl))) < 0)
return "function with varying-size return value cannot be inline";
- /* Cannot inline a function with a varying size argument. */
+ /* Cannot inline a function with a varying size argument or one that
+ receives a transparent union. */
for (parms = DECL_ARGUMENTS (fndecl); parms; parms = TREE_CHAIN (parms))
- if (int_size_in_bytes (TREE_TYPE (parms)) < 0)
- return "function with varying-size parameter cannot be inline";
+ {
+ if (int_size_in_bytes (TREE_TYPE (parms)) < 0)
+ return "function with varying-size parameter cannot be inline";
+ else if (TYPE_TRANSPARENT_UNION (TREE_TYPE (parms)))
+ return "function with transparent unit parameter cannot be inline";
+ }
if (!DECL_INLINE (fndecl) && get_max_uid () > max_insns)
{
@@ -214,7 +219,7 @@ static int in_nonparm_insns;
/* Subroutine for `save_for_inline{copying,nocopy}'. Performs initialization
needed to save FNDECL's insns and info for future inline expansion. */
-
+
static rtx
initialize_for_inline (fndecl, min_labelno, max_labelno, max_reg, copy)
tree fndecl;
@@ -322,7 +327,7 @@ initialize_for_inline (fndecl, min_labelno, max_labelno, max_reg, copy)
/* Subroutine for `save_for_inline{copying,nocopy}'. Finishes up the
things that must be done to make FNDECL expandable as an inline function.
HEAD contains the chain of insns to which FNDECL will expand. */
-
+
static void
finish_inline (fndecl, head)
tree fndecl;
@@ -381,7 +386,7 @@ save_for_inline_copying (fndecl)
int max_uid;
rtx first_nonparm_insn;
- /* Make and emit a return-label if we have not already done so.
+ /* Make and emit a return-label if we have not already done so.
Do this before recording the bounds on label numbers. */
if (return_label == 0)
@@ -791,7 +796,7 @@ save_constants (px)
again:
x = *px;
- /* If this is a CONST_DOUBLE, don't try to fix things up in
+ /* If this is a CONST_DOUBLE, don't try to fix things up in
CONST_DOUBLE_MEM, because this is an infinite recursion. */
if (GET_CODE (x) == CONST_DOUBLE)
return;
@@ -803,7 +808,7 @@ save_constants (px)
RTX_INTEGRATED_P (new) = 1;
/* If the MEM was in a different mode than the constant (perhaps we
- were only looking at the low-order part), surround it with a
+ were only looking at the low-order part), surround it with a
SUBREG so we can save both modes. */
if (GET_MODE (x) != const_mode)
@@ -976,7 +981,7 @@ copy_for_inline (orig)
it is possible for unshare_all_rtl to copy the address, into memory
that won't be saved. Although the MEM can safely be shared, and
won't be copied there, the address itself cannot be shared, and may
- need to be copied.
+ need to be copied.
There are also two exceptions with constants: The first is if the
constant is a LABEL_REF or the sum of the LABEL_REF
@@ -1235,6 +1240,7 @@ expand_inline_function (fndecl, parms, target, ignore, type, structure_value_add
tree arg = convert (TREE_TYPE (formal), TREE_VALUE (actual));
/* Mode of the variable used within the function. */
enum machine_mode mode = TYPE_MODE (TREE_TYPE (formal));
+ int invisiref = 0;
/* Make sure this formal has some correspondence in the users code
* before emitting any line notes for it. */
@@ -1263,6 +1269,7 @@ expand_inline_function (fndecl, parms, target, ignore, type, structure_value_add
store_expr (arg, stack_slot, 0);
arg_vals[i] = XEXP (stack_slot, 0);
+ invisiref = 1;
}
else if (GET_CODE (loc) != MEM)
{
@@ -1288,8 +1295,11 @@ expand_inline_function (fndecl, parms, target, ignore, type, structure_value_add
be two different pseudos, and `safe_from_p' will make all
sorts of smart assumptions about their not conflicting.
But if ARG_VALS[I] overlaps TARGET, these assumptions are
- wrong, so put ARG_VALS[I] into a fresh register. */
+ wrong, so put ARG_VALS[I] into a fresh register.
+ Don't worry about invisible references, since their stack
+ temps will never overlap the target. */
|| (target != 0
+ && ! invisiref
&& (GET_CODE (arg_vals[i]) == REG
|| GET_CODE (arg_vals[i]) == SUBREG
|| GET_CODE (arg_vals[i]) == MEM)
@@ -1300,7 +1310,7 @@ expand_inline_function (fndecl, parms, target, ignore, type, structure_value_add
|| (GET_CODE (arg_vals[i]) == SUBREG)))
arg_vals[i] = copy_to_mode_reg (GET_MODE (loc), arg_vals[i]);
}
-
+
/* Allocate the structures we use to remap things. */
map = (struct inline_remap *) alloca (sizeof (struct inline_remap));
@@ -1544,7 +1554,7 @@ expand_inline_function (fndecl, parms, target, ignore, type, structure_value_add
{
if (! structure_value_addr || ! aggregate_value_p (DECL_RESULT (fndecl)))
abort ();
-
+
/* Pass the function the address in which to return a structure value.
Note that a constructor can cause someone to call us with
STRUCTURE_VALUE_ADDR, but the initialization takes place
@@ -1640,7 +1650,7 @@ expand_inline_function (fndecl, parms, target, ignore, type, structure_value_add
for (insn = insns; insn; insn = NEXT_INSN (insn))
{
- rtx copy, pattern;
+ rtx copy, pattern, set;
map->orig_asm_operands_vector = 0;
@@ -1648,6 +1658,7 @@ expand_inline_function (fndecl, parms, target, ignore, type, structure_value_add
{
case INSN:
pattern = PATTERN (insn);
+ set = single_set (insn);
copy = 0;
if (GET_CODE (pattern) == USE
&& GET_CODE (XEXP (pattern, 0)) == REG
@@ -1659,33 +1670,47 @@ expand_inline_function (fndecl, parms, target, ignore, type, structure_value_add
/* Ignore setting a function value that we don't want to use. */
if (map->inline_target == 0
- && GET_CODE (pattern) == SET
- && GET_CODE (SET_DEST (pattern)) == REG
- && REG_FUNCTION_VALUE_P (SET_DEST (pattern)))
+ && set != 0
+ && GET_CODE (SET_DEST (set)) == REG
+ && REG_FUNCTION_VALUE_P (SET_DEST (set)))
{
- if (volatile_refs_p (SET_SRC (pattern)))
+ if (volatile_refs_p (SET_SRC (set)))
{
+ rtx new_set;
+
/* If we must not delete the source,
load it into a new temporary. */
copy = emit_insn (copy_rtx_and_substitute (pattern, map));
- SET_DEST (PATTERN (copy))
- = gen_reg_rtx (GET_MODE (SET_DEST (PATTERN (copy))));
+
+ new_set = single_set (copy);
+ if (new_set == 0)
+ abort ();
+
+ SET_DEST (new_set)
+ = gen_reg_rtx (GET_MODE (SET_DEST (new_set)));
}
else
break;
}
+
+ /* If this is setting the static chain rtx, omit it. */
+ else if (static_chain_value != 0
+ && set != 0
+ && GET_CODE (SET_DEST (set)) == REG
+ && rtx_equal_p (SET_DEST (set),
+ static_chain_incoming_rtx))
+ break;
+
/* If this is setting the static chain pseudo, set it from
the value we want to give it instead. */
else if (static_chain_value != 0
- && GET_CODE (pattern) == SET
- && rtx_equal_p (SET_SRC (pattern),
+ && set != 0
+ && rtx_equal_p (SET_SRC (set),
static_chain_incoming_rtx))
{
- rtx newdest = copy_rtx_and_substitute (SET_DEST (pattern), map);
-
- copy = emit_insn (gen_rtx (SET, VOIDmode, newdest,
- static_chain_value));
+ rtx newdest = copy_rtx_and_substitute (SET_DEST (set), map);
+ copy = emit_move_insn (newdest, static_chain_value);
static_chain_value = 0;
}
else
@@ -1925,7 +1950,7 @@ integrate_decl_tree (let, level, map)
if (level > 0)
pushlevel (0);
-
+
for (t = BLOCK_VARS (let); t; t = TREE_CHAIN (t))
{
tree d;
@@ -2063,7 +2088,7 @@ copy_rtx_and_substitute (orig, map)
start_sequence ();
loc = assign_stack_temp (BLKmode, size, 1);
loc = XEXP (loc, 0);
- /* When arguments grow downward, the virtual incoming
+ /* When arguments grow downward, the virtual incoming
args pointer points to the top of the argument block,
so the remapped location better do the same. */
#ifdef ARGS_GROW_DOWNWARD
@@ -2173,7 +2198,7 @@ copy_rtx_and_substitute (orig, map)
{
rtx constant = get_pool_constant (orig);
if (GET_CODE (constant) == LABEL_REF)
- return XEXP (force_const_mem (Pmode,
+ return XEXP (force_const_mem (Pmode,
copy_rtx_and_substitute (constant,
map)),
0);
@@ -2510,7 +2535,7 @@ subst_constants (loc, insn, map)
/* We can't call subst_constants on &SUBREG_REG (x) because any
constant or SUBREG wouldn't be valid inside our SUBEG. Instead,
see what is inside, try to form the new SUBREG and see if that is
- valid. We handle two cases: extracting a full word in an
+ valid. We handle two cases: extracting a full word in an
integral mode and extracting the low part. */
subst_constants (&inner, NULL_RTX, map);
@@ -2585,6 +2610,9 @@ subst_constants (loc, insn, map)
/* If storing a recognizable value save it for later recording. */
if ((map->num_sets < MAX_RECOG_OPERANDS)
&& (CONSTANT_P (src)
+ || (GET_CODE (src) == REG
+ && REGNO (src) >= FIRST_VIRTUAL_REGISTER
+ && REGNO (src) <= LAST_VIRTUAL_REGISTER)
|| (GET_CODE (src) == PLUS
&& GET_CODE (XEXP (src, 0)) == REG
&& REGNO (XEXP (src, 0)) >= FIRST_VIRTUAL_REGISTER
@@ -2610,7 +2638,7 @@ subst_constants (loc, insn, map)
}
format_ptr = GET_RTX_FORMAT (code);
-
+
/* If the first operand is an expression, save its mode for later. */
if (*format_ptr == 'e')
op0_mode = GET_MODE (XEXP (x, 0));
diff --git a/gnu/usr.bin/cc/cc_int/jump.c b/gnu/usr.bin/cc/cc_int/jump.c
index 0792f17..23c51bf 100644
--- a/gnu/usr.bin/cc/cc_int/jump.c
+++ b/gnu/usr.bin/cc/cc_int/jump.c
@@ -512,7 +512,7 @@ jump_optimize (f, cross_jump, noop_moves, after_regscan)
|| dreg != sreg)
break;
}
-
+
if (i < 0)
delete_insn (insn);
}
@@ -548,7 +548,7 @@ jump_optimize (f, cross_jump, noop_moves, after_regscan)
&& regno_first_uid[REGNO (SET_DEST (set))] == INSN_UID (insn)
/* We use regno_last_note_uid so as not to delete the setting
of a reg that's used in notes. A subsequent optimization
- might arrange to use that reg for real. */
+ might arrange to use that reg for real. */
&& regno_last_note_uid[REGNO (SET_DEST (set))] == INSN_UID (insn)
&& ! side_effects_p (SET_SRC (set))
&& ! find_reg_note (insn, REG_RETVAL, 0))
@@ -661,6 +661,7 @@ jump_optimize (f, cross_jump, noop_moves, after_regscan)
/* Detect jump to following insn. */
if (reallabelprev == insn && condjump_p (insn))
{
+ next = next_real_insn (JUMP_LABEL (insn));
delete_jump (insn);
changed = 1;
continue;
@@ -711,7 +712,7 @@ jump_optimize (f, cross_jump, noop_moves, after_regscan)
the insn if the only note is a REG_EQUAL or REG_EQUIV whose
value is the same as "b".
- INSN is the branch over the `else' part.
+ INSN is the branch over the `else' part.
We set:
@@ -875,7 +876,7 @@ jump_optimize (f, cross_jump, noop_moves, after_regscan)
if (validate_change (temp, &SET_DEST (temp1), new, 0))
{
next = emit_insn_after (gen_move_insn (temp2, new), insn);
- emit_insn_after_with_line_notes (PATTERN (temp),
+ emit_insn_after_with_line_notes (PATTERN (temp),
PREV_INSN (insn), temp);
delete_insn (temp);
reallabelprev = prev_active_insn (JUMP_LABEL (insn));
@@ -930,7 +931,7 @@ jump_optimize (f, cross_jump, noop_moves, after_regscan)
}
}
- /* Finally, handle the case where two insns are used to
+ /* Finally, handle the case where two insns are used to
compute EXP but a temporary register is used. Here we must
ensure that the temporary register is not used anywhere else. */
@@ -1026,7 +1027,7 @@ jump_optimize (f, cross_jump, noop_moves, after_regscan)
&& (GET_CODE (temp2 = SET_SRC (PATTERN (temp))) == REG
|| GET_CODE (temp2) == SUBREG
|| GET_CODE (temp2) == CONST_INT)
- /* Allow either form, but prefer the former if both apply.
+ /* Allow either form, but prefer the former if both apply.
There is no point in using the old value of TEMP1 if
it is a register, since cse will alias them. It can
lose if the old value were a hard register since CSE
@@ -1122,7 +1123,7 @@ jump_optimize (f, cross_jump, noop_moves, after_regscan)
target = emit_store_flag (gen_reg_rtx (GET_MODE (var)), code,
XEXP (temp4, 0), XEXP (temp4, 1),
VOIDmode,
- (code == LTU || code == LEU
+ (code == LTU || code == LEU
|| code == GEU || code == GTU),
normalizep);
if (target)
@@ -1132,7 +1133,7 @@ jump_optimize (f, cross_jump, noop_moves, after_regscan)
/* Put the store-flag insns in front of the first insn
used to compute the condition to ensure that we
- use the same values of them as the current
+ use the same values of them as the current
comparison. However, the remainder of the insns we
generate will be placed directly in front of the
jump insn, in case any of the pseudos we use
@@ -1192,7 +1193,7 @@ jump_optimize (f, cross_jump, noop_moves, after_regscan)
&& ! preserve_subexpressions_p ()
? target : NULL_RTX));
}
-
+
emit_move_insn (var, target);
seq = get_insns ();
end_sequence ();
@@ -1220,7 +1221,7 @@ jump_optimize (f, cross_jump, noop_moves, after_regscan)
/* If branches are expensive, convert
if (foo) bar++; to bar += (foo != 0);
- and similarly for "bar--;"
+ and similarly for "bar--;"
INSN is the conditional branch around the arithmetic. We set:
@@ -1434,7 +1435,7 @@ jump_optimize (f, cross_jump, noop_moves, after_regscan)
of the first jump. In some cases, the second jump must be
rewritten also.
- For example,
+ For example,
< == converts to > ==
< != converts to == >
etc.
@@ -1806,7 +1807,7 @@ jump_optimize (f, cross_jump, noop_moves, after_regscan)
= rangenext;
PREV_INSN (rangenext)
= PREV_INSN (range2after);
- PREV_INSN (range2after)
+ PREV_INSN (range2after)
= PREV_INSN (range1beg);
NEXT_INSN (range2after) = range1beg;
NEXT_INSN (PREV_INSN (range1beg))
@@ -2169,7 +2170,7 @@ duplicate_loop_exit_test (loop_start)
if (reg_map)
replace_regs (REG_NOTES (copy), reg_map, max_reg, 1);
}
-
+
/* If this is a simple jump, add it to the jump chain. */
if (INSN_UID (copy) < max_jump_chain && JUMP_LABEL (copy)
@@ -2202,11 +2203,11 @@ duplicate_loop_exit_test (loop_start)
emit_barrier_before (loop_start);
}
- delete_insn (next_nonnote_insn (loop_start));
-
/* Mark the exit code as the virtual top of the converted loop. */
emit_note_before (NOTE_INSN_LOOP_VTOP, exitcode);
+ delete_insn (next_nonnote_insn (loop_start));
+
return 1;
}
@@ -2314,7 +2315,7 @@ find_cross_jump (e1, e2, minimum, f1, f2)
p1 = PATTERN (i1);
p2 = PATTERN (i2);
-
+
/* If this is a CALL_INSN, compare register usage information.
If we don't check this on stack register machines, the two
CALL_INSNs might be merged leaving reg-stack.c with mismatching
@@ -2597,7 +2598,7 @@ can_reverse_comparison_p (comparison, insn)
arg0 = XEXP (comparison, 0);
/* Make sure ARG0 is one of the actual objects being compared. If we
- can't do this, we can't be sure the comparison can be reversed.
+ can't do this, we can't be sure the comparison can be reversed.
Handle cc0 and a MODE_CC register. */
if ((GET_CODE (arg0) == REG && GET_MODE_CLASS (GET_MODE (arg0)) == MODE_CC)
@@ -2630,7 +2631,7 @@ can_reverse_comparison_p (comparison, insn)
for the negated comparison.
WATCH OUT! reverse_condition is not safe to use on a jump
that might be acting on the results of an IEEE floating point comparison,
- because of the special treatment of non-signaling nans in comparisons.
+ because of the special treatment of non-signaling nans in comparisons.
Use can_reverse_comparison_p to be sure. */
enum rtx_code
@@ -3494,7 +3495,7 @@ invert_jump (jump, nlabel)
return 0;
}
-/* Invert the jump condition of rtx X contained in jump insn, INSN.
+/* Invert the jump condition of rtx X contained in jump insn, INSN.
Return 1 if we can do so, 0 if we cannot find a way to do so that
matches a pattern. */
@@ -3526,7 +3527,7 @@ invert_exp (x, insn)
GET_MODE (comp), XEXP (comp, 0),
XEXP (comp, 1)), 0))
return 1;
-
+
tem = XEXP (x, 1);
validate_change (insn, &XEXP (x, 1), XEXP (x, 2), 1);
validate_change (insn, &XEXP (x, 2), tem, 1);
@@ -3784,7 +3785,7 @@ rtx_renumbered_equal_p (x, y)
register int i;
register RTX_CODE code = GET_CODE (x);
register char *fmt;
-
+
if (x == y)
return 1;
@@ -3844,7 +3845,7 @@ rtx_renumbered_equal_p (x, y)
return reg_x >= 0 && reg_x == reg_y && word_x == word_y;
}
- /* Now we have disposed of all the cases
+ /* Now we have disposed of all the cases
in which different rtx codes can match. */
if (code != GET_CODE (y))
return 0;
@@ -3988,7 +3989,7 @@ true_regnum (x)
In general, if the first test fails, the program can branch
directly to `foo' and skip the second try which is doomed to fail.
We run this after loop optimization and before flow analysis. */
-
+
/* When comparing the insn patterns, we track the fact that different
pseudo-register numbers may have been used in each computation.
The following array stores an equivalence -- same_regs[I] == J means
@@ -4010,7 +4011,7 @@ static char *modified_regs;
static int modified_mem;
-/* Called via note_stores on each insn between the target of the first
+/* Called via note_stores on each insn between the target of the first
branch and the second branch. It marks any changed registers. */
static void
@@ -4038,7 +4039,7 @@ mark_modified_reg (dest, x)
}
/* F is the first insn in the chain of insns. */
-
+
void
thread_jumps (f, max_reg, flag_before_loop)
rtx f;
@@ -4054,7 +4055,7 @@ thread_jumps (f, max_reg, flag_before_loop)
will either always succeed or always fail depending on the relative
senses of the two branches. So adjust the first branch accordingly
in this case. */
-
+
rtx label, b1, b2, t1, t2;
enum rtx_code code1, code2;
rtx b1op0, b1op1, b2op0, b2op1;
@@ -4068,7 +4069,7 @@ thread_jumps (f, max_reg, flag_before_loop)
all_reset = (int *) alloca (max_reg * sizeof (int));
for (i = 0; i < max_reg; i++)
all_reset[i] = -1;
-
+
while (changed)
{
changed = 0;
@@ -4165,7 +4166,7 @@ thread_jumps (f, max_reg, flag_before_loop)
{
t1 = prev_nonnote_insn (b1);
t2 = prev_nonnote_insn (b2);
-
+
while (t1 != 0 && t2 != 0)
{
if (t2 == label)
@@ -4202,7 +4203,7 @@ thread_jumps (f, max_reg, flag_before_loop)
}
break;
}
-
+
/* If either of these is not a normal insn (it might be
a JUMP_INSN, CALL_INSN, or CODE_LABEL) we fail. (NOTEs
have already been skipped above.) Similarly, fail
@@ -4212,7 +4213,7 @@ thread_jumps (f, max_reg, flag_before_loop)
|| ! rtx_equal_for_thread_p (PATTERN (t1),
PATTERN (t2), t2))
break;
-
+
t1 = prev_nonnote_insn (t1);
t2 = prev_nonnote_insn (t2);
}
@@ -4224,7 +4225,7 @@ thread_jumps (f, max_reg, flag_before_loop)
/* This is like RTX_EQUAL_P except that it knows about our handling of
possibly equivalent registers and knows to consider volatile and
modified objects as not equal.
-
+
YINSN is the insn containing Y. */
int
@@ -4281,7 +4282,7 @@ rtx_equal_for_thread_p (x, y, yinsn)
num_same_regs++;
/* If this is the first time we are seeing a register on the `Y'
- side, see if it is the last use. If not, we can't thread the
+ side, see if it is the last use. If not, we can't thread the
jump, so mark it as not equivalent. */
if (regno_last_uid[REGNO (y)] != INSN_UID (yinsn))
return 0;
diff --git a/gnu/usr.bin/cc/cc_int/local-alloc.c b/gnu/usr.bin/cc/cc_int/local-alloc.c
index 3b2d81e..932f3b6 100644
--- a/gnu/usr.bin/cc/cc_int/local-alloc.c
+++ b/gnu/usr.bin/cc/cc_int/local-alloc.c
@@ -47,7 +47,7 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
Tying is represented with "quantity numbers".
A non-tied register is given a new quantity number.
Tied registers have the same quantity number.
-
+
We have provision to exempt registers, even when they are contained
within the block, that can be tied to others that are not contained in it.
This is so that global_alloc could process them both and tie them then.
@@ -165,6 +165,11 @@ static enum reg_class *qty_alternate_class;
static rtx *qty_scratch_rtx;
+/* Element Q is nonzero if this quantity has been used in a SUBREG
+ that changes its size. */
+
+static char *qty_changes_size;
+
/* Element Q is the register number of one pseudo register whose
reg_qty value is Q, or -1 is this quantity is for a SCRATCH. This
register should be the head of the chain maintained in reg_next_in_qty. */
@@ -289,6 +294,7 @@ alloc_qty (regno, mode, size, birth)
qty_min_class[qty] = reg_preferred_class (regno);
qty_alternate_class[qty] = reg_alternate_class (regno);
qty_n_refs[qty] = reg_n_refs[regno];
+ qty_changes_size[qty] = reg_changes_size[regno];
}
/* Similar to `alloc_qty', but allocates a quantity for a SCRATCH rtx
@@ -329,7 +335,7 @@ alloc_qty_for_scratch (scratch, n, insn, insn_code_num, insn_number)
{
case '=': case '+': case '?':
case '#': case '&': case '!':
- case '*': case '%':
+ case '*': case '%':
case '0': case '1': case '2': case '3': case '4':
case 'm': case '<': case '>': case 'V': case 'o':
case 'E': case 'F': case 'G': case 'H':
@@ -364,7 +370,7 @@ alloc_qty_for_scratch (scratch, n, insn, insn_code_num, insn_number)
class = GENERAL_REGS;
#endif
-
+
qty = next_qty++;
@@ -378,6 +384,7 @@ alloc_qty_for_scratch (scratch, n, insn, insn_code_num, insn_number)
qty_min_class[qty] = class;
qty_alternate_class[qty] = NO_REGS;
qty_n_refs[qty] = 1;
+ qty_changes_size[qty] = 0;
}
/* Main entry point of this file. */
@@ -439,6 +446,7 @@ local_alloc ()
qty_alternate_class
= (enum reg_class *) alloca (max_qty * sizeof (enum reg_class));
qty_n_refs = (int *) alloca (max_qty * sizeof (int));
+ qty_changes_size = (char *) alloca (max_qty * sizeof (char));
reg_qty = (int *) alloca (max_regno * sizeof (int));
reg_offset = (char *) alloca (max_regno * sizeof (char));
@@ -681,7 +689,7 @@ memref_used_between_p (memref, start, end)
Search forward to see if SRC dies before either it or DEST is modified,
but don't scan past the end of a basic block. If so, we can replace SRC
- with DEST and let SRC die in INSN.
+ with DEST and let SRC die in INSN.
This will reduce the number of registers live in that range and may enable
DEST to be tied to SRC, thus often saving one register in addition to a
@@ -925,7 +933,7 @@ optimize_reg_copy_2 (insn, dest, src)
break;
}
}
-
+
/* Find registers that are equivalent to a single value throughout the
compilation (either because they can be referenced in memory or are set once
from a single constant). Lower their priority for a register.
@@ -1036,7 +1044,7 @@ update_equiv_regs ()
a register used only in one basic block from a MEM. If so, and the
MEM remains unchanged for the life of the register, add a REG_EQUIV
note. */
-
+
note = find_reg_note (insn, REG_EQUIV, NULL_RTX);
if (note == 0 && reg_basic_block[regno] >= 0
@@ -1244,7 +1252,7 @@ block_alloc (b)
continue;
/* Likewise if each alternative has some operand that
- must match operand zero. In that case, skip any
+ must match operand zero. In that case, skip any
operand that doesn't list operand 0 since we know that
the operand always conflicts with operand 0. We
ignore commutatity in this case to keep things simple. */
@@ -1281,7 +1289,7 @@ block_alloc (b)
|| (r1 == recog_operand[i] && must_match_0 >= 0)
#endif
);
-
+
if (GET_CODE (r1) == REG || GET_CODE (r1) == SUBREG)
win = combine_regs (r1, r0, may_save_copy,
insn_number, insn, 0);
@@ -1389,7 +1397,7 @@ block_alloc (b)
alloc_qty_for_scratch (recog_operand[i], i, insn,
insn_code_number, insn_number);
- /* If this is an insn that has a REG_RETVAL note pointing at a
+ /* If this is an insn that has a REG_RETVAL note pointing at a
CLOBBER insn, we have reached the end of a REG_NO_CONFLICT
block, so clear any register number that combined within it. */
if ((note = find_reg_note (insn, REG_RETVAL, NULL_RTX)) != 0
@@ -1413,7 +1421,7 @@ block_alloc (b)
/* Now every register that is local to this basic block
should have been given a quantity, or else -1 meaning ignore it.
- Every quantity should have a known birth and death.
+ Every quantity should have a known birth and death.
Order the qtys so we assign them registers in order of the
number of suggested registers they need so we allocate those with
@@ -1465,8 +1473,8 @@ block_alloc (b)
qty_phys_reg[q] = -1;
}
- /* Order the qtys so we assign them registers in order of
- decreasing length of life. Normally call qsort, but if we
+ /* Order the qtys so we assign them registers in order of
+ decreasing length of life. Normally call qsort, but if we
have only a very small number of quantities, sort them ourselves. */
for (i = 0; i < next_qty; i++)
@@ -1513,7 +1521,7 @@ block_alloc (b)
{
if (N_REG_CLASSES > 1)
{
- qty_phys_reg[q] = find_free_reg (qty_min_class[q],
+ qty_phys_reg[q] = find_free_reg (qty_min_class[q],
qty_mode[q], q, 0, 0,
qty_birth[q], qty_death[q]);
if (qty_phys_reg[q] >= 0)
@@ -1643,7 +1651,7 @@ qty_sugg_compare (q1, q2)
if (sugg1 != sugg2)
return sugg1 - sugg2;
-
+
return pri2 - pri1;
}
@@ -1675,7 +1683,7 @@ qty_sugg_compare_1 (q1, q2)
if (sugg1 != sugg2)
return sugg1 - sugg2;
-
+
if (pri1 != pri2)
return pri2 - pri1;
@@ -1703,10 +1711,10 @@ qty_sugg_compare_1 (q1, q2)
MAY_SAVE_COPYCOPY is non-zero if this insn is simply copying USEDREG to
SETREG or if the input and output must share a register.
In that case, we record a hard reg suggestion in QTY_PHYS_COPY_SUGG.
-
+
There are elaborate checks for the validity of combining. */
-
+
static int
combine_regs (usedreg, setreg, may_save_copy, insn_number, insn, already_dead)
rtx usedreg, setreg;
@@ -1925,6 +1933,9 @@ update_qty_class (qty, reg)
rclass = reg_alternate_class (reg);
if (reg_class_subset_p (rclass, qty_alternate_class[qty]))
qty_alternate_class[qty] = rclass;
+
+ if (reg_changes_size[reg])
+ qty_changes_size[qty] = 1;
}
/* Handle something which alters the value of an rtx REG.
@@ -1964,7 +1975,7 @@ reg_is_born (reg, birth)
int birth;
{
register int regno;
-
+
if (GET_CODE (reg) == SUBREG)
regno = REGNO (SUBREG_REG (reg)) + SUBREG_WORD (reg);
else
@@ -2042,7 +2053,7 @@ wipe_dead_reg (reg, output_p)
(but actually we test only the first of the block for holding MODE)
and still free between insn BORN_INDEX and insn DEAD_INDEX,
and return the number of the first of them.
- Return -1 if such a block cannot be found.
+ Return -1 if such a block cannot be found.
If QTY crosses calls, insist on a register preserved by calls,
unless ACCEPT_CALL_CLOBBERED is nonzero.
@@ -2108,6 +2119,12 @@ find_free_reg (class, mode, qty, accept_call_clobbered, just_try_suggested,
SET_HARD_REG_BIT (used, FRAME_POINTER_REGNUM);
#endif
+#ifdef CLASS_CANNOT_CHANGE_SIZE
+ if (qty_changes_size[qty])
+ IOR_HARD_REG_SET (used,
+ reg_class_contents[(int) CLASS_CANNOT_CHANGE_SIZE]);
+#endif
+
/* Normally, the registers that can be used for the first register in
a multi-register quantity are the same as those that can be used for
subsequent registers. However, if just trying suggested registers,
@@ -2160,7 +2177,7 @@ find_free_reg (class, mode, qty, accept_call_clobbered, just_try_suggested,
/* If we are just trying suggested register, we have just tried copy-
suggested registers, and there are arithmetic-suggested registers,
try them. */
-
+
/* If it would be profitable to allocate a call-clobbered register
and save and restore it around calls, do that. */
if (just_try_suggested && qty_phys_num_copy_sugg[qty] != 0
@@ -2281,7 +2298,7 @@ no_conflict_p (insn, r0, r1)
&& ! find_reg_note (p, REG_NO_CONFLICT, r1))
return 0;
}
-
+
return ok;
}
diff --git a/gnu/usr.bin/cc/cc_int/loop.c b/gnu/usr.bin/cc/cc_int/loop.c
index c6caefe..1e65cde 100644
--- a/gnu/usr.bin/cc/cc_int/loop.c
+++ b/gnu/usr.bin/cc/cc_int/loop.c
@@ -20,7 +20,7 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
/* This is the loop optimization pass of the compiler.
It finds invariant computations within loops and moves them
- to the beginning of the loop. Then it identifies basic and
+ to the beginning of the loop. Then it identifies basic and
general induction variables. Strength reduction is applied to the general
induction variables, and induction variable elimination is applied to
the basic induction variables.
@@ -205,7 +205,7 @@ struct movable
rtx set_dest; /* The destination of this SET. */
rtx dependencies; /* When INSN is libcall, this is an EXPR_LIST
of any registers used within the LIBCALL. */
- int consec; /* Number of consecutive following insns
+ int consec; /* Number of consecutive following insns
that must be moved with this one. */
int regno; /* The register it sets */
short lifetime; /* lifetime of that register;
@@ -221,7 +221,7 @@ struct movable
that the reg is live outside the range from where it is set
to the following label. */
unsigned int done : 1; /* 1 inhibits further processing of this */
-
+
unsigned int partial : 1; /* 1 means this reg is used for zero-extending.
In particular, moving it does not make it
invariant. */
@@ -506,7 +506,7 @@ scan_loop (loop_start, end, nregs)
Note that if we mistakenly think that a loop is entered at the top
when, in fact, it is entered at the exit test, the only effect will be
slightly poorer optimization. Making the opposite error can generate
- incorrect code. Since very few loops now start with a jump to the
+ incorrect code. Since very few loops now start with a jump to the
exit test, the code here to detect that case is very conservative. */
for (p = NEXT_INSN (loop_start);
@@ -553,7 +553,7 @@ scan_loop (loop_start, end, nregs)
/* If SCAN_START was an insn created by loop, we don't know its luid
as required by loop_reg_used_before_p. So skip such loops. (This
- test may never be true, but it's best to play it safe.)
+ test may never be true, but it's best to play it safe.)
Also, skip loops where we do not start scanning at a label. This
test also rejects loops starting with a JUMP_INSN that failed the
@@ -658,7 +658,7 @@ scan_loop (loop_start, end, nregs)
temp = find_reg_note (p, REG_EQUIV, NULL_RTX);
if (temp)
src = XEXP (temp, 0), move_insn = 1;
- else
+ else
{
temp = find_reg_note (p, REG_EQUAL, NULL_RTX);
if (temp && CONSTANT_P (XEXP (temp, 0)))
@@ -715,12 +715,12 @@ scan_loop (loop_start, end, nregs)
can be combined as long as they are both in the loop, but
we move one of them outside the loop. For large loops,
this can lose. The most common case of this is the address
- of a function being called.
+ of a function being called.
Therefore, if this register is marked as being used exactly
once if we are in a loop with calls (a "large loop"), see if
we can replace the usage of this register with the source
- of this SET. If we can, delete this insn.
+ of this SET. If we can, delete this insn.
Don't do this if P has a REG_RETVAL note or if we have
SMALL_REGISTER_CLASSES and SET_SRC is a hard register. */
@@ -750,7 +750,7 @@ scan_loop (loop_start, end, nregs)
REG_NOTES (reg_single_usage[regno])
= replace_rtx (REG_NOTES (reg_single_usage[regno]),
SET_DEST (set), SET_SRC (set));
-
+
PUT_CODE (p, NOTE);
NOTE_LINE_NUMBER (p) = NOTE_INSN_DELETED;
NOTE_SOURCE_FILE (p) = 0;
@@ -950,7 +950,7 @@ scan_loop (loop_start, end, nregs)
all together as the priority of the first. */
combine_movables (movables, nregs);
-
+
/* Now consider each movable insn to decide whether it is worth moving.
Store 0 in n_times_set for each reg that is moved. */
@@ -1049,7 +1049,7 @@ libcall_other_reg (insn, equiv)
/* Return 1 if all uses of REG
are between INSN and the end of the basic block. */
-static int
+static int
reg_in_basic_block_p (insn, reg)
rtx insn, reg;
{
@@ -1130,7 +1130,7 @@ skip_consec_insns (insn, count)
rtx temp;
/* If first insn of libcall sequence, skip to end. */
- /* Do this at start of loop, since INSN is guaranteed to
+ /* Do this at start of loop, since INSN is guaranteed to
be an insn here. */
if (GET_CODE (insn) != NOTE
&& (temp = find_reg_note (insn, REG_LIBCALL, NULL_RTX)))
@@ -1173,7 +1173,7 @@ ignore_some_movables (movables)
m1->done = 1;
}
}
-}
+}
/* For each movable insn, see if the reg that it loads
leads when it dies right into another conditionally movable insn.
@@ -1685,6 +1685,8 @@ move_movables (movables, threshold, insn_count, loop_start, end, nregs)
}
p = delete_insn (p);
+ while (p && GET_CODE (p) == NOTE)
+ p = NEXT_INSN (p);
}
start_sequence ();
@@ -1714,7 +1716,7 @@ move_movables (movables, threshold, insn_count, loop_start, end, nregs)
rtx i1, temp;
/* If first insn of libcall sequence, skip to end. */
- /* Do this at start of loop, since p is guaranteed to
+ /* Do this at start of loop, since p is guaranteed to
be an insn here. */
if (GET_CODE (p) != NOTE
&& (temp = find_reg_note (p, REG_LIBCALL, NULL_RTX)))
@@ -1751,7 +1753,7 @@ move_movables (movables, threshold, insn_count, loop_start, end, nregs)
&& GET_CODE (PATTERN (next)) == USE)
&& GET_CODE (next) != NOTE)
break;
-
+
/* If that is the call, this may be the insn
that loads the function address.
@@ -1791,8 +1793,9 @@ move_movables (movables, threshold, insn_count, loop_start, end, nregs)
/* Because the USAGE information potentially
contains objects other than hard registers
we need to copy it. */
- CALL_INSN_FUNCTION_USAGE (i1) =
- copy_rtx (CALL_INSN_FUNCTION_USAGE (temp));
+ if (CALL_INSN_FUNCTION_USAGE (temp))
+ CALL_INSN_FUNCTION_USAGE (i1) =
+ copy_rtx (CALL_INSN_FUNCTION_USAGE (temp));
}
else
i1 = emit_insn_before (body, loop_start);
@@ -1812,7 +1815,7 @@ move_movables (movables, threshold, insn_count, loop_start, end, nregs)
rtx reg = m->set_dest;
rtx sequence;
rtx tem;
-
+
start_sequence ();
tem = expand_binop
(GET_MODE (reg), and_optab, reg,
@@ -1834,8 +1837,9 @@ move_movables (movables, threshold, insn_count, loop_start, end, nregs)
/* Because the USAGE information potentially
contains objects other than hard registers
we need to copy it. */
- CALL_INSN_FUNCTION_USAGE (i1) =
- copy_rtx (CALL_INSN_FUNCTION_USAGE (p));
+ if (CALL_INSN_FUNCTION_USAGE (p))
+ CALL_INSN_FUNCTION_USAGE (i1) =
+ copy_rtx (CALL_INSN_FUNCTION_USAGE (p));
}
else
i1 = emit_insn_before (PATTERN (p), loop_start);
@@ -1847,7 +1851,7 @@ move_movables (movables, threshold, insn_count, loop_start, end, nregs)
cause problems with later optimization passes.
It is possible for cse to create such notes
like this as a result of record_jump_cond. */
-
+
if ((temp = find_reg_note (i1, REG_EQUAL, NULL_RTX))
&& ! invariant_p (XEXP (temp, 0)))
remove_note (i1, temp);
@@ -1934,7 +1938,7 @@ move_movables (movables, threshold, insn_count, loop_start, end, nregs)
reg_map[m1->regno]
= gen_lowpart_common (GET_MODE (m1->set_dest),
m->set_dest);
-
+
/* Get rid of the matching insn
and prevent further processing of it. */
m1->done = 1;
@@ -2284,7 +2288,7 @@ find_and_verify_loops (f)
anywhere.
Also look for blocks of code ending in an unconditional branch that
- exits the loop. If such a block is surrounded by a conditional
+ exits the loop. If such a block is surrounded by a conditional
branch around the block, move the block elsewhere (see below) and
invert the jump to point to the code block. This may eliminate a
label in our loop and will simplify processing by both us and a
@@ -2530,7 +2534,7 @@ mark_loop_jump (x, loop_num)
fprintf (loop_dump_stream,
"\nLoop at %d ignored due to multiple entry points.\n",
INSN_UID (loop_number_loop_starts[dest_loop]));
-
+
loop_invalid[dest_loop] = 1;
}
return;
@@ -2885,7 +2889,7 @@ find_single_use_in_loop (insn, x, usage)
{
/* Don't count SET_DEST if it is a REG; otherwise count things
in SET_DEST because if a register is partially modified, it won't
- show up as a potential movable so we don't care how USAGE is set
+ show up as a potential movable so we don't care how USAGE is set
for it. */
if (GET_CODE (SET_DEST (x)) != REG)
find_single_use_in_loop (insn, SET_DEST (x), usage);
@@ -3196,9 +3200,9 @@ strength_reduce (scan_start, end, loop_top, insn_count,
/* Save insn immediately after the loop_end. Insns inserted after loop_end
must be put before this insn, so that they will appear in the right
- order (i.e. loop order).
+ order (i.e. loop order).
- If loop_end is the end of the current function, then emit a
+ If loop_end is the end of the current function, then emit a
NOTE_INSN_DELETED after loop_end and set end_insert_before to the
dummy note insn. */
if (NEXT_INSN (loop_end) != 0)
@@ -3356,7 +3360,7 @@ strength_reduce (scan_start, end, loop_top, insn_count,
? "not induction variable"
: (! bl->incremented ? "never incremented"
: "count error")));
-
+
reg_iv_type[bl->regno] = NOT_BASIC_INDUCT;
*backbl = bl->next;
}
@@ -3816,7 +3820,7 @@ strength_reduce (scan_start, end, loop_top, insn_count,
/* Rescan all givs. If a giv is the same as a giv not reduced, mark it
as not reduced.
-
+
For each giv register that can be reduced now: if replaceable,
substitute reduced reg wherever the old giv occurs;
else add new move insn "giv_reg = reduced_reg".
@@ -3953,11 +3957,11 @@ strength_reduce (scan_start, end, loop_top, insn_count,
We have to be careful that we didn't initially think we could eliminate
this biv because of a giv that we now think may be dead and shouldn't
- be used as a biv replacement.
+ be used as a biv replacement.
Also, there is the possibility that we may have a giv that looks
like it can be used to eliminate a biv, but the resulting insn
- isn't valid. This can happen, for example, on the 88k, where a
+ isn't valid. This can happen, for example, on the 88k, where a
JUMP_INSN can compare a register only with zero. Attempts to
replace it with a compare with a constant will fail.
@@ -4033,7 +4037,7 @@ strength_reduce (scan_start, end, loop_top, insn_count,
/* Unroll loops from within strength reduction so that we can use the
induction variable information that strength_reduce has already
collected. */
-
+
if (flag_unroll_loops)
unroll_loop (loop_end, insn_count, loop_start, end_insert_before, 1);
@@ -4387,7 +4391,7 @@ record_giv (v, insn, src_reg, dest_reg, mult_val, add_val, benefit,
/* Check each biv update, and fail if any are between the first
and last use of the giv.
-
+
If this loop contains an inner loop that was unrolled, then
the insn modifying the biv may have been emitted by the loop
unrolling code, and hence does not have a valid luid. Just
@@ -4595,7 +4599,7 @@ check_final_value (v, loop_start, loop_end)
last_giv_use = p;
}
}
-
+
/* Now that the lifetime of the giv is known, check for branches
from within the lifetime to outside the lifetime if it is still
replaceable. */
@@ -4770,7 +4774,7 @@ update_giv_derive (p)
Note that treating the entire pseudo as a BIV will result in making
simple increments to any GIVs based on it. However, if the variable
overflows in its declared mode but not its promoted mode, the result will
- be incorrect. This is acceptable if the variable is signed, since
+ be incorrect. This is acceptable if the variable is signed, since
overflows in such cases are undefined, but not if it is unsigned, since
those overflows are defined. So we only check for SIGN_EXTEND and
not ZERO_EXTEND.
@@ -5013,7 +5017,7 @@ general_induction_var (x, src_reg, add_val, mult_val)
returns 0.
For a non-zero return, the result will have a code of CONST_INT, USE,
- REG (for a BIV), PLUS, or MULT. No other codes will occur.
+ REG (for a BIV), PLUS, or MULT. No other codes will occur.
*BENEFIT will be incremented by the benefit of any sub-giv encountered. */
@@ -5297,7 +5301,7 @@ consec_sets_giv (first_benefit, p, src_reg, dest_reg,
rtx set;
/* Indicate that this is a giv so that we can update the value produced in
- each insn of the multi-insn sequence.
+ each insn of the multi-insn sequence.
This induction structure will be used only by the call to
general_induction_var below, so we can allocate it on our stack.
@@ -5367,7 +5371,7 @@ consec_sets_giv (first_benefit, p, src_reg, dest_reg,
/* Return an rtx, if any, that expresses giv G2 as a function of the register
represented by G1. If no such expression can be found, or it is clear that
- it cannot possibly be a valid address, 0 is returned.
+ it cannot possibly be a valid address, 0 is returned.
To perform the computation, we note that
G1 = a * v + b and
@@ -5828,7 +5832,7 @@ check_dbra_loop (loop_end, insn_count, loop_start)
p = emit_insn_before (gen_add2_insn (reg, new_add_val),
bl->biv->insn);
delete_insn (bl->biv->insn);
-
+
/* Update biv info to reflect its new status. */
bl->biv->insn = p;
bl->initial_value = start_value;
@@ -6075,6 +6079,10 @@ maybe_eliminate_biv_1 (x, insn, bl, eliminate_p, where)
else
break;
+#if 0 /* XXX patch to correct strength-reduction problem from
+ * Richard Henderson <richard@atheist.tamu.edu> incorporated
+ * 3 Jan 1996 - jkh@FreeBSD.org
+ */
if (CONSTANT_P (arg))
{
/* First try to replace with any giv that has constant positive
@@ -6114,7 +6122,7 @@ maybe_eliminate_biv_1 (x, insn, bl, eliminate_p, where)
/* If that failed, put back the change we made above. */
XEXP (x, 1-arg_operand) = reg;
}
-
+
/* Look for giv with positive constant mult_val and nonconst add_val.
Insert insns to calculate new compare value. */
@@ -6220,6 +6228,7 @@ maybe_eliminate_biv_1 (x, insn, bl, eliminate_p, where)
}
#endif
}
+#endif
/* If we get here, the biv can't be eliminated. */
return 0;
@@ -6240,7 +6249,7 @@ maybe_eliminate_biv_1 (x, insn, bl, eliminate_p, where)
switch (fmt[i])
{
case 'e':
- if (! maybe_eliminate_biv_1 (XEXP (x, i), insn, bl,
+ if (! maybe_eliminate_biv_1 (XEXP (x, i), insn, bl,
eliminate_p, where))
return 0;
break;
@@ -6255,7 +6264,7 @@ maybe_eliminate_biv_1 (x, insn, bl, eliminate_p, where)
}
return 1;
-}
+}
/* Return nonzero if the last use of REG
is in an insn following INSN in the same basic block. */
diff --git a/gnu/usr.bin/cc/cc_int/obstack.c b/gnu/usr.bin/cc/cc_int/obstack.c
index a8a4500..bf18ddc 100644
--- a/gnu/usr.bin/cc/cc_int/obstack.c
+++ b/gnu/usr.bin/cc/cc_int/obstack.c
@@ -31,7 +31,7 @@ Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
#if defined (_LIBC) || !defined (__GNU_LIBRARY__)
-#ifdef __STDC__
+#if defined (__STDC__) && __STDC__
#define POINTER void *
#else
#define POINTER char *
@@ -267,7 +267,7 @@ _obstack_newchunk (h, length)
This is here for debugging.
If you use it in a program, you are probably losing. */
-#ifdef __STDC__
+#if defined (__STDC__) && __STDC__
/* Suppress -Wmissing-prototypes warning. We don't want to declare this in
obstack.h because it is just for debugging. */
int _obstack_allocated_p (struct obstack *h, POINTER obj);
@@ -374,7 +374,7 @@ obstack_free (h, obj)
/* Now define the functional versions of the obstack macros.
Define them to simply use the corresponding macros to do the job. */
-#ifdef __STDC__
+#if defined (__STDC__) && __STDC__
/* These function definitions do not work with non-ANSI preprocessors;
they won't pass through the macro names in parentheses. */
diff --git a/gnu/usr.bin/cc/cc_int/optabs.c b/gnu/usr.bin/cc/cc_int/optabs.c
index 427ccf4..ac7230e 100644
--- a/gnu/usr.bin/cc/cc_int/optabs.c
+++ b/gnu/usr.bin/cc/cc_int/optabs.c
@@ -117,6 +117,13 @@ rtx bcmp_libfunc;
rtx memset_libfunc;
rtx bzero_libfunc;
+rtx eqhf2_libfunc;
+rtx nehf2_libfunc;
+rtx gthf2_libfunc;
+rtx gehf2_libfunc;
+rtx lthf2_libfunc;
+rtx lehf2_libfunc;
+
rtx eqsf2_libfunc;
rtx nesf2_libfunc;
rtx gtsf2_libfunc;
@@ -274,7 +281,7 @@ add_equal_note (seq, target, code, op0, op1)
/* Widen OP to MODE and return the rtx for the widened operand. UNSIGNEDP
says whether OP is signed or unsigned. NO_EXTEND is nonzero if we need
- not actually do a sign-extend or zero-extend, but can leave the
+ not actually do a sign-extend or zero-extend, but can leave the
higher-order bits of the result rtx undefined, for example, in the case
of logical operations, but not right shifts. */
@@ -689,13 +696,6 @@ expand_binop (mode, binoptab, op0, op1, target, unsignedp, methods)
if (carries == 0)
inter = 0;
else
- inter = expand_binop (word_mode, binoptab, outof_input,
- op1, outof_target, unsignedp, next_methods);
-
- if (inter != 0 && inter != outof_target)
- emit_move_insn (outof_target, inter);
-
- if (inter != 0)
inter = expand_binop (word_mode, unsigned_shift, into_input,
op1, 0, unsignedp, next_methods);
@@ -705,6 +705,13 @@ expand_binop (mode, binoptab, op0, op1, target, unsignedp, methods)
if (inter != 0 && inter != into_target)
emit_move_insn (into_target, inter);
+
+ if (inter != 0)
+ inter = expand_binop (word_mode, binoptab, outof_input,
+ op1, outof_target, unsignedp, next_methods);
+
+ if (inter != 0 && inter != outof_target)
+ emit_move_insn (outof_target, inter);
}
insns = get_insns ();
@@ -938,7 +945,7 @@ expand_binop (mode, binoptab, op0, op1, target, unsignedp, methods)
}
carry_in = carry_out;
- }
+ }
if (i == GET_MODE_BITSIZE (mode) / BITS_PER_WORD)
{
@@ -958,7 +965,7 @@ expand_binop (mode, binoptab, op0, op1, target, unsignedp, methods)
/* If we want to multiply two two-word values and have normal and widening
multiplies of single-word values, we can do this with three smaller
multiplications. Note that we do not make a REG_NO_CONFLICT block here
- because we are not operating on one word at a time.
+ because we are not operating on one word at a time.
The multiplication proceeds as follows:
_______________________
@@ -1108,7 +1115,7 @@ expand_binop (mode, binoptab, op0, op1, target, unsignedp, methods)
emit_move_insn (product_high, temp);
if (temp != 0)
- temp = expand_binop (word_mode, binoptab, op1_low, op0_xhigh,
+ temp = expand_binop (word_mode, binoptab, op1_low, op0_xhigh,
NULL_RTX, 0, OPTAB_DIRECT);
if (temp != 0)
@@ -1260,8 +1267,10 @@ expand_binop (mode, binoptab, op0, op1, target, unsignedp, methods)
NULL_RTX, unsignedp, methods);
if (temp1 == 0 || temp2 == 0)
- res = expand_binop (submode, add_optab, temp1, temp2,
- imagr, unsignedp, methods);
+ break;
+
+ res = expand_binop (submode, add_optab, temp1, temp2,
+ imagr, unsignedp, methods);
if (res == 0)
break;
@@ -1301,7 +1310,7 @@ expand_binop (mode, binoptab, op0, op1, target, unsignedp, methods)
case DIV:
/* (a+ib) / (c+id) = ((ac+bd)/(cc+dd)) + i((bc-ad)/(cc+dd)) */
-
+
if (imag1 == 0)
{
/* (a+ib) / (c+i0) = (a/c) + i(b/c) */
@@ -1344,7 +1353,7 @@ expand_binop (mode, binoptab, op0, op1, target, unsignedp, methods)
rtx real_t, imag_t;
rtx lhs, rhs;
rtx temp1, temp2;
-
+
/* Don't fetch these from memory more than once. */
real0 = force_reg (submode, real0);
real1 = force_reg (submode, real1);
@@ -1377,7 +1386,7 @@ expand_binop (mode, binoptab, op0, op1, target, unsignedp, methods)
/* Calculate the dividend */
real_t = expand_binop (submode, smul_optab, real0, real1,
NULL_RTX, unsignedp, methods);
-
+
imag_t = expand_binop (submode, smul_optab, real0, imag1,
NULL_RTX, unsignedp, methods);
@@ -1402,7 +1411,7 @@ expand_binop (mode, binoptab, op0, op1, target, unsignedp, methods)
real_t = expand_binop (submode, add_optab, temp1, temp2,
NULL_RTX, unsignedp, methods);
-
+
temp1 = expand_binop (submode, smul_optab, imag0, real1,
NULL_RTX, unsignedp, methods);
@@ -1446,7 +1455,7 @@ expand_binop (mode, binoptab, op0, op1, target, unsignedp, methods)
ok = 1;
}
break;
-
+
default:
abort ();
}
@@ -1461,9 +1470,9 @@ expand_binop (mode, binoptab, op0, op1, target, unsignedp, methods)
= gen_rtx (binoptab->code, mode, copy_rtx (op0), copy_rtx (op1));
else
equiv_value = 0;
-
+
emit_no_conflict_block (seq, target, op0, op1, equiv_value);
-
+
return target;
}
}
@@ -1727,7 +1736,7 @@ expand_twoval_binop (binoptab, op0, op1, targ0, targ1, unsignedp)
if (! (*insn_operand_predicate[icode][0]) (targ0, mode)
|| ! (*insn_operand_predicate[icode][3]) (targ1, mode))
abort ();
-
+
pat = GEN_FCN (icode) (targ0, xop0, xop1, targ1);
if (pat)
{
@@ -1843,7 +1852,7 @@ expand_unop (mode, unoptab, op0, target, unsignedp)
}
emit_insn (pat);
-
+
return temp;
}
else
@@ -1868,7 +1877,7 @@ expand_unop (mode, unoptab, op0, target, unsignedp)
(unoptab == neg_optab
|| unoptab == one_cmpl_optab)
&& class == MODE_INT);
-
+
temp = expand_unop (wider_mode, unoptab, xop0, NULL_RTX,
unsignedp);
@@ -1941,7 +1950,7 @@ expand_unop (mode, unoptab, op0, target, unsignedp)
if (target == 0)
target = gen_reg_rtx (mode);
-
+
start_sequence ();
target_piece = gen_imagpart (submode, target);
@@ -2010,7 +2019,7 @@ expand_unop (mode, unoptab, op0, target, unsignedp)
(unoptab == neg_optab
|| unoptab == one_cmpl_optab)
&& class == MODE_INT);
-
+
temp = expand_unop (wider_mode, unoptab, xop0, NULL_RTX,
unsignedp);
@@ -2042,6 +2051,90 @@ expand_unop (mode, unoptab, op0, target, unsignedp)
MODE is the mode of the operand; the mode of the result is
different but can be deduced from MODE.
+ UNSIGNEDP is relevant if extension is needed. */
+
+rtx
+expand_abs (mode, op0, target, unsignedp, safe)
+ enum machine_mode mode;
+ rtx op0;
+ rtx target;
+ int unsignedp;
+ int safe;
+{
+ rtx temp, op1;
+
+ /* First try to do it with a special abs instruction. */
+ temp = expand_unop (mode, abs_optab, op0, target, 0);
+ if (temp != 0)
+ return temp;
+
+ /* If this machine has expensive jumps, we can do integer absolute
+ value of X as (((signed) x >> (W-1)) ^ x) - ((signed) x >> (W-1)),
+ where W is the width of MODE. */
+
+ if (GET_MODE_CLASS (mode) == MODE_INT && BRANCH_COST >= 2)
+ {
+ rtx extended = expand_shift (RSHIFT_EXPR, mode, op0,
+ size_int (GET_MODE_BITSIZE (mode) - 1),
+ NULL_RTX, 0);
+
+ temp = expand_binop (mode, xor_optab, extended, op0, target, 0,
+ OPTAB_LIB_WIDEN);
+ if (temp != 0)
+ temp = expand_binop (mode, sub_optab, temp, extended, target, 0,
+ OPTAB_LIB_WIDEN);
+
+ if (temp != 0)
+ return temp;
+ }
+
+ /* If that does not win, use conditional jump and negate. */
+ op1 = gen_label_rtx ();
+ if (target == 0 || ! safe
+ || GET_MODE (target) != mode
+ || (GET_CODE (target) == MEM && MEM_VOLATILE_P (target))
+ || (GET_CODE (target) == REG
+ && REGNO (target) < FIRST_PSEUDO_REGISTER))
+ target = gen_reg_rtx (mode);
+
+ emit_move_insn (target, op0);
+ NO_DEFER_POP;
+
+ /* If this mode is an integer too wide to compare properly,
+ compare word by word. Rely on CSE to optimize constant cases. */
+ if (GET_MODE_CLASS (mode) == MODE_INT && ! can_compare_p (mode))
+ do_jump_by_parts_greater_rtx (mode, 0, target, const0_rtx,
+ NULL_RTX, op1);
+ else
+ {
+ temp = compare_from_rtx (target, CONST0_RTX (mode), GE, 0, mode,
+ NULL_RTX, 0);
+ if (temp == const1_rtx)
+ return target;
+ else if (temp != const0_rtx)
+ {
+ if (bcc_gen_fctn[(int) GET_CODE (temp)] != 0)
+ emit_jump_insn ((*bcc_gen_fctn[(int) GET_CODE (temp)]) (op1));
+ else
+ abort ();
+ }
+ }
+
+ op0 = expand_unop (mode, neg_optab, target, target, 0);
+ if (op0 != target)
+ emit_move_insn (target, op0);
+ emit_label (op1);
+ OK_DEFER_POP;
+ return target;
+}
+
+/* Emit code to compute the absolute value of OP0, with result to
+ TARGET if convenient. (TARGET may be 0.) The return value says
+ where the result actually is to be found.
+
+ MODE is the mode of the operand; the mode of the result is
+ different but can be deduced from MODE.
+
UNSIGNEDP is relevant for complex integer modes. */
rtx
@@ -2113,7 +2206,7 @@ expand_complex_abs (mode, op0, target, unsignedp)
}
emit_insn (pat);
-
+
return temp;
}
else
@@ -2270,7 +2363,7 @@ emit_unop_insn (icode, target, op0, code)
if (GET_CODE (pat) == SEQUENCE && code != UNKNOWN)
add_equal_note (pat, temp, code, op0, NULL_RTX);
-
+
emit_insn (pat);
if (temp != target)
@@ -2291,9 +2384,7 @@ emit_unop_insn (icode, target, op0, code)
INSNS is a block of code generated to perform the operation, not including
the CLOBBER and final copy. All insns that compute intermediate values
- are first emitted, followed by the block as described above. Only
- INSNs are allowed in the block; no library calls or jumps may be
- present.
+ are first emitted, followed by the block as described above.
TARGET, OP0, and OP1 are the output and inputs of the operations,
respectively. OP1 may be zero for a unary operation.
@@ -2302,7 +2393,8 @@ emit_unop_insn (icode, target, op0, code)
on the last insn.
If TARGET is not a register, INSNS is simply emitted with no special
- processing.
+ processing. Likewise if anything in INSNS is not an INSN or if
+ there is a libcall block inside INSNS.
The final insn emitted is returned. */
@@ -2317,6 +2409,11 @@ emit_no_conflict_block (insns, target, op0, op1, equiv)
if (GET_CODE (target) != REG || reload_in_progress)
return emit_insns (insns);
+ else
+ for (insn = insns; insn; insn = NEXT_INSN (insn))
+ if (GET_CODE (insn) != INSN
+ || find_reg_note (insn, REG_LIBCALL, NULL_RTX))
+ return emit_insns (insns);
/* First emit all insns that do not store into words of the output and remove
these from the list. */
@@ -2327,9 +2424,6 @@ emit_no_conflict_block (insns, target, op0, op1, equiv)
next = NEXT_INSN (insn);
- if (GET_CODE (insn) != INSN)
- abort ();
-
if (GET_CODE (PATTERN (insn)) == SET)
set = PATTERN (insn);
else if (GET_CODE (PATTERN (insn)) == PARALLEL)
@@ -2760,7 +2854,34 @@ emit_float_lib_cmp (x, y, comparison)
enum machine_mode mode = GET_MODE (x);
rtx libfunc = 0;
- if (mode == SFmode)
+ if (mode == HFmode)
+ switch (comparison)
+ {
+ case EQ:
+ libfunc = eqhf2_libfunc;
+ break;
+
+ case NE:
+ libfunc = nehf2_libfunc;
+ break;
+
+ case GT:
+ libfunc = gthf2_libfunc;
+ break;
+
+ case GE:
+ libfunc = gehf2_libfunc;
+ break;
+
+ case LT:
+ libfunc = lthf2_libfunc;
+ break;
+
+ case LE:
+ libfunc = lehf2_libfunc;
+ break;
+ }
+ else if (mode == SFmode)
switch (comparison)
{
case EQ:
@@ -2927,7 +3048,7 @@ rtx
gen_add2_insn (x, y)
rtx x, y;
{
- int icode = (int) add_optab->handlers[(int) GET_MODE (x)].insn_code;
+ int icode = (int) add_optab->handlers[(int) GET_MODE (x)].insn_code;
if (! (*insn_operand_predicate[icode][0]) (x, insn_operand_mode[icode][0])
|| ! (*insn_operand_predicate[icode][1]) (x, insn_operand_mode[icode][1])
@@ -2950,7 +3071,7 @@ rtx
gen_sub2_insn (x, y)
rtx x, y;
{
- int icode = (int) sub_optab->handlers[(int) GET_MODE (x)].insn_code;
+ int icode = (int) sub_optab->handlers[(int) GET_MODE (x)].insn_code;
if (! (*insn_operand_predicate[icode][0]) (x, insn_operand_mode[icode][0])
|| ! (*insn_operand_predicate[icode][1]) (x, insn_operand_mode[icode][1])
@@ -2979,7 +3100,7 @@ gen_move_insn (x, y)
rtx seq;
if (mode == VOIDmode)
- mode = GET_MODE (y);
+ mode = GET_MODE (y);
insn_code = mov_optab->handlers[(int) mode].insn_code;
@@ -3038,7 +3159,7 @@ gen_move_insn (x, y)
x = gen_lowpart (tmode, x);
y = gen_lowpart (tmode, y);
}
-
+
insn_code = mov_optab->handlers[(int) tmode].insn_code;
return (GEN_FCN (insn_code) (x, y));
}
@@ -3204,7 +3325,7 @@ expand_float (to, from, unsignedp)
rtx temp1;
rtx neglabel = gen_label_rtx ();
- /* Don't use TARGET if it isn't a register, is a hard register,
+ /* Don't use TARGET if it isn't a register, is a hard register,
or is the wrong mode. */
if (GET_CODE (target) != REG
|| REGNO (target) < FIRST_PSEUDO_REGISTER
@@ -3232,13 +3353,16 @@ expand_float (to, from, unsignedp)
NULL_RTX, 1, OPTAB_LIB_WIDEN);
temp1 = expand_shift (RSHIFT_EXPR, imode, from, integer_one_node,
NULL_RTX, 1);
- temp = expand_binop (imode, ior_optab, temp, temp1, temp, 1,
+ temp = expand_binop (imode, ior_optab, temp, temp1, temp, 1,
OPTAB_LIB_WIDEN);
expand_float (target, temp, 0);
/* Multiply by 2 to undo the shift above. */
- target = expand_binop (fmode, add_optab, target, target,
+ temp = expand_binop (fmode, add_optab, target, target,
target, 0, OPTAB_LIB_WIDEN);
+ if (temp != target)
+ emit_move_insn (target, temp);
+
do_pending_stack_adjust ();
emit_label (label);
goto done;
@@ -3278,7 +3402,7 @@ expand_float (to, from, unsignedp)
}
#endif
- /* No hardware instruction available; call a library rotine to convert from
+ /* No hardware instruction available; call a library routine to convert from
SImode, DImode, or TImode into SFmode, DFmode, XFmode, or TFmode. */
{
rtx libfcn;
@@ -3562,6 +3686,7 @@ expand_fix (to, from, unsignedp)
if (libfcn)
{
rtx insns;
+ rtx value;
to = protect_from_queue (to, 1);
from = protect_from_queue (from, 0);
@@ -3571,15 +3696,17 @@ expand_fix (to, from, unsignedp)
start_sequence ();
- emit_library_call (libfcn, 1, GET_MODE (to), 1, from, GET_MODE (from));
+ value = emit_library_call_value (libfcn, NULL_RTX, 1, GET_MODE (to),
+
+ 1, from, GET_MODE (from));
insns = get_insns ();
end_sequence ();
- emit_libcall_block (insns, target, hard_libcall_value (GET_MODE (to)),
- gen_rtx (unsignedp ? FIX : UNSIGNED_FIX,
+ emit_libcall_block (insns, target, value,
+ gen_rtx (unsignedp ? UNSIGNED_FIX : FIX,
GET_MODE (to), from));
}
-
+
if (GET_MODE (to) == GET_MODE (target))
emit_move_insn (to, target);
else
@@ -3711,17 +3838,17 @@ init_optabs ()
/* Start by initializing all tables to contain CODE_FOR_nothing. */
for (p = fixtab[0][0];
- p < fixtab[0][0] + sizeof fixtab / sizeof (fixtab[0][0][0]);
+ p < fixtab[0][0] + sizeof fixtab / sizeof (fixtab[0][0][0]);
p++)
*p = CODE_FOR_nothing;
for (p = fixtrunctab[0][0];
- p < fixtrunctab[0][0] + sizeof fixtrunctab / sizeof (fixtrunctab[0][0][0]);
+ p < fixtrunctab[0][0] + sizeof fixtrunctab / sizeof (fixtrunctab[0][0][0]);
p++)
*p = CODE_FOR_nothing;
for (p = floattab[0][0];
- p < floattab[0][0] + sizeof floattab / sizeof (floattab[0][0][0]);
+ p < floattab[0][0] + sizeof floattab / sizeof (floattab[0][0][0]);
p++)
*p = CODE_FOR_nothing;
@@ -3819,8 +3946,6 @@ init_optabs ()
init_integral_libfuncs (ashl_optab, "ashl", '3');
init_integral_libfuncs (ashr_optab, "ashr", '3');
init_integral_libfuncs (lshr_optab, "lshr", '3');
- init_integral_libfuncs (rotl_optab, "rotl", '3');
- init_integral_libfuncs (rotr_optab, "rotr", '3');
init_integral_libfuncs (smin_optab, "min", '3');
init_floating_libfuncs (smin_optab, "min", '3');
init_integral_libfuncs (smax_optab, "max", '3');
@@ -3957,6 +4082,13 @@ init_optabs ()
memset_libfunc = gen_rtx (SYMBOL_REF, Pmode, "memset");
bzero_libfunc = gen_rtx (SYMBOL_REF, Pmode, "bzero");
+ eqhf2_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__eqhf2");
+ nehf2_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__nehf2");
+ gthf2_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__gthf2");
+ gehf2_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__gehf2");
+ lthf2_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__lthf2");
+ lehf2_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__lehf2");
+
eqsf2_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__eqsf2");
nesf2_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__nesf2");
gtsf2_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__gtsf2");
diff --git a/gnu/usr.bin/cc/cc_int/print-tree.c b/gnu/usr.bin/cc/cc_int/print-tree.c
index f4f878f..3eb2d6a 100644
--- a/gnu/usr.bin/cc/cc_int/print-tree.c
+++ b/gnu/usr.bin/cc/cc_int/print-tree.c
@@ -109,10 +109,22 @@ print_node_brief (file, prefix, node, indent)
fprintf (file, " overflow");
if (TREE_INT_CST_HIGH (node) == 0)
- fprintf (file, " %1u", TREE_INT_CST_LOW (node));
+ fprintf (file,
+#if HOST_BITS_PER_WIDE_INT == HOST_BITS_PER_INT
+ " %1u",
+#else
+ " %1lu",
+#endif
+ TREE_INT_CST_LOW (node));
else if (TREE_INT_CST_HIGH (node) == -1
&& TREE_INT_CST_LOW (node) != 0)
- fprintf (file, " -%1u", -TREE_INT_CST_LOW (node));
+ fprintf (file,
+#if HOST_BITS_PER_WIDE_INT == HOST_BITS_PER_INT
+ " -%1u",
+#else
+ " -%1lu",
+#endif
+ -TREE_INT_CST_LOW (node));
else
fprintf (file,
#if HOST_BITS_PER_WIDE_INT == 64
@@ -132,8 +144,24 @@ print_node_brief (file, prefix, node, indent)
}
if (TREE_CODE (node) == REAL_CST)
{
-#ifndef REAL_IS_NOT_DOUBLE
- fprintf (file, " %e", TREE_REAL_CST (node));
+ REAL_VALUE_TYPE d;
+
+ if (TREE_OVERFLOW (node))
+ fprintf (file, " overflow");
+
+#if !defined(REAL_IS_NOT_DOUBLE) || defined(REAL_ARITHMETIC)
+ d = TREE_REAL_CST (node);
+ if (REAL_VALUE_ISINF (d))
+ fprintf (file, " Inf");
+ else if (REAL_VALUE_ISNAN (d))
+ fprintf (file, " Nan");
+ else
+ {
+ char string[100];
+
+ REAL_VALUE_TO_DECIMAL (d, "%e", string);
+ fprintf (file, " %s", string);
+ }
#else
{
int i;
@@ -143,7 +171,7 @@ print_node_brief (file, prefix, node, indent)
fprintf (file, "%02x", *p++);
fprintf (file, "");
}
-#endif /* REAL_IS_NOT_DOUBLE */
+#endif
}
fprintf (file, ">");
@@ -324,22 +352,47 @@ print_node (file, prefix, node, indent)
case 'd':
mode = DECL_MODE (node);
+ if (DECL_IGNORED_P (node))
+ fputs (" ignored", file);
+ if (DECL_ABSTRACT (node))
+ fputs (" abstract", file);
+ if (DECL_IN_SYSTEM_HEADER (node))
+ fputs (" in_system_header", file);
+ if (DECL_COMMON (node))
+ fputs (" common", file);
if (DECL_EXTERNAL (node))
fputs (" external", file);
- if (DECL_NONLOCAL (node))
- fputs (" nonlocal", file);
if (DECL_REGISTER (node))
fputs (" regdecl", file);
+ if (DECL_PACKED (node))
+ fputs (" packed", file);
+ if (DECL_NONLOCAL (node))
+ fputs (" nonlocal", file);
if (DECL_INLINE (node))
fputs (" inline", file);
- if (DECL_BIT_FIELD (node))
+
+ if (TREE_CODE (node) == TYPE_DECL && TYPE_DECL_SUPPRESS_DEBUG (node))
+ fputs (" supress-debug", file);
+
+ if (TREE_CODE (node) == FUNCTION_DECL && DECL_BUILT_IN (node))
+ fputs (" built-in", file);
+ if (TREE_CODE (node) == FUNCTION_DECL && DECL_BUILT_IN_NONANSI (node))
+ fputs (" built-in-nonansi", file);
+
+ if (TREE_CODE (node) == FIELD_DECL && DECL_BIT_FIELD (node))
fputs (" bit-field", file);
+ if (TREE_CODE (node) == LABEL_DECL && DECL_TOO_LATE (node))
+ fputs (" too-late", file);
+ if (TREE_CODE (node) == VAR_DECL && DECL_IN_TEXT_SECTION (node))
+ fputs (" in-text-section", file);
+
if (DECL_VIRTUAL_P (node))
fputs (" virtual", file);
- if (DECL_IGNORED_P (node))
- fputs (" ignored", file);
- if (DECL_IN_SYSTEM_HEADER (node))
- fputs (" in_system_header", file);
+ if (DECL_DEFER_OUTPUT (node))
+ fputs (" defer-output", file);
+ if (DECL_TRANSPARENT_UNION (node))
+ fputs (" transparent-union", file);
+
if (DECL_LANG_FLAG_0 (node))
fputs (" decl_0", file);
if (DECL_LANG_FLAG_1 (node))
@@ -413,7 +466,14 @@ print_node (file, prefix, node, indent)
case 't':
if (TYPE_NO_FORCE_BLK (node))
- fputs (" no_force_blk", file);
+ fputs (" no-force-blk", file);
+ if (TYPE_STRING_FLAG (node))
+ fputs (" string-flag", file);
+ if (TYPE_NEEDS_CONSTRUCTING (node))
+ fputs (" needs-constructing", file);
+ if (TYPE_TRANSPARENT_UNION (node))
+ fputs (" transparent-union", file);
+
if (TYPE_LANG_FLAG_0 (node))
fputs (" type_0", file);
if (TYPE_LANG_FLAG_1 (node))
@@ -558,10 +618,22 @@ print_node (file, prefix, node, indent)
fprintf (file, " overflow");
if (TREE_INT_CST_HIGH (node) == 0)
- fprintf (file, " %1u", TREE_INT_CST_LOW (node));
+ fprintf (file,
+#if HOST_BITS_PER_WIDE_INT == HOST_BITS_PER_INT
+ " %1u",
+#else
+ " %1lu",
+#endif
+ TREE_INT_CST_LOW (node));
else if (TREE_INT_CST_HIGH (node) == -1
&& TREE_INT_CST_LOW (node) != 0)
- fprintf (file, " -%1u", -TREE_INT_CST_LOW (node));
+ fprintf (file,
+#if HOST_BITS_PER_WIDE_INT == HOST_BITS_PER_INT
+ " -%1u",
+#else
+ " -%1lu",
+#endif
+ -TREE_INT_CST_LOW (node));
else
fprintf (file,
#if HOST_BITS_PER_WIDE_INT == 64
@@ -581,17 +653,36 @@ print_node (file, prefix, node, indent)
break;
case REAL_CST:
-#ifndef REAL_IS_NOT_DOUBLE
- fprintf (file, " %e", TREE_REAL_CST (node));
-#else
{
- char *p = (char *) &TREE_REAL_CST (node);
- fprintf (file, " 0x");
- for (i = 0; i < sizeof TREE_REAL_CST (node); i++)
- fprintf (file, "%02x", *p++);
- fprintf (file, "");
+ REAL_VALUE_TYPE d;
+
+ if (TREE_OVERFLOW (node))
+ fprintf (file, " overflow");
+
+#if !defined(REAL_IS_NOT_DOUBLE) || defined(REAL_ARITHMETIC)
+ d = TREE_REAL_CST (node);
+ if (REAL_VALUE_ISINF (d))
+ fprintf (file, " Inf");
+ else if (REAL_VALUE_ISNAN (d))
+ fprintf (file, " Nan");
+ else
+ {
+ char string[100];
+
+ REAL_VALUE_TO_DECIMAL (d, "%e", string);
+ fprintf (file, " %s", string);
+ }
+#else
+ {
+ int i;
+ unsigned char *p = (unsigned char *) &TREE_REAL_CST (node);
+ fprintf (file, " 0x");
+ for (i = 0; i < sizeof TREE_REAL_CST (node); i++)
+ fprintf (file, "%02x", *p++);
+ fprintf (file, "");
+ }
+#endif
}
-#endif /* REAL_IS_NOT_DOUBLE */
break;
case COMPLEX_CST:
diff --git a/gnu/usr.bin/cc/cc_int/real.c b/gnu/usr.bin/cc/cc_int/real.c
index cad4343..6a15925 100644
--- a/gnu/usr.bin/cc/cc_int/real.c
+++ b/gnu/usr.bin/cc/cc_int/real.c
@@ -86,7 +86,7 @@ research.att.com: netlib/cephes/ldouble.shar.Z */
both mean DFmode. In this case, the software floating-point
support available here is activated by writing
#define REAL_ARITHMETIC
- in tm.h.
+ in tm.h.
The case LONG_DOUBLE_TYPE_SIZE = 128 activates TFmode support
and may deactivate XFmode since `long double' is used to refer
@@ -246,15 +246,15 @@ unknown arithmetic type
#define NE 6
#define MAXDECEXP 4932
#define MINDECEXP -4956
-#define GET_REAL(r,e) bcopy (r, e, 2*NE)
-#define PUT_REAL(e,r) bcopy (e, r, 2*NE)
+#define GET_REAL(r,e) bcopy ((char *) r, (char *) e, 2*NE)
+#define PUT_REAL(e,r) bcopy ((char *) e, (char *) r, 2*NE)
#else /* no XFmode */
#if LONG_DOUBLE_TYPE_SIZE == 128
#define NE 10
#define MAXDECEXP 4932
#define MINDECEXP -4977
-#define GET_REAL(r,e) bcopy (r, e, 2*NE)
-#define PUT_REAL(e,r) bcopy (e, r, 2*NE)
+#define GET_REAL(r,e) bcopy ((char *) r, (char *) e, 2*NE)
+#define PUT_REAL(e,r) bcopy ((char *) e, (char *) r, 2*NE)
#else
#define NE 6
#define MAXDECEXP 4932
@@ -428,7 +428,7 @@ static void esqrt PROTO((unsigned EMUSHORT *, unsigned EMUSHORT *));
swapping ends if required, into output array of longs. The
result is normally passed to fprintf by the ASM_OUTPUT_ macros. */
-static void
+static void
endian (e, x, mode)
unsigned EMUSHORT e[];
long x[];
@@ -534,7 +534,7 @@ endian (e, x, mode)
/* This is the implementation of the REAL_ARITHMETIC macro. */
-void
+void
earith (value, icode, r1, r2)
REAL_VALUE_TYPE *value;
int icode;
@@ -613,7 +613,7 @@ PUT_REAL (v, value);
/* Truncate REAL_VALUE_TYPE toward zero to signed HOST_WIDE_INT.
implements REAL_VALUE_RNDZINT (x) (etrunci (x)). */
-REAL_VALUE_TYPE
+REAL_VALUE_TYPE
etrunci (x)
REAL_VALUE_TYPE x;
{
@@ -636,7 +636,7 @@ etrunci (x)
/* Truncate REAL_VALUE_TYPE toward zero to unsigned HOST_WIDE_INT;
implements REAL_VALUE_UNSIGNED_RNDZINT (x) (etruncui (x)). */
-REAL_VALUE_TYPE
+REAL_VALUE_TYPE
etruncui (x)
REAL_VALUE_TYPE x;
{
@@ -660,7 +660,7 @@ etruncui (x)
binary, rounding off as indicated by the machine_mode argument. Then it
promotes the rounded value to REAL_VALUE_TYPE. */
-REAL_VALUE_TYPE
+REAL_VALUE_TYPE
ereal_atof (s, t)
char *s;
enum machine_mode t;
@@ -697,7 +697,7 @@ ereal_atof (s, t)
/* Expansion of REAL_NEGATE. */
-REAL_VALUE_TYPE
+REAL_VALUE_TYPE
ereal_negate (x)
REAL_VALUE_TYPE x;
{
@@ -759,7 +759,7 @@ efixui (x)
/* REAL_VALUE_FROM_INT macro. */
-void
+void
ereal_from_int (d, i, j)
REAL_VALUE_TYPE *d;
HOST_WIDE_INT i, j;
@@ -793,7 +793,7 @@ ereal_from_int (d, i, j)
/* REAL_VALUE_FROM_UNSIGNED_INT macro. */
-void
+void
ereal_from_uint (d, i, j)
REAL_VALUE_TYPE *d;
unsigned HOST_WIDE_INT i, j;
@@ -814,7 +814,7 @@ ereal_from_uint (d, i, j)
/* REAL_VALUE_TO_INT macro. */
-void
+void
ereal_to_int (low, high, rr)
HOST_WIDE_INT *low, *high;
REAL_VALUE_TYPE rr;
@@ -993,7 +993,7 @@ debug_real (r)
REAL_VALUE_TO_DECIMAL (r, "%.20g", dstr);
fprintf (stderr, "%s", dstr);
-}
+}
/* Target values are arrays of host longs. A long is guaranteed
@@ -1001,7 +1001,7 @@ debug_real (r)
/* 128-bit long double */
-void
+void
etartdouble (r, l)
REAL_VALUE_TYPE r;
long l[];
@@ -1015,7 +1015,7 @@ etartdouble (r, l)
/* 80-bit long double */
-void
+void
etarldouble (r, l)
REAL_VALUE_TYPE r;
long l[];
@@ -1027,7 +1027,7 @@ etarldouble (r, l)
endian (e, l, XFmode);
}
-void
+void
etardouble (r, l)
REAL_VALUE_TYPE r;
long l[];
@@ -1112,11 +1112,11 @@ ereal_isneg (x)
most significant word first,
most significant bit is set)
ei[NI-1] low guard word (0x8000 bit is rounding place)
-
-
-
+
+
+
Routines for external format numbers
-
+
asctoe (string, e) ASCII string to extended double e type
asctoe64 (string, &d) ASCII string to long double
asctoe53 (string, &d) ASCII string to double
@@ -1157,10 +1157,10 @@ ereal_isneg (x)
eisinf (e) 1 if e has maximum exponent (non-IEEE)
or is infinite (IEEE)
eisnan (e) 1 if e is a NaN
-
+
Routines for internal format numbers
-
+
eaddm (ai, bi) add significands, bi = bi + ai
ecleaz (ei) ei = 0
ecleazs (ei) set ei = 0 but leave its sign alone
@@ -1190,13 +1190,13 @@ ereal_isneg (x)
after each arithmetic operation.
Exception flags are NOT fully supported.
-
+
Signaling NaN's are NOT supported; they are treated the same
as quiet NaN's.
-
+
Define INFINITY for support of infinity; otherwise a
saturation arithmetic is implemented.
-
+
Define NANS for support of Not-a-Number items; otherwise the
arithmetic will never produce a NaN output, and might be confused
by a NaN input.
@@ -1204,7 +1204,7 @@ ereal_isneg (x)
either a or b is a NaN. This means asking `if (ecmp (a,b) < 0)'
may not be legitimate. Use `if (ecmp (a,b) == -1)' for `less than'
if in doubt.
-
+
Denormals are always supported here where appropriate (e.g., not
for conversion to DEC numbers). */
@@ -1217,26 +1217,26 @@ ereal_isneg (x)
mode, most floating point constants are given as arrays
of octal integers to eliminate decimal to binary conversion
errors that might be introduced by the compiler.
-
+
For computers, such as IBM PC, that follow the IEEE
Standard for Binary Floating Point Arithmetic (ANSI/IEEE
Std 754-1985), the symbol IBMPC or MIEEE should be defined.
These numbers have 53-bit significands. In this mode, constants
are provided as arrays of hexadecimal 16 bit integers.
-
+
To accommodate other types of computer arithmetic, all
constants are also provided in a normal decimal radix
which one can hope are correctly converted to a suitable
format by the available C language compiler. To invoke
this mode, the symbol UNK is defined.
-
+
An important difference among these modes is a predefined
set of machine arithmetic constants for each. The numbers
MACHEP (the machine roundoff error), MAXNUM (largest number
represented), and several other parameters are preset by
the configuration symbol. Check the file const.c to
ensure that these values are correct for your computer.
-
+
For ANSI C compatibility, define ANSIC equal to 1. Currently
this affects only the atan2 function and others that use it. */
@@ -1331,7 +1331,7 @@ extern int rndprc;
/* Clear out entire external format number. */
-static void
+static void
eclear (x)
register unsigned EMUSHORT *x;
{
@@ -1345,7 +1345,7 @@ eclear (x)
/* Move external format number from a to b. */
-static void
+static void
emov (a, b)
register unsigned EMUSHORT *a, *b;
{
@@ -1358,17 +1358,17 @@ emov (a, b)
/* Absolute value of external format number. */
-static void
+static void
eabs (x)
unsigned EMUSHORT x[];
{
/* sign is top bit of last word of external format */
- x[NE - 1] &= 0x7fff;
+ x[NE - 1] &= 0x7fff;
}
/* Negate external format number. */
-static void
+static void
eneg (x)
unsigned EMUSHORT x[];
{
@@ -1380,7 +1380,7 @@ eneg (x)
/* Return 1 if sign bit of external format number is nonzero, else zero. */
-static int
+static int
eisneg (x)
unsigned EMUSHORT x[];
{
@@ -1394,7 +1394,7 @@ eisneg (x)
/* Return 1 if external format number is infinity, else return zero. */
-static int
+static int
eisinf (x)
unsigned EMUSHORT x[];
{
@@ -1413,7 +1413,7 @@ eisinf (x)
/* Check if e-type number is not a number. The bit pattern is one that we
defined, so we know for sure how to detect it. */
-static int
+static int
eisnan (x)
unsigned EMUSHORT x[];
{
@@ -1437,7 +1437,7 @@ eisnan (x)
/* Fill external format number with infinity pattern (IEEE)
or largest possible number (non-IEEE). */
-static void
+static void
einfin (x)
register unsigned EMUSHORT *x;
{
@@ -1481,7 +1481,7 @@ einfin (x)
This generates Intel's quiet NaN pattern for extended real.
The exponent is 7fff, the leading mantissa word is c000. */
-static void
+static void
enan (x, sign)
register unsigned EMUSHORT *x;
int sign;
@@ -1497,7 +1497,7 @@ enan (x, sign)
/* Move in external format number, converting it to internal format. */
-static void
+static void
emovi (a, b)
unsigned EMUSHORT *a, *b;
{
@@ -1545,7 +1545,7 @@ emovi (a, b)
/* Move internal format number out, converting it to external format. */
-static void
+static void
emovo (a, b)
unsigned EMUSHORT *a, *b;
{
@@ -1584,7 +1584,7 @@ emovo (a, b)
/* Clear out internal format number. */
-static void
+static void
ecleaz (xi)
register unsigned EMUSHORT *xi;
{
@@ -1597,7 +1597,7 @@ ecleaz (xi)
/* Same, but don't touch the sign. */
-static void
+static void
ecleazs (xi)
register unsigned EMUSHORT *xi;
{
@@ -1612,7 +1612,7 @@ ecleazs (xi)
/* Move internal format number from a to b. */
-static void
+static void
emovz (a, b)
register unsigned EMUSHORT *a, *b;
{
@@ -1640,7 +1640,7 @@ einan (x)
/* Return nonzero if internal format number is a NaN. */
-static int
+static int
eiisnan (x)
unsigned EMUSHORT x[];
{
@@ -1659,7 +1659,7 @@ eiisnan (x)
/* Return nonzero if sign of internal format number is nonzero. */
-static int
+static int
eiisneg (x)
unsigned EMUSHORT x[];
{
@@ -1681,7 +1681,7 @@ eiinfin (x)
/* Return nonzero if internal format number is infinite. */
-static int
+static int
eiisinf (x)
unsigned EMUSHORT x[];
{
@@ -1728,7 +1728,7 @@ ecmpm (a, b)
/* Shift significand down by 1 bit. */
-static void
+static void
eshdn1 (x)
register unsigned EMUSHORT *x;
{
@@ -1754,7 +1754,7 @@ eshdn1 (x)
/* Shift significand up by 1 bit. */
-static void
+static void
eshup1 (x)
register unsigned EMUSHORT *x;
{
@@ -1779,7 +1779,7 @@ eshup1 (x)
/* Shift significand down by 8 bits. */
-static void
+static void
eshdn8 (x)
register unsigned EMUSHORT *x;
{
@@ -1800,7 +1800,7 @@ eshdn8 (x)
/* Shift significand up by 8 bits. */
-static void
+static void
eshup8 (x)
register unsigned EMUSHORT *x;
{
@@ -1822,7 +1822,7 @@ eshup8 (x)
/* Shift significand up by 16 bits. */
-static void
+static void
eshup6 (x)
register unsigned EMUSHORT *x;
{
@@ -1840,7 +1840,7 @@ eshup6 (x)
/* Shift significand down by 16 bits. */
-static void
+static void
eshdn6 (x)
register unsigned EMUSHORT *x;
{
@@ -1858,7 +1858,7 @@ eshdn6 (x)
/* Add significands. x + y replaces y. */
-static void
+static void
eaddm (x, y)
unsigned EMUSHORT *x, *y;
{
@@ -1884,7 +1884,7 @@ eaddm (x, y)
/* Subtract significands. y - x replaces y. */
-static void
+static void
esubm (x, y)
unsigned EMUSHORT *x, *y;
{
@@ -1918,7 +1918,7 @@ static unsigned EMUSHORT equot[NI];
/* Divide significands */
-int
+int
edivm (den, num)
unsigned EMUSHORT den[], num[];
{
@@ -2015,7 +2015,7 @@ edivm (den, num)
/* Multiply significands */
-int
+int
emulm (a, b)
unsigned EMUSHORT a[], b[];
{
@@ -2224,15 +2224,15 @@ emulm (a, b)
The internal format number to be rounded is "s".
Input "lost" indicates whether or not the number is exact.
This is the so-called sticky bit.
-
+
Input "subflg" indicates whether the number was obtained
by a subtraction operation. In that case if lost is nonzero
then the number is slightly smaller than indicated.
-
+
Input "exp" is the biased exponent, which may be negative.
the exponent field of "s" is ignored but is replaced by
"exp" as adjusted by normalization and rounding.
-
+
Input "rcntrl" is the rounding control.
For future reference: In order for emdnorm to round off denormal
@@ -2240,7 +2240,7 @@ emulm (a, b)
adjusted to be the actual value it would have after conversion to
the final floating point type. This adjustment has been
implemented for all type conversions (etoe53, etc.) and decimal
- conversions, but not for the arithmetic functions (eadd, etc.).
+ conversions, but not for the arithmetic functions (eadd, etc.).
Data types having standard 15-bit exponents are not affected by
this, but SFmode and DFmode are affected. For example, ediv with
rndprc = 24 will not round correctly to 24-bit precision if the
@@ -2254,7 +2254,7 @@ static unsigned EMUSHORT rebit = 0;
static int re = 0;
static unsigned EMUSHORT rbit[NI];
-static void
+static void
emdnorm (s, lost, subflg, exp, rcntrl)
unsigned EMUSHORT s[];
int lost;
@@ -2452,7 +2452,7 @@ emdnorm (s, lost, subflg, exp, rcntrl)
static int subflg = 0;
-static void
+static void
esub (a, b, c)
unsigned EMUSHORT *a, *b, *c;
{
@@ -2485,7 +2485,7 @@ esub (a, b, c)
/* Add. */
-static void
+static void
eadd (a, b, c)
unsigned EMUSHORT *a, *b, *c;
{
@@ -2516,7 +2516,7 @@ eadd (a, b, c)
eadd1 (a, b, c);
}
-static void
+static void
eadd1 (a, b, c)
unsigned EMUSHORT *a, *b, *c;
{
@@ -2622,7 +2622,7 @@ eadd1 (a, b, c)
/* Divide. */
-static void
+static void
ediv (a, b, c)
unsigned EMUSHORT *a, *b, *c;
{
@@ -2726,7 +2726,7 @@ ediv (a, b, c)
/* Multiply. */
-static void
+static void
emul (a, b, c)
unsigned EMUSHORT *a, *b, *c;
{
@@ -2913,7 +2913,7 @@ e53toe (pe, y)
#endif /* not DEC */
}
-static void
+static void
e64toe (pe, y)
unsigned EMUSHORT *pe, *y;
{
@@ -2986,7 +2986,7 @@ e64toe (pe, y)
}
-static void
+static void
e113toe (pe, y)
unsigned EMUSHORT *pe, *y;
{
@@ -3064,7 +3064,7 @@ e113toe (pe, y)
/* Convert IEEE single precision to e type. */
-static void
+static void
e24toe (pe, y)
unsigned EMUSHORT *pe, *y;
{
@@ -3152,7 +3152,7 @@ e24toe (pe, y)
}
-static void
+static void
etoe113 (x, e)
unsigned EMUSHORT *x, *e;
{
@@ -3184,7 +3184,7 @@ etoe113 (x, e)
/* Move out internal format to ieee long double */
-static void
+static void
toe113 (a, b)
unsigned EMUSHORT *a, *b;
{
@@ -3235,7 +3235,7 @@ toe113 (a, b)
#endif
}
-static void
+static void
etoe64 (x, e)
unsigned EMUSHORT *x, *e;
{
@@ -3269,7 +3269,7 @@ etoe64 (x, e)
/* Move out internal format to ieee long double. */
-static void
+static void
toe64 (a, b)
unsigned EMUSHORT *a, *b;
{
@@ -3325,14 +3325,14 @@ toe64 (a, b)
#ifdef DEC
-static void
+static void
etoe53 (x, e)
unsigned EMUSHORT *x, *e;
{
etodec (x, e); /* see etodec.c */
}
-static void
+static void
toe53 (x, y)
unsigned EMUSHORT *x, *y;
{
@@ -3342,14 +3342,14 @@ toe53 (x, y)
#else
#ifdef IBM
-static void
+static void
etoe53 (x, e)
unsigned EMUSHORT *x, *e;
{
etoibm (x, e, DFmode);
}
-static void
+static void
toe53 (x, y)
unsigned EMUSHORT *x, *y;
{
@@ -3358,7 +3358,7 @@ toe53 (x, y)
#else /* it's neither DEC nor IBM */
-static void
+static void
etoe53 (x, e)
unsigned EMUSHORT *x, *e;
{
@@ -3390,7 +3390,7 @@ etoe53 (x, e)
}
-static void
+static void
toe53 (x, y)
unsigned EMUSHORT *x, *y;
{
@@ -3477,14 +3477,14 @@ toe53 (x, y)
#ifdef IBM
-static void
+static void
etoe24 (x, e)
unsigned EMUSHORT *x, *e;
{
etoibm (x, e, SFmode);
}
-static void
+static void
toe24 (x, y)
unsigned EMUSHORT *x, *y;
{
@@ -3493,7 +3493,7 @@ toe24 (x, y)
#else
-static void
+static void
etoe24 (x, e)
unsigned EMUSHORT *x, *e;
{
@@ -3524,7 +3524,7 @@ etoe24 (x, e)
toe24 (xi, e);
}
-static void
+static void
toe24 (x, y)
unsigned EMUSHORT *x, *y;
{
@@ -3607,13 +3607,13 @@ toe24 (x, y)
}
#endif /* not IBM */
-/* Compare two e type numbers.
+/* Compare two e type numbers.
Return +1 if a > b
0 if a == b
-1 if a < b
-2 if either a or b is a NaN. */
-static int
+static int
ecmp (a, b)
unsigned EMUSHORT *a, *b;
{
@@ -3680,7 +3680,7 @@ ecmp (a, b)
/* Find nearest integer to x = floor (x + 0.5). */
-static void
+static void
eround (x, y)
unsigned EMUSHORT *x, *y;
{
@@ -3693,7 +3693,7 @@ eround (x, y)
/* Convert HOST_WIDE_INT to e type. */
-static void
+static void
ltoe (lp, y)
HOST_WIDE_INT *lp;
unsigned EMUSHORT *y;
@@ -3735,7 +3735,7 @@ ltoe (lp, y)
/* Convert unsigned HOST_WIDE_INT to e type. */
-static void
+static void
ultoe (lp, y)
unsigned HOST_WIDE_INT *lp;
unsigned EMUSHORT *y;
@@ -3775,7 +3775,7 @@ ultoe (lp, y)
The output e-type fraction FRAC is the positive fractional
part of abs (X). */
-static void
+static void
eifrac (x, i, frac)
unsigned EMUSHORT *x;
HOST_WIDE_INT *i;
@@ -3858,7 +3858,7 @@ eifrac (x, i, frac)
A negative e type input yields integer output = 0
but correct fraction. */
-static void
+static void
euifrac (x, i, frac)
unsigned EMUSHORT *x;
unsigned HOST_WIDE_INT *i;
@@ -3929,7 +3929,7 @@ euifrac (x, i, frac)
/* Shift significand area up or down by the number of bits given by SC. */
-static int
+static int
eshift (x, sc)
unsigned EMUSHORT *x;
int sc;
@@ -3997,7 +3997,7 @@ eshift (x, sc)
/* Shift normalize the significand area pointed to by argument.
Shift count (up = positive) is returned. */
-static int
+static int
enormlz (x)
unsigned EMUSHORT x[];
{
@@ -4169,7 +4169,7 @@ static unsigned EMUSHORT emtens[NTEN + 1][NE] =
};
#endif
-static void
+static void
e24toasc (x, string, ndigs)
unsigned EMUSHORT x[];
char *string;
@@ -4182,7 +4182,7 @@ e24toasc (x, string, ndigs)
}
-static void
+static void
e53toasc (x, string, ndigs)
unsigned EMUSHORT x[];
char *string;
@@ -4195,7 +4195,7 @@ e53toasc (x, string, ndigs)
}
-static void
+static void
e64toasc (x, string, ndigs)
unsigned EMUSHORT x[];
char *string;
@@ -4207,7 +4207,7 @@ e64toasc (x, string, ndigs)
etoasc (w, string, ndigs);
}
-static void
+static void
e113toasc (x, string, ndigs)
unsigned EMUSHORT x[];
char *string;
@@ -4222,7 +4222,7 @@ e113toasc (x, string, ndigs)
static char wstring[80]; /* working storage for ASCII output */
-static void
+static void
etoasc (x, string, ndigs)
unsigned EMUSHORT x[];
char *string;
@@ -4539,7 +4539,7 @@ etoasc (x, string, ndigs)
/* ASCII to single */
-static void
+static void
asctoe24 (s, y)
char *s;
unsigned EMUSHORT *y;
@@ -4550,7 +4550,7 @@ asctoe24 (s, y)
/* ASCII to double */
-static void
+static void
asctoe53 (s, y)
char *s;
unsigned EMUSHORT *y;
@@ -4565,7 +4565,7 @@ asctoe53 (s, y)
/* ASCII to long double */
-static void
+static void
asctoe64 (s, y)
char *s;
unsigned EMUSHORT *y;
@@ -4575,7 +4575,7 @@ asctoe64 (s, y)
/* ASCII to 128-bit long double */
-static void
+static void
asctoe113 (s, y)
char *s;
unsigned EMUSHORT *y;
@@ -4585,7 +4585,7 @@ asctoe113 (s, y)
/* ASCII to super double */
-static void
+static void
asctoe (s, y)
char *s;
unsigned EMUSHORT *y;
@@ -4596,7 +4596,7 @@ asctoe (s, y)
/* ASCII to e type, with specified rounding precision = oprec. */
-static void
+static void
asctoeg (ss, y, oprec)
char *ss;
unsigned EMUSHORT *y;
@@ -4932,7 +4932,7 @@ static unsigned EMUSHORT bmask[] =
0x0000,
};
-static void
+static void
efloor (x, y)
unsigned EMUSHORT x[], y[];
{
@@ -4983,7 +4983,7 @@ efloor (x, y)
For example, 1.1 = 0.55 * 2**1
Handles denormalized numbers properly using long integer exp. */
-static void
+static void
efrexp (x, exp, s)
unsigned EMUSHORT x[];
int *exp;
@@ -5008,7 +5008,7 @@ efrexp (x, exp, s)
/* Return y = x * 2**pwr2. */
-static void
+static void
eldexp (x, pwr2, y)
unsigned EMUSHORT x[];
int pwr2;
@@ -5030,7 +5030,7 @@ eldexp (x, pwr2, y)
/* c = remainder after dividing b by a
Least significant integer quotient bits left in equot[]. */
-static void
+static void
eremain (a, b, c)
unsigned EMUSHORT a[], b[], c[];
{
@@ -5063,7 +5063,7 @@ eremain (a, b, c)
emovo (num, c);
}
-static void
+static void
eiremain (den, num)
unsigned EMUSHORT den[], num[];
{
@@ -5098,7 +5098,7 @@ eiremain (den, num)
error conditions (in the include file mconf.h).
Mnemonic Value Significance
-
+
DOMAIN 1 argument domain error
SING 2 function singularity
OVERFLOW 3 overflow range error
@@ -5108,7 +5108,7 @@ eiremain (den, num)
INVALID 7 NaN - producing operation
EDOM 33 Unix domain error code
ERANGE 34 Unix range error code
-
+
The default version of the file prints the function name,
passed to it by the pointer fctnam, followed by the
error condition. The display is directed to the standard
@@ -5116,7 +5116,7 @@ eiremain (den, num)
program. Users may wish to modify the program to abort by
calling exit under severe error conditions such as domain
errors.
-
+
Since all error conditions pass control to this function,
the display may be easily changed, eliminated, or directed
to an error logging device. */
@@ -5140,7 +5140,7 @@ static char *ermsg[NMSGS] =
int merror = 0;
extern int merror;
-static void
+static void
mtherr (name, code)
char *name;
int code;
@@ -5164,7 +5164,7 @@ mtherr (name, code)
#ifdef DEC
/* Convert DEC double precision to e type. */
-static void
+static void
dectoe (d, e)
unsigned EMUSHORT *d;
unsigned EMUSHORT *e;
@@ -5211,7 +5211,7 @@ dectoe (d, e)
; etodec (e, &d);
*/
-static void
+static void
etodec (x, d)
unsigned EMUSHORT *x, *d;
{
@@ -5229,7 +5229,7 @@ etodec (x, d)
todec (xi, d);
}
-static void
+static void
todec (x, y)
unsigned EMUSHORT *x, *y;
{
@@ -5275,7 +5275,7 @@ todec (x, y)
#ifdef IBM
/* Convert IBM single/double precision to e type. */
-static void
+static void
ibmtoe (d, e, mode)
unsigned EMUSHORT *d;
unsigned EMUSHORT *e;
@@ -5319,7 +5319,7 @@ ibmtoe (d, e, mode)
/* Convert e type to IBM single/double precision. */
-static void
+static void
etoibm (x, d, mode)
unsigned EMUSHORT *x, *d;
enum machine_mode mode;
@@ -5338,7 +5338,7 @@ etoibm (x, d, mode)
toibm (xi, d, mode);
}
-static void
+static void
toibm (x, y, mode)
unsigned EMUSHORT *x, *y;
enum machine_mode mode;
@@ -5643,7 +5643,7 @@ ditoe (di, e)
/* Convert e-type to unsigned 64-bit int. */
-static void
+static void
etoudi (x, i)
unsigned EMUSHORT *x;
unsigned EMUSHORT *i;
@@ -5723,7 +5723,7 @@ noshift:
/* Convert e-type to signed 64-bit int. */
-static void
+static void
etodi (x, i)
unsigned EMUSHORT *x;
unsigned EMUSHORT *i;
@@ -5824,7 +5824,7 @@ etodi (x, i)
static int esqinited = 0;
static unsigned short sqrndbit[NI];
-static void
+static void
esqrt (x, y)
unsigned EMUSHORT *x, *y;
{
diff --git a/gnu/usr.bin/cc/cc_int/recog.c b/gnu/usr.bin/cc/cc_int/recog.c
index 1072fe9..f4aac50 100644
--- a/gnu/usr.bin/cc/cc_int/recog.c
+++ b/gnu/usr.bin/cc/cc_int/recog.c
@@ -259,7 +259,7 @@ apply_change_group ()
{
int j;
- newpat = gen_rtx (PARALLEL, VOIDmode,
+ newpat = gen_rtx (PARALLEL, VOIDmode,
gen_rtvec (XVECLEN (pat, 0) - 1));
for (j = 0; j < XVECLEN (newpat, 0); j++)
XVECEXP (newpat, 0, j) = XVECEXP (pat, 0, j);
@@ -379,10 +379,10 @@ validate_replace_rtx_1 (loc, from, to, object)
/* If we have have a PLUS whose second operand is now a CONST_INT, use
plus_constant to try to simplify it. */
if (GET_CODE (XEXP (x, 1)) == CONST_INT && XEXP (x, 1) == to)
- validate_change (object, loc,
+ validate_change (object, loc,
plus_constant (XEXP (x, 0), INTVAL (XEXP (x, 1))), 1);
return;
-
+
case ZERO_EXTEND:
case SIGN_EXTEND:
/* In these cases, the operation to be performed depends on the mode
@@ -405,7 +405,7 @@ validate_replace_rtx_1 (loc, from, to, object)
return;
}
break;
-
+
case SUBREG:
/* If we have a SUBREG of a register that we are replacing and we are
replacing it with a MEM, make a new MEM and try replacing the
@@ -494,7 +494,7 @@ validate_replace_rtx_1 (loc, from, to, object)
break;
}
-
+
fmt = GET_RTX_FORMAT (code);
for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
{
@@ -1283,7 +1283,7 @@ decode_asm_operands (body, operands, operand_locs, constraints, modes)
{
if (GET_CODE (XVECEXP (body, 0, i)) == CLOBBER)
break; /* Past last SET */
-
+
if (operands)
operands[i] = SET_DEST (XVECEXP (body, 0, i));
if (operand_locs)
@@ -1529,7 +1529,7 @@ adj_offsettable_operand (op, offset)
{
register enum rtx_code code = GET_CODE (op);
- if (code == MEM)
+ if (code == MEM)
{
register rtx y = XEXP (op, 0);
register rtx new;
@@ -1718,9 +1718,9 @@ constrain_operands (insn_code_num, strict)
case 'p':
/* p is used for address_operands. When we are called by
- gen_input_reload, no one will have checked that the
- address is strictly valid, i.e., that all pseudos
- requiring hard regs have gotten them. */
+ gen_reload, no one will have checked that the address is
+ strictly valid, i.e., that all pseudos requiring hard regs
+ have gotten them. */
if (strict <= 0
|| (strict_memory_address_p
(insn_operand_mode[insn_code_num][opno], op)))
diff --git a/gnu/usr.bin/cc/cc_int/reg-stack.c b/gnu/usr.bin/cc/cc_int/reg-stack.c
index dd30344..900b413 100644
--- a/gnu/usr.bin/cc/cc_int/reg-stack.c
+++ b/gnu/usr.bin/cc/cc_int/reg-stack.c
@@ -225,9 +225,8 @@ static rtx FP_mode_reg[FIRST_PSEUDO_REGISTER][(int) MAX_MACHINE_MODE];
definition are validity of this information. */
#define BLOCK_NUM(INSN) \
- (((INSN_UID (INSN) > max_uid) \
- ? (int *)(abort() , 0) \
- : block_number)[INSN_UID (INSN)])
+ ((INSN_UID (INSN) > max_uid) \
+ ? (abort() , -1) : block_number[INSN_UID (INSN)])
extern rtx forced_labels;
extern rtx gen_jump ();
@@ -368,8 +367,8 @@ reg_to_stack (first, file)
block_stack_in = (stack) alloca (blocks * sizeof (struct stack_def));
block_out_reg_set = (HARD_REG_SET *) alloca (blocks * sizeof (HARD_REG_SET));
- bzero (block_stack_in, blocks * sizeof (struct stack_def));
- bzero (block_out_reg_set, blocks * sizeof (HARD_REG_SET));
+ bzero ((char *) block_stack_in, blocks * sizeof (struct stack_def));
+ bzero ((char *) block_out_reg_set, blocks * sizeof (HARD_REG_SET));
block_number = (int *) alloca ((max_uid + 1) * sizeof (int));
@@ -766,7 +765,7 @@ record_asm_reg_life (insn, regstack, operands, constraints,
int *operand_matches = (int *) alloca (n_operands * sizeof (int *));
- enum reg_class *operand_class
+ enum reg_class *operand_class
= (enum reg_class *) alloca (n_operands * sizeof (enum reg_class *));
int reg_used_as_output[FIRST_PSEUDO_REGISTER];
@@ -819,7 +818,7 @@ record_asm_reg_life (insn, regstack, operands, constraints,
Also enforce rule #5: Output operands must start at the top of
the reg-stack: output operands may not "skip" a reg. */
- bzero (reg_used_as_output, sizeof (reg_used_as_output));
+ bzero ((char *) reg_used_as_output, sizeof (reg_used_as_output));
for (i = 0; i < n_outputs; i++)
if (STACK_REG_P (operands[i]))
if (reg_class_size[(int) operand_class[i]] != 1)
@@ -852,7 +851,7 @@ record_asm_reg_life (insn, regstack, operands, constraints,
to the top of the reg-stack than any input that is not implicitly
popped. */
- bzero (implicitly_dies, sizeof (implicitly_dies));
+ bzero ((char *) implicitly_dies, sizeof (implicitly_dies));
for (i = first_input; i < first_input + n_inputs; i++)
if (STACK_REG_P (operands[i]))
{
@@ -1216,7 +1215,7 @@ find_blocks (first)
label_value_list);
}
- BLOCK_NUM (insn) = block;
+ block_number[INSN_UID (insn)] = block;
if (code != NOTE)
prev_code = code;
@@ -1258,7 +1257,7 @@ find_blocks (first)
&& SET_DEST (pat) == pc_rtx
&& uses_reg_or_mem (SET_SRC (pat)))
computed_jump = 1;
-
+
if (computed_jump)
{
for (x = label_value_list; x; x = XEXP (x, 1))
@@ -1591,7 +1590,6 @@ delete_insn_for_stacker (insn)
PUT_CODE (insn, NOTE);
NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
NOTE_SOURCE_FILE (insn) = 0;
- INSN_DELETED_P (insn) = 1;
}
/* Emit an insn to pop virtual register REG before or after INSN.
@@ -2245,7 +2243,7 @@ subst_asm_stack_regs (insn, regstack, operands, operands_loc, constraints,
rtx body = PATTERN (insn);
int *operand_matches = (int *) alloca (n_operands * sizeof (int *));
- enum reg_class *operand_class
+ enum reg_class *operand_class
= (enum reg_class *) alloca (n_operands * sizeof (enum reg_class *));
rtx *note_reg; /* Array of note contents */
@@ -2343,7 +2341,7 @@ subst_asm_stack_regs (insn, regstack, operands, operands_loc, constraints,
}
}
- bcopy (regstack, &temp_stack, sizeof (temp_stack));
+ bcopy ((char *) regstack, (char *) &temp_stack, sizeof (temp_stack));
/* Put the input regs into the desired place in TEMP_STACK. */
@@ -2581,7 +2579,7 @@ subst_stack_regs (insn, regstack)
/* subst_stack_regs_pat may have deleted a no-op insn. If so, any
REG_UNUSED will already have been dealt with, so just return. */
- if (INSN_DELETED_P (insn))
+ if (GET_CODE (insn) == NOTE)
return;
/* If there is a REG_UNUSED note on a stack register on this insn,
diff --git a/gnu/usr.bin/cc/cc_int/regclass.c b/gnu/usr.bin/cc/cc_int/regclass.c
index d4636d5..33097aa 100644
--- a/gnu/usr.bin/cc/cc_int/regclass.c
+++ b/gnu/usr.bin/cc/cc_int/regclass.c
@@ -83,7 +83,7 @@ HARD_REG_SET call_used_reg_set;
/* Data for initializing the above. */
static char initial_call_used_regs[] = CALL_USED_REGISTERS;
-
+
/* Indexed by hard register number, contains 1 for registers that are
fixed use -- i.e. in fixed_regs -- or a function value return register
or STRUCT_VALUE_REGNUM or STATIC_CHAIN_REGNUM. These are the
@@ -106,7 +106,7 @@ int n_non_fixed_regs;
and are also considered fixed. */
char global_regs[FIRST_PSEUDO_REGISTER];
-
+
/* Table of register numbers in the order in which to try to use them. */
#ifdef REG_ALLOC_ORDER
int reg_alloc_order[FIRST_PSEUDO_REGISTER] = REG_ALLOC_ORDER;
@@ -123,7 +123,7 @@ HARD_REG_SET reg_class_contents[N_REG_CLASSES];
#define N_REG_INTS \
((FIRST_PSEUDO_REGISTER + (HOST_BITS_PER_INT - 1)) / HOST_BITS_PER_INT)
-static unsigned int_reg_class_contents[N_REG_CLASSES][N_REG_INTS]
+static unsigned int_reg_class_contents[N_REG_CLASSES][N_REG_INTS]
= REG_CLASS_CONTENTS;
/* For each reg class, number of regs it contains. */
@@ -567,7 +567,7 @@ static char *prefclass;
It might appear to be more general to have a bitmask of classes here,
but since it is recommended that there be a class corresponding to the
- union of most major pair of classes, that generality is not required.
+ union of most major pair of classes, that generality is not required.
This is available after `regclass' is run. */
@@ -584,7 +584,7 @@ static int loop_cost;
static void record_reg_classes PROTO((int, int, rtx *, enum machine_mode *,
char **, rtx));
-static int copy_cost PROTO((rtx, enum machine_mode,
+static int copy_cost PROTO((rtx, enum machine_mode,
enum reg_class, int));
static void record_address_regs PROTO((rtx, enum reg_class, int));
static auto_inc_dec_reg_p PROTO((rtx, enum machine_mode));
@@ -777,7 +777,7 @@ regclass (f, nregs)
BASE_REG_CLASS, loop_cost * 2);
continue;
}
-
+
/* Improve handling of two-address insns such as
(set X (ashift CONST Y)) where CONST must be made to
match X. Change it into two insns: (set X CONST)
@@ -848,7 +848,7 @@ regclass (f, nregs)
Then handle any address registers. Finally record the desired
classes for any pseudos, doing it twice if some pair of
operands are commutative. */
-
+
for (i = 0; i < noperands; i++)
{
op_costs[i] = init_cost;
@@ -867,7 +867,7 @@ regclass (f, nregs)
/* Check for commutative in a separate loop so everything will
have been initialized. We must do this even if one operand
is a constant--see addsi3 in m68k.md. */
-
+
for (i = 0; i < noperands - 1; i++)
if (constraints[i][0] == '%')
{
@@ -911,7 +911,7 @@ regclass (f, nregs)
and find which class is preferred. Store that in
`prefclass[REGNO]'. Record in `altclass[REGNO]' the largest register
class any of whose registers is better than memory. */
-
+
if (pass == 0)
{
prefclass = (char *) oballoc (nregs);
@@ -964,7 +964,7 @@ regclass (f, nregs)
#endif
)
alt = reg_class_subunion[(int) alt][class];
-
+
/* If we don't add any classes, nothing to try. */
if (alt == best)
alt = (int) NO_REGS;
@@ -996,7 +996,7 @@ regclass (f, nregs)
This procedure works alternative by alternative. For each alternative
we assume that we will be able to allocate all pseudos to their ideal
register class and calculate the cost of using that alternative. Then
- we compute for each operand that is a pseudo-register, the cost of
+ we compute for each operand that is a pseudo-register, the cost of
having the pseudo allocated to each register class and using it in that
alternative. To this cost is added the cost of the alternative.
@@ -1041,7 +1041,7 @@ record_reg_classes (n_alts, n_ops, ops, modes, constraints, insn)
int win = 0;
char c;
- /* If this operand has no constraints at all, we can conclude
+ /* If this operand has no constraints at all, we can conclude
nothing about it since anything is valid. */
if (*p == 0)
@@ -1082,7 +1082,7 @@ record_reg_classes (n_alts, n_ops, ops, modes, constraints, insn)
|| REGNO (ops[j]) < FIRST_PSEUDO_REGISTER)
{
/* This op is a pseudo but the one it matches is not. */
-
+
/* If we can't put the other operand into a register, this
alternative can't be used. */
@@ -1375,7 +1375,7 @@ copy_cost (x, mode, class, to_p)
class = PREFERRED_RELOAD_CLASS (x, class);
#ifdef HAVE_SECONDARY_RELOADS
- /* If we need a secondary reload (we assume here that we are using
+ /* If we need a secondary reload (we assume here that we are using
the secondary reload as an intermediate, not a scratch register), the
cost is that to load the input into the intermediate register, then
to copy them. We use a special value of TO_P to avoid recursion. */
@@ -1470,7 +1470,7 @@ record_address_regs (x, class, scale)
/* If index and base registers are the same on this machine, just
record registers in any non-constant operands. We assume here,
- as well as in the tests below, that all addresses are in
+ as well as in the tests below, that all addresses are in
canonical form. */
else if (INDEX_REG_CLASS == BASE_REG_CLASS)
@@ -1492,7 +1492,7 @@ record_address_regs (x, class, scale)
else if (code1 == SYMBOL_REF || code1 == CONST || code1 == LABEL_REF)
record_address_regs (arg0, INDEX_REG_CLASS, scale);
- /* If this the sum of two registers where the first is known to be a
+ /* If this the sum of two registers where the first is known to be a
pointer, it must be a base register with the second an index. */
else if (code0 == REG && code1 == REG
@@ -1573,7 +1573,7 @@ record_address_regs (x, class, scale)
/* Return 1 if REG is valid as an auto-increment memory reference
to an object of MODE. */
-static
+static
auto_inc_dec_reg_p (reg, mode)
rtx reg;
enum machine_mode mode;
@@ -1753,7 +1753,7 @@ reg_scan_mark_refs (x, insn, note_flag)
Likewise if it is setting the destination from an address or from a
value equivalent to an address or to the sum of an address and
something else.
-
+
But don't do any of this if the pseudo corresponds to a user
variable since it should have already been set as a pointer based
on the type. */
diff --git a/gnu/usr.bin/cc/cc_int/reload.c b/gnu/usr.bin/cc/cc_int/reload.c
index b9a1c27..92a617b 100644
--- a/gnu/usr.bin/cc/cc_int/reload.c
+++ b/gnu/usr.bin/cc/cc_int/reload.c
@@ -86,6 +86,7 @@ a register with any other reload. */
#define REG_OK_STRICT
+#include <stdio.h>
#include "config.h"
#include "rtl.h"
#include "insn-config.h"
@@ -224,9 +225,9 @@ static int n_memlocs;
#ifdef SECONDARY_MEMORY_NEEDED
/* Save MEMs needed to copy from one class of registers to another. One MEM
- is used per mode, but normally only one or two modes are ever used.
+ is used per mode, but normally only one or two modes are ever used.
- We keep two versions, before and after register elimination. The one
+ We keep two versions, before and after register elimination. The one
after register elimination is record separately for each operand. This
is done in case the address is not valid to be sure that we separately
reload each. */
@@ -397,7 +398,7 @@ push_secondary_reload (in_p, x, opnum, optional, reload_class, reload_mode,
if (icode != CODE_FOR_nothing)
{
- /* If IN_P is non-zero, the reload register will be the output in
+ /* If IN_P is non-zero, the reload register will be the output in
operand 0. If IN_P is zero, the reload register will be the input
in operand 1. Outputs should have an initial "=", which we must
skip. */
@@ -564,7 +565,7 @@ push_secondary_reload (in_p, x, opnum, optional, reload_class, reload_mode,
reload_when_needed[s_reload] = secondary_type;
reload_secondary_in_reload[s_reload] = in_p ? t_reload : -1;
reload_secondary_out_reload[s_reload] = ! in_p ? t_reload : -1;
- reload_secondary_in_icode[s_reload] = in_p ? t_icode : CODE_FOR_nothing;
+ reload_secondary_in_icode[s_reload] = in_p ? t_icode : CODE_FOR_nothing;
reload_secondary_out_icode[s_reload]
= ! in_p ? t_icode : CODE_FOR_nothing;
reload_secondary_p[s_reload] = 1;
@@ -592,7 +593,7 @@ push_secondary_reload (in_p, x, opnum, optional, reload_class, reload_mode,
#ifdef SECONDARY_MEMORY_NEEDED
-/* Return a memory location that will be used to copy X in mode MODE.
+/* Return a memory location that will be used to copy X in mode MODE.
If we haven't already made a location for this mode in this insn,
call find_reloads_address on the location being returned. */
@@ -622,7 +623,7 @@ get_secondary_mem (x, mode, opnum, type)
if (secondary_memlocs_elim[(int) mode][opnum] != 0)
return secondary_memlocs_elim[(int) mode][opnum];
- /* If this is the first time we've tried to get a MEM for this mode,
+ /* If this is the first time we've tried to get a MEM for this mode,
allocate a new one. `something_changed' in reload will get set
by noticing that the frame size has changed. */
@@ -734,7 +735,7 @@ push_reload (in, out, inloc, outloc, class,
if (outmode == VOIDmode && out != 0)
outmode = GET_MODE (out);
- /* If IN is a pseudo register everywhere-equivalent to a constant, and
+ /* If IN is a pseudo register everywhere-equivalent to a constant, and
it is not in a hard register, reload straight from the constant,
since we want to get rid of such pseudo registers.
Often this is done earlier, but not always in find_reloads_address. */
@@ -777,8 +778,8 @@ push_reload (in, out, inloc, outloc, class,
a pseudo and hence will become a MEM) with M1 wider than M2 and the
register is a pseudo, also reload the inside expression.
For machines that extend byte loads, do this for any SUBREG of a pseudo
- where both M1 and M2 are a word or smaller unless they are the same
- size.
+ where both M1 and M2 are a word or smaller, M1 is wider than M2, and
+ M2 is an integral mode that gets extended when loaded.
Similar issue for (SUBREG:M1 (REG:M2 ...) ...) for a hard register R where
either M1 is not valid for R or M2 is wider than a word but we only
need one word to store an M2-sized quantity in R.
@@ -792,7 +793,11 @@ push_reload (in, out, inloc, outloc, class,
STRICT_LOW_PART (presumably, in == out in the cas).
Also reload the inner expression if it does not require a secondary
- reload but the SUBREG does. */
+ reload but the SUBREG does.
+
+ Finally, reload the inner expression if it is a register that is in
+ the class whose registers cannot be referenced in a different size
+ and M1 is not the same size as M2. */
if (in != 0 && GET_CODE (in) == SUBREG
&& (CONSTANT_P (SUBREG_REG (in))
@@ -808,7 +813,9 @@ push_reload (in, out, inloc, outloc, class,
&& (GET_MODE_SIZE (GET_MODE (SUBREG_REG (in)))
<= UNITS_PER_WORD)
&& (GET_MODE_SIZE (inmode)
- != GET_MODE_SIZE (GET_MODE (SUBREG_REG (in)))))
+ > GET_MODE_SIZE (GET_MODE (SUBREG_REG (in))))
+ && INTEGRAL_MODE_P (GET_MODE (SUBREG_REG (in)))
+ && LOAD_EXTEND_OP (GET_MODE (SUBREG_REG (in))) != NIL)
#endif
))
|| (GET_CODE (SUBREG_REG (in)) == REG
@@ -833,6 +840,15 @@ push_reload (in, out, inloc, outloc, class,
SUBREG_REG (in))
== NO_REGS))
#endif
+#ifdef CLASS_CANNOT_CHANGE_SIZE
+ || (GET_CODE (SUBREG_REG (in)) == REG
+ && REGNO (SUBREG_REG (in)) < FIRST_PSEUDO_REGISTER
+ && (TEST_HARD_REG_BIT
+ (reg_class_contents[(int) CLASS_CANNOT_CHANGE_SIZE],
+ REGNO (SUBREG_REG (in))))
+ && (GET_MODE_SIZE (GET_MODE (SUBREG_REG (in)))
+ != GET_MODE_SIZE (inmode)))
+#endif
))
{
in_subreg_loc = inloc;
@@ -885,15 +901,7 @@ push_reload (in, out, inloc, outloc, class,
&& REGNO (SUBREG_REG (out)) >= FIRST_PSEUDO_REGISTER)
|| GET_CODE (SUBREG_REG (out)) == MEM)
&& ((GET_MODE_SIZE (outmode)
- > GET_MODE_SIZE (GET_MODE (SUBREG_REG (out))))
-#ifdef LOAD_EXTEND_OP
- || (GET_MODE_SIZE (outmode) <= UNITS_PER_WORD
- && (GET_MODE_SIZE (GET_MODE (SUBREG_REG (out)))
- <= UNITS_PER_WORD)
- && (GET_MODE_SIZE (outmode)
- != GET_MODE_SIZE (GET_MODE (SUBREG_REG (out)))))
-#endif
- ))
+ > GET_MODE_SIZE (GET_MODE (SUBREG_REG (out))))))
|| (GET_CODE (SUBREG_REG (out)) == REG
&& REGNO (SUBREG_REG (out)) < FIRST_PSEUDO_REGISTER
&& ((GET_MODE_SIZE (outmode) <= UNITS_PER_WORD
@@ -913,11 +921,20 @@ push_reload (in, out, inloc, outloc, class,
SUBREG_REG (out))
== NO_REGS))
#endif
+#ifdef CLASS_CANNOT_CHANGE_SIZE
+ || (GET_CODE (SUBREG_REG (out)) == REG
+ && REGNO (SUBREG_REG (out)) < FIRST_PSEUDO_REGISTER
+ && (TEST_HARD_REG_BIT
+ (reg_class_contents[(int) CLASS_CANNOT_CHANGE_SIZE],
+ REGNO (SUBREG_REG (out))))
+ && (GET_MODE_SIZE (GET_MODE (SUBREG_REG (out)))
+ != GET_MODE_SIZE (outmode)))
+#endif
))
{
out_subreg_loc = outloc;
outloc = &SUBREG_REG (out);
- out = *outloc;
+ out = *outloc;
#ifndef LOAD_EXTEND_OP
if (GET_CODE (out) == MEM
&& GET_MODE_SIZE (GET_MODE (out)) > GET_MODE_SIZE (outmode))
@@ -1018,7 +1035,7 @@ push_reload (in, out, inloc, outloc, class,
/* We can use an existing reload if the class is right
and at least one of IN and OUT is a match
and the other is at worst neutral.
- (A zero compared against anything is neutral.)
+ (A zero compared against anything is neutral.)
If SMALL_REGISTER_CLASSES, don't use existing reloads unless they are
for the same thing since that can cause us to need more reload registers
@@ -1761,7 +1778,7 @@ operands_match_p (x, y)
register RTX_CODE code = GET_CODE (x);
register char *fmt;
int success_2;
-
+
if (x == y)
return 1;
if ((code == REG || (code == SUBREG && GET_CODE (SUBREG_REG (x)) == REG))
@@ -1820,7 +1837,7 @@ operands_match_p (x, y)
slow:
- /* Now we have disposed of all the cases
+ /* Now we have disposed of all the cases
in which different rtx codes can match. */
if (code != GET_CODE (y))
return 0;
@@ -1881,7 +1898,7 @@ operands_match_p (x, y)
int
n_occurrences (c, s)
- char c;
+ int c;
char *s;
{
int n = 0;
@@ -1891,11 +1908,11 @@ n_occurrences (c, s)
}
/* Describe the range of registers or memory referenced by X.
- If X is a register, set REG_FLAG and put the first register
+ If X is a register, set REG_FLAG and put the first register
number into START and the last plus one into END.
- If X is a memory reference, put a base address into BASE
+ If X is a memory reference, put a base address into BASE
and a range of integer offsets into START and END.
- If X is pushing on the stack, we can assume it causes no trouble,
+ If X is pushing on the stack, we can assume it causes no trouble,
so we set the SAFE field. */
static struct decomposition
@@ -1945,7 +1962,7 @@ decompose (x)
{
base = addr;
offset = const0_rtx;
- }
+ }
if (GET_CODE (offset) == CONST)
offset = XEXP (offset, 0);
if (GET_CODE (offset) == PLUS)
@@ -1986,7 +2003,7 @@ decompose (x)
else if (GET_CODE (x) == REG)
{
val.reg_flag = 1;
- val.start = true_regnum (x);
+ val.start = true_regnum (x);
if (val.start < 0)
{
/* A pseudo with no hard reg. */
@@ -2003,7 +2020,7 @@ decompose (x)
/* This could be more precise, but it's good enough. */
return decompose (SUBREG_REG (x));
val.reg_flag = 1;
- val.start = true_regnum (x);
+ val.start = true_regnum (x);
if (val.start < 0)
return decompose (SUBREG_REG (x));
else
@@ -2175,7 +2192,7 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
if (reg_set_p (cc0_rtx, PATTERN (insn)))
no_output_reloads = 1;
#endif
-
+
#ifdef SECONDARY_MEMORY_NEEDED
/* The eliminated forms of any secondary memory locations are per-insn, so
clear them out here. */
@@ -2289,7 +2306,7 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
modified[i] = RELOAD_READ;
- /* Scan this operand's constraint to see if it is an output operand,
+ /* Scan this operand's constraint to see if it is an output operand,
an in-out operand, is commutative, or should match another. */
while (c = *p++)
@@ -2356,7 +2373,7 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
and reload parts of the addresses into index registers.
Also here any references to pseudo regs that didn't get hard regs
but are equivalent to constants get replaced in the insn itself
- with those constants. Nobody will ever see them again.
+ with those constants. Nobody will ever see them again.
Finally, set up the preferred classes of each operand. */
@@ -2401,7 +2418,7 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
&& &SET_DEST (set) == recog_operand_loc[i]);
else if (code == PLUS)
/* We can get a PLUS as an "operand" as a result of
- register elimination. See eliminate_regs and gen_input_reload. */
+ register elimination. See eliminate_regs and gen_reload. */
substed_operand[i] = recog_operand[i] = *recog_operand_loc[i]
= find_reloads_toplev (recog_operand[i], i, address_type[i],
ind_levels, 0);
@@ -2434,7 +2451,7 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
address = copy_rtx (address);
/* If this is an output operand, we must output a CLOBBER
- after INSN so find_equiv_reg knows REGNO is being written.
+ after INSN so find_equiv_reg knows REGNO is being written.
Mark this insn specially, do we can put our output reloads
after it. */
@@ -2509,7 +2526,7 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
/* REJECT is a count of how undesirable this alternative says it is
if any reloading is required. If the alternative matches exactly
then REJECT is ignored, but otherwise it gets this much
- counted against it in addition to the reloading needed. Each
+ counted against it in addition to the reloading needed. Each
? counts three times here since we want the disparaging caused by
a bad register class to only count 1/3 as much. */
int reject = 0;
@@ -2550,15 +2567,18 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
|| GET_CODE (operand) == PLUS
/* We must force a reload of paradoxical SUBREGs
of a MEM because the alignment of the inner value
- may not be enough to do the outer reference.
+ may not be enough to do the outer reference. On
+ big-endian machines, it may also reference outside
+ the object.
On machines that extend byte operations and we have a
- SUBREG where both the inner and outer modes are different
- size but no wider than a word, combine.c has made
- assumptions about the behavior of the machine in such
+ SUBREG where both the inner and outer modes are no wider
+ than a word and the inner mode is narrower, is integral,
+ and gets extended when loaded from memory, combine.c has
+ made assumptions about the behavior of the machine in such
register access. If the data is, in fact, in memory we
must always load using the size assumed to be in the
- register and let the insn do the different-sized
+ register and let the insn do the different-sized
accesses. */
|| ((GET_CODE (operand) == MEM
|| (GET_CODE (operand)== REG
@@ -2567,12 +2587,15 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
< BIGGEST_ALIGNMENT)
&& (GET_MODE_SIZE (operand_mode[i])
> GET_MODE_SIZE (GET_MODE (operand))))
+ || (GET_CODE (operand) == MEM && BYTES_BIG_ENDIAN)
#ifdef LOAD_EXTEND_OP
|| (GET_MODE_SIZE (operand_mode[i]) <= UNITS_PER_WORD
&& (GET_MODE_SIZE (GET_MODE (operand))
<= UNITS_PER_WORD)
&& (GET_MODE_SIZE (operand_mode[i])
- != GET_MODE_SIZE (GET_MODE (operand))))
+ > GET_MODE_SIZE (GET_MODE (operand)))
+ && INTEGRAL_MODE_P (GET_MODE (operand))
+ && LOAD_EXTEND_OP (GET_MODE (operand)) != NIL)
#endif
))
/* Subreg of a hard reg which can't handle the subreg's mode
@@ -2708,7 +2731,7 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
case 'p':
/* All necessary reloads for an address_operand
were handled in find_reloads_address. */
- this_alternative[i] = (int) ALL_REGS;
+ this_alternative[i] = (int) BASE_REG_CLASS;
win = 1;
break;
@@ -2868,8 +2891,8 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
/* A SCRATCH is not a valid operand. */
&& GET_CODE (operand) != SCRATCH
#ifdef LEGITIMATE_PIC_OPERAND_P
- && (! CONSTANT_P (operand)
- || ! flag_pic
+ && (! CONSTANT_P (operand)
+ || ! flag_pic
|| LEGITIMATE_PIC_OPERAND_P (operand))
#endif
&& (GENERAL_REGS == ALL_REGS
@@ -2894,11 +2917,11 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
win = 1;
break;
#endif
-
+
default:
this_alternative[i]
= (int) reg_class_subunion[this_alternative[i]][(int) REG_CLASS_FROM_LETTER (c)];
-
+
reg:
if (GET_MODE (operand) == BLKmode)
break;
@@ -2950,7 +2973,7 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
reload. This is consistent with other code and is
required to avoid chosing another alternative when
the constant is moved into memory by this function on
- an early reload pass. Note that the test here is
+ an early reload pass. Note that the test here is
precisely the same as in the code below that calls
force_const_mem. */
if (CONSTANT_P (operand)
@@ -2981,7 +3004,7 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
/* We prefer to reload pseudos over reloading other things,
since such reloads may be able to be eliminated later.
If we are reloading a SCRATCH, we won't be generating any
- insns, just using a register, so it is also preferred.
+ insns, just using a register, so it is also preferred.
So bump REJECT in other cases. Don't do this in the
case where we are forcing a constant into memory and
it will then win since we don't want to have a different
@@ -2993,7 +3016,7 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
reject++;
}
- /* If this operand is a pseudo register that didn't get a hard
+ /* If this operand is a pseudo register that didn't get a hard
reg and this alternative accepts some register, see if the
class that we want is a subset of the preferred class for this
register. If not, but it intersects that class, use the
@@ -3024,7 +3047,7 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
{
/* Since we don't have a way of forming the intersection,
we just do something special if the preferred class
- is a subset of the class we have; that's the most
+ is a subset of the class we have; that's the most
common case anyway. */
if (reg_class_subset_p (preferred_class[i],
this_alternative[i]))
@@ -3043,7 +3066,7 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
if (this_alternative_earlyclobber[i]
&& this_alternative_win[i])
{
- struct decomposition early_data;
+ struct decomposition early_data;
early_data = decompose (recog_operand[i]);
@@ -3056,7 +3079,7 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
abort ();
continue;
}
-
+
if (this_alternative[i] == NO_REGS)
{
this_alternative_earlyclobber[i] = 0;
@@ -3278,9 +3301,9 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
One special case that is worth checking is when we have an
output that is earlyclobber but isn't used past the insn (typically
- a SCRATCH). In this case, we only need have the reload live
+ a SCRATCH). In this case, we only need have the reload live
through the insn itself, but not for any of our input or output
- reloads.
+ reloads.
In any case, anything needed to address this operand can remain
however they were previously categorized. */
@@ -3416,7 +3439,7 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
&& goal_alternative_matches[i] < 0
&& optimize)
{
- /* For each non-matching operand that's a MEM or a pseudo-register
+ /* For each non-matching operand that's a MEM or a pseudo-register
that didn't get a hard register, make an optional reload.
This may get done even if the insn needs no reloads otherwise. */
@@ -3479,7 +3502,7 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
operand_mode[i],
0, 1, goal_alternative_matches[i], RELOAD_OTHER);
}
-
+
/* If this insn pattern contains any MATCH_DUP's, make sure that
they will be substituted if the operands they match are substituted.
Also do now any substitutions we already did on the operands.
@@ -3561,7 +3584,7 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
}
}
- /* Scan all the reloads and update their type.
+ /* Scan all the reloads and update their type.
If a reload is for the address of an operand and we didn't reload
that operand, change the type. Similarly, change the operand number
of a reload when two operands match. If a reload is optional, treat it
@@ -3597,13 +3620,13 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
{
int secondary_in_reload = reload_secondary_in_reload[i];
- reload_when_needed[secondary_in_reload] =
+ reload_when_needed[secondary_in_reload] =
RELOAD_FOR_OPADDR_ADDR;
/* If there's a tertiary reload we have to change it also. */
if (secondary_in_reload > 0
&& reload_secondary_in_reload[secondary_in_reload] != -1)
- reload_when_needed[reload_secondary_in_reload[secondary_in_reload]]
+ reload_when_needed[reload_secondary_in_reload[secondary_in_reload]]
= RELOAD_FOR_OPADDR_ADDR;
}
@@ -3612,13 +3635,13 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
{
int secondary_out_reload = reload_secondary_out_reload[i];
- reload_when_needed[secondary_out_reload] =
+ reload_when_needed[secondary_out_reload] =
RELOAD_FOR_OPADDR_ADDR;
/* If there's a tertiary reload we have to change it also. */
if (secondary_out_reload
&& reload_secondary_out_reload[secondary_out_reload] != -1)
- reload_when_needed[reload_secondary_out_reload[secondary_out_reload]]
+ reload_when_needed[reload_secondary_out_reload[secondary_out_reload]]
= RELOAD_FOR_OPADDR_ADDR;
}
reload_when_needed[i] = RELOAD_FOR_OPERAND_ADDRESS;
@@ -3626,7 +3649,7 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
if (reload_when_needed[i] == RELOAD_FOR_INPUT_ADDRESS
&& operand_reloadnum[reload_opnum[i]] >= 0
- && (reload_when_needed[operand_reloadnum[reload_opnum[i]]]
+ && (reload_when_needed[operand_reloadnum[reload_opnum[i]]]
== RELOAD_OTHER))
reload_when_needed[i] = RELOAD_FOR_OTHER_ADDRESS;
@@ -3852,7 +3875,7 @@ find_reloads_toplev (x, opnum, type, ind_levels, is_set_dest)
if (code == SUBREG && GET_CODE (SUBREG_REG (x)) == REG)
{
- /* Check for SUBREG containing a REG that's equivalent to a constant.
+ /* Check for SUBREG containing a REG that's equivalent to a constant.
If the constant has a known value, truncate it right now.
Similarly if we are extracting a single-word of a multi-word
constant. If the constant is symbolic, allow it to be substituted
@@ -3904,7 +3927,7 @@ find_reloads_toplev (x, opnum, type, ind_levels, is_set_dest)
#endif
&& (reg_equiv_address[regno] != 0
|| (reg_equiv_mem[regno] != 0
- && (! strict_memory_address_p (GET_MODE (x),
+ && (! strict_memory_address_p (GET_MODE (x),
XEXP (reg_equiv_mem[regno], 0))
|| ! offsettable_memref_p (reg_equiv_mem[regno])))))
{
@@ -4171,7 +4194,7 @@ find_reloads_address (mode, memrefloc, ad, loc, opnum, type, ind_levels)
/* If we have an indexed stack slot, there are three possible reasons why
it might be invalid: The index might need to be reloaded, the address
might have been made by frame pointer elimination and hence have a
- constant out of range, or both reasons might apply.
+ constant out of range, or both reasons might apply.
We can easily check for an index needing reload, but even if that is the
case, we might also have an invalid constant. To avoid making the
@@ -4219,7 +4242,7 @@ find_reloads_address (mode, memrefloc, ad, loc, opnum, type, ind_levels)
return 1;
}
-
+
else if (GET_CODE (ad) == PLUS && GET_CODE (XEXP (ad, 1)) == CONST_INT
&& GET_CODE (XEXP (ad, 0)) == PLUS
&& (XEXP (XEXP (ad, 0), 1) == frame_pointer_rtx
@@ -4233,16 +4256,16 @@ find_reloads_address (mode, memrefloc, ad, loc, opnum, type, ind_levels)
&& ! memory_address_p (mode, ad))
{
*loc = ad = gen_rtx (PLUS, GET_MODE (ad),
+ XEXP (XEXP (ad, 0), 0),
plus_constant (XEXP (XEXP (ad, 0), 1),
- INTVAL (XEXP (ad, 1))),
- XEXP (XEXP (ad, 0), 0));
- find_reloads_address_part (XEXP (ad, 0), &XEXP (ad, 0), BASE_REG_CLASS,
+ INTVAL (XEXP (ad, 1))));
+ find_reloads_address_part (XEXP (ad, 1), &XEXP (ad, 1), BASE_REG_CLASS,
GET_MODE (ad), opnum, type, ind_levels);
- find_reloads_address_1 (XEXP (ad, 1), 1, &XEXP (ad, 1), opnum, type, 0);
+ find_reloads_address_1 (XEXP (ad, 0), 1, &XEXP (ad, 0), opnum, type, 0);
return 1;
}
-
+
/* See if address becomes valid when an eliminable register
in a sum is replaced. */
@@ -4535,7 +4558,7 @@ find_reloads_address_1 (x, context, loc, opnum, type, ind_levels)
&& REG_OK_FOR_BASE_P (op0))
return 0;
else if (REG_OK_FOR_BASE_P (op1))
- find_reloads_address_1 (orig_op0, 1, &XEXP (x, 0), opnum, type,
+ find_reloads_address_1 (orig_op0, 1, &XEXP (x, 0), opnum, type,
ind_levels);
else if (REG_OK_FOR_BASE_P (op0))
find_reloads_address_1 (orig_op1, 1, &XEXP (x, 1), opnum, type,
@@ -4704,7 +4727,7 @@ find_reloads_address_1 (x, context, loc, opnum, type, ind_levels)
if (reg_equiv_constant[regno] != 0)
{
- find_reloads_address_part (reg_equiv_constant[regno], loc,
+ find_reloads_address_part (reg_equiv_constant[regno], loc,
(context ? INDEX_REG_CLASS
: BASE_REG_CLASS),
GET_MODE (x), opnum, type, ind_levels);
@@ -5020,7 +5043,7 @@ refers_to_regno_for_reload_p (regno, endregno, x, loc)
}
return (endregno > i
- && regno < i + (i < FIRST_PSEUDO_REGISTER
+ && regno < i + (i < FIRST_PSEUDO_REGISTER
? HARD_REGNO_NREGS (i, GET_MODE (x))
: 1));
@@ -5100,7 +5123,7 @@ refers_to_regno_for_reload_p (regno, endregno, x, loc)
we check if any register number in X conflicts with the relevant register
numbers. If X is a constant, return 0. If X is a MEM, return 1 iff IN
contains a MEM (we don't bother checking for memory addresses that can't
- conflict because we expect this to be a rare case.
+ conflict because we expect this to be a rare case.
This function is similar to reg_overlap_mention_p in rtlanal.c except
that we look at equivalences for pseudos that didn't get hard registers. */
@@ -5165,14 +5188,14 @@ refers_to_mem_for_reload_p (x)
if (GET_CODE (x) == REG)
return (REGNO (x) >= FIRST_PSEUDO_REGISTER
&& reg_equiv_memory_loc[REGNO (x)]);
-
+
fmt = GET_RTX_FORMAT (GET_CODE (x));
for (i = GET_RTX_LENGTH (GET_CODE (x)) - 1; i >= 0; i--)
if (fmt[i] == 'e'
&& (GET_CODE (XEXP (x, i)) == MEM
|| refers_to_mem_for_reload_p (XEXP (x, i))))
return 1;
-
+
return 0;
}
@@ -5258,12 +5281,12 @@ find_equiv_reg (goal, insn, class, other, reload_reg_p, goalreg, mode)
/* On some machines, certain regs must always be rejected
because they don't behave the way ordinary registers do. */
-
+
#ifdef OVERLAPPING_REGNO_P
if (regno >= 0 && regno < FIRST_PSEUDO_REGISTER
&& OVERLAPPING_REGNO_P (regno))
return 0;
-#endif
+#endif
/* Scan insns back from INSN, looking for one that copies
a value into or out of GOAL.
@@ -5402,11 +5425,11 @@ find_equiv_reg (goal, insn, class, other, reload_reg_p, goalreg, mode)
/* On some machines, certain regs must always be rejected
because they don't behave the way ordinary registers do. */
-
+
#ifdef OVERLAPPING_REGNO_P
if (OVERLAPPING_REGNO_P (valueno))
return 0;
-#endif
+#endif
nregs = HARD_REGNO_NREGS (regno, mode);
valuenregs = HARD_REGNO_NREGS (valueno, mode);
@@ -5648,3 +5671,110 @@ regno_clobbered_p (regno, insn)
return 0;
}
+
+static char *reload_when_needed_name[] =
+{
+ "RELOAD_FOR_INPUT",
+ "RELOAD_FOR_OUTPUT",
+ "RELOAD_FOR_INSN",
+ "RELOAD_FOR_INPUT_ADDRESS",
+ "RELOAD_FOR_OUTPUT_ADDRESS",
+ "RELOAD_FOR_OPERAND_ADDRESS",
+ "RELOAD_FOR_OPADDR_ADDR",
+ "RELOAD_OTHER",
+ "RELOAD_FOR_OTHER_ADDRESS"
+};
+
+static char *reg_class_names[] = REG_CLASS_NAMES;
+
+/* This function is used to print the variables set by 'find_reloads' */
+
+void
+debug_reload()
+{
+ int r;
+
+ fprintf (stderr, "\nn_reloads = %d\n", n_reloads);
+
+ for (r = 0; r < n_reloads; r++)
+ {
+ fprintf (stderr, "\nRELOAD %d\n", r);
+
+ if (reload_in[r])
+ {
+ fprintf (stderr, "\nreload_in (%s) = ", mode_name[reload_inmode[r]]);
+ debug_rtx (reload_in[r]);
+ }
+
+ if (reload_out[r])
+ {
+ fprintf (stderr, "\nreload_out (%s) = ", mode_name[reload_outmode[r]]);
+ debug_rtx (reload_out[r]);
+ }
+
+ fprintf (stderr, "%s, ", reg_class_names[(int) reload_reg_class[r]]);
+
+ fprintf (stderr, "%s (opnum = %d)", reload_when_needed_name[(int)reload_when_needed[r]],
+ reload_opnum[r]);
+
+ if (reload_optional[r])
+ fprintf (stderr, ", optional");
+
+ if (reload_in[r])
+ fprintf (stderr, ", inc by %d\n", reload_inc[r]);
+
+ if (reload_nocombine[r])
+ fprintf (stderr, ", can combine", reload_nocombine[r]);
+
+ if (reload_secondary_p[r])
+ fprintf (stderr, ", secondary_reload_p");
+
+ if (reload_in_reg[r])
+ {
+ fprintf (stderr, "\nreload_in_reg:\t\t\t");
+ debug_rtx (reload_in_reg[r]);
+ }
+
+ if (reload_reg_rtx[r])
+ {
+ fprintf (stderr, "\nreload_reg_rtx:\t\t\t");
+ debug_rtx (reload_reg_rtx[r]);
+ }
+
+ if (reload_secondary_in_reload[r] != -1)
+ {
+ fprintf (stderr, "\nsecondary_in_reload = ");
+ fprintf (stderr, "%d ", reload_secondary_in_reload[r]);
+ }
+
+ if (reload_secondary_out_reload[r] != -1)
+ {
+ if (reload_secondary_in_reload[r] != -1)
+ fprintf (stderr, ", secondary_out_reload = ");
+ else
+ fprintf (stderr, "\nsecondary_out_reload = ");
+
+ fprintf (stderr, "%d", reload_secondary_out_reload[r]);
+ }
+
+
+ if (reload_secondary_in_icode[r] != CODE_FOR_nothing)
+ {
+ fprintf (stderr, "\nsecondary_in_icode = ");
+ fprintf (stderr, "%s", insn_name[r]);
+ }
+
+ if (reload_secondary_out_icode[r] != CODE_FOR_nothing)
+ {
+ if (reload_secondary_in_icode[r] != CODE_FOR_nothing)
+ fprintf (stderr, ", secondary_out_icode = ");
+ else
+ fprintf (stderr, "\nsecondary_out_icode = ");
+
+ fprintf (stderr, "%s ", insn_name[r]);
+ }
+ fprintf (stderr, "\n");
+ }
+
+ fprintf (stderr, "\n");
+}
diff --git a/gnu/usr.bin/cc/cc_int/reload1.c b/gnu/usr.bin/cc/cc_int/reload1.c
index e46d764..8eb4908d 100644
--- a/gnu/usr.bin/cc/cc_int/reload1.c
+++ b/gnu/usr.bin/cc/cc_int/reload1.c
@@ -327,7 +327,7 @@ struct hard_reg_n_uses { int regno; int uses; };
static int possible_group_p PROTO((int, int *));
static void count_possible_groups PROTO((int *, enum machine_mode *,
- int *));
+ int *, int));
static int modes_equiv_for_class_p PROTO((enum machine_mode,
enum machine_mode,
enum reg_class));
@@ -914,10 +914,10 @@ reload (first, global, dumpfile)
rtx old_notes = REG_NOTES (insn);
int did_elimination = 0;
- /* To compute the number of reload registers of each class
+ /* To compute the number of reload registers of each class
needed for an insn, we must similate what choose_reload_regs
can do. We do this by splitting an insn into an "input" and
- an "output" part. RELOAD_OTHER reloads are used in both.
+ an "output" part. RELOAD_OTHER reloads are used in both.
The input part uses those reloads, RELOAD_FOR_INPUT reloads,
which must be live over the entire input section of reloads,
and the maximum of all the RELOAD_FOR_INPUT_ADDRESS and
@@ -1153,7 +1153,8 @@ reload (first, global, dumpfile)
if (other_mode != VOIDmode && other_mode != allocate_mode
&& ! modes_equiv_for_class_p (allocate_mode,
other_mode, class))
- abort ();
+ fatal_insn ("Two dissimilar machine modes both need groups of consecutive regs of the same class",
+ insn);
}
else if (size == 1)
{
@@ -1278,10 +1279,10 @@ reload (first, global, dumpfile)
break;
}
- caller_save_needs
+ caller_save_needs
= (caller_save_group_size > 1
? insn_needs.other.groups
- : insn_needs.other.regs[nongroup_need]);
+ : insn_needs.other.regs[nongroup_need]);
if (caller_save_needs[(int) caller_save_spill_class] == 0)
{
@@ -1328,10 +1329,10 @@ reload (first, global, dumpfile)
need only in the smallest class in which it
is required. */
- bcopy (insn_needs.other.regs[0], basic_needs,
- sizeof basic_needs);
- bcopy (insn_needs.other.groups, basic_groups,
- sizeof basic_groups);
+ bcopy ((char *) insn_needs.other.regs[0],
+ (char *) basic_needs, sizeof basic_needs);
+ bcopy ((char *) insn_needs.other.groups,
+ (char *) basic_groups, sizeof basic_groups);
for (i = 0; i < N_REG_CLASSES; i++)
{
@@ -1349,19 +1350,14 @@ reload (first, global, dumpfile)
}
/* Now count extra regs if there might be a conflict with
- the return value register.
+ the return value register. */
- ??? This is not quite correct because we don't properly
- handle the case of groups, but if we end up doing
- something wrong, it either will end up not mattering or
- we will abort elsewhere. */
-
for (r = regno; r < regno + nregs; r++)
if (spill_reg_order[r] >= 0)
for (i = 0; i < N_REG_CLASSES; i++)
if (TEST_HARD_REG_BIT (reg_class_contents[i], r))
{
- if (basic_needs[i] > 0 || basic_groups[i] > 0)
+ if (basic_needs[i] > 0)
{
enum reg_class *p;
@@ -1370,6 +1366,15 @@ reload (first, global, dumpfile)
while (*p != LIM_REG_CLASSES)
insn_needs.other.regs[0][(int) *p++]++;
}
+ if (basic_groups[i] > 0)
+ {
+ enum reg_class *p;
+
+ insn_needs.other.groups[i]++;
+ p = reg_class_superclasses[i];
+ while (*p != LIM_REG_CLASSES)
+ insn_needs.other.groups[(int) *p++]++;
+ }
}
}
#endif /* SMALL_REGISTER_CLASSES */
@@ -1423,7 +1428,7 @@ reload (first, global, dumpfile)
mode_name[(int) group_mode[i]],
reg_class_names[i], INSN_UID (max_groups_insn[i]));
}
-
+
/* If we have caller-saves, set up the save areas and see if caller-save
will need a spill register. */
@@ -1537,8 +1542,8 @@ reload (first, global, dumpfile)
were in a block that didn't need any spill registers of a conflicting
class. We used to try to mark off the need for those registers,
but doing so properly is very complex and reallocating them is the
- simpler approach. First, "pack" potential_reload_regs by pushing
- any nonnegative entries towards the end. That will leave room
+ simpler approach. First, "pack" potential_reload_regs by pushing
+ any nonnegative entries towards the end. That will leave room
for the registers we already spilled.
Also, undo the marking of the spill registers from the last time
@@ -1603,7 +1608,8 @@ reload (first, global, dumpfile)
/* If any single spilled regs happen to form groups,
count them now. Maybe we don't really need
to spill another group. */
- count_possible_groups (group_size, group_mode, max_groups);
+ count_possible_groups (group_size, group_mode, max_groups,
+ class);
if (max_groups[class] <= 0)
break;
@@ -2063,68 +2069,65 @@ possible_group_p (regno, max_groups)
return 0;
}
-/* Count any groups that can be formed from the registers recently spilled.
- This is done class by class, in order of ascending class number. */
+/* Count any groups of CLASS that can be formed from the registers recently
+ spilled. */
static void
-count_possible_groups (group_size, group_mode, max_groups)
+count_possible_groups (group_size, group_mode, max_groups, class)
int *group_size;
enum machine_mode *group_mode;
int *max_groups;
+ int class;
{
- int i;
+ HARD_REG_SET new;
+ int i, j;
+
/* Now find all consecutive groups of spilled registers
and mark each group off against the need for such groups.
But don't count them against ordinary need, yet. */
- for (i = 0; i < N_REG_CLASSES; i++)
- if (group_size[i] > 1)
+ if (group_size[class] == 0)
+ return;
+
+ CLEAR_HARD_REG_SET (new);
+
+ /* Make a mask of all the regs that are spill regs in class I. */
+ for (i = 0; i < n_spills; i++)
+ if (TEST_HARD_REG_BIT (reg_class_contents[class], spill_regs[i])
+ && ! TEST_HARD_REG_BIT (counted_for_groups, spill_regs[i])
+ && ! TEST_HARD_REG_BIT (counted_for_nongroups, spill_regs[i]))
+ SET_HARD_REG_BIT (new, spill_regs[i]);
+
+ /* Find each consecutive group of them. */
+ for (i = 0; i < FIRST_PSEUDO_REGISTER && max_groups[class] > 0; i++)
+ if (TEST_HARD_REG_BIT (new, i)
+ && i + group_size[class] <= FIRST_PSEUDO_REGISTER
+ && HARD_REGNO_MODE_OK (i, group_mode[class]))
{
- HARD_REG_SET new;
- int j;
-
- CLEAR_HARD_REG_SET (new);
-
- /* Make a mask of all the regs that are spill regs in class I. */
- for (j = 0; j < n_spills; j++)
- if (TEST_HARD_REG_BIT (reg_class_contents[i], spill_regs[j])
- && ! TEST_HARD_REG_BIT (counted_for_groups, spill_regs[j])
- && ! TEST_HARD_REG_BIT (counted_for_nongroups,
- spill_regs[j]))
- SET_HARD_REG_BIT (new, spill_regs[j]);
-
- /* Find each consecutive group of them. */
- for (j = 0; j < FIRST_PSEUDO_REGISTER && max_groups[i] > 0; j++)
- if (TEST_HARD_REG_BIT (new, j)
- && j + group_size[i] <= FIRST_PSEUDO_REGISTER
- /* Next line in case group-mode for this class
- demands an even-odd pair. */
- && HARD_REGNO_MODE_OK (j, group_mode[i]))
- {
- int k;
- for (k = 1; k < group_size[i]; k++)
- if (! TEST_HARD_REG_BIT (new, j + k))
- break;
- if (k == group_size[i])
- {
- /* We found a group. Mark it off against this class's
- need for groups, and against each superclass too. */
- register enum reg_class *p;
- max_groups[i]--;
- p = reg_class_superclasses[i];
- while (*p != LIM_REG_CLASSES)
- max_groups[(int) *p++]--;
- /* Don't count these registers again. */
- for (k = 0; k < group_size[i]; k++)
- SET_HARD_REG_BIT (counted_for_groups, j + k);
- }
- /* Skip to the last reg in this group. When j is incremented
- above, it will then point to the first reg of the next
- possible group. */
- j += k - 1;
- }
- }
+ for (j = 1; j < group_size[class]; j++)
+ if (! TEST_HARD_REG_BIT (new, i + j))
+ break;
+ if (j == group_size[class])
+ {
+ /* We found a group. Mark it off against this class's need for
+ groups, and against each superclass too. */
+ register enum reg_class *p;
+
+ max_groups[class]--;
+ p = reg_class_superclasses[class];
+ while (*p != LIM_REG_CLASSES)
+ max_groups[(int) *p++]--;
+
+ /* Don't count these registers again. */
+ for (j = 0; j < group_size[class]; j++)
+ SET_HARD_REG_BIT (counted_for_groups, i + j);
+ }
+
+ /* Skip to the last reg in this group. When i is incremented above,
+ it will then point to the first reg of the next possible group. */
+ i += j - 1;
+ }
}
/* ALLOCATE_MODE is a register mode that needs to be reloaded. OTHER_MODE is
@@ -2165,7 +2168,7 @@ spill_failure (insn)
if (asm_noperands (PATTERN (insn)) >= 0)
error_for_asm (insn, "`asm' needs too many reloads");
else
- abort ();
+ fatal_insn ("Unable to find a register to spill.", insn);
}
/* Add a new register to the tables of available spill-registers
@@ -2763,7 +2766,7 @@ eliminate_regs (x, mem_mode, insn)
return x;
case MULT:
- /* If this is the product of an eliminable register and a
+ /* If this is the product of an eliminable register and a
constant, apply the distribute law and move the constant out
so that we have (plus (mult ..) ..). This is needed in order
to keep load-address insns valid. This case is pathalogical.
@@ -2886,11 +2889,20 @@ eliminate_regs (x, mem_mode, insn)
/* If we didn't change anything, we must retain the pseudo. */
if (new == reg_equiv_memory_loc[REGNO (SUBREG_REG (x))])
- new = XEXP (x, 0);
+ new = SUBREG_REG (x);
else
- /* Otherwise, ensure NEW isn't shared in case we have to reload
- it. */
- new = copy_rtx (new);
+ {
+ /* Otherwise, ensure NEW isn't shared in case we have to reload
+ it. */
+ new = copy_rtx (new);
+
+ /* In this case, we must show that the pseudo is used in this
+ insn so that delete_output_reload will do the right thing. */
+ if (insn != 0 && GET_CODE (insn) != EXPR_LIST
+ && GET_CODE (insn) != INSN_LIST)
+ emit_insn_before (gen_rtx (USE, VOIDmode, SUBREG_REG (x)),
+ insn);
+ }
}
else
new = eliminate_regs (SUBREG_REG (x), mem_mode, insn);
@@ -2907,7 +2919,11 @@ eliminate_regs (x, mem_mode, insn)
smaller. So leave the SUBREG then. */
&& ! (GET_CODE (SUBREG_REG (x)) == REG
&& GET_MODE_SIZE (GET_MODE (x)) <= UNITS_PER_WORD
- && GET_MODE_SIZE (GET_MODE (new)) <= UNITS_PER_WORD)
+ && GET_MODE_SIZE (GET_MODE (new)) <= UNITS_PER_WORD
+ && (GET_MODE_SIZE (GET_MODE (x))
+ > GET_MODE_SIZE (GET_MODE (new)))
+ && INTEGRAL_MODE_P (GET_MODE (new))
+ && LOAD_EXTEND_OP (GET_MODE (new)) != NIL)
#endif
)
{
@@ -3238,7 +3254,7 @@ eliminate_regs_in_insn (insn, replace)
old_asm_operands_vec = 0;
/* Replace the body of this insn with a substituted form. If we changed
- something, return non-zero.
+ something, return non-zero.
If we are replacing a body that was a (set X (plus Y Z)), try to
re-recognize the insn. We do this in case we had a simple addition
@@ -3489,7 +3505,7 @@ spill_hard_reg (regno, global, dumpfile, cant_eliminate)
return something_changed;
}
-/* Find all paradoxical subregs within X and update reg_max_ref_width.
+/* Find all paradoxical subregs within X and update reg_max_ref_width.
Also mark any hard registers used to store user variables as
forbidden from being used for spill registers. */
@@ -3668,11 +3684,12 @@ order_regs_for_reload ()
}
/* Used in reload_as_needed to sort the spilled regs. */
+
static int
compare_spill_regs (r1, r2)
short *r1, *r2;
{
- return *r1 < *r2 ? -1: 1;
+ return *r1 - *r2;
}
/* Reload pseudo-registers into hard regs around each insn as needed.
@@ -3840,7 +3857,7 @@ reload_as_needed (first, live_known)
&& ! reload_optional[i]
&& (reload_in[i] != 0 || reload_out[i] != 0
|| reload_secondary_p[i] != 0))
- abort ();
+ fatal_insn ("Non-optional registers need a spill register", insn);
/* Now compute which reload regs to reload them into. Perhaps
reusing reload regs from previous insns, or else output
@@ -3849,7 +3866,7 @@ reload_as_needed (first, live_known)
choose_reload_regs (insn, avoid_return_reg);
#ifdef SMALL_REGISTER_CLASSES
- /* Merge any reloads that we didn't combine for fear of
+ /* Merge any reloads that we didn't combine for fear of
increasing the number of spill registers needed but now
discover can be safely merged. */
merge_assigned_reloads (insn);
@@ -4381,7 +4398,7 @@ reload_reg_free_before_p (regno, opnum, type)
return (! TEST_HARD_REG_BIT (reload_reg_used_in_other_addr, regno)
&& ! TEST_HARD_REG_BIT (reload_reg_used_in_insn, regno)
&& ! TEST_HARD_REG_BIT (reload_reg_used_in_op_addr, regno));
-
+
case RELOAD_FOR_OUTPUT:
/* This can't be used in the output address for this operand and
anything that can't be used for it, except that we've already
@@ -4462,7 +4479,7 @@ reload_reg_reaches_end_p (regno, opnum, type)
return 1;
/* If this use is for part of the insn,
- its value reaches if no subsequent part uses the same register.
+ its value reaches if no subsequent part uses the same register.
Just like the above function, don't try to do this with lots
of fallthroughs. */
@@ -4508,7 +4525,7 @@ reload_reg_reaches_end_p (regno, opnum, type)
case RELOAD_FOR_INPUT:
/* Similar to input address, except we start at the next operand for
- both input and input address and we do not check for
+ both input and input address and we do not check for
RELOAD_FOR_OPERAND_ADDRESS and RELOAD_FOR_INSN since these
would conflict. */
@@ -4575,7 +4592,7 @@ reloads_conflict (r1, r2)
int r2_opnum = reload_opnum[r2];
/* RELOAD_OTHER conflicts with everything except RELOAD_FOR_OTHER_ADDRESS. */
-
+
if (r2_type == RELOAD_OTHER && r1_type != RELOAD_FOR_OTHER_ADDRESS)
return 1;
@@ -4584,7 +4601,7 @@ reloads_conflict (r1, r2)
switch (r1_type)
{
case RELOAD_FOR_INPUT:
- return (r2_type == RELOAD_FOR_INSN
+ return (r2_type == RELOAD_FOR_INSN
|| r2_type == RELOAD_FOR_OPERAND_ADDRESS
|| r2_type == RELOAD_FOR_OPADDR_ADDR
|| r2_type == RELOAD_FOR_INPUT
@@ -4603,7 +4620,7 @@ reloads_conflict (r1, r2)
|| r2_type == RELOAD_FOR_OPERAND_ADDRESS);
case RELOAD_FOR_OPADDR_ADDR:
- return (r2_type == RELOAD_FOR_INPUT
+ return (r2_type == RELOAD_FOR_INPUT
|| r2_type == RELOAD_FOR_OPADDR_ADDR);
case RELOAD_FOR_OUTPUT:
@@ -4709,7 +4726,7 @@ allocate_reload_reg (r, insn, last_reload, noerror)
of leapfrogging each other. Don't do this, however, when we have
group needs and failure would be fatal; if we only have a relatively
small number of spill registers, and more than one of them has
- group needs, then by starting in the middle, we may end up
+ group needs, then by starting in the middle, we may end up
allocating the first one in such a way that we are not left with
sufficient groups to handle the rest. */
@@ -4717,7 +4734,7 @@ allocate_reload_reg (r, insn, last_reload, noerror)
i = last_spill_reg;
else
i = -1;
-
+
for (count = 0; count < n_spills; count++)
{
int class = (int) reload_reg_class[r];
@@ -4794,7 +4811,7 @@ allocate_reload_reg (r, insn, last_reload, noerror)
if (new == 0 || GET_MODE (new) != reload_mode[r])
spill_reg_rtx[i] = new
= gen_rtx (REG, reload_mode[r], spill_regs[i]);
-
+
regno = true_regnum (new);
/* Detect when the reload reg can't hold the reload mode.
@@ -4836,7 +4853,7 @@ allocate_reload_reg (r, insn, last_reload, noerror)
failure:
if (asm_noperands (PATTERN (insn)) < 0)
/* It's the compiler's fault. */
- abort ();
+ fatal_insn ("Could not find a spill register", insn);
/* It's the user's fault; the operand's mode and constraint
don't match. Disable this reload so we don't crash in final. */
@@ -5508,7 +5525,7 @@ choose_reload_regs (insn, avoid_return_reg)
/* If SMALL_REGISTER_CLASSES are defined, we may not have merged two
reloads of the same item for fear that we might not have enough reload
registers. However, normally they will get the same reload register
- and hence actually need not be loaded twice.
+ and hence actually need not be loaded twice.
Here we check for the most common case of this phenomenon: when we have
a number of reloads for the same object, each of which were allocated
@@ -5591,7 +5608,7 @@ merge_assigned_reloads (insn)
? RELOAD_FOR_OTHER_ADDRESS : RELOAD_OTHER;
}
}
-}
+}
#endif /* SMALL_RELOAD_CLASSES */
/* Output insns to reload values in and out of the chosen reload regs. */
@@ -5628,7 +5645,9 @@ emit_reload_insns (insn)
{
register rtx old;
rtx oldequiv_reg = 0;
- rtx store_insn = 0;
+
+ if (reload_spill_index[j] >= 0)
+ new_spill_reg_store[reload_spill_index[j]] = 0;
old = reload_in[j];
if (old != 0 && ! reload_inherited[j]
@@ -5982,7 +6001,7 @@ emit_reload_insns (insn)
to see if it is being used as a scratch or intermediate
register and generate code appropriately. If we need
a scratch register, use REAL_OLDEQUIV since the form of
- the insn may depend on the actual address if it is
+ the insn may depend on the actual address if it is
a MEM. */
if (second_reload_reg)
@@ -6010,9 +6029,9 @@ emit_reload_insns (insn)
third_reload_reg)));
}
else
- gen_input_reload (second_reload_reg, oldequiv,
- reload_opnum[j],
- reload_when_needed[j]);
+ gen_reload (second_reload_reg, oldequiv,
+ reload_opnum[j],
+ reload_when_needed[j]);
oldequiv = second_reload_reg;
}
@@ -6021,8 +6040,8 @@ emit_reload_insns (insn)
#endif
if (! special && ! rtx_equal_p (reloadreg, oldequiv))
- gen_input_reload (reloadreg, oldequiv, reload_opnum[j],
- reload_when_needed[j]);
+ gen_reload (reloadreg, oldequiv, reload_opnum[j],
+ reload_when_needed[j]);
#if defined(SECONDARY_INPUT_RELOAD_CLASS) && defined(PRESERVE_DEATH_INFO_REGNO_P)
/* We may have to make a REG_DEAD note for the secondary reload
@@ -6246,7 +6265,7 @@ emit_reload_insns (insn)
/* VOIDmode should never happen for an output. */
if (asm_noperands (PATTERN (insn)) < 0)
/* It's the compiler's fault. */
- abort ();
+ fatal_insn ("VOIDmode on an output", insn);
error_for_asm (insn, "output operand is constant in `asm'");
/* Prevent crash--use something we know is valid. */
mode = word_mode;
@@ -6259,7 +6278,7 @@ emit_reload_insns (insn)
#ifdef SECONDARY_OUTPUT_RELOAD_CLASS
/* If we need two reload regs, set RELOADREG to the intermediate
- one, since it will be stored into OUT. We might need a secondary
+ one, since it will be stored into OLD. We might need a secondary
register only for an input reload, so check again here. */
if (reload_secondary_out_reload[j] >= 0)
@@ -6289,10 +6308,10 @@ emit_reload_insns (insn)
{
/* See if we need both a scratch and intermediate reload
register. */
+
int secondary_reload = reload_secondary_out_reload[j];
enum insn_code tertiary_icode
= reload_secondary_out_icode[secondary_reload];
- rtx pat;
if (GET_MODE (reloadreg) != mode)
reloadreg = gen_rtx (REG, mode, REGNO (reloadreg));
@@ -6301,44 +6320,24 @@ emit_reload_insns (insn)
{
rtx third_reloadreg
= reload_reg_rtx[reload_secondary_out_reload[secondary_reload]];
- pat = (GEN_FCN (tertiary_icode)
- (reloadreg, second_reloadreg, third_reloadreg));
- }
-#ifdef SECONDARY_MEMORY_NEEDED
- /* If we need a memory location to do the move, do it that way. */
- else if (GET_CODE (reloadreg) == REG
- && REGNO (reloadreg) < FIRST_PSEUDO_REGISTER
- && SECONDARY_MEMORY_NEEDED (REGNO_REG_CLASS (REGNO (reloadreg)),
- REGNO_REG_CLASS (REGNO (second_reloadreg)),
- GET_MODE (second_reloadreg)))
- {
- /* Get the memory to use and rewrite both registers
- to its mode. */
- rtx loc
- = get_secondary_mem (reloadreg,
- GET_MODE (second_reloadreg),
- reload_opnum[j],
- reload_when_needed[j]);
- rtx tmp_reloadreg;
-
- if (GET_MODE (loc) != GET_MODE (second_reloadreg))
- second_reloadreg = gen_rtx (REG, GET_MODE (loc),
- REGNO (second_reloadreg));
-
- if (GET_MODE (loc) != GET_MODE (reloadreg))
- tmp_reloadreg = gen_rtx (REG, GET_MODE (loc),
- REGNO (reloadreg));
- else
- tmp_reloadreg = reloadreg;
-
- emit_move_insn (loc, second_reloadreg);
- pat = gen_move_insn (tmp_reloadreg, loc);
+
+ /* Copy primary reload reg to secondary reload reg.
+ (Note that these have been swapped above, then
+ secondary reload reg to OLD using our insn. */
+
+ gen_reload (reloadreg, second_reloadreg,
+ reload_opnum[j], reload_when_needed[j]);
+ emit_insn ((GEN_FCN (tertiary_icode)
+ (real_old, reloadreg, third_reloadreg)));
+ special = 1;
}
-#endif
+
else
- pat = gen_move_insn (reloadreg, second_reloadreg);
+ /* Copy between the reload regs here and then to
+ OUT later. */
- emit_insn (pat);
+ gen_reload (reloadreg, second_reloadreg,
+ reload_opnum[j], reload_when_needed[j]);
}
}
}
@@ -6346,34 +6345,8 @@ emit_reload_insns (insn)
/* Output the last reload insn. */
if (! special)
- {
-#ifdef SECONDARY_MEMORY_NEEDED
- /* If we need a memory location to do the move, do it that way. */
- if (GET_CODE (old) == REG && REGNO (old) < FIRST_PSEUDO_REGISTER
- && SECONDARY_MEMORY_NEEDED (REGNO_REG_CLASS (REGNO (old)),
- REGNO_REG_CLASS (REGNO (reloadreg)),
- GET_MODE (reloadreg)))
- {
- /* Get the memory to use and rewrite both registers to
- its mode. */
- rtx loc = get_secondary_mem (old, GET_MODE (reloadreg),
- reload_opnum[j],
- reload_when_needed[j]);
-
- if (GET_MODE (loc) != GET_MODE (reloadreg))
- reloadreg = gen_rtx (REG, GET_MODE (loc),
- REGNO (reloadreg));
-
- if (GET_MODE (loc) != GET_MODE (old))
- old = gen_rtx (REG, GET_MODE (loc), REGNO (old));
-
- emit_insn (gen_move_insn (loc, reloadreg));
- emit_insn (gen_move_insn (old, loc));
- }
- else
-#endif
- emit_insn (gen_move_insn (old, reloadreg));
- }
+ gen_reload (old, reloadreg, reload_opnum[j],
+ reload_when_needed[j]);
#ifdef PRESERVE_DEATH_INFO_REGNO_P
/* If final will look at death notes for this reg,
@@ -6408,17 +6381,14 @@ emit_reload_insns (insn)
reg_has_output_reload will make this do nothing. */
note_stores (PATTERN (p), forget_old_reloads_1);
- if (reg_mentioned_p (reload_reg_rtx[j], PATTERN (p)))
- store_insn = p;
+ if (reg_mentioned_p (reload_reg_rtx[j], PATTERN (p))
+ && reload_spill_index[j] >= 0)
+ new_spill_reg_store[reload_spill_index[j]] = p;
}
output_reload_insns[reload_opnum[j]] = get_insns ();
end_sequence ();
-
}
-
- if (reload_spill_index[j] >= 0)
- new_spill_reg_store[reload_spill_index[j]] = store_insn;
}
/* Now write all the insns we made for reloads in the order expected by
@@ -6550,7 +6520,7 @@ emit_reload_insns (insn)
reg_last_reload_reg[nregno] = reload_reg_rtx[r];
/* If NREGNO is a hard register, it may occupy more than
- one register. If it does, say what is in the
+ one register. If it does, say what is in the
rest of the registers assuming that both registers
agree on how many words the object takes. If not,
invalidate the subsequent registers. */
@@ -6640,14 +6610,15 @@ emit_reload_insns (insn)
}
}
-/* Emit code to perform an input reload of IN to RELOADREG. IN is from
- operand OPNUM with reload type TYPE.
+/* Emit code to perform a reload from IN (which may be a reload register) to
+ OUT (which may also be a reload register). IN or OUT is from operand
+ OPNUM with reload type TYPE.
Returns first insn emitted. */
rtx
-gen_input_reload (reloadreg, in, opnum, type)
- rtx reloadreg;
+gen_reload (out, in, opnum, type)
+ rtx out;
rtx in;
int opnum;
enum reload_type type;
@@ -6714,13 +6685,13 @@ gen_input_reload (reloadreg, in, opnum, type)
it will be A = A + B as constrain_operands expects. */
if (GET_CODE (XEXP (in, 1)) == REG
- && REGNO (reloadreg) == REGNO (XEXP (in, 1)))
+ && REGNO (out) == REGNO (XEXP (in, 1)))
tem = op0, op0 = op1, op1 = tem;
if (op0 != XEXP (in, 0) || op1 != XEXP (in, 1))
in = gen_rtx (PLUS, GET_MODE (in), op0, op1);
- insn = emit_insn (gen_rtx (SET, VOIDmode, reloadreg, in));
+ insn = emit_insn (gen_rtx (SET, VOIDmode, out, in));
code = recog_memoized (insn);
if (code >= 0)
@@ -6749,16 +6720,16 @@ gen_input_reload (reloadreg, in, opnum, type)
&& REGNO (op1) >= FIRST_PSEUDO_REGISTER))
tem = op0, op0 = op1, op1 = tem;
- emit_insn (gen_move_insn (reloadreg, op0));
+ emit_insn (gen_move_insn (out, op0));
- /* If OP0 and OP1 are the same, we can use RELOADREG for OP1.
+ /* If OP0 and OP1 are the same, we can use OUT for OP1.
This fixes a problem on the 32K where the stack pointer cannot
be used as an operand of an add insn. */
if (rtx_equal_p (op0, op1))
- op1 = reloadreg;
+ op1 = out;
- insn = emit_insn (gen_add2_insn (reloadreg, op1));
+ insn = emit_insn (gen_add2_insn (out, op1));
/* If that failed, copy the address register to the reload register.
Then add the constant to the reload register. */
@@ -6777,43 +6748,44 @@ gen_input_reload (reloadreg, in, opnum, type)
delete_insns_since (last);
- emit_insn (gen_move_insn (reloadreg, op1));
- emit_insn (gen_add2_insn (reloadreg, op0));
+ emit_insn (gen_move_insn (out, op1));
+ emit_insn (gen_add2_insn (out, op0));
}
#ifdef SECONDARY_MEMORY_NEEDED
/* If we need a memory location to do the move, do it that way. */
else if (GET_CODE (in) == REG && REGNO (in) < FIRST_PSEUDO_REGISTER
+ && GET_CODE (out) == REG && REGNO (out) < FIRST_PSEUDO_REGISTER
&& SECONDARY_MEMORY_NEEDED (REGNO_REG_CLASS (REGNO (in)),
- REGNO_REG_CLASS (REGNO (reloadreg)),
- GET_MODE (reloadreg)))
+ REGNO_REG_CLASS (REGNO (out)),
+ GET_MODE (out)))
{
/* Get the memory to use and rewrite both registers to its mode. */
- rtx loc = get_secondary_mem (in, GET_MODE (reloadreg), opnum, type);
+ rtx loc = get_secondary_mem (in, GET_MODE (out), opnum, type);
- if (GET_MODE (loc) != GET_MODE (reloadreg))
- reloadreg = gen_rtx (REG, GET_MODE (loc), REGNO (reloadreg));
+ if (GET_MODE (loc) != GET_MODE (out))
+ out = gen_rtx (REG, GET_MODE (loc), REGNO (out));
if (GET_MODE (loc) != GET_MODE (in))
in = gen_rtx (REG, GET_MODE (loc), REGNO (in));
emit_insn (gen_move_insn (loc, in));
- emit_insn (gen_move_insn (reloadreg, loc));
+ emit_insn (gen_move_insn (out, loc));
}
#endif
/* If IN is a simple operand, use gen_move_insn. */
else if (GET_RTX_CLASS (GET_CODE (in)) == 'o' || GET_CODE (in) == SUBREG)
- emit_insn (gen_move_insn (reloadreg, in));
+ emit_insn (gen_move_insn (out, in));
#ifdef HAVE_reload_load_address
else if (HAVE_reload_load_address)
- emit_insn (gen_reload_load_address (reloadreg, in));
+ emit_insn (gen_reload_load_address (out, in));
#endif
- /* Otherwise, just write (set REGLOADREG IN) and hope for the best. */
+ /* Otherwise, just write (set OUT IN) and hope for the best. */
else
- emit_insn (gen_rtx (SET, VOIDmode, reloadreg, in));
+ emit_insn (gen_rtx (SET, VOIDmode, out, in));
/* Return the first insn emitted.
We can not just return get_last_insn, because there may have
@@ -6960,13 +6932,13 @@ inc_for_reload (reloadreg, value, inc_amount)
emit_insn (gen_move_insn (reloadreg, incloc));
/* See if we can directly increment INCLOC. Use a method similar to that
- in gen_input_reload. */
+ in gen_reload. */
last = get_last_insn ();
add_insn = emit_insn (gen_rtx (SET, VOIDmode, incloc,
gen_rtx (PLUS, GET_MODE (incloc),
incloc, inc)));
-
+
code = recog_memoized (add_insn);
if (code >= 0)
{
diff --git a/gnu/usr.bin/cc/cc_int/reorg.c b/gnu/usr.bin/cc/cc_int/reorg.c
index 4082ad8..d977404 100644
--- a/gnu/usr.bin/cc/cc_int/reorg.c
+++ b/gnu/usr.bin/cc/cc_int/reorg.c
@@ -54,7 +54,7 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
is taken.
The HP-PA always has a branch delay slot. For unconditional branches
- its effects can be annulled when the branch is taken. The effects
+ its effects can be annulled when the branch is taken. The effects
of the delay slot in a conditional branch can be nullified for forward
taken branches, or for untaken backward branches. This means
we can hoist insns from the fall-through path for forward branches or
@@ -244,12 +244,13 @@ static rtx steal_delay_list_from_fallthrough PROTO((rtx, rtx, rtx, rtx,
struct resources *,
int, int *, int *));
static void try_merge_delay_insns PROTO((rtx, rtx));
-static int redundant_insn_p PROTO((rtx, rtx, rtx));
+static rtx redundant_insn_p PROTO((rtx, rtx, rtx));
static int own_thread_p PROTO((rtx, rtx, int));
static int find_basic_block PROTO((rtx));
static void update_block PROTO((rtx, rtx));
static int reorg_redirect_jump PROTO((rtx, rtx));
static void update_reg_dead_notes PROTO((rtx, rtx));
+static void update_reg_unused_notes PROTO((rtx, rtx));
static void update_live_status PROTO((rtx, rtx));
static rtx next_insn_no_annul PROTO((rtx));
static void mark_target_live_regs PROTO((rtx, struct resources *));
@@ -334,7 +335,7 @@ mark_referenced_resources (x, res, include_delayed_effects)
We can not just fall through here since then we would be confused
by the ASM_INPUT rtx inside ASM_OPERANDS, which do not indicate
traditional asms unlike their normal usage. */
-
+
for (i = 0; i < ASM_OPERANDS_INPUT_LENGTH (x); i++)
mark_referenced_resources (ASM_OPERANDS_INPUT (x, i), res, 0);
return;
@@ -575,7 +576,7 @@ mark_set_resources (x, res, in_dest, include_delayed_effects)
case CLOBBER:
mark_set_resources (XEXP (x, 0), res, 1, 0);
return;
-
+
case SEQUENCE:
for (i = 0; i < XVECLEN (x, 0); i++)
if (! (INSN_ANNULLED_BRANCH_P (XVECEXP (x, 0, 0))
@@ -607,6 +608,22 @@ mark_set_resources (x, res, in_dest, include_delayed_effects)
mark_set_resources (XEXP (x, 0), res, 0, 0);
return;
+ case SUBREG:
+ if (in_dest)
+ {
+ if (GET_CODE (SUBREG_REG (x)) != REG)
+ mark_set_resources (SUBREG_REG (x), res,
+ in_dest, include_delayed_effects);
+ else
+ {
+ int regno = REGNO (SUBREG_REG (x)) + SUBREG_WORD (x);
+ int last_regno = regno + HARD_REGNO_NREGS (regno, GET_MODE (x));
+ for (i = regno; i < last_regno; i++)
+ SET_HARD_REG_BIT (res->regs, i);
+ }
+ }
+ return;
+
case REG:
if (in_dest)
for (i = 0; i < HARD_REGNO_NREGS (REGNO (x), GET_MODE (x)); i++)
@@ -756,7 +773,7 @@ find_end_label ()
|| GET_CODE (PATTERN (insn)) == CLOBBER)))
insn = PREV_INSN (insn);
- /* When a target threads its epilogue we might already have a
+ /* When a target threads its epilogue we might already have a
suitable return insn. If so put a label before it for the
end_of_function_label. */
if (GET_CODE (insn) == BARRIER
@@ -835,7 +852,7 @@ emit_delay_sequence (insn, list, length, avail)
rtx delay_insn = copy_rtx (insn);
/* If INSN is followed by a BARRIER, delete the BARRIER since it will only
- confuse further processing. Update LAST in case it was the last insn.
+ confuse further processing. Update LAST in case it was the last insn.
We will put the BARRIER back in later. */
if (NEXT_INSN (insn) && GET_CODE (NEXT_INSN (insn)) == BARRIER)
{
@@ -897,7 +914,7 @@ emit_delay_sequence (insn, list, length, avail)
if (NEXT_INSN (seq_insn) && GET_CODE (NEXT_INSN (seq_insn)) == INSN
&& GET_CODE (PATTERN (NEXT_INSN (seq_insn))) == SEQUENCE)
PREV_INSN (XVECEXP (PATTERN (NEXT_INSN (seq_insn)), 0, 0)) = seq_insn;
-
+
/* If there used to be a BARRIER, put it back. */
if (had_barrier)
emit_barrier_after (seq_insn);
@@ -923,7 +940,7 @@ add_to_delay_list (insn, delay_list)
if (delay_list == 0)
{
struct target_info *tinfo;
-
+
for (tinfo = target_hash_table[INSN_UID (insn) % TARGET_HASH_PRIME];
tinfo; tinfo = tinfo->next)
if (tinfo->uid == INSN_UID (insn))
@@ -940,7 +957,7 @@ add_to_delay_list (insn, delay_list)
XEXP (delay_list, 1) = add_to_delay_list (insn, XEXP (delay_list, 1));
return delay_list;
-}
+}
/* Delete INSN from the the delay slot of the insn that it is in. This may
produce an insn without anything in its delay slots. */
@@ -1198,15 +1215,15 @@ get_jump_flags (insn, label)
&& INSN_UID (insn) <= max_uid
&& label != 0
&& INSN_UID (label) <= max_uid)
- flags
+ flags
= (uid_to_ruid[INSN_UID (label)] > uid_to_ruid[INSN_UID (insn)])
? ATTR_FLAG_forward : ATTR_FLAG_backward;
/* No valid direction information. */
else
flags = 0;
-
+
/* If insn is a conditional branch call mostly_true_jump to get
- determine the branch prediction.
+ determine the branch prediction.
Non conditional branches are predicted as very likely taken. */
if (GET_CODE (insn) == JUMP_INSN
@@ -1264,7 +1281,7 @@ rare_destination (insn)
case CODE_LABEL:
return 0;
case BARRIER:
- /* A BARRIER can either be after a JUMP_INSN or a CALL_INSN. We
+ /* A BARRIER can either be after a JUMP_INSN or a CALL_INSN. We
don't scan past JUMP_INSNs, so any barrier we find here must
have been after a CALL_INSN and hence mean the call doesn't
return. */
@@ -1316,7 +1333,7 @@ mostly_true_jump (jump_insn, condition)
{
/* If this is the test of a loop, it is very likely true. We scan
backwards from the target label. If we find a NOTE_INSN_LOOP_BEG
- before the next real insn, we assume the branch is to the top of
+ before the next real insn, we assume the branch is to the top of
the loop. */
for (insn = PREV_INSN (target_label);
insn && GET_CODE (insn) == NOTE;
@@ -1352,7 +1369,7 @@ mostly_true_jump (jump_insn, condition)
return 2;
}
- /* If we couldn't figure out what this jump was, assume it won't be
+ /* If we couldn't figure out what this jump was, assume it won't be
taken. This should be rare. */
if (condition == 0)
return 0;
@@ -1402,7 +1419,7 @@ get_branch_condition (insn, target)
{
rtx pat = PATTERN (insn);
rtx src;
-
+
if (condjump_in_parallel_p (insn))
pat = XVECEXP (pat, 0, 0);
@@ -1648,13 +1665,13 @@ steal_delay_list_from_target (insn, condition, seq, delay_list,
return delay_list;
}
-/* Similar to steal_delay_list_from_target except that SEQ is on the
+/* Similar to steal_delay_list_from_target except that SEQ is on the
fallthrough path of INSN. Here we only do something if the delay insn
of SEQ is an unconditional branch. In that case we steal its delay slot
for INSN since unconditional branches are much easier to fill. */
static rtx
-steal_delay_list_from_fallthrough (insn, condition, seq,
+steal_delay_list_from_fallthrough (insn, condition, seq,
delay_list, sets, needed, other_needed,
slots_to_fill, pslots_filled, pannul_p)
rtx insn, condition;
@@ -1762,6 +1779,7 @@ try_merge_delay_insns (insn, thread)
for (trial = thread; !stop_search_p (trial, 1); trial = next_trial)
{
rtx pat = PATTERN (trial);
+ rtx oldtrial = trial;
next_trial = next_nonnote_insn (trial);
@@ -1781,6 +1799,8 @@ try_merge_delay_insns (insn, thread)
&& (trial = try_split (pat, trial, 0)) != 0
/* Update next_trial, in case try_split succeeded. */
&& (next_trial = next_nonnote_insn (trial))
+ /* Likewise THREAD. */
+ && (thread = oldtrial == thread ? trial : thread)
&& rtx_equal_p (PATTERN (next_to_match), PATTERN (trial))
/* Have to test this condition if annul condition is different
from (and less restrictive than) non-annulling one. */
@@ -1790,6 +1810,9 @@ try_merge_delay_insns (insn, thread)
if (! annul_p)
{
update_block (trial, thread);
+ if (trial == thread)
+ thread = next_active_insn (thread);
+
delete_insn (trial);
INSN_FROM_TARGET_P (next_to_match) = 0;
}
@@ -1900,7 +1923,7 @@ try_merge_delay_insns (insn, thread)
redundant insn, but the cost of splitting seems greater than the possible
gain in rare cases. */
-static int
+static rtx
redundant_insn_p (insn, target, delay_list)
rtx insn;
rtx target;
@@ -1933,17 +1956,17 @@ redundant_insn_p (insn, target, delay_list)
return 0;
/* Stop for an INSN or JUMP_INSN with delayed effects and its delay
- slots because it is difficult to track its resource needs
+ slots because it is difficult to track its resource needs
correctly. */
#ifdef INSN_SETS_ARE_DELAYED
if (INSN_SETS_ARE_DELAYED (XVECEXP (pat, 0, 0)))
- return 0;
+ return 0;
#endif
#ifdef INSN_REFERENCES_ARE_DELAYED
if (INSN_REFERENCES_ARE_DELAYED (XVECEXP (pat, 0, 0)))
- return 0;
+ return 0;
#endif
/* See if any of the insns in the delay slot match, updating
@@ -2035,12 +2058,12 @@ redundant_insn_p (insn, target, delay_list)
#ifdef INSN_SETS_ARE_DELAYED
if (INSN_SETS_ARE_DELAYED (XVECEXP (pat, 0, 0)))
- return 0;
+ return 0;
#endif
#ifdef INSN_REFERENCES_ARE_DELAYED
if (INSN_REFERENCES_ARE_DELAYED (XVECEXP (pat, 0, 0)))
- return 0;
+ return 0;
#endif
/* See if any of the insns in the delay slot match, updating
@@ -2057,7 +2080,7 @@ redundant_insn_p (insn, target, delay_list)
{
/* Show that this insn will be used in the sequel. */
INSN_FROM_TARGET_P (candidate) = 0;
- return 1;
+ return candidate;
}
/* Unless this is an annulled insn from the target of a branch,
@@ -2069,7 +2092,7 @@ redundant_insn_p (insn, target, delay_list)
}
- /* If the insn requiring the delay slot conflicts with INSN, we
+ /* If the insn requiring the delay slot conflicts with INSN, we
must stop. */
if (insn_sets_resource_p (XVECEXP (pat, 0, 0), &needed, 1))
return 0;
@@ -2079,7 +2102,7 @@ redundant_insn_p (insn, target, delay_list)
/* See if TRIAL is the same as INSN. */
pat = PATTERN (trial);
if (rtx_equal_p (pat, ipat))
- return 1;
+ return trial;
/* Can't go any further if TRIAL conflicts with INSN. */
if (insn_sets_resource_p (trial, &needed, 1))
@@ -2187,7 +2210,7 @@ update_block (insn, where)
{
int b;
- /* Ignore if this was in a delay slot and it came from the target of
+ /* Ignore if this was in a delay slot and it came from the target of
a branch. */
if (INSN_FROM_TARGET_P (insn))
return;
@@ -2254,6 +2277,33 @@ update_reg_dead_notes (insn, delayed_insn)
}
}
}
+
+/* Delete any REG_UNUSED notes that exist on INSN but not on REDUNDANT_INSN.
+
+ This handles the case of udivmodXi4 instructions which optimize their
+ output depending on whether any REG_UNUSED notes are present.
+ we must make sure that INSN calculates as many results as REDUNDANT_INSN
+ does. */
+
+static void
+update_reg_unused_notes (insn, redundant_insn)
+ rtx insn, redundant_insn;
+{
+ rtx p, link, next;
+
+ for (link = REG_NOTES (insn); link; link = next)
+ {
+ next = XEXP (link, 1);
+
+ if (REG_NOTE_KIND (link) != REG_UNUSED
+ || GET_CODE (XEXP (link, 0)) != REG)
+ continue;
+
+ if (! find_regno_note (redundant_insn, REG_UNUSED,
+ REGNO (XEXP (link, 0))))
+ remove_note (insn, link);
+ }
+}
/* Marks registers possibly live at the current place being scanned by
mark_target_live_regs. Used only by next two function. */
@@ -2416,7 +2466,7 @@ mark_target_live_regs (target, res)
}
else
{
- /* Allocate a place to put our results and chain it into the
+ /* Allocate a place to put our results and chain it into the
hash table. */
tinfo = (struct target_info *) oballoc (sizeof (struct target_info));
tinfo->uid = INSN_UID (target);
@@ -2543,7 +2593,7 @@ mark_target_live_regs (target, res)
= (first_regno
+ HARD_REGNO_NREGS (first_regno,
GET_MODE (XEXP (link, 0))));
-
+
for (i = first_regno; i < last_regno; i++)
SET_HARD_REG_BIT (pending_dead_regs, i);
}
@@ -2562,7 +2612,7 @@ mark_target_live_regs (target, res)
= (first_regno
+ HARD_REGNO_NREGS (first_regno,
GET_MODE (XEXP (link, 0))));
-
+
for (i = first_regno; i < last_regno; i++)
CLEAR_HARD_REG_BIT (current_live_regs, i);
}
@@ -2745,7 +2795,7 @@ fill_simple_delay_slots (first, non_jumps_p)
|| (GET_CODE (insn) == JUMP_INSN && non_jumps_p)
|| (GET_CODE (insn) != JUMP_INSN && ! non_jumps_p))
continue;
-
+
if (GET_CODE (insn) == JUMP_INSN)
flags = get_jump_flags (insn, JUMP_LABEL (insn));
else
@@ -2769,7 +2819,7 @@ fill_simple_delay_slots (first, non_jumps_p)
insn must exist when it is subsequently scanned.
This is tried on each insn with delay slots as some machines
- have insns which perform calls, but are not represented as
+ have insns which perform calls, but are not represented as
CALL_INSNs. */
slots_filled = 0;
@@ -2804,7 +2854,7 @@ fill_simple_delay_slots (first, non_jumps_p)
forward in execution sequence), it must not need or set any resources
that were set by later insns and must not set any resources that
are needed for those insns.
-
+
The delay slot insn itself sets resources unless it is a call
(in which case the called routine, not the insn itself, is doing
the setting). */
@@ -2828,7 +2878,7 @@ fill_simple_delay_slots (first, non_jumps_p)
if (GET_CODE (pat) == USE || GET_CODE (pat) == CLOBBER)
continue;
- /* Check for resource conflict first, to avoid unnecessary
+ /* Check for resource conflict first, to avoid unnecessary
splitting. */
if (! insn_references_resource_p (trial, &set, 1)
&& ! insn_sets_resource_p (trial, &set, 1)
@@ -2871,7 +2921,7 @@ fill_simple_delay_slots (first, non_jumps_p)
#if defined(ANNUL_IFFALSE_SLOTS) || defined(ANNUL_IFTRUE_SLOTS)
if (slots_filled != slots_to_fill
&& delay_list == 0
- && GET_CODE (insn) == JUMP_INSN
+ && GET_CODE (insn) == JUMP_INSN
&& (condjump_p (insn) || condjump_in_parallel_p (insn)))
{
delay_list = optimize_skip (insn);
@@ -2916,7 +2966,7 @@ fill_simple_delay_slots (first, non_jumps_p)
mark_referenced_resources (insn, &needed, 1);
maybe_never = 1;
}
- else
+ else
{
mark_set_resources (insn, &set, 0, 1);
mark_referenced_resources (insn, &needed, 1);
@@ -2927,7 +2977,7 @@ fill_simple_delay_slots (first, non_jumps_p)
target = JUMP_LABEL (insn);
target_uses = LABEL_NUSES (target) - 1;
}
-
+
}
for (trial = next_nonnote_insn (insn); trial; trial = next_trial)
@@ -3060,7 +3110,7 @@ fill_simple_delay_slots (first, non_jumps_p)
else
new_label = find_end_label ();
- delay_list
+ delay_list
= add_to_delay_list (copy_rtx (next_trial), delay_list);
slots_filled++;
reorg_redirect_jump (trial, new_label);
@@ -3085,7 +3135,7 @@ fill_simple_delay_slots (first, non_jumps_p)
#ifdef DELAY_SLOTS_FOR_EPILOGUE
/* See if the epilogue needs any delay slots. Try to fill them if so.
- The only thing we can do is scan backwards from the end of the
+ The only thing we can do is scan backwards from the end of the
function. If we did this in a previous pass, it is incorrect to do it
again. */
if (current_function_epilogue_delay_list)
@@ -3257,18 +3307,30 @@ fill_slots_from_thread (insn, condition, thread, opposite_thread, likely,
#endif
)
{
+ rtx prior_insn;
+
/* If TRIAL is redundant with some insn before INSN, we don't
actually need to add it to the delay list; we can merely pretend
we did. */
- if (redundant_insn_p (trial, insn, delay_list))
+ if (prior_insn = redundant_insn_p (trial, insn, delay_list))
{
if (own_thread)
{
update_block (trial, thread);
+ if (trial == thread)
+ {
+ thread = next_active_insn (thread);
+ if (new_thread == trial)
+ new_thread = thread;
+ }
+
delete_insn (trial);
}
else
- new_thread = next_active_insn (trial);
+ {
+ update_reg_unused_notes (prior_insn, trial);
+ new_thread = next_active_insn (trial);
+ }
continue;
}
@@ -3284,6 +3346,8 @@ fill_slots_from_thread (insn, condition, thread, opposite_thread, likely,
trial = try_split (pat, trial, 0);
if (new_thread == old_trial)
new_thread = trial;
+ if (thread == old_trial)
+ thread = trial;
pat = PATTERN (trial);
if (eligible_for_delay (insn, *pslots_filled, trial, flags))
goto winner;
@@ -3719,7 +3783,7 @@ relax_delay_slots (first)
continue;
}
}
-
+
/* If this is an unconditional jump and the previous insn is a
conditional jump, try reversing the condition of the previous
insn and swapping our targets. The next pass might be able to
@@ -3787,7 +3851,7 @@ relax_delay_slots (first)
if (trial == 0 && target_label != 0)
trial = find_end_label ();
- if (trial != target_label
+ if (trial != target_label
&& redirect_with_delay_slots_safe_p (delay_insn, trial, insn))
{
reorg_redirect_jump (delay_insn, trial);
@@ -3823,7 +3887,7 @@ relax_delay_slots (first)
if (target_label == 0)
target_label = find_end_label ();
- if (redirect_with_delay_slots_safe_p (delay_insn, target_label,
+ if (redirect_with_delay_slots_safe_p (delay_insn, target_label,
insn))
{
reorg_redirect_jump (delay_insn, target_label);
@@ -3909,6 +3973,17 @@ relax_delay_slots (first)
if (invert_jump (delay_insn, label))
{
+ int i;
+
+ /* Must update the INSN_FROM_TARGET_P bits now that
+ the branch is reversed, so that mark_target_live_regs
+ will handle the delay slot insn correctly. */
+ for (i = 1; i < XVECLEN (PATTERN (insn), 0); i++)
+ {
+ rtx slot = XVECEXP (PATTERN (insn), 0, i);
+ INSN_FROM_TARGET_P (slot) = ! INSN_FROM_TARGET_P (slot);
+ }
+
delete_insn (next);
next = insn;
}
@@ -3957,7 +4032,7 @@ make_return_insns (first)
real_return_label = get_label_before (insn);
break;
}
-
+
/* Show an extra usage of REAL_RETURN_LABEL so it won't go away if it
was equal to END_OF_FUNCTION_LABEL. */
LABEL_NUSES (real_return_label)++;
@@ -4079,7 +4154,7 @@ dbr_schedule (first, file)
flag_no_peephole = old_flag_no_peephole;
#endif
- /* If the current function has no insns other than the prologue and
+ /* If the current function has no insns other than the prologue and
epilogue, then do not try to fill any delay slots. */
if (n_basic_blocks == 0)
return;
@@ -4098,7 +4173,7 @@ dbr_schedule (first, file)
uid_to_ruid = (int *) alloca ((max_uid + 1) * sizeof (int *));
for (i = 0, insn = first; insn; i++, insn = NEXT_INSN (insn))
uid_to_ruid[INSN_UID (insn)] = i;
-
+
/* Initialize the list of insns that need filling. */
if (unfilled_firstobj == 0)
{
@@ -4118,12 +4193,12 @@ dbr_schedule (first, file)
&& (GET_CODE (PATTERN (insn)) == ADDR_VEC
|| GET_CODE (PATTERN (insn)) == ADDR_DIFF_VEC))
continue;
-
+
if (num_delay_slots (insn) > 0)
obstack_ptr_grow (&unfilled_slots_obstack, insn);
/* Ensure all jumps go to the last of a set of consecutive labels. */
- if (GET_CODE (insn) == JUMP_INSN
+ if (GET_CODE (insn) == JUMP_INSN
&& (condjump_p (insn) || condjump_in_parallel_p (insn))
&& JUMP_LABEL (insn) != 0
&& ((target = prev_label (next_active_insn (JUMP_LABEL (insn))))
diff --git a/gnu/usr.bin/cc/cc_int/rtl.c b/gnu/usr.bin/cc/cc_int/rtl.c
index 6f29f7f..4131c89 100644
--- a/gnu/usr.bin/cc/cc_int/rtl.c
+++ b/gnu/usr.bin/cc/cc_int/rtl.c
@@ -158,7 +158,7 @@ char *rtx_format[] = {
that rtx code. See rtl.def for documentation on the defined classes. */
char rtx_class[] = {
-#define DEF_RTL_EXPR(ENUM, NAME, FORMAT, CLASS) CLASS,
+#define DEF_RTL_EXPR(ENUM, NAME, FORMAT, CLASS) CLASS,
#include "rtl.def" /* rtl expressions are defined here */
#undef DEF_RTL_EXPR
};
@@ -301,7 +301,7 @@ copy_rtx (orig)
copy->volatil = orig->volatil;
copy->unchanging = orig->unchanging;
copy->integrated = orig->integrated;
-
+
format_ptr = GET_RTX_FORMAT (GET_CODE (copy));
for (i = 0; i < GET_RTX_LENGTH (GET_CODE (copy)); i++)
@@ -387,7 +387,7 @@ copy_most_rtx (orig, may_share)
copy->volatil = orig->volatil;
copy->unchanging = orig->unchanging;
copy->integrated = orig->integrated;
-
+
format_ptr = GET_RTX_FORMAT (GET_CODE (copy));
for (i = 0; i < GET_RTX_LENGTH (GET_CODE (copy)); i++)
@@ -490,7 +490,7 @@ read_skip_spaces (infile)
c = getc (infile);
if (c != '*')
dump_and_abort ('*', c, infile);
-
+
prevc = 0;
while (c = getc (infile))
{
@@ -643,7 +643,7 @@ read_rtx (infile)
break;
}
/* Now process the vector. */
-
+
case 'E':
{
register struct rtx_list *next_rtx, *rtx_list_link;
diff --git a/gnu/usr.bin/cc/cc_int/rtlanal.c b/gnu/usr.bin/cc/cc_int/rtlanal.c
index 188fb93..6a45cdf 100644
--- a/gnu/usr.bin/cc/cc_int/rtlanal.c
+++ b/gnu/usr.bin/cc/cc_int/rtlanal.c
@@ -154,7 +154,7 @@ rtx_addr_can_trap_p (x)
return 1;
}
-/* Return 1 if X refers to a memory location whose address
+/* Return 1 if X refers to a memory location whose address
cannot be compared reliably with constant addresses,
or if X refers to a BLKmode memory object. */
@@ -260,7 +260,7 @@ reg_mentioned_p (reg, in)
case CONST_INT:
return GET_CODE (reg) == CONST_INT && INTVAL (in) == INTVAL (reg);
-
+
case CONST_DOUBLE:
/* These are kept unique for a given value. */
return 0;
@@ -586,13 +586,13 @@ single_set (insn)
{
rtx set;
int i;
-
+
if (GET_RTX_CLASS (GET_CODE (insn)) != 'i')
return 0;
if (GET_CODE (PATTERN (insn)) == SET)
return PATTERN (insn);
-
+
else if (GET_CODE (PATTERN (insn)) == PARALLEL)
{
for (i = 0, set = 0; i < XVECLEN (PATTERN (insn), 0); i++)
@@ -608,7 +608,7 @@ single_set (insn)
}
return set;
}
-
+
return 0;
}
@@ -649,14 +649,14 @@ find_last_value (x, pinsn, valid_to)
return src;
}
}
-
+
/* If set in non-simple way, we don't have a value. */
if (reg_set_p (x, p))
break;
}
return x;
-}
+}
/* Return nonzero if register in range [REGNO, ENDREGNO)
appears either explicitly or implicitly in X
@@ -700,7 +700,7 @@ refers_to_regno_p (regno, endregno, x, loc)
return 1;
return (endregno > i
- && regno < i + (i < FIRST_PSEUDO_REGISTER
+ && regno < i + (i < FIRST_PSEUDO_REGISTER
? HARD_REGNO_NREGS (i, GET_MODE (x))
: 1));
@@ -1029,7 +1029,7 @@ rtx_equal_p (x, y)
If the item being stored in or clobbered is a SUBREG of a hard register,
the SUBREG will be passed. */
-
+
void
note_stores (x, fun)
register rtx x;
@@ -1146,7 +1146,7 @@ dead_or_set_regno_p (insn, test_regno)
if (GET_CODE (PATTERN (insn)) == SET)
{
rtx dest = SET_DEST (PATTERN (insn));
-
+
/* A value is totally replaced if it is the destination or the
destination is a SUBREG of REGNO that does not change the number of
words in it. */
@@ -1401,7 +1401,7 @@ volatile_insn_p (x)
{
register char *fmt = GET_RTX_FORMAT (code);
register int i;
-
+
for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
{
if (fmt[i] == 'e')
@@ -1464,7 +1464,7 @@ volatile_refs_p (x)
{
register char *fmt = GET_RTX_FORMAT (code);
register int i;
-
+
for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
{
if (fmt[i] == 'e')
@@ -1536,7 +1536,7 @@ side_effects_p (x)
{
register char *fmt = GET_RTX_FORMAT (code);
register int i;
-
+
for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
{
if (fmt[i] == 'e')
@@ -1603,6 +1603,10 @@ may_trap_p (x)
we can link this file into other programs. */
if (GET_CODE (XEXP (x, 1)) == CONST_INT && INTVAL (XEXP (x, 1)) == 0)
return 1;
+ case EXPR_LIST:
+ /* An EXPR_LIST is used to represent a function call. This
+ certainly may trap. */
+ return 1;
default:
/* Any floating arithmetic may trap. */
if (GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT)
@@ -1681,7 +1685,7 @@ inequality_comparisons_p (x)
return 1;
}
}
-
+
return 0;
}
@@ -1715,12 +1719,12 @@ replace_rtx (x, from, to)
}
return x;
-}
+}
/* Throughout the rtx X, replace many registers according to REG_MAP.
Return the replacement for X (which may be X with altered contents).
REG_MAP[R] is the replacement for register R, or 0 for don't replace.
- NREGS is the length of REG_MAP; regs >= NREGS are not mapped.
+ NREGS is the length of REG_MAP; regs >= NREGS are not mapped.
We only support REG_MAP entries of REG or SUBREG. Also, hard registers
should not be mapped to pseudos or vice versa since validate_change
diff --git a/gnu/usr.bin/cc/cc_int/sched.c b/gnu/usr.bin/cc/cc_int/sched.c
index 9870967..ef089ba 100644
--- a/gnu/usr.bin/cc/cc_int/sched.c
+++ b/gnu/usr.bin/cc/cc_int/sched.c
@@ -315,7 +315,7 @@ static void add_insn_mem_dependence PROTO((rtx *, rtx *, rtx, rtx));
static void flush_pending_lists PROTO((rtx));
static void sched_analyze_1 PROTO((rtx, rtx));
static void sched_analyze_2 PROTO((rtx, rtx));
-static void sched_analyze_insn PROTO((rtx, rtx));
+static void sched_analyze_insn PROTO((rtx, rtx, rtx));
static int sched_analyze PROTO((rtx, rtx));
static void sched_note_set PROTO((int, rtx, int));
static int rank_for_schedule PROTO((rtx *, rtx *));
@@ -791,7 +791,7 @@ memrefs_conflict_p (xsize, x, ysize, y, c)
If both memory references are volatile, then there must always be a
dependence between the two references, since their order can not be
changed. A volatile and non-volatile reference can be interchanged
- though.
+ though.
A MEM_IN_STRUCT reference at a non-QImode varying address can never
conflict with a non-MEM_IN_STRUCT reference at a fixed address. We must
@@ -2013,8 +2013,9 @@ sched_analyze_2 (x, insn)
/* Analyze an INSN with pattern X to find all dependencies. */
static void
-sched_analyze_insn (x, insn)
+sched_analyze_insn (x, insn, loop_notes)
rtx x, insn;
+ rtx loop_notes;
{
register RTX_CODE code = GET_CODE (x);
rtx link;
@@ -2048,6 +2049,36 @@ sched_analyze_insn (x, insn)
sched_analyze_2 (XEXP (link, 0), insn);
}
+ /* If there is a LOOP_{BEG,END} note in the middle of a basic block, then
+ we must be sure that no instructions are scheduled across it.
+ Otherwise, the reg_n_refs info (which depends on loop_depth) would
+ become incorrect. */
+
+ if (loop_notes)
+ {
+ int max_reg = max_reg_num ();
+ rtx link;
+
+ for (i = 0; i < max_reg; i++)
+ {
+ rtx u;
+ for (u = reg_last_uses[i]; u; u = XEXP (u, 1))
+ add_dependence (insn, XEXP (u, 0), REG_DEP_ANTI);
+ reg_last_uses[i] = 0;
+ if (reg_last_sets[i])
+ add_dependence (insn, reg_last_sets[i], 0);
+ }
+ reg_pending_sets_all = 1;
+
+ flush_pending_lists (insn);
+
+ link = loop_notes;
+ while (XEXP (link, 1))
+ link = XEXP (link, 1);
+ XEXP (link, 1) = REG_NOTES (insn);
+ REG_NOTES (insn) = loop_notes;
+ }
+
/* After reload, it is possible for an instruction to have a REG_DEAD note
for a register that actually dies a few instructions earlier. For
example, this can happen with SECONDARY_MEMORY_NEEDED reloads.
@@ -2107,7 +2138,8 @@ sched_analyze_insn (x, insn)
prev_dep_insn = insn;
dep_insn = PREV_INSN (insn);
while (GET_CODE (dep_insn) == INSN
- && GET_CODE (PATTERN (dep_insn)) == USE)
+ && GET_CODE (PATTERN (dep_insn)) == USE
+ && GET_CODE (XEXP (PATTERN (dep_insn), 0)) == REG)
{
SCHED_GROUP_P (prev_dep_insn) = 1;
@@ -2135,6 +2167,7 @@ sched_analyze (head, tail)
register int n_insns = 0;
register rtx u;
register int luid = 0;
+ rtx loop_notes = 0;
for (insn = head; ; insn = NEXT_INSN (insn))
{
@@ -2142,7 +2175,8 @@ sched_analyze (head, tail)
if (GET_CODE (insn) == INSN || GET_CODE (insn) == JUMP_INSN)
{
- sched_analyze_insn (PATTERN (insn), insn);
+ sched_analyze_insn (PATTERN (insn), insn, loop_notes);
+ loop_notes = 0;
n_insns += 1;
}
else if (GET_CODE (insn) == CALL_INSN)
@@ -2179,7 +2213,8 @@ sched_analyze (head, tail)
/* Add a fake REG_NOTE which we will later convert
back into a NOTE_INSN_SETJMP note. */
- REG_NOTES (insn) = gen_rtx (EXPR_LIST, REG_DEAD, constm1_rtx,
+ REG_NOTES (insn) = gen_rtx (EXPR_LIST, REG_DEAD,
+ GEN_INT (NOTE_INSN_SETJMP),
REG_NOTES (insn));
}
else
@@ -2207,7 +2242,8 @@ sched_analyze (head, tail)
}
LOG_LINKS (sched_before_next_call) = 0;
- sched_analyze_insn (PATTERN (insn), insn);
+ sched_analyze_insn (PATTERN (insn), insn, loop_notes);
+ loop_notes = 0;
/* We don't need to flush memory for a function call which does
not involve memory. */
@@ -2224,6 +2260,11 @@ sched_analyze (head, tail)
last_function_call = insn;
n_insns += 1;
}
+ else if (GET_CODE (insn) == NOTE
+ && (NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_BEG
+ || NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_END))
+ loop_notes = gen_rtx (EXPR_LIST, REG_DEAD,
+ GEN_INT (NOTE_LINE_NUMBER (insn)), loop_notes);
if (insn == tail)
return n_insns;
@@ -2290,7 +2331,7 @@ sched_note_set (b, x, death)
{
offset = (regno + j) / REGSET_ELT_BITS;
bit = (REGSET_ELT_TYPE) 1 << ((regno + j) % REGSET_ELT_BITS);
-
+
bb_live_regs[offset] &= ~bit;
bb_dead_regs[offset] |= bit;
}
@@ -2311,7 +2352,7 @@ sched_note_set (b, x, death)
{
offset = (regno + j) / REGSET_ELT_BITS;
bit = (REGSET_ELT_TYPE) 1 << ((regno + j) % REGSET_ELT_BITS);
-
+
bb_live_regs[offset] |= bit;
bb_dead_regs[offset] &= ~bit;
}
@@ -2669,13 +2710,13 @@ create_reg_dead_note (reg, insn)
rtx reg, insn;
{
rtx link;
-
+
/* The number of registers killed after scheduling must be the same as the
number of registers killed before scheduling. The number of REG_DEAD
notes may not be conserved, i.e. two SImode hard register REG_DEAD notes
might become one DImode hard register REG_DEAD note, but the number of
registers killed will be conserved.
-
+
We carefully remove REG_DEAD notes from the dead_notes list, so that
there will be none left at the end. If we run out early, then there
is a bug somewhere in flow, combine and/or sched. */
@@ -2800,7 +2841,7 @@ attach_deaths (x, insn, set_p)
because we may have to execute this code several times, e.g.
once for a clobber (which doesn't add a note) and later
for a use (which does add a note).
-
+
Always make the register live. We must do this even if it was
live before, because this may be an insn which sets and uses
the same register, in which case the register has already been
@@ -2825,6 +2866,16 @@ attach_deaths (x, insn, set_p)
{
if (! all_needed && ! dead_or_set_p (insn, x))
{
+ /* Check for the case where the register dying partially
+ overlaps the register set by this insn. */
+ if (regno < FIRST_PSEUDO_REGISTER
+ && HARD_REGNO_NREGS (regno, GET_MODE (x)) > 1)
+ {
+ int n = HARD_REGNO_NREGS (regno, GET_MODE (x));
+ while (--n >= 0)
+ some_needed |= dead_or_set_regno_p (insn, regno + n);
+ }
+
/* If none of the words in X is needed, make a REG_DEAD
note. Otherwise, we must make partial REG_DEAD
notes. */
@@ -2985,8 +3036,11 @@ unlink_notes (insn, tail)
/* Don't save away NOTE_INSN_SETJMPs, because they must remain
immediately after the call they follow. We use a fake
- (REG_DEAD (const_int -1)) note to remember them. */
- else if (NOTE_LINE_NUMBER (insn) != NOTE_INSN_SETJMP)
+ (REG_DEAD (const_int -1)) note to remember them.
+ Likewise with NOTE_INSN_LOOP_BEG and NOTE_INSN_LOOP_END. */
+ else if (NOTE_LINE_NUMBER (insn) != NOTE_INSN_SETJMP
+ && NOTE_LINE_NUMBER (insn) != NOTE_INSN_LOOP_BEG
+ && NOTE_LINE_NUMBER (insn) != NOTE_INSN_LOOP_END)
{
/* Insert the note at the end of the notes list. */
PREV_INSN (insn) = note_list;
@@ -3702,7 +3756,7 @@ schedule_block (b, file)
|| GET_CODE (XVECEXP (PATTERN (insn), 0, j)) == CLOBBER)
sched_note_set (b, XVECEXP (PATTERN (insn), 0, j), 1);
}
-
+
/* This code keeps life analysis information up to date. */
if (GET_CODE (insn) == CALL_INSN)
{
@@ -3803,17 +3857,23 @@ schedule_block (b, file)
PREV_INSN (last) = insn;
last = insn;
- /* Check to see if we need to re-emit a NOTE_INSN_SETJMP here. */
- if (GET_CODE (insn) == CALL_INSN)
- {
- rtx note = find_reg_note (insn, REG_DEAD, constm1_rtx);
+ /* Check to see if we need to re-emit any notes here. */
+ {
+ rtx note;
- if (note)
- {
- emit_note_after (NOTE_INSN_SETJMP, insn);
- remove_note (insn, note);
- }
- }
+ for (note = REG_NOTES (insn); note; note = XEXP (note, 1))
+ {
+ if (REG_NOTE_KIND (note) == REG_DEAD
+ && GET_CODE (XEXP (note, 0)) == CONST_INT)
+ {
+ if (INTVAL (XEXP (note, 0)) == NOTE_INSN_SETJMP)
+ emit_note_after (INTVAL (XEXP (note, 0)), insn);
+ else
+ last = emit_note_before (INTVAL (XEXP (note, 0)), last);
+ remove_note (insn, note);
+ }
+ }
+ }
/* Everything that precedes INSN now either becomes "ready", if
it can execute immediately before INSN, or "pending", if
@@ -4161,16 +4221,16 @@ update_n_sets (x, inc)
while (GET_CODE (dest) == STRICT_LOW_PART || GET_CODE (dest) == SUBREG
|| GET_CODE (dest) == ZERO_EXTRACT || GET_CODE (dest) == SIGN_EXTRACT)
dest = SUBREG_REG (dest);
-
+
if (GET_CODE (dest) == REG)
{
int regno = REGNO (dest);
-
+
if (regno < FIRST_PSEUDO_REGISTER)
{
register int i;
int endregno = regno + HARD_REGNO_NREGS (regno, GET_MODE (dest));
-
+
for (i = regno; i < endregno; i++)
reg_n_sets[i] += inc;
}
@@ -4658,7 +4718,7 @@ schedule_insns (dump_file)
This must be computed and saved now, because after a basic block's
predecessor has been scheduled, it is impossible to accurately
determine the correct line number for the first insn of the block. */
-
+
for (b = 0; b < n_basic_blocks; b++)
for (line = basic_block_head[b]; line; line = PREV_INSN (line))
if (GET_CODE (line) == NOTE && NOTE_LINE_NUMBER (line) > 0)
diff --git a/gnu/usr.bin/cc/cc_int/sdbout.c b/gnu/usr.bin/cc/cc_int/sdbout.c
index 6a03108..cd73964 100644
--- a/gnu/usr.bin/cc/cc_int/sdbout.c
+++ b/gnu/usr.bin/cc/cc_int/sdbout.c
@@ -53,7 +53,7 @@ AT&T C compiler. From the example below I would conclude the following:
/* Mips systems use the SDB functions to dump out symbols, but
do not supply usable syms.h include files. */
-#if defined(USG) && !defined(MIPS) && !defined (hpux)
+#if defined(USG) && !defined(MIPS) && !defined (hpux) && !defined(WINNT)
#include <syms.h>
/* Use T_INT if we don't have T_VOID. */
#ifndef T_VOID
@@ -291,7 +291,7 @@ sdbout_init (asm_file, input_file_name, syms)
if (DECL_NAME (t) && IDENTIFIER_POINTER (DECL_NAME (t)) != 0
&& !strcmp (IDENTIFIER_POINTER (DECL_NAME (t)), "__vtbl_ptr_type"))
sdbout_symbol (t, 0);
-#endif
+#endif
#if 0 /* Nothing need be output for the predefined types. */
/* Get all permanent types that have typedef names,
diff --git a/gnu/usr.bin/cc/cc_int/stmt.c b/gnu/usr.bin/cc/cc_int/stmt.c
index 4069829..2b5f06c 100644
--- a/gnu/usr.bin/cc/cc_int/stmt.c
+++ b/gnu/usr.bin/cc/cc_int/stmt.c
@@ -735,7 +735,7 @@ expand_goto (label)
addr = copy_rtx (p->nonlocal_goto_handler_slot);
temp = copy_to_reg (replace_rtx (addr, virtual_stack_vars_rtx,
hard_frame_pointer_rtx));
-
+
/* Restore the stack pointer. Note this uses fp just restored. */
addr = p->nonlocal_goto_stack_level;
if (addr)
@@ -892,11 +892,11 @@ bc_expand_goto_internal (opcode, label, body)
if (body && DECL_BIT_FIELD (body))
error ("jump to `%s' invalidly jumps into binding contour",
IDENTIFIER_POINTER (DECL_NAME (body)));
-
+
/* Emit immediate jump */
bc_emit_bytecode (opcode);
bc_emit_bytecode_labelref (label);
-
+
#ifdef DEBUG_PRINT_CODE
fputc ('\n', stderr);
#endif
@@ -1380,6 +1380,8 @@ expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line)
i = decode_reg_name (regname);
if (i >= 0 || i == -4)
++nclobbers;
+ else if (i == -2)
+ error ("unknown register name `%s' in `asm'", regname);
}
last_expr_type = 0;
@@ -1569,8 +1571,7 @@ expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line)
continue;
}
- error ("unknown register name `%s' in `asm'", regname);
- return;
+ /* Ignore unknown register, error already signalled. */
}
/* Use QImode since that's guaranteed to clobber just one reg. */
@@ -1600,7 +1601,7 @@ expand_expr_stmt (exp)
/* Restore stack depth */
if (stack_depth < org_stack_depth)
abort ();
-
+
bc_emit_instruction (drop);
last_expr_type = TREE_TYPE (exp);
@@ -1639,7 +1640,7 @@ expand_expr_stmt (exp)
else
{
rtx lab = gen_label_rtx ();
-
+
/* Compare the value with itself to reference it. */
emit_cmp_insn (last_expr_value, last_expr_value, EQ,
expand_expr (TYPE_SIZE (last_expr_type),
@@ -1730,7 +1731,7 @@ warn_if_unused_value (exp)
while (TREE_CODE (tem) == CONVERT_EXPR || TREE_CODE (tem) == NOP_EXPR)
tem = TREE_OPERAND (tem, 0);
- if (TREE_CODE (tem) == MODIFY_EXPR)
+ if (TREE_CODE (tem) == MODIFY_EXPR || TREE_CODE (tem) == INIT_EXPR)
return 0;
}
/* ... fall through ... */
@@ -1800,8 +1801,8 @@ expand_end_stmt_expr (t)
{
int i;
tree t;
-
-
+
+
/* At this point, all expressions have been evaluated in order.
However, all expression values have been popped when evaluated,
which means we have to recover the last expression value. This is
@@ -1810,20 +1811,20 @@ expand_end_stmt_expr (t)
is here recovered by undoing the `drop'. Since `drop' is
equivalent to `adjustackSI [1]', it can be undone with `adjstackSI
[-1]'. */
-
+
bc_adjust_stack (-1);
-
+
if (!last_expr_type)
last_expr_type = void_type_node;
-
+
t = make_node (RTL_EXPR);
TREE_TYPE (t) = last_expr_type;
RTL_EXPR_RTL (t) = NULL;
RTL_EXPR_SEQUENCE (t) = NULL;
-
+
/* Don't consider deleting this expr or containing exprs at tree level. */
TREE_THIS_VOLATILE (t) = 1;
-
+
last_expr_type = 0;
return t;
}
@@ -1932,6 +1933,17 @@ expand_start_else ()
cond_stack->data.cond.next_label = 0; /* No more _else or _elseif calls. */
}
+/* After calling expand_start_else, turn this "else" into an "else if"
+ by providing another condition. */
+
+void
+expand_elseif (cond)
+ tree cond;
+{
+ cond_stack->data.cond.next_label = gen_label_rtx ();
+ do_jump (cond, cond_stack->data.cond.next_label, NULL_RTX);
+}
+
/* Generate RTL for the end of an if-then.
Pop the record for it off of cond_stack. */
@@ -2111,7 +2123,7 @@ expand_end_loop ()
register rtx start_label;
rtx last_test_insn = 0;
int num_insns = 0;
-
+
if (output_bytecode)
{
bc_expand_end_loop ();
@@ -2490,7 +2502,7 @@ expand_return (retval)
bc_emit_instruction (ret);
return;
}
-
+
/* If function wants no value, give it none. */
if (TREE_CODE (TREE_TYPE (TREE_TYPE (current_function_decl))) == VOID_TYPE)
{
@@ -2501,7 +2513,15 @@ expand_return (retval)
}
/* Are any cleanups needed? E.g. C++ destructors to be run? */
+ /* This is not sufficient. We also need to watch for cleanups of the
+ expression we are about to expand. Unfortunately, we cannot know
+ if it has cleanups until we expand it, and we want to change how we
+ expand it depending upon if we need cleanups. We can't win. */
+#if 0
cleanups = any_pending_cleanups (1);
+#else
+ cleanups = 1;
+#endif
if (TREE_CODE (retval) == RESULT_DECL)
retval_rhs = retval;
@@ -3452,7 +3472,7 @@ bc_expand_decl_init (decl)
bc_adjust_stack (stack_depth - org_stack_depth);
}
-
+
/* CLEANUP is an expression to be executed at exit from this binding contour;
for example, in C++, it might call the destructor for this variable.
@@ -3510,6 +3530,17 @@ expand_anon_union_decl (decl, cleanup, decl_elts)
tree cleanup_elt = TREE_PURPOSE (decl_elts);
enum machine_mode mode = TYPE_MODE (TREE_TYPE (decl_elt));
+ /* Propagate the union's alignment to the elements. */
+ DECL_ALIGN (decl_elt) = DECL_ALIGN (decl);
+
+ /* If the element has BLKmode and the union doesn't, the union is
+ aligned such that the element doesn't need to have BLKmode, so
+ change the element's mode to the appropriate one for its size. */
+ if (mode == BLKmode && DECL_MODE (decl) != BLKmode)
+ DECL_MODE (decl_elt) = mode
+ = mode_for_size (TREE_INT_CST_LOW (DECL_SIZE (decl_elt)),
+ MODE_INT, 1);
+
/* (SUBREG (MEM ...)) at RTL generation time is invalid, so we
instead create a new MEM rtx with the proper mode. */
if (GET_CODE (x) == MEM)
@@ -4055,6 +4086,191 @@ bc_pushcase (value, label)
return 0;
}
+/* Returns the number of possible values of TYPE.
+ Returns -1 if the number is unknown or variable.
+ Returns -2 if the number does not fit in a HOST_WIDE_INT.
+ Sets *SPARENESS to 2 if TYPE is an ENUMERAL_TYPE whose values
+ do not increase monotonically (there may be duplicates);
+ to 1 if the values increase monotonically, but not always by 1;
+ otherwise sets it to 0. */
+
+HOST_WIDE_INT
+all_cases_count (type, spareness)
+ tree type;
+ int *spareness;
+{
+ HOST_WIDE_INT count, count_high = 0;
+ *spareness = 0;
+
+ switch (TREE_CODE (type))
+ {
+ tree t;
+ case BOOLEAN_TYPE:
+ count = 2;
+ break;
+ case CHAR_TYPE:
+ count = 1 << BITS_PER_UNIT;
+ break;
+ default:
+ case INTEGER_TYPE:
+ if (TREE_CODE (TYPE_MIN_VALUE (type)) != INTEGER_CST
+ || TREE_CODE (TYPE_MIN_VALUE (type)) != INTEGER_CST)
+ return -1;
+ else
+ {
+ /* count
+ = TREE_INT_CST_LOW (TYPE_MAX_VALUE (type))
+ - TREE_INT_CST_LOW (TYPE_MIN_VALUE (type)) + 1
+ but with overflow checking. */
+ tree mint = TYPE_MIN_VALUE (type);
+ tree maxt = TYPE_MAX_VALUE (type);
+ HOST_WIDE_INT lo, hi;
+ neg_double(TREE_INT_CST_LOW (mint), TREE_INT_CST_HIGH (mint),
+ &lo, &hi);
+ add_double(TREE_INT_CST_LOW (maxt), TREE_INT_CST_HIGH (maxt),
+ lo, hi, &lo, &hi);
+ add_double (lo, hi, 1, 0, &lo, &hi);
+ if (hi != 0 || lo < 0)
+ return -2;
+ count = lo;
+ }
+ break;
+ case ENUMERAL_TYPE:
+ count = 0;
+ for (t = TYPE_VALUES (type); t != NULL_TREE; t = TREE_CHAIN (t))
+ {
+ if (TREE_CODE (TYPE_MIN_VALUE (type)) != INTEGER_CST
+ || TREE_CODE (TREE_VALUE (t)) != INTEGER_CST
+ || TREE_INT_CST_LOW (TYPE_MIN_VALUE (type)) + count
+ != TREE_INT_CST_LOW (TREE_VALUE (t)))
+ *spareness = 1;
+ count++;
+ }
+ if (*spareness == 1)
+ {
+ tree prev = TREE_VALUE (TYPE_VALUES (type));
+ for (t = TYPE_VALUES (type); t = TREE_CHAIN (t), t != NULL_TREE; )
+ {
+ if (! tree_int_cst_lt (prev, TREE_VALUE (t)))
+ {
+ *spareness = 2;
+ break;
+ }
+ prev = TREE_VALUE (t);
+ }
+
+ }
+ }
+ return count;
+}
+
+
+#define BITARRAY_TEST(ARRAY, INDEX) \
+ ((ARRAY)[(unsigned)(INDEX) / HOST_BITS_PER_CHAR]\
+ & (1 << ((unsigned)(INDEX) % HOST_BITS_PER_CHAR)))
+#define BITARRAY_SET(ARRAY, INDEX) \
+ ((ARRAY)[(unsigned)(INDEX) / HOST_BITS_PER_CHAR]\
+ |= 1 << ((unsigned)(INDEX) % HOST_BITS_PER_CHAR))
+
+/* Set the elements of the bitstring CASES_SEEN (which has length COUNT),
+ with the case values we have seen, assuming the case expression
+ has the given TYPE.
+ SPARSENESS is as determined by all_cases_count.
+
+ The time needed is propotional to COUNT, unless
+ SPARSENESS is 2, in which case quadratic time is needed. */
+
+void
+mark_seen_cases (type, cases_seen, count, sparseness)
+ tree type;
+ unsigned char *cases_seen;
+ long count;
+ int sparseness;
+{
+ long i;
+
+ tree next_node_to_try = NULL_TREE;
+ long next_node_offset = 0;
+
+ register struct case_node *n;
+ tree val = make_node (INTEGER_CST);
+ TREE_TYPE (val) = type;
+ for (n = case_stack->data.case_stmt.case_list; n;
+ n = n->right)
+ {
+ TREE_INT_CST_LOW (val) = TREE_INT_CST_LOW (n->low);
+ TREE_INT_CST_HIGH (val) = TREE_INT_CST_HIGH (n->low);
+ while ( ! tree_int_cst_lt (n->high, val))
+ {
+ /* Calculate (into xlo) the "offset" of the integer (val).
+ The element with lowest value has offset 0, the next smallest
+ element has offset 1, etc. */
+
+ HOST_WIDE_INT xlo, xhi;
+ tree t;
+ if (sparseness == 2)
+ {
+ /* This less efficient loop is only needed to handle
+ duplicate case values (multiple enum constants
+ with the same value). */
+ for (t = TYPE_VALUES (type), xlo = 0; t != NULL_TREE;
+ t = TREE_CHAIN (t), xlo++)
+ {
+ if (tree_int_cst_equal (val, TREE_VALUE (t)))
+ BITARRAY_SET (cases_seen, xlo);
+ }
+ }
+ else
+ {
+ if (sparseness && TYPE_VALUES (type) != NULL_TREE)
+ {
+ /* The TYPE_VALUES will be in increasing order, so
+ starting searching where we last ended. */
+ t = next_node_to_try;
+ xlo = next_node_offset;
+ xhi = 0;
+ for (;;)
+ {
+ if (t == NULL_TREE)
+ {
+ t = TYPE_VALUES (type);
+ xlo = 0;
+ }
+ if (tree_int_cst_equal (val, TREE_VALUE (t)))
+ {
+ next_node_to_try = TREE_CHAIN (t);
+ next_node_offset = xlo + 1;
+ break;
+ }
+ xlo++;
+ t = TREE_CHAIN (t);
+ if (t == next_node_to_try)
+ break;
+ }
+ }
+ else
+ {
+ t = TYPE_MIN_VALUE (type);
+ if (t)
+ neg_double (TREE_INT_CST_LOW (t), TREE_INT_CST_HIGH (t),
+ &xlo, &xhi);
+ else
+ xlo = xhi = 0;
+ add_double (xlo, xhi,
+ TREE_INT_CST_LOW (val), TREE_INT_CST_HIGH (val),
+ &xlo, &xhi);
+ }
+
+ if (xhi == 0 && xlo >= 0 && xlo < count)
+ BITARRAY_SET (cases_seen, xlo);
+ }
+ add_double (TREE_INT_CST_LOW (val), TREE_INT_CST_HIGH (val),
+ 1, 0,
+ &TREE_INT_CST_LOW (val), &TREE_INT_CST_HIGH (val));
+ }
+ }
+}
+
/* Called when the index of a switch statement is an enumerated type
and there is no default label.
@@ -4075,37 +4291,55 @@ check_for_full_enumeration_handling (type)
register tree chain;
int all_values = 1;
+ /* True iff the selector type is a numbered set mode. */
+ int sparseness = 0;
+
+ /* The number of possible selector values. */
+ HOST_WIDE_INT size;
+
+ /* For each possible selector value. a one iff it has been matched
+ by a case value alternative. */
+ unsigned char *cases_seen;
+
+ /* The allocated size of cases_seen, in chars. */
+ long bytes_needed;
+ tree t;
+
if (output_bytecode)
{
bc_check_for_full_enumeration_handling (type);
return;
}
- /* The time complexity of this loop is currently O(N * M), with
- N being the number of members in the enumerated type, and
- M being the number of case expressions in the switch. */
+ if (! warn_switch)
+ return;
+
+ size = all_cases_count (type, &sparseness);
+ bytes_needed = (size + HOST_BITS_PER_CHAR) / HOST_BITS_PER_CHAR;
- for (chain = TYPE_VALUES (type);
- chain;
- chain = TREE_CHAIN (chain))
+ if (size > 0 && size < 600000
+ /* We deliberately use malloc here - not xmalloc. */
+ && (cases_seen = (unsigned char *) malloc (bytes_needed)) != NULL)
{
- /* Find a match between enumeral and case expression, if possible.
- Quit looking when we've gone too far (since case expressions
- are kept sorted in ascending order). Warn about enumerators not
- handled in the switch statement case expression list. */
-
- for (n = case_stack->data.case_stmt.case_list;
- n && tree_int_cst_lt (n->high, TREE_VALUE (chain));
- n = n->right)
- ;
+ long i;
+ tree v = TYPE_VALUES (type);
+ bzero (cases_seen, bytes_needed);
+
+ /* The time complexity of this code is normally O(N), where
+ N being the number of members in the enumerated type.
+ However, if type is a ENUMERAL_TYPE whose values do not
+ increase monotonically, quadratic time may be needed. */
+
+ mark_seen_cases (type, cases_seen, size, sparseness);
- if (!n || tree_int_cst_lt (TREE_VALUE (chain), n->low))
+ for (i = 0; v != NULL_TREE && i < size; i++, v = TREE_CHAIN (v))
{
- if (warn_switch)
+ if (BITARRAY_TEST(cases_seen, i) == 0)
warning ("enumeration value `%s' not handled in switch",
- IDENTIFIER_POINTER (TREE_PURPOSE (chain)));
- all_values = 0;
+ IDENTIFIER_POINTER (TREE_PURPOSE (v)));
}
+
+ free (cases_seen);
}
/* Now we go the other way around; we warn if there are case
@@ -4450,7 +4684,7 @@ expand_end_case (orig_index)
use_cost_table
= (TREE_CODE (TREE_TYPE (orig_index)) != ENUMERAL_TYPE
&& estimate_case_costs (thiscase->data.case_stmt.case_list));
- balance_case_nodes (&thiscase->data.case_stmt.case_list,
+ balance_case_nodes (&thiscase->data.case_stmt.case_list,
NULL_PTR);
emit_case_nodes (index, thiscase->data.case_stmt.case_list,
default_label, index_type);
@@ -4687,7 +4921,7 @@ bc_expand_end_case (expr)
/* Bad mode */
abort ();
-
+
bc_emit_bytecode_labeldef (BYTECODE_BC_LABEL (thiscase->exit_label));
/* Possibly issue enumeration warnings. */
@@ -4709,7 +4943,7 @@ bc_expand_end_case (expr)
/* Return unique bytecode ID. */
-int
+int
bc_new_uid ()
{
static int bc_uid = 0;
diff --git a/gnu/usr.bin/cc/cc_int/stor-layout.c b/gnu/usr.bin/cc/cc_int/stor-layout.c
index d2c6f28..3da5cc2 100644
--- a/gnu/usr.bin/cc/cc_int/stor-layout.c
+++ b/gnu/usr.bin/cc/cc_int/stor-layout.c
@@ -44,6 +44,10 @@ tree size_one_node;
The value is measured in bits. */
int maximum_field_alignment;
+/* If non-zero, the alignment of a bitsting or (power-)set value, in bits.
+ May be overridden by front-ends. */
+int set_alignment = 0;
+
#define GET_MODE_ALIGNMENT(MODE) \
MIN (BIGGEST_ALIGNMENT, \
MAX (1, (GET_MODE_UNIT_SIZE (MODE) * BITS_PER_UNIT)))
@@ -84,8 +88,8 @@ variable_size (size)
{
/* If the language-processor is to take responsibility for variable-sized
items (e.g., languages which have elaboration procedures like Ada),
- just return SIZE unchanged. */
- if (global_bindings_p () < 0)
+ just return SIZE unchanged. Likewise for self-referential sizes. */
+ if (global_bindings_p () < 0 || contains_placeholder_p (size))
return size;
size = save_expr (size);
@@ -101,7 +105,7 @@ variable_size (size)
}
if (immediate_size_expand)
- /* NULL_RTX is not defined; neither is the rtx type.
+ /* NULL_RTX is not defined; neither is the rtx type.
Also, we would like to pass const0_rtx here, but don't have it. */
expand_expr (size, expand_expr (integer_zero_node, NULL_PTR, VOIDmode, 0),
VOIDmode, 0);
@@ -898,6 +902,31 @@ layout_type (type)
TYPE_ALIGN (type) = GET_MODE_ALIGNMENT (TYPE_MODE (type));
break;
+ case SET_TYPE:
+ if (TREE_CODE (TYPE_MAX_VALUE (TYPE_DOMAIN (type))) != INTEGER_CST
+ || TREE_CODE (TYPE_MIN_VALUE (TYPE_DOMAIN (type))) != INTEGER_CST)
+ abort();
+ else
+ {
+#ifndef SET_WORD_SIZE
+#define SET_WORD_SIZE BITS_PER_WORD
+#endif
+ int alignment = set_alignment ? set_alignment : SET_WORD_SIZE;
+ int size_in_bits =
+ TREE_INT_CST_LOW (TYPE_MAX_VALUE (TYPE_DOMAIN (type)))
+ - TREE_INT_CST_LOW (TYPE_MIN_VALUE (TYPE_DOMAIN (type))) + 1;
+ int rounded_size
+ = ((size_in_bits + alignment - 1) / alignment) * alignment;
+ if (rounded_size > alignment)
+ TYPE_MODE (type) = BLKmode;
+ else
+ TYPE_MODE (type) = mode_for_size (alignment, MODE_INT, 1);
+ TYPE_SIZE (type) = size_int (rounded_size);
+ TYPE_ALIGN (type) = alignment;
+ TYPE_PRECISION (type) = size_in_bits;
+ }
+ break;
+
case FILE_TYPE:
/* The size may vary in different languages, so the language front end
should fill in the size. */
@@ -945,7 +974,7 @@ layout_type (type)
TYPE_MODE (variant) = mode;
}
}
-
+
pop_obstacks ();
resume_momentary (old);
}
diff --git a/gnu/usr.bin/cc/cc_int/stupid.c b/gnu/usr.bin/cc/cc_int/stupid.c
index 7ceec9f..3317feb 100644
--- a/gnu/usr.bin/cc/cc_int/stupid.c
+++ b/gnu/usr.bin/cc/cc_int/stupid.c
@@ -82,6 +82,11 @@ static int *reg_order;
static char *regs_live;
+/* Indexed by reg number, nonzero if reg was used in a SUBREG that changes
+ its size. */
+
+static char *regs_change_size;
+
/* Indexed by insn's suid, the set of hard regs live after that insn. */
static HARD_REG_SET *after_insn_hard_regs;
@@ -93,7 +98,7 @@ static HARD_REG_SET *after_insn_hard_regs;
static int stupid_reg_compare PROTO((int *, int *));
static int stupid_find_reg PROTO((int, enum reg_class, enum machine_mode,
- int, int));
+ int, int, int));
static void stupid_mark_refs PROTO((rtx, rtx));
/* Stupid life analysis is for the case where only variables declared
@@ -157,6 +162,9 @@ stupid_life_analysis (f, nregs, file)
reg_order = (int *) alloca (nregs * sizeof (int));
bzero ((char *) reg_order, nregs * sizeof (int));
+ regs_change_size = (char *) alloca (nregs * sizeof (char));
+ bzero ((char *) regs_change_size, nregs * sizeof (char));
+
reg_renumber = (short *) oballoc (nregs * sizeof (short));
for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
reg_renumber[i] = i;
@@ -250,11 +258,12 @@ stupid_life_analysis (f, nregs, file)
/* Now find the best hard-register class for this pseudo register */
if (N_REG_CLASSES > 1)
- reg_renumber[r] = stupid_find_reg (reg_n_calls_crossed[r],
+ reg_renumber[r] = stupid_find_reg (reg_n_calls_crossed[r],
reg_preferred_class (r),
PSEUDO_REGNO_MODE (r),
reg_where_born[r],
- reg_where_dead[r]);
+ reg_where_dead[r],
+ regs_change_size[r]);
/* If no reg available in that class, try alternate class. */
if (reg_renumber[r] == -1 && reg_alternate_class (r) != NO_REGS)
@@ -262,7 +271,8 @@ stupid_life_analysis (f, nregs, file)
reg_alternate_class (r),
PSEUDO_REGNO_MODE (r),
reg_where_born[r],
- reg_where_dead[r]);
+ reg_where_dead[r],
+ regs_change_size[r]);
}
if (file)
@@ -303,14 +313,19 @@ stupid_reg_compare (r1p, r2p)
Return -1 if such a block cannot be found.
If CALL_PRESERVED is nonzero, insist on registers preserved
- over subroutine calls, and return -1 if cannot find such. */
+ over subroutine calls, and return -1 if cannot find such.
+
+ If CHANGES_SIZE is nonzero, it means this register was used as the
+ operand of a SUBREG that changes its size. */
static int
-stupid_find_reg (call_preserved, class, mode, born_insn, dead_insn)
+stupid_find_reg (call_preserved, class, mode,
+ born_insn, dead_insn, changes_size)
int call_preserved;
enum reg_class class;
enum machine_mode mode;
int born_insn, dead_insn;
+ int changes_size;
{
register int i, ins;
#ifdef HARD_REG_SET
@@ -339,6 +354,12 @@ stupid_find_reg (call_preserved, class, mode, born_insn, dead_insn)
IOR_COMPL_HARD_REG_SET (used, reg_class_contents[(int) class]);
+#ifdef CLASS_CANNOT_CHANGE_SIZE
+ if (changes_size)
+ IOR_HARD_REG_SET (used,
+ reg_class_contents[(int) CLASS_CANNOT_CHANGE_SIZE]);
+#endif
+
for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
{
#ifdef REG_ALLOC_ORDER
@@ -471,9 +492,18 @@ stupid_mark_refs (x, insn)
return;
}
+ else if (code == SUBREG
+ && GET_CODE (SUBREG_REG (x)) == REG
+ && REGNO (SUBREG_REG (x)) >= FIRST_PSEUDO_REGISTER
+ && (GET_MODE_SIZE (GET_MODE (x))
+ != GET_MODE_SIZE (GET_MODE (SUBREG_REG (x))))
+ && (INTEGRAL_MODE_P (GET_MODE (x))
+ || INTEGRAL_MODE_P (GET_MODE (SUBREG_REG (x)))))
+ regs_change_size[REGNO (SUBREG_REG (x))] = 1;
+
/* Register value being used, not set. */
- if (code == REG)
+ else if (code == REG)
{
regno = REGNO (x);
if (regno < FIRST_PSEUDO_REGISTER)
diff --git a/gnu/usr.bin/cc/cc_int/toplev.c b/gnu/usr.bin/cc/cc_int/toplev.c
index d4b1043..30b027a8 100644
--- a/gnu/usr.bin/cc/cc_int/toplev.c
+++ b/gnu/usr.bin/cc/cc_int/toplev.c
@@ -36,6 +36,7 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
#include <ctype.h>
#include <sys/stat.h>
+#ifndef WINNT
#ifdef USG
#undef FLOAT
#include <sys/param.h>
@@ -50,6 +51,7 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
#include <sys/resource.h>
#endif
#endif
+#endif
#include "input.h"
#include "tree.h"
@@ -430,11 +432,7 @@ int flag_inline_functions;
int flag_keep_inline_functions;
-/* Nonzero means that functions declared `inline' will be treated
- as `static'. Prevents generation of zillions of copies of unused
- static inline functions; instead, `inlines' are written out
- only when actually used. Used in conjunction with -g. Also
- does the right thing with #pragma interface. */
+/* Nonzero means that functions will not be inlined. */
int flag_no_inline;
@@ -489,7 +487,7 @@ int flag_schedule_insns = 0;
int flag_schedule_insns_after_reload = 0;
/* -finhibit-size-directive inhibits output of .size for ELF.
- This is used only for compiling crtstuff.c,
+ This is used only for compiling crtstuff.c,
and it may be extended to other effects
needed for crtstuff.c on other systems. */
int flag_inhibit_size_directive = 0;
@@ -640,6 +638,8 @@ char *lang_options[] =
"-+e0", /* gcc.c tacks the `-' on the front. */
"-+e1",
"-+e2",
+ "-faccess-control",
+ "-fno-access-control",
"-fall-virtual",
"-fno-all-virtual",
"-falt-external-templates",
@@ -707,6 +707,10 @@ char *lang_options[] =
"-Wno-non-virtual-dtor",
"-Wextern-inline",
"-Wno-extern-inline",
+ "-Wreorder",
+ "-Wno-reorder",
+ "-Wsynth",
+ "-Wno-synth",
/* these are for obj c */
"-lang-objc",
@@ -775,7 +779,7 @@ unsigned id_clash_len;
/* Nonzero means warn about any objects definitions whose size is larger
than N bytes. Also want about function definitions whose returned
values are larger than N bytes. The value N is in `larger_than_size'. */
-
+
int warn_larger_than;
unsigned larger_than_size;
@@ -849,6 +853,9 @@ int dump_time;
int
get_run_time ()
{
+#ifdef WINNT
+ return 0;
+#else
#ifdef USG
struct tms tms;
#else
@@ -881,6 +888,7 @@ get_run_time ()
return (vms_times.proc_user_time + vms_times.proc_system_time) * 10000;
#endif
#endif
+#endif
}
#define TIMEVAR(VAR, BODY) \
@@ -942,20 +950,17 @@ fatal_io_error (name)
exit (35);
}
-/* Called to give a better error message when we don't have an insn to match
- what we are looking for or if the insn's constraints aren't satisfied,
- rather than just calling abort(). */
+/* Called to give a better error message for a bad insn rather than
+ just calling abort(). */
void
-fatal_insn_not_found (insn)
+fatal_insn (message, insn)
+ char *message;
rtx insn;
{
if (!output_bytecode)
{
- if (INSN_CODE (insn) < 0)
- error ("internal error--unrecognizable insn:");
- else
- error ("internal error--insn does not satisfy its constraints:");
+ error (message);
debug_rtx (insn);
}
if (asm_out_file)
@@ -993,6 +998,20 @@ fatal_insn_not_found (insn)
abort ();
}
+/* Called to give a better error message when we don't have an insn to match
+ what we are looking for or if the insn's constraints aren't satisfied,
+ rather than just calling abort(). */
+
+void
+fatal_insn_not_found (insn)
+ rtx insn;
+{
+ if (INSN_CODE (insn) < 0)
+ fatal_insn ("internal error--unrecognizable insn:", insn);
+ else
+ fatal_insn ("internal error--insn does not satisfy its constraints:", insn);
+}
+
/* This is the default decl_printable_name function. */
static char *
@@ -1170,7 +1189,7 @@ v_message_with_decl (decl, prefix, s, ap)
{
char fmt[sizeof "%.255s"];
long width = p - s;
-
+
if (width > 255L) width = 255L; /* arbitrary */
sprintf (fmt, "%%.%lds", width);
fprintf (stderr, fmt, s);
@@ -2227,7 +2246,7 @@ compile_file (name)
Therefore, I took out that change.
In future versions we should find another way to solve
that dbx problem. -- rms, 23 May 93. */
-
+
/* Don't let the first function fall at the same address
as gcc_compiled., if profiling. */
if (profile_flag || profile_block_flag)
@@ -2395,7 +2414,7 @@ compile_file (name)
&& DECL_EXTERNAL (decl)
&& ! TREE_PUBLIC (decl))
{
- pedwarn_with_decl (decl,
+ pedwarn_with_decl (decl,
"`%s' declared `static' but never defined");
/* This symbol is effectively an "extern" declaration now. */
TREE_PUBLIC (decl) = 1;
@@ -2719,6 +2738,7 @@ rest_of_compilation (decl)
if (warn_inline && specd)
warning_with_decl (decl, lose);
DECL_INLINE (decl) = 0;
+ DECL_ABSTRACT_ORIGIN (decl) = 0;
/* Don't really compile an extern inline function.
If we can't make it inline, pretend
it was only declared. */
@@ -3738,7 +3758,7 @@ You Lose! You must define PREFERRED_DEBUGGING_TYPE!
else if (!strncmp (str, "gstabs+", len))
write_symbols = DBX_DEBUG;
- /* Always enable extensions for -ggdb or -gstabs+,
+ /* Always enable extensions for -ggdb or -gstabs+,
always disable for -gstabs.
For plain -g, use system-specific default. */
if (write_symbols == DBX_DEBUG && !strncmp (str, "ggdb", len)
@@ -3763,7 +3783,7 @@ You Lose! You must define PREFERRED_DEBUGGING_TYPE!
else if (!strncmp (str, "gdwarf", len))
write_symbols = DWARF_DEBUG;
- /* Always enable extensions for -ggdb or -gdwarf+,
+ /* Always enable extensions for -ggdb or -gdwarf+,
always disable for -gdwarf.
For plain -g, use system-specific default. */
if (write_symbols == DWARF_DEBUG && !strncmp (str, "ggdb", len)
@@ -3810,7 +3830,7 @@ You Lose! You must define PREFERRED_DEBUGGING_TYPE!
use_gnu_debug_info_extensions = 0;
else
use_gnu_debug_info_extensions = DEFAULT_GDB_EXTENSIONS;
-#endif
+#endif
if (write_symbols == NO_DEBUG)
warning ("`-%s' option not supported on this version of GCC", str);
else if (level == 0)
@@ -3927,8 +3947,7 @@ You Lose! You must define PREFERRED_DEBUGGING_TYPE!
compile_file (filename);
-#ifndef OS2
-#ifndef VMS
+#if !defined(OS2) && !defined(VMS) && !defined(WINNT)
if (flag_print_mem)
{
#ifdef __alpha
@@ -3946,8 +3965,7 @@ You Lose! You must define PREFERRED_DEBUGGING_TYPE!
system ("ps v");
#endif /* not USG */
}
-#endif /* not VMS */
-#endif /* not OS2 */
+#endif /* not OS2 and not VMS and not WINNT */
if (errorcount)
exit (FATAL_EXIT_CODE);
@@ -4031,7 +4049,7 @@ print_single_switch (type, name)
line_position = 8;
}
}
-
+
/* Print default target switches for -version. */
static void
diff --git a/gnu/usr.bin/cc/cc_int/tree.c b/gnu/usr.bin/cc/cc_int/tree.c
index e0aa0ae..a790574 100644
--- a/gnu/usr.bin/cc/cc_int/tree.c
+++ b/gnu/usr.bin/cc/cc_int/tree.c
@@ -141,7 +141,7 @@ char *momentary_function_firstobj;
int all_types_permanent;
/* Stack of places to restore the momentary obstack back to. */
-
+
struct momentary_level
{
/* Pointer back to previous such level. */
@@ -319,8 +319,9 @@ gcc_obstack_init (obstack)
This is used before starting a nested function. */
void
-save_tree_status (p)
+save_tree_status (p, toplevel)
struct function *p;
+ int toplevel;
{
p->all_types_permanent = all_types_permanent;
p->momentary_stack = momentary_stack;
@@ -334,10 +335,15 @@ save_tree_status (p)
p->saveable_obstack = saveable_obstack;
p->rtl_obstack = rtl_obstack;
- /* Objects that need to be saved in this function can be in the nonsaved
- obstack of the enclosing function since they can't possibly be needed
- once it has returned. */
- function_maybepermanent_obstack = function_obstack;
+ if (! toplevel)
+ {
+ /* Objects that need to be saved in this function can be in the nonsaved
+ obstack of the enclosing function since they can't possibly be needed
+ once it has returned. */
+ function_maybepermanent_obstack = function_obstack;
+ maybepermanent_firstobj
+ = (char *) obstack_finish (function_maybepermanent_obstack);
+ }
function_obstack = (struct obstack *) xmalloc (sizeof (struct obstack));
gcc_obstack_init (function_obstack);
@@ -348,30 +354,32 @@ save_tree_status (p)
momentary_firstobj = (char *) obstack_finish (&momentary_obstack);
momentary_function_firstobj = momentary_firstobj;
- maybepermanent_firstobj
- = (char *) obstack_finish (function_maybepermanent_obstack);
}
/* Restore all variables describing the current status from the structure *P.
This is used after a nested function. */
void
-restore_tree_status (p)
+restore_tree_status (p, toplevel)
struct function *p;
+ int toplevel;
{
all_types_permanent = p->all_types_permanent;
momentary_stack = p->momentary_stack;
obstack_free (&momentary_obstack, momentary_function_firstobj);
- /* Free saveable storage used by the function just compiled and not
- saved.
-
- CAUTION: This is in function_obstack of the containing function. So
- we must be sure that we never allocate from that obstack during
- the compilation of a nested function if we expect it to survive past the
- nested function's end. */
- obstack_free (function_maybepermanent_obstack, maybepermanent_firstobj);
+ if (! toplevel)
+ {
+ /* Free saveable storage used by the function just compiled and not
+ saved.
+
+ CAUTION: This is in function_obstack of the containing function.
+ So we must be sure that we never allocate from that obstack during
+ the compilation of a nested function if we expect it to survive
+ past the nested function's end. */
+ obstack_free (function_maybepermanent_obstack, maybepermanent_firstobj);
+ }
obstack_free (function_obstack, 0);
free (function_obstack);
@@ -519,7 +527,10 @@ permanent_allocation (function_end)
/* Free up previous temporary obstack data */
obstack_free (&temporary_obstack, temporary_firstobj);
if (function_end)
- obstack_free (&momentary_obstack, momentary_function_firstobj);
+ {
+ obstack_free (&momentary_obstack, momentary_function_firstobj);
+ momentary_firstobj = momentary_function_firstobj;
+ }
else
obstack_free (&momentary_obstack, momentary_firstobj);
obstack_free (&maybepermanent_obstack, maybepermanent_firstobj);
@@ -858,7 +869,7 @@ make_node (code)
PARM_DECLs of top-level functions do not have this problem. However,
we allocate them where we put the FUNCTION_DECL for languauges such as
Ada that need to consult some flags in the PARM_DECLs of the function
- when calling it.
+ when calling it.
See comment in restore_tree_status for why we can't put this
in function_obstack. */
@@ -1154,7 +1165,7 @@ get_identifier (text)
hi &= (1 << HASHBITS) - 1;
hi %= MAX_HASH_TABLE;
-
+
/* Search table for identifier */
for (idp = hash_table[hi]; idp; idp = TREE_CHAIN (idp))
if (IDENTIFIER_LENGTH (idp) == len
@@ -1213,7 +1224,7 @@ set_identifier_size (size)
/* Return a newly constructed INTEGER_CST node whose constant value
is specified by the two ints LOW and HI.
- The TREE_TYPE is set to `int'.
+ The TREE_TYPE is set to `int'.
This function should be used via the `build_int_2' macro. */
@@ -1534,7 +1545,7 @@ real_twop (expr)
}
/* Nonzero if EXP is a constant or a cast of a constant. */
-
+
int
really_constant_p (exp)
tree exp;
@@ -1904,11 +1915,9 @@ staticp (arg)
switch (TREE_CODE (arg))
{
case FUNCTION_DECL:
- /* Nested functions aren't static. Since taking their address
+ /* Nested functions aren't static, since taking their address
involves a trampoline. */
- if (decl_function_context (arg) != 0)
- return 0;
- /* ... fall through ... */
+ return decl_function_context (arg) == 0;
case VAR_DECL:
return TREE_STATIC (arg) || DECL_EXTERNAL (arg);
@@ -1970,7 +1979,7 @@ save_expr (expr)
/* If the tree evaluates to a constant, then we don't want to hide that
fact (i.e. this allows further folding, and direct checks for constants).
However, a read-only object that has side effects cannot be bypassed.
- Since it is no problem to reevaluate literals, we just return the
+ Since it is no problem to reevaluate literals, we just return the
literal node. */
if (TREE_CONSTANT (t) || (TREE_READONLY (t) && ! TREE_SIDE_EFFECTS (t))
@@ -2243,7 +2252,7 @@ substitute_in_type (t, f, r)
/* If this is an anonymous field and the type of this field is
a UNION_TYPE or RECORD_TYPE with no elements, ignore it. If
- the type just has one element, treat that as the field.
+ the type just has one element, treat that as the field.
But don't do this if we are processing a QUAL_UNION_TYPE. */
if (TREE_CODE (t) != QUAL_UNION_TYPE && DECL_NAME (new_field) == 0
&& (TREE_CODE (TREE_TYPE (new_field)) == UNION_TYPE
@@ -2353,6 +2362,13 @@ stabilize_reference (ref)
stabilize_reference_1 (TREE_OPERAND (ref, 1)));
break;
+ case COMPOUND_EXPR:
+ result = build_nt (COMPOUND_EXPR,
+ stabilize_reference_1 (TREE_OPERAND (ref, 0)),
+ stabilize_reference (TREE_OPERAND (ref, 1)));
+ break;
+
+
/* If arg isn't a kind of lvalue we recognize, make no change.
Caller should recognize the error for an invalid lvalue. */
default:
@@ -2421,7 +2437,7 @@ stabilize_reference_1 (e)
/* Constants need no processing. In fact, we should never reach
here. */
return e;
-
+
case '2':
/* Division is slow and tends to be compiled with jumps,
especially the division by powers of 2 that is often
@@ -2444,7 +2460,7 @@ stabilize_reference_1 (e)
default:
abort ();
}
-
+
TREE_TYPE (result) = TREE_TYPE (e);
TREE_READONLY (result) = TREE_READONLY (e);
TREE_SIDE_EFFECTS (result) = TREE_SIDE_EFFECTS (e);
@@ -2792,19 +2808,14 @@ build_type_variant (type, constp, volatilep)
constp = !!constp;
volatilep = !!volatilep;
- /* If not generating auxiliary info, search the chain of variants to see
- if there is already one there just like the one we need to have. If so,
- use that existing one.
-
- We don't do this in the case where we are generating aux info because
- in that case we want each typedef names to get it's own distinct type
- node, even if the type of this new typedef is the same as some other
- (existing) type. */
+ /* Search the chain of variants to see if there is already one there just
+ like the one we need to have. If so, use that existing one. We must
+ preserve the TYPE_NAME, since there is code that depends on this. */
- if (!flag_gen_aux_info)
- for (t = TYPE_MAIN_VARIANT(type); t; t = TYPE_NEXT_VARIANT (t))
- if (constp == TYPE_READONLY (t) && volatilep == TYPE_VOLATILE (t))
- return t;
+ for (t = TYPE_MAIN_VARIANT(type); t; t = TYPE_NEXT_VARIANT (t))
+ if (constp == TYPE_READONLY (t) && volatilep == TYPE_VOLATILE (t)
+ && TYPE_NAME (t) == TYPE_NAME (type))
+ return t;
/* We need a new one. */
@@ -2819,7 +2830,7 @@ build_type_variant (type, constp, volatilep)
This is the right thing to do only when something else
about TYPE is modified in place. */
-tree
+void
change_main_variant (type, new_main)
tree type, new_main;
{
@@ -3054,7 +3065,9 @@ type_list_equal (l1, l2)
int cmp = simple_cst_equal (TREE_PURPOSE (t1), TREE_PURPOSE (t2));
if (cmp < 0)
abort ();
- if (cmp == 0)
+ if (cmp == 0
+ || TREE_TYPE (TREE_PURPOSE (t1))
+ != TREE_TYPE (TREE_PURPOSE (t2)))
return 0;
}
}
@@ -3608,7 +3621,7 @@ build_complex_type (component_type)
OP must have integer, real or enumeral type. Pointers are not allowed!
There are some cases where the obvious value we could return
- would regenerate to OP if converted to OP's type,
+ would regenerate to OP if converted to OP's type,
but would not extend like OP to wider types.
If FOR_TYPE indicates such extension is contemplated, we eschew such values.
For example, if OP is (unsigned short)(signed char)-1,
@@ -3843,7 +3856,7 @@ decl_function_context (decl)
{
if (TREE_CODE (context) == RECORD_TYPE
|| TREE_CODE (context) == UNION_TYPE)
- context = TYPE_CONTEXT (context);
+ context = NULL_TREE;
else if (TREE_CODE (context) == TYPE_DECL)
context = DECL_CONTEXT (context);
else if (TREE_CODE (context) == BLOCK)
@@ -3994,3 +4007,102 @@ get_file_function_name (kind)
return get_identifier (buf);
}
+
+/* Expand (the constant part of) a SET_TYPE CONTRUCTOR node.
+ The result is placed in BUFFER (which has length BIT_SIZE),
+ with one bit in each char ('\000' or '\001').
+
+ If the constructor is constant, NULL_TREE is returned.
+ Otherwise, a TREE_LIST of the non-constant elements is emitted. */
+
+tree
+get_set_constructor_bits (init, buffer, bit_size)
+ tree init;
+ char *buffer;
+ int bit_size;
+{
+ int i;
+ tree vals;
+ HOST_WIDE_INT domain_min
+ = TREE_INT_CST_LOW (TYPE_MIN_VALUE (TYPE_DOMAIN (TREE_TYPE (init))));
+ tree non_const_bits = NULL_TREE;
+ for (i = 0; i < bit_size; i++)
+ buffer[i] = 0;
+
+ for (vals = TREE_OPERAND (init, 1);
+ vals != NULL_TREE; vals = TREE_CHAIN (vals))
+ {
+ if (TREE_CODE (TREE_VALUE (vals)) != INTEGER_CST
+ || (TREE_PURPOSE (vals) != NULL_TREE
+ && TREE_CODE (TREE_PURPOSE (vals)) != INTEGER_CST))
+ non_const_bits =
+ tree_cons (TREE_PURPOSE (vals), TREE_VALUE (vals), non_const_bits);
+ else if (TREE_PURPOSE (vals) != NULL_TREE)
+ {
+ /* Set a range of bits to ones. */
+ HOST_WIDE_INT lo_index
+ = TREE_INT_CST_LOW (TREE_PURPOSE (vals)) - domain_min;
+ HOST_WIDE_INT hi_index
+ = TREE_INT_CST_LOW (TREE_VALUE (vals)) - domain_min;
+ if (lo_index < 0 || lo_index >= bit_size
+ || hi_index < 0 || hi_index >= bit_size)
+ abort ();
+ for ( ; lo_index <= hi_index; lo_index++)
+ buffer[lo_index] = 1;
+ }
+ else
+ {
+ /* Set a single bit to one. */
+ HOST_WIDE_INT index
+ = TREE_INT_CST_LOW (TREE_VALUE (vals)) - domain_min;
+ if (index < 0 || index >= bit_size)
+ {
+ error ("invalid initializer for bit string");
+ return NULL_TREE;
+ }
+ buffer[index] = 1;
+ }
+ }
+ return non_const_bits;
+}
+
+/* Expand (the constant part of) a SET_TYPE CONTRUCTOR node.
+ The result is placed in BUFFER (which is an array of WD_SIZE
+ words). TYPE_ALIGN bits are stored in each element of BUFFER.
+ If the constructor is constant, NULL_TREE is returned.
+ Otherwise, a TREE_LIST of the non-constant elements is emitted. */
+
+tree
+get_set_constructor_words (init, buffer, wd_size)
+ tree init;
+ HOST_WIDE_INT *buffer;
+ int wd_size;
+{
+ int i;
+ tree vals = TREE_OPERAND (init, 1);
+ int set_word_size = TYPE_ALIGN (TREE_TYPE (init));
+ int bit_size = wd_size * set_word_size;
+ int bit_pos = 0;
+ HOST_WIDE_INT *wordp = buffer;
+ char *bit_buffer = (char*)alloca(bit_size);
+ tree non_const_bits = get_set_constructor_bits (init, bit_buffer, bit_size);
+
+ for (i = 0; i < wd_size; i++)
+ buffer[i] = 0;
+
+ for (i = 0; i < bit_size; i++)
+ {
+ if (bit_buffer[i])
+ {
+#if BITS_BIG_ENDIAN
+ *wordp |= (1 << (set_word_size - 1 - bit_pos));
+#else
+ *wordp |= 1 << bit_pos;
+#endif
+ }
+ bit_pos++;
+ if (bit_pos >= set_word_size)
+ bit_pos = 0, wordp++;
+ }
+ return non_const_bits;
+}
diff --git a/gnu/usr.bin/cc/cc_int/unroll.c b/gnu/usr.bin/cc/cc_int/unroll.c
index 9b968ac..b498843 100644
--- a/gnu/usr.bin/cc/cc_int/unroll.c
+++ b/gnu/usr.bin/cc/cc_int/unroll.c
@@ -140,7 +140,7 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
struct _factor { int factor, count; } factors[NUM_FACTORS]
= { {2, 0}, {3, 0}, {5, 0}, {7, 0}};
-
+
/* Describes the different types of loop unrolling performed. */
enum unroll_types { UNROLL_COMPLETELY, UNROLL_MODULO, UNROLL_NAIVE };
@@ -792,7 +792,7 @@ unroll_loop (loop_end, insn_count, loop_start, end_insert_before,
/* Calculate the difference between the final and initial values.
Final value may be a (plus (reg x) (const_int 1)) rtx.
Let the following cse pass simplify this if initial value is
- a constant.
+ a constant.
We must copy the final and initial values here to avoid
improperly shared rtl. */
@@ -861,7 +861,7 @@ unroll_loop (loop_end, insn_count, loop_start, end_insert_before,
For the negative increment case, the branch here could easily
be merged with the `0' case branch above. For the positive
increment case, it is not clear how this can be simplified. */
-
+
if (abs_inc != 1)
{
int cmp_const;
@@ -885,7 +885,7 @@ unroll_loop (loop_end, insn_count, loop_start, end_insert_before,
sequence = gen_sequence ();
end_sequence ();
emit_insn_before (sequence, loop_start);
-
+
/* Only the last copy of the loop body here needs the exit
test, so set copy_end to exclude the compare/branch here,
and then reset it inside the loop when get to the last
@@ -1066,7 +1066,7 @@ unroll_loop (loop_end, insn_count, loop_start, end_insert_before,
{
insn = PREV_INSN (copy_start);
pattern = PATTERN (insn);
-
+
tem = map->label_map[CODE_LABEL_NUMBER
(XEXP (SET_SRC (pattern), 0))];
SET_SRC (pattern) = gen_rtx (LABEL_REF, VOIDmode, tem);
@@ -1096,7 +1096,7 @@ unroll_loop (loop_end, insn_count, loop_start, end_insert_before,
else
safety_label = emit_label_after (gen_label_rtx (), copy_end);
- /* Delete all of the original loop instructions. Don't delete the
+ /* Delete all of the original loop instructions. Don't delete the
LOOP_BEG note, or the first code label in the loop. */
insn = NEXT_INSN (copy_start);
@@ -1315,7 +1315,7 @@ calculate_giv_inc (pattern, src_insn, regno)
pattern = PATTERN (src_insn);
if (GET_CODE (SET_SRC (pattern)) != PLUS)
abort ();
-
+
/* The last insn emitted is not needed, so delete it to avoid confusing
the second cse pass. This insn sets the giv unnecessarily. */
delete_insn (get_last_insn ());
@@ -1335,11 +1335,27 @@ calculate_giv_inc (pattern, src_insn, regno)
one of the LO_SUM rtx. */
if (GET_CODE (increment) == LO_SUM)
increment = XEXP (increment, 1);
+ else if (GET_CODE (increment) == IOR)
+ {
+ /* The rs6000 port loads some constants with IOR. */
+ rtx second_part = XEXP (increment, 1);
+
+ src_insn = PREV_INSN (src_insn);
+ increment = SET_SRC (PATTERN (src_insn));
+ /* Don't need the last insn anymore. */
+ delete_insn (get_last_insn ());
+
+ if (GET_CODE (second_part) != CONST_INT
+ || GET_CODE (increment) != CONST_INT)
+ abort ();
+
+ increment = GEN_INT (INTVAL (increment) | INTVAL (second_part));
+ }
if (GET_CODE (increment) != CONST_INT)
abort ();
-
- /* The insn loading the constant into a register is not longer needed,
+
+ /* The insn loading the constant into a register is no longer needed,
so delete it. */
delete_insn (get_last_insn ());
}
@@ -1422,7 +1438,7 @@ final_reg_note_copy (notes, map)
/* Copy each instruction in the loop, substituting from map as appropriate.
This is very similar to a loop in expand_inline_function. */
-
+
static void
copy_loop_body (copy_start, copy_end, map, exit_label, last_iteration,
unroll_type, start_label, loop_end, insert_before,
@@ -1456,29 +1472,29 @@ copy_loop_body (copy_start, copy_end, map, exit_label, last_iteration,
map->label_map[CODE_LABEL_NUMBER (start_label)] = start_label;
start_sequence ();
-
+
insn = copy_start;
do
{
insn = NEXT_INSN (insn);
-
+
map->orig_asm_operands_vector = 0;
-
+
switch (GET_CODE (insn))
{
case INSN:
pattern = PATTERN (insn);
copy = 0;
giv_inc = 0;
-
+
/* Check to see if this is a giv that has been combined with
- some split address givs. (Combined in the sense that
+ some split address givs. (Combined in the sense that
`combine_givs' in loop.c has put two givs in the same register.)
In this case, we must search all givs based on the same biv to
find the address givs. Then split the address givs.
Do this before splitting the giv, since that may map the
SET_DEST to a new register. */
-
+
if (GET_CODE (pattern) == SET
&& GET_CODE (SET_DEST (pattern)) == REG
&& addr_combined_regs[REGNO (SET_DEST (pattern))])
@@ -1486,10 +1502,10 @@ copy_loop_body (copy_start, copy_end, map, exit_label, last_iteration,
struct iv_class *bl;
struct induction *v, *tv;
int regno = REGNO (SET_DEST (pattern));
-
+
v = addr_combined_regs[REGNO (SET_DEST (pattern))];
bl = reg_biv_class[REGNO (v->src_reg)];
-
+
/* Although the giv_inc amount is not needed here, we must call
calculate_giv_inc here since it might try to delete the
last insn emitted. If we wait until later to call it,
@@ -1510,24 +1526,24 @@ copy_loop_body (copy_start, copy_end, map, exit_label, last_iteration,
if (tv->mult_val != v->mult_val)
this_giv_inc = (this_giv_inc / INTVAL (v->mult_val)
* INTVAL (tv->mult_val));
-
+
tv->dest_reg = plus_constant (tv->dest_reg, this_giv_inc);
*tv->location = tv->dest_reg;
-
+
if (last_iteration && unroll_type != UNROLL_COMPLETELY)
{
/* Must emit an insn to increment the split address
giv. Add in the const_adjust field in case there
was a constant eliminated from the address. */
rtx value, dest_reg;
-
+
/* tv->dest_reg will be either a bare register,
or else a register plus a constant. */
if (GET_CODE (tv->dest_reg) == REG)
dest_reg = tv->dest_reg;
else
dest_reg = XEXP (tv->dest_reg, 0);
-
+
/* Check for shared address givs, and avoid
incrementing the shared psuedo reg more than
once. */
@@ -1547,7 +1563,7 @@ copy_loop_body (copy_start, copy_end, map, exit_label, last_iteration,
emit_unrolled_add (dest_reg, XEXP (value, 0),
XEXP (value, 1));
}
-
+
/* Reset the giv to be just the register again, in case
it is used after the set we have just emitted.
We must subtract the const_adjust factor added in
@@ -1558,22 +1574,22 @@ copy_loop_body (copy_start, copy_end, map, exit_label, last_iteration,
}
}
}
-
+
/* If this is a setting of a splittable variable, then determine
how to split the variable, create a new set based on this split,
and set up the reg_map so that later uses of the variable will
use the new split variable. */
-
+
dest_reg_was_split = 0;
-
+
if (GET_CODE (pattern) == SET
&& GET_CODE (SET_DEST (pattern)) == REG
&& splittable_regs[REGNO (SET_DEST (pattern))])
{
int regno = REGNO (SET_DEST (pattern));
-
+
dest_reg_was_split = 1;
-
+
/* Compute the increment value for the giv, if it wasn't
already computed above. */
@@ -1586,7 +1602,7 @@ copy_loop_body (copy_start, copy_end, map, exit_label, last_iteration,
{
/* Completely unrolling the loop. Set the induction
variable to a known constant value. */
-
+
/* The value in splittable_regs may be an invariant
value, so we must use plus_constant here. */
splittable_regs[regno]
@@ -1613,7 +1629,7 @@ copy_loop_body (copy_start, copy_end, map, exit_label, last_iteration,
be a constant plus the original register. Except
on the last iteration, when the result has to
go back into the original iteration var register. */
-
+
/* Handle bivs which must be mapped to a new register
when split. This happens for bivs which need their
final value set before loop entry. The new register
@@ -1626,18 +1642,18 @@ copy_loop_body (copy_start, copy_end, map, exit_label, last_iteration,
giv_src_reg = reg_biv_class[regno]->biv->src_reg;
giv_dest_reg = giv_src_reg;
}
-
+
#if 0
/* If non-reduced/final-value givs were split, then
this would have to remap those givs also. See
find_splittable_regs. */
#endif
-
+
splittable_regs[regno]
= GEN_INT (INTVAL (giv_inc)
+ INTVAL (splittable_regs[regno]));
giv_inc = splittable_regs[regno];
-
+
/* Now split the induction variable by changing the dest
of this insn to a new register, and setting its
reg_map entry to point to this new register.
@@ -1675,7 +1691,7 @@ copy_loop_body (copy_start, copy_end, map, exit_label, last_iteration,
copy = emit_insn (pattern);
}
REG_NOTES (copy) = initial_reg_note_copy (REG_NOTES (insn), map);
-
+
#ifdef HAVE_cc0
/* If this insn is setting CC0, it may need to look at
the insn that uses CC0 to see what type of insn it is.
@@ -1715,7 +1731,7 @@ copy_loop_body (copy_start, copy_end, map, exit_label, last_iteration,
map->const_age_map[regno] = -1;
}
break;
-
+
case JUMP_INSN:
pattern = copy_rtx_and_substitute (PATTERN (insn), map);
copy = emit_jump_insn (pattern);
@@ -1730,14 +1746,34 @@ copy_loop_body (copy_start, copy_end, map, exit_label, last_iteration,
case to be a branch past the end of the loop, and the
original jump label case to fall_through. */
- if (! invert_exp (pattern, copy)
- || ! redirect_exp (&pattern,
- map->label_map[CODE_LABEL_NUMBER
- (JUMP_LABEL (insn))],
- exit_label, copy))
- abort ();
+ if (invert_exp (pattern, copy))
+ {
+ if (! redirect_exp (&pattern,
+ map->label_map[CODE_LABEL_NUMBER
+ (JUMP_LABEL (insn))],
+ exit_label, copy))
+ abort ();
+ }
+ else
+ {
+ rtx jmp;
+ rtx lab = gen_label_rtx ();
+ /* Can't do it by reversing the jump (probably becasue we
+ couln't reverse the conditions), so emit a new
+ jump_insn after COPY, and redirect the jump around
+ that. */
+ jmp = emit_jump_insn_after (gen_jump (exit_label), copy);
+ jmp = emit_barrier_after (jmp);
+ emit_label_after (lab, jmp);
+ LABEL_NUSES (lab) = 0;
+ if (! redirect_exp (&pattern,
+ map->label_map[CODE_LABEL_NUMBER
+ (JUMP_LABEL (insn))],
+ lab, copy))
+ abort ();
+ }
}
-
+
#ifdef HAVE_cc0
if (cc0_insn)
try_constants (cc0_insn, map);
@@ -1777,7 +1813,7 @@ copy_loop_body (copy_start, copy_end, map, exit_label, last_iteration,
JUMP_LABEL (copy) = map->label_map[CODE_LABEL_NUMBER
(JUMP_LABEL (insn))];
}
-
+
/* If this is a non-local jump, then must increase the label
use count so that the label will not be deleted when the
original jump is deleted. */
@@ -1824,7 +1860,7 @@ copy_loop_body (copy_start, copy_end, map, exit_label, last_iteration,
emit_barrier ();
}
break;
-
+
case CALL_INSN:
pattern = copy_rtx_and_substitute (PATTERN (insn), map);
copy = emit_call_insn (pattern);
@@ -1846,7 +1882,7 @@ copy_loop_body (copy_start, copy_end, map, exit_label, last_iteration,
for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
map->const_equiv_map[i] = 0;
break;
-
+
case CODE_LABEL:
/* If this is the loop start label, then we don't need to emit a
copy of this label since no one will use it. */
@@ -1857,15 +1893,15 @@ copy_loop_body (copy_start, copy_end, map, exit_label, last_iteration,
map->const_age++;
}
break;
-
+
case BARRIER:
copy = emit_barrier ();
break;
-
+
case NOTE:
/* VTOP notes are valid only before the loop exit test. If placed
anywhere else, loop may generate bad code. */
-
+
if (NOTE_LINE_NUMBER (insn) != NOTE_INSN_DELETED
&& (NOTE_LINE_NUMBER (insn) != NOTE_INSN_LOOP_VTOP
|| (last_iteration && unroll_type != UNROLL_COMPLETELY)))
@@ -1874,16 +1910,16 @@ copy_loop_body (copy_start, copy_end, map, exit_label, last_iteration,
else
copy = 0;
break;
-
+
default:
abort ();
break;
}
-
+
map->insn_map[INSN_UID (insn)] = copy;
}
while (insn != copy_end);
-
+
/* Now finish coping the REG_NOTES. */
insn = copy_start;
do
@@ -1975,7 +2011,7 @@ back_branch_in_range_p (insn, loop_start, loop_end)
if (GET_CODE (p) == JUMP_INSN)
{
target_insn = JUMP_LABEL (p);
-
+
/* Search from loop_start to insn, to see if one of them is
the target_insn. We can't use INSN_LUID comparisons here,
since insn may not have an LUID entry. */
@@ -2041,7 +2077,7 @@ fold_rtx_mult_add (mult1, mult2, add1, mode)
Returns the increment value as an rtx, simplified as much as possible,
if it can be calculated. Otherwise, returns 0. */
-rtx
+rtx
biv_total_increment (bl, loop_start, loop_end)
struct iv_class *bl;
rtx loop_start, loop_end;
@@ -2148,7 +2184,7 @@ iteration_info (iteration_var, initial_value, increment, loop_start, loop_end)
bl = reg_biv_class[REGNO (v->src_reg)];
*initial_value = fold_rtx_mult_add (v->mult_val, bl->initial_value,
v->add_val, v->mode);
-
+
/* Increment value is mult_val times the increment value of the biv. */
*increment = biv_total_increment (bl, loop_start, loop_end);
@@ -2323,7 +2359,7 @@ find_splittable_regs (unroll_type, loop_start, loop_end, end_insert_before,
|| REGNO (bl->initial_value) < FIRST_PSEUDO_REGISTER))
{
rtx tem = gen_reg_rtx (bl->biv->mode);
-
+
emit_insn_before (gen_move_insn (tem, bl->biv->src_reg),
loop_start);
@@ -2437,7 +2473,7 @@ find_splittable_givs (bl, unroll_type, loop_start, loop_end, increment,
&& (! v->always_computable
|| back_branch_in_range_p (v->insn, loop_start, loop_end)))
continue;
-
+
/* The giv increment value must be a constant. */
giv_inc = fold_rtx_mult_add (v->mult_val, increment, const0_rtx,
v->mode);
@@ -2449,7 +2485,7 @@ find_splittable_givs (bl, unroll_type, loop_start, loop_end, increment,
the loop, or else the final value of the giv must be known.
Otherwise, it is not safe to split the giv since it may not have the
proper value on loop exit. */
-
+
/* The used outside loop test will fail for DEST_ADDR givs. They are
never used outside the loop anyways, so it is always safe to split a
DEST_ADDR giv. */
@@ -2489,11 +2525,11 @@ find_splittable_givs (bl, unroll_type, loop_start, loop_end, increment,
emit_insn_before (gen_move_insn (tem, v->dest_reg), loop_start);
emit_insn_before (gen_move_insn (v->dest_reg, final_value),
loop_start);
-
+
if (loop_dump_stream)
fprintf (loop_dump_stream, "Giv %d mapped to %d for split.\n",
REGNO (v->dest_reg), REGNO (tem));
-
+
v->src_reg = tem;
}
#endif
@@ -2565,7 +2601,7 @@ find_splittable_givs (bl, unroll_type, loop_start, loop_end, increment,
v->add_val, tem, loop_start);
value = tem;
}
-
+
splittable_regs[REGNO (v->new_reg)] = value;
}
else
@@ -2585,7 +2621,7 @@ find_splittable_givs (bl, unroll_type, loop_start, loop_end, increment,
catch some of the common cases of this. Currently, I leave
the work of simplifying multiple address givs to the
following cse pass. */
-
+
/* As a special case, if we have multiple identical address givs
within a single instruction, then we do use a single psuedo
reg for both. This is necessary in case one is a match_dup
@@ -2612,13 +2648,13 @@ find_splittable_givs (bl, unroll_type, loop_start, loop_end, increment,
/* If the address giv has a constant in its new_reg value,
then this constant can be pulled out and put in value,
instead of being part of the initialization code. */
-
+
if (GET_CODE (v->new_reg) == PLUS
&& GET_CODE (XEXP (v->new_reg, 1)) == CONST_INT)
{
v->dest_reg
= plus_constant (tem, INTVAL (XEXP (v->new_reg,1)));
-
+
/* Only succeed if this will give valid addresses.
Try to validate both the first and the last
address resulting from loop unrolling, if
@@ -2645,7 +2681,7 @@ find_splittable_givs (bl, unroll_type, loop_start, loop_end, increment,
}
else
v->dest_reg = tem;
-
+
/* If the address hasn't been checked for validity yet, do so
now, and fail completely if either the first or the last
unrolled copy of the address is not a valid address. */
@@ -2662,7 +2698,7 @@ find_splittable_givs (bl, unroll_type, loop_start, loop_end, increment,
INSN_UID (v->insn));
continue;
}
-
+
/* To initialize the new register, just move the value of
new_reg into it. This is not guaranteed to give a valid
instruction on machines with complex addressing modes.
@@ -2697,7 +2733,7 @@ find_splittable_givs (bl, unroll_type, loop_start, loop_end, increment,
else
{
v->dest_reg = value;
-
+
/* Check the resulting address for validity, and fail
if the resulting address would be illegal. */
if (! memory_address_p (v->mem_mode, v->dest_reg)
@@ -2713,28 +2749,28 @@ find_splittable_givs (bl, unroll_type, loop_start, loop_end, increment,
continue;
}
}
-
+
/* Store the value of dest_reg into the insn. This sharing
will not be a problem as this insn will always be copied
later. */
-
+
*v->location = v->dest_reg;
-
+
/* If this address giv is combined with a dest reg giv, then
save the base giv's induction pointer so that we will be
able to handle this address giv properly. The base giv
itself does not have to be splittable. */
-
+
if (v->same && v->same->giv_type == DEST_REG)
addr_combined_regs[REGNO (v->same->new_reg)] = v->same;
-
+
if (GET_CODE (v->new_reg) == REG)
{
/* This giv maybe hasn't been combined with any others.
Make sure that it's giv is marked as splittable here. */
-
+
splittable_regs[REGNO (v->new_reg)] = value;
-
+
/* Make it appear to depend upon itself, so that the
giv will be properly split in the main loop above. */
if (! v->same)
@@ -2757,7 +2793,7 @@ find_splittable_givs (bl, unroll_type, loop_start, loop_end, increment,
it makes sense to reduce&split givs when possible, as this will
result in simpler instructions, and will not require that a reg
be live across loop iterations. */
-
+
splittable_regs[REGNO (v->dest_reg)] = value;
fprintf (stderr, "Giv %d at insn %d not reduced\n",
REGNO (v->dest_reg), INSN_UID (v->insn));
@@ -2765,7 +2801,7 @@ find_splittable_givs (bl, unroll_type, loop_start, loop_end, increment,
continue;
#endif
}
-
+
/* Givs are only updated once by definition. Mark it so if this is
a splittable register. Don't need to do anything for address givs
where this may not be a register. */
@@ -2774,11 +2810,11 @@ find_splittable_givs (bl, unroll_type, loop_start, loop_end, increment,
splittable_regs_updates[REGNO (v->new_reg)] = 1;
result++;
-
+
if (loop_dump_stream)
{
int regnum;
-
+
if (GET_CODE (v->dest_reg) == CONST_INT)
regnum = -1;
else if (GET_CODE (v->dest_reg) != REG)
@@ -2860,7 +2896,7 @@ reg_dead_after_loop (reg, loop_start, loop_end)
/* Try to calculate the final value of the biv, the value it will have at
the end of the loop. If we can do it, return that value. */
-
+
rtx
final_biv_value (bl, loop_start, loop_end)
struct iv_class *bl;
@@ -2882,7 +2918,7 @@ final_biv_value (bl, loop_start, loop_end)
if (loop_dump_stream)
fprintf (loop_dump_stream,
"Final biv value for %d, reversed biv.\n", bl->regno);
-
+
return const0_rtx;
}
@@ -2897,7 +2933,7 @@ final_biv_value (bl, loop_start, loop_end)
&& invariant_p (bl->initial_value))
{
increment = biv_total_increment (bl, loop_start, loop_end);
-
+
if (increment && invariant_p (increment))
{
/* Can calculate the loop exit value, emit insns after loop
@@ -2914,7 +2950,7 @@ final_biv_value (bl, loop_start, loop_end)
if (loop_dump_stream)
fprintf (loop_dump_stream,
"Final biv value for %d, calculated.\n", bl->regno);
-
+
return tem;
}
}
@@ -2964,7 +3000,7 @@ final_giv_value (v, loop_start, loop_end)
/* Try to calculate the final value as a function of the biv it depends
upon. The only exit from the loop must be the fall through at the bottom
(otherwise it may not have its final value when the loop exits). */
-
+
/* ??? Can calculate the final giv value by subtracting off the
extra biv increments times the giv's mult_val. The loop must have
only one exit for this to work, but the loop iterations does not need
@@ -2986,7 +3022,7 @@ final_giv_value (v, loop_start, loop_end)
{
/* Can calculate the loop exit value of its biv as
(loop_n_iterations * increment) + initial_value */
-
+
/* The loop exit value of the giv is then
(final_biv_value - extra increments) * mult_val + add_val.
The extra increments are any increments to the biv which
@@ -3019,11 +3055,11 @@ final_giv_value (v, loop_start, loop_end)
emit_insn_before (seq, insert_before);
}
}
-
+
/* Now calculate the giv's final value. */
emit_iv_add_mult (tem, v->mult_val, v->add_val, tem,
insert_before);
-
+
if (loop_dump_stream)
fprintf (loop_dump_stream,
"Final giv value for %d, calc from biv's value.\n",
@@ -3071,13 +3107,17 @@ loop_iterations (loop_start, loop_end)
/* First find the iteration variable. If the last insn is a conditional
branch, and the insn before tests a register value, make that the
iteration variable. */
-
+
loop_initial_value = 0;
loop_increment = 0;
loop_final_value = 0;
loop_iteration_var = 0;
- last_loop_insn = prev_nonnote_insn (loop_end);
+ /* We used to use pren_nonnote_insn here, but that fails because it might
+ accidentally get the branch for a contained loop if the branch for this
+ loop was deleted. We can only trust branches immediately before the
+ loop_end. */
+ last_loop_insn = PREV_INSN (loop_end);
comparison = get_condition_for_loop (last_loop_insn);
if (comparison == 0)
@@ -3115,35 +3155,13 @@ loop_iterations (loop_start, loop_end)
/* iteration_info already printed a message. */
return 0;
- if (increment == 0)
- {
- if (loop_dump_stream)
- fprintf (loop_dump_stream,
- "Loop unrolling: Increment value can't be calculated.\n");
- return 0;
- }
- if (GET_CODE (increment) != CONST_INT)
- {
- if (loop_dump_stream)
- fprintf (loop_dump_stream,
- "Loop unrolling: Increment value not constant.\n");
- return 0;
- }
- if (GET_CODE (initial_value) != CONST_INT)
- {
- if (loop_dump_stream)
- fprintf (loop_dump_stream,
- "Loop unrolling: Initial value not constant.\n");
- return 0;
- }
-
/* If the comparison value is an invariant register, then try to find
its value from the insns before the start of the loop. */
if (GET_CODE (comparison_value) == REG && invariant_p (comparison_value))
{
rtx insn, set;
-
+
for (insn = PREV_INSN (loop_start); insn ; insn = PREV_INSN (insn))
{
if (GET_CODE (insn) == CODE_LABEL)
@@ -3185,7 +3203,28 @@ loop_iterations (loop_start, loop_end)
loop_increment = increment;
loop_final_value = final_value;
- if (final_value == 0)
+ if (increment == 0)
+ {
+ if (loop_dump_stream)
+ fprintf (loop_dump_stream,
+ "Loop unrolling: Increment value can't be calculated.\n");
+ return 0;
+ }
+ else if (GET_CODE (increment) != CONST_INT)
+ {
+ if (loop_dump_stream)
+ fprintf (loop_dump_stream,
+ "Loop unrolling: Increment value not constant.\n");
+ return 0;
+ }
+ else if (GET_CODE (initial_value) != CONST_INT)
+ {
+ if (loop_dump_stream)
+ fprintf (loop_dump_stream,
+ "Loop unrolling: Initial value not constant.\n");
+ return 0;
+ }
+ else if (final_value == 0)
{
if (loop_dump_stream)
fprintf (loop_dump_stream,
@@ -3233,7 +3272,7 @@ loop_iterations (loop_start, loop_end)
will overflow before the loop exits), 4 infinite loop cases, and 15
immediate exit (0 or 1 iteration depending on loop type) cases.
Only try to optimize the normal cases. */
-
+
/* (compare_dir/final_larger/increment_dir)
Normal cases: (0/-1/-1), (0/1/1), (-1/-1/-1), (1/1/1)
Reverse cases: (0/-1/1), (0/1/-1), (-1/-1/1), (1/1/-1)
diff --git a/gnu/usr.bin/cc/cc_int/varasm.c b/gnu/usr.bin/cc/cc_int/varasm.c
index cd49b0c..76f4b8c 100644
--- a/gnu/usr.bin/cc/cc_int/varasm.c
+++ b/gnu/usr.bin/cc/cc_int/varasm.c
@@ -213,7 +213,7 @@ named_section (name)
{
in_named_name = name;
in_section = in_named;
-
+
#ifdef ASM_OUTPUT_SECTION_NAME
ASM_OUTPUT_SECTION_NAME (asm_out_file, name);
#else
@@ -239,7 +239,7 @@ make_function_rtl (decl)
{
if (DECL_RTL (decl) == 0)
DECL_RTL (decl) = bc_gen_rtx (name, 0, (struct bc_label *) 0);
-
+
/* Record that at least one function has been defined. */
function_defined = 1;
return;
@@ -351,7 +351,7 @@ decode_reg_name (asmspec)
/* Get rid of confusing prefixes. */
asmspec = strip_reg_name (asmspec);
-
+
/* Allow a decimal number as a "register name". */
for (i = strlen (asmspec) - 1; i >= 0; i--)
if (! (asmspec[i] >= '0' && asmspec[i] <= '9'))
@@ -1285,7 +1285,7 @@ assemble_variable (decl, top_level, at_end, dont_output_data)
finish:
#ifdef XCOFF_DEBUGGING_INFO
/* Unfortunately, the IBM assembler cannot handle stabx before the actual
- declaration. When something like ".stabx "aa:S-2",aa,133,0" is emitted
+ declaration. When something like ".stabx "aa:S-2",aa,133,0" is emitted
and `aa' hasn't been output yet, the assembler generates a stab entry with
a value of zero, in addition to creating an unnecessary external entry
for `aa'. Hence, we must postpone dbxout_symbol to here at the end. */
@@ -1358,10 +1358,9 @@ contains_pointers_p (type)
}
}
-/* Output text storage for constructor CONSTR. Returns rtx of
- storage. */
+/* Output text storage for constructor CONSTR. */
-rtx
+void
bc_output_constructor (constr)
tree constr;
{
@@ -2584,21 +2583,21 @@ output_constant_def (exp)
the label number already assigned. */
hash = const_hash (exp) % MAX_HASH_TABLE;
-
+
for (desc = const_hash_table[hash]; desc; desc = desc->next)
if (compare_constant (exp, desc))
{
found = desc->label;
break;
}
-
+
if (found == 0)
{
/* No constant equal to EXP is known to have been output.
Make a constant descriptor to enter EXP in the hash table.
Assign the label number and record it in the descriptor for
future calls to this function to find. */
-
+
/* Create a string containing the label name, in LABEL. */
ASM_GENERATE_INTERNAL_LABEL (label, "LC", const_labelno);
@@ -2613,7 +2612,7 @@ output_constant_def (exp)
/* Create a string containing the label name, in LABEL. */
ASM_GENERATE_INTERNAL_LABEL (label, "LC", const_labelno);
}
-
+
/* We have a symbol name; construct the SYMBOL_REF and the MEM. */
push_obstacks_nochange ();
@@ -2621,7 +2620,7 @@ output_constant_def (exp)
end_temporary_allocation ();
def = gen_rtx (SYMBOL_REF, Pmode, desc->label);
-
+
TREE_CST_RTL (exp)
= gen_rtx (MEM, TYPE_MODE (TREE_TYPE (exp)), def);
RTX_UNCHANGING_P (TREE_CST_RTL (exp)) = 1;
@@ -3084,8 +3083,8 @@ force_const_mem (mode, x)
push_obstacks_nochange ();
rtl_in_saveable_obstack ();
- x = gen_rtx (CONST, GET_MODE (x),
- gen_rtx (PLUS, GET_MODE (x),
+ x = gen_rtx (CONST, GET_MODE (x),
+ gen_rtx (PLUS, GET_MODE (x),
XEXP (XEXP (x, 0), 0), XEXP (XEXP (x, 0), 1)));
pop_obstacks ();
}
@@ -3382,10 +3381,11 @@ output_constant (exp, size)
return;
/* Eliminate the NON_LVALUE_EXPR_EXPR that makes a cast not be an lvalue.
- That way we get the constant (we hope) inside it. Also, strip
- off any NOP_EXPR that converts between two record or union types. */
- while ((TREE_CODE (exp) == NOP_EXPR
+ That way we get the constant (we hope) inside it. Also, strip off any
+ NOP_EXPR that converts between two record, union, or array types. */
+ while ((TREE_CODE (exp) == NOP_EXPR
&& (TREE_TYPE (exp) == TREE_TYPE (TREE_OPERAND (exp, 0))
+ || TREE_CODE (TREE_TYPE (exp)) == ARRAY_TYPE
|| TREE_CODE (TREE_TYPE (exp)) == RECORD_TYPE
|| TREE_CODE (TREE_TYPE (exp)) == UNION_TYPE
|| TREE_CODE (TREE_TYPE (exp)) == QUAL_UNION_TYPE))
@@ -3489,9 +3489,9 @@ bc_assemble_integer (exp, size)
expand_expr() using EXPAND_SUM above in the RTL case? I
hate RMS.
FIXME: Copied as is from BC-GCC1; may need work. Don't hate. -bson */
-
+
exp = fold (exp);
-
+
while (TREE_CODE (exp) == NOP_EXPR || TREE_CODE (exp) == CONVERT_EXPR)
exp = TREE_OPERAND (exp, 0);
if (TREE_CODE (exp) == INTEGER_CST)
@@ -3523,7 +3523,7 @@ bc_assemble_integer (exp, size)
}
else
abort (); /* FIXME: ditto previous. */
-
+
if (addr_part == 0)
{
if (size == 1)
diff --git a/gnu/usr.bin/cc/cc_int/version.c b/gnu/usr.bin/cc/cc_int/version.c
index a77e9ff..f37f23f 100644
--- a/gnu/usr.bin/cc/cc_int/version.c
+++ b/gnu/usr.bin/cc/cc_int/version.c
@@ -1 +1 @@
-char *version_string = "2.6.0";
+char *version_string = "2.6.3";
diff --git a/gnu/usr.bin/cc/cc_int/xcoffout.c b/gnu/usr.bin/cc/cc_int/xcoffout.c
index 42b01f9..5518cfe 100644
--- a/gnu/usr.bin/cc/cc_int/xcoffout.c
+++ b/gnu/usr.bin/cc/cc_int/xcoffout.c
@@ -187,7 +187,7 @@ stab_to_sclass (stab)
return C_GSYM;
case N_FNAME:
- UNKNOWN_STAB ("N_FNAME");
+ UNKNOWN_STAB ("N_FNAME");
abort();
case N_FUN:
@@ -199,7 +199,7 @@ stab_to_sclass (stab)
#ifdef N_MAIN
case N_MAIN:
- UNKNOWN_STAB ("N_MAIN");
+ UNKNOWN_STAB ("N_MAIN");
abort ();
#endif
@@ -207,7 +207,7 @@ stab_to_sclass (stab)
return C_RSYM;
case N_SSYM:
- UNKNOWN_STAB ("N_SSYM");
+ UNKNOWN_STAB ("N_SSYM");
abort ();
case N_RPSYM:
@@ -223,59 +223,59 @@ stab_to_sclass (stab)
return C_ENTRY;
case N_SO:
- UNKNOWN_STAB ("N_SO");
+ UNKNOWN_STAB ("N_SO");
abort ();
case N_SOL:
- UNKNOWN_STAB ("N_SOL");
+ UNKNOWN_STAB ("N_SOL");
abort ();
case N_SLINE:
- UNKNOWN_STAB ("N_SLINE");
+ UNKNOWN_STAB ("N_SLINE");
abort ();
#ifdef N_DSLINE
case N_DSLINE:
- UNKNOWN_STAB ("N_DSLINE");
+ UNKNOWN_STAB ("N_DSLINE");
abort ();
#endif
#ifdef N_BSLINE
case N_BSLINE:
- UNKNOWN_STAB ("N_BSLINE");
+ UNKNOWN_STAB ("N_BSLINE");
abort ();
#endif
#if 0
/* This has the same value as N_BSLINE. */
case N_BROWS:
- UNKNOWN_STAB ("N_BROWS");
+ UNKNOWN_STAB ("N_BROWS");
abort ();
#endif
#ifdef N_BINCL
case N_BINCL:
- UNKNOWN_STAB ("N_BINCL");
+ UNKNOWN_STAB ("N_BINCL");
abort ();
#endif
#ifdef N_EINCL
case N_EINCL:
- UNKNOWN_STAB ("N_EINCL");
+ UNKNOWN_STAB ("N_EINCL");
abort ();
#endif
#ifdef N_EXCL
case N_EXCL:
- UNKNOWN_STAB ("N_EXCL");
+ UNKNOWN_STAB ("N_EXCL");
abort ();
#endif
case N_LBRAC:
- UNKNOWN_STAB ("N_LBRAC");
+ UNKNOWN_STAB ("N_LBRAC");
abort ();
case N_RBRAC:
- UNKNOWN_STAB ("N_RBRAC");
+ UNKNOWN_STAB ("N_RBRAC");
abort ();
case N_BCOMM:
@@ -286,31 +286,31 @@ stab_to_sclass (stab)
return C_ECOML;
case N_LENG:
- UNKNOWN_STAB ("N_LENG");
+ UNKNOWN_STAB ("N_LENG");
abort ();
case N_PC:
- UNKNOWN_STAB ("N_PC");
+ UNKNOWN_STAB ("N_PC");
abort ();
#ifdef N_M2C
case N_M2C:
- UNKNOWN_STAB ("N_M2C");
+ UNKNOWN_STAB ("N_M2C");
abort ();
#endif
#ifdef N_SCOPE
case N_SCOPE:
- UNKNOWN_STAB ("N_SCOPE");
+ UNKNOWN_STAB ("N_SCOPE");
abort ();
#endif
case N_CATCH:
- UNKNOWN_STAB ("N_CATCH");
+ UNKNOWN_STAB ("N_CATCH");
abort ();
default:
- UNKNOWN_STAB ("default");
+ UNKNOWN_STAB ("default");
abort ();
}
}
@@ -437,7 +437,7 @@ xcoffout_begin_block (file, line, n)
{
tree decl = current_function_decl;
-
+
/* The IBM AIX compiler does not emit a .bb for the function level scope,
so we avoid it here also. */
if (n != 1)
diff --git a/gnu/usr.bin/cc/cccp/Makefile b/gnu/usr.bin/cc/cccp/Makefile
new file mode 100644
index 0000000..43ec78c
--- /dev/null
+++ b/gnu/usr.bin/cc/cccp/Makefile
@@ -0,0 +1,11 @@
+#
+# $Id$
+#
+
+PROG = cpp
+SRCS = cccp.c cexp.c
+BINDIR= /usr/libexec
+.PATH: ${.CURDIR}/../cc_int
+SRCS+= obstack.c version.c
+
+.include <bsd.prog.mk>
diff --git a/gnu/usr.bin/cc/cpp/Makefile b/gnu/usr.bin/cc/cpp/Makefile
index 8467da4..43ec78c 100644
--- a/gnu/usr.bin/cc/cpp/Makefile
+++ b/gnu/usr.bin/cc/cpp/Makefile
@@ -1,12 +1,11 @@
#
-# $FreeBSD$
+# $Id$
#
PROG = cpp
SRCS = cccp.c cexp.c
BINDIR= /usr/libexec
-LDDESTDIR+= -L${.CURDIR}/../cc_int/obj
-LDDESTDIR+= -L${.CURDIR}/../cc_int
-LDADD+= -lcc_int
+.PATH: ${.CURDIR}/../cc_int
+SRCS+= obstack.c version.c
.include <bsd.prog.mk>
diff --git a/gnu/usr.bin/cc/cpp/cccp.c b/gnu/usr.bin/cc/cpp/cccp.c
index 640b36b..ee8ed5a 100644
--- a/gnu/usr.bin/cc/cpp/cccp.c
+++ b/gnu/usr.bin/cc/cpp/cccp.c
@@ -93,7 +93,6 @@ typedef unsigned char U_CHAR;
/* VMS-specific definitions */
#ifdef VMS
#include <time.h>
-#include <perror.h> /* This defines sys_errlist/sys_nerr properly */
#include <descrip.h>
#define O_RDONLY 0 /* Open arg for Read/Only */
#define O_WRONLY 1 /* Open arg for Write/Only */
@@ -117,7 +116,7 @@ typedef struct { unsigned :16, :16, :16; } vms_ino_t;
#define BSTRING /* VMS/GCC supplies the bstring routines */
#endif /* __GNUC__ */
#endif /* VMS */
-
+
extern char *index ();
extern char *rindex ();
@@ -186,13 +185,22 @@ extern char *getenv ();
extern FILE *fdopen ();
extern char *version_string;
extern struct tm *localtime ();
+#ifndef VMS
+#ifndef HAVE_STRERROR
extern int sys_nerr;
-#if defined(bsd4_4) || defined(__NetBSD__)
+#if defined(bsd4_4) || defined(__NetBSD__) || defined(__FreeBSD__)
extern const char *const sys_errlist[];
#else
extern char *sys_errlist[];
#endif
+#else /* HAVE_STERRROR */
+char *strerror ();
+#endif
+#else /* VMS */
+char *strerror (int,...);
+#endif
extern int parse_escape ();
+extern HOST_WIDE_INT parse_c_expression ();
#ifndef errno
extern int errno;
@@ -276,7 +284,7 @@ static void write_output ();
static int check_macro_name ();
static int compare_defs ();
static int compare_token_lists ();
-static int eval_if_expression ();
+static HOST_WIDE_INT eval_if_expression ();
static int discard_comments ();
static int change_newlines ();
static int line_for_error ();
@@ -388,6 +396,11 @@ static int print_include_names = 0;
static int no_line_commands;
+/* Nonzero means output the text in failing conditionals,
+ inside #failed ... #endfailed. */
+
+static int output_conditionals;
+
/* dump_only means inhibit output of the preprocessed text
and instead output the definitions of all user-defined
macros in a form suitable for use as input to cccp.
@@ -407,11 +420,11 @@ static enum {dump_none, dump_only, dump_names, dump_definitions}
static int debug_output = 0;
/* Nonzero indicates special processing used by the pcp program. The
- special effects of this mode are:
-
+ special effects of this mode are:
+
Inhibit all macro expansion, except those inside #if directives.
- Process #define directives normally, and output their contents
+ Process #define directives normally, and output their contents
to the output file.
Output preconditions to pcp_outfile indicating all the relevant
@@ -591,14 +604,14 @@ static struct default_include {
automatically in Makefile.in. */
{ CROSS_INCLUDE_DIR, 0, 0 },
/* This is another place that the target system's headers might be. */
- { TOOL_INCLUDE_DIR, 0, 1 },
+ { TOOL_INCLUDE_DIR, 0, 0 },
#else /* not CROSS_COMPILE */
/* This should be /usr/local/include and should come before
the fixincludes-fixed header files. */
{ LOCAL_INCLUDE_DIR, 0, 1 },
/* This is here ahead of GCC_INCLUDE_DIR because assert.h goes here.
Likewise, behind LOCAL_INCLUDE_DIR, where glibc puts its assert.h. */
- { TOOL_INCLUDE_DIR, 0, 1 },
+ { TOOL_INCLUDE_DIR, 0, 0 },
/* This is the dir for fixincludes. Put it just before
the files that we fix. */
{ GCC_INCLUDE_DIR, 0, 0 },
@@ -650,7 +663,7 @@ static char *include_prefix;
/* Global list of strings read in from precompiled files. This list
is kept in the order the strings are read in, with new strings being
added at the end through stringlist_tailp. We use this list to output
- the strings at the end of the run.
+ the strings at the end of the run.
*/
static STRINGDEF *stringlist;
static STRINGDEF **stringlist_tailp = &stringlist;
@@ -729,7 +742,7 @@ union hashval {
};
/*
- * special extension string that can be added to the last macro argument to
+ * special extension string that can be added to the last macro argument to
* allow it to absorb the "rest" of the arguments when expanded. Ex:
* #define wow(a, b...) process (b, a, b)
* { wow (1, 2, 3); } -> { process (2, 3, 1, 2, 3); }
@@ -956,7 +969,7 @@ static U_CHAR is_space[256];
#define SKIP_WHITE_SPACE(p) do { while (is_hor_space[*p]) p++; } while (0)
#define SKIP_ALL_WHITE_SPACE(p) do { while (is_space[*p]) p++; } while (0)
-
+
static int errors = 0; /* Error counter for exit code */
/* Name of output file, for error messages. */
@@ -1123,7 +1136,12 @@ main (argc, argv)
#endif
p = argv[0] + strlen (argv[0]);
- while (p != argv[0] && p[-1] != '/') --p;
+ while (p != argv[0] && p[-1] != '/'
+#ifdef DIR_SEPARATOR
+ && p[-1] != DIR_SEPARATOR
+#endif
+ )
+ --p;
progname = p;
#ifdef VMS
@@ -1195,6 +1213,9 @@ main (argc, argv)
else
include_prefix = argv[++i];
}
+ if (!strcmp (argv[i], "-ifoutput")) {
+ output_conditionals = 1;
+ }
if (!strcmp (argv[i], "-isystem")) {
struct file_name_list *dirtmp;
@@ -1322,8 +1343,11 @@ main (argc, argv)
pedantic = 1;
pedantic_errors = 1;
} else if (!strcmp (argv[i], "-pcp")) {
- char *pcp_fname = argv[++i];
- pcp_outfile =
+ char *pcp_fname;
+ if (i + 1 == argc)
+ fatal ("Filename missing after -pcp option");
+ pcp_fname = argv[++i];
+ pcp_outfile =
((pcp_fname[0] != '-' || pcp_fname[1] != '\0')
? fopen (pcp_fname, "w")
: fdopen (dup (fileno (stdout)), "w"));
@@ -1429,6 +1453,8 @@ main (argc, argv)
/* For -MD and -MMD options, write deps on file named by next arg. */
if (!strcmp (argv[i], "-MD")
|| !strcmp (argv[i], "-MMD")) {
+ if (i + 1 == argc)
+ fatal ("Filename missing after %s option", argv[i]);
i++;
deps_file = argv[i];
deps_mode = "w";
@@ -1437,7 +1463,7 @@ main (argc, argv)
and suppress the usual output. */
deps_stream = stdout;
inhibit_output = 1;
- }
+ }
break;
case 'd':
@@ -1606,7 +1632,11 @@ main (argc, argv)
/* Some people say that CPATH should replace the standard include dirs,
but that seems pointless: it comes before them, so it overrides them
anyway. */
+#ifdef WINNT
+ p = (char *) getenv ("Include");
+#else
p = (char *) getenv ("CPATH");
+#endif
if (p != 0 && ! no_standard_includes)
path_include (p);
@@ -1647,7 +1677,7 @@ main (argc, argv)
char *q;
while (*p == ' ' || *p == '\t')
p++;
- /* Handle -D options. */
+ /* Handle -D options. */
if (p[0] == '-' && p[1] == 'D') {
q = &p[2];
while (*p && *p != ' ' && *p != '\t')
@@ -1660,7 +1690,7 @@ main (argc, argv)
while (*p == ' ' || *p == '\t')
p++;
} else if (p[0] == '-' && p[1] == 'A') {
- /* Handle -A options (assertions). */
+ /* Handle -A options (assertions). */
char *assertion;
char *past_name;
char *value;
@@ -1935,7 +1965,7 @@ main (argc, argv)
deps_target = 0;
output_file = spec;
}
-
+
deps_file = output_file;
deps_mode = "a";
}
@@ -1958,7 +1988,11 @@ main (argc, argv)
int len;
/* Discard all directory prefixes from filename. */
- if ((q = rindex (in_fname, '/')) != NULL)
+ if ((q = rindex (in_fname, '/')) != NULL
+#ifdef DIR_SEPARATOR
+ && (q = rindex (in_fname, DIR_SEPARATOR)) != NULL
+#endif
+ )
++q;
else
q = in_fname;
@@ -2175,6 +2209,33 @@ path_include (path)
}
}
+/* Return the address of the first character in S that equals C.
+ S is an array of length N, possibly containing '\0's, and followed by '\0'.
+ Return 0 if there is no such character. Assume that C itself is not '\0'.
+ If we knew we could use memchr, we could just invoke memchr (S, C, N),
+ but unfortunately memchr isn't autoconfigured yet. */
+
+static U_CHAR *
+index0 (s, c, n)
+ U_CHAR *s;
+ int c;
+ int n;
+{
+ for (;;) {
+ char *q = index (s, c);
+ if (q)
+ return (U_CHAR *) q;
+ else {
+ int l = strlen (s);
+ if (l == n)
+ return 0;
+ l++;
+ s += l;
+ n -= l;
+ }
+ }
+}
+
/* Pre-C-Preprocessor to translate ANSI trigraph idiocy in BUF
before main CCCP processing. Name `pcp' is also in honor of the
drugs the trigraph designers must have been on.
@@ -2188,11 +2249,12 @@ static void
trigraph_pcp (buf)
FILE_BUF *buf;
{
- register U_CHAR c, *fptr, *bptr, *sptr;
+ register U_CHAR c, *fptr, *bptr, *sptr, *lptr;
int len;
fptr = bptr = sptr = buf->buf;
- while ((sptr = (U_CHAR *) index (sptr, '?')) != NULL) {
+ lptr = fptr + buf->length;
+ while ((sptr = (U_CHAR *) index0 (sptr, '?', lptr - sptr)) != NULL) {
if (*++sptr != '?')
continue;
switch (*++sptr) {
@@ -2261,25 +2323,15 @@ newline_fix (bp)
U_CHAR *bp;
{
register U_CHAR *p = bp;
- register int count = 0;
/* First count the backslash-newline pairs here. */
- while (1) {
- if (p[0] == '\\') {
- if (p[1] == '\n')
- p += 2, count++;
- else if (p[1] == '\r' && p[2] == '\n')
- p += 3, count++;
- else
- break;
- } else
- break;
- }
+ while (p[0] == '\\' && p[1] == '\n')
+ p += 2;
/* What follows the backslash-newlines is not embarrassing. */
- if (count == 0 || (*p != '/' && *p != '*'))
+ if (*p != '/' && *p != '*')
return;
/* Copy all potentially embarrassing characters
@@ -2290,7 +2342,7 @@ newline_fix (bp)
*bp++ = *p++;
/* Now write the same number of pairs after the embarrassing chars. */
- while (count-- > 0) {
+ while (bp < p) {
*bp++ = '\\';
*bp++ = '\n';
}
@@ -2304,24 +2356,14 @@ name_newline_fix (bp)
U_CHAR *bp;
{
register U_CHAR *p = bp;
- register int count = 0;
/* First count the backslash-newline pairs here. */
- while (1) {
- if (p[0] == '\\') {
- if (p[1] == '\n')
- p += 2, count++;
- else if (p[1] == '\r' && p[2] == '\n')
- p += 3, count++;
- else
- break;
- } else
- break;
- }
+ while (p[0] == '\\' && p[1] == '\n')
+ p += 2;
/* What follows the backslash-newlines is not embarrassing. */
- if (count == 0 || !is_idchar[*p])
+ if (!is_idchar[*p])
return;
/* Copy all potentially embarrassing characters
@@ -2332,7 +2374,7 @@ name_newline_fix (bp)
*bp++ = *p++;
/* Now write the same number of pairs after the embarrassing chars. */
- while (count-- > 0) {
+ while (bp < p) {
*bp++ = '\\';
*bp++ = '\n';
}
@@ -2366,7 +2408,7 @@ get_lintcmd (ibp, limit, argstart, arglen, cmdlen)
if (ibp >= limit) return NULL;
linsize = limit - ibp;
-
+
/* Oh, I wish C had lexical functions... hell, I'll just open-code the set */
if ((linsize >= 10) && !strncmp (ibp, "NOTREACHED", 10)) {
*cmdlen = 10;
@@ -2495,7 +2537,7 @@ do { ip = &instack[indepth]; \
obp = op->bufp; } while (0)
if (no_output && instack[indepth].fname != 0)
- skip_if_group (&instack[indepth], 1);
+ skip_if_group (&instack[indepth], 1, NULL);
obp = op->bufp;
RECACHE;
@@ -2513,22 +2555,25 @@ do { ip = &instack[indepth]; \
switch (c) {
case '\\':
- if (ibp >= limit)
- break;
- if (*ibp == '\n') {
- /* Always merge lines ending with backslash-newline,
- even in middle of identifier. */
+ if (*ibp == '\n' && !ip->macro) {
+ /* At the top level, always merge lines ending with backslash-newline,
+ even in middle of identifier. But do not merge lines in a macro,
+ since backslash might be followed by a newline-space marker. */
++ibp;
++ip->lineno;
--obp; /* remove backslash from obuf */
break;
}
+ /* If ANSI, backslash is just another character outside a string. */
+ if (!traditional)
+ goto randomchar;
/* Otherwise, backslash suppresses specialness of following char,
so copy it here to prevent the switch from seeing it.
But first get any pending identifier processed. */
if (ident_length > 0)
goto specialchar;
- *obp++ = *ibp++;
+ if (ibp < limit)
+ *obp++ = *ibp++;
break;
case '#':
@@ -2559,7 +2604,7 @@ do { ip = &instack[indepth]; \
if (ident_length)
goto specialchar;
-
+
/* # keyword: a # must be first nonblank char on the line */
if (beg_of_line == 0)
goto randomchar;
@@ -2608,7 +2653,7 @@ do { ip = &instack[indepth]; \
/* If not generating expanded output,
what we do with ordinary text is skip it.
Discard everything until next # directive. */
- skip_if_group (&instack[indepth], 1);
+ skip_if_group (&instack[indepth], 1, 0);
RECACHE;
beg_of_line = ibp;
break;
@@ -2632,7 +2677,7 @@ do { ip = &instack[indepth]; \
/* If not generating expanded output, ignore everything until
next # directive. */
if (no_output && instack[indepth].fname)
- skip_if_group (&instack[indepth], 1);
+ skip_if_group (&instack[indepth], 1, 0);
obp = op->bufp;
RECACHE;
beg_of_line = ibp;
@@ -2790,6 +2835,9 @@ do { ip = &instack[indepth]; \
char *lintcmd = get_lintcmd (ibp, limit, &argbp, &arglen, &cmdlen);
if (lintcmd != NULL) {
+ op->bufp = obp;
+ check_expand (op, cmdlen + arglen + 14);
+ obp = op->bufp;
/* I believe it is always safe to emit this newline: */
obp[-1] = '\n';
bcopy ("#pragma lint ", (char *) obp, 13);
@@ -2804,10 +2852,12 @@ do { ip = &instack[indepth]; \
}
/* OK, now bring us back to the state we were in before we entered
- this branch. We need #line b/c the newline for the pragma
- could fuck things up. */
+ this branch. We need #line because the #pragma's newline always
+ messes up the line count. */
+ op->bufp = obp;
output_line_command (ip, op, 0, same_file);
- *(obp++) = ' '; /* just in case, if comments are copied thru */
+ check_expand (op, limit - ibp + 2);
+ obp = op->bufp;
*(obp++) = '/';
}
}
@@ -2884,9 +2934,7 @@ do { ip = &instack[indepth]; \
ibp += 2;
}
c = *ibp++;
- /* ".." terminates a preprocessing number. This is useless for C
- code but useful for preprocessing other things. */
- if (!isalnum (c) && (c != '.' || *ibp == '.') && c != '_') {
+ if (!is_idchar[c] && c != '.') {
--ibp;
break;
}
@@ -2988,7 +3036,7 @@ do { ip = &instack[indepth]; \
if (ip->lineno != op->lineno) {
op->bufp = obp;
output_line_command (ip, op, 1, same_file);
- check_expand (op, ip->length - (ip->bufp - ip->buf));
+ check_expand (op, limit - ibp);
obp = op->bufp;
}
break;
@@ -3070,7 +3118,7 @@ randomchar:
startagain:
for (hp = hashtab[MAKE_POS (hash) % HASHSIZE]; hp != NULL;
hp = hp->next) {
-
+
if (hp->length == ident_length) {
int obufp_before_macroname;
int op_lineno_before_macroname;
@@ -3078,30 +3126,30 @@ startagain:
register U_CHAR *p = hp->name;
register U_CHAR *q = obp - i;
int disabled;
-
+
if (! redo_char)
q--;
-
+
do { /* All this to avoid a strncmp () */
if (*p++ != *q++)
goto hashcollision;
} while (--i);
-
+
/* We found a use of a macro name.
see if the context shows it is a macro call. */
-
+
/* Back up over terminating character if not already done. */
if (! redo_char) {
ibp--;
obp--;
}
-
+
/* Save this as a displacement from the beginning of the output
buffer. We can not save this as a position in the output
buffer, because it may get realloc'ed by RECACHE. */
obufp_before_macroname = (obp - op->buf) - ident_length;
op_lineno_before_macroname = op->lineno;
-
+
if (hp->type == T_PCSTRING) {
pcstring_used (hp); /* Mark the definition of this key
as needed, ensuring that it
@@ -3112,10 +3160,10 @@ startagain:
/* Record whether the macro is disabled. */
disabled = hp->type == T_DISABLED;
-
+
/* This looks like a macro ref, but if the macro was disabled,
just copy its name and put in a marker if requested. */
-
+
if (disabled) {
#if 0
/* This error check caught useful cases such as
@@ -3124,7 +3172,7 @@ startagain:
if (traditional)
error ("recursive use of macro `%s'", hp->name);
#endif
-
+
if (output_marks) {
check_expand (op, limit - ibp + 2);
*obp++ = '\n';
@@ -3132,7 +3180,7 @@ startagain:
}
break;
}
-
+
/* If macro wants an arglist, verify that a '(' follows.
first skip all whitespace, copying it to the output
after the macro name. Then, if there is no '(',
@@ -3144,7 +3192,7 @@ startagain:
U_CHAR *old_obp = obp;
int old_iln = ip->lineno;
int old_oln = op->lineno;
-
+
while (1) {
/* Scan forward over whitespace, copying it to the output. */
if (ibp == limit && ip->macro != 0) {
@@ -3223,12 +3271,20 @@ startagain:
break;
}
}
-
+
/* This is now known to be a macro call.
Discard the macro name from the output,
- along with any following whitespace just copied. */
+ along with any following whitespace just copied,
+ but preserve newlines if not outputting marks since this
+ is more likely to do the right thing with line numbers. */
obp = op->buf + obufp_before_macroname;
- op->lineno = op_lineno_before_macroname;
+ if (output_marks)
+ op->lineno = op_lineno_before_macroname;
+ else {
+ int newlines = op->lineno - op_lineno_before_macroname;
+ while (0 < newlines--)
+ *obp++ = '\n';
+ }
/* Prevent accidental token-pasting with a character
before the macro call. */
@@ -3248,7 +3304,7 @@ startagain:
ip->bufp = ibp;
op->bufp = obp;
macroexpand (hp, op);
-
+
/* Reexamine input stack, since macroexpand has pushed
a new level on it. */
obp = op->bufp;
@@ -3529,8 +3585,9 @@ handle_directive (ip, op)
if (*bp == '\n') {
ip->lineno++;
copy_command = 1;
- }
- bp++;
+ bp++;
+ } else if (traditional)
+ bp++;
}
break;
@@ -3555,7 +3612,14 @@ handle_directive (ip, op)
case '<':
if (!kt->angle_brackets)
break;
- while (*bp && *bp != '>') bp++;
+ while (bp < limit && *bp != '>' && *bp != '\n') {
+ if (*bp == '\\' && bp[1] == '\n') {
+ ip->lineno++;
+ copy_command = 1;
+ bp++;
+ }
+ bp++;
+ }
break;
case '/':
@@ -3783,7 +3847,7 @@ timestamp ()
{
static struct tm *timebuf;
if (!timebuf) {
- time_t t = time (0);
+ time_t t = time ((time_t *)0);
timebuf = localtime (&t);
}
return timebuf;
@@ -3815,7 +3879,7 @@ special_symbol (hp, op)
&& hp->type != T_SPEC_DEFINED && hp->type != T_CONST)
error ("Predefined macro `%s' used inside `#if' during precompilation",
hp->name);
-
+
for (i = indepth; i >= 0; i--)
if (instack[i].fname != NULL) {
ip = &instack[i];
@@ -3925,7 +3989,8 @@ special_symbol (hp, op)
goto oops;
if (hp = lookup (ip->bufp, -1, -1)) {
if (pcp_outfile && pcp_inside_if
- && hp->value.defn->predefined)
+ && (hp->type == T_CONST
+ || (hp->type == T_MACRO && hp->value.defn->predefined)))
/* Output a precondition for this macro use. */
fprintf (pcp_outfile, "#define %s\n", hp->name);
buf = " 1 ";
@@ -4324,7 +4389,7 @@ get_filename:
/* For -M, add this file to the dependencies. */
if (print_deps > (angle_brackets || (system_include_depth > 0)))
deps_output (fname, ' ');
- }
+ }
/* Handle -H option. */
if (print_include_names) {
@@ -4347,7 +4412,7 @@ get_filename:
if (!no_precomp)
do {
sprintf (pcftry, "%s%d", fname, pcfnum++);
-
+
pcf = open (pcftry, O_RDONLY, 0666);
if (pcf != -1)
{
@@ -4370,7 +4435,7 @@ get_filename:
}
}
} while (pcf != -1 && !pcfbuf);
-
+
/* Actually process the file */
if (pcfbuf) {
pcfname = xmalloc (strlen (pcftry) + 1);
@@ -4554,7 +4619,7 @@ read_name_map (dirname)
ptr->map_to[dirlen] = '/';
strcpy (ptr->map_to + dirlen + 1, to);
free (to);
- }
+ }
ptr->map_next = map_list_ptr->map_list_map;
map_list_ptr->map_list_map = ptr;
@@ -4565,12 +4630,12 @@ read_name_map (dirname)
}
fclose (f);
}
-
+
map_list_ptr->map_list_next = map_list;
map_list = map_list_ptr;
return map_list_ptr->map_list_map;
-}
+}
/* Try to open include file FILENAME. SEARCHPTR is the directory
being tried from the include file search path. This function maps
@@ -4586,6 +4651,7 @@ open_include_file (filename, searchptr)
register char *from;
char *p, *dir;
+#if 0
if (searchptr && ! searchptr->got_name_map)
{
searchptr->name_map = read_name_map (searchptr->fname
@@ -4608,7 +4674,7 @@ open_include_file (filename, searchptr)
}
}
}
-
+#endif
/* Try to find a mapping file for the particular directory we are
looking in. Thus #include <sys/types.h> will look up sys/types.h
in /usr/include/header.gcc and look up types.h in
@@ -4637,9 +4703,11 @@ open_include_file (filename, searchptr)
dir[p - filename] = '\0';
from = p + 1;
}
+#if 0
for (map = read_name_map (dir); map; map = map->map_next)
if (! strcmp (map->map_from, from))
return open (map->map_to, O_RDONLY, 0666);
+#endif
return open (filename, O_RDONLY, 0666);
}
@@ -4803,7 +4871,7 @@ static struct import_file *import_hash_table[IMPORT_HASH_SIZE];
/* Hash a file name for import_hash_table. */
-static int
+static int
import_hash (f)
char *f;
{
@@ -4884,9 +4952,9 @@ add_import (fd, fname)
/* Load the specified precompiled header into core, and verify its
preconditions. PCF indicates the file descriptor to read, which must
- be a regular file. FNAME indicates the file name of the original
+ be a regular file. FNAME indicates the file name of the original
header. *LIMIT will be set to an address one past the end of the file.
- If the preconditions of the file are not satisfied, the buffer is
+ If the preconditions of the file are not satisfied, the buffer is
freed and we return 0. If the preconditions are satisfied, return
the address of the buffer following the preconditions. The buffer, in
this case, should never be freed because various pieces of it will
@@ -4907,7 +4975,7 @@ check_precompiled (pcf, fname, limit)
if (pcp_outfile)
return 0;
-
+
if (file_size_and_mode (pcf, &st_mode, &st_size) < 0)
return 0;
@@ -4920,11 +4988,11 @@ check_precompiled (pcf, fname, limit)
}
else
abort ();
-
+
if (length > 0 && buf[length-1] != '\n')
buf[length++] = '\n';
buf[length] = '\0';
-
+
*limit = buf + length;
/* File is in core. Check the preconditions. */
@@ -4949,29 +5017,29 @@ check_precompiled (pcf, fname, limit)
precompiled header. These are a series of #define and #undef
lines which must match the current contents of the hash
table. */
-static int
+static int
check_preconditions (prec)
char *prec;
{
MACRODEF mdef;
char *lineend;
-
+
while (*prec) {
lineend = (char *) index (prec, '\n');
-
+
if (*prec++ != '#') {
error ("Bad format encountered while reading precompiled file");
return 0;
}
if (!strncmp (prec, "define", 6)) {
HASHNODE *hp;
-
+
prec += 6;
mdef = create_definition (prec, lineend, NULL_PTR);
if (mdef.defn == 0)
abort ();
-
+
if ((hp = lookup (mdef.symnam, mdef.symlen, -1)) == NULL
|| (hp->type != T_MACRO && hp->type != T_CONST)
|| (hp->type == T_MACRO
@@ -4983,7 +5051,7 @@ check_preconditions (prec)
} else if (!strncmp (prec, "undef", 5)) {
char *name;
int len;
-
+
prec += 5;
while (is_hor_space[(U_CHAR) *prec])
prec++;
@@ -4991,7 +5059,7 @@ check_preconditions (prec)
while (is_idchar[(U_CHAR) *prec])
prec++;
len = prec - name;
-
+
if (lookup (name, len, -1))
return 0;
} else {
@@ -5023,14 +5091,14 @@ pcfinclude (buf, limit, name, op)
nstrings = (nstrings << 8) | *cp++;
nstrings = (nstrings << 8) | *cp++;
nstrings = (nstrings << 8) | *cp++;
-
+
/* Looping over each string... */
while (nstrings--) {
U_CHAR *string_start;
U_CHAR *endofthiskey;
STRINGDEF *str;
int nkeys;
-
+
/* Each string starts with a STRINGDEF structure (str), followed */
/* by the text of the string (string_start) */
@@ -5042,14 +5110,14 @@ pcfinclude (buf, limit, name, op)
Do not include stddef.h--it will fail! */
if ((HOST_WIDE_INT) cp & 3)
cp += 4 - ((HOST_WIDE_INT) cp & 3);
-
+
/* Now get the string. */
str = (STRINGDEF *) cp;
string_start = cp += sizeof (STRINGDEF);
-
+
for (; *cp; cp++) /* skip the string */
;
-
+
/* We need to macro expand the string here to ensure that the
proper definition environment is in place. If it were only
expanded when we find out it is needed, macros necessary for
@@ -5061,11 +5129,11 @@ pcfinclude (buf, limit, name, op)
str->writeflag = 0;
str->filename = name;
str->output_mark = outbuf.bufp - outbuf.buf;
-
+
str->chain = 0;
*stringlist_tailp = str;
stringlist_tailp = &str->chain;
-
+
/* Next comes a fourbyte number indicating the number of keys */
/* for this string. */
nkeys = *cp++;
@@ -5081,19 +5149,19 @@ pcfinclude (buf, limit, name, op)
for (; nkeys--; free (tmpbuf.buf), cp = endofthiskey + 1) {
KEYDEF *kp = (KEYDEF *) cp;
HASHNODE *hp;
-
+
/* It starts with a KEYDEF structure */
cp += sizeof (KEYDEF);
-
+
/* Find the end of the key. At the end of this for loop we
advance CP to the start of the next key using this variable. */
endofthiskey = cp + strlen (cp);
kp->str = str;
-
+
/* Expand the key, and enter it into the hash table. */
tmpbuf = expand_to_temp_buffer (cp, endofthiskey, 0, 0);
tmpbuf.bufp = tmpbuf.buf;
-
+
while (is_hor_space[*tmpbuf.bufp])
tmpbuf.bufp++;
if (!is_idstart[*tmpbuf.bufp]
@@ -5101,7 +5169,7 @@ pcfinclude (buf, limit, name, op)
str->writeflag = 1;
continue;
}
-
+
hp = lookup (tmpbuf.bufp, -1, -1);
if (hp == NULL) {
kp->chain = 0;
@@ -5116,7 +5184,7 @@ pcfinclude (buf, limit, name, op)
}
}
/* This output_line_command serves to switch us back to the current
- input file in case some of these strings get output (which will
+ input file in case some of these strings get output (which will
result in line commands for the header file being output). */
output_line_command (&instack[indepth], op, 0, enter_file);
}
@@ -5128,7 +5196,7 @@ pcstring_used (hp)
HASHNODE *hp;
{
KEYDEF *kp;
-
+
for (kp = hp->value.keydef; kp; kp = kp->chain)
kp->str->writeflag = 1;
delete_macro (hp);
@@ -5149,16 +5217,16 @@ write_output ()
/* next_string_loc, in which case we print a series of strings, or */
/* it is less than next_string_loc, in which case we write some of */
/* the buffer. */
- cur_buf_loc = outbuf.buf;
+ cur_buf_loc = outbuf.buf;
next_string = stringlist;
-
+
while (cur_buf_loc < outbuf.bufp || next_string) {
if (next_string
&& cur_buf_loc - outbuf.buf == next_string->output_mark) {
if (next_string->writeflag) {
len = 4 * strlen (next_string->filename) + 32;
while (len > line_command_len)
- line_command = xrealloc (line_command,
+ line_command = xrealloc (line_command,
line_command_len *= 2);
sprintf (line_command, "\n# %d ", next_string->lineno);
strcpy (quote_string (line_command + strlen (line_command),
@@ -5166,15 +5234,15 @@ write_output ()
"\n");
safe_write (fileno (stdout), line_command, strlen (line_command));
safe_write (fileno (stdout), next_string->contents, next_string->len);
- }
+ }
next_string = next_string->chain;
}
else {
len = (next_string
- ? (next_string->output_mark
+ ? (next_string->output_mark
- (cur_buf_loc - outbuf.buf))
: outbuf.bufp - cur_buf_loc);
-
+
safe_write (fileno (stdout), cur_buf_loc, len);
cur_buf_loc += len;
}
@@ -5230,7 +5298,7 @@ struct arglist {
char rest_args;
};
-/* Create a DEFINITION node from a #define directive. Arguments are
+/* Create a DEFINITION node from a #define directive. Arguments are
as for do_define. */
static MACRODEF
create_definition (buf, limit, op)
@@ -5286,7 +5354,7 @@ create_definition (buf, limit, op)
if (!is_idstart[*bp])
pedwarn ("invalid character in macro parameter name");
-
+
/* Find the end of the arg name. */
while (is_idchar[*bp]) {
bp++;
@@ -5360,9 +5428,31 @@ create_definition (buf, limit, op)
} else {
/* Simple expansion or empty definition. */
- /* Skip spaces and tabs if any. */
- while (bp < limit && (*bp == ' ' || *bp == '\t'))
- ++bp;
+ if (bp < limit)
+ {
+ switch (*bp)
+ {
+ case '\t': case ' ': case '\r':
+ /* Skip spaces and tabs. */
+ while (++bp < limit && (*bp == ' ' || *bp == '\t' || *bp == '\r'))
+ continue;
+ break;
+
+ case '!': case '"': case '#': case '%': case '&': case '\'':
+ case ')': case '*': case '+': case ',': case '-': case '.':
+ case '/': case ':': case ';': case '<': case '=': case '>':
+ case '?': case '[': case '\\': case ']': case '^': case '{':
+ case '|': case '}': case '~':
+ warning ("missing white space after `#define %.*s'",
+ sym_length, symname);
+ break;
+
+ default:
+ pedwarn ("missing white space after `#define %.*s'",
+ sym_length, symname);
+ break;
+ }
+ }
/* Now everything from bp before limit is the definition. */
defn = collect_expansion (bp, limit, -1, NULL_PTR);
defn->args.argnames = (U_CHAR *) "";
@@ -5383,7 +5473,7 @@ create_definition (buf, limit, op)
mdef.defn = 0;
return mdef;
}
-
+
/* Process a #define command.
BUF points to the contents of the #define command, as a contiguous string.
LIMIT points to the first character past the end of the definition.
@@ -5570,7 +5660,7 @@ comp_def_part (first, beg1, len1, beg2, len2, last)
in that list, or -1 for a macro name that wants no argument list.
MACRONAME is the macro name itself (so we can avoid recursive expansion)
and NAMELEN is its length in characters.
-
+
Note that comments and backslash-newlines have already been deleted
from the argument. */
@@ -5659,16 +5749,8 @@ collect_expansion (buf, end, nargs, arglist)
expected_delimiter = c;
break;
- /* Special hack: if a \# is written in the #define
- include a # in the definition. This is useless for C code
- but useful for preprocessing other things. */
-
case '\\':
- /* \# quotes a # even outside of strings. */
- if (p < limit && *p == '#' && !expected_delimiter) {
- exp_p--;
- *exp_p++ = *p++;
- } else if (p < limit && expected_delimiter) {
+ if (p < limit && expected_delimiter) {
/* In a string, backslash goes through
and makes next char ordinary. */
*exp_p++ = *p++;
@@ -6503,7 +6585,7 @@ do_once ()
if (ip != NULL) {
struct file_name_list *new;
-
+
new = (struct file_name_list *) xmalloc (sizeof (struct file_name_list));
new->next = dont_repeat_files;
dont_repeat_files = new;
@@ -6537,7 +6619,7 @@ do_ident (buf, limit)
free (trybuf.buf);
/* Output directive name. */
- check_expand (op, 8);
+ check_expand (op, 7);
bcopy ("#ident ", (char *) op->bufp, 7);
op->bufp += 7;
@@ -6578,7 +6660,7 @@ do_pragma (buf, limit)
fname = p + 1;
if (p = (U_CHAR *) index (fname, '\"'))
*p = '\0';
-
+
for (ptr = all_include_files; ptr; ptr = ptr->next) {
inc_fname = (U_CHAR *) rindex (ptr->fname, '/');
inc_fname = inc_fname ? inc_fname + 1 : (U_CHAR *) ptr->fname;
@@ -6647,11 +6729,11 @@ do_if (buf, limit, op, keyword)
FILE_BUF *op;
struct directive *keyword;
{
- int value;
+ HOST_WIDE_INT value;
FILE_BUF *ip = &instack[indepth];
value = eval_if_expression (buf, limit - buf);
- conditional_skip (ip, value == 0, T_IF, NULL_PTR);
+ conditional_skip (ip, value == 0, T_IF, NULL_PTR, op);
return 0;
}
@@ -6666,7 +6748,7 @@ do_elif (buf, limit, op, keyword)
FILE_BUF *op;
struct directive *keyword;
{
- int value;
+ HOST_WIDE_INT value;
FILE_BUF *ip = &instack[indepth];
if (if_stack == instack[indepth].if_stack) {
@@ -6685,11 +6767,11 @@ do_elif (buf, limit, op, keyword)
}
if (if_stack->if_succeeded)
- skip_if_group (ip, 0);
+ skip_if_group (ip, 0, op);
else {
value = eval_if_expression (buf, limit - buf);
if (value == 0)
- skip_if_group (ip, 0);
+ skip_if_group (ip, 0, op);
else {
++if_stack->if_succeeded; /* continue processing input */
output_line_command (ip, op, 1, same_file);
@@ -6702,16 +6784,16 @@ do_elif (buf, limit, op, keyword)
* evaluate a #if expression in BUF, of length LENGTH,
* then parse the result as a C expression and return the value as an int.
*/
-static int
+static HOST_WIDE_INT
eval_if_expression (buf, length)
U_CHAR *buf;
int length;
{
FILE_BUF temp_obuf;
HASHNODE *save_defined;
- int value;
+ HOST_WIDE_INT value;
- save_defined = install ("defined", -1, T_SPEC_DEFINED, 0, 0, -1);
+ save_defined = install ("defined", -1, T_SPEC_DEFINED, 0, NULL_PTR, -1);
pcp_inside_if = 1;
temp_obuf = expand_to_temp_buffer (buf, buf + length, 0, 1);
pcp_inside_if = 0;
@@ -6738,7 +6820,7 @@ do_xifdef (buf, limit, op, keyword)
{
int skip;
FILE_BUF *ip = &instack[indepth];
- U_CHAR *end;
+ U_CHAR *end;
int start_of_file = 0;
U_CHAR *control_macro = 0;
@@ -6790,7 +6872,9 @@ do_xifdef (buf, limit, op, keyword)
if (pcp_outfile) {
/* Output a precondition for this macro. */
- if (hp && hp->value.defn->predefined)
+ if (hp &&
+ (hp->type == T_CONST
+ || (hp->type == T_MACRO && hp->value.defn->predefined)))
fprintf (pcp_outfile, "#define %s\n", hp->name);
else {
U_CHAR *cp = buf;
@@ -6808,8 +6892,8 @@ do_xifdef (buf, limit, op, keyword)
control_macro[end - buf] = 0;
}
}
-
- conditional_skip (ip, skip, T_IF, control_macro);
+
+ conditional_skip (ip, skip, T_IF, control_macro, op);
return 0;
}
@@ -6819,11 +6903,12 @@ do_xifdef (buf, limit, op, keyword)
Otherwise, CONTROL_MACRO is 0. */
static void
-conditional_skip (ip, skip, type, control_macro)
+conditional_skip (ip, skip, type, control_macro, op)
FILE_BUF *ip;
int skip;
enum node_type type;
U_CHAR *control_macro;
+ FILE_BUF *op;
{
IF_STACK_FRAME *temp;
@@ -6837,7 +6922,7 @@ conditional_skip (ip, skip, type, control_macro)
if_stack->type = type;
if (skip != 0) {
- skip_if_group (ip, 0);
+ skip_if_group (ip, 0, op);
return;
} else {
++if_stack->if_succeeded;
@@ -6851,9 +6936,10 @@ conditional_skip (ip, skip, type, control_macro)
* If ANY is nonzero, return at next directive of any sort.
*/
static void
-skip_if_group (ip, any)
+skip_if_group (ip, any, op)
FILE_BUF *ip;
int any;
+ FILE_BUF *op;
{
register U_CHAR *bp = ip->bufp, *cp;
register U_CHAR *endb = ip->buf + ip->length;
@@ -6862,6 +6948,25 @@ skip_if_group (ip, any)
U_CHAR *beg_of_line = bp;
register int ident_length;
U_CHAR *ident, *after_ident;
+ /* Save info about where the group starts. */
+ U_CHAR *beg_of_group = bp;
+ int beg_lineno = ip->lineno;
+
+ if (output_conditionals && op != 0) {
+ char *ptr = "#failed\n";
+ int len = strlen (ptr);
+
+ if (op->bufp > op->buf && op->bufp[-1] != '\n')
+ {
+ *op->bufp++ = '\n';
+ op->lineno++;
+ }
+ check_expand (op, len);
+ bcopy (ptr, (char *) op->bufp, len);
+ op->bufp += len;
+ op->lineno++;
+ output_line_command (ip, op, 1, 0);
+ }
while (bp < endb) {
switch (*bp++) {
@@ -7013,7 +7118,7 @@ skip_if_group (ip, any)
&& strncmp (cp, kt->name, kt->length) == 0) {
/* If we are asked to return on next directive, do so now. */
if (any)
- return;
+ goto done;
switch (kt->type) {
case T_IF:
@@ -7036,7 +7141,7 @@ skip_if_group (ip, any)
break;
}
else if (if_stack == save_if_stack)
- return; /* found what we came for */
+ goto done; /* found what we came for */
if (kt->type != T_ENDIF) {
if (if_stack->type == T_ELSE)
@@ -7058,10 +7163,32 @@ skip_if_group (ip, any)
pedwarn ("invalid preprocessor directive name");
}
}
+
ip->bufp = bp;
/* after this returns, rescan will exit because ip->bufp
now points to the end of the buffer.
rescan is responsible for the error message also. */
+
+ done:
+ if (output_conditionals && op != 0) {
+ char *ptr = "#endfailed\n";
+ int len = strlen (ptr);
+
+ if (op->bufp > op->buf && op->bufp[-1] != '\n')
+ {
+ *op->bufp++ = '\n';
+ op->lineno++;
+ }
+ check_expand (op, beg_of_line - beg_of_group);
+ bcopy ((char *) beg_of_group, (char *) op->bufp,
+ beg_of_line - beg_of_group);
+ op->bufp += beg_of_line - beg_of_group;
+ op->lineno += ip->lineno - beg_lineno;
+ check_expand (op, len);
+ bcopy (ptr, (char *) op->bufp, len);
+ op->bufp += len;
+ op->lineno++;
+ }
}
/*
@@ -7104,7 +7231,7 @@ do_else (buf, limit, op, keyword)
}
if (if_stack->if_succeeded)
- skip_if_group (ip, 0);
+ skip_if_group (ip, 0, op);
else {
++if_stack->if_succeeded; /* continue processing input */
output_line_command (ip, op, 1, same_file);
@@ -7431,7 +7558,7 @@ quote_string (dst, src)
*dst++ = '\\';
*dst++ = c;
break;
-
+
case '\0':
*dst++ = '\"';
*dst = '\0';
@@ -7578,7 +7705,7 @@ output_line_command (ip, op, conditional, file_change)
`stringified_length' is the length the argument would have
if stringified.
`use_count' is the number of times this macro arg is substituted
- into the macro. If the actual use count exceeds 10,
+ into the macro. If the actual use count exceeds 10,
the value stored is 10.
`free1' and `free2', if nonzero, point to blocks to be freed
when the macro argument data is no longer needed. */
@@ -7625,7 +7752,7 @@ macroexpand (hp, op)
/* recorded as a precondition. */
if (pcp_inside_if && pcp_outfile && defn->predefined)
dump_single_macro (hp, pcp_outfile);
-
+
nargs = defn->nargs;
if (nargs >= 0) {
@@ -8224,7 +8351,7 @@ macarg1 (start, limit, depthptr, newlines, comments, rest_args)
/* Discard comments and duplicate newlines
in the string of length LENGTH at START,
except inside of string constants.
- The string is copied into itself with its beginning staying fixed.
+ The string is copied into itself with its beginning staying fixed.
NEWLINES is the number of newlines that must be duplicated.
We assume that that much extra space is available past the end
@@ -8384,6 +8511,39 @@ change_newlines (start, length)
}
/*
+ * my_strerror - return the descriptive text associated with an `errno' code.
+ */
+
+char *
+my_strerror (errnum)
+ int errnum;
+{
+ char *result;
+
+#ifndef VMS
+#ifndef HAVE_STRERROR
+ result = (char *) ((errnum < sys_nerr) ? sys_errlist[errnum] : 0);
+#else
+ result = strerror (errnum);
+#endif
+#else /* VMS */
+ /* VAXCRTL's strerror() takes an optional second argument, which only
+ matters when the first argument is EVMSERR. However, it's simplest
+ just to pass it unconditionally. `vaxc$errno' is declared in
+ <errno.h>, and maintained by the library in parallel with `errno'.
+ We assume that caller's `errnum' either matches the last setting of
+ `errno' by the library or else does not have the value `EVMSERR'. */
+
+ result = strerror (errnum, vaxc$errno);
+#endif
+
+ if (!result)
+ result = "undocumented I/O error";
+
+ return result;
+}
+
+/*
* error - print error message and increment count of errors.
*/
@@ -8430,10 +8590,7 @@ error_from_errno (name)
if (ip != NULL)
fprintf (stderr, "%s:%d: ", ip->nominal_fname, ip->lineno);
- if (errno < sys_nerr)
- fprintf (stderr, "%s: %s\n", name, sys_errlist[errno]);
- else
- fprintf (stderr, "%s: undocumented I/O error\n", name);
+ fprintf (stderr, "%s: %s\n", name, my_strerror (errno));
errors++;
}
@@ -8877,16 +9034,18 @@ dump_single_macro (hp, of)
concat = 0;
for (ap = defn->pattern; ap != NULL; ap = ap->next) {
dump_defn_1 (defn->expansion, offset, ap->nchars, of);
- if (ap->nchars != 0)
- concat = 0;
offset += ap->nchars;
- if (ap->stringify)
- fprintf (of, " #");
- if (ap->raw_before && !concat)
- fprintf (of, " ## ");
- concat = 0;
+ if (!traditional) {
+ if (ap->nchars != 0)
+ concat = 0;
+ if (ap->stringify)
+ fprintf (of, " #");
+ if (ap->raw_before && !concat)
+ fprintf (of, " ## ");
+ concat = 0;
+ }
dump_arg_n (defn, ap->argno, of);
- if (ap->raw_after) {
+ if (!traditional && ap->raw_after) {
fprintf (of, " ## ");
concat = 1;
}
@@ -8915,7 +9074,7 @@ dump_all_macros ()
/* Output to OF a substring of a macro definition.
BASE is the beginning of the definition.
Output characters START thru LENGTH.
- Discard newlines outside of strings, thus
+ Unless traditional, discard newlines outside of strings, thus
converting funny-space markers to ordinary spaces. */
static void
@@ -8928,16 +9087,21 @@ dump_defn_1 (base, start, length, of)
U_CHAR *p = base + start;
U_CHAR *limit = base + start + length;
- while (p < limit) {
- if (*p != '\n')
- putc (*p, of);
- else if (*p == '\"' || *p =='\'') {
- U_CHAR *p1 = skip_quoted_string (p, limit, 0, NULL_PTR,
- NULL_PTR, NULL_PTR);
- fwrite (p, p1 - p, 1, of);
- p = p1 - 1;
+ if (traditional)
+ fwrite (p, sizeof (*p), length, of);
+ else {
+ while (p < limit) {
+ if (*p == '\"' || *p =='\'') {
+ U_CHAR *p1 = skip_quoted_string (p, limit, 0, NULL_PTR,
+ NULL_PTR, NULL_PTR);
+ fwrite (p, sizeof (*p), p1 - p, of);
+ p = p1;
+ } else {
+ if (*p != '\n')
+ putc (*p, of);
+ p++;
+ }
}
- p++;
}
}
@@ -9012,29 +9176,29 @@ initialize_builtins (inp, outp)
FILE_BUF *inp;
FILE_BUF *outp;
{
- install ("__LINE__", -1, T_SPECLINE, 0, 0, -1);
- install ("__DATE__", -1, T_DATE, 0, 0, -1);
- install ("__FILE__", -1, T_FILE, 0, 0, -1);
- install ("__BASE_FILE__", -1, T_BASE_FILE, 0, 0, -1);
- install ("__INCLUDE_LEVEL__", -1, T_INCLUDE_LEVEL, 0, 0, -1);
- install ("__VERSION__", -1, T_VERSION, 0, 0, -1);
+ install ("__LINE__", -1, T_SPECLINE, 0, NULL_PTR, -1);
+ install ("__DATE__", -1, T_DATE, 0, NULL_PTR, -1);
+ install ("__FILE__", -1, T_FILE, 0, NULL_PTR, -1);
+ install ("__BASE_FILE__", -1, T_BASE_FILE, 0, NULL_PTR, -1);
+ install ("__INCLUDE_LEVEL__", -1, T_INCLUDE_LEVEL, 0, NULL_PTR, -1);
+ install ("__VERSION__", -1, T_VERSION, 0, NULL_PTR, -1);
#ifndef NO_BUILTIN_SIZE_TYPE
- install ("__SIZE_TYPE__", -1, T_SIZE_TYPE, 0, 0, -1);
+ install ("__SIZE_TYPE__", -1, T_SIZE_TYPE, 0, NULL_PTR, -1);
#endif
#ifndef NO_BUILTIN_PTRDIFF_TYPE
- install ("__PTRDIFF_TYPE__ ", -1, T_PTRDIFF_TYPE, 0, 0, -1);
+ install ("__PTRDIFF_TYPE__ ", -1, T_PTRDIFF_TYPE, 0, NULL_PTR, -1);
#endif
- install ("__WCHAR_TYPE__", -1, T_WCHAR_TYPE, 0, 0, -1);
- install ("__USER_LABEL_PREFIX__", -1, T_USER_LABEL_PREFIX_TYPE, 0, 0, -1);
- install ("__REGISTER_PREFIX__", -1, T_REGISTER_PREFIX_TYPE, 0, 0, -1);
- install ("__TIME__", -1, T_TIME, 0, 0, -1);
+ install ("__WCHAR_TYPE__", -1, T_WCHAR_TYPE, 0, NULL_PTR, -1);
+ install ("__USER_LABEL_PREFIX__",-1,T_USER_LABEL_PREFIX_TYPE,0,NULL_PTR, -1);
+ install ("__REGISTER_PREFIX__", -1, T_REGISTER_PREFIX_TYPE, 0, NULL_PTR, -1);
+ install ("__TIME__", -1, T_TIME, 0, NULL_PTR, -1);
if (!traditional)
- install ("__STDC__", -1, T_CONST, STDC_VALUE, 0, -1);
+ install ("__STDC__", -1, T_CONST, STDC_VALUE, NULL_PTR, -1);
if (objc)
- install ("__OBJC__", -1, T_CONST, 1, 0, -1);
+ install ("__OBJC__", -1, T_CONST, 1, NULL_PTR, -1);
/* This is supplied using a -D by the compiler driver
so that it is present only when truly compiling with GNU C. */
-/* install ("__GNUC__", -1, T_CONST, 2, 0, -1); */
+/* install ("__GNUC__", -1, T_CONST, 2, NULL_PTR, -1); */
if (debug_output)
{
@@ -9119,6 +9283,12 @@ make_definition (str, op)
}
while (is_idchar[*++p])
;
+ if (*p == '(') {
+ while (is_idchar[*++p] || *p == ',' || is_hor_space[*p])
+ ;
+ if (*p++ != ')')
+ p = str; /* Error */
+ }
if (*p == 0) {
buf = (U_CHAR *) alloca (p - buf + 4);
strcpy ((char *)buf, str);
@@ -9137,7 +9307,18 @@ make_definition (str, op)
p++;
q = &buf[p - str];
while (*p) {
- if (*p == '\\' && p[1] == '\n')
+ if (*p == '\"' || *p == '\'') {
+ int unterminated = 0;
+ U_CHAR *p1 = skip_quoted_string (p, p + strlen (p), 0,
+ NULL_PTR, NULL_PTR, &unterminated);
+ if (unterminated)
+ return;
+ while (p != p1)
+ if (*p == '\\' && p[1] == '\n')
+ p += 2;
+ else
+ *q++ = *p++;
+ } else if (*p == '\\' && p[1] == '\n')
p += 2;
/* Change newline chars into newline-markers. */
else if (*p == '\n')
@@ -9151,7 +9332,7 @@ make_definition (str, op)
}
*q = 0;
}
-
+
ip = &instack[++indepth];
ip->nominal_fname = ip->fname = "*Initialization*";
@@ -9167,7 +9348,7 @@ make_definition (str, op)
;
/* Pass NULL instead of OP, since this is a "predefined" macro. */
- do_define (buf, buf + strlen (buf), NULL, kt);
+ do_define (buf, buf + strlen (buf), NULL_PTR, kt);
--indepth;
}
@@ -9236,7 +9417,7 @@ make_assertion (option, str)
error ("malformed option `%s %s'", option, str);
return;
}
-
+
ip = &instack[++indepth];
ip->nominal_fname = ip->fname = "*Initialization*";
@@ -9392,10 +9573,7 @@ perror_with_name (name)
char *name;
{
fprintf (stderr, "%s: ", progname);
- if (errno < sys_nerr)
- fprintf (stderr, "%s: %s\n", name, sys_errlist[errno]);
- else
- fprintf (stderr, "%s: undocumented I/O error\n", name);
+ fprintf (stderr, "%s: %s\n", name, my_strerror (errno));
errors++;
}
@@ -9517,7 +9695,7 @@ output_dots (fd, depth)
depth--;
}
}
-
+
#ifdef VMS
@@ -9568,11 +9746,11 @@ hack_vms_include_specification (fname)
/* We are trying to do a number of things here. First of all, we are
trying to hammer the filenames into a standard format, such that later
processing can handle them.
-
+
If the file name contains something like [dir.], then it recognizes this
as a root, and strips the ".]". Later processing will add whatever is
needed to get things working properly.
-
+
If no device is specified, then the first directory name is taken to be
a device name (or a rooted logical). */
@@ -9772,7 +9950,7 @@ fopen (fname, type)
return fopen (fname, type, "mbc=16");
}
-static int
+static int
open (fname, flags, prot)
char *fname;
int flags;
diff --git a/gnu/usr.bin/cc/cpp/cexp.c b/gnu/usr.bin/cc/cpp/cexp.c
index d1471aa..04d86e5 100644
--- a/gnu/usr.bin/cc/cpp/cexp.c
+++ b/gnu/usr.bin/cc/cpp/cexp.c
@@ -55,13 +55,27 @@ struct arglist {
#endif
#endif
+/* Find the largest host integer type and set its size and type. */
+
+#ifndef HOST_BITS_PER_WIDE_INT
+
+#if HOST_BITS_PER_LONG > HOST_BITS_PER_INT
+#define HOST_BITS_PER_WIDE_INT HOST_BITS_PER_LONG
+#define HOST_WIDE_INT long
+#else
+#define HOST_BITS_PER_WIDE_INT HOST_BITS_PER_INT
+#define HOST_WIDE_INT int
+#endif
+
+#endif
+
#ifndef NULL_PTR
#define NULL_PTR ((GENERIC_PTR)0)
#endif
int yylex ();
void yyerror ();
-int expression_value;
+HOST_WIDE_INT expression_value;
static jmp_buf parse_return_error;
@@ -119,7 +133,7 @@ static void integer_overflow ();
static long left_shift ();
static long right_shift ();
-#line 127 "cexp.y"
+#line 141 "cexp.y"
typedef union {
struct constant {long value; int unsignedp;} integer;
struct name {U_CHAR *address; int length;} name;
@@ -218,10 +232,10 @@ static const short yyrhs[] = { 35,
#if YYDEBUG != 0
static const short yyrline[] = { 0,
- 159, 164, 165, 172, 177, 180, 182, 185, 189, 191,
- 196, 201, 213, 228, 239, 246, 253, 259, 265, 268,
- 271, 277, 283, 289, 295, 298, 301, 304, 307, 310,
- 313, 315, 317, 322, 324, 337
+ 173, 178, 179, 186, 191, 194, 196, 199, 203, 205,
+ 210, 215, 227, 242, 253, 260, 267, 273, 279, 282,
+ 285, 291, 297, 303, 309, 312, 315, 318, 321, 324,
+ 327, 329, 331, 336, 338, 351
};
static const char * const yytname[] = { "$","error","$illegal.","INT","CHAR",
@@ -805,59 +819,59 @@ yyreduce:
switch (yyn) {
case 1:
-#line 160 "cexp.y"
+#line 174 "cexp.y"
{ expression_value = yyvsp[0].integer.value; ;
break;}
case 3:
-#line 166 "cexp.y"
+#line 180 "cexp.y"
{ if (pedantic)
pedwarn ("comma operator in operand of `#if'");
yyval.integer = yyvsp[0].integer; ;
break;}
case 4:
-#line 173 "cexp.y"
+#line 187 "cexp.y"
{ yyval.integer.value = - yyvsp[0].integer.value;
if ((yyval.integer.value & yyvsp[0].integer.value) < 0 && ! yyvsp[0].integer.unsignedp)
integer_overflow ();
yyval.integer.unsignedp = yyvsp[0].integer.unsignedp; ;
break;}
case 5:
-#line 178 "cexp.y"
+#line 192 "cexp.y"
{ yyval.integer.value = ! yyvsp[0].integer.value;
yyval.integer.unsignedp = 0; ;
break;}
case 6:
-#line 181 "cexp.y"
+#line 195 "cexp.y"
{ yyval.integer = yyvsp[0].integer; ;
break;}
case 7:
-#line 183 "cexp.y"
+#line 197 "cexp.y"
{ yyval.integer.value = ~ yyvsp[0].integer.value;
yyval.integer.unsignedp = yyvsp[0].integer.unsignedp; ;
break;}
case 8:
-#line 186 "cexp.y"
+#line 200 "cexp.y"
{ yyval.integer.value = check_assertion (yyvsp[0].name.address, yyvsp[0].name.length,
0, NULL_PTR);
yyval.integer.unsignedp = 0; ;
break;}
case 9:
-#line 190 "cexp.y"
+#line 204 "cexp.y"
{ keyword_parsing = 1; ;
break;}
case 10:
-#line 192 "cexp.y"
+#line 206 "cexp.y"
{ yyval.integer.value = check_assertion (yyvsp[-4].name.address, yyvsp[-4].name.length,
1, yyvsp[-1].keywords);
keyword_parsing = 0;
yyval.integer.unsignedp = 0; ;
break;}
case 11:
-#line 197 "cexp.y"
+#line 211 "cexp.y"
{ yyval.integer = yyvsp[-1].integer; ;
break;}
case 12:
-#line 202 "cexp.y"
+#line 216 "cexp.y"
{ yyval.integer.unsignedp = yyvsp[-2].integer.unsignedp || yyvsp[0].integer.unsignedp;
if (yyval.integer.unsignedp)
yyval.integer.value = (unsigned long) yyvsp[-2].integer.value * yyvsp[0].integer.value;
@@ -871,7 +885,7 @@ case 12:
} ;
break;}
case 13:
-#line 214 "cexp.y"
+#line 228 "cexp.y"
{ if (yyvsp[0].integer.value == 0)
{
error ("division by zero in #if");
@@ -888,7 +902,7 @@ case 13:
} ;
break;}
case 14:
-#line 229 "cexp.y"
+#line 243 "cexp.y"
{ if (yyvsp[0].integer.value == 0)
{
error ("division by zero in #if");
@@ -901,7 +915,7 @@ case 14:
yyval.integer.value = yyvsp[-2].integer.value % yyvsp[0].integer.value; ;
break;}
case 15:
-#line 240 "cexp.y"
+#line 254 "cexp.y"
{ yyval.integer.value = yyvsp[-2].integer.value + yyvsp[0].integer.value;
yyval.integer.unsignedp = yyvsp[-2].integer.unsignedp || yyvsp[0].integer.unsignedp;
if (! yyval.integer.unsignedp
@@ -910,7 +924,7 @@ case 15:
integer_overflow (); ;
break;}
case 16:
-#line 247 "cexp.y"
+#line 261 "cexp.y"
{ yyval.integer.value = yyvsp[-2].integer.value - yyvsp[0].integer.value;
yyval.integer.unsignedp = yyvsp[-2].integer.unsignedp || yyvsp[0].integer.unsignedp;
if (! yyval.integer.unsignedp
@@ -919,7 +933,7 @@ case 16:
integer_overflow (); ;
break;}
case 17:
-#line 254 "cexp.y"
+#line 268 "cexp.y"
{ yyval.integer.unsignedp = yyvsp[-2].integer.unsignedp;
if (yyvsp[0].integer.value < 0 && ! yyvsp[0].integer.unsignedp)
yyval.integer.value = right_shift (&yyvsp[-2].integer, -yyvsp[0].integer.value);
@@ -927,7 +941,7 @@ case 17:
yyval.integer.value = left_shift (&yyvsp[-2].integer, yyvsp[0].integer.value); ;
break;}
case 18:
-#line 260 "cexp.y"
+#line 274 "cexp.y"
{ yyval.integer.unsignedp = yyvsp[-2].integer.unsignedp;
if (yyvsp[0].integer.value < 0 && ! yyvsp[0].integer.unsignedp)
yyval.integer.value = left_shift (&yyvsp[-2].integer, -yyvsp[0].integer.value);
@@ -935,17 +949,17 @@ case 18:
yyval.integer.value = right_shift (&yyvsp[-2].integer, yyvsp[0].integer.value); ;
break;}
case 19:
-#line 266 "cexp.y"
+#line 280 "cexp.y"
{ yyval.integer.value = (yyvsp[-2].integer.value == yyvsp[0].integer.value);
yyval.integer.unsignedp = 0; ;
break;}
case 20:
-#line 269 "cexp.y"
+#line 283 "cexp.y"
{ yyval.integer.value = (yyvsp[-2].integer.value != yyvsp[0].integer.value);
yyval.integer.unsignedp = 0; ;
break;}
case 21:
-#line 272 "cexp.y"
+#line 286 "cexp.y"
{ yyval.integer.unsignedp = 0;
if (yyvsp[-2].integer.unsignedp || yyvsp[0].integer.unsignedp)
yyval.integer.value = (unsigned long) yyvsp[-2].integer.value <= yyvsp[0].integer.value;
@@ -953,7 +967,7 @@ case 21:
yyval.integer.value = yyvsp[-2].integer.value <= yyvsp[0].integer.value; ;
break;}
case 22:
-#line 278 "cexp.y"
+#line 292 "cexp.y"
{ yyval.integer.unsignedp = 0;
if (yyvsp[-2].integer.unsignedp || yyvsp[0].integer.unsignedp)
yyval.integer.value = (unsigned long) yyvsp[-2].integer.value >= yyvsp[0].integer.value;
@@ -961,7 +975,7 @@ case 22:
yyval.integer.value = yyvsp[-2].integer.value >= yyvsp[0].integer.value; ;
break;}
case 23:
-#line 284 "cexp.y"
+#line 298 "cexp.y"
{ yyval.integer.unsignedp = 0;
if (yyvsp[-2].integer.unsignedp || yyvsp[0].integer.unsignedp)
yyval.integer.value = (unsigned long) yyvsp[-2].integer.value < yyvsp[0].integer.value;
@@ -969,7 +983,7 @@ case 23:
yyval.integer.value = yyvsp[-2].integer.value < yyvsp[0].integer.value; ;
break;}
case 24:
-#line 290 "cexp.y"
+#line 304 "cexp.y"
{ yyval.integer.unsignedp = 0;
if (yyvsp[-2].integer.unsignedp || yyvsp[0].integer.unsignedp)
yyval.integer.value = (unsigned long) yyvsp[-2].integer.value > yyvsp[0].integer.value;
@@ -977,54 +991,54 @@ case 24:
yyval.integer.value = yyvsp[-2].integer.value > yyvsp[0].integer.value; ;
break;}
case 25:
-#line 296 "cexp.y"
+#line 310 "cexp.y"
{ yyval.integer.value = yyvsp[-2].integer.value & yyvsp[0].integer.value;
yyval.integer.unsignedp = yyvsp[-2].integer.unsignedp || yyvsp[0].integer.unsignedp; ;
break;}
case 26:
-#line 299 "cexp.y"
+#line 313 "cexp.y"
{ yyval.integer.value = yyvsp[-2].integer.value ^ yyvsp[0].integer.value;
yyval.integer.unsignedp = yyvsp[-2].integer.unsignedp || yyvsp[0].integer.unsignedp; ;
break;}
case 27:
-#line 302 "cexp.y"
+#line 316 "cexp.y"
{ yyval.integer.value = yyvsp[-2].integer.value | yyvsp[0].integer.value;
yyval.integer.unsignedp = yyvsp[-2].integer.unsignedp || yyvsp[0].integer.unsignedp; ;
break;}
case 28:
-#line 305 "cexp.y"
+#line 319 "cexp.y"
{ yyval.integer.value = (yyvsp[-2].integer.value && yyvsp[0].integer.value);
yyval.integer.unsignedp = 0; ;
break;}
case 29:
-#line 308 "cexp.y"
+#line 322 "cexp.y"
{ yyval.integer.value = (yyvsp[-2].integer.value || yyvsp[0].integer.value);
yyval.integer.unsignedp = 0; ;
break;}
case 30:
-#line 311 "cexp.y"
+#line 325 "cexp.y"
{ yyval.integer.value = yyvsp[-4].integer.value ? yyvsp[-2].integer.value : yyvsp[0].integer.value;
yyval.integer.unsignedp = yyvsp[-2].integer.unsignedp || yyvsp[0].integer.unsignedp; ;
break;}
case 31:
-#line 314 "cexp.y"
+#line 328 "cexp.y"
{ yyval.integer = yylval.integer; ;
break;}
case 32:
-#line 316 "cexp.y"
+#line 330 "cexp.y"
{ yyval.integer = yylval.integer; ;
break;}
case 33:
-#line 318 "cexp.y"
+#line 332 "cexp.y"
{ yyval.integer.value = 0;
yyval.integer.unsignedp = 0; ;
break;}
case 34:
-#line 323 "cexp.y"
+#line 337 "cexp.y"
{ yyval.keywords = 0; ;
break;}
case 35:
-#line 325 "cexp.y"
+#line 339 "cexp.y"
{ struct arglist *temp;
yyval.keywords = (struct arglist *) xmalloc (sizeof (struct arglist));
yyval.keywords->next = yyvsp[-2].keywords;
@@ -1039,7 +1053,7 @@ case 35:
temp->next->length = 1; ;
break;}
case 36:
-#line 338 "cexp.y"
+#line 352 "cexp.y"
{ yyval.keywords = (struct arglist *) xmalloc (sizeof (struct arglist));
yyval.keywords->name = yyvsp[-1].name.address;
yyval.keywords->length = yyvsp[-1].name.length;
@@ -1243,7 +1257,7 @@ yyerrhandle:
yystate = yyn;
goto yynewstate;
}
-#line 343 "cexp.y"
+#line 357 "cexp.y"
/* During parsing of a C expression, the pointer to the next character
@@ -1405,14 +1419,14 @@ yylex ()
switch (c) {
case 0:
return 0;
-
+
case ' ':
case '\t':
case '\r':
case '\n':
lexptr++;
goto retry;
-
+
case 'L':
/* Capital L may start a wide-string or wide-character constant. */
if (lexptr[1] == '\'')
@@ -1550,7 +1564,7 @@ yylex ()
/* This is always a signed type. */
yylval.integer.unsignedp = 0;
-
+
return CHAR;
/* some of these chars are invalid in constant expressions;
@@ -1608,7 +1622,7 @@ yylex ()
if (c >= '0' && c <= '9' && !keyword_parsing) {
/* It's a number */
for (namelen = 0;
- c = tokstart[namelen], is_idchar[c] || c == '.';
+ c = tokstart[namelen], is_idchar[c] || c == '.';
namelen++)
;
return parse_number (namelen);
@@ -1634,7 +1648,7 @@ yylex ()
for (namelen = 0; is_idchar[tokstart[namelen]]; namelen++)
;
}
-
+
lexptr += namelen;
yylval.name.address = tokstart;
yylval.name.length = namelen;
@@ -1687,7 +1701,7 @@ parse_escape (string_ptr)
case 0:
(*string_ptr)--;
return 0;
-
+
case '0':
case '1':
case '2':
@@ -1809,12 +1823,12 @@ right_shift (a, b)
/* We do not support C comments. They should be removed before
this function is called. */
-int
+HOST_WIDE_INT
parse_c_expression (string)
char *string;
{
lexptr = string;
-
+
if (lexptr == 0 || *lexptr == 0) {
error ("empty #if expression");
return 0; /* don't include the #if group */
@@ -1858,7 +1872,7 @@ main ()
if (buf[n] == EOF)
break;
buf[n] = '\0';
- printf ("parser returned %d\n", parse_c_expression (buf));
+ printf ("parser returned %ld\n", parse_c_expression (buf));
}
return 0;
diff --git a/gnu/usr.bin/cc/cpp/cpp.1 b/gnu/usr.bin/cc/cpp/cpp.1
index 54c4dfb..a58fb20 100644
--- a/gnu/usr.bin/cc/cpp/cpp.1
+++ b/gnu/usr.bin/cc/cpp/cpp.1
@@ -1 +1,674 @@
-.so man1/cccp.1
+.\" Copyright (c) 1991, 1992, 1993 Free Software Foundation \-*-Text-*-
+.\" See section COPYING for conditions for redistribution
+.TH cpp 1 "30, April 1993" "FreeBSD" "GNU Tools"
+.SH NAME
+cpp \- Compiler Preprocessor.
+.SH SYNOPSIS
+.hy 0
+.na
+.TP
+.B cpp
+.RB "[\|" \-$ "\|]"
+.RB "[\|" \-A \c
+.I predicate\c
+.RB [ (\c
+.I value\c
+.BR ) ]\|]
+.RB "[\|" \-C "\|]"
+.RB "[\|" \-D \c
+.I name\c
+.RB [ =\c
+.I definition\c
+\&]\|]
+.RB "[\|" \-dD "\|]"
+.RB "[\|" \-dM "\|]"
+.RB "[\|" "\-I\ "\c
+.I directory\c
+\&\|]
+.RB "[\|" \-H "\|]"
+.RB "[\|" \-I\- "\|]"
+.RB "[\|" "\-imacros\ "\c
+.I file\c
+\&\|]
+.RB "[\|" "\-include\ "\c
+.I file\c
+\&\|]
+.RB "[\|" "\-idirafter\ "\c
+.I dir\c
+\&\|]
+.RB "[\|" "\-iprefix\ "\c
+.I prefix\c
+\&\|]
+.RB "[\|" "\-iwithprefix\ "\c
+.I dir\c
+\&\|]
+.RB "[\|" \-lang\-c "\|]"
+.RB "[\|" \-lang\-c++ "\|]"
+.RB "[\|" \-lang\-objc "\|]"
+.RB "[\|" \-lang\-objc++ "\|]"
+.RB "[\|" \-lint "\|]"
+.RB "[\|" \-M\ [ \-MG "\|]]"
+.RB "[\|" \-MM\ [ \-MG "\|]]"
+.RB "[\|" \-MD\ \c
+.I file\ \c
+\&\|]
+.RB "[\|" \-MMD\ \c
+.I file\ \c
+\&\|]
+.RB "[\|" \-nostdinc "\|]"
+.RB "[\|" \-nostdinc++ "\|]"
+.RB "[\|" \-P "\|]"
+.RB "[\|" \-pedantic "\|]"
+.RB "[\|" \-pedantic\-errors "\|]"
+.RB "[\|" \-traditional "\|]"
+.RB "[\|" \-trigraphs "\|]"
+.RB "[\|" \-U \c
+.I name\c
+\&\|]
+.RB "[\|" \-undef "\|]"
+.RB "[\|" \-Wtrigraphs "\|]"
+.RB "[\|" \-Wcomment "\|]"
+.RB "[\|" \-Wall "\|]"
+.RB "[\|" \-Wtraditional "\|]"
+.br
+.RB "[\|" \c
+.I infile\c
+.RB | \- "\|]"
+.RB "[\|" \c
+.I outfile\c
+.RB | \- "\|]"
+.ad b
+.hy 1
+.SH DESCRIPTION
+The C preprocessor is a \c
+.I macro processor\c
+\& that is used automatically by
+the C compiler to transform your program before actual compilation. It is
+called a macro processor because it allows you to define \c
+.I macros\c
+\&,
+which are brief abbreviations for longer constructs.
+
+The C preprocessor provides four separate facilities that you can use as
+you see fit:
+.TP
+\(bu
+Inclusion of header files. These are files of declarations that can be
+substituted into your program.
+.TP
+\(bu
+Macro expansion. You can define \c
+.I macros\c
+\&, which are abbreviations
+for arbitrary fragments of C code, and then the C preprocessor will
+replace the macros with their definitions throughout the program.
+.TP
+\(bu
+Conditional compilation. Using special preprocessor commands, you
+can include or exclude parts of the program according to various
+conditions.
+.TP
+\(bu
+Line control. If you use a program to combine or rearrange source files into
+an intermediate file which is then compiled, you can use line control
+to inform the compiler of where each source line originally came from.
+.PP
+C preprocessors vary in some details. For a full explanation of the
+GNU C preprocessor, see the
+.B info
+file `\|\c
+.B cpp.info\c
+\&\|', or the manual
+.I The C Preprocessor\c
+\&. Both of these are built from the same documentation source file, `\|\c
+.B cpp.texinfo\c
+\&\|'. The GNU C
+preprocessor provides a superset of the features of ANSI Standard C.
+
+ANSI Standard C requires the rejection of many harmless constructs commonly
+used by today's C programs. Such incompatibility would be inconvenient for
+users, so the GNU C preprocessor is configured to accept these constructs
+by default. Strictly speaking, to get ANSI Standard C, you must use the
+options `\|\c
+.B \-trigraphs\c
+\&\|', `\|\c
+.B \-undef\c
+\&\|' and `\|\c
+.B \-pedantic\c
+\&\|', but in
+practice the consequences of having strict ANSI Standard C make it
+undesirable to do this.
+
+Most often when you use the C preprocessor you will not have to invoke it
+explicitly: the C compiler will do so automatically. However, the
+preprocessor is sometimes useful individually.
+
+The C preprocessor expects two file names as arguments, \c
+.I infile\c
+\& and
+\c
+.I outfile\c
+\&. The preprocessor reads \c
+.I infile\c
+\& together with any other
+files it specifies with `\|\c
+.B #include\c
+\&\|'. All the output generated by the
+combined input files is written in \c
+.I outfile\c
+\&.
+
+Either \c
+.I infile\c
+\& or \c
+.I outfile\c
+\& may be `\|\c
+.B \-\c
+\&\|', which as \c
+.I infile\c
+\&
+means to read from standard input and as \c
+.I outfile\c
+\& means to write to
+standard output. Also, if \c
+.I outfile\c
+\& or both file names are omitted,
+the standard output and standard input are used for the omitted file names.
+.SH OPTIONS
+Here is a table of command options accepted by the C preprocessor.
+These options can also be given when compiling a C program; they are
+passed along automatically to the preprocessor when it is invoked by
+the compiler.
+.TP
+.B \-P
+Inhibit generation of `\|\c
+.B #\c
+\&\|'-lines with line-number information in
+the output from the preprocessor. This might be
+useful when running the preprocessor on something that is not C code
+and will be sent to a program which might be confused by the
+`\|\c
+.B #\c
+\&\|'-lines.
+.TP
+.B \-C
+Do not discard comments: pass them through to the output file.
+Comments appearing in arguments of a macro call will be copied to the
+output before the expansion of the macro call.
+.TP
+.B \-traditional
+Try to imitate the behavior of old-fashioned C, as opposed to ANSI C.
+.TP
+.B \-trigraphs
+Process ANSI standard trigraph sequences. These are three-character
+sequences, all starting with `\|\c
+.B ??\c
+\&\|', that are defined by ANSI C to
+stand for single characters. For example, `\|\c
+.B ??/\c
+\&\|' stands for
+`\|\c
+.BR "\e" "\|',"
+so `\|\c
+.B '??/n'\c
+\&\|' is a character constant for a newline.
+Strictly speaking, the GNU C preprocessor does not support all
+programs in ANSI Standard C unless `\|\c
+.B \-trigraphs\c
+\&\|' is used, but if
+you ever notice the difference it will be with relief.
+
+You don't want to know any more about trigraphs.
+.TP
+.B \-pedantic
+Issue warnings required by the ANSI C standard in certain cases such
+as when text other than a comment follows `\|\c
+.B #else\c
+\&\|' or `\|\c
+.B #endif\c
+\&\|'.
+.TP
+.B \-pedantic\-errors
+Like `\|\c
+.B \-pedantic\c
+\&\|', except that errors are produced rather than
+warnings.
+.TP
+.B \-Wtrigraphs
+Warn if any trigraphs are encountered (assuming they are enabled).
+.TP
+.B \-Wcomment
+.TP
+.B \-Wcomments
+Warn whenever a comment-start sequence `\|\c
+.B /*\c
+\&\|' appears in a comment.
+(Both forms have the same effect).
+.TP
+.B \-Wall
+Requests both `\|\c
+.B \-Wtrigraphs\c
+\&\|' and `\|\c
+.B \-Wcomment\c
+\&\|' (but not
+`\|\c
+.B \-Wtraditional\c
+\&\|').
+.TP
+.B \-Wtraditional
+Warn about certain constructs that behave differently in traditional and
+ANSI C.
+.TP
+.BI "\-I " directory\c
+\&
+Add the directory \c
+.I directory\c
+\& to the end of the list of
+directories to be searched for header files.
+This can be used to override a system header file, substituting your
+own version, since these directories are searched before the system
+header file directories. If you use more than one `\|\c
+.B \-I\c
+\&\|' option,
+the directories are scanned in left-to-right order; the standard
+system directories come after.
+.TP
+.B \-I\-
+Any directories specified with `\|\c
+.B \-I\c
+\&\|' options before the `\|\c
+.B \-I\-\c
+\&\|'
+option are searched only for the case of `\|\c
+.B #include "\c
+.I file\c
+\&"\c
+\&\|';
+they are not searched for `\|\c
+.B #include <\c
+.I file\c
+\&>\c
+\&\|'.
+
+If additional directories are specified with `\|\c
+.B \-I\c
+\&\|' options after
+the `\|\c
+.B \-I\-\c
+\&\|', these directories are searched for all `\|\c
+.B #include\c
+\&\|'
+directives.
+
+In addition, the `\|\c
+.B \-I\-\c
+\&\|' option inhibits the use of the current
+directory as the first search directory for `\|\c
+.B #include "\c
+.I file\c
+\&"\c
+\&\|'.
+Therefore, the current directory is searched only if it is requested
+explicitly with `\|\c
+.B \-I.\c
+\&\|'. Specifying both `\|\c
+.B \-I\-\c
+\&\|' and `\|\c
+.B \-I.\c
+\&\|'
+allows you to control precisely which directories are searched before
+the current one and which are searched after.
+.TP
+.B \-nostdinc
+Do not search the standard system directories for header files.
+Only the directories you have specified with `\|\c
+.B \-I\c
+\&\|' options
+(and the current directory, if appropriate) are searched.
+.TP
+.B \-nostdinc++
+Do not search for header files in the C++ specific standard
+directories, but do still search the other standard directories.
+(This option is used when building libg++.)
+.TP
+.BI "\-D " "name"\c
+\&
+Predefine \c
+.I name\c
+\& as a macro, with definition `\|\c
+.B 1\c
+\&\|'.
+.TP
+.BI "\-D " "name" = definition
+\&
+Predefine \c
+.I name\c
+\& as a macro, with definition \c
+.I definition\c
+\&.
+There are no restrictions on the contents of \c
+.I definition\c
+\&, but if
+you are invoking the preprocessor from a shell or shell-like program
+you may need to use the shell's quoting syntax to protect characters
+such as spaces that have a meaning in the shell syntax. If you use more than
+one `\|\c
+.B \-D\c
+\&\|' for the same
+.I name\c
+\&, the rightmost definition takes effect.
+.TP
+.BI "\-U " "name"\c
+\&
+Do not predefine \c
+.I name\c
+\&. If both `\|\c
+.B \-U\c
+\&\|' and `\|\c
+.B \-D\c
+\&\|' are
+specified for one name, the `\|\c
+.B \-U\c
+\&\|' beats the `\|\c
+.B \-D\c
+\&\|' and the name
+is not predefined.
+.TP
+.B \-undef
+Do not predefine any nonstandard macros.
+.TP
+.BI "\-A " "name(" value )
+Assert (in the same way as the \c
+.B #assert\c
+\& command)
+the predicate \c
+.I name\c
+\& with tokenlist \c
+.I value\c
+\&. Remember to escape or quote the parentheses on
+shell command lines.
+
+You can use `\|\c
+.B \-A-\c
+\&\|' to disable all predefined assertions; it also
+undefines all predefined macros.
+.TP
+.B \-dM
+Instead of outputting the result of preprocessing, output a list of
+`\|\c
+.B #define\c
+\&\|' commands for all the macros defined during the
+execution of the preprocessor, including predefined macros. This gives
+you a way of finding out what is predefined in your version of the
+preprocessor; assuming you have no file `\|\c
+.B foo.h\c
+\&\|', the command
+.sp
+.br
+touch\ foo.h;\ cpp\ \-dM\ foo.h
+.br
+.sp
+will show the values of any predefined macros.
+.TP
+.B \-dD
+Like `\|\c
+.B \-dM\c
+\&\|' except in two respects: it does \c
+.I not\c
+\& include the
+predefined macros, and it outputs \c
+.I both\c
+\& the `\|\c
+.B #define\c
+\&\|'
+commands and the result of preprocessing. Both kinds of output go to
+the standard output file.
+.PP
+.TP
+.BR \-M\ [ \-MG ]
+Instead of outputting the result of preprocessing, output a rule
+suitable for \c
+.B make\c
+\& describing the dependencies of the main
+source file. The preprocessor outputs one \c
+.B make\c
+\& rule containing
+the object file name for that source file, a colon, and the names of
+all the included files. If there are many included files then the
+rule is split into several lines using `\|\c
+.B \\\\\c
+\&\|'-newline.
+
+`\|\c
+.B \-MG\c
+\&\|' says to treat missing header files as generated files and assume \c
+they live in the same directory as the source file. It must be specified \c
+in addition to `\|\c
+.B \-M\c
+\&\|'.
+
+This feature is used in automatic updating of makefiles.
+.TP
+.BR \-MM\ [ \-MG ]
+Like `\|\c
+.B \-M\c
+\&\|' but mention only the files included with `\|\c
+.B #include
+"\c
+.I file\c
+\&"\c
+\&\|'. System header files included with `\|\c
+.B #include
+<\c
+.I file\c
+\&>\c
+\&\|' are omitted.
+.TP
+.BI \-MD\ file
+Like `\|\c
+.B \-M\c
+\&\|' but the dependency information is written to `\|\c
+.I file\c
+\&\|'. This is in addition to compiling the file as
+specified\(em\&`\|\c
+.B \-MD\c
+\&\|' does not inhibit ordinary compilation the way
+`\|\c
+.B \-M\c
+\&\|' does.
+
+When invoking gcc, do not specify the `\|\c
+.I file\c
+\&\|' argument. Gcc will create file names made by replacing `\|\c
+.B .c\c
+\&\|' with `\|\c
+.B .d\c
+\&\|' at the end of the input file names.
+
+In Mach, you can use the utility \c
+.B md\c
+\& to merge multiple files
+into a single dependency file suitable for using with the `\|\c
+.B make\c
+\&\|'
+command.
+.TP
+.BI \-MMD\ file
+Like `\|\c
+.B \-MD\c
+\&\|' except mention only user header files, not system
+header files.
+.TP
+.B \-H
+Print the name of each header file used, in addition to other normal
+activities.
+.TP
+.BI "\-imacros " "file"\c
+\&
+Process \c
+.I file\c
+\& as input, discarding the resulting output, before
+processing the regular input file. Because the output generated from
+\c
+.I file\c
+\& is discarded, the only effect of `\|\c
+.B \-imacros \c
+.I file\c
+\&\c
+\&\|' is to
+make the macros defined in \c
+.I file\c
+\& available for use in the main
+input. The preprocessor evaluates any `\|\c
+.B \-D\c
+\&\|' and `\|\c
+.B \-U\c
+\&\|' options
+on the command line before processing `\|\c
+.B \-imacros \c
+.I file\c
+\&\|' \c
+\&.
+.TP
+.BI "\-include " "file"
+Process
+.I file
+as input, and include all the resulting output,
+before processing the regular input file.
+.TP
+.BI "-idirafter " "dir"\c
+\&
+Add the directory \c
+.I dir\c
+\& to the second include path. The directories
+on the second include path are searched when a header file is not found
+in any of the directories in the main include path (the one that
+`\|\c
+.B \-I\c
+\&\|' adds to).
+.TP
+.BI "-iprefix " "prefix"\c
+\&
+Specify \c
+.I prefix\c
+\& as the prefix for subsequent `\|\c
+.B \-iwithprefix\c
+\&\|'
+options.
+.TP
+.BI "-iwithprefix " "dir"\c
+\&
+Add a directory to the second include path. The directory's name is
+made by concatenating \c
+.I prefix\c
+\& and \c
+.I dir\c
+\&, where \c
+.I prefix\c
+\&
+was specified previously with `\|\c
+.B \-iprefix\c
+\&\|'.
+.TP
+.B \-lang-c
+.TP
+.B \-lang-c++
+.TP
+.B \-lang-objc
+.TP
+.B \-lang-objc++
+Specify the source language. `\|\c
+.B \-lang-c++\c
+\&\|' makes the preprocessor
+handle C++ comment syntax, and includes extra default include
+directories for C++, and `\|\c
+.B \-lang-objc\c
+\&\|' enables the Objective C
+`\|\c
+.B #import\c
+\&\|' directive. `\|\c
+.B \-lang-c\c
+\&\|' explicitly turns off both of
+these extensions, and `\|\c
+.B \-lang-objc++\c
+\&\|' enables both.
+
+These options are generated by the compiler driver \c
+.B gcc\c
+\&, but not
+passed from the `\|\c
+.B gcc\c
+\&\|' command line.
+.TP
+.B \-lint
+Look for commands to the program checker \c
+.B lint\c
+\& embedded in
+comments, and emit them preceded by `\|\c
+.B #pragma lint\c
+\&\|'. For example,
+the comment `\|\c
+.B /* NOTREACHED */\c
+\&\|' becomes `\|\c
+.B #pragma lint
+NOTREACHED\c
+\&\|'.
+
+This option is available only when you call \c
+.B cpp\c
+\& directly;
+\c
+.B gcc\c
+\& will not pass it from its command line.
+.TP
+.B \-$
+Forbid the use of `\|\c
+.B $\c
+\&\|' in identifiers. This is required for ANSI
+conformance. \c
+.B gcc\c
+\& automatically supplies this option to the
+preprocessor if you specify `\|\c
+.B \-ansi\c
+\&\|', but \c
+.B gcc\c
+\& doesn't
+recognize the `\|\c
+.B \-$\c
+\&\|' option itself\(em\&to use it without the other
+effects of `\|\c
+.B \-ansi\c
+\&\|', you must call the preprocessor directly.
+.SH "SEE ALSO"
+.RB "`\|" Cpp "\|'"
+entry in
+.B info\c
+\&;
+.I The C Preprocessor\c
+, Richard M. Stallman.
+.br
+.BR gcc "(" 1 ");"
+.RB "`\|" Gcc "\|'"
+entry in
+.B info\c
+\&;
+.I
+Using and Porting GNU CC (for version 2.0)\c
+, Richard M. Stallman.
+.SH COPYING
+Copyright (c) 1991, 1992, 1993 Free Software Foundation, Inc.
+.PP
+Permission is granted to make and distribute verbatim copies of
+this manual provided the copyright notice and this permission notice
+are preserved on all copies.
+.PP
+Permission is granted to copy and distribute modified versions of this
+manual under the conditions for verbatim copying, provided that the
+entire resulting derived work is distributed under the terms of a
+permission notice identical to this one.
+.PP
+Permission is granted to copy and distribute translations of this
+manual into another language, under the above conditions for modified
+versions, except that this permission notice may be included in
+translations approved by the Free Software Foundation instead of in
+the original English.
diff --git a/gnu/usr.bin/cc/doc/Makefile b/gnu/usr.bin/cc/doc/Makefile
new file mode 100644
index 0000000..10ed396
--- /dev/null
+++ b/gnu/usr.bin/cc/doc/Makefile
@@ -0,0 +1,8 @@
+INFO = gcc cpp reno gxxint
+
+gcc.info: gcc.texi invoke.texi install.texi extend.texi rtl.texi md.texi \
+ tm.texi
+
+reno.info: reno.texi templates.texi gpcompare.texi
+
+.include <bsd.info.mk>
diff --git a/gnu/usr.bin/cc/doc/cpp.texi b/gnu/usr.bin/cc/doc/cpp.texi
new file mode 100644
index 0000000..b1b19dc
--- /dev/null
+++ b/gnu/usr.bin/cc/doc/cpp.texi
@@ -0,0 +1,2807 @@
+\input texinfo
+@setfilename cpp.info
+@settitle The C Preprocessor
+
+@ignore
+@ifinfo
+@format
+START-INFO-DIR-ENTRY
+* Cpp: (cpp). The C preprocessor.
+END-INFO-DIR-ENTRY
+@end format
+@end ifinfo
+@end ignore
+
+@c @smallbook
+@c @cropmarks
+@c @finalout
+@setchapternewpage odd
+@ifinfo
+This file documents the GNU C Preprocessor.
+
+Copyright 1987, 1989, 1991, 1992, 1993, 1994 Free Software Foundation, Inc.
+
+Permission is granted to make and distribute verbatim copies of
+this manual provided the copyright notice and this permission notice
+are preserved on all copies.
+
+@ignore
+Permission is granted to process this file through Tex and print the
+results, provided the printed document carries copying permission
+notice identical to this one except for the removal of this paragraph
+(this paragraph not being relevant to the printed manual).
+
+@end ignore
+Permission is granted to copy and distribute modified versions of this
+manual under the conditions for verbatim copying, provided also that
+the entire resulting derived work is distributed under the terms of a
+permission notice identical to this one.
+
+Permission is granted to copy and distribute translations of this manual
+into another language, under the above conditions for modified versions.
+@end ifinfo
+
+@titlepage
+@c @finalout
+@title The C Preprocessor
+@subtitle Last revised July 1992
+@subtitle for GCC version 2
+@author Richard M. Stallman
+@page
+@vskip 2pc
+This booklet is eventually intended to form the first chapter of a GNU
+C Language manual.
+
+@vskip 0pt plus 1filll
+Copyright @copyright{} 1987, 1989, 1991, 1992, 1994 Free Software
+Foundation, Inc.
+
+Permission is granted to make and distribute verbatim copies of
+this manual provided the copyright notice and this permission notice
+are preserved on all copies.
+
+Permission is granted to copy and distribute modified versions of this
+manual under the conditions for verbatim copying, provided also that
+the entire resulting derived work is distributed under the terms of a
+permission notice identical to this one.
+
+Permission is granted to copy and distribute translations of this manual
+into another language, under the above conditions for modified versions.
+@end titlepage
+@page
+
+@node Top, Global Actions,, (DIR)
+@chapter The C Preprocessor
+
+The C preprocessor is a @dfn{macro processor} that is used automatically by
+the C compiler to transform your program before actual compilation. It is
+called a macro processor because it allows you to define @dfn{macros},
+which are brief abbreviations for longer constructs.
+
+The C preprocessor provides four separate facilities that you can use as
+you see fit:
+
+@itemize @bullet
+@item
+Inclusion of header files. These are files of declarations that can be
+substituted into your program.
+
+@item
+Macro expansion. You can define @dfn{macros}, which are abbreviations
+for arbitrary fragments of C code, and then the C preprocessor will
+replace the macros with their definitions throughout the program.
+
+@item
+Conditional compilation. Using special preprocessor commands, you
+can include or exclude parts of the program according to various
+conditions.
+
+@item
+Line control. If you use a program to combine or rearrange source files into
+an intermediate file which is then compiled, you can use line control
+to inform the compiler of where each source line originally came from.
+@end itemize
+
+C preprocessors vary in some details. This manual discusses the GNU C
+preprocessor, the C Compatible Compiler Preprocessor. The GNU C
+preprocessor provides a superset of the features of ANSI Standard C.
+
+ANSI Standard C requires the rejection of many harmless constructs commonly
+used by today's C programs. Such incompatibility would be inconvenient for
+users, so the GNU C preprocessor is configured to accept these constructs
+by default. Strictly speaking, to get ANSI Standard C, you must use the
+options @samp{-trigraphs}, @samp{-undef} and @samp{-pedantic}, but in
+practice the consequences of having strict ANSI Standard C make it
+undesirable to do this. @xref{Invocation}.
+
+@menu
+* Global Actions:: Actions made uniformly on all input files.
+* Commands:: General syntax of preprocessor commands.
+* Header Files:: How and why to use header files.
+* Macros:: How and why to use macros.
+* Conditionals:: How and why to use conditionals.
+* Combining Sources:: Use of line control when you combine source files.
+* Other Commands:: Miscellaneous preprocessor commands.
+* Output:: Format of output from the C preprocessor.
+* Invocation:: How to invoke the preprocessor; command options.
+* Concept Index:: Index of concepts and terms.
+* Index:: Index of commands, predefined macros and options.
+@end menu
+
+@node Global Actions, Commands, Top, Top
+@section Transformations Made Globally
+
+Most C preprocessor features are inactive unless you give specific commands
+to request their use. (Preprocessor commands are lines starting with
+@samp{#}; @pxref{Commands}). But there are three transformations that the
+preprocessor always makes on all the input it receives, even in the absence
+of commands.
+
+@itemize @bullet
+@item
+All C comments are replaced with single spaces.
+
+@item
+Backslash-Newline sequences are deleted, no matter where. This
+feature allows you to break long lines for cosmetic purposes without
+changing their meaning.
+
+@item
+Predefined macro names are replaced with their expansions
+(@pxref{Predefined}).
+@end itemize
+
+The first two transformations are done @emph{before} nearly all other parsing
+and before preprocessor commands are recognized. Thus, for example, you
+can split a line cosmetically with Backslash-Newline anywhere (except
+when trigraphs are in use; see below).
+
+@example
+/*
+*/ # /*
+*/ defi\
+ne FO\
+O 10\
+20
+@end example
+
+@noindent
+is equivalent into @samp{#define FOO 1020}. You can split even an escape
+sequence with Backslash-Newline. For example, you can split @code{"foo\bar"}
+between the @samp{\} and the @samp{b} to get
+
+@example
+"foo\\
+bar"
+@end example
+
+@noindent
+This behavior is unclean: in all other contexts, a Backslash can be
+inserted in a string constant as an ordinary character by writing a double
+Backslash, and this creates an exception. But the ANSI C standard requires
+it. (Strict ANSI C does not allow Newlines in string constants, so they
+do not consider this a problem.)
+
+But there are a few exceptions to all three transformations.
+
+@itemize @bullet
+@item
+C comments and predefined macro names are not recognized inside a
+@samp{#include} command in which the file name is delimited with
+@samp{<} and @samp{>}.
+
+@item
+C comments and predefined macro names are never recognized within a
+character or string constant. (Strictly speaking, this is the rule,
+not an exception, but it is worth noting here anyway.)
+
+@item
+Backslash-Newline may not safely be used within an ANSI ``trigraph''.
+Trigraphs are converted before Backslash-Newline is deleted. If you
+write what looks like a trigraph with a Backslash-Newline inside, the
+Backslash-Newline is deleted as usual, but it is then too late to
+recognize the trigraph.
+
+This exception is relevant only if you use the @samp{-trigraphs}
+option to enable trigraph processing. @xref{Invocation}.
+@end itemize
+
+@node Commands, Header Files, Global Actions, Top
+@section Preprocessor Commands
+
+@cindex preprocessor commands
+@cindex commands
+Most preprocessor features are active only if you use preprocessor commands
+to request their use.
+
+Preprocessor commands are lines in your program that start with @samp{#}.
+The @samp{#} is followed by an identifier that is the @dfn{command name}.
+For example, @samp{#define} is the command that defines a macro.
+Whitespace is also allowed before and after the @samp{#}.
+
+The set of valid command names is fixed. Programs cannot define new
+preprocessor commands.
+
+Some command names require arguments; these make up the rest of the command
+line and must be separated from the command name by whitespace. For example,
+@samp{#define} must be followed by a macro name and the intended expansion
+of the macro. @xref{Simple Macros}.
+
+A preprocessor command cannot be more than one line in normal circumstances.
+It may be split cosmetically with Backslash-Newline, but that has no effect
+on its meaning. Comments containing Newlines can also divide the command into
+multiple lines, but the comments are changed to Spaces before the command
+is interpreted. The only way a significant Newline can occur in a preprocessor
+command is within a string constant or character constant. Note that
+most C compilers that might be applied to the output from the preprocessor
+do not accept string or character constants containing Newlines.
+
+The @samp{#} and the command name cannot come from a macro expansion. For
+example, if @samp{foo} is defined as a macro expanding to @samp{define},
+that does not make @samp{#foo} a valid preprocessor command.
+
+@node Header Files, Macros, Commands, Top
+@section Header Files
+
+@cindex header file
+A header file is a file containing C declarations and macro definitions
+(@pxref{Macros}) to be shared between several source files. You request
+the use of a header file in your program with the C preprocessor command
+@samp{#include}.
+
+@menu
+* Header Uses:: What header files are used for.
+* Include Syntax:: How to write @samp{#include} commands.
+* Include Operation:: What @samp{#include} does.
+* Once-Only:: Preventing multiple inclusion of one header file.
+* Inheritance:: Including one header file in another header file.
+@end menu
+
+@node Header Uses, Include Syntax, Header Files, Header Files
+@subsection Uses of Header Files
+
+Header files serve two kinds of purposes.
+
+@itemize @bullet
+@item
+@findex system header files
+System header files declare the interfaces to parts of the operating
+system. You include them in your program to supply the definitions and
+declarations you need to invoke system calls and libraries.
+
+@item
+Your own header files contain declarations for interfaces between the
+source files of your program. Each time you have a group of related
+declarations and macro definitions all or most of which are needed in
+several different source files, it is a good idea to create a header
+file for them.
+@end itemize
+
+Including a header file produces the same results in C compilation as
+copying the header file into each source file that needs it. But such
+copying would be time-consuming and error-prone. With a header file, the
+related declarations appear in only one place. If they need to be changed,
+they can be changed in one place, and programs that include the header file
+will automatically use the new version when next recompiled. The header
+file eliminates the labor of finding and changing all the copies as well as
+the risk that a failure to find one copy will result in inconsistencies
+within a program.
+
+The usual convention is to give header files names that end with
+@file{.h}. Avoid unusual characters in header file names, as they
+reduce portability.
+
+@node Include Syntax, Include Operation, Header Uses, Header Files
+@subsection The @samp{#include} Command
+
+@findex #include
+Both user and system header files are included using the preprocessor
+command @samp{#include}. It has three variants:
+
+@table @code
+@item #include <@var{file}>
+This variant is used for system header files. It searches for a file
+named @var{file} in a list of directories specified by you, then in a
+standard list of system directories. You specify directories to
+search for header files with the command option @samp{-I}
+(@pxref{Invocation}). The option @samp{-nostdinc} inhibits searching
+the standard system directories; in this case only the directories
+you specify are searched.
+
+The parsing of this form of @samp{#include} is slightly special
+because comments are not recognized within the @samp{<@dots{}>}.
+Thus, in @samp{#include <x/*y>} the @samp{/*} does not start a comment
+and the command specifies inclusion of a system header file named
+@file{x/*y}. Of course, a header file with such a name is unlikely to
+exist on Unix, where shell wildcard features would make it hard to
+manipulate.@refill
+
+The argument @var{file} may not contain a @samp{>} character. It may,
+however, contain a @samp{<} character.
+
+@item #include "@var{file}"
+This variant is used for header files of your own program. It
+searches for a file named @var{file} first in the current directory,
+then in the same directories used for system header files. The
+current directory is the directory of the current input file. It is
+tried first because it is presumed to be the location of the files
+that the current input file refers to. (If the @samp{-I-} option is
+used, the special treatment of the current directory is inhibited.)
+
+The argument @var{file} may not contain @samp{"} characters. If
+backslashes occur within @var{file}, they are considered ordinary text
+characters, not escape characters. None of the character escape
+sequences appropriate to string constants in C are processed. Thus,
+@samp{#include "x\n\\y"} specifies a filename containing three
+backslashes. It is not clear why this behavior is ever useful, but
+the ANSI standard specifies it.
+
+@item #include @var{anything else}
+@cindex computed @samp{#include}
+This variant is called a @dfn{computed #include}. Any @samp{#include}
+command whose argument does not fit the above two forms is a computed
+include. The text @var{anything else} is checked for macro calls,
+which are expanded (@pxref{Macros}). When this is done, the result
+must fit one of the above two variants---in particular, the expanded
+text must in the end be surrounded by either quotes or angle braces.
+
+This feature allows you to define a macro which controls the file name
+to be used at a later point in the program. One application of this is
+to allow a site-specific configuration file for your program to specify
+the names of the system include files to be used. This can help in
+porting the program to various operating systems in which the necessary
+system header files are found in different places.
+@end table
+
+@node Include Operation, Once-Only, Include Syntax, Header Files
+@subsection How @samp{#include} Works
+
+The @samp{#include} command works by directing the C preprocessor to scan
+the specified file as input before continuing with the rest of the current
+file. The output from the preprocessor contains the output already
+generated, followed by the output resulting from the included file,
+followed by the output that comes from the text after the @samp{#include}
+command. For example, given a header file @file{header.h} as follows,
+
+@example
+char *test ();
+@end example
+
+@noindent
+and a main program called @file{program.c} that uses the header file,
+like this,
+
+@example
+int x;
+#include "header.h"
+
+main ()
+@{
+ printf (test ());
+@}
+@end example
+
+@noindent
+the output generated by the C preprocessor for @file{program.c} as input
+would be
+
+@example
+int x;
+char *test ();
+
+main ()
+@{
+ printf (test ());
+@}
+@end example
+
+Included files are not limited to declarations and macro definitions; those
+are merely the typical uses. Any fragment of a C program can be included
+from another file. The include file could even contain the beginning of a
+statement that is concluded in the containing file, or the end of a
+statement that was started in the including file. However, a comment or a
+string or character constant may not start in the included file and finish
+in the including file. An unterminated comment, string constant or
+character constant in an included file is considered to end (with an error
+message) at the end of the file.
+
+It is possible for a header file to begin or end a syntactic unit such
+as a function definition, but that would be very confusing, so don't do
+it.
+
+The line following the @samp{#include} command is always treated as a
+separate line by the C preprocessor even if the included file lacks a final
+newline.
+
+@node Once-Only, Inheritance, Include Operation, Header Files
+@subsection Once-Only Include Files
+@cindex repeated inclusion
+@cindex including just once
+
+Very often, one header file includes another. It can easily result that a
+certain header file is included more than once. This may lead to errors,
+if the header file defines structure types or typedefs, and is certainly
+wasteful. Therefore, we often wish to prevent multiple inclusion of a
+header file.
+
+The standard way to do this is to enclose the entire real contents of the
+file in a conditional, like this:
+
+@example
+#ifndef FILE_FOO_SEEN
+#define FILE_FOO_SEEN
+
+@var{the entire file}
+
+#endif /* FILE_FOO_SEEN */
+@end example
+
+The macro @code{FILE_FOO_SEEN} indicates that the file has been included
+once already. In a user header file, the macro name should not begin
+with @samp{_}. In a system header file, this name should begin with
+@samp{__} to avoid conflicts with user programs. In any kind of header
+file, the macro name should contain the name of the file and some
+additional text, to avoid conflicts with other header files.
+
+The GNU C preprocessor is programmed to notice when a header file uses
+this particular construct and handle it efficiently. If a header file
+is contained entirely in a @samp{#ifndef} conditional, then it records
+that fact. If a subsequent @samp{#include} specifies the same file,
+and the macro in the @samp{#ifndef} is already defined, then the file
+is entirely skipped, without even reading it.
+
+@findex #pragma once
+There is also an explicit command to tell the preprocessor that it need
+not include a file more than once. This is called @samp{#pragma once},
+and was used @emph{in addition to} the @samp{#ifndef} conditional around
+the contents of the header file. @samp{#pragma once} is now obsolete
+and should not be used at all.
+
+@findex #import
+In the Objective C language, there is a variant of @samp{#include}
+called @samp{#import} which includes a file, but does so at most once.
+If you use @samp{#import} @emph{instead of} @samp{#include}, then you
+don't need the conditionals inside the header file to prevent multiple
+execution of the contents.
+
+@samp{#import} is obsolete because it is not a well designed feature.
+It requires the users of a header file---the applications
+programmers---to know that a certain header file should only be included
+once. It is much better for the header file's implementor to write the
+file so that users don't need to know this. Using @samp{#ifndef}
+accomplishes this goal.
+
+@node Inheritance,, Once-Only, Header Files
+@subsection Inheritance and Header Files
+@cindex inheritance
+@cindex overriding a header file
+
+@dfn{Inheritance} is what happens when one object or file derives some
+of its contents by virtual copying from another object or file. In
+the case of C header files, inheritance means that one header file
+includes another header file and then replaces or adds something.
+
+If the inheriting header file and the base header file have different
+names, then inheritance is straightforward: simply write @samp{#include
+"@var{base}"} in the inheriting file.
+
+Sometimes it is necessary to give the inheriting file the same name as
+the base file. This is less straightforward.
+
+For example, suppose an application program uses the system header file
+@file{sys/signal.h}, but the version of @file{/usr/include/sys/signal.h}
+on a particular system doesn't do what the application program expects.
+It might be convenient to define a ``local'' version, perhaps under the
+name @file{/usr/local/include/sys/signal.h}, to override or add to the
+one supplied by the system.
+
+You can do this by using the option @samp{-I.} for compilation, and
+writing a file @file{sys/signal.h} that does what the application
+program expects. But making this file include the standard
+@file{sys/signal.h} is not so easy---writing @samp{#include
+<sys/signal.h>} in that file doesn't work, because it includes your own
+version of the file, not the standard system version. Used in that file
+itself, this leads to an infinite recursion and a fatal error in
+compilation.
+
+@samp{#include </usr/include/sys/signal.h>} would find the proper file,
+but that is not clean, since it makes an assumption about where the
+system header file is found. This is bad for maintenance, since it
+means that any change in where the system's header files are kept
+requires a change somewhere else.
+
+@findex #include_next
+The clean way to solve this problem is to use
+@samp{#include_next}, which means, ``Include the @emph{next} file with
+this name.'' This command works like @samp{#include} except in
+searching for the specified file: it starts searching the list of header
+file directories @emph{after} the directory in which the current file
+was found.
+
+Suppose you specify @samp{-I /usr/local/include}, and the list of
+directories to search also includes @file{/usr/include}; and suppose that
+both directories contain a file named @file{sys/signal.h}. Ordinary
+@samp{#include <sys/signal.h>} finds the file under
+@file{/usr/local/include}. If that file contains @samp{#include_next
+<sys/signal.h>}, it starts searching after that directory, and finds the
+file in @file{/usr/include}.
+
+@node Macros, Conditionals, Header Files, Top
+@section Macros
+
+A macro is a sort of abbreviation which you can define once and then
+use later. There are many complicated features associated with macros
+in the C preprocessor.
+
+@menu
+* Simple Macros:: Macros that always expand the same way.
+* Argument Macros:: Macros that accept arguments that are substituted
+ into the macro expansion.
+* Predefined:: Predefined macros that are always available.
+* Stringification:: Macro arguments converted into string constants.
+* Concatenation:: Building tokens from parts taken from macro arguments.
+* Undefining:: Cancelling a macro's definition.
+* Redefining:: Changing a macro's definition.
+* Macro Pitfalls:: Macros can confuse the unwary. Here we explain
+ several common problems and strange features.
+@end menu
+
+@node Simple Macros, Argument Macros, Macros, Macros
+@subsection Simple Macros
+@cindex simple macro
+@cindex manifest constant
+
+A @dfn{simple macro} is a kind of abbreviation. It is a name which
+stands for a fragment of code. Some people refer to these as
+@dfn{manifest constants}.
+
+Before you can use a macro, you must @dfn{define} it explicitly with the
+@samp{#define} command. @samp{#define} is followed by the name of the
+macro and then the code it should be an abbreviation for. For example,
+
+@example
+#define BUFFER_SIZE 1020
+@end example
+
+@noindent
+defines a macro named @samp{BUFFER_SIZE} as an abbreviation for the text
+@samp{1020}. If somewhere after this @samp{#define} command there comes
+a C statement of the form
+
+@example
+foo = (char *) xmalloc (BUFFER_SIZE);
+@end example
+
+@noindent
+then the C preprocessor will recognize and @dfn{expand} the macro
+@samp{BUFFER_SIZE}, resulting in
+
+@example
+foo = (char *) xmalloc (1020);
+@end example
+
+The use of all upper case for macro names is a standard convention.
+Programs are easier to read when it is possible to tell at a glance which
+names are macros.
+
+Normally, a macro definition must be a single line, like all C
+preprocessor commands. (You can split a long macro definition
+cosmetically with Backslash-Newline.) There is one exception: Newlines
+can be included in the macro definition if within a string or character
+constant. This is because it is not possible for a macro definition to
+contain an unbalanced quote character; the definition automatically
+extends to include the matching quote character that ends the string or
+character constant. Comments within a macro definition may contain
+Newlines, which make no difference since the comments are entirely
+replaced with Spaces regardless of their contents.
+
+Aside from the above, there is no restriction on what can go in a macro
+body. Parentheses need not balance. The body need not resemble valid C
+code. (But if it does not, you may get error messages from the C
+compiler when you use the macro.)
+
+The C preprocessor scans your program sequentially, so macro definitions
+take effect at the place you write them. Therefore, the following input to
+the C preprocessor
+
+@example
+foo = X;
+#define X 4
+bar = X;
+@end example
+
+@noindent
+produces as output
+
+@example
+foo = X;
+
+bar = 4;
+@end example
+
+After the preprocessor expands a macro name, the macro's definition body is
+appended to the front of the remaining input, and the check for macro calls
+continues. Therefore, the macro body can contain calls to other macros.
+For example, after
+
+@example
+#define BUFSIZE 1020
+#define TABLESIZE BUFSIZE
+@end example
+
+@noindent
+the name @samp{TABLESIZE} when used in the program would go through two
+stages of expansion, resulting ultimately in @samp{1020}.
+
+This is not at all the same as defining @samp{TABLESIZE} to be @samp{1020}.
+The @samp{#define} for @samp{TABLESIZE} uses exactly the body you
+specify---in this case, @samp{BUFSIZE}---and does not check to see whether
+it too is the name of a macro. It's only when you @emph{use} @samp{TABLESIZE}
+that the result of its expansion is checked for more macro names.
+@xref{Cascaded Macros}.
+
+@node Argument Macros, Predefined, Simple Macros, Macros
+@subsection Macros with Arguments
+@cindex macros with argument
+@cindex arguments in macro definitions
+@cindex function-like macro
+
+A simple macro always stands for exactly the same text, each time it is
+used. Macros can be more flexible when they accept @dfn{arguments}.
+Arguments are fragments of code that you supply each time the macro is
+used. These fragments are included in the expansion of the macro
+according to the directions in the macro definition. A macro that
+accepts arguments is called a @dfn{function-like macro} because the
+syntax for using it looks like a function call.
+
+@findex #define
+To define a macro that uses arguments, you write a @samp{#define} command
+with a list of @dfn{argument names} in parentheses after the name of the
+macro. The argument names may be any valid C identifiers, separated by
+commas and optionally whitespace. The open-parenthesis must follow the
+macro name immediately, with no space in between.
+
+For example, here is a macro that computes the minimum of two numeric
+values, as it is defined in many C programs:
+
+@example
+#define min(X, Y) ((X) < (Y) ? (X) : (Y))
+@end example
+
+@noindent
+(This is not the best way to define a ``minimum'' macro in GNU C.
+@xref{Side Effects}, for more information.)
+
+To use a macro that expects arguments, you write the name of the macro
+followed by a list of @dfn{actual arguments} in parentheses, separated by
+commas. The number of actual arguments you give must match the number of
+arguments the macro expects. Examples of use of the macro @samp{min}
+include @samp{min (1, 2)} and @samp{min (x + 28, *p)}.
+
+The expansion text of the macro depends on the arguments you use.
+Each of the argument names of the macro is replaced, throughout the
+macro definition, with the corresponding actual argument. Using the
+same macro @samp{min} defined above, @samp{min (1, 2)} expands into
+
+@example
+((1) < (2) ? (1) : (2))
+@end example
+
+@noindent
+where @samp{1} has been substituted for @samp{X} and @samp{2} for @samp{Y}.
+
+Likewise, @samp{min (x + 28, *p)} expands into
+
+@example
+((x + 28) < (*p) ? (x + 28) : (*p))
+@end example
+
+Parentheses in the actual arguments must balance; a comma within
+parentheses does not end an argument. However, there is no requirement
+for brackets or braces to balance, and they do not prevent a comma from
+separating arguments. Thus,
+
+@example
+macro (array[x = y, x + 1])
+@end example
+
+@noindent
+passes two arguments to @code{macro}: @samp{array[x = y} and @samp{x +
+1]}. If you want to supply @samp{array[x = y, x + 1]} as an argument,
+you must write it as @samp{array[(x = y, x + 1)]}, which is equivalent C
+code.
+
+After the actual arguments are substituted into the macro body, the entire
+result is appended to the front of the remaining input, and the check for
+macro calls continues. Therefore, the actual arguments can contain calls
+to other macros, either with or without arguments, or even to the same
+macro. The macro body can also contain calls to other macros. For
+example, @samp{min (min (a, b), c)} expands into this text:
+
+@example
+((((a) < (b) ? (a) : (b))) < (c)
+ ? (((a) < (b) ? (a) : (b)))
+ : (c))
+@end example
+
+@noindent
+(Line breaks shown here for clarity would not actually be generated.)
+
+@cindex blank macro arguments
+@cindex space as macro argument
+If a macro @code{foo} takes one argument, and you want to supply an
+empty argument, you must write at least some whitespace between the
+parentheses, like this: @samp{foo ( )}. Just @samp{foo ()} is providing
+no arguments, which is an error if @code{foo} expects an argument. But
+@samp{foo0 ()} is the correct way to call a macro defined to take zero
+arguments, like this:
+
+@example
+#define foo0() @dots{}
+@end example
+
+If you use the macro name followed by something other than an
+open-parenthesis (after ignoring any spaces, tabs and comments that
+follow), it is not a call to the macro, and the preprocessor does not
+change what you have written. Therefore, it is possible for the same name
+to be a variable or function in your program as well as a macro, and you
+can choose in each instance whether to refer to the macro (if an actual
+argument list follows) or the variable or function (if an argument list
+does not follow).
+
+Such dual use of one name could be confusing and should be avoided
+except when the two meanings are effectively synonymous: that is, when the
+name is both a macro and a function and the two have similar effects. You
+can think of the name simply as a function; use of the name for purposes
+other than calling it (such as, to take the address) will refer to the
+function, while calls will expand the macro and generate better but
+equivalent code. For example, you can use a function named @samp{min} in
+the same source file that defines the macro. If you write @samp{&min} with
+no argument list, you refer to the function. If you write @samp{min (x,
+bb)}, with an argument list, the macro is expanded. If you write
+@samp{(min) (a, bb)}, where the name @samp{min} is not followed by an
+open-parenthesis, the macro is not expanded, so you wind up with a call to
+the function @samp{min}.
+
+You may not define the same name as both a simple macro and a macro with
+arguments.
+
+In the definition of a macro with arguments, the list of argument names
+must follow the macro name immediately with no space in between. If there
+is a space after the macro name, the macro is defined as taking no
+arguments, and all the rest of the line is taken to be the expansion. The
+reason for this is that it is often useful to define a macro that takes no
+arguments and whose definition begins with an identifier in parentheses.
+This rule about spaces makes it possible for you to do either this:
+
+@example
+#define FOO(x) - 1 / (x)
+@end example
+
+@noindent
+(which defines @samp{FOO} to take an argument and expand into minus the
+reciprocal of that argument) or this:
+
+@example
+#define BAR (x) - 1 / (x)
+@end example
+
+@noindent
+(which defines @samp{BAR} to take no argument and always expand into
+@samp{(x) - 1 / (x)}).
+
+Note that the @emph{uses} of a macro with arguments can have spaces before
+the left parenthesis; it's the @emph{definition} where it matters whether
+there is a space.
+
+@node Predefined, Stringification, Argument Macros, Macros
+@subsection Predefined Macros
+
+@cindex predefined macros
+Several simple macros are predefined. You can use them without giving
+definitions for them. They fall into two classes: standard macros and
+system-specific macros.
+
+@menu
+* Standard Predefined:: Standard predefined macros.
+* Nonstandard Predefined:: Nonstandard predefined macros.
+@end menu
+
+@node Standard Predefined, Nonstandard Predefined, Predefined, Predefined
+@subsubsection Standard Predefined Macros
+@cindex standard predefined macros
+
+The standard predefined macros are available with the same meanings
+regardless of the machine or operating system on which you are using GNU C.
+Their names all start and end with double underscores. Those preceding
+@code{__GNUC__} in this table are standardized by ANSI C; the rest are
+GNU C extensions.
+
+@table @code
+@item __FILE__
+@findex __FILE__
+This macro expands to the name of the current input file, in the form of
+a C string constant. The precise name returned is the one that was
+specified in @samp{#include} or as the input file name argument.
+
+@item __LINE__
+@findex __LINE__
+This macro expands to the current input line number, in the form of a
+decimal integer constant. While we call it a predefined macro, it's
+a pretty strange macro, since its ``definition'' changes with each
+new line of source code.
+
+This and @samp{__FILE__} are useful in generating an error message to
+report an inconsistency detected by the program; the message can state
+the source line at which the inconsistency was detected. For example,
+
+@smallexample
+fprintf (stderr, "Internal error: "
+ "negative string length "
+ "%d at %s, line %d.",
+ length, __FILE__, __LINE__);
+@end smallexample
+
+A @samp{#include} command changes the expansions of @samp{__FILE__}
+and @samp{__LINE__} to correspond to the included file. At the end of
+that file, when processing resumes on the input file that contained
+the @samp{#include} command, the expansions of @samp{__FILE__} and
+@samp{__LINE__} revert to the values they had before the
+@samp{#include} (but @samp{__LINE__} is then incremented by one as
+processing moves to the line after the @samp{#include}).
+
+The expansions of both @samp{__FILE__} and @samp{__LINE__} are altered
+if a @samp{#line} command is used. @xref{Combining Sources}.
+
+@item __INCLUDE_LEVEL__
+@findex __INCLUDE_LEVEL_
+This macro expands to a decimal integer constant that represents the
+depth of nesting in include files. The value of this macro is
+incremented on every @samp{#include} command and decremented at every
+end of file. For input files specified by command line arguments,
+the nesting level is zero.
+
+@item __DATE__
+@findex __DATE__
+This macro expands to a string constant that describes the date on
+which the preprocessor is being run. The string constant contains
+eleven characters and looks like @samp{"Jan 29 1987"} or @w{@samp{"Apr
+1 1905"}}.
+
+@item __TIME__
+@findex __TIME__
+This macro expands to a string constant that describes the time at
+which the preprocessor is being run. The string constant contains
+eight characters and looks like @samp{"23:59:01"}.
+
+@item __STDC__
+@findex __STDC__
+This macro expands to the constant 1, to signify that this is ANSI
+Standard C. (Whether that is actually true depends on what C compiler
+will operate on the output from the preprocessor.)
+
+@item __GNUC__
+@findex __GNUC__
+This macro is defined if and only if this is GNU C. This macro is
+defined only when the entire GNU C compiler is in use; if you invoke the
+preprocessor directly, @samp{__GNUC__} is undefined. The value
+identifies the major version number of GNU CC (@samp{1} for GNU CC
+version 1, which is now obsolete, and @samp{2} for version 2).
+
+@item __GNUG__
+@findex __GNUG__
+The GNU C compiler defines this when the compilation language is
+C++; use @samp{__GNUG__} to distinguish between GNU C and GNU
+C++.
+
+@item __cplusplus
+@findex __cplusplus
+The draft ANSI standard for C++ used to require predefining this
+variable. Though it is no longer required, GNU C++ continues to define
+it, as do other popular C++ compilers. You can use @samp{__cplusplus}
+to test whether a header is compiled by a C compiler or a C++ compiler.
+
+@item __STRICT_ANSI__
+@findex __STRICT_ANSI__
+This macro is defined if and only if the @samp{-ansi} switch was
+specified when GNU C was invoked. Its definition is the null string.
+This macro exists primarily to direct certain GNU header files not to
+define certain traditional Unix constructs which are incompatible with
+ANSI C.
+
+@item __BASE_FILE__
+@findex __BASE_FILE__
+This macro expands to the name of the main input file, in the form
+of a C string constant. This is the source file that was specified
+as an argument when the C compiler was invoked.
+
+@item __VERSION__
+@findex __VERSION__
+This macro expands to a string which describes the version number of
+GNU C. The string is normally a sequence of decimal numbers separated
+by periods, such as @samp{"2.6.0"}. The only reasonable use of this
+macro is to incorporate it into a string constant.
+
+@item __OPTIMIZE__
+@findex __OPTIMIZE__
+This macro is defined in optimizing compilations. It causes certain
+GNU header files to define alternative macro definitions for some
+system library functions. It is unwise to refer to or test the
+definition of this macro unless you make very sure that programs will
+execute with the same effect regardless.
+
+@item __CHAR_UNSIGNED__
+@findex __CHAR_UNSIGNED__
+This macro is defined if and only if the data type @code{char} is
+unsigned on the target machine. It exists to cause the standard
+header file @file{limit.h} to work correctly. It is bad practice
+to refer to this macro yourself; instead, refer to the standard
+macros defined in @file{limit.h}. The preprocessor uses
+this macro to determine whether or not to sign-extend large character
+constants written in octal; see @ref{#if Command,,The @samp{#if} Command}.
+@end table
+
+@node Nonstandard Predefined,, Standard Predefined, Predefined
+@subsubsection Nonstandard Predefined Macros
+
+The C preprocessor normally has several predefined macros that vary between
+machines because their purpose is to indicate what type of system and
+machine is in use. This manual, being for all systems and machines, cannot
+tell you exactly what their names are; instead, we offer a list of some
+typical ones. You can use @samp{cpp -dM} to see the values of
+predefined macros; see @ref{Invocation}.
+
+Some nonstandard predefined macros describe the operating system in use,
+with more or less specificity. For example,
+
+@table @code
+@item unix
+@findex unix
+@samp{unix} is normally predefined on all Unix systems.
+
+@item BSD
+@findex BSD
+@samp{BSD} is predefined on recent versions of Berkeley Unix
+(perhaps only in version 4.3).
+@end table
+
+Other nonstandard predefined macros describe the kind of CPU, with more or
+less specificity. For example,
+
+@table @code
+@item vax
+@findex vax
+@samp{vax} is predefined on Vax computers.
+
+@item mc68000
+@findex mc68000
+@samp{mc68000} is predefined on most computers whose CPU is a Motorola
+68000, 68010 or 68020.
+
+@item m68k
+@findex m68k
+@samp{m68k} is also predefined on most computers whose CPU is a 68000,
+68010 or 68020; however, some makers use @samp{mc68000} and some use
+@samp{m68k}. Some predefine both names. What happens in GNU C
+depends on the system you are using it on.
+
+@item M68020
+@findex M68020
+@samp{M68020} has been observed to be predefined on some systems that
+use 68020 CPUs---in addition to @samp{mc68000} and @samp{m68k}, which
+are less specific.
+
+@item _AM29K
+@findex _AM29K
+@itemx _AM29000
+@findex _AM29000
+Both @samp{_AM29K} and @samp{_AM29000} are predefined for the AMD 29000
+CPU family.
+
+@item ns32000
+@findex ns32000
+@samp{ns32000} is predefined on computers which use the National
+Semiconductor 32000 series CPU.
+@end table
+
+Yet other nonstandard predefined macros describe the manufacturer of
+the system. For example,
+
+@table @code
+@item sun
+@findex sun
+@samp{sun} is predefined on all models of Sun computers.
+
+@item pyr
+@findex pyr
+@samp{pyr} is predefined on all models of Pyramid computers.
+
+@item sequent
+@findex sequent
+@samp{sequent} is predefined on all models of Sequent computers.
+@end table
+
+These predefined symbols are not only nonstandard, they are contrary to the
+ANSI standard because their names do not start with underscores.
+Therefore, the option @samp{-ansi} inhibits the definition of these
+symbols.
+
+This tends to make @samp{-ansi} useless, since many programs depend on the
+customary nonstandard predefined symbols. Even system header files check
+them and will generate incorrect declarations if they do not find the names
+that are expected. You might think that the header files supplied for the
+Uglix computer would not need to test what machine they are running on,
+because they can simply assume it is the Uglix; but often they do, and they
+do so using the customary names. As a result, very few C programs will
+compile with @samp{-ansi}. We intend to avoid such problems on the GNU
+system.
+
+What, then, should you do in an ANSI C program to test the type of machine
+it will run on?
+
+GNU C offers a parallel series of symbols for this purpose, whose names
+are made from the customary ones by adding @samp{__} at the beginning
+and end. Thus, the symbol @code{__vax__} would be available on a Vax,
+and so on.
+
+The set of nonstandard predefined names in the GNU C preprocessor is
+controlled (when @code{cpp} is itself compiled) by the macro
+@samp{CPP_PREDEFINES}, which should be a string containing @samp{-D}
+options, separated by spaces. For example, on the Sun 3, we use the
+following definition:
+
+@example
+#define CPP_PREDEFINES "-Dmc68000 -Dsun -Dunix -Dm68k"
+@end example
+
+@noindent
+This macro is usually specified in @file{tm.h}.
+
+@node Stringification, Concatenation, Predefined, Macros
+@subsection Stringification
+
+@cindex stringification
+@dfn{Stringification} means turning a code fragment into a string constant
+whose contents are the text for the code fragment. For example,
+stringifying @samp{foo (z)} results in @samp{"foo (z)"}.
+
+In the C preprocessor, stringification is an option available when macro
+arguments are substituted into the macro definition. In the body of the
+definition, when an argument name appears, the character @samp{#} before
+the name specifies stringification of the corresponding actual argument
+when it is substituted at that point in the definition. The same argument
+may be substituted in other places in the definition without
+stringification if the argument name appears in those places with no
+@samp{#}.
+
+Here is an example of a macro definition that uses stringification:
+
+@smallexample
+@group
+#define WARN_IF(EXP) \
+do @{ if (EXP) \
+ fprintf (stderr, "Warning: " #EXP "\n"); @} \
+while (0)
+@end group
+@end smallexample
+
+@noindent
+Here the actual argument for @samp{EXP} is substituted once as given,
+into the @samp{if} statement, and once as stringified, into the
+argument to @samp{fprintf}. The @samp{do} and @samp{while (0)} are
+a kludge to make it possible to write @samp{WARN_IF (@var{arg});},
+which the resemblance of @samp{WARN_IF} to a function would make
+C programmers want to do; see @ref{Swallow Semicolon}.
+
+The stringification feature is limited to transforming one macro argument
+into one string constant: there is no way to combine the argument with
+other text and then stringify it all together. But the example above shows
+how an equivalent result can be obtained in ANSI Standard C using the
+feature that adjacent string constants are concatenated as one string
+constant. The preprocessor stringifies the actual value of @samp{EXP}
+into a separate string constant, resulting in text like
+
+@smallexample
+@group
+do @{ if (x == 0) \
+ fprintf (stderr, "Warning: " "x == 0" "\n"); @} \
+while (0)
+@end group
+@end smallexample
+
+@noindent
+but the C compiler then sees three consecutive string constants and
+concatenates them into one, producing effectively
+
+@smallexample
+do @{ if (x == 0) \
+ fprintf (stderr, "Warning: x == 0\n"); @} \
+while (0)
+@end smallexample
+
+Stringification in C involves more than putting doublequote characters
+around the fragment; it is necessary to put backslashes in front of all
+doublequote characters, and all backslashes in string and character
+constants, in order to get a valid C string constant with the proper
+contents. Thus, stringifying @samp{p = "foo\n";} results in @samp{"p =
+\"foo\\n\";"}. However, backslashes that are not inside of string or
+character constants are not duplicated: @samp{\n} by itself stringifies to
+@samp{"\n"}.
+
+Whitespace (including comments) in the text being stringified is handled
+according to precise rules. All leading and trailing whitespace is ignored.
+Any sequence of whitespace in the middle of the text is converted to
+a single space in the stringified result.
+
+@node Concatenation, Undefining, Stringification, Macros
+@subsection Concatenation
+@cindex concatenation
+@cindex @samp{##}
+@dfn{Concatenation} means joining two strings into one. In the context
+of macro expansion, concatenation refers to joining two lexical units
+into one longer one. Specifically, an actual argument to the macro can be
+concatenated with another actual argument or with fixed text to produce
+a longer name. The longer name might be the name of a function,
+variable or type, or a C keyword; it might even be the name of another
+macro, in which case it will be expanded.
+
+When you define a macro, you request concatenation with the special
+operator @samp{##} in the macro body. When the macro is called,
+after actual arguments are substituted, all @samp{##} operators are
+deleted, and so is any whitespace next to them (including whitespace
+that was part of an actual argument). The result is to concatenate
+the syntactic tokens on either side of the @samp{##}.
+
+Consider a C program that interprets named commands. There probably needs
+to be a table of commands, perhaps an array of structures declared as
+follows:
+
+@example
+struct command
+@{
+ char *name;
+ void (*function) ();
+@};
+
+struct command commands[] =
+@{
+ @{ "quit", quit_command@},
+ @{ "help", help_command@},
+ @dots{}
+@};
+@end example
+
+It would be cleaner not to have to give each command name twice, once in
+the string constant and once in the function name. A macro which takes the
+name of a command as an argument can make this unnecessary. The string
+constant can be created with stringification, and the function name by
+concatenating the argument with @samp{_command}. Here is how it is done:
+
+@example
+#define COMMAND(NAME) @{ #NAME, NAME ## _command @}
+
+struct command commands[] =
+@{
+ COMMAND (quit),
+ COMMAND (help),
+ @dots{}
+@};
+@end example
+
+The usual case of concatenation is concatenating two names (or a name and a
+number) into a longer name. But this isn't the only valid case. It is
+also possible to concatenate two numbers (or a number and a name, such as
+@samp{1.5} and @samp{e3}) into a number. Also, multi-character operators
+such as @samp{+=} can be formed by concatenation. In some cases it is even
+possible to piece together a string constant. However, two pieces of text
+that don't together form a valid lexical unit cannot be concatenated. For
+example, concatenation with @samp{x} on one side and @samp{+} on the other
+is not meaningful because those two characters can't fit together in any
+lexical unit of C. The ANSI standard says that such attempts at
+concatenation are undefined, but in the GNU C preprocessor it is well
+defined: it puts the @samp{x} and @samp{+} side by side with no particular
+special results.
+
+Keep in mind that the C preprocessor converts comments to whitespace before
+macros are even considered. Therefore, you cannot create a comment by
+concatenating @samp{/} and @samp{*}: the @samp{/*} sequence that starts a
+comment is not a lexical unit, but rather the beginning of a ``long'' space
+character. Also, you can freely use comments next to a @samp{##} in a
+macro definition, or in actual arguments that will be concatenated, because
+the comments will be converted to spaces at first sight, and concatenation
+will later discard the spaces.
+
+@node Undefining, Redefining, Concatenation, Macros
+@subsection Undefining Macros
+
+@cindex undefining macros
+To @dfn{undefine} a macro means to cancel its definition. This is done
+with the @samp{#undef} command. @samp{#undef} is followed by the macro
+name to be undefined.
+
+Like definition, undefinition occurs at a specific point in the source
+file, and it applies starting from that point. The name ceases to be a
+macro name, and from that point on it is treated by the preprocessor as if
+it had never been a macro name.
+
+For example,
+
+@example
+#define FOO 4
+x = FOO;
+#undef FOO
+x = FOO;
+@end example
+
+@noindent
+expands into
+
+@example
+x = 4;
+
+x = FOO;
+@end example
+
+@noindent
+In this example, @samp{FOO} had better be a variable or function as well
+as (temporarily) a macro, in order for the result of the expansion to be
+valid C code.
+
+The same form of @samp{#undef} command will cancel definitions with
+arguments or definitions that don't expect arguments. The @samp{#undef}
+command has no effect when used on a name not currently defined as a macro.
+
+@node Redefining, Macro Pitfalls, Undefining, Macros
+@subsection Redefining Macros
+
+@cindex redefining macros
+@dfn{Redefining} a macro means defining (with @samp{#define}) a name that
+is already defined as a macro.
+
+A redefinition is trivial if the new definition is transparently identical
+to the old one. You probably wouldn't deliberately write a trivial
+redefinition, but they can happen automatically when a header file is
+included more than once (@pxref{Header Files}), so they are accepted
+silently and without effect.
+
+Nontrivial redefinition is considered likely to be an error, so
+it provokes a warning message from the preprocessor. However, sometimes it
+is useful to change the definition of a macro in mid-compilation. You can
+inhibit the warning by undefining the macro with @samp{#undef} before the
+second definition.
+
+In order for a redefinition to be trivial, the new definition must
+exactly match the one already in effect, with two possible exceptions:
+
+@itemize @bullet
+@item
+Whitespace may be added or deleted at the beginning or the end.
+
+@item
+Whitespace may be changed in the middle (but not inside strings).
+However, it may not be eliminated entirely, and it may not be added
+where there was no whitespace at all.
+@end itemize
+
+Recall that a comment counts as whitespace.
+
+@node Macro Pitfalls,, Redefining, Macros
+@subsection Pitfalls and Subtleties of Macros
+@cindex problems with macros
+@cindex pitfalls of macros
+
+In this section we describe some special rules that apply to macros and
+macro expansion, and point out certain cases in which the rules have
+counterintuitive consequences that you must watch out for.
+
+@menu
+* Misnesting:: Macros can contain unmatched parentheses.
+* Macro Parentheses:: Why apparently superfluous parentheses
+ may be necessary to avoid incorrect grouping.
+* Swallow Semicolon:: Macros that look like functions
+ but expand into compound statements.
+* Side Effects:: Unsafe macros that cause trouble when
+ arguments contain side effects.
+* Self-Reference:: Macros whose definitions use the macros' own names.
+* Argument Prescan:: Actual arguments are checked for macro calls
+ before they are substituted.
+* Cascaded Macros:: Macros whose definitions use other macros.
+* Newlines in Args:: Sometimes line numbers get confused.
+@end menu
+
+@node Misnesting, Macro Parentheses, Macro Pitfalls, Macro Pitfalls
+@subsubsection Improperly Nested Constructs
+
+Recall that when a macro is called with arguments, the arguments are
+substituted into the macro body and the result is checked, together with
+the rest of the input file, for more macro calls.
+
+It is possible to piece together a macro call coming partially from the
+macro body and partially from the actual arguments. For example,
+
+@example
+#define double(x) (2*(x))
+#define call_with_1(x) x(1)
+@end example
+
+@noindent
+would expand @samp{call_with_1 (double)} into @samp{(2*(1))}.
+
+Macro definitions do not have to have balanced parentheses. By writing an
+unbalanced open parenthesis in a macro body, it is possible to create a
+macro call that begins inside the macro body but ends outside of it. For
+example,
+
+@example
+#define strange(file) fprintf (file, "%s %d",
+@dots{}
+strange(stderr) p, 35)
+@end example
+
+@noindent
+This bizarre example expands to @samp{fprintf (stderr, "%s %d", p, 35)}!
+
+@node Macro Parentheses, Swallow Semicolon, Misnesting, Macro Pitfalls
+@subsubsection Unintended Grouping of Arithmetic
+@cindex parentheses in macro bodies
+
+You may have noticed that in most of the macro definition examples shown
+above, each occurrence of a macro argument name had parentheses around it.
+In addition, another pair of parentheses usually surround the entire macro
+definition. Here is why it is best to write macros that way.
+
+Suppose you define a macro as follows,
+
+@example
+#define ceil_div(x, y) (x + y - 1) / y
+@end example
+
+@noindent
+whose purpose is to divide, rounding up. (One use for this operation is
+to compute how many @samp{int} objects are needed to hold a certain
+number of @samp{char} objects.) Then suppose it is used as follows:
+
+@example
+a = ceil_div (b & c, sizeof (int));
+@end example
+
+@noindent
+This expands into
+
+@example
+a = (b & c + sizeof (int) - 1) / sizeof (int);
+@end example
+
+@noindent
+which does not do what is intended. The operator-precedence rules of
+C make it equivalent to this:
+
+@example
+a = (b & (c + sizeof (int) - 1)) / sizeof (int);
+@end example
+
+@noindent
+But what we want is this:
+
+@example
+a = ((b & c) + sizeof (int) - 1)) / sizeof (int);
+@end example
+
+@noindent
+Defining the macro as
+
+@example
+#define ceil_div(x, y) ((x) + (y) - 1) / (y)
+@end example
+
+@noindent
+provides the desired result.
+
+However, unintended grouping can result in another way. Consider
+@samp{sizeof ceil_div(1, 2)}. That has the appearance of a C expression
+that would compute the size of the type of @samp{ceil_div (1, 2)}, but in
+fact it means something very different. Here is what it expands to:
+
+@example
+sizeof ((1) + (2) - 1) / (2)
+@end example
+
+@noindent
+This would take the size of an integer and divide it by two. The precedence
+rules have put the division outside the @samp{sizeof} when it was intended
+to be inside.
+
+Parentheses around the entire macro definition can prevent such problems.
+Here, then, is the recommended way to define @samp{ceil_div}:
+
+@example
+#define ceil_div(x, y) (((x) + (y) - 1) / (y))
+@end example
+
+@node Swallow Semicolon, Side Effects, Macro Parentheses, Macro Pitfalls
+@subsubsection Swallowing the Semicolon
+
+@cindex semicolons (after macro calls)
+Often it is desirable to define a macro that expands into a compound
+statement. Consider, for example, the following macro, that advances a
+pointer (the argument @samp{p} says where to find it) across whitespace
+characters:
+
+@example
+#define SKIP_SPACES (p, limit) \
+@{ register char *lim = (limit); \
+ while (p != lim) @{ \
+ if (*p++ != ' ') @{ \
+ p--; break; @}@}@}
+@end example
+
+@noindent
+Here Backslash-Newline is used to split the macro definition, which must
+be a single line, so that it resembles the way such C code would be
+laid out if not part of a macro definition.
+
+A call to this macro might be @samp{SKIP_SPACES (p, lim)}. Strictly
+speaking, the call expands to a compound statement, which is a complete
+statement with no need for a semicolon to end it. But it looks like a
+function call. So it minimizes confusion if you can use it like a function
+call, writing a semicolon afterward, as in @samp{SKIP_SPACES (p, lim);}
+
+But this can cause trouble before @samp{else} statements, because the
+semicolon is actually a null statement. Suppose you write
+
+@example
+if (*p != 0)
+ SKIP_SPACES (p, lim);
+else @dots{}
+@end example
+
+@noindent
+The presence of two statements---the compound statement and a null
+statement---in between the @samp{if} condition and the @samp{else}
+makes invalid C code.
+
+The definition of the macro @samp{SKIP_SPACES} can be altered to solve
+this problem, using a @samp{do @dots{} while} statement. Here is how:
+
+@example
+#define SKIP_SPACES (p, limit) \
+do @{ register char *lim = (limit); \
+ while (p != lim) @{ \
+ if (*p++ != ' ') @{ \
+ p--; break; @}@}@} \
+while (0)
+@end example
+
+Now @samp{SKIP_SPACES (p, lim);} expands into
+
+@example
+do @{@dots{}@} while (0);
+@end example
+
+@noindent
+which is one statement.
+
+@node Side Effects, Self-Reference, Swallow Semicolon, Macro Pitfalls
+@subsubsection Duplication of Side Effects
+
+@cindex side effects (in macro arguments)
+@cindex unsafe macros
+Many C programs define a macro @samp{min}, for ``minimum'', like this:
+
+@example
+#define min(X, Y) ((X) < (Y) ? (X) : (Y))
+@end example
+
+When you use this macro with an argument containing a side effect,
+as shown here,
+
+@example
+next = min (x + y, foo (z));
+@end example
+
+@noindent
+it expands as follows:
+
+@example
+next = ((x + y) < (foo (z)) ? (x + y) : (foo (z)));
+@end example
+
+@noindent
+where @samp{x + y} has been substituted for @samp{X} and @samp{foo (z)}
+for @samp{Y}.
+
+The function @samp{foo} is used only once in the statement as it appears
+in the program, but the expression @samp{foo (z)} has been substituted
+twice into the macro expansion. As a result, @samp{foo} might be called
+two times when the statement is executed. If it has side effects or
+if it takes a long time to compute, the results might not be what you
+intended. We say that @samp{min} is an @dfn{unsafe} macro.
+
+The best solution to this problem is to define @samp{min} in a way that
+computes the value of @samp{foo (z)} only once. The C language offers no
+standard way to do this, but it can be done with GNU C extensions as
+follows:
+
+@example
+#define min(X, Y) \
+(@{ typeof (X) __x = (X), __y = (Y); \
+ (__x < __y) ? __x : __y; @})
+@end example
+
+If you do not wish to use GNU C extensions, the only solution is to be
+careful when @emph{using} the macro @samp{min}. For example, you can
+calculate the value of @samp{foo (z)}, save it in a variable, and use that
+variable in @samp{min}:
+
+@example
+#define min(X, Y) ((X) < (Y) ? (X) : (Y))
+@dots{}
+@{
+ int tem = foo (z);
+ next = min (x + y, tem);
+@}
+@end example
+
+@noindent
+(where we assume that @samp{foo} returns type @samp{int}).
+
+@node Self-Reference, Argument Prescan, Side Effects, Macro Pitfalls
+@subsubsection Self-Referential Macros
+
+@cindex self-reference
+A @dfn{self-referential} macro is one whose name appears in its definition.
+A special feature of ANSI Standard C is that the self-reference is not
+considered a macro call. It is passed into the preprocessor output
+unchanged.
+
+Let's consider an example:
+
+@example
+#define foo (4 + foo)
+@end example
+
+@noindent
+where @samp{foo} is also a variable in your program.
+
+Following the ordinary rules, each reference to @samp{foo} will expand into
+@samp{(4 + foo)}; then this will be rescanned and will expand into @samp{(4
++ (4 + foo))}; and so on until it causes a fatal error (memory full) in the
+preprocessor.
+
+However, the special rule about self-reference cuts this process short
+after one step, at @samp{(4 + foo)}. Therefore, this macro definition
+has the possibly useful effect of causing the program to add 4 to
+the value of @samp{foo} wherever @samp{foo} is referred to.
+
+In most cases, it is a bad idea to take advantage of this feature. A
+person reading the program who sees that @samp{foo} is a variable will
+not expect that it is a macro as well. The reader will come across the
+identifier @samp{foo} in the program and think its value should be that
+of the variable @samp{foo}, whereas in fact the value is four greater.
+
+The special rule for self-reference applies also to @dfn{indirect}
+self-reference. This is the case where a macro @var{x} expands to use a
+macro @samp{y}, and the expansion of @samp{y} refers to the macro
+@samp{x}. The resulting reference to @samp{x} comes indirectly from the
+expansion of @samp{x}, so it is a self-reference and is not further
+expanded. Thus, after
+
+@example
+#define x (4 + y)
+#define y (2 * x)
+@end example
+
+@noindent
+@samp{x} would expand into @samp{(4 + (2 * x))}. Clear?
+
+But suppose @samp{y} is used elsewhere, not from the definition of @samp{x}.
+Then the use of @samp{x} in the expansion of @samp{y} is not a self-reference
+because @samp{x} is not ``in progress''. So it does expand. However,
+the expansion of @samp{x} contains a reference to @samp{y}, and that
+is an indirect self-reference now because @samp{y} is ``in progress''.
+The result is that @samp{y} expands to @samp{(2 * (4 + y))}.
+
+It is not clear that this behavior would ever be useful, but it is specified
+by the ANSI C standard, so you may need to understand it.
+
+@node Argument Prescan, Cascaded Macros, Self-Reference, Macro Pitfalls
+@subsubsection Separate Expansion of Macro Arguments
+@cindex expansion of arguments
+@cindex macro argument expansion
+@cindex prescan of macro arguments
+
+We have explained that the expansion of a macro, including the substituted
+actual arguments, is scanned over again for macro calls to be expanded.
+
+What really happens is more subtle: first each actual argument text is scanned
+separately for macro calls. Then the results of this are substituted into
+the macro body to produce the macro expansion, and the macro expansion
+is scanned again for macros to expand.
+
+The result is that the actual arguments are scanned @emph{twice} to expand
+macro calls in them.
+
+Most of the time, this has no effect. If the actual argument contained
+any macro calls, they are expanded during the first scan. The result
+therefore contains no macro calls, so the second scan does not change it.
+If the actual argument were substituted as given, with no prescan,
+the single remaining scan would find the same macro calls and produce
+the same results.
+
+You might expect the double scan to change the results when a
+self-referential macro is used in an actual argument of another macro
+(@pxref{Self-Reference}): the self-referential macro would be expanded once
+in the first scan, and a second time in the second scan. But this is not
+what happens. The self-references that do not expand in the first scan are
+marked so that they will not expand in the second scan either.
+
+The prescan is not done when an argument is stringified or concatenated.
+Thus,
+
+@example
+#define str(s) #s
+#define foo 4
+str (foo)
+@end example
+
+@noindent
+expands to @samp{"foo"}. Once more, prescan has been prevented from
+having any noticeable effect.
+
+More precisely, stringification and concatenation use the argument as
+written, in un-prescanned form. The same actual argument would be used in
+prescanned form if it is substituted elsewhere without stringification or
+concatenation.
+
+@example
+#define str(s) #s lose(s)
+#define foo 4
+str (foo)
+@end example
+
+expands to @samp{"foo" lose(4)}.
+
+You might now ask, ``Why mention the prescan, if it makes no difference?
+And why not skip it and make the preprocessor faster?'' The answer is
+that the prescan does make a difference in three special cases:
+
+@itemize @bullet
+@item
+Nested calls to a macro.
+
+@item
+Macros that call other macros that stringify or concatenate.
+
+@item
+Macros whose expansions contain unshielded commas.
+@end itemize
+
+We say that @dfn{nested} calls to a macro occur when a macro's actual
+argument contains a call to that very macro. For example, if @samp{f}
+is a macro that expects one argument, @samp{f (f (1))} is a nested
+pair of calls to @samp{f}. The desired expansion is made by
+expanding @samp{f (1)} and substituting that into the definition of
+@samp{f}. The prescan causes the expected result to happen.
+Without the prescan, @samp{f (1)} itself would be substituted as
+an actual argument, and the inner use of @samp{f} would appear
+during the main scan as an indirect self-reference and would not
+be expanded. Here, the prescan cancels an undesirable side effect
+(in the medical, not computational, sense of the term) of the special
+rule for self-referential macros.
+
+But prescan causes trouble in certain other cases of nested macro calls.
+Here is an example:
+
+@example
+#define foo a,b
+#define bar(x) lose(x)
+#define lose(x) (1 + (x))
+
+bar(foo)
+@end example
+
+@noindent
+We would like @samp{bar(foo)} to turn into @samp{(1 + (foo))}, which
+would then turn into @samp{(1 + (a,b))}. But instead, @samp{bar(foo)}
+expands into @samp{lose(a,b)}, and you get an error because @code{lose}
+requires a single argument. In this case, the problem is easily solved
+by the same parentheses that ought to be used to prevent misnesting of
+arithmetic operations:
+
+@example
+#define foo (a,b)
+#define bar(x) lose((x))
+@end example
+
+The problem is more serious when the operands of the macro are not
+expressions; for example, when they are statements. Then parentheses
+are unacceptable because they would make for invalid C code:
+
+@example
+#define foo @{ int a, b; @dots{} @}
+@end example
+
+@noindent
+In GNU C you can shield the commas using the @samp{(@{@dots{}@})}
+construct which turns a compound statement into an expression:
+
+@example
+#define foo (@{ int a, b; @dots{} @})
+@end example
+
+Or you can rewrite the macro definition to avoid such commas:
+
+@example
+#define foo @{ int a; int b; @dots{} @}
+@end example
+
+There is also one case where prescan is useful. It is possible
+to use prescan to expand an argument and then stringify it---if you use
+two levels of macros. Let's add a new macro @samp{xstr} to the
+example shown above:
+
+@example
+#define xstr(s) str(s)
+#define str(s) #s
+#define foo 4
+xstr (foo)
+@end example
+
+This expands into @samp{"4"}, not @samp{"foo"}. The reason for the
+difference is that the argument of @samp{xstr} is expanded at prescan
+(because @samp{xstr} does not specify stringification or concatenation of
+the argument). The result of prescan then forms the actual argument for
+@samp{str}. @samp{str} uses its argument without prescan because it
+performs stringification; but it cannot prevent or undo the prescanning
+already done by @samp{xstr}.
+
+@node Cascaded Macros, Newlines in Args, Argument Prescan, Macro Pitfalls
+@subsubsection Cascaded Use of Macros
+
+@cindex cascaded macros
+@cindex macro body uses macro
+A @dfn{cascade} of macros is when one macro's body contains a reference
+to another macro. This is very common practice. For example,
+
+@example
+#define BUFSIZE 1020
+#define TABLESIZE BUFSIZE
+@end example
+
+This is not at all the same as defining @samp{TABLESIZE} to be @samp{1020}.
+The @samp{#define} for @samp{TABLESIZE} uses exactly the body you
+specify---in this case, @samp{BUFSIZE}---and does not check to see whether
+it too is the name of a macro.
+
+It's only when you @emph{use} @samp{TABLESIZE} that the result of its expansion
+is checked for more macro names.
+
+This makes a difference if you change the definition of @samp{BUFSIZE}
+at some point in the source file. @samp{TABLESIZE}, defined as shown,
+will always expand using the definition of @samp{BUFSIZE} that is
+currently in effect:
+
+@example
+#define BUFSIZE 1020
+#define TABLESIZE BUFSIZE
+#undef BUFSIZE
+#define BUFSIZE 37
+@end example
+
+@noindent
+Now @samp{TABLESIZE} expands (in two stages) to @samp{37}. (The
+@samp{#undef} is to prevent any warning about the nontrivial
+redefinition of @code{BUFSIZE}.)
+
+@node Newlines in Args,, Cascaded Macros, Macro Pitfalls
+@subsection Newlines in Macro Arguments
+@cindex newlines in macro arguments
+
+Traditional macro processing carries forward all newlines in macro
+arguments into the expansion of the macro. This means that, if some of
+the arguments are substituted more than once, or not at all, or out of
+order, newlines can be duplicated, lost, or moved around within the
+expansion. If the expansion consists of multiple statements, then the
+effect is to distort the line numbers of some of these statements. The
+result can be incorrect line numbers, in error messages or displayed in
+a debugger.
+
+The GNU C preprocessor operating in ANSI C mode adjusts appropriately
+for multiple use of an argument---the first use expands all the
+newlines, and subsequent uses of the same argument produce no newlines.
+But even in this mode, it can produce incorrect line numbering if
+arguments are used out of order, or not used at all.
+
+Here is an example illustrating this problem:
+
+@example
+#define ignore_second_arg(a,b,c) a; c
+
+ignore_second_arg (foo (),
+ ignored (),
+ syntax error);
+@end example
+
+@noindent
+The syntax error triggered by the tokens @samp{syntax error} results
+in an error message citing line four, even though the statement text
+comes from line five.
+
+@node Conditionals, Combining Sources, Macros, Top
+@section Conditionals
+
+@cindex conditionals
+In a macro processor, a @dfn{conditional} is a command that allows a part
+of the program to be ignored during compilation, on some conditions.
+In the C preprocessor, a conditional can test either an arithmetic expression
+or whether a name is defined as a macro.
+
+A conditional in the C preprocessor resembles in some ways an @samp{if}
+statement in C, but it is important to understand the difference between
+them. The condition in an @samp{if} statement is tested during the execution
+of your program. Its purpose is to allow your program to behave differently
+from run to run, depending on the data it is operating on. The condition
+in a preprocessor conditional command is tested when your program is compiled.
+Its purpose is to allow different code to be included in the program depending
+on the situation at the time of compilation.
+
+@menu
+* Uses: Conditional Uses. What conditionals are for.
+* Syntax: Conditional Syntax. How conditionals are written.
+* Deletion: Deleted Code. Making code into a comment.
+* Macros: Conditionals-Macros. Why conditionals are used with macros.
+* Assertions:: How and why to use assertions.
+* Errors: #error Command. Detecting inconsistent compilation parameters.
+@end menu
+
+@node Conditional Uses
+@subsection Why Conditionals are Used
+
+Generally there are three kinds of reason to use a conditional.
+
+@itemize @bullet
+@item
+A program may need to use different code depending on the machine or
+operating system it is to run on. In some cases the code for one
+operating system may be erroneous on another operating system; for
+example, it might refer to library routines that do not exist on the
+other system. When this happens, it is not enough to avoid executing
+the invalid code: merely having it in the program makes it impossible
+to link the program and run it. With a preprocessor conditional, the
+offending code can be effectively excised from the program when it is
+not valid.
+
+@item
+You may want to be able to compile the same source file into two
+different programs. Sometimes the difference between the programs is
+that one makes frequent time-consuming consistency checks on its
+intermediate data, or prints the values of those data for debugging,
+while the other does not.
+
+@item
+A conditional whose condition is always false is a good way to exclude
+code from the program but keep it as a sort of comment for future
+reference.
+@end itemize
+
+Most simple programs that are intended to run on only one machine will
+not need to use preprocessor conditionals.
+
+@node Conditional Syntax
+@subsection Syntax of Conditionals
+
+@findex #if
+A conditional in the C preprocessor begins with a @dfn{conditional
+command}: @samp{#if}, @samp{#ifdef} or @samp{#ifndef}.
+@xref{Conditionals-Macros}, for information on @samp{#ifdef} and
+@samp{#ifndef}; only @samp{#if} is explained here.
+
+@menu
+* If: #if Command. Basic conditionals using @samp{#if} and @samp{#endif}.
+* Else: #else Command. Including some text if the condition fails.
+* Elif: #elif Command. Testing several alternative possibilities.
+@end menu
+
+@node #if Command
+@subsubsection The @samp{#if} Command
+
+The @samp{#if} command in its simplest form consists of
+
+@example
+#if @var{expression}
+@var{controlled text}
+#endif /* @var{expression} */
+@end example
+
+The comment following the @samp{#endif} is not required, but it is a good
+practice because it helps people match the @samp{#endif} to the
+corresponding @samp{#if}. Such comments should always be used, except in
+short conditionals that are not nested. In fact, you can put anything at
+all after the @samp{#endif} and it will be ignored by the GNU C preprocessor,
+but only comments are acceptable in ANSI Standard C.
+
+@var{expression} is a C expression of integer type, subject to stringent
+restrictions. It may contain
+
+@itemize @bullet
+@item
+Integer constants, which are all regarded as @code{long} or
+@code{unsigned long}.
+
+@item
+Character constants, which are interpreted according to the character
+set and conventions of the machine and operating system on which the
+preprocessor is running. The GNU C preprocessor uses the C data type
+@samp{char} for these character constants; therefore, whether some
+character codes are negative is determined by the C compiler used to
+compile the preprocessor. If it treats @samp{char} as signed, then
+character codes large enough to set the sign bit will be considered
+negative; otherwise, no character code is considered negative.
+
+@item
+Arithmetic operators for addition, subtraction, multiplication,
+division, bitwise operations, shifts, comparisons, and logical
+operations (@samp{&&} and @samp{||}).
+
+@item
+Identifiers that are not macros, which are all treated as zero(!).
+
+@item
+Macro calls. All macro calls in the expression are expanded before
+actual computation of the expression's value begins.
+@end itemize
+
+Note that @samp{sizeof} operators and @code{enum}-type values are not allowed.
+@code{enum}-type values, like all other identifiers that are not taken
+as macro calls and expanded, are treated as zero.
+
+The @var{controlled text} inside of a conditional can include
+preprocessor commands. Then the commands inside the conditional are
+obeyed only if that branch of the conditional succeeds. The text can
+also contain other conditional groups. However, the @samp{#if} and
+@samp{#endif} commands must balance.
+
+@node #else Command
+@subsubsection The @samp{#else} Command
+
+@findex #else
+The @samp{#else} command can be added to a conditional to provide
+alternative text to be used if the condition is false. This is what
+it looks like:
+
+@example
+#if @var{expression}
+@var{text-if-true}
+#else /* Not @var{expression} */
+@var{text-if-false}
+#endif /* Not @var{expression} */
+@end example
+
+If @var{expression} is nonzero, and thus the @var{text-if-true} is
+active, then @samp{#else} acts like a failing conditional and the
+@var{text-if-false} is ignored. Contrariwise, if the @samp{#if}
+conditional fails, the @var{text-if-false} is considered included.
+
+@node #elif Command
+@subsubsection The @samp{#elif} Command
+
+@findex #elif
+One common case of nested conditionals is used to check for more than two
+possible alternatives. For example, you might have
+
+@example
+#if X == 1
+@dots{}
+#else /* X != 1 */
+#if X == 2
+@dots{}
+#else /* X != 2 */
+@dots{}
+#endif /* X != 2 */
+#endif /* X != 1 */
+@end example
+
+Another conditional command, @samp{#elif}, allows this to be abbreviated
+as follows:
+
+@example
+#if X == 1
+@dots{}
+#elif X == 2
+@dots{}
+#else /* X != 2 and X != 1*/
+@dots{}
+#endif /* X != 2 and X != 1*/
+@end example
+
+@samp{#elif} stands for ``else if''. Like @samp{#else}, it goes in the
+middle of a @samp{#if}-@samp{#endif} pair and subdivides it; it does not
+require a matching @samp{#endif} of its own. Like @samp{#if}, the
+@samp{#elif} command includes an expression to be tested.
+
+The text following the @samp{#elif} is processed only if the original
+@samp{#if}-condition failed and the @samp{#elif} condition succeeds.
+More than one @samp{#elif} can go in the same @samp{#if}-@samp{#endif}
+group. Then the text after each @samp{#elif} is processed only if the
+@samp{#elif} condition succeeds after the original @samp{#if} and any
+previous @samp{#elif} commands within it have failed. @samp{#else} is
+equivalent to @samp{#elif 1}, and @samp{#else} is allowed after any
+number of @samp{#elif} commands, but @samp{#elif} may not follow
+@samp{#else}.
+
+@node Deleted Code
+@subsection Keeping Deleted Code for Future Reference
+@cindex commenting out code
+
+If you replace or delete a part of the program but want to keep the old
+code around as a comment for future reference, the easy way to do this
+is to put @samp{#if 0} before it and @samp{#endif} after it. This is
+better than using comment delimiters @samp{/*} and @samp{*/} since those
+won't work if the code already contains comments (C comments do not
+nest).
+
+This works even if the code being turned off contains conditionals, but
+they must be entire conditionals (balanced @samp{#if} and @samp{#endif}).
+
+Conversely, do not use @samp{#if 0} for comments which are not C code.
+Use the comment delimiters @samp{/*} and @samp{*/} instead. The
+interior of @samp{#if 0} must consist of complete tokens; in particular,
+singlequote characters must balance. But comments often contain
+unbalanced singlequote characters (known in English as apostrophes).
+These confuse @samp{#if 0}. They do not confuse @samp{/*}.
+
+@node Conditionals-Macros
+@subsection Conditionals and Macros
+
+Conditionals are useful in connection with macros or assertions, because
+those are the only ways that an expression's value can vary from one
+compilation to another. A @samp{#if} command whose expression uses no
+macros or assertions is equivalent to @samp{#if 1} or @samp{#if 0}; you
+might as well determine which one, by computing the value of the
+expression yourself, and then simplify the program.
+
+For example, here is a conditional that tests the expression
+@samp{BUFSIZE == 1020}, where @samp{BUFSIZE} must be a macro.
+
+@example
+#if BUFSIZE == 1020
+ printf ("Large buffers!\n");
+#endif /* BUFSIZE is large */
+@end example
+
+(Programmers often wish they could test the size of a variable or data
+type in @samp{#if}, but this does not work. The preprocessor does not
+understand @code{sizeof}, or typedef names, or even the type keywords
+such as @code{int}.)
+
+@findex defined
+The special operator @samp{defined} is used in @samp{#if} expressions to
+test whether a certain name is defined as a macro. Either @samp{defined
+@var{name}} or @samp{defined (@var{name})} is an expression whose value
+is 1 if @var{name} is defined as macro at the current point in the
+program, and 0 otherwise. For the @samp{defined} operator it makes no
+difference what the definition of the macro is; all that matters is
+whether there is a definition. Thus, for example,@refill
+
+@example
+#if defined (vax) || defined (ns16000)
+@end example
+
+@noindent
+would succeed if either of the names @samp{vax} and @samp{ns16000} is
+defined as a macro. You can test the same condition using assertions
+(@pxref{Assertions}), like this:
+
+@example
+#if #cpu (vax) || #cpu (ns16000)
+@end example
+
+If a macro is defined and later undefined with @samp{#undef},
+subsequent use of the @samp{defined} operator returns 0, because
+the name is no longer defined. If the macro is defined again with
+another @samp{#define}, @samp{defined} will recommence returning 1.
+
+@findex #ifdef
+@findex #ifndef
+Conditionals that test whether just one name is defined are very common,
+so there are two special short conditional commands for this case.
+
+@table @code
+@item #ifdef @var{name}
+is equivalent to @samp{#if defined (@var{name})}.
+
+@item #ifndef @var{name}
+is equivalent to @samp{#if ! defined (@var{name})}.
+@end table
+
+Macro definitions can vary between compilations for several reasons.
+
+@itemize @bullet
+@item
+Some macros are predefined on each kind of machine. For example, on a
+Vax, the name @samp{vax} is a predefined macro. On other machines, it
+would not be defined.
+
+@item
+Many more macros are defined by system header files. Different
+systems and machines define different macros, or give them different
+values. It is useful to test these macros with conditionals to avoid
+using a system feature on a machine where it is not implemented.
+
+@item
+Macros are a common way of allowing users to customize a program for
+different machines or applications. For example, the macro
+@samp{BUFSIZE} might be defined in a configuration file for your
+program that is included as a header file in each source file. You
+would use @samp{BUFSIZE} in a preprocessor conditional in order to
+generate different code depending on the chosen configuration.
+
+@item
+Macros can be defined or undefined with @samp{-D} and @samp{-U}
+command options when you compile the program. You can arrange to
+compile the same source file into two different programs by choosing
+a macro name to specify which program you want, writing conditionals
+to test whether or how this macro is defined, and then controlling
+the state of the macro with compiler command options.
+@xref{Invocation}.
+@end itemize
+
+@ifinfo
+Assertions are usually predefined, but can be defined with preprocessor
+commands or command-line options.
+@end ifinfo
+
+@node Assertions
+@subsection Assertions
+
+@cindex assertions
+@dfn{Assertions} are a more systematic alternative to macros in writing
+conditionals to test what sort of computer or system the compiled
+program will run on. Assertions are usually predefined, but you can
+define them with preprocessor commands or command-line options.
+
+@cindex predicates
+The macros traditionally used to describe the type of target are not
+classified in any way according to which question they answer; they may
+indicate a hardware architecture, a particular hardware model, an
+operating system, a particular version of an operating system, or
+specific configuration options. These are jumbled together in a single
+namespace. In contrast, each assertion consists of a named question and
+an answer. The question is usually called the @dfn{predicate}.
+An assertion looks like this:
+
+@example
+#@var{predicate} (@var{answer})
+@end example
+
+@noindent
+You must use a properly formed identifier for @var{predicate}. The
+value of @var{answer} can be any sequence of words; all characters are
+significant except for leading and trailing whitespace, and differences
+in internal whitespace sequences are ignored. Thus, @samp{x + y} is
+different from @samp{x+y} but equivalent to @samp{x + y}. @samp{)} is
+not allowed in an answer.
+
+@cindex testing predicates
+Here is a conditional to test whether the answer @var{answer} is asserted
+for the predicate @var{predicate}:
+
+@example
+#if #@var{predicate} (@var{answer})
+@end example
+
+@noindent
+There may be more than one answer asserted for a given predicate. If
+you omit the answer, you can test whether @emph{any} answer is asserted
+for @var{predicate}:
+
+@example
+#if #@var{predicate}
+@end example
+
+@findex #system
+@findex #machine
+@findex #cpu
+Most of the time, the assertions you test will be predefined assertions.
+GNU C provides three predefined predicates: @code{system}, @code{cpu},
+and @code{machine}. @code{system} is for assertions about the type of
+software, @code{cpu} describes the type of computer architecture, and
+@code{machine} gives more information about the computer. For example,
+on a GNU system, the following assertions would be true:
+
+@example
+#system (gnu)
+#system (mach)
+#system (mach 3)
+#system (mach 3.@var{subversion})
+#system (hurd)
+#system (hurd @var{version})
+@end example
+
+@noindent
+and perhaps others. The alternatives with
+more or less version information let you ask more or less detailed
+questions about the type of system software.
+
+On a Unix system, you would find @code{#system (unix)} and perhaps one of:
+@code{#system (aix)}, @code{#system (bsd)}, @code{#system (hpux)},
+@code{#system (lynx)}, @code{#system (mach)}, @code{#system (posix)},
+@code{#system (svr3)}, @code{#system (svr4)}, or @code{#system (xpg4)}
+with possible version numbers following.
+
+Other values for @code{system} are @code{#system (mvs)}
+and @code{#system (vms)}.
+
+@strong{Portability note:} Many Unix C compilers provide only one answer
+for the @code{system} assertion: @code{#system (unix)}, if they support
+assertions at all. This is less than useful.
+
+An assertion with a multi-word answer is completely different from several
+assertions with individual single-word answers. For example, the presence
+of @code{system (mach 3.0)} does not mean that @code{system (3.0)} is true.
+It also does not directly imply @code{system (mach)}, but in GNU C, that
+last will normally be asserted as well.
+
+The current list of possible assertion values for @code{cpu} is:
+@code{#cpu (a29k)}, @code{#cpu (alpha)}, @code{#cpu (arm)}, @code{#cpu
+(clipper)}, @code{#cpu (convex)}, @code{#cpu (elxsi)}, @code{#cpu
+(tron)}, @code{#cpu (h8300)}, @code{#cpu (i370)}, @code{#cpu (i386)},
+@code{#cpu (i860)}, @code{#cpu (i960)}, @code{#cpu (m68k)}, @code{#cpu
+(m88k)}, @code{#cpu (mips)}, @code{#cpu (ns32k)}, @code{#cpu (hppa)},
+@code{#cpu (pyr)}, @code{#cpu (ibm032)}, @code{#cpu (rs6000)},
+@code{#cpu (sh)}, @code{#cpu (sparc)}, @code{#cpu (spur)}, @code{#cpu
+(tahoe)}, @code{#cpu (vax)}, @code{#cpu (we32000)}.
+
+@findex #assert
+You can create assertions within a C program using @samp{#assert}, like
+this:
+
+@example
+#assert @var{predicate} (@var{answer})
+@end example
+
+@noindent
+(Note the absence of a @samp{#} before @var{predicate}.)
+
+@cindex unassert
+@cindex assertions, undoing
+@cindex retracting assertions
+@findex #unassert
+Each time you do this, you assert a new true answer for @var{predicate}.
+Asserting one answer does not invalidate previously asserted answers;
+they all remain true. The only way to remove an assertion is with
+@samp{#unassert}. @samp{#unassert} has the same syntax as
+@samp{#assert}. You can also remove all assertions about
+@var{predicate} like this:
+
+@example
+#unassert @var{predicate}
+@end example
+
+You can also add or cancel assertions using command options
+when you run @code{gcc} or @code{cpp}. @xref{Invocation}.
+
+@node #error Command
+@subsection The @samp{#error} and @samp{#warning} Commands
+
+@findex #error
+The command @samp{#error} causes the preprocessor to report a fatal
+error. The rest of the line that follows @samp{#error} is used as the
+error message.
+
+You would use @samp{#error} inside of a conditional that detects a
+combination of parameters which you know the program does not properly
+support. For example, if you know that the program will not run
+properly on a Vax, you might write
+
+@smallexample
+@group
+#ifdef __vax__
+#error Won't work on Vaxen. See comments at get_last_object.
+#endif
+@end group
+@end smallexample
+
+@noindent
+@xref{Nonstandard Predefined}, for why this works.
+
+If you have several configuration parameters that must be set up by
+the installation in a consistent way, you can use conditionals to detect
+an inconsistency and report it with @samp{#error}. For example,
+
+@smallexample
+#if HASH_TABLE_SIZE % 2 == 0 || HASH_TABLE_SIZE % 3 == 0 \
+ || HASH_TABLE_SIZE % 5 == 0
+#error HASH_TABLE_SIZE should not be divisible by a small prime
+#endif
+@end smallexample
+
+@findex #warning
+The command @samp{#warning} is like the command @samp{#error}, but causes
+the preprocessor to issue a warning and continue preprocessing. The rest of
+the line that follows @samp{#warning} is used as the warning message.
+
+You might use @samp{#warning} in obsolete header files, with a message
+directing the user to the header file which should be used instead.
+
+@node Combining Sources, Other Commands, Conditionals, Top
+@section Combining Source Files
+
+@cindex line control
+One of the jobs of the C preprocessor is to inform the C compiler of where
+each line of C code came from: which source file and which line number.
+
+C code can come from multiple source files if you use @samp{#include};
+both @samp{#include} and the use of conditionals and macros can cause
+the line number of a line in the preprocessor output to be different
+from the line's number in the original source file. You will appreciate
+the value of making both the C compiler (in error messages) and symbolic
+debuggers such as GDB use the line numbers in your source file.
+
+The C preprocessor builds on this feature by offering a command by which
+you can control the feature explicitly. This is useful when a file for
+input to the C preprocessor is the output from another program such as the
+@code{bison} parser generator, which operates on another file that is the
+true source file. Parts of the output from @code{bison} are generated from
+scratch, other parts come from a standard parser file. The rest are copied
+nearly verbatim from the source file, but their line numbers in the
+@code{bison} output are not the same as their original line numbers.
+Naturally you would like compiler error messages and symbolic debuggers to
+know the original source file and line number of each line in the
+@code{bison} input.
+
+@findex #line
+@code{bison} arranges this by writing @samp{#line} commands into the output
+file. @samp{#line} is a command that specifies the original line number
+and source file name for subsequent input in the current preprocessor input
+file. @samp{#line} has three variants:
+
+@table @code
+@item #line @var{linenum}
+Here @var{linenum} is a decimal integer constant. This specifies that
+the line number of the following line of input, in its original source file,
+was @var{linenum}.
+
+@item #line @var{linenum} @var{filename}
+Here @var{linenum} is a decimal integer constant and @var{filename}
+is a string constant. This specifies that the following line of input
+came originally from source file @var{filename} and its line number there
+was @var{linenum}. Keep in mind that @var{filename} is not just a
+file name; it is surrounded by doublequote characters so that it looks
+like a string constant.
+
+@item #line @var{anything else}
+@var{anything else} is checked for macro calls, which are expanded.
+The result should be a decimal integer constant followed optionally
+by a string constant, as described above.
+@end table
+
+@samp{#line} commands alter the results of the @samp{__FILE__} and
+@samp{__LINE__} predefined macros from that point on. @xref{Standard
+Predefined}.
+
+The output of the preprocessor (which is the input for the rest of the
+compiler) contains commands that look much like @samp{#line} commands.
+They start with just @samp{#} instead of @samp{#line}, but this is
+followed by a line number and file name as in @samp{#line}. @xref{Output}.
+
+@node Other Commands, Output, Combining Sources, Top
+@section Miscellaneous Preprocessor Commands
+
+@cindex null command
+This section describes three additional preprocessor commands. They are
+not very useful, but are mentioned for completeness.
+
+The @dfn{null command} consists of a @samp{#} followed by a Newline, with
+only whitespace (including comments) in between. A null command is
+understood as a preprocessor command but has no effect on the preprocessor
+output. The primary significance of the existence of the null command is
+that an input line consisting of just a @samp{#} will produce no output,
+rather than a line of output containing just a @samp{#}. Supposedly
+some old C programs contain such lines.
+
+@findex #pragma
+The ANSI standard specifies that the @samp{#pragma} command has an
+arbitrary, implementation-defined effect. In the GNU C preprocessor,
+@samp{#pragma} commands are not used, except for @samp{#pragma once}
+(@pxref{Once-Only}). However, they are left in the preprocessor output,
+so they are available to the compilation pass.
+
+@findex #ident
+The @samp{#ident} command is supported for compatibility with certain
+other systems. It is followed by a line of text. On some systems, the
+text is copied into a special place in the object file; on most systems,
+the text is ignored and this command has no effect. Typically
+@samp{#ident} is only used in header files supplied with those systems
+where it is meaningful.
+
+@node Output, Invocation, Other Commands, Top
+@section C Preprocessor Output
+
+@cindex output format
+The output from the C preprocessor looks much like the input, except
+that all preprocessor command lines have been replaced with blank lines
+and all comments with spaces. Whitespace within a line is not altered;
+however, a space is inserted after the expansions of most macro calls.
+
+Source file name and line number information is conveyed by lines of
+the form
+
+@example
+# @var{linenum} @var{filename} @var{flags}
+@end example
+
+@noindent
+which are inserted as needed into the middle of the input (but never
+within a string or character constant). Such a line means that the
+following line originated in file @var{filename} at line @var{linenum}.
+
+After the file name comes zero or more flags, which are @samp{1},
+@samp{2} or @samp{3}. If there are multiple flags, spaces separate
+them. Here is what the flags mean:
+
+@table @samp
+@item 1
+This indicates the start of a new file.
+@item 2
+This indicates returning to a file (after having included another file).
+@item 3
+This indicates that the following text comes from a system header file,
+so certain warnings should be suppressed.
+@end table
+
+@node Invocation, Concept Index, Output, Top
+@section Invoking the C Preprocessor
+@cindex invocation of the preprocessor
+
+Most often when you use the C preprocessor you will not have to invoke it
+explicitly: the C compiler will do so automatically. However, the
+preprocessor is sometimes useful on its own.
+
+The C preprocessor expects two file names as arguments, @var{infile} and
+@var{outfile}. The preprocessor reads @var{infile} together with any other
+files it specifies with @samp{#include}. All the output generated by the
+combined input files is written in @var{outfile}.
+
+Either @var{infile} or @var{outfile} may be @samp{-}, which as @var{infile}
+means to read from standard input and as @var{outfile} means to write to
+standard output. Also, if @var{outfile} or both file names are omitted,
+the standard output and standard input are used for the omitted file names.
+
+@cindex options
+Here is a table of command options accepted by the C preprocessor.
+These options can also be given when compiling a C program; they are
+passed along automatically to the preprocessor when it is invoked by the
+compiler.
+
+@table @samp
+@item -P
+@findex -P
+Inhibit generation of @samp{#}-lines with line-number information in
+the output from the preprocessor (@pxref{Output}). This might be
+useful when running the preprocessor on something that is not C code
+and will be sent to a program which might be confused by the
+@samp{#}-lines.
+
+@item -C
+@findex -C
+Do not discard comments: pass them through to the output file.
+Comments appearing in arguments of a macro call will be copied to the
+output before the expansion of the macro call.
+
+@item -traditional
+@findex -traditional
+Try to imitate the behavior of old-fashioned C, as opposed to ANSI C.
+
+@itemize @bullet
+@item
+Traditional macro expansion pays no attention to singlequote or
+doublequote characters; macro argument symbols are replaced by the
+argument values even when they appear within apparent string or
+character constants.
+
+@item
+Traditionally, it is permissible for a macro expansion to end in the
+middle of a string or character constant. The constant continues into
+the text surrounding the macro call.
+
+@item
+However, traditionally the end of the line terminates a string or
+character constant, with no error.
+
+@item
+In traditional C, a comment is equivalent to no text at all. (In ANSI
+C, a comment counts as whitespace.)
+
+@item
+Traditional C does not have the concept of a ``preprocessing number''.
+It considers @samp{1.0e+4} to be three tokens: @samp{1.0e}, @samp{+},
+and @samp{4}.
+
+@item
+A macro is not suppressed within its own definition, in traditional C.
+Thus, any macro that is used recursively inevitably causes an error.
+
+@item
+The character @samp{#} has no special meaning within a macro definition
+in traditional C.
+
+@item
+In traditional C, the text at the end of a macro expansion can run
+together with the text after the macro call, to produce a single token.
+(This is impossible in ANSI C.)
+
+@item
+Traditionally, @samp{\} inside a macro argument suppresses the syntactic
+significance of the following character.
+@end itemize
+
+@item -trigraphs
+@findex -trigraphs
+Process ANSI standard trigraph sequences. These are three-character
+sequences, all starting with @samp{??}, that are defined by ANSI C to
+stand for single characters. For example, @samp{??/} stands for
+@samp{\}, so @samp{'??/n'} is a character constant for a newline.
+Strictly speaking, the GNU C preprocessor does not support all
+programs in ANSI Standard C unless @samp{-trigraphs} is used, but if
+you ever notice the difference it will be with relief.
+
+You don't want to know any more about trigraphs.
+
+@item -pedantic
+@findex -pedantic
+Issue warnings required by the ANSI C standard in certain cases such
+as when text other than a comment follows @samp{#else} or @samp{#endif}.
+
+@item -pedantic-errors
+@findex -pedantic-errors
+Like @samp{-pedantic}, except that errors are produced rather than
+warnings.
+
+@item -Wtrigraphs
+@findex -Wtrigraphs
+Warn if any trigraphs are encountered (assuming they are enabled).
+
+@item -Wcomment
+@findex -Wcomment
+@ignore
+@c "Not worth documenting" both singular and plural forms of this
+@c option, per RMS. But also unclear which is better; hence may need to
+@c switch this at some future date. pesch@cygnus.com, 2jan92.
+@itemx -Wcomments
+(Both forms have the same effect).
+@end ignore
+Warn whenever a comment-start sequence @samp{/*} appears in a comment.
+
+@item -Wall
+@findex -Wall
+Requests both @samp{-Wtrigraphs} and @samp{-Wcomment} (but not
+@samp{-Wtraditional}).
+
+@item -Wtraditional
+@findex -Wtraditional
+Warn about certain constructs that behave differently in traditional and
+ANSI C.
+
+@item -I @var{directory}
+@findex -I
+Add the directory @var{directory} to the end of the list of
+directories to be searched for header files (@pxref{Include Syntax}).
+This can be used to override a system header file, substituting your
+own version, since these directories are searched before the system
+header file directories. If you use more than one @samp{-I} option,
+the directories are scanned in left-to-right order; the standard
+system directories come after.
+
+@item -I-
+Any directories specified with @samp{-I} options before the @samp{-I-}
+option are searched only for the case of @samp{#include "@var{file}"};
+they are not searched for @samp{#include <@var{file}>}.
+
+If additional directories are specified with @samp{-I} options after
+the @samp{-I-}, these directories are searched for all @samp{#include}
+commands.
+
+In addition, the @samp{-I-} option inhibits the use of the current
+directory as the first search directory for @samp{#include "@var{file}"}.
+Therefore, the current directory is searched only if it is requested
+explicitly with @samp{-I.}. Specifying both @samp{-I-} and @samp{-I.}
+allows you to control precisely which directories are searched before
+the current one and which are searched after.
+
+@item -nostdinc
+@findex -nostdinc
+Do not search the standard system directories for header files.
+Only the directories you have specified with @samp{-I} options
+(and the current directory, if appropriate) are searched.
+
+@item -nostdinc++
+@findex -nostdinc++
+Do not search for header files in the C++-specific standard directories,
+but do still search the other standard directories.
+(This option is used when building libg++.)
+
+@item -D @var{name}
+@findex -D
+Predefine @var{name} as a macro, with definition @samp{1}.
+
+@item -D @var{name}=@var{definition}
+Predefine @var{name} as a macro, with definition @var{definition}.
+There are no restrictions on the contents of @var{definition}, but if
+you are invoking the preprocessor from a shell or shell-like program you
+may need to use the shell's quoting syntax to protect characters such as
+spaces that have a meaning in the shell syntax. If you use more than
+one @samp{-D} for the same @var{name}, the rightmost definition takes
+effect.
+
+@item -U @var{name}
+@findex -U
+Do not predefine @var{name}. If both @samp{-U} and @samp{-D} are
+specified for one name, the @samp{-U} beats the @samp{-D} and the name
+is not predefined.
+
+@item -undef
+@findex -undef
+Do not predefine any nonstandard macros.
+
+@item -A @var{predicate}(@var{answer})
+@findex -A
+Make an assertion with the predicate @var{predicate} and answer
+@var{answer}. @xref{Assertions}.
+
+@noindent
+You can use @samp{-A-} to disable all predefined assertions; it also
+undefines all predefined macros that identify the type of target system.
+
+@item -dM
+@findex -dM
+Instead of outputting the result of preprocessing, output a list of
+@samp{#define} commands for all the macros defined during the
+execution of the preprocessor, including predefined macros. This gives
+you a way of finding out what is predefined in your version of the
+preprocessor; assuming you have no file @samp{foo.h}, the command
+
+@example
+touch foo.h; cpp -dM foo.h
+@end example
+
+@noindent
+will show the values of any predefined macros.
+
+@item -dD
+@findex -dD
+Like @samp{-dM} except in two respects: it does @emph{not} include the
+predefined macros, and it outputs @emph{both} the @samp{#define}
+commands and the result of preprocessing. Both kinds of output go to
+the standard output file.
+
+@item -M [-MG]
+@findex -M
+Instead of outputting the result of preprocessing, output a rule
+suitable for @code{make} describing the dependencies of the main
+source file. The preprocessor outputs one @code{make} rule containing
+the object file name for that source file, a colon, and the names of
+all the included files. If there are many included files then the
+rule is split into several lines using @samp{\}-newline.
+
+@samp{-MG} says to treat missing header files as generated files and assume
+they live in the same directory as the source file. It must be specified
+in addition to @samp{-M}.
+
+This feature is used in automatic updating of makefiles.
+
+@item -MM [-MG]
+@findex -MM
+Like @samp{-M} but mention only the files included with @samp{#include
+"@var{file}"}. System header files included with @samp{#include
+<@var{file}>} are omitted.
+
+@item -MD @var{file}
+@findex -MD
+Like @samp{-M} but the dependency information is written to @var{file}.
+This is in addition to compiling the file as specified---@samp{-MD} does
+not inhibit ordinary compilation the way @samp{-M} does.
+
+When invoking gcc, do not specify the @var{file} argument.
+Gcc will create file names made by replacing ".c" with ".d" at
+the end of the input file names.
+
+In Mach, you can use the utility @code{md} to merge multiple dependency
+files into a single dependency file suitable for using with the @samp{make}
+command.
+
+@item -MMD @var{file}
+@findex -MMD
+Like @samp{-MD} except mention only user header files, not system
+header files.
+
+@item -H
+@findex -H
+Print the name of each header file used, in addition to other normal
+activities.
+
+@item -imacros @var{file}
+@findex -imacros
+Process @var{file} as input, discarding the resulting output, before
+processing the regular input file. Because the output generated from
+@var{file} is discarded, the only effect of @samp{-imacros @var{file}}
+is to make the macros defined in @var{file} available for use in the
+main input.
+
+@item -include @var{file}
+@findex -include
+Process @var{file} as input, and include all the resulting output,
+before processing the regular input file.
+
+@item -idirafter @var{dir}
+@findex -idirafter
+@cindex second include path
+Add the directory @var{dir} to the second include path. The directories
+on the second include path are searched when a header file is not found
+in any of the directories in the main include path (the one that
+@samp{-I} adds to).
+
+@item -iprefix @var{prefix}
+@findex -iprefix
+Specify @var{prefix} as the prefix for subsequent @samp{-iwithprefix}
+options.
+
+@item -iwithprefix @var{dir}
+@findex -iwithprefix
+Add a directory to the second include path. The directory's name is
+made by concatenating @var{prefix} and @var{dir}, where @var{prefix}
+was specified previously with @samp{-iprefix}.
+
+@item -isystem @var{dir}
+@findex -isystem
+Add a directory to the beginning of the second include path, marking it
+as a system directory, so that it gets the same special treatment as
+is applied to the standard system directories.
+
+@item -lang-c
+@itemx -lang-c++
+@itemx -lang-objc
+@itemx -lang-objc++
+@findex -lang-c
+@findex -lang-c++
+@findex -lang-objc
+@findex -lang-objc++
+Specify the source language. @samp{-lang-c++} makes the preprocessor
+handle C++ comment syntax (comments may begin with @samp{//}, in which
+case they end at end of line), and includes extra default include
+directories for C++; and @samp{-lang-objc} enables the Objective C
+@samp{#import} command. @samp{-lang-c} explicitly turns off both of
+these extensions, and @samp{-lang-objc++} enables both.
+
+These options are generated by the compiler driver @code{gcc}, but not
+passed from the @samp{gcc} command line.
+
+@item -lint
+Look for commands to the program checker @code{lint} embedded in
+comments, and emit them preceded by @samp{#pragma lint}. For example,
+the comment @samp{/* NOTREACHED */} becomes @samp{#pragma lint
+NOTREACHED}.
+
+This option is available only when you call @code{cpp} directly;
+@code{gcc} will not pass it from its command line.
+
+@item -$
+@findex -$
+Forbid the use of @samp{$} in identifiers. This is required for ANSI
+conformance. @code{gcc} automatically supplies this option to the
+preprocessor if you specify @samp{-ansi}, but @code{gcc} doesn't
+recognize the @samp{-$} option itself---to use it without the other
+effects of @samp{-ansi}, you must call the preprocessor directly.
+
+@end table
+
+@node Concept Index, Index, Invocation, Top
+@unnumbered Concept Index
+@printindex cp
+
+@node Index,, Concept Index, Top
+@unnumbered Index of Commands, Macros and Options
+@printindex fn
+
+@contents
+@bye
diff --git a/gnu/usr.bin/cc/doc/extend.texi b/gnu/usr.bin/cc/doc/extend.texi
new file mode 100644
index 0000000..13e8aa4
--- /dev/null
+++ b/gnu/usr.bin/cc/doc/extend.texi
@@ -0,0 +1,2919 @@
+@c Copyright (C) 1988, 1989, 1992, 1993, 1994 Free Software Foundation, Inc.
+@c This is part of the GCC manual.
+@c For copying conditions, see the file gcc.texi.
+
+@node C Extensions
+@chapter Extensions to the C Language Family
+@cindex extensions, C language
+@cindex C language extensions
+
+GNU C provides several language features not found in ANSI standard C.
+(The @samp{-pedantic} option directs GNU CC to print a warning message if
+any of these features is used.) To test for the availability of these
+features in conditional compilation, check for a predefined macro
+@code{__GNUC__}, which is always defined under GNU CC.
+
+These extensions are available in C and Objective C. Most of them are
+also available in C++. @xref{C++ Extensions,,Extensions to the
+C++ Language}, for extensions that apply @emph{only} to C++.
+
+@c The only difference between the two versions of this menu is that the
+@c version for clear INTERNALS has an extra node, "Constraints" (which
+@c appears in a separate chapter in the other version of the manual).
+@ifset INTERNALS
+@menu
+* Statement Exprs:: Putting statements and declarations inside expressions.
+* Local Labels:: Labels local to a statement-expression.
+* Labels as Values:: Getting pointers to labels, and computed gotos.
+* Nested Functions:: As in Algol and Pascal, lexical scoping of functions.
+* Constructing Calls:: Dispatching a call to another function.
+* Naming Types:: Giving a name to the type of some expression.
+* Typeof:: @code{typeof}: referring to the type of an expression.
+* Lvalues:: Using @samp{?:}, @samp{,} and casts in lvalues.
+* Conditionals:: Omitting the middle operand of a @samp{?:} expression.
+* Long Long:: Double-word integers---@code{long long int}.
+* Complex:: Data types for complex numbers.
+* Zero Length:: Zero-length arrays.
+* Variable Length:: Arrays whose length is computed at run time.
+* Macro Varargs:: Macros with variable number of arguments.
+* Subscripting:: Any array can be subscripted, even if not an lvalue.
+* Pointer Arith:: Arithmetic on @code{void}-pointers and function pointers.
+* Initializers:: Non-constant initializers.
+* Constructors:: Constructor expressions give structures, unions
+ or arrays as values.
+* Labeled Elements:: Labeling elements of initializers.
+* Cast to Union:: Casting to union type from any member of the union.
+* Case Ranges:: `case 1 ... 9' and such.
+* Function Attributes:: Declaring that functions have no side effects,
+ or that they can never return.
+* Function Prototypes:: Prototype declarations and old-style definitions.
+* Dollar Signs:: Dollar sign is allowed in identifiers.
+* Character Escapes:: @samp{\e} stands for the character @key{ESC}.
+* Variable Attributes:: Specifying attributes of variables.
+* Alignment:: Inquiring about the alignment of a type or variable.
+* Inline:: Defining inline functions (as fast as macros).
+* Extended Asm:: Assembler instructions with C expressions as operands.
+ (With them you can define ``built-in'' functions.)
+* Asm Labels:: Specifying the assembler name to use for a C symbol.
+* Explicit Reg Vars:: Defining variables residing in specified registers.
+* Alternate Keywords:: @code{__const__}, @code{__asm__}, etc., for header files.
+* Incomplete Enums:: @code{enum foo;}, with details to follow.
+* Function Names:: Printable strings which are the name of the current
+ function.
+@end menu
+@end ifset
+@ifclear INTERNALS
+@menu
+* Statement Exprs:: Putting statements and declarations inside expressions.
+* Local Labels:: Labels local to a statement-expression.
+* Labels as Values:: Getting pointers to labels, and computed gotos.
+* Nested Functions:: As in Algol and Pascal, lexical scoping of functions.
+* Constructing Calls:: Dispatching a call to another function.
+* Naming Types:: Giving a name to the type of some expression.
+* Typeof:: @code{typeof}: referring to the type of an expression.
+* Lvalues:: Using @samp{?:}, @samp{,} and casts in lvalues.
+* Conditionals:: Omitting the middle operand of a @samp{?:} expression.
+* Long Long:: Double-word integers---@code{long long int}.
+* Complex:: Data types for complex numbers.
+* Zero Length:: Zero-length arrays.
+* Variable Length:: Arrays whose length is computed at run time.
+* Macro Varargs:: Macros with variable number of arguments.
+* Subscripting:: Any array can be subscripted, even if not an lvalue.
+* Pointer Arith:: Arithmetic on @code{void}-pointers and function pointers.
+* Initializers:: Non-constant initializers.
+* Constructors:: Constructor expressions give structures, unions
+ or arrays as values.
+* Labeled Elements:: Labeling elements of initializers.
+* Cast to Union:: Casting to union type from any member of the union.
+* Case Ranges:: `case 1 ... 9' and such.
+* Function Attributes:: Declaring that functions have no side effects,
+ or that they can never return.
+* Function Prototypes:: Prototype declarations and old-style definitions.
+* Dollar Signs:: Dollar sign is allowed in identifiers.
+* Character Escapes:: @samp{\e} stands for the character @key{ESC}.
+* Variable Attributes:: Specifying attributes of variables.
+* Alignment:: Inquiring about the alignment of a type or variable.
+* Inline:: Defining inline functions (as fast as macros).
+* Extended Asm:: Assembler instructions with C expressions as operands.
+ (With them you can define ``built-in'' functions.)
+* Constraints:: Constraints for asm operands
+* Asm Labels:: Specifying the assembler name to use for a C symbol.
+* Explicit Reg Vars:: Defining variables residing in specified registers.
+* Alternate Keywords:: @code{__const__}, @code{__asm__}, etc., for header files.
+* Incomplete Enums:: @code{enum foo;}, with details to follow.
+* Function Names:: Printable strings which are the name of the current
+ function.
+@end menu
+@end ifclear
+
+@node Statement Exprs
+@section Statements and Declarations in Expressions
+@cindex statements inside expressions
+@cindex declarations inside expressions
+@cindex expressions containing statements
+@cindex macros, statements in expressions
+
+@c the above section title wrapped and causes an underfull hbox.. i
+@c changed it from "within" to "in". --mew 4feb93
+
+A compound statement enclosed in parentheses may appear as an expression
+in GNU C. This allows you to use loops, switches, and local variables
+within an expression.
+
+Recall that a compound statement is a sequence of statements surrounded
+by braces; in this construct, parentheses go around the braces. For
+example:
+
+@example
+(@{ int y = foo (); int z;
+ if (y > 0) z = y;
+ else z = - y;
+ z; @})
+@end example
+
+@noindent
+is a valid (though slightly more complex than necessary) expression
+for the absolute value of @code{foo ()}.
+
+The last thing in the compound statement should be an expression
+followed by a semicolon; the value of this subexpression serves as the
+value of the entire construct. (If you use some other kind of statement
+last within the braces, the construct has type @code{void}, and thus
+effectively no value.)
+
+This feature is especially useful in making macro definitions ``safe'' (so
+that they evaluate each operand exactly once). For example, the
+``maximum'' function is commonly defined as a macro in standard C as
+follows:
+
+@example
+#define max(a,b) ((a) > (b) ? (a) : (b))
+@end example
+
+@noindent
+@cindex side effects, macro argument
+But this definition computes either @var{a} or @var{b} twice, with bad
+results if the operand has side effects. In GNU C, if you know the
+type of the operands (here let's assume @code{int}), you can define
+the macro safely as follows:
+
+@example
+#define maxint(a,b) \
+ (@{int _a = (a), _b = (b); _a > _b ? _a : _b; @})
+@end example
+
+Embedded statements are not allowed in constant expressions, such as
+the value of an enumeration constant, the width of a bit field, or
+the initial value of a static variable.
+
+If you don't know the type of the operand, you can still do this, but you
+must use @code{typeof} (@pxref{Typeof}) or type naming (@pxref{Naming
+Types}).
+
+@node Local Labels
+@section Locally Declared Labels
+@cindex local labels
+@cindex macros, local labels
+
+Each statement expression is a scope in which @dfn{local labels} can be
+declared. A local label is simply an identifier; you can jump to it
+with an ordinary @code{goto} statement, but only from within the
+statement expression it belongs to.
+
+A local label declaration looks like this:
+
+@example
+__label__ @var{label};
+@end example
+
+@noindent
+or
+
+@example
+__label__ @var{label1}, @var{label2}, @dots{};
+@end example
+
+Local label declarations must come at the beginning of the statement
+expression, right after the @samp{(@{}, before any ordinary
+declarations.
+
+The label declaration defines the label @emph{name}, but does not define
+the label itself. You must do this in the usual way, with
+@code{@var{label}:}, within the statements of the statement expression.
+
+The local label feature is useful because statement expressions are
+often used in macros. If the macro contains nested loops, a @code{goto}
+can be useful for breaking out of them. However, an ordinary label
+whose scope is the whole function cannot be used: if the macro can be
+expanded several times in one function, the label will be multiply
+defined in that function. A local label avoids this problem. For
+example:
+
+@example
+#define SEARCH(array, target) \
+(@{ \
+ __label__ found; \
+ typeof (target) _SEARCH_target = (target); \
+ typeof (*(array)) *_SEARCH_array = (array); \
+ int i, j; \
+ int value; \
+ for (i = 0; i < max; i++) \
+ for (j = 0; j < max; j++) \
+ if (_SEARCH_array[i][j] == _SEARCH_target) \
+ @{ value = i; goto found; @} \
+ value = -1; \
+ found: \
+ value; \
+@})
+@end example
+
+@node Labels as Values
+@section Labels as Values
+@cindex labels as values
+@cindex computed gotos
+@cindex goto with computed label
+@cindex address of a label
+
+You can get the address of a label defined in the current function
+(or a containing function) with the unary operator @samp{&&}. The
+value has type @code{void *}. This value is a constant and can be used
+wherever a constant of that type is valid. For example:
+
+@example
+void *ptr;
+@dots{}
+ptr = &&foo;
+@end example
+
+To use these values, you need to be able to jump to one. This is done
+with the computed goto statement@footnote{The analogous feature in
+Fortran is called an assigned goto, but that name seems inappropriate in
+C, where one can do more than simply store label addresses in label
+variables.}, @code{goto *@var{exp};}. For example,
+
+@example
+goto *ptr;
+@end example
+
+@noindent
+Any expression of type @code{void *} is allowed.
+
+One way of using these constants is in initializing a static array that
+will serve as a jump table:
+
+@example
+static void *array[] = @{ &&foo, &&bar, &&hack @};
+@end example
+
+Then you can select a label with indexing, like this:
+
+@example
+goto *array[i];
+@end example
+
+@noindent
+Note that this does not check whether the subscript is in bounds---array
+indexing in C never does that.
+
+Such an array of label values serves a purpose much like that of the
+@code{switch} statement. The @code{switch} statement is cleaner, so
+use that rather than an array unless the problem does not fit a
+@code{switch} statement very well.
+
+Another use of label values is in an interpreter for threaded code.
+The labels within the interpreter function can be stored in the
+threaded code for super-fast dispatching.
+
+You can use this mechanism to jump to code in a different function. If
+you do that, totally unpredictable things will happen. The best way to
+avoid this is to store the label address only in automatic variables and
+never pass it as an argument.
+
+@node Nested Functions
+@section Nested Functions
+@cindex nested functions
+@cindex downward funargs
+@cindex thunks
+
+A @dfn{nested function} is a function defined inside another function.
+(Nested functions are not supported for GNU C++.) The nested function's
+name is local to the block where it is defined. For example, here we
+define a nested function named @code{square}, and call it twice:
+
+@example
+@group
+foo (double a, double b)
+@{
+ double square (double z) @{ return z * z; @}
+
+ return square (a) + square (b);
+@}
+@end group
+@end example
+
+The nested function can access all the variables of the containing
+function that are visible at the point of its definition. This is
+called @dfn{lexical scoping}. For example, here we show a nested
+function which uses an inherited variable named @code{offset}:
+
+@example
+bar (int *array, int offset, int size)
+@{
+ int access (int *array, int index)
+ @{ return array[index + offset]; @}
+ int i;
+ @dots{}
+ for (i = 0; i < size; i++)
+ @dots{} access (array, i) @dots{}
+@}
+@end example
+
+Nested function definitions are permitted within functions in the places
+where variable definitions are allowed; that is, in any block, before
+the first statement in the block.
+
+It is possible to call the nested function from outside the scope of its
+name by storing its address or passing the address to another function:
+
+@example
+hack (int *array, int size)
+@{
+ void store (int index, int value)
+ @{ array[index] = value; @}
+
+ intermediate (store, size);
+@}
+@end example
+
+Here, the function @code{intermediate} receives the address of
+@code{store} as an argument. If @code{intermediate} calls @code{store},
+the arguments given to @code{store} are used to store into @code{array}.
+But this technique works only so long as the containing function
+(@code{hack}, in this example) does not exit.
+
+If you try to call the nested function through its address after the
+containing function has exited, all hell will break loose. If you try
+to call it after a containing scope level has exited, and if it refers
+to some of the variables that are no longer in scope, you may be lucky,
+but it's not wise to take the risk. If, however, the nested function
+does not refer to anything that has gone out of scope, you should be
+safe.
+
+GNU CC implements taking the address of a nested function using a
+technique called @dfn{trampolines}. A paper describing them is
+available from @samp{maya.idiap.ch} in directory @file{pub/tmb},
+file @file{usenix88-lexic.ps.Z}.
+
+A nested function can jump to a label inherited from a containing
+function, provided the label was explicitly declared in the containing
+function (@pxref{Local Labels}). Such a jump returns instantly to the
+containing function, exiting the nested function which did the
+@code{goto} and any intermediate functions as well. Here is an example:
+
+@example
+@group
+bar (int *array, int offset, int size)
+@{
+ __label__ failure;
+ int access (int *array, int index)
+ @{
+ if (index > size)
+ goto failure;
+ return array[index + offset];
+ @}
+ int i;
+ @dots{}
+ for (i = 0; i < size; i++)
+ @dots{} access (array, i) @dots{}
+ @dots{}
+ return 0;
+
+ /* @r{Control comes here from @code{access}
+ if it detects an error.} */
+ failure:
+ return -1;
+@}
+@end group
+@end example
+
+A nested function always has internal linkage. Declaring one with
+@code{extern} is erroneous. If you need to declare the nested function
+before its definition, use @code{auto} (which is otherwise meaningless
+for function declarations).
+
+@example
+bar (int *array, int offset, int size)
+@{
+ __label__ failure;
+ auto int access (int *, int);
+ @dots{}
+ int access (int *array, int index)
+ @{
+ if (index > size)
+ goto failure;
+ return array[index + offset];
+ @}
+ @dots{}
+@}
+@end example
+
+@node Constructing Calls
+@section Constructing Function Calls
+@cindex constructing calls
+@cindex forwarding calls
+
+Using the built-in functions described below, you can record
+the arguments a function received, and call another function
+with the same arguments, without knowing the number or types
+of the arguments.
+
+You can also record the return value of that function call,
+and later return that value, without knowing what data type
+the function tried to return (as long as your caller expects
+that data type).
+
+@table @code
+@findex __builtin_apply_args
+@item __builtin_apply_args ()
+This built-in function returns a pointer of type @code{void *} to data
+describing how to perform a call with the same arguments as were passed
+to the current function.
+
+The function saves the arg pointer register, structure value address,
+and all registers that might be used to pass arguments to a function
+into a block of memory allocated on the stack. Then it returns the
+address of that block.
+
+@findex __builtin_apply
+@item __builtin_apply (@var{function}, @var{arguments}, @var{size})
+This built-in function invokes @var{function} (type @code{void (*)()})
+with a copy of the parameters described by @var{arguments} (type
+@code{void *}) and @var{size} (type @code{int}).
+
+The value of @var{arguments} should be the value returned by
+@code{__builtin_apply_args}. The argument @var{size} specifies the size
+of the stack argument data, in bytes.
+
+This function returns a pointer of type @code{void *} to data describing
+how to return whatever value was returned by @var{function}. The data
+is saved in a block of memory allocated on the stack.
+
+It is not always simple to compute the proper value for @var{size}. The
+value is used by @code{__builtin_apply} to compute the amount of data
+that should be pushed on the stack and copied from the incoming argument
+area.
+
+@findex __builtin_return
+@item __builtin_return (@var{result})
+This built-in function returns the value described by @var{result} from
+the containing function. You should specify, for @var{result}, a value
+returned by @code{__builtin_apply}.
+@end table
+
+@node Naming Types
+@section Naming an Expression's Type
+@cindex naming types
+
+You can give a name to the type of an expression using a @code{typedef}
+declaration with an initializer. Here is how to define @var{name} as a
+type name for the type of @var{exp}:
+
+@example
+typedef @var{name} = @var{exp};
+@end example
+
+This is useful in conjunction with the statements-within-expressions
+feature. Here is how the two together can be used to define a safe
+``maximum'' macro that operates on any arithmetic type:
+
+@example
+#define max(a,b) \
+ (@{typedef _ta = (a), _tb = (b); \
+ _ta _a = (a); _tb _b = (b); \
+ _a > _b ? _a : _b; @})
+@end example
+
+@cindex underscores in variables in macros
+@cindex @samp{_} in variables in macros
+@cindex local variables in macros
+@cindex variables, local, in macros
+@cindex macros, local variables in
+
+The reason for using names that start with underscores for the local
+variables is to avoid conflicts with variable names that occur within the
+expressions that are substituted for @code{a} and @code{b}. Eventually we
+hope to design a new form of declaration syntax that allows you to declare
+variables whose scopes start only after their initializers; this will be a
+more reliable way to prevent such conflicts.
+
+@node Typeof
+@section Referring to a Type with @code{typeof}
+@findex typeof
+@findex sizeof
+@cindex macros, types of arguments
+
+Another way to refer to the type of an expression is with @code{typeof}.
+The syntax of using of this keyword looks like @code{sizeof}, but the
+construct acts semantically like a type name defined with @code{typedef}.
+
+There are two ways of writing the argument to @code{typeof}: with an
+expression or with a type. Here is an example with an expression:
+
+@example
+typeof (x[0](1))
+@end example
+
+@noindent
+This assumes that @code{x} is an array of functions; the type described
+is that of the values of the functions.
+
+Here is an example with a typename as the argument:
+
+@example
+typeof (int *)
+@end example
+
+@noindent
+Here the type described is that of pointers to @code{int}.
+
+If you are writing a header file that must work when included in ANSI C
+programs, write @code{__typeof__} instead of @code{typeof}.
+@xref{Alternate Keywords}.
+
+A @code{typeof}-construct can be used anywhere a typedef name could be
+used. For example, you can use it in a declaration, in a cast, or inside
+of @code{sizeof} or @code{typeof}.
+
+@itemize @bullet
+@item
+This declares @code{y} with the type of what @code{x} points to.
+
+@example
+typeof (*x) y;
+@end example
+
+@item
+This declares @code{y} as an array of such values.
+
+@example
+typeof (*x) y[4];
+@end example
+
+@item
+This declares @code{y} as an array of pointers to characters:
+
+@example
+typeof (typeof (char *)[4]) y;
+@end example
+
+@noindent
+It is equivalent to the following traditional C declaration:
+
+@example
+char *y[4];
+@end example
+
+To see the meaning of the declaration using @code{typeof}, and why it
+might be a useful way to write, let's rewrite it with these macros:
+
+@example
+#define pointer(T) typeof(T *)
+#define array(T, N) typeof(T [N])
+@end example
+
+@noindent
+Now the declaration can be rewritten this way:
+
+@example
+array (pointer (char), 4) y;
+@end example
+
+@noindent
+Thus, @code{array (pointer (char), 4)} is the type of arrays of 4
+pointers to @code{char}.
+@end itemize
+
+@node Lvalues
+@section Generalized Lvalues
+@cindex compound expressions as lvalues
+@cindex expressions, compound, as lvalues
+@cindex conditional expressions as lvalues
+@cindex expressions, conditional, as lvalues
+@cindex casts as lvalues
+@cindex generalized lvalues
+@cindex lvalues, generalized
+@cindex extensions, @code{?:}
+@cindex @code{?:} extensions
+Compound expressions, conditional expressions and casts are allowed as
+lvalues provided their operands are lvalues. This means that you can take
+their addresses or store values into them.
+
+Standard C++ allows compound expressions and conditional expressions as
+lvalues, and permits casts to reference type, so use of this extension
+is deprecated for C++ code.
+
+For example, a compound expression can be assigned, provided the last
+expression in the sequence is an lvalue. These two expressions are
+equivalent:
+
+@example
+(a, b) += 5
+a, (b += 5)
+@end example
+
+Similarly, the address of the compound expression can be taken. These two
+expressions are equivalent:
+
+@example
+&(a, b)
+a, &b
+@end example
+
+A conditional expression is a valid lvalue if its type is not void and the
+true and false branches are both valid lvalues. For example, these two
+expressions are equivalent:
+
+@example
+(a ? b : c) = 5
+(a ? b = 5 : (c = 5))
+@end example
+
+A cast is a valid lvalue if its operand is an lvalue. A simple
+assignment whose left-hand side is a cast works by converting the
+right-hand side first to the specified type, then to the type of the
+inner left-hand side expression. After this is stored, the value is
+converted back to the specified type to become the value of the
+assignment. Thus, if @code{a} has type @code{char *}, the following two
+expressions are equivalent:
+
+@example
+(int)a = 5
+(int)(a = (char *)(int)5)
+@end example
+
+An assignment-with-arithmetic operation such as @samp{+=} applied to a cast
+performs the arithmetic using the type resulting from the cast, and then
+continues as in the previous case. Therefore, these two expressions are
+equivalent:
+
+@example
+(int)a += 5
+(int)(a = (char *)(int) ((int)a + 5))
+@end example
+
+You cannot take the address of an lvalue cast, because the use of its
+address would not work out coherently. Suppose that @code{&(int)f} were
+permitted, where @code{f} has type @code{float}. Then the following
+statement would try to store an integer bit-pattern where a floating
+point number belongs:
+
+@example
+*&(int)f = 1;
+@end example
+
+This is quite different from what @code{(int)f = 1} would do---that
+would convert 1 to floating point and store it. Rather than cause this
+inconsistency, we think it is better to prohibit use of @samp{&} on a cast.
+
+If you really do want an @code{int *} pointer with the address of
+@code{f}, you can simply write @code{(int *)&f}.
+
+@node Conditionals
+@section Conditionals with Omitted Operands
+@cindex conditional expressions, extensions
+@cindex omitted middle-operands
+@cindex middle-operands, omitted
+@cindex extensions, @code{?:}
+@cindex @code{?:} extensions
+
+The middle operand in a conditional expression may be omitted. Then
+if the first operand is nonzero, its value is the value of the conditional
+expression.
+
+Therefore, the expression
+
+@example
+x ? : y
+@end example
+
+@noindent
+has the value of @code{x} if that is nonzero; otherwise, the value of
+@code{y}.
+
+This example is perfectly equivalent to
+
+@example
+x ? x : y
+@end example
+
+@cindex side effect in ?:
+@cindex ?: side effect
+@noindent
+In this simple case, the ability to omit the middle operand is not
+especially useful. When it becomes useful is when the first operand does,
+or may (if it is a macro argument), contain a side effect. Then repeating
+the operand in the middle would perform the side effect twice. Omitting
+the middle operand uses the value already computed without the undesirable
+effects of recomputing it.
+
+@node Long Long
+@section Double-Word Integers
+@cindex @code{long long} data types
+@cindex double-word arithmetic
+@cindex multiprecision arithmetic
+
+GNU C supports data types for integers that are twice as long as
+@code{long int}. Simply write @code{long long int} for a signed
+integer, or @code{unsigned long long int} for an unsigned integer.
+To make an integer constant of type @code{long long int}, add the suffix
+@code{LL} to the integer. To make an integer constant of type
+@code{unsigned long long int}, add the suffix @code{ULL} to the integer.
+
+You can use these types in arithmetic like any other integer types.
+Addition, subtraction, and bitwise boolean operations on these types
+are open-coded on all types of machines. Multiplication is open-coded
+if the machine supports fullword-to-doubleword a widening multiply
+instruction. Division and shifts are open-coded only on machines that
+provide special support. The operations that are not open-coded use
+special library routines that come with GNU CC.
+
+There may be pitfalls when you use @code{long long} types for function
+arguments, unless you declare function prototypes. If a function
+expects type @code{int} for its argument, and you pass a value of type
+@code{long long int}, confusion will result because the caller and the
+subroutine will disagree about the number of bytes for the argument.
+Likewise, if the function expects @code{long long int} and you pass
+@code{int}. The best way to avoid such problems is to use prototypes.
+
+@node Complex
+@section Complex Numbers
+@cindex complex numbers
+
+GNU C supports complex data types. You can declare both complex integer
+types and complex floating types, using the keyword @code{__complex__}.
+
+For example, @samp{__complex__ double x;} declares @code{x} as a
+variable whose real part and imaginary part are both of type
+@code{double}. @samp{__complex__ short int y;} declares @code{y} to
+have real and imaginary parts of type @code{short int}; this is not
+likely to be useful, but it shows that the set of complex types is
+complete.
+
+To write a constant with a complex data type, use the suffix @samp{i} or
+@samp{j} (either one; they are equivalent). For example, @code{2.5fi}
+has type @code{__complex__ float} and @code{3i} has type
+@code{__complex__ int}. Such a constant always has a pure imaginary
+value, but you can form any complex value you like by adding one to a
+real constant.
+
+To extract the real part of a complex-valued expression @var{exp}, write
+@code{__real__ @var{exp}}. Likewise, use @code{__imag__} to
+extract the imaginary part.
+
+The operator @samp{~} performs complex conjugation when used on a value
+with a complex type.
+
+GNU CC can allocate complex automatic variables in a noncontiguous
+fashion; it's even possible for the real part to be in a register while
+the imaginary part is on the stack (or vice-versa). None of the
+supported debugging info formats has a way to represent noncontiguous
+allocation like this, so GNU CC describes a noncontiguous complex
+variable as if it were two separate variables of noncomplex type.
+If the variable's actual name is @code{foo}, the two fictitious
+variables are named @code{foo$real} and @code{foo$imag}. You can
+examine and set these two fictitious variables with your debugger.
+
+A future version of GDB will know how to recognize such pairs and treat
+them as a single variable with a complex type.
+
+@node Zero Length
+@section Arrays of Length Zero
+@cindex arrays of length zero
+@cindex zero-length arrays
+@cindex length-zero arrays
+
+Zero-length arrays are allowed in GNU C. They are very useful as the last
+element of a structure which is really a header for a variable-length
+object:
+
+@example
+struct line @{
+ int length;
+ char contents[0];
+@};
+
+@{
+ struct line *thisline = (struct line *)
+ malloc (sizeof (struct line) + this_length);
+ thisline->length = this_length;
+@}
+@end example
+
+In standard C, you would have to give @code{contents} a length of 1, which
+means either you waste space or complicate the argument to @code{malloc}.
+
+@node Variable Length
+@section Arrays of Variable Length
+@cindex variable-length arrays
+@cindex arrays of variable length
+
+Variable-length automatic arrays are allowed in GNU C. These arrays are
+declared like any other automatic arrays, but with a length that is not
+a constant expression. The storage is allocated at the point of
+declaration and deallocated when the brace-level is exited. For
+example:
+
+@example
+FILE *
+concat_fopen (char *s1, char *s2, char *mode)
+@{
+ char str[strlen (s1) + strlen (s2) + 1];
+ strcpy (str, s1);
+ strcat (str, s2);
+ return fopen (str, mode);
+@}
+@end example
+
+@cindex scope of a variable length array
+@cindex variable-length array scope
+@cindex deallocating variable length arrays
+Jumping or breaking out of the scope of the array name deallocates the
+storage. Jumping into the scope is not allowed; you get an error
+message for it.
+
+@cindex @code{alloca} vs variable-length arrays
+You can use the function @code{alloca} to get an effect much like
+variable-length arrays. The function @code{alloca} is available in
+many other C implementations (but not in all). On the other hand,
+variable-length arrays are more elegant.
+
+There are other differences between these two methods. Space allocated
+with @code{alloca} exists until the containing @emph{function} returns.
+The space for a variable-length array is deallocated as soon as the array
+name's scope ends. (If you use both variable-length arrays and
+@code{alloca} in the same function, deallocation of a variable-length array
+will also deallocate anything more recently allocated with @code{alloca}.)
+
+You can also use variable-length arrays as arguments to functions:
+
+@example
+struct entry
+tester (int len, char data[len][len])
+@{
+ @dots{}
+@}
+@end example
+
+The length of an array is computed once when the storage is allocated
+and is remembered for the scope of the array in case you access it with
+@code{sizeof}.
+
+If you want to pass the array first and the length afterward, you can
+use a forward declaration in the parameter list---another GNU extension.
+
+@example
+struct entry
+tester (int len; char data[len][len], int len)
+@{
+ @dots{}
+@}
+@end example
+
+@cindex parameter forward declaration
+The @samp{int len} before the semicolon is a @dfn{parameter forward
+declaration}, and it serves the purpose of making the name @code{len}
+known when the declaration of @code{data} is parsed.
+
+You can write any number of such parameter forward declarations in the
+parameter list. They can be separated by commas or semicolons, but the
+last one must end with a semicolon, which is followed by the ``real''
+parameter declarations. Each forward declaration must match a ``real''
+declaration in parameter name and data type.
+
+@node Macro Varargs
+@section Macros with Variable Numbers of Arguments
+@cindex variable number of arguments
+@cindex macro with variable arguments
+@cindex rest argument (in macro)
+
+In GNU C, a macro can accept a variable number of arguments, much as a
+function can. The syntax for defining the macro looks much like that
+used for a function. Here is an example:
+
+@example
+#define eprintf(format, args...) \
+ fprintf (stderr, format , ## args)
+@end example
+
+Here @code{args} is a @dfn{rest argument}: it takes in zero or more
+arguments, as many as the call contains. All of them plus the commas
+between them form the value of @code{args}, which is substituted into
+the macro body where @code{args} is used. Thus, we have this expansion:
+
+@example
+eprintf ("%s:%d: ", input_file_name, line_number)
+@expansion{}
+fprintf (stderr, "%s:%d: " , input_file_name, line_number)
+@end example
+
+@noindent
+Note that the comma after the string constant comes from the definition
+of @code{eprintf}, whereas the last comma comes from the value of
+@code{args}.
+
+The reason for using @samp{##} is to handle the case when @code{args}
+matches no arguments at all. In this case, @code{args} has an empty
+value. In this case, the second comma in the definition becomes an
+embarrassment: if it got through to the expansion of the macro, we would
+get something like this:
+
+@example
+fprintf (stderr, "success!\n" , )
+@end example
+
+@noindent
+which is invalid C syntax. @samp{##} gets rid of the comma, so we get
+the following instead:
+
+@example
+fprintf (stderr, "success!\n")
+@end example
+
+This is a special feature of the GNU C preprocessor: @samp{##} before a
+rest argument that is empty discards the preceding sequence of
+non-whitespace characters from the macro definition. (If another macro
+argument precedes, none of it is discarded.)
+
+It might be better to discard the last preprocessor token instead of the
+last preceding sequence of non-whitespace characters; in fact, we may
+someday change this feature to do so. We advise you to write the macro
+definition so that the preceding sequence of non-whitespace characters
+is just a single token, so that the meaning will not change if we change
+the definition of this feature.
+
+@node Subscripting
+@section Non-Lvalue Arrays May Have Subscripts
+@cindex subscripting
+@cindex arrays, non-lvalue
+
+@cindex subscripting and function values
+Subscripting is allowed on arrays that are not lvalues, even though the
+unary @samp{&} operator is not. For example, this is valid in GNU C though
+not valid in other C dialects:
+
+@example
+@group
+struct foo @{int a[4];@};
+
+struct foo f();
+
+bar (int index)
+@{
+ return f().a[index];
+@}
+@end group
+@end example
+
+@node Pointer Arith
+@section Arithmetic on @code{void}- and Function-Pointers
+@cindex void pointers, arithmetic
+@cindex void, size of pointer to
+@cindex function pointers, arithmetic
+@cindex function, size of pointer to
+
+In GNU C, addition and subtraction operations are supported on pointers to
+@code{void} and on pointers to functions. This is done by treating the
+size of a @code{void} or of a function as 1.
+
+A consequence of this is that @code{sizeof} is also allowed on @code{void}
+and on function types, and returns 1.
+
+The option @samp{-Wpointer-arith} requests a warning if these extensions
+are used.
+
+@node Initializers
+@section Non-Constant Initializers
+@cindex initializers, non-constant
+@cindex non-constant initializers
+
+As in standard C++, the elements of an aggregate initializer for an
+automatic variable are not required to be constant expressions in GNU C.
+Here is an example of an initializer with run-time varying elements:
+
+@example
+foo (float f, float g)
+@{
+ float beat_freqs[2] = @{ f-g, f+g @};
+ @dots{}
+@}
+@end example
+
+@node Constructors
+@section Constructor Expressions
+@cindex constructor expressions
+@cindex initializations in expressions
+@cindex structures, constructor expression
+@cindex expressions, constructor
+
+GNU C supports constructor expressions. A constructor looks like
+a cast containing an initializer. Its value is an object of the
+type specified in the cast, containing the elements specified in
+the initializer.
+
+Usually, the specified type is a structure. Assume that
+@code{struct foo} and @code{structure} are declared as shown:
+
+@example
+struct foo @{int a; char b[2];@} structure;
+@end example
+
+@noindent
+Here is an example of constructing a @code{struct foo} with a constructor:
+
+@example
+structure = ((struct foo) @{x + y, 'a', 0@});
+@end example
+
+@noindent
+This is equivalent to writing the following:
+
+@example
+@{
+ struct foo temp = @{x + y, 'a', 0@};
+ structure = temp;
+@}
+@end example
+
+You can also construct an array. If all the elements of the constructor
+are (made up of) simple constant expressions, suitable for use in
+initializers, then the constructor is an lvalue and can be coerced to a
+pointer to its first element, as shown here:
+
+@example
+char **foo = (char *[]) @{ "x", "y", "z" @};
+@end example
+
+Array constructors whose elements are not simple constants are
+not very useful, because the constructor is not an lvalue. There
+are only two valid ways to use it: to subscript it, or initialize
+an array variable with it. The former is probably slower than a
+@code{switch} statement, while the latter does the same thing an
+ordinary C initializer would do. Here is an example of
+subscripting an array constructor:
+
+@example
+output = ((int[]) @{ 2, x, 28 @}) [input];
+@end example
+
+Constructor expressions for scalar types and union types are is
+also allowed, but then the constructor expression is equivalent
+to a cast.
+
+@node Labeled Elements
+@section Labeled Elements in Initializers
+@cindex initializers with labeled elements
+@cindex labeled elements in initializers
+@cindex case labels in initializers
+
+Standard C requires the elements of an initializer to appear in a fixed
+order, the same as the order of the elements in the array or structure
+being initialized.
+
+In GNU C you can give the elements in any order, specifying the array
+indices or structure field names they apply to. This extension is not
+implemented in GNU C++.
+
+To specify an array index, write @samp{[@var{index}]} or
+@samp{[@var{index}] =} before the element value. For example,
+
+@example
+int a[6] = @{ [4] 29, [2] = 15 @};
+@end example
+
+@noindent
+is equivalent to
+
+@example
+int a[6] = @{ 0, 0, 15, 0, 29, 0 @};
+@end example
+
+@noindent
+The index values must be constant expressions, even if the array being
+initialized is automatic.
+
+To initialize a range of elements to the same value, write
+@samp{[@var{first} ... @var{last}] = @var{value}}. For example,
+
+@example
+int widths[] = @{ [0 ... 9] = 1, [10 ... 99] = 2, [100] = 3 @};
+@end example
+
+@noindent
+Note that the length of the array is the highest value specified
+plus one.
+
+In a structure initializer, specify the name of a field to initialize
+with @samp{@var{fieldname}:} before the element value. For example,
+given the following structure,
+
+@example
+struct point @{ int x, y; @};
+@end example
+
+@noindent
+the following initialization
+
+@example
+struct point p = @{ y: yvalue, x: xvalue @};
+@end example
+
+@noindent
+is equivalent to
+
+@example
+struct point p = @{ xvalue, yvalue @};
+@end example
+
+Another syntax which has the same meaning is @samp{.@var{fieldname} =}.,
+as shown here:
+
+@example
+struct point p = @{ .y = yvalue, .x = xvalue @};
+@end example
+
+You can also use an element label (with either the colon syntax or the
+period-equal syntax) when initializing a union, to specify which element
+of the union should be used. For example,
+
+@example
+union foo @{ int i; double d; @};
+
+union foo f = @{ d: 4 @};
+@end example
+
+@noindent
+will convert 4 to a @code{double} to store it in the union using
+the second element. By contrast, casting 4 to type @code{union foo}
+would store it into the union as the integer @code{i}, since it is
+an integer. (@xref{Cast to Union}.)
+
+You can combine this technique of naming elements with ordinary C
+initialization of successive elements. Each initializer element that
+does not have a label applies to the next consecutive element of the
+array or structure. For example,
+
+@example
+int a[6] = @{ [1] = v1, v2, [4] = v4 @};
+@end example
+
+@noindent
+is equivalent to
+
+@example
+int a[6] = @{ 0, v1, v2, 0, v4, 0 @};
+@end example
+
+Labeling the elements of an array initializer is especially useful
+when the indices are characters or belong to an @code{enum} type.
+For example:
+
+@example
+int whitespace[256]
+ = @{ [' '] = 1, ['\t'] = 1, ['\h'] = 1,
+ ['\f'] = 1, ['\n'] = 1, ['\r'] = 1 @};
+@end example
+
+@node Case Ranges
+@section Case Ranges
+@cindex case ranges
+@cindex ranges in case statements
+
+You can specify a range of consecutive values in a single @code{case} label,
+like this:
+
+@example
+case @var{low} ... @var{high}:
+@end example
+
+@noindent
+This has the same effect as the proper number of individual @code{case}
+labels, one for each integer value from @var{low} to @var{high}, inclusive.
+
+This feature is especially useful for ranges of ASCII character codes:
+
+@example
+case 'A' ... 'Z':
+@end example
+
+@strong{Be careful:} Write spaces around the @code{...}, for otherwise
+it may be parsed wrong when you use it with integer values. For example,
+write this:
+
+@example
+case 1 ... 5:
+@end example
+
+@noindent
+rather than this:
+
+@example
+case 1...5:
+@end example
+
+@node Cast to Union
+@section Cast to a Union Type
+@cindex cast to a union
+@cindex union, casting to a
+
+A cast to union type is similar to other casts, except that the type
+specified is a union type. You can specify the type either with
+@code{union @var{tag}} or with a typedef name. A cast to union is actually
+a constructor though, not a cast, and hence does not yield an lvalue like
+normal casts. (@xref{Constructors}.)
+
+The types that may be cast to the union type are those of the members
+of the union. Thus, given the following union and variables:
+
+@example
+union foo @{ int i; double d; @};
+int x;
+double y;
+@end example
+
+@noindent
+both @code{x} and @code{y} can be cast to type @code{union} foo.
+
+Using the cast as the right-hand side of an assignment to a variable of
+union type is equivalent to storing in a member of the union:
+
+@example
+union foo u;
+@dots{}
+u = (union foo) x @equiv{} u.i = x
+u = (union foo) y @equiv{} u.d = y
+@end example
+
+You can also use the union cast as a function argument:
+
+@example
+void hack (union foo);
+@dots{}
+hack ((union foo) x);
+@end example
+
+@node Function Attributes
+@section Declaring Attributes of Functions
+@cindex function attributes
+@cindex declaring attributes of functions
+@cindex functions that never return
+@cindex functions that have no side effects
+@cindex functions in arbitrary sections
+@cindex @code{volatile} applied to function
+@cindex @code{const} applied to function
+@cindex functions with @code{printf} or @code{scanf} style arguments
+
+In GNU C, you declare certain things about functions called in your program
+which help the compiler optimize function calls and check your code more
+carefully.
+
+The keyword @code{__attribute__} allows you to specify special
+attributes when making a declaration. This keyword is followed by an
+attribute specification inside double parentheses. Four attributes,
+@code{noreturn}, @code{const}, @code{format}, and @code{section} are
+currently defined for functions. Other attributes, including @code{section}
+are supported for variables declarations
+(@pxref{Variable Attributes}).
+
+You may also specify attributes with @samp{__} preceeding and following
+each keyword. This allows you to use them in header files without
+being concerned about a possible macro of the same name. For example,
+you may use @code{__noreturn__} instead of @code{noreturn}.
+
+@table @code
+@cindex @code{noreturn} function attribute
+@item noreturn
+A few standard library functions, such as @code{abort} and @code{exit},
+cannot return. GNU CC knows this automatically. Some programs define
+their own functions that never return. You can declare them
+@code{noreturn} to tell the compiler this fact. For example,
+
+@smallexample
+void fatal () __attribute__ ((noreturn));
+
+void
+fatal (@dots{})
+@{
+ @dots{} /* @r{Print error message.} */ @dots{}
+ exit (1);
+@}
+@end smallexample
+
+The @code{noreturn} keyword tells the compiler to assume that
+@code{fatal} cannot return. It can then optimize without regard to what
+would happen if @code{fatal} ever did return. This makes slightly
+better code. More importantly, it helps avoid spurious warnings of
+uninitialized variables.
+
+Do not assume that registers saved by the calling function are
+restored before calling the @code{noreturn} function.
+
+It does not make sense for a @code{noreturn} function to have a return
+type other than @code{void}.
+
+The attribute @code{noreturn} is not implemented in GNU C versions
+earlier than 2.5. An alternative way to declare that a function does
+not return, which works in the current version and in some older
+versions, is as follows:
+
+@smallexample
+typedef void voidfn ();
+
+volatile voidfn fatal;
+@end smallexample
+
+@cindex @code{const} function attribute
+@item const
+Many functions do not examine any values except their arguments, and
+have no effects except the return value. Such a function can be subject
+to common subexpression elimination and loop optimization just as an
+arithmetic operator would be. These functions should be declared
+with the attribute @code{const}. For example,
+
+@smallexample
+int square (int) __attribute__ ((const));
+@end smallexample
+
+@noindent
+says that the hypothetical function @code{square} is safe to call
+fewer times than the program says.
+
+The attribute @code{const} is not implemented in GNU C versions earlier
+than 2.5. An alternative way to declare that a function has no side
+effects, which works in the current version and in some older versions,
+is as follows:
+
+@smallexample
+typedef int intfn ();
+
+extern const intfn square;
+@end smallexample
+
+This approach does not work in GNU C++ from 2.6.0 on, since the language
+specifies that the @samp{const} must be attached to the return value.
+
+@cindex pointer arguments
+Note that a function that has pointer arguments and examines the data
+pointed to must @emph{not} be declared @code{const}. Likewise, a
+function that calls a non-@code{const} function usually must not be
+@code{const}. It does not make sense for a @code{const} function to
+return @code{void}.
+
+@item format (@var{archetype}, @var{string-index}, @var{first-to-check})
+@cindex @code{format} function attribute
+The @code{format} attribute specifies that a function takes @code{printf}
+or @code{scanf} style arguments which should be type-checked against a
+format string. For example, the declaration:
+
+@smallexample
+extern int
+my_printf (void *my_object, const char *my_format, ...)
+ __attribute__ ((format (printf, 2, 3)));
+@end smallexample
+
+@noindent
+causes the compiler to check the arguments in calls to @code{my_printf}
+for consistency with the @code{printf} style format string argument
+@code{my_format}.
+
+The parameter @var{archetype} determines how the format string is
+interpreted, and should be either @code{printf} or @code{scanf}. The
+parameter @var{string-index} specifies which argument is the format
+string argument (starting from 1), while @var{first-to-check} is the
+number of the first argument to check against the format string. For
+functions where the arguments are not available to be checked (such as
+@code{vprintf}), specify the third parameter as zero. In this case the
+compiler only checks the format string for consistency.
+
+In the example above, the format string (@code{my_format}) is the second
+argument of the function @code{my_print}, and the arguments to check
+start with the third argument, so the correct parameters for the format
+attribute are 2 and 3.
+
+The @code{format} attribute allows you to identify your own functions
+which take format strings as arguments, so that GNU CC can check the
+calls to these functions for errors. The compiler always checks formats
+for the ANSI library functions @code{printf}, @code{fprintf},
+@code{sprintf}, @code{scanf}, @code{fscanf}, @code{sscanf},
+@code{vprintf}, @code{vfprintf} and @code{vsprintf} whenever such
+warnings are requested (using @samp{-Wformat}), so there is no need to
+modify the header file @file{stdio.h}.
+
+@item section ("section-name")
+@cindex @code{section} function attribute
+Normally, the compiler places the code it generates in the @code{text} section.
+Sometimes, however, you need additional sections, or you need certain
+particular functions to appear in special sections. The @code{section}
+attribute specifies that a function lives in a particular section.
+For example, the declaration:
+
+@smallexample
+extern void foobar (void) __attribute__ ((section (".init")));
+@end smallexample
+
+@noindent
+puts the function @code{foobar} in the @code{.init} section.
+
+Some file formats do not support arbitrary sections so the @code{section}
+attribute is not available on all platforms.
+If you need to map the entire contents of a module to a particular
+section, consider using the facilities of the linker instead.
+@end table
+
+You can specify multiple attributes in a declaration by separating them
+by commas within the double parentheses or by immediately following an
+attribute declaration with another attribute declaration.
+
+@cindex @code{#pragma}, reason for not using
+@cindex pragma, reason for not using
+Some people object to the @code{__attribute__} feature, suggesting that ANSI C's
+@code{#pragma} should be used instead. There are two reasons for not
+doing this.
+
+@enumerate
+@item
+It is impossible to generate @code{#pragma} commands from a macro.
+
+@item
+There is no telling what the same @code{#pragma} might mean in another
+compiler.
+@end enumerate
+
+These two reasons apply to almost any application that might be proposed
+for @code{#pragma}. It is basically a mistake to use @code{#pragma} for
+@emph{anything}.
+
+@node Function Prototypes
+@section Prototypes and Old-Style Function Definitions
+@cindex function prototype declarations
+@cindex old-style function definitions
+@cindex promotion of formal parameters
+
+GNU C extends ANSI C to allow a function prototype to override a later
+old-style non-prototype definition. Consider the following example:
+
+@example
+/* @r{Use prototypes unless the compiler is old-fashioned.} */
+#if __STDC__
+#define P(x) x
+#else
+#define P(x) ()
+#endif
+
+/* @r{Prototype function declaration.} */
+int isroot P((uid_t));
+
+/* @r{Old-style function definition.} */
+int
+isroot (x) /* ??? lossage here ??? */
+ uid_t x;
+@{
+ return x == 0;
+@}
+@end example
+
+Suppose the type @code{uid_t} happens to be @code{short}. ANSI C does
+not allow this example, because subword arguments in old-style
+non-prototype definitions are promoted. Therefore in this example the
+function definition's argument is really an @code{int}, which does not
+match the prototype argument type of @code{short}.
+
+This restriction of ANSI C makes it hard to write code that is portable
+to traditional C compilers, because the programmer does not know
+whether the @code{uid_t} type is @code{short}, @code{int}, or
+@code{long}. Therefore, in cases like these GNU C allows a prototype
+to override a later old-style definition. More precisely, in GNU C, a
+function prototype argument type overrides the argument type specified
+by a later old-style definition if the former type is the same as the
+latter type before promotion. Thus in GNU C the above example is
+equivalent to the following:
+
+@example
+int isroot (uid_t);
+
+int
+isroot (uid_t x)
+@{
+ return x == 0;
+@}
+@end example
+
+GNU C++ does not support old-style function definitions, so this
+extension is irrelevant.
+
+@node Dollar Signs
+@section Dollar Signs in Identifier Names
+@cindex $
+@cindex dollar signs in identifier names
+@cindex identifier names, dollar signs in
+
+In GNU C, you may use dollar signs in identifier names. This is because
+many traditional C implementations allow such identifiers.
+
+On some machines, dollar signs are allowed in identifiers if you specify
+@w{@samp{-traditional}}. On a few systems they are allowed by default,
+even if you do not use @w{@samp{-traditional}}. But they are never
+allowed if you specify @w{@samp{-ansi}}.
+
+There are certain ANSI C programs (obscure, to be sure) that would
+compile incorrectly if dollar signs were permitted in identifiers. For
+example:
+
+@example
+#define foo(a) #a
+#define lose(b) foo (b)
+#define test$
+lose (test)
+@end example
+
+@node Character Escapes
+@section The Character @key{ESC} in Constants
+
+You can use the sequence @samp{\e} in a string or character constant to
+stand for the ASCII character @key{ESC}.
+
+@node Alignment
+@section Inquiring on Alignment of Types or Variables
+@cindex alignment
+@cindex type alignment
+@cindex variable alignment
+
+The keyword @code{__alignof__} allows you to inquire about how an object
+is aligned, or the minimum alignment usually required by a type. Its
+syntax is just like @code{sizeof}.
+
+For example, if the target machine requires a @code{double} value to be
+aligned on an 8-byte boundary, then @code{__alignof__ (double)} is 8.
+This is true on many RISC machines. On more traditional machine
+designs, @code{__alignof__ (double)} is 4 or even 2.
+
+Some machines never actually require alignment; they allow reference to any
+data type even at an odd addresses. For these machines, @code{__alignof__}
+reports the @emph{recommended} alignment of a type.
+
+When the operand of @code{__alignof__} is an lvalue rather than a type, the
+value is the largest alignment that the lvalue is known to have. It may
+have this alignment as a result of its data type, or because it is part of
+a structure and inherits alignment from that structure. For example, after
+this declaration:
+
+@example
+struct foo @{ int x; char y; @} foo1;
+@end example
+
+@noindent
+the value of @code{__alignof__ (foo1.y)} is probably 2 or 4, the same as
+@code{__alignof__ (int)}, even though the data type of @code{foo1.y}
+does not itself demand any alignment.@refill
+
+A related feature which lets you specify the alignment of an object is
+@code{__attribute__ ((aligned (@var{alignment})))}; see the following
+section.
+
+@node Variable Attributes
+@section Specifying Attributes of Variables
+@cindex attribute of variables
+@cindex variable attributes
+
+The keyword @code{__attribute__} allows you to specify special
+attributes of variables or structure fields. This keyword is followed
+by an attribute specification inside double parentheses. Four
+attributes are currently defined for variables: @code{aligned},
+@code{mode}, @code{packed}, and @code{section}. Other attributes are
+defined for functions, and thus not documented here;
+see @ref{Function Attributes}.
+
+You may also specify attributes with @samp{__} preceeding and following
+each keyword. This allows you to use them in header files without
+being concerned about a possible macro of the same name. For example,
+you may use @code{__aligned__} instead of @code{aligned}.
+
+@table @code
+@cindex @code{aligned} attribute
+@item aligned (@var{alignment})
+This attribute specifies a minimum alignment for the variable or
+structure field, measured in bytes. For example, the declaration:
+
+@smallexample
+int x __attribute__ ((aligned (16))) = 0;
+@end smallexample
+
+@noindent
+causes the compiler to allocate the global variable @code{x} on a
+16-byte boundary. On a 68040, this could be used in conjunction with
+an @code{asm} expression to access the @code{move16} instruction which
+requires 16-byte aligned operands.
+
+You can also specify the alignment of structure fields. For example, to
+create a double-word aligned @code{int} pair, you could write:
+
+@smallexample
+struct foo @{ int x[2] __attribute__ ((aligned (8))); @};
+@end smallexample
+
+@noindent
+This is an alternative to creating a union with a @code{double} member
+that forces the union to be double-word aligned.
+
+It is not possible to specify the alignment of functions; the alignment
+of functions is determined by the machine's requirements and cannot be
+changed. You cannot specify alignment for a typedef name because such a
+name is just an alias, not a distinct type.
+
+The @code{aligned} attribute can only increase the alignment; but you
+can decrease it by specifying @code{packed} as well. See below.
+
+The linker of your operating system imposes a maximum alignment. If the
+linker aligns each object file on a four byte boundary, then it is
+beyond the compiler's power to cause anything to be aligned to a larger
+boundary than that. For example, if the linker happens to put this object
+file at address 136 (eight more than a multiple of 64), then the compiler
+cannot guarantee an alignment of more than 8 just by aligning variables in
+the object file.
+
+@item mode (@var{mode})
+@cindex @code{mode} attribute
+This attribute specifies the data type for the declaration---whichever
+type corresponds to the mode @var{mode}. This in effect lets you
+request an integer or floating point type according to its width.
+
+@item packed
+@cindex @code{packed} attribute
+The @code{packed} attribute specifies that a variable or structure field
+should have the smallest possible alignment---one byte for a variable,
+and one bit for a field, unless you specify a larger value with the
+@code{aligned} attribute.
+
+Here is a structure in which the field @code{x} is packed, so that it
+immediately follows @code{a}:
+
+@example
+struct foo
+@{
+ char a;
+ int x[2] __attribute__ ((packed));
+@};
+@end example
+
+@item section ("section-name")
+@cindex @code{section} variable attribute
+Normally, the compiler places the objects it generates in sections like
+@code{data} and @code{bss}. Sometimes, however, you need additional sections,
+or you need certain particular variables to appear in special sections,
+for example to map to special hardware. The @code{section}
+attribute specifies that a variable (or function) lives in a particular
+section. For example, this small program uses several specific section names:
+
+@smallexample
+struct duart a __attribute__ ((section ("DUART_A"))) = @{ 0 @};
+struct duart b __attribute__ ((section ("DUART_B"))) = @{ 0 @};
+char stack[10000] __attribute__ ((section ("STACK"))) = @{ 0 @};
+int init_data_copy __attribute__ ((section ("INITDATACOPY"))) = 0;
+
+main()
+@{
+ /* Initialize stack pointer */
+ init_sp (stack + sizeof (stack));
+
+ /* Initialize initialized data */
+ memcpy (&init_data_copy, &data, &edata - &data);
+
+ /* Turn on the serial ports */
+ init_duart (&a);
+ init_duart (&b);
+@}
+@end smallexample
+
+@noindent
+Use the @code{section} attribute with an @emph{initialized} definition
+of a @emph{global} variable, as shown in the example. GNU CC issues
+a warning and otherwise ignores the @code{section} attribute in
+uninitialized variable declarations.
+
+You may only use the @code{section} attribute with a fully initialized
+global definition because of the way linkers work.
+The linker requires each object be defined once, with the exception that
+uninitialized variables tentatively go in the @code{common} (or @code{bss})
+section and can be multiply "defined".
+
+Some file formats do not support arbitrary sections so the @code{section}
+attribute is not available on all platforms.
+If you need to map the entire contents of a module to a particular
+section, consider using the facilities of the linker instead.
+
+@item transparent_union
+This attribute, attached to a function argument variable which is a
+union, means to pass the argument in the same way that the first union
+alternative would be passed. You can also use this attribute on a
+@code{typedef} for a union data type; then it applies to all function
+arguments with that type.
+@end table
+
+To specify multiple attributes, separate them by commas within the
+double parentheses: for example, @samp{__attribute__ ((aligned (16),
+packed))}.
+
+@node Inline
+@section An Inline Function is As Fast As a Macro
+@cindex inline functions
+@cindex integrating function code
+@cindex open coding
+@cindex macros, inline alternative
+
+By declaring a function @code{inline}, you can direct GNU CC to
+integrate that function's code into the code for its callers. This
+makes execution faster by eliminating the function-call overhead; in
+addition, if any of the actual argument values are constant, their known
+values may permit simplifications at compile time so that not all of the
+inline function's code needs to be included. The effect on code size is
+less predictable; object code may be larger or smaller with function
+inlining, depending on the particular case. Inlining of functions is an
+optimization and it really ``works'' only in optimizing compilation. If
+you don't use @samp{-O}, no function is really inline.
+
+To declare a function inline, use the @code{inline} keyword in its
+declaration, like this:
+
+@example
+inline int
+inc (int *a)
+@{
+ (*a)++;
+@}
+@end example
+
+(If you are writing a header file to be included in ANSI C programs, write
+@code{__inline__} instead of @code{inline}. @xref{Alternate Keywords}.)
+
+You can also make all ``simple enough'' functions inline with the option
+@samp{-finline-functions}. Note that certain usages in a function
+definition can make it unsuitable for inline substitution.
+
+Note that in C and Objective C, unlike C++, the @code{inline} keyword
+does not affect the linkage of the function.
+
+@cindex automatic @code{inline} for C++ member fns
+@cindex @code{inline} automatic for C++ member fns
+@cindex member fns, automatically @code{inline}
+@cindex C++ member fns, automatically @code{inline}
+GNU CC automatically inlines member functions defined within the class
+body of C++ programs even if they are not explicitly declared
+@code{inline}. (You can override this with @samp{-fno-default-inline};
+@pxref{C++ Dialect Options,,Options Controlling C++ Dialect}.)
+
+@cindex inline functions, omission of
+When a function is both inline and @code{static}, if all calls to the
+function are integrated into the caller, and the function's address is
+never used, then the function's own assembler code is never referenced.
+In this case, GNU CC does not actually output assembler code for the
+function, unless you specify the option @samp{-fkeep-inline-functions}.
+Some calls cannot be integrated for various reasons (in particular,
+calls that precede the function's definition cannot be integrated, and
+neither can recursive calls within the definition). If there is a
+nonintegrated call, then the function is compiled to assembler code as
+usual. The function must also be compiled as usual if the program
+refers to its address, because that can't be inlined.
+
+@cindex non-static inline function
+When an inline function is not @code{static}, then the compiler must assume
+that there may be calls from other source files; since a global symbol can
+be defined only once in any program, the function must not be defined in
+the other source files, so the calls therein cannot be integrated.
+Therefore, a non-@code{static} inline function is always compiled on its
+own in the usual fashion.
+
+If you specify both @code{inline} and @code{extern} in the function
+definition, then the definition is used only for inlining. In no case
+is the function compiled on its own, not even if you refer to its
+address explicitly. Such an address becomes an external reference, as
+if you had only declared the function, and had not defined it.
+
+This combination of @code{inline} and @code{extern} has almost the
+effect of a macro. The way to use it is to put a function definition in
+a header file with these keywords, and put another copy of the
+definition (lacking @code{inline} and @code{extern}) in a library file.
+The definition in the header file will cause most calls to the function
+to be inlined. If any uses of the function remain, they will refer to
+the single copy in the library.
+
+GNU C does not inline any functions when not optimizing. It is not
+clear whether it is better to inline or not, in this case, but we found
+that a correct implementation when not optimizing was difficult. So we
+did the easy thing, and turned it off.
+
+@node Extended Asm
+@section Assembler Instructions with C Expression Operands
+@cindex extended @code{asm}
+@cindex @code{asm} expressions
+@cindex assembler instructions
+@cindex registers
+
+In an assembler instruction using @code{asm}, you can now specify the
+operands of the instruction using C expressions. This means no more
+guessing which registers or memory locations will contain the data you want
+to use.
+
+You must specify an assembler instruction template much like what appears
+in a machine description, plus an operand constraint string for each
+operand.
+
+For example, here is how to use the 68881's @code{fsinx} instruction:
+
+@example
+asm ("fsinx %1,%0" : "=f" (result) : "f" (angle));
+@end example
+
+@noindent
+Here @code{angle} is the C expression for the input operand while
+@code{result} is that of the output operand. Each has @samp{"f"} as its
+operand constraint, saying that a floating point register is required. The
+@samp{=} in @samp{=f} indicates that the operand is an output; all output
+operands' constraints must use @samp{=}. The constraints use the same
+language used in the machine description (@pxref{Constraints}).
+
+Each operand is described by an operand-constraint string followed by the C
+expression in parentheses. A colon separates the assembler template from
+the first output operand, and another separates the last output operand
+from the first input, if any. Commas separate output operands and separate
+inputs. The total number of operands is limited to ten or to the maximum
+number of operands in any instruction pattern in the machine description,
+whichever is greater.
+
+If there are no output operands, and there are input operands, then there
+must be two consecutive colons surrounding the place where the output
+operands would go.
+
+Output operand expressions must be lvalues; the compiler can check this.
+The input operands need not be lvalues. The compiler cannot check whether
+the operands have data types that are reasonable for the instruction being
+executed. It does not parse the assembler instruction template and does
+not know what it means, or whether it is valid assembler input. The
+extended @code{asm} feature is most often used for machine instructions
+that the compiler itself does not know exist.
+
+The output operands must be write-only; GNU CC will assume that the values
+in these operands before the instruction are dead and need not be
+generated. Extended asm does not support input-output or read-write
+operands. For this reason, the constraint character @samp{+}, which
+indicates such an operand, may not be used.
+
+When the assembler instruction has a read-write operand, or an operand
+in which only some of the bits are to be changed, you must logically
+split its function into two separate operands, one input operand and one
+write-only output operand. The connection between them is expressed by
+constraints which say they need to be in the same location when the
+instruction executes. You can use the same C expression for both
+operands, or different expressions. For example, here we write the
+(fictitious) @samp{combine} instruction with @code{bar} as its read-only
+source operand and @code{foo} as its read-write destination:
+
+@example
+asm ("combine %2,%0" : "=r" (foo) : "0" (foo), "g" (bar));
+@end example
+
+@noindent
+The constraint @samp{"0"} for operand 1 says that it must occupy the same
+location as operand 0. A digit in constraint is allowed only in an input
+operand, and it must refer to an output operand.
+
+Only a digit in the constraint can guarantee that one operand will be in
+the same place as another. The mere fact that @code{foo} is the value of
+both operands is not enough to guarantee that they will be in the same
+place in the generated assembler code. The following would not work:
+
+@example
+asm ("combine %2,%0" : "=r" (foo) : "r" (foo), "g" (bar));
+@end example
+
+Various optimizations or reloading could cause operands 0 and 1 to be in
+different registers; GNU CC knows no reason not to do so. For example, the
+compiler might find a copy of the value of @code{foo} in one register and
+use it for operand 1, but generate the output operand 0 in a different
+register (copying it afterward to @code{foo}'s own address). Of course,
+since the register for operand 1 is not even mentioned in the assembler
+code, the result will not work, but GNU CC can't tell that.
+
+Some instructions clobber specific hard registers. To describe this, write
+a third colon after the input operands, followed by the names of the
+clobbered hard registers (given as strings). Here is a realistic example
+for the Vax:
+
+@example
+asm volatile ("movc3 %0,%1,%2"
+ : /* no outputs */
+ : "g" (from), "g" (to), "g" (count)
+ : "r0", "r1", "r2", "r3", "r4", "r5");
+@end example
+
+If you refer to a particular hardware register from the assembler code,
+then you will probably have to list the register after the third colon
+to tell the compiler that the register's value is modified. In many
+assemblers, the register names begin with @samp{%}; to produce one
+@samp{%} in the assembler code, you must write @samp{%%} in the input.
+
+If your assembler instruction can alter the condition code register,
+add @samp{cc} to the list of clobbered registers. GNU CC on some
+machines represents the condition codes as a specific hardware
+register; @samp{cc} serves to name this register. On other machines,
+the condition code is handled differently, and specifying @samp{cc}
+has no effect. But it is valid no matter what the machine.
+
+If your assembler instruction modifies memory in an unpredictable
+fashion, add @samp{memory} to the list of clobbered registers.
+This will cause GNU CC to not keep memory values cached in
+registers across the assembler instruction.
+
+You can put multiple assembler instructions together in a single @code{asm}
+template, separated either with newlines (written as @samp{\n}) or with
+semicolons if the assembler allows such semicolons. The GNU assembler
+allows semicolons and all Unix assemblers seem to do so. The input
+operands are guaranteed not to use any of the clobbered registers, and
+neither will the output operands' addresses, so you can read and write the
+clobbered registers as many times as you like. Here is an example of
+multiple instructions in a template; it assumes that the subroutine
+@code{_foo} accepts arguments in registers 9 and 10:
+
+@example
+asm ("movl %0,r9;movl %1,r10;call _foo"
+ : /* no outputs */
+ : "g" (from), "g" (to)
+ : "r9", "r10");
+@end example
+
+Unless an output operand has the @samp{&} constraint modifier, GNU CC may
+allocate it in the same register as an unrelated input operand, on the
+assumption that the inputs are consumed before the outputs are produced.
+This assumption may be false if the assembler code actually consists of
+more than one instruction. In such a case, use @samp{&} for each output
+operand that may not overlap an input.
+@xref{Modifiers}.
+
+If you want to test the condition code produced by an assembler instruction,
+you must include a branch and a label in the @code{asm} construct, as follows:
+
+@example
+asm ("clr %0;frob %1;beq 0f;mov #1,%0;0:"
+ : "g" (result)
+ : "g" (input));
+@end example
+
+@noindent
+This assumes your assembler supports local labels, as the GNU assembler
+and most Unix assemblers do.
+
+Speaking of labels, jumps from one @code{asm} to another are not
+supported. The compiler's optimizers do not know about these jumps,
+and therefore they cannot take account of them when deciding how to
+optimize.
+
+@cindex macros containing @code{asm}
+Usually the most convenient way to use these @code{asm} instructions is to
+encapsulate them in macros that look like functions. For example,
+
+@example
+#define sin(x) \
+(@{ double __value, __arg = (x); \
+ asm ("fsinx %1,%0": "=f" (__value): "f" (__arg)); \
+ __value; @})
+@end example
+
+@noindent
+Here the variable @code{__arg} is used to make sure that the instruction
+operates on a proper @code{double} value, and to accept only those
+arguments @code{x} which can convert automatically to a @code{double}.
+
+Another way to make sure the instruction operates on the correct data type
+is to use a cast in the @code{asm}. This is different from using a
+variable @code{__arg} in that it converts more different types. For
+example, if the desired type were @code{int}, casting the argument to
+@code{int} would accept a pointer with no complaint, while assigning the
+argument to an @code{int} variable named @code{__arg} would warn about
+using a pointer unless the caller explicitly casts it.
+
+If an @code{asm} has output operands, GNU CC assumes for optimization
+purposes that the instruction has no side effects except to change the
+output operands. This does not mean that instructions with a side effect
+cannot be used, but you must be careful, because the compiler may eliminate
+them if the output operands aren't used, or move them out of loops, or
+replace two with one if they constitute a common subexpression. Also, if
+your instruction does have a side effect on a variable that otherwise
+appears not to change, the old value of the variable may be reused later if
+it happens to be found in a register.
+
+You can prevent an @code{asm} instruction from being deleted, moved
+significantly, or combined, by writing the keyword @code{volatile} after
+the @code{asm}. For example:
+
+@example
+#define set_priority(x) \
+asm volatile ("set_priority %0": /* no outputs */ : "g" (x))
+@end example
+
+@noindent
+An instruction without output operands will not be deleted or moved
+significantly, regardless, unless it is unreachable.
+
+Note that even a volatile @code{asm} instruction can be moved in ways
+that appear insignificant to the compiler, such as across jump
+instructions. You can't expect a sequence of volatile @code{asm}
+instructions to remain perfectly consecutive. If you want consecutive
+output, use a single @code{asm}.
+
+It is a natural idea to look for a way to give access to the condition
+code left by the assembler instruction. However, when we attempted to
+implement this, we found no way to make it work reliably. The problem
+is that output operands might need reloading, which would result in
+additional following ``store'' instructions. On most machines, these
+instructions would alter the condition code before there was time to
+test it. This problem doesn't arise for ordinary ``test'' and
+``compare'' instructions because they don't have any output operands.
+
+If you are writing a header file that should be includable in ANSI C
+programs, write @code{__asm__} instead of @code{asm}. @xref{Alternate
+Keywords}.
+
+@ifclear INTERNALS
+@c Show the details on constraints if they do not appear elsewhere in
+@c the manual
+@include md.texi
+@end ifclear
+
+@node Asm Labels
+@section Controlling Names Used in Assembler Code
+@cindex assembler names for identifiers
+@cindex names used in assembler code
+@cindex identifiers, names in assembler code
+
+You can specify the name to be used in the assembler code for a C
+function or variable by writing the @code{asm} (or @code{__asm__})
+keyword after the declarator as follows:
+
+@example
+int foo asm ("myfoo") = 2;
+@end example
+
+@noindent
+This specifies that the name to be used for the variable @code{foo} in
+the assembler code should be @samp{myfoo} rather than the usual
+@samp{_foo}.
+
+On systems where an underscore is normally prepended to the name of a C
+function or variable, this feature allows you to define names for the
+linker that do not start with an underscore.
+
+You cannot use @code{asm} in this way in a function @emph{definition}; but
+you can get the same effect by writing a declaration for the function
+before its definition and putting @code{asm} there, like this:
+
+@example
+extern func () asm ("FUNC");
+
+func (x, y)
+ int x, y;
+@dots{}
+@end example
+
+It is up to you to make sure that the assembler names you choose do not
+conflict with any other assembler symbols. Also, you must not use a
+register name; that would produce completely invalid assembler code. GNU
+CC does not as yet have the ability to store static variables in registers.
+Perhaps that will be added.
+
+@node Explicit Reg Vars
+@section Variables in Specified Registers
+@cindex explicit register variables
+@cindex variables in specified registers
+@cindex specified registers
+@cindex registers, global allocation
+
+GNU C allows you to put a few global variables into specified hardware
+registers. You can also specify the register in which an ordinary
+register variable should be allocated.
+
+@itemize @bullet
+@item
+Global register variables reserve registers throughout the program.
+This may be useful in programs such as programming language
+interpreters which have a couple of global variables that are accessed
+very often.
+
+@item
+Local register variables in specific registers do not reserve the
+registers. The compiler's data flow analysis is capable of determining
+where the specified registers contain live values, and where they are
+available for other uses.
+
+These local variables are sometimes convenient for use with the extended
+@code{asm} feature (@pxref{Extended Asm}), if you want to write one
+output of the assembler instruction directly into a particular register.
+(This will work provided the register you specify fits the constraints
+specified for that operand in the @code{asm}.)
+@end itemize
+
+@menu
+* Global Reg Vars::
+* Local Reg Vars::
+@end menu
+
+@node Global Reg Vars
+@subsection Defining Global Register Variables
+@cindex global register variables
+@cindex registers, global variables in
+
+You can define a global register variable in GNU C like this:
+
+@example
+register int *foo asm ("a5");
+@end example
+
+@noindent
+Here @code{a5} is the name of the register which should be used. Choose a
+register which is normally saved and restored by function calls on your
+machine, so that library routines will not clobber it.
+
+Naturally the register name is cpu-dependent, so you would need to
+conditionalize your program according to cpu type. The register
+@code{a5} would be a good choice on a 68000 for a variable of pointer
+type. On machines with register windows, be sure to choose a ``global''
+register that is not affected magically by the function call mechanism.
+
+In addition, operating systems on one type of cpu may differ in how they
+name the registers; then you would need additional conditionals. For
+example, some 68000 operating systems call this register @code{%a5}.
+
+Eventually there may be a way of asking the compiler to choose a register
+automatically, but first we need to figure out how it should choose and
+how to enable you to guide the choice. No solution is evident.
+
+Defining a global register variable in a certain register reserves that
+register entirely for this use, at least within the current compilation.
+The register will not be allocated for any other purpose in the functions
+in the current compilation. The register will not be saved and restored by
+these functions. Stores into this register are never deleted even if they
+would appear to be dead, but references may be deleted or moved or
+simplified.
+
+It is not safe to access the global register variables from signal
+handlers, or from more than one thread of control, because the system
+library routines may temporarily use the register for other things (unless
+you recompile them specially for the task at hand).
+
+@cindex @code{qsort}, and global register variables
+It is not safe for one function that uses a global register variable to
+call another such function @code{foo} by way of a third function
+@code{lose} that was compiled without knowledge of this variable (i.e. in a
+different source file in which the variable wasn't declared). This is
+because @code{lose} might save the register and put some other value there.
+For example, you can't expect a global register variable to be available in
+the comparison-function that you pass to @code{qsort}, since @code{qsort}
+might have put something else in that register. (If you are prepared to
+recompile @code{qsort} with the same global register variable, you can
+solve this problem.)
+
+If you want to recompile @code{qsort} or other source files which do not
+actually use your global register variable, so that they will not use that
+register for any other purpose, then it suffices to specify the compiler
+option @samp{-ffixed-@var{reg}}. You need not actually add a global
+register declaration to their source code.
+
+A function which can alter the value of a global register variable cannot
+safely be called from a function compiled without this variable, because it
+could clobber the value the caller expects to find there on return.
+Therefore, the function which is the entry point into the part of the
+program that uses the global register variable must explicitly save and
+restore the value which belongs to its caller.
+
+@cindex register variable after @code{longjmp}
+@cindex global register after @code{longjmp}
+@cindex value after @code{longjmp}
+@findex longjmp
+@findex setjmp
+On most machines, @code{longjmp} will restore to each global register
+variable the value it had at the time of the @code{setjmp}. On some
+machines, however, @code{longjmp} will not change the value of global
+register variables. To be portable, the function that called @code{setjmp}
+should make other arrangements to save the values of the global register
+variables, and to restore them in a @code{longjmp}. This way, the same
+thing will happen regardless of what @code{longjmp} does.
+
+All global register variable declarations must precede all function
+definitions. If such a declaration could appear after function
+definitions, the declaration would be too late to prevent the register from
+being used for other purposes in the preceding functions.
+
+Global register variables may not have initial values, because an
+executable file has no means to supply initial contents for a register.
+
+On the Sparc, there are reports that g3 @dots{} g7 are suitable
+registers, but certain library functions, such as @code{getwd}, as well
+as the subroutines for division and remainder, modify g3 and g4. g1 and
+g2 are local temporaries.
+
+On the 68000, a2 @dots{} a5 should be suitable, as should d2 @dots{} d7.
+Of course, it will not do to use more than a few of those.
+
+@node Local Reg Vars
+@subsection Specifying Registers for Local Variables
+@cindex local variables, specifying registers
+@cindex specifying registers for local variables
+@cindex registers for local variables
+
+You can define a local register variable with a specified register
+like this:
+
+@example
+register int *foo asm ("a5");
+@end example
+
+@noindent
+Here @code{a5} is the name of the register which should be used. Note
+that this is the same syntax used for defining global register
+variables, but for a local variable it would appear within a function.
+
+Naturally the register name is cpu-dependent, but this is not a
+problem, since specific registers are most often useful with explicit
+assembler instructions (@pxref{Extended Asm}). Both of these things
+generally require that you conditionalize your program according to
+cpu type.
+
+In addition, operating systems on one type of cpu may differ in how they
+name the registers; then you would need additional conditionals. For
+example, some 68000 operating systems call this register @code{%a5}.
+
+Eventually there may be a way of asking the compiler to choose a register
+automatically, but first we need to figure out how it should choose and
+how to enable you to guide the choice. No solution is evident.
+
+Defining such a register variable does not reserve the register; it
+remains available for other uses in places where flow control determines
+the variable's value is not live. However, these registers are made
+unavailable for use in the reload pass. I would not be surprised if
+excessive use of this feature leaves the compiler too few available
+registers to compile certain functions.
+
+@node Alternate Keywords
+@section Alternate Keywords
+@cindex alternate keywords
+@cindex keywords, alternate
+
+The option @samp{-traditional} disables certain keywords; @samp{-ansi}
+disables certain others. This causes trouble when you want to use GNU C
+extensions, or ANSI C features, in a general-purpose header file that
+should be usable by all programs, including ANSI C programs and traditional
+ones. The keywords @code{asm}, @code{typeof} and @code{inline} cannot be
+used since they won't work in a program compiled with @samp{-ansi}, while
+the keywords @code{const}, @code{volatile}, @code{signed}, @code{typeof}
+and @code{inline} won't work in a program compiled with
+@samp{-traditional}.@refill
+
+The way to solve these problems is to put @samp{__} at the beginning and
+end of each problematical keyword. For example, use @code{__asm__}
+instead of @code{asm}, @code{__const__} instead of @code{const}, and
+@code{__inline__} instead of @code{inline}.
+
+Other C compilers won't accept these alternative keywords; if you want to
+compile with another compiler, you can define the alternate keywords as
+macros to replace them with the customary keywords. It looks like this:
+
+@example
+#ifndef __GNUC__
+#define __asm__ asm
+#endif
+@end example
+
+@samp{-pedantic} causes warnings for many GNU C extensions. You can
+prevent such warnings within one expression by writing
+@code{__extension__} before the expression. @code{__extension__} has no
+effect aside from this.
+
+@node Incomplete Enums
+@section Incomplete @code{enum} Types
+
+You can define an @code{enum} tag without specifying its possible values.
+This results in an incomplete type, much like what you get if you write
+@code{struct foo} without describing the elements. A later declaration
+which does specify the possible values completes the type.
+
+You can't allocate variables or storage using the type while it is
+incomplete. However, you can work with pointers to that type.
+
+This extension may not be very useful, but it makes the handling of
+@code{enum} more consistent with the way @code{struct} and @code{union}
+are handled.
+
+This extension is not supported by GNU C++.
+
+@node Function Names
+@section Function Names as Strings
+
+GNU CC predefines two string variables to be the name of the current function.
+The variable @code{__FUNCTION__} is the name of the function as it appears
+in the source. The variable @code{__PRETTY_FUNCTION__} is the name of
+the function pretty printed in a language specific fashion.
+
+These names are always the same in a C function, but in a C++ function
+they may be different. For example, this program:
+
+@smallexample
+extern "C" @{
+extern int printf (char *, ...);
+@}
+
+class a @{
+ public:
+ sub (int i)
+ @{
+ printf ("__FUNCTION__ = %s\n", __FUNCTION__);
+ printf ("__PRETTY_FUNCTION__ = %s\n", __PRETTY_FUNCTION__);
+ @}
+@};
+
+int
+main (void)
+@{
+ a ax;
+ ax.sub (0);
+ return 0;
+@}
+@end smallexample
+
+@noindent
+gives this output:
+
+@smallexample
+__FUNCTION__ = sub
+__PRETTY_FUNCTION__ = int a::sub (int)
+@end smallexample
+
+@node C++ Extensions
+@chapter Extensions to the C++ Language
+@cindex extensions, C++ language
+@cindex C++ language extensions
+
+The GNU compiler provides these extensions to the C++ language (and you
+can also use most of the C language extensions in your C++ programs). If you
+want to write code that checks whether these features are available, you can
+test for the GNU compiler the same way as for C programs: check for a
+predefined macro @code{__GNUC__}. You can also use @code{__GNUG__} to
+test specifically for GNU C++ (@pxref{Standard Predefined,,Standard
+Predefined Macros,cpp.info,The C Preprocessor}).
+
+@menu
+* Naming Results:: Giving a name to C++ function return values.
+* Min and Max:: C++ Minimum and maximum operators.
+* Destructors and Goto:: Goto is safe to use in C++ even when destructors
+ are needed.
+* C++ Interface:: You can use a single C++ header file for both
+ declarations and definitions.
+* Template Instantiation:: Methods for ensuring that exactly one copy of
+ each needed template instantiation is emitted.
+* C++ Signatures:: You can specify abstract types to get subtype
+ polymorphism independent from inheritance.
+@end menu
+
+@node Naming Results
+@section Named Return Values in C++
+
+@cindex @code{return}, in C++ function header
+@cindex return value, named, in C++
+@cindex named return value in C++
+@cindex C++ named return value
+GNU C++ extends the function-definition syntax to allow you to specify a
+name for the result of a function outside the body of the definition, in
+C++ programs:
+
+@example
+@group
+@var{type}
+@var{functionname} (@var{args}) return @var{resultname};
+@{
+ @dots{}
+ @var{body}
+ @dots{}
+@}
+@end group
+@end example
+
+You can use this feature to avoid an extra constructor call when
+a function result has a class type. For example, consider a function
+@code{m}, declared as @w{@samp{X v = m ();}}, whose result is of class
+@code{X}:
+
+@example
+X
+m ()
+@{
+ X b;
+ b.a = 23;
+ return b;
+@}
+@end example
+
+@cindex implicit argument: return value
+Although @code{m} appears to have no arguments, in fact it has one implicit
+argument: the address of the return value. At invocation, the address
+of enough space to hold @code{v} is sent in as the implicit argument.
+Then @code{b} is constructed and its @code{a} field is set to the value
+23. Finally, a copy constructor (a constructor of the form @samp{X(X&)})
+is applied to @code{b}, with the (implicit) return value location as the
+target, so that @code{v} is now bound to the return value.
+
+But this is wasteful. The local @code{b} is declared just to hold
+something that will be copied right out. While a compiler that
+combined an ``elision'' algorithm with interprocedural data flow
+analysis could conceivably eliminate all of this, it is much more
+practical to allow you to assist the compiler in generating
+efficient code by manipulating the return value explicitly,
+thus avoiding the local variable and copy constructor altogether.
+
+Using the extended GNU C++ function-definition syntax, you can avoid the
+temporary allocation and copying by naming @code{r} as your return value
+as the outset, and assigning to its @code{a} field directly:
+
+@example
+X
+m () return r;
+@{
+ r.a = 23;
+@}
+@end example
+
+@noindent
+The declaration of @code{r} is a standard, proper declaration, whose effects
+are executed @strong{before} any of the body of @code{m}.
+
+Functions of this type impose no additional restrictions; in particular,
+you can execute @code{return} statements, or return implicitly by
+reaching the end of the function body (``falling off the edge'').
+Cases like
+
+@example
+X
+m () return r (23);
+@{
+ return;
+@}
+@end example
+
+@noindent
+(or even @w{@samp{X m () return r (23); @{ @}}}) are unambiguous, since
+the return value @code{r} has been initialized in either case. The
+following code may be hard to read, but also works predictably:
+
+@example
+X
+m () return r;
+@{
+ X b;
+ return b;
+@}
+@end example
+
+The return value slot denoted by @code{r} is initialized at the outset,
+but the statement @samp{return b;} overrides this value. The compiler
+deals with this by destroying @code{r} (calling the destructor if there
+is one, or doing nothing if there is not), and then reinitializing
+@code{r} with @code{b}.
+
+This extension is provided primarily to help people who use overloaded
+operators, where there is a great need to control not just the
+arguments, but the return values of functions. For classes where the
+copy constructor incurs a heavy performance penalty (especially in the
+common case where there is a quick default constructor), this is a major
+savings. The disadvantage of this extension is that you do not control
+when the default constructor for the return value is called: it is
+always called at the beginning.
+
+@node Min and Max
+@section Minimum and Maximum Operators in C++
+
+It is very convenient to have operators which return the ``minimum'' or the
+``maximum'' of two arguments. In GNU C++ (but not in GNU C),
+
+@table @code
+@item @var{a} <? @var{b}
+@findex <?
+@cindex minimum operator
+is the @dfn{minimum}, returning the smaller of the numeric values
+@var{a} and @var{b};
+
+@item @var{a} >? @var{b}
+@findex >?
+@cindex maximum operator
+is the @dfn{maximum}, returning the larger of the numeric values @var{a}
+and @var{b}.
+@end table
+
+These operations are not primitive in ordinary C++, since you can
+use a macro to return the minimum of two things in C++, as in the
+following example.
+
+@example
+#define MIN(X,Y) ((X) < (Y) ? : (X) : (Y))
+@end example
+
+@noindent
+You might then use @w{@samp{int min = MIN (i, j);}} to set @var{min} to
+the minimum value of variables @var{i} and @var{j}.
+
+However, side effects in @code{X} or @code{Y} may cause unintended
+behavior. For example, @code{MIN (i++, j++)} will fail, incrementing
+the smaller counter twice. A GNU C extension allows you to write safe
+macros that avoid this kind of problem (@pxref{Naming Types,,Naming an
+Expression's Type}). However, writing @code{MIN} and @code{MAX} as
+macros also forces you to use function-call notation notation for a
+fundamental arithmetic operation. Using GNU C++ extensions, you can
+write @w{@samp{int min = i <? j;}} instead.
+
+Since @code{<?} and @code{>?} are built into the compiler, they properly
+handle expressions with side-effects; @w{@samp{int min = i++ <? j++;}}
+works correctly.
+
+@node Destructors and Goto
+@section @code{goto} and Destructors in GNU C++
+
+@cindex @code{goto} in C++
+@cindex destructors vs @code{goto}
+In C++ programs, you can safely use the @code{goto} statement. When you
+use it to exit a block which contains aggregates requiring destructors,
+the destructors will run before the @code{goto} transfers control. (In
+ANSI C++, @code{goto} is restricted to targets within the current
+block.)
+
+@cindex constructors vs @code{goto}
+The compiler still forbids using @code{goto} to @emph{enter} a scope
+that requires constructors.
+
+@node C++ Interface
+@section Declarations and Definitions in One Header
+
+@cindex interface and implementation headers, C++
+@cindex C++ interface and implementation headers
+C++ object definitions can be quite complex. In principle, your source
+code will need two kinds of things for each object that you use across
+more than one source file. First, you need an @dfn{interface}
+specification, describing its structure with type declarations and
+function prototypes. Second, you need the @dfn{implementation} itself.
+It can be tedious to maintain a separate interface description in a
+header file, in parallel to the actual implementation. It is also
+dangerous, since separate interface and implementation definitions may
+not remain parallel.
+
+@cindex pragmas, interface and implementation
+With GNU C++, you can use a single header file for both purposes.
+
+@quotation
+@emph{Warning:} The mechanism to specify this is in transition. For the
+nonce, you must use one of two @code{#pragma} commands; in a future
+release of GNU C++, an alternative mechanism will make these
+@code{#pragma} commands unnecessary.
+@end quotation
+
+The header file contains the full definitions, but is marked with
+@samp{#pragma interface} in the source code. This allows the compiler
+to use the header file only as an interface specification when ordinary
+source files incorporate it with @code{#include}. In the single source
+file where the full implementation belongs, you can use either a naming
+convention or @samp{#pragma implementation} to indicate this alternate
+use of the header file.
+
+@table @code
+@item #pragma interface
+@itemx #pragma interface "@var{subdir}/@var{objects}.h"
+@kindex #pragma interface
+Use this directive in @emph{header files} that define object classes, to save
+space in most of the object files that use those classes. Normally,
+local copies of certain information (backup copies of inline member
+functions, debugging information, and the internal tables that implement
+virtual functions) must be kept in each object file that includes class
+definitions. You can use this pragma to avoid such duplication. When a
+header file containing @samp{#pragma interface} is included in a
+compilation, this auxiliary information will not be generated (unless
+the main input source file itself uses @samp{#pragma implementation}).
+Instead, the object files will contain references to be resolved at link
+time.
+
+The second form of this directive is useful for the case where you have
+multiple headers with the same name in different directories. If you
+use this form, you must specify the same string to @samp{#pragma
+implementation}.
+
+@item #pragma implementation
+@itemx #pragma implementation "@var{objects}.h"
+@kindex #pragma implementation
+Use this pragma in a @emph{main input file}, when you want full output from
+included header files to be generated (and made globally visible). The
+included header file, in turn, should use @samp{#pragma interface}.
+Backup copies of inline member functions, debugging information, and the
+internal tables used to implement virtual functions are all generated in
+implementation files.
+
+@cindex implied @code{#pragma implementation}
+@cindex @code{#pragma implementation}, implied
+@cindex naming convention, implementation headers
+If you use @samp{#pragma implementation} with no argument, it applies to
+an include file with the same basename@footnote{A file's @dfn{basename}
+was the name stripped of all leading path information and of trailing
+suffixes, such as @samp{.h} or @samp{.C} or @samp{.cc}.} as your source
+file. For example, in @file{allclass.cc}, @samp{#pragma implementation}
+by itself is equivalent to @samp{#pragma implementation "allclass.h"}.
+
+In versions of GNU C++ prior to 2.6.0 @file{allclass.h} was treated as
+an implementation file whenever you would include it from
+@file{allclass.cc} even if you never specified @samp{#pragma
+implementation}. This was deemed to be more trouble than it was worth,
+however, and disabled.
+
+If you use an explicit @samp{#pragma implementation}, it must appear in
+your source file @emph{before} you include the affected header files.
+
+Use the string argument if you want a single implementation file to
+include code from multiple header files. (You must also use
+@samp{#include} to include the header file; @samp{#pragma
+implementation} only specifies how to use the file---it doesn't actually
+include it.)
+
+There is no way to split up the contents of a single header file into
+multiple implementation files.
+@end table
+
+@cindex inlining and C++ pragmas
+@cindex C++ pragmas, effect on inlining
+@cindex pragmas in C++, effect on inlining
+@samp{#pragma implementation} and @samp{#pragma interface} also have an
+effect on function inlining.
+
+If you define a class in a header file marked with @samp{#pragma
+interface}, the effect on a function defined in that class is similar to
+an explicit @code{extern} declaration---the compiler emits no code at
+all to define an independent version of the function. Its definition
+is used only for inlining with its callers.
+
+Conversely, when you include the same header file in a main source file
+that declares it as @samp{#pragma implementation}, the compiler emits
+code for the function itself; this defines a version of the function
+that can be found via pointers (or by callers compiled without
+inlining). If all calls to the function can be inlined, you can avoid
+emitting the function by compiling with @samp{-fno-implement-inlines}.
+If any calls were not inlined, you will get linker errors.
+
+@node Template Instantiation
+@section Where's the Template?
+
+@cindex template instantiation
+
+C++ templates are the first language feature to require more
+intelligence from the environment than one usually finds on a UNIX
+system. Somehow the compiler and linker have to make sure that each
+template instance occurs exactly once in the executable if it is needed,
+and not at all otherwise. There are two basic approaches to this
+problem, which I will refer to as the Borland model and the Cfront model.
+
+@table @asis
+@item Borland model
+Borland C++ solved the template instantiation problem by adding the code
+equivalent of common blocks to their linker; template instances
+are emitted in each translation unit that uses them, and they are
+collapsed together at run time. The advantage of this model is that the
+linker only has to consider the object files themselves; there is no
+external complexity to worry about. This disadvantage is that
+compilation time is increased because the template code is being
+compiled repeatedly. Code written for this model tends to include
+definitions of all member templates in the header file, since they must
+be seen to be compiled.
+
+@item Cfront model
+The AT&T C++ translator, Cfront, solved the template instantiation
+problem by creating the notion of a template repository, an
+automatically maintained place where template instances are stored. As
+individual object files are built, notes are placed in the repository to
+record where templates and potential type arguments were seen so that
+the subsequent instantiation step knows where to find them. At link
+time, any needed instances are generated and linked in. The advantages
+of this model are more optimal compilation speed and the ability to use
+the system linker; to implement the Borland model a compiler vendor also
+needs to replace the linker. The disadvantages are vastly increased
+complexity, and thus potential for error; theoretically, this should be
+just as transparent, but in practice it has been very difficult to build
+multiple programs in one directory and one program in multiple
+directories using Cfront. Code written for this model tends to separate
+definitions of non-inline member templates into a separate file, which
+is magically found by the link preprocessor when a template needs to be
+instantiated.
+@end table
+
+Currently, g++ implements neither automatic model. The g++ team hopes
+to have a repository working for 2.7.0. In the mean time, you have
+three options for dealing with template instantiations:
+
+@enumerate
+@item
+Do nothing. Pretend g++ does implement automatic instantiation
+management. Code written for the Borland model will work fine, but
+each translation unit will contain instances of each of the templates it
+uses. In a large program, this can lead to an unacceptable amount of code
+duplication.
+
+@item
+Add @samp{#pragma interface} to all files containing template
+definitions. For each of these files, add @samp{#pragma implementation
+"@var{filename}"} to the top of some @samp{.C} file which
+@samp{#include}s it. Then compile everything with -fexternal-templates.
+The templates will then only be expanded in the translation unit which
+implements them (i.e. has a @samp{#pragma implementation} line for the
+file where they live); all other files will use external references. If
+you're lucky, everything should work properly. If you get undefined
+symbol errors, you need to make sure that each template instance which
+is used in the program is used in the file which implements that
+template. If you don't have any use for a particular instance in that
+file, you can just instantiate it explicitly, using the syntax from the
+latest C++ working paper:
+
+@example
+template class A<int>;
+template ostream& operator << (ostream&, const A<int>&);
+@end example
+
+This strategy will work with code written for either model. If you are
+using code written for the Cfront model, the file containing a class
+template and the file containing its member templates should be
+implemented in the same translation unit.
+
+A slight variation on this approach is to use the flag
+-falt-external-templates instead; this flag causes template instances to
+be emitted in the translation unit that implements the header where they
+are first instantiated, rather than the one which implements the file
+where the templates are defined. This header must be the same in all
+translation units, or things are likely to break.
+
+@xref{C++ Interface,,Declarations and Definitions in One Header}, for
+more discussion of these pragmas.
+
+@item
+Explicitly instantiate all the template instances you use, and compile
+with -fno-implicit-templates. This is probably your best bet; it may
+require more knowledge of exactly which templates you are using, but
+it's less mysterious than the previous approach, and it doesn't require
+any @samp{#pragma}s or other g++-specific code. You can scatter the
+instantiations throughout your program, you can create one big file to
+do all the instantiations, or you can create tiny files like
+
+@example
+#include "Foo.h"
+#include "Foo.cc"
+
+template class Foo<int>;
+@end example
+
+for each instance you need, and create a template instantiation library
+from those. I'm partial to the last, but your mileage may vary. If you
+are using Cfront-model code, you can probably get away with not using
+-fno-implicit-templates when compiling files that don't @samp{#include}
+the member template definitions.
+@end enumerate
+
+@node C++ Signatures
+@section Type Abstraction using Signatures
+
+@findex signature
+@cindex type abstraction, C++
+@cindex C++ type abstraction
+@cindex subtype polymorphism, C++
+@cindex C++ subtype polymorphism
+@cindex signatures, C++
+@cindex C++ signatures
+
+In GNU C++, you can use the keyword @code{signature} to define a
+completely abstract class interface as a datatype. You can connect this
+abstraction with actual classes using signature pointers. If you want
+to use signatures, run the GNU compiler with the
+@samp{-fhandle-signatures} command-line option. (With this option, the
+compiler reserves a second keyword @code{sigof} as well, for a future
+extension.)
+
+Roughly, signatures are type abstractions or interfaces of classes.
+Some other languages have similar facilities. C++ signatures are
+related to ML's signatures, Haskell's type classes, definition modules
+in Modula-2, interface modules in Modula-3, abstract types in Emerald,
+type modules in Trellis/Owl, categories in Scratchpad II, and types in
+POOL-I. For a more detailed discussion of signatures, see
+@cite{Signatures: A C++ Extension for Type Abstraction and Subtype
+Polymorphism} by @w{Gerald} Baumgartner and Vincent F. Russo (Tech report
+CSD--TR--93--059, Dept. of Computer Sciences, Purdue University,
+September 1993, to appear in @emph{Software Practice & Experience}).
+You can get the tech report by anonymous FTP from
+@code{ftp.cs.purdue.edu} in @file{pub/reports/TR93-059.PS.Z}.
+
+Syntactically, a signature declaration is a collection of
+member function declarations and nested type declarations.
+For example, this signature declaration defines a new abstract type
+@code{S} with member functions @samp{int foo ()} and @samp{int bar (int)}:
+
+@example
+signature S
+@{
+ int foo ();
+ int bar (int);
+@};
+@end example
+
+Since signature types do not include implementation definitions, you
+cannot write an instance of a signature directly. Instead, you can
+define a pointer to any class that contains the required interfaces as a
+@dfn{signature pointer}. Such a class @dfn{implements} the signature
+type.
+@c Eventually signature references should work too.
+
+To use a class as an implementation of @code{S}, you must ensure that
+the class has public member functions @samp{int foo ()} and @samp{int
+bar (int)}. The class can have other member functions as well, public
+or not; as long as it offers what's declared in the signature, it is
+suitable as an implementation of that signature type.
+
+For example, suppose that @code{C} is a class that meets the
+requirements of signature @code{S} (@code{C} @dfn{conforms to}
+@code{S}). Then
+
+@example
+C obj;
+S * p = &obj;
+@end example
+
+@noindent
+defines a signature pointer @code{p} and initializes it to point to an
+object of type @code{C}.
+The member function call @w{@samp{int i = p->foo ();}}
+executes @samp{obj.foo ()}.
+
+@cindex @code{signature} in C++, advantages
+Abstract virtual classes provide somewhat similar facilities in standard
+C++. There are two main advantages to using signatures instead:
+
+@enumerate
+@item
+Subtyping becomes independent from inheritance. A class or signature
+type @code{T} is a subtype of a signature type @code{S} independent of
+any inheritance hierarchy as long as all the member functions declared
+in @code{S} are also found in @code{T}. So you can define a subtype
+hierarchy that is completely independent from any inheritance
+(implementation) hierarchy, instead of being forced to use types that
+mirror the class inheritance hierarchy.
+
+@item
+Signatures allow you to work with existing class hierarchies as
+implementations of a signature type. If those class hierarchies are
+only available in compiled form, you're out of luck with abstract virtual
+classes, since an abstract virtual class cannot be retrofitted on top of
+existing class hierarchies. So you would be required to write interface
+classes as subtypes of the abstract virtual class.
+@end enumerate
+
+@cindex default implementation, signature member function
+@cindex signature member function default implemention
+There is one more detail about signatures. A signature declaration can
+contain member function @emph{definitions} as well as member function
+declarations. A signature member function with a full definition is
+called a @emph{default implementation}; classes need not contain that
+particular interface in order to conform. For example, a
+class @code{C} can conform to the signature
+
+@example
+signature T
+@{
+ int f (int);
+ int f0 () @{ return f (0); @};
+@};
+@end example
+
+@noindent
+whether or not @code{C} implements the member function @samp{int f0 ()}.
+If you define @code{C::f0}, that definition takes precedence;
+otherwise, the default implementation @code{S::f0} applies.
+
+@ignore
+There will be more support for signatures in the future.
+Add to this doc as the implementation grows.
+In particular, the following features are planned but not yet
+implemented:
+@itemize @bullet
+@item signature references,
+@item signature inheritance,
+@item the @code{sigof} construct for extracting the signature information
+ of a class,
+@item views for renaming member functions when matching a class type
+ with a signature type,
+@item specifying exceptions with signature member functions, and
+@item signature templates.
+@end itemize
+This list is roughly in the order in which we intend to implement
+them. Watch this space for updates.
+@end ignore
diff --git a/gnu/usr.bin/cc/doc/gcc.texi b/gnu/usr.bin/cc/doc/gcc.texi
new file mode 100644
index 0000000..3523ae5
--- /dev/null
+++ b/gnu/usr.bin/cc/doc/gcc.texi
@@ -0,0 +1,4525 @@
+\input texinfo @c -*-texinfo-*-
+@c %**start of header
+@setfilename gcc.info
+@c @setfilename usegcc.info
+@c @setfilename portgcc.info
+@c To produce the full manual, use the "gcc.info" setfilename, and
+@c make sure the following do NOT begin with '@c' (and the @clear lines DO)
+@set INTERNALS
+@set USING
+@c To produce a user-only manual, use the "usegcc.info" setfilename, and
+@c make sure the following does NOT begin with '@c':
+@c @clear INTERNALS
+@c To produce a porter-only manual, use the "portgcc.info" setfilename,
+@c and make sure the following does NOT begin with '@c':
+@c @clear USING
+
+@c i have commented out the smallbook command below, and reformatted
+@c this manual in the regular book size for distribution. in addition,
+@c i commented out the commands that shift the text to one or the other
+@c side of the page for smallbook printing (which makes it easier for
+@c the photocopying people to handle...). -mew, 15june93
+
+@c (For FSF printing, turn on smallbook, comment out finalout below;
+@c that is all that is needed.)
+
+@c smallbook
+
+@c i also commented out the finalout command, so if there *are* any
+@c overfulls, you'll (hopefully) see the rectangle in the right hand
+@c margin. -mew 15june93
+@c finalout
+
+@c NOTE: checks/things to do:
+@c
+@c -have bob do a search in all seven files for "mew" (ideally --mew,
+@c but i may have forgotten the occasional "--"..).
+@c -item/itemx, text after all (sub/sub)section titles, etc..
+@c -consider putting the lists of options on pp 17--> etc in columns or
+@c somesuch.
+@c -spellcheck
+@c -continuity of phrasing; ie, bit-field vs bitfield in rtl.texi
+@c -overfulls. do a search for "mew" in the files, and you will see
+@c overfulls that i noted but could not deal with.
+@c -have to add text: beginning of chapter 8
+
+@c
+@c anything else? --mew 10feb93
+
+
+
+@ifset INTERNALS
+@ifset USING
+@settitle Using and Porting GNU CC
+@end ifset
+@end ifset
+@c seems reasonable to assume at least one of INTERNALS or USING is set...
+@ifclear INTERNALS
+@settitle Using GNU CC
+@end ifclear
+@ifclear USING
+@settitle Porting GNU CC
+@end ifclear
+
+@syncodeindex fn cp
+@syncodeindex vr cp
+@c %**end of header
+
+@c Use with @@smallbook.
+
+@c Cause even numbered pages to be printed on the left hand side of
+@c the page and odd numbered pages to be printed on the right hand
+@c side of the page. Using this, you can print on both sides of a
+@c sheet of paper and have the text on the same part of the sheet.
+
+@c The text on right hand pages is pushed towards the right hand
+@c margin and the text on left hand pages is pushed toward the left
+@c hand margin.
+@c (To provide the reverse effect, set bindingoffset to -0.75in.)
+
+@c @tex
+@c \global\bindingoffset=0.75in
+@c \global\normaloffset =0.75in
+@c @end tex
+
+@ifinfo
+@ifset INTERNALS
+@ifset USING
+This file documents the use and the internals of the GNU compiler.
+@end ifset
+@end ifset
+@ifclear USING
+This file documents the internals of the GNU compiler.
+@end ifclear
+@ifclear INTERNALS
+This file documents the use of the GNU compiler.
+@end ifclear
+
+Published by the Free Software Foundation
+675 Massachusetts Avenue
+Cambridge, MA 02139 USA
+
+Copyright (C) 1988, 1989, 1992, 1993, 1994 Free Software Foundation, Inc.
+
+Permission is granted to make and distribute verbatim copies of
+this manual provided the copyright notice and this permission notice
+are preserved on all copies.
+
+@ignore
+Permission is granted to process this file through Tex and print the
+results, provided the printed document carries copying permission
+notice identical to this one except for the removal of this paragraph
+(this paragraph not being relevant to the printed manual).
+
+@end ignore
+Permission is granted to copy and distribute modified versions of this
+manual under the conditions for verbatim copying, provided also that the
+sections entitled ``GNU General Public License,'' ``Funding for Free
+Software,'' and ``Protect Your Freedom---Fight `Look And Feel'@w{}'' are
+included exactly as in the original, and provided that the entire
+resulting derived work is distributed under the terms of a permission
+notice identical to this one.
+
+Permission is granted to copy and distribute translations of this manual
+into another language, under the above conditions for modified versions,
+except that the sections entitled ``GNU General Public License,''
+``Funding for Free Software,'' and ``Protect Your Freedom---Fight `Look
+And Feel'@w{}'', and this permission notice, may be included in
+translations approved by the Free Software Foundation instead of in the
+original English.
+@end ifinfo
+
+@setchapternewpage odd
+
+@titlepage
+@ifset INTERNALS
+@ifset USING
+@center @titlefont{Using and Porting GNU CC}
+
+@end ifset
+@end ifset
+@ifclear INTERNALS
+@title Using GNU CC
+@end ifclear
+@ifclear USING
+@title Porting GNU CC
+@end ifclear
+@sp 2
+@center Richard M. Stallman
+@sp 3
+@center Last updated 19 September 1994
+@sp 1
+@c The version number appears twice more in this file.
+
+@center for version 2.6
+@c @center (preliminary draft, which will change)
+@page
+@vskip 0pt plus 1filll
+Copyright @copyright{} 1988, 89, 92, 93, 1994 Free Software Foundation, Inc.
+@sp 2
+For GCC Version 2.6.@*
+@c Printed November, 1994.@*
+
+@c ISBN 1-882114-35-3
+@sp 1
+Published by the Free Software Foundation @*
+675 Massachusetts Avenue @*
+Cambridge, MA 02139 USA
+@sp 1
+Permission is granted to make and distribute verbatim copies of
+this manual provided the copyright notice and this permission notice
+are preserved on all copies.
+
+Permission is granted to copy and distribute modified versions of this
+manual under the conditions for verbatim copying, provided also that the
+sections entitled ``GNU General Public License,'' ``Funding for Free
+Software,'' and ``Protect Your Freedom---Fight `Look And Feel'@w{}'' are
+included exactly as in the original, and provided that the entire
+resulting derived work is distributed under the terms of a permission
+notice identical to this one.
+
+Permission is granted to copy and distribute translations of this manual
+into another language, under the above conditions for modified versions,
+except that the sections entitled ``GNU General Public License,''
+``Funding for Free Software,'' and ``Protect Your Freedom---Fight `Look
+And Feel'@w{}'', and this permission notice, may be included in
+translations approved by the Free Software Foundation instead of in the
+original English.
+@end titlepage
+@page
+
+@ifinfo
+
+@node Top, Copying,, (DIR)
+@top Introduction
+@cindex introduction
+
+@ifset INTERNALS
+@ifset USING
+This manual documents how to run, install and port the GNU
+compiler, as well as its new features and incompatibilities, and how to
+report bugs. It corresponds to GNU CC version 2.6.
+@end ifset
+@end ifset
+
+@ifclear INTERNALS
+This manual documents how to run and install the GNU compiler,
+as well as its new features and incompatibilities, and how to report
+bugs. It corresponds to GNU CC version 2.6.
+@end ifclear
+@ifclear USING
+This manual documents how to port the GNU compiler,
+as well as its new features and incompatibilities, and how to report
+bugs. It corresponds to GNU CC version 2.6.
+@end ifclear
+
+@end ifinfo
+@menu
+* Copying:: GNU General Public License says
+ how you can copy and share GNU CC.
+* Contributors:: People who have contributed to GNU CC.
+* Funding:: How to help assure funding for free software.
+* Look and Feel:: Protect your freedom---fight ``look and feel''.
+@ifset USING
+* G++ and GCC:: You can compile C or C++ programs.
+* Invoking GCC:: Command options supported by @samp{gcc}.
+* Installation:: How to configure, compile and install GNU CC.
+* C Extensions:: GNU extensions to the C language family.
+* C++ Extensions:: GNU extensions to the C++ language.
+* Trouble:: If you have trouble installing GNU CC.
+* Bugs:: How, why and where to report bugs.
+* Service:: How to find suppliers of support for GNU CC.
+* VMS:: Using GNU CC on VMS.
+@end ifset
+@ifset INTERNALS
+* Portability:: Goals of GNU CC's portability features.
+* Interface:: Function-call interface of GNU CC output.
+* Passes:: Order of passes, what they do, and what each file is for.
+* RTL:: The intermediate representation that most passes work on.
+* Machine Desc:: How to write machine description instruction patterns.
+* Target Macros:: How to write the machine description C macros.
+* Config:: Writing the @file{xm-@var{machine}.h} file.
+@end ifset
+
+* Index:: Index of concepts and symbol names.
+@end menu
+
+@node Copying
+@unnumbered GNU GENERAL PUBLIC LICENSE
+@center Version 2, June 1991
+
+@display
+Copyright @copyright{} 1989, 1991 Free Software Foundation, Inc.
+675 Mass Ave, Cambridge, MA 02139, USA
+
+Everyone is permitted to copy and distribute verbatim copies
+of this license document, but changing it is not allowed.
+@end display
+
+@unnumberedsec Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software---to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+@iftex
+@unnumberedsec TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+@end iftex
+@ifinfo
+@center TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+@end ifinfo
+
+@enumerate 0
+@item
+This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The ``Program'', below,
+refers to any such program or work, and a ``work based on the Program''
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term ``modification''.) Each licensee is addressed as ``you''.
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+@item
+You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+@item
+You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+@enumerate a
+@item
+You must cause the modified files to carry prominent notices
+stating that you changed the files and the date of any change.
+
+@item
+You must cause any work that you distribute or publish, that in
+whole or in part contains or is derived from the Program or any
+part thereof, to be licensed as a whole at no charge to all third
+parties under the terms of this License.
+
+@item
+If the modified program normally reads commands interactively
+when run, you must cause it, when started running for such
+interactive use in the most ordinary way, to print or display an
+announcement including an appropriate copyright notice and a
+notice that there is no warranty (or else, saying that you provide
+a warranty) and that users may redistribute the program under
+these conditions, and telling the user how to view a copy of this
+License. (Exception: if the Program itself is interactive but
+does not normally print such an announcement, your work based on
+the Program is not required to print an announcement.)
+@end enumerate
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+@item
+You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+@enumerate a
+@item
+Accompany it with the complete corresponding machine-readable
+source code, which must be distributed under the terms of Sections
+1 and 2 above on a medium customarily used for software interchange; or,
+
+@item
+Accompany it with a written offer, valid for at least three
+years, to give any third party, for a charge no more than your
+cost of physically performing source distribution, a complete
+machine-readable copy of the corresponding source code, to be
+distributed under the terms of Sections 1 and 2 above on a medium
+customarily used for software interchange; or,
+
+@item
+Accompany it with the information you received as to the offer
+to distribute corresponding source code. (This alternative is
+allowed only for noncommercial distribution and only if you
+received the program in object code or executable form with such
+an offer, in accord with Subsection b above.)
+@end enumerate
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+@item
+You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+@item
+You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+@item
+Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+@item
+If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+@item
+If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+@item
+The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and ``any
+later version'', you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+@item
+If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+@iftex
+@heading NO WARRANTY
+@end iftex
+@ifinfo
+@center NO WARRANTY
+@end ifinfo
+
+@item
+BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM ``AS IS'' WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+@item
+IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+@end enumerate
+
+@iftex
+@heading END OF TERMS AND CONDITIONS
+@end iftex
+@ifinfo
+@center END OF TERMS AND CONDITIONS
+@end ifinfo
+
+@page
+@unnumberedsec How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the ``copyright'' line and a pointer to where the full notice is found.
+
+@smallexample
+@var{one line to give the program's name and a brief idea of what it does.}
+Copyright (C) 19@var{yy} @var{name of author}
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+@end smallexample
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+@smallexample
+Gnomovision version 69, Copyright (C) 19@var{yy} @var{name of author}
+Gnomovision comes with ABSOLUTELY NO WARRANTY; for details
+type `show w'.
+This is free software, and you are welcome to redistribute it
+under certain conditions; type `show c' for details.
+@end smallexample
+
+The hypothetical commands @samp{show w} and @samp{show c} should show
+the appropriate parts of the General Public License. Of course, the
+commands you use may be called something other than @samp{show w} and
+@samp{show c}; they could even be mouse-clicks or menu items---whatever
+suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a ``copyright disclaimer'' for the program, if
+necessary. Here is a sample; alter the names:
+
+@smallexample
+Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+`Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+@var{signature of Ty Coon}, 1 April 1989
+Ty Coon, President of Vice
+@end smallexample
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
+
+@node Contributors
+@unnumbered Contributors to GNU CC
+@cindex contributors
+
+In addition to Richard Stallman, several people have written parts
+of GNU CC.
+
+@itemize @bullet
+@item
+The idea of using RTL and some of the optimization ideas came from the
+program PO written at the University of Arizona by Jack Davidson and
+Christopher Fraser. See ``Register Allocation and Exhaustive Peephole
+Optimization'', Software Practice and Experience 14 (9), Sept. 1984,
+857-866.
+
+@item
+Paul Rubin wrote most of the preprocessor.
+
+@item
+Leonard Tower wrote parts of the parser, RTL generator, and RTL
+definitions, and of the Vax machine description.
+
+@item
+Ted Lemon wrote parts of the RTL reader and printer.
+
+@item
+Jim Wilson implemented loop strength reduction and some other
+loop optimizations.
+
+@item
+Nobuyuki Hikichi of Software Research Associates, Tokyo, contributed
+the support for the Sony NEWS machine.
+
+@item
+Charles LaBrec contributed the support for the Integrated Solutions
+68020 system.
+
+@item
+Michael Tiemann of Cygnus Support wrote the front end for C++, as well
+as the support for inline functions and instruction scheduling. Also
+the descriptions of the National Semiconductor 32000 series cpu, the
+SPARC cpu and part of the Motorola 88000 cpu.
+
+@item
+Gerald Baumgartner added the signature extension to the C++ front-end.
+
+@item
+Jan Stein of the Chalmers Computer Society provided support for
+Genix, as well as part of the 32000 machine description.
+
+@item
+Randy Smith finished the Sun FPA support.
+
+@item
+Robert Brown implemented the support for Encore 32000 systems.
+
+@item
+David Kashtan of SRI adapted GNU CC to the Vomit-Making System (VMS).
+
+@item
+Alex Crain provided changes for the 3b1.
+
+@item
+Greg Satz and Chris Hanson assisted in making GNU CC work on HP-UX for
+the 9000 series 300.
+
+@item
+William Schelter did most of the work on the Intel 80386 support.
+
+@item
+Christopher Smith did the port for Convex machines.
+
+@item
+Paul Petersen wrote the machine description for the Alliant FX/8.
+
+@item
+Dario Dariol contributed the four varieties of sample programs
+that print a copy of their source.
+
+@item
+Alain Lichnewsky ported GNU CC to the Mips cpu.
+
+@item
+Devon Bowen, Dale Wiles and Kevin Zachmann ported GNU CC to the Tahoe.
+
+@item
+Jonathan Stone wrote the machine description for the Pyramid computer.
+
+@item
+Gary Miller ported GNU CC to Charles River Data Systems machines.
+
+@item
+Richard Kenner of the New York University Ultracomputer Research
+Laboratory wrote the machine descriptions for the AMD 29000, the DEC
+Alpha, the IBM RT PC, and the IBM RS/6000 as well as the support for
+instruction attributes. He also made changes to better support RISC
+processors including changes to common subexpression elimination,
+strength reduction, function calling sequence handling, and condition
+code support, in addition to generalizing the code for frame pointer
+elimination.
+
+@item
+Richard Kenner and Michael Tiemann jointly developed reorg.c, the delay
+slot scheduler.
+
+@item
+Mike Meissner and Tom Wood of Data General finished the port to the
+Motorola 88000.
+
+@item
+Masanobu Yuhara of Fujitsu Laboratories implemented the machine
+description for the Tron architecture (specifically, the Gmicro).
+
+@item
+NeXT, Inc.@: donated the front end that supports the Objective C
+language.
+@c We need to be careful to make it clear that "Objective C"
+@c is the name of a language, not that of a program or product.
+
+@item
+James van Artsdalen wrote the code that makes efficient use of
+the Intel 80387 register stack.
+
+@item
+Mike Meissner at the Open Software Foundation finished the port to the
+MIPS cpu, including adding ECOFF debug support, and worked on the
+Intel port for the Intel 80386 cpu.
+
+@item
+Ron Guilmette implemented the @code{protoize} and @code{unprotoize}
+tools, the support for Dwarf symbolic debugging information, and much of
+the support for System V Release 4. He has also worked heavily on the
+Intel 386 and 860 support.
+
+@item
+Torbjorn Granlund of the Swedish Institute of Computer Science
+implemented multiply-by-constant optimization and better long long
+support, and improved leaf function register allocation.
+
+@item
+Mike Stump implemented the support for Elxsi 64 bit CPU.
+
+@item
+John Wehle added the machine description for the Western Electric 32000
+processor used in several 3b series machines (no relation to the
+National Semiconductor 32000 processor).
+
+@ignore @c These features aren't advertised yet, since they don't fully work.
+@item
+Analog Devices helped implement the support for complex data types
+and iterators.
+@end ignore
+
+@item
+Holger Teutsch provided the support for the Clipper cpu.
+
+@item
+Kresten Krab Thorup wrote the run time support for the Objective C
+language.
+
+@item
+Stephen Moshier contributed the floating point emulator that assists in
+cross-compilation and permits support for floating point numbers wider
+than 64 bits.
+
+@item
+David Edelsohn contributed the changes to RS/6000 port to make it
+support the PowerPC and POWER2 architectures.
+
+@item
+Steve Chamberlain wrote the support for the Hitachi SH processor.
+
+@item
+Peter Schauer wrote the code to allow debugging to work on the Alpha.
+
+@item
+Oliver M. Kellogg of Deutsche Aerospace contributed the port to the
+MIL-STD-1750A.
+@end itemize
+
+@node Funding
+@chapter Funding Free Software
+
+If you want to have more free software a few years from now, it makes
+sense for you to help encourage people to contribute funds for its
+development. The most effective approach known is to encourage
+commercial redistributors to donate.
+
+Users of free software systems can boost the pace of development by
+encouraging for-a-fee distributors to donate part of their selling price
+to free software developers---the Free Software Foundation, and others.
+
+The way to convince distributors to do this is to demand it and expect
+it from them. So when you compare distributors, judge them partly by
+how much they give to free software development. Show distributors
+they must compete to be the one who gives the most.
+
+To make this approach work, you must insist on numbers that you can
+compare, such as, ``We will donate ten dollars to the Frobnitz project
+for each disk sold.'' Don't be satisfied with a vague promise, such as
+``A portion of the profits are donated,'' since it doesn't give a basis
+for comparison.
+
+Even a precise fraction ``of the profits from this disk'' is not very
+meaningful, since creative accounting and unrelated business decisions
+can greatly alter what fraction of the sales price counts as profit.
+If the price you pay is $50, ten percent of the profit is probably
+less than a dollar; it might be a few cents, or nothing at all.
+
+Some redistributors do development work themselves. This is useful too;
+but to keep everyone honest, you need to inquire how much they do, and
+what kind. Some kinds of development make much more long-term
+difference than others. For example, maintaining a separate version of
+a program contributes very little; maintaining the standard version of a
+program for the whole community contributes much. Easy new ports
+contribute little, since someone else would surely do them; difficult
+ports such as adding a new CPU to the GNU C compiler contribute more;
+major new features or packages contribute the most.
+
+By establishing the idea that supporting further development is ``the
+proper thing to do'' when distributing free software for a fee, we can
+assure a steady flow of resources into making more free software.
+
+@display
+Copyright (C) 1994 Free Software Foundation, Inc.
+Verbatim copying and redistribution of this section is permitted
+without royalty; alteration is not permitted.
+@end display
+
+@node Look and Feel
+@chapter Protect Your Freedom---Fight ``Look And Feel''
+@c the above chapter heading overflows onto the next line. --mew 1/26/93
+
+@quotation
+@i{This section is a political message from the League for Programming
+Freedom to the users of GNU CC. We have included it here because the
+issue of interface copyright is important to the GNU project.}
+@end quotation
+
+Apple and Lotus have tried to create a new form of legal monopoly: a
+copyright on a user interface.
+
+An interface is a kind of language---a set of conventions for
+communication between two entities, human or machine. Until a few years
+ago, the law seemed clear: interfaces were outside the domain of
+copyright, so programmers could program freely and implement whatever
+interface the users demanded. Imitating de-facto standard interfaces,
+sometimes with improvements, was standard practice in the computer
+field. These improvements, if accepted by the users, caught on and
+became the norm; in this way, much progress took place.
+
+Computer users, and most software developers, were happy with this state
+of affairs. However, large companies such as Apple and Lotus would
+prefer a different system---one in which they can own interfaces and
+thereby rid themselves of all serious competitors. They hope that
+interface copyright will give them, in effect, monopolies on major
+classes of software.
+
+Other large companies such as IBM and Digital also favor interface
+monopolies, for the same reason: if languages become property, they
+expect to own many de-facto standard languages. But Apple and Lotus are
+the ones who have actually sued. Lotus has won lawsuits against two
+small companies, which were thus put out of business. Then they sued
+Borland; this case is now before the court of appeals. Apple's lawsuit
+against HP and Microsoft is also being decided by an appeals court.
+Widespread rumors that Apple had lost the case are untrue; as of July
+1994, the final outcome is unknown.
+
+If the monopolists get their way, they will hobble the software field:
+
+@itemize @bullet
+@item
+Gratuitous incompatibilities will burden users. Imagine if each car
+manufacturer had to design a different way to start, stop, and steer a
+car.
+
+@item
+Users will be ``locked in'' to whichever interface they learn; then they
+will be prisoners of one supplier, who will charge a monopolistic price.
+
+@item
+Large companies have an unfair advantage wherever lawsuits become
+commonplace. Since they can afford to sue, they can intimidate smaller
+developers with threats even when they don't really have a case.
+
+@item
+Interface improvements will come slower, since incremental evolution
+through creative partial imitation will no longer occur.
+@end itemize
+
+If interface monopolies are accepted, other large companies are waiting
+to grab theirs:
+
+@itemize @bullet
+@item
+Adobe is expected to claim a monopoly on the interfaces of various popular
+application programs, if Borland's appeal against Lotus fails.
+
+@item
+Open Computing magazine reported a Microsoft vice president as threatening
+to sue people who copy the interface of Windows.
+@end itemize
+
+Users invest a great deal of time and money in learning to use computer
+interfaces. Far more, in fact, than software developers invest in
+developing @emph{and even implementing} the interfaces. Whoever can own
+an interface, has made its users into captives, and misappropriated
+their investment.
+
+To protect our freedom from monopolies like these, a group of
+programmers and users have formed a grass-roots political organization,
+the League for Programming Freedom.
+
+The purpose of the League is to oppose monopolistic practices such as
+interface copyright and software patents. The League calls for a return
+to the legal policies of the recent past, in which programmers could
+program freely. The League is not concerned with free software as an
+issue, and is not affiliated with the Free Software Foundation.
+
+The League's activities include publicizing the issue, as is being done
+here, and filing friend-of-the-court briefs on behalf of defendants sued
+by monopolists. Recently the League filed a friend-of-the-court brief
+for Borland in its appeal against Lotus.
+
+The League's membership rolls include John McCarthy, inventor of Lisp,
+Marvin Minsky, founder of the MIT Artificial Intelligence lab, Guy L.
+Steele, Jr., author of well-known books on Lisp and C, as well as
+Richard Stallman, the developer of GNU CC. Please join and add your
+name to the list. Membership dues in the League are $42 per year for
+programmers, managers and professionals; $10.50 for students; $21 for
+others.
+
+Activist members are especially important, but members who have no time
+to give are also important. Surveys at major ACM conferences have
+indicated a vast majority of attendees agree with the League. If just
+ten percent of the programmers who agree with the League join the
+League, we will probably triumph.
+
+To join, or for more information, phone (617) 243-4091 or write to:
+
+@display
+League for Programming Freedom
+1 Kendall Square #143
+P.O. Box 9171
+Cambridge, MA 02139
+@end display
+
+You can also send electronic mail to @code{lpf@@uunet.uu.net}.
+
+In addition to joining the League, here are some suggestions from the
+League for other things you can do to protect your freedom to write
+programs:
+
+@itemize @bullet
+@item
+Tell your friends and colleagues about this issue and how it threatens
+to ruin the computer industry.
+
+@item
+Mention that you are a League member in your @file{.signature}, and
+mention the League's email address for inquiries.
+
+@item
+Ask the companies you consider working for or working with to make
+statements against software monopolies, and give preference to those
+that do.
+
+@item
+When employers ask you to sign contracts giving them copyright or patent
+rights, insist on clauses saying they can use these rights only
+defensively. Don't rely on ``company policy,'' since that can change at
+any time; don't rely on an individual executive's private word, since
+that person may be replaced. Get a commitment just as binding as the
+commitment they get from you.
+
+@item
+Write to Congress to explain the importance of this issue.
+
+@display
+House Subcommittee on Intellectual Property
+2137 Rayburn Bldg
+Washington, DC 20515
+
+Senate Subcommittee on Patents, Trademarks and Copyrights
+United States Senate
+Washington, DC 20510
+@end display
+
+(These committees have received lots of mail already; let's give them
+even more.)
+@end itemize
+
+Democracy means nothing if you don't use it. Stand up and be counted!
+@ifset USING
+@node G++ and GCC
+@chapter Compile C, C++, or Objective C
+
+@cindex Objective C
+The C, C++, and Objective C versions of the compiler are integrated; the
+GNU C compiler can compile programs written in C, C++, or Objective C.
+
+@cindex GCC
+``GCC'' is a common shorthand term for the GNU C compiler. This is both
+the most general name for the compiler, and the name used when the
+emphasis is on compiling C programs.
+
+@cindex C++
+@cindex G++
+When referring to C++ compilation, it is usual to call the compiler
+``G++''. Since there is only one compiler, it is also accurate to call
+it ``GCC'' no matter what the language context; however, the term
+``G++'' is more useful when the emphasis is on compiling C++ programs.
+
+We use the name ``GNU CC'' to refer to the compilation system as a
+whole, and more specifically to the language-independent part of the
+compiler. For example, we refer to the optimization options as
+affecting the behavior of ``GNU CC'' or sometimes just ``the compiler''.
+
+Front ends for other languages, such as Ada 9X, Fortran, Modula-3, and
+Pascal, are under development. These front-ends, like that for C++, are
+built in subdirectories of GNU CC and link to it. The result is an
+integrated compiler that can compile programs written in C, C++,
+Objective C, or any of the languages for which you have installed front
+ends.
+
+In this manual, we only discuss the options for the C, Objective-C, and
+C++ compilers and those of the GNU CC core. Consult the documentation
+of the other front ends for the options to use when compiling programs
+written in other languages.
+
+@cindex compiler compared to C++ preprocessor
+@cindex intermediate C version, nonexistent
+@cindex C intermediate output, nonexistent
+G++ is a @emph{compiler}, not merely a preprocessor. G++ builds object
+code directly from your C++ program source. There is no intermediate C
+version of the program. (By contrast, for example, some other
+implementations use a program that generates a C program from your C++
+source.) Avoiding an intermediate C representation of the program means
+that you get better object code, and better debugging information. The
+GNU debugger, GDB, works with this information in the object code to
+give you comprehensive C++ source-level editing capabilities
+(@pxref{C,,C and C++,gdb.info, Debugging with GDB}).
+
+@c FIXME! Someone who knows something about Objective C ought to put in
+@c a paragraph or two about it here, and move the index entry down when
+@c there is more to point to than the general mention in the 1st par.
+
+@include invoke.texi
+
+@include install.texi
+
+@include extend.texi
+
+@node Trouble
+@chapter Known Causes of Trouble with GNU CC
+@cindex bugs, known
+@cindex installation trouble
+@cindex known causes of trouble
+
+This section describes known problems that affect users of GNU CC. Most
+of these are not GNU CC bugs per se---if they were, we would fix them.
+But the result for a user may be like the result of a bug.
+
+Some of these problems are due to bugs in other software, some are
+missing features that are too much work to add, and some are places
+where people's opinions differ as to what is best.
+
+@menu
+* Actual Bugs:: Bugs we will fix later.
+* Installation Problems:: Problems that manifest when you install GNU CC.
+* Cross-Compiler Problems:: Common problems of cross compiling with GNU CC.
+* Interoperation:: Problems using GNU CC with other compilers,
+ and with certain linkers, assemblers and debuggers.
+* External Bugs:: Problems compiling certain programs.
+* Incompatibilities:: GNU CC is incompatible with traditional C.
+* Fixed Headers:: GNU C uses corrected versions of system header files.
+ This is necessary, but doesn't always work smoothly.
+* Disappointments:: Regrettable things we can't change, but not quite bugs.
+* C++ Misunderstandings:: Common misunderstandings with GNU C++.
+* Protoize Caveats:: Things to watch out for when using @code{protoize}.
+* Non-bugs:: Things we think are right, but some others disagree.
+* Warnings and Errors:: Which problems in your code get warnings,
+ and which get errors.
+@end menu
+
+@node Actual Bugs
+@section Actual Bugs We Haven't Fixed Yet
+
+@itemize @bullet
+@item
+The @code{fixincludes} script interacts badly with automounters; if the
+directory of system header files is automounted, it tends to be
+unmounted while @code{fixincludes} is running. This would seem to be a
+bug in the automounter. We don't know any good way to work around it.
+
+@item
+The @code{fixproto} script will sometimes add prototypes for the
+@code{sigsetjmp} and @code{siglongjmp} functions that reference the
+@code{jmp_buf} type before that type is defined. To work around this,
+edit the offending file and place the typedef in front of the
+prototypes.
+
+@item
+There are several obscure case of mis-using struct, union, and
+enum tags that are not detected as errors by the compiler.
+
+@item
+When @samp{-pedantic-errors} is specified, GNU C will incorrectly give
+an error message when a function name is specified in an expression
+involving the comma operator.
+
+@item
+Loop unrolling doesn't work properly for certain C++ programs. This is
+a bug in the C++ front end. It sometimes emits incorrect debug info, and
+the loop unrolling code is unable to recover from this error.
+@end itemize
+
+@node Installation Problems
+@section Installation Problems
+
+This is a list of problems (and some apparent problems which don't
+really mean anything is wrong) that show up during installation of GNU
+CC.
+
+@itemize @bullet
+@item
+On certain systems, defining certain environment variables such as
+@code{CC} can interfere with the functioning of @code{make}.
+
+@item
+If you encounter seemingly strange errors when trying to build the
+compiler in a directory other than the source directory, it could be
+because you have previously configured the compiler in the source
+directory. Make sure you have done all the necessary preparations.
+@xref{Other Dir}.
+
+@item
+If you build GNU CC on a BSD system using a directory stored in a System
+V file system, problems may occur in running @code{fixincludes} if the
+System V file system doesn't support symbolic links. These problems
+result in a failure to fix the declaration of @code{size_t} in
+@file{sys/types.h}. If you find that @code{size_t} is a signed type and
+that type mismatches occur, this could be the cause.
+
+The solution is not to use such a directory for building GNU CC.
+
+@item
+In previous versions of GNU CC, the @code{gcc} driver program looked for
+@code{as} and @code{ld} in various places; for example, in files
+beginning with @file{/usr/local/lib/gcc-}. GNU CC version 2 looks for
+them in the directory
+@file{/usr/local/lib/gcc-lib/@var{target}/@var{version}}.
+
+Thus, to use a version of @code{as} or @code{ld} that is not the system
+default, for example @code{gas} or GNU @code{ld}, you must put them in
+that directory (or make links to them from that directory).
+
+@item
+Some commands executed when making the compiler may fail (return a
+non-zero status) and be ignored by @code{make}. These failures, which
+are often due to files that were not found, are expected, and can safely
+be ignored.
+
+@item
+It is normal to have warnings in compiling certain files about
+unreachable code and about enumeration type clashes. These files' names
+begin with @samp{insn-}. Also, @file{real.c} may get some warnings that
+you can ignore.
+
+@item
+Sometimes @code{make} recompiles parts of the compiler when installing
+the compiler. In one case, this was traced down to a bug in
+@code{make}. Either ignore the problem or switch to GNU Make.
+
+@item
+If you have installed a program known as purify, you may find that it
+causes errors while linking @code{enquire}, which is part of building
+GNU CC. The fix is to get rid of the file @code{real-ld} which purify
+installs---so that GNU CC won't try to use it.
+
+@item
+On Linux SLS 1.01, there is a problem with @file{libc.a}: it does not
+contain the obstack functions. However, GNU CC assumes that the obstack
+functions are in @file{libc.a} when it is the GNU C library. To work
+around this problem, change the @code{__GNU_LIBRARY__} conditional
+around line 31 to @samp{#if 1}.
+
+@item
+On some 386 systems, building the compiler never finishes because
+@code{enquire} hangs due to a hardware problem in the motherboard---it
+reports floating point exceptions to the kernel incorrectly. You can
+install GNU CC except for @file{float.h} by patching out the command to
+run @code{enquire}. You may also be able to fix the problem for real by
+getting a replacement motherboard. This problem was observed in
+Revision E of the Micronics motherboard, and is fixed in Revision F.
+It has also been observed in the MYLEX MXA-33 motherboard.
+
+If you encounter this problem, you may also want to consider removing
+the FPU from the socket during the compilation. Alternatively, if you
+are running SCO Unix, you can reboot and force the FPU to be ignored.
+To do this, type @samp{hd(40)unix auto ignorefpu}.
+
+@item
+On some 386 systems, GNU CC crashes trying to compile @file{enquire.c}.
+This happens on machines that don't have a 387 FPU chip. On 386
+machines, the system kernel is supposed to emulate the 387 when you
+don't have one. The crash is due to a bug in the emulator.
+
+One of these systems is the Unix from Interactive Systems: 386/ix.
+On this system, an alternate emulator is provided, and it does work.
+To use it, execute this command as super-user:
+
+@example
+ln /etc/emulator.rel1 /etc/emulator
+@end example
+
+@noindent
+and then reboot the system. (The default emulator file remains present
+under the name @file{emulator.dflt}.)
+
+Try using @file{/etc/emulator.att}, if you have such a problem on the
+SCO system.
+
+Another system which has this problem is Esix. We don't know whether it
+has an alternate emulator that works.
+
+On NetBSD 0.8, a similar problem manifests itself as these error messages:
+
+@example
+enquire.c: In function `fprop':
+enquire.c:2328: floating overflow
+@end example
+
+@item
+On SCO systems, when compiling GNU CC with the system's compiler,
+do not use @samp{-O}. Some versions of the system's compiler miscompile
+GNU CC with @samp{-O}.
+
+@cindex @code{genflags}, crash on Sun 4
+@item
+Sometimes on a Sun 4 you may observe a crash in the program
+@code{genflags} or @code{genoutput} while building GNU CC. This is said to
+be due to a bug in @code{sh}. You can probably get around it by running
+@code{genflags} or @code{genoutput} manually and then retrying the
+@code{make}.
+
+@item
+On Solaris 2, executables of GNU CC version 2.0.2 are commonly
+available, but they have a bug that shows up when compiling current
+versions of GNU CC: undefined symbol errors occur during assembly if you
+use @samp{-g}.
+
+The solution is to compile the current version of GNU CC without
+@samp{-g}. That makes a working compiler which you can use to recompile
+with @samp{-g}.
+
+@item
+Solaris 2 comes with a number of optional OS packages. Some of these
+packages are needed to use GNU CC fully. If you did not install all
+optional packages when installing Solaris, you will need to verify that
+the packages that GNU CC needs are installed.
+
+To check whether an optional package is installed, use
+the @code{pkginfo} command. To add an optional package, use the
+@code{pkgadd} command. For further details, see the Solaris
+documentation.
+
+For Solaris 2.0 and 2.1, GNU CC needs six packages: @samp{SUNWarc},
+@samp{SUNWbtool}, @samp{SUNWesu}, @samp{SUNWhea}, @samp{SUNWlibm}, and
+@samp{SUNWtoo}.
+
+For Solaris 2.2, GNU CC needs an additional seventh package: @samp{SUNWsprot}.
+
+@item
+On Solaris 2, trying to use the linker and other tools in
+@file{/usr/ucb} to install GNU CC has been observed to cause trouble.
+For example, the linker may hang indefinitely. The fix is to remove
+@file{/usr/ucb} from your @code{PATH}.
+
+@item
+If you use the 1.31 version of the MIPS assembler (such as was shipped
+with Ultrix 3.1), you will need to use the -fno-delayed-branch switch
+when optimizing floating point code. Otherwise, the assembler will
+complain when the GCC compiler fills a branch delay slot with a
+floating point instruction, such as @code{add.d}.
+
+@item
+If on a MIPS system you get an error message saying ``does not have gp
+sections for all it's [sic] sectons [sic]'', don't worry about it. This
+happens whenever you use GAS with the MIPS linker, but there is not
+really anything wrong, and it is okay to use the output file. You can
+stop such warnings by installing the GNU linker.
+
+It would be nice to extend GAS to produce the gp tables, but they are
+optional, and there should not be a warning about their absence.
+
+@item
+In Ultrix 4.0 on the MIPS machine, @file{stdio.h} does not work with GNU
+CC at all unless it has been fixed with @code{fixincludes}. This causes
+problems in building GNU CC. Once GNU CC is installed, the problems go
+away.
+
+To work around this problem, when making the stage 1 compiler, specify
+this option to Make:
+
+@example
+GCC_FOR_TARGET="./xgcc -B./ -I./include"
+@end example
+
+When making stage 2 and stage 3, specify this option:
+
+@example
+CFLAGS="-g -I./include"
+@end example
+
+@item
+Users have reported some problems with version 2.0 of the MIPS
+compiler tools that were shipped with Ultrix 4.1. Version 2.10
+which came with Ultrix 4.2 seems to work fine.
+
+Users have also reported some problems with version 2.20 of the
+MIPS compiler tools that were shipped with RISC/os 4.x. The earlier
+version 2.11 seems to work fine.
+
+@item
+Some versions of the MIPS linker will issue an assertion failure
+when linking code that uses @code{alloca} against shared
+libraries on RISC-OS 5.0, and DEC's OSF/1 systems. This is a bug
+in the linker, that is supposed to be fixed in future revisions.
+To protect against this, GNU CC passes @samp{-non_shared} to the
+linker unless you pass an explicit @samp{-shared} or
+@samp{-call_shared} switch.
+
+@item
+On System V release 3, you may get this error message
+while linking:
+
+@smallexample
+ld fatal: failed to write symbol name @var{something}
+ in strings table for file @var{whatever}
+@end smallexample
+
+This probably indicates that the disk is full or your ULIMIT won't allow
+the file to be as large as it needs to be.
+
+This problem can also result because the kernel parameter @code{MAXUMEM}
+is too small. If so, you must regenerate the kernel and make the value
+much larger. The default value is reported to be 1024; a value of 32768
+is said to work. Smaller values may also work.
+
+@item
+On System V, if you get an error like this,
+
+@example
+/usr/local/lib/bison.simple: In function `yyparse':
+/usr/local/lib/bison.simple:625: virtual memory exhausted
+@end example
+
+@noindent
+that too indicates a problem with disk space, ULIMIT, or @code{MAXUMEM}.
+
+@item
+Current GNU CC versions probably do not work on version 2 of the NeXT
+operating system.
+
+@item
+On NeXTStep 3.0, the Objective C compiler does not work, due,
+apparently, to a kernel bug that it happens to trigger. This problem
+does not happen on 3.1.
+
+@item
+On the Tower models 4@var{n}0 and 6@var{n}0, by default a process is not
+allowed to have more than one megabyte of memory. GNU CC cannot compile
+itself (or many other programs) with @samp{-O} in that much memory.
+
+To solve this problem, reconfigure the kernel adding the following line
+to the configuration file:
+
+@smallexample
+MAXUMEM = 4096
+@end smallexample
+
+@item
+On HP 9000 series 300 or 400 running HP-UX release 8.0, there is a bug
+in the assembler that must be fixed before GNU CC can be built. This
+bug manifests itself during the first stage of compilation, while
+building @file{libgcc2.a}:
+
+@smallexample
+_floatdisf
+cc1: warning: `-g' option not supported on this version of GCC
+cc1: warning: `-g1' option not supported on this version of GCC
+./xgcc: Internal compiler error: program as got fatal signal 11
+@end smallexample
+
+A patched version of the assembler is available by anonymous ftp from
+@code{altdorf.ai.mit.edu} as the file
+@file{archive/cph/hpux-8.0-assembler}. If you have HP software support,
+the patch can also be obtained directly from HP, as described in the
+following note:
+
+@quotation
+This is the patched assembler, to patch SR#1653-010439, where the
+assembler aborts on floating point constants.
+
+The bug is not really in the assembler, but in the shared library
+version of the function ``cvtnum(3c)''. The bug on ``cvtnum(3c)'' is
+SR#4701-078451. Anyway, the attached assembler uses the archive
+library version of ``cvtnum(3c)'' and thus does not exhibit the bug.
+@end quotation
+
+This patch is also known as PHCO_4484.
+
+@item
+On HP-UX version 8.05, but not on 8.07 or more recent versions,
+the @code{fixproto} shell script triggers a bug in the system shell.
+If you encounter this problem, upgrade your operating system or
+use BASH (the GNU shell) to run @code{fixproto}.
+
+@item
+Some versions of the Pyramid C compiler are reported to be unable to
+compile GNU CC. You must use an older version of GNU CC for
+bootstrapping. One indication of this problem is if you get a crash
+when GNU CC compiles the function @code{muldi3} in file @file{libgcc2.c}.
+
+You may be able to succeed by getting GNU CC version 1, installing it,
+and using it to compile GNU CC version 2. The bug in the Pyramid C
+compiler does not seem to affect GNU CC version 1.
+
+@item
+There may be similar problems on System V Release 3.1 on 386 systems.
+
+@item
+On the Intel Paragon (an i860 machine), if you are using operating
+system version 1.0, you will get warnings or errors about redefinition
+of @code{va_arg} when you build GNU CC.
+
+If this happens, then you need to link most programs with the library
+@file{iclib.a}. You must also modify @file{stdio.h} as follows: before
+the lines
+
+@example
+#if defined(__i860__) && !defined(_VA_LIST)
+#include <va_list.h>
+@end example
+
+@noindent
+insert the line
+
+@example
+#if __PGC__
+@end example
+
+@noindent
+and after the lines
+
+@example
+extern int vprintf(const char *, va_list );
+extern int vsprintf(char *, const char *, va_list );
+#endif
+@end example
+
+@noindent
+insert the line
+
+@example
+#endif /* __PGC__ */
+@end example
+
+These problems don't exist in operating system version 1.1.
+
+@item
+On the Altos 3068, programs compiled with GNU CC won't work unless you
+fix a kernel bug. This happens using system versions V.2.2 1.0gT1 and
+V.2.2 1.0e and perhaps later versions as well. See the file
+@file{README.ALTOS}.
+
+@item
+You will get several sorts of compilation and linking errors on the
+we32k if you don't follow the special instructions. @xref{Configurations}.
+
+@item
+A bug in the HP-UX 8.05 (and earlier) shell will cause the fixproto
+program to report an error of the form:
+
+@example
+./fixproto: sh internal 1K buffer overflow
+@end example
+
+To fix this, change the first line of the fixproto script to look like:
+
+@example
+#!/bin/ksh
+@end example
+@end itemize
+
+@node Cross-Compiler Problems
+@section Cross-Compiler Problems
+
+You may run into problems with cross compilation on certain machines,
+for several reasons.
+
+@itemize @bullet
+@item
+Cross compilation can run into trouble for certain machines because
+some target machines' assemblers require floating point numbers to be
+written as @emph{integer} constants in certain contexts.
+
+The compiler writes these integer constants by examining the floating
+point value as an integer and printing that integer, because this is
+simple to write and independent of the details of the floating point
+representation. But this does not work if the compiler is running on
+a different machine with an incompatible floating point format, or
+even a different byte-ordering.
+
+In addition, correct constant folding of floating point values
+requires representing them in the target machine's format.
+(The C standard does not quite require this, but in practice
+it is the only way to win.)
+
+It is now possible to overcome these problems by defining macros such
+as @code{REAL_VALUE_TYPE}. But doing so is a substantial amount of
+work for each target machine.
+@ifset INTERNALS
+@xref{Cross-compilation}.
+@end ifset
+@ifclear INTERNALS
+@xref{Cross-compilation,,Cross Compilation and Floating Point Format,
+gcc.info, Using and Porting GCC}.
+@end ifclear
+
+@item
+At present, the program @file{mips-tfile} which adds debug
+support to object files on MIPS systems does not work in a cross
+compile environment.
+@end itemize
+
+@node Interoperation
+@section Interoperation
+
+This section lists various difficulties encountered in using GNU C or
+GNU C++ together with other compilers or with the assemblers, linkers,
+libraries and debuggers on certain systems.
+
+@itemize @bullet
+@item
+Objective C does not work on the RS/6000.
+
+@item
+GNU C++ does not do name mangling in the same way as other C++
+compilers. This means that object files compiled with one compiler
+cannot be used with another.
+
+This effect is intentional, to protect you from more subtle problems.
+Compilers differ as to many internal details of C++ implementation,
+including: how class instances are laid out, how multiple inheritance is
+implemented, and how virtual function calls are handled. If the name
+encoding were made the same, your programs would link against libraries
+provided from other compilers---but the programs would then crash when
+run. Incompatible libraries are then detected at link time, rather than
+at run time.
+
+@item
+Older GDB versions sometimes fail to read the output of GNU CC version
+2. If you have trouble, get GDB version 4.4 or later.
+
+@item
+@cindex DBX
+DBX rejects some files produced by GNU CC, though it accepts similar
+constructs in output from PCC. Until someone can supply a coherent
+description of what is valid DBX input and what is not, there is
+nothing I can do about these problems. You are on your own.
+
+@item
+The GNU assembler (GAS) does not support PIC. To generate PIC code, you
+must use some other assembler, such as @file{/bin/as}.
+
+@item
+On some BSD systems, including some versions of Ultrix, use of profiling
+causes static variable destructors (currently used only in C++) not to
+be run.
+
+@item
+Use of @samp{-I/usr/include} may cause trouble.
+
+Many systems come with header files that won't work with GNU CC unless
+corrected by @code{fixincludes}. The corrected header files go in a new
+directory; GNU CC searches this directory before @file{/usr/include}.
+If you use @samp{-I/usr/include}, this tells GNU CC to search
+@file{/usr/include} earlier on, before the corrected headers. The
+result is that you get the uncorrected header files.
+
+Instead, you should use these options (when compiling C programs):
+
+@smallexample
+-I/usr/local/lib/gcc-lib/@var{target}/@var{version}/include -I/usr/include
+@end smallexample
+
+For C++ programs, GNU CC also uses a special directory that defines C++
+interfaces to standard C subroutines. This directory is meant to be
+searched @emph{before} other standard include directories, so that it
+takes precedence. If you are compiling C++ programs and specifying
+include directories explicitly, use this option first, then the two
+options above:
+
+@example
+-I/usr/local/lib/g++-include
+@end example
+
+@ignore
+@cindex @code{vfork}, for the Sun-4
+@item
+There is a bug in @code{vfork} on the Sun-4 which causes the registers
+of the child process to clobber those of the parent. Because of this,
+programs that call @code{vfork} are likely to lose when compiled
+optimized with GNU CC when the child code alters registers which contain
+C variables in the parent. This affects variables which are live in the
+parent across the call to @code{vfork}.
+
+If you encounter this, you can work around the problem by declaring
+variables @code{volatile} in the function that calls @code{vfork}, until
+the problem goes away, or by not declaring them @code{register} and not
+using @samp{-O} for those source files.
+@end ignore
+
+@item
+On some SGI systems, when you use @samp{-lgl_s} as an option,
+it gets translated magically to @samp{-lgl_s -lX11_s -lc_s}.
+Naturally, this does not happen when you use GNU CC.
+You must specify all three options explicitly.
+
+@item
+On a Sparc, GNU CC aligns all values of type @code{double} on an 8-byte
+boundary, and it expects every @code{double} to be so aligned. The Sun
+compiler usually gives @code{double} values 8-byte alignment, with one
+exception: function arguments of type @code{double} may not be aligned.
+
+As a result, if a function compiled with Sun CC takes the address of an
+argument of type @code{double} and passes this pointer of type
+@code{double *} to a function compiled with GNU CC, dereferencing the
+pointer may cause a fatal signal.
+
+One way to solve this problem is to compile your entire program with GNU
+CC. Another solution is to modify the function that is compiled with
+Sun CC to copy the argument into a local variable; local variables
+are always properly aligned. A third solution is to modify the function
+that uses the pointer to dereference it via the following function
+@code{access_double} instead of directly with @samp{*}:
+
+@smallexample
+inline double
+access_double (double *unaligned_ptr)
+@{
+ union d2i @{ double d; int i[2]; @};
+
+ union d2i *p = (union d2i *) unaligned_ptr;
+ union d2i u;
+
+ u.i[0] = p->i[0];
+ u.i[1] = p->i[1];
+
+ return u.d;
+@}
+@end smallexample
+
+@noindent
+Storing into the pointer can be done likewise with the same union.
+
+@item
+On Solaris, the @code{malloc} function in the @file{libmalloc.a} library
+may allocate memory that is only 4 byte aligned. Since GNU CC on the
+Sparc assumes that doubles are 8 byte aligned, this may result in a
+fatal signal if doubles are stored in memory allocated by the
+@file{libmalloc.a} library.
+
+The solution is to not use the @file{libmalloc.a} library. Use instead
+@code{malloc} and related functions from @file{libc.a}; they do not have
+this problem.
+
+@item
+Sun forgot to include a static version of @file{libdl.a} with some
+versions of SunOS (mainly 4.1). This results in undefined symbols when
+linking static binaries (that is, if you use @samp{-static}). If you
+see undefined symbols @code{_dlclose}, @code{_dlsym} or @code{_dlopen}
+when linking, compile and link against the file
+@file{mit/util/misc/dlsym.c} from the MIT version of X windows.
+
+@item
+The 128-bit long double format that the Sparc port supports currently
+works by using the architecturally defined quad-word floating point
+instructions. Since there is no hardware that supports these instructions
+they must be emulated by the operating system. Long doubles do not work
+in Sun OS versions 4.0.3 and earlier, because the kernel eumulator uses an
+obsolete and incompatible format. Long doubles do not work in Sun OS
+versions 4.1.1 to 4.1.3 because of emululator bugs that cause random
+unpredicatable failures. Long doubles appear to work in Sun OS 5.x
+(Solaris 2.x).
+
+@item
+On HP-UX version 9.01 on the HP PA, the HP compiler @code{cc} does not
+compile GNU CC correctly. We do not yet know why. However, GNU CC
+compiled on earlier HP-UX versions works properly on HP-UX 9.01 and can
+compile itself properly on 9.01.
+
+@item
+On the HP PA machine, ADB sometimes fails to work on functions compiled
+with GNU CC. Specifically, it fails to work on functions that use
+@code{alloca} or variable-size arrays. This is because GNU CC doesn't
+generate HP-UX unwind descriptors for such functions. It may even be
+impossible to generate them.
+
+@item
+Debugging (@samp{-g}) is not supported on the HP PA machine, unless you use
+the preliminary GNU tools (@pxref{Installation}).
+
+@item
+Taking the address of a label may generate errors from the HP-UX
+PA assembler. GAS for the PA does not have this problem.
+
+@item
+Using floating point parameters for indirect calls to static functions
+will not work when using the HP assembler. There simply is no way for GCC
+to specify what registers hold arguments for static functions when using
+the HP assembler. GAS for the PA does not have this problem.
+
+@item
+For some very large functions you may receive errors from the HP linker
+complaining about an out of bounds unconditional branch offset. Fixing
+this problem correctly requires fixing problems in GNU CC and GAS. We
+hope to fix this in time for GNU CC 2.6. Until then you can work around
+by making your function smaller, and if you are using GAS, splitting the
+function into multiple source files may be necessary.
+
+@item
+GNU CC compiled code sometimes emits warnings from the HP-UX assembler of
+the form:
+
+@smallexample
+(warning) Use of GR3 when
+ frame >= 8192 may cause conflict.
+@end smallexample
+
+These warnings are harmless and can be safely ignored.
+
+@item
+The current version of the assembler (@file{/bin/as}) for the RS/6000
+has certain problems that prevent the @samp{-g} option in GCC from
+working. Note that @file{Makefile.in} uses @samp{-g} by default when
+compiling @file{libgcc2.c}.
+
+IBM has produced a fixed version of the assembler. The upgraded
+assembler unfortunately was not included in any of the AIX 3.2 update
+PTF releases (3.2.2, 3.2.3, or 3.2.3e). Users of AIX 3.1 should request
+PTF U403044 from IBM and users of AIX 3.2 should request PTF U416277.
+See the file @file{README.RS6000} for more details on these updates.
+
+You can test for the presense of a fixed assembler by using the
+command
+
+@smallexample
+as -u < /dev/null
+@end smallexample
+
+@noindent
+If the command exits normally, the assembler fix already is installed.
+If the assembler complains that "-u" is an unknown flag, you need to
+order the fix.
+
+@item
+On the IBM RS/6000, compiling code of the form
+
+@smallexample
+extern int foo;
+
+@dots{} foo @dots{}
+
+static int foo;
+@end smallexample
+
+@noindent
+will cause the linker to report an undefined symbol @code{foo}.
+Although this behavior differs from most other systems, it is not a
+bug because redefining an @code{extern} variable as @code{static}
+is undefined in ANSI C.
+
+@item
+AIX on the RS/6000 provides support (NLS) for environments outside of
+the United States. Compilers and assemblers use NLS to support
+locale-specific representations of various objects including
+floating-point numbers ("." vs "," for separating decimal fractions).
+There have been problems reported where the library linked with GCC does
+not produce the same floating-point formats that the assembler accepts.
+If you have this problem, set the LANG environment variable to "C" or
+"En_US".
+
+@item
+Even if you specify @samp{-fdollars-in-identifiers},
+you cannot successfully use @samp{$} in identifiers on the RS/6000 due
+to a restriction in the IBM assembler. GAS supports these
+identifiers.
+
+@item
+On the RS/6000, XLC version 1.3.0.0 will miscompile @file{jump.c}. XLC
+version 1.3.0.1 or later fixes this problem. You can obtain XLC-1.3.0.2
+by requesting PTF 421749 from IBM.
+
+@item
+There is an assembler bug in versions of DG/UX prior to 5.4.2.01 that
+occurs when the @samp{fldcr} instruction is used. GNU CC uses
+@samp{fldcr} on the 88100 to serialize volatile memory references. Use
+the option @samp{-mno-serialize-volatile} if your version of the
+assembler has this bug.
+
+@item
+On VMS, GAS versions 1.38.1 and earlier may cause spurious warning
+messages from the linker. These warning messages complain of mismatched
+psect attributes. You can ignore them. @xref{VMS Install}.
+
+@item
+On NewsOS version 3, if you include both of the files @file{stddef.h}
+and @file{sys/types.h}, you get an error because there are two typedefs
+of @code{size_t}. You should change @file{sys/types.h} by adding these
+lines around the definition of @code{size_t}:
+
+@smallexample
+#ifndef _SIZE_T
+#define _SIZE_T
+@var{actual typedef here}
+#endif
+@end smallexample
+
+@cindex Alliant
+@item
+On the Alliant, the system's own convention for returning structures
+and unions is unusual, and is not compatible with GNU CC no matter
+what options are used.
+
+@cindex RT PC
+@cindex IBM RT PC
+@item
+On the IBM RT PC, the MetaWare HighC compiler (hc) uses a different
+convention for structure and union returning. Use the option
+@samp{-mhc-struct-return} to tell GNU CC to use a convention compatible
+with it.
+
+@cindex Vax calling convention
+@cindex Ultrix calling convention
+@item
+On Ultrix, the Fortran compiler expects registers 2 through 5 to be saved
+by function calls. However, the C compiler uses conventions compatible
+with BSD Unix: registers 2 through 5 may be clobbered by function calls.
+
+GNU CC uses the same convention as the Ultrix C compiler. You can use
+these options to produce code compatible with the Fortran compiler:
+
+@smallexample
+-fcall-saved-r2 -fcall-saved-r3 -fcall-saved-r4 -fcall-saved-r5
+@end smallexample
+
+@item
+On the WE32k, you may find that programs compiled with GNU CC do not
+work with the standard shared C ilbrary. You may need to link with
+the ordinary C compiler. If you do so, you must specify the following
+options:
+
+@smallexample
+-L/usr/local/lib/gcc-lib/we32k-att-sysv/2.6.0 -lgcc -lc_s
+@end smallexample
+
+The first specifies where to find the library @file{libgcc.a}
+specified with the @samp{-lgcc} option.
+
+GNU CC does linking by invoking @code{ld}, just as @code{cc} does, and
+there is no reason why it @emph{should} matter which compilation program
+you use to invoke @code{ld}. If someone tracks this problem down,
+it can probably be fixed easily.
+
+@item
+On the Alpha, you may get assembler errors about invalid syntax as a
+result of floating point constants. This is due to a bug in the C
+library functions @code{ecvt}, @code{fcvt} and @code{gcvt}. Given valid
+floating point numbers, they sometimes print @samp{NaN}.
+
+@item
+On Irix 4.0.5F (and perhaps in some other versions), an assembler bug
+sometimes reorders instructions incorrectly when optimization is turned
+on. If you think this may be happening to you, try using the GNU
+assembler; GAS version 2.1 supports ECOFF on Irix.
+
+Or use the @samp{-noasmopt} option when you compile GNU CC with itself,
+and then again when you compile your program. (This is a temporary
+kludge to turn off assembler optimization on Irix.) If this proves to
+be what you need, edit the assembler spec in the file @file{specs} so
+that it unconditionally passes @samp{-O0} to the assembler, and never
+passes @samp{-O2} or @samp{-O3}.
+@end itemize
+
+@node External Bugs
+@section Problems Compiling Certain Programs
+
+@c prevent bad page break with this line
+Certain programs have problems compiling.
+
+@itemize @bullet
+@item
+Parse errors may occur compiling X11 on a Decstation running Ultrix 4.2
+because of problems in DEC's versions of the X11 header files
+@file{X11/Xlib.h} and @file{X11/Xutil.h}. People recommend adding
+@samp{-I/usr/include/mit} to use the MIT versions of the header files,
+using the @samp{-traditional} switch to turn off ANSI C, or fixing the
+header files by adding this:
+
+@example
+#ifdef __STDC__
+#define NeedFunctionPrototypes 0
+#endif
+@end example
+
+@item
+If you have trouble compiling Perl on a SunOS 4 system, it may be
+because Perl specifies @samp{-I/usr/ucbinclude}. This accesses the
+unfixed header files. Perl specifies the options
+
+@example
+-traditional -Dvolatile=__volatile__
+-I/usr/include/sun -I/usr/ucbinclude
+-fpcc-struct-return
+@end example
+
+@noindent
+most of which are unnecessary with GCC 2.4.5 and newer versions. You
+can make a properly working Perl by setting @code{ccflags} to
+@samp{-fwritable-strings} (implied by the @samp{-traditional} in the
+original options) and @code{cppflags} to empty in @file{config.sh}, then
+typing @samp{./doSH; make depend; make}.
+
+@item
+On various 386 Unix systems derived from System V, including SCO, ISC,
+and ESIX, you may get error messages about running out of virtual memory
+while compiling certain programs.
+
+You can prevent this problem by linking GNU CC with the GNU malloc
+(which thus replaces the malloc that comes with the system). GNU malloc
+is available as a separate package, and also in the file
+@file{src/gmalloc.c} in the GNU Emacs 19 distribution.
+
+If you have installed GNU malloc as a separate library package, use this
+option when you relink GNU CC:
+
+@example
+MALLOC=/usr/local/lib/libgmalloc.a
+@end example
+
+Alternatively, if you have compiled @file{gmalloc.c} from Emacs 19, copy
+the object file to @file{gmalloc.o} and use this option when you relink
+GNU CC:
+
+@example
+MALLOC=gmalloc.o
+@end example
+@end itemize
+
+@node Incompatibilities
+@section Incompatibilities of GNU CC
+@cindex incompatibilities of GNU CC
+
+There are several noteworthy incompatibilities between GNU C and most
+existing (non-ANSI) versions of C. The @samp{-traditional} option
+eliminates many of these incompatibilities, @emph{but not all}, by
+telling GNU C to behave like the other C compilers.
+
+@itemize @bullet
+@cindex string constants
+@cindex read-only strings
+@cindex shared strings
+@item
+GNU CC normally makes string constants read-only. If several
+identical-looking string constants are used, GNU CC stores only one
+copy of the string.
+
+@cindex @code{mktemp}, and constant strings
+One consequence is that you cannot call @code{mktemp} with a string
+constant argument. The function @code{mktemp} always alters the
+string its argument points to.
+
+@cindex @code{sscanf}, and constant strings
+@cindex @code{fscanf}, and constant strings
+@cindex @code{scanf}, and constant strings
+Another consequence is that @code{sscanf} does not work on some systems
+when passed a string constant as its format control string or input.
+This is because @code{sscanf} incorrectly tries to write into the string
+constant. Likewise @code{fscanf} and @code{scanf}.
+
+The best solution to these problems is to change the program to use
+@code{char}-array variables with initialization strings for these
+purposes instead of string constants. But if this is not possible,
+you can use the @samp{-fwritable-strings} flag, which directs GNU CC
+to handle string constants the same way most C compilers do.
+@samp{-traditional} also has this effect, among others.
+
+@item
+@code{-2147483648} is positive.
+
+This is because 2147483648 cannot fit in the type @code{int}, so
+(following the ANSI C rules) its data type is @code{unsigned long int}.
+Negating this value yields 2147483648 again.
+
+@item
+GNU CC does not substitute macro arguments when they appear inside of
+string constants. For example, the following macro in GNU CC
+
+@example
+#define foo(a) "a"
+@end example
+
+@noindent
+will produce output @code{"a"} regardless of what the argument @var{a} is.
+
+The @samp{-traditional} option directs GNU CC to handle such cases
+(among others) in the old-fashioned (non-ANSI) fashion.
+
+@cindex @code{setjmp} incompatibilities
+@cindex @code{longjmp} incompatibilities
+@item
+When you use @code{setjmp} and @code{longjmp}, the only automatic
+variables guaranteed to remain valid are those declared
+@code{volatile}. This is a consequence of automatic register
+allocation. Consider this function:
+
+@example
+jmp_buf j;
+
+foo ()
+@{
+ int a, b;
+
+ a = fun1 ();
+ if (setjmp (j))
+ return a;
+
+ a = fun2 ();
+ /* @r{@code{longjmp (j)} may occur in @code{fun3}.} */
+ return a + fun3 ();
+@}
+@end example
+
+Here @code{a} may or may not be restored to its first value when the
+@code{longjmp} occurs. If @code{a} is allocated in a register, then
+its first value is restored; otherwise, it keeps the last value stored
+in it.
+
+If you use the @samp{-W} option with the @samp{-O} option, you will
+get a warning when GNU CC thinks such a problem might be possible.
+
+The @samp{-traditional} option directs GNU C to put variables in
+the stack by default, rather than in registers, in functions that
+call @code{setjmp}. This results in the behavior found in
+traditional C compilers.
+
+@item
+Programs that use preprocessor directives in the middle of macro
+arguments do not work with GNU CC. For example, a program like this
+will not work:
+
+@example
+foobar (
+#define luser
+ hack)
+@end example
+
+ANSI C does not permit such a construct. It would make sense to support
+it when @samp{-traditional} is used, but it is too much work to
+implement.
+
+@cindex external declaration scope
+@cindex scope of external declarations
+@cindex declaration scope
+@item
+Declarations of external variables and functions within a block apply
+only to the block containing the declaration. In other words, they
+have the same scope as any other declaration in the same place.
+
+In some other C compilers, a @code{extern} declaration affects all the
+rest of the file even if it happens within a block.
+
+The @samp{-traditional} option directs GNU C to treat all @code{extern}
+declarations as global, like traditional compilers.
+
+@item
+In traditional C, you can combine @code{long}, etc., with a typedef name,
+as shown here:
+
+@example
+typedef int foo;
+typedef long foo bar;
+@end example
+
+In ANSI C, this is not allowed: @code{long} and other type modifiers
+require an explicit @code{int}. Because this criterion is expressed
+by Bison grammar rules rather than C code, the @samp{-traditional}
+flag cannot alter it.
+
+@cindex typedef names as function parameters
+@item
+PCC allows typedef names to be used as function parameters. The
+difficulty described immediately above applies here too.
+
+@cindex whitespace
+@item
+PCC allows whitespace in the middle of compound assignment operators
+such as @samp{+=}. GNU CC, following the ANSI standard, does not
+allow this. The difficulty described immediately above applies here
+too.
+
+@cindex apostrophes
+@cindex '
+@item
+GNU CC complains about unterminated character constants inside of
+preprocessor conditionals that fail. Some programs have English
+comments enclosed in conditionals that are guaranteed to fail; if these
+comments contain apostrophes, GNU CC will probably report an error. For
+example, this code would produce an error:
+
+@example
+#if 0
+You can't expect this to work.
+#endif
+@end example
+
+The best solution to such a problem is to put the text into an actual
+C comment delimited by @samp{/*@dots{}*/}. However,
+@samp{-traditional} suppresses these error messages.
+
+@item
+Many user programs contain the declaration @samp{long time ();}. In the
+past, the system header files on many systems did not actually declare
+@code{time}, so it did not matter what type your program declared it to
+return. But in systems with ANSI C headers, @code{time} is declared to
+return @code{time_t}, and if that is not the same as @code{long}, then
+@samp{long time ();} is erroneous.
+
+The solution is to change your program to use @code{time_t} as the return
+type of @code{time}.
+
+@cindex @code{float} as function value type
+@item
+When compiling functions that return @code{float}, PCC converts it to
+a double. GNU CC actually returns a @code{float}. If you are concerned
+with PCC compatibility, you should declare your functions to return
+@code{double}; you might as well say what you mean.
+
+@cindex structures
+@cindex unions
+@item
+When compiling functions that return structures or unions, GNU CC
+output code normally uses a method different from that used on most
+versions of Unix. As a result, code compiled with GNU CC cannot call
+a structure-returning function compiled with PCC, and vice versa.
+
+The method used by GNU CC is as follows: a structure or union which is
+1, 2, 4 or 8 bytes long is returned like a scalar. A structure or union
+with any other size is stored into an address supplied by the caller
+(usually in a special, fixed register, but on some machines it is passed
+on the stack). The machine-description macros @code{STRUCT_VALUE} and
+@code{STRUCT_INCOMING_VALUE} tell GNU CC where to pass this address.
+
+By contrast, PCC on most target machines returns structures and unions
+of any size by copying the data into an area of static storage, and then
+returning the address of that storage as if it were a pointer value.
+The caller must copy the data from that memory area to the place where
+the value is wanted. GNU CC does not use this method because it is
+slower and nonreentrant.
+
+On some newer machines, PCC uses a reentrant convention for all
+structure and union returning. GNU CC on most of these machines uses a
+compatible convention when returning structures and unions in memory,
+but still returns small structures and unions in registers.
+
+You can tell GNU CC to use a compatible convention for all structure and
+union returning with the option @samp{-fpcc-struct-return}.
+
+@cindex preprocessing tokens
+@cindex preprocessing numbers
+@item
+GNU C complains about program fragments such as @samp{0x74ae-0x4000}
+which appear to be two hexadecimal constants separated by the minus
+operator. Actually, this string is a single @dfn{preprocessing token}.
+Each such token must correspond to one token in C. Since this does not,
+GNU C prints an error message. Although it may appear obvious that what
+is meant is an operator and two values, the ANSI C standard specifically
+requires that this be treated as erroneous.
+
+A @dfn{preprocessing token} is a @dfn{preprocessing number} if it
+begins with a digit and is followed by letters, underscores, digits,
+periods and @samp{e+}, @samp{e-}, @samp{E+}, or @samp{E-} character
+sequences.
+
+To make the above program fragment valid, place whitespace in front of
+the minus sign. This whitespace will end the preprocessing number.
+@end itemize
+
+@node Fixed Headers
+@section Fixed Header Files
+
+GNU CC needs to install corrected versions of some system header files.
+This is because most target systems have some header files that won't
+work with GNU CC unless they are changed. Some have bugs, some are
+incompatible with ANSI C, and some depend on special features of other
+compilers.
+
+Installing GNU CC automatically creates and installs the fixed header
+files, by running a program called @code{fixincludes} (or for certain
+targets an alternative such as @code{fixinc.svr4}). Normally, you
+don't need to pay attention to this. But there are cases where it
+doesn't do the right thing automatically.
+
+@itemize @bullet
+@item
+If you update the system's header files, such as by installing a new
+system version, the fixed header files of GNU CC are not automatically
+updated. The easiest way to update them is to reinstall GNU CC. (If
+you want to be clever, look in the makefile and you can find a
+shortcut.)
+
+@item
+On some systems, in particular SunOS 4, header file directories contain
+machine-specific symbolic links in certain places. This makes it
+possible to share most of the header files among hosts running the
+same version of SunOS 4 on different machine models.
+
+The programs that fix the header files do not understand this special
+way of using symbolic links; therefore, the directory of fixed header
+files is good only for the machine model used to build it.
+
+In SunOS 4, only programs that look inside the kernel will notice the
+difference between machine models. Therefore, for most purposes, you
+need not be concerned about this.
+
+It is possible to make separate sets of fixed header files for the
+different machine models, and arrange a structure of symbolic links so
+as to use the proper set, but you'll have to do this by hand.
+
+@item
+On Lynxos, GNU CC by default does not fix the header files. This is
+because bugs in the shell cause the @code{fixincludes} script to fail.
+
+This means you will encounter problems due to bugs in the system header
+files. It may be no comfort that they aren't GNU CC's fault, but it
+does mean that there's nothing for us to do about them.
+@end itemize
+
+@node Disappointments
+@section Disappointments and Misunderstandings
+
+These problems are perhaps regrettable, but we don't know any practical
+way around them.
+
+@itemize @bullet
+@item
+Certain local variables aren't recognized by debuggers when you compile
+with optimization.
+
+This occurs because sometimes GNU CC optimizes the variable out of
+existence. There is no way to tell the debugger how to compute the
+value such a variable ``would have had'', and it is not clear that would
+be desirable anyway. So GNU CC simply does not mention the eliminated
+variable when it writes debugging information.
+
+You have to expect a certain amount of disagreement between the
+executable and your source code, when you use optimization.
+
+@cindex conflicting types
+@cindex scope of declaration
+@item
+Users often think it is a bug when GNU CC reports an error for code
+like this:
+
+@example
+int foo (struct mumble *);
+
+struct mumble @{ @dots{} @};
+
+int foo (struct mumble *x)
+@{ @dots{} @}
+@end example
+
+This code really is erroneous, because the scope of @code{struct
+mumble} in the prototype is limited to the argument list containing it.
+It does not refer to the @code{struct mumble} defined with file scope
+immediately below---they are two unrelated types with similar names in
+different scopes.
+
+But in the definition of @code{foo}, the file-scope type is used
+because that is available to be inherited. Thus, the definition and
+the prototype do not match, and you get an error.
+
+This behavior may seem silly, but it's what the ANSI standard specifies.
+It is easy enough for you to make your code work by moving the
+definition of @code{struct mumble} above the prototype. It's not worth
+being incompatible with ANSI C just to avoid an error for the example
+shown above.
+
+@item
+Accesses to bitfields even in volatile objects works by accessing larger
+objects, such as a byte or a word. You cannot rely on what size of
+object is accessed in order to read or write the bitfield; it may even
+vary for a given bitfield according to the precise usage.
+
+If you care about controlling the amount of memory that is accessed, use
+volatile but do not use bitfields.
+
+@item
+GNU CC comes with shell scripts to fix certain known problems in system
+header files. They install corrected copies of various header files in
+a special directory where only GNU CC will normally look for them. The
+scripts adapt to various systems by searching all the system header
+files for the problem cases that we know about.
+
+If new system header files are installed, nothing automatically arranges
+to update the corrected header files. You will have to reinstall GNU CC
+to fix the new header files. More specifically, go to the build
+directory and delete the files @file{stmp-fixinc} and
+@file{stmp-headers}, and the subdirectory @code{include}; then do
+@samp{make install} again.
+
+@item
+On 68000 systems, you can get paradoxical results if you test the
+precise values of floating point numbers. For example, you can find
+that a floating point value which is not a NaN is not equal to itself.
+This results from the fact that the the floating point registers hold a
+few more bits of precision than fit in a @code{double} in memory.
+Compiled code moves values between memory and floating point registers
+at its convenience, and moving them into memory truncates them.
+
+You can partially avoid this problem by using the @samp{-ffloat-store}
+option (@pxref{Optimize Options}).
+
+@item
+On the MIPS, variable argument functions using @file{varargs.h}
+cannot have a floating point value for the first argument. The
+reason for this is that in the absence of a prototype in scope,
+if the first argument is a floating point, it is passed in a
+floating point register, rather than an integer register.
+
+If the code is rewritten to use the ANSI standard @file{stdarg.h}
+method of variable arguments, and the prototype is in scope at
+the time of the call, everything will work fine.
+@end itemize
+
+@node C++ Misunderstandings
+@section Common Misunderstandings with GNU C++
+
+@cindex misunderstandings in C++
+@cindex surprises in C++
+@cindex C++ misunderstandings
+C++ is a complex language and an evolving one, and its standard definition
+(the ANSI C++ draft standard) is also evolving. As a result,
+your C++ compiler may occasionally surprise you, even when its behavior is
+correct. This section discusses some areas that frequently give rise to
+questions of this sort.
+
+@menu
+* Static Definitions:: Static member declarations are not definitions
+* Temporaries:: Temporaries may vanish before you expect
+@end menu
+
+@node Static Definitions
+@subsection Declare @emph{and} Define Static Members
+
+@cindex C++ static data, declaring and defining
+@cindex static data in C++, declaring and defining
+@cindex declaring static data in C++
+@cindex defining static data in C++
+When a class has static data members, it is not enough to @emph{declare}
+the static member; you must also @emph{define} it. For example:
+
+@example
+class Foo
+@{
+ @dots{}
+ void method();
+ static int bar;
+@};
+@end example
+
+This declaration only establishes that the class @code{Foo} has an
+@code{int} named @code{Foo::bar}, and a member function named
+@code{Foo::method}. But you still need to define @emph{both}
+@code{method} and @code{bar} elsewhere. According to the draft ANSI
+standard, you must supply an initializer in one (and only one) source
+file, such as:
+
+@example
+int Foo::bar = 0;
+@end example
+
+Other C++ compilers may not correctly implement the standard behavior.
+As a result, when you switch to @code{g++} from one of these compilers,
+you may discover that a program that appeared to work correctly in fact
+does not conform to the standard: @code{g++} reports as undefined
+symbols any static data members that lack definitions.
+
+@node Temporaries
+@subsection Temporaries May Vanish Before You Expect
+
+@cindex temporaries, lifetime of
+@cindex portions of temporary objects, pointers to
+It is dangerous to use pointers or references to @emph{portions} of a
+temporary object. The compiler may very well delete the object before
+you expect it to, leaving a pointer to garbage. The most common place
+where this problem crops up is in classes like the libg++
+@code{String} class, that define a conversion function to type
+@code{char *} or @code{const char *}. However, any class that returns
+a pointer to some internal structure is potentially subject to this
+problem.
+
+For example, a program may use a function @code{strfunc} that returns
+@code{String} objects, and another function @code{charfunc} that
+operates on pointers to @code{char}:
+
+@example
+String strfunc ();
+void charfunc (const char *);
+@end example
+
+@noindent
+In this situation, it may seem natural to write @w{@samp{charfunc
+(strfunc ());}} based on the knowledge that class @code{String} has an
+explicit conversion to @code{char} pointers. However, what really
+happens is akin to @samp{charfunc (@w{strfunc ()}.@w{convert ()});},
+where the @code{convert} method is a function to do the same data
+conversion normally performed by a cast. Since the last use of the
+temporary @code{String} object is the call to the conversion function,
+the compiler may delete that object before actually calling
+@code{charfunc}. The compiler has no way of knowing that deleting the
+@code{String} object will invalidate the pointer. The pointer then
+points to garbage, so that by the time @code{charfunc} is called, it
+gets an invalid argument.
+
+Code like this may run successfully under some other compilers,
+especially those that delete temporaries relatively late. However, the
+GNU C++ behavior is also standard-conformant, so if your program depends
+on late destruction of temporaries it is not portable.
+
+If you think this is surprising, you should be aware that the ANSI C++
+committee continues to debate the lifetime-of-temporaries problem.
+
+For now, at least, the safe way to write such code is to give the
+temporary a name, which forces it to remain until the end of the scope of
+the name. For example:
+
+@example
+String& tmp = strfunc ();
+charfunc (tmp);
+@end example
+
+@node Protoize Caveats
+@section Caveats of using @code{protoize}
+
+The conversion programs @code{protoize} and @code{unprotoize} can
+sometimes change a source file in a way that won't work unless you
+rearrange it.
+
+@itemize @bullet
+@item
+@code{protoize} can insert references to a type name or type tag before
+the definition, or in a file where they are not defined.
+
+If this happens, compiler error messages should show you where the new
+references are, so fixing the file by hand is straightforward.
+
+@item
+There are some C constructs which @code{protoize} cannot figure out.
+For example, it can't determine argument types for declaring a
+pointer-to-function variable; this you must do by hand. @code{protoize}
+inserts a comment containing @samp{???} each time it finds such a
+variable; so you can find all such variables by searching for this
+string. ANSI C does not require declaring the argument types of
+pointer-to-function types.
+
+@item
+Using @code{unprotoize} can easily introduce bugs. If the program
+relied on prototypes to bring about conversion of arguments, these
+conversions will not take place in the program without prototypes.
+One case in which you can be sure @code{unprotoize} is safe is when
+you are removing prototypes that were made with @code{protoize}; if
+the program worked before without any prototypes, it will work again
+without them.
+
+You can find all the places where this problem might occur by compiling
+the program with the @samp{-Wconversion} option. It prints a warning
+whenever an argument is converted.
+
+@item
+Both conversion programs can be confused if there are macro calls in and
+around the text to be converted. In other words, the standard syntax
+for a declaration or definition must not result from expanding a macro.
+This problem is inherent in the design of C and cannot be fixed. If
+only a few functions have confusing macro calls, you can easily convert
+them manually.
+
+@item
+@code{protoize} cannot get the argument types for a function whose
+definition was not actually compiled due to preprocessor conditionals.
+When this happens, @code{protoize} changes nothing in regard to such
+a function. @code{protoize} tries to detect such instances and warn
+about them.
+
+You can generally work around this problem by using @code{protoize} step
+by step, each time specifying a different set of @samp{-D} options for
+compilation, until all of the functions have been converted. There is
+no automatic way to verify that you have got them all, however.
+
+@item
+Confusion may result if there is an occasion to convert a function
+declaration or definition in a region of source code where there is more
+than one formal parameter list present. Thus, attempts to convert code
+containing multiple (conditionally compiled) versions of a single
+function header (in the same vicinity) may not produce the desired (or
+expected) results.
+
+If you plan on converting source files which contain such code, it is
+recommended that you first make sure that each conditionally compiled
+region of source code which contains an alternative function header also
+contains at least one additional follower token (past the final right
+parenthesis of the function header). This should circumvent the
+problem.
+
+@item
+@code{unprotoize} can become confused when trying to convert a function
+definition or declaration which contains a declaration for a
+pointer-to-function formal argument which has the same name as the
+function being defined or declared. We recommand you avoid such choices
+of formal parameter names.
+
+@item
+You might also want to correct some of the indentation by hand and break
+long lines. (The conversion programs don't write lines longer than
+eighty characters in any case.)
+@end itemize
+
+@node Non-bugs
+@section Certain Changes We Don't Want to Make
+
+This section lists changes that people frequently request, but which
+we do not make because we think GNU CC is better without them.
+
+@itemize @bullet
+@item
+Checking the number and type of arguments to a function which has an
+old-fashioned definition and no prototype.
+
+Such a feature would work only occasionally---only for calls that appear
+in the same file as the called function, following the definition. The
+only way to check all calls reliably is to add a prototype for the
+function. But adding a prototype eliminates the motivation for this
+feature. So the feature is not worthwhile.
+
+@item
+Warning about using an expression whose type is signed as a shift count.
+
+Shift count operands are probably signed more often than unsigned.
+Warning about this would cause far more annoyance than good.
+
+@item
+Warning about assigning a signed value to an unsigned variable.
+
+Such assignments must be very common; warning about them would cause
+more annoyance than good.
+
+@item
+Warning about unreachable code.
+
+It's very common to have unreachable code in machine-generated
+programs. For example, this happens normally in some files of GNU C
+itself.
+
+@item
+Warning when a non-void function value is ignored.
+
+Coming as I do from a Lisp background, I balk at the idea that there is
+something dangerous about discarding a value. There are functions that
+return values which some callers may find useful; it makes no sense to
+clutter the program with a cast to @code{void} whenever the value isn't
+useful.
+
+@item
+Assuming (for optimization) that the address of an external symbol is
+never zero.
+
+This assumption is false on certain systems when @samp{#pragma weak} is
+used.
+
+@item
+Making @samp{-fshort-enums} the default.
+
+This would cause storage layout to be incompatible with most other C
+compilers. And it doesn't seem very important, given that you can get
+the same result in other ways. The case where it matters most is when
+the enumeration-valued object is inside a structure, and in that case
+you can specify a field width explicitly.
+
+@item
+Making bitfields unsigned by default on particular machines where ``the
+ABI standard'' says to do so.
+
+The ANSI C standard leaves it up to the implementation whether a bitfield
+declared plain @code{int} is signed or not. This in effect creates two
+alternative dialects of C.
+
+The GNU C compiler supports both dialects; you can specify the signed
+dialect with @samp{-fsigned-bitfields} and the unsigned dialect with
+@samp{-funsigned-bitfields}. However, this leaves open the question of
+which dialect to use by default.
+
+Currently, the preferred dialect makes plain bitfields signed, because
+this is simplest. Since @code{int} is the same as @code{signed int} in
+every other context, it is cleanest for them to be the same in bitfields
+as well.
+
+Some computer manufacturers have published Application Binary Interface
+standards which specify that plain bitfields should be unsigned. It is
+a mistake, however, to say anything about this issue in an ABI. This is
+because the handling of plain bitfields distinguishes two dialects of C.
+Both dialects are meaningful on every type of machine. Whether a
+particular object file was compiled using signed bitfields or unsigned
+is of no concern to other object files, even if they access the same
+bitfields in the same data structures.
+
+A given program is written in one or the other of these two dialects.
+The program stands a chance to work on most any machine if it is
+compiled with the proper dialect. It is unlikely to work at all if
+compiled with the wrong dialect.
+
+Many users appreciate the GNU C compiler because it provides an
+environment that is uniform across machines. These users would be
+inconvenienced if the compiler treated plain bitfields differently on
+certain machines.
+
+Occasionally users write programs intended only for a particular machine
+type. On these occasions, the users would benefit if the GNU C compiler
+were to support by default the same dialect as the other compilers on
+that machine. But such applications are rare. And users writing a
+program to run on more than one type of machine cannot possibly benefit
+from this kind of compatibility.
+
+This is why GNU CC does and will treat plain bitfields in the same
+fashion on all types of machines (by default).
+
+There are some arguments for making bitfields unsigned by default on all
+machines. If, for example, this becomes a universal de facto standard,
+it would make sense for GNU CC to go along with it. This is something
+to be considered in the future.
+
+(Of course, users strongly concerned about portability should indicate
+explicitly in each bitfield whether it is signed or not. In this way,
+they write programs which have the same meaning in both C dialects.)
+
+@item
+Undefining @code{__STDC__} when @samp{-ansi} is not used.
+
+Currently, GNU CC defines @code{__STDC__} as long as you don't use
+@samp{-traditional}. This provides good results in practice.
+
+Programmers normally use conditionals on @code{__STDC__} to ask whether
+it is safe to use certain features of ANSI C, such as function
+prototypes or ANSI token concatenation. Since plain @samp{gcc} supports
+all the features of ANSI C, the correct answer to these questions is
+``yes''.
+
+Some users try to use @code{__STDC__} to check for the availability of
+certain library facilities. This is actually incorrect usage in an ANSI
+C program, because the ANSI C standard says that a conforming
+freestanding implementation should define @code{__STDC__} even though it
+does not have the library facilities. @samp{gcc -ansi -pedantic} is a
+conforming freestanding implementation, and it is therefore required to
+define @code{__STDC__}, even though it does not come with an ANSI C
+library.
+
+Sometimes people say that defining @code{__STDC__} in a compiler that
+does not completely conform to the ANSI C standard somehow violates the
+standard. This is illogical. The standard is a standard for compilers
+that claim to support ANSI C, such as @samp{gcc -ansi}---not for other
+compilers such as plain @samp{gcc}. Whatever the ANSI C standard says
+is relevant to the design of plain @samp{gcc} without @samp{-ansi} only
+for pragmatic reasons, not as a requirement.
+
+@item
+Undefining @code{__STDC__} in C++.
+
+Programs written to compile with C++-to-C translators get the
+value of @code{__STDC__} that goes with the C compiler that is
+subsequently used. These programs must test @code{__STDC__}
+to determine what kind of C preprocessor that compiler uses:
+whether they should concatenate tokens in the ANSI C fashion
+or in the traditional fashion.
+
+These programs work properly with GNU C++ if @code{__STDC__} is defined.
+They would not work otherwise.
+
+In addition, many header files are written to provide prototypes in ANSI
+C but not in traditional C. Many of these header files can work without
+change in C++ provided @code{__STDC__} is defined. If @code{__STDC__}
+is not defined, they will all fail, and will all need to be changed to
+test explicitly for C++ as well.
+
+@item
+Deleting ``empty'' loops.
+
+GNU CC does not delete ``empty'' loops because the most likely reason
+you would put one in a program is to have a delay. Deleting them will
+not make real programs run any faster, so it would be pointless.
+
+It would be different if optimization of a nonempty loop could produce
+an empty one. But this generally can't happen.
+
+@item
+Making side effects happen in the same order as in some other compiler.
+
+@cindex side effects, order of evaluation
+@cindex order of evaluation, side effects
+It is never safe to depend on the order of evaluation of side effects.
+For example, a function call like this may very well behave differently
+from one compiler to another:
+
+@example
+void func (int, int);
+
+int i = 2;
+func (i++, i++);
+@end example
+
+There is no guarantee (in either the C or the C++ standard language
+definitions) that the increments will be evaluated in any particular
+order. Either increment might happen first. @code{func} might get the
+arguments @samp{3, 4}, or it might get @samp{4, 3}, or even @samp{3, 3}.
+
+@item
+Not allowing structures with volatile fields in registers.
+
+Strictly speaking, there is no prohibition in the ANSI C standard
+against allowing structures with volatile fields in registers, but
+it does not seem to make any sense and is probably not what you wanted
+to do. So the compiler will give an error message in this case.
+@end itemize
+
+@node Warnings and Errors
+@section Warning Messages and Error Messages
+
+@cindex error messages
+@cindex warnings vs errors
+@cindex messages, warning and error
+The GNU compiler can produce two kinds of diagnostics: errors and
+warnings. Each kind has a different purpose:
+
+@itemize @w{}
+@item
+@emph{Errors} report problems that make it impossible to compile your
+program. GNU CC reports errors with the source file name and line
+number where the problem is apparent.
+
+@item
+@emph{Warnings} report other unusual conditions in your code that
+@emph{may} indicate a problem, although compilation can (and does)
+proceed. Warning messages also report the source file name and line
+number, but include the text @samp{warning:} to distinguish them
+from error messages.
+@end itemize
+
+Warnings may indicate danger points where you should check to make sure
+that your program really does what you intend; or the use of obsolete
+features; or the use of nonstandard features of GNU C or C++. Many
+warnings are issued only if you ask for them, with one of the @samp{-W}
+options (for instance, @samp{-Wall} requests a variety of useful
+warnings).
+
+GNU CC always tries to compile your program if possible; it never
+gratuituously rejects a program whose meaning is clear merely because
+(for instance) it fails to conform to a standard. In some cases,
+however, the C and C++ standards specify that certain extensions are
+forbidden, and a diagnostic @emph{must} be issued by a conforming
+compiler. The @samp{-pedantic} option tells GNU CC to issue warnings in
+such cases; @samp{-pedantic-errors} says to make them errors instead.
+This does not mean that @emph{all} non-ANSI constructs get warnings
+or errors.
+
+@xref{Warning Options,,Options to Request or Suppress Warnings}, for
+more detail on these and related command-line options.
+
+@node Bugs
+@chapter Reporting Bugs
+@cindex bugs
+@cindex reporting bugs
+
+Your bug reports play an essential role in making GNU CC reliable.
+
+When you encounter a problem, the first thing to do is to see if it is
+already known. @xref{Trouble}. If it isn't known, then you should
+report the problem.
+
+Reporting a bug may help you by bringing a solution to your problem, or
+it may not. (If it does not, look in the service directory; see
+@ref{Service}.) In any case, the principal function of a bug report is
+to help the entire community by making the next version of GNU CC work
+better. Bug reports are your contribution to the maintenance of GNU CC.
+
+Since the maintainers are very overloaded, we cannot respond to every
+bug report. However, if the bug has not been fixed, we are likely to
+send you a patch and ask you to tell us whether it works.
+
+In order for a bug report to serve its purpose, you must include the
+information that makes for fixing the bug.
+
+@menu
+* Criteria: Bug Criteria. Have you really found a bug?
+* Where: Bug Lists. Where to send your bug report.
+* Reporting: Bug Reporting. How to report a bug effectively.
+* Patches: Sending Patches. How to send a patch for GNU CC.
+* Known: Trouble. Known problems.
+* Help: Service. Where to ask for help.
+@end menu
+
+@node Bug Criteria
+@section Have You Found a Bug?
+@cindex bug criteria
+
+If you are not sure whether you have found a bug, here are some guidelines:
+
+@itemize @bullet
+@cindex fatal signal
+@cindex core dump
+@item
+If the compiler gets a fatal signal, for any input whatever, that is a
+compiler bug. Reliable compilers never crash.
+
+@cindex invalid assembly code
+@cindex assembly code, invalid
+@item
+If the compiler produces invalid assembly code, for any input whatever
+(except an @code{asm} statement), that is a compiler bug, unless the
+compiler reports errors (not just warnings) which would ordinarily
+prevent the assembler from being run.
+
+@cindex undefined behavior
+@cindex undefined function value
+@cindex increment operators
+@item
+If the compiler produces valid assembly code that does not correctly
+execute the input source code, that is a compiler bug.
+
+However, you must double-check to make sure, because you may have run
+into an incompatibility between GNU C and traditional C
+(@pxref{Incompatibilities}). These incompatibilities might be considered
+bugs, but they are inescapable consequences of valuable features.
+
+Or you may have a program whose behavior is undefined, which happened
+by chance to give the desired results with another C or C++ compiler.
+
+For example, in many nonoptimizing compilers, you can write @samp{x;}
+at the end of a function instead of @samp{return x;}, with the same
+results. But the value of the function is undefined if @code{return}
+is omitted; it is not a bug when GNU CC produces different results.
+
+Problems often result from expressions with two increment operators,
+as in @code{f (*p++, *p++)}. Your previous compiler might have
+interpreted that expression the way you intended; GNU CC might
+interpret it another way. Neither compiler is wrong. The bug is
+in your code.
+
+After you have localized the error to a single source line, it should
+be easy to check for these things. If your program is correct and
+well defined, you have found a compiler bug.
+
+@item
+If the compiler produces an error message for valid input, that is a
+compiler bug.
+
+@cindex invalid input
+@item
+If the compiler does not produce an error message for invalid input,
+that is a compiler bug. However, you should note that your idea of
+``invalid input'' might be my idea of ``an extension'' or ``support
+for traditional practice''.
+
+@item
+If you are an experienced user of C or C++ compilers, your suggestions
+for improvement of GNU CC or GNU C++ are welcome in any case.
+@end itemize
+
+@node Bug Lists
+@section Where to Report Bugs
+@cindex bug report mailing lists
+@kindex bug-gcc@@prep.ai.mit.edu
+Send bug reports for GNU C to @samp{bug-gcc@@prep.ai.mit.edu}.
+
+@kindex bug-g++@@prep.ai.mit.edu
+@kindex bug-libg++@@prep.ai.mit.edu
+Send bug reports for GNU C++ to @samp{bug-g++@@prep.ai.mit.edu}.
+If your bug involves the C++ class library libg++, send mail to
+@samp{bug-lib-g++@@prep.ai.mit.edu}. If you're not sure, you can send
+the bug report to both lists.
+
+@strong{Do not send bug reports to @samp{help-gcc@@prep.ai.mit.edu} or
+to the newsgroup @samp{gnu.gcc.help}.} Most users of GNU CC do not want
+to receive bug reports. Those that do, have asked to be on
+@samp{bug-gcc} and/or @samp{bug-g++}.
+
+The mailing lists @samp{bug-gcc} and @samp{bug-g++} both have newsgroups
+which serve as repeaters: @samp{gnu.gcc.bug} and @samp{gnu.g++.bug}.
+Each mailing list and its newsgroup carry exactly the same messages.
+
+Often people think of posting bug reports to the newsgroup instead of
+mailing them. This appears to work, but it has one problem which can be
+crucial: a newsgroup posting does not contain a mail path back to the
+sender. Thus, if maintainers need more information, they may be unable
+to reach you. For this reason, you should always send bug reports by
+mail to the proper mailing list.
+
+As a last resort, send bug reports on paper to:
+
+@example
+GNU Compiler Bugs
+Free Software Foundation
+675 Mass Ave
+Cambridge, MA 02139
+@end example
+
+@node Bug Reporting
+@section How to Report Bugs
+@cindex compiler bugs, reporting
+
+The fundamental principle of reporting bugs usefully is this:
+@strong{report all the facts}. If you are not sure whether to state a
+fact or leave it out, state it!
+
+Often people omit facts because they think they know what causes the
+problem and they conclude that some details don't matter. Thus, you might
+assume that the name of the variable you use in an example does not matter.
+Well, probably it doesn't, but one cannot be sure. Perhaps the bug is a
+stray memory reference which happens to fetch from the location where that
+name is stored in memory; perhaps, if the name were different, the contents
+of that location would fool the compiler into doing the right thing despite
+the bug. Play it safe and give a specific, complete example. That is the
+easiest thing for you to do, and the most helpful.
+
+Keep in mind that the purpose of a bug report is to enable someone to
+fix the bug if it is not known. It isn't very important what happens if
+the bug is already known. Therefore, always write your bug reports on
+the assumption that the bug is not known.
+
+Sometimes people give a few sketchy facts and ask, ``Does this ring a
+bell?'' This cannot help us fix a bug, so it is basically useless. We
+respond by asking for enough details to enable us to investigate.
+You might as well expedite matters by sending them to begin with.
+
+Try to make your bug report self-contained. If we have to ask you for
+more information, it is best if you include all the previous information
+in your response, as well as the information that was missing.
+
+Please report each bug in a separate message. This makes it easier for
+us to track which bugs have been fixed and to forward your bugs reports
+to the appropriate maintainer.
+
+To enable someone to investigate the bug, you should include all these
+things:
+
+@itemize @bullet
+@item
+The version of GNU CC. You can get this by running it with the
+@samp{-v} option.
+
+Without this, we won't know whether there is any point in looking for
+the bug in the current version of GNU CC.
+
+@item
+A complete input file that will reproduce the bug. If the bug is in the
+C preprocessor, send a source file and any header files that it
+requires. If the bug is in the compiler proper (@file{cc1}), run your
+source file through the C preprocessor by doing @samp{gcc -E
+@var{sourcefile} > @var{outfile}}, then include the contents of
+@var{outfile} in the bug report. (When you do this, use the same
+@samp{-I}, @samp{-D} or @samp{-U} options that you used in actual
+compilation.)
+
+A single statement is not enough of an example. In order to compile it,
+it must be embedded in a complete file of compiler input; and the bug
+might depend on the details of how this is done.
+
+Without a real example one can compile, all anyone can do about your bug
+report is wish you luck. It would be futile to try to guess how to
+provoke the bug. For example, bugs in register allocation and reloading
+frequently depend on every little detail of the function they happen in.
+
+Even if the input file that fails comes from a GNU program, you should
+still send the complete test case. Don't ask the GNU CC maintainers to
+do the extra work of obtaining the program in question---they are all
+overworked as it is. Also, the problem may depend on what is in the
+header files on your system; it is unreliable for the GNU CC maintainers
+to try the problem with the header files available to them. By sending
+CPP output, you can eliminate this source of uncertainty and save us
+a certain percentage of wild goose chases.
+
+@item
+The command arguments you gave GNU CC or GNU C++ to compile that example
+and observe the bug. For example, did you use @samp{-O}? To guarantee
+you won't omit something important, list all the options.
+
+If we were to try to guess the arguments, we would probably guess wrong
+and then we would not encounter the bug.
+
+@item
+The type of machine you are using, and the operating system name and
+version number.
+
+@item
+The operands you gave to the @code{configure} command when you installed
+the compiler.
+
+@item
+A complete list of any modifications you have made to the compiler
+source. (We don't promise to investigate the bug unless it happens in
+an unmodified compiler. But if you've made modifications and don't tell
+us, then you are sending us on a wild goose chase.)
+
+Be precise about these changes. A description in English is not
+enough---send a context diff for them.
+
+Adding files of your own (such as a machine description for a machine we
+don't support) is a modification of the compiler source.
+
+@item
+Details of any other deviations from the standard procedure for installing
+GNU CC.
+
+@item
+A description of what behavior you observe that you believe is
+incorrect. For example, ``The compiler gets a fatal signal,'' or,
+``The assembler instruction at line 208 in the output is incorrect.''
+
+Of course, if the bug is that the compiler gets a fatal signal, then one
+can't miss it. But if the bug is incorrect output, the maintainer might
+not notice unless it is glaringly wrong. None of us has time to study
+all the assembler code from a 50-line C program just on the chance that
+one instruction might be wrong. We need @emph{you} to do this part!
+
+Even if the problem you experience is a fatal signal, you should still
+say so explicitly. Suppose something strange is going on, such as, your
+copy of the compiler is out of synch, or you have encountered a bug in
+the C library on your system. (This has happened!) Your copy might
+crash and the copy here would not. If you @i{said} to expect a crash,
+then when the compiler here fails to crash, we would know that the bug
+was not happening. If you don't say to expect a crash, then we would
+not know whether the bug was happening. We would not be able to draw
+any conclusion from our observations.
+
+If the problem is a diagnostic when compiling GNU CC with some other
+compiler, say whether it is a warning or an error.
+
+Often the observed symptom is incorrect output when your program is run.
+Sad to say, this is not enough information unless the program is short
+and simple. None of us has time to study a large program to figure out
+how it would work if compiled correctly, much less which line of it was
+compiled wrong. So you will have to do that. Tell us which source line
+it is, and what incorrect result happens when that line is executed. A
+person who understands the program can find this as easily as finding a
+bug in the program itself.
+
+@item
+If you send examples of assembler code output from GNU CC or GNU C++,
+please use @samp{-g} when you make them. The debugging information
+includes source line numbers which are essential for correlating the
+output with the input.
+
+@item
+If you wish to mention something in the GNU CC source, refer to it by
+context, not by line number.
+
+The line numbers in the development sources don't match those in your
+sources. Your line numbers would convey no useful information to the
+maintainers.
+
+@item
+Additional information from a debugger might enable someone to find a
+problem on a machine which he does not have available. However, you
+need to think when you collect this information if you want it to have
+any chance of being useful.
+
+@cindex backtrace for bug reports
+For example, many people send just a backtrace, but that is never
+useful by itself. A simple backtrace with arguments conveys little
+about GNU CC because the compiler is largely data-driven; the same
+functions are called over and over for different RTL insns, doing
+different things depending on the details of the insn.
+
+Most of the arguments listed in the backtrace are useless because they
+are pointers to RTL list structure. The numeric values of the
+pointers, which the debugger prints in the backtrace, have no
+significance whatever; all that matters is the contents of the objects
+they point to (and most of the contents are other such pointers).
+
+In addition, most compiler passes consist of one or more loops that
+scan the RTL insn sequence. The most vital piece of information about
+such a loop---which insn it has reached---is usually in a local variable,
+not in an argument.
+
+@findex debug_rtx
+What you need to provide in addition to a backtrace are the values of
+the local variables for several stack frames up. When a local
+variable or an argument is an RTX, first print its value and then use
+the GDB command @code{pr} to print the RTL expression that it points
+to. (If GDB doesn't run on your machine, use your debugger to call
+the function @code{debug_rtx} with the RTX as an argument.) In
+general, whenever a variable is a pointer, its value is no use
+without the data it points to.
+@end itemize
+
+Here are some things that are not necessary:
+
+@itemize @bullet
+@item
+A description of the envelope of the bug.
+
+Often people who encounter a bug spend a lot of time investigating
+which changes to the input file will make the bug go away and which
+changes will not affect it.
+
+This is often time consuming and not very useful, because the way we
+will find the bug is by running a single example under the debugger with
+breakpoints, not by pure deduction from a series of examples. You might
+as well save your time for something else.
+
+Of course, if you can find a simpler example to report @emph{instead} of
+the original one, that is a convenience. Errors in the output will be
+easier to spot, running under the debugger will take less time, etc.
+Most GNU CC bugs involve just one function, so the most straightforward
+way to simplify an example is to delete all the function definitions
+except the one where the bug occurs. Those earlier in the file may be
+replaced by external declarations if the crucial function depends on
+them. (Exception: inline functions may affect compilation of functions
+defined later in the file.)
+
+However, simplification is not vital; if you don't want to do this,
+report the bug anyway and send the entire test case you used.
+
+@item
+In particular, some people insert conditionals @samp{#ifdef BUG} around
+a statement which, if removed, makes the bug not happen. These are just
+clutter; we won't pay any attention to them anyway. Besides, you should
+send us cpp output, and that can't have conditionals.
+
+@item
+A patch for the bug.
+
+A patch for the bug is useful if it is a good one. But don't omit the
+necessary information, such as the test case, on the assumption that a
+patch is all we need. We might see problems with your patch and decide
+to fix the problem another way, or we might not understand it at all.
+
+Sometimes with a program as complicated as GNU CC it is very hard to
+construct an example that will make the program follow a certain path
+through the code. If you don't send the example, we won't be able to
+construct one, so we won't be able to verify that the bug is fixed.
+
+And if we can't understand what bug you are trying to fix, or why your
+patch should be an improvement, we won't install it. A test case will
+help us to understand.
+
+@xref{Sending Patches}, for guidelines on how to make it easy for us to
+understand and install your patches.
+
+@item
+A guess about what the bug is or what it depends on.
+
+Such guesses are usually wrong. Even I can't guess right about such
+things without first using the debugger to find the facts.
+
+@item
+A core dump file.
+
+We have no way of examining a core dump for your type of machine
+unless we have an identical system---and if we do have one,
+we should be able to reproduce the crash ourselves.
+@end itemize
+
+@node Sending Patches,, Bug Reporting, Bugs
+@section Sending Patches for GNU CC
+
+If you would like to write bug fixes or improvements for the GNU C
+compiler, that is very helpful. When you send your changes, please
+follow these guidelines to avoid causing extra work for us in studying
+the patches.
+
+If you don't follow these guidelines, your information might still be
+useful, but using it will take extra work. Maintaining GNU C is a lot
+of work in the best of circumstances, and we can't keep up unless you do
+your best to help.
+
+@itemize @bullet
+@item
+Send an explanation with your changes of what problem they fix or what
+improvement they bring about. For a bug fix, just include a copy of the
+bug report, and explain why the change fixes the bug.
+
+(Referring to a bug report is not as good as including it, because then
+we will have to look it up, and we have probably already deleted it if
+we've already fixed the bug.)
+
+@item
+Always include a proper bug report for the problem you think you have
+fixed. We need to convince ourselves that the change is right before
+installing it. Even if it is right, we might have trouble judging it if
+we don't have a way to reproduce the problem.
+
+@item
+Include all the comments that are appropriate to help people reading the
+source in the future understand why this change was needed.
+
+@item
+Don't mix together changes made for different reasons.
+Send them @emph{individually}.
+
+If you make two changes for separate reasons, then we might not want to
+install them both. We might want to install just one. If you send them
+all jumbled together in a single set of diffs, we have to do extra work
+to disentangle them---to figure out which parts of the change serve
+which purpose. If we don't have time for this, we might have to ignore
+your changes entirely.
+
+If you send each change as soon as you have written it, with its own
+explanation, then the two changes never get tangled up, and we can
+consider each one properly without any extra work to disentangle them.
+
+Ideally, each change you send should be impossible to subdivide into
+parts that we might want to consider separately, because each of its
+parts gets its motivation from the other parts.
+
+@item
+Send each change as soon as that change is finished. Sometimes people
+think they are helping us by accumulating many changes to send them all
+together. As explained above, this is absolutely the worst thing you
+could do.
+
+Since you should send each change separately, you might as well send it
+right away. That gives us the option of installing it immediately if it
+is important.
+
+@item
+Use @samp{diff -c} to make your diffs. Diffs without context are hard
+for us to install reliably. More than that, they make it hard for us to
+study the diffs to decide whether we want to install them. Unidiff
+format is better than contextless diffs, but not as easy to read as
+@samp{-c} format.
+
+If you have GNU diff, use @samp{diff -cp}, which shows the name of the
+function that each change occurs in.
+
+@item
+Write the change log entries for your changes. We get lots of changes,
+and we don't have time to do all the change log writing ourselves.
+
+Read the @file{ChangeLog} file to see what sorts of information to put
+in, and to learn the style that we use. The purpose of the change log
+is to show people where to find what was changed. So you need to be
+specific about what functions you changed; in large functions, it's
+often helpful to indicate where within the function the change was.
+
+On the other hand, once you have shown people where to find the change,
+you need not explain its purpose. Thus, if you add a new function, all
+you need to say about it is that it is new. If you feel that the
+purpose needs explaining, it probably does---but the explanation will be
+much more useful if you put it in comments in the code.
+
+If you would like your name to appear in the header line for who made
+the change, send us the header line.
+
+@item
+When you write the fix, keep in mind that we can't install a change that
+would break other systems.
+
+People often suggest fixing a problem by changing machine-independent
+files such as @file{toplev.c} to do something special that a particular
+system needs. Sometimes it is totally obvious that such changes would
+break GNU CC for almost all users. We can't possibly make a change like
+that. At best it might tell us how to write another patch that would
+solve the problem acceptably.
+
+Sometimes people send fixes that @emph{might} be an improvement in
+general---but it is hard to be sure of this. It's hard to install
+such changes because we have to study them very carefully. Of course,
+a good explanation of the reasoning by which you concluded the change
+was correct can help convince us.
+
+The safest changes are changes to the configuration files for a
+particular machine. These are safe because they can't create new bugs
+on other machines.
+
+Please help us keep up with the workload by designing the patch in a
+form that is good to install.
+@end itemize
+
+@node Service
+@chapter How To Get Help with GNU CC
+
+If you need help installing, using or changing GNU CC, there are two
+ways to find it:
+
+@itemize @bullet
+@item
+Send a message to a suitable network mailing list. First try
+@code{bug-gcc@@prep.ai.mit.edu}, and if that brings no response, try
+@code{help-gcc@@prep.ai.mit.edu}.
+
+@item
+Look in the service directory for someone who might help you for a fee.
+The service directory is found in the file named @file{SERVICE} in the
+GNU CC distribution.
+@end itemize
+
+@node VMS
+@chapter Using GNU CC on VMS
+
+@c prevent bad page break with this line
+Here is how to use GNU CC on VMS.
+
+@menu
+* Include Files and VMS:: Where the preprocessor looks for the include files.
+* Global Declarations:: How to do globaldef, globalref and globalvalue with
+ GNU CC.
+* VMS Misc:: Misc information.
+@end menu
+
+@node Include Files and VMS
+@section Include Files and VMS
+
+@cindex include files and VMS
+@cindex VMS and include files
+@cindex header files and VMS
+Due to the differences between the filesystems of Unix and VMS, GNU CC
+attempts to translate file names in @samp{#include} into names that VMS
+will understand. The basic strategy is to prepend a prefix to the
+specification of the include file, convert the whole filename to a VMS
+filename, and then try to open the file. GNU CC tries various prefixes
+one by one until one of them succeeds:
+
+@enumerate
+@item
+The first prefix is the @samp{GNU_CC_INCLUDE:} logical name: this is
+where GNU C header files are traditionally stored. If you wish to store
+header files in non-standard locations, then you can assign the logical
+@samp{GNU_CC_INCLUDE} to be a search list, where each element of the
+list is suitable for use with a rooted logical.
+
+@item
+The next prefix tried is @samp{SYS$SYSROOT:[SYSLIB.]}. This is where
+VAX-C header files are traditionally stored.
+
+@item
+If the include file specification by itself is a valid VMS filename, the
+preprocessor then uses this name with no prefix in an attempt to open
+the include file.
+
+@item
+If the file specification is not a valid VMS filename (i.e. does not
+contain a device or a directory specifier, and contains a @samp{/}
+character), the preprocessor tries to convert it from Unix syntax to
+VMS syntax.
+
+Conversion works like this: the first directory name becomes a device,
+and the rest of the directories are converted into VMS-format directory
+names. For example, the name @file{X11/foobar.h} is
+translated to @file{X11:[000000]foobar.h} or @file{X11:foobar.h},
+whichever one can be opened. This strategy allows you to assign a
+logical name to point to the actual location of the header files.
+
+@item
+If none of these strategies succeeds, the @samp{#include} fails.
+@end enumerate
+
+Include directives of the form:
+
+@example
+#include foobar
+@end example
+
+@noindent
+are a common source of incompatibility between VAX-C and GNU CC. VAX-C
+treats this much like a standard @code{#include <foobar.h>} directive.
+That is incompatible with the ANSI C behavior implemented by GNU CC: to
+expand the name @code{foobar} as a macro. Macro expansion should
+eventually yield one of the two standard formats for @code{#include}:
+
+@example
+#include "@var{file}"
+#include <@var{file}>
+@end example
+
+If you have this problem, the best solution is to modify the source to
+convert the @code{#include} directives to one of the two standard forms.
+That will work with either compiler. If you want a quick and dirty fix,
+define the file names as macros with the proper expansion, like this:
+
+@example
+#define stdio <stdio.h>
+@end example
+
+@noindent
+This will work, as long as the name doesn't conflict with anything else
+in the program.
+
+Another source of incompatibility is that VAX-C assumes that:
+
+@example
+#include "foobar"
+@end example
+
+@noindent
+is actually asking for the file @file{foobar.h}. GNU CC does not
+make this assumption, and instead takes what you ask for literally;
+it tries to read the file @file{foobar}. The best way to avoid this
+problem is to always specify the desired file extension in your include
+directives.
+
+GNU CC for VMS is distributed with a set of include files that is
+sufficient to compile most general purpose programs. Even though the
+GNU CC distribution does not contain header files to define constants
+and structures for some VMS system-specific functions, there is no
+reason why you cannot use GNU CC with any of these functions. You first
+may have to generate or create header files, either by using the public
+domain utility @code{UNSDL} (which can be found on a DECUS tape), or by
+extracting the relevant modules from one of the system macro libraries,
+and using an editor to construct a C header file.
+
+A @code{#include} file name cannot contain a DECNET node name. The
+preprocessor reports an I/O error if you attempt to use a node name,
+whether explicitly, or implicitly via a logical name.
+
+@node Global Declarations
+@section Global Declarations and VMS
+
+@findex GLOBALREF
+@findex GLOBALDEF
+@findex GLOBALVALUEDEF
+@findex GLOBALVALUEREF
+GNU CC does not provide the @code{globalref}, @code{globaldef} and
+@code{globalvalue} keywords of VAX-C. You can get the same effect with
+an obscure feature of GAS, the GNU assembler. (This requires GAS
+version 1.39 or later.) The following macros allow you to use this
+feature in a fairly natural way:
+
+@smallexample
+#ifdef __GNUC__
+#define GLOBALREF(TYPE,NAME) \
+ TYPE NAME \
+ asm ("_$$PsectAttributes_GLOBALSYMBOL$$" #NAME)
+#define GLOBALDEF(TYPE,NAME,VALUE) \
+ TYPE NAME \
+ asm ("_$$PsectAttributes_GLOBALSYMBOL$$" #NAME) \
+ = VALUE
+#define GLOBALVALUEREF(TYPE,NAME) \
+ const TYPE NAME[1] \
+ asm ("_$$PsectAttributes_GLOBALVALUE$$" #NAME)
+#define GLOBALVALUEDEF(TYPE,NAME,VALUE) \
+ const TYPE NAME[1] \
+ asm ("_$$PsectAttributes_GLOBALVALUE$$" #NAME) \
+ = @{VALUE@}
+#else
+#define GLOBALREF(TYPE,NAME) \
+ globalref TYPE NAME
+#define GLOBALDEF(TYPE,NAME,VALUE) \
+ globaldef TYPE NAME = VALUE
+#define GLOBALVALUEDEF(TYPE,NAME,VALUE) \
+ globalvalue TYPE NAME = VALUE
+#define GLOBALVALUEREF(TYPE,NAME) \
+ globalvalue TYPE NAME
+#endif
+@end smallexample
+
+@noindent
+(The @code{_$$PsectAttributes_GLOBALSYMBOL} prefix at the start of the
+name is removed by the assembler, after it has modified the attributes
+of the symbol). These macros are provided in the VMS binaries
+distribution in a header file @file{GNU_HACKS.H}. An example of the
+usage is:
+
+@example
+GLOBALREF (int, ijk);
+GLOBALDEF (int, jkl, 0);
+@end example
+
+The macros @code{GLOBALREF} and @code{GLOBALDEF} cannot be used
+straightforwardly for arrays, since there is no way to insert the array
+dimension into the declaration at the right place. However, you can
+declare an array with these macros if you first define a typedef for the
+array type, like this:
+
+@example
+typedef int intvector[10];
+GLOBALREF (intvector, foo);
+@end example
+
+Array and structure initializers will also break the macros; you can
+define the initializer to be a macro of its own, or you can expand the
+@code{GLOBALDEF} macro by hand. You may find a case where you wish to
+use the @code{GLOBALDEF} macro with a large array, but you are not
+interested in explicitly initializing each element of the array. In
+such cases you can use an initializer like: @code{@{0,@}}, which will
+initialize the entire array to @code{0}.
+
+A shortcoming of this implementation is that a variable declared with
+@code{GLOBALVALUEREF} or @code{GLOBALVALUEDEF} is always an array. For
+example, the declaration:
+
+@example
+GLOBALVALUEREF(int, ijk);
+@end example
+
+@noindent
+declares the variable @code{ijk} as an array of type @code{int [1]}.
+This is done because a globalvalue is actually a constant; its ``value''
+is what the linker would normally consider an address. That is not how
+an integer value works in C, but it is how an array works. So treating
+the symbol as an array name gives consistent results---with the
+exception that the value seems to have the wrong type. @strong{Don't
+try to access an element of the array.} It doesn't have any elements.
+The array ``address'' may not be the address of actual storage.
+
+The fact that the symbol is an array may lead to warnings where the
+variable is used. Insert type casts to avoid the warnings. Here is an
+example; it takes advantage of the ANSI C feature allowing macros that
+expand to use the same name as the macro itself.
+
+@example
+GLOBALVALUEREF (int, ss$_normal);
+GLOBALVALUEDEF (int, xyzzy,123);
+#ifdef __GNUC__
+#define ss$_normal ((int) ss$_normal)
+#define xyzzy ((int) xyzzy)
+#endif
+@end example
+
+Don't use @code{globaldef} or @code{globalref} with a variable whose
+type is an enumeration type; this is not implemented. Instead, make the
+variable an integer, and use a @code{globalvaluedef} for each of the
+enumeration values. An example of this would be:
+
+@example
+#ifdef __GNUC__
+GLOBALDEF (int, color, 0);
+GLOBALVALUEDEF (int, RED, 0);
+GLOBALVALUEDEF (int, BLUE, 1);
+GLOBALVALUEDEF (int, GREEN, 3);
+#else
+enum globaldef color @{RED, BLUE, GREEN = 3@};
+#endif
+@end example
+
+@node VMS Misc
+@section Other VMS Issues
+
+@cindex exit status and VMS
+@cindex return value of @code{main}
+@cindex @code{main} and the exit status
+GNU CC automatically arranges for @code{main} to return 1 by default if
+you fail to specify an explicit return value. This will be interpreted
+by VMS as a status code indicating a normal successful completion.
+Version 1 of GNU CC did not provide this default.
+
+GNU CC on VMS works only with the GNU assembler, GAS. You need version
+1.37 or later of GAS in order to produce value debugging information for
+the VMS debugger. Use the ordinary VMS linker with the object files
+produced by GAS.
+
+@cindex shared VMS run time system
+@cindex @file{VAXCRTL}
+Under previous versions of GNU CC, the generated code would occasionally
+give strange results when linked to the sharable @file{VAXCRTL} library.
+Now this should work.
+
+A caveat for use of @code{const} global variables: the @code{const}
+modifier must be specified in every external declaration of the variable
+in all of the source files that use that variable. Otherwise the linker
+will issue warnings about conflicting attributes for the variable. Your
+program will still work despite the warnings, but the variable will be
+placed in writable storage.
+
+@cindex name augmentation
+@cindex case sensitivity and VMS
+@cindex VMS and case sensitivity
+Although the VMS linker does distinguish between upper and lower case
+letters in global symbols, most VMS compilers convert all such symbols
+into upper case and most run-time library routines also have upper case
+names. To be able to reliably call such routines, GNU CC (by means of
+the assembler GAS) converts global symbols into upper case like other
+VMS compilers. However, since the usual practice in C is to distinguish
+case, GNU CC (via GAS) tries to preserve usual C behavior by augmenting
+each name that is not all lower case. This means truncating the name
+to at most 23 characters and then adding more characters at the end
+which encode the case pattern of those 23. Names which contain at
+least one dollar sign are an exception; they are converted directly into
+upper case without augmentation.
+
+Name augmentation yields bad results for programs that use precompiled
+libraries (such as Xlib) which were generated by another compiler. You
+can use the compiler option @samp{/NOCASE_HACK} to inhibit augmentation;
+it makes external C functions and variables case-independent as is usual
+on VMS. Alternatively, you could write all references to the functions
+and variables in such libraries using lower case; this will work on VMS,
+but is not portable to other systems. The compiler option @samp{/NAMES}
+also provides control over global name handling.
+
+Function and variable names are handled somewhat differently with GNU
+C++. The GNU C++ compiler performs @dfn{name mangling} on function
+names, which means that it adds information to the function name to
+describe the data types of the arguments that the function takes. One
+result of this is that the name of a function can become very long.
+Since the VMS linker only recognizes the first 31 characters in a name,
+special action is taken to ensure that each function and variable has a
+unique name that can be represented in 31 characters.
+
+If the name (plus a name augmentation, if required) is less than 32
+characters in length, then no special action is performed. If the name
+is longer than 31 characters, the assembler (GAS) will generate a
+hash string based upon the function name, truncate the function name to
+23 characters, and append the hash string to the truncated name. If the
+@samp{/VERBOSE} compiler option is used, the assembler will print both
+the full and truncated names of each symbol that is truncated.
+
+The @samp{/NOCASE_HACK} compiler option should not be used when you are
+compiling programs that use libg++. libg++ has several instances of
+objects (i.e. @code{Filebuf} and @code{filebuf}) which become
+indistinguishable in a case-insensitive environment. This leads to
+cases where you need to inhibit augmentation selectively (if you were
+using libg++ and Xlib in the same program, for example). There is no
+special feature for doing this, but you can get the result by defining a
+macro for each mixed case symbol for which you wish to inhibit
+augmentation. The macro should expand into the lower case equivalent of
+itself. For example:
+
+@example
+#define StuDlyCapS studlycaps
+@end example
+
+These macro definitions can be placed in a header file to minimize the
+number of changes to your source code.
+@end ifset
+
+@ifset INTERNALS
+@node Portability
+@chapter GNU CC and Portability
+@cindex portability
+@cindex GNU CC and portability
+
+The main goal of GNU CC was to make a good, fast compiler for machines in
+the class that the GNU system aims to run on: 32-bit machines that address
+8-bit bytes and have several general registers. Elegance, theoretical
+power and simplicity are only secondary.
+
+GNU CC gets most of the information about the target machine from a machine
+description which gives an algebraic formula for each of the machine's
+instructions. This is a very clean way to describe the target. But when
+the compiler needs information that is difficult to express in this
+fashion, I have not hesitated to define an ad-hoc parameter to the machine
+description. The purpose of portability is to reduce the total work needed
+on the compiler; it was not of interest for its own sake.
+
+@cindex endianness
+@cindex autoincrement addressing, availability
+@findex abort
+GNU CC does not contain machine dependent code, but it does contain code
+that depends on machine parameters such as endianness (whether the most
+significant byte has the highest or lowest address of the bytes in a word)
+and the availability of autoincrement addressing. In the RTL-generation
+pass, it is often necessary to have multiple strategies for generating code
+for a particular kind of syntax tree, strategies that are usable for different
+combinations of parameters. Often I have not tried to address all possible
+cases, but only the common ones or only the ones that I have encountered.
+As a result, a new target may require additional strategies. You will know
+if this happens because the compiler will call @code{abort}. Fortunately,
+the new strategies can be added in a machine-independent fashion, and will
+affect only the target machines that need them.
+@end ifset
+
+@ifset INTERNALS
+@node Interface
+@chapter Interfacing to GNU CC Output
+@cindex interfacing to GNU CC output
+@cindex run-time conventions
+@cindex function call conventions
+@cindex conventions, run-time
+
+GNU CC is normally configured to use the same function calling convention
+normally in use on the target system. This is done with the
+machine-description macros described (@pxref{Target Macros}).
+
+@cindex unions, returning
+@cindex structures, returning
+@cindex returning structures and unions
+However, returning of structure and union values is done differently on
+some target machines. As a result, functions compiled with PCC
+returning such types cannot be called from code compiled with GNU CC,
+and vice versa. This does not cause trouble often because few Unix
+library routines return structures or unions.
+
+GNU CC code returns structures and unions that are 1, 2, 4 or 8 bytes
+long in the same registers used for @code{int} or @code{double} return
+values. (GNU CC typically allocates variables of such types in
+registers also.) Structures and unions of other sizes are returned by
+storing them into an address passed by the caller (usually in a
+register). The machine-description macros @code{STRUCT_VALUE} and
+@code{STRUCT_INCOMING_VALUE} tell GNU CC where to pass this address.
+
+By contrast, PCC on most target machines returns structures and unions
+of any size by copying the data into an area of static storage, and then
+returning the address of that storage as if it were a pointer value.
+The caller must copy the data from that memory area to the place where
+the value is wanted. This is slower than the method used by GNU CC, and
+fails to be reentrant.
+
+On some target machines, such as RISC machines and the 80386, the
+standard system convention is to pass to the subroutine the address of
+where to return the value. On these machines, GNU CC has been
+configured to be compatible with the standard compiler, when this method
+is used. It may not be compatible for structures of 1, 2, 4 or 8 bytes.
+
+@cindex argument passing
+@cindex passing arguments
+GNU CC uses the system's standard convention for passing arguments. On
+some machines, the first few arguments are passed in registers; in
+others, all are passed on the stack. It would be possible to use
+registers for argument passing on any machine, and this would probably
+result in a significant speedup. But the result would be complete
+incompatibility with code that follows the standard convention. So this
+change is practical only if you are switching to GNU CC as the sole C
+compiler for the system. We may implement register argument passing on
+certain machines once we have a complete GNU system so that we can
+compile the libraries with GNU CC.
+
+On some machines (particularly the Sparc), certain types of arguments
+are passed ``by invisible reference''. This means that the value is
+stored in memory, and the address of the memory location is passed to
+the subroutine.
+
+@cindex @code{longjmp} and automatic variables
+If you use @code{longjmp}, beware of automatic variables. ANSI C says that
+automatic variables that are not declared @code{volatile} have undefined
+values after a @code{longjmp}. And this is all GNU CC promises to do,
+because it is very difficult to restore register variables correctly, and
+one of GNU CC's features is that it can put variables in registers without
+your asking it to.
+
+If you want a variable to be unaltered by @code{longjmp}, and you don't
+want to write @code{volatile} because old C compilers don't accept it,
+just take the address of the variable. If a variable's address is ever
+taken, even if just to compute it and ignore it, then the variable cannot
+go in a register:
+
+@example
+@{
+ int careful;
+ &careful;
+ @dots{}
+@}
+@end example
+
+@cindex arithmetic libraries
+@cindex math libraries
+Code compiled with GNU CC may call certain library routines. Most of
+them handle arithmetic for which there are no instructions. This
+includes multiply and divide on some machines, and floating point
+operations on any machine for which floating point support is disabled
+with @samp{-msoft-float}. Some standard parts of the C library, such as
+@code{bcopy} or @code{memcpy}, are also called automatically. The usual
+function call interface is used for calling the library routines.
+
+These library routines should be defined in the library @file{libgcc.a},
+which GNU CC automatically searches whenever it links a program. On
+machines that have multiply and divide instructions, if hardware
+floating point is in use, normally @file{libgcc.a} is not needed, but it
+is searched just in case.
+
+Each arithmetic function is defined in @file{libgcc1.c} to use the
+corresponding C arithmetic operator. As long as the file is compiled
+with another C compiler, which supports all the C arithmetic operators,
+this file will work portably. However, @file{libgcc1.c} does not work if
+compiled with GNU CC, because each arithmetic function would compile
+into a call to itself!
+@end ifset
+
+@ifset INTERNALS
+@node Passes
+@chapter Passes and Files of the Compiler
+@cindex passes and files of the compiler
+@cindex files and passes of the compiler
+@cindex compiler passes and files
+
+@cindex top level of compiler
+The overall control structure of the compiler is in @file{toplev.c}. This
+file is responsible for initialization, decoding arguments, opening and
+closing files, and sequencing the passes.
+
+@cindex parsing pass
+The parsing pass is invoked only once, to parse the entire input. The RTL
+intermediate code for a function is generated as the function is parsed, a
+statement at a time. Each statement is read in as a syntax tree and then
+converted to RTL; then the storage for the tree for the statement is
+reclaimed. Storage for types (and the expressions for their sizes),
+declarations, and a representation of the binding contours and how they nest,
+remain until the function is finished being compiled; these are all needed
+to output the debugging information.
+
+@findex rest_of_compilation
+@findex rest_of_decl_compilation
+Each time the parsing pass reads a complete function definition or
+top-level declaration, it calls either the function
+@code{rest_of_compilation}, or the function
+@code{rest_of_decl_compilation} in @file{toplev.c}, which are
+responsible for all further processing necessary, ending with output of
+the assembler language. All other compiler passes run, in sequence,
+within @code{rest_of_compilation}. When that function returns from
+compiling a function definition, the storage used for that function
+definition's compilation is entirely freed, unless it is an inline
+function
+@ifset USING
+(@pxref{Inline,,An Inline Function is As Fast As a Macro}).
+@end ifset
+@ifclear USING
+(@pxref{Inline,,An Inline Function is As Fast As a Macro,gcc.texi,Using GCC}).
+@end ifclear
+
+Here is a list of all the passes of the compiler and their source files.
+Also included is a description of where debugging dumps can be requested
+with @samp{-d} options.
+
+@itemize @bullet
+@item
+Parsing. This pass reads the entire text of a function definition,
+constructing partial syntax trees. This and RTL generation are no longer
+truly separate passes (formerly they were), but it is easier to think
+of them as separate.
+
+The tree representation does not entirely follow C syntax, because it is
+intended to support other languages as well.
+
+Language-specific data type analysis is also done in this pass, and every
+tree node that represents an expression has a data type attached.
+Variables are represented as declaration nodes.
+
+@cindex constant folding
+@cindex arithmetic simplifications
+@cindex simplifications, arithmetic
+Constant folding and some arithmetic simplifications are also done
+during this pass.
+
+The language-independent source files for parsing are
+@file{stor-layout.c}, @file{fold-const.c}, and @file{tree.c}.
+There are also header files @file{tree.h} and @file{tree.def}
+which define the format of the tree representation.@refill
+
+@c Avoiding overfull is tricky here.
+The source files to parse C are
+@file{c-parse.in},
+@file{c-decl.c},
+@file{c-typeck.c},
+@file{c-aux-info.c},
+@file{c-convert.c},
+and @file{c-lang.c}
+along with header files
+@file{c-lex.h}, and
+@file{c-tree.h}.
+
+The source files for parsing C++ are @file{cp-parse.y},
+@file{cp-class.c},@*
+@file{cp-cvt.c}, @file{cp-decl.c}, @file{cp-decl2.c},
+@file{cp-dem.c}, @file{cp-except.c},@*
+@file{cp-expr.c}, @file{cp-init.c}, @file{cp-lex.c},
+@file{cp-method.c}, @file{cp-ptree.c},@*
+@file{cp-search.c}, @file{cp-tree.c}, @file{cp-type2.c}, and
+@file{cp-typeck.c}, along with header files @file{cp-tree.def},
+@file{cp-tree.h}, and @file{cp-decl.h}.
+
+The special source files for parsing Objective C are
+@file{objc-parse.y}, @file{objc-actions.c}, @file{objc-tree.def}, and
+@file{objc-actions.h}. Certain C-specific files are used for this as
+well.
+
+The file @file{c-common.c} is also used for all of the above languages.
+
+@cindex RTL generation
+@item
+RTL generation. This is the conversion of syntax tree into RTL code.
+It is actually done statement-by-statement during parsing, but for
+most purposes it can be thought of as a separate pass.
+
+@cindex target-parameter-dependent code
+This is where the bulk of target-parameter-dependent code is found,
+since often it is necessary for strategies to apply only when certain
+standard kinds of instructions are available. The purpose of named
+instruction patterns is to provide this information to the RTL
+generation pass.
+
+@cindex tail recursion optimization
+Optimization is done in this pass for @code{if}-conditions that are
+comparisons, boolean operations or conditional expressions. Tail
+recursion is detected at this time also. Decisions are made about how
+best to arrange loops and how to output @code{switch} statements.
+
+@c Avoiding overfull is tricky here.
+The source files for RTL generation include
+@file{stmt.c},
+@file{calls.c},
+@file{expr.c},
+@file{explow.c},
+@file{expmed.c},
+@file{function.c},
+@file{optabs.c}
+and @file{emit-rtl.c}.
+Also, the file
+@file{insn-emit.c}, generated from the machine description by the
+program @code{genemit}, is used in this pass. The header file
+@file{expr.h} is used for communication within this pass.@refill
+
+@findex genflags
+@findex gencodes
+The header files @file{insn-flags.h} and @file{insn-codes.h},
+generated from the machine description by the programs @code{genflags}
+and @code{gencodes}, tell this pass which standard names are available
+for use and which patterns correspond to them.@refill
+
+Aside from debugging information output, none of the following passes
+refers to the tree structure representation of the function (only
+part of which is saved).
+
+@cindex inline, automatic
+The decision of whether the function can and should be expanded inline
+in its subsequent callers is made at the end of rtl generation. The
+function must meet certain criteria, currently related to the size of
+the function and the types and number of parameters it has. Note that
+this function may contain loops, recursive calls to itself
+(tail-recursive functions can be inlined!), gotos, in short, all
+constructs supported by GNU CC. The file @file{integrate.c} contains
+the code to save a function's rtl for later inlining and to inline that
+rtl when the function is called. The header file @file{integrate.h}
+is also used for this purpose.
+
+The option @samp{-dr} causes a debugging dump of the RTL code after
+this pass. This dump file's name is made by appending @samp{.rtl} to
+the input file name.
+
+@cindex jump optimization
+@cindex unreachable code
+@cindex dead code
+@item
+Jump optimization. This pass simplifies jumps to the following
+instruction, jumps across jumps, and jumps to jumps. It deletes
+unreferenced labels and unreachable code, except that unreachable code
+that contains a loop is not recognized as unreachable in this pass.
+(Such loops are deleted later in the basic block analysis.) It also
+converts some code originally written with jumps into sequences of
+instructions that directly set values from the results of comparisons,
+if the machine has such instructions.
+
+Jump optimization is performed two or three times. The first time is
+immediately following RTL generation. The second time is after CSE,
+but only if CSE says repeated jump optimization is needed. The
+last time is right before the final pass. That time, cross-jumping
+and deletion of no-op move instructions are done together with the
+optimizations described above.
+
+The source file of this pass is @file{jump.c}.
+
+The option @samp{-dj} causes a debugging dump of the RTL code after
+this pass is run for the first time. This dump file's name is made by
+appending @samp{.jump} to the input file name.
+
+@cindex register use analysis
+@item
+Register scan. This pass finds the first and last use of each
+register, as a guide for common subexpression elimination. Its source
+is in @file{regclass.c}.
+
+@cindex jump threading
+@item
+Jump threading. This pass detects a condition jump that branches to an
+identical or inverse test. Such jumps can be @samp{threaded} through
+the second conditional test. The source code for this pass is in
+@file{jump.c}. This optimization is only performed if
+@samp{-fthread-jumps} is enabled.
+
+@cindex common subexpression elimination
+@cindex constant propagation
+@item
+Common subexpression elimination. This pass also does constant
+propagation. Its source file is @file{cse.c}. If constant
+propagation causes conditional jumps to become unconditional or to
+become no-ops, jump optimization is run again when CSE is finished.
+
+The option @samp{-ds} causes a debugging dump of the RTL code after
+this pass. This dump file's name is made by appending @samp{.cse} to
+the input file name.
+
+@cindex loop optimization
+@cindex code motion
+@cindex strength-reduction
+@item
+Loop optimization. This pass moves constant expressions out of loops,
+and optionally does strength-reduction and loop unrolling as well.
+Its source files are @file{loop.c} and @file{unroll.c}, plus the header
+@file{loop.h} used for communication between them. Loop unrolling uses
+some functions in @file{integrate.c} and the header @file{integrate.h}.
+
+The option @samp{-dL} causes a debugging dump of the RTL code after
+this pass. This dump file's name is made by appending @samp{.loop} to
+the input file name.
+
+@item
+If @samp{-frerun-cse-after-loop} was enabled, a second common
+subexpression elimination pass is performed after the loop optimization
+pass. Jump threading is also done again at this time if it was specified.
+
+The option @samp{-dt} causes a debugging dump of the RTL code after
+this pass. This dump file's name is made by appending @samp{.cse2} to
+the input file name.
+
+@cindex register allocation, stupid
+@cindex stupid register allocation
+@item
+Stupid register allocation is performed at this point in a
+nonoptimizing compilation. It does a little data flow analysis as
+well. When stupid register allocation is in use, the next pass
+executed is the reloading pass; the others in between are skipped.
+The source file is @file{stupid.c}.
+
+@cindex data flow analysis
+@cindex analysis, data flow
+@cindex basic blocks
+@item
+Data flow analysis (@file{flow.c}). This pass divides the program
+into basic blocks (and in the process deletes unreachable loops); then
+it computes which pseudo-registers are live at each point in the
+program, and makes the first instruction that uses a value point at
+the instruction that computed the value.
+
+@cindex autoincrement/decrement analysis
+This pass also deletes computations whose results are never used, and
+combines memory references with add or subtract instructions to make
+autoincrement or autodecrement addressing.
+
+The option @samp{-df} causes a debugging dump of the RTL code after
+this pass. This dump file's name is made by appending @samp{.flow} to
+the input file name. If stupid register allocation is in use, this
+dump file reflects the full results of such allocation.
+
+@cindex instruction combination
+@item
+Instruction combination (@file{combine.c}). This pass attempts to
+combine groups of two or three instructions that are related by data
+flow into single instructions. It combines the RTL expressions for
+the instructions by substitution, simplifies the result using algebra,
+and then attempts to match the result against the machine description.
+
+The option @samp{-dc} causes a debugging dump of the RTL code after
+this pass. This dump file's name is made by appending @samp{.combine}
+to the input file name.
+
+@cindex instruction scheduling
+@cindex scheduling, instruction
+@item
+Instruction scheduling (@file{sched.c}). This pass looks for
+instructions whose output will not be available by the time that it is
+used in subsequent instructions. (Memory loads and floating point
+instructions often have this behavior on RISC machines). It re-orders
+instructions within a basic block to try to separate the definition and
+use of items that otherwise would cause pipeline stalls.
+
+Instruction scheduling is performed twice. The first time is immediately
+after instruction combination and the second is immediately after reload.
+
+The option @samp{-dS} causes a debugging dump of the RTL code after this
+pass is run for the first time. The dump file's name is made by
+appending @samp{.sched} to the input file name.
+
+@cindex register class preference pass
+@item
+Register class preferencing. The RTL code is scanned to find out
+which register class is best for each pseudo register. The source
+file is @file{regclass.c}.
+
+@cindex register allocation
+@cindex local register allocation
+@item
+Local register allocation (@file{local-alloc.c}). This pass allocates
+hard registers to pseudo registers that are used only within one basic
+block. Because the basic block is linear, it can use fast and
+powerful techniques to do a very good job.
+
+The option @samp{-dl} causes a debugging dump of the RTL code after
+this pass. This dump file's name is made by appending @samp{.lreg} to
+the input file name.
+
+@cindex global register allocation
+@item
+Global register allocation (@file{global.c}). This pass
+allocates hard registers for the remaining pseudo registers (those
+whose life spans are not contained in one basic block).
+
+@cindex reloading
+@item
+Reloading. This pass renumbers pseudo registers with the hardware
+registers numbers they were allocated. Pseudo registers that did not
+get hard registers are replaced with stack slots. Then it finds
+instructions that are invalid because a value has failed to end up in
+a register, or has ended up in a register of the wrong kind. It fixes
+up these instructions by reloading the problematical values
+temporarily into registers. Additional instructions are generated to
+do the copying.
+
+The reload pass also optionally eliminates the frame pointer and inserts
+instructions to save and restore call-clobbered registers around calls.
+
+Source files are @file{reload.c} and @file{reload1.c}, plus the header
+@file{reload.h} used for communication between them.
+
+The option @samp{-dg} causes a debugging dump of the RTL code after
+this pass. This dump file's name is made by appending @samp{.greg} to
+the input file name.
+
+@cindex instruction scheduling
+@cindex scheduling, instruction
+@item
+Instruction scheduling is repeated here to try to avoid pipeline stalls
+due to memory loads generated for spilled pseudo registers.
+
+The option @samp{-dR} causes a debugging dump of the RTL code after
+this pass. This dump file's name is made by appending @samp{.sched2}
+to the input file name.
+
+@cindex cross-jumping
+@cindex no-op move instructions
+@item
+Jump optimization is repeated, this time including cross-jumping
+and deletion of no-op move instructions.
+
+The option @samp{-dJ} causes a debugging dump of the RTL code after
+this pass. This dump file's name is made by appending @samp{.jump2}
+to the input file name.
+
+@cindex delayed branch scheduling
+@cindex scheduling, delayed branch
+@item
+Delayed branch scheduling. This optional pass attempts to find
+instructions that can go into the delay slots of other instructions,
+usually jumps and calls. The source file name is @file{reorg.c}.
+
+The option @samp{-dd} causes a debugging dump of the RTL code after
+this pass. This dump file's name is made by appending @samp{.dbr}
+to the input file name.
+
+@cindex register-to-stack conversion
+@item
+Conversion from usage of some hard registers to usage of a register
+stack may be done at this point. Currently, this is supported only
+for the floating-point registers of the Intel 80387 coprocessor. The
+source file name is @file{reg-stack.c}.
+
+The options @samp{-dk} causes a debugging dump of the RTL code after
+this pass. This dump file's name is made by appending @samp{.stack}
+to the input file name.
+
+@cindex final pass
+@cindex peephole optimization
+@item
+Final. This pass outputs the assembler code for the function. It is
+also responsible for identifying spurious test and compare
+instructions. Machine-specific peephole optimizations are performed
+at the same time. The function entry and exit sequences are generated
+directly as assembler code in this pass; they never exist as RTL.
+
+The source files are @file{final.c} plus @file{insn-output.c}; the
+latter is generated automatically from the machine description by the
+tool @file{genoutput}. The header file @file{conditions.h} is used
+for communication between these files.
+
+@cindex debugging information generation
+@item
+Debugging information output. This is run after final because it must
+output the stack slot offsets for pseudo registers that did not get
+hard registers. Source files are @file{dbxout.c} for DBX symbol table
+format, @file{sdbout.c} for SDB symbol table format, and
+@file{dwarfout.c} for DWARF symbol table format.
+@end itemize
+
+Some additional files are used by all or many passes:
+
+@itemize @bullet
+@item
+Every pass uses @file{machmode.def} and @file{machmode.h} which define
+the machine modes.
+
+@item
+Several passes use @file{real.h}, which defines the default
+representation of floating point constants and how to operate on them.
+
+@item
+All the passes that work with RTL use the header files @file{rtl.h}
+and @file{rtl.def}, and subroutines in file @file{rtl.c}. The tools
+@code{gen*} also use these files to read and work with the machine
+description RTL.
+
+@findex genconfig
+@item
+Several passes refer to the header file @file{insn-config.h} which
+contains a few parameters (C macro definitions) generated
+automatically from the machine description RTL by the tool
+@code{genconfig}.
+
+@cindex instruction recognizer
+@item
+Several passes use the instruction recognizer, which consists of
+@file{recog.c} and @file{recog.h}, plus the files @file{insn-recog.c}
+and @file{insn-extract.c} that are generated automatically from the
+machine description by the tools @file{genrecog} and
+@file{genextract}.@refill
+
+@item
+Several passes use the header files @file{regs.h} which defines the
+information recorded about pseudo register usage, and @file{basic-block.h}
+which defines the information recorded about basic blocks.
+
+@item
+@file{hard-reg-set.h} defines the type @code{HARD_REG_SET}, a bit-vector
+with a bit for each hard register, and some macros to manipulate it.
+This type is just @code{int} if the machine has few enough hard registers;
+otherwise it is an array of @code{int} and some of the macros expand
+into loops.
+
+@item
+Several passes use instruction attributes. A definition of the
+attributes defined for a particular machine is in file
+@file{insn-attr.h}, which is generated from the machine description by
+the program @file{genattr}. The file @file{insn-attrtab.c} contains
+subroutines to obtain the attribute values for insns. It is generated
+from the machine description by the program @file{genattrtab}.@refill
+@end itemize
+@end ifset
+
+@ifset INTERNALS
+@include rtl.texi
+@include md.texi
+@include tm.texi
+@end ifset
+
+@ifset INTERNALS
+@node Config
+@chapter The Configuration File
+@cindex configuration file
+@cindex @file{xm-@var{machine}.h}
+
+The configuration file @file{xm-@var{machine}.h} contains macro
+definitions that describe the machine and system on which the compiler
+is running, unlike the definitions in @file{@var{machine}.h}, which
+describe the machine for which the compiler is producing output. Most
+of the values in @file{xm-@var{machine}.h} are actually the same on all
+machines that GNU CC runs on, so large parts of all configuration files
+are identical. But there are some macros that vary:
+
+@table @code
+@findex USG
+@item USG
+Define this macro if the host system is System V.
+
+@findex VMS
+@item VMS
+Define this macro if the host system is VMS.
+
+@findex FAILURE_EXIT_CODE
+@item FAILURE_EXIT_CODE
+A C expression for the status code to be returned when the compiler
+exits after serious errors.
+
+@findex SUCCESS_EXIT_CODE
+@item SUCCESS_EXIT_CODE
+A C expression for the status code to be returned when the compiler
+exits without serious errors.
+
+@findex HOST_WORDS_BIG_ENDIAN
+@item HOST_WORDS_BIG_ENDIAN
+Defined if the host machine stores words of multi-word values in
+big-endian order. (GNU CC does not depend on the host byte ordering
+within a word.)
+
+@findex HOST_FLOAT_WORDS_BIG_ENDIAN
+@item HOST_FLOAT_WORDS_BIG_ENDIAN
+Define this macro to be 1 if the host machine stores @code{DFmode},
+@code{XFmode} or @code{TFmode} floating point numbers in memory with the
+word containing the sign bit at the lowest address; otherwise, define it
+to be zero.
+
+This macro need not be defined if the ordering is the same as for
+multi-word integers.
+
+@findex HOST_FLOAT_FORMAT
+@item HOST_FLOAT_FORMAT
+A numeric code distinguishing the floating point format for the host
+machine. See @code{TARGET_FLOAT_FORMAT} in @ref{Storage Layout} for the
+alternatives and default.
+
+@findex HOST_BITS_PER_CHAR
+@item HOST_BITS_PER_CHAR
+A C expression for the number of bits in @code{char} on the host
+machine.
+
+@findex HOST_BITS_PER_SHORT
+@item HOST_BITS_PER_SHORT
+A C expression for the number of bits in @code{short} on the host
+machine.
+
+@findex HOST_BITS_PER_INT
+@item HOST_BITS_PER_INT
+A C expression for the number of bits in @code{int} on the host
+machine.
+
+@findex HOST_BITS_PER_LONG
+@item HOST_BITS_PER_LONG
+A C expression for the number of bits in @code{long} on the host
+machine.
+
+@findex ONLY_INT_FIELDS
+@item ONLY_INT_FIELDS
+Define this macro to indicate that the host compiler only supports
+@code{int} bit fields, rather than other integral types, including
+@code{enum}, as do most C compilers.
+
+@findex EXECUTABLE_SUFFIX
+@item EXECUTABLE_SUFFIX
+Define this macro if the host system uses a naming convention for
+executable files that involves a common suffix (such as, in some
+systems, @samp{.exe}) that must be mentioned explicitly when you run
+the program.
+
+@findex OBSTACK_CHUNK_SIZE
+@item OBSTACK_CHUNK_SIZE
+A C expression for the size of ordinary obstack chunks.
+If you don't define this, a usually-reasonable default is used.
+
+@findex OBSTACK_CHUNK_ALLOC
+@item OBSTACK_CHUNK_ALLOC
+The function used to allocate obstack chunks.
+If you don't define this, @code{xmalloc} is used.
+
+@findex OBSTACK_CHUNK_FREE
+@item OBSTACK_CHUNK_FREE
+The function used to free obstack chunks.
+If you don't define this, @code{free} is used.
+
+@findex USE_C_ALLOCA
+@item USE_C_ALLOCA
+Define this macro to indicate that the compiler is running with the
+@code{alloca} implemented in C. This version of @code{alloca} can be
+found in the file @file{alloca.c}; to use it, you must also alter the
+@file{Makefile} variable @code{ALLOCA}. (This is done automatically
+for the systems on which we know it is needed.)
+
+If you do define this macro, you should probably do it as follows:
+
+@example
+#ifndef __GNUC__
+#define USE_C_ALLOCA
+#else
+#define alloca __builtin_alloca
+#endif
+@end example
+
+@noindent
+so that when the compiler is compiled with GNU CC it uses the more
+efficient built-in @code{alloca} function.
+
+@item FUNCTION_CONVERSION_BUG
+@findex FUNCTION_CONVERSION_BUG
+Define this macro to indicate that the host compiler does not properly
+handle converting a function value to a pointer-to-function when it is
+used in an expression.
+
+@findex HAVE_VPRINTF
+@findex vprintf
+@item HAVE_VPRINTF
+Define this if the library function @code{vprintf} is available on your
+system.
+
+@findex MULTIBYTE_CHARS
+@item MULTIBYTE_CHARS
+Define this macro to enable support for multibyte characters in the
+input to GNU CC. This requires that the host system support the ANSI C
+library functions for converting multibyte characters to wide
+characters.
+
+@findex HAVE_PUTENV
+@findex putenv
+@item HAVE_PUTENV
+Define this if the library function @code{putenv} is available on your
+system.
+
+@findex NO_SYS_SIGLIST
+@item NO_SYS_SIGLIST
+Define this if your system @emph{does not} provide the variable
+@code{sys_siglist}.
+
+@findex DONT_DECLARE_SYS_SIGLIST
+@item DONT_DECLARE_SYS_SIGLIST
+Define this if your system has the variable @code{sys_siglist}, and
+there is already a declaration of it in the system header files.
+
+@findex USE_PROTOTYPES
+@item USE_PROTOTYPES
+Define this to be 1 if you know that the host compiler supports
+prototypes, even if it doesn't define __STDC__, or define
+it to be 0 if you do not want any prototypes used in compiling
+GNU CC. If @samp{USE_PROTOTYPES} is not defined, it will be
+determined automatically whether your compiler supports
+prototypes by checking if @samp{__STDC__} is defined.
+
+@findex NO_MD_PROTOTYPES
+@item NO_MD_PROTOTYPES
+Define this if you wish suppression of prototypes generated from
+the machine description file, but to use other prototypes within
+GNU CC. If @samp{USE_PROTOTYPES} is defined to be 0, or the
+host compiler does not support prototypes, this macro has no
+effect.
+
+@findex MD_CALL_PROTOTYPES
+@item MD_CALL_PROTOTYPES
+Define this if you wish to generate prototypes for the
+@code{gen_call} or @code{gen_call_value} functions generated from
+the machine description file. If @samp{USE_PROTOTYPES} is
+defined to be 0, or the host compiler does not support
+prototypes, or @samp{NO_MD_PROTOTYPES} is defined, this macro has
+no effect. As soon as all of the machine descriptions are
+modified to have the appropriate number of arguments, this macro
+will be removed.
+
+@vindex sys_siglist
+Some systems do provide this variable, but with a different name such
+as @code{_sys_siglist}. On these systems, you can define
+@code{sys_siglist} as a macro which expands into the name actually
+provided.
+
+@findex NO_STAB_H
+@item NO_STAB_H
+Define this if your system does not have the include file
+@file{stab.h}. If @samp{USG} is defined, @samp{NO_STAB_H} is
+assumed.
+
+@findex PATH_SEPARATOR
+@item PATH_SEPARATOR
+Define this macro to be a C character constant representing the
+character used to separate components in paths. The default value is.
+the colon character
+
+@findex DIR_SEPARATOR
+@item DIR_SEPARATOR
+If your system uses some character other than slash to separate
+directory names within a file specification, define this macro to be a C
+character constant specifying that character. When GNU CC displays file
+names, the character you specify will be used. GNU CC will test for
+both slash and the character you specify when parsing filenames.
+@end table
+
+@findex bzero
+@findex bcmp
+In addition, configuration files for system V define @code{bcopy},
+@code{bzero} and @code{bcmp} as aliases. Some files define @code{alloca}
+as a macro when compiled with GNU CC, in order to take advantage of the
+benefit of GNU CC's built-in @code{alloca}.
+
+
+@node Index
+@unnumbered Index
+@end ifset
+
+@ifclear INTERNALS
+@node Index
+@unnumbered Index
+@end ifclear
+
+@printindex cp
+@summarycontents
+@contents
+@bye
diff --git a/gnu/usr.bin/cc/doc/gpcompare.texi b/gnu/usr.bin/cc/doc/gpcompare.texi
new file mode 100644
index 0000000..07a7ab5
--- /dev/null
+++ b/gnu/usr.bin/cc/doc/gpcompare.texi
@@ -0,0 +1,236 @@
+@node ANSI
+@chapter @sc{gnu} C++ Conformance to @sc{ansi} C++
+
+These changes in the @sc{gnu} C++ compiler were made to comply more
+closely with the @sc{ansi} base document, @cite{The Annotated C++
+Reference Manual} (the @sc{arm}). Further reducing the divergences from
+@sc{ansi} C++ is a continued goal of the @sc{gnu} C++ Renovation
+Project.
+
+@b{Section 3.4}, @i{Start and Termination}. It is now illegal to take
+the address of the function @samp{main()}.
+
+@b{Section 4.8}, @i{Pointers to Members}. The compiler produces
+an error for trying to convert between a pointer to a member and the type
+@samp{void *}.
+
+@b{Section 5.2.5}, @i{Increment and Decrement}. It is an error to use
+the increment and decrement operators on an enumerated type.
+
+@b{Section 5.3.2}, @i{Sizeof}. Doing @code{sizeof} on a function is now
+an error.
+
+@b{Section 5.3.4}, @i{Delete}. The syntax of a @i{cast-expression} is
+now more strictly controlled.
+
+@b{Section 7.1.1}, @i{Storage Class Specifiers}. Using the
+@code{static} and @code{extern} specifiers can now only be applied to
+names of objects, functions, and anonymous unions.
+
+@b{Section 7.1.1}, @i{Storage Class Specifiers}. The compiler no longer complains
+about taking the address of a variable which has been declared to have @code{register}
+storage.
+
+@b{Section 7.1.2}, @i{Function Specifiers}. The compiler produces an
+error when the @code{inline} or @code{virtual} specifiers are
+used on anything other than a function.
+
+@b{Section 8.3}, @i{Function Definitions}. It is now an error to shadow
+a parameter name with a local variable; in the past, the compiler only
+gave a warning in such a situation.
+
+@b{Section 8.4.1}, @i{Aggregates}. The rules concerning declaration of
+an aggregate are now all checked in the @sc{gnu} C++ compiler; they
+include having no private or protected members and no base classes.
+
+@b{Section 8.4.3}, @i{References}. Declaring an array of references is
+now forbidden. Initializing a reference with an initializer list is
+also considered an error.
+
+@b{Section 9.5}, @i{Unions}. Global anonymous unions must be declared
+@code{static}.
+
+@b{Section 11.4}, @i{Friends}. Declaring a member to be a friend of a
+type that has not yet been defined is an error.
+
+@b{Section 12.1}, @i{Constructors}. The compiler generates a
+default copy constructor for a class if no constructor has been declared.
+
+@ignore
+@b{Section 12.4}, @i{Destructors}. In accordance with the @sc{ansi} C++
+draft standard working paper, a pure virtual destructor must now be
+defined.
+@end ignore
+
+@b{Section 12.6.2}, @i{Special Member Functions}. When using a
+@i{mem-initializer} list, the compiler will now initialize class members
+in declaration order, not in the order in which you specify them.
+Also, the compiler enforces the rule that non-static @code{const}
+and reference members must be initialized with a @i{mem-initializer}
+list when their class does not have a constructor.
+
+@b{Section 12.8}, @i{Copying Class Objects}. The compiler generates
+default copy constructors correctly, and supplies default assignment
+operators compatible with user-defined ones.
+
+@b{Section 13.4}, @i{Overloaded Operators}. An overloaded operator may
+no longer have default arguments.
+
+@b{Section 13.4.4}, @i{Function Call}. An overloaded @samp{operator ()}
+must be a non-static member function.
+
+@b{Section 13.4.5}, @i{Subscripting}. An overloaded @samp{operator []}
+must be a non-static member function.
+
+@b{Section 13.4.6}, @i{Class Member Access}. An overloaded @samp{operator ->}
+must be a non-static member function.
+
+@b{Section 13.4.7}, @i{Increment and Decrement}. The compiler will now
+make sure a postfix @samp{@w{operator ++}} or @samp{@w{operator --}} has an
+@code{int} as its second argument.
+
+
+@node Encoding
+@chapter Name Encoding in @sc{gnu} C++
+
+@c FIXME!! rewrite name encoding section
+@c ...to give complete rules rather than diffs from ARM.
+@c To avoid plagiarism, invent some different way of structuring the
+@c description of the rules than what ARM uses.
+
+@cindex mangling
+@cindex name encoding
+@cindex encoding information in names
+In order to support its strong typing rules and the ability to provide
+function overloading, the C++ programming language @dfn{encodes}
+information about functions and objects, so that conflicts across object
+files can be detected during linking. @footnote{This encoding is also
+sometimes called, whimsically enough, @dfn{mangling}; the corresponding
+decoding is sometimes called @dfn{demangling}.} These rules tend to be
+unique to each individual implementation of C++.
+
+The scheme detailed in the commentary for 7.2.1 of @cite{The Annotated
+Reference Manual} offers a description of a possible implementation
+which happens to closely resemble the @code{cfront} compiler. The
+design used in @sc{gnu} C++ differs from this model in a number of ways:
+
+@itemize @bullet
+@item
+In addition to the basic types @code{void}, @code{char}, @code{short},
+@code{int}, @code{long}, @code{float}, @code{double}, and @code{long
+double}, @sc{gnu} C++ supports two additional types: @code{wchar_t}, the wide
+character type, and @code{long long} (if the host supports it). The
+encodings for these are @samp{w} and @samp{x} respectively.
+
+@item
+According to the @sc{arm}, qualified names (e.g., @samp{foo::bar::baz}) are
+encoded with a leading @samp{Q}. Followed by the number of
+qualifications (in this case, three) and the respective names, this
+might be encoded as @samp{Q33foo3bar3baz}. @sc{gnu} C++ adds a leading
+underscore to the list, producing @samp{_Q33foo3bar3baz}.
+
+@item
+The operator @samp{*=} is encoded as @samp{__aml}, not @samp{__amu}, to
+match the normal @samp{*} operator, which is encoded as @samp{__ml}.
+
+@c XXX left out ->(), __wr
+@item
+In addition to the normal operators, @sc{gnu} C++ also offers the minimum and
+maximum operators @samp{>?} and @samp{<?}, encoded as @samp{__mx} and
+@samp{__mn}, and the conditional operator @samp{?:}, encoded as @samp{__cn}.
+
+@cindex destructors, encoding of
+@cindex constructors, encoding of
+@item
+Constructors are encoded as simply @samp{__@var{name}}, where @var{name}
+is the encoded name (e.g., @code{3foo} for the @code{foo} class
+constructor). Destructors are encoded as two leading underscores
+separated by either a period or a dollar sign, depending on the
+capabilities of the local host, followed by the encoded name. For
+example, the destructor @samp{foo::~foo} is encoded as @samp{_$_3foo}.
+
+@item
+Virtual tables are encoded with a prefix of @samp{_vt}, rather than
+@samp{__vtbl}. The names of their classes are separated by dollar signs
+(or periods), and not encoded as normal: the virtual table for
+@code{foo} is @samp{__vt$foo}, and the table for @code{foo::bar} is
+named @samp{__vt$foo$bar}.
+
+@item
+Static members are encoded as a leading underscore, followed by the
+encoded name of the class in which they appear, a separating dollar sign
+or period, and finally the unencoded name of the variable. For example,
+if the class @code{foo} contains a static member @samp{bar}, its
+encoding would be @samp{_3foo$bar}.
+
+@item
+@sc{gnu} C++ is not as aggressive as other compilers when it comes to always
+generating @samp{Fv} for functions with no arguments. In particular,
+the compiler does not add the sequence to conversion operators. The
+function @samp{foo::bar()} is encoded as @samp{bar__3foo}, not
+@samp{bar__3fooFv}.
+
+@item
+The argument list for methods is not prefixed by a leading @samp{F}; it
+is considered implied.
+
+@item
+@sc{gnu} C++ approaches the task of saving space in encodings
+differently from that noted in the @sc{arm}. It does use the
+@samp{T@var{n}} and @samp{N@var{x}@var{y}} codes to signify copying the
+@var{n}th argument's type, and making the next @var{x} arguments be the
+type of the @var{y}th argument, respectively. However, the values for
+@var{n} and @var{y} begin at zero with @sc{gnu} C++, whereas the
+@sc{arm} describes them as starting at one. For the function @samp{foo
+(bartype, bartype)}, @sc{gnu} C++ uses @samp{foo__7bartypeT0}, while
+compilers following the @sc{arm} example generate @samp{foo__7bartypeT1}.
+
+@c Note it loses on `foo (int, int, int, int, int)'.
+@item
+@sc{gnu} C++ does not bother using the space-saving methods for types whose
+encoding is a single character (like an integer, encoded as @samp{i}).
+This is useful in the most common cases (two @code{int}s would result in
+using three letters, instead of just @samp{ii}).
+@end itemize
+
+@c @node Cfront
+@c @chapter @code{cfront} Compared to @sc{gnu} C++
+@c
+@c
+@c FIXME!! Fill in. Consider points in the following:
+@c
+@c @display
+@c Date: Thu, 2 Jan 92 21:35:20 EST
+@c From: raeburn@@cygnus.com
+@c Message-Id: <9201030235.AA10999@@cambridge.cygnus.com>
+@c To: mrs@@charlie.secs.csun.edu
+@c Cc: g++@@cygnus.com
+@c Subject: Re: ARM and GNU C++ incompatabilities
+@c
+@c Along with that, we should probably describe how g++ differs from
+@c cfront, in ways that the users will notice. (E.g., cfront supposedly
+@c allows "free (new char[10])"; does g++? How do the template
+@c implementations differ? "New" placement syntax?)
+@c @end display
+@c
+@c XXX For next revision.
+@c
+@c GNU C++:
+@c * supports expanding inline functions in many situations,
+@c including those which have static objects, use `for' statements,
+@c and other situations. Part of this versatility is due to is
+@c ability to not always generate temporaries for assignments.
+@c * deliberately allows divide by 0 and mod 0, since [according
+@c to Wilson] there are actually situations where you'd like to allow
+@c such things. Note on most systems it will cause some sort of trap
+@c or bus error. Cfront considers it an error.
+@c * does [appear to] support nested classes within templates.
+@c * conversion functions among baseclasses are all usable by
+@c a class that's derived from all of those bases.
+@c * sizeof works even when the class is defined within its ()'s
+@c * conditional expressions work with member fns and pointers to
+@c members.
+@c * can handle non-trivial declarations of variables within switch
+@c statements.
+@c
+@c Cfront:
diff --git a/gnu/usr.bin/cc/doc/gxxint.texi b/gnu/usr.bin/cc/doc/gxxint.texi
new file mode 100644
index 0000000..2441da1
--- /dev/null
+++ b/gnu/usr.bin/cc/doc/gxxint.texi
@@ -0,0 +1,1271 @@
+\input texinfo @c -*-texinfo-*-
+@c %**start of header
+@setfilename g++int.info
+@settitle G++ internals
+@setchapternewpage odd
+@c %**end of header
+
+@node Top, Limitations of g++, (dir), (dir)
+@chapter Internal Architecture of the Compiler
+
+This is meant to describe the C++ front-end for gcc in detail.
+Questions and comments to mrs@@cygnus.com.
+
+@menu
+* Limitations of g++::
+* Routines::
+* Implementation Specifics::
+* Glossary::
+* Macros::
+* Typical Behavior::
+* Coding Conventions::
+* Templates::
+* Access Control::
+* Error Reporting::
+* Parser::
+* Copying Objects::
+* Exception Handling::
+* Free Store::
+* Concept Index::
+@end menu
+
+@node Limitations of g++, Routines, Top, Top
+@section Limitations of g++
+
+@itemize @bullet
+@item
+Limitations on input source code: 240 nesting levels with the parser
+stacksize (YYSTACKSIZE) set to 500 (the default), and requires around
+16.4k swap space per nesting level. The parser needs about 2.09 *
+number of nesting levels worth of stackspace.
+
+@cindex pushdecl_class_level
+@item
+I suspect there are other uses of pushdecl_class_level that do not call
+set_identifier_type_value in tandem with the call to
+pushdecl_class_level. It would seem to be an omission.
+
+@cindex access checking
+@item
+Access checking is unimplemented for nested types.
+
+@cindex @code{volatile}
+@item
+@code{volatile} is not implemented in general.
+
+@cindex pointers to members
+@item
+Pointers to members are only minimally supported, and there are places
+where the grammar doesn't even properly accept them yet.
+
+@cindex multiple inheritance
+@item
+@code{this} will be wrong in virtual members functions defined in a
+virtual base class, when they are overridden in a derived class, when
+called via a non-left most object.
+
+An example would be:
+
+@example
+extern "C" int printf(const char*, ...);
+struct A @{ virtual void f() @{ @} @};
+struct B : virtual A @{ int b; B() : b(0) @{@} void f() @{ b++; @} @};
+struct C : B @{@};
+struct D : B @{@};
+struct E : C, D @{@};
+int main()
+@{
+ E e;
+ C& c = e; D& d = e;
+ c.f(); d.f();
+ printf ("C::b = %d, D::b = %d\n", e.C::b, e.D::b);
+ return 0;
+@}
+@end example
+
+This will print out 2, 0, instead of 1,1.
+
+@end itemize
+
+@node Routines, Implementation Specifics, Limitations of g++, Top
+@section Routines
+
+This section describes some of the routines used in the C++ front-end.
+
+@code{build_vtable} and @code{prepare_fresh_vtable} is used only within
+the @file{cp-class.c} file, and only in @code{finish_struct} and
+@code{modify_vtable_entries}.
+
+@code{build_vtable}, @code{prepare_fresh_vtable}, and
+@code{finish_struct} are the only routines that set @code{DECL_VPARENT}.
+
+@code{finish_struct} can steal the virtual function table from parents,
+this prohibits related_vslot from working. When finish_struct steals,
+we know that
+
+@example
+get_binfo (DECL_FIELD_CONTEXT (CLASSTYPE_VFIELD (t)), t, 0)
+@end example
+
+@noindent
+will get the related binfo.
+
+@code{layout_basetypes} does something with the VIRTUALS.
+
+Supposedly (according to Tiemann) most of the breadth first searching
+done, like in @code{get_base_distance} and in @code{get_binfo} was not
+because of any design decision. I have since found out the at least one
+part of the compiler needs the notion of depth first binfo searching, I
+am going to try and convert the whole thing, it should just work. The
+term left-most refers to the depth first left-most node. It uses
+@code{MAIN_VARIANT == type} as the condition to get left-most, because
+the things that have @code{BINFO_OFFSET}s of zero are shared and will
+have themselves as their own @code{MAIN_VARIANT}s. The non-shared right
+ones, are copies of the left-most one, hence if it is its own
+@code{MAIN_VARIENT}, we know it IS a left-most one, if it is not, it is
+a non-left-most one.
+
+@code{get_base_distance}'s path and distance matters in its use in:
+
+@itemize @bullet
+@item
+@code{prepare_fresh_vtable} (the code is probably wrong)
+@item
+@code{init_vfields} Depends upon distance probably in a safe way,
+build_offset_ref might use partial paths to do further lookups,
+hack_identifier is probably not properly checking access.
+
+@item
+@code{get_first_matching_virtual} probably should check for
+@code{get_base_distance} returning -2.
+
+@item
+@code{resolve_offset_ref} should be called in a more deterministic
+manner. Right now, it is called in some random contexts, like for
+arguments at @code{build_method_call} time, @code{default_conversion}
+time, @code{convert_arguments} time, @code{build_unary_op} time,
+@code{build_c_cast} time, @code{build_modify_expr} time,
+@code{convert_for_assignment} time, and
+@code{convert_for_initialization} time.
+
+But, there are still more contexts it needs to be called in, one was the
+ever simple:
+
+@example
+if (obj.*pmi != 7)
+ @dots{}
+@end example
+
+Seems that the problems were due to the fact that @code{TREE_TYPE} of
+the @code{OFFSET_REF} was not a @code{OFFSET_TYPE}, but rather the type
+of the referent (like @code{INTEGER_TYPE}). This problem was fixed by
+changing @code{default_conversion} to check @code{TREE_CODE (x)},
+instead of only checking @code{TREE_CODE (TREE_TYPE (x))} to see if it
+was @code{OFFSET_TYPE}.
+
+@end itemize
+
+@node Implementation Specifics, Glossary, Routines, Top
+@section Implementation Specifics
+
+@itemize @bullet
+@item Explicit Initialization
+
+The global list @code{current_member_init_list} contains the list of
+mem-initializers specified in a constructor declaration. For example:
+
+@example
+foo::foo() : a(1), b(2) @{@}
+@end example
+
+@noindent
+will initialize @samp{a} with 1 and @samp{b} with 2.
+@code{expand_member_init} places each initialization (a with 1) on the
+global list. Then, when the fndecl is being processed,
+@code{emit_base_init} runs down the list, initializing them. It used to
+be the case that g++ first ran down @code{current_member_init_list},
+then ran down the list of members initializing the ones that weren't
+explicitly initialized. Things were rewritten to perform the
+initializations in order of declaration in the class. So, for the above
+example, @samp{a} and @samp{b} will be initialized in the order that
+they were declared:
+
+@example
+class foo @{ public: int b; int a; foo (); @};
+@end example
+
+@noindent
+Thus, @samp{b} will be initialized with 2 first, then @samp{a} will be
+initialized with 1, regardless of how they're listed in the mem-initializer.
+
+@item Argument Matching
+
+In early 1993, the argument matching scheme in @sc{gnu} C++ changed
+significantly. The original code was completely replaced with a new
+method that will, hopefully, be easier to understand and make fixing
+specific cases much easier.
+
+The @samp{-fansi-overloading} option is used to enable the new code; at
+some point in the future, it will become the default behavior of the
+compiler.
+
+The file @file{cp-call.c} contains all of the new work, in the functions
+@code{rank_for_overload}, @code{compute_harshness},
+@code{compute_conversion_costs}, and @code{ideal_candidate}.
+
+Instead of using obscure numerical values, the quality of an argument
+match is now represented by clear, individual codes. The new data
+structure @code{struct harshness} (it used to be an @code{unsigned}
+number) contains:
+
+@enumerate a
+@item the @samp{code} field, to signify what was involved in matching two
+arguments;
+@item the @samp{distance} field, used in situations where inheritance
+decides which function should be called (one is ``closer'' than
+another);
+@item and the @samp{int_penalty} field, used by some codes as a tie-breaker.
+@end enumerate
+
+The @samp{code} field is a number with a given bit set for each type of
+code, OR'd together. The new codes are:
+
+@itemize @bullet
+@item @code{EVIL_CODE}
+The argument was not a permissible match.
+
+@item @code{CONST_CODE}
+Currently, this is only used by @code{compute_conversion_costs}, to
+distinguish when a non-@code{const} member function is called from a
+@code{const} member function.
+
+@item @code{ELLIPSIS_CODE}
+A match against an ellipsis @samp{...} is considered worse than all others.
+
+@item @code{USER_CODE}
+Used for a match involving a user-defined conversion.
+
+@item @code{STD_CODE}
+A match involving a standard conversion.
+
+@item @code{PROMO_CODE}
+A match involving an integral promotion. For these, the
+@code{int_penalty} field is used to handle the ARM's rule (XXX cite)
+that a smaller @code{unsigned} type should promote to a @code{int}, not
+to an @code{unsigned int}.
+
+@item @code{QUAL_CODE}
+Used to mark use of qualifiers like @code{const} and @code{volatile}.
+
+@item @code{TRIVIAL_CODE}
+Used for trivial conversions. The @samp{int_penalty} field is used by
+@code{convert_harshness} to communicate further penalty information back
+to @code{build_overload_call_real} when deciding which function should
+be call.
+@end itemize
+
+The functions @code{convert_to_aggr} and @code{build_method_call} use
+@code{compute_conversion_costs} to rate each argument's suitability for
+a given candidate function (that's how we get the list of candidates for
+@code{ideal_candidate}).
+
+@end itemize
+
+@node Glossary, Macros, Implementation Specifics, Top
+@section Glossary
+
+@table @r
+@item binfo
+The main data structure in the compiler used to represent the
+inheritance relationships between classes. The data in the binfo can be
+accessed by the BINFO_ accessor macros.
+
+@item vtable
+@itemx virtual function table
+
+The virtual function table holds information used in virtual function
+dispatching. In the compiler, they are usually referred to as vtables,
+or vtbls. The first index is not used in the normal way, I believe it
+is probably used for the virtual destructor.
+
+@item vfield
+
+vfields can be thought of as the base information needed to build
+vtables. For every vtable that exists for a class, there is a vfield.
+See also vtable and virtual function table pointer. When a type is used
+as a base class to another type, the virtual function table for the
+derived class can be based upon the vtable for the base class, just
+extended to include the additional virtual methods declared in the
+derived class. The virtual function table from a virtual base class is
+never reused in a derived class. @code{is_normal} depends upon this.
+
+@item virtual function table pointer
+
+These are @code{FIELD_DECL}s that are pointer types that point to
+vtables. See also vtable and vfield.
+@end table
+
+@node Macros, Typical Behavior, Glossary, Top
+@section Macros
+
+This section describes some of the macros used on trees. The list
+should be alphabetical. Eventually all macros should be documented
+here. There are some postscript drawings that can be used to better
+understnad from of the more complex data structures, contact Mike Stump
+(@code{mrs@@cygnus.com}) for information about them.
+
+@table @code
+@item BINFO_BASETYPES
+A vector of additional binfos for the types inherited by this basetype.
+The binfos are fully unshared (except for virtual bases, in which
+case the binfo structure is shared).
+
+ If this basetype describes type D as inherited in C,
+ and if the basetypes of D are E anf F,
+ then this vector contains binfos for inheritance of E and F by C.
+
+Has values of:
+
+ TREE_VECs
+
+
+@item BINFO_INHERITANCE_CHAIN
+Temporarily used to represent specific inheritances. It usually points
+to the binfo associated with the lesser derived type, but it can be
+reversed by reverse_path. For example:
+
+@example
+ Z ZbY least derived
+ |
+ Y YbX
+ |
+ X Xb most derived
+
+TYPE_BINFO (X) == Xb
+BINFO_INHERITANCE_CHAIN (Xb) == YbX
+BINFO_INHERITANCE_CHAIN (Yb) == ZbY
+BINFO_INHERITANCE_CHAIN (Zb) == 0
+@end example
+
+Not sure is the above is really true, get_base_distance has is point
+towards the most derived type, opposite from above.
+
+Set by build_vbase_path, recursive_bounded_basetype_p,
+get_base_distance, lookup_field, lookup_fnfields, and reverse_path.
+
+What things can this be used on:
+
+ TREE_VECs that are binfos
+
+
+@item BINFO_OFFSET
+The offset where this basetype appears in its containing type.
+BINFO_OFFSET slot holds the offset (in bytes) from the base of the
+complete object to the base of the part of the object that is allocated
+on behalf of this `type'. This is always 0 except when there is
+multiple inheritance.
+
+Used on TREE_VEC_ELTs of the binfos BINFO_BASETYPES (...) for example.
+
+
+@item BINFO_VIRTUALS
+A unique list of functions for the virtual function table. See also
+TYPE_BINFO_VIRTUALS.
+
+What things can this be used on:
+
+ TREE_VECs that are binfos
+
+
+@item BINFO_VTABLE
+Used to find the VAR_DECL that is the virtual function table associated
+with this binfo. See also TYPE_BINFO_VTABLE. To get the virtual
+function table pointer, see CLASSTYPE_VFIELD.
+
+What things can this be used on:
+
+ TREE_VECs that are binfos
+
+Has values of:
+
+ VAR_DECLs that are virtual function tables
+
+
+@item BLOCK_SUPERCONTEXT
+In the outermost scope of each function, it points to the FUNCTION_DECL
+node. It aids in better DWARF support of inline functions.
+
+
+@item CLASSTYPE_TAGS
+CLASSTYPE_TAGS is a linked (via TREE_CHAIN) list of member classes of a
+class. TREE_PURPOSE is the name, TREE_VALUE is the type (pushclass scans
+these and calls pushtag on them.)
+
+finish_struct scans these to produce TYPE_DECLs to add to the
+TYPE_FIELDS of the type.
+
+It is expected that name found in the TREE_PURPOSE slot is unique,
+resolve_scope_to_name is one such place that depends upon this
+uniqueness.
+
+
+@item CLASSTYPE_METHOD_VEC
+The following is true after finish_struct has been called (on the
+class?) but not before. Before finish_struct is called, things are
+different to some extent. Contains a TREE_VEC of methods of the class.
+The TREE_VEC_LENGTH is the number of differently named methods plus one
+for the 0th entry. The 0th entry is always allocated, and reserved for
+ctors and dtors. If there are none, TREE_VEC_ELT(N,0) == NULL_TREE.
+Each entry of the TREE_VEC is a FUNCTION_DECL. For each FUNCTION_DECL,
+there is a DECL_CHAIN slot. If the FUNCTION_DECL is the last one with a
+given name, the DECL_CHAIN slot is NULL_TREE. Otherwise it is the next
+method that has the same name (but a different signature). It would
+seem that it is not true that because the DECL_CHAIN slot is used in
+this way, we cannot call pushdecl to put the method in the global scope
+(cause that would overwrite the TREE_CHAIN slot), because they use
+different _CHAINs. finish_struct_methods setups up one version of the
+TREE_CHAIN slots on the FUNCTION_DECLs.
+
+friends are kept in TREE_LISTs, so that there's no need to use their
+TREE_CHAIN slot for anything.
+
+Has values of:
+
+ TREE_VECs
+
+
+@item CLASSTYPE_VFIELD
+Seems to be in the process of being renamed TYPE_VFIELD. Use on types
+to get the main virtual function table pointer. To get the virtual
+function table use BINFO_VTABLE (TYPE_BINFO ()).
+
+Has values of:
+
+ FIELD_DECLs that are virtual function table pointers
+
+What things can this be used on:
+
+ RECORD_TYPEs
+
+
+@item DECL_CLASS_CONTEXT
+Identifies the context that the _DECL was found in. For virtual function
+tables, it points to the type associated with the virtual function
+table. See also DECL_CONTEXT, DECL_FIELD_CONTEXT and DECL_FCONTEXT.
+
+The difference between this and DECL_CONTEXT, is that for virtuals
+functions like:
+
+@example
+struct A
+@{
+ virtual int f ();
+@};
+
+struct B : A
+@{
+ int f ();
+@};
+
+DECL_CONTEXT (A::f) == A
+DECL_CLASS_CONTEXT (A::f) == A
+
+DECL_CONTEXT (B::f) == A
+DECL_CLASS_CONTEXT (B::f) == B
+@end example
+
+Has values of:
+
+ RECORD_TYPEs, or UNION_TYPEs
+
+What things can this be used on:
+
+ TYPE_DECLs, _DECLs
+
+
+@item DECL_CONTEXT
+Identifies the context that the _DECL was found in. Can be used on
+virtual function tables to find the type associated with the virtual
+function table, but since they are FIELD_DECLs, DECL_FIELD_CONTEXT is a
+better access method. Internally the same as DECL_FIELD_CONTEXT, so
+don't us both. See also DECL_FIELD_CONTEXT, DECL_FCONTEXT and
+DECL_CLASS_CONTEXT.
+
+Has values of:
+
+ RECORD_TYPEs
+
+
+What things can this be used on:
+
+@display
+VAR_DECLs that are virtual function tables
+_DECLs
+@end display
+
+
+@item DECL_FIELD_CONTEXT
+Identifies the context that the FIELD_DECL was found in. Internally the
+same as DECL_CONTEXT, so don't us both. See also DECL_CONTEXT,
+DECL_FCONTEXT and DECL_CLASS_CONTEXT.
+
+Has values of:
+
+ RECORD_TYPEs
+
+What things can this be used on:
+
+@display
+FIELD_DECLs that are virtual function pointers
+FIELD_DECLs
+@end display
+
+
+@item DECL_NESTED_TYPENAME
+Holds the fully qualified type name. Example, Base::Derived.
+
+Has values of:
+
+ IDENTIFIER_NODEs
+
+What things can this be used on:
+
+ TYPE_DECLs
+
+
+@item DECL_NAME
+
+Has values of:
+
+@display
+0 for things that don't have names
+IDENTIFIER_NODEs for TYPE_DECLs
+@end display
+
+@item DECL_IGNORED_P
+A bit that can be set to inform the debug information output routines in
+the back-end that a certain _DECL node should be totally ignored.
+
+Used in cases where it is known that the debugging information will be
+output in another file, or where a sub-type is known not to be needed
+because the enclosing type is not needed.
+
+A compiler constructed virtual destructor in derived classes that do not
+define an exlicit destructor that was defined exlicit in a base class
+has this bit set as well. Also used on __FUNCTION__ and
+__PRETTY_FUNCTION__ to mark they are ``compiler generated.'' c-decl and
+c-lex.c both want DECL_IGNORED_P set for ``internally generated vars,''
+and ``user-invisible variable.''
+
+Functions built by the C++ front-end such as default destructors,
+virtual desctructors and default constructors want to be marked that
+they are compiler generated, but unsure why.
+
+Currently, it is used in an absolute way in the C++ front-end, as an
+optimization, to tell the debug information output routines to not
+generate debugging information that will be output by another separately
+compiled file.
+
+
+@item DECL_VIRTUAL_P
+A flag used on FIELD_DECLs and VAR_DECLs. (Documentation in tree.h is
+wrong.) Used in VAR_DECLs to indicate that the variable is a vtable.
+It is also used in FIELD_DECLs for vtable pointers.
+
+What things can this be used on:
+
+ FIELD_DECLs and VAR_DECLs
+
+
+@item DECL_VPARENT
+Used to point to the parent type of the vtable if there is one, else it
+is just the type associated with the vtable. Because of the sharing of
+virtual function tables that goes on, this slot is not very useful, and
+is in fact, not used in the compiler at all. It can be removed.
+
+What things can this be used on:
+
+ VAR_DECLs that are virtual function tables
+
+Has values of:
+
+ RECORD_TYPEs maybe UNION_TYPEs
+
+
+@item DECL_FCONTEXT
+Used to find the first baseclass in which this FIELD_DECL is defined.
+See also DECL_CONTEXT, DECL_FIELD_CONTEXT and DECL_CLASS_CONTEXT.
+
+How it is used:
+
+ Used when writing out debugging information about vfield and
+ vbase decls.
+
+What things can this be used on:
+
+ FIELD_DECLs that are virtual function pointers
+ FIELD_DECLs
+
+
+@item DECL_REFERENCE_SLOT
+Used to hold the initialize for the reference.
+
+What things can this be used on:
+
+ PARM_DECLs and VAR_DECLs that have a reference type
+
+
+@item DECL_VINDEX
+Used for FUNCTION_DECLs in two different ways. Before the structure
+containing the FUNCTION_DECL is laid out, DECL_VINDEX may point to a
+FUNCTION_DECL in a base class which is the FUNCTION_DECL which this
+FUNCTION_DECL will replace as a virtual function. When the class is
+laid out, this pointer is changed to an INTEGER_CST node which is
+suitable to find an index into the virtual function table. See
+get_vtable_entry as to how one can find the right index into the virtual
+function table. The first index 0, of a virtual function table it not
+used in the normal way, so the first real index is 1.
+
+DECL_VINDEX may be a TREE_LIST, that would seem to be a list of
+overridden FUNCTION_DECLs. add_virtual_function has code to deal with
+this when it uses the variable base_fndecl_list, but it would seem that
+somehow, it is possible for the TREE_LIST to pursist until method_call,
+and it should not.
+
+
+What things can this be used on:
+
+ FUNCTION_DECLs
+
+
+@item DECL_SOURCE_FILE
+Identifies what source file a particular declaration was found in.
+
+Has values of:
+
+ "<built-in>" on TYPE_DECLs to mean the typedef is built in
+
+
+@item DECL_SOURCE_LINE
+Identifies what source line number in the source file the declaration
+was found at.
+
+Has values of:
+
+@display
+0 for an undefined label
+
+0 for TYPE_DECLs that are internally generated
+
+0 for FUNCTION_DECLs for functions generated by the compiler
+ (not yet, but should be)
+
+0 for ``magic'' arguments to functions, that the user has no
+ control over
+@end display
+
+
+@item TREE_USED
+
+Has values of:
+
+ 0 for unused labels
+
+
+@item TREE_ADDRESSABLE
+A flag that is set for any type that has a constructor.
+
+
+@item TREE_COMPLEXITY
+They seem a kludge way to track recursion, poping, and pushing. They only
+appear in cp-decl.c and cp-decl2.c, so the are a good candidate for
+proper fixing, and removal.
+
+
+@item TREE_PRIVATE
+Set for FIELD_DECLs by finish_struct. But not uniformly set.
+
+The following routines do something with PRIVATE access:
+build_method_call, alter_access, finish_struct_methods,
+finish_struct, convert_to_aggr, CWriteLanguageDecl, CWriteLanguageType,
+CWriteUseObject, compute_access, lookup_field, dfs_pushdecl,
+GNU_xref_member, dbxout_type_fields, dbxout_type_method_1
+
+
+@item TREE_PROTECTED
+The following routines do something with PROTECTED access:
+build_method_call, alter_access, finish_struct, convert_to_aggr,
+CWriteLanguageDecl, CWriteLanguageType, CWriteUseObject,
+compute_access, lookup_field, GNU_xref_member, dbxout_type_fields,
+dbxout_type_method_1
+
+
+@item TYPE_BINFO
+Used to get the binfo for the type.
+
+Has values of:
+
+ TREE_VECs that are binfos
+
+What things can this be used on:
+
+ RECORD_TYPEs
+
+
+@item TYPE_BINFO_BASETYPES
+See also BINFO_BASETYPES.
+
+@item TYPE_BINFO_VIRTUALS
+A unique list of functions for the virtual function table. See also
+BINFO_VIRTUALS.
+
+What things can this be used on:
+
+ RECORD_TYPEs
+
+
+@item TYPE_BINFO_VTABLE
+Points to the virtual function table associated with the given type.
+See also BINFO_VTABLE.
+
+What things can this be used on:
+
+ RECORD_TYPEs
+
+Has values of:
+
+ VAR_DECLs that are virtual function tables
+
+
+@item TYPE_NAME
+Names the type.
+
+Has values of:
+
+@display
+0 for things that don't have names.
+should be IDENTIFIER_NODE for RECORD_TYPEs UNION_TYPEs and
+ ENUM_TYPEs.
+TYPE_DECL for RECORD_TYPEs, UNION_TYPEs and ENUM_TYPEs, but
+ shouldn't be.
+TYPE_DECL for typedefs, unsure why.
+@end display
+
+What things can one use this on:
+
+@display
+TYPE_DECLs
+RECORD_TYPEs
+UNION_TYPEs
+ENUM_TYPEs
+@end display
+
+History:
+
+ It currently points to the TYPE_DECL for RECORD_TYPEs,
+ UNION_TYPEs and ENUM_TYPEs, but it should be history soon.
+
+
+@item TYPE_METHODS
+Synonym for @code{CLASSTYPE_METHOD_VEC}. Chained together with
+@code{TREE_CHAIN}. @file{dbxout.c} uses this to get at the methods of a
+class.
+
+
+@item TYPE_DECL
+Used to represent typedefs, and used to represent bindings layers.
+
+Components:
+
+ DECL_NAME is the name of the typedef. For example, foo would
+ be found in the DECL_NAME slot when @code{typedef int foo;} is
+ seen.
+
+ DECL_SOURCE_LINE identifies what source line number in the
+ source file the declaration was found at. A value of 0
+ indicates that this TYPE_DECL is just an internal binding layer
+ marker, and does not correspond to a user suppiled typedef.
+
+ DECL_SOURCE_FILE
+
+@item TYPE_FIELDS
+A linked list (via @code{TREE_CHAIN}) of member types of a class. The
+list can contain @code{TYPE_DECL}s, but there can also be other things
+in the list apparently. See also @code{CLASSTYPE_TAGS}.
+
+
+@item TYPE_VIRTUAL_P
+A flag used on a @code{FIELD_DECL} or a @code{VAR_DECL}, indicates it is
+a virtual function table or a pointer to one. When used on a
+@code{FUNCTION_DECL}, indicates that it is a virtual function. When
+used on an @code{IDENTIFIER_NODE}, indicates that a function with this
+same name exists and has been declared virtual.
+
+When used on types, it indicates that the type has virtual functions, or
+is derived from one that does.
+
+Not sure if the above about virtual function tables is still true. See
+also info on @code{DECL_VIRTUAL_P}.
+
+What things can this be used on:
+
+ FIELD_DECLs, VAR_DECLs, FUNCTION_DECLs, IDENTIFIER_NODEs
+
+
+@item VF_BASETYPE_VALUE
+Get the associated type from the binfo that caused the given vfield to
+exist. This is the least derived class (the most parent class) that
+needed a virtual function table. It is probably the case that all uses
+of this field are misguided, but they need to be examined on a
+case-by-case basis. See history for more information on why the
+previous statement was made.
+
+Set at @code{finish_base_struct} time.
+
+What things can this be used on:
+
+ TREE_LISTs that are vfields
+
+History:
+
+ This field was used to determine if a virtual function table's
+ slot should be filled in with a certain virtual function, by
+ checking to see if the type returned by VF_BASETYPE_VALUE was a
+ parent of the context in which the old virtual function existed.
+ This incorrectly assumes that a given type _could_ not appear as
+ a parent twice in a given inheritance lattice. For single
+ inheritance, this would in fact work, because a type could not
+ possibly appear more than once in an inheritance lattice, but
+ with multiple inheritance, a type can appear more than once.
+
+
+@item VF_BINFO_VALUE
+Identifies the binfo that caused this vfield to exist. If this vfield
+is from the first direct base class that has a virtual function table,
+then VF_BINFO_VALUE is NULL_TREE, otherwise it will be the binfo of the
+direct base where the vfield came from. Can use @code{TREE_VIA_VIRTUAL}
+on result to find out if it is a virtual base class. Related to the
+binfo found by
+
+@example
+get_binfo (VF_BASETYPE_VALUE (vfield), t, 0)
+@end example
+
+@noindent
+where @samp{t} is the type that has the given vfield.
+
+@example
+get_binfo (VF_BASETYPE_VALUE (vfield), t, 0)
+@end example
+
+@noindent
+will return the binfo for the the given vfield.
+
+May or may not be set at @code{modify_vtable_entries} time. Set at
+@code{finish_base_struct} time.
+
+What things can this be used on:
+
+ TREE_LISTs that are vfields
+
+
+@item VF_DERIVED_VALUE
+Identifies the type of the most derived class of the vfield, excluding
+the the class this vfield is for.
+
+Set at @code{finish_base_struct} time.
+
+What things can this be used on:
+
+ TREE_LISTs that are vfields
+
+
+@item VF_NORMAL_VALUE
+Identifies the type of the most derived class of the vfield, including
+the class this vfield is for.
+
+Set at @code{finish_base_struct} time.
+
+What things can this be used on:
+
+ TREE_LISTs that are vfields
+
+
+@item WRITABLE_VTABLES
+This is a option that can be defined when building the compiler, that
+will cause the compiler to output vtables into the data segment so that
+the vtables maybe written. This is undefined by default, because
+normally the vtables should be unwritable. People that implement object
+I/O facilities may, or people that want to change the dynamic type of
+objects may want to have the vtables writable. Another way of achieving
+this would be to make a copy of the vtable into writable memory, but the
+drawback there is that that method only changes the type for one object.
+
+@end table
+
+@node Typical Behavior, Coding Conventions, Macros, Top
+@section Typical Behavior
+
+@cindex parse errors
+
+Whenever seemingly normal code fails with errors like
+@code{syntax error at `\@{'}, it's highly likely that grokdeclarator is
+returning a NULL_TREE for whatever reason.
+
+@node Coding Conventions, Templates, Typical Behavior, Top
+@section Coding Conventions
+
+It should never be that case that trees are modified in-place by the
+back-end, @emph{unless} it is guaranteed that the semantics are the same
+no matter how shared the tree structure is. @file{fold-const.c} still
+has some cases where this is not true, but rms hypothesizes that this
+will never be a problem.
+
+@node Templates, Access Control, Coding Conventions, Top
+@section Templates
+
+g++ uses the simple approach to instantiating templates: it blindly
+generates the code for each instantiation as needed. For class
+templates, g++ pushes the template parameters into the namespace for the
+duration of the instantiation; for function templates, it's a simple
+search and replace.
+
+This approach does not support any of the template definition-time error
+checking that is being bandied about by X3J16. It makes no attempt to deal
+with name binding in a consistent way.
+
+Instantiation of a class template is triggered by the use of a template
+class anywhere but in a straight declaration like @code{class A<int>}.
+This is wrong; in fact, it should not be triggered by typedefs or
+declarations of pointers. Now that explicit instantiation is supported,
+this misfeature is not necessary.
+
+Important functions:
+
+@table @code
+@item instantiate_class_template
+This function
+@end table
+
+@node Access Control, Error Reporting, Templates, Top
+@section Access Control
+The function compute_access returns one of three values:
+
+@table @code
+@item access_public
+means that the field can be accessed by the current lexical scope.
+
+@item access_protected
+means that the field cannot be accessed by the current lexical scope
+because it is protected.
+
+@item access_private
+means that the field cannot be accessed by the current lexical scope
+because it is private.
+@end table
+
+DECL_ACCESS is used for access declarations; alter_access creates a list
+of types and accesses for a given decl.
+
+Formerly, DECL_@{PUBLIC,PROTECTED,PRIVATE@} corresponded to the return
+codes of compute_access and were used as a cache for compute_access.
+Now they are not used at all.
+
+TREE_PROTECTED and TREE_PRIVATE are used to record the access levels
+granted by the containing class. BEWARE: TREE_PUBLIC means something
+completely unrelated to access control!
+
+@node Error Reporting, Parser, Access Control, Top
+@section Error Reporting
+
+The C++ front-end uses a call-back mechanism to allow functions to print
+out reasonable strings for types and functions without putting extra
+logic in the functions where errors are found. The interface is through
+the @code{cp_error} function (or @code{cp_warning}, etc.). The
+syntax is exactly like that of @code{error}, except that a few more
+conversions are supported:
+
+@itemize @bullet
+@item
+%C indicates a value of `enum tree_code'.
+@item
+%D indicates a *_DECL node.
+@item
+%E indicates a *_EXPR node.
+@item
+%L indicates a value of `enum languages'.
+@item
+%P indicates the name of a parameter (i.e. "this", "1", "2", ...)
+@item
+%T indicates a *_TYPE node.
+@item
+%O indicates the name of an operator (MODIFY_EXPR -> "operator =").
+
+@end itemize
+
+There is some overlap between these; for instance, any of the node
+options can be used for printing an identifier (though only @code{%D}
+tries to decipher function names).
+
+For a more verbose message (@code{class foo} as opposed to just @code{foo},
+including the return type for functions), use @code{%#c}.
+To have the line number on the error message indicate the line of the
+DECL, use @code{cp_error_at} and its ilk; to indicate which argument you want,
+use @code{%+D}, or it will default to the first.
+
+@node Parser, Copying Objects, Error Reporting, Top
+@section Parser
+
+Some comments on the parser:
+
+The @code{after_type_declarator} / @code{notype_declarator} hack is
+necessary in order to allow redeclarations of @code{TYPENAME}s, for
+instance
+
+@example
+typedef int foo;
+class A @{
+ char *foo;
+@};
+@end example
+
+In the above, the first @code{foo} is parsed as a @code{notype_declarator},
+and the second as a @code{after_type_declarator}.
+
+Ambiguities:
+
+There are currently four reduce/reduce ambiguities in the parser. They are:
+
+1) Between @code{template_parm} and
+@code{named_class_head_sans_basetype}, for the tokens @code{aggr
+identifier}. This situation occurs in code looking like
+
+@example
+template <class T> class A @{ @};
+@end example
+
+It is ambiguous whether @code{class T} should be parsed as the
+declaration of a template type parameter named @code{T} or an unnamed
+constant parameter of type @code{class T}. Section 14.6, paragraph 3 of
+the January '94 working paper states that the first interpretation is
+the correct one. This ambiguity results in two reduce/reduce conflicts.
+
+2) Between @code{primary} and @code{type_id} for code like @samp{int()}
+in places where both can be accepted, such as the argument to
+@code{sizeof}. Section 8.1 of the pre-San Diego working paper specifies
+that these ambiguous constructs will be interpreted as @code{typename}s.
+This ambiguity results in six reduce/reduce conflicts between
+@samp{absdcl} and @samp{functional_cast}.
+
+3) Between @code{functional_cast} and
+@code{complex_direct_notype_declarator}, for various token strings.
+This situation occurs in code looking like
+
+@example
+int (*a);
+@end example
+
+This code is ambiguous; it could be a declaration of the variable
+@samp{a} as a pointer to @samp{int}, or it could be a functional cast of
+@samp{*a} to @samp{int}. Section 6.8 specifies that the former
+interpretation is correct. This ambiguity results in 7 reduce/reduce
+conflicts. Another aspect of this ambiguity is code like 'int (x[2]);',
+which is resolved at the '[' and accounts for 6 reduce/reduce conflicts
+between @samp{direct_notype_declarator} and
+@samp{primary}/@samp{overqualified_id}. Finally, there are 4 r/r
+conflicts between @samp{expr_or_declarator} and @samp{primary} over code
+like 'int (a);', which could probably be resolved but would also
+probably be more trouble than it's worth. In all, this situation
+accounts for 17 conflicts. Ack!
+
+The second case above is responsible for the failure to parse 'LinppFile
+ppfile (String (argv[1]), &outs, argc, argv);' (from Rogue Wave
+Math.h++) as an object declaration, and must be fixed so that it does
+not resolve until later.
+
+4) Indirectly between @code{after_type_declarator} and @code{parm}, for
+type names. This occurs in (as one example) code like
+
+@example
+typedef int foo, bar;
+class A @{
+ foo (bar);
+@};
+@end example
+
+What is @code{bar} inside the class definition? We currently interpret
+it as a @code{parm}, as does Cfront, but IBM xlC interprets it as an
+@code{after_type_declarator}. I believe that xlC is correct, in light
+of 7.1p2, which says "The longest sequence of @i{decl-specifiers} that
+could possibly be a type name is taken as the @i{decl-specifier-seq} of
+a @i{declaration}." However, it seems clear that this rule must be
+violated in the case of constructors. This ambiguity accounts for 8
+conflicts.
+
+Unlike the others, this ambiguity is not recognized by the Working Paper.
+
+@node Copying Objects, Exception Handling, Parser, Top
+@section Copying Objects
+
+The generated copy assignment operator in g++ does not currently do the
+right thing for multiple inheritance involving virtual bases; it just
+calls the copy assignment operators for its direct bases. What it
+should probably do is:
+
+1) Split up the copy assignment operator for all classes that have
+vbases into "copy my vbases" and "copy everything else" parts. Or do
+the trickiness that the constructors do to ensure that vbases don't get
+initialized by intermediate bases.
+
+2) Wander through the class lattice, find all vbases for which no
+intermediate base has a user-defined copy assignment operator, and call
+their "copy everything else" routines. If not all of my vbases satisfy
+this criterion, warn, because this may be surprising behavior.
+
+3) Call the "copy everything else" routine for my direct bases.
+
+If we only have one direct base, we can just foist everything off onto
+them.
+
+This issue is currently under discussion in the core reflector
+(2/28/94).
+
+@node Exception Handling, Free Store, Copying Objects, Top
+@section Exception Handling
+
+Note, exception handling in g++ is still under development.
+
+This section describes the mapping of C++ exceptions in the C++
+front-end, into the back-end exception handling framework.
+
+The basic mechanism of exception handling in the back-end is
+unwind-protect a la elisp. This is a general, robust, and language
+independent representation for exceptions.
+
+The C++ front-end exceptions are mapping into the unwind-protect
+semantics by the C++ front-end. The mapping is describe below.
+
+Objects with RTTI support should use the RTTI information to do mapping
+and checking. Objects without RTTI, like int and const char *, have to
+use another means of matching. Currently we use the normal mangling used in
+building functions names. Int's are "i", const char * is PCc, etc...
+
+Unfortunately, the standard allows standard type conversions on throw
+parameters so they can match catch handlers. This means we need a
+mechanism to handle type conversion at run time, ICK. I read this part
+again, and it appears that we only have to be able to do a few of the
+conversions at run time, so we should be ok.
+
+In C++, all cleanups should be protected by exception regions. The
+region starts just after the reason why the cleanup is created has
+ended. For example, with an automatic variable, that has a constructor,
+it would be right after the constructor is run. The region ends just
+before the finalization is expanded. Since the backend may expand the
+cleanup multiple times along different paths, once for normal end of the
+region, once for non-local gotos, once for returns, etc, the backend
+must take special care to protect the finalization expansion, if the
+expansion is for any other reason than normal region end, and it is
+`inline' (it is inside the exception region). The backend can either
+choose to move them out of line, or it can created an exception region
+over the finalization to protect it, and in the handler associated with
+it, it would not run the finalization as it otherwise would have, but
+rather just rethrow to the outer handler, careful to skip the normal
+handler for the original region.
+
+In Ada, they will use the more runtime intensive approach of having
+fewer regions, but at the cost of additional work at run time, to keep a
+list of things that need cleanups. When a variable has finished
+construction, they add the cleanup to the list, when the come to the end
+of the lifetime of the variable, the run the list down. If the take a
+hit before the section finishes normally, they examine the list for
+actions to perform. I hope they add this logic into the back-end, as it
+would be nice to get that alternative approach in C++.
+
+On an rs6000, xlC stores exception objects on that stack, under the try
+block. When is unwinds down into a handler, the frame pointer is
+adjusted back to the normal value for the frame in which the handler
+resides, and the stack pointer is left unchanged from the time at which
+the object was throwed. This is so that there is always someplace for
+the exception object, and nothing can overwrite it, once we start
+throwing. The only bad part, is that the stack remains large.
+
+Flaws in g++'s exception handling. The stack pointer is restored from
+stack, we want to match rs6000, and propagate the stack pointer from
+time of throw, down, to the catch place.
+
+Only exact type matching of throw types works (references work also),
+catch variables cannot be used. Only works on a Sun sparc running SunOS
+4.1.x. Unwinding to outer catch clauses works. All temps and local
+variables are cleaned up in all unwinded scopes. Completed parts of
+partially constructed objects are not cleaned up. Don't expect
+exception handling to work right if you optimize, in fact the compiler
+will probably core dump. If two EH regions are the exact same size, the
+backend cannot tell which one is first. It punts by picking the last
+one, if they tie. This is usually right. We really should stick in a
+nop, if they are the same size.
+
+If we fall off the end of a series of catch blocks, we return to the
+flow of control in a normal fasion. But this is wrong, we should
+rethrow.
+
+When we invoke the copy constructor for an exception object because it
+is passed by value, and if we take a hit (exception) inside the copy
+constructor someplace, where do we go? I have tentatively choosen to
+not catch throws by the outer block at the same unwind level, if one
+exists, but rather to allow the frame to unwind into the next series of
+handlers, if any. If this is the wrong way to do it, we will need to
+protect the rest of the handler in some fashion. Maybe just changing
+the handler's handler to protect the whole series of handlers is the
+right way to go.
+
+The EH object is copied like it should be, if it is passed by value,
+otherwise we get a reference directly to it.
+
+EH objects make it through unwinding, but are subject to being
+overwritten as they are still past the top of stack. Don't throw
+automatic objects if this is a problem.
+
+Exceptions in catch handlers now go to outer block.
+
+@node Free Store, Concept Index, Exception Handling, Top
+@section Free Store
+
+operator new [] adds a magic cookie to the beginning of arrays for which
+the number of elements will be needed by operator delete []. These are
+arrays of objects with destructors and arrays of objects that define
+operator delete [] with the optional size_t argument. This cookie can
+be examined from a program as follows:
+
+@example
+typedef unsigned long size_t;
+extern "C" int printf (const char *, ...);
+
+size_t nelts (void *p)
+@{
+ struct cookie @{
+ size_t nelts __attribute__ ((aligned (sizeof (double))));
+ @};
+
+ cookie *cp = (cookie *)p;
+ --cp;
+
+ return cp->nelts;
+@}
+
+struct A @{
+ ~A() @{ @}
+@};
+
+main()
+@{
+ A *ap = new A[3];
+ printf ("%ld\n", nelts (ap));
+@}
+@end example
+
+@node Concept Index, , Free Store, Top
+@section Concept Index
+
+@printindex cp
+
+@bye
diff --git a/gnu/usr.bin/cc/doc/install.texi b/gnu/usr.bin/cc/doc/install.texi
new file mode 100644
index 0000000..cf0f306
--- /dev/null
+++ b/gnu/usr.bin/cc/doc/install.texi
@@ -0,0 +1,2089 @@
+@c Copyright (C) 1988, 1989, 1992, 1993, 1994 Free Software Foundation, Inc.
+@c This is part of the GCC manual.
+@c For copying conditions, see the file gcc.texi.
+
+@c The text of this file appears in the file INSTALL
+@c in the GCC distribution, as well as in the GCC manual.
+
+@ifclear INSTALLONLY
+@node Installation
+@chapter Installing GNU CC
+@end ifclear
+@cindex installing GNU CC
+
+@menu
+* Configurations:: Configurations Supported by GNU CC.
+* Other Dir:: Compiling in a separate directory (not where the source is).
+* Cross-Compiler:: Building and installing a cross-compiler.
+* Sun Install:: See below for installation on the Sun.
+* VMS Install:: See below for installation on VMS.
+* Collect2:: How @code{collect2} works; how it finds @code{ld}.
+* Header Dirs:: Understanding the standard header file directories.
+@end menu
+
+Here is the procedure for installing GNU CC on a Unix system. See
+@ref{VMS Install}, for VMS systems. In this section we assume you
+compile in the same directory that contains the source files; see
+@ref{Other Dir}, to find out how to compile in a separate directory on Unix
+systems.
+
+You cannot install GNU C by itself on MSDOS; it will not compile under
+any MSDOS compiler except itself. You need to get the complete
+compilation package DJGPP, which includes binaries as well as sources,
+and includes all the necessary compilation tools and libraries.
+
+@enumerate
+@item
+If you have built GNU CC previously in the same directory for a
+different target machine, do @samp{make distclean} to delete all files
+that might be invalid. One of the files this deletes is
+@file{Makefile}; if @samp{make distclean} complains that @file{Makefile}
+does not exist, it probably means that the directory is already suitably
+clean.
+
+@item
+On a System V release 4 system, make sure @file{/usr/bin} precedes
+@file{/usr/ucb} in @code{PATH}. The @code{cc} command in
+@file{/usr/ucb} uses libraries which have bugs.
+
+@item
+Specify the host, build and target machine configurations. You do this
+by running the file @file{configure}.
+
+The @dfn{build} machine is the system which you are using, the
+@dfn{host} machine is the system where you want to run the resulting
+compiler (normally the build machine), and the @dfn{target} machine is
+the system for which you want the compiler to generate code.
+
+If you are building a compiler to produce code for the machine it runs
+on (a native compiler), you normally do not need to specify any operands
+to @file{configure}; it will try to guess the type of machine you are on
+and use that as the build, host and target machines. So you don't need
+to specify a configuration when building a native compiler unless
+@file{configure} cannot figure out what your configuration is or guesses
+wrong.
+
+In those cases, specify the build machine's @dfn{configuration name}
+with the @samp{--build} option; the host and target will default to be
+the same as the build machine. (If you are building a cross-compiler,
+see @ref{Cross-Compiler}.)
+
+Here is an example:
+
+@smallexample
+./configure --build=sparc-sun-sunos4.1
+@end smallexample
+
+A configuration name may be canonical or it may be more or less
+abbreviated.
+
+A canonical configuration name has three parts, separated by dashes.
+It looks like this: @samp{@var{cpu}-@var{company}-@var{system}}.
+(The three parts may themselves contain dashes; @file{configure}
+can figure out which dashes serve which purpose.) For example,
+@samp{m68k-sun-sunos4.1} specifies a Sun 3.
+
+You can also replace parts of the configuration by nicknames or aliases.
+For example, @samp{sun3} stands for @samp{m68k-sun}, so
+@samp{sun3-sunos4.1} is another way to specify a Sun 3. You can also
+use simply @samp{sun3-sunos}, since the version of SunOS is assumed by
+default to be version 4. @samp{sun3-bsd} also works, since
+@file{configure} knows that the only BSD variant on a Sun 3 is SunOS.
+
+You can specify a version number after any of the system types, and some
+of the CPU types. In most cases, the version is irrelevant, and will be
+ignored. So you might as well specify the version if you know it.
+
+See @ref{Configurations}, for a list of supported configuration names and
+notes on many of the configurations. You should check the notes in that
+section before proceding any further with the installation of GNU CC.
+
+There are four additional options you can specify independently to
+describe variant hardware and software configurations. These are
+@samp{--with-gnu-as}, @samp{--with-gnu-ld}, @samp{--with-stabs} and
+@samp{--nfp}.
+
+@table @samp
+@item --with-gnu-as
+If you will use GNU CC with the GNU assembler (GAS), you should declare
+this by using the @samp{--with-gnu-as} option when you run
+@file{configure}.
+
+Using this option does not install GAS. It only modifies the output of
+GNU CC to work with GAS. Building and installing GAS is up to you.
+
+Conversely, if you @emph{do not} wish to use GAS and do not specify
+@samp{--with-gnu-as} when building GNU CC, it is up to you to make sure
+that GAS is not installed. GNU CC searches for a program named
+@code{as} in various directories; if the program it finds is GAS, then
+it runs GAS. If you are not sure where GNU CC finds the assembler it is
+using, try specifying @samp{-v} when you run it.
+
+The systems where it makes a difference whether you use GAS are@*
+@samp{hppa1.0-@var{any}-@var{any}}, @samp{hppa1.1-@var{any}-@var{any}},
+@samp{i386-@var{any}-sysv}, @samp{i386-@var{any}-isc},@*
+@samp{i860-@var{any}-bsd}, @samp{m68k-bull-sysv}, @samp{m68k-hp-hpux},
+@samp{m68k-sony-bsd},@*
+@samp{m68k-altos-sysv}, @samp{m68000-hp-hpux}, @samp{m68000-att-sysv},
+and @samp{mips-@var{any}}). On any other system, @samp{--with-gnu-as}
+has no effect.
+
+On the systems listed above (except for the HP-PA, for ISC on the
+386, and for @samp{mips-sgi-irix5.*}), if you use GAS, you should also
+use the GNU linker (and specify @samp{--with-gnu-ld}).
+
+@item --with-gnu-ld
+Specify the option @samp{--with-gnu-ld} if you plan to use the GNU
+linker with GNU CC.
+
+This option does not cause the GNU linker to be installed; it just
+modifies the behavior of GNU CC to work with the GNU linker.
+Specifically, it inhibits the installation of @code{collect2}, a program
+which otherwise serves as a front-end for the system's linker on most
+configurations.
+
+@item --with-stabs
+On MIPS based systems and on Alphas, you must specify whether you want
+GNU CC to create the normal ECOFF debugging format, or to use BSD-style
+stabs passed through the ECOFF symbol table. The normal ECOFF debug
+format cannot fully handle languages other than C. BSD stabs format can
+handle other languages, but it only works with the GNU debugger GDB.
+
+Normally, GNU CC uses the ECOFF debugging format by default; if you
+prefer BSD stabs, specify @samp{--with-stabs} when you configure GNU
+CC.
+
+No matter which default you choose when you configure GNU CC, the user
+can use the @samp{-gcoff} and @samp{-gstabs+} options to specify explicitly
+the debug format for a particular compilation.
+
+@samp{--with-stabs} is meaningful on the ISC system on the 386, also, if
+@samp{--with-gas} is used. It selects use of stabs debugging
+information embedded in COFF output. This kind of debugging information
+supports C++ well; ordinary COFF debugging information does not.
+
+@samp{--with-stabs} is also meaningful on 386 systems running SVR4. It
+selects use of stabs debugging information embedded in ELF output. The
+C++ compiler currently (2.6.0) does not support the DWARF debugging
+information normally used on 386 SVR4 platforms; stabs provide a
+workable alternative. This requires gas and gdb, as the normal SVR4
+tools can not generate or interpret stabs.
+
+@item --nfp
+On certain systems, you must specify whether the machine has a floating
+point unit. These systems include @samp{m68k-sun-sunos@var{n}} and
+@samp{m68k-isi-bsd}. On any other system, @samp{--nfp} currently has no
+effect, though perhaps there are other systems where it could usefully
+make a difference.
+@end table
+
+The @file{configure} script searches subdirectories of the source
+directory for other compilers that are to be integrated into GNU CC.
+The GNU compiler for C++, called G++ is in a subdirectory named
+@file{cp}. @file{configure} inserts rules into @file{Makefile} to build
+all of those compilers.
+
+Here we spell out what files will be set up by @code{configure}. Normally
+you need not be concerned with these files.
+
+@itemize @bullet
+@item
+@ifset INTERNALS
+A symbolic link named @file{config.h} is made to the top-level config
+file for the machine you will run the compiler on (@pxref{Config}).
+This file is responsible for defining information about the host
+machine. It includes @file{tm.h}.
+@end ifset
+@ifclear INTERNALS
+A symbolic link named @file{config.h} is made to the top-level config
+file for the machine you plan to run the compiler on (@pxref{Config,,The
+Configuration File, gcc.info, Using and Porting GCC}). This file is
+responsible for defining information about the host machine. It
+includes @file{tm.h}.
+@end ifclear
+
+The top-level config file is located in the subdirectory @file{config}.
+Its name is always @file{xm-@var{something}.h}; usually
+@file{xm-@var{machine}.h}, but there are some exceptions.
+
+If your system does not support symbolic links, you might want to
+set up @file{config.h} to contain a @samp{#include} command which
+refers to the appropriate file.
+
+@item
+A symbolic link named @file{tconfig.h} is made to the top-level config
+file for your target machine. This is used for compiling certain
+programs to run on that machine.
+
+@item
+A symbolic link named @file{tm.h} is made to the machine-description
+macro file for your target machine. It should be in the subdirectory
+@file{config} and its name is often @file{@var{machine}.h}.
+
+@item
+A symbolic link named @file{md} will be made to the machine description
+pattern file. It should be in the @file{config} subdirectory and its
+name should be @file{@var{machine}.md}; but @var{machine} is often not
+the same as the name used in the @file{tm.h} file because the
+@file{md} files are more general.
+
+@item
+A symbolic link named @file{aux-output.c} will be made to the output
+subroutine file for your machine. It should be in the @file{config}
+subdirectory and its name should be @file{@var{machine}.c}.
+
+@item
+The command file @file{configure} also constructs the file
+@file{Makefile} by adding some text to the template file
+@file{Makefile.in}. The additional text comes from files in the
+@file{config} directory, named @file{t-@var{target}} and
+@file{x-@var{host}}. If these files do not exist, it means nothing
+needs to be added for a given target or host.
+@c does the above work now? --mew
+@end itemize
+
+@item
+The standard directory for installing GNU CC is @file{/usr/local/lib}.
+If you want to install its files somewhere else, specify
+@samp{--prefix=@var{dir}} when you run @file{configure}. Here @var{dir}
+is a directory name to use instead of @file{/usr/local} for all purposes
+with one exception: the directory @file{/usr/local/include} is searched
+for header files no matter where you install the compiler. To override
+this name, use the @code{--local-prefix} option below.
+
+@item
+Specify @samp{--local-prefix=@var{dir}} if you want the compiler to
+search directory @file{@var{dir}/include} for locally installed header
+files @emph{instead} of @file{/usr/local/include}.
+
+You should specify @samp{--local-prefix} @strong{only} if your site has
+a different convention (not @file{/usr/local}) for where to put
+site-specific files.
+
+@strong{Do not} specify @file{/usr} as the @samp{--local-prefix}! The
+directory you use for @samp{--local-prefix} @strong{must not} contain
+any of the system's standard header files. If it did contain them,
+certain programs would be miscompiled (including GNU Emacs, on certain
+targets), because this would override and nullify the header file
+corrections made by the @code{fixincludes} script.
+
+@cindex Bison parser generator
+@cindex parser generator, Bison
+@item
+Make sure the Bison parser generator is installed. (This is
+unnecessary if the Bison output files @file{c-parse.c} and
+@file{cexp.c} are more recent than @file{c-parse.y} and @file{cexp.y}
+and you do not plan to change the @samp{.y} files.)
+
+Bison versions older than Sept 8, 1988 will produce incorrect output
+for @file{c-parse.c}.
+
+@item
+If you have chosen a configuration for GNU CC which requires other GNU
+tools (such as GAS or the GNU linker) instead of the standard system
+tools, install the required tools in the build directory under the names
+@file{as}, @file{ld} or whatever is appropriate. This will enable the
+compiler to find the proper tools for compilation of the program
+@file{enquire}.
+
+Alternatively, you can do subsequent compilation using a value of the
+@code{PATH} environment variable such that the necessary GNU tools come
+before the standard system tools.
+
+@item
+Build the compiler. Just type @samp{make LANGUAGES=c} in the compiler
+directory.
+
+@samp{LANGUAGES=c} specifies that only the C compiler should be
+compiled. The makefile normally builds compilers for all the supported
+languages; currently, C, C++ and Objective C. However, C is the only
+language that is sure to work when you build with other non-GNU C
+compilers. In addition, building anything but C at this stage is a
+waste of time.
+
+In general, you can specify the languages to build by typing the
+argument @samp{LANGUAGES="@var{list}"}, where @var{list} is one or more
+words from the list @samp{c}, @samp{c++}, and @samp{objective-c}. If
+you have any additional GNU compilers as subdirectories of the GNU CC
+source directory, you may also specify their names in this list.
+
+Ignore any warnings you may see about ``statement not reached'' in
+@file{insn-emit.c}; they are normal. Also, warnings about ``unknown
+escape sequence'' are normal in @file{genopinit.c} and perhaps some
+other files. Likewise, you should ignore warnings about ``constant is
+so large that it is unsigned'' in @file{insn-emit.c} and
+@file{insn-recog.c}. Any other compilation errors may represent bugs in
+the port to your machine or operating system, and
+@ifclear INSTALLONLY
+should be investigated and reported (@pxref{Bugs}).
+@end ifclear
+@ifset INSTALLONLY
+should be investigated and reported.
+@end ifset
+
+Some commercial compilers fail to compile GNU CC because they have bugs
+or limitations. For example, the Microsoft compiler is said to run out
+of macro space. Some Ultrix compilers run out of expression space; then
+you need to break up the statement where the problem happens.
+
+@item
+If you are building a cross-compiler, stop here. @xref{Cross-Compiler}.
+
+@cindex stage1
+@item
+Move the first-stage object files and executables into a subdirectory
+with this command:
+
+@smallexample
+make stage1
+@end smallexample
+
+The files are moved into a subdirectory named @file{stage1}.
+Once installation is complete, you may wish to delete these files
+with @code{rm -r stage1}.
+
+@item
+If you have chosen a configuration for GNU CC which requires other GNU
+tools (such as GAS or the GNU linker) instead of the standard system
+tools, install the required tools in the @file{stage1} subdirectory
+under the names @file{as}, @file{ld} or whatever is appropriate. This
+will enable the stage 1 compiler to find the proper tools in the
+following stage.
+
+Alternatively, you can do subsequent compilation using a value of the
+@code{PATH} environment variable such that the necessary GNU tools come
+before the standard system tools.
+
+@item
+Recompile the compiler with itself, with this command:
+
+@smallexample
+make CC="stage1/xgcc -Bstage1/" CFLAGS="-g -O"
+@end smallexample
+
+This is called making the stage 2 compiler.
+
+The command shown above builds compilers for all the supported
+languages. If you don't want them all, you can specify the languages to
+build by typing the argument @samp{LANGUAGES="@var{list}"}. @var{list}
+should contain one or more words from the list @samp{c}, @samp{c++},
+@samp{objective-c}, and @samp{proto}. Separate the words with spaces.
+@samp{proto} stands for the programs @code{protoize} and
+@code{unprotoize}; they are not a separate language, but you use
+@code{LANGUAGES} to enable or disable their installation.
+
+If you are going to build the stage 3 compiler, then you might want to
+build only the C language in stage 2.
+
+Once you have built the stage 2 compiler, if you are short of disk
+space, you can delete the subdirectory @file{stage1}.
+
+On a 68000 or 68020 system lacking floating point hardware,
+unless you have selected a @file{tm.h} file that expects by default
+that there is no such hardware, do this instead:
+
+@smallexample
+make CC="stage1/xgcc -Bstage1/" CFLAGS="-g -O -msoft-float"
+@end smallexample
+
+@item
+If you wish to test the compiler by compiling it with itself one more
+time, install any other necessary GNU tools (such as GAS or the GNU
+linker) in the @file{stage2} subdirectory as you did in the
+@file{stage1} subdirectory, then do this:
+
+@smallexample
+make stage2
+make CC="stage2/xgcc -Bstage2/" CFLAGS="-g -O"
+@end smallexample
+
+@noindent
+This is called making the stage 3 compiler. Aside from the @samp{-B}
+option, the compiler options should be the same as when you made the
+stage 2 compiler. But the @code{LANGUAGES} option need not be the
+same. The command shown above builds compilers for all the supported
+languages; if you don't want them all, you can specify the languages to
+build by typing the argument @samp{LANGUAGES="@var{list}"}, as described
+above.
+
+If you do not have to install any additional GNU tools, you may use the
+command
+
+@smallexample
+make bootstrap LANGUAGES=@var{language-list} BOOT_CFLAGS=@var{option-list}
+@end smallexample
+
+@noindent
+instead of making @file{stage1}, @file{stage2}, and performing
+the two compiler builds.
+
+@item
+Then compare the latest object files with the stage 2 object
+files---they ought to be identical, aside from time stamps (if any).
+
+On some systems, meaningful comparison of object files is impossible;
+they always appear ``different.'' This is currently true on Solaris and
+probably on all systems that use ELF object file format. On some
+versions of Irix on SGI machines and OSF/1 on Alpha systems, you will
+not be able to compare the files without specifying @file{-save-temps};
+see the description of individual systems above to see if you get
+comparison failures. You may have similar problems on other systems.
+
+Use this command to compare the files:
+
+@smallexample
+make compare
+@end smallexample
+
+This will mention any object files that differ between stage 2 and stage
+3. Any difference, no matter how innocuous, indicates that the stage 2
+compiler has compiled GNU CC incorrectly, and is therefore a potentially
+@ifclear INSTALLONLY
+serious bug which you should investigate and report (@pxref{Bugs}).
+@end ifclear
+@ifset INSTALLONLY
+serious bug which you should investigate and report.
+@end ifset
+
+If your system does not put time stamps in the object files, then this
+is a faster way to compare them (using the Bourne shell):
+
+@smallexample
+for file in *.o; do
+cmp $file stage2/$file
+done
+@end smallexample
+
+If you have built the compiler with the @samp{-mno-mips-tfile} option on
+MIPS machines, you will not be able to compare the files.
+
+@item
+Build the Objective C library (if you have built the Objective C
+compiler). Here is the command to do this:
+
+@smallexample
+make objc-runtime CC="stage2/xgcc -Bstage2/" CFLAGS="-g -O"
+@end smallexample
+
+@item
+Install the compiler driver, the compiler's passes and run-time support
+with @samp{make install}. Use the same value for @code{CC},
+@code{CFLAGS} and @code{LANGUAGES} that you used when compiling the
+files that are being installed. One reason this is necessary is that
+some versions of Make have bugs and recompile files gratuitously when
+you do this step. If you use the same variable values, those files will
+be recompiled properly.
+
+For example, if you have built the stage 2 compiler, you can use the
+following command:
+
+@smallexample
+make install CC="stage2/xgcc -Bstage2/" CFLAGS="-g -O" LANGUAGES="@var{list}"
+@end smallexample
+
+@noindent
+This copies the files @file{cc1}, @file{cpp} and @file{libgcc.a} to
+files @file{cc1}, @file{cpp} and @file{libgcc.a} in the directory
+@file{/usr/local/lib/gcc-lib/@var{target}/@var{version}}, which is where
+the compiler driver program looks for them. Here @var{target} is the
+target machine type specified when you ran @file{configure}, and
+@var{version} is the version number of GNU CC. This naming scheme
+permits various versions and/or cross-compilers to coexist.
+
+This also copies the driver program @file{xgcc} into
+@file{/usr/local/bin/gcc}, so that it appears in typical execution
+search paths.
+
+On some systems, this command causes recompilation of some files. This
+is usually due to bugs in @code{make}. You should either ignore this
+problem, or use GNU Make.
+
+@cindex @code{alloca} and SunOs
+@strong{Warning: there is a bug in @code{alloca} in the Sun library. To
+avoid this bug, be sure to install the executables of GNU CC that were
+compiled by GNU CC. (That is, the executables from stage 2 or 3, not
+stage 1.) They use @code{alloca} as a built-in function and never the
+one in the library.}
+
+(It is usually better to install GNU CC executables from stage 2 or 3,
+since they usually run faster than the ones compiled with some other
+compiler.)
+
+@item
+Install the Objective C library (if you are installing the Objective C
+compiler). Here is the command to do this:
+
+@smallexample
+make install-libobjc CC="stage2/xgcc -Bstage2/" CFLAGS="-g -O"
+@end smallexample
+
+@item
+If you're going to use C++, it's likely that you need to also install
+the libg++ distribution. It should be available from the same
+place where you got the GNU C distribution. Just as GNU C does not
+distribute a C runtime library, it also does not include a C++ run-time
+library. All I/O functionality, special class libraries, etc., are
+available in the libg++ distribution.
+@end enumerate
+
+@node Configurations
+@section Configurations Supported by GNU CC
+@cindex configurations supported by GNU CC
+
+Here are the possible CPU types:
+
+@quotation
+@c gmicro, alliant, spur and tahoe omitted since they don't work.
+1750a, a29k, alpha, arm, c@var{n}, clipper, dsp16xx, elxsi, h8300,
+hppa1.0, hppa1.1, i370, i386, i486, i860, i960, m68000, m68k, m88k,
+mips, ns32k, powerpc, pyramid, romp, rs6000, sh, sparc, sparclite,
+sparc64, vax, we32k.
+@end quotation
+
+Here are the recognized company names. As you can see, customary
+abbreviations are used rather than the longer official names.
+
+@c What should be done about merlin, tek*, dolphin?
+@quotation
+acorn, alliant, altos, apollo, att, bull,
+cbm, convergent, convex, crds, dec, dg, dolphin,
+elxsi, encore, harris, hitachi, hp, ibm, intergraph, isi,
+mips, motorola, ncr, next, ns, omron, plexus,
+sequent, sgi, sony, sun, tti, unicom.
+@end quotation
+
+The company name is meaningful only to disambiguate when the rest of
+the information supplied is insufficient. You can omit it, writing
+just @samp{@var{cpu}-@var{system}}, if it is not needed. For example,
+@samp{vax-ultrix4.2} is equivalent to @samp{vax-dec-ultrix4.2}.
+
+Here is a list of system types:
+
+@quotation
+386bsd, aix, acis, amigados, aos, aout, bosx, bsd, clix, ctix, cxux,
+dgux, dynix, ebmon, elf, esix, freebsd, hms, genix, gnu, gnu/linux,
+hiux, hpux, iris, irix, isc, luna, lynxos, mach, minix, msdos, mvs,
+netbsd, newsos, nindy, ns, osf, osfrose, ptx, riscix, riscos, rtu, sco,
+solaris, sunos, sym, sysv, ultrix, unicos, uniplus, unos, vms, vxworks,
+xenix.
+@end quotation
+
+@noindent
+You can omit the system type; then @file{configure} guesses the
+operating system from the CPU and company.
+
+You can add a version number to the system type; this may or may not
+make a difference. For example, you can write @samp{bsd4.3} or
+@samp{bsd4.4} to distinguish versions of BSD. In practice, the version
+number is most needed for @samp{sysv3} and @samp{sysv4}, which are often
+treated differently.
+
+If you specify an impossible combination such as @samp{i860-dg-vms},
+then you may get an error message from @file{configure}, or it may
+ignore part of the information and do the best it can with the rest.
+@file{configure} always prints the canonical name for the alternative
+that it used. GNU CC does not support all possible alternatives.
+
+Often a particular model of machine has a name. Many machine names are
+recognized as aliases for CPU/company combinations. Thus, the machine
+name @samp{sun3}, mentioned above, is an alias for @samp{m68k-sun}.
+Sometimes we accept a company name as a machine name, when the name is
+popularly used for a particular machine. Here is a table of the known
+machine names:
+
+@quotation
+3300, 3b1, 3b@var{n}, 7300, altos3068, altos,
+apollo68, att-7300, balance,
+convex-c@var{n}, crds, decstation-3100,
+decstation, delta, encore,
+fx2800, gmicro, hp7@var{nn}, hp8@var{nn},
+hp9k2@var{nn}, hp9k3@var{nn}, hp9k7@var{nn},
+hp9k8@var{nn}, iris4d, iris, isi68,
+m3230, magnum, merlin, miniframe,
+mmax, news-3600, news800, news, next,
+pbd, pc532, pmax, powerpc, ps2, risc-news,
+rtpc, sun2, sun386i, sun386, sun3,
+sun4, symmetry, tower-32, tower.
+@end quotation
+
+@noindent
+Remember that a machine name specifies both the cpu type and the company
+name.
+If you want to install your own homemade configuration files, you can
+use @samp{local} as the company name to access them. If you use
+configuration @samp{@var{cpu}-local}, the configuration name
+without the cpu prefix
+is used to form the configuration file names.
+
+Thus, if you specify @samp{m68k-local}, configuration uses
+files @file{m68k.md}, @file{local.h}, @file{m68k.c},
+@file{xm-local.h}, @file{t-local}, and @file{x-local}, all in the
+directory @file{config/m68k}.
+
+Here is a list of configurations that have special treatment or special
+things you must know:
+
+@table @samp
+@item 1750a-*-*
+MIL-STD-1750A processors.
+
+Starting with GCC 2.6.1, the MIL-STD-1750A cross configuration no longer
+supports the Tektronix Assembler, but instead produces output for
+@code{as1750}, an assembler/linker available under the GNU Public
+License for the 1750A. Contact @emph{okellogg@@salyko.cube.net} for more
+details on obtaining @samp{as1750}. A similarly licensed simulator for
+the 1750A is available from same address.
+
+You should ignore a fatal error during the building of libgcc (libgcc is
+not yet implemented for the 1750A.)
+
+The @code{as1750} assembler requires the file @file{ms1750.inc}, which is
+found in the directory @file{config/1750a}.
+
+GNU CC produced the same sections as the Fairchild F9450 C Compiler,
+namely:
+
+@table @code
+@item NREL
+The program code section.
+
+@item SREL
+The read/write (RAM) data section.
+
+@item KREL
+The read-only (ROM) constants section.
+
+@item IREL
+Initialization section (code to copy KREL to SREL).
+@end table
+
+The smallest addressable unit is 16 bits (BITS_PER_UNIT is 16). This
+means that type `char' is represented with a 16-bit word per character.
+The 1750A's "Load/Store Upper/Lower Byte" instructions are not used by
+GNU CC.
+
+There is a problem with long argument lists to functions. The compiler
+aborts if the sum of space needed by all arguments exceeds 14 words.
+This is because the arguments are passed in registers (R0..R13) not on
+the stack, and there is a problem with passing further arguments (i.e.
+beyond those in R0..R13) via the stack.
+
+If efficiency is less important than using long argument lists, you
+can change the definition of the @code{FUNCTION_ARG} macro in
+@file{config/1750/1750a.h} to always return zero. If you do that,
+GNU CC will pass all parameters on the stack.
+
+@item alpha-*-osf1
+Systems using processors that implement the DEC Alpha architecture and
+are running the OSF/1 operating system, for example the DEC Alpha AXP
+systems. (VMS on the Alpha is not currently supported by GNU CC.)
+
+GNU CC writes a @samp{.verstamp} directive to the assembler output file
+unless it is built as a cross-compiler. It gets the version to use from
+the system header file @file{/usr/include/stamp.h}. If you install a
+new version of OSF/1, you should rebuild GCC to pick up the new version
+stamp.
+
+Note that since the Alpha is a 64-bit architecture, cross-compilers from
+32-bit machines will not generate code as efficient as that generated
+when the compiler is running on a 64-bit machine because many
+optimizations that depend on being able to represent a word on the
+target in an integral value on the host cannot be performed. Building
+cross-compilers on the Alpha for 32-bit machines has only been tested in
+a few cases and may not work properly.
+
+@code{make compare} may fail on old versions of OSF/1 unless you add
+@samp{-save-temps} to @code{CFLAGS}. On these systems, the name of the
+assembler input file is stored in the object file, and that makes
+comparison fail if it differs between the @code{stage1} and
+@code{stage2} compilations. The option @samp{-save-temps} forces a
+fixed name to be used for the assembler input file, instead of a
+randomly chosen name in @file{/tmp}. Do not add @samp{-save-temps}
+unless the comparisons fail without that option. If you add
+@samp{-save-temps}, you will have to manually delete the @samp{.i} and
+@samp{.s} files after each series of compilations.
+
+GNU CC now supports both the native (ECOFF) debugging format used by DBX
+and GDB and an encapsulated STABS format for use only with GDB. See the
+discussion of the @samp{--with-stabs} option of @file{configure} above
+for more information on these formats and how to select them.
+
+There is a bug in DEC's assembler that produces incorrect line numbers
+for ECOFF format when the @samp{.align} directive is used. To work
+around this problem, GNU CC will not emit such alignment directives
+while writing ECOFF format debugging information even if optimization is
+being performed. Unfortunately, this has the very undesirable
+side-effect that code addresses when @samp{-O} is specified are
+different depending on whether or not @samp{-g} is also specified.
+
+To avoid this behavior, specify @samp{-gstabs+} and use GDB instead of
+DBX. DEC is now aware of this problem with the assembler and hopes to
+provide a fix shortly.
+
+@item arm
+Advanced RISC Machines ARM-family processors. These are often used in
+embedded applications. There are no standard Unix configurations.
+This configuration corresponds to the basic instruction sequences and will
+produce a.out format object modules.
+
+You may need to make a variant of the file @file{arm.h} for your particular
+configuration.
+
+@item arm-*-riscix
+The ARM2 or ARM3 processor running RISC iX, Acorn's port of BSD Unix. If
+you are running a version of RISC iX prior to 1.2 then you must specify
+the version number during configuration. Note that the assembler
+shipped with RISC iX does not support stabs debugging information; a
+new version of the assembler, with stabs support included, is now
+available from Acorn.
+
+@item a29k
+AMD Am29k-family processors. These are normally used in embedded
+applications. There are no standard Unix configurations.
+This configuration
+corresponds to AMD's standard calling sequence and binary interface
+and is compatible with other 29k tools.
+
+You may need to make a variant of the file @file{a29k.h} for your
+particular configuration.
+
+@item a29k-*-bsd
+AMD Am29050 used in a system running a variant of BSD Unix.
+
+@item decstation-*
+DECstations can support three different personalities: Ultrix,
+DEC OSF/1, and OSF/rose. To configure GCC for these platforms
+use the following configurations:
+
+@table @samp
+@item decstation-ultrix
+Ultrix configuration.
+
+@item decstation-osf1
+Dec's version of OSF/1.
+
+@item decstation-osfrose
+Open Software Foundation reference port of OSF/1 which uses the
+OSF/rose object file format instead of ECOFF. Normally, you
+would not select this configuration.
+@end table
+
+The MIPS C compiler needs to be told to increase its table size
+for switch statements with the @samp{-Wf,-XNg1500} option in
+order to compile @file{cp/parse.c}. If you use the @samp{-O2}
+optimization option, you also need to use @samp{-Olimit 3000}.
+Both of these options are automatically generated in the
+@file{Makefile} that the shell script @file{configure} builds.
+If you override the @code{CC} make variable and use the MIPS
+compilers, you may need to add @samp{-Wf,-XNg1500 -Olimit 3000}.
+
+@item elxsi-elxsi-bsd
+The Elxsi's C compiler has known limitations that prevent it from
+compiling GNU C. Please contact @code{mrs@@cygnus.com} for more details.
+
+@item dsp16xx
+A port to the AT&T DSP1610 family of processors.
+
+@ignore
+@item fx80
+Alliant FX/8 computer. Note that the standard installed C compiler in
+Concentrix 5.0 has a bug which prevent it from compiling GNU CC
+correctly. You can patch the compiler bug as follows:
+
+@smallexample
+cp /bin/pcc ./pcc
+adb -w ./pcc - << EOF
+15f6?w 6610
+EOF
+@end smallexample
+
+Then you must use the @samp{-ip12} option when compiling GNU CC
+with the patched compiler, as shown here:
+
+@smallexample
+make CC="./pcc -ip12" CFLAGS=-w
+@end smallexample
+
+Note also that Alliant's version of DBX does not manage to work with the
+output from GNU CC.
+@end ignore
+
+@item h8300-*-*
+The calling convention and structure layout has changed in release 2.6.
+All code must be recompiled. The calling convention now passes the
+first three arguments in function calls in registers. Structures are no
+longer a multiple of 2 bytes.
+
+@item hppa*-*-*
+There are two variants of this CPU, called 1.0 and 1.1, which have
+different machine descriptions. You must use the right one for your
+machine. All 7@var{nn} machines and 8@var{n}7 machines use 1.1, while
+all other 8@var{nn} machines use 1.0.
+
+The easiest way to handle this problem is to use @samp{configure
+hp@var{nnn}} or @samp{configure hp@var{nnn}-hpux}, where @var{nnn} is
+the model number of the machine. Then @file{configure} will figure out
+if the machine is a 1.0 or 1.1. Use @samp{uname -a} to find out the
+model number of your machine.
+
+@samp{-g} does not work on HP-UX, since that system uses a peculiar
+debugging format which GNU CC does not know about. However, @samp{-g}
+will work if you also use GAS and GDB in conjunction with GCC. We
+highly recommend using GAS for all HP-PA configurations.
+
+You should be using GAS-2.3 (or later) along with GDB-4.12 (or later). These
+can be retrieved from all the traditional GNU ftp archive sites.
+
+Build GAS and install the resulting binary as:
+
+@example
+/usr/local/lib/gcc-lib/@var{configuration}/@var{gccversion}/as
+@end example
+
+@noindent
+where @var{configuration} is the configuration name (perhaps
+@samp{hp@var{nnn}-hpux}) and @var{gccversion} is the GNU CC version
+number. Do this @emph{before} starting the build process, otherwise you will
+get errors from the HPUX assembler while building @file{libgcc2.a}. The
+command
+
+@example
+make install-dir
+@end example
+
+@noindent
+will create the necessary directory hierarchy so you can install GAS before
+building GCC.
+
+To enable debugging, configure GNU CC with the @samp{--with-gnu-as} option
+before building.
+
+It has been reported that GNU CC produces invalid assembly code for
+1.1 machines running HP-UX 8.02 when using the HP assembler. Typically
+the errors look like this:
+@example
+as: bug.s @@line#15 [err#1060]
+ Argument 0 or 2 in FARG upper
+ - lookahead = ARGW1=FR,RTNVAL=GR
+as: foo.s @@line#28 [err#1060]
+ Argument 0 or 2 in FARG upper
+ - lookahead = ARGW1=FR
+@end example
+
+You can check the version of HP-UX you are running by executing the command
+@samp{uname -r}. If you are indeed running HP-UX 8.02 on a PA and
+using the HP assembler then configure GCC with "hp@var{nnn}-hpux8.02".
+
+@item i370-*-*
+This port is very preliminary and has many known bugs. We hope to
+have a higher-quality port for this machine soon.
+
+@item i386-*-gnu/linux
+Bash-1.12 has a bug that causes configure to fail. The symptom is that
+the c++ subdirectory, @file{cp}, is not configured. Bash-1.14 and later
+work fine.
+
+@item i386-*-sco
+Compilation with RCC is recommended. Also, it may be a good idea to
+link with GNU malloc instead of the malloc that comes with the system.
+
+@item i386-*-sco3.2.4
+Use this configuration for SCO release 3.2 version 4.
+
+@item i386-*-isc
+It may be a good idea to link with GNU malloc instead of the malloc that
+comes with the system.
+
+In ISC version 4.1, @file{sed} core dumps when building
+@file{deduced.h}. Use the version of @file{sed} from version 4.0.
+
+@item i386-*-esix
+It may be good idea to link with GNU malloc instead of the malloc that
+comes with the system.
+
+@item i386-ibm-aix
+You need to use GAS version 2.1 or later, and and LD from
+GNU binutils version 2.2 or later.
+
+@item i386-sequent-bsd
+Go to the Berkeley universe before compiling. In addition, you probably
+need to create a file named @file{string.h} containing just one line:
+@samp{#include <strings.h>}.
+
+@item i386-sequent-ptx1*
+Sequent DYNIX/ptx 1.x.
+
+@item i386-sequent-ptx2*
+Sequent DYNIX/ptx 2.x.
+
+@item i386-sun-sunos4
+You may find that you need another version of GNU CC to begin
+bootstrapping with, since the current version when built with the
+system's own compiler seems to get an infinite loop compiling part of
+@file{libgcc2.c}. GNU CC version 2 compiled with GNU CC (any version)
+seems not to have this problem.
+
+See @ref{Sun Install}, for information on installing GNU CC on Sun
+systems.
+
+@item i860-intel-osf1
+This is the Paragon.
+@ifset INSTALLONLY
+If you have version 1.0 of the operating system, you need to take
+special steps to build GNU CC due to peculiarities of the system. Newer
+system versions have no problem. See the section `Installation Problems'
+in the GNU CC Manual.
+@end ifset
+@ifclear INSTALLONLY
+If you have version 1.0 of the operating system,
+see @ref{Installation Problems}, for special things you need to do to
+compensate for peculiarities in the system.
+@end ifclear
+
+@item m68000-hp-bsd
+HP 9000 series 200 running BSD. Note that the C compiler that comes
+with this system cannot compile GNU CC; contact @code{law@@cs.utah.edu}
+to get binaries of GNU CC for bootstrapping.
+
+@item m68k-altos
+Altos 3068. You must use the GNU assembler, linker and debugger.
+Also, you must fix a kernel bug. Details in the file @file{README.ALTOS}.
+
+@item m68k-att-sysv
+AT&T 3b1, a.k.a. 7300 PC. Special procedures are needed to compile GNU
+CC with this machine's standard C compiler, due to bugs in that
+compiler. You can bootstrap it more easily with
+previous versions of GNU CC if you have them.
+
+Installing GNU CC on the 3b1 is difficult if you do not already have
+GNU CC running, due to bugs in the installed C compiler. However,
+the following procedure might work. We are unable to test it.
+
+@enumerate
+@item
+Comment out the @samp{#include "config.h"} line on line 37 of
+@file{cccp.c} and do @samp{make cpp}. This makes a preliminary version
+of GNU cpp.
+
+@item
+Save the old @file{/lib/cpp} and copy the preliminary GNU cpp to that
+file name.
+
+@item
+Undo your change in @file{cccp.c}, or reinstall the original version,
+and do @samp{make cpp} again.
+
+@item
+Copy this final version of GNU cpp into @file{/lib/cpp}.
+
+@findex obstack_free
+@item
+Replace every occurrence of @code{obstack_free} in the file
+@file{tree.c} with @code{_obstack_free}.
+
+@item
+Run @code{make} to get the first-stage GNU CC.
+
+@item
+Reinstall the original version of @file{/lib/cpp}.
+
+@item
+Now you can compile GNU CC with itself and install it in the normal
+fashion.
+@end enumerate
+
+@item m68k-bull-sysv
+Bull DPX/2 series 200 and 300 with BOS-2.00.45 up to BOS-2.01. GNU CC works
+either with native assembler or GNU assembler. You can use
+GNU assembler with native coff generation by providing @samp{--with-gnu-as} to
+the configure script or use GNU assembler with dbx-in-coff encapsulation
+by providing @samp{--with-gnu-as --stabs}. For any problem with native
+assembler or for availability of the DPX/2 port of GAS, contact
+@code{F.Pierresteguy@@frcl.bull.fr}.
+
+@item m68k-crds-unox
+Use @samp{configure unos} for building on Unos.
+
+The Unos assembler is named @code{casm} instead of @code{as}. For some
+strange reason linking @file{/bin/as} to @file{/bin/casm} changes the
+behavior, and does not work. So, when installing GNU CC, you should
+install the following script as @file{as} in the subdirectory where
+the passes of GCC are installed:
+
+@example
+#!/bin/sh
+casm $*
+@end example
+
+The default Unos library is named @file{libunos.a} instead of
+@file{libc.a}. To allow GNU CC to function, either change all
+references to @samp{-lc} in @file{gcc.c} to @samp{-lunos} or link
+@file{/lib/libc.a} to @file{/lib/libunos.a}.
+
+@cindex @code{alloca}, for Unos
+When compiling GNU CC with the standard compiler, to overcome bugs in
+the support of @code{alloca}, do not use @samp{-O} when making stage 2.
+Then use the stage 2 compiler with @samp{-O} to make the stage 3
+compiler. This compiler will have the same characteristics as the usual
+stage 2 compiler on other systems. Use it to make a stage 4 compiler
+and compare that with stage 3 to verify proper compilation.
+
+(Perhaps simply defining @code{ALLOCA} in @file{x-crds} as described in
+the comments there will make the above paragraph superfluous. Please
+inform us of whether this works.)
+
+Unos uses memory segmentation instead of demand paging, so you will need
+a lot of memory. 5 Mb is barely enough if no other tasks are running.
+If linking @file{cc1} fails, try putting the object files into a library
+and linking from that library.
+
+@item m68k-hp-hpux
+HP 9000 series 300 or 400 running HP-UX. HP-UX version 8.0 has a bug in
+the assembler that prevents compilation of GNU CC. To fix it, get patch
+PHCO_4484 from HP.
+
+In addition, if you wish to use gas @samp{--with-gnu-as} you must use
+gas version 2.1 or later, and you must use the GNU linker version 2.1 or
+later. Earlier versions of gas relied upon a program which converted the
+gas output into the native HP/UX format, but that program has not been
+kept up to date. gdb does not understand that native HP/UX format, so
+you must use gas if you wish to use gdb.
+
+@item m68k-sun
+Sun 3. We do not provide a configuration file to use the Sun FPA by
+default, because programs that establish signal handlers for floating
+point traps inherently cannot work with the FPA.
+
+See @ref{Sun Install}, for information on installing GNU CC on Sun
+systems.
+
+@item m88k-*-svr3
+Motorola m88k running the AT&T/Unisoft/Motorola V.3 reference port.
+These systems tend to use the Green Hills C, revision 1.8.5, as the
+standard C compiler. There are apparently bugs in this compiler that
+result in object files differences between stage 2 and stage 3. If this
+happens, make the stage 4 compiler and compare it to the stage 3
+compiler. If the stage 3 and stage 4 object files are identical, this
+suggests you encountered a problem with the standard C compiler; the
+stage 3 and 4 compilers may be usable.
+
+It is best, however, to use an older version of GNU CC for bootstrapping
+if you have one.
+
+@item m88k-*-dgux
+Motorola m88k running DG/UX. To build 88open BCS native or cross
+compilers on DG/UX, specify the configuration name as
+@samp{m88k-*-dguxbcs} and build in the 88open BCS software development
+environment. To build ELF native or cross compilers on DG/UX, specify
+@samp{m88k-*-dgux} and build in the DG/UX ELF development environment.
+You set the software development environment by issuing
+@samp{sde-target} command and specifying either @samp{m88kbcs} or
+@samp{m88kdguxelf} as the operand.
+
+If you do not specify a configuration name, @file{configure} guesses the
+configuration based on the current software development environment.
+
+@item m88k-tektronix-sysv3
+Tektronix XD88 running UTekV 3.2e. Do not turn on
+optimization while building stage1 if you bootstrap with
+the buggy Green Hills compiler. Also, The bundled LAI
+System V NFS is buggy so if you build in an NFS mounted
+directory, start from a fresh reboot, or avoid NFS all together.
+Otherwise you may have trouble getting clean comparisons
+between stages.
+
+@item mips-mips-bsd
+MIPS machines running the MIPS operating system in BSD mode. It's
+possible that some old versions of the system lack the functions
+@code{memcpy}, @code{memcmp}, and @code{memset}. If your system lacks
+these, you must remove or undo the definition of
+@code{TARGET_MEM_FUNCTIONS} in @file{mips-bsd.h}.
+
+The MIPS C compiler needs to be told to increase its table size
+for switch statements with the @samp{-Wf,-XNg1500} option in
+order to compile @file{cp/parse.c}. If you use the @samp{-O2}
+optimization option, you also need to use @samp{-Olimit 3000}.
+Both of these options are automatically generated in the
+@file{Makefile} that the shell script @file{configure} builds.
+If you override the @code{CC} make variable and use the MIPS
+compilers, you may need to add @samp{-Wf,-XNg1500 -Olimit 3000}.
+
+@item mips-mips-riscos*
+The MIPS C compiler needs to be told to increase its table size
+for switch statements with the @samp{-Wf,-XNg1500} option in
+order to compile @file{cp/parse.c}. If you use the @samp{-O2}
+optimization option, you also need to use @samp{-Olimit 3000}.
+Both of these options are automatically generated in the
+@file{Makefile} that the shell script @file{configure} builds.
+If you override the @code{CC} make variable and use the MIPS
+compilers, you may need to add @samp{-Wf,-XNg1500 -Olimit 3000}.
+
+MIPS computers running RISC-OS can support four different
+personalities: default, BSD 4.3, System V.3, and System V.4
+(older versions of RISC-OS don't support V.4). To configure GCC
+for these platforms use the following configurations:
+
+@table @samp
+@item mips-mips-riscos@code{rev}
+Default configuration for RISC-OS, revision @code{rev}.
+
+@item mips-mips-riscos@code{rev}bsd
+BSD 4.3 configuration for RISC-OS, revision @code{rev}.
+
+@item mips-mips-riscos@code{rev}sysv4
+System V.4 configuration for RISC-OS, revision @code{rev}.
+
+@item mips-mips-riscos@code{rev}sysv
+System V.3 configuration for RISC-OS, revision @code{rev}.
+@end table
+
+The revision @code{rev} mentioned above is the revision of
+RISC-OS to use. You must reconfigure GCC when going from a
+RISC-OS revision 4 to RISC-OS revision 5. This has the effect of
+avoiding a linker
+@ifclear INSTALLONLY
+bug (see @ref{Installation Problems}, for more details).
+@end ifclear
+@ifset INSTALLONLY
+bug.
+@end ifset
+
+@item mips-sgi-*
+In order to compile GCC on an SGI running IRIX 4, the "c.hdr.lib"
+option must be installed from the CD-ROM supplied from Silicon Graphics.
+This is found on the 2nd CD in release 4.0.1.
+
+@code{make compare} may fail on version 5 of IRIX unless you add
+@samp{-save-temps} to @code{CFLAGS}. On these systems, the name of the
+assembler input file is stored in the object file, and that makes
+comparison fail if it differs between the @code{stage1} and
+@code{stage2} compilations. The option @samp{-save-temps} forces a
+fixed name to be used for the assembler input file, instead of a
+randomly chosen name in @file{/tmp}. Do not add @samp{-save-temps}
+unless the comparisons fail without that option. If you do you
+@samp{-save-temps}, you will have to manually delete the @samp{.i} and
+@samp{.s} files after each series of compilations.
+
+The MIPS C compiler needs to be told to increase its table size
+for switch statements with the @samp{-Wf,-XNg1500} option in
+order to compile @file{cp/parse.c}. If you use the @samp{-O2}
+optimization option, you also need to use @samp{-Olimit 3000}.
+Both of these options are automatically generated in the
+@file{Makefile} that the shell script @file{configure} builds.
+If you override the @code{CC} make variable and use the MIPS
+compilers, you may need to add @samp{-Wf,-XNg1500 -Olimit 3000}.
+
+On Irix version 4.0.5F, and perhaps on some other versions as well,
+there is an assembler bug that reorders instructions incorrectly. To
+work around it, specify the target configuration
+@samp{mips-sgi-irix4loser}. This configuration inhibits assembler
+optimization.
+
+In a compiler configured with target @samp{mips-sgi-irix4}, you can turn
+off assembler optimization by using the @samp{-noasmopt} option. This
+compiler option passes the option @samp{-O0} to the assembler, to
+inhibit reordering.
+
+The @samp{-noasmopt} option can be useful for testing whether a problem
+is due to erroneous assembler reordering. Even if a problem does not go
+away with @samp{-noasmopt}, it may still be due to assembler
+reordering---perhaps GNU CC itself was miscompiled as a result.
+
+To enable debugging under Irix 5, you must use GNU as 2.5 or later,
+and use the --with-gnu-as configure option when configuring gcc.
+GNU as is distributed as part of the binutils package.
+
+@item mips-sony-sysv
+Sony MIPS NEWS. This works in NEWSOS 5.0.1, but not in 5.0.2 (which
+uses ELF instead of COFF). Support for 5.0.2 will probably be provided
+soon by volunteers. In particular, the linker does not like the
+code generated by GCC when shared libraries are linked in.
+
+@item ns32k-encore
+Encore ns32000 system. Encore systems are supported only under BSD.
+
+@item ns32k-*-genix
+National Semiconductor ns32000 system. Genix has bugs in @code{alloca}
+and @code{malloc}; you must get the compiled versions of these from GNU
+Emacs.
+
+@item ns32k-sequent
+Go to the Berkeley universe before compiling. In addition, you probably
+need to create a file named @file{string.h} containing just one line:
+@samp{#include <strings.h>}.
+
+@item ns32k-utek
+UTEK ns32000 system (``merlin''). The C compiler that comes with this
+system cannot compile GNU CC; contact @samp{tektronix!reed!mason} to get
+binaries of GNU CC for bootstrapping.
+
+@item romp-*-aos
+@itemx romp-*-mach
+The only operating systems supported for the IBM RT PC are AOS and
+MACH. GNU CC does not support AIX running on the RT. We recommend you
+compile GNU CC with an earlier version of itself; if you compile GNU CC
+with @code{hc}, the Metaware compiler, it will work, but you will get
+mismatches between the stage 2 and stage 3 compilers in various files.
+These errors are minor differences in some floating-point constants and
+can be safely ignored; the stage 3 compiler is correct.
+
+@item rs6000-*-aix
+@itemx powerpc-*-aix
+Various early versions of each release of the IBM XLC compiler will not
+bootstrap GNU CC. Symptoms include differences between the stage2 and
+stage3 object files, and errors when compiling @file{libgcc.a} or
+@file{enquire}. Known problematic releases include: xlc-1.2.1.8,
+xlc-1.3.0.0 (distributed with AIX 3.2.5), and xlc-1.3.0.19. Both
+xlc-1.2.1.28 and xlc-1.3.0.24 (PTF 432238) are known to produce working
+versions of GNU CC, but most other recent releases correctly bootstrap
+GNU CC. Also, releases of AIX prior to AIX 3.2.4 include a version of
+the IBM assembler which does not accept debugging directives: assembler
+updates are available as PTFs. See the file @file{README.RS6000} for
+more details on both of these problems.
+
+Only AIX is supported on the PowerPC. GNU CC does not yet support the
+64-bit PowerPC instructions.
+
+Objective C does not work on this architecture.
+
+AIX on the RS/6000 provides support (NLS) for environments outside of
+the United States. Compilers and assemblers use NLS to support
+locale-specific representations of various objects including
+floating-point numbers ("." vs "," for separating decimal fractions).
+There have been problems reported where the library linked with GNU CC
+does not produce the same floating-point formats that the assembler
+accepts. If you have this problem, set the LANG environment variable to
+"C" or "En_US".
+
+@item vax-dec-ultrix
+Don't try compiling with Vax C (@code{vcc}). It produces incorrect code
+in some cases (for example, when @code{alloca} is used).
+
+Meanwhile, compiling @file{cp/parse.c} with pcc does not work because of
+an internal table size limitation in that compiler. To avoid this
+problem, compile just the GNU C compiler first, and use it to recompile
+building all the languages that you want to run.
+
+@item sparc-sun-*
+See @ref{Sun Install}, for information on installing GNU CC on Sun
+systems.
+
+@item vax-dec-vms
+See @ref{VMS Install}, for details on how to install GNU CC on VMS.
+
+@item we32k-*-*
+These computers are also known as the 3b2, 3b5, 3b20 and other similar
+names. (However, the 3b1 is actually a 68000; see
+@ref{Configurations}.)
+
+Don't use @samp{-g} when compiling with the system's compiler. The
+system's linker seems to be unable to handle such a large program with
+debugging information.
+
+The system's compiler runs out of capacity when compiling @file{stmt.c}
+in GNU CC. You can work around this by building @file{cpp} in GNU CC
+first, then use that instead of the system's preprocessor with the
+system's C compiler to compile @file{stmt.c}. Here is how:
+
+@example
+mv /lib/cpp /lib/cpp.att
+cp cpp /lib/cpp.gnu
+echo '/lib/cpp.gnu -traditional $@{1+"$@@"@}' > /lib/cpp
+chmod +x /lib/cpp
+@end example
+
+The system's compiler produces bad code for some of the GNU CC
+optimization files. So you must build the stage 2 compiler without
+optimization. Then build a stage 3 compiler with optimization.
+That executable should work. Here are the necessary commands:
+
+@example
+make LANGUAGES=c CC=stage1/xgcc CFLAGS="-Bstage1/ -g"
+make stage2
+make CC=stage2/xgcc CFLAGS="-Bstage2/ -g -O"
+@end example
+
+You may need to raise the ULIMIT setting to build a C++ compiler,
+as the file @file{cc1plus} is larger than one megabyte.
+@end table
+
+@node Other Dir
+@section Compilation in a Separate Directory
+@cindex other directory, compilation in
+@cindex compilation in a separate directory
+@cindex separate directory, compilation in
+
+If you wish to build the object files and executables in a directory
+other than the one containing the source files, here is what you must
+do differently:
+
+@enumerate
+@item
+Make sure you have a version of Make that supports the @code{VPATH}
+feature. (GNU Make supports it, as do Make versions on most BSD
+systems.)
+
+@item
+If you have ever run @file{configure} in the source directory, you must undo
+the configuration. Do this by running:
+
+@example
+make distclean
+@end example
+
+@item
+Go to the directory in which you want to build the compiler before
+running @file{configure}:
+
+@example
+mkdir gcc-sun3
+cd gcc-sun3
+@end example
+
+On systems that do not support symbolic links, this directory must be
+on the same file system as the source code directory.
+
+@item
+Specify where to find @file{configure} when you run it:
+
+@example
+../gcc/configure @dots{}
+@end example
+
+This also tells @code{configure} where to find the compiler sources;
+@code{configure} takes the directory from the file name that was used to
+invoke it. But if you want to be sure, you can specify the source
+directory with the @samp{--srcdir} option, like this:
+
+@example
+../gcc/configure --srcdir=../gcc @var{other options}
+@end example
+
+The directory you specify with @samp{--srcdir} need not be the same
+as the one that @code{configure} is found in.
+@end enumerate
+
+Now, you can run @code{make} in that directory. You need not repeat the
+configuration steps shown above, when ordinary source files change. You
+must, however, run @code{configure} again when the configuration files
+change, if your system does not support symbolic links.
+
+@node Cross-Compiler
+@section Building and Installing a Cross-Compiler
+@cindex cross-compiler, installation
+
+GNU CC can function as a cross-compiler for many machines, but not all.
+
+@itemize @bullet
+@item
+Cross-compilers for the Mips as target using the Mips assembler
+currently do not work, because the auxiliary programs
+@file{mips-tdump.c} and @file{mips-tfile.c} can't be compiled on
+anything but a Mips. It does work to cross compile for a Mips
+if you use the GNU assembler and linker.
+
+@item
+Cross-compilers between machines with different floating point formats
+have not all been made to work. GNU CC now has a floating point
+emulator with which these can work, but each target machine description
+needs to be updated to take advantage of it.
+
+@item
+Cross-compilation between machines of different word sizes is
+somewhat problematic and sometimes does not work.
+@end itemize
+
+Since GNU CC generates assembler code, you probably need a
+cross-assembler that GNU CC can run, in order to produce object files.
+If you want to link on other than the target machine, you need a
+cross-linker as well. You also need header files and libraries suitable
+for the target machine that you can install on the host machine.
+
+@menu
+* Steps of Cross:: Using a cross-compiler involves several steps
+ that may be carried out on different machines.
+* Configure Cross:: Configuring a cross-compiler.
+* Tools and Libraries:: Where to put the linker and assembler, and the C library.
+* Cross Headers:: Finding and installing header files
+ for a cross-compiler.
+* Cross Runtime:: Supplying arithmetic runtime routines (@file{libgcc1.a}).
+* Build Cross:: Actually compiling the cross-compiler.
+@end menu
+
+@node Steps of Cross
+@subsection Steps of Cross-Compilation
+
+To compile and run a program using a cross-compiler involves several
+steps:
+
+@itemize @bullet
+@item
+Run the cross-compiler on the host machine to produce assembler files
+for the target machine. This requires header files for the target
+machine.
+
+@item
+Assemble the files produced by the cross-compiler. You can do this
+either with an assembler on the target machine, or with a
+cross-assembler on the host machine.
+
+@item
+Link those files to make an executable. You can do this either with a
+linker on the target machine, or with a cross-linker on the host
+machine. Whichever machine you use, you need libraries and certain
+startup files (typically @file{crt@dots{}.o}) for the target machine.
+@end itemize
+
+It is most convenient to do all of these steps on the same host machine,
+since then you can do it all with a single invocation of GNU CC. This
+requires a suitable cross-assembler and cross-linker. For some targets,
+the GNU assembler and linker are available.
+
+@node Configure Cross
+@subsection Configuring a Cross-Compiler
+
+To build GNU CC as a cross-compiler, you start out by running
+@file{configure}. Use the @samp{--target=@var{target}} to specify the
+target type. If @file{configure} was unable to correctly identify the
+system you are running on, also specify the @samp{--build=@var{build}}
+option. For example, here is how to configure for a cross-compiler that
+produces code for an HP 68030 system running BSD on a system that
+@file{configure} can correctly identify:
+
+@smallexample
+./configure --target=m68k-hp-bsd4.3
+@end smallexample
+
+@node Tools and Libraries
+@subsection Tools and Libraries for a Cross-Compiler
+
+If you have a cross-assembler and cross-linker available, you should
+install them now. Put them in the directory
+@file{/usr/local/@var{target}/bin}. Here is a table of the tools
+you should put in this directory:
+
+@table @file
+@item as
+This should be the cross-assembler.
+
+@item ld
+This should be the cross-linker.
+
+@item ar
+This should be the cross-archiver: a program which can manipulate
+archive files (linker libraries) in the target machine's format.
+
+@item ranlib
+This should be a program to construct a symbol table in an archive file.
+@end table
+
+The installation of GNU CC will find these programs in that directory,
+and copy or link them to the proper place to for the cross-compiler to
+find them when run later.
+
+The easiest way to provide these files is to build the Binutils package
+and GAS. Configure them with the same @samp{--host} and @samp{--target}
+options that you use for configuring GNU CC, then build and install
+them. They install their executables automatically into the proper
+directory. Alas, they do not support all the targets that GNU CC
+supports.
+
+If you want to install libraries to use with the cross-compiler, such as
+a standard C library, put them in the directory
+@file{/usr/local/@var{target}/lib}; installation of GNU CC copies all
+all the files in that subdirectory into the proper place for GNU CC to
+find them and link with them. Here's an example of copying some
+libraries from a target machine:
+
+@example
+ftp @var{target-machine}
+lcd /usr/local/@var{target}/lib
+cd /lib
+get libc.a
+cd /usr/lib
+get libg.a
+get libm.a
+quit
+@end example
+
+@noindent
+The precise set of libraries you'll need, and their locations on
+the target machine, vary depending on its operating system.
+
+@cindex start files
+Many targets require ``start files'' such as @file{crt0.o} and
+@file{crtn.o} which are linked into each executable; these too should be
+placed in @file{/usr/local/@var{target}/lib}. There may be several
+alternatives for @file{crt0.o}, for use with profiling or other
+compilation options. Check your target's definition of
+@code{STARTFILE_SPEC} to find out what start files it uses.
+Here's an example of copying these files from a target machine:
+
+@example
+ftp @var{target-machine}
+lcd /usr/local/@var{target}/lib
+prompt
+cd /lib
+mget *crt*.o
+cd /usr/lib
+mget *crt*.o
+quit
+@end example
+
+@node Cross Runtime
+@subsection @file{libgcc.a} and Cross-Compilers
+
+Code compiled by GNU CC uses certain runtime support functions
+implicitly. Some of these functions can be compiled successfully with
+GNU CC itself, but a few cannot be. These problem functions are in the
+source file @file{libgcc1.c}; the library made from them is called
+@file{libgcc1.a}.
+
+When you build a native compiler, these functions are compiled with some
+other compiler--the one that you use for bootstrapping GNU CC.
+Presumably it knows how to open code these operations, or else knows how
+to call the run-time emulation facilities that the machine comes with.
+But this approach doesn't work for building a cross-compiler. The
+compiler that you use for building knows about the host system, not the
+target system.
+
+So, when you build a cross-compiler you have to supply a suitable
+library @file{libgcc1.a} that does the job it is expected to do.
+
+To compile @file{libgcc1.c} with the cross-compiler itself does not
+work. The functions in this file are supposed to implement arithmetic
+operations that GNU CC does not know how to open code, for your target
+machine. If these functions are compiled with GNU CC itself, they
+will compile into infinite recursion.
+
+On any given target, most of these functions are not needed. If GNU CC
+can open code an arithmetic operation, it will not call these functions
+to perform the operation. It is possible that on your target machine,
+none of these functions is needed. If so, you can supply an empty
+library as @file{libgcc1.a}.
+
+Many targets need library support only for multiplication and division.
+If you are linking with a library that contains functions for
+multiplication and division, you can tell GNU CC to call them directly
+by defining the macros @code{MULSI3_LIBCALL}, and the like. These
+macros need to be defined in the target description macro file. For
+some targets, they are defined already. This may be sufficient to
+avoid the need for libgcc1.a; if so, you can supply an empty library.
+
+Some targets do not have floating point instructions; they need other
+functions in @file{libgcc1.a}, which do floating arithmetic.
+Recent versions of GNU CC have a file which emulates floating point.
+With a certain amount of work, you should be able to construct a
+floating point emulator that can be used as @file{libgcc1.a}. Perhaps
+future versions will contain code to do this automatically and
+conveniently. That depends on whether someone wants to implement it.
+
+If your target system has another C compiler, you can configure GNU CC
+as a native compiler on that machine, build just @file{libgcc1.a} with
+@samp{make libgcc1.a} on that machine, and use the resulting file with
+the cross-compiler. To do this, execute the following on the target
+machine:
+
+@example
+cd @var{target-build-dir}
+./configure --host=sparc --target=sun3
+make libgcc1.a
+@end example
+
+@noindent
+And then this on the host machine:
+
+@example
+ftp @var{target-machine}
+binary
+cd @var{target-build-dir}
+get libgcc1.a
+quit
+@end example
+
+Another way to provide the functions you need in @file{libgcc1.a} is to
+define the appropriate @code{perform_@dots{}} macros for those
+functions. If these definitions do not use the C arithmetic operators
+that they are meant to implement, you should be able to compile them
+with the cross-compiler you are building. (If these definitions already
+exist for your target file, then you are all set.)
+
+To build @file{libgcc1.a} using the perform macros, use
+@samp{LIBGCC1=libgcc1.a OLDCC=./xgcc} when building the compiler.
+Otherwise, you should place your replacement library under the name
+@file{libgcc1.a} in the directory in which you will build the
+cross-compiler, before you run @code{make}.
+
+@node Cross Headers
+@subsection Cross-Compilers and Header Files
+
+If you are cross-compiling a standalone program or a program for an
+embedded system, then you may not need any header files except the few
+that are part of GNU CC (and those of your program). However, if you
+intend to link your program with a standard C library such as
+@file{libc.a}, then you probably need to compile with the header files
+that go with the library you use.
+
+The GNU C compiler does not come with these files, because (1) they are
+system-specific, and (2) they belong in a C library, not in a compiler.
+
+If the GNU C library supports your target machine, then you can get the
+header files from there (assuming you actually use the GNU library when
+you link your program).
+
+If your target machine comes with a C compiler, it probably comes with
+suitable header files also. If you make these files accessible from the host
+machine, the cross-compiler can use them also.
+
+Otherwise, you're on your own in finding header files to use when
+cross-compiling.
+
+When you have found suitable header files, put them in
+@file{/usr/local/@var{target}/include}, before building the cross
+compiler. Then installation will run fixincludes properly and install
+the corrected versions of the header files where the compiler will use
+them.
+
+Provide the header files before you build the cross-compiler, because
+the build stage actually runs the cross-compiler to produce parts of
+@file{libgcc.a}. (These are the parts that @emph{can} be compiled with
+GNU CC.) Some of them need suitable header files.
+
+Here's an example showing how to copy the header files from a target
+machine. On the target machine, do this:
+
+@example
+(cd /usr/include; tar cf - .) > tarfile
+@end example
+
+Then, on the host machine, do this:
+
+@example
+ftp @var{target-machine}
+lcd /usr/local/@var{target}/include
+get tarfile
+quit
+tar xf tarfile
+@end example
+
+@node Build Cross
+@subsection Actually Building the Cross-Compiler
+
+Now you can proceed just as for compiling a single-machine compiler
+through the step of building stage 1. If you have not provided some
+sort of @file{libgcc1.a}, then compilation will give up at the point
+where it needs that file, printing a suitable error message. If you
+do provide @file{libgcc1.a}, then building the compiler will automatically
+compile and link a test program called @file{cross-test}; if you get
+errors in the linking, it means that not all of the necessary routines
+in @file{libgcc1.a} are available.
+
+If you are making a cross-compiler for an embedded system, and there is
+no @file{stdio.h} header for it, then the compilation of @file{enquire}
+will probably fail. The job of @file{enquire} is to run on the target
+machine and figure out by experiment the nature of its floating point
+representation. @file{enquire} records its findings in the header file
+@file{float.h}. If you can't produce this file by running
+@file{enquire} on the target machine, then you will need to come up with
+a suitable @file{float.h} in some other way (or else, avoid using it in
+your programs).
+
+Do not try to build stage 2 for a cross-compiler. It doesn't work to
+rebuild GNU CC as a cross-compiler using the cross-compiler, because
+that would produce a program that runs on the target machine, not on the
+host. For example, if you compile a 386-to-68030 cross-compiler with
+itself, the result will not be right either for the 386 (because it was
+compiled into 68030 code) or for the 68030 (because it was configured
+for a 386 as the host). If you want to compile GNU CC into 68030 code,
+whether you compile it on a 68030 or with a cross-compiler on a 386, you
+must specify a 68030 as the host when you configure it.
+
+To install the cross-compiler, use @samp{make install}, as usual.
+
+@node Sun Install
+@section Installing GNU CC on the Sun
+@cindex Sun installation
+@cindex installing GNU CC on the Sun
+
+On Solaris (version 2.1), do not use the linker or other tools in
+@file{/usr/ucb} to build GNU CC. Use @code{/usr/ccs/bin}.
+
+Make sure the environment variable @code{FLOAT_OPTION} is not set when
+you compile @file{libgcc.a}. If this option were set to @code{f68881}
+when @file{libgcc.a} is compiled, the resulting code would demand to be
+linked with a special startup file and would not link properly without
+special pains.
+
+@cindex @code{alloca}, for SunOs
+There is a bug in @code{alloca} in certain versions of the Sun library.
+To avoid this bug, install the binaries of GNU CC that were compiled by
+GNU CC. They use @code{alloca} as a built-in function and never the one
+in the library.
+
+Some versions of the Sun compiler crash when compiling GNU CC. The
+problem is a segmentation fault in cpp. This problem seems to be due to
+the bulk of data in the environment variables. You may be able to avoid
+it by using the following command to compile GNU CC with Sun CC:
+
+@example
+make CC="TERMCAP=x OBJS=x LIBFUNCS=x STAGESTUFF=x cc"
+@end example
+
+@node VMS Install
+@section Installing GNU CC on VMS
+@cindex VMS installation
+@cindex installing GNU CC on VMS
+
+The VMS version of GNU CC is distributed in a backup saveset containing
+both source code and precompiled binaries.
+
+To install the @file{gcc} command so you can use the compiler easily, in
+the same manner as you use the VMS C compiler, you must install the VMS CLD
+file for GNU CC as follows:
+
+@enumerate
+@item
+Define the VMS logical names @samp{GNU_CC} and @samp{GNU_CC_INCLUDE}
+to point to the directories where the GNU CC executables
+(@file{gcc-cpp.exe}, @file{gcc-cc1.exe}, etc.) and the C include files are
+kept respectively. This should be done with the commands:@refill
+
+@smallexample
+$ assign /system /translation=concealed -
+ disk:[gcc.] gnu_cc
+$ assign /system /translation=concealed -
+ disk:[gcc.include.] gnu_cc_include
+@end smallexample
+
+@noindent
+with the appropriate disk and directory names. These commands can be
+placed in your system startup file so they will be executed whenever
+the machine is rebooted. You may, if you choose, do this via the
+@file{GCC_INSTALL.COM} script in the @file{[GCC]} directory.
+
+@item
+Install the @file{GCC} command with the command line:
+
+@smallexample
+$ set command /table=sys$common:[syslib]dcltables -
+ /output=sys$common:[syslib]dcltables gnu_cc:[000000]gcc
+$ install replace sys$common:[syslib]dcltables
+@end smallexample
+
+@item
+To install the help file, do the following:
+
+@smallexample
+$ library/help sys$library:helplib.hlb gcc.hlp
+@end smallexample
+
+@noindent
+Now you can invoke the compiler with a command like @samp{gcc /verbose
+file.c}, which is equivalent to the command @samp{gcc -v -c file.c} in
+Unix.
+@end enumerate
+
+If you wish to use GNU C++ you must first install GNU CC, and then
+perform the following steps:
+
+@enumerate
+@item
+Define the VMS logical name @samp{GNU_GXX_INCLUDE} to point to the
+directory where the preprocessor will search for the C++ header files.
+This can be done with the command:@refill
+
+@smallexample
+$ assign /system /translation=concealed -
+ disk:[gcc.gxx_include.] gnu_gxx_include
+@end smallexample
+
+@noindent
+with the appropriate disk and directory name. If you are going to be
+using libg++, this is where the libg++ install procedure will install
+the libg++ header files.
+
+@item
+Obtain the file @file{gcc-cc1plus.exe}, and place this in the same
+directory that @file{gcc-cc1.exe} is kept.
+
+The GNU C++ compiler can be invoked with a command like @samp{gcc /plus
+/verbose file.cc}, which is equivalent to the command @samp{g++ -v -c
+file.cc} in Unix.
+@end enumerate
+
+We try to put corresponding binaries and sources on the VMS distribution
+tape. But sometimes the binaries will be from an older version than the
+sources, because we don't always have time to update them. (Use the
+@samp{/version} option to determine the version number of the binaries and
+compare it with the source file @file{version.c} to tell whether this is
+so.) In this case, you should use the binaries you get to recompile the
+sources. If you must recompile, here is how:
+
+@enumerate
+@item
+Execute the command procedure @file{vmsconfig.com} to set up the files
+@file{tm.h}, @file{config.h}, @file{aux-output.c}, and @file{md.}, and
+to create files @file{tconfig.h} and @file{hconfig.h}. This procedure
+also creates several linker option files used by @file{make-cc1.com} and
+a data file used by @file{make-l2.com}.@refill
+
+@smallexample
+$ @@vmsconfig.com
+@end smallexample
+
+@item
+Setup the logical names and command tables as defined above. In
+addition, define the VMS logical name @samp{GNU_BISON} to point at the
+to the directories where the Bison executable is kept. This should be
+done with the command:@refill
+
+@smallexample
+$ assign /system /translation=concealed -
+ disk:[bison.] gnu_bison
+@end smallexample
+
+You may, if you choose, use the @file{INSTALL_BISON.COM} script in the
+@file{[BISON]} directory.
+
+@item
+Install the @samp{BISON} command with the command line:@refill
+
+@smallexample
+$ set command /table=sys$common:[syslib]dcltables -
+ /output=sys$common:[syslib]dcltables -
+ gnu_bison:[000000]bison
+$ install replace sys$common:[syslib]dcltables
+@end smallexample
+
+@item
+Type @samp{@@make-gcc} to recompile everything (alternatively, submit
+the file @file{make-gcc.com} to a batch queue). If you wish to build
+the GNU C++ compiler as well as the GNU CC compiler, you must first edit
+@file{make-gcc.com} and follow the instructions that appear in the
+comments.@refill
+
+@item
+In order to use GCC, you need a library of functions which GCC compiled code
+will call to perform certain tasks, and these functions are defined in the
+file @file{libgcc2.c}. To compile this you should use the command procedure
+@file{make-l2.com}, which will generate the library @file{libgcc2.olb}.
+@file{libgcc2.olb} should be built using the compiler built from
+the same distribution that @file{libgcc2.c} came from, and
+@file{make-gcc.com} will automatically do all of this for you.
+
+To install the library, use the following commands:@refill
+
+@smallexample
+$ library gnu_cc:[000000]gcclib/delete=(new,eprintf)
+$ library gnu_cc:[000000]gcclib/delete=L_*
+$ library libgcc2/extract=*/output=libgcc2.obj
+$ library gnu_cc:[000000]gcclib libgcc2.obj
+@end smallexample
+
+The first command simply removes old modules that will be replaced with
+modules from @file{libgcc2} under different module names. The modules
+@code{new} and @code{eprintf} may not actually be present in your
+@file{gcclib.olb}---if the VMS librarian complains about those modules
+not being present, simply ignore the message and continue on with the
+next command. The second command removes the modules that came from the
+previous version of the library @file{libgcc2.c}.
+
+Whenever you update the compiler on your system, you should also update the
+library with the above procedure.
+
+@item
+You may wish to build GCC in such a way that no files are written to the
+directory where the source files reside. An example would be the when
+the source files are on a read-only disk. In these cases, execute the
+following DCL commands (substituting your actual path names):
+
+@smallexample
+$ assign dua0:[gcc.build_dir.]/translation=concealed, -
+ dua1:[gcc.source_dir.]/translation=concealed gcc_build
+$ set default gcc_build:[000000]
+@end smallexample
+
+@noindent
+where the directory @file{dua1:[gcc.source_dir]} contains the source
+code, and the directory @file{dua0:[gcc.build_dir]} is meant to contain
+all of the generated object files and executables. Once you have done
+this, you can proceed building GCC as described above. (Keep in mind
+that @file{gcc_build} is a rooted logical name, and thus the device
+names in each element of the search list must be an actual physical
+device name rather than another rooted logical name).
+
+@item
+@strong{If you are building GNU CC with a previous version of GNU CC,
+you also should check to see that you have the newest version of the
+assembler}. In particular, GNU CC version 2 treats global constant
+variables slightly differently from GNU CC version 1, and GAS version
+1.38.1 does not have the patches required to work with GCC version 2.
+If you use GAS 1.38.1, then @code{extern const} variables will not have
+the read-only bit set, and the linker will generate warning messages
+about mismatched psect attributes for these variables. These warning
+messages are merely a nuisance, and can safely be ignored.
+
+If you are compiling with a version of GNU CC older than 1.33, specify
+@samp{/DEFINE=("inline=")} as an option in all the compilations. This
+requires editing all the @code{gcc} commands in @file{make-cc1.com}.
+(The older versions had problems supporting @code{inline}.) Once you
+have a working 1.33 or newer GNU CC, you can change this file back.
+
+@item
+If you want to build GNU CC with the VAX C compiler, you will need to
+make minor changes in @file{make-cccp.com} and @file{make-cc1.com}
+to choose alternate definitions of @code{CC}, @code{CFLAGS}, and
+@code{LIBS}. See comments in those files. However, you must
+also have a working version of the GNU assembler (GNU as, aka GAS) as
+it is used as the back-end for GNU CC to produce binary object modules
+and is not included in the GNU CC sources. GAS is also needed to
+compile @file{libgcc2} in order to build @file{gcclib} (see above);
+@file{make-l2.com} expects to be able to find it operational in
+@file{gnu_cc:[000000]gnu-as.exe}.
+
+To use GNU CC on VMS, you need the VMS driver programs
+@file{gcc.exe}, @file{gcc.com}, and @file{gcc.cld}. They are
+distributed with the VMS binaries (@file{gcc-vms}) rather than the
+GNU CC sources. GAS is also included in @file{gcc-vms}, as is Bison.
+
+Once you have successfully built GNU CC with VAX C, you should use the
+resulting compiler to rebuild itself. Before doing this, be sure to
+restore the @code{CC}, @code{CFLAGS}, and @code{LIBS} definitions in
+@file{make-cccp.com} and @file{make-cc1.com}. The second generation
+compiler will be able to take advantage of many optimizations that must
+be suppressed when building with other compilers.
+@end enumerate
+
+Under previous versions of GNU CC, the generated code would occasionally
+give strange results when linked with the sharable @file{VAXCRTL} library.
+Now this should work.
+
+Even with this version, however, GNU CC itself should not be linked with
+the sharable @file{VAXCRTL}. The version of @code{qsort} in
+@file{VAXCRTL} has a bug (known to be present in VMS versions V4.6
+through V5.5) which causes the compiler to fail.
+
+The executables are generated by @file{make-cc1.com} and
+@file{make-cccp.com} use the object library version of @file{VAXCRTL} in
+order to make use of the @code{qsort} routine in @file{gcclib.olb}. If
+you wish to link the compiler executables with the shareable image
+version of @file{VAXCRTL}, you should edit the file @file{tm.h} (created
+by @file{vmsconfig.com}) to define the macro @code{QSORT_WORKAROUND}.
+
+@code{QSORT_WORKAROUND} is always defined when GNU CC is compiled with
+VAX C, to avoid a problem in case @file{gcclib.olb} is not yet
+available.
+
+@node Collect2
+@section @code{collect2}
+
+Many target systems do not have support in the assembler and linker for
+``constructors''---initialization functions to be called before the
+official ``start'' of @code{main}. On such systems, GNU CC uses a
+utility called @code{collect2} to arrange to call these functions at
+start time.
+
+The program @code{collect2} works by linking the program once and
+looking through the linker output file for symbols with particular names
+indicating they are constructor functions. If it finds any, it
+creates a new temporary @samp{.c} file containing a table of them,
+compiles it, and links the program a second time including that file.
+
+@findex __main
+@cindex constructors, automatic calls
+The actual calls to the constructors are carried out by a subroutine
+called @code{__main}, which is called (automatically) at the beginning
+of the body of @code{main} (provided @code{main} was compiled with GNU
+CC). Calling @code{__main} is necessary, even when compiling C code, to
+allow linking C and C++ object code together. (If you use
+@samp{-nostdlib}, you get an unresolved reference to @code{__main},
+since it's defined in the standard GCC library. Include @samp{-lgcc} at
+the end of your compiler command line to resolve this reference.)
+
+The program @code{collect2} is installed as @code{ld} in the directory
+where the passes of the compiler are installed. When @code{collect2}
+needs to find the @emph{real} @code{ld}, it tries the following file
+names:
+
+@itemize @bullet
+@item
+@file{real-ld} in the directories listed in the compiler's search
+directories.
+
+@item
+@file{real-ld} in the directories listed in the environment variable
+@code{PATH}.
+
+@item
+The file specified in the @code{REAL_LD_FILE_NAME} configuration macro,
+if specified.
+
+@item
+@file{ld} in the compiler's search directories, except that
+@code{collect2} will not execute itself recursively.
+
+@item
+@file{ld} in @code{PATH}.
+@end itemize
+
+``The compiler's search directories'' means all the directories where
+@code{gcc} searches for passes of the compiler. This includes
+directories that you specify with @samp{-B}.
+
+Cross-compilers search a little differently:
+
+@itemize @bullet
+@item
+@file{real-ld} in the compiler's search directories.
+
+@item
+@file{@var{target}-real-ld} in @code{PATH}.
+
+@item
+The file specified in the @code{REAL_LD_FILE_NAME} configuration macro,
+if specified.
+
+@item
+@file{ld} in the compiler's search directories.
+
+@item
+@file{@var{target}-ld} in @code{PATH}.
+@end itemize
+
+@code{collect2} explicitly avoids running @code{ld} using the file name
+under which @code{collect2} itself was invoked. In fact, it remembers
+up a list of such names---in case one copy of @code{collect2} finds
+another copy (or version) of @code{collect2} installed as @code{ld} in a
+second place in the search path.
+
+@code{collect2} searches for the utilities @code{nm} and @code{strip}
+using the same algorithm as above for @code{ld}.
+
+@node Header Dirs
+@section Standard Header File Directories
+
+@code{GCC_INCLUDE_DIR} means the same thing for native and cross. It is
+where GNU CC stores its private include files, and also where GNU CC
+stores the fixed include files. A cross compiled GNU CC runs
+@code{fixincludes} on the header files in @file{$(tooldir)/include}.
+(If the cross compilation header files need to be fixed, they must be
+installed before GNU CC is built. If the cross compilation header files
+are already suitable for ANSI C and GNU CC, nothing special need be
+done).
+
+@code{GPLUS_INCLUDE_DIR} means the same thing for native and cross. It
+is where @code{g++} looks first for header files. @code{libg++}
+installs only target independent header files in that directory.
+
+@code{LOCAL_INCLUDE_DIR} is used only for a native compiler. It is
+normally @file{/usr/local/include}. GNU CC searches this directory so
+that users can install header files in @file{/usr/local/include}.
+
+@code{CROSS_INCLUDE_DIR} is used only for a cross compiler. GNU CC
+doesn't install anything there.
+
+@code{TOOL_INCLUDE_DIR} is used for both native and cross compilers. It
+is the place for other packages to install header files that GNU CC will
+use. For a cross-compiler, this is the equivalent of
+@file{/usr/include}. When you build a cross-compiler,
+@code{fixincludes} processes any header files in this directory.
diff --git a/gnu/usr.bin/cc/doc/invoke.texi b/gnu/usr.bin/cc/doc/invoke.texi
new file mode 100644
index 0000000..54534a0
--- /dev/null
+++ b/gnu/usr.bin/cc/doc/invoke.texi
@@ -0,0 +1,4214 @@
+@c Copyright (C) 1988, 1989, 1992, 1993, 1994 Free Software Foundation, Inc.
+@c This is part of the GCC manual.
+@c For copying conditions, see the file gcc.texi.
+
+@node Invoking GCC
+@chapter GNU CC Command Options
+@cindex GNU CC command options
+@cindex command options
+@cindex options, GNU CC command
+
+When you invoke GNU CC, it normally does preprocessing, compilation,
+assembly and linking. The ``overall options'' allow you to stop this
+process at an intermediate stage. For example, the @samp{-c} option
+says not to run the linker. Then the output consists of object files
+output by the assembler.
+
+Other options are passed on to one stage of processing. Some options
+control the preprocessor and others the compiler itself. Yet other
+options control the assembler and linker; most of these are not
+documented here, since you rarely need to use any of them.
+
+@cindex C compilation options
+Most of the command line options that you can use with GNU CC are useful
+for C programs; when an option is only useful with another language
+(usually C++), the explanation says so explicitly. If the description
+for a particular option does not mention a source language, you can use
+that option with all supported languages.
+
+@cindex C++ compilation options
+@xref{Invoking G++,,Compiling C++ Programs}, for a summary of special
+options for compiling C++ programs.
+
+@cindex grouping options
+@cindex options, grouping
+The @code{gcc} program accepts options and file names as operands. Many
+options have multiletter names; therefore multiple single-letter options
+may @emph{not} be grouped: @samp{-dr} is very different from @w{@samp{-d
+-r}}.
+
+@cindex order of options
+@cindex options, order
+You can mix options and other arguments. For the most part, the order
+you use doesn't matter. Order does matter when you use several options
+of the same kind; for example, if you specify @samp{-L} more than once,
+the directories are searched in the order specified.
+
+Many options have long names starting with @samp{-f} or with
+@samp{-W}---for example, @samp{-fforce-mem},
+@samp{-fstrength-reduce}, @samp{-Wformat} and so on. Most of
+these have both positive and negative forms; the negative form of
+@samp{-ffoo} would be @samp{-fno-foo}. This manual documents
+only one of these two forms, whichever one is not the default.
+
+@menu
+* Option Summary:: Brief list of all options, without explanations.
+* Overall Options:: Controlling the kind of output:
+ an executable, object files, assembler files,
+ or preprocessed source.
+* Invoking G++:: Compiling C++ programs.
+* C Dialect Options:: Controlling the variant of C language compiled.
+* C++ Dialect Options:: Variations on C++.
+* Warning Options:: How picky should the compiler be?
+* Debugging Options:: Symbol tables, measurements, and debugging dumps.
+* Optimize Options:: How much optimization?
+* Preprocessor Options:: Controlling header files and macro definitions.
+ Also, getting dependency information for Make.
+* Assembler Options:: Passing options to the assembler.
+* Link Options:: Specifying libraries and so on.
+* Directory Options:: Where to find header files and libraries.
+ Where to find the compiler executable files.
+* Target Options:: Running a cross-compiler, or an old version of GNU CC.
+* Submodel Options:: Specifying minor hardware or convention variations,
+ such as 68010 vs 68020.
+* Code Gen Options:: Specifying conventions for function calls, data layout
+ and register usage.
+* Environment Variables:: Env vars that affect GNU CC.
+* Running Protoize:: Automatically adding or removing function prototypes.
+@end menu
+
+@node Option Summary
+@section Option Summary
+
+Here is a summary of all the options, grouped by type. Explanations are
+in the following sections.
+
+@table @emph
+@item Overall Options
+@xref{Overall Options,,Options Controlling the Kind of Output}.
+@smallexample
+-c -S -E -o @var{file} -pipe -v -x @var{language}
+@end smallexample
+
+@item C Language Options
+@xref{C Dialect Options,,Options Controlling C Dialect}.
+@smallexample
+-ansi -fallow-single-precision -fcond-mismatch -fno-asm
+-fno-builtin -fsigned-bitfields -fsigned-char
+-funsigned-bitfields -funsigned-char -fwritable-strings
+-traditional -traditional-cpp -trigraphs
+@end smallexample
+
+@item C++ Language Options
+@xref{C++ Dialect Options,,Options Controlling C++ Dialect}.
+@smallexample
+-fall-virtual -fdollars-in-identifiers -felide-constructors
+-fenum-int-equiv -fexternal-templates -fhandle-signatures
+-fmemoize-lookups -fno-default-inline -fno-strict-prototype
+-fnonnull-objects -fthis-is-variable -nostdinc++
+-traditional +e@var{n}
+@end smallexample
+
+@item Warning Options
+@xref{Warning Options,,Options to Request or Suppress Warnings}.
+@smallexample
+-fsyntax-only -pedantic -pedantic-errors
+-w -W -Wall -Waggregate-return -Wbad-function-cast
+-Wcast-align -Wcast-qual -Wchar-subscript -Wcomment
+-Wconversion -Wenum-clash -Werror -Wformat
+-Wid-clash-@var{len} -Wimplicit -Wimport -Winline
+-Wlarger-than-@var{len} -Wmissing-declarations
+-Wmissing-prototypes -Wnested-externs
+-Wno-import -Woverloaded-virtual -Wparentheses
+-Wpointer-arith -Wredundant-decls -Wreorder -Wreturn-type -Wshadow
+-Wstrict-prototypes -Wswitch -Wsynth -Wtemplate-debugging
+-Wtraditional -Wtrigraphs -Wuninitialized -Wunused
+-Wwrite-strings
+@end smallexample
+
+@item Debugging Options
+@xref{Debugging Options,,Options for Debugging Your Program or GCC}.
+@smallexample
+-a -d@var{letters} -fpretend-float
+-g -g@var{level} -gcoff -gdwarf -gdwarf+
+-ggdb -gstabs -gstabs+ -gxcoff -gxcoff+
+-p -pg -print-file-name=@var{library} -print-libgcc-file-name
+-print-prog-name=@var{program} -save-temps
+@end smallexample
+
+@item Optimization Options
+@xref{Optimize Options,,Options that Control Optimization}.
+@smallexample
+-fcaller-saves -fcse-follow-jumps -fcse-skip-blocks
+-fdelayed-branch -fexpensive-optimizations
+-ffast-math -ffloat-store -fforce-addr -fforce-mem
+-finline-functions -fkeep-inline-functions
+-fno-default-inline -fno-defer-pop -fno-function-cse
+-fno-inline -fno-peephole -fomit-frame-pointer
+-frerun-cse-after-loop -fschedule-insns
+-fschedule-insns2 -fstrength-reduce -fthread-jumps
+-funroll-all-loops -funroll-loops
+-O -O0 -O1 -O2 -O3
+@end smallexample
+
+@item Preprocessor Options
+@xref{Preprocessor Options,,Options Controlling the Preprocessor}.
+@smallexample
+-A@var{question}(@var{answer}) -C -dD -dM -dN
+-D@var{macro}@r{[}=@var{defn}@r{]} -E -H
+-idirafter @var{dir}
+-include @var{file} -imacros @var{file}
+-iprefix @var{file} -iwithprefix @var{dir}
+-iwithprefixbefore @var{dir} -isystem @var{dir}
+-M -MD -MM -MMD -MG -nostdinc -P -trigraphs
+-undef -U@var{macro} -Wp,@var{option}
+@end smallexample
+
+@item Assembler Option
+@xref{Assembler Options,,Passing Options to the Assembler}.
+@smallexample
+-Wa,@var{option}
+@end smallexample
+
+@item Linker Options
+@xref{Link Options,,Options for Linking}.
+@smallexample
+@var{object-file-name}
+-l@var{library} -nostartfiles -nostdlib
+-s -static -shared -symbolic
+-Wl,@var{option} -Xlinker @var{option}
+-u @var{symbol}
+@end smallexample
+
+@item Directory Options
+@xref{Directory Options,,Options for Directory Search}.
+@smallexample
+-B@var{prefix} -I@var{dir} -I- -L@var{dir}
+@end smallexample
+
+@item Target Options
+@c I wrote this xref this way to avoid overfull hbox. -- rms
+@xref{Target Options}.
+@smallexample
+-b @var{machine} -V @var{version}
+@end smallexample
+
+@item Machine Dependent Options
+@xref{Submodel Options,,Hardware Models and Configurations}.
+@smallexample
+@emph{M680x0 Options}
+-m68000 -m68020 -m68020-40 -m68030 -m68040 -m68881
+-mbitfield -mc68000 -mc68020 -mfpa -mnobitfield
+-mrtd -mshort -msoft-float
+
+@emph{VAX Options}
+-mg -mgnu -munix
+
+@emph{SPARC Options}
+-mapp-regs -mcypress -mepilogue -mflat -mfpu -mhard-float
+-mhard-quad-float -mno-app-regs -mno-flat -mno-fpu
+-mno-epilogue -mno-unaligned-doubles
+-msoft-float -msoft-quad-float
+-msparclite -msupersparc -munaligned-doubles -mv8
+
+SPARC V9 compilers support the following options
+in addition to the above:
+
+-mmedlow -mmedany
+-mint32 -mint64 -mlong32 -mlong64
+-mno-stack-bias -mstack-bias
+
+@emph{Convex Options}
+-mc1 -mc2 -mc32 -mc34 -mc38
+-margcount -mnoargcount
+-mlong32 -mlong64
+-mvolatile-cache -mvolatile-nocache
+
+@emph{AMD29K Options}
+-m29000 -m29050 -mbw -mnbw -mdw -mndw
+-mlarge -mnormal -msmall
+-mkernel-registers -mno-reuse-arg-regs
+-mno-stack-check -mno-storem-bug
+-mreuse-arg-regs -msoft-float -mstack-check
+-mstorem-bug -muser-registers
+
+@emph{ARM Options}
+-mapcs -m2 -m3 -m6 -mbsd -mxopen -mno-symrename
+
+@emph{M88K Options}
+-m88000 -m88100 -m88110 -mbig-pic
+-mcheck-zero-division -mhandle-large-shift
+-midentify-revision -mno-check-zero-division
+-mno-ocs-debug-info -mno-ocs-frame-position
+-mno-optimize-arg-area -mno-serialize-volatile
+-mno-underscores -mocs-debug-info
+-mocs-frame-position -moptimize-arg-area
+-mserialize-volatile -mshort-data-@var{num} -msvr3
+-msvr4 -mtrap-large-shift -muse-div-instruction
+-mversion-03.00 -mwarn-passed-structs
+
+@emph{RS/6000 Options and PowerPC}
+-mcpu=@var{cpu type}
+-mpower -mno-power -mpower2 -pno-power2
+-mpowerpc -mno-powerpc
+-mpowerpc-gpopt -mno-powerpc-gpopt
+-mpowerpc-gfxopt -mno-powerpc-gfxopt
+-mnew-mnemonics -mno-new-mnemonics
+-mfull-toc -mminimal-toc -mno-fop-in-toc -mno-sum-in-toc
+
+@emph{RT Options}
+-mcall-lib-mul -mfp-arg-in-fpregs -mfp-arg-in-gregs
+-mfull-fp-blocks -mhc-struct-return -min-line-mul
+-mminimum-fp-blocks -mnohc-struct-return
+
+@emph{MIPS Options}
+-mabicalls -mcpu=@var{cpu type} -membedded-data
+-membedded-pic -mfp32 -mfp64 -mgas -mgp32 -mgp64
+-mgpopt -mhalf-pic -mhard-float -mint64 -mips1
+-mips2 -mips3 -mlong64 -mlong-calls -mmemcpy
+-mmips-as -mmips-tfile -mno-abicalls
+-mno-embedded-data -mno-embedded-pic
+-mno-gpopt -mno-long-calls
+-mno-memcpy -mno-mips-tfile -mno-rnames -mno-stats
+-mrnames -msoft-float
+-mstats -G @var{num} -nocpp
+
+@emph{i386 Options}
+-m486 -mno-486 -mno-fancy-math-387
+-mno-fp-ret-in-387 -mno-ieee-fp -mno-wide-multiply
+-mprofiler-epilogue -msoft-float -msvr3-shlib
+-mreg-alloc=@var{list}
+
+@emph{HPPA Options}
+-mdisable-fpregs -mdisable-indexing -mjump-in-delay
+-mgas -mlong-calls -mno-disable-fpregs -mno-disable-indexing
+-mno-gas -mno-jump-in-delay
+-mno-long-calls -mno-portable-runtime
+-mpa-risc-1-0 -mpa-risc-1-1 -mportable-runtime
+
+@emph{Intel 960 Options}
+-m@var{cpu type} -masm-compat -mclean-linkage
+-mcode-align -mcomplex-addr -mleaf-procedures
+-mic-compat -mic2.0-compat -mic3.0-compat
+-mintel-asm -mno-clean-linkage -mno-code-align
+-mno-complex-addr -mno-leaf-procedures
+-mno-old-align -mno-strict-align -mno-tail-call
+-mnumerics -mold-align -msoft-float -mstrict-align
+-mtail-call
+
+@emph{DEC Alpha Options}
+-mfp-regs -mno-fp-regs -mno-soft-float
+-msoft-float
+
+@emph{Clipper Options}
+-mc300 -mc400
+
+@emph{H8/300 Options}
+-mrelax -mh
+
+@emph{System V Options}
+-Qy -Qn -YP,@var{paths} -Ym,@var{dir}
+@end smallexample
+
+@item Code Generation Options
+@xref{Code Gen Options,,Options for Code Generation Conventions}.
+@smallexample
+-fcall-saved-@var{reg} -fcall-used-@var{reg}
+-ffixed-@var{reg} -finhibit-size-directive
+-fno-common -fno-ident -fno-gnu-linker
+-fpcc-struct-return -fpic -fPIC
+-freg-struct-return -fshared-data -fshort-enums
+-fshort-double -fvolatile -fvolatile-global
+-fverbose-asm +e0 +e1
+@end smallexample
+@end table
+
+@menu
+* Overall Options:: Controlling the kind of output:
+ an executable, object files, assembler files,
+ or preprocessed source.
+* C Dialect Options:: Controlling the variant of C language compiled.
+* C++ Dialect Options:: Variations on C++.
+* Warning Options:: How picky should the compiler be?
+* Debugging Options:: Symbol tables, measurements, and debugging dumps.
+* Optimize Options:: How much optimization?
+* Preprocessor Options:: Controlling header files and macro definitions.
+ Also, getting dependency information for Make.
+* Assembler Options:: Passing options to the assembler.
+* Link Options:: Specifying libraries and so on.
+* Directory Options:: Where to find header files and libraries.
+ Where to find the compiler executable files.
+* Target Options:: Running a cross-compiler, or an old version of GNU CC.
+@end menu
+
+@node Overall Options
+@section Options Controlling the Kind of Output
+
+Compilation can involve up to four stages: preprocessing, compilation
+proper, assembly and linking, always in that order. The first three
+stages apply to an individual source file, and end by producing an
+object file; linking combines all the object files (those newly
+compiled, and those specified as input) into an executable file.
+
+@cindex file name suffix
+For any given input file, the file name suffix determines what kind of
+compilation is done:
+
+@table @code
+@item @var{file}.c
+C source code which must be preprocessed.
+
+@item @var{file}.i
+C source code which should not be preprocessed.
+
+@item @var{file}.ii
+C++ source code which should not be preprocessed.
+
+@item @var{file}.m
+Objective-C source code. Note that you must link with the library
+@file{libobjc.a} to make an Objective-C program work.
+
+@item @var{file}.h
+C header file (not to be compiled or linked).
+
+@item @var{file}.cc
+@itemx @var{file}.cxx
+@itemx @var{file}.cpp
+@itemx @var{file}.C
+C++ source code which must be preprocessed. Note that in @samp{.cxx},
+the last two letters must both be literally @samp{x}. Likewise,
+@samp{.C} refers to a literal capital C.
+
+@item @var{file}.s
+Assembler code.
+
+@item @var{file}.S
+Assembler code which must be preprocessed.
+
+@item @var{other}
+An object file to be fed straight into linking.
+Any file name with no recognized suffix is treated this way.
+@end table
+
+You can specify the input language explicitly with the @samp{-x} option:
+
+@table @code
+@item -x @var{language}
+Specify explicitly the @var{language} for the following input files
+(rather than letting the compiler choose a default based on the file
+name suffix). This option applies to all following input files until
+the next @samp{-x} option. Possible values for @var{language} are:
+@example
+c objective-c c++
+c-header cpp-output c++-cpp-output
+assembler assembler-with-cpp
+@end example
+
+@item -x none
+Turn off any specification of a language, so that subsequent files are
+handled according to their file name suffixes (as they are if @samp{-x}
+has not been used at all).
+@end table
+
+If you only want some of the stages of compilation, you can use
+@samp{-x} (or filename suffixes) to tell @code{gcc} where to start, and
+one of the options @samp{-c}, @samp{-S}, or @samp{-E} to say where
+@code{gcc} is to stop. Note that some combinations (for example,
+@samp{-x cpp-output -E} instruct @code{gcc} to do nothing at all.
+
+@table @code
+@item -c
+Compile or assemble the source files, but do not link. The linking
+stage simply is not done. The ultimate output is in the form of an
+object file for each source file.
+
+By default, the object file name for a source file is made by replacing
+the suffix @samp{.c}, @samp{.i}, @samp{.s}, etc., with @samp{.o}.
+
+Unrecognized input files, not requiring compilation or assembly, are
+ignored.
+
+@item -S
+Stop after the stage of compilation proper; do not assemble. The output
+is in the form of an assembler code file for each non-assembler input
+file specified.
+
+By default, the assembler file name for a source file is made by
+replacing the suffix @samp{.c}, @samp{.i}, etc., with @samp{.s}.
+
+Input files that don't require compilation are ignored.
+
+@item -E
+Stop after the preprocessing stage; do not run the compiler proper. The
+output is in the form of preprocessed source code, which is sent to the
+standard output.
+
+Input files which don't require preprocessing are ignored.
+
+@cindex output file option
+@item -o @var{file}
+Place output in file @var{file}. This applies regardless to whatever
+sort of output is being produced, whether it be an executable file,
+an object file, an assembler file or preprocessed C code.
+
+Since only one output file can be specified, it does not make sense to
+use @samp{-o} when compiling more than one input file, unless you are
+producing an executable file as output.
+
+If @samp{-o} is not specified, the default is to put an executable file
+in @file{a.out}, the object file for @file{@var{source}.@var{suffix}} in
+@file{@var{source}.o}, its assembler file in @file{@var{source}.s}, and
+all preprocessed C source on standard output.@refill
+
+@item -v
+Print (on standard error output) the commands executed to run the stages
+of compilation. Also print the version number of the compiler driver
+program and of the preprocessor and the compiler proper.
+
+@item -pipe
+Use pipes rather than temporary files for communication between the
+various stages of compilation. This fails to work on some systems where
+the assembler is unable to read from a pipe; but the GNU assembler has
+no trouble.
+@end table
+
+@node Invoking G++
+@section Compiling C++ Programs
+
+@cindex suffixes for C++ source
+@cindex C++ source file suffixes
+C++ source files conventionally use one of the suffixes @samp{.C},
+@samp{.cc}, @samp{cpp}, or @samp{.cxx}; preprocessed C++ files use the
+suffix @samp{.ii}. GNU CC recognizes files with these names and
+compiles them as C++ programs even if you call the compiler the same way
+as for compiling C programs (usually with the name @code{gcc}).
+
+@findex g++
+@findex c++
+However, C++ programs often require class libraries as well as a
+compiler that understands the C++ language---and under some
+circumstances, you might want to compile programs from standard input,
+or otherwise without a suffix that flags them as C++ programs.
+@code{g++} is a program that calls GNU CC with the default language
+set to C++, and automatically specifies linking against the GNU class
+library libg++.
+@cindex @code{g++ 1.@var{xx}}
+@cindex @code{g++}, separate compiler
+@cindex @code{g++} older version
+@footnote{Prior to release 2 of the compiler,
+there was a separate @code{g++} compiler. That version was based on GNU
+CC, but not integrated with it. Versions of @code{g++} with a
+@samp{1.@var{xx}} version number---for example, @code{g++} version 1.37
+or 1.42---are much less reliable than the versions integrated with GCC
+2. Moreover, combining G++ @samp{1.@var{xx}} with a version 2 GCC will
+simply not work.} On many systems, the script @code{g++} is also
+installed with the name @code{c++}.
+
+@cindex invoking @code{g++}
+When you compile C++ programs, you may specify many of the same
+command-line options that you use for compiling programs in any
+language; or command-line options meaningful for C and related
+languages; or options that are meaningful only for C++ programs.
+@xref{C Dialect Options,,Options Controlling C Dialect}, for
+explanations of options for languages related to C.
+@xref{C++ Dialect Options,,Options Controlling C++ Dialect}, for
+explanations of options that are meaningful only for C++ programs.
+
+@node C Dialect Options
+@section Options Controlling C Dialect
+@cindex dialect options
+@cindex language dialect options
+@cindex options, dialect
+
+The following options control the dialect of C (or languages derived
+from C, such as C++ and Objective C) that the compiler accepts:
+
+@table @code
+@cindex ANSI support
+@item -ansi
+Support all ANSI standard C programs.
+
+This turns off certain features of GNU C that are incompatible with ANSI
+C, such as the @code{asm}, @code{inline} and @code{typeof} keywords, and
+predefined macros such as @code{unix} and @code{vax} that identify the
+type of system you are using. It also enables the undesirable and
+rarely used ANSI trigraph feature, and disallows @samp{$} as part of
+identifiers.
+
+The alternate keywords @code{__asm__}, @code{__extension__},
+@code{__inline__} and @code{__typeof__} continue to work despite
+@samp{-ansi}. You would not want to use them in an ANSI C program, of
+course, but it is useful to put them in header files that might be included
+in compilations done with @samp{-ansi}. Alternate predefined macros
+such as @code{__unix__} and @code{__vax__} are also available, with or
+without @samp{-ansi}.
+
+The @samp{-ansi} option does not cause non-ANSI programs to be
+rejected gratuitously. For that, @samp{-pedantic} is required in
+addition to @samp{-ansi}. @xref{Warning Options}.
+
+The macro @code{__STRICT_ANSI__} is predefined when the @samp{-ansi}
+option is used. Some header files may notice this macro and refrain
+from declaring certain functions or defining certain macros that the
+ANSI standard doesn't call for; this is to avoid interfering with any
+programs that might use these names for other things.
+
+The functions @code{alloca}, @code{abort}, @code{exit}, and
+@code{_exit} are not builtin functions when @samp{-ansi} is used.
+
+@item -fno-asm
+Do not recognize @code{asm}, @code{inline} or @code{typeof} as a
+keyword. These words may then be used as identifiers. You can use the
+keywords @code{__asm__}, @code{__inline__} and @code{__typeof__}
+instead. @samp{-ansi} implies @samp{-fno-asm}.
+
+@item -fno-builtin
+@cindex builtin functions
+@findex abort
+@findex abs
+@findex alloca
+@findex cos
+@findex exit
+@findex fabs
+@findex ffs
+@findex labs
+@findex memcmp
+@findex memcpy
+@findex sin
+@findex sqrt
+@findex strcmp
+@findex strcpy
+@findex strlen
+Don't recognize builtin functions that do not begin with two leading
+underscores. Currently, the functions affected include @code{abort},
+@code{abs}, @code{alloca}, @code{cos}, @code{exit}, @code{fabs},
+@code{ffs}, @code{labs}, @code{memcmp}, @code{memcpy}, @code{sin},
+@code{sqrt}, @code{strcmp}, @code{strcpy}, and @code{strlen}.
+
+GCC normally generates special code to handle certain builtin functions
+more efficiently; for instance, calls to @code{alloca} may become single
+instructions that adjust the stack directly, and calls to @code{memcpy}
+may become inline copy loops. The resulting code is often both smaller
+and faster, but since the function calls no longer appear as such, you
+cannot set a breakpoint on those calls, nor can you change the behavior
+of the functions by linking with a different library.
+
+The @samp{-ansi} option prevents @code{alloca} and @code{ffs} from being
+builtin functions, since these functions do not have an ANSI standard
+meaning.
+
+@item -trigraphs
+Support ANSI C trigraphs. You don't want to know about this
+brain-damage. The @samp{-ansi} option implies @samp{-trigraphs}.
+
+@cindex traditional C language
+@cindex C language, traditional
+@item -traditional
+Attempt to support some aspects of traditional C compilers.
+Specifically:
+
+@itemize @bullet
+@item
+All @code{extern} declarations take effect globally even if they
+are written inside of a function definition. This includes implicit
+declarations of functions.
+
+@item
+The newer keywords @code{typeof}, @code{inline}, @code{signed}, @code{const}
+and @code{volatile} are not recognized. (You can still use the
+alternative keywords such as @code{__typeof__}, @code{__inline__}, and
+so on.)
+
+@item
+Comparisons between pointers and integers are always allowed.
+
+@item
+Integer types @code{unsigned short} and @code{unsigned char} promote
+to @code{unsigned int}.
+
+@item
+Out-of-range floating point literals are not an error.
+
+@item
+Certain constructs which ANSI regards as a single invalid preprocessing
+number, such as @samp{0xe-0xd}, are treated as expressions instead.
+
+@item
+String ``constants'' are not necessarily constant; they are stored in
+writable space, and identical looking constants are allocated
+separately. (This is the same as the effect of
+@samp{-fwritable-strings}.)
+
+@cindex @code{longjmp} and automatic variables
+@item
+All automatic variables not declared @code{register} are preserved by
+@code{longjmp}. Ordinarily, GNU C follows ANSI C: automatic variables
+not declared @code{volatile} may be clobbered.
+
+@item
+@kindex \x
+@kindex \a
+@cindex escape sequences, traditional
+The character escape sequences @samp{\x} and @samp{\a} evaluate as the
+literal characters @samp{x} and @samp{a} respectively. Without
+@w{@samp{-traditional}}, @samp{\x} is a prefix for the hexadecimal
+representation of a character, and @samp{\a} produces a bell.
+
+@item
+In C++ programs, assignment to @code{this} is permitted with
+@samp{-traditional}. (The option @samp{-fthis-is-variable} also has
+this effect.)
+@end itemize
+
+You may wish to use @samp{-fno-builtin} as well as @samp{-traditional}
+if your program uses names that are normally GNU C builtin functions for
+other purposes of its own.
+
+You cannot use @samp{-traditional} if you include any header files that
+rely on ANSI C features. Some vendors are starting to ship systems with
+ANSI C header files and you cannot use @samp{-traditional} on such
+systems to compile files that include any system headers.
+
+@item
+In the preprocessor, comments convert to nothing at all, rather than
+to a space. This allows traditional token concatenation.
+
+@item
+In preprocessor directive, the @samp{#} symbol must appear as the first
+character of a line.
+
+@item
+In the preprocessor, macro arguments are recognized within string
+constants in a macro definition (and their values are stringified,
+though without additional quote marks, when they appear in such a
+context). The preprocessor always considers a string constant to end
+at a newline.
+
+@item
+@cindex detecting @w{@samp{-traditional}}
+The predefined macro @code{__STDC__} is not defined when you use
+@samp{-traditional}, but @code{__GNUC__} is (since the GNU extensions
+which @code{__GNUC__} indicates are not affected by
+@samp{-traditional}). If you need to write header files that work
+differently depending on whether @samp{-traditional} is in use, by
+testing both of these predefined macros you can distinguish four
+situations: GNU C, traditional GNU C, other ANSI C compilers, and other
+old C compilers. @xref{Standard Predefined,,Standard Predefined
+Macros,cpp.info,The C Preprocessor}, for more discussion of these and other
+predefined macros.
+
+@item
+@cindex string constants vs newline
+@cindex newline vs string constants
+The preprocessor considers a string constant to end at a newline (unless
+the newline is escaped with @samp{\}). (Without @w{@samp{-traditional}},
+string constants can contain the newline character as typed.)
+
+@item -traditional-cpp
+Attempt to support some aspects of traditional C preprocessors.
+This includes the last five items in the table immediately above,
+but none of the other effects of @samp{-traditional}.
+
+@item -fcond-mismatch
+Allow conditional expressions with mismatched types in the second and
+third arguments. The value of such an expression is void.
+
+@item -funsigned-char
+Let the type @code{char} be unsigned, like @code{unsigned char}.
+
+Each kind of machine has a default for what @code{char} should
+be. It is either like @code{unsigned char} by default or like
+@code{signed char} by default.
+
+Ideally, a portable program should always use @code{signed char} or
+@code{unsigned char} when it depends on the signedness of an object.
+But many programs have been written to use plain @code{char} and
+expect it to be signed, or expect it to be unsigned, depending on the
+machines they were written for. This option, and its inverse, let you
+make such a program work with the opposite default.
+
+The type @code{char} is always a distinct type from each of
+@code{signed char} or @code{unsigned char}, even though its behavior
+is always just like one of those two.
+
+@item -fsigned-char
+Let the type @code{char} be signed, like @code{signed char}.
+
+Note that this is equivalent to @samp{-fno-unsigned-char}, which is
+the negative form of @samp{-funsigned-char}. Likewise, the option
+@samp{-fno-signed-char} is equivalent to @samp{-funsigned-char}.
+
+@item -fsigned-bitfields
+@itemx -funsigned-bitfields
+@itemx -fno-signed-bitfields
+@itemx -fno-unsigned-bitfields
+These options control whether a bitfield is signed or unsigned, when the
+declaration does not use either @code{signed} or @code{unsigned}. By
+default, such a bitfield is signed, because this is consistent: the
+basic integer types such as @code{int} are signed types.
+
+However, when @samp{-traditional} is used, bitfields are all unsigned
+no matter what.
+
+@item -fwritable-strings
+Store string constants in the writable data segment and don't uniquize
+them. This is for compatibility with old programs which assume they can
+write into string constants. The option @samp{-traditional} also has
+this effect.
+
+Writing into string constants is a very bad idea; ``constants'' should
+be constant.
+
+@item -fallow-single-precision
+Do not promote single precision math operations to double precision,
+even when compiling with @samp{-traditional}.
+
+Traditional K&R C promotes all floating point operations to double
+precision, regardless of the sizes of the operands. On the
+architecture for which you are compiling, single precision may be faster
+than double precision. If you must use @samp{-traditional}, but want
+to use single precision operations when the operands are single
+precision, use this option. This option has no effect when compiling
+with ANSI or GNU C conventions (the default).
+
+@end table
+
+@node C++ Dialect Options
+@section Options Controlling C++ Dialect
+
+@cindex compiler options, C++
+@cindex C++ options, command line
+@cindex options, C++
+This section describes the command-line options that are only meaningful
+for C++ programs; but you can also use most of the GNU compiler options
+regardless of what language your program is in. For example, you
+might compile a file @code{firstClass.C} like this:
+
+@example
+g++ -g -felide-constructors -O -c firstClass.C
+@end example
+
+@noindent
+In this example, only @samp{-felide-constructors} is an option meant
+only for C++ programs; you can use the other options with any
+language supported by GNU CC.
+
+Here is a list of options that are @emph{only} for compiling C++ programs:
+
+@table @code
+@item -fno-access-control
+Turn off all access checking. This switch is mainly useful for working
+around bugs in the access control code.
+
+@item -fall-virtual
+Treat all possible member functions as virtual, implicitly.
+All member functions (except for constructor functions and @code{new} or
+@code{delete} member operators) are treated as virtual functions of the
+class where they appear.
+
+This does not mean that all calls to these member functions will be made
+through the internal table of virtual functions. Under some
+circumstances, the compiler can determine that a call to a given virtual
+function can be made directly; in these cases the calls are direct in
+any case.
+
+@item -fconserve-space
+Put uninitialized or runtime-initialized global variables into the
+common segment, as C does. This saves space in the executable at the
+cost of not diagnosing duplicate definitions. If your program
+mysteriously crashes after @code{main()} has completed, you may have an
+object that is being destroyed twice because two definitions were merged.
+
+@item -fdollars-in-identifiers
+Accept @samp{$} in identifiers. You can also explicitly prohibit use of
+@samp{$} with the option @samp{-fno-dollars-in-identifiers}. (GNU C++
+allows @samp{$} by default on some target systems but not others.)
+Traditional C allowed the character @samp{$} to form part of
+identifiers. However, ANSI C and C++ forbid @samp{$} in identifiers.
+
+@item -fenum-int-equiv
+Permit implicit conversion of @code{int} to enumeration types. Normally
+GNU C++ allows conversion of @code{enum} to @code{int}, but not the
+other way around.
+
+@item -fexternal-templates
+Cause template instantiations to obey @samp{#pragma interface} and
+@samp{implementation}; template instances are emitted or not according
+to the location of the template definition. @xref{Template
+Instantiation}, for more information.
+
+@item -falt-external-templates
+Similar to -fexternal-templates, but template instances are emitted or
+not according to the place where they are first instantiated.
+@xref{Template Instantiation}, for more information.
+
+@item -fno-implicit-templates
+Never emit code for templates which are instantiated implicitly (i.e. by
+use); only emit code for explicit instantiations. @xref{Template
+Instantiation}, for more information.
+
+@item -fhandle-signatures
+Recognize the @code{signature} and @code{sigof} keywords for specifying
+abstract types. The default (@samp{-fno-handle-signatures}) is not to
+recognize them. @xref{C++ Signatures, Type Abstraction using
+Signatures}.
+
+@item -fhuge-objects
+Support virtual function calls for objects that exceed the size
+representable by a @samp{short int}. Users should not use this flag by
+default; if you need to use it, the compiler will tell you so. If you
+compile any of your code with this flag, you must compile @emph{all} of
+your code with this flag (including libg++, if you use it).
+
+This flag is not useful when compiling with -fvtable-thunks.
+
+@item -fno-implement-inlines
+To save space, do not emit out-of-line copies of inline functions
+controlled by @samp{#pragma implementation}. This will cause linker
+errors if these functions are not inlined everywhere they are called.
+
+@item -fmemoize-lookups
+@itemx -fsave-memoized
+Use heuristics to compile faster. These heuristics are not enabled by
+default, since they are only effective for certain input files. Other
+input files compile more slowly.
+
+The first time the compiler must build a call to a member function (or
+reference to a data member), it must (1) determine whether the class
+implements member functions of that name; (2) resolve which member
+function to call (which involves figuring out what sorts of type
+conversions need to be made); and (3) check the visibility of the member
+function to the caller. All of this adds up to slower compilation.
+Normally, the second time a call is made to that member function (or
+reference to that data member), it must go through the same lengthy
+process again. This means that code like this:
+
+@smallexample
+cout << "This " << p << " has " << n << " legs.\n";
+@end smallexample
+
+@noindent
+makes six passes through all three steps. By using a software cache, a
+``hit'' significantly reduces this cost. Unfortunately, using the cache
+introduces another layer of mechanisms which must be implemented, and so
+incurs its own overhead. @samp{-fmemoize-lookups} enables the software
+cache.
+
+Because access privileges (visibility) to members and member functions
+may differ from one function context to the next, G++ may need to flush
+the cache. With the @samp{-fmemoize-lookups} flag, the cache is flushed
+after every function that is compiled. The @samp{-fsave-memoized} flag
+enables the same software cache, but when the compiler determines that
+the context of the last function compiled would yield the same access
+privileges of the next function to compile, it preserves the cache.
+This is most helpful when defining many member functions for the same
+class: with the exception of member functions which are friends of other
+classes, each member function has exactly the same access privileges as
+every other, and the cache need not be flushed.
+
+@item -fno-strict-prototype
+Treat a function declaration with no arguments, such as @samp{int foo
+();}, as C would treat it---as saying nothing about the number of
+arguments or their types. Normally, such a declaration in C++ means
+that the function @code{foo} takes no arguments.
+
+This option does not work with operator overloading, which places
+constraints on the parameter types.
+
+@item -fnonnull-objects
+Assume that objects reached through references are not null.
+
+Normally, GNU C++ makes conservative assumptions about objects reached
+through references. For example, the compiler must check that @code{a}
+is not null in code like the following:
+
+@example
+obj &a = g ();
+a.f (2);
+@end example
+
+Checking that references of this sort have non-null values requires
+extra code, however, and it is unnecessary for many programs. You can
+use @w{@samp{-fnonnull-objects}} to omit the checks for null, if your
+program doesn't require checking.
+
+This checking is currently only done for conversions to virtual base classes.
+
+@item -fthis-is-variable
+Permit assignment to @code{this}. The incorporation of user-defined
+free store management into C++ has made assignment to @samp{this} an
+anachronism. Therefore, by default it is invalid to assign to
+@code{this} within a class member function; that is, GNU C++ treats
+@samp{this} in a member function of class @code{X} as a non-lvalue of
+type @samp{X *}. However, for backwards compatibility, you can make it
+valid with @samp{-fthis-is-variable}.
+
+@item -fvtable-thunks
+Use @samp{thunks} to implement the virtual function dispatch table
+(@samp{vtable}). The traditional (cfront-style) approach to
+implementing vtables was to store a pointer to the function and two
+offsets for adjusting the @samp{this} pointer at the call site. Newer
+implementations store a single pointer to a @samp{thunk} function which
+does any necessary adjustment and then calls the target function.
+
+This option also enables a heuristic for controlling emission of
+vtables; if a class has any non-inline virtual functions, the vtable
+will be emitted in the translation unit containing the first one of
+those.
+
+@item -nostdinc++
+Do not search for header files in the standard directories specific to
+C++, but do still search the other standard directories. (This option
+is used when building libg++.)
+
+@item -traditional
+For C++ programs (in addition to the effects that apply to both C and
+C++), this has the same effect as @samp{-fthis-is-variable}.
+@xref{C Dialect Options,, Options Controlling C Dialect}.
+@end table
+
+In addition, these optimization, warning, and code generation options
+have meanings only for C++ programs:
+
+@table @code
+@item -fno-default-inline
+Do not assume @samp{inline} for functions defined inside a class scope.
+@xref{Optimize Options,,Options That Control Optimization}.
+
+@item -Wenum-clash
+@itemx -Woverloaded-virtual
+@itemx -Wtemplate-debugging
+Warnings that apply only to C++ programs. @xref{Warning
+Options,,Options to Request or Suppress Warnings}.
+
+@item +e@var{n}
+Control how virtual function definitions are used, in a fashion
+compatible with @code{cfront} 1.x. @xref{Code Gen Options,,Options for
+Code Generation Conventions}.
+@end table
+
+@node Warning Options
+@section Options to Request or Suppress Warnings
+@cindex options to control warnings
+@cindex warning messages
+@cindex messages, warning
+@cindex suppressing warnings
+
+Warnings are diagnostic messages that report constructions which
+are not inherently erroneous but which are risky or suggest there
+may have been an error.
+
+You can request many specific warnings with options beginning @samp{-W},
+for example @samp{-Wimplicit} to request warnings on implicit
+declarations. Each of these specific warning options also has a
+negative form beginning @samp{-Wno-} to turn off warnings;
+for example, @samp{-Wno-implicit}. This manual lists only one of the
+two forms, whichever is not the default.
+
+These options control the amount and kinds of warnings produced by GNU
+CC:
+
+@table @code
+@cindex syntax checking
+@item -fsyntax-only
+Check the code for syntax errors, but don't do anything beyond that.
+
+@item -w
+Inhibit all warning messages.
+
+@item -Wno-import
+Inhibit warning messages about the use of @samp{#import}.
+
+@item -pedantic
+Issue all the warnings demanded by strict ANSI standard C; reject
+all programs that use forbidden extensions.
+
+Valid ANSI standard C programs should compile properly with or without
+this option (though a rare few will require @samp{-ansi}). However,
+without this option, certain GNU extensions and traditional C features
+are supported as well. With this option, they are rejected.
+
+@samp{-pedantic} does not cause warning messages for use of the
+alternate keywords whose names begin and end with @samp{__}. Pedantic
+warnings are also disabled in the expression that follows
+@code{__extension__}. However, only system header files should use
+these escape routes; application programs should avoid them.
+@xref{Alternate Keywords}.
+
+This option is not intended to be @i{useful}; it exists only to satisfy
+pedants who would otherwise claim that GNU CC fails to support the ANSI
+standard.
+
+Some users try to use @samp{-pedantic} to check programs for strict ANSI
+C conformance. They soon find that it does not do quite what they want:
+it finds some non-ANSI practices, but not all---only those for which
+ANSI C @emph{requires} a diagnostic.
+
+A feature to report any failure to conform to ANSI C might be useful in
+some instances, but would require considerable additional work and would
+be quite different from @samp{-pedantic}. We recommend, rather, that
+users take advantage of the extensions of GNU C and disregard the
+limitations of other compilers. Aside from certain supercomputers and
+obsolete small machines, there is less and less reason ever to use any
+other C compiler other than for bootstrapping GNU CC.
+
+@item -pedantic-errors
+Like @samp{-pedantic}, except that errors are produced rather than
+warnings.
+
+@item -W
+Print extra warning messages for these events:
+
+@itemize @bullet
+@cindex @code{longjmp} warnings
+@item
+A nonvolatile automatic variable might be changed by a call to
+@code{longjmp}. These warnings as well are possible only in
+optimizing compilation.
+
+The compiler sees only the calls to @code{setjmp}. It cannot know
+where @code{longjmp} will be called; in fact, a signal handler could
+call it at any point in the code. As a result, you may get a warning
+even when there is in fact no problem because @code{longjmp} cannot
+in fact be called at the place which would cause a problem.
+
+@item
+A function can return either with or without a value. (Falling
+off the end of the function body is considered returning without
+a value.) For example, this function would evoke such a
+warning:
+
+@smallexample
+@group
+foo (a)
+@{
+ if (a > 0)
+ return a;
+@}
+@end group
+@end smallexample
+
+@item
+An expression-statement contains no side effects.
+
+@item
+An unsigned value is compared against zero with @samp{<} or @samp{<=}.
+
+@item
+A comparison like @samp{x<=y<=z} appears; this is equivalent to
+@samp{(x<=y ? 1 : 0) <= z}, which is a different interpretation from
+that of ordinary mathematical notation.
+
+@item
+Storage-class specifiers like @code{static} are not the first things in
+a declaration. According to the C Standard, this usage is obsolescent.
+
+@item
+An aggregate has a partly bracketed initializer.
+For example, the following code would evoke such a warning,
+because braces are missing around the initializer for @code{x.h}:
+
+@smallexample
+struct s @{ int f, g; @};
+struct t @{ struct s h; int i; @};
+struct t x = @{ 1, 2, 3 @};
+@end smallexample
+@end itemize
+
+@item -Wimplicit
+Warn whenever a function or parameter is implicitly declared.
+
+@item -Wreturn-type
+Warn whenever a function is defined with a return-type that defaults
+to @code{int}. Also warn about any @code{return} statement with no
+return-value in a function whose return-type is not @code{void}.
+
+@item -Wunused
+Warn whenever a variable is unused aside from its declaration,
+whenever a function is declared static but never defined, whenever a
+label is declared but not used, and whenever a statement computes a
+result that is explicitly not used.
+
+To suppress this warning for a local variable or expression, simply cast
+it to void. This will also work for file-scope variables, but if you
+want to mark them used at the point of definition, you can use this
+macro:
+
+@smallexample
+#define USE(var) \
+ static void *const use_##var = (&use_##var, &var, 0)
+
+USE (string);
+@end smallexample
+
+@item -Wswitch
+Warn whenever a @code{switch} statement has an index of enumeral type
+and lacks a @code{case} for one or more of the named codes of that
+enumeration. (The presence of a @code{default} label prevents this
+warning.) @code{case} labels outside the enumeration range also
+provoke warnings when this option is used.
+
+@item -Wcomment
+Warn whenever a comment-start sequence @samp{/*} appears in a comment.
+
+@item -Wtrigraphs
+Warn if any trigraphs are encountered (assuming they are enabled).
+
+@item -Wformat
+Check calls to @code{printf} and @code{scanf}, etc., to make sure that
+the arguments supplied have types appropriate to the format string
+specified.
+
+@item -Wchar-subscripts
+Warn if an array subscript has type @code{char}. This is a common cause
+of error, as programmers often forget that this type is signed on some
+machines.
+
+@item -Wuninitialized
+An automatic variable is used without first being initialized.
+
+These warnings are possible only in optimizing compilation,
+because they require data flow information that is computed only
+when optimizing. If you don't specify @samp{-O}, you simply won't
+get these warnings.
+
+These warnings occur only for variables that are candidates for
+register allocation. Therefore, they do not occur for a variable that
+is declared @code{volatile}, or whose address is taken, or whose size
+is other than 1, 2, 4 or 8 bytes. Also, they do not occur for
+structures, unions or arrays, even when they are in registers.
+
+Note that there may be no warning about a variable that is used only
+to compute a value that itself is never used, because such
+computations may be deleted by data flow analysis before the warnings
+are printed.
+
+These warnings are made optional because GNU CC is not smart
+enough to see all the reasons why the code might be correct
+despite appearing to have an error. Here is one example of how
+this can happen:
+
+@smallexample
+@{
+ int x;
+ switch (y)
+ @{
+ case 1: x = 1;
+ break;
+ case 2: x = 4;
+ break;
+ case 3: x = 5;
+ @}
+ foo (x);
+@}
+@end smallexample
+
+@noindent
+If the value of @code{y} is always 1, 2 or 3, then @code{x} is
+always initialized, but GNU CC doesn't know this. Here is
+another common case:
+
+@smallexample
+@{
+ int save_y;
+ if (change_y) save_y = y, y = new_y;
+ @dots{}
+ if (change_y) y = save_y;
+@}
+@end smallexample
+
+@noindent
+This has no bug because @code{save_y} is used only if it is set.
+
+Some spurious warnings can be avoided if you declare all the functions
+you use that never return as @code{noreturn}. @xref{Function
+Attributes}.
+
+@item -Wparentheses
+Warn if parentheses are omitted in certain contexts, such
+as when there is an assignment in a context where a truth value
+is expected, or when operators are nested whose precedence people
+often get confused about.
+
+@item -Wenum-clash
+@cindex enumeration clash warnings
+@cindex warning for enumeration conversions
+Warn about conversion between different enumeration types.
+(C++ only).
+
+@item -Wtemplate-debugging
+@cindex template debugging
+When using templates in a C++ program, warn if debugging is not yet
+fully available (C++ only).
+
+@item -Wreorder (C++ only)
+@cindex reordering, warning
+@cindex warning for reordering of member initializers
+Warn when the order of member initializers given in the code does not
+match the order in which they must be executed. For instance:
+
+@smallexample
+struct A @{
+ int i;
+ int j;
+ A(): j (0), i (1) @{ @}
+@};
+@end smallexample
+
+Here the compiler will warn that the member initializers for @samp{i}
+and @samp{j} will be rearranged to match the declaration order of the
+members.
+
+@item -Wall
+All of the above @samp{-W} options combined. These are all the
+options which pertain to usage that we recommend avoiding and that we
+believe is easy to avoid, even in conjunction with macros.
+@end table
+
+The remaining @samp{-W@dots{}} options are not implied by @samp{-Wall}
+because they warn about constructions that we consider reasonable to
+use, on occasion, in clean programs.
+
+@table @code
+@item -Wtraditional
+Warn about certain constructs that behave differently in traditional and
+ANSI C.
+
+@itemize @bullet
+@item
+Macro arguments occurring within string constants in the macro body.
+These would substitute the argument in traditional C, but are part of
+the constant in ANSI C.
+
+@item
+A function declared external in one block and then used after the end of
+the block.
+
+@item
+A @code{switch} statement has an operand of type @code{long}.
+@end itemize
+
+@item -Wshadow
+Warn whenever a local variable shadows another local variable.
+
+@item -Wid-clash-@var{len}
+Warn whenever two distinct identifiers match in the first @var{len}
+characters. This may help you prepare a program that will compile
+with certain obsolete, brain-damaged compilers.
+
+@item -Wlarger-than-@var{len}
+Warn whenever an object of larger than @var{len} bytes is defined.
+
+@item -Wpointer-arith
+Warn about anything that depends on the ``size of'' a function type or
+of @code{void}. GNU C assigns these types a size of 1, for
+convenience in calculations with @code{void *} pointers and pointers
+to functions.
+
+@item -Wbad-function-cast
+Warn whenever a function call is cast to a non-matching type.
+For example, warn if @code{int malloc()} is cast to @code{anything *}.
+
+@item -Wcast-qual
+Warn whenever a pointer is cast so as to remove a type qualifier from
+the target type. For example, warn if a @code{const char *} is cast
+to an ordinary @code{char *}.
+
+@item -Wcast-align
+Warn whenever a pointer is cast such that the required alignment of the
+target is increased. For example, warn if a @code{char *} is cast to
+an @code{int *} on machines where integers can only be accessed at
+two- or four-byte boundaries.
+
+@item -Wwrite-strings
+Give string constants the type @code{const char[@var{length}]} so that
+copying the address of one into a non-@code{const} @code{char *}
+pointer will get a warning. These warnings will help you find at
+compile time code that can try to write into a string constant, but
+only if you have been very careful about using @code{const} in
+declarations and prototypes. Otherwise, it will just be a nuisance;
+this is why we did not make @samp{-Wall} request these warnings.
+
+@item -Wconversion
+Warn if a prototype causes a type conversion that is different from what
+would happen to the same argument in the absence of a prototype. This
+includes conversions of fixed point to floating and vice versa, and
+conversions changing the width or signedness of a fixed point argument
+except when the same as the default promotion.
+
+Also, warn if a negative integer constant expression is implicitly
+converted to an unsigned type. For example, warn about the assignment
+@code{x = -1} if @code{x} is unsigned. But do not warn about explicit
+casts like @code{(unsigned) -1}.
+
+@item -Waggregate-return
+Warn if any functions that return structures or unions are defined or
+called. (In languages where you can return an array, this also elicits
+a warning.)
+
+@item -Wstrict-prototypes
+Warn if a function is declared or defined without specifying the
+argument types. (An old-style function definition is permitted without
+a warning if preceded by a declaration which specifies the argument
+types.)
+
+@item -Wmissing-prototypes
+Warn if a global function is defined without a previous prototype
+declaration. This warning is issued even if the definition itself
+provides a prototype. The aim is to detect global functions that fail
+to be declared in header files.
+
+@item -Wmissing-declarations
+Warn if a global function is defined without a previous declaration.
+Do so even if the definition itself provides a prototype.
+Use this option to detect global functions that are not declared in
+header files.
+
+@item -Wredundant-decls
+Warn if anything is declared more than once in the same scope, even in
+cases where multiple declaration is valid and changes nothing.
+
+@item -Wnested-externs
+Warn if an @code{extern} declaration is encountered within an function.
+
+@item -Winline
+Warn if a function can not be inlined, and either it was declared as inline,
+or else the @samp{-finline-functions} option was given.
+
+@item -Woverloaded-virtual
+@cindex overloaded virtual fn, warning
+@cindex warning for overloaded virtual fn
+Warn when a derived class function declaration may be an error in
+defining a virtual function (C++ only). In a derived class, the
+definitions of virtual functions must match the type signature of a
+virtual function declared in the base class. With this option, the
+compiler warns when you define a function with the same name as a
+virtual function, but with a type signature that does not match any
+declarations from the base class.
+
+@item -Wsynth (C++ only)
+@cindex warning for synthesized methods
+@cindex synthesized methods, warning
+Warn when g++'s synthesis behavior does not match that of cfront. For
+instance:
+
+@smallexample
+struct A @{
+ operator int ();
+ A& operator = (int);
+@};
+
+main ()
+@{
+ A a,b;
+ a = b;
+@}
+@end smallexample
+
+In this example, g++ will synthesize a default @samp{A& operator =
+(const A&);}, while cfront will use the user-defined @samp{operator =}.
+
+@item -Werror
+Make all warnings into errors.
+@end table
+
+@node Debugging Options
+@section Options for Debugging Your Program or GNU CC
+@cindex options, debugging
+@cindex debugging information options
+
+GNU CC has various special options that are used for debugging
+either your program or GCC:
+
+@table @code
+@item -g
+Produce debugging information in the operating system's native format
+(stabs, COFF, XCOFF, or DWARF). GDB can work with this debugging
+information.
+
+On most systems that use stabs format, @samp{-g} enables use of extra
+debugging information that only GDB can use; this extra information
+makes debugging work better in GDB but will probably make other debuggers
+crash or
+refuse to read the program. If you want to control for certain whether
+to generate the extra information, use @samp{-gstabs+}, @samp{-gstabs},
+@samp{-gxcoff+}, @samp{-gxcoff}, @samp{-gdwarf+}, or @samp{-gdwarf}
+(see below).
+
+Unlike most other C compilers, GNU CC allows you to use @samp{-g} with
+@samp{-O}. The shortcuts taken by optimized code may occasionally
+produce surprising results: some variables you declared may not exist
+at all; flow of control may briefly move where you did not expect it;
+some statements may not be executed because they compute constant
+results or their values were already at hand; some statements may
+execute in different places because they were moved out of loops.
+
+Nevertheless it proves possible to debug optimized output. This makes
+it reasonable to use the optimizer for programs that might have bugs.
+
+The following options are useful when GNU CC is generated with the
+capability for more than one debugging format.
+
+@item -ggdb
+Produce debugging information in the native format (if that is supported),
+including GDB extensions if at all possible.
+
+@item -gstabs
+Produce debugging information in stabs format (if that is supported),
+without GDB extensions. This is the format used by DBX on most BSD
+systems. On MIPS, Alpha and System V Release 4 systems this option
+produces stabs debugging output which is not understood by DBX or SDB.
+On System V Release 4 systems this option requires the GNU assembler.
+
+@item -gstabs+
+Produce debugging information in stabs format (if that is supported),
+using GNU extensions understood only by the GNU debugger (GDB). The
+use of these extensions is likely to make other debuggers crash or
+refuse to read the program.
+
+@item -gcoff
+Produce debugging information in COFF format (if that is supported).
+This is the format used by SDB on most System V systems prior to
+System V Release 4.
+
+@item -gxcoff
+Produce debugging information in XCOFF format (if that is supported).
+This is the format used by the DBX debugger on IBM RS/6000 systems.
+
+@item -gxcoff+
+Produce debugging information in XCOFF format (if that is supported),
+using GNU extensions understood only by the GNU debugger (GDB). The
+use of these extensions is likely to make other debuggers crash or
+refuse to read the program.
+
+@item -gdwarf
+Produce debugging information in DWARF format (if that is supported).
+This is the format used by SDB on most System V Release 4 systems.
+
+@item -gdwarf+
+Produce debugging information in DWARF format (if that is supported),
+using GNU extensions understood only by the GNU debugger (GDB). The
+use of these extensions is likely to make other debuggers crash or
+refuse to read the program.
+
+@item -g@var{level}
+@itemx -ggdb@var{level}
+@itemx -gstabs@var{level}
+@itemx -gcoff@var{level}
+@itemx -gxcoff@var{level}
+@itemx -gdwarf@var{level}
+Request debugging information and also use @var{level} to specify how
+much information. The default level is 2.
+
+Level 1 produces minimal information, enough for making backtraces in
+parts of the program that you don't plan to debug. This includes
+descriptions of functions and external variables, but no information
+about local variables and no line numbers.
+
+Level 3 includes extra information, such as all the macro definitions
+present in the program. Some debuggers support macro expansion when
+you use @samp{-g3}.
+
+@cindex @code{prof}
+@item -p
+Generate extra code to write profile information suitable for the
+analysis program @code{prof}. You must use this option when compiling
+the source files you want data about, and you must also use it when
+linking.
+
+@cindex @code{gprof}
+@item -pg
+Generate extra code to write profile information suitable for the
+analysis program @code{gprof}. You must use this option when compiling
+the source files you want data about, and you must also use it when
+linking.
+
+@cindex @code{tcov}
+@item -a
+Generate extra code to write profile information for basic blocks, which will
+record the number of times each basic block is executed, the basic block start
+address, and the function name containing the basic block. If @samp{-g} is
+used, the line number and filename of the start of the basic block will also be
+recorded. If not overridden by the machine description, the default action is
+to append to the text file @file{bb.out}.
+
+This data could be analyzed by a program like @code{tcov}. Note,
+however, that the format of the data is not what @code{tcov} expects.
+Eventually GNU @code{gprof} should be extended to process this data.
+
+@item -d@var{letters}
+Says to make debugging dumps during compilation at times specified by
+@var{letters}. This is used for debugging the compiler. The file names
+for most of the dumps are made by appending a word to the source file
+name (e.g. @file{foo.c.rtl} or @file{foo.c.jump}). Here are the
+possible letters for use in @var{letters}, and their meanings:
+
+@table @samp
+@item M
+Dump all macro definitions, at the end of preprocessing, and write no
+output.
+@item N
+Dump all macro names, at the end of preprocessing.
+@item D
+Dump all macro definitions, at the end of preprocessing, in addition to
+normal output.
+@item y
+Dump debugging information during parsing, to standard error.
+@item r
+Dump after RTL generation, to @file{@var{file}.rtl}.
+@item x
+Just generate RTL for a function instead of compiling it. Usually used
+with @samp{r}.
+@item j
+Dump after first jump optimization, to @file{@var{file}.jump}.
+@item s
+Dump after CSE (including the jump optimization that sometimes
+follows CSE), to @file{@var{file}.cse}.
+@item L
+Dump after loop optimization, to @file{@var{file}.loop}.
+@item t
+Dump after the second CSE pass (including the jump optimization that
+sometimes follows CSE), to @file{@var{file}.cse2}.
+@item f
+Dump after flow analysis, to @file{@var{file}.flow}.
+@item c
+Dump after instruction combination, to the file
+@file{@var{file}.combine}.
+@item S
+Dump after the first instruction scheduling pass, to
+@file{@var{file}.sched}.
+@item l
+Dump after local register allocation, to
+@file{@var{file}.lreg}.
+@item g
+Dump after global register allocation, to
+@file{@var{file}.greg}.
+@item R
+Dump after the second instruction scheduling pass, to
+@file{@var{file}.sched2}.
+@item J
+Dump after last jump optimization, to @file{@var{file}.jump2}.
+@item d
+Dump after delayed branch scheduling, to @file{@var{file}.dbr}.
+@item k
+Dump after conversion from registers to stack, to @file{@var{file}.stack}.
+@item a
+Produce all the dumps listed above.
+@item m
+Print statistics on memory usage, at the end of the run, to
+standard error.
+@item p
+Annotate the assembler output with a comment indicating which
+pattern and alternative was used.
+@end table
+
+@item -fpretend-float
+When running a cross-compiler, pretend that the target machine uses the
+same floating point format as the host machine. This causes incorrect
+output of the actual floating constants, but the actual instruction
+sequence will probably be the same as GNU CC would make when running on
+the target machine.
+
+@item -save-temps
+Store the usual ``temporary'' intermediate files permanently; place them
+in the current directory and name them based on the source file. Thus,
+compiling @file{foo.c} with @samp{-c -save-temps} would produce files
+@file{foo.i} and @file{foo.s}, as well as @file{foo.o}.
+
+@item -print-file-name=@var{library}
+Print the full absolute name of the library file @var{library} that
+would be used when linking---and don't do anything else. With this
+option, GNU CC does not compile or link anything; it just prints the
+file name.
+
+@item -print-prog-name=@var{program}
+Like @samp{-print-file-name}, but searches for a program such as @samp{cpp}.
+
+@item -print-libgcc-file-name
+Same as @samp{-print-file-name=libgcc.a}.
+
+This is useful when you use @samp{-nostdlib} but you do want to link
+with @file{libgcc.a}. You can do
+
+@example
+gcc -nostdlib @var{files}@dots{} `gcc -print-libgcc-file-name`
+@end example
+@end table
+
+@node Optimize Options
+@section Options That Control Optimization
+@cindex optimize options
+@cindex options, optimization
+
+These options control various sorts of optimizations:
+
+@table @code
+@item -O
+@itemx -O1
+Optimize. Optimizing compilation takes somewhat more time, and a lot
+more memory for a large function.
+
+Without @samp{-O}, the compiler's goal is to reduce the cost of
+compilation and to make debugging produce the expected results.
+Statements are independent: if you stop the program with a breakpoint
+between statements, you can then assign a new value to any variable or
+change the program counter to any other statement in the function and
+get exactly the results you would expect from the source code.
+
+Without @samp{-O}, the compiler only allocates variables declared
+@code{register} in registers. The resulting compiled code is a little
+worse than produced by PCC without @samp{-O}.
+
+With @samp{-O}, the compiler tries to reduce code size and execution
+time.
+
+When you specify @samp{-O}, the compiler turns on @samp{-fthread-jumps}
+and @samp{-fdefer-pop} on all machines. The compiler turns on
+@samp{-fdelayed-branch} on machines that have delay slots, and
+@samp{-fomit-frame-pointer} on machines that can support debugging even
+without a frame pointer. On some machines the compiler also turns
+on other flags.@refill
+
+@item -O2
+Optimize even more. GNU CC performs nearly all supported optimizations
+that do not involve a space-speed tradeoff. The compiler does not
+perform loop unrolling or function inlining when you specify @samp{-O2}.
+As compared to @samp{-O}, this option increases both compilation time
+and the performance of the generated code.
+
+@samp{-O2} turns on all optional optimizations except for loop unrolling
+and function inlining. It also turns on frame pointer elimination on
+machines where doing so does not interfer with debugging.
+
+@item -O3
+Optimize yet more. @samp{-O3} turns on all optimizations specified by
+@samp{-O2} and also turns on the @samp{inline-functions} option.
+
+@item -O0
+Do not optimize.
+
+If you use multiple @samp{-O} options, with or without level numbers,
+the last such option is the one that is effective.
+@end table
+
+Options of the form @samp{-f@var{flag}} specify machine-independent
+flags. Most flags have both positive and negative forms; the negative
+form of @samp{-ffoo} would be @samp{-fno-foo}. In the table below,
+only one of the forms is listed---the one which is not the default.
+You can figure out the other form by either removing @samp{no-} or
+adding it.
+
+@table @code
+@item -ffloat-store
+Do not store floating point variables in registers, and inhibit other
+options that might change whether a floating point value is taken from a
+register or memory.
+
+This option prevents undesirable excess precision on machines such as
+the 68000 where the floating registers (of the 68881) keep more
+precision than a @code{double} is supposed to have. For most programs,
+the excess precision does only good, but a few programs rely on the
+precise definition of IEEE floating point. Use @samp{-ffloat-store} for
+such programs.
+
+@item -fno-default-inline
+Do not make member functions inline by default merely because they are
+defined inside the class scope (C++ only). Otherwise, when you specify
+@w{@samp{-O}}, member functions defined inside class scope are compiled
+inline by default; i.e., you don't need to add @samp{inline} in front of
+the member function name.
+
+@item -fno-defer-pop
+Always pop the arguments to each function call as soon as that function
+returns. For machines which must pop arguments after a function call,
+the compiler normally lets arguments accumulate on the stack for several
+function calls and pops them all at once.
+
+@item -fforce-mem
+Force memory operands to be copied into registers before doing
+arithmetic on them. This may produce better code by making all
+memory references potential common subexpressions. When they are
+not common subexpressions, instruction combination should
+eliminate the separate register-load. I am interested in hearing
+about the difference this makes.
+
+@item -fforce-addr
+Force memory address constants to be copied into registers before
+doing arithmetic on them. This may produce better code just as
+@samp{-fforce-mem} may. I am interested in hearing about the
+difference this makes.
+
+@item -fomit-frame-pointer
+Don't keep the frame pointer in a register for functions that
+don't need one. This avoids the instructions to save, set up and
+restore frame pointers; it also makes an extra register available
+in many functions. @strong{It also makes debugging impossible on
+some machines.}
+
+@ifset INTERNALS
+On some machines, such as the Vax, this flag has no effect, because
+the standard calling sequence automatically handles the frame pointer
+and nothing is saved by pretending it doesn't exist. The
+machine-description macro @code{FRAME_POINTER_REQUIRED} controls
+whether a target machine supports this flag. @xref{Registers}.@refill
+@end ifset
+@ifclear INTERNALS
+On some machines, such as the Vax, this flag has no effect, because
+the standard calling sequence automatically handles the frame pointer
+and nothing is saved by pretending it doesn't exist. The
+machine-description macro @code{FRAME_POINTER_REQUIRED} controls
+whether a target machine supports this flag. @xref{Registers,,Register
+Usage, gcc.info, Using and Porting GCC}.@refill
+@end ifclear
+
+@item -fno-inline
+Don't pay attention to the @code{inline} keyword. Normally this option
+is used to keep the compiler from expanding any functions inline.
+Note that if you are not optimizing, no functions can be expanded inline.
+
+@item -finline-functions
+Integrate all simple functions into their callers. The compiler
+heuristically decides which functions are simple enough to be worth
+integrating in this way.
+
+If all calls to a given function are integrated, and the function is
+declared @code{static}, then the function is normally not output as
+assembler code in its own right.
+
+@item -fkeep-inline-functions
+Even if all calls to a given function are integrated, and the function
+is declared @code{static}, nevertheless output a separate run-time
+callable version of the function.
+
+@item -fno-function-cse
+Do not put function addresses in registers; make each instruction that
+calls a constant function contain the function's address explicitly.
+
+This option results in less efficient code, but some strange hacks
+that alter the assembler output may be confused by the optimizations
+performed when this option is not used.
+
+@item -ffast-math
+This option allows GCC to violate some ANSI or IEEE rules and/or
+specifications in the interest of optimizing code for speed. For
+example, it allows the compiler to assume arguments to the @code{sqrt}
+function are non-negative numbers and that no floating-point values
+are NaNs.
+
+This option should never be turned on by any @samp{-O} option since
+it can result in incorrect output for programs which depend on
+an exact implementation of IEEE or ANSI rules/specifications for
+math functions.
+@end table
+
+@c following causes underfulls.. they don't look great, but we deal.
+@c --mew 26jan93
+The following options control specific optimizations. The @samp{-O2}
+option turns on all of these optimizations except @samp{-funroll-loops}
+and @samp{-funroll-all-loops}. On most machines, the @samp{-O} option
+turns on the @samp{-fthread-jumps} and @samp{-fdelayed-branch} options,
+but specific machines may handle it differently.
+
+You can use the following flags in the rare cases when ``fine-tuning''
+of optimizations to be performed is desired.
+
+@table @code
+@item -fstrength-reduce
+Perform the optimizations of loop strength reduction and
+elimination of iteration variables.
+
+@item -fthread-jumps
+Perform optimizations where we check to see if a jump branches to a
+location where another comparison subsumed by the first is found. If
+so, the first branch is redirected to either the destination of the
+second branch or a point immediately following it, depending on whether
+the condition is known to be true or false.
+
+@item -fcse-follow-jumps
+In common subexpression elimination, scan through jump instructions
+when the target of the jump is not reached by any other path. For
+example, when CSE encounters an @code{if} statement with an
+@code{else} clause, CSE will follow the jump when the condition
+tested is false.
+
+@item -fcse-skip-blocks
+This is similar to @samp{-fcse-follow-jumps}, but causes CSE to
+follow jumps which conditionally skip over blocks. When CSE
+encounters a simple @code{if} statement with no else clause,
+@samp{-fcse-skip-blocks} causes CSE to follow the jump around the
+body of the @code{if}.
+
+@item -frerun-cse-after-loop
+Re-run common subexpression elimination after loop optimizations has been
+performed.
+
+@item -fexpensive-optimizations
+Perform a number of minor optimizations that are relatively expensive.
+
+@item -fdelayed-branch
+If supported for the target machine, attempt to reorder instructions
+to exploit instruction slots available after delayed branch
+instructions.
+
+@item -fschedule-insns
+If supported for the target machine, attempt to reorder instructions to
+eliminate execution stalls due to required data being unavailable. This
+helps machines that have slow floating point or memory load instructions
+by allowing other instructions to be issued until the result of the load
+or floating point instruction is required.
+
+@item -fschedule-insns2
+Similar to @samp{-fschedule-insns}, but requests an additional pass of
+instruction scheduling after register allocation has been done. This is
+especially useful on machines with a relatively small number of
+registers and where memory load instructions take more than one cycle.
+
+@item -fcaller-saves
+Enable values to be allocated in registers that will be clobbered by
+function calls, by emitting extra instructions to save and restore the
+registers around such calls. Such allocation is done only when it
+seems to result in better code than would otherwise be produced.
+
+This option is enabled by default on certain machines, usually those
+which have no call-preserved registers to use instead.
+
+@item -funroll-loops
+Perform the optimization of loop unrolling. This is only done for loops
+whose number of iterations can be determined at compile time or run time.
+@samp{-funroll-loop} implies both @samp{-fstrength-reduce} and
+@samp{-frerun-cse-after-loop}.
+
+@item -funroll-all-loops
+Perform the optimization of loop unrolling. This is done for all loops
+and usually makes programs run more slowly. @samp{-funroll-all-loops}
+implies @samp{-fstrength-reduce} as well as @samp{-frerun-cse-after-loop}.
+
+@item -fno-peephole
+Disable any machine-specific peephole optimizations.
+@end table
+
+@node Preprocessor Options
+@section Options Controlling the Preprocessor
+@cindex preprocessor options
+@cindex options, preprocessor
+
+These options control the C preprocessor, which is run on each C source
+file before actual compilation.
+
+If you use the @samp{-E} option, nothing is done except preprocessing.
+Some of these options make sense only together with @samp{-E} because
+they cause the preprocessor output to be unsuitable for actual
+compilation.
+
+@table @code
+@item -include @var{file}
+Process @var{file} as input before processing the regular input file.
+In effect, the contents of @var{file} are compiled first. Any @samp{-D}
+and @samp{-U} options on the command line are always processed before
+@samp{-include @var{file}}, regardless of the order in which they are
+written. All the @samp{-include} and @samp{-imacros} options are
+processed in the order in which they are written.
+
+@item -imacros @var{file}
+Process @var{file} as input, discarding the resulting output, before
+processing the regular input file. Because the output generated from
+@var{file} is discarded, the only effect of @samp{-imacros @var{file}}
+is to make the macros defined in @var{file} available for use in the
+main input.
+
+Any @samp{-D} and @samp{-U} options on the command line are always
+processed before @samp{-imacros @var{file}}, regardless of the order in
+which they are written. All the @samp{-include} and @samp{-imacros}
+options are processed in the order in which they are written.
+
+@item -idirafter @var{dir}
+@cindex second include path
+Add the directory @var{dir} to the second include path. The directories
+on the second include path are searched when a header file is not found
+in any of the directories in the main include path (the one that
+@samp{-I} adds to).
+
+@item -iprefix @var{prefix}
+Specify @var{prefix} as the prefix for subsequent @samp{-iwithprefix}
+options.
+
+@item -iwithprefix @var{dir}
+Add a directory to the second include path. The directory's name is
+made by concatenating @var{prefix} and @var{dir}, where @var{prefix} was
+specified previously with @samp{-iprefix}. If you have not specified a
+prefix yet, the directory containing the installed passes of the
+compiler is used as the default.
+
+@item -iwithprefixbefore @var{dir}
+Add a directory to the main include path. The directory's name is made
+by concatenating @var{prefix} and @var{dir}, as in the case of
+@samp{-iwithprefix}.
+
+@item -isystem @var{dir}
+Add a directory to the beginning of the second include path, marking it
+as a system directory, so that it gets the same special treatment as
+is applied to the standard system directories.
+
+@item -nostdinc
+Do not search the standard system directories for header files. Only
+the directories you have specified with @samp{-I} options (and the
+current directory, if appropriate) are searched. @xref{Directory
+Options}, for information on @samp{-I}.
+
+By using both @samp{-nostdinc} and @samp{-I-}, you can limit the include-file
+search path to only those directories you specify explicitly.
+
+@item -undef
+Do not predefine any nonstandard macros. (Including architecture flags).
+
+@item -E
+Run only the C preprocessor. Preprocess all the C source files
+specified and output the results to standard output or to the
+specified output file.
+
+@item -C
+Tell the preprocessor not to discard comments. Used with the
+@samp{-E} option.
+
+@item -P
+Tell the preprocessor not to generate @samp{#line} commands.
+Used with the @samp{-E} option.
+
+@cindex make
+@cindex dependencies, make
+@item -M
+Tell the preprocessor to output a rule suitable for @code{make}
+describing the dependencies of each object file. For each source file,
+the preprocessor outputs one @code{make}-rule whose target is the object
+file name for that source file and whose dependencies are all the
+@code{#include} header files it uses. This rule may be a single line or
+may be continued with @samp{\}-newline if it is long. The list of rules
+is printed on standard output instead of the preprocessed C program.
+
+@samp{-M} implies @samp{-E}.
+
+Another way to specify output of a @code{make} rule is by setting
+the environment variable @code{DEPENDENCIES_OUTPUT} (@pxref{Environment
+Variables}).
+
+@item -MM
+Like @samp{-M} but the output mentions only the user header files
+included with @samp{#include "@var{file}"}. System header files
+included with @samp{#include <@var{file}>} are omitted.
+
+@item -MD
+Like @samp{-M} but the dependency information is written to a file made by
+replacing ".c" with ".d" at the end of the input file names.
+This is in addition to compiling the file as specified---@samp{-MD} does
+not inhibit ordinary compilation the way @samp{-M} does.
+
+In Mach, you can use the utility @code{md} to merge multiple dependency
+files into a single dependency file suitable for using with the @samp{make}
+command.
+
+@item -MMD
+Like @samp{-MD} except mention only user header files, not system
+header files.
+
+@item -MG
+Treat missing header files as generated files and assume they live in the
+same directory as the source file. If you specify @samp{-MG}, you
+must also specify either @samp{-M} or @samp{-MM}. @samp{-MG} is not
+supported with @samp{-MD} or @samp{-MMD}.
+
+@item -H
+Print the name of each header file used, in addition to other normal
+activities.
+
+@item -A@var{question}(@var{answer})
+Assert the answer @var{answer} for @var{question}, in case it is tested
+with a preprocessor conditional such as @samp{#if
+#@var{question}(@var{answer})}. @samp{-A-} disables the standard
+assertions that normally describe the target machine.
+
+@item -D@var{macro}
+Define macro @var{macro} with the string @samp{1} as its definition.
+
+@item -D@var{macro}=@var{defn}
+Define macro @var{macro} as @var{defn}. All instances of @samp{-D} on
+the command line are processed before any @samp{-U} options.
+
+@item -U@var{macro}
+Undefine macro @var{macro}. @samp{-U} options are evaluated after all
+@samp{-D} options, but before any @samp{-include} and @samp{-imacros}
+options.
+
+@item -dM
+Tell the preprocessor to output only a list of the macro definitions
+that are in effect at the end of preprocessing. Used with the @samp{-E}
+option.
+
+@item -dD
+Tell the preprocessing to pass all macro definitions into the output, in
+their proper sequence in the rest of the output.
+
+@item -dN
+Like @samp{-dD} except that the macro arguments and contents are omitted.
+Only @samp{#define @var{name}} is included in the output.
+
+@item -trigraphs
+Support ANSI C trigraphs. The @samp{-ansi} option also has this effect.
+
+@item -Wp,@var{option}
+Pass @var{option} as an option to the preprocessor. If @var{option}
+contains commas, it is split into multiple options at the commas.
+@end table
+
+@node Assembler Options
+@section Passing Options to the Assembler
+
+@c prevent bad page break with this line
+You can pass options to the assembler.
+
+@table @code
+@item -Wa,@var{option}
+Pass @var{option} as an option to the assembler. If @var{option}
+contains commas, it is split into multiple options at the commas.
+@end table
+
+@node Link Options
+@section Options for Linking
+@cindex link options
+@cindex options, linking
+
+These options come into play when the compiler links object files into
+an executable output file. They are meaningless if the compiler is
+not doing a link step.
+
+@table @code
+@cindex file names
+@item @var{object-file-name}
+A file name that does not end in a special recognized suffix is
+considered to name an object file or library. (Object files are
+distinguished from libraries by the linker according to the file
+contents.) If linking is done, these object files are used as input
+to the linker.
+
+@item -c
+@itemx -S
+@itemx -E
+If any of these options is used, then the linker is not run, and
+object file names should not be used as arguments. @xref{Overall
+Options}.
+
+@cindex Libraries
+@item -l@var{library}
+Search the library named @var{library} when linking.
+
+It makes a difference where in the command you write this option; the
+linker searches processes libraries and object files in the order they
+are specified. Thus, @samp{foo.o -lz bar.o} searches library @samp{z}
+after file @file{foo.o} but before @file{bar.o}. If @file{bar.o} refers
+to functions in @samp{z}, those functions may not be loaded.
+
+The linker searches a standard list of directories for the library,
+which is actually a file named @file{lib@var{library}.a}. The linker
+then uses this file as if it had been specified precisely by name.
+
+The directories searched include several standard system directories
+plus any that you specify with @samp{-L}.
+
+Normally the files found this way are library files---archive files
+whose members are object files. The linker handles an archive file by
+scanning through it for members which define symbols that have so far
+been referenced but not defined. But if the file that is found is an
+ordinary object file, it is linked in the usual fashion. The only
+difference between using an @samp{-l} option and specifying a file name
+is that @samp{-l} surrounds @var{library} with @samp{lib} and @samp{.a}
+and searches several directories.
+
+@item -lobjc
+You need this special case of the @samp{-l} option in order to
+link an Objective C program.
+
+@item -nostartfiles
+Do not use the standard system startup files when linking.
+The standard libraries are used normally.
+
+@item -nostdlib
+Do not use the standard system libraries and startup files when linking.
+Only the files you specify will be passed to the linker.
+
+@cindex @code{-lgcc}, use with @code{-nostdlib}
+@cindex @code{-nostdlib} and unresolved references
+@cindex unresolved references and @code{-nostdlib}
+One of the standard libraries bypassed by @samp{-nostdlib} is
+@file{libgcc.a}, a library of internal subroutines that GNU CC uses to
+overcome shortcomings of particular machines, or special needs for some
+languages.
+@ifset INTERNALS
+(@xref{Interface,,Interfacing to GNU CC Output}, for more discussion of
+@file{libgcc.a}.)
+@end ifset
+@ifclear INTERNALS
+(@xref{Interface,,Interfacing to GNU CC Output,gcc.info,Porting GNU CC},
+for more discussion of @file{libgcc.a}.)
+@end ifclear
+In most cases, you need @file{libgcc.a} even when you want to avoid
+other standard libraries. In other words, when you specify
+@samp{-nostdlib} you should usually specify @samp{-lgcc} as well. This
+ensures that you have no unresolved references to internal GNU CC
+library subroutines. (For example, @samp{__main}, used to ensure C++
+constructors will be called; @pxref{Collect2,,@code{collect2}}.)
+
+@item -s
+Remove all symbol table and relocation information from the executable.
+
+@item -static
+On systems that support dynamic linking, this prevents linking with the shared
+libraries. On other systems, this
+option has no effect.
+
+@item -shared
+Produce a shared object which can then be linked with other objects to
+form an executable. Only a few systems support this option.
+
+@item -symbolic
+Bind references to global symbols when building a shared object. Warn
+about any unresolved references (unless overridden by the link editor
+option @samp{-Xlinker -z -Xlinker defs}). Only a few systems support
+this option.
+
+@item -Xlinker @var{option}
+Pass @var{option} as an option to the linker. You can use this to
+supply system-specific linker options which GNU CC does not know how to
+recognize.
+
+If you want to pass an option that takes an argument, you must use
+@samp{-Xlinker} twice, once for the option and once for the argument.
+For example, to pass @samp{-assert definitions}, you must write
+@samp{-Xlinker -assert -Xlinker definitions}. It does not work to write
+@samp{-Xlinker "-assert definitions"}, because this passes the entire
+string as a single argument, which is not what the linker expects.
+
+@item -Wl,@var{option}
+Pass @var{option} as an option to the linker. If @var{option} contains
+commas, it is split into multiple options at the commas.
+
+@item -u @var{symbol}
+Pretend the symbol @var{symbol} is undefined, to force linking of
+library modules to define it. You can use @samp{-u} multiple times with
+different symbols to force loading of additional library modules.
+@end table
+
+@node Directory Options
+@section Options for Directory Search
+@cindex directory options
+@cindex options, directory search
+@cindex search path
+
+These options specify directories to search for header files, for
+libraries and for parts of the compiler:
+
+@table @code
+@item -I@var{dir}
+Append directory @var{dir} to the list of directories searched for
+include files.
+
+@item -I-
+Any directories you specify with @samp{-I} options before the @samp{-I-}
+option are searched only for the case of @samp{#include "@var{file}"};
+they are not searched for @samp{#include <@var{file}>}.
+
+If additional directories are specified with @samp{-I} options after
+the @samp{-I-}, these directories are searched for all @samp{#include}
+directives. (Ordinarily @emph{all} @samp{-I} directories are used
+this way.)
+
+In addition, the @samp{-I-} option inhibits the use of the current
+directory (where the current input file came from) as the first search
+directory for @samp{#include "@var{file}"}. There is no way to
+override this effect of @samp{-I-}. With @samp{-I.} you can specify
+searching the directory which was current when the compiler was
+invoked. That is not exactly the same as what the preprocessor does
+by default, but it is often satisfactory.
+
+@samp{-I-} does not inhibit the use of the standard system directories
+for header files. Thus, @samp{-I-} and @samp{-nostdinc} are
+independent.
+
+@item -L@var{dir}
+Add directory @var{dir} to the list of directories to be searched
+for @samp{-l}.
+
+@item -B@var{prefix}
+This option specifies where to find the executables, libraries,
+include files, and data files of the compiler itself.
+
+The compiler driver program runs one or more of the subprograms
+@file{cpp}, @file{cc1}, @file{as} and @file{ld}. It tries
+@var{prefix} as a prefix for each program it tries to run, both with and
+without @samp{@var{machine}/@var{version}/} (@pxref{Target Options}).
+
+For each subprogram to be run, the compiler driver first tries the
+@samp{-B} prefix, if any. If that name is not found, or if @samp{-B}
+was not specified, the driver tries two standard prefixes, which are
+@file{/usr/lib/gcc/} and @file{/usr/local/lib/gcc-lib/}. If neither of
+those results in a file name that is found, the unmodified program
+name is searched for using the directories specified in your
+@samp{PATH} environment variable.
+
+@samp{-B} prefixes that effectively specify directory names also apply
+to libraries in the linker, because the compiler translates these
+options into @samp{-L} options for the linker. They also apply to
+includes files in the preprocessor, because the compiler translates these
+options into @samp{-isystem} options for the preprocessor. In this case,
+the compiler appends @samp{include} to the prefix.
+
+The run-time support file @file{libgcc.a} can also be searched for using
+the @samp{-B} prefix, if needed. If it is not found there, the two
+standard prefixes above are tried, and that is all. The file is left
+out of the link if it is not found by those means.
+
+Another way to specify a prefix much like the @samp{-B} prefix is to use
+the environment variable @code{GCC_EXEC_PREFIX}. @xref{Environment
+Variables}.
+@end table
+
+@node Target Options
+@section Specifying Target Machine and Compiler Version
+@cindex target options
+@cindex cross compiling
+@cindex specifying machine version
+@cindex specifying compiler version and target machine
+@cindex compiler version, specifying
+@cindex target machine, specifying
+
+By default, GNU CC compiles code for the same type of machine that you
+are using. However, it can also be installed as a cross-compiler, to
+compile for some other type of machine. In fact, several different
+configurations of GNU CC, for different target machines, can be
+installed side by side. Then you specify which one to use with the
+@samp{-b} option.
+
+In addition, older and newer versions of GNU CC can be installed side
+by side. One of them (probably the newest) will be the default, but
+you may sometimes wish to use another.
+
+@table @code
+@item -b @var{machine}
+The argument @var{machine} specifies the target machine for compilation.
+This is useful when you have installed GNU CC as a cross-compiler.
+
+The value to use for @var{machine} is the same as was specified as the
+machine type when configuring GNU CC as a cross-compiler. For
+example, if a cross-compiler was configured with @samp{configure
+i386v}, meaning to compile for an 80386 running System V, then you
+would specify @samp{-b i386v} to run that cross compiler.
+
+When you do not specify @samp{-b}, it normally means to compile for
+the same type of machine that you are using.
+
+@item -V @var{version}
+The argument @var{version} specifies which version of GNU CC to run.
+This is useful when multiple versions are installed. For example,
+@var{version} might be @samp{2.0}, meaning to run GNU CC version 2.0.
+
+The default version, when you do not specify @samp{-V}, is controlled
+by the way GNU CC is installed. Normally, it will be a version that
+is recommended for general use.
+@end table
+
+The @samp{-b} and @samp{-V} options actually work by controlling part of
+the file name used for the executable files and libraries used for
+compilation. A given version of GNU CC, for a given target machine, is
+normally kept in the directory @file{/usr/local/lib/gcc-lib/@var{machine}/@var{version}}.@refill
+
+Thus, sites can customize the effect of @samp{-b} or @samp{-V} either by
+changing the names of these directories or adding alternate names (or
+symbolic links). If in directory @file{/usr/local/lib/gcc-lib/} the
+file @file{80386} is a link to the file @file{i386v}, then @samp{-b
+80386} becomes an alias for @samp{-b i386v}.
+
+In one respect, the @samp{-b} or @samp{-V} do not completely change
+to a different compiler: the top-level driver program @code{gcc}
+that you originally invoked continues to run and invoke the other
+executables (preprocessor, compiler per se, assembler and linker)
+that do the real work. However, since no real work is done in the
+driver program, it usually does not matter that the driver program
+in use is not the one for the specified target and version.
+
+The only way that the driver program depends on the target machine is
+in the parsing and handling of special machine-specific options.
+However, this is controlled by a file which is found, along with the
+other executables, in the directory for the specified version and
+target machine. As a result, a single installed driver program adapts
+to any specified target machine and compiler version.
+
+The driver program executable does control one significant thing,
+however: the default version and target machine. Therefore, you can
+install different instances of the driver program, compiled for
+different targets or versions, under different names.
+
+For example, if the driver for version 2.0 is installed as @code{ogcc}
+and that for version 2.1 is installed as @code{gcc}, then the command
+@code{gcc} will use version 2.1 by default, while @code{ogcc} will use
+2.0 by default. However, you can choose either version with either
+command with the @samp{-V} option.
+
+@node Submodel Options
+@section Hardware Models and Configurations
+@cindex submodel options
+@cindex specifying hardware config
+@cindex hardware models and configurations, specifying
+@cindex machine dependent options
+
+Earlier we discussed the standard option @samp{-b} which chooses among
+different installed compilers for completely different target
+machines, such as Vax vs. 68000 vs. 80386.
+
+In addition, each of these target machine types can have its own
+special options, starting with @samp{-m}, to choose among various
+hardware models or configurations---for example, 68010 vs 68020,
+floating coprocessor or none. A single installed version of the
+compiler can compile for any model or configuration, according to the
+options specified.
+
+Some configurations of the compiler also support additional special
+options, usually for compatibility with other compilers on the same
+platform.
+
+@ifset INTERNALS
+These options are defined by the macro @code{TARGET_SWITCHES} in the
+machine description. The default for the options is also defined by
+that macro, which enables you to change the defaults.
+@end ifset
+
+@menu
+* M680x0 Options::
+* VAX Options::
+* SPARC Options::
+* Convex Options::
+* AMD29K Options::
+* ARM Options::
+* M88K Options::
+* RS/6000 and PowerPC Options::
+* RT Options::
+* MIPS Options::
+* i386 Options::
+* HPPA Options::
+* Intel 960 Options::
+* DEC Alpha Options::
+* Clipper Options::
+* H8/300 Options::
+* System V Options::
+@end menu
+
+@node M680x0 Options
+@subsection M680x0 Options
+@cindex M680x0 options
+
+These are the @samp{-m} options defined for the 68000 series. The default
+values for these options depends on which style of 68000 was selected when
+the compiler was configured; the defaults for the most common choices are
+given below.
+
+@table @code
+@item -m68000
+@itemx -mc68000
+Generate output for a 68000. This is the default
+when the compiler is configured for 68000-based systems.
+
+@item -m68020
+@itemx -mc68020
+Generate output for a 68020. This is the default
+when the compiler is configured for 68020-based systems.
+
+@item -m68881
+Generate output containing 68881 instructions for floating point.
+This is the default for most 68020 systems unless @samp{-nfp} was
+specified when the compiler was configured.
+
+@item -m68030
+Generate output for a 68030. This is the default when the compiler is
+configured for 68030-based systems.
+
+@item -m68040
+Generate output for a 68040. This is the default when the compiler is
+configured for 68040-based systems.
+
+This option inhibits the use of 68881/68882 instructions that have to be
+emulated by software on the 68040. If your 68040 does not have code to
+emulate those instructions, use @samp{-m68040}.
+
+@item -m68020-40
+Generate output for a 68040, without using any of the new instructions.
+This results in code which can run relatively efficiently on either a
+68020/68881 or a 68030 or a 68040. The generated code does use the
+68881 instructions that are emulated on the 68040.
+
+@item -mfpa
+Generate output containing Sun FPA instructions for floating point.
+
+@item -msoft-float
+Generate output containing library calls for floating point.
+@strong{Warning:} the requisite libraries are not part of GNU CC.
+Normally the facilities of the machine's usual C compiler are used, but
+this can't be done directly in cross-compilation. You must make your
+own arrangements to provide suitable library functions for
+cross-compilation.
+
+@item -mshort
+Consider type @code{int} to be 16 bits wide, like @code{short int}.
+
+@item -mnobitfield
+Do not use the bit-field instructions. The @samp{-m68000} option
+implies @w{@samp{-mnobitfield}}.
+
+@item -mbitfield
+Do use the bit-field instructions. The @samp{-m68020} option implies
+@samp{-mbitfield}. This is the default if you use a configuration
+designed for a 68020.
+
+@item -mrtd
+Use a different function-calling convention, in which functions
+that take a fixed number of arguments return with the @code{rtd}
+instruction, which pops their arguments while returning. This
+saves one instruction in the caller since there is no need to pop
+the arguments there.
+
+This calling convention is incompatible with the one normally
+used on Unix, so you cannot use it if you need to call libraries
+compiled with the Unix compiler.
+
+Also, you must provide function prototypes for all functions that
+take variable numbers of arguments (including @code{printf});
+otherwise incorrect code will be generated for calls to those
+functions.
+
+In addition, seriously incorrect code will result if you call a
+function with too many arguments. (Normally, extra arguments are
+harmlessly ignored.)
+
+The @code{rtd} instruction is supported by the 68010 and 68020
+processors, but not by the 68000.
+@end table
+
+@node VAX Options
+@subsection VAX Options
+@cindex VAX options
+
+These @samp{-m} options are defined for the Vax:
+
+@table @code
+@item -munix
+Do not output certain jump instructions (@code{aobleq} and so on)
+that the Unix assembler for the Vax cannot handle across long
+ranges.
+
+@item -mgnu
+Do output those jump instructions, on the assumption that you
+will assemble with the GNU assembler.
+
+@item -mg
+Output code for g-format floating point numbers instead of d-format.
+@end table
+
+@node SPARC Options
+@subsection SPARC Options
+@cindex SPARC options
+
+These @samp{-m} switches are supported on the SPARC:
+
+@table @code
+@item -mno-app-regs
+@itemx -mapp-regs
+Specify @samp{-mapp-regs} to generate output using the global registers
+2 through 4, which the SPARC SVR4 ABI reserves for applications. This
+is the default.
+
+To be fully SVR4 ABI compliant at the cost of some performance loss,
+specify @samp{-mno-app-regs}. You should compile libraries and system
+software with this option.
+
+@item -mfpu
+@itemx -mhard-float
+Generate output containing floating point instructions. This is the
+default.
+
+@item -mno-fpu
+@itemx -msoft-float
+Generate output containing library calls for floating point.
+@strong{Warning:} there is no GNU floating-point library for SPARC.
+Normally the facilities of the machine's usual C compiler are used, but
+this cannot be done directly in cross-compilation. You must make your
+own arrangements to provide suitable library functions for
+cross-compilation.
+
+@samp{-msoft-float} changes the calling convention in the output file;
+therefore, it is only useful if you compile @emph{all} of a program with
+this option. In particular, you need to compile @file{libgcc.a}, the
+library that comes with GNU CC, with @samp{-msoft-float} in order for
+this to work.
+
+@item -mhard-quad-float
+Generate output containing quad-word (long double) floating point
+instructions.
+
+@item -msoft-quad-float
+Generate output containing library calls for quad-word (long double)
+floating point instructions. The functions called are those specified
+in the SPARC ABI. This is the default.
+
+As of this writing, there are no sparc implementations that have hardware
+support for the quad-word floating point instructions. They all invoke
+a trap handler for one of these instructions, and then the trap handler
+emulates the effect of the instruction. Because of the trap handler overhead,
+this is much slower than calling the ABI library routines. Thus the
+@samp{-msoft-quad-float} option is the default.
+
+@item -mno-epilogue
+@itemx -mepilogue
+With @samp{-mepilogue} (the default), the compiler always emits code for
+function exit at the end of each function. Any function exit in
+the middle of the function (such as a return statement in C) will
+generate a jump to the exit code at the end of the function.
+
+With @samp{-mno-epilogue}, the compiler tries to emit exit code inline
+at every function exit.
+
+@item -mno-flat
+@itemx -mflat
+With @samp{-mflat}, the compiler does not generate save/restore instructions
+and will use a "flat" or single register window calling convention.
+This model uses %i7 as the frame pointer and is compatible with the normal
+register window model. Code from either may be intermixed although
+debugger support is still incomplete. The local registers and the input
+registers (0-5) are still treated as "call saved" registers and will be
+saved on the stack as necessary.
+
+With @samp{-mno-flat} (the default), the compiler emits save/restore
+instructions (except for leaf functions) and is the normal mode of operation.
+
+@item -mno-unaligned-doubles
+@itemx -munaligned-doubles
+Assume that doubles have 8 byte alignment. This is the default.
+
+With @samp{-munaligned-doubles}, GNU CC assumes that doubles have 8 byte
+alignment only if they are contained in another type, or if they have an
+absolute address. Otherwise, it assumes they have 4 byte alignment.
+Specifying this option avoids some rare compatibility problems with code
+generated by other compilers. It is not the default because it results
+in a performance loss, especially for floating point code.
+
+@item -mv8
+@itemx -msparclite
+These two options select variations on the SPARC architecture.
+
+By default (unless specifically configured for the Fujitsu SPARClite),
+GCC generates code for the v7 variant of the SPARC architecture.
+
+@samp{-mv8} will give you SPARC v8 code. The only difference from v7
+code is that the compiler emits the integer multiply and integer
+divide instructions which exist in SPARC v8 but not in SPARC v7.
+
+@samp{-msparclite} will give you SPARClite code. This adds the integer
+multiply, integer divide step and scan (@code{ffs}) instructions which
+exist in SPARClite but not in SPARC v7.
+
+@item -mcypress
+@itemx -msupersparc
+These two options select the processor for which the code is optimised.
+
+With @samp{-mcypress} (the default), the compiler optimizes code for the
+Cypress CY7C602 chip, as used in the SparcStation/SparcServer 3xx series.
+This is also apropriate for the older SparcStation 1, 2, IPX etc.
+
+With @samp{-msupersparc} the compiler optimizes code for the SuperSparc cpu, as
+used in the SparcStation 10, 1000 and 2000 series. This flag also enables use
+of the full SPARC v8 instruction set.
+@end table
+
+In a future version of GCC, these options will very likely be
+renamed to @samp{-mcpu=cypress} and @samp{-mcpu=supersparc}.
+
+These @samp{-m} switches are supported in addition to the above
+on SPARC V9 processors:
+
+@table @code
+@item -mmedlow
+Generate code for the Medium/Low code model: assume a 32 bit address space.
+Programs are statically linked, PIC is not supported. Pointers are still
+64 bits.
+
+It is very likely that a future version of GCC will rename this option.
+
+@item -mmedany
+Generate code for the Medium/Anywhere code model: assume a 32 bit text
+segment starting at offset 0, and a 32 bit data segment starting anywhere
+(determined at link time). Programs are statically linked, PIC is not
+supported. Pointers are still 64 bits.
+
+It is very likely that a future version of GCC will rename this option.
+
+@item -mint64
+Types long and int are 64 bits.
+
+@item -mlong32
+Types long and int are 32 bits.
+
+@item -mlong64
+@itemx -mint32
+Type long is 64 bits, and type int is 32 bits.
+
+@item -mstack-bias
+@itemx -mno-stack-bias
+With @samp{-mstack-bias}, GNU CC assumes that the stack pointer, and
+frame pointer if present, are offset by -2047 which must be added back
+when making stack frame references.
+Otherwise, assume no such offset is present.
+@end table
+
+@node Convex Options
+@subsection Convex Options
+@cindex Convex options
+
+These @samp{-m} options are defined for Convex:
+
+@table @code
+@item -mc1
+Generate output for C1. The code will run on any Convex machine.
+The preprocessor symbol @code{__convex__c1__} is defined.
+
+@item -mc2
+Generate output for C2. Uses instructions not available on C1.
+Scheduling and other optimizations are chosen for max performance on C2.
+The preprocessor symbol @code{__convex_c2__} is defined.
+
+@item -mc32
+Generate output for C32xx. Uses instructions not available on C1.
+Scheduling and other optimizations are chosen for max performance on C32.
+The preprocessor symbol @code{__convex_c32__} is defined.
+
+@item -mc34
+Generate output for C34xx. Uses instructions not available on C1.
+Scheduling and other optimizations are chosen for max performance on C34.
+The preprocessor symbol @code{__convex_c34__} is defined.
+
+@item -mc38
+Generate output for C38xx. Uses instructions not available on C1.
+Scheduling and other optimizations are chosen for max performance on C38.
+The preprocessor symbol @code{__convex_c38__} is defined.
+
+@item -margcount
+Generate code which puts an argument count in the word preceding each
+argument list. This is compatible with regular CC, and a few programs
+may need the argument count word. GDB and other source-level debuggers
+do not need it; this info is in the symbol table.
+
+@item -mnoargcount
+Omit the argument count word. This is the default.
+
+@item -mvolatile-cache
+Allow volatile references to be cached. This is the default.
+
+@item -mvolatile-nocache
+Volatile references bypass the data cache, going all the way to memory.
+This is only needed for multi-processor code that does not use standard
+synchronization instructions. Making non-volatile references to volatile
+locations will not necessarily work.
+
+@item -mlong32
+Type long is 32 bits, the same as type int. This is the default.
+
+@item -mlong64
+Type long is 64 bits, the same as type long long. This option is useless,
+because no library support exists for it.
+@end table
+
+@node AMD29K Options
+@subsection AMD29K Options
+@cindex AMD29K options
+
+These @samp{-m} options are defined for the AMD Am29000:
+
+@table @code
+@item -mdw
+@kindex -mdw
+@cindex DW bit (29k)
+Generate code that assumes the @code{DW} bit is set, i.e., that byte and
+halfword operations are directly supported by the hardware. This is the
+default.
+
+@item -mndw
+@kindex -mndw
+Generate code that assumes the @code{DW} bit is not set.
+
+@item -mbw
+@kindex -mbw
+@cindex byte writes (29k)
+Generate code that assumes the system supports byte and halfword write
+operations. This is the default.
+
+@item -mnbw
+@kindex -mnbw
+Generate code that assumes the systems does not support byte and
+halfword write operations. @samp{-mnbw} implies @samp{-mndw}.
+
+@item -msmall
+@kindex -msmall
+@cindex memory model (29k)
+Use a small memory model that assumes that all function addresses are
+either within a single 256 KB segment or at an absolute address of less
+than 256k. This allows the @code{call} instruction to be used instead
+of a @code{const}, @code{consth}, @code{calli} sequence.
+
+@item -mnormal
+@kindex -mnormal
+Use the normal memory model: Generate @code{call} instructions only when
+calling functions in the same file and @code{calli} instructions
+otherwise. This works if each file occupies less than 256 KB but allows
+the entire executable to be larger than 256 KB. This is the default.
+
+@item -mlarge
+Always use @code{calli} instructions. Specify this option if you expect
+a single file to compile into more than 256 KB of code.
+
+@item -m29050
+@kindex -m29050
+@cindex processor selection (29k)
+Generate code for the Am29050.
+
+@item -m29000
+@kindex -m29000
+Generate code for the Am29000. This is the default.
+
+@item -mkernel-registers
+@kindex -mkernel-registers
+@cindex kernel and user registers (29k)
+Generate references to registers @code{gr64-gr95} instead of to
+registers @code{gr96-gr127}. This option can be used when compiling
+kernel code that wants a set of global registers disjoint from that used
+by user-mode code.
+
+Note that when this option is used, register names in @samp{-f} flags
+must use the normal, user-mode, names.
+
+@item -muser-registers
+@kindex -muser-registers
+Use the normal set of global registers, @code{gr96-gr127}. This is the
+default.
+
+@item -mstack-check
+@itemx -mno-stack-check
+@kindex -mstack-check
+@cindex stack checks (29k)
+Insert (or do not insert) a call to @code{__msp_check} after each stack
+adjustment. This is often used for kernel code.
+
+@item -mstorem-bug
+@itemx -mno-storem-bug
+@kindex -mstorem-bug
+@cindex storem bug (29k)
+@samp{-mstorem-bug} handles 29k processors which cannot handle the
+separation of a mtsrim insn and a storem instruction (most 29000 chips
+to date, but not the 29050).
+
+@item -mno-reuse-arg-regs
+@itemx -mreuse-arg-regs
+@kindex -mreuse-arg-regs
+@samp{-mno-reuse-arg-regs} tells the compiler to only use incoming argument
+registers for copying out arguments. This helps detect calling a function
+with fewer arguments than it was declared with.
+
+@item -msoft-float
+@kindex -msoft-float
+Generate output containing library calls for floating point.
+@strong{Warning:} the requisite libraries are not part of GNU CC.
+Normally the facilities of the machine's usual C compiler are used, but
+this can't be done directly in cross-compilation. You must make your
+own arrangements to provide suitable library functions for
+cross-compilation.
+@end table
+
+@node ARM Options
+@subsection ARM Options
+@cindex ARM options
+
+These @samp{-m} options are defined for Advanced RISC Machines (ARM)
+architectures:
+
+@table @code
+@item -m2
+@itemx -m3
+@kindex -m2
+@kindex -m3
+These options are identical. Generate code for the ARM2 and ARM3
+processors. This option is the default. You should also use this
+option to generate code for ARM6 processors that are running with a
+26-bit program counter.
+
+@item -m6
+@kindex -m6
+Generate code for the ARM6 processor when running with a 32-bit program
+counter.
+
+@item -mapcs
+@kindex -mapcs
+Generate a stack frame that is compliant with the ARM Proceedure Call
+Standard for all functions, even if this is not strictly necessary for
+correct execution of the code.
+
+@item -mbsd
+@kindex -mbsd
+This option only applies to RISC iX. Emulate the native BSD-mode
+compiler. This is the default if @samp{-ansi} is not specified.
+
+@item -mxopen
+@kindex -mxopen
+This option only applies to RISC iX. Emulate the native X/Open-mode
+compiler.
+
+@item -mno-symrename
+@kindex -mno-symrename
+This option only applies to RISC iX. Do not run the assembler
+post-processor, @samp{symrename}, after code has been assembled.
+Normally it is necessary to modify some of the standard symbols in
+preparation for linking with the RISC iX C library; this option
+suppresses this pass. The post-processor is never run when the
+compiler is built for cross-compilation.
+@end table
+
+@node M88K Options
+@subsection M88K Options
+@cindex M88k options
+
+These @samp{-m} options are defined for Motorola 88k architectures:
+
+@table @code
+@item -m88000
+@kindex -m88000
+Generate code that works well on both the m88100 and the
+m88110.
+
+@item -m88100
+@kindex -m88100
+Generate code that works best for the m88100, but that also
+runs on the m88110.
+
+@item -m88110
+@kindex -m88110
+Generate code that works best for the m88110, and may not run
+on the m88100.
+
+@item -mbig-pic
+@kindex -mbig-pic
+Obsolete option to be removed from the next revision.
+Use @samp{-fPIC}.
+
+@item -midentify-revision
+@kindex -midentify-revision
+@kindex ident
+@cindex identifying source, compiler (88k)
+Include an @code{ident} directive in the assembler output recording the
+source file name, compiler name and version, timestamp, and compilation
+flags used.
+
+@item -mno-underscores
+@kindex -mno-underscores
+@cindex underscores, avoiding (88k)
+In assembler output, emit symbol names without adding an underscore
+character at the beginning of each name. The default is to use an
+underscore as prefix on each name.
+
+@item -mocs-debug-info
+@itemx -mno-ocs-debug-info
+@kindex -mocs-debug-info
+@kindex -mno-ocs-debug-info
+@cindex OCS (88k)
+@cindex debugging, 88k OCS
+Include (or omit) additional debugging information (about registers used
+in each stack frame) as specified in the 88open Object Compatibility
+Standard, ``OCS''. This extra information allows debugging of code that
+has had the frame pointer eliminated. The default for DG/UX, SVr4, and
+Delta 88 SVr3.2 is to include this information; other 88k configurations
+omit this information by default.
+
+@item -mocs-frame-position
+@kindex -mocs-frame-position
+@cindex register positions in frame (88k)
+When emitting COFF debugging information for automatic variables and
+parameters stored on the stack, use the offset from the canonical frame
+address, which is the stack pointer (register 31) on entry to the
+function. The DG/UX, SVr4, Delta88 SVr3.2, and BCS configurations use
+@samp{-mocs-frame-position}; other 88k configurations have the default
+@samp{-mno-ocs-frame-position}.
+
+@item -mno-ocs-frame-position
+@kindex -mno-ocs-frame-position
+@cindex register positions in frame (88k)
+When emitting COFF debugging information for automatic variables and
+parameters stored on the stack, use the offset from the frame pointer
+register (register 30). When this option is in effect, the frame
+pointer is not eliminated when debugging information is selected by the
+-g switch.
+
+@item -moptimize-arg-area
+@itemx -mno-optimize-arg-area
+@kindex -moptimize-arg-area
+@kindex -mno-optimize-arg-area
+@cindex arguments in frame (88k)
+Control how function arguments are stored in stack frames.
+@samp{-moptimize-arg-area} saves space by optimizing them, but this
+conflicts with the 88open specifications. The opposite alternative,
+@samp{-mno-optimize-arg-area}, agrees with 88open standards. By default
+GNU CC does not optimize the argument area.
+
+@item -mshort-data-@var{num}
+@kindex -mshort-data-@var{num}
+@cindex smaller data references (88k)
+@cindex r0-relative references (88k)
+Generate smaller data references by making them relative to @code{r0},
+which allows loading a value using a single instruction (rather than the
+usual two). You control which data references are affected by
+specifying @var{num} with this option. For example, if you specify
+@samp{-mshort-data-512}, then the data references affected are those
+involving displacements of less than 512 bytes.
+@samp{-mshort-data-@var{num}} is not effective for @var{num} greater
+than 64k.
+
+@item -mserialize-volatile
+@kindex -mserialize-volatile
+@itemx -mno-serialize-volatile
+@kindex -mno-serialize-volatile
+@cindex sequential consistency on 88k
+Do, or don't, generate code to guarantee sequential consistency
+of volatile memory references. By default, consistency is
+guaranteed.
+
+The order of memory references made by the MC88110 processor does
+not always match the order of the instructions requesting those
+references. In particular, a load instruction may execute before
+a preceding store instruction. Such reordering violates
+sequential consistency of volatile memory references, when there
+are multiple processors. When consistency must be guaranteed,
+GNU C generates special instructions, as needed, to force
+execution in the proper order.
+
+The MC88100 processor does not reorder memory references and so
+always provides sequential consistency. However, by default, GNU
+C generates the special instructions to guarantee consistency
+even when you use @samp{-m88100}, so that the code may be run on an
+MC88110 processor. If you intend to run your code only on the
+MC88100 processor, you may use @samp{-mno-serialize-volatile}.
+
+The extra code generated to guarantee consistency may affect the
+performance of your application. If you know that you can safely
+forgo this guarantee, you may use @samp{-mno-serialize-volatile}.
+
+@item -msvr4
+@itemx -msvr3
+@kindex -msvr4
+@kindex -msvr3
+@cindex assembler syntax, 88k
+@cindex SVr4
+Turn on (@samp{-msvr4}) or off (@samp{-msvr3}) compiler extensions
+related to System V release 4 (SVr4). This controls the following:
+
+@enumerate
+@item
+Which variant of the assembler syntax to emit.
+@item
+@samp{-msvr4} makes the C preprocessor recognize @samp{#pragma weak}
+that is used on System V release 4.
+@item
+@samp{-msvr4} makes GNU CC issue additional declaration directives used in
+SVr4.
+@end enumerate
+
+@samp{-msvr4} is the default for the m88k-motorola-sysv4 and
+m88k-dg-dgux m88k configurations. @samp{-msvr3} is the default for all
+other m88k configurations.
+
+@item -mversion-03.00
+@kindex -mversion-03.00
+This option is obsolete, and is ignored.
+@c ??? which asm syntax better for GAS? option there too?
+
+@item -mno-check-zero-division
+@itemx -mcheck-zero-division
+@kindex -mno-check-zero-division
+@kindex -mcheck-zero-division
+@cindex zero division on 88k
+Do, or don't, generate code to guarantee that integer division by
+zero will be detected. By default, detection is guaranteed.
+
+Some models of the MC88100 processor fail to trap upon integer
+division by zero under certain conditions. By default, when
+compiling code that might be run on such a processor, GNU C
+generates code that explicitly checks for zero-valued divisors
+and traps with exception number 503 when one is detected. Use of
+mno-check-zero-division suppresses such checking for code
+generated to run on an MC88100 processor.
+
+GNU C assumes that the MC88110 processor correctly detects all
+instances of integer division by zero. When @samp{-m88110} is
+specified, both @samp{-mcheck-zero-division} and
+@samp{-mno-check-zero-division} are ignored, and no explicit checks for
+zero-valued divisors are generated.
+
+@item -muse-div-instruction
+@kindex -muse-div-instruction
+@cindex divide instruction, 88k
+Use the div instruction for signed integer division on the
+MC88100 processor. By default, the div instruction is not used.
+
+On the MC88100 processor the signed integer division instruction
+div) traps to the operating system on a negative operand. The
+operating system transparently completes the operation, but at a
+large cost in execution time. By default, when compiling code
+that might be run on an MC88100 processor, GNU C emulates signed
+integer division using the unsigned integer division instruction
+divu), thereby avoiding the large penalty of a trap to the
+operating system. Such emulation has its own, smaller, execution
+cost in both time and space. To the extent that your code's
+important signed integer division operations are performed on two
+nonnegative operands, it may be desirable to use the div
+instruction directly.
+
+On the MC88110 processor the div instruction (also known as the
+divs instruction) processes negative operands without trapping to
+the operating system. When @samp{-m88110} is specified,
+@samp{-muse-div-instruction} is ignored, and the div instruction is used
+for signed integer division.
+
+Note that the result of dividing INT_MIN by -1 is undefined. In
+particular, the behavior of such a division with and without
+@samp{-muse-div-instruction} may differ.
+
+@item -mtrap-large-shift
+@itemx -mhandle-large-shift
+@kindex -mtrap-large-shift
+@kindex -mhandle-large-shift
+@cindex bit shift overflow (88k)
+@cindex large bit shifts (88k)
+Include code to detect bit-shifts of more than 31 bits; respectively,
+trap such shifts or emit code to handle them properly. By default GNU CC
+makes no special provision for large bit shifts.
+
+@item -mwarn-passed-structs
+@kindex -mwarn-passed-structs
+@cindex structure passing (88k)
+Warn when a function passes a struct as an argument or result.
+Structure-passing conventions have changed during the evolution of the C
+language, and are often the source of portability problems. By default,
+GNU CC issues no such warning.
+@end table
+
+@node RS/6000 and PowerPC Options
+@subsection IBM RS/6000 and PowerPC Options
+@cindex RS/6000 and PowerPC Options
+@cindex IBM RS/6000 and PowerPC Options
+
+These @samp{-m} options are defined for the IBM RS/6000 and PowerPC:
+@table @code
+@item -mpower
+@itemx -mno-power
+@itemx -mpower2
+@itemx -mno-power2
+@itemx -mpowerpc
+@itemx -mno-powerpc
+@itemx -mpowerpc-gpopt
+@itemx -mno-powerpc-gpopt
+@itemx -mpowerpc-gfxopt
+@itemx -mno-powerpc-gfxopt
+@kindex -mpower
+@kindex -mpower2
+@kindex -mpowerpc
+@kindex -mpowerpc-gpopt
+@kindex -mpowerpc-gfxopt
+GNU CC supports two related instruction set architectures for the
+RS/6000 and PowerPC. The @dfn{POWER} instruction set are those
+instructions supported by the @samp{rios} chip set used in the original
+RS/6000 systems and the @dfn{PowerPC} instruction set is the
+architecture of the Motorola MPC6xx microprocessors. The PowerPC
+architecture defines 64-bit instructions, but they are not supported by
+any current processors.
+
+Neither architecture is a subset of the other. However there is a
+large common subset of instructions supported by both. An MQ
+register is included in processors supporting the POWER architecture.
+
+You use these options to specify which instructions are available on the
+processor you are using. The default value of these options is
+determined when configuring GNU CC. Specifying the
+@samp{-mcpu=@var{cpu_type}} overrides the specification of these
+options. We recommend you use that option rather than these.
+
+The @samp{-mpower} option allows GNU CC to generate instructions that
+are found only in the POWER architecture and to use the MQ register.
+Specifying @samp{-mpower2} implies @samp{-power} and also allows GNU CC
+to generate instructions that are present in the POWER2 architecture but
+not the original POWER architecture.
+
+The @samp{-mpowerpc} option allows GNU CC to generate instructions that
+are found only in the 32-bit subset of the PowerPC architecture.
+Specifying @samp{-mpowerpc-gpopt} implies @samp{-mpowerpc} and also allows
+GNU CC to use the optional PowerPC architecture instructions in the
+General Purpose group, including floating-point square root. Specifying
+@samp{-mpowerpc-gfxopt} implies @samp{-mpowerpc} and also allows GNU CC to
+use the optional PowerPC architecture instructions in the Graphics
+group, including floating-point select.
+
+If you specify both @samp{-mno-power} and @samp{-mno-powerpc}, GNU CC
+will use only the instructions in the common subset of both
+architectures plus some special AIX common-mode calls, and will not use
+the MQ register. Specifying both @samp{-mpower} and @samp{-mpowerpc}
+permits GNU CC to use any instruction from either architecture and to
+allow use of the MQ register; specify this for the Motorola MPC601.
+
+@item -mnew-mnemonics
+@itemx -mold-mnemonics
+@kindex -mnew-mnemonics
+@kindex -mold-mnemonics
+Select which mnemonics to use in the generated assembler code.
+@samp{-mnew-mnemonics} requests output that uses the assembler mnemonics
+defined for the PowerPC architecture, while @samp{-mold-mnemonics}
+requests the assembler mnemonics defined for the POWER architecture.
+Instructions defined in only one architecture have only one mnemonic;
+GNU CC uses that mnemonic irrespective of which of thse options is
+specified.
+
+PowerPC assemblers support both the old and new mnemonics, as will later
+POWER assemblers. Current POWER assemblers only support the old
+mnemonics. Specify @samp{-mnew-mnemonics} if you have an assembler that
+supports them, otherwise specify @samp{-mold-mnemonics}.
+
+The default value of these options depends on how GNU CC was configured.
+Specifing @samp{-mcpu=@var{cpu_type}} sometimes overrides the value of
+these option. Unless you are building a cross-compiler, you should
+normally not specify either @samp{-mnew-mnemonics} or
+@samp{-mold-mnemonics}, but should instead accept the default.
+
+@item -mcpu=@var{cpu_type}
+Set architecture type, register usage, choice of mnemonics, and
+instruction scheduling parameters for machine type @var{cpu_type}. By
+default, @var{cpu_type} is the target system defined when GNU CC was
+configured. Supported values for @var{cpu_type} are @samp{rios1},
+@samp{rios2}, @samp{rsc}, @samp{601}, @samp{603}, @samp{604},
+@samp{power}, @samp{powerpc}, and @samp{common}. @samp{-mcpu=power} and
+@samp{-mcpu=powerpc} specify generic POWER and pure PowerPC (i.e., not
+MPC601) architecture machine types, with an appropriate, generic
+processor model assumed for scheduling purposes.@refill
+
+Specifying @samp{-mcpu=rios1}, @samp{-mcpu=rios2}, @samp{-mcpu=rsc}, or
+@samp{-mcpu=power} enables the @samp{-mpower} option and disables the
+@samp{-mpowerpc} option; @samp{-mcpu=601} enables both the
+@samp{-mpower} and @samp{-mpowerpc} options; @samp{-mcpu=603},
+@samp{-mcpu=604}, and @samp{-mcpu=powerpc} enable the @samp{-mpowerpc}
+option and disable the @samp{-mpower} option; @samp{-mcpu=common}
+disables both the @samp{-mpower} and @samp{-mpowerpc} options.@refill
+
+To generate code that will operate on all members of the RS/6000 and
+PowerPC families, specify @samp{-mcpu=common}. In that case, GNU CC
+will use only the instructions in the common subset of both
+architectures plus some special AIX common-mode calls, and will not use
+the MQ register. GNU CC assumes a generic processor model for scheduling
+purposes.
+
+Specifying @samp{-mcpu=rios1}, @samp{-mcpu=rios2}, @samp{-mcpu=rsc}, or
+@samp{-mcpu=power} also disables the @samp{new-mnemonics} option.
+Specifying @samp{-mcpu=601}, @samp{-mcpu=603}, @samp{-mcpu=604}, or
+@samp{-mcpu=powerpc} also enables the @samp{new-mnemonics}
+option.@refill
+
+@item -mfull-toc
+@itemx -mno-fp-in-toc
+@itemx -mno-sum-in-toc
+@itemx -mminimal-toc
+Modify generation of the TOC (Table Of Contents), which is created for
+every executable file. The @samp{-mfull-toc} option is selected by
+default. In that case, GNU CC will allocate at least one TOC entry for
+each unique non-automatic variable reference in your program. GNU CC
+will also place floating-point constants in the TOC. However, only
+16,384 entries are available in the TOC.
+
+If you receive a linker error message that saying you have overflowed
+the available TOC space, you can reduce the amount of TOC space used
+with the @samp{-mno-fp-in-toc} and @samp{-mno-sum-in-toc} options.
+@samp{-mno-fp-in-toc} prevents GNU CC from putting floating-point
+constants in the TOC and @samp{-mno-sum-in-toc} forces GNU CC to
+generate code to calculate the sum of an address and a constant at
+run-time instead of putting that sum into the TOC. You may specify one
+or both of these options. Each causes GNU CC to produce very slightly
+slower and larger code at the expense of conserving TOC space.
+
+If you still run out of space in the TOC even when you specify both of
+these options, specify @samp{-mminimal-toc} instead. This option causes
+GNU CC to make only one TOC entry for every file. When you specify this
+option, GNU CC will produce code that is slower and larger but which
+uses extremely little TOC space. You may wish to use this option
+only on files that contain less frequently executed code. @refill
+@end table
+@node RT Options
+@subsection IBM RT Options
+@cindex RT options
+@cindex IBM RT options
+
+These @samp{-m} options are defined for the IBM RT PC:
+
+@table @code
+@item -min-line-mul
+Use an in-line code sequence for integer multiplies. This is the
+default.
+
+@item -mcall-lib-mul
+Call @code{lmul$$} for integer multiples.
+
+@item -mfull-fp-blocks
+Generate full-size floating point data blocks, including the minimum
+amount of scratch space recommended by IBM. This is the default.
+
+@item -mminimum-fp-blocks
+Do not include extra scratch space in floating point data blocks. This
+results in smaller code, but slower execution, since scratch space must
+be allocated dynamically.
+
+@cindex @file{varargs.h} and RT PC
+@cindex @file{stdarg.h} and RT PC
+@item -mfp-arg-in-fpregs
+Use a calling sequence incompatible with the IBM calling convention in
+which floating point arguments are passed in floating point registers.
+Note that @code{varargs.h} and @code{stdargs.h} will not work with
+floating point operands if this option is specified.
+
+@item -mfp-arg-in-gregs
+Use the normal calling convention for floating point arguments. This is
+the default.
+
+@item -mhc-struct-return
+Return structures of more than one word in memory, rather than in a
+register. This provides compatibility with the MetaWare HighC (hc)
+compiler. Use the option @samp{-fpcc-struct-return} for compatibility
+with the Portable C Compiler (pcc).
+
+@item -mnohc-struct-return
+Return some structures of more than one word in registers, when
+convenient. This is the default. For compatibility with the
+IBM-supplied compilers, use the option @samp{-fpcc-struct-return} or the
+option @samp{-mhc-struct-return}.
+@end table
+
+@node MIPS Options
+@subsection MIPS Options
+@cindex MIPS options
+
+These @samp{-m} options are defined for the MIPS family of computers:
+
+@table @code
+@item -mcpu=@var{cpu type}
+Assume the defaults for the machine type @var{cpu type} when scheduling
+instructions. The choices for @var{cpu type} are @samp{r2000}, @samp{r3000},
+@samp{r4000}, @samp{r4400}, @samp{r4600}, and @samp{r6000}. While picking a
+specific @var{cpu type} will schedule things appropriately for that
+particular chip, the compiler will not generate any code that does not
+meet level 1 of the MIPS ISA (instruction set architecture) without
+the @samp{-mips2} or @samp{-mips3} switches being used.
+
+@item -mips1
+Issue instructions from level 1 of the MIPS ISA. This is the default.
+@samp{r3000} is the default @var{cpu type} at this ISA level.
+
+@item -mips2
+Issue instructions from level 2 of the MIPS ISA (branch likely, square
+root instructions). @samp{r6000} is the default @var{cpu type} at this
+ISA level.
+
+@item -mips3
+Issue instructions from level 3 of the MIPS ISA (64 bit instructions).
+@samp{r4000} is the default @var{cpu type} at this ISA level.
+This option does not change the sizes of any of the C data types.
+
+@item -mfp32
+Assume that 32 32-bit floating point registers are available. This is
+the default.
+
+@item -mfp64
+Assume that 32 64-bit floating point registers are available. This is
+the default when the @samp{-mips3} option is used.
+
+@item -mgp32
+Assume that 32 32-bit general purpose registers are available. This is
+the default.
+
+@item -mgp64
+Assume that 32 64-bit general purpose registers are available. This is
+the default when the @samp{-mips3} option is used.
+
+@item -mint64
+Types long, int, and pointer are 64 bits. This works only if @samp{-mips3}
+is also specified.
+
+@item -mlong64
+Types long and pointer are 64 bits, and type int is 32 bits.
+This works only if @samp{-mips3} is also specified.
+
+@item -mmips-as
+Generate code for the MIPS assembler, and invoke @file{mips-tfile} to
+add normal debug information. This is the default for all
+platforms except for the OSF/1 reference platform, using the OSF/rose
+object format. If the either of the @samp{-gstabs} or @samp{-gstabs+}
+switches are used, the @file{mips-tfile} program will encapsulate the
+stabs within MIPS ECOFF.
+
+@item -mgas
+Generate code for the GNU assembler. This is the default on the OSF/1
+reference platform, using the OSF/rose object format.
+
+@item -mrnames
+@itemx -mno-rnames
+The @samp{-mrnames} switch says to output code using the MIPS software
+names for the registers, instead of the hardware names (ie, @var{a0}
+instead of @var{$4}). The only known assembler that supports this option
+is the Algorithmics assembler.
+
+@item -mgpopt
+@itemx -mno-gpopt
+The @samp{-mgpopt} switch says to write all of the data declarations
+before the instructions in the text section, this allows the MIPS
+assembler to generate one word memory references instead of using two
+words for short global or static data items. This is on by default if
+optimization is selected.
+
+@item -mstats
+@itemx -mno-stats
+For each non-inline function processed, the @samp{-mstats} switch
+causes the compiler to emit one line to the standard error file to
+print statistics about the program (number of registers saved, stack
+size, etc.).
+
+@item -mmemcpy
+@itemx -mno-memcpy
+The @samp{-mmemcpy} switch makes all block moves call the appropriate
+string function (@samp{memcpy} or @samp{bcopy}) instead of possibly
+generating inline code.
+
+@item -mmips-tfile
+@itemx -mno-mips-tfile
+The @samp{-mno-mips-tfile} switch causes the compiler not
+postprocess the object file with the @file{mips-tfile} program,
+after the MIPS assembler has generated it to add debug support. If
+@file{mips-tfile} is not run, then no local variables will be
+available to the debugger. In addition, @file{stage2} and
+@file{stage3} objects will have the temporary file names passed to the
+assembler embedded in the object file, which means the objects will
+not compare the same. The @samp{-mno-mips-tfile} switch should only
+be used when there are bugs in the @file{mips-tfile} program that
+prevents compilation.
+
+@item -msoft-float
+Generate output containing library calls for floating point.
+@strong{Warning:} the requisite libraries are not part of GNU CC.
+Normally the facilities of the machine's usual C compiler are used, but
+this can't be done directly in cross-compilation. You must make your
+own arrangements to provide suitable library functions for
+cross-compilation.
+
+@item -mhard-float
+Generate output containing floating point instructions. This is the
+default if you use the unmodified sources.
+
+@item -mabicalls
+@itemx -mno-abicalls
+Emit (or do not emit) the pseudo operations @samp{.abicalls},
+@samp{.cpload}, and @samp{.cprestore} that some System V.4 ports use for
+position independent code.
+
+@item -mlong-calls
+@itemx -mno-long-calls
+Do all calls with the @samp{JALR} instruction, which requires
+loading up a function's address into a register before the call.
+You need to use this switch, if you call outside of the current
+512 megabyte segment to functions that are not through pointers.
+
+@item -mhalf-pic
+@itemx -mno-half-pic
+Put pointers to extern references into the data section and load them
+up, rather than put the references in the text section.
+
+@item -membedded-pic
+@itemx -mno-embedded-pic
+Generate PIC code suitable for some embedded systems. All calls are made
+using PC relative address, and all data is addressed using the $gp register.
+This requires GNU as and GNU ld which do most of the work.
+
+@item -membedded-data
+@itemx -mno-embedded-data
+Allocate variables to the read-only data section first if possible, then
+next in the small data section if possible, otherwise in data. This gives
+slightly slower code than the default, but reduces the amount of RAM required
+when executing, and thus may be preferred for some embedded systems.
+
+@item -G @var{num}
+@cindex smaller data references (MIPS)
+@cindex gp-relative references (MIPS)
+Put global and static items less than or equal to @var{num} bytes into
+the small data or bss sections instead of the normal data or bss
+section. This allows the assembler to emit one word memory reference
+instructions based on the global pointer (@var{gp} or @var{$28}),
+instead of the normal two words used. By default, @var{num} is 8 when
+the MIPS assembler is used, and 0 when the GNU assembler is used. The
+@samp{-G @var{num}} switch is also passed to the assembler and linker.
+All modules should be compiled with the same @samp{-G @var{num}}
+value.
+
+@item -nocpp
+Tell the MIPS assembler to not run it's preprocessor over user
+assembler files (with a @samp{.s} suffix) when assembling them.
+@end table
+
+@ifset INTERNALS
+These options are defined by the macro
+@code{TARGET_SWITCHES} in the machine description. The default for the
+options is also defined by that macro, which enables you to change the
+defaults.
+@end ifset
+
+@node i386 Options
+@subsection Intel 386 Options
+@cindex i386 Options
+@cindex Intel 386 Options
+
+These @samp{-m} options are defined for the i386 family of computers:
+
+@table @code
+@item -m486
+@itemx -mno-486
+Control whether or not code is optimized for a 486 instead of an
+386. Code generated for an 486 will run on a 386 and vice versa.
+
+@item -mno-ieee-fp
+@itemx -mieee-fp
+Control whether or not the compiler uses IEEE floating point
+comparisons. These handle correctly the case where the result of a
+comparison is unordered.
+
+@item -msoft-float
+Generate output containing library calls for floating point.
+@strong{Warning:} the requisite libraries are not part of GNU CC.
+Normally the facilities of the machine's usual C compiler are used, but
+this can't be done directly in cross-compilation. You must make your
+own arrangements to provide suitable library functions for
+cross-compilation.
+
+On machines where a function returns floating point results in the 80387
+register stack, some floating point opcodes may be emitted even if
+@samp{-msoft-float} is used.
+
+@item -mno-fp-ret-in-387
+Do not use the FPU registers for return values of functions.
+
+The usual calling convention has functions return values of types
+@code{float} and @code{double} in an FPU register, even if there
+is no FPU. The idea is that the operating system should emulate
+an FPU.
+
+The option @samp{-mno-fp-ret-in-387} causes such values to be returned
+in ordinary CPU registers instead.
+
+@item -mno-fancy-math-387
+Some 387 emulators do not support the @code{sin}, @code{cos} and
+@code{sqrt} instructions for the 387. Specify this option to avoid
+generating those instructions. This option is the default on FreeBSD.
+As of revision 2.6.1, these instructions are not generated unless you
+also use the @samp{-ffast-math} switch.
+
+@item -msvr3-shlib
+@itemx -mno-svr3-shlib
+Control whether GNU CC places uninitialized locals into @code{bss} or
+@code{data}. @samp{-msvr3-shlib} places these locals into @code{bss}.
+These options are meaningful only on System V Release 3.
+
+@item -mno-wide-multiply
+@itemx -mwide-multiply
+Control whether GNU CC uses the @code{mul} and @code{imul} that produce
+64 bit results in @code{eax:edx} from 32 bit operands to do @code{long
+long} multiplies and 32-bit division by constants.
+
+@item -mprofiler-epilogue
+@itemx -mno-profiler-epilogue
+Generate extra code to write profile information for function exits.
+This option has no effect except in combination with @samp{-g} or
+@samp{-pg}.
+
+@item -mreg-alloc=@var{regs}
+Control the default allocation order of integer registers. The
+string @var{regs} is a series of letters specifing a register. The
+supported letters are: @code{a} allocate EAX; @code{b} allocate EBX;
+@code{c} allocate ECX; @code{d} allocate EDX; @code{S} allocate ESI;
+@code{D} allocate EDI; @code{B} allocate EBP.
+@end table
+
+@node HPPA Options
+@subsection HPPA Options
+@cindex HPPA Options
+
+These @samp{-m} options are defined for the HPPA family of computers:
+
+@table @code
+@item -mpa-risc-1-0
+Generate code for a PA 1.0 processor.
+
+@item -mpa-risc-1-1
+Generate code for a PA 1.1 processor.
+
+@item -mjump-in-delay
+Fill delay slots of function calls with unconditional jump instructions
+by modifying the return pointer for the function call to be the target
+of the conditional jump.
+
+@item -mlong-calls
+Generate code which allows calls to functions greater than 256k away from
+the caller when the caller and callee are in the same source file. Do
+not turn this option on unless code refuses to link with "branch out of
+range errors" from the linker.
+
+@item -mdisable-fpregs
+Prevent floating point registers from being used in any manner. This is
+necessary for compiling kernels which perform lazy context switching of
+floating point registers. If you use this option and attempt to perform
+floating point operations, the compiler will abort.
+
+@item -mdisable-indexing
+Prevent the compiler from using indexing address modes. This avoids some
+rather obscure problems when compiling MIG generated code under MACH.
+
+@item -mportable-runtime
+Use the portable calling conventions proposed by HP for ELF systems. Note
+this option also enables @samp{-mlong-calls}.
+
+@item -mgas
+Enable the use of assembler directives only GAS understands.
+@end table
+
+@node Intel 960 Options
+@subsection Intel 960 Options
+
+These @samp{-m} options are defined for the Intel 960 implementations:
+
+@table @code
+@item -m@var{cpu type}
+Assume the defaults for the machine type @var{cpu type} for some of
+the other options, including instruction scheduling, floating point
+support, and addressing modes. The choices for @var{cpu type} are
+@samp{ka}, @samp{kb}, @samp{mc}, @samp{ca}, @samp{cf},
+@samp{sa}, and @samp{sb}.
+The default is
+@samp{kb}.
+
+@item -mnumerics
+@itemx -msoft-float
+The @samp{-mnumerics} option indicates that the processor does support
+floating-point instructions. The @samp{-msoft-float} option indicates
+that floating-point support should not be assumed.
+
+@item -mleaf-procedures
+@itemx -mno-leaf-procedures
+Do (or do not) attempt to alter leaf procedures to be callable with the
+@code{bal} instruction as well as @code{call}. This will result in more
+efficient code for explicit calls when the @code{bal} instruction can be
+substituted by the assembler or linker, but less efficient code in other
+cases, such as calls via function pointers, or using a linker that doesn't
+support this optimization.
+
+@item -mtail-call
+@itemx -mno-tail-call
+Do (or do not) make additional attempts (beyond those of the
+machine-independent portions of the compiler) to optimize tail-recursive
+calls into branches. You may not want to do this because the detection of
+cases where this is not valid is not totally complete. The default is
+@samp{-mno-tail-call}.
+
+@item -mcomplex-addr
+@itemx -mno-complex-addr
+Assume (or do not assume) that the use of a complex addressing mode is a
+win on this implementation of the i960. Complex addressing modes may not
+be worthwhile on the K-series, but they definitely are on the C-series.
+The default is currently @samp{-mcomplex-addr} for all processors except
+the CB and CC.
+
+@item -mcode-align
+@itemx -mno-code-align
+Align code to 8-byte boundaries for faster fetching (or don't bother).
+Currently turned on by default for C-series implementations only.
+
+@ignore
+@item -mclean-linkage
+@itemx -mno-clean-linkage
+These options are not fully implemented.
+@end ignore
+
+@item -mic-compat
+@itemx -mic2.0-compat
+@itemx -mic3.0-compat
+Enable compatibility with iC960 v2.0 or v3.0.
+
+@item -masm-compat
+@itemx -mintel-asm
+Enable compatibility with the iC960 assembler.
+
+@item -mstrict-align
+@itemx -mno-strict-align
+Do not permit (do permit) unaligned accesses.
+
+@item -mold-align
+Enable structure-alignment compatibility with Intel's gcc release version
+1.3 (based on gcc 1.37). Currently this is buggy in that @samp{#pragma
+align 1} is always assumed as well, and cannot be turned off.
+@end table
+
+@node DEC Alpha Options
+@subsection DEC Alpha Options
+
+These @samp{-m} options are defined for the DEC Alpha implementations:
+
+@table @code
+@item -mno-soft-float
+@itemx -msoft-float
+Use (do not use) the hardware floating-point instructions for
+floating-point operations. When @code{-msoft-float} is specified,
+functions in @file{libgcc1.c} will be used to perform floating-point
+operations. Unless they are replaced by routines that emulate the
+floating-point operations, or compiled in such a way as to call such
+emulations routines, these routines will issue floating-point
+operations. If you are compiling for an Alpha without floating-point
+operations, you must ensure that the library is built so as not to call
+them.
+
+Note that Alpha implementations without floating-point operations are
+required to have floating-point registers.
+
+@item -mfp-reg
+@itemx -mno-fp-regs
+Generate code that uses (does not use) the floating-point register set.
+@code{-mno-fp-regs} implies @code{-msoft-float}. If the floating-point
+register set is not used, floating point operands are passed in integer
+registers as if they were integers and floating-point results are passed
+in $0 instead of $f0. This is a non-standard calling sequence, so any
+function with a floating-point argument or return value called by code
+compiled with @code{-mno-fp-regs} must also be compiled with that
+option.
+
+A typical use of this option is building a kernel that does not use,
+and hence need not save and restore, any floating-point registers.
+@end table
+
+@node Clipper Options
+@subsection Clipper Options
+
+These @samp{-m} options are defined for the Clipper implementations:
+
+@table @code
+@item -mc300
+Produce code for a C300 Clipper processor. This is the default.
+
+@itemx -mc400
+Produce code for a C400 Clipper processor i.e. use floting point
+registers f8..f15.
+@end table
+
+@node H8/300 Options
+@subsection H8/300 Options
+
+These @samp{-m} options are defined for the H8/300 implementations:
+
+@table @code
+@item -mrelax
+Shorten some address references at link time, when possible; uses the
+linker option @samp{-relax}. @xref{H8/300,, @code{ld} and the H8/300,
+ld.info, Using ld}, for a fuller description.
+
+@item -mh
+Generate code for the H8/300H.
+@end table
+
+@node System V Options
+@subsection Options for System V
+
+These additional options are available on System V Release 4 for
+compatibility with other compilers on those systems:
+
+@table @code
+@ignore
+This should say *what the option does* and only then say
+"For compatibility only..."
+@item -G
+On SVr4 systems, @code{gcc} accepts the option @samp{-G} (and passes
+it to the system linker), for compatibility with other compilers.
+However, we suggest you use @samp{-symbolic} or @samp{-shared} as
+appropriate, instead of supplying linker options on the @code{gcc}
+command line.
+@end ignore
+
+@item -Qy
+Identify the versions of each tool used by the compiler, in a
+@code{.ident} assembler directive in the output.
+
+@item -Qn
+Refrain from adding @code{.ident} directives to the output file (this is
+the default).
+
+@item -YP,@var{dirs}
+Search the directories @var{dirs}, and no others, for libraries
+specified with @samp{-l}.
+
+@item -Ym,@var{dir}
+Look in the directory @var{dir} to find the M4 preprocessor.
+The assembler uses this option.
+@c This is supposed to go with a -Yd for predefined M4 macro files, but
+@c the generic assembler that comes with Solaris takes just -Ym.
+@end table
+
+@node Code Gen Options
+@section Options for Code Generation Conventions
+@cindex code generation conventions
+@cindex options, code generation
+@cindex run-time options
+
+These machine-independent options control the interface conventions
+used in code generation.
+
+Most of them have both positive and negative forms; the negative form
+of @samp{-ffoo} would be @samp{-fno-foo}. In the table below, only
+one of the forms is listed---the one which is not the default. You
+can figure out the other form by either removing @samp{no-} or adding
+it.
+
+@table @code
+@item -fpcc-struct-return
+Return ``short'' @code{struct} and @code{union} values in memory like
+longer ones, rather than in registers. This convention is less
+efficient, but it has the advantage of allowing intercallability between
+GNU CC-compiled files and files compiled with other compilers.
+
+The precise convention for returning structures in memory depends
+on the target configuration macros.
+
+Short structures and unions are those whose size and alignment match
+that of some integer type.
+
+@item -freg-struct-return
+Use the convention that @code{struct} and @code{union} values are
+returned in registers when possible. This is more efficient for small
+structures than @samp{-fpcc-struct-return}.
+
+If you specify neither @samp{-fpcc-struct-return} nor its contrary
+@samp{-freg-struct-return}, GNU CC defaults to whichever convention is
+standard for the target. If there is no standard convention, GNU CC
+defaults to @samp{-fpcc-struct-return}, except on targets where GNU CC
+is the principal compiler. In those cases, we can choose the standard,
+and we chose the more efficient register return alternative.
+
+@item -fshort-enums
+Allocate to an @code{enum} type only as many bytes as it needs for the
+declared range of possible values. Specifically, the @code{enum} type
+will be equivalent to the smallest integer type which has enough room.
+
+@item -fshort-double
+Use the same size for @code{double} as for @code{float}.
+
+@item -fshared-data
+Requests that the data and non-@code{const} variables of this
+compilation be shared data rather than private data. The distinction
+makes sense only on certain operating systems, where shared data is
+shared between processes running the same program, while private data
+exists in one copy per process.
+
+@item -fno-common
+Allocate even uninitialized global variables in the bss section of the
+object file, rather than generating them as common blocks. This has the
+effect that if the same variable is declared (without @code{extern}) in
+two different compilations, you will get an error when you link them.
+The only reason this might be useful is if you wish to verify that the
+program will work on other systems which always work this way.
+
+@item -fno-ident
+Ignore the @samp{#ident} directive.
+
+@item -fno-gnu-linker
+Do not output global initializations (such as C++ constructors and
+destructors) in the form used by the GNU linker (on systems where the GNU
+linker is the standard method of handling them). Use this option when
+you want to use a non-GNU linker, which also requires using the
+@code{collect2} program to make sure the system linker includes
+constructors and destructors. (@code{collect2} is included in the GNU CC
+distribution.) For systems which @emph{must} use @code{collect2}, the
+compiler driver @code{gcc} is configured to do this automatically.
+
+@item -finhibit-size-directive
+Don't output a @code{.size} assembler directive, or anything else that
+would cause trouble if the function is split in the middle, and the
+two halves are placed at locations far apart in memory. This option is
+used when compiling @file{crtstuff.c}; you should not need to use it
+for anything else.
+
+@item -fverbose-asm
+Put extra commentary information in the generated assembly code to
+make it more readable. This option is generally only of use to those
+who actually need to read the generated assembly code (perhaps while
+debugging the compiler itself).
+
+@item -fvolatile
+Consider all memory references through pointers to be volatile.
+
+@item -fvolatile-global
+Consider all memory references to extern and global data items to
+be volatile.
+
+@item -fpic
+@cindex global offset table
+@cindex PIC
+Generate position-independent code (PIC) suitable for use in a shared
+library, if supported for the target machine. Such code accesses all
+constant addresses through a global offset table (GOT). If the GOT size
+for the linked executable exceeds a machine-specific maximum size, you
+get an error message from the linker indicating that @samp{-fpic} does
+not work; in that case, recompile with @samp{-fPIC} instead. (These
+maximums are 16k on the m88k, 8k on the Sparc, and 32k on the m68k and
+RS/6000. The 386 has no such limit.)
+
+Position-independent code requires special support, and therefore works
+only on certain machines. For the 386, GNU CC supports PIC for System V
+but not for the Sun 386i. Code generated for the IBM RS/6000 is always
+position-independent.
+
+The GNU assembler does not fully support PIC. Currently, you must use
+some other assembler in order for PIC to work. We would welcome
+volunteers to upgrade GAS to handle this; the first part of the job is
+to figure out what the assembler must do differently.
+
+@item -fPIC
+If supported for the target machine, emit position-independent code,
+suitable for dynamic linking and avoiding any limit on the size of the
+global offset table. This option makes a difference on the m68k, m88k
+and the Sparc.
+
+Position-independent code requires special support, and therefore works
+only on certain machines.
+
+@item -ffixed-@var{reg}
+Treat the register named @var{reg} as a fixed register; generated code
+should never refer to it (except perhaps as a stack pointer, frame
+pointer or in some other fixed role).
+
+@var{reg} must be the name of a register. The register names accepted
+are machine-specific and are defined in the @code{REGISTER_NAMES}
+macro in the machine description macro file.
+
+This flag does not have a negative form, because it specifies a
+three-way choice.
+
+@item -fcall-used-@var{reg}
+Treat the register named @var{reg} as an allocatable register that is
+clobbered by function calls. It may be allocated for temporaries or
+variables that do not live across a call. Functions compiled this way
+will not save and restore the register @var{reg}.
+
+Use of this flag for a register that has a fixed pervasive role in the
+machine's execution model, such as the stack pointer or frame pointer,
+will produce disastrous results.
+
+This flag does not have a negative form, because it specifies a
+three-way choice.
+
+@item -fcall-saved-@var{reg}
+Treat the register named @var{reg} as an allocatable register saved by
+functions. It may be allocated even for temporaries or variables that
+live across a call. Functions compiled this way will save and restore
+the register @var{reg} if they use it.
+
+Use of this flag for a register that has a fixed pervasive role in the
+machine's execution model, such as the stack pointer or frame pointer,
+will produce disastrous results.
+
+A different sort of disaster will result from the use of this flag for
+a register in which function values may be returned.
+
+This flag does not have a negative form, because it specifies a
+three-way choice.
+
+@item +e0
+@itemx +e1
+Control whether virtual function definitions in classes are used to
+generate code, or only to define interfaces for their callers. (C++
+only).
+
+These options are provided for compatibility with @code{cfront} 1.x
+usage; the recommended alternative GNU C++ usage is in flux. @xref{C++
+Interface,,Declarations and Definitions in One Header}.
+
+With @samp{+e0}, virtual function definitions in classes are declared
+@code{extern}; the declaration is used only as an interface
+specification, not to generate code for the virtual functions (in this
+compilation).
+
+With @samp{+e1}, G++ actually generates the code implementing virtual
+functions defined in the code, and makes them publicly visible.
+@end table
+
+@node Environment Variables
+@section Environment Variables Affecting GNU CC
+@cindex environment variables
+
+This section describes several environment variables that affect how GNU
+CC operates. They work by specifying directories or prefixes to use
+when searching for various kinds of files.
+
+@ifclear INTERNALS
+Note that you can also specify places to search using options such as
+@samp{-B}, @samp{-I} and @samp{-L} (@pxref{Directory Options}). These
+take precedence over places specified using environment variables, which
+in turn take precedence over those specified by the configuration of GNU
+CC.
+@end ifclear
+@ifset INTERNALS
+Note that you can also specify places to search using options such as
+@samp{-B}, @samp{-I} and @samp{-L} (@pxref{Directory Options}). These
+take precedence over places specified using environment variables, which
+in turn take precedence over those specified by the configuration of GNU
+CC. @xref{Driver}.
+@end ifset
+
+@table @code
+@item TMPDIR
+@findex TMPDIR
+If @code{TMPDIR} is set, it specifies the directory to use for temporary
+files. GNU CC uses temporary files to hold the output of one stage of
+compilation which is to be used as input to the next stage: for example,
+the output of the preprocessor, which is the input to the compiler
+proper.
+
+@item GCC_EXEC_PREFIX
+@findex GCC_EXEC_PREFIX
+If @code{GCC_EXEC_PREFIX} is set, it specifies a prefix to use in the
+names of the subprograms executed by the compiler. No slash is added
+when this prefix is combined with the name of a subprogram, but you can
+specify a prefix that ends with a slash if you wish.
+
+If GNU CC cannot find the subprogram using the specified prefix, it
+tries looking in the usual places for the subprogram.
+
+The default value of @code{GCC_EXEC_PREFIX} is
+@file{@var{prefix}/lib/gcc-lib/@var{machine}/@var{version}/} where
+@var{prefix} is the value of @code{prefix} when you ran the
+@file{configure} script and @var{machine} and @var{version} are the
+configuration name and version number of GNU CC, respectively.
+
+Other prefixes specified with @samp{-B} take precedence over this prefix.
+
+This prefix is also used for finding files such as @file{crt0.o} that are
+used for linking.
+
+In addition, the prefix is used in an unusual way in finding the
+directories to search for header files. For each of the standard
+directories whose name normally begins with @samp{/usr/local/lib/gcc-lib}
+(more precisely, with the value of @code{GCC_INCLUDE_DIR}), GNU CC tries
+replacing that beginning with the specified prefix to produce an
+alternate directory name. Thus, with @samp{-Bfoo/}, GNU CC will search
+@file{foo/bar} where it would normally search @file{/usr/local/lib/bar}.
+These alternate directories are searched first; the standard directories
+come next.
+
+@item COMPILER_PATH
+@findex COMPILER_PATH
+The value of @code{COMPILER_PATH} is a colon-separated list of
+directories, much like @code{PATH}. GNU CC tries the directories thus
+specified when searching for subprograms, if it can't find the
+subprograms using @code{GCC_EXEC_PREFIX}.
+
+@item LIBRARY_PATH
+@findex LIBRARY_PATH
+The value of @code{LIBRARY_PATH} is a colon-separated list of
+directories, much like @code{PATH}. GNU CC tries the directories thus
+specified when searching for special linker files, if it can't find them
+using @code{GCC_EXEC_PREFIX}. Linking using GNU CC also uses these
+directories when searching for ordinary libraries for the @samp{-l}
+option (but directories specified with @samp{-L} come first).
+
+@item C_INCLUDE_PATH
+@itemx CPLUS_INCLUDE_PATH
+@itemx OBJC_INCLUDE_PATH
+@findex C_INCLUDE_PATH
+@findex CPLUS_INCLUDE_PATH
+@findex OBJC_INCLUDE_PATH
+@c @itemx OBJCPLUS_INCLUDE_PATH
+These environment variables pertain to particular languages. Each
+variable's value is a colon-separated list of directories, much like
+@code{PATH}. When GNU CC searches for header files, it tries the
+directories listed in the variable for the language you are using, after
+the directories specified with @samp{-I} but before the standard header
+file directories.
+
+@item DEPENDENCIES_OUTPUT
+@findex DEPENDENCIES_OUTPUT
+@cindex dependencies for make as output
+If this variable is set, its value specifies how to output dependencies
+for Make based on the header files processed by the compiler. This
+output looks much like the output from the @samp{-M} option
+(@pxref{Preprocessor Options}), but it goes to a separate file, and is
+in addition to the usual results of compilation.
+
+The value of @code{DEPENDENCIES_OUTPUT} can be just a file name, in
+which case the Make rules are written to that file, guessing the target
+name from the source file name. Or the value can have the form
+@samp{@var{file} @var{target}}, in which case the rules are written to
+file @var{file} using @var{target} as the target name.
+@end table
+
+@node Running Protoize
+@section Running Protoize
+
+The program @code{protoize} is an optional part of GNU C. You can use
+it to add prototypes to a program, thus converting the program to ANSI
+C in one respect. The companion program @code{unprotoize} does the
+reverse: it removes argument types from any prototypes that are found.
+
+When you run these programs, you must specify a set of source files as
+command line arguments. The conversion programs start out by compiling
+these files to see what functions they define. The information gathered
+about a file @var{foo} is saved in a file named @file{@var{foo}.X}.
+
+After scanning comes actual conversion. The specified files are all
+eligible to be converted; any files they include (whether sources or
+just headers) are eligible as well.
+
+But not all the eligible files are converted. By default,
+@code{protoize} and @code{unprotoize} convert only source and header
+files in the current directory. You can specify additional directories
+whose files should be converted with the @samp{-d @var{directory}}
+option. You can also specify particular files to exclude with the
+@samp{-x @var{file}} option. A file is converted if it is eligible, its
+directory name matches one of the specified directory names, and its
+name within the directory has not been excluded.
+
+Basic conversion with @code{protoize} consists of rewriting most
+function definitions and function declarations to specify the types of
+the arguments. The only ones not rewritten are those for varargs
+functions.
+
+@code{protoize} optionally inserts prototype declarations at the
+beginning of the source file, to make them available for any calls that
+precede the function's definition. Or it can insert prototype
+declarations with block scope in the blocks where undeclared functions
+are called.
+
+Basic conversion with @code{unprotoize} consists of rewriting most
+function declarations to remove any argument types, and rewriting
+function definitions to the old-style pre-ANSI form.
+
+Both conversion programs print a warning for any function declaration or
+definition that they can't convert. You can suppress these warnings
+with @samp{-q}.
+
+The output from @code{protoize} or @code{unprotoize} replaces the
+original source file. The original file is renamed to a name ending
+with @samp{.save}. If the @samp{.save} file already exists, then
+the source file is simply discarded.
+
+@code{protoize} and @code{unprotoize} both depend on GNU CC itself to
+scan the program and collect information about the functions it uses.
+So neither of these programs will work until GNU CC is installed.
+
+Here is a table of the options you can use with @code{protoize} and
+@code{unprotoize}. Each option works with both programs unless
+otherwise stated.
+
+@table @code
+@item -B @var{directory}
+Look for the file @file{SYSCALLS.c.X} in @var{directory}, instead of the
+usual directory (normally @file{/usr/local/lib}). This file contains
+prototype information about standard system functions. This option
+applies only to @code{protoize}.
+
+@item -c @var{compilation-options}
+Use @var{compilation-options} as the options when running @code{gcc} to
+produce the @samp{.X} files. The special option @samp{-aux-info} is
+always passed in addition, to tell @code{gcc} to write a @samp{.X} file.
+
+Note that the compilation options must be given as a single argument to
+@code{protoize} or @code{unprotoize}. If you want to specify several
+@code{gcc} options, you must quote the entire set of compilation options
+to make them a single word in the shell.
+
+There are certain @code{gcc} arguments that you cannot use, because they
+would produce the wrong kind of output. These include @samp{-g},
+@samp{-O}, @samp{-c}, @samp{-S}, and @samp{-o} If you include these in
+the @var{compilation-options}, they are ignored.
+
+@item -C
+Rename files to end in @samp{.C} instead of @samp{.c}.
+This is convenient if you are converting a C program to C++.
+This option applies only to @code{protoize}.
+
+@item -g
+Add explicit global declarations. This means inserting explicit
+declarations at the beginning of each source file for each function
+that is called in the file and was not declared. These declarations
+precede the first function definition that contains a call to an
+undeclared function. This option applies only to @code{protoize}.
+
+@item -i @var{string}
+Indent old-style parameter declarations with the string @var{string}.
+This option applies only to @code{protoize}.
+
+@code{unprotoize} converts prototyped function definitions to old-style
+function definitions, where the arguments are declared between the
+argument list and the initial @samp{@{}. By default, @code{unprotoize}
+uses five spaces as the indentation. If you want to indent with just
+one space instead, use @samp{-i " "}.
+
+@item -k
+Keep the @samp{.X} files. Normally, they are deleted after conversion
+is finished.
+
+@item -l
+Add explicit local declarations. @code{protoize} with @samp{-l} inserts
+a prototype declaration for each function in each block which calls the
+function without any declaration. This option applies only to
+@code{protoize}.
+
+@item -n
+Make no real changes. This mode just prints information about the conversions
+that would have been done without @samp{-n}.
+
+@item -N
+Make no @samp{.save} files. The original files are simply deleted.
+Use this option with caution.
+
+@item -p @var{program}
+Use the program @var{program} as the compiler. Normally, the name
+@file{gcc} is used.
+
+@item -q
+Work quietly. Most warnings are suppressed.
+
+@item -v
+Print the version number, just like @samp{-v} for @code{gcc}.
+@end table
+
+If you need special compiler options to compile one of your program's
+source files, then you should generate that file's @samp{.X} file
+specially, by running @code{gcc} on that source file with the
+appropriate options and the option @samp{-aux-info}. Then run
+@code{protoize} on the entire set of files. @code{protoize} will use
+the existing @samp{.X} file because it is newer than the source file.
+For example:
+
+@example
+gcc -Dfoo=bar file1.c -aux-info
+protoize *.c
+@end example
+
+@noindent
+You need to include the special files along with the rest in the
+@code{protoize} command, even though their @samp{.X} files already
+exist, because otherwise they won't get converted.
+
+@xref{Protoize Caveats}, for more information on how to use
+@code{protoize} successfully.
+
diff --git a/gnu/usr.bin/cc/doc/md.texi b/gnu/usr.bin/cc/doc/md.texi
new file mode 100644
index 0000000..d29eabb
--- /dev/null
+++ b/gnu/usr.bin/cc/doc/md.texi
@@ -0,0 +1,3965 @@
+@c Copyright (C) 1988, 1989, 1992, 1993, 1994 Free Software Foundation, Inc.
+@c This is part of the GCC manual.
+@c For copying conditions, see the file gcc.texi.
+
+@ifset INTERNALS
+@node Machine Desc
+@chapter Machine Descriptions
+@cindex machine descriptions
+
+A machine description has two parts: a file of instruction patterns
+(@file{.md} file) and a C header file of macro definitions.
+
+The @file{.md} file for a target machine contains a pattern for each
+instruction that the target machine supports (or at least each instruction
+that is worth telling the compiler about). It may also contain comments.
+A semicolon causes the rest of the line to be a comment, unless the semicolon
+is inside a quoted string.
+
+See the next chapter for information on the C header file.
+
+@menu
+* Patterns:: How to write instruction patterns.
+* Example:: An explained example of a @code{define_insn} pattern.
+* RTL Template:: The RTL template defines what insns match a pattern.
+* Output Template:: The output template says how to make assembler code
+ from such an insn.
+* Output Statement:: For more generality, write C code to output
+ the assembler code.
+* Constraints:: When not all operands are general operands.
+* Standard Names:: Names mark patterns to use for code generation.
+* Pattern Ordering:: When the order of patterns makes a difference.
+* Dependent Patterns:: Having one pattern may make you need another.
+* Jump Patterns:: Special considerations for patterns for jump insns.
+* Insn Canonicalizations::Canonicalization of Instructions
+* Peephole Definitions::Defining machine-specific peephole optimizations.
+* Expander Definitions::Generating a sequence of several RTL insns
+ for a standard operation.
+* Insn Splitting:: Splitting Instructions into Multiple Instructions
+* Insn Attributes:: Specifying the value of attributes for generated insns.
+@end menu
+
+@node Patterns
+@section Everything about Instruction Patterns
+@cindex patterns
+@cindex instruction patterns
+
+@findex define_insn
+Each instruction pattern contains an incomplete RTL expression, with pieces
+to be filled in later, operand constraints that restrict how the pieces can
+be filled in, and an output pattern or C code to generate the assembler
+output, all wrapped up in a @code{define_insn} expression.
+
+A @code{define_insn} is an RTL expression containing four or five operands:
+
+@enumerate
+@item
+An optional name. The presence of a name indicate that this instruction
+pattern can perform a certain standard job for the RTL-generation
+pass of the compiler. This pass knows certain names and will use
+the instruction patterns with those names, if the names are defined
+in the machine description.
+
+The absence of a name is indicated by writing an empty string
+where the name should go. Nameless instruction patterns are never
+used for generating RTL code, but they may permit several simpler insns
+to be combined later on.
+
+Names that are not thus known and used in RTL-generation have no
+effect; they are equivalent to no name at all.
+
+@item
+The @dfn{RTL template} (@pxref{RTL Template}) is a vector of incomplete
+RTL expressions which show what the instruction should look like. It is
+incomplete because it may contain @code{match_operand},
+@code{match_operator}, and @code{match_dup} expressions that stand for
+operands of the instruction.
+
+If the vector has only one element, that element is the template for the
+instruction pattern. If the vector has multiple elements, then the
+instruction pattern is a @code{parallel} expression containing the
+elements described.
+
+@item
+@cindex pattern conditions
+@cindex conditions, in patterns
+A condition. This is a string which contains a C expression that is
+the final test to decide whether an insn body matches this pattern.
+
+@cindex named patterns and conditions
+For a named pattern, the condition (if present) may not depend on
+the data in the insn being matched, but only the target-machine-type
+flags. The compiler needs to test these conditions during
+initialization in order to learn exactly which named instructions are
+available in a particular run.
+
+@findex operands
+For nameless patterns, the condition is applied only when matching an
+individual insn, and only after the insn has matched the pattern's
+recognition template. The insn's operands may be found in the vector
+@code{operands}.
+
+@item
+The @dfn{output template}: a string that says how to output matching
+insns as assembler code. @samp{%} in this string specifies where
+to substitute the value of an operand. @xref{Output Template}.
+
+When simple substitution isn't general enough, you can specify a piece
+of C code to compute the output. @xref{Output Statement}.
+
+@item
+Optionally, a vector containing the values of attributes for insns matching
+this pattern. @xref{Insn Attributes}.
+@end enumerate
+
+@node Example
+@section Example of @code{define_insn}
+@cindex @code{define_insn} example
+
+Here is an actual example of an instruction pattern, for the 68000/68020.
+
+@example
+(define_insn "tstsi"
+ [(set (cc0)
+ (match_operand:SI 0 "general_operand" "rm"))]
+ ""
+ "*
+@{ if (TARGET_68020 || ! ADDRESS_REG_P (operands[0]))
+ return \"tstl %0\";
+ return \"cmpl #0,%0\"; @}")
+@end example
+
+This is an instruction that sets the condition codes based on the value of
+a general operand. It has no condition, so any insn whose RTL description
+has the form shown may be handled according to this pattern. The name
+@samp{tstsi} means ``test a @code{SImode} value'' and tells the RTL generation
+pass that, when it is necessary to test such a value, an insn to do so
+can be constructed using this pattern.
+
+The output control string is a piece of C code which chooses which
+output template to return based on the kind of operand and the specific
+type of CPU for which code is being generated.
+
+@samp{"rm"} is an operand constraint. Its meaning is explained below.
+
+@node RTL Template
+@section RTL Template
+@cindex RTL insn template
+@cindex generating insns
+@cindex insns, generating
+@cindex recognizing insns
+@cindex insns, recognizing
+
+The RTL template is used to define which insns match the particular pattern
+and how to find their operands. For named patterns, the RTL template also
+says how to construct an insn from specified operands.
+
+Construction involves substituting specified operands into a copy of the
+template. Matching involves determining the values that serve as the
+operands in the insn being matched. Both of these activities are
+controlled by special expression types that direct matching and
+substitution of the operands.
+
+@table @code
+@findex match_operand
+@item (match_operand:@var{m} @var{n} @var{predicate} @var{constraint})
+This expression is a placeholder for operand number @var{n} of
+the insn. When constructing an insn, operand number @var{n}
+will be substituted at this point. When matching an insn, whatever
+appears at this position in the insn will be taken as operand
+number @var{n}; but it must satisfy @var{predicate} or this instruction
+pattern will not match at all.
+
+Operand numbers must be chosen consecutively counting from zero in
+each instruction pattern. There may be only one @code{match_operand}
+expression in the pattern for each operand number. Usually operands
+are numbered in the order of appearance in @code{match_operand}
+expressions.
+
+@var{predicate} is a string that is the name of a C function that accepts two
+arguments, an expression and a machine mode. During matching, the
+function will be called with the putative operand as the expression and
+@var{m} as the mode argument (if @var{m} is not specified,
+@code{VOIDmode} will be used, which normally causes @var{predicate} to accept
+any mode). If it returns zero, this instruction pattern fails to match.
+@var{predicate} may be an empty string; then it means no test is to be done
+on the operand, so anything which occurs in this position is valid.
+
+Most of the time, @var{predicate} will reject modes other than @var{m}---but
+not always. For example, the predicate @code{address_operand} uses
+@var{m} as the mode of memory ref that the address should be valid for.
+Many predicates accept @code{const_int} nodes even though their mode is
+@code{VOIDmode}.
+
+@var{constraint} controls reloading and the choice of the best register
+class to use for a value, as explained later (@pxref{Constraints}).
+
+People are often unclear on the difference between the constraint and the
+predicate. The predicate helps decide whether a given insn matches the
+pattern. The constraint plays no role in this decision; instead, it
+controls various decisions in the case of an insn which does match.
+
+@findex general_operand
+On CISC machines, the most common @var{predicate} is
+@code{"general_operand"}. This function checks that the putative
+operand is either a constant, a register or a memory reference, and that
+it is valid for mode @var{m}.
+
+@findex register_operand
+For an operand that must be a register, @var{predicate} should be
+@code{"register_operand"}. Using @code{"general_operand"} would be
+valid, since the reload pass would copy any non-register operands
+through registers, but this would make GNU CC do extra work, it would
+prevent invariant operands (such as constant) from being removed from
+loops, and it would prevent the register allocator from doing the best
+possible job. On RISC machines, it is usually most efficient to allow
+@var{predicate} to accept only objects that the constraints allow.
+
+@findex immediate_operand
+For an operand that must be a constant, you must be sure to either use
+@code{"immediate_operand"} for @var{predicate}, or make the instruction
+pattern's extra condition require a constant, or both. You cannot
+expect the constraints to do this work! If the constraints allow only
+constants, but the predicate allows something else, the compiler will
+crash when that case arises.
+
+@findex match_scratch
+@item (match_scratch:@var{m} @var{n} @var{constraint})
+This expression is also a placeholder for operand number @var{n}
+and indicates that operand must be a @code{scratch} or @code{reg}
+expression.
+
+When matching patterns, this is equivalent to
+
+@smallexample
+(match_operand:@var{m} @var{n} "scratch_operand" @var{pred})
+@end smallexample
+
+but, when generating RTL, it produces a (@code{scratch}:@var{m})
+expression.
+
+If the last few expressions in a @code{parallel} are @code{clobber}
+expressions whose operands are either a hard register or
+@code{match_scratch}, the combiner can add or delete them when
+necessary. @xref{Side Effects}.
+
+@findex match_dup
+@item (match_dup @var{n})
+This expression is also a placeholder for operand number @var{n}.
+It is used when the operand needs to appear more than once in the
+insn.
+
+In construction, @code{match_dup} acts just like @code{match_operand}:
+the operand is substituted into the insn being constructed. But in
+matching, @code{match_dup} behaves differently. It assumes that operand
+number @var{n} has already been determined by a @code{match_operand}
+appearing earlier in the recognition template, and it matches only an
+identical-looking expression.
+
+@findex match_operator
+@item (match_operator:@var{m} @var{n} @var{predicate} [@var{operands}@dots{}])
+This pattern is a kind of placeholder for a variable RTL expression
+code.
+
+When constructing an insn, it stands for an RTL expression whose
+expression code is taken from that of operand @var{n}, and whose
+operands are constructed from the patterns @var{operands}.
+
+When matching an expression, it matches an expression if the function
+@var{predicate} returns nonzero on that expression @emph{and} the
+patterns @var{operands} match the operands of the expression.
+
+Suppose that the function @code{commutative_operator} is defined as
+follows, to match any expression whose operator is one of the
+commutative arithmetic operators of RTL and whose mode is @var{mode}:
+
+@smallexample
+int
+commutative_operator (x, mode)
+ rtx x;
+ enum machine_mode mode;
+@{
+ enum rtx_code code = GET_CODE (x);
+ if (GET_MODE (x) != mode)
+ return 0;
+ return (GET_RTX_CLASS (code) == 'c'
+ || code == EQ || code == NE);
+@}
+@end smallexample
+
+Then the following pattern will match any RTL expression consisting
+of a commutative operator applied to two general operands:
+
+@smallexample
+(match_operator:SI 3 "commutative_operator"
+ [(match_operand:SI 1 "general_operand" "g")
+ (match_operand:SI 2 "general_operand" "g")])
+@end smallexample
+
+Here the vector @code{[@var{operands}@dots{}]} contains two patterns
+because the expressions to be matched all contain two operands.
+
+When this pattern does match, the two operands of the commutative
+operator are recorded as operands 1 and 2 of the insn. (This is done
+by the two instances of @code{match_operand}.) Operand 3 of the insn
+will be the entire commutative expression: use @code{GET_CODE
+(operands[3])} to see which commutative operator was used.
+
+The machine mode @var{m} of @code{match_operator} works like that of
+@code{match_operand}: it is passed as the second argument to the
+predicate function, and that function is solely responsible for
+deciding whether the expression to be matched ``has'' that mode.
+
+When constructing an insn, argument 3 of the gen-function will specify
+the operation (i.e. the expression code) for the expression to be
+made. It should be an RTL expression, whose expression code is copied
+into a new expression whose operands are arguments 1 and 2 of the
+gen-function. The subexpressions of argument 3 are not used;
+only its expression code matters.
+
+When @code{match_operator} is used in a pattern for matching an insn,
+it usually best if the operand number of the @code{match_operator}
+is higher than that of the actual operands of the insn. This improves
+register allocation because the register allocator often looks at
+operands 1 and 2 of insns to see if it can do register tying.
+
+There is no way to specify constraints in @code{match_operator}. The
+operand of the insn which corresponds to the @code{match_operator}
+never has any constraints because it is never reloaded as a whole.
+However, if parts of its @var{operands} are matched by
+@code{match_operand} patterns, those parts may have constraints of
+their own.
+
+@findex match_op_dup
+@item (match_op_dup:@var{m} @var{n}[@var{operands}@dots{}])
+Like @code{match_dup}, except that it applies to operators instead of
+operands. When constructing an insn, operand number @var{n} will be
+substituted at this point. But in matching, @code{match_op_dup} behaves
+differently. It assumes that operand number @var{n} has already been
+determined by a @code{match_operator} appearing earlier in the
+recognition template, and it matches only an identical-looking
+expression.
+
+@findex match_parallel
+@item (match_parallel @var{n} @var{predicate} [@var{subpat}@dots{}])
+This pattern is a placeholder for an insn that consists of a
+@code{parallel} expression with a variable number of elements. This
+expression should only appear at the top level of an insn pattern.
+
+When constructing an insn, operand number @var{n} will be substituted at
+this point. When matching an insn, it matches if the body of the insn
+is a @code{parallel} expression with at least as many elements as the
+vector of @var{subpat} expressions in the @code{match_parallel}, if each
+@var{subpat} matches the corresponding element of the @code{parallel},
+@emph{and} the function @var{predicate} returns nonzero on the
+@code{parallel} that is the body of the insn. It is the responsibility
+of the predicate to validate elements of the @code{parallel} beyond
+those listed in the @code{match_parallel}.@refill
+
+A typical use of @code{match_parallel} is to match load and store
+multiple expressions, which can contain a variable number of elements
+in a @code{parallel}. For example,
+@c the following is *still* going over. need to change the code.
+@c also need to work on grouping of this example. --mew 1feb93
+
+@smallexample
+(define_insn ""
+ [(match_parallel 0 "load_multiple_operation"
+ [(set (match_operand:SI 1 "gpc_reg_operand" "=r")
+ (match_operand:SI 2 "memory_operand" "m"))
+ (use (reg:SI 179))
+ (clobber (reg:SI 179))])]
+ ""
+ "loadm 0,0,%1,%2")
+@end smallexample
+
+This example comes from @file{a29k.md}. The function
+@code{load_multiple_operations} is defined in @file{a29k.c} and checks
+that subsequent elements in the @code{parallel} are the same as the
+@code{set} in the pattern, except that they are referencing subsequent
+registers and memory locations.
+
+An insn that matches this pattern might look like:
+
+@smallexample
+(parallel
+ [(set (reg:SI 20) (mem:SI (reg:SI 100)))
+ (use (reg:SI 179))
+ (clobber (reg:SI 179))
+ (set (reg:SI 21)
+ (mem:SI (plus:SI (reg:SI 100)
+ (const_int 4))))
+ (set (reg:SI 22)
+ (mem:SI (plus:SI (reg:SI 100)
+ (const_int 8))))])
+@end smallexample
+
+@findex match_par_dup
+@item (match_par_dup @var{n} [@var{subpat}@dots{}])
+Like @code{match_op_dup}, but for @code{match_parallel} instead of
+@code{match_operator}.
+
+@findex address
+@item (address (match_operand:@var{m} @var{n} "address_operand" ""))
+This complex of expressions is a placeholder for an operand number
+@var{n} in a ``load address'' instruction: an operand which specifies
+a memory location in the usual way, but for which the actual operand
+value used is the address of the location, not the contents of the
+location.
+
+@code{address} expressions never appear in RTL code, only in machine
+descriptions. And they are used only in machine descriptions that do
+not use the operand constraint feature. When operand constraints are
+in use, the letter @samp{p} in the constraint serves this purpose.
+
+@var{m} is the machine mode of the @emph{memory location being
+addressed}, not the machine mode of the address itself. That mode is
+always the same on a given target machine (it is @code{Pmode}, which
+normally is @code{SImode}), so there is no point in mentioning it;
+thus, no machine mode is written in the @code{address} expression. If
+some day support is added for machines in which addresses of different
+kinds of objects appear differently or are used differently (such as
+the PDP-10), different formats would perhaps need different machine
+modes and these modes might be written in the @code{address}
+expression.
+@end table
+
+@node Output Template
+@section Output Templates and Operand Substitution
+@cindex output templates
+@cindex operand substitution
+
+@cindex @samp{%} in template
+@cindex percent sign
+The @dfn{output template} is a string which specifies how to output the
+assembler code for an instruction pattern. Most of the template is a
+fixed string which is output literally. The character @samp{%} is used
+to specify where to substitute an operand; it can also be used to
+identify places where different variants of the assembler require
+different syntax.
+
+In the simplest case, a @samp{%} followed by a digit @var{n} says to output
+operand @var{n} at that point in the string.
+
+@samp{%} followed by a letter and a digit says to output an operand in an
+alternate fashion. Four letters have standard, built-in meanings described
+below. The machine description macro @code{PRINT_OPERAND} can define
+additional letters with nonstandard meanings.
+
+@samp{%c@var{digit}} can be used to substitute an operand that is a
+constant value without the syntax that normally indicates an immediate
+operand.
+
+@samp{%n@var{digit}} is like @samp{%c@var{digit}} except that the value of
+the constant is negated before printing.
+
+@samp{%a@var{digit}} can be used to substitute an operand as if it were a
+memory reference, with the actual operand treated as the address. This may
+be useful when outputting a ``load address'' instruction, because often the
+assembler syntax for such an instruction requires you to write the operand
+as if it were a memory reference.
+
+@samp{%l@var{digit}} is used to substitute a @code{label_ref} into a jump
+instruction.
+
+@samp{%=} outputs a number which is unique to each instruction in the
+entire compilation. This is useful for making local labels to be
+referred to more than once in a single template that generates multiple
+assembler instructions.
+
+@samp{%} followed by a punctuation character specifies a substitution that
+does not use an operand. Only one case is standard: @samp{%%} outputs a
+@samp{%} into the assembler code. Other nonstandard cases can be
+defined in the @code{PRINT_OPERAND} macro. You must also define
+which punctuation characters are valid with the
+@code{PRINT_OPERAND_PUNCT_VALID_P} macro.
+
+@cindex \
+@cindex backslash
+The template may generate multiple assembler instructions. Write the text
+for the instructions, with @samp{\;} between them.
+
+@cindex matching operands
+When the RTL contains two operands which are required by constraint to match
+each other, the output template must refer only to the lower-numbered operand.
+Matching operands are not always identical, and the rest of the compiler
+arranges to put the proper RTL expression for printing into the lower-numbered
+operand.
+
+One use of nonstandard letters or punctuation following @samp{%} is to
+distinguish between different assembler languages for the same machine; for
+example, Motorola syntax versus MIT syntax for the 68000. Motorola syntax
+requires periods in most opcode names, while MIT syntax does not. For
+example, the opcode @samp{movel} in MIT syntax is @samp{move.l} in Motorola
+syntax. The same file of patterns is used for both kinds of output syntax,
+but the character sequence @samp{%.} is used in each place where Motorola
+syntax wants a period. The @code{PRINT_OPERAND} macro for Motorola syntax
+defines the sequence to output a period; the macro for MIT syntax defines
+it to do nothing.
+
+@cindex @code{#} in template
+As a special case, a template consisting of the single character @code{#}
+instructs the compiler to first split the insn, and then output the
+resulting instructions separately. This helps eliminate redundancy in the
+output templates. If you have a @code{define_insn} that needs to emit
+multiple assembler instructions, and there is an matching @code{define_split}
+already defined, then you can simply use @code{#} as the output template
+instead of writing an output template that emits the multiple assembler
+instructions.
+
+If @code{ASSEMBLER_DIALECT} is defined, you can use
+@samp{@{option0|option1|option2@}} constructs in the templates. These
+describe multiple variants of assembler language syntax.
+@xref{Instruction Output}.
+
+@node Output Statement
+@section C Statements for Assembler Output
+@cindex output statements
+@cindex C statements for assembler output
+@cindex generating assembler output
+
+Often a single fixed template string cannot produce correct and efficient
+assembler code for all the cases that are recognized by a single
+instruction pattern. For example, the opcodes may depend on the kinds of
+operands; or some unfortunate combinations of operands may require extra
+machine instructions.
+
+If the output control string starts with a @samp{@@}, then it is actually
+a series of templates, each on a separate line. (Blank lines and
+leading spaces and tabs are ignored.) The templates correspond to the
+pattern's constraint alternatives (@pxref{Multi-Alternative}). For example,
+if a target machine has a two-address add instruction @samp{addr} to add
+into a register and another @samp{addm} to add a register to memory, you
+might write this pattern:
+
+@smallexample
+(define_insn "addsi3"
+ [(set (match_operand:SI 0 "general_operand" "=r,m")
+ (plus:SI (match_operand:SI 1 "general_operand" "0,0")
+ (match_operand:SI 2 "general_operand" "g,r")))]
+ ""
+ "@@
+ addr %2,%0
+ addm %2,%0")
+@end smallexample
+
+@cindex @code{*} in template
+@cindex asterisk in template
+If the output control string starts with a @samp{*}, then it is not an
+output template but rather a piece of C program that should compute a
+template. It should execute a @code{return} statement to return the
+template-string you want. Most such templates use C string literals, which
+require doublequote characters to delimit them. To include these
+doublequote characters in the string, prefix each one with @samp{\}.
+
+The operands may be found in the array @code{operands}, whose C data type
+is @code{rtx []}.
+
+It is very common to select different ways of generating assembler code
+based on whether an immediate operand is within a certain range. Be
+careful when doing this, because the result of @code{INTVAL} is an
+integer on the host machine. If the host machine has more bits in an
+@code{int} than the target machine has in the mode in which the constant
+will be used, then some of the bits you get from @code{INTVAL} will be
+superfluous. For proper results, you must carefully disregard the
+values of those bits.
+
+@findex output_asm_insn
+It is possible to output an assembler instruction and then go on to output
+or compute more of them, using the subroutine @code{output_asm_insn}. This
+receives two arguments: a template-string and a vector of operands. The
+vector may be @code{operands}, or it may be another array of @code{rtx}
+that you declare locally and initialize yourself.
+
+@findex which_alternative
+When an insn pattern has multiple alternatives in its constraints, often
+the appearance of the assembler code is determined mostly by which alternative
+was matched. When this is so, the C code can test the variable
+@code{which_alternative}, which is the ordinal number of the alternative
+that was actually satisfied (0 for the first, 1 for the second alternative,
+etc.).
+
+For example, suppose there are two opcodes for storing zero, @samp{clrreg}
+for registers and @samp{clrmem} for memory locations. Here is how
+a pattern could use @code{which_alternative} to choose between them:
+
+@smallexample
+(define_insn ""
+ [(set (match_operand:SI 0 "general_operand" "=r,m")
+ (const_int 0))]
+ ""
+ "*
+ return (which_alternative == 0
+ ? \"clrreg %0\" : \"clrmem %0\");
+ ")
+@end smallexample
+
+The example above, where the assembler code to generate was
+@emph{solely} determined by the alternative, could also have been specified
+as follows, having the output control string start with a @samp{@@}:
+
+@smallexample
+@group
+(define_insn ""
+ [(set (match_operand:SI 0 "general_operand" "=r,m")
+ (const_int 0))]
+ ""
+ "@@
+ clrreg %0
+ clrmem %0")
+@end group
+@end smallexample
+@end ifset
+
+@c Most of this node appears by itself (in a different place) even
+@c when the INTERNALS flag is clear. Passages that require the full
+@c manual's context are conditionalized to appear only in the full manual.
+@ifset INTERNALS
+@node Constraints
+@section Operand Constraints
+@cindex operand constraints
+@cindex constraints
+
+Each @code{match_operand} in an instruction pattern can specify a
+constraint for the type of operands allowed.
+@end ifset
+@ifclear INTERNALS
+@node Constraints
+@section Constraints for @code{asm} Operands
+@cindex operand constraints, @code{asm}
+@cindex constraints, @code{asm}
+@cindex @code{asm} constraints
+
+Here are specific details on what constraint letters you can use with
+@code{asm} operands.
+@end ifclear
+Constraints can say whether
+an operand may be in a register, and which kinds of register; whether the
+operand can be a memory reference, and which kinds of address; whether the
+operand may be an immediate constant, and which possible values it may
+have. Constraints can also require two operands to match.
+
+@ifset INTERNALS
+@menu
+* Simple Constraints:: Basic use of constraints.
+* Multi-Alternative:: When an insn has two alternative constraint-patterns.
+* Class Preferences:: Constraints guide which hard register to put things in.
+* Modifiers:: More precise control over effects of constraints.
+* Machine Constraints:: Existing constraints for some particular machines.
+* No Constraints:: Describing a clean machine without constraints.
+@end menu
+@end ifset
+
+@ifclear INTERNALS
+@menu
+* Simple Constraints:: Basic use of constraints.
+* Multi-Alternative:: When an insn has two alternative constraint-patterns.
+* Modifiers:: More precise control over effects of constraints.
+* Machine Constraints:: Special constraints for some particular machines.
+@end menu
+@end ifclear
+
+@node Simple Constraints
+@subsection Simple Constraints
+@cindex simple constraints
+
+The simplest kind of constraint is a string full of letters, each of
+which describes one kind of operand that is permitted. Here are
+the letters that are allowed:
+
+@table @asis
+@cindex @samp{m} in constraint
+@cindex memory references in constraints
+@item @samp{m}
+A memory operand is allowed, with any kind of address that the machine
+supports in general.
+
+@cindex offsettable address
+@cindex @samp{o} in constraint
+@item @samp{o}
+A memory operand is allowed, but only if the address is
+@dfn{offsettable}. This means that adding a small integer (actually,
+the width in bytes of the operand, as determined by its machine mode)
+may be added to the address and the result is also a valid memory
+address.
+
+@cindex autoincrement/decrement addressing
+For example, an address which is constant is offsettable; so is an
+address that is the sum of a register and a constant (as long as a
+slightly larger constant is also within the range of address-offsets
+supported by the machine); but an autoincrement or autodecrement
+address is not offsettable. More complicated indirect/indexed
+addresses may or may not be offsettable depending on the other
+addressing modes that the machine supports.
+
+Note that in an output operand which can be matched by another
+operand, the constraint letter @samp{o} is valid only when accompanied
+by both @samp{<} (if the target machine has predecrement addressing)
+and @samp{>} (if the target machine has preincrement addressing).
+
+@cindex @samp{V} in constraint
+@item @samp{V}
+A memory operand that is not offsettable. In other words, anything that
+would fit the @samp{m} constraint but not the @samp{o} constraint.
+
+@cindex @samp{<} in constraint
+@item @samp{<}
+A memory operand with autodecrement addressing (either predecrement or
+postdecrement) is allowed.
+
+@cindex @samp{>} in constraint
+@item @samp{>}
+A memory operand with autoincrement addressing (either preincrement or
+postincrement) is allowed.
+
+@cindex @samp{r} in constraint
+@cindex registers in constraints
+@item @samp{r}
+A register operand is allowed provided that it is in a general
+register.
+
+@cindex @samp{d} in constraint
+@item @samp{d}, @samp{a}, @samp{f}, @dots{}
+Other letters can be defined in machine-dependent fashion to stand for
+particular classes of registers. @samp{d}, @samp{a} and @samp{f} are
+defined on the 68000/68020 to stand for data, address and floating
+point registers.
+
+@cindex constants in constraints
+@cindex @samp{i} in constraint
+@item @samp{i}
+An immediate integer operand (one with constant value) is allowed.
+This includes symbolic constants whose values will be known only at
+assembly time.
+
+@cindex @samp{n} in constraint
+@item @samp{n}
+An immediate integer operand with a known numeric value is allowed.
+Many systems cannot support assembly-time constants for operands less
+than a word wide. Constraints for these operands should use @samp{n}
+rather than @samp{i}.
+
+@cindex @samp{I} in constraint
+@item @samp{I}, @samp{J}, @samp{K}, @dots{} @samp{P}
+Other letters in the range @samp{I} through @samp{P} may be defined in
+a machine-dependent fashion to permit immediate integer operands with
+explicit integer values in specified ranges. For example, on the
+68000, @samp{I} is defined to stand for the range of values 1 to 8.
+This is the range permitted as a shift count in the shift
+instructions.
+
+@cindex @samp{E} in constraint
+@item @samp{E}
+An immediate floating operand (expression code @code{const_double}) is
+allowed, but only if the target floating point format is the same as
+that of the host machine (on which the compiler is running).
+
+@cindex @samp{F} in constraint
+@item @samp{F}
+An immediate floating operand (expression code @code{const_double}) is
+allowed.
+
+@cindex @samp{G} in constraint
+@cindex @samp{H} in constraint
+@item @samp{G}, @samp{H}
+@samp{G} and @samp{H} may be defined in a machine-dependent fashion to
+permit immediate floating operands in particular ranges of values.
+
+@cindex @samp{s} in constraint
+@item @samp{s}
+An immediate integer operand whose value is not an explicit integer is
+allowed.
+
+This might appear strange; if an insn allows a constant operand with a
+value not known at compile time, it certainly must allow any known
+value. So why use @samp{s} instead of @samp{i}? Sometimes it allows
+better code to be generated.
+
+For example, on the 68000 in a fullword instruction it is possible to
+use an immediate operand; but if the immediate value is between -128
+and 127, better code results from loading the value into a register and
+using the register. This is because the load into the register can be
+done with a @samp{moveq} instruction. We arrange for this to happen
+by defining the letter @samp{K} to mean ``any integer outside the
+range -128 to 127'', and then specifying @samp{Ks} in the operand
+constraints.
+
+@cindex @samp{g} in constraint
+@item @samp{g}
+Any register, memory or immediate integer operand is allowed, except for
+registers that are not general registers.
+
+@cindex @samp{X} in constraint
+@item @samp{X}
+@ifset INTERNALS
+Any operand whatsoever is allowed, even if it does not satisfy
+@code{general_operand}. This is normally used in the constraint of
+a @code{match_scratch} when certain alternatives will not actually
+require a scratch register.
+@end ifset
+@ifclear INTERNALS
+Any operand whatsoever is allowed.
+@end ifclear
+
+@cindex @samp{0} in constraint
+@cindex digits in constraint
+@item @samp{0}, @samp{1}, @samp{2}, @dots{} @samp{9}
+An operand that matches the specified operand number is allowed. If a
+digit is used together with letters within the same alternative, the
+digit should come last.
+
+@cindex matching constraint
+@cindex constraint, matching
+This is called a @dfn{matching constraint} and what it really means is
+that the assembler has only a single operand that fills two roles
+@ifset INTERNALS
+considered separate in the RTL insn. For example, an add insn has two
+input operands and one output operand in the RTL, but on most CISC
+@end ifset
+@ifclear INTERNALS
+which @code{asm} distinguishes. For example, an add instruction uses
+two input operands and an output operand, but on most CISC
+@end ifclear
+machines an add instruction really has only two operands, one of them an
+input-output operand:
+
+@smallexample
+addl #35,r12
+@end smallexample
+
+Matching constraints are used in these circumstances.
+More precisely, the two operands that match must include one input-only
+operand and one output-only operand. Moreover, the digit must be a
+smaller number than the number of the operand that uses it in the
+constraint.
+
+@ifset INTERNALS
+For operands to match in a particular case usually means that they
+are identical-looking RTL expressions. But in a few special cases
+specific kinds of dissimilarity are allowed. For example, @code{*x}
+as an input operand will match @code{*x++} as an output operand.
+For proper results in such cases, the output template should always
+use the output-operand's number when printing the operand.
+@end ifset
+
+@cindex load address instruction
+@cindex push address instruction
+@cindex address constraints
+@cindex @samp{p} in constraint
+@item @samp{p}
+An operand that is a valid memory address is allowed. This is
+for ``load address'' and ``push address'' instructions.
+
+@findex address_operand
+@samp{p} in the constraint must be accompanied by @code{address_operand}
+as the predicate in the @code{match_operand}. This predicate interprets
+the mode specified in the @code{match_operand} as the mode of the memory
+reference for which the address would be valid.
+
+@cindex extensible constraints
+@cindex @samp{Q}, in constraint
+@item @samp{Q}, @samp{R}, @samp{S}, @dots{} @samp{U}
+Letters in the range @samp{Q} through @samp{U} may be defined in a
+machine-dependent fashion to stand for arbitrary operand types.
+@ifset INTERNALS
+The machine description macro @code{EXTRA_CONSTRAINT} is passed the
+operand as its first argument and the constraint letter as its
+second operand.
+
+A typical use for this would be to distinguish certain types of
+memory references that affect other insn operands.
+
+Do not define these constraint letters to accept register references
+(@code{reg}); the reload pass does not expect this and would not handle
+it properly.
+@end ifset
+@end table
+
+@ifset INTERNALS
+In order to have valid assembler code, each operand must satisfy
+its constraint. But a failure to do so does not prevent the pattern
+from applying to an insn. Instead, it directs the compiler to modify
+the code so that the constraint will be satisfied. Usually this is
+done by copying an operand into a register.
+
+Contrast, therefore, the two instruction patterns that follow:
+
+@smallexample
+(define_insn ""
+ [(set (match_operand:SI 0 "general_operand" "=r")
+ (plus:SI (match_dup 0)
+ (match_operand:SI 1 "general_operand" "r")))]
+ ""
+ "@dots{}")
+@end smallexample
+
+@noindent
+which has two operands, one of which must appear in two places, and
+
+@smallexample
+(define_insn ""
+ [(set (match_operand:SI 0 "general_operand" "=r")
+ (plus:SI (match_operand:SI 1 "general_operand" "0")
+ (match_operand:SI 2 "general_operand" "r")))]
+ ""
+ "@dots{}")
+@end smallexample
+
+@noindent
+which has three operands, two of which are required by a constraint to be
+identical. If we are considering an insn of the form
+
+@smallexample
+(insn @var{n} @var{prev} @var{next}
+ (set (reg:SI 3)
+ (plus:SI (reg:SI 6) (reg:SI 109)))
+ @dots{})
+@end smallexample
+
+@noindent
+the first pattern would not apply at all, because this insn does not
+contain two identical subexpressions in the right place. The pattern would
+say, ``That does not look like an add instruction; try other patterns.''
+The second pattern would say, ``Yes, that's an add instruction, but there
+is something wrong with it.'' It would direct the reload pass of the
+compiler to generate additional insns to make the constraint true. The
+results might look like this:
+
+@smallexample
+(insn @var{n2} @var{prev} @var{n}
+ (set (reg:SI 3) (reg:SI 6))
+ @dots{})
+
+(insn @var{n} @var{n2} @var{next}
+ (set (reg:SI 3)
+ (plus:SI (reg:SI 3) (reg:SI 109)))
+ @dots{})
+@end smallexample
+
+It is up to you to make sure that each operand, in each pattern, has
+constraints that can handle any RTL expression that could be present for
+that operand. (When multiple alternatives are in use, each pattern must,
+for each possible combination of operand expressions, have at least one
+alternative which can handle that combination of operands.) The
+constraints don't need to @emph{allow} any possible operand---when this is
+the case, they do not constrain---but they must at least point the way to
+reloading any possible operand so that it will fit.
+
+@itemize @bullet
+@item
+If the constraint accepts whatever operands the predicate permits,
+there is no problem: reloading is never necessary for this operand.
+
+For example, an operand whose constraints permit everything except
+registers is safe provided its predicate rejects registers.
+
+An operand whose predicate accepts only constant values is safe
+provided its constraints include the letter @samp{i}. If any possible
+constant value is accepted, then nothing less than @samp{i} will do;
+if the predicate is more selective, then the constraints may also be
+more selective.
+
+@item
+Any operand expression can be reloaded by copying it into a register.
+So if an operand's constraints allow some kind of register, it is
+certain to be safe. It need not permit all classes of registers; the
+compiler knows how to copy a register into another register of the
+proper class in order to make an instruction valid.
+
+@cindex nonoffsettable memory reference
+@cindex memory reference, nonoffsettable
+@item
+A nonoffsettable memory reference can be reloaded by copying the
+address into a register. So if the constraint uses the letter
+@samp{o}, all memory references are taken care of.
+
+@item
+A constant operand can be reloaded by allocating space in memory to
+hold it as preinitialized data. Then the memory reference can be used
+in place of the constant. So if the constraint uses the letters
+@samp{o} or @samp{m}, constant operands are not a problem.
+
+@item
+If the constraint permits a constant and a pseudo register used in an insn
+was not allocated to a hard register and is equivalent to a constant,
+the register will be replaced with the constant. If the predicate does
+not permit a constant and the insn is re-recognized for some reason, the
+compiler will crash. Thus the predicate must always recognize any
+objects allowed by the constraint.
+@end itemize
+
+If the operand's predicate can recognize registers, but the constraint does
+not permit them, it can make the compiler crash. When this operand happens
+to be a register, the reload pass will be stymied, because it does not know
+how to copy a register temporarily into memory.
+@end ifset
+
+@node Multi-Alternative
+@subsection Multiple Alternative Constraints
+@cindex multiple alternative constraints
+
+Sometimes a single instruction has multiple alternative sets of possible
+operands. For example, on the 68000, a logical-or instruction can combine
+register or an immediate value into memory, or it can combine any kind of
+operand into a register; but it cannot combine one memory location into
+another.
+
+These constraints are represented as multiple alternatives. An alternative
+can be described by a series of letters for each operand. The overall
+constraint for an operand is made from the letters for this operand
+from the first alternative, a comma, the letters for this operand from
+the second alternative, a comma, and so on until the last alternative.
+@ifset INTERNALS
+Here is how it is done for fullword logical-or on the 68000:
+
+@smallexample
+(define_insn "iorsi3"
+ [(set (match_operand:SI 0 "general_operand" "=m,d")
+ (ior:SI (match_operand:SI 1 "general_operand" "%0,0")
+ (match_operand:SI 2 "general_operand" "dKs,dmKs")))]
+ @dots{})
+@end smallexample
+
+The first alternative has @samp{m} (memory) for operand 0, @samp{0} for
+operand 1 (meaning it must match operand 0), and @samp{dKs} for operand
+2. The second alternative has @samp{d} (data register) for operand 0,
+@samp{0} for operand 1, and @samp{dmKs} for operand 2. The @samp{=} and
+@samp{%} in the constraints apply to all the alternatives; their
+meaning is explained in the next section (@pxref{Class Preferences}).
+@end ifset
+
+@c FIXME Is this ? and ! stuff of use in asm()? If not, hide unless INTERNAL
+If all the operands fit any one alternative, the instruction is valid.
+Otherwise, for each alternative, the compiler counts how many instructions
+must be added to copy the operands so that that alternative applies.
+The alternative requiring the least copying is chosen. If two alternatives
+need the same amount of copying, the one that comes first is chosen.
+These choices can be altered with the @samp{?} and @samp{!} characters:
+
+@table @code
+@cindex @samp{?} in constraint
+@cindex question mark
+@item ?
+Disparage slightly the alternative that the @samp{?} appears in,
+as a choice when no alternative applies exactly. The compiler regards
+this alternative as one unit more costly for each @samp{?} that appears
+in it.
+
+@cindex @samp{!} in constraint
+@cindex exclamation point
+@item !
+Disparage severely the alternative that the @samp{!} appears in.
+This alternative can still be used if it fits without reloading,
+but if reloading is needed, some other alternative will be used.
+@end table
+
+@ifset INTERNALS
+When an insn pattern has multiple alternatives in its constraints, often
+the appearance of the assembler code is determined mostly by which
+alternative was matched. When this is so, the C code for writing the
+assembler code can use the variable @code{which_alternative}, which is
+the ordinal number of the alternative that was actually satisfied (0 for
+the first, 1 for the second alternative, etc.). @xref{Output Statement}.
+@end ifset
+
+@ifset INTERNALS
+@node Class Preferences
+@subsection Register Class Preferences
+@cindex class preference constraints
+@cindex register class preference constraints
+
+@cindex voting between constraint alternatives
+The operand constraints have another function: they enable the compiler
+to decide which kind of hardware register a pseudo register is best
+allocated to. The compiler examines the constraints that apply to the
+insns that use the pseudo register, looking for the machine-dependent
+letters such as @samp{d} and @samp{a} that specify classes of registers.
+The pseudo register is put in whichever class gets the most ``votes''.
+The constraint letters @samp{g} and @samp{r} also vote: they vote in
+favor of a general register. The machine description says which registers
+are considered general.
+
+Of course, on some machines all registers are equivalent, and no register
+classes are defined. Then none of this complexity is relevant.
+@end ifset
+
+@node Modifiers
+@subsection Constraint Modifier Characters
+@cindex modifiers in constraints
+@cindex constraint modifier characters
+
+@c prevent bad page break with this line
+Here are constraint modifier characters.
+
+@table @samp
+@cindex @samp{=} in constraint
+@item =
+Means that this operand is write-only for this instruction: the previous
+value is discarded and replaced by output data.
+
+@cindex @samp{+} in constraint
+@item +
+Means that this operand is both read and written by the instruction.
+
+When the compiler fixes up the operands to satisfy the constraints,
+it needs to know which operands are inputs to the instruction and
+which are outputs from it. @samp{=} identifies an output; @samp{+}
+identifies an operand that is both input and output; all other operands
+are assumed to be input only.
+
+@cindex @samp{&} in constraint
+@item &
+Means (in a particular alternative) that this operand is written
+before the instruction is finished using the input operands.
+Therefore, this operand may not lie in a register that is used as an
+input operand or as part of any memory address.
+
+@samp{&} applies only to the alternative in which it is written. In
+constraints with multiple alternatives, sometimes one alternative
+requires @samp{&} while others do not. See, for example, the
+@samp{movdf} insn of the 68000.
+
+@samp{&} does not obviate the need to write @samp{=}.
+
+@cindex @samp{%} in constraint
+@item %
+Declares the instruction to be commutative for this operand and the
+following operand. This means that the compiler may interchange the
+two operands if that is the cheapest way to make all operands fit the
+constraints.
+@ifset INTERNALS
+This is often used in patterns for addition instructions
+that really have only two operands: the result must go in one of the
+arguments. Here for example, is how the 68000 halfword-add
+instruction is defined:
+
+@smallexample
+(define_insn "addhi3"
+ [(set (match_operand:HI 0 "general_operand" "=m,r")
+ (plus:HI (match_operand:HI 1 "general_operand" "%0,0")
+ (match_operand:HI 2 "general_operand" "di,g")))]
+ @dots{})
+@end smallexample
+@end ifset
+
+@cindex @samp{#} in constraint
+@item #
+Says that all following characters, up to the next comma, are to be
+ignored as a constraint. They are significant only for choosing
+register preferences.
+
+@ifset INTERNALS
+@cindex @samp{*} in constraint
+@item *
+Says that the following character should be ignored when choosing
+register preferences. @samp{*} has no effect on the meaning of the
+constraint as a constraint, and no effect on reloading.
+
+Here is an example: the 68000 has an instruction to sign-extend a
+halfword in a data register, and can also sign-extend a value by
+copying it into an address register. While either kind of register is
+acceptable, the constraints on an address-register destination are
+less strict, so it is best if register allocation makes an address
+register its goal. Therefore, @samp{*} is used so that the @samp{d}
+constraint letter (for data register) is ignored when computing
+register preferences.
+
+@smallexample
+(define_insn "extendhisi2"
+ [(set (match_operand:SI 0 "general_operand" "=*d,a")
+ (sign_extend:SI
+ (match_operand:HI 1 "general_operand" "0,g")))]
+ @dots{})
+@end smallexample
+@end ifset
+@end table
+
+@node Machine Constraints
+@subsection Constraints for Particular Machines
+@cindex machine specific constraints
+@cindex constraints, machine specific
+
+Whenever possible, you should use the general-purpose constraint letters
+in @code{asm} arguments, since they will convey meaning more readily to
+people reading your code. Failing that, use the constraint letters
+that usually have very similar meanings across architectures. The most
+commonly used constraints are @samp{m} and @samp{r} (for memory and
+general-purpose registers respectively; @pxref{Simple Constraints}), and
+@samp{I}, usually the letter indicating the most common
+immediate-constant format.
+
+For each machine architecture, the @file{config/@var{machine}.h} file
+defines additional constraints. These constraints are used by the
+compiler itself for instruction generation, as well as for @code{asm}
+statements; therefore, some of the constraints are not particularly
+interesting for @code{asm}. The constraints are defined through these
+macros:
+
+@table @code
+@item REG_CLASS_FROM_LETTER
+Register class constraints (usually lower case).
+
+@item CONST_OK_FOR_LETTER_P
+Immediate constant constraints, for non-floating point constants of
+word size or smaller precision (usually upper case).
+
+@item CONST_DOUBLE_OK_FOR_LETTER_P
+Immediate constant constraints, for all floating point constants and for
+constants of greater than word size precision (usually upper case).
+
+@item EXTRA_CONSTRAINT
+Special cases of registers or memory. This macro is not required, and
+is only defined for some machines.
+@end table
+
+Inspecting these macro definitions in the compiler source for your
+machine is the best way to be certain you have the right constraints.
+However, here is a summary of the machine-dependent constraints
+available on some particular machines.
+
+@table @emph
+@item ARM family---@file{arm.h}
+@table @code
+@item f
+Floating-point register
+
+@item F
+One of the floating-point constants 0.0, 0.5, 1.0, 2.0, 3.0, 4.0, 5.0
+or 10.0
+
+@item G
+Floating-point constant that would satisfy the constraint @samp{F} if it
+were negated
+
+@item I
+Integer that is valid as an immediate operand in a data processing
+instruction. That is, an integer in the range 0 to 255 rotated by a
+multiple of 2
+
+@item J
+Integer in the range -4095 to 4095
+
+@item K
+Integer that satisfies constraint @samp{I} when inverted (ones complement)
+
+@item L
+Integer that satisfies constraint @samp{I} when negated (twos complement)
+
+@item M
+Integer in the range 0 to 32
+
+@item Q
+A memory reference where the exact address is in a single register
+(`@samp{m}' is preferable for @code{asm} statements)
+
+@item R
+An item in the constant pool
+
+@item S
+A symbol in the text segment of the current file
+@end table
+
+@item AMD 29000 family---@file{a29k.h}
+@table @code
+@item l
+Local register 0
+
+@item b
+Byte Pointer (@samp{BP}) register
+
+@item q
+@samp{Q} register
+
+@item h
+Special purpose register
+
+@item A
+First accumulator register
+
+@item a
+Other accumulator register
+
+@item f
+Floating point register
+
+@item I
+Constant greater than 0, less than 0x100
+
+@item J
+Constant greater than 0, less than 0x10000
+
+@item K
+Constant whose high 24 bits are on (1)
+
+@item L
+16 bit constant whose high 8 bits are on (1)
+
+@item M
+32 bit constant whose high 16 bits are on (1)
+
+@item N
+32 bit negative constant that fits in 8 bits
+
+@item O
+The constant 0x80000000 or, on the 29050, any 32 bit constant
+whose low 16 bits are 0.
+
+@item P
+16 bit negative constant that fits in 8 bits
+
+@item G
+@itemx H
+A floating point constant (in @code{asm} statements, use the machine
+independent @samp{E} or @samp{F} instead)
+@end table
+
+@item IBM RS6000---@file{rs6000.h}
+@table @code
+@item b
+Address base register
+
+@item f
+Floating point register
+
+@item h
+@samp{MQ}, @samp{CTR}, or @samp{LINK} register
+
+@item q
+@samp{MQ} register
+
+@item c
+@samp{CTR} register
+
+@item l
+@samp{LINK} register
+
+@item x
+@samp{CR} register (condition register) number 0
+
+@item y
+@samp{CR} register (condition register)
+
+@item I
+Signed 16 bit constant
+
+@item J
+Constant whose low 16 bits are 0
+
+@item K
+Constant whose high 16 bits are 0
+
+@item L
+Constant suitable as a mask operand
+
+@item M
+Constant larger than 31
+
+@item N
+Exact power of 2
+
+@item O
+Zero
+
+@item P
+Constant whose negation is a signed 16 bit constant
+
+@item G
+Floating point constant that can be loaded into a register with one
+instruction per word
+
+@item Q
+Memory operand that is an offset from a register (@samp{m} is preferable
+for @code{asm} statements)
+@end table
+
+@item Intel 386---@file{i386.h}
+@table @code
+@item q
+@samp{a}, @code{b}, @code{c}, or @code{d} register
+
+@item A
+@samp{a}, or @code{d} register (for 64-bit ints)
+
+@item f
+Floating point register
+
+@item t
+First (top of stack) floating point register
+
+@item u
+Second floating point register
+
+@item a
+@samp{a} register
+
+@item b
+@samp{b} register
+
+@item c
+@samp{c} register
+
+@item d
+@samp{d} register
+
+@item D
+@samp{di} register
+
+@item S
+@samp{si} register
+
+@item I
+Constant in range 0 to 31 (for 32 bit shifts)
+
+@item J
+Constant in range 0 to 63 (for 64 bit shifts)
+
+@item K
+@samp{0xff}
+
+@item L
+@samp{0xffff}
+
+@item M
+0, 1, 2, or 3 (shifts for @code{lea} instruction)
+
+@item G
+Standard 80387 floating point constant
+@end table
+
+@item Intel 960---@file{i960.h}
+@table @code
+@item f
+Floating point register (@code{fp0} to @code{fp3})
+
+@item l
+Local register (@code{r0} to @code{r15})
+
+@item b
+Global register (@code{g0} to @code{g15})
+
+@item d
+Any local or global register
+
+@item I
+Integers from 0 to 31
+
+@item J
+0
+
+@item K
+Integers from -31 to 0
+
+@item G
+Floating point 0
+
+@item H
+Floating point 1
+@end table
+
+@item MIPS---@file{mips.h}
+@table @code
+@item d
+General-purpose integer register
+
+@item f
+Floating-point register (if available)
+
+@item h
+@samp{Hi} register
+
+@item l
+@samp{Lo} register
+
+@item x
+@samp{Hi} or @samp{Lo} register
+
+@item y
+General-purpose integer register
+
+@item z
+Floating-point status register
+
+@item I
+Signed 16 bit constant (for arithmetic instructions)
+
+@item J
+Zero
+
+@item K
+Zero-extended 16-bit constant (for logic instructions)
+
+@item L
+Constant with low 16 bits zero (can be loaded with @code{lui})
+
+@item M
+32 bit constant which requires two instructions to load (a constant
+which is not @samp{I}, @samp{K}, or @samp{L})
+
+@item N
+Negative 16 bit constant
+
+@item O
+Exact power of two
+
+@item P
+Positive 16 bit constant
+
+@item G
+Floating point zero
+
+@item Q
+Memory reference that can be loaded with more than one instruction
+(@samp{m} is preferable for @code{asm} statements)
+
+@item R
+Memory reference that can be loaded with one instruction
+(@samp{m} is preferable for @code{asm} statements)
+
+@item S
+Memory reference in external OSF/rose PIC format
+(@samp{m} is preferable for @code{asm} statements)
+@end table
+
+@item Motorola 680x0---@file{m68k.h}
+@table @code
+@item a
+Address register
+
+@item d
+Data register
+
+@item f
+68881 floating-point register, if available
+
+@item x
+Sun FPA (floating-point) register, if available
+
+@item y
+First 16 Sun FPA registers, if available
+
+@item I
+Integer in the range 1 to 8
+
+@item J
+16 bit signed number
+
+@item K
+Signed number whose magnitude is greater than 0x80
+
+@item L
+Integer in the range -8 to -1
+
+@item G
+Floating point constant that is not a 68881 constant
+
+@item H
+Floating point constant that can be used by Sun FPA
+@end table
+
+@need 1000
+@item SPARC---@file{sparc.h}
+@table @code
+@item f
+Floating-point register
+
+@item I
+Signed 13 bit constant
+
+@item J
+Zero
+
+@item K
+32 bit constant with the low 12 bits clear (a constant that can be
+loaded with the @code{sethi} instruction)
+
+@item G
+Floating-point zero
+
+@item H
+Signed 13 bit constant, sign-extended to 32 or 64 bits
+
+@item Q
+Memory reference that can be loaded with one instruction (@samp{m} is
+more appropriate for @code{asm} statements)
+
+@item S
+Constant, or memory address
+
+@item T
+Memory address aligned to an 8-byte boundary
+
+@item U
+Even register
+@end table
+@end table
+
+@ifset INTERNALS
+@node No Constraints
+@subsection Not Using Constraints
+@cindex no constraints
+@cindex not using constraints
+
+Some machines are so clean that operand constraints are not required. For
+example, on the Vax, an operand valid in one context is valid in any other
+context. On such a machine, every operand constraint would be @samp{g},
+excepting only operands of ``load address'' instructions which are
+written as if they referred to a memory location's contents but actual
+refer to its address. They would have constraint @samp{p}.
+
+@cindex empty constraints
+For such machines, instead of writing @samp{g} and @samp{p} for all
+the constraints, you can choose to write a description with empty constraints.
+Then you write @samp{""} for the constraint in every @code{match_operand}.
+Address operands are identified by writing an @code{address} expression
+around the @code{match_operand}, not by their constraints.
+
+When the machine description has just empty constraints, certain parts
+of compilation are skipped, making the compiler faster. However,
+few machines actually do not need constraints; all machine descriptions
+now in existence use constraints.
+@end ifset
+
+@ifset INTERNALS
+@node Standard Names
+@section Standard Pattern Names For Generation
+@cindex standard pattern names
+@cindex pattern names
+@cindex names, pattern
+
+Here is a table of the instruction names that are meaningful in the RTL
+generation pass of the compiler. Giving one of these names to an
+instruction pattern tells the RTL generation pass that it can use the
+pattern in to accomplish a certain task.
+
+@table @asis
+@cindex @code{mov@var{m}} instruction pattern
+@item @samp{mov@var{m}}
+Here @var{m} stands for a two-letter machine mode name, in lower case.
+This instruction pattern moves data with that machine mode from operand
+1 to operand 0. For example, @samp{movsi} moves full-word data.
+
+If operand 0 is a @code{subreg} with mode @var{m} of a register whose
+own mode is wider than @var{m}, the effect of this instruction is
+to store the specified value in the part of the register that corresponds
+to mode @var{m}. The effect on the rest of the register is undefined.
+
+This class of patterns is special in several ways. First of all, each
+of these names @emph{must} be defined, because there is no other way
+to copy a datum from one place to another.
+
+Second, these patterns are not used solely in the RTL generation pass.
+Even the reload pass can generate move insns to copy values from stack
+slots into temporary registers. When it does so, one of the operands is
+a hard register and the other is an operand that can need to be reloaded
+into a register.
+
+@findex force_reg
+Therefore, when given such a pair of operands, the pattern must generate
+RTL which needs no reloading and needs no temporary registers---no
+registers other than the operands. For example, if you support the
+pattern with a @code{define_expand}, then in such a case the
+@code{define_expand} mustn't call @code{force_reg} or any other such
+function which might generate new pseudo registers.
+
+This requirement exists even for subword modes on a RISC machine where
+fetching those modes from memory normally requires several insns and
+some temporary registers. Look in @file{spur.md} to see how the
+requirement can be satisfied.
+
+@findex change_address
+During reload a memory reference with an invalid address may be passed
+as an operand. Such an address will be replaced with a valid address
+later in the reload pass. In this case, nothing may be done with the
+address except to use it as it stands. If it is copied, it will not be
+replaced with a valid address. No attempt should be made to make such
+an address into a valid address and no routine (such as
+@code{change_address}) that will do so may be called. Note that
+@code{general_operand} will fail when applied to such an address.
+
+@findex reload_in_progress
+The global variable @code{reload_in_progress} (which must be explicitly
+declared if required) can be used to determine whether such special
+handling is required.
+
+The variety of operands that have reloads depends on the rest of the
+machine description, but typically on a RISC machine these can only be
+pseudo registers that did not get hard registers, while on other
+machines explicit memory references will get optional reloads.
+
+If a scratch register is required to move an object to or from memory,
+it can be allocated using @code{gen_reg_rtx} prior to reload. But this
+is impossible during and after reload. If there are cases needing
+scratch registers after reload, you must define
+@code{SECONDARY_INPUT_RELOAD_CLASS} and perhaps also
+@code{SECONDARY_OUTPUT_RELOAD_CLASS} to detect them, and provide
+patterns @samp{reload_in@var{m}} or @samp{reload_out@var{m}} to handle
+them. @xref{Register Classes}.
+
+The constraints on a @samp{move@var{m}} must permit moving any hard
+register to any other hard register provided that
+@code{HARD_REGNO_MODE_OK} permits mode @var{m} in both registers and
+@code{REGISTER_MOVE_COST} applied to their classes returns a value of 2.
+
+It is obligatory to support floating point @samp{move@var{m}}
+instructions into and out of any registers that can hold fixed point
+values, because unions and structures (which have modes @code{SImode} or
+@code{DImode}) can be in those registers and they may have floating
+point members.
+
+There may also be a need to support fixed point @samp{move@var{m}}
+instructions in and out of floating point registers. Unfortunately, I
+have forgotten why this was so, and I don't know whether it is still
+true. If @code{HARD_REGNO_MODE_OK} rejects fixed point values in
+floating point registers, then the constraints of the fixed point
+@samp{move@var{m}} instructions must be designed to avoid ever trying to
+reload into a floating point register.
+
+@cindex @code{reload_in} instruction pattern
+@cindex @code{reload_out} instruction pattern
+@item @samp{reload_in@var{m}}
+@itemx @samp{reload_out@var{m}}
+Like @samp{mov@var{m}}, but used when a scratch register is required to
+move between operand 0 and operand 1. Operand 2 describes the scratch
+register. See the discussion of the @code{SECONDARY_RELOAD_CLASS}
+macro in @pxref{Register Classes}.
+
+@cindex @code{movstrict@var{m}} instruction pattern
+@item @samp{movstrict@var{m}}
+Like @samp{mov@var{m}} except that if operand 0 is a @code{subreg}
+with mode @var{m} of a register whose natural mode is wider,
+the @samp{movstrict@var{m}} instruction is guaranteed not to alter
+any of the register except the part which belongs to mode @var{m}.
+
+@cindex @code{load_multiple} instruction pattern
+@item @samp{load_multiple}
+Load several consecutive memory locations into consecutive registers.
+Operand 0 is the first of the consecutive registers, operand 1
+is the first memory location, and operand 2 is a constant: the
+number of consecutive registers.
+
+Define this only if the target machine really has such an instruction;
+do not define this if the most efficient way of loading consecutive
+registers from memory is to do them one at a time.
+
+On some machines, there are restrictions as to which consecutive
+registers can be stored into memory, such as particular starting or
+ending register numbers or only a range of valid counts. For those
+machines, use a @code{define_expand} (@pxref{Expander Definitions})
+and make the pattern fail if the restrictions are not met.
+
+Write the generated insn as a @code{parallel} with elements being a
+@code{set} of one register from the appropriate memory location (you may
+also need @code{use} or @code{clobber} elements). Use a
+@code{match_parallel} (@pxref{RTL Template}) to recognize the insn. See
+@file{a29k.md} and @file{rs6000.md} for examples of the use of this insn
+pattern.
+
+@cindex @samp{store_multiple} instruction pattern
+@item @samp{store_multiple}
+Similar to @samp{load_multiple}, but store several consecutive registers
+into consecutive memory locations. Operand 0 is the first of the
+consecutive memory locations, operand 1 is the first register, and
+operand 2 is a constant: the number of consecutive registers.
+
+@cindex @code{add@var{m}3} instruction pattern
+@item @samp{add@var{m}3}
+Add operand 2 and operand 1, storing the result in operand 0. All operands
+must have mode @var{m}. This can be used even on two-address machines, by
+means of constraints requiring operands 1 and 0 to be the same location.
+
+@cindex @code{sub@var{m}3} instruction pattern
+@cindex @code{mul@var{m}3} instruction pattern
+@cindex @code{div@var{m}3} instruction pattern
+@cindex @code{udiv@var{m}3} instruction pattern
+@cindex @code{mod@var{m}3} instruction pattern
+@cindex @code{umod@var{m}3} instruction pattern
+@cindex @code{min@var{m}3} instruction pattern
+@cindex @code{max@var{m}3} instruction pattern
+@cindex @code{umin@var{m}3} instruction pattern
+@cindex @code{umax@var{m}3} instruction pattern
+@cindex @code{and@var{m}3} instruction pattern
+@cindex @code{ior@var{m}3} instruction pattern
+@cindex @code{xor@var{m}3} instruction pattern
+@item @samp{sub@var{m}3}, @samp{mul@var{m}3}
+@itemx @samp{div@var{m}3}, @samp{udiv@var{m}3}, @samp{mod@var{m}3}, @samp{umod@var{m}3}
+@itemx @samp{smin@var{m}3}, @samp{smax@var{m}3}, @samp{umin@var{m}3}, @samp{umax@var{m}3}
+@itemx @samp{and@var{m}3}, @samp{ior@var{m}3}, @samp{xor@var{m}3}
+Similar, for other arithmetic operations.
+
+@cindex @code{mulhisi3} instruction pattern
+@item @samp{mulhisi3}
+Multiply operands 1 and 2, which have mode @code{HImode}, and store
+a @code{SImode} product in operand 0.
+
+@cindex @code{mulqihi3} instruction pattern
+@cindex @code{mulsidi3} instruction pattern
+@item @samp{mulqihi3}, @samp{mulsidi3}
+Similar widening-multiplication instructions of other widths.
+
+@cindex @code{umulqihi3} instruction pattern
+@cindex @code{umulhisi3} instruction pattern
+@cindex @code{umulsidi3} instruction pattern
+@item @samp{umulqihi3}, @samp{umulhisi3}, @samp{umulsidi3}
+Similar widening-multiplication instructions that do unsigned
+multiplication.
+
+@cindex @code{divmod@var{m}4} instruction pattern
+@item @samp{divmod@var{m}4}
+Signed division that produces both a quotient and a remainder.
+Operand 1 is divided by operand 2 to produce a quotient stored
+in operand 0 and a remainder stored in operand 3.
+
+For machines with an instruction that produces both a quotient and a
+remainder, provide a pattern for @samp{divmod@var{m}4} but do not
+provide patterns for @samp{div@var{m}3} and @samp{mod@var{m}3}. This
+allows optimization in the relatively common case when both the quotient
+and remainder are computed.
+
+If an instruction that just produces a quotient or just a remainder
+exists and is more efficient than the instruction that produces both,
+write the output routine of @samp{divmod@var{m}4} to call
+@code{find_reg_note} and look for a @code{REG_UNUSED} note on the
+quotient or remainder and generate the appropriate instruction.
+
+@cindex @code{udivmod@var{m}4} instruction pattern
+@item @samp{udivmod@var{m}4}
+Similar, but does unsigned division.
+
+@cindex @code{ashl@var{m}3} instruction pattern
+@item @samp{ashl@var{m}3}
+Arithmetic-shift operand 1 left by a number of bits specified by operand
+2, and store the result in operand 0. Here @var{m} is the mode of
+operand 0 and operand 1; operand 2's mode is specified by the
+instruction pattern, and the compiler will convert the operand to that
+mode before generating the instruction.
+
+@cindex @code{ashr@var{m}3} instruction pattern
+@cindex @code{lshr@var{m}3} instruction pattern
+@cindex @code{rotl@var{m}3} instruction pattern
+@cindex @code{rotr@var{m}3} instruction pattern
+@item @samp{ashr@var{m}3}, @samp{lshr@var{m}3}, @samp{rotl@var{m}3}, @samp{rotr@var{m}3}
+Other shift and rotate instructions, analogous to the
+@code{ashl@var{m}3} instructions.
+
+@cindex @code{neg@var{m}2} instruction pattern
+@item @samp{neg@var{m}2}
+Negate operand 1 and store the result in operand 0.
+
+@cindex @code{abs@var{m}2} instruction pattern
+@item @samp{abs@var{m}2}
+Store the absolute value of operand 1 into operand 0.
+
+@cindex @code{sqrt@var{m}2} instruction pattern
+@item @samp{sqrt@var{m}2}
+Store the square root of operand 1 into operand 0.
+
+The @code{sqrt} built-in function of C always uses the mode which
+corresponds to the C data type @code{double}.
+
+@cindex @code{ffs@var{m}2} instruction pattern
+@item @samp{ffs@var{m}2}
+Store into operand 0 one plus the index of the least significant 1-bit
+of operand 1. If operand 1 is zero, store zero. @var{m} is the mode
+of operand 0; operand 1's mode is specified by the instruction
+pattern, and the compiler will convert the operand to that mode before
+generating the instruction.
+
+The @code{ffs} built-in function of C always uses the mode which
+corresponds to the C data type @code{int}.
+
+@cindex @code{one_cmpl@var{m}2} instruction pattern
+@item @samp{one_cmpl@var{m}2}
+Store the bitwise-complement of operand 1 into operand 0.
+
+@cindex @code{cmp@var{m}} instruction pattern
+@item @samp{cmp@var{m}}
+Compare operand 0 and operand 1, and set the condition codes.
+The RTL pattern should look like this:
+
+@smallexample
+(set (cc0) (compare (match_operand:@var{m} 0 @dots{})
+ (match_operand:@var{m} 1 @dots{})))
+@end smallexample
+
+@cindex @code{tst@var{m}} instruction pattern
+@item @samp{tst@var{m}}
+Compare operand 0 against zero, and set the condition codes.
+The RTL pattern should look like this:
+
+@smallexample
+(set (cc0) (match_operand:@var{m} 0 @dots{}))
+@end smallexample
+
+@samp{tst@var{m}} patterns should not be defined for machines that do
+not use @code{(cc0)}. Doing so would confuse the optimizer since it
+would no longer be clear which @code{set} operations were comparisons.
+The @samp{cmp@var{m}} patterns should be used instead.
+
+@cindex @code{movstr@var{m}} instruction pattern
+@item @samp{movstr@var{m}}
+Block move instruction. The addresses of the destination and source
+strings are the first two operands, and both are in mode @code{Pmode}.
+The number of bytes to move is the third operand, in mode @var{m}.
+
+The fourth operand is the known shared alignment of the source and
+destination, in the form of a @code{const_int} rtx. Thus, if the
+compiler knows that both source and destination are word-aligned,
+it may provide the value 4 for this operand.
+
+These patterns need not give special consideration to the possibility
+that the source and destination strings might overlap.
+
+@cindex @code{cmpstr@var{m}} instruction pattern
+@item @samp{cmpstr@var{m}}
+Block compare instruction, with five operands. Operand 0 is the output;
+it has mode @var{m}. The remaining four operands are like the operands
+of @samp{movstr@var{m}}. The two memory blocks specified are compared
+byte by byte in lexicographic order. The effect of the instruction is
+to store a value in operand 0 whose sign indicates the result of the
+comparison.
+
+@cindex @code{strlen@var{m}} instruction pattern
+Compute the length of a string, with three operands.
+Operand 0 is the result (of mode @var{m}), operand 1 is
+a @code{mem} referring to the first character of the string,
+operand 2 is the character to search for (normally zero),
+and operand 3 is a constant describing the known alignment
+of the beginning of the string.
+
+@cindex @code{float@var{mn}2} instruction pattern
+@item @samp{float@var{m}@var{n}2}
+Convert signed integer operand 1 (valid for fixed point mode @var{m}) to
+floating point mode @var{n} and store in operand 0 (which has mode
+@var{n}).
+
+@cindex @code{floatuns@var{mn}2} instruction pattern
+@item @samp{floatuns@var{m}@var{n}2}
+Convert unsigned integer operand 1 (valid for fixed point mode @var{m})
+to floating point mode @var{n} and store in operand 0 (which has mode
+@var{n}).
+
+@cindex @code{fix@var{mn}2} instruction pattern
+@item @samp{fix@var{m}@var{n}2}
+Convert operand 1 (valid for floating point mode @var{m}) to fixed
+point mode @var{n} as a signed number and store in operand 0 (which
+has mode @var{n}). This instruction's result is defined only when
+the value of operand 1 is an integer.
+
+@cindex @code{fixuns@var{mn}2} instruction pattern
+@item @samp{fixuns@var{m}@var{n}2}
+Convert operand 1 (valid for floating point mode @var{m}) to fixed
+point mode @var{n} as an unsigned number and store in operand 0 (which
+has mode @var{n}). This instruction's result is defined only when the
+value of operand 1 is an integer.
+
+@cindex @code{ftrunc@var{m}2} instruction pattern
+@item @samp{ftrunc@var{m}2}
+Convert operand 1 (valid for floating point mode @var{m}) to an
+integer value, still represented in floating point mode @var{m}, and
+store it in operand 0 (valid for floating point mode @var{m}).
+
+@cindex @code{fix_trunc@var{mn}2} instruction pattern
+@item @samp{fix_trunc@var{m}@var{n}2}
+Like @samp{fix@var{m}@var{n}2} but works for any floating point value
+of mode @var{m} by converting the value to an integer.
+
+@cindex @code{fixuns_trunc@var{mn}2} instruction pattern
+@item @samp{fixuns_trunc@var{m}@var{n}2}
+Like @samp{fixuns@var{m}@var{n}2} but works for any floating point
+value of mode @var{m} by converting the value to an integer.
+
+@cindex @code{trunc@var{mn}} instruction pattern
+@item @samp{trunc@var{m}@var{n}}
+Truncate operand 1 (valid for mode @var{m}) to mode @var{n} and
+store in operand 0 (which has mode @var{n}). Both modes must be fixed
+point or both floating point.
+
+@cindex @code{extend@var{mn}} instruction pattern
+@item @samp{extend@var{m}@var{n}}
+Sign-extend operand 1 (valid for mode @var{m}) to mode @var{n} and
+store in operand 0 (which has mode @var{n}). Both modes must be fixed
+point or both floating point.
+
+@cindex @code{zero_extend@var{mn}} instruction pattern
+@item @samp{zero_extend@var{m}@var{n}}
+Zero-extend operand 1 (valid for mode @var{m}) to mode @var{n} and
+store in operand 0 (which has mode @var{n}). Both modes must be fixed
+point.
+
+@cindex @code{extv} instruction pattern
+@item @samp{extv}
+Extract a bit field from operand 1 (a register or memory operand), where
+operand 2 specifies the width in bits and operand 3 the starting bit,
+and store it in operand 0. Operand 0 must have mode @code{word_mode}.
+Operand 1 may have mode @code{byte_mode} or @code{word_mode}; often
+@code{word_mode} is allowed only for registers. Operands 2 and 3 must
+be valid for @code{word_mode}.
+
+The RTL generation pass generates this instruction only with constants
+for operands 2 and 3.
+
+The bit-field value is sign-extended to a full word integer
+before it is stored in operand 0.
+
+@cindex @code{extzv} instruction pattern
+@item @samp{extzv}
+Like @samp{extv} except that the bit-field value is zero-extended.
+
+@cindex @code{insv} instruction pattern
+@item @samp{insv}
+Store operand 3 (which must be valid for @code{word_mode}) into a bit
+field in operand 0, where operand 1 specifies the width in bits and
+operand 2 the starting bit. Operand 0 may have mode @code{byte_mode} or
+@code{word_mode}; often @code{word_mode} is allowed only for registers.
+Operands 1 and 2 must be valid for @code{word_mode}.
+
+The RTL generation pass generates this instruction only with constants
+for operands 1 and 2.
+
+@cindex @code{s@var{cond}} instruction pattern
+@item @samp{s@var{cond}}
+Store zero or nonzero in the operand according to the condition codes.
+Value stored is nonzero iff the condition @var{cond} is true.
+@var{cond} is the name of a comparison operation expression code, such
+as @code{eq}, @code{lt} or @code{leu}.
+
+You specify the mode that the operand must have when you write the
+@code{match_operand} expression. The compiler automatically sees
+which mode you have used and supplies an operand of that mode.
+
+The value stored for a true condition must have 1 as its low bit, or
+else must be negative. Otherwise the instruction is not suitable and
+you should omit it from the machine description. You describe to the
+compiler exactly which value is stored by defining the macro
+@code{STORE_FLAG_VALUE} (@pxref{Misc}). If a description cannot be
+found that can be used for all the @samp{s@var{cond}} patterns, you
+should omit those operations from the machine description.
+
+These operations may fail, but should do so only in relatively
+uncommon cases; if they would fail for common cases involving
+integer comparisons, it is best to omit these patterns.
+
+If these operations are omitted, the compiler will usually generate code
+that copies the constant one to the target and branches around an
+assignment of zero to the target. If this code is more efficient than
+the potential instructions used for the @samp{s@var{cond}} pattern
+followed by those required to convert the result into a 1 or a zero in
+@code{SImode}, you should omit the @samp{s@var{cond}} operations from
+the machine description.
+
+@cindex @code{b@var{cond}} instruction pattern
+@item @samp{b@var{cond}}
+Conditional branch instruction. Operand 0 is a @code{label_ref} that
+refers to the label to jump to. Jump if the condition codes meet
+condition @var{cond}.
+
+Some machines do not follow the model assumed here where a comparison
+instruction is followed by a conditional branch instruction. In that
+case, the @samp{cmp@var{m}} (and @samp{tst@var{m}}) patterns should
+simply store the operands away and generate all the required insns in a
+@code{define_expand} (@pxref{Expander Definitions}) for the conditional
+branch operations. All calls to expand @samp{b@var{cond}} patterns are
+immediately preceded by calls to expand either a @samp{cmp@var{m}}
+pattern or a @samp{tst@var{m}} pattern.
+
+Machines that use a pseudo register for the condition code value, or
+where the mode used for the comparison depends on the condition being
+tested, should also use the above mechanism. @xref{Jump Patterns}
+
+The above discussion also applies to @samp{s@var{cond}} patterns.
+
+@cindex @code{call} instruction pattern
+@item @samp{call}
+Subroutine call instruction returning no value. Operand 0 is the
+function to call; operand 1 is the number of bytes of arguments pushed
+(in mode @code{SImode}, except it is normally a @code{const_int});
+operand 2 is the number of registers used as operands.
+
+On most machines, operand 2 is not actually stored into the RTL
+pattern. It is supplied for the sake of some RISC machines which need
+to put this information into the assembler code; they can put it in
+the RTL instead of operand 1.
+
+Operand 0 should be a @code{mem} RTX whose address is the address of the
+function. Note, however, that this address can be a @code{symbol_ref}
+expression even if it would not be a legitimate memory address on the
+target machine. If it is also not a valid argument for a call
+instruction, the pattern for this operation should be a
+@code{define_expand} (@pxref{Expander Definitions}) that places the
+address into a register and uses that register in the call instruction.
+
+@cindex @code{call_value} instruction pattern
+@item @samp{call_value}
+Subroutine call instruction returning a value. Operand 0 is the hard
+register in which the value is returned. There are three more
+operands, the same as the three operands of the @samp{call}
+instruction (but with numbers increased by one).
+
+Subroutines that return @code{BLKmode} objects use the @samp{call}
+insn.
+
+@cindex @code{call_pop} instruction pattern
+@cindex @code{call_value_pop} instruction pattern
+@item @samp{call_pop}, @samp{call_value_pop}
+Similar to @samp{call} and @samp{call_value}, except used if defined and
+if @code{RETURN_POPS_ARGS} is non-zero. They should emit a @code{parallel}
+that contains both the function call and a @code{set} to indicate the
+adjustment made to the frame pointer.
+
+For machines where @code{RETURN_POPS_ARGS} can be non-zero, the use of these
+patterns increases the number of functions for which the frame pointer
+can be eliminated, if desired.
+
+@cindex @code{untyped_call} instruction pattern
+@item @samp{untyped_call}
+Subroutine call instruction returning a value of any type. Operand 0 is
+the function to call; operand 1 is a memory location where the result of
+calling the function is to be stored; operand 2 is a @code{parallel}
+expression where each element is a @code{set} expression that indicates
+the saving of a function return value into the result block.
+
+This instruction pattern should be defined to support
+@code{__builtin_apply} on machines where special instructions are needed
+to call a subroutine with arbitrary arguments or to save the value
+returned. This instruction pattern is required on machines that have
+multiple registers that can hold a return value (i.e.
+@code{FUNCTION_VALUE_REGNO_P} is true for more than one register).
+
+@cindex @code{return} instruction pattern
+@item @samp{return}
+Subroutine return instruction. This instruction pattern name should be
+defined only if a single instruction can do all the work of returning
+from a function.
+
+Like the @samp{mov@var{m}} patterns, this pattern is also used after the
+RTL generation phase. In this case it is to support machines where
+multiple instructions are usually needed to return from a function, but
+some class of functions only requires one instruction to implement a
+return. Normally, the applicable functions are those which do not need
+to save any registers or allocate stack space.
+
+@findex reload_completed
+@findex leaf_function_p
+For such machines, the condition specified in this pattern should only
+be true when @code{reload_completed} is non-zero and the function's
+epilogue would only be a single instruction. For machines with register
+windows, the routine @code{leaf_function_p} may be used to determine if
+a register window push is required.
+
+Machines that have conditional return instructions should define patterns
+such as
+
+@smallexample
+(define_insn ""
+ [(set (pc)
+ (if_then_else (match_operator
+ 0 "comparison_operator"
+ [(cc0) (const_int 0)])
+ (return)
+ (pc)))]
+ "@var{condition}"
+ "@dots{}")
+@end smallexample
+
+where @var{condition} would normally be the same condition specified on the
+named @samp{return} pattern.
+
+@cindex @code{untyped_return} instruction pattern
+@item @samp{untyped_return}
+Untyped subroutine return instruction. This instruction pattern should
+be defined to support @code{__builtin_return} on machines where special
+instructions are needed to return a value of any type.
+
+Operand 0 is a memory location where the result of calling a function
+with @code{__builtin_apply} is stored; operand 1 is a @code{parallel}
+expression where each element is a @code{set} expression that indicates
+the restoring of a function return value from the result block.
+
+@cindex @code{nop} instruction pattern
+@item @samp{nop}
+No-op instruction. This instruction pattern name should always be defined
+to output a no-op in assembler code. @code{(const_int 0)} will do as an
+RTL pattern.
+
+@cindex @code{indirect_jump} instruction pattern
+@item @samp{indirect_jump}
+An instruction to jump to an address which is operand zero.
+This pattern name is mandatory on all machines.
+
+@cindex @code{casesi} instruction pattern
+@item @samp{casesi}
+Instruction to jump through a dispatch table, including bounds checking.
+This instruction takes five operands:
+
+@enumerate
+@item
+The index to dispatch on, which has mode @code{SImode}.
+
+@item
+The lower bound for indices in the table, an integer constant.
+
+@item
+The total range of indices in the table---the largest index
+minus the smallest one (both inclusive).
+
+@item
+A label that precedes the table itself.
+
+@item
+A label to jump to if the index has a value outside the bounds.
+(If the machine-description macro @code{CASE_DROPS_THROUGH} is defined,
+then an out-of-bounds index drops through to the code following
+the jump table instead of jumping to this label. In that case,
+this label is not actually used by the @samp{casesi} instruction,
+but it is always provided as an operand.)
+@end enumerate
+
+The table is a @code{addr_vec} or @code{addr_diff_vec} inside of a
+@code{jump_insn}. The number of elements in the table is one plus the
+difference between the upper bound and the lower bound.
+
+@cindex @code{tablejump} instruction pattern
+@item @samp{tablejump}
+Instruction to jump to a variable address. This is a low-level
+capability which can be used to implement a dispatch table when there
+is no @samp{casesi} pattern.
+
+This pattern requires two operands: the address or offset, and a label
+which should immediately precede the jump table. If the macro
+@code{CASE_VECTOR_PC_RELATIVE} is defined then the first operand is an
+offset which counts from the address of the table; otherwise, it is an
+absolute address to jump to. In either case, the first operand has
+mode @code{Pmode}.
+
+The @samp{tablejump} insn is always the last insn before the jump
+table it uses. Its assembler code normally has no need to use the
+second operand, but you should incorporate it in the RTL pattern so
+that the jump optimizer will not delete the table as unreachable code.
+
+@cindex @code{save_stack_block} instruction pattern
+@cindex @code{save_stack_function} instruction pattern
+@cindex @code{save_stack_nonlocal} instruction pattern
+@cindex @code{restore_stack_block} instruction pattern
+@cindex @code{restore_stack_function} instruction pattern
+@cindex @code{restore_stack_nonlocal} instruction pattern
+@item @samp{save_stack_block}
+@itemx @samp{save_stack_function}
+@itemx @samp{save_stack_nonlocal}
+@itemx @samp{restore_stack_block}
+@itemx @samp{restore_stack_function}
+@itemx @samp{restore_stack_nonlocal}
+Most machines save and restore the stack pointer by copying it to or
+from an object of mode @code{Pmode}. Do not define these patterns on
+such machines.
+
+Some machines require special handling for stack pointer saves and
+restores. On those machines, define the patterns corresponding to the
+non-standard cases by using a @code{define_expand} (@pxref{Expander
+Definitions}) that produces the required insns. The three types of
+saves and restores are:
+
+@enumerate
+@item
+@samp{save_stack_block} saves the stack pointer at the start of a block
+that allocates a variable-sized object, and @samp{restore_stack_block}
+restores the stack pointer when the block is exited.
+
+@item
+@samp{save_stack_function} and @samp{restore_stack_function} do a
+similar job for the outermost block of a function and are used when the
+function allocates variable-sized objects or calls @code{alloca}. Only
+the epilogue uses the restored stack pointer, allowing a simpler save or
+restore sequence on some machines.
+
+@item
+@samp{save_stack_nonlocal} is used in functions that contain labels
+branched to by nested functions. It saves the stack pointer in such a
+way that the inner function can use @samp{restore_stack_nonlocal} to
+restore the stack pointer. The compiler generates code to restore the
+frame and argument pointer registers, but some machines require saving
+and restoring additional data such as register window information or
+stack backchains. Place insns in these patterns to save and restore any
+such required data.
+@end enumerate
+
+When saving the stack pointer, operand 0 is the save area and operand 1
+is the stack pointer. The mode used to allocate the save area is the
+mode of operand 0. You must specify an integral mode, or
+@code{VOIDmode} if no save area is needed for a particular type of save
+(either because no save is needed or because a machine-specific save
+area can be used). Operand 0 is the stack pointer and operand 1 is the
+save area for restore operations. If @samp{save_stack_block} is
+defined, operand 0 must not be @code{VOIDmode} since these saves can be
+arbitrarily nested.
+
+A save area is a @code{mem} that is at a constant offset from
+@code{virtual_stack_vars_rtx} when the stack pointer is saved for use by
+nonlocal gotos and a @code{reg} in the other two cases.
+
+@cindex @code{allocate_stack} instruction pattern
+@item @samp{allocate_stack}
+Subtract (or add if @code{STACK_GROWS_DOWNWARD} is undefined) operand 0 from
+the stack pointer to create space for dynamically allocated data.
+
+Do not define this pattern if all that must be done is the subtraction.
+Some machines require other operations such as stack probes or
+maintaining the back chain. Define this pattern to emit those
+operations in addition to updating the stack pointer.
+@end table
+
+@node Pattern Ordering
+@section When the Order of Patterns Matters
+@cindex Pattern Ordering
+@cindex Ordering of Patterns
+
+Sometimes an insn can match more than one instruction pattern. Then the
+pattern that appears first in the machine description is the one used.
+Therefore, more specific patterns (patterns that will match fewer things)
+and faster instructions (those that will produce better code when they
+do match) should usually go first in the description.
+
+In some cases the effect of ordering the patterns can be used to hide
+a pattern when it is not valid. For example, the 68000 has an
+instruction for converting a fullword to floating point and another
+for converting a byte to floating point. An instruction converting
+an integer to floating point could match either one. We put the
+pattern to convert the fullword first to make sure that one will
+be used rather than the other. (Otherwise a large integer might
+be generated as a single-byte immediate quantity, which would not work.)
+Instead of using this pattern ordering it would be possible to make the
+pattern for convert-a-byte smart enough to deal properly with any
+constant value.
+
+@node Dependent Patterns
+@section Interdependence of Patterns
+@cindex Dependent Patterns
+@cindex Interdependence of Patterns
+
+Every machine description must have a named pattern for each of the
+conditional branch names @samp{b@var{cond}}. The recognition template
+must always have the form
+
+@example
+(set (pc)
+ (if_then_else (@var{cond} (cc0) (const_int 0))
+ (label_ref (match_operand 0 "" ""))
+ (pc)))
+@end example
+
+@noindent
+In addition, every machine description must have an anonymous pattern
+for each of the possible reverse-conditional branches. Their templates
+look like
+
+@example
+(set (pc)
+ (if_then_else (@var{cond} (cc0) (const_int 0))
+ (pc)
+ (label_ref (match_operand 0 "" ""))))
+@end example
+
+@noindent
+They are necessary because jump optimization can turn direct-conditional
+branches into reverse-conditional branches.
+
+It is often convenient to use the @code{match_operator} construct to
+reduce the number of patterns that must be specified for branches. For
+example,
+
+@example
+(define_insn ""
+ [(set (pc)
+ (if_then_else (match_operator 0 "comparison_operator"
+ [(cc0) (const_int 0)])
+ (pc)
+ (label_ref (match_operand 1 "" ""))))]
+ "@var{condition}"
+ "@dots{}")
+@end example
+
+In some cases machines support instructions identical except for the
+machine mode of one or more operands. For example, there may be
+``sign-extend halfword'' and ``sign-extend byte'' instructions whose
+patterns are
+
+@example
+(set (match_operand:SI 0 @dots{})
+ (extend:SI (match_operand:HI 1 @dots{})))
+
+(set (match_operand:SI 0 @dots{})
+ (extend:SI (match_operand:QI 1 @dots{})))
+@end example
+
+@noindent
+Constant integers do not specify a machine mode, so an instruction to
+extend a constant value could match either pattern. The pattern it
+actually will match is the one that appears first in the file. For correct
+results, this must be the one for the widest possible mode (@code{HImode},
+here). If the pattern matches the @code{QImode} instruction, the results
+will be incorrect if the constant value does not actually fit that mode.
+
+Such instructions to extend constants are rarely generated because they are
+optimized away, but they do occasionally happen in nonoptimized
+compilations.
+
+If a constraint in a pattern allows a constant, the reload pass may
+replace a register with a constant permitted by the constraint in some
+cases. Similarly for memory references. You must ensure that the
+predicate permits all objects allowed by the constraints to prevent the
+compiler from crashing.
+
+Because of this substitution, you should not provide separate patterns
+for increment and decrement instructions. Instead, they should be
+generated from the same pattern that supports register-register add
+insns by examining the operands and generating the appropriate machine
+instruction.
+
+@node Jump Patterns
+@section Defining Jump Instruction Patterns
+@cindex jump instruction patterns
+@cindex defining jump instruction patterns
+
+For most machines, GNU CC assumes that the machine has a condition code.
+A comparison insn sets the condition code, recording the results of both
+signed and unsigned comparison of the given operands. A separate branch
+insn tests the condition code and branches or not according its value.
+The branch insns come in distinct signed and unsigned flavors. Many
+common machines, such as the Vax, the 68000 and the 32000, work this
+way.
+
+Some machines have distinct signed and unsigned compare instructions, and
+only one set of conditional branch instructions. The easiest way to handle
+these machines is to treat them just like the others until the final stage
+where assembly code is written. At this time, when outputting code for the
+compare instruction, peek ahead at the following branch using
+@code{next_cc0_user (insn)}. (The variable @code{insn} refers to the insn
+being output, in the output-writing code in an instruction pattern.) If
+the RTL says that is an unsigned branch, output an unsigned compare;
+otherwise output a signed compare. When the branch itself is output, you
+can treat signed and unsigned branches identically.
+
+The reason you can do this is that GNU CC always generates a pair of
+consecutive RTL insns, possibly separated by @code{note} insns, one to
+set the condition code and one to test it, and keeps the pair inviolate
+until the end.
+
+To go with this technique, you must define the machine-description macro
+@code{NOTICE_UPDATE_CC} to do @code{CC_STATUS_INIT}; in other words, no
+compare instruction is superfluous.
+
+Some machines have compare-and-branch instructions and no condition code.
+A similar technique works for them. When it is time to ``output'' a
+compare instruction, record its operands in two static variables. When
+outputting the branch-on-condition-code instruction that follows, actually
+output a compare-and-branch instruction that uses the remembered operands.
+
+It also works to define patterns for compare-and-branch instructions.
+In optimizing compilation, the pair of compare and branch instructions
+will be combined according to these patterns. But this does not happen
+if optimization is not requested. So you must use one of the solutions
+above in addition to any special patterns you define.
+
+In many RISC machines, most instructions do not affect the condition
+code and there may not even be a separate condition code register. On
+these machines, the restriction that the definition and use of the
+condition code be adjacent insns is not necessary and can prevent
+important optimizations. For example, on the IBM RS/6000, there is a
+delay for taken branches unless the condition code register is set three
+instructions earlier than the conditional branch. The instruction
+scheduler cannot perform this optimization if it is not permitted to
+separate the definition and use of the condition code register.
+
+On these machines, do not use @code{(cc0)}, but instead use a register
+to represent the condition code. If there is a specific condition code
+register in the machine, use a hard register. If the condition code or
+comparison result can be placed in any general register, or if there are
+multiple condition registers, use a pseudo register.
+
+@findex prev_cc0_setter
+@findex next_cc0_user
+On some machines, the type of branch instruction generated may depend on
+the way the condition code was produced; for example, on the 68k and
+Sparc, setting the condition code directly from an add or subtract
+instruction does not clear the overflow bit the way that a test
+instruction does, so a different branch instruction must be used for
+some conditional branches. For machines that use @code{(cc0)}, the set
+and use of the condition code must be adjacent (separated only by
+@code{note} insns) allowing flags in @code{cc_status} to be used.
+(@xref{Condition Code}.) Also, the comparison and branch insns can be
+located from each other by using the functions @code{prev_cc0_setter}
+and @code{next_cc0_user}.
+
+However, this is not true on machines that do not use @code{(cc0)}. On
+those machines, no assumptions can be made about the adjacency of the
+compare and branch insns and the above methods cannot be used. Instead,
+we use the machine mode of the condition code register to record
+different formats of the condition code register.
+
+Registers used to store the condition code value should have a mode that
+is in class @code{MODE_CC}. Normally, it will be @code{CCmode}. If
+additional modes are required (as for the add example mentioned above in
+the Sparc), define the macro @code{EXTRA_CC_MODES} to list the
+additional modes required (@pxref{Condition Code}). Also define
+@code{EXTRA_CC_NAMES} to list the names of those modes and
+@code{SELECT_CC_MODE} to choose a mode given an operand of a compare.
+
+If it is known during RTL generation that a different mode will be
+required (for example, if the machine has separate compare instructions
+for signed and unsigned quantities, like most IBM processors), they can
+be specified at that time.
+
+If the cases that require different modes would be made by instruction
+combination, the macro @code{SELECT_CC_MODE} determines which machine
+mode should be used for the comparison result. The patterns should be
+written using that mode. To support the case of the add on the Sparc
+discussed above, we have the pattern
+
+@smallexample
+(define_insn ""
+ [(set (reg:CC_NOOV 0)
+ (compare:CC_NOOV
+ (plus:SI (match_operand:SI 0 "register_operand" "%r")
+ (match_operand:SI 1 "arith_operand" "rI"))
+ (const_int 0)))]
+ ""
+ "@dots{}")
+@end smallexample
+
+The @code{SELECT_CC_MODE} macro on the Sparc returns @code{CC_NOOVmode}
+for comparisons whose argument is a @code{plus}.
+
+@node Insn Canonicalizations
+@section Canonicalization of Instructions
+@cindex canonicalization of instructions
+@cindex insn canonicalization
+
+There are often cases where multiple RTL expressions could represent an
+operation performed by a single machine instruction. This situation is
+most commonly encountered with logical, branch, and multiply-accumulate
+instructions. In such cases, the compiler attempts to convert these
+multiple RTL expressions into a single canonical form to reduce the
+number of insn patterns required.
+
+In addition to algebraic simplifications, following canonicalizations
+are performed:
+
+@itemize @bullet
+@item
+For commutative and comparison operators, a constant is always made the
+second operand. If a machine only supports a constant as the second
+operand, only patterns that match a constant in the second operand need
+be supplied.
+
+@cindex @code{neg}, canonicalization of
+@cindex @code{not}, canonicalization of
+@cindex @code{mult}, canonicalization of
+@cindex @code{plus}, canonicalization of
+@cindex @code{minus}, canonicalization of
+For these operators, if only one operand is a @code{neg}, @code{not},
+@code{mult}, @code{plus}, or @code{minus} expression, it will be the
+first operand.
+
+@cindex @code{compare}, canonicalization of
+@item
+For the @code{compare} operator, a constant is always the second operand
+on machines where @code{cc0} is used (@pxref{Jump Patterns}). On other
+machines, there are rare cases where the compiler might want to construct
+a @code{compare} with a constant as the first operand. However, these
+cases are not common enough for it to be worthwhile to provide a pattern
+matching a constant as the first operand unless the machine actually has
+such an instruction.
+
+An operand of @code{neg}, @code{not}, @code{mult}, @code{plus}, or
+@code{minus} is made the first operand under the same conditions as
+above.
+
+@item
+@code{(minus @var{x} (const_int @var{n}))} is converted to
+@code{(plus @var{x} (const_int @var{-n}))}.
+
+@item
+Within address computations (i.e., inside @code{mem}), a left shift is
+converted into the appropriate multiplication by a power of two.
+
+@cindex @code{ior}, canonicalization of
+@cindex @code{and}, canonicalization of
+@cindex De Morgan's law
+De`Morgan's Law is used to move bitwise negation inside a bitwise
+logical-and or logical-or operation. If this results in only one
+operand being a @code{not} expression, it will be the first one.
+
+A machine that has an instruction that performs a bitwise logical-and of one
+operand with the bitwise negation of the other should specify the pattern
+for that instruction as
+
+@example
+(define_insn ""
+ [(set (match_operand:@var{m} 0 @dots{})
+ (and:@var{m} (not:@var{m} (match_operand:@var{m} 1 @dots{}))
+ (match_operand:@var{m} 2 @dots{})))]
+ "@dots{}"
+ "@dots{}")
+@end example
+
+@noindent
+Similarly, a pattern for a ``NAND'' instruction should be written
+
+@example
+(define_insn ""
+ [(set (match_operand:@var{m} 0 @dots{})
+ (ior:@var{m} (not:@var{m} (match_operand:@var{m} 1 @dots{}))
+ (not:@var{m} (match_operand:@var{m} 2 @dots{}))))]
+ "@dots{}"
+ "@dots{}")
+@end example
+
+In both cases, it is not necessary to include patterns for the many
+logically equivalent RTL expressions.
+
+@cindex @code{xor}, canonicalization of
+@item
+The only possible RTL expressions involving both bitwise exclusive-or
+and bitwise negation are @code{(xor:@var{m} @var{x} @var{y})}
+and @code{(not:@var{m} (xor:@var{m} @var{x} @var{y}))}.@refill
+
+@item
+The sum of three items, one of which is a constant, will only appear in
+the form
+
+@example
+(plus:@var{m} (plus:@var{m} @var{x} @var{y}) @var{constant})
+@end example
+
+@item
+On machines that do not use @code{cc0},
+@code{(compare @var{x} (const_int 0))} will be converted to
+@var{x}.@refill
+
+@cindex @code{zero_extract}, canonicalization of
+@cindex @code{sign_extract}, canonicalization of
+@item
+Equality comparisons of a group of bits (usually a single bit) with zero
+will be written using @code{zero_extract} rather than the equivalent
+@code{and} or @code{sign_extract} operations.
+
+@end itemize
+
+@node Peephole Definitions
+@section Machine-Specific Peephole Optimizers
+@cindex peephole optimizer definitions
+@cindex defining peephole optimizers
+
+In addition to instruction patterns the @file{md} file may contain
+definitions of machine-specific peephole optimizations.
+
+The combiner does not notice certain peephole optimizations when the data
+flow in the program does not suggest that it should try them. For example,
+sometimes two consecutive insns related in purpose can be combined even
+though the second one does not appear to use a register computed in the
+first one. A machine-specific peephole optimizer can detect such
+opportunities.
+
+@need 1000
+A definition looks like this:
+
+@smallexample
+(define_peephole
+ [@var{insn-pattern-1}
+ @var{insn-pattern-2}
+ @dots{}]
+ "@var{condition}"
+ "@var{template}"
+ "@var{optional insn-attributes}")
+@end smallexample
+
+@noindent
+The last string operand may be omitted if you are not using any
+machine-specific information in this machine description. If present,
+it must obey the same rules as in a @code{define_insn}.
+
+In this skeleton, @var{insn-pattern-1} and so on are patterns to match
+consecutive insns. The optimization applies to a sequence of insns when
+@var{insn-pattern-1} matches the first one, @var{insn-pattern-2} matches
+the next, and so on.@refill
+
+Each of the insns matched by a peephole must also match a
+@code{define_insn}. Peepholes are checked only at the last stage just
+before code generation, and only optionally. Therefore, any insn which
+would match a peephole but no @code{define_insn} will cause a crash in code
+generation in an unoptimized compilation, or at various optimization
+stages.
+
+The operands of the insns are matched with @code{match_operands},
+@code{match_operator}, and @code{match_dup}, as usual. What is not
+usual is that the operand numbers apply to all the insn patterns in the
+definition. So, you can check for identical operands in two insns by
+using @code{match_operand} in one insn and @code{match_dup} in the
+other.
+
+The operand constraints used in @code{match_operand} patterns do not have
+any direct effect on the applicability of the peephole, but they will
+be validated afterward, so make sure your constraints are general enough
+to apply whenever the peephole matches. If the peephole matches
+but the constraints are not satisfied, the compiler will crash.
+
+It is safe to omit constraints in all the operands of the peephole; or
+you can write constraints which serve as a double-check on the criteria
+previously tested.
+
+Once a sequence of insns matches the patterns, the @var{condition} is
+checked. This is a C expression which makes the final decision whether to
+perform the optimization (we do so if the expression is nonzero). If
+@var{condition} is omitted (in other words, the string is empty) then the
+optimization is applied to every sequence of insns that matches the
+patterns.
+
+The defined peephole optimizations are applied after register allocation
+is complete. Therefore, the peephole definition can check which
+operands have ended up in which kinds of registers, just by looking at
+the operands.
+
+@findex prev_nonnote_insn
+The way to refer to the operands in @var{condition} is to write
+@code{operands[@var{i}]} for operand number @var{i} (as matched by
+@code{(match_operand @var{i} @dots{})}). Use the variable @code{insn}
+to refer to the last of the insns being matched; use
+@code{prev_nonnote_insn} to find the preceding insns.
+
+@findex dead_or_set_p
+When optimizing computations with intermediate results, you can use
+@var{condition} to match only when the intermediate results are not used
+elsewhere. Use the C expression @code{dead_or_set_p (@var{insn},
+@var{op})}, where @var{insn} is the insn in which you expect the value
+to be used for the last time (from the value of @code{insn}, together
+with use of @code{prev_nonnote_insn}), and @var{op} is the intermediate
+value (from @code{operands[@var{i}]}).@refill
+
+Applying the optimization means replacing the sequence of insns with one
+new insn. The @var{template} controls ultimate output of assembler code
+for this combined insn. It works exactly like the template of a
+@code{define_insn}. Operand numbers in this template are the same ones
+used in matching the original sequence of insns.
+
+The result of a defined peephole optimizer does not need to match any of
+the insn patterns in the machine description; it does not even have an
+opportunity to match them. The peephole optimizer definition itself serves
+as the insn pattern to control how the insn is output.
+
+Defined peephole optimizers are run as assembler code is being output,
+so the insns they produce are never combined or rearranged in any way.
+
+Here is an example, taken from the 68000 machine description:
+
+@smallexample
+(define_peephole
+ [(set (reg:SI 15) (plus:SI (reg:SI 15) (const_int 4)))
+ (set (match_operand:DF 0 "register_operand" "=f")
+ (match_operand:DF 1 "register_operand" "ad"))]
+ "FP_REG_P (operands[0]) && ! FP_REG_P (operands[1])"
+ "*
+@{
+ rtx xoperands[2];
+ xoperands[1] = gen_rtx (REG, SImode, REGNO (operands[1]) + 1);
+#ifdef MOTOROLA
+ output_asm_insn (\"move.l %1,(sp)\", xoperands);
+ output_asm_insn (\"move.l %1,-(sp)\", operands);
+ return \"fmove.d (sp)+,%0\";
+#else
+ output_asm_insn (\"movel %1,sp@@\", xoperands);
+ output_asm_insn (\"movel %1,sp@@-\", operands);
+ return \"fmoved sp@@+,%0\";
+#endif
+@}
+")
+@end smallexample
+
+@need 1000
+The effect of this optimization is to change
+
+@smallexample
+@group
+jbsr _foobar
+addql #4,sp
+movel d1,sp@@-
+movel d0,sp@@-
+fmoved sp@@+,fp0
+@end group
+@end smallexample
+
+@noindent
+into
+
+@smallexample
+@group
+jbsr _foobar
+movel d1,sp@@
+movel d0,sp@@-
+fmoved sp@@+,fp0
+@end group
+@end smallexample
+
+@ignore
+@findex CC_REVERSED
+If a peephole matches a sequence including one or more jump insns, you must
+take account of the flags such as @code{CC_REVERSED} which specify that the
+condition codes are represented in an unusual manner. The compiler
+automatically alters any ordinary conditional jumps which occur in such
+situations, but the compiler cannot alter jumps which have been replaced by
+peephole optimizations. So it is up to you to alter the assembler code
+that the peephole produces. Supply C code to write the assembler output,
+and in this C code check the condition code status flags and change the
+assembler code as appropriate.
+@end ignore
+
+@var{insn-pattern-1} and so on look @emph{almost} like the second
+operand of @code{define_insn}. There is one important difference: the
+second operand of @code{define_insn} consists of one or more RTX's
+enclosed in square brackets. Usually, there is only one: then the same
+action can be written as an element of a @code{define_peephole}. But
+when there are multiple actions in a @code{define_insn}, they are
+implicitly enclosed in a @code{parallel}. Then you must explicitly
+write the @code{parallel}, and the square brackets within it, in the
+@code{define_peephole}. Thus, if an insn pattern looks like this,
+
+@smallexample
+(define_insn "divmodsi4"
+ [(set (match_operand:SI 0 "general_operand" "=d")
+ (div:SI (match_operand:SI 1 "general_operand" "0")
+ (match_operand:SI 2 "general_operand" "dmsK")))
+ (set (match_operand:SI 3 "general_operand" "=d")
+ (mod:SI (match_dup 1) (match_dup 2)))]
+ "TARGET_68020"
+ "divsl%.l %2,%3:%0")
+@end smallexample
+
+@noindent
+then the way to mention this insn in a peephole is as follows:
+
+@smallexample
+(define_peephole
+ [@dots{}
+ (parallel
+ [(set (match_operand:SI 0 "general_operand" "=d")
+ (div:SI (match_operand:SI 1 "general_operand" "0")
+ (match_operand:SI 2 "general_operand" "dmsK")))
+ (set (match_operand:SI 3 "general_operand" "=d")
+ (mod:SI (match_dup 1) (match_dup 2)))])
+ @dots{}]
+ @dots{})
+@end smallexample
+
+@node Expander Definitions
+@section Defining RTL Sequences for Code Generation
+@cindex expander definitions
+@cindex code generation RTL sequences
+@cindex defining RTL sequences for code generation
+
+On some target machines, some standard pattern names for RTL generation
+cannot be handled with single insn, but a sequence of RTL insns can
+represent them. For these target machines, you can write a
+@code{define_expand} to specify how to generate the sequence of RTL.
+
+@findex define_expand
+A @code{define_expand} is an RTL expression that looks almost like a
+@code{define_insn}; but, unlike the latter, a @code{define_expand} is used
+only for RTL generation and it can produce more than one RTL insn.
+
+A @code{define_expand} RTX has four operands:
+
+@itemize @bullet
+@item
+The name. Each @code{define_expand} must have a name, since the only
+use for it is to refer to it by name.
+
+@findex define_peephole
+@item
+The RTL template. This is just like the RTL template for a
+@code{define_peephole} in that it is a vector of RTL expressions
+each being one insn.
+
+@item
+The condition, a string containing a C expression. This expression is
+used to express how the availability of this pattern depends on
+subclasses of target machine, selected by command-line options when
+GNU CC is run. This is just like the condition of a
+@code{define_insn} that has a standard name.
+
+@item
+The preparation statements, a string containing zero or more C
+statements which are to be executed before RTL code is generated from
+the RTL template.
+
+Usually these statements prepare temporary registers for use as
+internal operands in the RTL template, but they can also generate RTL
+insns directly by calling routines such as @code{emit_insn}, etc.
+Any such insns precede the ones that come from the RTL template.
+@end itemize
+
+Every RTL insn emitted by a @code{define_expand} must match some
+@code{define_insn} in the machine description. Otherwise, the compiler
+will crash when trying to generate code for the insn or trying to optimize
+it.
+
+The RTL template, in addition to controlling generation of RTL insns,
+also describes the operands that need to be specified when this pattern
+is used. In particular, it gives a predicate for each operand.
+
+A true operand, which needs to be specified in order to generate RTL from
+the pattern, should be described with a @code{match_operand} in its first
+occurrence in the RTL template. This enters information on the operand's
+predicate into the tables that record such things. GNU CC uses the
+information to preload the operand into a register if that is required for
+valid RTL code. If the operand is referred to more than once, subsequent
+references should use @code{match_dup}.
+
+The RTL template may also refer to internal ``operands'' which are
+temporary registers or labels used only within the sequence made by the
+@code{define_expand}. Internal operands are substituted into the RTL
+template with @code{match_dup}, never with @code{match_operand}. The
+values of the internal operands are not passed in as arguments by the
+compiler when it requests use of this pattern. Instead, they are computed
+within the pattern, in the preparation statements. These statements
+compute the values and store them into the appropriate elements of
+@code{operands} so that @code{match_dup} can find them.
+
+There are two special macros defined for use in the preparation statements:
+@code{DONE} and @code{FAIL}. Use them with a following semicolon,
+as a statement.
+
+@table @code
+
+@findex DONE
+@item DONE
+Use the @code{DONE} macro to end RTL generation for the pattern. The
+only RTL insns resulting from the pattern on this occasion will be
+those already emitted by explicit calls to @code{emit_insn} within the
+preparation statements; the RTL template will not be generated.
+
+@findex FAIL
+@item FAIL
+Make the pattern fail on this occasion. When a pattern fails, it means
+that the pattern was not truly available. The calling routines in the
+compiler will try other strategies for code generation using other patterns.
+
+Failure is currently supported only for binary (addition, multiplication,
+shifting, etc.) and bitfield (@code{extv}, @code{extzv}, and @code{insv})
+operations.
+@end table
+
+Here is an example, the definition of left-shift for the SPUR chip:
+
+@smallexample
+@group
+(define_expand "ashlsi3"
+ [(set (match_operand:SI 0 "register_operand" "")
+ (ashift:SI
+@end group
+@group
+ (match_operand:SI 1 "register_operand" "")
+ (match_operand:SI 2 "nonmemory_operand" "")))]
+ ""
+ "
+@end group
+@end smallexample
+
+@smallexample
+@group
+@{
+ if (GET_CODE (operands[2]) != CONST_INT
+ || (unsigned) INTVAL (operands[2]) > 3)
+ FAIL;
+@}")
+@end group
+@end smallexample
+
+@noindent
+This example uses @code{define_expand} so that it can generate an RTL insn
+for shifting when the shift-count is in the supported range of 0 to 3 but
+fail in other cases where machine insns aren't available. When it fails,
+the compiler tries another strategy using different patterns (such as, a
+library call).
+
+If the compiler were able to handle nontrivial condition-strings in
+patterns with names, then it would be possible to use a
+@code{define_insn} in that case. Here is another case (zero-extension
+on the 68000) which makes more use of the power of @code{define_expand}:
+
+@smallexample
+(define_expand "zero_extendhisi2"
+ [(set (match_operand:SI 0 "general_operand" "")
+ (const_int 0))
+ (set (strict_low_part
+ (subreg:HI
+ (match_dup 0)
+ 0))
+ (match_operand:HI 1 "general_operand" ""))]
+ ""
+ "operands[1] = make_safe_from (operands[1], operands[0]);")
+@end smallexample
+
+@noindent
+@findex make_safe_from
+Here two RTL insns are generated, one to clear the entire output operand
+and the other to copy the input operand into its low half. This sequence
+is incorrect if the input operand refers to [the old value of] the output
+operand, so the preparation statement makes sure this isn't so. The
+function @code{make_safe_from} copies the @code{operands[1]} into a
+temporary register if it refers to @code{operands[0]}. It does this
+by emitting another RTL insn.
+
+Finally, a third example shows the use of an internal operand.
+Zero-extension on the SPUR chip is done by @code{and}-ing the result
+against a halfword mask. But this mask cannot be represented by a
+@code{const_int} because the constant value is too large to be legitimate
+on this machine. So it must be copied into a register with
+@code{force_reg} and then the register used in the @code{and}.
+
+@smallexample
+(define_expand "zero_extendhisi2"
+ [(set (match_operand:SI 0 "register_operand" "")
+ (and:SI (subreg:SI
+ (match_operand:HI 1 "register_operand" "")
+ 0)
+ (match_dup 2)))]
+ ""
+ "operands[2]
+ = force_reg (SImode, gen_rtx (CONST_INT,
+ VOIDmode, 65535)); ")
+@end smallexample
+
+@strong{Note:} If the @code{define_expand} is used to serve a
+standard binary or unary arithmetic operation or a bitfield operation,
+then the last insn it generates must not be a @code{code_label},
+@code{barrier} or @code{note}. It must be an @code{insn},
+@code{jump_insn} or @code{call_insn}. If you don't need a real insn
+at the end, emit an insn to copy the result of the operation into
+itself. Such an insn will generate no code, but it can avoid problems
+in the compiler.@refill
+
+@node Insn Splitting
+@section Defining How to Split Instructions
+@cindex insn splitting
+@cindex instruction splitting
+@cindex splitting instructions
+
+There are two cases where you should specify how to split a pattern into
+multiple insns. On machines that have instructions requiring delay
+slots (@pxref{Delay Slots}) or that have instructions whose output is
+not available for multiple cycles (@pxref{Function Units}), the compiler
+phases that optimize these cases need to be able to move insns into
+one-instruction delay slots. However, some insns may generate more than one
+machine instruction. These insns cannot be placed into a delay slot.
+
+Often you can rewrite the single insn as a list of individual insns,
+each corresponding to one machine instruction. The disadvantage of
+doing so is that it will cause the compilation to be slower and require
+more space. If the resulting insns are too complex, it may also
+suppress some optimizations. The compiler splits the insn if there is a
+reason to believe that it might improve instruction or delay slot
+scheduling.
+
+The insn combiner phase also splits putative insns. If three insns are
+merged into one insn with a complex expression that cannot be matched by
+some @code{define_insn} pattern, the combiner phase attempts to split
+the complex pattern into two insns that are recognized. Usually it can
+break the complex pattern into two patterns by splitting out some
+subexpression. However, in some other cases, such as performing an
+addition of a large constant in two insns on a RISC machine, the way to
+split the addition into two insns is machine-dependent.
+
+@cindex define_split
+The @code{define_split} definition tells the compiler how to split a
+complex insn into several simpler insns. It looks like this:
+
+@smallexample
+(define_split
+ [@var{insn-pattern}]
+ "@var{condition}"
+ [@var{new-insn-pattern-1}
+ @var{new-insn-pattern-2}
+ @dots{}]
+ "@var{preparation statements}")
+@end smallexample
+
+@var{insn-pattern} is a pattern that needs to be split and
+@var{condition} is the final condition to be tested, as in a
+@code{define_insn}. When an insn matching @var{insn-pattern} and
+satisfying @var{condition} is found, it is replaced in the insn list
+with the insns given by @var{new-insn-pattern-1},
+@var{new-insn-pattern-2}, etc.
+
+The @var{preparation statements} are similar to those statements that
+are specified for @code{define_expand} (@pxref{Expander Definitions})
+and are executed before the new RTL is generated to prepare for the
+generated code or emit some insns whose pattern is not fixed. Unlike
+those in @code{define_expand}, however, these statements must not
+generate any new pseudo-registers. Once reload has completed, they also
+must not allocate any space in the stack frame.
+
+Patterns are matched against @var{insn-pattern} in two different
+circumstances. If an insn needs to be split for delay slot scheduling
+or insn scheduling, the insn is already known to be valid, which means
+that it must have been matched by some @code{define_insn} and, if
+@code{reload_completed} is non-zero, is known to satisfy the constraints
+of that @code{define_insn}. In that case, the new insn patterns must
+also be insns that are matched by some @code{define_insn} and, if
+@code{reload_completed} is non-zero, must also satisfy the constraints
+of those definitions.
+
+As an example of this usage of @code{define_split}, consider the following
+example from @file{a29k.md}, which splits a @code{sign_extend} from
+@code{HImode} to @code{SImode} into a pair of shift insns:
+
+@smallexample
+(define_split
+ [(set (match_operand:SI 0 "gen_reg_operand" "")
+ (sign_extend:SI (match_operand:HI 1 "gen_reg_operand" "")))]
+ ""
+ [(set (match_dup 0)
+ (ashift:SI (match_dup 1)
+ (const_int 16)))
+ (set (match_dup 0)
+ (ashiftrt:SI (match_dup 0)
+ (const_int 16)))]
+ "
+@{ operands[1] = gen_lowpart (SImode, operands[1]); @}")
+@end smallexample
+
+When the combiner phase tries to split an insn pattern, it is always the
+case that the pattern is @emph{not} matched by any @code{define_insn}.
+The combiner pass first tries to split a single @code{set} expression
+and then the same @code{set} expression inside a @code{parallel}, but
+followed by a @code{clobber} of a pseudo-reg to use as a scratch
+register. In these cases, the combiner expects exactly two new insn
+patterns to be generated. It will verify that these patterns match some
+@code{define_insn} definitions, so you need not do this test in the
+@code{define_split} (of course, there is no point in writing a
+@code{define_split} that will never produce insns that match).
+
+Here is an example of this use of @code{define_split}, taken from
+@file{rs6000.md}:
+
+@smallexample
+(define_split
+ [(set (match_operand:SI 0 "gen_reg_operand" "")
+ (plus:SI (match_operand:SI 1 "gen_reg_operand" "")
+ (match_operand:SI 2 "non_add_cint_operand" "")))]
+ ""
+ [(set (match_dup 0) (plus:SI (match_dup 1) (match_dup 3)))
+ (set (match_dup 0) (plus:SI (match_dup 0) (match_dup 4)))]
+"
+@{
+ int low = INTVAL (operands[2]) & 0xffff;
+ int high = (unsigned) INTVAL (operands[2]) >> 16;
+
+ if (low & 0x8000)
+ high++, low |= 0xffff0000;
+
+ operands[3] = gen_rtx (CONST_INT, VOIDmode, high << 16);
+ operands[4] = gen_rtx (CONST_INT, VOIDmode, low);
+@}")
+@end smallexample
+
+Here the predicate @code{non_add_cint_operand} matches any
+@code{const_int} that is @emph{not} a valid operand of a single add
+insn. The add with the smaller displacement is written so that it
+can be substituted into the address of a subsequent operation.
+
+An example that uses a scratch register, from the same file, generates
+an equality comparison of a register and a large constant:
+
+@smallexample
+(define_split
+ [(set (match_operand:CC 0 "cc_reg_operand" "")
+ (compare:CC (match_operand:SI 1 "gen_reg_operand" "")
+ (match_operand:SI 2 "non_short_cint_operand" "")))
+ (clobber (match_operand:SI 3 "gen_reg_operand" ""))]
+ "find_single_use (operands[0], insn, 0)
+ && (GET_CODE (*find_single_use (operands[0], insn, 0)) == EQ
+ || GET_CODE (*find_single_use (operands[0], insn, 0)) == NE)"
+ [(set (match_dup 3) (xor:SI (match_dup 1) (match_dup 4)))
+ (set (match_dup 0) (compare:CC (match_dup 3) (match_dup 5)))]
+ "
+@{
+ /* Get the constant we are comparing against, C, and see what it
+ looks like sign-extended to 16 bits. Then see what constant
+ could be XOR'ed with C to get the sign-extended value. */
+
+ int c = INTVAL (operands[2]);
+ int sextc = (c << 16) >> 16;
+ int xorv = c ^ sextc;
+
+ operands[4] = gen_rtx (CONST_INT, VOIDmode, xorv);
+ operands[5] = gen_rtx (CONST_INT, VOIDmode, sextc);
+@}")
+@end smallexample
+
+To avoid confusion, don't write a single @code{define_split} that
+accepts some insns that match some @code{define_insn} as well as some
+insns that don't. Instead, write two separate @code{define_split}
+definitions, one for the insns that are valid and one for the insns that
+are not valid.
+
+@node Insn Attributes
+@section Instruction Attributes
+@cindex insn attributes
+@cindex instruction attributes
+
+In addition to describing the instruction supported by the target machine,
+the @file{md} file also defines a group of @dfn{attributes} and a set of
+values for each. Every generated insn is assigned a value for each attribute.
+One possible attribute would be the effect that the insn has on the machine's
+condition code. This attribute can then be used by @code{NOTICE_UPDATE_CC}
+to track the condition codes.
+
+@menu
+* Defining Attributes:: Specifying attributes and their values.
+* Expressions:: Valid expressions for attribute values.
+* Tagging Insns:: Assigning attribute values to insns.
+* Attr Example:: An example of assigning attributes.
+* Insn Lengths:: Computing the length of insns.
+* Constant Attributes:: Defining attributes that are constant.
+* Delay Slots:: Defining delay slots required for a machine.
+* Function Units:: Specifying information for insn scheduling.
+@end menu
+
+@node Defining Attributes
+@subsection Defining Attributes and their Values
+@cindex defining attributes and their values
+@cindex attributes, defining
+
+@findex define_attr
+The @code{define_attr} expression is used to define each attribute required
+by the target machine. It looks like:
+
+@smallexample
+(define_attr @var{name} @var{list-of-values} @var{default})
+@end smallexample
+
+@var{name} is a string specifying the name of the attribute being defined.
+
+@var{list-of-values} is either a string that specifies a comma-separated
+list of values that can be assigned to the attribute, or a null string to
+indicate that the attribute takes numeric values.
+
+@var{default} is an attribute expression that gives the value of this
+attribute for insns that match patterns whose definition does not include
+an explicit value for this attribute. @xref{Attr Example}, for more
+information on the handling of defaults. @xref{Constant Attributes},
+for information on attributes that do not depend on any particular insn.
+
+@findex insn-attr.h
+For each defined attribute, a number of definitions are written to the
+@file{insn-attr.h} file. For cases where an explicit set of values is
+specified for an attribute, the following are defined:
+
+@itemize @bullet
+@item
+A @samp{#define} is written for the symbol @samp{HAVE_ATTR_@var{name}}.
+
+@item
+An enumeral class is defined for @samp{attr_@var{name}} with
+elements of the form @samp{@var{upper-name}_@var{upper-value}} where
+the attribute name and value are first converted to upper case.
+
+@item
+A function @samp{get_attr_@var{name}} is defined that is passed an insn and
+returns the attribute value for that insn.
+@end itemize
+
+For example, if the following is present in the @file{md} file:
+
+@smallexample
+(define_attr "type" "branch,fp,load,store,arith" @dots{})
+@end smallexample
+
+@noindent
+the following lines will be written to the file @file{insn-attr.h}.
+
+@smallexample
+#define HAVE_ATTR_type
+enum attr_type @{TYPE_BRANCH, TYPE_FP, TYPE_LOAD,
+ TYPE_STORE, TYPE_ARITH@};
+extern enum attr_type get_attr_type ();
+@end smallexample
+
+If the attribute takes numeric values, no @code{enum} type will be
+defined and the function to obtain the attribute's value will return
+@code{int}.
+
+@node Expressions
+@subsection Attribute Expressions
+@cindex attribute expressions
+
+RTL expressions used to define attributes use the codes described above
+plus a few specific to attribute definitions, to be discussed below.
+Attribute value expressions must have one of the following forms:
+
+@table @code
+@cindex @code{const_int} and attributes
+@item (const_int @var{i})
+The integer @var{i} specifies the value of a numeric attribute. @var{i}
+must be non-negative.
+
+The value of a numeric attribute can be specified either with a
+@code{const_int} or as an integer represented as a string in
+@code{const_string}, @code{eq_attr} (see below), and @code{set_attr}
+(@pxref{Tagging Insns}) expressions.
+
+@cindex @code{const_string} and attributes
+@item (const_string @var{value})
+The string @var{value} specifies a constant attribute value.
+If @var{value} is specified as @samp{"*"}, it means that the default value of
+the attribute is to be used for the insn containing this expression.
+@samp{"*"} obviously cannot be used in the @var{default} expression
+of a @code{define_attr}.@refill
+
+If the attribute whose value is being specified is numeric, @var{value}
+must be a string containing a non-negative integer (normally
+@code{const_int} would be used in this case). Otherwise, it must
+contain one of the valid values for the attribute.
+
+@cindex @code{if_then_else} and attributes
+@item (if_then_else @var{test} @var{true-value} @var{false-value})
+@var{test} specifies an attribute test, whose format is defined below.
+The value of this expression is @var{true-value} if @var{test} is true,
+otherwise it is @var{false-value}.
+
+@cindex @code{cond} and attributes
+@item (cond [@var{test1} @var{value1} @dots{}] @var{default})
+The first operand of this expression is a vector containing an even
+number of expressions and consisting of pairs of @var{test} and @var{value}
+expressions. The value of the @code{cond} expression is that of the
+@var{value} corresponding to the first true @var{test} expression. If
+none of the @var{test} expressions are true, the value of the @code{cond}
+expression is that of the @var{default} expression.
+@end table
+
+@var{test} expressions can have one of the following forms:
+
+@table @code
+@cindex @code{const_int} and attribute tests
+@item (const_int @var{i})
+This test is true if @var{i} is non-zero and false otherwise.
+
+@cindex @code{not} and attributes
+@cindex @code{ior} and attributes
+@cindex @code{and} and attributes
+@item (not @var{test})
+@itemx (ior @var{test1} @var{test2})
+@itemx (and @var{test1} @var{test2})
+These tests are true if the indicated logical function is true.
+
+@cindex @code{match_operand} and attributes
+@item (match_operand:@var{m} @var{n} @var{pred} @var{constraints})
+This test is true if operand @var{n} of the insn whose attribute value
+is being determined has mode @var{m} (this part of the test is ignored
+if @var{m} is @code{VOIDmode}) and the function specified by the string
+@var{pred} returns a non-zero value when passed operand @var{n} and mode
+@var{m} (this part of the test is ignored if @var{pred} is the null
+string).
+
+The @var{constraints} operand is ignored and should be the null string.
+
+@cindex @code{le} and attributes
+@cindex @code{leu} and attributes
+@cindex @code{lt} and attributes
+@cindex @code{gt} and attributes
+@cindex @code{gtu} and attributes
+@cindex @code{ge} and attributes
+@cindex @code{geu} and attributes
+@cindex @code{ne} and attributes
+@cindex @code{eq} and attributes
+@cindex @code{plus} and attributes
+@cindex @code{minus} and attributes
+@cindex @code{mult} and attributes
+@cindex @code{div} and attributes
+@cindex @code{mod} and attributes
+@cindex @code{abs} and attributes
+@cindex @code{neg} and attributes
+@cindex @code{ashift} and attributes
+@cindex @code{lshiftrt} and attributes
+@cindex @code{ashiftrt} and attributes
+@item (le @var{arith1} @var{arith2})
+@itemx (leu @var{arith1} @var{arith2})
+@itemx (lt @var{arith1} @var{arith2})
+@itemx (ltu @var{arith1} @var{arith2})
+@itemx (gt @var{arith1} @var{arith2})
+@itemx (gtu @var{arith1} @var{arith2})
+@itemx (ge @var{arith1} @var{arith2})
+@itemx (geu @var{arith1} @var{arith2})
+@itemx (ne @var{arith1} @var{arith2})
+@itemx (eq @var{arith1} @var{arith2})
+These tests are true if the indicated comparison of the two arithmetic
+expressions is true. Arithmetic expressions are formed with
+@code{plus}, @code{minus}, @code{mult}, @code{div}, @code{mod},
+@code{abs}, @code{neg}, @code{and}, @code{ior}, @code{xor}, @code{not},
+@code{ashift}, @code{lshiftrt}, and @code{ashiftrt} expressions.@refill
+
+@findex get_attr
+@code{const_int} and @code{symbol_ref} are always valid terms (@pxref{Insn
+Lengths},for additional forms). @code{symbol_ref} is a string
+denoting a C expression that yields an @code{int} when evaluated by the
+@samp{get_attr_@dots{}} routine. It should normally be a global
+variable.@refill
+
+@findex eq_attr
+@item (eq_attr @var{name} @var{value})
+@var{name} is a string specifying the name of an attribute.
+
+@var{value} is a string that is either a valid value for attribute
+@var{name}, a comma-separated list of values, or @samp{!} followed by a
+value or list. If @var{value} does not begin with a @samp{!}, this
+test is true if the value of the @var{name} attribute of the current
+insn is in the list specified by @var{value}. If @var{value} begins
+with a @samp{!}, this test is true if the attribute's value is
+@emph{not} in the specified list.
+
+For example,
+
+@smallexample
+(eq_attr "type" "load,store")
+@end smallexample
+
+@noindent
+is equivalent to
+
+@smallexample
+(ior (eq_attr "type" "load") (eq_attr "type" "store"))
+@end smallexample
+
+If @var{name} specifies an attribute of @samp{alternative}, it refers to the
+value of the compiler variable @code{which_alternative}
+(@pxref{Output Statement}) and the values must be small integers. For
+example,@refill
+
+@smallexample
+(eq_attr "alternative" "2,3")
+@end smallexample
+
+@noindent
+is equivalent to
+
+@smallexample
+(ior (eq (symbol_ref "which_alternative") (const_int 2))
+ (eq (symbol_ref "which_alternative") (const_int 3)))
+@end smallexample
+
+Note that, for most attributes, an @code{eq_attr} test is simplified in cases
+where the value of the attribute being tested is known for all insns matching
+a particular pattern. This is by far the most common case.@refill
+
+@findex attr_flag
+@item (attr_flag @var{name})
+The value of an @code{attr_flag} expression is true if the flag
+specified by @var{name} is true for the @code{insn} currently being
+scheduled.
+
+@var{name} is a string specifying one of a fixed set of flags to test.
+Test the flags @code{forward} and @code{backward} to determine the
+direction of a conditional branch. Test the flags @code{very_likely},
+@code{likely}, @code{very_unlikely}, and @code{unlikely} to determine
+if a conditional branch is expected to be taken.
+
+If the @code{very_likely} flag is true, then the @code{likely} flag is also
+true. Likewise for the @code{very_unlikely} and @code{unlikely} flags.
+
+This example describes a conditional branch delay slot which
+can be nullified for forward branches that are taken (annul-true) or
+for backward branches which are not taken (annul-false).
+
+@smallexample
+(define_delay (eq_attr "type" "cbranch")
+ [(eq_attr "in_branch_delay" "true")
+ (and (eq_attr "in_branch_delay" "true")
+ (attr_flag "forward"))
+ (and (eq_attr "in_branch_delay" "true")
+ (attr_flag "backward"))])
+@end smallexample
+
+The @code{forward} and @code{backward} flags are false if the current
+@code{insn} being scheduled is not a conditional branch.
+
+The @code{very_likely} and @code{likely} flags are true if the
+@code{insn} being scheduled is not a conditional branch. The
+The @code{very_unlikely} and @code{unlikely} flags are false if the
+@code{insn} being scheduled is not a conditional branch.
+
+@code{attr_flag} is only used during delay slot scheduling and has no
+meaning to other passes of the compiler.
+@end table
+
+@node Tagging Insns
+@subsection Assigning Attribute Values to Insns
+@cindex tagging insns
+@cindex assigning attribute values to insns
+
+The value assigned to an attribute of an insn is primarily determined by
+which pattern is matched by that insn (or which @code{define_peephole}
+generated it). Every @code{define_insn} and @code{define_peephole} can
+have an optional last argument to specify the values of attributes for
+matching insns. The value of any attribute not specified in a particular
+insn is set to the default value for that attribute, as specified in its
+@code{define_attr}. Extensive use of default values for attributes
+permits the specification of the values for only one or two attributes
+in the definition of most insn patterns, as seen in the example in the
+next section.@refill
+
+The optional last argument of @code{define_insn} and
+@code{define_peephole} is a vector of expressions, each of which defines
+the value for a single attribute. The most general way of assigning an
+attribute's value is to use a @code{set} expression whose first operand is an
+@code{attr} expression giving the name of the attribute being set. The
+second operand of the @code{set} is an attribute expression
+(@pxref{Expressions}) giving the value of the attribute.@refill
+
+When the attribute value depends on the @samp{alternative} attribute
+(i.e., which is the applicable alternative in the constraint of the
+insn), the @code{set_attr_alternative} expression can be used. It
+allows the specification of a vector of attribute expressions, one for
+each alternative.
+
+@findex set_attr
+When the generality of arbitrary attribute expressions is not required,
+the simpler @code{set_attr} expression can be used, which allows
+specifying a string giving either a single attribute value or a list
+of attribute values, one for each alternative.
+
+The form of each of the above specifications is shown below. In each case,
+@var{name} is a string specifying the attribute to be set.
+
+@table @code
+@item (set_attr @var{name} @var{value-string})
+@var{value-string} is either a string giving the desired attribute value,
+or a string containing a comma-separated list giving the values for
+succeeding alternatives. The number of elements must match the number
+of alternatives in the constraint of the insn pattern.
+
+Note that it may be useful to specify @samp{*} for some alternative, in
+which case the attribute will assume its default value for insns matching
+that alternative.
+
+@findex set_attr_alternative
+@item (set_attr_alternative @var{name} [@var{value1} @var{value2} @dots{}])
+Depending on the alternative of the insn, the value will be one of the
+specified values. This is a shorthand for using a @code{cond} with
+tests on the @samp{alternative} attribute.
+
+@findex attr
+@item (set (attr @var{name}) @var{value})
+The first operand of this @code{set} must be the special RTL expression
+@code{attr}, whose sole operand is a string giving the name of the
+attribute being set. @var{value} is the value of the attribute.
+@end table
+
+The following shows three different ways of representing the same
+attribute value specification:
+
+@smallexample
+(set_attr "type" "load,store,arith")
+
+(set_attr_alternative "type"
+ [(const_string "load") (const_string "store")
+ (const_string "arith")])
+
+(set (attr "type")
+ (cond [(eq_attr "alternative" "1") (const_string "load")
+ (eq_attr "alternative" "2") (const_string "store")]
+ (const_string "arith")))
+@end smallexample
+
+@need 1000
+@findex define_asm_attributes
+The @code{define_asm_attributes} expression provides a mechanism to
+specify the attributes assigned to insns produced from an @code{asm}
+statement. It has the form:
+
+@smallexample
+(define_asm_attributes [@var{attr-sets}])
+@end smallexample
+
+@noindent
+where @var{attr-sets} is specified the same as for both the
+@code{define_insn} and the @code{define_peephole} expressions.
+
+These values will typically be the ``worst case'' attribute values. For
+example, they might indicate that the condition code will be clobbered.
+
+A specification for a @code{length} attribute is handled specially. The
+way to compute the length of an @code{asm} insn is to multiply the
+length specified in the expression @code{define_asm_attributes} by the
+number of machine instructions specified in the @code{asm} statement,
+determined by counting the number of semicolons and newlines in the
+string. Therefore, the value of the @code{length} attribute specified
+in a @code{define_asm_attributes} should be the maximum possible length
+of a single machine instruction.
+
+@node Attr Example
+@subsection Example of Attribute Specifications
+@cindex attribute specifications example
+@cindex attribute specifications
+
+The judicious use of defaulting is important in the efficient use of
+insn attributes. Typically, insns are divided into @dfn{types} and an
+attribute, customarily called @code{type}, is used to represent this
+value. This attribute is normally used only to define the default value
+for other attributes. An example will clarify this usage.
+
+Assume we have a RISC machine with a condition code and in which only
+full-word operations are performed in registers. Let us assume that we
+can divide all insns into loads, stores, (integer) arithmetic
+operations, floating point operations, and branches.
+
+Here we will concern ourselves with determining the effect of an insn on
+the condition code and will limit ourselves to the following possible
+effects: The condition code can be set unpredictably (clobbered), not
+be changed, be set to agree with the results of the operation, or only
+changed if the item previously set into the condition code has been
+modified.
+
+Here is part of a sample @file{md} file for such a machine:
+
+@smallexample
+(define_attr "type" "load,store,arith,fp,branch" (const_string "arith"))
+
+(define_attr "cc" "clobber,unchanged,set,change0"
+ (cond [(eq_attr "type" "load")
+ (const_string "change0")
+ (eq_attr "type" "store,branch")
+ (const_string "unchanged")
+ (eq_attr "type" "arith")
+ (if_then_else (match_operand:SI 0 "" "")
+ (const_string "set")
+ (const_string "clobber"))]
+ (const_string "clobber")))
+
+(define_insn ""
+ [(set (match_operand:SI 0 "general_operand" "=r,r,m")
+ (match_operand:SI 1 "general_operand" "r,m,r"))]
+ ""
+ "@@
+ move %0,%1
+ load %0,%1
+ store %0,%1"
+ [(set_attr "type" "arith,load,store")])
+@end smallexample
+
+Note that we assume in the above example that arithmetic operations
+performed on quantities smaller than a machine word clobber the condition
+code since they will set the condition code to a value corresponding to the
+full-word result.
+
+@node Insn Lengths
+@subsection Computing the Length of an Insn
+@cindex insn lengths, computing
+@cindex computing the length of an insn
+
+For many machines, multiple types of branch instructions are provided, each
+for different length branch displacements. In most cases, the assembler
+will choose the correct instruction to use. However, when the assembler
+cannot do so, GCC can when a special attribute, the @samp{length}
+attribute, is defined. This attribute must be defined to have numeric
+values by specifying a null string in its @code{define_attr}.
+
+In the case of the @samp{length} attribute, two additional forms of
+arithmetic terms are allowed in test expressions:
+
+@table @code
+@cindex @code{match_dup} and attributes
+@item (match_dup @var{n})
+This refers to the address of operand @var{n} of the current insn, which
+must be a @code{label_ref}.
+
+@cindex @code{pc} and attributes
+@item (pc)
+This refers to the address of the @emph{current} insn. It might have
+been more consistent with other usage to make this the address of the
+@emph{next} insn but this would be confusing because the length of the
+current insn is to be computed.
+@end table
+
+@cindex @code{addr_vec}, length of
+@cindex @code{addr_diff_vec}, length of
+For normal insns, the length will be determined by value of the
+@samp{length} attribute. In the case of @code{addr_vec} and
+@code{addr_diff_vec} insn patterns, the length is computed as
+the number of vectors multiplied by the size of each vector.
+
+Lengths are measured in addressable storage units (bytes).
+
+The following macros can be used to refine the length computation:
+
+@table @code
+@findex FIRST_INSN_ADDRESS
+@item FIRST_INSN_ADDRESS
+When the @code{length} insn attribute is used, this macro specifies the
+value to be assigned to the address of the first insn in a function. If
+not specified, 0 is used.
+
+@findex ADJUST_INSN_LENGTH
+@item ADJUST_INSN_LENGTH (@var{insn}, @var{length})
+If defined, modifies the length assigned to instruction @var{insn} as a
+function of the context in which it is used. @var{length} is an lvalue
+that contains the initially computed length of the insn and should be
+updated with the correct length of the insn. If updating is required,
+@var{insn} must not be a varying-length insn.
+
+This macro will normally not be required. A case in which it is
+required is the ROMP. On this machine, the size of an @code{addr_vec}
+insn must be increased by two to compensate for the fact that alignment
+may be required.
+@end table
+
+@findex get_attr_length
+The routine that returns @code{get_attr_length} (the value of the
+@code{length} attribute) can be used by the output routine to
+determine the form of the branch instruction to be written, as the
+example below illustrates.
+
+As an example of the specification of variable-length branches, consider
+the IBM 360. If we adopt the convention that a register will be set to
+the starting address of a function, we can jump to labels within 4k of
+the start using a four-byte instruction. Otherwise, we need a six-byte
+sequence to load the address from memory and then branch to it.
+
+On such a machine, a pattern for a branch instruction might be specified
+as follows:
+
+@smallexample
+(define_insn "jump"
+ [(set (pc)
+ (label_ref (match_operand 0 "" "")))]
+ ""
+ "*
+@{
+ return (get_attr_length (insn) == 4
+ ? \"b %l0\" : \"l r15,=a(%l0); br r15\");
+@}"
+ [(set (attr "length") (if_then_else (lt (match_dup 0) (const_int 4096))
+ (const_int 4)
+ (const_int 6)))])
+@end smallexample
+
+@node Constant Attributes
+@subsection Constant Attributes
+@cindex constant attributes
+
+A special form of @code{define_attr}, where the expression for the
+default value is a @code{const} expression, indicates an attribute that
+is constant for a given run of the compiler. Constant attributes may be
+used to specify which variety of processor is used. For example,
+
+@smallexample
+(define_attr "cpu" "m88100,m88110,m88000"
+ (const
+ (cond [(symbol_ref "TARGET_88100") (const_string "m88100")
+ (symbol_ref "TARGET_88110") (const_string "m88110")]
+ (const_string "m88000"))))
+
+(define_attr "memory" "fast,slow"
+ (const
+ (if_then_else (symbol_ref "TARGET_FAST_MEM")
+ (const_string "fast")
+ (const_string "slow"))))
+@end smallexample
+
+The routine generated for constant attributes has no parameters as it
+does not depend on any particular insn. RTL expressions used to define
+the value of a constant attribute may use the @code{symbol_ref} form,
+but may not use either the @code{match_operand} form or @code{eq_attr}
+forms involving insn attributes.
+
+@node Delay Slots
+@subsection Delay Slot Scheduling
+@cindex delay slots, defining
+
+The insn attribute mechanism can be used to specify the requirements for
+delay slots, if any, on a target machine. An instruction is said to
+require a @dfn{delay slot} if some instructions that are physically
+after the instruction are executed as if they were located before it.
+Classic examples are branch and call instructions, which often execute
+the following instruction before the branch or call is performed.
+
+On some machines, conditional branch instructions can optionally
+@dfn{annul} instructions in the delay slot. This means that the
+instruction will not be executed for certain branch outcomes. Both
+instructions that annul if the branch is true and instructions that
+annul if the branch is false are supported.
+
+Delay slot scheduling differs from instruction scheduling in that
+determining whether an instruction needs a delay slot is dependent only
+on the type of instruction being generated, not on data flow between the
+instructions. See the next section for a discussion of data-dependent
+instruction scheduling.
+
+@findex define_delay
+The requirement of an insn needing one or more delay slots is indicated
+via the @code{define_delay} expression. It has the following form:
+
+@smallexample
+(define_delay @var{test}
+ [@var{delay-1} @var{annul-true-1} @var{annul-false-1}
+ @var{delay-2} @var{annul-true-2} @var{annul-false-2}
+ @dots{}])
+@end smallexample
+
+@var{test} is an attribute test that indicates whether this
+@code{define_delay} applies to a particular insn. If so, the number of
+required delay slots is determined by the length of the vector specified
+as the second argument. An insn placed in delay slot @var{n} must
+satisfy attribute test @var{delay-n}. @var{annul-true-n} is an
+attribute test that specifies which insns may be annulled if the branch
+is true. Similarly, @var{annul-false-n} specifies which insns in the
+delay slot may be annulled if the branch is false. If annulling is not
+supported for that delay slot, @code{(nil)} should be coded.@refill
+
+For example, in the common case where branch and call insns require
+a single delay slot, which may contain any insn other than a branch or
+call, the following would be placed in the @file{md} file:
+
+@smallexample
+(define_delay (eq_attr "type" "branch,call")
+ [(eq_attr "type" "!branch,call") (nil) (nil)])
+@end smallexample
+
+Multiple @code{define_delay} expressions may be specified. In this
+case, each such expression specifies different delay slot requirements
+and there must be no insn for which tests in two @code{define_delay}
+expressions are both true.
+
+For example, if we have a machine that requires one delay slot for branches
+but two for calls, no delay slot can contain a branch or call insn,
+and any valid insn in the delay slot for the branch can be annulled if the
+branch is true, we might represent this as follows:
+
+@smallexample
+(define_delay (eq_attr "type" "branch")
+ [(eq_attr "type" "!branch,call")
+ (eq_attr "type" "!branch,call")
+ (nil)])
+
+(define_delay (eq_attr "type" "call")
+ [(eq_attr "type" "!branch,call") (nil) (nil)
+ (eq_attr "type" "!branch,call") (nil) (nil)])
+@end smallexample
+@c the above is *still* too long. --mew 4feb93
+
+@node Function Units
+@subsection Specifying Function Units
+@cindex function units, for scheduling
+
+On most RISC machines, there are instructions whose results are not
+available for a specific number of cycles. Common cases are instructions
+that load data from memory. On many machines, a pipeline stall will result
+if the data is referenced too soon after the load instruction.
+
+In addition, many newer microprocessors have multiple function units, usually
+one for integer and one for floating point, and often will incur pipeline
+stalls when a result that is needed is not yet ready.
+
+The descriptions in this section allow the specification of how much
+time must elapse between the execution of an instruction and the time
+when its result is used. It also allows specification of when the
+execution of an instruction will delay execution of similar instructions
+due to function unit conflicts.
+
+For the purposes of the specifications in this section, a machine is
+divided into @dfn{function units}, each of which execute a specific
+class of instructions in first-in-first-out order. Function units that
+accept one instruction each cycle and allow a result to be used in the
+succeeding instruction (usually via forwarding) need not be specified.
+Classic RISC microprocessors will normally have a single function unit,
+which we can call @samp{memory}. The newer ``superscalar'' processors
+will often have function units for floating point operations, usually at
+least a floating point adder and multiplier.
+
+@findex define_function_unit
+Each usage of a function units by a class of insns is specified with a
+@code{define_function_unit} expression, which looks like this:
+
+@smallexample
+(define_function_unit @var{name} @var{multiplicity} @var{simultaneity}
+ @var{test} @var{ready-delay} @var{issue-delay}
+ [@var{conflict-list}])
+@end smallexample
+
+@var{name} is a string giving the name of the function unit.
+
+@var{multiplicity} is an integer specifying the number of identical
+units in the processor. If more than one unit is specified, they will
+be scheduled independently. Only truly independent units should be
+counted; a pipelined unit should be specified as a single unit. (The
+only common example of a machine that has multiple function units for a
+single instruction class that are truly independent and not pipelined
+are the two multiply and two increment units of the CDC 6600.)
+
+@var{simultaneity} specifies the maximum number of insns that can be
+executing in each instance of the function unit simultaneously or zero
+if the unit is pipelined and has no limit.
+
+All @code{define_function_unit} definitions referring to function unit
+@var{name} must have the same name and values for @var{multiplicity} and
+@var{simultaneity}.
+
+@var{test} is an attribute test that selects the insns we are describing
+in this definition. Note that an insn may use more than one function
+unit and a function unit may be specified in more than one
+@code{define_function_unit}.
+
+@var{ready-delay} is an integer that specifies the number of cycles
+after which the result of the instruction can be used without
+introducing any stalls.
+
+@var{issue-delay} is an integer that specifies the number of cycles
+after the instruction matching the @var{test} expression begins using
+this unit until a subsequent instruction can begin. A cost of @var{N}
+indicates an @var{N-1} cycle delay. A subsequent instruction may also
+be delayed if an earlier instruction has a longer @var{ready-delay}
+value. This blocking effect is computed using the @var{simultaneity},
+@var{ready-delay}, @var{issue-delay}, and @var{conflict-list} terms.
+For a normal non-pipelined function unit, @var{simultaneity} is one, the
+unit is taken to block for the @var{ready-delay} cycles of the executing
+insn, and smaller values of @var{issue-delay} are ignored.
+
+@var{conflict-list} is an optional list giving detailed conflict costs
+for this unit. If specified, it is a list of condition test expressions
+to be applied to insns chosen to execute in @var{name} following the
+particular insn matching @var{test} that is already executing in
+@var{name}. For each insn in the list, @var{issue-delay} specifies the
+conflict cost; for insns not in the list, the cost is zero. If not
+specified, @var{conflict-list} defaults to all instructions that use the
+function unit.
+
+Typical uses of this vector are where a floating point function unit can
+pipeline either single- or double-precision operations, but not both, or
+where a memory unit can pipeline loads, but not stores, etc.
+
+As an example, consider a classic RISC machine where the result of a
+load instruction is not available for two cycles (a single ``delay''
+instruction is required) and where only one load instruction can be executed
+simultaneously. This would be specified as:
+
+@smallexample
+(define_function_unit "memory" 1 1 (eq_attr "type" "load") 2 0)
+@end smallexample
+
+For the case of a floating point function unit that can pipeline either
+single or double precision, but not both, the following could be specified:
+
+@smallexample
+(define_function_unit
+ "fp" 1 0 (eq_attr "type" "sp_fp") 4 4 [(eq_attr "type" "dp_fp")])
+(define_function_unit
+ "fp" 1 0 (eq_attr "type" "dp_fp") 4 4 [(eq_attr "type" "sp_fp")])
+@end smallexample
+
+@strong{Note:} The scheduler attempts to avoid function unit conflicts
+and uses all the specifications in the @code{define_function_unit}
+expression. It has recently come to our attention that these
+specifications may not allow modeling of some of the newer
+``superscalar'' processors that have insns using multiple pipelined
+units. These insns will cause a potential conflict for the second unit
+used during their execution and there is no way of representing that
+conflict. We welcome any examples of how function unit conflicts work
+in such processors and suggestions for their representation.
+@end ifset
diff --git a/gnu/usr.bin/cc/doc/reno.texi b/gnu/usr.bin/cc/doc/reno.texi
new file mode 100644
index 0000000..59c3448
--- /dev/null
+++ b/gnu/usr.bin/cc/doc/reno.texi
@@ -0,0 +1,752 @@
+\input texinfo @c -*- Texinfo -*-
+@setfilename reno-1.info
+
+@ifinfo
+@format
+START-INFO-DIR-ENTRY
+* Reno 1: (reno-1). The GNU C++ Renovation Project, Phase 1.
+END-INFO-DIR-ENTRY
+@end format
+@end ifinfo
+
+@ifinfo
+Copyright @copyright{} 1992, 1993, 1994 Free Software Foundation, Inc.
+
+Permission is granted to make and distribute verbatim copies of
+this manual provided the copyright notice and this permission notice
+are preserved on all copies.
+
+@ignore
+Permission is granted to process this file through TeX and print the
+results, provided the printed document carries a copying permission
+notice identical to this one except for the removal of this paragraph
+(this paragraph not being relevant to the printed manual).
+
+@end ignore
+
+Permission is granted to copy and distribute modified versions of this
+manual under the conditions for verbatim copying, provided also that
+the entire resulting derived work is distributed under the terms of a
+permission notice identical to this one.
+
+Permission is granted to copy and distribute translations of this manual
+into another language, under the above conditions for modified versions.
+@end ifinfo
+
+@setchapternewpage odd
+@settitle GNU C++ Renovation Project
+@c @smallbook
+
+@titlepage
+@finalout
+@title GNU C++ Renovation Project
+@subtitle Phase 1.3
+@author Brendan Kehoe, Jason Merrill,
+@author Mike Stump, Michael Tiemann
+@page
+
+Edited March, 1994 by Roland Pesch (@code{pesch@@cygnus.com})
+@vskip 0pt plus 1filll
+Copyright @copyright{} 1992, 1993, 1994 Free Software Foundation, Inc.
+
+Permission is granted to make and distribute verbatim copies of
+this manual provided the copyright notice and this permission notice
+are preserved on all copies.
+
+@ignore
+Permission is granted to process this file through Tex and print the
+results, provided the printed document carries copying permission
+notice identical to this one except for the removal of this paragraph
+(this paragraph not being relevant to the printed manual).
+@end ignore
+
+Permission is granted to copy and distribute modified versions of this
+manual under the conditions for verbatim copying, provided also that
+the entire resulting derived work is distributed under the terms of a
+permission notice identical to this one.
+
+Permission is granted to copy and distribute translations of this manual
+into another language, under the above conditions for modified versions.
+@end titlepage
+
+@ifinfo
+@node Top
+@top @sc{gnu} C++ Renovation Project
+
+This file describes the goals of the @sc{gnu} C++ Renovation Project,
+and its accomplishments to date (as of Phase 1.3).
+
+It also discusses the remaining divergences from @sc{gnu} C++, and how the
+name encoding in @sc{gnu} C++ differs from the sample encoding in
+@cite{The Annotated C++ Reference Manual}.
+@c This is not a good place to introduce the acronym ARM because it's
+@c info-only.
+
+@menu
+* Introduction:: What is the GNU C++ Renovation Project?
+* Changes:: Summary of changes since previous GNU C++ releases.
+* Plans:: Plans for Reno-2.
+* Templates:: The template implementation.
+* ANSI:: GNU C++ conformance to ANSI C++.
+* Encoding:: Name encoding in GNU C++.
+@end menu
+
+@end ifinfo
+
+@node Introduction
+@chapter Introduction
+
+As you may remember, @sc{gnu} C++ was the first native-code C++
+compiler available under Unix (December 1987). In November 1988, it was
+judged superior to the AT&T compiler in a Unix World review. In 1990 it
+won a Sun Observer ``Best-Of'' award. But now, with new requirements
+coming out of the @sc{ansi} C++ committee and a growing backlog of bugs, it's
+clear that @sc{gnu} C++ needs an overhaul.
+
+The C++ language has been under development since 1982. It has
+evolved significantly since its original incarnation (C with Classes),
+addressing many commercial needs and incorporating many lessons
+learned as more and more people started using ``object-oriented''
+programming techniques. In 1989, the first X3J16 committee meeting
+was held in Washington DC; in the interest of users, C++ was going to
+be standardized.
+
+As C++ has become more popular, more demands have been placed on its
+compilers. Some compilers are up to the demands, others are not.
+@sc{gnu} C++ was used to prototype several features which have since
+been incorporated into the standard, most notably exception handling.
+While @sc{gnu} C++ has been an excellent experimental vehicle, it did
+not have the resources that AT&T, Borland, or Microsoft have at their
+disposal.
+
+We believe that @sc{gnu} C++ is an important compiler, providing users with
+many of the features that have made @sc{gnu} C so popular: fast compilation,
+good error messages, innovative features, and full sources that may be
+freely redistributed. The purpose of this overhaul, dubbed the @var{@sc{gnu}
+C++ Renovation Project}, is to take advantage of the functionality that
+@sc{gnu} C++ offers today, to strengthen its base technology, and put it in a
+position to remain---as other @sc{gnu} software currently is---the technical
+leader in the field.
+
+This release represents the latest phase of work in strengthening the
+compiler on a variety of points. It includes many months of
+work concentrated on fixing many of the more egregious bugs that
+presented themselves in the compiler recently.
+@ignore
+@c FIXME-- update?
+Nearly 85% of all bugs reported in the period of February to September
+of 1992 were fixed as part of the work in the first phase.
+@end ignore
+In the coming months, we hope to continue expanding and enhancing the
+quality and dependability of the industry's only freely redistributable
+C++ compiler.
+
+@node Changes
+@chapter Changes in Behavior in @sc{gnu} C++
+
+The @sc{gnu} C++ compiler continues to improve and change. A major goal
+of our work has been to continue to bring the compiler into compliance
+with the draft @sc{ansi} C++ standard, and with @cite{The Annotated C++
+Reference Manual} (the @sc{arm}). This section outlines most of the
+user-noticeable changes that might be encountered during the normal
+course of use.
+
+@menu
+* Summary of Phase 1.3::
+* Major changes::
+* New features::
+* Enhancements and bug fixes::
+* Problems with debugging::
+@end menu
+
+@node Summary of Phase 1.3
+@section Summary of Changes in Phase 1.3
+
+The bulk of this note discusses the cumulative effects of the @sc{gnu} C++
+Renovation Project to date. The work during its most recent phase (1.3)
+had these major effects:
+
+@itemize @bullet
+@item The standard compiler driver @code{g++} is now the faster compiled
+version, rather than a shell script.
+
+@item Nested types work much better; notably, nesting is no longer
+restricted to nine levels.
+
+@item Better @sc{arm} conformance on member access control.
+
+@item The compiler now always generates default assignment operators
+(@samp{operator =}), copy constructors (@samp{X::X(X&)}), and default
+constructors (@samp{X::X()}) whenever they are required.
+
+@item The new draft @sc{ansi} standard keyword @code{mutable} is supported.
+
+@item @samp{-fansi-overloading} is the default, to comply better with
+the @sc{arm} (at some cost in compatibility to earlier versions of @sc{gnu} C++).
+
+@item More informative error messages.
+
+@item System include files are automatically treated as if they were
+wrapped in @samp{extern "C" @{ @}}.
+
+@item The new option @samp{-falt-external-templates} provides alternate
+template instantiation semantics.
+
+@item Operator declarations are now checked more strictly.
+
+@item You can now use template type arguments in the template parameter list.
+
+@item You can call the destructor for any type.
+
+@item The compiler source code is better organized.
+
+@item You can specify where to instantiate template definitions explicitly.
+@end itemize
+
+Much of the work in Phase 1.3 went to elimination of known bugs, as well
+as the major items above.
+
+During the span of Phase 1.3, there were also two changes associated
+with the compiler that, while not specifically part of the C++
+Renovation project, may be of interest:
+
+@itemize @bullet
+@item @code{gcov}, a code coverage tool for @sc{gnu cc}, is now available
+from Cygnus Support. (@code{gcov} is free software, but the @sc{fsf} has not
+yet accepted it.) @xref{Gcov,, @code{gcov}: a Test Coverage Program,
+gcc.info, Using GNU CC}, for more information (in Cygnus releases of
+that manual).
+
+@item @sc{gnu} C++ now supports @dfn{signatures}, a language extension to
+provide more flexibility in abstract type definitions. @xref{C++
+Signatures,, Type Abstraction using Signatures, gcc.info, Using GNU CC}.
+@end itemize
+
+@node Major changes
+@section Major Changes
+
+This release includes four wholesale rewrites of certain areas of
+compiler functionality:
+
+@enumerate 1
+@item Argument matching. @sc{gnu} C++ is more compliant with the rules
+described in Chapter 13, ``Overloading'', of the @sc{arm}. This behavior is
+the default, though you can specify it explicitly with
+@samp{-fansi-overloading}. For compatibility with earlier releases of
+@sc{gnu} C++, specify @samp{-fno-ansi-overloading}; this makes the compiler
+behave as it used to with respect to argument matching and name overloading.
+
+@item Default constructors/destructors. Section 12.8 of the @sc{arm}, ``Copying
+Class Objects'', and Section 12.1, ``Constructors'', state that a
+compiler must declare such default functions if the user does not
+specify them. @sc{gnu} C++ now declares, and generates when necessary,
+the defaults for constructors and destructors you might omit. In
+particular, assignment operators (@samp{operator =}) behave the same way
+whether you define them, or whether the compiler generates them by
+default; taking the address of the default @samp{operator =} is now
+guaranteed to work. Default copy constructors (@samp{X::X(X&)}) now
+function correctly, rather than calling the copy assignment operator for
+the base class. Finally, constructors (@samp{X::X()}), as well as
+assignment operators and copy constructors, are now available whenever
+they are required.
+
+@c XXX This may be taken out eventually...
+@item Binary incompatibility. There are no new binary incompatibilities
+in Phase 1.3, but Phase 1.2 introduced two binary incompatibilities with
+earlier releases. First, the functionality of @samp{operator
+new} and @samp{operator delete} changed. Name encoding
+(``mangling'') of virtual table names changed as well. Libraries
+built with versions of the compiler earlier than Phase 1.2 must be
+compiled with the new compiler. (This includes the Cygnus Q2
+progressive release and the FSF 2.4.5 release.)
+
+@item New @code{g++} driver.
+A new binary @code{g++} compiler driver replaces the shell script.
+The new driver executes faster.
+@end enumerate
+
+@node New features
+@section New features
+
+@itemize @bullet
+@item
+The compiler warns when a class contains only private constructors
+or destructors, and has no friends. At the request of some of our
+customers, we have added a new option, @samp{-Wctor-dtor-privacy} (on by
+default), and its negation, @samp{-Wno-ctor-dtor-privacy}, to control
+the emission of this warning. If, for example, you are working towards
+making your code compile warning-free, you can use @w{@samp{-Wall
+-Wno-ctor-dtor-privacy}} to find the most common warnings.
+
+@item
+There is now a mechanism which controls exactly when templates are
+expanded, so that you can reduce memory usage and program size and also
+instantiate them exactly once. You can control this mechanism with the
+option @samp{-fexternal-templates} and its corresponding negation
+@samp{-fno-external-templates}. Without this feature, space consumed by
+template instantiations can grow unacceptably in large-scale projects
+with many different source files. The default is
+@samp{-fno-external-templates}.
+
+You do not need to use the @samp{-fexternal-templates} option when
+compiling a file that does not define and instantiate templates used in
+other files, even if those files @emph{are} compiled with
+@samp{-fexternal-templates}. The only side effect is an increase in
+object size for each file that was compiled without
+@samp{-fexternal-templates}.
+
+When your code is compiled with @samp{-fexternal-templates}, all
+template instantiations are external; this requires that the templates
+be under the control of @samp{#pragma interface} and @samp{#pragma
+implementation}. All instantiations that will be needed should be in
+the implementation file; you can do this with a @code{typedef} that
+references the instantiation needed. Conversely, when you compile using
+the option @samp{-fno-external-templates}, all template instantiations are
+explicitly internal.
+
+@samp{-fexternal-templates} also allows you to finally separate class
+template function definitions from their declarations, thus speeding up
+compilation times for every file that includes the template declaration.
+Now you can have tens or even hundreds of lines in template
+declarations, and thousands or tens of thousands of lines in template
+definitions, with the definitions only going through the compiler once
+instead of once for each source file. It is important to note that you
+must remember to externally instantiate @emph{all} templates that are
+used from template declarations in interface files. If you forget to do
+this, unresolved externals will occur.
+
+In the example below, the object file generated (@file{example.o}) will
+contain the global instantiation for @samp{Stack<int>}. If other types
+of @samp{Stack} are needed, they can be added to @file{example.cc} or
+placed in a new file, in the same spirit as @file{example.cc}.
+
+@code{foo.h}:
+@smallexample
+@group
+#pragma interface "foo.h"
+template<class T>
+class Stack @{
+ static int statc;
+ static T statc2;
+ Stack() @{ @}
+ virtual ~Stack() @{ @}
+ int bar();
+@};
+@end group
+@end smallexample
+
+@code{example.cc}:
+@smallexample
+@group
+#pragma implementation "foo.h"
+#include "foo.h"
+
+typedef Stack<int> t;
+int Stack<int>::statc;
+int Stack<int>::statc2;
+int Stack<int>::bar() @{ @}
+@end group
+@end smallexample
+
+Note that using @samp{-fexternal-templates} does not reduce memory usage
+from completely different instantiations (@samp{Stack<Name>} vs.
+@samp{Stack<Net_Connection>}), but only collapses different occurrences
+of @samp{Stack<Name>} so that only one @samp{Stack<Name>} is generated.
+
+@samp{-falt-external-templates} selects a slight variation in the
+semantics described above (incidentally, you need not specify both
+options; @samp{-falt-external-templates} implies
+@samp{-fexternal-templates}).
+
+With @samp{-fexternal-templates}, the compiler emits a definition in the
+implementation file that includes the header definition, @emph{even if}
+instantiation is triggered from a @emph{different} implementation file
+(e.g. with a template that uses another template).
+
+With @samp{-falt-external-templates}, the definition always goes in the
+implementation file that triggers instantiation.
+
+For instance, with these two header files---
+
+@example
+@exdent @file{a.h}:
+#pragma interface
+template <class T> class A @{ @dots{} @};
+
+@exdent @file{b.h}:
+#pragma interface
+class B @{ @dots{} @};
+void f (A<B>);
+@end example
+
+Under @samp{-fexternal-templates}, the definition of @samp{A<B>} ends up
+in the implementation file that includes @file{a.h}. Under
+@samp{-falt-external-templates}, the same definition ends up in the
+implementation file that includes @file{b.h}.
+
+@item
+You can control explicitly where a template is instantiated, without
+having to @emph{use} the template to get an instantiation.
+
+To instantiate a class template explicitly, write @samp{template
+class @var{name}<paramvals>}, where @var{paramvals} is a list of values
+for the template parameters. For example, you might write
+
+@example
+template class A<int>
+@end example
+
+Similarly, to instantiate a function template explicitly, write
+@samp{template @var{fnsign}} where @var{fnsign} is the particular
+function signature you need. For example, you might write
+
+@example
+template void foo (int, int)
+@end example
+
+This syntax for explicit template instantiation agrees with recent
+extensions to the draft @sc{ansi} standard.
+
+@item
+The compiler's actions on @sc{ansi}-related warnings and errors have
+been further enhanced. The @samp{-pedantic-errors} option produces
+error messages in a number of new situations: using @code{return} in a
+non-@code{void} function (one returning a value); declaring a local
+variable that shadows a parameter (e.g., the function takes an argument
+@samp{a}, and has a local variable @samp{a}); and use of the @samp{asm}
+keyword. Finally, the compiler by default now issues a warning when
+converting from an @code{int} to an enumerated type. This is likely to
+cause many new warnings in code that hadn't triggered them before. For
+example, when you compile this code,
+
+@smallexample
+@group
+enum boolean @{ false, true @};
+void
+f ()
+@{
+ boolean x;
+
+ x = 1; //@i{assigning an @code{int} to an @code{enum} now triggers a warning}
+@}
+@end group
+@end smallexample
+
+@noindent
+you should see the warning ``@code{anachronistic conversion from integer
+type to enumeral type `boolean'}''. Instead of assigning the value 1,
+assign the original enumerated value @samp{true}.
+@end itemize
+
+@node Enhancements and bug fixes
+@section Enhancements and bug fixes
+
+@itemize @bullet
+@cindex nested types in template parameters
+@item
+You can now use nested types in a template parameter list, even if the nested
+type is defined within the same class that attempts to use the template.
+For example, given a template @code{list}, the following now works:
+
+@smallexample
+struct glyph @{
+ @dots{}
+ struct stroke @{ @dots{} @};
+ list<stroke> l;
+ @dots{}
+@}
+@end smallexample
+
+@cindex function pointers vs template parameters
+@item
+Function pointers now work in template parameter lists. For
+example, you might want to instantiate a parameterized @code{list} class
+in terms of a pointer to a function like this:
+
+@smallexample
+list<int (*)(int, void *)> fnlist;
+@end smallexample
+
+@item
+@c FIXME! Really no limit? Jason said "deeper than 9" now OK...
+Nested types are now handled correctly. In particular, there is no
+longer a limit to how deeply you can nest type definitions.
+
+@item
+@sc{gnu} C++ now conforms to the specifications in Chapter 11 of the
+@sc{arm}, ``Member Access Control''.
+
+@item
+The @sc{ansi} C++ committee has introduced a new keyword @code{mutable}.
+@sc{gnu} C++ supports it. Use @code{mutable} to specify that some
+particular members of a @code{const} class are @emph{not} constant. For
+example, you can use this to include a cache in a data structure that
+otherwise represents a read-only database.
+
+@item
+Error messages now explicitly specify the declaration, type, or
+expression that contains an error.
+
+@item
+To avoid copying and editing all system include files during @sc{gnu}
+C++ installation, the compiler now automatically recognizes system
+include files as C language definitions, as if they were wrapped in
+@samp{extern "C" @{ @dots{} @}}.
+
+@item
+The compiler checks operator declarations more strictly. For example,
+you may no longer declare an @samp{operator +} with three arguments.
+
+@item
+You can now use template type arguments in the same template
+parameter list where the type argument is specified (as well as in the
+template body). For example, you may write
+
+@example
+template <class T, T t> class A @{ @dots{} @};
+@end example
+
+@item
+Destructors are now available for all types, even built-in ones; for
+example, you can call @samp{int::~int}. (Destructors for types like
+@code{int} do not actually do anything, but their existence provides a
+level of generality that permits smooth template expansion in more
+cases.)
+
+@item
+Enumerated types declared inside a class are now handled correctly.
+
+@item
+An argument list for a function may not use an initializer list for its default
+value. For example, @w{@samp{void foo ( T x = @{ 1, 2 @} )}} is not permitted.
+
+@item
+A significant amount of work went into improving the ability of the
+compiler to act accurately on multiple inheritance and virtual
+functions. Virtual function dispatch has been enhanced as well.
+
+@item
+The warning concerning a virtual inheritance environment with a
+non-virtual destructor has been disabled, since it is not clear that
+such a warning is warranted.
+
+@item
+Until exception handling is fully implemented in the Reno-2 release, use
+of the identifiers @samp{catch}, @samp{throw}, or @samp{try} results
+in the warning:
+
+@smallexample
+t.C:1: warning: `catch', `throw', and `try'
+ are all C++ reserved words
+@end smallexample
+
+@item
+When giving a warning or error concerning initialization of a member in a
+class, the compiler gives the name of the member if it has one.
+
+@item
+Detecting friendship between classes is more accurately checked.
+
+@item
+The syntaxes of @w{@samp{#pragma implementation "file.h"}} and
+@samp{#pragma interface} are now more strictly controlled. The compiler
+notices (and warns) when any text follows @file{file.h} in the
+implementation pragma, or follows the word @samp{interface}. Any such
+text is otherwise ignored.
+
+@item
+Trying to declare a template on a variable or type is now considered an
+error, not an unimplemented feature.
+
+@item
+When an error occurs involving a template, the compiler attempts to
+tell you at which point of instantiation the error occurred, in
+addition to noting the line in the template declaration which had the
+actual error.
+
+@item
+The symbol names for function templates in the resulting assembly file
+are now encoded according to the arguments, rather than just being
+emitted as, for example, two definitions of a function @samp{foo}.
+
+@item
+Template member functions that are declared @code{static} no longer
+receive a @code{this} pointer.
+
+@item
+Case labels are no longer allowed to have commas to make up their
+expressions.
+
+@item
+Warnings concerning the shift count of a left or right shift now tell
+you if it was a @samp{left} or @samp{right} shift.
+
+@item
+The compiler now warns when a decimal constant is so large that it
+becomes @code{unsigned}.
+
+@item
+Union initializers which are raw constructors are now handled properly.
+
+@item
+The compiler no longer gives incorrect errors when initializing a
+union with an empty initializer list.
+
+@item
+Anonymous unions are now correctly used when nested inside a class.
+
+@item
+Anonymous unions declared as static class members are now handled
+properly.
+
+@item
+The compiler now notices when a field in a class is declared both as
+a type and a non-type.
+
+@item
+The compiler now warns when a user-defined function shadows a
+built-in function, rather than emitting an error.
+
+@item
+A conflict between two function declarations now produces an error
+regardless of their language context.
+
+@item
+Duplicate definitions of variables with @samp{extern "C"} linkage are no
+longer considered in error. (Note in C++ linkage---the default---you may
+not have more than one definition of a variable.)
+
+@item
+Referencing a label that is not defined in any function is now an error.
+
+@item
+The syntax for pointers to methods has been improved; there are still
+some minor bugs, but a number of cases should now be accepted by the
+compiler.
+
+@item
+In error messages, arguments are now numbered starting at 1, instead of
+0. Therefore, in the function @samp{void foo (int a, int b)}, the
+argument @samp{a} is argument 1, and @samp{b} is argument 2. There is
+no longer an argument 0.
+
+@item
+The tag for an enumerator, rather than its value, used as a default
+argument is now shown in all error messages. For example, @w{@samp{void
+foo (enum x (= true))}} is shown instead of @w{@samp{void foo (enum x (=
+1))}}.
+
+@item
+The @samp{__asm__} keyword is now accepted by the C++ front-end.
+
+@item
+Expressions of the form @samp{foo->~Class()} are now handled properly.
+
+@item
+The compiler now gives better warnings for situations which result in
+integer overflows (e.g., in storage sizes, enumerators, unary
+expressions, etc).
+
+@item
+@code{unsigned} bitfields are now promoted to @code{signed int} if the
+field isn't as wide as an @code{int}.
+
+@item
+Declaration and usage of prefix and postfix @samp{operator ++} and
+@samp{operator --} are now handled correctly. For example,
+
+@smallexample
+@group
+class foo
+@{
+public:
+ operator ++ ();
+ operator ++ (int);
+ operator -- ();
+ operator -- (int);
+@};
+
+void
+f (foo *f)
+@{
+ f++; // @i{call @code{f->operator++(int)}}
+ ++f; // @i{call @code{f->operator++()}}
+ f--; // @i{call @code{f->operator++(int)}}
+ --f; // @i{call @code{f->operator++()}}
+@}
+@end group
+@end smallexample
+
+@item
+In accordance with @sc{arm} section 10.1.1, ambiguities and dominance are now
+handled properly. The rules described in section 10.1.1 are now fully
+implemented.
+
+@end itemize
+
+@node Problems with debugging
+@section Problems with debugging
+
+Two problems remain with regard to debugging:
+
+@itemize @bullet
+@item
+Debugging of anonymous structures on the IBM RS/6000 host is incorrect.
+
+@item
+Symbol table size is overly large due to redundant symbol information;
+this can make @code{gdb} coredump under certain circumstances. This
+problem is not host-specific.
+@end itemize
+
+@node Plans
+@chapter Plans for Reno-2
+
+The overall goal for the second phase of the @sc{gnu} C++ Renovation
+Project is to bring @sc{gnu} C++ to a new level of reliability, quality,
+and competitiveness. As particular elements of this strategy, we intend
+to:
+
+@enumerate 0
+@item
+Fully implement @sc{ansi} exception handling.
+
+@item
+With the exception handling, add Runtime Type Identification
+(@sc{rtti}), if the @sc{ansi} committee adopts it into the standard.
+
+@item
+Bring the compiler into closer compliance with the @sc{arm} and the draft
+@sc{ansi} standard, and document what points in the @sc{arm} we do not yet comply,
+or agree, with.
+
+@item
+Add further support for the @sc{dwarf} debugging format.
+
+@item
+Finish the work to make the compiler compliant with @sc{arm} Section 12.6.2,
+initializing base classes in declaration order, rather than in the order
+that you specify them in a @var{mem-initializer} list.
+
+@item
+Perform a full coverage analysis on the compiler, and weed out unused
+code, for a gain in performance and a reduction in the size of the compiler.
+
+@item
+Further improve the multiple inheritance implementation in the
+compiler to make it cleaner and more complete.
+@end enumerate
+
+@noindent
+As always, we encourage you to make suggestions and ask questions about
+@sc{gnu} C++ as a whole, so we can be sure that the end of this project
+will bring a compiler that everyone will find essential for C++ and will
+meet the needs of the world's C++ community.
+
+@include templates.texi
+
+@include gpcompare.texi
+
+@contents
+
+@bye
diff --git a/gnu/usr.bin/cc/doc/rtl.texi b/gnu/usr.bin/cc/doc/rtl.texi
new file mode 100644
index 0000000..6da63f2
--- /dev/null
+++ b/gnu/usr.bin/cc/doc/rtl.texi
@@ -0,0 +1,2800 @@
+@c Copyright (C) 1988, 1989, 1992, 1994 Free Software Foundation, Inc.
+@c This is part of the GCC manual.
+@c For copying conditions, see the file gcc.texi.
+
+@node RTL
+@chapter RTL Representation
+@cindex RTL representation
+@cindex representation of RTL
+@cindex Register Transfer Language (RTL)
+
+Most of the work of the compiler is done on an intermediate representation
+called register transfer language. In this language, the instructions to be
+output are described, pretty much one by one, in an algebraic form that
+describes what the instruction does.
+
+RTL is inspired by Lisp lists. It has both an internal form, made up of
+structures that point at other structures, and a textual form that is used
+in the machine description and in printed debugging dumps. The textual
+form uses nested parentheses to indicate the pointers in the internal form.
+
+@menu
+* RTL Objects:: Expressions vs vectors vs strings vs integers.
+* Accessors:: Macros to access expression operands or vector elts.
+* Flags:: Other flags in an RTL expression.
+* Machine Modes:: Describing the size and format of a datum.
+* Constants:: Expressions with constant values.
+* Regs and Memory:: Expressions representing register contents or memory.
+* Arithmetic:: Expressions representing arithmetic on other expressions.
+* Comparisons:: Expressions representing comparison of expressions.
+* Bit Fields:: Expressions representing bitfields in memory or reg.
+* Conversions:: Extending, truncating, floating or fixing.
+* RTL Declarations:: Declaring volatility, constancy, etc.
+* Side Effects:: Expressions for storing in registers, etc.
+* Incdec:: Embedded side-effects for autoincrement addressing.
+* Assembler:: Representing @code{asm} with operands.
+* Insns:: Expression types for entire insns.
+* Calls:: RTL representation of function call insns.
+* Sharing:: Some expressions are unique; others *must* be copied.
+* Reading RTL:: Reading textual RTL from a file.
+@end menu
+
+@node RTL Objects, Accessors, RTL, RTL
+@section RTL Object Types
+@cindex RTL object types
+
+@cindex RTL integers
+@cindex RTL strings
+@cindex RTL vectors
+@cindex RTL expression
+@cindex RTX (See RTL)
+RTL uses five kinds of objects: expressions, integers, wide integers,
+strings and vectors. Expressions are the most important ones. An RTL
+expression (``RTX'', for short) is a C structure, but it is usually
+referred to with a pointer; a type that is given the typedef name
+@code{rtx}.
+
+An integer is simply an @code{int}; their written form uses decimal digits.
+A wide integer is an integral object whose type is @code{HOST_WIDE_INT}
+(@pxref{Config}); their written form uses decimal digits.
+
+A string is a sequence of characters. In core it is represented as a
+@code{char *} in usual C fashion, and it is written in C syntax as well.
+However, strings in RTL may never be null. If you write an empty string in
+a machine description, it is represented in core as a null pointer rather
+than as a pointer to a null character. In certain contexts, these null
+pointers instead of strings are valid. Within RTL code, strings are most
+commonly found inside @code{symbol_ref} expressions, but they appear in
+other contexts in the RTL expressions that make up machine descriptions.
+
+A vector contains an arbitrary number of pointers to expressions. The
+number of elements in the vector is explicitly present in the vector.
+The written form of a vector consists of square brackets
+(@samp{[@dots{}]}) surrounding the elements, in sequence and with
+whitespace separating them. Vectors of length zero are not created;
+null pointers are used instead.
+
+@cindex expression codes
+@cindex codes, RTL expression
+@findex GET_CODE
+@findex PUT_CODE
+Expressions are classified by @dfn{expression codes} (also called RTX
+codes). The expression code is a name defined in @file{rtl.def}, which is
+also (in upper case) a C enumeration constant. The possible expression
+codes and their meanings are machine-independent. The code of an RTX can
+be extracted with the macro @code{GET_CODE (@var{x})} and altered with
+@code{PUT_CODE (@var{x}, @var{newcode})}.
+
+The expression code determines how many operands the expression contains,
+and what kinds of objects they are. In RTL, unlike Lisp, you cannot tell
+by looking at an operand what kind of object it is. Instead, you must know
+from its context---from the expression code of the containing expression.
+For example, in an expression of code @code{subreg}, the first operand is
+to be regarded as an expression and the second operand as an integer. In
+an expression of code @code{plus}, there are two operands, both of which
+are to be regarded as expressions. In a @code{symbol_ref} expression,
+there is one operand, which is to be regarded as a string.
+
+Expressions are written as parentheses containing the name of the
+expression type, its flags and machine mode if any, and then the operands
+of the expression (separated by spaces).
+
+Expression code names in the @samp{md} file are written in lower case,
+but when they appear in C code they are written in upper case. In this
+manual, they are shown as follows: @code{const_int}.
+
+@cindex (nil)
+@cindex nil
+In a few contexts a null pointer is valid where an expression is normally
+wanted. The written form of this is @code{(nil)}.
+
+@node Accessors, Flags, RTL Objects, RTL
+@section Access to Operands
+@cindex accessors
+@cindex access to operands
+@cindex operand access
+
+@cindex RTL format
+For each expression type @file{rtl.def} specifies the number of
+contained objects and their kinds, with four possibilities: @samp{e} for
+expression (actually a pointer to an expression), @samp{i} for integer,
+@samp{w} for wide integer, @samp{s} for string, and @samp{E} for vector
+of expressions. The sequence of letters for an expression code is
+called its @dfn{format}. Thus, the format of @code{subreg} is
+@samp{ei}.@refill
+
+@cindex RTL format characters
+A few other format characters are used occasionally:
+
+@table @code
+@item u
+@samp{u} is equivalent to @samp{e} except that it is printed differently
+in debugging dumps. It is used for pointers to insns.
+
+@item n
+@samp{n} is equivalent to @samp{i} except that it is printed differently
+in debugging dumps. It is used for the line number or code number of a
+@code{note} insn.
+
+@item S
+@samp{S} indicates a string which is optional. In the RTL objects in
+core, @samp{S} is equivalent to @samp{s}, but when the object is read,
+from an @samp{md} file, the string value of this operand may be omitted.
+An omitted string is taken to be the null string.
+
+@item V
+@samp{V} indicates a vector which is optional. In the RTL objects in
+core, @samp{V} is equivalent to @samp{E}, but when the object is read
+from an @samp{md} file, the vector value of this operand may be omitted.
+An omitted vector is effectively the same as a vector of no elements.
+
+@item 0
+@samp{0} means a slot whose contents do not fit any normal category.
+@samp{0} slots are not printed at all in dumps, and are often used in
+special ways by small parts of the compiler.
+@end table
+
+There are macros to get the number of operands, the format, and the
+class of an expression code:
+
+@table @code
+@findex GET_RTX_LENGTH
+@item GET_RTX_LENGTH (@var{code})
+Number of operands of an RTX of code @var{code}.
+
+@findex GET_RTX_FORMAT
+@item GET_RTX_FORMAT (@var{code})
+The format of an RTX of code @var{code}, as a C string.
+
+@findex GET_RTX_CLASS
+@cindex classes of RTX codes
+@item GET_RTX_CLASS (@var{code})
+A single character representing the type of RTX operation that code
+@var{code} performs.
+
+The following classes are defined:
+
+@table @code
+@item o
+An RTX code that represents an actual object, such as @code{reg} or
+@code{mem}. @code{subreg} is not in this class.
+
+@item <
+An RTX code for a comparison. The codes in this class are
+@code{NE}, @code{EQ}, @code{LE}, @code{LT}, @code{GE}, @code{GT},
+@code{LEU}, @code{LTU}, @code{GEU}, @code{GTU}.@refill
+
+@item 1
+An RTX code for a unary arithmetic operation, such as @code{neg}.
+
+@item c
+An RTX code for a commutative binary operation, other than @code{NE}
+and @code{EQ} (which have class @samp{<}).
+
+@item 2
+An RTX code for a noncommutative binary operation, such as @code{MINUS}.
+
+@item b
+An RTX code for a bitfield operation, either @code{ZERO_EXTRACT} or
+@code{SIGN_EXTRACT}.
+
+@item 3
+An RTX code for other three input operations, such as @code{IF_THEN_ELSE}.
+
+@item i
+An RTX code for a machine insn (@code{INSN}, @code{JUMP_INSN}, and
+@code{CALL_INSN}).@refill
+
+@item m
+An RTX code for something that matches in insns, such as @code{MATCH_DUP}.
+
+@item x
+All other RTX codes.
+@end table
+@end table
+
+@findex XEXP
+@findex XINT
+@findex XWINT
+@findex XSTR
+Operands of expressions are accessed using the macros @code{XEXP},
+@code{XINT}, @code{XWINT} and @code{XSTR}. Each of these macros takes
+two arguments: an expression-pointer (RTX) and an operand number
+(counting from zero). Thus,@refill
+
+@example
+XEXP (@var{x}, 2)
+@end example
+
+@noindent
+accesses operand 2 of expression @var{x}, as an expression.
+
+@example
+XINT (@var{x}, 2)
+@end example
+
+@noindent
+accesses the same operand as an integer. @code{XSTR}, used in the same
+fashion, would access it as a string.
+
+Any operand can be accessed as an integer, as an expression or as a string.
+You must choose the correct method of access for the kind of value actually
+stored in the operand. You would do this based on the expression code of
+the containing expression. That is also how you would know how many
+operands there are.
+
+For example, if @var{x} is a @code{subreg} expression, you know that it has
+two operands which can be correctly accessed as @code{XEXP (@var{x}, 0)}
+and @code{XINT (@var{x}, 1)}. If you did @code{XINT (@var{x}, 0)}, you
+would get the address of the expression operand but cast as an integer;
+that might occasionally be useful, but it would be cleaner to write
+@code{(int) XEXP (@var{x}, 0)}. @code{XEXP (@var{x}, 1)} would also
+compile without error, and would return the second, integer operand cast as
+an expression pointer, which would probably result in a crash when
+accessed. Nothing stops you from writing @code{XEXP (@var{x}, 28)} either,
+but this will access memory past the end of the expression with
+unpredictable results.@refill
+
+Access to operands which are vectors is more complicated. You can use the
+macro @code{XVEC} to get the vector-pointer itself, or the macros
+@code{XVECEXP} and @code{XVECLEN} to access the elements and length of a
+vector.
+
+@table @code
+@findex XVEC
+@item XVEC (@var{exp}, @var{idx})
+Access the vector-pointer which is operand number @var{idx} in @var{exp}.
+
+@findex XVECLEN
+@item XVECLEN (@var{exp}, @var{idx})
+Access the length (number of elements) in the vector which is
+in operand number @var{idx} in @var{exp}. This value is an @code{int}.
+
+@findex XVECEXP
+@item XVECEXP (@var{exp}, @var{idx}, @var{eltnum})
+Access element number @var{eltnum} in the vector which is
+in operand number @var{idx} in @var{exp}. This value is an RTX.
+
+It is up to you to make sure that @var{eltnum} is not negative
+and is less than @code{XVECLEN (@var{exp}, @var{idx})}.
+@end table
+
+All the macros defined in this section expand into lvalues and therefore
+can be used to assign the operands, lengths and vector elements as well as
+to access them.
+
+@node Flags, Machine Modes, Accessors, RTL
+@section Flags in an RTL Expression
+@cindex flags in RTL expression
+
+RTL expressions contain several flags (one-bit bitfields) that are used
+in certain types of expression. Most often they are accessed with the
+following macros:
+
+@table @code
+@findex MEM_VOLATILE_P
+@cindex @code{mem} and @samp{/v}
+@cindex @code{volatil}, in @code{mem}
+@cindex @samp{/v} in RTL dump
+@item MEM_VOLATILE_P (@var{x})
+In @code{mem} expressions, nonzero for volatile memory references.
+Stored in the @code{volatil} field and printed as @samp{/v}.
+
+@findex MEM_IN_STRUCT_P
+@cindex @code{mem} and @samp{/s}
+@cindex @code{in_struct}, in @code{mem}
+@cindex @samp{/s} in RTL dump
+@item MEM_IN_STRUCT_P (@var{x})
+In @code{mem} expressions, nonzero for reference to an entire
+structure, union or array, or to a component of one. Zero for
+references to a scalar variable or through a pointer to a scalar.
+Stored in the @code{in_struct} field and printed as @samp{/s}.
+
+@findex REG_LOOP_TEST_P
+@cindex @code{reg} and @samp{/s}
+@cindex @code{in_struct}, in @code{reg}
+@item REG_LOOP_TEST_P
+In @code{reg} expressions, nonzero if this register's entire life is
+contained in the exit test code for some loop. Stored in the
+@code{in_struct} field and printed as @samp{/s}.
+
+@findex REG_USERVAR_P
+@cindex @code{reg} and @samp{/v}
+@cindex @code{volatil}, in @code{reg}
+@item REG_USERVAR_P (@var{x})
+In a @code{reg}, nonzero if it corresponds to a variable present in
+the user's source code. Zero for temporaries generated internally by
+the compiler. Stored in the @code{volatil} field and printed as
+@samp{/v}.
+
+@cindex @samp{/i} in RTL dump
+@findex REG_FUNCTION_VALUE_P
+@cindex @code{reg} and @samp{/i}
+@cindex @code{integrated}, in @code{reg}
+@item REG_FUNCTION_VALUE_P (@var{x})
+Nonzero in a @code{reg} if it is the place in which this function's
+value is going to be returned. (This happens only in a hard
+register.) Stored in the @code{integrated} field and printed as
+@samp{/i}.
+
+The same hard register may be used also for collecting the values of
+functions called by this one, but @code{REG_FUNCTION_VALUE_P} is zero
+in this kind of use.
+
+@findex SUBREG_PROMOTED_VAR_P
+@cindex @code{subreg} and @samp{/s}
+@cindex @code{in_struct}, in @code{subreg}
+@item SUBREG_PROMOTED_VAR_P
+Nonzero in a @code{subreg} if it was made when accessing an object that
+was promoted to a wider mode in accord with the @code{PROMOTED_MODE} machine
+description macro (@pxref{Storage Layout}). In this case, the mode of
+the @code{subreg} is the declared mode of the object and the mode of
+@code{SUBREG_REG} is the mode of the register that holds the object.
+Promoted variables are always either sign- or zero-extended to the wider
+mode on every assignment. Stored in the @code{in_struct} field and
+printed as @samp{/s}.
+
+@findex SUBREG_PROMOTED_UNSIGNED_P
+@cindex @code{subreg} and @samp{/u}
+@cindex @code{unchanging}, in @code{subreg}
+@item SUBREG_PROMOTED_UNSIGNED_P
+Nonzero in a @code{subreg} that has @code{SUBREG_PROMOTED_VAR_P} nonzero
+if the object being referenced is kept zero-extended and zero if it
+is kept sign-extended. Stored in the @code{unchanging} field and
+printed as @samp{/u}.
+
+@findex RTX_UNCHANGING_P
+@cindex @code{reg} and @samp{/u}
+@cindex @code{mem} and @samp{/u}
+@cindex @code{unchanging}, in @code{reg} and @code{mem}
+@cindex @samp{/u} in RTL dump
+@item RTX_UNCHANGING_P (@var{x})
+Nonzero in a @code{reg} or @code{mem} if the value is not changed.
+(This flag is not set for memory references via pointers to constants.
+Such pointers only guarantee that the object will not be changed
+explicitly by the current function. The object might be changed by
+other functions or by aliasing.) Stored in the
+@code{unchanging} field and printed as @samp{/u}.
+
+@findex RTX_INTEGRATED_P
+@cindex @code{integrated}, in @code{insn}
+@item RTX_INTEGRATED_P (@var{insn})
+Nonzero in an insn if it resulted from an in-line function call.
+Stored in the @code{integrated} field and printed as @samp{/i}. This
+may be deleted; nothing currently depends on it.
+
+@findex SYMBOL_REF_USED
+@cindex @code{used}, in @code{symbol_ref}
+@item SYMBOL_REF_USED (@var{x})
+In a @code{symbol_ref}, indicates that @var{x} has been used. This is
+normally only used to ensure that @var{x} is only declared external
+once. Stored in the @code{used} field.
+
+@findex SYMBOL_REF_FLAG
+@cindex @code{symbol_ref} and @samp{/v}
+@cindex @code{volatil}, in @code{symbol_ref}
+@item SYMBOL_REF_FLAG (@var{x})
+In a @code{symbol_ref}, this is used as a flag for machine-specific purposes.
+Stored in the @code{volatil} field and printed as @samp{/v}.
+
+@findex LABEL_OUTSIDE_LOOP_P
+@cindex @code{label_ref} and @samp{/s}
+@cindex @code{in_struct}, in @code{label_ref}
+@item LABEL_OUTSIDE_LOOP_P
+In @code{label_ref} expressions, nonzero if this is a reference to a
+label that is outside the innermost loop containing the reference to the
+label. Stored in the @code{in_struct} field and printed as @samp{/s}.
+
+@findex INSN_DELETED_P
+@cindex @code{volatil}, in @code{insn}
+@item INSN_DELETED_P (@var{insn})
+In an insn, nonzero if the insn has been deleted. Stored in the
+@code{volatil} field and printed as @samp{/v}.
+
+@findex INSN_ANNULLED_BRANCH_P
+@cindex @code{insn} and @samp{/u}
+@cindex @code{unchanging}, in @code{insn}
+@item INSN_ANNULLED_BRANCH_P (@var{insn})
+In an @code{insn} in the delay slot of a branch insn, indicates that an
+annulling branch should be used. See the discussion under
+@code{sequence} below. Stored in the @code{unchanging} field and printed
+as @samp{/u}.
+
+@findex INSN_FROM_TARGET_P
+@cindex @code{insn} and @samp{/s}
+@cindex @code{in_struct}, in @code{insn}
+@cindex @samp{/s} in RTL dump
+@item INSN_FROM_TARGET_P (@var{insn})
+In an @code{insn} in a delay slot of a branch, indicates that the insn
+is from the target of the branch. If the branch insn has
+@code{INSN_ANNULLED_BRANCH_P} set, this insn should only be executed if
+the branch is taken. For annulled branches with this bit clear, the
+insn should be executed only if the branch is not taken. Stored in the
+@code{in_struct} field and printed as @samp{/s}.
+
+@findex CONSTANT_POOL_ADDRESS_P
+@cindex @code{symbol_ref} and @samp{/u}
+@cindex @code{unchanging}, in @code{symbol_ref}
+@item CONSTANT_POOL_ADDRESS_P (@var{x})
+Nonzero in a @code{symbol_ref} if it refers to part of the current
+function's ``constants pool''. These are addresses close to the
+beginning of the function, and GNU CC assumes they can be addressed
+directly (perhaps with the help of base registers). Stored in the
+@code{unchanging} field and printed as @samp{/u}.
+
+@findex CONST_CALL_P
+@cindex @code{call_insn} and @samp{/u}
+@cindex @code{unchanging}, in @code{call_insn}
+@item CONST_CALL_P (@var{x})
+In a @code{call_insn}, indicates that the insn represents a call to a const
+function. Stored in the @code{unchanging} field and printed as @samp{/u}.
+
+@findex LABEL_PRESERVE_P
+@cindex @code{code_label} and @samp{/i}
+@cindex @code{in_struct}, in @code{code_label}
+@item LABEL_PRESERVE_P (@var{x})
+In a @code{code_label}, indicates that the label can never be deleted.
+Labels referenced by a non-local goto will have this bit set. Stored
+in the @code{in_struct} field and printed as @samp{/s}.
+
+@findex SCHED_GROUP_P
+@cindex @code{insn} and @samp{/i}
+@cindex @code{in_struct}, in @code{insn}
+@item SCHED_GROUP_P (@var{insn})
+During instruction scheduling, in an insn, indicates that the previous insn
+must be scheduled together with this insn. This is used to ensure that
+certain groups of instructions will not be split up by the instruction
+scheduling pass, for example, @code{use} insns before a @code{call_insn} may
+not be separated from the @code{call_insn}. Stored in the @code{in_struct}
+field and printed as @samp{/s}.
+@end table
+
+These are the fields which the above macros refer to:
+
+@table @code
+@findex used
+@item used
+Normally, this flag is used only momentarily, at the end of RTL
+generation for a function, to count the number of times an expression
+appears in insns. Expressions that appear more than once are copied,
+according to the rules for shared structure (@pxref{Sharing}).
+
+In a @code{symbol_ref}, it indicates that an external declaration for
+the symbol has already been written.
+
+In a @code{reg}, it is used by the leaf register renumbering code to ensure
+that each register is only renumbered once.
+
+@findex volatil
+@item volatil
+This flag is used in @code{mem}, @code{symbol_ref} and @code{reg}
+expressions and in insns. In RTL dump files, it is printed as
+@samp{/v}.
+
+@cindex volatile memory references
+In a @code{mem} expression, it is 1 if the memory reference is volatile.
+Volatile memory references may not be deleted, reordered or combined.
+
+In a @code{symbol_ref} expression, it is used for machine-specific
+purposes.
+
+In a @code{reg} expression, it is 1 if the value is a user-level variable.
+0 indicates an internal compiler temporary.
+
+In an insn, 1 means the insn has been deleted.
+
+@findex in_struct
+@item in_struct
+In @code{mem} expressions, it is 1 if the memory datum referred to is
+all or part of a structure or array; 0 if it is (or might be) a scalar
+variable. A reference through a C pointer has 0 because the pointer
+might point to a scalar variable. This information allows the compiler
+to determine something about possible cases of aliasing.
+
+In an insn in the delay slot of a branch, 1 means that this insn is from
+the target of the branch.
+
+During instruction scheduling, in an insn, 1 means that this insn must be
+scheduled as part of a group together with the previous insn.
+
+In @code{reg} expressions, it is 1 if the register has its entire life
+contained within the test expression of some loop.
+
+In @code{subreg} expressions, 1 means that the @code{subreg} is accessing
+an object that has had its mode promoted from a wider mode.
+
+In @code{label_ref} expressions, 1 means that the referenced label is
+outside the innermost loop containing the insn in which the @code{label_ref}
+was found.
+
+In @code{code_label} expressions, it is 1 if the label may never be deleted.
+This is used for labels which are the target of non-local gotos.
+
+In an RTL dump, this flag is represented as @samp{/s}.
+
+@findex unchanging
+@item unchanging
+In @code{reg} and @code{mem} expressions, 1 means
+that the value of the expression never changes.
+
+In @code{subreg} expressions, it is 1 if the @code{subreg} references an
+unsigned object whose mode has been promoted to a wider mode.
+
+In an insn, 1 means that this is an annulling branch.
+
+In a @code{symbol_ref} expression, 1 means that this symbol addresses
+something in the per-function constants pool.
+
+In a @code{call_insn}, 1 means that this instruction is a call to a
+const function.
+
+In an RTL dump, this flag is represented as @samp{/u}.
+
+@findex integrated
+@item integrated
+In some kinds of expressions, including insns, this flag means the
+rtl was produced by procedure integration.
+
+In a @code{reg} expression, this flag indicates the register
+containing the value to be returned by the current function. On
+machines that pass parameters in registers, the same register number
+may be used for parameters as well, but this flag is not set on such
+uses.
+@end table
+
+@node Machine Modes, Constants, Flags, RTL
+@section Machine Modes
+@cindex machine modes
+
+@findex enum machine_mode
+A machine mode describes a size of data object and the representation used
+for it. In the C code, machine modes are represented by an enumeration
+type, @code{enum machine_mode}, defined in @file{machmode.def}. Each RTL
+expression has room for a machine mode and so do certain kinds of tree
+expressions (declarations and types, to be precise).
+
+In debugging dumps and machine descriptions, the machine mode of an RTL
+expression is written after the expression code with a colon to separate
+them. The letters @samp{mode} which appear at the end of each machine mode
+name are omitted. For example, @code{(reg:SI 38)} is a @code{reg}
+expression with machine mode @code{SImode}. If the mode is
+@code{VOIDmode}, it is not written at all.
+
+Here is a table of machine modes. The term ``byte'' below refers to an
+object of @code{BITS_PER_UNIT} bits (@pxref{Storage Layout}).
+
+@table @code
+@findex QImode
+@item QImode
+``Quarter-Integer'' mode represents a single byte treated as an integer.
+
+@findex HImode
+@item HImode
+``Half-Integer'' mode represents a two-byte integer.
+
+@findex PSImode
+@item PSImode
+``Partial Single Integer'' mode represents an integer which occupies
+four bytes but which doesn't really use all four. On some machines,
+this is the right mode to use for pointers.
+
+@findex SImode
+@item SImode
+``Single Integer'' mode represents a four-byte integer.
+
+@findex PDImode
+@item PDImode
+``Partial Double Integer'' mode represents an integer which occupies
+eight bytes but which doesn't really use all eight. On some machines,
+this is the right mode to use for certain pointers.
+
+@findex DImode
+@item DImode
+``Double Integer'' mode represents an eight-byte integer.
+
+@findex TImode
+@item TImode
+``Tetra Integer'' (?) mode represents a sixteen-byte integer.
+
+@findex SFmode
+@item SFmode
+``Single Floating'' mode represents a single-precision (four byte) floating
+point number.
+
+@findex DFmode
+@item DFmode
+``Double Floating'' mode represents a double-precision (eight byte) floating
+point number.
+
+@findex XFmode
+@item XFmode
+``Extended Floating'' mode represents a triple-precision (twelve byte)
+floating point number. This mode is used for IEEE extended floating
+point.
+
+@findex TFmode
+@item TFmode
+``Tetra Floating'' mode represents a quadruple-precision (sixteen byte)
+floating point number.
+
+@findex CCmode
+@item CCmode
+``Condition Code'' mode represents the value of a condition code, which
+is a machine-specific set of bits used to represent the result of a
+comparison operation. Other machine-specific modes may also be used for
+the condition code. These modes are not used on machines that use
+@code{cc0} (see @pxref{Condition Code}).
+
+@findex BLKmode
+@item BLKmode
+``Block'' mode represents values that are aggregates to which none of
+the other modes apply. In RTL, only memory references can have this mode,
+and only if they appear in string-move or vector instructions. On machines
+which have no such instructions, @code{BLKmode} will not appear in RTL.
+
+@findex VOIDmode
+@item VOIDmode
+Void mode means the absence of a mode or an unspecified mode.
+For example, RTL expressions of code @code{const_int} have mode
+@code{VOIDmode} because they can be taken to have whatever mode the context
+requires. In debugging dumps of RTL, @code{VOIDmode} is expressed by
+the absence of any mode.
+
+@findex SCmode
+@findex DCmode
+@findex XCmode
+@findex TCmode
+@item SCmode, DCmode, XCmode, TCmode
+These modes stand for a complex number represented as a pair of floating
+point values. The floating point values are in @code{SFmode},
+@code{DFmode}, @code{XFmode}, and @code{TFmode}, respectively.
+
+@findex CQImode
+@findex CHImode
+@findex CSImode
+@findex CDImode
+@findex CTImode
+@findex COImode
+@item CQImode, CHImode, CSImode, CDImode, CTImode, COImode
+These modes stand for a complex number represented as a pair of integer
+values. The integer values are in @code{QImode}, @code{HImode},
+@code{SImode}, @code{DImode}, @code{TImode}, and @code{OImode},
+respectively.
+@end table
+
+The machine description defines @code{Pmode} as a C macro which expands
+into the machine mode used for addresses. Normally this is the mode
+whose size is @code{BITS_PER_WORD}, @code{SImode} on 32-bit machines.
+
+The only modes which a machine description @i{must} support are
+@code{QImode}, and the modes corresponding to @code{BITS_PER_WORD},
+@code{FLOAT_TYPE_SIZE} and @code{DOUBLE_TYPE_SIZE}.
+The compiler will attempt to use @code{DImode} for 8-byte structures and
+unions, but this can be prevented by overriding the definition of
+@code{MAX_FIXED_MODE_SIZE}. Alternatively, you can have the compiler
+use @code{TImode} for 16-byte structures and unions. Likewise, you can
+arrange for the C type @code{short int} to avoid using @code{HImode}.
+
+@cindex mode classes
+Very few explicit references to machine modes remain in the compiler and
+these few references will soon be removed. Instead, the machine modes
+are divided into mode classes. These are represented by the enumeration
+type @code{enum mode_class} defined in @file{machmode.h}. The possible
+mode classes are:
+
+@table @code
+@findex MODE_INT
+@item MODE_INT
+Integer modes. By default these are @code{QImode}, @code{HImode},
+@code{SImode}, @code{DImode}, and @code{TImode}.
+
+@findex MODE_PARTIAL_INT
+@item MODE_PARTIAL_INT
+The ``partial integer'' modes, @code{PSImode} and @code{PDImode}.
+
+@findex MODE_FLOAT
+@item MODE_FLOAT
+floating point modes. By default these are @code{SFmode}, @code{DFmode},
+@code{XFmode} and @code{TFmode}.
+
+@findex MODE_COMPLEX_INT
+@item MODE_COMPLEX_INT
+Complex integer modes. (These are not currently implemented).
+
+@findex MODE_COMPLEX_FLOAT
+@item MODE_COMPLEX_FLOAT
+Complex floating point modes. By default these are @code{SCmode},
+@code{DCmode}, @code{XCmode}, and @code{TCmode}.
+
+@findex MODE_FUNCTION
+@item MODE_FUNCTION
+Algol or Pascal function variables including a static chain.
+(These are not currently implemented).
+
+@findex MODE_CC
+@item MODE_CC
+Modes representing condition code values. These are @code{CCmode} plus
+any modes listed in the @code{EXTRA_CC_MODES} macro. @xref{Jump Patterns},
+also see @ref{Condition Code}.
+
+@findex MODE_RANDOM
+@item MODE_RANDOM
+This is a catchall mode class for modes which don't fit into the above
+classes. Currently @code{VOIDmode} and @code{BLKmode} are in
+@code{MODE_RANDOM}.
+@end table
+
+Here are some C macros that relate to machine modes:
+
+@table @code
+@findex GET_MODE
+@item GET_MODE (@var{x})
+Returns the machine mode of the RTX @var{x}.
+
+@findex PUT_MODE
+@item PUT_MODE (@var{x}, @var{newmode})
+Alters the machine mode of the RTX @var{x} to be @var{newmode}.
+
+@findex NUM_MACHINE_MODES
+@item NUM_MACHINE_MODES
+Stands for the number of machine modes available on the target
+machine. This is one greater than the largest numeric value of any
+machine mode.
+
+@findex GET_MODE_NAME
+@item GET_MODE_NAME (@var{m})
+Returns the name of mode @var{m} as a string.
+
+@findex GET_MODE_CLASS
+@item GET_MODE_CLASS (@var{m})
+Returns the mode class of mode @var{m}.
+
+@findex GET_MODE_WIDER_MODE
+@item GET_MODE_WIDER_MODE (@var{m})
+Returns the next wider natural mode. For example, the expression
+@code{GET_MODE_WIDER_MODE (QImode)} returns @code{HImode}.
+
+@findex GET_MODE_SIZE
+@item GET_MODE_SIZE (@var{m})
+Returns the size in bytes of a datum of mode @var{m}.
+
+@findex GET_MODE_BITSIZE
+@item GET_MODE_BITSIZE (@var{m})
+Returns the size in bits of a datum of mode @var{m}.
+
+@findex GET_MODE_MASK
+@item GET_MODE_MASK (@var{m})
+Returns a bitmask containing 1 for all bits in a word that fit within
+mode @var{m}. This macro can only be used for modes whose bitsize is
+less than or equal to @code{HOST_BITS_PER_INT}.
+
+@findex GET_MODE_ALIGNMENT
+@item GET_MODE_ALIGNMENT (@var{m)})
+Return the required alignment, in bits, for an object of mode @var{m}.
+
+@findex GET_MODE_UNIT_SIZE
+@item GET_MODE_UNIT_SIZE (@var{m})
+Returns the size in bytes of the subunits of a datum of mode @var{m}.
+This is the same as @code{GET_MODE_SIZE} except in the case of complex
+modes. For them, the unit size is the size of the real or imaginary
+part.
+
+@findex GET_MODE_NUNITS
+@item GET_MODE_NUNITS (@var{m})
+Returns the number of units contained in a mode, i.e.,
+@code{GET_MODE_SIZE} divided by @code{GET_MODE_UNIT_SIZE}.
+
+@findex GET_CLASS_NARROWEST_MODE
+@item GET_CLASS_NARROWEST_MODE (@var{c})
+Returns the narrowest mode in mode class @var{c}.
+@end table
+
+@findex byte_mode
+@findex word_mode
+The global variables @code{byte_mode} and @code{word_mode} contain modes
+whose classes are @code{MODE_INT} and whose bitsizes are either
+@code{BITS_PER_UNIT} or @code{BITS_PER_WORD}, respectively. On 32-bit
+machines, these are @code{QImode} and @code{SImode}, respectively.
+
+@node Constants, Regs and Memory, Machine Modes, RTL
+@section Constant Expression Types
+@cindex RTL constants
+@cindex RTL constant expression types
+
+The simplest RTL expressions are those that represent constant values.
+
+@table @code
+@findex const_int
+@item (const_int @var{i})
+This type of expression represents the integer value @var{i}. @var{i}
+is customarily accessed with the macro @code{INTVAL} as in
+@code{INTVAL (@var{exp})}, which is equivalent to @code{XWINT (@var{exp}, 0)}.
+
+@findex const0_rtx
+@findex const1_rtx
+@findex const2_rtx
+@findex constm1_rtx
+There is only one expression object for the integer value zero; it is
+the value of the variable @code{const0_rtx}. Likewise, the only
+expression for integer value one is found in @code{const1_rtx}, the only
+expression for integer value two is found in @code{const2_rtx}, and the
+only expression for integer value negative one is found in
+@code{constm1_rtx}. Any attempt to create an expression of code
+@code{const_int} and value zero, one, two or negative one will return
+@code{const0_rtx}, @code{const1_rtx}, @code{const2_rtx} or
+@code{constm1_rtx} as appropriate.@refill
+
+@findex const_true_rtx
+Similarly, there is only one object for the integer whose value is
+@code{STORE_FLAG_VALUE}. It is found in @code{const_true_rtx}. If
+@code{STORE_FLAG_VALUE} is one, @code{const_true_rtx} and
+@code{const1_rtx} will point to the same object. If
+@code{STORE_FLAG_VALUE} is -1, @code{const_true_rtx} and
+@code{constm1_rtx} will point to the same object.@refill
+
+@findex const_double
+@item (const_double:@var{m} @var{addr} @var{i0} @var{i1} @dots{})
+Represents either a floating-point constant of mode @var{m} or an
+integer constant too large to fit into @code{HOST_BITS_PER_WIDE_INT}
+bits but small enough to fit within twice that number of bits (GNU CC
+does not provide a mechanism to represent even larger constants). In
+the latter case, @var{m} will be @code{VOIDmode}.
+
+@findex CONST_DOUBLE_MEM
+@findex CONST_DOUBLE_CHAIN
+@var{addr} is used to contain the @code{mem} expression that corresponds
+to the location in memory that at which the constant can be found. If
+it has not been allocated a memory location, but is on the chain of all
+@code{const_double} expressions in this compilation (maintained using an
+undisplayed field), @var{addr} contains @code{const0_rtx}. If it is not
+on the chain, @var{addr} contains @code{cc0_rtx}. @var{addr} is
+customarily accessed with the macro @code{CONST_DOUBLE_MEM} and the
+chain field via @code{CONST_DOUBLE_CHAIN}.@refill
+
+@findex CONST_DOUBLE_LOW
+If @var{m} is @code{VOIDmode}, the bits of the value are stored in
+@var{i0} and @var{i1}. @var{i0} is customarily accessed with the macro
+@code{CONST_DOUBLE_LOW} and @var{i1} with @code{CONST_DOUBLE_HIGH}.
+
+If the constant is floating point (regardless of its precision), then
+the number of integers used to store the value depends on the size of
+@code{REAL_VALUE_TYPE} (@pxref{Cross-compilation}). The integers
+represent a floating point number, but not precisely in the target
+machine's or host machine's floating point format. To convert them to
+the precise bit pattern used by the target machine, use the macro
+@code{REAL_VALUE_TO_TARGET_DOUBLE} and friends (@pxref{Data Output}).
+
+@findex CONST0_RTX
+@findex CONST1_RTX
+@findex CONST2_RTX
+The macro @code{CONST0_RTX (@var{mode})} refers to an expression with
+value 0 in mode @var{mode}. If mode @var{mode} is of mode class
+@code{MODE_INT}, it returns @code{const0_rtx}. Otherwise, it returns a
+@code{CONST_DOUBLE} expression in mode @var{mode}. Similarly, the macro
+@code{CONST1_RTX (@var{mode})} refers to an expression with value 1 in
+mode @var{mode} and similarly for @code{CONST2_RTX}.
+
+@findex const_string
+@item (const_string @var{str})
+Represents a constant string with value @var{str}. Currently this is
+used only for insn attributes (@pxref{Insn Attributes}) since constant
+strings in C are placed in memory.
+
+@findex symbol_ref
+@item (symbol_ref:@var{mode} @var{symbol})
+Represents the value of an assembler label for data. @var{symbol} is
+a string that describes the name of the assembler label. If it starts
+with a @samp{*}, the label is the rest of @var{symbol} not including
+the @samp{*}. Otherwise, the label is @var{symbol}, usually prefixed
+with @samp{_}.
+
+The @code{symbol_ref} contains a mode, which is usually @code{Pmode}.
+Usually that is the only mode for which a symbol is directly valid.
+
+@findex label_ref
+@item (label_ref @var{label})
+Represents the value of an assembler label for code. It contains one
+operand, an expression, which must be a @code{code_label} that appears
+in the instruction sequence to identify the place where the label
+should go.
+
+The reason for using a distinct expression type for code label
+references is so that jump optimization can distinguish them.
+
+@item (const:@var{m} @var{exp})
+Represents a constant that is the result of an assembly-time
+arithmetic computation. The operand, @var{exp}, is an expression that
+contains only constants (@code{const_int}, @code{symbol_ref} and
+@code{label_ref} expressions) combined with @code{plus} and
+@code{minus}. However, not all combinations are valid, since the
+assembler cannot do arbitrary arithmetic on relocatable symbols.
+
+@var{m} should be @code{Pmode}.
+
+@findex high
+@item (high:@var{m} @var{exp})
+Represents the high-order bits of @var{exp}, usually a
+@code{symbol_ref}. The number of bits is machine-dependent and is
+normally the number of bits specified in an instruction that initializes
+the high order bits of a register. It is used with @code{lo_sum} to
+represent the typical two-instruction sequence used in RISC machines to
+reference a global memory location.
+
+@var{m} should be @code{Pmode}.
+@end table
+
+@node Regs and Memory, Arithmetic, Constants, RTL
+@section Registers and Memory
+@cindex RTL register expressions
+@cindex RTL memory expressions
+
+Here are the RTL expression types for describing access to machine
+registers and to main memory.
+
+@table @code
+@findex reg
+@cindex hard registers
+@cindex pseudo registers
+@item (reg:@var{m} @var{n})
+For small values of the integer @var{n} (those that are less than
+@code{FIRST_PSEUDO_REGISTER}), this stands for a reference to machine
+register number @var{n}: a @dfn{hard register}. For larger values of
+@var{n}, it stands for a temporary value or @dfn{pseudo register}.
+The compiler's strategy is to generate code assuming an unlimited
+number of such pseudo registers, and later convert them into hard
+registers or into memory references.
+
+@var{m} is the machine mode of the reference. It is necessary because
+machines can generally refer to each register in more than one mode.
+For example, a register may contain a full word but there may be
+instructions to refer to it as a half word or as a single byte, as
+well as instructions to refer to it as a floating point number of
+various precisions.
+
+Even for a register that the machine can access in only one mode,
+the mode must always be specified.
+
+The symbol @code{FIRST_PSEUDO_REGISTER} is defined by the machine
+description, since the number of hard registers on the machine is an
+invariant characteristic of the machine. Note, however, that not
+all of the machine registers must be general registers. All the
+machine registers that can be used for storage of data are given
+hard register numbers, even those that can be used only in certain
+instructions or can hold only certain types of data.
+
+A hard register may be accessed in various modes throughout one
+function, but each pseudo register is given a natural mode
+and is accessed only in that mode. When it is necessary to describe
+an access to a pseudo register using a nonnatural mode, a @code{subreg}
+expression is used.
+
+A @code{reg} expression with a machine mode that specifies more than
+one word of data may actually stand for several consecutive registers.
+If in addition the register number specifies a hardware register, then
+it actually represents several consecutive hardware registers starting
+with the specified one.
+
+Each pseudo register number used in a function's RTL code is
+represented by a unique @code{reg} expression.
+
+@findex FIRST_VIRTUAL_REGISTER
+@findex LAST_VIRTUAL_REGISTER
+Some pseudo register numbers, those within the range of
+@code{FIRST_VIRTUAL_REGISTER} to @code{LAST_VIRTUAL_REGISTER} only
+appear during the RTL generation phase and are eliminated before the
+optimization phases. These represent locations in the stack frame that
+cannot be determined until RTL generation for the function has been
+completed. The following virtual register numbers are defined:
+
+@table @code
+@findex VIRTUAL_INCOMING_ARGS_REGNUM
+@item VIRTUAL_INCOMING_ARGS_REGNUM
+This points to the first word of the incoming arguments passed on the
+stack. Normally these arguments are placed there by the caller, but the
+callee may have pushed some arguments that were previously passed in
+registers.
+
+@cindex @code{FIRST_PARM_OFFSET} and virtual registers
+@cindex @code{ARG_POINTER_REGNUM} and virtual registers
+When RTL generation is complete, this virtual register is replaced
+by the sum of the register given by @code{ARG_POINTER_REGNUM} and the
+value of @code{FIRST_PARM_OFFSET}.
+
+@findex VIRTUAL_STACK_VARS_REGNUM
+@cindex @code{FRAME_GROWS_DOWNWARD} and virtual registers
+@item VIRTUAL_STACK_VARS_REGNUM
+If @code{FRAME_GROWS_DOWNWARD} is defined, this points to immediately
+above the first variable on the stack. Otherwise, it points to the
+first variable on the stack.
+
+@cindex @code{STARTING_FRAME_OFFSET} and virtual registers
+@cindex @code{FRAME_POINTER_REGNUM} and virtual registers
+@code{VIRTUAL_STACK_VARS_REGNUM} is replaced with the sum of the
+register given by @code{FRAME_POINTER_REGNUM} and the value
+@code{STARTING_FRAME_OFFSET}.
+
+@findex VIRTUAL_STACK_DYNAMIC_REGNUM
+@item VIRTUAL_STACK_DYNAMIC_REGNUM
+This points to the location of dynamically allocated memory on the stack
+immediately after the stack pointer has been adjusted by the amount of
+memory desired.
+
+@cindex @code{STACK_DYNAMIC_OFFSET} and virtual registers
+@cindex @code{STACK_POINTER_REGNUM} and virtual registers
+This virtual register is replaced by the sum of the register given by
+@code{STACK_POINTER_REGNUM} and the value @code{STACK_DYNAMIC_OFFSET}.
+
+@findex VIRTUAL_OUTGOING_ARGS_REGNUM
+@item VIRTUAL_OUTGOING_ARGS_REGNUM
+This points to the location in the stack at which outgoing arguments
+should be written when the stack is pre-pushed (arguments pushed using
+push insns should always use @code{STACK_POINTER_REGNUM}).
+
+@cindex @code{STACK_POINTER_OFFSET} and virtual registers
+This virtual register is replaced by the sum of the register given by
+@code{STACK_POINTER_REGNUM} and the value @code{STACK_POINTER_OFFSET}.
+@end table
+
+@findex subreg
+@item (subreg:@var{m} @var{reg} @var{wordnum})
+@code{subreg} expressions are used to refer to a register in a machine
+mode other than its natural one, or to refer to one register of
+a multi-word @code{reg} that actually refers to several registers.
+
+Each pseudo-register has a natural mode. If it is necessary to
+operate on it in a different mode---for example, to perform a fullword
+move instruction on a pseudo-register that contains a single
+byte---the pseudo-register must be enclosed in a @code{subreg}. In
+such a case, @var{wordnum} is zero.
+
+Usually @var{m} is at least as narrow as the mode of @var{reg}, in which
+case it is restricting consideration to only the bits of @var{reg} that
+are in @var{m}.
+
+Sometimes @var{m} is wider than the mode of @var{reg}. These
+@code{subreg} expressions are often called @dfn{paradoxical}. They are
+used in cases where we want to refer to an object in a wider mode but do
+not care what value the additional bits have. The reload pass ensures
+that paradoxical references are only made to hard registers.
+
+The other use of @code{subreg} is to extract the individual registers of
+a multi-register value. Machine modes such as @code{DImode} and
+@code{TImode} can indicate values longer than a word, values which
+usually require two or more consecutive registers. To access one of the
+registers, use a @code{subreg} with mode @code{SImode} and a
+@var{wordnum} that says which register.
+
+Storing in a non-paradoxical @code{subreg} has undefined results for
+bits belonging to the same word as the @code{subreg}. This laxity makes
+it easier to generate efficient code for such instructions. To
+represent an instruction that preserves all the bits outside of those in
+the @code{subreg}, use @code{strict_low_part} around the @code{subreg}.
+
+@cindex @code{WORDS_BIG_ENDIAN}, effect on @code{subreg}
+The compilation parameter @code{WORDS_BIG_ENDIAN}, if set to 1, says
+that word number zero is the most significant part; otherwise, it is
+the least significant part.
+
+@cindex combiner pass
+@cindex reload pass
+@cindex @code{subreg}, special reload handling
+Between the combiner pass and the reload pass, it is possible to have a
+paradoxical @code{subreg} which contains a @code{mem} instead of a
+@code{reg} as its first operand. After the reload pass, it is also
+possible to have a non-paradoxical @code{subreg} which contains a
+@code{mem}; this usually occurs when the @code{mem} is a stack slot
+which replaced a pseudo register.
+
+Note that it is not valid to access a @code{DFmode} value in @code{SFmode}
+using a @code{subreg}. On some machines the most significant part of a
+@code{DFmode} value does not have the same format as a single-precision
+floating value.
+
+It is also not valid to access a single word of a multi-word value in a
+hard register when less registers can hold the value than would be
+expected from its size. For example, some 32-bit machines have
+floating-point registers that can hold an entire @code{DFmode} value.
+If register 10 were such a register @code{(subreg:SI (reg:DF 10) 1)}
+would be invalid because there is no way to convert that reference to
+a single machine register. The reload pass prevents @code{subreg}
+expressions such as these from being formed.
+
+@findex SUBREG_REG
+@findex SUBREG_WORD
+The first operand of a @code{subreg} expression is customarily accessed
+with the @code{SUBREG_REG} macro and the second operand is customarily
+accessed with the @code{SUBREG_WORD} macro.
+
+@findex scratch
+@cindex scratch operands
+@item (scratch:@var{m})
+This represents a scratch register that will be required for the
+execution of a single instruction and not used subsequently. It is
+converted into a @code{reg} by either the local register allocator or
+the reload pass.
+
+@code{scratch} is usually present inside a @code{clobber} operation
+(@pxref{Side Effects}).
+
+@findex cc0
+@cindex condition code register
+@item (cc0)
+This refers to the machine's condition code register. It has no
+operands and may not have a machine mode. There are two ways to use it:
+
+@itemize @bullet
+@item
+To stand for a complete set of condition code flags. This is best on
+most machines, where each comparison sets the entire series of flags.
+
+With this technique, @code{(cc0)} may be validly used in only two
+contexts: as the destination of an assignment (in test and compare
+instructions) and in comparison operators comparing against zero
+(@code{const_int} with value zero; that is to say, @code{const0_rtx}).
+
+@item
+To stand for a single flag that is the result of a single condition.
+This is useful on machines that have only a single flag bit, and in
+which comparison instructions must specify the condition to test.
+
+With this technique, @code{(cc0)} may be validly used in only two
+contexts: as the destination of an assignment (in test and compare
+instructions) where the source is a comparison operator, and as the
+first operand of @code{if_then_else} (in a conditional branch).
+@end itemize
+
+@findex cc0_rtx
+There is only one expression object of code @code{cc0}; it is the
+value of the variable @code{cc0_rtx}. Any attempt to create an
+expression of code @code{cc0} will return @code{cc0_rtx}.
+
+Instructions can set the condition code implicitly. On many machines,
+nearly all instructions set the condition code based on the value that
+they compute or store. It is not necessary to record these actions
+explicitly in the RTL because the machine description includes a
+prescription for recognizing the instructions that do so (by means of
+the macro @code{NOTICE_UPDATE_CC}). @xref{Condition Code}. Only
+instructions whose sole purpose is to set the condition code, and
+instructions that use the condition code, need mention @code{(cc0)}.
+
+On some machines, the condition code register is given a register number
+and a @code{reg} is used instead of @code{(cc0)}. This is usually the
+preferable approach if only a small subset of instructions modify the
+condition code. Other machines store condition codes in general
+registers; in such cases a pseudo register should be used.
+
+Some machines, such as the Sparc and RS/6000, have two sets of
+arithmetic instructions, one that sets and one that does not set the
+condition code. This is best handled by normally generating the
+instruction that does not set the condition code, and making a pattern
+that both performs the arithmetic and sets the condition code register
+(which would not be @code{(cc0)} in this case). For examples, search
+for @samp{addcc} and @samp{andcc} in @file{sparc.md}.
+
+@findex pc
+@item (pc)
+@cindex program counter
+This represents the machine's program counter. It has no operands and
+may not have a machine mode. @code{(pc)} may be validly used only in
+certain specific contexts in jump instructions.
+
+@findex pc_rtx
+There is only one expression object of code @code{pc}; it is the value
+of the variable @code{pc_rtx}. Any attempt to create an expression of
+code @code{pc} will return @code{pc_rtx}.
+
+All instructions that do not jump alter the program counter implicitly
+by incrementing it, but there is no need to mention this in the RTL.
+
+@findex mem
+@item (mem:@var{m} @var{addr})
+This RTX represents a reference to main memory at an address
+represented by the expression @var{addr}. @var{m} specifies how large
+a unit of memory is accessed.
+@end table
+
+@node Arithmetic, Comparisons, Regs and Memory, RTL
+@section RTL Expressions for Arithmetic
+@cindex arithmetic, in RTL
+@cindex math, in RTL
+@cindex RTL expressions for arithmetic
+
+Unless otherwise specified, all the operands of arithmetic expressions
+must be valid for mode @var{m}. An operand is valid for mode @var{m}
+if it has mode @var{m}, or if it is a @code{const_int} or
+@code{const_double} and @var{m} is a mode of class @code{MODE_INT}.
+
+For commutative binary operations, constants should be placed in the
+second operand.
+
+@table @code
+@findex plus
+@cindex RTL addition
+@cindex RTL sum
+@item (plus:@var{m} @var{x} @var{y})
+Represents the sum of the values represented by @var{x} and @var{y}
+carried out in machine mode @var{m}.
+
+@findex lo_sum
+@item (lo_sum:@var{m} @var{x} @var{y})
+Like @code{plus}, except that it represents that sum of @var{x} and the
+low-order bits of @var{y}. The number of low order bits is
+machine-dependent but is normally the number of bits in a @code{Pmode}
+item minus the number of bits set by the @code{high} code
+(@pxref{Constants}).
+
+@var{m} should be @code{Pmode}.
+
+@findex minus
+@cindex RTL subtraction
+@cindex RTL difference
+@item (minus:@var{m} @var{x} @var{y})
+Like @code{plus} but represents subtraction.
+
+@findex compare
+@cindex RTL comparison
+@item (compare:@var{m} @var{x} @var{y})
+Represents the result of subtracting @var{y} from @var{x} for purposes
+of comparison. The result is computed without overflow, as if with
+infinite precision.
+
+Of course, machines can't really subtract with infinite precision.
+However, they can pretend to do so when only the sign of the
+result will be used, which is the case when the result is stored
+in the condition code. And that is the only way this kind of expression
+may validly be used: as a value to be stored in the condition codes.
+
+The mode @var{m} is not related to the modes of @var{x} and @var{y},
+but instead is the mode of the condition code value. If @code{(cc0)}
+is used, it is @code{VOIDmode}. Otherwise it is some mode in class
+@code{MODE_CC}, often @code{CCmode}. @xref{Condition Code}.
+
+Normally, @var{x} and @var{y} must have the same mode. Otherwise,
+@code{compare} is valid only if the mode of @var{x} is in class
+@code{MODE_INT} and @var{y} is a @code{const_int} or
+@code{const_double} with mode @code{VOIDmode}. The mode of @var{x}
+determines what mode the comparison is to be done in; thus it must not
+be @code{VOIDmode}.
+
+If one of the operands is a constant, it should be placed in the
+second operand and the comparison code adjusted as appropriate.
+
+A @code{compare} specifying two @code{VOIDmode} constants is not valid
+since there is no way to know in what mode the comparison is to be
+performed; the comparison must either be folded during the compilation
+or the first operand must be loaded into a register while its mode is
+still known.
+
+@findex neg
+@item (neg:@var{m} @var{x})
+Represents the negation (subtraction from zero) of the value represented
+by @var{x}, carried out in mode @var{m}.
+
+@findex mult
+@cindex multiplication
+@cindex product
+@item (mult:@var{m} @var{x} @var{y})
+Represents the signed product of the values represented by @var{x} and
+@var{y} carried out in machine mode @var{m}.
+
+Some machines support a multiplication that generates a product wider
+than the operands. Write the pattern for this as
+
+@example
+(mult:@var{m} (sign_extend:@var{m} @var{x}) (sign_extend:@var{m} @var{y}))
+@end example
+
+where @var{m} is wider than the modes of @var{x} and @var{y}, which need
+not be the same.
+
+Write patterns for unsigned widening multiplication similarly using
+@code{zero_extend}.
+
+@findex div
+@cindex division
+@cindex signed division
+@cindex quotient
+@item (div:@var{m} @var{x} @var{y})
+Represents the quotient in signed division of @var{x} by @var{y},
+carried out in machine mode @var{m}. If @var{m} is a floating point
+mode, it represents the exact quotient; otherwise, the integerized
+quotient.
+
+Some machines have division instructions in which the operands and
+quotient widths are not all the same; you should represent
+such instructions using @code{truncate} and @code{sign_extend} as in,
+
+@example
+(truncate:@var{m1} (div:@var{m2} @var{x} (sign_extend:@var{m2} @var{y})))
+@end example
+
+@findex udiv
+@cindex unsigned division
+@cindex division
+@item (udiv:@var{m} @var{x} @var{y})
+Like @code{div} but represents unsigned division.
+
+@findex mod
+@findex umod
+@cindex remainder
+@cindex division
+@item (mod:@var{m} @var{x} @var{y})
+@itemx (umod:@var{m} @var{x} @var{y})
+Like @code{div} and @code{udiv} but represent the remainder instead of
+the quotient.
+
+@findex smin
+@findex smax
+@cindex signed minimum
+@cindex signed maximum
+@item (smin:@var{m} @var{x} @var{y})
+@itemx (smax:@var{m} @var{x} @var{y})
+Represents the smaller (for @code{smin}) or larger (for @code{smax}) of
+@var{x} and @var{y}, interpreted as signed integers in mode @var{m}.
+
+@findex umin
+@findex umax
+@cindex unsigned minimum and maximum
+@item (umin:@var{m} @var{x} @var{y})
+@itemx (umax:@var{m} @var{x} @var{y})
+Like @code{smin} and @code{smax}, but the values are interpreted as unsigned
+integers.
+
+@findex not
+@cindex complement, bitwise
+@cindex bitwise complement
+@item (not:@var{m} @var{x})
+Represents the bitwise complement of the value represented by @var{x},
+carried out in mode @var{m}, which must be a fixed-point machine mode.
+
+@findex and
+@cindex logical-and, bitwise
+@cindex bitwise logical-and
+@item (and:@var{m} @var{x} @var{y})
+Represents the bitwise logical-and of the values represented by
+@var{x} and @var{y}, carried out in machine mode @var{m}, which must be
+a fixed-point machine mode.
+
+@findex ior
+@cindex inclusive-or, bitwise
+@cindex bitwise inclusive-or
+@item (ior:@var{m} @var{x} @var{y})
+Represents the bitwise inclusive-or of the values represented by @var{x}
+and @var{y}, carried out in machine mode @var{m}, which must be a
+fixed-point mode.
+
+@findex xor
+@cindex exclusive-or, bitwise
+@cindex bitwise exclusive-or
+@item (xor:@var{m} @var{x} @var{y})
+Represents the bitwise exclusive-or of the values represented by @var{x}
+and @var{y}, carried out in machine mode @var{m}, which must be a
+fixed-point mode.
+
+@findex ashift
+@cindex left shift
+@cindex shift
+@cindex arithmetic shift
+@item (ashift:@var{m} @var{x} @var{c})
+Represents the result of arithmetically shifting @var{x} left by @var{c}
+places. @var{x} have mode @var{m}, a fixed-point machine mode. @var{c}
+be a fixed-point mode or be a constant with mode @code{VOIDmode}; which
+mode is determined by the mode called for in the machine description
+entry for the left-shift instruction. For example, on the Vax, the mode
+of @var{c} is @code{QImode} regardless of @var{m}.
+
+@findex lshiftrt
+@cindex right shift
+@findex ashiftrt
+@item (lshiftrt:@var{m} @var{x} @var{c})
+@itemx (ashiftrt:@var{m} @var{x} @var{c})
+Like @code{ashift} but for right shift. Unlike the case for left shift,
+these two operations are distinct.
+
+@findex rotate
+@cindex rotate
+@cindex left rotate
+@findex rotatert
+@cindex right rotate
+@item (rotate:@var{m} @var{x} @var{c})
+@itemx (rotatert:@var{m} @var{x} @var{c})
+Similar but represent left and right rotate. If @var{c} is a constant,
+use @code{rotate}.
+
+@findex abs
+@cindex absolute value
+@item (abs:@var{m} @var{x})
+Represents the absolute value of @var{x}, computed in mode @var{m}.
+
+@findex sqrt
+@cindex square root
+@item (sqrt:@var{m} @var{x})
+Represents the square root of @var{x}, computed in mode @var{m}.
+Most often @var{m} will be a floating point mode.
+
+@findex ffs
+@item (ffs:@var{m} @var{x})
+Represents one plus the index of the least significant 1-bit in
+@var{x}, represented as an integer of mode @var{m}. (The value is
+zero if @var{x} is zero.) The mode of @var{x} need not be @var{m};
+depending on the target machine, various mode combinations may be
+valid.
+@end table
+
+@node Comparisons, Bit Fields, Arithmetic, RTL
+@section Comparison Operations
+@cindex RTL comparison operations
+
+Comparison operators test a relation on two operands and are considered
+to represent a machine-dependent nonzero value described by, but not
+necessarily equal to, @code{STORE_FLAG_VALUE} (@pxref{Misc})
+if the relation holds, or zero if it does not. The mode of the
+comparison operation is independent of the mode of the data being
+compared. If the comparison operation is being tested (e.g., the first
+operand of an @code{if_then_else}), the mode must be @code{VOIDmode}.
+If the comparison operation is producing data to be stored in some
+variable, the mode must be in class @code{MODE_INT}. All comparison
+operations producing data must use the same mode, which is
+machine-specific.
+
+@cindex condition codes
+There are two ways that comparison operations may be used. The
+comparison operators may be used to compare the condition codes
+@code{(cc0)} against zero, as in @code{(eq (cc0) (const_int 0))}. Such
+a construct actually refers to the result of the preceding instruction
+in which the condition codes were set. The instructing setting the
+condition code must be adjacent to the instruction using the condition
+code; only @code{note} insns may separate them.
+
+Alternatively, a comparison operation may directly compare two data
+objects. The mode of the comparison is determined by the operands; they
+must both be valid for a common machine mode. A comparison with both
+operands constant would be invalid as the machine mode could not be
+deduced from it, but such a comparison should never exist in RTL due to
+constant folding.
+
+In the example above, if @code{(cc0)} were last set to
+@code{(compare @var{x} @var{y})}, the comparison operation is
+identical to @code{(eq @var{x} @var{y})}. Usually only one style
+of comparisons is supported on a particular machine, but the combine
+pass will try to merge the operations to produce the @code{eq} shown
+in case it exists in the context of the particular insn involved.
+
+Inequality comparisons come in two flavors, signed and unsigned. Thus,
+there are distinct expression codes @code{gt} and @code{gtu} for signed and
+unsigned greater-than. These can produce different results for the same
+pair of integer values: for example, 1 is signed greater-than -1 but not
+unsigned greater-than, because -1 when regarded as unsigned is actually
+@code{0xffffffff} which is greater than 1.
+
+The signed comparisons are also used for floating point values. Floating
+point comparisons are distinguished by the machine modes of the operands.
+
+@table @code
+@findex eq
+@cindex equal
+@item (eq:@var{m} @var{x} @var{y})
+1 if the values represented by @var{x} and @var{y} are equal,
+otherwise 0.
+
+@findex ne
+@cindex not equal
+@item (ne:@var{m} @var{x} @var{y})
+1 if the values represented by @var{x} and @var{y} are not equal,
+otherwise 0.
+
+@findex gt
+@cindex greater than
+@item (gt:@var{m} @var{x} @var{y})
+1 if the @var{x} is greater than @var{y}. If they are fixed-point,
+the comparison is done in a signed sense.
+
+@findex gtu
+@cindex greater than
+@cindex unsigned greater than
+@item (gtu:@var{m} @var{x} @var{y})
+Like @code{gt} but does unsigned comparison, on fixed-point numbers only.
+
+@findex lt
+@cindex less than
+@findex ltu
+@cindex unsigned less than
+@item (lt:@var{m} @var{x} @var{y})
+@itemx (ltu:@var{m} @var{x} @var{y})
+Like @code{gt} and @code{gtu} but test for ``less than''.
+
+@findex ge
+@cindex greater than
+@findex geu
+@cindex unsigned greater than
+@item (ge:@var{m} @var{x} @var{y})
+@itemx (geu:@var{m} @var{x} @var{y})
+Like @code{gt} and @code{gtu} but test for ``greater than or equal''.
+
+@findex le
+@cindex less than or equal
+@findex leu
+@cindex unsigned less than
+@item (le:@var{m} @var{x} @var{y})
+@itemx (leu:@var{m} @var{x} @var{y})
+Like @code{gt} and @code{gtu} but test for ``less than or equal''.
+
+@findex if_then_else
+@item (if_then_else @var{cond} @var{then} @var{else})
+This is not a comparison operation but is listed here because it is
+always used in conjunction with a comparison operation. To be
+precise, @var{cond} is a comparison expression. This expression
+represents a choice, according to @var{cond}, between the value
+represented by @var{then} and the one represented by @var{else}.
+
+On most machines, @code{if_then_else} expressions are valid only
+to express conditional jumps.
+
+@findex cond
+@item (cond [@var{test1} @var{value1} @var{test2} @var{value2} @dots{}] @var{default})
+Similar to @code{if_then_else}, but more general. Each of @var{test1},
+@var{test2}, @dots{} is performed in turn. The result of this expression is
+the @var{value} corresponding to the first non-zero test, or @var{default} if
+none of the tests are non-zero expressions.
+
+This is currently not valid for instruction patterns and is supported only
+for insn attributes. @xref{Insn Attributes}.
+@end table
+
+@node Bit Fields, Conversions, Comparisons, RTL
+@section Bit Fields
+@cindex bit fields
+
+Special expression codes exist to represent bitfield instructions.
+These types of expressions are lvalues in RTL; they may appear
+on the left side of an assignment, indicating insertion of a value
+into the specified bit field.
+
+@table @code
+@findex sign_extract
+@cindex @code{BITS_BIG_ENDIAN}, effect on @code{sign_extract}
+@item (sign_extract:@var{m} @var{loc} @var{size} @var{pos})
+This represents a reference to a sign-extended bit field contained or
+starting in @var{loc} (a memory or register reference). The bit field
+is @var{size} bits wide and starts at bit @var{pos}. The compilation
+option @code{BITS_BIG_ENDIAN} says which end of the memory unit
+@var{pos} counts from.
+
+If @var{loc} is in memory, its mode must be a single-byte integer mode.
+If @var{loc} is in a register, the mode to use is specified by the
+operand of the @code{insv} or @code{extv} pattern
+(@pxref{Standard Names}) and is usually a full-word integer mode.
+
+The mode of @var{pos} is machine-specific and is also specified
+in the @code{insv} or @code{extv} pattern.
+
+The mode @var{m} is the same as the mode that would be used for
+@var{loc} if it were a register.
+
+@findex zero_extract
+@item (zero_extract:@var{m} @var{loc} @var{size} @var{pos})
+Like @code{sign_extract} but refers to an unsigned or zero-extended
+bit field. The same sequence of bits are extracted, but they
+are filled to an entire word with zeros instead of by sign-extension.
+@end table
+
+@node Conversions, RTL Declarations, Bit Fields, RTL
+@section Conversions
+@cindex conversions
+@cindex machine mode conversions
+
+All conversions between machine modes must be represented by
+explicit conversion operations. For example, an expression
+which is the sum of a byte and a full word cannot be written as
+@code{(plus:SI (reg:QI 34) (reg:SI 80))} because the @code{plus}
+operation requires two operands of the same machine mode.
+Therefore, the byte-sized operand is enclosed in a conversion
+operation, as in
+
+@example
+(plus:SI (sign_extend:SI (reg:QI 34)) (reg:SI 80))
+@end example
+
+The conversion operation is not a mere placeholder, because there
+may be more than one way of converting from a given starting mode
+to the desired final mode. The conversion operation code says how
+to do it.
+
+For all conversion operations, @var{x} must not be @code{VOIDmode}
+because the mode in which to do the conversion would not be known.
+The conversion must either be done at compile-time or @var{x}
+must be placed into a register.
+
+@table @code
+@findex sign_extend
+@item (sign_extend:@var{m} @var{x})
+Represents the result of sign-extending the value @var{x}
+to machine mode @var{m}. @var{m} must be a fixed-point mode
+and @var{x} a fixed-point value of a mode narrower than @var{m}.
+
+@findex zero_extend
+@item (zero_extend:@var{m} @var{x})
+Represents the result of zero-extending the value @var{x}
+to machine mode @var{m}. @var{m} must be a fixed-point mode
+and @var{x} a fixed-point value of a mode narrower than @var{m}.
+
+@findex float_extend
+@item (float_extend:@var{m} @var{x})
+Represents the result of extending the value @var{x}
+to machine mode @var{m}. @var{m} must be a floating point mode
+and @var{x} a floating point value of a mode narrower than @var{m}.
+
+@findex truncate
+@item (truncate:@var{m} @var{x})
+Represents the result of truncating the value @var{x}
+to machine mode @var{m}. @var{m} must be a fixed-point mode
+and @var{x} a fixed-point value of a mode wider than @var{m}.
+
+@findex float_truncate
+@item (float_truncate:@var{m} @var{x})
+Represents the result of truncating the value @var{x}
+to machine mode @var{m}. @var{m} must be a floating point mode
+and @var{x} a floating point value of a mode wider than @var{m}.
+
+@findex float
+@item (float:@var{m} @var{x})
+Represents the result of converting fixed point value @var{x},
+regarded as signed, to floating point mode @var{m}.
+
+@findex unsigned_float
+@item (unsigned_float:@var{m} @var{x})
+Represents the result of converting fixed point value @var{x},
+regarded as unsigned, to floating point mode @var{m}.
+
+@findex fix
+@item (fix:@var{m} @var{x})
+When @var{m} is a fixed point mode, represents the result of
+converting floating point value @var{x} to mode @var{m}, regarded as
+signed. How rounding is done is not specified, so this operation may
+be used validly in compiling C code only for integer-valued operands.
+
+@findex unsigned_fix
+@item (unsigned_fix:@var{m} @var{x})
+Represents the result of converting floating point value @var{x} to
+fixed point mode @var{m}, regarded as unsigned. How rounding is done
+is not specified.
+
+@findex fix
+@item (fix:@var{m} @var{x})
+When @var{m} is a floating point mode, represents the result of
+converting floating point value @var{x} (valid for mode @var{m}) to an
+integer, still represented in floating point mode @var{m}, by rounding
+towards zero.
+@end table
+
+@node RTL Declarations, Side Effects, Conversions, RTL
+@section Declarations
+@cindex RTL declarations
+@cindex declarations, RTL
+
+Declaration expression codes do not represent arithmetic operations
+but rather state assertions about their operands.
+
+@table @code
+@findex strict_low_part
+@cindex @code{subreg}, in @code{strict_low_part}
+@item (strict_low_part (subreg:@var{m} (reg:@var{n} @var{r}) 0))
+This expression code is used in only one context: as the destination operand of a
+@code{set} expression. In addition, the operand of this expression
+must be a non-paradoxical @code{subreg} expression.
+
+The presence of @code{strict_low_part} says that the part of the
+register which is meaningful in mode @var{n}, but is not part of
+mode @var{m}, is not to be altered. Normally, an assignment to such
+a subreg is allowed to have undefined effects on the rest of the
+register when @var{m} is less than a word.
+@end table
+
+@node Side Effects, Incdec, RTL Declarations, RTL
+@section Side Effect Expressions
+@cindex RTL side effect expressions
+
+The expression codes described so far represent values, not actions.
+But machine instructions never produce values; they are meaningful
+only for their side effects on the state of the machine. Special
+expression codes are used to represent side effects.
+
+The body of an instruction is always one of these side effect codes;
+the codes described above, which represent values, appear only as
+the operands of these.
+
+@table @code
+@findex set
+@item (set @var{lval} @var{x})
+Represents the action of storing the value of @var{x} into the place
+represented by @var{lval}. @var{lval} must be an expression
+representing a place that can be stored in: @code{reg} (or
+@code{subreg} or @code{strict_low_part}), @code{mem}, @code{pc} or
+@code{cc0}.@refill
+
+If @var{lval} is a @code{reg}, @code{subreg} or @code{mem}, it has a
+machine mode; then @var{x} must be valid for that mode.@refill
+
+If @var{lval} is a @code{reg} whose machine mode is less than the full
+width of the register, then it means that the part of the register
+specified by the machine mode is given the specified value and the
+rest of the register receives an undefined value. Likewise, if
+@var{lval} is a @code{subreg} whose machine mode is narrower than
+the mode of the register, the rest of the register can be changed in
+an undefined way.
+
+If @var{lval} is a @code{strict_low_part} of a @code{subreg}, then the
+part of the register specified by the machine mode of the
+@code{subreg} is given the value @var{x} and the rest of the register
+is not changed.@refill
+
+If @var{lval} is @code{(cc0)}, it has no machine mode, and @var{x} may
+be either a @code{compare} expression or a value that may have any mode.
+The latter case represents a ``test'' instruction. The expression
+@code{(set (cc0) (reg:@var{m} @var{n}))} is equivalent to
+@code{(set (cc0) (compare (reg:@var{m} @var{n}) (const_int 0)))}.
+Use the former expression to save space during the compilation.
+
+@cindex jump instructions and @code{set}
+@cindex @code{if_then_else} usage
+If @var{lval} is @code{(pc)}, we have a jump instruction, and the
+possibilities for @var{x} are very limited. It may be a
+@code{label_ref} expression (unconditional jump). It may be an
+@code{if_then_else} (conditional jump), in which case either the
+second or the third operand must be @code{(pc)} (for the case which
+does not jump) and the other of the two must be a @code{label_ref}
+(for the case which does jump). @var{x} may also be a @code{mem} or
+@code{(plus:SI (pc) @var{y})}, where @var{y} may be a @code{reg} or a
+@code{mem}; these unusual patterns are used to represent jumps through
+branch tables.@refill
+
+If @var{lval} is neither @code{(cc0)} nor @code{(pc)}, the mode of
+@var{lval} must not be @code{VOIDmode} and the mode of @var{x} must be
+valid for the mode of @var{lval}.
+
+@findex SET_DEST
+@findex SET_SRC
+@var{lval} is customarily accessed with the @code{SET_DEST} macro and
+@var{x} with the @code{SET_SRC} macro.
+
+@findex return
+@item (return)
+As the sole expression in a pattern, represents a return from the
+current function, on machines where this can be done with one
+instruction, such as Vaxes. On machines where a multi-instruction
+``epilogue'' must be executed in order to return from the function,
+returning is done by jumping to a label which precedes the epilogue, and
+the @code{return} expression code is never used.
+
+Inside an @code{if_then_else} expression, represents the value to be
+placed in @code{pc} to return to the caller.
+
+Note that an insn pattern of @code{(return)} is logically equivalent to
+@code{(set (pc) (return))}, but the latter form is never used.
+
+@findex call
+@item (call @var{function} @var{nargs})
+Represents a function call. @var{function} is a @code{mem} expression
+whose address is the address of the function to be called.
+@var{nargs} is an expression which can be used for two purposes: on
+some machines it represents the number of bytes of stack argument; on
+others, it represents the number of argument registers.
+
+Each machine has a standard machine mode which @var{function} must
+have. The machine description defines macro @code{FUNCTION_MODE} to
+expand into the requisite mode name. The purpose of this mode is to
+specify what kind of addressing is allowed, on machines where the
+allowed kinds of addressing depend on the machine mode being
+addressed.
+
+@findex clobber
+@item (clobber @var{x})
+Represents the storing or possible storing of an unpredictable,
+undescribed value into @var{x}, which must be a @code{reg},
+@code{scratch} or @code{mem} expression.
+
+One place this is used is in string instructions that store standard
+values into particular hard registers. It may not be worth the
+trouble to describe the values that are stored, but it is essential to
+inform the compiler that the registers will be altered, lest it
+attempt to keep data in them across the string instruction.
+
+If @var{x} is @code{(mem:BLK (const_int 0))}, it means that all memory
+locations must be presumed clobbered.
+
+Note that the machine description classifies certain hard registers as
+``call-clobbered''. All function call instructions are assumed by
+default to clobber these registers, so there is no need to use
+@code{clobber} expressions to indicate this fact. Also, each function
+call is assumed to have the potential to alter any memory location,
+unless the function is declared @code{const}.
+
+If the last group of expressions in a @code{parallel} are each a
+@code{clobber} expression whose arguments are @code{reg} or
+@code{match_scratch} (@pxref{RTL Template}) expressions, the combiner
+phase can add the appropriate @code{clobber} expressions to an insn it
+has constructed when doing so will cause a pattern to be matched.
+
+This feature can be used, for example, on a machine that whose multiply
+and add instructions don't use an MQ register but which has an
+add-accumulate instruction that does clobber the MQ register. Similarly,
+a combined instruction might require a temporary register while the
+constituent instructions might not.
+
+When a @code{clobber} expression for a register appears inside a
+@code{parallel} with other side effects, the register allocator
+guarantees that the register is unoccupied both before and after that
+insn. However, the reload phase may allocate a register used for one of
+the inputs unless the @samp{&} constraint is specified for the selected
+alternative (@pxref{Modifiers}). You can clobber either a specific hard
+register, a pseudo register, or a @code{scratch} expression; in the
+latter two cases, GNU CC will allocate a hard register that is available
+there for use as a temporary.
+
+For instructions that require a temporary register, you should use
+@code{scratch} instead of a pseudo-register because this will allow the
+combiner phase to add the @code{clobber} when required. You do this by
+coding (@code{clobber} (@code{match_scratch} @dots{})). If you do
+clobber a pseudo register, use one which appears nowhere else---generate
+a new one each time. Otherwise, you may confuse CSE.
+
+There is one other known use for clobbering a pseudo register in a
+@code{parallel}: when one of the input operands of the insn is also
+clobbered by the insn. In this case, using the same pseudo register in
+the clobber and elsewhere in the insn produces the expected results.
+
+@findex use
+@item (use @var{x})
+Represents the use of the value of @var{x}. It indicates that the
+value in @var{x} at this point in the program is needed, even though
+it may not be apparent why this is so. Therefore, the compiler will
+not attempt to delete previous instructions whose only effect is to
+store a value in @var{x}. @var{x} must be a @code{reg} expression.
+
+During the delayed branch scheduling phase, @var{x} may be an insn.
+This indicates that @var{x} previously was located at this place in the
+code and its data dependencies need to be taken into account. These
+@code{use} insns will be deleted before the delayed branch scheduling
+phase exits.
+
+@findex parallel
+@item (parallel [@var{x0} @var{x1} @dots{}])
+Represents several side effects performed in parallel. The square
+brackets stand for a vector; the operand of @code{parallel} is a
+vector of expressions. @var{x0}, @var{x1} and so on are individual
+side effect expressions---expressions of code @code{set}, @code{call},
+@code{return}, @code{clobber} or @code{use}.@refill
+
+``In parallel'' means that first all the values used in the individual
+side-effects are computed, and second all the actual side-effects are
+performed. For example,
+
+@example
+(parallel [(set (reg:SI 1) (mem:SI (reg:SI 1)))
+ (set (mem:SI (reg:SI 1)) (reg:SI 1))])
+@end example
+
+@noindent
+says unambiguously that the values of hard register 1 and the memory
+location addressed by it are interchanged. In both places where
+@code{(reg:SI 1)} appears as a memory address it refers to the value
+in register 1 @emph{before} the execution of the insn.
+
+It follows that it is @emph{incorrect} to use @code{parallel} and
+expect the result of one @code{set} to be available for the next one.
+For example, people sometimes attempt to represent a jump-if-zero
+instruction this way:
+
+@example
+(parallel [(set (cc0) (reg:SI 34))
+ (set (pc) (if_then_else
+ (eq (cc0) (const_int 0))
+ (label_ref @dots{})
+ (pc)))])
+@end example
+
+@noindent
+But this is incorrect, because it says that the jump condition depends
+on the condition code value @emph{before} this instruction, not on the
+new value that is set by this instruction.
+
+@cindex peephole optimization, RTL representation
+Peephole optimization, which takes place together with final assembly
+code output, can produce insns whose patterns consist of a @code{parallel}
+whose elements are the operands needed to output the resulting
+assembler code---often @code{reg}, @code{mem} or constant expressions.
+This would not be well-formed RTL at any other stage in compilation,
+but it is ok then because no further optimization remains to be done.
+However, the definition of the macro @code{NOTICE_UPDATE_CC}, if
+any, must deal with such insns if you define any peephole optimizations.
+
+@findex sequence
+@item (sequence [@var{insns} @dots{}])
+Represents a sequence of insns. Each of the @var{insns} that appears
+in the vector is suitable for appearing in the chain of insns, so it
+must be an @code{insn}, @code{jump_insn}, @code{call_insn},
+@code{code_label}, @code{barrier} or @code{note}.
+
+A @code{sequence} RTX is never placed in an actual insn during RTL
+generation. It represents the sequence of insns that result from a
+@code{define_expand} @emph{before} those insns are passed to
+@code{emit_insn} to insert them in the chain of insns. When actually
+inserted, the individual sub-insns are separated out and the
+@code{sequence} is forgotten.
+
+After delay-slot scheduling is completed, an insn and all the insns that
+reside in its delay slots are grouped together into a @code{sequence}.
+The insn requiring the delay slot is the first insn in the vector;
+subsequent insns are to be placed in the delay slot.
+
+@code{INSN_ANNULLED_BRANCH_P} is set on an insn in a delay slot to
+indicate that a branch insn should be used that will conditionally annul
+the effect of the insns in the delay slots. In such a case,
+@code{INSN_FROM_TARGET_P} indicates that the insn is from the target of
+the branch and should be executed only if the branch is taken; otherwise
+the insn should be executed only if the branch is not taken.
+@xref{Delay Slots}.
+@end table
+
+These expression codes appear in place of a side effect, as the body of
+an insn, though strictly speaking they do not always describe side
+effects as such:
+
+@table @code
+@findex asm_input
+@item (asm_input @var{s})
+Represents literal assembler code as described by the string @var{s}.
+
+@findex unspec
+@findex unspec_volatile
+@item (unspec [@var{operands} @dots{}] @var{index})
+@itemx (unspec_volatile [@var{operands} @dots{}] @var{index})
+Represents a machine-specific operation on @var{operands}. @var{index}
+selects between multiple machine-specific operations.
+@code{unspec_volatile} is used for volatile operations and operations
+that may trap; @code{unspec} is used for other operations.
+
+These codes may appear inside a @code{pattern} of an
+insn, inside a @code{parallel}, or inside an expression.
+
+@findex addr_vec
+@item (addr_vec:@var{m} [@var{lr0} @var{lr1} @dots{}])
+Represents a table of jump addresses. The vector elements @var{lr0},
+etc., are @code{label_ref} expressions. The mode @var{m} specifies
+how much space is given to each address; normally @var{m} would be
+@code{Pmode}.
+
+@findex addr_diff_vec
+@item (addr_diff_vec:@var{m} @var{base} [@var{lr0} @var{lr1} @dots{}])
+Represents a table of jump addresses expressed as offsets from
+@var{base}. The vector elements @var{lr0}, etc., are @code{label_ref}
+expressions and so is @var{base}. The mode @var{m} specifies how much
+space is given to each address-difference.@refill
+@end table
+
+@node Incdec, Assembler, Side Effects, RTL
+@section Embedded Side-Effects on Addresses
+@cindex RTL preincrement
+@cindex RTL postincrement
+@cindex RTL predecrement
+@cindex RTL postdecrement
+
+Four special side-effect expression codes appear as memory addresses.
+
+@table @code
+@findex pre_dec
+@item (pre_dec:@var{m} @var{x})
+Represents the side effect of decrementing @var{x} by a standard
+amount and represents also the value that @var{x} has after being
+decremented. @var{x} must be a @code{reg} or @code{mem}, but most
+machines allow only a @code{reg}. @var{m} must be the machine mode
+for pointers on the machine in use. The amount @var{x} is decremented
+by is the length in bytes of the machine mode of the containing memory
+reference of which this expression serves as the address. Here is an
+example of its use:@refill
+
+@example
+(mem:DF (pre_dec:SI (reg:SI 39)))
+@end example
+
+@noindent
+This says to decrement pseudo register 39 by the length of a @code{DFmode}
+value and use the result to address a @code{DFmode} value.
+
+@findex pre_inc
+@item (pre_inc:@var{m} @var{x})
+Similar, but specifies incrementing @var{x} instead of decrementing it.
+
+@findex post_dec
+@item (post_dec:@var{m} @var{x})
+Represents the same side effect as @code{pre_dec} but a different
+value. The value represented here is the value @var{x} has @i{before}
+being decremented.
+
+@findex post_inc
+@item (post_inc:@var{m} @var{x})
+Similar, but specifies incrementing @var{x} instead of decrementing it.
+@end table
+
+These embedded side effect expressions must be used with care. Instruction
+patterns may not use them. Until the @samp{flow} pass of the compiler,
+they may occur only to represent pushes onto the stack. The @samp{flow}
+pass finds cases where registers are incremented or decremented in one
+instruction and used as an address shortly before or after; these cases are
+then transformed to use pre- or post-increment or -decrement.
+
+If a register used as the operand of these expressions is used in
+another address in an insn, the original value of the register is used.
+Uses of the register outside of an address are not permitted within the
+same insn as a use in an embedded side effect expression because such
+insns behave differently on different machines and hence must be treated
+as ambiguous and disallowed.
+
+An instruction that can be represented with an embedded side effect
+could also be represented using @code{parallel} containing an additional
+@code{set} to describe how the address register is altered. This is not
+done because machines that allow these operations at all typically
+allow them wherever a memory address is called for. Describing them as
+additional parallel stores would require doubling the number of entries
+in the machine description.
+
+@node Assembler, Insns, Incdec, RTL
+@section Assembler Instructions as Expressions
+@cindex assembler instructions in RTL
+
+@cindex @code{asm_operands}, usage
+The RTX code @code{asm_operands} represents a value produced by a
+user-specified assembler instruction. It is used to represent
+an @code{asm} statement with arguments. An @code{asm} statement with
+a single output operand, like this:
+
+@smallexample
+asm ("foo %1,%2,%0" : "=a" (outputvar) : "g" (x + y), "di" (*z));
+@end smallexample
+
+@noindent
+is represented using a single @code{asm_operands} RTX which represents
+the value that is stored in @code{outputvar}:
+
+@smallexample
+(set @var{rtx-for-outputvar}
+ (asm_operands "foo %1,%2,%0" "a" 0
+ [@var{rtx-for-addition-result} @var{rtx-for-*z}]
+ [(asm_input:@var{m1} "g")
+ (asm_input:@var{m2} "di")]))
+@end smallexample
+
+@noindent
+Here the operands of the @code{asm_operands} RTX are the assembler
+template string, the output-operand's constraint, the index-number of the
+output operand among the output operands specified, a vector of input
+operand RTX's, and a vector of input-operand modes and constraints. The
+mode @var{m1} is the mode of the sum @code{x+y}; @var{m2} is that of
+@code{*z}.
+
+When an @code{asm} statement has multiple output values, its insn has
+several such @code{set} RTX's inside of a @code{parallel}. Each @code{set}
+contains a @code{asm_operands}; all of these share the same assembler
+template and vectors, but each contains the constraint for the respective
+output operand. They are also distinguished by the output-operand index
+number, which is 0, 1, @dots{} for successive output operands.
+
+@node Insns, Calls, Assembler, RTL
+@section Insns
+@cindex insns
+
+The RTL representation of the code for a function is a doubly-linked
+chain of objects called @dfn{insns}. Insns are expressions with
+special codes that are used for no other purpose. Some insns are
+actual instructions; others represent dispatch tables for @code{switch}
+statements; others represent labels to jump to or various sorts of
+declarative information.
+
+In addition to its own specific data, each insn must have a unique
+id-number that distinguishes it from all other insns in the current
+function (after delayed branch scheduling, copies of an insn with the
+same id-number may be present in multiple places in a function, but
+these copies will always be identical and will only appear inside a
+@code{sequence}), and chain pointers to the preceding and following
+insns. These three fields occupy the same position in every insn,
+independent of the expression code of the insn. They could be accessed
+with @code{XEXP} and @code{XINT}, but instead three special macros are
+always used:
+
+@table @code
+@findex INSN_UID
+@item INSN_UID (@var{i})
+Accesses the unique id of insn @var{i}.
+
+@findex PREV_INSN
+@item PREV_INSN (@var{i})
+Accesses the chain pointer to the insn preceding @var{i}.
+If @var{i} is the first insn, this is a null pointer.
+
+@findex NEXT_INSN
+@item NEXT_INSN (@var{i})
+Accesses the chain pointer to the insn following @var{i}.
+If @var{i} is the last insn, this is a null pointer.
+@end table
+
+@findex get_insns
+@findex get_last_insn
+The first insn in the chain is obtained by calling @code{get_insns}; the
+last insn is the result of calling @code{get_last_insn}. Within the
+chain delimited by these insns, the @code{NEXT_INSN} and
+@code{PREV_INSN} pointers must always correspond: if @var{insn} is not
+the first insn,
+
+@example
+NEXT_INSN (PREV_INSN (@var{insn})) == @var{insn}
+@end example
+
+@noindent
+is always true and if @var{insn} is not the last insn,
+
+@example
+PREV_INSN (NEXT_INSN (@var{insn})) == @var{insn}
+@end example
+
+@noindent
+is always true.
+
+After delay slot scheduling, some of the insns in the chain might be
+@code{sequence} expressions, which contain a vector of insns. The value
+of @code{NEXT_INSN} in all but the last of these insns is the next insn
+in the vector; the value of @code{NEXT_INSN} of the last insn in the vector
+is the same as the value of @code{NEXT_INSN} for the @code{sequence} in
+which it is contained. Similar rules apply for @code{PREV_INSN}.
+
+This means that the above invariants are not necessarily true for insns
+inside @code{sequence} expressions. Specifically, if @var{insn} is the
+first insn in a @code{sequence}, @code{NEXT_INSN (PREV_INSN (@var{insn}))}
+is the insn containing the @code{sequence} expression, as is the value
+of @code{PREV_INSN (NEXT_INSN (@var{insn}))} is @var{insn} is the last
+insn in the @code{sequence} expression. You can use these expressions
+to find the containing @code{sequence} expression.@refill
+
+Every insn has one of the following six expression codes:
+
+@table @code
+@findex insn
+@item insn
+The expression code @code{insn} is used for instructions that do not jump
+and do not do function calls. @code{sequence} expressions are always
+contained in insns with code @code{insn} even if one of those insns
+should jump or do function calls.
+
+Insns with code @code{insn} have four additional fields beyond the three
+mandatory ones listed above. These four are described in a table below.
+
+@findex jump_insn
+@item jump_insn
+The expression code @code{jump_insn} is used for instructions that may
+jump (or, more generally, may contain @code{label_ref} expressions). If
+there is an instruction to return from the current function, it is
+recorded as a @code{jump_insn}.
+
+@findex JUMP_LABEL
+@code{jump_insn} insns have the same extra fields as @code{insn} insns,
+accessed in the same way and in addition contain a field
+@code{JUMP_LABEL} which is defined once jump optimization has completed.
+
+For simple conditional and unconditional jumps, this field contains the
+@code{code_label} to which this insn will (possibly conditionally)
+branch. In a more complex jump, @code{JUMP_LABEL} records one of the
+labels that the insn refers to; the only way to find the others
+is to scan the entire body of the insn.
+
+Return insns count as jumps, but since they do not refer to any labels,
+they have zero in the @code{JUMP_LABEL} field.
+
+@findex call_insn
+@item call_insn
+The expression code @code{call_insn} is used for instructions that may do
+function calls. It is important to distinguish these instructions because
+they imply that certain registers and memory locations may be altered
+unpredictably.
+
+@findex CALL_INSN_FUNCTION_USAGE
+@code{call_insn} insns have the same extra fields as @code{insn} insns,
+accessed in the same way and in addition contain a field
+@code{CALL_INSN_FUNCTION_USAGE}, which contains a list (chain of
+@code{expr_list} expressions) containing @code{use} and @code{clobber}
+expressions that denote hard registers used or clobbered by the called
+function. A register specified in a @code{clobber} in this list is
+modified @emph{after} the execution of the @code{call_insn}, while a
+register in a @code{clobber} in the body of the @code{call_insn} is
+clobbered before the insn completes execution. @code{clobber}
+expressions in this list augment registers specified in
+@code{CALL_USED_REGISTERS} (@pxref{Register Basics}).
+
+@findex code_label
+@findex CODE_LABEL_NUMBER
+@item code_label
+A @code{code_label} insn represents a label that a jump insn can jump
+to. It contains two special fields of data in addition to the three
+standard ones. @code{CODE_LABEL_NUMBER} is used to hold the @dfn{label
+number}, a number that identifies this label uniquely among all the
+labels in the compilation (not just in the current function).
+Ultimately, the label is represented in the assembler output as an
+assembler label, usually of the form @samp{L@var{n}} where @var{n} is
+the label number.
+
+When a @code{code_label} appears in an RTL expression, it normally
+appears within a @code{label_ref} which represents the address of
+the label, as a number.
+
+@findex LABEL_NUSES
+The field @code{LABEL_NUSES} is only defined once the jump optimization
+phase is completed and contains the number of times this label is
+referenced in the current function.
+
+@findex barrier
+@item barrier
+Barriers are placed in the instruction stream when control cannot flow
+past them. They are placed after unconditional jump instructions to
+indicate that the jumps are unconditional and after calls to
+@code{volatile} functions, which do not return (e.g., @code{exit}).
+They contain no information beyond the three standard fields.
+
+@findex note
+@findex NOTE_LINE_NUMBER
+@findex NOTE_SOURCE_FILE
+@item note
+@code{note} insns are used to represent additional debugging and
+declarative information. They contain two nonstandard fields, an
+integer which is accessed with the macro @code{NOTE_LINE_NUMBER} and a
+string accessed with @code{NOTE_SOURCE_FILE}.
+
+If @code{NOTE_LINE_NUMBER} is positive, the note represents the
+position of a source line and @code{NOTE_SOURCE_FILE} is the source file name
+that the line came from. These notes control generation of line
+number data in the assembler output.
+
+Otherwise, @code{NOTE_LINE_NUMBER} is not really a line number but a
+code with one of the following values (and @code{NOTE_SOURCE_FILE}
+must contain a null pointer):
+
+@table @code
+@findex NOTE_INSN_DELETED
+@item NOTE_INSN_DELETED
+Such a note is completely ignorable. Some passes of the compiler
+delete insns by altering them into notes of this kind.
+
+@findex NOTE_INSN_BLOCK_BEG
+@findex NOTE_INSN_BLOCK_END
+@item NOTE_INSN_BLOCK_BEG
+@itemx NOTE_INSN_BLOCK_END
+These types of notes indicate the position of the beginning and end
+of a level of scoping of variable names. They control the output
+of debugging information.
+
+@findex NOTE_INSN_LOOP_BEG
+@findex NOTE_INSN_LOOP_END
+@item NOTE_INSN_LOOP_BEG
+@itemx NOTE_INSN_LOOP_END
+These types of notes indicate the position of the beginning and end
+of a @code{while} or @code{for} loop. They enable the loop optimizer
+to find loops quickly.
+
+@findex NOTE_INSN_LOOP_CONT
+@item NOTE_INSN_LOOP_CONT
+Appears at the place in a loop that @code{continue} statements jump to.
+
+@findex NOTE_INSN_LOOP_VTOP
+@item NOTE_INSN_LOOP_VTOP
+This note indicates the place in a loop where the exit test begins for
+those loops in which the exit test has been duplicated. This position
+becomes another virtual start of the loop when considering loop
+invariants.
+
+@findex NOTE_INSN_FUNCTION_END
+@item NOTE_INSN_FUNCTION_END
+Appears near the end of the function body, just before the label that
+@code{return} statements jump to (on machine where a single instruction
+does not suffice for returning). This note may be deleted by jump
+optimization.
+
+@findex NOTE_INSN_SETJMP
+@item NOTE_INSN_SETJMP
+Appears following each call to @code{setjmp} or a related function.
+@end table
+
+These codes are printed symbolically when they appear in debugging dumps.
+@end table
+
+@cindex @code{HImode}, in @code{insn}
+@cindex @code{QImode}, in @code{insn}
+The machine mode of an insn is normally @code{VOIDmode}, but some
+phases use the mode for various purposes; for example, the reload pass
+sets it to @code{HImode} if the insn needs reloading but not register
+elimination and @code{QImode} if both are required. The common
+subexpression elimination pass sets the mode of an insn to @code{QImode}
+when it is the first insn in a block that has already been processed.
+
+Here is a table of the extra fields of @code{insn}, @code{jump_insn}
+and @code{call_insn} insns:
+
+@table @code
+@findex PATTERN
+@item PATTERN (@var{i})
+An expression for the side effect performed by this insn. This must be
+one of the following codes: @code{set}, @code{call}, @code{use},
+@code{clobber}, @code{return}, @code{asm_input}, @code{asm_output},
+@code{addr_vec}, @code{addr_diff_vec}, @code{trap_if}, @code{unspec},
+@code{unspec_volatile}, @code{parallel}, or @code{sequence}. If it is a @code{parallel},
+each element of the @code{parallel} must be one these codes, except that
+@code{parallel} expressions cannot be nested and @code{addr_vec} and
+@code{addr_diff_vec} are not permitted inside a @code{parallel} expression.
+
+@findex INSN_CODE
+@item INSN_CODE (@var{i})
+An integer that says which pattern in the machine description matches
+this insn, or -1 if the matching has not yet been attempted.
+
+Such matching is never attempted and this field remains -1 on an insn
+whose pattern consists of a single @code{use}, @code{clobber},
+@code{asm_input}, @code{addr_vec} or @code{addr_diff_vec} expression.
+
+@findex asm_noperands
+Matching is also never attempted on insns that result from an @code{asm}
+statement. These contain at least one @code{asm_operands} expression.
+The function @code{asm_noperands} returns a non-negative value for
+such insns.
+
+In the debugging output, this field is printed as a number followed by
+a symbolic representation that locates the pattern in the @file{md}
+file as some small positive or negative offset from a named pattern.
+
+@findex LOG_LINKS
+@item LOG_LINKS (@var{i})
+A list (chain of @code{insn_list} expressions) giving information about
+dependencies between instructions within a basic block. Neither a jump
+nor a label may come between the related insns.
+
+@findex REG_NOTES
+@item REG_NOTES (@var{i})
+A list (chain of @code{expr_list} and @code{insn_list} expressions)
+giving miscellaneous information about the insn. It is often information
+pertaining to the registers used in this insn.
+@end table
+
+The @code{LOG_LINKS} field of an insn is a chain of @code{insn_list}
+expressions. Each of these has two operands: the first is an insn,
+and the second is another @code{insn_list} expression (the next one in
+the chain). The last @code{insn_list} in the chain has a null pointer
+as second operand. The significant thing about the chain is which
+insns appear in it (as first operands of @code{insn_list}
+expressions). Their order is not significant.
+
+This list is originally set up by the flow analysis pass; it is a null
+pointer until then. Flow only adds links for those data dependencies
+which can be used for instruction combination. For each insn, the flow
+analysis pass adds a link to insns which store into registers values
+that are used for the first time in this insn. The instruction
+scheduling pass adds extra links so that every dependence will be
+represented. Links represent data dependencies, antidependencies and
+output dependencies; the machine mode of the link distinguishes these
+three types: antidependencies have mode @code{REG_DEP_ANTI}, output
+dependencies have mode @code{REG_DEP_OUTPUT}, and data dependencies have
+mode @code{VOIDmode}.
+
+The @code{REG_NOTES} field of an insn is a chain similar to the
+@code{LOG_LINKS} field but it includes @code{expr_list} expressions in
+addition to @code{insn_list} expressions. There are several kinds
+of register notes, which are distinguished by the machine mode, which
+in a register note is really understood as being an @code{enum reg_note}.
+The first operand @var{op} of the note is data whose meaning depends on
+the kind of note.
+
+@findex REG_NOTE_KIND
+@findex PUT_REG_NOTE_KIND
+The macro @code{REG_NOTE_KIND (@var{x})} returns the kind of
+register note. Its counterpart, the macro @code{PUT_REG_NOTE_KIND
+(@var{x}, @var{newkind})} sets the register note type of @var{x} to be
+@var{newkind}.
+
+Register notes are of three classes: They may say something about an
+input to an insn, they may say something about an output of an insn, or
+they may create a linkage between two insns. There are also a set
+of values that are only used in @code{LOG_LINKS}.
+
+These register notes annotate inputs to an insn:
+
+@table @code
+@findex REG_DEAD
+@item REG_DEAD
+The value in @var{op} dies in this insn; that is to say, altering the
+value immediately after this insn would not affect the future behavior
+of the program.
+
+This does not necessarily mean that the register @var{op} has no useful
+value after this insn since it may also be an output of the insn. In
+such a case, however, a @code{REG_DEAD} note would be redundant and is
+usually not present until after the reload pass, but no code relies on
+this fact.
+
+@findex REG_INC
+@item REG_INC
+The register @var{op} is incremented (or decremented; at this level
+there is no distinction) by an embedded side effect inside this insn.
+This means it appears in a @code{post_inc}, @code{pre_inc},
+@code{post_dec} or @code{pre_dec} expression.
+
+@findex REG_NONNEG
+@item REG_NONNEG
+The register @var{op} is known to have a nonnegative value when this
+insn is reached. This is used so that decrement and branch until zero
+instructions, such as the m68k dbra, can be matched.
+
+The @code{REG_NONNEG} note is added to insns only if the machine
+description has a @samp{decrement_and_branch_until_zero} pattern.
+
+@findex REG_NO_CONFLICT
+@item REG_NO_CONFLICT
+This insn does not cause a conflict between @var{op} and the item
+being set by this insn even though it might appear that it does.
+In other words, if the destination register and @var{op} could
+otherwise be assigned the same register, this insn does not
+prevent that assignment.
+
+Insns with this note are usually part of a block that begins with a
+@code{clobber} insn specifying a multi-word pseudo register (which will
+be the output of the block), a group of insns that each set one word of
+the value and have the @code{REG_NO_CONFLICT} note attached, and a final
+insn that copies the output to itself with an attached @code{REG_EQUAL}
+note giving the expression being computed. This block is encapsulated
+with @code{REG_LIBCALL} and @code{REG_RETVAL} notes on the first and
+last insns, respectively.
+
+@findex REG_LABEL
+@item REG_LABEL
+This insn uses @var{op}, a @code{code_label}, but is not a
+@code{jump_insn}. The presence of this note allows jump optimization to
+be aware that @var{op} is, in fact, being used.
+@end table
+
+The following notes describe attributes of outputs of an insn:
+
+@table @code
+@findex REG_EQUIV
+@findex REG_EQUAL
+@item REG_EQUIV
+@itemx REG_EQUAL
+This note is only valid on an insn that sets only one register and
+indicates that that register will be equal to @var{op} at run time; the
+scope of this equivalence differs between the two types of notes. The
+value which the insn explicitly copies into the register may look
+different from @var{op}, but they will be equal at run time. If the
+output of the single @code{set} is a @code{strict_low_part} expression,
+the note refers to the register that is contained in @code{SUBREG_REG}
+of the @code{subreg} expression.
+
+For @code{REG_EQUIV}, the register is equivalent to @var{op} throughout
+the entire function, and could validly be replaced in all its
+occurrences by @var{op}. (``Validly'' here refers to the data flow of
+the program; simple replacement may make some insns invalid.) For
+example, when a constant is loaded into a register that is never
+assigned any other value, this kind of note is used.
+
+When a parameter is copied into a pseudo-register at entry to a function,
+a note of this kind records that the register is equivalent to the stack
+slot where the parameter was passed. Although in this case the register
+may be set by other insns, it is still valid to replace the register
+by the stack slot throughout the function.
+
+In the case of @code{REG_EQUAL}, the register that is set by this insn
+will be equal to @var{op} at run time at the end of this insn but not
+necessarily elsewhere in the function. In this case, @var{op}
+is typically an arithmetic expression. For example, when a sequence of
+insns such as a library call is used to perform an arithmetic operation,
+this kind of note is attached to the insn that produces or copies the
+final value.
+
+These two notes are used in different ways by the compiler passes.
+@code{REG_EQUAL} is used by passes prior to register allocation (such as
+common subexpression elimination and loop optimization) to tell them how
+to think of that value. @code{REG_EQUIV} notes are used by register
+allocation to indicate that there is an available substitute expression
+(either a constant or a @code{mem} expression for the location of a
+parameter on the stack) that may be used in place of a register if
+insufficient registers are available.
+
+Except for stack homes for parameters, which are indicated by a
+@code{REG_EQUIV} note and are not useful to the early optimization
+passes and pseudo registers that are equivalent to a memory location
+throughout there entire life, which is not detected until later in
+the compilation, all equivalences are initially indicated by an attached
+@code{REG_EQUAL} note. In the early stages of register allocation, a
+@code{REG_EQUAL} note is changed into a @code{REG_EQUIV} note if
+@var{op} is a constant and the insn represents the only set of its
+destination register.
+
+Thus, compiler passes prior to register allocation need only check for
+@code{REG_EQUAL} notes and passes subsequent to register allocation
+need only check for @code{REG_EQUIV} notes.
+
+@findex REG_UNUSED
+@item REG_UNUSED
+The register @var{op} being set by this insn will not be used in a
+subsequent insn. This differs from a @code{REG_DEAD} note, which
+indicates that the value in an input will not be used subsequently.
+These two notes are independent; both may be present for the same
+register.
+
+@findex REG_WAS_0
+@item REG_WAS_0
+The single output of this insn contained zero before this insn.
+@var{op} is the insn that set it to zero. You can rely on this note if
+it is present and @var{op} has not been deleted or turned into a @code{note};
+its absence implies nothing.
+@end table
+
+These notes describe linkages between insns. They occur in pairs: one
+insn has one of a pair of notes that points to a second insn, which has
+the inverse note pointing back to the first insn.
+
+@table @code
+@findex REG_RETVAL
+@item REG_RETVAL
+This insn copies the value of a multi-insn sequence (for example, a
+library call), and @var{op} is the first insn of the sequence (for a
+library call, the first insn that was generated to set up the arguments
+for the library call).
+
+Loop optimization uses this note to treat such a sequence as a single
+operation for code motion purposes and flow analysis uses this note to
+delete such sequences whose results are dead.
+
+A @code{REG_EQUAL} note will also usually be attached to this insn to
+provide the expression being computed by the sequence.
+
+@findex REG_LIBCALL
+@item REG_LIBCALL
+This is the inverse of @code{REG_RETVAL}: it is placed on the first
+insn of a multi-insn sequence, and it points to the last one.
+
+@findex REG_CC_SETTER
+@findex REG_CC_USER
+@item REG_CC_SETTER
+@itemx REG_CC_USER
+On machines that use @code{cc0}, the insns which set and use @code{cc0}
+set and use @code{cc0} are adjacent. However, when branch delay slot
+filling is done, this may no longer be true. In this case a
+@code{REG_CC_USER} note will be placed on the insn setting @code{cc0} to
+point to the insn using @code{cc0} and a @code{REG_CC_SETTER} note will
+be placed on the insn using @code{cc0} to point to the insn setting
+@code{cc0}.@refill
+@end table
+
+These values are only used in the @code{LOG_LINKS} field, and indicate
+the type of dependency that each link represents. Links which indicate
+a data dependence (a read after write dependence) do not use any code,
+they simply have mode @code{VOIDmode}, and are printed without any
+descriptive text.
+
+@table @code
+@findex REG_DEP_ANTI
+@item REG_DEP_ANTI
+This indicates an anti dependence (a write after read dependence).
+
+@findex REG_DEP_OUTPUT
+@item REG_DEP_OUTPUT
+This indicates an output dependence (a write after write dependence).
+@end table
+
+For convenience, the machine mode in an @code{insn_list} or
+@code{expr_list} is printed using these symbolic codes in debugging dumps.
+
+@findex insn_list
+@findex expr_list
+The only difference between the expression codes @code{insn_list} and
+@code{expr_list} is that the first operand of an @code{insn_list} is
+assumed to be an insn and is printed in debugging dumps as the insn's
+unique id; the first operand of an @code{expr_list} is printed in the
+ordinary way as an expression.
+
+@node Calls, Sharing, Insns, RTL
+@section RTL Representation of Function-Call Insns
+@cindex calling functions in RTL
+@cindex RTL function-call insns
+@cindex function-call insns
+
+Insns that call subroutines have the RTL expression code @code{call_insn}.
+These insns must satisfy special rules, and their bodies must use a special
+RTL expression code, @code{call}.
+
+@cindex @code{call} usage
+A @code{call} expression has two operands, as follows:
+
+@example
+(call (mem:@var{fm} @var{addr}) @var{nbytes})
+@end example
+
+@noindent
+Here @var{nbytes} is an operand that represents the number of bytes of
+argument data being passed to the subroutine, @var{fm} is a machine mode
+(which must equal as the definition of the @code{FUNCTION_MODE} macro in
+the machine description) and @var{addr} represents the address of the
+subroutine.
+
+For a subroutine that returns no value, the @code{call} expression as
+shown above is the entire body of the insn, except that the insn might
+also contain @code{use} or @code{clobber} expressions.
+
+@cindex @code{BLKmode}, and function return values
+For a subroutine that returns a value whose mode is not @code{BLKmode},
+the value is returned in a hard register. If this register's number is
+@var{r}, then the body of the call insn looks like this:
+
+@example
+(set (reg:@var{m} @var{r})
+ (call (mem:@var{fm} @var{addr}) @var{nbytes}))
+@end example
+
+@noindent
+This RTL expression makes it clear (to the optimizer passes) that the
+appropriate register receives a useful value in this insn.
+
+When a subroutine returns a @code{BLKmode} value, it is handled by
+passing to the subroutine the address of a place to store the value.
+So the call insn itself does not ``return'' any value, and it has the
+same RTL form as a call that returns nothing.
+
+On some machines, the call instruction itself clobbers some register,
+for example to contain the return address. @code{call_insn} insns
+on these machines should have a body which is a @code{parallel}
+that contains both the @code{call} expression and @code{clobber}
+expressions that indicate which registers are destroyed. Similarly,
+if the call instruction requires some register other than the stack
+pointer that is not explicitly mentioned it its RTL, a @code{use}
+subexpression should mention that register.
+
+Functions that are called are assumed to modify all registers listed in
+the configuration macro @code{CALL_USED_REGISTERS} (@pxref{Register
+Basics}) and, with the exception of @code{const} functions and library
+calls, to modify all of memory.
+
+Insns containing just @code{use} expressions directly precede the
+@code{call_insn} insn to indicate which registers contain inputs to the
+function. Similarly, if registers other than those in
+@code{CALL_USED_REGISTERS} are clobbered by the called function, insns
+containing a single @code{clobber} follow immediately after the call to
+indicate which registers.
+
+@node Sharing
+@section Structure Sharing Assumptions
+@cindex sharing of RTL components
+@cindex RTL structure sharing assumptions
+
+The compiler assumes that certain kinds of RTL expressions are unique;
+there do not exist two distinct objects representing the same value.
+In other cases, it makes an opposite assumption: that no RTL expression
+object of a certain kind appears in more than one place in the
+containing structure.
+
+These assumptions refer to a single function; except for the RTL
+objects that describe global variables and external functions,
+and a few standard objects such as small integer constants,
+no RTL objects are common to two functions.
+
+@itemize @bullet
+@cindex @code{reg}, RTL sharing
+@item
+Each pseudo-register has only a single @code{reg} object to represent it,
+and therefore only a single machine mode.
+
+@cindex symbolic label
+@cindex @code{symbol_ref}, RTL sharing
+@item
+For any symbolic label, there is only one @code{symbol_ref} object
+referring to it.
+
+@cindex @code{const_int}, RTL sharing
+@item
+There is only one @code{const_int} expression with value 0, only
+one with value 1, and only one with value @minus{}1.
+Some other integer values are also stored uniquely.
+
+@cindex @code{pc}, RTL sharing
+@item
+There is only one @code{pc} expression.
+
+@cindex @code{cc0}, RTL sharing
+@item
+There is only one @code{cc0} expression.
+
+@cindex @code{const_double}, RTL sharing
+@item
+There is only one @code{const_double} expression with value 0 for
+each floating point mode. Likewise for values 1 and 2.
+
+@cindex @code{label_ref}, RTL sharing
+@cindex @code{scratch}, RTL sharing
+@item
+No @code{label_ref} or @code{scratch} appears in more than one place in
+the RTL structure; in other words, it is safe to do a tree-walk of all
+the insns in the function and assume that each time a @code{label_ref}
+or @code{scratch} is seen it is distinct from all others that are seen.
+
+@cindex @code{mem}, RTL sharing
+@item
+Only one @code{mem} object is normally created for each static
+variable or stack slot, so these objects are frequently shared in all
+the places they appear. However, separate but equal objects for these
+variables are occasionally made.
+
+@cindex @code{asm_operands}, RTL sharing
+@item
+When a single @code{asm} statement has multiple output operands, a
+distinct @code{asm_operands} expression is made for each output operand.
+However, these all share the vector which contains the sequence of input
+operands. This sharing is used later on to test whether two
+@code{asm_operands} expressions come from the same statement, so all
+optimizations must carefully preserve the sharing if they copy the
+vector at all.
+
+@item
+No RTL object appears in more than one place in the RTL structure
+except as described above. Many passes of the compiler rely on this
+by assuming that they can modify RTL objects in place without unwanted
+side-effects on other insns.
+
+@findex unshare_all_rtl
+@item
+During initial RTL generation, shared structure is freely introduced.
+After all the RTL for a function has been generated, all shared
+structure is copied by @code{unshare_all_rtl} in @file{emit-rtl.c},
+after which the above rules are guaranteed to be followed.
+
+@findex copy_rtx_if_shared
+@item
+During the combiner pass, shared structure within an insn can exist
+temporarily. However, the shared structure is copied before the
+combiner is finished with the insn. This is done by calling
+@code{copy_rtx_if_shared}, which is a subroutine of
+@code{unshare_all_rtl}.
+@end itemize
+
+@node Reading RTL
+@section Reading RTL
+
+To read an RTL object from a file, call @code{read_rtx}. It takes one
+argument, a stdio stream, and returns a single RTL object.
+
+Reading RTL from a file is very slow. This is no currently not a
+problem because reading RTL occurs only as part of building the
+compiler.
+
+People frequently have the idea of using RTL stored as text in a file as
+an interface between a language front end and the bulk of GNU CC. This
+idea is not feasible.
+
+GNU CC was designed to use RTL internally only. Correct RTL for a given
+program is very dependent on the particular target machine. And the RTL
+does not contain all the information about the program.
+
+The proper way to interface GNU CC to a new language front end is with
+the ``tree'' data structure. There is no manual for this data
+structure, but it is described in the files @file{tree.h} and
+@file{tree.def}.
diff --git a/gnu/usr.bin/cc/doc/templates.texi b/gnu/usr.bin/cc/doc/templates.texi
new file mode 100644
index 0000000..2a6db07
--- /dev/null
+++ b/gnu/usr.bin/cc/doc/templates.texi
@@ -0,0 +1,235 @@
+@node Templates
+@chapter The Template Implementation
+
+@cindex templates
+@cindex function templates
+@cindex class templates
+@cindex parameterized types
+@cindex types, parameterized
+The C++ template@footnote{Class templates are also known as
+@dfn{parameterized types}.} facility, which effectively allows use of
+variables for types in declarations, is one of the newest features of
+the language.
+
+@sc{gnu} C++ is one of the first compilers to implement many
+of the template facilities currently defined by the @sc{ansi} committee.
+
+Nevertheless, the template implementation is not yet complete. This
+chapter maps the current limitations of the @sc{gnu} C++ template
+implementation.
+
+@menu
+* Template limitations:: Limitations for function and class templates
+* Function templates:: Limitations for function templates
+* Class templates:: Limitations for class templates
+* Template debugging:: Debugging information for templates
+@end menu
+
+@node Template limitations
+@section Limitations for function and class templates
+
+@cindex template limitations
+@cindex template bugs
+@cindex bugs, templates
+These limitations apply to any use of templates (function templates or
+class templates) with @sc{gnu} C++:
+
+@table @emph
+@item Template definitions must be visible
+When you compile code with templates, the template definitions must come
+first (before the compiler needs to expand them), and template
+definitions you use must be visible in the current scope.
+@c FIXME! Is this a defined property of templates, rather than a
+@c temporary limitation?
+@c ANSWER: It's a limitation, but it's hard to say why it's a limitation
+@c to someone. We need an infinite link-cycle, in one camp, to
+@c accomplish things so you don't need the template definitions around.
+
+@cindex static data in template classes
+@cindex template classes, static data in
+@item Individual initializers needed for static data
+Templates for static data in template classes do not work. @xref{Class
+templates,,Limitations for class templates}.
+@end table
+
+@node Function templates
+@section Limitations for function templates
+
+@cindex function template limitations
+Function templates are implemented for the most part. The compiler can
+correctly determine template parameter values, and will delay
+instantiation of a function that uses templates until the requisite type
+information is available.
+
+@noindent
+The following limitations remain:
+
+@itemize @bullet
+@cindex template vs declaration, functions
+@cindex declaration vs template, functions
+@cindex function declaration vs template
+@item
+Narrowed specification: function declarations should not prevent
+template expansion. When you declare a function, @sc{gnu} C++
+interprets the declaration as an indication that you will provide a
+definition for that function. Therefore, @sc{gnu} C++ does not use a
+template expansion if there is also an applicable declaration. @sc{gnu}
+C++ only expands the template when there is no such declaration.
+
+The specification in Bjarne Stroustrup's @cite{The C++ Programming
+Language, Second Edition} is narrower, and the @sc{gnu} C++
+implementation is now clearly incorrect. With this new specification, a
+declaration that corresponds to an instantiation of a function template
+only affects whether conversions are needed to use that version of the
+function. It should no longer prevent expansion of the template
+definition.
+
+For example, this code fragment must be treated differently:
+
+@smallexample
+template <class X> X min (X& x1, X& x2) @{ @dots{} @}
+int min (int, int);
+@dots{}
+int i; short s;
+min (i, s); // @r{should call} min(int,int)
+ // @r{derived from template}
+@dots{}
+@end smallexample
+
+@item
+The compiler does not yet understand function signatures where types are
+nested within template parameters. For example, a function like the
+following produces a syntax error on the closing @samp{)} of the
+definition of the function @code{f}:
+
+@smallexample
+template <class T> class A @{ public: T x; class Y @{@}; @};
+template <class X> int f (A<X>::Y y) @{ @dots{} @}
+@end smallexample
+
+@cindex @code{inline} and function templates
+@cindex function templates and @code{inline}
+@item
+If you declare an @code{inline} function using templates, the compiler
+can only inline the code @emph{after} the first time you use
+that function with whatever particular type signature the template
+was instantiated.
+
+Removing this limitation is akin to supporting nested function
+definitions in @sc{gnu} C++; the limitation will probably remain until the
+more general problem of nested functions is solved.
+
+@item
+All the @emph{method} templates (templates for member functions) for a
+class must be visible to the compiler when the class template is
+instantiated.
+@end itemize
+
+@node Class templates
+@section Limitations for class templates
+
+@cindex class template limitations
+@ignore
+FIXME!! Include a comprehensible version of this if someone can explain it.
+ (Queried Brendan and Raeburn w/full orig context, 26may1993---pesch)
+ - [RHP: I don't understand what the following fragment refers to. If it's
+ the "BIG BUG" section in the original, why does it say "overriding class
+ declarations" here when the more detailed text refers to *function*
+ declarations? Here's the fragment I don't understand:]
+ there are problems with user-supplied overriding class declarations (see
+ below).
+@end ignore
+
+@itemize @bullet
+@ignore
+@cindex static data, not working in templates
+@item
+Templates for static data in template classes do not work.
+Currently, you must initialize each case of such data
+individually.
+@c FIXME!! Brendan to see if still true.
+@c ANSWER: This section presumes that it's incorrect to have to
+@c initialize for each type you instantiate with. It's not, it's the
+@c right way to do it.
+@end ignore
+
+Unfortunately, individual initializations of this sort are likely to be
+considered errors eventually; since they're needed now, you might want to
+flag places where you use them with comments to mark the need for a
+future transition.
+
+@cindex nested type results vs templates
+@item
+Member functions in template classes may not have results of nested
+type; @sc{gnu} C++ signals a syntax error on the attempt. The following
+example illustrates this problem with an @code{enum} type @code{alph}:
+
+@smallexample
+template <class T> class list @{
+ @dots{}
+ enum alph @{a,b,c@};
+ alph bar();
+ @dots{}
+@};
+
+template <class T>
+list<int>::alph list<int>::bar() // @i{Syntax error here}
+@{
+@dots{}
+@}
+@end smallexample
+
+@cindex preprocessor conditionals in templates
+@cindex conditionals (preprocessor) in templates
+@item
+A parsing bug makes it difficult to use preprocessor conditionals within
+templates. For example, in this code:
+
+@smallexample
+template <class T>
+class list @{
+ @dots{}
+#ifdef SYSWRONG
+ T x;
+#endif
+ @dots{}
+@}
+@end smallexample
+
+The preprocessor output leaves sourcefile line number information (lines
+like @samp{# 6 "foo.cc"} when it expands the @code{#ifdef} block. These
+lines confuse the compiler while parsing templates, giving a syntax
+error.
+
+If you cannot avoid preprocessor conditionals in templates, you can
+suppress the line number information using the @samp{-P} preprocessor
+option (but this will make debugging more difficult), by compiling the
+affected modules like this:
+
+@smallexample
+g++ -P foo.cc -o foo
+@end smallexample
+
+@cindex parsing errors, templates
+@item
+Parsing errors are reported when templates are first
+@emph{instantiated}---not on the template definition itself. In
+particular, if you do not instantiate a template definition at all, the
+compiler never reports any parsing errors that may be in the template
+definition.
+@end itemize
+
+@node Template debugging
+@section Debugging information for templates
+
+@cindex templates and debugging information
+@cindex debugging information and templates
+Debugging information for templates works for some object code formats,
+but not others. It works for stabs@footnote{Except that insufficient
+debugging information for methods of template classes is generated in
+stabs.} (used primarily in @sc{a.out} object code, but also in the Solaris 2
+version of @sc{elf}), and the @sc{mips} version of @sc{coff} debugging
+format.
+
+@sc{dwarf} support is currently minimal, and requires further
+development.
diff --git a/gnu/usr.bin/cc/doc/tm.texi b/gnu/usr.bin/cc/doc/tm.texi
new file mode 100644
index 0000000..3824d2f
--- /dev/null
+++ b/gnu/usr.bin/cc/doc/tm.texi
@@ -0,0 +1,6337 @@
+@c Copyright (C) 1988, 1989, 1992, 1993, 1994 Free Software Foundation, Inc.
+@c This is part of the GCC manual.
+@c For copying conditions, see the file gcc.texi.
+
+@node Target Macros
+@chapter Target Description Macros
+@cindex machine description macros
+@cindex target description macros
+@cindex macros, target description
+@cindex @file{tm.h} macros
+
+In addition to the file @file{@var{machine}.md}, a machine description
+includes a C header file conventionally given the name
+@file{@var{machine}.h}. This header file defines numerous macros
+that convey the information about the target machine that does not fit
+into the scheme of the @file{.md} file. The file @file{tm.h} should be
+a link to @file{@var{machine}.h}. The header file @file{config.h}
+includes @file{tm.h} and most compiler source files include
+@file{config.h}.
+
+@menu
+* Driver:: Controlling how the driver runs the compilation passes.
+* Run-time Target:: Defining @samp{-m} options like @samp{-m68000} and @samp{-m68020}.
+* Storage Layout:: Defining sizes and alignments of data.
+* Type Layout:: Defining sizes and properties of basic user data types.
+* Registers:: Naming and describing the hardware registers.
+* Register Classes:: Defining the classes of hardware registers.
+* Stack and Calling:: Defining which way the stack grows and by how much.
+* Varargs:: Defining the varargs macros.
+* Trampolines:: Code set up at run time to enter a nested function.
+* Library Calls:: Controlling how library routines are implicitly called.
+* Addressing Modes:: Defining addressing modes valid for memory operands.
+* Condition Code:: Defining how insns update the condition code.
+* Costs:: Defining relative costs of different operations.
+* Sections:: Dividing storage into text, data, and other sections.
+* PIC:: Macros for position independent code.
+* Assembler Format:: Defining how to write insns and pseudo-ops to output.
+* Debugging Info:: Defining the format of debugging output.
+* Cross-compilation:: Handling floating point for cross-compilers.
+* Misc:: Everything else.
+@end menu
+
+@node Driver
+@section Controlling the Compilation Driver, @file{gcc}
+@cindex driver
+@cindex controlling the compilation driver
+
+@c prevent bad page break with this line
+You can control the compilation driver.
+
+@table @code
+@findex SWITCH_TAKES_ARG
+@item SWITCH_TAKES_ARG (@var{char})
+A C expression which determines whether the option @samp{-@var{char}}
+takes arguments. The value should be the number of arguments that
+option takes--zero, for many options.
+
+By default, this macro is defined to handle the standard options
+properly. You need not define it unless you wish to add additional
+options which take arguments.
+
+@findex WORD_SWITCH_TAKES_ARG
+@item WORD_SWITCH_TAKES_ARG (@var{name})
+A C expression which determines whether the option @samp{-@var{name}}
+takes arguments. The value should be the number of arguments that
+option takes--zero, for many options. This macro rather than
+@code{SWITCH_TAKES_ARG} is used for multi-character option names.
+
+By default, this macro is defined as
+@code{DEFAULT_WORD_SWITCH_TAKES_ARG}, which handles the standard options
+properly. You need not define @code{WORD_SWITCH_TAKES_ARG} unless you
+wish to add additional options which take arguments. Any redefinition
+should call @code{DEFAULT_WORD_SWITCH_TAKES_ARG} and then check for
+additional options.
+
+@findex SWITCHES_NEED_SPACES
+@item SWITCHES_NEED_SPACES
+A string-valued C expression which is nonempty if the linker needs a
+space between the @samp{-L} or @samp{-o} option and its argument.
+
+If this macro is not defined, the default value is 0.
+
+@findex CPP_SPEC
+@item CPP_SPEC
+A C string constant that tells the GNU CC driver program options to
+pass to CPP. It can also specify how to translate options you
+give to GNU CC into options for GNU CC to pass to the CPP.
+
+Do not define this macro if it does not need to do anything.
+
+@findex NO_BUILTIN_SIZE_TYPE
+@item NO_BUILTIN_SIZE_TYPE
+If this macro is defined, the preprocessor will not define the builtin macro
+@code{__SIZE_TYPE__}. The macro @code{__SIZE_TYPE__} must then be defined
+by @code{CPP_SPEC} instead.
+
+This should be defined if @code{SIZE_TYPE} depends on target dependent flags
+which are not accessible to the preprocessor. Otherwise, it should not
+be defined.
+
+@findex NO_BUILTIN_PTRDIFF_TYPE
+@item NO_BUILTIN_PTRDIFF_TYPE
+If this macro is defined, the preprocessor will not define the builtin macro
+@code{__PTRDIFF_TYPE__}. The macro @code{__PTRDIFF_TYPE__} must then be
+defined by @code{CPP_SPEC} instead.
+
+This should be defined if @code{PTRDIFF_TYPE} depends on target dependent flags
+which are not accessible to the preprocessor. Otherwise, it should not
+be defined.
+
+@findex SIGNED_CHAR_SPEC
+@item SIGNED_CHAR_SPEC
+A C string constant that tells the GNU CC driver program options to
+pass to CPP. By default, this macro is defined to pass the option
+@samp{-D__CHAR_UNSIGNED__} to CPP if @code{char} will be treated as
+@code{unsigned char} by @code{cc1}.
+
+Do not define this macro unless you need to override the default
+definition.
+
+@findex CC1_SPEC
+@item CC1_SPEC
+A C string constant that tells the GNU CC driver program options to
+pass to @code{cc1}. It can also specify how to translate options you
+give to GNU CC into options for GNU CC to pass to the @code{cc1}.
+
+Do not define this macro if it does not need to do anything.
+
+@findex CC1PLUS_SPEC
+@item CC1PLUS_SPEC
+A C string constant that tells the GNU CC driver program options to
+pass to @code{cc1plus}. It can also specify how to translate options you
+give to GNU CC into options for GNU CC to pass to the @code{cc1plus}.
+
+Do not define this macro if it does not need to do anything.
+
+@findex ASM_SPEC
+@item ASM_SPEC
+A C string constant that tells the GNU CC driver program options to
+pass to the assembler. It can also specify how to translate options
+you give to GNU CC into options for GNU CC to pass to the assembler.
+See the file @file{sun3.h} for an example of this.
+
+Do not define this macro if it does not need to do anything.
+
+@findex ASM_FINAL_SPEC
+@item ASM_FINAL_SPEC
+A C string constant that tells the GNU CC driver program how to
+run any programs which cleanup after the normal assembler.
+Normally, this is not needed. See the file @file{mips.h} for
+an example of this.
+
+Do not define this macro if it does not need to do anything.
+
+@findex LINK_SPEC
+@item LINK_SPEC
+A C string constant that tells the GNU CC driver program options to
+pass to the linker. It can also specify how to translate options you
+give to GNU CC into options for GNU CC to pass to the linker.
+
+Do not define this macro if it does not need to do anything.
+
+@findex LIB_SPEC
+@item LIB_SPEC
+Another C string constant used much like @code{LINK_SPEC}. The difference
+between the two is that @code{LIB_SPEC} is used at the end of the
+command given to the linker.
+
+If this macro is not defined, a default is provided that
+loads the standard C library from the usual place. See @file{gcc.c}.
+
+@findex STARTFILE_SPEC
+@item STARTFILE_SPEC
+Another C string constant used much like @code{LINK_SPEC}. The
+difference between the two is that @code{STARTFILE_SPEC} is used at
+the very beginning of the command given to the linker.
+
+If this macro is not defined, a default is provided that loads the
+standard C startup file from the usual place. See @file{gcc.c}.
+
+@findex ENDFILE_SPEC
+@item ENDFILE_SPEC
+Another C string constant used much like @code{LINK_SPEC}. The
+difference between the two is that @code{ENDFILE_SPEC} is used at
+the very end of the command given to the linker.
+
+Do not define this macro if it does not need to do anything.
+
+@findex LINK_LIBGCC_SPECIAL
+@item LINK_LIBGCC_SPECIAL
+Define this macro meaning that @code{gcc} should find the library
+@file{libgcc.a} by hand, rather than passing the argument @samp{-lgcc}
+to tell the linker to do the search; also, @code{gcc} should not
+generate @samp{-L} options to pass to the linker (as it normally does).
+
+@findex LINK_LIBGCC_SPECIAL_1
+@item LINK_LIBGCC_SPECIAL_1
+Define this macro meaning that @code{gcc} should find the
+library @file{libgcc.a} by hand, rather than passing the argument
+@samp{-lgcc} to tell the linker to do the search.
+
+@findex RELATIVE_PREFIX_NOT_LINKDIR
+@item RELATIVE_PREFIX_NOT_LINKDIR
+Define this macro to tell @code{gcc} that it should only translate
+a @samp{-B} prefix into a @samp{-L} linker option if the prefix
+indicates an absolute file name.
+
+@findex STANDARD_EXEC_PREFIX
+@item STANDARD_EXEC_PREFIX
+Define this macro as a C string constant if you wish to override the
+standard choice of @file{/usr/local/lib/gcc-lib/} as the default prefix to
+try when searching for the executable files of the compiler.
+
+@findex MD_EXEC_PREFIX
+@item MD_EXEC_PREFIX
+If defined, this macro is an additional prefix to try after
+@code{STANDARD_EXEC_PREFIX}. @code{MD_EXEC_PREFIX} is not searched
+when the @samp{-b} option is used, or the compiler is built as a cross
+compiler.
+
+@findex STANDARD_STARTFILE_PREFIX
+@item STANDARD_STARTFILE_PREFIX
+Define this macro as a C string constant if you wish to override the
+standard choice of @file{/usr/local/lib/} as the default prefix to
+try when searching for startup files such as @file{crt0.o}.
+
+@findex MD_STARTFILE_PREFIX
+@item MD_STARTFILE_PREFIX
+If defined, this macro supplies an additional prefix to try after the
+standard prefixes. @code{MD_EXEC_PREFIX} is not searched when the
+@samp{-b} option is used, or when the compiler is built as a cross
+compiler.
+
+@findex MD_STARTFILE_PREFIX_1
+@item MD_STARTFILE_PREFIX_1
+If defined, this macro supplies yet another prefix to try after the
+standard prefixes. It is not searched when the @samp{-b} option is
+used, or when the compiler is built as a cross compiler.
+
+@findex LOCAL_INCLUDE_DIR
+@item LOCAL_INCLUDE_DIR
+Define this macro as a C string constant if you wish to override the
+standard choice of @file{/usr/local/include} as the default prefix to
+try when searching for local header files. @code{LOCAL_INCLUDE_DIR}
+comes before @code{SYSTEM_INCLUDE_DIR} in the search order.
+
+Cross compilers do not use this macro and do not search either
+@file{/usr/local/include} or its replacement.
+
+@findex SYSTEM_INCLUDE_DIR
+@item SYSTEM_INCLUDE_DIR
+Define this macro as a C string constant if you wish to specify a
+system-specific directory to search for header files before the standard
+directory. @code{SYSTEM_INCLUDE_DIR} comes before
+@code{STANDARD_INCLUDE_DIR} in the search order.
+
+Cross compilers do not use this macro and do not search the directory
+specified.
+
+@findex STANDARD_INCLUDE_DIR
+@item STANDARD_INCLUDE_DIR
+Define this macro as a C string constant if you wish to override the
+standard choice of @file{/usr/include} as the default prefix to
+try when searching for header files.
+
+Cross compilers do not use this macro and do not search either
+@file{/usr/include} or its replacement.
+
+@findex INCLUDE_DEFAULTS
+@item INCLUDE_DEFAULTS
+Define this macro if you wish to override the entire default search path
+for include files. The default search path includes
+@code{GCC_INCLUDE_DIR}, @code{LOCAL_INCLUDE_DIR},
+@code{SYSTEM_INCLUDE_DIR}, @code{GPLUSPLUS_INCLUDE_DIR}, and
+@code{STANDARD_INCLUDE_DIR}. In addition, @code{GPLUSPLUS_INCLUDE_DIR}
+and @code{GCC_INCLUDE_DIR} are defined automatically by @file{Makefile},
+and specify private search areas for GCC. The directory
+@code{GPLUSPLUS_INCLUDE_DIR} is used only for C++ programs.
+
+The definition should be an initializer for an array of structures.
+Each array element should have two elements: the directory name (a
+string constant) and a flag for C++-only directories. Mark the end of
+the array with a null element. For example, here is the definition used
+for VMS:
+
+@example
+#define INCLUDE_DEFAULTS \
+@{ \
+ @{ "GNU_GXX_INCLUDE:", 1@}, \
+ @{ "GNU_CC_INCLUDE:", 0@}, \
+ @{ "SYS$SYSROOT:[SYSLIB.]", 0@}, \
+ @{ ".", 0@}, \
+ @{ 0, 0@} \
+@}
+@end example
+@end table
+
+Here is the order of prefixes tried for exec files:
+
+@enumerate
+@item
+Any prefixes specified by the user with @samp{-B}.
+
+@item
+The environment variable @code{GCC_EXEC_PREFIX}, if any.
+
+@item
+The directories specified by the environment variable @code{COMPILER_PATH}.
+
+@item
+The macro @code{STANDARD_EXEC_PREFIX}.
+
+@item
+@file{/usr/lib/gcc/}.
+
+@item
+The macro @code{MD_EXEC_PREFIX}, if any.
+@end enumerate
+
+Here is the order of prefixes tried for startfiles:
+
+@enumerate
+@item
+Any prefixes specified by the user with @samp{-B}.
+
+@item
+The environment variable @code{GCC_EXEC_PREFIX}, if any.
+
+@item
+The directories specified by the environment variable @code{LIBRARY_PATH}.
+
+@item
+The macro @code{STANDARD_EXEC_PREFIX}.
+
+@item
+@file{/usr/lib/gcc/}.
+
+@item
+The macro @code{MD_EXEC_PREFIX}, if any.
+
+@item
+The macro @code{MD_STARTFILE_PREFIX}, if any.
+
+@item
+The macro @code{STANDARD_STARTFILE_PREFIX}.
+
+@item
+@file{/lib/}.
+
+@item
+@file{/usr/lib/}.
+@end enumerate
+
+@node Run-time Target
+@section Run-time Target Specification
+@cindex run-time target specification
+@cindex predefined macros
+@cindex target specifications
+
+@c prevent bad page break with this line
+Here are run-time target specifications.
+
+@table @code
+@findex CPP_PREDEFINES
+@item CPP_PREDEFINES
+Define this to be a string constant containing @samp{-D} options to
+define the predefined macros that identify this machine and system.
+These macros will be predefined unless the @samp{-ansi} option is
+specified.
+
+In addition, a parallel set of macros are predefined, whose names are
+made by appending @samp{__} at the beginning and at the end. These
+@samp{__} macros are permitted by the ANSI standard, so they are
+predefined regardless of whether @samp{-ansi} is specified.
+
+For example, on the Sun, one can use the following value:
+
+@smallexample
+"-Dmc68000 -Dsun -Dunix"
+@end smallexample
+
+The result is to define the macros @code{__mc68000__}, @code{__sun__}
+and @code{__unix__} unconditionally, and the macros @code{mc68000},
+@code{sun} and @code{unix} provided @samp{-ansi} is not specified.
+
+@findex STDC_VALUE
+@item STDC_VALUE
+Define the value to be assigned to the built-in macro @code{__STDC__}.
+The default is the value @samp{1}.
+
+@findex extern int target_flags
+@item extern int target_flags;
+This declaration should be present.
+
+@cindex optional hardware or system features
+@cindex features, optional, in system conventions
+@item TARGET_@dots{}
+This series of macros is to allow compiler command arguments to
+enable or disable the use of optional features of the target machine.
+For example, one machine description serves both the 68000 and
+the 68020; a command argument tells the compiler whether it should
+use 68020-only instructions or not. This command argument works
+by means of a macro @code{TARGET_68020} that tests a bit in
+@code{target_flags}.
+
+Define a macro @code{TARGET_@var{featurename}} for each such option.
+Its definition should test a bit in @code{target_flags}; for example:
+
+@smallexample
+#define TARGET_68020 (target_flags & 1)
+@end smallexample
+
+One place where these macros are used is in the condition-expressions
+of instruction patterns. Note how @code{TARGET_68020} appears
+frequently in the 68000 machine description file, @file{m68k.md}.
+Another place they are used is in the definitions of the other
+macros in the @file{@var{machine}.h} file.
+
+@findex TARGET_SWITCHES
+@item TARGET_SWITCHES
+This macro defines names of command options to set and clear
+bits in @code{target_flags}. Its definition is an initializer
+with a subgrouping for each command option.
+
+Each subgrouping contains a string constant, that defines the option
+name, and a number, which contains the bits to set in
+@code{target_flags}. A negative number says to clear bits instead;
+the negative of the number is which bits to clear. The actual option
+name is made by appending @samp{-m} to the specified name.
+
+One of the subgroupings should have a null string. The number in
+this grouping is the default value for @code{target_flags}. Any
+target options act starting with that value.
+
+Here is an example which defines @samp{-m68000} and @samp{-m68020}
+with opposite meanings, and picks the latter as the default:
+
+@smallexample
+#define TARGET_SWITCHES \
+ @{ @{ "68020", 1@}, \
+ @{ "68000", -1@}, \
+ @{ "", 1@}@}
+@end smallexample
+
+@findex TARGET_OPTIONS
+@item TARGET_OPTIONS
+This macro is similar to @code{TARGET_SWITCHES} but defines names of command
+options that have values. Its definition is an initializer with a
+subgrouping for each command option.
+
+Each subgrouping contains a string constant, that defines the fixed part
+of the option name, and the address of a variable. The variable, type
+@code{char *}, is set to the variable part of the given option if the fixed
+part matches. The actual option name is made by appending @samp{-m} to the
+specified name.
+
+Here is an example which defines @samp{-mshort-data-@var{number}}. If the
+given option is @samp{-mshort-data-512}, the variable @code{m88k_short_data}
+will be set to the string @code{"512"}.
+
+@smallexample
+extern char *m88k_short_data;
+#define TARGET_OPTIONS \
+ @{ @{ "short-data-", &m88k_short_data @} @}
+@end smallexample
+
+@findex TARGET_VERSION
+@item TARGET_VERSION
+This macro is a C statement to print on @code{stderr} a string
+describing the particular machine description choice. Every machine
+description should define @code{TARGET_VERSION}. For example:
+
+@smallexample
+#ifdef MOTOROLA
+#define TARGET_VERSION \
+ fprintf (stderr, " (68k, Motorola syntax)");
+#else
+#define TARGET_VERSION \
+ fprintf (stderr, " (68k, MIT syntax)");
+#endif
+@end smallexample
+
+@findex OVERRIDE_OPTIONS
+@item OVERRIDE_OPTIONS
+Sometimes certain combinations of command options do not make sense on
+a particular target machine. You can define a macro
+@code{OVERRIDE_OPTIONS} to take account of this. This macro, if
+defined, is executed once just after all the command options have been
+parsed.
+
+Don't use this macro to turn on various extra optimizations for
+@samp{-O}. That is what @code{OPTIMIZATION_OPTIONS} is for.
+
+@findex OPTIMIZATION_OPTIONS
+@item OPTIMIZATION_OPTIONS (@var{level})
+Some machines may desire to change what optimizations are performed for
+various optimization levels. This macro, if defined, is executed once
+just after the optimization level is determined and before the remainder
+of the command options have been parsed. Values set in this macro are
+used as the default values for the other command line options.
+
+@var{level} is the optimization level specified; 2 if @samp{-O2} is
+specified, 1 if @samp{-O} is specified, and 0 if neither is specified.
+
+You should not use this macro to change options that are not
+machine-specific. These should uniformly selected by the same
+optimization level on all supported machines. Use this macro to enable
+machbine-specific optimizations.
+
+@strong{Do not examine @code{write_symbols} in
+this macro!} The debugging options are not supposed to alter the
+generated code.
+
+@findex CAN_DEBUG_WITHOUT_FP
+@item CAN_DEBUG_WITHOUT_FP
+Define this macro if debugging can be performed even without a frame
+pointer. If this macro is defined, GNU CC will turn on the
+@samp{-fomit-frame-pointer} option whenever @samp{-O} is specified.
+@end table
+
+@node Storage Layout
+@section Storage Layout
+@cindex storage layout
+
+Note that the definitions of the macros in this table which are sizes or
+alignments measured in bits do not need to be constant. They can be C
+expressions that refer to static variables, such as the @code{target_flags}.
+@xref{Run-time Target}.
+
+@table @code
+@findex BITS_BIG_ENDIAN
+@item BITS_BIG_ENDIAN
+Define this macro to be the value 1 if the most significant bit in a
+byte has the lowest number; otherwise define it to be the value zero.
+This means that bit-field instructions count from the most significant
+bit. If the machine has no bit-field instructions, then this must still
+be defined, but it doesn't matter which value it is defined to.
+
+This macro does not affect the way structure fields are packed into
+bytes or words; that is controlled by @code{BYTES_BIG_ENDIAN}.
+
+@findex BYTES_BIG_ENDIAN
+@item BYTES_BIG_ENDIAN
+Define this macro to be 1 if the most significant byte in a word has the
+lowest number.
+
+@findex WORDS_BIG_ENDIAN
+@item WORDS_BIG_ENDIAN
+Define this macro to be 1 if, in a multiword object, the most
+significant word has the lowest number. This applies to both memory
+locations and registers; GNU CC fundamentally assumes that the order of
+words in memory is the same as the order in registers.
+
+@findex FLOAT_WORDS_BIG_ENDIAN
+@item FLOAT_WORDS_BIG_ENDIAN
+Define this macro to be 1 if @code{DFmode}, @code{XFmode} or
+@code{TFmode} floating point numbers are stored in memory with the word
+containing the sign bit at the lowest address; otherwise define it to be
+0.
+
+You need not define this macro if the ordering is the same as for
+multi-word integers.
+
+@findex BITS_PER_UNIT
+@item BITS_PER_UNIT
+Define this macro to be the number of bits in an addressable storage
+unit (byte); normally 8.
+
+@findex BITS_PER_WORD
+@item BITS_PER_WORD
+Number of bits in a word; normally 32.
+
+@findex MAX_BITS_PER_WORD
+@item MAX_BITS_PER_WORD
+Maximum number of bits in a word. If this is undefined, the default is
+@code{BITS_PER_WORD}. Otherwise, it is the constant value that is the
+largest value that @code{BITS_PER_WORD} can have at run-time.
+
+@findex UNITS_PER_WORD
+@item UNITS_PER_WORD
+Number of storage units in a word; normally 4.
+
+@findex MAX_UNITS_PER_WORD
+@item MAX_UNITS_PER_WORD
+Maximum number of units in a word. If this is undefined, the default is
+@code{UNITS_PER_WORD}. Otherwise, it is the constant value that is the
+largest value that @code{UNITS_PER_WORD} can have at run-time.
+
+@findex POINTER_SIZE
+@item POINTER_SIZE
+Width of a pointer, in bits.
+
+@findex PROMOTE_MODE
+@item PROMOTE_MODE (@var{m}, @var{unsignedp}, @var{type})
+A macro to update @var{m} and @var{unsignedp} when an object whose type
+is @var{type} and which has the specified mode and signedness is to be
+stored in a register. This macro is only called when @var{type} is a
+scalar type.
+
+On most RISC machines, which only have operations that operate on a full
+register, define this macro to set @var{m} to @code{word_mode} if
+@var{m} is an integer mode narrower than @code{BITS_PER_WORD}. In most
+cases, only integer modes should be widened because wider-precision
+floating-point operations are usually more expensive than their narrower
+counterparts.
+
+For most machines, the macro definition does not change @var{unsignedp}.
+However, some machines, have instructions that preferentially handle
+either signed or unsigned quantities of certain modes. For example, on
+the DEC Alpha, 32-bit loads from memory and 32-bit add instructions
+sign-extend the result to 64 bits. On such machines, set
+@var{unsignedp} according to which kind of extension is more efficient.
+
+Do not define this macro if it would never modify @var{m}.
+
+@findex PROMOTE_FUNCTION_ARGS
+@item PROMOTE_FUNCTION_ARGS
+Define this macro if the promotion described by @code{PROMOTE_MODE}
+should also be done for outgoing function arguments.
+
+@findex PROMOTE_FUNCTION_RETURN
+@item PROMOTE_FUNCTION_RETURN
+Define this macro if the promotion described by @code{PROMOTE_MODE}
+should also be done for the return value of functions.
+
+If this macro is defined, @code{FUNCTION_VALUE} must perform the same
+promotions done by @code{PROMOTE_MODE}.
+
+@findex PROMOTE_FOR_CALL_ONLY
+@item PROMOTE_FOR_CALL_ONLY
+Define this macro if the promotion described by @code{PROMOTE_MODE}
+should @emph{only} be performed for outgoing function arguments or
+function return values, as specified by @code{PROMOTE_FUNCTION_ARGS}
+and @code{PROMOTE_FUNCTION_RETURN}, respectively.
+
+@findex PARM_BOUNDARY
+@item PARM_BOUNDARY
+Normal alignment required for function parameters on the stack, in
+bits. All stack parameters receive at least this much alignment
+regardless of data type. On most machines, this is the same as the
+size of an integer.
+
+@findex STACK_BOUNDARY
+@item STACK_BOUNDARY
+Define this macro if you wish to preserve a certain alignment for
+the stack pointer. The definition is a C expression
+for the desired alignment (measured in bits).
+
+@cindex @code{PUSH_ROUNDING}, interaction with @code{STACK_BOUNDARY}
+If @code{PUSH_ROUNDING} is not defined, the stack will always be aligned
+to the specified boundary. If @code{PUSH_ROUNDING} is defined and specifies a
+less strict alignment than @code{STACK_BOUNDARY}, the stack may be
+momentarily unaligned while pushing arguments.
+
+@findex FUNCTION_BOUNDARY
+@item FUNCTION_BOUNDARY
+Alignment required for a function entry point, in bits.
+
+@findex BIGGEST_ALIGNMENT
+@item BIGGEST_ALIGNMENT
+Biggest alignment that any data type can require on this machine, in bits.
+
+@findex BIGGEST_FIELD_ALIGNMENT
+@item BIGGEST_FIELD_ALIGNMENT
+Biggest alignment that any structure field can require on this machine,
+in bits. If defined, this overrides @code{BIGGEST_ALIGNMENT} for
+structure fields only.
+
+@findex MAX_OFILE_ALIGNMENT
+@item MAX_OFILE_ALIGNMENT
+Biggest alignment supported by the object file format of this machine.
+Use this macro to limit the alignment which can be specified using the
+@code{__attribute__ ((aligned (@var{n})))} construct. If not defined,
+the default value is @code{BIGGEST_ALIGNMENT}.
+
+@findex DATA_ALIGNMENT
+@item DATA_ALIGNMENT (@var{type}, @var{basic-align})
+If defined, a C expression to compute the alignment for a static
+variable. @var{type} is the data type, and @var{basic-align} is the
+alignment that the object would ordinarily have. The value of this
+macro is used instead of that alignment to align the object.
+
+If this macro is not defined, then @var{basic-align} is used.
+
+@findex strcpy
+One use of this macro is to increase alignment of medium-size data to
+make it all fit in fewer cache lines. Another is to cause character
+arrays to be word-aligned so that @code{strcpy} calls that copy
+constants to character arrays can be done inline.
+
+@findex CONSTANT_ALIGNMENT
+@item CONSTANT_ALIGNMENT (@var{constant}, @var{basic-align})
+If defined, a C expression to compute the alignment given to a constant
+that is being placed in memory. @var{constant} is the constant and
+@var{basic-align} is the alignment that the object would ordinarily
+have. The value of this macro is used instead of that alignment to
+align the object.
+
+If this macro is not defined, then @var{basic-align} is used.
+
+The typical use of this macro is to increase alignment for string
+constants to be word aligned so that @code{strcpy} calls that copy
+constants can be done inline.
+
+@findex EMPTY_FIELD_BOUNDARY
+@item EMPTY_FIELD_BOUNDARY
+Alignment in bits to be given to a structure bit field that follows an
+empty field such as @code{int : 0;}.
+
+Note that @code{PCC_BITFIELD_TYPE_MATTERS} also affects the alignment
+that results from an empty field.
+
+@findex STRUCTURE_SIZE_BOUNDARY
+@item STRUCTURE_SIZE_BOUNDARY
+Number of bits which any structure or union's size must be a multiple of.
+Each structure or union's size is rounded up to a multiple of this.
+
+If you do not define this macro, the default is the same as
+@code{BITS_PER_UNIT}.
+
+@findex STRICT_ALIGNMENT
+@item STRICT_ALIGNMENT
+Define this macro to be the value 1 if instructions will fail to work
+if given data not on the nominal alignment. If instructions will merely
+go slower in that case, define this macro as 0.
+
+@findex PCC_BITFIELD_TYPE_MATTERS
+@item PCC_BITFIELD_TYPE_MATTERS
+Define this if you wish to imitate the way many other C compilers handle
+alignment of bitfields and the structures that contain them.
+
+The behavior is that the type written for a bitfield (@code{int},
+@code{short}, or other integer type) imposes an alignment for the
+entire structure, as if the structure really did contain an ordinary
+field of that type. In addition, the bitfield is placed within the
+structure so that it would fit within such a field, not crossing a
+boundary for it.
+
+Thus, on most machines, a bitfield whose type is written as @code{int}
+would not cross a four-byte boundary, and would force four-byte
+alignment for the whole structure. (The alignment used may not be four
+bytes; it is controlled by the other alignment parameters.)
+
+If the macro is defined, its definition should be a C expression;
+a nonzero value for the expression enables this behavior.
+
+Note that if this macro is not defined, or its value is zero, some
+bitfields may cross more than one alignment boundary. The compiler can
+support such references if there are @samp{insv}, @samp{extv}, and
+@samp{extzv} insns that can directly reference memory.
+
+The other known way of making bitfields work is to define
+@code{STRUCTURE_SIZE_BOUNDARY} as large as @code{BIGGEST_ALIGNMENT}.
+Then every structure can be accessed with fullwords.
+
+Unless the machine has bitfield instructions or you define
+@code{STRUCTURE_SIZE_BOUNDARY} that way, you must define
+@code{PCC_BITFIELD_TYPE_MATTERS} to have a nonzero value.
+
+If your aim is to make GNU CC use the same conventions for laying out
+bitfields as are used by another compiler, here is how to investigate
+what the other compiler does. Compile and run this program:
+
+@example
+struct foo1
+@{
+ char x;
+ char :0;
+ char y;
+@};
+
+struct foo2
+@{
+ char x;
+ int :0;
+ char y;
+@};
+
+main ()
+@{
+ printf ("Size of foo1 is %d\n",
+ sizeof (struct foo1));
+ printf ("Size of foo2 is %d\n",
+ sizeof (struct foo2));
+ exit (0);
+@}
+@end example
+
+If this prints 2 and 5, then the compiler's behavior is what you would
+get from @code{PCC_BITFIELD_TYPE_MATTERS}.
+
+@findex BITFIELD_NBYTES_LIMITED
+@item BITFIELD_NBYTES_LIMITED
+Like PCC_BITFIELD_TYPE_MATTERS except that its effect is limited to
+aligning a bitfield within the structure.
+
+@findex ROUND_TYPE_SIZE
+@item ROUND_TYPE_SIZE (@var{struct}, @var{size}, @var{align})
+Define this macro as an expression for the overall size of a structure
+(given by @var{struct} as a tree node) when the size computed from the
+fields is @var{size} and the alignment is @var{align}.
+
+The default is to round @var{size} up to a multiple of @var{align}.
+
+@findex ROUND_TYPE_ALIGN
+@item ROUND_TYPE_ALIGN (@var{struct}, @var{computed}, @var{specified})
+Define this macro as an expression for the alignment of a structure
+(given by @var{struct} as a tree node) if the alignment computed in the
+usual way is @var{computed} and the alignment explicitly specified was
+@var{specified}.
+
+The default is to use @var{specified} if it is larger; otherwise, use
+the smaller of @var{computed} and @code{BIGGEST_ALIGNMENT}
+
+@findex MAX_FIXED_MODE_SIZE
+@item MAX_FIXED_MODE_SIZE
+An integer expression for the size in bits of the largest integer
+machine mode that should actually be used. All integer machine modes of
+this size or smaller can be used for structures and unions with the
+appropriate sizes. If this macro is undefined, @code{GET_MODE_BITSIZE
+(DImode)} is assumed.
+
+@findex CHECK_FLOAT_VALUE
+@item CHECK_FLOAT_VALUE (@var{mode}, @var{value}, @var{overflow})
+A C statement to validate the value @var{value} (of type
+@code{double}) for mode @var{mode}. This means that you check whether
+@var{value} fits within the possible range of values for mode
+@var{mode} on this target machine. The mode @var{mode} is always
+a mode of class @code{MODE_FLOAT}. @var{overflow} is nonzero if
+the value is already known to be out of range.
+
+If @var{value} is not valid or if @var{overflow} is nonzero, you should
+set @var{overflow} to 1 and then assign some valid value to @var{value}.
+Allowing an invalid value to go through the compiler can produce
+incorrect assembler code which may even cause Unix assemblers to crash.
+
+This macro need not be defined if there is no work for it to do.
+
+@findex TARGET_FLOAT_FORMAT
+@item TARGET_FLOAT_FORMAT
+A code distinguishing the floating point format of the target machine.
+There are three defined values:
+
+@table @code
+@findex IEEE_FLOAT_FORMAT
+@item IEEE_FLOAT_FORMAT
+This code indicates IEEE floating point. It is the default; there is no
+need to define this macro when the format is IEEE.
+
+@findex VAX_FLOAT_FORMAT
+@item VAX_FLOAT_FORMAT
+This code indicates the peculiar format used on the Vax.
+
+@findex UNKNOWN_FLOAT_FORMAT
+@item UNKNOWN_FLOAT_FORMAT
+This code indicates any other format.
+@end table
+
+The value of this macro is compared with @code{HOST_FLOAT_FORMAT}
+(@pxref{Config}) to determine whether the target machine has the same
+format as the host machine. If any other formats are actually in use on
+supported machines, new codes should be defined for them.
+
+The ordering of the component words of floating point values stored in
+memory is controlled by @code{FLOAT_WORDS_BIG_ENDIAN} for the target
+machine and @code{HOST_FLOAT_WORDS_BIG_ENDIAN} for the host.
+@end table
+
+@node Type Layout
+@section Layout of Source Language Data Types
+
+These macros define the sizes and other characteristics of the standard
+basic data types used in programs being compiled. Unlike the macros in
+the previous section, these apply to specific features of C and related
+languages, rather than to fundamental aspects of storage layout.
+
+@table @code
+@findex INT_TYPE_SIZE
+@item INT_TYPE_SIZE
+A C expression for the size in bits of the type @code{int} on the
+target machine. If you don't define this, the default is one word.
+
+@findex MAX_INT_TYPE_SIZE
+@item MAX_INT_TYPE_SIZE
+Maximum number for the size in bits of the type @code{int} on the target
+machine. If this is undefined, the default is @code{INT_TYPE_SIZE}.
+Otherwise, it is the constant value that is the largest value that
+@code{INT_TYPE_SIZE} can have at run-time. This is used in @code{cpp}.
+
+@findex SHORT_TYPE_SIZE
+@item SHORT_TYPE_SIZE
+A C expression for the size in bits of the type @code{short} on the
+target machine. If you don't define this, the default is half a word.
+(If this would be less than one storage unit, it is rounded up to one
+unit.)
+
+@findex LONG_TYPE_SIZE
+@item LONG_TYPE_SIZE
+A C expression for the size in bits of the type @code{long} on the
+target machine. If you don't define this, the default is one word.
+
+@findex MAX_LONG_TYPE_SIZE
+@item MAX_LONG_TYPE_SIZE
+Maximum number for the size in bits of the type @code{long} on the
+target machine. If this is undefined, the default is
+@code{LONG_TYPE_SIZE}. Otherwise, it is the constant value that is the
+largest value that @code{LONG_TYPE_SIZE} can have at run-time. This is
+used in @code{cpp}.
+
+@findex LONG_LONG_TYPE_SIZE
+@item LONG_LONG_TYPE_SIZE
+A C expression for the size in bits of the type @code{long long} on the
+target machine. If you don't define this, the default is two
+words.
+
+@findex CHAR_TYPE_SIZE
+@item CHAR_TYPE_SIZE
+A C expression for the size in bits of the type @code{char} on the
+target machine. If you don't define this, the default is one quarter
+of a word. (If this would be less than one storage unit, it is rounded up
+to one unit.)
+
+@findex MAX_CHAR_TYPE_SIZE
+@item MAX_CHAR_TYPE_SIZE
+Maximum number for the size in bits of the type @code{char} on the
+target machine. If this is undefined, the default is
+@code{CHAR_TYPE_SIZE}. Otherwise, it is the constant value that is the
+largest value that @code{CHAR_TYPE_SIZE} can have at run-time. This is
+used in @code{cpp}.
+
+@findex FLOAT_TYPE_SIZE
+@item FLOAT_TYPE_SIZE
+A C expression for the size in bits of the type @code{float} on the
+target machine. If you don't define this, the default is one word.
+
+@findex DOUBLE_TYPE_SIZE
+@item DOUBLE_TYPE_SIZE
+A C expression for the size in bits of the type @code{double} on the
+target machine. If you don't define this, the default is two
+words.
+
+@findex LONG_DOUBLE_TYPE_SIZE
+@item LONG_DOUBLE_TYPE_SIZE
+A C expression for the size in bits of the type @code{long double} on
+the target machine. If you don't define this, the default is two
+words.
+
+@findex DEFAULT_SIGNED_CHAR
+@item DEFAULT_SIGNED_CHAR
+An expression whose value is 1 or 0, according to whether the type
+@code{char} should be signed or unsigned by default. The user can
+always override this default with the options @samp{-fsigned-char}
+and @samp{-funsigned-char}.
+
+@findex DEFAULT_SHORT_ENUMS
+@item DEFAULT_SHORT_ENUMS
+A C expression to determine whether to give an @code{enum} type
+only as many bytes as it takes to represent the range of possible values
+of that type. A nonzero value means to do that; a zero value means all
+@code{enum} types should be allocated like @code{int}.
+
+If you don't define the macro, the default is 0.
+
+@findex SIZE_TYPE
+@item SIZE_TYPE
+A C expression for a string describing the name of the data type to use
+for size values. The typedef name @code{size_t} is defined using the
+contents of the string.
+
+The string can contain more than one keyword. If so, separate them with
+spaces, and write first any length keyword, then @code{unsigned} if
+appropriate, and finally @code{int}. The string must exactly match one
+of the data type names defined in the function
+@code{init_decl_processing} in the file @file{c-decl.c}. You may not
+omit @code{int} or change the order---that would cause the compiler to
+crash on startup.
+
+If you don't define this macro, the default is @code{"long unsigned
+int"}.
+
+@findex PTRDIFF_TYPE
+@item PTRDIFF_TYPE
+A C expression for a string describing the name of the data type to use
+for the result of subtracting two pointers. The typedef name
+@code{ptrdiff_t} is defined using the contents of the string. See
+@code{SIZE_TYPE} above for more information.
+
+If you don't define this macro, the default is @code{"long int"}.
+
+@findex WCHAR_TYPE
+@item WCHAR_TYPE
+A C expression for a string describing the name of the data type to use
+for wide characters. The typedef name @code{wchar_t} is defined using
+the contents of the string. See @code{SIZE_TYPE} above for more
+information.
+
+If you don't define this macro, the default is @code{"int"}.
+
+@findex WCHAR_TYPE_SIZE
+@item WCHAR_TYPE_SIZE
+A C expression for the size in bits of the data type for wide
+characters. This is used in @code{cpp}, which cannot make use of
+@code{WCHAR_TYPE}.
+
+@findex MAX_WCHAR_TYPE_SIZE
+@item MAX_WCHAR_TYPE_SIZE
+Maximum number for the size in bits of the data type for wide
+characters. If this is undefined, the default is
+@code{WCHAR_TYPE_SIZE}. Otherwise, it is the constant value that is the
+largest value that @code{WCHAR_TYPE_SIZE} can have at run-time. This is
+used in @code{cpp}.
+
+@findex OBJC_INT_SELECTORS
+@item OBJC_INT_SELECTORS
+Define this macro if the type of Objective C selectors should be
+@code{int}.
+
+If this macro is not defined, then selectors should have the type
+@code{struct objc_selector *}.
+
+@findex OBJC_SELECTORS_WITHOUT_LABELS
+@item OBJC_SELECTORS_WITHOUT_LABELS
+Define this macro if the compiler can group all the selectors together
+into a vector and use just one label at the beginning of the vector.
+Otherwise, the compiler must give each selector its own assembler
+label.
+
+On certain machines, it is important to have a separate label for each
+selector because this enables the linker to eliminate duplicate selectors.
+
+@findex TARGET_BELL
+@item TARGET_BELL
+A C constant expression for the integer value for escape sequence
+@samp{\a}.
+
+@findex TARGET_TAB
+@findex TARGET_BS
+@findex TARGET_NEWLINE
+@item TARGET_BS
+@itemx TARGET_TAB
+@itemx TARGET_NEWLINE
+C constant expressions for the integer values for escape sequences
+@samp{\b}, @samp{\t} and @samp{\n}.
+
+@findex TARGET_VT
+@findex TARGET_FF
+@findex TARGET_CR
+@item TARGET_VT
+@itemx TARGET_FF
+@itemx TARGET_CR
+C constant expressions for the integer values for escape sequences
+@samp{\v}, @samp{\f} and @samp{\r}.
+@end table
+
+@node Registers
+@section Register Usage
+@cindex register usage
+
+This section explains how to describe what registers the target machine
+has, and how (in general) they can be used.
+
+The description of which registers a specific instruction can use is
+done with register classes; see @ref{Register Classes}. For information
+on using registers to access a stack frame, see @ref{Frame Registers}.
+For passing values in registers, see @ref{Register Arguments}.
+For returning values in registers, see @ref{Scalar Return}.
+
+@menu
+* Register Basics:: Number and kinds of registers.
+* Allocation Order:: Order in which registers are allocated.
+* Values in Registers:: What kinds of values each reg can hold.
+* Leaf Functions:: Renumbering registers for leaf functions.
+* Stack Registers:: Handling a register stack such as 80387.
+* Obsolete Register Macros:: Macros formerly used for the 80387.
+@end menu
+
+@node Register Basics
+@subsection Basic Characteristics of Registers
+
+@c prevent bad page break with this line
+Registers have various characteristics.
+
+@table @code
+@findex FIRST_PSEUDO_REGISTER
+@item FIRST_PSEUDO_REGISTER
+Number of hardware registers known to the compiler. They receive
+numbers 0 through @code{FIRST_PSEUDO_REGISTER-1}; thus, the first
+pseudo register's number really is assigned the number
+@code{FIRST_PSEUDO_REGISTER}.
+
+@item FIXED_REGISTERS
+@findex FIXED_REGISTERS
+@cindex fixed register
+An initializer that says which registers are used for fixed purposes
+all throughout the compiled code and are therefore not available for
+general allocation. These would include the stack pointer, the frame
+pointer (except on machines where that can be used as a general
+register when no frame pointer is needed), the program counter on
+machines where that is considered one of the addressable registers,
+and any other numbered register with a standard use.
+
+This information is expressed as a sequence of numbers, separated by
+commas and surrounded by braces. The @var{n}th number is 1 if
+register @var{n} is fixed, 0 otherwise.
+
+The table initialized from this macro, and the table initialized by
+the following one, may be overridden at run time either automatically,
+by the actions of the macro @code{CONDITIONAL_REGISTER_USAGE}, or by
+the user with the command options @samp{-ffixed-@var{reg}},
+@samp{-fcall-used-@var{reg}} and @samp{-fcall-saved-@var{reg}}.
+
+@findex CALL_USED_REGISTERS
+@item CALL_USED_REGISTERS
+@cindex call-used register
+@cindex call-clobbered register
+@cindex call-saved register
+Like @code{FIXED_REGISTERS} but has 1 for each register that is
+clobbered (in general) by function calls as well as for fixed
+registers. This macro therefore identifies the registers that are not
+available for general allocation of values that must live across
+function calls.
+
+If a register has 0 in @code{CALL_USED_REGISTERS}, the compiler
+automatically saves it on function entry and restores it on function
+exit, if the register is used within the function.
+
+@findex CONDITIONAL_REGISTER_USAGE
+@findex fixed_regs
+@findex call_used_regs
+@item CONDITIONAL_REGISTER_USAGE
+Zero or more C statements that may conditionally modify two variables
+@code{fixed_regs} and @code{call_used_regs} (both of type @code{char
+[]}) after they have been initialized from the two preceding macros.
+
+This is necessary in case the fixed or call-clobbered registers depend
+on target flags.
+
+You need not define this macro if it has no work to do.
+
+@cindex disabling certain registers
+@cindex controlling register usage
+If the usage of an entire class of registers depends on the target
+flags, you may indicate this to GCC by using this macro to modify
+@code{fixed_regs} and @code{call_used_regs} to 1 for each of the
+registers in the classes which should not be used by GCC. Also define
+the macro @code{REG_CLASS_FROM_LETTER} to return @code{NO_REGS} if it
+is called with a letter for a class that shouldn't be used.
+
+(However, if this class is not included in @code{GENERAL_REGS} and all
+of the insn patterns whose constraints permit this class are
+controlled by target switches, then GCC will automatically avoid using
+these registers when the target switches are opposed to them.)
+
+@findex NON_SAVING_SETJMP
+@item NON_SAVING_SETJMP
+If this macro is defined and has a nonzero value, it means that
+@code{setjmp} and related functions fail to save the registers, or that
+@code{longjmp} fails to restore them. To compensate, the compiler
+avoids putting variables in registers in functions that use
+@code{setjmp}.
+
+@findex INCOMING_REGNO
+@item INCOMING_REGNO (@var{out})
+Define this macro if the target machine has register windows. This C
+expression returns the register number as seen by the called function
+corresponding to the register number @var{out} as seen by the calling
+function. Return @var{out} if register number @var{out} is not an
+outbound register.
+
+@findex OUTGOING_REGNO
+@item OUTGOING_REGNO (@var{in})
+Define this macro if the target machine has register windows. This C
+expression returns the register number as seen by the calling function
+corresponding to the register number @var{in} as seen by the called
+function. Return @var{in} if register number @var{in} is not an inbound
+register.
+
+@ignore
+@findex PC_REGNUM
+@item PC_REGNUM
+If the program counter has a register number, define this as that
+register number. Otherwise, do not define it.
+@end ignore
+@end table
+
+@node Allocation Order
+@subsection Order of Allocation of Registers
+@cindex order of register allocation
+@cindex register allocation order
+
+@c prevent bad page break with this line
+Registers are allocated in order.
+
+@table @code
+@findex REG_ALLOC_ORDER
+@item REG_ALLOC_ORDER
+If defined, an initializer for a vector of integers, containing the
+numbers of hard registers in the order in which GNU CC should prefer
+to use them (from most preferred to least).
+
+If this macro is not defined, registers are used lowest numbered first
+(all else being equal).
+
+One use of this macro is on machines where the highest numbered
+registers must always be saved and the save-multiple-registers
+instruction supports only sequences of consecutive registers. On such
+machines, define @code{REG_ALLOC_ORDER} to be an initializer that lists
+the highest numbered allocatable register first.
+
+@findex ORDER_REGS_FOR_LOCAL_ALLOC
+@item ORDER_REGS_FOR_LOCAL_ALLOC
+A C statement (sans semicolon) to choose the order in which to allocate
+hard registers for pseudo-registers local to a basic block.
+
+Store the desired register order in the array @code{reg_alloc_order}.
+Element 0 should be the register to allocate first; element 1, the next
+register; and so on.
+
+The macro body should not assume anything about the contents of
+@code{reg_alloc_order} before execution of the macro.
+
+On most machines, it is not necessary to define this macro.
+@end table
+
+@node Values in Registers
+@subsection How Values Fit in Registers
+
+This section discusses the macros that describe which kinds of values
+(specifically, which machine modes) each register can hold, and how many
+consecutive registers are needed for a given mode.
+
+@table @code
+@findex HARD_REGNO_NREGS
+@item HARD_REGNO_NREGS (@var{regno}, @var{mode})
+A C expression for the number of consecutive hard registers, starting
+at register number @var{regno}, required to hold a value of mode
+@var{mode}.
+
+On a machine where all registers are exactly one word, a suitable
+definition of this macro is
+
+@smallexample
+#define HARD_REGNO_NREGS(REGNO, MODE) \
+ ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) \
+ / UNITS_PER_WORD))
+@end smallexample
+
+@findex HARD_REGNO_MODE_OK
+@item HARD_REGNO_MODE_OK (@var{regno}, @var{mode})
+A C expression that is nonzero if it is permissible to store a value
+of mode @var{mode} in hard register number @var{regno} (or in several
+registers starting with that one). For a machine where all registers
+are equivalent, a suitable definition is
+
+@smallexample
+#define HARD_REGNO_MODE_OK(REGNO, MODE) 1
+@end smallexample
+
+It is not necessary for this macro to check for the numbers of fixed
+registers, because the allocation mechanism considers them to be always
+occupied.
+
+@cindex register pairs
+On some machines, double-precision values must be kept in even/odd
+register pairs. The way to implement that is to define this macro
+to reject odd register numbers for such modes.
+
+@ignore
+@c I think this is not true now
+GNU CC assumes that it can always move values between registers and
+(suitably addressed) memory locations. If it is impossible to move a
+value of a certain mode between memory and certain registers, then
+@code{HARD_REGNO_MODE_OK} must not allow this mode in those registers.
+@end ignore
+
+The minimum requirement for a mode to be OK in a register is that the
+@samp{mov@var{mode}} instruction pattern support moves between the
+register and any other hard register for which the mode is OK; and that
+moving a value into the register and back out not alter it.
+
+Since the same instruction used to move @code{SImode} will work for all
+narrower integer modes, it is not necessary on any machine for
+@code{HARD_REGNO_MODE_OK} to distinguish between these modes, provided
+you define patterns @samp{movhi}, etc., to take advantage of this. This
+is useful because of the interaction between @code{HARD_REGNO_MODE_OK}
+and @code{MODES_TIEABLE_P}; it is very desirable for all integer modes
+to be tieable.
+
+Many machines have special registers for floating point arithmetic.
+Often people assume that floating point machine modes are allowed only
+in floating point registers. This is not true. Any registers that
+can hold integers can safely @emph{hold} a floating point machine
+mode, whether or not floating arithmetic can be done on it in those
+registers. Integer move instructions can be used to move the values.
+
+On some machines, though, the converse is true: fixed-point machine
+modes may not go in floating registers. This is true if the floating
+registers normalize any value stored in them, because storing a
+non-floating value there would garble it. In this case,
+@code{HARD_REGNO_MODE_OK} should reject fixed-point machine modes in
+floating registers. But if the floating registers do not automatically
+normalize, if you can store any bit pattern in one and retrieve it
+unchanged without a trap, then any machine mode may go in a floating
+register, so you can define this macro to say so.
+
+The primary significance of special floating registers is rather that
+they are the registers acceptable in floating point arithmetic
+instructions. However, this is of no concern to
+@code{HARD_REGNO_MODE_OK}. You handle it by writing the proper
+constraints for those instructions.
+
+On some machines, the floating registers are especially slow to access,
+so that it is better to store a value in a stack frame than in such a
+register if floating point arithmetic is not being done. As long as the
+floating registers are not in class @code{GENERAL_REGS}, they will not
+be used unless some pattern's constraint asks for one.
+
+@findex MODES_TIEABLE_P
+@item MODES_TIEABLE_P (@var{mode1}, @var{mode2})
+A C expression that is nonzero if it is desirable to choose register
+allocation so as to avoid move instructions between a value of mode
+@var{mode1} and a value of mode @var{mode2}.
+
+If @code{HARD_REGNO_MODE_OK (@var{r}, @var{mode1})} and
+@code{HARD_REGNO_MODE_OK (@var{r}, @var{mode2})} are ever different
+for any @var{r}, then @code{MODES_TIEABLE_P (@var{mode1},
+@var{mode2})} must be zero.
+@end table
+
+@node Leaf Functions
+@subsection Handling Leaf Functions
+
+@cindex leaf functions
+@cindex functions, leaf
+On some machines, a leaf function (i.e., one which makes no calls) can run
+more efficiently if it does not make its own register window. Often this
+means it is required to receive its arguments in the registers where they
+are passed by the caller, instead of the registers where they would
+normally arrive.
+
+The special treatment for leaf functions generally applies only when
+other conditions are met; for example, often they may use only those
+registers for its own variables and temporaries. We use the term ``leaf
+function'' to mean a function that is suitable for this special
+handling, so that functions with no calls are not necessarily ``leaf
+functions''.
+
+GNU CC assigns register numbers before it knows whether the function is
+suitable for leaf function treatment. So it needs to renumber the
+registers in order to output a leaf function. The following macros
+accomplish this.
+
+@table @code
+@findex LEAF_REGISTERS
+@item LEAF_REGISTERS
+A C initializer for a vector, indexed by hard register number, which
+contains 1 for a register that is allowable in a candidate for leaf
+function treatment.
+
+If leaf function treatment involves renumbering the registers, then the
+registers marked here should be the ones before renumbering---those that
+GNU CC would ordinarily allocate. The registers which will actually be
+used in the assembler code, after renumbering, should not be marked with 1
+in this vector.
+
+Define this macro only if the target machine offers a way to optimize
+the treatment of leaf functions.
+
+@findex LEAF_REG_REMAP
+@item LEAF_REG_REMAP (@var{regno})
+A C expression whose value is the register number to which @var{regno}
+should be renumbered, when a function is treated as a leaf function.
+
+If @var{regno} is a register number which should not appear in a leaf
+function before renumbering, then the expression should yield -1, which
+will cause the compiler to abort.
+
+Define this macro only if the target machine offers a way to optimize the
+treatment of leaf functions, and registers need to be renumbered to do
+this.
+@end table
+
+@findex leaf_function
+Normally, @code{FUNCTION_PROLOGUE} and @code{FUNCTION_EPILOGUE} must
+treat leaf functions specially. It can test the C variable
+@code{leaf_function} which is nonzero for leaf functions. (The variable
+@code{leaf_function} is defined only if @code{LEAF_REGISTERS} is
+defined.)
+@c changed this to fix overfull. ALSO: why the "it" at the beginning
+@c of the next paragraph?! --mew 2feb93
+
+@node Stack Registers
+@subsection Registers That Form a Stack
+
+There are special features to handle computers where some of the
+``registers'' form a stack, as in the 80387 coprocessor for the 80386.
+Stack registers are normally written by pushing onto the stack, and are
+numbered relative to the top of the stack.
+
+Currently, GNU CC can only handle one group of stack-like registers, and
+they must be consecutively numbered.
+
+@table @code
+@findex STACK_REGS
+@item STACK_REGS
+Define this if the machine has any stack-like registers.
+
+@findex FIRST_STACK_REG
+@item FIRST_STACK_REG
+The number of the first stack-like register. This one is the top
+of the stack.
+
+@findex LAST_STACK_REG
+@item LAST_STACK_REG
+The number of the last stack-like register. This one is the bottom of
+the stack.
+@end table
+
+@node Obsolete Register Macros
+@subsection Obsolete Macros for Controlling Register Usage
+
+These features do not work very well. They exist because they used to
+be required to generate correct code for the 80387 coprocessor of the
+80386. They are no longer used by that machine description and may be
+removed in a later version of the compiler. Don't use them!
+
+@table @code
+@findex OVERLAPPING_REGNO_P
+@item OVERLAPPING_REGNO_P (@var{regno})
+If defined, this is a C expression whose value is nonzero if hard
+register number @var{regno} is an overlapping register. This means a
+hard register which overlaps a hard register with a different number.
+(Such overlap is undesirable, but occasionally it allows a machine to
+be supported which otherwise could not be.) This macro must return
+nonzero for @emph{all} the registers which overlap each other. GNU CC
+can use an overlapping register only in certain limited ways. It can
+be used for allocation within a basic block, and may be spilled for
+reloading; that is all.
+
+If this macro is not defined, it means that none of the hard registers
+overlap each other. This is the usual situation.
+
+@findex INSN_CLOBBERS_REGNO_P
+@item INSN_CLOBBERS_REGNO_P (@var{insn}, @var{regno})
+If defined, this is a C expression whose value should be nonzero if
+the insn @var{insn} has the effect of mysteriously clobbering the
+contents of hard register number @var{regno}. By ``mysterious'' we
+mean that the insn's RTL expression doesn't describe such an effect.
+
+If this macro is not defined, it means that no insn clobbers registers
+mysteriously. This is the usual situation; all else being equal,
+it is best for the RTL expression to show all the activity.
+
+@cindex death notes
+@findex PRESERVE_DEATH_INFO_REGNO_P
+@item PRESERVE_DEATH_INFO_REGNO_P (@var{regno})
+If defined, this is a C expression whose value is nonzero if accurate
+@code{REG_DEAD} notes are needed for hard register number @var{regno}
+at the time of outputting the assembler code. When this is so, a few
+optimizations that take place after register allocation and could
+invalidate the death notes are not done when this register is
+involved.
+
+You would arrange to preserve death info for a register when some of the
+code in the machine description which is executed to write the assembler
+code looks at the death notes. This is necessary only when the actual
+hardware feature which GNU CC thinks of as a register is not actually a
+register of the usual sort. (It might, for example, be a hardware
+stack.)
+
+If this macro is not defined, it means that no death notes need to be
+preserved. This is the usual situation.
+@end table
+
+@node Register Classes
+@section Register Classes
+@cindex register class definitions
+@cindex class definitions, register
+
+On many machines, the numbered registers are not all equivalent.
+For example, certain registers may not be allowed for indexed addressing;
+certain registers may not be allowed in some instructions. These machine
+restrictions are described to the compiler using @dfn{register classes}.
+
+You define a number of register classes, giving each one a name and saying
+which of the registers belong to it. Then you can specify register classes
+that are allowed as operands to particular instruction patterns.
+
+@findex ALL_REGS
+@findex NO_REGS
+In general, each register will belong to several classes. In fact, one
+class must be named @code{ALL_REGS} and contain all the registers. Another
+class must be named @code{NO_REGS} and contain no registers. Often the
+union of two classes will be another class; however, this is not required.
+
+@findex GENERAL_REGS
+One of the classes must be named @code{GENERAL_REGS}. There is nothing
+terribly special about the name, but the operand constraint letters
+@samp{r} and @samp{g} specify this class. If @code{GENERAL_REGS} is
+the same as @code{ALL_REGS}, just define it as a macro which expands
+to @code{ALL_REGS}.
+
+Order the classes so that if class @var{x} is contained in class @var{y}
+then @var{x} has a lower class number than @var{y}.
+
+The way classes other than @code{GENERAL_REGS} are specified in operand
+constraints is through machine-dependent operand constraint letters.
+You can define such letters to correspond to various classes, then use
+them in operand constraints.
+
+You should define a class for the union of two classes whenever some
+instruction allows both classes. For example, if an instruction allows
+either a floating point (coprocessor) register or a general register for a
+certain operand, you should define a class @code{FLOAT_OR_GENERAL_REGS}
+which includes both of them. Otherwise you will get suboptimal code.
+
+You must also specify certain redundant information about the register
+classes: for each class, which classes contain it and which ones are
+contained in it; for each pair of classes, the largest class contained
+in their union.
+
+When a value occupying several consecutive registers is expected in a
+certain class, all the registers used must belong to that class.
+Therefore, register classes cannot be used to enforce a requirement for
+a register pair to start with an even-numbered register. The way to
+specify this requirement is with @code{HARD_REGNO_MODE_OK}.
+
+Register classes used for input-operands of bitwise-and or shift
+instructions have a special requirement: each such class must have, for
+each fixed-point machine mode, a subclass whose registers can transfer that
+mode to or from memory. For example, on some machines, the operations for
+single-byte values (@code{QImode}) are limited to certain registers. When
+this is so, each register class that is used in a bitwise-and or shift
+instruction must have a subclass consisting of registers from which
+single-byte values can be loaded or stored. This is so that
+@code{PREFERRED_RELOAD_CLASS} can always have a possible value to return.
+
+@table @code
+@findex enum reg_class
+@item enum reg_class
+An enumeral type that must be defined with all the register class names
+as enumeral values. @code{NO_REGS} must be first. @code{ALL_REGS}
+must be the last register class, followed by one more enumeral value,
+@code{LIM_REG_CLASSES}, which is not a register class but rather
+tells how many classes there are.
+
+Each register class has a number, which is the value of casting
+the class name to type @code{int}. The number serves as an index
+in many of the tables described below.
+
+@findex N_REG_CLASSES
+@item N_REG_CLASSES
+The number of distinct register classes, defined as follows:
+
+@example
+#define N_REG_CLASSES (int) LIM_REG_CLASSES
+@end example
+
+@findex REG_CLASS_NAMES
+@item REG_CLASS_NAMES
+An initializer containing the names of the register classes as C string
+constants. These names are used in writing some of the debugging dumps.
+
+@findex REG_CLASS_CONTENTS
+@item REG_CLASS_CONTENTS
+An initializer containing the contents of the register classes, as integers
+which are bit masks. The @var{n}th integer specifies the contents of class
+@var{n}. The way the integer @var{mask} is interpreted is that
+register @var{r} is in the class if @code{@var{mask} & (1 << @var{r})} is 1.
+
+When the machine has more than 32 registers, an integer does not suffice.
+Then the integers are replaced by sub-initializers, braced groupings containing
+several integers. Each sub-initializer must be suitable as an initializer
+for the type @code{HARD_REG_SET} which is defined in @file{hard-reg-set.h}.
+
+@findex REGNO_REG_CLASS
+@item REGNO_REG_CLASS (@var{regno})
+A C expression whose value is a register class containing hard register
+@var{regno}. In general there is more than one such class; choose a class
+which is @dfn{minimal}, meaning that no smaller class also contains the
+register.
+
+@findex BASE_REG_CLASS
+@item BASE_REG_CLASS
+A macro whose definition is the name of the class to which a valid
+base register must belong. A base register is one used in an address
+which is the register value plus a displacement.
+
+@findex INDEX_REG_CLASS
+@item INDEX_REG_CLASS
+A macro whose definition is the name of the class to which a valid
+index register must belong. An index register is one used in an
+address where its value is either multiplied by a scale factor or
+added to another register (as well as added to a displacement).
+
+@findex REG_CLASS_FROM_LETTER
+@item REG_CLASS_FROM_LETTER (@var{char})
+A C expression which defines the machine-dependent operand constraint
+letters for register classes. If @var{char} is such a letter, the
+value should be the register class corresponding to it. Otherwise,
+the value should be @code{NO_REGS}. The register letter @samp{r},
+corresponding to class @code{GENERAL_REGS}, will not be passed
+to this macro; you do not need to handle it.
+
+@findex REGNO_OK_FOR_BASE_P
+@item REGNO_OK_FOR_BASE_P (@var{num})
+A C expression which is nonzero if register number @var{num} is
+suitable for use as a base register in operand addresses. It may be
+either a suitable hard register or a pseudo register that has been
+allocated such a hard register.
+
+@findex REGNO_OK_FOR_INDEX_P
+@item REGNO_OK_FOR_INDEX_P (@var{num})
+A C expression which is nonzero if register number @var{num} is
+suitable for use as an index register in operand addresses. It may be
+either a suitable hard register or a pseudo register that has been
+allocated such a hard register.
+
+The difference between an index register and a base register is that
+the index register may be scaled. If an address involves the sum of
+two registers, neither one of them scaled, then either one may be
+labeled the ``base'' and the other the ``index''; but whichever
+labeling is used must fit the machine's constraints of which registers
+may serve in each capacity. The compiler will try both labelings,
+looking for one that is valid, and will reload one or both registers
+only if neither labeling works.
+
+@findex PREFERRED_RELOAD_CLASS
+@item PREFERRED_RELOAD_CLASS (@var{x}, @var{class})
+A C expression that places additional restrictions on the register class
+to use when it is necessary to copy value @var{x} into a register in class
+@var{class}. The value is a register class; perhaps @var{class}, or perhaps
+another, smaller class. On many machines, the following definition is
+safe:
+
+@example
+#define PREFERRED_RELOAD_CLASS(X,CLASS) CLASS
+@end example
+
+Sometimes returning a more restrictive class makes better code. For
+example, on the 68000, when @var{x} is an integer constant that is in range
+for a @samp{moveq} instruction, the value of this macro is always
+@code{DATA_REGS} as long as @var{class} includes the data registers.
+Requiring a data register guarantees that a @samp{moveq} will be used.
+
+If @var{x} is a @code{const_double}, by returning @code{NO_REGS}
+you can force @var{x} into a memory constant. This is useful on
+certain machines where immediate floating values cannot be loaded into
+certain kinds of registers.
+
+@findex PREFERRED_OUTPUT_RELOAD_CLASS
+@item PREFERRED_OUTPUT_RELOAD_CLASS (@var{x}, @var{class})
+Like @code{PREFERRED_RELOAD_CLASS}, but for output reloads instead of
+input reloads. If you don't define this macro, the default is to use
+@var{class}, unchanged.
+
+@findex LIMIT_RELOAD_CLASS
+@item LIMIT_RELOAD_CLASS (@var{mode}, @var{class})
+A C expression that places additional restrictions on the register class
+to use when it is necessary to be able to hold a value of mode
+@var{mode} in a reload register for which class @var{class} would
+ordinarily be used.
+
+Unlike @code{PREFERRED_RELOAD_CLASS}, this macro should be used when
+there are certain modes that simply can't go in certain reload classes.
+
+The value is a register class; perhaps @var{class}, or perhaps another,
+smaller class.
+
+Don't define this macro unless the target machine has limitations which
+require the macro to do something nontrivial.
+
+@findex SECONDARY_RELOAD_CLASS
+@findex SECONDARY_INPUT_RELOAD_CLASS
+@findex SECONDARY_OUTPUT_RELOAD_CLASS
+@item SECONDARY_RELOAD_CLASS (@var{class}, @var{mode}, @var{x})
+@itemx SECONDARY_INPUT_RELOAD_CLASS (@var{class}, @var{mode}, @var{x})
+@itemx SECONDARY_OUTPUT_RELOAD_CLASS (@var{class}, @var{mode}, @var{x})
+Many machines have some registers that cannot be copied directly to or
+from memory or even from other types of registers. An example is the
+@samp{MQ} register, which on most machines, can only be copied to or
+from general registers, but not memory. Some machines allow copying all
+registers to and from memory, but require a scratch register for stores
+to some memory locations (e.g., those with symbolic address on the RT,
+and those with certain symbolic address on the Sparc when compiling
+PIC). In some cases, both an intermediate and a scratch register are
+required.
+
+You should define these macros to indicate to the reload phase that it may
+need to allocate at least one register for a reload in addition to the
+register to contain the data. Specifically, if copying @var{x} to a
+register @var{class} in @var{mode} requires an intermediate register,
+you should define @code{SECONDARY_INPUT_RELOAD_CLASS} to return the
+largest register class all of whose registers can be used as
+intermediate registers or scratch registers.
+
+If copying a register @var{class} in @var{mode} to @var{x} requires an
+intermediate or scratch register, @code{SECONDARY_OUTPUT_RELOAD_CLASS}
+should be defined to return the largest register class required. If the
+requirements for input and output reloads are the same, the macro
+@code{SECONDARY_RELOAD_CLASS} should be used instead of defining both
+macros identically.
+
+The values returned by these macros are often @code{GENERAL_REGS}.
+Return @code{NO_REGS} if no spare register is needed; i.e., if @var{x}
+can be directly copied to or from a register of @var{class} in
+@var{mode} without requiring a scratch register. Do not define this
+macro if it would always return @code{NO_REGS}.
+
+If a scratch register is required (either with or without an
+intermediate register), you should define patterns for
+@samp{reload_in@var{m}} or @samp{reload_out@var{m}}, as required
+(@pxref{Standard Names}. These patterns, which will normally be
+implemented with a @code{define_expand}, should be similar to the
+@samp{mov@var{m}} patterns, except that operand 2 is the scratch
+register.
+
+Define constraints for the reload register and scratch register that
+contain a single register class. If the original reload register (whose
+class is @var{class}) can meet the constraint given in the pattern, the
+value returned by these macros is used for the class of the scratch
+register. Otherwise, two additional reload registers are required.
+Their classes are obtained from the constraints in the insn pattern.
+
+@var{x} might be a pseudo-register or a @code{subreg} of a
+pseudo-register, which could either be in a hard register or in memory.
+Use @code{true_regnum} to find out; it will return -1 if the pseudo is
+in memory and the hard register number if it is in a register.
+
+These macros should not be used in the case where a particular class of
+registers can only be copied to memory and not to another class of
+registers. In that case, secondary reload registers are not needed and
+would not be helpful. Instead, a stack location must be used to perform
+the copy and the @code{mov@var{m}} pattern should use memory as a
+intermediate storage. This case often occurs between floating-point and
+general registers.
+
+@findex SECONDARY_MEMORY_NEEDED
+@item SECONDARY_MEMORY_NEEDED (@var{class1}, @var{class2}, @var{m})
+Certain machines have the property that some registers cannot be copied
+to some other registers without using memory. Define this macro on
+those machines to be a C expression that is non-zero if objects of mode
+@var{m} in registers of @var{class1} can only be copied to registers of
+class @var{class2} by storing a register of @var{class1} into memory
+and loading that memory location into a register of @var{class2}.
+
+Do not define this macro if its value would always be zero.
+
+@findex SECONDARY_MEMORY_NEEDED_RTX
+@item SECONDARY_MEMORY_NEEDED_RTX (@var{mode})
+Normally when @code{SECONDARY_MEMORY_NEEDED} is defined, the compiler
+allocates a stack slot for a memory location needed for register copies.
+If this macro is defined, the compiler instead uses the memory location
+defined by this macro.
+
+Do not define this macro if you do not define
+@code{SECONDARY_MEMORY_NEEDED}.
+
+@findex SECONDARY_MEMORY_NEEDED_MODE
+@item SECONDARY_MEMORY_NEEDED_MODE (@var{mode})
+When the compiler needs a secondary memory location to copy between two
+registers of mode @var{mode}, it normally allocates sufficient memory to
+hold a quantity of @code{BITS_PER_WORD} bits and performs the store and
+load operations in a mode that many bits wide and whose class is the
+same as that of @var{mode}.
+
+This is right thing to do on most machines because it ensures that all
+bits of the register are copied and prevents accesses to the registers
+in a narrower mode, which some machines prohibit for floating-point
+registers.
+
+However, this default behavior is not correct on some machines, such as
+the DEC Alpha, that store short integers in floating-point registers
+differently than in integer registers. On those machines, the default
+widening will not work correctly and you must define this macro to
+suppress that widening in some cases. See the file @file{alpha.h} for
+details.
+
+Do not define this macro if you do not define
+@code{SECONDARY_MEMORY_NEEDED} or if widening @var{mode} to a mode that
+is @code{BITS_PER_WORD} bits wide is correct for your machine.
+
+@findex SMALL_REGISTER_CLASSES
+@item SMALL_REGISTER_CLASSES
+Normally the compiler avoids choosing registers that have been
+explicitly mentioned in the rtl as spill registers (these registers are
+normally those used to pass parameters and return values). However,
+some machines have so few registers of certain classes that there
+would not be enough registers to use as spill registers if this were
+done.
+
+Define @code{SMALL_REGISTER_CLASSES} on these machines. When it is
+defined, the compiler allows registers explicitly used in the rtl to be
+used as spill registers but avoids extending the lifetime of these
+registers.
+
+It is always safe to define this macro, but if you unnecessarily define
+it, you will reduce the amount of optimizations that can be performed in
+some cases. If you do not define this macro when it is required, the
+compiler will run out of spill registers and print a fatal error
+message. For most machines, you should not define this macro.
+
+@findex CLASS_LIKELY_SPILLED_P
+@item CLASS_LIKELY_SPILLED_P (@var{class})
+A C expression whose value is nonzero if pseudos that have been assigned
+to registers of class @var{class} would likely be spilled because
+registers of @var{class} are needed for spill registers.
+
+The default value of this macro returns 1 if @var{class} has exactly one
+register and zero otherwise. On most machines, this default should be
+used. Only define this macro to some other expression if pseudo
+allocated by @file{local-alloc.c} end up in memory because their hard
+registers were needed for spill regisers. If this macro returns nonzero
+for those classes, those pseudos will only be allocated by
+@file{global.c}, which knows how to reallocate the pseudo to another
+register. If there would not be another register available for
+reallocation, you should not change the definition of this macro since
+the only effect of such a definition would be to slow down register
+allocation.
+
+@findex CLASS_MAX_NREGS
+@item CLASS_MAX_NREGS (@var{class}, @var{mode})
+A C expression for the maximum number of consecutive registers
+of class @var{class} needed to hold a value of mode @var{mode}.
+
+This is closely related to the macro @code{HARD_REGNO_NREGS}. In fact,
+the value of the macro @code{CLASS_MAX_NREGS (@var{class}, @var{mode})}
+should be the maximum value of @code{HARD_REGNO_NREGS (@var{regno},
+@var{mode})} for all @var{regno} values in the class @var{class}.
+
+This macro helps control the handling of multiple-word values
+in the reload pass.
+
+@item CLASS_CANNOT_CHANGE_SIZE
+If defined, a C expression for a class that contains registers which the
+compiler must always access in a mode that is the same size as the mode
+in which it loaded the register, unless neither mode is integral.
+
+For the example, loading 32-bit integer or floating-point objects into
+floating-point registers on the Alpha extends them to 64-bits.
+Therefore loading a 64-bit object and then storing it as a 32-bit object
+does not store the low-order 32-bits, as would be the case for a normal
+register. Therefore, @file{alpha.h} defines this macro as
+@code{FLOAT_REGS}.
+@end table
+
+Three other special macros describe which operands fit which constraint
+letters.
+
+@table @code
+@findex CONST_OK_FOR_LETTER_P
+@item CONST_OK_FOR_LETTER_P (@var{value}, @var{c})
+A C expression that defines the machine-dependent operand constraint letters
+that specify particular ranges of integer values. If @var{c} is one
+of those letters, the expression should check that @var{value}, an integer,
+is in the appropriate range and return 1 if so, 0 otherwise. If @var{c} is
+not one of those letters, the value should be 0 regardless of @var{value}.
+
+@findex CONST_DOUBLE_OK_FOR_LETTER_P
+@item CONST_DOUBLE_OK_FOR_LETTER_P (@var{value}, @var{c})
+A C expression that defines the machine-dependent operand constraint
+letters that specify particular ranges of @code{const_double} values.
+
+If @var{c} is one of those letters, the expression should check that
+@var{value}, an RTX of code @code{const_double}, is in the appropriate
+range and return 1 if so, 0 otherwise. If @var{c} is not one of those
+letters, the value should be 0 regardless of @var{value}.
+
+@code{const_double} is used for all floating-point constants and for
+@code{DImode} fixed-point constants. A given letter can accept either
+or both kinds of values. It can use @code{GET_MODE} to distinguish
+between these kinds.
+
+@findex EXTRA_CONSTRAINT
+@item EXTRA_CONSTRAINT (@var{value}, @var{c})
+A C expression that defines the optional machine-dependent constraint
+letters that can be used to segregate specific types of operands,
+usually memory references, for the target machine. Normally this macro
+will not be defined. If it is required for a particular target machine,
+it should return 1 if @var{value} corresponds to the operand type
+represented by the constraint letter @var{c}. If @var{c} is not defined
+as an extra constraint, the value returned should be 0 regardless of
+@var{value}.
+
+For example, on the ROMP, load instructions cannot have their output in r0 if
+the memory reference contains a symbolic address. Constraint letter
+@samp{Q} is defined as representing a memory address that does
+@emph{not} contain a symbolic address. An alternative is specified with
+a @samp{Q} constraint on the input and @samp{r} on the output. The next
+alternative specifies @samp{m} on the input and a register class that
+does not include r0 on the output.
+@end table
+
+@node Stack and Calling
+@section Stack Layout and Calling Conventions
+@cindex calling conventions
+
+@c prevent bad page break with this line
+This describes the stack layout and calling conventions.
+
+@menu
+* Frame Layout::
+* Frame Registers::
+* Elimination::
+* Stack Arguments::
+* Register Arguments::
+* Scalar Return::
+* Aggregate Return::
+* Caller Saves::
+* Function Entry::
+* Profiling::
+@end menu
+
+@node Frame Layout
+@subsection Basic Stack Layout
+@cindex stack frame layout
+@cindex frame layout
+
+@c prevent bad page break with this line
+Here is the basic stack layout.
+
+@table @code
+@findex STACK_GROWS_DOWNWARD
+@item STACK_GROWS_DOWNWARD
+Define this macro if pushing a word onto the stack moves the stack
+pointer to a smaller address.
+
+When we say, ``define this macro if @dots{},'' it means that the
+compiler checks this macro only with @code{#ifdef} so the precise
+definition used does not matter.
+
+@findex FRAME_GROWS_DOWNWARD
+@item FRAME_GROWS_DOWNWARD
+Define this macro if the addresses of local variable slots are at negative
+offsets from the frame pointer.
+
+@findex ARGS_GROW_DOWNWARD
+@item ARGS_GROW_DOWNWARD
+Define this macro if successive arguments to a function occupy decreasing
+addresses on the stack.
+
+@findex STARTING_FRAME_OFFSET
+@item STARTING_FRAME_OFFSET
+Offset from the frame pointer to the first local variable slot to be allocated.
+
+If @code{FRAME_GROWS_DOWNWARD}, find the next slot's offset by
+subtracting the first slot's length from @code{STARTING_FRAME_OFFSET}.
+Otherwise, it is found by adding the length of the first slot to the
+value @code{STARTING_FRAME_OFFSET}.
+@c i'm not sure if the above is still correct.. had to change it to get
+@c rid of an overfull. --mew 2feb93
+
+@findex STACK_POINTER_OFFSET
+@item STACK_POINTER_OFFSET
+Offset from the stack pointer register to the first location at which
+outgoing arguments are placed. If not specified, the default value of
+zero is used. This is the proper value for most machines.
+
+If @code{ARGS_GROW_DOWNWARD}, this is the offset to the location above
+the first location at which outgoing arguments are placed.
+
+@findex FIRST_PARM_OFFSET
+@item FIRST_PARM_OFFSET (@var{fundecl})
+Offset from the argument pointer register to the first argument's
+address. On some machines it may depend on the data type of the
+function.
+
+If @code{ARGS_GROW_DOWNWARD}, this is the offset to the location above
+the first argument's address.
+
+@findex STACK_DYNAMIC_OFFSET
+@item STACK_DYNAMIC_OFFSET (@var{fundecl})
+Offset from the stack pointer register to an item dynamically allocated
+on the stack, e.g., by @code{alloca}.
+
+The default value for this macro is @code{STACK_POINTER_OFFSET} plus the
+length of the outgoing arguments. The default is correct for most
+machines. See @file{function.c} for details.
+
+@findex DYNAMIC_CHAIN_ADDRESS
+@item DYNAMIC_CHAIN_ADDRESS (@var{frameaddr})
+A C expression whose value is RTL representing the address in a stack
+frame where the pointer to the caller's frame is stored. Assume that
+@var{frameaddr} is an RTL expression for the address of the stack frame
+itself.
+
+If you don't define this macro, the default is to return the value
+of @var{frameaddr}---that is, the stack frame address is also the
+address of the stack word that points to the previous frame.
+
+@findex SETUP_FRAME_ADDRESSES
+@item SERTUP_FRAME_ADDRESSES ()
+If defined, a C expression that produces the machine-specific code to
+setup the stack so that arbitrary frames can be accessed. For example,
+on the Sparc, we must flush all of the register windows to the stack
+before we can access arbitrary stack frames.
+This macro will seldom need to be defined.
+
+@findex RETURN_ADDR_RTX
+@item RETURN_ADDR_RTX (@var{count}, @var{frameaddr})
+A C expression whose value is RTL representing the value of the return
+address for the frame @var{count} steps up from the current frame.
+@var{frameaddr} is the frame pointer of the @var{count} frame, or
+the frame pointer of the @var{count} @minus{} 1 frame if
+@code{RETURN_ADDR_IN_PREVIOUS_FRAME} is defined.
+
+@findex RETURN_ADDR_IN_PREVIOUS_FRAME
+@item RETURN_ADDR_IN_PREVIOUS_FRAME
+Define this if the return address of a particular stack frame is accessed
+from the frame pointer of the previous stack frame.
+@end table
+
+@need 2000
+@node Frame Registers
+@subsection Registers That Address the Stack Frame
+
+@c prevent bad page break with this line
+This discusses registers that address the stack frame.
+
+@table @code
+@findex STACK_POINTER_REGNUM
+@item STACK_POINTER_REGNUM
+The register number of the stack pointer register, which must also be a
+fixed register according to @code{FIXED_REGISTERS}. On most machines,
+the hardware determines which register this is.
+
+@findex FRAME_POINTER_REGNUM
+@item FRAME_POINTER_REGNUM
+The register number of the frame pointer register, which is used to
+access automatic variables in the stack frame. On some machines, the
+hardware determines which register this is. On other machines, you can
+choose any register you wish for this purpose.
+
+@findex HARD_FRAME_POINTER_REGNUM
+@item HARD_FRAME_POINTER_REGNUM
+On some machines the offset between the frame pointer and starting
+offset of the automatic variables is not known until after register
+allocation has been done (for example, because the saved registers are
+between these two locations). On those machines, define
+@code{FRAME_POINTER_REGNUM} the number of a special, fixed register to
+be used internally until the offset is known, and define
+@code{HARD_FRAME_POINTER_REGNUM} to be actual the hard register number
+used for the frame pointer.
+
+You should define this macro only in the very rare circumstances when it
+is not possible to calculate the offset between the frame pointer and
+the automatic variables until after register allocation has been
+completed. When this macro is defined, you must also indicate in your
+definition of @code{ELIMINABLE_REGS} how to eliminate
+@code{FRAME_POINTER_REGNUM} into either @code{HARD_FRAME_POINTER_REGNUM}
+or @code{STACK_POINTER_REGNUM}.
+
+Do not define this macro if it would be the same as
+@code{FRAME_POINTER_REGNUM}.
+
+@findex ARG_POINTER_REGNUM
+@item ARG_POINTER_REGNUM
+The register number of the arg pointer register, which is used to access
+the function's argument list. On some machines, this is the same as the
+frame pointer register. On some machines, the hardware determines which
+register this is. On other machines, you can choose any register you
+wish for this purpose. If this is not the same register as the frame
+pointer register, then you must mark it as a fixed register according to
+@code{FIXED_REGISTERS}, or arrange to be able to eliminate it
+(@pxref{Elimination}).
+
+@findex STATIC_CHAIN_REGNUM
+@findex STATIC_CHAIN_INCOMING_REGNUM
+@item STATIC_CHAIN_REGNUM
+@itemx STATIC_CHAIN_INCOMING_REGNUM
+Register numbers used for passing a function's static chain pointer. If
+register windows are used, the register number as seen by the called
+function is @code{STATIC_CHAIN_INCOMING_REGNUM}, while the register
+number as seen by the calling function is @code{STATIC_CHAIN_REGNUM}. If
+these registers are the same, @code{STATIC_CHAIN_INCOMING_REGNUM} need
+not be defined.@refill
+
+The static chain register need not be a fixed register.
+
+If the static chain is passed in memory, these macros should not be
+defined; instead, the next two macros should be defined.
+
+@findex STATIC_CHAIN
+@findex STATIC_CHAIN_INCOMING
+@item STATIC_CHAIN
+@itemx STATIC_CHAIN_INCOMING
+If the static chain is passed in memory, these macros provide rtx giving
+@code{mem} expressions that denote where they are stored.
+@code{STATIC_CHAIN} and @code{STATIC_CHAIN_INCOMING} give the locations
+as seen by the calling and called functions, respectively. Often the former
+will be at an offset from the stack pointer and the latter at an offset from
+the frame pointer.@refill
+
+@findex stack_pointer_rtx
+@findex frame_pointer_rtx
+@findex arg_pointer_rtx
+The variables @code{stack_pointer_rtx}, @code{frame_pointer_rtx}, and
+@code{arg_pointer_rtx} will have been initialized prior to the use of these
+macros and should be used to refer to those items.
+
+If the static chain is passed in a register, the two previous macros should
+be defined instead.
+@end table
+
+@node Elimination
+@subsection Eliminating Frame Pointer and Arg Pointer
+
+@c prevent bad page break with this line
+This is about eliminating the frame pointer and arg pointer.
+
+@table @code
+@findex FRAME_POINTER_REQUIRED
+@item FRAME_POINTER_REQUIRED
+A C expression which is nonzero if a function must have and use a frame
+pointer. This expression is evaluated in the reload pass. If its value is
+nonzero the function will have a frame pointer.
+
+The expression can in principle examine the current function and decide
+according to the facts, but on most machines the constant 0 or the
+constant 1 suffices. Use 0 when the machine allows code to be generated
+with no frame pointer, and doing so saves some time or space. Use 1
+when there is no possible advantage to avoiding a frame pointer.
+
+In certain cases, the compiler does not know how to produce valid code
+without a frame pointer. The compiler recognizes those cases and
+automatically gives the function a frame pointer regardless of what
+@code{FRAME_POINTER_REQUIRED} says. You don't need to worry about
+them.@refill
+
+In a function that does not require a frame pointer, the frame pointer
+register can be allocated for ordinary usage, unless you mark it as a
+fixed register. See @code{FIXED_REGISTERS} for more information.
+
+@findex INITIAL_FRAME_POINTER_OFFSET
+@findex get_frame_size
+@item INITIAL_FRAME_POINTER_OFFSET (@var{depth-var})
+A C statement to store in the variable @var{depth-var} the difference
+between the frame pointer and the stack pointer values immediately after
+the function prologue. The value would be computed from information
+such as the result of @code{get_frame_size ()} and the tables of
+registers @code{regs_ever_live} and @code{call_used_regs}.
+
+If @code{ELIMINABLE_REGS} is defined, this macro will be not be used and
+need not be defined. Otherwise, it must be defined even if
+@code{FRAME_POINTER_REQUIRED} is defined to always be true; in that
+case, you may set @var{depth-var} to anything.
+
+@findex ELIMINABLE_REGS
+@item ELIMINABLE_REGS
+If defined, this macro specifies a table of register pairs used to
+eliminate unneeded registers that point into the stack frame. If it is not
+defined, the only elimination attempted by the compiler is to replace
+references to the frame pointer with references to the stack pointer.
+
+The definition of this macro is a list of structure initializations, each
+of which specifies an original and replacement register.
+
+On some machines, the position of the argument pointer is not known until
+the compilation is completed. In such a case, a separate hard register
+must be used for the argument pointer. This register can be eliminated by
+replacing it with either the frame pointer or the argument pointer,
+depending on whether or not the frame pointer has been eliminated.
+
+In this case, you might specify:
+@example
+#define ELIMINABLE_REGS \
+@{@{ARG_POINTER_REGNUM, STACK_POINTER_REGNUM@}, \
+ @{ARG_POINTER_REGNUM, FRAME_POINTER_REGNUM@}, \
+ @{FRAME_POINTER_REGNUM, STACK_POINTER_REGNUM@}@}
+@end example
+
+Note that the elimination of the argument pointer with the stack pointer is
+specified first since that is the preferred elimination.
+
+@findex CAN_ELIMINATE
+@item CAN_ELIMINATE (@var{from-reg}, @var{to-reg})
+A C expression that returns non-zero if the compiler is allowed to try
+to replace register number @var{from-reg} with register number
+@var{to-reg}. This macro need only be defined if @code{ELIMINABLE_REGS}
+is defined, and will usually be the constant 1, since most of the cases
+preventing register elimination are things that the compiler already
+knows about.
+
+@findex INITIAL_ELIMINATION_OFFSET
+@item INITIAL_ELIMINATION_OFFSET (@var{from-reg}, @var{to-reg}, @var{offset-var})
+This macro is similar to @code{INITIAL_FRAME_POINTER_OFFSET}. It
+specifies the initial difference between the specified pair of
+registers. This macro must be defined if @code{ELIMINABLE_REGS} is
+defined.
+
+@findex LONGJMP_RESTORE_FROM_STACK
+@item LONGJMP_RESTORE_FROM_STACK
+Define this macro if the @code{longjmp} function restores registers from
+the stack frames, rather than from those saved specifically by
+@code{setjmp}. Certain quantities must not be kept in registers across
+a call to @code{setjmp} on such machines.
+@end table
+
+@node Stack Arguments
+@subsection Passing Function Arguments on the Stack
+@cindex arguments on stack
+@cindex stack arguments
+
+The macros in this section control how arguments are passed
+on the stack. See the following section for other macros that
+control passing certain arguments in registers.
+
+@table @code
+@findex PROMOTE_PROTOTYPES
+@item PROMOTE_PROTOTYPES
+Define this macro if an argument declared in a prototype as an
+integral type smaller than @code{int} should actually be passed as an
+@code{int}. In addition to avoiding errors in certain cases of
+mismatch, it also makes for better code on certain machines.
+
+@findex PUSH_ROUNDING
+@item PUSH_ROUNDING (@var{npushed})
+A C expression that is the number of bytes actually pushed onto the
+stack when an instruction attempts to push @var{npushed} bytes.
+
+If the target machine does not have a push instruction, do not define
+this macro. That directs GNU CC to use an alternate strategy: to
+allocate the entire argument block and then store the arguments into
+it.
+
+On some machines, the definition
+
+@example
+#define PUSH_ROUNDING(BYTES) (BYTES)
+@end example
+
+@noindent
+will suffice. But on other machines, instructions that appear
+to push one byte actually push two bytes in an attempt to maintain
+alignment. Then the definition should be
+
+@example
+#define PUSH_ROUNDING(BYTES) (((BYTES) + 1) & ~1)
+@end example
+
+@findex ACCUMULATE_OUTGOING_ARGS
+@findex current_function_outgoing_args_size
+@item ACCUMULATE_OUTGOING_ARGS
+If defined, the maximum amount of space required for outgoing arguments
+will be computed and placed into the variable
+@code{current_function_outgoing_args_size}. No space will be pushed
+onto the stack for each call; instead, the function prologue should
+increase the stack frame size by this amount.
+
+Defining both @code{PUSH_ROUNDING} and @code{ACCUMULATE_OUTGOING_ARGS}
+is not proper.
+
+@findex REG_PARM_STACK_SPACE
+@item REG_PARM_STACK_SPACE (@var{fndecl})
+Define this macro if functions should assume that stack space has been
+allocated for arguments even when their values are passed in
+registers.
+
+The value of this macro is the size, in bytes, of the area reserved for
+arguments passed in registers for the function represented by @var{fndecl}.
+
+This space can be allocated by the caller, or be a part of the
+machine-dependent stack frame: @code{OUTGOING_REG_PARM_STACK_SPACE} says
+which.
+@c above is overfull. not sure what to do. --mew 5feb93 did
+@c something, not sure if it looks good. --mew 10feb93
+
+@findex MAYBE_REG_PARM_STACK_SPACE
+@findex FINAL_REG_PARM_STACK_SPACE
+@item MAYBE_REG_PARM_STACK_SPACE
+@itemx FINAL_REG_PARM_STACK_SPACE (@var{const_size}, @var{var_size})
+Define these macros in addition to the one above if functions might
+allocate stack space for arguments even when their values are passed
+in registers. These should be used when the stack space allocated
+for arguments in registers is not a simple constant independent of the
+function declaration.
+
+The value of the first macro is the size, in bytes, of the area that
+we should initially assume would be reserved for arguments passed in registers.
+
+The value of the second macro is the actual size, in bytes, of the area
+that will be reserved for arguments passed in registers. This takes two
+arguments: an integer representing the number of bytes of fixed sized
+arguments on the stack, and a tree representing the number of bytes of
+variable sized arguments on the stack.
+
+When these macros are defined, @code{REG_PARM_STACK_SPACE} will only be
+called for libcall functions, the current function, or for a function
+being called when it is known that such stack space must be allocated.
+In each case this value can be easily computed.
+
+When deciding whether a called function needs such stack space, and how
+much space to reserve, GNU CC uses these two macros instead of
+@code{REG_PARM_STACK_SPACE}.
+
+@findex OUTGOING_REG_PARM_STACK_SPACE
+@item OUTGOING_REG_PARM_STACK_SPACE
+Define this if it is the responsibility of the caller to allocate the area
+reserved for arguments passed in registers.
+
+If @code{ACCUMULATE_OUTGOING_ARGS} is defined, this macro controls
+whether the space for these arguments counts in the value of
+@code{current_function_outgoing_args_size}.
+
+@findex STACK_PARMS_IN_REG_PARM_AREA
+@item STACK_PARMS_IN_REG_PARM_AREA
+Define this macro if @code{REG_PARM_STACK_SPACE} is defined, but the
+stack parameters don't skip the area specified by it.
+@c i changed this, makes more sens and it should have taken care of the
+@c overfull.. not as specific, tho. --mew 5feb93
+
+Normally, when a parameter is not passed in registers, it is placed on the
+stack beyond the @code{REG_PARM_STACK_SPACE} area. Defining this macro
+suppresses this behavior and causes the parameter to be passed on the
+stack in its natural location.
+
+@findex RETURN_POPS_ARGS
+@item RETURN_POPS_ARGS (@var{funtype}, @var{stack-size})
+A C expression that should indicate the number of bytes of its own
+arguments that a function pops on returning, or 0 if the
+function pops no arguments and the caller must therefore pop them all
+after the function returns.
+
+@var{funtype} is a C variable whose value is a tree node that
+describes the function in question. Normally it is a node of type
+@code{FUNCTION_TYPE} that describes the data type of the function.
+From this it is possible to obtain the data types of the value and
+arguments (if known).
+
+When a call to a library function is being considered, @var{funtype}
+will contain an identifier node for the library function. Thus, if
+you need to distinguish among various library functions, you can do so
+by their names. Note that ``library function'' in this context means
+a function used to perform arithmetic, whose name is known specially
+in the compiler and was not mentioned in the C code being compiled.
+
+@var{stack-size} is the number of bytes of arguments passed on the
+stack. If a variable number of bytes is passed, it is zero, and
+argument popping will always be the responsibility of the calling function.
+
+On the Vax, all functions always pop their arguments, so the definition
+of this macro is @var{stack-size}. On the 68000, using the standard
+calling convention, no functions pop their arguments, so the value of
+the macro is always 0 in this case. But an alternative calling
+convention is available in which functions that take a fixed number of
+arguments pop them but other functions (such as @code{printf}) pop
+nothing (the caller pops all). When this convention is in use,
+@var{funtype} is examined to determine whether a function takes a fixed
+number of arguments.
+@end table
+
+@node Register Arguments
+@subsection Passing Arguments in Registers
+@cindex arguments in registers
+@cindex registers arguments
+
+This section describes the macros which let you control how various
+types of arguments are passed in registers or how they are arranged in
+the stack.
+
+@table @code
+@findex FUNCTION_ARG
+@item FUNCTION_ARG (@var{cum}, @var{mode}, @var{type}, @var{named})
+A C expression that controls whether a function argument is passed
+in a register, and which register.
+
+The arguments are @var{cum}, which summarizes all the previous
+arguments; @var{mode}, the machine mode of the argument; @var{type},
+the data type of the argument as a tree node or 0 if that is not known
+(which happens for C support library functions); and @var{named},
+which is 1 for an ordinary argument and 0 for nameless arguments that
+correspond to @samp{@dots{}} in the called function's prototype.
+
+The value of the expression should either be a @code{reg} RTX for the
+hard register in which to pass the argument, or zero to pass the
+argument on the stack.
+
+For machines like the Vax and 68000, where normally all arguments are
+pushed, zero suffices as a definition.
+
+@cindex @file{stdarg.h} and register arguments
+The usual way to make the ANSI library @file{stdarg.h} work on a machine
+where some arguments are usually passed in registers, is to cause
+nameless arguments to be passed on the stack instead. This is done
+by making @code{FUNCTION_ARG} return 0 whenever @var{named} is 0.
+
+@cindex @code{MUST_PASS_IN_STACK}, and @code{FUNCTION_ARG}
+@cindex @code{REG_PARM_STACK_SPACE}, and @code{FUNCTION_ARG}
+You may use the macro @code{MUST_PASS_IN_STACK (@var{mode}, @var{type})}
+in the definition of this macro to determine if this argument is of a
+type that must be passed in the stack. If @code{REG_PARM_STACK_SPACE}
+is not defined and @code{FUNCTION_ARG} returns non-zero for such an
+argument, the compiler will abort. If @code{REG_PARM_STACK_SPACE} is
+defined, the argument will be computed in the stack and then loaded into
+a register.
+
+@findex FUNCTION_INCOMING_ARG
+@item FUNCTION_INCOMING_ARG (@var{cum}, @var{mode}, @var{type}, @var{named})
+Define this macro if the target machine has ``register windows'', so
+that the register in which a function sees an arguments is not
+necessarily the same as the one in which the caller passed the
+argument.
+
+For such machines, @code{FUNCTION_ARG} computes the register in which
+the caller passes the value, and @code{FUNCTION_INCOMING_ARG} should
+be defined in a similar fashion to tell the function being called
+where the arguments will arrive.
+
+If @code{FUNCTION_INCOMING_ARG} is not defined, @code{FUNCTION_ARG}
+serves both purposes.@refill
+
+@findex FUNCTION_ARG_PARTIAL_NREGS
+@item FUNCTION_ARG_PARTIAL_NREGS (@var{cum}, @var{mode}, @var{type}, @var{named})
+A C expression for the number of words, at the beginning of an
+argument, must be put in registers. The value must be zero for
+arguments that are passed entirely in registers or that are entirely
+pushed on the stack.
+
+On some machines, certain arguments must be passed partially in
+registers and partially in memory. On these machines, typically the
+first @var{n} words of arguments are passed in registers, and the rest
+on the stack. If a multi-word argument (a @code{double} or a
+structure) crosses that boundary, its first few words must be passed
+in registers and the rest must be pushed. This macro tells the
+compiler when this occurs, and how many of the words should go in
+registers.
+
+@code{FUNCTION_ARG} for these arguments should return the first
+register to be used by the caller for this argument; likewise
+@code{FUNCTION_INCOMING_ARG}, for the called function.
+
+@findex FUNCTION_ARG_PASS_BY_REFERENCE
+@item FUNCTION_ARG_PASS_BY_REFERENCE (@var{cum}, @var{mode}, @var{type}, @var{named})
+A C expression that indicates when an argument must be passed by reference.
+If nonzero for an argument, a copy of that argument is made in memory and a
+pointer to the argument is passed instead of the argument itself.
+The pointer is passed in whatever way is appropriate for passing a pointer
+to that type.
+
+On machines where @code{REG_PARM_STACK_SPACE} is not defined, a suitable
+definition of this macro might be
+@smallexample
+#define FUNCTION_ARG_PASS_BY_REFERENCE\
+(CUM, MODE, TYPE, NAMED) \
+ MUST_PASS_IN_STACK (MODE, TYPE)
+@end smallexample
+@c this is *still* too long. --mew 5feb93
+
+@findex FUNCTION_ARG_CALLEE_COPIES
+@item FUNCTION_ARG_CALLEE_COPIES (@var{cum}, @var{mode}, @var{type}, @var{named})
+If defined, a C expression that indicates when it is the called function's
+responsibility to make a copy of arguments passed by invisible reference.
+Normally, the caller makes a copy and passes the address of the copy to the
+routine being called. When FUNCTION_ARG_CALLEE_COPIES is defined and is
+nonzero, the caller does not make a copy. Instead, it passes a pointer to the
+``live'' value. The called function must not modify this value. If it can be
+determined that the value won't be modified, it need not make a copy;
+otherwise a copy must be made.
+
+@findex CUMULATIVE_ARGS
+@item CUMULATIVE_ARGS
+A C type for declaring a variable that is used as the first argument of
+@code{FUNCTION_ARG} and other related values. For some target machines,
+the type @code{int} suffices and can hold the number of bytes of
+argument so far.
+
+There is no need to record in @code{CUMULATIVE_ARGS} anything about the
+arguments that have been passed on the stack. The compiler has other
+variables to keep track of that. For target machines on which all
+arguments are passed on the stack, there is no need to store anything in
+@code{CUMULATIVE_ARGS}; however, the data structure must exist and
+should not be empty, so use @code{int}.
+
+@findex INIT_CUMULATIVE_ARGS
+@item INIT_CUMULATIVE_ARGS (@var{cum}, @var{fntype}, @var{libname})
+A C statement (sans semicolon) for initializing the variable @var{cum}
+for the state at the beginning of the argument list. The variable has
+type @code{CUMULATIVE_ARGS}. The value of @var{fntype} is the tree node
+for the data type of the function which will receive the args, or 0
+if the args are to a compiler support library function.
+
+When processing a call to a compiler support library function,
+@var{libname} identifies which one. It is a @code{symbol_ref} rtx which
+contains the name of the function, as a string. @var{libname} is 0 when
+an ordinary C function call is being processed. Thus, each time this
+macro is called, either @var{libname} or @var{fntype} is nonzero, but
+never both of them at once.
+
+@findex INIT_CUMULATIVE_INCOMING_ARGS
+@item INIT_CUMULATIVE_INCOMING_ARGS (@var{cum}, @var{fntype}, @var{libname})
+Like @code{INIT_CUMULATIVE_ARGS} but overrides it for the purposes of
+finding the arguments for the function being compiled. If this macro is
+undefined, @code{INIT_CUMULATIVE_ARGS} is used instead.
+
+The value passed for @var{libname} is always 0, since library routines
+with special calling conventions are never compiled with GNU CC. The
+argument @var{libname} exists for symmetry with
+@code{INIT_CUMULATIVE_ARGS}.
+@c could use "this macro" in place of @code{INIT_CUMULATIVE_ARGS}, maybe.
+@c --mew 5feb93 i switched the order of the sentences. --mew 10feb93
+
+@findex FUNCTION_ARG_ADVANCE
+@item FUNCTION_ARG_ADVANCE (@var{cum}, @var{mode}, @var{type}, @var{named})
+A C statement (sans semicolon) to update the summarizer variable
+@var{cum} to advance past an argument in the argument list. The
+values @var{mode}, @var{type} and @var{named} describe that argument.
+Once this is done, the variable @var{cum} is suitable for analyzing
+the @emph{following} argument with @code{FUNCTION_ARG}, etc.@refill
+
+This macro need not do anything if the argument in question was passed
+on the stack. The compiler knows how to track the amount of stack space
+used for arguments without any special help.
+
+@findex FUNCTION_ARG_PADDING
+@item FUNCTION_ARG_PADDING (@var{mode}, @var{type})
+If defined, a C expression which determines whether, and in which direction,
+to pad out an argument with extra space. The value should be of type
+@code{enum direction}: either @code{upward} to pad above the argument,
+@code{downward} to pad below, or @code{none} to inhibit padding.
+
+The @emph{amount} of padding is always just enough to reach the next
+multiple of @code{FUNCTION_ARG_BOUNDARY}; this macro does not control
+it.
+
+This macro has a default definition which is right for most systems.
+For little-endian machines, the default is to pad upward. For
+big-endian machines, the default is to pad downward for an argument of
+constant size shorter than an @code{int}, and upward otherwise.
+
+@findex FUNCTION_ARG_BOUNDARY
+@item FUNCTION_ARG_BOUNDARY (@var{mode}, @var{type})
+If defined, a C expression that gives the alignment boundary, in bits,
+of an argument with the specified mode and type. If it is not defined,
+@code{PARM_BOUNDARY} is used for all arguments.
+
+@findex FUNCTION_ARG_REGNO_P
+@item FUNCTION_ARG_REGNO_P (@var{regno})
+A C expression that is nonzero if @var{regno} is the number of a hard
+register in which function arguments are sometimes passed. This does
+@emph{not} include implicit arguments such as the static chain and
+the structure-value address. On many machines, no registers can be
+used for this purpose since all function arguments are pushed on the
+stack.
+@end table
+
+@node Scalar Return
+@subsection How Scalar Function Values Are Returned
+@cindex return values in registers
+@cindex values, returned by functions
+@cindex scalars, returned as values
+
+This section discusses the macros that control returning scalars as
+values---values that can fit in registers.
+
+@table @code
+@findex TRADITIONAL_RETURN_FLOAT
+@item TRADITIONAL_RETURN_FLOAT
+Define this macro if @samp{-traditional} should not cause functions
+declared to return @code{float} to convert the value to @code{double}.
+
+@findex FUNCTION_VALUE
+@item FUNCTION_VALUE (@var{valtype}, @var{func})
+A C expression to create an RTX representing the place where a
+function returns a value of data type @var{valtype}. @var{valtype} is
+a tree node representing a data type. Write @code{TYPE_MODE
+(@var{valtype})} to get the machine mode used to represent that type.
+On many machines, only the mode is relevant. (Actually, on most
+machines, scalar values are returned in the same place regardless of
+mode).@refill
+
+If @code{PROMOTE_FUNCTION_RETURN} is defined, you must apply the same
+promotion rules specified in @code{PROMOTE_MODE} if @var{valtype} is a
+scalar type.
+
+If the precise function being called is known, @var{func} is a tree
+node (@code{FUNCTION_DECL}) for it; otherwise, @var{func} is a null
+pointer. This makes it possible to use a different value-returning
+convention for specific functions when all their calls are
+known.@refill
+
+@code{FUNCTION_VALUE} is not used for return vales with aggregate data
+types, because these are returned in another way. See
+@code{STRUCT_VALUE_REGNUM} and related macros, below.
+
+@findex FUNCTION_OUTGOING_VALUE
+@item FUNCTION_OUTGOING_VALUE (@var{valtype}, @var{func})
+Define this macro if the target machine has ``register windows''
+so that the register in which a function returns its value is not
+the same as the one in which the caller sees the value.
+
+For such machines, @code{FUNCTION_VALUE} computes the register in which
+the caller will see the value. @code{FUNCTION_OUTGOING_VALUE} should be
+defined in a similar fashion to tell the function where to put the
+value.@refill
+
+If @code{FUNCTION_OUTGOING_VALUE} is not defined,
+@code{FUNCTION_VALUE} serves both purposes.@refill
+
+@code{FUNCTION_OUTGOING_VALUE} is not used for return vales with
+aggregate data types, because these are returned in another way. See
+@code{STRUCT_VALUE_REGNUM} and related macros, below.
+
+@findex LIBCALL_VALUE
+@item LIBCALL_VALUE (@var{mode})
+A C expression to create an RTX representing the place where a library
+function returns a value of mode @var{mode}. If the precise function
+being called is known, @var{func} is a tree node
+(@code{FUNCTION_DECL}) for it; otherwise, @var{func} is a null
+pointer. This makes it possible to use a different value-returning
+convention for specific functions when all their calls are
+known.@refill
+
+Note that ``library function'' in this context means a compiler
+support routine, used to perform arithmetic, whose name is known
+specially by the compiler and was not mentioned in the C code being
+compiled.
+
+The definition of @code{LIBRARY_VALUE} need not be concerned aggregate
+data types, because none of the library functions returns such types.
+
+@findex FUNCTION_VALUE_REGNO_P
+@item FUNCTION_VALUE_REGNO_P (@var{regno})
+A C expression that is nonzero if @var{regno} is the number of a hard
+register in which the values of called function may come back.
+
+A register whose use for returning values is limited to serving as the
+second of a pair (for a value of type @code{double}, say) need not be
+recognized by this macro. So for most machines, this definition
+suffices:
+
+@example
+#define FUNCTION_VALUE_REGNO_P(N) ((N) == 0)
+@end example
+
+If the machine has register windows, so that the caller and the called
+function use different registers for the return value, this macro
+should recognize only the caller's register numbers.
+
+@findex APPLY_RESULT_SIZE
+@item APPLY_RESULT_SIZE
+Define this macro if @samp{untyped_call} and @samp{untyped_return}
+need more space than is implied by @code{FUNCTION_VALUE_REGNO_P} for
+saving and restoring an arbitrary return value.
+@end table
+
+@node Aggregate Return
+@subsection How Large Values Are Returned
+@cindex aggregates as return values
+@cindex large return values
+@cindex returning aggregate values
+@cindex structure value address
+
+When a function value's mode is @code{BLKmode} (and in some other
+cases), the value is not returned according to @code{FUNCTION_VALUE}
+(@pxref{Scalar Return}). Instead, the caller passes the address of a
+block of memory in which the value should be stored. This address
+is called the @dfn{structure value address}.
+
+This section describes how to control returning structure values in
+memory.
+
+@table @code
+@findex RETURN_IN_MEMORY
+@item RETURN_IN_MEMORY (@var{type})
+A C expression which can inhibit the returning of certain function
+values in registers, based on the type of value. A nonzero value says
+to return the function value in memory, just as large structures are
+always returned. Here @var{type} will be a C expression of type
+@code{tree}, representing the data type of the value.
+
+Note that values of mode @code{BLKmode} must be explicitly handled
+by this macro. Also, the option @samp{-fpcc-struct-return}
+takes effect regardless of this macro. On most systems, it is
+possible to leave the macro undefined; this causes a default
+definition to be used, whose value is the constant 1 for @code{BLKmode}
+values, and 0 otherwise.
+
+Do not use this macro to indicate that structures and unions should always
+be returned in memory. You should instead use @code{DEFAULT_PCC_STRUCT_RETURN}
+to indicate this.
+
+@findex DEFAULT_PCC_STRUCT_RETURN
+@item DEFAULT_PCC_STRUCT_RETURN
+Define this macro to be 1 if all structure and union return values must be
+in memory. Since this results in slower code, this should be defined
+only if needed for compatibility with other compilers or with an ABI.
+If you define this macro to be 0, then the conventions used for structure
+and union return values are decided by the @code{RETURN_IN_MEMORY} macro.
+
+If not defined, this defaults to the value 1.
+
+@findex STRUCT_VALUE_REGNUM
+@item STRUCT_VALUE_REGNUM
+If the structure value address is passed in a register, then
+@code{STRUCT_VALUE_REGNUM} should be the number of that register.
+
+@findex STRUCT_VALUE
+@item STRUCT_VALUE
+If the structure value address is not passed in a register, define
+@code{STRUCT_VALUE} as an expression returning an RTX for the place
+where the address is passed. If it returns 0, the address is passed as
+an ``invisible'' first argument.
+
+@findex STRUCT_VALUE_INCOMING_REGNUM
+@item STRUCT_VALUE_INCOMING_REGNUM
+On some architectures the place where the structure value address
+is found by the called function is not the same place that the
+caller put it. This can be due to register windows, or it could
+be because the function prologue moves it to a different place.
+
+If the incoming location of the structure value address is in a
+register, define this macro as the register number.
+
+@findex STRUCT_VALUE_INCOMING
+@item STRUCT_VALUE_INCOMING
+If the incoming location is not a register, then you should define
+@code{STRUCT_VALUE_INCOMING} as an expression for an RTX for where the
+called function should find the value. If it should find the value on
+the stack, define this to create a @code{mem} which refers to the frame
+pointer. A definition of 0 means that the address is passed as an
+``invisible'' first argument.
+
+@findex PCC_STATIC_STRUCT_RETURN
+@item PCC_STATIC_STRUCT_RETURN
+Define this macro if the usual system convention on the target machine
+for returning structures and unions is for the called function to return
+the address of a static variable containing the value.
+
+Do not define this if the usual system convention is for the caller to
+pass an address to the subroutine.
+
+This macro has effect in @samp{-fpcc-struct-return} mode, but it does
+nothing when you use @samp{-freg-struct-return} mode.
+@end table
+
+@node Caller Saves
+@subsection Caller-Saves Register Allocation
+
+If you enable it, GNU CC can save registers around function calls. This
+makes it possible to use call-clobbered registers to hold variables that
+must live across calls.
+
+@table @code
+@findex DEFAULT_CALLER_SAVES
+@item DEFAULT_CALLER_SAVES
+Define this macro if function calls on the target machine do not preserve
+any registers; in other words, if @code{CALL_USED_REGISTERS} has 1
+for all registers. This macro enables @samp{-fcaller-saves} by default.
+Eventually that option will be enabled by default on all machines and both
+the option and this macro will be eliminated.
+
+@findex CALLER_SAVE_PROFITABLE
+@item CALLER_SAVE_PROFITABLE (@var{refs}, @var{calls})
+A C expression to determine whether it is worthwhile to consider placing
+a pseudo-register in a call-clobbered hard register and saving and
+restoring it around each function call. The expression should be 1 when
+this is worth doing, and 0 otherwise.
+
+If you don't define this macro, a default is used which is good on most
+machines: @code{4 * @var{calls} < @var{refs}}.
+@end table
+
+@node Function Entry
+@subsection Function Entry and Exit
+@cindex function entry and exit
+@cindex prologue
+@cindex epilogue
+
+This section describes the macros that output function entry
+(@dfn{prologue}) and exit (@dfn{epilogue}) code.
+
+@table @code
+@findex FUNCTION_PROLOGUE
+@item FUNCTION_PROLOGUE (@var{file}, @var{size})
+A C compound statement that outputs the assembler code for entry to a
+function. The prologue is responsible for setting up the stack frame,
+initializing the frame pointer register, saving registers that must be
+saved, and allocating @var{size} additional bytes of storage for the
+local variables. @var{size} is an integer. @var{file} is a stdio
+stream to which the assembler code should be output.
+
+The label for the beginning of the function need not be output by this
+macro. That has already been done when the macro is run.
+
+@findex regs_ever_live
+To determine which registers to save, the macro can refer to the array
+@code{regs_ever_live}: element @var{r} is nonzero if hard register
+@var{r} is used anywhere within the function. This implies the function
+prologue should save register @var{r}, provided it is not one of the
+call-used registers. (@code{FUNCTION_EPILOGUE} must likewise use
+@code{regs_ever_live}.)
+
+On machines that have ``register windows'', the function entry code does
+not save on the stack the registers that are in the windows, even if
+they are supposed to be preserved by function calls; instead it takes
+appropriate steps to ``push'' the register stack, if any non-call-used
+registers are used in the function.
+
+@findex frame_pointer_needed
+On machines where functions may or may not have frame-pointers, the
+function entry code must vary accordingly; it must set up the frame
+pointer if one is wanted, and not otherwise. To determine whether a
+frame pointer is in wanted, the macro can refer to the variable
+@code{frame_pointer_needed}. The variable's value will be 1 at run
+time in a function that needs a frame pointer. @xref{Elimination}.
+
+The function entry code is responsible for allocating any stack space
+required for the function. This stack space consists of the regions
+listed below. In most cases, these regions are allocated in the
+order listed, with the last listed region closest to the top of the
+stack (the lowest address if @code{STACK_GROWS_DOWNWARD} is defined, and
+the highest address if it is not defined). You can use a different order
+for a machine if doing so is more convenient or required for
+compatibility reasons. Except in cases where required by standard
+or by a debugger, there is no reason why the stack layout used by GCC
+need agree with that used by other compilers for a machine.
+
+@itemize @bullet
+@item
+@findex current_function_pretend_args_size
+A region of @code{current_function_pretend_args_size} bytes of
+uninitialized space just underneath the first argument arriving on the
+stack. (This may not be at the very start of the allocated stack region
+if the calling sequence has pushed anything else since pushing the stack
+arguments. But usually, on such machines, nothing else has been pushed
+yet, because the function prologue itself does all the pushing.) This
+region is used on machines where an argument may be passed partly in
+registers and partly in memory, and, in some cases to support the
+features in @file{varargs.h} and @file{stdargs.h}.
+
+@item
+An area of memory used to save certain registers used by the function.
+The size of this area, which may also include space for such things as
+the return address and pointers to previous stack frames, is
+machine-specific and usually depends on which registers have been used
+in the function. Machines with register windows often do not require
+a save area.
+
+@item
+A region of at least @var{size} bytes, possibly rounded up to an allocation
+boundary, to contain the local variables of the function. On some machines,
+this region and the save area may occur in the opposite order, with the
+save area closer to the top of the stack.
+
+@item
+@cindex @code{ACCUMULATE_OUTGOING_ARGS} and stack frames
+Optionally, when @code{ACCUMULATE_OUTGOING_ARGS} is defined, a region of
+@code{current_function_outgoing_args_size} bytes to be used for outgoing
+argument lists of the function. @xref{Stack Arguments}.
+@end itemize
+
+Normally, it is necessary for the macros @code{FUNCTION_PROLOGUE} and
+@code{FUNCTION_EPILOGUE} to treat leaf functions specially. The C
+variable @code{leaf_function} is nonzero for such a function.
+
+@findex EXIT_IGNORE_STACK
+@item EXIT_IGNORE_STACK
+Define this macro as a C expression that is nonzero if the return
+instruction or the function epilogue ignores the value of the stack
+pointer; in other words, if it is safe to delete an instruction to
+adjust the stack pointer before a return from the function.
+
+Note that this macro's value is relevant only for functions for which
+frame pointers are maintained. It is never safe to delete a final
+stack adjustment in a function that has no frame pointer, and the
+compiler knows this regardless of @code{EXIT_IGNORE_STACK}.
+
+@findex FUNCTION_EPILOGUE
+@item FUNCTION_EPILOGUE (@var{file}, @var{size})
+A C compound statement that outputs the assembler code for exit from a
+function. The epilogue is responsible for restoring the saved
+registers and stack pointer to their values when the function was
+called, and returning control to the caller. This macro takes the
+same arguments as the macro @code{FUNCTION_PROLOGUE}, and the
+registers to restore are determined from @code{regs_ever_live} and
+@code{CALL_USED_REGISTERS} in the same way.
+
+On some machines, there is a single instruction that does all the work
+of returning from the function. On these machines, give that
+instruction the name @samp{return} and do not define the macro
+@code{FUNCTION_EPILOGUE} at all.
+
+Do not define a pattern named @samp{return} if you want the
+@code{FUNCTION_EPILOGUE} to be used. If you want the target switches
+to control whether return instructions or epilogues are used, define a
+@samp{return} pattern with a validity condition that tests the target
+switches appropriately. If the @samp{return} pattern's validity
+condition is false, epilogues will be used.
+
+On machines where functions may or may not have frame-pointers, the
+function exit code must vary accordingly. Sometimes the code for these
+two cases is completely different. To determine whether a frame pointer
+is wanted, the macro can refer to the variable
+@code{frame_pointer_needed}. The variable's value will be 1 when compiling
+a function that needs a frame pointer.
+
+Normally, @code{FUNCTION_PROLOGUE} and @code{FUNCTION_EPILOGUE} must
+treat leaf functions specially. The C variable @code{leaf_function} is
+nonzero for such a function. @xref{Leaf Functions}.
+
+On some machines, some functions pop their arguments on exit while
+others leave that for the caller to do. For example, the 68020 when
+given @samp{-mrtd} pops arguments in functions that take a fixed
+number of arguments.
+
+@findex current_function_pops_args
+Your definition of the macro @code{RETURN_POPS_ARGS} decides which
+functions pop their own arguments. @code{FUNCTION_EPILOGUE} needs to
+know what was decided. The variable that is called
+@code{current_function_pops_args} is the number of bytes of its
+arguments that a function should pop. @xref{Scalar Return}.
+@c what is the "its arguments" in the above sentence referring to, pray
+@c tell? --mew 5feb93
+
+@findex DELAY_SLOTS_FOR_EPILOGUE
+@item DELAY_SLOTS_FOR_EPILOGUE
+Define this macro if the function epilogue contains delay slots to which
+instructions from the rest of the function can be ``moved''. The
+definition should be a C expression whose value is an integer
+representing the number of delay slots there.
+
+@findex ELIGIBLE_FOR_EPILOGUE_DELAY
+@item ELIGIBLE_FOR_EPILOGUE_DELAY (@var{insn}, @var{n})
+A C expression that returns 1 if @var{insn} can be placed in delay
+slot number @var{n} of the epilogue.
+
+The argument @var{n} is an integer which identifies the delay slot now
+being considered (since different slots may have different rules of
+eligibility). It is never negative and is always less than the number
+of epilogue delay slots (what @code{DELAY_SLOTS_FOR_EPILOGUE} returns).
+If you reject a particular insn for a given delay slot, in principle, it
+may be reconsidered for a subsequent delay slot. Also, other insns may
+(at least in principle) be considered for the so far unfilled delay
+slot.
+
+@findex current_function_epilogue_delay_list
+@findex final_scan_insn
+The insns accepted to fill the epilogue delay slots are put in an RTL
+list made with @code{insn_list} objects, stored in the variable
+@code{current_function_epilogue_delay_list}. The insn for the first
+delay slot comes first in the list. Your definition of the macro
+@code{FUNCTION_EPILOGUE} should fill the delay slots by outputting the
+insns in this list, usually by calling @code{final_scan_insn}.
+
+You need not define this macro if you did not define
+@code{DELAY_SLOTS_FOR_EPILOGUE}.
+@end table
+
+@node Profiling
+@subsection Generating Code for Profiling
+@cindex profiling, code generation
+
+These macros will help you generate code for profiling.
+
+@table @code
+@findex FUNCTION_PROFILER
+@item FUNCTION_PROFILER (@var{file}, @var{labelno})
+A C statement or compound statement to output to @var{file} some
+assembler code to call the profiling subroutine @code{mcount}.
+Before calling, the assembler code must load the address of a
+counter variable into a register where @code{mcount} expects to
+find the address. The name of this variable is @samp{LP} followed
+by the number @var{labelno}, so you would generate the name using
+@samp{LP%d} in a @code{fprintf}.
+
+@findex mcount
+The details of how the address should be passed to @code{mcount} are
+determined by your operating system environment, not by GNU CC. To
+figure them out, compile a small program for profiling using the
+system's installed C compiler and look at the assembler code that
+results.
+
+@findex PROFILE_BEFORE_PROLOGUE
+@item PROFILE_BEFORE_PROLOGUE
+Define this macro if the code for function profiling should come before
+the function prologue. Normally, the profiling code comes after.
+
+@findex FUNCTION_BLOCK_PROFILER
+@findex __bb_init_func
+@item FUNCTION_BLOCK_PROFILER (@var{file}, @var{labelno})
+A C statement or compound statement to output to @var{file} some
+assembler code to initialize basic-block profiling for the current
+object module. This code should call the subroutine
+@code{__bb_init_func} once per object module, passing it as its sole
+argument the address of a block allocated in the object module.
+
+The name of the block is a local symbol made with this statement:
+
+@example
+ASM_GENERATE_INTERNAL_LABEL (@var{buffer}, "LPBX", 0);
+@end example
+
+Of course, since you are writing the definition of
+@code{ASM_GENERATE_INTERNAL_LABEL} as well as that of this macro, you
+can take a short cut in the definition of this macro and use the name
+that you know will result.
+
+The first word of this block is a flag which will be nonzero if the
+object module has already been initialized. So test this word first,
+and do not call @code{__bb_init_func} if the flag is nonzero.
+
+@findex BLOCK_PROFILER
+@item BLOCK_PROFILER (@var{file}, @var{blockno})
+A C statement or compound statement to increment the count associated
+with the basic block number @var{blockno}. Basic blocks are numbered
+separately from zero within each compilation. The count associated
+with block number @var{blockno} is at index @var{blockno} in a vector
+of words; the name of this array is a local symbol made with this
+statement:
+
+@example
+ASM_GENERATE_INTERNAL_LABEL (@var{buffer}, "LPBX", 2);
+@end example
+
+@c This paragraph is the same as one a few paragraphs up.
+@c That is not an error.
+Of course, since you are writing the definition of
+@code{ASM_GENERATE_INTERNAL_LABEL} as well as that of this macro, you
+can take a short cut in the definition of this macro and use the name
+that you know will result.
+
+@findex BLOCK_PROFILER_CODE
+@item BLOCK_PROFILER_CODE
+A C function or functions which are needed in the library to
+support block profiling.
+@end table
+
+@node Varargs
+@section Implementing the Varargs Macros
+@cindex varargs implementation
+
+GNU CC comes with an implementation of @file{varargs.h} and
+@file{stdarg.h} that work without change on machines that pass arguments
+on the stack. Other machines require their own implementations of
+varargs, and the two machine independent header files must have
+conditionals to include it.
+
+ANSI @file{stdarg.h} differs from traditional @file{varargs.h} mainly in
+the calling convention for @code{va_start}. The traditional
+implementation takes just one argument, which is the variable in which
+to store the argument pointer. The ANSI implementation of
+@code{va_start} takes an additional second argument. The user is
+supposed to write the last named argument of the function here.
+
+However, @code{va_start} should not use this argument. The way to find
+the end of the named arguments is with the built-in functions described
+below.
+
+@table @code
+@findex __builtin_saveregs
+@item __builtin_saveregs ()
+Use this built-in function to save the argument registers in memory so
+that the varargs mechanism can access them. Both ANSI and traditional
+versions of @code{va_start} must use @code{__builtin_saveregs}, unless
+you use @code{SETUP_INCOMING_VARARGS} (see below) instead.
+
+On some machines, @code{__builtin_saveregs} is open-coded under the
+control of the macro @code{EXPAND_BUILTIN_SAVEREGS}. On other machines,
+it calls a routine written in assembler language, found in
+@file{libgcc2.c}.
+
+Code generated for the call to @code{__builtin_saveregs} appears at the
+beginning of the function, as opposed to where the call to
+@code{__builtin_saveregs} is written, regardless of what the code is.
+This is because the registers must be saved before the function starts
+to use them for its own purposes.
+@c i rewrote the first sentence above to fix an overfull hbox. --mew
+@c 10feb93
+
+@findex __builtin_args_info
+@item __builtin_args_info (@var{category})
+Use this built-in function to find the first anonymous arguments in
+registers.
+
+In general, a machine may have several categories of registers used for
+arguments, each for a particular category of data types. (For example,
+on some machines, floating-point registers are used for floating-point
+arguments while other arguments are passed in the general registers.)
+To make non-varargs functions use the proper calling convention, you
+have defined the @code{CUMULATIVE_ARGS} data type to record how many
+registers in each category have been used so far
+
+@code{__builtin_args_info} accesses the same data structure of type
+@code{CUMULATIVE_ARGS} after the ordinary argument layout is finished
+with it, with @var{category} specifying which word to access. Thus, the
+value indicates the first unused register in a given category.
+
+Normally, you would use @code{__builtin_args_info} in the implementation
+of @code{va_start}, accessing each category just once and storing the
+value in the @code{va_list} object. This is because @code{va_list} will
+have to update the values, and there is no way to alter the
+values accessed by @code{__builtin_args_info}.
+
+@findex __builtin_next_arg
+@item __builtin_next_arg (@var{lastarg})
+This is the equivalent of @code{__builtin_args_info}, for stack
+arguments. It returns the address of the first anonymous stack
+argument, as type @code{void *}. If @code{ARGS_GROW_DOWNWARD}, it
+returns the address of the location above the first anonymous stack
+argument. Use it in @code{va_start} to initialize the pointer for
+fetching arguments from the stack. Also use it in @code{va_start} to
+verify that the second parameter @var{lastarg} is the last named argument
+of the current function.
+
+@findex __builtin_classify_type
+@item __builtin_classify_type (@var{object})
+Since each machine has its own conventions for which data types are
+passed in which kind of register, your implementation of @code{va_arg}
+has to embody these conventions. The easiest way to categorize the
+specified data type is to use @code{__builtin_classify_type} together
+with @code{sizeof} and @code{__alignof__}.
+
+@code{__builtin_classify_type} ignores the value of @var{object},
+considering only its data type. It returns an integer describing what
+kind of type that is---integer, floating, pointer, structure, and so on.
+
+The file @file{typeclass.h} defines an enumeration that you can use to
+interpret the values of @code{__builtin_classify_type}.
+@end table
+
+These machine description macros help implement varargs:
+
+@table @code
+@findex EXPAND_BUILTIN_SAVEREGS
+@item EXPAND_BUILTIN_SAVEREGS (@var{args})
+If defined, is a C expression that produces the machine-specific code
+for a call to @code{__builtin_saveregs}. This code will be moved to the
+very beginning of the function, before any parameter access are made.
+The return value of this function should be an RTX that contains the
+value to use as the return of @code{__builtin_saveregs}.
+
+The argument @var{args} is a @code{tree_list} containing the arguments
+that were passed to @code{__builtin_saveregs}.
+
+If this macro is not defined, the compiler will output an ordinary
+call to the library function @samp{__builtin_saveregs}.
+
+@c !!! a bug in texinfo; how to make the entry on the @item line allow
+@c more than one line of text... help... --mew 10feb93
+@findex SETUP_INCOMING_VARARGS
+@item SETUP_INCOMING_VARARGS (@var{args_so_far}, @var{mode}, @var{type},
+@var{pretend_args_size}, @var{second_time})
+This macro offers an alternative to using @code{__builtin_saveregs} and
+defining the macro @code{EXPAND_BUILTIN_SAVEREGS}. Use it to store the
+anonymous register arguments into the stack so that all the arguments
+appear to have been passed consecutively on the stack. Once this is
+done, you can use the standard implementation of varargs that works for
+machines that pass all their arguments on the stack.
+
+The argument @var{args_so_far} is the @code{CUMULATIVE_ARGS} data
+structure, containing the values that obtain after processing of the
+named arguments. The arguments @var{mode} and @var{type} describe the
+last named argument---its machine mode and its data type as a tree node.
+
+The macro implementation should do two things: first, push onto the
+stack all the argument registers @emph{not} used for the named
+arguments, and second, store the size of the data thus pushed into the
+@code{int}-valued variable whose name is supplied as the argument
+@var{pretend_args_size}. The value that you store here will serve as
+additional offset for setting up the stack frame.
+
+Because you must generate code to push the anonymous arguments at
+compile time without knowing their data types,
+@code{SETUP_INCOMING_VARARGS} is only useful on machines that have just
+a single category of argument register and use it uniformly for all data
+types.
+
+If the argument @var{second_time} is nonzero, it means that the
+arguments of the function are being analyzed for the second time. This
+happens for an inline function, which is not actually compiled until the
+end of the source file. The macro @code{SETUP_INCOMING_VARARGS} should
+not generate any instructions in this case.
+@end table
+
+@node Trampolines
+@section Trampolines for Nested Functions
+@cindex trampolines for nested functions
+@cindex nested functions, trampolines for
+
+A @dfn{trampoline} is a small piece of code that is created at run time
+when the address of a nested function is taken. It normally resides on
+the stack, in the stack frame of the containing function. These macros
+tell GNU CC how to generate code to allocate and initialize a
+trampoline.
+
+The instructions in the trampoline must do two things: load a constant
+address into the static chain register, and jump to the real address of
+the nested function. On CISC machines such as the m68k, this requires
+two instructions, a move immediate and a jump. Then the two addresses
+exist in the trampoline as word-long immediate operands. On RISC
+machines, it is often necessary to load each address into a register in
+two parts. Then pieces of each address form separate immediate
+operands.
+
+The code generated to initialize the trampoline must store the variable
+parts---the static chain value and the function address---into the
+immediate operands of the instructions. On a CISC machine, this is
+simply a matter of copying each address to a memory reference at the
+proper offset from the start of the trampoline. On a RISC machine, it
+may be necessary to take out pieces of the address and store them
+separately.
+
+@table @code
+@findex TRAMPOLINE_TEMPLATE
+@item TRAMPOLINE_TEMPLATE (@var{file})
+A C statement to output, on the stream @var{file}, assembler code for a
+block of data that contains the constant parts of a trampoline. This
+code should not include a label---the label is taken care of
+automatically.
+
+@findex TRAMPOLINE_SECTION
+@item TRAMPOLINE_SECTION
+The name of a subroutine to switch to the section in which the
+trampoline template is to be placed (@pxref{Sections}). The default is
+a value of @samp{readonly_data_section}, which places the trampoline in
+the section containing read-only data.
+
+@findex TRAMPOLINE_SIZE
+@item TRAMPOLINE_SIZE
+A C expression for the size in bytes of the trampoline, as an integer.
+
+@findex TRAMPOLINE_ALIGNMENT
+@item TRAMPOLINE_ALIGNMENT
+Alignment required for trampolines, in bits.
+
+If you don't define this macro, the value of @code{BIGGEST_ALIGNMENT}
+is used for aligning trampolines.
+
+@findex INITIALIZE_TRAMPOLINE
+@item INITIALIZE_TRAMPOLINE (@var{addr}, @var{fnaddr}, @var{static_chain})
+A C statement to initialize the variable parts of a trampoline.
+@var{addr} is an RTX for the address of the trampoline; @var{fnaddr} is
+an RTX for the address of the nested function; @var{static_chain} is an
+RTX for the static chain value that should be passed to the function
+when it is called.
+
+@findex ALLOCATE_TRAMPOLINE
+@item ALLOCATE_TRAMPOLINE (@var{fp})
+A C expression to allocate run-time space for a trampoline. The
+expression value should be an RTX representing a memory reference to the
+space for the trampoline.
+
+@cindex @code{FUNCTION_EPILOGUE} and trampolines
+@cindex @code{FUNCTION_PROLOGUE} and trampolines
+If this macro is not defined, by default the trampoline is allocated as
+a stack slot. This default is right for most machines. The exceptions
+are machines where it is impossible to execute instructions in the stack
+area. On such machines, you may have to implement a separate stack,
+using this macro in conjunction with @code{FUNCTION_PROLOGUE} and
+@code{FUNCTION_EPILOGUE}.
+
+@var{fp} points to a data structure, a @code{struct function}, which
+describes the compilation status of the immediate containing function of
+the function which the trampoline is for. Normally (when
+@code{ALLOCATE_TRAMPOLINE} is not defined), the stack slot for the
+trampoline is in the stack frame of this containing function. Other
+allocation strategies probably must do something analogous with this
+information.
+@end table
+
+Implementing trampolines is difficult on many machines because they have
+separate instruction and data caches. Writing into a stack location
+fails to clear the memory in the instruction cache, so when the program
+jumps to that location, it executes the old contents.
+
+Here are two possible solutions. One is to clear the relevant parts of
+the instruction cache whenever a trampoline is set up. The other is to
+make all trampolines identical, by having them jump to a standard
+subroutine. The former technique makes trampoline execution faster; the
+latter makes initialization faster.
+
+To clear the instruction cache when a trampoline is initialized, define
+the following macros which describe the shape of the cache.
+
+@table @code
+@findex INSN_CACHE_SIZE
+@item INSN_CACHE_SIZE
+The total size in bytes of the cache.
+
+@findex INSN_CACHE_LINE_WIDTH
+@item INSN_CACHE_LINE_WIDTH
+The length in bytes of each cache line. The cache is divided into cache
+lines which are disjoint slots, each holding a contiguous chunk of data
+fetched from memory. Each time data is brought into the cache, an
+entire line is read at once. The data loaded into a cache line is
+always aligned on a boundary equal to the line size.
+
+@findex INSN_CACHE_DEPTH
+@item INSN_CACHE_DEPTH
+The number of alternative cache lines that can hold any particular memory
+location.
+@end table
+
+Alternatively, if the machine has system calls or instructions to clear
+the instruction cache directly, you can define the following macro.
+
+@table @code
+@findex CLEAR_INSN_CACHE
+@item CLEAR_INSN_CACHE (@var{BEG}, @var{END})
+If defined, expands to a C expression clearing the @emph{instruction
+cache} in the specified interval. If it is not defined, and the macro
+INSN_CACHE_SIZE is defined, some generic code is generated to clear the
+cache. The definition of this macro would typically be a series of
+@code{asm} statements. Both @var{BEG} and @var{END} are both pointer
+expressions.
+@end table
+
+To use a standard subroutine, define the following macro. In addition,
+you must make sure that the instructions in a trampoline fill an entire
+cache line with identical instructions, or else ensure that the
+beginning of the trampoline code is always aligned at the same point in
+its cache line. Look in @file{m68k.h} as a guide.
+
+@table @code
+@findex TRANSFER_FROM_TRAMPOLINE
+@item TRANSFER_FROM_TRAMPOLINE
+Define this macro if trampolines need a special subroutine to do their
+work. The macro should expand to a series of @code{asm} statements
+which will be compiled with GNU CC. They go in a library function named
+@code{__transfer_from_trampoline}.
+
+If you need to avoid executing the ordinary prologue code of a compiled
+C function when you jump to the subroutine, you can do so by placing a
+special label of your own in the assembler code. Use one @code{asm}
+statement to generate an assembler label, and another to make the label
+global. Then trampolines can use that label to jump directly to your
+special assembler code.
+@end table
+
+@node Library Calls
+@section Implicit Calls to Library Routines
+@cindex library subroutine names
+@cindex @file{libgcc.a}
+
+@c prevent bad page break with this line
+Here is an explanation of implicit calls to library routines.
+
+@table @code
+@findex MULSI3_LIBCALL
+@item MULSI3_LIBCALL
+A C string constant giving the name of the function to call for
+multiplication of one signed full-word by another. If you do not
+define this macro, the default name is used, which is @code{__mulsi3},
+a function defined in @file{libgcc.a}.
+
+@findex DIVSI3_LIBCALL
+@item DIVSI3_LIBCALL
+A C string constant giving the name of the function to call for
+division of one signed full-word by another. If you do not define
+this macro, the default name is used, which is @code{__divsi3}, a
+function defined in @file{libgcc.a}.
+
+@findex UDIVSI3_LIBCALL
+@item UDIVSI3_LIBCALL
+A C string constant giving the name of the function to call for
+division of one unsigned full-word by another. If you do not define
+this macro, the default name is used, which is @code{__udivsi3}, a
+function defined in @file{libgcc.a}.
+
+@findex MODSI3_LIBCALL
+@item MODSI3_LIBCALL
+A C string constant giving the name of the function to call for the
+remainder in division of one signed full-word by another. If you do
+not define this macro, the default name is used, which is
+@code{__modsi3}, a function defined in @file{libgcc.a}.
+
+@findex UMODSI3_LIBCALL
+@item UMODSI3_LIBCALL
+A C string constant giving the name of the function to call for the
+remainder in division of one unsigned full-word by another. If you do
+not define this macro, the default name is used, which is
+@code{__umodsi3}, a function defined in @file{libgcc.a}.
+
+@findex MULDI3_LIBCALL
+@item MULDI3_LIBCALL
+A C string constant giving the name of the function to call for
+multiplication of one signed double-word by another. If you do not
+define this macro, the default name is used, which is @code{__muldi3},
+a function defined in @file{libgcc.a}.
+
+@findex DIVDI3_LIBCALL
+@item DIVDI3_LIBCALL
+A C string constant giving the name of the function to call for
+division of one signed double-word by another. If you do not define
+this macro, the default name is used, which is @code{__divdi3}, a
+function defined in @file{libgcc.a}.
+
+@findex UDIVDI3_LIBCALL
+@item UDIVDI3_LIBCALL
+A C string constant giving the name of the function to call for
+division of one unsigned full-word by another. If you do not define
+this macro, the default name is used, which is @code{__udivdi3}, a
+function defined in @file{libgcc.a}.
+
+@findex MODDI3_LIBCALL
+@item MODDI3_LIBCALL
+A C string constant giving the name of the function to call for the
+remainder in division of one signed double-word by another. If you do
+not define this macro, the default name is used, which is
+@code{__moddi3}, a function defined in @file{libgcc.a}.
+
+@findex UMODDI3_LIBCALL
+@item UMODDI3_LIBCALL
+A C string constant giving the name of the function to call for the
+remainder in division of one unsigned full-word by another. If you do
+not define this macro, the default name is used, which is
+@code{__umoddi3}, a function defined in @file{libgcc.a}.
+
+@findex INIT_TARGET_OPTABS
+@item INIT_TARGET_OPTABS
+Define this macro as a C statement that declares additional library
+routines renames existing ones. @code{init_optabs} calls this macro after
+initializing all the normal library routines.
+
+@findex TARGET_EDOM
+@cindex @code{EDOM}, implicit usage
+@item TARGET_EDOM
+The value of @code{EDOM} on the target machine, as a C integer constant
+expression. If you don't define this macro, GNU CC does not attempt to
+deposit the value of @code{EDOM} into @code{errno} directly. Look in
+@file{/usr/include/errno.h} to find the value of @code{EDOM} on your
+system.
+
+If you do not define @code{TARGET_EDOM}, then compiled code reports
+domain errors by calling the library function and letting it report the
+error. If mathematical functions on your system use @code{matherr} when
+there is an error, then you should leave @code{TARGET_EDOM} undefined so
+that @code{matherr} is used normally.
+
+@findex GEN_ERRNO_RTX
+@cindex @code{errno}, implicit usage
+@item GEN_ERRNO_RTX
+Define this macro as a C expression to create an rtl expression that
+refers to the global ``variable'' @code{errno}. (On certain systems,
+@code{errno} may not actually be a variable.) If you don't define this
+macro, a reasonable default is used.
+
+@findex TARGET_MEM_FUNCTIONS
+@cindex @code{bcopy}, implicit usage
+@cindex @code{memcpy}, implicit usage
+@cindex @code{bzero}, implicit usage
+@cindex @code{memset}, implicit usage
+@item TARGET_MEM_FUNCTIONS
+Define this macro if GNU CC should generate calls to the System V
+(and ANSI C) library functions @code{memcpy} and @code{memset}
+rather than the BSD functions @code{bcopy} and @code{bzero}.
+
+@findex LIBGCC_NEEDS_DOUBLE
+@item LIBGCC_NEEDS_DOUBLE
+Define this macro if only @code{float} arguments cannot be passed to
+library routines (so they must be converted to @code{double}). This
+macro affects both how library calls are generated and how the library
+routines in @file{libgcc1.c} accept their arguments. It is useful on
+machines where floating and fixed point arguments are passed
+differently, such as the i860.
+
+@findex FLOAT_ARG_TYPE
+@item FLOAT_ARG_TYPE
+Define this macro to override the type used by the library routines to
+pick up arguments of type @code{float}. (By default, they use a union
+of @code{float} and @code{int}.)
+
+The obvious choice would be @code{float}---but that won't work with
+traditional C compilers that expect all arguments declared as @code{float}
+to arrive as @code{double}. To avoid this conversion, the library routines
+ask for the value as some other type and then treat it as a @code{float}.
+
+On some systems, no other type will work for this. For these systems,
+you must use @code{LIBGCC_NEEDS_DOUBLE} instead, to force conversion of
+the values @code{double} before they are passed.
+
+@findex FLOATIFY
+@item FLOATIFY (@var{passed-value})
+Define this macro to override the way library routines redesignate a
+@code{float} argument as a @code{float} instead of the type it was
+passed as. The default is an expression which takes the @code{float}
+field of the union.
+
+@findex FLOAT_VALUE_TYPE
+@item FLOAT_VALUE_TYPE
+Define this macro to override the type used by the library routines to
+return values that ought to have type @code{float}. (By default, they
+use @code{int}.)
+
+The obvious choice would be @code{float}---but that won't work with
+traditional C compilers gratuitously convert values declared as
+@code{float} into @code{double}.
+
+@findex INTIFY
+@item INTIFY (@var{float-value})
+Define this macro to override the way the value of a
+@code{float}-returning library routine should be packaged in order to
+return it. These functions are actually declared to return type
+@code{FLOAT_VALUE_TYPE} (normally @code{int}).
+
+These values can't be returned as type @code{float} because traditional
+C compilers would gratuitously convert the value to a @code{double}.
+
+A local variable named @code{intify} is always available when the macro
+@code{INTIFY} is used. It is a union of a @code{float} field named
+@code{f} and a field named @code{i} whose type is
+@code{FLOAT_VALUE_TYPE} or @code{int}.
+
+If you don't define this macro, the default definition works by copying
+the value through that union.
+
+@findex nongcc_SI_type
+@item nongcc_SI_type
+Define this macro as the name of the data type corresponding to
+@code{SImode} in the system's own C compiler.
+
+You need not define this macro if that type is @code{long int}, as it usually
+is.
+
+@findex nongcc_word_type
+@item nongcc_word_type
+Define this macro as the name of the data type corresponding to the
+word_mode in the system's own C compiler.
+
+You need not define this macro if that type is @code{long int}, as it usually
+is.
+
+@findex perform_@dots{}
+@item perform_@dots{}
+Define these macros to supply explicit C statements to carry out various
+arithmetic operations on types @code{float} and @code{double} in the
+library routines in @file{libgcc1.c}. See that file for a full list
+of these macros and their arguments.
+
+On most machines, you don't need to define any of these macros, because
+the C compiler that comes with the system takes care of doing them.
+
+@findex NEXT_OBJC_RUNTIME
+@item NEXT_OBJC_RUNTIME
+Define this macro to generate code for Objective C message sending using
+the calling convention of the NeXT system. This calling convention
+involves passing the object, the selector and the method arguments all
+at once to the method-lookup library function.
+
+The default calling convention passes just the object and the selector
+to the lookup function, which returns a pointer to the method.
+@end table
+
+@node Addressing Modes
+@section Addressing Modes
+@cindex addressing modes
+
+@c prevent bad page break with this line
+This is about addressing modes.
+
+@table @code
+@findex HAVE_POST_INCREMENT
+@item HAVE_POST_INCREMENT
+Define this macro if the machine supports post-increment addressing.
+
+@findex HAVE_PRE_INCREMENT
+@findex HAVE_POST_DECREMENT
+@findex HAVE_PRE_DECREMENT
+@item HAVE_PRE_INCREMENT
+@itemx HAVE_POST_DECREMENT
+@itemx HAVE_PRE_DECREMENT
+Similar for other kinds of addressing.
+
+@findex CONSTANT_ADDRESS_P
+@item CONSTANT_ADDRESS_P (@var{x})
+A C expression that is 1 if the RTX @var{x} is a constant which
+is a valid address. On most machines, this can be defined as
+@code{CONSTANT_P (@var{x})}, but a few machines are more restrictive
+in which constant addresses are supported.
+
+@findex CONSTANT_P
+@code{CONSTANT_P} accepts integer-values expressions whose values are
+not explicitly known, such as @code{symbol_ref}, @code{label_ref}, and
+@code{high} expressions and @code{const} arithmetic expressions, in
+addition to @code{const_int} and @code{const_double} expressions.
+
+@findex MAX_REGS_PER_ADDRESS
+@item MAX_REGS_PER_ADDRESS
+A number, the maximum number of registers that can appear in a valid
+memory address. Note that it is up to you to specify a value equal to
+the maximum number that @code{GO_IF_LEGITIMATE_ADDRESS} would ever
+accept.
+
+@findex GO_IF_LEGITIMATE_ADDRESS
+@item GO_IF_LEGITIMATE_ADDRESS (@var{mode}, @var{x}, @var{label})
+A C compound statement with a conditional @code{goto @var{label};}
+executed if @var{x} (an RTX) is a legitimate memory address on the
+target machine for a memory operand of mode @var{mode}.
+
+It usually pays to define several simpler macros to serve as
+subroutines for this one. Otherwise it may be too complicated to
+understand.
+
+This macro must exist in two variants: a strict variant and a
+non-strict one. The strict variant is used in the reload pass. It
+must be defined so that any pseudo-register that has not been
+allocated a hard register is considered a memory reference. In
+contexts where some kind of register is required, a pseudo-register
+with no hard register must be rejected.
+
+The non-strict variant is used in other passes. It must be defined to
+accept all pseudo-registers in every context where some kind of
+register is required.
+
+@findex REG_OK_STRICT
+Compiler source files that want to use the strict variant of this
+macro define the macro @code{REG_OK_STRICT}. You should use an
+@code{#ifdef REG_OK_STRICT} conditional to define the strict variant
+in that case and the non-strict variant otherwise.
+
+Subroutines to check for acceptable registers for various purposes (one
+for base registers, one for index registers, and so on) are typically
+among the subroutines used to define @code{GO_IF_LEGITIMATE_ADDRESS}.
+Then only these subroutine macros need have two variants; the higher
+levels of macros may be the same whether strict or not.@refill
+
+Normally, constant addresses which are the sum of a @code{symbol_ref}
+and an integer are stored inside a @code{const} RTX to mark them as
+constant. Therefore, there is no need to recognize such sums
+specifically as legitimate addresses. Normally you would simply
+recognize any @code{const} as legitimate.
+
+Usually @code{PRINT_OPERAND_ADDRESS} is not prepared to handle constant
+sums that are not marked with @code{const}. It assumes that a naked
+@code{plus} indicates indexing. If so, then you @emph{must} reject such
+naked constant sums as illegitimate addresses, so that none of them will
+be given to @code{PRINT_OPERAND_ADDRESS}.
+
+@cindex @code{ENCODE_SECTION_INFO} and address validation
+On some machines, whether a symbolic address is legitimate depends on
+the section that the address refers to. On these machines, define the
+macro @code{ENCODE_SECTION_INFO} to store the information into the
+@code{symbol_ref}, and then check for it here. When you see a
+@code{const}, you will have to look inside it to find the
+@code{symbol_ref} in order to determine the section. @xref{Assembler
+Format}.
+
+@findex saveable_obstack
+The best way to modify the name string is by adding text to the
+beginning, with suitable punctuation to prevent any ambiguity. Allocate
+the new name in @code{saveable_obstack}. You will have to modify
+@code{ASM_OUTPUT_LABELREF} to remove and decode the added text and
+output the name accordingly, and define @code{STRIP_NAME_ENCODING} to
+access the original name string.
+
+You can check the information stored here into the @code{symbol_ref} in
+the definitions of the macros @code{GO_IF_LEGITIMATE_ADDRESS} and
+@code{PRINT_OPERAND_ADDRESS}.
+
+@findex REG_OK_FOR_BASE_P
+@item REG_OK_FOR_BASE_P (@var{x})
+A C expression that is nonzero if @var{x} (assumed to be a @code{reg}
+RTX) is valid for use as a base register. For hard registers, it
+should always accept those which the hardware permits and reject the
+others. Whether the macro accepts or rejects pseudo registers must be
+controlled by @code{REG_OK_STRICT} as described above. This usually
+requires two variant definitions, of which @code{REG_OK_STRICT}
+controls the one actually used.
+
+@findex REG_OK_FOR_INDEX_P
+@item REG_OK_FOR_INDEX_P (@var{x})
+A C expression that is nonzero if @var{x} (assumed to be a @code{reg}
+RTX) is valid for use as an index register.
+
+The difference between an index register and a base register is that
+the index register may be scaled. If an address involves the sum of
+two registers, neither one of them scaled, then either one may be
+labeled the ``base'' and the other the ``index''; but whichever
+labeling is used must fit the machine's constraints of which registers
+may serve in each capacity. The compiler will try both labelings,
+looking for one that is valid, and will reload one or both registers
+only if neither labeling works.
+
+@findex LEGITIMIZE_ADDRESS
+@item LEGITIMIZE_ADDRESS (@var{x}, @var{oldx}, @var{mode}, @var{win})
+A C compound statement that attempts to replace @var{x} with a valid
+memory address for an operand of mode @var{mode}. @var{win} will be a
+C statement label elsewhere in the code; the macro definition may use
+
+@example
+GO_IF_LEGITIMATE_ADDRESS (@var{mode}, @var{x}, @var{win});
+@end example
+
+@noindent
+to avoid further processing if the address has become legitimate.
+
+@findex break_out_memory_refs
+@var{x} will always be the result of a call to @code{break_out_memory_refs},
+and @var{oldx} will be the operand that was given to that function to produce
+@var{x}.
+
+The code generated by this macro should not alter the substructure of
+@var{x}. If it transforms @var{x} into a more legitimate form, it
+should assign @var{x} (which will always be a C variable) a new value.
+
+It is not necessary for this macro to come up with a legitimate
+address. The compiler has standard ways of doing so in all cases. In
+fact, it is safe for this macro to do nothing. But often a
+machine-dependent strategy can generate better code.
+
+@findex GO_IF_MODE_DEPENDENT_ADDRESS
+@item GO_IF_MODE_DEPENDENT_ADDRESS (@var{addr}, @var{label})
+A C statement or compound statement with a conditional @code{goto
+@var{label};} executed if memory address @var{x} (an RTX) can have
+different meanings depending on the machine mode of the memory
+reference it is used for or if the address is valid for some modes
+but not others.
+
+Autoincrement and autodecrement addresses typically have mode-dependent
+effects because the amount of the increment or decrement is the size
+of the operand being addressed. Some machines have other mode-dependent
+addresses. Many RISC machines have no mode-dependent addresses.
+
+You may assume that @var{addr} is a valid address for the machine.
+
+@findex LEGITIMATE_CONSTANT_P
+@item LEGITIMATE_CONSTANT_P (@var{x})
+A C expression that is nonzero if @var{x} is a legitimate constant for
+an immediate operand on the target machine. You can assume that
+@var{x} satisfies @code{CONSTANT_P}, so you need not check this. In fact,
+@samp{1} is a suitable definition for this macro on machines where
+anything @code{CONSTANT_P} is valid.@refill
+@end table
+
+@node Condition Code
+@section Condition Code Status
+@cindex condition code status
+
+@c prevent bad page break with this line
+This describes the condition code status.
+
+@findex cc_status
+The file @file{conditions.h} defines a variable @code{cc_status} to
+describe how the condition code was computed (in case the interpretation of
+the condition code depends on the instruction that it was set by). This
+variable contains the RTL expressions on which the condition code is
+currently based, and several standard flags.
+
+Sometimes additional machine-specific flags must be defined in the machine
+description header file. It can also add additional machine-specific
+information by defining @code{CC_STATUS_MDEP}.
+
+@table @code
+@findex CC_STATUS_MDEP
+@item CC_STATUS_MDEP
+C code for a data type which is used for declaring the @code{mdep}
+component of @code{cc_status}. It defaults to @code{int}.
+
+This macro is not used on machines that do not use @code{cc0}.
+
+@findex CC_STATUS_MDEP_INIT
+@item CC_STATUS_MDEP_INIT
+A C expression to initialize the @code{mdep} field to ``empty''.
+The default definition does nothing, since most machines don't use
+the field anyway. If you want to use the field, you should probably
+define this macro to initialize it.
+
+This macro is not used on machines that do not use @code{cc0}.
+
+@findex NOTICE_UPDATE_CC
+@item NOTICE_UPDATE_CC (@var{exp}, @var{insn})
+A C compound statement to set the components of @code{cc_status}
+appropriately for an insn @var{insn} whose body is @var{exp}. It is
+this macro's responsibility to recognize insns that set the condition
+code as a byproduct of other activity as well as those that explicitly
+set @code{(cc0)}.
+
+This macro is not used on machines that do not use @code{cc0}.
+
+If there are insns that do not set the condition code but do alter
+other machine registers, this macro must check to see whether they
+invalidate the expressions that the condition code is recorded as
+reflecting. For example, on the 68000, insns that store in address
+registers do not set the condition code, which means that usually
+@code{NOTICE_UPDATE_CC} can leave @code{cc_status} unaltered for such
+insns. But suppose that the previous insn set the condition code
+based on location @samp{a4@@(102)} and the current insn stores a new
+value in @samp{a4}. Although the condition code is not changed by
+this, it will no longer be true that it reflects the contents of
+@samp{a4@@(102)}. Therefore, @code{NOTICE_UPDATE_CC} must alter
+@code{cc_status} in this case to say that nothing is known about the
+condition code value.
+
+The definition of @code{NOTICE_UPDATE_CC} must be prepared to deal
+with the results of peephole optimization: insns whose patterns are
+@code{parallel} RTXs containing various @code{reg}, @code{mem} or
+constants which are just the operands. The RTL structure of these
+insns is not sufficient to indicate what the insns actually do. What
+@code{NOTICE_UPDATE_CC} should do when it sees one is just to run
+@code{CC_STATUS_INIT}.
+
+A possible definition of @code{NOTICE_UPDATE_CC} is to call a function
+that looks at an attribute (@pxref{Insn Attributes}) named, for example,
+@samp{cc}. This avoids having detailed information about patterns in
+two places, the @file{md} file and in @code{NOTICE_UPDATE_CC}.
+
+@findex EXTRA_CC_MODES
+@item EXTRA_CC_MODES
+A list of names to be used for additional modes for condition code
+values in registers (@pxref{Jump Patterns}). These names are added
+to @code{enum machine_mode} and all have class @code{MODE_CC}. By
+convention, they should start with @samp{CC} and end with @samp{mode}.
+
+You should only define this macro if your machine does not use @code{cc0}
+and only if additional modes are required.
+
+@findex EXTRA_CC_NAMES
+@item EXTRA_CC_NAMES
+A list of C strings giving the names for the modes listed in
+@code{EXTRA_CC_MODES}. For example, the Sparc defines this macro and
+@code{EXTRA_CC_MODES} as
+
+@smallexample
+#define EXTRA_CC_MODES CC_NOOVmode, CCFPmode, CCFPEmode
+#define EXTRA_CC_NAMES "CC_NOOV", "CCFP", "CCFPE"
+@end smallexample
+
+This macro is not required if @code{EXTRA_CC_MODES} is not defined.
+
+@findex SELECT_CC_MODE
+@item SELECT_CC_MODE (@var{op}, @var{x}, @var{y})
+Returns a mode from class @code{MODE_CC} to be used when comparison
+operation code @var{op} is applied to rtx @var{x} and @var{y}. For
+example, on the Sparc, @code{SELECT_CC_MODE} is defined as (see
+@pxref{Jump Patterns} for a description of the reason for this
+definition)
+
+@smallexample
+#define SELECT_CC_MODE(OP,X,Y) \
+ (GET_MODE_CLASS (GET_MODE (X)) == MODE_FLOAT \
+ ? ((OP == EQ || OP == NE) ? CCFPmode : CCFPEmode) \
+ : ((GET_CODE (X) == PLUS || GET_CODE (X) == MINUS \
+ || GET_CODE (X) == NEG) \
+ ? CC_NOOVmode : CCmode))
+@end smallexample
+
+You need not define this macro if @code{EXTRA_CC_MODES} is not defined.
+
+@findex CANONICALIZE_COMPARISON
+@item CANONICALIZE_COMPARISON (@var{code}, @var{op0}, @var{op1})
+One some machines not all possible comparisons are defined, but you can
+convert an invalid comparison into a valid one. For example, the Alpha
+does not have a @code{GT} comparison, but you can use an @code{LT}
+comparison instead and swap the order of the operands.
+
+On such machines, define this macro to be a C statement to do any
+required conversions. @var{code} is the initial comparison code
+and @var{op0} and @var{op1} are the left and right operands of the
+comparison, respectively. You should modify @var{code}, @var{op0}, and
+@var{op1} as required.
+
+GNU CC will not assume that the comparison resulting from this macro is
+valid but will see if the resulting insn matches a pattern in the
+@file{md} file.
+
+You need not define this macro if it would never change the comparison
+code or operands.
+
+@findex REVERSIBLE_CC_MODE
+@item REVERSIBLE_CC_MODE (@var{mode})
+A C expression whose value is one if it is always safe to reverse a
+comparison whose mode is @var{mode}. If @code{SELECT_CC_MODE}
+can ever return @var{mode} for a floating-point inequality comparison,
+then @code{REVERSIBLE_CC_MODE (@var{mode})} must be zero.
+
+You need not define this macro if it would always returns zero or if the
+floating-point format is anything other than @code{IEEE_FLOAT_FORMAT}.
+For example, here is the definition used on the Sparc, where floating-point
+inequality comparisons are always given @code{CCFPEmode}:
+
+@smallexample
+#define REVERSIBLE_CC_MODE(MODE) ((MODE) != CCFPEmode)
+@end smallexample
+
+@end table
+
+@node Costs
+@section Describing Relative Costs of Operations
+@cindex costs of instructions
+@cindex relative costs
+@cindex speed of instructions
+
+These macros let you describe the relative speed of various operations
+on the target machine.
+
+@table @code
+@findex CONST_COSTS
+@item CONST_COSTS (@var{x}, @var{code}, @var{outer_code})
+A part of a C @code{switch} statement that describes the relative costs
+of constant RTL expressions. It must contain @code{case} labels for
+expression codes @code{const_int}, @code{const}, @code{symbol_ref},
+@code{label_ref} and @code{const_double}. Each case must ultimately
+reach a @code{return} statement to return the relative cost of the use
+of that kind of constant value in an expression. The cost may depend on
+the precise value of the constant, which is available for examination in
+@var{x}, and the rtx code of the expression in which it is contained,
+found in @var{outer_code}.
+
+@var{code} is the expression code---redundant, since it can be
+obtained with @code{GET_CODE (@var{x})}.
+
+@findex RTX_COSTS
+@findex COSTS_N_INSNS
+@item RTX_COSTS (@var{x}, @var{code}, @var{outer_code})
+Like @code{CONST_COSTS} but applies to nonconstant RTL expressions.
+This can be used, for example, to indicate how costly a multiply
+instruction is. In writing this macro, you can use the construct
+@code{COSTS_N_INSNS (@var{n})} to specify a cost equal to @var{n} fast
+instructions. @var{outer_code} is the code of the expression in which
+@var{x} is contained.
+
+This macro is optional; do not define it if the default cost assumptions
+are adequate for the target machine.
+
+@findex ADDRESS_COST
+@item ADDRESS_COST (@var{address})
+An expression giving the cost of an addressing mode that contains
+@var{address}. If not defined, the cost is computed from
+the @var{address} expression and the @code{CONST_COSTS} values.
+
+For most CISC machines, the default cost is a good approximation of the
+true cost of the addressing mode. However, on RISC machines, all
+instructions normally have the same length and execution time. Hence
+all addresses will have equal costs.
+
+In cases where more than one form of an address is known, the form with
+the lowest cost will be used. If multiple forms have the same, lowest,
+cost, the one that is the most complex will be used.
+
+For example, suppose an address that is equal to the sum of a register
+and a constant is used twice in the same basic block. When this macro
+is not defined, the address will be computed in a register and memory
+references will be indirect through that register. On machines where
+the cost of the addressing mode containing the sum is no higher than
+that of a simple indirect reference, this will produce an additional
+instruction and possibly require an additional register. Proper
+specification of this macro eliminates this overhead for such machines.
+
+Similar use of this macro is made in strength reduction of loops.
+
+@var{address} need not be valid as an address. In such a case, the cost
+is not relevant and can be any value; invalid addresses need not be
+assigned a different cost.
+
+On machines where an address involving more than one register is as
+cheap as an address computation involving only one register, defining
+@code{ADDRESS_COST} to reflect this can cause two registers to be live
+over a region of code where only one would have been if
+@code{ADDRESS_COST} were not defined in that manner. This effect should
+be considered in the definition of this macro. Equivalent costs should
+probably only be given to addresses with different numbers of registers
+on machines with lots of registers.
+
+This macro will normally either not be defined or be defined as a
+constant.
+
+@findex REGISTER_MOVE_COST
+@item REGISTER_MOVE_COST (@var{from}, @var{to})
+A C expression for the cost of moving data from a register in class
+@var{from} to one in class @var{to}. The classes are expressed using
+the enumeration values such as @code{GENERAL_REGS}. A value of 4 is the
+default; other values are interpreted relative to that.
+
+It is not required that the cost always equal 2 when @var{from} is the
+same as @var{to}; on some machines it is expensive to move between
+registers if they are not general registers.
+
+If reload sees an insn consisting of a single @code{set} between two
+hard registers, and if @code{REGISTER_MOVE_COST} applied to their
+classes returns a value of 2, reload does not check to ensure that the
+constraints of the insn are met. Setting a cost of other than 2 will
+allow reload to verify that the constraints are met. You should do this
+if the @samp{mov@var{m}} pattern's constraints do not allow such copying.
+
+@findex MEMORY_MOVE_COST
+@item MEMORY_MOVE_COST (@var{m})
+A C expression for the cost of moving data of mode @var{m} between a
+register and memory. A value of 2 is the default; this cost is relative
+to those in @code{REGISTER_MOVE_COST}.
+
+If moving between registers and memory is more expensive than between
+two registers, you should define this macro to express the relative cost.
+
+@findex BRANCH_COST
+@item BRANCH_COST
+A C expression for the cost of a branch instruction. A value of 1 is
+the default; other values are interpreted relative to that.
+@end table
+
+Here are additional macros which do not specify precise relative costs,
+but only that certain actions are more expensive than GNU CC would
+ordinarily expect.
+
+@table @code
+@findex SLOW_BYTE_ACCESS
+@item SLOW_BYTE_ACCESS
+Define this macro as a C expression which is nonzero if accessing less
+than a word of memory (i.e. a @code{char} or a @code{short}) is no
+faster than accessing a word of memory, i.e., if such access
+require more than one instruction or if there is no difference in cost
+between byte and (aligned) word loads.
+
+When this macro is not defined, the compiler will access a field by
+finding the smallest containing object; when it is defined, a fullword
+load will be used if alignment permits. Unless bytes accesses are
+faster than word accesses, using word accesses is preferable since it
+may eliminate subsequent memory access if subsequent accesses occur to
+other fields in the same word of the structure, but to different bytes.
+
+@findex SLOW_ZERO_EXTEND
+@item SLOW_ZERO_EXTEND
+Define this macro if zero-extension (of a @code{char} or @code{short}
+to an @code{int}) can be done faster if the destination is a register
+that is known to be zero.
+
+If you define this macro, you must have instruction patterns that
+recognize RTL structures like this:
+
+@smallexample
+(set (strict_low_part (subreg:QI (reg:SI @dots{}) 0)) @dots{})
+@end smallexample
+
+@noindent
+and likewise for @code{HImode}.
+
+@findex SLOW_UNALIGNED_ACCESS
+@item SLOW_UNALIGNED_ACCESS
+Define this macro to be the value 1 if unaligned accesses have a cost
+many times greater than aligned accesses, for example if they are
+emulated in a trap handler.
+
+When this macro is non-zero, the compiler will act as if
+@code{STRICT_ALIGNMENT} were non-zero when generating code for block
+moves. This can cause significantly more instructions to be produced.
+Therefore, do not set this macro non-zero if unaligned accesses only add a
+cycle or two to the time for a memory access.
+
+If the value of this macro is always zero, it need not be defined.
+
+@findex DONT_REDUCE_ADDR
+@item DONT_REDUCE_ADDR
+Define this macro to inhibit strength reduction of memory addresses.
+(On some machines, such strength reduction seems to do harm rather
+than good.)
+
+@findex MOVE_RATIO
+@item MOVE_RATIO
+The number of scalar move insns which should be generated instead of a
+string move insn or a library call. Increasing the value will always
+make code faster, but eventually incurs high cost in increased code size.
+
+If you don't define this, a reasonable default is used.
+
+@findex NO_FUNCTION_CSE
+@item NO_FUNCTION_CSE
+Define this macro if it is as good or better to call a constant
+function address than to call an address kept in a register.
+
+@findex NO_RECURSIVE_FUNCTION_CSE
+@item NO_RECURSIVE_FUNCTION_CSE
+Define this macro if it is as good or better for a function to call
+itself with an explicit address than to call an address kept in a
+register.
+
+@findex ADJUST_COST
+@item ADJUST_COST (@var{insn}, @var{link}, @var{dep_insn}, @var{cost})
+A C statement (sans semicolon) to update the integer variable @var{cost}
+based on the relationship between @var{insn} that is dependent on
+@var{dep_insn} through the dependence @var{link}. The default is to
+make no adjustment to @var{cost}. This can be used for example to
+specify to the scheduler that an output- or anti-dependence does not
+incur the same cost as a data-dependence.
+@end table
+
+@node Sections
+@section Dividing the Output into Sections (Texts, Data, @dots{})
+@c the above section title is WAY too long. maybe cut the part between
+@c the (...)? --mew 10feb93
+
+An object file is divided into sections containing different types of
+data. In the most common case, there are three sections: the @dfn{text
+section}, which holds instructions and read-only data; the @dfn{data
+section}, which holds initialized writable data; and the @dfn{bss
+section}, which holds uninitialized data. Some systems have other kinds
+of sections.
+
+The compiler must tell the assembler when to switch sections. These
+macros control what commands to output to tell the assembler this. You
+can also define additional sections.
+
+@table @code
+@findex TEXT_SECTION_ASM_OP
+@item TEXT_SECTION_ASM_OP
+A C expression whose value is a string containing the assembler
+operation that should precede instructions and read-only data. Normally
+@code{".text"} is right.
+
+@findex DATA_SECTION_ASM_OP
+@item DATA_SECTION_ASM_OP
+A C expression whose value is a string containing the assembler
+operation to identify the following data as writable initialized data.
+Normally @code{".data"} is right.
+
+@findex SHARED_SECTION_ASM_OP
+@item SHARED_SECTION_ASM_OP
+if defined, a C expression whose value is a string containing the
+assembler operation to identify the following data as shared data. If
+not defined, @code{DATA_SECTION_ASM_OP} will be used.
+
+@findex INIT_SECTION_ASM_OP
+@item INIT_SECTION_ASM_OP
+if defined, a C expression whose value is a string containing the
+assembler operation to identify the following data as initialization
+code. If not defined, GNU CC will assume such a section does not
+exist.
+
+@findex EXTRA_SECTIONS
+@findex in_text
+@findex in_data
+@item EXTRA_SECTIONS
+A list of names for sections other than the standard two, which are
+@code{in_text} and @code{in_data}. You need not define this macro
+on a system with no other sections (that GCC needs to use).
+
+@findex EXTRA_SECTION_FUNCTIONS
+@findex text_section
+@findex data_section
+@item EXTRA_SECTION_FUNCTIONS
+One or more functions to be defined in @file{varasm.c}. These
+functions should do jobs analogous to those of @code{text_section} and
+@code{data_section}, for your additional sections. Do not define this
+macro if you do not define @code{EXTRA_SECTIONS}.
+
+@findex READONLY_DATA_SECTION
+@item READONLY_DATA_SECTION
+On most machines, read-only variables, constants, and jump tables are
+placed in the text section. If this is not the case on your machine,
+this macro should be defined to be the name of a function (either
+@code{data_section} or a function defined in @code{EXTRA_SECTIONS}) that
+switches to the section to be used for read-only items.
+
+If these items should be placed in the text section, this macro should
+not be defined.
+
+@findex SELECT_SECTION
+@item SELECT_SECTION (@var{exp}, @var{reloc})
+A C statement or statements to switch to the appropriate section for
+output of @var{exp}. You can assume that @var{exp} is either a
+@code{VAR_DECL} node or a constant of some sort. @var{reloc}
+indicates whether the initial value of @var{exp} requires link-time
+relocations. Select the section by calling @code{text_section} or one
+of the alternatives for other sections.
+
+Do not define this macro if you put all read-only variables and
+constants in the read-only data section (usually the text section).
+
+@findex SELECT_RTX_SECTION
+@item SELECT_RTX_SECTION (@var{mode}, @var{rtx})
+A C statement or statements to switch to the appropriate section for
+output of @var{rtx} in mode @var{mode}. You can assume that @var{rtx}
+is some kind of constant in RTL. The argument @var{mode} is redundant
+except in the case of a @code{const_int} rtx. Select the section by
+calling @code{text_section} or one of the alternatives for other
+sections.
+
+Do not define this macro if you put all constants in the read-only
+data section.
+
+@findex JUMP_TABLES_IN_TEXT_SECTION
+@item JUMP_TABLES_IN_TEXT_SECTION
+Define this macro if jump tables (for @code{tablejump} insns) should be
+output in the text section, along with the assembler instructions.
+Otherwise, the readonly data section is used.
+
+This macro is irrelevant if there is no separate readonly data section.
+
+@findex ENCODE_SECTION_INFO
+@item ENCODE_SECTION_INFO (@var{decl})
+Define this macro if references to a symbol must be treated differently
+depending on something about the variable or function named by the
+symbol (such as what section it is in).
+
+The macro definition, if any, is executed immediately after the rtl for
+@var{decl} has been created and stored in @code{DECL_RTL (@var{decl})}.
+The value of the rtl will be a @code{mem} whose address is a
+@code{symbol_ref}.
+
+@cindex @code{SYMBOL_REF_FLAG}, in @code{ENCODE_SECTION_INFO}
+The usual thing for this macro to do is to record a flag in the
+@code{symbol_ref} (such as @code{SYMBOL_REF_FLAG}) or to store a
+modified name string in the @code{symbol_ref} (if one bit is not enough
+information).
+
+@findex STRIP_NAME_ENCODING
+@item STRIP_NAME_ENCODING (@var{var}, @var{sym_name})
+Decode @var{sym_name} and store the real name part in @var{var}, sans
+the characters that encode section info. Define this macro if
+@code{ENCODE_SECTION_INFO} alters the symbol's name string.
+@end table
+
+@node PIC
+@section Position Independent Code
+@cindex position independent code
+@cindex PIC
+
+This section describes macros that help implement generation of position
+independent code. Simply defining these macros is not enough to
+generate valid PIC; you must also add support to the macros
+@code{GO_IF_LEGITIMATE_ADDRESS} and @code{PRINT_OPERAND_ADDRESS}, as
+well as @code{LEGITIMIZE_ADDRESS}. You must modify the definition of
+@samp{movsi} to do something appropriate when the source operand
+contains a symbolic address. You may also need to alter the handling of
+switch statements so that they use relative addresses.
+@c i rearranged the order of the macros above to try to force one of
+@c them to the next line, to eliminate an overfull hbox. --mew 10feb93
+
+@table @code
+@findex PIC_OFFSET_TABLE_REGNUM
+@item PIC_OFFSET_TABLE_REGNUM
+The register number of the register used to address a table of static
+data addresses in memory. In some cases this register is defined by a
+processor's ``application binary interface'' (ABI). When this macro
+is defined, RTL is generated for this register once, as with the stack
+pointer and frame pointer registers. If this macro is not defined, it
+is up to the machine-dependent files to allocate such a register (if
+necessary).
+
+findex PIC_OFFSET_TABLE_REG_CALL_CLOBBERED
+@item PIC_OFFSET_TABLE_REG_CALL_CLOBBERED
+Define this macro if the register defined by
+@code{PIC_OFFSET_TABLE_REGNUM} is clobbered by calls. Do not define
+this macro if @code{PPIC_OFFSET_TABLE_REGNUM} is not defined.
+
+@findex FINALIZE_PIC
+@item FINALIZE_PIC
+By generating position-independent code, when two different programs (A
+and B) share a common library (libC.a), the text of the library can be
+shared whether or not the library is linked at the same address for both
+programs. In some of these environments, position-independent code
+requires not only the use of different addressing modes, but also
+special code to enable the use of these addressing modes.
+
+The @code{FINALIZE_PIC} macro serves as a hook to emit these special
+codes once the function is being compiled into assembly code, but not
+before. (It is not done before, because in the case of compiling an
+inline function, it would lead to multiple PIC prologues being
+included in functions which used inline functions and were compiled to
+assembly language.)
+
+@findex LEGITIMATE_PIC_OPERAND_P
+@item LEGITIMATE_PIC_OPERAND_P (@var{x})
+A C expression that is nonzero if @var{x} is a legitimate immediate
+operand on the target machine when generating position independent code.
+You can assume that @var{x} satisfies @code{CONSTANT_P}, so you need not
+check this. You can also assume @var{flag_pic} is true, so you need not
+check it either. You need not define this macro if all constants
+(including @code{SYMBOL_REF}) can be immediate operands when generating
+position independent code.
+@end table
+
+@node Assembler Format
+@section Defining the Output Assembler Language
+
+This section describes macros whose principal purpose is to describe how
+to write instructions in assembler language--rather than what the
+instructions do.
+
+@menu
+* File Framework:: Structural information for the assembler file.
+* Data Output:: Output of constants (numbers, strings, addresses).
+* Uninitialized Data:: Output of uninitialized variables.
+* Label Output:: Output and generation of labels.
+* Initialization:: General principles of initialization
+ and termination routines.
+* Macros for Initialization::
+ Specific macros that control the handling of
+ initialization and termination routines.
+* Instruction Output:: Output of actual instructions.
+* Dispatch Tables:: Output of jump tables.
+* Alignment Output:: Pseudo ops for alignment and skipping data.
+@end menu
+
+@node File Framework
+@subsection The Overall Framework of an Assembler File
+@cindex assembler format
+@cindex output of assembler code
+
+@c prevent bad page break with this line
+This describes the overall framework of an assembler file.
+
+@table @code
+@findex ASM_FILE_START
+@item ASM_FILE_START (@var{stream})
+A C expression which outputs to the stdio stream @var{stream}
+some appropriate text to go at the start of an assembler file.
+
+Normally this macro is defined to output a line containing
+@samp{#NO_APP}, which is a comment that has no effect on most
+assemblers but tells the GNU assembler that it can save time by not
+checking for certain assembler constructs.
+
+On systems that use SDB, it is necessary to output certain commands;
+see @file{attasm.h}.
+
+@findex ASM_FILE_END
+@item ASM_FILE_END (@var{stream})
+A C expression which outputs to the stdio stream @var{stream}
+some appropriate text to go at the end of an assembler file.
+
+If this macro is not defined, the default is to output nothing
+special at the end of the file. Most systems don't require any
+definition.
+
+On systems that use SDB, it is necessary to output certain commands;
+see @file{attasm.h}.
+
+@findex ASM_IDENTIFY_GCC
+@item ASM_IDENTIFY_GCC (@var{file})
+A C statement to output assembler commands which will identify
+the object file as having been compiled with GNU CC (or another
+GNU compiler).
+
+If you don't define this macro, the string @samp{gcc_compiled.:}
+is output. This string is calculated to define a symbol which,
+on BSD systems, will never be defined for any other reason.
+GDB checks for the presence of this symbol when reading the
+symbol table of an executable.
+
+On non-BSD systems, you must arrange communication with GDB in
+some other fashion. If GDB is not used on your system, you can
+define this macro with an empty body.
+
+@findex ASM_COMMENT_START
+@item ASM_COMMENT_START
+A C string constant describing how to begin a comment in the target
+assembler language. The compiler assumes that the comment will end at
+the end of the line.
+
+@findex ASM_APP_ON
+@item ASM_APP_ON
+A C string constant for text to be output before each @code{asm}
+statement or group of consecutive ones. Normally this is
+@code{"#APP"}, which is a comment that has no effect on most
+assemblers but tells the GNU assembler that it must check the lines
+that follow for all valid assembler constructs.
+
+@findex ASM_APP_OFF
+@item ASM_APP_OFF
+A C string constant for text to be output after each @code{asm}
+statement or group of consecutive ones. Normally this is
+@code{"#NO_APP"}, which tells the GNU assembler to resume making the
+time-saving assumptions that are valid for ordinary compiler output.
+
+@findex ASM_OUTPUT_SOURCE_FILENAME
+@item ASM_OUTPUT_SOURCE_FILENAME (@var{stream}, @var{name})
+A C statement to output COFF information or DWARF debugging information
+which indicates that filename @var{name} is the current source file to
+the stdio stream @var{stream}.
+
+This macro need not be defined if the standard form of output
+for the file format in use is appropriate.
+
+@findex ASM_OUTPUT_SOURCE_LINE
+@item ASM_OUTPUT_SOURCE_LINE (@var{stream}, @var{line})
+A C statement to output DBX or SDB debugging information before code
+for line number @var{line} of the current source file to the
+stdio stream @var{stream}.
+
+This macro need not be defined if the standard form of debugging
+information for the debugger in use is appropriate.
+
+@findex ASM_OUTPUT_IDENT
+@item ASM_OUTPUT_IDENT (@var{stream}, @var{string})
+A C statement to output something to the assembler file to handle a
+@samp{#ident} directive containing the text @var{string}. If this
+macro is not defined, nothing is output for a @samp{#ident} directive.
+
+@findex ASM_OUTPUT_SECTION_NAME
+@item ASM_OUTPUT_SECTION_NAME (@var{stream}, @var{string})
+A C statement to output something to the assembler file to switch to the
+section contained in @var{string}. Some target formats do not support
+arbitrary sections. Do not define this macro in such cases.
+
+At present this macro is only used to support section attributes.
+When this macro is undefined, section attributes are disabled.
+
+@findex OBJC_PROLOGUE
+@item OBJC_PROLOGUE
+A C statement to output any assembler statements which are required to
+precede any Objective C object definitions or message sending. The
+statement is executed only when compiling an Objective C program.
+@end table
+
+@need 2000
+@node Data Output
+@subsection Output of Data
+
+@c prevent bad page break with this line
+This describes data output.
+
+@table @code
+@findex ASM_OUTPUT_LONG_DOUBLE
+@findex ASM_OUTPUT_DOUBLE
+@findex ASM_OUTPUT_FLOAT
+@item ASM_OUTPUT_LONG_DOUBLE (@var{stream}, @var{value})
+@itemx ASM_OUTPUT_DOUBLE (@var{stream}, @var{value})
+@itemx ASM_OUTPUT_FLOAT (@var{stream}, @var{value})
+@itemx ASM_OUTPUT_THREE_QUARTER_FLOAT (@var{stream}, @var{value})
+@itemx ASM_OUTPUT_SHORT_FLOAT (@var{stream}, @var{value})
+@itemx ASM_OUTPUT_BYTE_FLOAT (@var{stream}, @var{value})
+A C statement to output to the stdio stream @var{stream} an assembler
+instruction to assemble a floating-point constant of @code{TFmode},
+@code{DFmode}, @code{SFmode}, @code{TQFmode}, @code{HFmode}, or
+@code{QFmode}, respectively, whose value is @var{value}. @var{value}
+will be a C expression of type @code{REAL_VALUE_TYPE}. Macros such as
+@code{REAL_VALUE_TO_TARGET_DOUBLE} are useful for writing these
+definitions.
+
+@findex ASM_OUTPUT_QUADRUPLE_INT
+@findex ASM_OUTPUT_DOUBLE_INT
+@findex ASM_OUTPUT_INT
+@findex ASM_OUTPUT_SHORT
+@findex ASM_OUTPUT_CHAR
+@findex output_addr_const
+@item ASM_OUTPUT_QUADRUPLE_INT (@var{stream}, @var{exp})
+@itemx ASM_OUTPUT_DOUBLE_INT (@var{stream}, @var{exp})
+@itemx ASM_OUTPUT_INT (@var{stream}, @var{exp})
+@itemx ASM_OUTPUT_SHORT (@var{stream}, @var{exp})
+@itemx ASM_OUTPUT_CHAR (@var{stream}, @var{exp})
+A C statement to output to the stdio stream @var{stream} an assembler
+instruction to assemble an integer of 16, 8, 4, 2 or 1 bytes,
+respectively, whose value is @var{value}. The argument @var{exp} will
+be an RTL expression which represents a constant value. Use
+@samp{output_addr_const (@var{stream}, @var{exp})} to output this value
+as an assembler expression.@refill
+
+For sizes larger than @code{UNITS_PER_WORD}, if the action of a macro
+would be identical to repeatedly calling the macro corresponding to
+a size of @code{UNITS_PER_WORD}, once for each word, you need not define
+the macro.
+
+@findex ASM_OUTPUT_BYTE
+@item ASM_OUTPUT_BYTE (@var{stream}, @var{value})
+A C statement to output to the stdio stream @var{stream} an assembler
+instruction to assemble a single byte containing the number @var{value}.
+
+@findex ASM_BYTE_OP
+@item ASM_BYTE_OP
+A C string constant giving the pseudo-op to use for a sequence of
+single-byte constants. If this macro is not defined, the default is
+@code{"byte"}.
+
+@findex ASM_OUTPUT_ASCII
+@item ASM_OUTPUT_ASCII (@var{stream}, @var{ptr}, @var{len})
+A C statement to output to the stdio stream @var{stream} an assembler
+instruction to assemble a string constant containing the @var{len}
+bytes at @var{ptr}. @var{ptr} will be a C expression of type
+@code{char *} and @var{len} a C expression of type @code{int}.
+
+If the assembler has a @code{.ascii} pseudo-op as found in the
+Berkeley Unix assembler, do not define the macro
+@code{ASM_OUTPUT_ASCII}.
+
+@findex ASM_OUTPUT_POOL_PROLOGUE
+@item ASM_OUTPUT_POOL_PROLOGUE (@var{file} @var{funname} @var{fundecl} @var{size})
+A C statement to output assembler commands to define the start of the
+constant pool for a function. @var{funname} is a string giving
+the name of the function. Should the return type of the function
+be required, it can be obtained via @var{fundecl}. @var{size}
+is the size, in bytes, of the constant pool that will be written
+immediately after this call.
+
+If no constant-pool prefix is required, the usual case, this macro need
+not be defined.
+
+@findex ASM_OUTPUT_SPECIAL_POOL_ENTRY
+@item ASM_OUTPUT_SPECIAL_POOL_ENTRY (@var{file}, @var{x}, @var{mode}, @var{align}, @var{labelno}, @var{jumpto})
+A C statement (with or without semicolon) to output a constant in the
+constant pool, if it needs special treatment. (This macro need not do
+anything for RTL expressions that can be output normally.)
+
+The argument @var{file} is the standard I/O stream to output the
+assembler code on. @var{x} is the RTL expression for the constant to
+output, and @var{mode} is the machine mode (in case @var{x} is a
+@samp{const_int}). @var{align} is the required alignment for the value
+@var{x}; you should output an assembler directive to force this much
+alignment.
+
+The argument @var{labelno} is a number to use in an internal label for
+the address of this pool entry. The definition of this macro is
+responsible for outputting the label definition at the proper place.
+Here is how to do this:
+
+@example
+ASM_OUTPUT_INTERNAL_LABEL (@var{file}, "LC", @var{labelno});
+@end example
+
+When you output a pool entry specially, you should end with a
+@code{goto} to the label @var{jumpto}. This will prevent the same pool
+entry from being output a second time in the usual manner.
+
+You need not define this macro if it would do nothing.
+
+@findex IS_ASM_LOGICAL_LINE_SEPARATOR
+@item IS_ASM_LOGICAL_LINE_SEPARATOR (@var{C})
+Define this macro as a C expression which is nonzero if @var{C} is
+used as a logical line separator by the assembler.
+
+If you do not define this macro, the default is that only
+the character @samp{;} is treated as a logical line separator.
+
+
+@findex ASM_OPEN_PAREN
+@findex ASM_CLOSE_PAREN
+@item ASM_OPEN_PAREN
+@itemx ASM_CLOSE_PAREN
+These macros are defined as C string constant, describing the syntax
+in the assembler for grouping arithmetic expressions. The following
+definitions are correct for most assemblers:
+
+@example
+#define ASM_OPEN_PAREN "("
+#define ASM_CLOSE_PAREN ")"
+@end example
+@end table
+
+ These macros are provided by @file{real.h} for writing the definitions
+of @code{ASM_OUTPUT_DOUBLE} and the like:
+
+@table @code
+@item REAL_VALUE_TO_TARGET_SINGLE (@var{x}, @var{l})
+@itemx REAL_VALUE_TO_TARGET_DOUBLE (@var{x}, @var{l})
+@itemx REAL_VALUE_TO_TARGET_LONG_DOUBLE (@var{x}, @var{l})
+@findex REAL_VALUE_TO_TARGET_SINGLE
+@findex REAL_VALUE_TO_TARGET_DOUBLE
+@findex REAL_VALUE_TO_TARGET_LONG_DOUBLE
+These translate @var{x}, of type @code{REAL_VALUE_TYPE}, to the target's
+floating point representation, and store its bit pattern in the array of
+@code{long int} whose address is @var{l}. The number of elements in the
+output array is determined by the size of the desired target floating
+point data type: 32 bits of it go in each @code{long int} array
+element. Each array element holds 32 bits of the result, even if
+@code{long int} is wider than 32 bits on the host machine.
+
+The array element values are designed so that you can print them out
+using @code{fprintf} in the order they should appear in the target
+machine's memory.
+
+@item REAL_VALUE_TO_DECIMAL (@var{x}, @var{format}, @var{string})
+@findex REAL_VALUE_TO_DECIMAL
+This macro converts @var{x}, of type @code{REAL_VALUE_TYPE}, to a
+decimal number and stores it as a string into @var{string}.
+You must pass, as @var{string}, the address of a long enough block
+of space to hold the result.
+
+The argument @var{format} is a @code{printf}-specification that serves
+as a suggestion for how to format the output string.
+@end table
+
+@node Uninitialized Data
+@subsection Output of Uninitialized Variables
+
+Each of the macros in this section is used to do the whole job of
+outputting a single uninitialized variable.
+
+@table @code
+@findex ASM_OUTPUT_COMMON
+@item ASM_OUTPUT_COMMON (@var{stream}, @var{name}, @var{size}, @var{rounded})
+A C statement (sans semicolon) to output to the stdio stream
+@var{stream} the assembler definition of a common-label named
+@var{name} whose size is @var{size} bytes. The variable @var{rounded}
+is the size rounded up to whatever alignment the caller wants.
+
+Use the expression @code{assemble_name (@var{stream}, @var{name})} to
+output the name itself; before and after that, output the additional
+assembler syntax for defining the name, and a newline.
+
+This macro controls how the assembler definitions of uninitialized
+global variables are output.
+
+@findex ASM_OUTPUT_ALIGNED_COMMON
+@item ASM_OUTPUT_ALIGNED_COMMON (@var{stream}, @var{name}, @var{size}, @var{alignment})
+Like @code{ASM_OUTPUT_COMMON} except takes the required alignment as a
+separate, explicit argument. If you define this macro, it is used in
+place of @code{ASM_OUTPUT_COMMON}, and gives you more flexibility in
+handling the required alignment of the variable. The alignment is specified
+as the number of bits.
+
+@findex ASM_OUTPUT_SHARED_COMMON
+@item ASM_OUTPUT_SHARED_COMMON (@var{stream}, @var{name}, @var{size}, @var{rounded})
+If defined, it is similar to @code{ASM_OUTPUT_COMMON}, except that it
+is used when @var{name} is shared. If not defined, @code{ASM_OUTPUT_COMMON}
+will be used.
+
+@findex ASM_OUTPUT_LOCAL
+@item ASM_OUTPUT_LOCAL (@var{stream}, @var{name}, @var{size}, @var{rounded})
+A C statement (sans semicolon) to output to the stdio stream
+@var{stream} the assembler definition of a local-common-label named
+@var{name} whose size is @var{size} bytes. The variable @var{rounded}
+is the size rounded up to whatever alignment the caller wants.
+
+Use the expression @code{assemble_name (@var{stream}, @var{name})} to
+output the name itself; before and after that, output the additional
+assembler syntax for defining the name, and a newline.
+
+This macro controls how the assembler definitions of uninitialized
+static variables are output.
+
+@findex ASM_OUTPUT_ALIGNED_LOCAL
+@item ASM_OUTPUT_ALIGNED_LOCAL (@var{stream}, @var{name}, @var{size}, @var{alignment})
+Like @code{ASM_OUTPUT_LOCAL} except takes the required alignment as a
+separate, explicit argument. If you define this macro, it is used in
+place of @code{ASM_OUTPUT_LOCAL}, and gives you more flexibility in
+handling the required alignment of the variable. The alignment is specified
+as the number of bits.
+
+@findex ASM_OUTPUT_SHARED_LOCAL
+@item ASM_OUTPUT_SHARED_LOCAL (@var{stream}, @var{name}, @var{size}, @var{rounded})
+If defined, it is similar to @code{ASM_OUTPUT_LOCAL}, except that it
+is used when @var{name} is shared. If not defined, @code{ASM_OUTPUT_LOCAL}
+will be used.
+@end table
+
+@node Label Output
+@subsection Output and Generation of Labels
+
+@c prevent bad page break with this line
+This is about outputting labels.
+
+@table @code
+@findex ASM_OUTPUT_LABEL
+@findex assemble_name
+@item ASM_OUTPUT_LABEL (@var{stream}, @var{name})
+A C statement (sans semicolon) to output to the stdio stream
+@var{stream} the assembler definition of a label named @var{name}.
+Use the expression @code{assemble_name (@var{stream}, @var{name})} to
+output the name itself; before and after that, output the additional
+assembler syntax for defining the name, and a newline.
+
+@findex ASM_DECLARE_FUNCTION_NAME
+@item ASM_DECLARE_FUNCTION_NAME (@var{stream}, @var{name}, @var{decl})
+A C statement (sans semicolon) to output to the stdio stream
+@var{stream} any text necessary for declaring the name @var{name} of a
+function which is being defined. This macro is responsible for
+outputting the label definition (perhaps using
+@code{ASM_OUTPUT_LABEL}). The argument @var{decl} is the
+@code{FUNCTION_DECL} tree node representing the function.
+
+If this macro is not defined, then the function name is defined in the
+usual manner as a label (by means of @code{ASM_OUTPUT_LABEL}).
+
+@findex ASM_DECLARE_FUNCTION_SIZE
+@item ASM_DECLARE_FUNCTION_SIZE (@var{stream}, @var{name}, @var{decl})
+A C statement (sans semicolon) to output to the stdio stream
+@var{stream} any text necessary for declaring the size of a function
+which is being defined. The argument @var{name} is the name of the
+function. The argument @var{decl} is the @code{FUNCTION_DECL} tree node
+representing the function.
+
+If this macro is not defined, then the function size is not defined.
+
+@findex ASM_DECLARE_OBJECT_NAME
+@item ASM_DECLARE_OBJECT_NAME (@var{stream}, @var{name}, @var{decl})
+A C statement (sans semicolon) to output to the stdio stream
+@var{stream} any text necessary for declaring the name @var{name} of an
+initialized variable which is being defined. This macro must output the
+label definition (perhaps using @code{ASM_OUTPUT_LABEL}). The argument
+@var{decl} is the @code{VAR_DECL} tree node representing the variable.
+
+If this macro is not defined, then the variable name is defined in the
+usual manner as a label (by means of @code{ASM_OUTPUT_LABEL}).
+
+@findex ASM_FINISH_DECLARE_OBJECT
+@item ASM_FINISH_DECLARE_OBJECT (@var{stream}, @var{decl}, @var{toplevel}, @var{atend})
+A C statement (sans semicolon) to finish up declaring a variable name
+once the compiler has processed its initializer fully and thus has had a
+chance to determine the size of an array when controlled by an
+initializer. This is used on systems where it's necessary to declare
+something about the size of the object.
+
+If you don't define this macro, that is equivalent to defining it to do
+nothing.
+
+@findex ASM_GLOBALIZE_LABEL
+@item ASM_GLOBALIZE_LABEL (@var{stream}, @var{name})
+A C statement (sans semicolon) to output to the stdio stream
+@var{stream} some commands that will make the label @var{name} global;
+that is, available for reference from other files. Use the expression
+@code{assemble_name (@var{stream}, @var{name})} to output the name
+itself; before and after that, output the additional assembler syntax
+for making that name global, and a newline.
+
+@findex ASM_OUTPUT_EXTERNAL
+@item ASM_OUTPUT_EXTERNAL (@var{stream}, @var{decl}, @var{name})
+A C statement (sans semicolon) to output to the stdio stream
+@var{stream} any text necessary for declaring the name of an external
+symbol named @var{name} which is referenced in this compilation but
+not defined. The value of @var{decl} is the tree node for the
+declaration.
+
+This macro need not be defined if it does not need to output anything.
+The GNU assembler and most Unix assemblers don't require anything.
+
+@findex ASM_OUTPUT_EXTERNAL_LIBCALL
+@item ASM_OUTPUT_EXTERNAL_LIBCALL (@var{stream}, @var{symref})
+A C statement (sans semicolon) to output on @var{stream} an assembler
+pseudo-op to declare a library function name external. The name of the
+library function is given by @var{symref}, which has type @code{rtx} and
+is a @code{symbol_ref}.
+
+This macro need not be defined if it does not need to output anything.
+The GNU assembler and most Unix assemblers don't require anything.
+
+@findex ASM_OUTPUT_LABELREF
+@item ASM_OUTPUT_LABELREF (@var{stream}, @var{name})
+A C statement (sans semicolon) to output to the stdio stream
+@var{stream} a reference in assembler syntax to a label named
+@var{name}. This should add @samp{_} to the front of the name, if that
+is customary on your operating system, as it is in most Berkeley Unix
+systems. This macro is used in @code{assemble_name}.
+
+@ignore @c Seems not to exist anymore.
+@findex ASM_OUTPUT_LABELREF_AS_INT
+@item ASM_OUTPUT_LABELREF_AS_INT (@var{file}, @var{label})
+Define this macro for systems that use the program @code{collect2}.
+The definition should be a C statement to output a word containing
+a reference to the label @var{label}.
+@end ignore
+
+@findex ASM_OUTPUT_INTERNAL_LABEL
+@item ASM_OUTPUT_INTERNAL_LABEL (@var{stream}, @var{prefix}, @var{num})
+A C statement to output to the stdio stream @var{stream} a label whose
+name is made from the string @var{prefix} and the number @var{num}.
+
+It is absolutely essential that these labels be distinct from the labels
+used for user-level functions and variables. Otherwise, certain programs
+will have name conflicts with internal labels.
+
+It is desirable to exclude internal labels from the symbol table of the
+object file. Most assemblers have a naming convention for labels that
+should be excluded; on many systems, the letter @samp{L} at the
+beginning of a label has this effect. You should find out what
+convention your system uses, and follow it.
+
+The usual definition of this macro is as follows:
+
+@example
+fprintf (@var{stream}, "L%s%d:\n", @var{prefix}, @var{num})
+@end example
+
+@findex ASM_GENERATE_INTERNAL_LABEL
+@item ASM_GENERATE_INTERNAL_LABEL (@var{string}, @var{prefix}, @var{num})
+A C statement to store into the string @var{string} a label whose name
+is made from the string @var{prefix} and the number @var{num}.
+
+This string, when output subsequently by @code{assemble_name}, should
+produce the output that @code{ASM_OUTPUT_INTERNAL_LABEL} would produce
+with the same @var{prefix} and @var{num}.
+
+If the string begins with @samp{*}, then @code{assemble_name} will
+output the rest of the string unchanged. It is often convenient for
+@code{ASM_GENERATE_INTERNAL_LABEL} to use @samp{*} in this way. If the
+string doesn't start with @samp{*}, then @code{ASM_OUTPUT_LABELREF} gets
+to output the string, and may change it. (Of course,
+@code{ASM_OUTPUT_LABELREF} is also part of your machine description, so
+you should know what it does on your machine.)
+
+@findex ASM_FORMAT_PRIVATE_NAME
+@item ASM_FORMAT_PRIVATE_NAME (@var{outvar}, @var{name}, @var{number})
+A C expression to assign to @var{outvar} (which is a variable of type
+@code{char *}) a newly allocated string made from the string
+@var{name} and the number @var{number}, with some suitable punctuation
+added. Use @code{alloca} to get space for the string.
+
+The string will be used as an argument to @code{ASM_OUTPUT_LABELREF} to
+produce an assembler label for an internal static variable whose name is
+@var{name}. Therefore, the string must be such as to result in valid
+assembler code. The argument @var{number} is different each time this
+macro is executed; it prevents conflicts between similarly-named
+internal static variables in different scopes.
+
+Ideally this string should not be a valid C identifier, to prevent any
+conflict with the user's own symbols. Most assemblers allow periods
+or percent signs in assembler symbols; putting at least one of these
+between the name and the number will suffice.
+
+@findex ASM_OUTPUT_DEF
+@item ASM_OUTPUT_DEF (@var{stream}, @var{name}, @var{value})
+A C statement to output to the stdio stream @var{stream} assembler code
+which defines (equates) the symbol @var{name} to have the value @var{value}.
+
+If SET_ASM_OP is defined, a default definition is provided which is
+correct for most systems.
+@findex OBJC_GEN_METHOD_LABEL
+@item OBJC_GEN_METHOD_LABEL (@var{buf}, @var{is_inst}, @var{class_name}, @var{cat_name}, @var{sel_name})
+Define this macro to override the default assembler names used for
+Objective C methods.
+
+The default name is a unique method number followed by the name of the
+class (e.g.@: @samp{_1_Foo}). For methods in categories, the name of
+the category is also included in the assembler name (e.g.@:
+@samp{_1_Foo_Bar}).
+
+These names are safe on most systems, but make debugging difficult since
+the method's selector is not present in the name. Therefore, particular
+systems define other ways of computing names.
+
+@var{buf} is an expression of type @code{char *} which gives you a
+buffer in which to store the name; its length is as long as
+@var{class_name}, @var{cat_name} and @var{sel_name} put together, plus
+50 characters extra.
+
+The argument @var{is_inst} specifies whether the method is an instance
+method or a class method; @var{class_name} is the name of the class;
+@var{cat_name} is the name of the category (or NULL if the method is not
+in a category); and @var{sel_name} is the name of the selector.
+
+On systems where the assembler can handle quoted names, you can use this
+macro to provide more human-readable names.
+@end table
+
+@node Initialization
+@subsection How Initialization Functions Are Handled
+@cindex initialization routines
+@cindex termination routines
+@cindex constructors, output of
+@cindex destructors, output of
+
+The compiled code for certain languages includes @dfn{constructors}
+(also called @dfn{initialization routines})---functions to initialize
+data in the program when the program is started. These functions need
+to be called before the program is ``started''---that is to say, before
+@code{main} is called.
+
+Compiling some languages generates @dfn{destructors} (also called
+@dfn{termination routines}) that should be called when the program
+terminates.
+
+To make the initialization and termination functions work, the compiler
+must output something in the assembler code to cause those functions to
+be called at the appropriate time. When you port the compiler to a new
+system, you need to specify how to do this.
+
+There are two major ways that GCC currently supports the execution of
+initialization and termination functions. Each way has two variants.
+Much of the structure is common to all four variations.
+
+@findex __CTOR_LIST__
+@findex __DTOR_LIST__
+The linker must build two lists of these functions---a list of
+initialization functions, called @code{__CTOR_LIST__}, and a list of
+termination functions, called @code{__DTOR_LIST__}.
+
+Each list always begins with an ignored function pointer (which may hold
+0, @minus{}1, or a count of the function pointers after it, depending on
+the environment). This is followed by a series of zero or more function
+pointers to constructors (or destructors), followed by a function
+pointer containing zero.
+
+Depending on the operating system and its executable file format, either
+@file{crtstuff.c} or @file{libgcc2.c} traverses these lists at startup
+time and exit time. Constructors are called in forward order of the
+list; destructors in reverse order.
+
+The best way to handle static constructors works only for object file
+formats which provide arbitrarily-named sections. A section is set
+aside for a list of constructors, and another for a list of destructors.
+Traditionally these are called @samp{.ctors} and @samp{.dtors}. Each
+object file that defines an initialization function also puts a word in
+the constructor section to point to that function. The linker
+accumulates all these words into one contiguous @samp{.ctors} section.
+Termination functions are handled similarly.
+
+To use this method, you need appropriate definitions of the macros
+@code{ASM_OUTPUT_CONSTRUCTOR} and @code{ASM_OUTPUT_DESTRUCTOR}. Usually
+you can get them by including @file{svr4.h}.
+
+When arbitrary sections are available, there are two variants, depending
+upon how the code in @file{crtstuff.c} is called. On systems that
+support an @dfn{init} section which is executed at program startup,
+parts of @file{crtstuff.c} are compiled into that section. The
+program is linked by the @code{gcc} driver like this:
+
+@example
+ld -o @var{output_file} crtbegin.o @dots{} crtend.o -lgcc
+@end example
+
+The head of a function (@code{__do_global_ctors}) appears in the init
+section of @file{crtbegin.o}; the remainder of the function appears in
+the init section of @file{crtend.o}. The linker will pull these two
+parts of the section together, making a whole function. If any of the
+user's object files linked into the middle of it contribute code, then that
+code will be executed as part of the body of @code{__do_global_ctors}.
+
+To use this variant, you must define the @code{INIT_SECTION_ASM_OP}
+macro properly.
+
+If no init section is available, do not define
+@code{INIT_SECTION_ASM_OP}. Then @code{__do_global_ctors} is built into
+the text section like all other functions, and resides in
+@file{libgcc.a}. When GCC compiles any function called @code{main}, it
+inserts a procedure call to @code{__main} as the first executable code
+after the function prologue. The @code{__main} function, also defined
+in @file{libgcc2.c}, simply calls @file{__do_global_ctors}.
+
+In file formats that don't support arbitrary sections, there are again
+two variants. In the simplest variant, the GNU linker (GNU @code{ld})
+and an `a.out' format must be used. In this case,
+@code{ASM_OUTPUT_CONSTRUCTOR} is defined to produce a @code{.stabs}
+entry of type @samp{N_SETT}, referencing the name @code{__CTOR_LIST__},
+and with the address of the void function containing the initialization
+code as its value. The GNU linker recognizes this as a request to add
+the value to a ``set''; the values are accumulated, and are eventually
+placed in the executable as a vector in the format described above, with
+a leading (ignored) count and a trailing zero element.
+@code{ASM_OUTPUT_DESTRUCTOR} is handled similarly. Since no init
+section is available, the absence of @code{INIT_SECTION_ASM_OP} causes
+the compilation of @code{main} to call @code{__main} as above, starting
+the initialization process.
+
+The last variant uses neither arbitrary sections nor the GNU linker.
+This is preferable when you want to do dynamic linking and when using
+file formats which the GNU linker does not support, such as `ECOFF'. In
+this case, @code{ASM_OUTPUT_CONSTRUCTOR} does not produce an
+@code{N_SETT} symbol; initialization and termination functions are
+recognized simply by their names. This requires an extra program in the
+linkage step, called @code{collect2}. This program pretends to be the
+linker, for use with GNU CC; it does its job by running the ordinary
+linker, but also arranges to include the vectors of initialization and
+termination functions. These functions are called via @code{__main} as
+described above.
+
+Choosing among these configuration options has been simplified by a set
+of operating-system-dependent files in the @file{config} subdirectory.
+These files define all of the relevant parameters. Usually it is
+sufficient to include one into your specific machine-dependent
+configuration file. These files are:
+
+@table @file
+@item aoutos.h
+For operating systems using the `a.out' format.
+
+@item next.h
+For operating systems using the `MachO' format.
+
+@item svr3.h
+For System V Release 3 and similar systems using `COFF' format.
+
+@item svr4.h
+For System V Release 4 and similar systems using `ELF' format.
+
+@item vms.h
+For the VMS operating system.
+@end table
+
+@ifinfo
+The following section describes the specific macros that control and
+customize the handling of initialization and termination functions.
+@end ifinfo
+
+@node Macros for Initialization
+@subsection Macros Controlling Initialization Routines
+
+Here are the macros that control how the compiler handles initialization
+and termination functions:
+
+@table @code
+@findex INIT_SECTION_ASM_OP
+@item INIT_SECTION_ASM_OP
+If defined, a C string constant for the assembler operation to identify
+the following data as initialization code. If not defined, GNU CC will
+assume such a section does not exist. When you are using special
+sections for initialization and termination functions, this macro also
+controls how @file{crtstuff.c} and @file{libgcc2.c} arrange to run the
+initialization functions.
+
+@item HAS_INIT_SECTION
+@findex HAS_INIT_SECTION
+If defined, @code{main} will not call @code{__main} as described above.
+This macro should be defined for systems that control the contents of the
+init section on a symbol-by-symbol basis, such as OSF/1, and should not
+be defined explicitly for systems that support
+@code{INIT_SECTION_ASM_OP}.
+
+@item INVOKE__main
+@findex INVOKE__main
+If defined, @code{main} will call @code{__main} despite the presence of
+@code{INIT_SECTION_ASM_OP}. This macro should be defined for systems
+where the init section is not actually run automatically, but is still
+useful for collecting the lists of constructors and destructors.
+
+@item ASM_OUTPUT_CONSTRUCTOR (@var{stream}, @var{name})
+@findex ASM_OUTPUT_CONSTRUCTOR
+Define this macro as a C statement to output on the stream @var{stream}
+the assembler code to arrange to call the function named @var{name} at
+initialization time.
+
+Assume that @var{name} is the name of a C function generated
+automatically by the compiler. This function takes no arguments. Use
+the function @code{assemble_name} to output the name @var{name}; this
+performs any system-specific syntactic transformations such as adding an
+underscore.
+
+If you don't define this macro, nothing special is output to arrange to
+call the function. This is correct when the function will be called in
+some other manner---for example, by means of the @code{collect2} program,
+which looks through the symbol table to find these functions by their
+names.
+
+@item ASM_OUTPUT_DESTRUCTOR (@var{stream}, @var{name})
+@findex ASM_OUTPUT_DESTRUCTOR
+This is like @code{ASM_OUTPUT_CONSTRUCTOR} but used for termination
+functions rather than initialization functions.
+@end table
+
+If your system uses @code{collect2} as the means of processing
+constructors, then that program normally uses @code{nm} to scan an
+object file for constructor functions to be called. On certain kinds of
+systems, you can define these macros to make @code{collect2} work faster
+(and, in some cases, make it work at all):
+
+@table @code
+@findex OBJECT_FORMAT_COFF
+@item OBJECT_FORMAT_COFF
+Define this macro if the system uses COFF (Common Object File Format)
+object files, so that @code{collect2} can assume this format and scan
+object files directly for dynamic constructor/destructor functions.
+
+@findex OBJECT_FORMAT_ROSE
+@item OBJECT_FORMAT_ROSE
+Define this macro if the system uses ROSE format object files, so that
+@code{collect2} can assume this format and scan object files directly
+for dynamic constructor/destructor functions.
+
+@findex REAL_NM_FILE_NAME
+@item REAL_NM_FILE_NAME
+Define this macro as a C string constant containing the file name to use
+to execute @code{nm}. The default is to search the path normally for
+@code{nm}.
+@end table
+
+These macros are effective only in a native compiler; @code{collect2} as
+part of a cross compiler always uses @code{nm} for the target machine.
+
+@node Instruction Output
+@subsection Output of Assembler Instructions
+
+@c prevent bad page break with this line
+This describes assembler instruction output.
+
+@table @code
+@findex REGISTER_NAMES
+@item REGISTER_NAMES
+A C initializer containing the assembler's names for the machine
+registers, each one as a C string constant. This is what translates
+register numbers in the compiler into assembler language.
+
+@findex ADDITIONAL_REGISTER_NAMES
+@item ADDITIONAL_REGISTER_NAMES
+If defined, a C initializer for an array of structures containing a name
+and a register number. This macro defines additional names for hard
+registers, thus allowing the @code{asm} option in declarations to refer
+to registers using alternate names.
+
+@findex ASM_OUTPUT_OPCODE
+@item ASM_OUTPUT_OPCODE (@var{stream}, @var{ptr})
+Define this macro if you are using an unusual assembler that
+requires different names for the machine instructions.
+
+The definition is a C statement or statements which output an
+assembler instruction opcode to the stdio stream @var{stream}. The
+macro-operand @var{ptr} is a variable of type @code{char *} which
+points to the opcode name in its ``internal'' form---the form that is
+written in the machine description. The definition should output the
+opcode name to @var{stream}, performing any translation you desire, and
+increment the variable @var{ptr} to point at the end of the opcode
+so that it will not be output twice.
+
+In fact, your macro definition may process less than the entire opcode
+name, or more than the opcode name; but if you want to process text
+that includes @samp{%}-sequences to substitute operands, you must take
+care of the substitution yourself. Just be sure to increment
+@var{ptr} over whatever text should not be output normally.
+
+@findex recog_operand
+If you need to look at the operand values, they can be found as the
+elements of @code{recog_operand}.
+
+If the macro definition does nothing, the instruction is output
+in the usual way.
+
+@findex FINAL_PRESCAN_INSN
+@item FINAL_PRESCAN_INSN (@var{insn}, @var{opvec}, @var{noperands})
+If defined, a C statement to be executed just prior to the output of
+assembler code for @var{insn}, to modify the extracted operands so
+they will be output differently.
+
+Here the argument @var{opvec} is the vector containing the operands
+extracted from @var{insn}, and @var{noperands} is the number of
+elements of the vector which contain meaningful data for this insn.
+The contents of this vector are what will be used to convert the insn
+template into assembler code, so you can change the assembler output
+by changing the contents of the vector.
+
+This macro is useful when various assembler syntaxes share a single
+file of instruction patterns; by defining this macro differently, you
+can cause a large class of instructions to be output differently (such
+as with rearranged operands). Naturally, variations in assembler
+syntax affecting individual insn patterns ought to be handled by
+writing conditional output routines in those patterns.
+
+If this macro is not defined, it is equivalent to a null statement.
+
+@findex PRINT_OPERAND
+@item PRINT_OPERAND (@var{stream}, @var{x}, @var{code})
+A C compound statement to output to stdio stream @var{stream} the
+assembler syntax for an instruction operand @var{x}. @var{x} is an
+RTL expression.
+
+@var{code} is a value that can be used to specify one of several ways
+of printing the operand. It is used when identical operands must be
+printed differently depending on the context. @var{code} comes from
+the @samp{%} specification that was used to request printing of the
+operand. If the specification was just @samp{%@var{digit}} then
+@var{code} is 0; if the specification was @samp{%@var{ltr}
+@var{digit}} then @var{code} is the ASCII code for @var{ltr}.
+
+@findex reg_names
+If @var{x} is a register, this macro should print the register's name.
+The names can be found in an array @code{reg_names} whose type is
+@code{char *[]}. @code{reg_names} is initialized from
+@code{REGISTER_NAMES}.
+
+When the machine description has a specification @samp{%@var{punct}}
+(a @samp{%} followed by a punctuation character), this macro is called
+with a null pointer for @var{x} and the punctuation character for
+@var{code}.
+
+@findex PRINT_OPERAND_PUNCT_VALID_P
+@item PRINT_OPERAND_PUNCT_VALID_P (@var{code})
+A C expression which evaluates to true if @var{code} is a valid
+punctuation character for use in the @code{PRINT_OPERAND} macro. If
+@code{PRINT_OPERAND_PUNCT_VALID_P} is not defined, it means that no
+punctuation characters (except for the standard one, @samp{%}) are used
+in this way.
+
+@findex PRINT_OPERAND_ADDRESS
+@item PRINT_OPERAND_ADDRESS (@var{stream}, @var{x})
+A C compound statement to output to stdio stream @var{stream} the
+assembler syntax for an instruction operand that is a memory reference
+whose address is @var{x}. @var{x} is an RTL expression.
+
+@cindex @code{ENCODE_SECTION_INFO} usage
+On some machines, the syntax for a symbolic address depends on the
+section that the address refers to. On these machines, define the macro
+@code{ENCODE_SECTION_INFO} to store the information into the
+@code{symbol_ref}, and then check for it here. @xref{Assembler Format}.
+
+@findex DBR_OUTPUT_SEQEND
+@findex dbr_sequence_length
+@item DBR_OUTPUT_SEQEND(@var{file})
+A C statement, to be executed after all slot-filler instructions have
+been output. If necessary, call @code{dbr_sequence_length} to
+determine the number of slots filled in a sequence (zero if not
+currently outputting a sequence), to decide how many no-ops to output,
+or whatever.
+
+Don't define this macro if it has nothing to do, but it is helpful in
+reading assembly output if the extent of the delay sequence is made
+explicit (e.g. with white space).
+
+@findex final_sequence
+Note that output routines for instructions with delay slots must be
+prepared to deal with not being output as part of a sequence (i.e.
+when the scheduling pass is not run, or when no slot fillers could be
+found.) The variable @code{final_sequence} is null when not
+processing a sequence, otherwise it contains the @code{sequence} rtx
+being output.
+
+@findex REGISTER_PREFIX
+@findex LOCAL_LABEL_PREFIX
+@findex USER_LABEL_PREFIX
+@findex IMMEDIATE_PREFIX
+@findex asm_fprintf
+@item REGISTER_PREFIX
+@itemx LOCAL_LABEL_PREFIX
+@itemx USER_LABEL_PREFIX
+@itemx IMMEDIATE_PREFIX
+If defined, C string expressions to be used for the @samp{%R}, @samp{%L},
+@samp{%U}, and @samp{%I} options of @code{asm_fprintf} (see
+@file{final.c}). These are useful when a single @file{md} file must
+support multiple assembler formats. In that case, the various @file{tm.h}
+files can define these macros differently.
+
+@findex ASSEMBLER_DIALECT
+@item ASSEMBLER_DIALECT
+If your target supports multiple dialects of assembler language (such as
+different opcodes), define this macro as a C expression that gives the
+numeric index of the assembler langauge dialect to use, with zero as the
+first variant.
+
+If this macro is defined, you may use
+@samp{@{option0|option1|option2@dots{}@}} constructs in the output
+templates of patterns (@pxref{Output Template}) or in the first argument
+of @code{asm_fprintf}. This construct outputs @samp{option0},
+@samp{option1} or @samp{option2}, etc., if the value of
+@code{ASSEMBLER_DIALECT} is zero, one or two, etc. Any special
+characters within these strings retain their usual meaning.
+
+If you do not define this macro, the characters @samp{@{}, @samp{|} and
+@samp{@}} do not have any special meaning when used in templates or
+operands to @code{asm_fprintf}.
+
+Define the macros @code{REGISTER_PREFIX}, @code{LOCAL_LABEL_PREFIX},
+@code{USER_LABEL_PREFIX} and @code{IMMEDIATE_PREFIX} if you can express
+the variations in assemble language syntax with that mechanism. Define
+@code{ASSEMBLER_DIALECT} and use the @samp{@{option0|option1@}} syntax
+if the syntax variant are larger and involve such things as different
+opcodes or operand order.
+
+@findex ASM_OUTPUT_REG_PUSH
+@item ASM_OUTPUT_REG_PUSH (@var{stream}, @var{regno})
+A C expression to output to @var{stream} some assembler code
+which will push hard register number @var{regno} onto the stack.
+The code need not be optimal, since this macro is used only when
+profiling.
+
+@findex ASM_OUTPUT_REG_POP
+@item ASM_OUTPUT_REG_POP (@var{stream}, @var{regno})
+A C expression to output to @var{stream} some assembler code
+which will pop hard register number @var{regno} off of the stack.
+The code need not be optimal, since this macro is used only when
+profiling.
+@end table
+
+@node Dispatch Tables
+@subsection Output of Dispatch Tables
+
+@c prevent bad page break with this line
+This concerns dispatch tables.
+
+@table @code
+@cindex dispatch table
+@findex ASM_OUTPUT_ADDR_DIFF_ELT
+@item ASM_OUTPUT_ADDR_DIFF_ELT (@var{stream}, @var{value}, @var{rel})
+This macro should be provided on machines where the addresses
+in a dispatch table are relative to the table's own address.
+
+The definition should be a C statement to output to the stdio stream
+@var{stream} an assembler pseudo-instruction to generate a difference
+between two labels. @var{value} and @var{rel} are the numbers of two
+internal labels. The definitions of these labels are output using
+@code{ASM_OUTPUT_INTERNAL_LABEL}, and they must be printed in the same
+way here. For example,
+
+@example
+fprintf (@var{stream}, "\t.word L%d-L%d\n",
+ @var{value}, @var{rel})
+@end example
+
+@findex ASM_OUTPUT_ADDR_VEC_ELT
+@item ASM_OUTPUT_ADDR_VEC_ELT (@var{stream}, @var{value})
+This macro should be provided on machines where the addresses
+in a dispatch table are absolute.
+
+The definition should be a C statement to output to the stdio stream
+@var{stream} an assembler pseudo-instruction to generate a reference to
+a label. @var{value} is the number of an internal label whose
+definition is output using @code{ASM_OUTPUT_INTERNAL_LABEL}.
+For example,
+
+@example
+fprintf (@var{stream}, "\t.word L%d\n", @var{value})
+@end example
+
+@findex ASM_OUTPUT_CASE_LABEL
+@item ASM_OUTPUT_CASE_LABEL (@var{stream}, @var{prefix}, @var{num}, @var{table})
+Define this if the label before a jump-table needs to be output
+specially. The first three arguments are the same as for
+@code{ASM_OUTPUT_INTERNAL_LABEL}; the fourth argument is the
+jump-table which follows (a @code{jump_insn} containing an
+@code{addr_vec} or @code{addr_diff_vec}).
+
+This feature is used on system V to output a @code{swbeg} statement
+for the table.
+
+If this macro is not defined, these labels are output with
+@code{ASM_OUTPUT_INTERNAL_LABEL}.
+
+@findex ASM_OUTPUT_CASE_END
+@item ASM_OUTPUT_CASE_END (@var{stream}, @var{num}, @var{table})
+Define this if something special must be output at the end of a
+jump-table. The definition should be a C statement to be executed
+after the assembler code for the table is written. It should write
+the appropriate code to stdio stream @var{stream}. The argument
+@var{table} is the jump-table insn, and @var{num} is the label-number
+of the preceding label.
+
+If this macro is not defined, nothing special is output at the end of
+the jump-table.
+@end table
+
+@node Alignment Output
+@subsection Assembler Commands for Alignment
+
+@c prevent bad page break with this line
+This describes commands for alignment.
+
+@table @code
+@findex ASM_OUTPUT_ALIGN_CODE
+@item ASM_OUTPUT_ALIGN_CODE (@var{file})
+A C expression to output text to align the location counter in the way
+that is desirable at a point in the code that is reached only by
+jumping.
+
+This macro need not be defined if you don't want any special alignment
+to be done at such a time. Most machine descriptions do not currently
+define the macro.
+
+@findex ASM_OUTPUT_LOOP_ALIGN
+@item ASM_OUTPUT_LOOP_ALIGN (@var{file})
+A C expression to output text to align the location counter in the way
+that is desirable at the beginning of a loop.
+
+This macro need not be defined if you don't want any special alignment
+to be done at such a time. Most machine descriptions do not currently
+define the macro.
+
+@findex ASM_OUTPUT_SKIP
+@item ASM_OUTPUT_SKIP (@var{stream}, @var{nbytes})
+A C statement to output to the stdio stream @var{stream} an assembler
+instruction to advance the location counter by @var{nbytes} bytes.
+Those bytes should be zero when loaded. @var{nbytes} will be a C
+expression of type @code{int}.
+
+@findex ASM_NO_SKIP_IN_TEXT
+@item ASM_NO_SKIP_IN_TEXT
+Define this macro if @code{ASM_OUTPUT_SKIP} should not be used in the
+text section because it fails put zeros in the bytes that are skipped.
+This is true on many Unix systems, where the pseudo--op to skip bytes
+produces no-op instructions rather than zeros when used in the text
+section.
+
+@findex ASM_OUTPUT_ALIGN
+@item ASM_OUTPUT_ALIGN (@var{stream}, @var{power})
+A C statement to output to the stdio stream @var{stream} an assembler
+command to advance the location counter to a multiple of 2 to the
+@var{power} bytes. @var{power} will be a C expression of type @code{int}.
+@end table
+
+@need 3000
+@node Debugging Info
+@section Controlling Debugging Information Format
+
+@c prevent bad page break with this line
+This describes how to specify debugging information.
+
+@menu
+* All Debuggers:: Macros that affect all debugging formats uniformly.
+* DBX Options:: Macros enabling specific options in DBX format.
+* DBX Hooks:: Hook macros for varying DBX format.
+* File Names and DBX:: Macros controlling output of file names in DBX format.
+* SDB and DWARF:: Macros for SDB (COFF) and DWARF formats.
+@end menu
+
+@node All Debuggers
+@subsection Macros Affecting All Debugging Formats
+
+@c prevent bad page break with this line
+These macros affect all debugging formats.
+
+@table @code
+@findex DBX_REGISTER_NUMBER
+@item DBX_REGISTER_NUMBER (@var{regno})
+A C expression that returns the DBX register number for the compiler
+register number @var{regno}. In simple cases, the value of this
+expression may be @var{regno} itself. But sometimes there are some
+registers that the compiler knows about and DBX does not, or vice
+versa. In such cases, some register may need to have one number in
+the compiler and another for DBX.
+
+If two registers have consecutive numbers inside GNU CC, and they can be
+used as a pair to hold a multiword value, then they @emph{must} have
+consecutive numbers after renumbering with @code{DBX_REGISTER_NUMBER}.
+Otherwise, debuggers will be unable to access such a pair, because they
+expect register pairs to be consecutive in their own numbering scheme.
+
+If you find yourself defining @code{DBX_REGISTER_NUMBER} in way that
+does not preserve register pairs, then what you must do instead is
+redefine the actual register numbering scheme.
+
+@findex DEBUGGER_AUTO_OFFSET
+@item DEBUGGER_AUTO_OFFSET (@var{x})
+A C expression that returns the integer offset value for an automatic
+variable having address @var{x} (an RTL expression). The default
+computation assumes that @var{x} is based on the frame-pointer and
+gives the offset from the frame-pointer. This is required for targets
+that produce debugging output for DBX or COFF-style debugging output
+for SDB and allow the frame-pointer to be eliminated when the
+@samp{-g} options is used.
+
+@findex DEBUGGER_ARG_OFFSET
+@item DEBUGGER_ARG_OFFSET (@var{offset}, @var{x})
+A C expression that returns the integer offset value for an argument
+having address @var{x} (an RTL expression). The nominal offset is
+@var{offset}.
+
+@findex PREFERRED_DEBUGGING_TYPE
+@item PREFERRED_DEBUGGING_TYPE
+A C expression that returns the type of debugging output GNU CC produces
+when the user specifies @samp{-g} or @samp{-ggdb}. Define this if you
+have arranged for GNU CC to support more than one format of debugging
+output. Currently, the allowable values are @code{DBX_DEBUG},
+@code{SDB_DEBUG}, @code{DWARF_DEBUG}, and @code{XCOFF_DEBUG}.
+
+The value of this macro only affects the default debugging output; the
+user can always get a specific type of output by using @samp{-gstabs},
+@samp{-gcoff}, @samp{-gdwarf}, or @samp{-gxcoff}.
+@end table
+
+@node DBX Options
+@subsection Specific Options for DBX Output
+
+@c prevent bad page break with this line
+These are specific options for DBX output.
+
+@table @code
+@findex DBX_DEBUGGING_INFO
+@item DBX_DEBUGGING_INFO
+Define this macro if GNU CC should produce debugging output for DBX
+in response to the @samp{-g} option.
+
+@findex XCOFF_DEBUGGING_INFO
+@item XCOFF_DEBUGGING_INFO
+Define this macro if GNU CC should produce XCOFF format debugging output
+in response to the @samp{-g} option. This is a variant of DBX format.
+
+@findex DEFAULT_GDB_EXTENSIONS
+@item DEFAULT_GDB_EXTENSIONS
+Define this macro to control whether GNU CC should by default generate
+GDB's extended version of DBX debugging information (assuming DBX-format
+debugging information is enabled at all). If you don't define the
+macro, the default is 1: always generate the extended information
+if there is any occasion to.
+
+@findex DEBUG_SYMS_TEXT
+@item DEBUG_SYMS_TEXT
+Define this macro if all @code{.stabs} commands should be output while
+in the text section.
+
+@findex ASM_STABS_OP
+@item ASM_STABS_OP
+A C string constant naming the assembler pseudo op to use instead of
+@code{.stabs} to define an ordinary debugging symbol. If you don't
+define this macro, @code{.stabs} is used. This macro applies only to
+DBX debugging information format.
+
+@findex ASM_STABD_OP
+@item ASM_STABD_OP
+A C string constant naming the assembler pseudo op to use instead of
+@code{.stabd} to define a debugging symbol whose value is the current
+location. If you don't define this macro, @code{.stabd} is used.
+This macro applies only to DBX debugging information format.
+
+@findex ASM_STABN_OP
+@item ASM_STABN_OP
+A C string constant naming the assembler pseudo op to use instead of
+@code{.stabn} to define a debugging symbol with no name. If you don't
+define this macro, @code{.stabn} is used. This macro applies only to
+DBX debugging information format.
+
+@findex DBX_NO_XREFS
+@item DBX_NO_XREFS
+Define this macro if DBX on your system does not support the construct
+@samp{xs@var{tagname}}. On some systems, this construct is used to
+describe a forward reference to a structure named @var{tagname}.
+On other systems, this construct is not supported at all.
+
+@findex DBX_CONTIN_LENGTH
+@item DBX_CONTIN_LENGTH
+A symbol name in DBX-format debugging information is normally
+continued (split into two separate @code{.stabs} directives) when it
+exceeds a certain length (by default, 80 characters). On some
+operating systems, DBX requires this splitting; on others, splitting
+must not be done. You can inhibit splitting by defining this macro
+with the value zero. You can override the default splitting-length by
+defining this macro as an expression for the length you desire.
+
+@findex DBX_CONTIN_CHAR
+@item DBX_CONTIN_CHAR
+Normally continuation is indicated by adding a @samp{\} character to
+the end of a @code{.stabs} string when a continuation follows. To use
+a different character instead, define this macro as a character
+constant for the character you want to use. Do not define this macro
+if backslash is correct for your system.
+
+@findex DBX_STATIC_STAB_DATA_SECTION
+@item DBX_STATIC_STAB_DATA_SECTION
+Define this macro if it is necessary to go to the data section before
+outputting the @samp{.stabs} pseudo-op for a non-global static
+variable.
+
+@findex DBX_TYPE_DECL_STABS_CODE
+@item DBX_TYPE_DECL_STABS_CODE
+The value to use in the ``code'' field of the @code{.stabs} directive
+for a typedef. The default is @code{N_LSYM}.
+
+@findex DBX_STATIC_CONST_VAR_CODE
+@item DBX_STATIC_CONST_VAR_CODE
+The value to use in the ``code'' field of the @code{.stabs} directive
+for a static variable located in the text section. DBX format does not
+provide any ``right'' way to do this. The default is @code{N_FUN}.
+
+@findex DBX_REGPARM_STABS_CODE
+@item DBX_REGPARM_STABS_CODE
+The value to use in the ``code'' field of the @code{.stabs} directive
+for a parameter passed in registers. DBX format does not provide any
+``right'' way to do this. The default is @code{N_RSYM}.
+
+@findex DBX_REGPARM_STABS_LETTER
+@item DBX_REGPARM_STABS_LETTER
+The letter to use in DBX symbol data to identify a symbol as a parameter
+passed in registers. DBX format does not customarily provide any way to
+do this. The default is @code{'P'}.
+
+@findex DBX_MEMPARM_STABS_LETTER
+@item DBX_MEMPARM_STABS_LETTER
+The letter to use in DBX symbol data to identify a symbol as a stack
+parameter. The default is @code{'p'}.
+
+@findex DBX_FUNCTION_FIRST
+@item DBX_FUNCTION_FIRST
+Define this macro if the DBX information for a function and its
+arguments should precede the assembler code for the function. Normally,
+in DBX format, the debugging information entirely follows the assembler
+code.
+
+@findex DBX_LBRAC_FIRST
+@item DBX_LBRAC_FIRST
+Define this macro if the @code{N_LBRAC} symbol for a block should
+precede the debugging information for variables and functions defined in
+that block. Normally, in DBX format, the @code{N_LBRAC} symbol comes
+first.
+
+@findex DBX_BLOCKS_FUNCTION_RELATIVE
+@item DBX_BLOCKS_FUNCTION_RELATIVE
+Define this macro if the value of a symbol describing the scope of a
+block (@code{N_LBRAC} or @code{N_RBRAC}) should be relative to the start
+of the enclosing function. Normally, GNU C uses an absolute address.
+@end table
+
+@node DBX Hooks
+@subsection Open-Ended Hooks for DBX Format
+
+@c prevent bad page break with this line
+These are hooks for DBX format.
+
+@table @code
+@findex DBX_OUTPUT_LBRAC
+@item DBX_OUTPUT_LBRAC (@var{stream}, @var{name})
+Define this macro to say how to output to @var{stream} the debugging
+information for the start of a scope level for variable names. The
+argument @var{name} is the name of an assembler symbol (for use with
+@code{assemble_name}) whose value is the address where the scope begins.
+
+@findex DBX_OUTPUT_RBRAC
+@item DBX_OUTPUT_RBRAC (@var{stream}, @var{name})
+Like @code{DBX_OUTPUT_LBRAC}, but for the end of a scope level.
+
+@findex DBX_OUTPUT_ENUM
+@item DBX_OUTPUT_ENUM (@var{stream}, @var{type})
+Define this macro if the target machine requires special handling to
+output an enumeration type. The definition should be a C statement
+(sans semicolon) to output the appropriate information to @var{stream}
+for the type @var{type}.
+
+@findex DBX_OUTPUT_FUNCTION_END
+@item DBX_OUTPUT_FUNCTION_END (@var{stream}, @var{function})
+Define this macro if the target machine requires special output at the
+end of the debugging information for a function. The definition should
+be a C statement (sans semicolon) to output the appropriate information
+to @var{stream}. @var{function} is the @code{FUNCTION_DECL} node for
+the function.
+
+@findex DBX_OUTPUT_STANDARD_TYPES
+@item DBX_OUTPUT_STANDARD_TYPES (@var{syms})
+Define this macro if you need to control the order of output of the
+standard data types at the beginning of compilation. The argument
+@var{syms} is a @code{tree} which is a chain of all the predefined
+global symbols, including names of data types.
+
+Normally, DBX output starts with definitions of the types for integers
+and characters, followed by all the other predefined types of the
+particular language in no particular order.
+
+On some machines, it is necessary to output different particular types
+first. To do this, define @code{DBX_OUTPUT_STANDARD_TYPES} to output
+those symbols in the necessary order. Any predefined types that you
+don't explicitly output will be output afterward in no particular order.
+
+Be careful not to define this macro so that it works only for C. There
+are no global variables to access most of the built-in types, because
+another language may have another set of types. The way to output a
+particular type is to look through @var{syms} to see if you can find it.
+Here is an example:
+
+@smallexample
+@{
+ tree decl;
+ for (decl = syms; decl; decl = TREE_CHAIN (decl))
+ if (!strcmp (IDENTIFIER_POINTER (DECL_NAME (decl)),
+ "long int"))
+ dbxout_symbol (decl);
+ @dots{}
+@}
+@end smallexample
+
+@noindent
+This does nothing if the expected type does not exist.
+
+See the function @code{init_decl_processing} in @file{c-decl.c} to find
+the names to use for all the built-in C types.
+
+Here is another way of finding a particular type:
+
+@c this is still overfull. --mew 10feb93
+@smallexample
+@{
+ tree decl;
+ for (decl = syms; decl; decl = TREE_CHAIN (decl))
+ if (TREE_CODE (decl) == TYPE_DECL
+ && (TREE_CODE (TREE_TYPE (decl))
+ == INTEGER_CST)
+ && TYPE_PRECISION (TREE_TYPE (decl)) == 16
+ && TYPE_UNSIGNED (TREE_TYPE (decl)))
+@group
+ /* @r{This must be @code{unsigned short}.} */
+ dbxout_symbol (decl);
+ @dots{}
+@}
+@end group
+@end smallexample
+@end table
+
+@node File Names and DBX
+@subsection File Names in DBX Format
+
+@c prevent bad page break with this line
+This describes file names in DBX format.
+
+@table @code
+@findex DBX_WORKING_DIRECTORY
+@item DBX_WORKING_DIRECTORY
+Define this if DBX wants to have the current directory recorded in each
+object file.
+
+Note that the working directory is always recorded if GDB extensions are
+enabled.
+
+@findex DBX_OUTPUT_MAIN_SOURCE_FILENAME
+@item DBX_OUTPUT_MAIN_SOURCE_FILENAME (@var{stream}, @var{name})
+A C statement to output DBX debugging information to the stdio stream
+@var{stream} which indicates that file @var{name} is the main source
+file---the file specified as the input file for compilation.
+This macro is called only once, at the beginning of compilation.
+
+This macro need not be defined if the standard form of output
+for DBX debugging information is appropriate.
+
+@findex DBX_OUTPUT_MAIN_SOURCE_DIRECTORY
+@item DBX_OUTPUT_MAIN_SOURCE_DIRECTORY (@var{stream}, @var{name})
+A C statement to output DBX debugging information to the stdio stream
+@var{stream} which indicates that the current directory during
+compilation is named @var{name}.
+
+This macro need not be defined if the standard form of output
+for DBX debugging information is appropriate.
+
+@findex DBX_OUTPUT_MAIN_SOURCE_FILE_END
+@item DBX_OUTPUT_MAIN_SOURCE_FILE_END (@var{stream}, @var{name})
+A C statement to output DBX debugging information at the end of
+compilation of the main source file @var{name}.
+
+If you don't define this macro, nothing special is output at the end
+of compilation, which is correct for most machines.
+
+@findex DBX_OUTPUT_SOURCE_FILENAME
+@item DBX_OUTPUT_SOURCE_FILENAME (@var{stream}, @var{name})
+A C statement to output DBX debugging information to the stdio stream
+@var{stream} which indicates that file @var{name} is the current source
+file. This output is generated each time input shifts to a different
+source file as a result of @samp{#include}, the end of an included file,
+or a @samp{#line} command.
+
+This macro need not be defined if the standard form of output
+for DBX debugging information is appropriate.
+@end table
+
+@need 2000
+@node SDB and DWARF
+@subsection Macros for SDB and DWARF Output
+
+@c prevent bad page break with this line
+Here are macros for SDB and DWARF output.
+
+@table @code
+@findex SDB_DEBUGGING_INFO
+@item SDB_DEBUGGING_INFO
+Define this macro if GNU CC should produce COFF-style debugging output
+for SDB in response to the @samp{-g} option.
+
+@findex DWARF_DEBUGGING_INFO
+@item DWARF_DEBUGGING_INFO
+Define this macro if GNU CC should produce dwarf format debugging output
+in response to the @samp{-g} option.
+
+@findex PUT_SDB_@dots{}
+@item PUT_SDB_@dots{}
+Define these macros to override the assembler syntax for the special
+SDB assembler directives. See @file{sdbout.c} for a list of these
+macros and their arguments. If the standard syntax is used, you need
+not define them yourself.
+
+@findex SDB_DELIM
+@item SDB_DELIM
+Some assemblers do not support a semicolon as a delimiter, even between
+SDB assembler directives. In that case, define this macro to be the
+delimiter to use (usually @samp{\n}). It is not necessary to define
+a new set of @code{PUT_SDB_@var{op}} macros if this is the only change
+required.
+
+@findex SDB_GENERATE_FAKE
+@item SDB_GENERATE_FAKE
+Define this macro to override the usual method of constructing a dummy
+name for anonymous structure and union types. See @file{sdbout.c} for
+more information.
+
+@findex SDB_ALLOW_UNKNOWN_REFERENCES
+@item SDB_ALLOW_UNKNOWN_REFERENCES
+Define this macro to allow references to unknown structure,
+union, or enumeration tags to be emitted. Standard COFF does not
+allow handling of unknown references, MIPS ECOFF has support for
+it.
+
+@findex SDB_ALLOW_FORWARD_REFERENCES
+@item SDB_ALLOW_FORWARD_REFERENCES
+Define this macro to allow references to structure, union, or
+enumeration tags that have not yet been seen to be handled. Some
+assemblers choke if forward tags are used, while some require it.
+@end table
+
+@node Cross-compilation
+@section Cross Compilation and Floating Point
+@cindex cross compilation and floating point
+@cindex floating point and cross compilation
+
+While all modern machines use 2's complement representation for integers,
+there are a variety of representations for floating point numbers. This
+means that in a cross-compiler the representation of floating point numbers
+in the compiled program may be different from that used in the machine
+doing the compilation.
+
+@findex atof
+Because different representation systems may offer different amounts of
+range and precision, the cross compiler cannot safely use the host
+machine's floating point arithmetic. Therefore, floating point constants
+must be represented in the target machine's format. This means that the
+cross compiler cannot use @code{atof} to parse a floating point constant;
+it must have its own special routine to use instead. Also, constant
+folding must emulate the target machine's arithmetic (or must not be done
+at all).
+
+The macros in the following table should be defined only if you are cross
+compiling between different floating point formats.
+
+Otherwise, don't define them. Then default definitions will be set up which
+use @code{double} as the data type, @code{==} to test for equality, etc.
+
+You don't need to worry about how many times you use an operand of any
+of these macros. The compiler never uses operands which have side effects.
+
+@table @code
+@findex REAL_VALUE_TYPE
+@item REAL_VALUE_TYPE
+A macro for the C data type to be used to hold a floating point value
+in the target machine's format. Typically this would be a
+@code{struct} containing an array of @code{int}.
+
+@findex REAL_VALUES_EQUAL
+@item REAL_VALUES_EQUAL (@var{x}, @var{y})
+A macro for a C expression which compares for equality the two values,
+@var{x} and @var{y}, both of type @code{REAL_VALUE_TYPE}.
+
+@findex REAL_VALUES_LESS
+@item REAL_VALUES_LESS (@var{x}, @var{y})
+A macro for a C expression which tests whether @var{x} is less than
+@var{y}, both values being of type @code{REAL_VALUE_TYPE} and
+interpreted as floating point numbers in the target machine's
+representation.
+
+@findex REAL_VALUE_LDEXP
+@findex ldexp
+@item REAL_VALUE_LDEXP (@var{x}, @var{scale})
+A macro for a C expression which performs the standard library
+function @code{ldexp}, but using the target machine's floating point
+representation. Both @var{x} and the value of the expression have
+type @code{REAL_VALUE_TYPE}. The second argument, @var{scale}, is an
+integer.
+
+@findex REAL_VALUE_FIX
+@item REAL_VALUE_FIX (@var{x})
+A macro whose definition is a C expression to convert the target-machine
+floating point value @var{x} to a signed integer. @var{x} has type
+@code{REAL_VALUE_TYPE}.
+
+@findex REAL_VALUE_UNSIGNED_FIX
+@item REAL_VALUE_UNSIGNED_FIX (@var{x})
+A macro whose definition is a C expression to convert the target-machine
+floating point value @var{x} to an unsigned integer. @var{x} has type
+@code{REAL_VALUE_TYPE}.
+
+@findex REAL_VALUE_RNDZINT
+@item REAL_VALUE_RNDZINT (@var{x})
+A macro whose definition is a C expression to round the target-machine
+floating point value @var{x} towards zero to an integer value (but still
+as a floating point number). @var{x} has type @code{REAL_VALUE_TYPE},
+and so does the value.
+
+@findex REAL_VALUE_UNSIGNED_RNDZINT
+@item REAL_VALUE_UNSIGNED_RNDZINT (@var{x})
+A macro whose definition is a C expression to round the target-machine
+floating point value @var{x} towards zero to an unsigned integer value
+(but still represented as a floating point number). @var{x} has type
+@code{REAL_VALUE_TYPE}, and so does the value.
+
+@findex REAL_VALUE_ATOF
+@item REAL_VALUE_ATOF (@var{string}, @var{mode})
+A macro for a C expression which converts @var{string}, an expression of
+type @code{char *}, into a floating point number in the target machine's
+representation for mode @var{mode}. The value has type
+@code{REAL_VALUE_TYPE}.
+
+@findex REAL_INFINITY
+@item REAL_INFINITY
+Define this macro if infinity is a possible floating point value, and
+therefore division by 0 is legitimate.
+
+@findex REAL_VALUE_ISINF
+@findex isinf
+@item REAL_VALUE_ISINF (@var{x})
+A macro for a C expression which determines whether @var{x}, a floating
+point value, is infinity. The value has type @code{int}.
+By default, this is defined to call @code{isinf}.
+
+@findex REAL_VALUE_ISNAN
+@findex isnan
+@item REAL_VALUE_ISNAN (@var{x})
+A macro for a C expression which determines whether @var{x}, a floating
+point value, is a ``nan'' (not-a-number). The value has type
+@code{int}. By default, this is defined to call @code{isnan}.
+@end table
+
+@cindex constant folding and floating point
+Define the following additional macros if you want to make floating
+point constant folding work while cross compiling. If you don't
+define them, cross compilation is still possible, but constant folding
+will not happen for floating point values.
+
+@table @code
+@findex REAL_ARITHMETIC
+@item REAL_ARITHMETIC (@var{output}, @var{code}, @var{x}, @var{y})
+A macro for a C statement which calculates an arithmetic operation of
+the two floating point values @var{x} and @var{y}, both of type
+@code{REAL_VALUE_TYPE} in the target machine's representation, to
+produce a result of the same type and representation which is stored
+in @var{output} (which will be a variable).
+
+The operation to be performed is specified by @var{code}, a tree code
+which will always be one of the following: @code{PLUS_EXPR},
+@code{MINUS_EXPR}, @code{MULT_EXPR}, @code{RDIV_EXPR},
+@code{MAX_EXPR}, @code{MIN_EXPR}.@refill
+
+@cindex overflow while constant folding
+The expansion of this macro is responsible for checking for overflow.
+If overflow happens, the macro expansion should execute the statement
+@code{return 0;}, which indicates the inability to perform the
+arithmetic operation requested.
+
+@findex REAL_VALUE_NEGATE
+@item REAL_VALUE_NEGATE (@var{x})
+A macro for a C expression which returns the negative of the floating
+point value @var{x}. Both @var{x} and the value of the expression
+have type @code{REAL_VALUE_TYPE} and are in the target machine's
+floating point representation.
+
+There is no way for this macro to report overflow, since overflow
+can't happen in the negation operation.
+
+@findex REAL_VALUE_TRUNCATE
+@item REAL_VALUE_TRUNCATE (@var{mode}, @var{x})
+A macro for a C expression which converts the floating point value
+@var{x} to mode @var{mode}.
+
+Both @var{x} and the value of the expression are in the target machine's
+floating point representation and have type @code{REAL_VALUE_TYPE}.
+However, the value should have an appropriate bit pattern to be output
+properly as a floating constant whose precision accords with mode
+@var{mode}.
+
+There is no way for this macro to report overflow.
+
+@findex REAL_VALUE_TO_INT
+@item REAL_VALUE_TO_INT (@var{low}, @var{high}, @var{x})
+A macro for a C expression which converts a floating point value
+@var{x} into a double-precision integer which is then stored into
+@var{low} and @var{high}, two variables of type @var{int}.
+
+@item REAL_VALUE_FROM_INT (@var{x}, @var{low}, @var{high})
+@findex REAL_VALUE_FROM_INT
+A macro for a C expression which converts a double-precision integer
+found in @var{low} and @var{high}, two variables of type @var{int},
+into a floating point value which is then stored into @var{x}.
+@end table
+
+@node Misc
+@section Miscellaneous Parameters
+@cindex parameters, miscellaneous
+
+@c prevent bad page break with this line
+Here are several miscellaneous parameters.
+
+@table @code
+@item PREDICATE_CODES
+@findex PREDICATE_CODES
+Define this if you have defined special-purpose predicates in the file
+@file{@var{machine}.c}. This macro is called within an initializer of an
+array of structures. The first field in the structure is the name of a
+predicate and the second field is an array of rtl codes. For each
+predicate, list all rtl codes that can be in expressions matched by the
+predicate. The list should have a trailing comma. Here is an example
+of two entries in the list for a typical RISC machine:
+
+@smallexample
+#define PREDICATE_CODES \
+ @{"gen_reg_rtx_operand", @{SUBREG, REG@}@}, \
+ @{"reg_or_short_cint_operand", @{SUBREG, REG, CONST_INT@}@},
+@end smallexample
+
+Defining this macro does not affect the generated code (however,
+incorrect definitions that omit an rtl code that may be matched by the
+predicate can cause the compiler to malfunction). Instead, it allows
+the table built by @file{genrecog} to be more compact and efficient,
+thus speeding up the compiler. The most important predicates to include
+in the list specified by this macro are thoses used in the most insn
+patterns.
+
+@findex CASE_VECTOR_MODE
+@item CASE_VECTOR_MODE
+An alias for a machine mode name. This is the machine mode that
+elements of a jump-table should have.
+
+@findex CASE_VECTOR_PC_RELATIVE
+@item CASE_VECTOR_PC_RELATIVE
+Define this macro if jump-tables should contain relative addresses.
+
+@findex CASE_DROPS_THROUGH
+@item CASE_DROPS_THROUGH
+Define this if control falls through a @code{case} insn when the index
+value is out of range. This means the specified default-label is
+actually ignored by the @code{case} insn proper.
+
+@findex CASE_VALUES_THRESHOLD
+@item CASE_VALUES_THRESHOLD
+Define this to be the smallest number of different values for which it
+is best to use a jump-table instead of a tree of conditional branches.
+The default is four for machines with a @code{casesi} instruction and
+five otherwise. This is best for most machines.
+
+@findex WORD_REGISTER_OPERATIONS
+@item WORD_REGISTER_OPERATIONS
+Define this macro if operations between registers with integral mode
+smaller than a word are always performed on the entire register.
+Most RISC machines have this property and most CISC machines do not.
+
+@findex LOAD_EXTEND_OP
+@item LOAD_EXTEND_OP (@var{mode})
+Define this macro to be a C expression indicating when insns that read
+memory in @var{mode}, an integral mode narrower than a word, set the
+bits outside of @var{mode} to be either the sign-extension or the
+zero-extension of the data read. Return @code{SIGN_EXTEND} for values
+of @var{mode} for which the
+insn sign-extends, @code{ZERO_EXTEND} for which it zero-extends, and
+@code{NIL} for other modes.
+
+This macro is not called with @var{mode} non-integral or with a width
+greater than or equal to @code{BITS_PER_WORD}, so you may return any
+value in this case. Do not define this macro if it would always return
+@code{NIL}. On machines where this macro is defined, you will normally
+define it as the constant @code{SIGN_EXTEND} or @code{ZERO_EXTEND}.
+
+@findex IMPLICIT_FIX_EXPR
+@item IMPLICIT_FIX_EXPR
+An alias for a tree code that should be used by default for conversion
+of floating point values to fixed point. Normally,
+@code{FIX_ROUND_EXPR} is used.@refill
+
+@findex FIXUNS_TRUNC_LIKE_FIX_TRUNC
+@item FIXUNS_TRUNC_LIKE_FIX_TRUNC
+Define this macro if the same instructions that convert a floating
+point number to a signed fixed point number also convert validly to an
+unsigned one.
+
+@findex EASY_DIV_EXPR
+@item EASY_DIV_EXPR
+An alias for a tree code that is the easiest kind of division to
+compile code for in the general case. It may be
+@code{TRUNC_DIV_EXPR}, @code{FLOOR_DIV_EXPR}, @code{CEIL_DIV_EXPR} or
+@code{ROUND_DIV_EXPR}. These four division operators differ in how
+they round the result to an integer. @code{EASY_DIV_EXPR} is used
+when it is permissible to use any of those kinds of division and the
+choice should be made on the basis of efficiency.@refill
+
+@findex MOVE_MAX
+@item MOVE_MAX
+The maximum number of bytes that a single instruction can move quickly
+from memory to memory.
+
+@findex MAX_MOVE_MAX
+@item MAX_MOVE_MAX
+The maximum number of bytes that a single instruction can move quickly
+from memory to memory. If this is undefined, the default is
+@code{MOVE_MAX}. Otherwise, it is the constant value that is the
+largest value that @code{MOVE_MAX} can have at run-time.
+
+@findex SHIFT_COUNT_TRUNCATED
+@item SHIFT_COUNT_TRUNCATED
+A C expression that is nonzero if on this machine the number of bits
+actually used for the count of a shift operation is equal to the number
+of bits needed to represent the size of the object being shifted. When
+this macro is non-zero, the compiler will assume that it is safe to omit
+a sign-extend, zero-extend, and certain bitwise `and' instructions that
+truncates the count of a shift operation. On machines that have
+instructions that act on bitfields at variable positions, which may
+include `bit test' instructions, a nonzero @code{SHIFT_COUNT_TRUNCATED}
+also enables deletion of truncations of the values that serve as
+arguments to bitfield instructions.
+
+If both types of instructions truncate the count (for shifts) and
+position (for bitfield operations), or if no variable-position bitfield
+instructions exist, you should define this macro.
+
+However, on some machines, such as the 80386 and the 680x0, truncation
+only applies to shift operations and not the (real or pretended)
+bitfield operations. Define @code{SHIFT_COUNT_TRUNCATED} to be zero on
+such machines. Instead, add patterns to the @file{md} file that include
+the implied truncation of the shift instructions.
+
+You need not define this macro if it would always have the value of zero.
+
+@findex TRULY_NOOP_TRUNCATION
+@item TRULY_NOOP_TRUNCATION (@var{outprec}, @var{inprec})
+A C expression which is nonzero if on this machine it is safe to
+``convert'' an integer of @var{inprec} bits to one of @var{outprec}
+bits (where @var{outprec} is smaller than @var{inprec}) by merely
+operating on it as if it had only @var{outprec} bits.
+
+On many machines, this expression can be 1.
+
+@c rearranged this, removed the phrase "it is reported that". this was
+@c to fix an overfull hbox. --mew 10feb93
+When @code{TRULY_NOOP_TRUNCATION} returns 1 for a pair of sizes for
+modes for which @code{MODES_TIEABLE_P} is 0, suboptimal code can result.
+If this is the case, making @code{TRULY_NOOP_TRUNCATION} return 0 in
+such cases may improve things.
+
+@findex STORE_FLAG_VALUE
+@item STORE_FLAG_VALUE
+A C expression describing the value returned by a comparison operator
+with an integral mode and stored by a store-flag instruction
+(@samp{s@var{cond}}) when the condition is true. This description must
+apply to @emph{all} the @samp{s@var{cond}} patterns and all the
+comparison operators whose results have a @code{MODE_INT} mode.
+
+A value of 1 or -1 means that the instruction implementing the
+comparison operator returns exactly 1 or -1 when the comparison is true
+and 0 when the comparison is false. Otherwise, the value indicates
+which bits of the result are guaranteed to be 1 when the comparison is
+true. This value is interpreted in the mode of the comparison
+operation, which is given by the mode of the first operand in the
+@samp{s@var{cond}} pattern. Either the low bit or the sign bit of
+@code{STORE_FLAG_VALUE} be on. Presently, only those bits are used by
+the compiler.
+
+If @code{STORE_FLAG_VALUE} is neither 1 or -1, the compiler will
+generate code that depends only on the specified bits. It can also
+replace comparison operators with equivalent operations if they cause
+the required bits to be set, even if the remaining bits are undefined.
+For example, on a machine whose comparison operators return an
+@code{SImode} value and where @code{STORE_FLAG_VALUE} is defined as
+@samp{0x80000000}, saying that just the sign bit is relevant, the
+expression
+
+@smallexample
+(ne:SI (and:SI @var{x} (const_int @var{power-of-2})) (const_int 0))
+@end smallexample
+
+@noindent
+can be converted to
+
+@smallexample
+(ashift:SI @var{x} (const_int @var{n}))
+@end smallexample
+
+@noindent
+where @var{n} is the appropriate shift count to move the bit being
+tested into the sign bit.
+
+There is no way to describe a machine that always sets the low-order bit
+for a true value, but does not guarantee the value of any other bits,
+but we do not know of any machine that has such an instruction. If you
+are trying to port GNU CC to such a machine, include an instruction to
+perform a logical-and of the result with 1 in the pattern for the
+comparison operators and let us know
+@ifset USING
+(@pxref{Bug Reporting,,How to Report Bugs}).
+@end ifset
+@ifclear USING
+(@pxref{Bug Reporting,,How to Report Bugs,gcc.info,Using GCC}).
+@end ifclear
+
+Often, a machine will have multiple instructions that obtain a value
+from a comparison (or the condition codes). Here are rules to guide the
+choice of value for @code{STORE_FLAG_VALUE}, and hence the instructions
+to be used:
+
+@itemize @bullet
+@item
+Use the shortest sequence that yields a valid definition for
+@code{STORE_FLAG_VALUE}. It is more efficient for the compiler to
+``normalize'' the value (convert it to, e.g., 1 or 0) than for the
+comparison operators to do so because there may be opportunities to
+combine the normalization with other operations.
+
+@item
+For equal-length sequences, use a value of 1 or -1, with -1 being
+slightly preferred on machines with expensive jumps and 1 preferred on
+other machines.
+
+@item
+As a second choice, choose a value of @samp{0x80000001} if instructions
+exist that set both the sign and low-order bits but do not define the
+others.
+
+@item
+Otherwise, use a value of @samp{0x80000000}.
+@end itemize
+
+Many machines can produce both the value chosen for
+@code{STORE_FLAG_VALUE} and its negation in the same number of
+instructions. On those machines, you should also define a pattern for
+those cases, e.g., one matching
+
+@smallexample
+(set @var{A} (neg:@var{m} (ne:@var{m} @var{B} @var{C})))
+@end smallexample
+
+Some machines can also perform @code{and} or @code{plus} operations on
+condition code values with less instructions than the corresponding
+@samp{s@var{cond}} insn followed by @code{and} or @code{plus}. On those
+machines, define the appropriate patterns. Use the names @code{incscc}
+and @code{decscc}, respectively, for the the patterns which perform
+@code{plus} or @code{minus} operations on condition code values. See
+@file{rs6000.md} for some examples. The GNU Superoptizer can be used to
+find such instruction sequences on other machines.
+
+You need not define @code{STORE_FLAG_VALUE} if the machine has no store-flag
+instructions.
+
+@findex FLOAT_STORE_FLAG_VALUE
+@item FLOAT_STORE_FLAG_VALUE
+A C expression that gives a non-zero floating point value that is
+returned when comparison operators with floating-point results are true.
+Define this macro on machine that have comparison operations that return
+floating-point values. If there are no such operations, do not define
+this macro.
+
+@findex Pmode
+@item Pmode
+An alias for the machine mode for pointers. Normally the definition
+can be
+
+@smallexample
+#define Pmode SImode
+@end smallexample
+
+@findex FUNCTION_MODE
+@item FUNCTION_MODE
+An alias for the machine mode used for memory references to functions
+being called, in @code{call} RTL expressions. On most machines this
+should be @code{QImode}.
+
+@findex INTEGRATE_THRESHOLD
+@item INTEGRATE_THRESHOLD (@var{decl})
+A C expression for the maximum number of instructions above which the
+function @var{decl} should not be inlined. @var{decl} is a
+@code{FUNCTION_DECL} node.
+
+The default definition of this macro is 64 plus 8 times the number of
+arguments that the function accepts. Some people think a larger
+threshold should be used on RISC machines.
+
+@findex SCCS_DIRECTIVE
+@item SCCS_DIRECTIVE
+Define this if the preprocessor should ignore @code{#sccs} directives
+and print no error message.
+
+@findex NO_IMPLICIT_EXTERN_C
+@item NO_IMPLICIT_EXTERN_C
+Define this macro if the system header files support C++ as well as C.
+This macro inhibits the usual method of using system header files in
+C++, which is to pretend that the file's contents are enclosed in
+@samp{extern "C" @{@dots{}@}}.
+
+@findex HANDLE_PRAGMA
+@findex #pragma
+@findex pragma
+@item HANDLE_PRAGMA (@var{stream})
+Define this macro if you want to implement any pragmas. If defined, it
+should be a C statement to be executed when @code{#pragma} is seen. The
+argument @var{stream} is the stdio input stream from which the source
+text can be read.
+
+It is generally a bad idea to implement new uses of @code{#pragma}. The
+only reason to define this macro is for compatibility with other
+compilers that do support @code{#pragma} for the sake of any user
+programs which already use it.
+
+@findex VALID_MACHINE_ATTRIBUTE
+@item VALID_MACHINE_ATTRIBUTE (@var{type}, @var{attributes}, @var{identifier})
+Define this macro if you want to support machine specific attributes for
+types. If defined, it should be a C statement whose value is nonzero if
+@var{identifier} is an attribute that is valid for @var{type}. The
+attributes in @var{attributes} have previously been assigned to @var{type}.
+
+@findex COMP_TYPE_ATTRIBUTES
+@item COMP_TYPE_ATTRIBUTES (@var{type1}, @var{type2})
+Define this macro if type attributes must be checked for compatibility.
+If defined, it should be a C statement that returns zero if the
+attributes on @var{type1} and @var{type2} are incompatible, one if they
+are compatible, and two if they are nearly compatible (which causes a
+warning to be generated).
+
+@findex SET_DEFAULT_TYPE_ATTRIBUTES
+@item SET_DEFAULT_TYPE_ATTRIBUTES (@var{type})
+Define this macro if you want to give the newly defined @var{type} some
+default attributes.
+
+@findex DOLLARS_IN_IDENTIFIERS
+@item DOLLARS_IN_IDENTIFIERS
+Define this macro to control use of the character @samp{$} in identifier
+names. The value should be 0, 1, or 2. 0 means @samp{$} is not allowed
+by default; 1 means it is allowed by default if @samp{-traditional} is
+used; 2 means it is allowed by default provided @samp{-ansi} is not used.
+1 is the default; there is no need to define this macro in that case.
+
+@findex NO_DOLLAR_IN_LABEL
+@item NO_DOLLAR_IN_LABEL
+Define this macro if the assembler does not accept the character
+@samp{$} in label names. By default constructors and destructors in
+G++ have @samp{$} in the identifiers. If this macro is defined,
+@samp{.} is used instead.
+
+@findex NO_DOT_IN_LABEL
+@item NO_DOT_IN_LABEL
+Define this macro if the assembler does not accept the character
+@samp{.} in label names. By default constructors and destructors in G++
+have names that use @samp{.}. If this macro is defined, these names
+are rewritten to avoid @samp{.}.
+
+@findex DEFAULT_MAIN_RETURN
+@item DEFAULT_MAIN_RETURN
+Define this macro if the target system expects every program's @code{main}
+function to return a standard ``success'' value by default (if no other
+value is explicitly returned).
+
+The definition should be a C statement (sans semicolon) to generate the
+appropriate rtl instructions. It is used only when compiling the end of
+@code{main}.
+
+@item HAVE_ATEXIT
+@findex HAVE_ATEXIT
+Define this if the target system supports the function
+@code{atexit} from the ANSI C standard. If this is not defined,
+and @code{INIT_SECTION_ASM_OP} is not defined, a default
+@code{exit} function will be provided to support C++.
+
+@item EXIT_BODY
+@findex EXIT_BODY
+Define this if your @code{exit} function needs to do something
+besides calling an external function @code{_cleanup} before
+terminating with @code{_exit}. The @code{EXIT_BODY} macro is
+only needed if netiher @code{HAVE_ATEXIT} nor
+@code{INIT_SECTION_ASM_OP} are defined.
+
+@findex INSN_SETS_ARE_DELAYED
+@item INSN_SETS_ARE_DELAYED (@var{insn})
+Define this macro as a C expression that is nonzero if it is safe for the
+delay slot scheduler to place instructions in the delay slot of @var{insn},
+even if they appear to use a resource set or clobbered in @var{insn}.
+@var{insn} is always a @code{jump_insn} or an @code{insn}; GNU CC knows that
+every @code{call_insn} has this behavior. On machines where some @code{insn}
+or @code{jump_insn} is really a function call and hence has this behavior,
+you should define this macro.
+
+You need not define this macro if it would always return zero.
+
+@findex INSN_REFERENCES_ARE_DELAYED
+@item INSN_REFERENCES_ARE_DELAYED (@var{insn})
+Define this macro as a C expression that is nonzero if it is safe for the
+delay slot scheduler to place instructions in the delay slot of @var{insn},
+even if they appear to set or clobber a resource referenced in @var{insn}.
+@var{insn} is always a @code{jump_insn} or an @code{insn}. On machines where
+some @code{insn} or @code{jump_insn} is really a function call and its operands
+are registers whose use is actually in the subroutine it calls, you should
+define this macro. Doing so allows the delay slot scheduler to move
+instructions which copy arguments into the argument registers into the delay
+slot of @var{insn}.
+
+You need not define this macro if it would always return zero.
+
+@findex MACHINE_DEPENDENT_REORG
+@item MACHINE_DEPENDENT_REORG (@var{insn})
+In rare cases, correct code generation requires extra machine
+dependent processing between the second jump optimization pass and
+delayed branch scheduling. On those machines, define this macro as a C
+statement to act on the code starting at @var{insn}.
+@end table
diff --git a/gnu/usr.bin/cc/f77/Makefile b/gnu/usr.bin/cc/f77/Makefile
new file mode 100644
index 0000000..e7ed051
--- /dev/null
+++ b/gnu/usr.bin/cc/f77/Makefile
@@ -0,0 +1,9 @@
+#
+# $Id: Makefile,v 1.1 1994/10/25 14:36:49 ljo Exp $
+#
+
+PROG = f77
+SRCS = f77.c
+BINDIR= /usr/bin
+
+.include <bsd.prog.mk>
diff --git a/gnu/usr.bin/cc/f77/f77.1 b/gnu/usr.bin/cc/f77/f77.1
new file mode 100644
index 0000000..cc501d7
--- /dev/null
+++ b/gnu/usr.bin/cc/f77/f77.1
@@ -0,0 +1,67 @@
+.Dd July 22, 1995
+.Dt F77 1
+.Os FreeBSD
+.Sh NAME
+.Nm f77
+.Nd FORTRAN compiler driver
+.Sh SYNOPSIS
+.Nm f77
+.Op options | files
+.Sh DESCRIPTION
+.Nm f77
+is a simple driver for the FORTRAN compilation process under FreeBSD.
+.Pp
+.Nm f77
+calls the FORTRAN to C translator
+.Nm f2c
+to translate the FORTRAN source to C. Then it calls
+.Nm cc
+to compile the resulting C code and
+.Nm as
+to assemble it. After this stage it may call
+.Nm ld
+to link the resulting object files together with the
+.Nm f2c
+library
+.Nm libf2c
+, the
+.Nm math
+library
+.Nm libm
+and other user specified libraries into an executable. Files ending in other
+suffixes than .f (.o, .c, ...) are also accepted in the commandline and will
+processed by the appropriate program.
+.Pp
+From the user side of view this FORTRAN to C translation is completely
+transparent -
+.Nm f77
+looks like a traditional FORTRAN compiler.
+.Pp
+Available options:
+.Pp
+The options that
+.Nm f77
+recognizes are a superset of the
+.Nm f2c
+and the
+.Nm cc
+options - please refer to their manpages for more details.
+.Pp
+.Sh FILES
+file.f FORTRAN source file
+.Pp
+file.o object file
+.Pp
+a.out link edited output
+.Pp
+/usr/lib/libf2c.a f2c library (contains libF77 and libI77)
+.Pp
+/usr/lib/libf2c.so.x.y shared f2c library
+.Pp
+.Sh SEE ALSO
+.Xr f2c 1 ,
+.Xr cc 1 ,
+.Xr as 1 ,
+.Xr ld 1
+.Sh BUGS
+The input file must end in .f - for instance .for will give problems.
diff --git a/gnu/usr.bin/cc/f77/f77.c b/gnu/usr.bin/cc/f77/f77.c
new file mode 100644
index 0000000..6ebb515
--- /dev/null
+++ b/gnu/usr.bin/cc/f77/f77.c
@@ -0,0 +1,542 @@
+/* f77 driver dervied from g++.c by Jonas Olsson */
+
+/* G++ preliminary semantic processing for the compiler driver.
+ Copyright (C) 1993, 1994 Free Software Foundation, Inc.
+ Contributed by Brendan Kehoe (brendan@cygnus.com).
+
+This file is part of GNU CC.
+
+GNU CC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU CC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* This program is a wrapper to the main `gcc' driver. For GNU C++,
+ we need to do two special things: a) append `-lg++' in situations
+ where it's appropriate, to link in libg++, and b) add `-xc++'..`-xnone'
+ around file arguments named `foo.c' or `foo.i'. So, we do all of
+ this semantic processing then just exec gcc with the new argument
+ list.
+
+ We used to do all of this in a small shell script, but many users
+ found the performance of this as a shell script to be unacceptable.
+ In situations where your PATH has a lot of NFS-mounted directories,
+ using a script that runs sed and other things would be a nasty
+ performance hit. With this program, we never search the PATH at all. */
+
+#include "config.h"
+#ifdef __STDC__
+#include <stdarg.h>
+#else
+#include <varargs.h>
+#endif
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/file.h> /* May get R_OK, etc. on some systems. */
+
+/* Defined to the name of the compiler; if using a cross compiler, the
+ Makefile should compile this file with the proper name
+ (e.g., "i386-aout-gcc"). */
+#ifndef GCC_NAME
+#define GCC_NAME "gcc"
+#endif
+
+/* This bit is set if we saw a `-xfoo' language specification. */
+#define LANGSPEC (1<<1)
+/* This bit is set if they did `-lm' or `-lmath'. */
+#define MATHLIB (1<<2)
+/* This bit is set if they did `-lf2c'. */
+#define F2CLIB (1<<3)
+
+/* On MSDOS, write temp files in current dir
+ because there's no place else we can expect to use. */
+#ifdef __MSDOS__
+#ifndef P_tmpdir
+#define P_tmpdir "."
+#endif
+#ifndef R_OK
+#define R_OK 4
+#define W_OK 2
+#define X_OK 1
+#endif
+#endif
+
+#ifndef VPROTO
+#ifdef __STDC__
+#define PVPROTO(ARGS) ARGS
+#define VPROTO(ARGS) ARGS
+#define VA_START(va_list,var) va_start(va_list,var)
+#else
+#define PVPROTO(ARGS) ()
+#define VPROTO(ARGS) (va_alist) va_dcl
+#define VA_START(va_list,var) va_start(va_list)
+#endif
+#endif
+
+extern int errno, sys_nerr;
+#if defined(bsd4_4) || defined(__NetBSD__)
+extern const char *const sys_errlist[];
+#else
+extern char *sys_errlist[];
+#endif
+
+/* Name with which this program was invoked. */
+static char *programname;
+
+#ifdef HAVE_VPRINTF
+/* Output an error message and exit */
+
+static void
+fatal VPROTO((char *format, ...))
+{
+#ifndef __STDC__
+ char *format;
+#endif
+ va_list ap;
+
+ VA_START (ap, format);
+
+#ifndef __STDC__
+ format = va_arg (ap, char*);
+#endif
+
+ fprintf (stderr, "%s: ", programname);
+ vfprintf (stderr, format, ap);
+ va_end (ap);
+ fprintf (stderr, "\n");
+#if 0
+ /* XXX Not needed for g++ driver. */
+ delete_temp_files ();
+#endif
+ exit (1);
+}
+
+static void
+error VPROTO((char *format, ...))
+{
+#ifndef __STDC__
+ char *format;
+#endif
+ va_list ap;
+
+ VA_START (ap, format);
+
+#ifndef __STDC__
+ format = va_arg (ap, char*);
+#endif
+
+ fprintf (stderr, "%s: ", programname);
+ vfprintf (stderr, format, ap);
+ va_end (ap);
+
+ fprintf (stderr, "\n");
+}
+
+#else /* not HAVE_VPRINTF */
+
+static void
+error (msg, arg1, arg2)
+ char *msg, *arg1, *arg2;
+{
+ fprintf (stderr, "%s: ", programname);
+ fprintf (stderr, msg, arg1, arg2);
+ fprintf (stderr, "\n");
+}
+
+static void
+fatal (msg, arg1, arg2)
+ char *msg, *arg1, *arg2;
+{
+ error (msg, arg1, arg2);
+#if 0
+ /* XXX Not needed for g++ driver. */
+ delete_temp_files ();
+#endif
+ exit (1);
+}
+
+#endif /* not HAVE_VPRINTF */
+
+/* More 'friendly' abort that prints the line and file.
+ config.h can #define abort fancy_abort if you like that sort of thing. */
+
+void
+fancy_abort ()
+{
+ fatal ("Internal f77 abort.");
+}
+
+char *
+xmalloc (size)
+ unsigned size;
+{
+ register char *value = (char *) malloc (size);
+ if (value == 0)
+ fatal ("virtual memory exhausted");
+ return value;
+}
+
+/* Return a newly-allocated string whose contents concatenate those
+ of s1, s2, s3. */
+static char *
+concat (s1, s2, s3)
+ char *s1, *s2, *s3;
+{
+ int len1 = strlen (s1), len2 = strlen (s2), len3 = strlen (s3);
+ char *result = xmalloc (len1 + len2 + len3 + 1);
+
+ strcpy (result, s1);
+ strcpy (result + len1, s2);
+ strcpy (result + len1 + len2, s3);
+ *(result + len1 + len2 + len3) = 0;
+
+ return result;
+}
+
+static void
+pfatal_with_name (name)
+ char *name;
+{
+ char *s;
+
+ if (errno < sys_nerr)
+ s = concat ("%s: ", sys_errlist[errno], "");
+ else
+ s = "cannot open %s";
+ fatal (s, name);
+}
+
+#ifdef __MSDOS__
+/* This is the common prefix we use to make temp file names. */
+char *temp_filename;
+
+/* Length of the prefix. */
+int temp_filename_length;
+
+/* Compute a string to use as the base of all temporary file names. */
+static char *
+choose_temp_base_try (try, base)
+char *try;
+char *base;
+{
+ char *rv;
+ if (base)
+ rv = base;
+ else if (try == (char *)0)
+ rv = 0;
+ else if (access (try, R_OK | W_OK) != 0)
+ rv = 0;
+ else
+ rv = try;
+ return rv;
+}
+
+static void
+choose_temp_base ()
+{
+ char *base = 0;
+ int len;
+
+ base = choose_temp_base_try (getenv ("TMPDIR"), base);
+ base = choose_temp_base_try (getenv ("TMP"), base);
+ base = choose_temp_base_try (getenv ("TEMP"), base);
+
+#ifdef P_tmpdir
+ base = choose_temp_base_try (P_tmpdir, base);
+#endif
+
+ base = choose_temp_base_try ("/usr/tmp", base);
+ base = choose_temp_base_try ("/tmp", base);
+
+ /* If all else fails, use the current directory! */
+ if (base == (char *)0)
+ base = "./";
+
+ len = strlen (base);
+ temp_filename = xmalloc (len + sizeof("/ccXXXXXX"));
+ strcpy (temp_filename, base);
+ if (len > 0 && temp_filename[len-1] != '/')
+ temp_filename[len++] = '/';
+ strcpy (temp_filename + len, "ccXXXXXX");
+
+ mktemp (temp_filename);
+ temp_filename_length = strlen (temp_filename);
+ if (temp_filename_length == 0)
+ abort ();
+}
+
+static void
+perror_exec (name)
+ char *name;
+{
+ char *s;
+
+ if (errno < sys_nerr)
+ s = concat ("installation problem, cannot exec %s: ",
+ sys_errlist[errno], "");
+ else
+ s = "installation problem, cannot exec %s";
+ error (s, name);
+}
+
+/* This is almost exactly what's in gcc.c:pexecute for MSDOS. */
+void
+run_dos (program, argv)
+ char *program;
+ char *argv[];
+{
+ char *scmd, *rf;
+ FILE *argfile;
+ int i;
+
+ choose_temp_base (); /* not in gcc.c */
+
+ scmd = (char *) malloc (strlen (program) + strlen (temp_filename) + 10);
+ rf = scmd + strlen (program) + 6;
+ sprintf (scmd, "%s.exe @%s.gp", program, temp_filename);
+
+ argfile = fopen (rf, "w");
+ if (argfile == 0)
+ pfatal_with_name (rf);
+
+ for (i=1; argv[i]; i++)
+ {
+ char *cp;
+ for (cp = argv[i]; *cp; cp++)
+ {
+ if (*cp == '"' || *cp == '\'' || *cp == '\\' || isspace (*cp))
+ fputc ('\\', argfile);
+ fputc (*cp, argfile);
+ }
+ fputc ('\n', argfile);
+ }
+ fclose (argfile);
+
+ i = system (scmd);
+
+ remove (rf);
+
+ if (i == -1)
+ perror_exec (program);
+}
+#endif /* __MSDOS__ */
+
+int
+main (argc, argv)
+ int argc;
+ char **argv;
+{
+ register int i, j = 0;
+ register char *p;
+ int verbose = 0;
+
+ /* This will be NULL if we encounter a situation where we should not
+ link in libf2c. */
+ char *library = "-lf2c";
+
+ /* Used to track options that take arguments, so we don't go wrapping
+ those with -xf2c/-xnone. */
+ char *quote = NULL;
+
+ /* The new argument list will be contained in this. */
+ char **arglist;
+
+ /* The name of the compiler we will want to run---by default, it
+ will be the definition of `GCC_NAME', e.g., `gcc'. */
+ char *gcc = GCC_NAME;
+
+ /* Non-zero if we saw a `-xfoo' language specification on the
+ command line. Used to avoid adding our own -xf2c if the user
+ already gave a language for the file. */
+ int saw_speclang = 0;
+
+ /* Non-zero if we saw `-lm' or `-lmath' on the command line. */
+ int saw_math = 0;
+
+ /* The number of arguments being added to what's in argv. By
+ default it's one new argument (adding `-lf2c'). We use this
+ to track the number of times we've inserted -xf2c/-xnone as well. */
+ int added = 2;
+
+ /* An array used to flag each argument that needs a bit set for
+ LANGSPEC or MATHLIB. */
+ int *args;
+
+ p = argv[0] + strlen (argv[0]);
+ while (p != argv[0] && p[-1] != '/')
+ --p;
+ programname = p;
+
+ if (argc == 1)
+ fatal ("No input files specified");
+
+#ifndef __MSDOS__
+ /* We do a little magic to find out where the main gcc executable
+ is. If they ran us as /usr/local/bin/f77, then we will look
+ for /usr/local/bin/gcc; similarly, if they just ran us as `f77',
+ we'll just look for `gcc'. */
+ if (p != argv[0])
+ {
+ *--p = '\0';
+ gcc = (char *) malloc ((strlen (argv[0]) + 1 + strlen (GCC_NAME) + 1)
+ * sizeof (char));
+ sprintf (gcc, "%s/%s", argv[0], GCC_NAME);
+ }
+#endif
+
+ args = (int *) malloc (argc * sizeof (int));
+ bzero (args, argc * sizeof (int));
+
+ for (i = 1; i < argc; i++)
+ {
+ /* If the previous option took an argument, we swallow it here. */
+ if (quote)
+ {
+ quote = NULL;
+ continue;
+ }
+
+ if (argv[i][0] == '\0' || argv[i][1] == '\0')
+ continue;
+
+ if (argv[i][0] == '-')
+ {
+ if (strcmp (argv[i], "-nostdlib") == 0)
+ {
+ added--;
+ library = NULL;
+ }
+ else if (strcmp (argv[i], "-lm") == 0
+ || strcmp (argv[i], "-lmath") == 0)
+ args[i] |= MATHLIB;
+ else if (strcmp (argv[i], "-v") == 0)
+ {
+ verbose = 1;
+ if (argc == 2)
+ {
+ /* If they only gave us `-v', don't try to link
+ in libf2c. */
+ added--;
+ library = NULL;
+ }
+ }
+ else if (strncmp (argv[i], "-x", 2) == 0)
+ saw_speclang = 1;
+ else if (((argv[i][2] == '\0'
+ && (char *)strchr ("bBVDUoeTuIYmLiA", argv[i][1]) != NULL)
+ || strcmp (argv[i], "-Tdata") == 0))
+ quote = argv[i];
+ else if (((argv[i][2] == '\0'
+ && (char *) strchr ("cSEM", argv[i][1]) != NULL)
+ || strcmp (argv[i], "-MM") == 0))
+ {
+ /* Don't specify libraries if we won't link, since that would
+ cause a warning. */
+ added--;
+ library = NULL;
+ }
+ else
+ /* Pass other options through. */
+ continue;
+ }
+ else
+ {
+ int len;
+
+ if (saw_speclang)
+ continue;
+
+ /* If the filename ends in .c or .i, put options around it.
+ But not if a specified -x option is currently active. */
+ len = strlen (argv[i]);
+ if (len > 2
+ && (argv[i][len - 1] == 'c' || argv[i][len - 1] == 'i')
+ && argv[i][len - 2] == '.')
+ {
+ args[i] |= LANGSPEC;
+ added += 2;
+ }
+ }
+ }
+
+ if (quote)
+ fatal ("argument to `%s' missing\n", quote);
+
+ if (added)
+ {
+ arglist = (char **) malloc ((argc + added + 1) * sizeof (char *));
+
+ for (i = 1, j = 1; i < argc; i++, j++)
+ {
+ arglist[j] = argv[i];
+
+ /* Make sure -lf2c is before the math library, since libg++
+ itself uses those math routines. */
+ if (!saw_math && (args[i] & MATHLIB) && library)
+ {
+ saw_math = 1;
+ arglist[j] = library;
+ arglist[++j] = argv[i];
+ }
+ /* ljo: We want .i and .c treated as C, so don't do anything */
+#if 0
+ /* Wrap foo.c and foo.i files in a language specification to
+ force the gcc compiler driver to run cc1plus on them. */
+ if (args[i] & LANGSPEC)
+ {
+ int len = strlen (argv[i]);
+ if (argv[i][len - 1] == 'i')
+ arglist[j++] = "-xc++-cpp-output";
+ else
+ arglist[j++] = "-xc++";
+ arglist[j++] = argv[i];
+ arglist[j] = "-xnone";
+ }
+#endif
+ }
+
+ /* Add `-lf2c' if we haven't already done so. */
+ if (library && !saw_math){
+ arglist[j++] = library;
+ arglist[j++] = "-lm";
+ }
+ arglist[j] = NULL;
+ }
+ else
+ /* No need to copy 'em all. */
+ arglist = argv;
+
+ arglist[0] = gcc;
+
+ if (verbose)
+ {
+ if (j == 0)
+ j = argc;
+
+ for (i = 0; i < j; i++)
+ fprintf (stderr, " %s", arglist[i]);
+ fprintf (stderr, "\n");
+ }
+#ifndef OS2
+#ifdef __MSDOS__
+ run_dos (gcc, arglist);
+#else /* !__MSDOS__ */
+ if (execvp (gcc, arglist) < 0)
+ pfatal_with_name (gcc);
+#endif /* __MSDOS__ */
+#else /* OS2 */
+ if (spawnvp (gcc, arglist) < 0)
+ pfatal_with_name (gcc);
+#endif
+
+ return 0;
+}
diff --git a/gnu/usr.bin/cc/include/bc-arity.h b/gnu/usr.bin/cc/include/bc-arity.h
index d311745..c75c040 100644
--- a/gnu/usr.bin/cc/include/bc-arity.h
+++ b/gnu/usr.bin/cc/include/bc-arity.h
@@ -2,16 +2,16 @@
{ 1, 0, 0, {0}},
{ 1, 2, 0, {0}},
{ 1, 2, 0, {0}},
-{ 0, 0, 1, {SIcode, }},
-{ 0, 0, 1, {SIcode, }},
-{ 0, 1, 1, {QIcode, }},
-{ 0, 1, 1, {HIcode, }},
-{ 0, 1, 1, {SIcode, }},
-{ 0, 1, 1, {DIcode, }},
-{ 0, 1, 1, {SFcode, }},
-{ 0, 1, 1, {DFcode, }},
-{ 0, 1, 1, {XFcode, }},
-{ 0, 1, 1, {Pcode, }},
+{ 0, 0, 1, {(char) SIcode, }},
+{ 0, 0, 1, {(char) SIcode, }},
+{ 0, 1, 1, {(char) QIcode, }},
+{ 0, 1, 1, {(char) HIcode, }},
+{ 0, 1, 1, {(char) SIcode, }},
+{ 0, 1, 1, {(char) DIcode, }},
+{ 0, 1, 1, {(char) SFcode, }},
+{ 0, 1, 1, {(char) DFcode, }},
+{ 0, 1, 1, {(char) XFcode, }},
+{ 0, 1, 1, {(char) Pcode, }},
{ 1, 1, 0, {0}},
{ 1, 1, 0, {0}},
{ 1, 1, 0, {0}},
@@ -30,10 +30,10 @@
{ 2, 0, 0, {0}},
{ 3, 0, 0, {0}},
{ 2, 0, 0, {0}},
-{ 1, 1, 1, {SIcode, }},
+{ 1, 1, 1, {(char) SIcode, }},
{ 1, 1, 0, {0}},
-{ 0, 1, 1, {SIcode, }},
-{ 0, 1, 1, {SIcode, }},
+{ 0, 1, 1, {(char) SIcode, }},
+{ 0, 1, 1, {(char) SIcode, }},
{ 1, 1, 0, {0}},
{ 1, 1, 0, {0}},
{ 1, 1, 0, {0}},
@@ -218,15 +218,15 @@
{ 2, 1, 0, {0}},
{ 2, 1, 0, {0}},
{ 4, 1, 0, {0}},
-{ 1, 0, 1, {SIcode, }},
-{ 1, 0, 1, {SIcode, }},
-{ 0, 0, 1, {SIcode, }},
+{ 1, 0, 1, {(char) SIcode, }},
+{ 1, 0, 1, {(char) SIcode, }},
+{ 0, 0, 1, {(char) SIcode, }},
{ 0, 0, 0, {0}},
-{ 1, 0, 3, {SIcode, SIcode, SIcode, }},
-{ 1, 0, 3, {SIcode, SIcode, SIcode, }},
-{ 1, 0, 3, {SIcode, SIcode, SIcode, }},
-{ 1, 0, 3, {SIcode, SIcode, SIcode, }},
+{ 1, 0, 3, {(char) SIcode, (char) SIcode, (char) SIcode, }},
+{ 1, 0, 3, {(char) SIcode, (char) SIcode, (char) SIcode, }},
+{ 1, 0, 3, {(char) SIcode, (char) SIcode, (char) SIcode, }},
+{ 1, 0, 3, {(char) SIcode, (char) SIcode, (char) SIcode, }},
{ 3, 0, 0, {0}},
{ 0, 1, 0, {0}},
{ 0, 0, 0, {0}},
-{ 0, 0, 1, {SIcode, }},
+{ 0, 0, 1, {(char) SIcode, }},
diff --git a/gnu/usr.bin/cc/include/bi-run.h b/gnu/usr.bin/cc/include/bi-run.h
index 669f2ab..391ab8a 100644
--- a/gnu/usr.bin/cc/include/bi-run.h
+++ b/gnu/usr.bin/cc/include/bi-run.h
@@ -39,7 +39,7 @@ struct callinfo
struct argtype retvaltype; /* Type of return value */
struct argtype argtypes[1]; /* Argument types */
};
-
+
/* Structure describing a bytecode function. If this changes, we also
need to change expand_function_end () in bc-trans.c */
struct bytecode
diff --git a/gnu/usr.bin/cc/include/bytecode.h b/gnu/usr.bin/cc/include/bytecode.h
index 87030be..16397b1 100644
--- a/gnu/usr.bin/cc/include/bytecode.h
+++ b/gnu/usr.bin/cc/include/bytecode.h
@@ -33,7 +33,7 @@ extern int max_stack_depth;
opcode = TREE_INT_CST_LOW (CST); \
bc_emit_bytecode_const ((char *) &opcode, sizeof opcode); \
}
-
+
#else
#define bc_emit_bytecode_DI_const(CST) \
@@ -43,7 +43,7 @@ extern int max_stack_depth;
opcode = TREE_INT_CST_HIGH (CST); \
bc_emit_bytecode_const ((char *) &opcode, sizeof opcode); \
}
-
+
#endif
diff --git a/gnu/usr.bin/cc/include/c-gperf.h b/gnu/usr.bin/cc/include/c-gperf.h
index edaaf22..4946075 100644
--- a/gnu/usr.bin/cc/include/c-gperf.h
+++ b/gnu/usr.bin/cc/include/c-gperf.h
@@ -49,10 +49,10 @@ hash (str, len)
static struct resword wordlist[] =
{
- {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",},
- {"",},
+ {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",},
+ {"",},
{"int", TYPESPEC, RID_INT},
- {"",}, {"",},
+ {"",}, {"",},
{"__typeof__", TYPEOF, NORID},
{"__signed__", TYPESPEC, RID_SIGNED},
{"__imag__", IMAGPART, NORID},
@@ -71,20 +71,20 @@ static struct resword wordlist[] =
{"__complex__", TYPESPEC, RID_COMPLEX},
{"__iterator", SCSPEC, RID_ITERATOR},
{"bycopy", TYPE_QUAL, RID_BYCOPY},
- {"",}, {"",}, {"",},
+ {"",}, {"",}, {"",},
{"__complex", TYPESPEC, RID_COMPLEX},
- {"",},
+ {"",},
{"in", TYPE_QUAL, RID_IN},
{"break", BREAK, NORID},
{"@defs", DEFS, NORID},
- {"",}, {"",}, {"",},
+ {"",}, {"",}, {"",},
{"extern", SCSPEC, RID_EXTERN},
{"if", IF, NORID},
{"typeof", TYPEOF, NORID},
{"typedef", SCSPEC, RID_TYPEDEF},
{"__typeof", TYPEOF, NORID},
{"sizeof", SIZEOF, NORID},
- {"",},
+ {"",},
{"return", RETURN, NORID},
{"const", TYPE_QUAL, RID_CONST},
{"__volatile__", TYPE_QUAL, RID_VOLATILE},
@@ -92,71 +92,71 @@ static struct resword wordlist[] =
{"@selector", SELECTOR, NORID},
{"__volatile", TYPE_QUAL, RID_VOLATILE},
{"__asm__", ASM_KEYWORD, NORID},
- {"",}, {"",},
+ {"",}, {"",},
{"continue", CONTINUE, NORID},
{"__alignof__", ALIGNOF, NORID},
{"__imag", IMAGPART, NORID},
{"__attribute__", ATTRIBUTE, NORID},
- {"",}, {"",},
+ {"",}, {"",},
{"__attribute", ATTRIBUTE, NORID},
{"for", FOR, NORID},
- {"",},
+ {"",},
{"@encode", ENCODE, NORID},
{"id", OBJECTNAME, RID_ID},
{"static", SCSPEC, RID_STATIC},
{"@interface", INTERFACE, NORID},
- {"",},
+ {"",},
{"__signed", TYPESPEC, RID_SIGNED},
- {"",},
+ {"",},
{"__label__", LABEL, NORID},
- {"",}, {"",},
+ {"",}, {"",},
{"__asm", ASM_KEYWORD, NORID},
{"char", TYPESPEC, RID_CHAR},
- {"",},
+ {"",},
{"inline", SCSPEC, RID_INLINE},
{"out", TYPE_QUAL, RID_OUT},
{"register", SCSPEC, RID_REGISTER},
{"__real", REALPART, NORID},
{"short", TYPESPEC, RID_SHORT},
- {"",},
+ {"",},
{"enum", ENUM, NORID},
{"inout", TYPE_QUAL, RID_INOUT},
- {"",},
+ {"",},
{"oneway", TYPE_QUAL, RID_ONEWAY},
{"union", UNION, NORID},
- {"",},
+ {"",},
{"__alignof", ALIGNOF, NORID},
- {"",},
+ {"",},
{"@implementation", IMPLEMENTATION, NORID},
- {"",},
+ {"",},
{"@class", CLASS, NORID},
- {"",},
+ {"",},
{"@public", PUBLIC, NORID},
{"asm", ASM_KEYWORD, NORID},
- {"",}, {"",}, {"",}, {"",}, {"",},
+ {"",}, {"",}, {"",}, {"",}, {"",},
{"default", DEFAULT, NORID},
- {"",},
+ {"",},
{"void", TYPESPEC, RID_VOID},
- {"",},
+ {"",},
{"@protected", PROTECTED, NORID},
{"@protocol", PROTOCOL, NORID},
- {"",}, {"",}, {"",},
+ {"",}, {"",}, {"",},
{"volatile", TYPE_QUAL, RID_VOLATILE},
- {"",}, {"",},
+ {"",}, {"",},
{"signed", TYPESPEC, RID_SIGNED},
{"float", TYPESPEC, RID_FLOAT},
{"@end", END, NORID},
- {"",}, {"",},
+ {"",}, {"",},
{"unsigned", TYPESPEC, RID_UNSIGNED},
{"@compatibility_alias", ALIAS, NORID},
{"double", TYPESPEC, RID_DOUBLE},
- {"",}, {"",},
+ {"",}, {"",},
{"auto", SCSPEC, RID_AUTO},
- {"",},
+ {"",},
{"goto", GOTO, NORID},
- {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",},
+ {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",},
{"do", DO, NORID},
- {"",}, {"",}, {"",}, {"",},
+ {"",}, {"",}, {"",}, {"",},
{"long", TYPESPEC, RID_LONG},
};
diff --git a/gnu/usr.bin/cc/include/expr.h b/gnu/usr.bin/cc/include/expr.h
index 3bb9490..affc28d 100644
--- a/gnu/usr.bin/cc/include/expr.h
+++ b/gnu/usr.bin/cc/include/expr.h
@@ -191,7 +191,7 @@ enum direction {none, upward, downward}; /* Value has this type. */
/* Supply a default definition for FUNCTION_ARG_BOUNDARY. Normally, we let
FUNCTION_ARG_PADDING, which also pads the length, handle any needed
alignment. */
-
+
#ifndef FUNCTION_ARG_BOUNDARY
#define FUNCTION_ARG_BOUNDARY(MODE, TYPE) PARM_BOUNDARY
#endif
@@ -284,7 +284,7 @@ extern optab sub_optab;
extern optab smul_optab; /* Signed and floating-point multiply */
extern optab smul_highpart_optab; /* Signed multiply, return high word */
extern optab umul_highpart_optab;
-extern optab smul_widen_optab; /* Signed multiply with result
+extern optab smul_widen_optab; /* Signed multiply with result
one machine mode wider than args */
extern optab umul_widen_optab;
extern optab sdiv_optab; /* Signed divide */
@@ -372,6 +372,13 @@ extern rtx bcmp_libfunc;
extern rtx memset_libfunc;
extern rtx bzero_libfunc;
+extern rtx eqhf2_libfunc;
+extern rtx nehf2_libfunc;
+extern rtx gthf2_libfunc;
+extern rtx gehf2_libfunc;
+extern rtx lthf2_libfunc;
+extern rtx lehf2_libfunc;
+
extern rtx eqsf2_libfunc;
extern rtx nesf2_libfunc;
extern rtx gtsf2_libfunc;
@@ -480,6 +487,9 @@ extern int expand_twoval_binop PROTO((optab, rtx, rtx, rtx, rtx, int));
/* Expand a unary arithmetic operation given optab rtx operand. */
extern rtx expand_unop PROTO((enum machine_mode, optab, rtx, rtx, int));
+/* Expand the absolute value operation. */
+extern rtx expand_abs PROTO((enum machine_mode, rtx, rtx, int, int));
+
/* Expand the complex absolute value operation. */
extern rtx expand_complex_abs PROTO((enum machine_mode, rtx, rtx, int));
diff --git a/gnu/usr.bin/cc/include/gbl-ctors.h b/gnu/usr.bin/cc/include/gbl-ctors.h
index 2e7f520..f673fb9 100644
--- a/gnu/usr.bin/cc/include/gbl-ctors.h
+++ b/gnu/usr.bin/cc/include/gbl-ctors.h
@@ -63,18 +63,23 @@ extern void __do_global_dtors ();
we define it once here as a macro to avoid various instances getting
out-of-sync with one another. */
-/* The first word may or may not contain the number of pointers in the table.
+/* Some systems place the number of pointers
+ in the first word of the table.
+ On other systems, that word is -1.
In all cases, the table is null-terminated.
- We ignore the first word and scan up to the null. */
+ If the length is not recorded, count up to the null. */
/* Some systems use a different strategy for finding the ctors.
For example, svr3. */
#ifndef DO_GLOBAL_CTORS_BODY
#define DO_GLOBAL_CTORS_BODY \
do { \
- func_ptr *p; \
- for (p = __CTOR_LIST__ + 1; *p; ) \
- (*p++) (); \
+ unsigned long nptrs = (unsigned long) __CTOR_LIST__[0]; \
+ unsigned i; \
+ if (nptrs == -1) \
+ for (nptrs = 0; __CTOR_LIST__[nptrs + 1] != 0; nptrs++); \
+ for (i = nptrs; i >= 1; i--) \
+ __CTOR_LIST__[i] (); \
} while (0)
#endif
diff --git a/gnu/usr.bin/cc/include/hard-reg-set.h b/gnu/usr.bin/cc/include/hard-reg-set.h
index 6bc668b..66111d5 100644
--- a/gnu/usr.bin/cc/include/hard-reg-set.h
+++ b/gnu/usr.bin/cc/include/hard-reg-set.h
@@ -209,7 +209,7 @@ extern char call_used_regs[FIRST_PSEUDO_REGISTER];
/* The same info as a HARD_REG_SET. */
extern HARD_REG_SET call_used_reg_set;
-
+
/* Indexed by hard register number, contains 1 for registers that are
fixed use -- i.e. in fixed_regs -- or a function value return register
or STRUCT_VALUE_REGNUM or STATIC_CHAIN_REGNUM. These are the
diff --git a/gnu/usr.bin/cc/include/i386/bsd.h b/gnu/usr.bin/cc/include/i386/bsd.h
index 8aec304..abc9f0e 100644
--- a/gnu/usr.bin/cc/include/i386/bsd.h
+++ b/gnu/usr.bin/cc/include/i386/bsd.h
@@ -22,6 +22,9 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
/* Include common aspects of all 386 Unix assemblers. */
#include "i386/unix.h"
+/* Don't assume anything about the header files. */
+#define NO_IMPLICIT_EXTERN_C
+
/* Use the Sequent Symmetry assembler syntax. */
#define TARGET_VERSION fprintf (stderr, " (80386, BSD syntax)");
diff --git a/gnu/usr.bin/cc/include/i386/i386.h b/gnu/usr.bin/cc/include/i386/i386.h
index 983bfc5..8d6bf34 100644
--- a/gnu/usr.bin/cc/include/i386/i386.h
+++ b/gnu/usr.bin/cc/include/i386/i386.h
@@ -1,4 +1,4 @@
-/* Definitions of target machine for GNU compiler for Intel 80386.
+/* Definitions of target machine for GNU compiler for Intel X86 (386, 486, pentium)
Copyright (C) 1988, 1992, 1994 Free Software Foundation, Inc.
This file is part of GNU CC.
@@ -62,77 +62,130 @@ extern int target_flags;
#define TARGET_CPU_DEFAULT 0
#endif
-/* Compile 80387 insns for floating point (not library calls). */
-#define TARGET_80387 (target_flags & 1)
-/* Compile code for an i486. */
-#define TARGET_486 (target_flags & 2)
+/* Masks for the -m switches */
+#define MASK_80387 000000000001 /* Hardware floating point */
+#define MASK_486 000000000002 /* 80486 specific */
+#define MASK_NOTUSED 000000000004 /* bit not currently used */
+#define MASK_RTD 000000000010 /* Use ret that pops args */
+#define MASK_REGPARM 000000000020 /* Pass args in eax, edx */
+#define MASK_SVR3_SHLIB 000000000040 /* Uninit locals into bss */
+#define MASK_IEEE_FP 000000000100 /* IEEE fp comparisons */
+#define MASK_FLOAT_RETURNS 000000000200 /* Return float in st(0) */
+#define MASK_NO_FANCY_MATH_387 000000000400 /* Disable sin, cos, sqrt */
+
+ /* Temporary codegen switches */
+#define MASK_DEBUG_ADDR 000001000000 /* Debug GO_IF_LEGITIMATE_ADDRESS */
+#define MASK_NO_WIDE_MULTIPLY 000002000000 /* Disable 32x32->64 multiplies */
+#define MASK_NO_MOVE 000004000000 /* Don't generate mem->mem */
+
+/* Use the floating point instructions */
+#define TARGET_80387 (target_flags & MASK_80387)
+
/* Compile using ret insn that pops args.
This will not work unless you use prototypes at least
- for all functions that can take varying numbers of args. */
-#define TARGET_RTD (target_flags & 8)
+ for all functions that can take varying numbers of args. */
+#define TARGET_RTD (target_flags & MASK_RTD)
+
/* Compile passing first two args in regs 0 and 1.
This exists only to test compiler features that will
be needed for RISC chips. It is not usable
and is not intended to be usable on this cpu. */
-#define TARGET_REGPARM (target_flags & 020)
+#define TARGET_REGPARM (target_flags & MASK_RTD)
/* Put uninitialized locals into bss, not data.
Meaningful only on svr3. */
-#define TARGET_SVR3_SHLIB (target_flags & 040)
+#define TARGET_SVR3_SHLIB (target_flags & MASK_SVR3_SHLIB)
/* Use IEEE floating point comparisons. These handle correctly the cases
where the result of a comparison is unordered. Normally SIGFPE is
generated in such cases, in which case this isn't needed. */
-#define TARGET_IEEE_FP (target_flags & 0100)
+#define TARGET_IEEE_FP (target_flags & MASK_IEEE_FP)
/* Functions that return a floating point value may return that value
in the 387 FPU or in 386 integer registers. If set, this flag causes
the 387 to be used, which is compatible with most calling conventions. */
-#define TARGET_FLOAT_RETURNS_IN_80387 (target_flags & 0200)
+#define TARGET_FLOAT_RETURNS_IN_80387 (target_flags & MASK_FLOAT_RETURNS)
/* Disable generation of FP sin, cos and sqrt operations for 387.
This is because FreeBSD lacks these in the math-emulator-code */
-#define TARGET_NO_FANCY_MATH_387 (target_flags & 0400)
-
-/* Macro to define tables used to set the flags.
- This is a list in braces of pairs in braces,
- each pair being { "NAME", VALUE }
- where VALUE is the bits to set or minus the bits to clear.
- An empty string NAME is used to identify the default VALUE. */
-
-#define TARGET_SWITCHES \
- { { "80387", 1}, \
- { "no-80387", -1}, \
- { "soft-float", -1}, \
- { "no-soft-float", 1}, \
- { "486", 2}, \
- { "no-486", -2}, \
- { "386", -2}, \
- { "rtd", 8}, \
- { "no-rtd", -8}, \
- { "regparm", 020}, \
- { "no-regparm", -020}, \
- { "svr3-shlib", 040}, \
- { "no-svr3-shlib", -040}, \
- { "ieee-fp", 0100}, \
- { "no-ieee-fp", -0100}, \
- { "fp-ret-in-387", 0200}, \
- { "no-fp-ret-in-387", -0200}, \
- { "no-fancy-math-387", 0400}, \
- { "fancy-math-387", -0400}, \
- SUBTARGET_SWITCHES \
- { "", TARGET_DEFAULT | TARGET_CPU_DEFAULT}}
-
-/* This is meant to be redefined in the host dependent files */
+#define TARGET_NO_FANCY_MATH_387 (target_flags & MASK_NO_FANCY_MATH_387)
+
+/* Temporary switches for tuning code generation */
+
+/* Disable 32x32->64 bit multiplies that are used for long long multiplies
+ and division by constants, but sometimes cause reload problems. */
+#define TARGET_NO_WIDE_MULTIPLY (target_flags & MASK_NO_WIDE_MULTIPLY)
+#define TARGET_WIDE_MULTIPLY (!TARGET_NO_WIDE_MULTIPLY)
+
+/* Debug GO_IF_LEGITIMATE_ADDRESS */
+#define TARGET_DEBUG_ADDR (target_flags & MASK_DEBUG_ADDR)
+
+/* Hack macros for tuning code generation */
+#define TARGET_MOVE ((target_flags & MASK_NO_MOVE) == 0) /* Don't generate memory->memory */
+
+/* Specific hardware switches */
+#define TARGET_486 (target_flags & MASK_486) /* 80486DX, 80486SX, 80486DX[24] */
+#define TARGET_386 (!TARGET_486) /* 80386 */
+
+#define TARGET_SWITCHES \
+{ { "80387", MASK_80387 }, \
+ { "no-80387", -MASK_80387 }, \
+ { "hard-float", MASK_80387 }, \
+ { "soft-float", -MASK_80387 }, \
+ { "no-soft-float", MASK_80387 }, \
+ { "386", -MASK_486 }, \
+ { "no-386", MASK_486 }, \
+ { "486", MASK_486 }, \
+ { "no-486", -MASK_486 }, \
+ { "rtd", MASK_RTD }, \
+ { "no-rtd", -MASK_RTD }, \
+ { "regparm", MASK_REGPARM }, \
+ { "no-regparm", -MASK_REGPARM }, \
+ { "svr3-shlib", MASK_SVR3_SHLIB }, \
+ { "no-svr3-shlib", -MASK_SVR3_SHLIB }, \
+ { "ieee-fp", MASK_IEEE_FP }, \
+ { "no-ieee-fp", -MASK_IEEE_FP }, \
+ { "fp-ret-in-387", MASK_FLOAT_RETURNS }, \
+ { "no-fp-ret-in-387", -MASK_FLOAT_RETURNS }, \
+ { "no-fancy-math-387", MASK_NO_FANCY_MATH_387 }, \
+ { "fancy-math-387", -MASK_NO_FANCY_MATH_387 }, \
+ { "no-wide-multiply", MASK_NO_WIDE_MULTIPLY }, \
+ { "wide-multiply", -MASK_NO_WIDE_MULTIPLY }, \
+ { "debug-addr", MASK_DEBUG_ADDR }, \
+ { "no-debug-addr", -MASK_DEBUG_ADDR }, \
+ { "move", -MASK_NO_MOVE }, \
+ { "no-move", MASK_NO_MOVE }, \
+ SUBTARGET_SWITCHES \
+ { "", TARGET_DEFAULT | TARGET_CPU_DEFAULT}}
+
+/* This macro is similar to `TARGET_SWITCHES' but defines names of
+ command options that have values. Its definition is an
+ initializer with a subgrouping for each command option.
+
+ Each subgrouping contains a string constant, that defines the
+ fixed part of the option name, and the address of a variable. The
+ variable, type `char *', is set to the variable part of the given
+ option if the fixed part matches. The actual option name is made
+ by appending `-m' to the specified name. */
+#define TARGET_OPTIONS \
+{ { "reg-alloc=", &i386_reg_alloc_order }, \
+ SUBTARGET_OPTIONS }
+
+/* Sometimes certain combinations of command options do not make
+ sense on a particular target machine. You can define a macro
+ `OVERRIDE_OPTIONS' to take account of this. This macro, if
+ defined, is executed once just after all the command options have
+ been parsed.
+
+ Don't use this macro to turn on various extra optimizations for
+ `-O'. That is what `OPTIMIZATION_OPTIONS' is for. */
+
+#define OVERRIDE_OPTIONS override_options ()
+
+/* These are meant to be redefined in the host dependent files */
#define SUBTARGET_SWITCHES
+#define SUBTARGET_OPTIONS
-#define OVERRIDE_OPTIONS \
-{ \
- SUBTARGET_OVERRIDE_OPTIONS \
-}
-
-/* This is meant to be redefined in the host dependent files */
-#define SUBTARGET_OVERRIDE_OPTIONS
/* target machine storage layout */
@@ -263,11 +316,39 @@ extern int target_flags;
listed once, even those in FIXED_REGISTERS. List frame pointer
late and fixed registers last. Note that, in general, we prefer
registers listed in CALL_USED_REGISTERS, keeping the others
- available for storage of persistent values. */
+ available for storage of persistent values.
+
+ Three different versions of REG_ALLOC_ORDER have been tried:
+
+ If the order is edx, ecx, eax, ... it produces a slightly faster compiler,
+ but slower code on simple functions returning values in eax.
+
+ If the order is eax, ecx, edx, ... it causes reload to abort when compiling
+ perl 4.036 due to not being able to create a DImode register (to hold a 2
+ word union).
+
+ If the order is eax, edx, ecx, ... it produces better code for simple
+ functions, and a slightly slower compiler. Users complained about the code
+ generated by allocating edx first, so restore the 'natural' order of things. */
#define REG_ALLOC_ORDER \
-/*ax,cx,dx,bx,si,di,bp,sp,st,st1,st2,st3,st4,st5,st6,st7,arg*/ \
-{ 0, 2, 1, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 }
+/*ax,dx,cx,bx,si,di,bp,sp,st,st1,st2,st3,st4,st5,st6,st7,arg*/ \
+{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 }
+
+/* A C statement (sans semicolon) to choose the order in which to
+ allocate hard registers for pseudo-registers local to a basic
+ block.
+
+ Store the desired register order in the array `reg_alloc_order'.
+ Element 0 should be the register to allocate first; element 1, the
+ next register; and so on.
+
+ The macro body should not assume anything about the contents of
+ `reg_alloc_order' before execution of the macro.
+
+ On most machines, it is not necessary to define this macro. */
+
+#define ORDER_REGS_FOR_LOCAL_ALLOC order_regs_for_local_alloc ()
/* Macro to conditionally modify fixed_regs/call_used_regs. */
#define CONDITIONAL_REGISTER_USAGE \
@@ -293,7 +374,7 @@ extern int target_flags;
This is ordinarily the length in words of a value of mode MODE
but can be less for certain modes in special long registers.
- Actually there are no two word move instructions for consecutive
+ Actually there are no two word move instructions for consecutive
registers. And only registers 0-3 may have mov byte instructions
applied to them.
*/
@@ -381,6 +462,27 @@ extern int target_flags;
/* Place in which caller passes the structure value address.
0 means push the value on the stack like an argument. */
#define STRUCT_VALUE 0
+
+/* A C expression which can inhibit the returning of certain function
+ values in registers, based on the type of value. A nonzero value
+ says to return the function value in memory, just as large
+ structures are always returned. Here TYPE will be a C expression
+ of type `tree', representing the data type of the value.
+
+ Note that values of mode `BLKmode' must be explicitly handled by
+ this macro. Also, the option `-fpcc-struct-return' takes effect
+ regardless of this macro. On most systems, it is possible to
+ leave the macro undefined; this causes a default definition to be
+ used, whose value is the constant 1 for `BLKmode' values, and 0
+ otherwise.
+
+ Do not use this macro to indicate that structures and unions
+ should always be returned in memory. You should instead use
+ `DEFAULT_PCC_STRUCT_RETURN' to indicate this. */
+
+#define RETURN_IN_MEMORY(TYPE) \
+ ((TYPE_MODE (TYPE) == BLKmode) || int_size_in_bytes (TYPE) > 12)
+
/* Define the classes of registers for register constraints in the
machine description. Also define ranges of constants.
@@ -448,7 +550,7 @@ enum reg_class
0x3, /* AD_REGS */ \
0xf, /* Q_REGS */ \
0x10, 0x20, /* SIREG, DIREG */ \
- 0x1007f, /* INDEX_REGS */ \
+ 0x07f, /* INDEX_REGS */ \
0x100ff, /* GENERAL_REGS */ \
0x0100, 0x0200, /* FP_TOP_REG, FP_SECOND_REG */ \
0xff00, /* FLOAT_REGS */ \
@@ -459,7 +561,6 @@ enum reg_class
reg number REGNO. This could be a conditional expression
or could index an array. */
-extern enum reg_class regclass_map[FIRST_PSEUDO_REGISTER];
#define REGNO_REG_CLASS(REGNO) (regclass_map[REGNO])
/* When defined, the compiler allows registers explicitly used in the
@@ -475,7 +576,7 @@ extern enum reg_class regclass_map[FIRST_PSEUDO_REGISTER];
#define FP_REG_P(X) (REG_P (X) && FP_REGNO_P (REGNO (X)))
#define FP_REGNO_P(n) ((n) >= FIRST_STACK_REG && (n) <= LAST_STACK_REG)
-
+
#define STACK_REG_P(xop) (REG_P (xop) && \
REGNO (xop) >= FIRST_STACK_REG && \
REGNO (xop) <= LAST_STACK_REG)
@@ -591,6 +692,32 @@ extern enum reg_class regclass_map[FIRST_PSEUDO_REGISTER];
#define CLASS_MAX_NREGS(CLASS, MODE) \
(FLOAT_CLASS_P (CLASS) ? 1 : \
((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD))
+
+/* A C expression whose value is nonzero if pseudos that have been
+ assigned to registers of class CLASS would likely be spilled
+ because registers of CLASS are needed for spill registers.
+
+ The default value of this macro returns 1 if CLASS has exactly one
+ register and zero otherwise. On most machines, this default
+ should be used. Only define this macro to some other expression
+ if pseudo allocated by `local-alloc.c' end up in memory because
+ their hard registers were needed for spill regisers. If this
+ macro returns nonzero for those classes, those pseudos will only
+ be allocated by `global.c', which knows how to reallocate the
+ pseudo to another register. If there would not be another
+ register available for reallocation, you should not change the
+ definition of this macro since the only effect of such a
+ definition would be to slow down register allocation. */
+
+#define CLASS_LIKELY_SPILLED_P(CLASS) \
+ (((CLASS) == AREG) \
+ || ((CLASS) == DREG) \
+ || ((CLASS) == CREG) \
+ || ((CLASS) == BREG) \
+ || ((CLASS) == AD_REGS) \
+ || ((CLASS) == SIREG) \
+ || ((CLASS) == DIREG))
+
/* Stack layout; function entry, exit and calling. */
@@ -762,11 +889,107 @@ extern enum reg_class regclass_map[FIRST_PSEUDO_REGISTER];
} \
}
+/* A C statement or compound statement to output to FILE some
+ assembler code to initialize basic-block profiling for the current
+ object module. This code should call the subroutine
+ `__bb_init_func' once per object module, passing it as its sole
+ argument the address of a block allocated in the object module.
+
+ The name of the block is a local symbol made with this statement:
+
+ ASM_GENERATE_INTERNAL_LABEL (BUFFER, "LPBX", 0);
+
+ Of course, since you are writing the definition of
+ `ASM_GENERATE_INTERNAL_LABEL' as well as that of this macro, you
+ can take a short cut in the definition of this macro and use the
+ name that you know will result.
+
+ The first word of this block is a flag which will be nonzero if the
+ object module has already been initialized. So test this word
+ first, and do not call `__bb_init_func' if the flag is nonzero. */
+
+#undef FUNCTION_BLOCK_PROFILER
+#define FUNCTION_BLOCK_PROFILER(STREAM, LABELNO) \
+do \
+ { \
+ static int num_func = 0; \
+ rtx xops[8]; \
+ char block_table[80], false_label[80]; \
+ \
+ ASM_GENERATE_INTERNAL_LABEL (block_table, "LPBX", 0); \
+ ASM_GENERATE_INTERNAL_LABEL (false_label, "LPBZ", num_func); \
+ \
+ xops[0] = const0_rtx; \
+ xops[1] = gen_rtx (SYMBOL_REF, VOIDmode, block_table); \
+ xops[2] = gen_rtx (MEM, Pmode, gen_rtx (SYMBOL_REF, VOIDmode, false_label)); \
+ xops[3] = gen_rtx (MEM, Pmode, gen_rtx (SYMBOL_REF, VOIDmode, "__bb_init_func")); \
+ xops[4] = gen_rtx (MEM, Pmode, xops[1]); \
+ xops[5] = stack_pointer_rtx; \
+ xops[6] = GEN_INT (4); \
+ xops[7] = gen_rtx (REG, Pmode, 0); /* eax */ \
+ \
+ CONSTANT_POOL_ADDRESS_P (xops[1]) = TRUE; \
+ CONSTANT_POOL_ADDRESS_P (xops[2]) = TRUE; \
+ \
+ output_asm_insn (AS2(cmp%L4,%0,%4), xops); \
+ output_asm_insn (AS1(jne,%2), xops); \
+ \
+ if (!flag_pic) \
+ output_asm_insn (AS1(push%L1,%1), xops); \
+ else \
+ { \
+ output_asm_insn (AS2 (lea%L7,%a1,%7), xops); \
+ output_asm_insn (AS1 (push%L7,%7), xops); \
+ } \
+ \
+ output_asm_insn (AS1(call,%P3), xops); \
+ output_asm_insn (AS2(add%L0,%6,%5), xops); \
+ ASM_OUTPUT_INTERNAL_LABEL (STREAM, "LPBZ", num_func); \
+ num_func++; \
+ } \
+while (0)
+
+
+/* A C statement or compound statement to increment the count
+ associated with the basic block number BLOCKNO. Basic blocks are
+ numbered separately from zero within each compilation. The count
+ associated with block number BLOCKNO is at index BLOCKNO in a
+ vector of words; the name of this array is a local symbol made
+ with this statement:
+
+ ASM_GENERATE_INTERNAL_LABEL (BUFFER, "LPBX", 2);
+
+ Of course, since you are writing the definition of
+ `ASM_GENERATE_INTERNAL_LABEL' as well as that of this macro, you
+ can take a short cut in the definition of this macro and use the
+ name that you know will result. */
+
+#define BLOCK_PROFILER(STREAM, BLOCKNO) \
+do \
+ { \
+ rtx xops[1], cnt_rtx; \
+ char counts[80]; \
+ \
+ ASM_GENERATE_INTERNAL_LABEL (counts, "LPBX", 2); \
+ cnt_rtx = gen_rtx (SYMBOL_REF, VOIDmode, counts); \
+ SYMBOL_REF_FLAG (cnt_rtx) = TRUE; \
+ \
+ if (BLOCKNO) \
+ cnt_rtx = plus_constant (cnt_rtx, (BLOCKNO)*4); \
+ \
+ if (flag_pic) \
+ cnt_rtx = gen_rtx (PLUS, Pmode, pic_offset_table_rtx, cnt_rtx); \
+ \
+ xops[0] = gen_rtx (MEM, SImode, cnt_rtx); \
+ output_asm_insn (AS1(inc%L0,%0), xops); \
+ } \
+while (0)
+
/* EXIT_IGNORE_STACK should be nonzero if, when returning from a function,
the stack pointer does not matter. The value is tested only in
functions that have frame pointers.
No definition is equivalent to always zero. */
-/* Note on the 386 it might be more efficient not to define this since
+/* Note on the 386 it might be more efficient not to define this since
we have to restore it ourselves from the frame pointer, in order to
use pop */
@@ -925,36 +1148,35 @@ do { \
After reload, it makes no difference, since pseudo regs have
been eliminated by then. */
-#ifndef REG_OK_STRICT
-
-/* Nonzero if X is a hard reg that can be used as an index or if
- it is a pseudo reg. */
-#define REG_OK_FOR_INDEX_P(X) \
- (REGNO (X) < STACK_POINTER_REGNUM \
+/* Non strict versions, pseudos are ok */
+#define REG_OK_FOR_INDEX_NONSTRICT_P(X) \
+ (REGNO (X) < STACK_POINTER_REGNUM \
|| REGNO (X) >= FIRST_PSEUDO_REGISTER)
-/* Nonzero if X is a hard reg that can be used as a base reg
- of if it is a pseudo reg. */
- /* ?wfs */
-
-#define REG_OK_FOR_BASE_P(X) \
- (REGNO (X) <= STACK_POINTER_REGNUM \
- || REGNO (X) == ARG_POINTER_REGNUM \
- || REGNO(X) >= FIRST_PSEUDO_REGISTER)
+#define REG_OK_FOR_BASE_NONSTRICT_P(X) \
+ (REGNO (X) <= STACK_POINTER_REGNUM \
+ || REGNO (X) == ARG_POINTER_REGNUM \
+ || REGNO (X) >= FIRST_PSEUDO_REGISTER)
-#define REG_OK_FOR_STRREG_P(X) \
+#define REG_OK_FOR_STRREG_NONSTRICT_P(X) \
(REGNO (X) == 4 || REGNO (X) == 5 || REGNO (X) >= FIRST_PSEUDO_REGISTER)
-#else
-
-/* Nonzero if X is a hard reg that can be used as an index. */
-#define REG_OK_FOR_INDEX_P(X) REGNO_OK_FOR_INDEX_P (REGNO (X))
-/* Nonzero if X is a hard reg that can be used as a base reg. */
-#define REG_OK_FOR_BASE_P(X) REGNO_OK_FOR_BASE_P (REGNO (X))
-#define REG_OK_FOR_STRREG_P(X) \
+/* Strict versions, hard registers only */
+#define REG_OK_FOR_INDEX_STRICT_P(X) REGNO_OK_FOR_INDEX_P (REGNO (X))
+#define REG_OK_FOR_BASE_STRICT_P(X) REGNO_OK_FOR_BASE_P (REGNO (X))
+#define REG_OK_FOR_STRREG_STRICT_P(X) \
(REGNO_OK_FOR_DIREG_P (REGNO (X)) || REGNO_OK_FOR_SIREG_P (REGNO (X)))
+#ifndef REG_OK_STRICT
+#define REG_OK_FOR_INDEX_P(X) REG_OK_FOR_INDEX_NONSTRICT_P(X)
+#define REG_OK_FOR_BASE_P(X) REG_OK_FOR_BASE_NONSTRICT_P(X)
+#define REG_OK_FOR_STRREG_P(X) REG_OK_FOR_STRREG_NONSTRICT_P(X)
+
+#else
+#define REG_OK_FOR_INDEX_P(X) REG_OK_FOR_INDEX_STRICT_P(X)
+#define REG_OK_FOR_BASE_P(X) REG_OK_FOR_BASE_STRICT_P(X)
+#define REG_OK_FOR_STRREG_P(X) REG_OK_FOR_STRREG_STRICT_P(X)
#endif
/* GO_IF_LEGITIMATE_ADDRESS recognizes an RTL expression
@@ -980,62 +1202,22 @@ do { \
#define LEGITIMATE_CONSTANT_P(X) 1
-#define GO_IF_INDEXABLE_BASE(X, ADDR) \
- if (GET_CODE (X) == REG && REG_OK_FOR_BASE_P (X)) goto ADDR
-
-#define LEGITIMATE_INDEX_REG_P(X) \
- (GET_CODE (X) == REG && REG_OK_FOR_INDEX_P (X))
-
-/* Return 1 if X is an index or an index times a scale. */
-
-#define LEGITIMATE_INDEX_P(X) \
- (LEGITIMATE_INDEX_REG_P (X) \
- || (GET_CODE (X) == MULT \
- && LEGITIMATE_INDEX_REG_P (XEXP (X, 0)) \
- && GET_CODE (XEXP (X, 1)) == CONST_INT \
- && (INTVAL (XEXP (X, 1)) == 2 \
- || INTVAL (XEXP (X, 1)) == 4 \
- || INTVAL (XEXP (X, 1)) == 8)))
-
-/* Go to ADDR if X is an index term, a base reg, or a sum of those. */
-
-#define GO_IF_INDEXING(X, ADDR) \
-{ if (LEGITIMATE_INDEX_P (X)) goto ADDR; \
- GO_IF_INDEXABLE_BASE (X, ADDR); \
- if (GET_CODE (X) == PLUS && LEGITIMATE_INDEX_P (XEXP (X, 0))) \
- { GO_IF_INDEXABLE_BASE (XEXP (X, 1), ADDR); } \
- if (GET_CODE (X) == PLUS && LEGITIMATE_INDEX_P (XEXP (X, 1))) \
- { GO_IF_INDEXABLE_BASE (XEXP (X, 0), ADDR); } }
-
-/* We used to allow this, but it isn't ever used.
- || ((GET_CODE (X) == POST_DEC || GET_CODE (X) == POST_INC) \
- && REG_P (XEXP (X, 0)) \
- && REG_OK_FOR_STRREG_P (XEXP (X, 0))) \
-*/
+#ifdef REG_OK_STRICT
+#define GO_IF_LEGITIMATE_ADDRESS(MODE, X, ADDR) \
+{ \
+ if (legitimate_address_p (MODE, X, 1)) \
+ goto ADDR; \
+}
-#define GO_IF_LEGITIMATE_ADDRESS(MODE, X, ADDR) \
+#else
+#define GO_IF_LEGITIMATE_ADDRESS(MODE, X, ADDR) \
{ \
- if (CONSTANT_ADDRESS_P (X) \
- && (! flag_pic || LEGITIMATE_PIC_OPERAND_P (X))) \
+ if (legitimate_address_p (MODE, X, 0)) \
goto ADDR; \
- GO_IF_INDEXING (X, ADDR); \
- if (GET_CODE (X) == PLUS && CONSTANT_ADDRESS_P (XEXP (X, 1))) \
- { \
- rtx x0 = XEXP (X, 0); \
- if (! flag_pic || ! SYMBOLIC_CONST (XEXP (X, 1))) \
- { GO_IF_INDEXING (x0, ADDR); } \
- else if (x0 == pic_offset_table_rtx) \
- goto ADDR; \
- else if (GET_CODE (x0) == PLUS) \
- { \
- if (XEXP (x0, 0) == pic_offset_table_rtx) \
- { GO_IF_INDEXABLE_BASE (XEXP (x0, 1), ADDR); } \
- if (XEXP (x0, 1) == pic_offset_table_rtx) \
- { GO_IF_INDEXABLE_BASE (XEXP (x0, 0), ADDR); } \
- } \
- } \
}
+#endif
+
/* Try machine-dependent ways of modifying an illegitimate address
to be legitimate. If we find one, return the new, valid address.
This macro is used in only one place: `memory_address' in explow.c.
@@ -1057,41 +1239,16 @@ do { \
When -fpic is used, special handling is needed for symbolic references.
See comments by legitimize_pic_address in i386.c for details. */
-#define LEGITIMIZE_ADDRESS(X,OLDX,MODE,WIN) \
-{ extern rtx legitimize_pic_address (); \
- int ch = (X) != (OLDX); \
- if (flag_pic && SYMBOLIC_CONST (X)) \
- { \
- (X) = legitimize_pic_address (X, 0); \
- if (memory_address_p (MODE, X)) \
- goto WIN; \
- } \
- if (GET_CODE (X) == PLUS) \
- { if (GET_CODE (XEXP (X, 0)) == MULT) \
- ch = 1, XEXP (X, 0) = force_operand (XEXP (X, 0), 0); \
- if (GET_CODE (XEXP (X, 1)) == MULT) \
- ch = 1, XEXP (X, 1) = force_operand (XEXP (X, 1), 0); \
- if (ch && GET_CODE (XEXP (X, 1)) == REG \
- && GET_CODE (XEXP (X, 0)) == REG) \
- goto WIN; \
- if (flag_pic && SYMBOLIC_CONST (XEXP (X, 1))) \
- ch = 1, (X) = legitimize_pic_address (X, 0); \
- if (ch) { GO_IF_LEGITIMATE_ADDRESS (MODE, X, WIN); } \
- if (GET_CODE (XEXP (X, 0)) == REG) \
- { register rtx temp = gen_reg_rtx (Pmode); \
- register rtx val = force_operand (XEXP (X, 1), temp); \
- if (val != temp) emit_move_insn (temp, val); \
- XEXP (X, 1) = temp; \
- goto WIN; } \
- else if (GET_CODE (XEXP (X, 1)) == REG) \
- { register rtx temp = gen_reg_rtx (Pmode); \
- register rtx val = force_operand (XEXP (X, 0), temp); \
- if (val != temp) emit_move_insn (temp, val); \
- XEXP (X, 0) = temp; \
- goto WIN; }}}
+#define LEGITIMIZE_ADDRESS(X, OLDX, MODE, WIN) \
+{ \
+ rtx orig_x = (X); \
+ (X) = legitimize_address (X, OLDX, MODE); \
+ if (memory_address_p (MODE, X)) \
+ goto WIN; \
+}
/* Nonzero if the constant value X is a legitimate general operand
- when generating PIC code. It is given that flag_pic is on and
+ when generating PIC code. It is given that flag_pic is on and
that X satisfies CONSTANT_P or is a CONST_DOUBLE. */
#define LEGITIMATE_PIC_OPERAND_P(X) \
@@ -1312,7 +1469,6 @@ while (0)
stored from the compare operation. Note that we can't use "rtx" here
since it hasn't been defined! */
-extern struct rtx_def *i386_compare_op0, *i386_compare_op1;
extern struct rtx_def *(*i386_compare_gen)(), *(*i386_compare_gen_eq)();
/* Tell final.c how to eliminate redundant test instructions. */
@@ -1515,7 +1671,7 @@ do { long l; \
/* This is how to output an element of a case-vector that is relative.
We don't use these on the 386 yet, because the ATT assembler can't do
- forward reference the differences.
+ forward reference the differences.
*/
#define ASM_OUTPUT_ADDR_DIFF_ELT(FILE, VALUE, REL) \
@@ -1658,6 +1814,60 @@ extern char *qi_high_reg_name[];
#define RET return ""
#define AT_SP(mode) (gen_rtx (MEM, (mode), stack_pointer_rtx))
+/* Functions in i386.c */
+extern void override_options ();
+extern void order_regs_for_local_alloc ();
+extern void output_op_from_reg ();
+extern void output_to_reg ();
+extern char *singlemove_string ();
+extern char *output_move_double ();
+extern char *output_move_memory ();
+extern char *output_move_pushmem ();
+extern int standard_80387_constant_p ();
+extern char *output_move_const_single ();
+extern int symbolic_operand ();
+extern int call_insn_operand ();
+extern int expander_call_insn_operand ();
+extern int symbolic_reference_mentioned_p ();
+extern void emit_pic_move ();
+extern void function_prologue ();
+extern int simple_386_epilogue ();
+extern void function_epilogue ();
+extern int legitimate_address_p ();
+extern struct rtx_def *legitimize_pic_address ();
+extern struct rtx_def *legitimize_address ();
+extern void print_operand ();
+extern void print_operand_address ();
+extern void notice_update_cc ();
+extern void split_di ();
+extern int binary_387_op ();
+extern int shift_op ();
+extern int VOIDmode_compare_op ();
+extern char *output_387_binary_op ();
+extern char *output_fix_trunc ();
+extern char *output_float_compare ();
+extern char *output_fp_cc0_set ();
+extern void save_386_machine_status ();
+extern void restore_386_machine_status ();
+extern void clear_386_stack_locals ();
+extern struct rtx_def *assign_386_stack_local ();
+
+/* Variables in i386.c */
+extern char *i386_reg_alloc_order; /* register allocation order */
+extern char *hi_reg_name[]; /* names for 16 bit regs */
+extern char *qi_reg_name[]; /* names for 8 bit regs (low) */
+extern char *qi_high_reg_name[]; /* names for 8 bit regs (high) */
+extern enum reg_class regclass_map[]; /* smalled class containing REGNO */
+extern struct rtx_def *i386_compare_op0; /* operand 0 for comparisons */
+extern struct rtx_def *i386_compare_op1; /* operand 1 for comparisons */
+
+/* External variables used */
+extern int optimize; /* optimization level */
+extern int obey_regdecls; /* TRUE if stupid register allocation */
+
+/* External functions used */
+extern struct rtx_def *force_operand ();
+
/*
Local variables:
version-control: t
diff --git a/gnu/usr.bin/cc/include/i386/unix.h b/gnu/usr.bin/cc/include/i386/unix.h
index 7209176..0f0b5d5 100644
--- a/gnu/usr.bin/cc/include/i386/unix.h
+++ b/gnu/usr.bin/cc/include/i386/unix.h
@@ -1,5 +1,5 @@
/* Definitions for Unix assembler syntax for the Intel 80386.
- Copyright (C) 1988 Free Software Foundation, Inc.
+ Copyright (C) 1988, 1994 Free Software Foundation, Inc.
This file is part of GNU CC.
@@ -28,15 +28,17 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
/* Note that the other files fail to use these
in some of the places where they should. */
-#ifdef __STDC__
+#if defined(__STDC__) || defined(ALMOST_STDC)
#define AS2(a,b,c) #a " " #b "," #c
+#define AS2C(b,c) " " #b "," #c
#define AS3(a,b,c,d) #a " " #b "," #c "," #d
#define AS1(a,b) #a " " #b
#else
#define AS1(a,b) "a b"
#define AS2(a,b,c) "a b,c"
+#define AS2C(b,c) " b,c"
#define AS3(a,b,c,d) "a b,c,d"
-#endif
+#endif
/* Define macro used to output shift-double opcodes when the shift
count is in %cl. Some assemblers require %cl as an argument;
@@ -74,7 +76,7 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
do \
{ fputs (",", (FILE)); PRINT_REG ((IREG), 0, (FILE)); } \
while (0)
-
+
/* Print an index scale factor SCALE. */
#define PRINT_SCALE(FILE,SCALE) \
if ((SCALE) != 1) fprintf ((FILE), ",%d", (SCALE))
@@ -96,7 +98,6 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
/* String containing the assembler's comment-starter. */
#define ASM_COMMENT_START "/"
-#define COMMENT_BEGIN "/"
/* Output to assembler file text saying following lines
may contain character constants, extra white space, comments, etc. */
diff --git a/gnu/usr.bin/cc/include/insn-codes.h b/gnu/usr.bin/cc/include/insn-codes.h
index 59e24c9..2c5c593 100644
--- a/gnu/usr.bin/cc/include/insn-codes.h
+++ b/gnu/usr.bin/cc/include/insn-codes.h
@@ -32,169 +32,184 @@ enum insn_code {
CODE_FOR_cmpdf_ccfpeq = 40,
CODE_FOR_cmpsf_cc = 41,
CODE_FOR_cmpsf_ccfpeq = 42,
- CODE_FOR_movsi = 48,
- CODE_FOR_movhi = 51,
- CODE_FOR_movstricthi = 52,
- CODE_FOR_movqi = 54,
- CODE_FOR_movstrictqi = 55,
- CODE_FOR_movsf = 57,
- CODE_FOR_swapdf = 59,
- CODE_FOR_movdf = 60,
- CODE_FOR_swapxf = 62,
- CODE_FOR_movxf = 63,
- CODE_FOR_movdi = 65,
- CODE_FOR_zero_extendhisi2 = 66,
- CODE_FOR_zero_extendqihi2 = 67,
- CODE_FOR_zero_extendqisi2 = 68,
- CODE_FOR_zero_extendsidi2 = 69,
- CODE_FOR_extendsidi2 = 70,
- CODE_FOR_extendhisi2 = 71,
- CODE_FOR_extendqihi2 = 72,
- CODE_FOR_extendqisi2 = 73,
- CODE_FOR_extendsfdf2 = 74,
- CODE_FOR_extenddfxf2 = 75,
- CODE_FOR_extendsfxf2 = 76,
- CODE_FOR_truncdfsf2 = 77,
- CODE_FOR_truncxfsf2 = 79,
- CODE_FOR_truncxfdf2 = 80,
- CODE_FOR_fixuns_truncxfsi2 = 81,
- CODE_FOR_fixuns_truncdfsi2 = 82,
- CODE_FOR_fixuns_truncsfsi2 = 83,
- CODE_FOR_fix_truncxfdi2 = 84,
- CODE_FOR_fix_truncdfdi2 = 85,
- CODE_FOR_fix_truncsfdi2 = 86,
- CODE_FOR_fix_truncxfsi2 = 90,
- CODE_FOR_fix_truncdfsi2 = 91,
- CODE_FOR_fix_truncsfsi2 = 92,
- CODE_FOR_floatsisf2 = 96,
- CODE_FOR_floatdisf2 = 97,
- CODE_FOR_floatsidf2 = 98,
- CODE_FOR_floatdidf2 = 99,
- CODE_FOR_floatsixf2 = 100,
- CODE_FOR_floatdixf2 = 101,
- CODE_FOR_adddi3 = 108,
- CODE_FOR_addsi3 = 109,
- CODE_FOR_addhi3 = 110,
- CODE_FOR_addqi3 = 111,
- CODE_FOR_addxf3 = 113,
- CODE_FOR_adddf3 = 114,
- CODE_FOR_addsf3 = 115,
- CODE_FOR_subdi3 = 116,
- CODE_FOR_subsi3 = 117,
- CODE_FOR_subhi3 = 118,
- CODE_FOR_subqi3 = 119,
- CODE_FOR_subxf3 = 120,
- CODE_FOR_subdf3 = 121,
- CODE_FOR_subsf3 = 122,
- CODE_FOR_mulhi3 = 124,
- CODE_FOR_mulsi3 = 126,
- CODE_FOR_umulqihi3 = 127,
- CODE_FOR_mulqihi3 = 128,
- CODE_FOR_umulsidi3 = 129,
- CODE_FOR_mulsidi3 = 130,
- CODE_FOR_mulxf3 = 131,
- CODE_FOR_muldf3 = 132,
- CODE_FOR_mulsf3 = 133,
- CODE_FOR_divqi3 = 134,
- CODE_FOR_udivqi3 = 135,
- CODE_FOR_divxf3 = 136,
- CODE_FOR_divdf3 = 137,
- CODE_FOR_divsf3 = 138,
- CODE_FOR_divmodsi4 = 139,
- CODE_FOR_divmodhi4 = 140,
- CODE_FOR_udivmodsi4 = 141,
- CODE_FOR_udivmodhi4 = 142,
- CODE_FOR_andsi3 = 143,
- CODE_FOR_andhi3 = 144,
- CODE_FOR_andqi3 = 145,
- CODE_FOR_iorsi3 = 146,
- CODE_FOR_iorhi3 = 147,
- CODE_FOR_iorqi3 = 148,
- CODE_FOR_xorsi3 = 149,
- CODE_FOR_xorhi3 = 150,
- CODE_FOR_xorqi3 = 151,
- CODE_FOR_negdi2 = 152,
- CODE_FOR_negsi2 = 153,
- CODE_FOR_neghi2 = 154,
- CODE_FOR_negqi2 = 155,
- CODE_FOR_negsf2 = 156,
- CODE_FOR_negdf2 = 157,
- CODE_FOR_negxf2 = 159,
- CODE_FOR_abssf2 = 161,
- CODE_FOR_absdf2 = 162,
- CODE_FOR_absxf2 = 164,
- CODE_FOR_sqrtsf2 = 166,
- CODE_FOR_sqrtdf2 = 167,
- CODE_FOR_sqrtxf2 = 169,
- CODE_FOR_sindf2 = 172,
- CODE_FOR_sinsf2 = 173,
- CODE_FOR_cosdf2 = 175,
- CODE_FOR_cossf2 = 176,
- CODE_FOR_one_cmplsi2 = 178,
- CODE_FOR_one_cmplhi2 = 179,
- CODE_FOR_one_cmplqi2 = 180,
- CODE_FOR_ashldi3 = 181,
- CODE_FOR_ashldi3_const_int = 182,
- CODE_FOR_ashldi3_non_const_int = 183,
- CODE_FOR_ashlsi3 = 184,
- CODE_FOR_ashlhi3 = 185,
- CODE_FOR_ashlqi3 = 186,
- CODE_FOR_ashrdi3 = 187,
- CODE_FOR_ashrdi3_const_int = 188,
- CODE_FOR_ashrdi3_non_const_int = 189,
- CODE_FOR_ashrsi3 = 190,
- CODE_FOR_ashrhi3 = 191,
- CODE_FOR_ashrqi3 = 192,
- CODE_FOR_lshrdi3 = 193,
- CODE_FOR_lshrdi3_const_int = 194,
- CODE_FOR_lshrdi3_non_const_int = 195,
- CODE_FOR_lshrsi3 = 196,
- CODE_FOR_lshrhi3 = 197,
- CODE_FOR_lshrqi3 = 198,
- CODE_FOR_rotlsi3 = 199,
- CODE_FOR_rotlhi3 = 200,
- CODE_FOR_rotlqi3 = 201,
- CODE_FOR_rotrsi3 = 202,
- CODE_FOR_rotrhi3 = 203,
- CODE_FOR_rotrqi3 = 204,
- CODE_FOR_seq = 211,
- CODE_FOR_sne = 213,
- CODE_FOR_sgt = 215,
- CODE_FOR_sgtu = 217,
- CODE_FOR_slt = 219,
- CODE_FOR_sltu = 221,
- CODE_FOR_sge = 223,
- CODE_FOR_sgeu = 225,
- CODE_FOR_sle = 227,
- CODE_FOR_sleu = 229,
- CODE_FOR_beq = 231,
- CODE_FOR_bne = 233,
- CODE_FOR_bgt = 235,
- CODE_FOR_bgtu = 237,
- CODE_FOR_blt = 239,
- CODE_FOR_bltu = 241,
- CODE_FOR_bge = 243,
- CODE_FOR_bgeu = 245,
- CODE_FOR_ble = 247,
- CODE_FOR_bleu = 249,
- CODE_FOR_jump = 261,
- CODE_FOR_indirect_jump = 262,
- CODE_FOR_casesi = 263,
- CODE_FOR_tablejump = 265,
- CODE_FOR_call_pop = 266,
- CODE_FOR_call = 269,
- CODE_FOR_call_value_pop = 272,
- CODE_FOR_call_value = 275,
- CODE_FOR_untyped_call = 278,
- CODE_FOR_untyped_return = 281,
- CODE_FOR_update_return = 282,
- CODE_FOR_return = 283,
- CODE_FOR_nop = 284,
- CODE_FOR_movstrsi = 285,
- CODE_FOR_cmpstrsi = 287,
- CODE_FOR_ffssi2 = 290,
- CODE_FOR_ffshi2 = 292,
- CODE_FOR_strlensi = 307,
+ CODE_FOR_movsi = 49,
+ CODE_FOR_movhi = 54,
+ CODE_FOR_movstricthi = 56,
+ CODE_FOR_movqi = 61,
+ CODE_FOR_movstrictqi = 63,
+ CODE_FOR_movsf = 65,
+ CODE_FOR_movsf_push_nomove = 66,
+ CODE_FOR_movsf_push = 67,
+ CODE_FOR_movsf_mem = 68,
+ CODE_FOR_movsf_normal = 69,
+ CODE_FOR_swapsf = 70,
+ CODE_FOR_movdf = 71,
+ CODE_FOR_movdf_push_nomove = 72,
+ CODE_FOR_movdf_push = 73,
+ CODE_FOR_movdf_mem = 74,
+ CODE_FOR_movdf_normal = 75,
+ CODE_FOR_swapdf = 76,
+ CODE_FOR_movxf = 77,
+ CODE_FOR_movxf_push_nomove = 78,
+ CODE_FOR_movxf_push = 79,
+ CODE_FOR_movxf_mem = 80,
+ CODE_FOR_movxf_normal = 81,
+ CODE_FOR_swapxf = 82,
+ CODE_FOR_movdi = 84,
+ CODE_FOR_zero_extendhisi2 = 85,
+ CODE_FOR_zero_extendqihi2 = 86,
+ CODE_FOR_zero_extendqisi2 = 87,
+ CODE_FOR_zero_extendsidi2 = 88,
+ CODE_FOR_extendsidi2 = 89,
+ CODE_FOR_extendhisi2 = 90,
+ CODE_FOR_extendqihi2 = 91,
+ CODE_FOR_extendqisi2 = 92,
+ CODE_FOR_extendsfdf2 = 93,
+ CODE_FOR_extenddfxf2 = 94,
+ CODE_FOR_extendsfxf2 = 95,
+ CODE_FOR_truncdfsf2 = 96,
+ CODE_FOR_truncxfsf2 = 98,
+ CODE_FOR_truncxfdf2 = 99,
+ CODE_FOR_fixuns_truncxfsi2 = 100,
+ CODE_FOR_fixuns_truncdfsi2 = 101,
+ CODE_FOR_fixuns_truncsfsi2 = 102,
+ CODE_FOR_fix_truncxfdi2 = 103,
+ CODE_FOR_fix_truncdfdi2 = 104,
+ CODE_FOR_fix_truncsfdi2 = 105,
+ CODE_FOR_fix_truncxfsi2 = 109,
+ CODE_FOR_fix_truncdfsi2 = 110,
+ CODE_FOR_fix_truncsfsi2 = 111,
+ CODE_FOR_floatsisf2 = 115,
+ CODE_FOR_floatdisf2 = 116,
+ CODE_FOR_floatsidf2 = 117,
+ CODE_FOR_floatdidf2 = 118,
+ CODE_FOR_floatsixf2 = 119,
+ CODE_FOR_floatdixf2 = 120,
+ CODE_FOR_adddi3 = 127,
+ CODE_FOR_addsi3 = 128,
+ CODE_FOR_addhi3 = 129,
+ CODE_FOR_addqi3 = 130,
+ CODE_FOR_movsi_lea = 131,
+ CODE_FOR_addxf3 = 132,
+ CODE_FOR_adddf3 = 133,
+ CODE_FOR_addsf3 = 134,
+ CODE_FOR_subdi3 = 135,
+ CODE_FOR_subsi3 = 136,
+ CODE_FOR_subhi3 = 137,
+ CODE_FOR_subqi3 = 138,
+ CODE_FOR_subxf3 = 139,
+ CODE_FOR_subdf3 = 140,
+ CODE_FOR_subsf3 = 141,
+ CODE_FOR_mulhi3 = 143,
+ CODE_FOR_mulsi3 = 145,
+ CODE_FOR_umulqihi3 = 146,
+ CODE_FOR_mulqihi3 = 147,
+ CODE_FOR_umulsidi3 = 148,
+ CODE_FOR_mulsidi3 = 149,
+ CODE_FOR_umulsi3_highpart = 150,
+ CODE_FOR_smulsi3_highpart = 151,
+ CODE_FOR_mulxf3 = 152,
+ CODE_FOR_muldf3 = 153,
+ CODE_FOR_mulsf3 = 154,
+ CODE_FOR_divqi3 = 155,
+ CODE_FOR_udivqi3 = 156,
+ CODE_FOR_divxf3 = 157,
+ CODE_FOR_divdf3 = 158,
+ CODE_FOR_divsf3 = 159,
+ CODE_FOR_divmodsi4 = 160,
+ CODE_FOR_divmodhi4 = 161,
+ CODE_FOR_udivmodsi4 = 162,
+ CODE_FOR_udivmodhi4 = 163,
+ CODE_FOR_andsi3 = 164,
+ CODE_FOR_andhi3 = 165,
+ CODE_FOR_andqi3 = 166,
+ CODE_FOR_iorsi3 = 167,
+ CODE_FOR_iorhi3 = 168,
+ CODE_FOR_iorqi3 = 169,
+ CODE_FOR_xorsi3 = 170,
+ CODE_FOR_xorhi3 = 171,
+ CODE_FOR_xorqi3 = 172,
+ CODE_FOR_negdi2 = 173,
+ CODE_FOR_negsi2 = 174,
+ CODE_FOR_neghi2 = 175,
+ CODE_FOR_negqi2 = 176,
+ CODE_FOR_negsf2 = 177,
+ CODE_FOR_negdf2 = 178,
+ CODE_FOR_negxf2 = 180,
+ CODE_FOR_abssf2 = 182,
+ CODE_FOR_absdf2 = 183,
+ CODE_FOR_absxf2 = 185,
+ CODE_FOR_sqrtsf2 = 187,
+ CODE_FOR_sqrtdf2 = 188,
+ CODE_FOR_sqrtxf2 = 190,
+ CODE_FOR_sindf2 = 193,
+ CODE_FOR_sinsf2 = 194,
+ CODE_FOR_cosdf2 = 196,
+ CODE_FOR_cossf2 = 197,
+ CODE_FOR_one_cmplsi2 = 199,
+ CODE_FOR_one_cmplhi2 = 200,
+ CODE_FOR_one_cmplqi2 = 201,
+ CODE_FOR_ashldi3 = 202,
+ CODE_FOR_ashldi3_const_int = 203,
+ CODE_FOR_ashldi3_non_const_int = 204,
+ CODE_FOR_ashlsi3 = 205,
+ CODE_FOR_ashlhi3 = 206,
+ CODE_FOR_ashlqi3 = 207,
+ CODE_FOR_ashrdi3 = 208,
+ CODE_FOR_ashrdi3_const_int = 209,
+ CODE_FOR_ashrdi3_non_const_int = 210,
+ CODE_FOR_ashrsi3 = 211,
+ CODE_FOR_ashrhi3 = 212,
+ CODE_FOR_ashrqi3 = 213,
+ CODE_FOR_lshrdi3 = 214,
+ CODE_FOR_lshrdi3_const_int = 215,
+ CODE_FOR_lshrdi3_non_const_int = 216,
+ CODE_FOR_lshrsi3 = 217,
+ CODE_FOR_lshrhi3 = 218,
+ CODE_FOR_lshrqi3 = 219,
+ CODE_FOR_rotlsi3 = 220,
+ CODE_FOR_rotlhi3 = 221,
+ CODE_FOR_rotlqi3 = 222,
+ CODE_FOR_rotrsi3 = 223,
+ CODE_FOR_rotrhi3 = 224,
+ CODE_FOR_rotrqi3 = 225,
+ CODE_FOR_seq = 232,
+ CODE_FOR_sne = 234,
+ CODE_FOR_sgt = 236,
+ CODE_FOR_sgtu = 238,
+ CODE_FOR_slt = 240,
+ CODE_FOR_sltu = 242,
+ CODE_FOR_sge = 244,
+ CODE_FOR_sgeu = 246,
+ CODE_FOR_sle = 248,
+ CODE_FOR_sleu = 250,
+ CODE_FOR_beq = 252,
+ CODE_FOR_bne = 254,
+ CODE_FOR_bgt = 256,
+ CODE_FOR_bgtu = 258,
+ CODE_FOR_blt = 260,
+ CODE_FOR_bltu = 262,
+ CODE_FOR_bge = 264,
+ CODE_FOR_bgeu = 266,
+ CODE_FOR_ble = 268,
+ CODE_FOR_bleu = 270,
+ CODE_FOR_jump = 282,
+ CODE_FOR_indirect_jump = 283,
+ CODE_FOR_casesi = 284,
+ CODE_FOR_tablejump = 286,
+ CODE_FOR_call_pop = 287,
+ CODE_FOR_call = 290,
+ CODE_FOR_call_value_pop = 293,
+ CODE_FOR_call_value = 296,
+ CODE_FOR_untyped_call = 299,
+ CODE_FOR_blockage = 300,
+ CODE_FOR_return = 301,
+ CODE_FOR_nop = 302,
+ CODE_FOR_movstrsi = 303,
+ CODE_FOR_cmpstrsi = 305,
+ CODE_FOR_ffssi2 = 308,
+ CODE_FOR_ffshi2 = 310,
+ CODE_FOR_strlensi = 325,
CODE_FOR_nothing };
#define MAX_INSN_CODE ((int) CODE_FOR_nothing)
diff --git a/gnu/usr.bin/cc/include/insn-flags.h b/gnu/usr.bin/cc/include/insn-flags.h
index c9dd771..625671e 100644
--- a/gnu/usr.bin/cc/include/insn-flags.h
+++ b/gnu/usr.bin/cc/include/insn-flags.h
@@ -36,10 +36,23 @@ from the machine description file `md'. */
#define HAVE_movqi 1
#define HAVE_movstrictqi 1
#define HAVE_movsf 1
-#define HAVE_swapdf 1
+#define HAVE_movsf_push_nomove (!TARGET_MOVE)
+#define HAVE_movsf_push 1
+#define HAVE_movsf_mem 1
+#define HAVE_movsf_normal ((!TARGET_MOVE || GET_CODE (operands[0]) != MEM) || (GET_CODE (operands[1]) != MEM))
+#define HAVE_swapsf 1
#define HAVE_movdf 1
-#define HAVE_swapxf 1
+#define HAVE_movdf_push_nomove (!TARGET_MOVE)
+#define HAVE_movdf_push 1
+#define HAVE_movdf_mem 1
+#define HAVE_movdf_normal ((!TARGET_MOVE || GET_CODE (operands[0]) != MEM) || (GET_CODE (operands[1]) != MEM))
+#define HAVE_swapdf 1
#define HAVE_movxf 1
+#define HAVE_movxf_push_nomove (!TARGET_MOVE)
+#define HAVE_movxf_push 1
+#define HAVE_movxf_mem 1
+#define HAVE_movxf_normal ((!TARGET_MOVE || GET_CODE (operands[0]) != MEM) || (GET_CODE (operands[1]) != MEM))
+#define HAVE_swapxf 1
#define HAVE_movdi 1
#define HAVE_zero_extendhisi2 1
#define HAVE_zero_extendqihi2 1
@@ -74,6 +87,7 @@ from the machine description file `md'. */
#define HAVE_addsi3 1
#define HAVE_addhi3 1
#define HAVE_addqi3 1
+#define HAVE_movsi_lea 1
#define HAVE_addxf3 (TARGET_80387)
#define HAVE_adddf3 (TARGET_80387)
#define HAVE_addsf3 (TARGET_80387)
@@ -88,8 +102,10 @@ from the machine description file `md'. */
#define HAVE_mulsi3 1
#define HAVE_umulqihi3 1
#define HAVE_mulqihi3 1
-#define HAVE_umulsidi3 1
-#define HAVE_mulsidi3 1
+#define HAVE_umulsidi3 (TARGET_WIDE_MULTIPLY)
+#define HAVE_mulsidi3 (TARGET_WIDE_MULTIPLY)
+#define HAVE_umulsi3_highpart (TARGET_WIDE_MULTIPLY)
+#define HAVE_smulsi3_highpart (TARGET_WIDE_MULTIPLY)
#define HAVE_mulxf3 (TARGET_80387)
#define HAVE_muldf3 (TARGET_80387)
#define HAVE_mulsf3 (TARGET_80387)
@@ -191,8 +207,7 @@ from the machine description file `md'. */
#define HAVE_call_value_pop 1
#define HAVE_call_value 1
#define HAVE_untyped_call 1
-#define HAVE_untyped_return 1
-#define HAVE_update_return 1
+#define HAVE_blockage 1
#define HAVE_return (simple_386_epilogue ())
#define HAVE_nop 1
#define HAVE_movstrsi 1
@@ -236,10 +251,23 @@ extern rtx gen_movstricthi PROTO((rtx, rtx));
extern rtx gen_movqi PROTO((rtx, rtx));
extern rtx gen_movstrictqi PROTO((rtx, rtx));
extern rtx gen_movsf PROTO((rtx, rtx));
-extern rtx gen_swapdf PROTO((rtx, rtx));
+extern rtx gen_movsf_push_nomove PROTO((rtx, rtx));
+extern rtx gen_movsf_push PROTO((rtx, rtx));
+extern rtx gen_movsf_mem PROTO((rtx, rtx));
+extern rtx gen_movsf_normal PROTO((rtx, rtx));
+extern rtx gen_swapsf PROTO((rtx, rtx));
extern rtx gen_movdf PROTO((rtx, rtx));
-extern rtx gen_swapxf PROTO((rtx, rtx));
+extern rtx gen_movdf_push_nomove PROTO((rtx, rtx));
+extern rtx gen_movdf_push PROTO((rtx, rtx));
+extern rtx gen_movdf_mem PROTO((rtx, rtx));
+extern rtx gen_movdf_normal PROTO((rtx, rtx));
+extern rtx gen_swapdf PROTO((rtx, rtx));
extern rtx gen_movxf PROTO((rtx, rtx));
+extern rtx gen_movxf_push_nomove PROTO((rtx, rtx));
+extern rtx gen_movxf_push PROTO((rtx, rtx));
+extern rtx gen_movxf_mem PROTO((rtx, rtx));
+extern rtx gen_movxf_normal PROTO((rtx, rtx));
+extern rtx gen_swapxf PROTO((rtx, rtx));
extern rtx gen_movdi PROTO((rtx, rtx));
extern rtx gen_zero_extendhisi2 PROTO((rtx, rtx));
extern rtx gen_zero_extendqihi2 PROTO((rtx, rtx));
@@ -274,6 +302,7 @@ extern rtx gen_adddi3 PROTO((rtx, rtx, rtx));
extern rtx gen_addsi3 PROTO((rtx, rtx, rtx));
extern rtx gen_addhi3 PROTO((rtx, rtx, rtx));
extern rtx gen_addqi3 PROTO((rtx, rtx, rtx));
+extern rtx gen_movsi_lea PROTO((rtx, rtx));
extern rtx gen_addxf3 PROTO((rtx, rtx, rtx));
extern rtx gen_adddf3 PROTO((rtx, rtx, rtx));
extern rtx gen_addsf3 PROTO((rtx, rtx, rtx));
@@ -290,6 +319,8 @@ extern rtx gen_umulqihi3 PROTO((rtx, rtx, rtx));
extern rtx gen_mulqihi3 PROTO((rtx, rtx, rtx));
extern rtx gen_umulsidi3 PROTO((rtx, rtx, rtx));
extern rtx gen_mulsidi3 PROTO((rtx, rtx, rtx));
+extern rtx gen_umulsi3_highpart PROTO((rtx, rtx, rtx));
+extern rtx gen_smulsi3_highpart PROTO((rtx, rtx, rtx));
extern rtx gen_mulxf3 PROTO((rtx, rtx, rtx));
extern rtx gen_muldf3 PROTO((rtx, rtx, rtx));
extern rtx gen_mulsf3 PROTO((rtx, rtx, rtx));
@@ -380,8 +411,7 @@ extern rtx gen_indirect_jump PROTO((rtx));
extern rtx gen_casesi PROTO((rtx, rtx, rtx, rtx, rtx));
extern rtx gen_tablejump PROTO((rtx, rtx));
extern rtx gen_untyped_call PROTO((rtx, rtx, rtx));
-extern rtx gen_untyped_return PROTO((rtx, rtx));
-extern rtx gen_update_return PROTO((rtx));
+extern rtx gen_blockage PROTO((void));
extern rtx gen_return PROTO((void));
extern rtx gen_nop PROTO((void));
extern rtx gen_movstrsi PROTO((rtx, rtx, rtx, rtx));
@@ -438,10 +468,23 @@ extern rtx gen_movstricthi ();
extern rtx gen_movqi ();
extern rtx gen_movstrictqi ();
extern rtx gen_movsf ();
-extern rtx gen_swapdf ();
+extern rtx gen_movsf_push_nomove ();
+extern rtx gen_movsf_push ();
+extern rtx gen_movsf_mem ();
+extern rtx gen_movsf_normal ();
+extern rtx gen_swapsf ();
extern rtx gen_movdf ();
-extern rtx gen_swapxf ();
+extern rtx gen_movdf_push_nomove ();
+extern rtx gen_movdf_push ();
+extern rtx gen_movdf_mem ();
+extern rtx gen_movdf_normal ();
+extern rtx gen_swapdf ();
extern rtx gen_movxf ();
+extern rtx gen_movxf_push_nomove ();
+extern rtx gen_movxf_push ();
+extern rtx gen_movxf_mem ();
+extern rtx gen_movxf_normal ();
+extern rtx gen_swapxf ();
extern rtx gen_movdi ();
extern rtx gen_zero_extendhisi2 ();
extern rtx gen_zero_extendqihi2 ();
@@ -476,6 +519,7 @@ extern rtx gen_adddi3 ();
extern rtx gen_addsi3 ();
extern rtx gen_addhi3 ();
extern rtx gen_addqi3 ();
+extern rtx gen_movsi_lea ();
extern rtx gen_addxf3 ();
extern rtx gen_adddf3 ();
extern rtx gen_addsf3 ();
@@ -492,6 +536,8 @@ extern rtx gen_umulqihi3 ();
extern rtx gen_mulqihi3 ();
extern rtx gen_umulsidi3 ();
extern rtx gen_mulsidi3 ();
+extern rtx gen_umulsi3_highpart ();
+extern rtx gen_smulsi3_highpart ();
extern rtx gen_mulxf3 ();
extern rtx gen_muldf3 ();
extern rtx gen_mulsf3 ();
@@ -582,8 +628,7 @@ extern rtx gen_indirect_jump ();
extern rtx gen_casesi ();
extern rtx gen_tablejump ();
extern rtx gen_untyped_call ();
-extern rtx gen_untyped_return ();
-extern rtx gen_update_return ();
+extern rtx gen_blockage ();
extern rtx gen_return ();
extern rtx gen_nop ();
extern rtx gen_movstrsi ();
diff --git a/gnu/usr.bin/cc/include/integrate.h b/gnu/usr.bin/cc/include/integrate.h
index 1176ac0..cb0abf2 100644
--- a/gnu/usr.bin/cc/include/integrate.h
+++ b/gnu/usr.bin/cc/include/integrate.h
@@ -100,7 +100,7 @@ struct inline_remap
rtx dest;
rtx equiv;
} equiv_sets[MAX_RECOG_OPERANDS];
- /* Record the last thing assigned to pc. This is used for folded
+ /* Record the last thing assigned to pc. This is used for folded
conditional branch insns. */
rtx last_pc_value;
#ifdef HAVE_cc0
diff --git a/gnu/usr.bin/cc/include/longlong.h b/gnu/usr.bin/cc/include/longlong.h
index e811c73..0380ef7 100644
--- a/gnu/usr.bin/cc/include/longlong.h
+++ b/gnu/usr.bin/cc/include/longlong.h
@@ -402,7 +402,7 @@
: "=d" (__w) \
: "%dI" ((USItype)(u)), \
"dI" ((USItype)(v))); \
- __w; })
+ __w; })
#endif /* __i960__ */
#if defined (__mc68000__)
diff --git a/gnu/usr.bin/cc/include/machmode.def b/gnu/usr.bin/cc/include/machmode.def
index 24d0ba5..3fa59aa 100644
--- a/gnu/usr.bin/cc/include/machmode.def
+++ b/gnu/usr.bin/cc/include/machmode.def
@@ -67,7 +67,7 @@ DEF_MACHMODE (HImode, "HI", MODE_INT, 2, 2, SImode)
/* Pointers on some machines use this type to distinguish them from ints.
Useful if a pointer is 4 bytes but has some bits that are not significant,
so it is really not quite as wide as an integer. */
-DEF_MACHMODE (PSImode, "PSI", MODE_PARTIAL_INT, 4, 4, VOIDmode)
+DEF_MACHMODE (PSImode, "PSI", MODE_PARTIAL_INT, 4, 4, PDImode)
DEF_MACHMODE (SImode, "SI", MODE_INT, 4, 4, DImode)
DEF_MACHMODE (PDImode, "PDI", MODE_PARTIAL_INT, 8, 8, VOIDmode)
DEF_MACHMODE (DImode, "DI", MODE_INT, 8, 8, TImode)
diff --git a/gnu/usr.bin/cc/include/obstack.h b/gnu/usr.bin/cc/include/obstack.h
index 0176719..7b04c90 100644
--- a/gnu/usr.bin/cc/include/obstack.h
+++ b/gnu/usr.bin/cc/include/obstack.h
@@ -119,7 +119,7 @@ Summary:
but in traditional C it is usually long. If we are in ANSI C and
don't already have ptrdiff_t get it. */
-#if defined (__STDC__) && ! defined (offsetof)
+#if defined (__STDC__) && __STDC__ && ! defined (offsetof)
#if defined (__GNUC__) && defined (IN_GCC)
/* On Next machine, the system's stddef.h screws up if included
after we have defined just ptrdiff_t, so include all of stddef.h.
@@ -132,7 +132,7 @@ Summary:
#include <stddef.h>
#endif
-#ifdef __STDC__
+#if defined (__STDC__) && __STDC__
#define PTR_INT_TYPE ptrdiff_t
#else
#define PTR_INT_TYPE long
@@ -167,7 +167,7 @@ struct obstack /* control current object in current chunk */
/* Declare the external functions we use; they are in obstack.c. */
-#ifdef __STDC__
+#if defined (__STDC__) && __STDC__
extern void _obstack_newchunk (struct obstack *, int);
extern void _obstack_free (struct obstack *, void *);
extern int _obstack_begin (struct obstack *, int, int,
@@ -181,7 +181,7 @@ extern int _obstack_begin ();
extern int _obstack_begin_1 ();
#endif
-#ifdef __STDC__
+#if defined (__STDC__) && __STDC__
/* Do the function-declarations after the structs
but before defining the macros. */
@@ -268,8 +268,11 @@ int obstack_chunk_size (struct obstack *obstack);
#define obstack_blank_fast(h,n) ((h)->next_free += (n))
-#if defined (__GNUC__) && defined (__STDC__)
-#if __GNUC__ < 2
+#if defined (__GNUC__) && defined (__STDC__) && __STDC__
+/* NextStep 2.0 cc is really gcc 1.93 but it defines __GNUC__ = 2 and
+ does not implement __extension__. But that compiler doesn't define
+ __GNUC_MINOR__. */
+#if __GNUC__ < 2 || (__NeXT__ && !__GNUC_MINOR__)
#define __extension__
#endif
@@ -328,7 +331,7 @@ __extension__ \
/* These assume that the obstack alignment is good enough for pointers or ints,
and that the data added so far to the current object
shares that much alignment. */
-
+
#define obstack_ptr_grow(OBSTACK,datum) \
__extension__ \
({ struct obstack *__o = (OBSTACK); \
@@ -492,7 +495,7 @@ __extension__ \
(h)->object_base = (h)->next_free, \
__INT_TO_PTR ((h)->temp)))
-#ifdef __STDC__
+#if defined (__STDC__) && __STDC__
#define obstack_free(h,obj) \
( (h)->temp = (char *)(obj) - (char *) (h)->chunk, \
(((h)->temp > 0 && (h)->temp < (h)->chunk_limit - (char *) (h)->chunk)\
diff --git a/gnu/usr.bin/cc/include/output.h b/gnu/usr.bin/cc/include/output.h
index ebd0a2f..fc15463 100644
--- a/gnu/usr.bin/cc/include/output.h
+++ b/gnu/usr.bin/cc/include/output.h
@@ -33,7 +33,7 @@ extern void app_enable PROTO((void));
Called from varasm.c before most kinds of output. */
extern void app_disable PROTO((void));
-/* Return the number of slots filled in the current
+/* Return the number of slots filled in the current
delayed branch sequence (we don't count the insn needing the
delay slot). Zero if not in a delayed branch sequence. */
extern int dbr_sequence_length PROTO((void));
diff --git a/gnu/usr.bin/cc/include/pcp.h b/gnu/usr.bin/cc/include/pcp.h
index 0b86a87..4ca0727 100644
--- a/gnu/usr.bin/cc/include/pcp.h
+++ b/gnu/usr.bin/cc/include/pcp.h
@@ -46,7 +46,7 @@ struct keydef
#define MAC --- Indicates MAC must be defined with any defn
#undef MAC --- Indicates MAC cannot be defined
-These preconditions must be true for a precompiled file to be used.
+These preconditions must be true for a precompiled file to be used.
The preconditions section is null terminated. */
/* Then, there is a four byte number (in network byte order) which */
@@ -70,7 +70,7 @@ The preconditions section is null terminated. */
Precondition 1
Precondition 2
- .
+ .
.
.
<NUL>
@@ -80,7 +80,7 @@ The preconditions section is null terminated. */
Number of keys
KEYDEF
Key . . . <NUL>
- KEYDEF
+ KEYDEF
Key . . . <NUL>
.
.
diff --git a/gnu/usr.bin/cc/include/real.h b/gnu/usr.bin/cc/include/real.h
index 34d6d67..de51448 100644
--- a/gnu/usr.bin/cc/include/real.h
+++ b/gnu/usr.bin/cc/include/real.h
@@ -216,7 +216,7 @@ extern REAL_VALUE_TYPE real_value_truncate ();
/* Defining REAL_IS_NOT_DOUBLE breaks certain initializations
when REAL_ARITHMETIC etc. are not defined. */
-/* Now see if the host and target machines use the same format.
+/* Now see if the host and target machines use the same format.
If not, define REAL_IS_NOT_DOUBLE (even if we end up representing
reals as doubles because we have no better way in this cross compiler.)
This turns off various optimizations that can happen when we know the
@@ -386,7 +386,7 @@ extern REAL_VALUE_TYPE dconstm1;
/* Union type used for extracting real values from CONST_DOUBLEs
or putting them in. */
-union real_extract
+union real_extract
{
REAL_VALUE_TYPE d;
HOST_WIDE_INT i[sizeof (REAL_VALUE_TYPE) / sizeof (HOST_WIDE_INT)];
diff --git a/gnu/usr.bin/cc/include/regs.h b/gnu/usr.bin/cc/include/regs.h
index 47463bf..1b394b2 100644
--- a/gnu/usr.bin/cc/include/regs.h
+++ b/gnu/usr.bin/cc/include/regs.h
@@ -1,5 +1,5 @@
/* Define per-register tables for data flow info and register allocation.
- Copyright (C) 1987, 1993 Free Software Foundation, Inc.
+ Copyright (C) 1987, 1993, 1994 Free Software Foundation, Inc.
This file is part of GNU CC.
@@ -53,6 +53,12 @@ extern short *reg_n_sets;
extern short *reg_n_deaths;
+/* Indexed by N; says whether a psuedo register N was ever used
+ within a SUBREG that changes the size of the reg. Some machines prohibit
+ such objects to be in certain (usually floating-point) registers. */
+
+extern char *reg_changes_size;
+
/* Get the number of consecutive words required to hold pseudo-reg N. */
#define PSEUDO_REGNO_SIZE(N) \
diff --git a/gnu/usr.bin/cc/include/reload.h b/gnu/usr.bin/cc/include/reload.h
index 4478b6a..d033db7 100644
--- a/gnu/usr.bin/cc/include/reload.h
+++ b/gnu/usr.bin/cc/include/reload.h
@@ -82,7 +82,7 @@ extern rtx reload_reg_rtx[MAX_RELOADS];
enum reload_type
{
- RELOAD_FOR_INPUT, RELOAD_FOR_OUTPUT, RELOAD_FOR_INSN,
+ RELOAD_FOR_INPUT, RELOAD_FOR_OUTPUT, RELOAD_FOR_INSN,
RELOAD_FOR_INPUT_ADDRESS, RELOAD_FOR_OUTPUT_ADDRESS,
RELOAD_FOR_OPERAND_ADDRESS, RELOAD_FOR_OPADDR_ADDR,
RELOAD_OTHER, RELOAD_FOR_OTHER_ADDRESS
@@ -126,7 +126,7 @@ extern enum insn_code reload_out_optab[];
/* Functions from reload.c: */
-/* Return a memory location that will be used to copy X in mode MODE.
+/* Return a memory location that will be used to copy X in mode MODE.
If we haven't already made a location for this mode in this insn,
call find_reloads_address on the location being returned. */
extern rtx get_secondary_mem PROTO((rtx, enum machine_mode,
@@ -216,9 +216,10 @@ extern void mark_home_live PROTO((int));
replacement (such as sp), plus an offset. */
extern rtx eliminate_regs PROTO((rtx, enum machine_mode, rtx));
-/* Emit code to perform an input reload of IN to RELOADREG. IN is from
- operand OPNUM with reload type TYPE. */
-extern rtx gen_input_reload PROTO((rtx, rtx, int, enum reload_type));
+/* Emit code to perform a reload from IN (which may be a reload register) to
+ OUT (which may also be a reload register). IN or OUT is from operand
+ OPNUM with reload type TYPE. */
+extern rtx gen_reload PROTO((rtx, rtx, int, enum reload_type));
/* Functions in caller-save.c: */
diff --git a/gnu/usr.bin/cc/include/rtl.h b/gnu/usr.bin/cc/include/rtl.h
index b0eb1c52..1701dd5 100644
--- a/gnu/usr.bin/cc/include/rtl.h
+++ b/gnu/usr.bin/cc/include/rtl.h
@@ -116,7 +116,7 @@ typedef struct rtx_def
0 if the MEM was a variable or the result of a * operator in C;
1 if it was the result of a . or -> operator (on a struct) in C.
1 in a REG if the register is used only in exit code a loop.
- 1 in a SUBREG expression if was generated from a variable with a
+ 1 in a SUBREG expression if was generated from a variable with a
promoted mode.
1 in a CODE_LABEL if the label is used for nonlocal gotos
and must not be deleted even if its count is zero.
@@ -130,7 +130,7 @@ typedef struct rtx_def
unsigned int in_struct : 1;
/* 1 if this rtx is used. This is used for copying shared structure.
See `unshare_all_rtl'.
- In a REG, this is not needed for that purpose, and used instead
+ In a REG, this is not needed for that purpose, and used instead
in `leaf_renumber_regs_insn'.
In a SYMBOL_REF, means that emit_library_call
has used it as the function. */
@@ -303,7 +303,7 @@ typedef struct rtvec_def{
register is spilled to the stack then the constant value
should be substituted for it. The contents of the REG_EQUIV
is the constant value or memory address, which may be different
- from the source of the SET although it has the same value.
+ from the source of the SET although it has the same value.
REG_EQUAL is like REG_EQUIV except that the destination
is only momentarily equal to the specified rtx. Therefore, it
cannot be used for substitution; but it can be used for cse.
@@ -510,7 +510,7 @@ extern char *note_insn_name[];
/* 1 if the REG contained in SUBREG_REG is already known to be
sign- or zero-extended from the mode of the SUBREG to the mode of
the reg. SUBREG_PROMOTED_UNSIGNED_P gives the signedness of the
- extension.
+ extension.
When used as a LHS, is means that this extension must be done
when assigning to SUBREG_REG. */
@@ -835,7 +835,7 @@ extern rtx const_true_rtx;
extern rtx const_tiny_rtx[3][(int) MAX_MACHINE_MODE];
-/* Returns a constant 0 rtx in mode MODE. Integer modes are treated the
+/* Returns a constant 0 rtx in mode MODE. Integer modes are treated the
same as VOIDmode. */
#define CONST0_RTX(MODE) (const_tiny_rtx[0][(int) (MODE)])
@@ -922,6 +922,10 @@ extern rtx output_constant_def PROTO((union tree_node *));
extern rtx immed_real_const PROTO((union tree_node *));
extern union tree_node *make_tree PROTO((union tree_node *, rtx));
+/* Abort routines */
+extern void fatal_insn_not_found PROTO((rtx));
+extern void fatal_insn PROTO((char *, rtx));
+
/* Define a default value for STORE_FLAG_VALUE. */
#ifndef STORE_FLAG_VALUE
diff --git a/gnu/usr.bin/cc/include/stack.h b/gnu/usr.bin/cc/include/stack.h
index c5d9a25..da4a54d 100644
--- a/gnu/usr.bin/cc/include/stack.h
+++ b/gnu/usr.bin/cc/include/stack.h
@@ -20,7 +20,7 @@ Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
on top of obstacks for GNU C++. */
/* Stack of data placed on obstacks. */
-
+
struct stack_level
{
/* Pointer back to previous such level. */
diff --git a/gnu/usr.bin/cc/include/tm.h b/gnu/usr.bin/cc/include/tm.h
index 12f7ebc..14aa504 100644
--- a/gnu/usr.bin/cc/include/tm.h
+++ b/gnu/usr.bin/cc/include/tm.h
@@ -19,9 +19,6 @@ You should have received a copy of the GNU General Public License
along with GNU CC; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
-/* This goes away when the math-emulator is fixed */
-#define TARGET_CPU_DEFAULT 0400 /* TARGET_NO_FANCY_MATH_387 */
-
/* This is tested by i386gas.h. */
#define YES_UNDERSCORES
@@ -30,8 +27,20 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
/* Get perform_* macros to build libgcc.a. */
#include "i386/perform.h"
+#define MASK_PROFILER_EPILOGUE 010000000000
+
+#define TARGET_PROFILER_EPILOGUE (target_flags & MASK_PROFILER_EPILOGUE)
+
+#undef SUBTARGET_SWITCHES
+#define SUBTARGET_SWITCHES \
+ { "profiler-epilogue", MASK_PROFILER_EPILOGUE}, \
+ { "no-profiler-epilogue", -MASK_PROFILER_EPILOGUE},
+
#undef CPP_PREDEFINES
-#define CPP_PREDEFINES "-Dunix -Di386 -D__FreeBSD__ -D__386BSD__ -Asystem(unix) -Asystem(FreeBSD) -Acpu(i386) -Amachine(i386)"
+#define CPP_PREDEFINES "-Dunix -Di386 -D__FreeBSD__=2 -Asystem(unix) -Asystem(FreeBSD) -Acpu(i386) -Amachine(i386)"
+
+#define STARTFILE_SPEC \
+ "%{pg:gcrt0.o%s}%{!pg:%{p:mcrt0.o%s}%{!p:%{static:scrt0.o%s}%{!static:crt0.o%s}}}"
#define INCLUDE_DEFAULTS { \
{ "/usr/include", 0 }, \
@@ -45,8 +54,12 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
#define LIB_SPEC "%{!p:%{!pg:-lc}}%{p:-lc_p}%{pg:-lc_p}"
#define LINK_SPEC \
- "%{!nostdlib:%{!r*:%{!e*:-e start}}} -dc -dp %{static:-Bstatic} %{assert*} \
+ "%{!nostdlib:%{!r:%{!e*:-e start}}} -dc -dp %{static:-Bstatic} %{assert*} \
%{p:-Bstatic} %{pg:-Bstatic} %{Z}"
+
+/* This goes away when the math emulator is fixed. */
+#undef TARGET_DEFAULT
+#define TARGET_DEFAULT (MASK_NO_FANCY_MATH_387 | 0301)
#undef SIZE_TYPE
#define SIZE_TYPE "unsigned int"
@@ -81,16 +94,19 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
#define FUNCTION_PROFILER_EPILOGUE(FILE) \
{ \
- if (flag_pic) \
- fprintf (FILE, "\tcall *mexitcount@GOT(%%ebx)\n"); \
- else \
- fprintf (FILE, "\tcall mexitcount\n"); \
+ if (TARGET_PROFILER_EPILOGUE) \
+ { \
+ if (flag_pic) \
+ fprintf (FILE, "\tcall *mexitcount@GOT(%%ebx)\n"); \
+ else \
+ fprintf (FILE, "\tcall mexitcount\n"); \
+ } \
}
-/* There are conflicting reports about whether this system uses
- a different assembler syntax. wilson@cygnus.com says # is right. */
-#undef COMMENT_BEGIN
-#define COMMENT_BEGIN "#"
+/* Override the default comment-starter of "/". */
+
+#undef ASM_COMMENT_START
+#define ASM_COMMENT_START "#"
#undef ASM_APP_ON
#define ASM_APP_ON "#APP\n"
@@ -123,6 +139,8 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
* Currently, we need the DECLARE_OBJECT_SIZE stuff.
*/
+#define HANDLE_SYSV_PRAGMA
+
/* Define the strings used for the special svr4 .type and .size directives.
These strings generally do not vary from one system running svr4 to
another, but if a given system (e.g. m88k running svr) needs to use
@@ -132,6 +150,7 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
#define TYPE_ASM_OP ".type"
#define SIZE_ASM_OP ".size"
#define WEAK_ASM_OP ".weak"
+#define SET_ASM_OP ".set"
/* The following macro defines the format used to output the second
operand of the .type assembler directive. Different svr4 assemblers
@@ -181,7 +200,7 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
size_directive_output = 0; \
if (!flag_inhibit_size_directive && DECL_SIZE (DECL)) \
{ \
- size_directive_output = 1; \
+ size_directive_output = 1; \
fprintf (FILE, "\t%s\t ", SIZE_ASM_OP); \
assemble_name (FILE, NAME); \
fprintf (FILE, ",%d\n", int_size_in_bytes (TREE_TYPE (DECL))); \
@@ -195,20 +214,21 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
size_directive_output was set
by ASM_DECLARE_OBJECT_NAME when it was run for the same decl. */
-#define ASM_FINISH_DECLARE_OBJECT(FILE, DECL, TOP_LEVEL, AT_END) \
-do { \
- char *name = XSTR (XEXP (DECL_RTL (DECL), 0), 0); \
- if (!flag_inhibit_size_directive && DECL_SIZE (DECL) \
- && ! AT_END && TOP_LEVEL \
- && DECL_INITIAL (DECL) == error_mark_node \
- && !size_directive_output) \
- { \
- fprintf (FILE, "\t%s\t ", SIZE_ASM_OP); \
- assemble_name (FILE, name); \
- fprintf (FILE, ",%d\n", int_size_in_bytes (TREE_TYPE (DECL))); \
- } \
+#define ASM_FINISH_DECLARE_OBJECT(FILE, DECL, TOP_LEVEL, AT_END) \
+do { \
+ char *name = XSTR (XEXP (DECL_RTL (DECL), 0), 0); \
+ if (!flag_inhibit_size_directive && DECL_SIZE (DECL) \
+ && ! AT_END && TOP_LEVEL \
+ && DECL_INITIAL (DECL) == error_mark_node \
+ && !size_directive_output) \
+ { \
+ fprintf (FILE, "\t%s\t ", SIZE_ASM_OP); \
+ assemble_name (FILE, name); \
+ fprintf (FILE, ",%d\n", int_size_in_bytes (TREE_TYPE (DECL)));\
+ } \
} while (0)
+
/* This is how to declare the size of a function. */
#define ASM_DECLARE_FUNCTION_SIZE(FILE, FNAME, DECL) \
@@ -229,99 +249,3 @@ do { \
putc ('\n', FILE); \
} \
} while (0)
-
-/* This section copied from i386/osfrose.h */
-
-/* A C statement or compound statement to output to FILE some
- assembler code to initialize basic-block profiling for the current
- object module. This code should call the subroutine
- `__bb_init_func' once per object module, passing it as its sole
- argument the address of a block allocated in the object module.
-
- The name of the block is a local symbol made with this statement:
-
- ASM_GENERATE_INTERNAL_LABEL (BUFFER, "LPBX", 0);
-
- Of course, since you are writing the definition of
- `ASM_GENERATE_INTERNAL_LABEL' as well as that of this macro, you
- can take a short cut in the definition of this macro and use the
- name that you know will result.
-
- The first word of this block is a flag which will be nonzero if the
- object module has already been initialized. So test this word
- first, and do not call `__bb_init_func' if the flag is nonzero. */
-
-#undef FUNCTION_BLOCK_PROFILER
-#define FUNCTION_BLOCK_PROFILER(STREAM, LABELNO) \
-do \
- { \
- if (!flag_pic) \
- { \
- fprintf (STREAM, "\tcmpl $0,%sPBX0\n", LPREFIX); \
- fprintf (STREAM, "\tjne 0f\n"); \
- fprintf (STREAM, "\tpushl $%sPBX0\n", LPREFIX); \
- fprintf (STREAM, "\tcall ___bb_init_func\n"); \
- fprintf (STREAM, "0:\n"); \
- } \
- else \
- { \
- fprintf (STREAM, "\tpushl %eax\n"); \
- fprintf (STREAM, "\tmovl %sPBX0@GOT(%ebx),%eax\n"); \
- fprintf (STREAM, "\tcmpl $0,(%eax)\n"); \
- fprintf (STREAM, "\tjne 0f\n"); \
- fprintf (STREAM, "\tpushl %eax\n"); \
- fprintf (STREAM, "\tcall ___bb_init_func@PLT\n"); \
- fprintf (STREAM, "0:\n"); \
- fprintf (STREAM, "\tpopl %eax\n"); \
- } \
- } \
-while (0)
-
-/* A C statement or compound statement to increment the count
- associated with the basic block number BLOCKNO. Basic blocks are
- numbered separately from zero within each compilation. The count
- associated with block number BLOCKNO is at index BLOCKNO in a
- vector of words; the name of this array is a local symbol made
- with this statement:
-
- ASM_GENERATE_INTERNAL_LABEL (BUFFER, "LPBX", 2);
-
- Of course, since you are writing the definition of
- `ASM_GENERATE_INTERNAL_LABEL' as well as that of this macro, you
- can take a short cut in the definition of this macro and use the
- name that you know will result. */
-
-#undef BLOCK_PROFILER
-#define BLOCK_PROFILER(STREAM, BLOCKNO) \
-do \
- { \
- if (!flag_pic) \
- fprintf (STREAM, "\tincl %sPBX2+%d\n", LPREFIX, (BLOCKNO)*4); \
- else \
- { \
- fprintf (STREAM, "\tpushl %eax\n"); \
- fprintf (STREAM, "\tmovl %sPBX2@GOT(%ebx),%eax\n", LPREFIX); \
- fprintf (STREAM, "\tincl %d(%eax)\n", (BLOCKNO)*4); \
- fprintf (STREAM, "\tpopl %eax\n"); \
- } \
- } \
-while (0)
-
-/* This is defined when gcc is compiled in the BSD-directory-tree, and must
- * make up for the gap to all the stuff done in the GNU-makefiles.
- */
-
-#ifdef FREEBSD_NATIVE
-
-#undef MD_EXEC_PREFIX
-#define MD_EXEC_PREFIX "/usr/libexec/"
-
-#undef STANDARD_STARTFILE_PREFIX
-#define STANDARD_STARTFILE_PREFIX "/usr/lib"
-
-#define DEFAULT_TARGET_MACHINE "i386-unknown-freebsd_1.0"
-#define GPLUSPLUS_INCLUDE_DIR "/usr/local/lib/gcc-lib/i386-unknown-freebsd_1.0/2.5.8/include"
-#define TOOL_INCLUDE_DIR "/usr/local/i386-unknown-freebsd_1.0/include"
-#define GCC_INCLUDE_DIR "/usr/local/lib/gcc-lib/i386-unknown-freebsd_1.0/2.5.8/include"
-
-#endif /* FREEBSD_NATIVE */
diff --git a/gnu/usr.bin/cc/include/tree.h b/gnu/usr.bin/cc/include/tree.h
index dbe5ff9..0955ad1 100644
--- a/gnu/usr.bin/cc/include/tree.h
+++ b/gnu/usr.bin/cc/include/tree.h
@@ -242,7 +242,7 @@ struct tree_common
In a FUNCTION_DECL, nonzero means its address is needed.
So it must be compiled even if it is an inline function.
In CONSTRUCTOR nodes, it means object constructed must be in memory.
- In LABEL_DECL nodes, it means a goto for this label has been seen
+ In LABEL_DECL nodes, it means a goto for this label has been seen
from a place outside all binding contours that restore stack levels.
In ..._TYPE nodes, it means that objects of this type must
be fully addressable. This means that pieces of this
@@ -619,6 +619,10 @@ struct tree_block
function when they are created. */
#define TYPE_NEEDS_CONSTRUCTING(NODE) ((NODE)->type.needs_constructing_flag)
+/* Indicates that objects of this type (a UNION_TYPE), should be passed
+ the same way that the first union alternative would be passed. */
+#define TYPE_TRANSPARENT_UNION(NODE) ((NODE)->type.transparent_union_flag)
+
struct tree_type
{
char common[sizeof (struct tree_common)];
@@ -637,6 +641,7 @@ struct tree_type
unsigned string_flag : 1;
unsigned no_force_blk_flag : 1;
unsigned needs_constructing_flag : 1;
+ unsigned transparent_union_flag : 1;
unsigned lang_flag_0 : 1;
unsigned lang_flag_1 : 1;
unsigned lang_flag_2 : 1;
@@ -644,7 +649,7 @@ struct tree_type
unsigned lang_flag_4 : 1;
unsigned lang_flag_5 : 1;
unsigned lang_flag_6 : 1;
- /* room for 6 more bits */
+ /* room for 5 more bits */
unsigned int align;
union tree_node *pointer_to;
@@ -687,7 +692,7 @@ struct tree_type
from the base of the complete object to the base of the part of the
object that is allocated on behalf of this `type'.
This is always 0 except when there is multiple inheritance. */
-
+
#define BINFO_OFFSET(NODE) TREE_VEC_ELT ((NODE), 1)
#define TYPE_BINFO_OFFSET(NODE) BINFO_OFFSET (TYPE_BINFO (NODE))
#define BINFO_OFFSET_ZEROP(NODE) (BINFO_OFFSET (NODE) == integer_zero_node)
@@ -878,10 +883,10 @@ struct tree_type
/* In a TYPE_DECL
nonzero means the detail info about this type is not dumped into stabs.
- Instead it will generate cross reference ('x') of names.
+ Instead it will generate cross reference ('x') of names.
This uses the same flag as DECL_EXTERNAL. */
#define TYPE_DECL_SUPPRESS_DEBUG(NODE) ((NODE)->decl.external_flag)
-
+
/* In VAR_DECL and PARM_DECL nodes, nonzero means declared `register'.
In LABEL_DECL nodes, nonzero means that an error message about
@@ -928,6 +933,11 @@ struct tree_type
so it should not be output now. */
#define DECL_DEFER_OUTPUT(NODE) ((NODE)->decl.defer_output)
+/* Used in PARM_DECLs whose type are unions to indicate that the
+ argument should be passed in the same way that the first union
+ alternative would be passed. */
+#define DECL_TRANSPARENT_UNION(NODE) ((NODE)->decl.transparent_union)
+
/* Additional flags for language-specific uses. */
#define DECL_LANG_FLAG_0(NODE) ((NODE)->decl.lang_flag_0)
#define DECL_LANG_FLAG_1(NODE) ((NODE)->decl.lang_flag_1)
@@ -963,7 +973,8 @@ struct tree_decl
unsigned in_system_header_flag : 1;
unsigned common_flag : 1;
unsigned defer_output : 1;
- /* room for five more */
+ unsigned transparent_union : 1;
+ /* room for four more */
unsigned lang_flag_0 : 1;
unsigned lang_flag_1 : 1;
@@ -1238,6 +1249,12 @@ extern tree get_pending_sizes PROTO((void));
extern tree sizetype;
+/* If nonzero, an upper limit on alignment of structure fields, in bits. */
+extern int maximum_field_alignment;
+
+/* If non-zero, the alignment of a bitsting or (power-)set value, in bits. */
+extern int set_alignment;
+
/* Concatenate two lists (chains of TREE_LIST nodes) X and Y
by making the last node in X point to Y.
Returns X, except if X is 0 returns Y. */
@@ -1481,6 +1498,9 @@ extern void (*incomplete_decl_finalize_hook) ();
/* In tree.c */
extern char *perm_calloc PROTO((int, long));
+extern tree get_set_constructor_bits PROTO((tree, char*, int));
+extern tree get_set_constructor_words PROTO((tree,
+ HOST_WIDE_INT*, int));
/* In stmt.c */
diff --git a/gnu/usr.bin/cc/legal/md b/gnu/usr.bin/cc/legal/md
index 3e43fb0..a4cfff5 100644
--- a/gnu/usr.bin/cc/legal/md
+++ b/gnu/usr.bin/cc/legal/md
@@ -1,4 +1,4 @@
-;; GCC machine description for Intel 80386.
+;; GCC machine description for Intel X86.
;; Copyright (C) 1988, 1994 Free Software Foundation, Inc.
;; Mostly by William Schelter.
@@ -157,7 +157,7 @@
if (find_regno_note (insn, REG_DEAD, FIRST_STACK_REG))
output_asm_insn (AS1 (fstp,%y0), operands);
- return (char *) output_fp_cc0_set (insn);
+ return output_fp_cc0_set (insn);
}")
;; Don't generate tstsf if generating IEEE code, since the `ftst' opcode
@@ -190,7 +190,7 @@
if (find_regno_note (insn, REG_DEAD, FIRST_STACK_REG))
output_asm_insn (AS1 (fstp,%y0), operands);
- return (char *) output_fp_cc0_set (insn);
+ return output_fp_cc0_set (insn);
}")
;; Don't generate tstdf if generating IEEE code, since the `ftst' opcode
@@ -223,7 +223,7 @@
if (find_regno_note (insn, REG_DEAD, FIRST_STACK_REG))
output_asm_insn (AS1 (fstp,%y0), operands);
- return (char *) output_fp_cc0_set (insn);
+ return output_fp_cc0_set (insn);
}")
;; Don't generate tstdf if generating IEEE code, since the `ftst' opcode
@@ -349,7 +349,7 @@
(clobber (match_scratch:HI 3 "=a"))]
"TARGET_80387
&& (GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM)"
- "* return (char *) output_float_compare (insn, operands);")
+ "* return output_float_compare (insn, operands);")
(define_insn ""
[(set (cc0)
@@ -359,7 +359,7 @@
(match_operand:SI 1 "nonimmediate_operand" "rm"))]))
(clobber (match_scratch:HI 3 "=a"))]
"TARGET_80387"
- "* return (char *) output_float_compare (insn, operands);")
+ "* return output_float_compare (insn, operands);")
(define_insn ""
[(set (cc0)
@@ -369,7 +369,7 @@
(match_operand:XF 1 "register_operand" "f")]))
(clobber (match_scratch:HI 3 "=a"))]
"TARGET_80387"
- "* return (char *) output_float_compare (insn, operands);")
+ "* return output_float_compare (insn, operands);")
(define_insn ""
[(set (cc0)
@@ -379,7 +379,7 @@
(match_operand:DF 1 "nonimmediate_operand" "fm"))]))
(clobber (match_scratch:HI 3 "=a"))]
"TARGET_80387"
- "* return (char *) output_float_compare (insn, operands);")
+ "* return output_float_compare (insn, operands);")
(define_insn ""
[(set (cc0)
@@ -389,7 +389,7 @@
(match_operand:SF 1 "nonimmediate_operand" "fm"))]))
(clobber (match_scratch:HI 3 "=a"))]
"TARGET_80387"
- "* return (char *) output_float_compare (insn, operands);")
+ "* return output_float_compare (insn, operands);")
(define_insn ""
[(set (cc0)
@@ -397,7 +397,7 @@
(match_operand:XF 1 "register_operand" "f")))
(clobber (match_scratch:HI 2 "=a"))]
"TARGET_80387"
- "* return (char *) output_float_compare (insn, operands);")
+ "* return output_float_compare (insn, operands);")
(define_insn ""
[(set (cc0)
@@ -407,7 +407,7 @@
(clobber (match_scratch:HI 3 "=a,a"))]
"TARGET_80387
&& (GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM)"
- "* return (char *) output_float_compare (insn, operands);")
+ "* return output_float_compare (insn, operands);")
(define_insn ""
[(set (cc0)
@@ -417,7 +417,7 @@
(match_operand:SI 1 "nonimmediate_operand" "rm"))]))
(clobber (match_scratch:HI 3 "=a"))]
"TARGET_80387"
- "* return (char *) output_float_compare (insn, operands);")
+ "* return output_float_compare (insn, operands);")
(define_insn ""
[(set (cc0)
@@ -427,7 +427,7 @@
(match_operand:DF 1 "register_operand" "f")]))
(clobber (match_scratch:HI 3 "=a"))]
"TARGET_80387"
- "* return (char *) output_float_compare (insn, operands);")
+ "* return output_float_compare (insn, operands);")
(define_insn ""
[(set (cc0)
@@ -437,7 +437,7 @@
(match_operand:SF 1 "nonimmediate_operand" "fm"))]))
(clobber (match_scratch:HI 3 "=a"))]
"TARGET_80387"
- "* return (char *) output_float_compare (insn, operands);")
+ "* return output_float_compare (insn, operands);")
(define_insn ""
[(set (cc0)
@@ -447,7 +447,7 @@
(match_operand:DF 1 "register_operand" "f")]))
(clobber (match_scratch:HI 3 "=a"))]
"TARGET_80387"
- "* return (char *) output_float_compare (insn, operands);")
+ "* return output_float_compare (insn, operands);")
(define_insn ""
[(set (cc0)
@@ -455,7 +455,7 @@
(match_operand:DF 1 "register_operand" "f")))
(clobber (match_scratch:HI 2 "=a"))]
"TARGET_80387"
- "* return (char *) output_float_compare (insn, operands);")
+ "* return output_float_compare (insn, operands);")
;; These two insns will never be generated by combine due to the mode of
;; the COMPARE.
@@ -466,7 +466,7 @@
; (match_operand:SF 1 "register_operand" "f"))))
; (clobber (match_scratch:HI 2 "=a"))]
; "TARGET_80387"
-; "* return (char *) output_float_compare (insn, operands);")
+; "* return output_float_compare (insn, operands);")
;
;(define_insn ""
; [(set (cc0)
@@ -475,7 +475,7 @@
; (match_operand:DF 1 "register_operand" "f")))
; (clobber (match_scratch:HI 2 "=a"))]
; "TARGET_80387"
-; "* return (char *) output_float_compare (insn, operands);")
+; "* return output_float_compare (insn, operands);")
(define_insn "cmpsf_cc_1"
[(set (cc0)
@@ -485,7 +485,7 @@
(clobber (match_scratch:HI 3 "=a,a"))]
"TARGET_80387
&& (GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM)"
- "* return (char *) output_float_compare (insn, operands);")
+ "* return output_float_compare (insn, operands);")
(define_insn ""
[(set (cc0)
@@ -495,7 +495,7 @@
(match_operand:SI 1 "nonimmediate_operand" "rm"))]))
(clobber (match_scratch:HI 3 "=a"))]
"TARGET_80387"
- "* return (char *) output_float_compare (insn, operands);")
+ "* return output_float_compare (insn, operands);")
(define_insn ""
[(set (cc0)
@@ -505,7 +505,7 @@
(match_operand:SF 1 "register_operand" "f")]))
(clobber (match_scratch:HI 3 "=a"))]
"TARGET_80387"
- "* return (char *) output_float_compare (insn, operands);")
+ "* return output_float_compare (insn, operands);")
(define_insn ""
[(set (cc0)
@@ -513,7 +513,7 @@
(match_operand:SF 1 "register_operand" "f")))
(clobber (match_scratch:HI 2 "=a"))]
"TARGET_80387"
- "* return (char *) output_float_compare (insn, operands);")
+ "* return output_float_compare (insn, operands);")
(define_expand "cmpxf"
[(set (cc0)
@@ -740,7 +740,7 @@
(define_insn ""
[(set (match_operand:SI 0 "push_operand" "=<")
(match_operand:SI 1 "general_operand" "g"))]
- "! TARGET_486"
+ "TARGET_386"
"push%L0 %1")
;; On a 486, it is faster to move MEM to a REG and then push, rather than
@@ -748,8 +748,14 @@
(define_insn ""
[(set (match_operand:SI 0 "push_operand" "=<")
+ (match_operand:SI 1 "nonmemory_operand" "ri"))]
+ "!TARGET_386 && TARGET_MOVE"
+ "push%L0 %1")
+
+(define_insn ""
+ [(set (match_operand:SI 0 "push_operand" "=<")
(match_operand:SI 1 "general_operand" "ri"))]
- "TARGET_486"
+ "!TARGET_386 && !TARGET_MOVE"
"push%L0 %1")
;; General case of fullword move.
@@ -767,6 +773,15 @@
if (flag_pic && SYMBOLIC_CONST (operands[1]))
emit_pic_move (operands, SImode);
+
+ /* Don't generate memory->memory moves, go through a register */
+ else if (TARGET_MOVE
+ && (reload_in_progress | reload_completed) == 0
+ && GET_CODE (operands[0]) == MEM
+ && GET_CODE (operands[1]) == MEM)
+ {
+ operands[1] = force_reg (SImode, operands[1]);
+ }
}")
;; On i486, incl reg is faster than movl $1,reg.
@@ -774,7 +789,7 @@
(define_insn ""
[(set (match_operand:SI 0 "general_operand" "=g,r")
(match_operand:SI 1 "general_operand" "ri,m"))]
- ""
+ "(!TARGET_MOVE || GET_CODE (operands[0]) != MEM) || (GET_CODE (operands[1]) != MEM)"
"*
{
rtx link;
@@ -793,21 +808,52 @@
/* Fastest way to change a 0 to a 1. */
return AS1 (inc%L0,%0);
+ if (flag_pic && SYMBOLIC_CONST (operands[1]))
+ return AS2 (lea%L0,%a1,%0);
+
return AS2 (mov%L0,%1,%0);
}")
(define_insn ""
[(set (match_operand:HI 0 "push_operand" "=<")
(match_operand:HI 1 "general_operand" "g"))]
- ""
+ "TARGET_386"
+ "push%W0 %1")
+
+(define_insn ""
+ [(set (match_operand:HI 0 "push_operand" "=<")
+ (match_operand:HI 1 "nonmemory_operand" "ri"))]
+ "!TARGET_386 && TARGET_MOVE"
+ "push%W0 %1")
+
+(define_insn ""
+ [(set (match_operand:HI 0 "push_operand" "=<")
+ (match_operand:HI 1 "general_operand" "ri"))]
+ "!TARGET_386 && !TARGET_MOVE"
"push%W0 %1")
;; On i486, an incl and movl are both faster than incw and movw.
-(define_insn "movhi"
+(define_expand "movhi"
+ [(set (match_operand:HI 0 "general_operand" "")
+ (match_operand:HI 1 "general_operand" ""))]
+ ""
+ "
+{
+ /* Don't generate memory->memory moves, go through a register */
+ if (TARGET_MOVE
+ && (reload_in_progress | reload_completed) == 0
+ && GET_CODE (operands[0]) == MEM
+ && GET_CODE (operands[1]) == MEM)
+ {
+ operands[1] = force_reg (HImode, operands[1]);
+ }
+}")
+
+(define_insn ""
[(set (match_operand:HI 0 "general_operand" "=g,r")
(match_operand:HI 1 "general_operand" "ri,m"))]
- ""
+ "(!TARGET_MOVE || GET_CODE (operands[0]) != MEM) || (GET_CODE (operands[1]) != MEM)"
"*
{
rtx link;
@@ -837,10 +883,26 @@
return AS2 (mov%W0,%1,%0);
}")
-(define_insn "movstricthi"
+(define_expand "movstricthi"
+ [(set (strict_low_part (match_operand:HI 0 "general_operand" ""))
+ (match_operand:HI 1 "general_operand" ""))]
+ ""
+ "
+{
+ /* Don't generate memory->memory moves, go through a register */
+ if (TARGET_MOVE
+ && (reload_in_progress | reload_completed) == 0
+ && GET_CODE (operands[0]) == MEM
+ && GET_CODE (operands[1]) == MEM)
+ {
+ operands[1] = force_reg (HImode, operands[1]);
+ }
+}")
+
+(define_insn ""
[(set (strict_low_part (match_operand:HI 0 "general_operand" "+g,r"))
(match_operand:HI 1 "general_operand" "ri,m"))]
- ""
+ "(!TARGET_MOVE || GET_CODE (operands[0]) != MEM) || (GET_CODE (operands[1]) != MEM)"
"*
{
rtx link;
@@ -868,8 +930,24 @@
;; the amount pushed up to a halfword.
(define_insn ""
[(set (match_operand:QI 0 "push_operand" "=<")
- (match_operand:QI 1 "general_operand" "q"))]
+ (match_operand:QI 1 "immediate_operand" "n"))]
""
+ "* return AS1 (push%W0,%1);")
+
+(define_insn ""
+ [(set (match_operand:QI 0 "push_operand" "=<")
+ (match_operand:QI 1 "nonimmediate_operand" "q"))]
+ "!TARGET_MOVE"
+ "*
+{
+ operands[1] = gen_rtx (REG, HImode, REGNO (operands[1]));
+ return AS1 (push%W0,%1);
+}")
+
+(define_insn ""
+ [(set (match_operand:QI 0 "push_operand" "=<")
+ (match_operand:QI 1 "register_operand" "q"))]
+ "TARGET_MOVE"
"*
{
operands[1] = gen_rtx (REG, HImode, REGNO (operands[1]));
@@ -881,10 +959,26 @@
;; ??? Do a recognizer for zero_extract that looks just like this, but reads
;; or writes %ah, %bh, %ch, %dh.
-(define_insn "movqi"
+(define_expand "movqi"
+ [(set (match_operand:QI 0 "general_operand" "")
+ (match_operand:QI 1 "general_operand" ""))]
+ ""
+ "
+{
+ /* Don't generate memory->memory moves, go through a register */
+ if (TARGET_MOVE
+ && (reload_in_progress | reload_completed) == 0
+ && GET_CODE (operands[0]) == MEM
+ && GET_CODE (operands[1]) == MEM)
+ {
+ operands[1] = force_reg (QImode, operands[1]);
+ }
+}")
+
+(define_insn ""
[(set (match_operand:QI 0 "general_operand" "=q,*r,qm")
(match_operand:QI 1 "general_operand" "*g,q,qn"))]
- ""
+ "(!TARGET_MOVE || GET_CODE (operands[0]) != MEM) || (GET_CODE (operands[1]) != MEM)"
"*
{
rtx link;
@@ -919,10 +1013,26 @@
;; If operands[1] is a constant, then an andl/orl sequence would be
;; faster.
-(define_insn "movstrictqi"
+(define_expand "movstrictqi"
+ [(set (strict_low_part (match_operand:QI 0 "general_operand" ""))
+ (match_operand:QI 1 "general_operand" ""))]
+ ""
+ "
+{
+ /* Don't generate memory->memory moves, go through a register */
+ if (TARGET_MOVE
+ && (reload_in_progress | reload_completed) == 0
+ && GET_CODE (operands[0]) == MEM
+ && GET_CODE (operands[1]) == MEM)
+ {
+ operands[1] = force_reg (QImode, operands[1]);
+ }
+}")
+
+(define_insn ""
[(set (strict_low_part (match_operand:QI 0 "general_operand" "+qm,q"))
(match_operand:QI 1 "general_operand" "*qn,m"))]
- ""
+ "(!TARGET_MOVE || GET_CODE (operands[0]) != MEM) || (GET_CODE (operands[1]) != MEM)"
"*
{
rtx link;
@@ -951,10 +1061,43 @@
return AS2 (mov%B0,%1,%0);
}")
-(define_insn ""
+(define_expand "movsf"
+ [(set (match_operand:SF 0 "general_operand" "")
+ (match_operand:SF 1 "general_operand" ""))]
+ ""
+ "
+{
+ /* Special case memory->memory moves and pushes */
+ if (TARGET_MOVE
+ && (reload_in_progress | reload_completed) == 0
+ && GET_CODE (operands[0]) == MEM
+ && (GET_CODE (operands[1]) == MEM || push_operand (operands[0], SFmode)))
+ {
+ rtx (*genfunc) PROTO((rtx, rtx)) = (push_operand (operands[0], SFmode))
+ ? gen_movsf_push
+ : gen_movsf_mem;
+
+ emit_insn ((*genfunc) (operands[0], operands[1]));
+ DONE;
+ }
+
+ /* If we are loading a floating point constant that isn't 0 or 1 into a register,
+ indicate we need the pic register loaded. This could be optimized into stores
+ of constants if the target eventually moves to memory, but better safe than
+ sorry. */
+ if (flag_pic
+ && GET_CODE (operands[0]) != MEM
+ && GET_CODE (operands[1]) == CONST_DOUBLE
+ && !standard_80387_constant_p (operands[1]))
+ {
+ current_function_uses_pic_offset_table = 1;
+ }
+}")
+
+(define_insn "movsf_push_nomove"
[(set (match_operand:SF 0 "push_operand" "=<,<")
(match_operand:SF 1 "general_operand" "gF,f"))]
- ""
+ "!TARGET_MOVE"
"*
{
if (STACK_REG_P (operands[1]))
@@ -979,14 +1122,61 @@
return AS1 (push%L1,%1);
}")
-;; Allow MEM-MEM moves before reload. The reload class for such a
-;; move will be ALL_REGS. PREFERRED_RELOAD_CLASS will narrow this to
-;; GENERAL_REGS. For the purposes of regclass, prefer FLOAT_REGS.
+(define_insn "movsf_push"
+ [(set (match_operand:SF 0 "push_operand" "=<,<,<,<")
+ (match_operand:SF 1 "general_operand" "rF,f,m,m"))
+ (clobber (match_scratch:SI 2 "=X,X,r,X"))]
+ ""
+ "*
+{
+ if (STACK_REG_P (operands[1]))
+ {
+ rtx xops[3];
+
+ if (! STACK_TOP_P (operands[1]))
+ abort ();
+
+ xops[0] = AT_SP (SFmode);
+ xops[1] = GEN_INT (4);
+ xops[2] = stack_pointer_rtx;
+
+ output_asm_insn (AS2 (sub%L2,%1,%2), xops);
+
+ if (find_regno_note (insn, REG_DEAD, FIRST_STACK_REG))
+ output_asm_insn (AS1 (fstp%S0,%0), xops);
+ else
+ output_asm_insn (AS1 (fst%S0,%0), xops);
+ RET;
+ }
+
+ else if (GET_CODE (operands[1]) != MEM || GET_CODE (operands[2]) != REG)
+ return AS1 (push%L1,%1);
+
+ else
+ {
+ output_asm_insn (AS2 (mov%L2,%1,%2), operands);
+ return AS1 (push%L2,%2);
+ }
+}")
+
+;; Special memory<->memory pattern that combine will recreate from the
+;; moves to pseudos.
+(define_insn "movsf_mem"
+ [(set (match_operand:SF 0 "memory_operand" "=m")
+ (match_operand:SF 1 "memory_operand" "m"))
+ (clobber (match_scratch:SI 2 "=&r"))]
+ ""
+ "*
+{
+ output_asm_insn (AS2 (mov%L2,%1,%2), operands);
+ return AS2 (mov%L0,%2,%0);
+}")
-(define_insn "movsf"
+;; For the purposes of regclass, prefer FLOAT_REGS.
+(define_insn "movsf_normal"
[(set (match_operand:SF 0 "general_operand" "=*rfm,*rf,f,!*rm")
(match_operand:SF 1 "general_operand" "*rf,*rfm,fG,fF"))]
- ""
+ "(!TARGET_MOVE || GET_CODE (operands[0]) != MEM) || (GET_CODE (operands[1]) != MEM)"
"*
{
int stack_top_dies = find_regno_note (insn, REG_DEAD, FIRST_STACK_REG) != 0;
@@ -1028,21 +1218,67 @@
/* Handle other kinds of reads to the 387 */
if (STACK_TOP_P (operands[0]) && GET_CODE (operands[1]) == CONST_DOUBLE)
- return (char *) output_move_const_single (operands);
+ return output_move_const_single (operands);
if (STACK_TOP_P (operands[0]))
return AS1 (fld%z1,%y1);
/* Handle all SFmode moves not involving the 387 */
- return (char *) singlemove_string (operands);
+ return singlemove_string (operands);
}")
-;;should change to handle the memory operands[1] without doing df push..
-(define_insn ""
+(define_insn "swapsf"
+ [(set (match_operand:SF 0 "register_operand" "f")
+ (match_operand:SF 1 "register_operand" "f"))
+ (set (match_dup 1)
+ (match_dup 0))]
+ ""
+ "*
+{
+ if (STACK_TOP_P (operands[0]))
+ return AS1 (fxch,%1);
+ else
+ return AS1 (fxch,%0);
+}")
+
+(define_expand "movdf"
+ [(set (match_operand:DF 0 "general_operand" "")
+ (match_operand:DF 1 "general_operand" ""))]
+ ""
+ "
+{
+ /* Special case memory->memory moves and pushes */
+ if (TARGET_MOVE
+ && (reload_in_progress | reload_completed) == 0
+ && GET_CODE (operands[0]) == MEM
+ && (GET_CODE (operands[1]) == MEM || push_operand (operands[0], DFmode)))
+ {
+ rtx (*genfunc) PROTO((rtx, rtx)) = (push_operand (operands[0], DFmode))
+ ? gen_movdf_push
+ : gen_movdf_mem;
+
+ emit_insn ((*genfunc) (operands[0], operands[1]));
+ DONE;
+ }
+
+ /* If we are loading a floating point constant that isn't 0 or 1 into a register,
+ indicate we need the pic register loaded. This could be optimized into stores
+ of constants if the target eventually moves to memory, but better safe than
+ sorry. */
+ if (flag_pic
+ && GET_CODE (operands[0]) != MEM
+ && GET_CODE (operands[1]) == CONST_DOUBLE
+ && !standard_80387_constant_p (operands[1]))
+ {
+ current_function_uses_pic_offset_table = 1;
+ }
+}")
+
+(define_insn "movdf_push_nomove"
[(set (match_operand:DF 0 "push_operand" "=<,<")
(match_operand:DF 1 "general_operand" "gF,f"))]
- ""
+ "!TARGET_MOVE"
"*
{
if (STACK_REG_P (operands[1]))
@@ -1063,31 +1299,55 @@
RET;
}
else
- return (char *) output_move_double (operands);
+ return output_move_double (operands);
}")
-(define_insn "swapdf"
- [(set (match_operand:DF 0 "register_operand" "f")
- (match_operand:DF 1 "register_operand" "f"))
- (set (match_dup 1)
- (match_dup 0))]
+(define_insn "movdf_push"
+ [(set (match_operand:DF 0 "push_operand" "=<,<,<,<,<")
+ (match_operand:DF 1 "general_operand" "rF,f,o,o,o"))
+ (clobber (match_scratch:SI 2 "=X,X,&r,&r,X"))
+ (clobber (match_scratch:SI 3 "=X,X,&r,X,X"))]
""
"*
{
- if (STACK_TOP_P (operands[0]))
- return AS1 (fxch,%1);
+ if (STACK_REG_P (operands[1]))
+ {
+ rtx xops[3];
+
+ xops[0] = AT_SP (SFmode);
+ xops[1] = GEN_INT (8);
+ xops[2] = stack_pointer_rtx;
+
+ output_asm_insn (AS2 (sub%L2,%1,%2), xops);
+
+ if (find_regno_note (insn, REG_DEAD, FIRST_STACK_REG))
+ output_asm_insn (AS1 (fstp%Q0,%0), xops);
+ else
+ output_asm_insn (AS1 (fst%Q0,%0), xops);
+
+ RET;
+ }
+
+ else if (GET_CODE (operands[1]) != MEM)
+ return output_move_double (operands);
+
else
- return AS1 (fxch,%0);
+ return output_move_pushmem (operands, insn, GET_MODE_SIZE (DFmode), 2, 4);
}")
-;; Allow MEM-MEM moves before reload. The reload class for such a
-;; move will be ALL_REGS. PREFERRED_RELOAD_CLASS will narrow this to
-;; GENERAL_REGS. For the purposes of regclass, prefer FLOAT_REGS.
-
-(define_insn "movdf"
- [(set (match_operand:DF 0 "general_operand" "=*rfm,*rf,f,!*rm")
- (match_operand:DF 1 "general_operand" "*rf,*rfm,fG,fF"))]
+(define_insn "movdf_mem"
+ [(set (match_operand:DF 0 "memory_operand" "=o,o")
+ (match_operand:DF 1 "memory_operand" "o,o"))
+ (clobber (match_scratch:SI 2 "=&r,&r"))
+ (clobber (match_scratch:SI 3 "=&r,X"))]
""
+ "* return output_move_memory (operands, insn, GET_MODE_SIZE (DFmode), 2, 4);")
+
+;; For the purposes of regclass, prefer FLOAT_REGS.
+(define_insn "movdf_normal"
+ [(set (match_operand:DF 0 "general_operand" "=f,fm,!*rf,!*rm")
+ (match_operand:DF 1 "general_operand" "fmG,f,*rfm,*rfF"))]
+ "(!TARGET_MOVE || GET_CODE (operands[0]) != MEM) || (GET_CODE (operands[1]) != MEM)"
"*
{
int stack_top_dies = find_regno_note (insn, REG_DEAD, FIRST_STACK_REG) != 0;
@@ -1129,20 +1389,68 @@
/* Handle other kinds of reads to the 387 */
if (STACK_TOP_P (operands[0]) && GET_CODE (operands[1]) == CONST_DOUBLE)
- return (char *) output_move_const_single (operands);
+ return output_move_const_single (operands);
if (STACK_TOP_P (operands[0]))
return AS1 (fld%z1,%y1);
/* Handle all DFmode moves not involving the 387 */
- return (char *) output_move_double (operands);
+ return output_move_double (operands);
}")
-(define_insn ""
+(define_insn "swapdf"
+ [(set (match_operand:DF 0 "register_operand" "f")
+ (match_operand:DF 1 "register_operand" "f"))
+ (set (match_dup 1)
+ (match_dup 0))]
+ ""
+ "*
+{
+ if (STACK_TOP_P (operands[0]))
+ return AS1 (fxch,%1);
+ else
+ return AS1 (fxch,%0);
+}")
+
+(define_expand "movxf"
+ [(set (match_operand:XF 0 "general_operand" "")
+ (match_operand:XF 1 "general_operand" ""))]
+ ""
+ "
+{
+ /* Special case memory->memory moves and pushes */
+ if (TARGET_MOVE
+ && (reload_in_progress | reload_completed) == 0
+ && GET_CODE (operands[0]) == MEM
+ && (GET_CODE (operands[1]) == MEM || push_operand (operands[0], XFmode)))
+ {
+ rtx (*genfunc) PROTO((rtx, rtx)) = (push_operand (operands[0], XFmode))
+ ? gen_movxf_push
+ : gen_movxf_mem;
+
+ emit_insn ((*genfunc) (operands[0], operands[1]));
+ DONE;
+ }
+
+ /* If we are loading a floating point constant that isn't 0 or 1 into a register,
+ indicate we need the pic register loaded. This could be optimized into stores
+ of constants if the target eventually moves to memory, but better safe than
+ sorry. */
+ if (flag_pic
+ && GET_CODE (operands[0]) != MEM
+ && GET_CODE (operands[1]) == CONST_DOUBLE
+ && !standard_80387_constant_p (operands[1]))
+ {
+ current_function_uses_pic_offset_table = 1;
+ }
+}")
+
+
+(define_insn "movxf_push_nomove"
[(set (match_operand:XF 0 "push_operand" "=<,<")
(match_operand:XF 1 "general_operand" "gF,f"))]
- ""
+ "!TARGET_MOVE"
"*
{
if (STACK_REG_P (operands[1]))
@@ -1161,29 +1469,53 @@
RET;
}
else
- return (char *) output_move_double (operands);
+ return output_move_double (operands);
}")
-(define_insn "swapxf"
- [(set (match_operand:XF 0 "register_operand" "f")
- (match_operand:XF 1 "register_operand" "f"))
- (set (match_dup 1)
- (match_dup 0))]
+(define_insn "movxf_push"
+ [(set (match_operand:XF 0 "push_operand" "=<,<,<,<,<")
+ (match_operand:XF 1 "general_operand" "rF,f,o,o,o"))
+ (clobber (match_scratch:SI 2 "=X,X,&r,&r,X"))
+ (clobber (match_scratch:SI 3 "=X,X,&r,X,X"))]
""
"*
{
- if (STACK_TOP_P (operands[0]))
- return AS1 (fxch,%1);
+ if (STACK_REG_P (operands[1]))
+ {
+ rtx xops[3];
+
+ xops[0] = AT_SP (SFmode);
+ xops[1] = GEN_INT (12);
+ xops[2] = stack_pointer_rtx;
+
+ output_asm_insn (AS2 (sub%L2,%1,%2), xops);
+ output_asm_insn (AS1 (fstp%T0,%0), xops);
+ if (! find_regno_note (insn, REG_DEAD, FIRST_STACK_REG))
+ output_asm_insn (AS1 (fld%T0,%0), xops);
+
+ RET;
+ }
+
+ else if (GET_CODE (operands[1]) != MEM
+ || GET_CODE (operands[2]) != REG)
+ return output_move_double (operands);
+
else
- return AS1 (fxch,%0);
+ return output_move_pushmem (operands, insn, GET_MODE_SIZE (XFmode), 2, 4);
}")
-(define_insn "movxf"
+(define_insn "movxf_mem"
+ [(set (match_operand:XF 0 "memory_operand" "=o,o")
+ (match_operand:XF 1 "memory_operand" "o,o"))
+ (clobber (match_scratch:SI 2 "=&r,&r"))
+ (clobber (match_scratch:SI 3 "=&r,X"))]
+ ""
+ "* return output_move_memory (operands, insn, GET_MODE_SIZE (XFmode), 2, 4);")
+
+(define_insn "movxf_normal"
[(set (match_operand:XF 0 "general_operand" "=f,fm,!*rf,!*rm")
(match_operand:XF 1 "general_operand" "fmG,f,*rfm,*rfF"))]
-;; [(set (match_operand:XF 0 "general_operand" "=*rf,*rfm,f,!*rm")
-;; (match_operand:XF 1 "general_operand" "*rfm,*rf,fG,fF"))]
- ""
+ "(!TARGET_MOVE || GET_CODE (operands[0]) != MEM) || (GET_CODE (operands[1]) != MEM)"
"*
{
int stack_top_dies = find_regno_note (insn, REG_DEAD, FIRST_STACK_REG) != 0;
@@ -1226,33 +1558,61 @@
/* Handle other kinds of reads to the 387 */
if (STACK_TOP_P (operands[0]) && GET_CODE (operands[1]) == CONST_DOUBLE)
- return (char *) output_move_const_single (operands);
+ return output_move_const_single (operands);
if (STACK_TOP_P (operands[0]))
return AS1 (fld%z1,%y1);
/* Handle all XFmode moves not involving the 387 */
- return (char *) output_move_double (operands);
+ return output_move_double (operands);
+}")
+
+(define_insn "swapxf"
+ [(set (match_operand:XF 0 "register_operand" "f")
+ (match_operand:XF 1 "register_operand" "f"))
+ (set (match_dup 1)
+ (match_dup 0))]
+ ""
+ "*
+{
+ if (STACK_TOP_P (operands[0]))
+ return AS1 (fxch,%1);
+ else
+ return AS1 (fxch,%0);
}")
(define_insn ""
- [(set (match_operand:DI 0 "push_operand" "=<")
- (match_operand:DI 1 "general_operand" "roiF"))]
+ [(set (match_operand:DI 0 "push_operand" "=<,<,<,<")
+ (match_operand:DI 1 "general_operand" "riF,o,o,o"))
+ (clobber (match_scratch:SI 2 "=X,&r,&r,X"))
+ (clobber (match_scratch:SI 3 "=X,&r,X,X"))]
""
"*
{
- return (char *) output_move_double (operands);
+ if (GET_CODE (operands[1]) != MEM)
+ return output_move_double (operands);
+
+ else
+ return output_move_pushmem (operands, insn, GET_MODE_SIZE (DImode), 2, 4);
}")
(define_insn "movdi"
- [(set (match_operand:DI 0 "general_operand" "=r,rm")
- (match_operand:DI 1 "general_operand" "m,riF"))]
+ [(set (match_operand:DI 0 "general_operand" "=o,o,r,rm")
+ (match_operand:DI 1 "general_operand" "o,o,m,riF"))
+ (clobber (match_scratch:SI 2 "=&r,&r,X,X"))
+ (clobber (match_scratch:SI 3 "=&r,X,X,X"))]
""
"*
{
- return (char *) output_move_double (operands);
+ rtx low[2], high[2], xop[6];
+
+ if (GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM)
+ return output_move_double (operands);
+ else
+ return output_move_memory (operands, insn, GET_MODE_SIZE (DImode), 2, 4);
}")
+
;;- conversion instructions
;;- NONE
@@ -1267,7 +1627,7 @@
""
"*
{
- if ((TARGET_486 || REGNO (operands[0]) == 0)
+ if ((!TARGET_386 || REGNO (operands[0]) == 0)
&& REG_P (operands[1]) && REGNO (operands[0]) == REGNO (operands[1]))
{
rtx xops[2];
@@ -1291,7 +1651,7 @@
""
"*
{
- if ((TARGET_486 || REGNO (operands[0]) == 0)
+ if ((!TARGET_386 || REGNO (operands[0]) == 0)
&& REG_P (operands[1]) && REGNO (operands[0]) == REGNO (operands[1]))
{
rtx xops[2];
@@ -1315,7 +1675,7 @@
""
"*
{
- if ((TARGET_486 || REGNO (operands[0]) == 0)
+ if ((!TARGET_386 || REGNO (operands[0]) == 0)
&& REG_P (operands[1]) && REGNO (operands[0]) == REGNO (operands[1]))
{
rtx xops[2];
@@ -1778,7 +2138,7 @@
(clobber (match_operand:SI 3 "memory_operand" "m"))
(clobber (match_scratch:SI 4 "=&q"))]
"TARGET_80387"
- "* return (char *) output_fix_trunc (insn, operands);")
+ "* return output_fix_trunc (insn, operands);")
(define_insn ""
[(set (match_operand:DI 0 "general_operand" "=rm")
@@ -1788,7 +2148,7 @@
(clobber (match_operand:SI 3 "memory_operand" "m"))
(clobber (match_scratch:SI 4 "=&q"))]
"TARGET_80387"
- "* return (char *) output_fix_trunc (insn, operands);")
+ "* return output_fix_trunc (insn, operands);")
(define_insn ""
[(set (match_operand:DI 0 "general_operand" "=rm")
@@ -1798,7 +2158,7 @@
(clobber (match_operand:SI 3 "memory_operand" "m"))
(clobber (match_scratch:SI 4 "=&q"))]
"TARGET_80387"
- "* return (char *) output_fix_trunc (insn, operands);")
+ "* return output_fix_trunc (insn, operands);")
;; Signed MODE_FLOAT conversion to SImode.
@@ -1851,7 +2211,7 @@
(clobber (match_operand:SI 3 "memory_operand" "m"))
(clobber (match_scratch:SI 4 "=&q"))]
"TARGET_80387"
- "* return (char *) output_fix_trunc (insn, operands);")
+ "* return output_fix_trunc (insn, operands);")
(define_insn ""
[(set (match_operand:SI 0 "general_operand" "=rm")
@@ -1860,7 +2220,7 @@
(clobber (match_operand:SI 3 "memory_operand" "m"))
(clobber (match_scratch:SI 4 "=&q"))]
"TARGET_80387"
- "* return (char *) output_fix_trunc (insn, operands);")
+ "* return output_fix_trunc (insn, operands);")
(define_insn ""
[(set (match_operand:SI 0 "general_operand" "=rm")
@@ -1869,7 +2229,7 @@
(clobber (match_operand:SI 3 "memory_operand" "m"))
(clobber (match_scratch:SI 4 "=&q"))]
"TARGET_80387"
- "* return (char *) output_fix_trunc (insn, operands);")
+ "* return output_fix_trunc (insn, operands);")
;; Conversion between fixed point and floating point.
;; The actual pattern that matches these is at the end of this file.
@@ -2019,25 +2379,75 @@
;;- add instructions
(define_insn "adddi3"
- [(set (match_operand:DI 0 "general_operand" "=&r,ro")
- (plus:DI (match_operand:DI 1 "general_operand" "%0,0")
- (match_operand:DI 2 "general_operand" "o,riF")))]
+ [(set (match_operand:DI 0 "general_operand" "=&r,ro,o,&r,ro,o,&r,o,o,o")
+ (plus:DI (match_operand:DI 1 "general_operand" "%0,0,0,o,riF,o,or,riF,riF,o")
+ (match_operand:DI 2 "general_operand" "o,riF,o,0,0,0,oriF,riF,o,o")))
+ (clobber (match_scratch:SI 3 "=X,X,&r,X,X,&r,X,X,&r,&r"))]
""
"*
{
- rtx low[3], high[3];
+ rtx low[3], high[3], xops[7], temp;
CC_STATUS_INIT;
+ if (rtx_equal_p (operands[0], operands[2]))
+ {
+ temp = operands[1];
+ operands[1] = operands[2];
+ operands[2] = temp;
+ }
+
split_di (operands, 3, low, high);
+ if (!rtx_equal_p (operands[0], operands[1]))
+ {
+ xops[0] = high[0];
+ xops[1] = low[0];
+ xops[2] = high[1];
+ xops[3] = low[1];
+
+ if (GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM)
+ {
+ output_asm_insn (AS2 (mov%L1,%3,%1), xops);
+ output_asm_insn (AS2 (mov%L0,%2,%0), xops);
+ }
+ else
+ {
+ xops[4] = high[2];
+ xops[5] = low[2];
+ xops[6] = operands[3];
+ output_asm_insn (AS2 (mov%L6,%3,%6), xops);
+ output_asm_insn (AS2 (add%L6,%5,%6), xops);
+ output_asm_insn (AS2 (mov%L1,%6,%1), xops);
+ output_asm_insn (AS2 (mov%L6,%2,%6), xops);
+ output_asm_insn (AS2 (adc%L6,%4,%6), xops);
+ output_asm_insn (AS2 (mov%L0,%6,%0), xops);
+ RET;
+ }
+ }
+
+ if (GET_CODE (operands[3]) == REG && GET_CODE (operands[2]) != REG)
+ {
+ xops[0] = high[0];
+ xops[1] = low[0];
+ xops[2] = high[2];
+ xops[3] = low[2];
+ xops[4] = operands[3];
+
+ output_asm_insn (AS2 (mov%L4,%3,%4), xops);
+ output_asm_insn (AS2 (add%L1,%4,%1), xops);
+ output_asm_insn (AS2 (mov%L4,%2,%4), xops);
+ output_asm_insn (AS2 (adc%L0,%4,%0), xops);
+ }
- if (GET_CODE (low[2]) != CONST_INT || INTVAL (low[2]) != 0)
+ else if (GET_CODE (low[2]) != CONST_INT || INTVAL (low[2]) != 0)
{
output_asm_insn (AS2 (add%L0,%2,%0), low);
output_asm_insn (AS2 (adc%L0,%2,%0), high);
}
+
else
output_asm_insn (AS2 (add%L0,%2,%0), high);
+
RET;
}")
@@ -2056,23 +2466,20 @@
if (REG_P (operands[2]) && REGNO (operands[0]) == REGNO (operands[2]))
return AS2 (add%L0,%1,%0);
- if (! TARGET_486 || ! REG_P (operands[2]))
- {
- CC_STATUS_INIT;
+ if (operands[2] == stack_pointer_rtx)
+ {
+ rtx temp;
- if (operands[2] == stack_pointer_rtx)
- {
- rtx temp;
+ temp = operands[1];
+ operands[1] = operands[2];
+ operands[2] = temp;
+ }
- temp = operands[1];
- operands[1] = operands[2];
- operands[2] = temp;
- }
- if (operands[2] != stack_pointer_rtx)
- {
- operands[1] = SET_SRC (PATTERN (insn));
- return AS2 (lea%L0,%a1,%0);
- }
+ if (operands[2] != stack_pointer_rtx)
+ {
+ CC_STATUS_INIT;
+ operands[1] = SET_SRC (PATTERN (insn));
+ return AS2 (lea%L0,%a1,%0);
}
output_asm_insn (AS2 (mov%L0,%1,%0), operands);
@@ -2171,7 +2578,7 @@
;; addsi3 is faster, so put this after.
-(define_insn ""
+(define_insn "movsi_lea"
[(set (match_operand:SI 0 "register_operand" "=r")
(match_operand:QI 1 "address_operand" "p"))]
""
@@ -2223,23 +2630,66 @@
;;- subtract instructions
(define_insn "subdi3"
- [(set (match_operand:DI 0 "general_operand" "=&r,ro")
- (minus:DI (match_operand:DI 1 "general_operand" "0,0")
- (match_operand:DI 2 "general_operand" "o,riF")))]
+ [(set (match_operand:DI 0 "general_operand" "=&r,ro,&r,o,o")
+ (minus:DI (match_operand:DI 1 "general_operand" "0,0,roiF,riF,o")
+ (match_operand:DI 2 "general_operand" "o,riF,roiF,riF,o")))
+ (clobber (match_scratch:SI 3 "=X,X,X,X,&r"))]
""
"*
{
- rtx low[3], high[3];
+ rtx low[3], high[3], xops[7];
CC_STATUS_INIT;
split_di (operands, 3, low, high);
- if (GET_CODE (low[2]) != CONST_INT || INTVAL (low[2]) != 0)
+ if (!rtx_equal_p (operands[0], operands[1]))
+ {
+ xops[0] = high[0];
+ xops[1] = low[0];
+ xops[2] = high[1];
+ xops[3] = low[1];
+
+ if (GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM)
+ {
+ output_asm_insn (AS2 (mov%L1,%3,%1), xops);
+ output_asm_insn (AS2 (mov%L0,%2,%0), xops);
+ }
+ else
+ {
+ xops[4] = high[2];
+ xops[5] = low[2];
+ xops[6] = operands[3];
+ output_asm_insn (AS2 (mov%L6,%3,%6), xops);
+ output_asm_insn (AS2 (sub%L6,%5,%6), xops);
+ output_asm_insn (AS2 (mov%L1,%6,%1), xops);
+ output_asm_insn (AS2 (mov%L6,%2,%6), xops);
+ output_asm_insn (AS2 (sbb%L6,%4,%6), xops);
+ output_asm_insn (AS2 (mov%L0,%6,%0), xops);
+ RET;
+ }
+ }
+
+ if (GET_CODE (operands[3]) == REG)
+ {
+ xops[0] = high[0];
+ xops[1] = low[0];
+ xops[2] = high[2];
+ xops[3] = low[2];
+ xops[4] = operands[3];
+
+ output_asm_insn (AS2 (mov%L4,%3,%4), xops);
+ output_asm_insn (AS2 (sub%L1,%4,%1), xops);
+ output_asm_insn (AS2 (mov%L4,%2,%4), xops);
+ output_asm_insn (AS2 (sbb%L0,%4,%0), xops);
+ }
+
+ else if (GET_CODE (low[2]) != CONST_INT || INTVAL (low[2]) != 0)
{
output_asm_insn (AS2 (sub%L0,%2,%0), low);
output_asm_insn (AS2 (sbb%L0,%2,%0), high);
}
+
else
output_asm_insn (AS2 (sub%L0,%2,%0), high);
@@ -2361,14 +2811,32 @@
[(set (match_operand:DI 0 "register_operand" "=A")
(mult:DI (zero_extend:DI (match_operand:SI 1 "register_operand" "%0"))
(zero_extend:DI (match_operand:SI 2 "nonimmediate_operand" "rm"))))]
- ""
+ "TARGET_WIDE_MULTIPLY"
"mul%L0 %2")
(define_insn "mulsidi3"
[(set (match_operand:DI 0 "register_operand" "=A")
(mult:DI (sign_extend:DI (match_operand:SI 1 "register_operand" "%0"))
(sign_extend:DI (match_operand:SI 2 "nonimmediate_operand" "rm"))))]
- ""
+ "TARGET_WIDE_MULTIPLY"
+ "imul%L0 %2")
+
+(define_insn "umulsi3_highpart"
+ [(set (match_operand:SI 0 "register_operand" "=d")
+ (truncate:SI (lshiftrt:DI (mult:DI (zero_extend:DI (match_operand:SI 1 "register_operand" "%a"))
+ (zero_extend:DI (match_operand:SI 2 "nonimmediate_operand" "rm")))
+ (const_int 32))))
+ (clobber (match_scratch:SI 3 "=a"))]
+ "TARGET_WIDE_MULTIPLY"
+ "mul%L0 %2")
+
+(define_insn "smulsi3_highpart"
+ [(set (match_operand:SI 0 "register_operand" "=d")
+ (truncate:SI (lshiftrt:DI (mult:DI (sign_extend:DI (match_operand:SI 1 "register_operand" "%a"))
+ (sign_extend:DI (match_operand:SI 2 "nonimmediate_operand" "rm")))
+ (const_int 32))))
+ (clobber (match_scratch:SI 3 "=a"))]
+ "TARGET_WIDE_MULTIPLY"
"imul%L0 %2")
;; The patterns that match these are at the end of this file.
@@ -2533,7 +3001,7 @@
if (INTVAL (operands[2]) == 0xffff && REG_P (operands[0])
&& (! REG_P (operands[1])
|| REGNO (operands[0]) != 0 || REGNO (operands[1]) != 0)
- && (! TARGET_486 || ! rtx_equal_p (operands[0], operands[1])))
+ && (TARGET_386 || ! rtx_equal_p (operands[0], operands[1])))
{
/* ??? tege: Should forget CC_STATUS only if we clobber a
remembered operand. Fix that later. */
@@ -2549,7 +3017,7 @@
&& !(REG_P (operands[1]) && NON_QI_REG_P (operands[1]))
&& (! REG_P (operands[1])
|| REGNO (operands[0]) != 0 || REGNO (operands[1]) != 0)
- && (! TARGET_486 || ! rtx_equal_p (operands[0], operands[1])))
+ && (TARGET_386 || ! rtx_equal_p (operands[0], operands[1])))
{
/* ??? tege: Should forget CC_STATUS only if we clobber a
remembered operand. Fix that later. */
@@ -3192,7 +3660,7 @@
{
if (REG_P (operands[0]) && REGNO (operands[0]) != REGNO (operands[1]))
{
- if (TARGET_486 && INTVAL (operands[2]) == 1)
+ if (!TARGET_386 && INTVAL (operands[2]) == 1)
{
output_asm_insn (AS2 (mov%L0,%1,%0), operands);
return AS2 (add%L0,%1,%0);
@@ -3693,7 +4161,7 @@
(const_int 1)
(match_operand:SI 2 "general_operand" "r"))
(match_operand:SI 3 "const_int_operand" "n"))]
- "! TARGET_486 && GET_CODE (operands[2]) != CONST_INT"
+ "TARGET_386 && GET_CODE (operands[2]) != CONST_INT"
"*
{
CC_STATUS_INIT;
@@ -3711,7 +4179,7 @@
(xor:SI (ashift:SI (const_int 1)
(match_operand:SI 1 "general_operand" "r"))
(match_operand:SI 2 "general_operand" "0")))]
- "! TARGET_486 && GET_CODE (operands[1]) != CONST_INT"
+ "TARGET_386 && GET_CODE (operands[1]) != CONST_INT"
"*
{
CC_STATUS_INIT;
@@ -3724,7 +4192,7 @@
(xor:SI (match_operand:SI 1 "general_operand" "0")
(ashift:SI (const_int 1)
(match_operand:SI 2 "general_operand" "r"))))]
- "! TARGET_486 && GET_CODE (operands[2]) != CONST_INT"
+ "TARGET_386 && GET_CODE (operands[2]) != CONST_INT"
"*
{
CC_STATUS_INIT;
@@ -4742,126 +5210,42 @@
"!HALF_PIC_P ()"
"call %P1")
+;; Call subroutine returning any type.
+
(define_expand "untyped_call"
- [(parallel [(call (match_operand:QI 0 "indirect_operand" "")
+ [(parallel [(call (match_operand 0 "" "")
(const_int 0))
- (match_operand:BLK 1 "memory_operand" "")
+ (match_operand 1 "" "")
(match_operand 2 "" "")])]
""
"
{
- rtx addr;
+ int i;
- if (flag_pic)
- current_function_uses_pic_offset_table = 1;
+ emit_call_insn (gen_call (operands[0], const0_rtx, NULL, const0_rtx));
- /* With half-pic, force the address into a register. */
- addr = XEXP (operands[0], 0);
- if (GET_CODE (addr) != REG && HALF_PIC_P () && !CONSTANT_ADDRESS_P (addr))
- XEXP (operands[0], 0) = force_reg (Pmode, addr);
-
- operands[1] = change_address (operands[1], DImode, XEXP (operands[1], 0));
- if (! expander_call_insn_operand (operands[1], QImode))
- operands[1]
- = change_address (operands[1], VOIDmode,
- copy_to_mode_reg (Pmode, XEXP (operands[1], 0)));
-}")
-
-(define_insn ""
- [(call (match_operand:QI 0 "call_insn_operand" "m")
- (const_int 0))
- (match_operand:DI 1 "memory_operand" "o")
- (match_operand 2 "" "")]
- ""
- "*
-{
- rtx addr = operands[1];
-
- if (GET_CODE (operands[0]) == MEM
- && ! CONSTANT_ADDRESS_P (XEXP (operands[0], 0)))
+ for (i = 0; i < XVECLEN (operands[2], 0); i++)
{
- operands[0] = XEXP (operands[0], 0);
- output_asm_insn (AS1 (call,%*%0), operands);
+ rtx set = XVECEXP (operands[2], 0, i);
+ emit_move_insn (SET_DEST (set), SET_SRC (set));
}
- else
- output_asm_insn (AS1 (call,%P0), operands);
-
- operands[2] = gen_rtx (REG, SImode, 0);
- output_asm_insn (AS2 (mov%L2,%2,%1), operands);
-
- operands[2] = gen_rtx (REG, SImode, 1);
- operands[1] = adj_offsettable_operand (addr, 4);
- output_asm_insn (AS2 (mov%L2,%2,%1), operands);
-
- operands[1] = adj_offsettable_operand (addr, 8);
- return AS1 (fnsave,%1);
-}")
-(define_insn ""
- [(call (mem:QI (match_operand:SI 0 "symbolic_operand" ""))
- (const_int 0))
- (match_operand:DI 1 "memory_operand" "o")
- (match_operand 2 "" "")]
- "!HALF_PIC_P ()"
- "*
-{
- rtx addr = operands[1];
-
- output_asm_insn (AS1 (call,%P0), operands);
-
- operands[2] = gen_rtx (REG, SImode, 0);
- output_asm_insn (AS2 (mov%L2,%2,%1), operands);
-
- operands[2] = gen_rtx (REG, SImode, 1);
- operands[1] = adj_offsettable_operand (addr, 4);
- output_asm_insn (AS2 (mov%L2,%2,%1), operands);
-
- operands[1] = adj_offsettable_operand (addr, 8);
- return AS1 (fnsave,%1);
-}")
-
-;; We use fnsave and frstor to save and restore the floating point result.
-;; These are expensive instructions and require a large space to save the
-;; FPU state. An more complicated alternative is to use fnstenv to store
-;; the FPU environment and test whether the stack top is valid. Store the
-;; result of the test, and if it is valid, pop and save the value. The
-;; untyped_return would check the test and optionally push the saved value.
-
-(define_expand "untyped_return"
- [(match_operand:BLK 0 "memory_operand" "")
- (match_operand 1 "" "")]
- ""
- "
-{
- rtx valreg1 = gen_rtx (REG, SImode, 0);
- rtx valreg2 = gen_rtx (REG, SImode, 1);
- rtx result = operands[0];
-
- /* Restore the FPU state. */
- emit_insn (gen_update_return (change_address (result, SImode,
- plus_constant (XEXP (result, 0),
- 8))));
-
- /* Reload the function value registers. */
- emit_move_insn (valreg1, change_address (result, SImode, XEXP (result, 0)));
- emit_move_insn (valreg2,
- change_address (result, SImode,
- plus_constant (XEXP (result, 0), 4)));
-
- /* Put USE insns before the return. */
- emit_insn (gen_rtx (USE, VOIDmode, valreg1));
- emit_insn (gen_rtx (USE, VOIDmode, valreg2));
-
- /* Construct the return. */
- expand_null_return ();
+ /* The optimizer does not know that the call sets the function value
+ registers we stored in the result block. We avoid problems by
+ claiming that all hard registers are used and clobbered at this
+ point. */
+ emit_insn (gen_blockage ());
DONE;
}")
-(define_insn "update_return"
- [(unspec:SI [(match_operand:SI 0 "memory_operand" "m")] 0)]
+;; UNSPEC_VOLATILE is considered to use and clobber all hard registers and
+;; all of memory. This blocks insns from being moved across this point.
+
+(define_insn "blockage"
+ [(unspec_volatile [(const_int 0)] 0)]
""
- "frstor %0")
+ "")
;; Insn emitted into the body of a function to return from a function.
;; This is only done if the function's epilogue is known to be simple.
@@ -5153,7 +5537,7 @@
[(match_operand:DF 1 "nonimmediate_operand" "0,fm")
(match_operand:DF 2 "nonimmediate_operand" "fm,0")]))]
"TARGET_80387"
- "* return (char *) output_387_binary_op (insn, operands);")
+ "* return output_387_binary_op (insn, operands);")
(define_insn ""
[(set (match_operand:DF 0 "register_operand" "=f")
@@ -5161,7 +5545,7 @@
[(float:DF (match_operand:SI 1 "general_operand" "rm"))
(match_operand:DF 2 "general_operand" "0")]))]
"TARGET_80387"
- "* return (char *) output_387_binary_op (insn, operands);")
+ "* return output_387_binary_op (insn, operands);")
(define_insn ""
[(set (match_operand:XF 0 "register_operand" "=f,f")
@@ -5169,7 +5553,7 @@
[(match_operand:XF 1 "nonimmediate_operand" "0,f")
(match_operand:XF 2 "nonimmediate_operand" "f,0")]))]
"TARGET_80387"
- "* return (char *) output_387_binary_op (insn, operands);")
+ "* return output_387_binary_op (insn, operands);")
(define_insn ""
[(set (match_operand:XF 0 "register_operand" "=f")
@@ -5177,7 +5561,7 @@
[(float:XF (match_operand:SI 1 "general_operand" "rm"))
(match_operand:XF 2 "general_operand" "0")]))]
"TARGET_80387"
- "* return (char *) output_387_binary_op (insn, operands);")
+ "* return output_387_binary_op (insn, operands);")
(define_insn ""
[(set (match_operand:XF 0 "register_operand" "=f,f")
@@ -5185,7 +5569,7 @@
[(float_extend:XF (match_operand:SF 1 "general_operand" "fm,0"))
(match_operand:XF 2 "general_operand" "0,f")]))]
"TARGET_80387"
- "* return (char *) output_387_binary_op (insn, operands);")
+ "* return output_387_binary_op (insn, operands);")
(define_insn ""
[(set (match_operand:XF 0 "register_operand" "=f")
@@ -5193,7 +5577,7 @@
[(match_operand:XF 1 "general_operand" "0")
(float:XF (match_operand:SI 2 "general_operand" "rm"))]))]
"TARGET_80387"
- "* return (char *) output_387_binary_op (insn, operands);")
+ "* return output_387_binary_op (insn, operands);")
(define_insn ""
[(set (match_operand:XF 0 "register_operand" "=f,f")
@@ -5202,7 +5586,7 @@
(float_extend:XF
(match_operand:SF 2 "general_operand" "fm,0"))]))]
"TARGET_80387"
- "* return (char *) output_387_binary_op (insn, operands);")
+ "* return output_387_binary_op (insn, operands);")
(define_insn ""
[(set (match_operand:DF 0 "register_operand" "=f,f")
@@ -5210,7 +5594,7 @@
[(float_extend:DF (match_operand:SF 1 "general_operand" "fm,0"))
(match_operand:DF 2 "general_operand" "0,f")]))]
"TARGET_80387"
- "* return (char *) output_387_binary_op (insn, operands);")
+ "* return output_387_binary_op (insn, operands);")
(define_insn ""
[(set (match_operand:DF 0 "register_operand" "=f")
@@ -5218,7 +5602,7 @@
[(match_operand:DF 1 "general_operand" "0")
(float:DF (match_operand:SI 2 "general_operand" "rm"))]))]
"TARGET_80387"
- "* return (char *) output_387_binary_op (insn, operands);")
+ "* return output_387_binary_op (insn, operands);")
(define_insn ""
[(set (match_operand:DF 0 "register_operand" "=f,f")
@@ -5227,7 +5611,7 @@
(float_extend:DF
(match_operand:SF 2 "general_operand" "fm,0"))]))]
"TARGET_80387"
- "* return (char *) output_387_binary_op (insn, operands);")
+ "* return output_387_binary_op (insn, operands);")
(define_insn ""
[(set (match_operand:SF 0 "register_operand" "=f,f")
@@ -5235,7 +5619,7 @@
[(match_operand:SF 1 "nonimmediate_operand" "0,fm")
(match_operand:SF 2 "nonimmediate_operand" "fm,0")]))]
"TARGET_80387"
- "* return (char *) output_387_binary_op (insn, operands);")
+ "* return output_387_binary_op (insn, operands);")
(define_insn ""
[(set (match_operand:SF 0 "register_operand" "=f")
@@ -5243,7 +5627,7 @@
[(float:SF (match_operand:SI 1 "general_operand" "rm"))
(match_operand:SF 2 "general_operand" "0")]))]
"TARGET_80387"
- "* return (char *) output_387_binary_op (insn, operands);")
+ "* return output_387_binary_op (insn, operands);")
(define_insn ""
[(set (match_operand:SF 0 "register_operand" "=f")
@@ -5251,7 +5635,7 @@
[(match_operand:SF 1 "general_operand" "0")
(float:SF (match_operand:SI 2 "general_operand" "rm"))]))]
"TARGET_80387"
- "* return (char *) output_387_binary_op (insn, operands);")
+ "* return output_387_binary_op (insn, operands);")
(define_expand "strlensi"
[(parallel [(set (match_dup 4)
diff --git a/gnu/usr.bin/cc/legal/parse.y b/gnu/usr.bin/cc/legal/parse.y
new file mode 100644
index 0000000..36c8aac
--- /dev/null
+++ b/gnu/usr.bin/cc/legal/parse.y
@@ -0,0 +1,3813 @@
+/* YACC parser for C++ syntax.
+ Copyright (C) 1988, 1989, 1993 Free Software Foundation, Inc.
+ Hacked by Michael Tiemann (tiemann@cygnus.com)
+
+This file is part of GNU CC.
+
+GNU CC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU CC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+
+/* This grammar is based on the GNU CC grammar. */
+
+/* Note: Bison automatically applies a default action of "$$ = $1" for
+ all derivations; this is applied before the explicit action, if one
+ is given. Keep this in mind when reading the actions. */
+
+/* Also note: this version contains experimental exception
+ handling features. They could break, change, disappear,
+ or otherwise exhibit volatile behavior. Don't depend on
+ me (Michael Tiemann) to protect you from any negative impact
+ this may have on your professional, personal, or spiritual life.
+
+ NEWS FLASH: This version now supports the exception handling
+ syntax of Stroustrup's 2nd edition, if -fansi-exceptions is given.
+ THIS IS WORK IN PROGRESS!!! The type of the 'throw' and the
+ 'catch' much match EXACTLY (no inheritance support or coercions).
+ Also, throw-specifications of functions don't work.
+ Destructors aren't called correctly. Etc, etc. --Per Bothner.
+ */
+
+%{
+/* Cause the `yydebug' variable to be defined. */
+#define YYDEBUG 1
+
+#include "config.h"
+
+#include <stdio.h>
+#include <errno.h>
+
+#include "tree.h"
+#include "input.h"
+#include "flags.h"
+#include "lex.h"
+#include "cp-tree.h"
+
+/* Since parsers are distinct for each language, put the language string
+ definition here. (fnf) */
+char *language_string = "GNU C++";
+
+extern tree void_list_node;
+extern struct obstack permanent_obstack;
+
+#ifndef errno
+extern int errno;
+#endif
+
+extern int end_of_file;
+extern int current_class_depth;
+
+void yyerror ();
+
+/* Like YYERROR but do call yyerror. */
+#define YYERROR1 { yyerror ("syntax error"); YYERROR; }
+
+#define OP0(NODE) (TREE_OPERAND (NODE, 0))
+#define OP1(NODE) (TREE_OPERAND (NODE, 1))
+
+/* Contains the statement keyword (if/while/do) to include in an
+ error message if the user supplies an empty conditional expression. */
+static char *cond_stmt_keyword;
+
+/* Nonzero if we have an `extern "C"' acting as an extern specifier. */
+int have_extern_spec;
+int used_extern_spec;
+
+void yyhook ();
+
+/* Cons up an empty parameter list. */
+#ifdef __GNUC__
+__inline
+#endif
+static tree
+empty_parms ()
+{
+ tree parms;
+
+ if (strict_prototype)
+ parms = void_list_node;
+ else
+ parms = NULL_TREE;
+ return parms;
+}
+%}
+
+%start program
+
+%union {long itype; tree ttype; char *strtype; enum tree_code code; }
+
+/* All identifiers that are not reserved words
+ and are not declared typedefs in the current block */
+%token IDENTIFIER
+
+/* All identifiers that are declared typedefs in the current block.
+ In some contexts, they are treated just like IDENTIFIER,
+ but they can also serve as typespecs in declarations. */
+%token TYPENAME
+
+/* Reserved words that specify storage class.
+ yylval contains an IDENTIFIER_NODE which indicates which one. */
+%token SCSPEC
+
+/* Reserved words that specify type.
+ yylval contains an IDENTIFIER_NODE which indicates which one. */
+%token TYPESPEC
+
+/* Reserved words that qualify type: "const" or "volatile".
+ yylval contains an IDENTIFIER_NODE which indicates which one. */
+%token TYPE_QUAL
+
+/* Character or numeric constants.
+ yylval is the node for the constant. */
+%token CONSTANT
+
+/* String constants in raw form.
+ yylval is a STRING_CST node. */
+%token STRING
+
+/* "...", used for functions with variable arglists. */
+%token ELLIPSIS
+
+/* the reserved words */
+/* SCO include files test "ASM", so use something else. */
+%token SIZEOF ENUM /* STRUCT UNION */ IF ELSE WHILE DO FOR SWITCH CASE DEFAULT
+%token BREAK CONTINUE RETURN GOTO ASM_KEYWORD GCC_ASM_KEYWORD TYPEOF ALIGNOF
+%token HEADOF CLASSOF SIGOF
+%token ATTRIBUTE EXTENSION LABEL
+
+/* the reserved words... C++ extensions */
+%token <ttype> AGGR
+%token <itype> VISSPEC
+%token DELETE NEW OVERLOAD THIS OPERATOR CXX_TRUE CXX_FALSE
+%token LEFT_RIGHT TEMPLATE
+%token TYPEID DYNAMIC_CAST STATIC_CAST REINTERPRET_CAST CONST_CAST
+%token <itype> SCOPE
+
+/* Define the operator tokens and their precedences.
+ The value is an integer because, if used, it is the tree code
+ to use in the expression made from the operator. */
+
+%left EMPTY /* used to resolve s/r with epsilon */
+
+%left error
+
+/* Add precedence rules to solve dangling else s/r conflict */
+%nonassoc IF
+%nonassoc ELSE
+
+%left IDENTIFIER TYPENAME PTYPENAME SCSPEC TYPESPEC TYPE_QUAL ENUM AGGR ELLIPSIS TYPEOF SIGOF OPERATOR
+
+%left '{' ',' ';'
+
+%right <code> ASSIGN '='
+%right <code> '?' ':'
+%left <code> OROR
+%left <code> ANDAND
+%left <code> '|'
+%left <code> '^'
+%left <code> '&'
+%left <code> MIN_MAX
+%left <code> EQCOMPARE
+%left <code> ARITHCOMPARE '<' '>'
+%left <code> LSHIFT RSHIFT
+%left <code> '+' '-'
+%left <code> '*' '/' '%'
+%left <code> POINTSAT_STAR DOT_STAR
+%right <code> UNARY PLUSPLUS MINUSMINUS '~'
+%left HYPERUNARY
+%left <ttype> PAREN_STAR_PAREN LEFT_RIGHT
+%left <code> POINTSAT '.' '(' '['
+
+%right SCOPE /* C++ extension */
+%nonassoc NEW DELETE TRY CATCH THROW
+
+%type <code> unop
+
+%type <ttype> identifier IDENTIFIER TYPENAME CONSTANT expr nonnull_exprlist
+%type <ttype> paren_expr_or_null nontrivial_exprlist
+%type <ttype> expr_no_commas cast_expr unary_expr primary string STRING
+%type <ttype> typed_declspecs reserved_declspecs boolean.literal
+%type <ttype> typed_typespecs reserved_typespecquals
+%type <ttype> declmods typespec typespecqual_reserved
+%type <ttype> SCSPEC TYPESPEC TYPE_QUAL nonempty_type_quals maybe_type_qual
+%type <itype> initdecls notype_initdecls initdcl /* C++ modification */
+%type <ttype> init initlist maybeasm
+%type <ttype> asm_operands nonnull_asm_operands asm_operand asm_clobbers
+%type <ttype> maybe_attribute attributes attribute attribute_list attrib
+%type <ttype> any_word
+
+%type <ttype> compstmt implicitly_scoped_stmt
+
+%type <ttype> declarator notype_declarator after_type_declarator
+%type <ttype> direct_notype_declarator direct_after_type_declarator
+
+%type <ttype> structsp opt.component_decl_list component_decl_list
+%type <ttype> component_decl components component_declarator
+%type <ttype> notype_components notype_component_declarator
+%type <ttype> after_type_component_declarator after_type_component_declarator0
+%type <ttype> notype_component_declarator0 component_decl_1
+%type <ttype> enumlist enumerator
+%type <ttype> type_id absdcl type_quals
+%type <ttype> direct_abstract_declarator conversion_declarator
+%type <ttype> new_type_id new_declarator direct_new_declarator
+%type <ttype> xexpr parmlist parms parm bad_parm full_parm
+%type <ttype> identifiers_or_typenames
+%type <ttype> fcast_or_absdcl regcast_or_absdcl sub_cast_expr
+%type <ttype> expr_or_declarator complex_notype_declarator
+%type <ttype> notype_unqualified_id unqualified_id qualified_id
+%type <ttype> overqualified_id notype_qualified_id
+%type <ttype> complex_direct_notype_declarator functional_cast
+%type <ttype> named_parm complex_parmlist typed_declspecs1 parms_comma
+
+/* C++ extensions */
+%token <ttype> TYPENAME_ELLIPSIS PTYPENAME
+%token <ttype> PRE_PARSED_FUNCTION_DECL EXTERN_LANG_STRING ALL
+%token <ttype> PRE_PARSED_CLASS_DECL
+%type <ttype> fn.def1 /* Not really! */
+%type <ttype> fn.def2 return_id
+%type <ttype> named_class_head named_class_head_sans_basetype
+%type <ttype> unnamed_class_head
+%type <ttype> class_head base_class_list
+%type <itype> base_class_access_list
+%type <ttype> base_class maybe_base_class_list base_class.1
+%type <ttype> maybe_raises ansi_raise_identifier ansi_raise_identifiers
+%type <ttype> component_declarator0
+%type <ttype> forhead.1 operator_name
+%type <ttype> object aggr
+%type <itype> new delete
+/* %type <ttype> primary_no_id */
+%type <ttype> nonmomentary_expr
+%type <itype> forhead.2 initdcl0 notype_initdcl0 member_init_list
+%type <ttype> template_header template_parm_list template_parm
+%type <ttype> template_type_parm
+%type <ttype> template_type template_arg_list template_arg
+%type <ttype> template_instantiation template_type_name tmpl.2
+%type <ttype> template_instantiate_once template_instantiate_some
+%type <itype> fn_tmpl_end
+/* %type <itype> try_for_typename */
+%type <ttype> condition xcond paren_cond_or_null
+%type <ttype> type_name nested_name_specifier nested_type ptr_to_mem
+%type <ttype> qualified_type_name complete_type_name notype_identifier
+%type <ttype> complex_type_name nested_name_specifier_1
+%type <itype> nomods_initdecls nomods_initdcl0
+%type <ttype> new_initializer new_placement specialization type_specifier_seq
+
+/* in order to recognize aggr tags as defining and thus shadowing. */
+%token TYPENAME_DEFN IDENTIFIER_DEFN PTYPENAME_DEFN
+%type <ttype> named_class_head_sans_basetype_defn
+%type <ttype> identifier_defn IDENTIFIER_DEFN TYPENAME_DEFN PTYPENAME_DEFN
+
+%type <strtype> .pushlevel
+
+/* spew.c depends on this being the last token. Define
+ any new tokens before this one! */
+%token END_OF_SAVED_INPUT
+
+%{
+/* List of types and structure classes of the current declaration. */
+static tree current_declspecs;
+
+/* When defining an aggregate, this is the most recent one being defined. */
+static tree current_aggr;
+
+/* Tell yyparse how to print a token's value, if yydebug is set. */
+
+#define YYPRINT(FILE,YYCHAR,YYLVAL) yyprint(FILE,YYCHAR,YYLVAL)
+extern void yyprint ();
+extern tree combine_strings PROTO((tree));
+%}
+
+%%
+program: /* empty */
+ | extdefs
+ {
+ /* In case there were missing closebraces,
+ get us back to the global binding level. */
+ while (! global_bindings_p ())
+ poplevel (0, 0, 0);
+ finish_file ();
+ }
+ ;
+
+/* the reason for the strange actions in this rule
+ is so that notype_initdecls when reached via datadef
+ can find a valid list of type and sc specs in $0. */
+
+extdefs:
+ { $<ttype>$ = NULL_TREE; } lang_extdef
+ { $<ttype>$ = NULL_TREE; }
+ | extdefs lang_extdef
+ { $<ttype>$ = NULL_TREE; }
+ ;
+
+.hush_warning:
+ { have_extern_spec = 1;
+ used_extern_spec = 0;
+ $<ttype>$ = NULL_TREE; }
+ ;
+.warning_ok:
+ { have_extern_spec = 0; }
+ ;
+
+asm_keyword:
+ ASM_KEYWORD
+ | GCC_ASM_KEYWORD
+ ;
+
+lang_extdef:
+ { if (pending_lang_change) do_pending_lang_change(); }
+ extdef
+ { if (! global_bindings_p () && ! pseudo_global_level_p())
+ pop_everything (); }
+ ;
+
+extdef:
+ fndef
+ { if (pending_inlines) do_pending_inlines (); }
+ | datadef
+ { if (pending_inlines) do_pending_inlines (); }
+ | template_def
+ { if (pending_inlines) do_pending_inlines (); }
+ | overloaddef
+ | asm_keyword '(' string ')' ';'
+ { if (TREE_CHAIN ($3)) $3 = combine_strings ($3);
+ assemble_asm ($3); }
+ | extern_lang_string '{' extdefs '}'
+ { pop_lang_context (); }
+ | extern_lang_string '{' '}'
+ { pop_lang_context (); }
+ | extern_lang_string .hush_warning fndef .warning_ok
+ { if (pending_inlines) do_pending_inlines ();
+ pop_lang_context (); }
+ | extern_lang_string .hush_warning datadef .warning_ok
+ { if (pending_inlines) do_pending_inlines ();
+ pop_lang_context (); }
+ ;
+
+extern_lang_string:
+ EXTERN_LANG_STRING
+ { push_lang_context ($1); }
+ ;
+
+template_header:
+ TEMPLATE '<'
+ { begin_template_parm_list (); }
+ template_parm_list '>'
+ { $$ = end_template_parm_list ($4); }
+ ;
+
+template_parm_list:
+ template_parm
+ { $$ = process_template_parm (NULL_TREE, $1); }
+ | template_parm_list ',' template_parm
+ { $$ = process_template_parm ($1, $3); }
+ ;
+
+template_type_parm:
+ aggr
+ {
+ $$ = build_tree_list ($1, NULL_TREE);
+ ttpa:
+ if (TREE_PURPOSE ($$) == signature_type_node)
+ sorry ("signature as template type parameter");
+ else if (TREE_PURPOSE ($$) != class_type_node)
+ pedwarn ("template type parameters must use the keyword `class'");
+ }
+ | aggr identifier
+ { $$ = build_tree_list ($1, $2); goto ttpa; }
+ ;
+
+template_parm:
+ /* The following rules introduce a new reduce/reduce
+ conflict on the ',' and '>' input tokens: they are valid
+ prefixes for a `structsp', which means they could match a
+ nameless parameter. See 14.6, paragraph 3.
+ By putting them before the `parm' rule, we get
+ their match before considering them nameless parameter
+ declarations. */
+ template_type_parm
+ { $$ = build_tree_list (NULL_TREE, $$); }
+ | template_type_parm '=' typespec
+ { $$ = build_tree_list ($3, $$); }
+ | full_parm
+ ;
+
+overloaddef:
+ OVERLOAD ov_identifiers ';'
+ { warning ("use of `overload' is an anachronism"); }
+ ;
+
+ov_identifiers: IDENTIFIER
+ { declare_overloaded ($1); }
+ | ov_identifiers ',' IDENTIFIER
+ { declare_overloaded ($3); }
+ ;
+
+template_def:
+ /* Class template declarations go here; they aren't normal class
+ declarations, because we can't process the bodies yet. */
+ template_header named_class_head_sans_basetype '{'
+ { yychar = '{'; goto template1; }
+ ';'
+ | template_header named_class_head_sans_basetype_defn '{'
+ { yychar = '{'; goto template1; }
+ ';'
+ | template_header named_class_head_sans_basetype ':'
+ { yychar = ':'; goto template1; }
+ ';'
+ | template_header named_class_head_sans_basetype_defn ':'
+ {
+ yychar = ':';
+ template1:
+ if (current_aggr == exception_type_node)
+ error ("template type must define an aggregate or union");
+ else if (current_aggr == signature_type_node)
+ sorry ("template type defining a signature");
+ /* Maybe pedantic warning for union?
+ How about an enum? :-) */
+ end_template_decl ($1, $2, current_aggr, 1);
+ reinit_parse_for_template (yychar, $1, $2);
+ yychar = YYEMPTY;
+ }
+ ';'
+ | template_header named_class_head_sans_basetype ';'
+ {
+ end_template_decl ($1, $2, current_aggr, 0);
+ /* declare $2 as template name with $1 parm list */
+ }
+ | template_header named_class_head_sans_basetype_defn ';'
+ {
+ end_template_decl ($1, $2, current_aggr, 0);
+ /* declare $2 as template name with $1 parm list */
+ }
+ | template_header /* notype_initdcl0 ';' */
+ notype_declarator maybe_raises maybeasm maybe_attribute
+ fn_tmpl_end
+ {
+ tree d;
+ int momentary;
+ int def = ($6 != ';');
+ momentary = suspend_momentary ();
+ d = start_decl ($<ttype>2, /*current_declspecs*/NULL_TREE, 0,
+ $3);
+ cplus_decl_attributes (d, $5);
+ finish_decl (d, NULL_TREE, $4, 0);
+ end_template_decl ($1, d, 0, def);
+ if (def)
+ reinit_parse_for_template ((int) $6, $1, d);
+ resume_momentary (momentary);
+ }
+ | template_header typed_declspecs /*initdcl0*/
+ declarator maybe_raises maybeasm maybe_attribute
+ fn_tmpl_end
+ {
+ tree d;
+ int momentary;
+ int def = ($7 != ';');
+
+ current_declspecs = $2;
+ momentary = suspend_momentary ();
+ d = start_decl ($<ttype>3, current_declspecs,
+ 0, $<ttype>4);
+ cplus_decl_attributes (d, $6);
+ finish_decl (d, NULL_TREE, $5, 0);
+ end_template_decl ($1, d, 0, def);
+ if (def)
+ {
+ reinit_parse_for_template ((int) $7, $1, d);
+ yychar = YYEMPTY;
+ }
+ note_list_got_semicolon ($<ttype>2);
+ resume_momentary (momentary);
+ }
+ | template_header declmods notype_declarator fn_tmpl_end
+ {
+ int def = ($4 != ';');
+ tree d = start_decl ($<ttype>3, $<ttype>2, 0, NULL_TREE);
+ finish_decl (d, NULL_TREE, NULL_TREE, 0);
+ end_template_decl ($1, d, 0, def);
+ if (def)
+ reinit_parse_for_template ((int) $4, $1, d);
+ }
+ /* Try to recover from syntax errors in templates. */
+ | template_header error '}' { end_template_decl ($1, 0, 0, 0); }
+ | template_header error ';' { end_template_decl ($1, 0, 0, 0); }
+ ;
+
+fn_tmpl_end: '{' { $$ = '{'; }
+ | ':' { $$ = ':'; }
+ | ';' { $$ = ';'; }
+ | '=' { $$ = '='; }
+ | RETURN { $$ = RETURN; }
+ ;
+
+datadef:
+ nomods_initdecls ';'
+ {}
+ | declmods notype_initdecls ';'
+ {}
+ /* Normal case to make fast: "const i;". */
+ | declmods notype_declarator ';'
+ { tree d;
+ d = start_decl ($<ttype>2, $<ttype>$, 0, NULL_TREE);
+ finish_decl (d, NULL_TREE, NULL_TREE, 0);
+ }
+ | typed_declspecs initdecls ';'
+ {
+ note_list_got_semicolon ($<ttype>$);
+ }
+ /* Normal case: make this fast. */
+ | typed_declspecs declarator ';'
+ { tree d;
+ d = start_decl ($<ttype>2, $<ttype>$, 0, NULL_TREE);
+ finish_decl (d, NULL_TREE, NULL_TREE, 0);
+ note_list_got_semicolon ($<ttype>$);
+ }
+ | declmods ';'
+ { pedwarn ("empty declaration"); }
+ | explicit_instantiation ';'
+ | typed_declspecs ';'
+ {
+ tree t = $<ttype>$;
+ shadow_tag (t);
+ if (TREE_CODE (t) == TREE_LIST
+ && TREE_PURPOSE (t) == NULL_TREE)
+ {
+ t = TREE_VALUE (t);
+ if (IS_AGGR_TYPE (t)
+ && IDENTIFIER_TEMPLATE (TYPE_IDENTIFIER (t)))
+ {
+ if (CLASSTYPE_USE_TEMPLATE (t) == 0)
+ SET_CLASSTYPE_TEMPLATE_SPECIALIZATION (t);
+ else if (CLASSTYPE_TEMPLATE_INSTANTIATION (t))
+ error ("override declaration for already-expanded template");
+ }
+ }
+ note_list_got_semicolon ($<ttype>$);
+ }
+ | error ';'
+ | error '}'
+ | ';'
+ ;
+
+fndef:
+ fn.def1 base_init compstmt_or_error
+ {
+ finish_function (lineno, 1);
+ /* finish_function performs these three statements:
+
+ expand_end_bindings (getdecls (), 1, 0);
+ poplevel (1, 1, 0);
+
+ expand_end_bindings (0, 0, 0);
+ poplevel (0, 0, 1);
+ */
+ if ($<ttype>$) process_next_inline ($<ttype>$);
+ }
+ | fn.def1 return_init base_init compstmt_or_error
+ {
+ finish_function (lineno, 1);
+ /* finish_function performs these three statements:
+
+ expand_end_bindings (getdecls (), 1, 0);
+ poplevel (1, 1, 0);
+
+ expand_end_bindings (0, 0, 0);
+ poplevel (0, 0, 1);
+ */
+ if ($<ttype>$) process_next_inline ($<ttype>$);
+ }
+ | fn.def1 nodecls compstmt_or_error
+ { finish_function (lineno, 0);
+ if ($<ttype>$) process_next_inline ($<ttype>$); }
+ | fn.def1 return_init ';' nodecls compstmt_or_error
+ { finish_function (lineno, 0);
+ if ($<ttype>$) process_next_inline ($<ttype>$); }
+ | fn.def1 return_init nodecls compstmt_or_error
+ { finish_function (lineno, 0);
+ if ($<ttype>$) process_next_inline ($<ttype>$); }
+ | typed_declspecs declarator error
+ {}
+ | declmods notype_declarator error
+ {}
+ | notype_declarator error
+ {}
+ ;
+
+fn.def1:
+ typed_declspecs declarator maybe_raises
+ { if (! start_function ($$, $2, $3, 0))
+ YYERROR1;
+ reinit_parse_for_function ();
+ $$ = NULL_TREE; }
+ | declmods notype_declarator maybe_raises
+ { if (! start_function ($$, $2, $3, 0))
+ YYERROR1;
+ reinit_parse_for_function ();
+ $$ = NULL_TREE; }
+ | notype_declarator maybe_raises
+ { if (! start_function (NULL_TREE, $$, $2, 0))
+ YYERROR1;
+ reinit_parse_for_function ();
+ $$ = NULL_TREE; }
+ | PRE_PARSED_FUNCTION_DECL
+ { start_function (NULL_TREE, TREE_VALUE ($$), NULL_TREE, 1);
+ reinit_parse_for_function (); }
+ ;
+
+/* more C++ complexity. See component_decl for a comment on the
+ reduce/reduce conflict introduced by these rules. */
+fn.def2:
+ typed_declspecs '(' parmlist ')' type_quals maybe_raises
+ {
+ $$ = build_parse_node (CALL_EXPR, TREE_VALUE ($1), $3, $5);
+ $$ = start_method (TREE_CHAIN ($1), $$, $6);
+ rest_of_mdef:
+ if (! $$)
+ YYERROR1;
+ if (yychar == YYEMPTY)
+ yychar = YYLEX;
+ reinit_parse_for_method (yychar, $$); }
+ | typed_declspecs LEFT_RIGHT type_quals maybe_raises
+ {
+ $$ = build_parse_node (CALL_EXPR, TREE_VALUE ($1),
+ empty_parms (), $3);
+ $$ = start_method (TREE_CHAIN ($1), $$, $4);
+ goto rest_of_mdef;
+ }
+ | typed_declspecs declarator maybe_raises
+ { $$ = start_method ($$, $2, $3); goto rest_of_mdef; }
+ | declmods notype_declarator maybe_raises
+ { $$ = start_method ($$, $2, $3); goto rest_of_mdef; }
+ | notype_declarator maybe_raises
+ { $$ = start_method (NULL_TREE, $$, $2); goto rest_of_mdef; }
+ ;
+
+return_id: RETURN IDENTIFIER
+ {
+ if (! current_function_parms_stored)
+ store_parm_decls ();
+ $$ = $2;
+ }
+ ;
+
+return_init: return_id
+ { store_return_init ($<ttype>$, NULL_TREE); }
+ | return_id '=' init
+ { store_return_init ($<ttype>$, $3); }
+ | return_id '(' nonnull_exprlist ')'
+ { store_return_init ($<ttype>$, $3); }
+ | return_id LEFT_RIGHT
+ { store_return_init ($<ttype>$, NULL_TREE); }
+ ;
+
+base_init:
+ ':' .set_base_init member_init_list
+ {
+ if ($3 == 0)
+ error ("no base initializers given following ':'");
+ setup_vtbl_ptr ();
+ /* Always keep the BLOCK node associated with the outermost
+ pair of curley braces of a function. These are needed
+ for correct operation of dwarfout.c. */
+ keep_next_level ();
+ }
+ ;
+
+.set_base_init:
+ /* empty */
+ {
+ if (! current_function_parms_stored)
+ store_parm_decls ();
+
+ /* Flag that we are processing base and member initializers. */
+ current_vtable_decl = error_mark_node;
+
+ if (DECL_CONSTRUCTOR_P (current_function_decl))
+ {
+ /* Make a contour for the initializer list. */
+ pushlevel (0);
+ clear_last_expr ();
+ expand_start_bindings (0);
+ }
+ else if (current_class_type == NULL_TREE)
+ error ("base initializers not allowed for non-member functions");
+ else if (! DECL_CONSTRUCTOR_P (current_function_decl))
+ error ("only constructors take base initializers");
+ }
+ ;
+
+member_init_list:
+ /* empty */
+ { $$ = 0; }
+ | member_init
+ { $$ = 1; }
+ | member_init_list ',' member_init
+ | member_init_list error
+ ;
+
+member_init: '(' nonnull_exprlist ')'
+ {
+ if (current_class_name && !flag_traditional)
+ pedwarn ("anachronistic old style base class initializer");
+ expand_member_init (C_C_D, NULL_TREE, $2);
+ }
+ | LEFT_RIGHT
+ {
+ if (current_class_name && !flag_traditional)
+ pedwarn ("anachronistic old style base class initializer");
+ expand_member_init (C_C_D, NULL_TREE, void_type_node);
+ }
+ | notype_identifier '(' nonnull_exprlist ')'
+ { expand_member_init (C_C_D, $<ttype>$, $3); }
+ | notype_identifier LEFT_RIGHT
+ { expand_member_init (C_C_D, $<ttype>$, void_type_node); }
+ | complete_type_name '(' nonnull_exprlist ')'
+ { expand_member_init (C_C_D, $<ttype>$, $3); }
+ | complete_type_name LEFT_RIGHT
+ { expand_member_init (C_C_D, $<ttype>$, void_type_node); }
+ /* GNU extension */
+ | notype_qualified_id '(' nonnull_exprlist ')'
+ {
+ do_member_init (OP0 ($1), OP1 ($1), $3);
+ }
+ | notype_qualified_id LEFT_RIGHT
+ {
+ do_member_init (OP0 ($1), OP1 ($1), void_type_node);
+ }
+ ;
+
+identifier:
+ IDENTIFIER
+ | TYPENAME
+ | PTYPENAME
+ ;
+
+notype_identifier:
+ IDENTIFIER
+ | PTYPENAME %prec EMPTY
+ ;
+
+identifier_defn:
+ IDENTIFIER_DEFN
+ | TYPENAME_DEFN
+ | PTYPENAME_DEFN
+ ;
+
+explicit_instantiation:
+ TEMPLATE specialization template_instantiation
+ { do_type_instantiation ($3 ? $3 : $2, NULL_TREE); }
+ | TEMPLATE typed_declspecs declarator
+ { do_function_instantiation ($2, $3, NULL_TREE); }
+ | SCSPEC TEMPLATE specialization template_instantiation
+ { do_type_instantiation ($4 ? $4 : $3, $1); }
+ | SCSPEC TEMPLATE typed_declspecs declarator
+ { do_function_instantiation ($3, $4, $1); }
+ ;
+
+template_type:
+ template_type_name tmpl.2 template_instantiation
+ { if ($3) $$ = $3; }
+ ;
+
+template_type_name:
+ PTYPENAME '<' template_arg_list '>'
+ { $$ = lookup_template_class ($$, $3, NULL_TREE); }
+ | PTYPENAME '<' '>'
+ { $$ = lookup_template_class ($$, NULL_TREE, NULL_TREE); }
+ | TYPENAME '<' template_arg_list '>'
+ { $$ = lookup_template_class ($$, $3, NULL_TREE); }
+ ;
+
+tmpl.2:
+ /* empty */ %prec EMPTY
+ { $$ = instantiate_class_template ($<ttype>0, 1); }
+ ;
+
+template_arg_list:
+ template_arg
+ { $$ = build_tree_list (NULL_TREE, $$); }
+ | template_arg_list ',' template_arg
+ { $$ = chainon ($$, build_tree_list (NULL_TREE, $3)); }
+ ;
+
+template_arg:
+ type_id
+ { $$ = groktypename ($$); }
+ | expr_no_commas %prec UNARY
+ ;
+
+template_instantiate_once:
+ PRE_PARSED_CLASS_DECL maybe_base_class_list
+ {
+ tree t, decl, tmpl;
+
+ tmpl = TREE_PURPOSE (IDENTIFIER_TEMPLATE ($1));
+ t = xref_tag (DECL_TEMPLATE_INFO (tmpl)->aggr, $1, $2, 0);
+ set_current_level_tags_transparency (1);
+ my_friendly_assert (TREE_CODE (t) == RECORD_TYPE
+ || TREE_CODE (t) == UNION_TYPE, 257);
+ $<ttype>$ = t;
+
+ /* Now, put a copy of the decl in global scope, to avoid
+ recursive expansion. */
+ decl = IDENTIFIER_LOCAL_VALUE ($1);
+ if (!decl)
+ decl = IDENTIFIER_CLASS_VALUE ($1);
+ /* Now, put a copy of the decl in global scope, to avoid
+ recursive expansion. */
+ if (decl)
+ {
+ /* Need to copy it to clear the chain pointer,
+ and need to get it into permanent storage. */
+ my_friendly_assert (TREE_CODE (decl) == TYPE_DECL, 258);
+ push_obstacks (&permanent_obstack, &permanent_obstack);
+ decl = copy_node (decl);
+ if (DECL_LANG_SPECIFIC (decl))
+ copy_lang_decl (decl);
+ pop_obstacks ();
+ pushdecl_top_level (decl);
+ }
+ /* Kludge; see instantiate_class_template. */
+ TYPE_BEING_DEFINED (t) = 0;
+ }
+ left_curly opt.component_decl_list '}'
+ {
+ tree t = finish_struct ($<ttype>3, $5, 0);
+
+ pop_obstacks ();
+ end_template_instantiation ($1);
+
+ /* Now go after the methods & class data. */
+ instantiate_member_templates ($1);
+
+ pop_tinst_level();
+
+ CLASSTYPE_GOT_SEMICOLON (t) = 1;
+ }
+ ;
+
+template_instantiation:
+ /* empty */
+ { $$ = NULL_TREE; }
+ | template_instantiate_once
+ { $$ = $1; }
+ ;
+
+template_instantiate_some:
+ /* empty */
+ { $$ = NULL_TREE; /* never used from here... */}
+ | template_instantiate_once template_instantiate_some
+ { $$ = $1; /*???*/ }
+ ;
+
+unop: '-'
+ { $$ = NEGATE_EXPR; }
+ | '+'
+ { $$ = CONVERT_EXPR; }
+ | PLUSPLUS
+ { $$ = PREINCREMENT_EXPR; }
+ | MINUSMINUS
+ { $$ = PREDECREMENT_EXPR; }
+ | '!'
+ { $$ = TRUTH_NOT_EXPR; }
+ ;
+
+expr: nontrivial_exprlist
+ { $$ = build_x_compound_expr ($$); }
+ | expr_no_commas
+ ;
+
+paren_expr_or_null:
+ LEFT_RIGHT
+ { error ("ANSI C++ forbids an empty condition for `%s'",
+ cond_stmt_keyword);
+ $$ = integer_zero_node; }
+ | '(' expr ')'
+ { $$ = build1 (CLEANUP_POINT_EXPR, bool_type_node,
+ bool_truthvalue_conversion ($2)); }
+ ;
+
+paren_cond_or_null:
+ LEFT_RIGHT
+ { error ("ANSI C++ forbids an empty condition for `%s'",
+ cond_stmt_keyword);
+ $$ = integer_zero_node; }
+ | '(' condition ')'
+ { $$ = build1 (CLEANUP_POINT_EXPR, bool_type_node,
+ bool_truthvalue_conversion ($2)); }
+ ;
+
+xcond:
+ /* empty */
+ { $$ = NULL_TREE; }
+ | condition
+ { $$ = build1 (CLEANUP_POINT_EXPR, bool_type_node,
+ bool_truthvalue_conversion ($$)); }
+ | error
+ { $$ = NULL_TREE; }
+ ;
+
+condition:
+ type_specifier_seq declarator maybe_raises maybeasm maybe_attribute '='
+ { {
+ tree d;
+ for (d = getdecls (); d; d = TREE_CHAIN (d))
+ if (TREE_CODE (d) == TYPE_DECL) {
+ tree s = TREE_TYPE (d);
+ if (TREE_CODE (s) == RECORD_TYPE)
+ cp_error ("definition of class `%T' in condition", s);
+ else if (TREE_CODE (s) == ENUMERAL_TYPE)
+ cp_error ("definition of enum `%T' in condition", s);
+ }
+ }
+ current_declspecs = $1;
+ $<itype>6 = suspend_momentary ();
+ $<ttype>$ = start_decl ($<ttype>2, current_declspecs, 1, $3);
+ cplus_decl_attributes ($<ttype>$, $5);
+ }
+ init
+ {
+ finish_decl ($<ttype>7, $8, $5, 0);
+ resume_momentary ($<itype>6);
+ $$ = $<ttype>7;
+ if (TREE_CODE (TREE_TYPE ($$)) == ARRAY_TYPE)
+ cp_error ("definition of array `%#D' in condition", $$);
+ }
+ | expr
+ ;
+
+already_scoped_stmt:
+ '{' '}'
+ { finish_stmt (); }
+ | '{' maybe_label_decls stmts '}'
+ { finish_stmt (); }
+ | '{' maybe_label_decls error '}'
+ { finish_stmt (); }
+ | simple_stmt
+ ;
+
+
+nontrivial_exprlist:
+ expr_no_commas ',' expr_no_commas
+ { $$ = tree_cons (NULL_TREE, $$,
+ build_tree_list (NULL_TREE, $3)); }
+ | expr_no_commas ',' error
+ { $$ = tree_cons (NULL_TREE, $$,
+ build_tree_list (NULL_TREE, error_mark_node)); }
+ | nontrivial_exprlist ',' expr_no_commas
+ { chainon ($$, build_tree_list (NULL_TREE, $3)); }
+ | nontrivial_exprlist ',' error
+ { chainon ($$, build_tree_list (NULL_TREE, error_mark_node)); }
+ ;
+
+nonnull_exprlist:
+ expr_no_commas
+ { $$ = build_tree_list (NULL_TREE, $$); }
+ | nontrivial_exprlist
+ ;
+
+unary_expr:
+ primary %prec UNARY
+ {
+#if 0
+ if (TREE_CODE ($$) == TYPE_EXPR)
+ $$ = build_component_type_expr (C_C_D, $$, NULL_TREE, 1);
+#endif
+ }
+ /* __extension__ turns off -pedantic for following primary. */
+ | EXTENSION
+ { $<itype>1 = pedantic;
+ pedantic = 0; }
+ cast_expr %prec UNARY
+ { $$ = $3;
+ pedantic = $<itype>1; }
+ | '*' cast_expr %prec UNARY
+ { $$ = build_x_indirect_ref ($2, "unary *"); }
+ | '&' cast_expr %prec UNARY
+ { $$ = build_x_unary_op (ADDR_EXPR, $2); }
+ | '~' cast_expr
+ { $$ = build_x_unary_op (BIT_NOT_EXPR, $2); }
+ | unop cast_expr %prec UNARY
+ { $$ = build_x_unary_op ($1, $2);
+ if ($1 == NEGATE_EXPR && TREE_CODE ($2) == INTEGER_CST)
+ TREE_NEGATED_INT ($$) = 1;
+ overflow_warning ($$);
+ }
+ /* Refer to the address of a label as a pointer. */
+ | ANDAND identifier
+ { tree label = lookup_label ($2);
+ if (label == NULL_TREE)
+ $$ = null_pointer_node;
+ else
+ {
+ TREE_USED (label) = 1;
+ $$ = build1 (ADDR_EXPR, ptr_type_node, label);
+ TREE_CONSTANT ($$) = 1;
+ }
+ }
+ | SIZEOF unary_expr %prec UNARY
+ { if (TREE_CODE ($2) == COMPONENT_REF
+ && DECL_BIT_FIELD (TREE_OPERAND ($2, 1)))
+ error ("sizeof applied to a bit-field");
+ /* ANSI says arrays and functions are converted inside comma.
+ But we can't really convert them in build_compound_expr
+ because that would break commas in lvalues.
+ So do the conversion here if operand was a comma. */
+ if (TREE_CODE ($2) == COMPOUND_EXPR
+ && (TREE_CODE (TREE_TYPE ($2)) == ARRAY_TYPE
+ || TREE_CODE (TREE_TYPE ($2)) == FUNCTION_TYPE))
+ $2 = default_conversion ($2);
+ else if (TREE_CODE ($2) == TREE_LIST)
+ {
+ tree t = TREE_VALUE ($2);
+ if (t != NULL_TREE
+ && TREE_CODE (TREE_TYPE (t)) == FUNCTION_TYPE)
+ pedwarn ("ANSI C++ forbids using sizeof() on a function");
+ }
+ $$ = c_sizeof (TREE_TYPE ($2)); }
+ | SIZEOF '(' type_id ')' %prec HYPERUNARY
+ { $$ = c_sizeof (groktypename ($3)); }
+ | ALIGNOF unary_expr %prec UNARY
+ { $$ = grok_alignof ($2); }
+ | ALIGNOF '(' type_id ')' %prec HYPERUNARY
+ { $$ = c_alignof (groktypename ($3)); }
+
+ /* The %prec EMPTY's here are required by the = init initializer
+ syntax extension; see below. */
+ | new new_type_id %prec EMPTY
+ { $$ = build_new (NULL_TREE, $2, NULL_TREE, $1); }
+ | new new_type_id new_initializer
+ { $$ = build_new (NULL_TREE, $2, $3, $1); }
+ | new new_placement new_type_id %prec EMPTY
+ { $$ = build_new ($2, $3, NULL_TREE, $1); }
+ | new new_placement new_type_id new_initializer
+ { $$ = build_new ($2, $3, $4, $1); }
+ | new '(' type_id ')' %prec EMPTY
+ { $$ = build_new (NULL_TREE, groktypename($3),
+ NULL_TREE, $1); }
+ | new '(' type_id ')' new_initializer
+ { $$ = build_new (NULL_TREE, groktypename($3), $5, $1); }
+ | new new_placement '(' type_id ')' %prec EMPTY
+ { $$ = build_new ($2, groktypename($4), NULL_TREE, $1); }
+ | new new_placement '(' type_id ')' new_initializer
+ { $$ = build_new ($2, groktypename($4), $6, $1); }
+
+ | delete cast_expr %prec UNARY
+ { $$ = delete_sanity ($2, NULL_TREE, 0, $1); }
+ | delete '[' ']' cast_expr %prec UNARY
+ { $$ = delete_sanity ($4, NULL_TREE, 1, $1);
+ if (yychar == YYEMPTY)
+ yychar = YYLEX; }
+ | delete '[' expr ']' cast_expr %prec UNARY
+ { $$ = delete_sanity ($5, $3, 2, $1);
+ if (yychar == YYEMPTY)
+ yychar = YYLEX; }
+ ;
+
+new_placement:
+ '(' nonnull_exprlist ')'
+ { $$ = $2; }
+ | '{' nonnull_exprlist '}'
+ {
+ $$ = $2;
+ pedwarn ("old style placement syntax, use () instead");
+ }
+ ;
+
+new_initializer:
+ '(' nonnull_exprlist ')'
+ { $$ = $2; }
+ | LEFT_RIGHT
+ { $$ = NULL_TREE; }
+ | '(' typespec ')'
+ {
+ cp_error ("`%T' is not a valid expression", $2);
+ $$ = error_mark_node;
+ }
+ /* GNU extension so people can use initializer lists. Note that
+ this alters the meaning of `new int = 1', which was previously
+ syntactically valid but semantically invalid. */
+ | '=' init
+ {
+ if (flag_ansi)
+ pedwarn ("ANSI C++ forbids initialization of new expression with `='");
+ $$ = $2;
+ }
+ ;
+
+/* This is necessary to postpone reduction of `int ((int)(int)(int))'. */
+regcast_or_absdcl:
+ '(' type_id ')' %prec EMPTY
+ { $2 = tree_cons (NULL_TREE, $2, void_list_node);
+ TREE_PARMLIST ($2) = 1;
+ $$ = build_parse_node (CALL_EXPR, NULL_TREE, $2,
+ NULL_TREE); }
+ | regcast_or_absdcl '(' type_id ')' %prec EMPTY
+ { $3 = tree_cons (NULL_TREE, $3, void_list_node);
+ TREE_PARMLIST ($3) = 1;
+ $$ = build_parse_node (CALL_EXPR, $$, $3, NULL_TREE); }
+ ;
+
+cast_expr:
+ sub_cast_expr
+ | regcast_or_absdcl sub_cast_expr %prec UNARY
+ { $$ = reparse_absdcl_as_casts ($$, $2); }
+ | regcast_or_absdcl '{' initlist maybecomma '}' %prec UNARY
+ {
+ tree init = build_nt (CONSTRUCTOR, NULL_TREE,
+ nreverse ($3));
+ if (flag_ansi)
+ pedwarn ("ANSI C++ forbids constructor-expressions");
+ /* Indicate that this was a GNU C constructor expression. */
+ TREE_HAS_CONSTRUCTOR (init) = 1;
+
+ $$ = reparse_absdcl_as_casts ($$, init);
+ }
+ ;
+
+sub_cast_expr:
+ unary_expr
+ | HEADOF '(' expr ')'
+ { $$ = build_headof ($3); }
+ | CLASSOF '(' expr ')'
+ { $$ = build_classof ($3); }
+ | CLASSOF '(' TYPENAME ')'
+ { if (is_aggr_typedef ($3, 1))
+ {
+ tree type = IDENTIFIER_TYPE_VALUE ($3);
+ if (! IS_SIGNATURE(type))
+ $$ = CLASSTYPE_DOSSIER (type);
+ else
+ {
+ sorry ("signature name as argument of `classof'");
+ $$ = error_mark_node;
+ }
+ }
+ else
+ $$ = error_mark_node;
+ }
+ ;
+
+expr_no_commas:
+ cast_expr
+ /* Handle general members. */
+ | expr_no_commas POINTSAT_STAR expr_no_commas
+ { $$ = build_x_binary_op (MEMBER_REF, $$, $3); }
+ | expr_no_commas DOT_STAR expr_no_commas
+ { $$ = build_m_component_ref ($$, $3); }
+ | expr_no_commas '+' expr_no_commas
+ { $$ = build_x_binary_op ($2, $$, $3); }
+ | expr_no_commas '-' expr_no_commas
+ { $$ = build_x_binary_op ($2, $$, $3); }
+ | expr_no_commas '*' expr_no_commas
+ { $$ = build_x_binary_op ($2, $$, $3); }
+ | expr_no_commas '/' expr_no_commas
+ { $$ = build_x_binary_op ($2, $$, $3); }
+ | expr_no_commas '%' expr_no_commas
+ { $$ = build_x_binary_op ($2, $$, $3); }
+ | expr_no_commas LSHIFT expr_no_commas
+ { $$ = build_x_binary_op ($2, $$, $3); }
+ | expr_no_commas RSHIFT expr_no_commas
+ { $$ = build_x_binary_op ($2, $$, $3); }
+ | expr_no_commas ARITHCOMPARE expr_no_commas
+ { $$ = build_x_binary_op ($2, $$, $3); }
+ | expr_no_commas '<' expr_no_commas
+ { $$ = build_x_binary_op (LT_EXPR, $$, $3); }
+ | expr_no_commas '>' expr_no_commas
+ { $$ = build_x_binary_op (GT_EXPR, $$, $3); }
+ | expr_no_commas EQCOMPARE expr_no_commas
+ { $$ = build_x_binary_op ($2, $$, $3); }
+ | expr_no_commas MIN_MAX expr_no_commas
+ { $$ = build_x_binary_op ($2, $$, $3); }
+ | expr_no_commas '&' expr_no_commas
+ { $$ = build_x_binary_op ($2, $$, $3); }
+ | expr_no_commas '|' expr_no_commas
+ { $$ = build_x_binary_op ($2, $$, $3); }
+ | expr_no_commas '^' expr_no_commas
+ { $$ = build_x_binary_op ($2, $$, $3); }
+ | expr_no_commas ANDAND expr_no_commas
+ { $$ = build_x_binary_op (TRUTH_ANDIF_EXPR, $$, $3); }
+ | expr_no_commas OROR expr_no_commas
+ { $$ = build_x_binary_op (TRUTH_ORIF_EXPR, $$, $3); }
+ | expr_no_commas '?' xexpr ':' expr_no_commas
+ { $$ = build_x_conditional_expr ($$, $3, $5); }
+ | expr_no_commas '=' expr_no_commas
+ { $$ = build_modify_expr ($$, NOP_EXPR, $3); }
+ | expr_no_commas ASSIGN expr_no_commas
+ { register tree rval;
+ if ((rval = build_opfncall (MODIFY_EXPR, LOOKUP_NORMAL, $$, $3,
+ make_node ($2))))
+ $$ = rval;
+ else
+ $$ = build_modify_expr ($$, $2, $3); }
+ | THROW
+ { $$ = build_throw (NULL_TREE); }
+ | THROW expr_no_commas
+ { $$ = build_throw ($2); }
+/* These extensions are not defined. The second arg to build_m_component_ref
+ is old, build_m_component_ref now does an implicit
+ build_indirect_ref (x, NULL_PTR) on the second argument.
+ | object '&' expr_no_commas %prec UNARY
+ { $$ = build_m_component_ref ($$, build_x_unary_op (ADDR_EXPR, $3)); }
+ | object unop expr_no_commas %prec UNARY
+ { $$ = build_m_component_ref ($$, build_x_unary_op ($2, $3)); }
+ | object '(' type_id ')' expr_no_commas %prec UNARY
+ { tree type = groktypename ($3);
+ $$ = build_m_component_ref ($$, build_c_cast (type, $5)); }
+ | object primary_no_id %prec UNARY
+ { $$ = build_m_component_ref ($$, $2); }
+*/
+ ;
+
+notype_unqualified_id:
+ '~' see_typename identifier
+ { $$ = build_parse_node (BIT_NOT_EXPR, $3); }
+ | operator_name
+ | IDENTIFIER
+ | PTYPENAME %prec EMPTY
+ ;
+
+unqualified_id:
+ notype_unqualified_id
+ | TYPENAME
+ ;
+
+expr_or_declarator:
+ notype_unqualified_id
+ | notype_qualified_id
+ | '*' expr_or_declarator %prec UNARY
+ { $$ = build_parse_node (INDIRECT_REF, $2); }
+ | '&' expr_or_declarator %prec UNARY
+ { $$ = build_parse_node (ADDR_EXPR, $2); }
+ ;
+
+direct_notype_declarator:
+ complex_direct_notype_declarator
+ | notype_unqualified_id
+ | notype_qualified_id
+ { push_nested_class (TREE_TYPE (OP0 ($$)), 3);
+ TREE_COMPLEXITY ($$) = current_class_depth; }
+ ;
+
+primary:
+ notype_unqualified_id
+ {
+ if (TREE_CODE ($$) == BIT_NOT_EXPR)
+ $$ = build_x_unary_op (BIT_NOT_EXPR, TREE_OPERAND ($$, 0));
+ else if (IDENTIFIER_OPNAME_P ($$))
+ {
+ tree op = $$;
+ $$ = lookup_name (op, 0);
+ if ($$ == NULL_TREE)
+ {
+ if (op != ansi_opname[ERROR_MARK])
+ error ("operator %s not defined",
+ operator_name_string (op));
+ $$ = error_mark_node;
+ }
+ }
+ else
+ $$ = do_identifier ($$);
+ }
+ | CONSTANT
+ | boolean.literal
+ | string
+ { $$ = combine_strings ($$); }
+ | '(' expr ')'
+ { $$ = $2; }
+ | '(' error ')'
+ { $$ = error_mark_node; }
+ | '('
+ { if (current_function_decl == 0)
+ {
+ error ("braced-group within expression allowed only inside a function");
+ YYERROR;
+ }
+ keep_next_level ();
+ $<ttype>$ = expand_start_stmt_expr (); }
+ compstmt ')'
+ { tree rtl_exp;
+ if (flag_ansi)
+ pedwarn ("ANSI C++ forbids braced-groups within expressions");
+ rtl_exp = expand_end_stmt_expr ($<ttype>2);
+ /* The statements have side effects, so the group does. */
+ TREE_SIDE_EFFECTS (rtl_exp) = 1;
+
+ if (TREE_CODE ($3) == BLOCK)
+ {
+ /* Make a BIND_EXPR for the BLOCK already made. */
+ $$ = build (BIND_EXPR, TREE_TYPE (rtl_exp),
+ NULL_TREE, rtl_exp, $3);
+ /* Remove the block from the tree at this point.
+ It gets put back at the proper place
+ when the BIND_EXPR is expanded. */
+ delete_block ($3);
+ }
+ else
+ $$ = $3;
+ }
+ | primary '(' nonnull_exprlist ')'
+ { /* [eichin:19911016.1902EST] */
+ $<ttype>$ = build_x_function_call ($1, $3, current_class_decl);
+ /* here we instantiate_class_template as needed... */
+ do_pending_templates ();
+ } template_instantiate_some {
+ if (TREE_CODE ($<ttype>5) == CALL_EXPR
+ && TREE_TYPE ($<ttype>5) != void_type_node)
+ $$ = require_complete_type ($<ttype>5);
+ else
+ $$ = $<ttype>5;
+ }
+ | primary LEFT_RIGHT
+ {
+ $$ = build_x_function_call ($$, NULL_TREE, current_class_decl);
+ if (TREE_CODE ($$) == CALL_EXPR
+ && TREE_TYPE ($$) != void_type_node)
+ $$ = require_complete_type ($$);
+ }
+ | primary '[' expr ']'
+ { $$ = grok_array_decl ($$, $3); }
+ | primary PLUSPLUS
+ { /* If we get an OFFSET_REF, turn it into what it really
+ means (e.g., a COMPONENT_REF). This way if we've got,
+ say, a reference to a static member that's being operated
+ on, we don't end up trying to find a member operator for
+ the class it's in. */
+ if (TREE_CODE ($$) == OFFSET_REF)
+ $$ = resolve_offset_ref ($$);
+ $$ = build_x_unary_op (POSTINCREMENT_EXPR, $$); }
+ | primary MINUSMINUS
+ { if (TREE_CODE ($$) == OFFSET_REF)
+ $$ = resolve_offset_ref ($$);
+ $$ = build_x_unary_op (POSTDECREMENT_EXPR, $$); }
+ /* C++ extensions */
+ | THIS
+ { if (current_class_decl)
+ {
+#ifdef WARNING_ABOUT_CCD
+ TREE_USED (current_class_decl) = 1;
+#endif
+ $$ = current_class_decl;
+ }
+ else if (current_function_decl
+ && DECL_STATIC_FUNCTION_P (current_function_decl))
+ {
+ error ("`this' is unavailable for static member functions");
+ $$ = error_mark_node;
+ }
+ else
+ {
+ if (current_function_decl)
+ error ("invalid use of `this' in non-member function");
+ else
+ error ("invalid use of `this' at top level");
+ $$ = error_mark_node;
+ }
+ }
+ | TYPE_QUAL '(' nonnull_exprlist ')'
+ {
+ tree type;
+ tree id = $$;
+
+ /* This is a C cast in C++'s `functional' notation. */
+ if ($3 == error_mark_node)
+ {
+ $$ = error_mark_node;
+ break;
+ }
+#if 0
+ if ($3 == NULL_TREE)
+ {
+ error ("cannot cast null list to type `%s'",
+ IDENTIFIER_POINTER (TYPE_NAME (id)));
+ $$ = error_mark_node;
+ break;
+ }
+#endif
+#if 0
+ /* type is not set! (mrs) */
+ if (type == error_mark_node)
+ $$ = error_mark_node;
+ else
+#endif
+ {
+ if (id == ridpointers[(int) RID_CONST])
+ type = build_type_variant (integer_type_node, 1, 0);
+ else if (id == ridpointers[(int) RID_VOLATILE])
+ type = build_type_variant (integer_type_node, 0, 1);
+#if 0
+ /* should not be able to get here (mrs) */
+ else if (id == ridpointers[(int) RID_FRIEND])
+ {
+ error ("cannot cast expression to `friend' type");
+ $$ = error_mark_node;
+ break;
+ }
+#endif
+ else my_friendly_abort (79);
+ $$ = build_c_cast (type, build_compound_expr ($3));
+ }
+ }
+ | functional_cast
+ | DYNAMIC_CAST '<' type_id '>' '(' expr ')'
+ { tree type = groktypename ($3);
+ $$ = build_dynamic_cast (type, $6); }
+ | STATIC_CAST '<' type_id '>' '(' expr ')'
+ { tree type = groktypename ($3);
+ $$ = build_static_cast (type, $6); }
+ | REINTERPRET_CAST '<' type_id '>' '(' expr ')'
+ { tree type = groktypename ($3);
+ $$ = build_reinterpret_cast (type, $6); }
+ | CONST_CAST '<' type_id '>' '(' expr ')'
+ { tree type = groktypename ($3);
+ $$ = build_const_cast (type, $6); }
+ | TYPEID '(' expr ')'
+ { $$ = build_typeid ($3); }
+ | TYPEID '(' type_id ')'
+ { tree type = groktypename ($3);
+ $$ = get_typeid (type); }
+ | global_scope IDENTIFIER
+ {
+ do_scoped_id:
+ $$ = IDENTIFIER_GLOBAL_VALUE ($2);
+ if (yychar == YYEMPTY)
+ yychar = YYLEX;
+ if (! $$)
+ {
+ if (yychar == '(' || yychar == LEFT_RIGHT)
+ $$ = implicitly_declare ($2);
+ else
+ {
+ if (IDENTIFIER_GLOBAL_VALUE ($2) != error_mark_node)
+ error ("undeclared variable `%s' (first use here)",
+ IDENTIFIER_POINTER ($2));
+ $$ = error_mark_node;
+ /* Prevent repeated error messages. */
+ IDENTIFIER_GLOBAL_VALUE ($2) = error_mark_node;
+ }
+ }
+ else
+ {
+ if (TREE_CODE ($$) == ADDR_EXPR)
+ assemble_external (TREE_OPERAND ($$, 0));
+ else
+ assemble_external ($$);
+ TREE_USED ($$) = 1;
+ }
+ if (TREE_CODE ($$) == CONST_DECL)
+ {
+ /* XXX CHS - should we set TREE_USED of the constant? */
+ $$ = DECL_INITIAL ($$);
+ /* This is to prevent an enum whose value is 0
+ from being considered a null pointer constant. */
+ $$ = build1 (NOP_EXPR, TREE_TYPE ($$), $$);
+ TREE_CONSTANT ($$) = 1;
+ }
+
+ }
+ | global_scope operator_name
+ {
+ got_scope = NULL_TREE;
+ if (TREE_CODE ($2) == IDENTIFIER_NODE)
+ goto do_scoped_id;
+ $$ = $2;
+ }
+ | overqualified_id %prec HYPERUNARY
+ { $$ = build_offset_ref (OP0 ($$), OP1 ($$)); }
+ | overqualified_id '(' nonnull_exprlist ')'
+ { $$ = build_member_call (OP0 ($$), OP1 ($$), $3); }
+ | overqualified_id LEFT_RIGHT
+ { $$ = build_member_call (OP0 ($$), OP1 ($$), NULL_TREE); }
+ | object unqualified_id %prec UNARY
+ { $$ = build_component_ref ($$, $2, NULL_TREE, 1); }
+ | object qualified_id %prec UNARY
+ { $$ = build_object_ref ($$, OP0 ($2), OP1 ($2)); }
+ | object unqualified_id '(' nonnull_exprlist ')'
+ {
+#if 0
+ /* This is a future direction of this code, but because
+ build_x_function_call cannot always undo what is done
+ in build_component_ref entirely yet, we cannot do this. */
+ $$ = build_x_function_call (build_component_ref ($$, $2, NULL_TREE, 1), $4, $$);
+ if (TREE_CODE ($$) == CALL_EXPR
+ && TREE_TYPE ($$) != void_type_node)
+ $$ = require_complete_type ($$);
+#else
+ $$ = build_method_call ($$, $2, $4, NULL_TREE,
+ (LOOKUP_NORMAL|LOOKUP_AGGR));
+#endif
+ }
+ | object unqualified_id LEFT_RIGHT
+ {
+#if 0
+ /* This is a future direction of this code, but because
+ build_x_function_call cannot always undo what is done
+ in build_component_ref entirely yet, we cannot do this. */
+ $$ = build_x_function_call (build_component_ref ($$, $2, NULL_TREE, 1), NULL_TREE, $$);
+ if (TREE_CODE ($$) == CALL_EXPR
+ && TREE_TYPE ($$) != void_type_node)
+ $$ = require_complete_type ($$);
+#else
+ $$ = build_method_call ($$, $2, NULL_TREE, NULL_TREE,
+ (LOOKUP_NORMAL|LOOKUP_AGGR));
+#endif
+ }
+ | object qualified_id '(' nonnull_exprlist ')'
+ {
+ if (IS_SIGNATURE (IDENTIFIER_TYPE_VALUE (OP0 ($2))))
+ {
+ warning ("signature name in scope resolution ignored");
+ $$ = build_method_call ($$, OP1 ($2), $4, NULL_TREE,
+ (LOOKUP_NORMAL|LOOKUP_AGGR));
+ }
+ else
+ $$ = build_scoped_method_call ($$, OP0 ($2), OP1 ($2), $4);
+ }
+ | object qualified_id LEFT_RIGHT
+ {
+ if (IS_SIGNATURE (IDENTIFIER_TYPE_VALUE (OP0 ($2))))
+ {
+ warning ("signature name in scope resolution ignored");
+ $$ = build_method_call ($$, OP1 ($2), NULL_TREE, NULL_TREE,
+ (LOOKUP_NORMAL|LOOKUP_AGGR));
+ }
+ else
+ $$ = build_scoped_method_call ($$, OP0 ($2), OP1 ($2), NULL_TREE);
+ }
+ /* p->int::~int() is valid -- 12.4 */
+ | object '~' TYPESPEC LEFT_RIGHT
+ {
+ if (TREE_CODE (TREE_TYPE ($1))
+ != TREE_CODE (TREE_TYPE (IDENTIFIER_GLOBAL_VALUE ($3))))
+ cp_error ("`%E' is not of type `%T'", $1, $3);
+ $$ = convert (void_type_node, $1);
+ }
+ | object TYPESPEC SCOPE '~' TYPESPEC LEFT_RIGHT
+ {
+ if ($2 != $5)
+ cp_error ("destructor specifier `%T::~%T()' must have matching names", $2, $5);
+ if (TREE_CODE (TREE_TYPE ($1))
+ != TREE_CODE (TREE_TYPE (IDENTIFIER_GLOBAL_VALUE ($2))))
+ cp_error ("`%E' is not of type `%T'", $1, $2);
+ $$ = convert (void_type_node, $1);
+ }
+ ;
+
+/* Not needed for now.
+
+primary_no_id:
+ '(' expr ')'
+ { $$ = $2; }
+ | '(' error ')'
+ { $$ = error_mark_node; }
+ | '('
+ { if (current_function_decl == 0)
+ {
+ error ("braced-group within expression allowed only inside a function");
+ YYERROR;
+ }
+ $<ttype>$ = expand_start_stmt_expr (); }
+ compstmt ')'
+ { if (flag_ansi)
+ pedwarn ("ANSI C++ forbids braced-groups within expressions");
+ $$ = expand_end_stmt_expr ($<ttype>2); }
+ | primary_no_id '(' nonnull_exprlist ')'
+ { $$ = build_x_function_call ($$, $3, current_class_decl); }
+ | primary_no_id LEFT_RIGHT
+ { $$ = build_x_function_call ($$, NULL_TREE, current_class_decl); }
+ | primary_no_id '[' expr ']'
+ { goto do_array; }
+ | primary_no_id PLUSPLUS
+ { $$ = build_x_unary_op (POSTINCREMENT_EXPR, $$); }
+ | primary_no_id MINUSMINUS
+ { $$ = build_x_unary_op (POSTDECREMENT_EXPR, $$); }
+ | SCOPE IDENTIFIER
+ { goto do_scoped_id; }
+ | SCOPE operator_name
+ { if (TREE_CODE ($2) == IDENTIFIER_NODE)
+ goto do_scoped_id;
+ goto do_scoped_operator;
+ }
+ ;
+*/
+
+new: NEW
+ { $$ = 0; }
+ | global_scope NEW
+ { got_scope = NULL_TREE; $$ = 1; }
+ ;
+
+delete: DELETE
+ { $$ = 0; }
+ | global_scope delete
+ { got_scope = NULL_TREE; $$ = 1; }
+ ;
+
+boolean.literal:
+ CXX_TRUE
+ { $$ = true_node; }
+ | CXX_FALSE
+ { $$ = false_node; }
+ ;
+
+/* Produces a STRING_CST with perhaps more STRING_CSTs chained onto it. */
+string:
+ STRING
+ | string STRING
+ { $$ = chainon ($$, $2); }
+ ;
+
+nodecls:
+ /* empty */
+ {
+ if (! current_function_parms_stored)
+ store_parm_decls ();
+ setup_vtbl_ptr ();
+ /* Always keep the BLOCK node associated with the outermost
+ pair of curley braces of a function. These are needed
+ for correct operation of dwarfout.c. */
+ keep_next_level ();
+ }
+ ;
+
+object: primary '.'
+ | primary POINTSAT
+ {
+ $$ = build_x_arrow ($$);
+ }
+ ;
+
+decl:
+ /* Normal case: make this fast. */
+ typespec declarator ';'
+ { tree d = get_decl_list ($1);
+ int yes = suspend_momentary ();
+ d = start_decl ($2, d, 0, NULL_TREE);
+ finish_decl (d, NULL_TREE, NULL_TREE, 0);
+ resume_momentary (yes);
+ if (IS_AGGR_TYPE_CODE (TREE_CODE ($1)))
+ note_got_semicolon ($1);
+ }
+ | typed_declspecs declarator ';'
+ { tree d = $1;
+ int yes = suspend_momentary ();
+ d = start_decl ($2, d, 0, NULL_TREE);
+ finish_decl (d, NULL_TREE, NULL_TREE, 0);
+ resume_momentary (yes);
+ note_list_got_semicolon ($1);
+ }
+ | typespec initdecls ';'
+ {
+ resume_momentary ($2);
+ if (IS_AGGR_TYPE_CODE (TREE_CODE ($1)))
+ note_got_semicolon ($1);
+ }
+ | typed_declspecs initdecls ';'
+ {
+ resume_momentary ($2);
+ note_list_got_semicolon ($1);
+ }
+ | declmods notype_initdecls ';'
+ { resume_momentary ($2); }
+ | typed_declspecs ';'
+ {
+ shadow_tag ($1);
+ note_list_got_semicolon ($1);
+ }
+ | declmods ';'
+ { warning ("empty declaration"); }
+ ;
+
+/* Any kind of declarator (thus, all declarators allowed
+ after an explicit typespec). */
+
+declarator:
+ after_type_declarator %prec EMPTY
+ | notype_declarator %prec EMPTY
+ ;
+
+/* This is necessary to postpone reduction of `int()()()()'. */
+fcast_or_absdcl:
+ LEFT_RIGHT %prec EMPTY
+ { $$ = build_parse_node (CALL_EXPR, NULL_TREE, empty_parms (),
+ NULL_TREE); }
+ | fcast_or_absdcl LEFT_RIGHT %prec EMPTY
+ { $$ = build_parse_node (CALL_EXPR, $$, empty_parms (),
+ NULL_TREE); }
+ ;
+
+/* ANSI type-id (8.1) */
+type_id:
+ typed_typespecs absdcl
+ { $$ = build_decl_list ($$, $2); }
+ | nonempty_type_quals absdcl
+ { $$ = build_decl_list ($$, $2); }
+ | typespec absdcl
+ { $$ = build_decl_list (get_decl_list ($$), $2); }
+ | typed_typespecs %prec EMPTY
+ { $$ = build_decl_list ($$, NULL_TREE); }
+ | nonempty_type_quals %prec EMPTY
+ { $$ = build_decl_list ($$, NULL_TREE); }
+ ;
+
+/* Declspecs which contain at least one type specifier or typedef name.
+ (Just `const' or `volatile' is not enough.)
+ A typedef'd name following these is taken as a name to be declared. */
+
+typed_declspecs:
+ typed_typespecs %prec EMPTY
+ | typed_declspecs1
+
+typed_declspecs1:
+ declmods typespec
+ { $$ = decl_tree_cons (NULL_TREE, $2, $$); }
+ | typespec reserved_declspecs %prec HYPERUNARY
+ { $$ = decl_tree_cons (NULL_TREE, $$, $2); }
+ | declmods typespec reserved_declspecs
+ { $$ = decl_tree_cons (NULL_TREE, $2, chainon ($3, $$)); }
+ | declmods typespec reserved_typespecquals
+ { $$ = decl_tree_cons (NULL_TREE, $2, chainon ($3, $$)); }
+ | declmods typespec reserved_typespecquals reserved_declspecs
+ { $$ = decl_tree_cons (NULL_TREE, $2,
+ chainon ($3, chainon ($4, $$))); }
+ ;
+
+reserved_declspecs:
+ SCSPEC
+ { if (extra_warnings)
+ warning ("`%s' is not at beginning of declaration",
+ IDENTIFIER_POINTER ($$));
+ $$ = build_decl_list (NULL_TREE, $$); }
+ | reserved_declspecs typespecqual_reserved
+ { $$ = decl_tree_cons (NULL_TREE, $2, $$); }
+ | reserved_declspecs SCSPEC
+ { if (extra_warnings)
+ warning ("`%s' is not at beginning of declaration",
+ IDENTIFIER_POINTER ($2));
+ $$ = decl_tree_cons (NULL_TREE, $2, $$); }
+ ;
+
+/* List of just storage classes and type modifiers.
+ A declaration can start with just this, but then it cannot be used
+ to redeclare a typedef-name. */
+
+declmods:
+ nonempty_type_quals %prec EMPTY
+ { TREE_STATIC ($$) = 1; }
+ | SCSPEC
+ { $$ = IDENTIFIER_AS_LIST ($$); }
+ | declmods TYPE_QUAL
+ { $$ = decl_tree_cons (NULL_TREE, $2, $$);
+ TREE_STATIC ($$) = 1; }
+ | declmods SCSPEC
+ { if (extra_warnings && TREE_STATIC ($$))
+ warning ("`%s' is not at beginning of declaration",
+ IDENTIFIER_POINTER ($2));
+ $$ = decl_tree_cons (NULL_TREE, $2, $$);
+ TREE_STATIC ($$) = TREE_STATIC ($1); }
+ ;
+
+
+/* Used instead of declspecs where storage classes are not allowed
+ (that is, for typenames and structure components).
+
+ C++ can takes storage classes for structure components.
+ Don't accept a typedef-name if anything but a modifier precedes it. */
+
+typed_typespecs:
+ typespec %prec EMPTY
+ { $$ = get_decl_list ($$); }
+ | nonempty_type_quals typespec
+ { $$ = decl_tree_cons (NULL_TREE, $2, $$); }
+ | typespec reserved_typespecquals
+ { $$ = decl_tree_cons (NULL_TREE, $$, $2); }
+ | nonempty_type_quals typespec reserved_typespecquals
+ { $$ = decl_tree_cons (NULL_TREE, $2, chainon ($3, $$)); }
+ ;
+
+reserved_typespecquals:
+ typespecqual_reserved
+ { $$ = build_decl_list (NULL_TREE, $$); }
+ | reserved_typespecquals typespecqual_reserved
+ { $$ = decl_tree_cons (NULL_TREE, $2, $$); }
+ ;
+
+/* A typespec (but not a type qualifier).
+ Once we have seen one of these in a declaration,
+ if a typedef name appears then it is being redeclared. */
+
+typespec: structsp
+ | TYPESPEC %prec EMPTY
+ | complete_type_name
+ | TYPEOF '(' expr ')'
+ { $$ = TREE_TYPE ($3);
+ if (flag_ansi)
+ pedwarn ("ANSI C++ forbids `typeof'"); }
+ | TYPEOF '(' type_id ')'
+ { $$ = groktypename ($3);
+ if (flag_ansi)
+ pedwarn ("ANSI C++ forbids `typeof'"); }
+ | SIGOF '(' expr ')'
+ { tree type = TREE_TYPE ($3);
+
+ if (IS_AGGR_TYPE (type))
+ {
+ sorry ("sigof type specifier");
+ $$ = type;
+ }
+ else
+ {
+ error ("`sigof' applied to non-aggregate expression");
+ $$ = error_mark_node;
+ }
+ }
+ | SIGOF '(' type_id ')'
+ { tree type = groktypename ($3);
+
+ if (IS_AGGR_TYPE (type))
+ {
+ sorry ("sigof type specifier");
+ $$ = type;
+ }
+ else
+ {
+ error("`sigof' applied to non-aggregate type");
+ $$ = error_mark_node;
+ }
+ }
+ ;
+
+/* A typespec that is a reserved word, or a type qualifier. */
+
+typespecqual_reserved: TYPESPEC
+ | TYPE_QUAL
+ | structsp
+ ;
+
+initdecls:
+ initdcl0
+ | initdecls ',' initdcl
+ ;
+
+notype_initdecls:
+ notype_initdcl0
+ | notype_initdecls ',' initdcl
+ ;
+
+nomods_initdecls:
+ nomods_initdcl0
+ | nomods_initdecls ',' initdcl
+ ;
+
+maybeasm:
+ /* empty */
+ { $$ = NULL_TREE; }
+ | asm_keyword '(' string ')'
+ { if (TREE_CHAIN ($3)) $3 = combine_strings ($3); $$ = $3; }
+ ;
+
+initdcl0:
+ declarator maybe_raises maybeasm maybe_attribute '='
+ { current_declspecs = $<ttype>0;
+ if (TREE_CODE (current_declspecs) != TREE_LIST)
+ current_declspecs = get_decl_list (current_declspecs);
+ if (have_extern_spec && !used_extern_spec)
+ {
+ current_declspecs = decl_tree_cons
+ (NULL_TREE, get_identifier ("extern"),
+ current_declspecs);
+ used_extern_spec = 1;
+ }
+ $<itype>5 = suspend_momentary ();
+ $<ttype>$ = start_decl ($<ttype>1, current_declspecs, 1, $2);
+ cplus_decl_attributes ($<ttype>$, $4); }
+ init
+/* Note how the declaration of the variable is in effect while its init is parsed! */
+ { finish_decl ($<ttype>6, $7, $3, 0);
+ $$ = $<itype>5; }
+ | declarator maybe_raises maybeasm maybe_attribute
+ { tree d;
+ current_declspecs = $<ttype>0;
+ if (TREE_CODE (current_declspecs) != TREE_LIST)
+ current_declspecs = get_decl_list (current_declspecs);
+ if (have_extern_spec && !used_extern_spec)
+ {
+ current_declspecs = decl_tree_cons
+ (NULL_TREE, get_identifier ("extern"),
+ current_declspecs);
+ used_extern_spec = 1;
+ }
+ $$ = suspend_momentary ();
+ d = start_decl ($<ttype>1, current_declspecs, 0, $2);
+ cplus_decl_attributes (d, $4);
+ finish_decl (d, NULL_TREE, $3, 0); }
+ ;
+
+initdcl:
+ declarator maybe_raises maybeasm maybe_attribute '='
+ { $<ttype>$ = start_decl ($<ttype>1, current_declspecs, 1, $2);
+ cplus_decl_attributes ($<ttype>$, $4); }
+ init
+/* Note how the declaration of the variable is in effect while its init is parsed! */
+ { finish_decl ($<ttype>6, $7, $3, 0); }
+ | declarator maybe_raises maybeasm maybe_attribute
+ { $<ttype>$ = start_decl ($<ttype>1, current_declspecs, 0, $2);
+ cplus_decl_attributes ($<ttype>$, $4);
+ finish_decl ($<ttype>$, NULL_TREE, $3, 0); }
+ ;
+
+notype_initdcl0:
+ notype_declarator maybe_raises maybeasm maybe_attribute '='
+ { current_declspecs = $<ttype>0;
+ $<itype>5 = suspend_momentary ();
+ $<ttype>$ = start_decl ($<ttype>1, current_declspecs, 1, $2);
+ cplus_decl_attributes ($<ttype>$, $4); }
+ init
+/* Note how the declaration of the variable is in effect while its init is parsed! */
+ { finish_decl ($<ttype>6, $7, $3, 0);
+ $$ = $<itype>5; }
+ | notype_declarator maybe_raises maybeasm maybe_attribute
+ { tree d;
+ current_declspecs = $<ttype>0;
+ $$ = suspend_momentary ();
+ d = start_decl ($<ttype>1, current_declspecs, 0, $2);
+ cplus_decl_attributes (d, $4);
+ finish_decl (d, NULL_TREE, $3, 0); }
+ ;
+
+nomods_initdcl0:
+ notype_declarator maybe_raises maybeasm maybe_attribute '='
+ { current_declspecs = NULL_TREE;
+ $<itype>5 = suspend_momentary ();
+ $<ttype>$ = start_decl ($1, current_declspecs, 1, $2);
+ cplus_decl_attributes ($<ttype>$, $4); }
+ init
+/* Note how the declaration of the variable is in effect while its init is parsed! */
+ { finish_decl ($<ttype>6, $7, $3, 0);
+ $$ = $<itype>5; }
+ | notype_declarator maybe_raises maybeasm maybe_attribute
+ { tree d;
+ current_declspecs = NULL_TREE;
+ $$ = suspend_momentary ();
+ d = start_decl ($1, current_declspecs, 0, $2);
+ cplus_decl_attributes (d, $4);
+ finish_decl (d, NULL_TREE, $3, 0); }
+ ;
+
+/* the * rules are dummies to accept the Apollo extended syntax
+ so that the header files compile. */
+maybe_attribute:
+ /* empty */
+ { $$ = NULL_TREE; }
+ | attributes
+ { $$ = $1; }
+ ;
+
+attributes:
+ attribute
+ { $$ = $1; }
+ | attributes attribute
+ { $$ = chainon ($1, $2); }
+ ;
+
+attribute:
+ ATTRIBUTE '(' '(' attribute_list ')' ')'
+ { $$ = $4; }
+ ;
+
+attribute_list:
+ attrib
+ { $$ = build_tree_list (NULL_TREE, $1); }
+ | attribute_list ',' attrib
+ { $$ = chainon ($1, build_tree_list (NULL_TREE, $3)); }
+ ;
+
+attrib:
+ /* empty */
+ { $$ = NULL_TREE; }
+ | any_word
+ { $$ = $1; }
+ | any_word '(' IDENTIFIER ')'
+ { $$ = tree_cons ($1, NULL_TREE, build_tree_list (NULL_TREE, $3)); }
+ | any_word '(' IDENTIFIER ',' nonnull_exprlist ')'
+ { $$ = tree_cons ($1, NULL_TREE, tree_cons (NULL_TREE, $3, $5)); }
+ | any_word '(' nonnull_exprlist ')'
+ { $$ = tree_cons ($1, NULL_TREE, $3); }
+ ;
+
+/* This still leaves out most reserved keywords,
+ shouldn't we include them? */
+
+any_word:
+ identifier
+ | SCSPEC
+ | TYPESPEC
+ | TYPE_QUAL
+ ;
+
+/* A nonempty list of identifiers, including typenames. */
+identifiers_or_typenames:
+ identifier
+ { $$ = build_tree_list (NULL_TREE, $1); }
+ | identifiers_or_typenames ',' identifier
+ { $$ = chainon ($1, build_tree_list (NULL_TREE, $3)); }
+ ;
+
+init:
+ expr_no_commas %prec '='
+ | '{' '}'
+ { $$ = build_nt (CONSTRUCTOR, NULL_TREE, NULL_TREE);
+ TREE_HAS_CONSTRUCTOR ($$) = 1; }
+ | '{' initlist '}'
+ { $$ = build_nt (CONSTRUCTOR, NULL_TREE, nreverse ($2));
+ TREE_HAS_CONSTRUCTOR ($$) = 1; }
+ | '{' initlist ',' '}'
+ { $$ = build_nt (CONSTRUCTOR, NULL_TREE, nreverse ($2));
+ TREE_HAS_CONSTRUCTOR ($$) = 1; }
+ | error
+ { $$ = NULL_TREE; }
+ ;
+
+/* This chain is built in reverse order,
+ and put in forward order where initlist is used. */
+initlist:
+ init
+ { $$ = build_tree_list (NULL_TREE, $$); }
+ | initlist ',' init
+ { $$ = tree_cons (NULL_TREE, $3, $$); }
+ /* These are for labeled elements. */
+ | '[' expr_no_commas ']' init
+ { $$ = build_tree_list ($2, $4); }
+ | initlist ',' CASE expr_no_commas ':' init
+ { $$ = tree_cons ($4, $6, $$); }
+ | identifier ':' init
+ { $$ = build_tree_list ($$, $3); }
+ | initlist ',' identifier ':' init
+ { $$ = tree_cons ($3, $5, $$); }
+ ;
+
+structsp:
+ ENUM identifier '{'
+ { $<itype>3 = suspend_momentary ();
+ $$ = start_enum ($2); }
+ enumlist maybecomma_warn '}'
+ { $$ = finish_enum ($<ttype>4, $5);
+ resume_momentary ((int) $<itype>3);
+ check_for_missing_semicolon ($<ttype>4); }
+ | ENUM identifier '{' '}'
+ { $$ = finish_enum (start_enum ($2), NULL_TREE);
+ check_for_missing_semicolon ($$); }
+ | ENUM '{'
+ { $<itype>2 = suspend_momentary ();
+ $$ = start_enum (make_anon_name ()); }
+ enumlist maybecomma_warn '}'
+ { $$ = finish_enum ($<ttype>3, $4);
+ resume_momentary ((int) $<itype>1);
+ check_for_missing_semicolon ($<ttype>3); }
+ | ENUM '{' '}'
+ { $$ = finish_enum (start_enum (make_anon_name()), NULL_TREE);
+ check_for_missing_semicolon ($$); }
+ | ENUM identifier
+ { $$ = xref_tag (enum_type_node, $2, NULL_TREE, 0); }
+ | ENUM complex_type_name
+ { $$ = xref_tag (enum_type_node, $2, NULL_TREE, 0); }
+
+ /* C++ extensions, merged with C to avoid shift/reduce conflicts */
+ | class_head left_curly opt.component_decl_list '}'
+ {
+ int semi;
+ tree id;
+
+#if 0
+ /* Need to rework class nesting in the
+ presence of nested classes, etc. */
+ shadow_tag (CLASSTYPE_AS_LIST ($$)); */
+#endif
+ if (yychar == YYEMPTY)
+ yychar = YYLEX;
+ semi = yychar == ';';
+ /* finish_struct nukes this anyway; if
+ finish_exception does too, then it can go. */
+ if (semi)
+ note_got_semicolon ($$);
+
+ if (TREE_CODE ($$) == ENUMERAL_TYPE)
+ /* $$ = $1 from default rule. */;
+ else if (CLASSTYPE_DECLARED_EXCEPTION ($$))
+ {
+ }
+ else
+ {
+ $$ = finish_struct ($$, $3, semi);
+ if (semi) note_got_semicolon ($$);
+ }
+
+ pop_obstacks ();
+
+ id = TYPE_IDENTIFIER ($$);
+ if (id && IDENTIFIER_TEMPLATE (id))
+ {
+ tree decl;
+
+ /* I don't know if the copying of this TYPE_DECL is
+ * really needed. However, it's such a small per-
+ * formance penalty that the extra safety is a bargain.
+ * - niklas@appli.se
+ */
+ push_obstacks (&permanent_obstack, &permanent_obstack);
+ decl = copy_node (lookup_name (id, 0));
+ if (DECL_LANG_SPECIFIC (decl))
+ copy_lang_decl (decl);
+ pop_obstacks ();
+ undo_template_name_overload (id, 0);
+ pushdecl_top_level (decl);
+ }
+ if (! semi)
+ check_for_missing_semicolon ($$); }
+ | class_head %prec EMPTY
+ {
+#if 0
+ /* It's no longer clear what the following error is supposed to
+ accomplish. If it turns out to be needed, add a comment why. */
+ if (TYPE_BINFO_BASETYPES ($$) && !TYPE_SIZE ($$))
+ {
+ error ("incomplete definition of type `%s'",
+ TYPE_NAME_STRING ($$));
+ $$ = error_mark_node;
+ }
+#endif
+ }
+ ;
+
+maybecomma:
+ /* empty */
+ | ','
+ ;
+
+maybecomma_warn:
+ /* empty */
+ | ','
+ { if (pedantic) pedwarn ("comma at end of enumerator list"); }
+ ;
+
+aggr: AGGR
+ | aggr SCSPEC
+ { error ("storage class specifier `%s' not allowed after struct or class", IDENTIFIER_POINTER ($2)); }
+ | aggr TYPESPEC
+ { error ("type specifier `%s' not allowed after struct or class", IDENTIFIER_POINTER ($2)); }
+ | aggr TYPE_QUAL
+ { error ("type qualifier `%s' not allowed after struct or class", IDENTIFIER_POINTER ($2)); }
+ | aggr AGGR
+ { error ("no body nor ';' separates two class, struct or union declarations"); }
+ ;
+
+specialization:
+ aggr template_type_name ';'
+ {
+ yyungetc (';', 1); current_aggr = $$; $$ = $2;
+ if ($<ttype>0 == ridpointers[(int) RID_TEMPLATE])
+ instantiate_class_template ($$, 2);
+ }
+ ;
+
+named_class_head_sans_basetype:
+ aggr identifier
+ { current_aggr = $$; $$ = $2; }
+ | aggr complex_type_name
+ { current_aggr = $$; $$ = $2; }
+ | aggr template_type %prec EMPTY
+ { current_aggr = $$; $$ = $2; }
+ | aggr template_type_name '{'
+ { yyungetc ('{', 1);
+ aggr2:
+ current_aggr = $$;
+ $$ = $2;
+ overload_template_name ($$, 0); }
+ | aggr template_type_name ':'
+ { yyungetc (':', 1); goto aggr2; }
+ | specialization
+ ;
+
+named_class_head_sans_basetype_defn:
+ aggr identifier_defn %prec EMPTY
+ { current_aggr = $$; $$ = $2; }
+ ;
+
+do_xref: /* empty */ %prec EMPTY
+ { $<ttype>$ = xref_tag (current_aggr, $<ttype>0, NULL_TREE, 1); }
+
+do_xref_defn: /* empty */ %prec EMPTY
+ { $<ttype>$ = xref_defn_tag (current_aggr, $<ttype>0, NULL_TREE); }
+
+named_class_head:
+ named_class_head_sans_basetype do_xref
+ maybe_base_class_list %prec EMPTY
+ {
+ if ($3)
+ $$ = xref_tag (current_aggr, $1, $3, 1);
+ else
+ $$ = $<ttype>2;
+ }
+ |
+ named_class_head_sans_basetype_defn do_xref_defn
+ maybe_base_class_list %prec EMPTY
+ {
+ if ($3)
+ $$ = xref_defn_tag (current_aggr, $1, $3);
+ else
+ $$ = $<ttype>2;
+ }
+ ;
+
+unnamed_class_head: aggr '{'
+ { $$ = xref_tag ($$, make_anon_name (), NULL_TREE, 0);
+ yyungetc ('{', 1); }
+ ;
+
+class_head: unnamed_class_head | named_class_head ;
+
+maybe_base_class_list:
+ %prec EMPTY /* empty */
+ { $$ = NULL_TREE; }
+ | ':' %prec EMPTY
+ { yyungetc(':', 1); $$ = NULL_TREE; }
+ | ':' base_class_list %prec EMPTY
+ { $$ = $2; }
+ ;
+
+base_class_list:
+ base_class
+ | base_class_list ',' base_class
+ { $$ = chainon ($$, $3); }
+ ;
+
+base_class:
+ base_class.1
+ {
+ tree type;
+ do_base_class1:
+ type = IDENTIFIER_TYPE_VALUE ($$);
+ if (! is_aggr_typedef ($$, 1))
+ $$ = NULL_TREE;
+ else if (current_aggr == signature_type_node
+ && (! type) && (! IS_SIGNATURE (type)))
+ {
+ error ("class name not allowed as base signature");
+ $$ = NULL_TREE;
+ }
+ else if (current_aggr == signature_type_node)
+ {
+ sorry ("signature inheritance, base type `%s' ignored",
+ IDENTIFIER_POINTER ($$));
+ $$ = build_tree_list ((tree)access_public, $$);
+ }
+ else if (type && IS_SIGNATURE (type))
+ {
+ error ("signature name not allowed as base class");
+ $$ = NULL_TREE;
+ }
+ else
+ $$ = build_tree_list ((tree)access_default, $$);
+ }
+ | base_class_access_list base_class.1
+ {
+ tree type;
+ do_base_class2:
+ type = IDENTIFIER_TYPE_VALUE ($2);
+ if (current_aggr == signature_type_node)
+ error ("access and source specifiers not allowed in signature");
+ if (! is_aggr_typedef ($2, 1))
+ $$ = NULL_TREE;
+ else if (current_aggr == signature_type_node
+ && (! type) && (! IS_SIGNATURE (type)))
+ {
+ error ("class name not allowed as base signature");
+ $$ = NULL_TREE;
+ }
+ else if (current_aggr == signature_type_node)
+ {
+ sorry ("signature inheritance, base type `%s' ignored",
+ IDENTIFIER_POINTER ($$));
+ $$ = build_tree_list ((tree)access_public, $2);
+ }
+ else if (type && IS_SIGNATURE (type))
+ {
+ error ("signature name not allowed as base class");
+ $$ = NULL_TREE;
+ }
+ else
+ $$ = build_tree_list ((tree) $$, $2);
+ }
+ ;
+
+base_class.1:
+ complete_type_name
+ | SIGOF '(' expr ')'
+ {
+ if (current_aggr == signature_type_node)
+ {
+ if (IS_AGGR_TYPE (TREE_TYPE ($3)))
+ {
+ sorry ("`sigof' as base signature specifier");
+ /* need to return some dummy signature identifier */
+ $$ = $3;
+ }
+ else
+ {
+ error ("`sigof' applied to non-aggregate expression");
+ $$ = error_mark_node;
+ }
+ }
+ else
+ {
+ error ("`sigof' in struct or class declaration");
+ $$ = error_mark_node;
+ }
+ }
+ | SIGOF '(' type_id ')'
+ {
+ if (current_aggr == signature_type_node)
+ {
+ if (IS_AGGR_TYPE (groktypename ($3)))
+ {
+ sorry ("`sigof' as base signature specifier");
+ /* need to return some dummy signature identifier */
+ $$ = $3;
+ }
+ else
+ {
+ error ("`sigof' applied to non-aggregate expression");
+ $$ = error_mark_node;
+ }
+ }
+ else
+ {
+ error ("`sigof' in struct or class declaration");
+ $$ = error_mark_node;
+ }
+ }
+ ;
+
+base_class_access_list:
+ VISSPEC
+ | SCSPEC
+ { if ($<ttype>$ != ridpointers[(int)RID_VIRTUAL])
+ sorry ("non-virtual access");
+ $$ = access_default_virtual; }
+ | base_class_access_list VISSPEC
+ { int err = 0;
+ if ($2 == access_protected)
+ {
+ warning ("`protected' access not implemented");
+ $2 = access_public;
+ err++;
+ }
+ else if ($2 == access_public)
+ {
+ if ($1 == access_private)
+ {
+ mixed:
+ error ("base class cannot be public and private");
+ }
+ else if ($1 == access_default_virtual)
+ $$ = access_public_virtual;
+ }
+ else /* $2 == access_private */
+ {
+ if ($1 == access_public)
+ goto mixed;
+ else if ($1 == access_default_virtual)
+ $$ = access_private_virtual;
+ }
+ }
+ | base_class_access_list SCSPEC
+ { if ($2 != ridpointers[(int)RID_VIRTUAL])
+ sorry ("non-virtual access");
+ if ($$ == access_public)
+ $$ = access_public_virtual;
+ else if ($$ == access_private)
+ $$ = access_private_virtual; }
+ ;
+
+left_curly: '{'
+ { tree t = $<ttype>0;
+ push_obstacks_nochange ();
+ end_temporary_allocation ();
+
+ if (! IS_AGGR_TYPE (t))
+ {
+ t = $<ttype>0 = make_lang_type (RECORD_TYPE);
+ TYPE_NAME (t) = get_identifier ("erroneous type");
+ }
+ if (TYPE_SIZE (t))
+ duplicate_tag_error (t);
+ if (TYPE_SIZE (t) || TYPE_BEING_DEFINED (t))
+ {
+ t = make_lang_type (TREE_CODE (t));
+ pushtag (TYPE_IDENTIFIER ($<ttype>0), t, 0);
+ $<ttype>0 = t;
+ }
+ pushclass (t, 0);
+ TYPE_BEING_DEFINED (t) = 1;
+ /* Reset the interface data, at the earliest possible
+ moment, as it might have been set via a class foo;
+ before. */
+ /* Don't change signatures. */
+ if (! IS_SIGNATURE (t))
+ {
+ extern tree pending_vtables;
+ int needs_writing;
+ tree name = TYPE_IDENTIFIER (t);
+
+ CLASSTYPE_INTERFACE_ONLY (t) = interface_only;
+ SET_CLASSTYPE_INTERFACE_UNKNOWN_X (t, interface_unknown);
+
+ /* Record how to set the access of this class's
+ virtual functions. If write_virtuals == 2 or 3, then
+ inline virtuals are ``extern inline''. */
+ switch (write_virtuals)
+ {
+ case 0:
+ case 1:
+ needs_writing = 1;
+ break;
+ case 2:
+ needs_writing = !! value_member (name, pending_vtables);
+ break;
+ case 3:
+ needs_writing = ! CLASSTYPE_INTERFACE_ONLY (t)
+ && CLASSTYPE_INTERFACE_KNOWN (t);
+ break;
+ default:
+ needs_writing = 0;
+ }
+ CLASSTYPE_VTABLE_NEEDS_WRITING (t) = needs_writing;
+ }
+#if 0
+ t = TYPE_IDENTIFIER ($<ttype>0);
+ if (t && IDENTIFIER_TEMPLATE (t))
+ overload_template_name (t, 1);
+#endif
+ }
+ ;
+
+opt.component_decl_list:
+ /* empty */
+ { $$ = NULL_TREE; }
+ | component_decl_list
+ {
+ if (current_aggr == signature_type_node)
+ $$ = build_tree_list ((tree) access_public, $$);
+ else
+ $$ = build_tree_list ((tree) access_default, $$);
+ }
+ | opt.component_decl_list VISSPEC ':' component_decl_list
+ {
+ tree visspec = (tree) $2;
+
+ if (current_aggr == signature_type_node)
+ {
+ error ("access specifier not allowed in signature");
+ visspec = (tree) access_public;
+ }
+ $$ = chainon ($$, build_tree_list (visspec, $4));
+ }
+ | opt.component_decl_list VISSPEC ':'
+ {
+ if (current_aggr == signature_type_node)
+ error ("access specifier not allowed in signature");
+ }
+ ;
+
+/* Note: we no longer warn about the semicolon after a component_decl_list.
+ ARM $9.2 says that the semicolon is optional, and therefore allowed. */
+component_decl_list:
+ component_decl
+ { if ($$ == void_type_node) $$ = NULL_TREE;
+ }
+ | component_decl_list component_decl
+ { /* In pushdecl, we created a reverse list of names
+ in this binding level. Make sure that the chain
+ of what we're trying to add isn't the item itself
+ (which can happen with what pushdecl's doing). */
+ if ($2 != NULL_TREE && $2 != void_type_node)
+ {
+ if (TREE_CHAIN ($2) != $$)
+ $$ = chainon ($$, $2);
+ else
+ $$ = $2;
+ }
+ }
+ | component_decl_list ';'
+ ;
+
+component_decl:
+ component_decl_1 ';'
+ | component_decl_1 '}'
+ { error ("missing ';' before right brace");
+ yyungetc ('}', 0); }
+ /* C++: handle constructors, destructors and inline functions */
+ /* note that INLINE is like a TYPESPEC */
+ | fn.def2 ':' /* base_init compstmt */
+ { $$ = finish_method ($$); }
+ | fn.def2 '{' /* nodecls compstmt */
+ { $$ = finish_method ($$); }
+ ;
+
+component_decl_1:
+ /* Do not add a "typed_declspecs declarator" rule here for
+ speed; we need to call grok_x_components for enums, so the
+ speedup would be insignificant. */
+ typed_declspecs components
+ {
+ $$ = grok_x_components ($$, $2);
+ }
+ | declmods notype_components
+ {
+ $$ = grok_x_components ($$, $2);
+ }
+ | notype_declarator maybe_raises maybeasm maybe_attribute
+ { $$ = grokfield ($$, NULL_TREE, $2, NULL_TREE, $3);
+ cplus_decl_attributes ($$, $4); }
+ | ':' expr_no_commas
+ { $$ = grokbitfield (NULL_TREE, NULL_TREE, $2); }
+ | error
+ { $$ = NULL_TREE; }
+
+ /* These rules introduce a reduce/reduce conflict; in
+ typedef int foo, bar;
+ class A {
+ foo (bar);
+ };
+ should "A::foo" be declared as a function or "A::bar" as a data
+ member? In other words, is "bar" an after_type_declarator or a
+ parmlist? */
+ | typed_declspecs '(' parmlist ')' type_quals
+ { $$ = build_parse_node (CALL_EXPR, TREE_VALUE ($1),
+ $3, $5);
+ $$ = grokfield ($$, TREE_CHAIN ($1), NULL_TREE, NULL_TREE,
+ NULL_TREE); }
+ | typed_declspecs LEFT_RIGHT type_quals
+ { $$ = build_parse_node (CALL_EXPR, TREE_VALUE ($1),
+ empty_parms (), $3);
+ $$ = grokfield ($$, TREE_CHAIN ($1), NULL_TREE, NULL_TREE,
+ NULL_TREE); }
+ ;
+
+/* The case of exactly one component is handled directly by component_decl. */
+components:
+ /* empty: possibly anonymous */
+ { $$ = NULL_TREE; }
+ | component_declarator0
+ | components ',' component_declarator
+ {
+ /* In this context, void_type_node encodes
+ friends. They have been recorded elsewhere. */
+ if ($$ == void_type_node)
+ $$ = $3;
+ else
+ $$ = chainon ($$, $3);
+ }
+ ;
+
+notype_components:
+ /* empty: possibly anonymous */
+ { $$ = NULL_TREE; }
+ | notype_component_declarator0
+ | notype_components ',' notype_component_declarator
+ {
+ /* In this context, void_type_node encodes
+ friends. They have been recorded elsewhere. */
+ if ($$ == void_type_node)
+ $$ = $3;
+ else
+ $$ = chainon ($$, $3);
+ }
+ ;
+
+component_declarator0:
+ after_type_component_declarator0
+ | notype_component_declarator0
+ ;
+
+component_declarator:
+ after_type_component_declarator
+ | notype_component_declarator
+ ;
+
+after_type_component_declarator0:
+ after_type_declarator maybe_raises maybeasm maybe_attribute
+ { current_declspecs = $<ttype>0;
+ $$ = grokfield ($$, current_declspecs, $2, NULL_TREE, $3);
+ cplus_decl_attributes ($$, $4); }
+ | after_type_declarator maybe_raises maybeasm maybe_attribute '=' init
+ { current_declspecs = $<ttype>0;
+ $$ = grokfield ($$, current_declspecs, $2, $6, $3);
+ cplus_decl_attributes ($$, $4); }
+ | TYPENAME ':' expr_no_commas maybe_attribute
+ { current_declspecs = $<ttype>0;
+ $$ = grokbitfield ($$, current_declspecs, $3);
+ cplus_decl_attributes ($$, $4); }
+ ;
+
+notype_component_declarator0:
+ notype_declarator maybe_raises maybeasm maybe_attribute
+ { current_declspecs = $<ttype>0;
+ $$ = grokfield ($$, current_declspecs, $2, NULL_TREE, $3);
+ cplus_decl_attributes ($$, $4); }
+ | notype_declarator maybe_raises maybeasm maybe_attribute '=' init
+ { current_declspecs = $<ttype>0;
+ $$ = grokfield ($$, current_declspecs, $2, $6, $3);
+ cplus_decl_attributes ($$, $4); }
+ | IDENTIFIER ':' expr_no_commas maybe_attribute
+ { current_declspecs = $<ttype>0;
+ $$ = grokbitfield ($$, current_declspecs, $3);
+ cplus_decl_attributes ($$, $4); }
+ | ':' expr_no_commas maybe_attribute
+ { current_declspecs = $<ttype>0;
+ $$ = grokbitfield (NULL_TREE, current_declspecs, $2);
+ cplus_decl_attributes ($$, $3); }
+ ;
+
+after_type_component_declarator:
+ after_type_declarator maybe_raises maybeasm maybe_attribute
+ { $$ = grokfield ($$, current_declspecs, $2, NULL_TREE, $3);
+ cplus_decl_attributes ($$, $4); }
+ | after_type_declarator maybe_raises maybeasm maybe_attribute '=' init
+ { $$ = grokfield ($$, current_declspecs, $2, $6, $3);
+ cplus_decl_attributes ($$, $4); }
+ | TYPENAME ':' expr_no_commas maybe_attribute
+ { $$ = grokbitfield ($$, current_declspecs, $3);
+ cplus_decl_attributes ($$, $4); }
+ ;
+
+notype_component_declarator:
+ notype_declarator maybe_raises maybeasm maybe_attribute
+ { $$ = grokfield ($$, current_declspecs, $2, NULL_TREE, $3);
+ cplus_decl_attributes ($$, $4); }
+ | notype_declarator maybe_raises maybeasm maybe_attribute '=' init
+ { $$ = grokfield ($$, current_declspecs, $2, $6, $3);
+ cplus_decl_attributes ($$, $4); }
+ | IDENTIFIER ':' expr_no_commas maybe_attribute
+ { $$ = grokbitfield ($$, current_declspecs, $3);
+ cplus_decl_attributes ($$, $4); }
+ | ':' expr_no_commas maybe_attribute
+ { $$ = grokbitfield (NULL_TREE, current_declspecs, $2);
+ cplus_decl_attributes ($$, $3); }
+ ;
+
+/* We chain the enumerators in reverse order.
+ Because of the way enums are built, the order is
+ insignificant. Take advantage of this fact. */
+
+enumlist:
+ enumerator
+ | enumlist ',' enumerator
+ { TREE_CHAIN ($3) = $$; $$ = $3; }
+ ;
+
+enumerator:
+ identifier
+ { $$ = build_enumerator ($$, NULL_TREE); }
+ | identifier '=' expr_no_commas
+ { $$ = build_enumerator ($$, $3); }
+ ;
+
+/* ANSI new-type-id (5.3.4) */
+new_type_id:
+ type_specifier_seq new_declarator
+ { $$ = build_decl_list ($$, $2); }
+ | type_specifier_seq %prec EMPTY
+ { $$ = build_decl_list ($$, NULL_TREE); }
+ /* GNU extension to allow arrays of arbitrary types with
+ non-constant dimension. */
+ | '(' type_id ')' '[' expr ']'
+ {
+ if (flag_ansi)
+ pedwarn ("ANSI C++ forbids array dimensions with parenthesized type in new");
+ $$ = build_parse_node (ARRAY_REF, TREE_VALUE ($2), $5);
+ $$ = build_decl_list (TREE_PURPOSE ($2), $$);
+ }
+ ;
+
+type_quals:
+ /* empty */ %prec EMPTY
+ { $$ = NULL_TREE; }
+ | type_quals TYPE_QUAL
+ { $$ = decl_tree_cons (NULL_TREE, $2, $$); }
+ ;
+
+nonempty_type_quals:
+ TYPE_QUAL
+ { $$ = IDENTIFIER_AS_LIST ($$); }
+ | nonempty_type_quals TYPE_QUAL
+ { $$ = decl_tree_cons (NULL_TREE, $2, $$); }
+ ;
+
+/* These rules must follow the rules for function declarations
+ and component declarations. That way, longer rules are preferred. */
+
+/* An expression which will not live on the momentary obstack. */
+nonmomentary_expr:
+ { $<itype>$ = suspend_momentary (); } expr
+ { resume_momentary ((int) $<itype>1); $$ = $2; }
+ ;
+
+/* A declarator that is allowed only after an explicit typespec. */
+/* may all be followed by prec '.' */
+after_type_declarator:
+ '*' nonempty_type_quals after_type_declarator %prec UNARY
+ { $$ = make_pointer_declarator ($2, $3); }
+ | '&' nonempty_type_quals after_type_declarator %prec UNARY
+ { $$ = make_reference_declarator ($2, $3); }
+ | '*' after_type_declarator %prec UNARY
+ { $$ = make_pointer_declarator (NULL_TREE, $2); }
+ | '&' after_type_declarator %prec UNARY
+ { $$ = make_reference_declarator (NULL_TREE, $2); }
+ | ptr_to_mem type_quals after_type_declarator
+ { tree arg = make_pointer_declarator ($2, $3);
+ $$ = build_parse_node (SCOPE_REF, $1, arg);
+ }
+ | direct_after_type_declarator
+ ;
+
+qualified_type_name:
+ type_name %prec EMPTY
+ {
+ /* Remember that this name has been used in the class
+ definition, as per [class.scope0] */
+ if (current_class_type
+ && TYPE_BEING_DEFINED (current_class_type)
+ && ! IDENTIFIER_CLASS_VALUE ($$))
+ {
+ tree t = lookup_name ($$, -2);
+ if (t)
+ pushdecl_class_level (t);
+ }
+ }
+ | nested_type
+ ;
+
+nested_type:
+ nested_name_specifier type_name %prec EMPTY
+ { $$ = $2; }
+ ;
+
+direct_after_type_declarator:
+ direct_after_type_declarator '(' nonnull_exprlist ')' type_quals %prec '.'
+ { $$ = build_parse_node (CALL_EXPR, $$, $3, $5); }
+ | direct_after_type_declarator '(' parmlist ')' type_quals %prec '.'
+ { $$ = build_parse_node (CALL_EXPR, $$, $3, $5); }
+ | direct_after_type_declarator LEFT_RIGHT type_quals %prec '.'
+ { $$ = build_parse_node (CALL_EXPR, $$, empty_parms (), $3); }
+ | direct_after_type_declarator '(' error ')' type_quals %prec '.'
+ { $$ = build_parse_node (CALL_EXPR, $$, NULL_TREE, NULL_TREE); }
+ | direct_after_type_declarator '[' nonmomentary_expr ']'
+ { $$ = build_parse_node (ARRAY_REF, $$, $3); }
+ | direct_after_type_declarator '[' ']'
+ { $$ = build_parse_node (ARRAY_REF, $$, NULL_TREE); }
+ | '(' after_type_declarator ')'
+ { $$ = $2; }
+ | nested_name_specifier type_name %prec EMPTY
+ { push_nested_class (TREE_TYPE ($$), 3);
+ $$ = build_parse_node (SCOPE_REF, $$, $2);
+ TREE_COMPLEXITY ($$) = current_class_depth; }
+ | type_name %prec EMPTY
+ ;
+
+/* A declarator allowed whether or not there has been
+ an explicit typespec. These cannot redeclare a typedef-name. */
+
+notype_declarator:
+ '*' nonempty_type_quals notype_declarator %prec UNARY
+ { $$ = make_pointer_declarator ($2, $3); }
+ | '&' nonempty_type_quals notype_declarator %prec UNARY
+ { $$ = make_reference_declarator ($2, $3); }
+ | '*' notype_declarator %prec UNARY
+ { $$ = make_pointer_declarator (NULL_TREE, $2); }
+ | '&' notype_declarator %prec UNARY
+ { $$ = make_reference_declarator (NULL_TREE, $2); }
+ | ptr_to_mem type_quals notype_declarator
+ { tree arg = make_pointer_declarator ($2, $3);
+ $$ = build_parse_node (SCOPE_REF, $1, arg);
+ }
+ | direct_notype_declarator
+ ;
+
+complex_notype_declarator:
+ '*' nonempty_type_quals notype_declarator %prec UNARY
+ { $$ = make_pointer_declarator ($2, $3); }
+ | '&' nonempty_type_quals notype_declarator %prec UNARY
+ { $$ = make_reference_declarator ($2, $3); }
+ | '*' complex_notype_declarator %prec UNARY
+ { $$ = make_pointer_declarator (NULL_TREE, $2); }
+ | '&' complex_notype_declarator %prec UNARY
+ { $$ = make_reference_declarator (NULL_TREE, $2); }
+ | ptr_to_mem type_quals notype_declarator
+ { tree arg = make_pointer_declarator ($2, $3);
+ $$ = build_parse_node (SCOPE_REF, $1, arg);
+ }
+ | complex_direct_notype_declarator
+ ;
+
+complex_direct_notype_declarator:
+ direct_notype_declarator '(' nonnull_exprlist ')' type_quals %prec '.'
+ { $$ = build_parse_node (CALL_EXPR, $$, $3, $5); }
+ | direct_notype_declarator '(' parmlist ')' type_quals %prec '.'
+ { $$ = build_parse_node (CALL_EXPR, $$, $3, $5); }
+ | direct_notype_declarator LEFT_RIGHT type_quals %prec '.'
+ { $$ = build_parse_node (CALL_EXPR, $$, empty_parms (), $3); }
+ | direct_notype_declarator '(' error ')' type_quals %prec '.'
+ { $$ = build_parse_node (CALL_EXPR, $$, NULL_TREE, NULL_TREE); }
+ | '(' expr_or_declarator ')'
+ { $$ = finish_decl_parsing ($2); }
+ | '(' complex_notype_declarator ')'
+ { $$ = $2; }
+ | direct_notype_declarator '[' nonmomentary_expr ']'
+ { $$ = build_parse_node (ARRAY_REF, $$, $3); }
+ | direct_notype_declarator '[' ']'
+ { $$ = build_parse_node (ARRAY_REF, $$, NULL_TREE); }
+ ;
+
+qualified_id:
+ nested_name_specifier unqualified_id
+ { got_scope = NULL_TREE;
+ $$ = build_parse_node (SCOPE_REF, $$, $2); }
+ ;
+
+notype_qualified_id:
+ nested_name_specifier notype_unqualified_id
+ { got_scope = NULL_TREE;
+ $$ = build_parse_node (SCOPE_REF, $$, $2); }
+ ;
+
+overqualified_id:
+ notype_qualified_id
+ | global_scope notype_qualified_id
+ { $$ = $2; }
+ ;
+
+functional_cast:
+ typespec '(' nonnull_exprlist ')'
+ { $$ = build_functional_cast ($$, $3); }
+ | typespec '(' expr_or_declarator ')'
+ { $$ = reparse_decl_as_expr ($$, $3); }
+ | typespec fcast_or_absdcl %prec EMPTY
+ { $$ = reparse_absdcl_as_expr ($$, $2); }
+ ;
+
+type_name:
+ TYPENAME
+ | template_type %prec EMPTY
+ ;
+
+nested_name_specifier:
+ nested_name_specifier_1
+ | nested_name_specifier nested_name_specifier_1
+ { $$ = $2; }
+ ;
+
+/* Why the @#$%^& do type_name and notype_identifier need to be expanded
+ inline here?!? (jason) */
+nested_name_specifier_1:
+ TYPENAME SCOPE
+ { got_scope = TREE_TYPE ($$); }
+ | template_type SCOPE
+ { got_scope = TREE_TYPE ($$); }
+/* These break 'const i;'
+ | IDENTIFIER SCOPE
+ {
+ failed_scope:
+ cp_error ("`%D' is not an aggregate typedef",
+ lastiddecl ? lastiddecl : $$);
+ $$ = error_mark_node;
+ }
+ | PTYPENAME SCOPE
+ { goto failed_scope; } */
+ ;
+
+complete_type_name:
+ qualified_type_name
+ | global_scope qualified_type_name
+ { $$ = $2; }
+ ;
+
+complex_type_name:
+ nested_type
+ | global_scope qualified_type_name
+ { $$ = $2; }
+ ;
+
+ptr_to_mem:
+ nested_name_specifier '*'
+ { got_scope = NULL_TREE; }
+ | global_scope nested_name_specifier '*'
+ { $$ = $2; got_scope = NULL_TREE; }
+ ;
+
+/* All uses of explicit global scope must go through this nonterminal so
+ that got_scope will be set before yylex is called to get the next token. */
+global_scope:
+ SCOPE
+ { got_scope = void_type_node; }
+ ;
+
+/* ANSI new-declarator (5.3.4) */
+new_declarator:
+ '*' type_quals new_declarator
+ { $$ = make_pointer_declarator ($2, $3); }
+ | '*' type_quals %prec EMPTY
+ { $$ = make_pointer_declarator ($2, NULL_TREE); }
+ | '&' type_quals new_declarator %prec EMPTY
+ { $$ = make_reference_declarator ($2, $3); }
+ | '&' type_quals %prec EMPTY
+ { $$ = make_reference_declarator ($2, NULL_TREE); }
+ | ptr_to_mem type_quals %prec EMPTY
+ { tree arg = make_pointer_declarator ($2, NULL_TREE);
+ $$ = build_parse_node (SCOPE_REF, $1, arg);
+ }
+ | ptr_to_mem type_quals new_declarator
+ { tree arg = make_pointer_declarator ($2, $3);
+ $$ = build_parse_node (SCOPE_REF, $1, arg);
+ }
+ | direct_new_declarator %prec EMPTY
+ ;
+
+/* ANSI direct-new-declarator (5.3.4) */
+direct_new_declarator:
+ '[' expr ']'
+ { $$ = build_parse_node (ARRAY_REF, NULL_TREE, $2); }
+ | direct_new_declarator '[' nonmomentary_expr ']'
+ { $$ = build_parse_node (ARRAY_REF, $$, $3); }
+ ;
+
+/* ANSI abstract-declarator (8.1) */
+absdcl:
+ '*' nonempty_type_quals absdcl
+ { $$ = make_pointer_declarator ($2, $3); }
+ | '*' absdcl
+ { $$ = make_pointer_declarator (NULL_TREE, $2); }
+ | '*' nonempty_type_quals %prec EMPTY
+ { $$ = make_pointer_declarator ($2, NULL_TREE); }
+ | '*' %prec EMPTY
+ { $$ = make_pointer_declarator (NULL_TREE, NULL_TREE); }
+ | '&' nonempty_type_quals absdcl
+ { $$ = make_reference_declarator ($2, $3); }
+ | '&' absdcl
+ { $$ = make_reference_declarator (NULL_TREE, $2); }
+ | '&' nonempty_type_quals %prec EMPTY
+ { $$ = make_reference_declarator ($2, NULL_TREE); }
+ | '&' %prec EMPTY
+ { $$ = make_reference_declarator (NULL_TREE, NULL_TREE); }
+ | ptr_to_mem type_quals %prec EMPTY
+ { tree arg = make_pointer_declarator ($2, NULL_TREE);
+ $$ = build_parse_node (SCOPE_REF, $1, arg);
+ }
+ | ptr_to_mem type_quals absdcl
+ { tree arg = make_pointer_declarator ($2, $3);
+ $$ = build_parse_node (SCOPE_REF, $1, arg);
+ }
+ | direct_abstract_declarator %prec EMPTY
+ ;
+
+/* ANSI direct-abstract-declarator (8.1) */
+direct_abstract_declarator:
+ '(' absdcl ')'
+ { $$ = $2; }
+ /* `(typedef)1' is `int'. */
+ | PAREN_STAR_PAREN
+ | direct_abstract_declarator '(' parmlist ')' type_quals %prec '.'
+ { $$ = build_parse_node (CALL_EXPR, $$, $3, $5); }
+ | direct_abstract_declarator LEFT_RIGHT type_quals %prec '.'
+ { $$ = build_parse_node (CALL_EXPR, $$, empty_parms (), $3); }
+ | direct_abstract_declarator '[' nonmomentary_expr ']' %prec '.'
+ { $$ = build_parse_node (ARRAY_REF, $$, $3); }
+ | direct_abstract_declarator '[' ']' %prec '.'
+ { $$ = build_parse_node (ARRAY_REF, $$, NULL_TREE); }
+ | '(' complex_parmlist ')' type_quals %prec '.'
+ { $$ = build_parse_node (CALL_EXPR, NULL_TREE, $2, $4); }
+ | regcast_or_absdcl type_quals %prec '.'
+ { TREE_OPERAND ($$, 2) = $2; }
+ | fcast_or_absdcl type_quals %prec '.'
+ { TREE_OPERAND ($$, 2) = $2; }
+ | '[' nonmomentary_expr ']' %prec '.'
+ { $$ = build_parse_node (ARRAY_REF, NULL_TREE, $2); }
+ | '[' ']' %prec '.'
+ { $$ = build_parse_node (ARRAY_REF, NULL_TREE, NULL_TREE); }
+ ;
+
+/* For C++, decls and stmts can be intermixed, so we don't need to
+ have a special rule that won't start parsing the stmt section
+ until we have a stmt that parses without errors. */
+
+stmts:
+ stmt
+ | errstmt
+ | stmts stmt
+ | stmts errstmt
+ ;
+
+errstmt: error ';'
+ ;
+
+/* build the LET_STMT node before parsing its contents,
+ so that any LET_STMTs within the context can have their display pointers
+ set up to point at this one. */
+
+.pushlevel: /* empty */
+ { emit_line_note (input_filename, lineno);
+ pushlevel (0);
+ clear_last_expr ();
+ push_momentary ();
+ expand_start_bindings (0); }
+ ;
+
+/* Read zero or more forward-declarations for labels
+ that nested functions can jump to. */
+maybe_label_decls:
+ /* empty */
+ | label_decls
+ { if (flag_ansi)
+ pedwarn ("ANSI C++ forbids label declarations"); }
+ ;
+
+label_decls:
+ label_decl
+ | label_decls label_decl
+ ;
+
+label_decl:
+ LABEL identifiers_or_typenames ';'
+ { tree link;
+ for (link = $2; link; link = TREE_CHAIN (link))
+ {
+ tree label = shadow_label (TREE_VALUE (link));
+ C_DECLARED_LABEL_FLAG (label) = 1;
+ declare_nonlocal_label (label);
+ }
+ }
+ ;
+
+/* This is the body of a function definition.
+ It causes syntax errors to ignore to the next openbrace. */
+compstmt_or_error:
+ compstmt
+ {}
+ | error compstmt
+ ;
+
+compstmt: '{' .pushlevel '}'
+ { expand_end_bindings (getdecls (), kept_level_p(), 1);
+ $$ = poplevel (kept_level_p (), 1, 0);
+ pop_momentary (); }
+ | '{' .pushlevel maybe_label_decls stmts '}'
+ { expand_end_bindings (getdecls (), kept_level_p(), 1);
+ $$ = poplevel (kept_level_p (), 1, 0);
+ pop_momentary (); }
+ | '{' .pushlevel maybe_label_decls stmts error '}'
+ { expand_end_bindings (getdecls (), kept_level_p(), 1);
+ $$ = poplevel (kept_level_p (), 0, 0);
+ pop_momentary (); }
+ | '{' .pushlevel maybe_label_decls error '}'
+ { expand_end_bindings (getdecls (), kept_level_p(), 1);
+ $$ = poplevel (kept_level_p (), 0, 0);
+ pop_momentary (); }
+ ;
+
+simple_if:
+ IF
+ { cond_stmt_keyword = "if"; }
+ .pushlevel paren_cond_or_null
+ { emit_line_note (input_filename, lineno);
+ expand_start_cond ($4, 0); }
+ implicitly_scoped_stmt
+ ;
+
+implicitly_scoped_stmt:
+ compstmt
+ { finish_stmt (); }
+ | .pushlevel simple_stmt
+ { expand_end_bindings (getdecls (), kept_level_p (), 1);
+ $$ = poplevel (kept_level_p (), 1, 0);
+ pop_momentary (); }
+ ;
+
+stmt:
+ compstmt
+ { finish_stmt (); }
+ | simple_stmt
+ ;
+
+simple_stmt:
+ decl
+ { finish_stmt (); }
+ | expr ';'
+ {
+ tree expr = $1;
+ emit_line_note (input_filename, lineno);
+ /* Do default conversion if safe and possibly important,
+ in case within ({...}). */
+ if ((TREE_CODE (TREE_TYPE (expr)) == ARRAY_TYPE
+ && lvalue_p (expr))
+ || TREE_CODE (TREE_TYPE (expr)) == FUNCTION_TYPE)
+ expr = default_conversion (expr);
+ cplus_expand_expr_stmt (expr);
+ clear_momentary ();
+ finish_stmt (); }
+ | simple_if ELSE
+ { expand_start_else (); }
+ implicitly_scoped_stmt
+ { expand_end_cond ();
+ expand_end_bindings (getdecls (), kept_level_p (), 1);
+ poplevel (kept_level_p (), 1, 0);
+ pop_momentary ();
+ finish_stmt (); }
+ | simple_if %prec IF
+ { expand_end_cond ();
+ expand_end_bindings (getdecls (), kept_level_p (), 1);
+ poplevel (kept_level_p (), 1, 0);
+ pop_momentary ();
+ finish_stmt (); }
+ | WHILE
+ { emit_nop ();
+ emit_line_note (input_filename, lineno);
+ expand_start_loop (1);
+ cond_stmt_keyword = "while"; }
+ .pushlevel paren_cond_or_null
+ { expand_exit_loop_if_false (0, $4); }
+ already_scoped_stmt
+ { expand_end_bindings (getdecls (), kept_level_p (), 1);
+ poplevel (kept_level_p (), 1, 0);
+ pop_momentary ();
+ expand_end_loop ();
+ finish_stmt (); }
+ | DO
+ { emit_nop ();
+ emit_line_note (input_filename, lineno);
+ expand_start_loop_continue_elsewhere (1); }
+ implicitly_scoped_stmt WHILE
+ { expand_loop_continue_here ();
+ cond_stmt_keyword = "do"; }
+ paren_expr_or_null ';'
+ { emit_line_note (input_filename, lineno);
+ expand_exit_loop_if_false (0, $6);
+ expand_end_loop ();
+ clear_momentary ();
+ finish_stmt (); }
+ | forhead.1
+ { emit_nop ();
+ emit_line_note (input_filename, lineno);
+ if ($1) cplus_expand_expr_stmt ($1);
+ expand_start_loop_continue_elsewhere (1); }
+ .pushlevel xcond ';'
+ { emit_line_note (input_filename, lineno);
+ if ($4) expand_exit_loop_if_false (0, $4); }
+ xexpr ')'
+ /* Don't let the tree nodes for $7 be discarded
+ by clear_momentary during the parsing of the next stmt. */
+ { push_momentary (); }
+ already_scoped_stmt
+ { emit_line_note (input_filename, lineno);
+ expand_end_bindings (getdecls (), kept_level_p (), 1);
+ poplevel (kept_level_p (), 1, 0);
+ pop_momentary ();
+ expand_loop_continue_here ();
+ if ($7) cplus_expand_expr_stmt ($7);
+ pop_momentary ();
+ expand_end_loop ();
+ finish_stmt (); }
+ | forhead.2
+ { emit_nop ();
+ emit_line_note (input_filename, lineno);
+ expand_start_loop_continue_elsewhere (1); }
+ .pushlevel xcond ';'
+ { emit_line_note (input_filename, lineno);
+ if ($4) expand_exit_loop_if_false (0, $4); }
+ xexpr ')'
+ /* Don't let the tree nodes for $7 be discarded
+ by clear_momentary during the parsing of the next stmt. */
+ { push_momentary ();
+ $<itype>8 = lineno; }
+ already_scoped_stmt
+ { emit_line_note (input_filename, (int) $<itype>8);
+ expand_end_bindings (getdecls (), kept_level_p (), 1);
+ poplevel (kept_level_p (), 1, 0);
+ pop_momentary ();
+ expand_loop_continue_here ();
+ if ($7) cplus_expand_expr_stmt ($7);
+ pop_momentary ();
+ expand_end_loop ();
+ finish_stmt ();
+ }
+ | SWITCH .pushlevel '(' condition ')'
+ { emit_line_note (input_filename, lineno);
+ c_expand_start_case ($4);
+ /* Don't let the tree nodes for $4 be discarded by
+ clear_momentary during the parsing of the next stmt. */
+ push_momentary (); }
+ implicitly_scoped_stmt
+ { expand_end_case ($4);
+ pop_momentary ();
+ expand_end_bindings (getdecls (), kept_level_p (), 1);
+ poplevel (kept_level_p (), 1, 0);
+ pop_momentary ();
+ finish_stmt (); }
+ | CASE expr_no_commas ':'
+ { register tree value = check_cp_case_value ($2);
+ register tree label
+ = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE);
+
+ if (value != error_mark_node)
+ {
+ tree duplicate;
+ int success = pushcase (value, convert_and_check,
+ label, &duplicate);
+ if (success == 1)
+ cp_error ("case label `%E' not within a switch statement", $2);
+ else if (success == 2)
+ {
+ cp_error ("duplicate case value `%E'", $2);
+ cp_error_at ("`%E' previously used here", duplicate);
+ }
+ else if (success == 3)
+ warning ("case value out of range");
+ else if (success == 5)
+ cp_error ("case label `%E' within scope of cleanup or variable array", $2);
+ }
+ define_case_label (label);
+ }
+ stmt
+ | CASE expr_no_commas ELLIPSIS expr_no_commas ':'
+ { register tree value1 = check_cp_case_value ($2);
+ register tree value2 = check_cp_case_value ($4);
+ register tree label
+ = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE);
+
+ if (flag_ansi)
+ pedwarn ("ANSI C++ forbids range expressions in switch statement");
+ if (value1 != error_mark_node
+ && value2 != error_mark_node)
+ {
+ tree duplicate;
+ int success = pushcase_range (value1, value2,
+ convert_and_check, label,
+ &duplicate);
+ if (success == 1)
+ error ("case label not within a switch statement");
+ else if (success == 2)
+ {
+ error ("duplicate (or overlapping) case value");
+ error_with_decl (duplicate, "this is the first entry overlapping that value");
+ }
+ else if (success == 3)
+ warning ("case value out of range");
+ else if (success == 4)
+ warning ("empty range specified");
+ else if (success == 5)
+ error ("case label within scope of cleanup or variable array");
+ }
+ define_case_label (label);
+ }
+ stmt
+ | DEFAULT ':'
+ {
+ tree duplicate;
+ register tree label
+ = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE);
+ int success = pushcase (NULL_TREE, 0, label, &duplicate);
+ if (success == 1)
+ error ("default label not within a switch statement");
+ else if (success == 2)
+ {
+ error ("multiple default labels in one switch");
+ error_with_decl (duplicate, "this is the first default label");
+ }
+ define_case_label (NULL_TREE);
+ }
+ stmt
+ | BREAK ';'
+ { emit_line_note (input_filename, lineno);
+ if ( ! expand_exit_something ())
+ error ("break statement not within loop or switch"); }
+ | CONTINUE ';'
+ { emit_line_note (input_filename, lineno);
+ if (! expand_continue_loop (0))
+ error ("continue statement not within a loop"); }
+ | RETURN ';'
+ { emit_line_note (input_filename, lineno);
+ c_expand_return (NULL_TREE); }
+ | RETURN expr ';'
+ { emit_line_note (input_filename, lineno);
+ c_expand_return ($2);
+ finish_stmt ();
+ }
+ | asm_keyword maybe_type_qual '(' string ')' ';'
+ { if (TREE_CHAIN ($4)) $4 = combine_strings ($4);
+ emit_line_note (input_filename, lineno);
+ expand_asm ($4);
+ finish_stmt ();
+ }
+ /* This is the case with just output operands. */
+ | asm_keyword maybe_type_qual '(' string ':' asm_operands ')' ';'
+ { if (TREE_CHAIN ($4)) $4 = combine_strings ($4);
+ emit_line_note (input_filename, lineno);
+ c_expand_asm_operands ($4, $6, NULL_TREE, NULL_TREE,
+ $2 == ridpointers[(int)RID_VOLATILE],
+ input_filename, lineno);
+ finish_stmt ();
+ }
+ /* This is the case with input operands as well. */
+ | asm_keyword maybe_type_qual '(' string ':' asm_operands ':' asm_operands ')' ';'
+ { if (TREE_CHAIN ($4)) $4 = combine_strings ($4);
+ emit_line_note (input_filename, lineno);
+ c_expand_asm_operands ($4, $6, $8, NULL_TREE,
+ $2 == ridpointers[(int)RID_VOLATILE],
+ input_filename, lineno);
+ finish_stmt ();
+ }
+ /* This is the case with clobbered registers as well. */
+ | asm_keyword maybe_type_qual '(' string ':' asm_operands ':'
+ asm_operands ':' asm_clobbers ')' ';'
+ { if (TREE_CHAIN ($4)) $4 = combine_strings ($4);
+ emit_line_note (input_filename, lineno);
+ c_expand_asm_operands ($4, $6, $8, $10,
+ $2 == ridpointers[(int)RID_VOLATILE],
+ input_filename, lineno);
+ finish_stmt ();
+ }
+ | GOTO '*' expr ';'
+ { emit_line_note (input_filename, lineno);
+ expand_computed_goto ($3); }
+ | GOTO identifier ';'
+ { tree decl;
+ emit_line_note (input_filename, lineno);
+ decl = lookup_label ($2);
+ TREE_USED (decl) = 1;
+ expand_goto (decl); }
+ | label_colon stmt
+ { finish_stmt (); }
+ | label_colon '}'
+ { error ("label must be followed by statement");
+ yyungetc ('}', 0);
+ finish_stmt (); }
+ | ';'
+ { finish_stmt (); }
+ | try_block
+ ;
+
+try_block:
+ TRY '{' .pushlevel
+ { expand_start_try_stmts (); }
+ ansi_try_stmts
+ { expand_end_try_stmts ();
+ expand_start_all_catch (); }
+ handler_seq
+ { expand_end_all_catch (); }
+ ;
+
+ansi_try_stmts:
+ '}'
+ /* An empty try block is degenerate, but it's better to
+ do extra work here than to do all the special-case work
+ everywhere else. */
+ { expand_end_bindings (0,1,1);
+ poplevel (2,0,0);
+ }
+ | stmts '}'
+ { expand_end_bindings (0,1,1);
+ poplevel (2,0,0);
+ }
+ | error '}'
+ { expand_end_bindings (0,1,1);
+ poplevel (2,0,0);
+ }
+ ;
+
+handler_seq:
+ /* empty */
+ | handler_seq CATCH
+ { emit_line_note (input_filename, lineno); }
+ handler_args compstmt
+ { expand_end_catch_block (); }
+ ;
+
+type_specifier_seq:
+ typed_typespecs %prec EMPTY
+ | nonempty_type_quals %prec EMPTY
+ ;
+
+handler_args:
+ '(' ELLIPSIS ')'
+ { expand_start_catch_block (NULL_TREE, NULL_TREE); }
+ /* This doesn't allow reference parameters, the below does.
+ | '(' type_specifier_seq absdcl ')'
+ { expand_start_catch_block ($2, $3); }
+ | '(' type_specifier_seq ')'
+ { expand_start_catch_block ($2, NULL_TREE); }
+ | '(' type_specifier_seq notype_declarator ')'
+ { expand_start_catch_block ($2, $3); }
+ | '(' typed_typespecs after_type_declarator ')'
+ { expand_start_catch_block ($2, $3); }
+ */
+ | '(' parm ')'
+ { expand_start_catch_block (TREE_PURPOSE ($2),
+ TREE_VALUE ($2)); }
+ ;
+
+label_colon:
+ IDENTIFIER ':'
+ { tree label;
+ do_label:
+ label = define_label (input_filename, lineno, $1);
+ if (label)
+ expand_label (label);
+ }
+ | PTYPENAME ':'
+ { goto do_label; }
+ | TYPENAME ':'
+ { goto do_label; }
+ ;
+
+forhead.1:
+ FOR '(' ';'
+ { $$ = NULL_TREE; }
+ | FOR '(' expr ';'
+ { $$ = $3; }
+ | FOR '(' '{' '}'
+ { $$ = NULL_TREE; }
+ ;
+
+forhead.2:
+ FOR '(' decl
+ { $$ = 0; }
+ | FOR '(' error ';'
+ { $$ = 0; }
+ | FOR '(' '{' .pushlevel stmts '}'
+ { $$ = 1; }
+ | FOR '(' '{' .pushlevel error '}'
+ { $$ = -1; }
+ ;
+
+/* Either a type-qualifier or nothing. First thing in an `asm' statement. */
+
+maybe_type_qual:
+ /* empty */
+ { emit_line_note (input_filename, lineno);
+ $$ = NULL_TREE; }
+ | TYPE_QUAL
+ { emit_line_note (input_filename, lineno); }
+ ;
+
+xexpr:
+ /* empty */
+ { $$ = NULL_TREE; }
+ | expr
+ | error
+ { $$ = NULL_TREE; }
+ ;
+
+/* These are the operands other than the first string and colon
+ in asm ("addextend %2,%1": "=dm" (x), "0" (y), "g" (*x)) */
+asm_operands: /* empty */
+ { $$ = NULL_TREE; }
+ | nonnull_asm_operands
+ ;
+
+nonnull_asm_operands:
+ asm_operand
+ | nonnull_asm_operands ',' asm_operand
+ { $$ = chainon ($$, $3); }
+ ;
+
+asm_operand:
+ STRING '(' expr ')'
+ { $$ = build_tree_list ($$, $3); }
+ ;
+
+asm_clobbers:
+ STRING
+ { $$ = tree_cons (NULL_TREE, $$, NULL_TREE); }
+ | asm_clobbers ',' STRING
+ { $$ = tree_cons (NULL_TREE, $3, $$); }
+ ;
+
+/* This is what appears inside the parens in a function declarator.
+ Its value is represented in the format that grokdeclarator expects.
+
+ In C++, declaring a function with no parameters
+ means that that function takes *no* parameters. */
+
+parmlist: /* empty */
+ {
+ if (strict_prototype)
+ $$ = void_list_node;
+ else
+ $$ = NULL_TREE;
+ }
+ | complex_parmlist
+ | type_id
+ { $$ = tree_cons (NULL_TREE, $$, void_list_node);
+ TREE_PARMLIST ($$) = 1; }
+ ;
+
+/* This nonterminal does not include the common sequence '(' type_id ')',
+ as it is ambiguous and must be disambiguated elsewhere. */
+complex_parmlist:
+ parms
+ {
+ $$ = chainon ($$, void_list_node);
+ TREE_PARMLIST ($$) = 1;
+ }
+ | parms_comma ELLIPSIS
+ {
+ TREE_PARMLIST ($$) = 1;
+ }
+ /* C++ allows an ellipsis without a separating ',' */
+ | parms ELLIPSIS
+ {
+ TREE_PARMLIST ($$) = 1;
+ }
+ | type_id ELLIPSIS
+ {
+ $$ = build_tree_list (NULL_TREE, $$);
+ TREE_PARMLIST ($$) = 1;
+ }
+ | ELLIPSIS
+ {
+ /* ARM $8.2.5 has this as a boxed-off comment. */
+ if (pedantic)
+ warning ("use of `...' without a first argument is non-portable");
+ $$ = NULL_TREE;
+ }
+ | TYPENAME_ELLIPSIS
+ {
+ TREE_PARMLIST ($$) = 1;
+ }
+ | parms TYPENAME_ELLIPSIS
+ {
+ TREE_PARMLIST ($$) = 1;
+ }
+ | type_id TYPENAME_ELLIPSIS
+ {
+ $$ = build_tree_list (NULL_TREE, $$);
+ TREE_PARMLIST ($$) = 1;
+ }
+ | parms ':'
+ {
+ /* This helps us recover from really nasty
+ parse errors, for example, a missing right
+ parenthesis. */
+ yyerror ("possibly missing ')'");
+ $$ = chainon ($$, void_list_node);
+ TREE_PARMLIST ($$) = 1;
+ yyungetc (':', 0);
+ yychar = ')';
+ }
+ | type_id ':'
+ {
+ /* This helps us recover from really nasty
+ parse errors, for example, a missing right
+ parenthesis. */
+ yyerror ("possibly missing ')'");
+ $$ = tree_cons (NULL_TREE, $$, void_list_node);
+ TREE_PARMLIST ($$) = 1;
+ yyungetc (':', 0);
+ yychar = ')';
+ }
+ ;
+
+/* A nonempty list of parameter declarations or type names. */
+parms:
+ named_parm
+ { $$ = build_tree_list (NULL_TREE, $$); }
+ | parm '=' init
+ { $$ = build_tree_list ($3, $$); }
+ | parms_comma full_parm
+ { $$ = chainon ($$, $2); }
+ | parms_comma bad_parm
+ { $$ = chainon ($$, build_tree_list (NULL_TREE, $2)); }
+ | parms_comma bad_parm '=' init
+ { $$ = chainon ($$, build_tree_list ($4, $2)); }
+ ;
+
+parms_comma:
+ parms ','
+ | type_id ','
+ { $$ = build_tree_list (NULL_TREE, $$); }
+ ;
+
+/* A single parameter declaration or parameter type name,
+ as found in a parmlist. The first four cases make up for 10%
+ of the time spent parsing C++. We cannot use them because
+ of `int id[]' which won't get parsed properly. */
+named_parm:
+/*
+ typed_declspecs dont_see_typename '*' IDENTIFIER
+ { $$ = build_tree_list ($$, build_parse_node (INDIRECT_REF, $4));
+ see_typename (); }
+ | typed_declspecs dont_see_typename '&' IDENTIFIER
+ { $$ = build_tree_list ($$, build_parse_node (ADDR_EXPR, $4));
+ see_typename (); }
+ | TYPENAME IDENTIFIER
+ { $$ = build_tree_list (get_decl_list ($$), $2); }
+ | TYPESPEC IDENTIFIER
+ { $$ = build_tree_list (get_decl_list ($$), $2); }
+ | */
+ /* Here we expand typed_declspecs inline to avoid mis-parsing of
+ TYPESPEC IDENTIFIER. */
+ typed_declspecs1 declarator
+ { $$ = build_tree_list ($$, $2); }
+ | typed_typespecs declarator
+ { $$ = build_tree_list ($$, $2); }
+ | typespec declarator
+ { $$ = build_tree_list (get_decl_list ($$), $2); }
+ | typed_declspecs1 absdcl
+ { $$ = build_tree_list ($$, $2); }
+ | typed_declspecs1 %prec EMPTY
+ { $$ = build_tree_list ($$, NULL_TREE); }
+ | declmods notype_declarator
+ { $$ = build_tree_list ($$, $2); }
+ ;
+
+full_parm:
+ parm
+ { $$ = build_tree_list (NULL_TREE, $$); }
+ | parm '=' init
+ { $$ = build_tree_list ($3, $$); }
+ ;
+
+parm:
+ named_parm
+ | type_id
+ ;
+
+see_typename: %prec EMPTY
+ { see_typename (); }
+ ;
+
+/*
+dont_see_typename: %prec EMPTY
+ { dont_see_typename (); }
+ ;
+
+try_for_typename:
+ {
+ if ($<ttype>-1 == error_mark_node)
+ $$ = 0;
+ else
+ {
+ $$ = 1;
+ pushclass ($<ttype>-1, 1);
+ }
+ }
+ ;
+*/
+
+bad_parm:
+ /* empty */ %prec EMPTY
+ {
+ warning ("type specifier omitted for parameter");
+ $$ = build_tree_list (TREE_PURPOSE (TREE_VALUE ($<ttype>-1)), NULL_TREE);
+ }
+ | notype_declarator
+ {
+ warning ("type specifier omitted for parameter");
+ $$ = build_tree_list (TREE_PURPOSE (TREE_VALUE ($<ttype>-1)), $$);
+ }
+ ;
+
+maybe_raises:
+ %prec EMPTY /* empty */
+ { $$ = NULL_TREE; }
+ | THROW '(' ansi_raise_identifiers ')' %prec EMPTY
+ { $$ = $3; }
+ ;
+
+ansi_raise_identifier:
+ type_id
+ { $$ = build_decl_list (NULL_TREE, $$); }
+ ;
+
+ansi_raise_identifiers:
+ ansi_raise_identifier
+ | ansi_raise_identifiers ',' ansi_raise_identifier
+ {
+ TREE_CHAIN ($3) = $$;
+ $$ = $3;
+ }
+ ;
+
+conversion_declarator:
+ /* empty */ %prec EMPTY
+ { $$ = NULL_TREE; }
+ | '*' type_quals conversion_declarator
+ { $$ = make_pointer_declarator ($2, $3); }
+ | '&' type_quals conversion_declarator
+ { $$ = make_reference_declarator ($2, $3); }
+ | ptr_to_mem type_quals conversion_declarator
+ { tree arg = make_pointer_declarator ($2, $3);
+ $$ = build_parse_node (SCOPE_REF, $1, arg);
+ }
+ ;
+
+operator: OPERATOR
+ { got_scope = NULL_TREE; }
+ ;
+
+operator_name:
+ operator '*'
+ { $$ = ansi_opname[MULT_EXPR]; }
+ | operator '/'
+ { $$ = ansi_opname[TRUNC_DIV_EXPR]; }
+ | operator '%'
+ { $$ = ansi_opname[TRUNC_MOD_EXPR]; }
+ | operator '+'
+ { $$ = ansi_opname[PLUS_EXPR]; }
+ | operator '-'
+ { $$ = ansi_opname[MINUS_EXPR]; }
+ | operator '&'
+ { $$ = ansi_opname[BIT_AND_EXPR]; }
+ | operator '|'
+ { $$ = ansi_opname[BIT_IOR_EXPR]; }
+ | operator '^'
+ { $$ = ansi_opname[BIT_XOR_EXPR]; }
+ | operator '~'
+ { $$ = ansi_opname[BIT_NOT_EXPR]; }
+ | operator ','
+ { $$ = ansi_opname[COMPOUND_EXPR]; }
+ | operator ARITHCOMPARE
+ { $$ = ansi_opname[$2]; }
+ | operator '<'
+ { $$ = ansi_opname[LT_EXPR]; }
+ | operator '>'
+ { $$ = ansi_opname[GT_EXPR]; }
+ | operator EQCOMPARE
+ { $$ = ansi_opname[$2]; }
+ | operator ASSIGN
+ { $$ = ansi_assopname[$2]; }
+ | operator '='
+ { $$ = ansi_opname [MODIFY_EXPR]; }
+ | operator LSHIFT
+ { $$ = ansi_opname[$2]; }
+ | operator RSHIFT
+ { $$ = ansi_opname[$2]; }
+ | operator PLUSPLUS
+ { $$ = ansi_opname[POSTINCREMENT_EXPR]; }
+ | operator MINUSMINUS
+ { $$ = ansi_opname[PREDECREMENT_EXPR]; }
+ | operator ANDAND
+ { $$ = ansi_opname[TRUTH_ANDIF_EXPR]; }
+ | operator OROR
+ { $$ = ansi_opname[TRUTH_ORIF_EXPR]; }
+ | operator '!'
+ { $$ = ansi_opname[TRUTH_NOT_EXPR]; }
+ | operator '?' ':'
+ { $$ = ansi_opname[COND_EXPR]; }
+ | operator MIN_MAX
+ { $$ = ansi_opname[$2]; }
+ | operator POINTSAT %prec EMPTY
+ { $$ = ansi_opname[COMPONENT_REF]; }
+ | operator POINTSAT_STAR %prec EMPTY
+ { $$ = ansi_opname[MEMBER_REF]; }
+ | operator LEFT_RIGHT
+ { $$ = ansi_opname[CALL_EXPR]; }
+ | operator '[' ']'
+ { $$ = ansi_opname[ARRAY_REF]; }
+ | operator NEW %prec EMPTY
+ { $$ = ansi_opname[NEW_EXPR]; }
+ | operator DELETE %prec EMPTY
+ { $$ = ansi_opname[DELETE_EXPR]; }
+ | operator NEW '[' ']'
+ { $$ = ansi_opname[VEC_NEW_EXPR]; }
+ | operator DELETE '[' ']'
+ { $$ = ansi_opname[VEC_DELETE_EXPR]; }
+ /* Names here should be looked up in class scope ALSO. */
+ | operator type_specifier_seq conversion_declarator
+ { $$ = grokoptypename ($2, $3); }
+ | operator error
+ { $$ = ansi_opname[ERROR_MARK]; }
+ ;
+
+%%
+
+#ifdef SPEW_DEBUG
+const char *
+debug_yytranslate (value)
+ int value;
+{
+ return yytname[YYTRANSLATE (value)];
+}
+
+#endif
diff --git a/gnu/usr.bin/cc/libgcc/Makefile b/gnu/usr.bin/cc/libgcc/Makefile
index 4b2c5a4..e18fcde 100644
--- a/gnu/usr.bin/cc/libgcc/Makefile
+++ b/gnu/usr.bin/cc/libgcc/Makefile
@@ -1,14 +1,12 @@
#
-# $FreeBSD$
+# $Id: Makefile,v 1.7 1995/03/12 09:37:26 phk Exp $
#
LIB= gcc
-INSTALL_PIC_ARCHIVE= yes
-SHLIB_MAJOR= 26
-SHLIB_MINOR= 0
+INSTALL_PIC_ARCHIVE= yes
-LIB1OBJS= _mulsi3.o _udivsi3.o _divsi3.o _umodsi3.o _modsi3.o _lshrsi3.o _lshlsi3.o _ashrsi3.o _ashlsi3.o _divdf3.o _muldf3.o _negdf2.o _adddf3.o _subdf3.o _fixdfsi.o _fixsfsi.o _floatsidf.o _floatsisf.o _truncdfsf2.o _extendsfdf2.o _addsf3.o _negsf2.o _subsf3.o _mulsf3.o _divsf3.o _eqdf2.o _nedf2.o _gtdf2.o _gedf2.o _ltdf2.o _ledf2.o _eqsf2.o _nesf2.o _gtsf2.o _gesf2.o _ltsf2.o _lesf2.o
-LIB2OBJS= _muldi3.o _divdi3.o _moddi3.o _udivdi3.o _umoddi3.o _negdi2.o _lshrdi3.o _lshldi3.o _ashldi3.o _ashrdi3.o _ffsdi2.o _udiv_w_sdiv.o _udivmoddi4.o _cmpdi2.o _ucmpdi2.o _floatdidf.o _floatdisf.o _fixunsdfsi.o _fixunssfsi.o _fixunsdfdi.o _fixdfdi.o _fixunssfdi.o _fixsfdi.o _fixxfdi.o _fixunsxfdi.o _floatdixf.o _fixunsxfsi.o _fixtfdi.o _fixunstfdi.o _floatditf.o __gcc_bcmp.o _varargs.o _eprintf.o _op_new.o _op_vnew.o _new_handler.o _op_delete.o _op_vdel.o _bb.o _shtab.o _clear_cache.o _trampoline.o __main.o _exit.o _ctors.o
+LIB1OBJS= _mulsi3.o _umodsi3.o _modsi3.o _lshrsi3.o _lshlsi3.o _ashrsi3.o _ashlsi3.o _divdf3.o _muldf3.o _negdf2.o _adddf3.o _subdf3.o _fixsfsi.o _floatsidf.o _floatsisf.o _truncdfsf2.o _extendsfdf2.o _addsf3.o _negsf2.o _subsf3.o _mulsf3.o _divsf3.o _eqdf2.o _nedf2.o _gtdf2.o _gedf2.o _ltdf2.o _ledf2.o _eqsf2.o _nesf2.o _gtsf2.o _gesf2.o _ltsf2.o _lesf2.o
+LIB2OBJS= _ffsdi2.o _udiv_w_sdiv.o _udivmoddi4.o _fixunssfsi.o _fixxfdi.o _fixunsxfdi.o _floatdixf.o _fixunsxfsi.o __gcc_bcmp.o _varargs.o _eprintf.o _op_new.o _op_vnew.o _new_handler.o _op_delete.o _op_vdel.o _bb.o _shtab.o _clear_cache.o __main.o _exit.o _ctors.o _eh.o _pure.o
OBJS= ${LIB1OBJS} ${LIB2OBJS}
LIB1SOBJS=${LIB1OBJS:.o=.so}
diff --git a/gnu/usr.bin/cc/libgcc/libgcc1.c b/gnu/usr.bin/cc/libgcc/libgcc1.c
index 7c0e0c1..dff271d 100644
--- a/gnu/usr.bin/cc/libgcc/libgcc1.c
+++ b/gnu/usr.bin/cc/libgcc/libgcc1.c
@@ -221,7 +221,7 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
These definitions work for machines where an SF value is
returned in the same register as an int. */
-#ifndef FLOAT_VALUE_TYPE
+#ifndef FLOAT_VALUE_TYPE
#define FLOAT_VALUE_TYPE int
#endif
diff --git a/gnu/usr.bin/cc/libgcc/libgcc2.c b/gnu/usr.bin/cc/libgcc/libgcc2.c
index fc2e1ac..746c67d 100644
--- a/gnu/usr.bin/cc/libgcc/libgcc2.c
+++ b/gnu/usr.bin/cc/libgcc/libgcc2.c
@@ -1187,10 +1187,10 @@ asm ("___builtin_saveregs:");
*/
asm (" fst.q %f8, 0(%sp)"); /* save floating regs (f8-f15) */
- asm (" fst.q %f12,16(%sp)");
+ asm (" fst.q %f12,16(%sp)");
asm (" st.l %r16,32(%sp)"); /* save integer regs (r16-r27) */
- asm (" st.l %r17,36(%sp)");
+ asm (" st.l %r17,36(%sp)");
asm (" st.l %r18,40(%sp)");
asm (" st.l %r19,44(%sp)");
asm (" st.l %r20,48(%sp)");
@@ -1256,9 +1256,9 @@ asm ("___builtin_saveregs:");
*/
asm (" fst.q f8, 0(sp)");
- asm (" fst.q f12,16(sp)");
+ asm (" fst.q f12,16(sp)");
asm (" st.l r16,32(sp)");
- asm (" st.l r17,36(sp)");
+ asm (" st.l r17,36(sp)");
asm (" st.l r18,40(sp)");
asm (" st.l r19,44(sp)");
asm (" st.l r20,48(sp)");
@@ -1327,7 +1327,7 @@ asm ("___builtin_saveregs:");
asm (" adds 80,sp,r16"); /* return address of the __va_ctl. */
asm (" bri r1");
asm (" mov r30,sp");
- /* recover stack and pass address to start
+ /* recover stack and pass address to start
of data. */
#endif /* not __PARAGON__ */
#endif /* not __svr4__ */
@@ -1428,6 +1428,7 @@ BLOCK_PROFILER_CODE
#undef NULL /* Avoid errors if stdio.h and our stddef.h mismatch. */
#include <stdio.h>
+char *ctime ();
#ifdef HAVE_ATEXIT
extern void atexit (void (*) (void));
@@ -1620,7 +1621,7 @@ __builtin_new (size_t sz)
(*__new_handler) ();
p = (void *) malloc (sz);
}
-
+
return p;
}
#endif /* L_op_new */
@@ -1737,7 +1738,7 @@ void
__clear_cache (beg, end)
char *beg, *end;
{
-#ifdef CLEAR_INSN_CACHE
+#ifdef CLEAR_INSN_CACHE
CLEAR_INSN_CACHE (beg, end);
#else
#ifdef INSN_CACHE_SIZE
@@ -1801,7 +1802,7 @@ __clear_cache (beg, end)
/* Compute the cache alignment of the place to stop clearing. */
#if 0 /* This is not needed for gcc's purposes. */
/* If the block to clear is bigger than a cache plane,
- we clear the entire cache, and OFFSET is already correct. */
+ we clear the entire cache, and OFFSET is already correct. */
if (end < beg + INSN_CACHE_PLANE_SIZE)
#endif
offset = (((int) (end + INSN_CACHE_LINE_WIDTH - 1)
@@ -1847,8 +1848,8 @@ __clear_cache (beg, end)
/* Jump to a trampoline, loading the static chain address. */
-#ifdef TRANSFER_FROM_TRAMPOLINE
-TRANSFER_FROM_TRAMPOLINE
+#ifdef TRANSFER_FROM_TRAMPOLINE
+TRANSFER_FROM_TRAMPOLINE
#endif
#if defined (NeXT) && defined (__MACH__)
@@ -1884,7 +1885,7 @@ __enable_execute_stack (addr)
#else
__clear_cache ((int) addr, (int) eaddr);
#endif
-}
+}
#endif /* defined (NeXT) && defined (__MACH__) */
@@ -1930,7 +1931,7 @@ __enable_execute_stack ()
int save_errno;
static unsigned long lowest = USRSTACK;
unsigned long current = (unsigned long) &save_errno & -NBPC;
-
+
/* Ignore errno being set. memctl sets errno to EINVAL whenever the
address is seen as 'negative'. That is the case with the stack. */
@@ -1995,21 +1996,9 @@ __do_global_dtors ()
#ifdef DO_GLOBAL_DTORS_BODY
DO_GLOBAL_DTORS_BODY;
#else
- unsigned nptrs = (unsigned HOST_WIDE_INT) __DTOR_LIST__[0];
- unsigned i;
-
- /* Some systems place the number of pointers
- in the first word of the table.
- On other systems, that word is -1.
- In all cases, the table is null-terminated. */
-
- /* If the length is not recorded, count up to the null. */
- if (nptrs == -1)
- for (nptrs = 0; __DTOR_LIST__[nptrs + 1] != 0; nptrs++);
-
- /* GNU LD format. */
- for (i = nptrs; i >= 1; i--)
- __DTOR_LIST__[i] ();
+ func_ptr *p;
+ for (p = __DTOR_LIST__ + 1; *p; )
+ (*p++) ();
#endif
}
@@ -2096,7 +2085,7 @@ extern void __do_global_dtors ();
extern void _cleanup ();
extern void _exit () __attribute__ ((noreturn));
-void
+void
exit (status)
int status;
{
@@ -2149,3 +2138,162 @@ func_ptr __CTOR_LIST__[2];
#include "gbl-ctors.h"
func_ptr __DTOR_LIST__[2];
#endif
+
+#ifdef L_eh
+typedef struct {
+ void *start;
+ void *end;
+ void *exception_handler;
+} exception_table;
+
+struct exception_table_node {
+ exception_table *table;
+ void *start;
+ void *end;
+ struct exception_table_node *next;
+};
+
+static int except_table_pos = 0;
+static void *except_pc = (void *)0;
+static struct exception_table_node *exception_table_list = 0;
+
+static exception_table *
+find_exception_table (pc)
+ void* pc;
+{
+ register struct exception_table_node *table = exception_table_list;
+ for ( ; table != 0; table = table->next)
+ {
+ if (table->start <= pc && table->end > pc)
+ return table->table;
+ }
+ return 0;
+}
+
+/* this routine takes a pc, and the address of the exception handler associated
+ with the closest exception table handler entry associated with that PC,
+ or 0 if there are no table entries the PC fits in. The algorithm works
+ something like this:
+
+ while(current_entry exists) {
+ if(current_entry.start < pc )
+ current_entry = next_entry;
+ else {
+ if(prev_entry.start <= pc && prev_entry.end > pc) {
+ save pointer to prev_entry;
+ return prev_entry.exception_handler;
+ }
+ else return 0;
+ }
+ }
+ return 0;
+
+ Assuming a correctly sorted table (ascending order) this routine should
+ return the tighest match...
+
+ In the advent of a tie, we have to give the last entry, as it represents
+ an inner block.
+ */
+
+
+void *
+__find_first_exception_table_match(pc)
+void *pc;
+{
+ exception_table *table = find_exception_table (pc);
+ int pos = 0;
+ int best = 0;
+ if (table == 0)
+ return (void*)0;
+#if 0
+ printf("find_first_exception_table_match(): pc = %x!\n",pc);
+#endif
+
+ except_pc = pc;
+
+#if 0
+ /* We can't do this yet, as we don't know that the table is sorted. */
+ do {
+ ++pos;
+ if (table[pos].start > except_pc)
+ /* found the first table[pos].start > except_pc, so the previous
+ entry better be the one we want! */
+ break;
+ } while(table[pos].exception_handler != (void*)-1);
+
+ --pos;
+ if (table[pos].start <= except_pc && table[pos].end > except_pc)
+ {
+ except_table_pos = pos;
+#if 0
+ printf("find_first_eh_table_match(): found match: %x\n",table[pos].exception_handler);
+#endif
+ return table[pos].exception_handler;
+ }
+#else
+ while (table[++pos].exception_handler != (void*)-1) {
+ if (table[pos].start <= except_pc && table[pos].end > except_pc)
+ {
+ /* This can apply. Make sure it is better or as good as the previous
+ best. */
+ /* The best one ends first. */
+ if (best == 0 || (table[pos].end <= table[best].end
+ /* The best one starts last. */
+ && table[pos].start >= table[best].start))
+ best = pos;
+ }
+ }
+ if (best != 0)
+ return table[best].exception_handler;
+#endif
+
+#if 0
+ printf("find_first_eh_table_match(): else: returning NULL!\n");
+#endif
+ return (void*)0;
+}
+
+int
+__throw_type_match (const char *catch_type, const char *throw_type)
+{
+#if 0
+ printf("__throw_type_match (): catch_type = %s, throw_type = %s\n",
+ catch_type, throw_type);
+#endif
+ return strcmp (catch_type, throw_type);
+}
+
+void
+__register_exceptions (exception_table *table)
+{
+ struct exception_table_node *node = (struct exception_table_node*)
+ malloc (sizeof (struct exception_table_node));
+ exception_table *range = table + 1;
+ node->table = table;
+
+ /* This look can be optimized away either if the table
+ is sorted, or if we pass in extra parameters. */
+ node->start = range->start;
+ node->end = range->end;
+ for (range++ ; range->start != (void*)(-1); range++)
+ {
+ if (range->start < node->start)
+ node->start = range->start;
+ if (range->end < node->end)
+ node->end = range->end;
+ }
+
+ node->next = exception_table_list;
+ exception_table_list = node;
+}
+#endif /* L_eh */
+
+#ifdef L_pure
+#define MESSAGE "pure virtual method called\n"
+void
+__pure_virtual ()
+{
+ write (2, MESSAGE, sizeof (MESSAGE) - 1);
+ _exit (-1);
+}
+#endif
diff --git a/gnu/usr.bin/cpio/COPYING b/gnu/usr.bin/cpio/COPYING
new file mode 100644
index 0000000..a43ea21
--- /dev/null
+++ b/gnu/usr.bin/cpio/COPYING
@@ -0,0 +1,339 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 675 Mass Ave, Cambridge, MA 02139, USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ Appendix: How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) 19yy <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) 19yy name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/gnu/usr.bin/cpio/COPYING.LIB b/gnu/usr.bin/cpio/COPYING.LIB
new file mode 100644
index 0000000..eb685a5
--- /dev/null
+++ b/gnu/usr.bin/cpio/COPYING.LIB
@@ -0,0 +1,481 @@
+ GNU LIBRARY GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1991 Free Software Foundation, Inc.
+ 675 Mass Ave, Cambridge, MA 02139, USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the library GPL. It is
+ numbered 2 because it goes with version 2 of the ordinary GPL.]
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+ This license, the Library General Public License, applies to some
+specially designated Free Software Foundation software, and to any
+other libraries whose authors decide to use it. You can use it for
+your libraries, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if
+you distribute copies of the library, or if you modify it.
+
+ For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you. You must make sure that they, too, receive or can get the source
+code. If you link a program with the library, you must provide
+complete object files to the recipients so that they can relink them
+with the library, after making changes to the library and recompiling
+it. And you must show them these terms so they know their rights.
+
+ Our method of protecting your rights has two steps: (1) copyright
+the library, and (2) offer you this license which gives you legal
+permission to copy, distribute and/or modify the library.
+
+ Also, for each distributor's protection, we want to make certain
+that everyone understands that there is no warranty for this free
+library. If the library is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original
+version, so that any problems introduced by others will not reflect on
+the original authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that companies distributing free
+software will individually obtain patent licenses, thus in effect
+transforming the program into proprietary software. To prevent this,
+we have made it clear that any patent must be licensed for everyone's
+free use or not licensed at all.
+
+ Most GNU software, including some libraries, is covered by the ordinary
+GNU General Public License, which was designed for utility programs. This
+license, the GNU Library General Public License, applies to certain
+designated libraries. This license is quite different from the ordinary
+one; be sure to read it in full, and don't assume that anything in it is
+the same as in the ordinary license.
+
+ The reason we have a separate public license for some libraries is that
+they blur the distinction we usually make between modifying or adding to a
+program and simply using it. Linking a program with a library, without
+changing the library, is in some sense simply using the library, and is
+analogous to running a utility program or application program. However, in
+a textual and legal sense, the linked executable is a combined work, a
+derivative of the original library, and the ordinary General Public License
+treats it as such.
+
+ Because of this blurred distinction, using the ordinary General
+Public License for libraries did not effectively promote software
+sharing, because most developers did not use the libraries. We
+concluded that weaker conditions might promote sharing better.
+
+ However, unrestricted linking of non-free programs would deprive the
+users of those programs of all benefit from the free status of the
+libraries themselves. This Library General Public License is intended to
+permit developers of non-free programs to use free libraries, while
+preserving your freedom as a user of such programs to change the free
+libraries that are incorporated in them. (We have not seen how to achieve
+this as regards changes in header files, but we have achieved it as regards
+changes in the actual functions of the Library.) The hope is that this
+will lead to faster development of free libraries.
+
+ The precise terms and conditions for copying, distribution and
+modification follow. Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library". The
+former contains code derived from the library, while the latter only
+works together with the library.
+
+ Note that it is possible for a library to be covered by the ordinary
+General Public License rather than by this special one.
+
+ GNU LIBRARY GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License Agreement applies to any software library which
+contains a notice placed by the copyright holder or other authorized
+party saying it may be distributed under the terms of this Library
+General Public License (also called "this License"). Each licensee is
+addressed as "you".
+
+ A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+ The "Library", below, refers to any such software library or work
+which has been distributed under these terms. A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language. (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+ "Source code" for a work means the preferred form of the work for
+making modifications to it. For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+ Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it). Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+
+ 1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+ You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+
+ 2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) The modified work must itself be a software library.
+
+ b) You must cause the files modified to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ c) You must cause the whole of the work to be licensed at no
+ charge to all third parties under the terms of this License.
+
+ d) If a facility in the modified Library refers to a function or a
+ table of data to be supplied by an application program that uses
+ the facility, other than as an argument passed when the facility
+ is invoked, then you must make a good faith effort to ensure that,
+ in the event an application does not supply such function or
+ table, the facility still operates, and performs whatever part of
+ its purpose remains meaningful.
+
+ (For example, a function in a library to compute square roots has
+ a purpose that is entirely well-defined independent of the
+ application. Therefore, Subsection 2d requires that any
+ application-supplied function or table used by this function must
+ be optional: if the application does not supply it, the square
+ root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library. To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License. (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.) Do not make any other change in
+these notices.
+
+ Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+ This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+ 4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+ If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library". Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+ However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library". The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+ When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library. The
+threshold for this to be true is not precisely defined by law.
+
+ If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work. (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+ Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+
+ 6. As an exception to the Sections above, you may also compile or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+ You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License. You must supply a copy of this License. If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License. Also, you must do one
+of these things:
+
+ a) Accompany the work with the complete corresponding
+ machine-readable source code for the Library including whatever
+ changes were used in the work (which must be distributed under
+ Sections 1 and 2 above); and, if the work is an executable linked
+ with the Library, with the complete machine-readable "work that
+ uses the Library", as object code and/or source code, so that the
+ user can modify the Library and then relink to produce a modified
+ executable containing the modified Library. (It is understood
+ that the user who changes the contents of definitions files in the
+ Library will not necessarily be able to recompile the application
+ to use the modified definitions.)
+
+ b) Accompany the work with a written offer, valid for at
+ least three years, to give the same user the materials
+ specified in Subsection 6a, above, for a charge no more
+ than the cost of performing this distribution.
+
+ c) If distribution of the work is made by offering access to copy
+ from a designated place, offer equivalent access to copy the above
+ specified materials from the same place.
+
+ d) Verify that the user has already received a copy of these
+ materials or that you have already sent this user a copy.
+
+ For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it. However, as a special exception,
+the source code distributed need not include anything that is normally
+distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+ It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system. Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+
+ 7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+ a) Accompany the combined library with a copy of the same work
+ based on the Library, uncombined with any other library
+ facilities. This must be distributed under the terms of the
+ Sections above.
+
+ b) Give prominent notice with the combined library of the fact
+ that part of it is a work based on the Library, and explaining
+ where to find the accompanying uncombined form of the same work.
+
+ 8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License. Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License. However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+ 9. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Library or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+ 10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all. For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded. In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+ 13. The Free Software Foundation may publish revised and/or new
+versions of the Library General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation. If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+
+ 14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission. For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this. Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+ NO WARRANTY
+
+ 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ Appendix: How to Apply These Terms to Your New Libraries
+
+ If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change. You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+ To apply these terms, attach the following notices to the library. It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the library's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the
+ library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+ <signature of Ty Coon>, 1 April 1990
+ Ty Coon, President of Vice
+
+That's all there is to it!
diff --git a/gnu/usr.bin/cpio/ChangeLog b/gnu/usr.bin/cpio/ChangeLog
new file mode 100644
index 0000000..9b18d4f
--- /dev/null
+++ b/gnu/usr.bin/cpio/ChangeLog
@@ -0,0 +1,781 @@
+Mon Jul 5 14:54:08 1993 John Oleynick (juo@spiff.gnu.ai.mit.edu)
+
+ * cpio.1: Updated man page for 2.3.
+ * Makefile.in: Create distribution with .gz extension, instead of .z.
+
+Tue Jun 29 18:54:37 1993 John Oleynick (juo@goldman.gnu.ai.mit.edu)
+
+ * Makefile.in: Added installdirs target (using mkinstalldirs).
+ * Added mkinstalldirs script.
+ * main.c, mt.c: Added --help option. Changed usage() to
+ take a stream and exit value (so --help can print on stdout
+ and return a 0 exit status).
+ * extern.h: Removed usage()'s prototype (it was out of date,
+ and only used in main.c).
+
+Thu May 6 00:22:22 1993 John Oleynick (juo@hal.gnu.ai.mit.edu)
+
+ * cpio.1: Added hpbin and hpodc.
+
+Tue May 4 00:32:29 1993 John Oleynick (juo@hal.gnu.ai.mit.edu)
+
+ * copyin.c (process_copy_in), copypass.c (process_copy_pass): When
+ deleting an existing file, if the file is a directory, use rmdir()
+ instead of unlink().
+
+Thu Apr 29 14:43:56 1993 John Oleynick (juo@goldman.gnu.ai.mit.edu)
+
+ * tar.c (read_in_tar_header): Clear non-protection bits from
+ mode, in case tar has left some device bits in there.
+
+Wed Apr 28 10:36:53 1993 John Oleynick (juo@goldman.gnu.ai.mit.edu)
+
+ * util.c: Added code to try and work around broken tape drivers
+ that have problems with tapes > 2Gb.
+
+ * copyout.c (process_copy_out): Pass file_hdr to
+ writeout_other_defers() and add_link_defer() by reference,
+ not by value.
+
+ * copyin.c (process_copy_in): Pass file_hdr to defer_copyin()
+ and create_defered_links() by reference, not by value.
+
+ * defer.c: include <sys/types.h> (to build on BSD 4.3 on HP300)
+
+Fri Apr 16 18:01:17 1993 John Oleynick (juo@goldman.gnu.ai.mit.edu)
+
+ * mt.c, util.c: Include <sys/mtio.h> if HAVE_SYS_MTIO_H is
+ defined, not HAVE_MTIO_H.
+
+Wed Apr 14 17:37:46 1993 John Oleynick (juo@goldman.gnu.ai.mit.edu)
+
+ * util.c: Include <sys/io/trioctl.h> if HAVE_SYS_IO_TRIOCTL_H
+ is defined.
+
+ * mt.c: Only include <sys/mtio.h> if HAVE_SYS_MTIO_H is defined.
+
+Fri Apr 2 13:09:11 1993 John Oleynick (juo@goldman.gnu.ai.mit.edu)
+
+ * configure.in: Added fnmatch to AC_REPLACE_FUNCS. Added
+ sys/io/trioctl.h to AC_HAVE_HEADERS.
+
+ * Makefile.in: Removed fnmatch.o from OBJS.
+
+ * copyin.c: Only include "fnmatch.h" if FNM_PATHNAME isn't
+ defined yet.
+
+ * mt.c: Include <sys/io/trioctl.h> if HAVE_SYS_IO_TRIOCTL_H is
+ defined.
+
+Mon Mar 29 17:04:06 1993 John Oleynick (juo@hal.gnu.ai.mit.edu)
+
+ * Many changes for supporting HPUX Context Dependent Files;
+ also some bug fixes to fix problems with multiply (hard) linked
+ device files; minor changes to support HPUX format archives
+ (slightly broken?) System V.4 posix tar archives and HPUX
+ posix tar archives.
+
+ * Makefile.in: New files defer.o, defer,c and defer.h; added
+ -DSYMLINK_USES_UMASK and -DHPUX_CDF comments; changed dist rule
+ to use gzip with tar, instead of compress.
+
+ * copyin.c: changes for new arf_hpbinary and arf_hpascii formats;
+ HPUX CDF's; DEBUG_CPIO; fixes to properly handle multiple
+ links in newc and crc format archives (new routines defer_copyin(),
+ create_defered_links(), create_final_defers()); move most
+ multiple (hard) link code to new routines link_name() and
+ link_to_maj_min_ino(); use new macro UMASKED_SYMLINK instead of
+ symlink().
+
+ * copyout.c: fixes to properly handle multiple links in newc
+ and crc format archives (new routines last_link(),
+ count_defered_links_to_dev_ino(), add_link_defer(),
+ writeout_other_defers(), writeout_final_defers(),
+ writeout_defered_file()); support for new arf_hpbinary and
+ arf_hpascii formats; support for HPUX CDF's.
+
+ * copypass.c: move most multiple link code to new routines
+ link_name() and link_to_maj_min_ino(); use new macro UMASKED_SYMLINK
+ instead of symlink(); support for HPUX CDF's.
+
+ * extern.h: added arf_hpascii and arf_hpbinary archive enum types;
+ added debug_flag.
+
+ * global.c: added debug_flag.
+
+ * main.c: added debug_flag; support for hpodc and hpbin formats.
+
+ * makepath.c: split from standard makpath.c to add support
+ for HPUX CDF's.
+
+ * mt.c: added !defined(__osf__) (from Andrew Marquis
+ <amarquis@genome.wi.mit.edu>).
+
+ * system.h: new macro UMASKED_SYMLINK
+
+ * tar.c: minor changes to read (slightly broken?) System V.4 posix
+ tar archives and HPUX posix tar archives.
+
+ * util.c: HPUX CDF support (including new routines
+ add_cdf_double_slashes() and islasparentcdf()); new routine
+ umasked_symlink().
+
+Sun Mar 14 23:00:14 1993 Jim Meyering (meyering@comco.com)
+
+ * copypass.c (process_copy_pass): Use <=, not just <, when comparing
+ mtimes. From Pieter Bowman <bowman@math.utah.edu>.
+
+Fri Jan 15 14:35:37 1993 David J. MacKenzie (djm@kropotkin.gnu.ai.mit.edu)
+
+ * copyin.c: Move include of fnmatch.h to get right FNM* macros.
+
+Tue Nov 24 08:45:32 1992 David J. MacKenzie (djm@goldman.gnu.ai.mit.edu)
+
+ * Version 2.2.
+
+ * copyout.c (process_copy_out): Add parens for gcc -Wall.
+ From Jim Meyering.
+
+ * system.h: Use HAVE_FCNTL_H, not USG.
+
+ * dstring.c, mt.c, system.h: Use HAVE_STRING_H, not USG.
+
+Fri Nov 20 22:47:18 1992 David J. MacKenzie (djm@goldman.gnu.ai.mit.edu)
+
+ * copyin.c (read_in_binary): Copy the dev and ino that are
+ already in `file_hdr' into `short_hdr'.
+ From dao@abars.att.com (David A Oshinsky).
+
+ * system.h [!_POSIX_VERSION]: Declare lseek as off_t, not long.
+ From Karl Berry.
+
+Wed Oct 14 13:53:41 1992 David J. MacKenzie (djm@goldman.gnu.ai.mit.edu)
+
+ * Version 2.1.
+
+Tue Oct 13 22:51:34 1992 David J. MacKenzie (djm@goldman.gnu.ai.mit.edu)
+
+ * main.c: Add --swap equivalent to -b.
+
+ * mt.c: Add f_force_local variable and -V --version option.
+
+Fri Oct 2 18:42:27 1992 David J. MacKenzie (djm@kropotkin.gnu.ai.mit.edu)
+
+ * main.c (long_opts, usage): Add --force-local option.
+
+Thu Oct 1 23:23:43 1992 David J. MacKenzie (djm@goldman.gnu.ai.mit.edu)
+
+ * main.c (process_args) [__MSDOS__]: Don't call geteuid.
+
+ * copyin.c (read_in_{old,new}_ascii): Use `l' for sscanf into longs.
+ * copyout.c (write_out_header): Ditto for sprintf.
+ * global.c, extern.h: Make input_size and output_size long.
+
+Thu Sep 10 23:39:30 1992 David J. MacKenzie (djm@nutrimat.gnu.ai.mit.edu)
+
+ * global.c, extern.h: Add new var f_force_local to work with
+ rmt.h change from tar.
+
+Sun Aug 23 00:18:20 1992 David J. MacKenzie (djm@churchy.gnu.ai.mit.edu)
+
+ * Version 2.0.
+
+ * tar.c (otoa): Compute value in an unsigned long, not an int.
+ * copyout.c (write_out_header) [__MSDOS__]: Don't use dev_t.
+
+ * main.c (process_args): By default, don't chown for non-root users.
+
+Sat Aug 22 14:17:54 1992 David J. MacKenzie (djm@nutrimat.gnu.ai.mit.edu)
+
+ * global.c, extern.h: Use uid_t and gid_t.
+
+ * main.c (main) [__EMX__]: Expand wildcards.
+ * system.h [__EMX__]: Alias some error names. From Kai Uwe Rommel.
+
+ * extern.h [__STDC__]: Use prototypes.
+
+ * copyin.c (process_copy_in), copyout.c (process_copy_out),
+ copypass.c (process_copy_pass): Open all files with O_BINARY.
+ Add cast to chmod call.
+ * util.c: Add cast to bcopy calls. Make hash_insert static.
+ From Kai Uwe Rommel.
+
+Thu Aug 20 22:03:49 1992 David J. MacKenzie (djm@nutrimat.gnu.ai.mit.edu)
+
+ * util.c (peek_in_buf): Don't print "end of file" before
+ getting the next reel of medium.
+
+ * copyin.c (read_in_old_ascii): Allocate space for NUL terminator.
+ Print newline for dot line when done, even if appending.
+
+Thu Jul 23 16:34:53 1992 David J. MacKenzie (djm@nutrimat.gnu.ai.mit.edu)
+
+ * tar.c (write_out_tar_header, read_in_tar_header)
+ [__MSDOS__]: Don't try to get user and group names.
+ * extern.h: Don't declare the functions to do it (need uid_t).
+
+ * main.c [__MSDOS__]: Ignore the -R option.
+
+ * system.h: Define makedev if defining major and minor.
+
+ * copyin.c, copyout.c [__MSDOS__]: setmode on archive_des, not
+ 0 and 1.
+
+Sat Jul 18 14:30:55 1992 David J. MacKenzie (djm@nutrimat.gnu.ai.mit.edu)
+
+ * tar.c, stripslash.c, userspec.c, cpiohdr.h, tar.h, tarhdr.h,
+ system.h: New files.
+ * Move portability stuff from various files to system.h.
+ * cpio.h: Rename header structure and members, and add
+ new structure for SVR4 format.
+ * copyin.c, copyout.c: Use the new structure internally, the
+ old one only for I/O in the old formats.
+ * copyin.c (read_in_header): Recognize the new archive formats.
+ (read_in_new_ascii, read_pattern_file, skip_padding): New functions.
+ (swab_array): Do the swapping using char pointers instead of
+ bitwise arithmetic.
+ (process_copy_in): Handle byte and halfword swapping and new formats.
+ Ok if a directory we want to make already exists, but set its perms.
+ Do chmod after chown to fix any set[ug]id bits.
+ Use `struct utimbuf' instead of a long array.
+ * copyout.c (write_out_header): Handle new formats.
+ (process_copy_out): Use `struct utimbuf'.
+ Handle appending and new formats.
+ Remove any leading `./' from filenames.
+ (read_for_checksum, clear_rest_of_block, pad_output): New functions.
+ * copypass.c (process_copy_pass): Use `struct utimbuf'.
+ Ok if a directory we want to make already exists, but set its perms.
+ Do chmod after chown to fix any set[ug]id bits.
+ Don't change perms of `.'.
+ * extern.h, global.c: Replace the separate format flags with
+ one variable. Add new variables for the new options.
+ * main.c: Add new options -A --append, -H --format, -C --io-size,
+ -M --message, --no-preserve-owner, -R --owner, -E --pattern-file,
+ -V --dot, -s --swap-bytes, -S --swap-halfwords, -b, -I, -k, -O.
+ (usage): Document them.
+ (process_args): Recognize them. Use open_archive.
+ (initialize_buffers): Allow room for tar archives and double buffers.
+ * util.c (empty_output_buffer_swap): New function.
+ (empty_output_buffer): Call it if swapping current file.
+ Check additional end of media indicators.
+ (swahw_array, peek_in_buf, prepare_append, open_archive,
+ set_new_media_message): New functions.
+ (fill_input_buffer): Don't print error message if end of media.
+ (toss_input): Don't seek, always read.
+ (copy_files): Update crc if needed.
+ (find_inode_file, add_inode): Check major and minor numbers as
+ well as dev.
+ (get_next_reel): Prompt user if archive name is unknown.
+ Print fancy messages.
+ Close the archive and reopen it.
+
+ Above primarily from John Oleynick <juo@klinzhai.rutgers.edu>.
+
+ * util.c (find_inode_file): Use modulus when computing initial
+ loop index.
+ (add_inode): Zero out new entry.
+ From scott@sctc.com (Scott Hammond).
+
+ * cpio.h, copyin.c, copyout.c: Rename `struct cpio_header'
+ members from h_foo to c_foo.
+
+Wed May 20 00:09:26 1992 David J. MacKenzie (djm@churchy.gnu.ai.mit.edu)
+
+ * copyin.c: If we include a header file specifically to get
+ major et al., assume we have them.
+
+Mon Mar 9 19:29:20 1992 David J. MacKenzie (djm@nutrimat.gnu.ai.mit.edu)
+
+ * mt.c (main): rmtclose the tape file descriptor.
+
+ * main.c (main): rmtclose the archive, if not in copy-pass mode.
+
+ * util.c (create_all_directories): Don't print a message when
+ creating a directory, for UNIX compat.
+
+ * copyin.c (process_copy_in), copypass.c (process_copy_pass):
+ Skip file if it has the same timestamp as existing file, not just
+ if it is older than existing file, for UNIX compat.
+
+Tue Mar 3 12:06:58 1992 David J. MacKenzie (djm@wookumz.gnu.ai.mit.edu)
+
+ * main.c, mt.c (usage): Document long options as starting with
+ -- instead of +.
+
+ * extern.h: Only declare lseek if not _POSIX_VERSION.
+
+Tue Dec 24 00:19:45 1991 David J. MacKenzie (djm at wookumz.gnu.ai.mit.edu)
+
+ * copyin.c: Use MAJOR_IN_MKDEV and MAJOR_IN_SYSMACROS instead
+ of USG and _POSIX_VERSION to find major and minor macros.
+
+ * mt.c: Use unistd.h and stdlib.h if available.
+
+ * copyin.c, copyout.c, copypass.c, util.c, extern.h: Change
+ POSIX ifdefs to HAVE_UNISTD_H and _POSIX_VERSION.
+
+Sun Aug 25 06:31:08 1991 David J. MacKenzie (djm at apple-gunkies)
+
+ * Version 1.5.
+
+ * bcopy.c: New file (moved from util.c).
+
+ * mt.c (print_status): Not all hpux machines have mt_fileno
+ and mt_blkno; rather than trying to track HP's product line,
+ just assume none of them have them.
+
+ * util.c (copy_buf_out, copy_in_buf): Use more efficient
+ copying technique for a big speedup.
+
+Fri Aug 2 04:06:45 1991 David J. MacKenzie (djm at apple-gunkies)
+
+ * configure: Support +srcdir. Create config.status.
+ Remove it and Makefile if interrupted while creating them.
+
+Thu Jul 18 09:43:40 1991 David J. MacKenzie (djm at wookumz.gnu.ai.mit.edu)
+
+ * Many files: use __MSDOS__ instead of MSDOS.
+
+ * util.c, configure: Use NO_MTIO instead of HAVE_MTIO, to keep
+ up with tar and rtapelib.c.
+
+Mon Jul 15 13:45:30 1991 David J. MacKenzie (djm at wookumz.gnu.ai.mit.edu)
+
+ * configure: Also look in sys/signal.h for signal decl.
+
+Thu Jul 11 01:50:32 1991 David J. MacKenzie (djm at wookumz.gnu.ai.mit.edu)
+
+ * Version 1.4.
+
+ * configure: Remove /etc and /usr/etc from PATH to avoid
+ finding /etc/install.
+
+Wed Jul 10 01:40:07 1991 David J. MacKenzie (djm at wookumz.gnu.ai.mit.edu)
+
+ * makefile.pc: Rewrite for Turbo C 2.0.
+ * util.c [__TURBOC__] (utime): New function.
+ * alloca.c, tcexparg.c: New files.
+
+ * extern.h [STDC_HEADERS]: Don't declare malloc and realloc.
+
+ * main.c [MSDOS]: Make binary mode the default.
+ * copyin.c, copyout.c: Make stdin or stdout binary mode as
+ appropriate (so cpio archives don't get corrupted).
+
+ * Many files: Use <string.h> if STDC_HEADERS as well as if USG.
+
+ * configure, Makefile.in: $(INSTALLPROG) -> $(INSTALL),
+ $(INSTALLTEXT) -> $(INSTALLDATA).
+
+Mon Jul 8 23:18:28 1991 David J. MacKenzie (djm at wookumz.gnu.ai.mit.edu)
+
+ * configure: For some library functions that might be missing,
+ conditionally add the .o files to Makefile instead of
+ defining func_MISSING.
+ * mkdir.c: Renamed from mkrmdir.c.
+
+Sat Jul 6 02:27:22 1991 David J. MacKenzie (djm at geech.gnu.ai.mit.edu)
+
+ * configure: echo messages to stdout, not stderr.
+ Use a test program to see if alloca needs -lPW.
+
+Thu Jun 27 16:15:15 1991 David J. MacKenzie (djm at geech.gnu.ai.mit.edu)
+
+ * copyin.c (process_copy_in), copyout.c (process_copy_out),
+ copypass.c (process_copy_pass): Check close return value for
+ delayed error notification because of NFS.
+
+Thu Jun 20 02:43:33 1991 David J. MacKenzie (djm at geech.gnu.ai.mit.edu)
+
+ * configure: Include $DEFS when compiling test programs.
+
+ * util.c: Only declare getpwuid and getgrgid if not POSIX.
+
+ * Version 1.3.
+
+ * copyin.c: Use time_t, not long, for time values.
+
+ * mt.c (print_status): Special cases for HP-UX and Ultrix.
+
+ * util.c: Compile bcopy if USG or STDC_HEADERS, not BCOPY_MISSING.
+
+Tue Jun 11 16:40:02 1991 David J. MacKenzie (djm at geech.gnu.ai.mit.edu)
+
+ * copyin.c: Don't include sys/sysmacros.h if _POSIX_SOURCE.
+
+ * copyin.c, copyout.c, copypass.c: Don't include sys/file.h if POSIX.
+
+ * util.c: Include sys/types.h before, not after, pwd.h and grp.h.
+
+ * configure: New shell script to aid configuration and create
+ Makefile from Makefile.in.
+
+ * copyin.c (process_copy_in): Use POSIX.2 fnmatch instead of
+ glob_match.
+
+Mon Jun 10 22:11:19 1991 David J. MacKenzie (djm at geech.gnu.ai.mit.edu)
+
+ * global.c, extern.h: New variable, name_end.
+ * main.c (process_args, usage): Add -0 +null option to set it.
+ * copypass.c (process_copy_pass), copyout.c (process_copy_out):
+ Use it.
+
+ * dstring.c (ds_fgetstr): New function made from ds_fgets.
+ (ds_fgets, ds_fgetname): Implement as front ends to ds_fgetstr.
+
+Sun Jun 2 15:45:24 1991 David J. MacKenzie (djm at wheat-chex)
+
+ * most files: use GPL version 2.
+
+Sat May 18 11:39:22 1991 David J. MacKenzie (djm at geech.gnu.ai.mit.edu)
+
+ * copyin.c, copypass.c: Take out #ifdef MSDOS around chown.
+ * util.c [MSDOS]: Provide dummy chown.
+
+Fri May 17 21:29:05 1991 David J. MacKenzie (djm at churchy.gnu.ai.mit.edu)
+
+ * Version 1.2.
+
+ * makefile.pc, cpio.cs: Update for new source and object files.
+
+Fri Mar 15 05:48:36 1991 David J. MacKenzie (djm at geech.ai.mit.edu)
+
+ * global.c, extern.h: New variable `archive_desc'.
+ * main.c (process_args): Set it.
+ * copyout.c (process_copy_out), copyin.c (process_copy_in):
+ Use it.
+
+ * copyout.c (process_copy_out), copyin.c (process_copy_in):
+ Remote tapes are special and not seekable; don't fstat them.
+
+ * main.c (main, usage): Add -F, +file option. Use rmtopen.
+ (main): Exit after printing version number.
+ * util.c (empty_output_buffer): Use rmtwrite instead of write.
+ (fill_input_buffer): Use rmtread instead of read.
+ (tape_offline): Use rmtioctl instead of ioctl.
+ Test HAVE_MTIO instead of MTIO_MISSING, for tar compatibility.
+
+Thu Mar 14 17:49:57 1991 David J. MacKenzie (djm at geech.ai.mit.edu)
+
+ * util.c (create_all_directories): Use make_path to do the work.
+
+Sat Jan 12 15:32:15 1991 David J. MacKenzie (djm at geech.ai.mit.edu)
+
+ * copyin.c, copyout.c, copypass.c, util.c: Only declare
+ `errno' if not MSDOS. Some Unix errno.h do, some don't . . . .
+
+ * global.c, extern.h: Make `input_size' and `output_size'
+ unsigned, for 16 bit machines.
+
+ * copyin.c (print_name_with_quoting): All non-ctrl chars are
+ printable on MS-DOS.
+
+ * util.c (empty_output_buffer): Never make sparse files;
+ can create unrunnable executables.
+ * copyin.c, copyout.c, copypass.c: Callers changed.
+ * util.c (finish_output_file): Function removed.
+
+Tue Nov 6 15:47:16 1990 David J. MacKenzie (djm at apple-gunkies)
+
+ * copyin.c, util.c, extern.h: Rename copystring to xstrdup.
+
+Mon Oct 29 02:24:41 1990 David J. MacKenzie (djm at apple-gunkies)
+
+ * util.c (empty_output_buffer): Only make sparse files if
+ NO_SPARSE_FILES is undefined, to accomodate dumb kernels.
+
+Wed Jul 25 18:48:35 1990 David J. MacKenzie (djm at albert.ai.mit.edu)
+
+ * util.c (getuser, getgroup): Make uid and gid unsigned short,
+ not int.
+
+Sat Jul 21 00:44:44 1990 David J. MacKenzie (djm at apple-gunkies)
+
+ * copyin.c, copyout.c, copypass.c, util.c, cpio.h: Add ifdefs
+ for MSDOS.
+
+Sun Jul 15 23:51:48 1990 David J. MacKenzie (djm at albert.ai.mit.edu)
+
+ * copyin.c, copyout.c, copypass.c, global.c, extern.h, util.c:
+ Use longs where appropriate, for 16 bit machines.
+
+Sun Jul 8 22:58:06 1990 David J. MacKenzie (djm at apple-gunkies)
+
+ * main.c (process_args, usage): Change -b option to -O (old), to
+ allow adding byte swapping later.
+
+Sat Jul 7 14:48:35 1990 David J. MacKenzie (dave at edfmd)
+
+ * Version 1.1.
+
+ * cpio.h: Make `mtime' and `filesize' unsigned long.
+ * copyin.c (read_in_binary), copyout.c (write_out_header):
+ High short-word of `mtime' and `filesize' always comes first.
+
+ * (read_in_ascii, read_in_binary): New functions, from code in
+ read_in_header.
+ (read_in_header): Search for valid magic number, then fill in
+ rest of header using read_in_ascii and read_in_binary.
+ * global.c, extern.h: New variable, `binary_flag'.
+ * main.c (process_args): Recognize new -b +binary option.
+ * util.c [BCOPY_MISSING] (bcopy): New function.
+
+Wed Jul 4 00:40:58 1990 David J. MacKenzie (djm at apple-gunkies)
+
+ * main.c (process_args): Add local pointers to functions to
+ work around a pcc bug found on a Convex.
+
+ * copyin.c (process_copy_in), util.c (toss_input,
+ create_all_directories, add_inode): Don't use `index' as a
+ variable name.
+
+Tue Jul 3 02:33:36 1990 David J. MacKenzie (djm at apple-gunkies)
+
+ * version 1.0.
+
+Mon Jul 2 23:18:56 1990 David J. MacKenzie (djm at twiddle)
+
+ * copyin.c (process_copy_in), copyout.c (process_copy_out),
+ copypass.c (process_copy_pass): Print "1 block", not "1 blocks".
+
+ * copyin.c (process_copy_in), copypass.c (process_copy_pass):
+ Unlink existing dest. file unless either it is newer and
+ not unconditional, or it is a directory.
+
+Mon Jul 2 03:57:41 1990 David J. MacKenzie (dave at edfmd)
+
+ * util.c (xrealloc): New function.
+ * dstring.c (ds_resize): Use xrealloc instead of free and
+ xmalloc. Never shrink the string.
+
+ * copypass.c (process_copy_pass): More efficient
+ string handling while constructing output filename.
+
+ * global.c, extern.h, main.c, cpio.h: Change from an enum,
+ `copy_command', to a pointer to a void function, `copy_function'.
+
+ * cpio.h (struct cpio_header): Make most fields unsigned.
+ Rename h_filesize to h_filesizes and h_mtime to h_mtimes, and
+ add new `long' fields with the old names at the end of the
+ structure.
+ * copyin.c (read_in_header): Set the long fields from the
+ short arrays, making sure longs are aligned properly.
+ (process_copy_in, long_format): Use the long fields.
+ * copyout.c (write_out_header): Set the short arrays from the
+ long fields, making sure longs are aligned properly.
+ (process_copy_out): Use the long fields.
+
+ * global.c, extern.h: New variable `output_is_seekable'.
+ * util.c (empty_output_buffer): If output_is_seekable, use
+ lseek to write blocks of zeros.
+ (finish_output_file): New function.
+ * copyin.c (process_copy_in), copyout.c (process_copy_out),
+ copypass.c (process_copy_pass): Set `output_is_seekable'
+ correctly and call finish_output_file.
+ * main.c (initialize_buffers): Allocate space for sentinel in
+ `output_buffer'.
+
+ * global.c, extern.h: New variable `numeric_uid'.
+ * main.c (process_args): Accept -n +numeric-uid-gid option, like ls.
+ * copyin.c (long_format): Use numeric_uid.
+
+ * copyin.c (process_copy_in), copyout.c (process_copy_out),
+ copypass.c (process_copy_pass): Don't (for verbose) print the
+ names of files that are not copied because of errors. Try to
+ create missing directories for all file types. Free temporary
+ buffers on error.
+
+Sat Jun 30 14:28:45 1990 David J. MacKenzie (djm at apple-gunkies)
+
+ * version.c: New file.
+ * main.c: Add -V, +version option.
+ * Makefile [dist]: Extract version number from version.c.
+
+Sat Jun 30 12:44:47 1990 David J. MacKenzie (dave at edfmd)
+
+ * global.c, extern.h, copyin.c, copyout.c, util.c: Rename
+ `{input,output}_is_regular' to `{input,output}_is_special' and
+ reverse the truth value.
+
+ * global.c, extern.h: New variable `input_is_seekable' to
+ control whether to skip data with lseek or read.
+ * copyin.c (process_copy_in): Set it.
+ * util.c (toss_input): Use it.
+
+ * global.c, extern.h: New variable `xstat' that selects stat
+ or lstat for input files.
+ * main.c (process_args): New option -L, +dereference to set
+ xstat to stat instead of lstat.
+ (usage): Document it.
+ * copyout.c (process_copy_out), copypass.c
+ (process_copy_pass): Use *xstat on input file.
+
+Sat Jun 30 01:53:12 1990 David J. MacKenzie (dave at edfmd)
+
+ * dstring.c (ds_init): Return void because return value was
+ never used.
+ (ds_resize): Ditto, and free old value instead of new one.
+
+ * util.c (empty_output_buffer, fill_input_buffer,
+ copy_out_buf, copy_in_buf, toss_input, copy_files): Return
+ void instead of an error value and make errors fatal
+ immediately instead of several levels up, to prevent printing
+ of multiple error messages by different levels of functions.
+
+ * copyin.c (read_in_header): Return void, because the error
+ handling all happens at lower levels.
+ (print_name_with_quoting): New function.
+ (long_format): Call print_name_with_quoting. Take additional
+ arg for name of linked-to file, and print it if nonzero.
+ (process_copy_in): For verbose listing of symlinks, read in
+ the linkname and pass it to long_format.
+
+ * extern.h: Declare some more functions.
+
+Thu Jun 28 16:07:15 1990 David J. MacKenzie (dave at edfmd)
+
+ * copypass.c (process_copy_pass): Warn about unknown file types.
+
+ * copyout.c (process_copy_out): Check fstat return for error.
+ Record filesize of 0 for special files. Warn about unknown
+ file types.
+
+ * copyin.c (process_copy_in): Warn about unknown file types.
+ (read_in_header): Warn about byte-reversed binary headers.
+
+Sat Jun 23 22:50:45 1990 David J. MacKenzie (dave at edfmd)
+
+ * main.c (main): Set umask to 0 so permissions of created
+ files are preserved.
+
+ * copyin.c, copyout.c, copypass.c, util.c: Pass file
+ descriptors as ints, not pointers to ints.
+ Cast file timestamps and sizes to long *, not int *, for 16
+ bit machines.
+ Use lstat instead of stat, if available.
+ Handle FIFO's, sockets, and symlinks, if supported by O.S.
+
+ * copyin.c (process_copy_in), copyout.c (process_copy_out):
+ Don't consider FIFO'S, sockets, etc. to be possible tape drives.
+
+ * util.c (create_all_directories): Fix incorrect loop
+ termination check. Only copy string if it contains slashes.
+ Don't check whether directory "" exists.
+ (tape_offline): Code moved from get_next_reel.
+ (get_next_reel): Print message before taking tape offline.
+ Read a line of arbitrary length.
+
+ * copyout.c, copyin.c, copypass.c: Always use utime, not utimes.
+
+ * copyin.c (swab_short): New macro.
+ (swab_array): New function.
+ (read_in_header): In binary mode, if a byte-swapped header is
+ read, swap the bytes back.
+ (process_copy_in, process_copy_pass): Don't stat each file to
+ create unless !unconditional_flag. Create device files correctly.
+ Don't temporarily allow files being created to be read by
+ other users. Don't unnecessarily chmod special files.
+
+Thu May 31 20:51:43 1990 David J. MacKenzie (djm at albert.ai.mit.edu)
+
+ * copyin.c (long_format): Use mode_string to format
+ file protections instead of doing it ourselves.
+ (protections): Function removed.
+
+Sat Apr 14 02:31:01 1990 David J. MacKenzie (djm at albert.ai.mit.edu)
+
+ * cpio.h (struct cpio_header): Make inode, mode, uid, gid
+ fields unsigned.
+
+ * util.c (getgroup): New function.
+ * copyin.c (long_format): Print group name of files.
+ Print file size, etc. as unsigned integers, not signed.
+
+ * main.c (process_args): If -t is given and neither -i, -o, or
+ -p is given, assume -i.
+
+ * Add -f, +nonmatching option.
+ * main.c: Rename +out to +create, +in to +extract,
+ +modification-time to +preserve-modification-time,
+ +pass to +pass-through.
+
+ * copyin.c (process_copy_in), copypass.c (process_copy_pass):
+ Don't complain in chown fails because the user doesn't have
+ permission.
+
+Fri Apr 13 13:53:20 1990 David J. MacKenzie (djm at albert.ai.mit.edu)
+
+ * Add ifdefs for USG/Xenix.
+ * util.c (cpio_error): Function removed.
+ * Use error instead of cpio_error, so system error messages
+ will be included.
+ * cpio.h: Rename 'hdr_struct' to 'struct cpio_header'.
+ * Move definition of xmalloc from dstring.c to util.c.
+ * global.c, extern.c: Add global `program_name'.
+ * main.c (main): Set program_name.
+ (process_args): Rename +reset-atime to +reset-access-time,
+ +table to +list.
+ Have +block-size take an argument.
+
+Thu Apr 12 13:33:32 1990 David J. MacKenzie (djm at rice-chex)
+
+ * util.c (find_inode_file): Make inode an int, not a short.
+
+ * Make functions that don't return a value have type void.
+ Add some casts to function calls.
+
+Wed Apr 11 14:55:28 1990 David J. MacKenzie (djm at albert.ai.mit.edu)
+
+ * main.c (process_args): -i, -o, and -p don't take arguments.
+
+ * main.c (process_args): Get the non-option args from the
+ correct elements of argv.
+
+Tue Apr 10 00:20:26 1990 David J. MacKenzie (djm at albert.ai.mit.edu)
+
+ * Indent source code and update copyrights.
+
+ * cpio.c (usage): Change `collection' to `archive' in message.
+
+Thu Dec 28 03:03:55 1989 David J. MacKenzie (djm at hobbes.ai.mit.edu)
+
+ * dstring.c (xmalloc): Don't return a null pointer if size is 0,
+ on the assumption that trying to allocate 0 bytes is a bug that
+ should be trapped.
+
+Wed Dec 20 03:24:48 1989 David J. MacKenzie (djm at hobbes.ai.mit.edu)
+
+ * All files: Change from GNU CPIO General Public License to
+ GNU General Public License.
+
+Mon Dec 18 13:18:36 1989 David J. MacKenzie (djm at hobbes.ai.mit.edu)
+
+ * Makefile: Add clean target and defines for CC and LDFLAGS.
+ Add dist target and SRCS, DISTFILES macros. Add tags and TAGS targets.
+ * dstring.c (ds_fgets): Read characters into an int, not char.
+ (xmalloc): New function.
+ (out_of_memory): Function removed.
+ Global: use xmalloc instead of malloc and out_of_memory.
+ * extern.h, global.c: Make flag variables ints instead of chars for
+ compatibility with getopt_long.
+ * extern.h: Declare more functions.
+ * main.c (usage): Put the whole usage message into a single string
+ and fix errors.
+ * util.c (create_all_directories): Remove unused variable.
+ (get_next_reel): Ditto.
+ * dstring.h: Declare function.
+
+Sat Dec 2 13:22:37 1989 David J. MacKenzie (djm at hobbes.ai.mit.edu)
+
+ * main.c: Change +copy-pass option to +pass, +copy-in to +in,
+ +copy-out to +out, and +mkdir to +make-directories, and add null
+ option to terminate table.
+ (process_args): Use the same code to handle long and short named
+ options.
+ (usage): Mention long options in message.
+
+Local Variables:
+mode: indented-text
+left-margin: 8
+version-control: never
+End:
diff --git a/gnu/usr.bin/cpio/Makefile b/gnu/usr.bin/cpio/Makefile
new file mode 100644
index 0000000..0d06fa4
--- /dev/null
+++ b/gnu/usr.bin/cpio/Makefile
@@ -0,0 +1,10 @@
+PROG= cpio
+CFLAGS+= -I${.CURDIR} -DRETSIGTYPE=void -DHAVE_SYS_MTIO_H=1 -DSTDC_HEADERS=1 -DHAVE_UNISTD_H=1 -DHAVE_STRING_H=1 -DHAVE_FCNTL_H=1 -DHAVE_UTIME_H=1 -DHAVE_STRERROR=1 -DHAVE_VPRINTF=1 -DDIRENT=1 -DHAVE_LCHOWN
+
+SRCS = copyin.c copyout.c copypass.c defer.c dstring.c fnmatch.c global.c \
+ lchown.c main.c tar.c util.c error.c filemode.c getopt.c getopt1.c \
+ version.c \
+ rtapelib.c dirname.c idcache.c makepath.c xmalloc.c stripslash.c \
+ userspec.c xstrdup.c
+
+.include <bsd.prog.mk>
diff --git a/gnu/usr.bin/cpio/NEWS b/gnu/usr.bin/cpio/NEWS
new file mode 100644
index 0000000..2648c84
--- /dev/null
+++ b/gnu/usr.bin/cpio/NEWS
@@ -0,0 +1,55 @@
+
+Major changes in version 2.3:
+
+* in newc and crc format archives, only store 1 copy of multiply linked files
+* handle multiply linked devices properly
+* handle multiply linked files with cpio -pl even when the source and
+ destination are on different file systems
+* support HPUX Context Dependent Files
+* read and write HPUX cpio archives
+* read System V.4 POSIX tar archives and HPUX POSIX tar archives
+* use rmdir, instead of unlink, to delete existing directories
+
+Major changes in version 2.2:
+
+* handle link counts correctly when reading binary cpio archives
+* configure checks for some libraries that SVR4 needs
+
+Major changes in version 2.1:
+
+* cpio can access remote non-device files as well as remote devices
+* fix bugs in the MS-DOS port
+* add --swap equivalent to -b option
+
+Version 2.0 adds the following features:
+
+Support for the SVR4 cpio formats, which can store inodes >65535, and
+for traditional and POSIX tar archives. Also adds these options:
+
+-A --append append to instead of replacing the archive
+-V --dot print a dot for each file processed
+-H --format select archive format
+-C --io-size select I/O block size in bytes
+-M --message print a message at end of media volumes
+--no-preserve-owner don't change files' owners when extracting
+-R --owner set files' owners when extracting
+-E --pattern-file list of shell filename patterns to process
+-s --swap-bytes handle byte-order differences when extracting files
+-S --swap-halfwords ditto
+-b like -sS
+-I input archive filename
+-k recognize corrupted archives (we alawys do it, though)
+-O output archive filename
+
+Some options of previous versions have been renamed in 2.0:
+
+--binary was replaced by --format=bin
+--portability was replaced by --format=odc
+
+Some options have changed meaning in 2.0, for SVR4 compatibility:
+
+-O used to select the binary archive format, now selects the output file
+-V used to print the version number, now prints a dot for each file
+
+Version 2.0 also fixes several bugs in the handling of files with
+multiple links and of multi-volume archives on floppy disks.
diff --git a/gnu/usr.bin/cpio/README b/gnu/usr.bin/cpio/README
new file mode 100644
index 0000000..83b5228
--- /dev/null
+++ b/gnu/usr.bin/cpio/README
@@ -0,0 +1,56 @@
+This is GNU cpio, a program to manage archives of files.
+As of version 2.0, it supports the features of the System V release 4
+cpio, including support for tar archives.
+
+The main advantages of GNU cpio over Unix versions are:
+
+* It can access tape drives on other hosts using TCP/IP.
+
+* `-o' and `-p' can copy symbolic links either as symbolic links or,
+with `-L', as the files they point to.
+
+* `-i' automatically recognizes the archive format and tries to
+recover from corrupted archives.
+
+* The output of '-itv' looks like 'ls -l'.
+
+* It accepts long-named options as well as traditional
+single-character options.
+
+A few features of other versions of cpio are missing from GNU cpio, including:
+
+* The `-6' option to support Sixth Edition Unix cpio archives with `-i'.
+
+* An option to limit volume size, like afio -s.
+
+
+GNU cpio supports the POSIX.1 "ustar" tar format. GNU tar supports a
+somewhat different, early draft of that format. That draft format has
+a slightly different magic number in the tar header and doesn't
+include the path prefix part of the header, which allows storing file
+names that are longer than 100 characters. GNU cpio knows to
+recognize the nonstandard GNU tar "ustar" archives.
+
+The following patch to GNU tar 1.11.1 makes GNU tar recognize standard
+"ustar" archives, such as GNU cpio produces, except that it won't use
+the path prefix. Without this patch, GNU tar thinks that standard
+"ustar" archives are old-format tar archives and can not use the extra
+information that "ustar" format contains. If you use this patch,
+remember that you will lose the beginnings of paths that are longer
+than 100 characters. That's why it's not an official part of GNU tar.
+(Adding support for the path prefix to GNU tar is not trivial.)
+
+--- list.c.orig Mon Sep 14 17:04:03 1992
++++ list.c Wed Oct 14 14:02:28 1992
+@@ -439,7 +439,7 @@
+ st->st_ctime = from_oct(1+12, header->header.ctime);
+ }
+
+- if (0==strcmp(header->header.magic, TMAGIC)) {
++ if (0==strncmp(header->header.magic, TMAGIC, 5)) {
+ /* Unix Standard tar archive */
+ *stdp = 1;
+ if (wantug) {
+
+Mail suggestions and bug reports for GNU cpio to
+bug-gnu-utils@prep.ai.mit.edu.
diff --git a/gnu/usr.bin/cpio/alloca.c b/gnu/usr.bin/cpio/alloca.c
new file mode 100644
index 0000000..c04c0ef
--- /dev/null
+++ b/gnu/usr.bin/cpio/alloca.c
@@ -0,0 +1,475 @@
+/* alloca.c -- allocate automatically reclaimed memory
+ (Mostly) portable public-domain implementation -- D A Gwyn
+
+ This implementation of the PWB library alloca function,
+ which is used to allocate space off the run-time stack so
+ that it is automatically reclaimed upon procedure exit,
+ was inspired by discussions with J. Q. Johnson of Cornell.
+ J.Otto Tennant <jot@cray.com> contributed the Cray support.
+
+ There are some preprocessor constants that can
+ be defined when compiling for your specific system, for
+ improved efficiency; however, the defaults should be okay.
+
+ The general concept of this implementation is to keep
+ track of all alloca-allocated blocks, and reclaim any
+ that are found to be deeper in the stack than the current
+ invocation. This heuristic does not reclaim storage as
+ soon as it becomes invalid, but it will do so eventually.
+
+ As a special case, alloca(0) reclaims storage without
+ allocating any. It is a good idea to use alloca(0) in
+ your main control loop, etc. to force garbage collection. */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+/* If compiling with GCC, this file's not needed. */
+#ifndef alloca
+
+#ifdef emacs
+#ifdef static
+/* actually, only want this if static is defined as ""
+ -- this is for usg, in which emacs must undefine static
+ in order to make unexec workable
+ */
+#ifndef STACK_DIRECTION
+you
+lose
+-- must know STACK_DIRECTION at compile-time
+#endif /* STACK_DIRECTION undefined */
+#endif /* static */
+#endif /* emacs */
+
+/* If your stack is a linked list of frames, you have to
+ provide an "address metric" ADDRESS_FUNCTION macro. */
+
+#ifdef CRAY
+long i00afunc ();
+#define ADDRESS_FUNCTION(arg) (char *) i00afunc (&(arg))
+#else
+#define ADDRESS_FUNCTION(arg) &(arg)
+#endif
+
+#if __STDC__
+typedef void *pointer;
+#else
+typedef char *pointer;
+#endif
+
+#define NULL 0
+
+/* Different portions of Emacs need to call different versions of
+ malloc. The Emacs executable needs alloca to call xmalloc, because
+ ordinary malloc isn't protected from input signals. On the other
+ hand, the utilities in lib-src need alloca to call malloc; some of
+ them are very simple, and don't have an xmalloc routine.
+
+ Non-Emacs programs expect this to call use xmalloc.
+
+ Callers below should use malloc. */
+
+#ifndef emacs
+#define malloc xmalloc
+extern pointer xmalloc ();
+#endif
+
+/* Define STACK_DIRECTION if you know the direction of stack
+ growth for your system; otherwise it will be automatically
+ deduced at run-time.
+
+ STACK_DIRECTION > 0 => grows toward higher addresses
+ STACK_DIRECTION < 0 => grows toward lower addresses
+ STACK_DIRECTION = 0 => direction of growth unknown */
+
+#ifndef STACK_DIRECTION
+#define STACK_DIRECTION 0 /* Direction unknown. */
+#endif
+
+#if STACK_DIRECTION != 0
+
+#define STACK_DIR STACK_DIRECTION /* Known at compile-time. */
+
+#else /* STACK_DIRECTION == 0; need run-time code. */
+
+static int stack_dir; /* 1 or -1 once known. */
+#define STACK_DIR stack_dir
+
+static void
+find_stack_direction ()
+{
+ static char *addr = NULL; /* Address of first `dummy', once known. */
+ auto char dummy; /* To get stack address. */
+
+ if (addr == NULL)
+ { /* Initial entry. */
+ addr = ADDRESS_FUNCTION (dummy);
+
+ find_stack_direction (); /* Recurse once. */
+ }
+ else
+ {
+ /* Second entry. */
+ if (ADDRESS_FUNCTION (dummy) > addr)
+ stack_dir = 1; /* Stack grew upward. */
+ else
+ stack_dir = -1; /* Stack grew downward. */
+ }
+}
+
+#endif /* STACK_DIRECTION == 0 */
+
+/* An "alloca header" is used to:
+ (a) chain together all alloca'ed blocks;
+ (b) keep track of stack depth.
+
+ It is very important that sizeof(header) agree with malloc
+ alignment chunk size. The following default should work okay. */
+
+#ifndef ALIGN_SIZE
+#define ALIGN_SIZE sizeof(double)
+#endif
+
+typedef union hdr
+{
+ char align[ALIGN_SIZE]; /* To force sizeof(header). */
+ struct
+ {
+ union hdr *next; /* For chaining headers. */
+ char *deep; /* For stack depth measure. */
+ } h;
+} header;
+
+static header *last_alloca_header = NULL; /* -> last alloca header. */
+
+/* Return a pointer to at least SIZE bytes of storage,
+ which will be automatically reclaimed upon exit from
+ the procedure that called alloca. Originally, this space
+ was supposed to be taken from the current stack frame of the
+ caller, but that method cannot be made to work for some
+ implementations of C, for example under Gould's UTX/32. */
+
+pointer
+alloca (size)
+ unsigned size;
+{
+ auto char probe; /* Probes stack depth: */
+ register char *depth = ADDRESS_FUNCTION (probe);
+
+#if STACK_DIRECTION == 0
+ if (STACK_DIR == 0) /* Unknown growth direction. */
+ find_stack_direction ();
+#endif
+
+ /* Reclaim garbage, defined as all alloca'd storage that
+ was allocated from deeper in the stack than currently. */
+
+ {
+ register header *hp; /* Traverses linked list. */
+
+ for (hp = last_alloca_header; hp != NULL;)
+ if ((STACK_DIR > 0 && hp->h.deep > depth)
+ || (STACK_DIR < 0 && hp->h.deep < depth))
+ {
+ register header *np = hp->h.next;
+
+ free ((pointer) hp); /* Collect garbage. */
+
+ hp = np; /* -> next header. */
+ }
+ else
+ break; /* Rest are not deeper. */
+
+ last_alloca_header = hp; /* -> last valid storage. */
+ }
+
+ if (size == 0)
+ return NULL; /* No allocation required. */
+
+ /* Allocate combined header + user data storage. */
+
+ {
+ register pointer new = malloc (sizeof (header) + size);
+ /* Address of header. */
+
+ ((header *) new)->h.next = last_alloca_header;
+ ((header *) new)->h.deep = depth;
+
+ last_alloca_header = (header *) new;
+
+ /* User storage begins just after header. */
+
+ return (pointer) ((char *) new + sizeof (header));
+ }
+}
+
+#ifdef CRAY
+
+#ifdef DEBUG_I00AFUNC
+#include <stdio.h>
+#endif
+
+#ifndef CRAY_STACK
+#define CRAY_STACK
+#ifndef CRAY2
+/* Stack structures for CRAY-1, CRAY X-MP, and CRAY Y-MP */
+struct stack_control_header
+ {
+ long shgrow:32; /* Number of times stack has grown. */
+ long shaseg:32; /* Size of increments to stack. */
+ long shhwm:32; /* High water mark of stack. */
+ long shsize:32; /* Current size of stack (all segments). */
+ };
+
+/* The stack segment linkage control information occurs at
+ the high-address end of a stack segment. (The stack
+ grows from low addresses to high addresses.) The initial
+ part of the stack segment linkage control information is
+ 0200 (octal) words. This provides for register storage
+ for the routine which overflows the stack. */
+
+struct stack_segment_linkage
+ {
+ long ss[0200]; /* 0200 overflow words. */
+ long sssize:32; /* Number of words in this segment. */
+ long ssbase:32; /* Offset to stack base. */
+ long:32;
+ long sspseg:32; /* Offset to linkage control of previous
+ segment of stack. */
+ long:32;
+ long sstcpt:32; /* Pointer to task common address block. */
+ long sscsnm; /* Private control structure number for
+ microtasking. */
+ long ssusr1; /* Reserved for user. */
+ long ssusr2; /* Reserved for user. */
+ long sstpid; /* Process ID for pid based multi-tasking. */
+ long ssgvup; /* Pointer to multitasking thread giveup. */
+ long sscray[7]; /* Reserved for Cray Research. */
+ long ssa0;
+ long ssa1;
+ long ssa2;
+ long ssa3;
+ long ssa4;
+ long ssa5;
+ long ssa6;
+ long ssa7;
+ long sss0;
+ long sss1;
+ long sss2;
+ long sss3;
+ long sss4;
+ long sss5;
+ long sss6;
+ long sss7;
+ };
+
+#else /* CRAY2 */
+/* The following structure defines the vector of words
+ returned by the STKSTAT library routine. */
+struct stk_stat
+ {
+ long now; /* Current total stack size. */
+ long maxc; /* Amount of contiguous space which would
+ be required to satisfy the maximum
+ stack demand to date. */
+ long high_water; /* Stack high-water mark. */
+ long overflows; /* Number of stack overflow ($STKOFEN) calls. */
+ long hits; /* Number of internal buffer hits. */
+ long extends; /* Number of block extensions. */
+ long stko_mallocs; /* Block allocations by $STKOFEN. */
+ long underflows; /* Number of stack underflow calls ($STKRETN). */
+ long stko_free; /* Number of deallocations by $STKRETN. */
+ long stkm_free; /* Number of deallocations by $STKMRET. */
+ long segments; /* Current number of stack segments. */
+ long maxs; /* Maximum number of stack segments so far. */
+ long pad_size; /* Stack pad size. */
+ long current_address; /* Current stack segment address. */
+ long current_size; /* Current stack segment size. This
+ number is actually corrupted by STKSTAT to
+ include the fifteen word trailer area. */
+ long initial_address; /* Address of initial segment. */
+ long initial_size; /* Size of initial segment. */
+ };
+
+/* The following structure describes the data structure which trails
+ any stack segment. I think that the description in 'asdef' is
+ out of date. I only describe the parts that I am sure about. */
+
+struct stk_trailer
+ {
+ long this_address; /* Address of this block. */
+ long this_size; /* Size of this block (does not include
+ this trailer). */
+ long unknown2;
+ long unknown3;
+ long link; /* Address of trailer block of previous
+ segment. */
+ long unknown5;
+ long unknown6;
+ long unknown7;
+ long unknown8;
+ long unknown9;
+ long unknown10;
+ long unknown11;
+ long unknown12;
+ long unknown13;
+ long unknown14;
+ };
+
+#endif /* CRAY2 */
+#endif /* not CRAY_STACK */
+
+#ifdef CRAY2
+/* Determine a "stack measure" for an arbitrary ADDRESS.
+ I doubt that "lint" will like this much. */
+
+static long
+i00afunc (long *address)
+{
+ struct stk_stat status;
+ struct stk_trailer *trailer;
+ long *block, size;
+ long result = 0;
+
+ /* We want to iterate through all of the segments. The first
+ step is to get the stack status structure. We could do this
+ more quickly and more directly, perhaps, by referencing the
+ $LM00 common block, but I know that this works. */
+
+ STKSTAT (&status);
+
+ /* Set up the iteration. */
+
+ trailer = (struct stk_trailer *) (status.current_address
+ + status.current_size
+ - 15);
+
+ /* There must be at least one stack segment. Therefore it is
+ a fatal error if "trailer" is null. */
+
+ if (trailer == 0)
+ abort ();
+
+ /* Discard segments that do not contain our argument address. */
+
+ while (trailer != 0)
+ {
+ block = (long *) trailer->this_address;
+ size = trailer->this_size;
+ if (block == 0 || size == 0)
+ abort ();
+ trailer = (struct stk_trailer *) trailer->link;
+ if ((block <= address) && (address < (block + size)))
+ break;
+ }
+
+ /* Set the result to the offset in this segment and add the sizes
+ of all predecessor segments. */
+
+ result = address - block;
+
+ if (trailer == 0)
+ {
+ return result;
+ }
+
+ do
+ {
+ if (trailer->this_size <= 0)
+ abort ();
+ result += trailer->this_size;
+ trailer = (struct stk_trailer *) trailer->link;
+ }
+ while (trailer != 0);
+
+ /* We are done. Note that if you present a bogus address (one
+ not in any segment), you will get a different number back, formed
+ from subtracting the address of the first block. This is probably
+ not what you want. */
+
+ return (result);
+}
+
+#else /* not CRAY2 */
+/* Stack address function for a CRAY-1, CRAY X-MP, or CRAY Y-MP.
+ Determine the number of the cell within the stack,
+ given the address of the cell. The purpose of this
+ routine is to linearize, in some sense, stack addresses
+ for alloca. */
+
+static long
+i00afunc (long address)
+{
+ long stkl = 0;
+
+ long size, pseg, this_segment, stack;
+ long result = 0;
+
+ struct stack_segment_linkage *ssptr;
+
+ /* Register B67 contains the address of the end of the
+ current stack segment. If you (as a subprogram) store
+ your registers on the stack and find that you are past
+ the contents of B67, you have overflowed the segment.
+
+ B67 also points to the stack segment linkage control
+ area, which is what we are really interested in. */
+
+ stkl = CRAY_STACKSEG_END ();
+ ssptr = (struct stack_segment_linkage *) stkl;
+
+ /* If one subtracts 'size' from the end of the segment,
+ one has the address of the first word of the segment.
+
+ If this is not the first segment, 'pseg' will be
+ nonzero. */
+
+ pseg = ssptr->sspseg;
+ size = ssptr->sssize;
+
+ this_segment = stkl - size;
+
+ /* It is possible that calling this routine itself caused
+ a stack overflow. Discard stack segments which do not
+ contain the target address. */
+
+ while (!(this_segment <= address && address <= stkl))
+ {
+#ifdef DEBUG_I00AFUNC
+ fprintf (stderr, "%011o %011o %011o\n", this_segment, address, stkl);
+#endif
+ if (pseg == 0)
+ break;
+ stkl = stkl - pseg;
+ ssptr = (struct stack_segment_linkage *) stkl;
+ size = ssptr->sssize;
+ pseg = ssptr->sspseg;
+ this_segment = stkl - size;
+ }
+
+ result = address - this_segment;
+
+ /* If you subtract pseg from the current end of the stack,
+ you get the address of the previous stack segment's end.
+ This seems a little convoluted to me, but I'll bet you save
+ a cycle somewhere. */
+
+ while (pseg != 0)
+ {
+#ifdef DEBUG_I00AFUNC
+ fprintf (stderr, "%011o %011o\n", pseg, size);
+#endif
+ stkl = stkl - pseg;
+ ssptr = (struct stack_segment_linkage *) stkl;
+ size = ssptr->sssize;
+ pseg = ssptr->sspseg;
+ result += size;
+ }
+ return (result);
+}
+
+#endif /* not CRAY2 */
+#endif /* CRAY */
+
+#endif /* no alloca */
diff --git a/gnu/usr.bin/cpio/copyin.c b/gnu/usr.bin/cpio/copyin.c
new file mode 100644
index 0000000..7c5d349
--- /dev/null
+++ b/gnu/usr.bin/cpio/copyin.c
@@ -0,0 +1,1272 @@
+/* copyin.c - extract or list a cpio archive
+ Copyright (C) 1990, 1991, 1992 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include "filetypes.h"
+#include "system.h"
+#include "cpiohdr.h"
+#include "dstring.h"
+#include "extern.h"
+#include "defer.h"
+#include "rmt.h"
+#ifndef FNM_PATHNAME
+#include <fnmatch.h>
+#endif
+
+#ifndef HAVE_LCHOWN
+#define lchown chown
+#endif
+
+static void read_pattern_file ();
+static void skip_padding ();
+static void defer_copyin ();
+static void create_defered_links ();
+static void create_final_defers ();
+
+/* Return 16-bit integer I with the bytes swapped. */
+#define swab_short(i) ((((i) << 8) & 0xff00) | (((i) >> 8) & 0x00ff))
+
+/* Read the header, including the name of the file, from file
+ descriptor IN_DES into FILE_HDR. */
+
+void
+read_in_header (file_hdr, in_des)
+ struct new_cpio_header *file_hdr;
+ int in_des;
+{
+ long bytes_skipped = 0; /* Bytes of junk found before magic number. */
+
+ /* Search for a valid magic number. */
+
+ if (archive_format == arf_unknown)
+ {
+ char tmpbuf[512];
+ int check_tar;
+ int peeked_bytes;
+
+ while (archive_format == arf_unknown)
+ {
+ peeked_bytes = peek_in_buf (tmpbuf, in_des, 512);
+ if (peeked_bytes < 6)
+ error (1, 0, "premature end of archive");
+
+ if (!strncmp (tmpbuf, "070701", 6))
+ archive_format = arf_newascii;
+ else if (!strncmp (tmpbuf, "070707", 6))
+ archive_format = arf_oldascii;
+ else if (!strncmp (tmpbuf, "070702", 6))
+ {
+ archive_format = arf_crcascii;
+ crc_i_flag = TRUE;
+ }
+ else if ((*((unsigned short *) tmpbuf) == 070707) ||
+ (*((unsigned short *) tmpbuf) == swab_short ((unsigned short) 070707)))
+ archive_format = arf_binary;
+ else if (peeked_bytes >= 512
+ && (check_tar = is_tar_header (tmpbuf)))
+ {
+ if (check_tar == 2)
+ archive_format = arf_ustar;
+ else
+ archive_format = arf_tar;
+ }
+ else
+ {
+ copy_in_buf ((char *) tmpbuf, in_des, 1L);
+ ++bytes_skipped;
+ }
+ }
+ }
+
+ if (archive_format == arf_tar || archive_format == arf_ustar)
+ {
+ if (append_flag)
+ last_header_start = input_bytes - io_block_size +
+ (in_buff - input_buffer);
+ if (bytes_skipped > 0)
+ error (0, 0, "warning: skipped %ld bytes of junk", bytes_skipped);
+ read_in_tar_header (file_hdr, in_des);
+ return;
+ }
+
+ file_hdr->c_tar_linkname = NULL;
+
+ copy_in_buf ((char *) file_hdr, in_des, 6L);
+ while (1)
+ {
+ if (append_flag)
+ last_header_start = input_bytes - io_block_size
+ + (in_buff - input_buffer) - 6;
+ if (archive_format == arf_newascii
+ && !strncmp ((char *) file_hdr, "070701", 6))
+ {
+ if (bytes_skipped > 0)
+ error (0, 0, "warning: skipped %ld bytes of junk", bytes_skipped);
+ read_in_new_ascii (file_hdr, in_des);
+ break;
+ }
+ if (archive_format == arf_crcascii
+ && !strncmp ((char *) file_hdr, "070702", 6))
+ {
+ if (bytes_skipped > 0)
+ error (0, 0, "warning: skipped %ld bytes of junk", bytes_skipped);
+ read_in_new_ascii (file_hdr, in_des);
+ break;
+ }
+ if ( (archive_format == arf_oldascii || archive_format == arf_hpoldascii)
+ && !strncmp ((char *) file_hdr, "070707", 6))
+ {
+ if (bytes_skipped > 0)
+ error (0, 0, "warning: skipped %ld bytes of junk", bytes_skipped);
+ read_in_old_ascii (file_hdr, in_des);
+ break;
+ }
+ if ( (archive_format == arf_binary || archive_format == arf_hpbinary)
+ && (file_hdr->c_magic == 070707
+ || file_hdr->c_magic == swab_short ((unsigned short) 070707)))
+ {
+ /* Having to skip 1 byte because of word alignment is normal. */
+ if (bytes_skipped > 0)
+ error (0, 0, "warning: skipped %ld bytes of junk", bytes_skipped);
+ read_in_binary (file_hdr, in_des);
+ break;
+ }
+ bytes_skipped++;
+ bcopy ((char *) file_hdr + 1, (char *) file_hdr, 5);
+ copy_in_buf ((char *) file_hdr + 5, in_des, 1L);
+ }
+}
+
+/* Fill in FILE_HDR by reading an old-format ASCII format cpio header from
+ file descriptor IN_DES, except for the magic number, which is
+ already filled in. */
+
+void
+read_in_old_ascii (file_hdr, in_des)
+ struct new_cpio_header *file_hdr;
+ int in_des;
+{
+ char ascii_header[78];
+ unsigned long dev;
+ unsigned long rdev;
+
+ copy_in_buf (ascii_header, in_des, 70L);
+ ascii_header[70] = '\0';
+ sscanf (ascii_header,
+ "%6lo%6lo%6lo%6lo%6lo%6lo%6lo%11lo%6lo%11lo",
+ &dev, &file_hdr->c_ino,
+ &file_hdr->c_mode, &file_hdr->c_uid, &file_hdr->c_gid,
+ &file_hdr->c_nlink, &rdev, &file_hdr->c_mtime,
+ &file_hdr->c_namesize, &file_hdr->c_filesize);
+ file_hdr->c_dev_maj = major (dev);
+ file_hdr->c_dev_min = minor (dev);
+ file_hdr->c_rdev_maj = major (rdev);
+ file_hdr->c_rdev_min = minor (rdev);
+
+ /* Read file name from input. */
+ if (file_hdr->c_name != NULL)
+ free (file_hdr->c_name);
+ file_hdr->c_name = (char *) xmalloc (file_hdr->c_namesize + 1);
+ copy_in_buf (file_hdr->c_name, in_des, (long) file_hdr->c_namesize);
+#ifndef __MSDOS__
+ /* HP/UX cpio creates archives that look just like ordinary archives,
+ but for devices it sets major = 0, minor = 1, and puts the
+ actual major/minor number in the filesize field. See if this
+ is an HP/UX cpio archive, and if so fix it. We have to do this
+ here because process_copy_in() assumes filesize is always 0
+ for devices. */
+ switch (file_hdr->c_mode & CP_IFMT)
+ {
+ case CP_IFCHR:
+ case CP_IFBLK:
+#ifdef CP_IFSOCK
+ case CP_IFSOCK:
+#endif
+#ifdef CP_IFIFO
+ case CP_IFIFO:
+#endif
+ if (file_hdr->c_filesize != 0
+ && file_hdr->c_rdev_maj == 0
+ && file_hdr->c_rdev_min == 1)
+ {
+ file_hdr->c_rdev_maj = major (file_hdr->c_filesize);
+ file_hdr->c_rdev_min = minor (file_hdr->c_filesize);
+ file_hdr->c_filesize = 0;
+ }
+ break;
+ default:
+ break;
+ }
+#endif /* __MSDOS__ */
+}
+
+/* Fill in FILE_HDR by reading a new-format ASCII format cpio header from
+ file descriptor IN_DES, except for the magic number, which is
+ already filled in. */
+
+void
+read_in_new_ascii (file_hdr, in_des)
+ struct new_cpio_header *file_hdr;
+ int in_des;
+{
+ char ascii_header[112];
+
+ copy_in_buf (ascii_header, in_des, 104L);
+ ascii_header[104] = '\0';
+ sscanf (ascii_header,
+ "%8lx%8lx%8lx%8lx%8lx%8lx%8lx%8lx%8lx%8lx%8lx%8lx%8lx",
+ &file_hdr->c_ino, &file_hdr->c_mode, &file_hdr->c_uid,
+ &file_hdr->c_gid, &file_hdr->c_nlink, &file_hdr->c_mtime,
+ &file_hdr->c_filesize, &file_hdr->c_dev_maj, &file_hdr->c_dev_min,
+ &file_hdr->c_rdev_maj, &file_hdr->c_rdev_min, &file_hdr->c_namesize,
+ &file_hdr->c_chksum);
+ /* Read file name from input. */
+ if (file_hdr->c_name != NULL)
+ free (file_hdr->c_name);
+ file_hdr->c_name = (char *) xmalloc (file_hdr->c_namesize);
+ copy_in_buf (file_hdr->c_name, in_des, (long) file_hdr->c_namesize);
+
+ /* In SVR4 ASCII format, the amount of space allocated for the header
+ is rounded up to the next long-word, so we might need to drop
+ 1-3 bytes. */
+ skip_padding (in_des, file_hdr->c_namesize + 110);
+}
+
+/* Fill in FILE_HDR by reading a binary format cpio header from
+ file descriptor IN_DES, except for the first 6 bytes (the magic
+ number, device, and inode number), which are already filled in. */
+
+void
+read_in_binary (file_hdr, in_des)
+ struct new_cpio_header *file_hdr;
+ int in_des;
+{
+ struct old_cpio_header short_hdr;
+
+ /* Copy the data into the short header, then later transfer
+ it into the argument long header. */
+ short_hdr.c_dev = ((struct old_cpio_header *) file_hdr)->c_dev;
+ short_hdr.c_ino = ((struct old_cpio_header *) file_hdr)->c_ino;
+ copy_in_buf (((char *) &short_hdr) + 6, in_des, 20L);
+
+ /* If the magic number is byte swapped, fix the header. */
+ if (file_hdr->c_magic == swab_short ((unsigned short) 070707))
+ {
+ static int warned = 0;
+
+ /* Alert the user that they might have to do byte swapping on
+ the file contents. */
+ if (warned == 0)
+ {
+ error (0, 0, "warning: archive header has reverse byte-order");
+ warned = 1;
+ }
+ swab_array ((char *) &short_hdr, 13);
+ }
+
+ file_hdr->c_dev_maj = major (short_hdr.c_dev);
+ file_hdr->c_dev_min = minor (short_hdr.c_dev);
+ file_hdr->c_ino = short_hdr.c_ino;
+ file_hdr->c_mode = short_hdr.c_mode;
+ file_hdr->c_uid = short_hdr.c_uid;
+ file_hdr->c_gid = short_hdr.c_gid;
+ file_hdr->c_nlink = short_hdr.c_nlink;
+ file_hdr->c_rdev_maj = major (short_hdr.c_rdev);
+ file_hdr->c_rdev_min = minor (short_hdr.c_rdev);
+ file_hdr->c_mtime = (unsigned long) short_hdr.c_mtimes[0] << 16
+ | short_hdr.c_mtimes[1];
+
+ file_hdr->c_namesize = short_hdr.c_namesize;
+ file_hdr->c_filesize = (unsigned long) short_hdr.c_filesizes[0] << 16
+ | short_hdr.c_filesizes[1];
+
+ /* Read file name from input. */
+ if (file_hdr->c_name != NULL)
+ free (file_hdr->c_name);
+ file_hdr->c_name = (char *) xmalloc (file_hdr->c_namesize);
+ copy_in_buf (file_hdr->c_name, in_des, (long) file_hdr->c_namesize);
+
+ /* In binary mode, the amount of space allocated in the header for
+ the filename is `c_namesize' rounded up to the next short-word,
+ so we might need to drop a byte. */
+ if (file_hdr->c_namesize % 2)
+ toss_input (in_des, 1L);
+
+#ifndef __MSDOS__
+ /* HP/UX cpio creates archives that look just like ordinary archives,
+ but for devices it sets major = 0, minor = 1, and puts the
+ actual major/minor number in the filesize field. See if this
+ is an HP/UX cpio archive, and if so fix it. We have to do this
+ here because process_copy_in() assumes filesize is always 0
+ for devices. */
+ switch (file_hdr->c_mode & CP_IFMT)
+ {
+ case CP_IFCHR:
+ case CP_IFBLK:
+#ifdef CP_IFSOCK
+ case CP_IFSOCK:
+#endif
+#ifdef CP_IFIFO
+ case CP_IFIFO:
+#endif
+ if (file_hdr->c_filesize != 0
+ && file_hdr->c_rdev_maj == 0
+ && file_hdr->c_rdev_min == 1)
+ {
+ file_hdr->c_rdev_maj = major (file_hdr->c_filesize);
+ file_hdr->c_rdev_min = minor (file_hdr->c_filesize);
+ file_hdr->c_filesize = 0;
+ }
+ break;
+ default:
+ break;
+ }
+#endif /* __MSDOS__ */
+}
+
+/* Exchange the bytes of each element of the array of COUNT shorts
+ starting at PTR. */
+
+void
+swab_array (ptr, count)
+ char *ptr;
+ int count;
+{
+ char tmp;
+
+ while (count-- > 0)
+ {
+ tmp = *ptr;
+ *ptr = *(ptr + 1);
+ ++ptr;
+ *ptr = tmp;
+ ++ptr;
+ }
+}
+
+/* Current time for verbose table. */
+static time_t current_time;
+
+/* Read the collection from standard input and create files
+ in the file system. */
+
+void
+process_copy_in ()
+{
+ char done = FALSE; /* True if trailer reached. */
+ int res; /* Result of various function calls. */
+ dynamic_string new_name; /* New file name for rename option. */
+ FILE *tty_in; /* Interactive file for rename option. */
+ FILE *tty_out; /* Interactive file for rename option. */
+ char *str_res; /* Result for string function. */
+ struct utimbuf times; /* For setting file times. */
+ struct stat file_stat; /* Output file stat record. */
+ struct new_cpio_header file_hdr; /* Output header information. */
+ int out_file_des; /* Output file descriptor. */
+ int in_file_des; /* Input file descriptor. */
+ char skip_file; /* Flag for use with patterns. */
+ int existing_dir; /* True if file is a dir & already exists. */
+ int i; /* Loop index variable. */
+ char *link_name = NULL; /* Name of hard and symbolic links. */
+#ifdef HPUX_CDF
+ int cdf_flag; /* True if file is a CDF. */
+ int cdf_char; /* Index of `+' char indicating a CDF. */
+#endif
+
+ /* Initialize the copy in. */
+ if (pattern_file_name)
+ read_pattern_file ();
+ file_hdr.c_name = NULL;
+ ds_init (&new_name, 128);
+ /* Initialize this in case it has members we don't know to set. */
+ bzero (&times, sizeof (struct utimbuf));
+
+ /* Open interactive file pair for rename operation. */
+ if (rename_flag)
+ {
+ tty_in = fopen (CONSOLE, "r");
+ if (tty_in == NULL)
+ error (2, errno, CONSOLE);
+ tty_out = fopen (CONSOLE, "w");
+ if (tty_out == NULL)
+ error (2, errno, CONSOLE);
+ }
+
+ /* Get date and time if needed for processing the table option. */
+ if (table_flag && verbose_flag)
+ time (&current_time);
+
+#ifdef __MSDOS__
+ setmode (archive_des, O_BINARY);
+#endif
+ /* Check whether the input file might be a tape. */
+ in_file_des = archive_des;
+ if (_isrmt (in_file_des))
+ {
+ input_is_special = 1;
+ input_is_seekable = 0;
+ }
+ else
+ {
+ if (fstat (in_file_des, &file_stat))
+ error (1, errno, "standard input is closed");
+ input_is_special =
+#ifdef S_ISBLK
+ S_ISBLK (file_stat.st_mode) ||
+#endif
+ S_ISCHR (file_stat.st_mode);
+ input_is_seekable = S_ISREG (file_stat.st_mode);
+ }
+ output_is_seekable = TRUE;
+
+ /* While there is more input in the collection, process the input. */
+ while (!done)
+ {
+ link_name = NULL;
+ swapping_halfwords = swapping_bytes = FALSE;
+
+ /* Start processing the next file by reading the header. */
+ read_in_header (&file_hdr, in_file_des);
+
+#ifdef DEBUG_CPIO
+ if (debug_flag)
+ {
+ struct new_cpio_header *h;
+ h = &file_hdr;
+ fprintf (stderr,
+ "magic = 0%o, ino = %d, mode = 0%o, uid = %d, gid = %d\n",
+ h->c_magic, h->c_ino, h->c_mode, h->c_uid, h->c_gid);
+ fprintf (stderr,
+ "nlink = %d, mtime = %d, filesize = %d, dev_maj = 0x%x\n",
+ h->c_nlink, h->c_mtime, h->c_filesize, h->c_dev_maj);
+ fprintf (stderr,
+ "dev_min = 0x%x, rdev_maj = 0x%x, rdev_min = 0x%x, namesize = %d\n",
+ h->c_dev_min, h->c_rdev_maj, h->c_rdev_min, h->c_namesize);
+ fprintf (stderr,
+ "chksum = %d, name = \"%s\", tar_linkname = \"%s\"\n",
+ h->c_chksum, h->c_name,
+ h->c_tar_linkname ? h->c_tar_linkname : "(null)" );
+
+ }
+#endif
+ /* Is this the header for the TRAILER file? */
+ if (strcmp ("TRAILER!!!", file_hdr.c_name) == 0)
+ {
+ done = TRUE;
+ break;
+ }
+
+ /* Does the file name match one of the given patterns? */
+ if (num_patterns <= 0)
+ skip_file = FALSE;
+ else
+ {
+ skip_file = copy_matching_files;
+ for (i = 0; i < num_patterns
+ && skip_file == copy_matching_files; i++)
+ {
+ if (fnmatch (save_patterns[i], file_hdr.c_name, 0) == 0)
+ skip_file = !copy_matching_files;
+ }
+ }
+
+ if (skip_file)
+ {
+ toss_input (in_file_des, file_hdr.c_filesize);
+ skip_padding (in_file_des, file_hdr.c_filesize);
+ }
+ else if (table_flag)
+ {
+ if (verbose_flag)
+ {
+#ifdef CP_IFLNK
+ if ((file_hdr.c_mode & CP_IFMT) == CP_IFLNK)
+ {
+ if (archive_format != arf_tar && archive_format != arf_ustar)
+ {
+ link_name = (char *) xmalloc ((unsigned int) file_hdr.c_filesize + 1);
+ link_name[file_hdr.c_filesize] = '\0';
+ copy_in_buf (link_name, in_file_des, file_hdr.c_filesize);
+ long_format (&file_hdr, link_name);
+ free (link_name);
+ skip_padding (in_file_des, file_hdr.c_filesize);
+ continue;
+ }
+ else
+ {
+ long_format (&file_hdr, file_hdr.c_tar_linkname);
+ continue;
+ }
+ }
+ else
+#endif
+ long_format (&file_hdr, (char *) 0);
+ }
+ else
+ printf ("%s\n", file_hdr.c_name);
+
+ toss_input (in_file_des, file_hdr.c_filesize);
+ skip_padding (in_file_des, file_hdr.c_filesize);
+ }
+ else if (append_flag)
+ {
+ toss_input (in_file_des, file_hdr.c_filesize);
+ skip_padding (in_file_des, file_hdr.c_filesize);
+ }
+ else
+ {
+ /* Copy the input file into the directory structure. */
+
+ /* Do we need to rename the file? */
+ if (rename_flag)
+ {
+ fprintf (tty_out, "rename %s -> ", file_hdr.c_name);
+ fflush (tty_out);
+ str_res = ds_fgets (tty_in, &new_name);
+ if (str_res == NULL || str_res[0] == 0)
+ {
+ toss_input (in_file_des, file_hdr.c_filesize);
+ skip_padding (in_file_des, file_hdr.c_filesize);
+ continue;
+ }
+ else
+ file_hdr.c_name = xstrdup (new_name.ds_string);
+ }
+
+ /* See if the file already exists. */
+ existing_dir = FALSE;
+ if (lstat (file_hdr.c_name, &file_stat) == 0)
+ {
+ if (S_ISDIR (file_stat.st_mode)
+ && ((file_hdr.c_mode & CP_IFMT) == CP_IFDIR))
+ {
+ /* If there is already a directory there that
+ we are trying to create, don't complain about
+ it. */
+ existing_dir = TRUE;
+ }
+ else if (!unconditional_flag
+ && file_hdr.c_mtime <= file_stat.st_mtime)
+ {
+ error (0, 0, "%s not created: newer or same age version exists",
+ file_hdr.c_name);
+ toss_input (in_file_des, file_hdr.c_filesize);
+ skip_padding (in_file_des, file_hdr.c_filesize);
+ continue; /* Go to the next file. */
+ }
+ else if (S_ISDIR (file_stat.st_mode)
+ ? rmdir (file_hdr.c_name)
+ : unlink (file_hdr.c_name))
+ {
+ error (0, errno, "cannot remove current %s",
+ file_hdr.c_name);
+ toss_input (in_file_des, file_hdr.c_filesize);
+ skip_padding (in_file_des, file_hdr.c_filesize);
+ continue; /* Go to the next file. */
+ }
+ }
+
+ /* Do the real copy or link. */
+ switch (file_hdr.c_mode & CP_IFMT)
+ {
+ case CP_IFREG:
+#ifndef __MSDOS__
+ /* Can the current file be linked to a previously copied file? */
+ if (file_hdr.c_nlink > 1 && (archive_format == arf_newascii
+ || archive_format == arf_crcascii) )
+ {
+ int link_res;
+ if (file_hdr.c_filesize == 0)
+ {
+ /* The newc and crc formats store multiply linked copies
+ of the same file in the archive only once. The
+ actual data is attached to the last link in the
+ archive, and the other links all have a filesize
+ of 0. Since this file has multiple links and a
+ filesize of 0, its data is probably attatched to
+ another file in the archive. Save the link, and
+ process it later when we get the actual data. We
+ can't just create it with length 0 and add the
+ data later, in case the file is readonly. We still
+ lose if its parent directory is readonly (and we aren't
+ running as root), but there's nothing we can do about
+ that. */
+ defer_copyin (&file_hdr);
+ toss_input (in_file_des, file_hdr.c_filesize);
+ skip_padding (in_file_des, file_hdr.c_filesize);
+ break;
+ }
+ /* If the file has data (filesize != 0), then presumably
+ any other links have already been defer_copyin'ed(),
+ but GNU cpio version 2.0-2.2 didn't do that, so we
+ still have to check for links here (and also in case
+ the archive was created and later appeneded to). */
+ link_res = link_to_maj_min_ino (file_hdr.c_name,
+ file_hdr.c_dev_maj, file_hdr.c_dev_maj,
+ file_hdr.c_ino);
+ if (link_res == 0)
+ {
+ toss_input (in_file_des, file_hdr.c_filesize);
+ skip_padding (in_file_des, file_hdr.c_filesize);
+ break;
+ }
+ }
+ else if (file_hdr.c_nlink > 1 && archive_format != arf_tar
+ && archive_format != arf_ustar)
+ {
+ int link_res;
+ link_res = link_to_maj_min_ino (file_hdr.c_name,
+ file_hdr.c_dev_maj, file_hdr.c_dev_maj,
+ file_hdr.c_ino);
+ if (link_res == 0)
+ {
+ toss_input (in_file_des, file_hdr.c_filesize);
+ skip_padding (in_file_des, file_hdr.c_filesize);
+ break;
+ }
+ }
+ else if ((archive_format == arf_tar || archive_format == arf_ustar)
+ && file_hdr.c_tar_linkname &&
+ file_hdr.c_tar_linkname[0] != '\0')
+ {
+ int link_res;
+ link_res = link_to_name (file_hdr.c_name,
+ file_hdr.c_tar_linkname);
+ if (link_res < 0)
+ {
+ error (0, errno, "cannot link %s to %s",
+ file_hdr.c_tar_linkname, file_hdr.c_name);
+ }
+ break;
+ }
+#endif
+
+ /* If not linked, copy the contents of the file. */
+ if (link_name == NULL)
+ {
+ out_file_des = open (file_hdr.c_name,
+ O_CREAT | O_WRONLY | O_BINARY, 0600);
+ if (out_file_des < 0 && create_dir_flag)
+ {
+ create_all_directories (file_hdr.c_name);
+ out_file_des = open (file_hdr.c_name,
+ O_CREAT | O_WRONLY | O_BINARY,
+ 0600);
+ }
+ if (out_file_des < 0)
+ {
+ error (0, errno, "%s", file_hdr.c_name);
+ toss_input (in_file_des, file_hdr.c_filesize);
+ skip_padding (in_file_des, file_hdr.c_filesize);
+ continue;
+ }
+
+ crc = 0;
+ if (swap_halfwords_flag)
+ {
+ if ((file_hdr.c_filesize % 4) == 0)
+ swapping_halfwords = TRUE;
+ else
+ error (0, 0, "cannot swap halfwords of %s: odd number of halfwords",
+ file_hdr.c_name);
+ }
+ if (swap_bytes_flag)
+ {
+ if ((file_hdr.c_filesize % 2) == 0)
+ swapping_bytes = TRUE;
+ else
+ error (0, 0, "cannot swap bytes of %s: odd number of bytes",
+ file_hdr.c_name);
+ }
+ copy_files (in_file_des, out_file_des, file_hdr.c_filesize);
+ empty_output_buffer (out_file_des);
+ if (close (out_file_des) < 0)
+ error (0, errno, "%s", file_hdr.c_name);
+
+ if (archive_format == arf_crcascii)
+ {
+ if (crc != file_hdr.c_chksum)
+ error (0, 0, "%s: checksum error (0x%x, should be 0x%x)",
+ file_hdr.c_name, crc, file_hdr.c_chksum);
+ }
+ /* File is now copied; set attributes. */
+ if (!no_chown_flag)
+ if ((chown (file_hdr.c_name,
+ set_owner_flag ? set_owner : file_hdr.c_uid,
+ set_group_flag ? set_group : file_hdr.c_gid) < 0)
+ && errno != EPERM)
+ error (0, errno, "%s", file_hdr.c_name);
+ /* chown may have turned off some permissions we wanted. */
+ if (chmod (file_hdr.c_name, (int) file_hdr.c_mode) < 0)
+ error (0, errno, "%s", file_hdr.c_name);
+ if (retain_time_flag)
+ {
+ times.actime = times.modtime = file_hdr.c_mtime;
+ if (utime (file_hdr.c_name, &times) < 0)
+ error (0, errno, "%s", file_hdr.c_name);
+ }
+ skip_padding (in_file_des, file_hdr.c_filesize);
+ if (file_hdr.c_nlink > 1 && (archive_format == arf_newascii
+ || archive_format == arf_crcascii) )
+ {
+ /* (see comment above for how the newc and crc formats
+ store multiple links). Now that we have the data
+ for this file, create any other links to it which
+ we defered. */
+ create_defered_links (&file_hdr);
+ }
+ }
+ break;
+
+ case CP_IFDIR:
+ /* Strip any trailing `/'s off the filename; tar puts
+ them on. We might as well do it here in case anybody
+ else does too, since they cause strange things to happen. */
+ strip_trailing_slashes (file_hdr.c_name);
+
+ /* Ignore the current directory. It must already exist,
+ and we don't want to change its permission, ownership
+ or time. */
+ if (file_hdr.c_name[0] == '.' && file_hdr.c_name[1] == '\0')
+ break;
+
+#ifdef HPUX_CDF
+ cdf_flag = 0;
+#endif
+ if (!existing_dir)
+
+ {
+#ifdef HPUX_CDF
+ /* If the directory name ends in a + and is SUID,
+ then it is a CDF. Strip the trailing + from
+ the name before creating it. */
+ cdf_char = strlen (file_hdr.c_name) - 1;
+ if ( (cdf_char > 0) &&
+ (file_hdr.c_mode & 04000) &&
+ (file_hdr.c_name [cdf_char] == '+') )
+ {
+ file_hdr.c_name [cdf_char] = '\0';
+ cdf_flag = 1;
+ }
+#endif
+ res = mkdir (file_hdr.c_name, file_hdr.c_mode);
+ }
+ else
+ res = 0;
+ if (res < 0 && create_dir_flag)
+ {
+ create_all_directories (file_hdr.c_name);
+ res = mkdir (file_hdr.c_name, file_hdr.c_mode);
+ }
+ if (res < 0)
+ {
+ error (0, errno, "%s", file_hdr.c_name);
+ continue;
+ }
+ if (!no_chown_flag)
+ if ((chown (file_hdr.c_name,
+ set_owner_flag ? set_owner : file_hdr.c_uid,
+ set_group_flag ? set_group : file_hdr.c_gid) < 0)
+ && errno != EPERM)
+ error (0, errno, "%s", file_hdr.c_name);
+ /* chown may have turned off some permissions we wanted. */
+ if (chmod (file_hdr.c_name, (int) file_hdr.c_mode) < 0)
+ error (0, errno, "%s", file_hdr.c_name);
+#ifdef HPUX_CDF
+ if (cdf_flag)
+ /* Once we "hide" the directory with the chmod(),
+ we have to refer to it using name+ instead of name. */
+ file_hdr.c_name [cdf_char] = '+';
+#endif
+ if (retain_time_flag)
+ {
+ times.actime = times.modtime = file_hdr.c_mtime;
+ if (utime (file_hdr.c_name, &times) < 0)
+ error (0, errno, "%s", file_hdr.c_name);
+ }
+ break;
+
+#ifndef __MSDOS__
+ case CP_IFCHR:
+ case CP_IFBLK:
+#ifdef CP_IFSOCK
+ case CP_IFSOCK:
+#endif
+#ifdef CP_IFIFO
+ case CP_IFIFO:
+#endif
+ if (file_hdr.c_nlink > 1 && archive_format != arf_tar
+ && archive_format != arf_ustar)
+ {
+ int link_res;
+ link_res = link_to_maj_min_ino (file_hdr.c_name,
+ file_hdr.c_dev_maj, file_hdr.c_dev_maj,
+ file_hdr.c_ino);
+ if (link_res == 0)
+ break;
+ }
+ else if (archive_format == arf_ustar &&
+ file_hdr.c_tar_linkname &&
+ file_hdr.c_tar_linkname [0] != '\0')
+ {
+ int link_res;
+ link_res = link_to_name (file_hdr.c_name,
+ file_hdr.c_tar_linkname);
+ if (link_res < 0)
+ {
+ error (0, errno, "cannot link %s to %s",
+ file_hdr.c_tar_linkname, file_hdr.c_name);
+ /* Something must be wrong, because we couldn't
+ find the file to link to. But can we assume
+ that the device maj/min numbers are correct
+ and fall through to the mknod? It's probably
+ safer to just break, rather than possibly
+ creating a bogus device file. */
+ }
+ break;
+ }
+
+ res = mknod (file_hdr.c_name, file_hdr.c_mode,
+ makedev (file_hdr.c_rdev_maj, file_hdr.c_rdev_min));
+ if (res < 0 && create_dir_flag)
+ {
+ create_all_directories (file_hdr.c_name);
+ res = mknod (file_hdr.c_name, file_hdr.c_mode,
+ makedev (file_hdr.c_rdev_maj, file_hdr.c_rdev_min));
+ }
+ if (res < 0)
+ {
+ error (0, errno, "%s", file_hdr.c_name);
+ continue;
+ }
+ if (!no_chown_flag)
+ if ((chown (file_hdr.c_name,
+ set_owner_flag ? set_owner : file_hdr.c_uid,
+ set_group_flag ? set_group : file_hdr.c_gid) < 0)
+ && errno != EPERM)
+ error (0, errno, "%s", file_hdr.c_name);
+ /* chown may have turned off some permissions we wanted. */
+ if (chmod (file_hdr.c_name, file_hdr.c_mode) < 0)
+ error (0, errno, "%s", file_hdr.c_name);
+ if (retain_time_flag)
+ {
+ times.actime = times.modtime = file_hdr.c_mtime;
+ if (utime (file_hdr.c_name, &times) < 0)
+ error (0, errno, "%s", file_hdr.c_name);
+ }
+ break;
+#endif
+
+#ifdef CP_IFLNK
+ case CP_IFLNK:
+ {
+ if (archive_format != arf_tar && archive_format != arf_ustar)
+ {
+ link_name = (char *) xmalloc ((unsigned int) file_hdr.c_filesize + 1);
+ link_name[file_hdr.c_filesize] = '\0';
+ copy_in_buf (link_name, in_file_des, file_hdr.c_filesize);
+ skip_padding (in_file_des, file_hdr.c_filesize);
+ }
+ else
+ {
+ link_name = xstrdup (file_hdr.c_tar_linkname);
+ }
+
+ res = UMASKED_SYMLINK (link_name, file_hdr.c_name,
+ file_hdr.c_mode);
+ if (res < 0 && create_dir_flag)
+ {
+ create_all_directories (file_hdr.c_name);
+ res = UMASKED_SYMLINK (link_name, file_hdr.c_name,
+ file_hdr.c_mode);
+ }
+ if (res < 0)
+ {
+ error (0, errno, "%s", file_hdr.c_name);
+ free (link_name);
+ link_name = NULL;
+ continue;
+ }
+ if (!no_chown_flag)
+ if ((lchown (file_hdr.c_name,
+ set_owner_flag ? set_owner : file_hdr.c_uid,
+ set_group_flag ? set_group : file_hdr.c_gid) < 0)
+ && errno != EPERM)
+ error (0, errno, "%s", file_hdr.c_name);
+ free (link_name);
+ link_name = NULL;
+ }
+ break;
+#endif
+
+ default:
+ error (0, 0, "%s: unknown file type", file_hdr.c_name);
+ toss_input (in_file_des, file_hdr.c_filesize);
+ skip_padding (in_file_des, file_hdr.c_filesize);
+ }
+
+ if (verbose_flag)
+ fprintf (stderr, "%s\n", file_hdr.c_name);
+ if (dot_flag)
+ fputc ('.', stderr);
+ }
+ }
+
+ if (dot_flag)
+ fputc ('\n', stderr);
+
+ if (append_flag)
+ return;
+
+ if (archive_format == arf_newascii || archive_format == arf_crcascii)
+ create_final_defers ();
+ res = (input_bytes + io_block_size - 1) / io_block_size;
+ if (res == 1)
+ fprintf (stderr, "1 block\n");
+ else
+ fprintf (stderr, "%d blocks\n", res);
+}
+
+/* Print the file described by FILE_HDR in long format.
+ If LINK_NAME is nonzero, it is the name of the file that
+ this file is a symbolic link to. */
+
+void
+long_format (file_hdr, link_name)
+ struct new_cpio_header *file_hdr;
+ char *link_name;
+{
+ char mbuf[11];
+ char tbuf[40];
+ time_t when;
+
+ mode_string (file_hdr->c_mode, mbuf);
+ mbuf[10] = '\0';
+
+ /* Get time values ready to print. */
+ when = file_hdr->c_mtime;
+ strftime(tbuf, sizeof(tbuf), "%c", localtime(&when));
+ if (current_time - when > 6L * 30L * 24L * 60L * 60L
+ || current_time - when < 0L)
+ {
+ /* The file is older than 6 months, or in the future.
+ Show the year instead of the time of day. */
+ strcpy (tbuf + 11, tbuf + 19);
+ }
+ tbuf[16] = '\0';
+
+ printf ("%s %3u ", mbuf, file_hdr->c_nlink);
+
+#ifndef __MSDOS__
+ if (numeric_uid)
+#endif
+ printf ("%-8u %-8u ", (unsigned int) file_hdr->c_uid,
+ (unsigned int) file_hdr->c_gid);
+#ifndef __MSDOS__
+ else
+ printf ("%-8.8s %-8.8s ", getuser (file_hdr->c_uid),
+ getgroup (file_hdr->c_gid));
+
+ if ((file_hdr->c_mode & CP_IFMT) == CP_IFCHR
+ || (file_hdr->c_mode & CP_IFMT) == CP_IFBLK)
+ printf ("%3u, %3u ", file_hdr->c_rdev_maj,
+ file_hdr->c_rdev_min);
+ else
+#endif
+ printf ("%8lu ", file_hdr->c_filesize);
+
+ printf ("%s ", tbuf + 4);
+
+ print_name_with_quoting (file_hdr->c_name);
+ if (link_name)
+ {
+ printf (" -> ");
+ print_name_with_quoting (link_name);
+ }
+ putc ('\n', stdout);
+}
+
+void
+print_name_with_quoting (p)
+ register char *p;
+{
+ register unsigned char c;
+
+ while (c = *p++)
+ {
+ switch (c)
+ {
+#ifndef __MSDOS__
+ case '\\':
+ printf ("\\\\");
+ break;
+#endif
+
+ case '\n':
+ printf ("\\n");
+ break;
+
+ case '\b':
+ printf ("\\b");
+ break;
+
+ case '\r':
+ printf ("\\r");
+ break;
+
+ case '\t':
+ printf ("\\t");
+ break;
+
+ case '\f':
+ printf ("\\f");
+ break;
+
+ case ' ':
+ printf ("\\ ");
+ break;
+
+ case '"':
+ printf ("\\\"");
+ break;
+
+ default:
+ if (c > 040 &&
+#ifdef __MSDOS__
+ c < 0377 && c != 0177
+#else
+ c < 0177
+#endif
+ )
+ putchar (c);
+ else
+ printf ("\\%03o", (unsigned int) c);
+ }
+ }
+}
+
+/* Read a pattern file (for the -E option). Put a list of
+ `num_patterns' elements in `save_patterns'. Any patterns that were
+ already in `save_patterns' (from the command line) are preserved. */
+
+static void
+read_pattern_file ()
+{
+ int max_new_patterns;
+ char **new_save_patterns;
+ int new_num_patterns;
+ int i;
+ dynamic_string pattern_name;
+ FILE *pattern_fp;
+
+ if (num_patterns < 0)
+ num_patterns = 0;
+ max_new_patterns = 1 + num_patterns;
+ new_save_patterns = (char **) xmalloc (max_new_patterns * sizeof (char *));
+ new_num_patterns = num_patterns;
+ ds_init (&pattern_name, 128);
+
+ pattern_fp = fopen (pattern_file_name, "r");
+ if (pattern_fp == NULL)
+ error (1, errno, "%s", pattern_file_name);
+ while (ds_fgetstr (pattern_fp, &pattern_name, '\n') != NULL)
+ {
+ if (new_num_patterns >= max_new_patterns)
+ {
+ max_new_patterns += 1;
+ new_save_patterns = (char **)
+ xrealloc ((char *) new_save_patterns,
+ max_new_patterns * sizeof (char *));
+ }
+ new_save_patterns[new_num_patterns] = xstrdup (pattern_name.ds_string);
+ ++new_num_patterns;
+ }
+ if (ferror (pattern_fp) || fclose (pattern_fp) == EOF)
+ error (1, errno, "%s", pattern_file_name);
+
+ for (i = 0; i < num_patterns; ++i)
+ new_save_patterns[i] = save_patterns[i];
+
+ save_patterns = new_save_patterns;
+ num_patterns = new_num_patterns;
+}
+
+/* Skip the padding on IN_FILE_DES after a header or file,
+ up to the next header.
+ The number of bytes skipped is based on OFFSET -- the current offset
+ from the last start of a header (or file) -- and the current
+ header type. */
+
+static void
+skip_padding (in_file_des, offset)
+ int in_file_des;
+ int offset;
+{
+ int pad;
+
+ if (archive_format == arf_crcascii || archive_format == arf_newascii)
+ pad = (4 - (offset % 4)) % 4;
+ else if (archive_format == arf_binary || archive_format == arf_hpbinary)
+ pad = (2 - (offset % 2)) % 2;
+ else if (archive_format == arf_tar || archive_format == arf_ustar)
+ pad = (512 - (offset % 512)) % 512;
+ else
+ pad = 0;
+
+ if (pad != 0)
+ toss_input (in_file_des, pad);
+}
+
+
+/* The newc and crc formats store multiply linked copies of the same file
+ in the archive only once. The actual data is attached to the last link
+ in the archive, and the other links all have a filesize of 0. When a
+ file in the archive has multiple links and a filesize of 0, its data is
+ probably "attatched" to another file in the archive, so we can't create
+ it right away. We have to "defer" creating it until we have created
+ the file that has the data "attatched" to it. We keep a list of the
+ "defered" links on deferments. */
+
+struct deferment *deferments = NULL;
+
+/* Add a file header to the deferments list. For now they all just
+ go on one list, although we could optimize this if necessary. */
+
+static void
+defer_copyin (file_hdr)
+ struct new_cpio_header *file_hdr;
+{
+ struct deferment *d;
+ d = create_deferment (file_hdr);
+ d->next = deferments;
+ deferments = d;
+ return;
+}
+
+/* We just created a file that (probably) has some other links to it
+ which have been defered. Go through all of the links on the deferments
+ list and create any which are links to this file. */
+
+static void
+create_defered_links (file_hdr)
+ struct new_cpio_header *file_hdr;
+{
+ struct deferment *d;
+ struct deferment *d_prev;
+ int ino;
+ int maj;
+ int min;
+ int link_res;
+ ino = file_hdr->c_ino;
+ maj = file_hdr->c_dev_maj;
+ min = file_hdr->c_dev_min;
+ d = deferments;
+ d_prev = NULL;
+ while (d != NULL)
+ {
+ if ( (d->header.c_ino == ino) && (d->header.c_dev_maj == maj)
+ && (d->header.c_dev_min == min) )
+ {
+ struct deferment *d_free;
+ link_res = link_to_name (d->header.c_name, file_hdr->c_name);
+ if (link_res < 0)
+ {
+ error (0, errno, "cannot link %s to %s",
+ d->header.c_name, file_hdr->c_name);
+ }
+ if (d_prev != NULL)
+ d_prev->next = d->next;
+ else
+ deferments = d->next;
+ d_free = d;
+ d = d->next;
+ free_deferment (d_free);
+ }
+ else
+ {
+ d_prev = d;
+ d = d->next;
+ }
+ }
+}
+
+/* If we had a multiply linked file that really was empty then we would
+ have defered all of its links, since we never found any with data
+ "attached", and they will still be on the deferment list even when
+ we are done reading the whole archive. Write out all of these
+ empty links that are still on the deferments list. */
+
+static void
+create_final_defers ()
+{
+ struct deferment *d;
+ struct deferment *d_prev;
+ struct new_cpio_header *h;
+ int link_res;
+ int out_file_des;
+ struct utimbuf times; /* For setting file times. */
+ /* Initialize this in case it has members we don't know to set. */
+ bzero (&times, sizeof (struct utimbuf));
+
+ for (d = deferments; d != NULL; d = d->next)
+ {
+ d = deferments;
+ link_res = link_to_maj_min_ino (d->header.c_name,
+ d->header.c_dev_maj, d->header.c_dev_maj,
+ d->header.c_ino);
+ if (link_res == 0)
+ {
+ continue;
+ }
+ out_file_des = open (d->header.c_name,
+ O_CREAT | O_WRONLY | O_BINARY, 0600);
+ if (out_file_des < 0 && create_dir_flag)
+ {
+ create_all_directories (d->header.c_name);
+ out_file_des = open (d->header.c_name,
+ O_CREAT | O_WRONLY | O_BINARY,
+ 0600);
+ }
+ if (out_file_des < 0)
+ {
+ error (0, errno, "%s", d->header.c_name);
+ continue;
+ }
+
+ if (close (out_file_des) < 0)
+ error (0, errno, "%s", d->header.c_name);
+
+ /* File is now copied; set attributes. */
+ if (!no_chown_flag)
+ if ((chown (d->header.c_name,
+ set_owner_flag ? set_owner : d->header.c_uid,
+ set_group_flag ? set_group : d->header.c_gid) < 0)
+ && errno != EPERM)
+ error (0, errno, "%s", d->header.c_name);
+ /* chown may have turned off some permissions we wanted. */
+ if (chmod (d->header.c_name, (int) d->header.c_mode) < 0)
+ error (0, errno, "%s", d->header.c_name);
+ if (retain_time_flag)
+ {
+ times.actime = times.modtime = d->header.c_mtime;
+ if (utime (d->header.c_name, &times) < 0)
+ error (0, errno, "%s", d->header.c_name);
+ }
+ }
+}
diff --git a/gnu/usr.bin/cpio/copyout.c b/gnu/usr.bin/cpio/copyout.c
new file mode 100644
index 0000000..77053d9
--- /dev/null
+++ b/gnu/usr.bin/cpio/copyout.c
@@ -0,0 +1,936 @@
+/* copyout.c - create a cpio archive
+ Copyright (C) 1990, 1991, 1992 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include "filetypes.h"
+#include "system.h"
+#include "cpiohdr.h"
+#include "dstring.h"
+#include "extern.h"
+#include "defer.h"
+#include "rmt.h"
+
+static unsigned long read_for_checksum ();
+static void clear_rest_of_block ();
+static void pad_output ();
+static int last_link ();
+static int count_defered_links_to_dev_ino ();
+static void add_link_defer ();
+static void writeout_other_defers ();
+static void writeout_final_defers();
+static void writeout_defered_file ();
+static int check_rdev ();
+
+/* Write out header FILE_HDR, including the file name, to file
+ descriptor OUT_DES. */
+
+void
+write_out_header (file_hdr, out_des)
+ struct new_cpio_header *file_hdr;
+ int out_des;
+{
+ if (archive_format == arf_newascii || archive_format == arf_crcascii)
+ {
+ char ascii_header[112];
+ char *magic_string;
+
+ if (archive_format == arf_crcascii)
+ magic_string = "070702";
+ else
+ magic_string = "070701";
+ sprintf (ascii_header,
+ "%6s%08lx%08lx%08lx%08lx%08lx%08lx%08lx%08lx%08lx%08lx%08lx%08lx%08lx",
+ magic_string,
+ file_hdr->c_ino, file_hdr->c_mode, file_hdr->c_uid,
+ file_hdr->c_gid, file_hdr->c_nlink, file_hdr->c_mtime,
+ file_hdr->c_filesize, file_hdr->c_dev_maj, file_hdr->c_dev_min,
+ file_hdr->c_rdev_maj, file_hdr->c_rdev_min, file_hdr->c_namesize,
+ file_hdr->c_chksum);
+ copy_buf_out (ascii_header, out_des, 110L);
+
+ /* Write file name to output. */
+ copy_buf_out (file_hdr->c_name, out_des, (long) file_hdr->c_namesize);
+ pad_output (out_des, file_hdr->c_namesize + 110);
+ }
+ else if (archive_format == arf_oldascii || archive_format == arf_hpoldascii)
+ {
+ char ascii_header[78];
+#ifndef __MSDOS__
+ dev_t dev;
+ dev_t rdev;
+
+ if (archive_format == arf_oldascii)
+ {
+ dev = makedev (file_hdr->c_dev_maj, file_hdr->c_dev_min);
+ rdev = makedev (file_hdr->c_rdev_maj, file_hdr->c_rdev_min);
+ }
+ else
+ {
+ /* HP/UX cpio creates archives that look just like ordinary archives,
+ but for devices it sets major = 0, minor = 1, and puts the
+ actual major/minor number in the filesize field. */
+ switch (file_hdr->c_mode & CP_IFMT)
+ {
+ case CP_IFCHR:
+ case CP_IFBLK:
+#ifdef CP_IFSOCK
+ case CP_IFSOCK:
+#endif
+#ifdef CP_IFIFO
+ case CP_IFIFO:
+#endif
+ file_hdr->c_filesize = makedev (file_hdr->c_rdev_maj,
+ file_hdr->c_rdev_min);
+ rdev = 1;
+ break;
+ default:
+ dev = makedev (file_hdr->c_dev_maj, file_hdr->c_dev_min);
+ rdev = makedev (file_hdr->c_rdev_maj, file_hdr->c_rdev_min);
+ break;
+ }
+ }
+#else
+ int dev = 0, rdev = 0;
+#endif
+
+ if ((file_hdr->c_ino >> 16) != 0)
+ error (0, 0, "%s: truncating inode number", file_hdr->c_name);
+
+ sprintf (ascii_header,
+ "%06lo%06lo%06lo%06lo%06lo%06lo%06lo%06lo%011lo%06lo%011lo",
+ file_hdr->c_magic & 0xFFFF, dev & 0xFFFF,
+ file_hdr->c_ino & 0xFFFF, file_hdr->c_mode & 0xFFFF,
+ file_hdr->c_uid & 0xFFFF, file_hdr->c_gid & 0xFFFF,
+ file_hdr->c_nlink & 0xFFFF, rdev & 0xFFFF,
+ file_hdr->c_mtime, file_hdr->c_namesize & 0xFFFF,
+ file_hdr->c_filesize);
+ copy_buf_out (ascii_header, out_des, 76L);
+
+ /* Write file name to output. */
+ copy_buf_out (file_hdr->c_name, out_des, (long) file_hdr->c_namesize);
+ }
+ else if (archive_format == arf_tar || archive_format == arf_ustar)
+ {
+ write_out_tar_header (file_hdr, out_des);
+ }
+ else
+ {
+ struct old_cpio_header short_hdr;
+
+ short_hdr.c_magic = 070707;
+ short_hdr.c_dev = makedev (file_hdr->c_dev_maj, file_hdr->c_dev_min);
+
+ if ((file_hdr->c_ino >> 16) != 0)
+ error (0, 0, "%s: truncating inode number", file_hdr->c_name);
+
+ short_hdr.c_ino = file_hdr->c_ino & 0xFFFF;
+ short_hdr.c_mode = file_hdr->c_mode & 0xFFFF;
+ short_hdr.c_uid = file_hdr->c_uid & 0xFFFF;
+ short_hdr.c_gid = file_hdr->c_gid & 0xFFFF;
+ short_hdr.c_nlink = file_hdr->c_nlink & 0xFFFF;
+ if (archive_format != arf_hpbinary)
+ short_hdr.c_rdev = makedev (file_hdr->c_rdev_maj, file_hdr->c_rdev_min);
+ else
+ {
+ switch (file_hdr->c_mode & CP_IFMT)
+ {
+ /* HP/UX cpio creates archives that look just like ordinary
+ archives, but for devices it sets major = 0, minor = 1, and
+ puts the actual major/minor number in the filesize field. */
+ case CP_IFCHR:
+ case CP_IFBLK:
+#ifdef CP_IFSOCK
+ case CP_IFSOCK:
+#endif
+#ifdef CP_IFIFO
+ case CP_IFIFO:
+#endif
+ file_hdr->c_filesize = makedev (file_hdr->c_rdev_maj,
+ file_hdr->c_rdev_min);
+ short_hdr.c_rdev = makedev (0, 1);
+ break;
+ default:
+ short_hdr.c_rdev = makedev (file_hdr->c_rdev_maj,
+ file_hdr->c_rdev_min);
+ break;
+ }
+ }
+ short_hdr.c_mtimes[0] = file_hdr->c_mtime >> 16;
+ short_hdr.c_mtimes[1] = file_hdr->c_mtime & 0xFFFF;
+
+ short_hdr.c_namesize = file_hdr->c_namesize & 0xFFFF;
+
+ short_hdr.c_filesizes[0] = file_hdr->c_filesize >> 16;
+ short_hdr.c_filesizes[1] = file_hdr->c_filesize & 0xFFFF;
+
+ /* Output the file header. */
+ copy_buf_out ((char *) &short_hdr, out_des, 26L);
+
+ /* Write file name to output. */
+ copy_buf_out (file_hdr->c_name, out_des, (long) file_hdr->c_namesize);
+
+ pad_output (out_des, file_hdr->c_namesize + 26);
+ }
+}
+
+/* Read a list of file names from the standard input
+ and write a cpio collection on the standard output.
+ The format of the header depends on the compatibility (-c) flag. */
+
+void
+process_copy_out ()
+{
+ int res; /* Result of functions. */
+ dynamic_string input_name; /* Name of file read from stdin. */
+ struct utimbuf times; /* For resetting file times after copy. */
+ struct stat file_stat; /* Stat record for file. */
+ struct new_cpio_header file_hdr; /* Output header information. */
+ int in_file_des; /* Source file descriptor. */
+ int out_file_des; /* Output file descriptor. */
+ char *p;
+
+ /* Initialize the copy out. */
+ ds_init (&input_name, 128);
+ /* Initialize this in case it has members we don't know to set. */
+ bzero (&times, sizeof (struct utimbuf));
+ file_hdr.c_magic = 070707;
+
+#ifdef __MSDOS__
+ setmode (archive_des, O_BINARY);
+#endif
+ /* Check whether the output file might be a tape. */
+ out_file_des = archive_des;
+ if (_isrmt (out_file_des))
+ {
+ output_is_special = 1;
+ output_is_seekable = 0;
+ }
+ else
+ {
+ if (fstat (out_file_des, &file_stat))
+ error (1, errno, "standard output is closed");
+ output_is_special =
+#ifdef S_ISBLK
+ S_ISBLK (file_stat.st_mode) ||
+#endif
+ S_ISCHR (file_stat.st_mode);
+ output_is_seekable = S_ISREG (file_stat.st_mode);
+ }
+
+ if (append_flag)
+ {
+ process_copy_in ();
+ prepare_append (out_file_des);
+ }
+
+ /* Copy files with names read from stdin. */
+ while (ds_fgetstr (stdin, &input_name, name_end) != NULL)
+ {
+ /* Check for blank line. */
+ if (input_name.ds_string[0] == 0)
+ {
+ error (0, 0, "blank line ignored");
+ continue;
+ }
+
+ /* Process next file. */
+ if ((*xstat) (input_name.ds_string, &file_stat) < 0)
+ error (0, errno, "%s", input_name.ds_string);
+ else
+ {
+ /* Set values in output header. */
+ file_hdr.c_dev_maj = major (file_stat.st_dev);
+ file_hdr.c_dev_min = minor (file_stat.st_dev);
+ file_hdr.c_ino = file_stat.st_ino;
+ /* For POSIX systems that don't define the S_IF macros,
+ we can't assume that S_ISfoo means the standard Unix
+ S_IFfoo bit(s) are set. So do it manually, with a
+ different name. Bleah. */
+ file_hdr.c_mode = (file_stat.st_mode & 07777);
+ if (S_ISREG (file_stat.st_mode))
+ file_hdr.c_mode |= CP_IFREG;
+ else if (S_ISDIR (file_stat.st_mode))
+ file_hdr.c_mode |= CP_IFDIR;
+#ifdef S_ISBLK
+ else if (S_ISBLK (file_stat.st_mode))
+ file_hdr.c_mode |= CP_IFBLK;
+#endif
+#ifdef S_ISCHR
+ else if (S_ISCHR (file_stat.st_mode))
+ file_hdr.c_mode |= CP_IFCHR;
+#endif
+#ifdef S_ISFIFO
+ else if (S_ISFIFO (file_stat.st_mode))
+ file_hdr.c_mode |= CP_IFIFO;
+#endif
+#ifdef S_ISLNK
+ else if (S_ISLNK (file_stat.st_mode))
+ file_hdr.c_mode |= CP_IFLNK;
+#endif
+#ifdef S_ISSOCK
+ else if (S_ISSOCK (file_stat.st_mode))
+ file_hdr.c_mode |= CP_IFSOCK;
+#endif
+#ifdef S_ISNWK
+ else if (S_ISNWK (file_stat.st_mode))
+ file_hdr.c_mode |= CP_IFNWK;
+#endif
+ file_hdr.c_uid = file_stat.st_uid;
+ file_hdr.c_gid = file_stat.st_gid;
+ file_hdr.c_nlink = file_stat.st_nlink;
+
+ /* The rdev is meaningless except for block and character
+ special files (POSIX standard) and perhaps fifos and
+ sockets. Clear it for other types of files so that
+ check_rdev() doesn't reject files just because stat()
+ put garbage in st_rdev and so that the output doesn't
+ depend on the garbage. */
+ switch (file_hdr.c_mode & CP_IFMT)
+ {
+ case CP_IFBLK:
+ case CP_IFCHR:
+#ifdef CP_IFIFO
+ case CP_IFIFO:
+#endif
+#ifdef CP_IFSOCK
+ case CP_IFSOCK:
+#endif
+ file_hdr.c_rdev_maj = major (file_stat.st_rdev);
+ file_hdr.c_rdev_min = minor (file_stat.st_rdev);
+ break;
+ default:
+ file_hdr.c_rdev_maj = 0;
+ file_hdr.c_rdev_min = 0;
+ break;
+ }
+
+ file_hdr.c_mtime = file_stat.st_mtime;
+ file_hdr.c_filesize = file_stat.st_size;
+ file_hdr.c_chksum = 0;
+ file_hdr.c_tar_linkname = NULL;
+
+ /* Strip leading `./' from the filename. */
+ p = input_name.ds_string;
+ while (*p == '.' && *(p + 1) == '/')
+ {
+ ++p;
+ while (*p == '/')
+ ++p;
+ }
+#ifndef HPUX_CDF
+ file_hdr.c_name = p;
+ file_hdr.c_namesize = strlen (p) + 1;
+#else
+ if ( (archive_format != arf_tar) && (archive_format != arf_ustar) )
+ {
+ /* We mark CDF's in cpio files by adding a 2nd `/' after the
+ "hidden" directory name. We need to do this so we can
+ properly recreate the directory as hidden (in case the
+ files of a directory go into the archive before the
+ directory itself (e.g from "find ... -depth ... | cpio")). */
+ file_hdr.c_name = add_cdf_double_slashes (p);
+ file_hdr.c_namesize = strlen (file_hdr.c_name) + 1;
+ }
+ else
+ {
+ /* We don't mark CDF's in tar files. We assume the "hidden"
+ directory will always go into the archive before any of
+ its files. */
+ file_hdr.c_name = p;
+ file_hdr.c_namesize = strlen (p) + 1;
+ }
+#endif
+ if ((archive_format == arf_tar || archive_format == arf_ustar)
+ && is_tar_filename_too_long (file_hdr.c_name))
+ {
+ error (0, 0, "%s: file name too long", file_hdr.c_name);
+ continue;
+ }
+ switch (check_rdev (&file_hdr))
+ {
+ case 1:
+ error (0, 0, "%s not dumped: major number would be truncated",
+ file_hdr.c_name);
+ continue;
+ case 2:
+ error (0, 0, "%s not dumped: minor number would be truncated",
+ file_hdr.c_name);
+ continue;
+ case 4:
+ error (0, 0, "%s not dumped: device number would be truncated",
+ file_hdr.c_name);
+ continue;
+ }
+
+ /* Copy the named file to the output. */
+ switch (file_hdr.c_mode & CP_IFMT)
+ {
+ case CP_IFREG:
+#ifndef __MSDOS__
+ if (archive_format == arf_tar || archive_format == arf_ustar)
+ {
+ char *otherfile;
+ if ((otherfile = find_inode_file (file_hdr.c_ino,
+ file_hdr.c_dev_maj,
+ file_hdr.c_dev_min)))
+ {
+ file_hdr.c_tar_linkname = otherfile;
+ write_out_header (&file_hdr, out_file_des);
+ break;
+ }
+ }
+ if ( (archive_format == arf_newascii || archive_format == arf_crcascii)
+ && (file_hdr.c_nlink > 1) )
+ {
+ if (last_link (&file_hdr) )
+ {
+ writeout_other_defers (&file_hdr, out_file_des);
+ }
+ else
+ {
+ add_link_defer (&file_hdr);
+ break;
+ }
+ }
+#endif
+ in_file_des = open (input_name.ds_string,
+ O_RDONLY | O_BINARY, 0);
+ if (in_file_des < 0)
+ {
+ error (0, errno, "%s", input_name.ds_string);
+ continue;
+ }
+
+ if (archive_format == arf_crcascii)
+ file_hdr.c_chksum = read_for_checksum (in_file_des,
+ file_hdr.c_filesize,
+ input_name.ds_string);
+
+ write_out_header (&file_hdr, out_file_des);
+ copy_files (in_file_des, out_file_des, file_hdr.c_filesize);
+
+#ifndef __MSDOS__
+ if (archive_format == arf_tar || archive_format == arf_ustar)
+ add_inode (file_hdr.c_ino, file_hdr.c_name, file_hdr.c_dev_maj,
+ file_hdr.c_dev_min);
+#endif
+
+ pad_output (out_file_des, file_hdr.c_filesize);
+
+ if (close (in_file_des) < 0)
+ error (0, errno, "%s", input_name.ds_string);
+ if (reset_time_flag)
+ {
+ times.actime = file_stat.st_atime;
+ times.modtime = file_stat.st_mtime;
+ if (utime (file_hdr.c_name, &times) < 0)
+ error (0, errno, "%s", file_hdr.c_name);
+ }
+ break;
+
+ case CP_IFDIR:
+ file_hdr.c_filesize = 0;
+ write_out_header (&file_hdr, out_file_des);
+ break;
+
+#ifndef __MSDOS__
+ case CP_IFCHR:
+ case CP_IFBLK:
+#ifdef CP_IFSOCK
+ case CP_IFSOCK:
+#endif
+#ifdef CP_IFIFO
+ case CP_IFIFO:
+#endif
+ if (archive_format == arf_tar)
+ {
+ error (0, 0, "%s not dumped: not a regular file",
+ file_hdr.c_name);
+ continue;
+ }
+ else if (archive_format == arf_ustar)
+ {
+ char *otherfile;
+ if ((otherfile = find_inode_file (file_hdr.c_ino,
+ file_hdr.c_dev_maj,
+ file_hdr.c_dev_min)))
+ {
+ /* This file is linked to another file already in the
+ archive, so write it out as a hard link. */
+ file_hdr.c_mode = (file_stat.st_mode & 07777);
+ file_hdr.c_mode |= CP_IFREG;
+ file_hdr.c_tar_linkname = otherfile;
+ write_out_header (&file_hdr, out_file_des);
+ break;
+ }
+ add_inode (file_hdr.c_ino, file_hdr.c_name,
+ file_hdr.c_dev_maj, file_hdr.c_dev_min);
+ }
+ file_hdr.c_filesize = 0;
+ write_out_header (&file_hdr, out_file_des);
+ break;
+#endif
+
+#ifdef CP_IFLNK
+ case CP_IFLNK:
+ {
+ char *link_name = (char *) xmalloc (file_stat.st_size + 1);
+
+ if (readlink (input_name.ds_string, link_name,
+ file_stat.st_size) < 0)
+ {
+ error (0, errno, "%s", input_name.ds_string);
+ free (link_name);
+ continue;
+ }
+ if (archive_format == arf_tar || archive_format == arf_ustar)
+ {
+ if (file_stat.st_size + 1 > 100)
+ {
+ error (0, 0, "%s: symbolic link too long",
+ file_hdr.c_name);
+ }
+ else
+ {
+ link_name[file_stat.st_size] = '\0';
+ file_hdr.c_tar_linkname = link_name;
+ write_out_header (&file_hdr, out_file_des);
+ }
+ }
+ else
+ {
+ write_out_header (&file_hdr, out_file_des);
+ copy_buf_out (link_name, out_file_des, file_stat.st_size);
+ pad_output (out_file_des, file_hdr.c_filesize);
+ }
+ free (link_name);
+ }
+ break;
+#endif
+
+ default:
+ error (0, 0, "%s: unknown file type", input_name.ds_string);
+ }
+
+ if (verbose_flag)
+ fprintf (stderr, "%s\n", input_name.ds_string);
+ if (dot_flag)
+ fputc ('.', stderr);
+ }
+ }
+
+ writeout_final_defers(out_file_des);
+ /* The collection is complete; append the trailer. */
+ file_hdr.c_ino = 0;
+ file_hdr.c_mode = 0;
+ file_hdr.c_uid = 0;
+ file_hdr.c_gid = 0;
+ file_hdr.c_nlink = 1; /* Must be 1 for crc format. */
+ file_hdr.c_dev_maj = 0;
+ file_hdr.c_dev_min = 0;
+ file_hdr.c_rdev_maj = 0;
+ file_hdr.c_rdev_min = 0;
+ file_hdr.c_mtime = 0;
+ file_hdr.c_chksum = 0;
+
+ file_hdr.c_filesize = 0;
+ file_hdr.c_namesize = 11;
+ file_hdr.c_name = "TRAILER!!!";
+ if (archive_format != arf_tar && archive_format != arf_ustar)
+ write_out_header (&file_hdr, out_file_des);
+ else
+ {
+ copy_buf_out (zeros_512, out_file_des, 512);
+ copy_buf_out (zeros_512, out_file_des, 512);
+ }
+
+ /* Fill up the output block. */
+ clear_rest_of_block (out_file_des);
+ empty_output_buffer (out_file_des);
+ if (dot_flag)
+ fputc ('\n', stderr);
+ res = (output_bytes + io_block_size - 1) / io_block_size;
+ if (res == 1)
+ fprintf (stderr, "1 block\n");
+ else
+ fprintf (stderr, "%d blocks\n", res);
+}
+
+/* Read FILE_SIZE bytes of FILE_NAME from IN_FILE_DES and
+ compute and return a checksum for them. */
+
+static unsigned long
+read_for_checksum (in_file_des, file_size, file_name)
+ int in_file_des;
+ int file_size;
+ char *file_name;
+{
+ unsigned long crc;
+ char buf[BUFSIZ];
+ int bytes_left;
+ int bytes_read;
+ int i;
+
+ crc = 0;
+
+ for (bytes_left = file_size; bytes_left > 0; bytes_left -= bytes_read)
+ {
+ bytes_read = read (in_file_des, buf, BUFSIZ);
+ if (bytes_read < 0)
+ error (1, errno, "cannot read checksum for %s", file_name);
+ if (bytes_read == 0)
+ break;
+ for (i = 0; i < bytes_read; ++i)
+ crc += buf[i] & 0xff;
+ }
+ if (lseek (in_file_des, 0L, SEEK_SET))
+ error (1, errno, "cannot read checksum for %s", file_name);
+
+ return crc;
+}
+
+/* Write out NULs to fill out the rest of the current block on
+ OUT_FILE_DES. */
+
+static void
+clear_rest_of_block (out_file_des)
+ int out_file_des;
+{
+ while (output_size < io_block_size)
+ {
+ if ((io_block_size - output_size) > 512)
+ copy_buf_out (zeros_512, out_file_des, 512);
+ else
+ copy_buf_out (zeros_512, out_file_des, io_block_size - output_size);
+ }
+}
+
+/* Write NULs on OUT_FILE_DES to move from OFFSET (the current location)
+ to the end of the header. */
+
+static void
+pad_output (out_file_des, offset)
+ int out_file_des;
+ int offset;
+{
+ int pad;
+
+ if (archive_format == arf_newascii || archive_format == arf_crcascii)
+ pad = (4 - (offset % 4)) % 4;
+ else if (archive_format == arf_tar || archive_format == arf_ustar)
+ pad = (512 - (offset % 512)) % 512;
+ else if (archive_format != arf_oldascii && archive_format != arf_hpoldascii)
+ pad = (2 - (offset % 2)) % 2;
+ else
+ pad = 0;
+
+ if (pad != 0)
+ copy_buf_out (zeros_512, out_file_des, pad);
+}
+
+
+/* When creating newc and crc archives if a file has multiple (hard)
+ links, we don't put any of them into the archive until we have seen
+ all of them (or until we get to the end of the list of files that
+ are going into the archive and know that we have seen all of the links
+ to the file that we will see). We keep these "defered" files on
+ this list. */
+
+struct deferment *deferouts = NULL;
+
+
+/* Is this file_hdr the last (hard) link to a file? I.e., have
+ we already seen and defered all of the other links? */
+
+static int
+last_link (file_hdr)
+ struct new_cpio_header *file_hdr;
+{
+ int other_files_sofar;
+
+ other_files_sofar = count_defered_links_to_dev_ino (file_hdr);
+ if (file_hdr->c_nlink == (other_files_sofar + 1) )
+ {
+ return 1;
+ }
+ return 0;
+}
+
+/* Count the number of other (hard) links to this file that have
+ already been defered. */
+
+static int
+count_defered_links_to_dev_ino (file_hdr)
+ struct new_cpio_header *file_hdr;
+{
+ struct deferment *d;
+ int ino;
+ int maj;
+ int min;
+ int count;
+ ino = file_hdr->c_ino;
+ maj = file_hdr->c_dev_maj;
+ min = file_hdr->c_dev_min;
+ count = 0;
+ for (d = deferouts; d != NULL; d = d->next)
+ {
+ if ( (d->header.c_ino == ino) && (d->header.c_dev_maj == maj)
+ && (d->header.c_dev_min == min) )
+ ++count;
+ }
+ return count;
+}
+
+/* Add the file header for a link that is being defered to the deferouts
+ list. */
+
+static void
+add_link_defer (file_hdr)
+ struct new_cpio_header *file_hdr;
+{
+ struct deferment *d;
+ d = create_deferment (file_hdr);
+ d->next = deferouts;
+ deferouts = d;
+}
+
+/* We are about to put a file into a newc or crc archive that is
+ multiply linked. We have already seen and defered all of the
+ other links to the file but haven't written them into the archive.
+ Write the other links into the archive, and remove them from the
+ deferouts list. */
+
+static void
+writeout_other_defers (file_hdr, out_des)
+ struct new_cpio_header *file_hdr;
+ int out_des;
+{
+ struct deferment *d;
+ struct deferment *d_prev;
+ int ino;
+ int maj;
+ int min;
+ int count;
+ ino = file_hdr->c_ino;
+ maj = file_hdr->c_dev_maj;
+ min = file_hdr->c_dev_min;
+ d_prev = NULL;
+ d = deferouts;
+ while (d != NULL)
+ {
+ if ( (d->header.c_ino == ino) && (d->header.c_dev_maj == maj)
+ && (d->header.c_dev_min == min) )
+ {
+ struct deferment *d_free;
+ d->header.c_filesize = 0;
+ write_out_header (&d->header, out_des);
+ if (d_prev != NULL)
+ d_prev->next = d->next;
+ else
+ deferouts = d->next;
+ d_free = d;
+ d = d->next;
+ free_deferment (d_free);
+ }
+ else
+ {
+ d_prev = d;
+ d = d->next;
+ }
+ }
+ return;
+}
+/* When writing newc and crc format archives we defer multiply linked
+ files until we have seen all of the links to the file. If a file
+ has links to it that aren't going into the archive, then we will
+ never see the "last" link to the file, so at the end we just write
+ all of the leftover defered files into the archive. */
+
+static void
+writeout_final_defers(out_des)
+ int out_des;
+{
+ struct deferment *d;
+ int other_count;
+ while (deferouts != NULL)
+ {
+ d = deferouts;
+ other_count = count_defered_links_to_dev_ino (&d->header);
+ if (other_count == 1)
+ {
+ writeout_defered_file (&d->header, out_des);
+ }
+ else
+ {
+ struct new_cpio_header file_hdr;
+ file_hdr = d->header;
+ file_hdr.c_filesize = 0;
+ write_out_header (&file_hdr, out_des);
+ }
+ deferouts = deferouts->next;
+ }
+}
+
+/* Write a file into the archive. This code is the same as
+ the code in process_copy_out(), but we need it here too
+ for writeout_final_defers() to call. */
+
+static void
+writeout_defered_file (header, out_file_des)
+ struct new_cpio_header *header;
+{
+ int in_file_des;
+ struct new_cpio_header file_hdr;
+ struct utimbuf times; /* For setting file times. */
+ /* Initialize this in case it has members we don't know to set. */
+ bzero (&times, sizeof (struct utimbuf));
+
+ file_hdr = *header;
+
+
+ in_file_des = open (header->c_name,
+ O_RDONLY | O_BINARY, 0);
+ if (in_file_des < 0)
+ {
+ error (0, errno, "%s", header->c_name);
+ return;
+ }
+
+ if (archive_format == arf_crcascii)
+ file_hdr.c_chksum = read_for_checksum (in_file_des,
+ file_hdr.c_filesize,
+ header->c_name);
+
+ write_out_header (&file_hdr, out_file_des);
+ copy_files (in_file_des, out_file_des, file_hdr.c_filesize);
+
+#ifndef __MSDOS__
+ if (archive_format == arf_tar || archive_format == arf_ustar)
+ add_inode (file_hdr.c_ino, file_hdr.c_name, file_hdr.c_dev_maj,
+ file_hdr.c_dev_min);
+#endif
+
+ pad_output (out_file_des, file_hdr.c_filesize);
+
+ if (close (in_file_des) < 0)
+ error (0, errno, "%s", header->c_name);
+ if (reset_time_flag)
+ {
+ times.actime = file_hdr.c_mtime;
+ times.modtime = file_hdr.c_mtime;
+ if (utime (file_hdr.c_name, &times) < 0)
+ error (0, errno, "%s", file_hdr.c_name);
+ }
+ return;
+}
+
+static int
+check_rdev (file_hdr)
+ struct new_cpio_header *file_hdr;
+{
+ if (archive_format == arf_newascii || archive_format == arf_crcascii)
+ {
+ if ((file_hdr->c_rdev_maj & 0xFFFFFFFF) != file_hdr->c_rdev_maj)
+ return 1;
+ if ((file_hdr->c_rdev_min & 0xFFFFFFFF) != file_hdr->c_rdev_min)
+ return 2;
+ }
+ else if (archive_format == arf_oldascii || archive_format == arf_hpoldascii)
+ {
+#ifndef __MSDOS__
+ dev_t rdev;
+
+ rdev = makedev (file_hdr->c_rdev_maj, file_hdr->c_rdev_min);
+ if (archive_format == arf_oldascii)
+ {
+ if ((rdev & 0xFFFF) != rdev)
+ return 4;
+ }
+ else
+ {
+ switch (file_hdr->c_mode & CP_IFMT)
+ {
+ case CP_IFCHR:
+ case CP_IFBLK:
+#ifdef CP_IFSOCK
+ case CP_IFSOCK:
+#endif
+#ifdef CP_IFIFO
+ case CP_IFIFO:
+#endif
+ /* We could handle one more bit if longs are >= 33 bits. */
+ if ((rdev & 037777777777) != rdev)
+ return 4;
+ break;
+ default:
+ if ((rdev & 0xFFFF) != rdev)
+ return 4;
+ break;
+ }
+ }
+#endif
+ }
+ else if (archive_format == arf_tar || archive_format == arf_ustar)
+ {
+ /* The major and minor formats are limited to 7 octal digits in ustar
+ format, and to_oct () adds a gratuitous trailing blank to further
+ limit the format to 6 octal digits. */
+ if ((file_hdr->c_rdev_maj & 0777777) != file_hdr->c_rdev_maj)
+ return 1;
+ if ((file_hdr->c_rdev_min & 0777777) != file_hdr->c_rdev_min)
+ return 2;
+ }
+ else
+ {
+#ifndef __MSDOS__
+ dev_t rdev;
+
+ rdev = makedev (file_hdr->c_rdev_maj, file_hdr->c_rdev_min);
+ if (archive_format != arf_hpbinary)
+ {
+ if ((rdev & 0xFFFF) != rdev)
+ return 4;
+ }
+ else
+ {
+ switch (file_hdr->c_mode & CP_IFMT)
+ {
+ case CP_IFCHR:
+ case CP_IFBLK:
+#ifdef CP_IFSOCK
+ case CP_IFSOCK:
+#endif
+#ifdef CP_IFIFO
+ case CP_IFIFO:
+#endif
+ if ((rdev & 0xFFFFFFFF) != rdev)
+ return 4;
+ file_hdr->c_filesize = rdev;
+ rdev = makedev (0, 1);
+ break;
+ default:
+ if ((rdev & 0xFFFF) != rdev)
+ return 4;
+ break;
+ }
+ }
+#endif
+ }
+ return 0;
+}
diff --git a/gnu/usr.bin/cpio/copypass.c b/gnu/usr.bin/cpio/copypass.c
new file mode 100644
index 0000000..0bf7c60
--- /dev/null
+++ b/gnu/usr.bin/cpio/copypass.c
@@ -0,0 +1,449 @@
+/* copypass.c - cpio copy pass sub-function.
+ Copyright (C) 1990, 1991, 1992 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include "filetypes.h"
+#include "system.h"
+#include "cpiohdr.h"
+#include "dstring.h"
+#include "extern.h"
+
+#ifndef HAVE_LCHOWN
+#define lchown chown
+#endif
+
+/* Copy files listed on the standard input into directory `directory_name'.
+ If `link_flag', link instead of copying. */
+
+void
+process_copy_pass ()
+{
+ dynamic_string input_name; /* Name of file from stdin. */
+ dynamic_string output_name; /* Name of new file. */
+ int dirname_len; /* Length of `directory_name'. */
+ int res; /* Result of functions. */
+ char *slash; /* For moving past slashes in input name. */
+ struct utimbuf times; /* For resetting file times after copy. */
+ struct stat in_file_stat; /* Stat record for input file. */
+ struct stat out_file_stat; /* Stat record for output file. */
+ int in_file_des; /* Input file descriptor. */
+ int out_file_des; /* Output file descriptor. */
+ int existing_dir; /* True if file is a dir & already exists. */
+#ifdef HPUX_CDF
+ int cdf_flag;
+ int cdf_char;
+#endif
+
+ /* Initialize the copy pass. */
+ dirname_len = strlen (directory_name);
+ ds_init (&input_name, 128);
+ ds_init (&output_name, dirname_len + 2);
+ strcpy (output_name.ds_string, directory_name);
+ output_name.ds_string[dirname_len] = '/';
+ output_is_seekable = TRUE;
+ /* Initialize this in case it has members we don't know to set. */
+ bzero (&times, sizeof (struct utimbuf));
+
+ /* Copy files with names read from stdin. */
+ while (ds_fgetstr (stdin, &input_name, name_end) != NULL)
+ {
+ int link_res = -1;
+
+ /* Check for blank line and ignore it if found. */
+ if (input_name.ds_string[0] == '\0')
+ {
+ error (0, 0, "blank line ignored");
+ continue;
+ }
+
+ /* Check for current directory and ignore it if found. */
+ if (input_name.ds_string[0] == '.'
+ && (input_name.ds_string[1] == '\0'
+ || (input_name.ds_string[1] == '/'
+ && input_name.ds_string[2] == '\0')))
+ continue;
+
+ if ((*xstat) (input_name.ds_string, &in_file_stat) < 0)
+ {
+ error (0, errno, "%s", input_name.ds_string);
+ continue;
+ }
+
+ /* Make the name of the new file. */
+ for (slash = input_name.ds_string; *slash == '/'; ++slash)
+ ;
+#ifdef HPUX_CDF
+ /* For CDF's we add a 2nd `/' after all "hidden" directories.
+ This kind of a kludge, but it's what we do when creating
+ archives, and it's easier to do this than to separately
+ keep track of which directories in a path are "hidden". */
+ slash = add_cdf_double_slashes (slash);
+#endif
+ ds_resize (&output_name, dirname_len + strlen (slash) + 2);
+ strcpy (output_name.ds_string + dirname_len + 1, slash);
+
+ existing_dir = FALSE;
+ if (lstat (output_name.ds_string, &out_file_stat) == 0)
+ {
+ if (S_ISDIR (out_file_stat.st_mode)
+ && S_ISDIR (in_file_stat.st_mode))
+ {
+ /* If there is already a directory there that
+ we are trying to create, don't complain about it. */
+ existing_dir = TRUE;
+ }
+ else if (!unconditional_flag
+ && in_file_stat.st_mtime <= out_file_stat.st_mtime)
+ {
+ error (0, 0, "%s not created: newer or same age version exists",
+ output_name.ds_string);
+ continue; /* Go to the next file. */
+ }
+ else if (S_ISDIR (out_file_stat.st_mode)
+ ? rmdir (output_name.ds_string)
+ : unlink (output_name.ds_string))
+ {
+ error (0, errno, "cannot remove current %s",
+ output_name.ds_string);
+ continue; /* Go to the next file. */
+ }
+ }
+
+ /* Do the real copy or link. */
+ if (S_ISREG (in_file_stat.st_mode))
+ {
+#ifndef __MSDOS__
+ /* Can the current file be linked to a another file?
+ Set link_name to the original file name. */
+ if (link_flag)
+ /* User said to link it if possible. Try and link to
+ the original copy. If that fails we'll still try
+ and link to a copy we've already made. */
+ link_res = link_to_name (output_name.ds_string,
+ input_name.ds_string);
+ if ( (link_res < 0) && (in_file_stat.st_nlink > 1) )
+ link_res = link_to_maj_min_ino (output_name.ds_string,
+ major (in_file_stat.st_dev),
+ minor (in_file_stat.st_dev),
+ in_file_stat.st_ino);
+#endif
+
+ /* If the file was not linked, copy contents of file. */
+ if (link_res < 0)
+ {
+ in_file_des = open (input_name.ds_string,
+ O_RDONLY | O_BINARY, 0);
+ if (in_file_des < 0)
+ {
+ error (0, errno, "%s", input_name.ds_string);
+ continue;
+ }
+ out_file_des = open (output_name.ds_string,
+ O_CREAT | O_WRONLY | O_BINARY, 0600);
+ if (out_file_des < 0 && create_dir_flag)
+ {
+ create_all_directories (output_name.ds_string);
+ out_file_des = open (output_name.ds_string,
+ O_CREAT | O_WRONLY | O_BINARY, 0600);
+ }
+ if (out_file_des < 0)
+ {
+ error (0, errno, "%s", output_name.ds_string);
+ close (in_file_des);
+ continue;
+ }
+
+ copy_files (in_file_des, out_file_des, in_file_stat.st_size);
+ empty_output_buffer (out_file_des);
+ if (close (in_file_des) < 0)
+ error (0, errno, "%s", input_name.ds_string);
+ if (close (out_file_des) < 0)
+ error (0, errno, "%s", output_name.ds_string);
+
+ /* Set the attributes of the new file. */
+ if (!no_chown_flag)
+ if ((chown (output_name.ds_string,
+ set_owner_flag ? set_owner : in_file_stat.st_uid,
+ set_group_flag ? set_group : in_file_stat.st_gid) < 0)
+ && errno != EPERM)
+ error (0, errno, "%s", output_name.ds_string);
+ /* chown may have turned off some permissions we wanted. */
+ if (chmod (output_name.ds_string, in_file_stat.st_mode) < 0)
+ error (0, errno, "%s", output_name.ds_string);
+ if (reset_time_flag)
+ {
+ times.actime = in_file_stat.st_atime;
+ times.modtime = in_file_stat.st_mtime;
+ if (utime (input_name.ds_string, &times) < 0)
+ error (0, errno, "%s", input_name.ds_string);
+ if (utime (output_name.ds_string, &times) < 0)
+ error (0, errno, "%s", output_name.ds_string);
+ }
+ if (retain_time_flag)
+ {
+ times.actime = times.modtime = in_file_stat.st_mtime;
+ if (utime (output_name.ds_string, &times) < 0)
+ error (0, errno, "%s", output_name.ds_string);
+ }
+ }
+ }
+ else if (S_ISDIR (in_file_stat.st_mode))
+ {
+#ifdef HPUX_CDF
+ cdf_flag = 0;
+#endif
+ if (!existing_dir)
+ {
+#ifdef HPUX_CDF
+ /* If the directory name ends in a + and is SUID,
+ then it is a CDF. Strip the trailing + from the name
+ before creating it. */
+ cdf_char = strlen (output_name.ds_string) - 1;
+ if ( (cdf_char > 0) &&
+ (in_file_stat.st_mode & 04000) &&
+ (output_name.ds_string [cdf_char] == '+') )
+ {
+ output_name.ds_string [cdf_char] = '\0';
+ cdf_flag = 1;
+ }
+#endif
+ res = mkdir (output_name.ds_string, in_file_stat.st_mode);
+
+ }
+ else
+ res = 0;
+ if (res < 0 && create_dir_flag)
+ {
+ create_all_directories (output_name.ds_string);
+ res = mkdir (output_name.ds_string, in_file_stat.st_mode);
+ }
+ if (res < 0)
+ {
+ error (0, errno, "%s", output_name.ds_string);
+ continue;
+ }
+ if (!no_chown_flag)
+ if ((chown (output_name.ds_string,
+ set_owner_flag ? set_owner : in_file_stat.st_uid,
+ set_group_flag ? set_group : in_file_stat.st_gid) < 0)
+ && errno != EPERM)
+ error (0, errno, "%s", output_name.ds_string);
+ /* chown may have turned off some permissions we wanted. */
+ if (chmod (output_name.ds_string, in_file_stat.st_mode) < 0)
+ error (0, errno, "%s", output_name.ds_string);
+#ifdef HPUX_CDF
+ if (cdf_flag)
+ /* Once we "hide" the directory with the chmod(),
+ we have to refer to it using name+ isntead of name. */
+ output_name.ds_string [cdf_char] = '+';
+#endif
+ if (retain_time_flag)
+ {
+ times.actime = times.modtime = in_file_stat.st_mtime;
+ if (utime (output_name.ds_string, &times) < 0)
+ error (0, errno, "%s", output_name.ds_string);
+ }
+ }
+#ifndef __MSDOS__
+ else if (S_ISCHR (in_file_stat.st_mode) ||
+ S_ISBLK (in_file_stat.st_mode) ||
+#ifdef S_ISFIFO
+ S_ISFIFO (in_file_stat.st_mode) ||
+#endif
+#ifdef S_ISSOCK
+ S_ISSOCK (in_file_stat.st_mode) ||
+#endif
+ 0)
+ {
+ /* Can the current file be linked to a another file?
+ Set link_name to the original file name. */
+ if (link_flag)
+ /* User said to link it if possible. */
+ link_res = link_to_name (output_name.ds_string,
+ input_name.ds_string);
+ if ( (link_res < 0) && (in_file_stat.st_nlink > 1) )
+ link_res = link_to_maj_min_ino (output_name.ds_string,
+ major (in_file_stat.st_dev),
+ minor (in_file_stat.st_dev),
+ in_file_stat.st_ino);
+
+ if (link_res < 0)
+ {
+ res = mknod (output_name.ds_string, in_file_stat.st_mode,
+ in_file_stat.st_rdev);
+ if (res < 0 && create_dir_flag)
+ {
+ create_all_directories (output_name.ds_string);
+ res = mknod (output_name.ds_string, in_file_stat.st_mode,
+ in_file_stat.st_rdev);
+ }
+ if (res < 0)
+ {
+ error (0, errno, "%s", output_name.ds_string);
+ continue;
+ }
+ if (!no_chown_flag)
+ if ((chown (output_name.ds_string,
+ set_owner_flag ? set_owner : in_file_stat.st_uid,
+ set_group_flag ? set_group : in_file_stat.st_gid) < 0)
+ && errno != EPERM)
+ error (0, errno, "%s", output_name.ds_string);
+ /* chown may have turned off some permissions we wanted. */
+ if (chmod (output_name.ds_string, in_file_stat.st_mode) < 0)
+ error (0, errno, "%s", output_name.ds_string);
+ if (retain_time_flag)
+ {
+ times.actime = times.modtime = in_file_stat.st_mtime;
+ if (utime (output_name.ds_string, &times) < 0)
+ error (0, errno, "%s", output_name.ds_string);
+ }
+ }
+ }
+#endif
+
+#ifdef S_ISLNK
+ else if (S_ISLNK (in_file_stat.st_mode))
+ {
+ char *link_name;
+ link_name = (char *) xmalloc ((unsigned int) in_file_stat.st_size + 1);
+
+ if (readlink (input_name.ds_string, link_name,
+ in_file_stat.st_size) < 0)
+ {
+ error (0, errno, "%s", input_name.ds_string);
+ free (link_name);
+ continue;
+ }
+ link_name[in_file_stat.st_size] = '\0';
+
+ res = UMASKED_SYMLINK (link_name, output_name.ds_string,
+ in_file_stat.st_mode);
+ if (res < 0 && create_dir_flag)
+ {
+ create_all_directories (output_name.ds_string);
+ res = UMASKED_SYMLINK (link_name, output_name.ds_string,
+ in_file_stat.st_mode);
+ }
+ if (res < 0)
+ {
+ error (0, errno, "%s", output_name.ds_string);
+ free (link_name);
+ continue;
+ }
+
+ /* Set the attributes of the new link. */
+ if (!no_chown_flag)
+ if ((lchown (output_name.ds_string,
+ set_owner_flag ? set_owner : in_file_stat.st_uid,
+ set_group_flag ? set_group : in_file_stat.st_gid) < 0)
+ && errno != EPERM)
+ error (0, errno, "%s", output_name.ds_string);
+ free (link_name);
+ }
+#endif
+ else
+ {
+ error (0, 0, "%s: unknown file type", input_name.ds_string);
+ }
+
+ if (verbose_flag)
+ fprintf (stderr, "%s\n", output_name.ds_string);
+ if (dot_flag)
+ fputc ('.', stderr);
+ }
+
+ if (dot_flag)
+ fputc ('\n', stderr);
+ res = (output_bytes + io_block_size - 1) / io_block_size;
+ if (res == 1)
+ fprintf (stderr, "1 block\n");
+ else
+ fprintf (stderr, "%d blocks\n", res);
+}
+
+/* Try and create a hard link from FILE_NAME to another file
+ with the given major/minor device number and inode. If no other
+ file with the same major/minor/inode numbers is known, add this file
+ to the list of known files and associated major/minor/inode numbers
+ and return -1. If another file with the same major/minor/inode
+ numbers is found, try and create another link to it using
+ link_to_name, and return 0 for success and -1 for failure. */
+
+int
+link_to_maj_min_ino (file_name, st_dev_maj, st_dev_min, st_ino)
+ char *file_name;
+ int st_dev_maj;
+ int st_dev_min;
+ int st_ino;
+{
+ int link_res;
+ char *link_name;
+ link_res = -1;
+#ifndef __MSDOS__
+ /* Is the file a link to a previously copied file? */
+ link_name = find_inode_file (st_ino,
+ st_dev_maj,
+ st_dev_min);
+ if (link_name == NULL)
+ add_inode (st_ino, file_name,
+ st_dev_maj,
+ st_dev_min);
+ else
+ link_res = link_to_name (file_name, link_name);
+#endif
+ return link_res;
+}
+
+/* Try and create a hard link from LINK_NAME to LINK_TARGET. If
+ `create_dir_flag' is set, any non-existent (parent) directories
+ needed by LINK_NAME will be created. If the link is successfully
+ created and `verbose_flag' is set, print "LINK_TARGET linked to LINK_NAME\n".
+ If the link can not be created and `link_flag' is set, print
+ "cannot link LINK_TARGET to LINK_NAME\n". Return 0 if the link
+ is created, -1 otherwise. */
+
+int
+link_to_name (link_name, link_target)
+ char *link_name;
+ char *link_target;
+{
+ int res;
+#ifdef __MSDOS__
+ res = -1;
+#else /* not __MSDOS__ */
+ res = link (link_target, link_name);
+ if (res < 0 && create_dir_flag)
+ {
+ create_all_directories (link_name);
+ res = link (link_target, link_name);
+ }
+ if (res == 0)
+ {
+ if (verbose_flag)
+ error (0, 0, "%s linked to %s",
+ link_target, link_name);
+ }
+ else if (link_flag)
+ {
+ error (0, errno, "cannot link %s to %s",
+ link_target, link_name);
+ }
+#endif /* not __MSDOS__ */
+ return res;
+}
diff --git a/gnu/usr.bin/cpio/cpio.1 b/gnu/usr.bin/cpio/cpio.1
new file mode 100644
index 0000000..e2aeefd
--- /dev/null
+++ b/gnu/usr.bin/cpio/cpio.1
@@ -0,0 +1,312 @@
+.TH CPIO 1L \" -*- nroff -*-
+.SH NAME
+cpio \- copy files to and from archives
+.SH SYNOPSIS
+.B cpio
+{\-o|\-\-create} [\-0acvABLV] [\-C bytes] [\-H format] [\-M message]
+[\-O [[user@]host:]archive] [\-F [[user@]host:]archive]
+[\-\-file=[[user@]host:]archive] [\-\-format=format] [\-\-message=message]
+[\-\-null] [\-\-reset-access-time] [\-\-verbose] [\-\-dot] [\-\-append]
+[\-\-block-size=blocks] [\-\-dereference] [\-\-io-size=bytes]
+[\-\-help] [\-\-version] < name-list [> archive]
+
+.B cpio
+{\-i|\-\-extract} [\-bcdfmnrtsuvBSV] [\-C bytes] [\-E file] [\-H format]
+[\-M message] [\-R [user][:.][group]] [\-I [[user@]host:]archive]
+[\-F [[user@]host:]archive] [\-\-file=[[user@]host:]archive]
+[\-\-make-directories] [\-\-nonmatching] [\-\-preserve-modification-time]
+[\-\-numeric-uid-gid] [\-\-rename] [\-\-list] [\-\-swap-bytes] [\-\-swap] [\-\-dot]
+[\-\-unconditional] [\-\-verbose] [\-\-block-size=blocks] [\-\-swap-halfwords]
+[\-\-io-size=bytes] [\-\-pattern-file=file] [\-\-format=format]
+[\-\-owner=[user][:.][group]] [\-\-no-preserve-owner] [\-\-message=message]
+[\-\-help] [\-\-version] [pattern...] [< archive]
+
+.B cpio
+{\-p|\-\-pass-through} [\-0adlmuvLV] [\-R [user][:.][group]]
+[\-\-null] [\-\-reset-access-time] [\-\-make-directories] [\-\-link]
+[\-\-preserve-modification-time] [\-\-unconditional] [\-\-verbose] [\-\-dot]
+[\-\-dereference] [\-\-owner=[user][:.][group]] [\-\-no-preserve-owner]
+[\-\-help] [\-\-version] destination-directory < name-list
+.SH DESCRIPTION
+This manual page
+documents the GNU version of
+.BR cpio .
+.B cpio
+copies files into or out of a cpio or tar archive, which is a file that
+contains other files plus information about them, such as their
+pathname, owner, timestamps, and access permissions. The archive can
+be another file on the disk, a magnetic tape, or a pipe.
+.B cpio
+has three operating modes.
+.PP
+In copy-out mode,
+.B cpio
+copies files into an archive. It reads a list of filenames, one per
+line, on the standard input, and writes the archive onto the standard
+output. A typical way to generate the list of filenames is with the
+.B find
+command; you should give
+.B find
+the \-depth option to minimize problems with permissions on
+directories that are unwritable or not searchable.
+.PP
+In copy-in mode,
+.B cpio
+copies files out of an archive or lists the archive contents. It
+reads the archive from the standard input. Any non-option command
+line arguments are shell globbing patterns; only files in the archive
+whose names match one or more of those patterns are copied from the
+archive. Unlike in the shell, an initial `.' in a filename does
+match a wildcard at the start of a pattern, and a `/' in a filename
+can match wildcards. If no patterns are given, all files are
+extracted.
+.PP
+In copy-pass mode,
+.B cpio
+copies files from one directory tree to another, combining the
+copy-out and copy-in steps without actually using an archive.
+It reads the list of files to copy from the standard input; the
+directory into which it will copy them is given as a non-option
+argument.
+.PP
+.B cpio
+supports the following archive formats: binary, old ASCII, new
+ASCII, crc, HPUX binary, HPUX old ASCII, old tar, and POSIX.1 tar.
+The binary format
+is obsolete because it encodes information about the files in a way
+that is not portable between different machine architectures.
+The old ASCII format is portable between different machine architectures,
+but should not be used on file systems with more than 65536 i-nodes.
+The new ASCII format is portable between different machine architectures
+and can be used on any size file system, but is not supported by all
+versions of
+.BR cpio ;
+currently, it is only supported by GNU and Unix System V R4.
+The crc format is
+like the new ASCII format, but also contains a checksum for each file
+which
+.B cpio
+calculates when creating an archive
+and verifies when the file is extracted from the archive.
+The HPUX formats are provided for compatibility with HPUX's cpio which
+stores device files differently.
+.PP
+The tar format is provided for compatibility with
+the
+.B tar
+program. It can not be used to archive files with names
+longer than 100 characters, and can not be used to archive "special"
+(block or character devices) files.
+The POSIX.1 tar format can not be used to archive files with names longer
+than 255 characters (less unless they have a "/" in just the right place).
+.PP
+By default,
+.B cpio
+creates binary format archives, for compatibility with
+older
+.B cpio
+programs.
+When extracting from archives,
+.B cpio
+automatically recognizes which kind of archive it is reading and can
+read archives created on machines with a different byte-order.
+.PP
+Some of the options to
+.B cpio
+apply only to certain operating modes; see the SYNOPSIS section for a
+list of which options are allowed in which modes.
+.SS OPTIONS
+.TP
+.I "\-0, \-\-null"
+In copy-out and copy-pass modes, read a list of filenames terminated
+by a null character instead of a newline, so that files whose names
+contain newlines can be archived. GNU
+.B find
+is one way to produce a list of null-terminated filenames.
+.TP
+.I "\-a, \-\-reset-access-time"
+Reset the access times of files after reading them, so that it does
+not look like they have just been read.
+.TP
+.I "\-A, \-\-append"
+Append to an existing archive. Only works in copy-out mode. The
+archive must be a disk file specified with the
+.I \-O
+or
+.I "\-F (\-\-file)"
+option.
+.TP
+.I "\-b, \-\-swap"
+In copy-in mode, swap both halfwords of words and bytes of halfwords
+in the data. Equivalent to
+.IR "\-sS" .
+Use this option to convert 32-bit integers between big-endian and
+little-endian machines.
+.TP
+.I "\-B"
+Set the I/O block size to 5120 bytes. Initially the block size is 512
+bytes.
+.TP
+.I "\-\-block-size=BLOCK-SIZE"
+Set the I/O block size to BLOCK-SIZE * 512 bytes.
+.TP
+.I "\-c"
+Use the old portable (ASCII) archive format.
+.TP
+.I "\-C IO-SIZE, \-\-io-size=IO-SIZE"
+Set the I/O block size to IO-SIZE bytes.
+.TP
+.I "\-d, \-\-make-directories"
+Create leading directories where needed.
+.TP
+.I "\-E FILE, \-\-pattern-file=FILE"
+In copy-in mode, read additional patterns specifying filenames to
+extract or list from FILE. The lines of FILE are treated as if they
+had been non-option arguments to
+.BR cpio .
+.TP
+.I "\-f, \-\-nonmatching"
+Only copy files that do not match any of the given patterns.
+.TP
+.I "\-F, \-\-file=archive"
+Archive filename to use instead of standard input or output. To use a
+tape drive on another machine as the archive, use a filename that
+starts with `HOSTNAME:'. The hostname can be preceded by a
+username and an `@' to access the remote tape drive as that user, if
+you have permission to do so (typically an entry in that user's
+`~/.rhosts' file).
+.TP
+.I "\-\-force-local"
+With
+.IR \-F ,
+.IR \-I ,
+or
+.IR \-O ,
+take the archive file name to be a local file even if it contains a
+colon, which would ordinarily indicate a remote host name.
+.TP
+.I "\-H FORMAT, \-\-format=FORMAT"
+Use archive format FORMAT. The valid formats are listed below;
+the same names are also recognized in all-caps. The default in
+copy-in mode is to automatically detect the archive format, and in
+copy-out mode is "bin".
+.RS
+.IP bin
+The obsolete binary format.
+.IP odc
+The old (POSIX.1) portable format.
+.IP newc
+The new (SVR4) portable format, which supports file systems having
+more than 65536 i-nodes.
+.IP crc
+The new (SVR4) portable format with a checksum added.
+.IP tar
+The old tar format.
+.IP ustar
+The POSIX.1 tar format. Also recognizes GNU
+.B tar
+archives, which are similar but not identical.
+.IP hpbin
+The obsolete binary format used by HPUX's cpio (which stores device files
+differently).
+.IP hpodc
+The portable format used by HPUX's cpio (which stores device files differently).
+.RE
+.TP
+.I "\-i, \-\-extract"
+Run in copy-in mode.
+.TP
+.I "\-I archive"
+Archive filename to use instead of standard input. To use a
+tape drive on another machine as the archive, use a filename that
+starts with `HOSTNAME:'. The hostname can be preceded by a
+username and an `@' to access the remote tape drive as that user, if
+you have permission to do so (typically an entry in that user's
+`~/.rhosts' file).
+.TP
+.I \-k
+Ignored; for compatibility with other versions of
+.BR cpio .
+.TP
+.I "\-l, \-\-link"
+Link files instead of copying them, when possible (usable only with the
+.I \-p
+option).
+.TP
+.I "\-L, \-\-dereference"
+Dereference symbolic links (copy the files that they point to instead
+of copying the links).
+.TP
+.I "\-m, \-\-preserve-modification-time"
+Retain previous file modification times when creating files.
+.TP
+.I "\-M MESSAGE, \-\-message=MESSAGE"
+Print MESSAGE when the end of a volume of the backup media (such as a
+tape or a floppy disk) is reached, to prompt the user to insert a new
+volume. If MESSAGE contains the string "%d", it is replaced by the
+current volume number (starting at 1).
+.TP
+.I "\-n, \-\-numeric-uid-gid"
+In the verbose table of contents listing, show numeric UID and GID
+instead of translating them into names.
+.TP
+.I " \-\-no-preserve-owner"
+In copy-in mode and copy-pass mode, do not change the ownership of the
+files; leave them owned by the user extracting them. This is the
+default for non-root users, so that users on System V don't
+inadvertantly give away files.
+.TP
+.I "\-o, \-\-create"
+Run in copy-out mode.
+.TP
+.I "\-O archive"
+Archive filename to use instead of standard output. To use a
+tape drive on another machine as the archive, use a filename that
+starts with `HOSTNAME:'. The hostname can be preceded by a
+username and an `@' to access the remote tape drive as that user, if
+you have permission to do so (typically an entry in that user's
+`~/.rhosts' file).
+.TP
+.I "\-p, \-\-pass-through"
+Run in copy-pass mode.
+.TP
+.I "\-r, \-\-rename"
+Interactively rename files.
+.TP
+.I "\-R [user][:.][group], \-\-owner [user][:.][group]"
+In copy-out and copy-pass modes, set the ownership of all files
+created to the specified user and/or group. Either the user or the
+group, or both, must be present. If the group is omitted but the ":"
+or "." separator is given, use the given user's login group. Only the
+super-user can change files' ownership.
+.TP
+.I "\-s, \-\-swap-bytes"
+In copy-in mode, swap the bytes of each halfword (pair of bytes) in
+the files.
+.TP
+.I "\-S, \-\-swap-halfwords"
+In copy-in mode, swap the halfwords of each word (4 bytes) in the
+files.
+.TP
+.I "\-t, \-\-list"
+Print a table of contents of the input.
+.TP
+.I "\-u, \-\-unconditional"
+Replace all files, without asking whether to replace existing newer
+files with older files.
+.TP
+.I "\-v, \-\-verbose"
+List the files processed, or with
+.IR \-t ,
+give an `ls \-l' style table of contents listing. In a verbose table
+of contents of a ustar archive, user and group names in the archive
+that do not exist on the local system are replaced by the names that
+correspond locally to the numeric UID and GID stored in the archive.
+.TP
+.I "\-V \-\-dot"
+Print a "." for each file processed.
+.TP
+.I "\-\-version"
+Print the
+.B cpio
+program version number and exit.
diff --git a/gnu/usr.bin/cpio/cpio.h b/gnu/usr.bin/cpio/cpio.h
new file mode 100644
index 0000000..537da72
--- /dev/null
+++ b/gnu/usr.bin/cpio/cpio.h
@@ -0,0 +1,69 @@
+/* Extended cpio format from POSIX.1.
+ Copyright (C) 1992 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#ifndef _CPIO_H
+
+#define _CPIO_H 1
+
+/* A cpio archive consists of a sequence of files.
+ Each file has a 76 byte header,
+ a variable length, NUL terminated filename,
+ and variable length file data.
+ A header for a filename "TRAILER!!!" indicates the end of the archive. */
+
+/* All the fields in the header are ISO 646 (approximately ASCII) strings
+ of octal numbers, left padded, not NUL terminated.
+
+ Field Name Length in Bytes Notes
+ c_magic 6 must be "070707"
+ c_dev 6
+ c_ino 6
+ c_mode 6 see below for value
+ c_uid 6
+ c_gid 6
+ c_nlink 6
+ c_rdev 6 only valid for chr and blk special files
+ c_mtime 11
+ c_namesize 6 count includes terminating NUL in pathname
+ c_filesize 11 must be 0 for FIFOs and directories */
+
+/* Values for c_mode, OR'd together: */
+
+#define C_IRUSR 000400
+#define C_IWUSR 000200
+#define C_IXUSR 000100
+#define C_IRGRP 000040
+#define C_IWGRP 000020
+#define C_IXGRP 000010
+#define C_IROTH 000004
+#define C_IWOTH 000002
+#define C_IXOTH 000001
+
+#define C_ISUID 004000
+#define C_ISGID 002000
+#define C_ISVTX 001000
+
+#define C_ISBLK 060000
+#define C_ISCHR 020000
+#define C_ISDIR 040000
+#define C_ISFIFO 010000
+#define C_ISSOCK 0140000
+#define C_ISLNK 0120000
+#define C_ISCTG 0110000
+#define C_ISREG 0100000
+
+#endif /* cpio.h */
diff --git a/gnu/usr.bin/cpio/cpiohdr.h b/gnu/usr.bin/cpio/cpiohdr.h
new file mode 100644
index 0000000..9694af6
--- /dev/null
+++ b/gnu/usr.bin/cpio/cpiohdr.h
@@ -0,0 +1,90 @@
+/* Extended cpio header from POSIX.1.
+ Copyright (C) 1992 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#ifndef _CPIOHDR_H
+
+#define _CPIOHDR_H 1
+
+#include <cpio.h>
+
+struct old_cpio_header
+{
+ unsigned short c_magic;
+ short c_dev;
+ unsigned short c_ino;
+ unsigned short c_mode;
+ unsigned short c_uid;
+ unsigned short c_gid;
+ unsigned short c_nlink;
+ short c_rdev;
+ unsigned short c_mtimes[2];
+ unsigned short c_namesize;
+ unsigned short c_filesizes[2];
+ unsigned long c_mtime; /* Long-aligned copy of `c_mtimes'. */
+ unsigned long c_filesize; /* Long-aligned copy of `c_filesizes'. */
+ char *c_name;
+};
+
+/* "New" portable format and CRC format:
+
+ Each file has a 110 byte header,
+ a variable length, NUL terminated filename,
+ and variable length file data.
+ A header for a filename "TRAILER!!!" indicates the end of the archive. */
+
+/* All the fields in the header are ISO 646 (approximately ASCII) strings
+ of hexadecimal numbers, left padded, not NUL terminated.
+
+ Field Name Length in Bytes Notes
+ c_magic 6 "070701" for "new" portable format
+ "070702" for CRC format
+ c_ino 8
+ c_mode 8
+ c_uid 8
+ c_gid 8
+ c_nlink 8
+ c_mtime 8
+ c_filesize 8 must be 0 for FIFOs and directories
+ c_maj 8
+ c_min 8
+ c_rmaj 8 only valid for chr and blk special files
+ c_rmin 8 only valid for chr and blk special files
+ c_namesize 8 count includes terminating NUL in pathname
+ c_chksum 8 0 for "new" portable format; for CRC format
+ the sum of all the bytes in the file */
+
+struct new_cpio_header
+{
+ unsigned short c_magic;
+ unsigned long c_ino;
+ unsigned long c_mode;
+ unsigned long c_uid;
+ unsigned long c_gid;
+ unsigned long c_nlink;
+ unsigned long c_mtime;
+ unsigned long c_filesize;
+ long c_dev_maj;
+ long c_dev_min;
+ long c_rdev_maj;
+ long c_rdev_min;
+ unsigned long c_namesize;
+ unsigned long c_chksum;
+ char *c_name;
+ char *c_tar_linkname;
+};
+
+#endif /* cpiohdr.h */
diff --git a/gnu/usr.bin/cpio/defer.c b/gnu/usr.bin/cpio/defer.c
new file mode 100644
index 0000000..efe60e0
--- /dev/null
+++ b/gnu/usr.bin/cpio/defer.c
@@ -0,0 +1,43 @@
+/* defer.c - handle "defered" links in newc and crc archives
+ Copyright (C) 1993 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <stdio.h>
+#include <sys/types.h>
+#include "system.h"
+#include "cpiohdr.h"
+#include "extern.h"
+#include "defer.h"
+
+struct deferment *
+create_deferment (file_hdr)
+ struct new_cpio_header *file_hdr;
+{
+ struct deferment *d;
+ d = (struct deferment *) xmalloc (sizeof (struct deferment) );
+ d->header = *file_hdr;
+ d->header.c_name = (char *) xmalloc (strlen (file_hdr->c_name) + 1);
+ strcpy (d->header.c_name, file_hdr->c_name);
+ return d;
+}
+
+void
+free_deferment (d)
+ struct deferment *d;
+{
+ free (d->header.c_name);
+ free (d);
+}
diff --git a/gnu/usr.bin/cpio/defer.h b/gnu/usr.bin/cpio/defer.h
new file mode 100644
index 0000000..89abffe
--- /dev/null
+++ b/gnu/usr.bin/cpio/defer.h
@@ -0,0 +1,8 @@
+struct deferment
+ {
+ struct deferment *next;
+ struct new_cpio_header header;
+ };
+
+struct deferment *create_deferment P_((struct new_cpio_header *file_hdr));
+void free_deferment P_((struct deferment *d));
diff --git a/gnu/usr.bin/cpio/dirname.c b/gnu/usr.bin/cpio/dirname.c
new file mode 100644
index 0000000..5a92ce5
--- /dev/null
+++ b/gnu/usr.bin/cpio/dirname.c
@@ -0,0 +1,66 @@
+/* dirname.c -- return all but the last element in a path
+ Copyright (C) 1990 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#ifdef STDC_HEADERS
+#include <stdlib.h>
+#else
+char *malloc ();
+#endif
+#if defined(STDC_HEADERS) || defined(HAVE_STRING_H)
+#include <string.h>
+#ifndef rindex
+#define rindex strrchr
+#endif
+#else
+#include <strings.h>
+#endif
+
+/* Return the leading directories part of PATH,
+ allocated with malloc. If out of memory, return 0.
+ Assumes that trailing slashes have already been
+ removed. */
+
+char *
+dirname (path)
+ char *path;
+{
+ char *newpath;
+ char *slash;
+ int length; /* Length of result, not including NUL. */
+
+ slash = rindex (path, '/');
+ if (slash == 0)
+ {
+ /* File is in the current directory. */
+ path = ".";
+ length = 1;
+ }
+ else
+ {
+ /* Remove any trailing slashes from the result. */
+ while (slash > path && *slash == '/')
+ --slash;
+
+ length = slash - path + 1;
+ }
+ newpath = malloc (length + 1);
+ if (newpath == 0)
+ return 0;
+ strncpy (newpath, path, length);
+ newpath[length] = 0;
+ return newpath;
+}
diff --git a/gnu/usr.bin/cpio/dstring.c b/gnu/usr.bin/cpio/dstring.c
new file mode 100644
index 0000000..26d6bbc
--- /dev/null
+++ b/gnu/usr.bin/cpio/dstring.c
@@ -0,0 +1,114 @@
+/* dstring.c - The dynamic string handling routines used by cpio.
+ Copyright (C) 1990, 1991, 1992 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <stdio.h>
+#if defined(HAVE_STRING_H) || defined(STDC_HEADERS)
+#include <string.h>
+#else
+#include <strings.h>
+#endif
+#include "dstring.h"
+
+#if __STDC__
+# define P_(s) s
+#else
+# define P_(s) ()
+#endif
+char *xmalloc P_((unsigned n));
+char *xrealloc P_((char *p, unsigned n));
+
+/* Initialiaze dynamic string STRING with space for SIZE characters. */
+
+void
+ds_init (string, size)
+ dynamic_string *string;
+ int size;
+{
+ string->ds_length = size;
+ string->ds_string = (char *) xmalloc (size);
+}
+
+/* Expand dynamic string STRING, if necessary, to hold SIZE characters. */
+
+void
+ds_resize (string, size)
+ dynamic_string *string;
+ int size;
+{
+ if (size > string->ds_length)
+ {
+ string->ds_length = size;
+ string->ds_string = (char *) xrealloc ((char *) string->ds_string, size);
+ }
+}
+
+/* Dynamic string S gets a string terminated by the EOS character
+ (which is removed) from file F. S will increase
+ in size during the function if the string from F is longer than
+ the current size of S.
+ Return NULL if end of file is detected. Otherwise,
+ Return a pointer to the null-terminated string in S. */
+
+char *
+ds_fgetstr (f, s, eos)
+ FILE *f;
+ dynamic_string *s;
+ char eos;
+{
+ int insize; /* Amount needed for line. */
+ int strsize; /* Amount allocated for S. */
+ int next_ch;
+
+ /* Initialize. */
+ insize = 0;
+ strsize = s->ds_length;
+
+ /* Read the input string. */
+ next_ch = getc (f);
+ while (next_ch != eos && next_ch != EOF)
+ {
+ if (insize >= strsize - 1)
+ {
+ ds_resize (s, strsize * 2 + 2);
+ strsize = s->ds_length;
+ }
+ s->ds_string[insize++] = next_ch;
+ next_ch = getc (f);
+ }
+ s->ds_string[insize++] = '\0';
+
+ if (insize == 1 && next_ch == EOF)
+ return NULL;
+ else
+ return s->ds_string;
+}
+
+char *
+ds_fgets (f, s)
+ FILE *f;
+ dynamic_string *s;
+{
+ return ds_fgetstr (f, s, '\n');
+}
+
+char *
+ds_fgetname (f, s)
+ FILE *f;
+ dynamic_string *s;
+{
+ return ds_fgetstr (f, s, '\0');
+}
diff --git a/gnu/usr.bin/cpio/dstring.h b/gnu/usr.bin/cpio/dstring.h
new file mode 100644
index 0000000..369da0b
--- /dev/null
+++ b/gnu/usr.bin/cpio/dstring.h
@@ -0,0 +1,49 @@
+/* dstring.h - Dynamic string handling include file. Requires strings.h.
+ Copyright (C) 1990, 1991, 1992 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+/* A dynamic string consists of record that records the size of an
+ allocated string and the pointer to that string. The actual string
+ is a normal zero byte terminated string that can be used with the
+ usual string functions. The major difference is that the
+ dynamic_string routines know how to get more space if it is needed
+ by allocating new space and copying the current string. */
+
+typedef struct
+{
+ int ds_length; /* Actual amount of storage allocated. */
+ char *ds_string; /* String. */
+} dynamic_string;
+
+
+/* Macros that look similar to the original string functions.
+ WARNING: These macros work only on pointers to dynamic string records.
+ If used with a real record, an "&" must be used to get the pointer. */
+#define ds_strlen(s) strlen ((s)->ds_string)
+#define ds_strcmp(s1, s2) strcmp ((s1)->ds_string, (s2)->ds_string)
+#define ds_strncmp(s1, s2, n) strncmp ((s1)->ds_string, (s2)->ds_string, n)
+#define ds_index(s, c) index ((s)->ds_string, c)
+#define ds_rindex(s, c) rindex ((s)->ds_string, c)
+
+void ds_init ();
+void ds_resize ();
+char *ds_fgetname ();
+char *ds_fgets ();
+char *ds_fgetstr ();
diff --git a/gnu/usr.bin/cpio/error.c b/gnu/usr.bin/cpio/error.c
new file mode 100644
index 0000000..e849c5b
--- /dev/null
+++ b/gnu/usr.bin/cpio/error.c
@@ -0,0 +1,106 @@
+/* error.c -- error handler for noninteractive utilities
+ Copyright (C) 1990, 1991, 1992 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* Written by David MacKenzie. */
+
+#include <stdio.h>
+
+#ifdef HAVE_VPRINTF
+
+#if __STDC__
+#include <stdarg.h>
+#define VA_START(args, lastarg) va_start(args, lastarg)
+#else /* !__STDC__ */
+#include <varargs.h>
+#define VA_START(args, lastarg) va_start(args)
+#endif /* !__STDC__ */
+
+#else /* !HAVE_VPRINTF */
+
+#ifdef HAVE_DOPRNT
+#define va_alist args
+#define va_dcl int args;
+#else /* !HAVE_DOPRNT */
+#define va_alist a1, a2, a3, a4, a5, a6, a7, a8
+#define va_dcl char *a1, *a2, *a3, *a4, *a5, *a6, *a7, *a8;
+#endif /* !HAVE_DOPRNT */
+
+#endif /* !HAVE_VPRINTF */
+
+#ifdef STDC_HEADERS
+#include <stdlib.h>
+#include <string.h>
+#else /* !STDC_HEADERS */
+void exit ();
+#endif /* !STDC_HEADERS */
+
+extern char *program_name;
+
+#ifndef HAVE_STRERROR
+static char *
+private_strerror (errnum)
+ int errnum;
+{
+ extern char *sys_errlist[];
+ extern int sys_nerr;
+
+ if (errnum > 0 && errnum <= sys_nerr)
+ return sys_errlist[errnum];
+ return "Unknown system error";
+}
+#define strerror private_strerror
+#endif /* !HAVE_STRERROR */
+
+/* Print the program name and error message MESSAGE, which is a printf-style
+ format string with optional args.
+ If ERRNUM is nonzero, print its corresponding system error message.
+ Exit with status STATUS if it is nonzero. */
+/* VARARGS */
+void
+#if defined (HAVE_VPRINTF) && __STDC__
+error (int status, int errnum, char *message, ...)
+#else /* !HAVE_VPRINTF or !__STDC__ */
+error (status, errnum, message, va_alist)
+ int status;
+ int errnum;
+ char *message;
+ va_dcl
+#endif /* !HAVE_VPRINTF or !__STDC__ */
+{
+#ifdef HAVE_VPRINTF
+ va_list args;
+#endif /* HAVE_VPRINTF */
+
+ fprintf (stderr, "%s: ", program_name);
+#ifdef HAVE_VPRINTF
+ VA_START (args, message);
+ vfprintf (stderr, message, args);
+ va_end (args);
+#else /* !HAVE_VPRINTF */
+#ifdef HAVE_DOPRNT
+ _doprnt (message, &args, stderr);
+#else /* !HAVE_DOPRNT */
+ fprintf (stderr, message, a1, a2, a3, a4, a5, a6, a7, a8);
+#endif /* !HAVE_DOPRNT */
+#endif /* !HAVE_VPRINTF */
+ if (errnum)
+ fprintf (stderr, ": %s", strerror (errnum));
+ putc ('\n', stderr);
+ fflush (stderr);
+ if (status)
+ exit (status);
+}
diff --git a/gnu/usr.bin/cpio/extern.h b/gnu/usr.bin/cpio/extern.h
new file mode 100644
index 0000000..6009f19
--- /dev/null
+++ b/gnu/usr.bin/cpio/extern.h
@@ -0,0 +1,181 @@
+/* extern.h - External declarations for cpio. Requires system.h.
+ Copyright (C) 1990, 1991, 1992 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+enum archive_format
+{
+ arf_unknown, arf_binary, arf_oldascii, arf_newascii, arf_crcascii,
+ arf_tar, arf_ustar, arf_hpoldascii, arf_hpbinary
+};
+extern enum archive_format archive_format;
+extern int reset_time_flag;
+extern int io_block_size;
+extern int create_dir_flag;
+extern int rename_flag;
+extern int table_flag;
+extern int unconditional_flag;
+extern int verbose_flag;
+extern int dot_flag;
+extern int link_flag;
+extern int retain_time_flag;
+extern int crc_i_flag;
+extern int append_flag;
+extern int swap_bytes_flag;
+extern int swap_halfwords_flag;
+extern int swapping_bytes;
+extern int swapping_halfwords;
+extern int set_owner_flag;
+extern uid_t set_owner;
+extern int set_group_flag;
+extern gid_t set_group;
+extern int no_chown_flag;
+extern int last_header_start;
+extern int copy_matching_files;
+extern int numeric_uid;
+extern char *pattern_file_name;
+extern char *new_media_message;
+extern char *new_media_message_with_number;
+extern char *new_media_message_after_number;
+extern int archive_des;
+extern char *archive_name;
+extern unsigned long crc;
+#ifdef DEBUG_CPIO
+extern int debug_flag;
+#endif
+
+extern char *input_buffer, *output_buffer;
+extern char *in_buff, *out_buff;
+extern long input_size, output_size;
+extern long input_bytes, output_bytes;
+extern char zeros_512[];
+extern char *directory_name;
+extern char **save_patterns;
+extern int num_patterns;
+extern char name_end;
+extern char input_is_special;
+extern char output_is_special;
+extern char input_is_seekable;
+extern char output_is_seekable;
+extern int f_force_local;
+extern char *program_name;
+extern int (*xstat) ();
+extern void (*copy_function) ();
+
+#if __STDC__ || defined(__MSDOS__)
+# define P_(s) s
+#else
+# define P_(s) ()
+#endif
+
+/* copyin.c */
+void read_in_header P_((struct new_cpio_header *file_hdr, int in_des));
+void read_in_old_ascii P_((struct new_cpio_header *file_hdr, int in_des));
+void read_in_new_ascii P_((struct new_cpio_header *file_hdr, int in_des));
+void read_in_binary P_((struct new_cpio_header *file_hdr, int in_des));
+void swab_array P_((char *arg, int count));
+void process_copy_in P_((void));
+void long_format P_((struct new_cpio_header *file_hdr, char *link_name));
+void print_name_with_quoting P_((char *p));
+
+/* copyout.c */
+void write_out_header P_((struct new_cpio_header *file_hdr, int out_des));
+void process_copy_out P_((void));
+
+/* copypass.c */
+void process_copy_pass P_((void));
+
+/* dirname.c */
+char *dirname P_((char *path));
+
+/* error.c */
+void error P_((int status, int errnum, char *message, ...));
+
+/* filemode.c */
+void mode_string P_((unsigned int mode, char *str));
+
+/* idcache.c */
+#ifndef __MSDOS__
+char *getgroup ();
+char *getuser ();
+uid_t *getuidbyname ();
+gid_t *getgidbyname ();
+#endif
+
+/* lchown.c */
+#ifdef HAVE_LCHOWN
+int lchown P_((const char *path, uid_t owner, gid_t group));
+#endif
+
+/* main.c */
+void process_args P_((int argc, char *argv[]));
+void initialize_buffers P_((void));
+
+/* makepath.c */
+int make_path P_((char *argpath, int mode, int parent_mode,
+ uid_t owner, gid_t group, char *verbose_fmt_string));
+
+/* stripslash.c */
+void strip_trailing_slashes P_((char *path));
+
+/* tar.c */
+void write_out_tar_header P_((struct new_cpio_header *file_hdr, int out_des));
+int null_block P_((long *block, int size));
+void read_in_tar_header P_((struct new_cpio_header *file_hdr, int in_des));
+int otoa P_((char *s, unsigned long *n));
+int is_tar_header P_((char *buf));
+int is_tar_filename_too_long P_((char *name));
+
+/* userspec.c */
+#ifndef __MSDOS__
+char *parse_user_spec P_((char *name, uid_t *uid, gid_t *gid,
+ char **username, char **groupname));
+#endif
+
+/* util.c */
+void empty_output_buffer P_((int out_des));
+void swahw_array P_((char *ptr, int count));
+void fill_input_buffer P_((int in_des, int num_bytes));
+void copy_buf_out P_((char *in_buf, int out_des, long num_bytes));
+void copy_in_buf P_((char *in_buf, int in_des, long num_bytes));
+int peek_in_buf P_((char *peek_buf, int in_des, int num_bytes));
+void toss_input P_((int in_des, long num_bytes));
+void copy_files P_((int in_des, int out_des, long num_bytes));
+void create_all_directories P_((char *name));
+void prepare_append P_((int out_file_des));
+char *find_inode_file P_((unsigned long node_num,
+ unsigned long major_num, unsigned long minor_num));
+void add_inode P_((unsigned long node_num, char *file_name,
+ unsigned long major_num, unsigned long minor_num));
+int open_archive P_((char *file));
+void tape_offline P_((int tape_des));
+void get_next_reel P_((int tape_des));
+void set_new_media_message P_((char *message));
+#ifdef __MSDOS__
+int chown P_((char *path, int owner, int group));
+#endif
+#ifdef __TURBOC__
+int utime P_((char *filename, struct utimbuf *utb));
+#endif
+#ifdef HPUX_CDF
+char *add_cdf_double_slashes P_((char *filename));
+#endif
+
+/* xmalloc.c */
+char *xmalloc P_((unsigned n));
+char *xrealloc P_((char *p, unsigned n));
+
+/* xstrdup.c */
+char *xstrdup P_((char *string));
diff --git a/gnu/usr.bin/cpio/filemode.c b/gnu/usr.bin/cpio/filemode.c
new file mode 100644
index 0000000..9293af6
--- /dev/null
+++ b/gnu/usr.bin/cpio/filemode.c
@@ -0,0 +1,229 @@
+/* filemode.c -- make a string describing file modes
+ Copyright (C) 1985, 1990 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#ifndef S_IREAD
+#define S_IREAD S_IRUSR
+#define S_IWRITE S_IWUSR
+#define S_IEXEC S_IXUSR
+#endif
+
+#if !defined(S_ISREG) || defined(NO_MODE_T)
+/* Doesn't have POSIX.1 stat stuff or doesn't have mode_t. */
+#define mode_t unsigned short
+#endif
+
+#if !defined(S_ISBLK) && defined(S_IFBLK)
+#define S_ISBLK(m) (((m) & S_IFMT) == S_IFBLK)
+#endif
+#if !defined(S_ISCHR) && defined(S_IFCHR)
+#define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR)
+#endif
+#if !defined(S_ISDIR) && defined(S_IFDIR)
+#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
+#endif
+#if !defined(S_ISREG) && defined(S_IFREG)
+#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
+#endif
+#if !defined(S_ISFIFO) && defined(S_IFIFO)
+#define S_ISFIFO(m) (((m) & S_IFMT) == S_IFIFO)
+#endif
+#if !defined(S_ISLNK) && defined(S_IFLNK)
+#define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK)
+#endif
+#if !defined(S_ISSOCK) && defined(S_IFSOCK)
+#define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK)
+#endif
+#if !defined(S_ISMPB) && defined(S_IFMPB) /* V7 */
+#define S_ISMPB(m) (((m) & S_IFMT) == S_IFMPB)
+#define S_ISMPC(m) (((m) & S_IFMT) == S_IFMPC)
+#endif
+#if !defined(S_ISNWK) && defined(S_IFNWK) /* HP/UX */
+#define S_ISNWK(m) (((m) & S_IFMT) == S_IFNWK)
+#endif
+
+void mode_string ();
+static char ftypelet ();
+static void rwx ();
+static void setst ();
+
+/* filemodestring - fill in string STR with an ls-style ASCII
+ representation of the st_mode field of file stats block STATP.
+ 10 characters are stored in STR; no terminating null is added.
+ The characters stored in STR are:
+
+ 0 File type. 'd' for directory, 'c' for character
+ special, 'b' for block special, 'm' for multiplex,
+ 'l' for symbolic link, 's' for socket, 'p' for fifo,
+ '-' for regular, '?' for any other file type
+
+ 1 'r' if the owner may read, '-' otherwise.
+
+ 2 'w' if the owner may write, '-' otherwise.
+
+ 3 'x' if the owner may execute, 's' if the file is
+ set-user-id, '-' otherwise.
+ 'S' if the file is set-user-id, but the execute
+ bit isn't set.
+
+ 4 'r' if group members may read, '-' otherwise.
+
+ 5 'w' if group members may write, '-' otherwise.
+
+ 6 'x' if group members may execute, 's' if the file is
+ set-group-id, '-' otherwise.
+ 'S' if it is set-group-id but not executable.
+
+ 7 'r' if any user may read, '-' otherwise.
+
+ 8 'w' if any user may write, '-' otherwise.
+
+ 9 'x' if any user may execute, 't' if the file is "sticky"
+ (will be retained in swap space after execution), '-'
+ otherwise.
+ 'T' if the file is sticky but not executable. */
+
+void
+filemodestring (statp, str)
+ struct stat *statp;
+ char *str;
+{
+ mode_string (statp->st_mode, str);
+}
+
+/* Like filemodestring, but only the relevant part of the `struct stat'
+ is given as an argument. */
+
+void
+mode_string (mode, str)
+ unsigned short mode;
+ char *str;
+{
+ str[0] = ftypelet (mode);
+ rwx ((mode & 0700) << 0, &str[1]);
+ rwx ((mode & 0070) << 3, &str[4]);
+ rwx ((mode & 0007) << 6, &str[7]);
+ setst (mode, str);
+}
+
+/* Return a character indicating the type of file described by
+ file mode BITS:
+ 'd' for directories
+ 'b' for block special files
+ 'c' for character special files
+ 'm' for multiplexor files
+ 'l' for symbolic links
+ 's' for sockets
+ 'p' for fifos
+ '-' for regular files
+ '?' for any other file type. */
+
+static char
+ftypelet (bits)
+ mode_t bits;
+{
+#ifdef S_ISBLK
+ if (S_ISBLK (bits))
+ return 'b';
+#endif
+ if (S_ISCHR (bits))
+ return 'c';
+ if (S_ISDIR (bits))
+ return 'd';
+ if (S_ISREG (bits))
+ return '-';
+#ifdef S_ISFIFO
+ if (S_ISFIFO (bits))
+ return 'p';
+#endif
+#ifdef S_ISLNK
+ if (S_ISLNK (bits))
+ return 'l';
+#endif
+#ifdef S_ISSOCK
+ if (S_ISSOCK (bits))
+ return 's';
+#endif
+#ifdef S_ISMPC
+ if (S_ISMPC (bits))
+ return 'm';
+#endif
+#ifdef S_ISNWK
+ if (S_ISNWK (bits))
+ return 'n';
+#endif
+ return '?';
+}
+
+/* Look at read, write, and execute bits in BITS and set
+ flags in CHARS accordingly. */
+
+static void
+rwx (bits, chars)
+ unsigned short bits;
+ char *chars;
+{
+ chars[0] = (bits & S_IREAD) ? 'r' : '-';
+ chars[1] = (bits & S_IWRITE) ? 'w' : '-';
+ chars[2] = (bits & S_IEXEC) ? 'x' : '-';
+}
+
+/* Set the 's' and 't' flags in file attributes string CHARS,
+ according to the file mode BITS. */
+
+static void
+setst (bits, chars)
+ unsigned short bits;
+ char *chars;
+{
+#ifdef S_ISUID
+ if (bits & S_ISUID)
+ {
+ if (chars[3] != 'x')
+ /* Set-uid, but not executable by owner. */
+ chars[3] = 'S';
+ else
+ chars[3] = 's';
+ }
+#endif
+#ifdef S_ISGID
+ if (bits & S_ISGID)
+ {
+ if (chars[6] != 'x')
+ /* Set-gid, but not executable by group. */
+ chars[6] = 'S';
+ else
+ chars[6] = 's';
+ }
+#endif
+#ifdef S_ISVTX
+ if (bits & S_ISVTX)
+ {
+ if (chars[9] != 'x')
+ /* Sticky, but not executable by others. */
+ chars[9] = 'T';
+ else
+ chars[9] = 't';
+ }
+#endif
+}
diff --git a/gnu/usr.bin/cpio/filetypes.h b/gnu/usr.bin/cpio/filetypes.h
new file mode 100644
index 0000000..46a79a9
--- /dev/null
+++ b/gnu/usr.bin/cpio/filetypes.h
@@ -0,0 +1,84 @@
+/* filetypes.h - deal with POSIX annoyances
+ Copyright (C) 1991 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* Include sys/types.h and sys/stat.h before this file. */
+
+#ifndef S_ISREG /* Doesn't have POSIX.1 stat stuff. */
+#define mode_t unsigned short
+#endif
+
+/* Define the POSIX macros for systems that lack them. */
+#if !defined(S_ISBLK) && defined(S_IFBLK)
+#define S_ISBLK(m) (((m) & S_IFMT) == S_IFBLK)
+#endif
+#if !defined(S_ISCHR) && defined(S_IFCHR)
+#define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR)
+#endif
+#if !defined(S_ISDIR) && defined(S_IFDIR)
+#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
+#endif
+#if !defined(S_ISREG) && defined(S_IFREG)
+#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
+#endif
+#if !defined(S_ISFIFO) && defined(S_IFIFO)
+#define S_ISFIFO(m) (((m) & S_IFMT) == S_IFIFO)
+#endif
+#if !defined(S_ISLNK) && defined(S_IFLNK)
+#define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK)
+#endif
+#if !defined(S_ISSOCK) && defined(S_IFSOCK)
+#define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK)
+#endif
+#if !defined(S_ISNWK) && defined(S_IFNWK) /* HP/UX network special */
+#define S_ISNWK(m) (((m) & S_IFMT) == S_IFNWK)
+#endif
+
+/* Define the file type bits used in cpio archives.
+ They have the same values as the S_IF bits in traditional Unix. */
+
+#define CP_IFMT 0170000 /* Mask for all file type bits. */
+
+#if defined(S_ISBLK)
+#define CP_IFBLK 0060000
+#endif
+#if defined(S_ISCHR)
+#define CP_IFCHR 0020000
+#endif
+#if defined(S_ISDIR)
+#define CP_IFDIR 0040000
+#endif
+#if defined(S_ISREG)
+#define CP_IFREG 0100000
+#endif
+#if defined(S_ISFIFO)
+#define CP_IFIFO 0010000
+#endif
+#if defined(S_ISLNK)
+#define CP_IFLNK 0120000
+#endif
+#if defined(S_ISSOCK)
+#define CP_IFSOCK 0140000
+#endif
+#if defined(S_ISNWK)
+#define CP_IFNWK 0110000
+#endif
+
+#ifndef S_ISLNK
+#define lstat stat
+#endif
+int lstat ();
+int stat ();
diff --git a/gnu/usr.bin/cpio/fnmatch.c b/gnu/usr.bin/cpio/fnmatch.c
new file mode 100644
index 0000000..8a25a90
--- /dev/null
+++ b/gnu/usr.bin/cpio/fnmatch.c
@@ -0,0 +1,200 @@
+/* Copyright (C) 1991, 1992, 1993 Free Software Foundation, Inc.
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public License as
+published by the Free Software Foundation; either version 2 of the
+License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with this library; see the file COPYING.LIB. If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA. */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <errno.h>
+#include <fnmatch.h>
+#include <ctype.h>
+
+
+/* Comment out all this code if we are using the GNU C Library, and are not
+ actually compiling the library itself. This code is part of the GNU C
+ Library, but also included in many other GNU distributions. Compiling
+ and linking in this code is a waste when using the GNU C library
+ (especially if it is a shared library). Rather than having every GNU
+ program understand `configure --with-gnu-libc' and omit the object files,
+ it is simpler to just do this in the source for each such file. */
+
+#if defined (_LIBC) || !defined (__GNU_LIBRARY__)
+
+
+#if !defined(__GNU_LIBRARY__) && !defined(STDC_HEADERS)
+extern int errno;
+#endif
+
+/* Match STRING against the filename pattern PATTERN, returning zero if
+ it matches, nonzero if not. */
+int
+fnmatch (pattern, string, flags)
+ const char *pattern;
+ const char *string;
+ int flags;
+{
+ register const char *p = pattern, *n = string;
+ register char c;
+
+/* Note that this evalutes C many times. */
+#define FOLD(c) ((flags & FNM_CASEFOLD) && isupper (c) ? tolower (c) : (c))
+
+ while ((c = *p++) != '\0')
+ {
+ c = FOLD (c);
+
+ switch (c)
+ {
+ case '?':
+ if (*n == '\0')
+ return FNM_NOMATCH;
+ else if ((flags & FNM_FILE_NAME) && *n == '/')
+ return FNM_NOMATCH;
+ else if ((flags & FNM_PERIOD) && *n == '.' &&
+ (n == string || ((flags & FNM_FILE_NAME) && n[-1] == '/')))
+ return FNM_NOMATCH;
+ break;
+
+ case '\\':
+ if (!(flags & FNM_NOESCAPE))
+ {
+ c = *p++;
+ c = FOLD (c);
+ }
+ if (FOLD (*n) != c)
+ return FNM_NOMATCH;
+ break;
+
+ case '*':
+ if ((flags & FNM_PERIOD) && *n == '.' &&
+ (n == string || ((flags & FNM_FILE_NAME) && n[-1] == '/')))
+ return FNM_NOMATCH;
+
+ for (c = *p++; c == '?' || c == '*'; c = *p++, ++n)
+ if (((flags & FNM_FILE_NAME) && *n == '/') ||
+ (c == '?' && *n == '\0'))
+ return FNM_NOMATCH;
+
+ if (c == '\0')
+ return 0;
+
+ {
+ char c1 = (!(flags & FNM_NOESCAPE) && c == '\\') ? *p : c;
+ c1 = FOLD (c1);
+ for (--p; *n != '\0'; ++n)
+ if ((c == '[' || FOLD (*n) == c1) &&
+ fnmatch (p, n, flags & ~FNM_PERIOD) == 0)
+ return 0;
+ return FNM_NOMATCH;
+ }
+
+ case '[':
+ {
+ /* Nonzero if the sense of the character class is inverted. */
+ register int not;
+
+ if (*n == '\0')
+ return FNM_NOMATCH;
+
+ if ((flags & FNM_PERIOD) && *n == '.' &&
+ (n == string || ((flags & FNM_FILE_NAME) && n[-1] == '/')))
+ return FNM_NOMATCH;
+
+ not = (*p == '!' || *p == '^');
+ if (not)
+ ++p;
+
+ c = *p++;
+ for (;;)
+ {
+ register char cstart = c, cend = c;
+
+ if (!(flags & FNM_NOESCAPE) && c == '\\')
+ cstart = cend = *p++;
+
+ cstart = cend = FOLD (cstart);
+
+ if (c == '\0')
+ /* [ (unterminated) loses. */
+ return FNM_NOMATCH;
+
+ c = *p++;
+ c = FOLD (c);
+
+ if ((flags & FNM_FILE_NAME) && c == '/')
+ /* [/] can never match. */
+ return FNM_NOMATCH;
+
+ if (c == '-' && *p != ']')
+ {
+ cend = *p++;
+ if (!(flags & FNM_NOESCAPE) && cend == '\\')
+ cend = *p++;
+ if (cend == '\0')
+ return FNM_NOMATCH;
+ cend = FOLD (cend);
+
+ c = *p++;
+ }
+
+ if (FOLD (*n) >= cstart && FOLD (*n) <= cend)
+ goto matched;
+
+ if (c == ']')
+ break;
+ }
+ if (!not)
+ return FNM_NOMATCH;
+ break;
+
+ matched:;
+ /* Skip the rest of the [...] that already matched. */
+ while (c != ']')
+ {
+ if (c == '\0')
+ /* [... (unterminated) loses. */
+ return FNM_NOMATCH;
+
+ c = *p++;
+ if (!(flags & FNM_NOESCAPE) && c == '\\')
+ /* XXX 1003.2d11 is unclear if this is right. */
+ ++p;
+ }
+ if (not)
+ return FNM_NOMATCH;
+ }
+ break;
+
+ default:
+ if (c != FOLD (*n))
+ return FNM_NOMATCH;
+ }
+
+ ++n;
+ }
+
+ if (*n == '\0')
+ return 0;
+
+ if ((flags & FNM_LEADING_DIR) && *n == '/')
+ /* The FNM_LEADING_DIR flag says that "foo*" matches "foobar/frobozz". */
+ return 0;
+
+ return FNM_NOMATCH;
+}
+
+#endif /* _LIBC or not __GNU_LIBRARY__. */
diff --git a/gnu/usr.bin/cpio/fnmatch.h b/gnu/usr.bin/cpio/fnmatch.h
new file mode 100644
index 0000000..1157bf0
--- /dev/null
+++ b/gnu/usr.bin/cpio/fnmatch.h
@@ -0,0 +1,60 @@
+/* Copyright (C) 1991, 1992, 1993 Free Software Foundation, Inc.
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public License as
+published by the Free Software Foundation; either version 2 of the
+License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with this library; see the file COPYING.LIB. If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA. */
+
+#ifndef _FNMATCH_H
+
+#define _FNMATCH_H 1
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if defined (__cplusplus) || (defined (__STDC__) && __STDC__)
+#undef __GNU_P
+#define __GNU_P(args) args
+#else /* Not C++ or ANSI C. */
+#undef __GNU_P
+#define __GNU_P(args) ()
+/* We can get away without defining `const' here only because in this file
+ it is used only inside the prototype for `fnmatch', which is elided in
+ non-ANSI C where `const' is problematical. */
+#endif /* C++ or ANSI C. */
+
+/* Bits set in the FLAGS argument to `fnmatch'. */
+#define FNM_PATHNAME (1 << 0) /* No wildcard can ever match `/'. */
+#define FNM_NOESCAPE (1 << 1) /* Backslashes don't quote special chars. */
+#define FNM_PERIOD (1 << 2) /* Leading `.' is matched only explicitly. */
+
+#if !defined (_POSIX_C_SOURCE) || _POSIX_C_SOURCE < 2 || defined (_GNU_SOURCE)
+#define FNM_FILE_NAME FNM_PATHNAME /* Preferred GNU name. */
+#define FNM_LEADING_DIR (1 << 3) /* Ignore `/...' after a match. */
+#define FNM_CASEFOLD (1 << 4) /* Compare without regard to case. */
+#endif
+
+/* Value returned by `fnmatch' if STRING does not match PATTERN. */
+#define FNM_NOMATCH 1
+
+/* Match STRING against the filename pattern PATTERN,
+ returning zero if it matches, FNM_NOMATCH if not. */
+extern int fnmatch __GNU_P ((const char *__pattern, const char *__string,
+ int __flags));
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* fnmatch.h */
diff --git a/gnu/usr.bin/cpio/getopt.c b/gnu/usr.bin/cpio/getopt.c
new file mode 100644
index 0000000..2867a90
--- /dev/null
+++ b/gnu/usr.bin/cpio/getopt.c
@@ -0,0 +1,744 @@
+/* Getopt for GNU.
+ NOTE: getopt is now part of the C library, so if you don't know what
+ "Keep this file name-space clean" means, talk to roland@gnu.ai.mit.edu
+ before changing it!
+
+ Copyright (C) 1987, 88, 89, 90, 91, 92, 1993
+ Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any
+ later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#if !__STDC__ && !defined(const) && IN_GCC
+#define const
+#endif
+
+/* This tells Alpha OSF/1 not to define a getopt prototype in <stdio.h>. */
+#ifndef _NO_PROTO
+#define _NO_PROTO
+#endif
+
+#include <stdio.h>
+
+/* Comment out all this code if we are using the GNU C Library, and are not
+ actually compiling the library itself. This code is part of the GNU C
+ Library, but also included in many other GNU distributions. Compiling
+ and linking in this code is a waste when using the GNU C library
+ (especially if it is a shared library). Rather than having every GNU
+ program understand `configure --with-gnu-libc' and omit the object files,
+ it is simpler to just do this in the source for each such file. */
+
+#if defined (_LIBC) || !defined (__GNU_LIBRARY__)
+
+
+/* This needs to come after some library #include
+ to get __GNU_LIBRARY__ defined. */
+#ifdef __GNU_LIBRARY__
+/* Don't include stdlib.h for non-GNU C libraries because some of them
+ contain conflicting prototypes for getopt. */
+#include <stdlib.h>
+#endif /* GNU C library. */
+
+/* If GETOPT_COMPAT is defined, `+' as well as `--' can introduce a
+ long-named option. Because this is not POSIX.2 compliant, it is
+ being phased out. */
+/* #define GETOPT_COMPAT */
+
+/* This version of `getopt' appears to the caller like standard Unix `getopt'
+ but it behaves differently for the user, since it allows the user
+ to intersperse the options with the other arguments.
+
+ As `getopt' works, it permutes the elements of ARGV so that,
+ when it is done, all the options precede everything else. Thus
+ all application programs are extended to handle flexible argument order.
+
+ Setting the environment variable POSIXLY_CORRECT disables permutation.
+ Then the behavior is completely standard.
+
+ GNU application programs can use a third alternative mode in which
+ they can distinguish the relative order of options and other arguments. */
+
+#include "getopt.h"
+
+/* For communication from `getopt' to the caller.
+ When `getopt' finds an option that takes an argument,
+ the argument value is returned here.
+ Also, when `ordering' is RETURN_IN_ORDER,
+ each non-option ARGV-element is returned here. */
+
+char *optarg = 0;
+
+/* Index in ARGV of the next element to be scanned.
+ This is used for communication to and from the caller
+ and for communication between successive calls to `getopt'.
+
+ On entry to `getopt', zero means this is the first call; initialize.
+
+ When `getopt' returns EOF, this is the index of the first of the
+ non-option elements that the caller should itself scan.
+
+ Otherwise, `optind' communicates from one call to the next
+ how much of ARGV has been scanned so far. */
+
+/* XXX 1003.2 says this must be 1 before any call. */
+int optind = 0;
+
+/* The next char to be scanned in the option-element
+ in which the last option character we returned was found.
+ This allows us to pick up the scan where we left off.
+
+ If this is zero, or a null string, it means resume the scan
+ by advancing to the next ARGV-element. */
+
+static char *nextchar;
+
+/* Callers store zero here to inhibit the error message
+ for unrecognized options. */
+
+int opterr = 1;
+
+/* Set to an option character which was unrecognized.
+ This must be initialized on some systems to avoid linking in the
+ system's own getopt implementation. */
+
+int optopt = '?';
+
+/* Describe how to deal with options that follow non-option ARGV-elements.
+
+ If the caller did not specify anything,
+ the default is REQUIRE_ORDER if the environment variable
+ POSIXLY_CORRECT is defined, PERMUTE otherwise.
+
+ REQUIRE_ORDER means don't recognize them as options;
+ stop option processing when the first non-option is seen.
+ This is what Unix does.
+ This mode of operation is selected by either setting the environment
+ variable POSIXLY_CORRECT, or using `+' as the first character
+ of the list of option characters.
+
+ PERMUTE is the default. We permute the contents of ARGV as we scan,
+ so that eventually all the non-options are at the end. This allows options
+ to be given in any order, even with programs that were not written to
+ expect this.
+
+ RETURN_IN_ORDER is an option available to programs that were written
+ to expect options and other ARGV-elements in any order and that care about
+ the ordering of the two. We describe each non-option ARGV-element
+ as if it were the argument of an option with character code 1.
+ Using `-' as the first character of the list of option characters
+ selects this mode of operation.
+
+ The special argument `--' forces an end of option-scanning regardless
+ of the value of `ordering'. In the case of RETURN_IN_ORDER, only
+ `--' can cause `getopt' to return EOF with `optind' != ARGC. */
+
+static enum
+{
+ REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER
+} ordering;
+
+#ifdef __GNU_LIBRARY__
+/* We want to avoid inclusion of string.h with non-GNU libraries
+ because there are many ways it can cause trouble.
+ On some systems, it contains special magic macros that don't work
+ in GCC. */
+#include <string.h>
+#define my_index strchr
+#else
+
+/* Avoid depending on library functions or files
+ whose names are inconsistent. */
+
+char *getenv ();
+
+static char *
+my_index (str, chr)
+ const char *str;
+ int chr;
+{
+ while (*str)
+ {
+ if (*str == chr)
+ return (char *) str;
+ str++;
+ }
+ return 0;
+}
+
+/* If using GCC, we can safely declare strlen this way.
+ If not using GCC, it is ok not to declare it. */
+#ifdef __GNUC__
+#ifdef IN_GCC
+#include "gstddef.h"
+#else
+#include <stddef.h>
+#endif
+extern size_t strlen (const char *);
+#endif
+
+#endif /* GNU C library. */
+
+/* Handle permutation of arguments. */
+
+/* Describe the part of ARGV that contains non-options that have
+ been skipped. `first_nonopt' is the index in ARGV of the first of them;
+ `last_nonopt' is the index after the last of them. */
+
+static int first_nonopt;
+static int last_nonopt;
+
+/* Exchange two adjacent subsequences of ARGV.
+ One subsequence is elements [first_nonopt,last_nonopt)
+ which contains all the non-options that have been skipped so far.
+ The other is elements [last_nonopt,optind), which contains all
+ the options processed since those non-options were skipped.
+
+ `first_nonopt' and `last_nonopt' are relocated so that they describe
+ the new indices of the non-options in ARGV after they are moved. */
+
+static void
+exchange (argv)
+ char **argv;
+{
+ int bottom = first_nonopt;
+ int middle = last_nonopt;
+ int top = optind;
+ char *tem;
+
+ /* Exchange the shorter segment with the far end of the longer segment.
+ That puts the shorter segment into the right place.
+ It leaves the longer segment in the right place overall,
+ but it consists of two parts that need to be swapped next. */
+
+ while (top > middle && middle > bottom)
+ {
+ if (top - middle > middle - bottom)
+ {
+ /* Bottom segment is the short one. */
+ int len = middle - bottom;
+ register int i;
+
+ /* Swap it with the top part of the top segment. */
+ for (i = 0; i < len; i++)
+ {
+ tem = argv[bottom + i];
+ argv[bottom + i] = argv[top - (middle - bottom) + i];
+ argv[top - (middle - bottom) + i] = tem;
+ }
+ /* Exclude the moved bottom segment from further swapping. */
+ top -= len;
+ }
+ else
+ {
+ /* Top segment is the short one. */
+ int len = top - middle;
+ register int i;
+
+ /* Swap it with the bottom part of the bottom segment. */
+ for (i = 0; i < len; i++)
+ {
+ tem = argv[bottom + i];
+ argv[bottom + i] = argv[middle + i];
+ argv[middle + i] = tem;
+ }
+ /* Exclude the moved top segment from further swapping. */
+ bottom += len;
+ }
+ }
+
+ /* Update records for the slots the non-options now occupy. */
+
+ first_nonopt += (optind - last_nonopt);
+ last_nonopt = optind;
+}
+
+/* Scan elements of ARGV (whose length is ARGC) for option characters
+ given in OPTSTRING.
+
+ If an element of ARGV starts with '-', and is not exactly "-" or "--",
+ then it is an option element. The characters of this element
+ (aside from the initial '-') are option characters. If `getopt'
+ is called repeatedly, it returns successively each of the option characters
+ from each of the option elements.
+
+ If `getopt' finds another option character, it returns that character,
+ updating `optind' and `nextchar' so that the next call to `getopt' can
+ resume the scan with the following option character or ARGV-element.
+
+ If there are no more option characters, `getopt' returns `EOF'.
+ Then `optind' is the index in ARGV of the first ARGV-element
+ that is not an option. (The ARGV-elements have been permuted
+ so that those that are not options now come last.)
+
+ OPTSTRING is a string containing the legitimate option characters.
+ If an option character is seen that is not listed in OPTSTRING,
+ return '?' after printing an error message. If you set `opterr' to
+ zero, the error message is suppressed but we still return '?'.
+
+ If a char in OPTSTRING is followed by a colon, that means it wants an arg,
+ so the following text in the same ARGV-element, or the text of the following
+ ARGV-element, is returned in `optarg'. Two colons mean an option that
+ wants an optional arg; if there is text in the current ARGV-element,
+ it is returned in `optarg', otherwise `optarg' is set to zero.
+
+ If OPTSTRING starts with `-' or `+', it requests different methods of
+ handling the non-option ARGV-elements.
+ See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above.
+
+ Long-named options begin with `--' instead of `-'.
+ Their names may be abbreviated as long as the abbreviation is unique
+ or is an exact match for some defined option. If they have an
+ argument, it follows the option name in the same ARGV-element, separated
+ from the option name by a `=', or else the in next ARGV-element.
+ When `getopt' finds a long-named option, it returns 0 if that option's
+ `flag' field is nonzero, the value of the option's `val' field
+ if the `flag' field is zero.
+
+ The elements of ARGV aren't really const, because we permute them.
+ But we pretend they're const in the prototype to be compatible
+ with other systems.
+
+ LONGOPTS is a vector of `struct option' terminated by an
+ element containing a name which is zero.
+
+ LONGIND returns the index in LONGOPT of the long-named option found.
+ It is only valid when a long-named option has been found by the most
+ recent call.
+
+ If LONG_ONLY is nonzero, '-' as well as '--' can introduce
+ long-named options. */
+
+int
+_getopt_internal (argc, argv, optstring, longopts, longind, long_only)
+ int argc;
+ char *const *argv;
+ const char *optstring;
+ const struct option *longopts;
+ int *longind;
+ int long_only;
+{
+ int option_index;
+
+ optarg = 0;
+
+ /* Initialize the internal data when the first call is made.
+ Start processing options with ARGV-element 1 (since ARGV-element 0
+ is the program name); the sequence of previously skipped
+ non-option ARGV-elements is empty. */
+
+ if (optind == 0)
+ {
+ first_nonopt = last_nonopt = optind = 1;
+
+ nextchar = NULL;
+
+ /* Determine how to handle the ordering of options and nonoptions. */
+
+ if (optstring[0] == '-')
+ {
+ ordering = RETURN_IN_ORDER;
+ ++optstring;
+ }
+ else if (optstring[0] == '+')
+ {
+ ordering = REQUIRE_ORDER;
+ ++optstring;
+ }
+ else if (getenv ("POSIXLY_CORRECT") != NULL)
+ ordering = REQUIRE_ORDER;
+ else
+ ordering = PERMUTE;
+ }
+
+ if (nextchar == NULL || *nextchar == '\0')
+ {
+ if (ordering == PERMUTE)
+ {
+ /* If we have just processed some options following some non-options,
+ exchange them so that the options come first. */
+
+ if (first_nonopt != last_nonopt && last_nonopt != optind)
+ exchange ((char **) argv);
+ else if (last_nonopt != optind)
+ first_nonopt = optind;
+
+ /* Now skip any additional non-options
+ and extend the range of non-options previously skipped. */
+
+ while (optind < argc
+ && (argv[optind][0] != '-' || argv[optind][1] == '\0')
+#ifdef GETOPT_COMPAT
+ && (longopts == NULL
+ || argv[optind][0] != '+' || argv[optind][1] == '\0')
+#endif /* GETOPT_COMPAT */
+ )
+ optind++;
+ last_nonopt = optind;
+ }
+
+ /* Special ARGV-element `--' means premature end of options.
+ Skip it like a null option,
+ then exchange with previous non-options as if it were an option,
+ then skip everything else like a non-option. */
+
+ if (optind != argc && !strcmp (argv[optind], "--"))
+ {
+ optind++;
+
+ if (first_nonopt != last_nonopt && last_nonopt != optind)
+ exchange ((char **) argv);
+ else if (first_nonopt == last_nonopt)
+ first_nonopt = optind;
+ last_nonopt = argc;
+
+ optind = argc;
+ }
+
+ /* If we have done all the ARGV-elements, stop the scan
+ and back over any non-options that we skipped and permuted. */
+
+ if (optind == argc)
+ {
+ /* Set the next-arg-index to point at the non-options
+ that we previously skipped, so the caller will digest them. */
+ if (first_nonopt != last_nonopt)
+ optind = first_nonopt;
+ return EOF;
+ }
+
+ /* If we have come to a non-option and did not permute it,
+ either stop the scan or describe it to the caller and pass it by. */
+
+ if ((argv[optind][0] != '-' || argv[optind][1] == '\0')
+#ifdef GETOPT_COMPAT
+ && (longopts == NULL
+ || argv[optind][0] != '+' || argv[optind][1] == '\0')
+#endif /* GETOPT_COMPAT */
+ )
+ {
+ if (ordering == REQUIRE_ORDER)
+ return EOF;
+ optarg = argv[optind++];
+ return 1;
+ }
+
+ /* We have found another option-ARGV-element.
+ Start decoding its characters. */
+
+ nextchar = (argv[optind] + 1
+ + (longopts != NULL && argv[optind][1] == '-'));
+ }
+
+ if (longopts != NULL
+ && ((argv[optind][0] == '-'
+ && (argv[optind][1] == '-' || long_only))
+#ifdef GETOPT_COMPAT
+ || argv[optind][0] == '+'
+#endif /* GETOPT_COMPAT */
+ ))
+ {
+ const struct option *p;
+ char *s = nextchar;
+ int exact = 0;
+ int ambig = 0;
+ const struct option *pfound = NULL;
+ int indfound;
+
+ while (*s && *s != '=')
+ s++;
+
+ /* Test all options for either exact match or abbreviated matches. */
+ for (p = longopts, option_index = 0; p->name;
+ p++, option_index++)
+ if (!strncmp (p->name, nextchar, s - nextchar))
+ {
+ if (s - nextchar == strlen (p->name))
+ {
+ /* Exact match found. */
+ pfound = p;
+ indfound = option_index;
+ exact = 1;
+ break;
+ }
+ else if (pfound == NULL)
+ {
+ /* First nonexact match found. */
+ pfound = p;
+ indfound = option_index;
+ }
+ else
+ /* Second nonexact match found. */
+ ambig = 1;
+ }
+
+ if (ambig && !exact)
+ {
+ if (opterr)
+ fprintf (stderr, "%s: option `%s' is ambiguous\n",
+ argv[0], argv[optind]);
+ nextchar += strlen (nextchar);
+ optind++;
+ return '?';
+ }
+
+ if (pfound != NULL)
+ {
+ option_index = indfound;
+ optind++;
+ if (*s)
+ {
+ /* Don't test has_arg with >, because some C compilers don't
+ allow it to be used on enums. */
+ if (pfound->has_arg)
+ optarg = s + 1;
+ else
+ {
+ if (opterr)
+ {
+ if (argv[optind - 1][1] == '-')
+ /* --option */
+ fprintf (stderr,
+ "%s: option `--%s' doesn't allow an argument\n",
+ argv[0], pfound->name);
+ else
+ /* +option or -option */
+ fprintf (stderr,
+ "%s: option `%c%s' doesn't allow an argument\n",
+ argv[0], argv[optind - 1][0], pfound->name);
+ }
+ nextchar += strlen (nextchar);
+ return '?';
+ }
+ }
+ else if (pfound->has_arg == 1)
+ {
+ if (optind < argc)
+ optarg = argv[optind++];
+ else
+ {
+ if (opterr)
+ fprintf (stderr, "%s: option `%s' requires an argument\n",
+ argv[0], argv[optind - 1]);
+ nextchar += strlen (nextchar);
+ return optstring[0] == ':' ? ':' : '?';
+ }
+ }
+ nextchar += strlen (nextchar);
+ if (longind != NULL)
+ *longind = option_index;
+ if (pfound->flag)
+ {
+ *(pfound->flag) = pfound->val;
+ return 0;
+ }
+ return pfound->val;
+ }
+ /* Can't find it as a long option. If this is not getopt_long_only,
+ or the option starts with '--' or is not a valid short
+ option, then it's an error.
+ Otherwise interpret it as a short option. */
+ if (!long_only || argv[optind][1] == '-'
+#ifdef GETOPT_COMPAT
+ || argv[optind][0] == '+'
+#endif /* GETOPT_COMPAT */
+ || my_index (optstring, *nextchar) == NULL)
+ {
+ if (opterr)
+ {
+ if (argv[optind][1] == '-')
+ /* --option */
+ fprintf (stderr, "%s: unrecognized option `--%s'\n",
+ argv[0], nextchar);
+ else
+ /* +option or -option */
+ fprintf (stderr, "%s: unrecognized option `%c%s'\n",
+ argv[0], argv[optind][0], nextchar);
+ }
+ nextchar = (char *) "";
+ optind++;
+ return '?';
+ }
+ }
+
+ /* Look at and handle the next option-character. */
+
+ {
+ char c = *nextchar++;
+ char *temp = my_index (optstring, c);
+
+ /* Increment `optind' when we start to process its last character. */
+ if (*nextchar == '\0')
+ ++optind;
+
+ if (temp == NULL || c == ':')
+ {
+ if (opterr)
+ {
+#if 0
+ if (c < 040 || c >= 0177)
+ fprintf (stderr, "%s: unrecognized option, character code 0%o\n",
+ argv[0], c);
+ else
+ fprintf (stderr, "%s: unrecognized option `-%c'\n", argv[0], c);
+#else
+ /* 1003.2 specifies the format of this message. */
+ fprintf (stderr, "%s: illegal option -- %c\n", argv[0], c);
+#endif
+ }
+ optopt = c;
+ return '?';
+ }
+ if (temp[1] == ':')
+ {
+ if (temp[2] == ':')
+ {
+ /* This is an option that accepts an argument optionally. */
+ if (*nextchar != '\0')
+ {
+ optarg = nextchar;
+ optind++;
+ }
+ else
+ optarg = 0;
+ nextchar = NULL;
+ }
+ else
+ {
+ /* This is an option that requires an argument. */
+ if (*nextchar != '\0')
+ {
+ optarg = nextchar;
+ /* If we end this ARGV-element by taking the rest as an arg,
+ we must advance to the next element now. */
+ optind++;
+ }
+ else if (optind == argc)
+ {
+ if (opterr)
+ {
+#if 0
+ fprintf (stderr, "%s: option `-%c' requires an argument\n",
+ argv[0], c);
+#else
+ /* 1003.2 specifies the format of this message. */
+ fprintf (stderr, "%s: option requires an argument -- %c\n",
+ argv[0], c);
+#endif
+ }
+ optopt = c;
+ if (optstring[0] == ':')
+ c = ':';
+ else
+ c = '?';
+ }
+ else
+ /* We already incremented `optind' once;
+ increment it again when taking next ARGV-elt as argument. */
+ optarg = argv[optind++];
+ nextchar = NULL;
+ }
+ }
+ return c;
+ }
+}
+
+int
+getopt (argc, argv, optstring)
+ int argc;
+ char *const *argv;
+ const char *optstring;
+{
+ return _getopt_internal (argc, argv, optstring,
+ (const struct option *) 0,
+ (int *) 0,
+ 0);
+}
+
+#endif /* _LIBC or not __GNU_LIBRARY__. */
+
+#ifdef TEST
+
+/* Compile with -DTEST to make an executable for use in testing
+ the above definition of `getopt'. */
+
+int
+main (argc, argv)
+ int argc;
+ char **argv;
+{
+ int c;
+ int digit_optind = 0;
+
+ while (1)
+ {
+ int this_option_optind = optind ? optind : 1;
+
+ c = getopt (argc, argv, "abc:d:0123456789");
+ if (c == EOF)
+ break;
+
+ switch (c)
+ {
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ if (digit_optind != 0 && digit_optind != this_option_optind)
+ printf ("digits occur in two different argv-elements.\n");
+ digit_optind = this_option_optind;
+ printf ("option %c\n", c);
+ break;
+
+ case 'a':
+ printf ("option a\n");
+ break;
+
+ case 'b':
+ printf ("option b\n");
+ break;
+
+ case 'c':
+ printf ("option c with value `%s'\n", optarg);
+ break;
+
+ case '?':
+ break;
+
+ default:
+ printf ("?? getopt returned character code 0%o ??\n", c);
+ }
+ }
+
+ if (optind < argc)
+ {
+ printf ("non-option ARGV-elements: ");
+ while (optind < argc)
+ printf ("%s ", argv[optind++]);
+ printf ("\n");
+ }
+
+ exit (0);
+}
+
+#endif /* TEST */
diff --git a/gnu/usr.bin/cpio/getopt.h b/gnu/usr.bin/cpio/getopt.h
new file mode 100644
index 0000000..45541f5
--- /dev/null
+++ b/gnu/usr.bin/cpio/getopt.h
@@ -0,0 +1,129 @@
+/* Declarations for getopt.
+ Copyright (C) 1989, 1990, 1991, 1992, 1993 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any
+ later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#ifndef _GETOPT_H
+#define _GETOPT_H 1
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* For communication from `getopt' to the caller.
+ When `getopt' finds an option that takes an argument,
+ the argument value is returned here.
+ Also, when `ordering' is RETURN_IN_ORDER,
+ each non-option ARGV-element is returned here. */
+
+extern char *optarg;
+
+/* Index in ARGV of the next element to be scanned.
+ This is used for communication to and from the caller
+ and for communication between successive calls to `getopt'.
+
+ On entry to `getopt', zero means this is the first call; initialize.
+
+ When `getopt' returns EOF, this is the index of the first of the
+ non-option elements that the caller should itself scan.
+
+ Otherwise, `optind' communicates from one call to the next
+ how much of ARGV has been scanned so far. */
+
+extern int optind;
+
+/* Callers store zero here to inhibit the error message `getopt' prints
+ for unrecognized options. */
+
+extern int opterr;
+
+/* Set to an option character which was unrecognized. */
+
+extern int optopt;
+
+/* Describe the long-named options requested by the application.
+ The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector
+ of `struct option' terminated by an element containing a name which is
+ zero.
+
+ The field `has_arg' is:
+ no_argument (or 0) if the option does not take an argument,
+ required_argument (or 1) if the option requires an argument,
+ optional_argument (or 2) if the option takes an optional argument.
+
+ If the field `flag' is not NULL, it points to a variable that is set
+ to the value given in the field `val' when the option is found, but
+ left unchanged if the option is not found.
+
+ To have a long-named option do something other than set an `int' to
+ a compiled-in constant, such as set a value from `optarg', set the
+ option's `flag' field to zero and its `val' field to a nonzero
+ value (the equivalent single-letter option character, if there is
+ one). For long options that have a zero `flag' field, `getopt'
+ returns the contents of the `val' field. */
+
+struct option
+{
+#if __STDC__
+ const char *name;
+#else
+ char *name;
+#endif
+ /* has_arg can't be an enum because some compilers complain about
+ type mismatches in all the code that assumes it is an int. */
+ int has_arg;
+ int *flag;
+ int val;
+};
+
+/* Names for the values of the `has_arg' field of `struct option'. */
+
+#define no_argument 0
+#define required_argument 1
+#define optional_argument 2
+
+#if __STDC__
+#if defined(__GNU_LIBRARY__)
+/* Many other libraries have conflicting prototypes for getopt, with
+ differences in the consts, in stdlib.h. To avoid compilation
+ errors, only prototype getopt for the GNU C library. */
+extern int getopt (int argc, char *const *argv, const char *shortopts);
+#else /* not __GNU_LIBRARY__ */
+extern int getopt ();
+#endif /* not __GNU_LIBRARY__ */
+extern int getopt_long (int argc, char *const *argv, const char *shortopts,
+ const struct option *longopts, int *longind);
+extern int getopt_long_only (int argc, char *const *argv,
+ const char *shortopts,
+ const struct option *longopts, int *longind);
+
+/* Internal only. Users should not call this directly. */
+extern int _getopt_internal (int argc, char *const *argv,
+ const char *shortopts,
+ const struct option *longopts, int *longind,
+ int long_only);
+#else /* not __STDC__ */
+extern int getopt ();
+extern int getopt_long ();
+extern int getopt_long_only ();
+
+extern int _getopt_internal ();
+#endif /* not __STDC__ */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _GETOPT_H */
diff --git a/gnu/usr.bin/cpio/getopt1.c b/gnu/usr.bin/cpio/getopt1.c
new file mode 100644
index 0000000..a32615c
--- /dev/null
+++ b/gnu/usr.bin/cpio/getopt1.c
@@ -0,0 +1,176 @@
+/* getopt_long and getopt_long_only entry points for GNU getopt.
+ Copyright (C) 1987, 88, 89, 90, 91, 92, 1993
+ Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any
+ later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "getopt.h"
+
+#if !__STDC__ && !defined(const) && IN_GCC
+#define const
+#endif
+
+#include <stdio.h>
+
+/* Comment out all this code if we are using the GNU C Library, and are not
+ actually compiling the library itself. This code is part of the GNU C
+ Library, but also included in many other GNU distributions. Compiling
+ and linking in this code is a waste when using the GNU C library
+ (especially if it is a shared library). Rather than having every GNU
+ program understand `configure --with-gnu-libc' and omit the object files,
+ it is simpler to just do this in the source for each such file. */
+
+#if defined (_LIBC) || !defined (__GNU_LIBRARY__)
+
+
+/* This needs to come after some library #include
+ to get __GNU_LIBRARY__ defined. */
+#ifdef __GNU_LIBRARY__
+#include <stdlib.h>
+#else
+char *getenv ();
+#endif
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+int
+getopt_long (argc, argv, options, long_options, opt_index)
+ int argc;
+ char *const *argv;
+ const char *options;
+ const struct option *long_options;
+ int *opt_index;
+{
+ return _getopt_internal (argc, argv, options, long_options, opt_index, 0);
+}
+
+/* Like getopt_long, but '-' as well as '--' can indicate a long option.
+ If an option that starts with '-' (not '--') doesn't match a long option,
+ but does match a short option, it is parsed as a short option
+ instead. */
+
+int
+getopt_long_only (argc, argv, options, long_options, opt_index)
+ int argc;
+ char *const *argv;
+ const char *options;
+ const struct option *long_options;
+ int *opt_index;
+{
+ return _getopt_internal (argc, argv, options, long_options, opt_index, 1);
+}
+
+
+#endif /* _LIBC or not __GNU_LIBRARY__. */
+
+#ifdef TEST
+
+#include <stdio.h>
+
+int
+main (argc, argv)
+ int argc;
+ char **argv;
+{
+ int c;
+ int digit_optind = 0;
+
+ while (1)
+ {
+ int this_option_optind = optind ? optind : 1;
+ int option_index = 0;
+ static struct option long_options[] =
+ {
+ {"add", 1, 0, 0},
+ {"append", 0, 0, 0},
+ {"delete", 1, 0, 0},
+ {"verbose", 0, 0, 0},
+ {"create", 0, 0, 0},
+ {"file", 1, 0, 0},
+ {0, 0, 0, 0}
+ };
+
+ c = getopt_long (argc, argv, "abc:d:0123456789",
+ long_options, &option_index);
+ if (c == EOF)
+ break;
+
+ switch (c)
+ {
+ case 0:
+ printf ("option %s", long_options[option_index].name);
+ if (optarg)
+ printf (" with arg %s", optarg);
+ printf ("\n");
+ break;
+
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ if (digit_optind != 0 && digit_optind != this_option_optind)
+ printf ("digits occur in two different argv-elements.\n");
+ digit_optind = this_option_optind;
+ printf ("option %c\n", c);
+ break;
+
+ case 'a':
+ printf ("option a\n");
+ break;
+
+ case 'b':
+ printf ("option b\n");
+ break;
+
+ case 'c':
+ printf ("option c with value `%s'\n", optarg);
+ break;
+
+ case 'd':
+ printf ("option d with value `%s'\n", optarg);
+ break;
+
+ case '?':
+ break;
+
+ default:
+ printf ("?? getopt returned character code 0%o ??\n", c);
+ }
+ }
+
+ if (optind < argc)
+ {
+ printf ("non-option ARGV-elements: ");
+ while (optind < argc)
+ printf ("%s ", argv[optind++]);
+ printf ("\n");
+ }
+
+ exit (0);
+}
+
+#endif /* TEST */
diff --git a/gnu/usr.bin/cpio/global.c b/gnu/usr.bin/cpio/global.c
new file mode 100644
index 0000000..d4b5441
--- /dev/null
+++ b/gnu/usr.bin/cpio/global.c
@@ -0,0 +1,168 @@
+/* global.c - global variables and initial values for cpio.
+ Copyright (C) 1990, 1991, 1992 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <sys/types.h>
+#include "cpiohdr.h"
+#include "dstring.h"
+#include "system.h"
+#include "extern.h"
+
+/* If TRUE, reset access times after reading files (-a). */
+int reset_time_flag = FALSE;
+
+/* Block size value, initially 512. -B sets to 5120. */
+int io_block_size = 512;
+
+/* The header format to recognize and produce. */
+enum archive_format archive_format = arf_unknown;
+
+/* If TRUE, create directories as needed. (-d with -i or -p) */
+int create_dir_flag = FALSE;
+
+/* If TRUE, interactively rename files. (-r) */
+int rename_flag = FALSE;
+
+/* If TRUE, print a table of contents of input. (-t) */
+int table_flag = FALSE;
+
+/* If TRUE, copy unconditionally (older replaces newer). (-u) */
+int unconditional_flag = FALSE;
+
+/* If TRUE, list the files processed, or ls -l style output with -t. (-v) */
+int verbose_flag = FALSE;
+
+/* If TRUE, print a . for each file processed. (-V) */
+int dot_flag = FALSE;
+
+/* If TRUE, link files whenever possible. Used with -p option. (-l) */
+int link_flag = FALSE;
+
+/* If TRUE, retain previous file modification time. (-m) */
+int retain_time_flag = FALSE;
+
+/* Set TRUE if crc_flag is TRUE and we are doing a cpio -i. Used
+ by copy_files so it knows whether to compute the crc. */
+int crc_i_flag = FALSE;
+
+/* If TRUE, append to end of archive. (-A) */
+int append_flag = FALSE;
+
+/* If TRUE, swap bytes of each file during cpio -i. */
+int swap_bytes_flag = FALSE;
+
+/* If TRUE, swap halfwords of each file during cpio -i. */
+int swap_halfwords_flag = FALSE;
+
+/* If TRUE, we are swapping halfwords on the current file. */
+int swapping_halfwords = FALSE;
+
+/* If TRUE, we are swapping bytes on the current file. */
+int swapping_bytes = FALSE;
+
+/* If TRUE, set ownership of all files to UID `set_owner'. */
+int set_owner_flag = FALSE;
+uid_t set_owner;
+
+/* If TRUE, set group ownership of all files to GID `set_group'. */
+int set_group_flag = FALSE;
+gid_t set_group;
+
+/* If TRUE, do not chown the files. */
+int no_chown_flag = FALSE;
+
+#ifdef DEBUG_CPIO
+/* If TRUE, print debugging information. */
+int debug_flag = FALSE;
+#endif
+
+/* File position of last header read. Only used during -A to determine
+ where the old TRAILER!!! record started. */
+int last_header_start = 0;
+
+/* With -i; if TRUE, copy only files that match any of the given patterns;
+ if FALSE, copy only files that do not match any of the patterns. (-f) */
+int copy_matching_files = TRUE;
+
+/* With -itv; if TRUE, list numeric uid and gid instead of translating them
+ into names. */
+int numeric_uid = FALSE;
+
+/* Name of file containing additional patterns (-E). */
+char *pattern_file_name = NULL;
+
+/* Message to print when end of medium is reached (-M). */
+char *new_media_message = NULL;
+
+/* With -M with %d, message to print when end of medium is reached. */
+char *new_media_message_with_number = NULL;
+char *new_media_message_after_number = NULL;
+
+/* File descriptor containing the archive. */
+int archive_des;
+
+/* Name of file containing the archive, if known; NULL if stdin/out. */
+char *archive_name = NULL;
+
+/* CRC checksum. */
+unsigned long crc;
+
+/* Input and output buffers. */
+char *input_buffer, *output_buffer;
+
+/* Current locations in `input_buffer' and `output_buffer'. */
+char *in_buff, *out_buff;
+
+/* Current number of bytes stored at `input_buff' and `output_buff'. */
+long input_size, output_size;
+
+/* Total number of bytes read and written for all files. */
+long input_bytes, output_bytes;
+
+/* 512 bytes of 0; used for various padding operations. */
+char zeros_512[512];
+
+/* Saving of argument values for later reference. */
+char *directory_name = NULL;
+char **save_patterns;
+int num_patterns;
+
+/* Character that terminates file names read from stdin. */
+char name_end = '\n';
+
+/* TRUE if input (cpio -i) or output (cpio -o) is a device node. */
+char input_is_special = FALSE;
+char output_is_special = FALSE;
+
+/* TRUE if lseek works on the input. */
+char input_is_seekable = FALSE;
+
+/* TRUE if lseek works on the output. */
+char output_is_seekable = FALSE;
+
+/* If nonzero, don't consider file names that contain a `:' to be
+ on remote hosts; all files are local. */
+int f_force_local = 0;
+
+/* The name this program was run with. */
+char *program_name;
+
+/* A pointer to either lstat or stat, depending on whether
+ dereferencing of symlinks is done for input files. */
+int (*xstat) ();
+
+/* Which copy operation to perform. (-i, -o, -p) */
+void (*copy_function) () = 0;
diff --git a/gnu/usr.bin/cpio/idcache.c b/gnu/usr.bin/cpio/idcache.c
new file mode 100644
index 0000000..341c9f4
--- /dev/null
+++ b/gnu/usr.bin/cpio/idcache.c
@@ -0,0 +1,206 @@
+/* idcache.c -- map user and group IDs, cached for speed
+ Copyright (C) 1985, 1988, 1989, 1990 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <pwd.h>
+#include <grp.h>
+
+#if defined(STDC_HEADERS) || defined(HAVE_STRING_H)
+#include <string.h>
+#else
+#include <strings.h>
+#endif
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#ifndef _POSIX_VERSION
+struct passwd *getpwuid ();
+struct passwd *getpwnam ();
+struct group *getgrgid ();
+struct group *getgrnam ();
+#endif
+
+char *xmalloc ();
+char *xstrdup ();
+
+struct userid
+{
+ union
+ {
+ uid_t u;
+ gid_t g;
+ } id;
+ char *name;
+ struct userid *next;
+};
+
+static struct userid *user_alist;
+
+/* The members of this list have names not in the local passwd file. */
+static struct userid *nouser_alist;
+
+/* Translate UID to a login name or a stringified number,
+ with cache. */
+
+char *
+getuser (uid)
+ uid_t uid;
+{
+ register struct userid *tail;
+ struct passwd *pwent;
+ char usernum_string[20];
+
+ for (tail = user_alist; tail; tail = tail->next)
+ if (tail->id.u == uid)
+ return tail->name;
+
+ pwent = getpwuid (uid);
+ tail = (struct userid *) xmalloc (sizeof (struct userid));
+ tail->id.u = uid;
+ if (pwent == 0)
+ {
+ sprintf (usernum_string, "%u", (unsigned) uid);
+ tail->name = xstrdup (usernum_string);
+ }
+ else
+ tail->name = xstrdup (pwent->pw_name);
+
+ /* Add to the head of the list, so most recently used is first. */
+ tail->next = user_alist;
+ user_alist = tail;
+ return tail->name;
+}
+
+/* Translate USER to a UID, with cache.
+ Return NULL if there is no such user.
+ (We also cache which user names have no passwd entry,
+ so we don't keep looking them up.) */
+
+uid_t *
+getuidbyname (user)
+ char *user;
+{
+ register struct userid *tail;
+ struct passwd *pwent;
+
+ for (tail = user_alist; tail; tail = tail->next)
+ /* Avoid a function call for the most common case. */
+ if (*tail->name == *user && !strcmp (tail->name, user))
+ return &tail->id.u;
+
+ for (tail = nouser_alist; tail; tail = tail->next)
+ /* Avoid a function call for the most common case. */
+ if (*tail->name == *user && !strcmp (tail->name, user))
+ return 0;
+
+ pwent = getpwnam (user);
+
+ tail = (struct userid *) xmalloc (sizeof (struct userid));
+ tail->name = xstrdup (user);
+
+ /* Add to the head of the list, so most recently used is first. */
+ if (pwent)
+ {
+ tail->id.u = pwent->pw_uid;
+ tail->next = user_alist;
+ user_alist = tail;
+ return &tail->id.u;
+ }
+
+ tail->next = nouser_alist;
+ nouser_alist = tail;
+ return 0;
+}
+
+/* Use the same struct as for userids. */
+static struct userid *group_alist;
+static struct userid *nogroup_alist;
+
+/* Translate GID to a group name or a stringified number,
+ with cache. */
+
+char *
+getgroup (gid)
+ gid_t gid;
+{
+ register struct userid *tail;
+ struct group *grent;
+ char groupnum_string[20];
+
+ for (tail = group_alist; tail; tail = tail->next)
+ if (tail->id.g == gid)
+ return tail->name;
+
+ grent = getgrgid (gid);
+ tail = (struct userid *) xmalloc (sizeof (struct userid));
+ tail->id.g = gid;
+ if (grent == 0)
+ {
+ sprintf (groupnum_string, "%u", (unsigned int) gid);
+ tail->name = xstrdup (groupnum_string);
+ }
+ else
+ tail->name = xstrdup (grent->gr_name);
+
+ /* Add to the head of the list, so most recently used is first. */
+ tail->next = group_alist;
+ group_alist = tail;
+ return tail->name;
+}
+
+/* Translate GROUP to a UID, with cache.
+ Return NULL if there is no such group.
+ (We also cache which group names have no group entry,
+ so we don't keep looking them up.) */
+
+gid_t *
+getgidbyname (group)
+ char *group;
+{
+ register struct userid *tail;
+ struct group *grent;
+
+ for (tail = group_alist; tail; tail = tail->next)
+ /* Avoid a function call for the most common case. */
+ if (*tail->name == *group && !strcmp (tail->name, group))
+ return &tail->id.g;
+
+ for (tail = nogroup_alist; tail; tail = tail->next)
+ /* Avoid a function call for the most common case. */
+ if (*tail->name == *group && !strcmp (tail->name, group))
+ return 0;
+
+ grent = getgrnam (group);
+
+ tail = (struct userid *) xmalloc (sizeof (struct userid));
+ tail->name = xstrdup (group);
+
+ /* Add to the head of the list, so most recently used is first. */
+ if (grent)
+ {
+ tail->id.g = grent->gr_gid;
+ tail->next = group_alist;
+ group_alist = tail;
+ return &tail->id.g;
+ }
+
+ tail->next = nogroup_alist;
+ nogroup_alist = tail;
+ return 0;
+}
diff --git a/gnu/usr.bin/cpio/lchown.c b/gnu/usr.bin/cpio/lchown.c
new file mode 100644
index 0000000..99c5b26
--- /dev/null
+++ b/gnu/usr.bin/cpio/lchown.c
@@ -0,0 +1,27 @@
+/* lchown.c - dummy version of lchown for systems that do not store
+ file owners of symbolic links.
+ Copyright (C) 1995 Rodney W. Grimes, Accurate Automation Company
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* Written by Rodney W. Grimes <rgrimes@FreeBSD.Org> */
+
+#include <unistd.h>
+
+int
+lchown(const char *path, uid_t owner, gid_t group) {
+
+ return (0);
+}
diff --git a/gnu/usr.bin/cpio/main.c b/gnu/usr.bin/cpio/main.c
new file mode 100644
index 0000000..9346b78
--- /dev/null
+++ b/gnu/usr.bin/cpio/main.c
@@ -0,0 +1,485 @@
+/* main.c - main program and argument processing for cpio.
+ Copyright (C) 1990, 1991, 1992 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* Written by Phil Nelson <phil@cs.wwu.edu>,
+ David MacKenzie <djm@gnu.ai.mit.edu>,
+ and John Oleynick <juo@klinzhai.rutgers.edu>. */
+
+#include <stdio.h>
+#include <getopt.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#ifdef __FreeBSD__
+#include <locale.h>
+#endif
+#include "filetypes.h"
+#include "system.h"
+#include "cpiohdr.h"
+#include "dstring.h"
+#include "extern.h"
+#include "rmt.h"
+
+struct option long_opts[] =
+{
+ {"null", 0, 0, '0'},
+ {"append", 0, 0, 'A'},
+ {"block-size", 1, 0, 130},
+ {"create", 0, 0, 'o'},
+ {"dereference", 0, 0, 'L'},
+ {"dot", 0, 0, 'V'},
+ {"extract", 0, 0, 'i'},
+ {"file", 1, 0, 'F'},
+ {"force-local", 0, &f_force_local, 1},
+ {"format", 1, 0, 'H'},
+ {"help", 0, 0, 132},
+ {"io-size", 1, 0, 'C'},
+ {"link", 0, &link_flag, TRUE},
+ {"list", 0, &table_flag, TRUE},
+ {"make-directories", 0, &create_dir_flag, TRUE},
+ {"message", 1, 0, 'M'},
+ {"no-preserve-owner", 0, 0, 134},
+ {"nonmatching", 0, &copy_matching_files, FALSE},
+ {"numeric-uid-gid", 0, &numeric_uid, TRUE},
+ {"owner", 1, 0, 'R'},
+ {"pass-through", 0, 0, 'p'},
+ {"pattern-file", 1, 0, 'E'},
+ {"preserve-modification-time", 0, &retain_time_flag, TRUE},
+ {"rename", 0, &rename_flag, TRUE},
+ {"swap", 0, 0, 'b'},
+ {"swap-bytes", 0, 0, 's'},
+ {"swap-halfwords", 0, 0, 'S'},
+ {"reset-access-time", 0, &reset_time_flag, TRUE},
+ {"unconditional", 0, &unconditional_flag, TRUE},
+ {"verbose", 0, &verbose_flag, TRUE},
+ {"version", 0, 0, 131},
+#ifdef DEBUG_CPIO
+ {"debug", 0, &debug_flag, TRUE},
+#endif
+ {0, 0, 0, 0}
+};
+
+/* Print usage message and exit with error. */
+
+void
+usage (fp, status)
+ FILE *fp;
+ int status;
+{
+ fprintf (fp, "\
+Usage: %s {-o|--create} [-0acvABLV] [-C bytes] [-H format] [-M message]\n\
+ [-O [[user@]host:]archive] [-F [[user@]host:]archive]\n\
+ [--file=[[user@]host:]archive] [--format=format] [--message=message]\n\
+ [--null] [--reset-access-time] [--verbose] [--dot] [--append]\n\
+ [--block-size=blocks] [--dereference] [--io-size=bytes]\n\
+ [--force-local] [--help] [--version] < name-list [> archive]\n", program_name);
+ fprintf (fp, "\
+ %s {-i|--extract} [-bcdfmnrtsuvBSV] [-C bytes] [-E file] [-H format]\n\
+ [-M message] [-R [user][:.][group]] [-I [[user@]host:]archive]\n\
+ [-F [[user@]host:]archive] [--file=[[user@]host:]archive]\n\
+ [--make-directories] [--nonmatching] [--preserve-modification-time]\n\
+ [--numeric-uid-gid] [--rename] [--list] [--swap-bytes] [--swap] [--dot]\n\
+ [--unconditional] [--verbose] [--block-size=blocks] [--swap-halfwords]\n\
+ [--io-size=bytes] [--pattern-file=file] [--format=format]\n\
+ [--owner=[user][:.][group]] [--no-preserve-owner] [--message=message]\n\
+ [--force-local] [--help] [--version] [pattern...] [< archive]\n",
+ program_name);
+ fprintf (fp, "\
+ %s {-p|--pass-through} [-0adlmuvLV] [-R [user][:.][group]]\n\
+ [--null] [--reset-access-time] [--make-directories] [--link]\n\
+ [--preserve-modification-time] [--unconditional] [--verbose] [--dot]\n\
+ [--dereference] [--owner=[user][:.][group]] [--no-preserve-owner]\n\
+ [--help] [--version] destination-directory < name-list\n", program_name);
+ exit (status);
+}
+
+/* Process the arguments. Set all options and set up the copy pass
+ directory or the copy in patterns. */
+
+void
+process_args (argc, argv)
+ int argc;
+ char *argv[];
+{
+ extern char *version_string;
+ void (*copy_in) (); /* Work around for pcc bug. */
+ void (*copy_out) ();
+ int c;
+ char *input_archive_name = 0;
+ char *output_archive_name = 0;
+
+ if (argc < 2)
+ usage (stderr, 2);
+
+ xstat = lstat;
+
+ while ((c = getopt_long (argc, argv,
+ "0aAbBcC:dfE:F:H:iI:lLmM:noO:prR:sStuvVz",
+ long_opts, (int *) 0)) != -1)
+ {
+ switch (c)
+ {
+ case 0: /* A long option that just sets a flag. */
+ break;
+
+ case '0': /* Read null-terminated filenames. */
+ name_end = '\0';
+ break;
+
+ case 'a': /* Reset access times. */
+ reset_time_flag = TRUE;
+ break;
+
+ case 'A': /* Append to the archive. */
+ append_flag = TRUE;
+ break;
+
+ case 'b': /* Swap bytes and halfwords. */
+ swap_bytes_flag = TRUE;
+ swap_halfwords_flag = TRUE;
+ break;
+
+ case 'B': /* Set block size to 5120. */
+ io_block_size = 5120;
+ break;
+
+ case 130: /* --block-size */
+ io_block_size = atoi (optarg);
+ if (io_block_size < 1)
+ error (2, 0, "invalid block size");
+ io_block_size *= 512;
+ break;
+
+ case 'c': /* Use the old portable ASCII format. */
+ if (archive_format != arf_unknown)
+ usage (stderr, 2);
+#ifdef SVR4_COMPAT
+ archive_format = arf_newascii; /* -H newc. */
+#else
+ archive_format = arf_oldascii; /* -H odc. */
+#endif
+ break;
+
+ case 'C': /* Block size. */
+ io_block_size = atoi (optarg);
+ if (io_block_size < 1)
+ error (2, 0, "invalid block size");
+ break;
+
+ case 'd': /* Create directories where needed. */
+ create_dir_flag = TRUE;
+ break;
+
+ case 'f': /* Only copy files not matching patterns. */
+ copy_matching_files = FALSE;
+ break;
+
+ case 'E': /* Pattern file name. */
+ pattern_file_name = optarg;
+ break;
+
+ case 'F': /* Archive file name. */
+ archive_name = optarg;
+ break;
+
+ case 'H': /* Header format name. */
+ if (archive_format != arf_unknown)
+ usage (stderr, 2);
+ if (!strcmp (optarg, "crc") || !strcmp (optarg, "CRC"))
+ archive_format = arf_crcascii;
+ else if (!strcmp (optarg, "newc") || !strcmp (optarg, "NEWC"))
+ archive_format = arf_newascii;
+ else if (!strcmp (optarg, "odc") || !strcmp (optarg, "ODC"))
+ archive_format = arf_oldascii;
+ else if (!strcmp (optarg, "bin") || !strcmp (optarg, "BIN"))
+ archive_format = arf_binary;
+ else if (!strcmp (optarg, "ustar") || !strcmp (optarg, "USTAR"))
+ archive_format = arf_ustar;
+ else if (!strcmp (optarg, "tar") || !strcmp (optarg, "TAR"))
+ archive_format = arf_tar;
+ else if (!strcmp (optarg, "hpodc") || !strcmp (optarg, "HPODC"))
+ archive_format = arf_hpoldascii;
+ else if (!strcmp (optarg, "hpbin") || !strcmp (optarg, "HPBIN"))
+ archive_format = arf_hpbinary;
+ else
+ error (2, 0, "\
+invalid archive format `%s'; valid formats are:\n\
+crc newc odc bin ustar tar (all-caps also recognized)", optarg);
+ break;
+
+ case 'i': /* Copy-in mode. */
+ if (copy_function != 0)
+ usage (stderr, 2);
+ copy_function = process_copy_in;
+ break;
+
+ case 'I': /* Input archive file name. */
+ input_archive_name = optarg;
+ break;
+
+ case 'k': /* Handle corrupted archives. We always handle
+ corrupted archives, but recognize this
+ option for compatability. */
+ break;
+
+ case 'l': /* Link files when possible. */
+ link_flag = TRUE;
+ break;
+
+ case 'L': /* Dereference symbolic links. */
+ xstat = stat;
+ break;
+
+ case 'm': /* Retain previous file modify times. */
+ retain_time_flag = TRUE;
+ break;
+
+ case 'M': /* New media message. */
+ set_new_media_message (optarg);
+ break;
+
+ case 'n': /* Long list owner and group as numbers. */
+ numeric_uid = TRUE;
+ break;
+
+ case 134: /* --no-preserve-owner */
+ if (set_owner_flag || set_group_flag)
+ usage (stderr, 2);
+ no_chown_flag = TRUE;
+ break;
+
+ case 'o': /* Copy-out mode. */
+ if (copy_function != 0)
+ usage (stderr, 2);
+ copy_function = process_copy_out;
+ break;
+
+ case 'O': /* Output archive file name. */
+ output_archive_name = optarg;
+ break;
+
+ case 'p': /* Copy-pass mode. */
+ if (copy_function != 0)
+ usage (stderr, 2);
+ copy_function = process_copy_pass;
+ break;
+
+ case 'r': /* Interactively rename. */
+ rename_flag = TRUE;
+ break;
+
+ case 'R': /* Set the owner. */
+ if (no_chown_flag)
+ usage (stderr, 2);
+#ifndef __MSDOS__
+ {
+ char *e, *u, *g;
+
+ e = parse_user_spec (optarg, &set_owner, &set_group, &u, &g);
+ if (e)
+ error (2, 0, "%s: %s", optarg, e);
+ if (u)
+ {
+ free (u);
+ set_owner_flag = TRUE;
+ }
+ if (g)
+ {
+ free (g);
+ set_group_flag = TRUE;
+ }
+ }
+#endif
+ break;
+
+ case 's': /* Swap bytes. */
+ swap_bytes_flag = TRUE;
+ break;
+
+ case 'S': /* Swap halfwords. */
+ swap_halfwords_flag = TRUE;
+ break;
+
+ case 't': /* Only print a list. */
+ table_flag = TRUE;
+ break;
+
+ case 'u': /* Replace all! Unconditionally! */
+ unconditional_flag = TRUE;
+ break;
+
+ case 'v': /* Verbose! */
+ verbose_flag = TRUE;
+ break;
+
+ case 'V': /* Print `.' for each file. */
+ dot_flag = TRUE;
+ break;
+
+ case 131:
+ printf ("GNU cpio %s", version_string);
+ exit (0);
+ break;
+
+ case 132: /* --help */
+ usage (stdout, 0);
+ break;
+
+ default:
+ usage (stderr, 2);
+ }
+ }
+
+ /* Do error checking and look at other args. */
+
+ if (copy_function == 0)
+ {
+ if (table_flag)
+ copy_function = process_copy_in;
+ else
+ usage (stderr, 2);
+ }
+
+ if ((!table_flag || !verbose_flag) && numeric_uid)
+ usage (stderr, 2);
+
+ /* Work around for pcc bug. */
+ copy_in = process_copy_in;
+ copy_out = process_copy_out;
+
+ if (copy_function == copy_in)
+ {
+ archive_des = 0;
+ if (link_flag || reset_time_flag || xstat != lstat || append_flag
+ || output_archive_name
+ || (archive_name && input_archive_name))
+ usage (stderr, 2);
+ if (archive_format == arf_crcascii)
+ crc_i_flag = TRUE;
+ num_patterns = argc - optind;
+ save_patterns = &argv[optind];
+ if (input_archive_name)
+ archive_name = input_archive_name;
+ }
+ else if (copy_function == copy_out)
+ {
+ archive_des = 1;
+ if (argc != optind || create_dir_flag || rename_flag
+ || table_flag || unconditional_flag || link_flag
+ || retain_time_flag || no_chown_flag || set_owner_flag
+ || set_group_flag || swap_bytes_flag || swap_halfwords_flag
+ || (append_flag && !(archive_name || output_archive_name))
+ || input_archive_name || (archive_name && output_archive_name))
+ usage (stderr, 2);
+ if (archive_format == arf_unknown)
+ archive_format = arf_binary;
+ if (output_archive_name)
+ archive_name = output_archive_name;
+ }
+ else
+ {
+ /* Copy pass. */
+ archive_des = -1;
+ if (argc - 1 != optind || archive_format != arf_unknown
+ || swap_bytes_flag || swap_halfwords_flag
+ || table_flag || rename_flag || append_flag)
+ usage (stderr, 2);
+ directory_name = argv[optind];
+ }
+
+ if (archive_name)
+ {
+ if (copy_function != copy_in && copy_function != copy_out)
+ usage (stderr, 2);
+ archive_des = open_archive (archive_name);
+ if (archive_des < 0)
+ error (1, errno, "%s", archive_name);
+ }
+
+#ifndef __MSDOS__
+ /* Prevent SysV non-root users from giving away files inadvertantly.
+ This happens automatically on BSD, where only root can give
+ away files. */
+ if (set_owner_flag == FALSE && set_group_flag == FALSE && geteuid ())
+ no_chown_flag = TRUE;
+#endif
+}
+
+/* Initialize the input and output buffers to their proper size and
+ initialize all variables associated with the input and output
+ buffers. */
+
+void
+initialize_buffers ()
+{
+ int buf_size;
+
+ /* Make sure buffers can always hold 2 blocks and that they
+ are big enough to hold 1 tar record (512 bytes) even if it
+ is not aligned on a block boundary. The extra buffer space
+ is needed by process_copyin and peek_in_buf to automatically
+ figure out what kind of archive it is reading. */
+
+ if (io_block_size >= 512)
+ buf_size = 2 * io_block_size;
+ else
+ buf_size = 1024;
+ input_buffer = (char *) xmalloc (buf_size);
+ in_buff = input_buffer;
+ input_size = 0;
+ input_bytes = 0;
+
+ /* Leave space for an `int' sentinel for `empty_output_buffer',
+ in case we ever put back sparseness checking. */
+ output_buffer = (char *) xmalloc (buf_size + sizeof (int) * 2);
+ out_buff = output_buffer;
+ output_size = 0;
+ output_bytes = 0;
+
+ /* Clear the block of zeros. */
+ bzero (zeros_512, 512);
+}
+
+void
+main (argc, argv)
+ int argc;
+ char *argv[];
+{
+ program_name = argv[0];
+ umask (0);
+
+#ifdef __FreeBSD__
+ (void) setlocale (LC_ALL, "");
+#endif
+#ifdef __TURBOC__
+ _fmode = O_BINARY; /* Put stdin and stdout in binary mode. */
+#endif
+#ifdef __EMX__ /* gcc on OS/2. */
+ _response (&argc, &argv);
+ _wildcard (&argc, &argv);
+#endif
+
+ process_args (argc, argv);
+
+ initialize_buffers ();
+
+ (*copy_function) ();
+
+ if (archive_des >= 0 && rmtclose (archive_des) == -1)
+ error (1, errno, "error closing archive");
+
+ exit (0);
+}
diff --git a/gnu/usr.bin/cpio/makepath.c b/gnu/usr.bin/cpio/makepath.c
new file mode 100644
index 0000000..b9c09d7
--- /dev/null
+++ b/gnu/usr.bin/cpio/makepath.c
@@ -0,0 +1,297 @@
+/* makepath.c -- Ensure that a directory path exists.
+ Copyright (C) 1990 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* Written by David MacKenzie <djm@gnu.ai.mit.edu> and
+ Jim Meyering <meyering@cs.utexas.edu>. */
+
+/* This copy of makepath is almost like the fileutils one, but has
+ changes for HPUX CDF's. Maybe the 2 versions of makepath can
+ come together again in the future. */
+
+#ifdef __GNUC__
+#define alloca __builtin_alloca
+#else
+#ifdef HAVE_ALLOCA_H
+#include <alloca.h>
+#else
+#ifdef _AIX
+ #pragma alloca
+#else
+char *alloca ();
+#endif
+#endif
+#endif
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#if !defined(S_ISDIR) && defined(S_IFDIR)
+#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
+#endif
+
+#ifdef STDC_HEADERS
+#include <errno.h>
+#include <stdlib.h>
+#else
+extern int errno;
+#endif
+
+#if defined(STDC_HEADERS) || defined(HAVE_STRING_H)
+#include <string.h>
+#define index strchr
+#else
+#include <strings.h>
+#endif
+
+#ifdef __MSDOS__
+typedef int uid_t;
+typedef int gid_t;
+#endif
+
+void error ();
+
+/* Ensure that the directory ARGPATH exists.
+ Remove any trailing slashes from ARGPATH before calling this function.
+
+ Make any leading directories that don't already exist, with
+ permissions PARENT_MODE.
+ If the last element of ARGPATH does not exist, create it as
+ a new directory with permissions MODE.
+ If OWNER and GROUP are non-negative, make them the UID and GID of
+ created directories.
+ If VERBOSE_FMT_STRING is nonzero, use it as a printf format
+ string for printing a message after successfully making a directory,
+ with the name of the directory that was just made as an argument.
+
+ Return 0 if ARGPATH exists as a directory with the proper
+ ownership and permissions when done, otherwise 1. */
+
+int
+make_path (argpath, mode, parent_mode, owner, group, verbose_fmt_string)
+ char *argpath;
+ int mode;
+ int parent_mode;
+ uid_t owner;
+ gid_t group;
+ char *verbose_fmt_string;
+{
+ char *dirpath; /* A copy we can scribble NULs on. */
+ struct stat stats;
+ int retval = 0;
+ int oldmask = umask (0);
+ dirpath = alloca (strlen (argpath) + 1);
+ strcpy (dirpath, argpath);
+
+ if (stat (dirpath, &stats))
+ {
+ char *slash;
+ int tmp_mode; /* Initial perms for leading dirs. */
+ int re_protect; /* Should leading dirs be unwritable? */
+ struct ptr_list
+ {
+ char *dirname_end;
+ struct ptr_list *next;
+ };
+ struct ptr_list *p, *leading_dirs = NULL;
+
+ /* If leading directories shouldn't be writable or executable,
+ or should have set[ug]id or sticky bits set and we are setting
+ their owners, we need to fix their permissions after making them. */
+ if (((parent_mode & 0300) != 0300)
+ || (owner != (uid_t) -1 && group != (gid_t) -1
+ && (parent_mode & 07000) != 0))
+ {
+ tmp_mode = 0700;
+ re_protect = 1;
+ }
+ else
+ {
+ tmp_mode = parent_mode;
+ re_protect = 0;
+ }
+
+ slash = dirpath;
+ while (*slash == '/')
+ slash++;
+ while ((slash = index (slash, '/')))
+ {
+#ifdef HPUX_CDF
+ int iscdf;
+ iscdf = 0;
+#endif
+ *slash = '\0';
+ if (stat (dirpath, &stats))
+ {
+#ifdef HPUX_CDF
+ /* If this component of the pathname ends in `+' and is
+ followed by 2 `/'s, then this is a CDF. We remove the
+ `+' from the name and create the directory. Later
+ we will "hide" the directory. */
+ if ( (*(slash +1) == '/') && (*(slash -1) == '+') )
+ {
+ iscdf = 1;
+ *(slash -1) = '\0';
+ }
+#endif
+ if (mkdir (dirpath, tmp_mode))
+ {
+ error (0, errno, "cannot make directory `%s'", dirpath);
+ umask (oldmask);
+ return 1;
+ }
+ else
+ {
+ if (verbose_fmt_string != NULL)
+ error (0, 0, verbose_fmt_string, dirpath);
+
+ if (owner != (uid_t) -1 && group != (gid_t) -1
+ && chown (dirpath, owner, group)
+#ifdef AFS
+ && errno != EPERM
+#endif
+ )
+ {
+ error (0, errno, "%s", dirpath);
+ retval = 1;
+ }
+ if (re_protect)
+ {
+ struct ptr_list *new = (struct ptr_list *)
+ alloca (sizeof (struct ptr_list));
+ new->dirname_end = slash;
+ new->next = leading_dirs;
+ leading_dirs = new;
+ }
+#ifdef HPUX_CDF
+ if (iscdf)
+ {
+ /* If this is a CDF, "hide" the directory by setting
+ its hidden/setuid bit. Also add the `+' back to
+ its name (since once it's "hidden" we must refer
+ to as `name+' instead of `name'). */
+ chmod (dirpath, 04700);
+ *(slash - 1) = '+';
+ }
+#endif
+ }
+ }
+ else if (!S_ISDIR (stats.st_mode))
+ {
+ error (0, 0, "`%s' exists but is not a directory", dirpath);
+ umask (oldmask);
+ return 1;
+ }
+
+ *slash++ = '/';
+
+ /* Avoid unnecessary calls to `stat' when given
+ pathnames containing multiple adjacent slashes. */
+ while (*slash == '/')
+ slash++;
+ }
+
+ /* We're done making leading directories.
+ Make the final component of the path. */
+
+ if (mkdir (dirpath, mode))
+ {
+ error (0, errno, "cannot make directory `%s'", dirpath);
+ umask (oldmask);
+ return 1;
+ }
+ if (verbose_fmt_string != NULL)
+ error (0, 0, verbose_fmt_string, dirpath);
+
+ if (owner != (uid_t) -1 && group != (gid_t) -1)
+ {
+ if (chown (dirpath, owner, group)
+#ifdef AFS
+ && errno != EPERM
+#endif
+ )
+ {
+ error (0, errno, "%s", dirpath);
+ retval = 1;
+ }
+ }
+ /* chown may have turned off some permission bits we wanted. */
+ if ((mode & 07000) != 0 && chmod (dirpath, mode))
+ {
+ error (0, errno, "%s", dirpath);
+ retval = 1;
+ }
+
+ /* If the mode for leading directories didn't include owner "wx"
+ privileges, we have to reset their protections to the correct
+ value. */
+ for (p = leading_dirs; p != NULL; p = p->next)
+ {
+ *(p->dirname_end) = '\0';
+#if 0
+ /* cpio always calls make_path with parent mode 0700, so
+ we don't have to do this. If we ever do have to do this,
+ we have to stat the directory first to get the setuid
+ bit so we don't break HP CDF's. */
+ if (chmod (dirpath, parent_mode))
+ {
+ error (0, errno, "%s", dirpath);
+ retval = 1;
+ }
+#endif
+
+ }
+ }
+ else
+ {
+ /* We get here if the entire path already exists. */
+
+ if (!S_ISDIR (stats.st_mode))
+ {
+ error (0, 0, "`%s' exists but is not a directory", dirpath);
+ umask (oldmask);
+ return 1;
+ }
+
+ /* chown must precede chmod because on some systems,
+ chown clears the set[ug]id bits for non-superusers,
+ resulting in incorrect permissions.
+ On System V, users can give away files with chown and then not
+ be able to chmod them. So don't give files away. */
+
+ if (owner != (uid_t) -1 && group != (gid_t) -1
+ && chown (dirpath, owner, group)
+#ifdef AFS
+ && errno != EPERM
+#endif
+ )
+ {
+ error (0, errno, "%s", dirpath);
+ retval = 1;
+ }
+ if (chmod (dirpath, mode))
+ {
+ error (0, errno, "%s", dirpath);
+ retval = 1;
+ }
+ }
+
+ umask (oldmask);
+ return retval;
+}
diff --git a/gnu/usr.bin/cpio/rmt.h b/gnu/usr.bin/cpio/rmt.h
new file mode 100644
index 0000000..2155223
--- /dev/null
+++ b/gnu/usr.bin/cpio/rmt.h
@@ -0,0 +1,98 @@
+/* Definitions for communicating with a remote tape drive.
+ Copyright (C) 1988, 1992 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#if !defined(_POSIX_VERSION)
+#ifdef __MSDOS__
+#include <io.h>
+#else /* !__MSDOS__ */
+extern off_t lseek ();
+#endif /* __MSDOS__ */
+#endif /* _POSIX_VERSION */
+
+#ifdef NO_REMOTE
+#define _isrmt(f) 0
+#define rmtopen open
+#define rmtaccess access
+#define rmtstat stat
+#define rmtcreat creat
+#define rmtlstat lstat
+#define rmtread read
+#define rmtwrite write
+#define rmtlseek lseek
+#define rmtclose close
+#define rmtioctl ioctl
+#define rmtdup dup
+#define rmtfstat fstat
+#define rmtfcntl fcntl
+#define rmtisatty isatty
+
+#else /* !NO_REMOTE */
+
+#define __REM_BIAS 128
+#define RMTIOCTL
+
+#ifndef O_CREAT
+#define O_CREAT 01000
+#endif
+
+extern char *__rmt_path;
+
+#if defined(STDC_HEADERS) || defined(HAVE_STRING_H)
+#include <string.h>
+#ifndef index
+#define index strchr
+#endif
+#else
+extern char *index ();
+#endif
+
+#define _remdev(path) (!f_force_local && (__rmt_path=index(path, ':')))
+#define _isrmt(fd) ((fd) >= __REM_BIAS)
+
+#define rmtopen(path,oflag,mode) (_remdev(path) ? __rmt_open(path, oflag, mode, __REM_BIAS) : open(path, oflag, mode))
+#define rmtaccess(path, amode) (_remdev(path) ? 0 : access(path, amode))
+#define rmtstat(path, buf) (_remdev(path) ? (errno = EOPNOTSUPP), -1 : stat(path, buf))
+#define rmtcreat(path, mode) (_remdev(path) ? __rmt_open (path, 1 | O_CREAT, mode, __REM_BIAS) : creat(path, mode))
+#define rmtlstat(path,buf) (_remdev(path) ? (errno = EOPNOTSUPP), -1 : lstat(path,buf))
+
+#define rmtread(fd, buf, n) (_isrmt(fd) ? __rmt_read(fd - __REM_BIAS, buf, n) : read(fd, buf, n))
+#define rmtwrite(fd, buf, n) (_isrmt(fd) ? __rmt_write(fd - __REM_BIAS, buf, n) : write(fd, buf, n))
+#define rmtlseek(fd, off, wh) (_isrmt(fd) ? __rmt_lseek(fd - __REM_BIAS, off, wh) : lseek(fd, off, wh))
+#define rmtclose(fd) (_isrmt(fd) ? __rmt_close(fd - __REM_BIAS) : close(fd))
+#ifdef RMTIOCTL
+#define rmtioctl(fd,req,arg) (_isrmt(fd) ? __rmt_ioctl(fd - __REM_BIAS, req, arg) : ioctl(fd, req, arg))
+#else
+#define rmtioctl(fd,req,arg) (_isrmt(fd) ? (errno = EOPNOTSUPP), -1 : ioctl(fd, req, arg))
+#endif
+#define rmtdup(fd) (_isrmt(fd) ? (errno = EOPNOTSUPP), -1 : dup(fd))
+#define rmtfstat(fd, buf) (_isrmt(fd) ? (errno = EOPNOTSUPP), -1 : fstat(fd, buf))
+#define rmtfcntl(fd,cmd,arg) (_isrmt(fd) ? (errno = EOPNOTSUPP), -1 : fcntl (fd, cmd, arg))
+#define rmtisatty(fd) (_isrmt(fd) ? 0 : isatty(fd))
+
+#undef RMTIOCTL
+
+int __rmt_open ();
+int __rmt_close ();
+int __rmt_read ();
+int __rmt_write ();
+long __rmt_lseek ();
+int __rmt_ioctl ();
+#endif /* !NO_REMOTE */
diff --git a/gnu/usr.bin/cpio/rtapelib.c b/gnu/usr.bin/cpio/rtapelib.c
new file mode 100644
index 0000000..eece76f
--- /dev/null
+++ b/gnu/usr.bin/cpio/rtapelib.c
@@ -0,0 +1,582 @@
+/* Functions for communicating with a remote tape drive.
+ Copyright (C) 1988, 1992 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* The man page rmt(8) for /etc/rmt documents the remote mag tape
+ protocol which rdump and rrestore use. Unfortunately, the man
+ page is *WRONG*. The author of the routines I'm including originally
+ wrote his code just based on the man page, and it didn't work, so he
+ went to the rdump source to figure out why. The only thing he had to
+ change was to check for the 'F' return code in addition to the 'E',
+ and to separate the various arguments with \n instead of a space. I
+ personally don't think that this is much of a problem, but I wanted to
+ point it out. -- Arnold Robbins
+
+ Originally written by Jeff Lee, modified some by Arnold Robbins.
+ Redone as a library that can replace open, read, write, etc., by
+ Fred Fish, with some additional work by Arnold Robbins.
+ Modified to make all rmtXXX calls into macros for speed by Jay Fenlason.
+ Use -DHAVE_NETDB_H for rexec code, courtesy of Dan Kegel, srs!dan. */
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <signal.h>
+
+#ifdef HAVE_SYS_MTIO_H
+#include <sys/ioctl.h>
+#include <sys/mtio.h>
+#endif
+
+#ifdef HAVE_NETDB_H
+#include <netdb.h>
+#endif
+
+#include <errno.h>
+#include <setjmp.h>
+#include <sys/stat.h>
+
+#ifndef errno
+extern int errno;
+#endif
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#ifdef STDC_HEADERS
+#include <string.h>
+#include <stdlib.h>
+#endif
+
+/* Maximum size of a fully qualified host name. */
+#define MAXHOSTLEN 257
+
+/* Size of buffers for reading and writing commands to rmt.
+ (An arbitrary limit.) */
+#define CMDBUFSIZE 64
+
+#ifndef RETSIGTYPE
+#define RETSIGTYPE void
+#endif
+
+/* Maximum number of simultaneous remote tape connections.
+ (Another arbitrary limit.) */
+#define MAXUNIT 4
+
+/* Return the parent's read side of remote tape connection FILDES. */
+#define READ(fildes) (from_rmt[fildes][0])
+
+/* Return the parent's write side of remote tape connection FILDES. */
+#define WRITE(fildes) (to_rmt[fildes][1])
+
+/* The pipes for receiving data from remote tape drives. */
+static int from_rmt[MAXUNIT][2] =
+{-1, -1, -1, -1, -1, -1, -1, -1};
+
+/* The pipes for sending data to remote tape drives. */
+static int to_rmt[MAXUNIT][2] =
+{-1, -1, -1, -1, -1, -1, -1, -1};
+
+/* Temporary variable used by macros in rmt.h. */
+char *__rmt_path;
+
+/* Close remote tape connection FILDES. */
+
+static void
+_rmt_shutdown (fildes)
+ int fildes;
+{
+ close (READ (fildes));
+ close (WRITE (fildes));
+ READ (fildes) = -1;
+ WRITE (fildes) = -1;
+}
+
+/* Attempt to perform the remote tape command specified in BUF
+ on remote tape connection FILDES.
+ Return 0 if successful, -1 on error. */
+
+static int
+command (fildes, buf)
+ int fildes;
+ char *buf;
+{
+ register int buflen;
+ RETSIGTYPE (*pipe_handler) ();
+
+ /* Save the current pipe handler and try to make the request. */
+
+ pipe_handler = signal (SIGPIPE, SIG_IGN);
+ buflen = strlen (buf);
+ if (write (WRITE (fildes), buf, buflen) == buflen)
+ {
+ signal (SIGPIPE, pipe_handler);
+ return 0;
+ }
+
+ /* Something went wrong. Close down and go home. */
+
+ signal (SIGPIPE, pipe_handler);
+ _rmt_shutdown (fildes);
+ errno = EIO;
+ return -1;
+}
+
+/* Read and return the status from remote tape connection FILDES.
+ If an error occurred, return -1 and set errno. */
+
+static int
+status (fildes)
+ int fildes;
+{
+ int i;
+ char c, *cp;
+ char buffer[CMDBUFSIZE];
+
+ /* Read the reply command line. */
+
+ for (i = 0, cp = buffer; i < CMDBUFSIZE; i++, cp++)
+ {
+ if (read (READ (fildes), cp, 1) != 1)
+ {
+ _rmt_shutdown (fildes);
+ errno = EIO;
+ return -1;
+ }
+ if (*cp == '\n')
+ {
+ *cp = '\0';
+ break;
+ }
+ }
+
+ if (i == CMDBUFSIZE)
+ {
+ _rmt_shutdown (fildes);
+ errno = EIO;
+ return -1;
+ }
+
+ /* Check the return status. */
+
+ for (cp = buffer; *cp; cp++)
+ if (*cp != ' ')
+ break;
+
+ if (*cp == 'E' || *cp == 'F')
+ {
+ errno = atoi (cp + 1);
+ /* Skip the error message line. */
+ while (read (READ (fildes), &c, 1) == 1)
+ if (c == '\n')
+ break;
+
+ if (*cp == 'F')
+ _rmt_shutdown (fildes);
+
+ return -1;
+ }
+
+ /* Check for mis-synced pipes. */
+
+ if (*cp != 'A')
+ {
+ _rmt_shutdown (fildes);
+ errno = EIO;
+ return -1;
+ }
+
+ /* Got an `A' (success) response. */
+ return atoi (cp + 1);
+}
+
+#ifdef HAVE_NETDB_H
+/* Execute /etc/rmt as user USER on remote system HOST using rexec.
+ Return a file descriptor of a bidirectional socket for stdin and stdout.
+ If USER is NULL, or an empty string, use the current username.
+
+ By default, this code is not used, since it requires that
+ the user have a .netrc file in his/her home directory, or that the
+ application designer be willing to have rexec prompt for login and
+ password info. This may be unacceptable, and .rhosts files for use
+ with rsh are much more common on BSD systems. */
+
+static int
+_rmt_rexec (host, user)
+ char *host;
+ char *user;
+{
+ struct servent *rexecserv;
+ int save_stdin = dup (fileno (stdin));
+ int save_stdout = dup (fileno (stdout));
+ int tape_fd; /* Return value. */
+
+ /* When using cpio -o < filename, stdin is no longer the tty.
+ But the rexec subroutine reads the login and the passwd on stdin,
+ to allow remote execution of the command.
+ So, reopen stdin and stdout on /dev/tty before the rexec and
+ give them back their original value after. */
+ if (freopen ("/dev/tty", "r", stdin) == NULL)
+ freopen ("/dev/null", "r", stdin);
+ if (freopen ("/dev/tty", "w", stdout) == NULL)
+ freopen ("/dev/null", "w", stdout);
+
+ rexecserv = getservbyname ("exec", "tcp");
+ if (NULL == rexecserv)
+ {
+ fprintf (stderr, "exec/tcp: service not available");
+ exit (1);
+ }
+ if (user != NULL && *user == '\0')
+ user = NULL;
+ tape_fd = rexec (&host, rexecserv->s_port, user, NULL,
+ "/etc/rmt", (int *) NULL);
+ fclose (stdin);
+ fdopen (save_stdin, "r");
+ fclose (stdout);
+ fdopen (save_stdout, "w");
+
+ return tape_fd;
+}
+
+#endif /* HAVE_NETDB_H */
+
+/* Open a magtape device on the system specified in PATH, as the given user.
+ PATH has the form `[user@]system:/dev/????'.
+ If COMPAT is defined, it can also have the form `system[.user]:/dev/????'.
+
+ OFLAG is O_RDONLY, O_WRONLY, etc.
+ MODE is ignored; 0666 is always used.
+
+ If successful, return the remote tape pipe number plus BIAS.
+ On error, return -1. */
+
+int
+__rmt_open (path, oflag, mode, bias)
+ char *path;
+ int oflag;
+ int mode;
+ int bias;
+{
+ int i, rc;
+ char buffer[CMDBUFSIZE]; /* Command buffer. */
+ char system[MAXHOSTLEN]; /* The remote host name. */
+ char device[CMDBUFSIZE]; /* The remote device name. */
+ char login[CMDBUFSIZE]; /* The remote user name. */
+ char *sys, *dev, *user; /* For copying into the above buffers. */
+
+ sys = system;
+ dev = device;
+ user = login;
+
+ /* Find an unused pair of file descriptors. */
+
+ for (i = 0; i < MAXUNIT; i++)
+ if (READ (i) == -1 && WRITE (i) == -1)
+ break;
+
+ if (i == MAXUNIT)
+ {
+ errno = EMFILE;
+ return -1;
+ }
+
+ /* Pull apart the system and device, and optional user.
+ Don't munge the original string. */
+
+ while (*path != '@'
+#ifdef COMPAT
+ && *path != '.'
+#endif
+ && *path != ':')
+ {
+ *sys++ = *path++;
+ }
+ *sys = '\0';
+ path++;
+
+ if (*(path - 1) == '@')
+ {
+ /* Saw user part of user@host. Start over. */
+ strcpy (user, system);
+ sys = system;
+ while (*path != ':')
+ {
+ *sys++ = *path++;
+ }
+ *sys = '\0';
+ path++;
+ }
+#ifdef COMPAT
+ else if (*(path - 1) == '.')
+ {
+ while (*path != ':')
+ {
+ *user++ = *path++;
+ }
+ *user = '\0';
+ path++;
+ }
+#endif
+ else
+ *user = '\0';
+
+ while (*path)
+ {
+ *dev++ = *path++;
+ }
+ *dev = '\0';
+
+#ifdef HAVE_NETDB_H
+ /* Execute the remote command using rexec. */
+ READ (i) = WRITE (i) = _rmt_rexec (system, login);
+ if (READ (i) < 0)
+ return -1;
+#else /* !HAVE_NETDB_H */
+ /* Set up the pipes for the `rsh' command, and fork. */
+
+ if (pipe (to_rmt[i]) == -1 || pipe (from_rmt[i]) == -1)
+ return -1;
+
+ rc = fork ();
+ if (rc == -1)
+ return -1;
+
+ if (rc == 0)
+ {
+ /* Child. */
+ close (0);
+ dup (to_rmt[i][0]);
+ close (to_rmt[i][0]);
+ close (to_rmt[i][1]);
+
+ close (1);
+ dup (from_rmt[i][1]);
+ close (from_rmt[i][0]);
+ close (from_rmt[i][1]);
+
+ setuid (getuid ());
+ setgid (getgid ());
+
+ if (*login)
+ {
+ execl ("/usr/ucb/rsh", "rsh", system, "-l", login,
+ "/etc/rmt", (char *) 0);
+ execl ("/usr/bin/remsh", "remsh", system, "-l", login,
+ "/etc/rmt", (char *) 0);
+ execl ("/usr/bin/rsh", "rsh", system, "-l", login,
+ "/etc/rmt", (char *) 0);
+ execl ("/usr/bsd/rsh", "rsh", system, "-l", login,
+ "/etc/rmt", (char *) 0);
+ execl ("/usr/bin/nsh", "nsh", system, "-l", login,
+ "/etc/rmt", (char *) 0);
+ }
+ else
+ {
+ execl ("/usr/ucb/rsh", "rsh", system,
+ "/etc/rmt", (char *) 0);
+ execl ("/usr/bin/remsh", "remsh", system,
+ "/etc/rmt", (char *) 0);
+ execl ("/usr/bin/rsh", "rsh", system,
+ "/etc/rmt", (char *) 0);
+ execl ("/usr/bsd/rsh", "rsh", system,
+ "/etc/rmt", (char *) 0);
+ execl ("/usr/bin/nsh", "nsh", system,
+ "/etc/rmt", (char *) 0);
+ }
+
+ /* Bad problems if we get here. */
+
+ perror ("cannot execute remote shell");
+ _exit (1);
+ }
+
+ /* Parent. */
+ close (to_rmt[i][0]);
+ close (from_rmt[i][1]);
+#endif /* !HAVE_NETDB_H */
+
+ /* Attempt to open the tape device. */
+
+ sprintf (buffer, "O%s\n%d\n", device, oflag);
+ if (command (i, buffer) == -1 || status (i) == -1)
+ return -1;
+
+ return i + bias;
+}
+
+/* Close remote tape connection FILDES and shut down.
+ Return 0 if successful, -1 on error. */
+
+int
+__rmt_close (fildes)
+ int fildes;
+{
+ int rc;
+
+ if (command (fildes, "C\n") == -1)
+ return -1;
+
+ rc = status (fildes);
+ _rmt_shutdown (fildes);
+ return rc;
+}
+
+/* Read up to NBYTE bytes into BUF from remote tape connection FILDES.
+ Return the number of bytes read on success, -1 on error. */
+
+int
+__rmt_read (fildes, buf, nbyte)
+ int fildes;
+ char *buf;
+ unsigned int nbyte;
+{
+ int rc, i;
+ char buffer[CMDBUFSIZE];
+
+ sprintf (buffer, "R%d\n", nbyte);
+ if (command (fildes, buffer) == -1 || (rc = status (fildes)) == -1)
+ return -1;
+
+ for (i = 0; i < rc; i += nbyte, buf += nbyte)
+ {
+ nbyte = read (READ (fildes), buf, rc - i);
+ if (nbyte <= 0)
+ {
+ _rmt_shutdown (fildes);
+ errno = EIO;
+ return -1;
+ }
+ }
+
+ return rc;
+}
+
+/* Write NBYTE bytes from BUF to remote tape connection FILDES.
+ Return the number of bytes written on success, -1 on error. */
+
+int
+__rmt_write (fildes, buf, nbyte)
+ int fildes;
+ char *buf;
+ unsigned int nbyte;
+{
+ char buffer[CMDBUFSIZE];
+ RETSIGTYPE (*pipe_handler) ();
+
+ sprintf (buffer, "W%d\n", nbyte);
+ if (command (fildes, buffer) == -1)
+ return -1;
+
+ pipe_handler = signal (SIGPIPE, SIG_IGN);
+ if (write (WRITE (fildes), buf, nbyte) == nbyte)
+ {
+ signal (SIGPIPE, pipe_handler);
+ return status (fildes);
+ }
+
+ /* Write error. */
+ signal (SIGPIPE, pipe_handler);
+ _rmt_shutdown (fildes);
+ errno = EIO;
+ return -1;
+}
+
+/* Perform an imitation lseek operation on remote tape connection FILDES.
+ Return the new file offset if successful, -1 if on error. */
+
+long
+__rmt_lseek (fildes, offset, whence)
+ int fildes;
+ long offset;
+ int whence;
+{
+ char buffer[CMDBUFSIZE];
+
+ sprintf (buffer, "L%ld\n%d\n", offset, whence);
+ if (command (fildes, buffer) == -1)
+ return -1;
+
+ return status (fildes);
+}
+
+/* Perform a raw tape operation on remote tape connection FILDES.
+ Return the results of the ioctl, or -1 on error. */
+
+#ifdef MTIOCTOP
+int
+__rmt_ioctl (fildes, op, arg)
+ int fildes, op;
+ char *arg;
+{
+ char c;
+ int rc, cnt;
+ char buffer[CMDBUFSIZE];
+
+ switch (op)
+ {
+ default:
+ errno = EINVAL;
+ return -1;
+
+ case MTIOCTOP:
+ /* MTIOCTOP is the easy one. Nothing is transfered in binary. */
+ sprintf (buffer, "I%d\n%d\n", ((struct mtop *) arg)->mt_op,
+ ((struct mtop *) arg)->mt_count);
+ if (command (fildes, buffer) == -1)
+ return -1;
+ return status (fildes); /* Return the count. */
+
+ case MTIOCGET:
+ /* Grab the status and read it directly into the structure.
+ This assumes that the status buffer is not padded
+ and that 2 shorts fit in a long without any word
+ alignment problems; i.e., the whole struct is contiguous.
+ NOTE - this is probably NOT a good assumption. */
+
+ if (command (fildes, "S") == -1 || (rc = status (fildes)) == -1)
+ return -1;
+
+ for (; rc > 0; rc -= cnt, arg += cnt)
+ {
+ cnt = read (READ (fildes), arg, rc);
+ if (cnt <= 0)
+ {
+ _rmt_shutdown (fildes);
+ errno = EIO;
+ return -1;
+ }
+ }
+
+ /* Check for byte position. mt_type is a small integer field
+ (normally) so we will check its magnitude. If it is larger than
+ 256, we will assume that the bytes are swapped and go through
+ and reverse all the bytes. */
+
+ if (((struct mtget *) arg)->mt_type < 256)
+ return 0;
+
+ for (cnt = 0; cnt < rc; cnt += 2)
+ {
+ c = arg[cnt];
+ arg[cnt] = arg[cnt + 1];
+ arg[cnt + 1] = c;
+ }
+
+ return 0;
+ }
+}
+
+#endif
diff --git a/gnu/usr.bin/cpio/stripslash.c b/gnu/usr.bin/cpio/stripslash.c
new file mode 100644
index 0000000..2971d4c
--- /dev/null
+++ b/gnu/usr.bin/cpio/stripslash.c
@@ -0,0 +1,39 @@
+/* stripslash.c -- remove trailing slashes from a string
+ Copyright (C) 1990 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#if defined(STDC_HEADERS) || defined(HAVE_STRING_H)
+#include <string.h>
+#else
+#include <strings.h>
+#endif
+
+/* Remove trailing slashes from PATH.
+ This is useful when using filename completion from a shell that
+ adds a "/" after directory names (such as tcsh and bash), because
+ the Unix rename and rmdir system calls return an "Invalid argument" error
+ when given a path that ends in "/" (except for the root directory). */
+
+void
+strip_trailing_slashes (path)
+ char *path;
+{
+ int last;
+
+ last = strlen (path) - 1;
+ while (last > 0 && path[last] == '/')
+ path[last--] = '\0';
+}
diff --git a/gnu/usr.bin/cpio/system.h b/gnu/usr.bin/cpio/system.h
new file mode 100644
index 0000000..abe732d
--- /dev/null
+++ b/gnu/usr.bin/cpio/system.h
@@ -0,0 +1,139 @@
+/* System dependent declarations. Requires sys/types.h.
+ Copyright (C) 1992 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#if defined(STDC_HEADERS) || defined(HAVE_STRING_H)
+#include <string.h>
+#ifndef index
+#define index strchr
+#endif
+#ifndef rindex
+#define rindex strrchr
+#endif
+#ifndef bcmp
+#define bcmp(s1, s2, n) memcmp ((s1), (s2), (n))
+#endif
+#ifndef bzero
+#define bzero(s, n) memset ((s), 0, (n))
+#endif
+#else
+#include <strings.h>
+#endif
+
+#include <time.h>
+
+#ifdef STDC_HEADERS
+#include <stdlib.h>
+#endif
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#ifndef SEEK_SET
+#define SEEK_SET 0
+#define SEEK_CUR 1
+#define SEEK_END 2
+#endif
+
+#ifndef _POSIX_VERSION
+off_t lseek ();
+#endif
+
+/* Since major is a function on SVR4, we can't use `ifndef major'. */
+#ifdef MAJOR_IN_MKDEV
+#include <sys/mkdev.h>
+#define HAVE_MAJOR
+#endif
+
+#ifdef MAJOR_IN_SYSMACROS
+#include <sys/sysmacros.h>
+#define HAVE_MAJOR
+#endif
+
+#ifdef major /* Might be defined in sys/types.h. */
+#define HAVE_MAJOR
+#endif
+
+#ifndef HAVE_MAJOR
+#define major(dev) (((dev) >> 8) & 0xff)
+#define minor(dev) ((dev) & 0xff)
+#define makedev(ma, mi) (((ma) << 8) | (mi))
+#endif
+#undef HAVE_MAJOR
+
+#if defined(__MSDOS__) || defined(_POSIX_VERSION) || defined(HAVE_FCNTL_H)
+#include <fcntl.h>
+#else
+#include <sys/file.h>
+#endif
+#ifndef O_BINARY
+#define O_BINARY 0
+#endif
+
+#include <errno.h>
+#ifndef errno
+extern int errno;
+#endif
+#ifdef __EMX__ /* gcc on OS/2. */
+#define EPERM EACCES
+#define ENXIO EIO
+#endif
+
+#ifdef HAVE_UTIME_H
+#include <utime.h>
+#else
+struct utimbuf
+{
+ time_t actime;
+ time_t modtime;
+};
+#endif
+
+#ifdef TRUE
+#undef TRUE
+#endif
+#define TRUE 1
+#ifdef FALSE
+#undef FALSE
+#endif
+#define FALSE 0
+
+#ifndef __MSDOS__
+#define CONSOLE "/dev/tty"
+#else
+#define CONSOLE "con"
+#endif
+
+#ifdef __MSDOS__
+typedef int uid_t;
+typedef int gid_t;
+#endif
+
+/* On most systems symlink() always creates links with rwxrwxrwx
+ protection modes, but on some (HP/UX 8.07; I think maybe DEC's OSF
+ on MIPS too) symlink() uses the value of umask, so links' protection modes
+ aren't always rwxrwxrwx. There doesn't seem to be any way to change
+ the modes of a link (no system call like, say, lchmod() ), it seems
+ the only way to set the modes right is to set umask before calling
+ symlink(). */
+
+#ifndef SYMLINK_USES_UMASK
+#define UMASKED_SYMLINK(name1,name2,mode) symlink(name1,name2)
+#else
+#define UMASKED_SYMLINK(name1,name2,mode) umasked_symlink(name1,name2,mode)
+#endif /* SYMLINK_USES_UMASK */
+
diff --git a/gnu/usr.bin/cpio/tar.c b/gnu/usr.bin/cpio/tar.c
new file mode 100644
index 0000000..84cb0ad
--- /dev/null
+++ b/gnu/usr.bin/cpio/tar.c
@@ -0,0 +1,522 @@
+/* tar.c - read in write tar headers for cpio
+ Copyright (C) 1992 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include "filetypes.h"
+#include "system.h"
+#include "cpiohdr.h"
+#include "dstring.h"
+#include "extern.h"
+#include "rmt.h"
+#include "tarhdr.h"
+
+static void to_oct ();
+static char *stash_tar_linkname ();
+static char *stash_tar_filename ();
+
+/* Compute and return a checksum for TAR_HDR,
+ counting the checksum bytes as if they were spaces. */
+
+unsigned long
+tar_checksum (tar_hdr)
+ struct tar_header *tar_hdr;
+{
+ unsigned long sum = 0;
+ char *p = (char *) tar_hdr;
+ char *q = p + TARRECORDSIZE;
+ int i;
+
+ while (p < tar_hdr->chksum)
+ sum += *p++ & 0xff;
+ for (i = 0; i < 8; ++i)
+ {
+ sum += ' ';
+ ++p;
+ }
+ while (p < q)
+ sum += *p++ & 0xff;
+ return sum;
+}
+
+/* Write out header FILE_HDR, including the file name, to file
+ descriptor OUT_DES. */
+
+void
+write_out_tar_header (file_hdr, out_des)
+ struct new_cpio_header *file_hdr;
+ int out_des;
+{
+ int name_len;
+ union tar_record tar_rec;
+ struct tar_header *tar_hdr = (struct tar_header *) &tar_rec;
+
+ bzero ((char *) &tar_rec, TARRECORDSIZE);
+
+ /* process_copy_out must ensure that file_hdr->c_name is short enough,
+ or we will lose here. */
+
+ name_len = strlen (file_hdr->c_name);
+ if (name_len <= TARNAMESIZE)
+ {
+ strncpy (tar_hdr->name, file_hdr->c_name, name_len);
+ }
+ else
+ {
+ /* Fit as much as we can into `name', the rest into `prefix'. */
+ char *suffix = file_hdr->c_name + name_len - TARNAMESIZE;
+
+ /* We have to put the boundary at a slash. */
+ name_len = TARNAMESIZE;
+ while (*suffix != '/')
+ {
+ --name_len;
+ ++suffix;
+ }
+ strncpy (tar_hdr->name, suffix + 1, name_len);
+ strncpy (tar_hdr->prefix, file_hdr->c_name, suffix - file_hdr->c_name);
+ }
+
+ /* SVR4 seems to want the whole mode, not just protection modes.
+ Nobody else seems to care, so we might as well put it all in. */
+ to_oct (file_hdr->c_mode, 8, tar_hdr->mode);
+ to_oct (file_hdr->c_uid, 8, tar_hdr->uid);
+ to_oct (file_hdr->c_gid, 8, tar_hdr->gid);
+ to_oct (file_hdr->c_filesize, 12, tar_hdr->size);
+ to_oct (file_hdr->c_mtime, 12, tar_hdr->mtime);
+
+ switch (file_hdr->c_mode & CP_IFMT)
+ {
+ case CP_IFREG:
+ if (file_hdr->c_tar_linkname)
+ {
+ /* process_copy_out makes sure that c_tar_linkname is shorter
+ than TARLINKNAMESIZE. */
+ strncpy (tar_hdr->linkname, file_hdr->c_tar_linkname,
+ TARLINKNAMESIZE);
+ tar_hdr->typeflag = LNKTYPE;
+ to_oct (0, 12, tar_hdr->size);
+ }
+ else
+ tar_hdr->typeflag = REGTYPE;
+ break;
+ case CP_IFDIR:
+ tar_hdr->typeflag = DIRTYPE;
+ break;
+#ifndef __MSDOS__
+ case CP_IFCHR:
+ tar_hdr->typeflag = CHRTYPE;
+ break;
+ case CP_IFBLK:
+ tar_hdr->typeflag = BLKTYPE;
+ break;
+#ifdef CP_IFIFO
+ case CP_IFIFO:
+ tar_hdr->typeflag = FIFOTYPE;
+ break;
+#endif /* CP_IFIFO */
+#ifdef CP_IFLNK
+ case CP_IFLNK:
+ tar_hdr->typeflag = SYMTYPE;
+ /* process_copy_out makes sure that c_tar_linkname is shorter
+ than TARLINKNAMESIZE. */
+ strncpy (tar_hdr->linkname, file_hdr->c_tar_linkname,
+ TARLINKNAMESIZE);
+ to_oct (0, 12, tar_hdr->size);
+ break;
+#endif /* CP_IFLNK */
+#endif /* !__MSDOS__ */
+ }
+
+ if (archive_format == arf_ustar)
+ {
+ char *name;
+
+ strncpy (tar_hdr->magic, TMAGIC, TMAGLEN);
+ strncpy (tar_hdr->magic + TMAGLEN, TVERSION, TVERSLEN);
+
+#ifndef __MSDOS__
+ name = getuser (file_hdr->c_uid);
+ if (name)
+ strcpy (tar_hdr->uname, name);
+ name = getgroup (file_hdr->c_gid);
+ if (name)
+ strcpy (tar_hdr->gname, name);
+#endif
+
+ to_oct (file_hdr->c_rdev_maj, 8, tar_hdr->devmajor);
+ to_oct (file_hdr->c_rdev_min, 8, tar_hdr->devminor);
+ }
+
+ to_oct (tar_checksum (tar_hdr), 8, tar_hdr->chksum);
+
+ copy_buf_out ((char *) &tar_rec, out_des, TARRECORDSIZE);
+}
+
+/* Return nonzero iff all the bytes in BLOCK are NUL.
+ SIZE is the number of bytes to check in BLOCK; it must be a
+ multiple of sizeof (long). */
+
+int
+null_block (block, size)
+ long *block;
+ int size;
+{
+ register long *p = block;
+ register int i = size / sizeof (long);
+
+ while (i--)
+ if (*p++)
+ return 0;
+ return 1;
+}
+
+/* Read a tar header, including the file name, from file descriptor IN_DES
+ into FILE_HDR. */
+
+void
+read_in_tar_header (file_hdr, in_des)
+ struct new_cpio_header *file_hdr;
+ int in_des;
+{
+ long bytes_skipped = 0;
+ int warned = FALSE;
+ union tar_record tar_rec;
+ struct tar_header *tar_hdr = (struct tar_header *) &tar_rec;
+#ifndef __MSDOS__
+ uid_t *uidp;
+ gid_t *gidp;
+#endif
+
+ copy_in_buf ((char *) &tar_rec, in_des, TARRECORDSIZE);
+
+ /* Check for a block of 0's. */
+ if (null_block ((long *) &tar_rec, TARRECORDSIZE))
+ {
+#if 0
+ /* Found one block of 512 0's. If the next block is also all 0's
+ then this is the end of the archive. If not, assume the
+ previous block was all corruption and continue reading
+ the archive. */
+ /* Commented out because GNU tar sometimes creates archives with
+ only one block of 0's at the end. This happened for the
+ cpio 2.0 distribution! */
+ copy_in_buf ((char *) &tar_rec, in_des, TARRECORDSIZE);
+ if (null_block ((long *) &tar_rec, TARRECORDSIZE))
+#endif
+ {
+ file_hdr->c_name = "TRAILER!!!";
+ return;
+ }
+#if 0
+ bytes_skipped = TARRECORDSIZE;
+#endif
+ }
+
+ while (1)
+ {
+ otoa (tar_hdr->chksum, &file_hdr->c_chksum);
+
+ if (file_hdr->c_chksum != tar_checksum (tar_hdr))
+ {
+ /* If the checksum is bad, skip 1 byte and try again. When
+ we try again we do not look for an EOF record (all zeros),
+ because when we start skipping bytes in a corrupted archive
+ the chances are pretty good that we might stumble across
+ 2 blocks of 512 zeros (that probably is not really the last
+ record) and it is better to miss the EOF and give the user
+ a "premature EOF" error than to give up too soon on a corrupted
+ archive. */
+ if (!warned)
+ {
+ error (0, 0, "invalid header: checksum error");
+ warned = TRUE;
+ }
+ bcopy (((char *) &tar_rec) + 1, (char *) &tar_rec,
+ TARRECORDSIZE - 1);
+ copy_in_buf (((char *) &tar_rec) + (TARRECORDSIZE - 1), in_des, 1);
+ ++bytes_skipped;
+ continue;
+ }
+
+ if (archive_format != arf_ustar)
+ file_hdr->c_name = stash_tar_filename (NULL, tar_hdr->name);
+ else
+ file_hdr->c_name = stash_tar_filename (tar_hdr->prefix, tar_hdr->name);
+ file_hdr->c_nlink = 1;
+ otoa (tar_hdr->mode, &file_hdr->c_mode);
+ file_hdr->c_mode = file_hdr->c_mode & 07777;
+#ifndef __MSDOS__
+ if (archive_format == arf_ustar
+ && (uidp = getuidbyname (tar_hdr->uname)))
+ file_hdr->c_uid = *uidp;
+ else
+#endif
+ otoa (tar_hdr->uid, &file_hdr->c_uid);
+#ifndef __MSDOS__
+ if (archive_format == arf_ustar
+ && (gidp = getgidbyname (tar_hdr->gname)))
+ file_hdr->c_gid = *gidp;
+ else
+#endif
+ otoa (tar_hdr->gid, &file_hdr->c_gid);
+ otoa (tar_hdr->size, &file_hdr->c_filesize);
+ otoa (tar_hdr->mtime, &file_hdr->c_mtime);
+ otoa (tar_hdr->devmajor, (unsigned long *) &file_hdr->c_rdev_maj);
+ otoa (tar_hdr->devminor, (unsigned long *) &file_hdr->c_rdev_min);
+ file_hdr->c_tar_linkname = NULL;
+
+ switch (tar_hdr->typeflag)
+ {
+ case REGTYPE:
+ case CONTTYPE: /* For now, punt. */
+ default:
+ file_hdr->c_mode |= CP_IFREG;
+ break;
+ case DIRTYPE:
+ file_hdr->c_mode |= CP_IFDIR;
+ break;
+#ifndef __MSDOS__
+ case CHRTYPE:
+ file_hdr->c_mode |= CP_IFCHR;
+ /* If a POSIX tar header has a valid linkname it's always supposed
+ to set typeflag to be LNKTYPE. System V.4 tar seems to
+ be broken, and for device files with multiple links it
+ puts the name of the link into linkname, but leaves typeflag
+ as CHRTYPE, BLKTYPE, FIFOTYPE, etc. */
+ file_hdr->c_tar_linkname = stash_tar_linkname (tar_hdr->linkname);
+
+ /* Does POSIX say that the filesize must be 0 for devices? We
+ assume so, but HPUX's POSIX tar sets it to be 1 which causes
+ us problems (when reading an archive we assume we can always
+ skip to the next file by skipping filesize bytes). For
+ now at least, it's easier to clear filesize for devices,
+ rather than check everywhere we skip in copyin.c. */
+ file_hdr->c_filesize = 0;
+ break;
+ case BLKTYPE:
+ file_hdr->c_mode |= CP_IFBLK;
+ file_hdr->c_tar_linkname = stash_tar_linkname (tar_hdr->linkname);
+ file_hdr->c_filesize = 0;
+ break;
+#ifdef CP_IFIFO
+ case FIFOTYPE:
+ file_hdr->c_mode |= CP_IFIFO;
+ file_hdr->c_tar_linkname = stash_tar_linkname (tar_hdr->linkname);
+ file_hdr->c_filesize = 0;
+ break;
+#endif
+ case SYMTYPE:
+#ifdef CP_IFLNK
+ file_hdr->c_mode |= CP_IFLNK;
+ file_hdr->c_tar_linkname = stash_tar_linkname (tar_hdr->linkname);
+ file_hdr->c_filesize = 0;
+ break;
+ /* Else fall through. */
+#endif
+ case LNKTYPE:
+ file_hdr->c_mode |= CP_IFREG;
+ file_hdr->c_tar_linkname = stash_tar_linkname (tar_hdr->linkname);
+ file_hdr->c_filesize = 0;
+ break;
+#endif /* !__MSDOS__ */
+ case AREGTYPE:
+ /* Old tar format; if the last char in filename is '/' then it is
+ a directory, otherwise it's a regular file. */
+ if (file_hdr->c_name[strlen (file_hdr->c_name) - 1] == '/')
+ file_hdr->c_mode |= CP_IFDIR;
+ else
+ file_hdr->c_mode |= CP_IFREG;
+ break;
+ }
+ break;
+ }
+ if (bytes_skipped > 0)
+ error (0, 0, "warning: skipped %ld bytes of junk", bytes_skipped);
+}
+
+/* Stash the tar linkname in static storage. */
+
+static char *
+stash_tar_linkname (linkname)
+ char *linkname;
+{
+ static char hold_tar_linkname[TARLINKNAMESIZE + 1];
+
+ strncpy (hold_tar_linkname, linkname, TARLINKNAMESIZE);
+ hold_tar_linkname[TARLINKNAMESIZE] = '\0';
+ return hold_tar_linkname;
+}
+
+/* Stash the tar filename and optional prefix in static storage. */
+
+static char *
+stash_tar_filename (prefix, filename)
+ char *prefix;
+ char *filename;
+{
+ static char hold_tar_filename[TARNAMESIZE + TARPREFIXSIZE + 2];
+ if (prefix == NULL || *prefix == '\0')
+ {
+ strncpy (hold_tar_filename, filename, TARNAMESIZE);
+ hold_tar_filename[TARNAMESIZE] = '\0';
+ }
+ else
+ {
+ strncpy (hold_tar_filename, prefix, TARPREFIXSIZE);
+ hold_tar_filename[TARPREFIXSIZE] = '\0';
+ strcat (hold_tar_filename, "/");
+ strncat (hold_tar_filename, filename, TARNAMESIZE);
+ hold_tar_filename[TARPREFIXSIZE + TARNAMESIZE] = '\0';
+ }
+ return hold_tar_filename;
+}
+
+/* Convert the string of octal digits S into a number and store
+ it in *N. Return nonzero if the whole string was converted,
+ zero if there was something after the number.
+ Skip leading and trailing spaces. */
+
+int
+otoa (s, n)
+ char *s;
+ unsigned long *n;
+{
+ unsigned long val = 0;
+
+ while (*s == ' ')
+ ++s;
+ while (*s >= '0' && *s <= '7')
+ val = 8 * val + *s++ - '0';
+ while (*s == ' ')
+ ++s;
+ *n = val;
+ return *s == '\0';
+}
+
+/* Convert a number into a string of octal digits.
+ Convert long VALUE into a DIGITS-digit field at WHERE,
+ including a trailing space and room for a NUL. DIGITS==3 means
+ 1 digit, a space, and room for a NUL.
+
+ We assume the trailing NUL is already there and don't fill it in.
+ This fact is used by start_header and finish_header, so don't change it!
+
+ This is be equivalent to:
+ sprintf (where, "%*lo ", digits - 2, value);
+ except that sprintf fills in the trailing NUL and we don't. */
+
+static void
+to_oct (value, digits, where)
+ register long value;
+ register int digits;
+ register char *where;
+{
+ --digits; /* Leave the trailing NUL slot alone. */
+ where[--digits] = ' '; /* Put in the space, though. */
+
+ /* Produce the digits -- at least one. */
+ do
+ {
+ where[--digits] = '0' + (char) (value & 7); /* One octal digit. */
+ value >>= 3;
+ }
+ while (digits > 0 && value != 0);
+
+ /* Add leading spaces, if necessary. */
+ while (digits > 0)
+ where[--digits] = ' ';
+}
+
+/* Return
+ 2 if BUF is a valid POSIX tar header (the checksum is correct
+ and it has the "ustar" magic string),
+ 1 if BUF is a valid old tar header (the checksum is correct),
+ 0 otherwise. */
+
+int
+is_tar_header (buf)
+ char *buf;
+{
+ struct tar_header *tar_hdr = (struct tar_header *) buf;
+ unsigned long chksum;
+
+ otoa (tar_hdr->chksum, &chksum);
+
+ if (chksum != tar_checksum (tar_hdr))
+ return 0;
+
+ /* GNU tar 1.10 and previous set the magic field to be "ustar " instead
+ of "ustar\0". Only look at the first 5 characters of the magic
+ field so we can recognize old GNU tar ustar archives. */
+ if (!strncmp (tar_hdr->magic, TMAGIC, TMAGLEN - 1))
+ return 2;
+ return 1;
+}
+
+/* Return TRUE if the filename is too long to fit in a tar header.
+ For old tar headers, if the filename's length is less than or equal
+ to 100 then it will fit, otherwise it will not. For POSIX tar headers,
+ if the filename's length is less than or equal to 100 then it
+ will definitely fit, and if it is greater than 256 then it
+ will definitely not fit. If the length is between 100 and 256,
+ then the filename will fit only if it is possible to break it
+ into a 155 character "prefix" and 100 character "name". There
+ must be a slash between the "prefix" and the "name", although
+ the slash is not stored or counted in either the "prefix" or
+ the "name", and there must be at least one character in both
+ the "prefix" and the "name". If it is not possible to break down
+ the filename like this then it will not fit. */
+
+int
+is_tar_filename_too_long (name)
+ char *name;
+{
+ int whole_name_len;
+ int prefix_name_len;
+ char *p;
+
+ whole_name_len = strlen (name);
+ if (whole_name_len <= TARNAMESIZE)
+ return FALSE;
+
+ if (archive_format != arf_ustar)
+ return TRUE;
+
+ if (whole_name_len > TARNAMESIZE + TARPREFIXSIZE + 1)
+ return TRUE;
+
+ /* See whether we can split up the name into acceptably-sized
+ `prefix' and `name' (`p') pieces. Start out by making `name'
+ as big as possible, then shrink it by looking for the first '/'. */
+ p = name + whole_name_len - TARNAMESIZE;
+ while (*p != '/' && *p != '\0')
+ ++p;
+ if (*p == '\0')
+ /* The last component of the path is longer than TARNAMESIZE. */
+ return TRUE;
+
+ prefix_name_len = p - name - 1;
+ /* Interestingly, a name consisting of a slash followed by
+ TARNAMESIZE characters can't be stored, because the prefix
+ would be empty, and thus ignored. */
+ if (prefix_name_len > TARPREFIXSIZE || prefix_name_len == 0)
+ return TRUE;
+
+ return FALSE;
+}
diff --git a/gnu/usr.bin/cpio/tar.h b/gnu/usr.bin/cpio/tar.h
new file mode 100644
index 0000000..411579c
--- /dev/null
+++ b/gnu/usr.bin/cpio/tar.h
@@ -0,0 +1,112 @@
+/* Extended tar format from POSIX.1.
+ Copyright (C) 1992 Free Software Foundation, Inc.
+ Written by David J. MacKenzie.
+
+This file is part of the GNU C Library.
+
+The GNU C Library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public License as
+published by the Free Software Foundation; either version 2 of the
+License, or (at your option) any later version.
+
+The GNU C Library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with the GNU C Library; see the file COPYING.LIB. If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA. */
+
+#ifndef _TAR_H
+
+#define _TAR_H 1
+
+
+/* A tar archive consists of 512-byte blocks.
+ Each file in the archive has a header block followed by 0+ data blocks.
+ Two blocks of NUL bytes indicate the end of the archive. */
+
+/* The fields of header blocks:
+ All strings are stored as ISO 646 (approximately ASCII) strings.
+
+ Fields are numeric unless otherwise noted below; numbers are ISO 646
+ representations of octal numbers, with leading zeros as needed.
+
+ linkname is only valid when typeflag==LNKTYPE. It doesn't use prefix;
+ files that are links to pathnames >100 chars long can not be stored
+ in a tar archive.
+
+ If typeflag=={LNKTYPE,SYMTYPE,DIRTYPE} then size must be 0.
+
+ devmajor and devminor are only valid for typeflag=={BLKTYPE,CHRTYPE}.
+
+ chksum contains the sum of all 512 bytes in the header block,
+ treating each byte as an 8-bit unsigned value and treating the
+ 8 bytes of chksum as blank characters.
+
+ uname and gname are used in preference to uid and gid, if those
+ names exist locally.
+
+ Field Name Byte Offset Length in Bytes Field Type
+ name 0 100 NUL-terminated if NUL fits
+ mode 100 8
+ uid 108 8
+ gid 116 8
+ size 124 12
+ mtime 136 12
+ chksum 148 8
+ typeflag 156 1 see below
+ linkname 157 100 NUL-terminated if NUL fits
+ magic 257 6 must be TMAGIC (NUL term.)
+ version 263 2 must be TVERSION
+ uname 265 32 NUL-terminated
+ gname 297 32 NUL-terminated
+ devmajor 329 8
+ devminor 337 8
+ prefix 345 155 NUL-terminated if NUL fits
+
+ If the first character of prefix is '\0', the file name is name;
+ otherwise, it is prefix/name. Files whose pathnames don't fit in that
+ length can not be stored in a tar archive. */
+
+/* The bits in mode: */
+#define TSUID 04000
+#define TSGID 02000
+#define TSVTX 01000
+#define TUREAD 00400
+#define TUWRITE 00200
+#define TUEXEC 00100
+#define TGREAD 00040
+#define TGWRITE 00020
+#define TGEXEC 00010
+#define TOREAD 00004
+#define TOWRITE 00002
+#define TOEXEC 00001
+
+/* The values for typeflag:
+ Values 'A'-'Z' are reserved for custom implementations.
+ All other values are reserved for future POSIX.1 revisions. */
+
+#define REGTYPE '0' /* Regular file (preferred code). */
+#define AREGTYPE '\0' /* Regular file (alternate code). */
+#define LNKTYPE '1' /* Hard link. */
+#define SYMTYPE '2' /* Symbolic link (hard if not supported). */
+#define CHRTYPE '3' /* Character special. */
+#define BLKTYPE '4' /* Block special. */
+#define DIRTYPE '5' /* Directory. */
+#define FIFOTYPE '6' /* Named pipe. */
+#define CONTTYPE '7' /* Contiguous file */
+ /* (regular file if not supported). */
+
+/* Contents of magic field and its length. */
+#define TMAGIC "ustar"
+#define TMAGLEN 6
+
+/* Contents of the version field and its length. */
+#define TVERSION "00"
+#define TVERSLEN 2
+
+
+#endif /* tar.h */
diff --git a/gnu/usr.bin/cpio/tarhdr.h b/gnu/usr.bin/cpio/tarhdr.h
new file mode 100644
index 0000000..54de0d6
--- /dev/null
+++ b/gnu/usr.bin/cpio/tarhdr.h
@@ -0,0 +1,62 @@
+/* Extended tar header from POSIX.1.
+ Copyright (C) 1992 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#ifndef _TARHDR_H
+
+#define _TARHDR_H 1
+
+#include <tar.h>
+
+/* Size of `name' field. */
+#define TARNAMESIZE 100
+
+/* Size of `linkname' field. */
+#define TARLINKNAMESIZE 100
+
+/* Size of `prefix' field. */
+#define TARPREFIXSIZE 155
+
+/* Size of entire tar header. */
+#define TARRECORDSIZE 512
+
+struct tar_header
+{
+ char name[TARNAMESIZE];
+ char mode[8];
+ char uid[8];
+ char gid[8];
+ char size[12];
+ char mtime[12];
+ char chksum[8];
+ char typeflag;
+ char linkname[TARLINKNAMESIZE];
+ char magic[6];
+ char version[2];
+ char uname[32];
+ char gname[32];
+ char devmajor[8];
+ char devminor[8];
+ char prefix[TARPREFIXSIZE];
+};
+
+union tar_record
+{
+ struct tar_header header;
+ char buffer[TARRECORDSIZE];
+};
+
+#endif /* tarhdr.h */
diff --git a/gnu/usr.bin/cpio/tcexparg.c b/gnu/usr.bin/cpio/tcexparg.c
new file mode 100644
index 0000000..c5d88f0
--- /dev/null
+++ b/gnu/usr.bin/cpio/tcexparg.c
@@ -0,0 +1,240 @@
+/* tcexparg.c - Unix-style command line wildcards for Turbo C 2.0
+
+ This file is in the public domain.
+
+ Compile your main program with -Dmain=_main and link with this file.
+
+ After that, it is just as if the operating system had expanded the
+ arguments, except that they are not sorted. The program name and all
+ arguments that are expanded from wildcards are lowercased.
+
+ Syntax for wildcards:
+ * Matches zero or more of any character (except a '.' at
+ the beginning of a name).
+ ? Matches any single character.
+ [r3z] Matches 'r', '3', or 'z'.
+ [a-d] Matches a single character in the range 'a' through 'd'.
+ [!a-d] Matches any single character except a character in the
+ range 'a' through 'd'.
+
+ The period between the filename root and its extension need not be
+ given explicitly. Thus, the pattern `a*e' will match 'abacus.exe'
+ and 'axyz.e' as well as 'apple'. Comparisons are not case sensitive.
+
+ Authors:
+ The expargs code is a modification of wildcard expansion code
+ written for Turbo C 1.0 by
+ Richard Hargrove
+ Texas Instruments, Inc.
+ P.O. Box 869305, m/s 8473
+ Plano, Texas 75086
+ 214/575-4128
+ and posted to USENET in September, 1987.
+
+ The wild_match code was written by Rich Salz, rsalz@bbn.com,
+ posted to net.sources in November, 1986.
+
+ The code connecting the two is by Mike Slomin, bellcore!lcuxa!mike2,
+ posted to comp.sys.ibm.pc in November, 1988.
+
+ Major performance enhancements and bug fixes, and source cleanup,
+ by David MacKenzie, djm@gnu.ai.mit.edu. */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <dos.h>
+#include <dir.h>
+
+/* Number of new arguments to allocate space for at a time. */
+#define ARGS_INCREMENT 10
+
+/* The name this program was run with, for error messages. */
+static char *program_name;
+
+static char **grow_argv (char **new_argv, int new_argc);
+static void fatal_error (const char *message);
+
+int wild_match (char *string, char *pattern);
+char *basename (char *path);
+
+char **expargs (int *, char **);
+
+#ifdef main
+#undef main
+#endif
+
+int
+main (int argc, char **argv, char **envp)
+{
+ argv = expargs (&argc, argv);
+ return _main (argc, argv, envp);
+}
+
+char **
+expargs (int *pargc, char **argv)
+{
+ char path[MAXPATH + 1];
+ char **new_argv;
+ struct ffblk block;
+ char *path_base;
+ char *arg_base;
+ int argind;
+ int new_argc;
+ int path_length;
+ int matched;
+
+ program_name = argv[0];
+ if (program_name && *program_name)
+ strlwr (program_name);
+ new_argv = grow_argv (NULL, 0);
+ new_argv[0] = argv[0];
+ new_argc = 1;
+
+ for (argind = 1; argind < *pargc; ++argind)
+ {
+ matched = 0;
+ if (strpbrk (argv[argind], "?*[") != NULL)
+ {
+ strncpy (path, argv[argind], MAXPATH - 3);
+ path_base = basename (path);
+ strcpy (path_base, "*.*");
+ arg_base = argv[argind] + (path_base - path);
+
+ if (!findfirst (path, &block, FA_DIREC))
+ {
+ strlwr (path);
+ do
+ {
+ /* Only match "." and ".." explicitly. */
+ if (*block.ff_name == '.' && *arg_base != '.')
+ continue;
+ path_length = stpcpy (path_base, block.ff_name) - path + 1;
+ strlwr (path_base);
+ if (wild_match (path, argv[argind]))
+ {
+ matched = 1;
+ new_argv[new_argc] = (char *) malloc (path_length);
+ if (new_argv[new_argc] == NULL)
+ fatal_error ("memory exhausted");
+ strcpy (new_argv[new_argc++], path);
+ new_argv = grow_argv (new_argv, new_argc);
+ }
+ } while (!findnext (&block));
+ }
+ }
+ if (matched == 0)
+ new_argv[new_argc++] = argv[argind];
+ new_argv = grow_argv (new_argv, new_argc);
+ }
+
+ *pargc = new_argc;
+ new_argv[new_argc] = NULL;
+ return &new_argv[0];
+}
+
+/* Return a pointer to the last element of PATH. */
+
+char *
+basename (char *path)
+{
+ char *tail;
+
+ for (tail = path; *path; ++path)
+ if (*path == ':' || *path == '\\')
+ tail = path + 1;
+ return tail;
+}
+
+static char **
+grow_argv (char **new_argv, int new_argc)
+{
+ if (new_argc % ARGS_INCREMENT == 0)
+ {
+ new_argv = (char **) realloc
+ (new_argv, sizeof (char *) * (new_argc + ARGS_INCREMENT));
+ if (new_argv == NULL)
+ fatal_error ("memory exhausted");
+ }
+ return new_argv;
+}
+
+static void
+fatal_error (const char *message)
+{
+ putc ('\n', stderr);
+ if (program_name && *program_name)
+ {
+ fputs (program_name, stderr);
+ fputs (": ", stderr);
+ }
+ fputs (message, stderr);
+ putc ('\n', stderr);
+ exit (1);
+}
+
+/* Shell-style pattern matching for ?, \, [], and * characters.
+ I'm putting this replacement in the public domain.
+
+ Written by Rich $alz, mirror!rs, Wed Nov 26 19:03:17 EST 1986. */
+
+/* The character that inverts a character class; '!' or '^'. */
+#define INVERT '!'
+
+static int star (char *string, char *pattern);
+
+/* Return nonzero if `string' matches Unix-style wildcard pattern
+ `pattern'; zero if not. */
+
+int
+wild_match (char *string, char *pattern)
+{
+ int prev; /* Previous character in character class. */
+ int matched; /* If 1, character class has been matched. */
+ int reverse; /* If 1, character class is inverted. */
+
+ for (; *pattern; string++, pattern++)
+ switch (*pattern)
+ {
+ case '\\':
+ /* Literal match with following character; fall through. */
+ pattern++;
+ default:
+ if (*string != *pattern)
+ return 0;
+ continue;
+ case '?':
+ /* Match anything. */
+ if (*string == '\0')
+ return 0;
+ continue;
+ case '*':
+ /* Trailing star matches everything. */
+ return *++pattern ? star (string, pattern) : 1;
+ case '[':
+ /* Check for inverse character class. */
+ reverse = pattern[1] == INVERT;
+ if (reverse)
+ pattern++;
+ for (prev = 256, matched = 0; *++pattern && *pattern != ']';
+ prev = *pattern)
+ if (*pattern == '-'
+ ? *string <= *++pattern && *string >= prev
+ : *string == *pattern)
+ matched = 1;
+ if (matched == reverse)
+ return 0;
+ continue;
+ }
+
+ return *string == '\0';
+}
+
+static int
+star (char *string, char *pattern)
+{
+ while (wild_match (string, pattern) == 0)
+ if (*++string == '\0')
+ return 0;
+ return 1;
+}
diff --git a/gnu/usr.bin/cpio/userspec.c b/gnu/usr.bin/cpio/userspec.c
new file mode 100644
index 0000000..44d7d91
--- /dev/null
+++ b/gnu/usr.bin/cpio/userspec.c
@@ -0,0 +1,180 @@
+/* userspec.c -- Parse a user and group string.
+ Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* Written by David MacKenzie <djm@gnu.ai.mit.edu>. */
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <pwd.h>
+#include <grp.h>
+
+#if defined(STDC_HEADERS) || defined(HAVE_STRING_H)
+#include <string.h>
+#ifndef index
+#define index strchr
+#endif
+#else
+#include <strings.h>
+#endif
+
+#ifdef STDC_HEADERS
+#include <stdlib.h>
+#else
+char *malloc ();
+#endif
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#ifndef _POSIX_VERSION
+struct passwd *getpwnam ();
+struct group *getgrnam ();
+struct group *getgrgid ();
+#endif
+
+#ifdef _POSIX_SOURCE
+#define endpwent()
+#define endgrent()
+#endif
+
+#define isdigit(c) ((c) >= '0' && (c) <= '9')
+
+char *strdup ();
+static int isnumber ();
+
+/* Extract from NAME, which has the form "[user][:.][group]",
+ a USERNAME, UID U, GROUPNAME, and GID G.
+ Either user or group, or both, must be present.
+ If the group is omitted but the ":" or "." separator is given,
+ use the given user's login group.
+
+ USERNAME and GROUPNAME will be in newly malloc'd memory.
+ Either one might be NULL instead, indicating that it was not
+ given and the corresponding numeric ID was left unchanged.
+ Might write NULs into NAME.
+
+ Return NULL if successful, a static error message string if not. */
+
+char *
+parse_user_spec (name, uid, gid, username, groupname)
+ char *name;
+ uid_t *uid;
+ gid_t *gid;
+ char **username, **groupname;
+{
+ static char *tired = "virtual memory exhausted";
+ struct passwd *pwd;
+ struct group *grp;
+ char *cp;
+ int use_login_group = 0;
+
+ *username = *groupname = NULL;
+
+ /* Check whether a group is given. */
+ cp = index (name, ':');
+ if (cp == NULL)
+ cp = index (name, '.');
+ if (cp != NULL)
+ {
+ *cp++ = '\0';
+ if (*cp == '\0')
+ {
+ if (cp == name + 1)
+ /* Neither user nor group given, just "." or ":". */
+ return "can not omit both user and group";
+ else
+ /* "user.". */
+ use_login_group = 1;
+ }
+ else
+ {
+ /* Explicit group. */
+ *groupname = strdup (cp);
+ if (*groupname == NULL)
+ return tired;
+ grp = getgrnam (cp);
+ if (grp == NULL)
+ {
+ if (!isnumber (cp))
+ return "invalid group";
+ *gid = atoi (cp);
+ }
+ else
+ *gid = grp->gr_gid;
+ endgrent (); /* Save a file descriptor. */
+ }
+ }
+
+ /* Parse the user name, now that any group has been removed. */
+
+ if (name[0] == '\0')
+ /* No user name was given, just a group. */
+ return NULL;
+
+ *username = strdup (name);
+ if (*username == NULL)
+ return tired;
+
+ pwd = getpwnam (name);
+ if (pwd == NULL)
+ {
+ if (!isnumber (name))
+ return "invalid user";
+ if (use_login_group)
+ return "cannot get the login group of a numeric UID";
+ *uid = atoi (name);
+ }
+ else
+ {
+ *uid = pwd->pw_uid;
+ if (use_login_group)
+ {
+ *gid = pwd->pw_gid;
+ grp = getgrgid (pwd->pw_gid);
+ if (grp == NULL)
+ {
+ *groupname = malloc (15);
+ if (*groupname == NULL)
+ return tired;
+ sprintf (*groupname, "%u", pwd->pw_gid);
+ }
+ else
+ {
+ *groupname = strdup (grp->gr_name);
+ if (*groupname == NULL)
+ return tired;
+ }
+ endgrent ();
+ }
+ }
+ endpwent ();
+ return NULL;
+}
+
+/* Return nonzero if STR represents an unsigned decimal integer,
+ otherwise return 0. */
+
+static int
+isnumber (str)
+ char *str;
+{
+ for (; *str; str++)
+ if (!isdigit (*str))
+ return 0;
+ return 1;
+}
diff --git a/gnu/usr.bin/cpio/util.c b/gnu/usr.bin/cpio/util.c
new file mode 100644
index 0000000..e2e1c1e
--- /dev/null
+++ b/gnu/usr.bin/cpio/util.c
@@ -0,0 +1,1102 @@
+/* util.c - Several utility routines for cpio.
+ Copyright (C) 1990, 1991, 1992 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <stdio.h>
+#include <sys/types.h>
+#ifdef HPUX_CDF
+#include <sys/stat.h>
+#endif
+#include "system.h"
+#include "cpiohdr.h"
+#include "dstring.h"
+#include "extern.h"
+#include "rmt.h"
+
+#ifndef __MSDOS__
+#include <sys/ioctl.h>
+#else
+#include <io.h>
+#endif
+
+#ifdef HAVE_SYS_MTIO_H
+#ifdef HAVE_SYS_IO_TRIOCTL_H
+#include <sys/io/trioctl.h>
+#endif
+#include <sys/mtio.h>
+#endif
+
+static void empty_output_buffer_swap ();
+static void hash_insert ();
+
+/* Write `output_size' bytes of `output_buffer' to file
+ descriptor OUT_DES and reset `output_size' and `out_buff'. */
+
+void
+empty_output_buffer (out_des)
+ int out_des;
+{
+ int bytes_written;
+
+#ifdef BROKEN_LONG_TAPE_DRIVER
+ static long output_bytes_before_lseek = 0;
+#endif
+
+ if (swapping_halfwords || swapping_bytes)
+ {
+ empty_output_buffer_swap (out_des);
+ return;
+ }
+
+#ifdef BROKEN_LONG_TAPE_DRIVER
+ /* Some tape drivers seem to have a signed internal seek pointer and
+ they lose if it overflows and becomes negative (e.g. when writing
+ tapes > 2Gb). Doing an lseek (des, 0, SEEK_SET) seems to reset the
+ seek pointer and prevent it from overflowing. */
+ if (output_is_special
+ && (output_bytes_before_lseek += output_size) < 0L)
+ {
+ lseek(out_des, 0L, SEEK_SET);
+ output_bytes_before_lseek = 0;
+ }
+#endif
+
+ bytes_written = rmtwrite (out_des, output_buffer, output_size);
+ if (bytes_written != output_size)
+ {
+ int rest_bytes_written;
+ int rest_output_size;
+
+ if (output_is_special
+ && (bytes_written >= 0
+ || (bytes_written < 0
+ && (errno == ENOSPC || errno == EIO || errno == ENXIO))))
+ {
+ get_next_reel (out_des);
+ if (bytes_written > 0)
+ rest_output_size = output_size - bytes_written;
+ else
+ rest_output_size = output_size;
+ rest_bytes_written = rmtwrite (out_des, output_buffer,
+ rest_output_size);
+ if (rest_bytes_written != rest_output_size)
+ error (1, errno, "write error");
+ }
+ else
+ error (1, errno, "write error");
+ }
+ output_bytes += output_size;
+ out_buff = output_buffer;
+ output_size = 0;
+}
+
+/* Write `output_size' bytes of `output_buffer' to file
+ descriptor OUT_DES with byte and/or halfword swapping and reset
+ `output_size' and `out_buff'. This routine should not be called
+ with `swapping_bytes' set unless the caller knows that the
+ file being written has an even number of bytes, and it should not be
+ called with `swapping_halfwords' set unless the caller knows
+ that the file being written has a length divisible by 4. If either
+ of those restrictions are not met, bytes may be lost in the output
+ file. OUT_DES must refer to a file that we are creating during
+ a process_copy_in, so we don't have to check for end of media
+ errors or be careful about only writing in blocks of `output_size'
+ bytes. */
+
+static void
+empty_output_buffer_swap (out_des)
+ int out_des;
+{
+ /* Since `output_size' might not be divisible by 4 or 2, we might
+ not be able to be able to swap all the bytes and halfwords in
+ `output_buffer' (e.g., if `output_size' is odd), so we might not be
+ able to write them all. We will swap and write as many bytes as
+ we can, and save the rest in `left_overs' for the next time we are
+ called. */
+ static char left_overs[4];
+ static int left_over_bytes = 0;
+
+ int bytes_written;
+ int complete_halfwords;
+ int complete_words;
+ int extra_bytes;
+
+ output_bytes += output_size;
+
+ out_buff = output_buffer;
+
+ if (swapping_halfwords)
+ {
+ if (left_over_bytes != 0)
+ {
+ while (output_size > 0 && left_over_bytes < 4)
+ {
+ left_overs[left_over_bytes++] = *out_buff++;
+ --output_size;
+ }
+ if (left_over_bytes < 4)
+ {
+ out_buff = output_buffer;
+ output_size = 0;
+ return;
+ }
+ swahw_array (left_overs, 1);
+ if (swapping_bytes)
+ swab_array (left_overs, 2);
+ bytes_written = rmtwrite (out_des, left_overs, 4);
+ if (bytes_written != 4)
+ error (1, errno, "write error");
+ left_over_bytes = 0;
+ }
+ complete_words = output_size / 4;
+ if (complete_words > 0)
+ {
+ swahw_array (out_buff, complete_words);
+ if (swapping_bytes)
+ swab_array (out_buff, 2 * complete_words);
+ bytes_written = rmtwrite (out_des, out_buff, 4 * complete_words);
+ if (bytes_written != (4 * complete_words))
+ error (1, errno, "write error");
+ }
+ out_buff += (4 * complete_words);
+ extra_bytes = output_size % 4;
+ while (extra_bytes > 0)
+ {
+ left_overs[left_over_bytes++] = *out_buff++;
+ --extra_bytes;
+ }
+
+ }
+ else
+ {
+ if (left_over_bytes != 0)
+ {
+ while (output_size > 0 && left_over_bytes < 2)
+ {
+ left_overs[left_over_bytes++] = *out_buff++;
+ --output_size;
+ }
+ if (left_over_bytes < 2)
+ {
+ out_buff = output_buffer;
+ output_size = 0;
+ return;
+ }
+ swab_array (left_overs, 1);
+ bytes_written = rmtwrite (out_des, left_overs, 2);
+ if (bytes_written != 2)
+ error (1, errno, "write error");
+ left_over_bytes = 0;
+ }
+ complete_halfwords = output_size / 2;
+ if (complete_halfwords > 0)
+ {
+ swab_array (out_buff, complete_halfwords);
+ bytes_written = rmtwrite (out_des, out_buff, 2 * complete_halfwords);
+ if (bytes_written != (2 * complete_halfwords))
+ error (1, errno, "write error");
+ }
+ out_buff += (2 * complete_halfwords);
+ extra_bytes = output_size % 2;
+ while (extra_bytes > 0)
+ {
+ left_overs[left_over_bytes++] = *out_buff++;
+ --extra_bytes;
+ }
+ }
+
+ out_buff = output_buffer;
+ output_size = 0;
+}
+
+/* Exchange the halfwords of each element of the array of COUNT longs
+ starting at PTR. PTR does not have to be aligned at a word
+ boundary. */
+
+void
+swahw_array (ptr, count)
+ char *ptr;
+ int count;
+{
+ char tmp;
+
+ for (; count > 0; --count)
+ {
+ tmp = *ptr;
+ *ptr = *(ptr + 2);
+ *(ptr + 2) = tmp;
+ ++ptr;
+ tmp = *ptr;
+ *ptr = *(ptr + 2);
+ *(ptr + 2) = tmp;
+ ptr += 3;
+ }
+}
+
+/* Read at most NUM_BYTES or `io_block_size' bytes, whichever is smaller,
+ into the start of `input_buffer' from file descriptor IN_DES.
+ Set `input_size' to the number of bytes read and reset `in_buff'.
+ Exit with an error if end of file is reached. */
+
+#ifdef BROKEN_LONG_TAPE_DRIVER
+static long input_bytes_before_lseek = 0;
+#endif
+
+void
+fill_input_buffer (in_des, num_bytes)
+ int in_des;
+ int num_bytes;
+{
+#ifdef BROKEN_LONG_TAPE_DRIVER
+ /* Some tape drivers seem to have a signed internal seek pointer and
+ they lose if it overflows and becomes negative (e.g. when writing
+ tapes > 4Gb). Doing an lseek (des, 0, SEEK_SET) seems to reset the
+ seek pointer and prevent it from overflowing. */
+ if (input_is_special
+ && (input_bytes_before_lseek += num_bytes) < 0L)
+ {
+ lseek(in_des, 0L, SEEK_SET);
+ input_bytes_before_lseek = 0;
+ }
+#endif
+ in_buff = input_buffer;
+ num_bytes = (num_bytes < io_block_size) ? num_bytes : io_block_size;
+ input_size = rmtread (in_des, input_buffer, num_bytes);
+ if (input_size == 0 && input_is_special)
+ {
+ get_next_reel (in_des);
+ input_size = rmtread (in_des, input_buffer, num_bytes);
+ }
+ if (input_size < 0)
+ error (1, errno, "read error");
+ if (input_size == 0)
+ {
+ error (0, 0, "premature end of file");
+ exit (1);
+ }
+ input_bytes += input_size;
+}
+
+/* Copy NUM_BYTES of buffer IN_BUF to `out_buff', which may be partly full.
+ When `out_buff' fills up, flush it to file descriptor OUT_DES. */
+
+void
+copy_buf_out (in_buf, out_des, num_bytes)
+ char *in_buf;
+ int out_des;
+ long num_bytes;
+{
+ register long bytes_left = num_bytes; /* Bytes needing to be copied. */
+ register long space_left; /* Room left in output buffer. */
+
+ while (bytes_left > 0)
+ {
+ space_left = io_block_size - output_size;
+ if (space_left == 0)
+ empty_output_buffer (out_des);
+ else
+ {
+ if (bytes_left < space_left)
+ space_left = bytes_left;
+ bcopy (in_buf, out_buff, (unsigned) space_left);
+ out_buff += space_left;
+ output_size += space_left;
+ in_buf += space_left;
+ bytes_left -= space_left;
+ }
+ }
+}
+
+/* Copy NUM_BYTES of buffer `in_buff' into IN_BUF.
+ `in_buff' may be partly full.
+ When `in_buff' is exhausted, refill it from file descriptor IN_DES. */
+
+void
+copy_in_buf (in_buf, in_des, num_bytes)
+ char *in_buf;
+ int in_des;
+ long num_bytes;
+{
+ register long bytes_left = num_bytes; /* Bytes needing to be copied. */
+ register long space_left; /* Bytes to copy from input buffer. */
+
+ while (bytes_left > 0)
+ {
+ if (input_size == 0)
+ fill_input_buffer (in_des, io_block_size);
+ if (bytes_left < input_size)
+ space_left = bytes_left;
+ else
+ space_left = input_size;
+ bcopy (in_buff, in_buf, (unsigned) space_left);
+ in_buff += space_left;
+ in_buf += space_left;
+ input_size -= space_left;
+ bytes_left -= space_left;
+ }
+}
+
+/* Copy the the next NUM_BYTES bytes of `input_buffer' into PEEK_BUF.
+ If NUM_BYTES bytes are not available, read the next `io_block_size' bytes
+ into the end of `input_buffer' and update `input_size'.
+
+ Return the number of bytes copied into PEEK_BUF.
+ If the number of bytes returned is less than NUM_BYTES,
+ then EOF has been reached. */
+
+int
+peek_in_buf (peek_buf, in_des, num_bytes)
+ char *peek_buf;
+ int in_des;
+ int num_bytes;
+{
+ long tmp_input_size;
+ long got_bytes;
+ char *append_buf;
+
+#ifdef BROKEN_LONG_TAPE_DRIVER
+ /* Some tape drivers seem to have a signed internal seek pointer and
+ they lose if it overflows and becomes negative (e.g. when writing
+ tapes > 4Gb). Doing an lseek (des, 0, SEEK_SET) seems to reset the
+ seek pointer and prevent it from overflowing. */
+ if (input_is_special
+ && (input_bytes_before_lseek += num_bytes) < 0L)
+ {
+ lseek(in_des, 0L, SEEK_SET);
+ input_bytes_before_lseek = 0;
+ }
+#endif
+
+ while (input_size < num_bytes)
+ {
+ append_buf = in_buff + input_size;
+ tmp_input_size = rmtread (in_des, append_buf, io_block_size);
+ if (tmp_input_size == 0)
+ {
+ if (input_is_special)
+ {
+ get_next_reel (in_des);
+ tmp_input_size = rmtread (in_des, append_buf, io_block_size);
+ }
+ else
+ break;
+ }
+ if (tmp_input_size < 0)
+ error (1, errno, "read error");
+ input_bytes += tmp_input_size;
+ input_size += tmp_input_size;
+ }
+ if (num_bytes <= input_size)
+ got_bytes = num_bytes;
+ else
+ got_bytes = input_size;
+ bcopy (in_buff, peek_buf, (unsigned) got_bytes);
+ return got_bytes;
+}
+
+/* Skip the next NUM_BYTES bytes of file descriptor IN_DES. */
+
+void
+toss_input (in_des, num_bytes)
+ int in_des;
+ long num_bytes;
+{
+ register long bytes_left = num_bytes; /* Bytes needing to be copied. */
+ register long space_left; /* Bytes to copy from input buffer. */
+
+ while (bytes_left > 0)
+ {
+ if (input_size == 0)
+ fill_input_buffer (in_des, io_block_size);
+ if (bytes_left < input_size)
+ space_left = bytes_left;
+ else
+ space_left = input_size;
+ in_buff += space_left;
+ input_size -= space_left;
+ bytes_left -= space_left;
+ }
+}
+
+/* Copy a file using the input and output buffers, which may start out
+ partly full. After the copy, the files are not closed nor the last
+ block flushed to output, and the input buffer may still be partly
+ full. If `crc_i_flag' is set, add each byte to `crc'.
+ IN_DES is the file descriptor for input;
+ OUT_DES is the file descriptor for output;
+ NUM_BYTES is the number of bytes to copy. */
+
+void
+copy_files (in_des, out_des, num_bytes)
+ int in_des;
+ int out_des;
+ long num_bytes;
+{
+ long size;
+ long k;
+
+ while (num_bytes > 0)
+ {
+ if (input_size == 0)
+ fill_input_buffer (in_des, io_block_size);
+ size = (input_size < num_bytes) ? input_size : num_bytes;
+ if (crc_i_flag)
+ {
+ for (k = 0; k < size; ++k)
+ crc += in_buff[k] & 0xff;
+ }
+ copy_buf_out (in_buff, out_des, size);
+ num_bytes -= size;
+ input_size -= size;
+ in_buff += size;
+ }
+}
+
+/* Create all directories up to but not including the last part of NAME.
+ Do not destroy any nondirectories while creating directories. */
+
+void
+create_all_directories (name)
+ char *name;
+{
+ char *dir;
+ int mode;
+#ifdef HPUX_CDF
+ int cdf;
+#endif
+
+ dir = dirname (name);
+ mode = 0700;
+#ifdef HPUX_CDF
+ cdf = islastparentcdf (name);
+ if (cdf)
+ {
+ dir [strlen (dir) - 1] = '\0'; /* remove final + */
+ mode = 04700;
+ }
+
+#endif
+
+ if (dir == NULL)
+ error (2, 0, "virtual memory exhausted");
+
+ if (dir[0] != '.' || dir[1] != '\0')
+ make_path (dir, mode, 0700, -1, -1, (char *) NULL);
+
+ free (dir);
+}
+
+/* Prepare to append to an archive. We have been in
+ process_copy_in, keeping track of the position where
+ the last header started in `last_header_start'. Now we
+ have the starting position of the last header (the TRAILER!!!
+ header, or blank record for tar archives) and we want to start
+ writing (appending) over the last header. The last header may
+ be in the middle of a block, so to keep the buffering in sync
+ we lseek back to the start of the block, read everything up
+ to but not including the last header, lseek back to the start
+ of the block, and then do a copy_buf_out of what we read.
+ Actually, we probably don't have to worry so much about keeping the
+ buffering perfect since you can only append to archives that
+ are disk files. */
+
+void
+prepare_append (out_file_des)
+ int out_file_des;
+{
+ int start_of_header;
+ int start_of_block;
+ int useful_bytes_in_block;
+ char *tmp_buf;
+
+ start_of_header = last_header_start;
+ /* Figure out how many bytes we will rewrite, and where they start. */
+ useful_bytes_in_block = start_of_header % io_block_size;
+ start_of_block = start_of_header - useful_bytes_in_block;
+
+ if (lseek (out_file_des, start_of_block, SEEK_SET) < 0)
+ error (1, errno, "cannot seek on output");
+ if (useful_bytes_in_block > 0)
+ {
+ tmp_buf = (char *) xmalloc (useful_bytes_in_block);
+ read (out_file_des, tmp_buf, useful_bytes_in_block);
+ if (lseek (out_file_des, start_of_block, SEEK_SET) < 0)
+ error (1, errno, "cannot seek on output");
+ copy_buf_out (tmp_buf, out_file_des, useful_bytes_in_block);
+ free (tmp_buf);
+ }
+
+ /* We are done reading the archive, so clear these since they
+ will now be used for reading in files that we are appending
+ to the archive. */
+ input_size = 0;
+ input_bytes = 0;
+ in_buff = input_buffer;
+}
+
+/* Support for remembering inodes with multiple links. Used in the
+ "copy in" and "copy pass" modes for making links instead of copying
+ the file. */
+
+struct inode_val
+{
+ unsigned long inode;
+ unsigned long major_num;
+ unsigned long minor_num;
+ char *file_name;
+};
+
+/* Inode hash table. Allocated by first call to add_inode. */
+static struct inode_val **hash_table = NULL;
+
+/* Size of current hash table. Initial size is 47. (47 = 2*22 + 3) */
+static int hash_size = 22;
+
+/* Number of elements in current hash table. */
+static int hash_num;
+
+/* Find the file name associated with NODE_NUM. If there is no file
+ associated with NODE_NUM, return NULL. */
+
+char *
+find_inode_file (node_num, major_num, minor_num)
+ unsigned long node_num;
+ unsigned long major_num;
+ unsigned long minor_num;
+{
+#ifndef __MSDOS__
+ int start; /* Initial hash location. */
+ int temp; /* Rehash search variable. */
+
+ if (hash_table != NULL)
+ {
+ /* Hash function is node number modulo the table size. */
+ start = node_num % hash_size;
+
+ /* Initial look into the table. */
+ if (hash_table[start] == NULL)
+ return NULL;
+ if (hash_table[start]->inode == node_num
+ && hash_table[start]->major_num == major_num
+ && hash_table[start]->minor_num == minor_num)
+ return hash_table[start]->file_name;
+
+ /* The home position is full with a different inode record.
+ Do a linear search terminated by a NULL pointer. */
+ for (temp = (start + 1) % hash_size;
+ hash_table[temp] != NULL && temp != start;
+ temp = (temp + 1) % hash_size)
+ {
+ if (hash_table[temp]->inode == node_num
+ && hash_table[start]->major_num == major_num
+ && hash_table[start]->minor_num == minor_num)
+ return hash_table[temp]->file_name;
+ }
+ }
+#endif
+ return NULL;
+}
+
+/* Associate FILE_NAME with the inode NODE_NUM. (Insert into hash table.) */
+
+void
+add_inode (node_num, file_name, major_num, minor_num)
+ unsigned long node_num;
+ char *file_name;
+ unsigned long major_num;
+ unsigned long minor_num;
+{
+#ifndef __MSDOS__
+ struct inode_val *temp;
+
+ /* Create new inode record. */
+ temp = (struct inode_val *) xmalloc (sizeof (struct inode_val));
+ temp->inode = node_num;
+ temp->major_num = major_num;
+ temp->minor_num = minor_num;
+ temp->file_name = xstrdup (file_name);
+
+ /* Do we have to increase the size of (or initially allocate)
+ the hash table? */
+ if (hash_num == hash_size || hash_table == NULL)
+ {
+ struct inode_val **old_table; /* Pointer to old table. */
+ int i; /* Index for re-insert loop. */
+
+ /* Save old table. */
+ old_table = hash_table;
+ if (old_table == NULL)
+ hash_num = 0;
+
+ /* Calculate new size of table and allocate it.
+ Sequence of table sizes is 47, 97, 197, 397, 797, 1597, 3197, 6397 ...
+ where 3197 and most of the sizes after 6397 are not prime. The other
+ numbers listed are prime. */
+ hash_size = 2 * hash_size + 3;
+ hash_table = (struct inode_val **)
+ xmalloc (hash_size * sizeof (struct inode_val *));
+ bzero (hash_table, hash_size * sizeof (struct inode_val *));
+
+ /* Insert the values from the old table into the new table. */
+ for (i = 0; i < hash_num; i++)
+ hash_insert (old_table[i]);
+
+ if (old_table != NULL)
+ free (old_table);
+ }
+
+ /* Insert the new record and increment the count of elements in the
+ hash table. */
+ hash_insert (temp);
+ hash_num++;
+#endif /* __MSDOS__ */
+}
+
+/* Do the hash insert. Used in normal inserts and resizing the hash
+ table. It is guaranteed that there is room to insert the item.
+ NEW_VALUE is the pointer to the previously allocated inode, file
+ name association record. */
+
+static void
+hash_insert (new_value)
+ struct inode_val *new_value;
+{
+ int start; /* Home position for the value. */
+ int temp; /* Used for rehashing. */
+
+ /* Hash function is node number modulo the table size. */
+ start = new_value->inode % hash_size;
+
+ /* Do the initial look into the table. */
+ if (hash_table[start] == NULL)
+ {
+ hash_table[start] = new_value;
+ return;
+ }
+
+ /* If we get to here, the home position is full with a different inode
+ record. Do a linear search for the first NULL pointer and insert
+ the new item there. */
+ temp = (start + 1) % hash_size;
+ while (hash_table[temp] != NULL)
+ temp = (temp + 1) % hash_size;
+
+ /* Insert at the NULL. */
+ hash_table[temp] = new_value;
+}
+
+/* Open FILE in the mode specified by the command line options
+ and return an open file descriptor for it,
+ or -1 if it can't be opened. */
+
+int
+open_archive (file)
+ char *file;
+{
+ int fd;
+ void (*copy_in) (); /* Workaround for pcc bug. */
+
+ copy_in = process_copy_in;
+
+ if (copy_function == copy_in)
+ fd = rmtopen (file, O_RDONLY | O_BINARY, 0666);
+ else
+ {
+ if (!append_flag)
+ fd = rmtopen (file, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0666);
+ else
+ fd = rmtopen (file, O_RDWR | O_BINARY, 0666);
+ }
+
+ return fd;
+}
+
+/* Attempt to rewind the tape drive on file descriptor TAPE_DES
+ and take it offline. */
+
+void
+tape_offline (tape_des)
+ int tape_des;
+{
+#if defined(MTIOCTOP) && defined(MTOFFL)
+ struct mtop control;
+
+ control.mt_op = MTOFFL;
+ control.mt_count = 1;
+ rmtioctl (tape_des, MTIOCTOP, &control); /* Don't care if it fails. */
+#endif
+}
+
+/* The file on file descriptor TAPE_DES is assumed to be magnetic tape
+ (or floppy disk or other device) and the end of the medium
+ has been reached. Ask the user for to mount a new "tape" to continue
+ the processing. If the user specified the device name on the
+ command line (with the -I, -O, -F or --file options), then we can
+ automatically re-open the same device to use the next medium. If the
+ user did not specify the device name, then we have to ask them which
+ device to use. */
+
+void
+get_next_reel (tape_des)
+ int tape_des;
+{
+ static int reel_number = 1;
+ FILE *tty_in; /* File for interacting with user. */
+ FILE *tty_out; /* File for interacting with user. */
+ int old_tape_des;
+ char *next_archive_name;
+ dynamic_string new_name;
+ char *str_res;
+
+ ds_init (&new_name, 128);
+
+ /* Open files for interactive communication. */
+ tty_in = fopen (CONSOLE, "r");
+ if (tty_in == NULL)
+ error (2, errno, CONSOLE);
+ tty_out = fopen (CONSOLE, "w");
+ if (tty_out == NULL)
+ error (2, errno, CONSOLE);
+
+ old_tape_des = tape_des;
+ tape_offline (tape_des);
+ rmtclose (tape_des);
+
+ /* Give message and wait for carrage return. User should hit carrage return
+ only after loading the next tape. */
+ ++reel_number;
+ if (new_media_message)
+ fprintf (tty_out, "%s", new_media_message);
+ else if (new_media_message_with_number)
+ fprintf (tty_out, "%s%d%s", new_media_message_with_number, reel_number,
+ new_media_message_after_number);
+ else if (archive_name)
+ fprintf (tty_out, "Found end of tape. Load next tape and press RETURN. ");
+ else
+ fprintf (tty_out, "Found end of tape. To continue, type device/file name when ready.\n");
+
+ fflush (tty_out);
+
+ if (archive_name)
+ {
+ int c;
+
+ do
+ c = getc (tty_in);
+ while (c != EOF && c != '\n');
+
+ tape_des = open_archive (archive_name);
+ if (tape_des == -1)
+ error (1, errno, "%s", archive_name);
+ }
+ else
+ {
+ do
+ {
+ if (tape_des < 0)
+ {
+ fprintf (tty_out,
+ "To continue, type device/file name when ready.\n");
+ fflush (tty_out);
+ }
+
+ str_res = ds_fgets (tty_in, &new_name);
+ if (str_res == NULL || str_res[0] == '\0')
+ exit (1);
+ next_archive_name = str_res;
+
+ tape_des = open_archive (next_archive_name);
+ if (tape_des == -1)
+ error (0, errno, "%s", next_archive_name);
+ }
+ while (tape_des < 0);
+ }
+
+ /* We have to make sure that `tape_des' has not changed its value even
+ though we closed it and reopened it, since there are local
+ copies of it in other routines. This works fine on Unix (even with
+ rmtread and rmtwrite) since open will always return the lowest
+ available file descriptor and we haven't closed any files (e.g.,
+ stdin, stdout or stderr) that were opened before we originally opened
+ the archive. */
+
+ if (tape_des != old_tape_des)
+ error (1, 0, "internal error: tape descriptor changed from %d to %d",
+ old_tape_des, tape_des);
+
+ free (new_name.ds_string);
+ fclose (tty_in);
+ fclose (tty_out);
+}
+
+/* If MESSAGE does not contain the string "%d", make `new_media_message'
+ a copy of MESSAGE. If MESSAGES does contain the string "%d", make
+ `new_media_message_with_number' a copy of MESSAGE up to, but
+ not including, the string "%d", and make `new_media_message_after_number'
+ a copy of MESSAGE after the string "%d". */
+
+void
+set_new_media_message (message)
+ char *message;
+{
+ char *p;
+ int prev_was_percent;
+
+ p = message;
+ prev_was_percent = 0;
+ while (*p != '\0')
+ {
+ if (*p == 'd' && prev_was_percent)
+ break;
+ prev_was_percent = (*p == '%');
+ ++p;
+ }
+ if (*p == '\0')
+ {
+ new_media_message = xstrdup (message);
+ }
+ else
+ {
+ int length = p - message - 1;
+
+ new_media_message_with_number = xmalloc (length + 1);
+ strncpy (new_media_message_with_number, message, length);
+ new_media_message_with_number[length] = '\0';
+ length = strlen (p + 1);
+ new_media_message_after_number = xmalloc (length + 1);
+ strcpy (new_media_message_after_number, message);
+ }
+}
+
+#ifdef SYMLINK_USES_UMASK
+/* Most machines always create symlinks with rwxrwxrwx protection,
+ but some (HP/UX 8.07; maybe DEC's OSF on MIPS, too?) use the
+ umask when creating symlinks, so if your umask is 022 you end
+ up with rwxr-xr-x symlinks (although HP/UX seems to completely
+ ignore the protection). There doesn't seem to be any way to
+ manipulate the modes once the symlinks are created (e.g.
+ a hypothetical "lchmod"), so to create them with the right
+ modes we have to set the umask first. */
+
+int
+umasked_symlink (name1, name2, mode)
+ char *name1;
+ char *name2;
+ int mode;
+{
+ int old_umask;
+ int rc;
+ mode = ~(mode & 0777) & 0777;
+ old_umask = umask (mode);
+ rc = symlink (name1, name2);
+ umask (old_umask);
+ return rc;
+}
+#endif /* SYMLINK_USES_UMASK */
+
+#ifdef __MSDOS__
+int
+chown (path, owner, group)
+ char *path;
+ int owner, group;
+{
+ return 0;
+}
+#endif
+
+#ifdef __TURBOC__
+#include <time.h>
+#include <fcntl.h>
+#include <io.h>
+
+int
+utime (char *filename, struct utimbuf *utb)
+{
+ extern int errno;
+ struct tm *tm;
+ struct ftime filetime;
+ time_t when;
+ int fd;
+ int status;
+
+ if (utb == 0)
+ when = time (0);
+ else
+ when = utb->modtime;
+
+ fd = _open (filename, O_RDWR);
+ if (fd == -1)
+ return -1;
+
+ tm = localtime (&when);
+ if (tm->tm_year < 80)
+ filetime.ft_year = 0;
+ else
+ filetime.ft_year = tm->tm_year - 80;
+ filetime.ft_month = tm->tm_mon + 1;
+ filetime.ft_day = tm->tm_mday;
+ if (tm->tm_hour < 0)
+ filetime.ft_hour = 0;
+ else
+ filetime.ft_hour = tm->tm_hour;
+ filetime.ft_min = tm->tm_min;
+ filetime.ft_tsec = tm->tm_sec / 2;
+
+ status = setftime (fd, &filetime);
+ _close (fd);
+ return status;
+}
+#endif
+#ifdef HPUX_CDF
+/* When we create a cpio archive we mark CDF's by putting an extra `/'
+ after their component name so we can distinguish the CDF's when we
+ extract the archive (in case the "hidden" directory's files appear
+ in the archive before the directory itself). E.g., in the path
+ "a/b+/c", if b+ is a CDF, we will write this path as "a/b+//c" in
+ the archive so when we extract the archive we will know that b+
+ is actually a CDF, and not an ordinary directory whose name happens
+ to end in `+'. We also do the same thing internally in copypass.c. */
+
+
+/* Take an input pathname and check it for CDF's. Insert an extra
+ `/' in the pathname after each "hidden" directory. If we add
+ any `/'s, return a malloced string (which it will reuse for
+ later calls so our caller doesn't have to worry about freeing
+ the string) instead of the original input string. */
+
+char *
+add_cdf_double_slashes (input_name)
+ char *input_name;
+{
+ static char *ret_name = NULL; /* re-usuable return buffer (malloc'ed) */
+ static int ret_size = -1; /* size of return buffer. */
+ char *p;
+ char *q;
+ int n;
+ struct stat dir_stat;
+
+ /* Search for a `/' preceeded by a `+'. */
+
+ for (p = input_name; *p != '\0'; ++p)
+ {
+ if ( (*p == '+') && (*(p + 1) == '/') )
+ break;
+ }
+
+ /* If we didn't find a `/' preceeded by a `+' then there are
+ no CDF's in this pathname. Return the original pathname. */
+
+ if (*p == '\0')
+ return input_name;
+
+ /* There was a `/' preceeded by a `+' in the pathname. If it is a CDF
+ then we will need to copy the input pathname to our return
+ buffer so we can insert the extra `/'s. Since we can't tell
+ yet whether or not it is a CDF we will just always copy the
+ string to the return buffer. First we have to make sure the
+ buffer is large enough to hold the string and any number of
+ extra `/'s we might add. */
+
+ n = 2 * (strlen (input_name) + 1);
+ if (n >= ret_size)
+ {
+ if (ret_size < 0)
+ ret_name = (char *) malloc (n);
+ else
+ ret_name = (char *)realloc (ret_name, n);
+ ret_size = n;
+ }
+
+ /* Clear the `/' after this component, so we can stat the pathname
+ up to and including this component. */
+ ++p;
+ *p = '\0';
+ if ((*xstat) (input_name, &dir_stat) < 0)
+ {
+ error (0, errno, "%s", input_name);
+ return input_name;
+ }
+
+ /* Now put back the `/' after this component and copy the pathname up to
+ and including this component and its trailing `/' to the return
+ buffer. */
+ *p++ = '/';
+ strncpy (ret_name, input_name, p - input_name);
+ q = ret_name + (p - input_name);
+
+ /* If it was a CDF, add another `/'. */
+ if (S_ISDIR (dir_stat.st_mode) && (dir_stat.st_mode & 04000) )
+ *q++ = '/';
+
+ /* Go through the rest of the input pathname, copying it to the
+ return buffer, and adding an extra `/' after each CDF. */
+ while (*p != '\0')
+ {
+ if ( (*p == '+') && (*(p + 1) == '/') )
+ {
+ *q++ = *p++;
+
+ *p = '\0';
+ if ((*xstat) (input_name, &dir_stat) < 0)
+ {
+ error (0, errno, "%s", input_name);
+ return input_name;
+ }
+ *p = '/';
+
+ if (S_ISDIR (dir_stat.st_mode) && (dir_stat.st_mode & 04000) )
+ *q++ = '/';
+ }
+ *q++ = *p++;
+ }
+ *q = '\0';
+
+ return ret_name;
+}
+
+/* Is the last parent directory (e.g., c in a/b/c/d) a CDF? If the
+ directory name ends in `+' and is followed by 2 `/'s instead of 1
+ then it is. This is only the case for cpio archives, but we don't
+ have to worry about tar because tar always has the directory before
+ its files (or else we lose). */
+
+islastparentcdf(path)
+ char *path;
+{
+ char *newpath;
+ char *slash;
+ int slash_count;
+ int length; /* Length of result, not including NUL. */
+
+ slash = rindex (path, '/');
+ if (slash == 0)
+ return 0;
+ else
+ {
+ slash_count = 0;
+ while (slash > path && *slash == '/')
+ {
+ ++slash_count;
+ --slash;
+ }
+
+
+ if ( (*slash == '+') && (slash_count >= 2) )
+ return 1;
+ }
+ return 0;
+}
+#endif
diff --git a/gnu/usr.bin/cpio/version.c b/gnu/usr.bin/cpio/version.c
new file mode 100644
index 0000000..38a63f2
--- /dev/null
+++ b/gnu/usr.bin/cpio/version.c
@@ -0,0 +1,2 @@
+/* The version number of cpio and mt. */
+char *version_string = "version 2.3\n";
diff --git a/gnu/usr.bin/cpio/xmalloc.c b/gnu/usr.bin/cpio/xmalloc.c
new file mode 100644
index 0000000..f989004
--- /dev/null
+++ b/gnu/usr.bin/cpio/xmalloc.c
@@ -0,0 +1,65 @@
+/* xmalloc.c -- malloc with out of memory checking
+ Copyright (C) 1990, 1991 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#ifdef STDC_HEADERS
+#include <stdlib.h>
+#else
+char *malloc ();
+char *realloc ();
+void free ();
+#endif
+
+void error ();
+
+/* Allocate N bytes of memory dynamically, with error checking. */
+
+char *
+xmalloc (n)
+ unsigned n;
+{
+ char *p;
+
+ p = malloc (n);
+ if (p == 0)
+ /* Must exit with 2 for `cmp'. */
+ error (2, 0, "virtual memory exhausted");
+ return p;
+}
+
+/* Change the size of an allocated block of memory P to N bytes,
+ with error checking.
+ If P is NULL, run xmalloc.
+ If N is 0, run free and return NULL. */
+
+char *
+xrealloc (p, n)
+ char *p;
+ unsigned n;
+{
+ if (p == 0)
+ return xmalloc (n);
+ if (n == 0)
+ {
+ free (p);
+ return 0;
+ }
+ p = realloc (p, n);
+ if (p == 0)
+ /* Must exit with 2 for `cmp'. */
+ error (2, 0, "virtual memory exhausted");
+ return p;
+}
diff --git a/gnu/usr.bin/cpio/xstrdup.c b/gnu/usr.bin/cpio/xstrdup.c
new file mode 100644
index 0000000..9588bc7
--- /dev/null
+++ b/gnu/usr.bin/cpio/xstrdup.c
@@ -0,0 +1,32 @@
+/* xstrdup.c -- copy a string with out of memory checking
+ Copyright (C) 1990 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#if defined(STDC_HEADERS) || defined(HAVE_STRING_H)
+#include <string.h>
+#else
+#include <strings.h>
+#endif
+char *xmalloc ();
+
+/* Return a newly allocated copy of STRING. */
+
+char *
+xstrdup (string)
+ char *string;
+{
+ return strcpy (xmalloc (strlen (string) + 1), string);
+}
diff --git a/gnu/usr.bin/cvs/BUGS b/gnu/usr.bin/cvs/BUGS
new file mode 100644
index 0000000..3ad13a8
--- /dev/null
+++ b/gnu/usr.bin/cvs/BUGS
@@ -0,0 +1,248 @@
+* `cvs checkout -d nested/dir/path <module>' just doesn't work. The
+ simpler version -- `cvs checkout -d single-dir <module>' works,
+ however.
+
+
+* CVS leaves .#mumble files around when a conflict occurs. (Note:
+ this is intentional and is documented in doc/cvs.texinfo. Of course
+ whether it is a good idea is a separate question).
+
+
+* pcl-cvs doesn't like it when you try to check in a file which isn't
+ up-to-date. The messages produced by the server perhaps don't match
+ what pcl-cvs is looking for.
+
+
+* From: Roland McGrath <roland@gnu.ai.mit.edu>
+ To: Cyclic CVS Hackers <cyclic-cvs@cyclic.com>
+ Subject: weird bug
+ Date: Sat, 25 Mar 1995 16:41:41 -0500
+ X-Windows: Even your dog won't like it.
+
+ I just noticed some droppings on my disk from what must be a pretty weird
+ bug in remote CVS.
+
+ In my home directory on a repository machine I use, I find:
+
+ drwxr-xr-x 4 roland staff 512 Mar 7 14:08 cvs-serv28962
+ drwxr-xr-x 4 roland staff 512 Mar 7 14:11 cvs-serv28978
+ drwxr-xr-x 4 roland staff 512 Mar 7 15:13 cvs-serv29141
+
+ OK, so these are leftover cruft from some cvs run that got aborted.
+ Well, it should clean up after itself, but so what.
+
+ The last one is pretty dull; the real weirdness is the contents of the
+ first two directories.
+
+ duality 77 # ls -RF cvs-serv28978/
+ CVS/ cvs-serv28978/
+
+ cvs-serv28978/CVS:
+ Entries Repository
+
+ cvs-serv28978/cvs-serv28978:
+ arpa/
+
+ cvs-serv28978/cvs-serv28978/arpa:
+ CVS/ cvs-serv28978/
+
+ cvs-serv28978/cvs-serv28978/arpa/CVS:
+ Entries Repository
+
+ cvs-serv28978/cvs-serv28978/arpa/cvs-serv28978:
+ assert/
+
+ cvs-serv28978/cvs-serv28978/arpa/cvs-serv28978/assert:
+ CVS/ cvs-serv28978/
+
+ cvs-serv28978/cvs-serv28978/arpa/cvs-serv28978/assert/CVS:
+ Entries Repository
+
+ cvs-serv28978/cvs-serv28978/arpa/cvs-serv28978/assert/cvs-serv28978:
+ bare/
+
+ cvs-serv28978/cvs-serv28978/arpa/cvs-serv28978/assert/cvs-serv28978/bare:
+ CVS/ cvs-serv28978/
+
+ cvs-serv28978/cvs-serv28978/arpa/cvs-serv28978/assert/cvs-serv28978/bare/CVS:
+ Entries Repository
+
+ cvs-serv28978/cvs-serv28978/arpa/cvs-serv28978/assert/cvs-serv28978/bare/cvs-serv28978:
+ conf/
+
+ cvs-serv28978/cvs-serv28978/arpa/cvs-serv28978/assert/cvs-serv28978/bare/cvs-serv28978/conf:
+ CVS/ cvs-serv28978/
+
+ cvs-serv28978/cvs-serv28978/arpa/cvs-serv28978/assert/cvs-serv28978/bare/cvs-serv28978/conf/CVS:
+ Entries Repository
+
+ cvs-serv28978/cvs-serv28978/arpa/cvs-serv28978/assert/cvs-serv28978/bare/cvs-serv28978/conf/cvs-serv28978:
+ crypt/
+
+ cvs-serv28978/cvs-serv28978/arpa/cvs-serv28978/assert/cvs-serv28978/bare/cvs-serv28978/conf/cvs-serv28978/crypt:
+ CVS/ cvs-serv28978/
+
+ cvs-serv28978/cvs-serv28978/arpa/cvs-serv28978/assert/cvs-serv28978/bare/cvs-serv28978/conf/cvs-serv28978/crypt/CVS:
+ Entries Repository
+
+ cvs-serv28978/cvs-serv28978/arpa/cvs-serv28978/assert/cvs-serv28978/bare/cvs-serv28978/conf/cvs-serv28978/crypt/cvs-serv28978:
+ csu/
+
+ cvs-serv28978/cvs-serv28978/arpa/cvs-serv28978/assert/cvs-serv28978/bare/cvs-serv28978/conf/cvs-serv28978/crypt/cvs-serv28978/csu:
+ CVS/ cvs-serv28978/
+
+ cvs-serv28978/cvs-serv28978/arpa/cvs-serv28978/assert/cvs-serv28978/bare/cvs-serv28978/conf/cvs-serv28978/crypt/cvs-serv28978/csu/CVS:
+ Entries Repository
+
+ cvs-serv28978/cvs-serv28978/arpa/cvs-serv28978/assert/cvs-serv28978/bare/cvs-serv28978/conf/cvs-serv28978/crypt/cvs-serv28978/csu/cvs-serv28978:
+ ctype/
+
+ cvs-serv28978/cvs-serv28978/arpa/cvs-serv28978/assert/cvs-serv28978/bare/cvs-serv28978/conf/cvs-serv28978/crypt/cvs-serv28978/csu/cvs-serv28978/ctype:
+ CVS/ cvs-serv28978/
+
+ [...]
+
+ ls: cvs-serv28978/cvs-serv28978/arpa/cvs-serv28978/assert/cvs-serv28978/bare/cvs-serv28978/conf/cvs-serv28978/crypt/cvs-serv28978/csu/cvs-serv28978/ctype/cvs-serv28978/dirent/cvs-serv28978/elf/cvs-serv28978/gnu/cvs-serv28978/gnulib/cvs-serv28978/grp/cvs-serv28978/hurd/cvs-serv28978/hurd/hurd/cvs-serv28978/inet/cvs-serv28978/inet/arpa/cvs-serv28978/inet/netinet[...]/cvs-serv28978/posix/cvs-serv28978/posix/glob/cvs-serv28978/posix/gnu/cvs-serv28978/posix/sys/cvs-serv28978/protocols/cvs-serv28978/pwd/cvs-serv28978/resolv/cvs-serv28978/resolv/arpa/cvs-serv28978/resolv/sys/cvs-serv28978/resource/cvs-serv28978/resource/sys/cvs-serv28978/rpc/cvs-serv28978/setjmp/cvs-serv28978/signal/cvs-serv28978/signal/sys/cvs-serv28978/socket/cvs-serv28978/socket: File name too long
+ cvs-serv28978/cvs-serv28978/arpa/cvs-serv28978/assert/cvs-serv28978/bare/cvs-serv28978/conf/cvs-serv28978/crypt/cvs-serv28978/csu/cvs-serv28978/ctype/cvs-serv28978/dirent/cvs-serv28978/elf/cvs-serv28978/gnu/cvs-serv28978/gnulib/cvs-serv28978/grp/cvs-serv28978/hurd/cvs-serv28978/hurd/hurd/cvs-serv28978/inet/cvs-serv28978/inet/arpa/cvs-serv28978/inet/netinet[...]/cvs-serv28978/posix/glob/cvs-serv28978/posix/gnu/cvs-serv28978/posix/sys/cvs-serv28978/protocols/cvs-serv28978/pwd/cvs-serv28978/resolv/cvs-serv28978/resolv/arpa/cvs-serv28978/resolv/sys/cvs-serv28978/resource/cvs-serv28978/resource/sys/cvs-serv28978/rpc/cvs-serv28978/setjmp/cvs-serv28978/signal/cvs-serv28978/signal/sys/cvs-serv28978/socket/cvs-serv28978:
+
+
+* From: billr@mpd.tandem.com (Bill Robertson)
+ Subject: Problem with rtag and the -D option
+ Date: Fri, 17 Mar 1995 10:53:29 -0600 (CST)
+
+ I have been trying to use the -D option to specify a date for tagging, but
+ rtag does not recognize the -D option. It is documented to do so and I've
+ tested the use of -D with cvs update and cvs diff and it works fine there.
+
+
+* We need some version numbers really badly. Are there some
+ (and Charles Hannum is just not including them in his reports), or do
+ we simply have no reliable way to distinguish between the various
+ versions of rCVS people on the list are running?
+
+ Now that I think of it, version numbers present a problem when
+ people can update their sources anytime and rebuild. I think the
+ solution is to increment a minor version number *every* time a bug is
+ fixed, so we can identify uniquely what someone is running when they
+ submit a report. This implies recording the version increments in the
+ ChangeLog; that way we can just look to see where a particular version
+ lies in relation to the flow of changing code.
+
+ Should we be doing same with Guppy? I guess not -- it's only
+ important when you have people who are updating directly from your
+ development tree, which is the case with the remote-cvs folks.
+
+ Thoughts?
+
+
+* (Charles Hannum <mycroft@ai.mit.edu>) has these bugs:
+
+ I just tossed remote CVS at a fairly large source tree that I already
+ had, and noticed a few problems:
+
+ 1) server.c assumes that /usr/tmp is a valid default for the place to
+ store files uploaded from the client. There are a number of systems
+ that now use /var/tmp. These should probably be detected by autoconf.
+
+ 2) The server deals rather ungracefully with the tmp directory
+ becoming full.
+
+ 3) There's some oddness with relative paths in Repository files that
+ causes the directory prefix to be added twice; e.g. if I have CVSROOT
+ set to `machine:/this/dir', and I try to update in a directory whose
+ Repository file says `src/bin', the server looks in
+ `/this/dir/machine:/this/dir/src/bin'.
+
+* From: "Charles M. Hannum" <mycroft@ai.mit.edu>
+ To: jimb@duality.gnu.ai.mit.edu, roland@duality.gnu.ai.mit.edu
+ Subject: Serious flaw in remote CVS
+ Date: Wed, 22 Feb 1995 20:54:36 -0500
+
+ I just found a major flaw in the current implementation. Because the
+ sockets are not changed to non-blocking mode, write(2)s can hang. In
+ some cases, this happens on both sides at the same time, with the
+ socket buffers full in both directions. This causes a deadlock,
+ because both processes are stuck in I/O wait and thus never drain
+ their input queues.
+
+ Until this is fixed, I can't use it. I'll look at the problem myself
+ at some point, but I don't know when.
+
+
+ From: "Charles M. Hannum" <mycroft@ai.mit.edu>
+ To: remote-cvs@cyclic.com
+ Cc: jimb@totoro.bio.indiana.edu
+ Subject: Re: forwarded message from Charles M. Hannum
+ Date: Wed, 22 Feb 1995 22:07:07 -0500
+
+ FYI, this happened because the tmp directory on the server became
+ full. Somehow the server started interpreting the files the client
+ was sending as commands, and started spewing tons of errors.
+ Apparently the errors are sent with blocking I/O, or something, and
+ thus allowed the deadlock to happen.
+
+
+* From: "Charles M. Hannum" <mycroft@ai.mit.edu>
+ To: remote-cvs@cyclic.com
+ Subject: Regarding that relative path problem
+ Date: Thu, 23 Feb 1995 02:41:51 -0500
+
+ This is actually more serious. If you have `bar.com:/foo' as your CVS
+ root directory, then:
+
+ 1) When you check things out, the Repository files will contain
+ `/foo/...' (i.e. without the machine name), which makes little sense.
+
+ 2) If you instead have a relative path, when the Repository file is
+ read, `bar.com:/foo' is prepended. This is sent to the server, but
+ confuses it, because it's not expecting the machine name to be
+ prepended.
+
+ A slightly klugy fix would be to have the client prepend the machine
+ name when writing a new Repository file, and strip it off before
+ sending one to the server. This would be backward-compatible with the
+ current arrangement.
+
+
+* From: "Charles M. Hannum" <mycroft@ai.mit.edu>
+ To: remote-cvs@cyclic.com
+ Subject: Still one more bug
+ Date: Sat, 25 Feb 1995 17:01:15 -0500
+
+ mycroft@duality [1]; cd /usr/src/lib/libc
+ mycroft@duality [1]; cvs diff -c2 '-D1 day ago' -Dnow
+ cvs server: Diffing .
+ cvs server: Diffing DB
+ cvs [server aborted]: could not chdir to DB: No such file or directory
+ mycroft@duality [1];
+
+ `DB' is an old directory, which no longer has files in it, and is
+ removed automatically when I use the `-P' option to checkout.
+
+ This error doesn't occur when run locally.
+
+ P.S. Is anyone working on fixing these bugs?
+
+
+* From: Roland McGrath <roland@gnu.ai.mit.edu>
+ To: Cyclic CVS Hackers <cyclic-cvs@cyclic.com>
+ Subject: bizarre failure mode
+ Date: Tue, 7 Mar 95 14:17:28 -0500
+
+ This is pretty weird:
+
+ CVS_SERVER='TMPDIR=. /usr/local/bin/cvs' ../cvs-build/src/cvs update -q
+ cvs [server aborted]: could not get working directory: Result too large
+ [Exit 1]
+ asylum 29 % grep 'Result too large' /usr/include/sys/errno.h
+ #define ERANGE 34 /* Result too large */
+
+ Now, getcwd fails with ERANGE when the buffer is too small. But I don't
+ know why that would be the case; I don't think there are exceptionally long
+ directory names involved. It would be robust to notice ERANGE and use a
+ bigger buffer. But I suspect something weirder is going on.
+
+ The repository in question in duality.gnu.ai.mit.edu:/gd4/gnu/cvsroot/libc.
+
+ Send me a PGP-signed message if you want the password to use the machine
+ where the problem showed up.
diff --git a/gnu/usr.bin/cvs/FAQ b/gnu/usr.bin/cvs/FAQ
new file mode 100644
index 0000000..84d4a3a
--- /dev/null
+++ b/gnu/usr.bin/cvs/FAQ
@@ -0,0 +1,10006 @@
+
+Archive-name: cvs-faq
+Hand Revision: 3.5 <<== Include this in your comments
+Last Updated: 1995/03/09
+$Revision: 1.4 $
+$Date: 1995/10/02 23:13:07 $
+
+===========================================================================
+== Frequently Asked Questions about CVS (The Concurrent Versions System) ==
+===========================================================================
+
+ This document attempts to answer questions posed by users of CVS.
+
+ CVS installers, administrators and maintainers looking for info on
+ system setup should read the section entitled "Installing CVS".
+
+
+ Disclaimer:
+
+ Although an attempt has been made to ensure the veracity of the
+ following material, no responsibility is assumed for any use, or
+ for any consequences resulting from any use, of the information
+ contained herein. No guarantee of suitability for any purpose
+ is offered or implied. Nothing in this document may be assumed
+ to represent the employers of its contributors.
+
+ I also might have slipped in a whopper or two to see if you are
+ paying attention. ;-) In other words, don't bet the house on
+ anything you read here unless you have checked it out yourself.
+
+
+
+ Send questions and answers (along with additions to, subtractions
+ from, and divisions of existing questions -- no multiplications,
+ square roots, or transcendental functions, my cabinet is full of them)
+ to the author, who wrote all unattributed text: (Does it always
+ feel strange to refer to oneself in the third person?)
+
+ David G. Grubbs <dgg@world.std.com>
+
+
+ Major revisions contain enough alterations to render change markers
+ meaningless. (Major revisions are those with a final digit of '0',
+ such as 2.0 or 3.0.) To help readers of previous versions of this
+ document, minor revisions will be annotated:
+
+ Change markers: Column 1 will contain a:
+
+ '-' for a Question that has changed.
+ '=' for an Answer that has changed.
+ '#' for an entry with changes to both Question and Answer.
+ '+' for a newly added Question and Answer.
+
+
+ Trivial changes, such as question reordering or spelling and grammar
+ corrections are not marked. Deleted questions will simply disappear,
+ as will any question that can be answered by "get the latest release".
+
+ Editorial comments are delimited by pairs of "[[" & "]]". They
+ contain either references to the (usually unfinished) nature of the
+ FAQ entry itself, version-specific comments to be removed (or
+ altered) when new revisions of CVS are released or snide remarks from
+ the editor.
+
+ If you plan to do anything with this document other than:
+
+ - Read it.
+ - Redistribute the whole document along with the date and revision.
+ - Post sections as answers to CVS questions (as long as you
+ identify it as coming from the FAQ.)
+
+ talk to the author first.
+
+
+
+============================================
+== Section 0 ==== Introduction ====
+============================================
+
+The questions in this document come from many sources in many forms. Some
+are simple, some verbose. A few are difficult, but all of them have been
+asked of the author at one time or another. Some questions are really
+three or more different problems rolled into one plaintive cry for help.
+Others reveal one of the bugs or weaknesses of CVS.
+
+CVS addresses some difficult problems to which there are no perfect
+solutions. CVS also changes over time as new features are required.
+
+Therefore, the questions are about a complicated moving target.
+
+Though in most cases I've tried to provide the simplest answer I can
+think of, some of the *questions* are difficult to follow. If you
+aren't using CVS regularly, don't expect to understand everything.
+
+A Frequently Asked Questions document is not a substitute for the man page
+or any other documentation. It is an attempt to answer questions.
+
+You should also keep in mind that FAQs are not really intended to be
+read in their entirety like a text book. You should use "grep" or
+your editor's search capability to hunt for keywords and read the
+sections you need.
+
+
+Questions are divided into five numbered Sections. Sections are divided
+into lettered sub-sections. The questions are numbered sequentially
+within each sub-section, though they are in no particular order.
+
+
+ 1. What is CVS?
+ A. What is CVS? What's it for? Why CVS?
+ B. Where do I find it? Where can I find Help?
+ C. How does CVS differ from other similar software?
+ D. What do you mean by . . .? (Definitions)
+
+ 2. User Tasks
+ A. Getting Started
+ B. Common User Tasks
+ C. Less Common User Tasks
+ D. General Questions
+
+ 3. Commands
+ A. through P. One section for each CVS command.
+
+ 4. Advanced Topics
+ A. Installing CVS
+ B. Setting up and Managing the Repository
+ C. Branching and Merging
+ D. Tricks of the Trade
+ E. Internal errors
+ F. Related Software
+ G. Engineering
+ H. Other Systems
+
+ 5. Past & Future
+ A. Contributors.
+ B. Bugs and Patches
+ C. Development
+ D. Professional Support
+
+ 6. Table of Contents
+
+
+Final note:
+
+ Except for the "Past & Future" section, all answers in this
+ document refer to CVS version 1.4. The latest released version is
+ 1.5.
+
+
+============================================
+== Section 1 ==== What is CVS? ====
+============================================
+
+----------------
+-- Section 1A -- What is CVS? What's it for? Why CVS?
+----------------
+
+ **** Questions:
+
+ 1A.1 What does CVS stand for? Can you describe it in one sentence?
+ 1A.2 What is CVS for? What does it do for me?
+ 1A.3 How does CVS work?
+ 1A.4 What is CVS useful for?
+ 1A.5 What is CVS *not* useful for?
+
+
+ **** Answers:
+
+ 1A.1 What does CVS stand for? Can you describe it in one sentence?
+
+ "CVS" is an acronym for the "Concurrent Versions System".
+
+ CVS is a "Source Control" or "Revision Control" tool
+ designed to keep track of source changes made by groups of
+ developers working on the same files, allowing them to
+ stay in sync with each other as each individual chooses.
+
+
+ 1A.2 What is CVS for? What does it do for me?
+
+ CVS is used to keep track of collections of files in a shared
+ directory called "The Repository". Each collection of files
+ can be given a "module" name, which is used to "checkout"
+ that collection.
+
+ After checkout, files can be modified (using your favorite
+ editor), "committed" back into the Repository and compared
+ against earlier revisions. Collections of files can be
+ "tagged" with a symbolic name for later retrieval.
+
+ You can add new files, remove files you no longer want, ask for
+ information about sets of files in three different ways,
+ produce patch "diffs" from a base revision and merge the
+ committed changes of other developers into your working files.
+
+
+ 1A.3 How does CVS work?
+
+ CVS saves its version-control information in RCS files stored in a
+ directory hierarchy, called the Repository, which is separate from
+ the user's working directory.
+
+ Files in the Repository are stored in a format dictated by the
+ RCS commands CVS uses to do much of its real work. RCS files
+ are standard byte-stream files with an internal format described
+ by keywords stored in the files themselves.
+
+ To begin work, you execute a "checkout" command, handing it a
+ module name or directory path (relative to the $CVSROOT variable)
+ you want to work on. CVS copies the latest revision of each file
+ in the specified module or directory out of the Repository and
+ into a directory tree created in your current directory. You may
+ specify a particular branch to work on by symbolic name if you
+ don't want to work on the default (main or trunk) branch.
+
+ You may then modify files in the new directory tree, build them
+ into output files and test the results. When you want to make
+ your changes available to other developers, you "commit" them back
+ into the Repository.
+
+ Other developers can check out the same files at the same time.
+ To merge the committed work of others into your working files
+ you use the "update" command. When your merged files build
+ and test correctly, you may commit the merged result. This
+ method is referred to as "copy-modify-merge", which does not
+ require locks on the source files.
+
+ At any time, usually at some milestone, you can "tag" the
+ committed files, producing a symbolic name that can be handed to a
+ future "checkout" command. A special form of "tag" produces a
+ branch in development, as usually happens at "release" time.
+
+ When you no longer plan to modify or refer to your local copy
+ of the files, they can be removed.
+
+
+ 1A.4 What is CVS useful for?
+
+ CVS is intended to handle source control for files in three major
+ situations:
+
+ 1. Multiple developers working on the same files.
+
+ The major advantage of using CVS over the simpler tools like
+ RCS or SCCS is that it allows multiple developers to work on
+ the same sources at the same time.
+
+ The shared Repository provides a rendezvous for committed
+ sources that allows developers a fair amount of flexibility in
+ how often to publish (via the "commit" command) changes or
+ include work committed by others (via the "update" command).
+
+
+ 2. Tracking a stream of releases from a source vendor.
+
+ If you are making changes to sources distributed by someone
+ else, the CVS feature, called the Vendor Branch, allows you to
+ combine local modifications with repeated vendor releases.
+
+ I have found this most useful when dealing with sources from
+ three major classes of source vendor:
+
+ a. Large companies who send you tapes full of the latest
+ release (e.g. Unix OS vendors, database companies).
+
+ b. Public Domain software which *always* requires work.
+
+ c. Pseudo-Public sources which may require work.
+ (e.g. GNU programs, X, CVS itself, etc.)
+
+
+ 3. Branching development.
+
+ Aside from the "Vendor Branch", there are three kinds of
+ "branches in development" that CVS can support:
+
+ a. Your working directory can be treated as a private branch.
+
+ b. A Development branch can be shared by one or more developers.
+
+ c. At release time, a branch is usually created for bug fixes.
+
+ (See 1D.9 and Section 4C for more info on branches.)
+
+ CVS's branch support is a bit primitive, but it was designed to
+ allow you to create branches, work on them for while and merge
+ them back into the main line of development. You should also
+ be able to merge work performed on the main branch into the
+ branch you are working on. Arbitrary sharing and merging
+ between branches is not currently supported.
+
+
+ 1A.5 What is CVS *not* useful for?
+
+ CVS is not a build system.
+
+ Though the structure of your Repository and modules file
+ interact with your build system (e.g. a tree of Makefiles),
+ they are essentially independent.
+
+ CVS does not dictate how you build anything. It merely stores
+ files for retrieval in a tree structure you devise.
+
+ CVS does not dictate how to use disk space in the checked out
+ working directories. If you require your Makefiles or build
+ procedures to know the relative positions of everything else,
+ you wind up requiring the entire Repository to be checked out.
+ That's simply bad planning.
+
+ If you modularize your work, and construct a build system
+ that will share files (via links, mounts, VPATH in Makefiles,
+ etc.), you can arrange your disk usage however you like.
+
+ But you have to remember that *any* such system is a lot of
+ work to construct and maintain. CVS does not address the
+ issues involved. You must use your brain and a collection
+ of other tools to provide a build scheme to match your plans.
+
+ Of course, you should use CVS to maintain the tools created to
+ support such a build system (scripts, Makefiles, etc).
+
+
+ CVS is not a substitute for management.
+
+ You and your project leaders are expected to plan what you are
+ doing. Everyone involved must be aware of schedules, merge
+ points, branch names, release dates and the range of
+ procedures needed to build products. (If you produce it and
+ someone else uses it, it is a product.) CVS can't cover for a
+ failure to manage your project.
+
+ CVS is an instrument for making sources dance to your tune.
+ But you are the piper and the composer. No instrument plays
+ itself or writes its own music.
+
+
+ CVS is not a substitute for developer communication.
+
+ When faced with conflicts within a single file, most
+ developers manage to resolve them without too much effort.
+ But a more general definition of "conflict" includes problems
+ too difficult to solve without communication between
+ developers.
+
+ CVS cannot determine when simultaneous changes within a single
+ file, or across a whole collection of files, will logically
+ conflict with one another. Its concept of a "conflict" is
+ purely textual, arising when two changes to the same base file
+ are near enough to spook the merge command into dropping
+ conflict markers into the merged file.
+
+ CVS is not capable of figuring out distributed conflicts in
+ program logic. For example, if you change the arguments to
+ function X defined in file A and, at the same time, edit file
+ B, adding new calls to function X using the old arguments.
+ You are outside the realm of CVS's competence.
+
+ Acquire the habit of reading specs and talking to your peers.
+
+
+ CVS is not a configuration management system.
+
+ CVS is a source control system. The phrase "configuration
+ management" is a marketing term, not an industry-recognized
+ set of functions.
+
+ A true "configuration management system" would contain
+ elements of the following:
+
+ * Source control.
+ * Dependency tracking.
+ * Build systems (i.e. What to build and how to find
+ things during a build. What is shared? What is local?)
+ * Bug tracking.
+ * Automated Testing procedures.
+ * Release Engineering documentation and procedures.
+ * Tape Construction.
+ * Customer Installation.
+ * A way for users to run different versions of the same
+ software on the same host at the same time.
+
+ CVS provides only the first.
+
+
+
+----------------
+-- Section 1B -- Where do I find CVS? Where can I find Help?
+----------------
+
+ **** Questions:
+
+ 1B.1 How do I get more information about CVS?
+ 1B.2 Is there an archive of CVS material?
+ 1B.3 How do I get files out of the archive if I don't have FTP?
+ 1B.4 How do I get a copy of the latest version of CVS?
+ 1B.5 Is there a mailing list devoted to CVS? How do I find it?
+ 1B.6 What happened to the CVS Usenet newsgroup I heard about?
+
+
+ **** Answers:
+
+ 1B.1 How do I get more information about CVS?
+
+ 1. The first thing I would do is to read the Info file that comes
+ with the CVS sources under "doc". You can format and read the
+ cvs.texinfo file in two ways: 1. Use TeX to format it and a
+ "dvips" command to print it and 2. Install the cvs.info files
+ that are created by the Makefile and read them online using the
+ Emacs "info-mode" or a stand-alone "info" reader.
+
+ 2. Then I'd run "cvsinit" to set up a Repository and read the man
+ page while trying out the commands.
+
+ Type "cvs -H" for general help or "cvs -H command" for
+ command-specific help.
+
+ 3. For background, you can read the original CVS paper (in the
+ source tree, under "doc"). It describes the purpose of CVS and
+ some of how it was designed. Note that the emphasis of the
+ document (especially on multiple vendors providing the same
+ sources) is somewhat out of date.
+
+ 4. For more detailed information about "internals", read the man
+ pages for RCS. If you are a programmer, you can also read the
+ source code to CVS.
+
+ 5. Other information and tutorials may be available in the "doc"
+ directory of the FTP archive described below.
+
+ 6. For current information, and a fair amount of detail, join the
+ info-cvs mailing list described below.
+
+
+ 1B.2 Is there an archive of CVS material?
+
+ An anonymous FTP area has been set up. It contains many of the
+ CVS files you might want, including extra documentation, patches
+ and a copy of the latest release.
+
+ ftp ftp.delos.com
+ >>> User: anonymous
+ >>> Passwd: <Your Internet address>
+ cd /pub/cvs
+ get README
+ get Index
+
+ The README has more (and more up-to-date) information. The Index
+ contains a terse list of what is in the archive.
+
+ A WWW home page is also available at http://www.delos.com/cvs.
+
+
+ 1B.3 How do I get files out of the archive if I don't have FTP?
+
+ Use one of the FTP<->Email servers. These are the ones
+ I've been told about:
+
+
+ 1. FTPMAIL service is available from the same host as the FTP
+ server described above. Send mail to "ftpmail@delos.com"
+ containing "help" in the body of the message. For example,
+ on most Unix systems, you can type:
+
+ echo help | Mail ftpmail@delos.com
+
+ The FTPMAIL server will respond with a document describing how
+ to use the server. If the "Mail" command doesn't exist on your
+ system, try "mailx", "/usr/ucb/mail" or "/bin/mail".
+
+
+ 2. If you are on BITNET, use Princeton's BITFTP server. Type
+
+ echo 'send help' | Mail bitftp@pucc.princeton.edu
+
+ (It is likely that only BITNET addresses can use this one.)
+
+
+ 3. Other possibilities I've heard of from the net:
+ (Try the one closest to you.)
+
+ ftpmail@decwrl.dec.com
+ ftpmail@sunsite.unc.edu
+ ftpmail@cs.arizona.edu
+ ftpmail@cs.uow.edu.au
+ ftpmail@doc.ic.ac.uk
+
+
+ 1B.4 How do I get a copy of the latest version of CVS?
+
+ The latest released version of CVS and all the programs it
+ depends on should be available through anonymous FTP on any FSF
+ archive. The main FSF archive is at "prep.ai.mit.edu". There are
+ mirrors of the FSF archive on UUNET and other large Internet sites.
+
+ Program(s) Suggested revision
+ ----------- -----------------------
+ CVS 1.5
+ RCS 5.7 (latest version available today)
+ GNU diff 2.7 (or later) [contained in diffutils-2.7]
+ GDBM 1.5 (or later) [optional]
+
+ The GNU version of diff is suggested by both the RCS and CVS
+ configuration instructions because it works better than the
+ standard version.
+
+ It is a good idea not to accept the versions of CVS, RCS or diff
+ you find lying on your system unless you have checked out their
+ provenance. Using inconsistent collections of tools can cause you
+ more trouble than you can probably afford.
+
+ The FTP archive mentioned above should contain the latest official
+ release of CVS, some official and unofficial patches and possibly
+ complete patched versions of CVS in use somewhere.
+
+
+ 1B.5 Is there a mailing list devoted to CVS? How do I find it?
+
+ An Internet mailing list named "info-cvs" grew out of the private
+ mailing list used by the CVS 1.3 alpha testers in early 1992.
+ Throughout 1994, the list received an average of 100 messages per
+ month.
+
+ You can add yourself to the mailing list by sending an Email
+ message to:
+
+ info-cvs-request@prep.ai.mit.edu
+
+ (Don't forget the "-request" or you'll send a message to the
+ whole list, some of whom are capable of remote execution.)
+
+ Mail to the whole list should be sent to:
+
+ info-cvs@prep.ai.mit.edu
+
+ An archive of the mailing list is maintained in the FTP archive
+ mentioned above.
+
+
+ 1B.6 What happened to the CVS Usenet newsgroup I heard about?
+
+
+ A Usenet newsgroup named "gnu.cvs.info" was announced in April
+ 1993, with an expected creation date of August, 1993.
+
+ As of this writing (October, 1994) it hasn't appeared.
+
+ If the newsgroup is ever created, it and the mailing list should
+ be bidirectionally gatewayed, meaning that you only need access to
+ one of them. Anything sent to the mailing list would be
+ automatically posted to "gnu.cvs.info" and anything posted to the
+ newsgroup would be automatically mailed to "info-cvs".
+
+ A newsgroup would be easier to use than a mailing list. If the
+ CVS newsgroup ever shows up, ask your system administrator whether
+ you get the "gnu" hierarchy. If so, select a news reader and dive
+ in.
+
+
+----------------
+-- Section 1C -- How does CVS differ from other, similar software?
+----------------
+
+This section attempts to list programs purporting to cover some of the
+same territory as CVS. [[These are very sparsely documented here. If you
+know something about one of these tools, how about trying to flesh out an
+entry or two?]]
+
+
+ **** Questions:
+
+ 1C.1 How does CVS differ from RCS?
+ 1C.2 How does CVS differ from SCCS?
+ 1C.3 How does CVS differ from ClearCase?
+#1C.4 How does CVS differ from TeamWare/SparcWorks?
+ 1C.5 How does CVS differ from Aegis?
+ 1C.6 How does CVS differ from Shapetools?
+ 1C.7 How does CVS differ from TeamNet?
+ 1C.8 How does CVS differ from ProFrame?
+ 1C.9 How does CVS differ from CaseWare/CM?
+ 1C.10 How does CVS differ from Sublime?
+ 1C.11 How does CVS differ from PVCS?
+ 1C.12 How does CVS differ from CMVC?
+
+
+ **** Answers:
+
+
+ 1C.1 How does CVS differ from RCS?
+
+ CVS uses RCS to do much of its work and absolutely all the work
+ of changing the underlying RCS files in the Repository.
+
+ RCS comprises a set of programs designed to keep track of changes
+ to individual files. Of course, it also allows you to refer to
+ multiple files on the command line, but they are handled by
+ iterating over individual files. There is no pretense of
+ coordinated interaction among groups of files.
+
+ CVS's main intent is to provide a set of grouping functions that
+ allow you to treat a collection of RCS files as a single object.
+ Of course, CVS also has to do a lot of iteration, but it tries
+ its best to hide that it is doing so. In addition, CVS has some
+ truly group-oriented facets, such as the modules file and the CVS
+ administrative files that refer to a whole directory or module.
+
+ One group aspect that can be a bit confusing is that a CVS branch
+ is not the same as an RCS branch. To support a CVS branch, CVS
+ uses "tags" (what RCS calls "symbols") and some local state,
+ in addition to RCS branches.
+
+ Other features offered by CVS that are not supported directly by
+ RCS are
+
+ 1. Automatic determination of the state of a file, (e.g.
+ modified, up-to-date with the Repository, already tagged
+ with the same string, etc.) which helps in limiting the
+ amount of displayed text you have to wade through to
+ figure out what changed and what to do next.
+
+ 2. A copy-modify-merge scheme that avoids locking the files
+ and allows simultaneous development on a single file.
+
+ 3. Serialization of commits. CVS requires you to merge all
+ changes committed (via "update") since you checked out
+ your working copy of the file. Although it is still
+ possible to commit a file filled with old data, it is less
+ likely than when using raw RCS.
+
+ 4. Relatively easy merging of releases from external Vendors.
+
+
+ 1C.2 How does CVS differ from SCCS?
+
+ SCCS is much closer to RCS than to CVS, so some of the previous
+ entry applies.
+
+ You might want to take a look at Walter Tichy's papers on RCS,
+ which are referred to in the RCS man pages.
+
+ [[More info here?]]
+
+
+ 1C.3 How does CVS differ from ClearCase?
+
+ ClearCase is a distributed client-server version control system.
+ ClearCase is a variant DSEE tools, formerly available on Apollo
+ platforms. The ClearCase tool set includes a few X-based
+ interface tools, a command-line interface, and C programmer API.
+ It is currently available on Sun, HP, SGI and OSF/1 platforms.
+
+ ClearCase uses a special Unix filesystem type, called "mvfs"
+ for "multi-version file system". Conceptually, mvfs adds
+ another dimension to a regular Unix filesystem. The new
+ axis is used to store the different versions of files and to
+ provide a tree-hierarchical view of a collection of objects that
+ might be scattered across any number of separate hosts on your
+ local network.
+
+ Each user acquires a "view" into the file database by creating a
+ special mvfs mount point on their machine. Each view has a
+ "configuration spec" containing a set of selection rules that
+ specify the particular version of each file to make visible in
+ that view. You can think of a "view" as a work area in CVS, except
+ that the files don't really exist on your local disk until you
+ modify them. This technique conserves disk space because it
+ doesn't keep private copies of read-only files.
+
+ Another advantage is that a view is "transparent" in the sense that
+ all of the files in a "view" appear to be regular Unix files to
+ other tools and Unix system calls. An extended naming convention
+ allows access to particular versions of a file directly:
+ "test.cc@@/main/bugfix/3" identifies the third version of test.c
+ on the bugfix branch.
+
+ ClearCase supports both the copy-modify-merge model of CVS (by
+ using what are called "unreserved checkouts" and the
+ checkin/checkout development model with file locking. Directories
+ are version-controlled objects as well as files. A graphical merge
+ tool is provided. Like RCS, ClearCase supports branches, symbolic
+ tags, and delta compression. ASCII as well as binary files are
+ supported, and converters from RCS, SCCS, DSEE formats are also
+ included.
+
+ A make-compatible build facility is provided that can identify
+ common object code and share it among developers. A build
+ auditing feature automatically records file dependencies by
+ tracking every file that is opened when producing a derived
+ object, thus making explicit dependency lists unnecessary. Pre-
+ and post-event triggers are available for most ClearCase
+ operations to invoke user programs or shell scripts. User-defined
+ attributes can be assigned to any version or object. Hyper-links
+ between version controlled objects can record their relationship.
+
+ For more information, contact:
+
+ Atria Software, Inc.
+ 24 Prime Park Way
+ Natick, MA 01760
+ info@atria.com
+
+ (508) 650-1193 (phone)
+ (508) 650-1196 (fax)
+
+ Originally contributed by Steve Turner
+ Edited by the author of this FAQ.
+
+
+#1C.4 How does CVS differ from TeamWare/SparcWorks?
+
+ TeamWare is a configuration management tool from Sun Microsystems,
+ a part of SparcWorks. It uses the same copy and merge model as
+ CVS. The central abstraction is a workspace, which corresponds to
+ either a CVS branch or a checked out module. TeamWare allows you
+ to manipulate workspaces directly, including moving and merging
+ code between workspaces. You can put your workspace on tape and
+ continue to work with it at home, just like you can with CVS.
+ TeamWare is built upon and compatible with SCCS.
+
+ TeamWare provides both a command line interface and a graphical
+ interface. The CodeManager tool will display the project as a
+ tree of workspaces, and allows you to manipulate them with drag
+ and drop. The other tools are VersionTool that displays and
+ manipulates a dag with a version history of a single file,
+ CheckPoint that will create symbolic tags, MakeTool, a make
+ compatible tool with a GUI, and FileMerge which will interactively
+ merge files when needed (like emerge for emacs). If you have a
+ sun, you can try /usr/old/mergetool for an old SunView version of
+ FileMerge.
+
+ Email: sunprosig@sun.com
+
+ Originally extracted from TeamWare
+ Marketing literature by Per Abrahamsen.
+ Edited by the author of this FAQ.
+
+
+ For more information, contact:
+
+ SunExpress, Inc.
+ P.O. Box 4426
+ Bridgeton, MO 63044-9863
+ (800)873-7869
+
+
+ 1C.5 How does CVS differ from Aegis?
+
+ Aegis appears to be a policy-setting tool that allows you to use
+ other sub-programs (make, RCS, etc.) to implement pieces of the
+ imposed policy.
+
+ The initial document seems to say that most Unix tools are
+ inadequate for use under Aegis.
+
+ It is not really similar to CVS and requires a different mindset.
+
+ [[Need more info here.]]
+
+
+ 1C.6 How does CVS differ from Shapetools?
+
+ Shapetools includes a build mechanism (called Shape, not
+ surprisingly) that is aware of the version mechanism, and some
+ dependency tracking. It is based on a file system extension
+ called Attributed File System, which allows arbitrary-sized
+ "attributes" to be associated with a file. Files are version
+ controlled in a manner similar to RCS. Configurations are managed
+ through the Shapefile, an extension of the Makefile syntax and
+ functionality. Shape includes version selection rules to allow
+ sophisticated selection of component versions in a build.
+
+ Shapetools' concurrency control is pessimistic, in contrast to
+ that of CVS. Also, there's very limited support for branching and
+ merging. It has a built-in policy for transitioning a system from
+ initial development to production.
+
+ Contributed by Don Dwiggins
+
+
+ 1C.7 How does CVS differ from TeamNet?
+
+ TeamNet is a configuration management tool from TeamOne.
+
+ For more information, contact:
+
+ TeamOne
+ 710 Lakeway Drive, Ste 100
+ Sunnyvale, CA 94086
+ (800) 442-6650
+
+ Contributed by Steve Turner
+
+
+ 1C.8 How does CVS differ from ProFrame?
+
+ ProFrame is a new system integration framework from IBM.
+ ProFrame is compliant with the CFI (CAD Framework Initiative)
+ industry standards, including the Scheme extension language.
+
+ ProFrame consists of three major components: (1) the Process
+ Manager that automates your local design methodology (2) the
+ Design Data Manager handles configuration management, and (3)
+ Inter-tool Communication to provide a communication path among
+ tools running on heterogeneous servers.
+
+ The Design Data Manager(2) is probably the appropriate
+ component to compare to CVS. The Design Data Manager provides
+ version control with checkin/checkout capability,
+ configuration management, and data dependency tracking. A
+ graphical data selection interface is provided. Using this
+ interface, you may create and manipulate objects and hierarchy
+ structures, view the revision history for an object, and view
+ and assign attributes to a design object.
+
+ The ProFrame server currently runs only on RS6000, but clients
+ may be a wide variety of Unix platforms. Contact IBM for the
+ latest platform information.
+
+ For more information, contact:
+
+ IBM
+ EDA Marketing and Sales
+ P.O. Box 950, M/S P121
+ Poughkeepsie, NY 12602
+ (800) 332-0066
+
+
+ Contributed by Steve Turner
+ [extracted from the ProFrame 1.1.0 datasheet]
+
+
+ 1C.9 How does CVS differ from CaseWare/CM?
+
+ CaseWare/CM is a software configuration management product
+ from CaseWare, Inc. CaseWare/CM may be customized to support
+ a wide variety of methodologies, including various phases of
+ the software lifecycle, and different access rights for users.
+
+ A GUI is provided to view version histories and
+ configurations. A merge tools is also included. CaseWare
+ supports type-specific lifecycles, which allows different types
+ of files to move through different lifecycles. Also provided
+ is a build facility to support automatic dependency analysis,
+ parallel, distributed, and remote builds, and variant
+ releases.
+
+ CaseWare/CM has been integrated with other CASE tools,
+ including FrameMaker, ALSYS Ada, CodeCenter/Object Center, HP
+ SoftBench, and Software Through Pictures. CaseWare also
+ offers CaseWare/PT, a problem tracking system to integrate
+ change requests with configuration management.
+
+ Multiple vendors and operating systems are supported.
+
+ For more information, contact:
+
+ CaseWare, Inc.
+ 108 Pacifica, 2nd Floor
+ Irvine, CA 92718-3332
+ (714) 453-2200 (phone)
+ (714) 453-2276 (fax)
+
+ Contributed by Steve Turner
+ [extracted from the CaseWare/CM data sheet]
+
+
+ 1C.10 How does CVS differ from Sublime?
+
+ Produced by AT&T.
+
+ [[Need more info here.]]
+
+
+ 1C.11 How does CVS differ from PVCS?
+
+ PVCS works on single files like RCS and SCCS, CVS works on
+ complete subsystems. PVCS has a make utility (called a
+ configuration builder), CVS does not. PVCS has a GUI interface
+ for Unix, DOS, OS/2, and MS Windows.
+
+ Intersolv, Inc.
+ 1700 NW 167th Place
+ OR 97006
+
+ Contributed by Per Abrahamsen
+ [Extracted from Intersolv Marketing literature.]
+
+
+ 1C.12 How does CVS differ from CMVC?
+
+ CMVC is an IBM Configuration Management and Version Control
+ system. (Though I'm not certain that's the right acronym
+ expansion.) It runs on Suns, HPs, RS6000s, OS/2 and Windows.
+
+ Other than revision control, it apparently has features to manage
+ releases, bug tracking and the connection between alterations and
+ reported bugs and feature requests. It is a client/server system,
+ based on a choice of commercial Relational Database systems, and
+ it provides a Motif or command line interface.
+
+ Unlike CVS, it uses a strict locking protocol to serialize source
+ code alterations.
+
+
+----------------
+-- Section 1D -- What do you mean by . . .? (Definitions)
+----------------
+
+ **** Questions:
+
+ 1D.1 What are "The Repository", "$CVSROOT" and "CVSROOT"?
+ 1D.2 What is an RCS file?
+ 1D.3 What is a working file?
+ 1D.4 What is a working directory (or working area)?
+ 1D.5 What is "checking out"?
+ 1D.6 What is a revision?
+ 1D.7 What is a "Tag"?
+ 1D.8 What are "HEAD" and "BASE"?
+ 1D.9 What is a Branch?
+ 1D.10 What is "the trunk"?
+ 1D.11 What is a module?
+ 1D.12 What does "merge" mean?
+
+
+ **** Answers:
+
+
+ 1D.1 What are "The Repository", "$CVSROOT" and "CVSROOT"?
+
+ The Repository is a directory tree containing the CVS
+ administrative files and all the RCS files that constitute
+ "imported" or "committed" work. The Repository is kept in a
+ shared area, separate from the working areas of all developers.
+
+ Users of CVS must set their "CVSROOT" environment variable to the
+ absolute pathname of the head of the Repository. Most command
+ line interpreters replace an instance of "$CVSROOT" with the value
+ of the "CVSROOT" environment variable. By analogy, in this
+ document "$CVSROOT" is used as shorthand for "the absolute
+ pathname of the directory at the head of the Repository".
+
+ One of the things found in $CVSROOT is a directory named CVSROOT.
+ It contains all the "state", the administrative files, that CVS
+ needs during execution. The "modules", "history", "commitinfo",
+ "loginfo" and other files can be found there. See 4B.2 for more
+ information about CVSROOT files.
+
+
+ 1D.2 What is an RCS file?
+
+ An RCS file is a text file containing the source text and the
+ revision history for all committed revisions of a source file. It
+ is stored separately from the working files, in a directory
+ hierarchy, called the Repository.
+
+ RCS is the "Revision Control System" that CVS uses to manage
+ individual files. RCS file names normally end in ",v", but
+ that can be altered (via the RCS -x option) to conform to file
+ naming standards on platforms with unusual filename limitations.
+
+
+ 1D.3 What is a working file?
+
+ A working file is a disk file containing a checked-out copy of a
+ source file that earlier had been placed under CVS. If the
+ working file has been edited, the changes since the last committed
+ revision are invisible to other users of CVS.
+
+
+ 1D.4 What is a working directory (or working area)?
+
+ A working directory is the place where you work and the place
+ from which you "commit" files.
+
+ The "checkout" command creates a tree of working directories,
+ filling them with working files. Each working directory contains
+ a sub-directory named ./CVS containing three administrative files,
+ which are created by "checkout" and are always present:
+
+ ./CVS/Entries
+ contains information about working files.
+
+ ./CVS/Repository
+ contains the location of the directory within the
+ Repository that was used to create the working directory.
+
+ ./CVS/Root
+ contains the value of $CVSROOT at the time you created
+ the working directory.
+
+ Other files may also appear in ./CVS depending on the state of
+ your working directory:
+
+ ./CVS/Tag
+ contains the "sticky tag" associated with the whole
+ directory. See 3A.2 for its main purpose.
+ [Created by "checkout" or "update" when using "-r <tag>".]
+ [Deleted by "checkout" or "update" when using '-A'.]
+
+ ./CVS/Entries.Static
+ contains a fixed list of working files. If this file
+ exists, an "update" doesn't automatically bring newly
+ added files out of the Repository.
+ [Created and maintained by hand.]
+
+ ./CVS/Checkin.prog
+ contains a program to run whenever anything in the
+ working directory is committed.
+ [Created by checkout if "-i <prog>" appears in the
+ modules file for the checked-out module.]
+
+ ./CVS/Update.prog
+ contains a program to run whenever anything in the
+ working directory is updated.
+ [Created by checkout if "-u <prog>" appears in the
+ modules file for the checked-out module.]
+
+ ./CVS/<file>,p
+ ./CVS/<file>,t
+ contain (possibly zero-length) state information about an
+ "add" that has not been committed.
+ [Created by "add".]
+ [Deleted by "commit" or "remove".]
+
+
+ 1D.5 What is "checking out"?
+
+ "Checking out" is the act of using the "checkout" command to
+ copy a particular revision from a set of RCS files into your
+ working area. You normally execute "checkout" only once per
+ working directory (or tree of working directories), maintaining
+ them thereafter with the "update" command.
+
+ See section 3C on the "checkout" command.
+
+
+ 1D.6 What is a revision?
+
+ A "revision" is a version of a file that was "committed"
+ ("checked in", in RCS terms) some time in the past. CVS (and
+ RCS) can retrieve any file that was committed by specifying its
+ revision number or its "tag" ("symbolic name", in RCS terms).
+
+ In CVS, a "tag" is more useful than a revision number. It usually
+ marks a milestone in development represented by different revision
+ numbers in different files, all available as one "tagged"
+ collection.
+
+ Sometimes the word "revision" is used as shorthand for "the file
+ you get if you retrieve (via "checkout" or "update") the given
+ revision from the Repository."
+
+
+ 1D.7 What is a "Tag"?
+
+ A "Tag" is a symbolic name, a synonym or alias for a
+ particular revision number in a file. The CVS "tag" command
+ places the same "Tag" on all files in a working directory,
+ allowing you to retrieve those files by name in the future.
+
+ The CVS "Tag" is implemented by applying RCS "symbols" to each
+ individual file. The Tags on a file (or collection of files) may
+ be displayed using the "log" command.
+
+
+ 1D.8 What are "HEAD" and "BASE"?
+
+ HEAD and BASE are built-in tags that don't show up in the "log"
+ or "status" listings. They are interpreted directly by CVS.
+
+ "HEAD" refers to the latest revision on the current branch in the
+ Repository. The current branch is either the main line of
+ development, or a branch in development created by placing a
+ branch tag on a set of files and checking out that branch.
+
+ "BASE" refers to the revision on the current branch you last
+ checked out, updated, or committed. If you have not modified
+ your working file, "BASE" is the committed revision matching it.
+
+ Most of the time BASE and HEAD refer to the same revision. They
+ can become different in two ways:
+
+ 1. Someone else changed HEAD by committing a new revision of your
+ file to the Repository. You can pull BASE up to equal HEAD by
+ executing "update".
+
+ 2. You moved BASE backward by executing "checkout" or "update"
+ with the option "-r <rev/tag>" or "-D <date>". CVS records a
+ sticky tag and moves your files to the specified earlier
+ revision. You can clear the sticky tag and pull BASE up to
+ equal HEAD again by executing "update -A".
+
+
+ 1D.9 What is a Branch?
+
+ In general, a branch is any mechanism that allows one or more
+ developers to modify a file without affecting anyone other than
+ those working on the same branch.
+
+ There are four kinds of "branch" CVS can manage:
+
+ 1. The Vendor Branch.
+
+ A single vendor branch is supported. The "import" command
+ takes a sequence of releases from a source code vendor (called
+ a "vendor" even if no money is involved), placing them on a
+ special "Vendor" branch. The Vendor branch is considered part
+ of the "Main line" of development, though it must be merged
+ into locally modified files on the RCS Main branch before the
+ "import" is complete.
+
+ See Section 3H ("import").
+
+ 2. Your Working directory.
+
+ A checked-out working directory, can be treated like a private
+ branch. No one but you can touch your files. You have
+ complete control over when you include work committed by
+ others. However, you can't commit or tag intermediate versions
+ of your work.
+
+ 3. A Development branch.
+
+ A group of developers can share changes among the group,
+ without affecting the Main line of development, by creating a
+ branch. Only those who have checked-out the branch see the
+ changes committed to that branch. This kind of branch is
+ usually temporary, collapsing (i.e. merge and forget) into the
+ Main line when the project requiring the branch is completed.
+
+ You can also create a private branch of this type, allowing an
+ individual to commit (and tag) intermediate revisions without
+ changing the Main line. It should be managed exactly like a
+ Development Branch -- collapsed into the Main line (or its
+ parent branch, if that is not the Main Branch) and forgotten
+ when the work is done.
+
+ 4. A Release branch.
+
+ At release time, a branch should be created marking what was
+ released. Later, small changes (sometimes called "patches")
+ can be made to the release without including everything else on
+ the Main line of development. You avoid forcing the customer
+ to accept new, possibly untested, features added since the
+ release. This is also the way to correct bugs found during
+ testing in an environment where other developers have continued
+ to commit to the Main line while you are testing and packaging
+ the release.
+
+ Although the internal format of this type of branch (branch tag
+ and RCS branches) is the same as in a development branch, its
+ purpose and the way it is managed are different. The major
+ difference is that a Release branch is normally Permanent.
+ Once you let a release out the door to customers, or to the
+ next stage of whatever process you are using, you should retain
+ forever the branch marking that release.
+
+ Since the branch is permanent, you cannot incorporate the
+ branch fixes into the Main line by "collapsing" (merging and
+ forgetting) the release branch. For large changes to many
+ files on the release branch, you will have to perform a branch
+ merge using "update -j <rev> -j <rev>". (See 4C.7)
+
+ The most common way to merge small changes back into Main line
+ development is to make the change in both places
+ simultaneously. This is faster than trying to perform a
+ selective merge.
+
+ See 1D.12 (merges) and Section 4C, on Branching for more info.
+
+
+ 1D.10 What is "the trunk"?
+
+ Another name for the RCS Main Branch. The RCS Main Branch is
+ related, but not equivalent, to both the CVS Main branch and what
+ developers consider to be the Main line of development.
+ See 3H.3 and Section 4C on Branching.
+
+
+ 1D.11 What is a module?
+
+ In essence, a module is a name you hand to the "checkout" command
+ to retrieve one or more files to work on. It was originally
+ intended to be a simple, unique name in the "modules" file
+ attached to a directory or a subset of files within a directory.
+
+ The module idea is now a somewhat slippery concept that can be
+ defined in two different ways:
+
+ A. A module is an argument to "checkout". There are three types:
+
+ 1. An entry in the modules file. A "module" name as described
+ in 'B.' below.
+
+ 2. A relative path to a directory or file in the Repository.
+
+ 3. A mixed-mode string of "modulename/relative-path".
+ Everything up to the first slash ('/') is looked up as a
+ module. The relative path is appended to the directory
+ associated with the module name and the resulting path is
+ checked out as in #2 above.
+
+
+ B. A module is a unique (within the file) character string in the
+ first column of the modules file. There are five types:
+
+ 1. A name for a directory within the Repository that
+ allows you to ignore the parent directories above it.
+
+ Example:
+
+ emacs gnu/emacs
+
+
+ 2. A name for a subset of the files within such a directory.
+
+ Example:
+
+ ls unix/bin Makefile ls.c
+
+ The 2nd through Nth strings in the above can be files,
+ directories or module substitutions. No relative paths.
+
+ A module substitution occurs when you use a '&module-name'
+ reference. The module-name referred to is logically
+ substituted for the '&module-name' string.
+
+
+ 3. A relative pathname to a directory within the Repository
+ which, when checked out, creates an image of part of the
+ Repository structure in your current directory.
+
+ Example:
+
+ gnu/emacs -o /bin/emacs.helper gnu/emacs
+
+ The files checked out are exactly the same as the files
+ "checkout" would retrieve if the path weren't even in the
+ modules file. The only reason to put this kind of relative
+ pathname into the modules file is to hook one of the helper
+ functions onto it.
+
+
+ 4. A relative pathname to a single file within the Repository
+ which, when checked out, creates something you probably
+ don't want: It creates a directory by the name of the file
+ and puts the file in it.
+
+ Example:
+
+ gnu/emacs/Makefile -o /bin/emacs.helper gnu/emacs Makefile
+
+ The file checked out is the same as what you would get if
+ you handed the relative pathname to the "checkout" command.
+ But it puts it in a strange place. The only reason to do
+ this is to hook a helper function onto a specific file name.
+
+
+ 5. An alias consisting of a list of any of the above, including
+ other aliases, plus exceptions.
+
+ Example:
+
+ my_work -a emacs !emacs/tests gnu/bison unix/bin/ls.c
+
+
+ The exception "!emacs/test" above is functionally equivalent
+ to specifying "!emacs/tests" on the "checkout" command line.
+
+
+ Another way to look at it is that the modules file is simply
+ another way to "name" files. The hierarchical directory
+ structure provides another. You should use whatever turns out to
+ be simplest for your development group.
+
+ See 4G.2 for some specific ideas about how to use the modules file.
+
+
+ 1D.12 What does "merge" mean?
+
+ A merge is a way of combining changes made in two independent
+ copies of a common starting file. Checking out an RCS revision
+ produces a file, so for the purposes of a merge "file" and
+ "revision" are equivalent. So, we can say there are always three
+ "files" involved in a merge:
+
+ 1. The original, starting, "base" or "branch point" file.
+ 2. A copy of the base file modified in one way.
+ 3. Another copy of the base file modified in a different way.
+
+ Humans aren't very good at handling three things at once, so the
+ terminology dealing with merges can become strained. One way to
+ think about it is that all merges are performed by inserting the
+ difference between a base revision and a later revision (committed
+ by someone else) into your working file. Both the "later"
+ revision and your working file are presumed to have started life
+ as a copy of the "base" revision.
+
+ In CVS, there are three main types of "merge":
+
+ 1. The "update" command automatically merges revisions committed
+ by others into your working file. In this case, the three
+ files involved in the merge are:
+
+ Base: The revision you originally checked out.
+ Later: A revision committed onto the current branch
+ after you checked out the Base revision.
+ Working: Your working file. The one lying in the working
+ directory containing changes you have made.
+
+ 2. The "update -j <branch_tag> {optional files}" command merges
+ changes made on the given branch into your working files, which
+ is presumed to be on the Main line of development.
+
+ See 4C.6
+
+ 3. The "update -j <rev> -j <rev> {optional files}" command merges
+ the difference between two specified revisions into files in
+ your working directory. The two revisions <rev> are usually on
+ the same branch and, when updating multiple files, they are
+ most useful when they are Tag names rather than numeric
+ revisions.
+
+ See 4C.7
+
+
+
+
+==========================================
+== Section 2 ==== User Tasks ====
+==========================================
+
+----------------
+-- Section 2A -- Getting Started
+----------------
+
+ **** Questions:
+
+ 2A.1 What is the first thing I have to know?
+ 2A.2 Where do I work?
+ 2A.3 What does CVS use from my environment?
+ 2A.4 OK, I've been told that CVS is set up, my module is named
+ "ralph" and I have to start editing. What do I type?
+ 2A.5 I have been using RCS for a while. Can I convert to CVS without
+ losing my revision history? How about converting from SCCS?
+
+
+ **** Answers:
+
+ 2A.1 What is the first thing I have to know?
+
+ Your organization has most likely assigned one or more persons to
+ understand, baby-sit and administer the CVS programs and the data
+ Repository. I call these persons Repository Administrators. They
+ should have set up a Repository and "imported" files into it.
+
+ If you don't believe anyone has this responsibility, or you are
+ just testing CVS, then *you* are the Repository Administrator.
+
+ If you are a normal user of CVS ask your Repository Administrator
+ what module you should check out.
+
+ Then you can work.
+
+ If you *are* the Repository Administrator, you will want to read
+ everything you can get your hands on, including this FAQ. Source
+ control issues can be difficult, especially when you get to
+ branches and release planning. Expect to feel stupid for a few
+ days/weeks.
+
+ No tool in the universe avoids the need for intelligent
+ organization. In other words, there are all sorts of related
+ issues you will probably have to learn. Don't expect to dive in
+ without any preparation, stuff your 300 Megabytes of sources into
+ CVS and expect to start working. If you don't prepare first, you
+ will probably spend a few sleepless nights.
+
+
+ 2A.2 Where do I work?
+
+ Wherever you have disk space. That's one of the advantages of
+ CVS: you use the "checkout" command to copy files from the
+ Repository to your working directory, which can be anywhere you
+ have the space.
+
+ Your local group might have conventions for where to work.
+ Ask your peers.
+
+
+ 2A.3 What does CVS use from my environment?
+
+ You must set two environment variables. Some shells share these
+ variables with local shell variables using a different syntax.
+ You'll have to learn how your shell handles them.
+
+ Variable Value (or action)
+ --------- ---------------------
+ CVSROOT Absolute pathname of the head of your Repository.
+
+ PATH Normally set to a list of ':'-separated directory
+ pathnames searched to find executables. You must
+ make sure "cvs" is in one of the directories.
+
+ If your CVS was built with the RCSBIN directory set
+ to null (""), and you don't set the RCSBIN
+ variable mentioned below, then the RCS commands
+ also must be somewhere in your PATH.
+
+
+ Optional variables: (Used if set, but ignored otherwise.)
+
+ Variable Value (or action)
+ --------- ---------------------
+ CVSEDITOR The name of your favorite fast-start editor
+ program. You'll be kicked into your editor to
+ supply revision comments if you don't specify them
+ via -m "Log message" on the command line.
+
+ EDITOR Used if CVSEDITOR doesn't exist. If EDITOR
+ doesn't exist, CVS uses a configured constant,
+ usually, "vi".
+
+ CVSREAD Sets files to read-only on "checkout".
+
+ RCSBIN Changes where CVS finds the RCS commands.
+
+ CVSIGNORE Adds to the ignore list. See Section 2D.
+
+
+ Other variables used by CVS that are normally set upon login:
+
+ Variable Value (or action)
+ --------- ---------------------
+ LOGNAME Used to find the real user name.
+
+ USER Used to find the real user name if no LOGNAME.
+
+ HOME Used to determine your home directory, if set.
+ Otherwise LOGNAME/USER/getuid() are used to find
+ your home directory from the passwd file.
+
+ TMPDIR Used during import. It might also be used if your
+ platform's version of mktemp(3) is unusual, or
+ you have changed the source to use tmpnam(3).
+
+
+
+ 2A.4 OK, I've been told that CVS is set up, my module is named
+ "ralph" and I have to start editing. What do I type?
+
+ cd <where you have some space to work>
+ cvs checkout ralph
+ cd ralph
+
+ And hack away.
+
+
+ 2A.5 I have been using RCS for a while. Can I convert to CVS without
+ losing my revision history? How about converting from SCCS?
+
+ If you are asking such questions, you are not a mere user of CVS,
+ but one of its Administrators! You should take a look at Section
+ 4A, "Installing CVS" and Section 4B, "Setting up and Managing
+ the Repository".
+
+
+----------------
+-- Section 2B -- Common User Tasks
+----------------
+
+What I consider a "common user task" generally involves combinations
+of the following commands:
+
+ checkout, update, commit, diff, log, status, tag, add
+
+
+Conventions in this section:
+
+ 1. Before each CVS command, you are assumed to have typed a "cd"
+ command to move into a writable working directory.
+
+ 2. All further "cd" commands specified in the examples are assumed
+ to start in the above working directory.
+
+ 3. Unless a point is being made about multiple instances, all modules
+ are named <module>, all tags are named <tag> (branch tags are
+ named <branch_tag>) and all files are named <file>.
+
+ The checkout command will take a relative path name in place
+ of a module name. If you use a relative pathname in place of
+ <module>, you should use the same relative path every place
+ you see <module> in that example.
+
+
+ **** Questions:
+
+ 2B.1 What is the absolute minimum I have to do to edit a file?
+ 2B.2 If I edit multiple files, must I type "commit" for each one?
+ 2B.3 How do I get rid of the <module> directory that "checkout" created?
+ 2B.4 How do I find out what has changed since my last update?
+ 2B.5 I just created a new file. How do I add it to the Repository?
+ 2B.6 How do I merge changes made by others into my working directory?
+ 2B.7 How do I label a set of revisions so I can retrieve them later?
+ 2B.8 How do I checkout an old release of a module, directory or file?
+ 2B.9 What do I have to remember to do periodically?
+
+
+ **** Answers:
+
+
+ 2B.1 What is the absolute minimum I have to do to edit a file?
+
+ Tell your Repository Administrator to create a module covering the
+ directory or files you care about. You will be told that your
+ module name is <module>. Then type:
+
+ cvs checkout <module>
+ cd <module>
+ emacs <file> # Isn't Emacs a synonym for edit?
+ cvs commit <file>
+
+ If you don't use modules (in my opinion, a mistake), you can check
+ out a directory by substituting its relative path within the
+ Repository for <module> in the example above.
+
+ To work on a single file, you'll have to change "cd <module>" to
+ "cd `dirname <module>`".
+
+
+ 2B.2 If I edit multiple files, must I type "commit" for each one?
+
+ No. You can commit a list of files and directories, including
+ relative paths into multiple directories. You can also commit
+ every modified file in the current directory or in all directories
+ and subdirectories from your current directory downward. See 3D.2.
+
+
+ 2B.3 How do I get rid of the <module> directory that "checkout" created?
+
+ Change your directory to be the same as when you executed the
+ "checkout" command that created <module>.
+
+ If you want to get rid of the CVS control information, but leave
+ the files and directories, type:
+
+ cvs release <module>
+
+ If you want to obliterate the entire directory, type:
+
+ cvs release -d <module>
+
+ ("release -d" searches through the output of "cvs -n update" and
+ refuses to continue if the "update" command finds any modified
+ files or non-ignored foreign files. Foreign directories too.)
+
+ If you don't care about keeping "history", or checking for
+ modified and foreign files, you can just remove the whole
+ directory. That's "rm -rf <module>" under Unix.
+
+
+ 2B.4 How do I find out what has changed since my last update?
+
+ There are many ways to answer this.
+
+ To find out what you've changed in your current working directory
+ since your last checkout, update or commit, type:
+
+ cvs diff
+
+ To find out what other people have added (to your branch) since
+ you last checked out or updated, type:
+
+ cvs diff -r BASE -r HEAD
+
+ To look at a revision history containing the comments for all
+ changes, you can use the "log" command.
+
+ You can also use "history" to trace a wide variety of events.
+
+
+ 2B.5 I just created a new file. How do I add it to the Repository?
+
+ The "update" command will mark files CVS doesn't know about in
+ your working directory with a '?' indicator.
+
+ ? <file>
+
+ To add <file> to the Repository, type:
+
+ cvs add <file>
+ cvs commit <file>
+
+ See 3A.[2-5] and 4C.8 for branch and merge considerations.
+
+
+ 2B.6 How do I merge changes made by others into my working directory?
+
+ If you are asking about other branches, see Section 4C on
+ "Branching". You will have to use the "update -j" command.
+
+ Retrieving changes made to the Repository on the *same* branch you
+ are working on is the main purpose of the "update" command. The
+ "update" command tries to merge work committed to the Repository
+ by others since you last executed "checkout", "update" or "commit"
+ into your working files.
+
+ For a single file, there are six possible results when you type
+ the "update" command:
+
+ 1. If the file is lying in your working directory, but is not
+ under CVS, it will do nothing but print:
+
+ ? <file>
+
+ 2. If neither you nor anyone else has committed changes to <file>,
+ since your last "checkout", "update" or "commit", "update"
+ will print nothing and do nothing.
+
+ 3. If you have made no changes to a working file, but you or
+ others have committed changes to the Repository since your last
+ "checkout", "update" or "commit" of this working file, CVS will
+ remove your working file and replace it with a copy of the
+ latest revision of that file in the Repository. It will print:
+
+ U <file>
+
+ You might want to examine the changes (using the CVS "diff"
+ command) to see if they mesh with your own in related files.
+
+ 4. If you have made changes to a working file, but no one has
+ changed your BASE revision (the revision you retrieved from the
+ Repository in your last "checkout", "update" or "commit"),
+ "update" will print:
+
+ M <file>
+
+ Nothing changes. You were told that you have a modified
+ file in your directory.
+
+ 5. If you have made changes to your working file and you or others
+ have committed changes to the Repository, but in different
+ sections of the file, CVS will merge the changes stored in the
+ Repository since your last "checkout", "update" or "commit"
+ into your working file. "update" will print:
+
+ RCS file: /Repository/module/<file>
+ retrieving revision 1.X
+ retrieving revision 1.Y
+ Merging differences between 1.X and 1.Y into <file>
+ M <file>
+
+ If you execute "diff" before and after this step, you should
+ see the same output, since both the base file and your working
+ file changed in parallel. This is one of the few times the
+ otherwise nonsensical phrase "same difference" means something.
+
+ 6. If both you and those who committed files (since your last
+ checkout, update or commit) have made changes to the same
+ section of a file, CVS will merge the changes into your file as
+ in #5 above, but it will leave conflict indicators in the file.
+ "update" will print:
+
+ RCS file: /Repository/module/<file>
+ retrieving revision 1.X
+ retrieving revision 1.Y
+ Merging differences between 1.X and 1.Y into <file>
+ rcsmerge warning: overlaps during merge
+ cvs update: conflicts found in <file>
+ C <file>
+
+ This is a "conflict". The file will contain markers
+ surrounding the overlapping text. The 'C' conflict indicator
+ is sticky -- subsequent "update" commands will continue to show
+ a 'C' until you edit the file.
+
+ You must examine the overlaps with care and resolve the problem
+ by analyzing how to retain the features of both changes. See
+ 2D.7 and 3P.6 for more details on conflict resolution.
+
+
+ 2B.7 How do I label a set of revisions so I can retrieve them later?
+
+ To "tag" the BASE revisions (the ones you last checked out,
+ updated, or committed) you should "cd" to the head of the working
+ directory you want to tag and type:
+
+ cvs tag <tag>
+
+ It recursively walks through your working directory tagging the
+ BASE revisions of all files.
+
+ To "tag" the latest revision on the Main branch in the
+ Repository, you can use the following from anywhere:
+ (No "cd" is required -- it works directly on the Repository.)
+
+ cvs rtag <tag> <module>
+
+
+ 2B.8 How do I checkout an old release of a module, directory or file?
+
+ Module names and directories are simply ways to name sets of
+ files. Once the names are determined, there are 6 ways to specify
+ which revision of a particular file to check out:
+
+ 1. By tag or symbolic name, via the "-r <tag>" option.
+
+ 2. By date, via the "-D <date>" option.
+
+ 3. By branch tag (a type of tag with a magic format), via the
+ "-r <branch_tag>" option.
+
+ 4. By date within a branch, via the "-r <branch_tag>:<date>"
+ option.
+
+ 5. By an explicit branch revision number ("-r <rev>"), which
+ refers to the latest revision on the branch. This isn't really
+ an "old" revision, from the branch's perspective, but from the
+ user's perspective the whole branch might have been abandoned
+ in the past.
+
+ 6. An explicit revision number: "-r <rev>" Though this works, it
+ is almost useless for more than one file.
+
+
+ You type:
+
+ cvs checkout <option-specified-above> <module>
+ cd <module>
+
+
+ 2B.9 What do I have to remember to do periodically?
+
+ You should execute "cvs -n update" fairly often to keep track of
+ what you and others have changed. It won't change anything -- it
+ will just give you a report.
+
+ Unless you are purposely delaying the inclusion of others' work,
+ you should execute "update" once in a while and resolve the
+ conflicts. It is not good to get too far out of sync with the
+ rest of the developers working on your branch.
+
+ It is assumed that your system administrators have arranged for
+ editor backup and Unix temp files (#* and .#*) to be deleted after
+ a few weeks. But you might want to look around for anything else
+ that is ignored or hidden. Try "cvs -n update -I !" to see all
+ the ignored files.
+
+ If you are the Repository Administrator, see 4B.16 on
+ Administrator responsibilities.
+
+
+----------------
+-- Section 2C -- Less Common User Tasks
+----------------
+
+What I consider a "less common user task" generally involves one or
+more of the following commands:
+
+ history, import, export, rdiff, release, remove, rtag
+
+
+ **** Questions:
+
+ 2C.1 Can I create non-CVS sub-directories in my working directory?
+ 2C.2 How do I add new sub-directories to the Repository?
+ 2C.3 How do I remove a file I don't need?
+ 2C.4 How do I rename a file?
+ 2C.5 How do I make sure that all the files and directories in my
+ working directory are really in the Repository?
+ 2C.6 How do I create a branch?
+ 2C.7 How do I modify the modules file? How about the other files in
+ the CVSROOT administrative area?
+ 2C.8 How do I split a file into pieces, retaining revision histories?
+
+
+ **** Answers:
+
+
+ 2C.1 Can I create non-CVS sub-directories in my working directory?
+
+ Yes. Unless the directory exists in the Repository, "update" will
+ skip over them and print a '?' the way it does for files you
+ forgot to add. You can avoid seeing the '?' by adding the name
+ of the foreign directory to the ./.cvsignore file, just ask you
+ can do with files.
+
+ If you explicitly mention a foreign directory on the "update"
+ command line, it will traverse the directory and waste a bit of
+ time, but if any directory or sub-directory lacks the ./CVS
+ administrative directory, CVS will print an error and abort.
+
+
+ 2C.2 How do I add new sub-directories to the Repository?
+
+ The "add" command will work on directories. You type:
+
+ mkdir <dir>
+ cvs add <dir>
+
+ It will respond:
+
+ Directory /Repos/<dir> added to the repository
+
+ and will create both a matching directory in the Repository and a
+ ./CVS administrative directory within the local <dir> directory.
+
+
+ 2C.3 How do I remove a file I don't need?
+
+ (See the questions in Section 4B on removing files from the
+ Repository.)
+
+ You type:
+
+ rm <file>
+ cvs remove <file>
+
+ CVS registers the file for removal. To complete the removal, you
+ must type:
+
+ cvs commit <file>
+
+ CVS moves the file to the Attic associated with your working
+ directory. Each directory in the Repository stores its deleted
+ files in an Attic sub-directory. A normal "checkout" doesn't
+ look in the Attic, but if you specify a tag, a date or a
+ revision, the "checkout" (or "update") command will retrieve
+ files from the Attic with that tag, date or revision.
+
+
+ 2C.4 How do I rename a file?
+
+ CVS does not offer a way to rename a file in a way that CVS can
+ track later. See Section 4B for more information.
+
+ Here is the best (to some, the only acceptable) way to get the
+ effect of renaming, while preserving the change log:
+
+ 1. Copy the RCS (",v") file directly in the Repository.
+
+ cp $CVSROOT/<odir>/<ofile>,v $CVSROOT/<ndir>/<nfile>,v
+
+ By duplicating the file, you will preserve the change
+ history and the ability to retrieve earlier revisions of the
+ old file via the "-r <tag/rev>" or "-D <date>" options to
+ "checkout" and "update".
+
+ 2. Remove the old file using CVS.
+
+ cd <working-dir>/<odir>
+ rm <ofile>
+ cvs remove <ofile>
+ cvs commit <ofile>
+
+ This will move the <ofile> to the Attic associated with
+ <odir>.
+
+ 3. Retrieve <nfile> and remove all the Tags from it.
+
+ By stripping off all the old Tags, "checkout -r" and
+ "update -r" won't retrieve revisions Tagged before
+ the renaming.
+
+ cd <working-dir>/<ndir>
+ cvs update <nfile>
+ cvs log <nfile> # Save the list of Tags
+ cvs tag -d <tag1> <nfile>
+ cvs tag -d <tag2> <nfile>
+ . . .
+
+
+ This technique can be used to rename files within one directory or
+ across different directories. You can apply this idea to
+ directories too, as long as you apply the above to each file and
+ don't delete the old directory.
+
+ Of course, you have to change your build system (e.g. Makefile) in
+ your <working-dir> to know about the name change.
+
+ Warning: Stripping the old tags from the copied file will allow
+ "-r <tag>" to do the right thing, but you will still have problems
+ with "-D <date>" because there is no place to store the "deletion
+ time". See 5B.3 for more details.
+
+
+ 2C.5 How do I make sure that all the files and directories in my
+ working directory are really in the Repository?
+
+ A "cvs update", or "cvs -n update" (which won't modify your
+ working directory) will display foreign elements, which have no
+ counterpart in the Repository, preceded by a '?'. To register
+ foreign directories, you can use "cvs add". To register foreign
+ files, you can use "cvs add" followed by "cvs commit".
+
+ You could also checkout your module, or the Repository directory
+ associated with your working directory, a second time into another
+ work area and compare it to your working directory using the
+ (non-CVS) "diff -r" command.
+
+ By default many patterns of files are ignored. If you create a
+ file named "core" or a file ending in ".o", it is usually
+ ignored. If you really want to see all the files that aren't in
+ the Repository, you can use a special "ignore" pattern to say
+ "ignore no files". Try executing: (You may have to quote or
+ backwhack (i.e. precede by '\') the '!' in your shell.)
+
+ cvs -n update -I !
+
+ The above command will display not only the normal modified,
+ update and conflict indicators ('M', 'U', and 'C' respectively) on
+ files within the Repository, but it will also display each file
+ not in the Repository preceded by a '?' character.
+
+ The '-n' option will not allow "update" to alter your working
+ directory.
+
+
+ 2C.6 How do I create a branch?
+
+ Type this in your working directory:
+
+ cvs tag -b <branch_tag>
+
+ and you will create a branch. No files have real branches in them
+ yet, but if you move onto the branch by typing:
+
+ cvs update -r <branch_tag>
+
+ and commit a file in the normal way:
+
+ cvs commit <file>
+
+ then a branch will be created in the underlying <file>,v file and
+ the new revision of <file> will appear only on that branch.
+
+ See Section 4C, on Branching.
+
+
+ 2C.7 How do I modify the modules file? How about the other files in
+ the CVSROOT administrative area?
+
+ A module named "modules" has been provided in the default modules
+ file, so you can type:
+
+ cvs checkout modules
+ cd modules
+
+ Another module named CVSROOT has been provided in the default
+ modules file, covering all the administrative files. Type:
+
+ cvs checkout CVSROOT
+ cd CVSROOT
+
+ Then you can edit your files, followed by:
+
+ cvs commit
+
+ If you start with the provided template for the "modules" file,
+ the CVSROOT and the "modules" module will have the "mkmodules"
+ program as a "commit helper". After a file is committed to such a
+ module, "mkmodules" will convert a number of standard files (See
+ 4B.2) in the CVSROOT directory inside the Repository into a form
+ that is usable by CVS.
+
+
+ 2C.8 How do I split a file into pieces, retaining revision histories?
+
+ If you and a coworker find yourselves repeatedly committing the
+ same file, but never for changes in the same area of the file, you
+ might want to split the file into two or more pieces. If you are
+ both changing the same section of code, splitting the file is of
+ no use. You should talk to each other instead.
+
+ If you decide to split the file, here's a suggestion. In many
+ ways, it is similar to multiple "renamings" as described in
+ 2C.4 above.
+
+ Say you want to split <fileA>, which already in the Repository,
+ into three pieces, <fileA>, <fileB> and <fileC>.
+
+ 1. Copy the RCS (",v") files directly in the Repository,
+ creating the new files, then bring readable copies of the
+ new files into the working directory via "update".
+
+ cp $CVSROOT/<path>/<fileA>,v $CVSROOT/<path>/<fileB>,v
+ cp $CVSROOT/<path>/<fileA>,v $CVSROOT/<path>/<fileC>,v
+ cvs update <fileB> <fileC>
+
+ 2. Then remove all the <tags> from the new files by using:
+
+ cvs log <fileB> <fileC> # Save the list of <tag?>
+ cvs tag -d <tag1> <fileB> <fileC>
+ cvs tag -d <tag2> <fileB> <fileC>
+ . . .
+
+ 3. Edit each file until it has the data you want in it.
+ This is a hand-editing job, not something CVS can handle.
+ Then commit all the files.
+
+ [From experience, I'd suggest making sure that only one copy
+ of each line of code exists among the three files, except
+ for "include" statements, which must be duplicated. And
+ make sure the code compiles.]
+
+ emacs <fileA> <fileB> <fileC>
+ cvs commit <fileA> <fileB> <fileC>
+
+
+ As in the "rename" case, by duplicating the files, you'll preserve
+ the change history and the ability to retrieve earlier revisions.
+
+ Of course, you have to alter your build system (e.g. Makefiles) to
+ take the new names and the change in contents into account.
+
+
+
+----------------
+-- Section 2D -- General Questions
+----------------
+
+ **** Questions:
+
+ 2D.1 How do I see what CVS is trying to do?
+ 2D.2 If I work with multiple modules, should I check them all out and
+ commit them occasionally? Is it OK to leave modules checked out?
+ 2D.3 What is a "sticky" tag? What makes it sticky? How do I loosen it?
+ 2D.4 How do I get an old revision without updating the "sticky tag"?
+ 2D.5 What operations disregard sticky tags?
+ 2D.6 Is there a way to avoid reverting my Emacs buffer after
+ committing a file? Is there a "cvs-mode" for Emacs?
+ 2D.7 How does conflict resolution work? What *really* happens if two
+ of us change the same file?
+ 2D.8 How can I tell who has a module checked out?
+ 2D.9 Where did the .#<file>.1.3 file in my working directory come from?
+ 2D.10 What is this "ignore" business? What is it ignoring?
+ 2D.11 Is there a way to set user-specific configuration options?
+ 2D.12 Is it safe to interrupt CVS using Control-C?
+ 2D.13 How do I turn off the "admin" command?
+ 2D.14 How do I turn off the ability to disable history via "cvs -l"?
+ 2D.15 How do I keep certain people from accessing certain directories?
+
+
+ **** Answers:
+
+
+ 2D.1 How do I see what CVS is trying to do?
+
+ The '-t' option on the main "cvs" command will display every
+ external command (mostly RCS commands and file deletions) it
+ executes. When combined with the '-n' option, which prevents the
+ execution of any command that might modify a file, you can see
+ what it will do before you let it fly. The '-t' option will *not*
+ display every internal action, only calls to external programs.
+
+ To see a harmless example, try typing:
+
+ cvs -nt update
+
+ Some systems offer a "trace" or "truss" command that will display
+ all system calls as they happen. This is a *very* low-level
+ interface that does not normally follow the execution of external
+ commands, but it can be useful.
+
+ The most complete answer is to read the source, compile it
+ with the '-g' option and step through it under a debugger.
+
+
+ 2D.2 If I work with multiple modules, should I check them all out and
+ commit them occasionally? Is it OK to leave modules checked out?
+
+ The simple answers are "Yes."
+
+ There is no reason to remove working directories, other than to
+ save disk space. As long as you have committed the files you
+ choose to make public, your working directory is just like any
+ other directory.
+
+ CVS doesn't care whether you leave modules checked out or not.
+ The advantage of leaving them checked out is that you can quickly
+ visit them to make and commit changes.
+
+
+ 2D.3 What is a "sticky" tag? What makes it sticky? How do I loosen it?
+
+ When you execute "update -r <tag>", CVS remembers the <tag>. It
+ has become "sticky" in the sense that until you change it or
+ remove it, the tag is remembered and used in references to the
+ file as if you had typed "-r <tag>" on the command line.
+
+ It is most useful for a <branch_tag>, which is a sticky tag
+ indicating what branch you are working on.
+
+ A revision number ("-r <rev-number>") or date ("-D <date>") can
+ also become sticky when they are specified on the command line.
+
+ A sticky tag, revision or date remains until you specify another
+ tag, revision or date the same way. The "update -A" command
+ moves back to the Main branch, which has the side-effect of
+ clearing all sticky items on the updated files.
+
+ The "checkout" command creates sticky tags, revisions and dates
+ the same way "update" does.
+
+ Also, the '-k' option records a "sticky" keyword option that
+ is used in further "updates until "update -A" is specified.
+
+
+ 2D.4 How do I get an old revision without updating the "sticky tag"?
+
+ Use the '-p' option to "pipe" data to standard output. The
+ command "update -p -r <tag/rev>" sends the selected revision to
+ your standard output (usually the terminal, unless redirected).
+ The '-p' affects no disk files, leaving a "sticky tag" unaltered
+ and avoiding all other side-effects of a normal "update".
+
+ If you want to save the result, you can redirect "stdout" to a
+ file using your shell's redirection capability. In most shells
+ the following command works:
+
+ cvs update -p -r <tag/rev> filename > diskfile
+
+
+ 2D.5 What operations disregard sticky tags?
+
+ The functions that routinely disregard sticky tags are:
+
+ 1. Those that work directly on the Repository or its
+ administrative files:
+
+ admin rtag log status remove history
+
+ 2. Those that take Tags or revisions as arguments and ignore
+ everything else: (They also never *set* a sticky tag.)
+
+ rdiff import export
+
+ 3. The "release" command itself ignores sticky tags, but it
+ calls "cvs -n update" (which *does* pay attention to a
+ sticky tag) to figure out what inconsistencies exist in
+ the working directory. If no discrepancies exist between
+ the files you originally checked out (possibly marked by a
+ sticky tag) and what is there now, "release -d" will
+ delete them all.
+
+ 4. The "tag" command works on the revision lying in the
+ working directory however it got there. That the revision
+ lying there might happen to have a sticky tag attached to
+ it is not the "tag" command's concern.
+
+
+ The main function that *does* read and write sticky tags is the
+ "update" command. You can avoid referring to or changing the
+ sticky tag by using the '-p' option, which sends files to your
+ terminal, touching nothing else.
+
+ The "checkout" command sets sticky tags when checking out a new
+ module and it acts like "update" when checking out a module into
+ an existing directory.
+
+ The "diff" and "commit" commands use the sticky tags, unless
+ overridden on the command line. They do not set sticky tags.
+ Note that you can only "commit" to a file checked out with a
+ sticky tag, if the tag identifies a branch.
+
+ There are really two types of sticky tags, one attached to
+ individual files (in the ./CVS/Entries file) and one attached to
+ each directory (in the ./CVS/Tag file). They can differ.
+
+ The "add" command registers the desire to add a new file. If the
+ "directory tag" (./CVS/Tag) file exists at the time of the "add",
+ the value stored in ./CVS/Tag becomes the "sticky tag" on the new
+ file. The file doesn't exist in the Repository until you "commit"
+ it, but the ./CVS/Entries file holds the sticky tag name from the
+ time of the "add" forward.
+
+
+ 2D.6 Is there a way to avoid reverting my Emacs buffer after
+ committing a file? Is there a "cvs-mode" for Emacs?
+
+ See Section 4F.1
+
+
+ 2D.7 How does conflict resolution work? What *really* happens if two
+ of us change the same file?
+
+ While editing files, there is no conflict. You are working on
+ separate copies of the file stored in the virtual "branch"
+ represented by your working directories. After one of you commits
+ a file, the other may not commit the same file until "update" has
+ merged the earlier committed changes into the later working file.
+
+ For example, say you both check out rev 1.2 of <file> and make
+ change to your working files. Your coworker commits revision 1.3.
+ When you try to commit your file, CVS says:
+
+ cvs commit: Up-to-date check failed for `<file>'
+
+ You must merge your coworker's changes into your working file by
+ typing:
+
+ cvs update <file>
+
+ which will produce the output described in 2B.6.
+
+ If a conflict occurs, the filename will be shown with a status of
+ 'C'. After you resolve any overlaps caused by the merging
+ process, you may then commit the file. See 3P.6 for info on
+ "sticky conflicts".
+
+ Even if you get a simple 'M', you should examine the differences
+ before committing the file. A smooth, error-free text merge is
+ still no indication that the file is in proper shape. Compile and
+ test it at least.
+
+ The answer to two obvious questions is "Yes".
+
+ Yes, the first one who commits avoids the merge. Later developers
+ have to merge the earlier changes into their working files before
+ committing the merged result. Depending on how difficult the merge
+ is and how important the contending projects are, the order of
+ commits and updates might have to be carefully staged.
+
+ And yes, between the time you execute "update" and "commit" (while
+ you are fixing conflicts and testing the results) someone else may
+ commit another revision of <file>. You will have to execute
+ "update" again to merge the new work before committing. Most
+ organizations don't have this problem. If you do, you might
+ consider splitting the file. Or hiring a manager.
+
+
+ 2D.8 How can I tell who has a module checked out?
+
+ If you "checkout" module names (not relative pathnames) and you
+ use the release command, the "history" command will display active
+ checkouts, who has them and where they were checked out. It is
+ advisory only; it can be circumvented by using the '-l' option on
+ the main "cvs" command.
+
+
+ 2D.9 Where did the .#<file>.1.3 file in my working directory come from?
+
+ It was created during an "update" when CVS merged changes from the
+ Repository into your modified working file.
+
+ It serves the same purpose as any "backup" file: saving your bacon
+ often enough to be worth retaining. It is invaluable in
+ recovering when things go wrong.
+
+ Say Developers A (you) and B check out rev 1.3 of file <file>.
+ You both make changes -- different changes. B commits first, so
+ <file>,v in the Repository contains revisions up through 1.4.
+
+ At this point, there are 5 (yes, five) versions of the file of
+ interest to you:
+
+ 1. Revision 1.3 (What you originally checked out.)
+ 2. Revision 1.4 (What you need from developer B.)
+ 3. Your old working file. (Before the update.)
+ 4. Your new working file. (After the merge caused by "update".)
+ 5. Revision 1.5 (Which you will commit shortly.)
+
+ In the case where your working file was not modified, #1 and #3
+ will be the same, as will #2 and #4. In this degenerate case,
+ there is no need to create #5. The following assumes that your
+ working file was modified.
+
+ If the merge executed by the "update" caused no overlaps, and you
+ commit the file immediately, #4 and #5 will be the same. But you
+ can make arbitrary changes before committing, so the difference
+ between #4 and #5 might be more than just the correction of
+ overlaps. In general, though, you don't need #4 after a commit.
+
+ But #3 (which is the one saved as ".#<file>.1.3") holds all of
+ your work, independent of B's work. It could represent a major
+ effort that you couldn't afford to lose. If you don't save it
+ somewhere, the merge makes #3 *disappear* under a potential
+ blizzard of conflicts caused by overlapping changes.
+
+ I have been saved a few times, and others I support have been
+ saved hundreds of times, by the ability to "diff <original file>
+ <original file with only my work added>", which can be done in the
+ example above by the Unix shell command:
+
+ cvs update -p -r 1.3 <file> | diff - .#<file>.1.3
+
+ The assumption is that the ".#" files will be useful far beyond
+ the "commit" point, but not forever. You are expected to run
+ the "normal" Unix cleanup script from "cron", which removes "#*"
+ and ".#*" files older than a some period chosen by your
+ sysadmin, usually ranging from 7 to 30 days.
+
+ A question was raised about the need for #3 after #5 has been
+ committed, under the assumption that you won't commit files until
+ everything is exactly as you like them.
+
+ This assumes perfect humans, which violates one of the Cardinal
+ rules of Software Engineering: Never assume any form of discipline
+ on the part of the users of software. If restrictions are not
+ bound into the software, then you, the toolsmith, have to arrange
+ a recovery path.
+
+ In other words, I've seen every possible variety of screwup you
+ can imagine in #5. There is no way to make assumptions about
+ what "should" happen. I've seen #5 filled with zeros because of
+ NFS failures, I've seen emacs core dumps that leave #5 in an
+ unreasonable state, I've seen a foolish developer uppercase the
+ whole file (with his "undo" size set low so he couldn't undo it)
+ and decide that it would be less work to play with the
+ uppercased file than to blow it away and start over. I've even
+ seen committed files with conflict markers still in them, a sure
+ sign of carelessness.
+
+ There are all sorts of scenarios where having #3 is incredibly
+ useful. You can move it back into place and try again.
+
+
+ 2D.10 What is this "ignore" business? What is it ignoring?
+
+ The "update" and "import" commands use collections of Unix
+ wildcards to skip over files and directories matching any of those
+ patterns.
+
+ You may add to the built-in ignore list by adding lines of
+ whitespace-separated wildcards to the following places: (They are
+ read in this order.)
+
+ 1. In a file named "cvsignore" in $CVSROOT/CVSROOT.
+
+ A Repository Administrator uses this to add site-specific
+ files and patterns to the built-in ignore list.
+
+ 2. In a file named ".cvsignore" in your home directory.
+
+ For user-specific files. For example, if you use "__" as
+ your default junk file prefix, you can put "__*" in your
+ .cvsignore file.
+
+ People who play around exclusively in directory trees where the
+ Makefiles are generated by "imake" or "configure" might want to
+ put "Makefile" in their ignore list, since they are all
+ generated and usually don't end up in the Repository.
+
+ 3. In the CVSIGNORE environment variable.
+
+ For session-specific files.
+
+ 4. Via the '-I' option on "import" or "update" commands.
+
+ For this-command-only files.
+
+ 5. In a file named ".cvsignore" within each directory.
+
+ The contents of a ".cvsignore" file in each directory is
+ temporarily added to the ignore list. This way you can ignore
+ files that are peculiar to that directory, such as executables
+ and other generated files without known wildcard patterns.
+
+ In any of the places listed above, a single '!' character nulls
+ out the ignore list. A Repository administrator can use this to
+ override, rather than enhance, the built-in ignore list. A user
+ can choose to override the system-wide ignore list. For example,
+ if you place "! *.o *.a" in your .cvsignore file, only *.o *.a
+ files, plus any files a local-directory .cvsignore file, are
+ ignored.
+
+ A variant of the ignore-file scheme is used internally during
+ checkout. "Module names" found in the modules file (or on the
+ "checkout" command line) that begin with a '!' are ignored during
+ checkout. This is useful to permanently ignore (if the '!' path
+ is in the modules file) or temporarily ignore (if the '!' path is
+ on the command line) a sub-directory within a Repository
+ hierarchy. For example:
+
+ cvs checkout !gnu/emacs/tests gnu/emacs
+
+ would checkout the module (or relative path within $CVSROOT) named
+ "gnu/emacs", but ignore the "tests" directory within it.
+
+
+ 2D.11 Is there a way to set user-specific configuration options?
+
+ User-specific configuration is available through use of a ".cvsrc"
+ file in your home directory.
+
+ CVS searches the first column of your ~/.cvsrc file for the cvs
+ command name you invoked. If the command is found, the rest of
+ the line is treated like a set of command line options, stuffed
+ into the command line before the arguments you actually typed.
+
+ For example, if you always want to see context diffs and you never
+ want to have to delete a file before you run "cvs remove", then
+ you should create a .cvsrc file containing the following:
+
+ diff -c
+ remove -f
+
+ which will add the given options to every invocation of the given
+ commands.
+
+ [[The rest of this will be removed someday, when CVS changes.]]
+
+ I would like to stop here with a comment that the command name to
+ use is the full, canonical one. But the command that the cvsrc
+ support uses is the string you typed on the command line, not the
+ proper command. So to get the full effect of the above example,
+ you should also add all the alternate command names:
+
+ di -c
+ dif -c
+ rm -f
+ delete -f
+
+ There are two other limitations that will probably be fixed when
+ CVS sprouts long option names:
+
+ 1. It only affects options made available on the command line.
+
+ There is a limited number of short options. With long option
+ names, there is no problem. You can have as many long options
+ as you like, affecting anything that looks malleable.
+
+ 2. The existing command line options do not come in on/off pairs,
+ so there is no easy way to override your ~/.cvsrc configuration
+ for a single invocation of a command.
+
+ Choosing a good set of long option pairs would fix this.
+
+
+ 2D.12 Is it safe to interrupt CVS using Control-C?
+
+ It depends on what you mean by "safe". ("Ah," said Arthur,
+ "this is obviously some strange usage of the word *safe* that I
+ wasn't previously aware of." -- Hitchhiker's Guide to the Galaxy)
+
+ You won't hurt the underlying RCS files and if you are executing a
+ command that only *reads* data, you will have no cleanup to do.
+
+ But you may have to hit Control-C repeatedly to stop it. CVS uses
+ the Unix "system" routine which blocks signals in the CVS parent
+ process. A single Control-C during "system" will only halt the
+ child process, usually some form of RCS command.
+
+ If you don't hit another Control-C while the CVS process has
+ control, it is likely to continue onto the next task assuming that
+ the earlier one did its job. It is not enough to hit two
+ Control-C's. You might simply kill two child processes and not
+ interrupt CVS at all. Depending on the speed of your processor,
+ your terminal and your fingers, you might have to hit dozens of
+ Control-C's to stop the damn thing.
+
+
+ Executing a CVS command, such as "commit" or "tag" that writes
+ to the files is a different matter.
+
+ Since CVS is not a full-fledged database, with what database
+ people call "commit points", merely stopping the process will not
+ back out the "transaction" and place you back in the starting
+ blocks. CVS has no concept of an "atomic" transaction or of
+ "backtracking", which means that a command can be half-executed.
+
+ Hitting Control-C will usually leave lock files that you have to
+ go clean up in the Repository.
+
+ Example1:
+
+ If you interrupt a multi-file "commit" in the middle of
+ an RCS checkin, RCS will leave the file either fully
+ checked-in or in its original state. But CVS might have
+ been half-way through the list of files to commit. The
+ directory or module will be inconsistent.
+
+ To recover, you must remove the lock files, then decide
+ whether you want to back out or finish the job.
+
+ To back out, you'll have to apply the "admin -o"
+ command, very carefully, to remove the newly committed
+ revisions. This is usually a bad idea, but is
+ occasionally necessary.
+
+ To finish, you can simply retype the same commit command.
+ CVS will figure out what files are still modified and
+ commit them. It helps that RCS doesn't leave a file in an
+ intermediate state.
+
+
+ Example2:
+
+ If you interrupt a multi-file "tag" command, you have a
+ problem similar, but not equivalent, to interrupting a
+ "commit". The RCS file will still be consistent, but
+ unlike "commit", which only *adds* to the RCS file, "tag"
+ can *move* a tag and it doesn't keep a history of what
+ revision a tag used to be attached to.
+
+ Normally, you have little choice but to re-execute the
+ command and allow it to tag everything consistently.
+
+ You might be able to recover by carefully re-applying the
+ tags via the "cvs admin -N" command, but you'll still have
+ to dig up from outside sources the information you use to
+ determine what tag was on what revision in what file.
+ the Repository, or by using the equivalent: "cvs admin".
+
+
+ Halting a new "checkout" should cause no harm. If you don't want
+ it, "release" (or rm -rf) it. If you do want it, re-execute the
+ command. A repeated "checkout" from above a directory acts like a
+ repeated "update -d" within it.
+
+ Halting "update" half-way will give you an unpredictable
+ collection of files and revisions. To continue, you can rerun the
+ update and it should move you forward into in a known state. To
+ back out, you'll have to examine the output from the first
+ "update" command, take a look at each file that was modified and
+ reconstruct the previous state by editing the ./CVS/Entries file
+ and by using "cvs admin". Good Luck.
+
+
+ 2D.13 How do I turn off the "admin" command?
+
+ In the current revision, you'd have to edit the source code.
+
+
+ 2D.14 How do I turn off the ability to disable history via "cvs -l"?
+
+ In the current revision, you'd have to edit the source code.
+
+
+ 2D.15 How do I keep certain people from accessing certain directories?
+
+ If you don't try to run CVS set[ug]id, you can use Unix groups and
+ permissions to limit access to the Repository.
+
+ If you only want to limit "commit" commands, you can write a
+ program to put in the "commitinfo" file. In the "contrib"
+ directory, there are a few scripts that might help you out.
+
+
+
+========================================
+== Section 3 ==== Commands ====
+========================================
+
+This section contains questions that are easily recognized to be about a
+single command, usually of the form: "Why does the 'xyz' command do this?"
+
+Questions about "missing" features and side-effects not attributable to a
+particular command are in Section 2D, "General Questions".
+
+I won't provide patches here that are longer than a few lines. Patches
+referred to in this section are available in the FTP archive described
+toward the beginning of this document.
+
+
+----------------
+-- Section 3A -- "add", "ad", "new"
+----------------
+
+ **** Questions:
+
+ 3A.1 What is "add" for?
+ 3A.2 How do I add a new file to the branch I'm working on?
+ 3A.3 Why did my new file end up in the Attic?
+ 3A.4 Now that it's in the Attic, how do I connect it to the Main branch?
+ 3A.5 How do I avoid the hassle of reconnecting an Attic-only file to
+ the Main Branch?
+ 3A.6 How do I cancel an "add"?
+ 3A.7 What are the ./CVS/file,p and ./CVS/file,t files for?
+ 3A.8 How do I "add" a binary file?
+
+
+ **** Answers:
+
+ 3A.1 What is "add" for?
+
+ To add a new directory to the Repository or to register the
+ desire to add a new file to the Repository.
+
+ The directory is created immediately, while the desire to add the
+ file is recorded in the local ./CVS administrative directory. To
+ really add the file to the Repository, you must then "commit" it.
+
+
+ 3A.2 How do I add a new file to the branch I'm working on?
+
+ The user actions for adding a file to any branch, including the
+ Main Branch, are exactly the same.
+
+ You are in a directory checked out (or updated) with the '-A'
+ option (to place you on the Main Branch) or the "-r <branch_tag>"
+ option (to place you on a branch tagged with <branch_tag>). To
+ add <file> to the branch you are on, you type:
+
+ cvs add <file>
+ cvs commit <file>
+
+ If no ./CVS/Tag file exists (the '-A' option deletes it), the
+ file will be added to the Main Branch. If a ./CVS/Tag file exists
+ (the "-r <branch_tag>" option creates it), the file will be added
+ to the branch named (i.e. tagged with) <branch_tag>.
+
+ Unless you took steps to first add the file to the Main Branch,
+ your new file ends up in the Attic.
+
+
+ 3A.3 Why did my new file end up in the Attic?
+
+ The file is thrown into the Attic to keep it from being visible
+ when you check out the Main Branch, since it was never committed
+ to the Main Branch.
+
+
+ 3A.4 Now that it's in the Attic, how do I connect it to the Main branch?
+
+ That can be considered a kind of "merge". See 4C.8
+
+
+ 3A.5 How do I avoid the hassle of reconnecting an Attic-only file to
+ the Main Branch?
+
+ You create it on the Main Branch first, then branch it.
+
+ If you haven't yet added the file or if you decided to delete the
+ new Attic file and start over, then do the following:
+ (If you added the file (or worse, the 157 files) to the Attic and
+ don't want to start over, try the procedure in 4C.8.)
+
+
+ 1. Temporarily remove the sticky branch information. Either:
+
+ A. Move the whole directory back to the Main Branch.
+ [This might not be a good idea if you have modified files,
+ since it will require a merge in each direction.]
+
+ cvs update -A
+
+ *or*
+
+ B. Move the ./CVS/Tag file out of the way.
+
+ mv ./CVS/Tag HOLD_Tag
+
+ 2. Add and branch the file "normally":
+
+ cvs add <file>
+ cvs commit <file>
+ cvs tag -b <branch_tag> <file>
+
+ [<branch_tag> is the same Branch Tag as you used on all
+ the other files. Look at ./CVS/Entries or the output
+ from "cvs stat" for sticky tags.]
+
+ 3. Clean up the temporary step.
+
+ A. If you moved the ./CVS/Tag file, put it back. Then
+ move the new file onto the branch where you are working.
+
+ mv HOLD_Tag ./CVS/Tag
+ cvs update -r <branch_tag> <file>
+
+ B. If you ran "update -A" rather than moving the ./CVS/Tag
+ file, move the whole directory (including the new file) back
+ onto the branch where you were working:
+
+ cvs update -r <branch_tag>
+
+
+ 3A.6 How do I cancel an "add"?
+
+ If you want to remove the file entirely and cancel the "add" at
+ the same time, type:
+
+ cvs remove -f <file>
+
+ If you want to cancel the "add", but leave the file as it was
+ before you typed "cvs add", then you have to fake it:
+
+ mv <file> <file>.hold
+ cvs remove <file>
+ mv <file>.hold <file>
+
+
+ 3A.7 What are the ./CVS/file,p and ./CVS/file,t files for?
+
+ The ./CVS/file,p and ./CVS/file,t files are created by the "add"
+ command to hold command line options and message text between the
+ time of the "add" command and the expected "commit".
+
+ The ./CVS/file,p file is always null, since its function was
+ absorbed by the "options" field in the ./CVS/Entries file. If you
+ put something in this file it will be used as arguments to the RCS
+ "ci" command that commit uses to check the file in, but CVS itself
+ doesn't put anything there.
+
+ The ./CVS/file,t file is null unless you specify an initial
+ message in an "add -m 'message'" command. The text is handed to
+ "rcs -i -t./CVS/file,t" to create the initial RCS file container.
+
+ Both files must exist to commit a newly added file. If the
+ ./CVS/file,p file doesn't exist, CVS prints an error and aborts
+ the commit. If the ./CVS/file,t file doesn't exist, RCS prints an
+ error and CVS gets confused, but does no harm.
+
+ To recover from missing ,p and ,t files, just create two
+ zero-length files and rerun the "commit".
+
+
+ 3A.8 How do I "add" a binary file?
+
+ If you configured CVS to use the GNU version of "diff" and
+ "diff3", you only need to turn off RCS keyword expansion.
+
+ First you turn off RCS keyword expansion for the initial checkin
+ by using "add -ko". It works like "update -ko" in creating a
+ "sticky" option only for the copy of the file in the current
+ working directory.
+
+ cvs add -ko <file>
+
+ Commit the file normally. The sticky -ko option will be used.
+
+ cvs commit <file>
+
+ Then mark the RCS file in the Repository so that keyword
+ expansion is turned off for all checked out versions of the file.
+
+ cvs admin -ko <file>
+
+ Since "admin -ko" records the keyword substitution value in the
+ Repository's RCS file, you no longer need the sticky option. You
+ can turn it off with the "update -A" command, but if you were on a
+ branch, you'll have to follow it "update -r <branch_tag>" to put
+ yourself back on the branch.
+
+
+ Managing that binary file is another problem. See 4D.1.
+
+
+
+----------------
+-- Section 3B -- "admin", "adm", "rcs"
+----------------
+
+ **** Questions:
+
+ 3B.1 What is "admin" for?
+ 3B.2 Wow! Isn't that dangerous?
+ 3B.3 What would I normally use "admin" for?
+ 3B.4 What should I avoid when using "admin"?
+ 3B.5 How do I restrict the "admin" command? The -i flag in the modules
+ file can restrict commits. What's the equivalent for "admin"?
+ 3B.6 I backed out a revision with "admin -o" and committed a
+ replacement. Why doesn't "update" retrieve the new revision?
+
+
+ **** Answers:
+
+
+ 3B.1 What is "admin" for?
+
+ To provide direct access to the underlying "rcs" command (which
+ is not documented in this FAQ) bypassing all safeguards and CVS
+ assumptions.
+
+
+ 3B.2 Wow! Isn't that dangerous?
+
+ Yes.
+
+ Though you can't hurt the internal structure of an RCS file using
+ its own "rcs" command, you *can* change the underlying RCS
+ files using "admin" in ways that CVS can't handle.
+
+ If you feel the need to use "admin", create some test files
+ with the RCS "ci" command and experiment on them with "rcs"
+ before blasting any CVS files.
+
+
+ 3B.3 What would I normally use "admin" for?
+
+ Normally, you wouldn't use admin at all. In unusual
+ circumstances, experts can use it to set up or restore the
+ internal RCS state that CVS requires.
+
+ You can use "admin -o" (for "outdate") to remove revisions
+ you don't care about. This has its own problems, such as leaving
+ dangling Tags and confusing the "update" command.
+
+ There is some feeling among manipulators of binary files that
+ "admin -l" should be used to serialize access. See 3C.8.
+
+ An interesting use for "admin" came up while maintaining CVS
+ itself. I import versions of CVS onto the Vendor branch of my
+ copy of CVS, make changes to some files and ship the diffs
+ (created by "cvs diff -c -r TO_BRIAN") off to Brian Berliner.
+ After creating the diff, I retag ("cvs tag -F TO_BRIAN") the
+ working directory, which is then ready to produce the next patch.
+
+ I'll use "add.c" as an example (only because the name is short).
+
+ When the next release came out, I discovered that the released
+ "add.c" (version 1.1.1.3 on the Vendor branch) was exactly the
+ same as my modified file (version 1.3). I didn't care about the
+ changelog on versions 1.2 and 1.3 (or the evidence of having done
+ the work), so I decided to revert the file to the state where it
+ looked like I had not touched the file -- where I was just using
+ the latest on the vendor branch after a sequence of imports.
+
+ To do that, I removed all the revisions on the main branch, except
+ for the original 1.1 from which the Vendor branch sprouts:
+
+ cvs admin -o1.2: add.c
+
+ Then I set the RCS "default branch" back to the Vendor branch, the
+ way import would have created it:
+
+ cvs admin -b1.1.1 add.c
+
+ And I moved the "TO_BRIAN" Tag to the latest revision on the
+ Vendor branch, since that is the base from which further patches
+ would be created (if I made any):
+
+ cvs admin -NTO_BRIAN:1.1.1.3 add.c
+
+ Instead of 1.1.1.3, I could have used one of the "Release Tags"
+ last applied by "import" (3rd through Nth arguments).
+
+ Suggestion: Practice on non-essential files.
+
+
+
+ 3B.4 What should I avoid when using "admin"?
+
+ If you know exactly what you are doing, hack away. But under
+ normal circumstances:
+
+ Never use "admin" to alter branches (using the '-b' option), which
+ CVS takes very seriously. If you change the default branch, CVS
+ will not work as expected. If you create new branches without
+ using the "tag -b" command, you may not be able to treat them as
+ CVS branches.
+
+ See 3C.8 for a short discussion of how to use "admin -l" for
+ serializing access to binary files.
+
+ The "admin -o <file>" allows you to delete revisions, usually a
+ bad idea. You should commit a correction rather than back out a
+ revision. Outdating a revision is prone to all sorts of problems:
+
+ 1. Discarding data is always a bad idea. Unless something in the
+ revision you just committed is a threat to your job or your
+ life, (like naming a function "<boss's name>_is_a_dweeb", or
+ including the combination to the local Mafioso's safe in a C
+ comment), just leave it there. No one cares about simple
+ mistakes -- just commit a corrected revision.
+
+ 2. The time travel paradoxes you can cause by changing history
+ are not worth the trouble. Even if CVS can't interfere with
+ your parents' introduction, it *can* log commits in at least
+ two ways (history and loginfo). The reports now lie -- the
+ revision referred to in the logs no longer exists.
+
+ 3. If you used "import" to place <file> into CVS, outdating all
+ the revisions on the Main branch back to and including revision
+ 1.2 (or worse, 1.1), will produce an invalid CVS file.
+
+ If the <file>,v file only contains revision 1.1 (and the
+ connected branch revision 1.1.1.1), then the default branch
+ must be set to the Vendor branch as it was when you first
+ imported the file. Outdating back through 1.2 doesn't restore
+ the branch setting. Despite the above admonition against it,
+ "admin -b" is the only way to recover:
+
+ cvs admin -b1.1.1 <file>
+
+ 4. Although you can't outdate a physical (RCS) branch point
+ without removing the whole branch, you *can* outdate a revision
+ referred to by a magic branch tag. If you do so, you will
+ invalidate the branch.
+
+ 5. If you "outdate" a tagged revision, you will invalidate all
+ uses of the <tag>, not just the one on <file>. A tag is
+ supposed to be attached to a consistent set of files, usually a
+ set built as a unit. By discarding one of the files in the
+ set, you have destroyed the utility of the <tag>. And it
+ leaves a dangling tag, which points to nothing.
+
+ 6. And even worse, if you commit a revision already tagged, you
+ will alter what the <tag> pointed to without using the "tag"
+ command. For example, if revision 1.3 has <tag> attached to it
+ and you "outdate" the 1.3 revision, <tag> will point to a
+ nonexistent revision. Although this is annoying, it is nowhere
+ near as much trouble as the problem that will occur when you
+ commit to this file again, recreating revision 1.3. The old
+ tag will point to the new revision, a file that was not in
+ existence when the <tag> was applied. And the discrepancy is
+ nearly undetectable.
+
+
+ If you don't understand the above, you should not use the admin
+ command at all.
+
+
+ 3B.5 How do I restrict the "admin" command? The -i flag in the modules
+ file can restrict commits. What's the equivalent for "admin"?
+
+ At this writing, to disable the "admin" command, you will have
+ to change the program source code, recompile and reinstall.
+
+
+ 3B.6 I backed out a revision with "admin -o" and committed a
+ replacement. Why doesn't "update" retrieve the new revision?
+
+ CVS is confused because the revision in the ./CVS/Entries file
+ matches the latest revision in the Repository *and* the timestamp
+ in the ./CVS/Entries file matches your working file. CVS believes
+ that your file is "up-to-date" and doesn't need to be updated.
+
+ You can cause CVS to notice the change by "touch"ing the file.
+ Unfortunately what CVS will tell you is that you have a "Modified"
+ file. If you then "commit" the file, you will bypass the
+ normal CVS check for "up-to-date" and will probably commit the
+ revision that was originally removed by "admin -o".
+
+ Changing a file without changing the revision number confuses CVS
+ no matter whether you did it by replacing the revision (using
+ "admin -o" and "commit" or raw RCS commands) or by applying an
+ editor directly to a Repository (",v") file. Don't do it unless
+ you are absolutely certain no one has the latest revision of the
+ file checked out.
+
+ The best solution to this is to institute a program of deterrent
+ flogging of abusers of "admin -o".
+
+ The "admin" command has other problems." See 3B.4 above.
+
+
+----------------
+-- Section 3C -- "checkout", "co", "get"
+----------------
+
+ **** Questions:
+
+ 3C.1 What is "checkout" for?
+ 3C.2 What is the "module" that "checkout" takes on the command line?
+ 3C.3 Isn't a CVS "checkout" just a bunch of RCS checkouts?
+ 3C.4 What's the difference between "update" and "checkout"?
+ 3C.5 Why can't I check out a file from within my working directory?
+ 3C.6 How do I avoid dealing with those long relative pathnames?
+ 3C.7 Can I move a checked-out directory? Does CVS remember where it
+ was checked out?
+ 3C.8 How can I lock files while I'm working on them the way RCS does?
+ 3C.9 What is "checkout -s"? How is it different from "checkout -c"?
+
+
+ **** Answers:
+
+ 3C.1 What is "checkout" for?
+
+ To acquire a copy of a module (or set of files) to work on.
+
+ All work on files controlled by CVS starts with a "checkout".
+
+
+ 3C.2 What is the "module" that "checkout" takes on the command line?
+
+ It is a name for a directory or a collection of files in the
+ Repository. It provides a compact name space and the ability to
+ execute before and after helper functions based on definitions in
+ the modules file.
+
+ See 1D.11.
+
+
+ 3C.3 Isn't a CVS "checkout" just a bunch of RCS checkouts?
+
+ Like much of CVS, a similar RCS concept is used to support a CVS
+ function. But a CVS checkout is *not* the same as an RCS
+ checkout.
+
+ Differences include:
+
+ 1. CVS does not lock the files. Others may access them at the
+ same time.
+
+ 2. CVS works best when you provide a name for a collection of
+ files (a module or a directory) rather than an explicit list of
+ files to work on.
+
+ 3. CVS remembers what revisions you checked out and what branch
+ you are on, simplifying later commands.
+
+
+ 3C.4 What's the difference between "update" and "checkout"?
+
+ The "checkout" and "update" commands are nearly equivalent in how
+ they treat individual files. They differ in the following ways:
+
+ 1. The "checkout" command always creates a directory, moves into
+ it, then becomes equivalent to "update -d".
+
+ 2. The "update" command does not create directories unless you add
+ the '-d' option.
+
+ 3. "Update" is intended to be executed within a working directory
+ created by "checkout". It doesn't take a module or directory
+ argument, but figures out what Repository files to look at by
+ reading the files in the ./CVS administrative directory.
+
+ 4. The two commands generate completely different types of records
+ in the "history" file.
+
+
+ 3C.5 Why can't I check out a file from within my working directory?
+
+ Though you *can* check out a file, you normally check out a module
+ or directory. And you normally do it only once at the beginning
+ of a project.
+
+ After the initial "checkout", you can use the "update" command
+ to retrieve any file you want within the checked-out directory.
+ There is no need for further "checkout" commands.
+
+ If you want to retrieve another module or directory to work on,
+ you must provide two pathnames: where to find it in the Repository
+ and where to put it on disk. The "modules" file and your current
+ directory supply two pieces of naming information. While inside a
+ checked-out working directory, the CVS administrative information
+ provides most of the rest.
+
+ You should be careful not to confuse CVS with RCS and use
+ "checkout" in the RCS sense. An RCS "checkout" (which is
+ performed by the RCS "co" command) is closer to a "cvs update"
+ than to a "cvs checkout".
+
+
+ 3C.6 How do I avoid dealing with those long relative pathnames?
+
+ This question has also been phrased:
+
+ How do I avoid all those layers of directories on checkout?
+ or
+ Why do I have to go to the top of my working directory and
+ checkout some long pathname to get a file or two?
+
+
+ This type of question occurs only among groups of people who
+ decide not to use "modules". The answer is to use "modules".
+
+ When you hand the "checkout" command a relative pathname rather
+ than a module name, all directories in the path are created,
+ maintaining the same directory hierarchy as in the Repository.
+ The same kind of environment results if you specify a "module"
+ that is really an alias expanding into a list of relative
+ pathnames rather than a list of module names.
+
+ If you use "module" names, "checkout" creates a single
+ directory by the name of the module in your current directory.
+ This "module" directory becomes your working directory.
+
+ The "module" concept combines the ability to "name" a collection
+ of files with the ability to structure the Repository so that
+ consistent sets of files are checked out together. It is the
+ responsibility of the Repository Administrators to set up a
+ modules file that describes the software within the Repository.
+
+
+ 3C.7 Can I move a checked-out directory? Does CVS remember where it
+ was checked out?
+
+ Yes and Yes.
+
+ The ./CVS/Repository file in each working directory contains a
+ pathname pointing to the matching directory within the
+ Repository. The pathname is either absolute or relative to
+ $CVSROOT, depending on how you configured CVS.
+
+ When you move a checked-out directory, the CVS administrative
+ files will move along with it. As long as you don't move the
+ Repository itself, or alter your $CVSROOT variable, the moved
+ directory will continue to be usable.
+
+ CVS remembers where you checked out the directory in the
+ "history" file, which can be edited, or even ignored if you
+ don't use the "working directory" information displayed by the
+ "history" command.
+
+
+ 3C.8 How can I lock files while I'm working on them the way RCS does?
+
+ Until the day arrives of the all-powerful merge tool, there are
+ still files that must be accessed serially. For those instances,
+ here's a potential solution:
+
+ 1. Install a pre-commit program in the "commitinfo" file to check
+ for RCS locks. The program "rcslock.pl" performs this
+ function. It can be found in the contrib directory of the CVS
+ source distribution.
+
+ 2. When you want to make a change to a file you know can't be
+ merged, first use "cvs admin -l" to lock the file. If you
+ can't acquire the lock, use the standard "locked out" protocol:
+ go talk to the person holding the lock.
+
+ 3. Make sure the pre-commit program prints a message and exits
+ with a non-zero status if someone besides the user running
+ "commit" has the file locked. This non-zero exist status will
+ cause the "commit" to fail cleanly.
+
+ 4. Make sure the pre-commit program exits with a zero status if
+ the file is either unlocked or locked by the user running
+ "commit". The "cvs commit" command that kicked off the
+ pre-commit program will take a zero exist status as an OK and
+ checkin the file, which has the side-effect of unlocking it.
+
+
+ ===> The following is opinion and context. Don't read it if you
+ are looking for a quick fix.
+
+ The topic of locking CVS files resurfaces on the network every so
+ often, producing the same results each time:
+
+ The Big Endians:
+
+ CVS was designed to avoid locks, using a copy-modify-merge
+ model. Locking is not necessary and you should take the time
+ to learn the CVS model which many people find workable. So why
+ not get with the program and learn how to think the CVS way?
+
+ The Little Endians:
+
+ The users determine how a tool is to be used, not the
+ designers. We, the users, have always used locking, our bosses
+ demand locking, locking is good, locking is God. I don't want
+ to hear any more lectures on the CVS model. Make locking work.
+
+ Any organization making active changes to a source base will
+ eventually face the need to do parallel development. Parallel
+ development implies merges. (If you plan to keep separate copies
+ of everything and never merge, good luck. Tell me who you work
+ for so I can buy stock in your disk suppliers this year and sell
+ your stock short next year.)
+
+ Merges will never go away. CVS chose to make "merges" stand
+ front and center as an important, common occurrence in
+ development. It is one way of looking at things.
+
+ For free-format text, the merge paradigm gives you a considerable
+ amount of freedom. It does take a bit of management, but any
+ project should be ready to deal with it.
+
+ On the other hand, there are many files that can't be merged using
+ text merge techniques. Straight text merge programs like "diff3"
+ are guaranteed to fail on executables (with relative branch
+ statements), files with self-referential counts stored in the file
+ (such as TAGS files), or files with relative motion statements in
+ them (such as Frame MIF files, many postscript files). They
+ aren't all binary files.
+
+ For these types of files, and many others, there are only two
+ solutions:
+
+ 1. Complex merge tools that are intimately aware of the contents
+ of the files to be merged. (ClearCase, and probably others,
+ allow you to define your own "files types" with associated
+ "merge tools".)
+
+ 2. Serialization of access to the file. The only technical
+ solution to the problem of serialization is "locking".
+
+
+ Since you can call a program that offers:
+
+ "Which one do you want? A/B?"
+
+ a "merge tool", more and more merge tools will appear which can be
+ hooked into a merge-intensive program like CVS. Think of a bitmap
+ "merge" tool that displays the bitmaps on the screen and offers a
+ "paint" interface to allow you to cut and paste, overlay, invert
+ or fuse the two images such that the result is a "merged" file.
+
+ My conclusion is that the need for locking is temporary, awaiting
+ better technology. For large development groups, locking is not
+ an alternative to merging for text files.
+
+
+ 3C.9 What is "checkout -s"? How is it different from "checkout -c"?
+
+ The '-c' and '-s' options to "checkout" both cause the modules
+ file to appear on standard output, but formatted differently.
+
+ "checkout -c" lists the modules file alphabetized by the module
+ name. It also prints all data (including options like '-a' and
+ "-o <prog>") specified in the modules file.
+
+ "checkout -s" lists the modules file sorted by "status" field,
+ then by module name. The status field was intended to allow you
+ to mark modules with strings of your choice to get a quick sorted
+ report based on the data you chose to put in the status fields. I
+ have used it for priority ("Showstopper", etc as tied into a bug
+ database), for porting status ("Ported", "Compiled", etc. when
+ porting a large collection of modules), for "assignee" (the person
+ responsible for maintenance), and for "test suite" (which
+ automatic test procedure to run for a particular module).
+
+
+----------------
+-- Section 3D -- "commit", "ci", "com"
+----------------
+
+ **** Questions:
+
+ 3D.1 What is "commit" for?
+ 3D.2 If I edit ten files, do I have to type "commit" ten times?
+ 3D.3 Explain: cvs commit: Up-to-date check failed for `<file>'
+ 3D.4 What happens if two people try to "commit" conflicting changes?
+ 3D.5 I committed something and I don't like it. How do I remove it?
+ 3D.6 Explain: cvs commit: sticky tag `V3' for file `X' is not a branch
+ 3D.7 Why does "commit -r <tag/rev>" put newly added files in the Attic?
+ 3D.8 Why would a "commit" of a newly added file not produce rev 1.1?
+
+
+ **** Answers:
+
+ 3D.1 What is "commit" for?
+
+ To store new revisions in the Repository, making them visible
+ to other users.
+
+
+ 3D.2 If I edit ten files, do I have to type "commit" ten times?
+
+ No. The "commit" command will take multiple filenames, directory
+ names and relative pathnames on the command line and commit them
+ all with the same log message. If a file is unchanged, even if it
+ is explicitly listed on the command line, CVS will skip it.
+
+ Like all CVS commands, "commit" will work on the whole directory
+ by default. Just type "cvs commit" to tell CVS to commit all
+ modified files (i.e. the files that "update" would display
+ preceded by 'M') in the current directory and in all
+ sub-directories.
+
+
+ 3D.3 Explain: cvs commit: Up-to-date check failed for `<file>'
+
+ You may not "commit" a file if your BASE revision (i.e. the
+ revision you last checked out, committed or retrieved via
+ "update") doesn't match the HEAD revision (i.e the latest revision
+ on your branch, usually the Main Branch).
+
+ In other words, someone committed a revision since you last
+ executed "checkout", "update" or "commit". You must now execute
+ "update" to merge the other person's changes into your working
+ file before "commit" will work. You are thus protected (somewhat)
+ from a common form of race condition in source control systems,
+ where a checkin of a minor alteration of a second copy of the same
+ base file obliterates the changes made in the first.
+
+ Normally, the "update" command's auto-merge should be followed
+ by another round of building and testing before the "commit".
+
+
+ 3D.4 What happens if two people try to "commit" conflicting changes?
+
+ Conflicts can occur only when two developers check out the same
+ revision of the same file and make changes. The first developer
+ to commit the file has no chance of seeing the conflict. Only the
+ second developer runs into it, usually when faced with the
+ "Up-to-date" error explained in the previous question.
+
+ There are two types of conflicts:
+
+ 1. When two developers make changes to the same section of code,
+ the auto-merge caused by "update" will print a 'C' on your
+ terminal and leave "overlap" markers in the file.
+
+ You are expected to examine and clean them up before committing
+ the file. (That may be obvious to *some* of you, but . . .)
+
+ 2. A more difficult problem arises when two developers change
+ different sections of code, but make calls to, or somehow
+ depend on, the old version of each other's code.
+
+ The auto-merge does the "right" thing, if you view the file
+ as a series of text lines. But as a program, the two
+ developers have created a problem for themselves.
+
+ This is no different from making cross-referential changes in
+ *separate* files. CVS can't help you. In a perfect world, you
+ would each refer to the specification and resolve it
+ independently. In the real world you have to talk/argue, read
+ code, test and debug until the combined changes work again.
+
+ Welcome to the world of parallel development.
+
+
+ 3D.5 I committed something and I don't like it. How do I remove it?
+
+ Though you *can* use the "admin -o" (synonym: "rcs -o") command to
+ delete revisions, unless the file you committed is so embarrassing
+ that the need to eradicate it overrides the need to be careful,
+ you should just grab an old version of the file ("update -p -r
+ <previous-rev>" might help here) and commit it on top of the
+ offending revision.
+
+ See Section 3B on "admin".
+
+
+ 3D.6 Explain: cvs commit: sticky tag `V3' for file `X' is not a branch
+
+ The message implies two things:
+
+ 1. You created your working directory by using "checkout -r
+ V3", or you recently executed "update -r V3".
+
+ 2. The tag named V3 is not a branch tag.
+
+
+ CVS records (i.e. makes "sticky") any "-r <tag/rev>" argument
+ handed to the "checkout" or "update" commands. The <tag/rev> is
+ recorded as the CVS working branch, which is the branch to which
+ "commit" will add a new revision.
+
+ Branch tags are created when you use the -b switch on the "tag" or
+ "rtag" commands. Branch tags are magic tags that don't create a
+ physical branch, but merely mark the revision to branch from when
+ the branch is needed. The first commit to a magic branch creates
+ a physical branch in the RCS files.
+
+ You can commit onto the end of the Main Trunk, if you have no
+ sticky tag at all, or onto the end of a branch, if you have a
+ sticky branch tag. But you can't commit a file that has a sticky
+ tag not pointing to a branch. CVS assumes a sticky Tag or
+ Revision that does not refer to a branch is attached to the middle
+ of a series of revisions. You can't squeeze a new revision
+ between two others. Sticky dates also block commits since they
+ never refer to a branch.
+
+
+ Scenario1:
+
+ If you don't want a branch and were just looking at an old
+ revision, then you can move back to the Main Branch by typing:
+
+ cvs update -A {files or dirs, default is '.'}
+
+ or you can move to the branch named <branch_tag> by:
+
+ cvs update -r <branch_tag> {files or dirs, default is '.'}
+
+
+ Scenario2:
+
+ If you really wanted to be on a branch and made an earlier
+ mistake by tagging your branch point with a non-branch tag,
+ you can recover by adding a new branch tag to the old
+ non-branch tag:
+
+ cvs rtag -b -r <oldtag> <newtag> <module>
+
+ (It was not a big mistake. Branch-point tags can be useful.
+ But the <newtag> must have a different name.)
+
+ If you don't know the <module> name or don't use "modules",
+ you can also use "tag" this way:
+
+ cvs update -r <oldtag>
+ cvs tag -b <newtag> .
+
+ Then, to put your working directory onto the branch, you type:
+
+ cvs update -r <newtag>
+
+
+ You can't delete <oldtag> before adding <newtag>, and I would
+ not advise deleting the <oldtag> at all, because it is useful
+ in referring to the branch point. If you must, you can delete
+ the non-branch tag by:
+
+ cvs rtag -d <oldtag> <module>
+ or
+ cvs tag -d <oldtag> .
+
+
+ Scenario3:
+
+ If you made the same mistake as in Scenario2 (of placing a
+ non-branch tag where you wanted a branch tag), but really want
+ <oldtag> to be the name of your branch, you can execute a
+ slightly different series of commands to rename it and move
+ your working directory onto the branch.
+
+ Warning: This is not a way to rename a branch tag. It is a way
+ to turn a non-branch tag into a branch tag with the
+ same name.
+
+ cvs rtag -r <oldtag> <branch_point_tag> <module>
+ cvs rtag -d <oldtag> <module>
+ cvs rtag -b -r <branch_point_tag> <oldtag> <module>
+
+ Then, if you really must, delete the <branch_point_tag>:
+
+ cvs rtag -d <branch_point_tag> <module>
+
+
+
+ Note: The unwieldy mixture of "tag" and "rtag" is mostly
+ because you can't specify a revision (-r <tag>) to the
+ "tag" command.
+
+ See 4C.3 for more info on creating a branch.
+
+
+ 3D.7 Why does "commit -r <tag/rev>" put newly added files in the Attic?
+
+ If you specify "-r <rev>" (where <rev> is a dotted numeric number
+ like 2.4), it correctly sets the initial revision to <rev>, but it
+ also attaches the numeric <rev> as a sticky tag and throws the
+ file into the Attic. This is a bug. The obvious solution is to
+ move the file out of the Attic into the associated Repository
+ directory and "update -A" the file. There are no Tags to clean up.
+
+ If you specify "-r <tag>" to commit a newly added file, the <tag>
+ is treated like a <branch_tag>, which becomes a symbolic RCS label
+ pointing to the string '1', which can be considered to be the
+ "Main branch number" when the main branch is still at revision
+ 1.N. The file is also thrown into the Attic. See 4C.8 for a way
+ to recover from this.
+
+ In fact, a plain "commit" without the "-r" will throw a newly
+ added file into the Attic if you added it to a directory checked
+ out on a branch. See 3A.[2-5].
+
+ See Section 4C, on Branching, for many more details.
+
+
+ 3D.8 Why would a "commit" of a newly added file not produce rev 1.1?
+
+ When committing a newly added file CVS looks for the highest main
+ branch major number in all files in the ./CVS/Entries file.
+ Normally it is '1', but if you have a file of revision 3.27 in
+ your directory, CVS will find the '3' and create revision 3.1 for
+ the first rev of <file>. Normally, the first revision is 1.1.
+
+
+----------------
+-- Section 3E -- "diff", "di", "dif"
+----------------
+
+ **** Questions:
+
+ 3E.1 What is "diff" for?
+ 3E.2 Why did "diff" display nothing when I know there are later
+ committed revisions in the Repository?
+ 3E.3 How do I display what changed in the Repository since I last
+ executed "checkout", "update" or "commit"?
+ 3E.4 How do I display the difference between my working file and what
+ I checked in last Thursday?
+ 3E.5 Why can't I pass long options, like --unified, to "diff"?
+
+
+ **** Answers:
+
+ 3E.1 What is "diff" for?
+
+ 1. To display the difference between a working file and its BASE
+ revision (the revision last checked out, updated or committed):
+
+ cvs diff <file>
+
+ 2. To display the difference between a working file and a
+ committed revision of the same file:
+
+ cvs diff -r <tag/rev> <file>
+
+ 3. To display the difference between two committed revisions of
+ the same file:
+
+ cvs diff -r <tag1/rev1> -r <tag2/rev2> <file>
+
+ You can specify any number of <file> arguments. Without any
+ <file> arguments, it compares the whole directory.
+
+ In the examples above, "-D <date>" may be substituted wherever
+ "-r <tag/rev>" appears. The revision a <date> refers to is the
+ revision that existed on that date.
+
+
+ 3E.2 Why did "diff" display nothing when I know there are later
+ committed revisions in the Repository?
+
+ By default, "diff" displays the difference between your working
+ file and the BASE revision. If you haven't made any changes to
+ the file since your last "checkout", "update" or "commit" there is
+ no difference to display.
+
+ To display the difference between your working file and the latest
+ revision committed to your current branch, type:
+
+ cvs diff -r HEAD <file>
+
+
+ 3E.3 How do I display what changed in the Repository since I last
+ executed "checkout", "update" or "commit"?
+
+ A special tag (interpreted by CVS -- it does not appear in the Tag
+ list) named "BASE" always refers to the revision you last checked
+ out, updated or committed. Another special tag named "HEAD"
+ always refers to the latest revision on your working branch.
+
+ To compare BASE and HEAD, you type:
+
+ cvs diff -r BASE -r HEAD <file>
+
+
+ 3E.4 How do I display the difference between my working file and what
+ I checked in last Thursday?
+
+ cvs diff -D "last Thursday" <file>
+
+ where "last Thursday" is a date string. To be more precise, the
+ argument to the '-D' option is a timestamp. Many formats are
+ accepted. See the man page under "-D date_spec" for details.
+
+
+ 3E.5 Why can't I pass long options, like --unified, to "diff"?
+
+ CVS only handles single character '-X' arguments, not the FSF long
+ options. CVS also passes through only arguments it knows about,
+ because a few arguments are captured and interpreted by CVS.
+
+ If you didn't configure RCS and CVS to use the GNU version of
+ diff, long options wouldn't work even if future versions of CVS
+ acquire the ability to pass them through.
+
+ Most of the long options have equivalent single-character options,
+ which do work. The "--unified" option is equivalent to '-u' in
+ revisions of GNU diff since 1.15.
+
+
+
+----------------
+-- Section 3F -- "export", "exp", "ex"
+----------------
+
+ **** Questions:
+
+ 3F.1 What is "export" for?
+ 3F.2 Why does it remove the RCS keywords so I can't use the "ident"
+ command on the source files?
+ 3F.3 Can I override the '-kv' flag CVS passes to RCS?
+ 3F.4 Why doesn't "export" have a '-k' flag like "import" does?
+ 3F.5 Why does "export -D" check out every file in the Attic?
+
+
+ **** Answers:
+
+ 3F.1 What is "export" for?
+
+ "export" checks out a copy of a module in a form intended for
+ export outside the CVS environment. The "export" command produces
+ the same directory and file structure as the "checkout" command,
+ but it doesn't create "CVS" sub-directories and it removes all the
+ RCS keywords from the files.
+
+
+ 3F.2 Why does it remove the RCS keywords so I can't use the "ident"
+ command on the source files?
+
+ It removes the RCS keywords, so that if the recipient of the
+ exported sources checks them into another set of RCS files (with
+ or without CVS), and then makes modifications through RCS or CVS
+ commands, the revision numbers that they had when you exported
+ them will be preserved. (That ident no longer works is just an
+ unfortunate side effect.)
+
+ The theory is that you are exporting the sources to someone else
+ who will make independent changes, and at some point you or they
+ will want to know what revisions from your Repository they started
+ with (probably to merge changes, or to try to decide whether to
+ merge changes).
+
+ A better way to handle this situation would be to give them their
+ own branch of your Repository. They would need to remember to
+ checkin the exported sources with RCS IDs intact (ci -k) so that
+ their changes would get revision numbers from the branch, rather
+ than starting at 1.1 again. Perhaps a future version of CVS will
+ provide a way to export sources this way.
+
+ Contributed by Dan Franklin
+
+
+ 3F.3 Can I override the '-kv' flag CVS passes to RCS?
+
+ Not as of CVS version 1.4.
+
+
+ 3F.4 Why doesn't "export" have a '-k' flag like "import" does?
+
+ Export is intended for a specific purpose -- to remove all trace
+ of revision control on the way *out* of CVS.
+
+
+ 3F.5 Why does "export -D" check out every file in the Attic?
+
+ See 5B.3 for an explanation of the same problem with "update".
+
+
+
+----------------
+-- Section 3G -- "history", "hi", "his"
+----------------
+
+ **** Questions:
+
+ 3G.1 What is "history" for?
+ 3G.2 Of what use is it?
+ 3G.3 What is this, Big Brother?
+ 3G.4 I deleted my working directory and "history" still says I have
+ it checked out. How do I fix it?
+ 3G.5 So I *can* edit the History file?
+ 3G.6 Why does the history file grow so quickly?
+ 3G.7 What is the difference between "cvs history -r <tag/rev>" and
+ "cvs history -t <tag>"?
+ 3G.8 Why does "cvs history -c -t <tag>" fail to print anything?
+ 3G.9 "cvs history -a -o" only printed one line for each checked-out
+ module. Shouldn't it print all the directories where the
+ modules are checked out?
+ 3G.10 I can't figure out "history", can you give me concrete examples?
+ 3G.11 Can we merge history files when we merge Repositories?
+
+
+ **** Answers:
+
+ 3G.1 What is "history" for?
+
+ To provide information difficult or impossible to extract out of
+ the RCS files, such as a "tag" history or a summary of module
+ activities.
+
+
+ 3G.2 Of what use is it?
+
+ I have found it useful in a number of ways, including:
+
+ 1. Providing a list of files changed since
+
+ - A tagged release.
+ - Yesterday, last Thursday, or a specific date.
+ - Someone changed a specific file.
+
+ 2. Providing a list of special events:
+
+ - Files added or removed since one of the above events.
+ - Merge failures since one of the above events. (Where did the
+ conflicts occur?)
+ - Has anyone (and who) grabbed the revision of this file I
+ committed last week, or are they still working blind?
+
+ 3. Telling me how often a file/directory/module has been changed.
+
+ 4. Dumping a summary of work done on a particular module,
+ including who last worked on it and what changed.
+
+ 5. Displaying the checked-out modules and where they are being
+ worked on.
+
+ 6. To tell me what users "joe" and "malcolm" have done this week.
+
+
+ 3G.3 What is this, Big Brother?
+
+ War is Peace.
+ Freedom is Slavery.
+ Ignorance is Strength.
+
+ Normally manager types and those with the power to play Big
+ Brother don't care about this information. The Software Engineer
+ responsible for integration usually wants to know who is working
+ on what and what changed. Use your imagination.
+
+
+ 3G.4 I deleted my working directory and "history" still says I have
+ it checked out. How do I fix it?
+
+ You can use "release -f" to forcibly add a "release" record to the
+ history file for a working directory associated with a "module".
+ If your version of "release" doesn't have the '-f' option, or you
+ checked out the directory using a relative path, you have to edit
+ the $CVSROOT/CVSROOT/history file.
+
+ You can remove the last 'O' line in the history file referring
+ to the module in question or add an 'F' record.
+
+
+ 3G.5 So I *can* edit the History file?
+
+ Yes, but if you are using history at all, you should take a little
+ care not to lose information. I normally use Emacs on the file,
+ since it can detect that a file has changed out from under it.
+ You could also copy and zero out the history file, edit the copy
+ and append any new records to the edited copy before replacing it.
+
+
+ 3G.6 Why does the history file grow so quickly?
+
+ It stores 'U' records, which come in handy sometimes when you
+ are tracking whether people have updated each other's code
+ before testing. There should (and probably will sometime) be a
+ way to choose what kinds of events go into the history file.
+
+ The contributed "cln_hist.pl" script will remove all the 'U'
+ records, plus matching pairs of 'O' and 'F' records during
+ your normal clean up of the history file.
+
+
+ 3G.7 What is the difference between "cvs history -r <tag/rev>" and
+ "cvs history -t <tag>"?
+
+ The '-t' option looks for a Tag record stored by "rtag" in the
+ history file and limits the search to dates after the last <tag>
+ of the given name was added.
+
+ The '-r' option was intended to search all files looking for the
+ <tag> in the RCS files. It takes forever and needs to be
+ rewritten.
+
+
+ 3G.8 Why does "cvs history -c -t <tag>" fail to print anything?
+
+ You have been using "tag" instead of "rtag". The "tag" command
+ currently doesn't store a history record. This is another remnant
+ of CVS's earlier firm belief in "modules". But it also has a
+ basis in how "rtag" and "tag" were originally used.
+
+ "rtag" was intended for large-scale tagging of large chunks of the
+ Repository, an event work recording. "tag" was intended for
+ adding and updating tags on a few files or directories, though it
+ could also be used to tag the entire checked-out working tree when
+ there is no module defined to match the tree or when the working
+ tree is the only place where the right collection of revisions to
+ tag can be found.
+
+
+ 3G.9 "cvs history -a -o" only printed one line for each checked-out
+ module. Shouldn't it print all the directories where the
+ modules are checked out?
+
+ Not as designed.
+
+ Command Question it is supposed to answer.
+ ---------------- ------------------------------------------
+ cvs history -o What modules do I have checked out?
+ cvs history -a -o <same for all users>
+
+ cvs history -o -w What working directories have I created
+ and what modules are in them?
+ cvs history -a -o -w <same for every user>
+
+ The -o option chooses the "checked out modules" report, which is
+ the default history report.
+
+
+ 3G.10 I can't figure out "history", can you give me concrete examples?
+
+ Default output selects records only for the user who executes the
+ "history" command. To see records for other users, add one or
+ more "-u user" options or the '-a' option to select *all* users.
+
+ To list (for the selected users): Type "cvs history" and:
+
+ * Checked out modules: -o (the default)
+ * Files added since creation: -x A
+ * Modified files since creation: -c
+ * Modified files since last Friday: -c -D 'last Friday'
+ * Modified files since TAG was added: -c -t <tag>
+ * Modified files since TAG on files: -c -r <tag>
+ * Last modifier of file/Repository X? -c -l -[fp] X
+ * Modified files since string "str": -c -b str
+ * Tag history: (Actually "rtag".) -T
+ * History of file/Repository/module X: -[fpn] X
+ * Module report on "module": -m module
+
+
+ 3G.11 Can we merge history files when we merge Repositories?
+
+ Assuming that the two Repositories have different sets of
+ pathnames, it should be possible to merge two history files by
+ sorting them together by the timestamp fields.
+
+ You should be able to run:
+
+ sort +0.1 ${dir1}/history ${dir2}/history > history
+
+
+ If you "diff" a standard history file before and after such a
+ sort, you might see other differences caused by garbage (split
+ lines, nulls, etc) in the file. If your Repository is mounted
+ through NFS onto multiple machines you will also see a few
+ differences caused by different clocks on different machines.
+ (Especially if you don't use NTP to keep the clocks in sync.)
+
+
+
+----------------
+-- Section 3H -- "import", "im", "imp"
+----------------
+
+ **** Questions:
+
+ 3H.1 What is "import" for?
+ 3H.2 How am I supposed to use "import"?
+ 3H.3 Why does import put files on a branch? Why can't I work on the
+ main trunk instead of a Vendor branch?
+ 3H.4 Is there any way to import binary files?
+ 3H.5 Why does "import" corrupt some binary files?
+ 3H.6 How do I retain the original $\Revision$ strings in the sources?
+=3H.7 I imported some files for the Yarg compiler that compiles files
+ with a suffix of ".yarg" and whose comment prefix is "YARG> ".
+ When I check them out, they will no longer compile because they
+ have this junk in them. Why?
+ 3H.8 How do I make "import" save the timestamps on the original files?
+ 3H.9 Why can't I "import" 3 releases on different branches?
+ 3H.10 What do I do if the Vendor adds or deletes files between releases?
+ 3H.11 What about if the Vendor changes the names of files or
+ directories, or rearranges the whole structure between releases?
+ 3H.12 I thought "import" was for Vendor releases, why would I use it
+ for code of my own? Do I have to use import?
+ 3H.13 How do I import a large Vendor release?
+ 3H.14 Explain: ERROR: cannot create link to <file>: Permission denied
+ 3H.15 Where does the -m <message> go when the file doesn't change?
+ 3H.16 How do I "import" just the files ignored by a previous "import"?
+ 3H.17 Why did "import" ignore all the symlinks?
+
+
+ **** Answers:
+
+ 3H.1 What is "import" for?
+
+ The "import" command is a fast way to insert a whole tree of files
+ into CVS.
+
+ The first "import" to a particular file within the Repository
+ creates an RCS file with a single revision on the "Vendor branch."
+ Subsequent "import"s of the same file within the Repository append
+ a new revision onto the Vendor branch. It does not, as some seem
+ to believe, create a new branch for each "import". All "imports"
+ are appended to the single Vendor branch.
+
+ If the file hasn't changed, no new revision is created -- the new
+ "Release-Tag" is added to the previous revision.
+
+ After the import is finished, files you have not changed locally
+ are considered to have changed in the "Main line of development".
+ Files you *have* changed locally must have the new Vendor code
+ merged into them before they are visible on the "Main line".
+
+ See 4C.6 and 4C.15
+
+
+ 3H.2 How am I supposed to use "import"?
+
+ Create a source directory containing only the files you want to
+ import. Make sure you clean up any cruft left over from previous
+ builds or editing. You want to make sure that the directory
+ contains only what you want to call "source" from which everything
+ else is built.
+
+ If this is not the first import from this "Vendor", you should
+ also compare the output of "find . ! -name CVS -print | sort"
+ executed both at the head of a checked out working directory and
+ at the head of the sources to be imported. If you find any
+ deleted or renamed files, you have to deal with them by hand.
+ (See 4B.8 on renaming.)
+
+ "cd" into your source directory and type:
+
+ cvs import -m "Message" <repos> <Vendor-Tag> <Release-Tag>
+
+ where <repos> is the relative directory pathname within the
+ Repository that corresponds to the sources you are importing.
+
+ You might also consider using the "-I !" option to avoid ignoring
+ anything. It is easier to remove bogus files from the Repository
+ than to create a sparse tree of the ignored files and rerun
+ "import".
+
+ For example, if the FSF, CVS, Make and I are still active in the
+ year 2015, I'll import version 89.53 of GNU make this way:
+
+ cvs import -m "GNUmake V89.53" gnu/make GNU GNUMAKE_89_53
+
+ See 3H.13 for more details.
+
+
+ 3H.3 Why does import put files on a branch? Why can't I work on the
+ main trunk instead of a Vendor branch?
+
+ This was a Design choice. The Vendor branch is the way "import"
+ deals with a Vendor release. It is a solution to the Engineering
+ problem of how to merge multiple external releases of
+ Vendor-supplied sources into your ongoing work. The Vendor
+ releases are kept on a separate, special, "Vendor" branch and your
+ work is kept on the RCS trunk. New Vendor releases are imported
+ onto the Vendor branch and then merged into your work, if there is
+ any, on the trunk.
+
+ This way, you can use CVS to find out not only about your work,
+ but you can also find out what the Vendor changed by diffing
+ between two of the Release Tags you handed to "import".
+
+ CVS was designed to work this way. If you use CVS in some other
+ way, you should think carefully about what you are doing.
+
+ Note that the CVS "Main Branch" and the RCS Main Trunk are not the
+ same. Placing files on the Vendor Branch doesn't keep you from
+ creating a development branch to work on.
+
+ See Section 4C, on Branching.
+
+
+ If you are not working with 3rd party (i.e. Vendor) sources, you
+ can skip the "import" and avoid the Vendor branch entirely. It
+ works just as well to move pre-existing RCS files into Repository
+ directories.
+
+ You can create a whole Repository tree by copying a directory
+ hierarchy of normal source files directly into the Repository and
+ applying CVS to it. Here's an idea you should *test* before using:
+
+ cd <your source tree>
+ set source = `pwd`
+ set module = xyzzy <<== Your choice of directory name
+ mkdir $CVSROOT/$module
+ cd $CVSROOT/$module
+ (cd $source; tar cf - .) | tar xvpBf -
+ find . -type f -exec ci -t-Original. {} \;
+
+ The RCS "ci" command, without -u or -l options, will turn your
+ source file into an RCS (",v") and delete the original source.
+
+
+ 3H.4 Is there any way to import binary files?
+
+ If you configured CVS to use the GNU version of "diff" and
+ "diff3", then you can import any kind of file.
+
+ Binary files with RCS keywords in them are a problem, since you
+ don't want them to expand.
+
+ If the tree you are about to "import" is entirely filled with
+ binary files, you can use the '-ko' option on "import".
+ Otherwise, I would run the import normally, then fix the binary
+ files as described below in 3H.5.
+
+ See 4D.1 on Binary files.
+
+
+ 3H.5 Why does "import" corrupt some binary files?
+
+ The RCS "co" command, when it is invoked by a CVS "checkout" or
+ "update" (or after a "commit") command, searches for and expands a
+ list of keywords within the file. They are documented in the RCS
+ "co" man page. Strings such as "$\Id$" (or "$\Id:"), or
+ "$\Revision$" (or "$\Revision:") are altered to the include the
+ indicated information.
+
+ [[Note: The keywords should appear in the text without the '\'
+ character I have inserted to *avoid* expansion here. The only
+ real RCS keywords in this document are at the top of the file,
+ where I store the Revision and Date.]]
+
+ If RCS keyword strings show up in a binary file, they will be
+ altered unless you set the '-ko' option on the RCS files to tell
+ RCS to keep the original keyword values and not to expand new
+ ones. After "import", you can set the '-ko' option this way:
+
+ cvs admin -ko <file>
+ rm <file>
+ cvs update <file>
+
+ After an import that didn't use '-ko' (because the whole tree
+ wasn't of binary files) you should fix up the binary files as
+ described above before checking out any new copies of the files
+ and before updating any working directories you checked out
+ earlier.
+
+ See 4D.1 on Binary files.
+
+
+ 3H.6 How do I retain the original $\Revision$ strings in the sources?
+
+ If you want to leave old RCS keywords as they are, you can use the
+ '-ko' tricks described above.
+
+
+=3H.7 I imported some files for the Yarg compiler that compiles files
+ with a suffix of ".yarg" and whose comment prefix is "YARG> ".
+ When I check them out, they will no longer compile because they
+ have this junk in them. Why?
+
+ YARG>YARG>YARG>YARG>YARG>YARG>YARG>YARG>YARG>YARG>YARG>YARG>YARG>
+ YARG> $\Log:
+ # Revision 1.3 1998/03/03 00:16:16 bubba
+ # What is 2+2 anyway?
+ #
+ # Revision 1.2 1998/03/03 00:15:15 bubba
+ # Added scorekeeping.
+ YARG>
+ YARG>YARG>YARG>YARG>YARG>YARG>YARG>YARG>YARG>YARG>YARG>YARG>YARG>
+
+
+ Well bubba, "Yarg" hasn't hit the big time yet. Neither RCS nor
+ CVS know about your suffix or your comment prefix. So you have
+ two choices:
+
+ 1. Check out the Yarg-less module, and tell all the files about
+ your comment prefix. Visit each directory and type:
+
+ cvs admin -c"YARG> " *.yarg
+
+ If *all* files in the whole directory tree are Yarg files,
+ you can use this instead:
+
+ cvs admin -c"YARG> " .
+
+ Then save any changes you made, remove all the "*.yarg" files
+ and grab new copies from the Repository:
+
+ rm *.yarg
+ (or: find . -name '*.yarg' -exec rm {} ';')
+ (or: find . -name '*.yarg' -print | xargs rm)
+ (or: find . -name '*.yarg' -print0 | xargs -0 rm
+ if you have spaces in filenames and the GNU find/xargs.)
+ cvs update
+
+ It might be faster to remove the whole directory and check it
+ out again.
+
+ 2. Change the import.c file in the CVS sources and add the .yarg
+ suffix, along with the "YARG> " comment prefix to the
+ "comtable" array.
+
+ If you ever plan to add new files with $\Log in them, you
+ should also go into the RCS sources and make the same change in
+ the table contained in the "rcsfnms.c" file.
+
+ Then delete the imported files from the Repository and
+ re-"import" the sources.
+
+
+ 3H.8 How do I make "import" save the timestamps on the original files?
+
+ Use "import -d" to save the current timestamps on the files as the
+ RCS revision times.
+
+ See 4D.8 for another aspect of file timestamps.
+
+
+ 3H.9 Why can't I "import" 3 releases on different branches?
+
+ I'll bet you typed something like this:
+
+ cd /src/blasto.v2
+ cvs import -b 1.1.2 VENDOR2 Version2
+ cd /src/blasto.v3
+ cvs import -b 1.1.3 VENDOR3 Version3
+ cd /src/blasto.v4
+ cvs import -b 1.1.4 VENDOR4 Version4
+
+ This is wrong, or at least it won't help you much. You have
+ created three separate Vendor branches, which is probably not
+ what you wanted.
+
+ Earlier versions of CVS, as described in Brian Berliner's Usenix
+ paper, tried to support multiple Vendor branches on the theory
+ that you might receive source for the *same* program from multiple
+ vendors. It turns out that this is very rare, whereas the need to
+ branch in *your* development, for releases and for project
+ branches, is much greater.
+
+ So the model now is to use a single vendor branch to contain a
+ series of releases from the same vendor. Your work moves along
+ on the Main Trunk, or on a CVS branch to support a real
+ "branch in development".
+
+ To set this up, you should type this instead of the above:
+
+ cd /src/blasto.v2
+ cvs import VENDOR Version2
+ cd /src/blasto.v3
+ cvs import VENDOR Version3
+ cd /src/blasto.v4
+ cvs import VENDOR Version4
+
+
+ 3H.10 What do I do if the Vendor adds or deletes files between releases?
+
+ Added files show up with no extra effort. To handle "removed"
+ files, you should always compare the tree structure of the new
+ release against the one you have in your Repository. If the
+ Vendor has removed files since the previous release, go into a
+ working directory containing your current version of the sources
+ and "cvs remove" (followed by "cvs commit" to make it really take
+ effect) each file that is no longer in the latest release.
+
+ Using this scheme will allow you to "checkout" any version of
+ the vendor's code, with the correct revisions and files, by
+ using "checkout -r Version[234]".
+
+ Renames are harder to find, since you have to compare file
+ contents to determine that one has occurred. If you notice one,
+ see 4B.8 on renaming files.
+
+
+ 3H.11 What about if the Vendor changes the names of files or
+ directories, or rearranges the whole structure between releases?
+
+ Currently CVS can't handle this cleanly. It requires
+ "renaming" a bunch of files or directories.
+
+ See 4B.8 on "renaming" for more details.
+
+ What I generally do is to close the Repository for a while and
+ make changes in both the Repository and in a copy of the vendor
+ release until the structure matches, then execute the import.
+
+ If you ever have to check out and build an old version, you may
+ have to use the new, or completely different Makefiles.
+
+
+ 3H.12 I thought "import" was for Vendor releases, why would I use it
+ for code of my own? Do I have to use import?
+
+ For code you produce yourself, "import" is a convenience for fast
+ insertion of whole trees. It is not necessary. You can just as
+ easily create ",v" files using the RCS "ci" command and move
+ them directly into the Repository.
+
+ Other than the CVSROOT directory, the Repository consists entirely
+ of directories of ",v" files. The Repository contains no other
+ state information.
+
+ See Section 4B, on Setting up and Managing the Repository.
+
+
+ 3H.13 How do I import a large Vendor release?
+
+ When the sum of the changes made by the Vendor and the changes
+ made by local developers is small, "import" is not a big
+ problem. But when you are managing a large Repository, any care
+ taken up front will save you time later.
+
+ First read the following, then, before executing "import", see the
+ questions in Section 4C dealing with branch merges and Vendor
+ branch merges.
+
+ 0. If this is not the first import of this code, before starting,
+ rtag the whole directory you will be changing.
+
+ 1. The first step is to make sure the structure of the new files
+ matches the structure of the current Repository.
+
+ Run "find . -print | sort" on both trees and "diff" the output.
+
+ 2. Alter the "source" tree until the "diff" (of the list of
+ filenames, not of the whole trees) shows that the directory
+ structures are equivalent.
+
+ The "comm" command, if you have it, can help figure out what
+ has been added or deleted between releases.
+
+ 3. If they deleted any files, you can handle them cleanly with
+ "cvs remove". The command "comm -23 files.old files.new" will
+ show you a list of files that need to be removed.
+
+ You should examine the list first to see if any have been
+ renamed rather than simply deleted.
+
+ 4. If they renamed any files, see 4B.8 on renaming files.
+
+ 5. Remember to *SAVE* the output from the import command.
+
+ 6. When you have dealt with removed and renamed files, then you
+ can execute the import:
+
+ cd <new source>
+ cvs import -I ! -m "Message" <repos> <VendorTag> <ReleaseTag>
+
+
+ Where
+
+ "-I !" is an optional argument that keeps "import" from
+ ignoring files. The comparison of the "find"
+ commands above will probably avoid the need for
+ this, but it is easier to remove files from the
+ Repository than to run a subset "import" to catch
+ just the ignored files.
+ [You might have to quote or backwhack the '!'.]
+
+ Message is the log message to be stored in the RCS files.
+
+ <repos> is a relative path to a directory within the
+ Repository. The directory <new source> must be at
+ the same relative level within the new sources as
+ the <repos> you give is within the Repository. (I
+ realize this is not obvious. Experiment first.)
+
+ <VendorTag> is a Tag used to identify the Vendor who sent you
+ the files you are importing. All "imports" into
+ the same <repos> *must* use the same VendorTag.
+ You can find it later by using the "log" command.
+
+ <ReleaseTag> is a Tag used to identify the particular release
+ of the software you are importing. It must be
+ unique and should be mnemonic -- at least include
+ the revision number in it. (Note: you can't use
+ '.' characters in a Tag. Substitute '_' or '-'.)
+
+ 7. There will be six categories of files to deal with.
+ (Actually there are eight, but you have already dealt with
+ "removed" and "renamed" files.)
+
+ If this is the first "import" into a given <repos> directory,
+ only the first three of these ('I', 'L' and 'N') can occur.
+
+
+ a. Ignored file.
+
+ CVS prints: I filename
+
+ You'll need to examine it to see if it *should* have been
+ ignored. If you use "-I !", nothing will be ignored.
+
+
+ b. Symbolic link.
+
+ CVS prints: L linkname
+
+ Links are "ignored", but you'll probably want to create
+ a "checkout helper" function to regenerate them.
+
+
+ c. New file.
+
+ CVS prints: N filename
+
+ CVS creates a new file in the Repository. You don't
+ have to do anything to the file, but you might have to
+ change Makefiles to refer to it if this is really a new
+ file.
+
+
+ d. A file unchanged by the Vendor since its last release.
+
+ CVS prints: U filename
+
+ CVS will notice this and simply add the new ReleaseTag
+ to the latest rev on the Vendor branch.
+
+ No work will be needed by you, whether you have changed
+ the file or not. No one will notice anything.
+
+ e. A file changed by the Vendor, but not by you.
+
+ CVS prints: U filename
+
+ CVS should add the file onto the vendor branch and
+ attach the Release Tag to it.
+
+ When you next execute "update" in any working directory
+ you'll get the new revision.
+
+
+ f. A file changed by both the Vendor and by you.
+
+ CVS prints: C filename
+
+ These are the trouble files. For each of these files
+ (or in groups -- I usually do one directory at a
+ time), you must execute:
+
+ cvs update -j <PreviousReleaseTag> -j <ReleaseTag>
+ or
+ cvs update -j <VendorTag:yesterday> -j <VendorTag>
+
+ It will print either 'M' (if no overlaps) or 'C', if
+ overlaps. If a 'C' shows up, you'll need to edit the
+ file by hand.
+
+ Then, for every file, you'll need to execute "cvs commit".
+
+ See the part of Section 4C dealing with branch merges.
+
+
+ 8. If you are truly performing a large import, you will most
+ likely need help. Managing those people is another problem
+ area.
+
+ Since the merge of the Vendor branch is just like any other
+ merge, you should read section 4C for more info about
+ performing and cleaning up merges.
+
+ The larger the import, and the larger the group of people
+ involved, the more often you should use "tag" and "rtag" to
+ record even trivial milestones. See 4C.14, especially the
+ "paranoid" section.
+
+ Before starting the import, you should install and test a
+ "commitinfo" procedure to record all commits in a file or via
+ Email to a mail archive. Along with the tags you placed on the
+ Repository before the import, this archive will help to track
+ what was changed, if problems occur
+
+ There are four stages to the recovery:
+
+ A. Parcel out the work -- Effective Emacs Engineering.
+
+ As input to the assignment process, you might want to
+ examine the tree and record the last person who changed the
+ file. You can also research, if you don't already know, who
+ is expert in each area of the software.
+
+ Examine the import log (you saved the output, right?),
+ estimate how much work is involved in each area and assign
+ groups of files to individual developers. Unless some
+ directory is immense, it is easier to manage if you assign
+ whole directories to one person.
+
+ Keep a list. Suggest a completion date/time. Tell them to
+ "commit" the file when they are finished with the merge.
+ If you tagged the Repository before starting the import, you
+ should have no trouble figuring out what happened.
+
+ If you can, find out (or tell them) which working directory
+ to use. You should verify that the working directory they
+ use is on the Main Branch ("update -A") and without modified
+ files.
+
+ If you trust your crew, have them notify you by Email. Have
+ them send you the output from "cvs update" in their working
+ directory. You might have to poll some people until you are
+ certain they have finished, or have given up. (This is not
+ an invention. I've heard a false, "Yeah, sure. I finished
+ yesterday," more times that you'd believe.)
+
+ When all reports are in, go on to the Source Verification
+ stage.
+
+ B. Source Verification -- CVS and other Tools.
+
+ If you didn't dictate which ones to use, find all working
+ directories and run "cvs -n update" in all of them. The
+ history command and the "commitinfo" log you set up might
+ help to find checked out working directories.
+
+ Sticky conflict flags will help, but they can't recover from
+ sloppiness or incompetence. You might want to check
+ everything out into a tree and grep for the parts of the
+ merge conflict markers CVS doesn't look for. CVS looks for
+ the string '^>>>>>>> '. The merge operation also puts
+ '^<<<<<<< ' and '^======= ' markers in the file that
+ careless developers might leave there.
+
+ If you find problems simply by looking at the source files
+ and working directories, start the flogging now. Resolving
+ the textual conflicts is the easy part. Weed the turkeys
+ out before reaching the next part of the cleanup -- the
+ resolution of logical conflicts.
+
+ Then apply a set of post-commit tags.
+
+ C. Logical Verification -- Diff and powerful eyeballs.
+
+ No source control system can solve the problem of resolving
+ distributed conflicts in program logic. If you change the
+ argument template for function A (defined in file A.c) and
+ add new calls to function A from within function B (defined
+ in file B.c) using the old argument format, you are outside
+ the realm of CVS's competence.
+
+ Assign someone to understand what the Vendor changed by
+ running "cvs diff -c -r <PreviousReleaseTag> <ReleaseTag>",
+ where the tags were those handed to the last two invocations
+ of "import".
+
+ Then have the same person compare that output (logically or
+ you can actually diff the diffs) to the output of the
+ similar "cvs diff -c -r <pre-import-tag> <post-commit-tag>".
+ The two sets of differences should be almost identical.
+ They should both show only the work *you* have performed.
+
+ D. Product Verification -- Build and Test.
+
+ Don't let your help off the hook until you verify that the
+ merge actually produced something that can compile and pass
+ tests. Compiling should really be part of the logical
+ verification phase, but you should test the output of the
+ build system before declaring victory and releasing the
+ troops.
+
+
+ 9. After it is all built, apply another set of tags to mark the
+ end of the "import process". You can delete the intermediate
+ tags you added during source and logic testing, but keep the
+ "pre-import" and "post-import" tags forever.
+
+
+ Of course, experience can tell you when to skip a step. But I'd
+ start out by considering each one as necessary unless you can
+ prove otherwise.
+
+
+
+ 3H.14 Explain: ERROR: cannot create link to <file>: Permission denied
+
+ This error appears when you try to execute a second (or later)
+ "import" into the same module from a directory to which you don't
+ have write access.
+
+ The "link error" is caused by a feature purposely added to
+ speed up the import.
+
+ Though the error message is somewhat strange, it indicates that
+ "import" is supposed to be executed only in writable directories.
+
+
+ 3H.15 Where does the -m <message> go when the file doesn't change?
+
+ The <message> handed to import is used as an RCS log message, but
+ only if the imported file changed since the last version on the
+ Vendor branch. If the imported file hasn't changed, then no new
+ revision is created. The <ReleaseTag> is still applied, but to
+ the previous revision. So the Tags are still correct, but the
+ message is lost.
+
+ Maybe it should be appended to the previous log message. But
+ currently it isn't.
+
+
+ 3H.16 How do I "import" just the files ignored by a previous "import"?
+
+ A real answer follows, but first, an editorial:
+
+ I am now convinced that you should always use the "-I !"
+ option. Removing a few extraneous files from the Repository
+ is a lot easier than the recovery step described below.
+
+
+ Let's assume your original import procedure was:
+ (We assume there is enough disk space in /tmp.)
+
+ cd <head-of-vendor-tree>
+ cvs import -m 'xyz 1.3' gnu/xyz GNU GNUXYZ_1_3 | tee /tmp/IMP
+
+ To import just the files ignored by "import", I would do this:
+
+ 1. Create a list of the ignored files to import:
+
+ cd <head-of-vendor-tree>
+ awk '/^I / {print $2}' /tmp/IMP | sed 's|^gnu/xyz/||' > /tmp/IG
+ [Edit the IG file to contain just the files you want.]
+
+ 2. Then create a sparse directory by handing your list to the GNU
+ version of "tar", installed in many places as "gtar":
+
+ mkdir /tmp/FIXUP
+ gtar -T /tmp/IG -c -f - . | (cd /tmp/FIXUP; gtar xvBf -)
+
+ 3. Then rerun the import. Use the exact same command, but execute
+ it in the sparse directory tree you just created. And this
+ time, tell it not to ignore anything.
+
+ cd /tmp/FIXUP
+ cvs import -I ! -m 'xyz 1.3' gnu/xyz GNU GNUXYZ_1_3
+
+
+ 3H.17 Why did "import" ignore all the symlinks?
+
+ This is another design choice.
+
+ Like the Unix "tar" command, "import" could sprout an option to
+ follow symbolic links, but I don't think CVS will ever follow
+ symbolic links by default.
+
+ Two possible future enhancements have been seriously discussed:
+
+ 1. Treat symbolic links as data in its parent directory (the way
+ ClearCase does) in some sort of per-directory control file.
+
+ 2. Treat symbolic links as version-controlled elements themselves,
+ whose data is the value of readlink(2).
+
+ For now, they are simply ignored.
+
+ If you want to save and reconstruct symlinks, you might want to
+ define a "checkout" or "update" program in the modules file which
+ could consult a file kept under CVS in your working directory and
+ make sure the specified links are in place.
+
+
+
+----------------
+-- Section 3I -- "log", "lo", "rlog"
+----------------
+
+ **** Questions:
+
+ 3I.1 What is "log" for?
+ 3I.2 How do I extract the log entries between two revisions?
+ 3I.3 How do I extract the log entries on a whole branch?
+ 3I.4 How do I generate ChangeLogs from RCS logs?
+ 3I.5 Why does "log" tell me a file was committed exactly 5 hours later
+ than I know it was?
+
+
+ **** Answers:
+
+ 3I.1 What is "log" for?
+
+ To provide an interface to the RCS "rlog" command, which displays
+ information about the underlying RCS files, including the revision
+ history and Tag (RCS calls it a "symbol") list.
+
+
+ 3I.2 How do I extract the log entries between two revisions?
+
+ If both <rev1> and <rev2> are on the same branch, you can get
+ what you are looking for with: (If they aren't on the same branch
+ you'll either get an error or a display of the whole change log.)
+
+ cvs log -r<rev1>:<rev2> <file>
+
+ If you want all the revisions on the branch from <rev1> to the end
+ of the branch <rev1> is on, you can use:
+
+ cvs log -r<rev1>: <file>
+
+ (If <rev1> is a numeric RCS symbol attached to a branch revision
+ with an even number of '.'s in it, you get the whole branch.)
+
+ If you want all the revisions on the branch from the beginning of
+ the branch <rev2> is on up to revision <rev2>, you can use:
+
+ cvs log -r:<rev2> <file>
+
+
+ Note: Depending on whether <rev1> and <rev2> are:
+
+ - numeric or symbolic
+ - in the file or not
+ - on the same branch or not
+
+ the RCS "rlog" (and therefore the "cvs log") command will
+ display some combination of:
+
+ - error messages
+ - (intuitively correct) partial log listings
+ - a display of the entire change log.
+
+
+ 3I.3 How do I extract the log entries on a whole branch?
+
+ cvs log -r<rev> <file>
+
+ where <rev> must be a branch revision (one with an even number
+ of dots) or a *non-branch* tag on a branch revision. Non-branch
+ tags on a branch revision are not normally attached by CVS, to add
+ one you will have to explicitly tag a physical branch number
+ within each file. Since these branch numbers are almost never the
+ same in different files, this command is not all that useful.
+
+ The intuitive command (at least from the CVS perspective):
+
+ cvs log -r<branch_tag> <file>
+
+ does not work.
+
+
+ 3I.4 How do I generate ChangeLogs from RCS logs?
+
+ A program called rcs2log is distributed as part of GNU Emacs 19.
+ A (possibly older) version of this program appears in the contrib
+ directory of the cvs source tree.
+
+
+ 3I.5 Why does "log" tell me a file was committed exactly 5 hours later
+ than I know it was?
+
+ I can tell by this question that you were working in a time zone
+ that is 5 hours behind GMT (e.g. the U.S. East Coast in winter).
+
+ RCS file dates are stored in GMT to allow users in different time
+ zones to agree on the meaning of a timestamp. At first glance
+ this doesn't seem necessary, but many companies use distributed
+ file systems, such as NFS or AFS, across multiple timezones.
+
+ Some standard form must be used. GMT, as the "grid origin", is an
+ obvious candidate. The only other reasonable choice is to put the
+ timezone information in all the time stamps, but that changes the
+ RCS file format incompatibly, a step which has been avoided in the
+ last few RCS releases.
+
+
+----------------
+-- Section 3J -- "patch", "pa", "rdiff"
+----------------
+
+ **** Questions:
+
+ 3J.1 What is "patch" for?
+ 3J.2 Why does "patch" include files from the Attic when I use '-D'?
+ 3J.3 How do I make "patch" produce a patch for one or two files?
+ It seems to work only with modules.
+
+
+ **** Answers:
+
+ 3J.1 What is "patch" for?
+
+ To produce a "diff" between tagged releases to be handed to the
+ "patch" command at other sites. This is the standard way that
+ source patches are distributed on the network.
+
+
+ 3J.2 Why does "patch" include files from the Attic when I use '-D'?
+
+ See the explanation of the same problem with "update -D"
+ contained in section 5B.
+
+
+ 3J.3 How do I make "patch" produce a patch for one or two files?
+ It seems to work only with modules.
+
+ Patch is intended for producing patches of whole modules between
+ releases to be distributed to remote sites. Instead of "patch",
+ you can use the "diff" command with the '-c' context option:
+
+ cvs diff -c -r <rev/tag> -r <rev/tag> <file1> . . .
+
+ The patch command will be able to merge such a "diff" into the
+ remote source files.
+
+ If you configured CVS to use a version of "diff" that supports the
+ '-u' option, you can produce a more compact "patch" in "unidiff"
+ format. The latest revisions of the patch command can parse and
+ apply patches in "unidiff" format.
+
+
+
+----------------
+-- Section 3K -- "release", "re", "rel"
+----------------
+
+
+ **** Questions:
+
+ 3K.1 What is "release" for?
+ 3K.2 Why can't I reverse a "cvs checkout path/name/subdir" with a
+ "cvs release path/name/subdir" without an "unknown module name"?
+ 3K.3 Why can't I "release" portions of a checked out directory? I
+ should be able to "release" any file or sub-directory within
+ my working directory.
+ 3K.4 I removed the tree that I was about to start working on. How do I
+ tell cvs that I want to release it if I don't have it anymore?
+ 3K.5 Why doesn't "release -d module" reverse a "checkout module"?
+ 3K.6 Why can't I release a module renamed with "cvs checkout -d"?
+
+
+ **** Answers:
+
+ 3K.1 What is "release" for?
+
+ To register that a module is no longer in use. It is intended
+ to reverse the effects of a "checkout" by adding a record to
+ the history file to balance the checkout record and by
+ optionally allowing you to delete the checked-out directory
+ associated with the module name.
+
+
+ 3K.2 Why can't I reverse a "cvs checkout path/name/subdir" with a
+ "cvs release path/name/subdir" without an "unknown module name"?
+
+ A simplistic implementation. (I can say this -- I wrote it.)
+
+ The "release" function was written for CVS 1.2 under the
+ assumption that the "module name" is a first class, unavoidable
+ interface to the Repository, allowing no way to retrieve anything
+ other than by module name. Though it is easier to program that
+ way, many users of CVS believe the modules support to be too
+ primitive to allow such a limitation.
+
+ Since "release" was written, other parts of CVS broke that
+ assumption. It needs to be revised.
+
+
+ 3K.3 Why can't I "release" portions of a checked out directory? I
+ should be able to "release" any file or sub-directory within
+ my working directory.
+
+ This isn't really a limitation in "release", per se. CVS doesn't
+ try to keep track of which files in which directories are "checked
+ out" and which are just lying there. You can delete directories
+ and "update" will not bring them back unless you add a special
+ "-d" option.
+
+ In other words, CVS doesn't keep track of how you adjust the
+ partition between files you consider part of your working set and
+ files that were checked out because they are part of the same
+ module or directory. And neither does "release".
+
+ In future CVS releases, "release" might become sophisticated
+ enough to handle both the reversal of a "checkout" and the
+ deletion of random portions of the working directory, but it isn't
+ that way now.
+
+
+ 3K.4 I removed the tree that I was about to start working on. How do I
+ tell cvs that I want to release it if I don't have it anymore?
+
+ See 3G.4.
+
+
+ 3K.5 Why doesn't "release -d module" reverse a "checkout module"?
+
+ It does, if you are using "module" in a way that "release"
+ expects: a non-alias string in the left column of the "modules"
+ database.
+
+ If "module" is really an alias, or if you are using a relative
+ path in the place of "module", or if you renamed the directory
+ with the -d option in the modules file or on the "checkout"
+ command line, then the current version of "release" won't work.
+
+ Future versions of "release" will probably fix most of these.
+
+
+ 3K.6 Why can't I release a module renamed with "cvs checkout -d"?
+
+ The current version of "release" doesn't know how to track the
+ renaming option ('-d') of the "checkout" command. It will
+ probably be fixed in the future.
+
+
+
+----------------
+-- Section 3L -- "remove", "rm", "delete"
+----------------
+
+ **** Questions:
+
+ 3L.1 What is "remove" for?
+ 3L.2 Why doesn't "remove" work on directories when it appears to try?
+ 3L.3 I don't like removing files. Is there another way to ignore them?
+ 3L.4 I just removed a file. How do I resurrect it?
+ 3L.5 Why doesn't "remove" delete the file? Instead, it prints an
+ error message and tells me to remove the file by hand.
+
+
+ **** Answers:
+
+ 3L.1 What is "remove" for?
+
+ To remove a file from the working branch. It removes a file from
+ the main branch by placing it in an "Attic" directory.
+
+
+ 3L.2 Why doesn't "remove" work on directories when it appears to try?
+
+ Oversight. It should be able to delete an empty directory, but
+ you still don't have a way to remember when it was there and when
+ it disappeared to allow the "-D <date>" option to work.
+
+ You'll have to remove the working directory and the matching
+ directory in the Repository.
+
+
+ 3L.3 I don't like removing files. Is there another way to ignore them?
+
+ There's no reason to be hasty in using the "remove" command.
+
+ If there is a way to ignore files in your build procedures, I'd
+ just do that. Later, when you decide that the files are really
+ ancient, you can execute a "remove" command to clean up.
+
+ The CVS "ignore" concept can't ignore files already in CVS.
+
+
+ 3L.4 I just removed a file. How do I resurrect it?
+
+ If you executed "remove", but haven't typed "commit" (you can
+ tell this by the 'R' notation that "update" prints next to the
+ file), you can execute "add" to reverse the "remove".
+
+ If you followed the "remove" with a "commit", you'll have
+ to move it back out of the Attic by hand:
+
+ I use something like this: (csh-like syntax)
+
+ set repos = `cat ./CVS/Repository`
+ mv $repos/Attic/filename,v $repos/filename,v
+
+ (If you use relative paths in your Repository files, that first
+ line becomes: set repos = $CVSROOT/`cat ./CVS/Repository`)
+
+ While a file is in the Attic, you can't "add" another file by
+ the same name. To add such a file you either have to move it by
+ hand as in the above, or delete it from the Attic.
+
+ The main reason for the Attic is to retain files with tags in
+ them. If you execute: "update -r <oldtag>", files with <oldtag>
+ attached to some revision will be taken from the normal Repository
+ area and from the Attic. That's why you can't "add" a file with
+ the same name. "remove" only moves a file off the main branch, it
+ doesn't obliterate it.
+
+
+ 3L.5 Why doesn't "remove" delete the file? Instead, it prints an
+ error message and tells me to remove the file by hand.
+
+ Design choice. Unix software written within last decade, usually
+ requires an extra verification step, such as answering a question
+ or adding a flag on the command line. CVS currently requires that
+ you delete the file first unless you specify the '-f' (force)
+ option, which deletes the file before performing "cvs remove".
+
+
+
+----------------
+-- Section 3M -- "rtag", "rt", "rfreeze"
+----------------
+
+(See the "tag" section below for the general questions about Tagging, which
+ "tag" and "rtag" share in common.)
+
+
+ **** Questions:
+
+ 3M.1 What is "rtag" for?
+ 3M.2 Why use "rtag"? It assumes no one is changing the Repository.
+ 3M.3 What revision does "rtag -r <tag1> <tag2>" actually put the tag on?
+ 3M.4 What happens if the tags are the same in "rtag -r <tag> <tag>"?
+ 3M.5 Why doesn't "rtag -b -r <branch_tag1> <branch_tag2>" rename or
+ duplicate a magic branch tag?
+
+
+ **** Answers:
+
+ 3M.1 What is "rtag" for?
+
+ To add a symbolic label (a "tag") to the last committed revisions
+ of a module directly in the Repository.
+
+
+ 3M.2 Why use "rtag"? It assumes no one is changing the Repository.
+
+ Though the "tag" command is more useful in marking the
+ revisions you have in a particular working directory, "rtag" is
+ much handier for whole-Repository actions, which occur at major
+ release boundaries.
+
+
+ 3M.3 What revision does "rtag -r <tag1> <tag2>" actually put the tag on?
+
+ In short, the '-r' option is another way to select the revision to
+ tag. The revision is selected the same way for all commands that
+ accept a "-r <tag/rev>" option.
+
+ Depending on whether <tag1> is a <branch_tag>, or a non-branch
+ <tag> and on whether you use the '-b' option to "rtag", you get
+ four different results:
+
+ 1. rtag -r <tag1> <tag2>
+
+ Adds the non-branch tag <tag2> to the same revision that the
+ non-branch tag <tag1> is attached to.
+
+ Example:
+ <tag1> --> TT1
+ <tag2> --> TT2
+ <file> --> Symbols: TT1:1.4
+ After --> Symbols: TT1:1.4,TT2:1.4
+
+
+ 2. rtag -r <branch_tag1> <tag2>
+
+ Adds the non-branch tag <tag2> to the HEAD of (the highest
+ revision number on) the branch labelled with tag <branch_tag1>.
+
+ Example:
+ <branch_tag1> --> BR1
+ <tag2> --> TT2
+ <file> --> Symbols: BR1:1.2.0.2 (1.2.2.5 is HEAD)
+ After --> Symbols: BR1:1.2.0.2,TT2:1.2.2.5
+
+ If the branch tagged by <branch_tag1> has not been created,
+ then the tag shows up on the branch point revision:
+
+ Example:
+ <branch_tag1> --> BR1
+ <tag2> --> TT2
+ <file> --> Symbols: BR1:1.2.0.2 (No 1.2.X exists.)
+ After --> Symbols: BR1:1.2.0.2,TT2:1.2
+
+
+ 3. rtag -b -r <tag1> <branch_tag2>
+
+ Adds the magic branch tag <branch_tag2> to the revision that
+ the non-branch tag <tag1> is attached to, preparing it to be a
+ branch point.
+
+ Example:
+ <tag1> --> TT1
+ <branch_tag2> --> BR2
+ <file> --> Symbol: TT1:1.4
+ After --> Symbol: TT1:1.4, BR2:1.4.0.2
+
+
+ 4. rtag -b -r <branch_tag1> <branch_tag2>
+
+ Adds the magic branch tag <branch_tag2> to the revision at the
+ HEAD of (the highest revision number on) the branch labelled
+ with <branch_tag1>, preparing it to be a branch point.
+
+ Example:
+ <branch_tag1> --> BR1
+ <branch_tag2> --> BR2
+ <file> --> Symbol: BR1:1.2.0.2 (1.2.2.5 is HEAD)
+ After --> Symbol: BR1:1.2.0.2,BR2:1.2.2.5.0.2
+
+ If the branch tagged by <branch_tag1> has not been created,
+ then the tag shows up as a second branch off the same
+ branch point revision:
+
+ Example:
+ <branch_tag1> --> BR1
+ <tag2> --> TT2
+ <file> --> Symbols: BR1:1.2.0.2 (No 1.2.X exists.)
+ After --> Symbols: BR1:1.2.0.2,TT2:1.2.0.4
+
+
+
+ In all four cases above, if <tag2> already exists on the file, you
+ get an error unless you specify the '-F' option.
+
+ In all four cases, if <tag1> does not exist on the file, <tag2> is
+ not added unless you specify the '-f' option.
+
+
+ 3M.4 What happens if the tags are the same in "rtag -r <tag> <tag>"?
+
+ Again, there are four cases depending on whether <tag> is a
+ branch tag, or a non-branch tag and on whether you use the
+ '-b' option to "rtag":
+
+ 1. rtag -r <tag> <tag>
+
+ Is a no-op. It does nothing even with '-F' specified.
+
+ If you add the '-f' option ("rtag -f -r <tag> <tag>"), then
+ <tag> is attached to the latest revision on the Main Branch if
+ the file does *not* already have <tag> on some revision.
+
+ If the <tag> is already on the file, using "rtag -f" is still
+ a no-op.
+
+
+ 2. rtag -r <branch_tag> <branch_tag>
+
+ Produces an error, since the <branch_tag> is already on some
+ revision of the file.
+
+ But, "rtag -F -r <branch_tag> <branch_tag>" turns the magic
+ branch tag into a non-branch tag.
+
+ Symbols: BR1:1.4.0.2
+ becomes
+ Symbols: BR1:1.4
+
+
+ 3. rtag -b -r <tag> <tag>
+
+ Produces an error, since the <tag> is already on the file.
+
+ But, "rtag -F -b -r <tag> <tag>" turns the non-branch
+ tag into a magic branch tag.
+
+ Symbols: BR1:1.4
+ becomes
+ Symbols: BR1:1.4.0.2
+
+
+ 4. rtag -b -r <branch_tag> <branch_tag>
+
+ Produces an error, since the <branch_tag> is already on the
+ file.
+
+ But, "rtag -F -b -r <branch_tag> <branch_tag>" increments the
+ branch number. It essentially removes the branch and creates a
+ new one by the same name.
+
+ Symbols: BR1:1.2.0.4
+ becomes
+ Symbols: BR1:1.2.0.6
+
+
+
+ 3M.5 Why doesn't "rtag -b -r <branch_tag1> <branch_tag2>" rename or
+ duplicate a magic branch tag?
+
+ None of the "tag" or "rtag" options rename anything. They only
+ apply (or, with the '-F' option, move) tags to specific revisions
+ in the file.
+
+ See 3M.[3-4] above for details of how it works.
+
+ To rename a non-branch tag, see 3O.9.
+ To rename a magic branch tag, see 4D.5
+
+
+
+----------------
+-- Section 3N -- "status", "st", "stat"
+----------------
+
+ **** Questions:
+
+ 3N.1 What is "status" for?
+ 3N.2 Why does "status" limit the File: at the top to 17 characters?
+ 3N.3 Why does it print "Sticky" lines when the values are "(none)"?
+ 3N.4 Shouldn't the status "Needs Checkout" be "Needs Update"?
+
+
+ **** Answers:
+
+ 3N.1 What is "status" for?
+
+ To display the status of files, including the revision and branch
+ you are working on and the existence of "sticky" information.
+
+
+ 3N.2 Why does "status" limit the File: at the top to 17 characters?
+
+ Designed that way to line up with other data. You can find the
+ whole filename in the line beginning with "RCS version:", which is
+ not limited in length.
+
+
+ 3N.3 Why does it print "Sticky" lines when the values are "(none)"?
+
+ Oversight. It should probably elide lines without information.
+
+
+ 3N.4 Shouldn't the status "Needs Checkout" be "Needs Update"?
+
+ Probably.
+
+ [[Did this show up in CVS 1.4?]]
+
+
+
+----------------
+-- Section 3O -- "tag", "ta", "freeze"
+----------------
+
+ **** Questions:
+
+ 3O.1 What is "tag" for?
+ 3O.2 What is the difference between "tag" and "rtag"?
+ 3O.3 Why does "tag -b" not put a tag on the Branch Point revision?
+ How do I refer to the Branch Point?
+ 3O.4 So "{r}tag" labels a bunch of files. What do you use a Tag for?
+ 3O.5 How do I get "tag" and "rtag" to send mail the way "commit" does?
+ 3O.6 Why can't "tag" handle the '-r' option that "rtag" takes?
+ 3O.7 After a "tag <tag>" in my working directory, why doesn't "checkout
+ -r <tag>" somewhere else produce copies of my current files?
+ 3O.8 Why doesn't "tag" write a history record the way "rtag" does?
+ 3O.9 How do I rename a <tag>?
+
+
+ **** Answers:
+
+ 3O.1 What is "tag" for?
+
+ To add a symbolic label (a "tag") to the RCS files last checked
+ out, updated or committed in a working directory.
+
+
+ 3O.2 What is the difference between "tag" and "rtag"?
+
+ The end result of both commands is that a <tag>, or symbolic name,
+ is attached to a single revision in each of a collection of files.
+
+ The differences lie in:
+
+ 1. The collection of files they work on.
+
+ "rtag" works on the collection of files referred to by a
+ "module" name as defined in the "modules" file, or a relative
+ path within the Repository.
+
+ "tag" works on files and directories specified on the command
+ line within the user's working directory. (Default is '.')
+
+ Both commands recursively follow directory hierarchies within
+ the named files and directories.
+
+ 2. The revisions they choose to tag.
+
+ "rtag" places a tag on the latest committed revision of
+ each file on the branch specified by the '-r' option. By
+ default it tags the Main Branch.
+
+ "tag" places a tag on the BASE (i.e. last checked out, updated
+ or committed) revision of each file found in the working
+ directory. (The BASE revision of a file is the one stored in
+ the ./CVS/Entries file.)
+
+ 3. A different set of command line options.
+
+ For example, "rtag" takes a "-r <oldtag>" option to retag an
+ existing tag. The "tag" command does not.
+
+ 4. How it is logged.
+
+ Currently "rtag" records the <tag> and the module in the
+ "history" file, while "tag" does not.
+
+
+ 3O.3 Why does "tag -b" not put a tag on the Branch Point revision?
+ How do I refer to the Branch Point?
+
+ This is probably an oversight, or a disbelief in the need for it.
+ If everything works perfectly, the "update -j" command will do the
+ merge you need and you don't need to check up on it by playing
+ with the branch point revision.
+
+ The '-b' option attaches a magic branch tag to allow CVS later to
+ figure out the branch point. The actual revision that <tag> is
+ attached to does not exist. References to the branch tag are
+ equivalent to references to the latest revision on the branch.
+
+ There is no way to refer to the branch point without adding a
+ non-branch tag. You might want to add non-branch tags as a
+ habit and add branch tags later, possibly immediate after adding
+ the non-branch tag. See 4C.3 on Creating a Branch.
+
+
+ 3O.4 So "{r}tag" labels a bunch of files. What do you use a Tag for?
+
+ You use it to "checkout" the labeled collection of files as a
+ single object, referring to it by name.
+
+ Anywhere a revision number can be used a Tag can be used. In fact
+ tags are more useful because they draw a line through a collection
+ of files, marking a development milestone.
+
+ The way to think about a Tag is as a curve drawn through a matrix
+ of filename vs. revision number. Consider this:
+
+ Say we have 5 files (in some arbitrary modules, some may be in 2
+ or more modules by name, some may be in 2 or more modules because
+ of the Repository tree structure) with the following revisions:
+
+ file1 file2 file3 file4 file5
+
+ 1.1 1.1 1.1 1.1 /--1.1* <-*- <tag>
+ 1.2*- 1.2 1.2 -1.2*-
+ 1.3 \- 1.3*- 1.3 / 1.3
+ 1.4 \ 1.4 / 1.4
+ \-1.5*- 1.5
+ 1.6
+
+ At some time in the past, the '*' versions were tagged. Think
+ of the <tag> as a handle attached to the curve drawn through the
+ tagged revisions. When you pull on the handle, you get all the
+ tagged revisions. Another way to look at it is that you draw a
+ straight line through the set of revisions you care about and
+ shuffle the other revisions accordingly. Like this:
+
+ file1 file2 file3 file4 file5
+
+ 1.1
+ 1.2
+ 1.1 1.3 _
+ 1.1 1.2 1.4 1.1 /
+ 1.2*----1.3*----1.5*----1.2*----1.1 (--- <-- Look here
+ 1.3 1.6 1.3 \_
+ 1.4 1.4
+ 1.5
+
+ I find that using these visual aids, it is much easier to
+ understand what a <tag> is and what it is useful for.
+
+
+ 3O.5 How do I get "tag" and "rtag" to send mail the way "commit" does?
+
+ The "commit" command is supported by two files ("commitinfo"
+ and "loginfo") not used by other commands. To do logging the
+ same way for "tag" and "rtag" would require another file like
+ loginfo, which currently doesn't exist.
+
+ The "rtag" command requires a "module" entry, which can specify a
+ "tag" program using the "-t programname" option on the module
+ line.
+
+ There is no equivalent support for "tag".
+
+
+ 3O.6 Why can't "tag" handle the '-r' option that "rtag" takes?
+
+ Oversight. The answer is probably "Fixed in a Future Release."
+
+
+ 3O.7 After a "tag <tag>" in my working directory, why doesn't "checkout
+ -r <tag>" somewhere else produce copies of my current files?
+
+ The only reason this would fail, other than misspelling the <tag>
+ string, is that you didn't "commit" your work before "tagging" it.
+ Only committed revisions may be tagged. Modified files are not
+ marked for later tagging.
+
+
+ 3O.8 Why doesn't "tag" write a history record the way "rtag" does?
+
+ The "rtag" command was originally intended to place major
+ "release" tags onto modules. The "tag" functionality was
+ developed to *move* the more significant tag when slight changes
+ to individual files sneaked in after the release tag was stamped
+ onto the Repository.
+
+ The significant event was the "rtag", which was recorded in the
+ "history" file for the "history -T" option to work.
+
+ It turns out that "tag" is generally more useful than "rtag", so
+ the model has changed. Future revisions of CVS will probably
+ store both kinds of tags in the history file.
+
+
+ 3O.9 How do I rename a <tag>?
+
+ For a procedure to rename a branch tag, See section 4D.5
+ The following covers only non-branch tags.
+
+ First, pick a <newtag> that is not in use. You could reuse
+ (i.e. move) an existing tag to the new revisions using the '-F'
+ option, but that will confuse matters when both tags are not
+ already on a file. (It will probably confuse "rtag -f" too.)
+
+ Use "rtag" to place <newtag> only on revisions attached to
+ <oldtag> in the whole Repository, then delete the old one.
+
+ cvs rtag -r <oldtag> <newtag> world
+ cvs rtag -d <oldtag> world.
+
+
+ You can also checkout or update your working directory to the
+ <oldtag> and "tag" rather than "rtag" the result. But that
+ will take longer and it has the chance of producing conflicts.
+
+ cvs update -r <oldtag>
+ cvs tag <newtag>
+ cvs tag -d <oldtag>
+ cvs update -A (or cvs update -r <previous_tag>)
+
+
+----------------
+-- Section 3P -- "update", "up", "upd"
+----------------
+
+ **** Questions:
+
+ 3P.1 What is "update" for?
+ 3P.2 What do 'U', 'M' and 'C' mean when I type "update"? Are they
+ different for "cvs -n update"?
+ 3P.3 What's the difference between "update" and "checkout"?
+ 3P.4 Why don't I get new files when I execute "update"?
+ 3P.5 Why does "update" say 'M' both for plain modified files and for
+ successful (i.e. conflict-free) merges? Aren't they different?
+ 3P.6 What's a "sticky conflict"? How does it know a conflict occurred?
+ 3P.7 Is there a feature to tell me what I have changed, added and
+ removed without changing anything?
+ 3P.8 Why were all my files deleted when I executed "update"?
+
+
+ **** Answers:
+
+ 3P.1 What is "update" for?
+
+ The "update" command is by far the most important command and is
+ probably also the most used command.
+
+ It has five purposes: (And many options.)
+
+ 1. To display the status of your working files.
+
+ Though a plain "update" also displays the status, it does so
+ after possibly altering your working directory. To see the
+ status of your working files without changing anything, type:
+
+ cvs -n update {optional list of files}
+
+
+ 2. To merge changes made by others to the branch you are working
+ on into your working files.
+
+ Each working directory is attached to a branch, usually the
+ Main branch. To merge changes made on your working branch
+ since your last checkout, update or commit, type:
+
+ cvs update {optional list of files}
+
+
+ 3. To merge changes made on another branch into the branch you are
+ working on (your "working branch").
+
+ If you want to grab a whole branch, from the branch point,
+ which is assumed to be on the Main Branch, to the end of the
+ branch, you type:
+
+ cvs update -j <branch_tag> {optional files}
+
+ If you want to grab the changes made between two tags or
+ revisions, you type:
+
+ cvs update -j <tag1> -j <tag2> {optional files}
+
+ (If you are working with a single file, the Tags could also be
+ revisions numbers. Unless you take great care to match
+ revision numbers across different files (a waste of time given
+ the way Tags work), using revision numbers in place of the
+ Tags for multiple files would be meaningless.)
+
+
+ 4. To move your working directory to another branch.
+
+ A working directory is presumed to be attached to (or working
+ on) a particular branch, usually the Main branch. To alter
+ what CVS believes to be your working branch, you "move" to that
+ branch.
+
+ To move to a tagged branch, type:
+
+ cvs update -r <branch_tag> {optional files}
+
+ To move to the Main Branch, type:
+
+ cvs update -A {optional files}
+
+ If you have modified files in your working directory, this is
+ not a clean move. CVS will attempt to merge the changes
+ necessary to make it look like you made the same changes to the
+ new branch as you made in the old one. But if you do this
+ twice without resolving the merge conflicts each time, you can
+ lose work.
+
+
+ 5. To retrieve old revisions of files.
+
+ This option is similar to 4 above but you are not restricted to
+ using a <branch_tag>. You may specify any revision or <tag>
+ with '-r' and get the specified revision or the tagged
+ revision:
+
+ cvs update -r <tag/rev> {optional files}
+
+ Or you may specify any date with '-D':
+
+ cvs update -D <date> {optional files}
+
+ The '-p' option sends the revisions to standard output
+ (normally your terminal) rather than setting the "sticky" tag
+ and changing the files.
+
+
+ 3P.2 What do 'U', 'M' and 'C' mean when I type "update"? Are they
+ different for "cvs -n update"?
+
+ "cvs update" merges changes made to the Repository, since your
+ last "checkout", "update" or "commit", into your working files.
+ You can think of it as changing your BASE revision.
+
+ "cvs update" prints lines beginning with:
+
+ 'U' after replacing your unmodified file with a different
+ revision from the Repository.
+
+ 'M' for two different reasons:
+
+ 1. for files you have modified that have not changed in
+ the Repository.
+
+ 2. after a merge, if it detected no conflicts.
+
+ 'C' after a merge, if it detected conflicts. See 2D.7 and
+ 3P.6 for more info on conflict resolution and "sticky
+ conflicts."
+
+ "cvs -n update" shows what it *would* do, rather than doing it.
+ Or, another way of looking at it, "cvs -n update" displays the
+ relationship between your current BASE revisions (identified in
+ your ./CVS/Entries file) and the HEAD revisions (the latest
+ revisions in the Repository).
+
+ "cvs -n update" prints lines beginning with:
+
+ 'U' for files you have not modified that have changed in the
+ Repository.
+
+ 'M' for files you have modified that have not changed in the
+ Repository.
+
+ 'C' for files you have modified that have also been changed in
+ the Repository.
+
+
+ See 4C.6 for what the letters mean when merging in from another
+ branch. The output is almost the same for a normal update if you
+ consider the Repository as the branch and your working directory
+ as the "trunk".
+
+
+ 3P.3 What's the difference between "update" and "checkout"?
+
+ See 3C.4 above.
+
+
+ 3P.4 Why don't I get new files when I execute "update"?
+
+ There are six reasons for nothing to happen during an "update":
+
+ 1. Nothing on your branch changed in the Repository.
+
+ If no one has committed anything to the branch you are working
+ on (normally the Main branch) since the last time you executed
+ "checkout", "update" or "commit", nothing will happen.
+
+ It's like shouting "xyzzy" or "plugh" in the wrong room.
+
+ 2. You have a "sticky" non-branch <tag> or <date> attached to the
+ working files you are trying to "update".
+
+ At some time in the past you checked out or updated your
+ directory with the "-r <tag>" or "-D <date>" option. Until you
+ do it again with a different tag or date, or go back to the
+ Main Branch with "update -A", you will never again see any
+ updates.
+
+ 3. The ./CVS/Entries.Static file exists and you are expecting a
+ new file.
+
+ If your ./CVS administrative directory contains a file named
+ Entries.Static, no files will be checked out that aren't
+ already in the Entries or Entries.Static file.
+
+ 4. You forgot to use the '-d' option and are looking for new
+ directories.
+
+ If you execute "update" without the '-d' option, it will not
+ create new directories that have been added to the Repository.
+
+ 5. You typed "update" instead of "cvs update".
+
+ On most Unix systems, your disk caches are now furiously being
+ flushed by multiple update daemons, destroying performance and
+ proving to management that you need more CPU power. :-)
+
+ On HP systems you might be asked what package you want to
+ install from the "update server".
+
+ 6. Someone removed (using "admin -o") your BASE revision (the
+ revision CVS thought you had in your working directory), then
+ committed a "replacement". CVS is now confused because the
+ revision in the Repository matches your BASE revision when the
+ files themselves don't match. See 3B.6.
+
+
+ 3P.5 Why does "update" say 'M' both for plain modified files and for
+ successful (i.e. conflict-free) merges? Aren't they different?
+
+ A design choice. Yes, they are different internally, but that
+ shouldn't matter. Your files are in the same condition after the
+ "update" as they were before -- a "diff" will display only your
+ modifications. And you are expected to continue onward with parts
+ two and three of the normal development cycle: "emacs" (a synonym
+ for "edit" in most of the civilized world) and "commit".
+
+
+ 3P.6 What's a "sticky conflict"? How does it know a conflict occurred?
+
+ When a "cvs update" (or an "update -j") creates a conflict, it
+ prints a 'C' and stores the timestamp of the file after the merge
+ in a special field in the ./CVS/Entries file.
+
+ This conflict indication implies that the merge command altered
+ your working file to contain conflict markers surrounding the
+ overlapping code segments. For example, say that
+
+ - Two developers acquire revision 1.2 of <file> via "checkout" or
+ "update".
+
+ - Developer A changes line 1 from "9999" to "5555", then commits
+ the file, creating revision 1.3.
+
+ - Developer B changes line 1 from "9999" to "7777", then tries to
+ commit the file, but is blocked because the file is not up to
+ date. Developer B then runs "update" and sees the conflict
+ marker 'C'. The beginning of the file would look like this:
+
+ <<<<<<< <file> The working <file> in question.
+ 7777 Change made to the working <file>.
+ =======
+ 5555 Change made in the first commit (1.3)
+ >>>>>>> 1.3 The revision created by the first commit.
+
+ The conflict is "sticky", which means that until the conflict is
+ cleared, the "update" command will continue to display the file's
+ status as 'C' and the "status" command will show the file's status
+ as "Unresolved Conflict".
+
+ Until the conflict is cleared, "commit" is blocked for this file.
+
+ The sticky conflict indicator can be cleared by:
+
+ 1. Resolving the conflict by editing the file. Two things must
+ happen before the conflict is considered resolved:
+
+ The timestamp of the file must change.
+ *and*
+ The file must contain no conflict markers. (The string
+ searched for in the file is the regexp: "^>>>>>>> ".)
+
+ After clearing the sticky conflict indicator, you may then
+ commit the file normally.
+
+ 2. Removing the file and running "update". This throws away the
+ local changes and accepts the latest committed file on this
+ branch. No commit is needed.
+
+ 3. Forcing the commit to happen by using "commit -f". This is
+ probably a mistake since there are few lines of real
+ text that begin with ">>>>>>> ".
+
+
+ 3P.7 Is there a feature to tell me what I have changed, added and
+ removed without changing anything?
+
+ The command "cvs -n update" will do exactly that.
+
+
+ 3P.8 Why were all my files deleted when I executed "update"?
+
+ You probably executed "update -r <tag>" some time ago, then
+ removed <tag> from the Repository files. "update -r <tag>" will
+ delete a file that doesn't contain <tag>.
+
+ A way to fix this is to "cd" into your working directory and
+ type:
+
+ cvs update -A
+
+ If you don't want the latest revisions on the Main (or Vendor)
+ Branch, then decide what Tag (normal or branch) you want and type:
+
+ cvs update -r <the_tag_you_want>
+
+ Another way to make a file disappear is to execute "update -D
+ <date>" where <date> is before the date stamped onto the first
+ revision in the RCS file.
+
+
+
+===============================================
+== Section 4 ==== Advanced Topics ====
+===============================================
+
+----------------
+-- Section 4A -- Installing CVS
+----------------
+
+ **** Questions:
+
+ 4A.1 What do I have to do before I install CVS?
+ 4A.2 How do I configure the CVS programs?
+ 4A.3 What do I have to install?
+ 4A.4 How do I work around the merge problems in GNU diff version 2.1
+ or later?
+
+
+ **** Answers:
+
+ 4A.1 What do I have to do before I install CVS?
+
+ 1. You must decide where to set up a Repository.
+
+ Though you can construct a Repository tree structure using
+ links and mount points, there must be a single copy of each
+ real file across your entire organization. You may not "rdist"
+ files and expect to edit both copies.
+
+ CVS does not support a truly distributed Repository. You can
+ have multiple Repositories, but each one must be mounted (not
+ copied or "rdist"ed) from a single place onto all machines
+ where it will be used.
+
+ Initially, a Repository takes about same amount of disk space
+ as the sources you want to put into it, plus a bit of overhead
+ for the RCS files.
+
+ See Section 4B. For multiple Repositories, see 4G.3
+
+ 2. You need a directory in everyone's $PATH variable where you can
+ install all the executables. /usr/local/bin is a common place.
+
+ 3. You need some helper tools besides CVS such as "RCS" and a
+ good set of "diff" and "diff3" programs. See 1B.4 for
+ suggestions.
+
+ 4. Read the README, INSTALL and ChangeLog files to see what you
+ are getting into.
+
+ 5. Make sure you have versions of all the programs mentioned in
+ the "cvs/src/options.h" and "cvs/src/rcs.h" files.
+
+ 6. Though you can probably muddle along without it, you should
+ appoint one or more "Repository Administrators" who will be
+ responsible for maintaining the Repository structure,
+ administrative files and the "modules" interface.
+
+ Someone at your site should probably be on the info-cvs mailing
+ list. See 1B.5.
+
+
+ 4A.2 How do I configure the CVS programs?
+
+ 1. You should certainly start by reading the README file, the
+ INSTALL files and possibly the ChangeLogs in each directory,
+ the Makefile.in files and the "cvsinit.sh" program.
+
+ 2. Edit the "options.h" file in the "src" directory.
+
+ You might need to specify a few site-specific pieces of
+ information including the names of a number of functions.
+
+ Hint1: You probably want to set the DIFF macro to use your
+ version of the GNU diff program with the '-a' option.
+ Ours is set to "gdiff -a".
+
+ Hint2: You want to use RCS 5.6.0.1 or greater and set the
+ "HAVE_RCS5" macro.
+
+ 3. Execute the ./configure command.
+
+ 4. Type "make".
+
+ 5. After running "make" you might try running the "sanity.sh"
+ script:
+ ./src/sanity.sh `pwd`/src/cvs
+
+ It writes into /tmp/cvs-sanity by default.
+
+ 6. Finish reading the INSTALL file and test out the system.
+
+
+ 4A.3 What do I have to install?
+
+ 1. Install the "cvs" executable and "mkmodules" from the CVS
+ sources. The man page is useful too. If you plan to report
+ bugs, you should also install "cvsbug".
+
+ 2. Make sure you have versions of all the programs mentioned in
+ the options.h file, most of which are included in a standard
+ Unix system.
+
+ 3. Unless you plan to reimplement RCS [:-)], you must install RCS.
+
+ It is a very good idea to examine the RCS installation
+ instructions and make sure you are using the GNU versions of
+ "diff" and "diff3" or merges (an important part of CVS) will
+ not work as well as you'd like.
+
+ 4. Set your $CVSROOT environment variable and create the
+ Repository (which you planned out in 4A.1) with the "cvsinit"
+ command at the top of the CVS sources.
+
+ 5. You'll need to edit the Repository control files created by
+ "cvsinit".
+
+ 6. Install any helper programs mentioned in the modules file.
+
+
+ 4A.4 How do I work around the merge problems in GNU diff version 2.1
+ or later?
+
+ See 1B.4 If you use recent versions of RCS and "diff", you won't
+ run into the above. If you do, see 5B.8
+
+
+----------------
+-- Section 4B -- Setting up and Managing the Repository
+----------------
+
+ **** Questions:
+
+ 4B.1 What do I do first? How do I create a Repository?
+ 4B.2 What are those files in $CVSROOT/CVSROOT?
+ 4B.3 Is there any other state stored in the Repository besides in the
+ $CVSROOT/CVSROOT directory?
+ 4B.4 How do I put sources into the Repository?
+ 4B.5 What file permissions should I use on (and in) the Repository?
+ 4B.6 How do I structure my Repository?
+ 4B.7 Why would anyone use "modules"? They are too restrictive. I
+ want to be able to select just the files I want to edit.
+ 4B.8 How do I rename a file or directory? What are the consequences?
+ 4B.9 What are "Attic" directories?
+ 4B.10 Is it OK to remove anything from the Repository?
+ 4B.11 Can I convert to CVS from RCS without losing my revision history?
+ 4B.12 Can I move RCS files with branches in them into the Repository?
+ 4B.13 Can I use raw RCS commands on the Repository?
+ 4B.14 How do I convert from SCCS to RCS?
+ 4B.15 How do I limit access to the Repository?
+ 4B.16 What are the Repository Administrator's responsibilities?
+ 4B.17 How do I move the whole Repository?
+ 4B.18 How do I change permissions on a file in the Repository by using
+ a CVS command? (i.e. without using "chmod 777 $CVSROOT/dir/file")
+
+
+ **** Answers:
+
+
+ 4B.1 What do I do first? How do I create a Repository?
+
+ First, install all the programs. (See Section 4A.)
+
+ Then create a Repository by executing "cvsinit", which works only
+ from within the head of the CVS source directory. (It needs files
+ from the distribution to work.)
+
+ If you want a very primitive Repository and don't want to save a
+ history log, refer to modules, or use any of the "info" files for
+ logging, pre-commit checks, or editing templates, you can dispense
+ with "cvsinit" entirely. I would advise executing it.
+
+ The cvsinit program will create a short modules file containing
+ the module named "CVSROOT". To to your work directory and type:
+
+ cvs checkout CVSROOT
+
+ Then read the files that are checked out.
+
+ You will certainly want to add modules of your own. Edit the
+ "modules" file and add lines to describe the items you want to
+ "checkout" by module name. Here's a short list that could be
+ used for storing a small number of GNU and PD sources:
+
+ local local
+
+ gnu local/gnu
+ emacs local/gnu/emacs
+ cvs local/gnu/cvs
+
+ public local/public
+ pdprog1 local/public/pdprog1
+ pdprog2 local/public/pdprog2
+
+ test test
+ junk test/junk
+
+
+ When you are done editing, "commit" the modules file. If you
+ configured CVS to use "dbm", you might have to edit and commit the
+ modules file twice to change the pathname of the mkmodules program
+ in the modules file.
+
+ Try using the "import" command to insert the "junk" module
+ and play around until you are comfortable.
+
+
+
+ 4B.2 What are those files in $CVSROOT/CVSROOT?
+
+ There are eight Repository control (or "database") files of
+ interest in the CVSROOT directory:
+
+ 1. modules contains the "modules" database. See 1D.11, 2C.7,
+ 4B.6 and 4B.7 for more details.
+
+ 2. commitinfo contains two columns: 1. a regular expression to
+ match against pathnames within the Repository and
+ 2. a <command> to execute for matching pathnames.
+
+ When you execute "commit", CVS passes the
+ Repository pathname for each directory (and the
+ files to commit within that directory) to
+ <command>. If <command> exits with a non-zero
+ status, the commit is blocked.
+
+ A <command> associated with a pathname of
+ "DEFAULT" is executed if nothing else matches.
+ Every <command> associated with a pathname of
+ "ALL" is executed separately.
+
+ 3. rcsinfo contains the same first column as commitinfo, but
+ the second column is a template file for
+ specifying the log entry you are required to enter
+ for each commit.
+
+ "DEFAULT" and "ALL" work the same as in the
+ commitinfo file.
+
+ 4. editinfo contains the same two columns as commitinfo, but
+ the <command> in the second column is intended to
+ do some consistency checking on the commit log.
+
+ "DEFAULT" works as in commitinfo.
+
+ 5. loginfo contains the same two columns as commitinfo, but
+ the <command> is expected to read a log message
+ from its standard input. The <command> can do
+ anything it wants with the log information, but
+ normally it is appended to a log file or sent to
+ mailing lists.
+
+ "DEFAULT" & "ALL" work the same as in commitinfo.
+
+ 6. cvsignore contains "ignore" patterns that are added to the
+ built-in ignore list. See 2D.10.
+
+ 7. checkoutlist contains a list of other files kept under RCS in
+ $CVSROOT/CVSROOT that should be checked out by
+ mkmodules to provide a readable copy.
+
+ 8. history contains a stream of text records, one for each
+ event that the "history" command is interested
+ in. Though the contents of the history file can
+ be read, it is intended to be read and displayed
+ by the "history" command. This file is the only
+ one in the above list that is not under RCS.
+
+
+ 4B.3 Is there any other state stored in the Repository besides in the
+ $CVSROOT/CVSROOT directory?
+
+ Only in the RCS files. The Repository holds exactly two things:
+ the tree of RCS files (each usually ending in ",v") and the
+ CVSROOT directory described above.
+
+
+ 4B.4 How do I put sources into the Repository?
+
+ There are three main ways to put files in the Repository:
+
+ 1. Use the "import" command described in Section 3H.
+
+ This method is the fastest way to put trees of new code into
+ the Repository and the *only* way to handle source releases
+ from a 3rd party software vendor.
+
+ 2. Use "add" followed by "commit".
+
+ This is how to add new files and directories to the Repository,
+ a few at a time. Directories don't need to be committed.
+
+ 3. You can move RCS files directly into the Repository.
+
+ You should create a directory hierarchy to hold them, but you
+ can just move arbitrary ",v" files into the Repository. The
+ only "state" in the Repository other than within ",v" files is
+ in the required CVSROOT directory at the top of the Repository.
+
+
+ 4B.5 What file permissions should I use on (and in) the Repository?
+
+ If you run a completely open environment (which usually means that
+ you don't have, or don't want to waste, the time to deal with it):
+
+ - Set all directory permissions to 777.
+
+ - Have everyone set their umasks to 0.
+
+ (BTW, I don't suggest this. I am merely reporting it.)
+
+
+ If you are a normal Unix shop and want to use groups effectively:
+
+ - Set all the directory permissions in the Repository to 775.
+
+ If you are using a system that handles both System V and BSD
+ filesystems, you might have to set the permissions to 2775.)
+
+ If you are using one of the many recent versions of Unix that
+ don't allow you to use the full octal mode, then you'll have
+ to type: chmod u=rwx,g=rwx,o=rx,g+s <dir>
+
+ - Change all the groups on the directories to match the groups
+ you want to write to various directories.
+
+ - Make sure every user is in the appropriate groups.
+
+ - Have everyone set their umask to 002, including root.
+
+
+ If you don't want non-group members to even read the files, do the
+ above, but change:
+
+ - Repository directory permissions to 770. (or 2770)
+
+ - umasks to 007.
+
+
+ If you work in an environment where people can't be trusted to
+ set their "umask" to something reasonable, you might want to set
+ the umask for them:
+
+ mv /usr/local/bin/cvs /usr/local/bin/cvs.real
+ cat > /usr/local/bin/cvs
+ #!/bin/sh
+ umask 2 # Or whatever your site standard is.
+ exec /usr/local/bin/cvs.real ${1+"$@"}
+ ^D
+
+
+ 4B.6 How do I structure my Repository?
+
+ The Repository holds your software. It can be all interrelated
+ or it can be a bunch of separately managed directories.
+
+ How you break a whole system down into its component parts, while
+ defining interfaces between them, is one aspect of "Software
+ Engineering", a discipline that requires the study of dozens of
+ strange and wonderful areas of the computer and management worlds.
+
+ CVS provides a way to keep track of changes to individual files,
+ a way to "tag" collections of files, and a way to "name"
+ collections of files and directories. That's all. Everything
+ else is in the way you apply it.
+
+ In other words, you should structure your Repository to match your
+ needs, usually tied in with the other tools you use to build,
+ install and distribute your work. Common needs include the
+ ability to:
+
+ - mount (or automount) directories from many places in your
+ organization.
+ - check out just what you need and no more.
+ - check out multiple sections in a fixed relation to each other.
+ - check out large sections to match the assumptions built into
+ your build system. (Makefiles?)
+
+ In my opinion, you should start small and keep everything in one
+ tree, placing each major sub-system into a separate directory.
+ Later, when you know what you are doing, you can make it more
+ sophisticated.
+
+
+ 4B.7 Why would anyone use "modules"? They are too restrictive. I
+ want to be able to select just the files I want to edit.
+
+ Any form of structure is restrictive. If you believe that total
+ chaos is a viable working paradigm, or if you believe you can keep
+ track of the interrelations between all portions of your
+ Repository in your head, then you can do what you please.
+
+ If you believe that systems of files require management and
+ structure, then the "modules" idea is very useful. It is a way
+ to impose a naming scheme on a tree of files, a naming scheme that
+ can be simpler than a large list of relative pathnames.
+
+ The "modules" file represents a published interface to the
+ Repository set up by your Repository Administrator. If s/he did a
+ creditable job, the modules offered will be internally consistent
+ and will smoothly interact with the rest of your environment.
+
+
+ 4B.8 How do I rename a file or directory? What are the consequences?
+
+ In CVS there is no single "rename" command.
+
+ See 2C.4 for the suggested way to rename a file or directory.
+
+ The rest of this section covers some of the consequences of
+ renaming.
+
+ A "renaming database" has been proposed that would keep track
+ of name changes so that "update -r <tag>" would continue to
+ work across the renaming. But as it stands, you have to pick
+ one of the following options:
+
+ 1. Use the technique described in 2C.4. (For each file, duplicate
+ the file in the Repository, "remove" the old version so it
+ winds up in the Attic and strip all Tags off the new version.)
+
+ - "update -r <tag>" produces the correct files.
+
+ - The duplicated revision history can be slightly misleading.
+
+ - A plain (i.e. without the "-r <tag>") "checkout" or "update
+ -d" will create directories "renamed" this way, but you can
+ delete it and a plain "update" won't bring it back.
+
+
+ 2. Move the files and directories in the Repository to the new
+ names.
+
+ - You save the revision history under a different file name.
+
+ - You save a little space.
+
+ - "update -r <tag>" produces the wrong files or directories.
+
+ This is not a good general solution, but if you plan never to
+ look back (someone may be gaining on you!), it is sometimes a
+ useful notion.
+
+ If you are clever with Makefiles, you might be able to rework
+ them to handle either the new or old names, depending on
+ which ones exist at the time. Then you can move an old <tag>
+ onto the new, more sophisticated, revision of the Makefile.
+ (Yes, this changes the "released" file if <tag> indicates a
+ release. But it is an option.)
+
+ - Important Note: If you rename a directory, you must rename
+ the corresponding directory in every checked-out working
+ directory. At the same time, you must edit the pathname
+ stored in the ./CVS/Repository file within each of the moved
+ directories.
+
+ The easiest way to move a lot of directories around is to
+ tell everyone to remove their working directories and check
+ them out again from scratch.
+
+ - The file exists in the working directory and in the
+ ./CVS/Entries file, but not in the Repository. For the old
+ file, "update" prints:
+
+ cvs update: xyz.c is no longer in the repository
+
+ and deletes the file. If the file was modified, "update"
+ prints:
+
+ cvs update: conflict: xyz.c is modified but
+ no longer in the repository
+ C xyz.c
+
+ and leaves the file alone. In the new directory, you see:
+
+ U xyz.c
+
+ as you would if someone else executed "add" and "commit".
+
+
+ 3. For each file, copy the working file to a new name in the
+ working directory and use the "cvs remove" to get rid of the
+ old old file and "cvs add" to add the new one. Since there is
+ no way for CVS to remove a directory, this only works for files.
+
+ - This is what most people think of first. Without a "rename"
+ command, the remove/add technique seems obvious.
+
+ - You lose the connection of your new working file to its past
+ revision history.
+
+
+ 4B.9 What are "Attic" directories?
+
+ When you use the "remove" command on a file, CVS doesn't delete
+ the file, it only registers your desire to delete it.
+
+ When you "commit" a removed file, CVS moves the Repository's
+ matching RCS file into a sub-directory named "Attic" within the
+ Repository.
+
+ Attic files are examined when the '-r' or '-D' option is used
+ on "checkout" or "update". If the specified revision, tag or
+ date matches one on a file in the Attic, that file is checked out
+ with the others.
+
+ You can think of the Attic as a sort of dead branch, which is only
+ looked at when you refer to a <tag> or <date>.
+
+
+ 4B.10 Is it OK to remove anything from the Repository?
+
+ In general, removing anything from the Repository is a bad idea.
+ The information in a deleted object is lost forever. There are
+ many ways to skip over files, directories and revisions without
+ deleting them.
+
+ Here are some of the consequences of removing the following things
+ stored in the Repository:
+
+ 1. CVSROOT files (Repository control files)
+
+ The Repository will work without any of them, but you should
+ understand what you are losing by deleting them. See 4B.2.
+
+ 2. Revisions
+
+ The only way to remove revisions is to use the "admin -o"
+ command (or the equivalent RCS command "rcs -o").
+
+ They are lost forever. Any tags formerly attached to deleted
+ revisions are now pointing into the Phantom Zone. You'll need
+ to contact Jor-el to get them back.
+
+ 3. Files
+
+ You should not remove a file unless you truly never want to see
+ it again. If you want to be able to check out an old revision
+ of this file, use "cvs remove" instead.
+
+ 4. Tags
+
+ Tags take up little space and you can't recover from deleting
+ them. If you depend on tags for releases you will lose vital
+ information.
+
+ 5. Directories
+
+ There is no Attic for directories, so the only way to remove
+ them is to use "rm -r". They are gone forever.
+
+ If you delete (or move) a directory, all checked-out versions
+ of that directory will cause CVS to halt. You'll have to visit
+ each checked-out directory and remove the matching working
+ directory by hand.
+
+ 6. Attic files
+
+ The "remove" command sends files to the Attic. To really
+ delete them, you have to go into the Attic and use "rm".
+
+ If a file in the Attic has a Tag on it that you might ever want
+ to check out again, you probably don't want to delete it.
+
+ 7. Lock files (named: "#cvs.[wr]fl.<pid>")
+
+ These are lock files. If you are getting "lock" errors and
+ the dates on the lock files indicate that they are old, you can
+ delete them.
+
+ Deleting lock files still in use by a CVS process might produce
+ unusual errors.
+
+
+ 4B.11 Can I convert to CVS from RCS without losing my revision history?
+
+ Yes, you can simply move (or copy) your RCS files into a directory
+ within the Repository, check out that directory and start working.
+
+
+ 4B.12 Can I move RCS files with branches in them into the Repository?
+
+ Yes, but they may not work if you created branches in a way that
+ conflicts with CVS's assumptions:
+
+ 1. You can't use .0. branches. (They are reserved for "Magic"
+ branch tags.)
+
+ 2. If you use branch 1.1.1, you can't use the Vendor branch.
+
+ You can use other RCS branches under CVS. There is no need to
+ create "magic" branch tags because the physical branch already
+ exists.
+
+
+ 4B.13 Can I use raw RCS commands on the Repository?
+
+ You can use raw rcs commands directly on the Repository if you
+ take a little care. The Repository itself contains no "CVS state"
+ (as opposed to RCS revision histories) outside the CVSROOT
+ directory.
+
+ But using raw RCS commands to change branches, tags or other
+ things that CVS depends on may render the files unusable.
+
+ See 4D.7 on RCS/CVS sharing of the Repository and Section 3B on
+ the "admin" command.
+
+
+ 4B.14 How do I convert from SCCS to RCS?
+
+ You'll have to execute something like "sccs2rcs" (in the CVS
+ contrib directory) on every file. Then you can move the resulting
+ RCS files into the Repository as described above.
+
+
+ 4B.15 How do I limit access to the Repository?
+
+ There are all sorts of ways to restrict access to Repository
+ files, none of which are hooked directly into CVS.
+
+ Techniques for limiting access include:
+
+ 1. Training, management and good backups.
+
+ The best form of Repository control is a combination of:
+
+ - A reliable backup scheme (verify it!)
+ - Enough training to ensure your developers are competent
+ and knowledgeable about all areas of your sources.
+ - Effective management of the boundaries and grey areas.
+
+ In many cases, technical solutions to "security" problems are
+ inadequate. You should first try to avoid them.
+
+ Personal Opinion: In an environment where "unknowns" are
+ allowed to touch important sources the "owner" of the CVS
+ Repository must be a large, loud, vigorous lout with a
+ well-balanced truncheon and the right to use it. Don't
+ underestimate the effectiveness of letting everyone know they
+ will be strapped into the stocks on the Town Common and pelted
+ with vegetables if they break something they don't understand
+ without first asking the experts.
+
+ 2. Set Unix groups and permissions. See 4B.5.
+ You can set different owners, groups and permissions for each
+ sub-directory within the Repository if that helps.
+
+ 3. Catch invocations of "commit" by defining pre-commit programs
+ in the "commitinfo" file. This is fairly powerful, since it
+ can block commits based on anything you can program. Take a
+ look at the programs in the "contrib" directory of the CVS
+ source tree.
+
+ 4. Use multiple Repositories, each with its own protection scheme.
+ If you use NFS (or AFS) you can even use "export" restrictions
+ to various groups of machines to keep (for example) the
+ Engineering Repository off the Customer Service machines.
+
+ 5. Try the "setgid" trick described in 4D.13.
+
+ 6. Try to use the RCS access control lists, though I don't
+ think CVS will handle them cleanly.
+
+ 7. Edit the source code to CVS to add your own access control.
+
+
+ 4B.16 What are the Repository Administrator's responsibilities?
+
+ Generally, the Administrator should set "policy", create the
+ Repository and monitor its size and control files.
+
+ Some specific responsibilities include:
+
+ 1. Examining the Repository once in a while to clean up:
+
+ a. Trash files left by misguided developers who mistake the
+ Repository for a working directory.
+
+ b. Non-RCS files. Other than the files CVS needs in the
+ $CVSROOT/CVSROOT directory, every file in the Repository
+ should be an RCS file.
+
+ c. Lock files (both CVS '#*' and RCS ',*' files) left around
+ after crashes.
+
+ d. Wrong permissions, groups and ownerships.
+
+ e. Locked files. (RCS locks, that is.)
+
+ f. Attic files that should never have been under CVS at all.
+ Don't blindly delete files from Attic directories -- they
+ were mostly put there (via the "cvs remove") for a reason.
+ Files that should be deleted are binary files (e.g. '*.o',
+ 'core', executables) that were mistakenly inserted by
+ "import -I !".
+
+ 2. Maintaining the modules file.
+
+ 3. Storing site-specific ignore patterns in the
+ $CVSROOT/CVSROOT/cvsignore file.
+
+ 4. Storing the names of non-standard CVSROOT files (See 4B.2) in
+ the $CVSROOT/CVSROOT/checkoutlist
+
+ 5. Maintaining the other Repository control files: commitinfo,
+ loginfo, rcsinfo and editinfo.
+
+ 6. Pruning the history file every once in a while. (Try the
+ "cln_hist.pl" script in the "contrib" directory.)
+
+ 7. Staying aware of developments on the info-cvs mailing list and
+ what is available in the FTP and WWW archives.
+
+ 8. Running "ps ax" once in a while and kill off any "update"
+ programs not running as "root". It is too easy to leave the
+ "cvs" off the front of the "cvs update" command.
+
+ 9. Executing monitor programs to check the internal consistency of
+ the Repository files. Ideas:
+
+ a. Files that have a default RCS branch that is not 1.1.1
+ (From an abuse of "admin -b".)
+
+ b. Files that have only Revisions 1.1 and 1.1.1.1, with a
+ default branch of "MAIN". (From an abuse of "admin -o".)
+
+ c. Existing branch tags and various branch consistency checks.
+
+
+ 4B.17 How do I move the whole Repository?
+
+ Copy or move the tree. (On Unix systems, a set of piped "tar"
+ commands works great. If the Repository does not contain any
+ symlinks, which it normally doesn't, you can also use "cp -r".)
+
+ If you can avoid changing $CVSROOT (i.e. the "logical" pathname of
+ the Repository) by replacing the old location with a symbolic link
+ to the new location, you don't have to do anything else.
+
+ (You could also mount the new location on top of the old location
+ if you are using NFS or some other filesystem that allows it.)
+
+
+ If you must change $CVSROOT, you must also tell everyone to change
+ the CVSROOT environment variable in all running shells and in any
+ personal configuration files ('.' files on Unix) where it is set.
+
+ The Repository itself contains no references to its own name,
+ except possibly in some of the files in the CVSROOT directory. If
+ your modules (or loginfo, commitinfo, etc.) file mentions helper
+ programs directly in the Repository, you'll have to change the
+ pathnames to point to the new Repository location.
+
+ The main changes you'll have to make are to all the CVS
+ administrative files (./CVS/Repository and ./CVS/Root) in every
+ working directory ever checked out from the previous location of
+ the Repository you just moved.
+
+ You have three choices:
+
+ 1. If all ./CVS/Repository files in all working directories
+ contain relative pathnames, you don't have to do anything else.
+
+ 2. Have everyone "release" or delete their working directories
+ (after committing, or just saving, their work) and check them
+ all out again from the new Repository after the move.
+
+ 3. Use "find . ( -name Repository -o -name Root )" and a
+ PERL or shell script to run through all the ./CVS/Repository
+ and ./CVS/Root files and edit the values in the files.
+
+
+ 4B.18 How do I change permissions on a file in the Repository by using
+ a CVS command? (i.e. without using "chmod 777 $CVSROOT/dir/file")
+
+ When you first "import" or "add"/"commit" a file, the read and
+ execute bits on the Repository file are inherited from the
+ original source file, while the write bits on the Repository file
+ are are turned off. This is a standard RCS action.
+
+ After that, there is no way to alter the permissions on a file in
+ the Repository using CVS (or RCS) commands. You have to change
+ the permissions on both your working file and on the Repository
+ file from which it was retrieved.
+
+ Whenever you "checkout" the file or retrieve a new revision via
+ "update" (or after a "commit"), your working file is set to match
+ the permissions of the Repository file, minus any "umask" bits you
+ have set.
+
+
+
+----------------
+-- Section 4C -- Branching and Merging
+----------------
+
+ **** Questions:
+
+ 4C.1 What is a branch?
+ 4C.2 Why (or when) would I want to create a branch?
+ 4C.3 How do I create and checkout a branch?
+ 4C.4 Once created, how do I manage a branch?
+ 4C.5 Are there any extra issues in managing multiple branches?
+ 4C.6 How do I merge a whole branch back into the trunk?
+=4C.7 How do I merge changes from the trunk into my branch or between
+ branches?
+ 4C.8 How do I merge onto the Main Branch a file that exists only on a
+ branch other than the Main Branch? (i.e. it is in the Attic)
+ 4C.9 How do I know what branch I'm (working) on?
+ 4C.10 Do I really have to know the name of the branch I'm working on?
+ 4C.11 How do I refer to the revision where I branched so I can see
+ what changed since the Branch Point on another branch?
+ 4C.12 Why didn't the command "cvs admin -bBRANCH1 *" create a branch?
+ 4C.13 Is it possible to set the "default CVS branch" for everyone?
+ 4C.14 How do I perform a large merge?
+ 4C.15 Is a Vendor merge any different from a branch merge?
+ 4C.16 How do I go back to a previous version of the code on a branch?
+ 4C.17 Once I've found the files I want, how do I start changing them?
+ I keep getting warnings about sticky tags.
+ 4C.18 Why do I get the latest files on the branch when I tried to
+ "update -r <tag>"?
+ 4C.19 How can I avoid a merge? I just want to move the latest revision
+ on my working branch directly onto the trunk.
+ 4C.20 How to I avoid merge collisions in the RCS $\Log$ data?
+ 4C.21 Why should I trust automatic merges?
+ 4C.22 How does CVS decide if it can safely perform a merge?
+ 4C.23 After resolving merge conflicts in a file, what if I want to keep
+ my previous version, and not take any of the branch changes?
+
+
+ **** Answers:
+
+ 4C.1 What is a branch?
+
+ Unfortunately, the word "branch" is an overloaded technical term.
+ It is used in too many different ways in three categories. It
+ might help to understand some of the issues by going through
+ the categories:
+
+ 1. How Humans use the word "branch":
+
+ Most development starts with everyone working on the same
+ software, making changes and heading toward a single goal.
+ This is called something like "Main Line Development". Note
+ that though many people do main line development on CVS's
+ "Main Branch", that is a choice, not a requirement.
+
+ After a release or when one or more developers want to go off
+ and work on some project for a while, the Software Engineers
+ assigned to deal with large software issues generate a "Branch
+ in Development" to support the release or project. (Keep in
+ mind that a programmer is no more a Software Engineer than a
+ carpenter is a Civil Engineer.)
+
+ Essentially, the word "branch" implies a way to allow
+ simultaneous development on the same files by multiple people.
+
+ The above terms are human-oriented. They refer to actions
+ that people would like to take. They do *not* imply any
+ particular implementation or set of procedures. Branches in
+ development can be supported in many different ways.
+
+
+ 2. How CVS uses the word "branch":
+
+ CVS uses the word "branch" in a number of ways. The two most
+ important are:
+
+ - The vendor branch holds releases from (normally) an
+ outside software vendor. It is implemented using a
+ specific RCS branch (i.e. 1.1.1).
+
+ - The "Main Branch", which normally holds your "Main Line
+ Development", but is defined as the collection of
+ revisions you get when you "checkout" something fresh, or
+ when you use the '-A' option to "update".
+
+ Important Note: The CVS "Main Branch" is *not* the same as
+ the RCS concept with the same name. If you are using Vendor
+ Branches, files you have never changed are on three branches at
+ the same time:
+
+ - The RCS 1.1.1 branch.
+ - The CVS Vendor branch.
+ - The CVS "Main Branch".
+
+ The concepts overlap, but they are not equivalent.
+
+ In referring to CVS, "branch" can be used in four other ways:
+
+ - A CVS working directory satisfies the definition of
+ "branch" for a single developer -- you are on a private
+ "virtual branch" that does not appear in any of the RCS
+ files or the CVS control files.
+
+ - The CVS "default branch" is the Repository source for the
+ collection of files in your working directory. It is
+ *not* the same as the RCS "default branch". Normally the
+ CVS default branch is the same as the CVS Main branch. If
+ you use the "-r <branch_tag>" option to the "checkout"
+ command, you will record a "sticky" tag that changes your
+ default branch to the one you checked out.
+
+ - A "magic" branch can be a branch that hasn't happened
+ yet. It is implemented by a special tag you can check out
+ that is not attached to a real RCS branch. When you
+ commit a file to a magic branch, the branch becomes real
+ (i.e. a physical RCS branch).
+
+ - And, of course, CVS uses "branch" to indicate a
+ human-oriented "branch in development".
+
+ 3. How RCS uses the word "branch":
+
+ - The RCS "Main Branch" (Synonym: "The Trunk") contains a
+ series of two-part revision numbers separated by a single '.'
+ (e.g. 1.2). It is treated specially and is the initial
+ default branch. (The default default?)
+
+ - The RCS "Default" branch starts out attached to the RCS "Main
+ Branch". For RCS purposes, it can be changed to point to any
+ branch. Within CVS, you *must*not* alter the RCS default
+ branch. It is used to support the CVS idea of a "Main
+ Branch" and it must either point to the RCS Main Branch, or
+ the Vendor Branch (1.1.1) if you haven't made any changes to
+ the file since you executed "import".
+
+
+ 4C.2 Why (or when) would I want to create a branch?
+
+ Remember that you can think of your working directory as a
+ "branch for one". You can consider yourself to be on a branch
+ all the time because you can work without interfering with others
+ until your project (big or small) is done.
+
+ The four major situations when you should create a branch:
+
+ 1. When you expect to take a long time or make a large set of
+ changes that the merging process will be difficult. Both
+ "long" and "large" are defined in your own environment.
+
+ 2. When you want to be able to "commit" and "tag" your work
+ repeatedly without affecting others.
+
+ If you ever think you need Source Control for your own work,
+ but don't want your changes to affect others, create a private
+ branch. (Put your username in the branch tag, to make it
+ obvious that it is private.)
+
+ 3. When you need to share code among a group of developers, but
+ not the whole development organization working on the files.
+
+ Rather than trying to share a working directory, you can move
+ onto a branch and share your work with others by "committing"
+ your work onto the branch. Developers not working on the
+ branch won't see your work unless they switch to your branch or
+ explicitly merge your branch into theirs.
+
+ 4. When you need to make minor changes to a released system.
+
+ Normally a "release" is labeled by a branch tag, allowing later
+ work on the released files. If the release is labeled by a
+ non-branch tag, it is easy to add a branch tag to a previously
+ tagged module with the "rtag" command. If the release is not
+ tagged, you made a mistake. Recovery requires identifying all
+ revisions involved in the release and adding a tag to them.
+
+
+ 4C.3 How do I create and checkout a branch?
+
+ Suggested technique:
+
+ 1. Attach a non-branch tag to all the revisions you want to
+ branch from. (i.e. the branch point revisions)
+
+ 2. When you decide you really need a branch, attach a branch tag
+ to the same revisions marked by the non-branch tag.
+
+ 3. "Checkout" or "update" your working directory onto the branch.
+
+
+ A. Suggested procedure when using modules:
+
+ 1. cvs rtag <branch_point_tag> module
+ 2. cvs rtag -b -r <branch_point_tag> <branch_tag> <module>
+ 3. cvs checkout -r <branch_tag> module
+
+
+ B. Suggested procedure when using your working directory, which
+ contains the revisions of your working files you want to branch
+ from:
+
+ 1. cvs tag <branch_point_tag>
+ 2. cvs rtag -b -r <branch_point_tag> <branch_tag> <module>
+ 3. cvs update -r <branch_tag>
+
+
+ In each procedure above, Step #1 applies a non-branch tag to all
+ the branch point revisions in the module/directory. Though this
+ is not strictly necessary, if you don't add a non-branch tag to
+ the revisions you branch from, you won't be able to refer to the
+ branch point in the future.
+
+ Between steps 1 & 2 you may commit changes. The result would be
+ same because "rtag -r <oldtag> <newtag>" applies <newtag> to the
+ same revision that <oldtag> is attached to. You can use this
+ technique to avoid attaching *any* branch tags until you need
+ them.
+
+ Step B.2 has two corollaries:
+
+ 1. If you plan to create the branch tag before committing
+ anything in your working directory, you can use "cvs tag -b
+ <branch_tag>" instead of the "rtag" command.
+
+ 2. The <module> can be a relative path to a directory
+ from which your working directory was checked out.
+
+ If you have trouble figuring out what <module> to use (or
+ pathname to use in its place), you can aim it at whatever
+ parent directories you believe will cover all your work.
+
+ If you are sure the <branch_tag> is not being used anywhere
+ else, you can even aim it at the whole Repository ($CVSROOT),
+ if you have to. It might take some extra time, but assuming
+ that your <tag> is a unique string and you don't use the '-f'
+ option to "rtag -r", "rtag" will only add a <tag> to files in
+ which it actually *finds* the earlier <tag>.
+
+ In each procedure above, Step #3 may occur any time after step 2.
+ Unless you explicitly remove them with "tag -d", a <tag> is
+ permanent.
+
+
+ The <branch_tag> is an unusual creature. It labels a branch in a
+ way that allows you to "checkout" the branch, to "commit" files to
+ the end of the branch and to refer to the end of the branch. It
+ does not label the base of the branch (the branch point).
+
+ There are two obvious ways to choose the <branch_point_tag> and
+ <branch_tag> names. But keep in mind that the <branch_tag> is
+ typed by any developer who wants to work on the branch -- you
+ should make it mean something to them.
+
+ Style #1 presumes that the simple version string refers to a set
+ of designed, documented or promised features, not to a specific
+ set of files. In this case, you tag the branch with the generic
+ Version string and assume that whenever you refer to "Version",
+ you want the "latest" set of files associated with that Version,
+ including all patches. (You can substitute whatever you like for
+ "bp_", as long as your <branch_point_tag> is some modification of
+ the <branch_tag>.)
+
+ <branch_point_tag> Matching <branch_tag>
+
+ bp_V1_3 V1_3
+ bp_Release2-3-5 Release2-3-5
+ bp_Production4_5 Release4_5
+
+
+ Style #2 presumes that the simple version string refers to the
+ specific set of files used to construct the first release of
+ "version". In this case, you tag the branch-point revisions with
+ the generic Version string and assume that whenever you refer to
+ this Version, you want the original set of released revisions. To
+ get the latest patched revisions of the release, you refer to the
+ branch tag "latest_<branch_point_tag>". (You can substitute what
+ ever you like for "latest_", as long as your <branch_tag> is some
+ modification of the <branch_point_tag>.)
+
+ <branch_point_tag> Matching <branch_tag>
+
+ V1_3 latest_V1_3
+ Release2-3-5 latest_Release2-3-5
+ Release4_5 latest_Production4_5
+
+
+ In both styles you can find out what you had to change since the
+ original release of this Version by typing:
+
+ cvs diff -r <branch_point_tag> -r <branch_tag>
+
+ For Style 1, this is:
+
+ cvs diff -r bp_<branch_tag> -r <branch_tag>
+
+ For Style 2, this is:
+
+ cvs diff -r <branch_point_tag> -r latest_<branch_point_tag>
+
+
+ Notes on "being on a branch":
+
+ - "update -r <tag>" tells CVS to attach a "sticky tag" to
+ working directory (in ./CVS/Tag) and the checked-out files (on
+ each line of ./CVS/Entries).
+
+ - A "sticky" <tag> (including a <branch_tag>) causes most CVS
+ commands to act as if "-r <tag>" were on the command line.
+
+ - A "sticky" <branch_tag> indicates that the working directory
+ (and working files) are "on the branch".
+
+
+ 4C.4 Once created, how do I manage a branch?
+
+ The most important thing you should know about managing a branch
+ is that the creation of a branch is not a lightweight act. When
+ you create a branch, you must also create a set of procedures to
+ keep track of it.
+
+ Specifically, you must:
+
+ - Remember that the branch exists. (This is non-trivial if you
+ create a lot of them.)
+
+ - Plan when to merge it back into the main line of development.
+
+ - Schedule the order that multiple branch merges are to be done.
+
+ - If you ever intend to merge branches into each other, instead of
+ limiting merges of branch work back into the "main line", you
+ must keep careful track of which parts of which branches have
+ merged into which other branches.
+
+
+ The simplest way to deal with branches is to limit their number,
+ "collapse" them back into the main line as quickly as is
+ reasonable and forget them. If a group wants to continue working,
+ tell them to create another branch off the fully merged main line.
+
+ Remember that CVS is just a tool. Over time, it will probably
+ handle branching better, requiring less careful attendance.
+ But no matter how good it becomes, the whole idea of "branching"
+ is a complicated management problem. Don't take it lightly.
+
+
+ 4C.5 Are there any extra issues in managing multiple branches?
+
+ If you plan to split from the "main line" and merge back after a
+ time, the only problem will be scheduling the order of branch
+ merges. As each branch is merged, the main line must be rebuilt
+ and tested. Merging multiple branches (i.e. "lines of
+ development") before building and testing creates more problems
+ than you are ready for.
+
+ If you plan to collapse some branches into others, then move the
+ combined branches back into the main line, you have to be careful
+ with the revisions and tags you hand to your "update -j"
+ command, but it shouldn't be much trouble.
+
+ If you plan to allow every branch to incrementally take the work
+ done on other branches, you are creating an almost insurmountable
+ bookkeeping problem. Every developer will say "Hey, I can
+ handle taking just this little bit," but for the system as a
+ whole it is disaster. Try it once and see. If you are forced
+ into this situation, you will need to keep track of the beginning
+ and end points of every merge ever done. Good Luck.
+
+
+ 4C.6 How do I merge a whole branch back into the trunk?
+
+ If you don't have a working directory, you can checkout and merge
+ in one command:
+
+ cvs checkout -j <branch_tag> <module>
+ cd <module>
+
+ If you already have a working directory:
+
+ cd <working_directory>
+ cvs update <== Optional, to bring it up to date.
+ cvs update -j <branch_tag>
+
+ CVS will print lines beginning with
+
+ 'U' for files that you hadn't changed, but the branch did.
+
+ 'M' for files that you changed and the branch didn't
+ *and* for files that you both changed that were merged
+ without overlaps. (This overload is unfortunate.)
+
+ 'C' for files that you both changed in a way that conflicts
+ with each other.
+
+ You need to go edit all the 'C' files and clean up the conflicts.
+ Then you must commit them.
+
+
+=4C.7 How do I merge changes from the trunk into my branch or between
+ branches?
+
+ The idea is similar to the above, but since CVS doesn't treat the
+ main branch like other branches, you'll have to be more careful.
+ There are 5 different ways to look at the problem.
+
+ A. The way to merge *all* changes made on the trunk into a working
+ branch is to move to the branch you want via "checkout -r" or
+ "update -r":
+
+ cvs update -r <branch_tag> {optional files}
+
+ Then merge the changes from the trunk into your working branch
+ using the pseudo-tag named "HEAD":
+
+ cvs up -j HEAD {optional files}
+
+ You will get everything from the branch point of the branch
+ named <branch_tag> up to the HEAD of the main branch. This is
+ still kind of strange. If the file is on a branch, HEAD should
+ be the latest thing on the branch, not the HEAD of MAIN. But
+ that's not the way CVS (currently) works.
+
+ If you run "cvs up -j HEAD" again after adding more revisions
+ to the trunk, you may get overlaps for the text you have
+ already merged. It depends on your version of your RCS "merge"
+ command (actually the "co -j" option, which depends on the
+ version of "diff3" you configured RCS to use).
+
+
+ B. You can merge the difference between any two <tags> using
+ two "-j" options on "update" or "checkout".
+
+ Identify the two tags on the branch you want to merge from.
+
+ cvs update -j <tag1> -j <tag2> {optional files}
+
+ This step assumes you were careful about tagging milestones.
+ You can use this technique for any two <tags> on the same
+ branch, even the trunk. It is also possible to use tags on
+ different branches, but you'll have to ponder the meaning of
+ the difference between those two tags.
+
+ In place of one of the <tags>, you can use a <branch_tag> to
+ refer to the latest revision on that branch. See 4C.11 and
+ 4C.3 for info on branch points.
+
+ Merges can also be performed by handing RCS revisions to the
+ '-j' options, but since revision numbers aren't the same in all
+ files, merging by number is normally limited to one file. Sets
+ of files with the exact same trees of branches and revision
+ numbers would work too, but that's a rare situation.
+
+
+ C. To "take" revisions from other branches instead of merging
+ them, see 4C.19 for an idea.
+
+
+ D. A way to gain the effect of merging the main to the branch is
+ to merge the branch into the main using the normal
+
+ cvs update -A {optional files}
+ cvs update -j <branch_tag> {optional files}
+ cvs commit
+ cvs tag -F -b <same_branch_tag> {optional files}
+
+ See part B of 4D.5
+
+
+ E. Other oddities.
+
+ This also works, but is probably not officially supported:
+
+ cvs update -j N {optional files}
+
+ where N is a number. This will merge all the changes from the
+ branch point up to the highest revision on the main branch
+ starting with N. For example, if your highest trunk revision
+ is 1.52, you can use this to grab revisions from the trunk:
+
+ cvs update -j 1 {optional files}
+
+ Another example: Say you have a branch point at rev 1.2 for a
+ branch named "BR1" and trunk revisions 1.3, 1.4, 2.1, 2.2, 2.3,
+ 3.1, 3.2. Then:
+
+ cvs update -j 1 {optional files}
+
+ will merge the changes from 1.2 to 1.4
+
+ cvs update -j 2 {optional files}
+
+ will merge the changes from 1.2 to 2.3
+
+ cvs update -j 3 {optional files}
+
+ will merge the changes from 1.2 to 3.2, which in this example, is
+ equivalent to the use of "-j HEAD" in part A above.
+
+ The intuitive (at least to me):
+
+ cvs up -j MAIN (or TRUNK) {optional files}
+
+ doesn't work. If the trunk (i.e. "main branch") had an
+ implicit branch named "MAIN", you could use:
+
+ cvs up -j MAIN:10/26 -j MAIN:now {optional files}
+
+ and refer to date-stamped revisions on the trunk using the
+ <branch_tag>:<date> support that works on other branches.
+
+ You might also think you could place an explicit tag on branch
+ 1 (or higher) (e.g. MAINHACK:1) and use it in place of the
+ implicit "MAIN", but I haven't found the right combination.
+
+ [[If you find working techniques, I'll add them here.]]
+
+
+ 4C.8 How do I merge onto the Main Branch a file that exists only on a
+ branch other than the Main Branch? (i.e. it is in the Attic)
+
+ For how such a file can exist, see 3A.2 and 3A.3.
+
+ For how to avoid creating such a file, see 3A.5.
+
+ Though you might think that the "update -j" command could perform
+ the "merge" of a file from the side branch to the Main Branch, it
+ isn't (yet) smart enough. Unfortunately, there is no single CVS
+ command to do this -- it takes three steps:
+
+ 1. To move something onto the Main Branch from the Attic, you have
+ to physically move the file from the Attic to the main
+ Repository directory associated with your working directory.
+
+ It is exactly like resurrecting a removed file. See 3L.4
+
+ I use something like this: (csh-like syntax)
+
+ set repos = `cat ./CVS/Repository`
+ mv $repos/Attic/filename,v $repos/filename,v
+
+ (If you use relative paths in your Repository files, that first
+ line becomes: set repos = $CVSROOT/`cat ./CVS/Repository`)
+
+ 2. Now that the file is physically in the right place within the
+ Repository, "update -A" will make it appear in your working
+ directory on the Main Branch. Do that now.
+
+ 3. You now have a choice. The act of physically moving the file
+ has fused together the <branch_tag> branch and the Main Branch
+ for this file. You can continue that way, making changes along
+ the RCS Main Branch which CVS will (for this type of file only)
+ treat as both the Main Branch and the <branch_tag> branch.
+
+ The other choice, which I would suggest, is to re-tag the file
+ with <branch_tag>, restoring a normal-looking magic branch tag
+ to the file:
+
+ cvs tag -F -b <branch_tag> <file>
+
+
+ After you have done the above, you can run "update -A" or "update
+ -r <branch_tag>" to resume whatever you were doing before you
+ started this procedure.
+
+ Caveat: The final result is a file whose revision tree doesn't
+ look like it was ever on any branch but the Main Branch until the
+ above "tag -F -b" command was executed. CVS and RCS have no way
+ of saving the history of the actions you have just performed.
+
+
+ 4C.9 How do I know what branch I'm (working) on?
+
+ Type:
+ cvs status
+
+ and look at the "Sticky Tag" field for each file. If:
+
+ 1. The *same* tag is on *every* file in your working tree, *and*
+ 2. That tag matches the contents of the ./CVS/Tag file, *and*
+ 3. That tag is a branch tag,
+
+ then you know what branch you are working on. You can get sticky
+ Tag information directly from the ./CVS/Entries file instead of
+ "cvs status".
+
+ If all the sticky Tags don't agree, then your directory is
+ temporarily inconsistent. This is a feature allowing you to make
+ changes (or perform merges) to individual files on multiple
+ branches without checking out the whole directory.
+
+ The sticky Tag on each file in the ./CVS/Entries file (as
+ displayed by the "status" command) indicates what branch the
+ working file is on. New files are added to the Tag stored
+ in ./CVS/Tag.
+
+ To force your entire working directory onto the same branch, type:
+
+ cvs update -r <branch_tag>
+
+
+ 4C.10 Do I really have to know the name of the branch I'm working on?
+
+ If a developer can't be relied on to know what branch of
+ development to work on, then either the developer's manager
+ isn't planning branches properly or the developer has serious
+ problems.
+
+ I have found that one of the hardest concepts to get across to
+ developers (and some managers) is that "a branch in development"
+ (as opposed to the use of RCS branches to support some other
+ scheme) is a heavyweight act. Every time you create a real branch
+ in development, you must spawn a set of managerial procedures and
+ a schedule by which you plan to merge each branch into each other
+ branch. Unless you plan to keep it simple and collapse (by
+ merging and forgetting) branches quickly, they are not to be
+ created lightly.
+
+ In other words, if you don't regularly attend group meetings in
+ which the branch to be worked on is a major topic of discussion,
+ then the group is not managing branches properly.
+
+ We created a couple major branches a few months ago and even the
+ customer service people refer to the "XYZ branch" as a shorthand
+ for "continuing development on the XYZ project".
+
+
+ 4C.11 How do I refer to the revision where I branched so I can see
+ what changed since the Branch Point on another branch?
+
+ Given the current <branch_tag> format, there is no direct way to
+ refer to the branch point, which is more useful in many ways
+ than referring to the branch, which always refers to the latest
+ revision on the branch.
+
+ When CVS adds a branch tag, it attaches an RCS symbol to a
+ non-existent revision number containing the revision number of the
+ branch point as a prefix. (See Section 3O, on the "tag" command.)
+ RCS can't use the CVS magic branch tag and many of the CVS
+ commands can't refer to it.
+
+ To be certain of your ability to refer to a branch point, you must
+ create a "branch point" tag at the same time as the Branch tag.
+ See 4C.3.
+
+
+ 4C.12 Why didn't the command "cvs admin -bBRANCH1 *" create a branch?
+
+ Because your command creates an RCS branch, not a CVS branch. See
+ the above discussion on branches. RCS branches are used to
+ support CVS branches, but they are not the same. You can't act as
+ if you have direct control over the RCS files.
+
+ The "admin" command was placed there as a convenience to allow
+ you to execute raw "rcs" commands on the Repository, taking
+ advantage of CVS's ability to find the files in the Repository.
+
+ But you have to remember that you are using RCS commands on a
+ CVS Repository, which is not generally safe unless you know
+ exactly what CVS depends on.
+
+ For one thing, CVS insists on control of the default branch. It
+ is set either to the Main branch or the Vendor branch depending
+ on whether you have changed the Vendor's code. If you change
+ the default branch, you are monkeying with the internals and
+ you will get unexpected results.
+
+ To set your "default CVS branch" to BRANCH1, you must use
+ "checkout" or "update" with the "-r BRANCH1" option. Then you
+ have changed CVS's idea of your "default branch", which has
+ little to do with RCS's default branch.
+
+
+ 4C.13 Is it possible to set the "default CVS branch" for everyone?
+
+ No. It doesn't work that way.
+
+ When using CVS, all administrative information (such as what
+ branch you checked out) is stored in CVS sub-directories, local to
+ the user. There is no global state, other than the description
+ and logging files in the $CVSROOT/CVSROOT directory.
+
+ You tell "checkout" or "update" what branch you want to check out
+ via the "-r <tag>" option. The default is CVS's "Main Branch".
+
+ I don't see a problem in *designing* a new way to indicate what
+ branch you get by default, instead of the main one, but that's not
+ how it currently works.
+
+
+ 4C.14 How do I perform a large merge?
+
+ Large merges require a bit more planning to be able to track
+ what has happened in the inevitable cases where something goes
+ wrong. No tool can force a "merge" to make perfect sense.
+
+ Though you can handle the details in many different ways, the two
+ ends of the spectrum of merge techniques are: gonzo and paranoid.
+
+ A. The gonzo method assumes that you know everything about your
+ sources so that recovery from failures is "just a matter of
+ typing." You created the branch this way:
+
+ cvs checkout <module>
+ cd <module>
+ cvs tag -b <branch_tag>
+ cvs update -r <branch_tag>
+ >>> Edit away.
+ cvs commit <<== Onto branch
+
+ Now you want to merge your branch back into the Main branch,
+ you are certain you can make it work, or at least detect all
+ the failures, so you dive in and hack away: (For simplicity, we
+ will assume you are collapsing (i.e. merging and forgetting) a
+ side-branch into the Main branch from your single working
+ directory.)
+
+ cvs update -A
+ cvs update -j <branch_tag>
+ >>> Edit the 'C' files and remove the overlaps.
+ >>> Edit some more to make it all compile and work.
+ cvs commit
+
+ Looks simple. For more details on the output from the
+ "update -j" command, see 3P.2 and 4C.6.
+
+ Note: You could also checkout a whole new working directory and
+ perform the merge at the same time by replacing the two
+ update commands with these two commands:
+
+ cvs checkout -j <branch_tag> <module>
+ cd <module>
+
+
+ B. The paranoid way is more difficult, but it can catch all sorts
+ of problems. You created the branch this way:
+
+ cvs checkout <module>
+ cd <module>
+ cvs tag <branch_point_tag>
+ cvs tag -b <branch_tag>
+ cvs update -r <branch_tag>
+ >>> Edit away.
+ cvs commit <<== Onto branch
+
+ The extra tag command places a non-branch tag on the Branch
+ Point, an act that makes it easier to do "diffs" later. Now we
+ decide to perform the merge:
+
+ cvs tag <latest_on_branch_tag>
+ cvs update -A
+ *1* cvs diff -r <branch_point_tag> -r <latest_on_branch_tag>
+ >>> *1* shows all the changes on the branch.
+ *2* cvs diff -r <branch_point_tag> -r HEAD
+ >>> *2* shows the changes on the trunk since branching.
+ cvs tag <premerge_tag>
+ cvs update -j <branch_tag>
+ >>> Edit the 'C' files and remove the overlaps.
+ *3* cvs diff
+ >>> Verify that *3* matches *1*, except for line numbers.
+ cvs commit
+ cvs tag <just_merge_changes_tag>
+ >>> Edit some more to make it all compile and work.
+ cvs commit
+ cvs tag <after_merge_cleanup_tag>
+
+
+ The reason *3* and *1* match so closely is that they are the
+ differences between two pairs of starting points and ending points
+ after the same data was inserted. If they are significantly
+ different, you will want to figure out why.
+
+ NOTE: You will have to tell everyone to stay the hell out of the
+ Repository while you do this. If they commit something while you
+ are in the middle of a merge, your job will be much more
+ difficult. If they "update" at the wrong time, their work will
+ be randomized until you finish. It's better to call a halt.
+
+ See 3H.13 for some more information about dealing with merges
+ after import. The last part of the procedure is applicable to any
+ large merge.
+
+
+ 4C.15 Is a Vendor merge any different from a branch merge?
+
+ No. In most ways, a Vendor branch is exactly the same as any
+ other branch. In a Vendor merge, the data is append to the branch
+ by the "import" command, rather than by hand-editing, but the
+ merge process is the same.
+
+ See the "import" command in section 3H.
+
+
+ 4C.16 How do I go back to a previous version of the code on a branch?
+
+ You can avoid digging into RCS revision numbers (executing "update
+ -r <rev>" on each file) by trying one of these:
+
+ 1. Use non-branch tags as you normally would. Non-branch tags
+ attach to specific revisions, so a "tag <tag>" command would
+ mark the revisions you have in your working directory, which
+ are on your branch. If you need to retrieve them, use "update
+ -r <non-branch-tag>"
+
+ Doing this overrides the sticky <branch_tag> attached to your
+ working directory with a non-branch tag, which means you won't
+ be able to commit until you again move forward to the end of
+ the branch with "update -r <branch_tag>".
+
+ 2. Use the "update -r <branch_tag>:<date>" trick.
+
+ This is almost like using the '-D' option, but it looks for
+ revisions extant on <date> only along the given branch.
+
+ As in #1, you can't commit to this kind of working area,
+ because it has a sticky date referring to revisions in the
+ middle of a branch.
+
+
+ 3. You can branch a branch.
+
+ If you add a branch tag to file in a working directory that was
+ checked out on a branch, you will branch the branch. This
+ works just fine, though you'll have to play some games to merge
+ everything back together again. You'll also create 6-part
+ revision numbers. (They'll be 8-part revision numbers if you
+ branch a branch that started out with some unmodified files on
+ the Vendor branch. Think about it. How does revision
+ 1.2.4.2.4.2.2.1 grab you?)
+
+
+ 4C.17 Once I've found the files I want, how do I start changing them?
+ I keep getting warnings about sticky tags.
+
+ What you probably did was type "cvs update -r <tag>" where <tag>
+ is a non-branch tag. "update" created a sticky tag for a specific
+ revision, not a branch. To start working right there, you have to
+ create a branch to work on.
+
+ You have two choices.
+
+ A. You can do it in place and keep working:
+
+ cvs tag -b <branch_tag> <<== To tag the current files.
+ cvs update -r <branch_tab> <<== To move onto the branch.
+
+ B. You can do it "externally" and create a new working directory:
+
+ cvs rtag -b -r <tag> <branch_tag> <module>
+ cvs checkout -r <branch_tag> <module>
+
+ <module> can be a relative path within the Repository.
+
+ <tag> in the above is the non-branch tag you placed earlier
+ that caused the error in your question. Be warned that
+ if <tag> is not set on all the files (or all the right
+ revisions) you won't get exactly what you wanted.
+
+
+ 4C.18 Why do I get the latest files on the branch when I tried to
+ "update -r <tag>"?
+
+ If "update -r <tag>" always retrieves the latest files on a
+ branch, then <tag> is really a <branch_tag>. A branch tag is
+ supposed to be used to grab a branch to work on. Since you can't
+ modify a file in the middle of a branch, checking out a
+ <branch_tag> will give you the latest revision on the branch.
+
+ If you want to "checkout" a specific collection of revisions, you
+ must use a "non-branch" tag. See the first part of 4C.16.
+
+
+ 4C.19 How can I avoid a merge? I just want to move the latest revision
+ on my working branch directly onto the trunk.
+
+ There is no direct way to do this using CVS, though the technique
+ is not difficult using shell commands. Here's one way:
+
+ 1. Move your working directory to the Main Branch.
+
+ cvs update -A
+
+ 2. Use "update -p" to grab the latest revision on the branch and
+ write it over your working files. Make sure you don't have an
+ modified files -- you will lose them. The following is in
+ "csh" syntax. Change the wildcard to grab the files you want
+
+ foreach i (Makefile *.cc *.hh)
+ cvs update -p -r <branch_tag> $i > $i
+ end
+
+ 3. Commit all the working files onto the Main Branch.
+
+ cvs commit -m 'Moved branch <branch_tag> onto MAIN'
+
+ You should experiment with the above before blasting everything.
+
+
+ 4C.20 How to I avoid merge collisions in the RCS $\Log$ data?
+
+ In short, you can't. The RCS $\Log$ keyword is handled
+ differently from all other RCS keywords.
+
+ On the info-cvs mailing list, there is a periodic discussion that
+ goes something like this:
+
+ Question: How do I deal with $\Log$?
+ Answer1: You can't do much with it. Here's how it works. . .
+ Answer2: I've found a limited way to use it. . .
+ Answer3: Get rid of it. $\Log$ is an abomination.
+
+ I tend to lean toward answer #3. There are only two sets of
+ people who would ever have access to logs stored within sources
+ files, developers and source customers.
+
+ For developers:
+
+ 1. Log entries within sources files are notoriously incomplete,
+ rushed, poorly phrased and in many cases incorrect, making them
+ useless for debugging or file maintenance. I remember a maxim
+ from "Software Tools" (I believe): "Read the code, not the
+ comments." No managerial order or plan for programmer
+ discipline will affect this in the real world.
+
+ 2. Log entries are usually in an unreadable mixture of styles.
+ Many log entries are just plain meaningless. Some are foolish.
+ Some are even insulting. Examples:
+
+ "Corrected spelling of misspelling."
+ "Bug fix."
+ "Reversed stupid change in previous revisions."
+ "If Joe could do his job, this would already have worked."
+
+ 3. Log entries are not managed well by the tools. Any merge can
+ cause conflicts in the $\Log$ data. Branch merges produce
+ incomplete logs. They can be edited into chaos and they are
+ not regenerated. They waste space duplicating information
+ available to the developer with a single command.
+
+ 4. Even if correct when originally entered, as changes are made to
+ the file, log entries become false over time. Humans are not
+ good at reading down through a list and remembering only the
+ last change affecting something. Over time *most* of the log
+ is wrong.
+
+ 5. Even if still correct, the log data is almost useless to
+ developers without the code diffs. If you can get code diffs,
+ you can display the log.
+
+
+ For source customers the problem is even worse. The last thing
+ you want to show customers is a hodge-podge of tiny comments about
+ large changes followed by a series of emergency fixes before
+ delivery. If you distribute sources, then you should provide
+ documentation, or changelogs reviewed by people who won't let
+ comments like "Fixed for stupid customer." out the door.
+
+ Conclusion: Though some people would prefer to see in this FAQ
+ techniques for making the $\Log$ entries the best they can be, I
+ believe them to be a lost cause. My suggestion is to hunt down,
+ root out and destroy all occurrences of $\Log$ and the unusable
+ data attached to it wherever you may find it.
+
+
+ 4C.21 Why should I trust automatic merges?
+
+ Some developers have the feeling that three-way merging doesn't
+ work. They fear and distrust the way the "update" command
+ automatically merges committed changes from the Repository into
+ the working file.
+
+ Experience has shown that most merges are utterly painless and
+ most of the rest are easily resolved. The few conflicts that
+ cause headaches are nearly all due to poor communication between
+ developers, a problem no source control system can obviate.
+
+ Some developers were troubled in the past by flaky Unix software.
+ I can't say that everything is perfect, but the tools CVS depends
+ on (RCS and diff, mainly) are fairly solid nowadays. They work.
+
+ Since it does seem to work for most of us, the algorithm is
+ unlikely to change soon. Why not test it on a couple trouble
+ spots and if it works for you, use it for a while? Then you can
+ make an informed decision.
+
+
+ 4C.22 How does CVS decide if it can safely perform a merge?
+
+ CVS can merge any text file, possibly discovering a conflict and
+ leaving overlaps for you to edit. Editing the conflict markers
+ out of the file is a moment's work, but resolving the conflict
+ could take an arbitrary amount of time. CVS works to determine if
+ it *should* merge, not if it *can*.
+
+ See 2B.6 for how the merge proceeds.
+
+
+ 4C.23 After resolving merge conflicts in a file, what if I want to keep
+ my previous version, and not take any of the branch changes?
+
+ If you want to retain your previous version, a version on the
+ MAIN branch greater than 1.1 (one you committed there), just throw
+ the merged file away and "cvs update" the file.
+
+ You don't need to commit something to remember it. The tags you
+ place before and after the merge should give all the handles you
+ need to find various versions. You don't have to create a new
+ version of the file.
+
+ If you want to retain the previous Vendor revision, you can grab a
+ copy of it using "cvs update -p" and commit it or use the
+ technique described in 3B.3 to revert back to the Vendor branch.
+
+
+
+----------------
+-- Section 4D -- Tricks of the Trade
+----------------
+
+This section covers topics ranging from simple ideas that occur to every
+CVS user to time-saving procedures I consider difficult to understand.
+
+Some are therefore dangerous. Avoid anything you don't fully understand.
+
+
+ **** Questions:
+
+ 4D.1 How can you even check in binary files, let alone allow CVS to
+ do its auto-merge trick on them?
+ 4D.2 Can I edit the RCS (",v") files in the Repository?
+ 4D.3 Can I edit the ./CVS/{Entries,Repository,Tag} files?
+ 4D.4 Someone executed "admin -o" and removed revisions to which
+ tags/symbols were attached. How do I fix them?
+ 4D.5 How do I move or rename a magic branch tag?
+ 4D.6 Can I use RCS locally to record my changes without making them
+ globally visible by committing them?
+ 4D.7 How can I allow access to the Repository by both CVS and RCS?
+ 4D.8 I "updated" a file my friend, "bubba", committed yesterday.
+ Why doesn't the file now have a modified date of yesterday?
+ 4D.9 While in the middle of a large "commit", how do I run other
+ commands, like "diff" or "stat" without seeing lock errors?
+ 4D.10 Where did the ./CVS/Entries.Static file come from? What is it for?
+ 4D.11 Why did I get the wrong Repository in the loginfo message?
+ 4D.12 How do I run CVS setuid so I can only allow access through the
+ CVS program itself?
+ 4D.13 How about using groups and setgid() then?
+ 4D.14 How do I use the "commitinfo" file?
+ 4D.15 How do I use the "loginfo" files?
+ 4D.16 How can I keep people with restrictive umask values from blocking
+ access to the Repository?
+ 4D.17 Why do timestamps sometimes get set to the date of the revision,
+ sometimes not? The inconsistency causes unnecessary recompiles.
+
+
+ **** Answers:
+
+ 4D.1 How can you even check in binary files, let alone allow CVS to
+ do its auto-merge trick on them?
+
+ If you configure RCS and CVS to use the GNU version of diff with
+ the '-a' option, CVS and RCS will handle binary files. See
+ section 4A for configuration info.
+
+ You may also need to apply the '-ko' flag to the files to avoid
+ expanding RCS keywords, which can be done via:
+
+ cvs admin -ko filename
+
+
+ The only real problem occurs when "cvs update" attempts to merge
+ binary revisions committed elsewhere into a modified working file.
+ This can be a particular problem if you are trying to use CVS on
+ Frame or Interleaf (document processing systems) that produce
+ non-text output.
+
+ See 3C.8 for a way to serialize access to binary files.
+ See 3A.8 for adding binary files, 3H.4 for importing binary files
+ and 3B.4 for some more information about "admin".
+
+
+ 4D.2 Can I edit the RCS (",v") files in the Repository?
+
+ Yes, but be very careful. The RCS files are not free-form files,
+ they have a structure that is easily broken by hand-editing. The
+ only time I would suggest doing this is to recover from emergency
+ failures that are difficult to deal with using CVS commands,
+ including the "admin" command, which can talk directly to RCS.
+
+ Though no one actively encourages the editing of RCS files, many
+ people have succumbed to the urge to do so when pressed for time.
+ The reasons given, usually with evident contrition, include:
+
+ - Editing mistakes in, or adding text to, log entries. (If you
+ have RCS 5.6 or later, you should use `cvs admin -m'.)
+ - Renaming or moving symbolic names. (You should `cvs admin -N'
+ instead.)
+ - Unlocking a file by changing the "locker" from someone else to
+ yourself. (It's safer to use `cvs admin -u -l'.)
+ - Making global changes to past history. Example: Eradicating
+ former employees names from old documents and Author entries.
+ (And someone thought the "history" command was evidence of Big
+ Brother! I never realized how much help a wide-open revision
+ control system could have provided to The Ministry of Truth.)
+
+
+ 4D.3 Can I edit the ./CVS/{Entries,Repository,Tag} files?
+
+ Yes, but with CVS 1.3 and later, there is almost no reason to edit
+ any of the CVS administrative files.
+
+ If you move pieces of your Repository around it can be faster to
+ edit all the ./CVS/Repository files rather than checking out a
+ large tree. But that is nearly the only reason to do so.
+
+
+ 4D.4 Someone executed "admin -o" and removed revisions to which
+ tags/symbols were attached. How do I fix them?
+
+ It depends on what you mean by "fix". I can think of three ways
+ to fix your predicament:
+
+
+ 1. Remove the tags.
+
+ Assuming you really wanted to get rid of the revision and its
+ associated tags, you can remove them with the "admin" command.
+ The "tag -d" command will only remove tags attached to existing
+ revisions. You can remove a tag, even if it is attached to a
+ non-existent revision, by typing:
+
+ cvs admin -N<tag> <file>
+
+ 2. Retrieve the outdated revision.
+
+ You should first look in your backup system for recent versions
+ of the file. If you can't use them, you can carefully extract
+ each revision that followed the earliest outdated revision
+ using RCS (or "cvs admin") commands and reconstruct the file
+ with all the right revisions, branches and tags. This is a lot
+ of work.
+
+ You *can't* insert a revision into the current RCS file.
+
+ 3. Move the Tags to another revision in each file.
+
+ If you want to move the tags to another valid revision, you
+ have two choices, both of which require that you find all the
+ revision numbers of the files you want to "tag" and execute the
+ following command sequences on each <file>.
+
+ a. Use "update" to grab the revision you want, then
+ execute a normal "tag" command to Tag that revision:
+
+ cvs update -r <rev> <file>
+ cvs tag <tag> <file>
+
+ b. Use "admin" to set the tag to a specific revision:
+
+ cvs admin -N<tag>:<rev> <file>
+
+
+ 4D.5 How do I move or rename a magic branch tag?
+
+ (To rename a non-branch <tag> see 3O.9.)
+
+ Before reading this, read 3M.3 and 3M.4 and understand exactly
+ how tag and rtag use '-r' and why it won't do the right job here.
+
+ A. First, I have to explain exactly what a magic branch tag is.
+
+ A magic <branch_tag> is an artificial tag attached to a
+ non-existent revision on a non-existent branch number zero. It
+ looks like this:
+
+ TAG1:<X>.0.Y
+
+ <X> is the "branch point revision", a normal revision with an
+ odd number of '.'s in it. (e.g. 1.5, 1.3.1.6, etc)
+
+ Y is an even number (e.g. 2, 4, 6, etc.) All CVS branches,
+ other than the Vendor branch, are even numbered.
+
+ TAG1 is considered by CVS to be attached to revision <X>. The
+ first "update -r TAG1 <file>" after applying TAG1 will produce
+ a copy of revision <X> with a sticky tag of TAG1. The first
+ "commit" to that file will cause CVS to construct an RCS branch
+ named <X>.Y and check in revision <X>.Y.1 on the new branch.
+
+ Note: TAG1 is *not* considered to be attached to <X> by RCS,
+ which explains why you can't refer directly to the branch point
+ revision for some CVS commands.
+
+
+ B. Moving a magic <branch_tag> is the act of reapplying the same
+ tag to different revisions in the file:
+
+ TAG1:<X>.0.Y
+ to
+ TAG1:<X>.0.Z or TAG1:<A>.0.B
+
+ You can move a magic branch tag to the revisions of your choice
+ by using "update" to find the revisions you want to tag and
+ reapplying the tag to all the files with the '-F' option to
+ force it to move the existing <branch_tag>.
+
+ cvs update -r <tag/rev> (or '-A' for the Main Branch)
+ cvs tag -F -b <branch_tag>
+
+ If the earlier location of TAG1 refers to a physical branch
+ within any RCS file, moving it will make the existing branch in
+ the file seem to disappear from CVS's view. This is not a good
+ idea unless you really want to forget the existence of those
+ RCS branches.
+
+ If the "update" above retrieves the original branch point
+ revision (<X>), the "tag" command above will create the tag:
+
+ TAG1:<X>.0.Z
+
+ Where Z is 2 greater than the highest magic branch already on
+ revision <X>. The TAG1 branch will still have the same branch
+ point (i.e. revision <X>), but the first commit to the new TAG1
+ branch will create a different RCS branch number (<X>.Z instead
+ of <X>.Y).
+
+
+ C. Renaming a magic <branch_tag> is the act of changing
+
+ TAG1:<X>.0.Y
+ to
+ TAG2:<X>.0.Y
+
+ There is no harm in changing a tag name as long as you forget
+ that TAG1 ever existed and you clean up any working directories
+ with sticky TAG1 tags on them by using "update -A", "update -r
+ <other_tag>" or by removing the working directories.
+
+ On the other hand, actually changing the tag is not easy.
+
+ See 3M.3 for why the seemingly obvious solution won't work:
+
+ cvs tag -b -r <old_branch_tag> <new_branch_tag>
+
+ The only direct way to rename a magic tag is to use the "admin"
+ command on each file: (You might want to use '-n'. Read "man
+ rcs" and look at the '-n' and '-N' options.)
+
+ cvs admin -N<new_branch_tag>:<old_branch_tag> .
+ cvs tag -d <old_branch_tag>
+
+ But you have to be careful because "admin" is different from
+ other CVS commands:
+
+ 1. "admin" can be used recursively, but only by specifying
+ directory names in its argument list (e.g. '.'),
+
+ 2. Where "rtag -r <old_branch_tag>" would interpret
+ <old_branch_tag> as a magic CVS branch tag, "admin" is a
+ direct interface to RCS which sees a magic branch tag as
+ a simple (though non-existent) RCS revision number.
+
+ This is good for us in this particular case, but different
+ from normal CVS.
+
+ 3. "admin" also skips the Attic and produces different kinds
+ of errors than CVS usually does. (Because they are coming
+ directly from RCS.)
+
+
+ The other way to rename a magic <branch_tag> is to edit the
+ Repository files with a script of some kind. I've done it in
+ the past, but I'll leave it as an exercise for the reader.
+
+
+ 4D.6 Can I use RCS locally to record my changes without making them
+ globally visible by committing them?
+
+ You can, but it will probably confuse CVS to have ",v" files in
+ your working directory. And you will lose all your log entries
+ when you finally commit it.
+
+ Your best bet is to create your own CVS branch and work there.
+ You can commit as many revisions as you want, then merge it back
+ into the main line (or parent branch) when you are finished.
+
+
+ 4D.7 How can I allow access to the Repository by both CVS and RCS?
+
+ The first step is to try not to. If some people are using CVS,
+ there is no reason for everyone not to. It is not hard to learn
+ the basics and CVS makes certain operations *easier* than a series
+ of RCS commands. Personal preference in what software tools can
+ be applied to a shared Repository has to take second place to
+ system integration needs. If you disagree, try writing some Lisp
+ code for inclusion in your Unix kernel and see what kind of
+ reception you get.
+
+ If you really must allow routine RCS access to the CVS Repository,
+ you can link an RCS sub-directory into a piece of the Repository:
+
+ ln -s /Repository/some/directory/I/want RCS
+
+ and RCS will work just fine.
+
+
+ Those who are using RCS will have to keep the following in mind:
+
+ 1. If a file was originally added to the Repository by "import"
+ and has not been changed using CVS, the *RCS* default branch
+ will remain attached to the Vendor branch, causing revisions
+ checked-in by "ci" to wind up on the Vendor branch, instead of
+ the main branch. Only CVS moves the RCS default branch on
+ first commit.
+
+ The way around this is to checkin (using "ci") all the files
+ first and move them into the Repository. That way they won't
+ have Vendor branches. Then RCS will work OK.
+
+ 2. It is possible to use "rcs" and "ci" to make the files unusable
+ by CVS. The same is true of the CVS "admin" command.
+
+ 3. Normal RCS practice locks a file on checkout with "co -l". In
+ such an environment, RCS users should plan to keep survival
+ gear and food for at least 30 days near their desks. When
+ faced with bizarre and unexpected permission errors, howling
+ mobs of slavering CVS users will run the RCS users out of town
+ with pitchforks and machetes.
+
+ See 3C.8 for a way to avoid machetes aroused by lock collisions.
+
+ 4. Though files checked in by RCS users will correctly cause
+ "up-to-date" failures during CVS "commits" and they will be
+ auto-merged into CVS working directories during "update", the
+ opposite won't happen.
+
+ RCS users will get no warning and will not be required to merge
+ older work into their code. They can easily checkin an old
+ file on top of a new revision added by CVS, discarding work
+ committed earlier by CVS users.
+
+ See the howling mob scenario described above.
+
+
+ RCS is great. I have used it for years. But I wouldn't mix it
+ this way. In a two-camp society, you are asking for real trouble,
+ both in technical hassles to clean up and in political hassles to
+ soothe. Branch merges will also be a major problem.
+
+
+ 4D.8 I "updated" a file my friend, "bubba", committed yesterday.
+ Why doesn't the file now have a modified date of yesterday?
+
+ CVS restores dates from the RCS files only on first "checkout".
+ After that, it is more important to maintain a timestamp relative
+ to the other files in the working directory.
+
+ Example: You committed a source file at 5PM. Bubba updated his
+ copy of the file, grabbing your changes, then changed and
+ committed a new revision of the file at 6PM. At 7PM, you compile
+ your file. Then you execute "update". If CVS sets the date to
+ the one in the RCS file, the file would be given a timestamp of
+ 6PM and your Makefile wouldn't rebuild anything that depended on
+ it. Bad news.
+
+ Note that the same logic applies to retrieving a revision out of
+ the Repository to replace a deleted file. If CVS changes your
+ file in an existing working directory, whether it was because a
+ new revision was committed by someone else or because you deleted
+ your working file, the timestamp on the retrieved working file
+ *must* be set to the current time.
+
+ When you first retrieve a file, there is no reason to expect any
+ particular timestamp on the file within your working area. But
+ later, when dependency checking is performed during a build, it is
+ more important for the timestamps on the local files to be
+ consistent with each other than than it is for working files to
+ match the timestamps on the files in the Repository.
+ See 4D.17 for some more about timestamps.
+
+
+ 4D.9 While in the middle of a large "commit", how do I run other
+ commands, like "diff" or "stat" without seeing lock errors?
+
+ Type:
+ cvs -n <command>
+
+
+ The '-n' option to the main cvs command turns off lock checking, a
+ reasonable act for read-only commands given the promise offered by
+ '-n' not to alter anything. The "diff", "log" and "stat" commands
+ provide the same information (for files that are not being
+ committed) when used with and without the '-n' option.
+
+ Warning: Ignoring locks can produce inconsistent information
+ across a collection of files if you are looking at the revisions
+ affected by an active commit. Be careful when creating "patches"
+ from the output of "cvs -n diff". If you are looking only at your
+ working files, tagged revisions, and BASE revisions (revisions
+ whose numbers are read from your ./CVS/Entries files), you should
+ get consistent results. Of course, if you catch a single file in
+ the middle of RCS activity, you might get some strange errors.
+
+ Note that the suggested command is "cvs -n <command>". The
+ visually similar command "cvs <command> -n" has no relation to the
+ suggested usage and has an entirely different meaning for each
+ command.
+
+ "cvs -n update" also works in the middle of a commit, providing
+ slightly different information from a plain "cvs update". But, of
+ course, it also avoids modifying anything.
+
+ You could also use the RCS functions, "rlog" and "rcsdiff" to
+ display some of the information by referring directly to the
+ Repository files.
+
+ You need RCS version 5 or later for the commands described above
+ to work reliably.
+
+
+ 4D.10 Where did the ./CVS/Entries.Static file come from? What is it for?
+
+ Each CVS working directory contains a ./CVS/Entries file listing
+ the files managed by CVS in that working directory. Normally, if
+ the "update" command finds a file in the Repository that is not in
+ the ./CVS/Entries file, "update" copies the appropriate revision
+ of the "new" file out of the Repository and adds the filename to
+ the Entries file. This happens for files:
+
+ 1. Added to the Repository from another working directory.
+ 2. Dragged out of the Attic when switching branches with
+ "update -A" or "update -r".
+ 3. Whose names were deleted from the ./CVS/Entries file.
+
+ If the ./CVS/Entries.Static file exists, CVS will only bring out
+ revisions of files that are contained in either ./CVS/Entries or
+ ./CVS/Entries.Static. If a Repository file is found in *neither*
+ file, it is ignored.
+
+ The ./CVS/Entries.Static file is created when you check out an
+ individual file or a module that creates working directories that
+ don't contain all files in the corresponding Repository directory.
+ In those cases, without an ./CVS/Entries.Static file, a simple
+ "update" would bring more files out of the Repository than the
+ original "checkout" wanted.
+
+ The ./CVS/Entries.Static file can be removed by hand. It is
+ automatically removed if you run "update -d" to create new
+ directories (even if no new directories are created).
+ (Internally, since "checkout" turns on the '-d' flag and calls the
+ "update" routine, a "checkout" of a module or directory that
+ writes into an existing directory will also remove the
+ ./CVS/Entries.Static file.)
+
+
+ 4D.11 Why did I get the wrong Repository in the loginfo message?
+
+ You probably:
+
+ 1. Use multiple Repositories.
+
+ 2. Configured CVS to use absolute pathnames in the
+ ./CVS/Repository file.
+
+ 3. Configured CVS not to use the ./CVS/Root file.
+
+ 4. Typed the "commit" command in one Repository with your
+ $CVSROOT pointing at another.
+
+ "commit" and all other CVS commands will heed an absolute pathname
+ in the ./CVS/Repository file (or in the "-d CVSrootdir" override),
+ but the log function doesn't take arguments -- it just looks at
+ $CVSROOT.
+
+ If you avoid even one of the four steps above, you won't see this
+ problem. If you configure ./CVS/Root, you won't be allowed to
+ execute the program causing the error.
+
+
+ 4D.12 How do I run CVS setuid so I can only allow access through the
+ CVS program itself?
+
+ Setuid to root is not a great idea. Any program that modifies
+ files and is used by a widely distributed group of users is not a
+ good candidate for a setuid program. (The worst suggestion I've
+ ever heard was to make *Emacs* setuid to root.)
+
+ Root access on Unix is too powerful. Also, it might not work in
+ some (secure?) environments.
+
+ Running it setuid to some user other than root might work, if you
+ add this line to main.c near the beginning:
+
+ setuid(geteuid());
+
+ Otherwise it uses *your* access rights, rather than the effective
+ uid's.
+
+ Also, you have to invent a fake user whose name will show up in
+ various places. But many sites, especially those who might want a
+ setuid CVS for "security", want personal accountability -- no
+ generic accounts. I don't know whether accountability outweighs
+ file security.
+
+ And finally, unless you take action to limit the "admin"
+ command, you are leaving yourself unprotected anyway.
+
+
+ 4D.13 How about using groups and setgid() then?
+
+ Here is a way to run CVS setgid in some environments:
+
+ 0. Stick this near the front of the main() in main.c:
+
+ setgid(getegid());
+
+ This will allow "access" to work on systems where it
+ only works on the real gid.
+
+ 1. Create a group named "cvsg". (This example uses "cvsg". You
+ can name it as you wish.)
+
+ 2. Put *no* users in the "cvsg" group. You can put Repository
+ administrators in this group if you want to.
+
+ 3. Set the cvs executable to setgid (not setuid):
+
+ cd /usr/local/bin; chown root.cvsg cvs; chmod 2755 cvs
+
+ 4. Make sure every file in the Repository is in group "cvsg":
+
+ chown -R root.cvsg $CVSROOT
+
+ 5. Change all directory permissions to 770. This allows all
+ access to the files by the "cvsg" group (which has no members!)
+ and no access at all to anyone else.
+
+ find $CVSROOT -type d -exec chmod 2770 {} \;
+
+ On some systems you might have to type:
+
+ find $CVSROOT -type d -exec chmod u=rwx,g=rwx,o=,g+s {} \;
+
+ This should allow only the cvs program (or other "setgid to group
+ cvsg") programs to write into the area, but no one else. Yes the
+ user winds up owning the file, but s/he can't find it again later
+ since s/he can't traverse the tree. (If you enable the world
+ execute bit (mode 2771) on directories, users can traverse the
+ tree and the user who last wrote the file can still write to it.)
+
+ If you want to allow read access, check out an entire tree
+ somewhere. You have to do this anyway to build it.
+
+ Note: If you are using a stupid file system that can't inherit
+ file groups from the parent directory (even with the "setgid"
+ (Octal 2000) bit set), you might have to modify CVS (or RCS) to
+ reset the group every time you create a new file. I have not
+ tested this.
+
+ The setgid() method shares with the setuid() method the problem of
+ keeping "admin" from breaking things.
+
+
+ 4D.14 How do I use the "commitinfo" file?
+
+ Go read 4B.2 first.
+
+ The "commitinfo" file allows you to execute "sanity check"
+ functions before allowing a commit. If any function called from
+ within the commitinfo file exits with a non-zero status, the
+ commit is denied.
+
+ To fill out a "commitinfo" file, ask yourself (and those sharing
+ your Repository) these questions:
+
+ - Is there anything you want to check or change before someone is
+ allowed to commit a file? If not, forget commitinfo.
+
+ If you want to serialize binary files, you might consider
+ something like the rcslock.pl program in the contrib directory
+ of the CVS sources.
+
+ - Do you want to execute the same exact thing before committing to
+ every file in the Repository? (This is useful if you want to
+ program the restrictions yourself.) If so, set up a single line
+ in the commitinfo:
+
+ DEFAULT /absolute/path/to/program
+
+ CVS executes the program once for each directory that "commit"
+ traverses, passing as arguments the directory and the files to
+ be committed within that directory.
+
+ Write your program accordingly. Some examples exist in the
+ contrib directory.
+
+ - Do you want a different kind of sanity check performed for
+ different directories? If so, you'll have to decide what to do
+ for all directories and enter lines like this:
+
+ regexp1 /absolute/path/to/program-for-regexp1
+ regexp2 /absolute/path/to/program-for-regexp2
+ DEFAULT /absolute/path/to/program-for-all-else
+
+
+ - Is there anything you want to happen before *all* commits, in
+ addition to other pattern matches? If so, include a line like
+ this:
+
+ ALL /absolute/path/to/program
+
+ It is executed independently of all the above. And it's
+ repeatable -- you can have as many ALL lines as you like.
+
+
+ 4D.15 How do I use the "loginfo" files?
+
+ See 4B.2 and the "commitinfo" question above.
+
+ The "loginfo" file has the same format as the "commitinfo"
+ file, but its function is different. Where the "commitinfo"
+ information is used before a commit, the "loginfo" file is used
+ after a commit.
+
+ All the commands in the "loginfo" file should read data from
+ standard input, then either append it to a file or send a message
+ to a mailing list. If you want to make it simple, you can put
+ shell (the shell used by "popen(3)") command lines directly in the
+ "loginfo" (or "commitinfo") file. These seem to work:
+
+ ^special /usr/ucb/Mail -s %s special-mailing-list
+ ^other /usr/ucb/Mail -s %s other-mailing-list
+ DEFAULT (echo '===='; echo %s; cat) > /path/name/to/log/file
+
+
+ 4D.16 How can I keep people with restrictive umask values from blocking
+ access to the Repository?
+
+ If a user creates a new file with restricted permissions
+ (e.g. 0600), and commits it, the Repository will have a file in it
+ that is unreadable by everyone. The 0600 example would be
+ unreadable by *anyone* but root and the user who created it.
+
+ There are 3 solutions to this:
+
+ 0. Let it happen. This is a valid way to protect things. If
+ everyone is working alone, a umask of 077 is OK. If everyone
+ is working only in small groups, a umask of 007 is OK.
+
+ 1. Train your users not to create such things if you expect to
+ share them.
+
+ 2. See 4B.5 for a small script that will reset the umask.
+
+ I personally don't like the idea of a program automatically
+ *loosening* security. It would be better for you all to talk
+ about the issue and decide how to work together.
+
+
+ 4D.17 Why do timestamps sometimes get set to the date of the revision,
+ sometimes not? The inconsistency causes unnecessary recompiles.
+
+ The "checkout" command normally sets the timestamp of a working
+ file to match the timestamp stored on the revision in the
+ Repository's RCS file.
+
+ The "commit" command retains the timestamp of the file, if the
+ act of checking it in didn't change it (by expanding keywords).
+
+ The "update" command sets the time to the revision time the first
+ time it sees the file. After that, it sets the time of the file
+ to the current time. See 4D.8 for a reason why.
+
+ Here's a two-line PERL program to set timestamps on files based on
+ other timestamps. I've found this program useful. When you are
+ certain you don't want a source file to be recompiled, you can set
+ its timestamp to the stamp on the object file.
+
+ #!/usr/local/bin/perl
+ #
+ # Set timestamp of args 2nd-Last to that of the first arg.
+ #
+ ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,$atime,$mtime,$ctime)
+ = stat(shift);
+ utime($atime,$mtime,@ARGV);
+
+
+
+----------------
+-- Section 4E -- Internal errors
+----------------
+
+ **** Questions:
+
+ 4E.1 Explain: "ci error: unexpected EOF in diff output"
+ 4E.2 Explain: "RCS file /Repository/module/file.c,v is in use"
+ 4E.3 Explain: "co error, line 2: Missing access list"
+ 4E.4 Explain: "error: RCS file name `xyz .c' contains white space"
+ 4E.5 Explain: cvs checkout: warning: <X> is not (any longer) pertinent
+ 4E.6 Why did a Repository file change from <file>,v to ,<file>,?
+
+
+ **** Answers:
+
+ 4E.1 Explain: "ci error: unexpected EOF in diff output"
+
+ RCS versions earlier than 5.5 print the above error when a file
+ does not end in a newline character. It can be caused by:
+
+ - Editing with Emacs and not using "require-final-newline".
+ - Committing a binary file.
+ - Filesystem failures (NFS!) that put nulls in your file.
+
+ The solution is to upgrade to RCS 5.5 or later. (Of course, this
+ won't fix filesystem failures. It will merely allow RCS (and
+ therefore CVS) to handle the file without error.)
+
+
+ 4E.2 Explain: "RCS file /Repository/module/file.c,v is in use"
+
+ This is an RCS error that occurs when its internal lock file has
+ been left around by an RCS command interrupted by some sort of
+ system crash, disk failure or SIGKILL signal.
+
+ Go into the Repository and look for files with names similar to
+ "file.c,v", usually starting with ',', '_' or '#'. Make
+ sure they are really crash remnants and do not belong to
+ transactions in progress -- a recent last-modified timestamp
+ is a good indicator of a live transaction. Delete them if they
+ are old.
+
+
+ 4E.3 Explain: "co error, line 2: Missing access list"
+
+ This is an error message from RCS Version 3 when it tries to read
+ a file created by a later version of RCS.
+
+ HP decided to "standardize" on an ancient version of RCS some time
+ ago. You can't use it for CVS. See 4H.6.
+
+ Since the error comes from having a later version of RCS than HP
+ supports, you probably did install the later version but must have
+ recently changed your $PATH or installed the HP package that has
+ RCS in it.
+
+ You should either reconfigure CVS to use absolute pathnames to the
+ proper versions of the RCS programs that CVS uses, or change your
+ PATH to look there first. If you haven't installed the latest
+ version of RCS, you should upgrade. See 1B.4
+
+
+ 4E.4 Explain: "error: RCS file name `xyz .c' contains white space"
+
+ RCS 5.6 doesn't allow white space in filenames. Apparently this
+ restriction will be removed in RCS 5.7, but CVS may still require
+ that filenames have no white space in them.
+
+
+ 4E.5 Explain: cvs checkout: warning: <X> is not (any longer) pertinent
+
+ This message occurs in three instances:
+
+ 1. When there is an entry in the ./CVS/Entries for file <X> and
+ there is no RCS file in the Repository to back it up.
+
+ If the working file exists, and hasn't changed (determined from
+ the timestamp) it is removed.
+
+
+ 2. When you try to check out a piece of the Repository with:
+
+ cvs checkout some/place/in/repository/tree
+
+ and at least the first element of the path (i.e. "some" in the
+ above) exists, but some part of the rest of it does not.
+
+ The checkout command checks the modules file first for the
+ whole path, then for a prefix of the path as a module name. If
+ it doesn't find *any* portion of your path in the modules file,
+ it says:
+
+ cvs checkout: cannot find module `<module/path>' - ignored
+
+ If it finds some set of prefix directories, it prints the
+ message you see.
+
+ In practice this is usually a spelling error.
+
+ 3. If the Repository files you are trying to check out or update
+ are not readable by you, the same problems can occur.
+ Check the permissions on the files involved.
+
+
+
+ 4E.6 Why did a Repository file change from <file>,v to ,<file>,?
+
+ This is an RCS problem, since the ,<file>, syntax for file names
+ is used by RCS and not CVS.
+
+ RCS constructs a new <file>,v in a temporary file named ,<file>,
+ (which doubles as a lock file) then renames it to <file>,v when it
+ is done. The only way this is reliable is if your system's
+ version of rename(2) is an atomic, as required by POSIX.
+
+ If your system has a non-atomic (and therefore non-POSIX)
+ rename(2) system call, RCS runs uses an internal version of this
+ algorithm to approximate the atomic rename:
+
+ rm <file>,v; ln ,<file>, <file>,v; rm ,<file>,
+
+ If the system crashes, or you lose your NFS connection between the
+ first "rm", but before the "ln", you can be left only with the
+ ,<file>, file. If the crash or network failure occurs between the
+ "ln" and the final "rm", you could be left with a pair of linked
+ names.
+
+ Recovery:
+ - If only the ,<file>, exists, rename it to <file>,v.
+
+ - If both ,<file>, and <file>,v exist and are linked, remove the
+ ,<file>, file.
+
+ - If both ,<file>, and <file>,v exist and are separate files, look
+ at the dates, "diff" them and make your best guess. This sounds
+ like the remnants of two separate events.
+
+
+
+----------------
+-- Section 4F -- Related Software
+----------------
+
+ **** Questions:
+
+ 4F.1 How do I use CVS under Emacs? Is there an Emacs cvs-mode?
+ 4F.2 What is GIC (Graphical Interface to CVS)?
+ 4F.3 What is CAVEMAN?
+
+
+ **** Answers:
+
+This section covers a small handful of subsystems that connect to CVS in
+some way. Most are "front ends" in that they offer a different user
+interface to CVS, but use CVS to perform the normal tasks.
+
+ NOTE: The short summaries below combine details culled from public
+ announcements of the listed software with the personal opinions of
+ the author of the FAQ entry.
+
+ 4F.1 How do I use CVS under Emacs? Is there an Emacs cvs-mode?
+
+ The pcl-cvs package distributed with CVS is an emacs package that
+ helps with the update/commit process. When you are ready to
+ update, you use the 'cvs-update' command within emacs. This
+ executes "update" and fills a cvs-mode buffer with a line for each
+ file that changed. The most helpful features are: descriptive
+ words for what happened (i.e. Merged or Conflict rather than 'U'
+ or 'C'), single keys bound to diffs and commits, and the ability
+ to mark arbitrary groups of files, possibly from different
+ directories, for commit as a whole.
+
+ All the developers in my group that use emacs find pcl-cvs a much
+ friendlier and more helpful way to update/commit than raw cvs.
+ One vi user even converted to emacs just to use pcl-cvs.
+
+ Contributed by Jeffrey M Loomis
+
+ 4F.2 What is GIC (Graphical Interface to CVS)?
+
+ GIC provides a graphical user interface to the Concurrent Version
+ System (CVS), a powerful revision control system. GIC is
+ implemented in the Tcl/Tk programming language and is intended to
+ augment the sometimes cumbersome CVS command line interface.
+ Novices should find GIC to be much easier to learn than the CVS
+ command line.
+
+ While GIC is easy to use, it does not contain any documentation on
+ CVS. Users of GIC must first learn the concepts of CVS such as
+ modules and merging, as well as the simple functions, such as
+ committing and updating. The CVS manual page and the README file
+ are good places to look.
+
+ contact
+ David Marwood
+ marwood@cpsc.ucalgary.ca
+
+ [Extracted from an announcement by David Marwood.]
+
+ GIC can be obtained by anonymous ftp to (on the date of this FAQ)
+
+ ftp.cpsc.ucalgary.ca:/pub/users/marwood/gic-1.1.tar.Z
+ ftp.cpsc.ucalgary.ca:/pub/users/marwood/gic-1.2b1.tar.Z
+
+
+ 4F.3 What is CAVEMAN?
+
+ CAVEMAN is a front end to CVS written in PERL providing a
+ collection of features desired by the site where it was developed.
+
+ - The ability to spread a "project" over multiple Repositories.
+ - Optional automatic tagging after each commit.
+ - Additional locking of files.
+ - Extra before and after program hooks.
+ - A layer of event logging.
+ - All sorts of error messages.
+ - Many changes to the semantics of commands.
+
+ It is available via anonymous ftp on ftp.llnl.gov [128.115.54.18]
+ in gnu/caveman_vX.Y.Z.tar.gz (The numbers X, Y, & Z vary.)
+
+ contact
+ Kathleen Dyer kdyer@llnl.gov
+ (510)423-6803
+ (510)423-5112 FAX
+
+ [[Does someone want to elaborate?]]
+
+
+----------------
+-- Section 4G -- Engineering
+----------------
+
+ **** Questions:
+
+ 4G.1 Where can I find out about Software Engineering?
+ 4G.2 How do I flexibly arrange the modules file to describe my sources?
+ 4G.3 Can I have multiple source repositories, one for each project?
+ 4G.4 Who should administer the Repository and manage the modules file?
+ 4G.5 Isn't disk space a big factor? CVS copies files out of the
+ Repository, duplicating everything.
+
+
+ **** Answers:
+
+This section is really beyond the scope of CVS, but so many people ask
+questions about how to do Software Configuration and Engineering that I
+thought I'd try to include some information. If you have any
+improvements, references or ideas, speak up.
+
+
+
+ 4G.1 Where can I find out about Software Engineering?
+
+ A couple different people suggested this book:
+
+ Software Configuration Management: Coordination for Team
+ Productivity; Wayne A. Babich; Addison Wesley; 1986;
+ ISBN 0-201-10161-0
+
+
+ A number of others suggested Appendix B of the book "Decline and
+ Fall of the American Programmer" by Ed Yourdon, called "The
+ Programmer's Bookshelf". It list 87 books you are expected to
+ have read. Since they publish many of the books, Prentice-Hall
+ distributes this list as "Prentice Hall Professional Technical
+ reference PTR-125-AA3.
+
+ One interesting item from the Yourdon book: The total number
+ of professional computer books sold is less than the number
+ of programmers currently in the United States. It wasn't clear
+ from the book whether this meant "per year" or not, but it is
+ still frightening.
+
+
+ 4G.2 How do I flexibly arrange the modules file to describe my sources?
+
+ An equivalent question might be, "How do I structure my sources?"
+ This can be a difficult question especially in the areas that are
+ more political than technical.
+
+ Generally you want to think about which pieces of your system need
+ to be checked out together, built as one system or tagged as a
+ consistent whole. You should certainly create module names that
+ correspond to complete, buildable collections that you would tag
+ and release as one "product". It is also convenient to create
+ module names for small sections of the Repository containing
+ files that will all be worked on at the same time by the same
+ person or group.
+
+ Once you have defined the structure of your work, you can usually
+ see how to lay it out in a Repository. After that the modules
+ file is easy. You set up module names and aliases to match what
+ you need to check out by name. If you like relative directories,
+ it is possible, but not recommended, to work completely without a
+ modules file. See 1D.11 and 2C.7 for some info about the modules
+ file.
+
+ Here are a few types of modules. You should experiment to see
+ what kind of structure each of these produces. They all have
+ different uses.
+
+ 1. Connected projects in one group with two separate helper
+ directories. The helper directories can contain build tools,
+ header files, libraries, or whatever you like.
+
+ These are all aliases that checkout relative pathnames. The
+ equivalent results could be produced by placing the selected
+ relative pathnames on the "cvs checkout" command line.
+
+ pr1 -a P1 HELPERS
+ pr2 -a P2 HELPERS
+ pr3 -a P3 HELPERS
+ pr12 -a P1 P2 HELPERS
+ pr13 -a P1 P3 HELPERS
+ pr23 -a P2 P3 HELPERS
+
+ P1 -a group1/proj1
+ P2 -a group1/proj2
+ P3 -a group1/proj3
+ HELPERS -a group1/helper1 group1/helper2 MAKEFILE
+ MAKEFILE -a group1/Makefile
+
+ Actual Repository directory structure: (from $CVSROOT down)
+
+ group1/
+ Makefile
+ The top level Makefile.
+ helper1/
+ helper2/
+ Helper files and dirs
+ proj1/
+ Files and dirs
+ proj2/
+ Files and dirs
+ proj3/
+ Files and dirs
+
+ "checkout group1" produces a duplicate of the above.
+ "checkout projX" produces all but "projY" and "projZ".
+ "checkout projXY" produces all but "projZ".
+
+
+ 2. Here is the exact same set of module names describing the same
+ Repository layout using module names (and aliases containing
+ module names) instead of merely aliases for relative pathnames.
+
+ There is one difference in the result. The name of the top
+ level directory in the checked out working tree will match the
+ "module" name (e.g. pr1) instead of always being "group1" as it
+ was in the first example above.
+
+ pr1 group1 proj1 &HELPERS
+ pr2 group1 proj2 &HELPERS
+ pr3 group1 proj3 &HELPERS
+ pr12 group1 proj1 proj2 &HELPERS
+ pr13 group1 proj1 proj3 &HELPERS
+ pr23 group1 proj2 proj3 &HELPERS
+
+ HELPERS -a helper1 helper2 group1-Makefile
+ helper1 group1/helper1
+ helper2 group1/helper2
+ group1-Makefile -d . group1 Makefile
+
+ The above line (with the -d in it) says that when the
+ module named "group1-Makefile" is checked out, the file
+ named Makefile file will be found in a directory named
+ $CVSROOT/group1 and will be checked out into a directory
+ named '.', which obviously already exists.
+
+ The & references say to interpret those pathnames relative
+ to the directory where the whole module is stored. For
+ the "pr1" module, that directory is "group1", so the
+ &HELPERS reference winds up placing Makefile in '.'
+ relative to "group1".
+
+
+ 3. A short one containing the basic "module" actions:
+
+ m1 head/path file1 dir2 file3 dir4 file5
+
+ When checked out, a directory named "m1" appears in your
+ current directory. Elements named file1, dir2, file3,
+ dir4, and file5 appear in it. They were originally taken
+ as relative paths from $CVSROOT/head/path.
+
+
+ 4. Here's another way to construct a working directory out of
+ pieces of the Repository:
+
+ projX projX Makefile &projX_inc &projX_src &projX_doc
+
+ # The first line selects a single file within projX, plus
+ # the contents of three other modules. Those three other
+ # modules rename their directories.
+
+ projX_inc -d include projX/inc
+ projX_src -d source projX/src
+ projX_doc -d documentation projX/doc
+
+
+ 5. A Unix tree. This is similar to what CVS was developed for and
+ the way I have used it for years.
+
+ # Top level
+ unix unix
+ u_bin unix/bin
+ u_etc unix/etc
+ u_man unix/man
+ usr-bin unix/usr.bin
+
+ # Subdirs of top level dirs. (tiny subset)
+ ls unix/bin/ls
+ fsck unix/etc/fsck
+ man8 unix/man/man8
+
+ # Programs without subdirs. (tiny subset)
+ cat unix/bin Makefile cat.c
+ uniq unix/usr.bin Makefile uniq.c
+
+ # /usr/local/src
+ localsrc localsrc
+ gnu localsrc/gnu
+ public localsrc/public
+ X11 localsrc/X11
+
+ # GNU and PD tools
+ cvs localsrc/gnu/cvs
+ emacs localsrc/gnu/emacs
+ rcs localsrc/gnu/rcs
+ btoa localsrc/public/btoa
+ tcsh localsrc/public/tcsh
+
+ # X11 related items.
+ tvtwm localsrc/X11/contrib/tvtwm
+
+ "unix" was checked out and built from the top down, using a set
+ of Makefiles that knew about the whole structure. "localsrc"
+ was kept checked out in /usr/local/src.
+
+ At any time I could run "checkout ls" or "checkout cat" and get
+ a simple directory with only that tool in it, plus a subset
+ Makefile that knew how to build that tool against the installed
+ (or alternate, via environment variables) headers and libraries.
+
+ I found it very handy to be able to run "ls" and see the three
+ tools I was porting that week.
+
+
+ 4G.3 Can I have multiple source repositories, one for each project?
+
+ Yes, you can have as many Repositories as you like. But each
+ Repository must be managed separately, creating additional work.
+
+ Question 4A.1 provides a short description of setting up a
+ single Repository. A few additional considerations:
+
+ 1. It is a good idea to start by creating a single Repository and
+ split it up (or create additional Repositories) only if you
+ believe it is really necessary. I would only create a new
+ Repository if the data is completely disconnected from the rest
+ of the main Repository.
+
+ 2. If there is a lot of overlap among the developers working on
+ the collections of files you want to place in different
+ Repositories, or if there is any connection between those
+ collections, I would go out of my way to create a single
+ Repository. It is much easier to manage.
+
+ 3. Disk space should not be a factor since you can build up a
+ Repository using symbolic links and/or remote mounts.
+
+ 4. Each Repository is completely distinct. You can't check out
+ modules from different Repositories at the same time. A better
+ way of looking at it is that if you *can* check out two modules
+ or directories with a single "checkout" command (without
+ contortions or explicit absolute pathnames), then they are in
+ the same Repository.
+
+ 5. To "checkout" modules from multiple Repositories, you must use
+ the "cvs -d" option on all CVS commands or alter your $CVSROOT
+ variable when you change focus to another Repository. If you
+ work with multiple Repositories, it is a good idea to configure
+ CVS to use absolute pathnames in the ./CVS/Repository file,
+ since most commands (other than "checkout") will use that file
+ rather than $CVSROOT.
+
+ 6. If you configure CVS to use relative pathnames in your
+ ./CVS/Repository files, you must always be careful to set your
+ $CVSROOT properly or you will get unexpected results.
+
+ If you have two modules or directories by the same name at the
+ same relative path inside two different Repositories, you are
+ asking for disaster. You could unexpectedly update a directory
+ with completely unrelated files. This is not a fanciful
+ example -- a Repository is occasionally duplicated for release
+ purposes in which case *all* the paths in the two Repositories
+ are the same.
+
+
+ 4G.4 Who should administer the Repository and manage the modules file?
+
+ This is a "management style" question. In large or traditional
+ groups, the CVS procedures are warped to conform to local
+ conventions. In small groups, in groups with strong personalities
+ or on new projects the choice of source control procedures can
+ help create some of the working environment. Here is a taxonomy
+ of environments I have worked in or helped set up:
+
+ Situation 1.
+
+ A small number of competent developers working on a medium
+ size project. We all got along and we all respected each
+ other (at least technically). Anyone edited anything.
+
+ Modules and Repository admin was mostly left to me. I never
+ found a problem in minor changes made by anyone else.
+
+
+ Situation 2.
+
+ A large number of experienced developers sprinkled with
+ wackos. Many of the developers didn't want to deal with any
+ kind of source control. They wanted a full-service source
+ control system that caused them zero thought.
+
+ I learned "big stick" diplomacy here. There was a small
+ number of "designated" (by me) people who were allowed to do
+ *anything* other than "update" and "commit". Even "checkouts"
+ were controlled. This is where I found "history" and
+ "release" the most useful.
+
+ Situation 3.
+
+ A small number of developers who wanted me to "help", but who
+ didn't want to deal with anything other than their favorite
+ algorithms.
+
+ I didn't have the time to baby-sit this group, so I designated
+ one of them to be my official contact and made him do it all.
+ He felt sullied by the requirement to pay attention to
+ anything other than his pet coding projects, but enjoyed the
+ "status" of being the only one who could touch the control
+ files without my kicking the chair out from under him.
+
+ Situation 4.
+
+ A huge number of developers of covering the whole spectrum of
+ competence and experience split into 20 groups, none of which
+ cooperated with the others, working on 57 different projects,
+ most of which didn't inter-operate.
+
+ Managing it in any coherent way was not my responsibility (and
+ beyond my tolerance for chaos). Too many people. So I
+ privately designated a person in each group to be the contact
+ and kept watch on the Repository activity. When something
+ went wrong, I notified the contact for the group and told him
+ what was happening and *he* kept his troops in line. They
+ were tougher with their own group that I would have been.
+
+ Eventually only a few people were willing to touch the control
+ files, since they were flamed from all directions if they
+ screwed up.
+
+ Situation 5.
+
+ In a medium group of really *serious*, and seriously
+ overworked, people, someone else was designated the "master".
+ I convinced the master I knew what I was doing and went on my
+ way.
+
+ No one else in the world was allowed to touch anything.
+
+ Situation 6.
+
+ In a large amorphous group of beginners, experts and clowns,
+ over whom no one had official control, I was forced to employ
+ a group of relative beginners (who became experts rather
+ quickly) to police the world. The ultimate in locking the
+ barn after the horse was stolen, we kept Chaos from destroying
+ us only by use of superior firepower.
+
+
+
+ My choice, if allowed, is to let anyone touch anything. I keep
+ backups of important items and let people know individually
+ whether I want them to touch things or not. If someone on my "no
+ touch" list touches and succeeds, they are allowed more slack. If
+ they screw up after being warned, their screwup becomes public.
+ After a few months, I usually have no trouble keeping the world
+ running smoothly, at least from my (and CVS's) perspective.
+
+
+ 4G.5 Isn't disk space a big factor? CVS copies files out of the
+ Repository, duplicating everything.
+
+ Everyone knows that disk space is getting cheaper. How do we
+ reconcile this with the equally well-known problem that *all* disk
+ is *always* filled up?
+
+ In my opinion, the main reason disk space will never be an
+ unlimited resource is that it is the major variable in
+ organizational time/space tradeoffs. It isn't a problem of waste
+ or an aspect of Murphy's law, as some claim it is, but rather a
+ direct consequence of good management. Disk space is, and will
+ always be, a limited resource.
+
+ First, the cost of *deploying* that disk is not dropping as fast
+ as the cost of the storage medium. The cost of machines to hold
+ the disks and the networks to connect them are dropping more
+ slowly than disk media. And the cost of the human time necessary
+ to manage the machines, networks, disks, and the developers using
+ them, is not dropping at all. The cost of human time continues to
+ rise.
+
+ If management decides that expensive human time can be saved by
+ using all that new disk space to keep the last three releases
+ online, then that's what it will be used for. If each release
+ takes up a Gigabyte and you support 30 platforms, a simple
+ time-saving suggestion has just grabbed 100 Gigabytes of disk
+ space. And we've ignored the potential disk storage needed to
+ support "better Customer Service", another management refrain.
+
+ Even at 30 cents per Megabyte (next year's price), you've just
+ used up $30,000 of disk space. And that doesn't count the
+ computers, tape drives and humans necessary to maintain and deploy
+ all of it. Spending money to save time has its own overhead, too.
+
+
+ Binaries are getting bigger. Graphics and data collection devices
+ can eat up any amount of disk. There are more tools available,
+ more libraries, more raw data than you can ever store. My home
+ computer has a Gigabyte of disk on it. It could easily handle 30.
+
+ The "economy" of disk storage media will never remove the need to
+ manage disk space.
+
+
+ So, here's an un-reviewed suggestion originally from Graydon Dodson
+ <grdodson@lexmark.com>, which I've altered and edited heavily.
+
+ - Keep a directory where the whole tree is checked out. (It might
+ be built and tested once in a while to make sure it is worth
+ linking to, but that doesn't affect the source control aspect of
+ this procedure). Let's call it /master/build.
+
+ - Write a tool that creates a tree of directories (like the X11
+ "lndir" command) filled with links to the checked out files in
+ the /master/build tree.
+
+ This tool should also provide real copies of, not symlinks to,
+ all the files within the CVS administrative directories.
+
+ - You could also provide a way for the tool to take a list of
+ whole directories that you will never change, for which it would
+ create a single symlink to the directory and not a subtree of
+ symlinks to files. Or you could rm -r pieces of the resulting
+ working directory yourself and replace it with links.
+
+ - If you want to edit a file, you have to grab a real copy and
+ keep it until your revision shows up in the /master/build tree.
+ I'd create a script to do this: cvsgrab <file>
+
+ #!/bin/csh -f
+ set f = $1
+ if (! -l $f) then
+ echo "file $f is not a symlink"
+ exit 1
+ endif
+ rm $f
+ set rev = `grep "^/$f/" CVS/Entries | awk -F/ '{print $3}'`
+ cvs update -p -r $rev $f > $f
+
+ You can't do a plain "cvs update" since that would grab newer
+ revisions from the Repository, not the revision you wanted to
+ start with. After the file is no longer a symlink, you can work
+ normally. You'll have to run "update" before "commit" anyway if
+ there are newer revisions.
+
+ - Presumably there would also be a tool to traverse the link tree
+ and revert it to links if there are no modified files and/or if
+ all the real files match the revision of the /master/build tree.
+
+ - To avoid confusing CVS when the /master/build revisions are
+ updated but your CVS/Entries files is not, CVS would have to
+ change to handle symlinks. It currently causes problems with
+ this scenario:
+
+ 1. ./<file> is a symlink.
+ 2. ./CVS/Entries says you are revision 1.2.
+ 3. The corresponding CVS/Entries file in /master/build
+ says the latest revision is 1.3.
+ 4. cvs update <file> shows a 'C' conflict flag.
+
+
+----------------
+-- Section 4H -- Other Systems
+----------------
+
+ **** Questions:
+
+ 4H.1 I use a NeXT. Is there anything I need to know?
+ 4H.2 I use OS/2 and/or DOS. Is there anything I need to know?
+ 4H.3 I use SCO Unix. Is there anything I need to know?
+ 4H.4 I use AIX. Is there anything I need to know?
+ 4H.5 I use IRIX. Is there anything I need to know?
+ 4H.6 I use an HP system. Is there anything I need to know?
+ 4H.7 I use AFS. Is there anything I need to know?
+ 4H.8 I use A/UX. Is there anything I need to know?
+
+
+ **** Answers:
+
+Out of the box, CVS works on most varieties of Unix. Some near-Unix
+systems have a few problems and non-Unix systems have a *lot* of problems.
+
+ 4H.1 I use a NeXT. Is there anything I need to know?
+
+ NeXTSTEP 3.0's Interface Builder uses "nib" directories, rather
+ than the files used in previous revisions. It removes files it
+ doesn't recognize, making it impossible to place such a directory
+ under CVS -- the CVS admin directory will be removed.
+
+ Some time ago, <Bob_Vadnais@pdh.com> posted a palette named
+ CVSPalette that claimed to resolve this problem. It was intended
+ to preserve the CVS administrative directories within nib
+ documents (directories) that Interface Builder usually removes.
+
+ CVSPalette is no longer in its announced place:
+
+ ftp.cs.orst.edu:/pub/next/submissions
+
+ though I did find two other interesting files on ftp.cs.orst.edu:
+
+ /software/NeXT/sources/tools/cvs-next-2_1_1.tar.Z
+
+ which is a port of CVS 1.3 (along with RCS and diff) and:
+
+ /software/NeXT/sources/programming/cvs.postamble-2.4.gz
+
+ which appears to be a set of wrappers for CVS commands that claim
+ to allow you to use CVS effectively (and without need for the
+ "command line") on a NeXT machine.
+
+
+ [[Anyone know the truth about CVS and NeXT?]]
+
+
+ 4H.2 I use OS/2 and/or DOS. Is there anything I need to know?
+
+ You can share RCS files between Unix and DOS while avoiding the
+ MS-DOS file name limits by setting your RCSINIT environment
+ variable to '-x/,v'. New RCS files will be created without the
+ standard ",v" suffix, though files ending in ",v" will still be
+ found if there is no matching file in the same directory without
+ the ",v".
+
+ Erik van Linstee <linstee@dutecaj.et.tudelft.nl> offers an
+ OS/2 and a DOS port of CVS 1.3 in:
+
+ ftp.informatik.tu-muenchen.de:/pub/comp/os/os2/gnu/devtools
+ or
+ ftp.rrzn.uni-hannover.de:/pub/os2-local
+
+ The files are named:
+
+ cvs13p?[bs].zip
+
+ Where the ? stands for the patch level (currently 8) and the b is
+ for the binaries, the s for the sources.
+
+ There are three binaries. An OS/2 only one (32-bit), a DOS only one
+ (16-bit) and an EMX one that runs on both (32-bit).
+
+ There are many differences between the Unix and the DOS versions
+ of CVS. Read the material that comes with the DOS version before
+ using it.
+
+ [[Updates?]].
+
+
+ 4H.3 I use SCO Unix. Is there anything I need to know?
+
+ On SCO/UNIX 3.2 V2.0 POSIX signals don't work. Unfortunately the
+ configure program detects POSIXness and configures in the use of
+ POSIX signals. Workaround : Edit out the check for POSIXness in
+ the configure script. [[You could also remove all occurrences of
+ "-DPOSIX=1" from the Makefiles after configure is run. -dgg-]]
+
+ SCO/UNIX doesn't understand #!/<some shell> syntax. This breaks
+ the use of log.pl as it gets invoked by /bin/sh instead of
+ !#/usr/local/bin/perl. WorkAround : edit log.pl and change it into
+ a shell script which invokes perl with log.perl (renamed from
+ log.pl) as input.
+ Contributed by Joe Drumgoole
+
+
+ 4H.4 I use AIX. Is there anything I need to know?
+
+ The only report on AIX claims to have no trouble using it in
+ concert with SunOS and IRIX platforms.
+
+
+ 4H.5 I use IRIX. Is there anything I need to know?
+
+ If you see "uid" numbers where you would expect user names, try
+ adding -lsun to the link line. Without it CVS is unable to
+ retrieve "passwd" data through NIS.
+
+
+ 4H.6 I use an HP system. Is there anything I need to know?
+
+ HP distributes RCS version 3 (a circa 1983 release!) with HP-UX.
+ CVS does not work with RCS version 3; it requires RCS version 4
+ or later. Your best bet is to find the latest version of RCS
+ and install it somewhere.
+
+ HP-UX 8.07 has a serious bug with the mmap system call and NFS
+ files; the bug can crash the operating system. Make sure that
+ you configure RCS to avoid mmap by setting has_mmap to 0 in
+ RCS's conf.h. This bug is fixed in HP-UX 9.
+
+ Contributed by Paul Eggert
+
+ If using the setgid() trick described in 4D.13, you will have to
+ create an entry in the /etc/privgroup file to give the group
+ assigned to the cvs executable setgid permission (see
+ setprivgrp(1m)). Additionally, if you are restricting "read"
+ access to the Repository by limiting access to the executable
+ (this requires yet another group), then you will require that
+ /etc/logingroup exists and is configured correctly (usually it's
+ just alink to /etc/group).
+
+ Contributed by Dale Woolridge
+
+
+ 4H.7 I use AFS. Is there anything I need to know?
+
+ There is a problem with the way CVS performs its locking when the
+ files are within AFS. When your current PTS id != your uid, the
+ locks are not deleted. The stat() system call returns the PTS id
+ of the owner. If that id != your uid, CVS assumes you did not lock
+ it, and leaves the lock files alone. The next time you try to use
+ it, it complains that someone has the repository locked.
+
+ Contributed by Michael Ganzberger
+
+ [[This was against CVS 1.3. Is it still in CVS 1.4?]]
+
+
+ 4H.8 I use A/UX. Is there anything I need to know?
+
+ [[??]]
+
+
+
+
+=============================================
+== Section 5 ==== Past & Future ====
+=============================================
+
+----------------
+-- Section 5A -- Contributors
+----------------
+
+ **** Questions:
+
+=5A.1 Who wrote CVS?
+ 5A.2 You didn't write all of this FAQ, did you?
+
+
+ **** Answers:
+
+
+=5A.1 Who wrote CVS?
+
+ Brian Berliner <berliner@sun.com> converted a collection of
+ scripts written by Dick Grune <dick@cs.vu.nl> into a C program,
+ then added all sorts of features. He continues to maintain CVS.
+
+ Jeff Polk <polk@bsdi.com> wrote much of the code added between
+ revisions 1.2 and 1.3. Many others were involved at some level.
+
+ david d zuhn <zoo@armadillo.com> fixed a number of bugs, added
+ some of the new features, reworked the whole thing to be more
+ portable, and provided much of the energy to push CVS 1.4 out
+ the door.
+
+ Jim Kingdon implemented CVS 1.5's remote repository access
+ features, fixed many bugs, and managed the release of version 1.5.
+
+ Take a look at the README and the ChangeLog files in the CVS
+ sources for more contributors.
+
+
+ 5A.2 You didn't write all of this FAQ, did you?
+
+ In the original hunt for questions to answer (performed in
+ Jan/Feb, 1993), I polled hundreds of people and I rephrased all
+ sorts of text found on the net. Between 2/93 and 10/93, I
+ released about 20 versions, with corrections and additions from
+ the info-cvs mailing list and private correspondence.
+
+ Between 10/93 and 10/94 I extracted frequently asked questions
+ from the 1200 mail messages to the info-cvs mailing list,
+ turned them into focused questions and tried to answer them.
+
+ 93/02/?? ~4000 lines
+ 93/06/?? ~5000 lines
+ 93/10/23 7839 lines 278K
+ 94/10/29 9856 lines 360K
+ 95/05/09 9981 lines 365K
+
+ Because there are so many posers of questions, I will list only
+ those who contribute answers or help significantly with the
+ content and structure of this document.
+
+ If I used someone else's text verbatim, I mentioned it in the
+ given answer. The people whose email postings have added to this
+ document or who have added to my understanding are:
+
+ Brian Berliner <berliner@sun.com>, CVS maintainer.
+ Paul Eggert <eggert@twinsun.com>, RCS maintainer.
+
+ Gray Watson <gray@antaire.com>
+ Per Cederqvist <ceder@signum.se>
+ Pete Clark <pclark@is.com>
+
+ all of whom have sent me copies of their tutorials
+ and local CVS documentation.
+
+ Additional contributors, who have sent me ideas, text, corrections
+ and support include (in alphabetical order):
+
+ Per Abrahamsen <amanda@iesd.auc.dk>
+ Donald Amby <amby@mixcom.mixcom.com>
+ Mark D Baushke <mdb@cisco.com>
+ Jim Blandy <jimb@cyclic.com>
+ Tom Cunningham <tomc@bouwsma,sps.mot.com>
+ Graydon Dodson <grdodson@lexmark.com>
+ Joe Drumgoole <joed@splatter.demon.co.uk>
+ Don Dwiggins <dwig@markv.com>
+ Bryant Eastham <bryant@ced.utah.edu>
+ Dan Franklin <dan@diamond.bbn.com>
+ Michael Ganzberger <ganzbergermd@ES.net>
+ Steve Harris <vsh%etnibsd@uunet.uu.net>
+ Erik van Linstee <linstee@dutecaj.et.tudelft.nl>
+ Jeffrey M Loomis <jml@world.std.com>
+ Barry Margolin <barmar@near.net>
+ Mark K. Mellis <mkm@ncd.com>
+ Chris Moore <Chris.Moore@src.bae.co.uk>
+ Gary Oberbrunner <garyo@avs.com>
+ Steve Turner <stevet@carrier.sps.mot.com>
+ Dave Wolfe <dwolfe@pffft.sps.mot.com>
+ Dale Woolridge <dwoolridge@cid.aes.doe.ca>
+
+
+
+ Please send corrections. If I forgot you, remind me and I'll add
+ your name to the list.
+
+
+----------------
+-- Section 5B -- Bugs and Patches
+----------------
+
+This section addresses some known bugs and patches for them.
+Large patches will be stored in the FTP area.
+See the Development section later for stuff being worked on.
+
+ **** Questions:
+
+ 5B.1 Why can't CVS handle deletion of directories?
+ 5B.2 Why can't CVS handle the moving of sources from one place in the
+ directory hierarchy to another?
+ 5B.3 When I typed "cvs update -D <date>", why did it check out all
+ sorts of ancient files from the Attic? Shouldn't it just create
+ the set of files and revisions that existed at that date?
+ 5B.4 When I typed "cvs update -D <date>" in my branch, why did it
+ screw up all my files?
+ 5B.5 When I executed "checkout" into an existing directory I got "No
+ such file or directory" errors. Why?
+ 5B.6 Why does "update" send all output to the terminal after 26 files
+ have been updated?
+ 5B.7 Why does the merge occasionally resurrect lines of code?
+ 5B.8 Why does the merge fail when my "rcsmerge" program is
+ configured to use GNU diff version 2.1 or later?
+
+
+ **** Answers:
+
+ 5B.1 Why can't CVS handle deletion of directories?
+
+ An oversight, probably. [[Fixed in a future release?]]
+
+
+ 5B.2 Why can't CVS handle the moving of sources from one place in the
+ directory hierarchy to another?
+
+ A "renaming database" has been proposed to track the history of
+ pathname changes in the Repository. A general solution is a
+ difficult problem. See 4B.8.
+
+
+ 5B.3 When I typed "cvs update -D <date>", why did it check out all
+ sorts of ancient files from the Attic? Shouldn't it just create
+ the set of files and revisions that existed at that date?
+
+ This seems to be a bug, but is really the lack of any obvious
+ place to store the date when a file is "removed".
+
+ There are four ranges of dates that CVS has to deal with when
+ trying to determine what revision was available on <date>:
+
+ 1. Dates before the earliest revision in the file.
+
+ 2. Dates between any two revisions in the file.
+
+ 3. Dates between the latest revision in the file and the date
+ when the file was moved to the Attic by "commit".
+
+ 4. Dates after moving the file to the Attic.
+
+ Since the date when a file is moved to the Attic is not stored
+ anywhere, CVS can't tell the difference between #3 and #4.
+ To avoid not producing a file that should exist in case #3, it
+ produces extraneous files in case #4.
+
+
+ For the above reason, if you have removed files in the Attic, it
+ is better to use "-r <tag>, or even "-r HEAD" than to use a
+ date spec.
+
+ If you must use "-D <date>", then you should either archive and
+ delete Attic files (losing some past history) or construct your
+ Makefiles to work with an explicit list of files and let the old
+ source files stay in the working directory. The contents of the
+ revision-controlled Makefile can then be considered to contain
+ deletion "information".
+
+
+ 5B.4 When I typed "cvs update -D <date>" in my branch, why did it
+ screw up all my files?
+
+ Currently, the internal routine ("version_ts") that looks up
+ info about a file, overrides both the tag and date if *either*
+ the tag or date is specified on the command line. If only the
+ date is specified, it should not override a branch tag, but it
+ does.
+
+ In CVS 1.3, the documented "-D <branch_tag>:<date>" syntax only
+ works with the Main Branch and the Vendor Branch.
+
+ [[Is this fixed in CVS 1.4? This is one item I didn't check.]]
+
+
+ 5B.5 When I executed "checkout" into an existing directory I got "No
+ such file or directory" errors. Why?
+
+ Though the man page says that "checkout" turns into an
+ "update -d" in directories that already exist, it is referring
+ to directories that already exist *and* were created by CVS.
+
+ When you try to run "checkout" on top of an existing directory
+ structure, some of which wasn't created by CVS, it will handle
+ directories and non-CVS files within directories already under
+ CVS, but it will display the above error on non-CVS files within
+ non-CVS directories.
+
+
+ 5B.6 Why does "update" send all output to the terminal after 26 files
+ have been updated?
+
+ CVS uses the "tmpnam()" function to generate temporary file names.
+ The ANSI standard for the "tmpnam()" function says:
+
+ "The tmpnam function generates a different string each time it is
+ called, up to TMP_MAX times. If it is called more than TMP_MAX
+ times, the behavior is implementation defined."
+
+ Later it says that the value of "TMP_MAX shall be at least 25."
+
+ On some platforms, the above specification is taken literally by
+ turning "at least 25" into "exactly 26" and by doing something
+ foolish (i.e. "implementation defined") after that. Some
+ systems return the same name repeatedly, which causes one form of
+ trouble. Others return NULL or garbage, which causes a different
+ form of trouble.
+
+ The broken systems appear to be cycling a single character through
+ the alphabet. SunOS cycles 3 characters through the alphabet, so
+ it won't cause trouble until 26 cubed or 17576 calls to
+ "tmpnam()".
+
+ Since CVS doesn't depend on the exact format of the tmp files, the
+ workaround is to provide a "tmpnam()" that doesn't have a limit
+ on the number of calls to it.
+
+
+ 5B.7 Why does the merge occasionally resurrect lines of code?
+
+ The diff3 program provided by GNU diff version 1.15 has a bug
+ that occasionally causes text to come back from the dead.
+
+ This is an old problem which you can avoid by upgrading to the
+ latest GNU "diffutils" package. If you were using GNU diff
+ version 1.15 and plan to upgrade to the latest GNU diff program,
+ see the next question.
+
+
+ 5B.8 Why does the merge fail when my "rcsmerge" program is
+ configured to use GNU diff version 2.1 or later?
+
+ A change in the overlap format was introduced in GNU diff3
+ between versions 2.0 and 2.1 that causes RCS versions before
+ 5.6.0.1 to fail during a merge.
+
+ To get consistent rcsmerge behavior, you have four choices:
+
+ 1. Go back to using GNU diff 1.15 or 2.0 with RCS versions 5.5 or
+ 5.6. If you want to use GNU diff 2.1 or later, you'll have to
+ pick one of the other three choices in this list.
+
+ 2. Grab RCS version 5.6.0.1 from an FSF archive and set the
+ DIFF3_A macro to '1' as it tells you to in the Makefile:
+
+ #define DIFF3_A 1
+
+ 3. Patch the RCS 5.6 source. Change line 84 in "merger.c" from:
+
+ DIFF3, "-am", "-L", label[0], "-L", label[1],
+ to
+ DIFF3, "-amE", "-L", label[0], "-L", "", "-L", label[1],
+
+ 4. Wait both for RCS version 5.7 to be released and for a new
+ version of CVS that can deal with it.
+
+
+----------------
+-- Section 5C -- Development
+----------------
+
+
+ **** Questions:
+
+ 5C.1 Where do I send bug reports?
+ 5C.2 Where do I send fixes and patches?
+ 5C.3 Where do I send ideas for future development?
+=5C.4 What plans are there for new features?
+ 5C.5 I have some time and I'd like to help. What can I do for you?
+
+
+ **** Answers:
+
+ 5C.1 Where do I send bug reports?
+
+ First make sure it is a bug. Talk to your friends, coworkers and
+ anyone you know who uses CVS. Search this FAQ for related issues.
+ Then test it carefully. Try out variations to narrow down the
+ problem. Make sure it is repeatable. Look for workarounds so you
+ can report them.
+
+ If you are still sure it's a bug and you tried to fix it, skip to
+ the next question. Otherwise, send a message to the info-cvs
+ mailing list containing one of the following:
+
+ 1. If you have a good repeatable case and you think you know what
+ is going on, then describe the problem in detail. Include
+ a workaround if you have one.
+
+ 2. If you have no idea what is going on, go ahead and send a
+ question to the info-cvs mailing list. Include any information
+ you have describing the symptoms.
+
+
+ 5C.2 Where do I send fixes and patches?
+
+ First make sure the "fix" does something useful. Have someone
+ review your fix. Spend a bit of one person's time in a detailed
+ analysis of your vast idea before displaying a half-vast idea to
+ hundreds of people.
+
+ If you tried to fix it and the patch is small, include the patch
+ in your message. Make sure the patch is based on the latest
+ released version of CVS.
+
+ If you tried to fix it and the patch is large, you should think
+ about why it is so large. Did you add a generally useful feature,
+ or did it grow out of hand?
+
+ If you still believe it is solid, produce a patch file using the
+ CVS commands "patch" or "diff -c". [[You *are* keeping CVS under
+ CVS, right?]] The patch should be based on the latest released
+ version of CVS. Then use the "cvsbug" program (provided with the
+ CVS sources) to send it to the CVS maintainers. A self-contained
+ patch that provides a single useful feature or correction might
+ show up independently in the patches directory of the FTP archive.
+
+ If careful testing reveals an RCS bug rather than a CVS bug, you
+ can send bug reports to: rcs-bugs@cs.purdue.edu
+
+
+ 5C.3 Where do I send ideas for future development?
+
+ If you have a bright idea, discuss it on the info-cvs mailing
+ list. If you have the time to implement something you can test,
+ send the diffs along too as described above.
+
+
+=5C.4 What plans are there for new features?
+
+ A "rename" or "per-directory" database has been bandied about on
+ the net for years. It is needed, but it is a lot of work.
+
+ CVS version 1.5 supports remote repository access, but Paul
+ F. Kunz <Paul_Kunz@slac.stanford.edu> has produced another version
+ (rCVS) that also runs remotely. It is available for testing.
+
+ On the host "preprint.slac.stanford.edu", you can find:
+ Paper: slacpubs/5000/slac-pub-5923.ps.Z
+
+ This was for a conference in Sept, 1993, before first beta.
+
+ On the host "ftp.slac.stanford.edu", you can find:
+ Sources: pub/sources/rcvs-0.8.1.tar.Z
+
+ With the caveat that until version 1.0 is available, rCVS should
+ be considered an unreliable Beta release, you are invited to
+ grab a copy and test it.
+
+
+ [[Others?]]
+
+
+ 5C.5 I have some time and I'd like to help. What can I do for you?
+
+ You can review this document, correct errors and fill in any of
+ the incomplete sections.
+
+ You can add to the contrib area, which contains useful ways to use
+ some of the programmable CVS facilities (loginfo, commitinfo) or
+ ways of connecting to work environments (pcl-cvs).
+
+ You could write a regression test suite. Or at least a scaffold
+ into which we can drop tests.
+
+ You can write specs for new features, fix bugs, review the man
+ page or . . .
+
+ [[Brian?]]
+
+ [[Is there some way we can register someone as working
+ on something or should we just stay in the "implement it and
+ send it to me" mode?]]
+
+----------------
+-- Section 5D -- Professional Support
+----------------
+
+
+ **** Questions:
+
++5D.1 Doesn't Cygnus support CVS?
++5D.2 What is Cyclic Software doing with CVS?
+
+
+ **** Answers:
+
++5D.1 Doesn't Cygnus support CVS?
+
+ Cygnus is a company that supports a variety of FSF software. It
+ uses a version of CVS and people from Cygnus are on the info-cvs
+ mailing list.
+
+ [[Could someone from Cygnus state Cygnus's official and unofficial
+ relationship with CVS?]]
+
+
++5D.2 What is Cyclic Software doing with CVS?
+
+ Cyclic Software exists to provide support for CVS. Here's a copy
+ of their product line sheet:
+
+
+ Cyclic Software
+ Standard Support
+
+ Cyclic Software offers support contracts for CVS. This
+ includes:
+
+ * Full source, binaries, and documentation for CVS, RCS, GNU
+ diffutils, patch, and gzip -- that is, CVS and everything it
+ wants to run -- via FTP or tape;
+
+ * guaranteed responses for bugs within 5 business days;
+
+ * guaranteed fixes for reproducible bugs within 10 business days.
+
+ (By "reproducible bugs", we mean instances where the software
+ clearly does not behave as documentation or reasonable
+ expectations indicate it should, and that we are able to
+ reproduce this misbehavior reliably. Naturally, we will make
+ every possible effort to reproduce the bugs you report; our
+ experience has been that it's usually not difficult.)
+
+ We charge a fixed fee for:
+
+ * one year
+
+ * one host type (hardware & operating system)
+
+ * twenty users at your site, with two of those users designated
+ as "contacts" for CVS, to reduce communication problems.
+
+ If the host type is not one we have access to for testing
+ purposes, you can either lend us a machine of the appropriate type
+ for the duration of the contract, or pay an additional fee
+ up-front. We have access to Solaris, Irix, HP-UX, Linux and
+ Ultrix. (This list is subject to change; contact us for details.)
+
+ If the above fee structure is not well-suited to your
+ organization, please say so. We're interested in tailoring our
+ services to be as useful to you as possible.
+
+ Training
+
+ We offer on-site training in the use of CVS at a daily rate,
+ plus expenses (inc. travel, accommodations). The classes target
+ new and intermediate users of CVS; we feel advanced users benefit
+ more from a written manual and the source code.
+
+ Custom Enhancements
+
+ We will implement enhancements to CVS or its documentation, and
+ port CVS to new architectures. Our rates for this work depend on
+ the amount of work to be done.
+
+ We strongly prefer to work on enhancements suitable for
+ incorporation into the general CVS release upon completion; we
+ will help you design the enhancement in a way that makes this
+ possible.
+
+ Short-Term Consulting
+
+ We will do short-term consulting at hourly rates. These rates
+ are calculated to include the overhead of dealing in short time
+ periods. Therefore, in sufficiently large projects, we recommend
+ arranging a long-term support contract instead of dealing on an
+ hourly basis.
+
+ Anything Else
+
+ Cyclic Software is interested in arranging contracts for work
+ in other areas, to be produced as free software. Everything is
+ negotiable.
+
+ How To Contact Us
+
+ (Email is preferred.)
+
+ Email: <info@cyclic.com>
+ Phone: +1 812 335 9023
+ Web: http://www.cyclic.com
+ SnailMail: Cyclic Software
+ P.O. Box 804
+ Bloomington, IN 47402-0804
+ USA
+
+ Contributed by Jim Blandy
+
+
+
+=================================================
+== Section 6 ==== Table of Contents ====
+=================================================
+
+===========================================================================
+== Frequently Asked Questions about CVS (The Concurrent Versions System) ==
+===========================================================================
+
+============================================
+== Section 0 ==== Introduction ====
+============================================
+
+Questions are divided into five numbered Sections. Sections are divided
+into lettered sub-sections. The questions are numbered sequentially
+within each sub-section, though they are in no particular order.
+
+ 1. What is CVS?
+ A. What is CVS? What's it for? Why CVS?
+ B. Where do I find it? Where can I find Help?
+ C. How does CVS differ from other similar software?
+ D. What do you mean by . . .? (Definitions)
+
+ 2. User Tasks
+ A. Getting Started
+ B. Common User Tasks
+ C. Less Common User Tasks
+ D. General Questions
+
+ 3. Commands
+ A. through P. One section for each CVS command.
+
+ 4. Advanced Topics
+ A. Installing CVS
+ B. Setting up and Managing the Repository
+ C. Branching and Merging
+ D. Tricks of the Trade
+ E. Internal errors
+ F. Related Software
+ G. Engineering
+ H. Other Systems
+
+ 5. Past & Future
+ A. Contributors.
+ B. Bugs and Patches
+ C. Development
+ D. Professional Support
+
+ 6. Table of Contents
+
+
+
+============================================
+== Section 1 ==== What is CVS? ====
+============================================
+
+----------------
+-- Section 1A -- What is CVS? What's it for? Why CVS?
+----------------
+ 1A.1 What does CVS stand for? Can you describe it in one sentence?
+ 1A.2 What is CVS for? What does it do for me?
+ 1A.3 How does CVS work?
+ 1A.4 What is CVS useful for?
+ 1A.5 What is CVS *not* useful for?
+
+----------------
+-- Section 1B -- Where do I find CVS? Where can I find Help?
+----------------
+ 1B.1 How do I get more information about CVS?
+ 1B.2 Is there an archive of CVS material?
+ 1B.3 How do I get files out of the archive if I don't have FTP?
+ 1B.4 How do I get a copy of the latest version of CVS?
+ 1B.5 Is there a mailing list devoted to CVS? How do I find it?
+ 1B.6 What happened to the CVS Usenet newsgroup I heard about?
+
+----------------
+-- Section 1C -- How does CVS differ from other, similar software?
+----------------
+ 1C.1 How does CVS differ from RCS?
+ 1C.2 How does CVS differ from SCCS?
+ 1C.3 How does CVS differ from ClearCase?
+#1C.4 How does CVS differ from TeamWare/SparcWorks?
+ 1C.5 How does CVS differ from Aegis?
+ 1C.6 How does CVS differ from Shapetools?
+ 1C.7 How does CVS differ from TeamNet?
+ 1C.8 How does CVS differ from ProFrame?
+ 1C.9 How does CVS differ from CaseWare/CM?
+ 1C.10 How does CVS differ from Sublime?
+ 1C.11 How does CVS differ from PVCS?
+ 1C.12 How does CVS differ from CMVC?
+
+----------------
+-- Section 1D -- What do you mean by . . .? (Definitions)
+----------------
+ 1D.1 What are "The Repository", "$CVSROOT" and "CVSROOT"?
+ 1D.2 What is an RCS file?
+ 1D.3 What is a working file?
+ 1D.4 What is a working directory (or working area)?
+ 1D.5 What is "checking out"?
+ 1D.6 What is a revision?
+ 1D.7 What is a "Tag"?
+ 1D.8 What are "HEAD" and "BASE"?
+ 1D.9 What is a Branch?
+ 1D.10 What is "the trunk"?
+ 1D.11 What is a module?
+ 1D.12 What does "merge" mean?
+
+
+==========================================
+== Section 2 ==== User Tasks ====
+==========================================
+
+----------------
+-- Section 2A -- Getting Started
+----------------
+ 2A.1 What is the first thing I have to know?
+ 2A.2 Where do I work?
+ 2A.3 What does CVS use from my environment?
+ 2A.4 OK, I've been told that CVS is set up, my module is named
+ "ralph" and I have to start editing. What do I type?
+ 2A.5 I have been using RCS for a while. Can I convert to CVS without
+ losing my revision history? How about converting from SCCS?
+
+----------------
+-- Section 2B -- Common User Tasks
+----------------
+ 2B.1 What is the absolute minimum I have to do to edit a file?
+ 2B.2 If I edit multiple files, must I type "commit" for each one?
+ 2B.3 How do I get rid of the <module> directory that "checkout" created?
+ 2B.4 How do I find out what has changed since my last update?
+ 2B.5 I just created a new file. How do I add it to the Repository?
+ 2B.6 How do I merge changes made by others into my working directory?
+ 2B.7 How do I label a set of revisions so I can retrieve them later?
+ 2B.8 How do I checkout an old release of a module, directory or file?
+ 2B.9 What do I have to remember to do periodically?
+
+----------------
+-- Section 2C -- Less Common User Tasks
+----------------
+ 2C.1 Can I create non-CVS sub-directories in my working directory?
+ 2C.2 How do I add new sub-directories to the Repository?
+ 2C.3 How do I remove a file I don't need?
+ 2C.4 How do I rename a file?
+ 2C.5 How do I make sure that all the files and directories in my
+ working directory are really in the Repository?
+ 2C.6 How do I create a branch?
+ 2C.7 How do I modify the modules file? How about the other files in
+ the CVSROOT administrative area?
+ 2C.8 How do I split a file into pieces, retaining revision histories?
+
+----------------
+-- Section 2D -- General Questions
+----------------
+ 2D.1 How do I see what CVS is trying to do?
+ 2D.2 If I work with multiple modules, should I check them all out and
+ commit them occasionally? Is it OK to leave modules checked out?
+ 2D.3 What is a "sticky" tag? What makes it sticky? How do I loosen it?
+ 2D.4 How do I get an old revision without updating the "sticky tag"?
+ 2D.5 What operations disregard sticky tags?
+ 2D.6 Is there a way to avoid reverting my Emacs buffer after
+ committing a file? Is there a "cvs-mode" for Emacs?
+ 2D.7 How does conflict resolution work? What *really* happens if two
+ of us change the same file?
+ 2D.8 How can I tell who has a module checked out?
+ 2D.9 Where did the .#<file>.1.3 file in my working directory come from?
+ 2D.10 What is this "ignore" business? What is it ignoring?
+ 2D.11 Is there a way to set user-specific configuration options?
+ 2D.12 Is it safe to interrupt CVS using Control-C?
+ 2D.13 How do I turn off the "admin" command?
+ 2D.14 How do I turn off the ability to disable history via "cvs -l"?
+ 2D.15 How do I keep certain people from accessing certain directories?
+
+
+========================================
+== Section 3 ==== Commands ====
+========================================
+
+----------------
+-- Section 3A -- "add", "ad", "new"
+----------------
+ 3A.1 What is "add" for?
+ 3A.2 How do I add a new file to the branch I'm working on?
+ 3A.3 Why did my new file end up in the Attic?
+ 3A.4 Now that it's in the Attic, how do I connect it to the Main branch?
+ 3A.5 How do I avoid the hassle of reconnecting an Attic-only file to
+ the Main Branch?
+ 3A.6 How do I cancel an "add"?
+ 3A.7 What are the ./CVS/file,p and ./CVS/file,t files for?
+ 3A.8 How do I "add" a binary file?
+
+----------------
+-- Section 3B -- "admin", "adm", "rcs"
+----------------
+ 3B.1 What is "admin" for?
+ 3B.2 Wow! Isn't that dangerous?
+ 3B.3 What would I normally use "admin" for?
+ 3B.4 What should I avoid when using "admin"?
+ 3B.5 How do I restrict the "admin" command? The -i flag in the modules
+ file can restrict commits. What's the equivalent for "admin"?
+ 3B.6 I backed out a revision with "admin -o" and committed a
+ replacement. Why doesn't "update" retrieve the new revision?
+
+----------------
+-- Section 3C -- "checkout", "co", "get"
+----------------
+ 3C.1 What is "checkout" for?
+ 3C.2 What is the "module" that "checkout" takes on the command line?
+ 3C.3 Isn't a CVS "checkout" just a bunch of RCS checkouts?
+ 3C.4 What's the difference between "update" and "checkout"?
+ 3C.5 Why can't I check out a file from within my working directory?
+ 3C.6 How do I avoid dealing with those long relative pathnames?
+ 3C.7 Can I move a checked-out directory? Does CVS remember where it
+ was checked out?
+ 3C.8 How can I lock files while I'm working on them the way RCS does?
+ 3C.9 What is "checkout -s"? How is it different from "checkout -c"?
+
+----------------
+-- Section 3D -- "commit", "ci", "com"
+----------------
+ 3D.1 What is "commit" for?
+ 3D.2 If I edit ten files, do I have to type "commit" ten times?
+ 3D.3 Explain: cvs commit: Up-to-date check failed for `<file>'
+ 3D.4 What happens if two people try to "commit" conflicting changes?
+ 3D.5 I committed something and I don't like it. How do I remove it?
+ 3D.6 Explain: cvs commit: sticky tag `V3' for file `X' is not a branch
+ 3D.7 Why does "commit -r <tag/rev>" put newly added files in the Attic?
+ 3D.8 Why would a "commit" of a newly added file not produce rev 1.1?
+
+----------------
+-- Section 3E -- "diff", "di", "dif"
+----------------
+ 3E.1 What is "diff" for?
+ 3E.2 Why did "diff" display nothing when I know there are later
+ committed revisions in the Repository?
+ 3E.3 How do I display what changed in the Repository since I last
+ executed "checkout", "update" or "commit"?
+ 3E.4 How do I display the difference between my working file and what
+ I checked in last Thursday?
+ 3E.5 Why can't I pass long options, like --unified, to "diff"?
+
+----------------
+-- Section 3F -- "export", "exp", "ex"
+----------------
+ 3F.1 What is "export" for?
+ 3F.2 Why does it remove the RCS keywords so I can't use the "ident"
+ command on the source files?
+ 3F.3 Can I override the '-kv' flag CVS passes to RCS?
+ 3F.4 Why doesn't "export" have a '-k' flag like "import" does?
+ 3F.5 Why does "export -D" check out every file in the Attic?
+
+----------------
+-- Section 3G -- "history", "hi", "his"
+----------------
+ 3G.1 What is "history" for?
+ 3G.2 Of what use is it?
+ 3G.3 What is this, Big Brother?
+ 3G.4 I deleted my working directory and "history" still says I have
+ it checked out. How do I fix it?
+ 3G.5 So I *can* edit the History file?
+ 3G.6 Why does the history file grow so quickly?
+ 3G.7 What is the difference between "cvs history -r <tag/rev>" and
+ "cvs history -t <tag>"?
+ 3G.8 Why does "cvs history -c -t <tag>" fail to print anything?
+ 3G.9 "cvs history -a -o" only printed one line for each checked-out
+ module. Shouldn't it print all the directories where the
+ modules are checked out?
+ 3G.10 I can't figure out "history", can you give me concrete examples?
+ 3G.11 Can we merge history files when we merge Repositories?
+
+----------------
+-- Section 3H -- "import", "im", "imp"
+----------------
+ 3H.1 What is "import" for?
+ 3H.2 How am I supposed to use "import"?
+ 3H.3 Why does import put files on a branch? Why can't I work on the
+ main trunk instead of a Vendor branch?
+ 3H.4 Is there any way to import binary files?
+ 3H.5 Why does "import" corrupt some binary files?
+ 3H.6 How do I retain the original $\Revision$ strings in the sources?
+=3H.7 I imported some files for the Yarg compiler that compiles files
+ with a suffix of ".yarg" and whose comment prefix is "YARG> ".
+ When I check them out, they will no longer compile because they
+ have this junk in them. Why?
+ 3H.8 How do I make "import" save the timestamps on the original files?
+ 3H.9 Why can't I "import" 3 releases on different branches?
+ 3H.10 What do I do if the Vendor adds or deletes files between releases?
+ 3H.11 What about if the Vendor changes the names of files or
+ directories, or rearranges the whole structure between releases?
+ 3H.12 I thought "import" was for Vendor releases, why would I use it
+ for code of my own? Do I have to use import?
+ 3H.13 How do I import a large Vendor release?
+ 3H.14 Explain: ERROR: cannot create link to <file>: Permission denied
+ 3H.15 Where does the -m <message> go when the file doesn't change?
+ 3H.16 How do I "import" just the files ignored by a previous "import"?
+ 3H.17 Why did "import" ignore all the symlinks?
+
+----------------
+-- Section 3I -- "log", "lo", "rlog"
+----------------
+ 3I.1 What is "log" for?
+ 3I.2 How do I extract the log entries between two revisions?
+ 3I.3 How do I extract the log entries on a whole branch?
+ 3I.4 How do I generate ChangeLogs from RCS logs?
+ 3I.5 Why does "log" tell me a file was committed exactly 5 hours later
+ than I know it was?
+
+----------------
+-- Section 3J -- "patch", "pa", "rdiff"
+----------------
+ 3J.1 What is "patch" for?
+ 3J.2 Why does "patch" include files from the Attic when I use '-D'?
+ 3J.3 How do I make "patch" produce a patch for one or two files?
+ It seems to work only with modules.
+
+----------------
+-- Section 3K -- "release", "re", "rel"
+----------------
+ 3K.1 What is "release" for?
+ 3K.2 Why can't I reverse a "cvs checkout path/name/subdir" with a
+ "cvs release path/name/subdir" without an "unknown module name"?
+ 3K.3 Why can't I "release" portions of a checked out directory? I
+ should be able to "release" any file or sub-directory within
+ my working directory.
+ 3K.4 I removed the tree that I was about to start working on. How do I
+ tell cvs that I want to release it if I don't have it anymore?
+ 3K.5 Why doesn't "release -d module" reverse a "checkout module"?
+ 3K.6 Why can't I release a module renamed with "cvs checkout -d"?
+
+----------------
+-- Section 3L -- "remove", "rm", "delete"
+----------------
+ 3L.1 What is "remove" for?
+ 3L.2 Why doesn't "remove" work on directories when it appears to try?
+ 3L.3 I don't like removing files. Is there another way to ignore them?
+ 3L.4 I just removed a file. How do I resurrect it?
+ 3L.5 Why doesn't "remove" delete the file? Instead, it prints an
+ error message and tells me to remove the file by hand.
+
+----------------
+-- Section 3M -- "rtag", "rt", "rfreeze"
+----------------
+ 3M.1 What is "rtag" for?
+ 3M.2 Why use "rtag"? It assumes no one is changing the Repository.
+ 3M.3 What revision does "rtag -r <tag1> <tag2>" actually put the tag on?
+ 3M.4 What happens if the tags are the same in "rtag -r <tag> <tag>"?
+ 3M.5 Why doesn't "rtag -b -r <branch_tag1> <branch_tag2>" rename or
+ duplicate a magic branch tag?
+
+----------------
+-- Section 3N -- "status", "st", "stat"
+----------------
+ 3N.1 What is "status" for?
+ 3N.2 Why does "status" limit the File: at the top to 17 characters?
+ 3N.3 Why does it print "Sticky" lines when the values are "(none)"?
+ 3N.4 Shouldn't the status "Needs Checkout" be "Needs Update"?
+
+----------------
+-- Section 3O -- "tag", "ta", "freeze"
+----------------
+ 3O.1 What is "tag" for?
+ 3O.2 What is the difference between "tag" and "rtag"?
+ 3O.3 Why does "tag -b" not put a tag on the Branch Point revision?
+ How do I refer to the Branch Point?
+ 3O.4 So "{r}tag" labels a bunch of files. What do you use a Tag for?
+ 3O.5 How do I get "tag" and "rtag" to send mail the way "commit" does?
+ 3O.6 Why can't "tag" handle the '-r' option that "rtag" takes?
+ 3O.7 After a "tag <tag>" in my working directory, why doesn't "checkout
+ -r <tag>" somewhere else produce copies of my current files?
+ 3O.8 Why doesn't "tag" write a history record the way "rtag" does?
+ 3O.9 How do I rename a <tag>?
+
+----------------
+-- Section 3P -- "update", "up", "upd"
+----------------
+ 3P.1 What is "update" for?
+ 3P.2 What do 'U', 'M' and 'C' mean when I type "update"? Are they
+ different for "cvs -n update"?
+ 3P.3 What's the difference between "update" and "checkout"?
+ 3P.4 Why don't I get new files when I execute "update"?
+ 3P.5 Why does "update" say 'M' both for plain modified files and for
+ successful (i.e. conflict-free) merges? Aren't they different?
+ 3P.6 What's a "sticky conflict"? How does it know a conflict occurred?
+ 3P.7 Is there a feature to tell me what I have changed, added and
+ removed without changing anything?
+ 3P.8 Why were all my files deleted when I executed "update"?
+
+
+===============================================
+== Section 4 ==== Advanced Topics ====
+===============================================
+
+----------------
+-- Section 4A -- Installing CVS
+----------------
+ 4A.1 What do I have to do before I install CVS?
+ 4A.2 How do I configure the CVS programs?
+ 4A.3 What do I have to install?
+ 4A.4 How do I work around the merge problems in GNU diff version 2.1
+ or later?
+
+----------------
+-- Section 4B -- Setting up and Managing the Repository
+----------------
+ 4B.1 What do I do first? How do I create a Repository?
+ 4B.2 What are those files in $CVSROOT/CVSROOT?
+ 4B.3 Is there any other state stored in the Repository besides in the
+ $CVSROOT/CVSROOT directory?
+ 4B.4 How do I put sources into the Repository?
+ 4B.5 What file permissions should I use on (and in) the Repository?
+ 4B.6 How do I structure my Repository?
+ 4B.7 Why would anyone use "modules"? They are too restrictive. I
+ want to be able to select just the files I want to edit.
+ 4B.8 How do I rename a file or directory? What are the consequences?
+ 4B.9 What are "Attic" directories?
+ 4B.10 Is it OK to remove anything from the Repository?
+ 4B.11 Can I convert to CVS from RCS without losing my revision history?
+ 4B.12 Can I move RCS files with branches in them into the Repository?
+ 4B.13 Can I use raw RCS commands on the Repository?
+ 4B.14 How do I convert from SCCS to RCS?
+ 4B.15 How do I limit access to the Repository?
+ 4B.16 What are the Repository Administrator's responsibilities?
+ 4B.17 How do I move the whole Repository?
+ 4B.18 How do I change permissions on a file in the Repository by using
+ a CVS command? (i.e. without using "chmod 777 $CVSROOT/dir/file")
+
+----------------
+-- Section 4C -- Branching and Merging
+----------------
+ 4C.1 What is a branch?
+ 4C.2 Why (or when) would I want to create a branch?
+ 4C.3 How do I create and checkout a branch?
+ 4C.4 Once created, how do I manage a branch?
+ 4C.5 Are there any extra issues in managing multiple branches?
+ 4C.6 How do I merge a whole branch back into the trunk?
+=4C.7 How do I merge changes from the trunk into my branch or between
+ branches?
+ 4C.8 How do I merge onto the Main Branch a file that exists only on a
+ branch other than the Main Branch? (i.e. it is in the Attic)
+ 4C.9 How do I know what branch I'm (working) on?
+ 4C.10 Do I really have to know the name of the branch I'm working on?
+ 4C.11 How do I refer to the revision where I branched so I can see
+ what changed since the Branch Point on another branch?
+ 4C.12 Why didn't the command "cvs admin -bBRANCH1 *" create a branch?
+ 4C.13 Is it possible to set the "default CVS branch" for everyone?
+ 4C.14 How do I perform a large merge?
+ 4C.15 Is a Vendor merge any different from a branch merge?
+ 4C.16 How do I go back to a previous version of the code on a branch?
+ 4C.17 Once I've found the files I want, how do I start changing them?
+ I keep getting warnings about sticky tags.
+ 4C.18 Why do I get the latest files on the branch when I tried to
+ "update -r <tag>"?
+ 4C.19 How can I avoid a merge? I just want to move the latest revision
+ on my working branch directly onto the trunk.
+ 4C.20 How to I avoid merge collisions in the RCS $\Log$ data?
+ 4C.21 Why should I trust automatic merges?
+ 4C.22 How does CVS decide if it can safely perform a merge?
+ 4C.23 After resolving merge conflicts in a file, what if I want to keep
+ my previous version, and not take any of the branch changes?
+
+----------------
+-- Section 4D -- Tricks of the Trade
+----------------
+ 4D.1 How can you even check in binary files, let alone allow CVS to
+ do its auto-merge trick on them?
+ 4D.2 Can I edit the RCS (",v") files in the Repository?
+ 4D.3 Can I edit the ./CVS/{Entries,Repository,Tag} files?
+ 4D.4 Someone executed "admin -o" and removed revisions to which
+ tags/symbols were attached. How do I fix them?
+ 4D.5 How do I move or rename a magic branch tag?
+ 4D.6 Can I use RCS locally to record my changes without making them
+ globally visible by committing them?
+ 4D.7 How can I allow access to the Repository by both CVS and RCS?
+ 4D.8 I "updated" a file my friend, "bubba", committed yesterday.
+ Why doesn't the file now have a modified date of yesterday?
+ 4D.9 While in the middle of a large "commit", how do I run other
+ commands, like "diff" or "stat" without seeing lock errors?
+ 4D.10 Where did the ./CVS/Entries.Static file come from? What is it for?
+ 4D.11 Why did I get the wrong Repository in the loginfo message?
+ 4D.12 How do I run CVS setuid so I can only allow access through the
+ CVS program itself?
+ 4D.13 How about using groups and setgid() then?
+ 4D.14 How do I use the "commitinfo" file?
+ 4D.15 How do I use the "loginfo" files?
+ 4D.16 How can I keep people with restrictive umask values from blocking
+ access to the Repository?
+ 4D.17 Why do timestamps sometimes get set to the date of the revision,
+ sometimes not? The inconsistency causes unnecessary recompiles.
+
+----------------
+-- Section 4E -- Internal errors
+----------------
+ 4E.1 Explain: "ci error: unexpected EOF in diff output"
+ 4E.2 Explain: "RCS file /Repository/module/file.c,v is in use"
+ 4E.3 Explain: "co error, line 2: Missing access list"
+ 4E.4 Explain: "error: RCS file name `xyz .c' contains white space"
+ 4E.5 Explain: cvs checkout: warning: <X> is not (any longer) pertinent
+ 4E.6 Why did a Repository file change from <file>,v to ,<file>,?
+
+----------------
+-- Section 4F -- Related Software
+----------------
+ 4F.1 How do I use CVS under Emacs? Is there an Emacs cvs-mode?
+ 4F.2 What is GIC (Graphical Interface to CVS)?
+ 4F.3 What is CAVEMAN?
+
+----------------
+-- Section 4G -- Engineering
+----------------
+ 4G.1 Where can I find out about Software Engineering?
+ 4G.2 How do I flexibly arrange the modules file to describe my sources?
+ 4G.3 Can I have multiple source repositories, one for each project?
+ 4G.4 Who should administer the Repository and manage the modules file?
+ 4G.5 Isn't disk space a big factor? CVS copies files out of the
+ Repository, duplicating everything.
+
+----------------
+-- Section 4H -- Other Systems
+----------------
+ 4H.1 I use a NeXT. Is there anything I need to know?
+ 4H.2 I use OS/2 and/or DOS. Is there anything I need to know?
+ 4H.3 I use SCO Unix. Is there anything I need to know?
+ 4H.4 I use AIX. Is there anything I need to know?
+ 4H.5 I use IRIX. Is there anything I need to know?
+ 4H.6 I use an HP system. Is there anything I need to know?
+ 4H.7 I use AFS. Is there anything I need to know?
+ 4H.8 I use A/UX. Is there anything I need to know?
+
+
+=============================================
+== Section 5 ==== Past & Future ====
+=============================================
+
+----------------
+-- Section 5A -- Contributors
+----------------
+=5A.1 Who wrote CVS?
+ 5A.2 You didn't write all of this FAQ, did you?
+
+----------------
+-- Section 5B -- Bugs and Patches
+----------------
+ 5B.1 Why can't CVS handle deletion of directories?
+ 5B.2 Why can't CVS handle the moving of sources from one place in the
+ directory hierarchy to another?
+ 5B.3 When I typed "cvs update -D <date>", why did it check out all
+ sorts of ancient files from the Attic? Shouldn't it just create
+ the set of files and revisions that existed at that date?
+ 5B.4 When I typed "cvs update -D <date>" in my branch, why did it
+ screw up all my files?
+ 5B.5 When I executed "checkout" into an existing directory I got "No
+ such file or directory" errors. Why?
+ 5B.6 Why does "update" send all output to the terminal after 26 files
+ have been updated?
+ 5B.7 Why does the merge occasionally resurrect lines of code?
+ 5B.8 Why does the merge fail when my "rcsmerge" program is
+ configured to use GNU diff version 2.1 or later?
+
+----------------
+-- Section 5C -- Development
+----------------
+ 5C.1 Where do I send bug reports?
+ 5C.2 Where do I send fixes and patches?
+ 5C.3 Where do I send ideas for future development?
+=5C.4 What plans are there for new features?
+ 5C.5 I have some time and I'd like to help. What can I do for you?
+
+----------------
+-- Section 5D -- Professional Support
+----------------
++5D.1 Doesn't Cygnus support CVS?
++5D.2 What is Cyclic Software doing with CVS?
+
+
+=================================================
+== Section 6 ==== Table of Contents ====
+=================================================
+
+% End of Table of Contents
+% End of CVS FAQ document
+
+# Local Variables:
+# mode: text
+# fill-column: 74
+# fill-prefix: "\t"
+# End:
diff --git a/gnu/usr.bin/cvs/INSTALL b/gnu/usr.bin/cvs/INSTALL
new file mode 100644
index 0000000..898af66
--- /dev/null
+++ b/gnu/usr.bin/cvs/INSTALL
@@ -0,0 +1,356 @@
+#ident "$CVSid$"
+
+First, read the README file. If you're still happy...
+
+CVS has been tested on the following platforms. The most recent
+version of CVS reported to have been tested is indicated, but more
+recent versions of CVS probably will work too. Please send updates to
+this list to info-cvs@prep.ai.mit.edu.
+
+Alpha:
+ DEC Alpha running OSF/1 version 1.3 using cc (about 1.4A2)
+ DEC Alpha running OSF/1 version 2.0 (1.4.90)
+ DEC Alpha running OSF/1 version 2.1 (about 1.4A2)
+ DEC Alpha running OSF/1 version 3.0 (1.5.95) (footnote 7)
+HPPA:
+ HP 9000/710 running HP-UX 8.07A using gcc (about 1.4A2)
+ HP 9000/715 running HP-UX 9.01 (1.6)
+ HPPA 1.1 running HP-UX A.09.03 (1.5.95) (footnote 8)
+ NextSTEP 3.3 (1.4.92, a few tweaks needed)
+i386 family:
+ Gateway P5-66 (pentium) running Solaris 2.4 using gcc (about 1.4A2)
+ PC Clone running UnixWare v1.1.1 using gcc (about 1.4A2)
+ PC Clone running ISC 4.0.1 (1.5.94)
+ PC Clone running Fintronic Linux 1.2.5 (1.5)
+ PC Clone running BSDI 2.0 (1.4.93) (footnote 5)
+ PC Clone running Windows NT 3.51 (1.6.2 client-only)
+ FreeBSD 2.0.5, i486, gcc (1.5.95)
+ NextSTEP 3.3 (1.4.92, a few tweaks needed)
+ SCO Unix 3.2.4.2 (1.4.93) (footnote 4)
+ SCO OpenServer 5.0.0, "CC='cc -b elf' configure"
+m68k:
+ Sun 3 running SunOS 4.1.1_U1 w/ bundled K&R /usr/5bin/cc (1.6)
+ NextSTEP 3.3 (1.4.92, a few tweaks needed)
+m88k:
+ Data General AViiON running dgux 5.4R2.10 (1.5)
+ Harris Nighthawk 5800 running CX/UX 7.1 (1.5) (footnote 6)
+MIPS:
+ DECstation running Ultrix 4.2a (1.4.90)
+ DECstation running Ultrix 4.3 (1.5)
+ SGI running Irix 4.0.5H using gcc and cc (about 1.4A2) (footnote 2)
+ SGI running Irix 5.3 (1.4.93)
+ SGI running Irix-6 (about 1.4.90) (footnote 3)
+ Siemens-Nixdorf RM600 running SINIX-Y (1.6)
+PowerPC or RS/6000:
+ IBM RS/6000 running AIX 3.2.5 (cc=xlc, CVS 1.5)
+ IBM RS/6000 running AIX 4.1 using gcc and cc (about 1.4A2) (footnote 1)
+SPARC:
+ Sun SPARC running SunOS 4.1.4 w/ bundled K&R /usr/5bin/cc (1.6)
+ Sun SPARC running SunOS 4.1.3, 4.1.2, and 4.1.1 (1.5)
+ Sun SPARC running SunOS 4.1.3, w/ bundled K&R cc (1.5.94)
+ Sun SPARCstation 10 running Solaris 2.3 using gcc and cc (about 1.4A2)
+ Sun SPARCstation running Solaris 2.4 using gcc and cc (about 1.5.91)
+ Sun SPARC running Solaris 2.5 (2.5 beta?) (1.6.2)
+ NextSTEP 3.3 (1.4.92, a few tweaks needed)
+
+(footnote 1)
+ AIX 4.1 systems fail to run "configure" due to bugs in their
+ "/bin/sh" implementation. You might want to try feeding the
+ configure script to "bash" ported to AIX 4.1. (about 1.4A2).
+
+(footnote 2)
+ Some Irix 4.0 systems may core dump in malloc while running
+ CVS. We believe this is a bug in the Irix malloc. You can
+ workaround this bug by linking with "-lmalloc" if necessary.
+ (about 1.4A2).
+
+(footnote 3)
+ There are some warnings about pointer casts which can safely be
+ ignored. (about 1.4.90).
+
+(footnote 4) Comment out the include of sys/time.h in src/server.c. (1.4.93)
+ You also may have to make sure TIME_WITH_SYS_TIME is undef'ed.
+
+(footnote 5) Change /usr/tmp to /var/tmp in src/server.c (2 places) (1.4.93).
+
+(footnote 6) Build in ucb universe with COFF compiler tools. Put
+ /usr/local/bin first in PATH while doing a configure, make
+ and install of GNU diffutils-2.7, rcs-5.7, then cvs-1.5.
+
+(footnote 7) Manoj Srivastava <srivasta@pilgrim.umass.edu> reports
+ success with this configure command:
+ CC=cc CFLAGS='-O2 -Olimit 2000 -std1' ./configure --verbose alpha-dec-osf
+
+(footnote 8) Manoj Srivastava <srivasta@pilgrim.umass.edu> reports
+ success with this configure command:
+ CC=cc CFLAGS='+O2 -Aa -D_HPUX_SOURCE' ./configure --verbose hppa1.1-hp-hpux
+
+-------------------------------------------------------------------------------
+
+Installation under Unix:
+
+1) Run "configure":
+
+ $ ./configure
+
+ You can specify an alternate destination to override the default with
+ the --prefix option:
+
+ $ ./configure --prefix=/usr/local/gnu
+
+ or some path that is more appropriate for your site. The default prefix
+ value is "/usr/local", with binaries in sub-directory "bin", manual
+ pages in sub-directory "man", and libraries in sub-directory "lib".
+
+ This release of CVS also requires RCS commands to be installed in
+ the user's PATH (or a path you have configured in src/options.h).
+ If you don't have RCS, you will need to get it from GNU as well. It
+ is best to get the version 5.7 (or later) version of RCS, available
+ from prep.ai.mit.edu in the file pub/gnu/rcs-5.7.tar.gz. It is best
+ (although not essential) to avoid RCS versions 5.6.[5-7] beta
+ because the rcsmerge therein defaults to -A instead of -E which
+ affects the way CVS handles conflicts (this is fixed in RCS 5.6.8
+ and RCS 5.7).
+
+ Along with RCS, you will want to run GNU diffutils. This will allow
+ revision control of files with binary data (a real nice feature).
+ You will need at least version 1.15 of GNU diff for this to work.
+ The current version of GNU diffutils is 2.7, and it is also
+ available from prep.ai.mit.edu in the file pub/gnu/diffutils-2.7.tar.gz.
+
+ WARNING: Be sure that you (have) configure(d) RCS to work correctly
+ with GNU diff to avoid other configuration problems.
+
+ Configure will attempt to discern the location of your most capable
+ version of diff, and tries to find the GNU Diffutils version first.
+ You can explicitly tell configure to use the diffutils that's
+ installed in the same place you intend to install CVS:
+
+ $ ./configure --with-diffutils
+
+ Or, if you've installed it somewhere else, you can give configure
+ the full pathname:
+
+ $ ./configure --with-diffutils=/usr/gnu/bin/diff
+
+ Configure will also try to find a version of grep that supports the
+ '-s' option, and tries to find the GNU Grep version first. You can
+ similarly tell it where to find GNU Grep:
+
+ $ ./configure --with-gnugrep
+ $ ./configure --with-gnugrep=/usr/gnu/bin/grep
+
+ If you are using the remote client, you will need a version of patch
+ which understands unidiffs (such as any recent version of GNU
+ patch). Configure does not yet check to see if you've got this, so
+ be careful!
+
+ NOTE: The configure program will cache the results of the previous
+ configure execution. If you need to re-run configure from scratch, you
+ may need to run "make distclean" first to remove the cached
+ configuration information.
+
+ Try './configure --help' for further information on its usage.
+
+ NOTE ON CVS's USE OF NDBM:
+
+ By default, CVS uses some built-in ndbm emulation code to allow
+ CVS to work in a heterogeneous environment. However, if you have
+ a very large modules database, this may not work well. You will
+ need to edit src/options.h to turn off the MY_NDBM #define and
+ re-run configure. If you do this, the following comments apply.
+ If not, you may safely skip these comments.
+
+ If you configure CVS to use the real ndbm(3) libraries and
+ you do not have them installed in a "normal" place, you will
+ probably want to get the GNU version of ndbm (gdbm) and install
+ that before running the CVS configure script. Be aware that the
+ GDBM 1.5 release does NOT install the <ndbm.h> header file included
+ with the release automatically. You may have to install it by hand.
+
+ If you configure CVS to use the ndbm(3) libraries, you cannot
+ compile CVS with GNU cc (gcc) on Sun-4 SPARC systems. However, gcc
+ 2.0 may have fixed this limitation if -fpcc-struct-return is
+ defined. When using gcc on other systems to compile CVS, you *may*
+ need to specify the -fpcc-struct-return option to gcc (you will
+ *know* you have to if "cvs checkout" core dumps in some ndbm
+ function). You can do this as follows:
+
+ $ CC='gcc -fpcc-struct-return' ./configure
+
+ for sh, bash, and ksh users and:
+
+ % setenv CC 'gcc -fpcc-struct-return'
+ % ./configure
+
+ for csh and tcsh users.
+
+ END OF NOTE FOR NDBM GUNK.
+
+2) Edit src/options.h. Appropriate things to look at may be the
+ invocation locations of programs like DIFF, GREP, RM, and SORT.
+ Also glance at the default values for the environment variables
+ that CVS uses, in particular, the RCSBIN variable, which holds the
+ path to where the RCS programs live on your system. The
+ likelihood is that you don't have to change anything here, except
+ perhaps adding the -a option to DIFF if you are using GNU diff.
+
+3) Try to build it:
+
+ $ make
+
+ This will (hopefully) make the needed CVS binaries within the "src"
+ directory. If something fails for your system, using the "cvsbug"
+ script submit your "config.status" file together with your host
+ type, operating system and compiler information, make output, and
+ anything else you think will be helpful.
+
+ You may also wish to validate the correctness of the new binary by
+ running the regression tests:
+
+ $ make check
+
+ Note that if your /bin/sh doesn't support shell functions, you'll
+ have to try something like this, where "/bin/sh5" is replaced by the
+ pathname of a shell which handles normal shell functions:
+
+ $ make SHELL=/bin/sh5 check
+
+ WARNING: This test can take quite a while to run, esp. if your
+ disks are slow or over-loaded.
+
+ If you receive any un-expected output from the regression tests,
+ using the "cvsbug" script please submit your "config.status" file,
+ together with your host type, operating system and compiler
+ information, the contents of /tmp/cvs-sanity/check.log, and any
+ "make check" output.
+
+4) Install the binaries/documentation:
+
+ $ make install
+
+ Depending on your installation's configuration, you may need to be
+ root to do this.
+
+5) Take a look at the CVS documentation.
+
+ $ man cvs
+
+ and
+
+ $ info cvs
+
+ See what it can do for you, and if it fits your environment (or can
+ possibly be made to fit your environment). If things look good,
+ continue on...
+
+6) Setup the master source repository. Choose a directory with ample disk
+ space available for source files. This is where the RCS ",v" files
+ will be stored. Note that this should be some shared directory for your
+ site. It should probably be auto-mounted, if you're running NFS.
+
+ Say you choose "/src/master" as the root of your source repository.
+ Run the "cvsinit" script to help you set it up. It will ask you to
+ enter the path to your CVSROOT area. You would enter /src/master in
+ this example.
+
+ $ ./cvsinit
+
+ The cvsinit script will setup a reasonable CVSROOT area to start with.
+ It is also valuable to folks who already have a CVSROOT area setup from
+ using earlier releases of CVS. It assumes that you have installed CVS
+ already (step 4) and that the RCS programs (co and ci) are in your
+ PATH. There are many ways to customize CVS for your site. Read the
+ cvs(5) manual page when you get the chance.
+
+7) Have all users of the CVS system set the CVSROOT environment
+ variable appropriately to reflect the placement of your source
+ repository. If the above example is used, the following commands
+ can be placed in user's ~/.profile, ~/.bash_profile file; or in the
+ site-wide /etc/profile:
+
+ CVSROOT=/src/master; export CVSROOT
+
+ for sh/bash/ksh users, or place the following commands in the user's
+ ~/.cshrc, ~/.login, or /etc/chsrc file:
+
+ setenv CVSROOT /src/master
+
+ for csh/tcsh users. If these environment variables are not already set
+ in your current shell, set them now (or source the login script you
+ just edited). You will need to have the CVSROOT environment variable
+ set to continue on to the next step.
+
+8) It might be a good idea to jump right in and put the CVS distribution
+ directly under CVS control. From within the top-level directory of the
+ CVS distribution (the one that contains this README file) do the
+ following commands:
+
+ $ make distclean
+ $ cvs import -m 'CVS 1.6 distribution' cvs CVS CVS-1_6
+
+9) Having done step 8, one should be able to checkout a fresh copy of the
+ CVS distribution and hack away at the sources with the following command:
+
+ $ cd
+ $ cvs checkout cvs
+
+ This will make the directory "cvs" in your current directory and
+ populate it with the appropriate CVS files and directories.
+
+10) Remember to edit the modules file manually when sources are checked in
+ with "cvs import" or "cvs add". A copy of the modules file for editing
+ can usually be retrieved with the "cvs checkout modules" command, and
+ definitely with the "cvs checkout CVSROOT" command. See cvs(5).
+
+11) Read the NEWS file to see what's new.
+
+12) Hack away.
+
+-------------------------------------------------------------------------------
+
+Detailed information about your interaction with "configure":
+
+The "configure" script and its interaction with its options and the
+environment is described here. For more detailed documentation about
+"configure", please refer to the GNU Autoconf documentation.
+
+Supported options are:
+
+ --srcdir=DIR Useful for compiling on many different
+ machines sharing one source tree.
+ --prefix=DIR The root of where to install the
+ various pieces of CVS (/usr/local).
+ --exec_prefix=DIR If you want executables in a
+ host-dependent place and shared
+ things in a host-independent place.
+ --with-diffutils[=PATH] Assume use of GNU diffutils is possible.
+ --with-gnugrep[=PATH] Assume use of GNU grep is possible.
+
+The following environment variables override configure's default
+behaviour:
+
+ CC If not set, tries to use gcc first,
+ then cc. Also tries to use "-g -O"
+ as options, backing down to -g
+ alone if that doesn't work.
+ INSTALL If not set, tries to use "install", then
+ "./install-sh" as a final choice.
+ RANLIB If not set, tries to determine if "ranlib"
+ is available, choosing "echo" if it doesn't
+ appear to be.
+ YACC If not set, tries to determine if "bison"
+ is available, choosing "yacc" if it doesn't
+ appear to be.
+
+-------------------------------------------------------------------------------
+Installation under Windows NT:
+
+You may find interesting information in windows-NT/README.
+
+1) Using Microsoft Visual C++ version 2.1, open the project `cvsnt.mak',
+ in the top directory of the CVS distribution.
+2) Choose "Build cvs.exe" from the "Project" menu.
+3) MSVC will place the executable file cvs.exe in WinDebug, or whatever
+ your target directory is.
+-------------------------------------------------------------------------------
diff --git a/gnu/usr.bin/cvs/MINOR-BUGS b/gnu/usr.bin/cvs/MINOR-BUGS
new file mode 100644
index 0000000..7b85719
--- /dev/null
+++ b/gnu/usr.bin/cvs/MINOR-BUGS
@@ -0,0 +1,60 @@
+Low-priority bugs go here. We don't have many yet -- everything is
+high-priority at the moment. :-)
+
+
+* From: Jeff Johnson <jbj@brewster.JBJ.ORG>
+ To: cyclic-cvs@cyclic.com
+ Subject: Named_Root assumes . on server
+ Date: Wed, 17 May 1995 11:04:53 -0400 (EDT)
+
+ Problem:
+ On server, Name_Root() attempts (aggressively) to set CVSADM_Root.
+ If ~/CVS/Root exists (wrto rsh login), then CVSADM_Root will be
+ initialized from that file. The sanity check between the root
+ repository and the invocation will fail if the two values are not
+ coincidentally the same.
+
+ Workaround:
+ There's a zillion ways to fix this bugture/featurelet. My current
+ workaround is to remove ~/CVS/Root on the server. I shall attempt
+ a better fix as soon as I can determine what appears politically
+ correct. IMHO, the CVS/Root stuff (and getenv("CVSROOT") also) is
+ a bit fragile and tedious in an rcmd() driven CCVS environment.
+
+
+* (Jeff Johnson <jbj@jbj.org>)
+ I tried a "cvs status -v" and received the following:
+
+ ? CVS
+ ? programs/CVS
+ ? tests/CVS
+ cvs server: Examining .
+ ===================================================================
+ File: Install.dec Status: Up-to-date
+ ...
+
+ I claim that CVS dirs should be ignored.
+
+
+* I sometimes get this message:
+
+ Could not look up address for your host. Permission denied.
+ cvs [update aborted]: premature end of file from server
+
+ The client's response should be cleaned up.
+
+* In the gb-grep module, update-ChangeLog (and therefore, I assume,
+ rcs2log) truncates file names --- I get entries for things called
+ ring/lenstring.h instead of lenstring/lenstring.h.
+
+* On remote checkout, files don't have the right time/date stamps in
+ the CVS/Entries files. Doesn't look like the C/S protocol has any
+ way to send this information along (according to cvsclient.texi).
+ Perhaps we can spiff it up a bit by using the conflict field for the
+ stamp on the checkout/update command. Please note that this really
+ doesn't do very much for us even if we get it done.
+
+* Does the function that lists the available modules in the repository
+ belong under the "checkout" function? Perhaps it is more logically
+ grouped with the "history" function or we should create a new "info"
+ function?
diff --git a/gnu/usr.bin/cvs/Makefile b/gnu/usr.bin/cvs/Makefile
new file mode 100644
index 0000000..a9b43ae
--- /dev/null
+++ b/gnu/usr.bin/cvs/Makefile
@@ -0,0 +1,5 @@
+# $Id: Makefile,v 1.6 1995/04/14 15:15:27 nate Exp $
+
+SUBDIR = lib cvs mkmodules contrib cvsbug cvsinit doc examples
+
+.include <bsd.subdir.mk>
diff --git a/gnu/usr.bin/cvs/Makefile.inc b/gnu/usr.bin/cvs/Makefile.inc
new file mode 100644
index 0000000..9c26b86
--- /dev/null
+++ b/gnu/usr.bin/cvs/Makefile.inc
@@ -0,0 +1,8 @@
+.if exists(${.CURDIR}/../lib/obj)
+LIBDESTDIR= ${.CURDIR}/../lib/obj
+.else
+LIBDESTDIR= ${.CURDIR}/../lib
+.endif
+
+LDDESTDIR= -L${LIBDESTDIR}
+LIBCVS= ${LIBDESTDIR}/libcvs.a
diff --git a/gnu/usr.bin/cvs/NEWS b/gnu/usr.bin/cvs/NEWS
new file mode 100644
index 0000000..8965819
--- /dev/null
+++ b/gnu/usr.bin/cvs/NEWS
@@ -0,0 +1,863 @@
+Changes since 1.6:
+
+* RCS keyword "Name" supported for "cvs update -r <tag>" and "cvs
+checkout -r <tag>".
+
+* If there is a group whose name matches a compiled in value which
+defaults to "cvsadmin", only members of that group can use "cvs
+admin".
+
+* CVS now sets the modes of files in the repository based on the
+CVSUMASK environment variable or a compiled in value defaulting to
+002. This way other developers will be able to access the files in
+the repository regardless of the umask of the developer creating them.
+
+* The command name .cvsrc now matches the official name of the
+command, not the one (possibly an alias) by which it was invoked. If
+you had previously relied on "cvs di" and "cvs diff" using different
+options, instead use a shell function or alias (for example "alias
+cvsdi='cvs diff -u'").
+
+Changes from 1.5 to 1.6:
+
+* Del updated the man page to include all of the new features
+of CVS 1.6.
+
+* "cvs tag" now supports a "-r | -D" option for tagging an already
+tagged revision / specific revision of a file.
+
+* There is a "taginfo" file in CVSROOT that supports filtering and
+recording of tag operations.
+
+* Long options support added, including --help and --version options.
+
+* "cvs release" no longer cares whether or not the directory being
+released has an entry in the `modules' file.
+
+* The modules file now takes a -e option which is used instead of -o
+for "cvs export". If your modules file has a -o option which you want
+to be used for "cvs export", change it to specify -e as well as -o.
+
+* "cvs export" now takes a -k option to set RCS keyword expansion.
+This way you can export binary files. If you want the old behavior,
+you need to specify -kv.
+
+* "cvs update", "cvs rdiff", "cvs checkout", "cvs import", "cvs
+release", "cvs rtag", and "cvs tag" used to take -q and -Q options
+after the command name (e.g. "cvs update -q"). This was confusing
+because other commands, such as "cvs ci", did not. So the options
+after the command name have been removed and you must now specify, for
+example, "cvs -q update", which has been supported since CVS 1.3.
+
+* New "wrappers" feature. This allows you to set a hook which
+transforms files on their way in and out of cvs (apparently on the
+NeXT there is some particular usefulness in tarring things up in the
+repository). It also allows you to declare files as merge-by-copy
+which means that instead of trying to merge the file, CVS will merely
+copy the new version. There is a CVSROOT/cvswrappers file and an
+optionsl ~/.cvswrappers file to support this feature.
+
+* You can set CVSROOT to user@host:dir, not just host:dir, if your
+username on the server host is different than on the client host.
+
+* VISUAL is accepted as well as EDITOR.
+
+* $CVSROOT is expanded in *info files.
+
+Changes from 1.4A2 to 1.5:
+
+* Remote implementation. This is very helpful when collaborating on a
+project with someone across a wide-area network. This release can
+also be used locally, like other CVS versions, if you have no need for
+remote access.
+
+Here are some of the features of the remote implementation:
+- It uses reliable transport protocols (TCP/IP) for remote repository
+ access, not NFS. NFS is unusable over long distances (and sometimes
+ over short distances)
+- It transfers only those files that have changed in the repository or
+ the working directory. To save transmission time, it will transfer
+ patches when appropriate, and can compress data for transmission.
+- The server never holds CVS locks while waiting for a reply from the client;
+ this makes the system robust when used over flaky networks.
+
+The remote features are documented in doc/cvsclient.texi in the CVS
+distribution, but the main doc file, cvs.texinfo, has not yet been
+updated to include the remote features.
+
+* Death support. See src/README-rm-add for more information on this.
+
+* Many speedups, especially from jtc@cygnus.com.
+
+* CVS 1.2 compatibility code has been removed as a speedup. If you
+have working directories checked out by CVS 1.2, CVS 1.3 or 1.4A2 will
+try to convert them, but CVS 1.5 and later will not (if the working
+directory is up to date and contains no extraneous files, you can just
+remove it, and then check out a new working directory). Likewise if
+your repository contains a CVSROOT.adm directory instead of a CVSROOT
+directory, you need to rename it.
+
+Fri Oct 21 20:58:54 1994 Brian Berliner <berliner@sun.com>
+
+ * Changes between CVS 1.3 and CVS 1.4 Alpha-2
+
+ * A new program, "cvsbug", is provided to let you send bug reports
+ directly to the CVS maintainers. Please use it instead of sending
+ mail to the info-cvs mailing list. If your build fails, you may
+ have to invoke "cvsbug" directly from the "src" directory as
+ "src/cvsbug.sh".
+
+ * A new User's Guide and Tutorial, written by Per Cederqvist
+ <ceder@signum.se> of Signum Support. See the "doc" directory. A
+ PostScript version is included as "doc/cvs.ps".
+
+ * The Frequesntly Asked Questions file, FAQ, has been added to the
+ release. Unfortunately, its contents are likely out-of-date.
+
+ * The "cvsinit" shell script is now installed in the $prefix/bin
+ directory like the other programs. You can now create new
+ CVS repositories with great ease.
+
+ * Index: lines are now printed on output from 'diff' and 'rdiff',
+ in order to facilitate application of patches to multiple subdirs.
+
+ * Support for a ~/.cvsrc file, which allows you to specify options
+ that are always supposed to be given to a specific command. This
+ feature shows the non-orthogonality of the option set, since while
+ there may be an option to turn something on, the option to turn
+ that same thing off may not exist.
+
+ * You can now list subdirectories that you wish to ignore in a
+ modules listing, such as:
+
+ gcc -a gnu/gcc, !gnu/gcc/testsuites
+
+ which will check out everything underneath gnu/gcc, except
+ everything underneath gnu/gcc/testsuites.
+
+ * It is now much harder to accidentally overwrite an existing tag
+ name, since attempting to move a tag name will result in a error,
+ unless the -F (force) flag is given to the tag subcommands.
+
+ * Better error checking on matching of the repository used to
+ check code out from against the repository the current cvs
+ commnands would use. (Thanks to Mark Baushke <mdb@cisco.com>)
+
+ * Better support for sites with multiple CVSROOT repositories has
+ been contributed. The file "CVS/Root" in your working directory
+ is created to hold the full path to the CVS repository and a
+ simple check is made against your current CVSROOT setting.
+
+ * You can now specify an RCS keyword substitution value when you
+ import files into the repository.
+
+ * Uses a much newer version of Autoconf, and conforms to the GNU
+ coding standards much more closely. No, it still doesn't have
+ long option names.
+
+ * Code cleanup. Many passes through gcc -Wall helped to identify
+ a number of questionable constructs. Most arbitrary length limits
+ were removed.
+
+ * Profiling to determine bottlenecks helped to identify the best
+ places to spend time speeding up the code, which was then done. A
+ number of performance enhancements in filename matching have sped
+ up checkouts.
+
+ * Many more contributions have been added to the "contrib"
+ directory. See the README file in that directory for more
+ information.
+
+ * "cvs commit" will try harder to not change the file's
+ modification time after the commit. If the file does not change
+ as a result of the commit operation, CVS will preserve the
+ original modification time, thus speeding up future make-type
+ builds.
+
+ * "cvs commit" now includes any removed files in the (optional)
+ pre-commit checking program that may be invoked. Previously, only
+ added and modified files were included.
+
+ * It is now possible to commit a file directly onto the trunk at a
+ specific revision level by doing "cvs commit -r3.0 file.c", where
+ "3.0" specifies the revision you wish to create. The file must be
+ up-to-date with the current head of the trunk for this to succeed.
+
+ * "cvs commit" will now function with a pre-commit program that
+ has arguments specified in the "commitinfo" file.
+
+ * The "mkmodules" program will now look within the
+ $CVSROOT/CVSROOT/checkoutlist" file for any additional files that
+ should be automatically checked out within CVSROOT; mkmodules also
+ tries harder to preserve any execute bits the files may have
+ originally had.
+
+ * "cvs diff" is much more accurate about its exit status now. It
+ now returns the maximum exit status of any invoked diff.
+
+ * The "-I !" option is now supported for the import and update
+ commands correctly. It will properly clear the ignore list now.
+
+ * Some problems with "cvs import" handling of .cvsignore have been
+ fixed; as well, some rampant recursion problems with import have
+ also been fixed.
+
+ * "cvs rdiff" (aka "cvs patch") now tries to set the modify time
+ of any temporary files it uses to match those specified for the
+ particular revision. This allows a more accurate patch image to
+ be created.
+
+ * "cvs status" has improved revision descriptions. "Working
+ revision" is used for the revision of the working file that you
+ edit directly; "Repository revision" is the revision of the file
+ with the $CVSROOT source repository. Also, the output is clearer
+ with regard to sticky and branch revisions.
+
+ * CVS no longer dumps core when given a mixture of directories and
+ files in sub-directories (as in "cvs ci file1 dir1/file2").
+ Instead, arguments are now clumped into their respective directory
+ and operated on in chunks, together.
+
+ * If the CVSEDITOR environment variable is set, that editor is
+ used for log messages instead of the EDITOR environment variable.
+ This makes it easy to substitute intelligent programs to make more
+ elaborate log messages. Contributed by Mark D Baushke
+ (mdb@cisco.com).
+
+ * Command argument changes:
+ cvs: The "-f" option has been added to ignore
+ the ~/.cvsrc file.
+ commit: Renamed the "-f logfile" option to the
+ "-F logfile" option. Added the "-f"
+ option to force a commit of the specified
+ files (this disables recursion).
+ history: Added "-t timezone" option to force any
+ date-specific output into the specified
+ timezone.
+ import: Added "-d" option to use the file's
+ modification time as the time of the
+ import. Added "-k sub" option to set the
+ default RCS keyword substitution mode for
+ newly-created files.
+ remove: Added "-f" option to force the file's
+ automatic removal if it still exists in
+ the working directory (use with caution).
+ rtag: Added "-F" option to move the tag if it
+ already exists -- new default is to NOT
+ move tags automatically.
+ tag: Added "-F" option to move the tag if it
+ already exists -- new default is to NOT
+ move tags automatically.
+
+Tue Apr 7 15:55:25 1992 Brian Berliner (berliner at sun.com)
+
+ * Changes between CVS 1.3 Beta-3 and official CVS 1.3!
+
+ * A new shell script is provided, "./cvsinit", which can be run at
+ install time to help setup your $CVSROOT area. This can greatly
+ ease your entry into CVS usage.
+
+ * The INSTALL file has been updated to include the machines on
+ which CVS has compiled successfully. I think CVS 1.3 is finally
+ portable. Thanks to all the Beta testers!
+
+ * Support for the "editinfo" file was contributed. This file
+ (located in $CVSROOT/CVSROOT) can be used to specify a special
+ "editor" to run on a per-directory basis within the repository,
+ instead of the usual user's editor. As such, it can verify that
+ the log message entered by the user is of the appropriate form
+ (contains a bugid and test validation, for example).
+
+ * The manual pages cvs(1) and cvs(5) have been updated.
+
+ * The "mkmodules" command now informs you when your modules file
+ has duplicate entries.
+
+ * The "add" command now preserves any per-directory sticky tag when
+ you add a new directory to your checked-out sources.
+
+ * The "admin" command is now a fully recursive interface to the
+ "rcs" program which operates on your checked-out sources. It no
+ longer requires you to specify the full path to the RCS file.
+
+ * The per-file sticky tags can now be effectively removed with
+ "cvs update -A file", even if you had checked out the whole
+ directory with a per-directory sticky tag. This allows a great
+ deal of flexibility in managing the revisions that your checked-out
+ sources are based upon (both per-directory and per-file sticky
+ tags).
+
+ * The "cvs -n commit" command now works, to show which files are
+ out-of-date and will cause the real commit to fail, or which files
+ will fail any pre-commit checks. Also, the "cvs -n import ..."
+ command will now show you what it would've done without actually
+ doing it.
+
+ * Doing "cvs commit modules" to checkin the modules file will no
+ properly run the "mkmodules" program (assuming you have setup your
+ $CVSROOT/CVSROOT/modules file to do so).
+
+ * The -t option in the modules file (which specifies a program to
+ run when you do a "cvs rtag" operation on a module) now gets the
+ symbolic tag as the second argument when invoked.
+
+ * When the source repository is locked by another user, that user's
+ login name will be displayed as the holder of the lock.
+
+ * Doing "cvs checkout module/file.c" now works even if
+ module/file.c is in the Attic (has been removed from main-line
+ development).
+
+ * Doing "cvs commit */Makefile" now works as one would expect.
+ Rather than trying to commit everything recursively, it will now
+ commit just the files specified.
+
+ * The "cvs remove" command is now fully recursive. To schedule a
+ file for removal, all you have to do is "rm file" and "cvs rm".
+ With no arguments, "cvs rm" will schedule all files that have been
+ physically removed for removal from the source repository at the
+ next "cvs commit".
+
+ * The "cvs tag" command now prints "T file" for each file that was
+ tagged by this invocation and "D file" for each file that had the
+ tag removed (as with "cvs tag -d").
+
+ * The -a option has been added to "cvs rtag" to force it to clean
+ up any old, matching tags for files that have been removed (in the
+ Attic) that may not have been touched by this tag operation. This
+ can help keep a consistent view with your tag, even if you re-use
+ it frequently.
+
+Sat Feb 29 16:02:05 1992 Brian Berliner (berliner at sun.com)
+
+ * Changes between CVS 1.3 Beta-2 and CVS 1.3 Beta-3
+
+ * Many portability fixes, thanks to all the Beta testers! With any
+ luck, this Beta release will compile correctly on most anything.
+ Hey, what are we without our dreams.
+
+ * CVS finally has support for doing isolated development on a
+ branch off the current (or previous!) revisions. This is also
+ extremely nice for generating patches for previously released
+ software while development is progressing on the next release.
+ Here's an example of creating a branch to fix a patch with the 2.0
+ version of the "foo" module, even though we are already well into
+ the 3.0 release. Do:
+
+ % cvs rtag -b -rFOO_2_0 FOO_2_0_Patch foo
+ % cvs checkout -rFOO_2_0_Patch foo
+ % cd foo
+ [[ hack away ]]
+ % cvs commit
+
+ A physical branch will be created in the RCS file only when you
+ actually commit the change. As such, forking development at some
+ random point in time is extremely light-weight -- requiring just a
+ symbolic tag in each file until a commit is done. To fork
+ development at the currently checked out sources, do:
+
+ % cvs tag -b Personal_Hack
+ % cvs update -rPersonal_Hack
+ [[ hack away ]]
+ % cvs commit
+
+ Now, if you decide you want the changes made in the Personal_Hack
+ branch to be merged in with other changes made in the main-line
+ development, you could do:
+
+ % cvs commit # to make Personal_Hack complete
+ % cvs update -A # to update sources to main-line
+ % cvs update -jPersonal_Hack # to merge Personal_Hack
+
+ to update your checked-out sources, or:
+
+ % cvs checkout -jPersonal_Hack module
+
+ to checkout a fresh copy.
+
+ To support this notion of forked development, CVS reserves
+ all even-numbered branches for its own use. In addition, CVS
+ reserves the ".0" and ".1" branches. So, if you intend to do your
+ own branches by hand with RCS, you should use odd-numbered branches
+ starting with ".3", as in "1.1.3", "1.1.5", 1.2.9", ....
+
+ * The "cvs commit" command now supports a fully functional -r
+ option, allowing you to commit your changes to a specific numeric
+ revision or symbolic tag with full consistency checks. Numeric
+ tags are useful for bringing your sources all up to some revision
+ level:
+
+ % cvs commit -r2.0
+
+ For symbolic tags, you can only commit to a tag that references a
+ branch in the RCS file. One created by "cvs rtag -b" or from
+ "cvs tag -b" is appropriate (see below).
+
+ * Roland Pesch <pesch@cygnus.com> and K. Richard Pixley
+ <rich@cygnus.com> were kind enough to contribute two new manual
+ pages for CVS: cvs(1) and cvs(5). Most of the new CVS 1.3 features
+ are now documented, with the exception of the new branch support
+ added to commit/rtag/tag/checkout/update.
+
+ * The -j options of checkout/update have been added. The "cvs join"
+ command has been removed.
+
+ With one -j option, CVS will merge the changes made between the
+ resulting revision and the revision that it is based on (e.g., if
+ the tag refers to a branch, CVS will merge all changes made in
+ that branch into your working file).
+
+ With two -j options, CVS will merge in the changes between the two
+ respective revisions. This can be used to "remove" a certain delta
+ from your working file. E.g., If the file foo.c is based on
+ revision 1.6 and I want to remove the changes made between 1.3 and
+ 1.5, I might do:
+
+ % cvs update -j1.5 -j1.3 foo.c # note the order...
+
+ In addition, each -j option can contain on optional date
+ specification which, when used with branches, can limit the chosen
+ revision to one within a specific date. An optional date is
+ specified by adding a colon (:) to the tag, as in:
+
+ -jSymbolic_Tag:Date_Specifier
+
+ An example might be what "cvs import" tells you to do when you have
+ just imported sources that have conflicts with local changes:
+
+ % cvs checkout -jTAG:yesterday -jTAG module
+
+ which tells CVS to merge in the changes made to the branch
+ specified by TAG in the last 24 hours. If this is not what is
+ intended, substitute "yesterday" for whatever format of date that
+ is appropriate, like:
+
+ % cvs checkout -jTAG:'1 week ago' -jTAG module
+
+ * "cvs diff" now supports the special tags "BASE" and "HEAD". So,
+ the command:
+
+ % cvs diff -u -rBASE -rHEAD
+
+ will effectively show the changes made by others (in unidiff
+ format) that will be merged into your working sources with your
+ next "cvs update" command. "-rBASE" resolves to the revision that
+ your working file is based on. "-rHEAD" resolves to the current
+ head of the branch or trunk that you are working on.
+
+ * The -P option of "cvs checkout" now means to Prune empty
+ directories, as with "update". The default is to not remove empty
+ directories. However, if you do "checkout" with any -r options, -P
+ will be implied. I.e., checking out with a tag will cause empty
+ directories to be pruned automatically.
+
+ * The new file INSTALL describes how to install CVS, including
+ detailed descriptions of interfaces to "configure".
+
+ * The example loginfo file in examples/loginfo has been updated to
+ use the perl script included in contrib/log.pl. The nice thing
+ about this log program is that it records the revision numbers of
+ your change in the log message.
+
+ Example files for commitinfo and rcsinfo are now included in the
+ examples directory.
+
+ * All "#if defined(__STDC__) && __STDC__ == 1" lines have been
+ changed to be "#if __STDC__" to fix some problems with the former.
+
+ * The lib/regex.[ch] files have been updated to the 1.3 release of
+ the GNU regex package.
+
+ * The ndbm emulation routines included with CVS 1.3 Beta-2 in the
+ src/ndbm.[ch] files has been moved into the src/myndbm.[ch] files
+ to avoid any conflict with the system <ndbm.h> header file. If
+ you had a previous CVS 1.3 Beta release, you will want to "cvs
+ remove ndbm.[ch]" form your copy of CVS as well.
+
+ * "cvs add" and "cvs remove" are a bit more verbose, telling you
+ what to do to add/remove your file permanently.
+
+ * We no longer mess with /dev/tty in "commit" and "add".
+
+ * More things are quiet with the -Q option set.
+
+ * New src/config.h option: If CVS_BADROOT is set, CVS will not
+ allow people really logged in as "root" to commit changes.
+
+ * "cvs diff" exits with a status of 0 if there were no diffs, 1 if
+ there were diffs, and 2 if there were errors.
+
+ * "cvs -n diff" is now supported so that you can still run diffs
+ even while in the middle of committing files.
+
+ * Handling of the CVS/Entries file is now much more robust.
+
+ * The default file ignore list now includes "*.so".
+
+ * "cvs import" did not expand '@' in the log message correctly. It
+ does now. Also, import now uses the ignore file facility
+ correctly.
+
+ Import will now tell you whether there were conflicts that need to
+ be resolved, and how to resolve them.
+
+ * "cvs log" has been changed so that you can "log" things that are
+ not a part of the current release (in the Attic).
+
+ * If you don't change the editor message on commit, CVS now prompts
+ you with the choice:
+
+ !)reuse this message unchanged for remaining dirs
+
+ which allows you to tell CVS that you have no intention of changing
+ the log message for the remainder of the commit.
+
+ * It is no longer necessary to have CVSROOT set if you are using
+ the -H option to get Usage information on the commands.
+
+ * Command argument changes:
+ checkout: -P handling changed as described above.
+ New -j option (up to 2 can be specified)
+ for doing rcsmerge kind of things on
+ checkout.
+ commit: -r option now supports committing to a
+ numeric or symbolic tags, with some
+ restrictions. Full consistency checks will
+ be done.
+ Added "-f logfile" option, which tells
+ commit to glean the log message from the
+ specified file, rather than invoking the
+ editor.
+ rtag: Added -b option to create a branch tag,
+ useful for creating a patch for a previous
+ release, or for forking development.
+ tag: Added -b option to create a branch tag,
+ useful for creating a patch for a previous
+ release, or for forking development.
+ update: New -j option (up to 2 can be specified)
+ for doing rcsmerge kind of things on
+ update.
+
+Thu Jan 9 10:51:35 MST 1992 Jeff Polk (polk at BSDI.COM)
+
+ * Changes between CVS 1.3 Beta-1 and CVS 1.3 Beta-2
+
+ * Thanks to K. Richard Pixley at Cygnus we now have function
+ prototypes in all the files
+
+ * Some small changes to configure for portability. There have
+ been other portability problems submitted that have not been fixed
+ (Brian will be working on those). Additionally all __STDC__
+ tests have been modified to check __STDC__ against the constant 1
+ (this is what the Second edition of K&R says must be true).
+
+ * Lots of additional error checking for forked processes (run_exec)
+ (thanks again to K. Richard Pixley)
+
+ * Lots of miscellaneous bug fixes - including but certainly not
+ limited to:
+ various commit core dumps
+ various update core dumps
+ bogus results from status with numeric sticky tags
+ commitprog used freed memory
+ Entries file corruption caused by No_Difference
+ commit to revision broken (now works if branch exists)
+ ignore file processing broken for * and !
+ ignore processing didn't handle memory reasonably
+ miscellaneous bugs in the recursion processor
+ file descriptor leak in ParseInfo
+ CVSROOT.adm->CVSROOT rename bug
+ lots of lint fixes
+
+ * Reformatted all the code in src (with GNU indent) and then
+ went back and fixed prototypes, etc since indent gets confused. The
+ rationale is that it is better to do it sooner than later and now
+ everything is consistent and will hopefully stay that way.
+ The basic options to indent were: "-bad -bbb -bap -cdb -d0 -bl -bli0
+ -nce -pcs -cs -cli4 -di1 -nbc -psl -lp -i4 -ip4 -c41" and then
+ miscellaneous formatting fixes were applied. Note also that the
+ "-nfc1" or "-nfca" may be appropriate in files where comments have
+ been carefully formatted (e.g, modules.c).
+
+Sat Dec 14 20:35:22 1991 Brian Berliner (berliner at sun.com)
+
+ * Changes between CVS 1.2 and CVS 1.3 Beta are described here.
+
+ * Lots of portability work. CVS now uses the GNU "configure"
+ script to dynamically determine the features provided by your
+ system. It probably is not foolproof, but it is better than
+ nothing. Please let me know of any portability problems. Some
+ file names were changed to fit within 14-characters.
+
+ * CVS has a new RCS parser that is much more flexible and
+ extensible. It should read all known RCS ",v" format files.
+
+ * Most of the commands now are fully recursive, rather than just
+ operating on the current directory alone. This includes "commit",
+ which makes it real easy to do an "atomic" commit of all the
+ changes made to a CVS hierarchy of sources. Most of the commands
+ also correctly handle file names that are in directories other than
+ ".", including absolute path names. Commands now accept the "-R"
+ option to force recursion on (though it is always the default now)
+ and the "-l" option to force recursion off, doing just "." and not
+ any sub-directories.
+
+ * CVS supports many of the features provided with the RCS 5.x
+ distribution - including the new "-k" keyword expansion options. I
+ recommend using RCS 5.x (5.6 is the current official RCS version)
+ and GNU diff 1.15 (or later) distributions with CVS.
+
+ * Checking out files with symbolic tags/dates is now "sticky", in
+ that CVS remembers the tag/date used for each file (and directory)
+ and will use that tag/date automatically on the next "update" call.
+ This stickyness also holds for files checked out with the the new
+ RCS 5.x "-k" options.
+
+ * The "cvs diff" command now recognizes all of the rcsdiff 5.x
+ options. Unidiff format is available by installing the GNU
+ diff 1.15 distribution.
+
+ * The old "CVS.adm" directories created on checkout are now called
+ "CVS" directories, to look more like "RCS" and "SCCS". Old CVS.adm
+ directories are automagically converted to CVS directories. The
+ old "CVSROOT.adm" directory within the source repository is
+ automagically changed into a "CVSROOT" directory as well.
+
+ * Symbolic links in the source repository are fully supported ONLY
+ if you use RCS 5.6 or later and (of course) your system supports
+ symlinks.
+
+ * A history database has been contributed which maintains the
+ history of certain CVS operations, as well as providing a wide array
+ of querying options.
+
+ * The "cvs" program has a "-n" option which can be used with the
+ "update" command to show what would be updated without actually
+ doing the update, like: "cvs -n update". All usage statements
+ have been cleaned up and made more verbose.
+
+ * The module database parsing has been rewritten. The new format
+ is compatible with the old format, but with much more
+ functionality. It allows modules to be created that grab pieces or
+ whole directories from various different parts of your source
+ repository. Module-relative specifications are also correctly
+ recognized now, like "cvs checkout module/file.c".
+
+ * A configurable template can be specified such that on a "commit",
+ certain directories can supply a template that the user must fill
+ before completing the commit operation.
+
+ * A configurable pre-commit checking program can be specified which
+ will run to verify that a "commit" can happen. This feature can be
+ used to restrict certain users from changing certain pieces of the
+ source repository, or denying commits to the entire source
+ repository.
+
+ * The new "cvs export" command is much like "checkout", but
+ establishes defaults suitable for exporting code to others (expands
+ out keywords, forces the use of a symbolic tag, and does not create
+ "CVS" directories within the checked out sources.
+
+ * The new "cvs import" command replaces the deprecated "checkin"
+ shell script and is used to import sources into CVS control. It is
+ also much faster for the first-time import. Some algorithmic
+ improvements have also been made to reduce the number of
+ conflicting files on next-time imports.
+
+ * The new "cvs admin" command is basically an interface to the
+ "rcs" program. (Not yet implemented very well).
+
+ * Signal handling (on systems with BSD or POSIX signals) is much
+ improved. Interrupting CVS now works with a single interrupt!
+
+ * CVS now invokes RCS commands by direct fork/exec rather than
+ calling system(3). This improves performance by removing a call to
+ the shell to parse the arguments.
+
+ * Support for the .cvsignore file has been contributed. CVS will
+ now show "unknown" files as "? filename" as the result of an "update"
+ command. The .cvsignore file can be used to add files to the
+ current list of ignored files so that they won't show up as unknown.
+
+ * Command argument changes:
+ cvs: Added -l to turn off history logging.
+ Added -n to show what would be done without actually
+ doing anything.
+ Added -q/-Q for quiet and really quiet settings.
+ Added -t to show debugging trace.
+ add: Added -k to allow RCS 5.x -k options to be specified.
+ admin: New command; an interface to rcs(1).
+ checkout: Added -A to reset sticky tags/date/options.
+ Added -N to not shorten module paths.
+ Added -R option to force recursion.
+ Changed -p (prune empty directories) to -P option.
+ Changed -f option; forcing tags match is now default.
+ Added -p option to checkout module to standard output.
+ Added -s option to cat the modules db with status.
+ Added -d option to checkout in the specified directory.
+ Added -k option to use RCS 5.x -k support.
+ commit: Removed -a option; use -l instead.
+ Removed -f option.
+ Added -l option to disable recursion.
+ Added -R option to force recursion.
+ If no files specified, commit is recursive.
+ diff: Now recognizes all RCS 5.x rcsdiff options.
+ Added -l option to disable recursion.
+ Added -R option to force recursion.
+ history: New command; displays info about CVS usage.
+ import: Replaces "checkin" shell script; imports sources
+ under CVS control. Ignores files on the ignore
+ list (see -I option or .cvsignore description above).
+ export: New command; like "checkout", but w/special options
+ turned on by default to facilitate exporting sources.
+ join: Added -B option to join from base of the branch;
+ join now defaults to only joining with the top two
+ revisions on the branch.
+ Added -k option for RCS 5.x -k support.
+ log: Supports all RCS 5.x options.
+ Added -l option to disable recursion.
+ Added -R option to force recursion.
+ patch: Changed -f option; forcing tags match is now default.
+ Added -c option to force context-style diffs.
+ Added -u option to support unidiff-style diffs.
+ Added -V option to support RCS specific-version
+ keyword expansion formats.
+ Added -R option to force recursion.
+ remove: No option changes. It's a bit more verbose.
+ rtag: Equivalent to the old "cvs tag" command.
+ No option changes. It's a lot faster for re-tag.
+ status: New output formats with more information.
+ Added -l option to disable recursion.
+ Added -R option to force recursion.
+ Added -v option to show symbolic tags for files.
+ tag: Functionality changed to tag checked out files
+ rather than modules; use "rtag" command to get the
+ old "cvs tag" behaviour.
+ update: Added -A to reset sticky tags/date/options.
+ Changed -p (prune empty directories) to -P option.
+ Changed -f option; forcing tags match is now default.
+ Added -p option to checkout module to standard output.
+ Added -I option to add files to the ignore list.
+ Added -R option to force recursion.
+
+ Major Contributors:
+
+ * Jeff Polk <polk@bsdi.com> rewrote most of the grody code of CVS
+ 1.2. He made just about everything dynamic (by using malloc),
+ added a generic hashed list manager, re-wrote the modules database
+ parsing in a compatible - but extended way, generalized directory
+ hierarchy recursion for virtually all the commands (including
+ commit!), generalized the loginfo file to be used for pre-commit
+ checks and commit templates, wrote a new and flexible RCS parser,
+ fixed an uncountable number of bugs, and helped in the design of
+ future CVS features. If there's anything gross left in CVS, it's
+ probably my fault!
+
+ * David G. Grubbs <dgg@odi.com> contributed the CVS "history" and
+ "release" commands. As well as the ever-so-useful "-n" option of
+ CVS which tells CVS to show what it would do, without actually
+ doing it. He also contributed support for the .cvsignore file.
+
+ * Paul Sander, HaL Computer Systems, Inc. <paul@hal.com> wrote and
+ contributed the code in lib/sighandle.c. I added support for
+ POSIX, BSD, and non-POSIX/non-BSD systems.
+
+ * Free Software Foundation contributed the "configure" script and
+ other compatibility support in the "lib" directory, which will help
+ make CVS much more portable.
+
+ * Many others have contributed bug reports and enhancement requests.
+ Some have even submitted actual code which I have not had time yet
+ to integrate into CVS. Maybe for the next release.
+
+ * Thanks to you all!
+
+Wed Feb 6 10:10:58 1991 Brian Berliner (berliner at sun.com)
+
+ * Changes from CVS 1.0 Patchlevel 1 to CVS 1.0 Patchlevel 2; also
+ known as "Changes from CVS 1.1 to CVS 1.2".
+
+ * Major new support with this release is the ability to use the
+ recently-posted RCS 5.5 distribution with CVS 1.2. See below for
+ other assorted bug-fixes that have been thrown in.
+
+ * ChangeLog (new): Added Emacs-style change-log file to CVS 1.2
+ release. Chronological description of changes between release.
+
+ * README: Small fixes to installation instructions. My email
+ address is now "berliner@sun.com".
+
+ * src/Makefile: Removed "rcstime.h". Removed "depend" rule.
+
+ * src/partime.c: Updated to RCS 5.5 version with hooks for CVS.
+ * src/maketime.c: Updated to RCS 5.5 version with hooks for CVS.
+ * src/rcstime.h: Removed from the CVS 1.2 distribution.
+ Thanks to Paul Eggert <eggert@twinsun.com> for these changes.
+
+ * src/checkin.csh: Support for RCS 5.5 parsing.
+ Thanks to Paul Eggert <eggert@twinsun.com> for this change.
+
+ * src/collect_sets.c (Collect_Sets): Be quieter if "-f" option is
+ specified. When checking out files on-top-of other files that CVS
+ doesn't know about, run a diff in the hopes that they are really
+ the same file before aborting.
+
+ * src/commit.c (branch_number): Fix for RCS 5.5 parsing.
+ Thanks to Paul Eggert <eggert@twinsun.com> for this change.
+
+ * src/commit.c (do_editor): Bug fix - fprintf missing argument
+ which sometimes caused core dumps.
+
+ * src/modules.c (process_module): Properly NULL-terminate
+ update_dir[] in all cases.
+
+ * src/no_difference.c (No_Difference): The wrong RCS revision was
+ being registered in certain (strange) cases.
+
+ * src/patch.c (get_rcsdate): New algorithm. No need to call
+ maketime() any longer.
+ Thanks to Paul Eggert <eggert@twinsun.com> for this change.
+
+ * src/patchlevel.h: Increased patch level to "2".
+
+ * src/subr.c (isdir, islink): Changed to compare stat mode bits
+ correctly.
+
+ * src/tag.c (tag_file): Added support for following symbolic links
+ that are in the master source repository when tagging. Made tag
+ somewhat quieter in certain cases.
+
+ * src/update.c (update_process_lists): Unlink the user's file if it
+ was put on the Wlist, meaning that the user's file is not modified
+ and its RCS file has been removed by someone else.
+
+ * src/update.c (update): Support for "cvs update dir" to correctly
+ just update the argument directory "dir".
+
+ * src/cvs.h: Fixes for RCS 5.5 parsing.
+ * src/version_number.c (Version_Number): Fixes for parsing RCS 5.5
+ and older RCS-format files.
+ Thanks to Paul Eggert <eggert@twinsun.com> for these changes.
+
+ * src/version_number.c (Version_Number): Bug fixes for "-f" option.
+ Bug fixes for parsing with certain branch numbers. RCS
+ revision/symbol parsing is much more solid now.
+
+Wed Feb 14 10:01:33 1990 Brian Berliner (berliner at sun.com)
+
+ * Changes from CVS 1.0 Patchlevel 0 to CVS 1.0 Patchlevel 1; also
+ known as "Changes from CVS 1.0 to CVS 1.1".
+
+ * src/patch.c (get_rcsdate): Portability fix. Replaced call to
+ timelocal() with call to maketime().
+
+Mon Nov 19 23:15:11 1990 Brian Berliner (berliner at prisma.com)
+
+ * Sent CVS 1.0 release to comp.sources.unix moderator and FSF.
+
+ * Special thanks to Dick Grune <dick@cs.vu.nl> for his work on the
+ 1986 version of CVS and making it available to the world. Dick's
+ version is available on uunet.uu.net in the
+ comp.sources.unix/volume6/cvs directory.
+
+$CVSid: @(#)ChangeLog 1.35 94/10/22 $
diff --git a/gnu/usr.bin/cvs/PROJECTS b/gnu/usr.bin/cvs/PROJECTS
new file mode 100644
index 0000000..de76576
--- /dev/null
+++ b/gnu/usr.bin/cvs/PROJECTS
@@ -0,0 +1,59 @@
+This is a list of projects for CVS. In general, unlike the things in
+the TODO file, these need more analysis to determine if and how
+worthwhile each task is.
+
+I haven't gone through TODO, but it's likely that it has entries that
+are actually more appropriate for this list.
+
+0. Improved Efficency
+
+* CVS uses a single doubly linked list/hash table data structure for
+ all of its lists. Since the back links are only used for deleting
+ list nodes it might be beneficial to use singly linked lists or a
+ tree structure. Most likely, a single list implementation will not
+ be appropriate for all uses.
+
+ One easy change would be to remove the "type" field out of the list
+ and node structures. I have found it to be of very little use when
+ debugging, and each instance eats up a word of memory. This can add
+ up and be a problem on memory-starved machines.
+
+ Profiles have shown that on fast machines like the Alpha, fsortcmp()
+ is one of the hot spots.
+
+* Dynamically allocated character strings are created, copied, and
+ destroyed throughout CVS. The overhead of malloc()/strcpy()/free()
+ needs to be measured. If significant, it could be minimized by using a
+ reference counted string "class".
+
+* File modification time is stored as a character string. It might be
+ worthwile to use a time_t internally if the time to convert a time_t
+ (from struct stat) to a string is greater that the time to convert a
+ ctime style string (from the entries file) to a time_t. time_t is
+ an machine-dependant type (although it's pretty standard on UN*X
+ systems), so we would have to have different conversion routines.
+ Profiles show that both operations are called about the same number
+ of times.
+
+* stat() is one of the largest performance bottlenecks on systems
+ without the 4.4BSD filesystem. By spliting information out of
+ the filesystem (perhaps the "rename database") we should be
+ able to improve performance.
+
+* Parsing RCS files is very expensive. This might be unnecessary if
+ RCS files are only used as containers for revisions, and tag,
+ revision, and date information was available in easy to read
+ (and modify) indexes. This becomes very apparent with files
+ with several hundred revisions.
+
+* A RCS "library", so CVS could operate on RCS files directly.
+
+ CVS parses RCS files in order to determine if work needs to be done,
+ and then RCS parses the files again when it is performing the work.
+ This would be much faster if CVS could do whatever is necessary
+ by itself.
+
+1. Improved testsuite/sanity check script
+
+* Need to use a code coverage tool to determine how much the sanity
+ script tests, and fill in the holes.
diff --git a/gnu/usr.bin/cvs/README b/gnu/usr.bin/cvs/README
new file mode 100644
index 0000000..b257f89
--- /dev/null
+++ b/gnu/usr.bin/cvs/README
@@ -0,0 +1,207 @@
+$CVSid: @(#)README 1.32 94/10/22 $
+
+ CVS Kit
+
+ Copyright (c) 1993-1994 Brian Berliner
+ Copyright (c) 1992 Brian Berliner and Jeff Polk
+ Copyright (c) 1989-1992, Brian Berliner
+ All Rights Reserved
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 1, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+-------------------------------------------------------------------------------
+
+Welcome to CVS!
+
+Bug reports are accepted, however note that someone may or may not
+feel like taking care of your bug report. Support contracts are
+available from Cyclic Software (http://www.cyclic.com).
+
+To report bugs send mail to bug-cvs@prep.ai.mit.edu, or run the "cvsbug"
+program and fill out the template:
+
+ $ cvsbug
+
+The "cvsbug" program is installed in the same location as the "cvs"
+program. If your installation failed, you may need to run "cvsbug"
+directly out of the "src" directory as "src/cvsbug.sh".
+
+Please consult the INSTALL file for information on tested
+configurations. If you have a comment about an already tested
+configuration, or have tried CVS on a new configuration, please write
+to the above address and let us know! Free software only works if we
+all help out.
+
+Finally, we cannot guarantee that this release will not completely wipe out
+all of your work from your system. We do some simple testing before each
+release, but you are completely on your own. We recommend testing this
+release on a source repository that is not critical to your work. THIS
+SOFTWARE IS SUPPLIED COMPLETELY "AS IS". NO WARRANTY....
+
+Thanks for your support!
+
+ -The CVS Team, and the Cyclic CVS Hackers
+
+-------------------------------------------------------------------------------
+
+CVS is a freely available collection of programs that provide for software
+release and revision control functions in a UNIX environment. It is
+designed to work on top of the RCS distribution, V4 and later. CVS does
+understand how to parse older RCS formats, but cannot do any of the fancier
+features (like vendor branch support) without RCS branch support.
+
+Short blurb from the manual page (larger blurb is included there):
+ cvs is a front end to the rcs(1) revision control system
+ which extends the notion of revision control from a collec-
+ tion of files in a single directory to a hierarchical col-
+ lection of directories consisting of revision controlled
+ files. These directories and files can be combined together
+ to form a software release. cvs provides the functions
+ necessary to manage these software releases and to control
+ the concurrent editing of source files among multiple
+ software developers.
+
+And a whole lot more. See the man/cvs.1 file for more information.
+
+-------------------------------------------------------------------------------
+
+Special note to current CVS 1.3 users:
+
+--> You can skip this section and go straight to "Installation" if you <--
+--> have not been running any previous releases of CVS. <--
+
+See the NEWS file for a description of features new in this version.
+
+Some files have been renamed from the CVS 1.3 distribution. If you're
+not careful, this can cause your CVS build to fail in strange ways.
+In particular, be sure to remove the src/config.h file (which is now
+src/options.h), as the correct config.h file is generated
+automatically by the "configure" stage of installation (and installed
+in this directory).
+
+-------------------------------------------------------------------------------
+
+Installation:
+
+Please read the INSTALL file for installation instructions. Brief summary:
+
+ $ ./configure
+ $ make
+ $ make check # optional, long-running, step
+ $ make install
+ $ cvsinit
+
+-------------------------------------------------------------------------------
+
+* How do I get up-to-date information and information about other
+versions of CVS?
+
+On the web, http://www.winternet.com/~zoo/cvs/ or
+http://www.loria.fr/~molli/cvs-index.html.
+
+The mailing list for CVS is info-cvs@prep.ai.mit.edu. Send
+subscription and removal requests for that list to
+info-cvs-requests@prep.ai.mit.edu.
+
+[Historical note: info-cvs@prep.ai.mit.edu is now the union of
+ info-cvs@prep and cyclic-cvs@cyclic.com. Please use the prep
+ address.]
+
+-------------------------------------------------------------------------------
+
+Credits:
+
+The conflict-resolution algorithms and much of the administrative file
+definitions of CVS were based on the original package written by Dick Grune
+at Vrije Universiteit in Amsterdam <dick@cs.vu.nl>, and posted to
+comp.sources.unix in the volume 6 release sometime in 1986. This original
+version was a collection of shell scripts. I am thankful that Dick made
+his work available.
+
+Brian Berliner from Prisma, Inc. (now at Sun Microsystems, Inc.)
+<berliner@sun.com> converted the original CVS shell scripts into reasonably
+fast C and added many, many features to support software release control
+functions. See the manual page in the "man" directory. A copy of the
+USENIX article presented at the Winter 1990 USENIX Conference, Washington
+D.C., is included in the "doc" directory.
+
+Jeff Polk from BSDI <polk@bsdi.com> converted the CVS 1.2
+sources into much more readable and maintainable C code. He also added a
+whole lot of functionality and modularity to the code in the process.
+See the ChangeLog file.
+
+david d `zoo' zuhn <zoo@armadillo.com> contributed the working base code
+for CVS 1.4 Alpha. His work carries on from work done by K. Richard Pixley
+and others at Cygnus Support. The CVS 1.4 upgrade is due in large part to
+Zoo's efforts.
+
+David G. Grubbs <dgg@odi.com> contributed the CVS "history" and "release"
+commands. As well as the ever-so-useful "-n" option of CVS which tells CVS
+to show what it would do, without actually doing it. He also contributed
+support for the .cvsignore file.
+
+The Free Software Foundation (GNU) contributed most of the portability
+framework that CVS now uses. This can be found in the "configure" script,
+the Makefile's, and basically most of the "lib" directory.
+
+K. Richard Pixley, Cygnus Support <rich@cygnus.com> contributed many bug
+fixes/enhancement as well as completing early reviews of the CVS 1.3 manual
+pages.
+
+Roland Pesch, then of Cygnus Support <roland@wrs.com> contributed brand new
+cvs(1) and cvs(5) manual pages. We should all thank him for saving us from
+my poor use of our language!
+
+Paul Sander, HaL Computer Systems, Inc. <paul@hal.com> wrote and
+contributed the code in lib/sighandle.c. I added support for POSIX, BSD,
+and non-POSIX/non-BSD systems.
+
+Jim Kingdon and others at Cygnus Support <info@cygnus.com> wrote the
+remote repository access code.
+
+In addition to the above contributors, the following Beta testers deserve
+special mention for their support. If I have left off your name, I
+apologize. Just write to me and let me know!
+
+ Mark D. Baushke <mdb@cisco.com>
+ Per Cederqvist <ceder@signum.se>
+ J.T. Conklin (jtc@cygnus.com>
+ Vince DeMarco <vdemarco@fdcsrvr.cs.mci.com>
+ Paul Eggert <eggert@twinsun.com>
+ Lal George <george@research.att.com>
+ Dean E. Hardi <Dean.E.Hardi@ccmail.jpl.nasa.gov>
+ Mike Heath <mike@pencom.com>
+ Jim Kingdon <kingdon@cygnus.com>
+ Bernd Leibing <bernd.leibing@rz.uni-ulm.de>
+ Benedict Lofstedt <benedict@tusc.com.au>
+ Dave Love <d.love@dl.ac.uk>
+ Robert Lupton the Good <rhl@astro.princeton.edu>
+ Tom McAliney <tom@hilco.com>
+ Eberhard Mattes <mattes@azu.informatik.uni-stuttgart.de>
+ Jim Meyering <meyering@comco.com>
+ Thomas Mohr <mohr@lts.sel.alcatel.de>
+ Thomas Nilsson <thoni@softlab.se>
+ Raye Raskin <raye.raskin@lia.com>
+ Harlan Stenn <harlan@landmark.com>
+ Gunnar Tornblom <gunnar.tornblom@senet.abb.se>
+ Greg A. Woods <woods@kuma.web.net>
+
+Many contributors have added code to the "contrib" directory. See the
+README file there for a list of what is available. There is also a
+contributed GNU Emacs CVS-mode in contrib/pcl-cvs.
+
+-------------------------------------------------------------------------------
+
+ Cyclic Software <info@cyclic.com>
diff --git a/gnu/usr.bin/cvs/TODO b/gnu/usr.bin/cvs/TODO
new file mode 100644
index 0000000..1b8cb60
--- /dev/null
+++ b/gnu/usr.bin/cvs/TODO
@@ -0,0 +1,474 @@
+$CVSid: @(#)TODO 1.26 94/09/21 $
+
+14. Pathname stripper, for checkout, as well as for writing the
+ Repository file.
+ [[ I have a simple one, but need to make sure to call it at all the
+ appropriate points ]]
+ (I'm not sure what this means -kingdon, Jun 1995).
+
+16. List of current users of a directory needs to be maintained.
+ [[ sort of solved by history database ]]
+
+22. Catch signals for cleanup when "add"ing files.
+
+24. Insist on a log message.
+ (This should be configurable via commitinfo or some new config file
+ -kingdon, Jun 1995).
+
+30. Add "patch" program option to the modules database.
+
+31. Think hard about ^C recovery.
+
+35. Add "admin" command as an interface to "rcs".
+ [[ a cheesy version is there, but it should be re-done ]]
+
+38. Think hard about using RCS state information to allow one to checkin
+ a new vendor release without having it be accessed until it has been
+ integrated into the local changes.
+
+39. Think about allowing parallel source trees that can easily track
+ each other.
+ [[ sort of solved with the automagic branch support, but I want more ]]
+
+45. Consider enhancing the "patch" and "tag" command support in the module
+ database -- they seem hard to use since these commands deal directly
+ with the RCS ,v files.
+
+46. Perhaps checkout/checkin/tag/patch commands should be imbedded in the
+ file system directly, using special known command names?
+
+49. cvs xxx commands should be able to deal with files in other
+ directories. I want to do a cvs add foo/bar.c.
+ [[ most commands now use the generic recursion processor, but not all;
+ this note is left here to remind me to fix the others ]]
+
+51. a way to identify what files other people are working on. Imagine "cvs
+ modified", which prints out a table like
+
+ file modifiers
+ ===== =========
+ foo.c
+ bar.c wsd
+ baz.c nrt jda
+
+ I think this would be pretty difficult; I don't know if this
+ information is stored anywhere. Also it's hard to say how one gets a
+ user name, maybe a path to their local hierarchy is all you could get.
+ [[ the history stuff does some of this, but not all ]]
+
+52. SCCS has a feature that I would *love* to see in CVS, as it is very
+ useful. One may make a private copy of SCCS suid to a particular user,
+ so other users in the authentication list may check files in and out of
+ a project directory without mucking about with groups. Is there any
+ plan to provide a similar functionality to CVS? Our site (and, I'd
+ imagine, many other sites with large user bases) has decided against
+ having the user-groups feature of unix available to the users, due to
+ perceived administrative, technical and performance headaches. A tool
+ such as CVS with features that provide group-like functionality would
+ be a huge help.
+
+53. I'd suggest a way to notify users if/when a file(s) is being worked on.
+ I suggest:
+ + Always checkout/update files a readonly.
+ + To work on a file, the user should do:
+ cvs advise filename
+ + This would maintain their email address associated with that
+ file name in the repository and change the file mode to writable.
+ + If other references to that file exist, the registered individuals
+ are notified via email that another user(s) is going to be working
+ on same.
+ + When a committ occurs, the user is automatically 'unadvise'd (the
+ inverse command should be supported as well) and other's are notified
+ that a merge will be necessary before their checkin can be
+ successful.
+
+62. Consider using revision controlled files and directories to handle the
+ new module format -- consider a cvs command front-end to
+ add/delete/modify module contents, maybe.
+
+63. The "import" and vendor support commands (co -j) need to be documented
+ better.
+
+64. Need to greatly increase the performance of an initial checkout.
+ [[ it got better, then we added functionality, making it worse again ]]
+
+66. Length of the CVS temporary files must be limited to 14 characters for
+ System-V stupid support. As weel as the length on the CVS.adm files.
+
+67. cvs import should populate the vendor sources with CVS.adm files so
+ that one could use the vendor sources directly without having the check
+ them out.
+
+69. Consider enhacing import to add a module automatically to the module
+ database. Perhaps with a new option, or perhaps with an editor.
+
+72. Consider re-design of the module -o, -i, -t options to use the file
+ system more intuitively.
+
+73. Consider an option (in .cvsrc?) to automatically add files that are new
+ and specified to commit.
+
+74. Consider adding a way to remove directories/files that you are done
+ with... somehow.
+ [[ cvs release sort of does this ]]
+
+76. Consider adding a layer of abstraction so that CVS can work with both
+ RCS and SCCS files. Larry says this should be #ifdef'ed.
+
+79. Might be nice to have some sort of interface to TFS and tagged
+ revisions.
+
+82. Maybe the import stuff should allow an arbitrary revision to be
+ specified.
+
+84. Improve the documentation about administration of the repository and
+ how to add/remove files and the use of symbolic links.
+
+85. Add revision controlled symbolic links to CVS using one of the tag
+ fields in the RCS file.
+
+91. Better document the format of the source repository and how one might
+ convert their current SCCS or RCS files into CVS format.
+
+92. Look into this:
+ After a bit of soul searching via dbx, I realized my sin was that I'd
+ specified "echo" as the program to call from loginfo. The commit
+ procedure worked fine till it hit my echo, then silently aborted
+ leaving the lockfiles intact. Since I needn't use the loginfo
+ facility, I simply removed those commands and it all works.
+
+93. Need to think hard about release and development environments. Think
+ about execsets as well.
+
+98. If diff3 bombs out (too many differences) cvs then thinks that the file
+ has been updated and is OK to be commited even though the file
+ has not yet been merged.
+
+100. Checked out files should have revision control support. Maybe.
+
+102. Perhaps directory modes should be propagated on all import check-ins.
+ Not necessarily uid/gid changes.
+
+103. setuid/setgid on files is suspect.
+
+104. cvs should recover nicely on unreadable files/directories.
+
+105. cvs should have administrative tools to allow for changing permissions
+ and modes and what not. In particular, this would make cvs a
+ more attractive alternative to rdist.
+
+107. It should be possible to specify a list of symbolic revisions to
+ checkout such that the list is processed in reverse order looking for
+ matches within the RCS file for the symbolic revision. If there is
+ not a match, the next symbolic rev on the list is checked, and so on,
+ until all symbolic revs are exhausted. This would allow one to, say,
+ checkout "4.0" + "4.0.3" + "4.0.3Patch1" + "4.0.3Patch2" to get the
+ most recent 4.x stuff. This is usually handled by just specifying the
+ right release_tag, but most people forget to do this.
+
+108. If someone creates a whole new directory (i.e. adds it to the cvs
+ repository) and you happen to have a directory in your source farm by
+ the same name, when you do your cvs update -d it SILENTLY does
+ *nothing* to that directory. At least, I think it was silent;
+ certainly, it did *not* abort my cvs update, as it would have if the
+ same thing had happened with a file instead of a directory.
+
+109. I had gotten pieces of the sys directory in the past but not a
+ complete tree. I just did something like:
+
+ cvs get *
+
+ Where sys was in * and got the message
+
+ cvs get: Executing 'sys/tools/make_links sys'
+ sh: sys/tools/make_links: not found
+
+ I suspect this is because I didn't have the file in question,
+ but I do not understand how I could fool it into getting an
+ error. I think a later cvs get sys seemed to work so perhaps
+ something is amiss in handling multiple arguments to cvs get?
+
+113. The "cvs update" command should tee its output to a log file in ".".
+ (why? What is wrong with piping stdout to "tee"? -kingdon, Jun 1995)
+
+115. I still think "cvs modules" is a good idea.
+ Since everything else is inside cvs, "mkmodules" should be in there too:
+
+ Add a "modules" (synonym "mod") command directly in cvs.
+ ("checkout -c" is not really intuitive. I'd move it into "mod -s".)
+
+ "mod" Print database as typed. (line count as record id?)
+ "mod -s" Print the sorted database (as "checkout -c" does now)
+ "mod -m" Internal replacement for "mkmodules" command.
+ "mod module ..." Print the raw dbm record for the named modules
+ "mod -p module ..." Print relative filenames contained in modules.(no ",v")
+ "mod -l module ..." Prints more info about relative filenames ("ls -l"?)
+ "mod -f file ..." Tells you what module(s) the filenames are in.
+
+119. Consider an option to have import checkout the RCS or SCCS files
+ if necessary.
+
+122. If Name_Repository fails, it currently causes CVS to die completely. It
+ should instead return NULL and have the caller do something reasonable.
+
+123. Add a flag to import to not build vendor branches for local code.
+
+124. Anyway, I thought you might want to add something like the following
+ to the cvs and mkmodules man pages:
+
+ BUGS
+ The sum of the sizes of a module key and its contents are
+ limited. See ndbm(3).
+
+126. Do an analysis to see if CVS is forgetting to close file descriptors.
+ Especially when committing many files (more than the open file limit
+ for the particular UNIX).
+
+127. Look at *info files; they should all be quiet if the files are not
+ there. Should be able to point at a RCS directory and go.
+
+128. When I tag a file, the message tells me that I'm tagging a directory.
+
+129. Something strange seems to have happened here. When I check this out,
+ the update lines (U CFTS/...) seem to report a bogus leading CFTS
+ (e.g. U CFTS/Medusa_TS/...) when the later files are checked out.
+
+ The directory structure doesn't seem to be botched, just the
+ messages. I don't recall seeing this before.
+
+130. cvs diff with no -r arguments does not need to look up the current RCS
+ version number since it only cares about what's in the Entries file.
+ This should make it much faster.
+
+ It should ParseEntries itself and access the entries list much like
+ Version_TS does (sticky tags and sticky options may need to be
+ supported here as well). Then it should only diff the things that
+ have the wrong time stamp (the ones that look modified).
+
+134. Make a statement about using hard NFS mounts to your source
+ repository. Look into checking NULL fgets() returns with ferror() to
+ see if an error had occurred.
+
+135. The email CVS sends with each checkin, should include the version
+ number of each file it is checking in.
+ [[ Sort of solved by contrib/log.pl, which does a good job of this ]]
+
+137. Some sites might want CVS to fsync() the RCS ,v file to protect
+ against nasty hardware errors. There is a slight performance hit with
+ doing so, though, so it should be configurable in the .cvsrc file.
+ Also, along with this, we should look at the places where CVS itself
+ could be a little more synchronous so as not to lose data.
+ [[ I've done some of this, but it could use much more ]]
+
+138. Some people have suggested that CVS use a VPATH-like environment
+ variable to limit the amount of sources that need to be duplicated for
+ sites with giant source trees and no disk space.
+
+141. Import should accept modules as its directory argument.
+
+143. Update the documentation to show that the source repository is
+ something far away from the files that you work on.
+
+144. Have cvs checkout look for the environment variable CVSPREFIX
+ (or CVSMODPREFIX or some such). If it's set, then when looking
+ up an alias in the modules database, first look it up with the
+ value of CVSPREFIX attached, and then look for the alias itself.
+ This would be useful when you have several projects in a single
+ repository. You could have aliases abc_src and xyz_src and
+ tell people working on project abc to put "setenv CVSPREFIX abc_"
+ in their .cshrc file (or equivalent for other shells).
+ Then they could do "cvs co src" to get a copy of their src
+ directory, not xyz's. (This should create a directory called
+ src, not abc_src.)
+
+145. After you create revision 1.1.1.1 in the previous scenario, if
+ you do "cvs update -r1 filename" you get revision 1.1, not
+ 1.1.1.1. It would be nice to get the later revision. Again,
+ this restriction comes from RCS and is probably hard to
+ change in CVS. Sigh.
+
+ |"cvs update -r1 filename" does not tell RCS to follow any branches. CVS
+ |tries to be consistent with RCS in this fashion, so I would not change
+ |this. Within CVS we do have the flexibility of extending things, like
+ |making a revision of the form "-r1HEAD" find the most recent revision
+ |(branch or not) with a "1." prefix in the RCS file. This would get what
+ |you want maybe.
+
+ This would be very useful. Though I would prefer an option
+ such as "-v1" rather than "-r1HEAD". This option might be
+ used quite often.
+
+146. The merging of files should be controlled via a hook so that programs
+ other than "rcsmerge" can be used, like Sun's filemerge or emacs's
+ emerge.el. (but be careful in making this work client/server--it means
+ doing the interactive merging at the end after the server is done).
+
+149. On Sun, 2 Feb 92 22:01:38 EST, rouilj@dl5000.bc.edu (John P. Rouillard)
+ said:
+ Maybe there should be an option to cvs admin that allows a user to
+ change the Repository file with some degree of error checking?
+ Something like "cvs admin reposmv /old/path /new/pretty/path". Before
+ it does the replace it check to see that the files
+ /new/pretty/path/<dir>/<files> exist.
+
+150. I have a customer request for a way to specify log message per
+ file, non-interactively before the commit, such that a single, fully
+ recursive commit prompts for one commit message, and concatenates the
+ per file messages for each file. In short, one commit, one editor
+ session, log messages allowed to vary across files within the commit.
+ Also, the per file messages should be allowed to be written when the
+ files are changed, which may predate the commit considerably.
+
+ A new command seems appropriate for this. The state can be saved in the
+ CVS directory. I.e.,
+
+ % cvs msg foo.c
+ Enter log message for foo.c
+ >> fixed an uninitialized variable
+ >> ^D
+
+ The text is saved as CVS/foo.c,m (or some such name) and commit is
+ modified to append (prepend?) the text (if found) to the log message
+ specified at commit time. Easy enough.
+
+151. Also, is there a flag I am missing that allows replacing Ulrtx_Build
+ by Ultrix_build? I.E. I would like a tag replacement to be a one step
+ operation rather than a two step "cvs rtag -r Ulrtx_Build Ultrix_Build"
+ followed by "cvs trag -d Ulrtx_Build"
+
+152. The "cvs -n" option does not work as one would expect for all the
+ commands. In particular, for "commit" and "import", where one would
+ also like to see what it would do, without actually doing anything.
+
+153. There should be some command (maybe I just haven't figured
+ out which one...) to import a source directory which is already
+ RCS-administered without losing all prior RCS gathered data. Thus, it
+ would have to examine the RCS files and choose a starting version and
+ branch higher than previous ones used.
+
+154. When committing the modules file, a pre-commit check should be done to
+ verify the validity of the new modules file before allowing it to be
+ committed. This could easily be done by adding an option to mkmodules
+ to perform the verification.
+
+155. The options for "cvs history" are mutually exclusive, even though
+ useful queries can be done if they are not, as in specifying both a
+ module and a tag. A workaround is to specify the module, then run the
+ output through grep to only display lines that begin with T, which are
+ tag lines.
+
+156. Also, how hard would it be to allow continuation lines in the
+ {commit,rcs,log}info files? It would probably be useful with all of
+ the various flags that are now available, or if somebody has a lot of
+ files to put into a module.
+
+157. The "cvs release" command does not understand about module names with
+ the same flexibility that the "checkout" and "rdiff" commands do.
+ It should, though, since it's confusing right now.
+
+158. If I do a recursive commit and find that the same RCS file is checked
+ out (and modified!) in two different places within my checked-out
+ files (but within the realm of a single "commit"), CVS will commit the
+ first change, then overwrite that change with the second change. We
+ should catch this (typically unusual) case and issue an appropriate
+ diagnostic and die.
+
+159. On "update", when a merge is done, CVS should remember that your file
+ was merged into and should keep reminding you of this fact until you
+ actually look at the file (change its access time). Once you do this,
+ it should go back to being a normal, unmodified file. This way, after
+ a big update, you can run update again to see which files just got
+ merged and may need attention.
+
+160. The checks that the commit command does should be extended to make
+ sure that the revision that we will lock is not already locked by
+ someone else. Maybe it should also lock the new revision if the old
+ revision was already locked by the user as well, thus moving the lock
+ forward after the commit.
+
+161. The date parser included with CVS (lib/getdate.y) does not support
+ such RCS-supported dates as "1992/03/07". It probably should.
+
+163. The rtag/tag commands should have an option that removes the specified
+ tag from any file that is in the attic. This allows one to re-use a
+ tag (like "Mon", "Tue", ...) all the time and still have it tag the
+ real main-line code.
+
+164. The *info files should allow multiple ocurrences of $CVSROOT and/or
+ other cvs variables. They probably should *not* expand environment
+ variables, as their behavior probably should not depend on who is
+ running CVS.
+
+165. The "import" command will create RCS files automatically, but will
+ screw-up when trying to create long file names on short file name
+ file systems. Perhaps import should be a bit more cautious.
+
+166. There really needs to be a "Getting Started" document which describes
+ some of the new CVS philosophies. Folks coming straight from SCCS or
+ RCS might be confused by "cvs import". Also need to explain:
+ - How one might setup their $CVSROOT
+ - What all the tags mean in an "import" command
+ - Tags are important; revision numbers are not
+
+167. "cvs log" doesn't understand about CVS magic branch numbers. As such,
+ the command:
+
+ cvs log -r1.63.2
+ cvs log -rC2
+
+ where "C2" is a magic branch that resolves to 1.63.2 do not print the
+ same things. Sigh.
+
+169. We are using CVS as the configuration control for a software reuse library.
+ What we do is do system calls passing the needed arguments. In the next
+ release, it would be nice to see an option to put cvs .o files into a
+ archive library with an API. This enhancement would go nicely with the
+ notion of being able to integrate tools into a large software engineering
+ environment.
+
+170. Is there an "info" file that can be invoked when a file is checked out, or
+ updated ? What I want to do is to advise users, particularly novices, of
+ the state of their working source whenever they check something out, as
+ a sanity check.
+
+ For example, I've written a perl script which tells you what branch you're
+ on, if any. Hopefully this will help guard against mistaken checkins to
+ the trunk, or to the wrong branch. I suppose I can do this in
+ "commitinfo", but it'd be nice to advise people before they edit their
+ files.
+
+ It would also be nice if there was some sort of "verboseness" switch to
+ the checkout and update commands that could turn this invocation of the
+ script off, for mature users.
+
+173. We have a tagged branch in CVS. How do we get the version of that branch
+ (for an entire directory) that corresponds to the files on that branch on a
+ certain day? I'd like to specify BOTH -r and -D to 'cvs checkout', but I
+ can't. It looks like I can only specify the date for the main line (as
+ opposed to any branches). True? Any workarounds to get what I need?
+
+174. I would like to see "cvs release" modified so that it only removes files
+ which are known to CVS - all the files in the repository, plus those which
+ are listed in .cvsignore. This way, if you do leave something valuable in
+ a source tree you can "cvs release -d" the tree and your non-CVS goodies
+ are still there. If a user is going to leave non-CVS files in their source
+ trees, they really should have to clean them up by hand.
+
+175. And, in the feature request department, I'd dearly love a command-line
+ interface to adding a new module to the CVSROOT/modules file.
+
+176. If you use the -i flag in the modules file, you can control access
+ to source code; this is a Good Thing under certain circumstances. I
+ just had a nasty thought, and on experiment discovered that the
+ filter specified by -i is _not_ run before a cvs admin command; as
+ this allows a user to go behind cvs's back and delete information
+ (cvs admin -o1.4 file) this seems like a serious problem.
+
+177. We've got some external vendor source that sits under a source code
+ hierarchy, and when we do a cvs update, it gets wiped out because
+ its tag is different from the "main" distribution. I've tried to
+ use "-I" to ignore the directory, as well as .cvsignore, but this
+ doesn't work.
+
+179. "cvs admin" does not log its actions with loginfo, nor does it check
+ whether the action is allowed with commitinfo. It should.
diff --git a/gnu/usr.bin/cvs/contrib/Makefile b/gnu/usr.bin/cvs/contrib/Makefile
new file mode 100644
index 0000000..3e21c04
--- /dev/null
+++ b/gnu/usr.bin/cvs/contrib/Makefile
@@ -0,0 +1,37 @@
+# $Id: Makefile,v 1.3 1995/12/11 01:23:42 peter Exp $
+
+SUBDIR= pcl-cvs
+
+SCRIPTS= ccvs-rsh rcs2log clmerge cln_hist commit_prep cvs_acls cvscheck \
+ log log_accum mfpipe rcs-to-cvs rcs2log rcslock sccs2rcs \
+ easy-import
+
+FILES= README cvscheck.man cvshelp.man descend.man intro.doc
+
+EXAMPDIR= /usr/share/examples/cvs
+PERLPATH= /usr/bin/perl
+CLEANFILES+= $(SCRIPTS)
+
+.SUFFIXES: .sh .csh .pl
+
+all: ${SCRIPTS}
+
+.sh:
+ cp $< $@
+
+.csh:
+ sed -e 's,xCSH_PATHx,/bin/csh,' $< > $@
+
+.pl:
+ sed -e 's,xPERL_PATHx,$(PERLPATH),' $< > $@
+
+
+beforeinstall:
+ ${INSTALL} -c -o ${BINOWN} -g ${BINGRP} -m ${BINMODE} \
+ ${SCRIPTS} ${DESTDIR}${EXAMPDIR}/contrib
+ cd ${.CURDIR} ; \
+ ${INSTALL} -c -o ${BINOWN} -g ${BINGRP} -m 644 \
+ ${FILES} ${DESTDIR}${EXAMPDIR}/contrib
+
+.include "../../Makefile.inc"
+.include <bsd.prog.mk>
diff --git a/gnu/usr.bin/cvs/contrib/README b/gnu/usr.bin/cvs/contrib/README
new file mode 100644
index 0000000..e84b176
--- /dev/null
+++ b/gnu/usr.bin/cvs/contrib/README
@@ -0,0 +1,90 @@
+$CVSid: @(#)README 1.12 94/09/25 $
+
+This "contrib" directory is a place holder for code/scripts sent to
+me by contributors around the world. This README file will be kept
+up-to-date from release to release. BUT, I must point out that these
+contributions are really, REALLY UNSUPPORTED. In fact, I probably
+don't even know what they do. Nor do I guarantee to have tried them,
+or ported them to work with this CVS distribution. If you have questions,
+you might contact the author, but you should not necessarily expect
+a reply. USE AT YOUR OWN RISK -- and all that stuff.
+
+Contents of this directory:
+
+ README This file.
+ log A perl script suitable for including in your
+ $CVSROOT/CVSROOT/loginfo file for logging commit
+ changes. Includes the RCS revision of the change
+ as part of the log.
+ Contributed by Kevin Samborn <samborn@sunrise.com>.
+ pcl-cvs A directory that contains GNU Emacs lisp code which
+ implements a CVS-mode for emacs.
+ Contributed by Per Cederqvist <ceder@lysator.liu.se>.
+ commit_prep A perl script, to be combined with log_accum.pl, to
+ log_accum provide for a way to combine the individual log
+ messages of a multi-directory "commit" into a
+ single log message, and mail the result somewhere.
+ Can also do other checks for $Id and that you are
+ committing the correct revision of the file.
+ Read the comments carefully.
+ Contributed by David Hampton <hampton@cisco.com>.
+ mfpipe Another perl script for logging. Allows you to
+ pipe the log message to a file and/or send mail
+ to some alias.
+ Contributed by John Clyne <clyne@niwot.scd.ucar.edu>.
+ rcs-to-cvs Script to import sources that may have been under
+ RCS control already.
+ Contributed by Per Cederqvist <ceder@lysator.liu.se>.
+ cvscheck Identifies files added, changed, or removed in a
+ cvscheck.man checked out CVS tree; also notices unknown files.
+ Contributed by Lowell Skoog <fluke!lowell@uunet.uu.net>
+ cvshelp.man An introductory manual page written by Lowell Skoog
+ <fluke!lowell@uunet.uu.net>. It is most likely
+ out-of-date relative to CVS 1.3, but still may be
+ useful.
+ dirfns A shar file which contains some code that might
+ help your system support opendir/readdir/closedir,
+ if it does not already.
+ Copied from the C-News distribution.
+ rcslock A perl script that can be added to your commitinfo
+ file that tries to determine if your RCS file is
+ currently locked by someone else, as might be the
+ case for a binary file.
+ Contributed by John Rouillard <rouilj@cs.umb.edu>.
+ ccvs-rsh A Perl script which allows "rsh pipelines" to
+ be built in order to use Cyclic CVS from
+ behind some varieties of firewall.
+ cvs_acls A perl script that implements Access Control Lists
+ by using the "commitinfo" hook provided with the
+ "cvs commit" command.
+ Contributed by David G. Grubbs <dgg@ksr.com>.
+ descend A shell script that can be used to recursively
+ descend.man descend through a directory. In CVS 1.2, this was
+ very useful, since many of the commands were not
+ recursive. In CVS 1.3 (and later), however, most of
+ the commands are recursive. However, this may still
+ come in handy.
+ Contributed by Lowell Skoog <fluke!lowell@uunet.uu.net>
+ cln_hist A perl script to compress your
+ $CVSROOT/CVSROOT/history file, as it can grow quite
+ large after extended use.
+ Contributed by David G. Grubbs <dgg@ksr.com>
+ sccs2rcs A C-shell script that can convert (some) SCCS files
+ into RCS files, retaining the info contained in the
+ SCCS file (like dates, author, and log message).
+ Contributed by Ken Cox <kenstir@viewlogic.com>.
+ intro.doc A user's view of what you need to know to get
+ started with CVS.
+ Contributed by <Steven.Pemberton@cwi.nl>.
+ rcs2sccs A shell script to convert simple RCS files into
+ SCCS files, originally gleaned off the network
+ somewhere (originally by "kenc") and modified by
+ Jerry Jelinek <jerry@rmtc.Central.Sun.COM> and
+ Brian Berliner <berliner@sun.com> to increase
+ robustness and add support for one-level of branches.
+ rcs2log A shell script to create a ChangeLog-format file
+ given only a set of RCS files.
+ Contributed by Paul Eggert <eggert@twinsun.com>.
+ clmerge A perl script to handle merge conflicts in GNU
+ style ChangeLog files .
+ Contributed by Tom Tromey <tromey@busco.lanl.gov>.
diff --git a/gnu/usr.bin/cvs/contrib/ccvs-rsh.pl b/gnu/usr.bin/cvs/contrib/ccvs-rsh.pl
new file mode 100644
index 0000000..f01c66a
--- /dev/null
+++ b/gnu/usr.bin/cvs/contrib/ccvs-rsh.pl
@@ -0,0 +1,97 @@
+#! xPERL_PATHx
+
+# The version of the remote shell program on some Linuxes, at least,
+# misuses GNU getopt in such a way that it plucks arguments to rsh
+# that look like command-line switches from anywhere in rsh's
+# arguments. This is the Wrong Thing to do, and causes older versions
+# of CCVS to break.
+
+# In addition, if we live behind a firewall and have to construct a
+# "pipeline" of rshes through different machines in order to get to
+# the outside world, each rshd along the way undoes the hard work CCVS
+# does to put the command to be executed at the far end into a single
+# argument. Sigh.
+
+# This script is a very minimal wrapper to rsh which makes sure that
+# the commands to be executed remotely are packed into a single
+# argument before we call exec(). It works on the idea of a "proxy
+# chain", which is a set of machines you go through to get to the CCVS
+# server machine.
+
+# Each host you go through before you reach the CCVS server machine
+# should have a copy of this script somewhere (preferably accessible
+# directly from your PATH envariable). In addition, each host you go
+# through before you reach the firewall should have the CVS_PROXY_HOST
+# envariable set to the next machine in the chain, and CVS_PROXY_USER
+# set if necessary.
+
+# This really isn't as complex as it sounds. Honest.
+
+# Bryan O'Sullivan <bos@serpentine.com> April 1995
+
+$usage = "usage: ccvs-rsh hostname [-l username] command [...]\n";
+
+if ($#ARGV < 1) {
+ print STDERR $usage;
+ exit 1;
+}
+
+# Try to pick a sane version of the remote shell command to run. This
+# only understands BSD and Linux machines; if your remote shell is
+# called "remsh" under some System V (e.g. HP-SUX), you should edit
+# the line manually to suit yourself.
+
+$rsh = (-x "/usr/ucb/rsh") ? "/usr/ucb/rsh" : "/usr/bin/rsh";
+
+# If you are not rshing directly to the CCVS server machine, make the
+# following variable point at ccvs-rsh on the next machine in the
+# proxy chain. If it's accessible through the PATH envariable, you
+# can just set this to "ccvs-rsh".
+
+$ccvs_rsh = "ccvs-rsh";
+
+# There shouldn't be any user-serviceable parts beyond this point.
+
+$host = $ARGV[0];
+
+if ($ARGV[1] eq "-l") {
+ if ($#ARGV < 3) {
+ print STDERR $usage;
+ exit 1;
+ }
+ $user = $ARGV[2];
+ $cbase = 3;
+} else {
+ $cbase = 1;
+}
+
+# You might think you shoul be able to do something like
+# $command = join(' ', $ARGV[$cbase..$#ARGV]);
+# to achieve the effect of the following block of code, but it doesn't
+# work under Perl 4 on Linux, at least. Sigh.
+
+$command = $ARGV[$cbase];
+for ($cbase++; $cbase <= $#ARGV; $cbase++) {
+ $command .= " " . $ARGV[$cbase];
+}
+
+if (defined $ENV{"CVS_PROXY_HOST"}) {
+ $command = (defined $user)
+ ? "$ccvs_rsh $host -l $user $command"
+ : "$ccvs_rsh $host $command";
+
+ if (defined $ENV{"CVS_PROXY_USER"}) {
+ exec ($rsh, $ENV{"CVS_PROXY_HOST"}, "-l", $ENV{"CVS_PROXY_USER"},
+ $command);
+ } else {
+ exec ($rsh, $ENV{"CVS_PROXY_HOST"}, $command);
+ }
+} elsif (defined $user) {
+ exec ($rsh, $host, "-l", $user, $command);
+} else {
+ if (defined $ENV{"CVS_PROXY_USER"}) {
+ exec ($rsh, $host, "-l", $ENV{"CVS_PROXY_USER"}, $command);
+ } else {
+ exec ($rsh, $host, $command);
+ }
+}
diff --git a/gnu/usr.bin/cvs/contrib/clmerge.pl b/gnu/usr.bin/cvs/contrib/clmerge.pl
new file mode 100644
index 0000000..ac81371
--- /dev/null
+++ b/gnu/usr.bin/cvs/contrib/clmerge.pl
@@ -0,0 +1,152 @@
+#! xPERL_PATHx
+
+# Merge conflicted ChangeLogs
+# tromey Mon Aug 15 1994
+
+# Usage is:
+#
+# cl-merge [-i] file ...
+#
+# With -i, it works in place (backups put in a ~ file). Otherwise the
+# merged ChangeLog is printed to stdout.
+
+# Please report any bugs to me. I wrote this yesterday, so there are no
+# guarantees about its performance. I recommend checking its output
+# carefully. If you do send a bug report, please include the failing
+# ChangeLog, so I can include it in my test suite.
+#
+# Tom
+# ---
+# tromey@busco.lanl.gov Member, League for Programming Freedom
+# Sadism and farce are always inexplicably linked.
+# -- Alexander Theroux
+
+
+# Month->number mapping. Used for sorting.
+%months = ('Jan', 0,
+ 'Feb', 1,
+ 'Mar', 2,
+ 'Apr', 3,
+ 'May', 4,
+ 'Jun', 5,
+ 'Jul', 6,
+ 'Aug', 7,
+ 'Sep', 8,
+ 'Oct', 9,
+ 'Nov', 10,
+ 'Dec', 11);
+
+# If '-i' is given, do it in-place.
+if ($ARGV[0] eq '-i') {
+ shift (@ARGV);
+ $^I = '~';
+}
+
+$lastkey = '';
+$lastval = '';
+$conf = 0;
+%conflist = ();
+
+$tjd = 0;
+
+# Simple state machine. The states:
+#
+# 0 Not in conflict. Just copy input to output.
+# 1 Beginning an entry. Next non-blank line is key.
+# 2 In entry. Entry beginner transitions to state 1.
+while (<>) {
+ if (/^<<<</ || /^====/) {
+ # Start of a conflict.
+
+ # Copy last key into array.
+ if ($lastkey ne '') {
+ $conflist{$lastkey} = $lastval;
+
+ $lastkey = '';
+ $lastval = '';
+ }
+
+ $conf = 1;
+ } elsif (/^>>>>/) {
+ # End of conflict. Output.
+
+ # Copy last key into array.
+ if ($lastkey ne '') {
+ $conflist{$lastkey} = $lastval;
+
+ $lastkey = '';
+ $lastval = '';
+ }
+
+ foreach (reverse sort clcmp keys %conflist) {
+ print STDERR "doing $_" if $tjd;
+ print $_;
+ print $conflist{$_};
+ }
+
+ $lastkey = '';
+ $lastval = '';
+ $conf = 0;
+ %conflist = ();
+ } elsif ($conf == 1) {
+ # Beginning an entry. Skip empty lines. Error if not a real
+ # beginner.
+ if (/^$/) {
+ # Empty line; just skip at this point.
+ } elsif (/^[MTWFS]/) {
+ # Looks like the name of a day; assume opener and move to
+ # "in entry" state.
+ $lastkey = $_;
+ $conf = 2;
+ print STDERR "found $_" if $tjd;
+ } else {
+ die ("conflict crosses entry boundaries: $_");
+ }
+ } elsif ($conf == 2) {
+ # In entry. Copy into variable until we see beginner line.
+ if (/^[MTWFS]/) {
+ # Entry beginner line.
+
+ # Copy last key into array.
+ if ($lastkey ne '') {
+ $conflist{$lastkey} = $lastval;
+
+ $lastkey = '';
+ $lastval = '';
+ }
+
+ $lastkey = $_;
+ print STDERR "found $_" if $tjd;
+ $lastval = '';
+ } else {
+ $lastval .= $_;
+ }
+ } else {
+ # Just copy.
+ print;
+ }
+}
+
+# Compare ChangeLog time strings like <=>.
+#
+# 0 1 2 3
+# Thu Aug 11 13:22:42 1994 Tom Tromey (tromey@creche.colorado.edu)
+# 0123456789012345678901234567890
+#
+sub clcmp {
+ # First check year.
+ $r = substr ($a, 20, 4) <=> substr ($b, 20, 4);
+
+ # Now check month.
+ $r = $months{substr ($a, 4, 3)} <=> $months{substr ($b, 4, 3)} if !$r;
+
+ # Now check day.
+ $r = substr ($a, 8, 2) <=> substr ($b, 8, 2) if !$r;
+
+ # Now check time (3 parts).
+ $r = substr ($a, 11, 2) <=> substr ($b, 11, 2) if !$r;
+ $r = substr ($a, 14, 2) <=> substr ($b, 14, 2) if !$r;
+ $r = substr ($a, 17, 2) <=> substr ($b, 17, 2) if !$r;
+
+ $r;
+}
diff --git a/gnu/usr.bin/cvs/contrib/cln_hist.pl b/gnu/usr.bin/cvs/contrib/cln_hist.pl
new file mode 100644
index 0000000..ff49d0a
--- /dev/null
+++ b/gnu/usr.bin/cvs/contrib/cln_hist.pl
@@ -0,0 +1,92 @@
+#! xPERL_PATHx
+# -*-Perl-*-
+#
+# $Id: cln_hist.pl,v 1.2 1995/07/10 02:01:26 kfogel Exp $
+# Contributed by David G. Grubbs <dgg@ksr.com>
+#
+# Clean up the history file. 10 Record types: MAR OFT WUCG
+#
+# WUCG records are thrown out.
+# MAR records are retained.
+# T records: retain only last tag with same combined tag/module.
+#
+# Two passes: Walk through the first time and remember the
+# 1. Last Tag record with same "tag" and "module" names.
+# 2. Last O record with unique user/module/directory, unless followed
+# by a matching F record.
+#
+
+$r = $ENV{"CVSROOT"};
+$c = "$r/CVSROOT";
+$h = "$c/history";
+
+eval "print STDERR \$die='Unknown parameter $1\n' if !defined \$$1; \$$1=\$';"
+ while ($ARGV[0] =~ /^(\w+)=/ && shift(@ARGV));
+exit 255 if $die; # process any variable=value switches
+
+%tags = ();
+%outs = ();
+
+#
+# Move history file to safe place and re-initialize a new one.
+#
+rename($h, "$h.bak");
+open(XX, ">$h");
+close(XX);
+
+#
+# Pass1 -- remember last tag and checkout.
+#
+open(HIST, "$h.bak");
+while (<HIST>) {
+ next if /^[MARWUCG]/;
+
+ # Save whole line keyed by tag|module
+ if (/^T/) {
+ @tmp = split(/\|/, $_);
+ $tags{$tmp[4] . '|' . $tmp[5]} = $_;
+ }
+ # Save whole line
+ if (/^[OF]/) {
+ @tmp = split(/\|/, $_);
+ $outs{$tmp[1] . '|' . $tmp[2] . '|' . $tmp[5]} = $_;
+ }
+}
+
+#
+# Pass2 -- print out what we want to save.
+#
+open(SAVE, ">$h.work");
+open(HIST, "$h.bak");
+while (<HIST>) {
+ next if /^[FWUCG]/;
+
+ # If whole line matches saved (i.e. "last") one, print it.
+ if (/^T/) {
+ @tmp = split(/\|/, $_);
+ next if $tags{$tmp[4] . '|' . $tmp[5]} ne $_;
+ }
+ # Save whole line
+ if (/^O/) {
+ @tmp = split(/\|/, $_);
+ next if $outs{$tmp[1] . '|' . $tmp[2] . '|' . $tmp[5]} ne $_;
+ }
+
+ print SAVE $_;
+}
+
+#
+# Put back the saved stuff
+#
+system "cat $h >> $h.work";
+
+if (-s $h) {
+ rename ($h, "$h.interim");
+ print "history.interim has non-zero size.\n";
+} else {
+ unlink($h);
+}
+
+rename ("$h.work", $h);
+
+exit(0);
diff --git a/gnu/usr.bin/cvs/contrib/commit_prep.pl b/gnu/usr.bin/cvs/contrib/commit_prep.pl
new file mode 100644
index 0000000..5272c04
--- /dev/null
+++ b/gnu/usr.bin/cvs/contrib/commit_prep.pl
@@ -0,0 +1,216 @@
+#! xPERL_PATHx
+# -*-Perl-*-
+#
+#ident "@(#)cvs/contrib:$Name: $:$Id: commit_prep.pl,v 1.2 1995/07/10 02:01:29 kfogel Exp $"
+#
+# Perl filter to handle pre-commit checking of files. This program
+# records the last directory where commits will be taking place for
+# use by the log_accum.pl script. For new files, it forces the
+# existence of a RCS "Id" keyword in the first ten lines of the file.
+# For existing files, it checks version number in the "Id" line to
+# prevent losing changes because an old version of a file was copied
+# into the direcory.
+#
+# Possible future enhancements:
+#
+# Check for cruft left by unresolved conflicts. Search for
+# "^<<<<<<<$", "^-------$", and "^>>>>>>>$".
+#
+# Look for a copyright and automagically update it to the
+# current year. [[ bad idea! -- woods ]]
+#
+#
+# Contributed by David Hampton <hampton@cisco.com>
+#
+# Hacked on lots by Greg A. Woods <woods@web.net>
+
+#
+# Configurable options
+#
+
+# Constants (remember to protect strings from RCS keyword substitution)
+#
+$LAST_FILE = "/tmp/#cvs.lastdir"; # must match name in log_accum.pl
+$ENTRIES = "CVS/Entries";
+
+# Patterns to find $Log keywords in files
+#
+$LogString1 = "\\\$\\Log: .* \\\$";
+$LogString2 = "\\\$\\Log\\\$";
+$NoLog = "%s - contains an RCS \$Log keyword. It must not!\n";
+
+# pattern to match an RCS Id keyword line with an existing ID
+#
+$IDstring = "\"@\\(#\\)[^:]*:.*\\\$\Id: .*\\\$\"";
+$NoId = "
+%s - Does not contain a properly formatted line with the keyword \"Id:\".
+ I.e. no lines match \"" . $IDstring . "\".
+ Please see the template files for an example.\n";
+
+# pattern to match an RCS Id keyword line for a new file (i.e. un-expanded)
+#
+$NewId = "\"@(#)[^:]*:.*\\$\Id\\$\"";
+
+$NoName = "
+%s - The ID line should contain only \"@(#)module/path:\$Name\$:\$\Id\$\"
+ for a newly created file.\n";
+
+$BadName = "
+%s - The file name '%s' in the ID line does not match
+ the actual filename.\n";
+
+$BadVersion = "
+%s - How dare you!!! You replaced your copy of the file '%s',
+ which was based upon version %s, with an %s version based
+ upon %s. Please move your '%s' out of the way, perform an
+ update to get the current version, and them merge your changes
+ into that file, then try the commit again.\n";
+
+#
+# Subroutines
+#
+
+sub write_line {
+ local($filename, $line) = @_;
+ open(FILE, ">$filename") || die("Cannot open $filename, stopped");
+ print(FILE $line, "\n");
+ close(FILE);
+}
+
+sub check_version {
+ local($i, $id, $rname, $version);
+ local($filename, $cvsversion) = @_;
+
+ open(FILE, "<$filename") || return(0);
+
+ @all_lines = ();
+ $idpos = -1;
+ $newidpos = -1;
+ for ($i = 0; <FILE>; $i++) {
+ chop;
+ push(@all_lines, $_);
+ if ($_ =~ /$IDstring/) {
+ $idpos = $i;
+ }
+ if ($_ =~ /$NewId/) {
+ $newidpos = $i;
+ }
+ }
+
+ if (grep(/$LogString1/, @all_lines) || grep(/$LogString2/, @all_lines)) {
+ print STDERR sprintf($NoLog, $filename);
+ return(1);
+ }
+
+ if ($debug != 0) {
+ print STDERR sprintf("file = %s, version = %d.\n", $filename, $cvsversion{$filename});
+ }
+
+ if ($cvsversion{$filename} == 0) {
+ if ($newidpos != -1 && $all_lines[$newidpos] !~ /$NewId/) {
+ print STDERR sprintf($NoName, $filename);
+ return(1);
+ }
+ return(0);
+ }
+
+ if ($idpos == -1) {
+ print STDERR sprintf($NoId, $filename);
+ return(1);
+ }
+
+ $line = $all_lines[$idpos];
+ $pos = index($line, "Id: ");
+ if ($debug != 0) {
+ print STDERR sprintf("%d in '%s'.\n", $pos, $line);
+ }
+ ($id, $rname, $version) = split(' ', substr($line, $pos));
+ if ($rname ne "$filename,v") {
+ print STDERR sprintf($BadName, $filename, substr($rname, 0, length($rname)-2));
+ return(1);
+ }
+ if ($cvsversion{$filename} < $version) {
+ print STDERR sprintf($BadVersion, $filename, $filename, $cvsversion{$filename},
+ "newer", $version, $filename);
+ return(1);
+ }
+ if ($cvsversion{$filename} > $version) {
+ print STDERR sprintf($BadVersion, $filename, $filename, $cvsversion{$filename},
+ "older", $version, $filename);
+ return(1);
+ }
+ return(0);
+}
+
+#
+# Main Body
+#
+
+$id = getpgrp(); # You *must* use a shell that does setpgrp()!
+
+# Check each file (except dot files) for an RCS "Id" keyword.
+#
+$check_id = 0;
+
+# Record the directory for later use by the log_accumulate stript.
+#
+$record_directory = 0;
+
+# parse command line arguments
+#
+while (@ARGV) {
+ $arg = shift @ARGV;
+
+ if ($arg eq '-d') {
+ $debug = 1;
+ print STDERR "Debug turned on...\n";
+ } elsif ($arg eq '-c') {
+ $check_id = 1;
+ } elsif ($arg eq '-r') {
+ $record_directory = 1;
+ } else {
+ push(@files, $arg);
+ }
+}
+
+$directory = shift @files;
+
+if ($debug != 0) {
+ print STDERR "dir - ", $directory, "\n";
+ print STDERR "files - ", join(":", @files), "\n";
+ print STDERR "id - ", $id, "\n";
+}
+
+# Suck in the CVS/Entries file
+#
+open(ENTRIES, $ENTRIES) || die("Cannot open $ENTRIES.\n");
+while (<ENTRIES>) {
+ local($filename, $version) = split('/', substr($_, 1));
+ $cvsversion{$filename} = $version;
+}
+
+# Now check each file name passed in, except for dot files. Dot files
+# are considered to be administrative files by this script.
+#
+if ($check_id != 0) {
+ $failed = 0;
+ foreach $arg (@files) {
+ if (index($arg, ".") == 0) {
+ next;
+ }
+ $failed += &check_version($arg);
+ }
+ if ($failed) {
+ print STDERR "\n";
+ exit(1);
+ }
+}
+
+# Record this directory as the last one checked. This will be used
+# by the log_accumulate script to determine when it is processing
+# the final directory of a multi-directory commit.
+#
+if ($record_directory != 0) {
+ &write_line("$LAST_FILE.$id", $directory);
+}
+exit(0);
diff --git a/gnu/usr.bin/cvs/contrib/cvs-format.el b/gnu/usr.bin/cvs/contrib/cvs-format.el
new file mode 100644
index 0000000..cdbd842
--- /dev/null
+++ b/gnu/usr.bin/cvs/contrib/cvs-format.el
@@ -0,0 +1,81 @@
+;; -*- lisp-interaction -*-
+;; -*- emacs-lisp -*-
+;;
+;;
+;; originally from...
+;; Rich's personal .emacs file. feel free to copy.
+;;
+;; Last Mod Wed Feb 5 16:11:47 PST 1992, by rich@cygnus.com
+;;
+
+;;
+;;
+;; This section sets constants used by c-mode for formating
+;;
+;;
+
+;; If `c-auto-newline' is non-`nil', newlines are inserted both
+;;before and after braces that you insert, and after colons and semicolons.
+;;Correct C indentation is done on all the lines that are made this way.
+
+(setq c-auto-newline nil)
+
+
+;;*Non-nil means TAB in C mode should always reindent the current line,
+;;regardless of where in the line point is when the TAB command is used.
+;;It might be desirable to set this to nil for CVS, since unlike GNU
+;; CVS often uses comments over to the right separated by TABs.
+;; Depends some on whether you're in the habit of using TAB to
+;; reindent.
+;(setq c-tab-always-indent nil)
+
+;;; It seems to me that
+;;; `M-x set-c-style BSD RET'
+;;; or
+;;; (set-c-style "BSD")
+;;; takes care of the indentation parameters correctly.
+
+
+;; C does not have anything analogous to particular function names for which
+;;special forms of indentation are desirable. However, it has a different
+;;need for customization facilities: many different styles of C indentation
+;;are in common use.
+;;
+;; There are six variables you can set to control the style that Emacs C
+;;mode will use.
+;;
+;;`c-indent-level'
+;; Indentation of C statements within surrounding block. The surrounding
+;; block's indentation is the indentation of the line on which the
+;; open-brace appears.
+
+(setq c-indent-level 4)
+
+;;`c-continued-statement-offset'
+;; Extra indentation given to a substatement, such as the then-clause of
+;; an if or body of a while.
+
+(setq c-continued-statement-offset 4)
+
+;;`c-brace-offset'
+;; Extra indentation for line if it starts with an open brace.
+
+(setq c-brace-offset -4)
+
+;;`c-brace-imaginary-offset'
+;; An open brace following other text is treated as if it were this far
+;; to the right of the start of its line.
+
+(setq c-brace-imaginary-offset 0)
+
+;;`c-argdecl-indent'
+;; Indentation level of declarations of C function arguments.
+
+(setq c-argdecl-indent 4)
+
+;;`c-label-offset'
+;; Extra indentation for line that is a label, or case or default.
+
+(setq c-label-offset -4)
+
+;;;; eof
diff --git a/gnu/usr.bin/cvs/contrib/cvs_acls.pl b/gnu/usr.bin/cvs/contrib/cvs_acls.pl
new file mode 100644
index 0000000..bcb544d
--- /dev/null
+++ b/gnu/usr.bin/cvs/contrib/cvs_acls.pl
@@ -0,0 +1,143 @@
+#! xPERL_PATHx
+# -*-Perl-*-
+#
+# $Id: cvs_acls.pl,v 1.2 1995/07/10 02:01:33 kfogel Exp $
+#
+# Access control lists for CVS. dgg@ksr.com (David G. Grubbs)
+#
+# CVS "commitinfo" for matching repository names, running the program it finds
+# on the same line. More information is available in the CVS man pages.
+#
+# ==== INSTALLATION:
+#
+# To use this program as I intended, do the following four things:
+#
+# 0. Install PERL. :-)
+#
+# 1. Put one line, as the *only* non-comment line, in your commitinfo file:
+#
+# DEFAULT /usr/local/bin/cvs_acls
+#
+# 2. Install this file as /usr/local/bin/cvs_acls and make it executable.
+#
+# 3. Create a file named $CVSROOT/CVSROOT/avail.
+#
+# ==== FORMAT OF THE avail FILE:
+#
+# The avail file determines whether you may commit files. It contains lines
+# read from top to bottom, keeping track of a single "bit". The "bit"
+# defaults to "on". It can be turned "off" by "unavail" lines and "on" by
+# "avail" lines. ==> Last one counts.
+#
+# Any line not beginning with "avail" or "unavail" is ignored.
+#
+# Lines beginning with "avail" or "unavail" are assumed to be '|'-separated
+# triples: (All spaces and tabs are ignored in a line.)
+#
+# {avail.*,unavail.*} [| user,user,... [| repos,repos,...]]
+#
+# 1. String starting with "avail" or "unavail".
+# 2. Optional, comma-separated list of usernames.
+# 3. Optional, comma-separated list of repository pathnames.
+# These are pathnames relative to $CVSROOT. They can be directories or
+# filenames. A directory name allows access to all files and
+# directories below it.
+#
+# Example: (Text from the ';;' rightward may not appear in the file.)
+#
+# unavail ;; Make whole repository unavailable.
+# avail|dgg ;; Except for user "dgg".
+# avail|fred, john|bin/ls ;; Except when "fred" or "john" commit to
+# ;; the module whose repository is "bin/ls"
+#
+# PROGRAM LOGIC:
+#
+# CVS passes to @ARGV an absolute directory pathname (the repository
+# appended to your $CVSROOT variable), followed by a list of filenames
+# within that directory.
+#
+# We walk through the avail file looking for a line that matches both
+# the username and repository.
+#
+# A username match is simply the user's name appearing in the second
+# column of the avail line in a space-or-comma separate list.
+#
+# A repository match is either:
+# - One element of the third column matches $ARGV[0], or some
+# parent directory of $ARGV[0].
+# - Otherwise *all* file arguments ($ARGV[1..$#ARGV]) must be
+# in the file list in one avail line.
+# - In other words, using directory names in the third column of
+# the avail file allows committing of any file (or group of
+# files in a single commit) in the tree below that directory.
+# - If individual file names are used in the third column of
+# the avail file, then files must be committed individually or
+# all files specified in a single commit must all appear in
+# third column of a single avail line.
+#
+
+$debug = 0;
+$cvsroot = $ENV{'CVSROOT'};
+$availfile = $cvsroot . "/CVSROOT/avail";
+$myname = $ENV{"USER"} if !($myname = $ENV{"LOGNAME"});
+
+eval "print STDERR \$die='Unknown parameter $1\n' if !defined \$$1; \$$1=\$';"
+ while ($ARGV[0] =~ /^(\w+)=/ && shift(@ARGV));
+exit 255 if $die; # process any variable=value switches
+
+die "Must set CVSROOT\n" if !$cvsroot;
+($repos = shift) =~ s:^$cvsroot/::;
+grep($_ = $repos . '/' . $_, @ARGV);
+
+print "$$ Repos: $repos\n","$$ ==== ",join("\n$$ ==== ",@ARGV),"\n" if $debug;
+
+$exit_val = 0; # Good Exit value
+
+$universal_off = 0;
+open (AVAIL, $availfile) || exit(0); # It is ok for avail file not to exist
+while (<AVAIL>) {
+ chop;
+ next if /^\s*\#/;
+ next if /^\s*$/;
+ ($flagstr, $u, $m) = split(/[\s,]*\|[\s,]*/, $_);
+
+ # Skip anything not starting with "avail" or "unavail" and complain.
+ (print "Bad avail line: $_\n"), next
+ if ($flagstr !~ /^avail/ && $flagstr !~ /^unavail/);
+
+ # Set which bit we are playing with. ('0' is OK == Available).
+ $flag = (($& eq "avail") ? 0 : 1);
+
+ # If we find a "universal off" flag (i.e. a simple "unavail") remember it
+ $universal_off = 1 if ($flag && !$u && !$m);
+
+ # $myname considered "in user list" if actually in list or is NULL
+ $in_user = (!$u || grep ($_ eq $myname, split(/[\s,]+/,$u)));
+ print "$$ \$myname($myname) in user list: $_\n" if $debug && $in_user;
+
+ # Module matches if it is a NULL module list in the avail line. If module
+ # list is not null, we check every argument combination.
+ if (!($in_repo = !$m)) {
+ @tmp = split(/[\s,]+/,$m);
+ for $j (@tmp) {
+ # If the repos from avail is a parent(or equal) dir of $repos, OK
+ $in_repo = 1, last if ($repos eq $j || $repos =~ /^$j\//);
+ }
+ if (!$in_repo) {
+ $in_repo = 1;
+ for $j (@ARGV) {
+ last if !($in_repo = grep ($_ eq $j, @tmp));
+ }
+ }
+ }
+ print "$$ \$repos($repos) in repository list: $_\n" if $debug && $in_repo;
+
+ $exit_val = $flag if ($in_user && $in_repo);
+ print "$$ ==== \$exit_val = $exit_val\n$$ ==== \$flag = $flag\n" if $debug;
+}
+close(AVAIL);
+print "$$ ==== \$exit_val = $exit_val\n" if $debug;
+print "**** Access denied: Insufficient Karma ($myname|$repos)\n" if $exit_val;
+print "**** Access allowed: Personal Karma exceeds Environmental Karma.\n"
+ if $universal_off && !$exit_val;
+exit($exit_val);
diff --git a/gnu/usr.bin/cvs/contrib/cvscheck.man b/gnu/usr.bin/cvs/contrib/cvscheck.man
new file mode 100644
index 0000000..61a064a
--- /dev/null
+++ b/gnu/usr.bin/cvs/contrib/cvscheck.man
@@ -0,0 +1,53 @@
+.\" $Id: cvscheck.man,v 1.1.1.3 1995/08/28 16:20:24 jimb Exp $
+.\" Contributed by Lowell Skoog <fluke!lowell@uunet.uu.net>
+.TH CVSCHECK LOCAL "4 March 1991" FLUKE
+.SH NAME
+cvscheck \- identify files added, changed, or removed in a CVS working
+directory
+.SH SYNOPSIS
+.B cvscheck
+.SH DESCRIPTION
+This command is a housekeeping aid. It should be run in a working
+directory that has been checked out using CVS. It identifies files
+that have been added, changed, or removed in the working directory, but
+not CVS
+.BR commit ted.
+It also determines whether the files have been CVS
+.BR add ed
+or CVS
+.BR remove d.
+For directories, this command determines only whether they have been
+.BR add ed.
+It operates in the current directory only.
+.LP
+This command provides information that is available using CVS
+.B status
+and CVS
+.BR diff .
+The advantage of
+.B cvscheck
+is that its output is very concise. It saves you the strain (and
+potential error) of interpreting the output of CVS
+.B status
+and
+.BR diff .
+.LP
+See
+.BR cvs (local)
+or
+.BR cvshelp (local)
+for instructions on how to add or remove a file or directory in a
+CVS-controlled package.
+.SH DIAGNOSTICS
+The exit status is 0 if no files have been added, changed, or removed
+from the current directory. Otherwise, the command returns a count of
+the adds, changes, and deletes.
+.SH SEE ALSO
+.BR cvs (local),
+.BR cvshelp (local)
+.SH AUTHOR
+Lowell Skoog
+.br
+Software Technology Group
+.br
+Technical Computing
diff --git a/gnu/usr.bin/cvs/contrib/cvscheck.sh b/gnu/usr.bin/cvs/contrib/cvscheck.sh
new file mode 100644
index 0000000..96dba6e
--- /dev/null
+++ b/gnu/usr.bin/cvs/contrib/cvscheck.sh
@@ -0,0 +1,84 @@
+#! /bin/sh
+# $Id: cvscheck.sh,v 1.1 1995/07/10 02:26:29 kfogel Exp $
+#
+# cvscheck - identify files added, changed, or removed
+# in CVS working directory
+#
+# Contributed by Lowell Skoog <fluke!lowell@uunet.uu.net>
+#
+# This program should be run in a working directory that has been
+# checked out using CVS. It identifies files that have been added,
+# changed, or removed in the working directory, but not "cvs
+# committed". It also determines whether the files have been "cvs
+# added" or "cvs removed". For directories, it is only practical to
+# determine whether they have been added.
+
+name=cvscheck
+changes=0
+
+# If we can't run CVS commands in this directory
+cvs status . > /dev/null 2>&1
+if [ $? != 0 ] ; then
+
+ # Bail out
+ echo "$name: there is no version here; bailing out" 1>&2
+ exit 1
+fi
+
+# Identify files added to working directory
+for file in .* * ; do
+
+ # Skip '.' and '..'
+ if [ $file = '.' -o $file = '..' ] ; then
+ continue
+ fi
+
+ # If a regular file
+ if [ -f $file ] ; then
+ if cvs status $file | grep -s '^From:[ ]*New file' ; then
+ echo "file added: $file - not CVS committed"
+ changes=`expr $changes + 1`
+ elif cvs status $file | grep -s '^From:[ ]*no entry for' ; then
+ echo "file added: $file - not CVS added, not CVS committed"
+ changes=`expr $changes + 1`
+ fi
+
+ # Else if a directory
+ elif [ -d $file -a $file != CVS.adm ] ; then
+
+ # Move into it
+ cd $file
+
+ # If CVS commands don't work inside
+ cvs status . > /dev/null 2>&1
+ if [ $? != 0 ] ; then
+ echo "directory added: $file - not CVS added"
+ changes=`expr $changes + 1`
+ fi
+
+ # Move back up
+ cd ..
+ fi
+done
+
+# Identify changed files
+changedfiles=`cvs diff | egrep '^diff' | awk '{print $3}'`
+for file in $changedfiles ; do
+ echo "file changed: $file - not CVS committed"
+ changes=`expr $changes + 1`
+done
+
+# Identify files removed from working directory
+removedfiles=`cvs status | egrep '^File:[ ]*no file' | awk '{print $4}'`
+
+# Determine whether each file has been cvs removed
+for file in $removedfiles ; do
+ if cvs status $file | grep -s '^From:[ ]*-' ; then
+ echo "file removed: $file - not CVS committed"
+ else
+ echo "file removed: $file - not CVS removed, not CVS committed"
+ fi
+ changes=`expr $changes + 1`
+done
+
+exit $changes
diff --git a/gnu/usr.bin/cvs/contrib/cvshelp.man b/gnu/usr.bin/cvs/contrib/cvshelp.man
new file mode 100644
index 0000000..2cfae1f
--- /dev/null
+++ b/gnu/usr.bin/cvs/contrib/cvshelp.man
@@ -0,0 +1,562 @@
+.\" $Id: cvshelp.man,v 1.1.1.3 1995/08/28 16:20:28 jimb Exp $
+.\" Contributed by Lowell Skoog <fluke!lowell@uunet.uu.net>
+.\" Full space in nroff; half space in troff
+.de SP
+.if n .sp
+.if t .sp .5
+..
+.\" Start a command example
+.de XS
+.SP
+.in +.5i
+.ft B
+.nf
+..
+.\" End a command example
+.de XE
+.fi
+.ft P
+.in -.5i
+.SP
+..
+.TH CVSHELP LOCAL "17 March 1991" FLUKE
+.SH NAME
+cvshelp \- advice on using the Concurrent Versions System
+.SH DESCRIPTION
+This man page is based on experience using CVS.
+It is bound to change as we gain more experience.
+If you come up with better advice than is found here,
+contact the Software Technology
+Group and we will add it to this page.
+.SS "Getting Started"
+Use the following steps to prepare to use CVS:
+.TP
+\(bu
+Take a look at the CVS manual page to see what it can do for you, and
+if it fits your environment (or can possibly be made to fit your
+environment).
+.XS
+man cvs
+.XE
+If things look good, continue on...
+.TP
+\(bu
+Setup the master source repository. Choose a directory with
+ample disk space available for source files. This is where the RCS
+`,v' files will be stored. Say you choose
+.B /src/master
+as the root
+of your source repository. Make the
+.SB CVSROOT.adm
+directory in the root of the source repository:
+.XS
+mkdir /src/master/CVSROOT.adm
+.XE
+.TP
+\(bu
+Populate this directory with the
+.I loginfo
+and
+.I modules
+files from the
+.B "/usr/doc/local/cvs"
+directory. Edit these files to reflect your local source repository
+environment \- they may be quite small initially, but will grow as
+sources are added to your source repository. Turn these files into
+RCS controlled files:
+.XS
+cd /src/master/CVSROOT.adm
+ci \-m'Initial loginfo file' loginfo
+ci \-m'Initial modules file' modules
+.XE
+.TP
+\(bu
+Run the command:
+.XS
+mkmodules /src/master/CVSROOT.adm
+.XE
+This will build the
+.BR ndbm (3)
+file for the modules database.
+.TP
+\(bu
+Remember to edit the
+.I modules
+file manually when sources are checked
+in with
+.B checkin
+or CVS
+.BR add .
+A copy of the
+.I modules
+file for editing can be retrieved with the command:
+.XS
+cvs checkout CVSROOT.adm
+.XE
+.TP
+\(bu
+Have all users of the CVS system set the
+.SM CVSROOT
+environment variable appropriately to reflect the placement of your
+source repository. If the above example is used, the following
+commands can be placed in a
+.I .login
+or
+.I .profile
+file:
+.XS
+setenv CVSROOT /src/master
+.XE
+for csh users, and
+.XS
+CVSROOT=/src/master; export CVSROOT
+.XE
+for sh users.
+.SS "Placing Locally Written Sources Under CVS Control"
+Say you want to place the `whizbang' sources under
+CVS control. Say further that the sources have never
+been under revision control before.
+.TP
+\(bu
+Move the source hierarchy (lock, stock, and barrel)
+into the master source repository:
+.XS
+mv ~/whizbang $CVSROOT
+.XE
+.TP
+\(bu
+Clean out unwanted object files:
+.XS
+cd $CVSROOT/whizbang
+make clean
+.XE
+.TP
+\(bu
+Turn every file in the hierarchy into an RCS controlled file:
+.XS
+descend \-f 'ci \-t/dev/null \-m"Placed under CVS control" \-nV\fR\fIx\fR\fB_\fR\fIy\fR\fB *'
+.XE
+In this example, the initial release tag is \fBV\fIx\fB_\fIy\fR,
+representing version \fIx\fR.\fIy\fR.
+.LP
+You can use CVS on sources that are already under RCS control.
+The following example shows how.
+In this example, the source package is called `skunkworks'.
+.TP
+\(bu
+Move the source hierarchy into the master source
+repository:
+.XS
+mv ~/skunkworks $CVSROOT
+.XE
+.TP
+\(bu
+Clean out unwanted object files:
+.XS
+cd $CVSROOT/skunkworks
+make clean
+.XE
+.TP
+\(bu
+Clean out unwanted working files, leaving only the RCS `,v' files:
+.XS
+descend \-r rcsclean
+.XE
+Note: If any working files have been checked out and changed,
+.B rcsclean
+will fail. Check in the modified working files
+and run the command again.
+.TP
+\(bu
+Get rid of
+.SB RCS
+subdirectories. CVS does not use them.
+.XS
+descend \-r \-f 'mv RCS/*,v .'
+descend \-r \-f 'rmdir RCS'
+.XE
+.TP
+\(bu
+Delete any unwanted files that remain in the source hierarchy. Then
+make sure all files are under RCS control:
+.XS
+descend \-f 'ci \-t/dev/null \-m"Placed under CVS control" \-n\fR\fItag\fR\fB *'
+.XE
+.I tag
+is the latest symbolic revision tag that you applied to your package
+(if any). Note: This command will probably generate lots of error
+messages (for directories and existing RCS files) that you can
+ignore.
+.SS "Placing a Third-Party Source Distribution Under CVS Control"
+The
+.B checkin
+command checks third-party sources into CVS. The
+difference between third-party sources and locally
+written sources is that third-party sources must be checked into a
+separate branch (called the
+.IR "vendor branch" )
+of the RCS tree. This makes it possible to merge local changes to
+the sources with later releases from the vendor.
+.TP
+\(bu
+Save the original distribution kit somewhere. For example, if the
+master source repository is
+.B /src/master
+the distribution kit could be saved in
+.BR /src/dist .
+Organize the distribution directory so that each release
+is clearly identifiable.
+.TP
+\(bu
+Unpack the package in a scratch directory, for example
+.BR ~/scratch .
+.TP
+\(bu
+Create a repository for the package.
+In this example, the package is called `Bugs-R-Us 4.3'.
+.XS
+mkdir $CVSROOT/bugs
+.XE
+.TP
+\(bu
+Check in the unpacked files:
+.XS
+cd ~/scratch
+checkin \-m 'Bugs-R-Us 4.3 distribution' bugs VENDOR V4_3
+.XE
+There is nothing magic about the tag `VENDOR', which is applied to
+the vendor branch. You can use whatever tag you want. `VENDOR' is a
+useful convention.
+.TP
+\(bu
+Never modify vendor files before checking them in.
+Check in the files
+.I exactly
+as you unpacked them.
+If you check in locally modified files, future vendor releases may
+wipe out your local changes.
+.SS "Working With CVS-Controlled Sources"
+To use or edit the sources, you must check out a private copy.
+For the following examples, the master files are assumed to reside in
+.BR "$CVSROOT/behemoth" .
+The working directory is
+.BR "~/work" .
+See
+.BR cvs (local)
+for more details on the commands mentioned below.
+.TP
+.I "To Check Out Working Files
+Use CVS
+.BR checkout :
+.XS
+cd ~/work
+cvs checkout behemoth
+.XE
+There is nothing magic about the working directory. CVS will check
+out sources anywhere you like. Once you have a working copy of the
+sources, you can compile or edit them as desired.
+.TP
+.I "To Display Changes You Have Made"
+Use CVS
+.BR diff
+to display detailed changes, equivalent to
+.BR rcsdiff (local).
+You can also use
+.BR cvscheck (local)
+to list files added, changed, and removed in
+the directory, but not yet
+.BR commit ted.
+You must be in a directory containing working files.
+.TP
+.I "To Display Revision Information"
+Use CVS
+.BR log ,
+which is equivalent to
+.BR rlog (local).
+You must be in a directory containing working files.
+.TP
+.I "To Update Working Files"
+Use CVS
+.BR update
+in a directory containing working files.
+This command brings your working files up
+to date with changes checked into the
+master repository since you last checked out or updated
+your files.
+.TP
+.I "To Check In Your Changes"
+Use CVS
+.BR commit
+in a directory containing working files.
+This command checks your changes into the master repository.
+You can specify files by name or use
+.XS
+cvs commit \-a
+.XE
+to
+.B commit
+all the files you have changed.
+.TP
+.I "To Add a File"
+Add the file to the working directory.
+Use CVS
+.B add
+to mark the file as added.
+Use CVS
+.B commit
+to add the file to the master repository.
+.TP
+.I "To Remove a File"
+Remove the file from the working directory.
+Use CVS
+.B remove
+to mark the file as removed.
+Use CVS
+.B commit
+to move the file from its current location in the master repository
+to the CVS
+.IR Attic
+directory.
+.TP
+.I "To Add a Directory"
+Add the directory to the working directory.
+Use CVS
+.B add
+to add the directory to the master repository.
+.TP
+.I "To Remove a Directory"
+.br
+You shouldn't remove directories under CVS. You should instead remove
+their contents and then prune them (using the
+.B \-f
+and
+.B \-p
+options) when you
+.B checkout
+or
+.B update
+your working files.
+.TP
+.I "To Tag a Release"
+Use CVS
+.B tag
+to apply a symbolic tag to the latest revision of each file in the
+master repository. For example:
+.XS
+cvs tag V2_1 behemoth
+.XE
+.TP
+.I "To Retrieve an Exact Copy of a Previous Release"
+During a CVS
+.B checkout
+or
+.BR update ,
+use the
+.B \-r
+option to retrieve revisions associated with a symbolic tag.
+Use the
+.B \-f
+option to ignore all RCS files that do not contain the
+tag.
+Use the
+.B \-p
+option to prune directories that wind up empty because none
+of their files matched the tag. Example:
+.XS
+cd ~/work
+cvs checkout \-r V2_1 \-f \-p behemoth
+.XE
+.SS "Logging Changes"
+It is a good idea to keep a change log together with the
+sources. As a minimum, the change log should name and describe each
+tagged release. The change log should also be under CVS control and
+should be tagged along with the sources.
+.LP
+.BR cvslog (local)
+can help. This command logs
+changes reported during CVS
+.B commit
+operations. It automatically
+updates a change log file in your working directory. When you are
+finished making changes, you (optionally) edit the change log file and
+then commit it to the master repository.
+.LP
+Note: You must edit the change log to describe a new release
+and
+.B commit
+it to the master repository
+.I before
+.BR tag ging
+the release using CVS. Otherwise, the release description will not be
+included in the tagged package.
+.LP
+See
+.BR cvslog (local)
+for more information.
+.SS "Merging a Subsequent Third-Party Distribution"
+The initial steps in this process are identical to placing a
+third-party distribution under CVS for the first time: save the
+distribution kit and unpack the package in a scratch directory. From
+that point the steps diverge.
+The following example considers release 5.0 of the
+Bugs-R-Us package.
+.TP
+\(bu
+Check in the sources after unpacking them:
+.XS
+cd ~/scratch
+checkin \-m 'Bugs-R-Us 5.0 distribution' bugs VENDOR V5_0 \\
+ | tee ~/WARNINGS
+.XE
+It is important to save the output of
+.B checkin
+in a file
+because it lists the sources that have been locally modified.
+It is best to save the file in a different directory (for example,
+your home directory). Otherwise,
+.B checkin
+will try to check it into the master repository.
+.TP
+\(bu
+In your usual working directory, check out a fresh copy of the
+distribution that you just checked in.
+.XS
+cd ~/work
+cvs checkout \-r VENDOR bugs
+.XE
+The
+.B checkout
+command shown above retrieves the latest revision on the vendor branch.
+.TP
+\(bu
+See the `WARNINGS' file for a list of all locally modified
+sources.
+For each locally modified source,
+look at the differences between
+the new distribution and the latest local revision:
+.XS
+cvs diff \-r \fR\fILocalRev file\fR\fB
+.XE
+In this command,
+.I LocalRev
+is the latest
+numeric or symbolic revision
+on the RCS trunk of
+.IR file .
+You can use CVS
+.B log
+to get the revision history.
+.TP
+\(bu
+If your local modifications to a file have been incorporated into
+the vendor's distribution, then you should reset the default RCS
+branch for that file to the vendor branch. CVS doesn't provide a
+mechanism to do this. You have to do it by hand in the master
+repository:
+.XS
+rcs \-bVENDOR \fR\fIfile\fR\fB,v
+.XE
+.TP
+\(bu
+If your local modifications need to be merged with the
+new distribution, use CVS
+.B join
+to do it:
+.XS
+cvs join \-r VENDOR \fR\fIfile\fR\fB
+.XE
+The resulting file will be placed in your working directory.
+Edit it to resolve any overlaps.
+.TP
+\(bu
+Test the merged package.
+.TP
+\(bu
+Commit all modified files to the repository:
+.XS
+cvs commit \-a
+.XE
+.TP
+\(bu
+Tag the repository with a new local tag.
+.SS "Applying Patches to Third-Party Sources"
+Patches are handled in a manner very similar to complete
+third-party distributions. This example considers patches applied to
+Bugs-R-Us release 5.0.
+.TP
+\(bu
+Save the patch files together with the distribution kit
+to which they apply.
+The patch file names should clearly indicate the patch
+level.
+.TP
+\(bu
+In a scratch directory, check out the last `clean' vendor copy \- the
+highest revision on the vendor branch with
+.IR "no local changes" :
+.XS
+cd ~/scratch
+cvs checkout \-r VENDOR bugs
+.XE
+.TP
+\(bu
+Use
+.BR patch (local)
+to apply the patches. You should now have an image of the
+vendor's software just as though you had received a complete,
+new release.
+.TP
+\(bu
+Proceed with the steps described for merging a subsequent third-party
+distribution.
+.TP
+\(bu
+Note: When you get to the step that requires you
+to check out the new distribution after you have
+checked it into the vendor branch, you should move to a different
+directory. Do not attempt to
+.B checkout
+files in the directory in
+which you applied the patches. If you do, CVS will try to merge the
+changes that you made during patching with the version being checked
+out and things will get very confusing. Instead,
+go to a different directory (like your working directory) and
+check out the files there.
+.SS "Advice to Third-Party Source Hackers"
+As you can see from the preceding sections, merging local changes
+into third-party distributions remains difficult, and probably
+always will. This fact suggests some guidelines:
+.TP
+\(bu
+Minimize local changes.
+.I Never
+make stylistic changes.
+Change makefiles only as much as needed for installation. Avoid
+overhauling anything. Pray that the vendor does the same.
+.TP
+\(bu
+Avoid renaming files or moving them around.
+.TP
+\(bu
+Put independent, locally written files like help documents, local
+tools, or man pages in a sub-directory called `local-additions'.
+Locally written files that are linked into an existing executable
+should be added right in with the vendor's sources (not in a
+`local-additions' directory).
+If, in the future,
+the vendor distributes something
+equivalent to your locally written files
+you can CVS
+.B remove
+the files from the `local-additions' directory at that time.
+.SH SEE ALSO
+.BR cvs (local),
+.BR checkin (local),
+.BR cvslog (local),
+.BR cvscheck (local)
+.SH AUTHOR
+Lowell Skoog
+.br
+Software Technology Group
+.br
+Technical Computing
diff --git a/gnu/usr.bin/cvs/contrib/descend.man b/gnu/usr.bin/cvs/contrib/descend.man
new file mode 100644
index 0000000..5ac46f4
--- /dev/null
+++ b/gnu/usr.bin/cvs/contrib/descend.man
@@ -0,0 +1,115 @@
+.\" $Id: descend.man,v 1.1.1.3 1995/08/28 16:20:31 jimb Exp $
+.TH DESCEND 1 "31 March 1992"
+.SH NAME
+descend \- walk directory tree and execute a command at each node
+.SH SYNOPSIS
+.B descend
+[
+.B \-afqrv
+]
+.I command
+[
+.I directory
+\&.\|.\|.
+]
+.SH DESCRIPTION
+.B descend
+walks down a directory tree and executes a command at each node. It
+is not as versatile as
+.BR find (1),
+but it has a simpler syntax. If no
+.I directory
+is specified,
+.B descend
+starts at the current one.
+.LP
+Unlike
+.BR find ,
+.B descend
+can be told to skip the special directories associated with RCS,
+CVS, and SCCS. This makes
+.B descend
+especially handy for use with these packages. It can be used with
+other commands too, of course.
+.LP
+.B descend
+is a poor man's way to make any command recursive. Note:
+.B descend
+does not follow symbolic links to directories unless they are
+specified on the command line.
+.SH OPTIONS
+.TP 15
+.B \-a
+.I All.
+Descend into directories that begin with '.'.
+.TP
+.B \-f
+.I Force.
+Ignore errors during descent. Normally,
+.B descend
+quits when an error occurs.
+.TP
+.B \-q
+.I Quiet.
+Suppress the message `In directory
+.IR directory '
+that is normally printed during the descent.
+.TP
+.B \-r
+.I Restricted.
+Don't descend into the special directories
+.SB RCS,
+.SB CVS,
+.SB CVS.adm,
+and
+.SB SCCS.
+.TP
+.B \-v
+.I Verbose.
+Print
+.I command
+before executing it.
+.SH EXAMPLES
+.TP 15
+.B "descend ls"
+Cheap substitute for `ls -R'.
+.TP 15
+.B "descend -f 'rm *' tree"
+Strip `tree' of its leaves. This command descends the `tree'
+directory, removing all regular files. Since
+.BR rm (1)
+does not remove directories, this command leaves the directory
+structure of `tree' intact, but denuded. The
+.B \-f
+option is required to keep
+.B descend
+from quitting. You could use `rm \-f' instead.
+.TP
+.B "descend -r 'co RCS/*'" /project/src/
+Check out every RCS file under the directory
+.BR "/project/src" .
+.TP
+.B "descend -r 'cvs diff'"
+Perform CVS `diff' operation on every directory below (and including)
+the current one.
+.SH DIAGNOSTICS
+Returns 1 if errors occur (and the
+.B \-f
+option is not used). Otherwise returns 0.
+.SH SEE ALSO
+.BR find (1),
+.BR rcsintro (1),
+.BR cvs (1),
+.BR sccs (1)
+.SH AUTHOR
+Lowell Skoog
+.br
+Software Technology Group
+.br
+John Fluke Mfg. Co., Inc.
+.SH BUGS
+Shell metacharacters in
+.I command
+may have bizarre effects. In particular, compound commands
+(containing ';', '[', and ']' characters) will not work. It is best
+to enclose complicated commands in single quotes \(aa\ \(aa.
diff --git a/gnu/usr.bin/cvs/contrib/descend.sh b/gnu/usr.bin/cvs/contrib/descend.sh
new file mode 100644
index 0000000..e6a7880
--- /dev/null
+++ b/gnu/usr.bin/cvs/contrib/descend.sh
@@ -0,0 +1,116 @@
+#! /bin/sh
+# $Id: descend.sh,v 1.1 1995/07/10 02:26:32 kfogel Exp $
+#
+# descend - walk down a directory tree and execute a command at each node
+
+fullname=$0
+name=descend
+usage="Usage: $name [-afqrv] command [directory ...]\n
+\040\040-a\040\040All: descend into directories starting with '.'\n
+\040\040-f\040\040Force: ignore errors during descent\n
+\040\040-q\040\040Quiet: don't print directory names\n
+\040\040-r\040\040Restricted: don't descend into RCS, CVS.adm, SCCS directories\n
+\040\040-v\040\040Verbose: print command before executing it"
+
+# Scan for options
+while getopts afqrv option; do
+ case $option in
+ a)
+ alldirs=$option
+ options=$options" "-$option
+ ;;
+ f)
+ force=$option
+ options=$options" "-$option
+ ;;
+ q)
+ verbose=
+ quiet=$option
+ options=$options" "-$option
+ ;;
+ r)
+ restricted=$option
+ options=$options" "-$option
+ ;;
+ v)
+ verbose=$option
+ quiet=
+ options=$options" "-$option
+ ;;
+ \?)
+ /usr/5bin/echo $usage 1>&2
+ exit 1
+ ;;
+ esac
+done
+shift `expr $OPTIND - 1`
+
+# Get command to execute
+if [ $# -lt 1 ] ; then
+ /usr/5bin/echo $usage 1>&2
+ exit 1
+else
+ command=$1
+ shift
+fi
+
+# If no directory specified, use '.'
+if [ $# -lt 1 ] ; then
+ default_dir=.
+fi
+
+# For each directory specified
+for dir in $default_dir "$@" ; do
+
+ # Spawn sub-shell so we return to starting directory afterward
+ (cd $dir
+
+ # Execute specified command
+ if [ -z "$quiet" ] ; then
+ echo In directory `hostname`:`pwd`
+ fi
+ if [ -n "$verbose" ] ; then
+ echo $command
+ fi
+ eval "$command" || if [ -z "$force" ] ; then exit 1; fi
+
+ # Collect dot file names if necessary
+ if [ -n "$alldirs" ] ; then
+ dotfiles=.*
+ else
+ dotfiles=
+ fi
+
+ # For each file in current directory
+ for file in $dotfiles * ; do
+
+ # Skip '.' and '..'
+ if [ "$file" = "." -o "$file" = ".." ] ; then
+ continue
+ fi
+
+ # If a directory but not a symbolic link
+ if [ -d "$file" -a ! -h "$file" ] ; then
+
+ # If not skipping this type of directory
+ if [ \( "$file" != "RCS" -a \
+ "$file" != "SCCS" -a \
+ "$file" != "CVS" -a \
+ "$file" != "CVS.adm" \) \
+ -o -z "$restricted" ] ; then
+
+ # Recursively descend into it
+ $fullname $options "$command" "$file" \
+ || if [ -z "$force" ] ; then exit 1; fi
+ fi
+
+ # Else if a directory AND a symbolic link
+ elif [ -d "$file" -a -h "$file" ] ; then
+
+ if [ -z "$quiet" ] ; then
+ echo In directory `hostname`:`pwd`/$file: symbolic link: skipping
+ fi
+ fi
+ done
+ ) || if [ -z "$force" ] ; then exit 1; fi
+done
diff --git a/gnu/usr.bin/cvs/contrib/dirfns.shar b/gnu/usr.bin/cvs/contrib/dirfns.shar
new file mode 100644
index 0000000..8324c41
--- /dev/null
+++ b/gnu/usr.bin/cvs/contrib/dirfns.shar
@@ -0,0 +1,481 @@
+echo 'directory.3':
+sed 's/^X//' >'directory.3' <<'!'
+X.TH DIRECTORY 3 imported
+X.DA 9 Oct 1985
+X.SH NAME
+Xopendir, readdir, telldir, seekdir, rewinddir, closedir \- high-level directory operations
+X.SH SYNOPSIS
+X.B #include <sys/types.h>
+X.br
+X.B #include <ndir.h>
+X.PP
+X.SM
+X.B DIR
+X.B *opendir(filename)
+X.br
+X.B char *filename;
+X.PP
+X.SM
+X.B struct direct
+X.B *readdir(dirp)
+X.br
+X.B DIR *dirp;
+X.PP
+X.SM
+X.B long
+X.B telldir(dirp)
+X.br
+X.B DIR *dirp;
+X.PP
+X.SM
+X.B seekdir(dirp, loc)
+X.br
+X.B DIR *dirp;
+X.br
+X.B long loc;
+X.PP
+X.SM
+X.B rewinddir(dirp)
+X.br
+X.B DIR *dirp;
+X.PP
+X.SM
+X.B closedir(dirp)
+X.br
+X.B DIR *dirp;
+X.SH DESCRIPTION
+XThis library provides high-level primitives for directory scanning,
+Xsimilar to those available for 4.2BSD's (very different) directory system.
+X.\"The purpose of this library is to simulate
+X.\"the new flexible length directory names of 4.2bsd UNIX
+X.\"on top of the old directory structure of v7.
+XIt incidentally provides easy portability to and from 4.2BSD (insofar
+Xas such portability is not compromised by other 4.2/VAX dependencies).
+X.\"It allows programs to be converted immediately
+X.\"to the new directory access interface,
+X.\"so that they need only be relinked
+X.\"when moved to 4.2bsd.
+X.\"It is obtained with the loader option
+X.\".BR \-lndir .
+X.PP
+X.I Opendir
+Xopens the directory named by
+X.I filename
+Xand associates a
+X.I directory stream
+Xwith it.
+X.I Opendir
+Xreturns a pointer to be used to identify the
+X.I directory stream
+Xin subsequent operations.
+XThe pointer
+X.SM
+X.B NULL
+Xis returned if
+X.I filename
+Xcannot be accessed or is not a directory.
+X.PP
+X.I Readdir
+Xreturns a pointer to the next directory entry.
+XIt returns
+X.B NULL
+Xupon reaching the end of the directory or detecting
+Xan invalid
+X.I seekdir
+Xoperation.
+X.PP
+X.I Telldir
+Xreturns the current location associated with the named
+X.I directory stream.
+X.PP
+X.I Seekdir
+Xsets the position of the next
+X.I readdir
+Xoperation on the
+X.I directory stream.
+XThe new position reverts to the one associated with the
+X.I directory stream
+Xwhen the
+X.I telldir
+Xoperation was performed.
+XValues returned by
+X.I telldir
+Xare good only for the lifetime of the DIR pointer from
+Xwhich they are derived.
+XIf the directory is closed and then reopened,
+Xthe
+X.I telldir
+Xvalue may be invalidated
+Xdue to undetected directory compaction in 4.2BSD.
+XIt is safe to use a previous
+X.I telldir
+Xvalue immediately after a call to
+X.I opendir
+Xand before any calls to
+X.I readdir.
+X.PP
+X.I Rewinddir
+Xresets the position of the named
+X.I directory stream
+Xto the beginning of the directory.
+X.PP
+X.I Closedir
+Xcauses the named
+X.I directory stream
+Xto be closed,
+Xand the structure associated with the DIR pointer to be freed.
+X.PP
+XA
+X.I direct
+Xstructure is as follows:
+X.PP
+X.RS
+X.nf
+Xstruct direct {
+X /* unsigned */ long d_ino; /* inode number of entry */
+X unsigned short d_reclen; /* length of this record */
+X unsigned short d_namlen; /* length of string in d_name */
+X char d_name[MAXNAMLEN + 1]; /* name must be no longer than this */
+X};
+X.fi
+X.RE
+X.PP
+XThe
+X.I d_reclen
+Xfield is meaningless in non-4.2BSD systems and should be ignored.
+XThe use of a
+X.I long
+Xfor
+X.I d_ino
+Xis also a 4.2BSDism;
+X.I ino_t
+X(see
+X.IR types (5))
+Xshould be used elsewhere.
+XThe macro
+X.I DIRSIZ(dp)
+Xgives the minimum memory size needed to hold the
+X.I direct
+Xvalue pointed to by
+X.IR dp ,
+Xwith the minimum necessary allocation for
+X.IR d_name .
+X.PP
+XThe preferred way to search the current directory for entry ``name'' is:
+X.PP
+X.RS
+X.nf
+X len = strlen(name);
+X dirp = opendir(".");
+X if (dirp == NULL) {
+X fprintf(stderr, "%s: can't read directory .\\n", argv[0]);
+X return NOT_FOUND;
+X }
+X while ((dp = readdir(dirp)) != NULL)
+X if (dp->d_namlen == len && strcmp(dp->d_name, name) == 0) {
+X closedir(dirp);
+X return FOUND;
+X }
+X closedir(dirp);
+X return NOT_FOUND;
+X.RE
+X.\".SH LINKING
+X.\"This library is accessed by specifying ``-lndir'' as the
+X.\"last argument to the compile line, e.g.:
+X.\".PP
+X.\" cc -I/usr/include/ndir -o prog prog.c -lndir
+X.SH "SEE ALSO"
+Xopen(2),
+Xclose(2),
+Xread(2),
+Xlseek(2)
+X.SH HISTORY
+XWritten by
+XKirk McKusick at Berkeley (ucbvax!mckusick).
+XMiscellaneous bug fixes from elsewhere.
+XThe size of the data structure has been decreased to avoid excessive
+Xspace waste under V7 (where filenames are 14 characters at most).
+XFor obscure historical reasons, the include file is also available
+Xas
+X.IR <ndir/sys/dir.h> .
+XThe Berkeley version lived in a separate library (\fI\-lndir\fR),
+Xwhereas ours is
+Xpart of the C library, although the separate library is retained to
+Xmaximize compatibility.
+X.PP
+XThis manual page has been substantially rewritten to be informative in
+Xthe absence of a 4.2BSD manual.
+X.SH BUGS
+XThe
+X.I DIRSIZ
+Xmacro actually wastes a bit of space due to some padding requirements
+Xthat are an artifact of 4.2BSD.
+X.PP
+XThe returned value of
+X.I readdir
+Xpoints to a static area that will be overwritten by subsequent calls.
+X.PP
+XThere are some unfortunate name conflicts with the \fIreal\fR V7
+Xdirectory structure definitions.
+!
+echo 'dir.h':
+sed 's/^X//' >'dir.h' <<'!'
+X/* dir.h 4.4 82/07/25 */
+X
+X/*
+X * A directory consists of some number of blocks of DIRBLKSIZ
+X * bytes, where DIRBLKSIZ is chosen such that it can be transferred
+X * to disk in a single atomic operation (e.g. 512 bytes on most machines).
+X *
+X * Each DIRBLKSIZ byte block contains some number of directory entry
+X * structures, which are of variable length. Each directory entry has
+X * a struct direct at the front of it, containing its inode number,
+X * the length of the entry, and the length of the name contained in
+X * the entry. These are followed by the name padded to a 4 byte boundary
+X * with null bytes. All names are guaranteed null terminated.
+X * The maximum length of a name in a directory is MAXNAMLEN.
+X *
+X * The macro DIRSIZ(dp) gives the amount of space required to represent
+X * a directory entry. Free space in a directory is represented by
+X * entries which have dp->d_reclen >= DIRSIZ(dp). All DIRBLKSIZ bytes
+X * in a directory block are claimed by the directory entries. This
+X * usually results in the last entry in a directory having a large
+X * dp->d_reclen. When entries are deleted from a directory, the
+X * space is returned to the previous entry in the same directory
+X * block by increasing its dp->d_reclen. If the first entry of
+X * a directory block is free, then its dp->d_ino is set to 0.
+X * Entries other than the first in a directory do not normally have
+X * dp->d_ino set to 0.
+X */
+X#define DIRBLKSIZ 512
+X#ifdef VMUNIX
+X#define MAXNAMLEN 255
+X#else
+X#define MAXNAMLEN 14
+X#endif
+X
+Xstruct direct {
+X /* unsigned */ long d_ino; /* inode number of entry */
+X unsigned short d_reclen; /* length of this record */
+X unsigned short d_namlen; /* length of string in d_name */
+X char d_name[MAXNAMLEN + 1]; /* name must be no longer than this */
+X};
+X
+X/*
+X * The DIRSIZ macro gives the minimum record length which will hold
+X * the directory entry. This requires the amount of space in struct direct
+X * without the d_name field, plus enough space for the name with a terminating
+X * null byte (dp->d_namlen+1), rounded up to a 4 byte boundary.
+X */
+X#undef DIRSIZ
+X#define DIRSIZ(dp) \
+X ((sizeof (struct direct) - (MAXNAMLEN+1)) + (((dp)->d_namlen+1 + 3) &~ 3))
+X
+X#ifndef KERNEL
+X/*
+X * Definitions for library routines operating on directories.
+X */
+Xtypedef struct _dirdesc {
+X int dd_fd;
+X long dd_loc;
+X long dd_size;
+X char dd_buf[DIRBLKSIZ];
+X} DIR;
+X#ifndef NULL
+X#define NULL 0
+X#endif
+Xextern DIR *opendir();
+Xextern struct direct *readdir();
+Xextern long telldir();
+X#ifdef void
+Xextern void seekdir();
+Xextern void closedir();
+X#endif
+X#define rewinddir(dirp) seekdir((dirp), (long)0)
+X#endif KERNEL
+!
+echo 'makefile':
+sed 's/^X//' >'makefile' <<'!'
+XDIR = closedir.o opendir.o readdir.o seekdir.o telldir.o
+XCFLAGS=-O -I. -Dvoid=int
+XDEST=..
+X
+Xall: $(DIR)
+X
+Xmv: $(DIR)
+X mv $(DIR) $(DEST)
+X
+Xcpif: dir.h
+X cp dir.h /usr/include/ndir.h
+X
+Xclean:
+X rm -f *.o
+!
+echo 'closedir.c':
+sed 's/^X//' >'closedir.c' <<'!'
+Xstatic char sccsid[] = "@(#)closedir.c 4.2 3/10/82";
+X
+X#include <sys/types.h>
+X#include <dir.h>
+X
+X/*
+X * close a directory.
+X */
+Xvoid
+Xclosedir(dirp)
+X register DIR *dirp;
+X{
+X close(dirp->dd_fd);
+X dirp->dd_fd = -1;
+X dirp->dd_loc = 0;
+X free((char *)dirp);
+X}
+!
+echo 'opendir.c':
+sed 's/^X//' >'opendir.c' <<'!'
+X/* Copyright (c) 1982 Regents of the University of California */
+X
+Xstatic char sccsid[] = "@(#)opendir.c 4.4 11/12/82";
+X
+X#include <sys/types.h>
+X#include <sys/stat.h>
+X#include <dir.h>
+X
+X/*
+X * open a directory.
+X */
+XDIR *
+Xopendir(name)
+X char *name;
+X{
+X register DIR *dirp;
+X register int fd;
+X struct stat statbuf;
+X char *malloc();
+X
+X if ((fd = open(name, 0)) == -1)
+X return NULL;
+X if (fstat(fd, &statbuf) == -1 || !(statbuf.st_mode & S_IFDIR)) {
+X close(fd);
+X return NULL;
+X }
+X if ((dirp = (DIR *)malloc(sizeof(DIR))) == NULL) {
+X close (fd);
+X return NULL;
+X }
+X dirp->dd_fd = fd;
+X dirp->dd_loc = 0;
+X dirp->dd_size = 0; /* so that telldir will work before readdir */
+X return dirp;
+X}
+!
+echo 'readdir.c':
+sed 's/^X//' >'readdir.c' <<'!'
+X/* Copyright (c) 1982 Regents of the University of California */
+X
+Xstatic char sccsid[] = "@(#)readdir.c 4.3 8/8/82";
+X
+X#include <sys/types.h>
+X#include <dir.h>
+X
+X/*
+X * read an old stlye directory entry and present it as a new one
+X */
+X#define ODIRSIZ 14
+X
+Xstruct olddirect {
+X ino_t od_ino;
+X char od_name[ODIRSIZ];
+X};
+X
+X/*
+X * get next entry in a directory.
+X */
+Xstruct direct *
+Xreaddir(dirp)
+X register DIR *dirp;
+X{
+X register struct olddirect *dp;
+X static struct direct dir;
+X
+X for (;;) {
+X if (dirp->dd_loc == 0) {
+X dirp->dd_size = read(dirp->dd_fd, dirp->dd_buf,
+X DIRBLKSIZ);
+X if (dirp->dd_size <= 0) {
+X dirp->dd_size = 0;
+X return NULL;
+X }
+X }
+X if (dirp->dd_loc >= dirp->dd_size) {
+X dirp->dd_loc = 0;
+X continue;
+X }
+X dp = (struct olddirect *)(dirp->dd_buf + dirp->dd_loc);
+X dirp->dd_loc += sizeof(struct olddirect);
+X if (dp->od_ino == 0)
+X continue;
+X dir.d_ino = dp->od_ino;
+X strncpy(dir.d_name, dp->od_name, ODIRSIZ);
+X dir.d_name[ODIRSIZ] = '\0'; /* insure null termination */
+X dir.d_namlen = strlen(dir.d_name);
+X dir.d_reclen = DIRBLKSIZ;
+X return (&dir);
+X }
+X}
+!
+echo 'seekdir.c':
+sed 's/^X//' >'seekdir.c' <<'!'
+Xstatic char sccsid[] = "@(#)seekdir.c 4.9 3/25/83";
+X
+X#include <sys/param.h>
+X#include <dir.h>
+X
+X/*
+X * seek to an entry in a directory.
+X * Only values returned by "telldir" should be passed to seekdir.
+X */
+Xvoid
+Xseekdir(dirp, loc)
+X register DIR *dirp;
+X long loc;
+X{
+X long curloc, base, offset;
+X struct direct *dp;
+X extern long lseek();
+X
+X curloc = telldir(dirp);
+X if (loc == curloc)
+X return;
+X base = loc & ~(DIRBLKSIZ - 1);
+X offset = loc & (DIRBLKSIZ - 1);
+X (void) lseek(dirp->dd_fd, base, 0);
+X dirp->dd_size = 0;
+X dirp->dd_loc = 0;
+X while (dirp->dd_loc < offset) {
+X dp = readdir(dirp);
+X if (dp == NULL)
+X return;
+X }
+X}
+!
+echo 'telldir.c':
+sed 's/^X//' >'telldir.c' <<'!'
+Xstatic char sccsid[] = "@(#)telldir.c 4.1 2/21/82";
+X
+X#include <sys/types.h>
+X#include <dir.h>
+X
+X/*
+X * return a pointer into a directory
+X */
+Xlong
+Xtelldir(dirp)
+X DIR *dirp;
+X{
+X long lseek();
+X
+X return (lseek(dirp->dd_fd, 0L, 1) - dirp->dd_size + dirp->dd_loc);
+X}
+!
+echo done
diff --git a/gnu/usr.bin/cvs/contrib/easy-import.pl b/gnu/usr.bin/cvs/contrib/easy-import.pl
new file mode 100644
index 0000000..7bcfc39
--- /dev/null
+++ b/gnu/usr.bin/cvs/contrib/easy-import.pl
@@ -0,0 +1,388 @@
+#! xPERL_PATHx
+#
+# Support for importing a source collection into CVS.
+# Tries to prevent the user from the most common pitfalls (like creating
+# new top-level repositories or second-level areas accidentally), and
+# cares to do some of the `dirty' work like maintaining the modules
+# database accordingly.
+#
+# Written by Jörg Wunsch, 95/03/07, and placed in the public domain.
+#
+# $Id: easy-import.pl,v 1.4 1995/12/11 00:45:43 peter Exp $
+
+require "complete.pl";
+require "getopts.pl";
+
+
+sub scan_opts
+{
+ local($status);
+
+ $status = &Getopts("nv");
+
+ $dont_do_it = "-n" if $opt_n;
+ if($opt_v) {
+ print STDERR '$Source: /home/ncvs/src/gnu/usr.bin/cvs/contrib/easy-import.pl,v $ $Revision: 1.4 $' . "\n"; # 'emacs kludge
+ exit 0;
+ }
+ die "usage: $0 [-v] [-n] [moduledir]\n" .
+ " -n: don't do any commit, show only\n" .
+ " -v: show program version\n"
+ unless $status && $#ARGV <= 0;
+
+ if($#ARGV == 0) {
+ $moduledir = $ARGV[0];
+ shift;
+ }
+}
+
+sub lsdir
+{
+ # find all subdirectories under @_
+ # ignore all CVS entries, dot entries, and non-directories
+
+ local($base) = @_;
+ local(@ls, @rv, $fname);
+
+ opendir(DIR, $base) || die "Cannot find dir $base.\n";
+
+ @ls = readdir(DIR);
+ closedir(DIR);
+
+ @rv = ();
+
+ foreach $fname (@ls) {
+ next if $fname =~ /^CVS/ || $fname eq "Attic"
+ || $fname =~ /^\./ || ! -d "$base/$fname";
+ @rv = (@rv, $fname);
+ }
+
+ return sort(@rv);
+}
+
+
+sub contains
+{
+ # look if the first parameter is contained in the list following it
+ local($item, @list) = @_;
+ local($found, $i);
+
+ $found = 0;
+ foreach $i (@list) {
+ return 1 if $i eq $item;
+ }
+ return 0;
+}
+
+
+
+sub term_init
+{
+ # first, get some terminal attributes
+
+ # try bold mode first
+ $so = `tput md`; $se = `tput me`;
+
+ # if no bold mode available, use standout mode
+ if ($so eq "") {
+ $so = `tput so`; $se = `tput se`;
+ }
+
+ # try if we can underscore
+ $us = `tput us`; $ue = `tput ue`;
+ # if we don't have it available, or same as bold/standout, disable it
+ if ($us eq "" || $us eq $so) {
+ $us = $ue = "";
+ }
+
+ # look how many columns we've got
+ if($ENV{'COLUMNS'} ne "") {
+ $columns = $ENV{'COLUMNS'};
+ } elsif(-t STDIN) { # if we operate on a terminal...
+ local($word, $tmp);
+
+ open(STTY, "stty -a|");
+ $_ = <STTY>; # try getting the tty win structure value
+ close(STTY);
+ chop;
+ $columns = 0;
+ foreach $word (split) {
+ $columns = $tmp if $word eq "columns;"; # the number preceding
+ $tmp = $word;
+ }
+ } else {
+ $columns = 80;
+ }
+ # sanity
+ $columns = 80 unless $columns >= 5;
+}
+
+
+sub list
+{
+ # pretty-print a list
+ # imports: global variable $columns
+ local(@items) = @_;
+ local($longest,$i,$item,$cols,$width);
+
+ # find the longest item
+ $longest = 0;
+ foreach $item (@items) {
+ $i = length($item);
+ $longest = $i if $longest < $i;
+ }
+ $width = $longest + 1;
+ $cols = int($columns / $width);
+
+ $i = 0;
+ foreach $item (@items) {
+ print $item;
+ if(++$i == $cols) {
+ $i = 0; print "\n";
+ } else {
+ print ' ' x ($width - length($item));
+ }
+ }
+ print "\n" unless $i == 0;
+}
+
+sub cvs_init
+{
+ # get the CVS repository(s)
+
+ die "You need to have the \$CVSROOT variable set.\n"
+ unless $ENV{'CVSROOT'} ne "";
+
+ # get the list of available repositories
+ $cvsroot = $ENV{'CVSROOT'};
+ @reps = &lsdir($cvsroot);
+}
+
+
+sub lsmodules
+{
+ # list all known CVS modules
+ local(@rv, $mname, $_);
+
+ @rv = ();
+
+ open(CVS, "cvs co -c|");
+ while($_ = <CVS>) {
+ chop;
+ ($mname) = split;
+ next if $mname eq "";
+ @rv = (@rv, $mname);
+ }
+ close(CVS);
+
+ return @rv;
+}
+
+
+sub checktag
+{
+ # check a given string for tag rules
+ local($s, $name) = @_;
+ local($regexp);
+
+ if($name eq "vendor") { $regexp = '^[A-Z][A-Z0-9_]*$'; }
+ elsif($name eq "release") { $regexp = '^[a-z][a-z0-9_]*$'; }
+ else {
+ print STDERR "Internal error: unknown tag name $name\n";
+ exit(2);
+ }
+
+ if($s !~ /$regexp/) {
+ print "\a${us}Valid $name tags must match the regexp " .
+ "$regexp.${ue}\n";
+ return 0;
+ }
+ if($s =~ /^RELENG/) {
+ print "\a${us}Tags must not start with the word \"RELENG\".${ue}\n";
+ return 0;
+ }
+
+ return 1;
+}
+
+
+&scan_opts;
+&term_init;
+&cvs_init;
+
+if(! $moduledir) {
+ @dirs = &lsdir(".");
+ print "${so}Import from which directory?${se}\n";
+ @dirs = (@dirs, ".");
+ &list(@dirs);
+ $moduledir = &Complete("Which? [.]: ", @dirs);
+ $moduledir = "." unless $moduledir ne "";
+}
+
+chdir $moduledir || die "Cannot chdir to $moduledir\n";
+
+print "${so}Available repositories:${se}\n";
+&list(@reps);
+
+# the following kludge prevents the Complete package from starting
+# over with the string just selected; Complete should better provide
+# some reinitialize method
+$Complete'return = ""; $Complete'r = 0;
+
+$selected =
+ &Complete("Enter repository (<TAB>=complete, ^D=show): ",
+ @reps);
+
+die "\aYou cannot create new repositories with this script.\n"
+ unless &contains($selected, @reps);
+
+$rep = $selected;
+
+print "\n${so}Selected repository:${se} ${us}$rep${ue}\n";
+
+
+@areas = &lsdir("$cvsroot/$rep");
+
+print "${so}Existent areas in this repository:${se}\n";
+&list(@areas);
+
+$Complete'return = ""; $Complete'r = 0;
+
+$selected =
+ &Complete("Enter area name (<TAB>=complete, ^D=show): ",
+ @areas);
+
+print "\a${us}Warning: this will create a new area.${ue}\n"
+ unless &contains($selected, @areas);
+
+$area = "$rep/$selected";
+
+print "\n${so}[Working on:${se} ${us}$area${ue}${so}]${se}\n";
+
+for(;;) {
+ $| = 1;
+ print "${so}Enter the module path:${se} $area/";
+ $| = 0;
+ $modpath = <>;
+ chop $modpath;
+ if ($modpath eq "") {
+ print "\a${us}You cannot use an empty module path.${ue}\n";
+ next;
+ }
+ last if ! -d "$cvsroot/$area/$modpath";
+ print "\a${us}This module path does already exist; " .
+ "choose another one.${ue}\n";
+}
+
+
+@newdirs = ();
+$dir1 = "$cvsroot/$area";
+$dir2 = "$area";
+
+@newdirs = (@newdirs, "$dir2") if ! -d $dir1;
+
+foreach $ele (split(/\//, $modpath)) {
+ $dir1 = "$dir1/$ele";
+ $dir2 = "$dir2/$ele";
+ @newdirs = (@newdirs, "$dir2") if ! -d $dir1;
+}
+
+print "${so}You're going to create the following new directories:${se}\n";
+
+&list(@newdirs);
+
+@cvsmods = &lsmodules();
+
+for(;;) {
+ $| = 1;
+ print "${so}Gimme the module name:${se} ";
+ $| = 0;
+ $modname = <>;
+ chop $modname;
+ if ($modname eq "") {
+ print "\a${us}You cannot use an empty module name.${ue}\n";
+ next;
+ }
+ last if !&contains($modname, @cvsmods);
+ print "\a${us}This module name does already exist; " .
+ "choose another one.${ue}\n";
+}
+
+
+for(;;) {
+ $| = 1;
+ print "${so}Enter a \`vendor\' tag (e. g. the authors ID):${se} ";
+ $| = 0;
+ $vtag = <>;
+ chop $vtag;
+ last if &checktag($vtag, "vendor");
+}
+
+for(;;) {
+ $| = 1;
+ print "${so}Enter a \`release\' tag (e. g. the version #):${se} ";
+ $| = 0;
+ $rtag = <>;
+ chop $rtag;
+ last if &checktag($rtag, "release");
+}
+
+
+$| = 1;
+print "${so}This is your last chance to interrupt, " .
+ "hit <return> to go on:${se} ";
+$| = 0;
+<>;
+
+$mod = "";
+foreach $tmp (@cvsmods) {
+ if($tmp gt $modname) {
+ $mod = $tmp;
+ last;
+ }
+}
+
+if($mod eq "") {
+ # we are going to append our module
+ $cmd = "\$\na\n";
+} else {
+ # we can insert it
+ $cmd = "/^${mod}[ \t]/\ni\n";
+}
+
+print "${so}Checking out the modules database...${se}\n";
+system("cvs co modules") && die "${us}failed.\n${ue}";
+
+print "${so}Inserting new module...${se}\n";
+open(ED, "|ed modules/modules") || die "${us}Cannot start ed${ue}\n";
+print(ED "${cmd}${modname}" . ' ' x (16 - length($modname)) .
+ "$area/${modpath}\n.\nw\nq\n");
+close(ED);
+
+print "${so}Commiting new modules database...${se}\n";
+system("cvs $dont_do_it commit -m \" " .
+ "${modname} --> $area/${modpath}\" modules")
+ && die "Commit failed\n";
+
+system("cvs $dont_do_it -Q release -d modules");
+
+print "${so}Importing source. Enter a commit message in the editor.${se}\n";
+
+system("cvs $dont_do_it import $area/$modpath $vtag $rtag");
+
+print "${so}You are done now. Go to a different directory, perform a${se}\n".
+ "${us}cvs co ${modname}${ue} ${so}command, and see if your new module" .
+ " builds ok.${se}\n";
+
+if($dont_do_it) {
+print <<END
+
+
+${so}Since you did not allow to commit anything, you'll have${se}
+${so}to remove the edited modules' database yourself.${se}
+${so}To do this, perform a${se}
+${us}cd ${moduledir}; cvs -Q release -d modules${ue}
+${so}command.${se}
+END
+;
+}
diff --git a/gnu/usr.bin/cvs/contrib/intro.doc b/gnu/usr.bin/cvs/contrib/intro.doc
new file mode 100644
index 0000000..a6d4ec1
--- /dev/null
+++ b/gnu/usr.bin/cvs/contrib/intro.doc
@@ -0,0 +1,112 @@
+Date: Tue, 16 Jun 1992 17:05:23 +0200
+From: Steven.Pemberton@cwi.nl
+Message-Id: <9206161505.AA06927.steven@sijs.cwi.nl>
+To: berliner@Sun.COM
+Subject: cvs
+
+INTRODUCTION TO USING CVS
+
+ CVS is a system that lets groups of people work simultaneously on
+ groups of files (for instance program sources).
+
+ It works by holding a central 'repository' of the most recent version
+ of the files. You may at any time create a personal copy of these
+ files; if at a later date newer versions of the files are put in the
+ repository, you can 'update' your copy.
+
+ You may edit your copy of the files freely. If new versions of the
+ files have been put in the repository in the meantime, doing an update
+ merges the changes in the central copy into your copy.
+ (It can be that when you do an update, the changes in the
+ central copy clash with changes you have made in your own
+ copy. In this case cvs warns you, and you have to resolve the
+ clash in your copy.)
+
+ When you are satisfied with the changes you have made in your copy of
+ the files, you can 'commit' them into the central repository.
+ (When you do a commit, if you haven't updated to the most
+ recent version of the files, cvs tells you this; then you have
+ to first update, resolve any possible clashes, and then redo
+ the commit.)
+
+USING CVS
+
+ Suppose that a number of repositories have been stored in
+ /usr/src/cvs. Whenever you use cvs, the environment variable
+ CVSROOT must be set to this (for some reason):
+
+ CVSROOT=/usr/src/cvs
+ export CVSROOT
+
+TO CREATE A PERSONAL COPY OF A REPOSITORY
+
+ Suppose you want a copy of the files in repository 'views' to be
+ created in your directory src. Go to the place where you want your
+ copy of the directory, and do a 'checkout' of the directory you
+ want:
+
+ cd $HOME/src
+ cvs checkout views
+
+ This creates a directory called (in this case) 'views' in the src
+ directory, containing a copy of the files, which you may now work
+ on to your heart's content.
+
+TO UPDATE YOUR COPY
+
+ Use the command 'cvs update'.
+
+ This will update your copy with any changes from the central
+ repository, telling you which files have been updated (their names
+ are displayed with a U before them), and which have been modified
+ by you and not yet committed (preceded by an M). You will be
+ warned of any files that contain clashes, the clashes will be
+ marked in the file surrounded by lines of the form <<<< and >>>>.
+
+TO COMMIT YOUR CHANGES
+
+ Use the command 'cvs commit'.
+
+ You will be put in an editor to make a message that describes the
+ changes that you have made (for future reference). Your changes
+ will then be added to the central copy.
+
+ADDING AND REMOVING FILES
+
+ It can be that the changes you want to make involve a completely
+ new file, or removing an existing one. The commands to use here
+ are:
+
+ cvs add <filename>
+ cvs remove <filename>
+
+ You still have to do a commit after these commands. You may make
+ any number of new files in your copy of the repository, but they
+ will not be committed to the central copy unless you do a 'cvs add'.
+
+OTHER USEFUL COMMANDS AND HINTS
+
+ To see the commit messages for files, and who made them, use:
+
+ cvs log [filenames]
+
+ To see the differences between your version and the central version:
+
+ cvs diff [filenames]
+
+ To give a file a new name, rename it and do an add and a remove.
+
+ To lose your changes and go back to the version from the
+ repository, delete the file and do an update.
+
+ After an update where there have been clashes, your original
+ version of the file is saved as .#file.version.
+
+ All the cvs commands mentioned accept a flag '-n', that doesn't do
+ the action, but lets you see what would happen. For instance, you
+ can use 'cvs -n update' to see which files would be updated.
+
+MORE INFORMATION
+
+ This is necessarily a very brief introduction. See the manual page
+ (man cvs) for full details.
diff --git a/gnu/usr.bin/cvs/contrib/log.pl b/gnu/usr.bin/cvs/contrib/log.pl
new file mode 100644
index 0000000..5e3bf48
--- /dev/null
+++ b/gnu/usr.bin/cvs/contrib/log.pl
@@ -0,0 +1,169 @@
+#! xPERL_PATHx
+# -*-Perl-*-
+#
+#ident "$CVSid$"
+#
+# XXX: FIXME: handle multiple '-f logfile' arguments
+#
+# XXX -- I HATE Perl! This *will* be re-written in shell/awk/sed soon!
+#
+
+# Usage: log.pl [[-m user] ...] [-s] -f logfile 'dirname file ...'
+#
+# -m user - for each user to receive cvs log reports
+# (multiple -m's permitted)
+# -s - to prevent "cvs status -v" messages
+# -f logfile - for the logfile to append to (mandatory,
+# but only one logfile can be specified).
+
+# here is what the output looks like:
+#
+# From: woods@kuma.domain.top
+# Subject: CVS update: testmodule
+#
+# Date: Wednesday November 23, 1994 @ 14:15
+# Author: woods
+#
+# Update of /local/src-CVS/testmodule
+# In directory kuma:/home/kuma/woods/work.d/testmodule
+#
+# Modified Files:
+# test3
+# Added Files:
+# test6
+# Removed Files:
+# test4
+# Log Message:
+# - wow, what a test
+#
+# (and for each file the "cvs status -v" output is appended unless -s is used)
+#
+# ==================================================================
+# File: test3 Status: Up-to-date
+#
+# Working revision: 1.41 Wed Nov 23 14:15:59 1994
+# Repository revision: 1.41 /local/src-CVS/cvs/testmodule/test3,v
+# Sticky Options: -ko
+#
+# Existing Tags:
+# local-v2 (revision: 1.7)
+# local-v1 (revision: 1.1.1.2)
+# CVS-1_4A2 (revision: 1.1.1.2)
+# local-v0 (revision: 1.2)
+# CVS-1_4A1 (revision: 1.1.1.1)
+# CVS (branch: 1.1.1)
+
+$cvsroot = $ENV{'CVSROOT'};
+
+# turn off setgid
+#
+$) = $(;
+
+$dostatus = 1;
+
+# parse command line arguments
+#
+while (@ARGV) {
+ $arg = shift @ARGV;
+
+ if ($arg eq '-m') {
+ $users = "$users " . shift @ARGV;
+ } elsif ($arg eq '-f') {
+ ($logfile) && die "Too many '-f' args";
+ $logfile = shift @ARGV;
+ } elsif ($arg eq '-s') {
+ $dostatus = 0;
+ } else {
+ ($donefiles) && die "Too many arguments!\n";
+ $donefiles = 1;
+ @files = split(/ /, $arg);
+ }
+}
+
+# the first argument is the module location relative to $CVSROOT
+#
+$modulepath = shift @files;
+
+$mailcmd = "| Mail -s 'CVS update: $modulepath'";
+
+# Initialise some date and time arrays
+#
+@mos = (January,February,March,April,May,June,July,August,September,
+ October,November,December);
+@days = (Sunday,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday);
+
+($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime;
+
+# get a login name for the guy doing the commit....
+#
+$login = getlogin || (getpwuid($<))[0] || "nobody";
+
+# open log file for appending
+#
+open(OUT, ">>" . $logfile) || die "Could not open(" . $logfile . "): $!\n";
+
+# send mail, if there's anyone to send to!
+#
+if ($users) {
+ $mailcmd = "$mailcmd $users";
+ open(MAIL, $mailcmd) || die "Could not Exec($mailcmd): $!\n";
+}
+
+# print out the log Header
+#
+print OUT "\n";
+print OUT "****************************************\n";
+print OUT "Date:\t$days[$wday] $mos[$mon] $mday, 19$year @ $hour:" . sprintf("%02d", $min) . "\n";
+print OUT "Author:\t$login\n\n";
+
+if (MAIL) {
+ print MAIL "\n";
+ print MAIL "Date:\t$days[$wday] $mos[$mon] $mday, 19$year @ $hour:" . sprintf("%02d", $min) . "\n";
+ print MAIL "Author:\t$login\n\n";
+}
+
+# print the stuff from logmsg that comes in on stdin to the logfile
+#
+open(IN, "-");
+while (<IN>) {
+ print OUT $_;
+ if (MAIL) {
+ print MAIL $_;
+ }
+}
+close(IN);
+
+print OUT "\n";
+
+# after log information, do an 'cvs -Qq status -v' on each file in the arguments.
+#
+if ($dostatus != 0) {
+ while (@files) {
+ $file = shift @files;
+ if ($file eq "-") {
+ print OUT "[input file was '-']\n";
+ if (MAIL) {
+ print MAIL "[input file was '-']\n";
+ }
+ last;
+ }
+ open(RCS, "-|") || exec 'cvs', '-nQq', 'status', '-v', $file;
+ while (<RCS>) {
+ print OUT;
+ if (MAIL) {
+ print MAIL;
+ }
+ }
+ close(RCS);
+ }
+}
+
+close(OUT);
+die "Write to $logfile failed" if $?;
+
+close(MAIL);
+die "Pipe to $mailcmd failed" if $?;
+
+## must exit cleanly
+##
+exit 0;
diff --git a/gnu/usr.bin/cvs/contrib/log_accum.pl b/gnu/usr.bin/cvs/contrib/log_accum.pl
new file mode 100644
index 0000000..b47f433
--- /dev/null
+++ b/gnu/usr.bin/cvs/contrib/log_accum.pl
@@ -0,0 +1,496 @@
+#! xPERL_PATHx
+# -*-Perl-*-
+#
+# Perl filter to handle the log messages from the checkin of files in
+# a directory. This script will group the lists of files by log
+# message, and mail a single consolidated log message at the end of
+# the commit.
+#
+# This file assumes a pre-commit checking program that leaves the
+# names of the first and last commit directories in a temporary file.
+#
+# Contributed by David Hampton <hampton@cisco.com>
+#
+# hacked greatly by Greg A. Woods <woods@planix.com>
+
+# Usage: log_accum.pl [-d] [-s] [-M module] [[-m mailto] ...] [-f logfile]
+# -d - turn on debugging
+# -m mailto - send mail to "mailto" (multiple)
+# -M modulename - set module name to "modulename"
+# -f logfile - write commit messages to logfile too
+# -s - *don't* run "cvs status -v" for each file
+
+#
+# Configurable options
+#
+
+$MAILER = "Mail"; # set this to something that takes "-s"
+
+#
+# End user configurable options.
+#
+
+# Constants (don't change these!)
+#
+$STATE_NONE = 0;
+$STATE_CHANGED = 1;
+$STATE_ADDED = 2;
+$STATE_REMOVED = 3;
+$STATE_LOG = 4;
+
+$LAST_FILE = "/tmp/#cvs.lastdir";
+
+$CHANGED_FILE = "/tmp/#cvs.files.changed";
+$ADDED_FILE = "/tmp/#cvs.files.added";
+$REMOVED_FILE = "/tmp/#cvs.files.removed";
+$LOG_FILE = "/tmp/#cvs.files.log";
+
+$FILE_PREFIX = "#cvs.files";
+
+#
+# Subroutines
+#
+
+sub cleanup_tmpfiles {
+ local($wd, @files);
+
+ $wd = `pwd`;
+ chdir("/tmp") || die("Can't chdir('/tmp')\n");
+ opendir(DIR, ".");
+ push(@files, grep(/^$FILE_PREFIX\..*\.$id$/, readdir(DIR)));
+ closedir(DIR);
+ foreach (@files) {
+ unlink $_;
+ }
+ unlink $LAST_FILE . "." . $id;
+
+ chdir($wd);
+}
+
+sub write_logfile {
+ local($filename, @lines) = @_;
+
+ open(FILE, ">$filename") || die("Cannot open log file $filename.\n");
+ print FILE join("\n", @lines), "\n";
+ close(FILE);
+}
+
+sub append_to_logfile {
+ local($filename, @lines) = @_;
+
+ open(FILE, ">$filename") || die("Cannot open log file $filename.\n");
+ print FILE join("\n", @lines), "\n";
+ close(FILE);
+}
+
+sub format_names {
+ local($dir, @files) = @_;
+ local(@lines);
+
+ $format = "\t%-" . sprintf("%d", length($dir)) . "s%s ";
+
+ $lines[0] = sprintf($format, $dir, ":");
+
+ if ($debug) {
+ print STDERR "format_names(): dir = ", $dir, "; files = ", join(":", @files), ".\n";
+ }
+ foreach $file (@files) {
+ if (length($lines[$#lines]) + length($file) > 65) {
+ $lines[++$#lines] = sprintf($format, " ", " ");
+ }
+ $lines[$#lines] .= $file . " ";
+ }
+
+ @lines;
+}
+
+sub format_lists {
+ local(@lines) = @_;
+ local(@text, @files, $lastdir);
+
+ if ($debug) {
+ print STDERR "format_lists(): ", join(":", @lines), "\n";
+ }
+ @text = ();
+ @files = ();
+ $lastdir = shift @lines; # first thing is always a directory
+ if ($lastdir !~ /.*\/$/) {
+ die("Damn, $lastdir doesn't look like a directory!\n");
+ }
+ foreach $line (@lines) {
+ if ($line =~ /.*\/$/) {
+ push(@text, &format_names($lastdir, @files));
+ $lastdir = $line;
+ @files = ();
+ } else {
+ push(@files, $line);
+ }
+ }
+ push(@text, &format_names($lastdir, @files));
+
+ @text;
+}
+
+sub append_names_to_file {
+ local($filename, $dir, @files) = @_;
+
+ if (@files) {
+ open(FILE, ">>$filename") || die("Cannot open file $filename.\n");
+ print FILE $dir, "\n";
+ print FILE join("\n", @files), "\n";
+ close(FILE);
+ }
+}
+
+sub read_line {
+ local($line);
+ local($filename) = @_;
+
+ open(FILE, "<$filename") || die("Cannot open file $filename.\n");
+ $line = <FILE>;
+ close(FILE);
+ chop($line);
+ $line;
+}
+
+sub read_logfile {
+ local(@text);
+ local($filename, $leader) = @_;
+
+ open(FILE, "<$filename");
+ while (<FILE>) {
+ chop;
+ push(@text, $leader.$_);
+ }
+ close(FILE);
+ @text;
+}
+
+sub build_header {
+ local($header);
+ local($sec,$min,$hour,$mday,$mon,$year) = localtime(time);
+ $header = sprintf("CVSROOT:\t%s\nModule name:\t%s\nChanges by:\t%s@%s\t%02d/%02d/%02d %02d:%02d:%02d",
+ $cvsroot,
+ $modulename,
+ $login, $hostdomain,
+ $year%100, $mon+1, $mday,
+ $hour, $min, $sec);
+}
+
+sub mail_notification {
+ local($name, @text) = @_;
+ open(MAIL, "| $MAILER -s \"CVS Update: " . $modulename . "\" " . $name);
+ print MAIL join("\n", @text), "\n";
+ close(MAIL);
+}
+
+sub write_commitlog {
+ local($logfile, @text) = @_;
+
+ open(FILE, ">>$logfile");
+ print FILE join("\n", @text), "\n";
+ close(FILE);
+}
+
+#
+# Main Body
+#
+
+# Initialize basic variables
+#
+$debug = 0;
+$id = getpgrp(); # note, you *must* use a shell which does setpgrp()
+$state = $STATE_NONE;
+$login = getlogin || (getpwuid($<))[0] || "nobody";
+chop($hostname = `hostname`);
+chop($domainname = `domainname`);
+$hostdomain = $hostname . $domainname;
+$cvsroot = $ENV{'CVSROOT'};
+$do_status = 1;
+$modulename = "";
+
+# parse command line arguments (file list is seen as one arg)
+#
+while (@ARGV) {
+ $arg = shift @ARGV;
+
+ if ($arg eq '-d') {
+ $debug = 1;
+ print STDERR "Debug turned on...\n";
+ } elsif ($arg eq '-m') {
+ $mailto = "$mailto " . shift @ARGV;
+ } elsif ($arg eq '-M') {
+ $modulename = shift @ARGV;
+ } elsif ($arg eq '-s') {
+ $do_status = 0;
+ } elsif ($arg eq '-f') {
+ ($commitlog) && die("Too many '-f' args\n");
+ $commitlog = shift @ARGV;
+ } else {
+ ($donefiles) && die("Too many arguments! Check usage.\n");
+ $donefiles = 1;
+ @files = split(/ /, $arg);
+ }
+}
+($mailto) || die("No -m mail recipient specified\n");
+
+# for now, the first "file" is the repository directory being committed,
+# relative to the $CVSROOT location
+#
+@path = split('/', $files[0]);
+
+# XXX there are some ugly assumptions in here about module names and
+# XXX directories relative to the $CVSROOT location -- really should
+# XXX read $CVSROOT/CVSROOT/modules, but that's not so easy to do, since
+# XXX we have to parse it backwards.
+#
+if ($modulename eq "") {
+ $modulename = $path[0]; # I.e. the module name == top-level dir
+}
+if ($#path == 0) {
+ $dir = ".";
+} else {
+ $dir = join('/', @path);
+}
+$dir = $dir . "/";
+
+if ($debug) {
+ print STDERR "module - ", $modulename, "\n";
+ print STDERR "dir - ", $dir, "\n";
+ print STDERR "path - ", join(":", @path), "\n";
+ print STDERR "files - ", join(":", @files), "\n";
+ print STDERR "id - ", $id, "\n";
+}
+
+# Check for a new directory first. This appears with files set as follows:
+#
+# files[0] - "path/name/newdir"
+# files[1] - "-"
+# files[2] - "New"
+# files[3] - "directory"
+#
+if ($files[2] =~ /New/ && $files[3] =~ /directory/) {
+ local(@text);
+
+ @text = ();
+ push(@text, &build_header());
+ push(@text, "");
+ push(@text, $files[0]);
+ push(@text, "");
+
+ while (<STDIN>) {
+ chop; # Drop the newline
+ push(@text, $_);
+ }
+
+ &mail_notification($mailto, @text);
+
+ exit 0;
+}
+
+# Check for an import command. This appears with files set as follows:
+#
+# files[0] - "path/name"
+# files[1] - "-"
+# files[2] - "Imported"
+# files[3] - "sources"
+#
+if ($files[2] =~ /Imported/ && $files[3] =~ /sources/) {
+ local(@text);
+
+ @text = ();
+ push(@text, &build_header());
+ push(@text, "");
+ push(@text, $files[0]);
+ push(@text, "");
+
+ while (<STDIN>) {
+ chop; # Drop the newline
+ push(@text, $_);
+ }
+
+ &mail_notification($mailto, @text);
+
+ exit 0;
+}
+
+# Iterate over the body of the message collecting information.
+#
+while (<STDIN>) {
+ chop; # Drop the newline
+
+ if (/^In directory/) {
+ push(@log_lines, $_);
+ push(@log_lines, "");
+ next;
+ }
+
+ if (/^Modified Files/) { $state = $STATE_CHANGED; next; }
+ if (/^Added Files/) { $state = $STATE_ADDED; next; }
+ if (/^Removed Files/) { $state = $STATE_REMOVED; next; }
+ if (/^Log Message/) { $state = $STATE_LOG; next; }
+
+ s/^[ \t\n]+//; # delete leading whitespace
+ s/[ \t\n]+$//; # delete trailing whitespace
+
+ if ($state == $STATE_CHANGED) { push(@changed_files, split); }
+ if ($state == $STATE_ADDED) { push(@added_files, split); }
+ if ($state == $STATE_REMOVED) { push(@removed_files, split); }
+ if ($state == $STATE_LOG) { push(@log_lines, $_); }
+}
+
+# Strip leading and trailing blank lines from the log message. Also
+# compress multiple blank lines in the body of the message down to a
+# single blank line.
+#
+while ($#log_lines > -1) {
+ last if ($log_lines[0] ne "");
+ shift(@log_lines);
+}
+while ($#log_lines > -1) {
+ last if ($log_lines[$#log_lines] ne "");
+ pop(@log_lines);
+}
+for ($i = $#log_lines; $i > 0; $i--) {
+ if (($log_lines[$i - 1] eq "") && ($log_lines[$i] eq "")) {
+ splice(@log_lines, $i, 1);
+ }
+}
+
+if ($debug) {
+ print STDERR "Searching for log file index...";
+}
+# Find an index to a log file that matches this log message
+#
+for ($i = 0; ; $i++) {
+ local(@text);
+
+ last if (! -e "$LOG_FILE.$i.$id"); # the next available one
+ @text = &read_logfile("$LOG_FILE.$i.$id", "");
+ last if ($#text == -1); # nothing in this file, use it
+ last if (join(" ", @log_lines) eq join(" ", @text)); # it's the same log message as another
+}
+if ($debug) {
+ print STDERR " found log file at $i.$id, now writing tmp files.\n";
+}
+
+# Spit out the information gathered in this pass.
+#
+&append_names_to_file("$CHANGED_FILE.$i.$id", $dir, @changed_files);
+&append_names_to_file("$ADDED_FILE.$i.$id", $dir, @added_files);
+&append_names_to_file("$REMOVED_FILE.$i.$id", $dir, @removed_files);
+&write_logfile("$LOG_FILE.$i.$id", @log_lines);
+
+# Check whether this is the last directory. If not, quit.
+#
+if ($debug) {
+ print STDERR "Checking current dir against last dir.\n";
+}
+$_ = &read_line("$LAST_FILE.$id");
+
+if ($_ ne $cvsroot . "/" . $files[0]) {
+ if ($debug) {
+ print STDERR sprintf("Current directory %s is not last directory %s.\n", $cvsroot . "/" .$files[0], $_);
+ }
+ exit 0;
+}
+if ($debug) {
+ print STDERR sprintf("Current directory %s is last directory %s -- all commits done.\n", $files[0], $_);
+}
+
+#
+# End Of Commits!
+#
+
+# This is it. The commits are all finished. Lump everything together
+# into a single message, fire a copy off to the mailing list, and drop
+# it on the end of the Changes file.
+#
+
+#
+# Produce the final compilation of the log messages
+#
+@text = ();
+@status_txt = ();
+push(@text, &build_header());
+push(@text, "");
+
+for ($i = 0; ; $i++) {
+ last if (! -e "$LOG_FILE.$i.$id"); # we're done them all!
+ @lines = &read_logfile("$CHANGED_FILE.$i.$id", "");
+ if ($#lines >= 0) {
+ push(@text, "Modified files:");
+ push(@text, &format_lists(@lines));
+ }
+ @lines = &read_logfile("$ADDED_FILE.$i.$id", "");
+ if ($#lines >= 0) {
+ push(@text, "Added files:");
+ push(@text, &format_lists(@lines));
+ }
+ @lines = &read_logfile("$REMOVED_FILE.$i.$id", "");
+ if ($#lines >= 0) {
+ push(@text, "Removed files:");
+ push(@text, &format_lists(@lines));
+ }
+ if ($#text >= 0) {
+ push(@text, "");
+ }
+ @lines = &read_logfile("$LOG_FILE.$i.$id", "\t");
+ if ($#lines >= 0) {
+ push(@text, "Log message:");
+ push(@text, @lines);
+ push(@text, "");
+ }
+ if ($do_status) {
+ local(@changed_files);
+
+ @changed_files = ();
+ push(@changed_files, &read_logfile("$CHANGED_FILE.$i.$id", ""));
+ push(@changed_files, &read_logfile("$ADDED_FILE.$i.$id", ""));
+ push(@changed_files, &read_logfile("$REMOVED_FILE.$i.$id", ""));
+
+ if ($debug) {
+ print STDERR "main: pre-sort changed_files = ", join(":", @changed_files), ".\n";
+ }
+ sort(@changed_files);
+ if ($debug) {
+ print STDERR "main: post-sort changed_files = ", join(":", @changed_files), ".\n";
+ }
+
+ foreach $dofile (@changed_files) {
+ if ($dofile =~ /\/$/) {
+ next; # ignore the silly "dir" entries
+ }
+ if ($debug) {
+ print STDERR "main(): doing 'cvs -nQq status -v $dofile'\n";
+ }
+ open(STATUS, "-|") || exec 'cvs', '-nQq', 'status', '-v', $dofile;
+ while (<STATUS>) {
+ chop;
+ push(@status_txt, $_);
+ }
+ }
+ }
+}
+
+# Write to the commitlog file
+#
+if ($commitlog) {
+ &write_commitlog($commitlog, @text);
+}
+
+if ($#status_txt >= 0) {
+ push(@text, @status_txt);
+}
+
+# Mailout the notification.
+#
+&mail_notification($mailto, @text);
+
+# cleanup
+#
+if (! $debug) {
+ &cleanup_tmpfiles();
+}
+
+exit 0;
diff --git a/gnu/usr.bin/cvs/contrib/mfpipe.pl b/gnu/usr.bin/cvs/contrib/mfpipe.pl
new file mode 100644
index 0000000..bae7a72
--- /dev/null
+++ b/gnu/usr.bin/cvs/contrib/mfpipe.pl
@@ -0,0 +1,88 @@
+#! xPERL_PATHx
+# -*-Perl-*-
+#
+# From: clyne@niwot.scd.ucar.EDU (John Clyne)
+# Date: Fri, 28 Feb 92 09:54:21 MST
+#
+# BTW, i wrote a perl script that is similar to 'nfpipe' except that in
+# addition to logging to a file it provides a command line option for mailing
+# change notices to a group of users. Obviously you probably wouldn't want
+# to mail every change. But there may be certain directories that are commonly
+# accessed by a group of users who would benefit from an email notice.
+# Especially if they regularly beat on the same directory. Anyway if you
+# think anyone would be interested here it is.
+#
+# $Id: mfpipe.pl,v 1.2 1995/07/10 02:01:57 kfogel Exp $
+#
+#
+# File: mfpipe
+#
+# Author: John Clyne
+# National Center for Atmospheric Research
+# PO 3000, Boulder, Colorado
+#
+# Date: Wed Feb 26 18:34:53 MST 1992
+#
+# Description: Tee standard input to mail a list of users and to
+# a file. Used by CVS logging.
+#
+# Usage: mfpipe [-f file] [user@host...]
+#
+# Environment: CVSROOT
+# Path to CVS root.
+#
+# Files:
+#
+#
+# Options: -f file
+# Capture output to 'file'
+#
+
+$header = "Log Message:\n";
+
+$mailcmd = "| mail -s 'CVS update notice'";
+$whoami = `whoami`;
+chop $whoami;
+$date = `date`;
+chop $date;
+
+$cvsroot = $ENV{'CVSROOT'};
+
+while (@ARGV) {
+ $arg = shift @ARGV;
+
+ if ($arg eq '-f') {
+ $file = shift @ARGV;
+ }
+ else {
+ $users = "$users $arg";
+ }
+}
+
+if ($users) {
+ $mailcmd = "$mailcmd $users";
+ open(MAIL, $mailcmd) || die "Execing $mail: $!\n";
+}
+
+if ($file) {
+ $logfile = "$cvsroot/LOG/$file";
+ open(FILE, ">> $logfile") || die "Opening $logfile: $!\n";
+}
+
+print FILE "$whoami $date--------BEGIN LOG ENTRY-------------\n" if ($logfile);
+
+while (<>) {
+ print FILE $log if ($log && $logfile);
+
+ print FILE $_ if ($logfile);
+ print MAIL $_ if ($users);
+
+ $log = "log: " if ($_ eq $header);
+}
+
+close FILE;
+die "Write failed" if $?;
+close MAIL;
+die "Mail failed" if $?;
+
+exit 0;
diff --git a/gnu/usr.bin/cvs/contrib/pcl-cvs/ChangeLog b/gnu/usr.bin/cvs/contrib/pcl-cvs/ChangeLog
new file mode 100644
index 0000000..ac24f44
--- /dev/null
+++ b/gnu/usr.bin/cvs/contrib/pcl-cvs/ChangeLog
@@ -0,0 +1,774 @@
+Wed Nov 22 11:01:50 1995 Joshua Cowan <jcowan@hermit.reslife.okstate.edu>
+
+ * pcl-cvs.el (cvs-changelog-ours-p): use `user-full-name' if
+ `add-log-full-name' unbound, as not every uses the stuff in
+ add-log.el. Same with `add-log-mailing-address'.
+ (cvs-changelog-entries): change to `change-log-mode' unless
+ already in it.
+
+Sun Jul 9 20:57:11 1995 Karl Fogel <kfogel@floss.cyclic.com>
+
+ * "/bin/rmdir" as default, not "/usr/local/bin/rmdir".
+
+Fri Jun 16 15:24:34 1995 Jim Kingdon (kingdon@cyclic.com)
+
+ * pcl-cvs.elc, pcl-cvs-lucid.elc: Added.
+
+ * Makefile.in: Rename from Makefile and set srcdir.
+
+Thu May 18 17:10:27 1995 Jim Blandy <jimb@totoro.bio.indiana.edu>
+
+ Automatically guess CVS log entries from ChangeLog contents.
+ * pcl-cvs.el (cvs-mode-changelog-commit): New command.
+ (cvs-changelog-full-paragraphs): New variable.
+ (cvs-changelog-name, cvs-narrow-changelog,
+ cvs-changelog-paragraph, cvs-changelog-subparagraph,
+ cvs-changelog-entry, cvs-changelog-ours-p, cvs-relative-path,
+ cvs-changelog-entries, cvs-changelog-insert-entries, cvs-union,
+ cvs-insert-changelog-entries, cvs-edit-delete-common-indentation):
+ New functions.
+ (cvs-mode-map): Bind 'C' to cvs-mode-changelog-commit.
+ (cvs-mode): Mention cvs-mode-changelog-commit in docstring.
+
+ Give the info files names ending in ".info".
+ * Makefile (INFOFILES, install_info): Change pcl-cvs to
+ pcl-cvs.info.
+ (pcl-cvs.info): Target renamed from pcl-cvs.
+ (DISTFILES): pcl-cvs removed; we handle the info files explicitly
+ in the dist-dir target.
+ (dist-dir): Depend on pcl-cvs.info. Distribute pcl-cvs.info*.
+ * pcl-cvs.texinfo: Change @setfilename appropriately.
+ * INSTALL: Updated.
+ * .cvsignore: Correctly ignore the info files.
+
+ * README: Note that pcl-cvs has been tested under 19.28, and that
+ the "cookie" naming conflict was resolved in 19.11.
+
+ * Makefile (pcl-cvs-lucid.elc): Changed this target from
+ pcl-cvs-lucid.el. That's a source file, for goodness' sake!
+
+Tue May 9 13:56:50 1995 Jim Blandy <jimb@totoro.bio.indiana.edu>
+
+ * Change references to "Cygnus's remote CVS" to "Cyclic CVS".
+
+Wed May 3 13:55:27 1995 Jim Blandy <jimb@totoro.bio.indiana.edu>
+
+ * pcl-cvs.el (cvs-parse-stderr): Handle colons after both
+ "rcsmerge" and "warning".
+
+Fri Apr 28 22:38:14 1995 Jim Blandy <jimb@totoro.bio.indiana.edu>
+
+ * Makefile (ELFILES): Include pcl-cvs-startup.el.
+ (info, pcl-cvs): Call makeinfo appropriately for modern versions.
+ (pcl-cvs.aux): List dependency on pcl-cvs.texinfo.
+ (pcl-cvs.ps): New target.
+ (DVIPS): New variable.
+ (dist-dir): Renamed from dist, updated to accept DISTDIR value
+ passed from parent.
+ (DISTFILES): New varible.
+ (pcl-cvs.elc, pcl-cvs-lucid.elc): Add targets to elcfiles target.
+
+Tue Apr 25 21:33:49 1995 Jim Blandy <jimb@totoro.bio.indiana.edu>
+
+ * pcl-cvs.el: (cvs-parse-stderr): Recognize "conflicts" as well as
+ "overlaps" before "during merge."
+
+Thu Feb 16 12:17:20 1995 Jim Blandy <jimb@totoro.bio.indiana.edu>
+
+ * pcl-cvs.el (cvs-parse-stderr): Recognize "conflicts found in..."
+ messages attributed to "cvs server", as well as "cvs update".
+
+Sat Feb 4 01:47:01 1995 Jim Blandy <jimb@totoro.bio.indiana.edu>
+
+ * pcl-cvs.el: Deal with the 'P' action, produced by remote CVS.
+ (cvs-parse-stdout): Treat 'P' like 'U' --- file is updated.
+
+Tue Jan 31 23:31:39 1995 Jim Blandy <jimb@totoro.bio.indiana.edu>
+
+ * pcl-cvs.el (cvs-cvsroot-required): New variable.
+ (cvs-do-update): If cvs-cvsroot-required is not set, don't complain if
+ CVSROOT and cvs-cvsroot are both unset.
+
+Sun Jan 22 21:22:22 1995 Jim Blandy <jimb@totoro.bio.indiana.edu>
+
+ * pcl-cvs.el (cvs-parse-stderr):
+ Some changes for Cygnus's Remote CVS. Treat
+ messages like "cvs server: Updating DIRECTORY" as we treat those like
+ "cvs update: Updating DIRECTORY". Ignore other messages starting with
+ "cvs server".
+
+ * pcl-cvs.el (cvs-parse-stderr): Re-indent.
+
+ * .cvsignore: Add ignore list for Texinfo litter.
+
+ * Makefile (lispdir): Set appropriately for totoro.
+ * pcl-cvs.el (cvs-program, cvs-diff-program, cvs-rmdir-program): Same.
+
+Tue Jun 1 00:00:03 1993 Per Cederqvist (ceder@lysator.liu.se)
+
+ * Release 1.05. (This release was promised before the end of May,
+ but I didn't quite make it. No, I didn't fake the date above).
+
+Mon May 31 01:32:25 1993 Per Cederqvist (ceder@lysator.liu.se)
+
+ * Removed the elib sub-directory. Users must now get the Elib
+ library separately.
+ * pcl-cvs.texinfo: Document it.
+
+ * pcl-cvs-lucid.el: A new version, supplied by Jamie Zawinsky,
+ added.
+
+ * pcl-cvs Id 68: Transform RCS keywords
+ * Makefile (pcl-cvs-$(VER)): Remove the $ signs in most files in
+ the distribution.
+
+ * pcl-cvs Id 76: Extra " in cvs-mode-add.
+ * pcl-cvs.el (cvs-mode-add): Don't add the extra level of quotes
+ around the log message, since it doesn't work with CVS.
+
+ * pcl-cvs Id 56: '-d <CVSROOT>' support in pcl-cvs
+ * pcl-cvs.el (cvs-change-cvsroot): New function.
+
+ * pcl-cvs Id 77: *cvs* isn't cleared properly
+ * pcl-cvs.el (cvs-do-update): Always erase the *cvs* buffer and
+ re-create the collection.
+
+ * pcl-cvs.el (cvs-do-update): Set mode-line-process in the *cvs*
+ buffer.
+ * pcl-cvs.el (cvs-mode): Reset mode-line-process.
+
+ * pcl-cvs Id 59: sort .cvsignore alphabetically!
+ * pcl-cvs.el (cvs-sort-ignore-file): New variable.
+ * pcl-cvs.el (cvs-mode-ignore): Use it.
+ * pcl-cvs.texinfo: Document it.
+
+ * pcl-cvs Id 75: Require final newline.
+ * pcl-cvs.el (cvs-commit-buffer-require-final-newline): New
+ variable.
+ * pcl-cvs.el (cvs-edit-done): Use it.
+ * pcl-cvs.texinfo: Document it.
+
+ * pcl-cvs Id 72: make clean deletes lucid-emacs.el
+ * dist-makefile (ELCFILES): Fixed a typo.
+
+ * pcl-cvs Id 46: "cvs remove f" "touch f" "cvs update f" -> parse err.
+ * pcl-cvs.el (cvs-fileinfo->type): New type: REM-EXIST.
+ * pcl-cvs.el (cvs-shadow-entry-p): A REMOVED that follows a
+ REM-EXIST is a shadow.
+ * pcl-cvs.el (cvs-parse-stderr): Recognize the "should be removed
+ and is still there" message.
+ * pcl-cvs.el (cvs-pp): Recognize REM-EXIST.
+ * pcl-cvs.el (cvs-mode-undo-local-changes): Recognize and complain
+ about REM-EXIST. Defensive test added: complain about unknown types.
+
+ * pcl-cvs.el (cvs-mode-add): Add an extra level of quotes around
+ the log message. This is apparently needed by RCVS. <This change
+ has been removed. --ceder>.
+
+ * pcl-cvs.el (cvs-parse-stderr): Ignore output from RCVS.
+
+Tue Apr 27 00:48:40 1993 Per Cederqvist (ceder@lysator.liu.se)
+
+ * pcl-cvs.el (cvs-startup-message): Now a defconst instead of a
+ defvar.
+ * pcl-cvs.el (cvs-mode-commit): Add a defvar for it.
+
+ * dist-makefile (EMACS): Use $(EMACS) instead of hard-coding 'emacs'.
+
+Sat Apr 17 12:47:10 1993 Per Cederqvist (ceder@lysator.liu.se)
+
+ * Release 1.04.
+
+ * pcl-cvs.texinfo: Updated the Contributors node.
+
+ * pcl-cvs Id 58: Lucid GNU Emacs support
+ * pcl-cvs-lucid.el: New file, contributed by the people at Lucid.
+ * pcl-cvs.el: Autoload pcl-cvs-lucid if running in an Lucid GNU
+ Emacs.
+ * compile-all.el: (files-to-compile): Add pcl-cvs-lucid.
+ * dist-makefile (ELFILES, ELCFILES): Dito.
+
+ * pcl-cvs Id 55: cvs-diff-backup swaps old and new version.
+ * pcl-cvs.el (cvs-diff-backup-extractor): Old version should be
+ first.
+ * pcl-cvs.el (cvs-mode-diff-backup): Call cvs-backup-diffable
+ correctly.
+
+ * pcl-cvs Id 64: elib substitute
+ * dist-makefile (install): Warn about Elib.
+ * pcl-cvs.texinfo: Talk about Elib.
+
+ * pcl-cvs Id 50: Committing the *commit* buffer twice.
+ * pcl-cvs.el (cvs-edit-done): Report an error if cvs-commit-list
+ is empty, and empty it when the commit is done.
+
+ * pcl-cvs Id 56: '-d <CVSROOT>' support.
+ * pcl-cvs.el (cvs-cvsroot): New variable.
+ * pcl-cvs.el (cvs-do-update, all callers of cvs-execute-list): Use
+ it everywhere CVS is called, to override CVSROOT.
+ * pcl-cvs.texinfo (Customization): Document it.
+
+Thu Apr 1 00:34:55 1993 Per Cederqvist (ceder@lysator.liu.se)
+
+ * pcl-cvs.el (cvs-retrieve-revision-to-tmpfile): Exit status nil
+ from call-process means everything was successful in some Emacs
+ versions.
+
+ * pcl-cvs.el (cvs-mode-map): Bind "q" to bury-buffer.
+ * pcl-cvs.texinfo: Document it.
+
+Thu Mar 11 00:05:03 1993 Per Cederqvist (ceder@lysator.liu.se)
+
+ * Release 1.03-Emerge (not released).
+
+ * Makefile (pcl-cvs-$(VER)): Don't includ elib-dll-debug.el in the
+ distribution. (It's included as elib/dll-debug.el).
+
+ * pcl-cvs.el (cvs-mode): Document the "e" key (cvs-mode-emerge).
+
+Tue Mar 9 00:02:57 1993 Per Cederqvist (ceder@lysator.liu.se)
+
+ * pcl-cvs.texinfo (Emerge): New node.
+
+ * pcl-cvs.el (cvs-kill-buffer-visiting): New function.
+
+ * pcl-cvs.el (cvs-mode-emerge): Handle Conflict and Merged files.
+
+ * pcl-cvs.el (cvs-retrieve-revision-to-tmpfile): Handle any revision.
+
+ * pcl-cvs.el (cvs-fileinfo-*): Store base-revision instead of
+ backup-file.
+
+ * pcl-cvs.el (cvs-backup-diffable): The file is only diffable if
+ the backup file is readable.
+
+ * pcl-cvs.el (cvs-mode-map): Bind "e" to cvs-mode-emerge instead
+ of cvs-mode-find-file (which is anyhow bound to "f").
+
+Mon Mar 8 23:06:52 1993 Per Cederqvist (ceder@lysator.liu.se)
+
+ * pcl-cvs.el (cvs-mode-emerge): New function. Currently only
+ handles emerge of Modified files.
+
+ * pcl-cvs.el (cvs-retrieve-revision-to-tmpfile): New function.
+
+Sun Jan 24 20:07:18 1993 Per Cederqvist (ceder@lysator.liu.se)
+
+ * elib-dll-debug.el: Moved to elib.
+
+Mon Jan 18 00:35:59 1993 Per Cederqvist (ceder@mauritz)
+
+ * pcl-cvs.el (cvs-do-update): Added a probably unnecessary sit-for.
+
+ * Release 1.03-Elib-0.05.1 (not released).
+
+ * Elib 0.05 compatibility:
+ * elib-dll-debug.el, pcl-cvs-buffer.el, test-dll.el: Fix the
+ require strings.
+ * pcl-cvs.el (cvs-pp): Insert the string.
+
+ * Release 1.03-Elib-0.05 (not released).
+
+ * elib: New directory, containing the parts of elib that are
+ required for pcl-cvs. Changes to the files in that directory
+ that are present in Elib are documented in the ChangeLog of
+ Elib, not here.
+ * Makefile (pcl-cvs-$(VER)): Copy the new dir to the distribution.
+ * dist-makefile (ELFILES, ELCFILES): Don't include the Elib files.
+
+Fri Jan 8 02:43:49 1993 Per Cederqvist (ceder@konrad)
+
+ * pcl-cvs.el (cvs-mode-map): Bind "e" to cvs-mode-find-file, like
+ in dired.
+
+Sun Jan 3 23:25:13 1993 Per Cederqvist (ceder@konrad)
+
+ * elib-dll.el, elib-node.el, cookie.el: Moved to the elib package.
+ Pcl-cvs now requires elib.
+
+Tue Dec 29 22:06:57 1992 Per Cederqvist (ceder@konrad)
+
+ * pcl-cvs.el: Tracked the latest (last?) rename of all functions
+ in cookie.el.
+
+Thu Sep 24 00:29:16 1992 Per Cederqvist (ceder@robert)
+
+ * pcl-cvs.texinfo (Archives): This version is not distributed with
+ CVS 1.3, so don't claim that it is.
+
+Fri Aug 21 15:17:08 1992 Per Cederqvist (ceder@maskros)
+
+ * pcl-cvs.el (cvs-parse-stderr): Fixed two "(set head" that should
+ be "(setq head".
+
+Thu Aug 20 05:53:58 1992 Per Cederqvist (ceder@robin)
+
+ * cookie.el: Changes to this file is documented in the ChangeLog
+ of elib in the future.
+
+Tue Aug 18 03:30:28 1992 Per Cederqvist (ceder@robin)
+
+ * pcl-cvs.el: Don't use cookie-last-tin (which no longer exists).
+
+ * cookie.el: Use prefix cookie:: for internal functions.
+
+ * cookie.el: (cookie:enter-after, cookie:enter-before,
+ cookie:nth-cookie): Implemented.
+ * cookie.el: No longer define (impl).
+
+ * cookie.el: More renames:
+ cookie:next-cookie -> cookie:goto-next-tin
+ cookie:previous-cookie -> cookie:goto-previous-tin
+ tin-next -> cookie:next-tin
+ tin-previous -> cookie:previous-tin
+ tin-nth -> cookie:nth-tin
+ tin-delete -> cookie:delete-tin
+ cookie:collect -> cookie:collect-cookies
+ cookie:tin-collect -> cookie:collect-tins
+ (new) -> cookie:tin-collect-cookies
+ (new) -> cookie:tin-collect-tins
+ cookie:refresh -> cookie:refresh-all
+ tin-invalidate-tins -> cookie:invalidate-tins
+
+Mon Aug 17 01:39:49 1992 Per Cederqvist (ceder@robin)
+
+ * cookie.el (cookie:set-buffer-bind-dll-let*): New macro. Used in
+ many places instead of cookie:set-buffer-bind-dll.
+ * cookie.el (cookie:set-buffer-bind-dll): Renamed the macro
+ cookie:set-buffer to this.
+
+ * pcl-cvs.el (cvs-use-temp-buffer): Set default-directory.
+
+Sun Aug 16 20:51:30 1992 Per Cederqvist (ceder@robin)
+
+ * pcl-cvs.el (cvs-add-sub): Fixed call to cvs-add-file-update-buffer.
+
+Sat Aug 8 20:28:21 1992 Per Cederqvist (ceder@robin)
+
+ * Release 1.03-Cookie-II (not released).
+
+ * pcl-cvs.el (cvs-mode-diff-cvs): Don't care about the exit status
+ from ``cvs diff''.
+
+ * pcl-cvs.el (cvs-mode): Document cvs-mode-undo-local-changes.
+ * pcl-cvs.el (cvs-diffable): New function.
+
+ * pcl-cvs.el: Use the new cookie package.
+ * pcl-cvs.el (cvs-cookie-handle): New variable.
+ * pcl-cvs.el (cvs-do-update): User the new cookie:create
+ interface, and cookie:clear if the buffer already existed. Make
+ the buffer read-only.
+ * pcl-cvs.el (cvs-mode-next-line, cvs-mode-previous-line): New
+ functions (used instead of cookie:next-cookie and
+ cookie:previous-cookie).
+
+ * cookie.el: Major redesign. The handle that is passed to all
+ cookie functions is now a new datatype, and not the buffer that
+ the cookies resides in. This way it is possible to have more than
+ one set of cookies in a buffer. Things that used to be
+ buffer-local variables are now fields in the handle data type.
+ cookie-last-tin is no longer available.
+ * cookie.el (cookie:create): The buffer is not cleared, nor set to
+ be read-only.
+ * cookie.el (cookie:next-cookie, cookie:previous-cookie): Since
+ the first argument is now a handle and not a buffer, these can no
+ longer be called interactively. You have to write a small wrapper
+ about them.
+ * cookie.el (cookie:buffer): New function.
+
+Tue Aug 4 03:02:25 1992 Per Cederqvist (ceder@robert)
+
+ * pcl-cvs.texinfo (Bugs): Renamed "Reporting bugs and ideas" to
+ "Bugs" and added a table of known bugs/FAQ:s.
+
+Mon Aug 3 00:19:39 1992 Per Cederqvist (ceder@robert)
+
+ * pcl-cvs.el, pcl-cvs.texinfo: Big Renaming Time!
+ The commands that operate in the *cvs* buffer:
+ cvs-add-change-log-entry-other-window -> cvs-mode-add-change-log-entry-other-window
+ cvs-mark-all-files -> cvs-mode-mark-all-files
+ cvs-revert-updated-buffers -> cvs-mode-revert-updated-buffers
+ cvs-undo-local-changes -> cvs-mode-undo-local-changes
+ cvs-unmark-up -> cvs-mode-unmark-up
+ cvs-acknowledge -> cvs-mode-acknowledge
+ cvs-unmark-all-files -> cvs-mode-unmark-all-files
+ cvs-add -> cvs-mode-add
+ cvs-diff-backup -> cvs-mode-diff-backup
+ cvs-commit -> cvs-mode-commit
+ cvs-diff-cvs -> cvs-mode-diff-cvs
+ cvs-find-file -> cvs-mode-find-file
+ cvs-update-no-prompt -> cvs-mode-update-no-prompt
+ cvs-ignore -> cvs-mode-ignore
+ cvs-log -> cvs-mode-log
+ cvs-mark -> cvs-mode-mark
+ cvs-find-file-other-window -> cvs-mode-find-file-other-window
+ cvs-remove-file -> cvs-mode-remove-file
+ cvs-status -> cvs-mode-status
+ cvs-remove-handled -> cvs-mode-remove-handled
+ cvs-unmark -> cvs-mode-unmark
+
+ * pcl-cvs.el (cvs-cvs-diff-flags): Variable deleted.
+ * pcl-cvs.el (cvs-diff-cvs): Use cvs-diff-flags instead.
+ * pcl-cvs.texinfo (Customization): Update the doc.
+
+ * pcl-cvs.el (cvs-diff-cvs): Handle exit status 0 (no diffs), 1
+ (diffs) and other (error).
+ * pcl-cvs.el (cvs-execute-list): Add support for this kind of
+ thing.
+
+ * Revert buffers for committed files:
+ * pcl-cvs.el (cvs-auto-revert-after-commit): New variable.
+ * pcl-cvs.texinfo (Committing changes, Customization): Document
+ it.
+ * pcl-cvs.el (cvs-after-commit-function): New function.
+
+ * pcl-cvs.el (cvs-execute-list): Return the exit status or nil.
+ * pcl-cvs.el (cvs-edit-done, cvs-diff-cvs, cvs-remove-file,
+ cvs-undo-local-changes, cvs-add, cvs-status, cvs-log): Use the
+ exit status to generate an error message.
+
+
+ * pcl-cvs.el (cvs-do-update): It should be "cvs -n update -l", not
+ "cvs -l update -n". Put the -n and/or -l in the message that is
+ displayed in the *cvs* buffer during the update.
+
+Sat Aug 1 00:55:49 1992 Per Cederqvist (ceder@robert)
+
+ * cookie.el (cookie-sort): New function.
+
+ * cookie.el (cookie-clear): Rewritten. No longer clears all local
+ variables.
+
+Tue Jul 28 17:21:17 1992 Per Cederqvist (ceder@robin)
+
+ * pcl-cvs.el (cvs-parse-stderr): Try to handle the output from RCS
+ when it is compiled without DIFF3_BIN and a conflict occurs.
+
+ * pcl-cvs.texinfo (Getting Started): Fixed typo.
+
+ * pcl-cvs-startup.el (cvs-update-other-window): Make the autoload
+ be interactive.
+
+Mon Jul 27 19:36:40 1992 Per Cederqvist (ceder@robin)
+
+ * pcl-cvs.el (cvs-revert-updated-buffers, cvs-revert-fileinfo):
+ New functions.
+ * pcl-cvs.texinfo (Reverting your buffers): Document it.
+
+ * pcl-cvs.el (cvs-fileinfo->full-path): New function.
+ * pcl-cvs.el (cvs-full-path): Use it.
+
+ * cookie.el (cookie-map, cookie-map-reverse): Better doc-
+ string. Removed the unused local variable 'result'.
+
+ * compile-all.el: Renamed elib-files to files-to-compare.
+ * compile-all.el (compile-pcl-cvs): Bind load-path in a let
+ statement instead of globally.
+
+Thu Jul 23 19:02:41 1992 Per Cederqvist (ceder@robin)
+
+ * pcl-cvs.el (cvs-do-update): Check that CVSROOT is set.
+ * pcl-cvs.el (cvs-diff-cvs): Check that cvs-cvs-diff-flags is a
+ list.
+ * pcl-cvs.el (cvs-diff-backup): Check that cvs-diff-flags is a
+ list.
+
+Tue Jul 21 11:27:39 1992 Per Cederqvist (ceder@robin)
+
+ * pcl-cvs.el (cvs-parse-error): Make the *cvs* buffer writeable
+ before trying to write the email message. Require sendmail before
+ trying to switch to mail-mode.
+
+ * pcl-cvs.el (cvs-do-update): Check that cvs-program exists.
+
+ * pcl-cvs.el (cvs-skip-line): Fixed bracketing error.
+
+Mon Jul 20 10:31:51 1992 Per Cederqvist (ceder@robin)
+
+ * Release 1.03.
+
+ * pcl-cvs.el, cookie.el: Indentation fixes.
+
+ * Makefile (pcl-cvs-$(VER)): Include NEWS in the distribution.
+
+ * pcl-cvs.el (cvs-rm-program): Deleted.
+ * pcl-cvs.el (cvs-rmdir-program, cvs-lock-file): New variables.
+
+ * Handle lock files in a nicer way:
+ * pcl-cvs.el (cvs-update-filter, cvs-delete-lock,
+ cvs-lock-file-p): New functions.
+ * pcl-cvs.el (cvs-do-update, cvs-sentinel): Redirect stdout to the
+ temporary file, not stderr. Use cvs-update-filter.
+ * pcl-cvs.el (cvs-parse-update): New arguments.
+ * pcl-cvs.el (cvs-parse-buffer): Renamed to cvs-parse-update.
+ * pcl-cvs.el (cvs-stderr-file): Renamed to cvs-stdout-file.
+ * pcl-cvs.texinfo (Miscellaneous commands, Updating the
+ directory): Document cvs-delete-lock.
+
+ * pcl-cvs.el (cvs-mode): Don't reset buffer-read-only.
+
+ * pcl-cvs.el (cvs-find-file-other-window): Don't save-some-buffers.
+
+Thu Jul 16 00:19:58 1992 Per Cederqvist (ceder@robin)
+
+ * pcl-cvs.el, test-cookie-el: Use the new names from cookie.el.
+
+ * cookie.el: Big Renaming Time!
+ External functions:
+ cookie-next -> tin-next
+ cookie-previous -> tin-previous
+ cookie-nth -> tin-nth
+ cookie-delete -> tin-delete
+ cookie-filter-tins -> tin-filter
+ cookie-get-selection -> tin-get-selection
+ cookie-start-marker -> tin-start-marker
+ cookie-end-marker -> tin-end-marker
+ cookie-invalidate-tins -> tin-invalidate-tins
+ cookie-collect-tins -> tin-collect
+ cookie-collect-cookies -> cookie-collect
+ Internal functions:
+ cookie-create-tin -> cookie-create-wrapper
+ cookie-tin-start-marker -> cookie-wrapper-start-marker
+ cookie-tin-cookie-safe -> cookie-wrapper-cookie-safe
+ cookie-tin-cookie -> cookie-wrapper-cookie
+ set-cookie-tin-start-marker -> cookie-wrapper-set-start-marker
+ set-cookie-tin-cookie -> cookie-wrapper-set-cookie
+ cookie-tin-p -> cookie-wrapper-p
+ cookie-create-tin-and-insert -> cookie-create-wrapper-and-insert
+
+ * pcl-cvs.el (cvs-find-file, cvs-find-file-other-window): Signal
+ an appropriate error message if the *cvs* buffer is empty.
+
+ * cookie.el (cookie-create): Make the buffer read-only.
+ * cookie.el (cookie-create-tin-and-insert, cookie-refresh,
+ cookie-delete-tin-internal, cookie-refresh-tin): Bind
+ buffer-read-only to nil while changing the contents of
+ the buffer.
+
+ * pcl-cvs.el (cvs-byte-compile-files): New function.
+ * pcl-cvs.texinfo (Miscellaneous commands): Document it.
+
+ * pcl-cvs.el (cvs-diff-ignore-marks): New variable.
+ * pcl-cvs.el (cvs-diff-cvs, cvs-diff-backup): Don't consider
+ marked files to be selected if a prefix argument is given XOR the
+ variable cvs-diff-ignore-marks is non-nil.
+ * pcl-cvs.el (cvs-get-marked): New optional argument `ignore-marks'.
+ * pcl-cvs.texinfo (Customization, Viewing differences): Document
+ this behaviour.
+
+ * pcl-cvs.el (cvs-undo-local-changes): New function.
+ * pcl-cvs.texinfo (Undoing changes): Document
+ cvs-undo-local-changes.
+ * pcl-cvs.el (cvs-mode-map): cvs-unmark-all-files moved from "U"
+ to "ESC DEL". cvs-undo-local-changes bound to "U".
+ * pcl-cvs.texinfo (Marking files): Document ESC DEL.
+
+ * pcl-cvs.el (cvs-skip-line): New arguments. All callers updated.
+ Now calls cvs-parse-error if a parse error occurs.
+ * pcl-cvs.el (cvs-parse-error): New function that creates a bug
+ report.
+ * pcl-cvs.el (cvs-parse-stderr, cvs-parse-stdout): New arguments.
+ The only caller (cvs-parse-buffer) updated. Call cvs-parse-error
+ in case of parse error.
+
+ * pcl-cvs.el (pcl-cvs-version): New variable.
+
+ * cookie.el (cookie-create): Kill all local variables in the buffer.
+
+Fri Jul 10 11:17:40 1992 Per Cederqvist (ceder@robin)
+
+ * Release 1.03beta1.
+
+Thu Jul 9 03:12:00 1992 Per Cederqvist (ceder@robin)
+
+ * pcl-cvs.el (cvs-update-running): New variable.
+ * pcl-cvs.el (cvs-do-update): Use it instead of the previous local
+ variable cvs-process (that no longer exists). Make sure that only
+ one `cvs update' runs at any given moment.
+ * pcl-cvs.el (cvs-sentinel): Reset cvs-update-running when the
+ update process exits.
+
+ * pcl-cvs.el (cvs-update): Switch to the *cvs* buffer.
+ * pcl-cvs.el (cvs-update-other-window): New function.
+ * pcl-cvs-startup.el (cvs-update-other-window): Added a autoload
+ for it.
+ * pcl-cvs.el (cvs-do-update): Don't pop up any buffer in a window
+ - let cvs-update or cvs-update-other-window handle that. Also
+ don't kill the *cvs* buffer, but rather insert a "Running cvs..."
+ message into it.
+ * pcl-cvs.el (cvs-parse-buffer): Don't change the window
+ configuration.
+
+ * pcl-cvs.el (cvs-create-fileinfo, cvs-pp, cvs-fileninfo->type):
+ New type for a fileinfo: MESSAGE.
+
+ * pcl-cvs.el (cvs-cvs-buffer): Deleted the variable. Use
+ cvs-buffer-name instead. (I no longer have any plans to allow more
+ than one cvs update to run at the same time - things only get
+ confusing). Changed all places where cvs-cvs-buffer was used.
+
+ * pcl-cvs.el: Take care of update programs (the -u option in the
+ modules file):
+ * pcl-cvs.el (cvs-update-prog-output-skip-regexp): New variable.
+ * pcl-cvs.el (cvs-parse-stdout): Skip output from the update
+ program (using cvs-update-prog-output-skip-regexp).
+ * pcl-cvs.texinfo (Future enhancements): Document that the
+ solution is not as good as it should be.
+ * pcl-cvs.texinfo (Customization): Document the variable.
+
+Wed Jul 8 20:29:44 1992 Per Cederqvist (ceder@robin)
+
+ * pcl-cvs.el (cvs-do-update): Check that this-dir really exists
+ and is a directory, and that this-dir/CVS exists and is a
+ directory.
+
+Tue Jul 7 01:02:24 1992 Per Cederqvist (ceder@robin)
+
+ * pcl-cvs.texinfo (Customization): Document TMPDIR.
+
+ * This chunk of modifications should make it possible to run
+ pcl-cvs on hosts that do not line-buffer stdout (such as
+ DECstation). They work by diverting stdout and stderr from
+ `cvs update' and later sorting them together.
+ * pcl-cvs.el (cvs-parse-stderr): Don't fail to parse conflict
+ data.
+ * pcl-cvs.el (cvs-remove-stdout-shadows, cvs-shadow-entry-p): New
+ functions.
+ * pcl-cvs.el (cvs-parse-buffer): Use it.
+ * pcl-cvs.el (cvs-remove-empty-directories): New function.
+ * pcl-cvs.el (cvs-remove-handled, cvs-parse-buffer): Use it.
+ * pcl-cvs.el (cvs-get-current-dir): New argument ROOT-DIR. All
+ calls to cvs-get-current-dir updated.
+ * pcl-cvs.el (cvs-do-update): Allocate a tmp file. Use cvs-shell
+ (typically /bin/sh) to redirect stderr from CVS to the tmp file.
+ * pcl-cvs.el (cvs-sentinel): Handle the tmp file. Remove it when
+ it is parsed.
+ * pcl-cvs.el (cvs-parse-buffer): New argument STDERR-BUFFER. All
+ calls to cvs-parse-buffer updated. Rewritten to handle the
+ separation of stderr and stdout.
+ * pcl-cvs.el (cvs-shell, cvs-stderr-file): New variables.
+ * pcl-cvs.el (cvs-compare-fileinfos, cvs-parse-stderr,
+ cvs-parse-stdout): New functions.
+
+ * pcl-cvs.el (cvs-parse-buffer): Some modifications for output
+ from RCS 5.6.
+
+Tue Apr 7 09:11:27 1992 Per Cederqvist (ceder@leopold)
+
+ * Release 1.02.
+
+ * pcl-cvs.el (cvs-diff-backup, cvs-edit-done, cvs-status): Call
+ save-some-buffers.
+
+ * pcl-cvs.el (cvs-diff-backup-extractor): Fixed syntax error.
+
+ * Makefile, README, compile-all.el, dist-makefile, pcl-cvs.el,
+ pcl-cvs.texinfo (XXRELEASEXX): A magic string that is substituted
+ for the current release number when a distribution is made.
+ (Release 1.01 says that it is release 1.00).
+
+ * pcl-cvs.el (cvs-find-file): Added missing pair of parenthesis.
+
+Mon Mar 30 14:25:26 1992 Per Cederqvist (ceder@leopold)
+
+ * Release 1.01.
+
+ * pcl-cvs.el (cvs-parse-buffer): The message when waiting for a
+ lock has been changed.
+
+Sun Mar 29 05:29:57 1992 Per Cederqvist (ceder@leopold)
+
+ * Release 1.00.
+
+ * pcl-cvs.el (cvs-do-update, cvs-sentinel, cvs-parse-buffer):
+ Major rewrite of buffer and window selection and handling.
+ The *cvs* buffer is now killed whenever a new "cvs update" is
+ initiated. The -update buffer is replaced with the *cvs*
+ buffer when the update is completed.
+
+Sat Mar 28 21:03:05 1992 Per Cederqvist (ceder@robin)
+
+ * pcl-cvs.el (cvs-delete-unused-temporary-buffers): Fixed it.
+
+ * pcl-cvs.el (cvs-auto-remove-handled): New variable.
+ * pcl-cvs.el (cvs-edit-done): Use it.
+ * pcl-cvs.texinfo (Customization, Removing handled entries):
+ Document it.
+
+ * pcl-cvs.el (cvs-mode): Turn of the undo feature. It really
+ isn't useful in a cookie buffer...
+
+ * pcl-cvs.el (cvs-edit-done): Committing a file now looks more
+ like diffing a file. The window handling is better.
+ * pcl-cvs.el (cvs-use-temp-buffer): The &optional switch is no
+ longer needed.
+
+Mon Mar 23 00:20:33 1992 Per Cederqvist (ceder@robin)
+
+ * Release 0.97.
+
+ * pcl-cvs.el (default-directory): Make sure it always ends in a
+ slash. fileinfo->dir does NOT end in a slash, and I had forgotten
+ to call file-name-as-directory in various places.
+
+ * pcl-cvs.el (cvs-diff-backup-extractor): Signal an error if a
+ fileinfo without backup file is given.
+
+ * pcl-cvs.el (cvs-mode): Added documentation.
+
+ * pcl-cvs.el (cvs-execute-list): Fix the order of files in the
+ same directory.
+
+ * pcl-cvs.el (cvs-log-flags, cvs-status-flags): New variables.
+ * pcl-cvs.el (cvs-log, cvs-status): Use them.
+ * pcl-cvs.texinfo (Customization): Document them.
+
+ * pcl-cvs.el (cvs-diff-backup): Filter non-backup-diffable files
+ at an earlier stage, like cvs-commit does.
+
+ * pcl-cvs.el (cvs-diff-flags): New variable.
+ * pcl-cvs.el (cvs-diff-backup): Use it.
+ * pcl-cvs.texinfo (Customization): Document it.
+
+ * pcl-cvs.el (cvs-execute-single-file-list): Remove &rest before
+ last argument. No callers needed updating.
+
+ * pcl-cvs.el (cvs-execute-list): Remove the &rest before the last
+ argument (constant-args). Update all callers of cvs-execute-list
+ to use the new calling convention.
+ * pcl-cvs.el (cvs-cvs-diff-flags): Now a list of strings instead
+ of a string.
+ * pcl-cvs.texinfo (Customization): Document the change to
+ cvs-cvs-diff-flags.
+
+ * Release 0.96.
+
+ * pcl-cvs.el (cvs-cvs-diff-flags): New variable.
+ * pcl-cvs.el (cvs-diff-cvs): Use it.
+ * pcl-cvs.texinfo (Customization, Viewing differences): Document it.
+
+ * pcl-cvs.el (cvs-use-temp-buffe): Don't switch to the temporary
+ buffer. Use display-buffer and set-buffer instead. This way
+ cvs-log, cvs-status, cvs-diff-cvs and friends don't select the
+ temporary buffer. The cursor will remain in the *cvs* buffer.
+
+Sun Mar 22 21:50:18 1992 Per Cederqvist (ceder@robin)
+
+ * pcl-cvs.el (cvs-find-file, cvs-find-file-other-window): Don't
+ prompt when reading in a directory in dired.
+
+ * Makefile (pcl-cvs-$(VER)): Include pcl-cvs-startup.el in the
+ distribution.
+
+ * dist-makefile (pcl-cvs.dvi): Don't fail even if texindex does
+ not exist.
+
+ * pcl-cvs.texinfo (@setchapternewpage): Changed from 'off' to 'on'.
+ * pcl-cvs.texinfo (Variable index): Joined into function index.
+ * pcl-cvs.texinfo (Key index): add a description about the key.
+ * pcl-cvs.texinfo: Many other small changes.
+
+Wed Mar 18 01:58:38 1992 Per Cederqvist (ceder@leopold)
+
+ * Use GNU General Public License version 2.
+
diff --git a/gnu/usr.bin/cvs/contrib/pcl-cvs/INSTALL b/gnu/usr.bin/cvs/contrib/pcl-cvs/INSTALL
new file mode 100644
index 0000000..7679967
--- /dev/null
+++ b/gnu/usr.bin/cvs/contrib/pcl-cvs/INSTALL
@@ -0,0 +1,89 @@
+This text is copied from the TeXinfo manual for pcl-cvs.
+
+Installation of the pcl-cvs program
+===================================
+
+ 1. Edit the file `Makefile' to reflect the situation at your site.
+ The only things you have to change is the definition of `lispdir'
+ and `infodir'. The elisp files will be copied to `lispdir', and
+ the info file to `infodir'.
+
+ 2. Configure pcl-cvs.el
+
+ There are a couple of paths that you have to check to make sure
+ that they match you system. They appear early in the file
+ pcl-cvs.el.
+
+ *NOTE:* If your system is running emacs 18.57 or earlier you
+ MUST uncomment the line that says:
+
+ (setq delete-exited-processes nil)
+
+ Setting `delete-exited-processes' to `nil' works around a bug in
+ emacs that causes it to dump core. The bug was fixed in emacs
+ 18.58.
+
+ 3. Release 1.05 and later of pcl-cvs requires parts of the Elib
+ library, version 0.07 or later. Elib is available via anonymous
+ ftp from prep.ai.mit.edu in `pub/gnu/elib-0.07.tar.z', and from
+ a lot of other sites that mirrors prep. Get Elib, and install
+ it, before proceeding.
+
+ 4. Type `make install' in the source directory. This will
+ byte-compile all `.el' files and copy both the `.el' and the
+ `.elc' into the directory you specified in step 1.
+
+ If you don't want to install the `.el' files but only the `.elc'
+ files (the byte-compiled files), you can type ``make
+ install_elc'' instead of ``make install''.
+
+ If you only want to create the compiled elisp files, but don't
+ want to install them, you can type `make elcfiles' instead.
+ This is what happens if you only type `make' without parameters.
+
+ 5. Edit the file `default.el' in your emacs lisp directory (usually
+ `/usr/gnu/emacs/lisp' or something similar) and enter the
+ contents of the file `pcl-cvs-startup.el' into it. It contains
+ a couple of `auto-load's that facilitates the use of pcl-cvs.
+
+
+
+Installation of the on-line manual.
+===================================
+
+ 1. Move the info file `pcl-cvs.info' to your standard info
+ directory. This might be called something like
+ `/usr/gnu/emacs/info'.
+
+ 2. Edit the file `dir' in the info directory and enter one line to
+ contain a pointer to the info file `pcl-cvs.info'. The line can,
+ for instance, look like this:
+
+ * Pcl-cvs: (pcl-cvs.info). An Emacs front-end to CVS.
+
+
+How to make the on-line manual from pcl-cvs.texinfo
+===================================================
+
+ 1. Create the info file `pcl-cvs.info' from `pcl-cvs.texinfo' by
+ typing `make info'. If you don't have the program `makeinfo' you
+ can get it by anonymous ftp from e.g. `ftp.gnu.ai.mit.edu' as
+ `pub/gnu/texinfo-2.14.tar.Z' (there might be a newer version
+ there when you read this).
+
+
+How to make typeset documentation from pcl-cvs.texinfo
+======================================================
+
+ If you have TeX installed at your site, you can make a typeset
+manual from `pcl-cvs.texinfo'.
+
+ 1. Run TeX by typing ``make pcl-cvs.dvi''. You will not get the
+ indices unless you have the `texindex' program.
+
+ 2. Convert the resulting device independent file `pcl-cvs.dvi' to a
+ form which your printer can output and print it. If you have a
+ postscript printer there is a program, `dvi2ps', which does.
+ There is also a program which comes together with TeX, `dvips',
+ which you can use.
+
diff --git a/gnu/usr.bin/cvs/contrib/pcl-cvs/Makefile b/gnu/usr.bin/cvs/contrib/pcl-cvs/Makefile
new file mode 100644
index 0000000..7186a6b
--- /dev/null
+++ b/gnu/usr.bin/cvs/contrib/pcl-cvs/Makefile
@@ -0,0 +1,16 @@
+# $Id: Makefile,v 1.6 1995/12/11 01:27:18 peter Exp $
+
+FILES= ChangeLog INSTALL NEWS README \
+ compile-all.el pcl-cvs-lucid.el pcl-cvs-startup.el \
+ pcl-cvs.el pcl-cvs.texinfo compile.sh
+
+NOOBJ= noobj
+
+EXAMPDIR= /usr/share/examples/cvs
+
+beforeinstall:
+ ${INSTALL} -c -o ${BINOWN} -g ${BINGRP} -m 644 \
+ ${FILES} ${DESTDIR}${EXAMPDIR}/pcl-cvs
+
+.include "../../../Makefile.inc"
+.include <bsd.prog.mk>
diff --git a/gnu/usr.bin/cvs/contrib/pcl-cvs/NEWS b/gnu/usr.bin/cvs/contrib/pcl-cvs/NEWS
new file mode 100644
index 0000000..4f563ff
--- /dev/null
+++ b/gnu/usr.bin/cvs/contrib/pcl-cvs/NEWS
@@ -0,0 +1,113 @@
+This is the NEWS file for pcl-cvs, an Elisp front-end to CVS.
+
+User-visible changes in pcl-cvs from 1.04 to 1.05:
+
+* Elib is no longer distributed with pcl-cvs. You must get Elib
+ separately, for instance from ftp.lysator.liu.se in pub/emacs.
+
+* The Lucid Emacs support works again.
+
+* A new function, cvs-change-cvsroot, can be used to interactively
+ switch between CVS repositories.
+
+* The mode line in the *cvs* buffer now indicates when a "cvs update"
+ is running.
+
+* The .cvsignore file is automatically sorted alphabetically (to
+ reduce the risk of conflicts when two people add different files
+ simultaneously). This behaviour can be turned off with
+ cvs-sort-ignore-file.
+
+* A trailing newline is always added in commit log messages. This
+ behaviour can be turned off with
+ cvs-commit-buffer-require-final-newline.
+
+* This version of pcl-cvs should work together with RCVS. I have not
+ tested this myself, though.
+
+* Plus some bug fixes. (Note that the version of cookie.el that is
+ distributed with pcl-cvs 1.04 contains errors that affects pcl-cvs.
+ You should get Elib 0.07).
+
+
+User-visible changes in pcl-cvs from 1.03 to 1.04:
+
+* Support for Emerge. Hitting "e" on a file that is Modified, Merged
+ or in Conflict will start Emerge, an interactive file merger written
+ in Emacs Lisp. This requires Emerge version 4. Emerge is not
+ included in this package. If you can't find it anywhere else, you
+ can get in from ftp.lysator.liu.se in pub/emacs. This package makes
+ it a lot easier to resolve conflicts.
+
+* Emacs will now automatically revert your buffers when the CVS
+ commands pcl-cvs issues causes the file to change. This automatic
+ revert never occurs if the buffer contents did not agree with the
+ file prior to the command.
+
+* If you are running Lucid GNU Emacs, you will get some fonts and
+ mouse support. This was contributed from people at Lucid.
+
+* The variable cvs-cvsroot can be used to select the location if the
+ repository. You no longer need to exit Emacs, setenv CVSROOT, and
+ start a new Emacs if you work with multiple repositories.
+
+* The "q" key can be used to hide the *cvs* buffer.
+
+* The name of the commands in the *cvs* have changed. If it was called
+ cvs-foo, it will now be called cvs-mode-foo. See the ChangeLog
+ entry from Tue Aug 4 03:02:25 1992 for a complete list of changes.
+
+* The variable cvs-cvs-diff-flags is no longer used. Instead,
+ cvs-diff-flags is always used.
+
+* Plus a lot of bug fixes.
+
+
+User-visible changes in pcl-cvs from 1.02 to 1.03:
+
+* Output from CVS to stdout and stderr is separated and parsed
+ independently. In that way pcl-cvs should work regardless of
+ whether stdout is buffered or line-buffered. Pcl-cvs should now
+ work with CVS 1.3 without modifications on hosts such as
+ DECstations.
+
+* Pcl-cvs now fully supports RCS version 5.6 as well as 5.5.
+
+* New functions:
+
+ + cvs-undo-local-changes ("U") - Undo all your modifications
+ to a file and get the newest
+ version from the repository.
+ + cvs-update-other-window - Similar to cvs-update.
+ + cvs-byte-compile-files - Byte compile the selected files.
+
+* cvs-update now displays the *cvs* buffer, which initially contains a
+ small message ("Running `cvs update' in /foo/bar/gazonk/...") until
+ the update is ready. The *cvs* buffer no longer pops up when the
+ update is ready. It often failed to pop up, due to race conditions
+ that are very hard to solve (and I doubt that they were at all
+ solvable).
+
+* cvs-unmark-all-files is moved from "U" to "ESC DEL" to be
+ "compatible" with dired.
+
+* cvs-diff ("d") and cvs-diff-backup ("b") can be configured to work
+ on only the file the cursor is positioned on, and ignore any marked
+ files. A prefix argument toggles this.
+
+* Only one `cvs update' can be run at a time. (It was previously
+ possible to start more than one simultaneously, but pcl-cvs could
+ not really handle more than one.)
+
+* Some rudimentary support for programs that CVS runs at update (due
+ to the -u switch in the modules file).
+
+* Pcl-cvs now automatically generates a bug report if it can't parse
+ the output from CVS.
+
+* The *cvs* buffer is read-only.
+
+* Pcl-cvs now creates temporary files in $TMPDIR if that environment
+ variable is set (otherwise it uses /tmp).
+
+---End of file NEWS---
diff --git a/gnu/usr.bin/cvs/contrib/pcl-cvs/README b/gnu/usr.bin/cvs/contrib/pcl-cvs/README
new file mode 100644
index 0000000..a9b8106
--- /dev/null
+++ b/gnu/usr.bin/cvs/contrib/pcl-cvs/README
@@ -0,0 +1,29 @@
+@(#) Id: README,v 1.14 1993/05/31 22:43:36 ceder Exp
+
+This is the readme file for pcl-cvs, release 1.05.
+
+This release of pcl-cvs requires Elib 0.07 or later. Elib is no
+longer distributed with pcl-cvs, since that caused too much confusion.
+You can get Elib from ftp.lysator.liu.se in pub/emacs/elib-*.tar.?.
+
+Pcl-cvs is a front-end to CVS version 1.3. It integrates the most
+frequently used CVS commands into emacs.
+
+There is some configuration that needs to be done in pcl-cvs.el to get
+it to work. See the instructions in file INSTALL.
+
+Full documentation is in pcl-cvs.texinfo. Since it requires makeinfo
+version 2 or 3 a preformatted info file is also included (pcl-cvs.info).
+
+If you have been using a previous version of pcl-cvs (for instance
+1.02 which is distributed with CVS 1.3) you should read through the
+file NEWS to see what has changed.
+
+This release has been tested under Emacs 18.59, Emacs 19.28 and Lucid
+Emacs 19.6. Emacs 19.10 unfortunately has a file named cookie.el that
+collides with the cookie.el that is distributed in Elib. This
+conflict was resolved in 19.11. For earlier versions, there are
+instructions in Elib 0.07 for how to work around the problem.
+
+ Per Cederqvist
+ (updated by Jim Blandy)
diff --git a/gnu/usr.bin/cvs/contrib/pcl-cvs/compile-all.el b/gnu/usr.bin/cvs/contrib/pcl-cvs/compile-all.el
new file mode 100644
index 0000000..6563277
--- /dev/null
+++ b/gnu/usr.bin/cvs/contrib/pcl-cvs/compile-all.el
@@ -0,0 +1,52 @@
+;;;; @(#) Id: compile-all.el,v 1.11 1993/05/31 18:40:25 ceder Exp
+;;;; This file byte-compiles all .el files in pcl-cvs release 1.05.
+;;;;
+;;;; Copyright (C) 1991 Inge Wallin
+;;;;
+;;;; This file was once upon a time part of Elib, but have since been
+;;;; modified by Per Cederqvist.
+;;;;
+;;;; GNU Elib is free software; you can redistribute it and/or modify
+;;;; it under the terms of the GNU General Public License as published by
+;;;; the Free Software Foundation; either version 1, or (at your option)
+;;;; any later version.
+;;;;
+;;;; GNU Elib is distributed in the hope that it will be useful,
+;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;;;; GNU General Public License for more details.
+;;;;
+;;;; You should have received a copy of the GNU General Public License
+;;;; along with GNU Emacs; see the file COPYING. If not, write to
+;;;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+;;;;
+
+
+(setq files-to-compile '("pcl-cvs" "pcl-cvs-lucid"))
+
+
+(defun compile-file-if-necessary (file)
+ "Compile FILE if necessary.
+
+This is done if FILE.el is newer than FILE.elc or if FILE.elc doesn't exist."
+ (let ((el-name (concat file ".el"))
+ (elc-name (concat file ".elc")))
+ (if (or (not (file-exists-p elc-name))
+ (file-newer-than-file-p el-name elc-name))
+ (progn
+ (message (format "Byte-compiling %s..." el-name))
+ (byte-compile-file el-name)))))
+
+
+(defun compile-pcl-cvs ()
+ "Byte-compile all uncompiled files of pcl-cvs."
+
+ (interactive)
+
+ ;; Be sure to have . in load-path since a number of files
+ ;; depend on other files and we always want the newer one even if
+ ;; a previous version of pcl-cvs exists.
+ (let ((load-path (append '(".") load-path)))
+
+ (mapcar (function compile-file-if-necessary)
+ files-to-compile)))
diff --git a/gnu/usr.bin/cvs/contrib/pcl-cvs/compile.sh b/gnu/usr.bin/cvs/contrib/pcl-cvs/compile.sh
new file mode 100644
index 0000000..b940370
--- /dev/null
+++ b/gnu/usr.bin/cvs/contrib/pcl-cvs/compile.sh
@@ -0,0 +1,2 @@
+#! /bin/sh
+emacs -batch -l compile-all.el -f compile-pcl-cvs
diff --git a/gnu/usr.bin/cvs/contrib/pcl-cvs/pcl-cvs-lucid.el b/gnu/usr.bin/cvs/contrib/pcl-cvs/pcl-cvs-lucid.el
new file mode 100644
index 0000000..d1f69e3
--- /dev/null
+++ b/gnu/usr.bin/cvs/contrib/pcl-cvs/pcl-cvs-lucid.el
@@ -0,0 +1,133 @@
+;;; Mouse and font support for PCL-CVS 1.3 running in Lucid GNU Emacs
+;; @(#) Id: pcl-cvs-lucid.el,v 1.2 1993/05/31 19:37:34 ceder Exp
+;; Copyright (C) 1992-1993 Free Software Foundation, Inc.
+
+;; This file is part of GNU Emacs.
+
+;; GNU Emacs is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 2, or (at your option)
+;; any later version.
+
+;; GNU Emacs is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GNU Emacs; see the file COPYING. If not, write to
+;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+
+;; This simply adds a menu of the common CVS commands to the menubar and to
+;; the right mouse button. Clicking right moves point, and then pops up a
+;; menu from which commands can be executed.
+;;
+;; This could stand to be a lot more clever: for example, the "Commit Changes"
+;; command should only be active on files for which there is something to
+;; commit. Also, some indication of which files the command applies to
+;; (especially in the presence of multiple marked files) would be nice.
+;;
+;; Middle-click runs find-file.
+
+
+(require 'pcl-cvs)
+
+(defvar cvs-menu
+ '("CVS"
+ ["Find File" cvs-mode-find-file t]
+ ["Find File Other Window" cvs-mode-find-file-other-window t]
+ ["Interactively Merge (emerge)" cvs-mode-emerge t]
+ ["Diff against Repository" cvs-mode-diff-cvs t]
+ ["Diff against Backup Version" cvs-mode-diff-backup t]
+ "----"
+ ["Commit Changes to Repository" cvs-mode-commit t]
+ ["Revert File from Repository" cvs-mode-undo-local-changes t]
+ ["Add File to Repository" cvs-mode-add t]
+ ["Remove File from Repository" cvs-mode-remove-file t]
+ ["Ignore File" cvs-mode-ignore t]
+ ["Hide File" cvs-mode-acknowledge t]
+ ["Hide Handled Files" cvs-mode-remove-handled t]
+ "----"
+ ["Add ChangeLog Entry" cvs-mode-add-change-log-entry-other-window t]
+ ["Show CVS Log" cvs-mode-log t]
+ ["Show CVS Status" cvs-mode-status t]
+ "----"
+ ["Mark File" cvs-mode-mark t]
+ ["Unmark File" cvs-mode-unmark t]
+ ["Mark All Files" cvs-mode-mark-all-files t]
+ ["Unmark All Files" cvs-mode-unmark-all-files t]
+ "----"
+ ["Quit" bury-buffer t]
+ ))
+
+(defun cvs-menu (e)
+ (interactive "e")
+ (mouse-set-point e)
+ (beginning-of-line)
+ (or (looking-at "^[* ] ") (error "No CVS file line here"))
+ (popup-menu cvs-menu))
+
+(defun cvs-mouse-find-file (e)
+ (interactive "e")
+ (mouse-set-point e)
+ (beginning-of-line)
+ (or (looking-at "^[* ] ") (error "No CVS file line here"))
+ (cvs-mode-find-file (point)))
+
+(define-key cvs-mode-map 'button3 'cvs-menu)
+(define-key cvs-mode-map 'button2 'cvs-mouse-find-file)
+
+(make-face 'cvs-header-face)
+(make-face 'cvs-filename-face)
+(make-face 'cvs-status-face)
+
+(or (face-differs-from-default-p 'cvs-header-face)
+ (copy-face 'italic 'cvs-header-face))
+
+(or (face-differs-from-default-p 'cvs-filename-face)
+ (copy-face 'bold 'cvs-filename-face))
+
+(or (face-differs-from-default-p 'cvs-status-face)
+ (copy-face 'bold-italic 'cvs-status-face))
+
+
+(defun pcl-mode-motion-highlight-line (event)
+ (if (save-excursion
+ (let* ((window (event-window event))
+ (buffer (and window (window-buffer window)))
+ (point (and buffer (event-point event))))
+ (and point
+ (progn
+ (set-buffer buffer)
+ (goto-char point)
+ (beginning-of-line)
+ (looking-at "^[* ] ")))))
+ (mode-motion-highlight-line event)))
+
+(defconst pcl-cvs-font-lock-keywords
+ '(("^In directory \\(.+\\)$" 1 cvs-header-face)
+ ("^[* ] \\w+ +\\(ci\\)" 1 cvs-status-face)
+ ("^[* ] \\(Conflict\\|Merged\\)" 1 cvs-status-face)
+ ("^[* ] \\w+ +\\(ci +\\)?\\(.+\\)$" 2 cvs-filename-face)
+ )
+ "Patterns to highlight in the *cvs* buffer.")
+
+(defun pcl-cvs-fontify ()
+ ;;
+ ;; set up line highlighting
+ (require 'mode-motion)
+ (setq mode-motion-hook 'pcl-mode-motion-highlight-line)
+ ;;
+ ;; set up menubar
+ (if (and current-menubar (not (assoc "CVS" current-menubar)))
+ (progn
+ (set-buffer-menubar (copy-sequence current-menubar))
+ (add-menu nil "CVS" (cdr cvs-menu))))
+ ;;
+ ;; fontify mousable lines
+ (set (make-local-variable 'font-lock-keywords) pcl-cvs-font-lock-keywords)
+ (font-lock-mode 1)
+ )
+
+(add-hook 'cvs-mode-hook 'pcl-cvs-fontify)
diff --git a/gnu/usr.bin/cvs/contrib/pcl-cvs/pcl-cvs-startup.el b/gnu/usr.bin/cvs/contrib/pcl-cvs/pcl-cvs-startup.el
new file mode 100644
index 0000000..f9b2de0
--- /dev/null
+++ b/gnu/usr.bin/cvs/contrib/pcl-cvs/pcl-cvs-startup.el
@@ -0,0 +1,14 @@
+;;; @(#) Id: pcl-cvs-startup.el,v 1.4 1993/05/31 18:40:33 ceder Exp
+(autoload 'cvs-update "pcl-cvs"
+ "Run a 'cvs update' in the current working directory. Feed the
+output to a *cvs* buffer and run cvs-mode on it.
+If optional prefix argument LOCAL is non-nil, 'cvs update -l' is run."
+ t)
+
+(autoload 'cvs-update-other-window "pcl-cvs"
+ "Run a 'cvs update' in the current working directory. Feed the
+output to a *cvs* buffer, display it in the other window, and run
+cvs-mode on it.
+
+If optional prefix argument LOCAL is non-nil, 'cvs update -l' is run."
+ t)
diff --git a/gnu/usr.bin/cvs/contrib/pcl-cvs/pcl-cvs.el b/gnu/usr.bin/cvs/contrib/pcl-cvs/pcl-cvs.el
new file mode 100644
index 0000000..d9c15d5
--- /dev/null
+++ b/gnu/usr.bin/cvs/contrib/pcl-cvs/pcl-cvs.el
@@ -0,0 +1,2493 @@
+;;; @(#) Id: pcl-cvs.el,v 1.93 1993/05/31 22:44:00 ceder Exp
+;;; pcl-cvs.el -- A Front-end to CVS 1.3 or later. Release 1.05.
+;;; Copyright (C) 1991, 1992, 1993 Per Cederqvist
+;;;
+;;; This program is free software; you can redistribute it and/or modify
+;;; it under the terms of the GNU General Public License as published by
+;;; the Free Software Foundation; either version 2 of the License, or
+;;; (at your option) any later version.
+;;;
+;;; This program is distributed in the hope that it will be useful,
+;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;;; GNU General Public License for more details.
+;;;
+;;; You should have received a copy of the GNU General Public License
+;;; along with this program; if not, write to the Free Software
+;;; Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+;;;; See below for installation instructions.
+;;;;
+;;;; There is an TeXinfo file that describes this package. The GNU
+;;;; General Public License is included in that file. You should read
+;;;; it to get the most from this package.
+
+;;;; Send bug reports and improvements to ceder@lysator.liu.se or
+;;;; ceder@signum.se. Talk some about Signum Support here. +++FIXME
+
+;;; Don't try to use this with CVS 1.2 or earlier. It won't work. Get
+;;; CVS 1.3. This package works together with RCS 5.6 and probably 5.5
+;;; as well.
+
+;;; Mail questions and bug reports to ceder@lysator.liu.se.
+
+(require 'cookie)
+(provide 'pcl-cvs)
+
+;;; -------------------------------------------------------
+;;; START OF THINGS TO CHECK WHEN INSTALLING
+
+(defvar cvs-program "/usr/local/bin/cvs"
+ "*Full path to the cvs executable.")
+
+(defvar cvs-diff-program "/usr/local/bin/diff"
+ "*Full path to the diff program.")
+
+(defvar cvs-rmdir-program "/bin/rmdir"
+ "*Full path to the rmdir program. Typically /bin/rmdir.")
+
+;; Uncomment the following line if you are running on 18.57 or earlier.
+;(setq delete-exited-processes nil)
+;; Emacs version 18.57 and earlier is likely to crash if
+;; delete-exited-processes is t, since the sentinel uses lots of
+;; memory, and 18.57 forgets to GCPROT a variable if
+;; delete-exited-processes is t.
+
+(defvar cvs-shell "/bin/sh"
+ "*Full path to a shell that can do redirection on stdout.")
+
+;;; END OF THINGS TO CHECK WHEN INSTALLING
+;;; --------------------------------------------------------
+
+(defvar cvs-cvsroot nil
+ "*Specifies where the (current) cvs master repository is.
+Overrides the $CVSROOT variable by sending \" -d dir\" to all cvs commands.
+This switch is useful if you have multiple CVS repositories.")
+
+(defvar cvs-cvsroot-required t
+ "*Specifies whether CVS needs to be told where the repository is.
+
+In CVS 1.3, if your CVSROOT environment variable is not set, and you
+do not set the `cvs-cvsroot' lisp variable, CVS will have no idea
+where to find the repository, and refuse to run. CVS 1.4 and later
+store the repository path with the working directories, so most
+operations don't need to be told where the repository is.
+
+If you work with multiple repositories with CVS 1.4, it's probably
+advisable to leave your CVSROOT environment variable unset, set this
+variable to nil, and let CVS figure out where the repository is for
+itself.")
+
+(defvar cvs-stdout-file nil
+ "Name of the file that holds the output that CVS sends to stdout.
+This variable is buffer local.")
+
+(defvar cvs-lock-file nil
+ "Full path to a lock file that CVS is waiting for (or was waiting for).")
+
+(defvar cvs-bakprefix ".#"
+ "The prefix that CVS prepends to files when rcsmerge'ing.")
+
+(defvar cvs-erase-input-buffer nil
+ "*Non-nil if input buffers should be cleared before asking for new info.")
+
+(defvar cvs-auto-remove-handled nil
+ "*Non-nil if cvs-mode-remove-handled should be called automatically.
+If this is set to any non-nil value entries that does not need to be
+checked in will be removed from the *cvs* buffer after every cvs-mode-commit
+command.")
+
+(defvar cvs-sort-ignore-file t
+ "*Non-nil if cvs-mode-ignore should sort the .cvsignore automatically.")
+
+(defvar cvs-auto-revert-after-commit t
+ "*Non-nil if committed buffers should be automatically reverted.")
+
+(defconst cvs-cursor-column 14
+ "Column to position cursor in in cvs-mode.
+Column 0 is left-most column.")
+
+(defvar cvs-mode-map nil
+ "Keymap for the cvs mode.")
+
+(defvar cvs-edit-mode-map nil
+ "Keymap for the cvs edit mode (used when editing cvs log messages).")
+
+(defvar cvs-buffer-name "*cvs*"
+ "Name of the cvs buffer.")
+
+(defvar cvs-commit-prompt-buffer "*cvs-commit-message*"
+ "Name of buffer in which the user is prompted for a log message when
+committing files.")
+
+(defvar cvs-commit-buffer-require-final-newline t
+ "*t says silently put a newline at the end of commit log messages.
+Non-nil but not t says ask user whether to add a newline in each such case.
+nil means don't add newlines.")
+
+(defvar cvs-temp-buffer-name "*cvs-tmp*"
+ "*Name of the cvs temporary buffer.
+Output from cvs is placed here by synchronous commands.")
+
+(defvar cvs-diff-ignore-marks nil
+ "*Non-nil if cvs-diff and cvs-mode-diff-backup should ignore any marked files.
+Normally they run diff on the files that are marked (with cvs-mode-mark),
+or the file under the cursor if no files are marked. If this variable
+is set to a non-nil value they will always run diff on the file on the
+current line.")
+
+(defvar cvs-status-flags nil
+ "*List of strings to pass to ``cvs status''.")
+
+(defvar cvs-log-flags nil
+ "*List of strings to pass to ``cvs log''.")
+
+(defvar cvs-diff-flags nil
+ "*List of strings to use as flags to pass to ``diff'' and ``cvs diff''.
+Used by cvs-mode-diff-cvs and cvs-mode-diff-backup.
+Set this to '(\"-u\") to get a Unidiff format, or '(\"-c\") to get context diffs.")
+
+(defvar cvs-update-prog-output-skip-regexp "$"
+ "*A regexp that matches the end of the output from all cvs update programs.
+That is, output from any programs that are run by CVS (by the flag -u
+in the `modules' file - see cvs(5)) when `cvs update' is performed should
+terminate with a line that this regexp matches. It is enough that
+some part of the line is matched.
+
+The default (a single $) fits programs without output.")
+
+;; The variables below are used internally by pcl-cvs. You should
+;; never change them.
+
+(defvar cvs-buffers-to-delete nil
+ "List of temporary buffers that should be discarded as soon as possible.
+Due to a bug in emacs 18.57 the sentinel can't discard them reliably.")
+
+;; You are NOT allowed to disable this message by default. However, you
+;; are encouraged to inform your users that by adding
+;; (setq cvs-inhibit-copyright-message t)
+;; to their .emacs they can get rid of it. Just don't add that line
+;; to your default.el!
+(defvar cvs-inhibit-copyright-message nil
+ "*Non-nil means don't display a Copyright message in the ``*cvs*'' buffer.")
+
+(defconst pcl-cvs-version "1.05"
+ "A string denoting the current release version of pcl-cvs.")
+
+(defconst cvs-startup-message
+ (if cvs-inhibit-copyright-message
+ "PCL-CVS release 1.05"
+ "PCL-CVS release 1.05. Copyright (C) 1992, 1993 Per Cederqvist
+Pcl-cvs comes with absolutely no warranty; for details consult the manual.
+This is free software, and you are welcome to redistribute it under certain
+conditions; again, consult the TeXinfo manual for details.")
+ "*Startup message for CVS.")
+
+(defvar cvs-update-running nil
+ "This is set to nil when no process is running, and to
+the process when a cvs update process is running.")
+
+(defvar cvs-cookie-handle nil
+ "Handle for the cookie structure that is displayed in the *cvs* buffer.")
+
+(defvar cvs-mode-commit nil
+ "Used internally by pcl-cvs.")
+
+;;; The cvs data structure:
+;;;
+;;; When the `cvs update' is ready we parse the output. Every file
+;;; that is affected in some way is added as a cookie of fileinfo
+;;; (as defined below).
+;;;
+
+;;; cvs-fileinfo
+;;;
+;;; marked t/nil
+;;; type One of
+;;; UPDATED - file copied from repository
+;;; MODIFIED - modified by you, unchanged in
+;;; repository
+;;; ADDED - added by you, not yet committed
+;;; REMOVED - removed by you, not yet committed
+;;; CVS-REMOVED- removed, since file no longer exists
+;;; in the repository.
+;;; MERGED - successful merge
+;;; CONFLICT - conflict when merging
+;;; REM-CONFLICT-removed in repository, changed locally.
+;;; MOD-CONFLICT-removed locally, changed in repository.
+;;; REM-EXIST -removed locally, but still exists.
+;;; DIRCHANGE - A change of directory.
+;;; UNKNOWN - An unknown file.
+;;; MOVE-AWAY - A file that is in the way.
+;;; REPOS-MISSING- The directory is removed from the
+;;; repository. Go fetch a backup.
+;;; MESSAGE - This is a special fileinfo that is used
+;;; to display a text that should be in
+;;; full-log.
+;;; dir Directory the file resides in. Should not end with
+;;; slash.
+;;; file-name The file name.
+;;; base-revision The revision that the working file was based on.
+;;; Only valid for MERGED and CONFLICT files.
+;;; cvs-diff-buffer A buffer that contains a 'cvs diff file'.
+;;; backup-diff-buffer A buffer that contains a 'diff file backup-file'.
+;;; full-log The output from cvs, unparsed.
+;;; mod-time Modification time of file used for *-diff-buffer.
+;;; handled True if this file doesn't require further action.
+;;;
+;;; Constructor:
+
+;;; cvs-fileinfo
+
+;;; Constructor:
+
+(defun cvs-create-fileinfo (type
+ dir
+ file-name
+ full-log)
+ "Create a fileinfo from all parameters.
+Arguments: TYPE DIR FILE-NAME FULL-LOG.
+A fileinfo has the following fields:
+
+ marked t/nil
+ type One of
+ UPDATED - file copied from repository
+ MODIFIED - modified by you, unchanged in
+ repository
+ ADDED - added by you, not yet committed
+ REMOVED - removed by you, not yet committed
+ CVS-REMOVED- removed, since file no longer exists
+ in the repository.
+ MERGED - successful merge
+ CONFLICT - conflict when merging
+ REM-CONFLICT-removed in repository, but altered
+ locally.
+ MOD-CONFLICT-removed locally, changed in repository.
+ REM-EXIST - removed locally, but still exists.
+ DIRCHANGE - A change of directory.
+ UNKNOWN - An unknown file.
+ MOVE-AWAY - A file that is in the way.
+ REPOS-MISSING- The directory has vanished from the
+ repository.
+ MESSAGE - This is a special fileinfo that is used
+ to display a text that should be in
+ full-log.
+ dir Directory the file resides in. Should not end with slash.
+ file-name The file name.
+ backup-file Name of the backup file if MERGED or CONFLICT.
+ cvs-diff-buffer A buffer that contains a 'cvs diff file'.
+ backup-diff-buffer A buffer that contains a 'diff file backup-file'.
+ full-log The output from cvs, unparsed.
+ mod-time Modification time of file used for *-diff-buffer.
+ handled True if this file doesn't require further action."
+ (cons
+ 'CVS-FILEINFO
+ (vector nil nil type dir file-name nil nil nil full-log nil)))
+
+
+;;; Selectors:
+
+(defun cvs-fileinfo->handled (cvs-fileinfo)
+ "Get the `handled' field from CVS-FILEINFO."
+ (elt (cdr cvs-fileinfo) 0))
+
+(defun cvs-fileinfo->marked (cvs-fileinfo)
+ "Check if CVS-FILEINFO is marked."
+ (elt (cdr cvs-fileinfo) 1))
+
+(defun cvs-fileinfo->type (cvs-fileinfo)
+ "Get type from CVS-FILEINFO.
+Type is one of UPDATED, MODIFIED, ADDED, REMOVED, CVS-REMOVED, MERGED,
+CONFLICT, REM-CONFLICT, MOD-CONFLICT, REM-EXIST, DIRCHANGE, UNKNOWN, MOVE-AWAY,
+REPOS-MISSING or MESSAGE."
+ (elt (cdr cvs-fileinfo) 2))
+
+(defun cvs-fileinfo->dir (cvs-fileinfo)
+ "Get dir from CVS-FILEINFO.
+The directory name does not end with a slash. "
+ (elt (cdr cvs-fileinfo) 3))
+
+(defun cvs-fileinfo->file-name (cvs-fileinfo)
+ "Get file-name from CVS-FILEINFO."
+ (elt (cdr cvs-fileinfo) 4))
+
+(defun cvs-fileinfo->base-revision (cvs-fileinfo)
+ "Get the base revision from CVS-FILEINFO."
+ (elt (cdr cvs-fileinfo) 5))
+
+(defun cvs-fileinfo->cvs-diff-buffer (cvs-fileinfo)
+ "Get cvs-diff-buffer from CVS-FILEINFO."
+ (elt (cdr cvs-fileinfo) 6))
+
+(defun cvs-fileinfo->backup-diff-buffer (cvs-fileinfo)
+ "Get backup-diff-buffer from CVS-FILEINFO."
+ (elt (cdr cvs-fileinfo) 7))
+
+(defun cvs-fileinfo->full-log (cvs-fileinfo)
+ "Get full-log from CVS-FILEINFO."
+ (elt (cdr cvs-fileinfo) 8))
+
+(defun cvs-fileinfo->mod-time (cvs-fileinfo)
+ "Get mod-time from CVS-FILEINFO."
+ (elt (cdr cvs-fileinfo) 9))
+
+;;; Modifiers:
+
+(defun cvs-set-fileinfo->handled (cvs-fileinfo newval)
+ "Set handled in CVS-FILEINFO to NEWVAL."
+ (aset (cdr cvs-fileinfo) 0 newval))
+
+(defun cvs-set-fileinfo->marked (cvs-fileinfo newval)
+ "Set marked in CVS-FILEINFO to NEWVAL."
+ (aset (cdr cvs-fileinfo) 1 newval))
+
+(defun cvs-set-fileinfo->type (cvs-fileinfo newval)
+ "Set type in CVS-FILEINFO to NEWVAL."
+ (aset (cdr cvs-fileinfo) 2 newval))
+
+(defun cvs-set-fileinfo->dir (cvs-fileinfo newval)
+ "Set dir in CVS-FILEINFO to NEWVAL.
+The directory should now end with a slash."
+ (aset (cdr cvs-fileinfo) 3 newval))
+
+(defun cvs-set-fileinfo->file-name (cvs-fileinfo newval)
+ "Set file-name in CVS-FILEINFO to NEWVAL."
+ (aset (cdr cvs-fileinfo) 4 newval))
+
+(defun cvs-set-fileinfo->base-revision (cvs-fileinfo newval)
+ "Set base-revision in CVS-FILEINFO to NEWVAL."
+ (aset (cdr cvs-fileinfo) 5 newval))
+
+(defun cvs-set-fileinfo->cvs-diff-buffer (cvs-fileinfo newval)
+ "Set cvs-diff-buffer in CVS-FILEINFO to NEWVAL."
+ (aset (cdr cvs-fileinfo) 6 newval))
+
+(defun cvs-set-fileinfo->backup-diff-buffer (cvs-fileinfo newval)
+ "Set backup-diff-buffer in CVS-FILEINFO to NEWVAL."
+ (aset (cdr cvs-fileinfo) 7 newval))
+
+(defun cvs-set-fileinfo->full-log (cvs-fileinfo newval)
+ "Set full-log in CVS-FILEINFO to NEWVAL."
+ (aset (cdr cvs-fileinfo) 8 newval))
+
+(defun cvs-set-fileinfo->mod-time (cvs-fileinfo newval)
+ "Set full-log in CVS-FILEINFO to NEWVAL."
+ (aset (cdr cvs-fileinfo) 9 newval))
+
+
+
+;;; Predicate:
+
+(defun cvs-fileinfo-p (object)
+ "Return t if OBJECT is a cvs-fileinfo."
+ (eq (car-safe object) 'CVS-FILEINFO))
+
+;;;; End of types.
+
+(defun cvs-use-temp-buffer ()
+ "Display a temporary buffer in another window and select it.
+The selected window will not be changed. The temporary buffer will
+be erased and writable."
+
+ (let ((dir default-directory))
+ (display-buffer (get-buffer-create cvs-temp-buffer-name))
+ (set-buffer cvs-temp-buffer-name)
+ (setq buffer-read-only nil)
+ (setq default-directory dir)
+ (erase-buffer)))
+
+; Too complicated to handle all the cases that are generated.
+; Maybe later.
+;(defun cvs-examine (directory &optional local)
+; "Run a 'cvs -n update' in the current working directory.
+;That is, check what needs to be done, but don't change the disc.
+;Feed the output to a *cvs* buffer and run cvs-mode on it.
+;If optional prefix argument LOCAL is non-nil, 'cvs update -l' is run."
+; (interactive (list (read-file-name "CVS Update (directory): "
+; nil default-directory nil)
+; current-prefix-arg))
+; (cvs-do-update directory local 'noupdate))
+
+(defun cvs-update (directory &optional local)
+ "Run a 'cvs update' in the current working directory. Feed the
+output to a *cvs* buffer and run cvs-mode on it.
+If optional prefix argument LOCAL is non-nil, 'cvs update -l' is run."
+ (interactive (list (read-file-name "CVS Update (directory): "
+ nil default-directory nil)
+ current-prefix-arg))
+ (cvs-do-update directory local nil)
+ (switch-to-buffer cvs-buffer-name))
+
+(defun cvs-update-other-window (directory &optional local)
+ "Run a 'cvs update' in the current working directory. Feed the
+output to a *cvs* buffer, display it in the other window, and run
+cvs-mode on it.
+
+If optional prefix argument LOCAL is non-nil, 'cvs update -l' is run."
+ (interactive (list (read-file-name "CVS Update other window (directory): "
+ nil default-directory nil)
+ current-prefix-arg))
+ (cvs-do-update directory local nil)
+ (switch-to-buffer-other-window cvs-buffer-name))
+
+(defun cvs-filter (predicate list &rest extra-args)
+ "Apply PREDICATE to each element on LIST.
+Args: PREDICATE LIST &rest EXTRA-ARGS.
+Return a new list consisting of those elements that PREDICATE
+returns non-nil for.
+
+If more than two arguments are given the remaining args are
+passed to PREDICATE."
+ ;; Avoid recursion - this should work for LONG lists also!
+ (let* ((head (cons 'dummy-header nil))
+ (tail head))
+ (while list
+ (if (apply predicate (car list) extra-args)
+ (setq tail (setcdr tail (list (car list)))))
+ (setq list (cdr list)))
+ (cdr head)))
+
+(defun cvs-mode-update-no-prompt ()
+ "Run cvs update in current directory."
+ (interactive)
+ (cvs-do-update default-directory nil nil))
+
+(defun cvs-do-update (directory local dont-change-disc)
+ "Do a 'cvs update' in DIRECTORY.
+Args: DIRECTORY LOCAL DONT-CHANGE-DISC &optional NOTTHISWINDOW.
+If LOCAL is non-nil 'cvs update -l' is executed.
+If DONT-CHANGE-DISC is non-nil 'cvs -n update' is executed.
+Both LOCAL and DONT-CHANGE-DISC may be non-nil simultaneously.
+
+*Note*: DONT-CHANGE-DISC does not yet work. The parser gets confused."
+ (save-some-buffers)
+ (if (not (file-exists-p cvs-program))
+ (error "%s: file not found (check setting of cvs-program)"
+ cvs-program))
+ (if (and cvs-cvsroot-required
+ (not (or (getenv "CVSROOT") cvs-cvsroot)))
+ (error "Both cvs-cvsroot and environment variable CVSROOT unset."))
+ (let* ((this-dir (file-name-as-directory (expand-file-name directory)))
+ (update-buffer (generate-new-buffer
+ (concat (file-name-nondirectory
+ (substring this-dir 0 -1))
+ "-update")))
+ (temp-name (make-temp-name
+ (concat (file-name-as-directory
+ (or (getenv "TMPDIR") "/tmp"))
+ "pcl-cvs.")))
+ (args nil))
+
+ ;; Check that this-dir exists and is a directory that is under CVS contr.
+
+ (if (not (file-directory-p this-dir))
+ (error "%s is not a directory." this-dir))
+ (if (not (file-directory-p (concat this-dir "CVS")))
+ (error "%s does not contain CVS controlled files." this-dir))
+
+ ;; Check that at most one `cvs update' is run at any time.
+
+ (if (and cvs-update-running (process-status cvs-update-running)
+ (or (eq (process-status cvs-update-running) 'run)
+ (eq (process-status cvs-update-running) 'stop)))
+ (error "Can't run two `cvs update' simultaneously."))
+
+ ;; Generate "-d /master -n update -l".
+ (setq args (concat (if cvs-cvsroot (concat " -d " cvs-cvsroot))
+ (if dont-change-disc " -n ")
+ " update "
+ (if local " -l ")))
+
+ ;; Set up the buffer that receives the stderr output from "cvs update".
+ (set-buffer update-buffer)
+ (setq default-directory this-dir)
+ (make-local-variable 'cvs-stdout-file)
+ (setq cvs-stdout-file temp-name)
+
+ (setq cvs-update-running
+ (let ((process-connection-type nil)) ; Use a pipe, not a pty.
+ (start-process "cvs" update-buffer cvs-shell "-c"
+ (concat cvs-program " " args " > " temp-name))))
+
+ (setq mode-line-process
+ (concat ": "
+ (symbol-name (process-status cvs-update-running))))
+ (set-buffer-modified-p (buffer-modified-p)) ; Update the mode line.
+ (set-process-sentinel cvs-update-running 'cvs-sentinel)
+ (set-process-filter cvs-update-running 'cvs-update-filter)
+ (set-marker (process-mark cvs-update-running) (point-min))
+
+ (save-excursion
+ (set-buffer (get-buffer-create cvs-buffer-name))
+ (setq buffer-read-only nil)
+ (erase-buffer)
+ (cvs-mode))
+
+ (setq cvs-cookie-handle
+ (collection-create
+ cvs-buffer-name 'cvs-pp
+ cvs-startup-message ;Se comment above cvs-startup-message.
+ "---------- End -----"))
+
+ (cookie-enter-first
+ cvs-cookie-handle
+ (cvs-create-fileinfo
+ 'MESSAGE nil nil (concat "\n Running `cvs " args "' in " this-dir
+ "...\n")))
+
+ (save-excursion
+ (set-buffer cvs-buffer-name)
+ (setq mode-line-process
+ (concat ": "
+ (symbol-name (process-status cvs-update-running))))
+ (set-buffer-modified-p (buffer-modified-p)) ; Update the mode line.
+ (setq buffer-read-only t))
+
+ ;; Work around a bug in emacs 18.57 and earlier.
+ (setq cvs-buffers-to-delete
+ (cvs-delete-unused-temporary-buffers cvs-buffers-to-delete)))
+
+ ;; The following line is said to improve display updates on some
+ ;; emacses. It shouldn't be needed, but it does no harm.
+ (sit-for 0))
+
+
+(defun cvs-delete-unused-temporary-buffers (list)
+ "Delete all buffers on LIST that is not visible.
+Return a list of all buffers that still is alive."
+
+ (cond
+ ((null list) nil)
+ ((get-buffer-window (car list))
+ (cons (car list)
+ (cvs-delete-unused-temporary-buffers (cdr list))))
+ (t
+ (kill-buffer (car list))
+ (cvs-delete-unused-temporary-buffers (cdr list)))))
+
+
+(put 'cvs-mode 'mode-class 'special)
+
+(defun cvs-mode ()
+ "\\<cvs-mode-map>Mode used for pcl-cvs, a frontend to CVS.
+
+To get the *cvs* buffer you should use ``\\[cvs-update]''.
+
+Full documentation is in the Texinfo file. These are the most useful commands:
+
+\\[cvs-mode-previous-line] Move up. \\[cvs-mode-next-line] Move down.
+\\[cvs-mode-commit] Commit file. \\[cvs-mode-update-no-prompt] Reupdate directory.
+\\[cvs-mode-mark] Mark file/dir. \\[cvs-mode-unmark] Unmark file/dir.
+\\[cvs-mode-mark-all-files] Mark all files. \\[cvs-mode-unmark-all-files] Unmark all files.
+\\[cvs-mode-find-file] Edit file/run Dired. \\[cvs-mode-find-file-other-window] Find file or run Dired in other window.
+\\[cvs-mode-remove-handled] Remove processed entries. \\[cvs-mode-add-change-log-entry-other-window] Write ChangeLog in other window.
+\\[cvs-mode-add] Add to repository. \\[cvs-mode-remove-file] Remove file.
+\\[cvs-mode-diff-cvs] Diff between base revision. \\[cvs-mode-diff-backup] Diff backup file.
+\\[cvs-mode-emerge] Run emerge on base revision/backup file.
+\\[cvs-mode-acknowledge] Delete line from buffer. \\[cvs-mode-ignore] Add file to the .cvsignore file.
+\\[cvs-mode-log] Run ``cvs log''. \\[cvs-mode-status] Run ``cvs status''.
+\\[cvs-mode-changelog-commit] Like \\[cvs-mode-commit], but get default log text from ChangeLog.
+\\[cvs-mode-undo-local-changes] Revert the last checked in version - discard your changes to the file.
+
+Entry to this mode runs cvs-mode-hook.
+This description is updated for release 1.05 of pcl-cvs.
+
+All bindings:
+\\{cvs-mode-map}"
+ (interactive)
+ (setq major-mode 'cvs-mode)
+ (setq mode-name "CVS")
+ (setq mode-line-process nil)
+ (buffer-flush-undo (current-buffer))
+ (make-local-variable 'goal-column)
+ (setq goal-column cvs-cursor-column)
+ (use-local-map cvs-mode-map)
+ (run-hooks 'cvs-mode-hook))
+
+(defun cvs-sentinel (proc msg)
+ "Sentinel for the cvs update process.
+This is responsible for parsing the output from the cvs update when
+it is finished."
+ (cond
+ ((null (buffer-name (process-buffer proc)))
+ ;; buffer killed
+ (set-process-buffer proc nil))
+ ((memq (process-status proc) '(signal exit))
+ (let* ((obuf (current-buffer))
+ (omax (point-max))
+ (opoint (point)))
+ ;; save-excursion isn't the right thing if
+ ;; process-buffer is current-buffer
+ (unwind-protect
+ (progn
+ (set-buffer (process-buffer proc))
+ (setq mode-line-process
+ (concat ": "
+ (symbol-name (process-status proc))))
+ (let* ((out-file cvs-stdout-file)
+ (stdout-buffer (find-file-noselect out-file)))
+ (cvs-parse-update stdout-buffer (process-buffer proc))
+ (setq cvs-buffers-to-delete
+ (cons (process-buffer proc)
+ (cons stdout-buffer
+ cvs-buffers-to-delete)))
+ (delete-file out-file)))
+ (set-buffer-modified-p (buffer-modified-p))
+ (setq cvs-update-running nil))
+ (if (equal obuf (process-buffer proc))
+ nil
+ (set-buffer (process-buffer proc))
+ (if (< opoint omax)
+ (goto-char opoint))
+ (set-buffer obuf))))))
+
+(defun cvs-update-filter (proc string)
+ "Filter function for pcl-cvs.
+This function gets the output that CVS sends to stderr. It inserts it
+into (process-buffer proc) but it also checks if CVS is waiting for a
+lock file. If so, it inserts a message cookie in the *cvs* buffer."
+ (let ((old-buffer (current-buffer))
+ (data (match-data)))
+ (unwind-protect
+ (progn
+ (set-buffer (process-buffer proc))
+ (save-excursion
+ ;; Insert the text, moving the process-marker.
+ (goto-char (process-mark proc))
+ (insert string)
+ (set-marker (process-mark proc) (point))
+ ;; Delete any old lock message
+ (if (tin-nth cvs-cookie-handle 1)
+ (tin-delete cvs-cookie-handle
+ (tin-nth cvs-cookie-handle 1)))
+ ;; Check if CVS is waiting for a lock.
+ (beginning-of-line 0) ;Move to beginning of last
+ ;complete line.
+ (cond
+ ((looking-at
+ "^cvs update: \\[..:..:..\\] waiting \
+for \\(.*\\)lock in \\(.*\\)$")
+ (setq cvs-lock-file (buffer-substring (match-beginning 2)
+ (match-end 2)))
+ (cookie-enter-last
+ cvs-cookie-handle
+ (cvs-create-fileinfo
+ 'MESSAGE nil nil
+ (concat "\tWaiting for "
+ (buffer-substring (match-beginning 1)
+ (match-end 1))
+ "lock in " cvs-lock-file
+ ".\n\t (type M-x cvs-delete-lock to delete it)")))))))
+ (store-match-data data)
+ (set-buffer old-buffer))))
+
+(defun cvs-delete-lock ()
+ "Delete the lock file that CVS is waiting for.
+Note that this can be dangerous. You should only do this
+if you are convinced that the process that created the lock is dead."
+ (interactive)
+ (cond
+ ((not (or (file-exists-p
+ (concat (file-name-as-directory cvs-lock-file) "#cvs.lock"))
+ (cvs-filter (function cvs-lock-file-p)
+ (directory-files cvs-lock-file))))
+ (error "No lock files found."))
+ ((yes-or-no-p (concat "Really delete locks in " cvs-lock-file "? "))
+ ;; Re-read the directory -- the locks might have disappeared.
+ (let ((locks (cvs-filter (function cvs-lock-file-p)
+ (directory-files cvs-lock-file))))
+ (while locks
+ (delete-file (concat (file-name-as-directory cvs-lock-file)
+ (car locks)))
+ (setq locks (cdr locks)))
+ (cvs-remove-directory
+ (concat (file-name-as-directory cvs-lock-file) "#cvs.lock"))))))
+
+(defun cvs-remove-directory (dir)
+ "Remove a directory."
+ (if (file-directory-p dir)
+ (call-process cvs-rmdir-program nil nil nil dir)
+ (error "Not a directory: %s" dir))
+ (if (file-exists-p dir)
+ (error "Could not remove directory %s" dir)))
+
+(defun cvs-lock-file-p (file)
+ "Return true if FILE looks like a CVS lock file."
+ (or
+ (string-match "^#cvs.tfl.[0-9]+$" file)
+ (string-match "^#cvs.rfl.[0-9]+$" file)
+ (string-match "^#cvs.wfl.[0-9]+$" file)))
+
+(defun cvs-skip-line (stdout stderr regexp &optional arg)
+ "Like forward-line, but check that the skipped line matches REGEXP.
+Args: STDOUT STDERR REGEXP &optional ARG.
+
+If it doesn't match REGEXP a bug report is generated and displayed.
+STDOUT and STDERR is only used to do that.
+
+If optional ARG, a number, is given the ARGth parenthesized expression
+in the REGEXP is returned as a string.
+Point should be in column 1 when this function is called."
+ (cond
+ ((looking-at regexp)
+ (forward-line 1)
+ (if arg
+ (buffer-substring (match-beginning arg)
+ (match-end arg))))
+ (t
+ (cvs-parse-error stdout stderr
+ (if (eq (current-buffer) stdout) 'STDOUT 'STDERR)
+ (point)))))
+
+(defun cvs-get-current-dir (root-dir dirname)
+ "Return current working directory, suitable for cvs-parse-update.
+Args: ROOT-DIR DIRNAME.
+Concatenates ROOT-DIR and DIRNAME to form an absolute path."
+ (if (string= "." dirname)
+ (substring root-dir 0 -1)
+ (concat root-dir dirname)))
+
+(defun cvs-compare-fileinfos (a b)
+ "Compare fileinfo A with fileinfo B and return t if A is `less'."
+ (cond
+ ;; Sort acording to directories.
+ ((string< (cvs-fileinfo->dir a) (cvs-fileinfo->dir b)) t)
+ ((not (string= (cvs-fileinfo->dir a) (cvs-fileinfo->dir b))) nil)
+
+ ;; The DIRCHANGE entry is always first within the directory.
+ ((and (eq (cvs-fileinfo->type a) 'DIRCHANGE)
+ (not (eq (cvs-fileinfo->type b) 'DIRCHANGE))) t)
+ ((and (eq (cvs-fileinfo->type b) 'DIRCHANGE)
+ (not (eq (cvs-fileinfo->type a) 'DIRCHANGE))) nil)
+ ;; All files are sorted by file name.
+ ((string< (cvs-fileinfo->file-name a) (cvs-fileinfo->file-name b)))))
+
+(defun cvs-parse-error (stdout-buffer stderr-buffer err-buf pos)
+ "Handle a parse error when parsing the output from cvs.
+Args: STDOUT-BUFFER STDERR-BUFFER ERR-BUF POS.
+ERR-BUF should be 'STDOUT or 'STDERR."
+ (setq pos (1- pos))
+ (set-buffer cvs-buffer-name)
+ (setq buffer-read-only nil)
+ (erase-buffer)
+ (insert "To: ceder@lysator.liu.se\n")
+ (insert "Subject: pcl-cvs " pcl-cvs-version " parse error.\n")
+ (insert "--text follows this line--\n\n")
+ (insert "This bug report is automatically generated by pcl-cvs\n")
+ (insert "because it doesn't understand some output from CVS. Below\n")
+ (insert "is detailed information about the error. Please send\n")
+ (insert "this, together with any information you think might be\n")
+ (insert "useful for me to fix the bug, to the address above. But\n")
+ (insert "please check the \"known problems\" section of the\n")
+ (insert "documentation first. Note that this buffer contains\n")
+ (insert "information that you might consider confidential. You\n")
+ (insert "are encouraged to read through it before sending it.\n")
+ (insert "\n")
+ (insert "Press C-c C-c to send this email.\n\n")
+ (insert "Please state the version of these programs you are using:\n")
+ (insert "RCS: \ndiff: \n\n")
+
+ (let* ((stdout (save-excursion (set-buffer stdout-buffer) (buffer-string)))
+ (stderr (save-excursion (set-buffer stderr-buffer) (buffer-string)))
+ (errstr (if (eq err-buf 'STDOUT) stdout stderr))
+ (errline-end (string-match "\n" errstr pos))
+ (errline (substring errstr pos errline-end)))
+ (insert (format "Offending line (%d chars): >" (- errline-end pos)))
+ (insert errline)
+ (insert "<\n")
+ (insert "Sent to " (symbol-name err-buf) " at pos " (format "%d\n" pos))
+ (insert "Emacs-version: " (emacs-version) "\n")
+ (insert "Pcl-cvs $" "Id:" "$" ": " "Id: pcl-cvs.el,v 1.93 1993/05/31 22:44:00 ceder Exp \n")
+ (insert "\n")
+ (insert (format "--- Contents of stdout buffer (%d chars) ---\n"
+ (length stdout)))
+ (insert stdout)
+ (insert "--- End of stdout buffer ---\n")
+ (insert (format "--- Contents of stderr buffer (%d chars) ---\n"
+ (length stderr)))
+ (insert stderr)
+ (insert "--- End of stderr buffer ---\n")
+ (insert "End of bug report.\n")
+ (require 'sendmail)
+ (mail-mode)
+ (error "CVS parse error - please report this bug.")))
+
+(defun cvs-parse-update (stdout-buffer stderr-buffer)
+ "Parse the output from `cvs update'.
+
+Args: STDOUT-BUFFER STDERR-BUFFER.
+
+This functions parses the from `cvs update' (which should be
+separated in its stdout- and stderr-components) and prints a
+pretty representation of it in the *cvs* buffer.
+
+Signals an error if unexpected output was detected in the buffer."
+ (let* ((head (cons 'dummy nil))
+ (tail (cvs-parse-stderr stdout-buffer stderr-buffer
+ head default-directory))
+ (root-dir default-directory))
+ (cvs-parse-stdout stdout-buffer stderr-buffer tail root-dir)
+ (setq head (sort (cdr head) (function cvs-compare-fileinfos)))
+
+ (collection-clear cvs-cookie-handle)
+ (collection-append-cookies cvs-cookie-handle head)
+ (cvs-remove-stdout-shadows)
+ (cvs-remove-empty-directories)
+ (set-buffer cvs-buffer-name)
+ (cvs-mode)
+ (goto-char (point-min))
+ (tin-goto-previous cvs-cookie-handle (point-min) 1)
+ (setq default-directory root-dir)))
+
+(defun cvs-remove-stdout-shadows ()
+ "Remove entries in the *cvs* buffer that comes from both stdout and stderr.
+If there is two entries for a single file the second one should be
+deleted. (Remember that sort uses a stable sort algorithm, so one can
+be sure that the stderr entry is always first)."
+ (collection-filter-tins cvs-cookie-handle
+ (function
+ (lambda (tin)
+ (not (cvs-shadow-entry-p tin))))))
+
+(defun cvs-shadow-entry-p (tin)
+ "Return non-nil if TIN is a shadow entry.
+Args: TIN.
+A TIN is a shadow entry if the previous tin contains the same file."
+ (let* ((previous-tin (tin-previous cvs-cookie-handle tin))
+ (curr (tin-cookie cvs-cookie-handle tin))
+ (prev (and previous-tin
+ (tin-cookie cvs-cookie-handle previous-tin))))
+ (and
+ prev curr
+ (string= (cvs-fileinfo->file-name prev) (cvs-fileinfo->file-name curr))
+ (string= (cvs-fileinfo->dir prev) (cvs-fileinfo->dir curr))
+ (or
+ (and (eq (cvs-fileinfo->type prev) 'CONFLICT)
+ (eq (cvs-fileinfo->type curr) 'CONFLICT))
+ (and (eq (cvs-fileinfo->type prev) 'MERGED)
+ (eq (cvs-fileinfo->type curr) 'MODIFIED))
+ (and (eq (cvs-fileinfo->type prev) 'REM-EXIST)
+ (eq (cvs-fileinfo->type curr) 'REMOVED))))))
+
+
+(defun cvs-parse-stderr (stdout-buffer stderr-buffer head dir)
+ "Parse the output from CVS that is written to stderr.
+Args: STDOUT-BUFFER STDERR-BUFFER HEAD DIR
+STDOUT-BUFFER holds the output that cvs sent to stdout. It is only
+used to create a bug report in case there is a parse error.
+STDERR-BUFFER is the buffer that holds the output to parse.
+HEAD is a cons-cell, the head of the list that is built.
+DIR is the directory the `cvs update' was run in.
+
+This function returns the last cons-cell in the list that is built."
+
+ (save-window-excursion
+ (set-buffer stderr-buffer)
+ (goto-char (point-min))
+ (let ((current-dir dir)
+ (root-dir dir))
+
+ (while (< (point) (point-max))
+ (cond
+
+ ;; RCVS support (for now, we simply ignore any output from
+ ;; RCVS, including error messages!)
+
+ ((looking-at "updating of .* finished$")
+ (forward-line 1))
+
+ ((looking-at "REMOTE FOLDER:.*")
+ (forward-line 1)
+ (while (and (< (point) (point-max)) (not (looking-at "phase 2.*")))
+ (forward-line 1))
+ (forward-line 2))
+
+ ((looking-at "turn on remote mode$")
+ (forward-line 1)
+ (while (and (< (point) (point-max)) (not (looking-at "phase 2.*")))
+ (forward-line 1))
+ (forward-line 2))
+
+ ((looking-at "phase 3.*")
+ (goto-char (point-max)))
+
+ ;; End of RCVS stuff.
+
+ ;; CVS is descending a subdirectory.
+ ;; (The "server" case is there to support Cyclic CVS.)
+ ((looking-at "cvs \\(update\\|server\\): Updating \\(.*\\)$")
+ (setq current-dir
+ (cvs-get-current-dir
+ root-dir
+ (buffer-substring (match-beginning 2) (match-end 2))))
+ (setcdr head (list (cvs-create-fileinfo
+ 'DIRCHANGE current-dir
+ nil (buffer-substring (match-beginning 0)
+ (match-end 0)))))
+ (setq head (cdr head))
+ (forward-line 1))
+
+ ;; File removed, since it is removed (by third party) in repository.
+
+ ((or (looking-at
+ "cvs update: warning: \\(.*\\) is not (any longer) pertinent")
+ (looking-at
+ "cvs update: \\(.*\\) is no longer in the repository"))
+
+ (setcdr head (list (cvs-create-fileinfo
+ 'CVS-REMOVED current-dir
+ (file-name-nondirectory
+ (buffer-substring (match-beginning 1)
+ (match-end 1)))
+ (buffer-substring (match-beginning 0)
+ (match-end 0)))))
+ (setq head (cdr head))
+ (forward-line 1))
+
+ ;; File removed by you, but recreated by cvs. Ignored.
+
+ ((looking-at "cvs update: warning: .* was lost$")
+ (forward-line 1))
+
+ ;; A file that has been created by you, but added to the cvs
+ ;; repository by another.
+
+ ((looking-at "^cvs update: move away \\(.*\\); it is in the way$")
+ (setcdr head (list (cvs-create-fileinfo
+ 'MOVE-AWAY current-dir
+ (file-name-nondirectory
+ (buffer-substring (match-beginning 1)
+ (match-end 1)))
+ (buffer-substring (match-beginning 0)
+ (match-end 0)))))
+ (setq head (cdr head))
+ (forward-line 1))
+
+ ;; Empty line. Probably inserted by mistake by user (or developer :-)
+ ;; Ignore.
+
+ ((looking-at "^$")
+ (forward-line 1))
+
+ ;; Cvs waits for a lock. Ignore.
+
+ ((looking-at
+ "^cvs update: \\[..:..:..\\] waiting for .*lock in ")
+ (forward-line 1))
+
+ ;; File removed in repository, but edited by you.
+
+ ((looking-at
+ "cvs update: conflict: \\(.*\\) is modified but no longer \
+in the repository$")
+ (setcdr head (list
+ (cvs-create-fileinfo
+ 'REM-CONFLICT current-dir
+ (file-name-nondirectory
+ (buffer-substring (match-beginning 1) (match-end 1)))
+ (buffer-substring (match-beginning 0)
+ (match-end 0)))))
+ (setq head (cdr head))
+ (forward-line 1))
+
+ ((looking-at
+ "cvs update: conflict: removed \\(.*\\) was modified by \
+second party")
+ (setcdr head
+ (list
+ (cvs-create-fileinfo
+ 'MOD-CONFLICT current-dir
+ (buffer-substring (match-beginning 1) (match-end 1))
+ (buffer-substring (match-beginning 0) (match-end 0)))))
+ (setq head (cdr head))
+ (forward-line 1))
+
+ ((looking-at
+ "cvs update: \\(.*\\) should be removed and is still there")
+ (setcdr head
+ (list
+ (cvs-create-fileinfo
+ 'REM-EXIST current-dir
+ (buffer-substring (match-beginning 1) (match-end 1))
+ (buffer-substring (match-beginning 0) (match-end 0)))))
+ (setq head (cdr head))
+ (forward-line 1))
+
+ ((looking-at "cvs update: in directory ")
+ (let ((start (point)))
+ (forward-line 1)
+ (cvs-skip-line
+ stdout-buffer stderr-buffer
+ (regexp-quote "cvs [update aborted]: there is no repository "))
+ (setcdr head (list
+ (cvs-create-fileinfo
+ 'REPOS-MISSING current-dir
+ nil
+ (buffer-substring start (point)))))
+ (setq head (cdr head))))
+
+ ;; Ignore other messages from Cyclic CVS.
+ ((looking-at "cvs server:")
+ (forward-line 1))
+
+ (t
+
+ ;; CVS has decided to merge someone elses changes into this
+ ;; document. This leads to a lot of garbage being printed.
+ ;; First there is two lines that contains no information
+ ;; that we skip (but we check that we recognize them).
+
+ (let ((complex-start (point))
+ initial-revision filename)
+
+ (cvs-skip-line stdout-buffer stderr-buffer "^RCS file: .*$")
+ (setq initial-revision
+ (cvs-skip-line stdout-buffer stderr-buffer
+ "^retrieving revision \\(.*\\)$" 1))
+ (cvs-skip-line stdout-buffer stderr-buffer
+ "^retrieving revision .*$")
+
+ ;; Get the file name from the next line.
+
+ (setq
+ filename
+ (cvs-skip-line
+ stdout-buffer stderr-buffer
+ "^Merging differences between [0-9.]+ and [0-9.]+ into \\(.*\\)$"
+ 1))
+
+ (cond
+ ;; Was it a conflict?
+ ((looking-at
+ ;; Allow both RCS 5.5 and 5.6. (5.6 prints "rcs" and " warning").
+ "^\\(rcs\\)?merge:?\\( warning\\)?: \\(overlaps\\|conflicts\\) during merge$")
+
+ ;; Yes, this is a conflict.
+ (cvs-skip-line
+ stdout-buffer stderr-buffer
+ "^\\(rcs\\)?merge:?\\( warning\\)?: \\(overlaps\\|conflicts\\) during merge$")
+
+ (cvs-skip-line stdout-buffer stderr-buffer
+ "^cvs \\(update\\|server\\): conflicts found in ")
+
+ (let ((fileinfo
+ (cvs-create-fileinfo
+ 'CONFLICT current-dir
+ filename
+ (buffer-substring complex-start (point)))))
+
+ (cvs-set-fileinfo->base-revision fileinfo initial-revision)
+
+ (setcdr head (list fileinfo))
+ (setq head (cdr head))))
+
+ ;; Was it a conflict, and was RCS compiled without DIFF3_BIN?
+
+ ((looking-at
+ ;; Allow both RCS 5.5 and 5.6. (5.6 prints "rcs" and " warning").
+ "^\\(rcs\\)?merge\\( warning\\)?: overlaps or other probl\
+ems during merge$")
+
+ ;; Yes, this is a conflict.
+ (cvs-skip-line
+ stdout-buffer stderr-buffer
+ "^\\(rcs\\)?merge\\( warning\\)?: overlaps .*during merge$")
+
+ (cvs-skip-line stdout-buffer stderr-buffer
+ "^cvs update: could not merge ")
+ (cvs-skip-line stdout-buffer stderr-buffer
+ "^cvs update: restoring .* from backup file ")
+
+ (let ((fileinfo
+ (cvs-create-fileinfo
+ 'CONFLICT current-dir
+ filename
+ (buffer-substring complex-start (point)))))
+
+ (setcdr head (list fileinfo))
+ (setq head (cdr head))))
+
+ (t
+ ;; Not a conflict; it must be a succesful merge.
+ (let ((fileinfo
+ (cvs-create-fileinfo
+ 'MERGED current-dir
+ filename
+ (buffer-substring complex-start (point)))))
+ (cvs-set-fileinfo->base-revision fileinfo initial-revision)
+ (setcdr head (list fileinfo))
+ (setq head (cdr head)))))))))))
+ head)
+
+
+(defun cvs-parse-stdout (stdout-buffer stderr-buffer head root-dir)
+ "Parse the output from CVS that is written to stdout.
+Args: STDOUT-BUFFER STDERR-BUFFER HEAD ROOT-DIR
+STDOUT-BUFFER is the buffer that holds the output to parse.
+STDERR-BUFFER holds the output that cvs sent to stderr. It is only
+used to create a bug report in case there is a parse error.
+
+HEAD is a cons-cell, the head of the list that is built.
+ROOT-DIR is the directory the `cvs update' was run in.
+
+This function doesn't return anything particular."
+ (save-window-excursion
+ (set-buffer stdout-buffer)
+ (goto-char (point-min))
+ (while (< (point) (point-max))
+ (cond
+
+ ;; M: The file is modified by the user, and untouched in the repository.
+ ;; A: The file is "cvs add"ed, but not "cvs ci"ed.
+ ;; R: The file is "cvs remove"ed, but not "cvs ci"ed.
+ ;; C: Conflict
+ ;; U, P: The file is copied from the repository.
+ ;; ?: Unknown file.
+
+
+ ((looking-at "\\([MARCUP?]\\) \\(.*\\)$")
+ (let*
+ ((c (char-after (match-beginning 1)))
+ (full-path
+ (concat (file-name-as-directory root-dir)
+ (buffer-substring (match-beginning 2) (match-end 2))))
+ (fileinfo (cvs-create-fileinfo
+ (cond ((eq c ?M) 'MODIFIED)
+ ((eq c ?A) 'ADDED)
+ ((eq c ?R) 'REMOVED)
+ ((eq c ?C) 'CONFLICT)
+ ((eq c ?U) 'UPDATED)
+ ;; generated when Cyclic CVS sends a
+ ;; patch instead of the full file:
+ ((eq c ?P) 'UPDATED)
+ ((eq c ??) 'UNKNOWN))
+ (substring (file-name-directory full-path) 0 -1)
+ (file-name-nondirectory full-path)
+ (buffer-substring (match-beginning 0) (match-end 0)))))
+ ;; Updated files require no further action.
+ (if (memq c '(?U ?P))
+ (cvs-set-fileinfo->handled fileinfo t))
+
+ ;; Link this last on the list.
+ (setcdr head (list fileinfo))
+ (setq head (cdr head))
+ (forward-line 1)))
+
+ ;; Executing a program because of the -u option in modules.
+ ((looking-at "cvs update: Executing")
+ ;; Skip by any output the program may generate to stdout.
+ ;; Note that pcl-cvs will get seriously confused if the
+ ;; program prints anything to stderr.
+ (re-search-forward cvs-update-prog-output-skip-regexp)
+ (forward-line 1))
+
+ (t (cvs-parse-error stdout-buffer stderr-buffer 'STDOUT (point)))))))
+
+(defun cvs-pp (fileinfo)
+ "Pretty print FILEINFO. Insert a printed representation in current buffer.
+For use by the cookie package."
+
+ (let ((a (cvs-fileinfo->type fileinfo))
+ (s (if (cvs-fileinfo->marked fileinfo)
+ "*" " "))
+ (f (cvs-fileinfo->file-name fileinfo))
+ (ci (if (cvs-fileinfo->handled fileinfo)
+ " " "ci")))
+ (insert
+ (cond
+ ((eq a 'UPDATED)
+ (format "%s Updated %s" s f))
+ ((eq a 'MODIFIED)
+ (format "%s Modified %s %s" s ci f))
+ ((eq a 'MERGED)
+ (format "%s Merged %s %s" s ci f))
+ ((eq a 'CONFLICT)
+ (format "%s Conflict %s" s f))
+ ((eq a 'ADDED)
+ (format "%s Added %s %s" s ci f))
+ ((eq a 'REMOVED)
+ (format "%s Removed %s %s" s ci f))
+ ((eq a 'UNKNOWN)
+ (format "%s Unknown %s" s f))
+ ((eq a 'CVS-REMOVED)
+ (format "%s Removed from repository: %s" s f))
+ ((eq a 'REM-CONFLICT)
+ (format "%s Conflict: Removed from repository, changed by you: %s" s f))
+ ((eq a 'MOD-CONFLICT)
+ (format "%s Conflict: Removed by you, changed in repository: %s" s f))
+ ((eq a 'REM-EXIST)
+ (format "%s Conflict: Removed by you, but still exists: %s" s f))
+ ((eq a 'DIRCHANGE)
+ (format "\nIn directory %s:"
+ (cvs-fileinfo->dir fileinfo)))
+ ((eq a 'MOVE-AWAY)
+ (format "%s Move away %s - it is in the way" s f))
+ ((eq a 'REPOS-MISSING)
+ (format " This repository is missing! Remove this dir manually."))
+ ((eq a 'MESSAGE)
+ (cvs-fileinfo->full-log fileinfo))
+ (t
+ (format "%s Internal error! %s" s f))))))
+
+
+;;; You can define your own keymap in .emacs. pcl-cvs.el won't overwrite it.
+
+(if cvs-mode-map
+ nil
+ (setq cvs-mode-map (make-keymap))
+ (suppress-keymap cvs-mode-map)
+ (define-key cvs-mode-map " " 'cvs-mode-next-line)
+ (define-key cvs-mode-map "?" 'describe-mode)
+ (define-key cvs-mode-map "A" 'cvs-mode-add-change-log-entry-other-window)
+ (define-key cvs-mode-map "M" 'cvs-mode-mark-all-files)
+ (define-key cvs-mode-map "R" 'cvs-mode-revert-updated-buffers)
+ (define-key cvs-mode-map "U" 'cvs-mode-undo-local-changes)
+ (define-key cvs-mode-map "\C-?" 'cvs-mode-unmark-up)
+ (define-key cvs-mode-map "\C-k" 'cvs-mode-acknowledge)
+ (define-key cvs-mode-map "\C-n" 'cvs-mode-next-line)
+ (define-key cvs-mode-map "\C-p" 'cvs-mode-previous-line)
+ (define-key cvs-mode-map "\M-\C-?" 'cvs-mode-unmark-all-files)
+ (define-key cvs-mode-map "a" 'cvs-mode-add)
+ (define-key cvs-mode-map "b" 'cvs-mode-diff-backup)
+ (define-key cvs-mode-map "c" 'cvs-mode-commit)
+ (define-key cvs-mode-map "C" 'cvs-mode-changelog-commit)
+ (define-key cvs-mode-map "d" 'cvs-mode-diff-cvs)
+ (define-key cvs-mode-map "e" 'cvs-mode-emerge)
+ (define-key cvs-mode-map "f" 'cvs-mode-find-file)
+ (define-key cvs-mode-map "g" 'cvs-mode-update-no-prompt)
+ (define-key cvs-mode-map "i" 'cvs-mode-ignore)
+ (define-key cvs-mode-map "l" 'cvs-mode-log)
+ (define-key cvs-mode-map "m" 'cvs-mode-mark)
+ (define-key cvs-mode-map "n" 'cvs-mode-next-line)
+ (define-key cvs-mode-map "o" 'cvs-mode-find-file-other-window)
+ (define-key cvs-mode-map "p" 'cvs-mode-previous-line)
+ (define-key cvs-mode-map "q" 'bury-buffer)
+ (define-key cvs-mode-map "r" 'cvs-mode-remove-file)
+ (define-key cvs-mode-map "s" 'cvs-mode-status)
+ (define-key cvs-mode-map "x" 'cvs-mode-remove-handled)
+ (define-key cvs-mode-map "u" 'cvs-mode-unmark))
+
+
+(defun cvs-get-marked (&optional ignore-marks)
+ "Return a list of all selected tins.
+If there are any marked tins, and IGNORE-MARKS is nil, return them.
+Otherwise, if the cursor selects a directory, return all files in it.
+Otherwise return (a list containing) the file the cursor points to, or
+an empty list if it doesn't point to a file at all.
+
+Args: &optional IGNORE-MARKS."
+
+ (cond
+ ;; Any marked cookies?
+ ((and (not ignore-marks)
+ (collection-collect-tin cvs-cookie-handle 'cvs-fileinfo->marked)))
+ ;; Nope.
+ (t
+ (let ((sel (tin-locate cvs-cookie-handle (point))))
+ (cond
+ ;; If a directory is selected, all it members are returned.
+ ((and sel (eq (cvs-fileinfo->type
+ (tin-cookie cvs-cookie-handle sel))
+ 'DIRCHANGE))
+ (collection-collect-tin
+ cvs-cookie-handle 'cvs-dir-member-p
+ (cvs-fileinfo->dir (tin-cookie cvs-cookie-handle sel))))
+ (t
+ (list sel)))))))
+
+
+(defun cvs-dir-member-p (fileinfo dir)
+ "Return true if FILEINFO represents a file in directory DIR."
+ (and (not (eq (cvs-fileinfo->type fileinfo) 'DIRCHANGE))
+ (string= (cvs-fileinfo->dir fileinfo) dir)))
+
+(defun cvs-dir-empty-p (tin)
+ "Return non-nil if TIN is a directory that is empty.
+Args: CVS-BUF TIN."
+ (and (eq (cvs-fileinfo->type (tin-cookie cvs-cookie-handle tin)) 'DIRCHANGE)
+ (or (not (tin-next cvs-cookie-handle tin))
+ (eq (cvs-fileinfo->type
+ (tin-cookie cvs-cookie-handle
+ (tin-next cvs-cookie-handle tin)))
+ 'DIRCHANGE))))
+
+(defun cvs-mode-revert-updated-buffers ()
+ "Revert any buffers that are UPDATED, MERGED or CONFLICT."
+ (interactive)
+ (cookie-map (function cvs-revert-fileinfo) cvs-cookie-handle))
+
+(defun cvs-revert-fileinfo (fileinfo)
+ "Revert the buffer that holds the file in FILEINFO if it has changed,
+and if the type is UPDATED, MERGED or CONFLICT."
+ (let* ((type (cvs-fileinfo->type fileinfo))
+ (file (cvs-fileinfo->full-path fileinfo))
+ (buffer (get-file-buffer file)))
+ ;; For a revert to happen...
+ (cond
+ ((and
+ ;; ...the type must be one that justifies a revert...
+ (or (eq type 'UPDATED)
+ (eq type 'MERGED)
+ (eq type 'CONFLICT))
+ ;; ...and the user must be editing the file...
+ buffer)
+ (save-excursion
+ (set-buffer buffer)
+ (cond
+ ((buffer-modified-p)
+ (error "%s: edited since last cvs-update."
+ (buffer-file-name)))
+ ;; Go ahead and revert the file.
+ (t (revert-buffer 'dont-use-auto-save-file 'dont-ask))))))))
+
+
+(defun cvs-mode-remove-handled ()
+ "Remove all lines that are handled.
+Empty directories are removed."
+ (interactive)
+ ;; Pass one: remove files that are handled.
+ (collection-filter-cookies cvs-cookie-handle
+ (function
+ (lambda (fileinfo) (not (cvs-fileinfo->handled fileinfo)))))
+ ;; Pass two: remove empty directories.
+ (cvs-remove-empty-directories))
+
+
+(defun cvs-remove-empty-directories ()
+ "Remove empty directories in the *cvs* buffer."
+ (collection-filter-tins cvs-cookie-handle
+ (function
+ (lambda (tin)
+ (not (cvs-dir-empty-p tin))))))
+
+(defun cvs-mode-mark (pos)
+ "Mark a fileinfo. Args: POS.
+If the fileinfo is a directory, all the contents of that directory are
+marked instead. A directory can never be marked.
+POS is a buffer position."
+
+ (interactive "d")
+
+ (let* ((tin (tin-locate cvs-cookie-handle pos))
+ (sel (tin-cookie cvs-cookie-handle tin)))
+
+ (cond
+ ;; Does POS point to a directory? If so, mark all files in that directory.
+ ((eq (cvs-fileinfo->type sel) 'DIRCHANGE)
+ (cookie-map
+ (function (lambda (f dir)
+ (cond
+ ((cvs-dir-member-p f dir)
+ (cvs-set-fileinfo->marked f t)
+ t)))) ;Tell cookie to redisplay this cookie.
+ cvs-cookie-handle
+ (cvs-fileinfo->dir sel)))
+ (t
+ (cvs-set-fileinfo->marked sel t)
+ (tin-invalidate cvs-cookie-handle tin)
+ (tin-goto-next cvs-cookie-handle pos 1)))))
+
+
+(defun cvs-committable (tin)
+ "Check if the TIN is committable.
+It is committable if it
+ a) is not handled and
+ b) is either MODIFIED, ADDED, REMOVED, MERGED or CONFLICT."
+ (let* ((fileinfo (tin-cookie cvs-cookie-handle tin))
+ (type (cvs-fileinfo->type fileinfo)))
+ (and (not (cvs-fileinfo->handled fileinfo))
+ (or (eq type 'MODIFIED)
+ (eq type 'ADDED)
+ (eq type 'REMOVED)
+ (eq type 'MERGED)
+ (eq type 'CONFLICT)))))
+
+(defun cvs-mode-commit ()
+
+ "Check in all marked files, or the current file.
+The user will be asked for a log message in a buffer.
+If cvs-erase-input-buffer is non-nil that buffer will be erased.
+Otherwise mark and point will be set around the entire contents of the
+buffer so that it is easy to kill the contents of the buffer with \\[kill-region]."
+
+ (interactive)
+
+ (let* ((cvs-buf (current-buffer))
+ (marked (cvs-filter (function cvs-committable)
+ (cvs-get-marked))))
+ (if (null marked)
+ (error "Nothing to commit!")
+ (pop-to-buffer (get-buffer-create cvs-commit-prompt-buffer))
+ (goto-char (point-min))
+
+ (if cvs-erase-input-buffer
+ (erase-buffer)
+ (push-mark (point-max)))
+ (cvs-edit-mode)
+ (make-local-variable 'cvs-commit-list)
+ (setq cvs-commit-list marked)
+ (message "Press C-c C-c when you are done editing."))))
+
+
+(defun cvs-edit-done ()
+ "Commit the files to the repository."
+ (interactive)
+ (if (null cvs-commit-list)
+ (error "You have already commited the files"))
+ (if (and (> (point-max) 1)
+ (/= (char-after (1- (point-max))) ?\n)
+ (or (eq cvs-commit-buffer-require-final-newline t)
+ (and cvs-commit-buffer-require-final-newline
+ (yes-or-no-p
+ (format "Buffer %s does not end in newline. Add one? "
+ (buffer-name))))))
+ (save-excursion
+ (goto-char (point-max))
+ (insert ?\n)))
+ (save-some-buffers)
+ (let ((cc-list cvs-commit-list)
+ (cc-buffer (get-buffer cvs-buffer-name))
+ (msg-buffer (current-buffer))
+ (msg (buffer-substring (point-min) (point-max))))
+ (pop-to-buffer cc-buffer)
+ (bury-buffer msg-buffer)
+ (cvs-use-temp-buffer)
+ (message "Committing...")
+ (if (cvs-execute-list cc-list cvs-program
+ (if cvs-cvsroot
+ (list "-d" cvs-cvsroot "commit" "-m" msg)
+ (list "commit" "-m" msg)))
+ (error "Something went wrong. Check the %s buffer carefully."
+ cvs-temp-buffer-name))
+ (let ((ccl cc-list))
+ (while ccl
+ (cvs-after-commit-function (tin-cookie cvs-cookie-handle (car ccl)))
+ (setq ccl (cdr ccl))))
+ (apply 'tin-invalidate cvs-cookie-handle cc-list)
+ (set-buffer msg-buffer)
+ (setq cvs-commit-list nil)
+ (set-buffer cc-buffer)
+ (if cvs-auto-remove-handled
+ (cvs-mode-remove-handled)))
+
+ (message "Committing... Done."))
+
+(defun cvs-after-commit-function (fileinfo)
+ "Do everything that needs to be done when FILEINFO has been commited.
+The fileinfo->handle is set, and if the buffer is present it is reverted."
+ (cvs-set-fileinfo->handled fileinfo t)
+ (if cvs-auto-revert-after-commit
+ (let* ((file (cvs-fileinfo->full-path fileinfo))
+ (buffer (get-file-buffer file)))
+ ;; For a revert to happen...
+ (if buffer
+ ;; ...the user must be editing the file...
+ (save-excursion
+ (set-buffer buffer)
+ (if (not (buffer-modified-p))
+ ;; ...but it must be unmodified.
+ (revert-buffer 'dont-use-auto-save-file 'dont-ask)))))))
+
+
+(defun cvs-execute-list (tin-list program constant-args)
+ "Run PROGRAM on all elements on TIN-LIST.
+Args: TIN-LIST PROGRAM CONSTANT-ARGS
+The PROGRAM will be called with pwd set to the directory the
+files reside in. CONSTANT-ARGS should be a list of strings. The
+arguments given to the program will be CONSTANT-ARGS followed by all
+the files (from TIN-LIST) that resides in that directory. If the files
+in TIN-LIST resides in different directories the PROGRAM will be run
+once for each directory (if all files in the same directory appears
+after each other).
+
+Any output from PROGRAM will be inserted in the current buffer.
+
+This function return nil if all went well, or the numerical exit
+status or a signal name as a string. Note that PROGRAM might be called
+several times. This will return non-nil if something goes wrong, but
+there is no way to know which process that failed."
+
+ (let ((exitstatus nil))
+ (while tin-list
+ (let ((current-dir (cvs-fileinfo->dir
+ (tin-cookie cvs-cookie-handle
+ (car tin-list))))
+ arg-list arg-str)
+
+ ;; Collect all marked files in this directory.
+
+ (while (and tin-list
+ (string=
+ current-dir
+ (cvs-fileinfo->dir
+ (tin-cookie cvs-cookie-handle (car tin-list)))))
+ (setq arg-list
+ (cons (cvs-fileinfo->file-name
+ (tin-cookie cvs-cookie-handle (car tin-list)))
+ arg-list))
+ (setq tin-list (cdr tin-list)))
+
+ (setq arg-list (nreverse arg-list))
+
+ ;; Execute the command on all the files that were collected.
+
+ (setq default-directory (file-name-as-directory current-dir))
+ (insert (format "=== cd %s\n" default-directory))
+ (insert (format "=== %s %s\n\n"
+ program
+ (mapconcat '(lambda (foo) foo)
+ (nconc (copy-sequence constant-args)
+ arg-list)
+ " ")))
+ (let ((res (apply 'call-process program nil t t
+ (nconc (copy-sequence constant-args) arg-list))))
+ ;; Remember the first, or highest, exitstatus.
+ (if (and (not (and (integerp res) (zerop res)))
+ (or (null exitstatus)
+ (and (integerp exitstatus) (= 1 exitstatus))))
+ (setq exitstatus res)))
+ (goto-char (point-max))))
+ exitstatus))
+
+
+(defun cvs-execute-single-file-list (tin-list extractor program constant-args)
+ "Run PROGRAM on all elements on TIN-LIST.
+
+Args: TIN-LIST EXTRACTOR PROGRAM CONSTANT-ARGS
+
+The PROGRAM will be called with pwd set to the directory the files
+reside in. CONSTANT-ARGS is a list of strings to pass as arguments to
+PROGRAM. The arguments given to the program will be CONSTANT-ARGS
+followed by the list that EXTRACTOR returns.
+
+EXTRACTOR will be called once for each file on TIN-LIST. It is given
+one argument, the cvs-fileinfo. It can return t, which means ignore
+this file, or a list of arguments to send to the program."
+
+ (while tin-list
+ (let ((default-directory (file-name-as-directory
+ (cvs-fileinfo->dir
+ (tin-cookie cvs-cookie-handle
+ (car tin-list)))))
+ (arg-list
+ (funcall extractor
+ (tin-cookie cvs-cookie-handle (car tin-list)))))
+
+ ;; Execute the command unless extractor returned t.
+
+ (if (eq arg-list t)
+ nil
+ (insert (format "=== cd %s\n" default-directory))
+ (insert (format "=== %s %s\n\n"
+ program
+ (mapconcat '(lambda (foo) foo)
+ (nconc (copy-sequence constant-args)
+ arg-list)
+ " ")))
+ (apply 'call-process program nil t t
+ (nconc (copy-sequence constant-args) arg-list))
+ (goto-char (point-max))))
+ (setq tin-list (cdr tin-list))))
+
+
+(defun cvs-edit-mode ()
+ "\\<cvs-edit-mode-map>Mode for editing cvs log messages.
+Commands:
+\\[cvs-edit-done] checks in the file when you are ready.
+This mode is based on fundamental mode."
+ (interactive)
+ (use-local-map cvs-edit-mode-map)
+ (setq major-mode 'cvs-edit-mode)
+ (setq mode-name "CVS Log")
+ (auto-fill-mode 1))
+
+
+(if cvs-edit-mode-map
+ nil
+ (setq cvs-edit-mode-map (make-sparse-keymap))
+ (define-prefix-command 'cvs-control-c-prefix)
+ (define-key cvs-edit-mode-map "\C-c" 'cvs-control-c-prefix)
+ (define-key cvs-edit-mode-map "\C-c\C-c" 'cvs-edit-done))
+
+
+(defun cvs-diffable (tins)
+ "Return a list of all tins on TINS that it makes sense to run
+``cvs diff'' on."
+ ;; +++ There is an unnecessary (nreverse) here. Get the list the
+ ;; other way around instead!
+ (let ((result nil))
+ (while tins
+ (let ((type (cvs-fileinfo->type
+ (tin-cookie cvs-cookie-handle (car tins)))))
+ (if (or (eq type 'MODIFIED)
+ (eq type 'UPDATED)
+ (eq type 'MERGED)
+ (eq type 'CONFLICT)
+ (eq type 'REMOVED) ;+++Does this line make sense?
+ (eq type 'ADDED)) ;+++Does this line make sense?
+ (setq result (cons (car tins) result)))
+ (setq tins (cdr tins))))
+ (nreverse result)))
+
+
+(defun cvs-mode-diff-cvs (&optional ignore-marks)
+ "Diff the selected files against the repository.
+The flags in the variable cvs-diff-flags (which should be a list
+of strings) will be passed to ``cvs diff''. If the variable
+cvs-diff-ignore-marks is non-nil any marked files will not be
+considered to be selected. An optional prefix argument will invert
+the influence from cvs-diff-ignore-marks."
+
+ (interactive "P")
+
+ (if (not (listp cvs-diff-flags))
+ (error "cvs-diff-flags should be a list of strings"))
+
+ (save-some-buffers)
+ (let ((marked (cvs-diffable
+ (cvs-get-marked
+ (or (and ignore-marks (not cvs-diff-ignore-marks))
+ (and (not ignore-marks) cvs-diff-ignore-marks))))))
+ (cvs-use-temp-buffer)
+ (message "cvsdiffing...")
+ ;; Don't care much about the exit status since it is the _sum_ of
+ ;; the status codes from the different files (not the _max_ as it
+ ;; should be).
+ (if (cvs-execute-list marked cvs-program
+ (if cvs-cvsroot
+ (cons "-d" (cons cvs-cvsroot
+ (cons "diff" cvs-diff-flags)))
+ (cons "diff" cvs-diff-flags)))
+ (message "cvsdiffing... Done.")
+ (message "cvsdiffing... No differences found."))))
+
+
+(defun cvs-backup-diffable (tin)
+ "Check if the TIN is backup-diffable.
+It must have a backup file to be diffable."
+ (file-readable-p
+ (cvs-fileinfo->backup-file (tin-cookie cvs-cookie-handle tin))))
+
+(defun cvs-mode-diff-backup (&optional ignore-marks)
+ "Diff the files against the backup file.
+This command can be used on files that are marked with \"Merged\"
+or \"Conflict\" in the *cvs* buffer.
+
+If the variable cvs-diff-ignore-marks is non-nil any marked files will
+not be considered to be selected. An optional prefix argument will
+invert the influence from cvs-diff-ignore-marks.
+
+The flags in cvs-diff-flags will be passed to ``diff''."
+
+ (interactive "P")
+
+ (if (not (listp cvs-diff-flags))
+ (error "cvs-diff-flags should be a list of strings."))
+
+ (save-some-buffers)
+ (let ((marked (cvs-filter
+ (function cvs-backup-diffable)
+ (cvs-get-marked
+ (or
+ (and ignore-marks (not cvs-diff-ignore-marks))
+ (and (not ignore-marks) cvs-diff-ignore-marks))))))
+ (if (null marked)
+ (error "No ``Conflict'' or ``Merged'' file selected!"))
+ (cvs-use-temp-buffer)
+ (message "diffing...")
+ (cvs-execute-single-file-list
+ marked 'cvs-diff-backup-extractor cvs-diff-program cvs-diff-flags))
+ (message "diffing... Done."))
+
+
+(defun cvs-diff-backup-extractor (fileinfo)
+ "Return the filename and the name of the backup file as a list.
+Signal an error if there is no backup file."
+ (if (not (file-readable-p (cvs-fileinfo->backup-file fileinfo)))
+ (error "%s has no backup file."
+ (concat
+ (file-name-as-directory (cvs-fileinfo->dir fileinfo))
+ (cvs-fileinfo->file-name fileinfo))))
+ (list (cvs-fileinfo->backup-file fileinfo)
+ (cvs-fileinfo->file-name fileinfo)))
+
+(defun cvs-mode-find-file-other-window (pos)
+ "Select a buffer containing the file in another window.
+Args: POS"
+ (interactive "d")
+ (let ((tin (tin-locate cvs-cookie-handle pos)))
+ (if tin
+ (let ((type (cvs-fileinfo->type (tin-cookie cvs-cookie-handle
+ tin))))
+ (cond
+ ((or (eq type 'REMOVED)
+ (eq type 'CVS-REMOVED))
+ (error "Can't visit a removed file."))
+ ((eq type 'DIRCHANGE)
+ (let ((obuf (current-buffer))
+ (odir default-directory))
+ (setq default-directory
+ (file-name-as-directory
+ (cvs-fileinfo->dir
+ (tin-cookie cvs-cookie-handle tin))))
+ (dired-other-window default-directory)
+ (set-buffer obuf)
+ (setq default-directory odir)))
+ (t
+ (find-file-other-window (cvs-full-path tin)))))
+ (error "There is no file to find."))))
+
+(defun cvs-fileinfo->full-path (fileinfo)
+ "Return the full path for the file that is described in FILEINFO."
+ (concat
+ (file-name-as-directory
+ (cvs-fileinfo->dir fileinfo))
+ (cvs-fileinfo->file-name fileinfo)))
+
+(defun cvs-full-path (tin)
+ "Return the full path for the file that is described in TIN."
+ (cvs-fileinfo->full-path (tin-cookie cvs-cookie-handle tin)))
+
+(defun cvs-mode-find-file (pos)
+ "Select a buffer containing the file in another window.
+Args: POS"
+ (interactive "d")
+ (let* ((cvs-buf (current-buffer))
+ (tin (tin-locate cvs-cookie-handle pos)))
+ (if tin
+ (let* ((fileinfo (tin-cookie cvs-cookie-handle tin))
+ (type (cvs-fileinfo->type fileinfo)))
+ (cond
+ ((or (eq type 'REMOVED)
+ (eq type 'CVS-REMOVED))
+ (error "Can't visit a removed file."))
+ ((eq type 'DIRCHANGE)
+ (let ((odir default-directory))
+ (setq default-directory
+ (file-name-as-directory (cvs-fileinfo->dir fileinfo)))
+ (dired default-directory)
+ (set-buffer cvs-buf)
+ (setq default-directory odir)))
+ (t
+ (find-file (cvs-full-path tin)))))
+ (error "There is no file to find."))))
+
+(defun cvs-mode-mark-all-files ()
+ "Mark all files.
+Directories are not marked."
+ (interactive)
+ (cookie-map (function (lambda (cookie)
+ (cond
+ ((not (eq (cvs-fileinfo->type cookie) 'DIRCHANGE))
+ (cvs-set-fileinfo->marked cookie t)
+ t))))
+ cvs-cookie-handle))
+
+
+(defun cvs-mode-unmark (pos)
+ "Unmark a fileinfo. Args: POS."
+ (interactive "d")
+
+ (let* ((tin (tin-locate cvs-cookie-handle pos))
+ (sel (tin-cookie cvs-cookie-handle tin)))
+
+ (cond
+ ((eq (cvs-fileinfo->type sel) 'DIRCHANGE)
+ (cookie-map
+ (function (lambda (f dir)
+ (cond
+ ((cvs-dir-member-p f dir)
+ (cvs-set-fileinfo->marked f nil)
+ t))))
+ cvs-cookie-handle
+ (cvs-fileinfo->dir sel)))
+ (t
+ (cvs-set-fileinfo->marked sel nil)
+ (tin-invalidate cvs-cookie-handle tin)
+ (tin-goto-next cvs-cookie-handle pos 1)))))
+
+(defun cvs-mode-unmark-all-files ()
+ "Unmark all files.
+Directories are also unmarked, but that doesn't matter, since
+they should always be unmarked."
+ (interactive)
+ (cookie-map (function (lambda (cookie)
+ (cvs-set-fileinfo->marked cookie nil)
+ t))
+ cvs-cookie-handle))
+
+
+(defun cvs-do-removal (tins)
+ "Remove files.
+Args: TINS.
+TINS is a list of tins that the
+user wants to delete. The files are deleted. If the type of
+the tin is 'UNKNOWN the tin is removed from the buffer. If it
+is anything else the file is added to a list that should be
+`cvs remove'd and the tin is changed to be of type 'REMOVED.
+
+Returns a list of tins files that should be `cvs remove'd."
+ (cvs-use-temp-buffer)
+ (mapcar 'cvs-insert-full-path tins)
+ (cond
+ ((and tins (yes-or-no-p (format "Delete %d files? " (length tins))))
+ (let (files-to-remove)
+ (while tins
+ (let* ((tin (car tins))
+ (fileinfo (tin-cookie cvs-cookie-handle tin))
+ (type (cvs-fileinfo->type fileinfo)))
+ (if (not (or (eq type 'REMOVED) (eq type 'CVS-REMOVED)))
+ (progn
+ (delete-file (cvs-full-path tin))
+ (cond
+ ((or (eq type 'UNKNOWN) (eq type 'MOVE-AWAY))
+ (tin-delete cvs-cookie-handle tin))
+ (t
+ (setq files-to-remove (cons tin files-to-remove))
+ (cvs-set-fileinfo->type fileinfo 'REMOVED)
+ (cvs-set-fileinfo->handled fileinfo nil)
+ (tin-invalidate cvs-cookie-handle tin))))))
+ (setq tins (cdr tins)))
+ files-to-remove))
+ (t nil)))
+
+
+
+(defun cvs-mode-remove-file ()
+ "Remove all marked files."
+ (interactive)
+ (let ((files-to-remove (cvs-do-removal (cvs-get-marked))))
+ (if (null files-to-remove)
+ nil
+ (cvs-use-temp-buffer)
+ (message "removing from repository...")
+ (if (cvs-execute-list files-to-remove cvs-program
+ (if cvs-cvsroot
+ (list "-d" cvs-cvsroot "remove")
+ '("remove")))
+ (error "CVS exited with non-zero exit status.")
+ (message "removing from repository... done.")))))
+
+(defun cvs-mode-undo-local-changes ()
+ "Undo local changes to all marked files.
+The file is removed and `cvs update FILE' is run."
+ (interactive)
+ (let ((tins-to-undo (cvs-get-marked)))
+ (cvs-use-temp-buffer)
+ (mapcar 'cvs-insert-full-path tins-to-undo)
+ (cond
+ ((and tins-to-undo (yes-or-no-p (format "Undo changes to %d files? "
+ (length tins-to-undo))))
+ (let (files-to-update)
+ (while tins-to-undo
+ (let* ((tin (car tins-to-undo))
+ (fileinfo (tin-cookie cvs-cookie-handle tin))
+ (type (cvs-fileinfo->type fileinfo)))
+ (cond
+ ((or
+ (eq type 'UPDATED) (eq type 'MODIFIED) (eq type 'MERGED)
+ (eq type 'CONFLICT) (eq type 'CVS-REMOVED)
+ (eq type 'REM-CONFLICT) (eq type 'MOVE-AWAY)
+ (eq type 'REMOVED))
+ (if (not (eq type 'REMOVED))
+ (delete-file (cvs-full-path tin)))
+ (setq files-to-update (cons tin files-to-update))
+ (cvs-set-fileinfo->type fileinfo 'UPDATED)
+ (cvs-set-fileinfo->handled fileinfo t)
+ (tin-invalidate cvs-cookie-handle tin))
+
+ ((eq type 'MOD-CONFLICT)
+ (error "Use cvs-mode-add instead on %s."
+ (cvs-fileinfo->file-name fileinfo)))
+
+ ((eq type 'REM-CONFLICT)
+ (error "Can't deal with a file you have removed and recreated."))
+
+ ((eq type 'DIRCHANGE)
+ (error "Undo on directories not supported (yet)."))
+
+ ((eq type 'ADDED)
+ (error "There is no old revision to get for %s"
+ (cvs-fileinfo->file-name fileinfo)))
+ (t (error "cvs-mode-undo-local-changes: can't handle an %s"
+ type)))
+
+ (setq tins-to-undo (cdr tins-to-undo))))
+ (cvs-use-temp-buffer)
+ (message "Regetting files from repository...")
+ (if (cvs-execute-list files-to-update cvs-program
+ (if cvs-cvsroot
+ (list "-d" cvs-cvsroot "update")
+ '("update")))
+ (error "CVS exited with non-zero exit status.")
+ (message "Regetting files from repository... done.")))))))
+
+(defun cvs-mode-acknowledge ()
+ "Remove all marked files from the buffer."
+ (interactive)
+
+ (mapcar (function (lambda (tin)
+ (tin-delete cvs-cookie-handle tin)))
+ (cvs-get-marked)))
+
+
+(defun cvs-mode-unmark-up (pos)
+ "Unmark the file on the previous line.
+Takes one argument POS, a buffer position."
+ (interactive "d")
+ (let ((tin (tin-goto-previous cvs-cookie-handle pos 1)))
+ (cond
+ (tin
+ (cvs-set-fileinfo->marked (tin-cookie cvs-cookie-handle tin)
+ nil)
+ (tin-invalidate cvs-cookie-handle tin)))))
+
+(defun cvs-mode-previous-line (arg)
+ "Go to the previous line.
+If a prefix argument is given, move by that many lines."
+ (interactive "p")
+ (tin-goto-previous cvs-cookie-handle (point) arg))
+
+(defun cvs-mode-next-line (arg)
+ "Go to the next line.
+If a prefix argument is given, move by that many lines."
+ (interactive "p")
+ (tin-goto-next cvs-cookie-handle (point) arg))
+
+(defun cvs-add-file-update-buffer (tin)
+ "Subfunction to cvs-mode-add. Internal use only.
+Update the display. Return non-nil if `cvs add' should be called on this
+file. Args: TIN.
+Returns 'ADD or 'RESURRECT."
+ (let ((fileinfo (tin-cookie cvs-cookie-handle tin)))
+ (cond
+ ((eq (cvs-fileinfo->type fileinfo) 'UNKNOWN)
+ (cvs-set-fileinfo->type fileinfo 'ADDED)
+ (tin-invalidate cvs-cookie-handle tin)
+ 'ADD)
+ ((eq (cvs-fileinfo->type fileinfo) 'REMOVED)
+ (cvs-set-fileinfo->type fileinfo 'UPDATED)
+ (cvs-set-fileinfo->handled fileinfo t)
+ (tin-invalidate cvs-cookie-handle tin)
+ 'RESURRECT))))
+
+(defun cvs-add-sub (cvs-buf candidates)
+ "Internal use only.
+Args: CVS-BUF CANDIDATES.
+CANDIDATES is a list of tins. Updates the CVS-BUF and returns a pair of lists.
+The first list is unknown tins that shall be `cvs add -m msg'ed.
+The second list is removed files that shall be `cvs add'ed (resurrected)."
+ (let (add resurrect)
+ (while candidates
+ (let ((type (cvs-add-file-update-buffer (car candidates))))
+ (cond ((eq type 'ADD)
+ (setq add (cons (car candidates) add)))
+ ((eq type 'RESURRECT)
+ (setq resurrect (cons (car candidates) resurrect)))))
+ (setq candidates (cdr candidates)))
+ (cons add resurrect)))
+
+(defun cvs-mode-add ()
+ "Add marked files to the cvs repository."
+ (interactive)
+
+ (let* ((buf (current-buffer))
+ (result (cvs-add-sub buf (cvs-get-marked)))
+ (added (car result))
+ (resurrect (cdr result))
+ (msg (if added (read-from-minibuffer "Enter description: "))))
+
+ (if (or resurrect added)
+ (cvs-use-temp-buffer))
+
+ (cond (resurrect
+ (message "Resurrecting files from repository...")
+ (if (cvs-execute-list resurrect cvs-program
+ (if cvs-cvsroot
+ (list "-d" cvs-cvsroot "add")
+ '("add")))
+ (error "CVS exited with non-zero exit status.")
+ (message "Done."))))
+
+ (cond (added
+ (message "Adding new files to repository...")
+ (if (cvs-execute-list added cvs-program
+ (if cvs-cvsroot
+ (list "-d" cvs-cvsroot "add" "-m" msg)
+ (list "add" "-m" msg)))
+ (error "CVS exited with non-zero exit status.")
+ (message "Done."))))))
+
+(defun cvs-mode-ignore ()
+ "Arrange so that CVS ignores the selected files.
+This command ignores files that are not flagged as `Unknown'."
+ (interactive)
+
+ (mapcar (function (lambda (tin)
+ (cond
+ ((eq (cvs-fileinfo->type
+ (tin-cookie cvs-cookie-handle tin))
+ 'UNKNOWN)
+ (cvs-append-to-ignore
+ (tin-cookie cvs-cookie-handle tin))
+ (tin-delete cvs-cookie-handle tin)))))
+ (cvs-get-marked)))
+
+(defun cvs-append-to-ignore (fileinfo)
+ "Append the file in fileinfo to the .cvsignore file"
+ (save-window-excursion
+ (set-buffer (find-file-noselect (concat (file-name-as-directory
+ (cvs-fileinfo->dir fileinfo))
+ ".cvsignore")))
+ (goto-char (point-max))
+ (if (not (zerop (current-column)))
+ (insert "\n"))
+ (insert (cvs-fileinfo->file-name fileinfo) "\n")
+ (if cvs-sort-ignore-file
+ (sort-lines nil (point-min) (point-max)))
+ (save-buffer)))
+
+(defun cvs-mode-status ()
+ "Show cvs status for all marked files."
+ (interactive)
+
+ (save-some-buffers)
+ (let ((marked (cvs-get-marked)))
+ (cvs-use-temp-buffer)
+ (message "Running cvs status ...")
+ (if (cvs-execute-list
+ marked cvs-program
+ (if cvs-cvsroot
+ (cons "-d" (cons cvs-cvsroot (cons "status" cvs-status-flags)))
+ (cons "status" cvs-status-flags)))
+ (error "CVS exited with non-zero exit status.")
+ (message "Running cvs status ... Done."))))
+
+(defun cvs-mode-log ()
+ "Display the cvs log of all selected files."
+ (interactive)
+
+ (let ((marked (cvs-get-marked)))
+ (cvs-use-temp-buffer)
+ (message "Running cvs log ...")
+ (if (cvs-execute-list marked cvs-program
+ (if cvs-cvsroot
+ (cons "-d" (cons cvs-cvsroot
+ (cons "log" cvs-log-flags)))
+ (cons "log" cvs-log-flags)))
+ (error "CVS exited with non-zero exit status.")
+ (message "Running cvs log ... Done."))))
+
+(defun cvs-byte-compile-files ()
+ "Run byte-compile-file on all selected files that end in '.el'."
+ (interactive)
+ (let ((marked (cvs-get-marked)))
+ (while marked
+ (let ((filename (cvs-full-path (car marked))))
+ (if (string-match "\\.el$" filename)
+ (byte-compile-file filename)))
+ (setq marked (cdr marked)))))
+
+(defun cvs-insert-full-path (tin)
+ "Insert full path to the file described in TIN in the current buffer."
+ (insert (format "%s\n" (cvs-full-path tin))))
+
+
+(defun cvs-mode-add-change-log-entry-other-window (pos)
+ "Add a ChangeLog entry in the ChangeLog of the current directory.
+Args: POS."
+ (interactive "d")
+ (let* ((cvs-buf (current-buffer))
+ (odir default-directory))
+ (setq default-directory
+ (file-name-as-directory
+ (cvs-fileinfo->dir
+ (tin-cookie
+ cvs-cookie-handle
+ (tin-locate cvs-cookie-handle pos)))))
+ (if (not default-directory) ;In case there was no entries.
+ (setq default-directory odir))
+ (add-change-log-entry-other-window)
+ (set-buffer cvs-buf)
+ (setq default-directory odir)))
+
+
+(defun print-cvs-tin (foo)
+ "Debug utility."
+ (let ((cookie (tin-cookie cvs-cookie-handle foo))
+ (stream (get-buffer-create "debug")))
+ (princ "==============\n" stream)
+ (princ (cvs-fileinfo->file-name cookie) stream)
+ (princ "\n" stream)
+ (princ (cvs-fileinfo->dir cookie) stream)
+ (princ "\n" stream)
+ (princ (cvs-fileinfo->full-log cookie) stream)
+ (princ "\n" stream)
+ (princ (cvs-fileinfo->marked cookie) stream)
+ (princ "\n" stream)))
+
+(defun cvs-mode-emerge (pos)
+ "Emerge appropriate revisions of the selected file.
+Args: POS"
+ (interactive "d")
+ (let* ((cvs-buf (current-buffer))
+ (tin (tin-locate cvs-cookie-handle pos)))
+ (if tin
+ (let* ((fileinfo (tin-cookie cvs-cookie-handle tin))
+ (type (cvs-fileinfo->type fileinfo)))
+ (cond
+ ((eq type 'MODIFIED)
+ (require 'emerge)
+ (let ((tmp-file
+ (cvs-retrieve-revision-to-tmpfile fileinfo)))
+ (unwind-protect
+ (if (not (emerge-files
+ t
+ (cvs-fileinfo->full-path fileinfo)
+ tmp-file
+ (cvs-fileinfo->full-path fileinfo)))
+ (error "Emerge session failed"))
+ (delete-file tmp-file))))
+
+ ((or (eq type 'MERGED)
+ (eq type 'CONFLICT))
+ (require 'emerge)
+ (let ((tmp-file
+ (cvs-retrieve-revision-to-tmpfile
+ fileinfo))
+ (ancestor-file
+ (cvs-retrieve-revision-to-tmpfile
+ fileinfo
+ (cvs-fileinfo->base-revision fileinfo))))
+ (unwind-protect
+ (if (not (emerge-files-with-ancestor
+ t
+ (cvs-fileinfo->backup-file fileinfo)
+ tmp-file
+ ancestor-file
+ (cvs-fileinfo->full-path fileinfo)))
+ (error "Emerge session failed"))
+ (delete-file tmp-file)
+ (delete-file ancestor-file))))
+ (t
+ (error "Can only emerge \"Modified\", \"Merged\" or \"Conflict\"%s"
+ " files"))))
+ (error "There is no file to emerge."))))
+
+(defun cvs-retrieve-revision-to-tmpfile (fileinfo &optional revision)
+ "Retrieve the latest revision of the file in FILEINFO to a temporary file.
+If second optional argument REVISION is given, retrieve that revision instead."
+ (let
+ ((temp-name (make-temp-name
+ (concat (file-name-as-directory
+ (or (getenv "TMPDIR") "/tmp"))
+ "pcl-cvs." revision))))
+ (cvs-kill-buffer-visiting temp-name)
+ (if revision
+ (message "Retrieving revision %s..." revision)
+ (message "Retrieving latest revision..."))
+ (let ((res (call-process cvs-shell nil nil nil "-c"
+ (concat cvs-program " update -p "
+ (if revision
+ (concat "-r " revision " ")
+ "")
+ (cvs-fileinfo->full-path fileinfo)
+ " > " temp-name))))
+ (if (and res (not (and (integerp res) (zerop res))))
+ (error "Something went wrong: %s" res))
+
+ (if revision
+ (message "Retrieving revision %s... Done." revision)
+ (message "Retrieving latest revision... Done."))
+ (find-file-noselect temp-name)
+ temp-name)))
+
+(defun cvs-fileinfo->backup-file (fileinfo)
+ "Construct the file name of the backup file for FILEINFO."
+ (if (cvs-fileinfo->base-revision fileinfo)
+ (concat cvs-bakprefix (cvs-fileinfo->file-name fileinfo)
+ "." (cvs-fileinfo->base-revision fileinfo))))
+
+(defun cvs-kill-buffer-visiting (filename)
+ "If there is any buffer visiting FILENAME, kill it (without confirmation)."
+ (let ((l (buffer-list)))
+ (while l
+ (if (string= (buffer-file-name (car l)) filename)
+ (kill-buffer (car l)))
+ (setq l (cdr l)))))
+
+(defun cvs-change-cvsroot (newroot)
+ "Change the cvsroot."
+ (interactive "DNew repository: ")
+ (if (or (file-directory-p (expand-file-name "CVSROOT" newroot))
+ (y-or-n-p (concat "Warning: no CVSROOT found inside repository."
+ " Change cvs-cvsroot anyhow?")))
+ (setq cvs-cvsroot newroot)))
+
+(if (string-match "Lucid" emacs-version)
+ (progn
+ (autoload 'pcl-cvs-fontify "pcl-cvs-lucid")
+ (add-hook 'cvs-mode-hook 'pcl-cvs-fontify)))
+
+
+(defvar cvs-changelog-full-paragraphs t
+ "If non-nil, include full ChangeLog paragraphs in the CVS log.
+This may be set in the ``local variables'' section of a ChangeLog, to
+indicate the policy for that ChangeLog.
+
+A ChangeLog paragraph is a bunch of log text containing no blank lines;
+a paragraph usually describes a set of changes with a single purpose,
+but perhaps spanning several functions in several files. Changes in
+different paragraphs are unrelated.
+
+You could argue that the CVS log entry for a file should contain the
+full ChangeLog paragraph mentioning the change to the file, even though
+it may mention other files, because that gives you the full context you
+need to understand the change. This is the behavior you get when this
+variable is set to t.
+
+On the other hand, you could argue that the CVS log entry for a change
+should contain only the text for the changes which occurred in that
+file, because the CVS log is per-file. This is the behavior you get
+when this variable is set to nil.")
+
+(defun cvs-changelog-name (directory)
+ "Return the name of the ChangeLog file that handles DIRECTORY.
+This is in DIRECTORY or one of its parents.
+Signal an error if we can't find an appropriate ChangeLog file."
+ (let ((dir (file-name-as-directory directory))
+ file)
+ (while (and dir
+ (not (file-exists-p
+ (setq file (expand-file-name "ChangeLog" dir)))))
+ (let ((last dir))
+ (setq dir (file-name-directory (directory-file-name dir)))
+ (if (equal last dir)
+ (setq dir nil))))
+ (or dir
+ (error "Can't find ChangeLog for %s" directory))
+ file))
+
+(defun cvs-narrow-changelog ()
+ "Narrow to the top page of the current buffer, a ChangeLog file.
+Actually, the narrowed region doesn't include the date line.
+A \"page\" in a ChangeLog file is the area between two dates."
+ (or (eq major-mode 'change-log-mode)
+ (error "cvs-narrow-changelog: current buffer isn't a ChangeLog"))
+
+ (goto-char (point-min))
+
+ ;; Skip date line and subsequent blank lines.
+ (forward-line 1)
+ (if (looking-at "[ \t\n]*\n")
+ (goto-char (match-end 0)))
+
+ (let ((start (point)))
+ (forward-page 1)
+ (narrow-to-region start (point))
+ (goto-char (point-min))))
+
+(defun cvs-changelog-paragraph ()
+ "Return the bounds of the ChangeLog paragraph containing point.
+If we are between paragraphs, return the previous paragraph."
+ (save-excursion
+ (beginning-of-line)
+ (if (looking-at "^[ \t]*$")
+ (skip-chars-backward " \t\n" (point-min)))
+ (list (progn
+ (if (re-search-backward "^[ \t]*\n" nil 'or-to-limit)
+ (goto-char (match-end 0)))
+ (point))
+ (if (re-search-forward "^[ \t\n]*$" nil t)
+ (match-beginning 0)
+ (point)))))
+
+(defun cvs-changelog-subparagraph ()
+ "Return the bounds of the ChangeLog subparagraph containing point.
+A subparagraph is a block of non-blank lines beginning with an asterisk.
+If we are between subparagraphs, return the previous subparagraph."
+ (save-excursion
+ (end-of-line)
+ (if (search-backward "*" nil t)
+ (list (progn (beginning-of-line) (point))
+ (progn
+ (forward-line 1)
+ (if (re-search-forward "^[ \t]*[\n*]" nil t)
+ (match-beginning 0)
+ (point-max))))
+ (list (point) (point)))))
+
+(defun cvs-changelog-entry ()
+ "Return the bounds of the ChangeLog entry containing point.
+The variable `cvs-changelog-full-paragraphs' decides whether an
+\"entry\" is a paragraph or a subparagraph; see its documentation string
+for more details."
+ (if cvs-changelog-full-paragraphs
+ (cvs-changelog-paragraph)
+ (cvs-changelog-subparagraph)))
+
+(defun cvs-changelog-ours-p ()
+ "See if ChangeLog entry at point is for the current user, today.
+Return non-nil iff it is."
+ ;; Code adapted from add-change-log-entry.
+ (looking-at (concat (regexp-quote (substring (current-time-string)
+ 0 10))
+ ".* "
+ (regexp-quote (substring (current-time-string) -4))
+ "[ \t]+"
+ (regexp-quote (if (boundp 'add-log-full-name)
+ add-log-full-name
+ user-full-name))
+ " <"
+ (regexp-quote
+ (if (boundp 'add-log-mailing-address)
+ add-log-mailing-address
+ user-mail-address)))))
+
+(defun cvs-relative-path (base child)
+ "Return a directory path relative to BASE for CHILD.
+If CHILD doesn't seem to be in a subdirectory of BASE, just return
+the full path to CHILD."
+ (let ((base (file-name-as-directory (expand-file-name base)))
+ (child (expand-file-name child)))
+ (or (string= base (substring child 0 (length base)))
+ (error "cvs-relative-path: %s isn't in %s" child base))
+ (substring child (length base))))
+
+(defun cvs-changelog-entries (file)
+ "Return the ChangeLog entries for FILE, and the ChangeLog they came from.
+The return value looks like this:
+ (LOGBUFFER (ENTRYSTART . ENTRYEND) ...)
+where LOGBUFFER is the name of the ChangeLog buffer, and each
+\(ENTRYSTART . ENTRYEND\) pair is a buffer region."
+ (save-excursion
+ (set-buffer (find-file-noselect
+ (cvs-changelog-name
+ (file-name-directory
+ (expand-file-name file)))))
+ (or (eq major-mode 'change-log-mode)
+ (change-log-mode))
+ (goto-char (point-min))
+ (if (looking-at "[ \t\n]*\n")
+ (goto-char (match-end 0)))
+ (if (not (cvs-changelog-ours-p))
+ (list (current-buffer))
+ (save-restriction
+ (cvs-narrow-changelog)
+ (goto-char (point-min))
+
+ ;; Search for the name of FILE relative to the ChangeLog. If that
+ ;; doesn't occur anywhere, they're not using full relative
+ ;; filenames in the ChangeLog, so just look for FILE; we'll accept
+ ;; some false positives.
+ (let ((pattern (cvs-relative-path
+ (file-name-directory buffer-file-name) file)))
+ (if (or (string= pattern "")
+ (not (save-excursion
+ (search-forward pattern nil t))))
+ (setq pattern file))
+
+ (let (texts)
+ (while (search-forward pattern nil t)
+ (let ((entry (cvs-changelog-entry)))
+ (setq texts (cons entry texts))
+ (goto-char (elt entry 1))))
+
+ (cons (current-buffer) texts)))))))
+
+(defun cvs-changelog-insert-entries (buffer regions)
+ "Insert those regions in BUFFER specified in REGIONS.
+Sort REGIONS front-to-back first."
+ (let ((regions (sort regions 'car-less-than-car))
+ (last))
+ (while regions
+ (if (and last (< last (car (car regions))))
+ (newline))
+ (setq last (elt (car regions) 1))
+ (apply 'insert-buffer-substring buffer (car regions))
+ (setq regions (cdr regions)))))
+
+(defun cvs-union (set1 set2)
+ "Return the union of SET1 and SET2, according to `equal'."
+ (while set2
+ (or (member (car set2) set1)
+ (setq set1 (cons (car set2) set1)))
+ (setq set2 (cdr set2)))
+ set1)
+
+(defun cvs-insert-changelog-entries (files)
+ "Given a list of files FILES, insert the ChangeLog entries for them."
+ (let ((buffer-entries nil))
+
+ ;; Add each buffer to buffer-entries, and associate it with the list
+ ;; of entries we want from that file.
+ (while files
+ (let* ((entries (cvs-changelog-entries (car files)))
+ (pair (assq (car entries) buffer-entries)))
+ (if pair
+ (setcdr pair (cvs-union (cdr pair) (cdr entries)))
+ (setq buffer-entries (cons entries buffer-entries))))
+ (setq files (cdr files)))
+
+ ;; Now map over each buffer in buffer-entries, sort the entries for
+ ;; each buffer, and extract them as strings.
+ (while buffer-entries
+ (cvs-changelog-insert-entries (car (car buffer-entries))
+ (cdr (car buffer-entries)))
+ (if (and (cdr buffer-entries) (cdr (car buffer-entries)))
+ (newline))
+ (setq buffer-entries (cdr buffer-entries)))))
+
+(defun cvs-edit-delete-common-indentation ()
+ "Unindent the current buffer rigidly until at least one line is flush left."
+ (save-excursion
+ (let ((common 100000))
+ (goto-char (point-min))
+ (while (< (point) (point-max))
+ (if (not (looking-at "^[ \t]*$"))
+ (setq common (min common (current-indentation))))
+ (forward-line 1))
+ (indent-rigidly (point-min) (point-max) (- common)))))
+
+(defun cvs-mode-changelog-commit ()
+
+ "Check in all marked files, or the current file.
+Ask the user for a log message in a buffer.
+
+This is just like `\\[cvs-mode-commit]', except that it tries to provide
+appropriate default log messages by looking at the ChangeLogs. The
+idea is to write your ChangeLog entries first, and then use this
+command to commit your changes.
+
+To select default log text, we:
+- find the ChangeLogs for the files to be checked in,
+- verify that the top entry in the ChangeLog is on the current date
+ and by the current user; if not, we don't provide any default text,
+- search the ChangeLog entry for paragraphs containing the names of
+ the files we're checking in, and finally
+- use those paragraphs as the log text."
+
+ (interactive)
+
+ (let* ((cvs-buf (current-buffer))
+ (marked (cvs-filter (function cvs-committable)
+ (cvs-get-marked))))
+ (if (null marked)
+ (error "Nothing to commit!")
+ (pop-to-buffer (get-buffer-create cvs-commit-prompt-buffer))
+ (goto-char (point-min))
+
+ (erase-buffer)
+ (cvs-insert-changelog-entries
+ (mapcar (lambda (tin)
+ (let ((cookie (tin-cookie cvs-cookie-handle tin)))
+ (expand-file-name
+ (cvs-fileinfo->file-name cookie)
+ (cvs-fileinfo->dir cookie))))
+ marked))
+ (cvs-edit-delete-common-indentation)
+
+ (cvs-edit-mode)
+ (make-local-variable 'cvs-commit-list)
+ (setq cvs-commit-list marked)
+ (message "Press C-c C-c when you are done editing."))))
diff --git a/gnu/usr.bin/cvs/contrib/pcl-cvs/pcl-cvs.texinfo b/gnu/usr.bin/cvs/contrib/pcl-cvs/pcl-cvs.texinfo
new file mode 100644
index 0000000..bb0a4fe
--- /dev/null
+++ b/gnu/usr.bin/cvs/contrib/pcl-cvs/pcl-cvs.texinfo
@@ -0,0 +1,1744 @@
+\input texinfo @c -*-texinfo-*-
+
+@comment Id: pcl-cvs.texinfo,v 1.45 1993/05/31 22:38:15 ceder Exp
+@comment Documentation for the GNU Emacs CVS mode.
+@comment Copyright (C) 1992 Per Cederqvist
+
+@comment This file is part of the pcl-cvs distribution.
+
+@comment Pcl-cvs is free software; you can redistribute it and/or modify
+@comment it under the terms of the GNU General Public License as published by
+@comment the Free Software Foundation; either version 1, or (at your option)
+@comment any later version.
+
+@comment Pcl-cvs is distributed in the hope that it will be useful,
+@comment but WITHOUT ANY WARRANTY; without even the implied warranty of
+@comment MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+@comment GNU General Public License for more details.
+
+@comment You should have received a copy of the GNU General Public License
+@comment along with pcl-cvs; see the file COPYING. If not, write to
+@comment the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+@setfilename pcl-cvs.info
+@settitle Pcl-cvs - The Emacs Front-End to CVS
+@setchapternewpage on
+
+@ifinfo
+Copyright @copyright{} 1992 Per Cederqvist
+
+Permission is granted to make and distribute verbatim copies of
+this manual provided the copyright notice and this permission notice
+are preserved on all copies.
+
+@ignore
+Permission is granted to process this file through Tex and print the
+results, provided the printed document carries copying permission
+notice identical to this one except for the removal of this paragraph
+(this paragraph not being relevant to the printed manual).
+
+@end ignore
+Permission is granted to copy and distribute modified versions of this
+manual under the conditions for verbatim copying, provided also that the
+section entitled ``GNU General Public License'' is included exactly as
+in the original, and provided that the entire resulting derived work is
+distributed under the terms of a permission notice identical to this one.
+
+Permission is granted to copy and distribute translations of this manual
+into another language, under the above conditions for modified versions,
+except that the section entitled ``GNU General Public License'' and
+this permission notice may be included in translations approved by the
+Free Software Foundation instead of in the original English.
+@end ifinfo
+
+@synindex vr fn
+@comment The titlepage section does not appear in the Info file.
+@titlepage
+@sp 4
+@comment The title is printed in a large font.
+@center @titlefont{User's Guide}
+@sp
+@center @titlefont{to}
+@sp
+@center @titlefont{pcl-cvs - the Emacs Front-End to CVS}
+@sp 2
+@center release 1.05
+@comment -release-
+@sp 3
+@center Per Cederqvist
+@sp 3
+@center last updated 31 May 1993
+@comment -date-
+
+@comment The following two commands start the copyright page
+@comment for the printed manual. This will not appear in the Info file.
+@page
+@vskip 0pt plus 1filll
+Copyright @copyright{} 1992 Per Cederqvist
+
+Permission is granted to make and distribute verbatim copies of
+this manual provided the copyright notice and this permission notice
+are preserved on all copies.
+
+Permission is granted to copy and distribute modified versions of this
+manual under the conditions for verbatim copying, provided also that the
+section entitled ``GNU General Public License'' is included exactly as
+in the original, and provided that the entire resulting derived work is
+distributed under the terms of a permission notice identical to this one.
+
+Permission is granted to copy and distribute translations of this manual
+into another language, under the above conditions for modified versions,
+except that the section entitled ``GNU General Public License'' and
+this permission notice may be included in translations approved by the
+Free Software Foundation instead of in the original English.
+@end titlepage
+
+@comment ================================================================
+@comment The real text starts here
+@comment ================================================================
+
+@node Top, Copying, (dir), (dir)
+@comment node-name, next, previous, up
+
+
+@ifinfo
+This info manual describes pcl-cvs which is a GNU Emacs front-end to
+CVS. It works with CVS version 1.3. This manual is updated to release
+1.05 of pcl-cvs.
+@end ifinfo
+@comment -release-
+
+@menu
+* Copying:: GNU General Public License
+* Installation:: How to install pcl-cvs on your system.
+* About pcl-cvs:: Authors and ftp sites.
+
+* Getting started:: An introduction with a walk-through example.
+* Buffer contents:: An explanation of the buffer contents.
+* Commands:: All commands, grouped by type.
+
+* Customization:: How you can tailor pcl-cvs to suit your needs.
+* Future enhancements:: Future enhancements of pcl-cvs.
+* Bugs:: Bugs (known and unknown).
+* Function and Variable Index:: List of functions and variables.
+* Concept Index:: List of concepts.
+* Key Index:: List of keystrokes.
+
+ --- The Detailed Node Listing ---
+
+Installation
+
+* Pcl-cvs installation:: How to install pcl-cvs on your system.
+* On-line manual installation:: How to install the on-line manual.
+* Typeset manual installation:: How to create typeset documentation
+ about pcl-cvs.
+
+About pcl-cvs
+
+* Contributors:: Contributors to pcl-cvs.
+* Archives:: Where can I get a copy of Pcl-Cvs?
+
+Buffer contents
+
+* File status:: The meaning of the second field.
+* Selected files:: How selection works.
+
+Commands
+
+* Updating the directory:: Commands to update the local directory
+* Movement commands:: How to move up and down in the buffer
+* Marking files:: How to mark files that other commands
+ will later operate on.
+* Committing changes:: Checking in your modifications to the
+ CVS repository.
+* Editing files:: Loading files into Emacs.
+* Getting info about files:: Display the log and status of files.
+* Adding and removing files:: Adding and removing files
+* Undoing changes:: Undoing changes
+* Removing handled entries:: Uninteresting lines can easily be removed.
+* Ignoring files:: Telling CVS to ignore generated files.
+* Viewing differences:: Commands to @samp{diff} different versions.
+* Emerge::
+* Reverting your buffers:: Reverting your buffers
+* Miscellaneous commands:: Miscellaneous commands
+@end menu
+
+@node Copying, Installation, Top, Top
+@unnumbered GNU GENERAL PUBLIC LICENSE
+@center Version 2, June 1991
+
+@display
+Copyright @copyright{} 1989, 1991 Free Software Foundation, Inc.
+675 Mass Ave, Cambridge, MA 02139, USA
+
+Everyone is permitted to copy and distribute verbatim copies
+of this license document, but changing it is not allowed.
+@end display
+
+@unnumberedsec Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software---to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+@iftex
+@unnumberedsec TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+@end iftex
+@ifinfo
+@center TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+@end ifinfo
+
+@enumerate
+@item
+This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The ``Program'', below,
+refers to any such program or work, and a ``work based on the Program''
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term ``modification''.) Each licensee is addressed as ``you''.
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+@item
+You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+@item
+You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+@enumerate a
+@item
+You must cause the modified files to carry prominent notices
+stating that you changed the files and the date of any change.
+
+@item
+You must cause any work that you distribute or publish, that in
+whole or in part contains or is derived from the Program or any
+part thereof, to be licensed as a whole at no charge to all third
+parties under the terms of this License.
+
+@item
+If the modified program normally reads commands interactively
+when run, you must cause it, when started running for such
+interactive use in the most ordinary way, to print or display an
+announcement including an appropriate copyright notice and a
+notice that there is no warranty (or else, saying that you provide
+a warranty) and that users may redistribute the program under
+these conditions, and telling the user how to view a copy of this
+License. (Exception: if the Program itself is interactive but
+does not normally print such an announcement, your work based on
+the Program is not required to print an announcement.)
+@end enumerate
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+@item
+You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+@enumerate a
+@item
+Accompany it with the complete corresponding machine-readable
+source code, which must be distributed under the terms of Sections
+1 and 2 above on a medium customarily used for software interchange; or,
+
+@item
+Accompany it with a written offer, valid for at least three
+years, to give any third party, for a charge no more than your
+cost of physically performing source distribution, a complete
+machine-readable copy of the corresponding source code, to be
+distributed under the terms of Sections 1 and 2 above on a medium
+customarily used for software interchange; or,
+
+@item
+Accompany it with the information you received as to the offer
+to distribute corresponding source code. (This alternative is
+allowed only for noncommercial distribution and only if you
+received the program in object code or executable form with such
+an offer, in accord with Subsection b above.)
+@end enumerate
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+@item
+You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+@item
+You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+@item
+Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+@item
+If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+@item
+If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+@item
+The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and ``any
+later version'', you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+@item
+If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+@iftex
+@heading NO WARRANTY
+@end iftex
+@ifinfo
+@center NO WARRANTY
+@end ifinfo
+
+@item
+BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM ``AS IS'' WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+@item
+IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+@end enumerate
+
+@iftex
+@heading END OF TERMS AND CONDITIONS
+@end iftex
+@ifinfo
+@center END OF TERMS AND CONDITIONS
+@end ifinfo
+
+@page
+@unnumberedsec Appendix: How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the ``copyright'' line and a pointer to where the full notice is found.
+
+@smallexample
+@var{one line to give the program's name and a brief idea of what it does.}
+Copyright (C) 19@var{yy} @var{name of author}
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+@end smallexample
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+@smallexample
+Gnomovision version 69, Copyright (C) 19@var{yy} @var{name of author}
+Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+This is free software, and you are welcome to redistribute it
+under certain conditions; type `show c' for details.
+@end smallexample
+
+The hypothetical commands @samp{show w} and @samp{show c} should show
+the appropriate parts of the General Public License. Of course, the
+commands you use may be called something other than @samp{show w} and
+@samp{show c}; they could even be mouse-clicks or menu items---whatever
+suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a ``copyright disclaimer'' for the program, if
+necessary. Here is a sample; alter the names:
+
+@example
+Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+`Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+@var{signature of Ty Coon}, 1 April 1989
+Ty Coon, President of Vice
+@end example
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
+
+@node Installation, About pcl-cvs, Copying, Top
+@comment node-name, next, previous, up
+@chapter Installation
+@cindex Installation
+
+This section describes the installation of pcl-cvs, the GNU Emacs CVS
+front-end. You should install not only the elisp files themselves, but
+also the on-line documentation so that your users will know how to use
+it. You can create typeset documentation from the file
+@file{pcl-cvs.texinfo} as well as an on-line info file. The following
+steps are also described in the file @file{INSTALL} in the source
+directory.
+
+@menu
+* Pcl-cvs installation:: How to install pcl-cvs on your system.
+* On-line manual installation:: How to install the on-line manual.
+* Typeset manual installation:: How to create typeset documentation
+ about pcl-cvs.
+@end menu
+
+@node Pcl-cvs installation, On-line manual installation, Installation, Installation
+@comment node-name, next, previous, up
+@section Installation of the pcl-cvs program
+@cindex Installation of elisp files
+
+@enumerate
+@item
+Edit the file @file{Makefile} to reflect the situation at your site.
+The only things you have to change is the definition of @code{lispdir}
+and @code{infodir}. The elisp files will be copied to @code{lispdir},
+and the info file to @code{infodir}.
+
+@item
+Configure pcl-cvs.el
+
+There are a couple of paths that you have to check to make sure that
+they match you system. They appear early in the file pcl-cvs.el.
+
+@strong{NOTE:} If your system is running emacs 18.57 or earlier you MUST
+uncomment the line that says:
+
+@example
+(setq delete-exited-processes nil)
+@end example
+
+Setting @code{delete-exited-processes} to @code{nil} works around a bug
+in emacs that causes it to dump core. The bug was fixed in emacs
+18.58.@refill
+
+@item
+Release 1.05 and later of pcl-cvs requires parts of the Elib library,
+version 0.07 or later. Elib is available via anonymous ftp from
+prep.ai.mit.edu in @file{pub/gnu/elib-0.07.tar.z}, and from a lot of
+other sites that mirrors prep. Get Elib, and install it, before
+proceeding.
+
+@item
+Type @samp{make install} in the source directory. This will
+byte-compile all @file{.el} files and copy both the @file{.el} and the
+@file{.elc} into the directory you specified in step 1.
+
+If you don't want to install the @file{.el} files but only the
+@file{.elc} files (the byte-compiled files), you can type `@samp{make
+install_elc}' instead of `@samp{make install}'.
+
+If you only want to create the compiled elisp files, but don't want to
+install them, you can type @samp{make elcfiles} instead. This is what
+happens if you only type @samp{make} without parameters.
+
+@item
+Edit the file @file{default.el} in your emacs lisp directory (usually
+@file{/usr/gnu/emacs/lisp} or something similar) and enter the contents
+of the file @file{pcl-cvs-startup.el} into it. It contains a couple of
+@code{auto-load}s that facilitates the use of pcl-cvs.
+
+@end enumerate
+
+@node On-line manual installation, Typeset manual installation, Pcl-cvs installation, Installation
+@comment node-name, next, previous, up
+@section Installation of the on-line manual.
+@cindex Manual installation (on-line)
+@cindex Installation of on-line manual
+@cindex Generating the on-line manual
+@cindex On-line manual (how to generate)
+@cindex Info-file (how to generate)
+
+@enumerate
+@item
+Create the info file @file{pcl-cvs} from @file{pcl-cvs.texinfo} by
+typing @samp{make info}. If you don't have the program @samp{makeinfo}
+you can get it by anonymous ftp from e.g. @samp{ftp.gnu.ai.mit.edu} as
+@file{pub/gnu/texinfo-2.14.tar.Z} (there might be a newer version there
+when you read this), or you could use the preformatted info file
+@file{pcl-cvs.info} that is included in the distribution (type
+@samp{cp pcl-cvs.info pcl-cvs}).@refill
+
+@item
+Move the info file @file{pcl-cvs} to your standard info directory.
+This might be called something like @file{/usr/gnu/emacs/info}.@refill
+
+@item
+Edit the file @file{dir} in the info directory and enter one line to
+contain a pointer to the info file @file{pcl-cvs}. The line can, for
+instance, look like this:@refill
+
+@example
+* Pcl-cvs: (pcl-cvs). An Emacs front-end to CVS.
+@end example
+@end enumerate
+
+@node Typeset manual installation, , On-line manual installation, Installation
+@comment node-name, next, previous, up
+@section How to make typeset documentation from pcl-cvs.texinfo
+@cindex Manual installation (typeset)
+@cindex Installation of typeset manual
+@cindex Printing a manual
+@cindex TeX - generating a typeset manual
+@cindex Generating a typeset manual
+
+If you have @TeX{} installed at your site, you can make a typeset manual
+from @file{pcl-cvs.texinfo}.
+
+@enumerate
+@item
+Run @TeX{} by typing `@samp{make pcl-cvs.dvi}'. You will not get the
+indices unless you have the @code{texindex} program.
+
+@item
+Convert the resulting device independent file @file{pcl-cvs.dvi} to a
+form which your printer can output and print it. If you have a
+postscript printer there is a program, @code{dvi2ps}, which does. There
+is also a program which comes together with @TeX{}, @code{dvips}, which
+you can use.
+
+@end enumerate
+
+@node About pcl-cvs, Getting started, Installation, Top
+@comment node-name, next, previous, up
+@chapter About pcl-cvs
+@cindex About pcl-cvs
+
+Pcl-cvs is a front-end to CVS version 1.3. It integrates the most
+frequently used CVS commands into emacs.
+
+@menu
+* Contributors:: Contributors to pcl-cvs.
+* Archives:: Where can I get a copy of Pcl-Cvs?
+@end menu
+
+@node Contributors, Archives, About pcl-cvs, About pcl-cvs
+@comment node-name, next, previous, up
+@section Contributors to pcl-cvs
+@cindex Contributors
+@cindex Authors
+
+Contributions to the package are welcome. I have limited time to work
+on this project, but I will gladly add any code that you contribute to
+me to this package (@pxref{Bugs}).
+
+The following persons have made contributions to pcl-cvs.
+
+@itemize @bullet
+@item
+Brian Berliner wrote CVS, together with some other contributors.
+Without his work on CVS this package would be useless@dots{}
+
+@item
+Per Cederqvist wrote most of the otherwise unattributed functions in
+pcl-cvs as well as all documentation.
+
+@item
+Inge Wallin (@samp{inge@@lysator.liu.se}) wrote the skeleton to
+@file{pcl-cvs.texinfo}, and gave useful comments on it. He also wrote
+the files @file{elib-node.el} and @file{compile-all.el}. The file
+@file{cookie.el} was inspired by Inge.@refill
+
+@item
+Linus Tolke (@samp{linus@@lysator.liu.se}) contributed useful comments
+on both the functionality and the documentation.@refill
+
+@item
+Jamie Zawinski (@samp{jwz@@lucid.com}) contributed
+@file{pcl-cvs-lucid.el}.
+
+@item
+Leif Lonnblad contributed RCVS support.
+@end itemize
+
+Apart from these, a lot of people have send me suggestions, ideas,
+requests, bug reports and encouragement. Thanks a lot! Without your
+there would be no new releases of pcl-cvs.
+
+@node Archives, , Contributors, About pcl-cvs
+@comment node-name, next, previous, up
+@section Where can I get pcl-cvs?
+@cindex Sites
+@cindex Archives
+@cindex Ftp-sites
+@cindex Getting pcl-cvs
+@cindex Email archives
+
+The latest release of pcl-cvs can be fetched via anonymous ftp from
+@code{ftp.lysator.liu.se}, (IP no. 130.236.254.1) in the directory
+@code{pub/emacs}. If you don't live in Scandinavia you should probably
+check with archie to see if there is a site closer to you that archives
+pcl-cvs.
+
+New releases will be announced to appropriate newsgroups. If you send
+your email address to me I will add you to my list of people to mail
+when I make a new release.
+
+@node Getting started, Buffer contents, About pcl-cvs, Top
+@comment node-name, next, previous, up
+@chapter Getting started
+@cindex Introduction
+@cindex Example run
+
+This document assumes that you know what CVS is, and that you at least
+knows the fundamental concepts of CVS. If that is not the case you
+should read the man page for CVS.
+
+Pcl-cvs is only useful once you have checked out a module. So before
+you invoke it you must have a copy of a module somewhere in the file
+system.
+
+You invoke pcl-cvs by typing @kbd{M-x cvs-update RET}. If your emacs
+responds with @samp{[No match]} your system administrator has not
+installed pcl-cvs properly. Try @kbd{M-x load-library RET pcl-cvs RET}.
+If that also fails - talk to your root. If it succeeds you might put
+this line in your @file{.emacs} file so that you don't have to type the
+@samp{load-library} command every time you wish to use pcl-cvs:
+
+@example
+(autoload 'cvs-update "pcl-cvs" nil t)
+@end example
+
+The function @code{cvs-update} will ask for a directory. The command
+@samp{cvs update} will be run in that directory. (It should contain
+files that have been checked out from a CVS archive.) The output from
+@code{cvs} will be parsed and presented in a table in a buffer called
+@samp{*cvs*}. It might look something like this:
+
+@example
+PCL-CVS release 1.05.
+@comment -release-
+
+In directory /users/ceder/FOO/test:
+ Updated bar
+ Updated file.txt
+ Modified ci namechange
+ Updated newer
+
+In directory /users/ceder/FOO/test/sub:
+ Modified ci ChangeLog
+---------- End -----
+@end example
+
+In this example the three files (@file{bar}, @file{file.txt} and
+@file{newer}) that are marked with @samp{Updated} have been copied from
+the CVS repository to @file{/users/ceder/FOO/test/} since someone else
+have checked in newer versions of them. Two files (@file{namechange}
+and @file{sub/ChangeLog}) have been modified locally, and needs to be
+checked in.
+
+You can move the cursor up and down in the buffer with @kbd{C-n} and
+@kbd{C-p} or @kbd{n} and @kbd{p}. If you press @kbd{c} on one of the
+@samp{Modified} files that file will be checked in to the CVS
+repository. @xref{Committing changes}. You can press @kbd{x} to get rid
+of the "uninteresting" files that have only been @samp{Updated} (and
+don't require any further action from you).@refill
+
+You can also easily get a @samp{diff} between your modified file and the
+base version that you started from, and you can get the output from
+@samp{cvs log} and @samp{cvs status} on the listed files simply by
+pressing a key (@pxref{Getting info about files}).
+
+@node Buffer contents, Commands, Getting started, Top
+@comment node-name, next, previous, up
+@chapter Buffer contents
+@cindex Buffer contents
+
+The display contains four columns. They contain, from left to right:
+
+@itemize @bullet
+@item
+An asterisk when the file is @dfn{marked} (@pxref{Selected
+files}).@refill
+@item
+The status of the file. See @xref{File status}, for more information.@refill
+@item
+A "need to be checked in"-marker (@samp{ci}).
+@item
+The file name.
+@end itemize
+
+@menu
+* File status:: The meaning of the second field.
+* Selected files:: How selection works.
+@end menu
+
+@node File status, Selected files, Buffer contents, Buffer contents
+@comment node-name, next, previous, up
+@section File status
+@cindex File status
+@cindex Updated (file status)
+@cindex Modified (file status)
+@cindex Merged (file status)
+@cindex Conflict (file status)
+@cindex Added (file status)
+@cindex Removed (file status)
+@cindex Unknown (file status)
+@cindex Removed from repository (file status)
+@cindex Removed from repository, changed by you (file status)
+@cindex Removed by you, changed in repository (file status)
+@cindex Move away @var{file} - it is in the way (file status)
+@cindex This repository is missing!@dots{} (file status)
+
+The @samp{file status} field can have the following values:
+
+@table @samp
+@item Updated
+The file was brought up to date with respect to the repository. This is
+done for any file that exists in the repository but not in your source,
+and for files that you haven't changed but are not the most recent
+versions available in the repository.@refill
+
+@item Modified
+The file is modified in your working directory, and there was no
+modification to the same file in the repository.@refill
+
+@item Merged
+The file is modified in your working directory, and there were
+modifications in the repository as well as in your copy, but they were
+merged successfully, without conflict, in your working directory.@refill
+
+@item Conflict
+A conflict was detected while trying to merge your changes to @var{file}
+with changes from the source repository. @var{file} (the copy in your
+working directory) is now the output of the @samp{rcsmerge} command on
+the two versions; an unmodified copy of your file is also in your
+working directory, with the name @file{.#@var{file}.@var{version}},
+where @var{version} is the RCS revision that your modified file started
+from. @xref{Viewing differences}, for more details.@refill
+
+@item Added
+The file has been added by you, but it still needs to be checked in to
+the repository.@refill
+
+@item Removed
+The file has been removed by you, but it needs to be checked in to the
+repository. You can resurrect it by typing @kbd{a} (@pxref{Adding and
+removing files}).@refill
+
+@item Unknown
+A file that was detected in your directory, but that neither appears in
+the repository, nor is present on the list of files that CVS should
+ignore.@refill
+
+@end table
+
+There are also a few special cases, that rarely occur, which have longer
+strings in the fields:
+
+@table @samp
+@item Removed from repository
+The file has been removed from your directory since someone has removed
+it from the repository. (It is still present in the Attic directory, so
+no permanent loss has occurred). This, unlike the other entries in this
+table, is not an error condition.@refill
+
+@item Removed from repository, changed by you
+You have modified a file that someone have removed from the repository.
+You can correct this situation by removing the file manually (see
+@pxref{Adding and removing files}).@refill
+
+@item Removed by you, changed in repository
+You have removed a file, and before you committed the removal someone
+committed a change to that file. You could use @kbd{a} to resurrect the
+file (see @pxref{Adding and removing files}).@refill
+
+@item Move away @var{file} - it is in the way
+For some reason CVS does not like the file @var{file}. Rename or remove
+it.@refill
+
+@item This repository is missing! Remove this dir manually.
+It is impossible to remove a directory in the CVS repository in a clean
+way. Someone have tried to remove one, and CVS gets confused. Remove
+your copy of the directory.@refill
+@end table
+
+@node Selected files, , File status, Buffer contents
+@comment node-name, next, previous, up
+@section Selected files
+@cindex Selected files
+@cindex Marked files
+@cindex File selection
+@cindex Active files
+
+Many of the commands works on the current set of @dfn{selected} files.
+
+@itemize @bullet
+@item
+If there are any files that are marked they constitute the set of
+selected files.@refill
+@item
+Otherwise, if the cursor points to a file, that file is the selected
+file.@refill
+@item
+Otherwise, if the cursor points to a directory, all the files in that
+directory that appears in the buffer are the selected files.
+@end itemize
+
+This scheme might seem a little complicated, but once one get used to
+it, it is quite powerful.
+
+@xref{Marking files} tells how you mark and unmark files.
+
+@node Commands, Customization, Buffer contents, Top
+@comment node-name, next, previous, up
+@chapter Commands
+
+@iftex
+This chapter describes all the commands that you can use in pcl-cvs.
+@end iftex
+@ifinfo
+The nodes in this menu contains explanations about all the commands that
+you can use in pcl-cvs. They are grouped together by type.
+@end ifinfo
+
+@menu
+* Updating the directory:: Commands to update the local directory
+* Movement commands:: How to move up and down in the buffer
+* Marking files:: How to mark files that other commands
+ will later operate on.
+* Committing changes:: Checking in your modifications to the
+ CVS repository.
+* Editing files:: Loading files into Emacs.
+* Getting info about files:: Display the log and status of files.
+* Adding and removing files:: Adding and removing files
+* Undoing changes:: Undoing changes
+* Removing handled entries:: Uninteresting lines can easily be removed.
+* Ignoring files:: Telling CVS to ignore generated files.
+* Viewing differences:: Commands to @samp{diff} different versions.
+* Emerge::
+* Reverting your buffers:: Reverting your buffers
+* Miscellaneous commands:: Miscellaneous commands
+@end menu
+
+@node Updating the directory, Movement commands, Commands, Commands
+@comment node-name, next, previous, up
+@section Updating the directory
+@findex cvs-update
+@findex cvs-mode-update-no-prompt
+@findex cvs-delete-lock
+@cindex Getting the *cvs* buffer
+@kindex g - Rerun @samp{cvs update}
+
+
+@table @kbd
+
+@item M-x cvs-update
+Run a @samp{cvs update} command. You will be asked for the directory in
+which the @samp{cvs update} will be run. The output will be parsed by
+pcl-cvs, and the result printed in the @samp{*cvs*} buffer (see
+@pxref{Buffer contents} for a description of the contents).@refill
+
+By default, @samp{cvs-update} will descend recursively into
+subdirectories. You can avoid that behavior by giving a prefix
+argument to it (e.g., by typing @kbd{C-u M-x cvs-update RET}).@refill
+
+All other commands in pcl-cvs requires that you have a @samp{*cvs*}
+buffer. This is the command that you use to get one.@refill
+
+CVS uses lock files in the repository to ensure the integrity of the
+data files in the repository. They might be left behind i.e. if a
+workstation crashes in the middle of a CVS operation. CVS outputs a
+message when it is waiting for a lock file to go away. Pcl-cvs will
+show the same message in the *cvs* buffer, together with instructions
+for deleting the lock files. You should normally not have to delete
+them manually --- just wait a little while and the problem should fix
+itself. But if the lock files doesn't disappear you can delete them
+with @kbd{M-x cvs-delete-lock RET}.@refill
+
+@item g
+This will run @samp{cvs update} again. It will always use the same
+buffer that was used with the previous @samp{cvs update}. Give a prefix
+argument to avoid descending into subdirectories. This runs the command
+@samp{cvs-mode-update-no-prompt}.@refill
+@end table
+@node Movement commands, Marking files, Updating the directory, Commands
+@comment node-name, next, previous, up
+@section Movement Commands
+@cindex Movement Commands
+@findex cookie-next-cookie
+@findex cookie-previous-cookie
+@kindex SPC - Move down one file
+@kindex C-n - Move down one file
+@kindex n - Move down one file
+@kindex C-p - Move up one file
+@kindex p - Move up on file
+
+You can use most normal Emacs commands to move forward and backward in
+the buffer. Some keys are rebound to functions that take advantage of
+the fact that the buffer is a pcl-cvs buffer:
+
+
+@table @kbd
+@item SPC
+@itemx C-n
+@itemx n
+These keys move the cursor one file forward, towards the end of the
+buffer (@code{cookie-next-cookie}).
+
+@item C-p
+@itemx p
+These keys move one file backward, towards the beginning of the buffer
+(@code{cookie-previous-cookie}).
+@end table
+
+@node Marking files, Committing changes, Movement commands, Commands
+@comment node-name, next, previous, up
+@section Marking files
+@cindex Selecting files (commands to mark files)
+@cindex Marking files
+@kindex m - marking a file
+@kindex M - marking all files
+@kindex u - unmark a file
+@kindex ESC DEL - unmark all files
+@kindex DEL - unmark previous file
+@findex cvs-mode-mark
+@findex cvs-mode-unmark
+@findex cvs-mode-mark-all-files
+@findex cvs-mode-unmark-all-files
+@findex cvs-mode-unmark-up
+
+Pcl-cvs works on a set of @dfn{selected files} (@pxref{Selected files}).
+You can mark and unmark files with these commands:
+
+@table @kbd
+@item m
+This marks the file that the cursor is positioned on. If the cursor is
+positioned on a directory all files in that directory will be marked.
+(@code{cvs-mode-mark}).
+
+@item u
+Unmark the file that the cursor is positioned on. If the cursor is on a
+directory, all files in that directory will be unmarked.
+(@code{cvs-mode-unmark}).@refill
+
+@item M
+Mark @emph{all} files in the buffer (@code{cvs-mode-mark-all-files}).
+
+@item @key{ESC} @key{DEL}
+Unmark @emph{all} files (@code{cvs-mode-unmark-all-files}).
+
+@item @key{DEL}
+Unmark the file on the previous line, and move point to that line
+(@code{cvs-mode-unmark-up}).
+@end table
+
+@node Committing changes, Editing files, Marking files, Commands
+@comment node-name, next, previous, up
+@section Committing changes
+@cindex Committing changes
+@cindex Ci
+@findex cvs-mode-commit
+@kindex c - commit files
+@vindex cvs-erase-input-buffer (variable)
+@vindex cvs-auto-revert-after-commit (variable)
+@cindex Commit buffer
+@cindex Edit buffer
+@cindex Erasing commit message
+@cindex Reverting buffers after commit
+
+@table @kbd
+@item c
+All files that have a "need to be checked in"-marker (@pxref{Buffer
+contents}) can be checked in with the @kbd{c} command. It checks in all
+selected files (@pxref{Selected files}) (except those who lack the
+"ci"-marker - they are ignored). Pressing @kbd{c} causes
+@code{cvs-mode-commit} to be run.@refill
+
+When you press @kbd{c} you will get a buffer called
+@samp{*cvs-commit-message*}. Enter the log message for the file(s) in
+it. When you are ready you should press @kbd{C-c C-c} to actually
+commit the files (using @code{cvs-edit-done}).
+
+Normally the @samp{*cvs-commit-message*} buffer will retain the log
+message from the previous commit, but if the variable
+@code{cvs-erase-input-buffer} is set to a non-@code{nil} value the
+buffer will be erased. Point and mark will always be located around the
+entire buffer so that you can easily erase it with @kbd{C-w}
+(@samp{kill-region}).@refill
+
+If you are editing the files in your emacs an automatic
+@samp{revert-buffer} will be performed. (If the file contains
+@samp{$@asis{Id}$} keywords @samp{cvs commit} will write a new file with
+the new values substituted. The auto-revert makes sure that you get
+them into your buffer). The revert will not occur if you have modified
+your buffer, or if @samp{cvs-auto-revert-after-commit} is set to
+@samp{nil}.@refill
+@end table
+
+@node Editing files, Getting info about files, Committing changes, Commands
+@comment node-name, next, previous, up
+@section Editing files
+
+@cindex Editing files
+@cindex Finding files
+@cindex Loading files
+@cindex Dired
+@cindex Invoking dired
+@findex cvs-mode-find-file
+@findex cvs-mode-find-file-other-window
+@findex cvs-mode-add-change-log-entry-other-window
+@kindex f - find file or directory
+@kindex o - find file in other window
+@kindex A - add ChangeLog entry
+
+There are currently three commands that can be used to find a file (that
+is, load it into a buffer and start editing it there). These commands
+work on the line that the cursor is situated at. They ignore any marked
+files.
+
+@table @kbd
+@item f
+Find the file that the cursor points to. Run @samp{dired}
+@ifinfo
+(@pxref{Dired,,,Emacs})
+@end ifinfo
+if the cursor points to a directory (@code{cvs-mode-find-file}).@refill
+
+@item o
+Like @kbd{f}, but use another window
+(@code{cvs-mode-find-file-other-window}).@refill
+
+@item A
+Invoke @samp{add-change-log-entry-other-window} to edit a
+@samp{ChangeLog} file. The @samp{ChangeLog} will be found in the
+directory of the file the cursor points to.
+(@code{cvs-mode-add-change-log-entry-other-window}).@refill
+@end table
+
+@node Getting info about files, Adding and removing files, Editing files, Commands
+@comment node-name, next, previous, up
+@section Getting info about files
+@cindex Status (cvs command)
+@cindex Log (RCS/cvs command)
+@cindex Getting status
+@kindex l - run @samp{cvs log}
+@kindex s - run @samp{cvs status}
+@findex cvs-mode-log
+@findex cvs-mode-status
+
+Both of the following commands can be customized.
+@xref{Customization}.@refill
+
+@table @kbd
+@item l
+Run @samp{cvs log} on all selected files, and show the result in a
+temporary buffer (@code{cvs-mode-log}).
+
+@item s
+Run @samp{cvs status} on all selected files, and show the result in a
+temporary buffer (@code{cvs-mode-status}).
+@end table
+
+@node Adding and removing files, Undoing changes, Getting info about files, Commands
+@comment node-name, next, previous, up
+@section Adding and removing files
+@cindex Adding files
+@cindex Removing files
+@cindex Resurrecting files
+@cindex Deleting files
+@cindex Putting files under CVS control
+@kindex a - add a file
+@kindex r - remove a file
+@findex cvs-mode-add
+@findex cvs-mode-remove-file
+
+The following commands are available to make it easy to add and remove
+files from the CVS repository.
+
+@table @kbd
+@item a
+Add all selected files. This command can be used on @samp{Unknown}
+files (see @pxref{File status}). The status of the file will change to
+@samp{Added}, and you will have to use @kbd{c} (@samp{cvs-mode-commit}, see
+@pxref{Committing changes}) to really add the file to the
+repository.@refill
+
+This command can also be used on @samp{Removed} files (before you commit
+them) to resurrect them.
+
+Selected files that are neither @samp{Unknown} nor @samp{Removed} will
+be ignored by this command.
+
+The command that is run is @code{cvs-mode-add}.
+
+@item r
+This command removes the selected files (after prompting for
+confirmation). The files are @samp{rm}ed from your directory and
+(unless the status was @samp{Unknown}; @pxref{File status}) they will
+also be @samp{cvs remove}d. If the files were @samp{Unknown} they will
+disappear from the buffer. Otherwise their status will change to
+@samp{Removed}, and you must use @kbd{c} (@samp{cvs-mode-commit},
+@pxref{Committing changes}) to commit the removal.@refill
+
+The command that is run is @code{cvs-mode-remove-file}.
+@end table
+
+@node Undoing changes, Removing handled entries, Adding and removing files, Commands
+@comment node-name, next, previous, up
+@section Undoing changes
+@cindex Undo changes
+@cindex Flush changes
+@kindex U - undo changes
+@findex cvs-mode-undo-local-changes
+
+@table @kbd
+@item U
+If you have modified a file, and for some reason decide that you don't
+want to keep the changes, you can undo them with this command. It works
+by removing your working copy of the file and then getting the latest
+version from the repository (@code{cvs-mode-undo-local-changes}.
+@end table
+
+@node Removing handled entries, Ignoring files, Undoing changes, Commands
+@comment node-name, next, previous, up
+@section Removing handled entries
+@cindex Expunging uninteresting entries
+@cindex Uninteresting entries, getting rid of them
+@cindex Getting rid of uninteresting lines
+@cindex Removing uninteresting (processed) lines
+@cindex Handled lines, removing them
+@kindex x - remove processed entries
+@kindex C-k - remove selected entries
+@findex cvs-mode-remove-handled
+@findex cvs-mode-acknowledge
+@findex cvs-mode-ignore
+
+@table @kbd
+@item x
+This command allows you to remove all entries that you have processed.
+More specifically, the lines for @samp{Updated} files (@pxref{File
+status} and files that have been checked in (@pxref{Committing changes})
+are removed from the buffer. If a directory becomes empty the heading
+for that directory is also removed. This makes it easier to get an
+overview of what needs to be done.
+
+The command is called @code{cvs-mode-remove-handled}. If
+@samp{cvs-auto-remove-handled} is set to non-@code{nil} this will
+automatically be performed after every commit.@refill
+
+@item C-k
+This command can be used for lines that @samp{cvs-mode-remove-handled} would
+not delete, but that you want to delete (@code{cvs-mode-acknowledge}).
+@end table
+
+@node Ignoring files, Viewing differences, Removing handled entries, Commands
+@comment node-name, next, previous, up
+@section Ignoring files
+
+@table @kbd
+@item i
+Arrange so that CVS will ignore the selected files. The file names are
+added to the @file{.cvsignore} file in the corresponding directory. If
+the @file{.cvsignore} doesn't exist it will be created.
+
+The @file{.cvsignore} file should normally be added to the repository,
+but you could ignore it also if you like it better that way.
+
+This runs @code{cvs-mode-ignore}.
+@end table
+
+@node Viewing differences, Emerge, Ignoring files, Commands
+@comment node-name, next, previous, up
+@section Viewing differences
+@cindex Diff
+@cindex Conflicts, how to resolve them
+@cindex Viewing differences
+@kindex d - run @samp{cvs diff}
+@kindex b - diff backup file
+@findex cvs-mode-diff-cvs
+@findex cvs-mode-diff-backup
+@vindex cvs-diff-ignore-marks (variable)
+
+@table @kbd
+@item d
+Display a @samp{cvs diff} between the selected files and the RCS version
+that they are based on. @xref{Customization} describes how you can send
+flags to @samp{cvs diff}. If @var{cvs-diff-ignore-marks} is set to a
+non-@code{nil} value or if a prefix argument is given (but not both) any
+marked files will not be considered to be selected.
+(@code{cvs-mode-diff-cvs}).@refill
+
+@item b
+If CVS finds a conflict while merging two versions of a file (during a
+@samp{cvs update}, @pxref{Updating the directory}) it will save the
+original file in a file called @file{.#@var{FILE}.@var{VERSION}} where
+@var{FILE} is the name of the file, and @var{VERSION} is the RCS version
+number that your file was based on.@refill
+
+With the @kbd{b} command you can run a @samp{diff} on the files
+@file{.#@var{FILE}.@var{VERSION}} and @file{@var{FILE}}. You can get a
+context- or Unidiff by setting @samp{cvs-diff-flags} -
+@pxref{Customization}. This command only works on files that have
+status @samp{Conflict} or @samp{Merged}.@refill
+
+If @var{cvs-diff-ignore-marks} is set to a non-@code{nil} value or if a
+prefix argument is given (but not both) any marked files will not be
+considered to be selected. (@code{cvs-mode-diff-backup}).@refill
+@end table
+
+@node Emerge, Reverting your buffers, Viewing differences, Commands
+@comment node-name, next, previous, up
+@section Running emerge
+@cindex Emerge
+@cindex Invoking emerge
+@cindex Conflicts, resolving
+@cindex Resolving conflicts
+@kindex e - invoke @samp{emerge}
+@findex cvs-mode-emerge
+
+@table @kbd
+@item e
+Invoke @samp{emerge} on one file. This command works slightly different
+depending on the file status.
+
+@table @asis
+@item @samp{Modified}
+Run @samp{emerge-files} with your working file as file A, and the latest
+revision in the repository as file B.
+
+@item @samp{Merged}
+@itemx @samp{Conflict}
+Run @samp{emerge-files-with-ancestor} with your working file (as it was
+prior to your invocation of @samp{cvs-update}) as file A, the latest
+revision in the repository as file B, and the revision that you based
+your local modifications on as ancestor.
+@end table
+
+@strong{Note:} CVS has already performed a merge. The resulting file is
+not used in any way if you use this command. If you use the @kbd{q}
+command inside @samp{emerge} (to successfully terminate the merge) the
+file that CVS created will be overwritten.
+@end table
+
+@node Reverting your buffers, Miscellaneous commands, Emerge, Commands
+@comment node-name, next, previous, up
+@section Reverting your buffers
+@findex cvs-mode-revert-updated-buffers
+@kindex R - revert buffers
+@cindex Syncing buffers
+@cindex Reverting buffers
+
+@table @kbd
+@item R
+If you are editing (or just viewing) a file in a buffer, and that file
+is changed by CVS during a @samp{cvs-update}, all you have to do is type
+@kbd{R} in the *cvs* buffer to read in the new versions of the
+files.@refill
+
+All files that are @samp{Updated}, @samp{Merged} or in @samp{Conflict}
+are reverted from the disk. Any other files are ignored. Only files
+that you were already editing are read.@refill
+
+An error is signalled if you have modified the buffer since it was last
+changed. (@code{cvs-mode-revert-updated-buffers}).@refill
+@end table
+
+@node Miscellaneous commands, , Reverting your buffers, Commands
+@comment node-name, next, previous, up
+@section Miscellaneous commands
+@findex cvs-byte-compile-files
+@cindex Recompiling elisp files
+@cindex Byte compilation
+@cindex Getting rid of lock files
+@cindex Lock files
+@kindex q - bury the *cvs* buffer
+@findex bury-buffer
+
+@table @kbd
+@item M-x cvs-byte-compile-files
+Byte compile all selected files that end in .el.
+
+@item M-x cvs-delete-lock
+This command can be used in any buffer, and deletes the lock files that
+the *cvs* buffer informs you about. You should normally never have to
+use this command since CVS tries very carefully to always remove the
+lock files itself.
+
+You can only use this command when a message in the *cvs* buffer tells
+you so. You should wait a while before using this command in case
+someone else is running a cvs command.
+
+@item q
+Bury the *cvs* buffer. (@code{bury-buffer}).
+
+@end table
+
+@node Customization, Future enhancements, Commands, Top
+@comment node-name, next, previous, up
+@chapter Customization
+@vindex cvs-erase-input-buffer (variable)
+@vindex cvs-inhibit-copyright-message (variable)
+@vindex cvs-diff-flags (variable)
+@vindex cvs-diff-ignore-marks (variable)
+@vindex cvs-log-flags (variable)
+@vindex cvs-status-flags (variable)
+@vindex cvs-auto-remove-handled (variable)
+@vindex cvs-update-prog-output-skip-regexp (variable)
+@vindex cvs-cvsroot (variable)
+@vindex TMPDIR (environment variable)
+@vindex cvs-auto-revert-after-commit (variable)
+@vindex cvs-commit-buffer-require-final-newline (variable)
+@vindex cvs-sort-ignore-file (variable)
+@cindex Inhibiting the Copyright message.
+@cindex Copyright message, getting rid of it
+@cindex Getting rid of the Copyright message.
+@cindex Customization
+@cindex Variables, list of all
+@cindex Erasing the input buffer
+@cindex Context diff, how to get
+@cindex Unidiff, how to get
+@cindex Automatically remove handled files
+@cindex -u option in modules file
+@cindex Modules file (-u option)
+@cindex Update program (-u option in modules file)
+@cindex Reverting buffers after commit
+@cindex Require final newline
+@cindex Automatically inserting newline
+@cindex Commit message, inserting newline
+@cindex Sorting the .cvsignore file
+@cindex .cvsignore file, sorting
+@cindex Automatically sorting .cvsignore
+
+If you have an idea about any customization that would be handy but
+isn't present in this list, please tell me! @xref{Bugs} for info on how
+to reach me.@refill
+
+@table @samp
+@item cvs-erase-input-buffer
+If set to anything else than @code{nil} the edit buffer will be erased
+before you write the log message (@pxref{Committing changes}).
+
+@item cvs-inhibit-copyright-message
+The copyright message that is displayed on startup can be annoying after
+a while. Set this variable to @samp{t} if you want to get rid of it.
+(But don't set this to @samp{t} in the system defaults file - new users
+should see this message at least once).
+
+@item cvs-diff-flags
+A list of strings to pass as arguments to the @samp{cvs diff} and
+@samp{diff} programs. This is used by @samp{cvs-mode-diff-cvs} and
+@samp{cvs-mode-diff-backup} (key @kbd{b}, @pxref{Viewing differences}). If
+you prefer the Unidiff format you could add this line to your
+@file{.emacs} file:@refill
+
+@example
+(setq cvs-diff-flags '("-u"))
+@end example
+
+@item cvs-diff-ignore-marks
+If this variable is non-@code{nil} or if a prefix argument is given (but
+not both) to @samp{cvs-mode-diff-cvs} or @samp{cvs-mode-diff-backup}
+marked files are not considered selected.
+
+@item cvs-log-flags
+List of strings to send to @samp{cvs log}. Used by @samp{cvs-mode-log}
+(key @kbd{l}, @pxref{Getting info about files}).
+
+@item cvs-status-flags
+List of strings to send to @samp{cvs status}. Used by @samp{cvs-mode-status}
+(key @kbd{s}, @pxref{Getting info about files}).
+
+@item cvs-auto-remove-handled
+If this variable is set to any non-@code{nil} value
+@samp{cvs-mode-remove-handled} will be called every time you check in
+files, after the check-in is ready. @xref{Removing handled
+entries}.@refill
+
+@item cvs-auto-revert-after-commit
+If this variable is set to any non-@samp{nil} value any buffers you have
+that visit a file that is committed will be automatically reverted.
+This variable is default @samp{t}. @xref{Committing changes}.@refill
+
+@item cvs-update-prog-output-skip-regexp
+The @samp{-u} flag in the @file{modules} file can be used to run a command
+whenever a @samp{cvs update} is performed (see cvs(5)). This regexp
+is used to search for the last line in that output. It is normally set
+to @samp{"$"}. That setting is only correct if the command outputs
+nothing. Note that pcl-cvs will get very confused if the command
+outputs @emph{anything} to @samp{stderr}.
+
+@item cvs-cvsroot
+This variable can be set to override @samp{CVSROOT}. It should be a
+string. If it is set then everytime a cvs command is run it will be
+called as @samp{cvs -d @var{cvs-cvsroot}@dots{}} This can be useful if
+your site has several repositories.
+
+@item TMPDIR
+Pcl-cvs uses this @emph{environment variable} to decide where to put the
+temporary files it needs. It defaults to @file{/tmp} if it is not set.
+
+@item cvs-commit-buffer-require-final-newline
+When you enter a log message in the @samp{*cvs-commit-message*} buffer
+pcl-cvs will normally automatically insert a trailing newline, unless
+there already is one. This behavior can be controlled via
+@samp{cvs-commit-buffer-require-final-newline}. If it is @samp{t} (the
+default behavior), a newline will always be appended. If it is
+@samp{nil}, newlines will never be appended. Any other value causes
+pcl-cvs to ask the user whenever there is no trailing newline in the
+commit message buffer.
+
+@item cvs-sort-ignore-file
+If this variable is set to any non-@samp{nil} value the
+@file{.cvsignore} will always be sorted whenever you use
+@samp{cvs-mode-ignore} to add a file to it. This option is on by
+default.
+
+@end table
+@node Future enhancements, Bugs, Customization, Top
+@comment node-name, next, previous, up
+@chapter Future enhancements
+@cindex Enhancements
+
+Pcl-cvs is still under development and needs a number of enhancements to
+be called complete. Below is my current wish-list for future releases
+of pcl-cvs. Please, let me know which of these features you want most.
+They are listed below in approximately the order that I currently think
+I will implement them in.
+
+@itemize @bullet
+@item
+Rewritten parser code. There are many situations where pcl-cvs will
+fail to recognize the output from CVS. The situation could be greatly
+increased.
+
+@item
+@samp{cvs-status}. This will run @samp{cvs status} in a directory and
+produce a buffer that looks pretty much like the current *cvs* buffer.
+That buffer will include information for all version-controlled files.
+(There will be a simple keystroke to remove all "uninteresting" files,
+that is, files that are "Up-to-date"). In this new buffer you will be
+able to update a file, commit a file, et c. The big win with this is
+that you will be able to watch the differences between your current
+working file and the head revision in the repository before you update
+the file, and you can then choose to update it or let it wait for a
+while longer.
+
+@item
+Log mode. When this mode is finished you will be able to move around
+(using @kbd{n} and @kbd{p}) between the revisions of a file, mark two of
+them, and run a diff between them. You will be able to hide branches
+(similar to the way you can hide sub-paragraphs in outline-mode) and do
+merges between revisions. Other ideas about this are welcome.
+
+@item
+The current model for marks in the *cvs* buffer seems to be confusing.
+I am considering to use the VM model instead, where marks are normally
+inactive. To activate the mark, you issue a command like
+@samp{cvs-mode-next-command-uses-marks}. I might implement a flag so
+that you can use either version. Feedback on this before I start coding
+it is very welcome.
+
+@item
+It should be possible to run commands such as @samp{cvs log}, @samp{cvs
+status} and @samp{cvs commit} directly from a buffer containing a file,
+instead of having to @samp{cvs-update}. If the directory contains many
+files the @samp{cvs-update} can take quite some time, especially on a
+slow machine. I planed to put these kind of commands on the prefix
+@kbd{C-c C-v}, but that turned out to be used by for instance c++-mode.
+If you have any suggestions for a better prefix key, please let me know.
+
+@item
+Increased robustness. For instance, you can not currently press
+@kbd{C-g} when you are entering the description of a file that you are
+adding without confusing pcl-cvs.
+
+@item
+Support for multiple active *cvs* buffers.
+
+@item
+Dired support. I have an experimental @file{dired-cvs.el} that works
+together with CVS 1.2. Unfortunately I wrote it on top of a
+non-standard @file{dired.el}, so it must be rewritten.@refill
+
+@item
+An ability to send user-supplied options to all the cvs commands.
+
+@item
+Pcl-cvs is not at all clever about what it should do when @samp{cvs
+update} runs a program (due to the @samp{-u} option in the
+@file{modules} file --- see @samp{cvs(5)}). The current release uses a
+regexp to search for the end. At the very least that regexp should be
+configured for different modules. Tell me if you have any idea about
+what is the right thing to do. In a perfect world the program should
+also be allowed to print to @samp{stderr} without causing pcl-cvs to
+crash.
+@end itemize
+
+
+If you miss something in this wish-list, let me know! I don't promise
+that I will write it, but I will at least try to coordinate the efforts
+of making a good Emacs front end to CVS. See @xref{Bugs} for
+information about how to reach me.@refill
+
+So far, I have written most of pcl-cvs in my all-to-rare spare time. If
+you want pcl-cvs to be developed faster you can write a contract with
+Signum Support to do the extension. You can reach Signum Support by
+email to @samp{info@@signum.se} or via mail to Signum Support AB, Box
+2044, S-580 02 Linkoping, Sweden. Phone: +46 (0) 13 - 21 46 00. Fax: +46
+(0) 13 - 21 47 00.
+
+@node Bugs, Function and Variable Index, Future enhancements, Top
+@comment node-name, next, previous, up
+@chapter Bugs (known and unknown)
+@cindex Reporting bugs and ideas
+@cindex Bugs, how to report them
+@cindex Author, how to reach
+@cindex Email to the author
+@cindex Known bugs
+@cindex Bugs, known
+@cindex FAQ
+@cindex Problems, list of common
+
+If you find a bug or misfeature, don't hesitate to tell me! Send email
+to @samp{ceder@@lysator.liu.se}.
+
+If you have ideas for improvements, or if you have written some
+extensions to this package, I would like to hear from you. I hope that
+you find this package useful!
+
+Below is a partial list of currently known problems with pcl-cvs version
+1.05.
+
+@table @asis
+@item Commit causes Emacs to hang
+Emacs waits for the @samp{cvs commit} command to finish before you can
+do anything. If you start a background job from the loginfo file you
+must take care that it closes @samp{stdout} and @samp{stderr} if you do
+not want to wait for it. (You do that with @samp{background-command &>-
+2&>- &} if you are starting @samp{background-command} from a
+@samp{/bin/sh} shell script).
+
+Your emacs will also hang if there was a lock file in the repository.
+In this case you can type @kbd{C-g} to get control over your emacs
+again.
+
+@item Name clash in Emacs 19
+This is really a bug in Elib or the Emacs 19 distribution. Both Elib and
+Emacs 19.6 through at least 19.10 contains a file named
+@file{cookie.el}. One of the files will have to be renamed, and we are
+currently negotiating about which of the files to rename.
+
+@item Commands while cvs-update is running
+It is possible to type commands in the *cvs* buffer while the update is
+running, but error messages is all that you will get. The error
+messages should be better.
+
+@item Unexpected output from CVS
+Unexpected output from CVS confuses pcl-cvs. It will currently create a
+bug report that you can mail to me. It should do something more
+civilized.
+@end table
+
+@node Function and Variable Index, Concept Index, Bugs, Top
+@comment node-name, next, previous, up
+@unnumbered Function and Variable Index
+
+@printindex fn
+
+@node Concept Index, Key Index, Function and Variable Index, Top
+@comment node-name, next, previous, up
+@unnumbered Concept Index
+
+@printindex cp
+
+@node Key Index, , Concept Index, Top
+@comment node-name, next, previous, up
+@unnumbered Key Index
+
+@printindex ky
+
+@summarycontents
+@contents
+@bye
diff --git a/gnu/usr.bin/cvs/contrib/rcs-to-cvs.sh b/gnu/usr.bin/cvs/contrib/rcs-to-cvs.sh
new file mode 100644
index 0000000..3af83d7
--- /dev/null
+++ b/gnu/usr.bin/cvs/contrib/rcs-to-cvs.sh
@@ -0,0 +1,185 @@
+#! /bin/sh
+#
+# $Id: rcs-to-cvs.sh,v 1.2 1995/07/15 03:40:34 jimb Exp $
+# Based on the CVS 1.0 checkin csh script.
+# Contributed by Per Cederqvist <ceder@signum.se>.
+# Rewritten in sh by David MacKenzie <djm@cygnus.com>.
+#
+# Copyright (c) 1989, Brian Berliner
+#
+# You may distribute under the terms of the GNU General Public License.
+#
+#############################################################################
+#
+# Check in sources that previously were under RCS or no source control system.
+#
+# The repository is the directory where the sources should be deposited.
+#
+# Traverses the current directory, ensuring that an
+# identical directory structure exists in the repository directory. It
+# then checks the files in in the following manner:
+#
+# 1) If the file doesn't yet exist, check it in as revision 1.1
+#
+# The script also is somewhat verbose in letting the user know what is
+# going on. It prints a diagnostic when it creates a new file, or updates
+# a file that has been modified on the trunk.
+#
+# Bugs: doesn't put the files in branch 1.1.1
+# doesn't put in release and vendor tags
+#
+#############################################################################
+
+usage="Usage: rcs-to-cvs [-v] [-m message] [-f message_file] repository"
+vbose=0
+message=""
+message_file=/usr/tmp/checkin.$$
+got_one=0
+
+if [ $# -lt 1 ]; then
+ echo "$usage" >&2
+ exit 1
+fi
+
+while [ $# -ne 0 ]; do
+ case "$1" in
+ -v)
+ vbose=1
+ ;;
+ -m)
+ shift
+ echo $1 > $message_file
+ got_one=1
+ ;;
+ -f)
+ shift
+ message_file=$1
+ got_one=2
+ ;;
+ *)
+ break
+ esac
+ shift
+done
+
+if [ $# -lt 1 ]; then
+ echo "$usage" >&2
+ exit 1
+fi
+
+repository=$1
+shift
+
+if [ -z "$CVSROOT" ]; then
+ echo "Please the environmental variable CVSROOT to the root" >&2
+ echo " of the tree you wish to update" >&2
+ exit 1
+fi
+
+if [ $got_one -eq 0 ]; then
+ echo "Please Edit this file to contain the RCS log information" >$message_file
+ echo "to be associated with this directory (please remove these lines)">>$message_file
+ ${EDITOR-/usr/ucb/vi} $message_file
+ got_one=1
+fi
+
+# Ya gotta share.
+umask 0
+
+update_dir=${CVSROOT}/${repository}
+[ ! -d ${update_dir} ] && mkdir $update_dir
+
+if [ -d SCCS ]; then
+ echo SCCS files detected! >&2
+ exit 1
+fi
+if [ -d RCS ]; then
+ co RCS/*
+fi
+
+for name in * .[a-zA-Z0-9]*
+do
+ case "$name" in
+ RCS | *~ | \* | .\[a-zA-Z0-9\]\* ) continue ;;
+ esac
+ echo $name
+ if [ $vbose -ne 0 ]; then
+ echo "Updating ${repository}/${name}"
+ fi
+ if [ -d "$name" ]; then
+ if [ ! -d "${update_dir}/${name}" ]; then
+ echo "WARNING: Creating new directory ${repository}/${name}"
+ mkdir "${update_dir}/${name}"
+ if [ $? -ne 0 ]; then
+ echo "ERROR: mkdir failed - aborting" >&2
+ exit 1
+ fi
+ fi
+ cd "$name"
+ if [ $? -ne 0 ]; then
+ echo "ERROR: Couldn\'t cd to $name - aborting" >&2
+ exit 1
+ fi
+ if [ $vbose -ne 0 ]; then
+ $0 -v -f $message_file "${repository}/${name}"
+ else
+ $0 -f $message_file "${repository}/${name}"
+ fi
+ if [ $? -ne 0 ]; then
+ exit 1
+ fi
+ cd ..
+ else # if not directory
+ if [ ! -f "$name" ]; then
+ echo "WARNING: $name is neither a regular file"
+ echo " nor a directory - ignored"
+ continue
+ fi
+ file="${update_dir}/${name},v"
+ comment=""
+ if grep -s '\$Log.*\$' "${name}"; then # If $Log keyword
+ myext=`echo $name | sed 's,.*\.,,'`
+ [ "$myext" = "$name" ] && myext=
+ case "$myext" in
+ c | csh | e | f | h | l | mac | me | mm | ms | p | r | red | s | sh | sl | cl | ml | el | tex | y | ye | yr | "" )
+ ;;
+
+ * )
+ echo "For file ${file}:"
+ grep '\$Log.*\$' "${name}"
+ echo -n "Please insert a comment leader for file ${name} > "
+ read comment
+ ;;
+ esac
+ fi
+ if [ ! -f "$file" ]; then # If not exists in repository
+ if [ ! -f "${update_dir}/Attic/${name},v" ]; then
+ echo "WARNING: Creating new file ${repository}/${name}"
+ if [ -f RCS/"${name}",v ]; then
+ echo "MSG: Copying old rcs file."
+ cp RCS/"${name}",v "$file"
+ else
+ if [ -n "${comment}" ]; then
+ rcs -q -i -c"${comment}" -t${message_file} -m'.' "$file"
+ fi
+ ci -q -u1.1 -t${message_file} -m'.' "$file"
+ if [ $? -ne 0 ]; then
+ echo "ERROR: Initial check-in of $file failed - aborting" >&2
+ exit 1
+ fi
+ fi
+ else
+ file="${update_dir}/Attic/${name},v"
+ echo "WARNING: IGNORED: ${repository}/Attic/${name}"
+ continue
+ fi
+ else # File existed
+ echo "ERROR: File exists in repository: Ignored: $file"
+ continue
+ fi
+ fi
+done
+
+[ $got_one -eq 1 ] && rm -f $message_file
+
+exit 0
diff --git a/gnu/usr.bin/cvs/contrib/rcs2log.sh b/gnu/usr.bin/cvs/contrib/rcs2log.sh
new file mode 100644
index 0000000..ccea907
--- /dev/null
+++ b/gnu/usr.bin/cvs/contrib/rcs2log.sh
@@ -0,0 +1,592 @@
+#! /bin/sh
+
+# RCS to ChangeLog generator
+
+# Generate a change log prefix from RCS files and the ChangeLog (if any).
+# Output the new prefix to standard output.
+# You can edit this prefix by hand, and then prepend it to ChangeLog.
+
+# Ignore log entries that start with `#'.
+# Clump together log entries that start with `{topic} ',
+# where `topic' contains neither white space nor `}'.
+
+# Author: Paul Eggert <eggert@twinsun.com>
+
+# $Id: rcs2log.sh,v 1.2 1995/07/28 19:48:45 eggert Exp $
+
+# Copyright 1992, 1993, 1994, 1995 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; see the file COPYING. If not, write to
+# the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+tab=' '
+nl='
+'
+
+# Parse options.
+
+# defaults
+: ${AWK=awk}
+: ${TMPDIR=/tmp}
+hostname= # name of local host (if empty, will deduce it later)
+indent=8 # indent of log line
+length=79 # suggested max width of log line
+logins= # login names for people we know fullnames and mailaddrs of
+loginFullnameMailaddrs= # login<tab>fullname<tab>mailaddr triplets
+recursive= # t if we want recursive rlog
+rlog_options= # options to pass to rlog
+tabwidth=8 # width of horizontal tab
+
+while :
+do
+ case $1 in
+ -i) indent=${2?}; shift;;
+ -h) hostname=${2?}; shift;;
+ -l) length=${2?}; shift;;
+ -[nu]) # -n is obsolescent; it is replaced by -u.
+ case $1 in
+ -n) case ${2?}${3?}${4?} in
+ *"$tab"* | *"$nl"*)
+ echo >&2 "$0: -n '$2' '$3' '$4': tabs, newlines not allowed"
+ exit 1
+ esac
+ loginFullnameMailaddrs=$loginFullnameMailaddrs$nl$2$tab$3$tab$4
+ shift; shift; shift;;
+ -u)
+ # If $2 is not tab-separated, use colon for separator.
+ case ${2?} in
+ *"$nl"*)
+ echo >&2 "$0: -u '$2': newlines not allowed"
+ exit 1;;
+ *"$tab"*)
+ t=$tab;;
+ *)
+ t=:
+ esac
+ case $2 in
+ *"$t"*"$t"*"$t"*)
+ echo >&2 "$0: -u '$2': too many fields"
+ exit 1;;
+ *"$t"*"$t"*)
+ ;;
+ *)
+ echo >&2 "$0: -u '$2': not enough fields"
+ exit 1
+ esac
+ loginFullnameMailaddrs=$loginFullnameMailaddrs$nl$2
+ shift
+ esac
+ logins=$logins$nl$login
+ ;;
+ -r) rlog_options=$rlog_options$nl${2?}; shift;;
+ -R) recursive=t;;
+ -t) tabwidth=${2?}; shift;;
+ -*) echo >&2 "$0: usage: $0 [options] [file ...]
+Options:
+ [-h hostname] [-i indent] [-l length] [-R] [-r rlog_option]
+ [-t tabwidth] [-u 'login<TAB>fullname<TAB>mailaddr']..."
+ exit 1;;
+ *) break
+ esac
+ shift
+done
+
+month_data='
+ m[0]="Jan"; m[1]="Feb"; m[2]="Mar"
+ m[3]="Apr"; m[4]="May"; m[5]="Jun"
+ m[6]="Jul"; m[7]="Aug"; m[8]="Sep"
+ m[9]="Oct"; m[10]="Nov"; m[11]="Dec"
+
+ # days in non-leap year thus far, indexed by month (0-12)
+ mo[0]=0; mo[1]=31; mo[2]=59; mo[3]=90
+ mo[4]=120; mo[5]=151; mo[6]=181; mo[7]=212
+ mo[8]=243; mo[9]=273; mo[10]=304; mo[11]=334
+ mo[12]=365
+'
+
+
+# Put rlog output into $rlogout.
+
+# If no rlog options are given,
+# log the revisions checked in since the first ChangeLog entry.
+case $rlog_options in
+'')
+ date=1970
+ if test -s ChangeLog
+ then
+ # Add 1 to seconds to avoid duplicating most recent log.
+ e='
+ /^... ... [ 0-9][0-9] [ 0-9][0-9]:[0-9][0-9]:[0-9][0-9] [0-9]+ /{
+ '"$month_data"'
+ year = $5
+ for (i=0; i<=11; i++) if (m[i] == $2) break
+ dd = $3
+ hh = substr($0,12,2)
+ mm = substr($0,15,2)
+ ss = substr($0,18,2)
+ ss++
+ if (ss == 60) {
+ ss = 0
+ mm++
+ if (mm == 60) {
+ mm = 0
+ hh++
+ if (hh == 24) {
+ hh = 0
+ dd++
+ monthdays = mo[i+1] - mo[i]
+ if (i == 1 && year%4 == 0 && (year%100 != 0 || year%400 == 0)) monthdays++
+ if (dd == monthdays + 1) {
+ dd = 1
+ i++
+ if (i == 12) {
+ i = 0
+ year++
+ }
+ }
+ }
+ }
+ }
+ # Output comma instead of space to avoid CVS 1.5 bug.
+ printf "%d/%02d/%02d,%02d:%02d:%02d\n", year,i+1,dd,hh,mm,ss
+ exit
+ }
+ '
+ d=`$AWK "$e" <ChangeLog` || exit
+ case $d in
+ ?*) date=$d
+ esac
+ fi
+ datearg="-d>$date"
+esac
+
+# If CVS is in use, examine its repository, not the normal RCS files.
+if test ! -f CVS/Repository
+then
+ rlog=rlog
+ repository=
+else
+ rlog='cvs log'
+ repository=`sed 1q <CVS/Repository` || exit
+ test ! -f CVS/Root || CVSROOT=`cat <CVS/Root` || exit
+ case $CVSROOT in
+ *:/*)
+ # remote repository
+ ;;
+ *)
+ # local repository
+ case $repository in
+ /*) ;;
+ *) repository=${CVSROOT?}/$repository
+ esac
+ if test ! -d "$repository"
+ then
+ echo >&2 "$0: $repository: bad repository (see CVS/Repository)"
+ exit 1
+ fi
+ esac
+fi
+
+# With no arguments, examine all files under the RCS directory.
+case $# in
+0)
+ case $repository in
+ '')
+ oldIFS=$IFS
+ IFS=$nl
+ case $recursive in
+ t)
+ RCSdirs=`find . -name RCS -type d -print`
+ filesFromRCSfiles='s|,v$||; s|/RCS/|/|; s|^\./||'
+ files=`
+ {
+ case $RCSdirs in
+ ?*) find $RCSdirs -type f -print
+ esac
+ find . -name '*,v' -print
+ } |
+ sort -u |
+ sed "$filesFromRCSfiles"
+ `;;
+ *)
+ files=
+ for file in RCS/.* RCS/* .*,v *,v
+ do
+ case $file in
+ RCS/. | RCS/..) continue;;
+ RCS/.\* | RCS/\* | .\*,v | \*,v) test -f "$file" || continue
+ esac
+ files=$files$nl$file
+ done
+ case $files in
+ '') exit 0
+ esac
+ esac
+ set x $files
+ shift
+ IFS=$oldIFS
+ esac
+esac
+
+llogout=$TMPDIR/rcs2log$$l
+rlogout=$TMPDIR/rcs2log$$r
+trap exit 1 2 13 15
+trap "rm -f $llogout $rlogout; exit 1" 0
+
+case $rlog_options in
+?*) $rlog $rlog_options ${1+"$@"} >$rlogout;;
+'') $rlog "$datearg" ${1+"$@"} >$rlogout
+esac || exit
+
+
+# Get the full name of each author the logs mention, and set initialize_fullname
+# to awk code that initializes the `fullname' awk associative array.
+# Warning: foreign authors (i.e. not known in the passwd file) are mishandled;
+# you have to fix the resulting output by hand.
+
+initialize_fullname=
+initialize_mailaddr=
+
+case $loginFullnameMailaddrs in
+?*)
+ case $loginFullnameMailaddrs in
+ *\"* | *\\*)
+ sed 's/["\\]/\\&/g' >$llogout <<EOF || exit
+$loginFullnameMailaddrs
+EOF
+ loginFullnameMailaddrs=`cat $llogout`
+ esac
+
+ oldIFS=$IFS
+ IFS=$nl
+ for loginFullnameMailaddr in $loginFullnameMailaddrs
+ do
+ case $loginFullnameMailaddr in
+ *"$tab"*) IFS=$tab;;
+ *) IFS=:
+ esac
+ set x $loginFullnameMailaddr
+ login=$2
+ fullname=$3
+ mailaddr=$4
+ initialize_fullname="$initialize_fullname
+ fullname[\"$login\"] = \"$fullname\""
+ initialize_mailaddr="$initialize_mailaddr
+ mailaddr[\"$login\"] = \"$mailaddr\""
+ done
+ IFS=$oldIFS
+esac
+
+case $llogout in
+?*) sort -u -o $llogout <<EOF || exit
+$logins
+EOF
+esac
+output_authors='/^date: / {
+ if ($2 ~ /^[0-9]*[-\/][0-9][0-9][-\/][0-9][0-9]$/ && $3 ~ /^[0-9][0-9]:[0-9][0-9]:[0-9][0-9][-+0-9:]*;$/ && $4 == "author:" && $5 ~ /^[^;]*;$/) {
+ print substr($5, 1, length($5)-1)
+ }
+}'
+authors=`
+ $AWK "$output_authors" <$rlogout |
+ case $llogout in
+ '') sort -u;;
+ ?*) sort -u | comm -23 - $llogout
+ esac
+`
+case $authors in
+?*)
+ cat >$llogout <<EOF || exit
+$authors
+EOF
+ initialize_author_script='s/["\\]/\\&/g; s/.*/author[\"&\"] = 1/'
+ initialize_author=`sed -e "$initialize_author_script" <$llogout`
+ awkscript='
+ BEGIN {
+ alphabet = "abcdefghijklmnopqrstuvwxyz"
+ ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ '"$initialize_author"'
+ }
+ {
+ if (author[$1]) {
+ fullname = $5
+ if (fullname ~ /[0-9]+-[^(]*\([0-9]+\)$/) {
+ # Remove the junk from fullnames like "0000-Admin(0000)".
+ fullname = substr(fullname, index(fullname, "-") + 1)
+ fullname = substr(fullname, 1, index(fullname, "(") - 1)
+ }
+ if (fullname ~ /,[^ ]/) {
+ # Some sites put comma-separated junk after the fullname.
+ # Remove it, but leave "Bill Gates, Jr" alone.
+ fullname = substr(fullname, 1, index(fullname, ",") - 1)
+ }
+ abbr = index(fullname, "&")
+ if (abbr) {
+ a = substr($1, 1, 1)
+ A = a
+ i = index(alphabet, a)
+ if (i) A = substr(ALPHABET, i, 1)
+ fullname = substr(fullname, 1, abbr-1) A substr($1, 2) substr(fullname, abbr+1)
+ }
+
+ # Quote quotes and backslashes properly in full names.
+ # Do not use gsub; traditional awk lacks it.
+ quoted = ""
+ rest = fullname
+ for (;;) {
+ p = index(rest, "\\")
+ q = index(rest, "\"")
+ if (p) {
+ if (q && q<p) p = q
+ } else {
+ if (!q) break
+ p = q
+ }
+ quoted = quoted substr(rest, 1, p-1) "\\" substr(rest, p, 1)
+ rest = substr(rest, p+1)
+ }
+
+ printf "fullname[\"%s\"] = \"%s%s\"\n", $1, quoted, rest
+ author[$1] = 0
+ }
+ }
+ '
+
+ initialize_fullname=`
+ (cat /etc/passwd; ypmatch $authors passwd) 2>/dev/null |
+ $AWK -F: "$awkscript"
+ `$initialize_fullname
+esac
+
+
+# Function to print a single log line.
+# We don't use awk functions, to stay compatible with old awk versions.
+# `Log' is the log message (with \n replaced by \r).
+# `files' contains the affected files.
+printlogline='{
+
+ # Following the GNU coding standards, rewrite
+ # * file: (function): comment
+ # to
+ # * file (function): comment
+ if (Log ~ /^\([^)]*\): /) {
+ i = index(Log, ")")
+ files = files " " substr(Log, 1, i)
+ Log = substr(Log, i+3)
+ }
+
+ # If "label: comment" is too long, break the line after the ":".
+ sep = " "
+ if ('"$length"' <= '"$indent"' + 1 + length(files) + index(Log, CR)) sep = "\n" indent_string
+
+ # Print the label.
+ printf "%s*%s:", indent_string, files
+
+ # Print each line of the log, transliterating \r to \n.
+ while ((i = index(Log, CR)) != 0) {
+ logline = substr(Log, 1, i-1)
+ if (logline ~ /[^'"$tab"' ]/) {
+ printf "%s%s\n", sep, logline
+ } else {
+ print ""
+ }
+ sep = indent_string
+ Log = substr(Log, i+1)
+ }
+}'
+
+case $hostname in
+'')
+ hostname=`(
+ hostname || uname -n || uuname -l || cat /etc/whoami
+ ) 2>/dev/null` || {
+ echo >&2 "$0: cannot deduce hostname"
+ exit 1
+ }
+esac
+
+
+# Process the rlog output, generating ChangeLog style entries.
+
+# First, reformat the rlog output so that each line contains one log entry.
+# Transliterate \n to \r so that multiline entries fit on a single line.
+# Discard irrelevant rlog output.
+$AWK <$rlogout '
+ BEGIN { repository = "'"$repository"'" }
+ /^RCS file:/ {
+ if (repository != "") {
+ filename = $3
+ if (substr(filename, 1, length(repository) + 1) == repository "/") {
+ filename = substr(filename, length(repository) + 2)
+ }
+ if (filename ~ /,v$/) {
+ filename = substr(filename, 1, length(filename) - 2)
+ }
+ }
+ }
+ /^Working file:/ { if (repository == "") filename = $3 }
+ /^date: /, /^(-----------*|===========*)$/ {
+ if ($0 ~ /^branches: /) { next }
+ if ($0 ~ /^date: [0-9][- +\/0-9:]*;/) {
+ date = $2
+ if (date ~ /-/) {
+ # An ISO format date. Replace all "-"s with "/"s.
+ newdate = ""
+ while ((i = index(date, "-")) != 0) {
+ newdate = newdate substr(date, 1, i-1) "/"
+ date = substr(date, i+1)
+ }
+ date = newdate date
+ }
+ # Ignore any time zone; ChangeLog has no room for it.
+ time = substr($3, 1, 8)
+ author = substr($5, 1, length($5)-1)
+ printf "%s %s %s %s %c", filename, date, time, author, 13
+ next
+ }
+ if ($0 ~ /^(-----------*|===========*)$/) { print ""; next }
+ printf "%s%c", $0, 13
+ }
+' |
+
+# Now each line is of the form
+# FILENAME YYYY/MM/DD HH:MM:SS AUTHOR \rLOG
+# where \r stands for a carriage return,
+# and each line of the log is terminated by \r instead of \n.
+# Sort the log entries, first by date+time (in reverse order),
+# then by author, then by log entry, and finally by file name (just in case).
+sort +1 -3r +3 +0 |
+
+# Finally, reformat the sorted log entries.
+$AWK '
+ BEGIN {
+ # Some awk variants do not understand "\r" or "\013", so we have to
+ # put a carriage return directly in the file.
+ CR=" " # <-- There is a single CR between the " chars here.
+
+ # Initialize the fullname and mailaddr associative arrays.
+ '"$initialize_fullname"'
+ '"$initialize_mailaddr"'
+
+ # Initialize indent string.
+ indent_string = ""
+ i = '"$indent"'
+ if (0 < '"$tabwidth"')
+ for (; '"$tabwidth"' <= i; i -= '"$tabwidth"')
+ indent_string = indent_string "\t"
+ while (1 <= i--)
+ indent_string = indent_string " "
+
+ # Set up date conversion tables.
+ # RCS uses a nice, clean, sortable format,
+ # but ChangeLog wants the traditional, ugly ctime format.
+
+ # January 1, 0 AD (Gregorian) was Saturday = 6
+ EPOCH_WEEKDAY = 6
+ # Of course, there was no 0 AD, but the algorithm works anyway.
+
+ w[0]="Sun"; w[1]="Mon"; w[2]="Tue"; w[3]="Wed"
+ w[4]="Thu"; w[5]="Fri"; w[6]="Sat"
+
+ '"$month_data"'
+ }
+
+ {
+ newlog = substr($0, 1 + index($0, CR))
+
+ # Ignore log entries prefixed by "#".
+ if (newlog ~ /^#/) { next }
+
+ if (Log != newlog || date != $2 || author != $4) {
+
+ # The previous log and this log differ.
+
+ # Print the old log.
+ if (date != "") '"$printlogline"'
+
+ # Logs that begin with "{clumpname} " should be grouped together,
+ # and the clumpname should be removed.
+ # Extract the new clumpname from the log header,
+ # and use it to decide whether to output a blank line.
+ newclumpname = ""
+ sep = "\n"
+ if (date == "") sep = ""
+ if (newlog ~ /^\{[^'"$tab"' }]*}['"$tab"' ]/) {
+ i = index(newlog, "}")
+ newclumpname = substr(newlog, 1, i)
+ while (substr(newlog, i+1) ~ /^['"$tab"' ]/) i++
+ newlog = substr(newlog, i+1)
+ if (clumpname == newclumpname) sep = ""
+ }
+ printf sep
+ clumpname = newclumpname
+
+ # Get ready for the next log.
+ Log = newlog
+ if (files != "")
+ for (i in filesknown)
+ filesknown[i] = 0
+ files = ""
+ }
+ if (date != $2 || author != $4) {
+ # The previous date+author and this date+author differ.
+ # Print the new one.
+ date = $2
+ author = $4
+
+ # Convert nice RCS date like "1992/01/03 00:03:44"
+ # into ugly ctime date like "Fri Jan 3 00:03:44 1992".
+ # Calculate day of week from Gregorian calendar.
+ i = index($2, "/")
+ year = substr($2, 1, i-1) + 0
+ monthday = substr($2, i+1)
+ i = index(monthday, "/")
+ month = substr(monthday, 1, i-1) + 0
+ day = substr(monthday, i+1) + 0
+ leap = 0
+ if (2 < month && year%4 == 0 && (year%100 != 0 || year%400 == 0)) leap = 1
+ days_since_Sunday_before_epoch = EPOCH_WEEKDAY + year * 365 + int((year + 3) / 4) - int((year + 99) / 100) + int((year + 399) / 400) + mo[month-1] + leap + day - 1
+
+ # Print "date fullname (email address)".
+ # Get fullname and email address from associative arrays;
+ # default to author and author@hostname if not in arrays.
+ if (fullname[author])
+ auth = fullname[author]
+ else
+ auth = author
+ printf "%s %s %2d %s %d %s ", w[days_since_Sunday_before_epoch%7], m[month-1], day, $3, year, auth
+ if (mailaddr[author])
+ printf "<%s>\n\n", mailaddr[author]
+ else
+ printf "<%s@%s>\n\n", author, "'"$hostname"'"
+ }
+ if (! filesknown[$1]) {
+ filesknown[$1] = 1
+ if (files == "") files = " " $1
+ else files = files ", " $1
+ }
+ }
+ END {
+ # Print the last log.
+ if (date != "") {
+ '"$printlogline"'
+ printf "\n"
+ }
+ }
+' &&
+
+
+# Exit successfully.
+
+exec rm -f $llogout $rlogout
diff --git a/gnu/usr.bin/cvs/contrib/rcs2sccs.sh b/gnu/usr.bin/cvs/contrib/rcs2sccs.sh
new file mode 100644
index 0000000..af70138
--- /dev/null
+++ b/gnu/usr.bin/cvs/contrib/rcs2sccs.sh
@@ -0,0 +1,143 @@
+#! /bin/sh
+#
+#
+# OrigId: rcs2sccs,v 1.12 90/10/04 20:52:23 kenc Exp Locker: kenc
+# $Id: rcs2sccs.sh,v 1.1 1995/07/10 02:26:45 kfogel Exp $
+
+############################################################
+# Error checking
+#
+if [ ! -d SCCS ] ; then
+ mkdir SCCS
+fi
+
+logfile=/tmp/rcs2sccs_$$_log
+rm -f $logfile
+tmpfile=/tmp/rcs2sccs_$$_tmp
+rm -f $tmpfile
+emptyfile=/tmp/rcs2sccs_$$_empty
+echo -n "" > $emptyfile
+initialfile=/tmp/rcs2sccs_$$_init
+echo "Initial revision" > $initialfile
+sedfile=/tmp/rcs2sccs_$$_sed
+rm -f $sedfile
+revfile=/tmp/rcs2sccs_$$_rev
+rm -f $revfile
+commentfile=/tmp/rcs2sccs_$$_comment
+rm -f $commentfile
+
+# create the sed script
+cat > $sedfile << EOF
+s,;Id;,%Z%%M% %I% %E%,g
+s,;SunId;,%Z%%M% %I% %E%,g
+s,;RCSfile;,%M%,g
+s,;Revision;,%I%,g
+s,;Date;,%E%,g
+s,;Id:.*;,%Z%%M% %I% %E%,g
+s,;SunId:.*;,%Z%%M% %I% %E%,g
+s,;RCSfile:.*;,%M%,g
+s,;Revision:.*;,%I%,g
+s,;Date:.*;,%E%,g
+EOF
+sed -e 's/;/\\$/g' $sedfile > $tmpfile
+cp $tmpfile $sedfile
+############################################################
+# Loop over every RCS file in RCS dir
+#
+for vfile in *,v; do
+ # get rid of the ",v" at the end of the name
+ file=`echo $vfile | sed -e 's/,v$//'`
+
+ # work on each rev of that file in ascending order
+ firsttime=1
+ rlog $file | grep "^revision [0-9][0-9]*\." | awk '{print $2}' | sed -e 's/\./ /g' | sort -n -u +0 +1 +2 +3 +4 +5 +6 +7 +8 | sed -e 's/ /./g' > $revfile
+ for rev in `cat $revfile`; do
+ if [ $? != 0 ]; then
+ echo ERROR - revision
+ exit
+ fi
+ # get file into current dir and get stats
+ date=`rlog -r$rev $file | grep "^date: " | awk '{print $2; exit}' | sed -e 's/^19//'`
+ time=`rlog -r$rev $file | grep "^date: " | awk '{print $3; exit}' | sed -e 's/;//'`
+ author=`rlog -r$rev $file | grep "^date: " | awk '{print $5; exit}' | sed -e 's/;//'`
+ date="$date $time"
+ echo ""
+ rlog -r$rev $file | sed -e '/^branches: /d' -e '1,/^date: /d' -e '/^===========/d' -e 's/$/\\/' | awk '{if ((total += length($0) + 1) < 510) print $0}' > $commentfile
+ echo "==> file $file, rev=$rev, date=$date, author=$author"
+ rm -f $file
+ co -r$rev $file >> $logfile 2>&1
+ if [ $? != 0 ]; then
+ echo ERROR - co
+ exit
+ fi
+ echo checked out of RCS
+
+ # add SCCS keywords in place of RCS keywords
+ sed -f $sedfile $file > $tmpfile
+ if [ $? != 0 ]; then
+ echo ERROR - sed
+ exit
+ fi
+ echo performed keyword substitutions
+ rm -f $file
+ cp $tmpfile $file
+
+ # check file into SCCS
+ if [ "$firsttime" = "1" ]; then
+ firsttime=0
+ echo about to do sccs admin
+ echo sccs admin -n -i$file $file < $commentfile
+ sccs admin -n -i$file $file < $commentfile >> $logfile 2>&1
+ if [ $? != 0 ]; then
+ echo ERROR - sccs admin
+ exit
+ fi
+ echo initial rev checked into SCCS
+ else
+ case $rev in
+ *.*.*.*)
+ brev=`echo $rev | sed -e 's/\.[0-9]*$//'`
+ sccs admin -fb $file 2>>$logfile
+ echo sccs get -e -p -r$brev $file
+ sccs get -e -p -r$brev $file >/dev/null 2>>$logfile
+ ;;
+ *)
+ echo sccs get -e -p $file
+ sccs get -e -p $file >/dev/null 2>> $logfile
+ ;;
+ esac
+ if [ $? != 0 ]; then
+ echo ERROR - sccs get
+ exit
+ fi
+ sccs delta $file < $commentfile >> $logfile 2>&1
+ if [ $? != 0 ]; then
+ echo ERROR - sccs delta -r$rev $file
+ exit
+ fi
+ echo checked into SCCS
+ fi
+ sed -e "s;^d D $rev ../../.. ..:..:.. [^ ][^ ]*;d D $rev $date $author;" SCCS/s.$file > $tmpfile
+ rm -f SCCS/s.$file
+ cp $tmpfile SCCS/s.$file
+ chmod 444 SCCS/s.$file
+ sccs admin -z $file
+ if [ $? != 0 ]; then
+ echo ERROR - sccs admin -z
+ exit
+ fi
+ done
+ rm -f $file
+done
+
+
+############################################################
+# Clean up
+#
+echo cleaning up...
+rm -f $tmpfile $emptyfile $initialfile $sedfile $commentfile
+echo ===================================================
+echo " Conversion Completed Successfully"
+echo ===================================================
+
+rm -f *,v
diff --git a/gnu/usr.bin/cvs/contrib/rcslock.pl b/gnu/usr.bin/cvs/contrib/rcslock.pl
new file mode 100644
index 0000000..01e349f
--- /dev/null
+++ b/gnu/usr.bin/cvs/contrib/rcslock.pl
@@ -0,0 +1,235 @@
+#! xPERL_PATHx
+# -*-Perl-*-
+
+# Author: John Rouillard (rouilj@cs.umb.edu)
+# Supported: Yeah right. (Well what do you expect for 2 hours work?)
+# Blame-to: rouilj@cs.umb.edu
+# Complaints to: Anybody except Brian Berliner, he's blameless for
+# this script.
+# Acknowlegements: The base code for this script has been acquired
+# from the log.pl script.
+
+# rcslock.pl - A program to prevent commits when a file to be ckecked
+# in is locked in the repository.
+
+# There are times when you need exclusive access to a file. This
+# often occurs when binaries are checked into the repository, since
+# cvs's (actually rcs's) text based merging mechanism won't work. This
+# script allows you to use the rcs lock mechanism (rcs -l) to make
+# sure that no changes to a repository are able to be committed if
+# those changes would result in a locked file being changed.
+
+# WARNING:
+# This script will work only if locking is set to strict.
+#
+
+# Setup:
+# Add the following line to the commitinfo file:
+
+# ALL /local/location/for/script/lockcheck [options]
+
+# Where ALL is replaced by any suitable regular expression.
+# Options are -v for verbose info, or -d for debugging info.
+# The %s will provide the repository directory name and the names of
+# all changed files.
+
+# Use:
+# When a developer needs exclusive access to a version of a file, s/he
+# should use "rcs -l" in the repository tree to lock the version they
+# are working on. CVS will automagically release the lock when the
+# commit is performed.
+
+# Method:
+# An "rlog -h" is exec'ed to give info on all about to be
+# committed files. This (header) information is parsed to determine
+# if any locks are outstanding and what versions of the file are
+# locked. This filename, version number info is used to index an
+# associative array. All of the files to be committed are checked to
+# see if any locks are outstanding. If locks are outstanding, the
+# version number of the current file (taken from the CVS/Entries
+# subdirectory) is used in the key to determine if that version is
+# locked. If the file being checked in is locked by the person doing
+# the checkin, the commit is allowed, but if the lock is held on that
+# version of a file by another person, the commit is not allowed.
+
+$ext = ",v"; # The extension on your rcs files.
+
+$\="\n"; # I hate having to put \n's at the end of my print statements
+$,=' '; # Spaces should occur between arguments to print when printed
+
+# turn off setgid
+#
+$) = $(;
+
+#
+# parse command line arguments
+#
+require 'getopts.pl';
+
+&Getopts("vd"); # verbose or debugging
+
+# Verbose is useful when debugging
+$opt_v = $opt_d if defined $opt_d;
+
+# $files[0] is really the name of the subdirectory.
+# @files = split(/ /,$ARGV[0]);
+@files = @ARGV[0..$#ARGV];
+$cvsroot = $ENV{'CVSROOT'};
+
+#
+# get login name
+#
+$login = getlogin || (getpwuid($<))[0] || "nobody";
+
+#
+# save the current directory since we have to return here to parse the
+# CVS/Entries file if a lock is found.
+#
+$pwd = `/bin/pwd`;
+chop $pwd;
+
+print "Starting directory is $pwd" if defined $opt_d ;
+
+#
+# cd to the repository directory and check on the files.
+#
+print "Checking directory ", $files[0] if defined $opt_v ;
+
+if ( $files[0] =~ /^\// )
+{
+ print "Directory path is $files[0]" if defined $opt_d ;
+ chdir $files[0] || die "Can't change to repository directory $files[0]" ;
+}
+else
+{
+ print "Directory path is $cvsroot/$files[0]" if defined $opt_d ;
+ chdir ($cvsroot . "/" . $files[0]) ||
+ die "Can't change to repository directory $files[0] in $cvsroot" ;
+}
+
+
+# Open the rlog process and apss all of the file names to that one
+# process to cut down on exec overhead. This may backfire if there
+# are too many files for the system buffer to handle, but if there are
+# that many files, chances are that the cvs repository is not set up
+# cleanly.
+
+print "opening rlog -h @files[1..$#files] |" if defined $opt_d;
+
+open( RLOG, "rlog -h @files[1..$#files] |") || die "Can't run rlog command" ;
+
+# Create the locks associative array. The elements in the array are
+# of two types:
+#
+# The name of the RCS file with a value of the total number of locks found
+# for that file,
+# or
+#
+# The name of the rcs file concatenated with the version number of the lock.
+# The value of this element is the name of the locker.
+
+# The regular expressions used to split the rcs info may have to be changed.
+# The current ones work for rcs 5.6.
+
+$lock = 0;
+
+while (<RLOG>)
+{
+ chop;
+ next if /^$/; # ditch blank lines
+
+ if ( $_ =~ /^RCS file: (.*)$/ )
+ {
+ $curfile = $1;
+ next;
+ }
+
+ if ( $_ =~ /^locks: strict$/ )
+ {
+ $lock = 1 ;
+ next;
+ }
+
+ if ( $lock )
+ {
+ # access list: is the line immediately following the list of locks.
+ if ( /^access list:/ )
+ { # we are done getting lock info for this file.
+ $lock = 0;
+ }
+ else
+ { # We are accumulating lock info.
+
+ # increment the lock count
+ $locks{$curfile}++;
+ # save the info on the version that is locked. $2 is the
+ # version number $1 is the name of the locker.
+ $locks{"$curfile" . "$2"} = $1
+ if /[ ]*([a-zA-Z._]*): ([0-9.]*)$/;
+
+ print "lock by $1 found on $curfile version $2" if defined $opt_d;
+
+ }
+ }
+}
+
+# Lets go back to the starting directory and see if any locked files
+# are ones we are interested in.
+
+chdir $pwd;
+
+# fo all of the file names (remember $files[0] is the directory name
+foreach $i (@files[1..$#files])
+{
+ if ( defined $locks{$i . $ext} )
+ { # well the file has at least one lock outstanding
+
+ # find the base version number of our file
+ &parse_cvs_entry($i,*entry);
+
+ # is our version of this file locked?
+ if ( defined $locks{$i . $ext . $entry{"version"}} )
+ { # if so, it is by us?
+ if ( $login ne ($by = $locks{$i . $ext . $entry{"version"}}) )
+ {# crud somebody else has it locked.
+ $outstanding_lock++ ;
+ print "$by has file $i locked for version " , $entry{"version"};
+ }
+ else
+ { # yeah I have it locked.
+ print "You have a lock on file $i for version " , $entry{"version"}
+ if defined $opt_v;
+ }
+ }
+ }
+}
+
+exit $outstanding_lock;
+
+
+### End of main program
+
+sub parse_cvs_entry
+{ # a very simple minded hack at parsing an entries file.
+local ( $file, *entry ) = @_;
+local ( @pp );
+
+
+open(ENTRIES, "< CVS/Entries") || die "Can't open entries file";
+
+while (<ENTRIES>)
+ {
+ if ( $_ =~ /^\/$file\// )
+ {
+ @pp = split('/');
+
+ $entry{"name"} = $pp[1];
+ $entry{"version"} = $pp[2];
+ $entry{"dates"} = $pp[3];
+ $entry{"name"} = $pp[4];
+ $entry{"name"} = $pp[5];
+ $entry{"sticky"} = $pp[6];
+ return;
+ }
+ }
+}
diff --git a/gnu/usr.bin/cvs/contrib/sccs2rcs.csh b/gnu/usr.bin/cvs/contrib/sccs2rcs.csh
new file mode 100644
index 0000000..0f31893
--- /dev/null
+++ b/gnu/usr.bin/cvs/contrib/sccs2rcs.csh
@@ -0,0 +1,277 @@
+#! xCSH_PATHx -f
+#
+# Sccs2rcs is a script to convert an existing SCCS
+# history into an RCS history without losing any of
+# the information contained therein.
+# It has been tested under the following OS's:
+# SunOS 3.5, 4.0.3, 4.1
+# Ultrix-32 2.0, 3.1
+#
+# Things to note:
+# + It will NOT delete or alter your ./SCCS history under any circumstances.
+#
+# + Run in a directory where ./SCCS exists and where you can
+# create ./RCS
+#
+# + /usr/local/bin is put in front of the default path.
+# (SCCS under Ultrix is set-uid sccs, bad bad bad, so
+# /usr/local/bin/sccs here fixes that)
+#
+# + Date, time, author, comments, branches, are all preserved.
+#
+# + If a command fails somewhere in the middle, it bombs with
+# a message -- remove what it's done so far and try again.
+# "rm -rf RCS; sccs unedit `sccs tell`; sccs clean"
+# There is no recovery and exit is far from graceful.
+# If a particular module is hanging you up, consider
+# doing it separately; move it from the current area so that
+# the next run will have a better chance or working.
+# Also (for the brave only) you might consider hacking
+# the s-file for simpler problems: I've successfully changed
+# the date of a delta to be in sync, then run "sccs admin -z"
+# on the thing.
+#
+# + After everything finishes, ./SCCS will be moved to ./old-SCCS.
+#
+# This file may be copied, processed, hacked, mutilated, and
+# even destroyed as long as you don't tell anyone you wrote it.
+#
+# Ken Cox
+# Viewlogic Systems, Inc.
+# kenstir@viewlogic.com
+# ...!harvard!cg-atla!viewlog!kenstir
+#
+# Various hacks made by Brian Berliner before inclusion in CVS contrib area.
+#
+# $Id: sccs2rcs.csh,v 1.1 1995/07/10 02:26:48 kfogel Exp $
+
+
+#we'll assume the user set up the path correctly
+# for the Pmax, /usr/ucb/sccs is suid sccs, what a pain
+# /usr/local/bin/sccs should override /usr/ucb/sccs there
+set path = (/usr/local/bin $path)
+
+
+############################################################
+# Error checking
+#
+if (! -w .) then
+ echo "Error: ./ not writeable by you."
+ exit 1
+endif
+if (! -d SCCS) then
+ echo "Error: ./SCCS directory not found."
+ exit 1
+endif
+set edits = (`sccs tell`)
+if ($#edits) then
+ echo "Error: $#edits file(s) out for edit...clean up before converting."
+ exit 1
+endif
+if (-d RCS) then
+ echo "Warning: RCS directory exists"
+ if (`ls -a RCS | wc -l` > 2) then
+ echo "Error: RCS directory not empty
+ exit 1
+ endif
+else
+ mkdir RCS
+endif
+
+sccs clean
+
+set logfile = /tmp/sccs2rcs_$$_log
+rm -f $logfile
+set tmpfile = /tmp/sccs2rcs_$$_tmp
+rm -f $tmpfile
+set emptyfile = /tmp/sccs2rcs_$$_empty
+echo -n "" > $emptyfile
+set initialfile = /tmp/sccs2rcs_$$_init
+echo "Initial revision" > $initialfile
+set sedfile = /tmp/sccs2rcs_$$_sed
+rm -f $sedfile
+set revfile = /tmp/sccs2rcs_$$_rev
+rm -f $revfile
+
+# the quotes surround the dollar signs to fool RCS when I check in this script
+set sccs_keywords = (\
+ '%W%[ ]*%G%'\
+ '%W%[ ]*%E%'\
+ '%W%'\
+ '%Z%%M%[ ]*%I%[ ]*%G%'\
+ '%Z%%M%[ ]*%I%[ ]*%E%'\
+ '%M%[ ]*%I%[ ]*%G%'\
+ '%M%[ ]*%I%[ ]*%E%'\
+ '%M%'\
+ '%I%'\
+ '%G%'\
+ '%E%'\
+ '%U%')
+set rcs_keywords = (\
+ '$'Id'$'\
+ '$'Id'$'\
+ '$'Id'$'\
+ '$'SunId'$'\
+ '$'SunId'$'\
+ '$'Id'$'\
+ '$'Id'$'\
+ '$'RCSfile'$'\
+ '$'Revision'$'\
+ '$'Date'$'\
+ '$'Date'$'\
+ '')
+
+
+############################################################
+# Get some answers from user
+#
+echo ""
+echo "Do you want to be prompted for a description of each"
+echo "file as it is checked in to RCS initially?"
+echo -n "(y=prompt for description, n=null description) [y] ?"
+set ans = $<
+if ((_$ans == _) || (_$ans == _y) || (_$ans == _Y)) then
+ set nodesc = 0
+else
+ set nodesc = 1
+endif
+echo ""
+echo "The default keyword substitutions are as follows and are"
+echo "applied in the order specified:"
+set i = 1
+while ($i <= $#sccs_keywords)
+# echo ' '\"$sccs_keywords[$i]\"' ==> '\"$rcs_keywords[$i]\"
+ echo " $sccs_keywords[$i] ==> $rcs_keywords[$i]"
+ @ i = $i + 1
+end
+echo ""
+echo -n "Do you want to change them [n] ?"
+set ans = $<
+if ((_$ans != _) && (_$ans != _n) && (_$ans != _N)) then
+ echo "You can't always get what you want."
+ echo "Edit this script file and change the variables:"
+ echo ' $sccs_keywords'
+ echo ' $rcs_keywords'
+else
+ echo "good idea."
+endif
+
+# create the sed script
+set i = 1
+while ($i <= $#sccs_keywords)
+ echo "s,$sccs_keywords[$i],$rcs_keywords[$i],g" >> $sedfile
+ @ i = $i + 1
+end
+
+onintr ERROR
+
+############################################################
+# Loop over every s-file in SCCS dir
+#
+foreach sfile (SCCS/s.*)
+ # get rid of the "s." at the beginning of the name
+ set file = `echo $sfile:t | sed -e "s/^..//"`
+
+ # work on each rev of that file in ascending order
+ set firsttime = 1
+ sccs prs $file | grep "^D " | awk '{print $2}' | sed -e 's/\./ /g' | sort -n -u +0 +1 +2 +3 +4 +5 +6 +7 +8 | sed -e 's/ /./g' > $revfile
+ foreach rev (`cat $revfile`)
+ if ($status != 0) goto ERROR
+
+ # get file into current dir and get stats
+ set date = `sccs prs -r$rev $file | grep "^D " | awk '{printf("19%s %s", $3, $4); exit}'`
+ set author = `sccs prs -r$rev $file | grep "^D " | awk '{print $5; exit}'`
+ echo ""
+ echo "==> file $file, rev=$rev, date=$date, author=$author"
+ sccs edit -r$rev $file >>& $logfile
+ if ($status != 0) goto ERROR
+ echo checked out of SCCS
+
+ # add RCS keywords in place of SCCS keywords
+ sed -f $sedfile $file > $tmpfile
+ if ($status != 0) goto ERROR
+ echo performed keyword substitutions
+ cp $tmpfile $file
+
+ # check file into RCS
+ if ($firsttime) then
+ set firsttime = 0
+ if ($nodesc) then
+ echo about to do ci
+ echo ci -f -r$rev -d"$date" -w$author -t$emptyfile $file
+ ci -f -r$rev -d"$date" -w$author -t$emptyfile $file < $initialfile >>& $logfile
+ if ($status != 0) goto ERROR
+ echo initial rev checked into RCS without description
+ else
+ echo ""
+ echo Enter a brief description of the file $file \(end w/ Ctrl-D\):
+ cat > $tmpfile
+ ci -f -r$rev -d"$date" -w$author -t$tmpfile $file < $initialfile >>& $logfile
+ if ($status != 0) goto ERROR
+ echo initial rev checked into RCS
+ endif
+ else
+ # get RCS lock
+ set lckrev = `echo $rev | sed -e 's/\.[0-9]*$//'`
+ if ("$lckrev" =~ [0-9]*.*) then
+ # need to lock the brach -- it is OK if the lock fails
+ rcs -l$lckrev $file >>& $logfile
+ else
+ # need to lock the trunk -- must succeed
+ rcs -l $file >>& $logfile
+ if ($status != 0) goto ERROR
+ endif
+ echo got lock
+ sccs prs -r$rev $file | grep "." > $tmpfile
+ # it's OK if grep fails here and gives status == 1
+ # put the delta message in $tmpfile
+ ed $tmpfile >>& $logfile <<EOF
+/COMMENTS
+1,.d
+w
+q
+EOF
+ ci -f -r$rev -d"$date" -w$author $file < $tmpfile >>& $logfile
+ if ($status != 0) goto ERROR
+ echo checked into RCS
+ endif
+ sccs unedit $file >>& $logfile
+ if ($status != 0) goto ERROR
+ end
+ rm -f $file
+end
+
+
+############################################################
+# Clean up
+#
+echo cleaning up...
+mv SCCS old-SCCS
+rm -f $tmpfile $emptyfile $initialfile $sedfile
+echo ===================================================
+echo " Conversion Completed Successfully"
+echo ""
+echo " SCCS history now in old-SCCS/"
+echo ===================================================
+set exitval = 0
+goto cleanup
+
+ERROR:
+foreach f (`sccs tell`)
+ sccs unedit $f
+end
+echo ""
+echo ""
+echo Danger\! Danger\!
+echo Some command exited with a non-zero exit status.
+echo Log file exists in $logfile.
+echo ""
+echo Incomplete history in ./RCS -- remove it
+echo Original unchanged history in ./SCCS
+set exitval = 1
+
+cleanup:
+# leave log file
+rm -f $tmpfile $emptyfile $initialfile $sedfile $revfile
+
+exit $exitval
diff --git a/gnu/usr.bin/cvs/cvs/ChangeLog b/gnu/usr.bin/cvs/cvs/ChangeLog
new file mode 100644
index 0000000..36c3906
--- /dev/null
+++ b/gnu/usr.bin/cvs/cvs/ChangeLog
@@ -0,0 +1,3205 @@
+Sat Dec 9 22:01:41 1995 Dan O'Connor <doconnor@tii.com>
+
+ * commit.c (check_fileproc): pass RUN_REALLY flag to run_exec,
+ because it's okay to examine the file with noexec set.
+
+Sat Dec 9 20:28:01 1995 Karl Fogel <kfogel@floss.cyclic.com>
+
+ * client.c (update_entries): new var, `bin, init to 0.
+ Use it in determining whether to convert the file.
+ (send_modified): same as above.
+
+Fri Dec 8 17:47:39 1995 Karl Fogel <kfogel@floss.cyclic.com>
+
+ * server.c (downcase_string): removed.
+ (check_repository_password): don't deal with case-insensitivity
+ anymore.
+
+ * options.h.in (CVS_PASSWORDS_CASE_SENSITIVE): deleted this. No
+ need for it anymore.
+
+Thu Dec 7 21:08:39 1995 Karl Fogel <kfogel@floss.cyclic.com>
+
+ * server.c (check_repository_password): when checking for false
+ prefix-matches, look for ':', not '@'. Duh.
+
+Thu Dec 7 18:44:51 1995 Karl Fogel <kfogel@floss.cyclic.com>
+
+ * options.h.in (CVS_PASSWORDS_CASE_SENSITIVE): replaces
+ CVS_PASSWORDS_CASE_INSENSITIVE; passwords are now insensitive by
+ default. Expanded explanatory comment.
+
+ * login.c (get_cvs_password): Use memset(), not bzero(). I
+ botched this change earlier.
+
+ * server.c (check_repository_password): no need to check
+ xmalloc()'s return value.
+ (check_repository_password): check for false prefix-matches (for
+ example, username is "theo" and linebuf contains user
+ "theocracy").
+
+Thu Dec 7 14:49:16 1995 Jim Meyering (meyering@comco.com)
+
+ * filesubr.c (isaccessible): Rename from isaccessable.
+ Update callers.
+ * cvs.h: Update prototype.
+ * main.c (main): Update callers.
+ * server.c (main): Update callers.
+
+Thu Dec 7 12:50:20 1995 Adam Glass <glass@NetBSD.ORG>
+
+ * cvs.h: "isaccessible" is the correct spelling.
+ Also add "const" to second arg to make prototype match
+ declaration.
+
+Thu Dec 7 11:06:51 1995 Karl Fogel <kfogel@floss.cyclic.com>
+
+ * client.c, login.c: memset() instead of bzero().
+
+Thu Dec 7 00:08:53 1995 Karl Fogel <kfogel@floss.cyclic.com>
+
+ * server.c (authenticate_connection): document server's side of
+ the Authentication Protocol too.
+
+ * client.c (connect_to_pserver): when printing out "unrecognized
+ response", also print out the offending response.
+
+ * server.c (check_password): take `repository' arg too now.
+ Call check_repository_password() before checking /etc/passwd.
+ (check_repository_password): new func.
+
+ * options.h.in (CVS_PASSWORDS_CASE_INSENSITIVE): new define, unset
+ by default.
+
+Wed Dec 6 18:51:16 1995 Karl Fogel <kfogel@floss.cyclic.com>
+
+ * server.c (check_password): If user has a null password, then
+ return 1 if arg is also null.
+ Reverse sense of return value. Caller changed.
+
+Wed Dec 6 14:42:57 1995 Karl Fogel <kfogel@floss.cyclic.com>
+
+ * server.c (check_password): new func.
+ (authenticate_connection): call above new func.
+
+ * login.c (login): use construct_cvspass_filename().
+ If CVSroot is not "fully-qualified", then insist the user qualify
+ it before going on.
+ (get_cvs_password): fleshed out. Now reads from ~/.cvspass, or
+ prompts if no appropriate password found.
+ (construct_cvspass_filename): new func.
+
+ * server.c (authenticate_connection): send ACK or NACK to client.
+
+ * client.c (connect_to_pserver): check for ACK vs NACK response
+ from server after sending authorization request.
+
+ * login.c (get_cvs_password): new func.
+
+ * client.c (connect_to_pserver): use new func get_cvs_password().
+ Prototype it at top of file. Hmmm.
+
+Wed Dec 6 13:29:22 1995 Karl Fogel <kfogel@floss.cyclic.com>
+
+ * server.c: same as below (AUTH_SERVER_SUPPORT).
+
+ * main.c: same as below (AUTH_SERVER_SUPPORT where appropriate).
+
+ * login.c: same same as below.
+
+ * cvs.h: same as below.
+
+ * client.c: use AUTH_CLIENT_SUPPORT, not CVS_LOGIN.
+
+ * options.h.in (AUTH_CLIENT_SUPPORT, AUTH_SERVER_SUPPORT): these
+ replace CVS_LOGIN.
+
+Wed Dec 6 00:04:58 1995 Karl Fogel <kfogel@floss.cyclic.com>
+
+ * server.c (authenticate_connection): expanded comment.
+
+Tue Dec 5 23:37:39 1995 Karl Fogel <kfogel@floss.cyclic.com>
+
+ * client.c (connect_to_pserver): read password from prompt for
+ now.
+
+ * server.c (authenticate_connection): if the password passes
+ muster, then don't abort.
+
+Tue Dec 5 22:46:37 1995 Karl Fogel <kfogel@floss.cyclic.com>
+
+ * subr.c (strip_trailing_newlines): new func.
+
+ * client.c (connect_to_pserver): took out print statements.
+
+ * server.c (authenticate_connection): removed print statments.
+ Use new func strip_trailing_newlines() to purify `repository',
+ `username', and `password'.
+ Run a primitive password check, just for testing.
+
+ * client.c (connect_to_pserver): use CVS_AUTH_PORT.
+ Take tofdp, fromfdp, and log args. Caller changed.
+ (get_responses_and_close): either kerberos and CVS_LOGIN might
+ have one fd for both directions, so adjust #ifdef accordingly.
+
+ * cvs.h (CVS_AUTH_PORT): new define, default to 2401.
+ Prototype strip_trailing_newlines().
+
+Tue Dec 5 16:53:35 1995 Karl Fogel <kfogel@floss.cyclic.com>
+
+ * server.c (authenticate_connection): new func.
+
+ * client.c (init_sockaddr): func moved here from login.c.
+ (connect_to_pserver): same as above. Take no args, now.
+ Include <sys/socket.h>, <netinet/in.h>, <netdb.h>, if CVS_LOGIN.
+
+ * cvs.h: Declare use_authenticating_server, as extern int.
+ Declare connect_to_pserver().
+
+ * main.c (main): call authenticate_connection(). Removed testing
+ code.
+ Add 'a' to the short-option string in the getopt() call.
+
+ * login.c (connect_to_pserver): moved to client.c.
+
+Tue Dec 5 16:01:42 1995 Peter Chubb <peterc@bookworm.sw.oz.au>
+ (patch applied by Karl Fogel <kfogel@cyclic.com>)
+
+ * update.c (join_file): if vers->vn_user is "0", file has been
+ removed on the current branch, so print an error and return.
+
+Mon Dec 4 14:27:42 1995 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * Version 1.6.3.
+
+Mon Dec 4 16:28:25 1995 Norbert Kiesel <nk@col.sw-ley.de>
+
+ * release.c (release): add return (0) as last line
+
+ * cvs.h: declare program_path
+
+ * main.c define program_path
+ (main): set program_path
+
+ * release.c (release): use program_path for update_cmd
+
+Mon Dec 4 11:22:42 1995 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * Version 1.6.2.
+
+Sun Dec 3 20:02:29 1995 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * rcs.h (struct rcsnode), rcs.c (freercsnode): Add expand field.
+ * rcs.h (RCSEXPAND): New #define.
+ * rcs.c (RCS_reparsercsfile): Record keyword expansion in expand
+ field of struct rcsnode.
+ * update.c (checkout_file): Set keyword expansion in Entries file
+ from rcs file if there is nowhere else to set it from.
+ * client.c (send_modified, update_entries) [LINES_CRLF_TERMINATED]:
+ If -kb is in effect, don't convert.
+
+ * update.c (update_file_proc), commit.c (check_fileproc),
+ rcscmds.c (RCS_merge): Direct stdout to DEVNULL rather than
+ passing -s option to grep. This avoids trouble with respect to
+ finding a grep which support -s and whether we should use the (GNU
+ grep) -q option if it exists.
+ * options.h.in: Change "@ggrep_path@" to "grep".
+
+Fri Dec 1 11:53:19 1995 Norbert Kiesel <nk@col.sw-ley.de>
+
+ * rcs.c (RCS_gettag): new parameter return_both force return both
+ tags: the symbolic and the numeric one.
+ (RCS_getversion): new parameter return_both is forwarded to
+ RCS_gettag.
+
+ * rtag.c, tag.c, commit.c, patch.c, update.c: pass 0 as additional
+ last parameter to RCS_getversion and RCS_gettag
+
+ * rcs.h (RCS_gettag): new parameter return_both.
+ (RCS_getversion): new parameter return_both.
+
+ * cvs.h (struct vers_ts): add vn_tag slot for symbolic tag name
+
+ * vers_ts.c (Version_TS): call RCS_getversion with 1 for
+ return_both and split output into vn_rcs and vn_tag
+ (freevers_ts): free vn_tag
+
+ * update.c (checkout_file): use vn_tag instead of vn_rcs when
+ calling 'rcs co' to allow rcs expansion of :$Name :
+
+Thu Nov 30 20:44:30 1995 Karl Fogel <kfogel@floss.cyclic.com>
+
+ * client.c (get_responses_and_close): undo previous change
+ regarding waitpid(). The problem has been solved by modifying
+ os2/waitpid.c instead of its callers.
+
+Thu Nov 30 16:37:10 1995 Karl Fogel <kfogel@floss.cyclic.com>
+
+ * client.c: All these changes are for OS/2, which will no longer have
+ a separate client.c:
+ (start_kerberos_server): new func, contains code that
+ used to be in start_server().
+ (start_server): moved kerberos code to above function, reorganized
+ the rest. Added authentication clause.
+ (call_in_directory): test errno against EACCESS, if EACCESS is
+ defined (this is for OS/2's oddball mkdir).
+ (change_mode): don't set execute permission on anything if
+ EXECUTE_PERMISSION_LOSES is defined.
+ (get_responses_and_close): if START_RSH_WITH_POPEN_RW, then use
+ pclose() instead of fclose().
+ If waitpid errors with ECHILD, don't die. This is okay.
+ (start_rsh_server): alternate definition if
+ START_RSH_WITH_POPEN_RW.
+
+ * main.c: [all these changes conditional on CVS_LOGIN: ]
+ Don't prototype connect_to_pserver, don't enter it in cmds[]
+ (actually, it was never in there, I don't know why my previous
+ change said it was).
+ (use_authenticating_server): new global var.
+ (main): if "-a", then set above new var to TRUE.
+ (usg): document "-a" option.
+
+Wed Nov 29 12:55:10 1995 Karl Fogel <kfogel@floss.cyclic.com>
+
+ * main.c: Prototype connect_to_pserver(), and enter it in cmds[].
+ (main): test some extremely primitive authentication.
+
+ * login.c: Include <sys/socket.h>
+ (connect_to_pserver): new func.
+ (init_sockaddr): new func.
+
+Mon Nov 20 14:07:41 1995 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * Makefile.in (TAGFILES): Separate out from DISTFILES, for C code.
+ (TAGS,tags): Use TAGFILES not DISTFILES.
+
+Sun Nov 19 11:22:43 1995 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * recurse.c (do_recursion): Don't call server_pause_check if there
+ are writelocks around. Revise comment to reflect fact we are no
+ longer relying on a writelock'd operations being "unable" to
+ generate enough data to pause.
+
+Sun Nov 19 10:04:50 1995 Peter Wemm <peter@haywire.DIALix.COM>
+
+ * server.c, server.h, options.h.in: Implement hooks for doing
+ simple flow control on the server to prevent VM exhaustion on a
+ slow network with a fast server.
+ * recurse.c: Call the flow control check at a convenient location
+ while no locks are active. This is a convenience tradeoff against
+ accurate flow control - if you have a large directory it will all
+ be queued up, bypassing the flow control check until the next
+ directory is processed.
+
+Sat Nov 18 16:22:06 1995 Karl Fogel <kfogel@floss.cyclic.com>
+
+ * client.c, update.c, vers_ts.c, server.c, rcs.c, lock.c,
+ ignore.c, entries.c, diff.c, commit.c, checkin.c:
+ Use new macro `existence_error', instead of comparing errno to
+ ENOENT directly.
+
+Fri Nov 17 14:56:12 1995 Karl Fogel <kfogel@floss.cyclic.com>
+
+ * client.c (start_server): removed alternate version of this func,
+ since os2/client.c will now be used under OS/2.
+
+Thu Nov 16 22:57:12 1995 Karl Fogel <kfogel@floss.cyclic.com>
+
+ * client.c (start_server): ifdef HAVE_POPEN_RW, use a different
+ version of start_server(). This is maybe not the cleanest cut to
+ make, but it's better than mucking around with yet more #ifdefs in
+ the middle of the old start_server() function. Once things are
+ up, I may reposition this code.
+
+Wed Nov 15 15:33:37 1995 Karl Fogel <kfogel@floss.cyclic.com>
+
+ * main.c (main): ifdef NEED_CALL_SOCKINIT, then call SockInit().
+ Only OS/2 needs this initialization.
+
+Tue Nov 14 18:54:01 1995 Greg A. Woods <woods@most.weird.com>
+
+ * patch.c:
+ - fix orientation of test for result of getline() call
+ - use fputs() not printf() when just copying file out
+
+ * cvsbug.sh:
+ - add space after #!
+ - new rcs id
+ - allow version to be edited by Makefile.
+
+ * Makefile.in:
+ - make Makefile a dependent of all (this might not be perfect, but
+ it at least gives you a chance to catch up on the second
+ go-around).
+ - filter cvsbug.sh in a manner similar to cvsinit.sh to get the
+ version number set from version.c
+
+Tue Nov 14 13:28:17 1995 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * sanity.sh: Call old log file check.plog, not check.olog.
+
+ * sanity.sh: Convert remaining tests from old-style ('***' on fail
+ and nothing on pass), to new-style (FAIL on fail and PASS on pass).
+
+ * sanity.sh: Fix ability to run only some of the tests (always run
+ tests 1-4.75 to set up repository, document better how it works).
+
+ * sanity.sh: Change "completed successfully" to "completed" in
+ message--many tests, but not all, exit if they fail.
+
+Tue Nov 14 15:10:00 1995 Greg A. Woods <woods@most.weird.com>
+
+ * sanity.sh: test 63 doesn't work and probably can't
+
+Tue Nov 14 12:22:00 1995 Greg A. Woods <woods@most.weird.com>
+
+ * sanity.sh: many minor tweaks:
+ - make the optional arguments almost work
+ - use a function 'directory_cmp' instead of 'diff -r'
+ - fix up a few more tests that weren't working....
+
+Mon Nov 13 07:33:55 1995 Karl Fogel <kfogel@floss.cyclic.com>
+
+ * cvs.h: ifdef USE_OWN_POPEN, #include "popen.h". Only OS/2 has
+ its own popen()/pclose() right now.
+
+Mon Nov 13 04:06:10 1995 Karl Fogel <kfogel@floss.cyclic.com>
+
+ * cvs.h: conform to 80 column standard (yes, I'm a pedant).
+
+Sat Nov 11 13:45:13 1995 Karl Fogel <kfogel@floss.cyclic.com>
+
+ * client.c (process_prune_candidates): use unlink_file_dir() to
+ remove the directory, instead of invoking "rm" via run_exec().
+
+Fri Nov 10 14:38:56 1995 Karl Fogel <kfogel@floss.cyclic.com>
+
+ * main.c (main): removed "#define KF_GETOPT_LONG 1", since that
+ change is no longer in testing.
+
+Thu Nov 9 20:32:12 1995 Karl Fogel <kfogel@floss.cyclic.com>
+
+ * release.c (release): Use Popen(), not popen().
+
+Wed Nov 8 10:20:20 1995 Jim Meyering (meyering@comco.com)
+
+ * entries.c (ParseTag): Remove dcl of unused local.
+
+ * patch.c: Include getline.h.
+
+Wed Nov 8 11:57:31 1995 Norbert Kiesel <nk@col.sw-ley.de>
+
+ * options.h.in: add configuration option STEXID_SUPPORT (default
+ is off i.e. old semantics)
+
+ * filesubr.c (isaccessable): new function. Checks access-rights
+ for files like access(), but is getxid-safe. Falls back to
+ access() if SETXID_SUPPORT is not enabled.
+ (isfile): replace stat() by isaccessable(file, F_OK)
+ (isreadable): replace access() by isaccessable()
+ (iswritable): ditto
+ (make_directory): rename local variable buf to sb
+
+ * cvs.h: add prototype for new function isaccessable.
+
+ * server.c (serve_root): replace access() by isaccessable()
+
+ * cvsrc.c (read_cvsrc): replace access() by isreadable()
+
+ * main.c (main): replace access() by isaccessable()
+
+Wed Nov 8 10:22:41 1995 Greg A. Woods <woods@most.weird.com>
+
+ * entries.c (fgetentent): change definition to static to match the
+ declaration at the top of the file
+
+Tue Nov 7 16:59:25 1995 J.T. Conklin <jtc@lestat.cygnus.com>
+
+ * rcs.c (RCS_getbranch, RCS_getdate, RCS_getrevtime, RCS_gettag,
+ RCS_getversion, RCS_head): Use assert() instead of attempting to
+ "do the right thing" with a bogus RCSNode argument.
+
+Mon Nov 6 14:24:34 1995 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * vers_ts.c: Remove ctime define. It is just asking for trouble.
+
+Mon Nov 6 11:58:26 1995 Karl Fogel <kfogel@floss.cyclic.com>
+
+ * vers_ts.c: ifdef ctime, undef it before redefining it. It is a
+ macro on some systems.
+
+ * lock.c: don't prototype ctime() here. (See note below about
+ fgetentent() in entries.c.)
+
+Sun Nov 5 16:06:01 1995 Karl Fogel <kfogel@floss.cyclic.com>
+
+ * entries.c (fgetentent): don't prototype ctime here; we include
+ cvs.h, which includes system.h, which includes <time.h>
+ unconditionally (either as <time.h> or <sys/time.h>). Anyway, IBM
+ C/C++ chokes on mid-function, or even mid-file, prototypes. Sigh.
+
+Thu Nov 2 21:51:04 1995 Dan Wilder <dan@gasboy.com>
+
+ * rtag.c (rtag): Fix typo ("-T" -> "-F").
+
+Tue Oct 31 19:09:11 1995 Dan Wilder <dan@gasboy.com>
+
+ * diff.c (diff_dirproc): just return R_SKIP_ALL if dir not exist.
+ (diff_file_nodiff): don't complain if file doesn't exist, just
+ ignore.
+
+Tue Oct 31 09:25:10 1995 Norbert Kiesel <nk@col.sw-ley.de>
+
+ * sanity.sh: Use absolute pathname for mkmodules.
+
+Sat Oct 28 01:01:41 1995 Jim Meyering (meyering@comco.com)
+
+ * entries.c (ParseTag): Use getline instead of fgets.
+
+Fri Oct 27 13:44:20 1995 Karl Fogel <kfogel@floss.cyclic.com>
+
+ * cvs.h: do nothing about alloca ifdef ALLOCA_IN_STDLIB. I am
+ rather suspicious of this solution, and will not be surprised to
+ find out that there's a Right Way to handle this situation ("this
+ situation" being that OS/2 simply declares alloca in <stdlib.h>).
+ Suggestions are welcome; see src/cvs.h and lib/system.h to see why
+ I was getting a conflict in the first place.
+
+Wed Oct 25 16:03:20 1995 J.T. Conklin <jtc@slave.cygnus.com>
+
+ * cvs.h (struct entnode): Add user field.
+ * entries.c (fputentent): New function, write entries line.
+ (write_ent_proc): Call fputentent to write entries line.
+ (Entnode_Create): New function, construct new Entnode.
+ (Entnode_Destroy): New function, destruct old Entnode.
+ (AddEntryNode): Changed to take an Entnode argument instead of
+ separate user, version, timestamp, etc. arguments.
+ (fgetentent): Changed to return Entnode.
+ (struct entent, free_entent): Removed.
+
+Wed Oct 25 12:44:32 1995 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * admin.c (admin): Don't rely on ANSI C string concatenation;
+ SunOS 4.1.3 /bin/cc doesn't support it.
+
+Tue Oct 24 22:34:22 1995 Anthony J. Lill <ajlill@ajlc.waterloo.on.ca>
+
+ * import.c (expand_at_signs): Check errno as well as return value
+ from putc. Some systems bogusly return EOF when successfully
+ writing 0xff.
+
+Tue Oct 24 14:32:45 1995 Norbert Kiesel <nk@col.sw-ley.de>
+
+ * admin.c (admin): use getcaller() instead of getpwuid
+
+ * subr.c (getcaller): prefer getlogin() to $USER and $LOGNAME
+ (especially useful for NT where getuid always returns 0)
+
+Tue Oct 24 06:22:08 1995 Jim Meyering (meyering@comco.com)
+
+ * cvsrc.c (read_cvsrc): Use getline instead of fgets.
+ * patch.c (patch_fileproc): Use getline instead of fgets.
+
+ * entries.c (fgetentent): Use getline instead of fgets.
+ Use xmalloc to allocate space for each returned entry.
+ Since LINE is no longer static, save it in struct entent.
+ (struct entent): New member, line.
+ (free_entent): New function.
+ (Entries_Open): Call it after each call to fgetentent.
+
+Tue Oct 24 11:13:15 1995 Norbert Kiesel <nk@col.sw-ley.de>
+
+ * cvs.h: Declare valloc again, but this time with the right
+ signature (also changed in libs/valloc.c)
+
+Mon Oct 23 12:17:03 1995 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * logmsg.c (do_editor): Check for errors from stdio calls.
+
+Mon Oct 23 12:37:06 1995 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.h: Don't declare valloc. Some systems (e.g. linux) declare
+ it in stdlib.h in a conflicting way.
+
+Mon Oct 23 08:41:25 1995 Jim Meyering (meyering@comco.com)
+
+ * commit.c (commit_filesdoneproc): Use getline instead of fgets.
+
+ * logmsg.c (do_editor): Use getline instead of fgets.
+ (rcsinfo_proc): Likewise.
+
+ * logmsg.c (do_editor): Lose if fclose of temp file output
+ stream fails.
+
+Mon Oct 23 11:59:41 1995 Norbert Kiesel <nk@col.sw-ley.de>
+
+ * cvs.h: add valloc declaration
+
+ * server.h: add server_cleanup prototype
+
+ * server.c: remove server_cleanup prototype
+
+ * mkmodules.c (server_cleanup): fix parameter type
+
+ * server.c: encapsulate wait_sig in #ifdef sun (it's only used in
+ code which is also encapsulated in #ifdef sun)
+
+ * rcscmds.c (RCS_deltag, RCS_lock): add definition of noerr
+ parameter
+
+ * error.c: include cvs.h instead of config.h, add USE(rcsid)
+
+ * error.c (error): fix parameter type
+
+ * update.c (join_file): encapsulate recent changes from garyo
+ within #ifdef SERVER_SUPPORT
+
+Sun Oct 22 13:47:53 1995 J.T. Conklin <jtc@slave.cygnus.com>
+
+ * client.c (update_entries): Fix memory leak; free mode_string and
+ file_timestamp.
+ (send_fileproc): Fix memory leak; call freevers_ts before exiting.
+
+ * module.c (do_module): Partially fix memory leak; added
+ variable so that the address of memory allocated by line2argv
+ is retained, but comment out the call to free_names. Freeing
+ the vector at that point loses because some of the elements
+ may be used later in the function.
+ (cat_module): fix memory leak.
+
+ * recurse.c (start_recursion): Fix memory leak; free return
+ value of Name_Repository after it has been used.
+
+Sat Oct 21 23:24:26 1995 Jim Meyering (meyering@comco.com)
+
+ * client.c (send_modified) [LINES_CRLF_TERMINATED]: Comment text
+ after #endif.
+
+Fri Oct 20 14:41:49 1995 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * sanity.sh: Add test 87a, to test for bug fixed by garyo in
+ change below.
+
+Fri Oct 20 10:59:58 1995 Gary Oberbrunner <garyo@darkstar.avs.com>
+
+ * update.c (join_file): send file back to client even if no
+ conflicts were detected, by calling Register().
+
+Fri Oct 20 10:46:45 1995 Norbert Kiesel <nk@col.sw-ley.de>
+
+ * lock.c: Add prototype for Check_Owner
+
+Thu Oct 19 16:38:14 1995 Jim Meyering (meyering@comco.com)
+
+ * lock.c (Check_Owner): Declare function `static int'.
+
+Thu Oct 19 14:58:40 1995 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * expand_path.c (expand_variable): Fix typo ('*'->'(').
+
+Thu Oct 19 14:58:40 1995 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * commit.c (commit_filesdoneproc): Check for errors from fopen,
+ fgets, and fclose.
+
+ * rcscmds.c (RCS_merge): Remove comment about rcsmerge -E.
+ Hacking CVS was never a very good solution; the situation is fixed
+ in RCS 5.7, and is documented in ../INSTALL.
+
+Thu Oct 19 15:06:15 1995 Jim Meyering (meyering@comco.com)
+
+ * filesubr.c (xchmod): Parenthesize arithmetic in operand of |
+ to placate gcc -Wall.
+
+ * expand_path.c (expand_path): Parenthesize assignments used as
+ truth values to placate gcc -Wall.
+
+ * commit.c (checkaddfile): Remove dcls of unused variables.
+ * lock.c (unlock): Remove dcl of unused variable.
+
+Thu Oct 19 14:58:40 1995 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * root.c (Create_Root): If noexec, don't create CVS/Root.
+
+Wed Oct 18 11:19:40 1995 J.T. Conklin <jtc@slave.cygnus.com>
+
+ * lock.c (unlock): Change order of comparison so that Check_Owner
+ is called only if other conditions are true. This performance
+ enhancement was broken when the AFS support was added.
+
+Wed Oct 18 12:51:33 1995 Karl Fogel <kfogel@floss.cyclic.com>
+
+ * main.c (main): check if argv[0] is "pserver" with else-if, not
+ if, since we've already asked if it's "kserver".
+
+Tue Oct 17 18:09:23 1995 Warren Jones <wjones@tc.fluke.com>
+ and Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * sanity.sh: Deal with supplying a relative cvs filename, or
+ with a cvs filename which doesn't have basename "cvs".
+
+Mon Oct 16 15:58:31 1995 Vince Demarco <vdemarco@bou.shl.com>
+
+ * parseinfo.c (Parse_Info): if the Keyword isn't ALL the current
+ version doesn't use the expanded variable, It should.
+
+Mon Oct 16 15:58:31 1995 Gary Oberbrunner <garyo@avs.com>
+ and Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * server.c (server_register): Don't pass NULL to printf if tag,
+ date, or conflict is NULL.
+
+Thu Oct 12 12:13:42 1995 Karl Fogel <kfogel@floss.cyclic.com>
+
+ * main.c (main): begin to handle "pserver"; support not complete
+ yet, however.
+
+Thu Oct 12 02:52:13 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
+
+ * expand_path.c: Don't #include <pwd.h>, since cvs.h already does,
+ and not all systems' <pwd.h>s are protected from multiple inclusion.
+ * login.c: Likewise.
+
+Wed Oct 11 15:23:24 1995 Karl Fogel <kfogel@floss.cyclic.com>
+
+ * login.c (login): handle everything correctly now.
+
+Wed Oct 11 12:02:48 1995 Norbert Kiesel <nk@col.sw-ley.de>
+
+ * rcs.c (RCS_gettag): support RCS keyword Name
+
+Tue Oct 10 19:11:16 1995 Karl Fogel <kfogel@floss.cyclic.com>
+
+ * options.h.in (CVS_LOGIN): discuss, but leave commented out.
+ The "cvs login" command is still under construction; however, the
+ repository was changing so fast that instead of creating a branch
+ and dealing with the attendant hair, I'm just developing on the
+ trunk, making sure that everything is surrounded by "#ifdef
+ CVS_LOGIN ... #endif" so I don't get in anyone's way.
+
+ * login.c: include cvs.h before checking CVS_LOGIN, so it has a
+ chance to get defined before we ask if it's defined.
+ (login): oops, use semi not comma in `for' loop init.
+
+ * Makefile.in (SOURCES, OBJECTS): include login.c, login.o.
+
+ * main.c: added protoype for login().
+ Added "login" entry to cmds[].
+ (usg): added line about "login".
+
+ * login.c: new file.
+
+Tue Oct 10 18:33:47 1995 Karl Fogel <kfogel@totoro.cyclic.com>
+
+ * Makefile.in (COMMON_OBJECTS): added error.o.
+ (OBJECTS): took error.o out; it's in COMMON_OBJECTS now.
+
+Tue Oct 10 12:02:37 1995 Thorsten Lockert <tholo@sigmasoft.com>
+
+ * cvsbug.sh: Cater to lame versions of sh (4.4BSD ash) by using
+ ${foo-bar} instead of `if....`.
+
+Tue Oct 10 12:02:37 1995 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * remove.c (remove_fileproc): If noexec, don't remove file. Check
+ for error when removing file.
+
+Sun Oct 8 12:32:15 1995 Peter Wemm <peter@haywire.DIALix.COM>
+
+ * run.c: detect/use POSIX/BSD style reliable signals for critical
+ section masking etc. Helps prevent stray locks on interruption.
+
+Sat Oct 7 23:26:54 1995 Norbert Kiesel <nk@col.sw-ley.de>
+
+ * admin.c (admin): If group CVS_ADMIN_GROUP exists, allow only
+ users in that group to use "cvs admin".
+ * options.h.in: Default CVS_ADMIN_GROUP to "cvsadmin".
+
+Sat Oct 7 23:05:24 1995 Norbert Kiesel <nk@col.sw-ley.de>
+
+ * add.c, checkout.c, commit.c, cvs.h, filesubr.c, import.c,
+ lock.c, main.c, modules.c, options.h.in: New variable cvsumask
+ which is used to set mode of files in repository (regardless of
+ umask in effect when cvs is run).
+
+Sat Oct 7 22:40:17 1995 Stephen Bailey <sjbailey@sand.npl.washington.edu>
+
+ * lock.c: Include AFSCVS ifdefs to deal with AFS's lack of
+ correspondance between userid's from stat and from geteuid.
+
+Sat Oct 7 22:28:49 1995 Scott Carson <sdc@TracerTech.COM>
+
+ * add.c (add): Pass -ko, not -k -ko, to set keyword expansion options.
+
+ * admin.c (admin): Don't skip first argument when sending to server.
+
+Fri Oct 6 21:45:03 1995 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * version.c: Version 1.6.1.
+
+Fri Oct 6 21:31:28 1995 Jeff Johnson <jbj@brewster.jbj.org>
+
+ * cvs.h, admin.c, client.c, commit.c, log.c, modules.c,
+ parseinfo.c, patch.c, recurse.c, rtag.c, status.c, tag.c:
+ Prototype when dealing in pointers to functions.
+
+Fri Oct 6 21:07:22 1995 Mark H. Wilkinson <mhw@minster.york.ac.uk>
+
+ * cvsrc.c (read_cvsrc): fix look up of command names in cvsrc file
+ to use full name from command table rather than possible nickname
+ in argv. Fixes errors with things like `cvs di' when cvsrc has
+ `diff -u5' in it.
+
+Thu Aug 3 01:03:52 1995 Vince DeMarco <vdemarco@bou.shl.com>
+
+ * parseinfo.c (Parse_Info): Add code to call expand_path function
+ instead of using built in code.
+
+ * wrapper.c (wrap_add): Add code to call expand_path function to
+ expand all built in variables.
+
+ * expand_path.c (New file): expand things that look like
+ environmental variables (only expand local CVS environmental
+ variables) and user names like ~/.
+ * cvs.h: Declare expand_path.
+
+ * Makefile.in (SOURCES, OBJECTS): Added expand_path.c,
+ expand_path.o.
+
+Fri Oct 6 14:03:09 1995 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * ignore.c (ign_setup): Don't try to look for a file in CVSroot if
+ client. (The recent tightening of the error checking detects this).
+
+ * commit.c (checkaddfile): Don't try to pass options if it is "".
+
+Thu Oct 5 18:04:46 1995 Karl Fogel <kfogel@totoro.cyclic.com>
+
+ * sanity.sh: unset CVSREAD, since it causes the script to bomb.
+
+Thu Oct 5 18:29:17 1995 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * remove.c, add.c, commit.c, cvs.h: Remove CVSEXT_OPT stuff; it
+ has been broken for ages and the options are already stored in the
+ Entries file.
+
+Thu Oct 5 18:20:13 1995 Norbert Kiesel <nk@col.sw-ley.de>
+
+ * commit.c (checkaddfile): New argument options; pass it to RCS.
+ (commit_fileproc): Pass it.
+
+Tue Oct 3 09:26:00 1995 Karl Fogel <kfogel@totoro.cyclic.com>
+
+ * version.c: upped to 1.6.
+
+Mon Oct 2 18:10:35 1995 Larry Jones <larry.jones@sdrc.com>
+
+ * server.c: if HAVE_SYS_BSDTYPES_H, include <sys/bsdtypes.h>.
+
+Mon Oct 2 10:34:53 1995 Karl Fogel <kfogel@totoro.cyclic.com>
+
+ * version.c: Upped version to 1.5.95.
+
+Mon Oct 2 15:16:47 1995 Norbert Kiesel <nk@col.sw-ley.de>
+
+ * tag.c, rtag.c: pass "mov" instead of "add" if tag will be moved
+ (i.e. invoked with -F)
+
+Sun Oct 1 18:36:34 1995 Karl Fogel <kfogel@totoro.cyclic.com>
+
+ * version.c: upped to 1.5.94.
+
+ * server.c: reverted earlier ISC change (of Sep. 28).
+
+ * version.c: upped to 1.5.93, for Peter Wemm's new SVR4 patch.
+
+Sun Oct 1 14:51:59 1995 Harlan Stenn <Harlan.Stenn@pfcs.com>
+
+ * main.c: don't #include <pwd.h>; cvs.h does that already.
+
+Fri Sep 29 15:21:35 1995 Karl Fogel <kfogel@floss.cyclic.com>
+
+ * version.c: upped to 1.5.91 for another pre-1.6 release.
+
+Fri Sep 29 14:41:14 1995 <bmeier@rzu.unizh.ch>
+
+ * root.c: start rcsid[] with "CVSid".
+
+Fri Sep 29 13:22:44 1995 Jim Blandy <jimb@totoro.cyclic.com>
+
+ * diff.c (diff): Doc fix.
+
+Fri Sep 29 14:32:36 1995 Norbert Kiesel <nk@col.sw-ley.de>
+
+ * repos.c (Short_Repository): chop superfluous "/".
+
+ * tag.c (pretag_proc): correct user-visible string.
+
+ * rtag.c (pretag_proc): correct user-visible string.
+
+Fri Sep 29 13:45:36 1995 Karl Fogel <kfogel@floss.cyclic.com>
+
+ * cvs.h (USE): if __GNUC__ != 2, expand to a dummy var instead of
+ nothing.
+
+Thu Sep 28 13:37:05 1995 Larry Jones <larry.jones@sdrc.com>
+
+ * server.c: ifdef ISC, include <sys/bsdtypes.h>.
+
+Fri Sep 29 07:54:22 1995 Mike Sutton <mws115@llcoolj.dayton.saic.com>
+
+ * filesubr.c (last_component): Don't use ANSI style declaration.
+
+Wed Sep 27 15:24:00 1995 Del <del@matra.com.au>
+
+ * tag.c, rtag.c: Pass a few extra options to the script
+ named in taginfo (del/add, and revision number).
+
+ * tag.c: Support a -r option (at long last). Also needs
+ a -f option to tag the head if there is no matching -r tag.
+
+Tue Sep 26 11:41:08 1995 Karl Fogel <kfogel@totoro.cyclic.com>
+
+ * version.c: Upped version to 1.5.89 for test release preceding
+ 1.6.
+
+Wed Sep 20 15:32:49 1995 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * ignore.c (ign_add_file): Check for errors from fopen and fclose.
+
+Tue Sep 19 18:02:16 1995 Jim Blandy <jimb@totoro.cyclic.com>
+
+ * Makefile.in (DISTFILES): Remove sanity.el from this list; the
+ file has been deleted.
+
+Thu Sep 14 14:17:52 1995 Peter Wemm <peter@haywire.dialix.com>
+
+ * import.c: Recover from being unable to open the user file.
+
+ * update.c (join_file): Print a message in the case where the file
+ was added.
+
+ * mkmodules.c: Deal with .db as well as .pag/.dir (for use with
+ BSD 4.4 and real dbm support).
+
+Mon Sep 11 15:44:13 1995 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * release.c (release): Revise comment regarding why and how we
+ skip argv[0].
+
+Mon Sep 11 10:03:59 1995 Karl Fogel <kfogel@floss.cyclic.com>
+
+ * release.c (release): use return value of pclose to determine
+ success of update.
+
+Mon Sep 11 09:56:33 1995 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * release.c (release_delete): Fix comment.
+
+Sun Sep 10 18:48:35 1995 Karl Fogel <kfogel@floss.cyclic.com>
+
+ * release.c (release): made work with client/server.
+ Don't ask if <arg> is mentioned in `modules'.
+
+Fri Sep 8 13:25:55 1995 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * sanity.sh: When committing a removal, send stdout to LOGFILE;
+ this is no longer a silent operation.
+
+ * sanity.sh: Remove OUTPUT variable; it is unused.
+
+ * client.c: Add comment regarding deleting temp file.
+ * main.c: Add comment regarding getopt REQUIRE_ORDER.
+
+Thu Sep 7 20:24:46 1995 Karl Fogel <kfogel@floss.cyclic.com>
+
+ * main.c (main): use getopt_long(), accept "--help" and
+ "--version".
+ Don't assume EOF is -1.
+
+Thu Sep 7 19:18:00 1995 Jim Blandy <jimb@cyclic.com>
+
+ * cvs.h (unlink_file_dir): Add prototype for this.
+
+Thu Sep 7 14:38:06 1995 Karl Fogel <kfogel@floss.cyclic.com>
+
+ * ALL FILES: add semicolon, as indicated below.
+
+ * cvs.h (USE): don't provide semicolon in the expansion of the USE
+ macro; we'd rather the callers provided it themselves because that
+ way etags doesn't get fooled.
+
+Mon Sep 4 23:30:41 1995 Magnus Hyllander <mhy@os.se>
+
+ * checkout.c: cvs export now takes -k option and does not default
+ to -kv.
+ * checkout.c, cvs.h, modules.c: Modules file now takes -e option
+ for cvs export.
+
+Mon Sep 4 23:30:41 1995 Kirby Koster <koster@sctc.com>
+
+ * commit.c: When committing a removal, print a message saying what
+ we are doing.
+
+Wed Aug 2 10:06:51 1995 Vince DeMarco <vdemarco@bou.shl.com>
+
+ * server.c: fix compiler warnings (on NeXT) (declare functions as
+ static inline instead of just static) functions: get_buffer_date,
+ buf_append_char, and buf_append_data
+
+Mon Sep 4 22:31:28 1995 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * client.c (update_entries), import.c (expand_at_signs): Check for
+ errors from fread and putc.
+
+Fri Sep 1 00:03:17 1995 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * sanity.sh: Fix TODO item pathname.
+
+ * sanity.el: Removed. It was out of date, didn't do much, and I
+ doubt anyone was using it.
+
+ * no_diff.c (No_Difference): Don't change the modes of the files.
+
+Thu Aug 31 13:14:34 1995 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * version.c: Change version to 1.5.1.
+
+ * client.c (start_rsh_server): Don't pass -d to "cvs server"
+ invocation via rsh (restore change which was lost when NT stuff
+ was merged in).
+ * sanity.sh: Add TODO item suggesting test for bug which this fixes.
+
+Wed Aug 30 12:36:37 1995 Jim Blandy <jimb@totoro.cyclic.com>
+
+ * sanity.sh (basic1): Make sure first-dir is deleted before
+ running this set of tests.
+
+ * subr.c: Extract file twiddling functions to a different file,
+ because we want to use different versions of many of these
+ routines under Windows NT.
+ (copy_file, isdir, islink, isfile, isreadable, iswritable,
+ open_file, make_directory, make_directories, xchmod,
+ rename_file, link_file, unlink_file, xcmp, tmpnam,
+ unlink_file_dir, deep_remove_dir): Moved to...
+ * filesubr.c: ...this file, which is new.
+ * Makefile.in (SOURCES): Mention filesubr.c.
+ (COMMON_OBJECTS): Mention filesubr.o.
+
+ * subr.c: Extract process execution guts to a different file,
+ because we want to replace these routines entirely under
+ Windows NT.
+ (VA_START, va_alist, va_dcl): Move this stuff...
+ (run_add_arg, run_init_prog): and these declarations...
+ (run_prog, run_argv, run_argc, run_argc_allocated): and these
+ variables...
+ (run_setup, run_arg, run_args, run_add_arg, run_init_prog,
+ run_exec, run_print, Popen): and these functions...
+ * run.c: To this file, which is new.
+ * Makefile.in (SOURCES): Mention run.c.
+ (COMMON_OBJECTS): Mention run.o.
+
+ * status.c (status): Call ign_setup, if client_active. Otherwise,
+ we don't end up ignoring CVS directories and such.
+
+ * server.c (mkdir_p, dirswitch): Use CVS_MKDIR instead of mkdir.
+
+ * repos.c (Name_Repository): Use the isabsolute function instead of
+ checking the first character of the path.
+ * root.c (Name_Root): Same.
+
+ * release.c (release): Use fncmp instead of strcmp to compare
+ filenames.
+
+ * rcs.c (RCS_parse, RCS_parsercsfile) [LINES_CRLF_TERMINATED]:
+ Abort, because we have strong reason to believe this code is
+ wrong.
+
+ * patch.c (patch): Register signal handlers iff the signal name is
+ #defined.
+
+ * no_diff.c (No_Difference): Don't try to include server_active in
+ trace message unless SERVER_SUPPORT is #defined.
+
+ * modules.c (do_module): Use CVS_MKDIR instead of mkdir.
+
+ * mkmodules.c (main): Call last_component instead of writing it out.
+
+ * main.c (main): Call last_component instead of writing it out.
+ Break up the long copyright string into several strings; Microsoft
+ Visual C++ can't handle a line that long. Feh.
+ Use fncmp instead of strcmp to compare filenames.
+ Register signal handlers iff the signal name is #defined.
+
+ * lock.c (readers_exist): Don't check return value of closedir.
+ Most of the rest of the code doesn't, and some systems don't
+ provide a return value anyway.
+ (set_lock): Use CVS_MKDIR instead of mkdir.
+
+ * import.c (import): Use the isabsolute function instead of
+ checking the first character of the path.
+ Try to delete the temporary file again after we close it, so it'll
+ get deleted on systems that don't let you delete files that are
+ open.
+ (add_rev): Instead of making a hard link to the working file and
+ checking in the revision with ci -r, use ci -u and restore the
+ permission bits.
+ (comtable): Include lines from SYSTEM_COMMENT_TABLE, if it is
+ #defined.
+ (add_rcs_file) [LINES_CRLF_TERMINATED]: Abort, because we have
+ strong reason to believe this code is wrong.
+ (import_descend_dir): Use CVS_MKDIR instead of mkdir.
+
+ * history.c (read_hrecs): Open the file with OPEN_BINARY.
+
+ * find_names.c (add_entries_proc, fsortcmp): Add prototypes.
+ * entries.c (write_ent_proc): Add prototype.
+ * hash.c (walklist): Add prototype for PROC argument.
+ (sortlist): Add prototype for COMP argument.
+ (printnode): Add a prototype, and make it static.
+
+ * cvs.h (wrap_add_file, wrap_add): Add extern decls for these;
+ they're used in import.c and update.c.
+ * wrapper.c (wrap_add_file, wrap_add): Remove them from here.
+
+ * cvs.h (RUN_NORMAL, RUN_COMBINED, RUN_REALLY, RUN_STDOUT_APPEND,
+ RUN_STDERR_APPEND, RUN_SIGNIGNORE, RUN_TTY, run_arg, run_print,
+ run_setup, run_args, run_exec, Popen, piped_child, close_on_exec,
+ filter_stream_through_program, waitpid): Move all these
+ declarations and definitions to the same section.
+
+ * cvs.h (error_set_cleanup): Fix prototype.
+
+ * cvs.h (isabsolute, last_component): New extern decls.
+
+ * cvs.h (link_file): Function is deleted; remove extern decl.
+
+ * cvs.h (DEATH_STATE, DEATH_SUPPORT): Move #definitions of these
+ above the point where we #include rcs.h, since rcs.h tests them
+ (or DEATH_SUPPORT, at least).
+
+ * cvs.h (DEVNULL): #define this iff it isn't already #defined.
+ config.h may want to override it.
+
+ * cvs.h (SERVER_SUPPORT, CLIENT_SUPPORT): Don't #define these
+ here; let config.h do that. On some systems, we don't have any
+ server support.
+
+ * cvs.h: Don't #include <io.h> or <direct.h>; we take care of
+ those in lib/system.h.
+
+ * commit.c (commit): Open logfile with the OPEN_BINARY flag.
+ (precommit_proc): Use the isabsolute function, instead of
+ comparing the first character with /.
+ (remove_file, checkaddfile): Use CVS_MKDIR instead of mkdir.
+
+ * client.c (send_repository): Use larger line buffers.
+
+ * client.c [LINES_CRLF_TERMINATED] (update_entries): If we've just
+ received a gzipped file, copy it over, converting LF to CRLF,
+ instead of just renaming it into place.
+ [LINES_CRLF_TERMINATED] (send_modified): Convert file to LF format
+ before sending with gzip.
+ (send_modified): Don't be disturbed if we get fewer than
+ sb.st_size characters when we read. The read function may be
+ collapsing CRLF to LF for us.
+
+ * client.c: Add forward declarations for all the cvs command
+ functions we call.
+
+ * client.c: Add forward static declarations for all the
+ handle_mumble functions.
+
+ On some systems, RSH converts LF to CRLF; this screws us up.
+ * client.c (rsh_pid): Declare this iff RSH_NOT_TRANSPARENT is not
+ #defined.
+ (get_responses_and_close): Use SHUTDOWN_SERVER if it is #defined.
+ Only wait for rsh process to exit if RSH_NOT_TRANSPARENT is not
+ #defined.
+ (start_rsh_server): Declare and define only if
+ RSH_NOT_TRANSPARENT is not #defined. Use piped_child, instead of
+ writing all that out.
+ (start_server): Only try to call start_rsh_server if
+ RSH_NOT_TRANSPARENT is not #defined. Use START_SERVER if it is
+ #defined. Convert file descriptors to stdio file pointers using
+ the FOPEN_BINARY_WRITE and FOPEN_BINARY_READ strings.
+
+ * client.h (rsh_pid): Don't declare this; it's never used elsewhere.
+ (supported_request): Add external declaration for this;
+ it's used in checkout.c.
+
+ Move process-running functions to run.c; we need to totally
+ replace these on other systems, like Windows NT.
+ * client.c (close_on_exec, filter_stream_through_program): Moved
+ to run.c.
+ * run.c (close_on_exec, filter_stream_through_program): Here they
+ are.
+
+ * add.c (add_directory): Use CVS_MKDIR instead of straight mkdir.
+ * checkout.c (checkout, build_dirs_and_chdir): Same.
+ (checkout_proc): Use fncmp instead of strcmp.
+ * client.c (call_in_directory): Use CVS_MKDIR instead of straight
+ mkdir.
+
+ * client.c (handle_checksum): Cast return value of strtol.
+
+Wed Aug 30 10:35:46 1995 Stefan Monnier <stefan.monnier@epfl.ch>
+
+ * main.c (main): Allow -d to override CVSROOT_ENV.
+
+Thu Aug 24 18:57:49 1995 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.h, rcscmds.c (RCS_unlock, RCS_deltag, RCS_lock): Add extra
+ parameter for whether to direct stderr to DEVNULL.
+ * checkin.c, tag.c, rtag.c, import.c, commit.c: Pass extra
+ argument. 1 if stderr had been directed to DEVNULL before
+ rcscmds.c was in use, 0 if it was RUN_TTY.
+
+ * cvs.h: Add comment regarding attic.
+
+Tue Aug 22 10:09:29 1995 Alexander Dupuy <dupuy@smarts.com>
+
+ * rcs.c (whitespace): Cast to unsigned char in case char is signed
+ and value is negative.
+
+Tue Aug 22 10:09:29 1995 Kirby Koster <koster@sctc.com>
+ and Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * update.c (join_file): If vers->vn_user is NULL, just return.
+
+Tue Aug 22 10:09:29 1995 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * server.c, client.c: Add comments about modes and umasks.
+
+Mon Aug 21 12:54:14 1995 Rick Sladkey <jrs@world.std.com>
+
+ * update.c (update_filesdone_proc): If pipeout, don't try to
+ create CVS/Root.
+
+Mon Aug 21 12:54:14 1995 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * client.c (start_rsh_server): Don't pass -d to "cvs server"
+ invocation via rsh.
+
+ * server.c (serve_root): Report errors via pending_error_text.
+ (serve_valid_requests): Check for pending errors.
+
+Sun Aug 20 00:59:46 1995 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * options.h.in: Document usage of DIFF in update.c
+ * update.c: Use DIFF -c, not DIFF -u. The small improvement in
+ diff size is not worth the hassle in terms of everyone having to
+ make sure that DIFF is GNU diff (IMHO).
+
+Sat Aug 19 22:05:46 1995 Jim Blandy <jimb@totoro.cyclic.com>
+
+ * recurse.c (start_recursion): Doc fix.
+
+ * server.c (do_cvs_command): Clear error_use_protocol in the
+ child.
+ (server): Set error_use_protocol.
+
+Sun Aug 13 15:33:37 1995 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * server.c (do_cvs_command): Don't select on exceptions.
+
+Fri Aug 4 00:13:47 1995 Jim Meyering (meyering@comco.com)
+
+ * Makefile.in (LDFLAGS): Set to @LDFLAGS@.
+ (options.h): Depend on ../config.status and options.h.in.
+ Add rule to build it from dependents.
+
+ * add.c: Include save-cwd.h.
+ (add_directory): Use save_cwd and restore_cwd instead of
+ explicit getwd then chdir.
+ * import.c (import_descend_dir): Likewise.
+ * modules.c (do_module): Likewise.
+
+ * recurse.c (save_cwd, restore_cwd, free_cwd): Remove functions.
+ New versions have been broken out into save-cwd.c.
+ (do_dir_proc): Adapt to handle status code returned by new versions
+ of save_cwd and restore_cwd -- and one fewer argument to restore_cwd.
+ (unroll_files_proc): Likewise.
+
+ * wrapper.c (wrap_name_has): Add default: abort () to switch
+ statement to avoid warning from gcc -Wall.
+ (wrap_matching_entry): Remove dcl of unused TEMP.
+ (wrap_tocvs_process_file): Remove dcl of unused ERR.
+ (wrap_fromcvs_process_file): Likewise.
+
+ * cvs.h: Remove prototype for error. Instead, include error.h.
+ Also, remove trailing white space.
+
+Thu Aug 3 10:12:20 1995 Jim Meyering (meyering@comco.com)
+
+ * import.c (import_descend_dir): Don't print probably-bogus CWD
+ in error messages saying `cannot get working directory'.
+
+Sun Jul 30 20:52:04 1995 James Kingdon <kingdon@harvey.cyclic.com>
+
+ * parseinfo.c (Parse_Info): Revise comments and indentation.
+
+Sun Jul 30 15:30:16 1995 Vince DeMarco <vdemarco@bou.shl.com>
+
+ * history.c: put ifdef SERVER_SUPPORT around tracing code incase
+ the client/server code is not compiled into the program.
+
+Sat Jul 29 16:59:49 1995 James Kingdon <kingdon@harvey.cyclic.com>
+
+ * subr.c (deep_remove_dir): Use struct dirent, not struct direct.
+
+Sat Jul 29 18:32:06 1995 Vince DeMarco <vdemarco@bou.shl.com>
+
+ * add.c: Check wrap_name_has.
+
+ * diff.c, checkin.c, import.c: have code call unlink_file_dir in
+ the appropriate places instead of just calling unlink_file.
+
+ * checkin.c: Remove one unlink call.
+
+ * import.c (comtable): Add .m .psw .pswm.
+
+ * import.c (add_rcs_file): Remove tocvsPath before returning.
+
+ * subr.c (unlink_file_dir): Add new function. unlinks the file if
+ it is a file. or will do a recursive delete if the path is
+ actually a directory.
+ (deep_remove_dir): New function, helps unlink_file_dir.
+
+ * mkmodules.c: Added CVSROOTADM_WRAPPER (cvswrappers file) to the
+ checkout file list.
+
+Fri Jul 28 16:27:56 1995 James Kingdon <kingdon@harvey.cyclic.com>
+
+ * checkout.c (safe_location): Use PATH_MAX not MAXPATHLEN.
+
+Fri Jul 28 19:37:03 1995 Paul Eggert <eggert@twinsun.com>
+
+ * log.c (cvslog, log_fileproc): Pass all options (except -l)
+ to rlog as-is, so that users can put spaces in options,
+ can specify multiple -d options, etc.
+ (ac, av): New variables.
+ (log_option_with_arg, options): Remove.
+
+ (log_fileproc): Don't prepend `/' to file name if update_dir is empty.
+
+Tue Jul 25 00:52:26 1995 James Kingdon <kingdon@harvey.cyclic.com>
+
+ * checkout.c (safe_location): Don't use PROTO in function definition.
+
+Mon Jul 24 18:32:06 1995 Vince DeMarco <vdemarco@bou.shl.com>
+
+ * checkout.c (safe_location): fix a compiler warning. (Declare
+ safe_location). Changed code in safe_location to call getwd
+ instead of getcwd. getwd is declared in the ../lib directory and
+ used exclusively thoughout the code. (this helps portability on
+ non POSIX systems).
+
+ * wrapper.c: updated Andrew Athan's email address.
+
+ * main.c: fix an ifdef so the code will compile. syntax error in
+ the ifdef for CVS_NOADMIN.
+
+Mon Jul 24 13:25:00 1995 Del <del@babel.dialix.oz.au>
+
+ * checkout.c: New procedure safe_location.
+ Ensures that you don't check out into the repository
+ itself.
+
+ * tag.c, rtag.c, cvs.h, mkmodules.c: Added a "taginfo" file in
+ CVSROOT to perform pre-tag checks.
+
+ * main.c, options.h.in: Added a compile time option to
+ disable the admin command.
+
+Fri Jul 21 17:07:42 1995 James Kingdon <kingdon@harvey.cyclic.com>
+
+ * update.c, status.c, patch.c, checkout.c, import.c, release.c,
+ rtag.c, tag.c: Now -q and -Q options just print an error message
+ telling you to use global -q and -Q options. The non-global
+ options were a mess because some commands accepted them and some
+ did not, and they were redundant with -q and -Q global options.
+
+ * rcs.c, cvs.h, commit.c, log.c, find_names.c: Remove CVS.dea
+ stuff. It is slower than the alternatives and I don't think
+ anyone ever actually used it.
+
+Fri Jul 21 10:35:10 1995 Vince DeMarco <vdemarco@bou.shl.com>
+
+ * Makefile.in (SOURCES, OBJECTS): Add wrapper.c, wrapper.o.
+ * add.c, admin.c, checkout.c, commit.c, diff.c, import.c, log.c,
+ remove.c, status.c: Call wrap_setup at start of commands.
+ * add.c (add): Check for wrapper, as well as directory, in repository.
+ * checkin.c: Add tocvsPath variable and associated handling.
+ * cvs.h: Add wrapper declarations.
+ * diff.c: Add tocvsPath variable and associated handling.
+ * import.c: Add -W option, CVSDOTWRAPPER handling.
+ (import_descend): check wrap_name_has.
+ (update_rcs_file, add_rev, add_rcs_file): add tocvsPath
+ variable and associated handling.
+ * no_diff.c: Add tocvsPath variable and associated handling.
+ * recurse.c (start_recursion): Check wrap_name_has.
+ * update.c: Copy, don't merge, copy-by-merge files. Attempt to
+ use -j on a copy-by-merge file generates a warning and no further
+ action.
+ * update.c: Add CVSDOTWRAPPER handling.
+ * wrapper.c: Added.
+
+Fri Jul 21 00:20:52 1995 James Kingdon <kingdon@harvey.cyclic.com>
+
+ * client.c: Revert David Lamkin patch, except for the bits about
+ removing temp_filename and the .rej file.
+ * sanity.sh (errmsg1): Test for the underlying bug which Lamkin
+ kludged around.
+ * client.c (call_in_directory): Set short_pathname to include the
+ filename, not just the directory. Improve comments regarding what
+ is passed to FUNC.
+
+Thu Jul 20 17:51:54 1995 David Lamkin <drl@net-tel.co.uk>
+
+ * client.c (short_pathname): Fixes the fetching of the whole file
+ after a patch to bring it up to date has failed:
+ - failed_patches[] now holds short path to file that failed
+ - patch temp files are unlinked where the patch is done
+
+Thu Jul 20 12:37:10 1995 James Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.h: Declare error_set_cleanup
+ * main.c: Call it.
+ (error_cleanup): New function.
+
+Thu Jul 20 12:17:16 1995 Mark H. Wilkinson <mhw@minster.york.ac.uk>
+
+ * add.c, admin.c, checkin.c, checkout.c, classify.c, client.c,
+ client.h, commit.c, create_adm.c, cvs.h, diff.c, entries.c,
+ history.c, import.c, log.c, main.c, modules.c, no_diff.c, patch.c,
+ release.c, remove.c, repos.c, rtag.c, server.c, server.h,
+ status.c, subr.c, tag.c, update.c, vers_ts.c, version.c: Put
+ client code inside #ifdef CLIENT_SUPPORT, server code inside
+ #ifdef SERVER_SUPPORT. When reporting version, report whether
+ client and/or server are compiled in.
+
+Wed Jul 19 18:00:00 1995 Jim Blandy <jimb@cyclic.com>
+
+ * subr.c (copy_file): Declare local var n to be an int,
+ not a size_t. size_t is unsigned, and the return values
+ of read and write are definitely not unsigned.
+
+ * cvs.h [HAVE_IO_H]: #include <io.h>.
+ [HAVE_DIRECT_H]: #include <direct.h>.
+
+Fri Jul 14 22:28:46 1995 Jim Blandy <jimb@totoro.cyclic.com>
+
+ * server.c (dirswitch, serve_static_directory, serve_sticky,
+ serve_lost, server_write_entries, serve_checkin_prog,
+ serve_update_prog): Include more information in error messages.
+ (Thanks, DJM.)
+
+ * cvsbug.sh: Use /usr/sbin/sendmail, unless it doesn't
+ exist, in which case use /usr/lib/sendmail. (Thanks, DJM.)
+
+ * server.c (server, server_cleanup): Use "/tmp" instead of
+ "/usr/tmp" when the TMPDIR environment variable isn't set. This
+ is what the rest of the code uses.
+
+Thu Jul 13 11:03:17 1995 Jim Meyering (meyering@comco.com)
+
+ * recurse.c (free_cwd): New function.
+ (save_cwd, restore_cwd): Use it instead of simply freeing any
+ string. The function also closes any open file descriptor.
+
+ * import.c (comtable): Now static.
+ (comtable): Put braces around each element of initializer.
+
+ * cvs.h: Add prototype for xgetwd.
+ * recurse.c (save_cwd, restore_cwd): New functions to encapsulate
+ run-time solution to secure-SunOS vs. fchown problem.
+ (do_dir_proc, unroll_files_proc): Use new functions instead of
+ open-coded fchdir/chdir calls with cpp directives.
+
+ * sanity.sh: Change out of TESTDIR before removing it.
+ Some versions of rm fail when asked to delete the current directory.
+
+Wed Jul 12 22:35:04 1995 Jim Meyering (meyering@comco.com)
+
+ * client.c (get_short_pathname): Add const qualifier to parameter dcl.
+ (copy_a_file): Remove set-but-not-used variable, LEN.
+ (handle_clear_static_directory): Likewise: SHORT_PATHNAME.
+ (set_sticky): Likewise: LEN.
+ (handle_set_sticky): Likewise: SHORT_PATHNAME.
+ (handle_clear_sticky): Likewise: SHORT_PATHNAME.
+ (start_rsh_server): Convert perl-style `cond || stmt' to more
+ conventional C-style `if (cond) stmt.' Sheesh.
+ Remove dcl of unused file-static, SEND_CONTENTS.
+
+ * history.c: Remove dcls of set-but-not-used file-statics,
+ HISTSIZE, HISTDATA.
+ (read_hrecs): Don't set them.
+
+ * import.c (add_rev): Remove dcl of set-but-not-used local, RETCODE.
+
+ * repos.c (Name_Repository): Remove dcl of set-but-not-used local,
+ HAS_CVSADM.
+
+ * cvsrc.c (read_cvsrc): Parenthesize assignment used as truth value.
+
+Tue Jul 11 16:49:41 1995 J.T. Conklin <jtc@rtl.cygnus.com>
+
+ * hash.h (struct entnode, Entnode): moved from here...
+ * cvs.h: to here.
+
+Wed Jul 12 19:45:24 1995 Dominik Westner (dominik@gowest.ppp.informatik.uni-muenchen.de)
+
+ * client.c (server_user): new var.
+ (parse_cvsroot): set above if repo is "user@host:/dir".
+ (start_rsh_server): if server_user set, then use it.
+
+Wed Jul 12 10:53:36 1995 Karl Fogel <kfogel@floss.cyclic.com>
+
+ * sanity.sh: remove the TESTDIR after done.
+
+ * cvsbug.sh (GNATS_ADDR): now bug-cvs@prep.ai.mit.edu again.
+
+Tue Jul 11 15:53:08 1995 Greg A. Woods <woods@most.weird.com>
+
+ * options.h.in: depend on configure for grep and diff, now that
+ changes to configure.in are applied.
+
+Tue Jul 11 14:32:14 1995 Michael Shields <shields@tembel.org>
+
+ * Makefile.in (LDFLAGS): Pick up from configure.
+
+Tue Jul 11 14:20:00 1995 Loren James Rittle <rittle@supra.comm.mot.com>
+
+ * import.c (add_rev), commit.c (remove_file, ci_new_rev),
+ checkin.c (Checkin), subr.c (make_message_rcslegal), cvs.h:
+ Always perform sanity check and fix-up on messages to be passed
+ directly to RCS via the '-m' switch. RCS 5.7 requires that a
+ non-total-whitespace, non-null message be provided or it will
+ abort with an error. CVS is not setup to handle any returned
+ error from 'ci' gracefully and, thus, the repository entered a
+ trashed state.
+
+ * sanity.sh: Add regression tests for new code and interactions
+ with RCS 5.7.
+
+Sun Jul 9 19:03:00 1995 Greg A. Woods <woods@most.weird.com>
+
+ * .cvsignore: added new backup file
+
+ * options.h.in: our new configure.in finds the right diff and
+ grep paths now....
+
+ * subr.c: quote the string in run_print() for visibility
+ - indent a comment
+ - Jun Hamano's xchmod() patch to prevent writable files
+ (from previous local changes)
+
+ * logmsg.c: fix a NULL pointer de-reference
+ - clean up some string handling code...
+ (from previous local changes)
+
+ * parseinfo.c: add hack to expand $CVSROOT in an *info file.
+ - document "ALL" and "DEFAULT" in opening comment for Parse_Info()
+ - fix the code to match the comments w.r.t. callbacks for "ALL"
+ - add a line of trace output...
+ (from previous local changes)
+
+ * mkmodules.c: add support for comments in CVSROOT/checkoutlist
+ - add CVSroot used by something other .o, ala main.c
+ (from previous local changes)
+
+ * main.c, cvs.h: add support for $VISUAL as log msg editor
+ (from previous local changes)
+
+ * status.c: add support for -q and -Q (from previous local changes)
+
+
+Sun Jul 9 18:44:32 1995 Karl Fogel <kfogel@floss.cyclic.com>
+
+ * log.c: trivial change to test ChangeLog stuff.
+
+Sat Jul 8 20:33:57 1995 Paul Eggert <eggert@twinsun.com>
+
+ * history.c: (history_write): Don't assume that fopen(..., "a")
+ lets one interleave writes to the history file from different processes
+ without interlocking. Use open's O_APPEND option instead.
+ Throw in an lseek to lessen the race bugs on non-Posix hosts.
+ * cvs.h, subr.c (Fopen): Remove.
+
+ * log.c (log_fileproc): Pass working file name to rlog, so that
+ the name is reported correctly.
+
+Fri Jul 7 18:29:37 1995 Michael Hohmuth <hohmuth@inf.tu-dresden.de>
+
+ * client.c, client.h (client_import_setup): New function.
+ (client_import_done, client_process_import_file): Add comments
+ regarding now-redundant code.
+ * import.c (import): Call client_import_setup.
+
+Tue Jul 4 09:21:26 1995 Bernd Leibing <bernd.leibing@rz.uni-ulm.de>
+
+ * rcs.c (RCS_parsercsfile_i): Rename error to l_error; SunOS4 /bin/cc
+ doesn't like a label and function with the same name.
+
+Sun Jul 2 12:51:33 1995 Fred Appelman <Fred.Appelman@cv.ruu.nl>
+
+ * logmsg.c: Rename strlist to str_list to avoid conflict with
+ Unixware 2.01.
+
+Thu Jun 29 17:37:22 1995 Paul Eggert <eggert@twinsun.com>
+
+ * rcs.c (RCS_check_kflag): Allow RCS 5.7's new -kb option.
+
+Wed Jun 28 09:53:14 1995 James Kingdon <kingdon@harvey.cyclic.com>
+
+ * Makefile.in (HEADERS): Remove options.h.in.
+ (DISTFILES): Add options.h.in.
+ Depend on options.h in addition to HEADERS.
+
+Tue Jun 27 22:37:28 1995 Vince Demarco <vdemarco@bou.shl.com>
+
+ * subr.c: Don't try to do fancy waitstatus stuff for NeXT,
+ lib/wait.h is sufficient.
+
+Mon Jun 26 15:17:45 1995 James Kingdon <kingdon@harvey.cyclic.com>
+
+ * Makefile.in (DISTFILES): Remove RCS-patches and convert.sh.
+
+Fri Jun 23 13:38:28 1995 J.T. Conklin (jtc@rtl.cygnus.com)
+
+ * server.c (dirswitch, serve_co): Use CVSADM macro instead of
+ literal "CVS".
+
+Fri Jun 23 00:00:51 1995 James Kingdon <kingdon@harvey.cyclic.com>
+
+ * README-rm-add: Do not talk about patching RCS, that only
+ confuses people.
+ * RCS-patches, convert.sh: Removed (likewise).
+
+Thu Jun 22 10:41:41 1995 James Kingdon <kingdon@harvey.cyclic.com>
+
+ * subr.c: Change -1 to (size_t)-1 when comparing against a size_t.
+
+Wed Jun 21 16:51:54 1995 nk@ipgate.col.sw-ley.de (Norbert Kiesel)
+
+ * create_adm.c, entries.c, modules.c: Avoid coredumps if
+ timestamps, tags, etc., are NULL.
+
+Tue Jun 20 15:52:53 1995 Jim Meyering (meyering@comco.com)
+
+ * checkout.c (checkout): Remove dcl of unused variable.
+ * client.c (call_in_directory, handle_clear_static_directory,
+ handle_set_sticky, handle_clear_sticky, send_a_repository,
+ send_modified, send_dirent_proc): Remove dcls of unused variables.
+ * server.c (receive_file, serve_modified, server_cleanup):
+ Remove dcls of unused variables.
+ * subr.c (copy_file): Remove dcl of unused variable.
+ * vers_ts.c (time_stamp_server): Remove dcl of unused variable.
+
+Mon Jun 19 13:49:35 1995 Jim Blandy <jimb@totoro.cyclic.com>
+
+ * sanity.sh: Fix commencement message --- the test suite says
+ "Ok." when it's done.
+
+Fri Jun 16 11:23:44 1995 Jim Meyering (meyering@comco.com)
+
+ * entries.c (fgetentent): Parenthesize assignment in if-conditional.
+
+Thu Jun 15 17:33:28 1995 J.T. Conklin <jtc@rtl.cygnus.com>
+
+ * server.c (get_buffer_data, buf_append_char, buf_append_data):
+ Don't conditionalize use of "inline". Autoconf takes care of
+ defining it away on systems that don't grok it.
+
+Thu Jun 15 13:43:38 1995 Jim Kingdon (kingdon@cyclic.com)
+
+ * options.h.in (DIFF): Default to "diff" not "diff -a" since diff
+ might not support the -a option.
+
+Wed Jun 14 11:29:42 1995 J.T. Conklin <jtc@rtl.cygnus.com>
+
+ * import.c (import_descend): Initialize dirlist to NULL.
+
+ * subr.c (copy_file): Fix infinite loop.
+
+ * server.c (serve_directory): fix a memory leak.
+
+ * checkout.c, commit.c, diff.c, history.c, import.c, log.c,
+ patch.c, release.c, remove.c, rtag.c, status.c, tag.c, update.c:
+ Use send_arg() to send command line arguments to server.
+
+ * commit.c (fsortcmp), find_names (fsortcmp), hash.c (hashp,
+ findnode), hash.h (findnode), rcs.c (RCS_addnode,
+ RCS_check_kflag, RCS_check_tag, RCS_isdead, RCS_parse,
+ RCS_parsercsfile_i), rcs.h (RCS_addnode, RCS_check_kflag,
+ RCS_check_tag, RCS_parse): Added const qualifiers as
+ appropriate.
+ * rcs.h (RCS_isdead): Added prototype.
+
+ * hash.h (walklist, sortlist): correct function prototypes.
+
+ * ignore.c (ign_setup): don't bother checking to see if file
+ exists before calling ign_add_file.
+
+Fri Jun 9 11:24:06 1995 J.T. Conklin <jtc@rtl.cygnus.com>
+
+ * all source files (rcsid): Added const qualifer.
+ * ignore.c (ign_default): Added const qualifier.
+ * subr.c (numdots): Added const qualifier to function argument.
+ * cvs.h (numdots): Added const qualifier to prototype argument.
+
+ * client.c (change_mode): Tied consecutive if statements testing
+ the same variable together with else if.
+
+ * import.c (import_descend): Build list of subdirectories when
+ reading directory, and then process the subdirectories in that
+ list. This change avoids I/O overhead of rereading directory
+ and reloading ignore list (.cvsignore) for each subdirectory.
+
+Thu Jun 8 11:54:24 1995 J.T. Conklin <jtc@rtl.cygnus.com>
+
+ * import.c (import_descend): Use 4.4BSD d_type field if it is
+ present.
+
+ * lock.c (set_lockers_name): Use %lu in format and cast st_uid
+ field to unsigned long.
+
+ * import.c (import): Use RCS_check_kflag() to check -k options.
+ (keyword_usage, str2expmode, strn2expmode, expand_names):
+ Removed.
+ * rcs.c (RCS_check_kflag): Added keyword_usage array from import.c
+ for more descriptive error messages.
+
+ * subr.c (run_setup, run_args): Changed variable argument
+ processing to work on machines that use <varargs.h>.
+
+ * subr.c (copy_file, xcmp): Changed to read the file(s) by blocks
+ rather than by reading the whole file into a huge buffer. The
+ claim that this was reasonable because source files tend to be
+ small does not hold up in real world situations. CVS is used
+ to manage non-source files, and mallocs of 400K+ buffers (x2
+ for xcmp) can easily fail due to lack of available memory or
+ even memory pool fragmentation.
+ (block_read): New function, taken from GNU cmp and slightly
+ modified.
+
+ * subr.c (xcmp): Added const qualifier to function arguments.
+ * cvs.h (xcmp): Added const qualifer to prototype arguments.
+
+Wed Jun 7 11:28:31 1995 J.T. Conklin <jtc@rtl.cygnus.com>
+
+ * cvs.h (Popen): Added prototype.
+ (Fopen, open_file, isreadable, iswritable, isdir, isfile,
+ islink, make_directory, make_directories, rename_file,
+ link_file, unlink_file, copy_file): Added const qualifer to
+ prototype arguments.
+ * subr.c (Fopen, Popen, open_file, isreadable, iswritable, isdir,
+ isfile, islink, make_directory, make_directories, rename_file,
+ link_file, unlink_file, copy_file): Added const qualifier to
+ function arguments.
+
+ * logmsg.c (logfile_write), recurse.c (do_recursion, addfile):
+ Don't cast void functions to a void expression. There is at
+ least one compiler (MPW) that balks at this.
+
+ * rcs.c (keysize, valsize): Change type to size_t.
+
+ * add.c (add_directory): Don't cast umask() argument to int.
+
+ * import.c (add_rcs_file): Changed type of mode to mode_t.
+
+ * rcscmds.c (RCS_merge): New function.
+ * cvs.h (RCS_merge): Declare.
+ * update.c (merge_file, join_file): Call RCS_merge instead of
+ invoking rcsmerge directly.
+
+ * cvs.h: Include <stdlib.h> if HAVE_STDC_HEADERS, otherwise
+ declared getenv().
+ * cvsrc.c, ignore.c, main.c: Removed getenv() declaration.
+
+ * client.c (mode_to_string): Changed to take mode_t instead of
+ struct statb argument. Simplified implementation, no longer
+ overallocates storage for returned mode string.
+ * client.h (mode_to_string): Updated declaration.
+ * server.c (server_updated): Updated for new calling conventions,
+ pass st_mode instead of pointer to struct statb.
+
+ * cvs.h (CONST): Removed definition, use of const qualifier is
+ determined by autoconf.
+ * history.c, modules.c, parseinfo.c: Use const instead of CONST.
+
+ * add.c, admin.c, checkout.c, commit.c, diff.c, import.c, log.c,
+ main.c, mkmodules.c, patch.c, recurse.c, remove.c, rtag.c,
+ server.c, status.c, subr.c, tag.c, update.c: Changed function
+ arguments "char *argv[]" to "char **argv" to silence lint
+ warnings about performing arithmetic on arrays.
+
+Tue Jun 6 18:57:21 1995 Jim Blandy <jimb@totoro.cyclic.com>
+
+ * version.c: Fix up version string, to say that this is Cyclic
+ CVS.
+
+Tue Jun 6 15:26:16 1995 J.T. Conklin <jtc@rtl.cygnus.com>
+
+ * subr.c (run_setup, run_args, run_add_arg, xstrdup): Add const
+ qualifier to format argument.
+ * cvs.h (run_setup, run_args, xstrdup): Likewise.
+
+ * Makefile.in (SOURCES): Added rcscmds.c.
+ (OBJECTS): Added rcscmds.o.
+
+ * rcscmds.c: New file, with new functions RCS_settag, RCS_deltag,
+ RCS_setbranch, RCS_lock, RCS_unlock.
+ * checkin.c, commit.c, import.c, rtag.c, tag.c: Call above
+ functions instead of exec'ing rcs commands.
+ * cvs.h: Declare new functions.
+
+Mon May 29 21:40:54 1995 J.T. Conklin (jtc@rtl.cygnus.com)
+
+ * recurse.c (start_recursion, do_recursion): Set entries to NULL
+ after calling Entries_Close().
+
+Sat May 27 08:08:18 1995 Jim Meyering (meyering@comco.com)
+
+ * Makefile.in (check): Export RCSBIN only if there exists an
+ `rcs' executable in ../../rcs/src. Before, tests would fail when
+ the directory existed but contained no executables.
+ (distclean): Remove options.h, now that it's generated.
+ (Makefile): Regenerate only *this* file when Makefile.in is
+ out of date. Depend on ../config.status.
+
+Fri May 26 14:34:28 1995 J.T. Conklin <jtc@rtl.cygnus.com>
+
+ * entries.c (Entries_Open): Added missing fclose().
+ (Entries_Close): Don't write Entries unless Entries.Log exists.
+
+ * entries.c (Entries_Open): Renamed from ParseEntries; changed to
+ process Entries Log files left over from previous crashes or
+ aborted runs.
+ (Entries_Close): New function, write out Entries file if
+ neccessary and erase Log file.
+ (Register): Append changed records to Log file instead of
+ re-writing file.
+ (fgetentent): New function, parse one Entry record from a file.
+ (AddEntryNode): It's no longer an error for two records with the
+ same name to be added to the list. New records replace older
+ ones.
+ * cvs.h (Entries_Open, Entries_Close): Add prototypes.
+ (CVSADM_ENTLOG): New constant, name of Entries Log file.
+ * add.c, checkout.c, client.c, find_names.c, recurse.c: Use
+ Entries_Open()/Entries_Close() instead of ParseEntries()/dellist().
+
+ * add.c, admin.c, checkout.c, client.c, commit.c, diff.c,
+ history.c, import.c, log.c, patch.c, release.c, remove.c,
+ rtag.c, server.c, status.c, tag.c, update.c: Changed
+ conditionals so that return value of *printf is tested less than
+ 0 instead of equal to EOF.
+
+Thu May 25 08:30:12 1995 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * subr.c (xmalloc): Never try to malloc zero bytes; if the user
+ asks for zero bytes, malloc one instead.
+
+Wed May 24 12:44:25 1995 Ken Raeburn <raeburn@cujo.cygnus.com>
+
+ * subr.c (xmalloc): Don't complain about NULL if zero bytes were
+ requested.
+
+Tue May 16 21:49:05 1995 Jim Blandy <jimb@totoro.bio.indiana.edu>
+
+ * subr.c (xmalloc): Never try to malloc zero bytes; if the user
+ asks for zero bytes, malloc one instead.
+
+Mon May 15 14:35:11 1995 J.T. Conklin <jtc@rtl.cygnus.com>
+
+ * lock.c (L_LOCK_OWNED): Removed.
+
+ * add.c, checkout.c, client.c, create_adm.c, cvs.h, entries.c,
+ find_names.c modules.c, recurse.c, release.c, repos.c, update.c:
+ removed CVS 1.2 compatibility/upgrade code.
+
+Mon May 8 11:25:07 1995 J.T. Conklin <jtc@rtl.cygnus.com>
+
+ * lock.c (write_lock): Missed one instance where rmdir(tmp) should
+ have been changed to clear_lock().
+
+Wed May 3 11:08:32 1995 J.T. Conklin <jtc@rtl.cygnus.com>
+
+ * create_adm.c, entries.c, import.c, root.c: Changed conditionals
+ so that return value of *printf is tested less than 0 instead of
+ equal to EOF --- That's all Standard C requires.
+
+Wed May 3 18:03:37 1995 Samuel Tardieu <tardieu@emma.enst.fr>
+
+ * rcs.h: removed #ifdef CVS_PRIVATE and #endif because cvs didn't
+ compile anymore.
+
+Mon May 1 13:58:53 1995 J.T. Conklin <jtc@rtl.cygnus.com>
+
+ * rcs.c, rcs.h: Implemented lazy parsing of rcs files.
+ RCS_parsercsfile_i modified to read only the first two records
+ of rcs files, a new function RCS_reparsercsfile is called only
+ when additional information (tags, revision numbers, dates,
+ etc.) is required.
+
+Mon May 1 12:20:02 1995 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * Makefile.in (INCLUDES): Include -I. for options.h.
+
+Fri Apr 28 16:16:33 1995 Jim Blandy <jimb@totoro.bio.indiana.edu>
+
+ * Makefile.in (SOURCES, HEADERS, DISTFILES): Updated.
+ (dist-dir): Renamed from dist; changed to work with DISTDIR
+ variable passed from parent.
+
+ We don't want to include a file the user has to edit in the
+ distribution.
+ * options.h: No longer distributed.
+ * options.h.in: Distribute this instead.
+ * ../INSTALL, ../README: Installation instructions updated.
+
+ * client.c (start_rsh_server): Send the remote command to rsh as a
+ single string.
+
+Fri Apr 28 00:29:49 1995 Noel Cragg <noel@vo.com>
+
+ * commit.c: Added initializer for FORCE_CI
+
+ * sanity.sh: Fix tests added 25 Apr -- they were expecting the
+ server to make noise, but the CVS_SERVER variable had been
+ accidentally set with the `-Q' flag. Ran all tests -- both
+ locally and remotely -- to verify that the change didn't break
+ anything.
+
+Thu Apr 27 12:41:52 1995 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * Makefile.in: Revise comment regarding check vs. remotecheck.
+
+Thu Apr 27 12:52:28 1995 Bryan O'Sullivan <bos@cyclic.com>
+
+ * client.c (start_rsh_server): If the CVS_RSH environment variable
+ is set, use its contents as the name of the program to invoke
+ instead of `rsh'.
+
+Thu Apr 27 12:18:38 1995 Noel Cragg <noel@vo.com>
+
+ * checkout.c (checkout): To fix new bug created by Apr 23 change,
+ re-enabled "expand-module" functionality, because it has the side
+ effect of setting the checkin/update programs for a directory. To
+ solve the local/remote checkout problem that prompted this change
+ in the first place, I performed the next change.
+ * server.c (expand_proc): Now returns expansions for aliases only.
+
+Wed Apr 26 12:07:42 1995 J.T. Conklin <jtc@rtl.cygnus.com>
+
+ * rcs.c (getrcskey): Rewritten to process runs of whitespace chars
+ and rcs @ strings instead of using state variables "white" and
+ "funky".
+
+Fri Apr 7 15:49:25 1995 J.T. Conklin <jtc@rtl.cygnus.com>
+
+ * lock.c (unlock): Only call stat if we need to.
+
+Wed Apr 26 10:48:44 1995 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * server.c (new_entries_line): Don't prototype.
+
+Tue Apr 25 22:19:16 1995 Jim Blandy <jimb@totoro.bio.indiana.edu>
+
+ * sanity.sh: Add new tests to catch bugs in Apr 23 change.
+
+Tue Apr 25 17:10:55 1995 Roland McGrath <roland@baalperazim.frob.com>
+
+ * create_adm.c (Create_Admin): Use getwd instead of getcwd.
+
+Sun Apr 23 20:58:32 1995 Noel Cragg <noel@vo.com>
+
+ * checkout.c (checkout): Disabled "expand-module" functionality on
+ remote checkout, since it makes modules behave like aliases (see
+ longer note there). This change necessitated the change below.
+ Also merged the like parts of a conditional.
+
+ * client.c (call_in_directory): Changed the algorithm that created
+ nested and directories and the "CVS" administration directories
+ therein. The algoithm wrongly assumed that the name of the
+ directory that that was to be created and the repository name were
+ the same, which breaks modules.
+
+ * create_adm.c (Create_Admin), module.c (do_module), server.c
+ (server_register), subr.c, entries.c: Added fprintfs for trace-mode
+ debugging.
+
+ * client.c (client_send_expansions): Argument to function didn't
+ have a type -- added one.
+
+ * server.c (new_entries_line): Arguments to this function are
+ never used -- reoved them and fixed callers.
+
+Sat Apr 22 11:17:20 1995 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * rcs.c (RCS_parse): If we can't open the file, give an error
+ message (except for ENOENT in case callers rely on that).
+
+Wed Apr 19 08:52:37 1995 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * client.c (send_repository): Check for CVSADM_ENTSTAT in `dir', not
+ in `.'.
+
+ * sanity.sh: Add TODO list. Revise some comments. Add tests of
+ one working directory adding a file and other updating it.
+
+Sat Apr 8 14:52:55 1995 Jim Blandy <jimb@totoro.bio.indiana.edu>
+
+ * Makefile.in (CFLAGS): Let configure set the default for CFLAGS.
+ Under GCC, we want -g -O.
+
+Fri Apr 7 15:49:25 1995 J.T. Conklin <jtc@rtl.cygnus.com>
+
+ * root.c (Name_Root): merge identical adjacent conditionals.
+
+ * create_admin.c (Create_Admin): Rearranged check for CVSADM and
+ OCVSADM directories so that CVSADM pathname is only built once.
+
+ * update.c (update_dirleave_proc): Removed code to remove CVS
+ administration directory if command_name == "export" and to
+ create CVS/Root file if it is not present. Identical code
+ in update_filesdone_proc() will perform these same actions.
+ Also removed code that read and verfied CVS/Root. This is
+ expensive, and if it is necessary should happen in the
+ general recursion processor rather than in the update
+ callbacks.
+
+ * lock.c (masterlock): New variable, pathname of master lockdir.
+ (set_lock): removed lockdir argument, now constructs it itself
+ and stores it in masterlock.
+ (clear_lock): new function, removes master lockdir.
+ (Reader_Lock, write_lock): call clear_lock instead of removing
+ master lockdir.
+ (Reader_Lock, write_lock): #ifdef'd out CVSTFL code.
+
+ * main.c (main): register Lock_Cleanup signal handler.
+ * lock.c (Reader_Lock, write_lock): no longer register
+ Lock_Cleanup.
+
+ * main.c (main): initialize new array hostname.
+ * lock.c (Reader_Lock, write_lock): Use global hostname array.
+ * logmsg.c (logfile_write): Likewise.
+
+ * recurse.c (do_dir_proc, unroll_files_proc): Use open()/fchdir()
+ instead of getwd()/chdir() on systems that support the fchdir()
+ system call.
+
+Fri Apr 7 06:57:20 1995 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * server.c: Include the word "server" in error message for memory
+ exhausted, so the user knows which machine ran out of memory.
+
+ * sanity.sh: For remote, set CVS_SERVER to test the right server,
+ rather than a random one from the PATH.
+
+ * commit.c [DEATH_STATE]: Pass -f to `ci'.
+
+Thu Apr 6 13:05:15 1995 Jim Blandy <jimb@totoro.bio.indiana.edu>
+
+ * commit.c (checkaddfile): If we didn't manage to fopen the file,
+ don't try to fclose it.
+
+ * client.c (handle_m, handle_e): Use fwrite, rather than a loop of
+ putc's. Sometimes these streams are unbuffered.
+
+Tue Apr 4 11:33:56 1995 Jim Blandy <jimb@totoro.bio.indiana.edu>
+
+ * (DISTFILES): Include cvsbug.sh, ChangeLog, NOTES, RCS-patches,
+ README-rm-add, ChangeLog.fsf, sanity.sh, sanity.el, and
+ .cvsignore.
+
+Mon Mar 27 08:58:42 1995 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * rcs.c (RCS_parsercsfile_i): Accept `dead' state regardless of
+ DEATH_STATE define. Revise comments regarding DEATH_STATE versus
+ CVSDEA versus the scheme which uses a patched RCS.
+ * README-rm-add, RCS-patches: Explain what versions of CVS need
+ RCS patches.
+
+Sat Mar 25 18:51:39 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
+
+ * server.c (server_cleanup): Only do the abysmal kludge of waiting
+ for command and draining the pipe #ifdef sun. The code makes
+ assumptions not valid on all systems, and is only there to
+ workaround a SunOS bug.
+
+Wed Mar 22 21:55:56 1995 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * server.c (mkdir_p): Call stat only if we get the EACCES. Faster
+ and more elegant.
+
+Tue Jan 31 20:59:19 1995 Ken Raeburn <raeburn@cujo.cygnus.com>
+
+ * server.c: Try to avoid starting the "rm -rf" at cleanup time
+ until after subprocesses have finished.
+ (command_fds_to_drain, max_command_fd): New variables.
+ (do_cvs_command): Set them.
+ (command_pid_is_dead): New variable.
+ (wait_sig): New function.
+ (server_cleanup): If command_pid is nonzero, wait for it to die,
+ draining output from it in the meantime. If nonzero SIG was
+ passed, send a signal to the subprocess, to encourage it to die
+ soon.
+
+ * main.c (usage): Argument is now `const char *const *'.
+ * cvs.h (usage): Changed prototype.
+ (USE): Make new variable `const'.
+ * add.c (add_usage), admin.c (admin_usage), checkout.c
+ (checkout_usage, export_usage, checkout), commit.c (commit_usage),
+ diff.c (diff_usage), history.c (history_usg), import.c
+ (import_usage, keyword_usage), log.c (log_usage), main.c (usg),
+ patch.c (patch_usage), release.c (release_usage), remove.c
+ (remove_usage), rtag.c (rtag_usage), server.c (server), status.c
+ (status_usage), tag.c (tag_usage), update.c (update_usage): Usage
+ messages are now const arrays of pointers to const char.
+
+ * import.c (comtable): Now const.
+ * main.c (rcsid): Now static.
+ (cmd): Now const.
+ (main): Local variable CM now points to const.
+ * server.c (outbuf_memory_error): Local var MSG now const.
+
+ * client.c (client_commit_usage): Deleted.
+
+Sat Dec 31 15:51:55 1994 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * logmsg.c (do_editor): Allocate enough space for trailing '\0'.
+
+Fri Mar 3 11:59:49 1995 Jim Blandy <jimb@totoro.bio.indiana.edu>
+
+ * cvsbug.sh: Call it "Cyclic CVS" now, not "Remote CVS". Call it
+ version C1.4A, not 1.4A2-remote. Send bugs to cyclic-cvs, not
+ remote-cvs.
+
+ * classify.c (Classify_File): Put check for dead file inside
+ "#ifdef DEATH_SUPPORT".
+
+Thu Feb 23 23:03:43 1995 Jim Blandy <jimb@totoro.bio.indiana.edu>
+
+ * update.c (join_file): Don't pass the -E option to rcsmerge here,
+ either (see Jan 22 change).
+
+Mon Feb 13 13:28:46 1995 Jim Blandy <jimb@totoro.bio.indiana.edu>
+
+ * cvsbug.sh: Send bug reports to remote-cvs@cyclic.com, rather
+ than to the ordinary CVS bug address. This does mean we'll have
+ to wade through GNATS-style bug reports, sigh.
+
+Wed Feb 8 06:42:27 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
+
+ * server.c: Don't include <sys/stat.h>; system.h already does, and
+ 4.3BSD can't take it twice.
+
+ * subr.c [! HAVE_VPRINTF] (run_setup, run_args): Don't use va_dcl
+ in declaration. Declare the a1..a8 args which are used in the
+ sprintf call.
+ * cvs.h [! HAVE_VPRINTF] (run_setup, run_args): Don't prototype
+ args, to avoid conflicting with the function definitions
+ themselves.
+
+Tue Feb 7 20:10:00 1995 Jim Blandy <jimb@totoro.bio.indiana.edu>
+
+ * client.c (update_entries): Pass the patch subprocess the switch
+ "-b ~", not "-b~"; the latter form seems not to work with patch
+ version 2.0 and earlier --- it takes the next argv element as the
+ backup suffix, and thus doesn't notice that the patch file's name
+ has been specified, thus doesn't find the patch, thus... *aargh*
+
+Fri Feb 3 20:28:21 1995 Jim Blandy <jimb@totoro.bio.indiana.edu>
+
+ * log.c (log_option_with_arg): New function.
+ (cvslog): Use it and send_arg to handle the rlog options that take
+ arguments. The code used to use send_option_string for
+ everything, which assumes that "-d1995/01/02" is equivalent to
+ "-d -1 -9 -9 -5 ...".
+
+Tue Jan 31 15:02:01 1995 Jim Blandy <jimb@floss.life.uiuc.edu>
+
+ * server.c: #include <sys/stat.h> for the new stat call in mkdir_p.
+ (mkdir_p): Don't try to create the intermediate directory if it
+ exists already. Some systems return EEXIST, but others return
+ EACCES, which we can't otherwise distinguish from a real access
+ problem.
+
+Sun Jan 22 15:25:45 1995 Jim Blandy <jimb@totoro.bio.indiana.edu>
+
+ * update.c (merge_file): My rcsmerge doesn't accept a -E option,
+ and it doesn't look too important, so don't pass it.
+
+Fri Jan 20 14:24:58 1995 Ian Lance Taylor <ian@sanguine.cygnus.com>
+
+ * client.c (do_deferred_progs): Don't try to chdir to toplevel_wd
+ if it has not been set.
+ (process_prune_candidates): Likewise.
+
+Mon Nov 28 09:59:14 1994 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * client.c (client_commit): Move guts of function from here...
+ * commit.c (commit): ...to here.
+
+Mon Nov 28 15:14:36 1994 Ken Raeburn <raeburn@cujo.cygnus.com>
+
+ * server.c (buf_input_data, buf_send_output): Start cpp directives
+ in column 1, otherwise Sun 4 pcc complains.
+
+Mon Nov 28 09:59:14 1994 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * client.c (add_prune_candidate): Don't try to prune ".".
+
+Tue Nov 22 05:27:10 1994 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * server.c, client.c: More formatting cleanups.
+
+ * client.h, client.c: New variable client_prune_dirs.
+ * update.c (update), checkout.c (checkout): Set it.
+ * client.c (add_prune_candidate, process_prune_candidates): New
+ functions.
+ (send_repository, call_in_directory, get_responses_and_close):
+ Call them.
+
+Wed Nov 23 01:17:32 1994 Ian Lance Taylor (ian@tweedledumb.cygnus.com)
+
+ * server.c (do_cvs_command): Don't select on STDOUT_FILENO unless
+ we have something to write.
+
+Tue Nov 22 05:27:10 1994 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * remove.c (remove_fileproc): Only call server_checked_in if we
+ actually are changing the entries file.
+
+ * server.c (server_write_entries): New function.
+ (dirswitch, do_cvs_command): Call it.
+ (serve_entry, serve_updated): Just update in-memory data
+ structures, don't mess with CVS/Entries file.
+
+Mon Nov 21 10:15:11 1994 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * server.c (server_checked_in): Set scratched_file to NULL after
+ using it.
+
+ * checkin.c (Checkin): If the file was changed by the checkin,
+ call server_updated not server_checked_in.
+
+Sun Nov 20 08:01:51 1994 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * client.c (send_repository): Move check for update_dir NULL to
+ before where we check last_update_dir. Check for "" here too.
+
+ * client.c (send_repository): Use new argument dir.
+
+ * client.c: Pass new argument dir to send_repository and
+ send_a_repository.
+
+ * server.c, server.h (server_prog): New function.
+ * modules.c (do_modules): Call it if server_expanding.
+ * client.c: Support Set-checkin-prog and Set-update-prog responses.
+ * server.c, client.c: Add Checkin-prog and Update-prog requests.
+
+Fri Nov 18 14:04:38 1994 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * client.c (get_short_pathname, is_cvsroot_level,
+ call_in_directory): Base whether this is new-style or
+ old-style based on whether we actually used the Directory request,
+ not based on whether the pathname is absolute. Rename
+ directory_supported to use_directory.
+ * server.c: Rename use_relative_pathnames to use_dir_and_repos.
+ * client.c (send_a_repository): If update_dir is absolute, don't
+ use it to try to reconstruct how far we have recursed.
+
+ * server.c, server.h, client.c, client.h, vers_ts.c, update.h:
+ More cosmetic changes (identation, PARAMS vs. PROTO, eliminate
+ alloca, etc.) to remote CVS to make it more like the rest of CVS.
+
+ * server.c: Make server_temp_dir just the dir name, not the name
+ with "%s" at the end.
+ * server.c, client.c: Add "Max-dotdot" request, and use it to make
+ extra directories in server_temp_dir if needed.
+
+Thu Nov 17 09:03:28 1994 Jim Kingdon <kingdon@cygnus.com>
+
+ * client.c: Fix two cases where NULL was used and 0 was meant.
+
+Mon Nov 14 08:48:41 1994 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * server.c (serve_unchanged): Set noexec to 0 when calling Register.
+
+ * update.c (merge_file): Don't call xcmp if noexec.
+
+Fri Nov 11 13:58:22 1994 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * client.c (call_in_directory): Deal with it if reposdirname is
+ not a subdirectory of toplevel_repos.
+
+Mon Nov 7 09:12:01 1994 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * patch.c: If file is removed and we don't have a tag or date,
+ just print "current release".
+
+ * classify.c (Classify_File): Treat dead files appropriately.
+
+Fri Nov 4 07:33:03 1994 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * main.c (main) [SERVER_SUPPORT]: Move call to getwd past where we
+ know whether we are the server or not. Set CurDir to "<remote>"
+ if we are the server.
+
+ * client.c: Remove #if 0'd function option_with_arg.
+ Remove #if 0'd code pertaining to the old way of logging the
+ session.
+
+ * client.c (start_rsh_server): Don't invoke the server with the
+ -d option.
+ * server.c (serve_root): Test root for validity, just like main.c
+ does for non-remote CVS.
+ * main.c (main): If `cvs server' happens with a colon in the
+ CVSroot, just handle it normally; don't make it an error.
+
+Wed Nov 2 11:09:38 1994 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * client.c (send_dirent_proc): If dir does not exist, just return
+ R_SKIP_ALL.
+
+ * server.c, client.c: Add Directory request and support for
+ local relative pathnames (along with the repository absolute
+ pathnames).
+ * update.c, add.c, checkout.c, checkin.c, cvs.h, create_adm.c,
+ commit.c, modules.c, server.c, server.h, remove.c, client.h:
+ Pass update_dir to server_* functions. Include update_dir in
+ more error messages.
+
+Fri Oct 28 08:54:00 1994 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * client.c: Reformat to bring closer to cvs standards for brace
+ position, comment formatting, etc.
+
+ * sanity.sh: Remove wrong "last mod" line. Convert more tests to
+ put PASS or FAIL in log file. Change it so arguments to the
+ script specify which tests to run.
+
+ * client.c, client.h, server.c, checkout.c: Expand modules in
+ separate step from the checkout itself.
+
+Sat Oct 22 20:33:35 1994 Ken Raeburn (raeburn@kr-pc.cygnus.com)
+
+ * update.c (join_file): When checking for null return from
+ RCS_getversion, still do return even if quiet flag is set.
+
+Thu Oct 13 07:36:11 1994 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * client.c (send_files): Call send_repository even if
+ toplevel_repos was NULL.
+
+ * server.c (server_updated): If joining, don't remove file.
+
+ * update.c (join_file): If server and file is unmodified, check it
+ out before joining. After joining, call server_updated. New
+ argument repository.
+
+ * server.c, server.h (server_copy_file): New function.
+ * update.c (update_file_proc, join_file): Call it.
+ * client.c (copy_file, handle_copy_file): New functions.
+ * client.c (responses): Add "Copy-file".
+
+ * client.c, client.h: Make toplevel_wd, failed_patches and
+ failed_patches_count extern.
+ * client.c (client_update): Move guts of function from here...
+ * update.c (update): ...to here.
+
+ * client.c, checkout.c: Likewise for checkout.
+
+ * client.c (is_cvsroot_level): New function.
+ (handle_set_sticky, handle_clear_sticky,
+ handle_clear_static_directory): Call it, instead of checking
+ short_pathname for a slash.
+
+ * client.c, client.h (client_process_import_file,
+ client_import_done): New functions.
+ * import.c (import, import_descend): Use them.
+ * import.c (import_descend): If server, don't mention ignored CVS
+ directories.
+ * import.c (import_descend_dir): If client, don't print warm
+ fuzzies, or make directories in repository. If server, print warm
+ fuzzies to stdout not stderr.
+ * client.c (send_modified): New function, broken out from
+ send_fileproc.
+ (send_fileproc): Call it.
+
+ * client.c (handle_clear_sticky, handle_set_sticky,
+ handle_clear_static_directory, handle_set_static_directory): If
+ command is export, just return.
+ (call_in_directory, update_entries): If command is export, don't
+ create CVS directories, CVS/Entries files, etc.
+ * update.c (update_filesdone_proc): Don't remove CVS directories if
+ client_active.
+
+ * client.c (send_a_repository): Instead of insisting that
+ repository end with update_dir, just strip as many pathname
+ components from the end as there are in update_dir.
+
+ * Makefile.in (remotecheck): New target, pass -r to sanity.sh.
+ * sanity.sh: Accept -r argument which means to test remote cvs.
+
+ * tag.c (tag), rtag.c (rtag), patch.c (patch), import.c (import),
+ admin.c (admin), release.c (release): If client_active, connect to
+ the server and send the right requests.
+ * main.c (cmds): Add these commands.
+ (main): Remove code which would strip hostname off cvsroot and try
+ the command locally. There are no longer any commands which are
+ not supported.
+ * client.c, client.h (client_rdiff, client_tag, client_rtag,
+ client_import, client_admin, client_export, client_history,
+ client_release): New functions.
+ * server.c (serve_rdiff, serve_tag, serve_rtag, serve_import,
+ serve_admin, serve_export, serve_history, serve_release): New
+ functions.
+ (requests): List them.
+ * server.c: Declare cvs commands (add, admin, etc.).
+ * cvs.h, server.h: Don't declare any of them here.
+ * main.c: Restore declarations of cvs commands which were
+ previously removed.
+
+ * cvs.h: New define DEATH_STATE, commented out for now.
+ * rcs.c (RCS_parsercsfile_i), commit.c (remove_file, checkaddfile)
+ [DEATH_STATE]: Use RCS state to record a dead file.
+
+Mon Oct 3 09:44:54 1994 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * status.c (status_fileproc): Now that ts_rcs is just one time,
+ don't try to print the second time from it. (Same as raeburn 20
+ Aug change, it accidentally got lost in 1.4 Alpha-1 merge).
+
+ * cvs.h (CVSDEA): Added (but commented out for now).
+ * rcs.c (RCS_parsercsfile_i) [CVSDEA]: Also look in CVSDEA to see if
+ something is dead.
+ * commit.c (ci_new_rev, mark_file) [CVSDEA]: New functions.
+ (remove_file, checkaddfile) [CVSDEA]: Use them instead of ci -K.
+ * find_names.c (find_dirs) [CVSDEA]: Don't match CVSDEA directories.
+ * update.c (checkout_file): Check RCS_isdead rather than relying
+ on co to not create the file.
+
+ * sanity.sh: Direct output to logfile, not /dev/null.
+
+ * subr.c (run_exec): Print error message if we are unable to exec.
+
+ * commit.c (remove_file): Call Scratch_Entry when removing tag
+ from file. The DEATH_SUPPORT ifdef was erroneous.
+
+Sun Oct 2 20:33:27 1994 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * commit.c (checkaddfile): Instead of calling isdir before
+ attempting to create the directory, just ignore EEXIST errors from
+ mkdir. (This removes some DEATH_SUPPORT ifdefs which actually had
+ nothing to do with death support).
+
+Thu Sep 29 09:23:57 1994 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * diff.c (diff): Search attic too if we have a second tag/date.
+ (diff_fileproc): If we have a second tag/date, don't do all the
+ checking regarding the user file.
+
+Mon Sep 26 12:02:15 1994 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * checkin.c (Checkin): Check for error from unlink_file.
+
+Mon Sep 26 08:51:10 1994 Anthony J. Lill (ajlill@ajlc.waterloo.on.ca)
+
+ * rcs.c (getrcskey): Allocate space for terminating '\0' if
+ necessary.
+
+Sat Sep 24 09:07:37 1994 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * commit.c (commit_fileproc): Set got_message = 1 when calling
+ do_editor (accidentally omitted from last change).
+
+Fri Sep 23 11:59:25 1994 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ Revert buggy parts of Rich's change of 1 Nov 1993 (keeping the
+ dynamic buffer allocation, which was the point of that change).
+ * logmsg.c (do_editor): Reinstate message arg, but make it char
+ **messagep instead of char *message. Change occurances of message
+ to *messagep. Char return type from char * back to void.
+ * cvs.h: Change do_editor declaration.
+ * commit.c: Reinstate got_message variable
+ (commit_filesdoneproc, commit_fileproc, commit_direntproc): Use it.
+ * import.c (import), commit.c (commit_fileproc,
+ commit_direntproc): Pass &message to do_editor; don't expect it to
+ return a value.
+ * client.c (client_commit): Likewise.
+ * import.c (import): Deal with it if message is NULL.
+
+Wed Sep 21 09:43:25 1994 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * server.c (server_updated): If the file doesn't exist, skip it.
+
+ * diff.c, client.h, client.c: Rename diff_client_senddate to
+ client_senddate and move from diff.c to client.c.
+ * client.c (client_update, client_checkout): Use it.
+
+Sat Sep 17 08:36:58 1994 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * checkout.c (checkout_proc): Don't pass NULL to Register for
+ version. (should fix "cvs co -r <nonexistent-tag> <file>"
+ coredump on Solaris).
+
+Fri Sep 16 08:38:02 1994 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * diff.c (diff_fileproc): Set top_rev from vn_user, not vn_rcs.
+ Rename it to user_file_rev because it need not be the head of any
+ branch.
+ (diff_file_nodiff): After checking user_file_rev, if we have both
+ use_rev1 and use_rev2, compare them instead of going on to code
+ which assumes use_rev2 == NULL.
+
+Thu Sep 15 08:20:23 1994 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * status.c (status): Return a value in client_active case.
+
+Thu Sep 15 15:02:12 1994 Ian Lance Taylor (ian@sanguine.cygnus.com)
+
+ * server.c (serve_modified): Create the file even if the size is
+ zero.
+
+Thu Sep 15 08:20:23 1994 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * lock.c (readers_exist): Clear errno each time around the loop,
+ not just the first time.
+
+ * client.c (start_server): Don't send Global_option -q twice.
+
+ * no_diff.c (No_Difference): Check for error from unlink.
+
+ * no_diff.c, cvs.h (No_Difference): New args repository,
+ update_dir. Call server_update_entries if needed. Use update_dir
+ in error message.
+ * classify.c (Classify_File): Pass new args to No_Difference.
+
+ * server.c (server_update_entries, server_checked_in,
+ server_updated): Don't do anything if noexec.
+
+ * client.c (send_fileproc): Rather than guessing how big the gzip
+ output may be, just realloc the buffer as needed.
+
+Tue Sep 13 13:22:03 1994 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * lock.c: Check for errors from unlink, readdir, and closedir.
+
+ * classify.c (Classify_File): Pass repository and update_dir to
+ sticky_ck.
+ (sticky_ck): New args repository and update_dir.
+ * server.c, server.h (server_update_entries): New function.
+ * classify.c (sticky_ck): Call it.
+ * client.c: New response "New-entry".
+ * client.c (send_fileproc): Send tag/date from vers->entdata, not
+ from vers itself.
+
+Mon Sep 12 07:07:05 1994 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * server.c: Clean up formatting ("= (errno)" -> "= errno").
+
+ * cvs.h: Declare strerror.
+
+ * client.c: Add code to deal with Set-sticky and Clear-sticky
+ responses, and Sticky request.
+ * server.c: Add code to deal with Sticky request.
+ * server.c, server.h (server_set_sticky): New function.
+ * create_adm.c (Create_Admin), update.c (update, update_dirent_proc),
+ commit.c (commit_dirleaveproc): Call it.
+ * client.c, client.h (send_files): Add parameter aflag.
+ * add.c (add), diff.c (diff), log.c (cvslog), remove.c (cvsremove),
+ status.c (status),
+ client.c (client_commit, client_update, client_checkout): Pass it.
+ * client.c (client_update): Add -A flag.
+
+Fri Sep 9 07:05:35 1994 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * entries.c (WriteTag): Check for error from unlink_file.
+
+ * server.c (server_updated): Initialize size to 0. Previously if
+ the file was zero length, the variable size got used without being
+ set.
+
+Thu Sep 8 14:23:05 1994 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * server.c (serve_repository): Check for error from fopen on
+ CVSADM_ENT.
+
+ * update.c (update, update_dirent_proc): Check for errors when
+ removing Entries.Static.
+
+ * client.c: Add code to deal with Set-static-directory and
+ Clear-static-directory responses, and Static-directory request.
+ * server.c, server.h (server_clear_entstat, server_set_entstat):
+ New functions.
+ * update.c, checkout.c, modules.c: Call them.
+ * server.c: Add code to deal with Static-directory request.
+
+ * server.c, client.c: Use strchr and strrchr instead of index and
+ rindex.
+
+ * server.c (serve_unchanged, serve_lost): Change comments which
+ referred to changing timestamp; we don't always change the
+ timestamp in those cases anymore.
+
+Wed Sep 7 10:58:12 1994 J.T. Conklin (jtc@rtl.cygnus.com)
+
+ * cvsrc.c (read_cvsrc): Don't call getenv() three times when one
+ time will do.
+
+ * subr.c (xmalloc, xrealloc): Change type of bytes argument from
+ int to size_t and remove the test that checks if it is less than
+ zero.
+ * cvs.h (xmalloc, xrealloc): Update prototype.
+
+Thu Sep 1 12:22:20 1994 Jim Kingdon (kingdon@cygnus.com)
+
+ * update.c (merge_file, join_file): Pass -E to rcsmerge.
+ (merge_file): If rcsmerge doesn't change the file, say so.
+
+ * recurse.c, cvs.h (start_recursion): New argument wd_is_repos.
+ * recurse.c (start_recursion): Use it instead of checking whether
+ command_name is rtag to find out if we are cd'd to the repository.
+ * client.c, update.c, commit.c, status.c, diff.c, log.c, admin.c,
+ remove.c, tag.c: Pass 0 for wd_is_repos.
+ * rtag.c, patch.c: Pass 1 for wd_is_repos.
+
+ * classify.c, cvs.h (Classify_File): New argument pipeout.
+ * classify.c (Classify_File): If pipeout, don't complain if the
+ file is already there.
+ * update.c, commit.c, status.c: Change callers.
+
+ * mkmodules.c (main): Don't print "reminders" if commitinfo,
+ loginfo, rcsinfo, or editinfo files are missing.
+
+Mon Aug 22 23:22:59 1994 Ken Raeburn (raeburn@kr-pc.cygnus.com)
+
+ * server.c (strerror): Static definition replaced by extern
+ declaration.
+
+Sun Aug 21 07:16:27 1994 Ken Raeburn (raeburn@kr-pc.cygnus.com)
+
+ * client.c (update_entries): Run "patch" with input from
+ /dev/null, so if it's the wrong version, it fails quickly rather
+ than waiting for EOF from terminal before failing.
+
+Sat Aug 20 04:16:33 1994 Ken Raeburn (raeburn@cujo.cygnus.com)
+
+ * server.c (serve_unchanged): Instead of creating a file with a
+ zero timestamp, rewrite the entries file to have "=" in the
+ timestamp field.
+ * vers_ts.c (mark_lost, mark_unchanged): New macros.
+ (time_stamp_server): Use them, for clarity. Interpret "="
+ timestamp as an unchanged file. A zero-timestamp file should
+ never be encountered now in use_unchanged mode.
+
+ * client.c (start_server): If CVS_CLIENT_PORT indicates a
+ non-positive port number, skip straight to rsh connection.
+
+ * status.c (status_fileproc): Fix ts_rcs reference when printing
+ version info, to correspond to new Entries file format. Don't
+ print it at all if server_active, because it won't have any useful
+ data.
+
+Thu Aug 18 14:38:21 1994 Ken Raeburn (raeburn@cujo.cygnus.com)
+
+ * cvs.h (status): Declare.
+ * client.c (client_status): New function.
+
+ * client.h (client_status): Declare.
+ * main.c (cmds): Include it.
+ * server.c (serve_status): New function.
+ (requests): Add it.
+ * status.c (status): Do the remote thing if client_active.
+
+ * client.c (supported_request): New function.
+ (start_server): Use it.
+
+ * server.c (receive_partial_file): New function, broken out from
+ serve_modified. Operate with fixed-size local buffer, instead of
+ growing stack frame by entire file size.
+ (receive_file): New function, broken out from serve_modified.
+ (serve_modified): Call it.
+ (server): Print out name of unrecognized request.
+
+ More generic stream-filtering support:
+ * client.c (close_on_exec, filter_stream_through_program): New
+ functions.
+ (server_fd): New variable.
+ (get_responses_and_close): Direct non-rsh connection is now
+ indicated by server_fd being non-negative. File descriptors for
+ to_server and from_server may now be different in case "tee"
+ filtering is being done. Wait for rsh_pid specifically.
+ (start_server): Use filter_stream_through_program for "tee"
+ filter, and enable it for direct Kerberos-authenticated
+ connections. Use dup to create new file descriptors for server
+ connection if logging is enabled.
+ (start_rsh_server): Disable code that deals with logging.
+
+ Per-file compression support:
+ * cvs.h (gzip_level): Declare.
+ * main.c (usg): Describe new -z argument.
+ (main): Recognize it and set gzip_level.
+ * client.c (filter_through_gzip, filter_through_gunzip): New
+ functions to handle compression.
+ (update_entries): If size starts with "z", uncompress
+ (start_server): If gzip_level is non-zero and server supports it,
+ issue gzip-file-contents request.
+ (send_fileproc): Optionally compress file contents. Use a
+ slightly larger buffer, anticipating the worst case.
+ * server.c (gzip_level): Define here.
+ (receive_file): Uncompress file contents if needed.
+ (serve_modified): Recognize "z" in file size and pass receive_file
+ appropriate flag.
+ (buf_read_file_to_eof, buf_chain_length): New functions.
+ (server_updated): Call them when sending a compressed file.
+ (serve_gzip_contents): New function; set gzip_level.
+ (requests): Added gzip-file-contents request.
+
+Wed Aug 17 09:37:44 1994 J.T. Conklin (jtc@cygnus.com)
+
+ * find_names.c (find_dirs): Use 4.4BSD filesystem feature (it
+ contains the file type in the dirent structure) to avoid
+ stat'ing each file.
+
+ * commit.c (remove_file,checkaddfile): Change type of umask
+ variables from int to mode_t.
+ * subr.c (): Likewise.
+
+Tue Aug 16 19:56:34 1994 Mark Eichin (eichin@cygnus.com)
+
+ * diff.c (diff_fileproc): Don't use diff_rev* because they're
+ invariant across calls -- add new variable top_rev.
+ (diff_file_nodiff): After checking possible use_rev* values, if
+ top_rev is set drop it in as well (if we don't already have two
+ versions) and then clear it for next time around.
+
+Wed Aug 10 20:50:47 1994 Mark Eichin (eichin@cygnus.com)
+
+ * diff.c (diff_fileproc): if ts_user and ts_rcs match, then the
+ file is at the top of the tree -- so we might not even have a
+ copy. Put the revision into diff_rev1 or diff_rev2.
+
+Wed Aug 10 14:55:38 1994 Ken Raeburn (raeburn@cujo.cygnus.com)
+
+ * server.c (do_cvs_command): Use waitpid.
+
+ * subr.c (run_exec): Always use waitpid.
+
+ * Makefile.in (CC, LIBS): Define here, in case "make" is run in
+ this directory instead of top level.
+
+Wed Aug 10 13:57:06 1994 Mark Eichin (eichin@cygnus.com)
+
+ * client.c (krb_get_err_text): use HAVE_KRB_GET_ERR_TEXT to
+ determine if we need to use the array or the function.
+ * main.c: ditto.
+
+Tue Aug 9 16:43:30 1994 Ken Raeburn (raeburn@cujo.cygnus.com)
+
+ * entries.c (ParseEntries): If timestamp is in old format, rebuild
+ it in the new format. Fudge an unmatchable entry that won't
+ trigger this code next time around, if the file is modified.
+
+ * vers_ts.c (time_stamp): Only put st_mtime field into timestamp,
+ and use GMT time for it. With st_ctime or in local time, copying
+ trees between machines in different time zones makes all the files
+ look modified.
+ (time_stamp_server): Likewise.
+
+Tue Aug 9 19:40:51 1994 Mark Eichin (eichin@cygnus.com)
+
+ * main.c (main): use krb_get_err_text function instead of
+ krb_err_txt array.
+
+Thu Aug 4 15:37:50 1994 Ian Lance Taylor (ian@sanguine.cygnus.com)
+
+ * main.c (main): When invoked as kserver, set LOGNAME and USER
+ environment variables to the remote user name.
+
+Thu Aug 4 07:44:37 1994 Mark Eichin (eichin@cygnus.com)
+
+ * client.c: (handle_valid_requests): if we get an option that has
+ rq_enableme set, then send that option. If it is UseUnchanged, set
+ use_unchanged so that the rest of the client knows about
+ it. (Could become a more general method for dealing with protocol
+ upgrades.)
+ (send_fileproc): if use_unchanged didn't get set, send an
+ old-style "Lost" request, otherwise send an "Unchanged" request.
+ * server.c (serve_unchanged): new function, same as serve_lost,
+ but used in the opposite case.
+ (requests): add new UseUnchanged and Unchanged requests, and make
+ "Lost" optional (there isn't a good way to interlock these.)
+ * server.h (request.status): rq_enableme, new value for detecting
+ compatibility changes.
+ * vers_ts.c (time_stamp_server): swap meaning of zero timestamp if
+ use_unchanged is set.
+
+Tue Jul 26 10:19:30 1994 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * sanity.sh: Separate CVSROOT_FILENAME, which must be the filename
+ of the root, from CVSROOT, which can include a hostname for
+ testing remote CVS. (but the tests aren't yet prepared to deal
+ with the bugs in remote CVS).
+
+ * import.c (update_rcs_file): Change temporary file name in TMPDIR
+ from FILE_HOLDER to cvs-imp<process-id>.
+
+ * sanity.sh: Add ">/dev/null" and "2>/dev/null" many places to
+ suppress spurious output. Comment out tests which don't work (cvs
+ add on top-level directory, cvs diff when non-committed adds or
+ removes have been made, cvs release, test 53 (already commented as
+ broken), retagging without deleting old tag, test 63). Now 'make
+ check' runs without any failures.
+
+Fri Jul 15 12:58:29 1994 Ian Lance Taylor (ian@sanguine.cygnus.com)
+
+ * Makefile.in (install): Do not depend upon installdirs.
+
+Thu Jul 14 15:49:42 1994 Ian Lance Taylor (ian@sanguine.cygnus.com)
+
+ * client.c, server.c: Don't try to handle alloca here; it's
+ handled by cvs.h.
+
+Tue Jul 12 13:32:40 1994 Ian Lance Taylor (ian@sanguine.cygnus.com)
+
+ * client.c (update_entries): Reset stored_checksum_valid if we
+ quit early because of a patch failure.
+
+Fri Jul 8 11:13:05 1994 Ian Lance Taylor (ian@sanguine.cygnus.com)
+
+ * client.c (responses): Mark "Remove-entry" as optional.
+
+Thu Jul 7 14:07:58 1994 Ian Lance Taylor (ian@sanguine.cygnus.com)
+
+ * server.c (server_updated): Add new checksum argument. If it is
+ not NULL, and the client supports the "Checksum" response, send
+ it.
+ * server.h (server_updated): Update prototype.
+ * update.c: Include md5.h.
+ (update_file_proc): Pass new arguments to patch_file and
+ server_updated.
+ (patch_file): Add new checksum argument. Set it to the MD5
+ checksum of the version of the file being checked out.
+ (merge_file): Pass new argument to server_updated.
+ * client.c: Include md5.h.
+ (stored_checksum_valid, stored_checksum): New static variables.
+ (handle_checksum): New static function.
+ (update_entries): If a checksum was received, check it against the
+ MD5 checksum of the final file.
+ (responses): Add "Checksum".
+ (start_server): Clear stored_checksum_valid.
+ * commit.c (commit_fileproc): Pass new argument to server_updated.
+
+ * client.h (struct response): Move definition in from client.c,
+ add status field.
+ (responses): Declare.
+ * client.c (struct response): Remove definition; moved to
+ client.h.
+ (responses): Make non-static. Initialize status field.
+ * server.c (serve_valid_responses): Check and record valid
+ responses, just as in handle_valid_requests in client.c.
+
+ * diff.c (diff_client_senddate): New function.
+ (diff): Use it to send -D arguments to server.
+
+Wed Jul 6 12:52:37 1994 J.T. Conklin (jtc@phishhead.cygnus.com)
+
+ * rcs.c (RCS_parsercsfile_i): New function, parse RCS file
+ referenced by file ptr argument.
+ (RCS_parsercsfile): Open file and pass its file ptr to above function.
+ (RCS_parse): Likewise.
+
+Wed Jul 6 01:25:38 1994 Ian Lance Taylor (ian@tweedledumb.cygnus.com)
+
+ * client.c (update_entries): Print message indicating that an
+ unpatchable file will be refetched.
+ (client_update): Print message when refetching unpatchable files.
+
+Fri Jul 1 07:16:29 1994 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * client.c (send_dirent_proc): Don't call send_a_repository if
+ repository is "".
+
+Fri Jul 1 13:58:11 1994 Ian Lance Taylor (ian@sanguine.cygnus.com)
+
+ * client.c (last_dirname, last_repos): Move out of function.
+ (failed_patches, failed_patches_count): New static variables.
+ (update_entries): If patch program fails, save short_pathname in
+ failed_patches array, only exit program if retcode is -1, and
+ return out of the function rather than update the Entries line.
+ (start_server): Clear toplevel_repos, last_dirname, last_repos.
+ (client_update): If failed_patches is not NULL after doing first
+ update, do another update, but remove all the failed files first.
+
+Thu Jun 30 09:08:57 1994 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * server.c (requests): Add request "Global_option".
+ (serve_global_option): New function, to handle it.
+ * client.c (start_server): Deal with global options. Check for
+ errors from fprintf.
+
+ * client.c (send_fileproc): Split out code which sends repository
+ into new function send_a_repository. Also, deal with update_dir
+ being ".".
+ (send_dirent_proc): Call send_a_repository.
+ * add.c (add): If client_active, do special processing for
+ directories.
+ (add_directory): If server_active, don't try to create CVSADM
+ directory.
+
+Thu Jun 30 11:58:52 1994 Ian Lance Taylor (ian@sanguine.cygnus.com)
+
+ * client.c (update_entries): If patch succeeds, remove the backup
+ file.
+ * server.c (server_updated): Add new argument file_info. If it is
+ not NULL, use it rather than sb to get the file mode.
+ * server.h (server_updated): Update prototype for new argument.
+ * update.c (update_file_proc): Pass new arguments to patch_file
+ and server_updated.
+ (patch_file): Add new argument file_info. Don't use -p to check
+ out new version, check it out into file and rename that to file2.
+ If result is not readable, assume file is dead and set docheckout.
+ Call xchmod on file2. Close the patch file after checking for a
+ binary diff. Set file_info to the results of stat on file2.
+ (merge_file): Pass new argument to server_updated.
+ * commit.c (commit_fileproc): Pass new argument to server_updated.
+
+Wed Jun 29 13:00:41 1994 Ian Lance Taylor (ian@sanguine.cygnus.com)
+
+ * client.c (krb_realmofhost): Declare, since it's not the current
+ <krb.h>.
+ (start_server): Save the name returned by gethostbyname. Call
+ krb_realmofhost to get the realm. Pass the resulting realm to
+ krb_sendauth. Pass the saved real name to krb_sendauth, rather
+ than server_host.
+
+ * update.c (update_file_proc): Pass &docheckout to patch_file. If
+ it is set to 1, fall through to T_CHECKOUT case.
+ (patch_file): Add docheckout argument. Set it to 1 if we can't
+ make a patch. Check out the files and run diff rather than
+ rcsdiff. If either file does not end in a newline, we can't make
+ a patch. If the patch starts with the string "Binary", assume
+ one or the other is a binary file, and that we can't make a patch.
+
+Tue Jun 28 11:57:29 1994 Ian Lance Taylor (ian@sanguine.cygnus.com)
+
+ * client.c (update_entries): If the patch file is empty, don't run
+ patch program; avoids error message.
+
+ * classify.c (Classify_File): Return T_CHECKOUT, not T_PATCH, if
+ the file is in the Attic.
+
+ * cvs.h (enum classify_type): Add T_PATCH.
+ * config.h (PATCH_PROGRAM): Define.
+ * classify.c (Classify_File): If user file exists and is not
+ modified, and using the same -k options, return T_PATCH instead of
+ T_CHECKOUT.
+ * update.c (patches): New static variable.
+ (update): Add u to gnu_getopt argument. Handle it.
+ (update_file_proc): Handle T_PATCH.
+ (patch_file): New static function.
+ * server.h (enum server_updated_arg4): Add SERVER_PATCHED.
+ * server.c (server_updated): Handle SERVER_PATCHED by sending
+ "Patched" command.
+ (serve_ignore): New static function.
+ (requests): Add "update-patches".
+ (client_update): If the server supports "update-patches", send -u.
+ * client.c (struct update_entries_data): Change contents field
+ from int to an unnamed enum.
+ (update_entries): Correponding change. If contents is
+ UPDATE_ENTRIES_PATCH, pass the input to the patch program.
+ (handle_checked_in): Initialize contents to enum value, not int.
+ (handle_updated, handle_merged): Likewise.
+ (handle_patched): New static function.
+ (responses): Add "Patched".
+ * commit.c (check_fileproc): Handle T_PATCH.
+ * status.c (status_fileproc): Likewise.
+
+ * client.c (start_server): If CVS_CLIENT_PORT is set in the
+ environment, connect to that port, rather than looking up "cvs" in
+ /etc/services. For debugging.
+
+Tue Jun 21 12:48:16 1994 Ken Raeburn (raeburn@cujo.cygnus.com)
+
+ * update.c (joining): Return result of comparing pointer with
+ NULL, not result of casting (truncating, on Alpha) pointer to int.
+
+ * main.c (main) [HAVE_KERBEROS]: Impose a umask if starting as
+ Kerberos server, so temp directories won't be world-writeable.
+
+ * update.c (update_filesdone_proc) [CVSADM_ROOT]: If environment
+ variable CVS_IGNORE_REMOTE_ROOT is set and repository is remote,
+ don't create CVS/Root file.
+ * main.c (main): If env var CVS_IGNORE_REMOTE_ROOT is set, don't
+ check CVS/Root.
+
+Fri Jun 10 18:48:32 1994 Mark Eichin (eichin@cygnus.com)
+
+ * server.c (O_NDELAY): use POSIX O_NONBLOCK by default, unless it
+ isn't available (in which case substitute O_NDELAY.)
+
+Thu Jun 9 19:17:44 1994 Mark Eichin (eichin@cygnus.com)
+
+ * server.c (server_cleanup): chdir out of server_temp_dir before
+ deleting it (so that it works on non-BSD systems.) Code for choice
+ of directory cloned from server().
+
+Fri May 27 18:16:01 1994 Ian Lance Taylor (ian@tweedledumb.cygnus.com)
+
+ * client.c (update_entries): Add return type of void.
+ (get_responses_and_close): If using Kerberos and from_server and
+ to_server are using the same file descriptor, use shutdown, not
+ fclose. Close from_server.
+ (start_server): New function; most of old version renamed to
+ start_rsh_server.
+ (start_rsh_server): Mostly renamed from old start_server.
+ (send_fileproc): Use %lu and cast sb.st_size in fprintf call.
+ (send_files): Remove unused variables repos and i.
+ (option_no_arg): Comment out; unused.
+ * main.c (main): Initialize cvs_update_env to 0. If command is
+ "kserver", authenticate and change command to "server". If
+ command is "server", don't call Name_Root, don't check access to
+ history file, and don't assume that CVSroot is not NULL.
+ * server.c (my_memmove): Removed.
+ (strerror): Change check from STRERROR_MISSING to HAVE_STRERROR.
+ (serve_root): Likewise for putenv.
+ (serve_modified): Initialize buf to NULL.
+ (struct output_buffer, buf_try_send): Remove old buffering code.
+ (struct buffer, struct buffer_data, BUFFER_DATA_SIZE,
+ allocate_buffer_datas, get_buffer_data, buf_empty_p,
+ buf_append_char, buf_append_data, buf_read_file, buf_input_data,
+ buf_copy_lines): New buffering code.
+ (buf_output, buf_output0, buf_send_output, set_nonblock,
+ set_block, buf_send_counted, buf_copy_counted): Rewrite for new
+ buffering code.
+ (protocol, protocol_memory_error, outbuf_memory_error,
+ do_cvs_command, server_updated): Rewrite for new buffering code.
+ (input_memory_error): New function.
+ (server): Put Rcsbin at start of PATH in environment.
+ * Makefile.in: Add @includeopt@ to DEFS.
+
+Fri May 20 08:13:10 1994 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * cvs.h, classify.c (Classify_File): New argument update_dir.
+ Include it in user messages.
+ * commit.c (check_fileproc), status.c (status_fileproc), update.c
+ (update_file_proc): Pass update_dir to Classify_File.
+ * commit.c (check_fileproc), update.c (checkout_file):
+ Include update_dir in user messages.
+ * commit.c (check_fileproc) update.c (update_file_proc): Re-word
+ "unknown status" message.
+
+ * server.c (server_checked_in): Deal with the case where
+ scratched_file is set rather than entries_line.
+
+ * entries.c (Register): Write file even if server_active.
+ * add.c (add): Add comment about how we depend on above behavior.
+
+Tue May 17 08:16:42 1994 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * mkmodules.c: Add dummy server_active and server_cleanup, to go
+ with the dummy Lock_Cleanup already there.
+
+ * server.c (server_cleanup): No longer static.
+
+Sat May 7 10:17:17 1994 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ Deal with add and remove:
+ * commit.c (checkaddfile): If CVSEXT_OPT or CVSEXT_LOG file does
+ not exist, just silently keep going.
+ (remove_file): If server_active, remove file before creating
+ temporary file with that name.
+ * server.c (serve_remove, serve_add): New functions.
+ (requests): Add them.
+ * server.c (server_register): If options is NULL, it means there
+ are no options.
+ * server.c, server.h (server_scratch_entry_only): New function.
+ New variable kill_scratched_file.
+ (server_scratch, server_updated): Deal with kill_scratched_file.
+ * commit.c (commit_fileproc): If server_active, call
+ server_scratch_entry_only and server_updated.
+ * add.c (add): Add client_active code.
+ (add): If server_active, call server_checked_in for each file added.
+ * remove.c (remove): Add client_active code.
+ (remove_fileproc): If server_active, call server_checked_in.
+ * main.c (cmds), client.c, client.h: New functions client_add and
+ client_remove.
+ * Move declarations of add, cvsremove, diff, and cvslog from
+ main.c to cvs.h.
+ * client.c (call_in_directory): Update comment regarding Root and
+ Repository files.
+ (send_fileproc): Only send Entries line if Version_TS really finds
+ an entry. If it doesn't find one, send Modified.
+ (update_entries): If version is empty or starts with 0 or -,
+ create a dummy timestamp.
+
+Thu May 5 19:02:51 1994 Per Bothner (bothner@kalessin.cygnus.com)
+
+ * recurse/c (start_recursion): If we're doing rtag, and thus
+ have cd'd to the reporsitory, add ,v to a file name before stat'ing.
+
+Wed Apr 20 15:01:45 1994 Ian Lance Taylor (ian@tweedledumb.cygnus.com)
+
+ * client.c (client_commit): Call ign_setup.
+ (client_update, client_checkout): Likewise.
+ * diff.c (diff): If client, call ign_setup.
+ * log.c (cvslog): Likewise.
+ * update.h (ignlist): Change definition to declaration to avoid
+ depending upon common semantics (not required by ANSI C, and not
+ the default on Irix 5).
+ * update.c (ignlist): Define.
+
+Tue Apr 19 00:02:54 1994 John Gilmore (gnu@cygnus.com)
+
+ Add support for remote `cvs log'; clean up `cvs diff' a bit.
+
+ * client.c (send_arg): Make external.
+ (send_option_string): New function.
+ (client_diff_usage): Remove, unused.
+ (client_diff): Just call diff, not do_diff.
+ (client_log): Add.
+ * client.h (client_log, send_arg, send_option_string): Declare.
+ * cvs.h (cvslog): Declare.
+ * diff.c (do_diff): Fold back into diff(), distinguish by checking
+ client_active.
+ (diff): Remove `-*' arg parsing crud; use send_option_string.
+ * log.c (cvslog): If a client, start the server, pass options
+ and files, and handle server responses.
+ * main.c (cmds): Add client_log.
+ (main): Remove obnoxious message every time CVS/Root is used.
+ Now CVS will be quiet about it -- unless there is a conflict
+ between $CVSROOT or -d value versus CVS/Root.
+ * server.c (serve_log): Add.
+ (requests): Add "log".
+
+Mon Apr 18 22:07:53 1994 John Gilmore (gnu@cygnus.com)
+
+ Add support for remote `cvs diff'.
+
+ * diff.c (diff): Break guts out into new fn do_diff.
+ Add code to handle starting server, writing args,
+ sending files, and retrieving responses.
+ (includes): Use PARAMS for static function declarations.
+ * client.c (to_server, from_server, rsh_pid,
+ get_responses_and_close, start_server, send_files,
+ option_with_arg): Make external.
+ (send_file_names): New function.
+ (client_diff): New function.
+ * client.h (client_diff, to_server, from_server,
+ rsh_pid, option_with_arg, get_responses_and_close, start_server,
+ send_file_names, send_files): Declare.
+ * cvs.h (diff): Declare.
+ * main.c (cmds): Add client_diff to command table.
+ * server.c (serve_diff): New function.
+ (requests): Add serve_diff.
+ (server): Bug fix: avoid free()ing incremented cmd pointer.
+ * update.h (update_filesdone_proc): Declare with PARAMS.
+
+Sat Apr 16 04:20:09 1994 John Gilmore (gnu@cygnus.com)
+
+ * root.c (Name_root): Fix tyop (CVSroot when root meant).
+
+Sat Apr 16 03:49:36 1994 John Gilmore (gnu@cygnus.com)
+
+ Clean up remote `cvs update' to properly handle ignored
+ files (and files that CVS can't identify), and to create
+ CVS/Root entries on the client side, not the server side.
+
+ * client.c (send_fileproc): Handle the ignore list.
+ (send_dirent_proc): New function for handling ignores.
+ (send_files): Use update_filesdone_proc and send_dirent_proc
+ while recursing through the local filesystem.
+ * update.h: New file.
+ * update.c: Move a few things into update.h so that client.c
+ can use them.
+
+Fri Mar 11 13:13:20 1994 Ian Lance Taylor (ian@tweedledumb.cygnus.com)
+
+ * server.c: If O_NDELAY is not defined, but O_NONBLOCK is, define
+ O_NDELAY to O_NONBLOCK.
+
+Wed Mar 9 21:08:30 1994 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ Fix some spurious remote CVS errors caused by the CVS/Root patches:
+ * update.c (update_filesdone_proc): If server_active, don't try to
+ create CVS/Root.
+ * root.c (Name_Root): Make error messages which happen if root is
+ not an absolute pathname or if it doesn't exist a bit clearer.
+ Skip them if root contains a colon.
+
+Mon Nov 1 15:54:51 1993 K. Richard Pixley (rich@sendai.cygnus.com)
+
+ * client.c (client_commit): dynamically allocate message.
+
+Tue Jun 1 17:03:05 1993 david d `zoo' zuhn (zoo at cirdan.cygnus.com)
+
+ * server.h: remove alloca cruft
+
+ * server.c: replace with better alloca cruft
+
+Mon May 24 11:25:11 1993 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * entries.c (Scratch_Entry): Update our local Entries file even if
+ server_active.
+
+ * server.c (server_scratch, server_register): If both Register
+ and Scratch_Entry happen, use whichever one happened later.
+ If neither happen, silently continue.
+
+ * client.c (client_checkout): Initialize tag and date (eichin and
+ I independently discovered this bug at the same time).
+
+Wed May 19 10:11:51 1993 Mark Eichin (eichin@cygnus.com)
+
+ * client.c (update_entries): handle short reads over the net
+ (SVR4 fread is known to be broken, specifically for short
+ reads off of streams.)
+
+Tue May 18 15:53:44 1993 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * server.c (do_cvs_command): Fix fencepost error in setting
+ num_to_check.
+
+ * server.c (do_cvs_command): If terminated with a core dump, print
+ message and set dont_delete_temp.
+ (server_cleanup): If dont_delete_temp, don't delete it.
+
+ * client.c (get_server_responses): Don't change cmd since we
+ are going to "free (cmd)".
+
+ * server.c: Rename memmove to my_memmove pending a real fix.
+
+ * server.c (do_cvs_command): Set num_to_check to largest descriptor
+ we try to use, rather than using (non-portable) getdtablesize.
+
+Wed May 12 15:31:40 1993 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ Add CVS client feature:
+ * client.{c,h}: New files.
+ * cvs.h: Include client.h.
+ * main.c: If CVSROOT has a colon, use client commands instead.
+ * vers_ts.c (Version_TS): If repository arg is NULL, don't worry
+ about the repository.
+ * logmsg.c (do_editor): If repository or changes is NULL, just don't
+ use those features.
+ * create_adm.c (Create_Admin), callers: Move the test for whether
+ the repository exists from here to callers.
+ * repos.c (Name_Repository): Don't test whether the repository exists
+ if client_active set (might be better to move test to callers).
+
+ Add CVS server feature:
+ * server.{c,h}: New files.
+ * cvs.h: Include server.h.
+ * checkin.c (Checkin): Call server_checked_in.
+ * update.c (update_file_proc, merge_files): Call server_updated.
+ * entries.c (Register): Call server_register.
+ (Scratch_Entry): Call server_scratch.
+ * main.c: Add server to cmds.
+ * vers_ts.c (Version_TS): If server_active, call new function
+ time_stamp_server to set ts_user.
+
diff --git a/gnu/usr.bin/cvs/cvs/Makefile b/gnu/usr.bin/cvs/cvs/Makefile
new file mode 100644
index 0000000..94c505f
--- /dev/null
+++ b/gnu/usr.bin/cvs/cvs/Makefile
@@ -0,0 +1,20 @@
+# $Id: Makefile,v 1.12 1995/12/11 02:22:27 peter Exp $
+
+PROG= cvs
+MAN1= cvs.1
+MAN5= cvs.5
+SRCS= add.c admin.c checkin.c checkout.c classify.c client.c commit.c \
+ create_adm.c cvsrc.c diff.c entries.c expand_path.c find_names.c \
+ history.c ignore.c import.c lock.c log.c login.c logmsg.c main.c \
+ modules.c no_diff.c parseinfo.c patch.c rcs.c rcscmds.c recurse.c \
+ release.c remove.c repos.c root.c rtag.c server.c status.c tag.c \
+ update.c vers_ts.c wrapper.c
+
+CFLAGS+= -I${.CURDIR}/../lib -DHAVE_CONFIG_H
+
+DPADD+= ${LIBCVS} ${LIBGNUREGEX} ${LIBMD}
+LDADD+= -lcvs -lgnuregex -lmd
+
+.include "../../Makefile.inc"
+.include <bsd.prog.mk>
+
diff --git a/gnu/usr.bin/cvs/cvs/NOTES b/gnu/usr.bin/cvs/cvs/NOTES
new file mode 100644
index 0000000..646ebdf
--- /dev/null
+++ b/gnu/usr.bin/cvs/cvs/NOTES
@@ -0,0 +1,60 @@
+wishlist - Tue Nov 2 15:22:58 PST 1993
+
+* bcopy -> memcpy & friends.
+ ** done 12/18/93
+
+* remove static buffers.
+* replace list & node cache with recursive obstacks, (xmalloc,
+ getnode, getlist)
+* check all io functions for error return codes. also check all
+ system calls.
+* error check mkdir.
+
+---
+Old notes...
+
+* All sizing limits are gone. The rest of these items were incidental
+ in that effort.
+
+* login name from history was duplicated. taught existing routine to
+ cache and use that instead. Also add routines to cache uid, pid,
+ etc.
+
+* ign strings were never freed. Now they are.
+
+* there was a printf("... %s ...", cp) vs *cp bug in history.c. Now
+ fixed.
+
+* The environment variables TMPDIR, HOME, and LOGNAME were not
+ honored. Now they are.
+
+* extra line inserted by do_editor() is gone. Then obviated. Editor
+ is now called exactly once per checkin.
+
+* revised editor behaviour. Never use /dev/tty. If the editor
+ session fails, we haven't yet done anything. Therefor the user can
+ safely rerun cvs and we should just fail. Also use the editor for
+ initial log messages on added files. Also omit the confirmation
+ when adding directories. Adding directories will require an
+ explicit "commit" step soon. Make it possible to prevent null login
+ messages using #define REQUIRE_LOG_MESSAGES
+
+* prototypes for all callbacks.
+
+* all callbacks get ref pointers.
+
+* do_recursion/start_recursion now use recusion_frame's rather than a
+ list of a lot of pointers and global variables.
+
+* corrected types on status_dirproc().
+
+* CONFIRM_DIRECTORY_ADDS
+
+* re_comp was innappropriate in a few places. I've eliminated it.
+
+* FORCE_MESSAGE_ON_ADD
+
+* So I built a regression test. Let's call it a sanity check to be
+ less ambitious. It exposed that cvs is difficult to call from
+ scripts.
+
diff --git a/gnu/usr.bin/cvs/cvs/README-rm-add b/gnu/usr.bin/cvs/cvs/README-rm-add
new file mode 100644
index 0000000..17c721f
--- /dev/null
+++ b/gnu/usr.bin/cvs/cvs/README-rm-add
@@ -0,0 +1,48 @@
+WHAT THE "DEATH SUPPORT" FEATURES DO:
+
+(this really should be in the main manual, but noone has gotten around
+to updating it).
+
+CVS with death support can record when a file is active, or alive, and
+when it is removed, or dead. With this facility you can record the
+history of a file, including the fact that at some point in its life
+the file was removed and then later added.
+
+First, the following now works as expected:
+
+ touch foo
+ cvs add foo ; cvs ci -m "added" foo
+ rm foo
+ cvs rm foo ; cvs ci -m "removed" foo
+ touch foo
+ cvs add foo ; cvs ci -m "resurrected" foo
+
+Second, files can now be added or removed in a branch and later merged
+into the trunk.
+
+ cvs update -A
+ touch a b c
+ cvs add a b c ; cvs ci -m "added" a b c
+ cvs tag -b branchtag
+ cvs update -r branchtag
+ touch d ; cvs add d
+ rm a ; cvs rm a
+ cvs ci -m "added d, removed a"
+ cvs update -A
+ cvs update -jbranchtag
+
+Added and removed files may also be merged between branches.
+
+Files removed in the trunk may be merged into branches.
+
+Files added on the trunk are a special case. They cannot be merged
+into a branch. Instead, simply branch the file by hand.
+
+I also extended the "cvs update -j" semantic slightly. Like before,
+if you use two -j options, the changes made between the first and the
+second will be merged into your working files. This has not changed.
+
+If you use only one -j option, it is used as the second -j option.
+The first is assumed to be the greatest common ancestor revision
+between the revision specified by the -j and the BASE revision of your
+working file.
diff --git a/gnu/usr.bin/cvs/cvs/add.c b/gnu/usr.bin/cvs/cvs/add.c
new file mode 100644
index 0000000..f798a22
--- /dev/null
+++ b/gnu/usr.bin/cvs/cvs/add.c
@@ -0,0 +1,539 @@
+/*
+ * Copyright (c) 1992, Brian Berliner and Jeff Polk
+ * Copyright (c) 1989-1992, Brian Berliner
+ *
+ * You may distribute under the terms of the GNU General Public License as
+ * specified in the README file that comes with the CVS 1.4 kit.
+ *
+ * Add
+ *
+ * Adds a file or directory to the RCS source repository. For a file,
+ * the entry is marked as "needing to be added" in the user's own CVS
+ * directory, and really added to the repository when it is committed.
+ * For a directory, it is added at the appropriate place in the source
+ * repository and a CVS directory is generated within the directory.
+ *
+ * The -m option is currently the only supported option. Some may wish to
+ * supply standard "rcs" options here, but I've found that this causes more
+ * trouble than anything else.
+ *
+ * The user files or directories must already exist. For a directory, it must
+ * not already have a CVS file in it.
+ *
+ * An "add" on a file that has been "remove"d but not committed will cause the
+ * file to be resurrected.
+ */
+
+#include "cvs.h"
+#include "save-cwd.h"
+
+#ifndef lint
+static const char rcsid[] = "$CVSid: @(#)add.c 1.55 94/10/22 $";
+USE(rcsid);
+#endif
+
+static int add_directory PROTO((char *repository, char *dir));
+static int build_entry PROTO((char *repository, char *user, char *options,
+ char *message, List * entries, char *tag));
+
+static const char *const add_usage[] =
+{
+ "Usage: %s %s [-k rcs-kflag] [-m message] files...\n",
+ "\t-k\tUse \"rcs-kflag\" to add the file with the specified kflag.\n",
+ "\t-m\tUse \"message\" for the creation log.\n",
+ NULL
+};
+
+int
+add (argc, argv)
+ int argc;
+ char **argv;
+{
+ char *message = NULL;
+ char *user;
+ int i;
+ char *repository;
+ int c;
+ int err = 0;
+ int added_files = 0;
+ char *options = NULL;
+ List *entries;
+ Vers_TS *vers;
+
+ if (argc == 1 || argc == -1)
+ usage (add_usage);
+
+ wrap_setup ();
+
+ /* parse args */
+ optind = 1;
+ while ((c = getopt (argc, argv, "k:m:")) != -1)
+ {
+ switch (c)
+ {
+ case 'k':
+ if (options)
+ free (options);
+ options = RCS_check_kflag (optarg);
+ break;
+
+ case 'm':
+ message = xstrdup (optarg);
+ break;
+ case '?':
+ default:
+ usage (add_usage);
+ break;
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (argc <= 0)
+ usage (add_usage);
+
+ /* find the repository associated with our current dir */
+ repository = Name_Repository ((char *) NULL, (char *) NULL);
+
+#ifdef CLIENT_SUPPORT
+ if (client_active)
+ {
+ int i;
+ start_server ();
+ ign_setup ();
+ if (options) send_arg(options);
+ option_with_arg ("-m", message);
+ for (i = 0; i < argc; ++i)
+ /* FIXME: Does this erroneously call Create_Admin in error
+ conditions which are only detected once the server gets its
+ hands on things? */
+ if (isdir (argv[i]))
+ {
+ char *tag;
+ char *date;
+ char *rcsdir = xmalloc (strlen (repository)
+ + strlen (argv[i]) + 10);
+
+ /* before we do anything else, see if we have any
+ per-directory tags */
+ ParseTag (&tag, &date);
+
+ sprintf (rcsdir, "%s/%s", repository, argv[i]);
+
+ Create_Admin (argv[i], argv[i], rcsdir, tag, date);
+
+ if (tag)
+ free (tag);
+ if (date)
+ free (date);
+ free (rcsdir);
+ }
+ send_files (argc, argv, 0, 0);
+ if (fprintf (to_server, "add\n") < 0)
+ error (1, errno, "writing to server");
+ return get_responses_and_close ();
+ }
+#endif
+
+ entries = Entries_Open (0);
+
+ /* walk the arg list adding files/dirs */
+ for (i = 0; i < argc; i++)
+ {
+ int begin_err = err;
+ int begin_added_files = added_files;
+
+ user = argv[i];
+ strip_trailing_slashes (user);
+ if (strchr (user, '/') != NULL)
+ {
+ error (0, 0,
+ "cannot add files with '/' in their name; %s not added", user);
+ err++;
+ continue;
+ }
+
+ vers = Version_TS (repository, options, (char *) NULL, (char *) NULL,
+ user, 0, 0, entries, (List *) NULL);
+ if (vers->vn_user == NULL)
+ {
+ /* No entry available, ts_rcs is invalid */
+ if (vers->vn_rcs == NULL)
+ {
+ /* There is no RCS file either */
+ if (vers->ts_user == NULL)
+ {
+ /* There is no user file either */
+ error (0, 0, "nothing known about %s", user);
+ err++;
+ }
+ else if (!isdir (user) || wrap_name_has (user, WRAP_TOCVS))
+ {
+ /*
+ * See if a directory exists in the repository with
+ * the same name. If so, blow this request off.
+ */
+ char dname[PATH_MAX];
+ (void) sprintf (dname, "%s/%s", repository, user);
+ if (isdir (dname))
+ {
+ error (0, 0,
+ "cannot add file `%s' since the directory",
+ user);
+ error (0, 0, "`%s' already exists in the repository",
+ dname);
+ error (1, 0, "illegal filename overlap");
+ }
+
+ /* There is a user file, so build the entry for it */
+ if (build_entry (repository, user, vers->options,
+ message, entries, vers->tag) != 0)
+ err++;
+ else
+ {
+ added_files++;
+ if (!quiet)
+ {
+#ifdef DEATH_SUPPORT
+ if (vers->tag)
+ error (0, 0, "\
+scheduling %s `%s' for addition on branch `%s'",
+ (wrap_name_has (user, WRAP_TOCVS)
+ ? "wrapper"
+ : "file"),
+ user, vers->tag);
+ else
+#endif /* DEATH_SUPPORT */
+ error (0, 0, "scheduling %s `%s' for addition",
+ (wrap_name_has (user, WRAP_TOCVS)
+ ? "wrapper"
+ : "file"),
+ user);
+ }
+ }
+ }
+ }
+#ifdef DEATH_SUPPORT
+ else if (RCS_isdead (vers->srcfile, vers->vn_rcs))
+ {
+ if (isdir (user) && !wrap_name_has (user, WRAP_TOCVS))
+ {
+ error (0, 0, "the directory `%s' cannot be added because a file of the", user);
+ error (1, 0, "same name already exists in the repository.");
+ }
+ else
+ {
+ if (vers->tag)
+ error (0, 0, "file `%s' will be added on branch `%s' from version %s",
+ user, vers->tag, vers->vn_rcs);
+ else
+ error (0, 0, "version %s of `%s' will be resurrected",
+ vers->vn_rcs, user);
+ Register (entries, user, "0", vers->ts_user, NULL,
+ vers->tag, NULL, NULL);
+ ++added_files;
+ }
+ }
+#endif /* DEATH_SUPPORT */
+ else
+ {
+ /*
+ * There is an RCS file already, so somebody else must've
+ * added it
+ */
+ error (0, 0, "%s added independently by second party", user);
+ err++;
+ }
+ }
+ else if (vers->vn_user[0] == '0' && vers->vn_user[1] == '\0')
+ {
+
+ /*
+ * An entry for a new-born file, ts_rcs is dummy, but that is
+ * inappropriate here
+ */
+ error (0, 0, "%s has already been entered", user);
+ err++;
+ }
+ else if (vers->vn_user[0] == '-')
+ {
+ /* An entry for a removed file, ts_rcs is invalid */
+ if (vers->ts_user == NULL)
+ {
+ /* There is no user file (as it should be) */
+ if (vers->vn_rcs == NULL)
+ {
+
+ /*
+ * There is no RCS file, so somebody else must've removed
+ * it from under us
+ */
+ error (0, 0,
+ "cannot resurrect %s; RCS file removed by second party", user);
+ err++;
+ }
+ else
+ {
+
+ /*
+ * There is an RCS file, so remove the "-" from the
+ * version number and restore the file
+ */
+ char *tmp = xmalloc (strlen (user) + 50);
+
+ (void) strcpy (tmp, vers->vn_user + 1);
+ (void) strcpy (vers->vn_user, tmp);
+ (void) sprintf (tmp, "Resurrected %s", user);
+ Register (entries, user, vers->vn_user, tmp, vers->options,
+ vers->tag, vers->date, vers->ts_conflict);
+ free (tmp);
+
+ /* XXX - bugs here; this really resurrect the head */
+ /* Note that this depends on the Register above actually
+ having written Entries, or else it won't really
+ check the file out. */
+ if (update (2, argv + i - 1) == 0)
+ {
+ error (0, 0, "%s, version %s, resurrected", user,
+ vers->vn_user);
+ }
+ else
+ {
+ error (0, 0, "could not resurrect %s", user);
+ err++;
+ }
+ }
+ }
+ else
+ {
+ /* The user file shouldn't be there */
+ error (0, 0, "%s should be removed and is still there (or is back again)", user);
+ err++;
+ }
+ }
+ else
+ {
+ /* A normal entry, ts_rcs is valid, so it must already be there */
+ error (0, 0, "%s already exists, with version number %s", user,
+ vers->vn_user);
+ err++;
+ }
+ freevers_ts (&vers);
+
+ /* passed all the checks. Go ahead and add it if its a directory */
+ if (begin_err == err
+ && isdir (user)
+ && !wrap_name_has (user, WRAP_TOCVS))
+ {
+ err += add_directory (repository, user);
+ continue;
+ }
+#ifdef SERVER_SUPPORT
+ if (server_active && begin_added_files != added_files)
+ server_checked_in (user, ".", repository);
+#endif
+ }
+ if (added_files)
+ error (0, 0, "use 'cvs commit' to add %s permanently",
+ (added_files == 1) ? "this file" : "these files");
+
+ Entries_Close (entries);
+
+ if (message)
+ free (message);
+
+ return (err);
+}
+
+/*
+ * The specified user file is really a directory. So, let's make sure that
+ * it is created in the RCS source repository, and that the user's directory
+ * is updated to include a CVS directory.
+ *
+ * Returns 1 on failure, 0 on success.
+ */
+static int
+add_directory (repository, dir)
+ char *repository;
+ char *dir;
+{
+ char rcsdir[PATH_MAX];
+ struct saved_cwd cwd;
+ char message[PATH_MAX + 100];
+ char *tag, *date;
+
+ if (strchr (dir, '/') != NULL)
+ {
+ error (0, 0,
+ "directory %s not added; must be a direct sub-directory", dir);
+ return (1);
+ }
+ if (strcmp (dir, CVSADM) == 0)
+ {
+ error (0, 0, "cannot add a `%s' directory", CVSADM);
+ return (1);
+ }
+
+ /* before we do anything else, see if we have any per-directory tags */
+ ParseTag (&tag, &date);
+
+ /* now, remember where we were, so we can get back */
+ if (save_cwd (&cwd))
+ return (1);
+ if (chdir (dir) < 0)
+ {
+ error (0, errno, "cannot chdir to %s", dir);
+ return (1);
+ }
+#ifdef SERVER_SUPPORT
+ if (!server_active && isfile (CVSADM))
+#else
+ if (isfile (CVSADM))
+#endif
+ {
+ error (0, 0, "%s/%s already exists", dir, CVSADM);
+ goto out;
+ }
+
+ (void) sprintf (rcsdir, "%s/%s", repository, dir);
+ if (isfile (rcsdir) && !isdir (rcsdir))
+ {
+ error (0, 0, "%s is not a directory; %s not added", rcsdir, dir);
+ goto out;
+ }
+
+ /* setup the log message */
+ (void) sprintf (message, "Directory %s added to the repository\n", rcsdir);
+ if (tag)
+ {
+ (void) strcat (message, "--> Using per-directory sticky tag `");
+ (void) strcat (message, tag);
+ (void) strcat (message, "'\n");
+ }
+ if (date)
+ {
+ (void) strcat (message, "--> Using per-directory sticky date `");
+ (void) strcat (message, date);
+ (void) strcat (message, "'\n");
+ }
+
+ if (!isdir (rcsdir))
+ {
+ mode_t omask;
+ Node *p;
+ List *ulist;
+
+#if 0
+ char line[MAXLINELEN];
+
+ (void) printf ("Add directory %s to the repository (y/n) [n] ? ",
+ rcsdir);
+ (void) fflush (stdout);
+ clearerr (stdin);
+ if (fgets (line, sizeof (line), stdin) == NULL ||
+ (line[0] != 'y' && line[0] != 'Y'))
+ {
+ error (0, 0, "directory %s not added", rcsdir);
+ goto out;
+ }
+#endif
+
+ omask = umask (cvsumask);
+ if (CVS_MKDIR (rcsdir, 0777) < 0)
+ {
+ error (0, errno, "cannot mkdir %s", rcsdir);
+ (void) umask (omask);
+ goto out;
+ }
+ (void) umask (omask);
+
+ /*
+ * Set up an update list with a single title node for Update_Logfile
+ */
+ ulist = getlist ();
+ p = getnode ();
+ p->type = UPDATE;
+ p->delproc = update_delproc;
+ p->key = xstrdup ("- New directory");
+ p->data = (char *) T_TITLE;
+ (void) addnode (ulist, p);
+ Update_Logfile (rcsdir, message, (char *) NULL, (FILE *) NULL, ulist);
+ dellist (&ulist);
+ }
+
+#ifdef SERVER_SUPPORT
+ if (!server_active)
+ Create_Admin (".", dir, rcsdir, tag, date);
+#else
+ Create_Admin (".", dir, rcsdir, tag, date);
+#endif
+ if (tag)
+ free (tag);
+ if (date)
+ free (date);
+
+ (void) printf ("%s", message);
+out:
+ if (restore_cwd (&cwd, NULL))
+ exit (1);
+ free_cwd (&cwd);
+ return (0);
+}
+
+/*
+ * Builds an entry for a new file and sets up "CVS/file",[pt] by
+ * interrogating the user. Returns non-zero on error.
+ */
+static int
+build_entry (repository, user, options, message, entries, tag)
+ char *repository;
+ char *user;
+ char *options;
+ char *message;
+ List *entries;
+ char *tag;
+{
+ char fname[PATH_MAX];
+ char line[MAXLINELEN];
+ FILE *fp;
+
+#ifndef DEATH_SUPPORT
+ /* when using the rcs death support, this case is not a problem. */
+ /*
+ * There may be an old file with the same name in the Attic! This is,
+ * perhaps, an awkward place to check for this, but other places are
+ * equally awkward.
+ */
+ (void) sprintf (fname, "%s/%s/%s%s", repository, CVSATTIC, user, RCSEXT);
+ if (isreadable (fname))
+ {
+ error (0, 0, "there is an old file %s already in %s/%s", user,
+ repository, CVSATTIC);
+ return (1);
+ }
+#endif /* no DEATH_SUPPORT */
+
+ if (noexec)
+ return (0);
+
+ /*
+ * The requested log is read directly from the user and stored in the
+ * file user,t. If the "message" argument is set, use it as the
+ * initial creation log (which typically describes the file).
+ */
+ (void) sprintf (fname, "%s/%s%s", CVSADM, user, CVSEXT_LOG);
+ fp = open_file (fname, "w+");
+ if (message && fputs (message, fp) == EOF)
+ error (1, errno, "cannot write to %s", fname);
+ if (fclose(fp) == EOF)
+ error(1, errno, "cannot close %s", fname);
+
+ /*
+ * Create the entry now, since this allows the user to interrupt us above
+ * without needing to clean anything up (well, we could clean up the
+ * ,t file, but who cares).
+ */
+ (void) sprintf (line, "Initial %s", user);
+ Register (entries, user, "0", line, options, tag, (char *) 0, (char *) 0);
+ return (0);
+}
diff --git a/gnu/usr.bin/cvs/cvs/admin.c b/gnu/usr.bin/cvs/cvs/admin.c
new file mode 100644
index 0000000..f12e143
--- /dev/null
+++ b/gnu/usr.bin/cvs/cvs/admin.c
@@ -0,0 +1,179 @@
+/*
+ * Copyright (c) 1992, Brian Berliner and Jeff Polk
+ * Copyright (c) 1989-1992, Brian Berliner
+ *
+ * You may distribute under the terms of the GNU General Public License as
+ * specified in the README file that comes with the CVS 1.4 kit.
+ *
+ * Administration
+ *
+ * For now, this is basically a front end for rcs. All options are passed
+ * directly on.
+ */
+
+#include "cvs.h"
+#ifdef CVS_ADMIN_GROUP
+#include <grp.h>
+#endif
+
+#ifndef lint
+static const char rcsid[] = "$CVSid: @(#)admin.c 1.20 94/09/30 $";
+USE(rcsid);
+#endif
+
+static Dtype admin_dirproc PROTO((char *dir, char *repos, char *update_dir));
+static int admin_fileproc PROTO((char *file, char *update_dir,
+ char *repository, List *entries,
+ List *srcfiles));
+
+static const char *const admin_usage[] =
+{
+ "Usage: %s %s rcs-options files...\n",
+ NULL
+};
+
+static int ac;
+static char **av;
+
+int
+admin (argc, argv)
+ int argc;
+ char **argv;
+{
+ int err;
+#ifdef CVS_ADMIN_GROUP
+ struct group *grp;
+#endif
+ if (argc <= 1)
+ usage (admin_usage);
+
+#ifdef CVS_ADMIN_GROUP
+ grp = getgrnam(CVS_ADMIN_GROUP);
+ /* skip usage right check if group CVS_ADMIN_GROUP does not exist */
+ if (grp != NULL)
+ {
+ char *me = getcaller();
+ char **grnam = grp->gr_mem;
+ int denied = 1;
+
+ while (*grnam)
+ {
+ if (strcmp(*grnam, me) == 0)
+ {
+ denied = 0;
+ break;
+ }
+ grnam++;
+ }
+
+ if (denied)
+ error (1, 0, "usage is restricted to members of the group %s",
+ CVS_ADMIN_GROUP);
+ }
+#endif
+
+ wrap_setup ();
+
+ /* skip all optional arguments to see if we have any file names */
+ for (ac = 1; ac < argc; ac++)
+ if (argv[ac][0] != '-')
+ break;
+ argc -= ac;
+ av = argv + 1;
+ argv += ac;
+ ac--;
+ if (ac == 0 || argc == 0)
+ usage (admin_usage);
+
+#ifdef CLIENT_SUPPORT
+ if (client_active)
+ {
+ int i;
+
+ /* We're the client side. Fire up the remote server. */
+ start_server ();
+
+ ign_setup ();
+
+ for (i = 0; i <= ac; ++i) /* XXX send -ko too with i = 0 */
+ send_arg (av[i]);
+
+#if 0
+ /* FIXME: We shouldn't have to send current files, but I'm not sure
+ whether it works. So send the files --
+ it's slower but it works. */
+ send_file_names (argc, argv);
+#else
+ send_files (argc, argv, 0, 0);
+#endif
+ if (fprintf (to_server, "admin\n") < 0)
+ error (1, errno, "writing to server");
+ return get_responses_and_close ();
+ }
+#endif /* CLIENT_SUPPORT */
+
+ /* start the recursion processor */
+ err = start_recursion (admin_fileproc, (FILESDONEPROC) NULL, admin_dirproc,
+ (DIRLEAVEPROC) NULL, argc, argv, 0,
+ W_LOCAL, 0, 1, (char *) NULL, 1, 0);
+ return (err);
+}
+
+/*
+ * Called to run "rcs" on a particular file.
+ */
+/* ARGSUSED */
+static int
+admin_fileproc (file, update_dir, repository, entries, srcfiles)
+ char *file;
+ char *update_dir;
+ char *repository;
+ List *entries;
+ List *srcfiles;
+{
+ Vers_TS *vers;
+ char *version;
+ char **argv;
+ int argc;
+ int retcode = 0;
+
+ vers = Version_TS (repository, (char *) NULL, (char *) NULL, (char *) NULL,
+ file, 0, 0, entries, srcfiles);
+
+ version = vers->vn_user;
+ if (version == NULL)
+ return (0);
+ else if (strcmp (version, "0") == 0)
+ {
+ error (0, 0, "cannot admin newly added file `%s'", file);
+ return (0);
+ }
+
+ run_setup ("%s%s", Rcsbin, RCS);
+ for (argc = ac, argv = av; argc; argc--, argv++)
+ run_arg (*argv);
+ run_arg (vers->srcfile->path);
+ if ((retcode = run_exec (RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL)) != 0)
+ {
+ if (!quiet)
+ error (0, retcode == -1 ? errno : 0,
+ "%s failed for `%s'", RCS, file);
+ return (1);
+ }
+ return (0);
+}
+
+/*
+ * Print a warm fuzzy message
+ */
+/* ARGSUSED */
+static Dtype
+admin_dirproc (dir, repos, update_dir)
+ char *dir;
+ char *repos;
+ char *update_dir;
+{
+ if (!quiet)
+ error (0, 0, "Administrating %s", update_dir);
+ return (R_PROCESS);
+}
diff --git a/gnu/usr.bin/cvs/cvs/checkin.c b/gnu/usr.bin/cvs/cvs/checkin.c
new file mode 100644
index 0000000..ef3b81a
--- /dev/null
+++ b/gnu/usr.bin/cvs/cvs/checkin.c
@@ -0,0 +1,204 @@
+/*
+ * Copyright (c) 1992, Brian Berliner and Jeff Polk
+ * Copyright (c) 1989-1992, Brian Berliner
+ *
+ * You may distribute under the terms of the GNU General Public License as
+ * specified in the README file that comes with the CVS 1.4 kit.
+ *
+ * Check In
+ *
+ * Does a very careful checkin of the file "user", and tries not to spoil its
+ * modification time (to avoid needless recompilations). When RCS ID keywords
+ * get expanded on checkout, however, the modification time is updated and
+ * there is no good way to get around this.
+ *
+ * Returns non-zero on error.
+ */
+
+#include "cvs.h"
+
+#ifndef lint
+static const char rcsid[] = "$CVSid: @(#)checkin.c 1.48 94/10/07 $";
+USE(rcsid);
+#endif
+
+int
+Checkin (type, file, update_dir, repository,
+ rcs, rev, tag, options, message, entries)
+ int type;
+ char *file;
+ char *update_dir;
+ char *repository;
+ char *rcs;
+ char *rev;
+ char *tag;
+ char *options;
+ char *message;
+ List *entries;
+{
+ char fname[PATH_MAX];
+ Vers_TS *vers;
+ int set_time;
+ char *fullname;
+
+ char *tocvsPath = NULL;
+
+ fullname = xmalloc (strlen (update_dir) + strlen (file) + 10);
+ if (update_dir[0] == '\0')
+ strcpy (fullname, file);
+ else
+ sprintf (fullname, "%s/%s", update_dir, file);
+
+ (void) printf ("Checking in %s;\n", fullname);
+ (void) sprintf (fname, "%s/%s%s", CVSADM, CVSPREFIX, file);
+
+ /*
+ * Move the user file to a backup file, so as to preserve its
+ * modification times, then place a copy back in the original file name
+ * for the checkin and checkout.
+ */
+
+ tocvsPath = wrap_tocvs_process_file (fullname);
+
+ if (!noexec)
+ {
+ if (tocvsPath)
+ {
+ copy_file (tocvsPath, fname);
+ if (unlink_file_dir (file) < 0)
+ if (! existence_error (errno))
+ error (1, errno, "cannot remove %s", file);
+ copy_file (tocvsPath, file);
+ }
+ else
+ {
+ copy_file (file, fname);
+ }
+ }
+
+ run_setup ("%s%s -f %s%s", Rcsbin, RCS_CI,
+ rev ? "-r" : "", rev ? rev : "");
+ run_args ("-m%s", make_message_rcslegal (message));
+ run_arg (rcs);
+
+ switch (run_exec (RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL))
+ {
+ case 0: /* everything normal */
+
+ /*
+ * The checkin succeeded, so now check the new file back out and
+ * see if it matches exactly with the one we checked in. If it
+ * does, just move the original user file back, thus preserving
+ * the modes; otherwise, we have no recourse but to leave the
+ * newly checkout file as the user file and remove the old
+ * original user file.
+ */
+
+ if (strcmp (options, "-V4") == 0) /* upgrade to V5 now */
+ options[0] = '\0';
+ run_setup ("%s%s -q %s %s%s", Rcsbin, RCS_CO, options,
+ rev ? "-r" : "", rev ? rev : "");
+ run_arg (rcs);
+ (void) run_exec (RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL);
+ xchmod (file, 1);
+ if (xcmp (file, fname) == 0)
+ {
+ rename_file (fname, file);
+ /* the time was correct, so leave it alone */
+ set_time = 0;
+ }
+ else
+ {
+ if (unlink_file (fname) < 0)
+ error (0, errno, "cannot remove %s", fname);
+ /* sync up with the time from the RCS file */
+ set_time = 1;
+ }
+
+ wrap_fromcvs_process_file (file);
+
+ /*
+ * If we want read-only files, muck the permissions here, before
+ * getting the file time-stamp.
+ */
+ if (cvswrite == FALSE)
+ xchmod (file, 0);
+
+#ifndef DEATH_SUPPORT
+ /* With death_support, files added with tags go into branches immediately. */
+
+ /* for added files with symbolic tags, need to add the tag too */
+ if (type == 'A' && tag && !isdigit (*tag))
+ {
+ (void) RCS_settag(rcs, tag, rev);
+ }
+#endif /* No DEATH_SUPPORT */
+
+ /* re-register with the new data */
+ vers = Version_TS (repository, (char *) NULL, tag, (char *) NULL,
+ file, 1, set_time, entries, (List *) NULL);
+ if (strcmp (vers->options, "-V4") == 0)
+ vers->options[0] = '\0';
+ Register (entries, file, vers->vn_rcs, vers->ts_user,
+ vers->options, vers->tag, vers->date, (char *) 0);
+ history_write (type, (char *) 0, vers->vn_rcs, file, repository);
+ freevers_ts (&vers);
+
+ if (tocvsPath)
+ if (unlink_file_dir (tocvsPath) < 0)
+ error (0, errno, "cannot remove %s", tocvsPath);
+
+ break;
+
+ case -1: /* fork failed */
+ if (tocvsPath)
+ if (unlink_file_dir (tocvsPath) < 0)
+ error (0, errno, "cannot remove %s", tocvsPath);
+
+ if (!noexec)
+ error (1, errno, "could not check in %s -- fork failed",
+ fullname);
+ return (1);
+
+ default: /* ci failed */
+
+ /*
+ * The checkin failed, for some unknown reason, so we restore the
+ * original user file, print an error, and return an error
+ */
+ if (tocvsPath)
+ if (unlink_file_dir (tocvsPath) < 0)
+ error (0, errno, "cannot remove %s", tocvsPath);
+
+ if (!noexec)
+ {
+ rename_file (fname, file);
+ error (0, 0, "could not check in %s", fullname);
+ }
+ return (1);
+ }
+
+ /*
+ * When checking in a specific revision, we may have locked the wrong
+ * branch, so to be sure, we do an extra unlock here before
+ * returning.
+ */
+ if (rev)
+ {
+ (void) RCS_unlock (rcs, NULL, 1);
+ }
+
+#ifdef SERVER_SUPPORT
+ if (server_active)
+ {
+ if (set_time)
+ /* Need to update the checked out file on the client side. */
+ server_updated (file, update_dir, repository, SERVER_UPDATED,
+ NULL, NULL);
+ else
+ server_checked_in (file, update_dir, repository);
+ }
+#endif
+
+ return (0);
+}
diff --git a/gnu/usr.bin/cvs/cvs/checkout.c b/gnu/usr.bin/cvs/cvs/checkout.c
new file mode 100644
index 0000000..bb126dd
--- /dev/null
+++ b/gnu/usr.bin/cvs/cvs/checkout.c
@@ -0,0 +1,874 @@
+/*
+ * Copyright (c) 1992, Brian Berliner and Jeff Polk
+ * Copyright (c) 1989-1992, Brian Berliner
+ *
+ * You may distribute under the terms of the GNU General Public License as
+ * specified in the README file that comes with the CVS 1.4 kit.
+ *
+ * Create Version
+ *
+ * "checkout" creates a "version" of an RCS repository. This version is owned
+ * totally by the user and is actually an independent copy, to be dealt with
+ * as seen fit. Once "checkout" has been called in a given directory, it
+ * never needs to be called again. The user can keep up-to-date by calling
+ * "update" when he feels like it; this will supply him with a merge of his
+ * own modifications and the changes made in the RCS original. See "update"
+ * for details.
+ *
+ * "checkout" can be given a list of directories or files to be updated and in
+ * the case of a directory, will recursivley create any sub-directories that
+ * exist in the repository.
+ *
+ * When the user is satisfied with his own modifications, the present version
+ * can be committed by "commit"; this keeps the present version in tact,
+ * usually.
+ *
+ * The call is cvs checkout [options] <module-name>...
+ *
+ * "checkout" creates a directory ./CVS, in which it keeps its administration,
+ * in two files, Repository and Entries. The first contains the name of the
+ * repository. The second contains one line for each registered file,
+ * consisting of the version number it derives from, its time stamp at
+ * derivation time and its name. Both files are normal files and can be
+ * edited by the user, if necessary (when the repository is moved, e.g.)
+ */
+
+#include "cvs.h"
+
+#ifndef lint
+static const char rcsid[] = "$CVSid: @(#)checkout.c 1.78 94/10/07 $";
+USE(rcsid);
+#endif
+
+static char *findslash PROTO((char *start, char *p));
+static int build_dirs_and_chdir PROTO((char *dir, char *prepath, char *realdir,
+ int sticky));
+static int checkout_proc PROTO((int *pargc, char **argv, char *where,
+ char *mwhere, char *mfile, int shorten,
+ int local_specified, char *omodule,
+ char *msg));
+static int safe_location PROTO((void));
+
+static const char *const checkout_usage[] =
+{
+ "Usage:\n %s %s [-ANPcflnps] [-r rev | -D date] [-d dir] [-k kopt] modules...\n",
+ "\t-A\tReset any sticky tags/date/kopts.\n",
+ "\t-N\tDon't shorten module paths if -d specified.\n",
+ "\t-P\tPrune empty directories.\n",
+ "\t-c\t\"cat\" the module database.\n",
+ "\t-f\tForce a head revision match if tag/date not found.\n",
+ "\t-l\tLocal directory only, not recursive\n",
+ "\t-n\tDo not run module program (if any).\n",
+ "\t-p\tCheck out files to standard output.\n",
+ "\t-s\tLike -c, but include module status.\n",
+ "\t-r rev\tCheck out revision or tag. (implies -P)\n",
+ "\t-D date\tCheck out revisions as of date. (implies -P)\n",
+ "\t-d dir\tCheck out into dir instead of module name.\n",
+ "\t-k kopt\tUse RCS kopt -k option on checkout.\n",
+ "\t-j rev\tMerge in changes made between current revision and rev.\n",
+ NULL
+};
+
+static const char *const export_usage[] =
+{
+ "Usage: %s %s [-NPfln] [-r rev | -D date] [-d dir] [-k kopt] module...\n",
+ "\t-N\tDon't shorten module paths if -d specified.\n",
+ "\t-f\tForce a head revision match if tag/date not found.\n",
+ "\t-l\tLocal directory only, not recursive\n",
+ "\t-n\tDo not run module program (if any).\n",
+ "\t-r rev\tCheck out revision or tag.\n",
+ "\t-D date\tCheck out revisions as of date.\n",
+ "\t-d dir\tCheck out into dir instead of module name.\n",
+ "\t-k kopt\tUse RCS kopt -k option on checkout.\n",
+ NULL
+};
+
+static int checkout_prune_dirs;
+static int force_tag_match = 1;
+static int pipeout;
+static int aflag;
+static char *options = NULL;
+static char *tag = NULL;
+static char *date = NULL;
+static char *join_rev1 = NULL;
+static char *join_rev2 = NULL;
+static char *preload_update_dir = NULL;
+
+int
+checkout (argc, argv)
+ int argc;
+ char **argv;
+{
+ int i;
+ int c;
+ DBM *db;
+ int cat = 0, err = 0, status = 0;
+ int run_module_prog = 1;
+ int local = 0;
+ int shorten = -1;
+ char *where = NULL;
+ char *valid_options;
+ const char *const *valid_usage;
+ enum mtype m_type;
+
+ /*
+ * A smaller subset of options are allowed for the export command, which
+ * is essentially like checkout, except that it hard-codes certain
+ * options to be default (like -kv) and takes care to remove the CVS
+ * directory when it has done its duty
+ */
+ if (strcmp (command_name, "export") == 0)
+ {
+ m_type = EXPORT;
+ valid_options = "Nnk:d:flRQqr:D:";
+ valid_usage = export_usage;
+ }
+ else
+ {
+ m_type = CHECKOUT;
+ valid_options = "ANnk:d:flRpQqcsr:D:j:P";
+ valid_usage = checkout_usage;
+ }
+
+ if (argc == -1)
+ usage (valid_usage);
+
+ ign_setup ();
+ wrap_setup ();
+
+ optind = 1;
+ while ((c = getopt (argc, argv, valid_options)) != -1)
+ {
+ switch (c)
+ {
+ case 'A':
+ aflag = 1;
+ break;
+ case 'N':
+ shorten = 0;
+ break;
+ case 'k':
+ if (options)
+ free (options);
+ options = RCS_check_kflag (optarg);
+ break;
+ case 'n':
+ run_module_prog = 0;
+ break;
+ case 'Q':
+ case 'q':
+#ifdef SERVER_SUPPORT
+ /* The CVS 1.5 client sends these options (in addition to
+ Global_option requests), so we must ignore them. */
+ if (!server_active)
+#endif
+ error (1, 0,
+ "-q or -Q must be specified before \"%s\"",
+ command_name);
+ break;
+ case 'l':
+ local = 1;
+ break;
+ case 'R':
+ local = 0;
+ break;
+ case 'P':
+ checkout_prune_dirs = 1;
+ break;
+ case 'p':
+ pipeout = 1;
+ run_module_prog = 0; /* don't run module prog when piping */
+ noexec = 1; /* so no locks will be created */
+ break;
+ case 'c':
+ cat = 1;
+ break;
+ case 'd':
+ where = optarg;
+ if (shorten == -1)
+ shorten = 1;
+ break;
+ case 's':
+ status = 1;
+ break;
+ case 'f':
+ force_tag_match = 0;
+ break;
+ case 'r':
+ tag = optarg;
+ checkout_prune_dirs = 1;
+ break;
+ case 'D':
+ date = Make_Date (optarg);
+ checkout_prune_dirs = 1;
+ break;
+ case 'j':
+ if (join_rev2)
+ error (1, 0, "only two -j options can be specified");
+ if (join_rev1)
+ join_rev2 = optarg;
+ else
+ join_rev1 = optarg;
+ break;
+ case '?':
+ default:
+ usage (valid_usage);
+ break;
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (shorten == -1)
+ shorten = 0;
+
+ if ((!(cat + status) && argc == 0) || ((cat + status) && argc != 0)
+ || (tag && date))
+ usage (valid_usage);
+
+ if (where && pipeout)
+ error (1, 0, "-d and -p are mutually exclusive");
+
+ if (strcmp (command_name, "export") == 0)
+ {
+ if (!tag && !date)
+ {
+ error (0, 0, "must specify a tag or date");
+ usage (valid_usage);
+ }
+ if (tag && isdigit (tag[0]))
+ error (1, 0, "tag `%s' must be a symbolic tag", tag);
+/*
+ * mhy 950615: -kv doesn't work for binaries with RCS keywords.
+ * Instead use the default provided in the RCS file (-ko for binaries).
+ */
+#if 0
+ if (!options)
+ options = RCS_check_kflag ("v");/* -kv is default */
+#endif
+ }
+
+ if (!safe_location()) {
+ error(1, 0, "Cannot check out files into the repository itself");
+ }
+
+#ifdef CLIENT_SUPPORT
+ if (client_active)
+ {
+ int expand_modules;
+
+ start_server ();
+
+ ign_setup ();
+
+ /* We have to expand names here because the "expand-modules"
+ directive to the server has the side-effect of having the
+ server send the check-in and update programs for the
+ various modules/dirs requested. If we turn this off and
+ simply request the names of the modules and directories (as
+ below in !expand_modules), those files (CVS/Checking.prog
+ or CVS/Update.prog) don't get created. Grrr. */
+
+ expand_modules = (!cat && !status && !pipeout
+ && supported_request ("expand-modules"));
+
+ if (expand_modules)
+ {
+ /* This is done here because we need to read responses
+ from the server before we send the command checkout or
+ export files. */
+
+ client_expand_modules (argc, argv, local);
+ }
+
+ if (!run_module_prog) send_arg ("-n");
+ if (local) send_arg ("-l");
+ if (pipeout) send_arg ("-p");
+ if (!force_tag_match) send_arg ("-f");
+ if (aflag)
+ send_arg("-A");
+ if (!shorten)
+ send_arg("-N");
+ if (checkout_prune_dirs && strcmp (command_name, "export") != 0)
+ send_arg("-P");
+ client_prune_dirs = checkout_prune_dirs;
+ if (cat)
+ send_arg("-c");
+ if (where != NULL)
+ {
+ option_with_arg ("-d", where);
+ }
+ if (status)
+ send_arg("-s");
+ if (strcmp (command_name, "export") != 0
+ && options != NULL
+ && options[0] != '\0')
+ send_arg (options);
+ option_with_arg ("-r", tag);
+ if (date)
+ client_senddate (date);
+ if (join_rev1 != NULL)
+ option_with_arg ("-j", join_rev1);
+ if (join_rev2 != NULL)
+ option_with_arg ("-j", join_rev2);
+
+ if (expand_modules)
+ {
+ client_send_expansions (local);
+ }
+ else
+ {
+ int i;
+ for (i = 0; i < argc; ++i)
+ send_arg (argv[i]);
+ client_nonexpanded_setup ();
+ }
+
+ if (fprintf
+ (to_server,
+ strcmp (command_name, "export") == 0 ? "export\n" : "co\n")
+ < 0)
+ error (1, errno, "writing to server");
+
+ return get_responses_and_close ();
+ }
+#endif
+
+ if (cat || status)
+ {
+ cat_module (status);
+ return (0);
+ }
+ db = open_module ();
+
+ /*
+ * if we have more than one argument and where was specified, we make the
+ * where, cd into it, and try to shorten names as much as possible.
+ * Otherwise, we pass the where as a single argument to do_module.
+ */
+ if (argc > 1 && where != NULL)
+ {
+ char repository[PATH_MAX];
+
+ (void) CVS_MKDIR (where, 0777);
+ if (chdir (where) < 0)
+ error (1, errno, "cannot chdir to %s", where);
+ preload_update_dir = xstrdup (where);
+ where = (char *) NULL;
+ if (!isfile (CVSADM))
+ {
+ (void) sprintf (repository, "%s/%s/%s", CVSroot, CVSROOTADM,
+ CVSNULLREPOS);
+ if (!isfile (repository))
+ {
+ mode_t omask;
+ omask = umask (cvsumask);
+ (void) CVS_MKDIR (repository, 0777);
+ (void) umask (omask);
+ }
+
+ /* I'm not sure whether this check is redundant. */
+ if (!isdir (repository))
+ error (1, 0, "there is no repository %s", repository);
+
+ Create_Admin (".", where, repository,
+ (char *) NULL, (char *) NULL);
+ if (!noexec)
+ {
+ FILE *fp;
+
+ fp = open_file (CVSADM_ENTSTAT, "w+");
+ if (fclose(fp) == EOF)
+ error(1, errno, "cannot close %s", CVSADM_ENTSTAT);
+#ifdef SERVER_SUPPORT
+ if (server_active)
+ server_set_entstat (preload_update_dir, repository);
+#endif
+ }
+ }
+ }
+
+ /*
+ * if where was specified (-d) and we have not taken care of it already
+ * with the multiple arg stuff, and it was not a simple directory name
+ * but rather a path, we strip off everything but the last component and
+ * attempt to cd to the indicated place. where then becomes simply the
+ * last component
+ */
+ if (where != NULL && strchr (where, '/') != NULL)
+ {
+ char *slash;
+
+ slash = strrchr (where, '/');
+ *slash = '\0';
+
+ if (chdir (where) < 0)
+ error (1, errno, "cannot chdir to %s", where);
+
+ preload_update_dir = xstrdup (where);
+
+ where = slash + 1;
+ if (*where == '\0')
+ where = NULL;
+ }
+
+ for (i = 0; i < argc; i++)
+ err += do_module (db, argv[i], m_type, "Updating", checkout_proc,
+ where, shorten, local, run_module_prog,
+ (char *) NULL);
+ close_module (db);
+ return (err);
+}
+
+static int
+safe_location ()
+{
+ char current[PATH_MAX];
+ char hardpath[PATH_MAX+5];
+ int x;
+
+ x = readlink(CVSroot, hardpath, sizeof hardpath - 1);
+ if (x == -1)
+ {
+ strcpy(hardpath, CVSroot);
+ }
+ hardpath[x] = '\0';
+ getwd (current);
+ if (strncmp(current, hardpath, strlen(hardpath)) == 0)
+ {
+ return (0);
+ }
+ return (1);
+}
+
+/*
+ * process_module calls us back here so we do the actual checkout stuff
+ */
+/* ARGSUSED */
+static int
+checkout_proc (pargc, argv, where, mwhere, mfile, shorten,
+ local_specified, omodule, msg)
+ int *pargc;
+ char **argv;
+ char *where;
+ char *mwhere;
+ char *mfile;
+ int shorten;
+ int local_specified;
+ char *omodule;
+ char *msg;
+{
+ int err = 0;
+ int which;
+ char *cp;
+ char *cp2;
+ char repository[PATH_MAX];
+ char xwhere[PATH_MAX];
+ char *oldupdate = NULL;
+ char *prepath;
+ char *realdirs;
+
+ /*
+ * OK, so we're doing the checkout! Our args are as follows:
+ * argc,argv contain either dir or dir followed by a list of files
+ * where contains where to put it (if supplied by checkout)
+ * mwhere contains the module name or -d from module file
+ * mfile says do only that part of the module
+ * shorten = TRUE says shorten as much as possible
+ * omodule is the original arg to do_module()
+ */
+
+ /* set up the repository (maybe) for the bottom directory */
+ (void) sprintf (repository, "%s/%s", CVSroot, argv[0]);
+
+ /* save the original value of preload_update_dir */
+ if (preload_update_dir != NULL)
+ oldupdate = xstrdup (preload_update_dir);
+
+ /* fix up argv[] for the case of partial modules */
+ if (mfile != NULL)
+ {
+ char file[PATH_MAX];
+
+ /* if mfile is really a path, straighten it out first */
+ if ((cp = strrchr (mfile, '/')) != NULL)
+ {
+ *cp = 0;
+ (void) strcat (repository, "/");
+ (void) strcat (repository, mfile);
+
+ /*
+ * Now we need to fill in the where correctly. if !shorten, tack
+ * the rest of the path onto where if where is filled in
+ * otherwise tack the rest of the path onto mwhere and make that
+ * the where
+ *
+ * If shorten is enabled, we might use mwhere to set where if
+ * nobody set it yet, so we'll need to setup mwhere as the last
+ * component of the path we are tacking onto repository
+ */
+ if (!shorten)
+ {
+ if (where != NULL)
+ (void) sprintf (xwhere, "%s/%s", where, mfile);
+ else
+ (void) sprintf (xwhere, "%s/%s", mwhere, mfile);
+ where = xwhere;
+ }
+ else
+ {
+ char *slash;
+
+ if ((slash = strrchr (mfile, '/')) != NULL)
+ mwhere = slash + 1;
+ else
+ mwhere = mfile;
+ }
+ mfile = cp + 1;
+ }
+
+ (void) sprintf (file, "%s/%s", repository, mfile);
+ if (isdir (file))
+ {
+
+ /*
+ * The portion of a module was a directory, so kludge up where to
+ * be the subdir, and fix up repository
+ */
+ (void) strcpy (repository, file);
+
+ /*
+ * At this point, if shorten is not enabled, we make where either
+ * where with mfile concatenated, or if where hadn't been set we
+ * set it to mwhere with mfile concatenated.
+ *
+ * If shorten is enabled and where hasn't been set yet, then where
+ * becomes mfile
+ */
+ if (!shorten)
+ {
+ if (where != NULL)
+ (void) sprintf (xwhere, "%s/%s", where, mfile);
+ else
+ (void) sprintf (xwhere, "%s/%s", mwhere, mfile);
+ where = xwhere;
+ }
+ else if (where == NULL)
+ where = mfile;
+ }
+ else
+ {
+ int i;
+
+ /*
+ * The portion of a module was a file, so kludge up argv to be
+ * correct
+ */
+ for (i = 1; i < *pargc; i++)/* free the old ones */
+ free (argv[i]);
+ argv[1] = xstrdup (mfile); /* set up the new one */
+ *pargc = 2;
+
+ /* where gets mwhere if where isn't set */
+ if (where == NULL)
+ where = mwhere;
+ }
+ }
+
+ /*
+ * if shorten is enabled and where isn't specified yet, we pluck the last
+ * directory component of argv[0] and make it the where
+ */
+ if (shorten && where == NULL)
+ {
+ if ((cp = strrchr (argv[0], '/')) != NULL)
+ {
+ (void) strcpy (xwhere, cp + 1);
+ where = xwhere;
+ }
+ }
+
+ /* if where is still NULL, use mwhere if set or the argv[0] dir */
+ if (where == NULL)
+ {
+ if (mwhere)
+ where = mwhere;
+ else
+ {
+ (void) strcpy (xwhere, argv[0]);
+ where = xwhere;
+ }
+ }
+
+ if (preload_update_dir != NULL)
+ {
+ char tmp[PATH_MAX];
+
+ (void) sprintf (tmp, "%s/%s", preload_update_dir, where);
+ free (preload_update_dir);
+ preload_update_dir = xstrdup (tmp);
+ }
+ else
+ preload_update_dir = xstrdup (where);
+
+ /*
+ * At this point, where is the directory we want to build, repository is
+ * the repository for the lowest level of the path.
+ */
+
+ /*
+ * If we are sending everything to stdout, we can skip a whole bunch of
+ * work from here
+ */
+ if (!pipeout)
+ {
+
+ /*
+ * We need to tell build_dirs not only the path we want it to build,
+ * but also the repositories we want it to populate the path with. To
+ * accomplish this, we pass build_dirs a ``real path'' with valid
+ * repositories and a string to pre-pend based on how many path
+ * elements exist in where. Big Black Magic
+ */
+ prepath = xstrdup (repository);
+ cp = strrchr (where, '/');
+ cp2 = strrchr (prepath, '/');
+ while (cp != NULL)
+ {
+ cp = findslash (where, cp - 1);
+ cp2 = findslash (prepath, cp2 - 1);
+ }
+ *cp2 = '\0';
+ realdirs = cp2 + 1;
+
+ /*
+ * build dirs on the path if necessary and leave us in the bottom
+ * directory (where if where was specified) doesn't contain a CVS
+ * subdir yet, but all the others contain CVS and Entries.Static
+ * files
+ */
+ if (build_dirs_and_chdir (where, prepath, realdirs, *pargc <= 1) != 0)
+ {
+ error (0, 0, "ignoring module %s", omodule);
+ free (prepath);
+ free (preload_update_dir);
+ preload_update_dir = oldupdate;
+ return (1);
+ }
+
+ /* clean up */
+ free (prepath);
+
+ /* set up the repository (or make sure the old one matches) */
+ if (!isfile (CVSADM))
+ {
+ FILE *fp;
+
+ if (!noexec && *pargc > 1)
+ {
+ /* I'm not sure whether this check is redundant. */
+ if (!isdir (repository))
+ error (1, 0, "there is no repository %s", repository);
+
+ Create_Admin (".", where, repository,
+ (char *) NULL, (char *) NULL);
+ fp = open_file (CVSADM_ENTSTAT, "w+");
+ if (fclose(fp) == EOF)
+ error(1, errno, "cannot close %s", CVSADM_ENTSTAT);
+#ifdef SERVER_SUPPORT
+ if (server_active)
+ server_set_entstat (where, repository);
+#endif
+ }
+ else
+ {
+ /* I'm not sure whether this check is redundant. */
+ if (!isdir (repository))
+ error (1, 0, "there is no repository %s", repository);
+
+ Create_Admin (".", where, repository, tag, date);
+ }
+ }
+ else
+ {
+ char *repos;
+
+ /* get the contents of the previously existing repository */
+ repos = Name_Repository ((char *) NULL, preload_update_dir);
+ if (fncmp (repository, repos) != 0)
+ {
+ error (0, 0, "existing repository %s does not match %s",
+ repos, repository);
+ error (0, 0, "ignoring module %s", omodule);
+ free (repos);
+ free (preload_update_dir);
+ preload_update_dir = oldupdate;
+ return (1);
+ }
+ free (repos);
+ }
+ }
+
+ /*
+ * If we are going to be updating to stdout, we need to cd to the
+ * repository directory so the recursion processor can use the current
+ * directory as the place to find repository information
+ */
+ if (pipeout)
+ {
+ if (chdir (repository) < 0)
+ {
+ error (0, errno, "cannot chdir to %s", repository);
+ free (preload_update_dir);
+ preload_update_dir = oldupdate;
+ return (1);
+ }
+ which = W_REPOS;
+ }
+ else
+ which = W_LOCAL | W_REPOS;
+
+ if (tag != NULL || date != NULL)
+ which |= W_ATTIC;
+
+ /*
+ * if we are going to be recursive (building dirs), go ahead and call the
+ * update recursion processor. We will be recursive unless either local
+ * only was specified, or we were passed arguments
+ */
+ if (!(local_specified || *pargc > 1))
+ {
+ if (strcmp (command_name, "export") != 0 && !pipeout)
+ history_write ('O', preload_update_dir, tag ? tag : date, where,
+ repository);
+ err += do_update (0, (char **) NULL, options, tag, date,
+ force_tag_match, 0 /* !local */ ,
+ 1 /* update -d */ , aflag, checkout_prune_dirs,
+ pipeout, which, join_rev1, join_rev2,
+ preload_update_dir);
+ free (preload_update_dir);
+ preload_update_dir = oldupdate;
+ return (err);
+ }
+
+ if (!pipeout)
+ {
+ int i;
+ List *entries;
+
+ /* we are only doing files, so register them */
+ entries = Entries_Open (0);
+ for (i = 1; i < *pargc; i++)
+ {
+ char line[MAXLINELEN];
+ char *user;
+ Vers_TS *vers;
+
+ user = argv[i];
+ vers = Version_TS (repository, options, tag, date, user,
+ force_tag_match, 0, entries, (List *) NULL);
+ if (vers->ts_user == NULL)
+ {
+ (void) sprintf (line, "Initial %s", user);
+ Register (entries, user, vers->vn_rcs ? vers->vn_rcs : "0",
+ line, vers->options, vers->tag,
+ vers->date, (char *) 0);
+ }
+ freevers_ts (&vers);
+ }
+
+ Entries_Close (entries);
+ }
+
+ /* Don't log "export", just regular "checkouts" */
+ if (strcmp (command_name, "export") != 0 && !pipeout)
+ history_write ('O', preload_update_dir, (tag ? tag : date), where,
+ repository);
+
+ /* go ahead and call update now that everything is set */
+ err += do_update (*pargc - 1, argv + 1, options, tag, date,
+ force_tag_match, local_specified, 1 /* update -d */,
+ aflag, checkout_prune_dirs, pipeout, which, join_rev1,
+ join_rev2, preload_update_dir);
+ free (preload_update_dir);
+ preload_update_dir = oldupdate;
+ return (err);
+}
+
+static char *
+findslash (start, p)
+ char *start;
+ char *p;
+{
+ while (p >= start && *p != '/')
+ p--;
+ if (p < start)
+ return (NULL);
+ else
+ return (p);
+}
+
+/*
+ * build all the dirs along the path to dir with CVS subdirs with appropriate
+ * repositories and Entries.Static files
+ */
+static int
+build_dirs_and_chdir (dir, prepath, realdir, sticky)
+ char *dir;
+ char *prepath;
+ char *realdir;
+ int sticky;
+{
+ FILE *fp;
+ char repository[PATH_MAX];
+ char path[PATH_MAX];
+ char path2[PATH_MAX];
+ char *slash;
+ char *slash2;
+ char *cp;
+ char *cp2;
+
+ (void) strcpy (path, dir);
+ (void) strcpy (path2, realdir);
+ for (cp = path, cp2 = path2;
+ (slash = strchr (cp, '/')) != NULL && (slash2 = strchr (cp2, '/')) != NULL;
+ cp = slash + 1, cp2 = slash2 + 1)
+ {
+ *slash = '\0';
+ *slash2 = '\0';
+ (void) CVS_MKDIR (cp, 0777);
+ if (chdir (cp) < 0)
+ {
+ error (0, errno, "cannot chdir to %s", cp);
+ return (1);
+ }
+ if (!isfile (CVSADM) && strcmp (command_name, "export") != 0)
+ {
+ (void) sprintf (repository, "%s/%s", prepath, path2);
+ /* I'm not sure whether this check is redundant. */
+ if (!isdir (repository))
+ error (1, 0, "there is no repository %s", repository);
+ Create_Admin (".", cp, repository, sticky ? (char *) NULL : tag,
+ sticky ? (char *) NULL : date);
+ if (!noexec)
+ {
+ fp = open_file (CVSADM_ENTSTAT, "w+");
+ if (fclose(fp) == EOF)
+ error(1, errno, "cannot close %s", CVSADM_ENTSTAT);
+#ifdef SERVER_SUPPORT
+ if (server_active)
+ server_set_entstat (path, repository);
+#endif
+ }
+ }
+ *slash = '/';
+ *slash2 = '/';
+ }
+ (void) CVS_MKDIR (cp, 0777);
+ if (chdir (cp) < 0)
+ {
+ error (0, errno, "cannot chdir to %s", cp);
+ return (1);
+ }
+ return (0);
+}
diff --git a/gnu/usr.bin/cvs/cvs/classify.c b/gnu/usr.bin/cvs/cvs/classify.c
new file mode 100644
index 0000000..23fafca
--- /dev/null
+++ b/gnu/usr.bin/cvs/cvs/classify.c
@@ -0,0 +1,504 @@
+/*
+ * Copyright (c) 1992, Brian Berliner and Jeff Polk
+ * Copyright (c) 1989-1992, Brian Berliner
+ *
+ * You may distribute under the terms of the GNU General Public License as
+ * specified in the README file that comes with the CVS 1.4 kit.
+ *
+ */
+
+#include "cvs.h"
+
+#ifndef lint
+static const char rcsid[] = "$CVSid: @(#)classify.c 1.17 94/10/07 $";
+USE(rcsid);
+#endif
+
+#ifdef SERVER_SUPPORT
+static void sticky_ck PROTO((char *file, int aflag, Vers_TS * vers,
+ List * entries,
+ char *repository, char *update_dir));
+#else
+static void sticky_ck PROTO((char *file, int aflag, Vers_TS * vers, List * entries));
+#endif
+
+/*
+ * Classify the state of a file
+ */
+Ctype
+Classify_File (file, tag, date, options, force_tag_match, aflag, repository,
+ entries, srcfiles, versp, update_dir, pipeout)
+ char *file;
+ char *tag;
+ char *date;
+ char *options;
+ int force_tag_match;
+ int aflag;
+ char *repository;
+ List *entries;
+ List *srcfiles;
+ Vers_TS **versp;
+ char *update_dir;
+ int pipeout;
+{
+ Vers_TS *vers;
+ Ctype ret;
+ char *fullname;
+
+ fullname = xmalloc (strlen (update_dir) + strlen (file) + 10);
+ if (update_dir[0] == '\0')
+ strcpy (fullname, file);
+ else
+ sprintf (fullname, "%s/%s", update_dir, file);
+
+ /* get all kinds of good data about the file */
+ vers = Version_TS (repository, options, tag, date, file,
+ force_tag_match, 0, entries, srcfiles);
+
+ if (vers->vn_user == NULL)
+ {
+ /* No entry available, ts_rcs is invalid */
+ if (vers->vn_rcs == NULL)
+ {
+ /* there is no RCS file either */
+ if (vers->ts_user == NULL)
+ {
+ /* there is no user file */
+ if (!force_tag_match || !(vers->tag || vers->date))
+ if (!really_quiet)
+ error (0, 0, "nothing known about %s", fullname);
+ ret = T_UNKNOWN;
+ }
+ else
+ {
+ /* there is a user file */
+ if (!force_tag_match || !(vers->tag || vers->date))
+ if (!really_quiet)
+ error (0, 0, "use `cvs add' to create an entry for %s",
+ fullname);
+ ret = T_UNKNOWN;
+ }
+ }
+#ifdef DEATH_SUPPORT
+ else if (RCS_isdead (vers->srcfile, vers->vn_rcs))
+ {
+ if (vers->ts_user == NULL)
+ /*
+ * Logically seems to me this should be T_UPTODATE.
+ * But the joining code in update.c seems to expect
+ * T_CHECKOUT, and that is what has traditionally been
+ * returned for this case.
+ */
+ ret = T_CHECKOUT;
+ else
+ {
+ error (0, 0, "use `cvs add' to create an entry for %s",
+ fullname);
+ ret = T_UNKNOWN;
+ }
+ }
+#endif
+ else
+ {
+ /* there is an rcs file */
+
+ if (vers->ts_user == NULL)
+ {
+ /* There is no user file; needs checkout */
+ ret = T_CHECKOUT;
+ }
+ else
+ {
+ if (pipeout)
+ {
+ /*
+ * The user file doesn't necessarily have anything
+ * to do with this.
+ */
+ ret = T_CHECKOUT;
+ }
+ /*
+ * There is a user file; print a warning and add it to the
+ * conflict list, only if it is indeed different from what we
+ * plan to extract
+ */
+ else if (No_Difference (file, vers, entries,
+ repository, update_dir))
+ {
+ /* the files were different so it is a conflict */
+ if (!really_quiet)
+ error (0, 0, "move away %s; it is in the way",
+ fullname);
+ ret = T_CONFLICT;
+ }
+ else
+ /* since there was no difference, still needs checkout */
+ ret = T_CHECKOUT;
+ }
+ }
+ }
+ else if (strcmp (vers->vn_user, "0") == 0)
+ {
+ /* An entry for a new-born file; ts_rcs is dummy */
+
+ if (vers->ts_user == NULL)
+ {
+ /*
+ * There is no user file, but there should be one; remove the
+ * entry
+ */
+ if (!really_quiet)
+ error (0, 0, "warning: new-born %s has disappeared", fullname);
+ ret = T_REMOVE_ENTRY;
+ }
+ else
+ {
+ /* There is a user file */
+
+ if (vers->vn_rcs == NULL)
+ /* There is no RCS file, added file */
+ ret = T_ADDED;
+#ifdef DEATH_SUPPORT
+ else if (RCS_isdead (vers->srcfile, vers->vn_rcs))
+ /* we are resurrecting. */
+ ret = T_ADDED;
+#endif /* DEATH_SUPPORT */
+ else
+ {
+#ifdef DEATH_SUPPORT
+ if (vers->srcfile->flags & INATTIC
+ && vers->srcfile->flags & VALID)
+ {
+ /* This file has been added on some branch other than
+ the one we are looking at. In the branch we are
+ looking at, the file was already valid. */
+ if (!really_quiet)
+ error (0, 0,
+ "conflict: %s has been added, but already exists",
+ fullname);
+ }
+ else
+ {
+#endif /* DEATH_SUPPORT */
+ /*
+ * There is an RCS file, so someone else must have checked
+ * one in behind our back; conflict
+ */
+ if (!really_quiet)
+ error (0, 0,
+ "conflict: %s created independently by second party",
+ fullname);
+#ifdef DEATH_SUPPORT
+ }
+#endif
+ ret = T_CONFLICT;
+ }
+ }
+ }
+ else if (vers->vn_user[0] == '-')
+ {
+ /* An entry for a removed file, ts_rcs is invalid */
+
+ if (vers->ts_user == NULL)
+ {
+ char tmp[PATH_MAX];
+
+ /* There is no user file (as it should be) */
+
+ (void) sprintf (tmp, "-%s", vers->vn_rcs ? vers->vn_rcs : "");
+
+ if (vers->vn_rcs == NULL)
+ {
+
+ /*
+ * There is no RCS file; this is all-right, but it has been
+ * removed independently by a second party; remove the entry
+ */
+ ret = T_REMOVE_ENTRY;
+ }
+ else if (strcmp (tmp, vers->vn_user) == 0)
+
+ /*
+ * The RCS file is the same version as the user file was, and
+ * that's OK; remove it
+ */
+ ret = T_REMOVED;
+ else
+ {
+
+ /*
+ * The RCS file is a newer version than the removed user file
+ * and this is definitely not OK; make it a conflict.
+ */
+ if (!really_quiet)
+ error (0, 0,
+ "conflict: removed %s was modified by second party",
+ fullname);
+ ret = T_CONFLICT;
+ }
+ }
+ else
+ {
+ /* The user file shouldn't be there */
+ if (!really_quiet)
+ error (0, 0, "%s should be removed and is still there",
+ fullname);
+ ret = T_REMOVED;
+ }
+ }
+ else
+ {
+ /* A normal entry, TS_Rcs is valid */
+ if (vers->vn_rcs == NULL)
+ {
+ /* There is no RCS file */
+
+ if (vers->ts_user == NULL)
+ {
+ /* There is no user file, so just remove the entry */
+ if (!really_quiet)
+ error (0, 0, "warning: %s is not (any longer) pertinent",
+ fullname);
+ ret = T_REMOVE_ENTRY;
+ }
+ else if (strcmp (vers->ts_user, vers->ts_rcs) == 0)
+ {
+
+ /*
+ * The user file is still unmodified, so just remove it from
+ * the entry list
+ */
+ if (!really_quiet)
+ error (0, 0, "%s is no longer in the repository",
+ fullname);
+ ret = T_REMOVE_ENTRY;
+ }
+ else
+ {
+ /*
+ * The user file has been modified and since it is no longer
+ * in the repository, a conflict is raised
+ */
+ if (No_Difference (file, vers, entries,
+ repository, update_dir))
+ {
+ /* they are different -> conflict */
+ if (!really_quiet)
+ error (0, 0,
+ "conflict: %s is modified but no longer in the repository",
+ fullname);
+ ret = T_CONFLICT;
+ }
+ else
+ {
+ /* they weren't really different */
+ if (!really_quiet)
+ error (0, 0,
+ "warning: %s is not (any longer) pertinent",
+ fullname);
+ ret = T_REMOVE_ENTRY;
+ }
+ }
+ }
+ else if (strcmp (vers->vn_rcs, vers->vn_user) == 0)
+ {
+ /* The RCS file is the same version as the user file */
+
+ if (vers->ts_user == NULL)
+ {
+
+ /*
+ * There is no user file, so note that it was lost and
+ * extract a new version
+ */
+ if (strcmp (command_name, "update") == 0)
+ if (!really_quiet)
+ error (0, 0, "warning: %s was lost", fullname);
+ ret = T_CHECKOUT;
+ }
+ else if (strcmp (vers->ts_user, vers->ts_rcs) == 0)
+ {
+
+ /*
+ * The user file is still unmodified, so nothing special at
+ * all to do -- no lists updated, unless the sticky -k option
+ * has changed. If the sticky tag has changed, we just need
+ * to re-register the entry
+ */
+ if (vers->entdata->options &&
+ strcmp (vers->entdata->options, vers->options) != 0)
+ ret = T_CHECKOUT;
+ else
+ {
+#ifdef SERVER_SUPPORT
+ sticky_ck (file, aflag, vers, entries,
+ repository, update_dir);
+#else
+ sticky_ck (file, aflag, vers, entries);
+#endif
+ ret = T_UPTODATE;
+ }
+ }
+ else
+ {
+
+ /*
+ * The user file appears to have been modified, but we call
+ * No_Difference to verify that it really has been modified
+ */
+ if (No_Difference (file, vers, entries,
+ repository, update_dir))
+ {
+
+ /*
+ * they really are different; modified if we aren't
+ * changing any sticky -k options, else needs merge
+ */
+#ifdef XXX_FIXME_WHEN_RCSMERGE_IS_FIXED
+ if (strcmp (vers->entdata->options ?
+ vers->entdata->options : "", vers->options) == 0)
+ ret = T_MODIFIED;
+ else
+ ret = T_NEEDS_MERGE;
+#else
+ ret = T_MODIFIED;
+#ifdef SERVER_SUPPORT
+ sticky_ck (file, aflag, vers, entries,
+ repository, update_dir);
+#else
+ sticky_ck (file, aflag, vers, entries);
+#endif /* SERVER_SUPPORT */
+#endif
+ }
+ else
+ {
+ /* file has not changed; check out if -k changed */
+ if (strcmp (vers->entdata->options ?
+ vers->entdata->options : "", vers->options) != 0)
+ {
+ ret = T_CHECKOUT;
+ }
+ else
+ {
+
+ /*
+ * else -> note that No_Difference will Register the
+ * file already for us, using the new tag/date. This
+ * is the desired behaviour
+ */
+ ret = T_UPTODATE;
+ }
+ }
+ }
+ }
+ else
+ {
+ /* The RCS file is a newer version than the user file */
+
+ if (vers->ts_user == NULL)
+ {
+ /* There is no user file, so just get it */
+
+ if (strcmp (command_name, "update") == 0)
+ if (!really_quiet)
+ error (0, 0, "warning: %s was lost", fullname);
+ ret = T_CHECKOUT;
+ }
+ else if (strcmp (vers->ts_user, vers->ts_rcs) == 0)
+ {
+
+ /*
+ * The user file is still unmodified, so just get it as well
+ */
+#ifdef SERVER_SUPPORT
+ if (strcmp (vers->entdata->options ?
+ vers->entdata->options : "", vers->options) != 0
+ || (vers->srcfile != NULL
+ && (vers->srcfile->flags & INATTIC) != 0))
+ ret = T_CHECKOUT;
+ else
+ ret = T_PATCH;
+#else
+ ret = T_CHECKOUT;
+#endif
+ }
+ else
+ {
+ if (No_Difference (file, vers, entries,
+ repository, update_dir))
+ /* really modified, needs to merge */
+ ret = T_NEEDS_MERGE;
+#ifdef SERVER_SUPPORT
+ else if ((strcmp (vers->entdata->options ?
+ vers->entdata->options : "", vers->options)
+ != 0)
+ || (vers->srcfile != NULL
+ && (vers->srcfile->flags & INATTIC) != 0))
+ /* not really modified, check it out */
+ ret = T_CHECKOUT;
+ else
+ ret = T_PATCH;
+#else
+ else
+ /* not really modified, check it out */
+ ret = T_CHECKOUT;
+#endif
+ }
+ }
+ }
+
+ /* free up the vers struct, or just return it */
+ if (versp != (Vers_TS **) NULL)
+ *versp = vers;
+ else
+ freevers_ts (&vers);
+
+ free (fullname);
+
+ /* return the status of the file */
+ return (ret);
+}
+
+static void
+#ifdef SERVER_SUPPORT
+sticky_ck (file, aflag, vers, entries, repository, update_dir)
+#else
+sticky_ck (file, aflag, vers, entries)
+#endif
+ char *file;
+ int aflag;
+ Vers_TS *vers;
+ List *entries;
+#ifdef SERVER_SUPPORT
+ char *repository;
+ char *update_dir;
+#endif
+{
+ if (aflag || vers->tag || vers->date)
+ {
+ char *enttag = vers->entdata->tag;
+ char *entdate = vers->entdata->date;
+
+ if ((enttag && vers->tag && strcmp (enttag, vers->tag)) ||
+ ((enttag && !vers->tag) || (!enttag && vers->tag)) ||
+ (entdate && vers->date && strcmp (entdate, vers->date)) ||
+ ((entdate && !vers->date) || (!entdate && vers->date)))
+ {
+ Register (entries, file, vers->vn_user, vers->ts_rcs,
+ vers->options, vers->tag, vers->date, vers->ts_conflict);
+
+#ifdef SERVER_SUPPORT
+ if (server_active)
+ {
+ /* We need to update the entries line on the client side.
+ It is possible we will later update it again via
+ server_updated or some such, but that is OK. */
+ server_update_entries
+ (file, update_dir, repository,
+ strcmp (vers->ts_rcs, vers->ts_user) == 0 ?
+ SERVER_UPDATED : SERVER_MERGED);
+ }
+#endif
+ }
+ }
+}
diff --git a/gnu/usr.bin/cvs/cvs/client.c b/gnu/usr.bin/cvs/cvs/client.c
new file mode 100644
index 0000000..dd96db8
--- /dev/null
+++ b/gnu/usr.bin/cvs/cvs/client.c
@@ -0,0 +1,3542 @@
+/* CVS client-related stuff. */
+
+#include "cvs.h"
+
+#ifdef CLIENT_SUPPORT
+
+#include "update.h" /* Things shared with update.c */
+#include "md5.h"
+
+#ifdef AUTH_CLIENT_SUPPORT
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netdb.h>
+char *get_cvs_password PROTO((char *user, char *host, char *cvsrooot));
+#endif /* AUTH_CLIENT_SUPPORT */
+
+#if HAVE_KERBEROS
+#define CVS_PORT 1999
+
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include <krb.h>
+
+extern char *krb_realmofhost ();
+#ifndef HAVE_KRB_GET_ERR_TEXT
+#define krb_get_err_text(status) krb_err_txt[status]
+#endif /* HAVE_KRB_GET_ERR_TEXT */
+#endif /* HAVE_KERBEROS */
+
+static void add_prune_candidate PROTO((char *));
+
+/* All the commands. */
+int add PROTO((int argc, char **argv));
+int admin PROTO((int argc, char **argv));
+int checkout PROTO((int argc, char **argv));
+int commit PROTO((int argc, char **argv));
+int diff PROTO((int argc, char **argv));
+int history PROTO((int argc, char **argv));
+int import PROTO((int argc, char **argv));
+int cvslog PROTO((int argc, char **argv));
+int patch PROTO((int argc, char **argv));
+int release PROTO((int argc, char **argv));
+int cvsremove PROTO((int argc, char **argv));
+int rtag PROTO((int argc, char **argv));
+int status PROTO((int argc, char **argv));
+int tag PROTO((int argc, char **argv));
+int update PROTO((int argc, char **argv));
+
+/* All the response handling functions. */
+static void handle_ok PROTO((char *, int));
+static void handle_error PROTO((char *, int));
+static void handle_valid_requests PROTO((char *, int));
+static void handle_checked_in PROTO((char *, int));
+static void handle_new_entry PROTO((char *, int));
+static void handle_checksum PROTO((char *, int));
+static void handle_copy_file PROTO((char *, int));
+static void handle_updated PROTO((char *, int));
+static void handle_merged PROTO((char *, int));
+static void handle_patched PROTO((char *, int));
+static void handle_removed PROTO((char *, int));
+static void handle_remove_entry PROTO((char *, int));
+static void handle_set_static_directory PROTO((char *, int));
+static void handle_clear_static_directory PROTO((char *, int));
+static void handle_set_sticky PROTO((char *, int));
+static void handle_clear_sticky PROTO((char *, int));
+static void handle_set_checkin_prog PROTO((char *, int));
+static void handle_set_update_prog PROTO((char *, int));
+static void handle_module_expansion PROTO((char *, int));
+static void handle_m PROTO((char *, int));
+static void handle_e PROTO((char *, int));
+
+#endif /* CLIENT_SUPPORT */
+
+#if defined(CLIENT_SUPPORT) || defined(SERVER_SUPPORT)
+
+/* Shared with server. */
+
+/*
+ * Return a malloc'd, '\0'-terminated string
+ * corresponding to the mode in SB.
+ */
+char *
+#ifdef __STDC__
+mode_to_string (mode_t mode)
+#else /* ! __STDC__ */
+mode_to_string (mode)
+ mode_t mode;
+#endif /* __STDC__ */
+{
+ char buf[18], u[4], g[4], o[4];
+ int i;
+
+ i = 0;
+ if (mode & S_IRUSR) u[i++] = 'r';
+ if (mode & S_IWUSR) u[i++] = 'w';
+ if (mode & S_IXUSR) u[i++] = 'x';
+ u[i] = '\0';
+
+ i = 0;
+ if (mode & S_IRGRP) g[i++] = 'r';
+ if (mode & S_IWGRP) g[i++] = 'w';
+ if (mode & S_IXGRP) g[i++] = 'x';
+ g[i] = '\0';
+
+ i = 0;
+ if (mode & S_IROTH) o[i++] = 'r';
+ if (mode & S_IWOTH) o[i++] = 'w';
+ if (mode & S_IXOTH) o[i++] = 'x';
+ o[i] = '\0';
+
+ sprintf(buf, "u=%s,g=%s,o=%s", u, g, o);
+ return xstrdup(buf);
+}
+
+/*
+ * Change mode of FILENAME to MODE_STRING.
+ * Returns 0 for success or errno code.
+ */
+int
+change_mode (filename, mode_string)
+ char *filename;
+ char *mode_string;
+{
+ char *p;
+ mode_t mode = 0;
+
+ p = mode_string;
+ while (*p != '\0')
+ {
+ if ((p[0] == 'u' || p[0] == 'g' || p[0] == 'o') && p[1] == '=')
+ {
+ int can_read = 0, can_write = 0, can_execute = 0;
+ char *q = p + 2;
+ while (*q != ',' && *q != '\0')
+ {
+ if (*q == 'r')
+ can_read = 1;
+ else if (*q == 'w')
+ can_write = 1;
+ else if (*q == 'x')
+ can_execute = 1;
+ ++q;
+ }
+ if (p[0] == 'u')
+ {
+ if (can_read)
+ mode |= S_IRUSR;
+ if (can_write)
+ mode |= S_IWUSR;
+ if (can_execute)
+ {
+#ifdef EXECUTE_PERMISSION_LOSES
+ KFF_DEBUG (printf ("*** S_IXUSR in change_mode().\n"));
+#else /* ! EXECUTE_PERMISSION_LOSES */
+ mode |= S_IXUSR;
+#endif /* EXECUTE_PERMISSION_LOSES */
+ }
+ }
+ else if (p[0] == 'g')
+ {
+ if (can_read)
+ mode |= S_IRGRP;
+ if (can_write)
+ mode |= S_IWGRP;
+ if (can_execute)
+ {
+#ifdef EXECUTE_PERMISSION_LOSES
+ KFF_DEBUG (printf ("*** S_IXGRP in change_mode().\n"));
+#else /* ! EXECUTE_PERMISSION_LOSES */
+ mode |= S_IXGRP;
+#endif /* EXECUTE_PERMISSION_LOSES */
+ }
+ }
+ else if (p[0] == 'o')
+ {
+ if (can_read)
+ mode |= S_IROTH;
+ if (can_write)
+ mode |= S_IWOTH;
+ if (can_execute)
+ {
+#ifdef EXECUTE_PERMISSION_LOSES
+ KFF_DEBUG (printf ("*** S_IXOTH in change_mode().\n"));
+#else /* ! EXECUTE_PERMISSION_LOSES */
+ mode |= S_IXOTH;
+#endif /* EXECUTE_PERMISSION_LOSES */
+ }
+ }
+ }
+ /* Skip to the next field. */
+ while (*p != ',' && *p != '\0')
+ ++p;
+ if (*p == ',')
+ ++p;
+ }
+ if (chmod (filename, mode) < 0)
+ return errno;
+ return 0;
+}
+
+#endif /* CLIENT_SUPPORT or SERVER_SUPPORT */
+
+#ifdef CLIENT_SUPPORT
+
+/* The host part of CVSROOT. */
+static char *server_host;
+/* The user part of CVSROOT */
+static char *server_user;
+/* The repository part of CVSROOT. */
+static char *server_cvsroot;
+
+int client_active;
+
+int client_prune_dirs;
+
+/* Set server_host and server_cvsroot. */
+static void
+parse_cvsroot ()
+{
+ char *p;
+
+ server_host = xstrdup (CVSroot);
+ server_cvsroot = strchr (server_host, ':');
+ *server_cvsroot = '\0';
+ ++server_cvsroot;
+
+ if ( (p = strchr (server_host, '@')) == NULL) {
+ server_user = NULL;
+ } else {
+ server_user = server_host;
+ server_host = p;
+ ++server_host;
+ *p = '\0';
+ }
+
+ client_active = 1;
+}
+
+/* Stream to write to the server. */
+FILE *to_server;
+/* Stream to read from the server. */
+FILE *from_server;
+
+#if ! RSH_NOT_TRANSPARENT
+/* Process ID of rsh subprocess. */
+static int rsh_pid = -1;
+#endif /* ! RSH_NOT_TRANSPARENT */
+
+
+/*
+ * Read a line from the server.
+ *
+ * Space for the result is malloc'd and should be freed by the caller.
+ *
+ * Returns number of bytes read. If EOF_OK, then return 0 on end of file,
+ * else end of file is an error.
+ */
+static int
+read_line (resultp, eof_ok)
+ char **resultp;
+ int eof_ok;
+{
+ int c;
+ char *result;
+ int input_index = 0;
+ int result_size = 80;
+
+ fflush (to_server);
+ result = (char *) xmalloc (result_size);
+
+ while (1)
+ {
+ c = getc (from_server);
+
+ if (c == EOF)
+ {
+ free (result);
+ if (ferror (from_server))
+ error (1, errno, "reading from server");
+ /* It's end of file. */
+ if (eof_ok)
+ return 0;
+ else
+ error (1, 0, "premature end of file from server");
+ }
+
+ if (c == '\n')
+ break;
+
+ result[input_index++] = c;
+ while (input_index + 1 >= result_size)
+ {
+ result_size *= 2;
+ result = (char *) xrealloc (result, result_size);
+ }
+ }
+
+ if (resultp)
+ *resultp = result;
+
+ /* Terminate it just for kicks, but we *can* deal with embedded NULs. */
+ result[input_index] = '\0';
+
+ if (resultp == NULL)
+ free (result);
+ return input_index;
+}
+
+#endif /* CLIENT_SUPPORT */
+
+
+#if defined(CLIENT_SUPPORT) || defined(SERVER_SUPPORT)
+
+/*
+ * Zero if compression isn't supported or requested; non-zero to indicate
+ * a compression level to request from gzip.
+ */
+int gzip_level;
+
+int filter_through_gzip (fd, dir, level, pidp)
+ int fd, dir, level;
+ pid_t *pidp;
+{
+ static char buf[5] = "-";
+ static char *gzip_argv[3] = { "gzip", buf };
+
+ sprintf (buf+1, "%d", level);
+ return filter_stream_through_program (fd, dir, &gzip_argv[0], pidp);
+}
+
+int filter_through_gunzip (fd, dir, pidp)
+ int fd, dir;
+ pid_t *pidp;
+{
+ static char *gunzip_argv[2] = { "gunzip" };
+ return filter_stream_through_program (fd, dir, &gunzip_argv[0], pidp);
+}
+
+#endif /* CLIENT_SUPPORT or SERVER_SUPPORT */
+
+#ifdef CLIENT_SUPPORT
+
+/*
+ * The Repository for the top level of this command (not necessarily
+ * the CVSROOT, just the current directory at the time we do it).
+ */
+static char *toplevel_repos;
+
+/* Working directory when we first started. */
+char toplevel_wd[PATH_MAX];
+
+static void
+handle_ok (args, len)
+ char *args;
+ int len;
+{
+ return;
+}
+
+static void
+handle_error (args, len)
+ char *args;
+ int len;
+{
+ int something_printed;
+
+ /*
+ * First there is a symbolic error code followed by a space, which
+ * we ignore.
+ */
+ char *p = strchr (args, ' ');
+ if (p == NULL)
+ {
+ error (0, 0, "invalid data from cvs server");
+ return;
+ }
+ ++p;
+ len -= p - args;
+ something_printed = 0;
+ for (; len > 0; --len)
+ {
+ something_printed = 1;
+ putc (*p++, stderr);
+ }
+ if (something_printed)
+ putc ('\n', stderr);
+}
+
+static void
+handle_valid_requests (args, len)
+ char *args;
+ int len;
+{
+ char *p = args;
+ char *q;
+ struct request *rq;
+ do
+ {
+ q = strchr (p, ' ');
+ if (q != NULL)
+ *q++ = '\0';
+ for (rq = requests; rq->name != NULL; ++rq)
+ {
+ if (strcmp (rq->name, p) == 0)
+ break;
+ }
+ if (rq->name == NULL)
+ /*
+ * It is a request we have never heard of (and thus never
+ * will want to use). So don't worry about it.
+ */
+ ;
+ else
+ {
+ if (rq->status == rq_enableme)
+ {
+ /*
+ * Server wants to know if we have this, to enable the
+ * feature.
+ */
+ if (fprintf(to_server, "%s\n", rq->name) < 0)
+ error (1, errno, "writing to server");
+ if (!strcmp("UseUnchanged",rq->name))
+ use_unchanged = 1;
+ }
+ else
+ rq->status = rq_supported;
+ }
+ p = q;
+ } while (q != NULL);
+ for (rq = requests; rq->name != NULL; ++rq)
+ {
+ if (rq->status == rq_essential)
+ error (1, 0, "request `%s' not supported by server", rq->name);
+ else if (rq->status == rq_optional)
+ rq->status = rq_not_supported;
+ }
+}
+
+static int use_directory = -1;
+
+static char *get_short_pathname PROTO((const char *));
+
+static char *
+get_short_pathname (name)
+ const char *name;
+{
+ const char *retval;
+ if (use_directory)
+ return (char *) name;
+ if (strncmp (name, toplevel_repos, strlen (toplevel_repos)) != 0)
+ error (1, 0, "server bug: name `%s' doesn't specify file in `%s'",
+ name, toplevel_repos);
+ retval = name + strlen (toplevel_repos) + 1;
+ if (retval[-1] != '/')
+ error (1, 0, "server bug: name `%s' doesn't specify file in `%s'",
+ name, toplevel_repos);
+ return (char *) retval;
+}
+
+/*
+ * Do all the processing for PATHNAME, where pathname consists of the
+ * repository and the filename. The parameters we pass to FUNC are:
+ * DATA is just the DATA parameter which was passed to
+ * call_in_directory; ENT_LIST is a pointer to an entries list (which
+ * we manage the storage for); SHORT_PATHNAME is the pathname of the
+ * file relative to the (overall) directory in which the command is
+ * taking place; and FILENAME is the filename portion only of
+ * SHORT_PATHNAME. When we call FUNC, the curent directory points to
+ * the directory portion of SHORT_PATHNAME. */
+
+static char *last_dirname;
+
+static void
+call_in_directory (pathname, func, data)
+ char *pathname;
+ void (*func) PROTO((char *data, List *ent_list, char *short_pathname,
+ char *filename));
+ char *data;
+{
+ static List *last_entries;
+
+ char *dirname;
+ char *filename;
+ /* Just the part of pathname relative to toplevel_repos. */
+ char *short_pathname = get_short_pathname (pathname);
+ char *p;
+
+ /*
+ * Do the whole descent in parallel for the repositories, so we
+ * know what to put in CVS/Repository files. I'm not sure the
+ * full hair is necessary since the server does a similar
+ * computation; I suspect that we only end up creating one
+ * directory at a time anyway.
+ *
+ * Also note that we must *only* worry about this stuff when we
+ * are creating directories; `cvs co foo/bar; cd foo/bar; cvs co
+ * CVSROOT; cvs update' is legitimate, but in this case
+ * foo/bar/CVSROOT/CVS/Repository is not a subdirectory of
+ * foo/bar/CVS/Repository.
+ */
+ char *reposname;
+ char *short_repos;
+ char *reposdirname;
+ char *rdirp;
+ int reposdirname_absolute;
+
+ reposname = NULL;
+ if (use_directory)
+ read_line (&reposname, 0);
+
+ reposdirname_absolute = 0;
+ if (reposname != NULL)
+ {
+ if (strncmp (reposname, toplevel_repos, strlen (toplevel_repos)) != 0)
+ {
+ reposdirname_absolute = 1;
+ short_repos = reposname;
+ }
+ else
+ {
+ short_repos = reposname + strlen (toplevel_repos) + 1;
+ if (short_repos[-1] != '/')
+ {
+ reposdirname_absolute = 1;
+ short_repos = reposname;
+ }
+ }
+ }
+ else
+ {
+ short_repos = short_pathname;
+ }
+ reposdirname = xstrdup (short_repos);
+ p = strrchr (reposdirname, '/');
+ if (p == NULL)
+ {
+ reposdirname = xrealloc (reposdirname, 2);
+ reposdirname[0] = '.'; reposdirname[1] = '\0';
+ }
+ else
+ *p = '\0';
+
+ dirname = xstrdup (short_pathname);
+ p = strrchr (dirname, '/');
+ if (p == NULL)
+ {
+ dirname = xrealloc (dirname, 2);
+ dirname[0] = '.'; dirname[1] = '\0';
+ }
+ else
+ *p = '\0';
+ if (client_prune_dirs)
+ add_prune_candidate (dirname);
+
+ filename = strrchr (short_repos, '/');
+ if (filename == NULL)
+ filename = short_repos;
+ else
+ ++filename;
+
+ if (reposname != NULL)
+ {
+ /* This is the use_directory case. */
+
+ short_pathname = xmalloc (strlen (pathname) + strlen (filename) + 5);
+ strcpy (short_pathname, pathname);
+ strcat (short_pathname, filename);
+ }
+
+ if (last_dirname == NULL
+ || strcmp (last_dirname, dirname) != 0)
+ {
+ if (last_dirname)
+ free (last_dirname);
+ last_dirname = dirname;
+
+ if (toplevel_wd[0] == '\0')
+ if (getwd (toplevel_wd) == NULL)
+ error (1, 0,
+ "could not get working directory: %s", toplevel_wd);
+
+ if (chdir (toplevel_wd) < 0)
+ error (1, errno, "could not chdir to %s", toplevel_wd);
+ if (chdir (dirname) < 0)
+ {
+ char *dir;
+ char *dirp;
+
+ if (! existence_error (errno))
+ error (1, errno, "could not chdir to %s", dirname);
+
+ /* Directory does not exist, we need to create it. */
+ dir = xmalloc (strlen (dirname) + 1);
+ dirp = dirname;
+ rdirp = reposdirname;
+
+ /* This algorithm makes nested directories one at a time
+ and create CVS administration files in them. For
+ example, we're checking out foo/bar/baz from the
+ repository:
+
+ 1) create foo, point CVS/Repository to <root>/foo
+ 2) .. foo/bar .. <root>/foo/bar
+ 3) .. foo/bar/baz .. <root>/foo/bar/baz
+
+ As you can see, we're just stepping along DIRNAME (with
+ DIRP) and REPOSDIRNAME (with RDIRP) respectively.
+
+ We need to be careful when we are checking out a
+ module, however, since DIRNAME and REPOSDIRNAME are not
+ going to be the same. Since modules will not have any
+ slashes in their names, we should watch the output of
+ STRCHR to decide whether or not we should use STRCHR on
+ the RDIRP. That is, if we're down to a module name,
+ don't keep picking apart the repository directory name. */
+
+ do
+ {
+ dirp = strchr (dirp, '/');
+ if (dirp)
+ {
+ strncpy (dir, dirname, dirp - dirname);
+ dir[dirp - dirname] = '\0';
+ /* Skip the slash. */
+ ++dirp;
+ if (rdirp == NULL)
+ error (0, 0,
+ "internal error: repository string too short.");
+ else
+ rdirp = strchr (rdirp, '/');
+ }
+ else
+ {
+ /* If there are no more slashes in the dir name,
+ we're down to the most nested directory -OR- to
+ the name of a module. In the first case, we
+ should be down to a DIRP that has no slashes,
+ so it won't help/hurt to do another STRCHR call
+ on DIRP. It will definitely hurt, however, if
+ we're down to a module name, since a module
+ name can point to a nested directory (that is,
+ DIRP will still have slashes in it. Therefore,
+ we should set it to NULL so the routine below
+ copies the contents of REMOTEDIRNAME onto the
+ root repository directory (does this if rdirp
+ is set to NULL, because we used to do an extra
+ STRCHR call here). */
+
+ rdirp = NULL;
+ strcpy (dir, dirname);
+ }
+
+ if (CVS_MKDIR (dir, 0777) < 0)
+ {
+ /* Now, let me get this straight. In IBM C/C++
+ * under OS/2, the error string for EEXIST is:
+ *
+ * "The file already exists",
+ *
+ * and the error string for EACCESS is:
+ *
+ * "The file or directory specified is read-only".
+ *
+ * Nonetheless, mkdir() will set EACCESS if the
+ * directory *exists*, according both to the
+ * documentation and its actual behavior.
+ *
+ * I'm sure that this made sense, to someone,
+ * somewhere, sometime. Just not me, here, now.
+ */
+#ifdef EACCESS
+ if ((errno != EACCESS) && (errno != EEXIST))
+ error (1, errno, "cannot make directory %s", dir);
+#else /* ! defined(EACCESS) */
+ if ((errno != EEXIST))
+ error (1, errno, "cannot make directory %s", dir);
+#endif /* defined(EACCESS) */
+
+ /* It already existed, fine. Just keep going. */
+ }
+ else if (strcmp (command_name, "export") == 0)
+ /* Don't create CVSADM directories if this is export. */
+ ;
+ else
+ {
+ /*
+ * Put repository in CVS/Repository. For historical
+ * (pre-CVS/Root) reasons, this is an absolute pathname,
+ * but what really matters is the part of it which is
+ * relative to cvsroot.
+ */
+ char *repo;
+ char *r;
+
+ repo = xmalloc (strlen (reposdirname)
+ + strlen (toplevel_repos)
+ + 80);
+ if (reposdirname_absolute)
+ r = repo;
+ else
+ {
+ strcpy (repo, toplevel_repos);
+ strcat (repo, "/");
+ r = repo + strlen (repo);
+ }
+
+ if (rdirp)
+ {
+ strncpy (r, reposdirname, rdirp - reposdirname);
+ r[rdirp - reposdirname] = '\0';
+ }
+ else
+ strcpy (r, reposdirname);
+
+ Create_Admin (dir, dir, repo,
+ (char *)NULL, (char *)NULL);
+ free (repo);
+ }
+
+ if (rdirp != NULL)
+ {
+ /* Skip the slash. */
+ ++rdirp;
+ }
+
+ } while (dirp != NULL);
+ free (dir);
+ /* Now it better work. */
+ if (chdir (dirname) < 0)
+ error (1, errno, "could not chdir to %s", dirname);
+ }
+
+ if (strcmp (command_name, "export") != 0)
+ {
+ if (last_entries)
+ Entries_Close (last_entries);
+ last_entries = Entries_Open (0);
+ }
+ }
+ else
+ free (dirname);
+ free (reposdirname);
+ (*func) (data, last_entries, short_pathname, filename);
+ if (reposname != NULL)
+ {
+ free (short_pathname);
+ free (reposname);
+ }
+}
+
+static void
+copy_a_file (data, ent_list, short_pathname, filename)
+ char *data;
+ List *ent_list;
+ char *short_pathname;
+ char *filename;
+{
+ char *newname;
+
+ read_line (&newname, 0);
+ copy_file (filename, newname);
+ free (newname);
+}
+
+static void
+handle_copy_file (args, len)
+ char *args;
+ int len;
+{
+ call_in_directory (args, copy_a_file, (char *)NULL);
+}
+
+/*
+ * The Checksum response gives the checksum for the file transferred
+ * over by the next Updated, Merged or Patch response. We just store
+ * it here, and then check it in update_entries.
+ */
+
+static int stored_checksum_valid;
+static unsigned char stored_checksum[16];
+
+static void
+handle_checksum (args, len)
+ char *args;
+ int len;
+{
+ char *s;
+ char buf[3];
+ int i;
+
+ if (stored_checksum_valid)
+ error (1, 0, "Checksum received before last one was used");
+
+ s = args;
+ buf[2] = '\0';
+ for (i = 0; i < 16; i++)
+ {
+ char *bufend;
+
+ buf[0] = *s++;
+ buf[1] = *s++;
+ stored_checksum[i] = (char) strtol (buf, &bufend, 16);
+ if (bufend != buf + 2)
+ break;
+ }
+
+ if (i < 16 || *s != '\0')
+ error (1, 0, "Invalid Checksum response: `%s'", args);
+
+ stored_checksum_valid = 1;
+}
+
+/*
+ * If we receive a patch, but the patch program fails to apply it, we
+ * want to request the original file. We keep a list of files whose
+ * patches have failed.
+ */
+
+char **failed_patches;
+int failed_patches_count;
+
+struct update_entries_data
+{
+ enum {
+ /*
+ * We are just getting an Entries line; the local file is
+ * correct.
+ */
+ UPDATE_ENTRIES_CHECKIN,
+ /* We are getting the file contents as well. */
+ UPDATE_ENTRIES_UPDATE,
+ /*
+ * We are getting a patch against the existing local file, not
+ * an entire new file.
+ */
+ UPDATE_ENTRIES_PATCH
+ } contents;
+
+ /*
+ * String to put in the timestamp field or NULL to use the timestamp
+ * of the file.
+ */
+ char *timestamp;
+};
+
+/* Update the Entries line for this file. */
+static void
+update_entries (data_arg, ent_list, short_pathname, filename)
+ char *data_arg;
+ List *ent_list;
+ char *short_pathname;
+ char *filename;
+{
+ char *entries_line;
+ struct update_entries_data *data = (struct update_entries_data *)data_arg;
+
+ char *cp;
+ char *user;
+ char *vn;
+ /* Timestamp field. Always empty according to the protocol. */
+ char *ts;
+ char *options;
+ char *tag;
+ char *date;
+ char *tag_or_date;
+ char *scratch_entries;
+ int bin = 0;
+
+ read_line (&entries_line, 0);
+
+ /*
+ * Parse the entries line.
+ */
+ if (strcmp (command_name, "export") != 0)
+ {
+ scratch_entries = xstrdup (entries_line);
+
+ if (scratch_entries[0] != '/')
+ error (1, 0, "bad entries line `%s' from server", entries_line);
+ user = scratch_entries + 1;
+ if ((cp = strchr (user, '/')) == NULL)
+ error (1, 0, "bad entries line `%s' from server", entries_line);
+ *cp++ = '\0';
+ vn = cp;
+ if ((cp = strchr (vn, '/')) == NULL)
+ error (1, 0, "bad entries line `%s' from server", entries_line);
+ *cp++ = '\0';
+
+ ts = cp;
+ if ((cp = strchr (ts, '/')) == NULL)
+ error (1, 0, "bad entries line `%s' from server", entries_line);
+ *cp++ = '\0';
+ options = cp;
+ if ((cp = strchr (options, '/')) == NULL)
+ error (1, 0, "bad entries line `%s' from server", entries_line);
+ *cp++ = '\0';
+ tag_or_date = cp;
+
+ /* If a slash ends the tag_or_date, ignore everything after it. */
+ cp = strchr (tag_or_date, '/');
+ if (cp != NULL)
+ *cp = '\0';
+ tag = (char *) NULL;
+ date = (char *) NULL;
+ if (*tag_or_date == 'T')
+ tag = tag_or_date + 1;
+ else if (*tag_or_date == 'D')
+ date = tag_or_date + 1;
+ }
+
+ if (data->contents == UPDATE_ENTRIES_UPDATE
+ || data->contents == UPDATE_ENTRIES_PATCH)
+ {
+ char *size_string;
+ char *mode_string;
+ int size;
+ int size_read;
+ int size_left;
+ int fd;
+ char *buf;
+ char *buf2;
+ char *temp_filename;
+ int use_gzip, gzip_status;
+ pid_t gzip_pid = 0;
+
+ read_line (&mode_string, 0);
+
+ read_line (&size_string, 0);
+ if (size_string[0] == 'z')
+ {
+ use_gzip = 1;
+ size = atoi (size_string+1);
+ }
+ else
+ {
+ use_gzip = 0;
+ size = atoi (size_string);
+ }
+ free (size_string);
+
+ temp_filename = xmalloc (strlen (filename) + 80);
+#ifdef _POSIX_NO_TRUNC
+ sprintf (temp_filename, ".new.%.9s", filename);
+#else /* _POSIX_NO_TRUNC */
+ sprintf (temp_filename, ".new.%s", filename);
+#endif /* _POSIX_NO_TRUNC */
+ buf = xmalloc (size);
+
+ /* Some systems, like OS/2 and Windows NT, end lines with CRLF
+ instead of just LF. Format translation is done in the C
+ library I/O funtions. Here we tell them whether or not to
+ convert -- if this file is marked "binary" with the RCS -kb
+ flag, then we don't want to convert, else we do (because
+ CVS assumes text files by default). */
+
+ bin = !(strcmp (options, "-kb"));
+ fd = open (temp_filename,
+ O_WRONLY | O_CREAT | O_TRUNC | (bin ? OPEN_BINARY : 0),
+ 0777);
+
+ if (fd < 0)
+ error (1, errno, "writing %s", short_pathname);
+
+ if (use_gzip)
+ fd = filter_through_gunzip (fd, 0, &gzip_pid);
+
+ if (size > 0)
+ {
+ buf2 = buf;
+ size_left = size;
+ while ((size_read = fread (buf2, 1, size_left, from_server)) != size_left)
+ {
+ if (feof (from_server))
+ /* FIXME: Should delete temp_filename. */
+ error (1, 0, "unexpected end of file from server");
+ else if (ferror (from_server))
+ /* FIXME: Should delete temp_filename. */
+ error (1, errno, "reading from server");
+ else
+ {
+ /* short reads are ok if we keep trying */
+ buf2 += size_read;
+ size_left -= size_read;
+ }
+ }
+ if (write (fd, buf, size) != size)
+ error (1, errno, "writing %s", short_pathname);
+ }
+ if (close (fd) < 0)
+ error (1, errno, "writing %s", short_pathname);
+ if (gzip_pid > 0)
+ {
+ if (waitpid (gzip_pid, &gzip_status, 0) == -1)
+ error (1, errno, "waiting for gzip process %d", gzip_pid);
+ else if (gzip_status != 0)
+ error (1, 0, "gzip process exited %d", gzip_status);
+ }
+
+ gzip_pid = -1;
+
+ /* Since gunzip writes files without converting LF to CRLF
+ (a reasonable behavior), we now have a patch file in LF
+ format. Leave the file as is if we're just going to feed
+ it to patch; patch can handle it. However, if it's the
+ final source file, convert it. */
+
+ if (data->contents == UPDATE_ENTRIES_UPDATE)
+ {
+#ifdef LINES_CRLF_TERMINATED
+
+ /* `bin' is non-zero iff `options' contains "-kb", meaning
+ treat this file as binary. */
+
+ if (use_gzip && (! bin))
+ {
+ convert_file (temp_filename, O_RDONLY | OPEN_BINARY,
+ filename, O_WRONLY | O_CREAT | O_TRUNC);
+ if (unlink (temp_filename) < 0)
+ error (0, errno, "warning: couldn't delete %s",
+ temp_filename);
+ }
+ else
+ rename_file (temp_filename, filename);
+
+#else /* ! LINES_CRLF_TERMINATED */
+ rename_file (temp_filename, filename);
+#endif /* LINES_CRLF_TERMINATED */
+ }
+ else
+ {
+ int retcode;
+ char backup[PATH_MAX];
+ struct stat s;
+
+ (void) sprintf (backup, "%s~", filename);
+ (void) unlink_file (backup);
+ if (!isfile (filename))
+ error (1, 0, "patch original file %s does not exist",
+ short_pathname);
+ if (stat (temp_filename, &s) < 0)
+ error (1, 1, "can't stat patch file %s", temp_filename);
+ if (s.st_size == 0)
+ retcode = 0;
+ else
+ {
+ run_setup ("%s -f -s -b ~ %s %s", PATCH_PROGRAM,
+ filename, temp_filename);
+ retcode = run_exec (DEVNULL, RUN_TTY, RUN_TTY, RUN_NORMAL);
+ }
+ /* FIXME: should we really be silently ignoring errors? */
+ (void) unlink_file (temp_filename);
+ if (retcode == 0)
+ {
+ /* FIXME: should we really be silently ignoring errors? */
+ (void) unlink_file (backup);
+ }
+ else
+ {
+ int old_errno = errno;
+ char *path_tmp;
+
+ if (isfile (backup))
+ rename_file (backup, filename);
+
+ /* Get rid of the patch reject file. */
+ path_tmp = xmalloc (strlen (filename + 10));
+ strcpy (path_tmp, filename);
+ strcat (path_tmp, ".rej");
+ /* FIXME: should we really be silently ignoring errors? */
+ (void) unlink_file (path_tmp);
+ free (path_tmp);
+
+ /* Save this file to retrieve later. */
+ failed_patches =
+ (char **) xrealloc ((char *) failed_patches,
+ ((failed_patches_count + 1)
+ * sizeof (char *)));
+ failed_patches[failed_patches_count] =
+ xstrdup (short_pathname);
+ ++failed_patches_count;
+
+ error (retcode == -1 ? 1 : 0, retcode == -1 ? old_errno : 0,
+ "could not patch %s%s", filename,
+ retcode == -1 ? "" : "; will refetch");
+
+ stored_checksum_valid = 0;
+
+ return;
+ }
+ }
+ free (temp_filename);
+
+ if (stored_checksum_valid)
+ {
+ FILE *e;
+ struct MD5Context context;
+ unsigned char buf[8192];
+ unsigned len;
+ unsigned char checksum[16];
+
+ /*
+ * Compute the MD5 checksum. This will normally only be
+ * used when receiving a patch, so we always compute it
+ * here on the final file, rather than on the received
+ * data.
+ *
+ * Note that if the file is a text file, we should read it
+ * here using text mode, so its lines will be terminated the same
+ * way they were transmitted.
+ */
+ e = fopen (filename, "r");
+ if (e == NULL)
+ error (1, errno, "could not open %s", short_pathname);
+
+ MD5Init (&context);
+ while ((len = fread (buf, 1, sizeof buf, e)) != 0)
+ MD5Update (&context, buf, len);
+ if (ferror (e))
+ error (1, errno, "could not read %s", short_pathname);
+ MD5Final (checksum, &context);
+
+ fclose (e);
+
+ stored_checksum_valid = 0;
+
+ if (memcmp (checksum, stored_checksum, 16) != 0)
+ {
+ if (data->contents != UPDATE_ENTRIES_PATCH)
+ error (1, 0, "checksum failure on %s",
+ short_pathname);
+
+ error (0, 0,
+ "checksum failure after patch to %s; will refetch",
+ short_pathname);
+
+ /* Save this file to retrieve later. */
+ failed_patches =
+ (char **) xrealloc ((char *) failed_patches,
+ ((failed_patches_count + 1)
+ * sizeof (char *)));
+ failed_patches[failed_patches_count] =
+ xstrdup (short_pathname);
+ ++failed_patches_count;
+
+ return;
+ }
+ }
+
+ {
+ /* FIXME: we should be respecting the umask. */
+ int status = change_mode (filename, mode_string);
+ if (status != 0)
+ error (0, status, "cannot change mode of %s", short_pathname);
+ }
+
+ free (mode_string);
+ free (buf);
+ }
+
+ /*
+ * Process the entries line. Do this after we've written the file,
+ * since we need the timestamp.
+ */
+ if (strcmp (command_name, "export") != 0)
+ {
+ char *local_timestamp;
+ char *file_timestamp;
+
+ local_timestamp = data->timestamp;
+ if (local_timestamp == NULL || ts[0] == '+')
+ file_timestamp = time_stamp (filename);
+ else
+ file_timestamp = NULL;
+
+ /*
+ * These special version numbers signify that it is not up to
+ * date. Create a dummy timestamp which will never compare
+ * equal to the timestamp of the file.
+ */
+ if (vn[0] == '\0' || vn[0] == '0' || vn[0] == '-')
+ local_timestamp = "dummy timestamp";
+ else if (local_timestamp == NULL)
+ local_timestamp = file_timestamp;
+
+ Register (ent_list, filename, vn, local_timestamp,
+ options, tag, date, ts[0] == '+' ? file_timestamp : NULL);
+
+ if (file_timestamp)
+ free (file_timestamp);
+
+ free (scratch_entries);
+ }
+ free (entries_line);
+}
+
+static void
+handle_checked_in (args, len)
+ char *args;
+ int len;
+{
+ struct update_entries_data dat;
+ dat.contents = UPDATE_ENTRIES_CHECKIN;
+ dat.timestamp = NULL;
+ call_in_directory (args, update_entries, (char *)&dat);
+}
+
+static void
+handle_new_entry (args, len)
+ char *args;
+ int len;
+{
+ struct update_entries_data dat;
+ dat.contents = UPDATE_ENTRIES_CHECKIN;
+ dat.timestamp = "dummy timestamp from new-entry";
+ call_in_directory (args, update_entries, (char *)&dat);
+}
+
+static void
+handle_updated (args, len)
+ char *args;
+ int len;
+{
+ struct update_entries_data dat;
+ dat.contents = UPDATE_ENTRIES_UPDATE;
+ dat.timestamp = NULL;
+ call_in_directory (args, update_entries, (char *)&dat);
+}
+
+static void
+handle_merged (args, len)
+ char *args;
+ int len;
+{
+ struct update_entries_data dat;
+ dat.contents = UPDATE_ENTRIES_UPDATE;
+ dat.timestamp = "Result of merge";
+ call_in_directory (args, update_entries, (char *)&dat);
+}
+
+static void
+handle_patched (args, len)
+ char *args;
+ int len;
+{
+ struct update_entries_data dat;
+ dat.contents = UPDATE_ENTRIES_PATCH;
+ dat.timestamp = NULL;
+ call_in_directory (args, update_entries, (char *)&dat);
+}
+
+static void
+remove_entry (data, ent_list, short_pathname, filename)
+ char *data;
+ List *ent_list;
+ char *short_pathname;
+ char *filename;
+{
+ Scratch_Entry (ent_list, filename);
+}
+
+static void
+handle_remove_entry (args, len)
+ char *args;
+ int len;
+{
+ call_in_directory (args, remove_entry, (char *)NULL);
+}
+
+static void
+remove_entry_and_file (data, ent_list, short_pathname, filename)
+ char *data;
+ List *ent_list;
+ char *short_pathname;
+ char *filename;
+{
+ Scratch_Entry (ent_list, filename);
+ if (unlink_file (filename) < 0)
+ error (0, errno, "unable to remove %s", short_pathname);
+}
+
+static void
+handle_removed (args, len)
+ char *args;
+ int len;
+{
+ call_in_directory (args, remove_entry_and_file, (char *)NULL);
+}
+
+/* Is this the top level (directory containing CVSROOT)? */
+static int
+is_cvsroot_level (pathname)
+ char *pathname;
+{
+ char *short_pathname;
+
+ if (strcmp (toplevel_repos, server_cvsroot) != 0)
+ return 0;
+
+ if (!use_directory)
+ {
+ if (strncmp (pathname, server_cvsroot, strlen (server_cvsroot)) != 0)
+ error (1, 0,
+ "server bug: pathname `%s' doesn't specify file in `%s'",
+ pathname, server_cvsroot);
+ short_pathname = pathname + strlen (server_cvsroot) + 1;
+ if (short_pathname[-1] != '/')
+ error (1, 0,
+ "server bug: pathname `%s' doesn't specify file in `%s'",
+ pathname, server_cvsroot);
+ return strchr (short_pathname, '/') == NULL;
+ }
+ else
+ {
+ return strchr (pathname, '/') == NULL;
+ }
+}
+
+static void
+set_static (data, ent_list, short_pathname, filename)
+ char *data;
+ List *ent_list;
+ char *short_pathname;
+ char *filename;
+{
+ FILE *fp;
+ fp = open_file (CVSADM_ENTSTAT, "w+");
+ if (fclose (fp) == EOF)
+ error (1, errno, "cannot close %s", CVSADM_ENTSTAT);
+}
+
+static void
+handle_set_static_directory (args, len)
+ char *args;
+ int len;
+{
+ if (strcmp (command_name, "export") == 0)
+ {
+ /* Swallow the repository. */
+ read_line (NULL, 0);
+ return;
+ }
+ call_in_directory (args, set_static, (char *)NULL);
+}
+
+static void
+clear_static (data, ent_list, short_pathname, filename)
+ char *data;
+ List *ent_list;
+ char *short_pathname;
+ char *filename;
+{
+ if (unlink_file (CVSADM_ENTSTAT) < 0 && ! existence_error (errno))
+ error (1, errno, "cannot remove file %s", CVSADM_ENTSTAT);
+}
+
+static void
+handle_clear_static_directory (pathname, len)
+ char *pathname;
+ int len;
+{
+ if (strcmp (command_name, "export") == 0)
+ {
+ /* Swallow the repository. */
+ read_line (NULL, 0);
+ return;
+ }
+
+ if (is_cvsroot_level (pathname))
+ {
+ /*
+ * Top level (directory containing CVSROOT). This seems to normally
+ * lack a CVS directory, so don't try to create files in it.
+ */
+ return;
+ }
+ call_in_directory (pathname, clear_static, (char *)NULL);
+}
+
+static void
+set_sticky (data, ent_list, short_pathname, filename)
+ char *data;
+ List *ent_list;
+ char *short_pathname;
+ char *filename;
+{
+ char *tagspec;
+ FILE *f;
+
+ read_line (&tagspec, 0);
+ f = open_file (CVSADM_TAG, "w+");
+ if (fprintf (f, "%s\n", tagspec) < 0)
+ error (1, errno, "writing %s", CVSADM_TAG);
+ if (fclose (f) == EOF)
+ error (1, errno, "closing %s", CVSADM_TAG);
+ free (tagspec);
+}
+
+static void
+handle_set_sticky (pathname, len)
+ char *pathname;
+ int len;
+{
+ if (strcmp (command_name, "export") == 0)
+ {
+ /* Swallow the repository. */
+ read_line (NULL, 0);
+ /* Swallow the tag line. */
+ (void) read_line (NULL, 0);
+ return;
+ }
+ if (is_cvsroot_level (pathname))
+ {
+ /*
+ * Top level (directory containing CVSROOT). This seems to normally
+ * lack a CVS directory, so don't try to create files in it.
+ */
+
+ /* Swallow the repository. */
+ read_line (NULL, 0);
+ /* Swallow the tag line. */
+ (void) read_line (NULL, 0);
+ return;
+ }
+
+ call_in_directory (pathname, set_sticky, (char *)NULL);
+}
+
+static void
+clear_sticky (data, ent_list, short_pathname, filename)
+ char *data;
+ List *ent_list;
+ char *short_pathname;
+ char *filename;
+{
+ if (unlink_file (CVSADM_TAG) < 0 && ! existence_error (errno))
+ error (1, errno, "cannot remove %s", CVSADM_TAG);
+}
+
+static void
+handle_clear_sticky (pathname, len)
+ char *pathname;
+ int len;
+{
+ if (strcmp (command_name, "export") == 0)
+ {
+ /* Swallow the repository. */
+ read_line (NULL, 0);
+ return;
+ }
+
+ if (is_cvsroot_level (pathname))
+ {
+ /*
+ * Top level (directory containing CVSROOT). This seems to normally
+ * lack a CVS directory, so don't try to create files in it.
+ */
+ return;
+ }
+
+ call_in_directory (pathname, clear_sticky, (char *)NULL);
+}
+
+struct save_prog {
+ char *name;
+ char *dir;
+ struct save_prog *next;
+};
+
+static struct save_prog *checkin_progs;
+static struct save_prog *update_progs;
+
+/*
+ * Unlike some requests this doesn't include the repository. So we can't
+ * just call call_in_directory and have the right thing happen; we save up
+ * the requests and do them at the end.
+ */
+static void
+handle_set_checkin_prog (args, len)
+ char *args;
+ int len;
+{
+ char *prog;
+ struct save_prog *p;
+ read_line (&prog, 0);
+ p = (struct save_prog *) xmalloc (sizeof (struct save_prog));
+ p->next = checkin_progs;
+ p->dir = xstrdup (args);
+ p->name = prog;
+ checkin_progs = p;
+}
+
+static void
+handle_set_update_prog (args, len)
+ char *args;
+ int len;
+{
+ char *prog;
+ struct save_prog *p;
+ read_line (&prog, 0);
+ p = (struct save_prog *) xmalloc (sizeof (struct save_prog));
+ p->next = update_progs;
+ p->dir = xstrdup (args);
+ p->name = prog;
+ update_progs = p;
+}
+
+static void do_deferred_progs PROTO((void));
+
+static void
+do_deferred_progs ()
+{
+ struct save_prog *p;
+ struct save_prog *q;
+
+ char fname[PATH_MAX];
+ FILE *f;
+ if (toplevel_wd[0] != '\0')
+ {
+ if (chdir (toplevel_wd) < 0)
+ error (1, errno, "could not chdir to %s", toplevel_wd);
+ }
+ for (p = checkin_progs; p != NULL; )
+ {
+ sprintf (fname, "%s/%s", p->dir, CVSADM_CIPROG);
+ f = open_file (fname, "w");
+ if (fprintf (f, "%s\n", p->name) < 0)
+ error (1, errno, "writing %s", fname);
+ if (fclose (f) == EOF)
+ error (1, errno, "closing %s", fname);
+ free (p->name);
+ free (p->dir);
+ q = p->next;
+ free (p);
+ p = q;
+ }
+ checkin_progs = NULL;
+ for (p = update_progs; p != NULL; p = p->next)
+ {
+ sprintf (fname, "%s/%s", p->dir, CVSADM_UPROG);
+ f = open_file (fname, "w");
+ if (fprintf (f, "%s\n", p->name) < 0)
+ error (1, errno, "writing %s", fname);
+ if (fclose (f) == EOF)
+ error (1, errno, "closing %s", fname);
+ free (p->name);
+ free (p->dir);
+ free (p);
+ }
+ update_progs = NULL;
+}
+
+static int client_isemptydir PROTO((char *));
+
+/*
+ * Returns 1 if the argument directory exists and is completely empty,
+ * other than the existence of the CVS directory entry. Zero otherwise.
+ */
+static int
+client_isemptydir (dir)
+ char *dir;
+{
+ DIR *dirp;
+ struct dirent *dp;
+
+ if ((dirp = opendir (dir)) == NULL)
+ {
+ if (! existence_error (errno))
+ error (0, errno, "cannot open directory %s for empty check", dir);
+ return (0);
+ }
+ errno = 0;
+ while ((dp = readdir (dirp)) != NULL)
+ {
+ if (strcmp (dp->d_name, ".") != 0 && strcmp (dp->d_name, "..") != 0 &&
+ strcmp (dp->d_name, CVSADM) != 0)
+ {
+ (void) closedir (dirp);
+ return (0);
+ }
+ }
+ if (errno != 0)
+ {
+ error (0, errno, "cannot read directory %s", dir);
+ (void) closedir (dirp);
+ return (0);
+ }
+ (void) closedir (dirp);
+ return (1);
+}
+
+struct save_dir {
+ char *dir;
+ struct save_dir *next;
+};
+
+struct save_dir *prune_candidates;
+
+static void
+add_prune_candidate (dir)
+ char *dir;
+{
+ struct save_dir *p;
+
+ if (dir[0] == '.' && dir[1] == '\0')
+ return;
+ p = (struct save_dir *) xmalloc (sizeof (struct save_dir));
+ p->dir = xstrdup (dir);
+ p->next = prune_candidates;
+ prune_candidates = p;
+}
+
+static void process_prune_candidates PROTO((void));
+
+static void
+process_prune_candidates ()
+{
+ struct save_dir *p;
+ struct save_dir *q;
+
+ if (toplevel_wd[0] != '\0')
+ {
+ if (chdir (toplevel_wd) < 0)
+ error (1, errno, "could not chdir to %s", toplevel_wd);
+ }
+ for (p = prune_candidates; p != NULL; )
+ {
+ if (client_isemptydir (p->dir))
+ {
+ unlink_file_dir (p->dir);
+ }
+ free (p->dir);
+ q = p->next;
+ free (p);
+ p = q;
+ }
+}
+
+/* Send a Repository line. */
+
+static char *last_repos;
+static char *last_update_dir;
+
+static void send_repository PROTO((char *, char *, char *));
+
+static void
+send_repository (dir, repos, update_dir)
+ char *dir;
+ char *repos;
+ char *update_dir;
+{
+ char *adm_name;
+
+ if (update_dir == NULL || update_dir[0] == '\0')
+ update_dir = ".";
+
+ if (last_repos != NULL
+ && strcmp (repos, last_repos) == 0
+ && last_update_dir != NULL
+ && strcmp (update_dir, last_update_dir) == 0)
+ /* We've already sent it. */
+ return;
+
+ if (client_prune_dirs)
+ add_prune_candidate (update_dir);
+
+ /* 80 is large enough for any of CVSADM_*. */
+ adm_name = xmalloc (strlen (dir) + 80);
+
+ if (use_directory == -1)
+ use_directory = supported_request ("Directory");
+
+ if (use_directory)
+ {
+ if (fprintf (to_server, "Directory ") < 0)
+ error (1, errno, "writing to server");
+ if (fprintf (to_server, "%s", update_dir) < 0)
+ error (1, errno, "writing to server");
+
+ if (fprintf (to_server, "\n%s\n", repos)
+ < 0)
+ error (1, errno, "writing to server");
+ }
+ else
+ {
+ if (fprintf (to_server, "Repository %s\n", repos) < 0)
+ error (1, errno, "writing to server");
+ }
+ if (supported_request ("Static-directory"))
+ {
+ adm_name[0] = '\0';
+ if (dir[0] != '\0')
+ {
+ strcat (adm_name, dir);
+ strcat (adm_name, "/");
+ }
+ strcat (adm_name, CVSADM_ENTSTAT);
+ if (isreadable (adm_name))
+ {
+ if (fprintf (to_server, "Static-directory\n") < 0)
+ error (1, errno, "writing to server");
+ }
+ }
+ if (supported_request ("Sticky"))
+ {
+ FILE *f;
+ if (dir[0] == '\0')
+ strcpy (adm_name, CVSADM_TAG);
+ else
+ sprintf (adm_name, "%s/%s", dir, CVSADM_TAG);
+
+ f = fopen (adm_name, "r");
+ if (f == NULL)
+ {
+ if (! existence_error (errno))
+ error (1, errno, "reading %s", adm_name);
+ }
+ else
+ {
+ char line[80];
+ char *nl;
+ if (fprintf (to_server, "Sticky ") < 0)
+ error (1, errno, "writing to server");
+ while (fgets (line, sizeof (line), f) != NULL)
+ {
+ if (fprintf (to_server, "%s", line) < 0)
+ error (1, errno, "writing to server");
+ nl = strchr (line, '\n');
+ if (nl != NULL)
+ break;
+ }
+ if (nl == NULL)
+ if (fprintf (to_server, "\n") < 0)
+ error (1, errno, "writing to server");
+ if (fclose (f) == EOF)
+ error (0, errno, "closing %s", adm_name);
+ }
+ }
+ if (supported_request ("Checkin-prog"))
+ {
+ FILE *f;
+ if (dir[0] == '\0')
+ strcpy (adm_name, CVSADM_CIPROG);
+ else
+ sprintf (adm_name, "%s/%s", dir, CVSADM_CIPROG);
+
+ f = fopen (adm_name, "r");
+ if (f == NULL)
+ {
+ if (! existence_error (errno))
+ error (1, errno, "reading %s", adm_name);
+ }
+ else
+ {
+ char line[80];
+ char *nl;
+ if (fprintf (to_server, "Checkin-prog ") < 0)
+ error (1, errno, "writing to server");
+ while (fgets (line, sizeof (line), f) != NULL)
+ {
+ if (fprintf (to_server, "%s", line) < 0)
+ error (1, errno, "writing to server");
+ nl = strchr (line, '\n');
+ if (nl != NULL)
+ break;
+ }
+ if (nl == NULL)
+ if (fprintf (to_server, "\n") < 0)
+ error (1, errno, "writing to server");
+ if (fclose (f) == EOF)
+ error (0, errno, "closing %s", adm_name);
+ }
+ }
+ if (supported_request ("Update-prog"))
+ {
+ FILE *f;
+ if (dir[0] == '\0')
+ strcpy (adm_name, CVSADM_UPROG);
+ else
+ sprintf (adm_name, "%s/%s", dir, CVSADM_UPROG);
+
+ f = fopen (adm_name, "r");
+ if (f == NULL)
+ {
+ if (! existence_error (errno))
+ error (1, errno, "reading %s", adm_name);
+ }
+ else
+ {
+ char line[80];
+ char *nl;
+ if (fprintf (to_server, "Update-prog ") < 0)
+ error (1, errno, "writing to server");
+ while (fgets (line, sizeof (line), f) != NULL)
+ {
+ if (fprintf (to_server, "%s", line) < 0)
+ error (1, errno, "writing to server");
+ nl = strchr (line, '\n');
+ if (nl != NULL)
+ break;
+ }
+ if (nl == NULL)
+ if (fprintf (to_server, "\n") < 0)
+ error (1, errno, "writing to server");
+ if (fclose (f) == EOF)
+ error (0, errno, "closing %s", adm_name);
+ }
+ }
+ if (last_repos != NULL)
+ free (last_repos);
+ if (last_update_dir != NULL)
+ free (last_update_dir);
+ last_repos = xstrdup (repos);
+ last_update_dir = xstrdup (update_dir);
+}
+
+/* Send a Repository line and set toplevel_repos. */
+static void send_a_repository PROTO((char *, char *, char *));
+
+static void
+send_a_repository (dir, repository, update_dir)
+ char *dir;
+ char *repository;
+ char *update_dir;
+{
+ if (toplevel_repos == NULL && repository != NULL)
+ {
+ if (update_dir[0] == '\0'
+ || (update_dir[0] == '.' && update_dir[1] == '\0'))
+ toplevel_repos = xstrdup (repository);
+ else
+ {
+ /*
+ * Get the repository from a CVS/Repository file if update_dir
+ * is absolute. This is not correct in general, because
+ * the CVS/Repository file might not be the top-level one.
+ * This is for cases like "cvs update /foo/bar" (I'm not
+ * sure it matters what toplevel_repos we get, but it does
+ * matter that we don't hit the "internal error" code below).
+ */
+ if (update_dir[0] == '/')
+ toplevel_repos = Name_Repository (update_dir, update_dir);
+ else
+ {
+ /*
+ * Guess the repository of that directory by looking at a
+ * subdirectory and removing as many pathname components
+ * as are in update_dir. I think that will always (or at
+ * least almost always) be 1.
+ *
+ * So this deals with directories which have been
+ * renamed, though it doesn't necessarily deal with
+ * directories which have been put inside other
+ * directories (and cvs invoked on the containing
+ * directory). I'm not sure the latter case needs to
+ * work.
+ */
+ /*
+ * This gets toplevel_repos wrong for "cvs update ../foo"
+ * but I'm not sure toplevel_repos matters in that case.
+ */
+ int slashes_in_update_dir;
+ int slashes_skipped;
+ char *p;
+
+ slashes_in_update_dir = 0;
+ for (p = update_dir; *p != '\0'; ++p)
+ if (*p == '/')
+ ++slashes_in_update_dir;
+
+ slashes_skipped = 0;
+ p = repository + strlen (repository);
+ while (1)
+ {
+ if (p == repository)
+ error (1, 0,
+ "internal error: not enough slashes in %s",
+ repository);
+ if (*p == '/')
+ ++slashes_skipped;
+ if (slashes_skipped < slashes_in_update_dir + 1)
+ --p;
+ else
+ break;
+ }
+ toplevel_repos = xmalloc (p - repository + 1);
+ /* Note that we don't copy the trailing '/'. */
+ strncpy (toplevel_repos, repository, p - repository);
+ toplevel_repos[p - repository] = '\0';
+ }
+ }
+ }
+
+ send_repository (dir, repository, update_dir);
+}
+
+static int modules_count;
+static int modules_allocated;
+static char **modules_vector;
+
+static void
+handle_module_expansion (args, len)
+ char *args;
+ int len;
+{
+ if (modules_vector == NULL)
+ {
+ modules_allocated = 1; /* Small for testing */
+ modules_vector = (char **) xmalloc
+ (modules_allocated * sizeof (modules_vector[0]));
+ }
+ else if (modules_count >= modules_allocated)
+ {
+ modules_allocated *= 2;
+ modules_vector = (char **) xrealloc
+ ((char *) modules_vector,
+ modules_allocated * sizeof (modules_vector[0]));
+ }
+ modules_vector[modules_count] = xmalloc (strlen (args) + 1);
+ strcpy (modules_vector[modules_count], args);
+ ++modules_count;
+}
+
+void
+client_expand_modules (argc, argv, local)
+ int argc;
+ char **argv;
+ int local;
+{
+ int errs;
+ int i;
+
+ for (i = 0; i < argc; ++i)
+ send_arg (argv[i]);
+ send_a_repository ("", server_cvsroot, "");
+ if (fprintf (to_server, "expand-modules\n") < 0)
+ error (1, errno, "writing to server");
+ errs = get_server_responses ();
+ if (last_repos != NULL)
+ free (last_repos);
+ last_repos = NULL;
+ if (last_update_dir != NULL)
+ free (last_update_dir);
+ last_update_dir = NULL;
+ if (errs)
+ error (errs, 0, "");
+}
+
+void
+client_send_expansions (local)
+ int local;
+{
+ int i;
+ char *argv[1];
+ for (i = 0; i < modules_count; ++i)
+ {
+ argv[0] = modules_vector[i];
+ if (isfile (argv[0]))
+ send_files (1, argv, local, 0);
+ else
+ send_file_names (1, argv);
+ }
+ send_a_repository ("", server_cvsroot, "");
+}
+
+void
+client_nonexpanded_setup ()
+{
+ send_a_repository ("", server_cvsroot, "");
+}
+
+static void
+handle_m (args, len)
+ char *args;
+ int len;
+{
+ fwrite (args, len, sizeof (*args), stdout);
+ putc ('\n', stdout);
+}
+
+static void
+handle_e (args, len)
+ char *args;
+ int len;
+{
+ fwrite (args, len, sizeof (*args), stderr);
+ putc ('\n', stderr);
+}
+
+#endif /* CLIENT_SUPPORT */
+#if defined(CLIENT_SUPPORT) || defined(SERVER_SUPPORT)
+
+/* This table must be writeable if the server code is included. */
+struct response responses[] =
+{
+#ifdef CLIENT_SUPPORT
+#define RSP_LINE(n, f, t, s) {n, f, t, s}
+#else /* ! CLIENT_SUPPORT */
+#define RSP_LINE(n, f, t, s) {n, s}
+#endif /* CLIENT_SUPPORT */
+
+ RSP_LINE("ok", handle_ok, response_type_ok, rs_essential),
+ RSP_LINE("error", handle_error, response_type_error, rs_essential),
+ RSP_LINE("Valid-requests", handle_valid_requests, response_type_normal,
+ rs_essential),
+ RSP_LINE("Checked-in", handle_checked_in, response_type_normal,
+ rs_essential),
+ RSP_LINE("New-entry", handle_new_entry, response_type_normal, rs_optional),
+ RSP_LINE("Checksum", handle_checksum, response_type_normal, rs_optional),
+ RSP_LINE("Copy-file", handle_copy_file, response_type_normal, rs_optional),
+ RSP_LINE("Updated", handle_updated, response_type_normal, rs_essential),
+ RSP_LINE("Merged", handle_merged, response_type_normal, rs_essential),
+ RSP_LINE("Patched", handle_patched, response_type_normal, rs_optional),
+ RSP_LINE("Removed", handle_removed, response_type_normal, rs_essential),
+ RSP_LINE("Remove-entry", handle_remove_entry, response_type_normal,
+ rs_optional),
+ RSP_LINE("Set-static-directory", handle_set_static_directory,
+ response_type_normal,
+ rs_optional),
+ RSP_LINE("Clear-static-directory", handle_clear_static_directory,
+ response_type_normal,
+ rs_optional),
+ RSP_LINE("Set-sticky", handle_set_sticky, response_type_normal,
+ rs_optional),
+ RSP_LINE("Clear-sticky", handle_clear_sticky, response_type_normal,
+ rs_optional),
+ RSP_LINE("Set-checkin-prog", handle_set_checkin_prog, response_type_normal,
+ rs_optional),
+ RSP_LINE("Set-update-prog", handle_set_update_prog, response_type_normal,
+ rs_optional),
+ RSP_LINE("Module-expansion", handle_module_expansion, response_type_normal,
+ rs_optional),
+ RSP_LINE("M", handle_m, response_type_normal, rs_essential),
+ RSP_LINE("E", handle_e, response_type_normal, rs_essential),
+ /* Possibly should be response_type_error. */
+ RSP_LINE(NULL, NULL, response_type_normal, rs_essential)
+
+#undef RSP_LINE
+};
+
+#endif /* CLIENT_SUPPORT or SERVER_SUPPORT */
+#ifdef CLIENT_SUPPORT
+
+/*
+ * Get some server responses and process them. Returns nonzero for
+ * error, 0 for success.
+ */
+int
+get_server_responses ()
+{
+ struct response *rs;
+ do
+ {
+ char *cmd;
+ int len;
+
+ len = read_line (&cmd, 0);
+ for (rs = responses; rs->name != NULL; ++rs)
+ if (strncmp (cmd, rs->name, strlen (rs->name)) == 0)
+ {
+ int cmdlen = strlen (rs->name);
+ if (cmd[cmdlen] == '\0')
+ ;
+ else if (cmd[cmdlen] == ' ')
+ ++cmdlen;
+ else
+ /*
+ * The first len characters match, but it's a different
+ * response. e.g. the response is "oklahoma" but we
+ * matched "ok".
+ */
+ continue;
+ (*rs->func) (cmd + cmdlen, len - cmdlen);
+ break;
+ }
+ if (rs->name == NULL)
+ /* It's OK to print just to the first '\0'. */
+ error (0, 0,
+ "warning: unrecognized response `%s' from cvs server",
+ cmd);
+ free (cmd);
+ } while (rs->type == response_type_normal);
+ return rs->type == response_type_error ? 1 : 0;
+}
+
+/* Get the responses and then close the connection. */
+int server_fd = -1;
+
+int
+get_responses_and_close ()
+{
+ int errs = get_server_responses ();
+
+ do_deferred_progs ();
+
+ if (client_prune_dirs)
+ process_prune_candidates ();
+
+#if defined(HAVE_KERBEROS) || defined(AUTH_CLIENT_SUPPORT)
+ if (server_fd != -1)
+ {
+ if (shutdown (server_fd, 1) < 0)
+ error (1, errno, "shutting down connection to %s", server_host);
+ /*
+ * In this case, both sides of the net connection will use the
+ * same fd.
+ */
+ if (fileno (from_server) != fileno (to_server))
+ {
+ if (fclose (to_server) != 0)
+ error (1, errno, "closing down connection to %s", server_host);
+ }
+ }
+ else
+#endif /* HAVE_KERBEROS || AUTH_CLIENT_SUPPORT */
+
+#ifdef SHUTDOWN_SERVER
+ SHUTDOWN_SERVER (fileno (to_server));
+#else /* ! SHUTDOWN_SERVER */
+ {
+
+#ifdef START_RSH_WITH_POPEN_RW
+ if (pclose (to_server) == EOF)
+#else /* ! START_RSH_WITH_POPEN_RW */
+ if (fclose (to_server) == EOF)
+#endif /* START_RSH_WITH_POPEN_RW */
+ {
+ error (1, errno, "closing connection to %s", server_host);
+ }
+ }
+
+ if (getc (from_server) != EOF)
+ error (0, 0, "dying gasps from %s unexpected", server_host);
+ else if (ferror (from_server))
+ error (0, errno, "reading from %s", server_host);
+
+ fclose (from_server);
+#endif /* SHUTDOWN_SERVER */
+
+#if ! RSH_NOT_TRANSPARENT
+ if (rsh_pid != -1
+ && waitpid (rsh_pid, (int *) 0, 0) == -1)
+ if (errno != ECHILD)
+ error (1, errno, "waiting for process %d", rsh_pid);
+#endif /* ! RSH_NOT_TRANSPARENT */
+
+ return errs;
+}
+
+#ifndef RSH_NOT_TRANSPARENT
+static void start_rsh_server PROTO((int *, int *));
+#endif /* RSH_NOT_TRANSPARENT */
+
+int
+supported_request (name)
+ char *name;
+{
+ struct request *rq;
+
+ for (rq = requests; rq->name; rq++)
+ if (!strcmp (rq->name, name))
+ return rq->status == rq_supported;
+ error (1, 0, "internal error: testing support for unknown option?");
+}
+
+
+#ifdef AUTH_CLIENT_SUPPORT
+void
+init_sockaddr (name, hostname, port)
+ struct sockaddr_in *name;
+ const char *hostname;
+ unsigned short int port;
+{
+ struct hostent *hostinfo;
+
+ name->sin_family = AF_INET;
+ name->sin_port = htons (port);
+ hostinfo = gethostbyname (hostname);
+ if (hostinfo == NULL)
+ {
+ fprintf (stderr, "Unknown host %s.\n", hostname);
+ exit (EXIT_FAILURE);
+ }
+ name->sin_addr = *(struct in_addr *) hostinfo->h_addr;
+}
+
+void
+connect_to_pserver (tofdp, fromfdp, log)
+ int *tofdp, *fromfdp;
+ char *log;
+{
+ int sock;
+ int tofd, fromfd;
+ struct hostent *host;
+ struct sockaddr_in client_sai;
+
+ sock = socket (AF_INET, SOCK_STREAM, 0);
+ if (sock == -1)
+ {
+ fprintf (stderr, "socket() failed\n");
+ exit (1);
+ }
+ init_sockaddr (&client_sai, server_host, CVS_AUTH_PORT);
+ connect (sock, (struct sockaddr *) &client_sai, sizeof (client_sai));
+
+ /* Run the authorization mini-protocol before anything else. */
+ {
+ int i;
+ char ch, read_buf[PATH_MAX];
+ char *begin = "BEGIN AUTH REQUEST\n";
+ char *repository = server_cvsroot;
+ char *username = server_user;
+ char *password = NULL;
+ char *end = "END AUTH REQUEST\n";
+
+ /* Get the password, probably from ~/.cvspass. */
+ password = get_cvs_password (server_user, server_host, server_cvsroot);
+
+ /* Announce that we're starting the authorization protocol. */
+ write (sock, begin, strlen (begin));
+
+ /* Send the data the server needs. */
+ write (sock, repository, strlen (repository));
+ write (sock, "\n", 1);
+ write (sock, username, strlen (username));
+ write (sock, "\n", 1);
+ write (sock, password, strlen (password));
+ write (sock, "\n", 1);
+
+ /* Announce that we're ending the authorization protocol. */
+ write (sock, end, strlen (end));
+
+ /* Paranoia. */
+ memset (password, 0, strlen (password));
+
+ /* Get ACK or NACK from the server.
+ *
+ * We could avoid this careful read-char loop by having the ACK
+ * and NACK cookies be of the same length, so we'd simply read
+ * that length and see what we got. But then there'd be Yet
+ * Another Protocol Requirement floating around, and someday
+ * someone would make a change that breaks it and spend a hellish
+ * day tracking it down. Therefore, we use "\n" to mark off the
+ * end of both ACK and NACK, and we read until "\n".
+ */
+ ch = 0;
+ memset (read_buf, 0, PATH_MAX);
+ for (i = 0; (i < (PATH_MAX - 1)) && (ch != '\n'); i++)
+ {
+ read (sock, &ch, 1);
+ read_buf[i] = ch;
+ }
+
+ if (strcmp (read_buf, "I HATE YOU\n") == 0)
+ {
+ /* Authorization not granted. */
+ if (shutdown (sock, 2) < 0)
+ error (1, errno, "shutdown() failed (server %s)", server_host);
+ error (1, 0,
+ "authorization failed: server %s rejected access",
+ server_host);
+ }
+ else if (strcmp (read_buf, "I LOVE YOU\n") != 0)
+ {
+ /* Unrecognized response from server. */
+ if (shutdown (sock, 2) < 0)
+ error (1, errno, "shutdown() failed (server %s)", server_host);
+ error (1, 0,
+ "unrecognized auth response from %s: %s",
+ server_host, read_buf);
+ }
+ /* Else authorization granted, so we can go on... */
+ }
+
+ /* This was stolen straight from start_kerberos_server(). */
+ {
+ server_fd = sock;
+ close_on_exec (server_fd);
+ /*
+ * If we do any filtering, TOFD and FROMFD will be
+ * closed. So make sure they're copies of SERVER_FD,
+ * and not the same fd number.
+ */
+ if (log)
+ {
+ tofd = dup (sock);
+ fromfd = dup (sock);
+ }
+ else
+ tofd = fromfd = sock;
+ }
+
+ /* Hand them back to the caller. */
+ *tofdp = tofd;
+ *fromfdp = fromfd;
+}
+#endif /* AUTH_CLIENT_SUPPORT */
+
+
+#if HAVE_KERBEROS
+void
+start_kerberos_server (tofdp, fromfdp, log)
+ int *tofdp, *fromfdp;
+ char *log;
+{
+ int tofd, fromfd;
+
+ struct hostent *hp;
+ char *hname;
+ const char *realm;
+ const char *portenv;
+ int port;
+ struct sockaddr_in sin;
+ int s;
+ KTEXT_ST ticket;
+ int status;
+
+ /*
+ * We look up the host to give a better error message if it
+ * does not exist. However, we then pass server_host to
+ * krb_sendauth, rather than the canonical name, because
+ * krb_sendauth is going to do its own canonicalization anyhow
+ * and that lets us not worry about the static storage used by
+ * gethostbyname.
+ */
+ hp = gethostbyname (server_host);
+ if (hp == NULL)
+ error (1, 0, "%s: unknown host", server_host);
+ hname = xmalloc (strlen (hp->h_name) + 1);
+ strcpy (hname, hp->h_name);
+
+ realm = krb_realmofhost (hname);
+
+ portenv = getenv ("CVS_CLIENT_PORT");
+ if (portenv != NULL)
+ {
+ port = atoi (portenv);
+ if (port <= 0)
+ goto try_rsh_no_message;
+ port = htons (port);
+ }
+ else
+ {
+ struct servent *sp;
+
+ sp = getservbyname ("cvs", "tcp");
+ if (sp == NULL)
+ port = htons (CVS_PORT);
+ else
+ port = sp->s_port;
+ }
+
+ s = socket (AF_INET, SOCK_STREAM, 0);
+ if (s < 0)
+ error (1, errno, "socket");
+
+ memset (&sin, 0, sizeof sin);
+ sin.sin_family = AF_INET;
+ sin.sin_addr.s_addr = INADDR_ANY;
+ sin.sin_port = 0;
+
+ if (bind (s, (struct sockaddr *) &sin, sizeof sin) < 0)
+ error (1, errno, "bind");
+
+ memcpy (&sin.sin_addr, hp->h_addr, hp->h_length);
+ sin.sin_port = port;
+
+ tofd = -1;
+ if (connect (s, (struct sockaddr *) &sin, sizeof sin) < 0)
+ {
+ error (0, errno, "connect");
+ close (s);
+ }
+ else
+ {
+ struct sockaddr_in laddr;
+ int laddrlen;
+ MSG_DAT msg_data;
+ CREDENTIALS cred;
+ Key_schedule sched;
+
+ laddrlen = sizeof (laddr);
+ if (getsockname (s, (struct sockaddr *) &laddr, &laddrlen) < 0)
+ error (1, errno, "getsockname");
+
+ /* We don't care about the checksum, and pass it as zero. */
+ status = krb_sendauth (KOPT_DO_MUTUAL, s, &ticket, "rcmd",
+ hname, realm, (unsigned long) 0, &msg_data,
+ &cred, sched, &laddr, &sin, "KCVSV1.0");
+ if (status != KSUCCESS)
+ {
+ error (0, 0, "kerberos: %s", krb_get_err_text(status));
+ close (s);
+ }
+ else
+ {
+ server_fd = s;
+ close_on_exec (server_fd);
+ /*
+ * If we do any filtering, TOFD and FROMFD will be
+ * closed. So make sure they're copies of SERVER_FD,
+ * and not the same fd number.
+ */
+ if (log)
+ {
+ tofd = dup (s);
+ fromfd = dup (s);
+ }
+ else
+ tofd = fromfd = s;
+ }
+ }
+
+ if (tofd == -1)
+ {
+ error (0, 0, "trying to start server using rsh");
+ try_rsh_no_message:
+ server_fd = -1;
+#if ! RSH_NOT_TRANSPARENT
+ start_rsh_server (&tofd, &fromfd);
+#else /* RSH_NOT_TRANSPARENT */
+#if defined (START_SERVER)
+ START_SERVER (&tofd, &fromfd, getcaller (),
+ server_user, server_host, server_cvsroot);
+#endif /* defined (START_SERVER) */
+#endif /* ! RSH_NOT_TRANSPARENT */
+ }
+ free (hname);
+
+ /* Give caller the values it wants. */
+ *tofdp = tofd;
+ *fromfdp = fromfd;
+}
+
+#endif /* HAVE_KERBEROS */
+
+/* Contact the server. */
+void
+start_server ()
+{
+ int tofd, fromfd;
+ char *log = getenv ("CVS_CLIENT_LOG");
+
+#if HAVE_KERBEROS
+ start_kerberos_server (&tofd, &fromfd, log);
+
+#else /* ! HAVE_KERBEROS */
+
+#ifdef AUTH_CLIENT_SUPPORT
+ if (use_authenticating_server)
+ {
+ connect_to_pserver (&tofd, &fromfd, log);
+ }
+ else
+#endif /* AUTH_CLIENT_SUPPORT */
+ {
+#if ! RSH_NOT_TRANSPARENT
+ start_rsh_server (&tofd, &fromfd);
+#else /* RSH_NOT_TRANSPARENT */
+
+#if defined(START_SERVER)
+ START_SERVER (&tofd, &fromfd, getcaller (),
+ server_user, server_host, server_cvsroot);
+#endif /* defined(START_SERVER) */
+#endif /* ! RSH_NOT_TRANSPARENT */
+ }
+#endif /* HAVE_KERBEROS */
+
+ /* todo: some OS's don't need these calls... */
+ close_on_exec (tofd);
+ close_on_exec (fromfd);
+
+ if (log)
+ {
+ int len = strlen (log);
+ char *buf = xmalloc (5 + len);
+ char *p;
+ static char *teeprog[3] = { "tee" };
+
+ teeprog[1] = buf;
+ strcpy (buf, log);
+ p = buf + len;
+
+ strcpy (p, ".in");
+ tofd = filter_stream_through_program (tofd, 0, teeprog, 0);
+
+ strcpy (p, ".out");
+ fromfd = filter_stream_through_program (fromfd, 1, teeprog, 0);
+
+ free (buf);
+ }
+
+ /* These will use binary mode on systems which have it. */
+ to_server = fdopen (tofd, FOPEN_BINARY_WRITE);
+ if (to_server == NULL)
+ error (1, errno, "cannot fdopen %d for write", tofd);
+ from_server = fdopen (fromfd, FOPEN_BINARY_READ);
+ if (from_server == NULL)
+ error (1, errno, "cannot fdopen %d for read", fromfd);
+
+ /* Clear static variables. */
+ if (toplevel_repos != NULL)
+ free (toplevel_repos);
+ toplevel_repos = NULL;
+ if (last_dirname != NULL)
+ free (last_dirname);
+ last_dirname = NULL;
+ if (last_repos != NULL)
+ free (last_repos);
+ last_repos = NULL;
+ if (last_update_dir != NULL)
+ free (last_update_dir);
+ last_update_dir = NULL;
+ stored_checksum_valid = 0;
+
+ if (fprintf (to_server, "Root %s\n", server_cvsroot) < 0)
+ error (1, errno, "writing to server");
+ {
+ struct response *rs;
+ if (fprintf (to_server, "Valid-responses") < 0)
+ error (1, errno, "writing to server");
+ for (rs = responses; rs->name != NULL; ++rs)
+ {
+ if (fprintf (to_server, " %s", rs->name) < 0)
+ error (1, errno, "writing to server");
+ }
+ if (fprintf (to_server, "\n") < 0)
+ error (1, errno, "writing to server");
+ }
+ if (fprintf (to_server, "valid-requests\n") < 0)
+ error (1, errno, "writing to server");
+ if (get_server_responses ())
+ exit (1);
+
+ /*
+ * Now handle global options.
+ *
+ * -H, -f, -d, -e should be handled OK locally.
+ *
+ * -b we ignore (treating it as a server installation issue).
+ * FIXME: should be an error message.
+ *
+ * -v we print local version info; FIXME: Add a protocol request to get
+ * the version from the server so we can print that too.
+ *
+ * -l -t -r -w -q -n and -Q need to go to the server.
+ */
+
+ {
+ int have_global = supported_request ("Global_option");
+
+ if (noexec)
+ {
+ if (have_global)
+ {
+ if (fprintf (to_server, "Global_option -n\n") < 0)
+ error (1, errno, "writing to server");
+ }
+ else
+ error (1, 0,
+ "This server does not support the global -n option.");
+ }
+ if (quiet)
+ {
+ if (have_global)
+ {
+ if (fprintf (to_server, "Global_option -q\n") < 0)
+ error (1, errno, "writing to server");
+ }
+ else
+ error (1, 0,
+ "This server does not support the global -q option.");
+ }
+ if (really_quiet)
+ {
+ if (have_global)
+ {
+ if (fprintf (to_server, "Global_option -Q\n") < 0)
+ error (1, errno, "writing to server");
+ }
+ else
+ error (1, 0,
+ "This server does not support the global -Q option.");
+ }
+ if (!cvswrite)
+ {
+ if (have_global)
+ {
+ if (fprintf (to_server, "Global_option -r\n") < 0)
+ error (1, errno, "writing to server");
+ }
+ else
+ error (1, 0,
+ "This server does not support the global -r option.");
+ }
+ if (trace)
+ {
+ if (have_global)
+ {
+ if (fprintf (to_server, "Global_option -t\n") < 0)
+ error (1, errno, "writing to server");
+ }
+ else
+ error (1, 0,
+ "This server does not support the global -t option.");
+ }
+ if (logoff)
+ {
+ if (have_global)
+ {
+ if (fprintf (to_server, "Global_option -l\n") < 0)
+ error (1, errno, "writing to server");
+ }
+ else
+ error (1, 0,
+ "This server does not support the global -l option.");
+ }
+ }
+ if (gzip_level)
+ {
+ if (supported_request ("gzip-file-contents"))
+ {
+ if (fprintf (to_server, "gzip-file-contents %d\n", gzip_level) < 0)
+ error (1, 0, "writing to server");
+ }
+ else
+ {
+ fprintf (stderr, "server doesn't support gzip-file-contents\n");
+ gzip_level = 0;
+ }
+ }
+}
+
+#ifndef RSH_NOT_TRANSPARENT
+/* Contact the server by starting it with rsh. */
+
+/* Right now, we have two different definitions for this function,
+ depending on whether we start the rsh server using popenRW or not.
+ This isn't ideal, and the best thing would probably be to change
+ the OS/2 port to be more like the regular Unix client (i.e., by
+ implementing piped_child)... but I'm doing something else at the
+ moment, and wish to make only one change at a time. -Karl */
+
+#ifdef START_RSH_WITH_POPEN_RW
+
+static void
+start_rsh_server (tofdp, fromfdp)
+ int *tofdp, *fromfdp;
+{
+ int pipes[2];
+
+ /* If you're working through firewalls, you can set the
+ CVS_RSH environment variable to a script which uses rsh to
+ invoke another rsh on a proxy machine. */
+ char *cvs_rsh = getenv ("CVS_RSH");
+ char *cvs_server = getenv ("CVS_SERVER");
+ char command[PATH_MAX];
+ int i = 0;
+ /* This needs to fit "rsh", "-b", "-l", "USER", "host",
+ "cmd (w/ args)", and NULL. We leave some room to grow. */
+ char *rsh_argv[10];
+
+ if (!cvs_rsh)
+ cvs_rsh = "rsh";
+ if (!cvs_server)
+ cvs_server = "cvs";
+
+ /* If you are running a very old (Nov 3, 1994, before 1.5)
+ * version of the server, you need to make sure that your .bashrc
+ * on the server machine does not set CVSROOT to something
+ * containing a colon (or better yet, upgrade the server). */
+
+ /* The command line starts out with rsh. */
+ rsh_argv[i++] = cvs_rsh;
+
+ /* "-b" for binary, under OS/2. */
+ rsh_argv[i++] = "-b";
+
+ /* Then we strcat more things on the end one by one. */
+ if (server_user != NULL)
+ {
+ rsh_argv[i++] = "-l";
+ rsh_argv[i++] = server_user;
+ }
+
+ rsh_argv[i++] = server_host;
+ rsh_argv[i++] = cvs_server;
+ rsh_argv[i++] = "server";
+
+ /* Mark the end of the arg list. */
+ rsh_argv[i] = (char *) NULL;
+
+ if (trace)
+ {
+ fprintf (stderr, " -> Starting server: ");
+ fprintf (stderr, "%s", command);
+ putc ('\n', stderr);
+ }
+
+ /* Do the deed. */
+ rsh_pid = popenRW (rsh_argv, pipes);
+ if (rsh_pid < 0)
+ error (1, errno, "cannot start server via rsh");
+
+ /* Give caller the file descriptors. */
+ *tofdp = pipes[0];
+ *fromfdp = pipes[1];
+}
+
+#else /* ! START_RSH_WITH_POPEN_RW */
+
+static void
+start_rsh_server (tofdp, fromfdp)
+ int *tofdp;
+ int *fromfdp;
+{
+ /* If you're working through firewalls, you can set the
+ CVS_RSH environment variable to a script which uses rsh to
+ invoke another rsh on a proxy machine. */
+ char *cvs_rsh = getenv ("CVS_RSH");
+ char *cvs_server = getenv ("CVS_SERVER");
+ char *command;
+
+ if (!cvs_rsh)
+ cvs_rsh = "rsh";
+ if (!cvs_server)
+ cvs_server = "cvs";
+
+ /* Pass the command to rsh as a single string. This shouldn't
+ affect most rsh servers at all, and will pacify some buggy
+ versions of rsh that grab switches out of the middle of the
+ command (they're calling the GNU getopt routines incorrectly). */
+ command = xmalloc (strlen (cvs_server)
+ + strlen (server_cvsroot)
+ + 50);
+
+ /* If you are running a very old (Nov 3, 1994, before 1.5)
+ * version of the server, you need to make sure that your .bashrc
+ * on the server machine does not set CVSROOT to something
+ * containing a colon (or better yet, upgrade the server). */
+ sprintf (command, "%s server", cvs_server);
+
+ {
+ char *argv[10];
+ char **p = argv;
+
+ *p++ = cvs_rsh;
+ *p++ = server_host;
+
+ /* If the login names differ between client and server
+ * pass it on to rsh.
+ */
+ if (server_user != NULL)
+ {
+ *p++ = "-l";
+ *p++ = server_user;
+ }
+
+ *p++ = command;
+ *p++ = NULL;
+
+ if (trace)
+ {
+ int i;
+
+ fprintf (stderr, " -> Starting server: ");
+ for (i = 0; argv[i]; i++)
+ fprintf (stderr, "%s ", argv[i]);
+ putc ('\n', stderr);
+ }
+ rsh_pid = piped_child (argv, tofdp, fromfdp);
+
+ if (rsh_pid < 0)
+ error (1, errno, "cannot start server via rsh");
+ }
+}
+
+#endif /* START_RSH_WITH_POPEN_RW */
+#endif /* ! RSH_NOT_TRANSPARENT */
+
+
+
+/* Send an argument STRING. */
+void
+send_arg (string)
+ char *string;
+{
+ char *p = string;
+ if (fprintf (to_server, "Argument ") < 0)
+ error (1, errno, "writing to server");
+ while (*p)
+ {
+ if (*p == '\n')
+ {
+ if (fprintf (to_server, "\nArgumentx ") < 0)
+ error (1, errno, "writing to server");
+ }
+ else if (putc (*p, to_server) == EOF)
+ error (1, errno, "writing to server");
+ ++p;
+ }
+ if (putc ('\n', to_server) == EOF)
+ error (1, errno, "writing to server");
+}
+
+static void send_modified PROTO ((char *, char *, Vers_TS *));
+
+static void
+send_modified (file, short_pathname, vers)
+ char *file;
+ char *short_pathname;
+ Vers_TS *vers;
+{
+ /* File was modified, send it. */
+ struct stat sb;
+ int fd;
+ char *buf;
+ char *mode_string;
+ int bufsize;
+ int bin = 0;
+
+ /* Don't think we can assume fstat exists. */
+ if (stat (file, &sb) < 0)
+ error (1, errno, "reading %s", short_pathname);
+
+ mode_string = mode_to_string (sb.st_mode);
+
+ /* Beware: on systems using CRLF line termination conventions,
+ the read and write functions will convert CRLF to LF, so the
+ number of characters read is not the same as sb.st_size. Text
+ files should always be transmitted using the LF convention, so
+ we don't want to disable this conversion. */
+ bufsize = sb.st_size;
+ buf = xmalloc (bufsize);
+
+ /* Is the file marked as containing binary data by the "-kb" flag?
+ If so, make sure to open it in binary mode: */
+
+ bin = !(strcmp (vers->options, "-kb"));
+ fd = open (file, O_RDONLY | (bin ? OPEN_BINARY : 0));
+
+ if (fd < 0)
+ error (1, errno, "reading %s", short_pathname);
+
+ if (gzip_level && sb.st_size > 100)
+ {
+ int nread, newsize = 0, gzip_status;
+ pid_t gzip_pid;
+ char *bufp = buf;
+ int readsize = 8192;
+#ifdef LINES_CRLF_TERMINATED
+ char tempfile[L_tmpnam];
+ int converting;
+#endif /* LINES_CRLF_TERMINATED */
+
+#ifdef LINES_CRLF_TERMINATED
+ /* Assume everything in a "cvs import" is text. */
+ if (vers == NULL)
+ converting = 1;
+ else
+ /* Otherwise, we convert things unless they're binary. */
+ converting = (! bin);
+
+ if (converting)
+ {
+ /* gzip reads and writes files without munging CRLF
+ sequences, as it should, but files should be
+ transmitted in LF form. Convert CRLF to LF before
+ gzipping, on systems where this is necessary.
+
+ If Windows NT supported fork, we could do this by
+ pushing another filter on in front of gzip. But it
+ doesn't. I'd have to write a trivial little program to
+ do the conversion and have CVS spawn it off. But
+ little executables like that always get lost.
+
+ Alternatively, this cruft could go away if we switched
+ to a gzip library instead of a subprocess; then we
+ could tell gzip to open the file with CRLF translation
+ enabled. */
+ if (close (fd) < 0)
+ error (0, errno, "warning: can't close %s", short_pathname);
+
+ tmpnam (tempfile);
+ convert_file (file, O_RDONLY,
+ tempfile,
+ O_WRONLY | O_CREAT | O_TRUNC | OPEN_BINARY);
+
+ /* This OPEN_BINARY doesn't make any difference, I think, because
+ gzip will deal with the inherited handle as it pleases. But I
+ do remember something obscure in the manuals about propagating
+ the translation mode to created processes via environment
+ variables, ick. */
+ fd = open (tempfile, O_RDONLY | OPEN_BINARY);
+ if (fd < 0)
+ error (1, errno, "reading %s", short_pathname);
+ }
+#endif /* LINES_CRLF_TERMINATED */
+
+ fd = filter_through_gzip (fd, 1, gzip_level, &gzip_pid);
+ while (1)
+ {
+ if ((bufp - buf) + readsize >= bufsize)
+ {
+ /*
+ * We need to expand the buffer if gzip ends up expanding
+ * the file.
+ */
+ newsize = bufp - buf;
+ while (newsize + readsize >= bufsize)
+ bufsize *= 2;
+ buf = xrealloc (buf, bufsize);
+ bufp = buf + newsize;
+ }
+ nread = read (fd, bufp, readsize);
+ if (nread < 0)
+ error (1, errno, "reading from gzip pipe");
+ else if (nread == 0)
+ /* eof */
+ break;
+ bufp += nread;
+ }
+ newsize = bufp - buf;
+ if (close (fd) < 0)
+ error (0, errno, "warning: can't close %s", short_pathname);
+
+ if (waitpid (gzip_pid, &gzip_status, 0) != gzip_pid)
+ error (1, errno, "waiting for gzip proc %d", gzip_pid);
+ else if (gzip_status != 0)
+ error (1, errno, "gzip exited %d", gzip_status);
+
+#if LINES_CRLF_TERMINATED
+ if (converting)
+ {
+ if (unlink (tempfile) < 0)
+ error (0, errno,
+ "warning: can't remove temp file %s", tempfile);
+ }
+#endif /* LINES_CRLF_TERMINATED */
+
+ fprintf (to_server, "Modified %s\n%s\nz%lu\n", file, mode_string,
+ (unsigned long) newsize);
+ fwrite (buf, newsize, 1, to_server);
+ if (feof (to_server) || ferror (to_server))
+ error (1, errno, "writing to server");
+ }
+ else
+ {
+ int newsize;
+
+ {
+ char *bufp = buf;
+ int len;
+
+ while ((len = read (fd, bufp, (buf + sb.st_size) - bufp)) > 0)
+ bufp += len;
+
+ if (len < 0)
+ error (1, errno, "reading %s", short_pathname);
+
+ newsize = bufp - buf;
+ }
+ if (close (fd) < 0)
+ error (0, errno, "warning: can't close %s", short_pathname);
+
+ if (fprintf (to_server, "Modified %s\n%s\n%lu\n", file,
+ mode_string, (unsigned long) newsize) < 0)
+ error (1, errno, "writing to server");
+
+ /*
+ * Note that this only ends with a newline if the file ended with
+ * one.
+ */
+ if (newsize > 0)
+ if (fwrite (buf, newsize, 1, to_server) != 1)
+ error (1, errno, "writing to server");
+ }
+ free (buf);
+ free (mode_string);
+}
+
+/* Deal with one file. */
+static int
+send_fileproc (file, update_dir, repository, entries, srcfiles)
+ char *file;
+ char *update_dir;
+ char *repository;
+ List *entries;
+ List *srcfiles;
+{
+ Vers_TS *vers;
+ int update_dir_len = strlen (update_dir);
+ char *short_pathname = xmalloc (update_dir_len + strlen (file) + 40);
+ strcpy (short_pathname, update_dir);
+ if (update_dir[0] != '\0')
+ strcat (short_pathname, "/");
+ strcat (short_pathname, file);
+
+ send_a_repository ("", repository, update_dir);
+
+ vers = Version_TS ((char *)NULL, (char *)NULL, (char *)NULL,
+ (char *)NULL,
+ file, 0, 0, entries, (List *)NULL);
+
+ if (vers->vn_user != NULL)
+ {
+ /* The Entries request. */
+ /* Not sure about whether this deals with -k and stuff right. */
+ if (fprintf (to_server, "Entry /%s/%s/%s%s/%s/", file, vers->vn_user,
+ vers->ts_conflict == NULL ? "" : "+",
+ (vers->ts_conflict == NULL ? ""
+ : (vers->ts_user != NULL &&
+ strcmp (vers->ts_conflict, vers->ts_user) == 0
+ ? "="
+ : "modified")),
+ vers->options) < 0)
+ error (1, errno, "writing to server");
+ if (vers->entdata != NULL && vers->entdata->tag)
+ {
+ if (fprintf (to_server, "T%s", vers->entdata->tag) < 0)
+ error (1, errno, "writing to server");
+ }
+ else if (vers->entdata != NULL && vers->entdata->date)
+ if (fprintf (to_server, "D%s", vers->entdata->date) < 0)
+ error (1, errno, "writing to server");
+ if (fprintf (to_server, "\n") < 0)
+ error (1, errno, "writing to server");
+ }
+
+ if (vers->ts_user == NULL)
+ {
+ /*
+ * Do we want to print "file was lost" like normal CVS?
+ * Would it always be appropriate?
+ */
+ /* File no longer exists. */
+ if (!use_unchanged)
+ {
+ /* if the server is old, use the old request... */
+ if (fprintf (to_server, "Lost %s\n", file) < 0)
+ error (1, errno, "writing to server");
+ /*
+ * Otherwise, don't do anything for missing files,
+ * they just happen.
+ */
+ }
+ }
+ else if (vers->ts_rcs == NULL
+ || strcmp (vers->ts_user, vers->ts_rcs) != 0)
+ {
+ send_modified (file, short_pathname, vers);
+ }
+ else
+ {
+ /* Only use this request if the server supports it... */
+ if (use_unchanged)
+ if (fprintf (to_server, "Unchanged %s\n", file) < 0)
+ error (1, errno, "writing to server");
+ }
+
+ /* if this directory has an ignore list, add this file to it */
+ if (ignlist)
+ {
+ Node *p;
+
+ p = getnode ();
+ p->type = FILES;
+ p->key = xstrdup (file);
+ (void) addnode (ignlist, p);
+ }
+
+ freevers_ts (&vers);
+ free (short_pathname);
+ return 0;
+}
+
+/*
+ * send_dirent_proc () is called back by the recursion processor before a
+ * sub-directory is processed for update.
+ * A return code of 0 indicates the directory should be
+ * processed by the recursion code. A return of non-zero indicates the
+ * recursion code should skip this directory.
+ *
+ */
+static Dtype
+send_dirent_proc (dir, repository, update_dir)
+ char *dir;
+ char *repository;
+ char *update_dir;
+{
+ int dir_exists;
+ char *cvsadm_repos_name;
+
+ /*
+ * If the directory does not exist yet (e.g. "cvs update -d
+ * foo"), no need to send any files from it.
+ */
+ dir_exists = isdir (dir);
+
+ if (ignore_directory (update_dir))
+ {
+ /* print the warm fuzzy message */
+ if (!quiet)
+ error (0, 0, "Ignoring %s", update_dir);
+ return (R_SKIP_ALL);
+ }
+
+ /* initialize the ignore list for this directory */
+ ignlist = getlist ();
+
+ /*
+ * If there is an empty directory (e.g. we are doing `cvs add' on a
+ * newly-created directory), the server still needs to know about it.
+ */
+
+ cvsadm_repos_name = xmalloc (strlen (dir) + sizeof (CVSADM_REP) + 80);
+ sprintf (cvsadm_repos_name, "%s/%s", dir, CVSADM_REP);
+ if (dir_exists && isreadable (cvsadm_repos_name))
+ {
+ /*
+ * Get the repository from a CVS/Repository file whenever possible.
+ * The repository variable is wrong if the names in the local
+ * directory don't match the names in the repository.
+ */
+ char *repos = Name_Repository (dir, update_dir);
+ send_a_repository (dir, repos, update_dir);
+ free (repos);
+ }
+ else
+ send_a_repository (dir, repository, update_dir);
+ free (cvsadm_repos_name);
+
+ return (dir_exists ? R_PROCESS : R_SKIP_ALL);
+}
+
+/*
+ * Send each option in a string to the server, one by one.
+ * This assumes that the options are single characters. For
+ * more complex parsing, do it yourself.
+ */
+
+void
+send_option_string (string)
+ char *string;
+{
+ char *p;
+ char it[3];
+
+ for (p = string; p[0]; p++) {
+ if (p[0] == ' ')
+ continue;
+ if (p[0] == '-')
+ continue;
+ it[0] = '-';
+ it[1] = p[0];
+ it[2] = '\0';
+ send_arg (it);
+ }
+}
+
+
+/* Send the names of all the argument files to the server. */
+
+void
+send_file_names (argc, argv)
+ int argc;
+ char **argv;
+{
+ int i;
+ char *p;
+ char *q;
+ int level;
+ int max_level;
+
+ /* Send Max-dotdot if needed. */
+ max_level = 0;
+ for (i = 0; i < argc; ++i)
+ {
+ p = argv[i];
+ level = 0;
+ do
+ {
+ q = strchr (p, '/');
+ if (q != NULL)
+ ++q;
+ if (p[0] == '.' && p[1] == '.' && (p[2] == '\0' || p[2] == '/'))
+ {
+ --level;
+ if (-level > max_level)
+ max_level = -level;
+ }
+ else if (p[0] == '.' && (p[1] == '\0' || p[1] == '/'))
+ ;
+ else
+ ++level;
+ p = q;
+ } while (p != NULL);
+ }
+ if (max_level > 0)
+ {
+ if (supported_request ("Max-dotdot"))
+ {
+ if (fprintf (to_server, "Max-dotdot %d\n", max_level) < 0)
+ error (1, errno, "writing to server");
+ }
+ else
+ /*
+ * "leading .." is not strictly correct, as this also includes
+ * cases like "foo/../..". But trying to explain that in the
+ * error message would probably just confuse users.
+ */
+ error (1, 0,
+ "leading .. not supported by old (pre-Max-dotdot) servers");
+ }
+
+ for (i = 0; i < argc; ++i)
+ send_arg (argv[i]);
+}
+
+
+/*
+ * Send Repository, Modified and Entry. argc and argv contain only
+ * the files to operate on (or empty for everything), not options.
+ * local is nonzero if we should not recurse (-l option). Also sends
+ * Argument lines for argc and argv, so should be called after options
+ * are sent.
+ */
+void
+send_files (argc, argv, local, aflag)
+ int argc;
+ char **argv;
+ int local;
+ int aflag;
+{
+ int err;
+
+ send_file_names (argc, argv);
+
+ /*
+ * aflag controls whether the tag/date is copied into the vers_ts.
+ * But we don't actually use it, so I don't think it matters what we pass
+ * for aflag here.
+ */
+ err = start_recursion
+ (send_fileproc, update_filesdone_proc,
+ send_dirent_proc, (DIRLEAVEPROC)NULL,
+ argc, argv, local, W_LOCAL, aflag, 0, (char *)NULL, 0, 0);
+ if (err)
+ exit (1);
+ if (toplevel_repos == NULL)
+ /*
+ * This happens if we are not processing any files,
+ * or for checkouts in directories without any existing stuff
+ * checked out. The following assignment is correct for the
+ * latter case; I don't think toplevel_repos matters for the
+ * former.
+ */
+ toplevel_repos = xstrdup (server_cvsroot);
+ send_repository ("", toplevel_repos, ".");
+}
+
+void
+client_import_setup (repository)
+ char *repository;
+{
+ if (toplevel_repos == NULL) /* should always be true */
+ send_a_repository ("", repository, "");
+}
+
+/*
+ * Process the argument import file.
+ */
+int
+client_process_import_file (message, vfile, vtag, targc, targv, repository)
+ char *message;
+ char *vfile;
+ char *vtag;
+ int targc;
+ char *targv[];
+ char *repository;
+{
+ char *short_pathname;
+ int first_time;
+
+ /* FIXME: I think this is always false now that we call
+ client_import_setup at the start. */
+
+ first_time = toplevel_repos == NULL;
+
+ if (first_time)
+ send_a_repository ("", repository, "");
+
+ if (strncmp (repository, toplevel_repos, strlen (toplevel_repos)) != 0)
+ error (1, 0,
+ "internal error: pathname `%s' doesn't specify file in `%s'",
+ repository, toplevel_repos);
+ short_pathname = repository + strlen (toplevel_repos) + 1;
+
+ if (!first_time)
+ {
+ send_a_repository ("", repository, short_pathname);
+ }
+ send_modified (vfile, short_pathname, NULL);
+ return 0;
+}
+
+void
+client_import_done ()
+{
+ if (toplevel_repos == NULL)
+ /*
+ * This happens if we are not processing any files,
+ * or for checkouts in directories without any existing stuff
+ * checked out. The following assignment is correct for the
+ * latter case; I don't think toplevel_repos matters for the
+ * former.
+ */
+ /* FIXME: "can't happen" now that we call client_import_setup
+ at the beginning. */
+ toplevel_repos = xstrdup (server_cvsroot);
+ send_repository ("", toplevel_repos, ".");
+}
+
+/*
+ * Send an option with an argument, dealing correctly with newlines in
+ * the argument. If ARG is NULL, forget the whole thing.
+ */
+void
+option_with_arg (option, arg)
+ char *option;
+ char *arg;
+{
+ if (arg == NULL)
+ return;
+ if (fprintf (to_server, "Argument %s\n", option) < 0)
+ error (1, errno, "writing to server");
+ send_arg (arg);
+}
+
+/*
+ * Send a date to the server. This will passed a string which is the
+ * result of Make_Date, and looks like YY.MM.DD.HH.MM.SS, where all
+ * the letters are single digits. The time will be GMT. getdate on
+ * the server can't parse that, so we turn it back into something
+ * which it can parse.
+ */
+
+void
+client_senddate (date)
+ const char *date;
+{
+ int year, month, day, hour, minute, second;
+ char buf[100];
+
+ if (sscanf (date, DATEFORM, &year, &month, &day, &hour, &minute, &second)
+ != 6)
+ {
+ error (1, 0, "diff_client_senddate: sscanf failed on date");
+ }
+
+#ifndef HAVE_RCS5
+ /* We need to fix the timezone in this case; see Make_Date. */
+ abort ();
+#endif /* HAVE_RCS5 */
+
+ sprintf (buf, "%d/%d/%d %d:%d:%d GMT", month, day, year,
+ hour, minute, second);
+ option_with_arg ("-D", buf);
+}
+
+int
+client_commit (argc, argv)
+ int argc;
+ char **argv;
+{
+ parse_cvsroot ();
+
+ return commit (argc, argv);
+}
+
+int
+client_update (argc, argv)
+ int argc;
+ char **argv;
+{
+ parse_cvsroot ();
+
+ return update (argc, argv);
+}
+
+int
+client_checkout (argc, argv)
+ int argc;
+ char **argv;
+{
+ parse_cvsroot ();
+
+ return checkout (argc, argv);
+}
+
+int
+client_diff (argc, argv)
+ int argc;
+ char **argv;
+{
+ parse_cvsroot ();
+
+ return diff (argc, argv); /* Call real code */
+}
+
+int
+client_status (argc, argv)
+ int argc;
+ char **argv;
+{
+ parse_cvsroot ();
+ return status (argc, argv);
+}
+
+int
+client_log (argc, argv)
+ int argc;
+ char **argv;
+{
+
+ parse_cvsroot ();
+
+ return cvslog (argc, argv); /* Call real code */
+}
+
+int
+client_add (argc, argv)
+ int argc;
+ char **argv;
+{
+
+ parse_cvsroot ();
+
+ return add (argc, argv); /* Call real code */
+}
+
+int
+client_remove (argc, argv)
+ int argc;
+ char **argv;
+{
+
+ parse_cvsroot ();
+
+ return cvsremove (argc, argv); /* Call real code */
+}
+
+int
+client_rdiff (argc, argv)
+ int argc;
+ char **argv;
+{
+
+ parse_cvsroot ();
+
+ return patch (argc, argv); /* Call real code */
+}
+
+int
+client_tag (argc, argv)
+ int argc;
+ char **argv;
+{
+
+ parse_cvsroot ();
+
+ return tag (argc, argv); /* Call real code */
+}
+
+int
+client_rtag (argc, argv)
+ int argc;
+ char **argv;
+{
+
+ parse_cvsroot ();
+
+ return rtag (argc, argv); /* Call real code */
+}
+
+int
+client_import (argc, argv)
+ int argc;
+ char **argv;
+{
+
+ parse_cvsroot ();
+
+ return import (argc, argv); /* Call real code */
+}
+
+int
+client_admin (argc, argv)
+ int argc;
+ char **argv;
+{
+
+ parse_cvsroot ();
+
+ return admin (argc, argv); /* Call real code */
+}
+
+int
+client_export (argc, argv)
+ int argc;
+ char **argv;
+{
+
+ parse_cvsroot ();
+
+ return checkout (argc, argv); /* Call real code */
+}
+
+int
+client_history (argc, argv)
+ int argc;
+ char **argv;
+{
+
+ parse_cvsroot ();
+
+ return history (argc, argv); /* Call real code */
+}
+
+int
+client_release (argc, argv)
+ int argc;
+ char **argv;
+{
+
+ parse_cvsroot ();
+
+ return release (argc, argv); /* Call real code */
+}
+
+#endif /* CLIENT_SUPPORT */
diff --git a/gnu/usr.bin/cvs/cvs/client.h b/gnu/usr.bin/cvs/cvs/client.h
new file mode 100644
index 0000000..0602900
--- /dev/null
+++ b/gnu/usr.bin/cvs/cvs/client.h
@@ -0,0 +1,163 @@
+/* Interface between the client and the rest of CVS. */
+
+/* Stuff shared with the server. */
+extern char *mode_to_string PROTO((mode_t));
+extern int change_mode PROTO((char *, char *));
+
+extern int gzip_level;
+extern int filter_through_gzip PROTO((int, int, int, pid_t *));
+extern int filter_through_gunzip PROTO((int, int, pid_t *));
+
+#ifdef CLIENT_SUPPORT
+/*
+ * Functions to perform CVS commands via the protocol. argc and argv
+ * are the arguments and the return value is the exit status (zero success
+ * nonzero failure).
+ */
+extern int client_commit PROTO((int argc, char **argv));
+extern int client_update PROTO((int argc, char **argv));
+extern int client_checkout PROTO((int argc, char **argv));
+extern int client_diff PROTO((int argc, char **argv));
+extern int client_log PROTO((int argc, char **argv));
+extern int client_add PROTO((int argc, char **argv));
+extern int client_remove PROTO((int argc, char **argv));
+extern int client_status PROTO((int argc, char **argv));
+extern int client_rdiff PROTO((int argc, char **argv));
+extern int client_tag PROTO((int argc, char **argv));
+extern int client_rtag PROTO((int argc, char **argv));
+extern int client_import PROTO((int argc, char **argv));
+extern int client_admin PROTO((int argc, char **argv));
+extern int client_export PROTO((int argc, char **argv));
+extern int client_history PROTO((int argc, char **argv));
+extern int client_release PROTO((int argc, char **argv));
+
+/*
+ * Flag variable for seeing whether common code is running as a client
+ * or to do a local operation.
+ */
+extern int client_active;
+
+/* Is the -P option to checkout or update specified? */
+extern int client_prune_dirs;
+
+/* Stream to write to the server. */
+extern FILE *to_server;
+/* Stream to read from the server. */
+extern FILE *from_server;
+
+/* Internal functions that handle client communication to server, etc. */
+int supported_request PROTO ((char *));
+void option_with_arg PROTO((char *option, char *arg));
+
+/* Get the responses and then close the connection. */
+extern int get_responses_and_close PROTO((void));
+
+extern int get_server_responses PROTO((void));
+
+/* Start up the connection to the server on the other end. */
+void
+start_server PROTO((void));
+
+/* Send the names of all the argument files to the server. */
+void
+send_file_names PROTO((int argc, char **argv));
+
+/*
+ * Send Repository, Modified and Entry. argc and argv contain only
+ * the files to operate on (or empty for everything), not options.
+ * local is nonzero if we should not recurse (-l option). Also sends
+ * Argument lines for argc and argv, so should be called after options
+ * are sent.
+ */
+void
+send_files PROTO((int argc, char **argv, int local, int aflag));
+
+/*
+ * Like send_files but never send "Unchanged"--just send the contents of the
+ * file in that case. This is used to fix it if you import a directory which
+ * happens to have CVS directories (yes it is obscure but the testsuite tests
+ * it).
+ */
+void
+send_files_contents PROTO((int argc, char **argv, int local, int aflag));
+
+/* Send an argument to the remote server. */
+void
+send_arg PROTO((char *string));
+
+/* Send a string of single-char options to the remote server, one by one. */
+void
+send_option_string PROTO((char *string));
+
+#endif /* CLIENT_SUPPORT */
+
+/*
+ * This structure is used to catalog the responses the client is
+ * prepared to see from the server.
+ */
+
+struct response
+{
+ /* Name of the response. */
+ char *name;
+
+#ifdef CLIENT_SUPPORT
+ /*
+ * Function to carry out the response. ARGS is the text of the
+ * command after name and, if present, a single space, have been
+ * stripped off. The function can scribble into ARGS if it wants.
+ */
+ void (*func) PROTO((char *args, int len));
+
+ /*
+ * ok and error are special; they indicate we are at the end of the
+ * responses, and error indicates we should exit with nonzero
+ * exitstatus.
+ */
+ enum {response_type_normal, response_type_ok, response_type_error} type;
+#endif
+
+ /* Used by the server to indicate whether response is supported by
+ the client, as set by the Valid-responses request. */
+ enum {
+ /*
+ * Failure to implement this response can imply a fatal
+ * error. This should be set only for responses which were in the
+ * original version of the protocol; it should not be set for new
+ * responses.
+ */
+ rs_essential,
+
+ /* Some clients might not understand this response. */
+ rs_optional,
+
+ /*
+ * Set by the server to one of the following based on what this
+ * client actually supports.
+ */
+ rs_supported,
+ rs_not_supported
+ } status;
+};
+
+/* Table of responses ending in an entry with a NULL name. */
+
+extern struct response responses[];
+
+#ifdef CLIENT_SUPPORT
+
+extern void client_senddate PROTO((const char *date));
+extern void client_expand_modules PROTO((int argc, char **argv, int local));
+extern void client_send_expansions PROTO((int local));
+extern void client_nonexpanded_setup PROTO((void));
+
+extern char **failed_patches;
+extern int failed_patches_count;
+extern char toplevel_wd[];
+extern void client_import_setup PROTO((char *repository));
+extern int client_process_import_file
+ PROTO((char *message, char *vfile, char *vtag,
+ int targc, char *targv[], char *repository));
+extern void client_import_done PROTO((void));
+
+#endif /* CLIENT_SUPPORT */
diff --git a/gnu/usr.bin/cvs/cvs/commit.c b/gnu/usr.bin/cvs/cvs/commit.c
new file mode 100644
index 0000000..888804e
--- /dev/null
+++ b/gnu/usr.bin/cvs/cvs/commit.c
@@ -0,0 +1,1834 @@
+/*
+ * Copyright (c) 1992, Brian Berliner and Jeff Polk
+ * Copyright (c) 1989-1992, Brian Berliner
+ *
+ * You may distribute under the terms of the GNU General Public License as
+ * specified in the README file that comes with the CVS 1.4 kit.
+ *
+ * Commit Files
+ *
+ * "commit" commits the present version to the RCS repository, AFTER
+ * having done a test on conflicts.
+ *
+ * The call is: cvs commit [options] files...
+ *
+ */
+
+#include "cvs.h"
+#include "getline.h"
+
+#ifndef lint
+static const char rcsid[] = "$CVSid: @(#)commit.c 1.101 94/10/07 $";
+USE(rcsid);
+#endif
+
+static Dtype check_direntproc PROTO((char *dir, char *repos, char *update_dir));
+static int check_fileproc PROTO((char *file, char *update_dir, char *repository,
+ List * entries, List * srcfiles));
+static int check_filesdoneproc PROTO((int err, char *repos, char *update_dir));
+static int checkaddfile PROTO((char *file, char *repository, char *tag,
+ char *options, List *srcfiles));
+static Dtype commit_direntproc PROTO((char *dir, char *repos, char *update_dir));
+static int commit_dirleaveproc PROTO((char *dir, int err, char *update_dir));
+static int commit_fileproc PROTO((char *file, char *update_dir, char *repository,
+ List * entries, List * srcfiles));
+static int commit_filesdoneproc PROTO((int err, char *repository, char *update_dir));
+static int finaladd PROTO((char *file, char *revision, char *tag,
+ char *options, char *update_dir,
+ char *repository, List *entries));
+static int findmaxrev PROTO((Node * p, void *closure));
+static int fsortcmp PROTO((const Node * p, const Node * q));
+static int lock_RCS PROTO((char *user, char *rcs, char *rev, char *repository));
+static int lock_filesdoneproc PROTO((int err, char *repository, char *update_dir));
+static int lockrcsfile PROTO((char *file, char *repository, char *rev));
+static int precommit_list_proc PROTO((Node * p, void *closure));
+static int precommit_proc PROTO((char *repository, char *filter));
+static int remove_file PROTO((char *file, char *repository, char *tag,
+ char *message, List *entries, List *srcfiles));
+static void fix_rcs_modes PROTO((char *rcs, char *user));
+static void fixaddfile PROTO((char *file, char *repository));
+static void fixbranch PROTO((char *file, char *repository, char *branch));
+static void unlockrcs PROTO((char *file, char *repository));
+static void ci_delproc PROTO((Node *p));
+static void masterlist_delproc PROTO((Node *p));
+static void locate_rcs PROTO((char *file, char *repository, char *rcs));
+
+struct commit_info
+{
+ Ctype status; /* as returned from Classify_File() */
+ char *rev; /* a numeric rev, if we know it */
+ char *tag; /* any sticky tag, or -r option */
+ char *options; /* Any sticky -k option */
+};
+struct master_lists
+{
+ List *ulist; /* list for Update_Logfile */
+ List *cilist; /* list with commit_info structs */
+};
+
+static int force_ci = 0;
+static int got_message;
+static int run_module_prog = 1;
+static int aflag;
+static char *tag;
+static char *write_dirtag;
+static char *logfile;
+static List *mulist;
+static List *locklist;
+static char *message;
+
+static const char *const commit_usage[] =
+{
+ "Usage: %s %s [-nRlf] [-m msg | -F logfile] [-r rev] files...\n",
+ "\t-n\tDo not run the module program (if any).\n",
+ "\t-R\tProcess directories recursively.\n",
+ "\t-l\tLocal directory only (not recursive).\n",
+ "\t-f\tForce the file to be committed; disables recursion.\n",
+ "\t-F file\tRead the log message from file.\n",
+ "\t-m msg\tLog message.\n",
+ "\t-r rev\tCommit to this branch or trunk revision.\n",
+ NULL
+};
+
+int
+commit (argc, argv)
+ int argc;
+ char **argv;
+{
+ int c;
+ int err = 0;
+ int local = 0;
+
+ if (argc == -1)
+ usage (commit_usage);
+
+#ifdef CVS_BADROOT
+ /*
+ * For log purposes, do not allow "root" to commit files. If you look
+ * like root, but are really logged in as a non-root user, it's OK.
+ */
+ if (geteuid () == (uid_t) 0)
+ {
+ struct passwd *pw;
+
+ if ((pw = (struct passwd *) getpwnam (getcaller ())) == NULL)
+ error (1, 0, "you are unknown to this system");
+ if (pw->pw_uid == (uid_t) 0)
+ error (1, 0, "cannot commit files as 'root'");
+ }
+#endif /* CVS_BADROOT */
+
+ optind = 1;
+ while ((c = getopt (argc, argv, "nlRm:fF:r:")) != -1)
+ {
+ switch (c)
+ {
+ case 'n':
+ run_module_prog = 0;
+ break;
+ case 'm':
+#ifdef FORCE_USE_EDITOR
+ use_editor = TRUE;
+#else
+ use_editor = FALSE;
+#endif
+ if (message)
+ {
+ free (message);
+ message = NULL;
+ }
+
+ message = xstrdup(optarg);
+ break;
+ case 'r':
+ if (tag)
+ free (tag);
+ tag = xstrdup (optarg);
+ break;
+ case 'l':
+ local = 1;
+ break;
+ case 'R':
+ local = 0;
+ break;
+ case 'f':
+ force_ci = 1;
+ local = 1; /* also disable recursion */
+ break;
+ case 'F':
+#ifdef FORCE_USE_EDITOR
+ use_editor = TRUE;
+#else
+ use_editor = FALSE;
+#endif
+ logfile = optarg;
+ break;
+ case '?':
+ default:
+ usage (commit_usage);
+ break;
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+ /* numeric specified revision means we ignore sticky tags... */
+ if (tag && isdigit (*tag))
+ {
+ aflag = 1;
+ /* strip trailing dots */
+ while (tag[strlen (tag) - 1] == '.')
+ tag[strlen (tag) - 1] = '\0';
+ }
+
+ /* some checks related to the "-F logfile" option */
+ if (logfile)
+ {
+ int n, logfd;
+ struct stat statbuf;
+
+ if (message)
+ error (1, 0, "cannot specify both a message and a log file");
+
+ if ((logfd = open (logfile, O_RDONLY | OPEN_BINARY)) < 0)
+ error (1, errno, "cannot open log file %s", logfile);
+
+ if (fstat(logfd, &statbuf) < 0)
+ error (1, errno, "cannot find size of log file %s", logfile);
+
+ message = xmalloc (statbuf.st_size + 1);
+
+ if ((n = read (logfd, message, statbuf.st_size + 1)) < 0)
+ error (1, errno, "cannot read log message from %s", logfile);
+
+ (void) close (logfd);
+ message[n] = '\0';
+ }
+
+#ifdef CLIENT_SUPPORT
+ if (client_active)
+ {
+ /*
+ * Do this now; don't ask for a log message if we can't talk to the
+ * server. But if there is a syntax error in the options, give
+ * an error message without connecting.
+ */
+ start_server ();
+
+ ign_setup ();
+
+ /*
+ * We do this once, not once for each directory as in normal CVS.
+ * The protocol is designed this way. This is a feature.
+ *
+ * We could provide the lists of changed, modified, etc. files,
+ * however. Our failure to do so is just laziness, not design.
+ */
+ if (use_editor)
+ do_editor (".", &message, (char *)NULL, (List *)NULL);
+
+ /* We always send some sort of message, even if empty. */
+ option_with_arg ("-m", message);
+
+ if (local)
+ send_arg("-l");
+ if (force_ci)
+ send_arg("-f");
+ if (!run_module_prog)
+ send_arg("-n");
+ option_with_arg ("-r", tag);
+
+ send_files (argc, argv, local, 0);
+
+ if (fprintf (to_server, "ci\n") < 0)
+ error (1, errno, "writing to server");
+ return get_responses_and_close ();
+ }
+#endif
+
+ /* XXX - this is not the perfect check for this */
+ if (argc <= 0)
+ write_dirtag = tag;
+
+ wrap_setup ();
+
+ /*
+ * Run the recursion processor to find all the dirs to lock and lock all
+ * the dirs
+ */
+ locklist = getlist ();
+ err = start_recursion ((FILEPROC) NULL, lock_filesdoneproc,
+ (DIRENTPROC) NULL, (DIRLEAVEPROC) NULL, argc,
+ argv, local, W_LOCAL, aflag, 0, (char *) NULL, 0,
+ 0);
+ sortlist (locklist, fsortcmp);
+ if (Writer_Lock (locklist) != 0)
+ error (1, 0, "lock failed - giving up");
+
+ /*
+ * Set up the master update list
+ */
+ mulist = getlist ();
+
+ /*
+ * Run the recursion processor to verify the files are all up-to-date
+ */
+ err = start_recursion (check_fileproc, check_filesdoneproc,
+ check_direntproc, (DIRLEAVEPROC) NULL, argc,
+ argv, local, W_LOCAL, aflag, 0, (char *) NULL, 1,
+ 0);
+ if (err)
+ {
+ Lock_Cleanup ();
+ error (1, 0, "correct above errors first!");
+ }
+
+ /*
+ * Run the recursion processor to commit the files
+ */
+ if (noexec == 0)
+ err = start_recursion (commit_fileproc, commit_filesdoneproc,
+ commit_direntproc, commit_dirleaveproc,
+ argc, argv, local, W_LOCAL, aflag, 0,
+ (char *) NULL, 1, 0);
+
+ /*
+ * Unlock all the dirs and clean up
+ */
+ Lock_Cleanup ();
+ dellist (&mulist);
+ dellist (&locklist);
+ return (err);
+}
+
+/*
+ * compare two lock list nodes (for sort)
+ */
+static int
+fsortcmp (p, q)
+ const Node *p;
+ const Node *q;
+{
+ return (strcmp (p->key, q->key));
+}
+
+/*
+ * Create a list of repositories to lock
+ */
+/* ARGSUSED */
+static int
+lock_filesdoneproc (err, repository, update_dir)
+ int err;
+ char *repository;
+ char *update_dir;
+{
+ Node *p;
+
+ p = getnode ();
+ p->type = LOCK;
+ p->key = xstrdup (repository);
+ /* FIXME-KRP: this error condition should not simply be passed by. */
+ if (p->key == NULL || addnode (locklist, p) != 0)
+ freenode (p);
+ return (err);
+}
+
+/*
+ * Check to see if a file is ok to commit and make sure all files are
+ * up-to-date
+ */
+/* ARGSUSED */
+static int
+check_fileproc (file, update_dir, repository, entries, srcfiles)
+ char *file;
+ char *update_dir;
+ char *repository;
+ List *entries;
+ List *srcfiles;
+{
+ Ctype status;
+ char *xdir;
+ Node *p;
+ List *ulist, *cilist;
+ Vers_TS *vers;
+ struct commit_info *ci;
+ int save_noexec, save_quiet, save_really_quiet;
+
+ save_noexec = noexec;
+ save_quiet = quiet;
+ save_really_quiet = really_quiet;
+ noexec = quiet = really_quiet = 1;
+
+ /* handle specified numeric revision specially */
+ if (tag && isdigit (*tag))
+ {
+ /* If the tag is for the trunk, make sure we're at the head */
+ if (numdots (tag) < 2)
+ {
+ status = Classify_File (file, (char *) NULL, (char *) NULL,
+ (char *) NULL, 1, aflag, repository,
+ entries, srcfiles, &vers, update_dir, 0);
+ if (status == T_UPTODATE || status == T_MODIFIED ||
+ status == T_ADDED)
+ {
+ Ctype xstatus;
+
+ freevers_ts (&vers);
+ xstatus = Classify_File (file, tag, (char *) NULL,
+ (char *) NULL, 1, aflag, repository,
+ entries, srcfiles, &vers, update_dir,
+ 0);
+ if (xstatus == T_REMOVE_ENTRY)
+ status = T_MODIFIED;
+ else if (status == T_MODIFIED && xstatus == T_CONFLICT)
+ status = T_MODIFIED;
+ else
+ status = xstatus;
+ }
+ }
+ else
+ {
+ char *xtag, *cp;
+
+ /*
+ * The revision is off the main trunk; make sure we're
+ * up-to-date with the head of the specified branch.
+ */
+ xtag = xstrdup (tag);
+ if ((numdots (xtag) & 1) != 0)
+ {
+ cp = strrchr (xtag, '.');
+ *cp = '\0';
+ }
+ status = Classify_File (file, xtag, (char *) NULL,
+ (char *) NULL, 1, aflag, repository,
+ entries, srcfiles, &vers, update_dir, 0);
+ if ((status == T_REMOVE_ENTRY || status == T_CONFLICT)
+ && (cp = strrchr (xtag, '.')) != NULL)
+ {
+ /* pluck one more dot off the revision */
+ *cp = '\0';
+ freevers_ts (&vers);
+ status = Classify_File (file, xtag, (char *) NULL,
+ (char *) NULL, 1, aflag, repository,
+ entries, srcfiles, &vers, update_dir,
+ 0);
+ if (status == T_UPTODATE || status == T_REMOVE_ENTRY)
+ status = T_MODIFIED;
+ }
+ /* now, muck with vers to make the tag correct */
+ free (vers->tag);
+ vers->tag = xstrdup (tag);
+ free (xtag);
+ }
+ }
+ else
+ status = Classify_File (file, tag, (char *) NULL, (char *) NULL,
+ 1, 0, repository, entries, srcfiles, &vers,
+ update_dir, 0);
+ noexec = save_noexec;
+ quiet = save_quiet;
+ really_quiet = save_really_quiet;
+
+ /*
+ * If the force-commit option is enabled, and the file in question
+ * appears to be up-to-date, just make it look modified so that
+ * it will be committed.
+ */
+ if (force_ci && status == T_UPTODATE)
+ status = T_MODIFIED;
+
+ switch (status)
+ {
+ case T_CHECKOUT:
+#ifdef SERVER_SUPPORT
+ case T_PATCH:
+#endif
+ case T_NEEDS_MERGE:
+ case T_CONFLICT:
+ case T_REMOVE_ENTRY:
+ if (update_dir[0] == '\0')
+ error (0, 0, "Up-to-date check failed for `%s'", file);
+ else
+ error (0, 0, "Up-to-date check failed for `%s/%s'",
+ update_dir, file);
+ freevers_ts (&vers);
+ return (1);
+ case T_MODIFIED:
+ case T_ADDED:
+ case T_REMOVED:
+ /*
+ * some quick sanity checks; if no numeric -r option specified:
+ * - can't have a sticky date
+ * - can't have a sticky tag that is not a branch
+ * Also,
+ * - if status is T_REMOVED, can't have a numeric tag
+ * - if status is T_ADDED, rcs file must not exist
+ * - if status is T_ADDED, can't have a non-trunk numeric rev
+ * - if status is T_MODIFIED and a Conflict marker exists, don't
+ * allow the commit if timestamp is identical or if we find
+ * an RCS_MERGE_PAT in the file.
+ */
+ if (!tag || !isdigit (*tag))
+ {
+ if (vers->date)
+ {
+ if (update_dir[0] == '\0')
+ error (0, 0,
+ "cannot commit with sticky date for file `%s'",
+ file);
+ else
+ error
+ (0, 0,
+ "cannot commit with sticky date for file `%s/%s'",
+ update_dir, file);
+ freevers_ts (&vers);
+ return (1);
+ }
+ if (status == T_MODIFIED && vers->tag &&
+ !RCS_isbranch (file, vers->tag, srcfiles))
+ {
+ if (update_dir[0] == '\0')
+ error (0, 0,
+ "sticky tag `%s' for file `%s' is not a branch",
+ vers->tag, file);
+ else
+ error
+ (0, 0,
+ "sticky tag `%s' for file `%s/%s' is not a branch",
+ vers->tag, update_dir, file);
+ freevers_ts (&vers);
+ return (1);
+ }
+ }
+ if (status == T_MODIFIED && !force_ci && vers->ts_conflict)
+ {
+ char *filestamp;
+ int retcode;
+
+ /*
+ * We found a "conflict" marker.
+ *
+ * If the timestamp on the file is the same as the
+ * timestamp stored in the Entries file, we block the commit.
+ */
+#ifdef SERVER_SUPPORT
+ if (server_active)
+ retcode = vers->ts_conflict[0] != '=';
+ else {
+ filestamp = time_stamp (file);
+ retcode = strcmp (vers->ts_conflict, filestamp);
+ free (filestamp);
+ }
+#else
+ filestamp = time_stamp (file);
+ retcode = strcmp (vers->ts_conflict, filestamp);
+ free (filestamp);
+#endif
+ if (retcode == 0)
+ {
+ if (update_dir[0] == '\0')
+ error (0, 0,
+ "file `%s' had a conflict and has not been modified",
+ file);
+ else
+ error (0, 0,
+ "file `%s/%s' had a conflict and has not been modified",
+ update_dir, file);
+ freevers_ts (&vers);
+ return (1);
+ }
+
+ /*
+ * If the timestamps differ, look for Conflict indicators
+ * in the file to see if we should block the commit anyway
+ */
+ run_setup ("%s", GREP);
+ run_arg (RCS_MERGE_PAT);
+ run_arg (file);
+ retcode = run_exec (RUN_TTY, DEVNULL, RUN_TTY, RUN_REALLY);
+
+ if (retcode == -1)
+ {
+ if (update_dir[0] == '\0')
+ error (1, errno,
+ "fork failed while examining conflict in `%s'",
+ file);
+ else
+ error (1, errno,
+ "fork failed while examining conflict in `%s/%s'",
+ update_dir, file);
+ }
+ else if (retcode == 0)
+ {
+ if (update_dir[0] == '\0')
+ error (0, 0,
+ "file `%s' still contains conflict indicators",
+ file);
+ else
+ error (0, 0,
+ "file `%s/%s' still contains conflict indicators",
+ update_dir, file);
+ freevers_ts (&vers);
+ return (1);
+ }
+ }
+
+ if (status == T_REMOVED && vers->tag && isdigit (*vers->tag))
+ {
+ if (update_dir[0] == '\0')
+ error (0, 0,
+ "cannot remove file `%s' which has a numeric sticky tag of `%s'",
+ file, vers->tag);
+ else
+ error (0, 0,
+ "cannot remove file `%s/%s' which has a numeric sticky tag of `%s'",
+ update_dir, file, vers->tag);
+ freevers_ts (&vers);
+ return (1);
+ }
+ if (status == T_ADDED)
+ {
+ char rcs[PATH_MAX];
+
+#ifdef DEATH_SUPPORT
+ /* Don't look in the attic; if it exists there we will
+ move it back out in checkaddfile. */
+ sprintf(rcs, "%s/%s%s", repository, file, RCSEXT);
+#else
+ locate_rcs (file, repository, rcs);
+#endif
+ if (isreadable (rcs))
+ {
+ if (update_dir[0] == '\0')
+ error (0, 0,
+ "cannot add file `%s' when RCS file `%s' already exists",
+ file, rcs);
+ else
+ error (0, 0,
+ "cannot add file `%s/%s' when RCS file `%s' already exists",
+ update_dir, file, rcs);
+ freevers_ts (&vers);
+ return (1);
+ }
+ if (vers->tag && isdigit (*vers->tag) &&
+ numdots (vers->tag) > 1)
+ {
+ if (update_dir[0] == '\0')
+ error (0, 0,
+ "cannot add file `%s' with revision `%s'; must be on trunk",
+ file, vers->tag);
+ else
+ error (0, 0,
+ "cannot add file `%s/%s' with revision `%s'; must be on trunk",
+ update_dir, file, vers->tag);
+ freevers_ts (&vers);
+ return (1);
+ }
+ }
+
+ /* done with consistency checks; now, to get on with the commit */
+ if (update_dir[0] == '\0')
+ xdir = ".";
+ else
+ xdir = update_dir;
+ if ((p = findnode (mulist, xdir)) != NULL)
+ {
+ ulist = ((struct master_lists *) p->data)->ulist;
+ cilist = ((struct master_lists *) p->data)->cilist;
+ }
+ else
+ {
+ struct master_lists *ml;
+
+ ulist = getlist ();
+ cilist = getlist ();
+ p = getnode ();
+ p->key = xstrdup (xdir);
+ p->type = UPDATE;
+ ml = (struct master_lists *)
+ xmalloc (sizeof (struct master_lists));
+ ml->ulist = ulist;
+ ml->cilist = cilist;
+ p->data = (char *) ml;
+ p->delproc = masterlist_delproc;
+ (void) addnode (mulist, p);
+ }
+
+ /* first do ulist, then cilist */
+ p = getnode ();
+ p->key = xstrdup (file);
+ p->type = UPDATE;
+ p->delproc = update_delproc;
+ p->data = (char *) status;
+ (void) addnode (ulist, p);
+
+ p = getnode ();
+ p->key = xstrdup (file);
+ p->type = UPDATE;
+ p->delproc = ci_delproc;
+ ci = (struct commit_info *) xmalloc (sizeof (struct commit_info));
+ ci->status = status;
+ if (vers->tag)
+ if (isdigit (*vers->tag))
+ ci->rev = xstrdup (vers->tag);
+ else
+ ci->rev = RCS_whatbranch (file, vers->tag, srcfiles);
+ else
+ ci->rev = (char *) NULL;
+ ci->tag = xstrdup (vers->tag);
+ ci->options = xstrdup(vers->options);
+ p->data = (char *) ci;
+ (void) addnode (cilist, p);
+ break;
+ case T_UNKNOWN:
+ if (update_dir[0] == '\0')
+ error (0, 0, "nothing known about `%s'", file);
+ else
+ error (0, 0, "nothing known about `%s/%s'", update_dir, file);
+ freevers_ts (&vers);
+ return (1);
+ case T_UPTODATE:
+ break;
+ default:
+ error (0, 0, "CVS internal error: unknown status %d", status);
+ break;
+ }
+
+ freevers_ts (&vers);
+ return (0);
+}
+
+/*
+ * Print warm fuzzies while examining the dirs
+ */
+/* ARGSUSED */
+static Dtype
+check_direntproc (dir, repos, update_dir)
+ char *dir;
+ char *repos;
+ char *update_dir;
+{
+ if (!quiet)
+ error (0, 0, "Examining %s", update_dir);
+
+ return (R_PROCESS);
+}
+
+/*
+ * Walklist proc to run pre-commit checks
+ */
+static int
+precommit_list_proc (p, closure)
+ Node *p;
+ void *closure;
+{
+ if (p->data == (char *) T_ADDED || p->data == (char *) T_MODIFIED ||
+ p->data == (char *) T_REMOVED)
+ {
+ run_arg (p->key);
+ }
+ return (0);
+}
+
+/*
+ * Callback proc for pre-commit checking
+ */
+static List *ulist;
+static int
+precommit_proc (repository, filter)
+ char *repository;
+ char *filter;
+{
+ /* see if the filter is there, only if it's a full path */
+ if (isabsolute (filter))
+ {
+ char *s, *cp;
+
+ s = xstrdup (filter);
+ for (cp = s; *cp; cp++)
+ if (isspace (*cp))
+ {
+ *cp = '\0';
+ break;
+ }
+ if (!isfile (s))
+ {
+ error (0, errno, "cannot find pre-commit filter `%s'", s);
+ free (s);
+ return (1); /* so it fails! */
+ }
+ free (s);
+ }
+
+ run_setup ("%s %s", filter, repository);
+ (void) walklist (ulist, precommit_list_proc, NULL);
+ return (run_exec (RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL|RUN_REALLY));
+}
+
+/*
+ * Run the pre-commit checks for the dir
+ */
+/* ARGSUSED */
+static int
+check_filesdoneproc (err, repos, update_dir)
+ int err;
+ char *repos;
+ char *update_dir;
+{
+ int n;
+ Node *p;
+
+ /* find the update list for this dir */
+ p = findnode (mulist, update_dir);
+ if (p != NULL)
+ ulist = ((struct master_lists *) p->data)->ulist;
+ else
+ ulist = (List *) NULL;
+
+ /* skip the checks if there's nothing to do */
+ if (ulist == NULL || ulist->list->next == ulist->list)
+ return (err);
+
+ /* run any pre-commit checks */
+ if ((n = Parse_Info (CVSROOTADM_COMMITINFO, repos, precommit_proc, 1)) > 0)
+ {
+ error (0, 0, "Pre-commit check failed");
+ err += n;
+ }
+
+ return (err);
+}
+
+/*
+ * Do the work of committing a file
+ */
+static int maxrev;
+static char sbranch[PATH_MAX];
+
+/* ARGSUSED */
+static int
+commit_fileproc (file, update_dir, repository, entries, srcfiles)
+ char *file;
+ char *update_dir;
+ char *repository;
+ List *entries;
+ List *srcfiles;
+{
+ Node *p;
+ int err = 0;
+ List *ulist, *cilist;
+ struct commit_info *ci;
+ char rcs[PATH_MAX];
+
+ if (update_dir[0] == '\0')
+ p = findnode (mulist, ".");
+ else
+ p = findnode (mulist, update_dir);
+
+ /*
+ * if p is null, there were file type command line args which were
+ * all up-to-date so nothing really needs to be done
+ */
+ if (p == NULL)
+ return (0);
+ ulist = ((struct master_lists *) p->data)->ulist;
+ cilist = ((struct master_lists *) p->data)->cilist;
+
+ /*
+ * At this point, we should have the commit message unless we were called
+ * with files as args from the command line. In that latter case, we
+ * need to get the commit message ourselves
+ */
+ if (use_editor && !got_message)
+ {
+ got_message = 1;
+ do_editor (update_dir, &message, repository, ulist);
+ }
+
+ p = findnode (cilist, file);
+ if (p == NULL)
+ return (0);
+
+ ci = (struct commit_info *) p->data;
+ if (ci->status == T_MODIFIED)
+ {
+ if (lockrcsfile (file, repository, ci->rev) != 0)
+ {
+ unlockrcs (file, repository);
+ err = 1;
+ goto out;
+ }
+ }
+ else if (ci->status == T_ADDED)
+ {
+ if (checkaddfile (file, repository, ci->tag, ci->options,
+ srcfiles) != 0)
+ {
+ fixaddfile (file, repository);
+ err = 1;
+ goto out;
+ }
+
+#ifdef DEATH_SUPPORT
+ /* adding files with a tag, now means adding them on a branch.
+ Since the branch test was done in check_fileproc for
+ modified files, we need to stub it in again here. */
+
+ if (ci->tag) {
+ locate_rcs (file, repository, rcs);
+ ci->rev = RCS_whatbranch (file, ci->tag, srcfiles);
+ err = Checkin ('A', file, update_dir, repository, rcs, ci->rev,
+ ci->tag, ci->options, message, entries);
+ if (err != 0)
+ {
+ unlockrcs (file, repository);
+ fixbranch (file, repository, sbranch);
+ }
+
+ ci->status = T_UPTODATE;
+ }
+#endif /* DEATH_SUPPORT */
+ }
+
+ /*
+ * Add the file for real
+ */
+ if (ci->status == T_ADDED)
+ {
+ char *xrev = (char *) NULL;
+
+ if (ci->rev == NULL)
+ {
+ /* find the max major rev number in this directory */
+ maxrev = 0;
+ (void) walklist (entries, findmaxrev, NULL);
+ if (maxrev == 0)
+ maxrev = 1;
+ xrev = xmalloc (20);
+ (void) sprintf (xrev, "%d", maxrev);
+ }
+
+ /* XXX - an added file with symbolic -r should add tag as well */
+ err = finaladd (file, ci->rev ? ci->rev : xrev, ci->tag, ci->options,
+ update_dir, repository, entries);
+ if (xrev)
+ free (xrev);
+ }
+ else if (ci->status == T_MODIFIED)
+ {
+ locate_rcs (file, repository, rcs);
+ err = Checkin ('M', file, update_dir, repository,
+ rcs, ci->rev, ci->tag,
+ ci->options, message, entries);
+ if (err != 0)
+ {
+ unlockrcs (file, repository);
+ fixbranch (file, repository, sbranch);
+ }
+ }
+ else if (ci->status == T_REMOVED)
+ {
+ err = remove_file (file, repository, ci->tag, message,
+ entries, srcfiles);
+#ifdef SERVER_SUPPORT
+ if (server_active) {
+ server_scratch_entry_only ();
+ server_updated (file, update_dir, repository,
+ /* Doesn't matter, it won't get checked. */
+ SERVER_UPDATED, (struct stat *) NULL,
+ (unsigned char *) NULL);
+ }
+#endif
+ }
+
+out:
+ if (err != 0)
+ {
+ /* on failure, remove the file from ulist */
+ p = findnode (ulist, file);
+ if (p)
+ delnode (p);
+ }
+
+ return (err);
+}
+
+/*
+ * Log the commit and clean up the update list
+ */
+/* ARGSUSED */
+static int
+commit_filesdoneproc (err, repository, update_dir)
+ int err;
+ char *repository;
+ char *update_dir;
+{
+ char *xtag = (char *) NULL;
+ Node *p;
+ List *ulist;
+
+ p = findnode (mulist, update_dir);
+ if (p == NULL)
+ return (err);
+
+ ulist = ((struct master_lists *) p->data)->ulist;
+
+ got_message = 0;
+
+ /* see if we need to specify a per-directory or -r option tag */
+ if (tag == NULL)
+ ParseTag (&xtag, (char **) NULL);
+
+ Update_Logfile (repository, message, tag ? tag : xtag, (FILE *) 0, ulist);
+ if (xtag)
+ free (xtag);
+
+ if (err == 0 && run_module_prog)
+ {
+ FILE *fp;
+
+ if ((fp = fopen (CVSADM_CIPROG, "r")) != NULL)
+ {
+ char *line;
+ int line_length;
+ size_t line_chars_allocated;
+ char *repository;
+
+ line = NULL;
+ line_chars_allocated = 0;
+ line_length = getline (&line, &line_chars_allocated, fp);
+ if (line_length > 0)
+ {
+ /* Remove any trailing newline. */
+ if (line[line_length - 1] == '\n')
+ line[--line_length] = '\0';
+ repository = Name_Repository ((char *) NULL, update_dir);
+ run_setup ("%s %s", line, repository);
+ (void) printf ("%s %s: Executing '", program_name,
+ command_name);
+ run_print (stdout);
+ (void) printf ("'\n");
+ (void) run_exec (RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL);
+ free (repository);
+ }
+ else
+ {
+ if (ferror (fp))
+ error (0, errno, "warning: error reading %s",
+ CVSADM_CIPROG);
+ }
+ if (line != NULL)
+ free (line);
+ if (fclose (fp) < 0)
+ error (0, errno, "warning: cannot close %s", CVSADM_CIPROG);
+ }
+ else
+ {
+ if (! existence_error (errno))
+ error (0, errno, "warning: cannot open %s", CVSADM_CIPROG);
+ }
+ }
+
+ return (err);
+}
+
+/*
+ * Get the log message for a dir and print a warm fuzzy
+ */
+/* ARGSUSED */
+static Dtype
+commit_direntproc (dir, repos, update_dir)
+ char *dir;
+ char *repos;
+ char *update_dir;
+{
+ Node *p;
+ List *ulist;
+ char *real_repos;
+
+ /* find the update list for this dir */
+ p = findnode (mulist, update_dir);
+ if (p != NULL)
+ ulist = ((struct master_lists *) p->data)->ulist;
+ else
+ ulist = (List *) NULL;
+
+ /* skip the files as an optimization */
+ if (ulist == NULL || ulist->list->next == ulist->list)
+ return (R_SKIP_FILES);
+
+ /* print the warm fuzzy */
+ if (!quiet)
+ error (0, 0, "Committing %s", update_dir);
+
+ /* get commit message */
+ if (use_editor)
+ {
+ got_message = 1;
+ real_repos = Name_Repository (dir, update_dir);
+ do_editor (update_dir, &message, real_repos, ulist);
+ free (real_repos);
+ }
+ return (R_PROCESS);
+}
+
+/*
+ * Process the post-commit proc if necessary
+ */
+/* ARGSUSED */
+static int
+commit_dirleaveproc (dir, err, update_dir)
+ char *dir;
+ int err;
+ char *update_dir;
+{
+ /* update the per-directory tag info */
+ if (err == 0 && write_dirtag != NULL)
+ {
+ WriteTag ((char *) NULL, write_dirtag, (char *) NULL);
+#ifdef SERVER_SUPPORT
+ if (server_active)
+ server_set_sticky (update_dir, Name_Repository (dir, update_dir),
+ write_dirtag, (char *) NULL);
+#endif
+ }
+
+ return (err);
+}
+
+/*
+ * find the maximum major rev number in an entries file
+ */
+static int
+findmaxrev (p, closure)
+ Node *p;
+ void *closure;
+{
+ char *cp;
+ int thisrev;
+ Entnode *entdata;
+
+ entdata = (Entnode *) p->data;
+ cp = strchr (entdata->version, '.');
+ if (cp != NULL)
+ *cp = '\0';
+ thisrev = atoi (entdata->version);
+ if (cp != NULL)
+ *cp = '.';
+ if (thisrev > maxrev)
+ maxrev = thisrev;
+ return (0);
+}
+
+/*
+ * Actually remove a file by moving it to the attic
+ * XXX - if removing a ,v file that is a relative symbolic link to
+ * another ,v file, we probably should add a ".." component to the
+ * link to keep it relative after we move it into the attic.
+ */
+static int
+remove_file (file, repository, tag, message, entries, srcfiles)
+ char *file;
+ char *repository;
+ char *tag;
+ char *message;
+ List *entries;
+ List *srcfiles;
+{
+ mode_t omask;
+ int retcode;
+ char rcs[PATH_MAX];
+ char *tmp;
+
+#ifdef DEATH_SUPPORT
+ int branch;
+ char *lockflag;
+ char *corev;
+ char *rev;
+ char *prev_rev;
+ Node *p;
+ RCSNode *rcsfile;
+
+ corev = NULL;
+ rev = NULL;
+ prev_rev = NULL;
+ lockflag = 0;
+#endif /* DEATH_SUPPORT */
+
+ retcode = 0;
+
+ locate_rcs (file, repository, rcs);
+
+#ifdef DEATH_SUPPORT
+ branch = 0;
+ if (tag && !(branch = RCS_isbranch (file, tag, srcfiles)))
+#else
+ if (tag)
+#endif
+ {
+ /* a symbolic tag is specified; just remove the tag from the file */
+ if ((retcode = RCS_deltag (rcs, tag, 1)) != 0)
+ {
+ if (!quiet)
+ error (0, retcode == -1 ? errno : 0,
+ "failed to remove tag `%s' from `%s'", tag, rcs);
+ return (1);
+ }
+ Scratch_Entry (entries, file);
+ return (0);
+ }
+
+#ifdef DEATH_SUPPORT
+ /* we are removing the file from either the head or a branch */
+ /* commit a new, dead revision. */
+
+ /* Print message indicating that file is going to be removed. */
+ (void) printf ("Removing %s;\n", file);
+
+ rev = NULL;
+ lockflag = "-l";
+ if (branch)
+ {
+ char *branchname;
+
+ rev = RCS_whatbranch (file, tag, srcfiles);
+ if (rev == NULL)
+ {
+ error (0, 0, "cannot find branch \"%s\".", tag);
+ return (1);
+ }
+
+ p = findnode (srcfiles, file);
+ if (p == NULL)
+ {
+ error (0, 0, "boy, I'm confused.");
+ return (1);
+ }
+ rcsfile = (RCSNode *) p->data;
+ branchname = RCS_getbranch (rcsfile, rev, 1);
+ if (branchname == NULL)
+ {
+ /* no revision exists on this branch. use the previous
+ revision but do not lock. */
+ corev = RCS_gettag (rcsfile, tag, 1, 0);
+ prev_rev = xstrdup(rev);
+ lockflag = "";
+ } else
+ {
+ corev = xstrdup (rev);
+ prev_rev = xstrdup(branchname);
+ free (branchname);
+ }
+
+ } else /* Not a branch */
+ {
+
+ /* Get current head revision of file. */
+ p = findnode (srcfiles, file);
+ if (p == NULL)
+ {
+ error (0, 0, "could not find parsed rcsfile %s", file);
+ return (1);
+ }
+ rcsfile = (RCSNode *) p->data;
+ prev_rev = RCS_head (rcsfile);
+ }
+
+ /* if removing without a tag or a branch, then make sure the default
+ branch is the trunk. */
+ if (!tag && !branch)
+ {
+ if (RCS_setbranch (rcs, NULL) != 0)
+ {
+ error (0, 0, "cannot change branch to default for %s",
+ rcs);
+ return (1);
+ }
+ }
+
+#ifdef SERVER_SUPPORT
+ if (server_active) {
+ /* If this is the server, there will be a file sitting in the
+ temp directory which is the kludgy way in which server.c
+ tells time_stamp that the file is no longer around. Remove
+ it so we can create temp files with that name (ignore errors). */
+ unlink_file (file);
+ }
+#endif
+
+ /* check something out. Generally this is the head. If we have a
+ particular rev, then name it. except when creating a branch,
+ lock the rev we're checking out. */
+ run_setup ("%s%s %s %s%s %s", Rcsbin, RCS_CO,
+ lockflag,
+ rev ? "-r" : "",
+ rev ? corev : "", rcs);
+ if ((retcode = run_exec (RUN_TTY, RUN_TTY, DEVNULL, RUN_NORMAL))
+ != 0) {
+ if (!quiet)
+ error (0, retcode == -1 ? errno : 0,
+ "failed to check out `%s'", rcs);
+ return (1);
+ }
+
+ if (corev != NULL)
+ free (corev);
+
+#ifdef DEATH_STATE
+ run_setup ("%s%s -f -sdead %s%s", Rcsbin, RCS_CI, rev ? "-r" : "",
+#else
+ run_setup ("%s%s -K %s%s", Rcsbin, RCS_CI, rev ? "-r" : "",
+#endif
+ rev ? rev : "");
+ run_args ("-m%s", make_message_rcslegal (message));
+ run_arg (rcs);
+ if ((retcode = run_exec (RUN_TTY, RUN_TTY, DEVNULL, RUN_NORMAL))
+ != 0) {
+ if (!quiet)
+ error (0, retcode == -1 ? errno : 0,
+ "failed to commit dead revision for `%s'", rcs);
+ return (1);
+ }
+
+ if (rev != NULL)
+ free (rev);
+
+ if (!branch)
+#else /* No DEATH_SUPPORT */
+ else
+#endif /* No DEATH_SUPPORT */
+ {
+ /* this was the head; really move it into the Attic */
+ tmp = xmalloc(strlen(repository) +
+ sizeof('/') +
+ sizeof(CVSATTIC) +
+ sizeof('/') +
+ strlen(file) +
+ sizeof(RCSEXT) + 1);
+ (void) sprintf (tmp, "%s/%s", repository, CVSATTIC);
+ omask = umask (cvsumask);
+ (void) CVS_MKDIR (tmp, 0777);
+ (void) umask (omask);
+ (void) sprintf (tmp, "%s/%s/%s%s", repository, CVSATTIC, file, RCSEXT);
+
+#ifdef DEATH_SUPPORT
+ if (strcmp (rcs, tmp) != 0
+ && rename (rcs, tmp) == -1
+ && (isreadable (rcs) || !isreadable (tmp)))
+ {
+ free(tmp);
+ return (1);
+ }
+ free(tmp);
+ }
+
+ /* Print message that file was removed. */
+ (void) printf ("%s <-- %s\n", rcs, file);
+ (void) printf ("new revision: delete; ");
+ (void) printf ("previous revision: %s\n", prev_rev);
+ (void) printf ("done\n");
+ free(prev_rev);
+
+ Scratch_Entry (entries, file);
+ return (0);
+#else /* No DEATH_SUPPORT */
+
+ if ((strcmp (rcs, tmp) == 0 || rename (rcs, tmp) != -1) ||
+ (!isreadable (rcs) && isreadable (tmp)))
+ {
+ Scratch_Entry (entries, file);
+ /* FIXME: should free tmp. */
+ return (0);
+ }
+ /* FIXME: should free tmp. */
+ }
+ return (1);
+#endif /* No DEATH_SUPPORT */
+}
+
+/*
+ * Do the actual checkin for added files
+ */
+static int
+finaladd (file, rev, tag, options, update_dir, repository, entries)
+ char *file;
+ char *rev;
+ char *tag;
+ char *options;
+ char *update_dir;
+ char *repository;
+ List *entries;
+{
+ int ret;
+ char tmp[PATH_MAX];
+ char rcs[PATH_MAX];
+
+ locate_rcs (file, repository, rcs);
+ ret = Checkin ('A', file, update_dir, repository, rcs, rev, tag, options,
+ message, entries);
+ if (ret == 0)
+ {
+ (void) sprintf (tmp, "%s/%s%s", CVSADM, file, CVSEXT_LOG);
+ (void) unlink_file (tmp);
+ }
+ else
+ fixaddfile (file, repository);
+ return (ret);
+}
+
+/*
+ * Unlock an rcs file
+ */
+static void
+unlockrcs (file, repository)
+ char *file;
+ char *repository;
+{
+ char rcs[PATH_MAX];
+ int retcode = 0;
+
+ locate_rcs (file, repository, rcs);
+
+ if ((retcode = RCS_unlock (rcs, NULL, 0)) != 0)
+ error (retcode == -1 ? 1 : 0, retcode == -1 ? errno : 0,
+ "could not unlock %s", rcs);
+}
+
+/*
+ * remove a partially added file. if we can parse it, leave it alone.
+ */
+static void
+fixaddfile (file, repository)
+ char *file;
+ char *repository;
+{
+ RCSNode *rcsfile;
+ char rcs[PATH_MAX];
+ int save_really_quiet;
+
+ locate_rcs (file, repository, rcs);
+ save_really_quiet = really_quiet;
+ really_quiet = 1;
+ if ((rcsfile = RCS_parsercsfile (rcs)) == NULL)
+ (void) unlink_file (rcs);
+ else
+ freercsnode (&rcsfile);
+ really_quiet = save_really_quiet;
+}
+
+/*
+ * put the branch back on an rcs file
+ */
+static void
+fixbranch (file, repository, branch)
+ char *file;
+ char *repository;
+ char *branch;
+{
+ char rcs[PATH_MAX];
+ int retcode = 0;
+
+ if (branch != NULL && branch[0] != '\0')
+ {
+ locate_rcs (file, repository, rcs);
+ if ((retcode = RCS_setbranch (rcs, branch)) != 0)
+ error (retcode == -1 ? 1 : 0, retcode == -1 ? errno : 0,
+ "cannot restore branch to %s for %s", branch, rcs);
+ }
+}
+
+/*
+ * do the initial part of a file add for the named file. if adding
+ * with a tag, put the file in the Attic and point the symbolic tag
+ * at the committed revision.
+ */
+
+static int
+checkaddfile (file, repository, tag, options, srcfiles)
+ char *file;
+ char *repository;
+ char *tag;
+ char *options;
+ List *srcfiles;
+{
+ char rcs[PATH_MAX];
+ char fname[PATH_MAX];
+ mode_t omask;
+ int retcode = 0;
+#ifdef DEATH_SUPPORT
+ int newfile = 0;
+#endif
+
+ if (tag)
+ {
+ (void) sprintf(rcs, "%s/%s", repository, CVSATTIC);
+ omask = umask (cvsumask);
+ if (CVS_MKDIR (rcs, 0777) != 0 && errno != EEXIST)
+ error (1, errno, "cannot make directory `%s'", rcs);;
+ (void) umask (omask);
+ (void) sprintf (rcs, "%s/%s/%s%s", repository, CVSATTIC, file, RCSEXT);
+ }
+ else
+ locate_rcs (file, repository, rcs);
+
+#ifdef DEATH_SUPPORT
+ if (isreadable(rcs))
+ {
+ /* file has existed in the past. Prepare to resurrect. */
+ char oldfile[PATH_MAX];
+ char *rev;
+ Node *p;
+ RCSNode *rcsfile;
+
+ if (tag == NULL)
+ {
+ /* we are adding on the trunk, so move the file out of the
+ Attic. */
+ strcpy (oldfile, rcs);
+ sprintf (rcs, "%s/%s%s", repository, file, RCSEXT);
+
+ if (strcmp (oldfile, rcs) == 0
+ || rename (oldfile, rcs) != 0
+ || isreadable (oldfile)
+ || !isreadable (rcs))
+ {
+ error (0, 0, "failed to move `%s' out of the attic.",
+ file);
+ return (1);
+ }
+ }
+
+ p = findnode (srcfiles, file);
+ if (p == NULL)
+ {
+ error (0, 0, "could not find parsed rcsfile %s", file);
+ return (1);
+ }
+
+ rcsfile = (RCSNode *) p->data;
+ rev = RCS_getversion (rcsfile, tag, NULL, 1, 0);
+ /* and lock it */
+ if (lock_RCS (file, rcs, rev, repository)) {
+ error (0, 0, "cannot lock `%s'.", rcs);
+ free (rev);
+ return (1);
+ }
+
+ free (rev);
+ } else {
+ /* this is the first time we have ever seen this file; create
+ an rcs file. */
+ run_setup ("%s%s -i", Rcsbin, RCS);
+
+ (void) sprintf (fname, "%s/%s%s", CVSADM, file, CVSEXT_LOG);
+ /* If the file does not exist, no big deal. In particular, the
+ server does not (yet at least) create CVSEXT_LOG files. */
+ if (isfile (fname))
+ run_args ("-t%s/%s%s", CVSADM, file, CVSEXT_LOG);
+
+ /* Set RCS keyword expansion options. */
+ if (options && options[0] == '-' && options[1] == 'k')
+ run_arg (options);
+ run_arg (rcs);
+ if ((retcode = run_exec (RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL)) != 0)
+ {
+ error (retcode == -1 ? 1 : 0, retcode == -1 ? errno : 0,
+ "could not create %s", rcs);
+ return (1);
+ }
+ newfile = 1;
+ }
+
+ /* when adding a file for the first time, and using a tag, we need
+ to create a dead revision on the trunk. */
+ if (tag && newfile)
+ {
+ char tmp[PATH_MAX];
+
+ /* move the new file out of the way. */
+ (void) sprintf (fname, "%s/%s%s", CVSADM, CVSPREFIX, file);
+ rename_file (file, fname);
+ copy_file (DEVNULL, file);
+
+ /* commit a dead revision. */
+ (void) sprintf (tmp, "-mfile %s was initially added on branch %s.", file, tag);
+#ifdef DEATH_STATE
+ run_setup ("%s%s -q -f -sdead", Rcsbin, RCS_CI);
+#else
+ run_setup ("%s%s -q -K", Rcsbin, RCS_CI);
+#endif
+ run_arg (tmp);
+ run_arg (rcs);
+ if ((retcode = run_exec (RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL)) != 0)
+ {
+ error (retcode == -1 ? 1 : 0, retcode == -1 ? errno : 0,
+ "could not create initial dead revision %s", rcs);
+ return (1);
+ }
+
+ /* put the new file back where it was */
+ rename_file (fname, file);
+
+ /* and lock it once again. */
+ if (lock_RCS (file, rcs, NULL, repository)) {
+ error (0, 0, "cannot lock `%s'.", rcs);
+ return (1);
+ }
+ }
+
+ if (tag != NULL)
+ {
+ /* when adding with a tag, we need to stub a branch, if it
+ doesn't already exist. */
+ Node *p;
+ RCSNode *rcsfile;
+
+ rcsfile = RCS_parse (file, repository);
+ if (rcsfile == NULL)
+ {
+ error (0, 0, "could not read %s", rcs);
+ return (1);
+ }
+
+ if (!RCS_nodeisbranch (tag, rcsfile)) {
+ /* branch does not exist. Stub it. */
+ char *head;
+ char *magicrev;
+
+ head = RCS_getversion (rcsfile, NULL, NULL, 0, 0);
+ magicrev = RCS_magicrev (rcsfile, head);
+ if ((retcode = RCS_settag(rcs, tag, magicrev)) != 0)
+ {
+ error (retcode == -1 ? 1 : 0, retcode == -1 ? errno : 0,
+ "could not stub branch %s for %s", tag, rcs);
+ return (1);
+ }
+
+ freercsnode (&rcsfile);
+
+ /* reparse the file, then add it to our list. */
+ rcsfile = RCS_parse (file, repository);
+ if (rcsfile == NULL)
+ {
+ error (0, 0, "could not reparse %s", rcs);
+ return (1);
+ }
+
+ free (head);
+ free (magicrev);
+ }
+ else
+ {
+ /* lock the branch. (stubbed branches need not be locked.) */
+ if (lock_RCS (file, rcs, NULL, repository)) {
+ error (0, 0, "cannot lock `%s'.", rcs);
+ return (1);
+ }
+ }
+
+ /* add (replace) this rcs file to our list */
+ p = findnode (srcfiles, file);
+
+ if (p != NULL)
+ freercsnode((RCSNode **) &p->data);
+
+ delnode(p);
+
+ RCS_addnode (file, rcsfile, srcfiles);
+ }
+#else /* No DEATH_SUPPORT */
+ run_setup ("%s%s -i", Rcsbin, RCS);
+ run_args ("-t%s/%s%s", CVSADM, file, CVSEXT_LOG);
+ /* Set RCS keyword expansion options. */
+ if (options && options[0] == '-' && options[1] == 'k')
+ run_arg (options);
+ run_arg (rcs);
+ if ((retcode = run_exec (RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL)) != 0)
+ {
+ error (retcode == -1 ? 1 : 0, retcode == -1 ? errno : 0,
+ "could not create %s", rcs);
+ return (1);
+ }
+#endif /* No DEATH_SUPPORT */
+
+ fix_rcs_modes (rcs, file);
+ return (0);
+}
+
+/*
+ * Lock the rcs file ``file''
+ */
+static int
+lockrcsfile (file, repository, rev)
+ char *file;
+ char *repository;
+ char *rev;
+{
+ char rcs[PATH_MAX];
+
+ locate_rcs (file, repository, rcs);
+ if (lock_RCS (file, rcs, rev, repository) != 0)
+ return (1);
+ else
+ return (0);
+}
+
+/*
+ * Attempt to place a lock on the RCS file; returns 0 if it could and 1 if it
+ * couldn't. If the RCS file currently has a branch as the head, we must
+ * move the head back to the trunk before locking the file, and be sure to
+ * put the branch back as the head if there are any errors.
+ */
+static int
+lock_RCS (user, rcs, rev, repository)
+ char *user;
+ char *rcs;
+ char *rev;
+ char *repository;
+{
+ RCSNode *rcsfile;
+ char *branch = NULL;
+ int err = 0;
+
+ /*
+ * For a specified, numeric revision of the form "1" or "1.1", (or when
+ * no revision is specified ""), definitely move the branch to the trunk
+ * before locking the RCS file.
+ *
+ * The assumption is that if there is more than one revision on the trunk,
+ * the head points to the trunk, not a branch... and as such, it's not
+ * necessary to move the head in this case.
+ */
+ if (rev == NULL || (rev && isdigit (*rev) && numdots (rev) < 2))
+ {
+ if ((rcsfile = RCS_parsercsfile (rcs)) == NULL)
+ {
+ /* invalid rcs file? */
+ err = 1;
+ }
+ else
+ {
+ /* rcsfile is valid */
+ branch = xstrdup (rcsfile->branch);
+ freercsnode (&rcsfile);
+ if (branch != NULL)
+ {
+ if (RCS_setbranch (rcs, NULL) != 0)
+ {
+ error (0, 0, "cannot change branch to default for %s",
+ rcs);
+ if (branch)
+ free (branch);
+ return (1);
+ }
+ }
+ err = RCS_lock(rcs, NULL, 0);
+ }
+ }
+ else
+ {
+ (void) RCS_lock(rcs, rev, 1);
+ }
+
+ if (err == 0)
+ {
+ if (branch)
+ {
+ (void) strcpy (sbranch, branch);
+ free (branch);
+ }
+ else
+ sbranch[0] = '\0';
+ return (0);
+ }
+
+ /* try to restore the branch if we can on error */
+ if (branch != NULL)
+ fixbranch (user, repository, branch);
+
+ if (branch)
+ free (branch);
+ return (1);
+}
+
+/*
+ * Called when "add"ing files to the RCS respository, as it is necessary to
+ * preserve the file modes in the same fashion that RCS does. This would be
+ * automatic except that we are placing the RCS ,v file very far away from
+ * the user file, and I can't seem to convince RCS of the location of the
+ * user file. So we munge it here, after the ,v file has been successfully
+ * initialized with "rcs -i".
+ */
+static void
+fix_rcs_modes (rcs, user)
+ char *rcs;
+ char *user;
+{
+ struct stat sb;
+
+ if (stat (user, &sb) != -1)
+ (void) chmod (rcs, (int) sb.st_mode & ~0222);
+}
+
+/*
+ * free an UPDATE node's data (really nothing to do)
+ */
+void
+update_delproc (p)
+ Node *p;
+{
+ p->data = (char *) NULL;
+}
+
+/*
+ * Free the commit_info structure in p.
+ */
+static void
+ci_delproc (p)
+ Node *p;
+{
+ struct commit_info *ci;
+
+ ci = (struct commit_info *) p->data;
+ if (ci->rev)
+ free (ci->rev);
+ if (ci->tag)
+ free (ci->tag);
+ if (ci->options)
+ free (ci->options);
+ free (ci);
+}
+
+/*
+ * Free the commit_info structure in p.
+ */
+static void
+masterlist_delproc (p)
+ Node *p;
+{
+ struct master_lists *ml;
+
+ ml = (struct master_lists *) p->data;
+ dellist (&ml->ulist);
+ dellist (&ml->cilist);
+ free (ml);
+}
+
+/*
+ * Find an RCS file in the repository.
+ */
+static void
+locate_rcs (file, repository, rcs)
+ char *file;
+ char *repository;
+ char *rcs;
+{
+ (void) sprintf (rcs, "%s/%s%s", repository, file, RCSEXT);
+ if (!isreadable (rcs))
+ {
+ (void) sprintf (rcs, "%s/%s/%s%s", repository, CVSATTIC, file, RCSEXT);
+ if (!isreadable (rcs))
+ (void) sprintf (rcs, "%s/%s%s", repository, file, RCSEXT);
+ }
+}
diff --git a/gnu/usr.bin/cvs/cvs/convert.sh b/gnu/usr.bin/cvs/cvs/convert.sh
new file mode 100644
index 0000000..728e79f
--- /dev/null
+++ b/gnu/usr.bin/cvs/cvs/convert.sh
@@ -0,0 +1,28 @@
+#!/bin/sh
+#
+# short script to convert cvs repositories to support file death.
+#
+
+WORKDIR=/tmp/$$-cvs-convert
+mkdir ${WORKDIR}
+cd ${WORKDIR}
+
+case $# in
+1) ;;
+*)
+ echo Usage: convert repository 2>&1
+ exit 1
+ ;;
+esac
+
+attics=`find $1 -name Attic -print`
+
+for i in ${attics} ; do
+ mkdir $i/SAVE
+ for j in $i/*,v ; do
+ echo $j
+ cp $j $i/SAVE
+ co -l $j
+ ci -f -sdead -m"recording file death" $j
+ done
+done
diff --git a/gnu/usr.bin/cvs/cvs/create_adm.c b/gnu/usr.bin/cvs/cvs/create_adm.c
new file mode 100644
index 0000000..1fe8185
--- /dev/null
+++ b/gnu/usr.bin/cvs/cvs/create_adm.c
@@ -0,0 +1,144 @@
+/*
+ * Copyright (c) 1992, Brian Berliner and Jeff Polk
+ * Copyright (c) 1989-1992, Brian Berliner
+ *
+ * You may distribute under the terms of the GNU General Public License as
+ * specified in the README file that comes with the CVS 1.4 kit.
+ *
+ * Create Administration.
+ *
+ * Creates a CVS administration directory based on the argument repository; the
+ * "Entries" file is prefilled from the "initrecord" argument.
+ */
+
+#include "cvs.h"
+
+#ifndef lint
+static const char rcsid[] = "$CVSid: @(#)create_adm.c 1.28 94/09/23 $";
+USE(rcsid);
+#endif
+
+/* update_dir includes dir as its last component. */
+
+void
+Create_Admin (dir, update_dir, repository, tag, date)
+ char *dir;
+ char *update_dir;
+ char *repository;
+ char *tag;
+ char *date;
+{
+ FILE *fout;
+ char *cp;
+ char tmp[PATH_MAX];
+
+#ifdef SERVER_SUPPORT
+ if (trace)
+ {
+ char wd[PATH_MAX];
+ getwd (wd);
+ fprintf (stderr, "%c-> Create_Admin (%s, %s, %s, %s, %s) in %s\n",
+ (server_active) ? 'S' : ' ',
+ dir, update_dir, repository, tag ? tag : "",
+ date ? date : "", wd);
+ }
+#endif
+
+ if (noexec)
+ return;
+
+ if (dir != NULL)
+ (void) sprintf (tmp, "%s/%s", dir, CVSADM);
+ else
+ (void) strcpy (tmp, CVSADM);
+ if (isfile (tmp))
+ error (1, 0, "there is a version in %s already", update_dir);
+
+ make_directory (tmp);
+
+#ifdef CVSADM_ROOT
+ /* record the current cvs root for later use */
+
+ Create_Root (dir, CVSroot);
+#endif /* CVSADM_ROOT */
+ if (dir != NULL)
+ (void) sprintf (tmp, "%s/%s", dir, CVSADM_REP);
+ else
+ (void) strcpy (tmp, CVSADM_REP);
+ fout = fopen (tmp, "w+");
+ if (fout == NULL)
+ {
+ if (update_dir[0] == '\0')
+ error (1, errno, "cannot open %s", tmp);
+ else
+ error (1, errno, "cannot open %s/%s", update_dir, CVSADM_REP);
+ }
+ cp = repository;
+ strip_path (cp);
+
+#ifdef RELATIVE_REPOS
+ /*
+ * If the Repository file is to hold a relative path, try to strip off
+ * the leading CVSroot argument.
+ */
+ if (CVSroot != NULL)
+ {
+ char path[PATH_MAX];
+
+ (void) sprintf (path, "%s/", CVSroot);
+ if (strncmp (repository, path, strlen (path)) == 0)
+ cp = repository + strlen (path);
+ }
+#endif
+
+ if (fprintf (fout, "%s\n", cp) < 0)
+ {
+ if (update_dir[0] == '\0')
+ error (1, errno, "write to %s failed", tmp);
+ else
+ error (1, errno, "write to %s/%s failed", update_dir, CVSADM_REP);
+ }
+ if (fclose (fout) == EOF)
+ {
+ if (update_dir[0] == '\0')
+ error (1, errno, "cannot close %s", tmp);
+ else
+ error (1, errno, "cannot close %s/%s", update_dir, CVSADM_REP);
+ }
+
+ /* now, do the Entries file */
+ if (dir != NULL)
+ (void) sprintf (tmp, "%s/%s", dir, CVSADM_ENT);
+ else
+ (void) strcpy (tmp, CVSADM_ENT);
+ fout = fopen (tmp, "w+");
+ if (fout == NULL)
+ {
+ if (update_dir[0] == '\0')
+ error (1, errno, "cannot open %s", tmp);
+ else
+ error (1, errno, "cannot open %s/%s", update_dir, CVSADM_ENT);
+ }
+ if (fclose (fout) == EOF)
+ {
+ if (update_dir[0] == '\0')
+ error (1, errno, "cannot close %s", tmp);
+ else
+ error (1, errno, "cannot close %s/%s", update_dir, CVSADM_ENT);
+ }
+
+ /* Create a new CVS/Tag file */
+ WriteTag (dir, tag, date);
+
+#ifdef SERVER_SUPPORT
+ if (server_active)
+ server_set_sticky (update_dir, repository, tag, date);
+
+ if (trace)
+ {
+ fprintf (stderr, "%c<- Create_Admin\n",
+ (server_active) ? 'S' : ' ');
+ }
+#endif
+
+}
diff --git a/gnu/usr.bin/cvs/cvs/cvs.1 b/gnu/usr.bin/cvs/cvs/cvs.1
new file mode 100644
index 0000000..5a70301
--- /dev/null
+++ b/gnu/usr.bin/cvs/cvs/cvs.1
@@ -0,0 +1,2185 @@
+.de Id
+.ds Rv \\$3
+.ds Dt \\$4
+..
+.Id $Id: cvs.1,v 1.7 1995/11/15 01:02:41 woods Exp $
+.TH CVS 1 "\*(Dt"
+.\" Full space in nroff; half space in troff
+.de SP
+.if n .sp
+.if t .sp .5
+..
+.\" quoted command
+.de `
+.RB ` "\|\\$1\|" '\\$2
+..
+.SH "NAME"
+cvs \- Concurrent Versions System
+.SH "SYNOPSIS"
+.TP
+\fBcvs\fP [ \fIcvs_options\fP ]
+.I cvs_command
+[
+.I command_options
+] [
+.I command_args
+]
+.SH "DESCRIPTION"
+.IX "revision control system" "\fLcvs\fR"
+.IX cvs "" "\fLcvs\fP \- concurrent versions system"
+.IX "concurrent versions system \- \fLcvs\fP"
+.IX "release control system" "cvs command" "" "\fLcvs\fP \- concurrent versions system"
+.IX "source control system" "cvs command" "" "\fLcvs\fP \- concurrent versions system"
+.IX revisions "cvs command" "" "\fLcvs\fP \- source control"
+.B cvs
+is a front end to the
+.BR rcs ( 1 )
+revision control system which extends
+the notion of revision control from a collection of files in a single
+directory to a hierarchical collection of directories consisting of
+revision controlled files.
+These directories and files can be combined together to form a software
+release.
+.B cvs
+provides the functions necessary to manage these software releases and to
+control the concurrent editing of source files among multiple software
+developers.
+.SP
+.B cvs
+keeps a single copy of the master sources.
+This copy is called the source ``repository''; it contains all the
+information to permit extracting previous software releases at any
+time based on either a symbolic revision tag, or a date in the past.
+.SH "ESSENTIAL COMMANDS"
+.B cvs
+provides a rich variety of commands (\fIcvs_command\fP in the
+Synopsis), each of which often has a wealth of options, to satisfy the
+many needs of source management in distributed environments. However,
+you don't have to master every detail to do useful work with
+.BR cvs ;
+in fact, five commands are sufficient to use (and contribute to)
+the source repository.
+.TP
+\fBcvs checkout\fP \fImodules\fP\|.\|.\|.
+A necessary preliminary for most \fBcvs\fP work: creates your private
+copy of the source for \fImodules\fP (named collections of source; you
+can also use a path relative to the source repository here). You can
+work with this copy without interfering with others' work. At least
+one subdirectory level is always created.
+.TP
+.B cvs update
+Execute this command from \fIwithin\fP your private source
+directory when you wish to update your copies of source files from
+changes that other developers have made to the source in the
+repository.
+.TP
+\fBcvs add\fP \fIfile\fP\|.\|.\|.
+Use this command to enroll new files in \fBcvs\fP records of your
+working directory. The files will be added to the repository the next
+time you run
+.` "cvs commit".
+Note:
+You should use the
+.` "cvs import"
+command to bootstrap new sources into the source repository.
+.` "cvs add"
+is only used for new files to an already checked-out module.
+.TP
+\fBcvs remove\fP \fIfile\fP\|.\|.\|.
+Use this command (after erasing any files listed) to declare that you
+wish to eliminate files from the repository. The removal does not
+affect others until you run
+.` "cvs commit".
+.TP
+\fBcvs commit\fP \fIfile\fP\|.\|.\|.
+Use this command when you wish to ``publish'' your changes to other
+developers, by incorporating them in the source repository.
+.SH "OPTIONS"
+The
+.B cvs
+command line can include
+.IR cvs_options ,
+which apply to the overall
+.B cvs
+program; a
+.IR cvs_command ,
+which specifies a particular action on the source repository; and
+.I command_options
+and
+.I command_arguments
+to fully specify what the
+.I cvs_command
+will do.
+.SP
+.I Warning:
+you must be careful of precisely where you place options relative to the
+.IR cvs_command .
+The same option can mean different things depending on whether it
+is in the
+.I cvs_options
+position (to the left of a
+.B cvs
+command) or in the
+.I command_options
+position (to the right of a
+.B cvs
+command).
+.SP
+There are only two situations where you may omit
+.IR cvs_command :
+.` "cvs \-H"
+or
+.` "cvs --help"
+elicits a list of available commands, and
+.` "cvs \-v"
+or
+.` "cvs --version"
+displays version information on \fBcvs\fP itself.
+.SP
+.SH "CVS OPTIONS"
+As of release 1.6,
+.B cvs
+supports
+.SM GNU
+style long options as well as short options. Only
+a few long options are currently supported, these are listed in
+brackets after the short options whose functions they duplicate.
+.SP
+Use these options to control the overall
+.B cvs
+program:
+.TP
+.B \-H [ --help ]
+Display usage information about the specified
+.I cvs_command
+(but do not actually execute the command). If you don't specify a
+command name,
+.` "cvs \-H"
+displays a summary of all the commands available.
+.TP
+.B \-Q
+Causes the command to be
+.I really
+quiet; the command will generate output only for serious problems.
+.TP
+.B \-q
+Causes the command to be somewhat quiet; informational messages, such
+as reports of recursion through subdirectories, are suppressed.
+.TP
+\fB\-b\fP \fIbindir\fP
+Use
+.I bindir
+as the directory where
+.SM RCS
+programs are located.
+Overrides the setting of the
+.SM RCSBIN
+environment variable.
+This value should be specified as an absolute pathname.
+.TP
+\fB\-d\fP \fICVS_root_directory\fP
+Use
+.I CVS_root_directory
+as the root directory pathname of the master
+.SM RCS
+source repository.
+Overrides the setting of the
+.SM CVSROOT
+environment variable.
+This value should be specified as an absolute pathname.
+.TP
+\fB\-e\fP \fIeditor\fP
+Use
+.I editor
+to enter revision log information.
+Overrides the setting of the
+.SM CVSEDITOR
+and the
+.SM EDITOR
+environment variables.
+.TP
+.B \-f
+Do not read the
+.B cvs
+startup file (\fI~/.cvsrc\fP).
+.TP
+.B \-l
+Do not log the
+.I cvs_command
+in the command history (but execute it anyway). See the description
+of the
+.B history
+command for information on command history.
+.TP
+.B \-n
+Do not change any files. Attempt to execute the
+.IR cvs_command ,
+but only to issue reports; do not remove, update, or merge any
+existing files, or create any new files.
+.TP
+.B \-t
+Trace program execution; display messages showing the steps of
+.B cvs
+activity. Particularly useful with
+.B \-n
+to explore the potential impact of an unfamiliar command.
+.TP
+.B \-r
+Makes new working files read-only.
+Same effect as if the
+.SM CVSREAD
+environment variable is set.
+.TP
+.B \-v [ --version ]
+Displays version and copyright information for
+.BR cvs .
+.TP
+.B \-w
+Makes new working files read-write (default).
+Overrides the setting of the
+.SM CVSREAD
+environment variable.
+.TP
+\fB\-z\fP \fIcompression\-level\fP
+When transferring files across the network use
+.B gzip
+with compression level \fIcompression\-level\fP to compress and
+de-compress data as it is transferred. Requires the presence of
+the
+.SM GNU
+.B gzip
+program in the current search path at both ends of the link.
+.SH "USAGE"
+Except when requesting general help with
+.` "cvs \-H",
+you must specify a
+.I cvs_command
+to
+.B cvs
+to select a specific release control function to perform.
+Each
+.B cvs
+command accepts its own collection of options and arguments.
+However, many options are available across several commands.
+You can display a usage summary for each command by specifying the
+.B \-H
+option with the command.
+.SH "CVS STARTUP FILE"
+Normally, when CVS starts up, it reads the
+.I .cvsrc
+file from the home directory of the user reading it. This startup
+procedure can be turned off with the
+.B \-f
+flag.
+.SP
+The
+.I .cvsrc
+file lists CVS commands with a list of arguments, one command per
+line. For example, the following line in \fI.cvsrc\fP:
+.SP
+diff \-c
+.SP
+will mean that the
+.` "cvs diff"
+command will always be passed the \-c option in addition to any
+other options that are specified in the command line (in this case
+it will have the effect of producing context sensitive diffs for
+all executions of
+.` "cvs diff"
+).
+.SH "CVS COMMAND SUMMARY"
+Here are brief descriptions of all the
+.B cvs
+commands:
+.TP
+.B add
+Add a new file or directory to the repository, pending a
+.` "cvs commit"
+on the same file.
+Can only be done from within sources created by a previous
+.` "cvs checkout"
+invocation.
+Use
+.` "cvs import"
+to place whole new hierarchies of sources under
+.B cvs
+control.
+(Does not directly affect repository; changes
+working directory.)
+.TP
+.B admin
+Execute
+.SM RCS
+control functions on the source repository. (Changes
+repository directly; uses working directory without changing it.)
+.TP
+.B checkout
+Make a working directory of source files for editing. (Creates or changes
+working directory.)
+.TP
+.B commit
+Apply to the source repository changes, additions, and deletions from your
+working directory. (Changes repository.)
+.TP
+.B diff
+Show differences between files in working directory and source
+repository, or between two revisions in source repository.
+(Does not change either repository or working directory.)
+.TP
+.B export
+Prepare copies of a set of source files for shipment off site.
+Differs from
+.` "cvs checkout"
+in that no
+.B cvs
+administrative directories are created (and therefore
+.` "cvs commit"
+cannot be executed from a directory prepared with
+.` "cvs export"),
+and a symbolic tag must be specified.
+(Does not change repository; creates directory similar to working
+directories).
+.TP
+.B history
+Show reports on
+.B cvs
+commands that you or others have executed on a particular file or
+directory in the source repository. (Does not change repository or
+working directory.) History logs are kept only if enabled by creation
+of the
+.` "$CVSROOT/CVSROOT/history"
+file; see
+.BR cvs ( 5 ).
+.TP
+.B import
+Incorporate a set of updates from off-site into the source repository,
+as a ``vendor branch''. (Changes repository.)
+.TP
+.B log
+Display
+.SM RCS
+log information.
+(Does not change repository or working directory.)
+.TP
+.B rdiff
+Prepare a collection of diffs as a patch file between two releases in
+the repository. (Does not change repository or working directory.)
+.TP
+.B release
+Cancel a
+.` "cvs checkout",
+abandoning any changes.
+(Can delete working directory; no effect on repository.)
+.TP
+.B remove
+Remove files from the source repository, pending a
+.` "cvs commit"
+on the same files. (Does not directly affect repository;
+changes working directory.)
+.TP
+.B rtag
+Explicitly specify a symbolic tag for particular revisions of files in the
+source repository. See also
+.` "cvs tag".
+(Changes repository directly; does not require or affect
+working directory.)
+.TP
+.B status
+Show current status of files: latest version, version in working
+directory, whether working version has been edited and, optionally,
+symbolic tags in the
+.SM RCS
+file. (Does not change
+repository or working directory.)
+.TP
+.B tag
+Specify a symbolic tag for files in the repository. By default, tags
+the revisions
+that were last synchronized with your working directory. (Changes
+repository directly; uses working directory without changing it.)
+.TP
+.B update
+Bring your working directory up to date with changes from the
+repository. Merges are performed automatically when possible; a
+warning is issued if manual resolution is required for conflicting
+changes. (Changes working directory; does not change repository.)
+.SH "COMMON COMMAND OPTIONS"
+This section describes the
+.I command_options
+that are available across several
+.B cvs
+commands. Not all commands support all of these options; each option
+is only supported for commands where it makes sense. However, when
+a command has one of these options you can count on the same meaning
+for the option as in other commands. (Other command
+options, which are listed with the individual commands, may have
+different meanings from one
+.B cvs
+command to another.)
+.I "Warning:"
+the
+.B history
+command is an exception;
+it supports many options that conflict
+even with these standard options.
+.TP
+\fB\-D\fP \fIdate_spec\fP
+Use the most recent revision no later than \fIdate_spec\fP (a single
+argument, date description specifying a date in the
+past). A wide variety of date formats are supported by the underlying
+.SM RCS
+facilities, similar to those described in
+.BR co ( 1 ),
+but not exactly the same.
+The \fIdate_spec\fP is interpreted as being in the local timezone, unless a
+specific timezone is specified.
+The specification is ``sticky'' when you use it to make a
+private copy of a source file; that is, when you get a working file
+using \fB\-D\fP, \fBcvs\fP records the date you
+specified, so that further updates in the same directory will use the
+same date (unless you explicitly override it; see the description of
+the \fBupdate\fP command).
+.B \-D
+is available with the
+.BR checkout ", " diff ", " history ", " export ", "
+.BR rdiff ", " rtag ", and "
+.B update
+commands.
+Examples of valid date specifications include:
+.in +1i
+.ft B
+.nf
+1 month ago
+2 hours ago
+400000 seconds ago
+last year
+last Monday
+yesterday
+a fortnight ago
+3/31/92 10:00:07 PST
+January 23, 1987 10:05pm
+22:00 GMT
+.fi
+.ft P
+.in -1i
+.TP
+.B \-f
+When you specify a particular date or tag to \fBcvs\fP commands, they
+normally ignore files that do not contain the tag (or did not exist on
+the date) that you specified. Use the \fB\-f\fP option if you want
+files retrieved even when there is no match for the tag or date. (The
+most recent version is used in this situation.)
+.B \-f
+is available with these commands:
+.BR checkout ", " export ", "
+.BR rdiff ", " rtag ", and " update .
+.TP
+.B \-H
+Help; describe the options available for this command. This is the
+only option supported for
+.I all
+.B cvs
+commands.
+.TP
+\fB\-k\fP \fIkflag\fP
+Alter the default
+.SM RCS
+processing of keywords; all the
+.B \-k
+options described in
+.BR co ( 1 )
+are available. The \fB\-k\fP option is available with the
+.BR add ", " checkout ", " diff ", " export ", "
+.BR rdiff ", and " update
+commands. Your \fIkflag\fP specification is ``sticky'' when you use
+it to create a private copy of a source file; that is, when you use
+this option with the \fBcheckout\fP or \fBupdate\fP commands,
+\fBcvs\fP associates your selected \fIkflag\fP with the file, and
+continues to use it with future \fBupdate\fP commands on the same file
+until you specify otherwise.
+.SP
+Some of the more useful \fIkflag\fPs are \-ko and \-kb (for binary files,
+only compatible with
+.SM RCS
+version 5.7 or later), and \-kv which is useful for an
+.B export
+where you wish to retain keyword information after an
+.B import
+at some other site.
+.TP
+.B \-l
+Local; run only in current working directory, rather than recurring through
+subdirectories. Available with the following commands:
+.BR checkout ", " commit ", " diff ", "
+.BR export ", " remove ", " rdiff ", " rtag ", "
+.BR status ", " tag ", and " update .
+.I Warning:
+this is not the same
+as the overall
+.` "cvs \-l"
+option, which you can specify to the
+.I left
+of a
+.B cvs
+command!
+.TP
+.B \-n
+Do
+.I not
+run any
+.BR checkout / commit / tag / update
+program. (A program can be specified to run on each of these
+activities, in the modules database; this option bypasses it.)
+Available with the
+.BR checkout ", " commit ", " export ", and "
+.B rtag
+commands.
+.I Warning:
+this is not the same
+as the overall
+.` "cvs \-n"
+option, which you can specify to the
+.I left
+of a
+.B cvs
+command!
+.TP
+.B \-P
+Prune (remove) directories that are empty after being updated, on
+.BR checkout ", or " update .
+Normally, an empty directory (one that is void of revision-controlled
+files) is left alone.
+Specifying
+.B \-P
+will cause these directories to be silently removed from your checked-out
+sources.
+This does not remove the directory from the repository, only from your
+checked out copy.
+Note that this option is implied by the
+.B \-r
+or
+.B \-D
+options of
+.BR checkout " and " export .
+.TP
+.B \-p
+Pipe the files retrieved from the repository to standard output,
+rather than writing them in the current directory. Available with the
+.BR checkout " and " update
+commands.
+.TP
+\fB\-r\fP \fItag\fP
+Use the revision specified by the
+.I tag
+argument instead of the default ``head'' revision. As well as
+arbitrary tags defined with the \fBtag\fP or \fBrtag\fP command, two
+special tags are always available:
+.` "HEAD"
+refers to the most
+recent version available in the repository, and
+.` "BASE"
+refers to the revision you last checked out into the current working
+directory.
+.SP
+The \fItag\fP specification is ``sticky'' when you use
+this option with
+.` "cvs checkout"
+or
+.` "cvs update"
+to
+make your own copy of a file: \fBcvs\fP remembers the \fItag\fP and
+continues to use it on future \fBupdate\fP commands, until you specify
+otherwise.
+.I tag
+can be either a symbolic or numeric tag, in
+.SM RCS
+fashion.
+Specifying the
+.B \-q
+global option along with the
+.B \-r
+command option is often useful, to suppress the warning messages when the
+.SM RCS
+file does not contain the specified tag.
+.B \-r
+is available with the
+.BR checkout ", " commit ", " diff ", "
+.BR history ", " export ", "
+.BR rdiff ", " rtag ", and " update
+commands.
+.I Warning:
+this is not the same
+as the overall
+.` "cvs \-r"
+option, which you can specify to the
+.I left
+of a
+.B cvs
+command!
+.SH "CVS COMMANDS"
+Here (finally) are details on all the
+.B cvs
+commands and the options each accepts. The summary lines at the top
+of each command's description highlight three kinds of things:
+.TP 1i
+\ \ \ \ Command Options and Arguments
+Special options are described in detail below; common command options
+may appear only in the summary line.
+.TP 1i
+\ \ \ \ Working Directory, or Repository?
+Some \fBcvs\fP commands require a working directory to operate; some
+require a repository. Also, some commands \fIchange\fP the
+repository, some change the working directory, and some change
+nothing.
+.TP 1i
+\ \ \ \ Synonyms
+Many commands have synonyms, which you may find easier to
+remember (or type) than the principal name.
+.PP
+.TP
+\fBadd\fP [\fB\-k\fP \fIkflag\fP] [\fB\-m '\fP\fImessage\fP\fB'\fP] \fIfiles.\|.\|.\fP
+.I Requires:
+repository, working directory.
+.br
+.I Changes:
+working directory.
+.br
+.I Synonym:
+.B new
+.br
+Use the
+.B add
+command to create a new file or directory in the
+.SM RCS
+source repository.
+The files or directories specified with
+.B add
+must already exist in the current directory (which must have been created
+with the
+.B checkout
+command).
+To add a whole new directory hierarchy to the source repository
+(for example, files received from a third-party vendor), use the
+.` "cvs import"
+command instead.
+.SP
+If the argument to
+.` "cvs add"
+refers to an immediate sub-directory, the directory is
+created at the correct place in the
+.SM RCS
+source repository, and the necessary
+.B cvs
+administration files are created in your working directory.
+If the directory already exists in the source repository,
+.` "cvs add"
+still creates the administration files in your version of the directory.
+This allows you to use
+.` "cvs add"
+to add a particular directory to your private sources even if
+someone else created that directory after your
+.B checkout
+of the sources. You can do the following:
+.SP
+.in +1i
+.ft B
+.nf
+example% mkdir new_directory
+example% cvs add new_directory
+example% cvs update new_directory
+.fi
+.ft P
+.in -1i
+.SP
+An alternate approach using
+.` "cvs update"
+might be:
+.SP
+.in +1i
+.ft B
+.nf
+example% cvs update -d new_directory
+.fi
+.ft P
+.in -1i
+.SP
+(To add \fIany available\fP new directories to your working directory, it's
+probably simpler to use
+.` "cvs checkout"
+or
+.` "cvs update -d".)
+.SP
+The added files are not placed in the
+.SM RCS
+source repository until you use
+.` "cvs commit"
+to make the change permanent.
+Doing a
+.` "cvs add"
+on a file that was removed with the
+.` "cvs remove"
+command will resurrect the file, if no
+.` "cvs commit"
+command intervened.
+.SP
+You will have the opportunity to specify a logging message, as usual,
+when you use
+.` "cvs commit"
+to make the new file permanent. If you'd like to have another
+logging message associated with just
+.I creation
+of the file (for example, to describe the file's purpose), you can
+specify it with the
+.` "\-m \fImessage\fP"
+option to the
+.B add
+command.
+.SP
+The
+.` "-k kflag"
+option specifies the default way that this
+file will be checked out.
+The
+.` "kflag"
+argument is stored in the
+.SM RCS
+file and can be changed with
+.` "cvs admin".
+Specifying
+.` "-ko"
+is useful for checking in binaries that
+shouldn't have the
+.SM RCS
+id strings expanded.
+.TP
+\fBadmin\fP [\fIrcs-options\fP] \fIfiles.\|.\|.\fP
+.I Requires:
+repository, working directory.
+.br
+.I Changes:
+repository.
+.br
+.I Synonym:
+.B rcs
+.br
+This is the
+.B cvs
+interface to assorted administrative
+.SM RCS
+facilities, documented in
+.BR rcs ( 1 ).
+.` "cvs admin"
+simply passes all its options and arguments to the
+.B rcs
+command; it does no filtering or other processing.
+This command does work recursively, however, so extreme care should be
+used.
+.TP
+\fBcheckout\fP [\fBoptions\fP] \fImodules\fP.\|.\|.
+.I Requires:
+repository.
+.br
+.I Changes:
+working directory.
+.br
+.I Synonyms:
+.BR co ", " get
+.br
+Make a working directory containing copies of the source files specified by
+.IR modules .
+You must execute
+.` "cvs checkout"
+before using most of the other
+.B cvs
+commands, since most of them operate on your working directory.
+.SP
+\fImodules\fP are either symbolic names (themselves defined as the
+module
+.` "modules"
+in the source repository; see
+.BR cvs ( 5 ))
+for some collection of source directories and files, or paths to
+directories or files in the repository.
+.SP
+Depending on the
+.I modules
+you specify,
+.B checkout
+may recursively create directories and populate them with the appropriate
+source files.
+You can then edit these source files at any time (regardless of whether
+other software developers are editing their own copies of the sources);
+update them to include new changes applied by others to the source
+repository; or commit your work as a permanent change to the
+.SM RCS
+repository.
+.SP
+Note that
+.B checkout
+is used to create directories.
+The top-level directory created is always added to the directory
+where
+.B checkout
+is invoked, and usually has the same name as the specified
+.IR module .
+In the case of a
+.I module
+alias, the created sub-directory may have a different name, but you can be
+sure that it will be a sub-directory, and that
+.B checkout
+will show the relative path leading to each file as it is extracted into
+your private work area (unless you specify the
+.B \-Q
+global option).
+.SP
+Running
+.` "cvs checkout"
+on a directory that was already built by a prior
+.B checkout
+is also permitted, and
+has the same effect as specifying the
+.B \-d
+option to the
+.B update
+command described below.
+.SP
+The
+.I options
+permitted with
+.` "cvs checkout"
+include the standard command options
+.BR \-P ", " \-f ", "
+.BI \-k " kflag"
+\&,
+.BR \-l ", " \-n ", " \-p ", "
+.BR \-r
+.IR tag ", and"
+.BI \-D " date"\c
+\&.
+.SP
+In addition to those, you can use these special command options
+with
+.BR checkout :
+.SP
+Use the
+.B \-A
+option to reset any sticky tags, dates, or
+.B \-k
+options. (If you get a working file using one of the
+\fB\-r\fP, \fB\-D\fP, or \fB\-k\fP options, \fBcvs\fP remembers the
+corresponding tag, date, or \fIkflag\fP and continues using it on
+future updates; use the \fB\-A\fP option to make \fBcvs\fP forget these
+specifications, and retrieve the ``head'' version of the file).
+.SP
+The
+.BI \-j " branch"
+option merges the changes made between the
+resulting revision and the revision that it is based on (e.g., if
+the tag refers to a branch,
+.B cvs
+will merge all changes made in that branch into your working file).
+.SP
+With two \fB-j\fP options,
+.B cvs
+will merge in the changes between the two respective revisions.
+This can be used to ``remove'' a certain delta from your working file.
+.SP
+In addition, each \fB-j\fP option can contain on optional date
+specification which, when used with branches, can limit the chosen
+revision to one within a specific date.
+An optional date is specified by adding a colon (:) to the tag.
+An example might be what
+.` "cvs import"
+tells you to do when you have
+just imported sources that have conflicts with local changes:
+.SP
+.in +1i
+.ft B
+.nf
+example% cvs checkout -jTAG:yesterday -jTAG module
+.fi
+.ft P
+.in -1i
+.SP
+Use the
+.B \-N
+option with
+.` "\-d \fIdir\fP"
+to avoid shortening module paths in your working directory. (Normally, \fBcvs\fP shortens paths as much as possible when you specify an explicit target directory.)
+.SP
+Use the
+.B \-c
+option to copy the module file, sorted, to the standard output,
+instead of creating or modifying any files or directories in your
+working directory.
+.SP
+Use the
+.BI \-d " dir"
+option to create a directory called
+.I dir
+for the working files, instead of using the module name. Unless you
+also use \fB\-N\fP, the paths created under \fIdir\fP will be as short
+as possible.
+.SP
+Use the
+.B \-s
+option to display per-module status information stored with
+the
+.B \-s
+option within the modules file.
+.TP
+\fBcommit\fP [\fB\-lnR\fP] [\fB\-m\fP '\fIlog_message\fP' | \fB\-f\fP \fIfile\fP] [\fB\-r\fP \fIrevision\fP] [\fIfiles.\|.\|.\fP]
+.I Requires:
+working directory, repository.
+.br
+.I Changes:
+repository.
+.br
+.I Synonym:
+.B ci
+.br
+Use
+.` "cvs commit"
+when you want to incorporate changes from your working source
+files into the general source repository.
+.SP
+If you don't specify particular \fIfiles\fP to commit, all
+of the files in your working current directory are examined.
+.B commit
+is careful to change in the repository only those files that you have
+really changed. By default (or if you explicitly specify the
+.B \-R
+option), files
+in subdirectories are also examined and committed if they have
+changed; you can use the
+.B \-l
+option to limit
+.B commit
+to the current directory only.
+Sometimes you may want to force a file to be committed even though it
+is unchanged; this is achieved with the
+.B \-f
+flag, which also has the effect of disabling recursion (you can turn
+it back on with
+.B \-R
+of course).
+.SP
+.B commit
+verifies that the selected files are up to date with the current revisions
+in the source repository; it will notify you, and exit without
+committing, if any of the specified files must be made current first
+with
+.` "cvs update".
+.B commit
+does not call the
+.B update
+command for you, but rather leaves that for you to do when
+the time is right.
+.SP
+When all is well, an editor is invoked to allow you to enter a log
+message that will be written to one or more logging programs and placed in the
+.SM RCS
+source repository file.
+You can instead specify the log message on the command line with the
+.B \-m
+option, thus suppressing the editor invocation, or use the
+.B \-F
+option to specify that the argument \fIfile\fP contains the log message.
+.SP
+The
+.B \-r
+option can be used to commit to a particular symbolic or numeric revision
+within the
+.SM RCS
+file.
+For example, to bring all your files up to the
+.SM RCS
+revision ``3.0'' (including those that haven't changed), you might do:
+.SP
+.in +1i
+.ft B
+.nf
+example% cvs commit -r3.0
+.fi
+.ft P
+.in -1i
+.SP
+.B cvs
+will only allow you to commit to a revision that is on the main trunk (a
+revision with a single dot).
+However, you can also commit to a branch revision (one that has an even
+number of dots) with the
+.B \-r
+option.
+To create a branch revision, one typically use the
+.B \-b
+option of the
+.BR rtag " or " tag
+commands.
+Then, either
+.BR checkout " or " update
+can be used to base your sources on the newly created branch.
+From that point on, all
+.B commit
+changes made within these working sources will be automatically added
+to a branch revision, thereby not perturbing main-line development in any
+way.
+For example, if you had to create a patch to the 1.2 version of the
+product, even though the 2.0 version is already under development, you
+might do:
+.SP
+.in +1i
+.ft B
+.nf
+example% cvs rtag -b -rFCS1_2 FCS1_2_Patch product_module
+example% cvs checkout -rFCS1_2_Patch product_module
+example% cd product_module
+[[ hack away ]]
+example% cvs commit
+.fi
+.ft P
+.in -1i
+.SP
+Say you have been working on some extremely experimental software, based on
+whatever revision you happened to checkout last week.
+If others in your group would like to work on this software with you, but
+without disturbing main-line development, you could commit your change to a
+new branch.
+Others can then checkout your experimental stuff and utilize the full
+benefit of
+.B cvs
+conflict resolution.
+The scenario might look like:
+.SP
+.in +1i
+.ft B
+.nf
+example% cvs tag -b EXPR1
+example% cvs update -rEXPR1
+[[ hack away ]]
+example% cvs commit
+.fi
+.ft P
+.in -1i
+.SP
+Others would simply do
+.` "cvs checkout -rEXPR1 whatever_module"
+to work with you on the experimental change.
+.TP
+\fBdiff\fP [\fB\-kl\fP] [\fIrcsdiff_options\fP] [[\fB\-r\fP \fIrev1\fP | \fB\-D\fP \fIdate1\fP] [\fB\-r\fP \fIrev2\fP | \fB\-D\fP \fIdate2\fP]] [\fIfiles.\|.\|.\fP]
+.I Requires:
+working directory, repository.
+.br
+.I Changes:
+nothing.
+.br
+You can compare your working files with revisions in the source
+repository, with the
+.` "cvs diff"
+command. If you don't specify a particular revision, your files
+are compared with the revisions they were based on. You can also use
+the standard
+.B cvs
+command option
+.B \-r
+to specify a particular revision to compare your files with. Finally,
+if you use
+.B \-r
+twice, you can see differences between two revisions in the
+repository.
+You can also specify
+.B \-D
+options to diff against a revision in the past.
+The
+.B \-r
+and
+.B \-D
+options can be mixed together with at most two options ever specified.
+.SP
+See
+.BR rcsdiff ( 1 )
+for a list of other accepted options.
+.SP
+If you don't specify any files,
+.B diff
+will display differences for all those files in the current directory
+(and its subdirectories, unless you use the standard option
+.BR \-l )
+that
+differ from the corresponding revision in the source repository
+(i.e. files that
+.I you
+have changed), or that differ from the revision specified.
+.TP
+\fBexport\fP [\-\fBf\|lNnQq\fP] \fB\-r\fP \fIrev\fP\||\|\fB\-D\fP \fIdate\fP [\fB\-d\fP \fIdir\fP] [\fB\-k\fP \fIkflag\fP] \fImodule\fP.\|.\|.
+.I Requires:
+repository.
+.br
+.I Changes:
+current directory.
+.br
+This command is a variant of
+.` "cvs checkout";
+use it when you want a copy of the source for \fImodule\fP
+without the \fBcvs\fP administrative directories. For example, you
+might use
+.` "cvs export"
+to prepare source for shipment
+off-site. This command \fIrequires\fP that you specify a date or tag
+(with \fB\-D\fP or \fB\-r\fP), so that you can count on reproducing
+the source you ship to others.
+.SP
+The only non-standard options are
+.` "\-d \fIdir\fP"
+(write the
+source into directory \fIdir\fP) and
+.` "\-N"
+(don't shorten
+module paths).
+These have the same meanings as the same options in
+.` "cvs checkout".
+.SP
+The
+.B \-kv
+option is useful when
+.B export
+is used.
+This causes any
+.SM RCS
+keywords to be expanded such that an
+.B import
+done at some other site will not lose the keyword revision information.
+Other \fIkflag\fPs may be used with
+.` "cvs export"
+and are described in
+.BR co ( 1 ).
+.TP
+\fBhistory\fP [\fB\-\fP\fIreport\fP] [\fB\-\fP\fIflags\fP] [\fB\-\fP\fIoptions args\fP] [\fIfiles\fP.\|.\|.]
+.I Requires:
+the file
+.` "$CVSROOT/CVSROOT/history"
+.br
+.I Changes:
+nothing.
+.br
+\fBcvs\fP keeps a history file that tracks each use of the
+\fBcheckout\fP, \fBcommit\fP, \fBrtag\fP, \fBupdate\fP, and \fBrelease\fP
+commands. You can use
+.` "cvs history"
+to display this
+information in various formats.
+.SP
+.I Warning:
+.` "cvs history"
+uses
+.` "\-f",
+.` "\-l",
+.` "\-n",
+and
+.` "\-p"
+in ways that conflict with the
+descriptions in
+.SM
+COMMON COMMAND OPTIONS\c
+\&.
+.SP
+Several options (shown above as \fB\-\fP\fIreport\fP) control what
+kind of report is generated:
+.TP 1i
+.B \ \ \ \ \ \ \-c
+Report on each time \fBcommit\fP was used (i.e., each time the
+repository was modified).
+.TP 1i
+\fB\ \ \ \ \ \ \-m\fP \fImodule\fP
+Report on a particular \fImodule\fP. (You can meaningfully use
+\fB\-m\fP more than once on the command line.)
+.TP 1i
+.B \ \ \ \ \ \ \-o
+Report on checked-out modules.
+.TP 1i
+.B \ \ \ \ \ \ \-T
+Report on all tags.
+.TP 1i
+\fB\ \ \ \ \ \ \-x\fP \fItype\fP
+Extract a particular set of record types \fIX\fP from the \fBcvs\fP
+history. The types are indicated by single letters, which you may
+specify in combination.
+Certain commands have a single record type: \fBcheckout\fP (type `O'),
+\fBrelease\fP (type `F'), and \fBrtag\fP (type `T'). One of four
+record types may result from an \fBupdate\fP: `W', when the working copy
+of a file is deleted during update (because it was gone from the
+repository); `U', when a working file was copied from the
+repository; `G', when a merge was necessary and it succeeded; and 'C',
+when a merge was necessary but collisions were detected (requiring
+manual merging). Finally, one of three record types results from
+\fBcommit\fP: `M', when a file was modified; `A', when a file is first
+added; and `R', when a file is removed.
+.TP 1i
+.B \ \ \ \ \ \ \-e
+Everything (all record types); equivalent to specifying
+.` "\-xMACFROGWUT".
+.TP 1i
+\fB\ \ \ \ \ \ \-z\fP \fIzone\fP
+Use time zone
+.I zone
+when outputting history records.
+The zone name
+.B LT
+stands for local time;
+numeric offsets stand for hours and minutes ahead of UTC.
+For example,
+.B +0530
+stands for 5 hours and 30 minutes ahead of (i.e. east of) UTC.
+.PP
+.RS .5i
+The options shown as \fB\-\fP\fIflags\fP constrain the report without
+requiring option arguments:
+.RE
+.TP 1i
+.B \ \ \ \ \ \ \-a
+Show data for all users (the default is to show data only for the user
+executing
+.` "cvs history").
+.TP 1i
+.B \ \ \ \ \ \ \-l
+Show last modification only.
+.TP 1i
+.B \ \ \ \ \ \ \-w
+Show only the records for modifications done from the same working
+directory where
+.` "cvs history"
+is executing.
+.PP
+.RS .5i
+The options shown as \fB\-\fP\fIoptions args\fP constrain the report
+based on an argument:
+.RE
+.TP 1i
+\fB\ \ \ \ \ \ \-b\fP \fIstr\fP
+Show data back to a record containing the string \fIstr\fP in either
+the module name, the file name, or the repository path.
+.TP 1i
+\fB\ \ \ \ \ \ \-D\fP \fIdate\fP
+Show data since \fIdate\fP.
+.TP 1i
+\fB\ \ \ \ \ \ \-p\fP \fIrepository\fP
+Show data for a particular source repository (you can specify several
+\fB\-p\fP options on the same command line).
+.TP 1i
+\fB\ \ \ \ \ \ \-r\fP \fIrev\fP
+Show records referring to revisions since the revision or tag
+named \fIrev\fP appears in individual RCS files.
+Each
+.SM RCS
+file is searched for the revision or tag.
+.TP 1i
+\fB\ \ \ \ \ \ \-t\fP \fItag\fP
+Show records since tag \fItag\fP was last added to the the history file.
+This differs from the \fB-r\fP flag above in that it reads
+only the history file, not the
+.SM RCS
+files, and is much faster.
+.TP 1i
+\fB\ \ \ \ \ \ \-u\fP \fIname\fP
+Show records for user \fIname\fP.
+.PP
+.TP
+\fBimport\fP [\fB\-\fP\fIoptions\fP] \fIrepository vendortag releasetag\fP.\|.\|.
+.I Requires:
+Repository, source distribution directory.
+.br
+.I Changes:
+repository.
+.br
+Use
+.` "cvs import"
+to incorporate an entire source
+distribution from an outside source (e.g., a source vendor) into your
+source repository directory. You can use this command both for
+initial creation of a repository, and for wholesale updates to the
+module form the outside source.
+.SP
+The \fIrepository\fP argument gives a directory name (or a path to a
+directory) under the CVS root directory for repositories; if the
+directory did not exist, \fBimport\fP creates it.
+.SP
+When you use \fBimport\fP for updates to source that has been modified in your
+source repository (since a prior \fBimport\fP), it
+will notify you of any files that conflict in the two branches of
+development; use
+.` "cvs checkout -j"
+to reconcile the differences, as \fBimport\fP instructs you to do.
+.SP
+By default, certain file names are ignored during
+.` "cvs import":
+names associated with
+.SM CVS
+administration, or with other common source control systems; common
+names for patch files, object files, archive files, and editor backup
+files; and other names that are usually artifacts of assorted utilities.
+Currently, the default list of ignored files includes files matching
+these names:
+.SP
+.in +1i
+.ft B
+.nf
+RCSLOG RCS SCCS
+CVS* cvslog.*
+tags TAGS
+\&.make.state .nse_depinfo
+*~ #* .#* ,*
+*.old *.bak *.BAK *.orig *.rej .del\-*
+*.a *.o *.so *.Z *.elc *.ln core
+.fi
+.ft P
+.in -1i
+.SP
+The outside source is saved in a first-level
+.SM RCS
+branch, by default
+.` "1.1.1".
+Updates are leaves of this
+branch; for example, files from the first imported collection of
+source will be revision
+.` "1.1.1.1",
+then files from the first
+imported update will be revision
+.` "1.1.1.2",
+and so on.
+.SP
+At least three arguments are required. \fIrepository\fP is needed to
+identify the collection of source. \fIvendortag\fP is a tag for the
+entire branch (e.g., for
+.` "1.1.1").
+You must also specify at
+least one \fIreleasetag\fP to identify the files at the leaves created
+each time you execute
+.` "cvs import".
+.SP
+One of the standard
+.B cvs
+command options is available: \fB\-m\fP
+\fImessage\fP. If you do not specify a logging message with
+\fB\-m\fP, your editor is invoked (as with \fBcommit\fP) to allow you
+to enter one.
+.SP
+There are three additional special options.
+.SP
+Use
+.` "\-d"
+to specify that each file's time of last modification should be used
+for the checkin date and time.
+.SP
+Use
+.` "\-b \fIbranch\fP"
+to specify a first-level branch other
+than
+.` "1.1.1".
+.SP
+Use
+.` "\-I \fIname\fP"
+to specify file names that should be
+ignored during \fBimport\fP. You can use this option repeatedly.
+To avoid ignoring any files at all (even those ignored by default),
+specify
+.` "\-I !".
+.TP
+\fBlog\fP [\fB\-l\fP] \fIrlog-options [files\fP\|.\|.\|.]
+.I Requires:
+repository, working directory.
+.br
+.I Changes:
+nothing.
+.br
+.I Synonym:
+.B rlog
+.br
+Display log information for \fIfiles\fP.
+.` "cvs log"
+calls
+the
+.SM RCS
+utility \fBrlog\fP; all the options described in
+.BR rlog ( 1 )
+are available. Among the more useful \fBrlog\fP options are \fB\-h\fP
+to display only the header (including tag definitions, but omitting
+most of the full log); \fB\-r\fP to select logs on particular
+revisions or ranges of revisions; and \fB\-d\fP to select particular
+dates or date ranges. See
+.BR rlog ( 1 )
+for full explanations.
+This command is recursive by default, unless the
+.B \-l
+option is specified.
+.TP
+\fBrdiff\fP [\fB\-\fP\fIflags\fP] [\fB\-V\fP \fIvn\fP] [\fB\-r\fP \fIt\fP|\fB\-D\fP \fId\fP [\fB\-r\fP \fIt2\fP|\fB\-D\fP \fId2\fP]] \fImodules\|.\|.\|.\fP
+.I Requires:
+repository.
+.br
+.I Changes:
+nothing.
+.br
+.I Synonym:
+.B patch
+.br
+Builds a Larry Wall format
+.BR patch ( 1 )
+file between two releases, that can be fed directly into the
+.B patch
+program to bring an old release up-to-date with the new release.
+(This is one of the few \fBcvs\fP commands that operates directly from
+the repository, and doesn't require a prior
+.BR checkout .)
+The diff output is sent to the standard output device.
+You can specify (using the standard \fB\-r\fP and \fB\-D\fP options)
+any combination of one or two revisions or dates.
+If only one revision or date is specified, the
+patch file reflects differences between that revision or date and the
+current ``head'' revisions in the
+.SM RCS
+file.
+.SP
+Note that if the software release affected
+is contained in more than one directory, then it may be necessary to
+specify the
+.B \-p
+option to the
+.B patch
+command when patching the old sources, so that
+.B patch
+is able to find the files that are located in other directories.
+.SP
+If you use the option \fB\-V\fP \fIvn\fP,
+.SM RCS
+keywords are expanded according to the rules current in
+.SM RCS
+version \fIvn\fP (the expansion format changed with
+.SM RCS
+version 5).
+.SP
+The standard option \fIflags\fP \fB\-f\fP, and \fB\-l\fP
+are available with this command. There are also several
+special options flags:
+.SP
+If you use the
+.B \-s
+option, no patch output is produced.
+Instead, a summary of the changed or added files between the two
+releases is sent to the standard output device.
+This is useful for finding out, for example, which files have changed
+between two dates or revisions.
+.SP
+If you use the
+.B \-t
+option, a diff of the top two revisions is sent to the standard output device.
+This is most useful for seeing what the last change to a file was.
+.SP
+If you use the
+.B \-u
+option, the patch output uses the newer ``unidiff'' format for context
+diffs.
+.SP
+You can use
+.B \-c
+to explicitly specify the
+.` "diff \-c"
+form of context diffs
+(which is the default), if you like.
+.TP
+\fBrelease\fP [\fB\-dQq\fP] \fImodules\fP\|.\|.\|.
+.I Requires:
+Working directory.
+.br
+.I Changes:
+Working directory, history log.
+.br
+This command is meant to safely cancel the effect of
+.` "cvs checkout'.
+Since
+.B cvs
+doesn't lock files, it isn't strictly necessary to use this command.
+You can always simply delete your working directory, if you
+like; but you risk losing changes you may have forgotten, and you
+leave no trace in the
+.B cvs
+history file that you've abandoned your checkout.
+.SP
+Use
+.` "cvs release"
+to avoid these problems. This command
+checks that no un-committed changes are present; that you are
+executing it from immediately above, or inside, a \fBcvs\fP working
+directory; and that the repository recorded for your files is the same
+as the repository defined in the module database.
+.SP
+If all these conditions are true,
+.` "cvs release"
+leaves a
+record of its execution (attesting to your intentionally abandoning
+your checkout) in the
+.B cvs
+history log.
+.SP
+You can use the \fB\-d\fP flag to request that your working copies of
+the source files be deleted if the \fBrelease\fP succeeds.
+.TP
+\fBremove\fP [\fB\-lR\fP] [\fIfiles\|.\|.\|.\fP]
+.I Requires:
+Working directory.
+.br
+.I Changes:
+Working directory.
+.br
+.I Synonyms:
+.BR rm ", " delete
+.br
+Use this command to declare that you wish to remove \fIfiles\fP from
+the source repository. Like most
+.B cvs
+commands,
+.` "cvs remove"
+works on files in your working
+directory, not directly on the repository. As a safeguard, it also
+requires that you first erase the specified files from your working
+directory.
+.SP
+The files are not actually removed until you apply your changes to the
+repository with
+.BR commit ;
+at that point, the corresponding
+.SM RCS
+files in the source repository are
+.I moved
+into the
+.` "Attic"
+directory (also within the source repository).
+.SP
+This command is recursive by default, scheduling all physically removed
+files that it finds for removal by the next
+.BR commit .
+Use the
+.B \-l
+option to avoid this recursion, or just specify that actual files that you
+wish remove to consider.
+.TP
+\fBrtag\fP [\fB\-f\|alnRQq\fP] [\fB\-b\fP] [\fB\-d\fP] [\fB\-r\fP \fItag\fP | \fB\-D\fP \fIdate\fP] \fIsymbolic_tag\fP \fImodules\|.\|.\|.\fP
+.I Requires:
+repository.
+.br
+.I Changes:
+repository.
+.br
+.I Synonym:
+.B rfreeze
+.br
+You can use this command to assign symbolic tags to particular,
+explicitly specified source versions in the repository.
+.` "cvs rtag"
+works directly on the repository contents (and requires no
+prior
+.BR checkout ).
+Use
+.` "cvs tag"
+instead, to base the selection of
+versions to tag on the contents of your working directory.
+.SP
+In general, tags (often the symbolic names of software distributions)
+should not be removed, but the
+.B \-d
+option is available as a means to remove completely obsolete symbolic names
+if necessary (as might be the case for an Alpha release, say).
+.SP
+.` "cvs rtag"
+will not move a tag that already exists. With the \fB\-F\fP option,
+however,
+.` "cvs rtag"
+will re-locate any instance of \fIsymbolic_tag\fP that already exists
+on that file to the new repository versions. Without the \fB\-F\fP
+option, attempting to use
+.` "cvs rtag"
+to apply a tag that already exists on that file will produce an error
+message.
+.SP
+The \fB-b\fP option makes the tag a ``branch'' tag, allowing
+concurrent, isolated development.
+This is most useful for creating a patch to a previously released software
+distribution.
+.SP
+You can use the standard \fB\-r\fP and \fB\-D\fP options to tag only those
+files that already contain a certain tag. This method would be used
+to rename a tag: tag only the files identified by the old tag, then delete the
+old tag, leaving the new tag on exactly the same files as the old tag.
+.SP
+.B rtag
+executes recursively by default, tagging all subdirectories of
+\fImodules\fP you specify in the argument. You can restrict its
+operation to top-level directories with the standard \fB\-l\fP option;
+or you can explicitly request recursion with \fB\-R\fP.
+.SP
+The modules database can specify a program to execute whenever a tag
+is specified; a typical use is to send electronic mail to a group of
+interested parties. If you want to bypass that program, use the
+standard \fB\-n\fP option.
+.SP
+Use the
+.B \-a
+option to have
+.B rtag
+look in the
+.` "Attic"
+for removed files that contain the specified tag.
+The tag is removed from these files, which makes it convenient to re-use a
+symbolic tag as development continues (and files get removed from the
+up-coming distribution).
+.TP
+\fBstatus\fP [\fB\-lRqQ\fP] [\fB\-v\fP] [\fIfiles\fP\|.\|.\|.]
+.I Requires:
+working directory, repository.
+.br
+.I Changes:
+nothing.
+.br
+Display a brief report on the current status of \fIfiles\fP with
+respect to the source repository, including any ``sticky'' tags,
+dates, or \fB\-k\fP options. (``Sticky'' options will restrict how
+.` "cvs update"
+operates until you reset them; see the
+description of
+.` "cvs update \-A\|.\|.\|.".)
+.SP
+You can also use this command to anticipate the potential impact of a
+.` "cvs update"
+on your working source directory. If you do
+not specify any \fIfiles\fP explicitly, reports are shown for all
+files that \fBcvs\fP has placed in your working directory. You can
+limit the scope of this search to the current directory itself (not
+its subdirectories) with the standard \fB\-l\fP option flag; or you
+can explicitly request recursive status reports with the \fB\-R\fP
+option.
+.SP
+The
+.B \-v
+option causes the symbolic tags for the
+.SM RCS
+file to be displayed as well.
+.TP
+\fBtag\fP [\fB\-lQqR\fP] [\fB\-F\fP] [\fB\-b\fP] [\fB\-d\fP] [\fB\-r\fP \fItag\fP | \fB\-D\fP \fIdate\fP] [\fB\-f\fP] \fIsymbolic_tag\fP [\fIfiles\fP\|.\|.\|.\|]
+.I Requires:
+working directory, repository.
+.br
+.I Changes:
+repository.
+.br
+.I Synonym:
+.B freeze
+.br
+Use this command to assign symbolic tags to the nearest repository
+versions to your working sources. The tags are applied immediately to
+the repository, as with \fBrtag\fP.
+.SP
+One use for tags is to record a ``snapshot'' of the current sources
+when the software freeze date of a project arrives. As bugs are fixed
+after the freeze date, only those changed sources that are to be part
+of the release need be re-tagged.
+.SP
+The symbolic tags are meant to permanently record which revisions of which
+files were used in creating a software distribution.
+The
+.BR checkout ,
+.B export
+and
+.B update
+commands allow you to extract an exact copy of a tagged release at any time in
+the future, regardless of whether files have been changed, added, or removed
+since the release was tagged.
+.SP
+You can use the standard \fB\-r\fP and \fB\-D\fP options to tag only those
+files that already contain a certain tag. This method would be used
+to rename a tag: tag only the files identified by the old tag, then delete the
+old tag, leaving the new tag on exactly the same files as the old tag.
+.SP
+Specifying the \fB\-f\fP flag in addition to the \fB\-r\fP or \fB\-D\fP
+flags will tag those files named on the command line even if they do not
+contain the old tag or did not exist on the specified date.
+.SP
+By default (without a \fB\-r\fP or \fB\-D\fP flag)
+the versions to be tagged are supplied
+implicitly by the \fBcvs\fP records of your working files' history
+rather than applied explicitly.
+.SP
+If you use
+.` "cvs tag \-d \fIsymbolic_tag\fP\|.\|.\|.",
+the
+symbolic tag you specify is
+.I deleted
+instead of being added. \fIWarning\fP: Be very certain of your ground
+before you delete a tag; doing this effectively discards some
+historical information, which may later turn out to have been valuable.
+.SP
+.` "cvs tag"
+will not move a tag that already exists. With the \fB\-F\fP option,
+however,
+.` "cvs tag"
+will re-locate any instance of \fIsymbolic_tag\fP that already exists
+on that file to the new repository versions. Without the \fB\-F\fP
+option, attempting to use
+.` "cvs tag"
+to apply a tag that already exists on that file will produce an error
+message.
+.SP
+The \fB-b\fP option makes the tag a ``branch'' tag, allowing
+concurrent, isolated development.
+This is most useful for creating a patch to a previously released software
+distribution.
+.SP
+Normally,
+.B tag
+executes recursively through subdirectories; you can prevent this by
+using the standard \fB\-l\fP option, or specify the recursion
+explicitly by using \fB\-R\fP.
+.TP
+\fBupdate\fP [\fB\-Adf\|lPpQqR\fP] [\fB\-d\fP] [\fB\-r\fP \fItag\fP|\fB\-D\fP \fIdate\fP] \fIfiles\|.\|.\|.\fP
+.I Requires:
+repository, working directory.
+.br
+.I Changes:
+working directory.
+.br
+After you've run
+.B checkout
+to create your private copy of source from the common repository,
+other developers will continue changing the central source. From time
+to time, when it is convenient in your development process, you can
+use the
+.B update
+command
+from within your working directory to reconcile your work with any
+revisions applied to the source repository since your last
+.B checkout
+or
+.BR update .
+.SP
+.B update
+keeps you informed of its progress by printing a line for each file,
+prefaced with one of the characters
+.` "U A R M C ?"
+to indicate the status of the file:
+.TP 1i
+\fBU\fP \fIfile\fP
+The file was brought \fIup to date\fP with respect to the repository.
+This is done for any file that exists in the repository but not in
+your source, and for files that you haven't changed but are not the most
+recent versions available in the repository.
+.TP 1i
+\fBA\fP \fIfile\fP
+The file has been \fIadded\fP to your private copy of the sources, and
+will be added to the
+.SM RCS
+source repository when you run
+.` "cvs commit"
+on the file.
+This is a reminder to you that the file needs to be committed.
+.TP 1i
+\fBR\fP \fIfile\fP
+The file has been \fIremoved\fP from your private copy of the sources, and
+will be removed from the
+.SM RCS
+source repository when you run
+.` "cvs commit"
+on the file.
+This is a reminder to you that the file needs to be committed.
+.TP 1i
+\fBM\fP \fIfile\fP
+The file is \fImodified\fP in your working directory.
+.` "M"
+can indicate one of two states for a file you're working on: either
+there were no modifications to the same file in the repository, so
+that your file remains as you last saw it; or there were modifications
+in the repository as well as in your copy, but they were
+\fImerged\fP successfully, without conflict, in your working
+directory.
+.TP 1i
+\fBC\fP \fIfile\fP
+A \fIconflict\fP was detected while trying to merge your changes to
+\fIfile\fP with changes from the source repository. \fIfile\fP (the
+copy in your working directory) is now the output of the
+.BR rcsmerge ( 1 )
+command on the two versions; an unmodified copy of your file is also
+in your working directory, with the name `\fB.#\fP\fIfile\fP\fB.\fP\fIversion\fP',
+where
+.I version
+is the
+.SM RCS
+revision that your modified file started from.
+(Note that some systems automatically purge files that begin with
+\&
+.` ".#"
+if they have not been accessed for a few days.
+If you intend to keep a copy of your original file, it is a very good
+idea to rename it.)
+.TP 1i
+\fB?\fP \fIfile\fP
+\fIfile\fP is in your working directory, but does not correspond to
+anything in the source repository, and is not in the list of files
+for \fBcvs\fP to ignore (see the description of the \fB\-I\fP option).
+.PP
+.RS .5i
+.SP
+Use the
+.B \-A
+option to reset any sticky tags, dates, or
+.B \-k
+options. (If you get a working copy of a file by using one of the
+\fB\-r\fP, \fB\-D\fP, or \fB\-k\fP options, \fBcvs\fP remembers the
+corresponding tag, date, or \fIkflag\fP and continues using it on
+future updates; use the \fB\-A\fP option to make \fBcvs\fP forget these
+specifications, and retrieve the ``head'' version of the file).
+.SP
+The \fB\-j\fP\fIbranch\fP option
+merges the changes made between the
+resulting revision and the revision that it is based on (e.g., if
+the tag refers to a branch,
+.B cvs
+will merge all changes made in
+that branch into your working file).
+.SP
+With two \fB-j\fP options,
+.B cvs
+will merge in the changes between the two respective revisions.
+This can be used to ``remove'' a certain delta from your working file.
+E.g., If the file foo.c is based on
+revision 1.6 and I want to remove the changes made between 1.3 and
+1.5, I might do:
+.SP
+.in +1i
+.ft B
+.nf
+example% cvs update -j1.5 -j1.3 foo.c # note the order...
+.fi
+.ft P
+.in -1i
+.SP
+In addition, each \fB-j\fP option can contain on optional date
+specification which, when used with branches, can limit the chosen
+revision to one within a specific date.
+An optional date is specified by adding a colon (:) to the tag.
+.SP
+.in +1i
+.ft B
+.nf
+-jSymbolic_Tag:Date_Specifier
+.fi
+.ft P
+.in -1i
+.SP
+Use the
+.B \-d
+option to create any directories that exist in the repository if they're
+missing from the working directory. (Normally, update acts only on
+directories and files that were already enrolled in your
+working directory.) This is useful for updating directories
+that were created in the repository since the initial
+\fBcheckout\fP; but it has an unfortunate side effect. If you
+deliberately avoided certain directories in the repository when you
+created your working directory (either through use of a module name or by
+listing explicitly the files and directories you wanted on the
+command line), then updating with
+.B \-d
+will create those directories, which may not be what you want.
+.SP
+Use \fB\-I\fP \fIname\fP to ignore files whose names match \fIname\fP
+(in your working directory) during the update. You can specify
+\fB\-I\fP more than once on the command line to specify several files
+to ignore. By default,
+\fBupdate\fP ignores files whose names match any of the following:
+.SP
+.in +1i
+.ft B
+.nf
+RCSLOG RCS SCCS
+CVS* cvslog.*
+tags TAGS
+\&.make.state .nse_depinfo
+*~ #* .#* ,*
+*.old *.bak *.BAK *.orig *.rej .del\-*
+*.a *.o *.so *.Z *.elc *.ln core
+.fi
+.ft P
+.in -1i
+.SP
+Use
+.` "\-I !"
+to avoid ignoring any files at all.
+.SP
+The standard \fBcvs\fP command options \fB\-f\fP, \fB\-k\fP,
+\fB\-l\fP, \fB\-P\fP, \fB\-p\fP, and \fB\-r\fP
+are also available with \fBupdate\fP.
+.RE
+.SH "FILES"
+For more detailed information on
+.B cvs
+supporting files, see
+.BR cvs ( 5 ).
+.LP
+.I
+Files in home directories:
+.TP
+\&.cvsrc
+The
+.B cvs
+initialisation file. Lines in this file can be used to specify default
+options for each
+.B cvs
+command. For example the line
+.` "diff \-c"
+will ensure that
+.` "cvs diff"
+is always passed the
+.B \-c
+option in addition to any other options passed on the command line.
+.TP
+\&.cvswrappers
+Specifies wrappers to be used in addition to those specified in the
+CVSROOT/cvswrappers file in the repository.
+.LP
+.I
+Files in working directories:
+.TP
+CVS
+A directory of \fBcvs\fP administrative files.
+.I
+Do not delete.
+.TP
+CVS/Entries
+List and status of files in your working directory.
+.TP
+CVS/Entries.Backup
+A backup of
+.` "CVS/Entries".
+.TP
+CVS/Entries.Static
+Flag: do not add more entries on
+.` "cvs update".
+.TP
+CVS/Root
+Pathname to the repository (
+.SM CVSROOT
+) location at the time of checkout. This file is used instead
+of the
+.SM CVSROOT
+environment variable if the environment variable is not
+set. A warning message will be issued when the contents of this
+file and the
+.SM CVSROOT
+environment variable differ. The file may be over-ridden by the
+presence of the
+.SM CVS_IGNORE_REMOTE_ROOT
+environment variable.
+.TP
+CVS/Repository
+Pathname to the corresponding directory in the source repository.
+.TP
+CVS/Tag
+Contains the per-directory ``sticky'' tag or date information.
+This file is created/updated when you specify
+.B \-r
+or
+.B \-D
+to the
+.B checkout
+or
+.B update
+commands, and no files are specified.
+.TP
+CVS/Checkin.prog
+Name of program to run on
+.` "cvs commit".
+.TP
+CVS/Update.prog
+Name of program to run on
+.` "cvs update".
+.LP
+.I
+Files in source repositories:
+.TP
+$CVSROOT/CVSROOT
+Directory of global administrative files for repository.
+.TP
+CVSROOT/commitinfo,v
+Records programs for filtering
+.` "cvs commit"
+requests.
+.TP
+CVSROOT/cvswrappers,v
+Records
+.B cvs
+wrapper commands to be used when checking files into and out of the
+repository. Wrappers allow the file or directory to be processed
+on the way in and out of CVS. The intended uses are many, one
+possible use would be to reformat a C file before the file is checked
+in, so all of the code in the repository looks the same.
+.TP
+CVSROOT/editinfo,v
+Records programs for editing/validating
+.` "cvs commit"
+log entries.
+.TP
+CVSROOT/history
+Log file of \fBcvs\fP transactions.
+.TP
+CVSROOT/loginfo,v
+Records programs for piping
+.` "cvs commit"
+log entries.
+.TP
+CVSROOT/modules,v
+Definitions for modules in this repository.
+.TP
+CVSROOT/rcsinfo,v
+Records pathnames to templates used during a
+.` "cvs commit"
+operation.
+.TP
+CVSROOT/taginfo,v
+Records programs for validating/logging
+.` "cvs tag"
+and
+.` "cvs rtag"
+operations.
+.TP
+MODULE/Attic
+Directory for removed source files.
+.TP
+#cvs.lock
+A lock directory created by
+.B cvs
+when doing sensitive changes to the
+.SM RCS
+source repository.
+.TP
+#cvs.tfl.\fIpid\fP
+Temporary lock file for repository.
+.TP
+#cvs.rfl.\fIpid\fP
+A read lock.
+.TP
+#cvs.wfl.\fIpid\fP
+A write lock.
+.SH "ENVIRONMENT VARIABLES"
+.TP
+.SM CVSROOT
+Should contain the full pathname to the root of the
+.B cvs
+source repository (where the
+.SM RCS
+files are kept). This information must be available to \fBcvs\fP for
+most commands to execute; if
+.SM CVSROOT
+is not set, or if you wish to override it for one invocation, you can
+supply it on the command line:
+.` "cvs \-d \fIcvsroot cvs_command\fP\|.\|.\|."
+You may not need to set
+.SM CVSROOT
+if your \fBcvs\fP binary has the right path compiled in; use
+.` "cvs \-v"
+to display all compiled-in paths.
+.TP
+.SM CVSREAD
+If this is set,
+.B checkout
+and
+.B update
+will try hard to make the files in your working directory read-only.
+When this is not set, the default behavior is to permit modification
+of your working files.
+.TP
+.SM RCSBIN
+Specifies the full pathname where to find
+.SM RCS
+programs, such as
+.BR co ( 1 )
+and
+.BR ci ( 1 ).
+If not set, a compiled-in value is used; see the display from
+.` "cvs \-v".
+.TP
+.SM CVSEDITOR
+Specifies the program to use for recording log messages during
+.BR commit .
+If not set, the
+.SM EDITOR
+environment variable is used instead.
+If
+.SM EDITOR
+is not set either, the default is
+.BR /usr/ucb/vi .
+.TP
+.SM CVS_IGNORE_REMOTE_ROOT
+If this variable is set then
+.B cvs
+will ignore all references to remote repositories in the CVS/Root file.
+.TP
+.SM CVS_RSH
+.B cvs
+uses the contents of this variable to determine the name of the
+remote shell command to use when starting a
+.B cvs
+server. If this variable is not set then
+.` "rsh"
+is used.
+.TP
+.SM CVS_SERVER
+.B cvs
+uses the contents of this variable to determine the name of the
+.B cvs
+server command. If this variable is not set then
+.` "cvs"
+is used.
+.TP
+.SM CVSWRAPPERS
+This variable is used by the
+.` "cvswrappers"
+script to determine the name of the wrapper file, in addition to the
+wrappers defaults contained in the repository
+.SM (CVSROOT/cvswrappers)
+and the user's home directory (~/.cvswrappers).
+.SH "AUTHORS"
+.TP
+Dick Grune
+Original author of the
+.B cvs
+shell script version posted to
+.B comp.sources.unix
+in the volume6 release of December, 1986.
+Credited with much of the
+.B cvs
+conflict resolution algorithms.
+.TP
+Brian Berliner
+Coder and designer of the
+.B cvs
+program itself in April, 1989, based on the original work done by Dick.
+.TP
+Jeff Polk
+Helped Brian with the design of the
+.B cvs
+module and vendor branch support and author of the
+.BR checkin ( 1 )
+shell script (the ancestor of
+.` "cvs import").
+.SH "SEE ALSO"
+.BR ci ( 1 ),
+.BR co ( 1 ),
+.BR cvs ( 5 ),
+.BR cvsbug ( 8 ),
+.BR cvsinit ( 8 ),
+.BR diff ( 1 ),
+.BR grep ( 1 ),
+.BR mkmodules ( 1 ),
+.BR patch ( 1 ),
+.BR rcs ( 1 ),
+.BR rcsdiff ( 1 ),
+.BR rcsmerge ( 1 ),
+.BR rlog ( 1 ),
+.BR rm ( 1 ),
+.BR sort ( 1 ).
diff --git a/gnu/usr.bin/cvs/cvs/cvs.5 b/gnu/usr.bin/cvs/cvs/cvs.5
new file mode 100644
index 0000000..cb4f455
--- /dev/null
+++ b/gnu/usr.bin/cvs/cvs/cvs.5
@@ -0,0 +1,367 @@
+.TH cvs 5 "12 February 1992"
+.\" Full space in nroff; half space in troff
+.de SP
+.if n .sp
+.if t .sp .5
+..
+.SH NAME
+cvs \- Concurrent Versions System support files
+.SH SYNOPSIS
+.hy 0
+.na
+.TP
+.B $CVSROOT/CVSROOT/commitinfo,v
+.TP
+.B $CVSROOT/CVSROOT/cvsignore,v
+.TP
+.B $CVSROOT/CVSROOT/cvswrappers,v
+.TP
+.B $CVSROOT/CVSROOT/editinfo,v
+.TP
+.B $CVSROOT/CVSROOT/history
+.TP
+.B $CVSROOT/CVSROOT/loginfo,v
+.TP
+.B $CVSROOT/CVSROOT/modules,v
+.TP
+.B $CVSROOT/CVSROOT/rcsinfo,v
+.TP
+.B $CVSROOT/CVSROOT/taginfo,v
+.ad b
+.hy 1
+.SH DESCRIPTION
+.B cvs
+is a system for providing source control to hierarchical collections
+of source directories. Commands and procedures for using \fBcvs\fP
+are described in
+.BR cvs ( 1 ).
+.SP
+.B cvs
+manages \fIsource repositories\fP, the directories containing master
+copies of the revision-controlled files, by copying particular
+revisions of the files to (and modifications back from) developers'
+private \fIworking directories\fP. In terms of file structure, each
+individual source repository is an immediate subdirectory of
+\fB$CVSROOT\fP.
+.SP
+The files described here are supporting files; they do not have to
+exist for \fBcvs\fP to operate, but they allow you to make \fBcvs\fP
+operation more flexible.
+.SP
+The
+.BR cvsinit ( 1 )
+shell script included at the top-level of the
+.B cvs
+distribution can be used to setup an initial
+.B $CVSROOT/CVSROOT
+area, if you don't have one already.
+.SP
+You can use the `\|modules\|' file to define symbolic names for
+collections of source maintained with \fBcvs\fP. If there is no
+`\|modules\|' file, developers must specify complete path names
+(absolute, or relative to \fB$CVSROOT\fP) for the files they wish to
+manage with \fBcvs\fP commands.
+.SP
+You can use the `\|commitinfo\|' file to define programs to execute
+whenever `\|\fBcvs commit\fP\|' is about to execute.
+These programs are used for ``pre-commit'' checking to verify that the
+modified, added, and removed files are really ready to be committed.
+Some uses for this check might be to turn off a portion (or all) of the
+source repository from a particular person or group.
+Or, perhaps, to verify that the changed files conform to the site's
+standards for coding practice.
+.SP
+You can use the `\|cvswrappers\|' file to record
+.B cvs
+wrapper commands to be used when checking files into and out of the
+repository. Wrappers allow the file or directory to be processed
+on the way in and out of CVS. The intended uses are many, one
+possible use would be to reformat a C file before the file is checked
+in, so all of the code in the repository looks the same.
+.SP
+You can use the `\|loginfo\|' file to define programs to execute after
+any
+.BR commit ,
+which writes a log entry for changes in the repository.
+These logging programs might be used to append the log message to a file.
+Or send the log message through electronic mail to a group of developers.
+Or, perhaps, post the log message to a particular newsgroup.
+.SP
+You can use the `\|taginfo\|' file to define programs to execute after
+any
+.BR tag or rtag
+operation. These programs might be used to append a message to a file
+listing the new tag name and the programmer who created it, or send mail
+to a group of developers, or, perhaps, post a message to a particular
+newsgroup.
+.SP
+You can use the `\|rcsinfo\|' file to define forms for log messages.
+.SP
+You can use the `\|editinfo\|' file to define a program to execute for
+editing/validating `\|\fBcvs commit\fP\|' log entries.
+This is most useful when used with a `\|rcsinfo\|' forms specification, as
+it can verify that the proper fields of the form have been filled in by the
+user committing the change.
+.SP
+You can use the `\|cvsignore\|' file to specify the default list of
+files to ignore during \fBupdate\fP.
+.SP
+You can use the `\|history\|' file to record the \fBcvs\fP commands
+that affect the repository.
+The creation of this file enables history logging.
+.SH FILES
+.TP
+.B modules
+The `\|modules\|' file records your definitions of names for
+collections of source code. \fBcvs\fP will use these definitions if
+you create a file with the right format in
+`\|\fB$CVSROOT/CVSROOT/modules,v\fP\|'.
+The
+.BR mkmodules ( 1 )
+command should be run whenever the modules file changes, so that the
+appropriate files can be generated (depending on how you have configured
+.B cvs
+operation).
+.SP
+To allow convenient editing of the `\|modules\|' file itself, the file should
+include an entry like the following (where \fIlocalbin\fP represents the
+directory where your site installs programs like
+.BR mkmodules ( 1 )):
+.SP
+.nf
+\&\fBmodules \-i /\fP\fIlocalbin\fP\fB/mkmodules CVSROOT modules\fP
+.fi
+.SP
+This defines the name `\|\fBmodules\fP\|' as the module name for the
+file itself, so that you can use
+.SP
+.in +1i
+.ft B
+.nf
+example% cvs checkout modules
+.fi
+.ft P
+.in -1i
+.SP
+to get an editable copy of the file. You should define similar module
+entries for the other configuration files described here (except
+\&`\|history\|').
+The
+.BR cvsinit ( 8 )
+script will setup a smilar `\|modules\|' file for you automatically.
+.SP
+The `\|modules\|' file may contain blank lines and comments (lines
+beginning with `\|\fB#\fP\|') as well as module definitions.
+Long lines can be continued on the next line by specifying a backslash
+(``\e'') as the last character on the line.
+.SP
+A \fImodule definition\fP is a single line of the `\|modules\|' file,
+in either of two formats. In both cases, \fImname\fP represents the
+symbolic module name, and the remainder of the line is its definition.
+.SP
+\fImname\fP \fB\-a\fP \fIaliases\fP\|.\|.\|.
+.br
+This represents the simplest way of defining a module \fImname\fP.
+The `\|\fB\-a\fP\|' flags the definition as a simple alias: \fBcvs\fP
+will treat any use of \fImname\fP (as a command argument) as if the list
+of names \fIaliases\fP had been specified instead. \fIaliases\fP may
+contain either other module names or paths. When you use paths in
+\fIaliases\fP, `\|\fBcvs checkout\fP\|' creates all intermediate
+directories in the working directory, just as if the path had been
+specified explicitly in the \fBcvs\fP arguments.
+.SP
+.nf
+\fImname\fP [ \fIoptions\fP ] \fIdir\fP [ \fIfiles\fP\|.\|.\|. ] [ \fB&\fP\fImodule\fP\|.\|.\|. ]
+.fi
+.SP
+In the simplest case, this form of module definition reduces to
+`\|\fImname dir\fP\|'. This defines all the files in directory
+\fIdir\fP as module \fImname\fP. \fIdir\fP is a relative path (from
+\fB$CVSROOT\fP) to a directory of source in one of the source
+repositories. In this case, on \fBcheckout\fP, a single directory
+called \fImname\fP is created as a working directory; no intermediate
+directory levels are used by default, even if \fIdir\fP was a path
+involving several directory levels.
+.SP
+By explicitly specifying \fIfiles\fP in the module definition after
+\fIdir\fP, you can select particular files from directory
+\fIdir\fP. The sample definition for \fBmodules\fP is an example of
+a module defined with a single file from a particular directory. Here
+is another example:
+.SP
+.nf
+.ft B
+m4test unsupported/gnu/m4 foreach.m4 forloop.m4
+.ft P
+.fi
+.SP
+With this definition, executing `\|\fBcvs checkout m4test\fP\|'
+will create a single working directory `\|m4test\|' containing the two
+files listed, which both come from a common directory several levels
+deep in the \fBcvs\fP source repository.
+.SP
+A module definition can refer to other modules by including
+`\|\fB&\fP\fImodule\fP\|' in its definition. \fBcheckout\fP creates
+a subdirectory for each such \fImodule\fP, in your working directory.
+.br
+.I
+New in \fBcvs\fP 1.3;
+avoid this feature if sharing module definitions with older versions
+of \fBcvs\fP.
+.SP
+Finally, you can use one or more of the following \fIoptions\fP in
+module definitions:
+.SP
+\&`\|\fB\-d\fP \fIname\fP\|', to name the working directory something
+other than the module name.
+.br
+.I
+New in \fBcvs\fP 1.3;
+avoid this feature if sharing module definitions with older versions
+of \fBcvs\fP.
+.SP
+\&`\|\fB\-i\fP \fIprog\fP\|' allows you to specify a program \fIprog\fP
+to run whenever files in a module are committed. \fIprog\fP runs with a
+single argument, the full pathname of the affected directory in a
+source repository. The `\|commitinfo\|', `\|loginfo\|', and
+`\|editinfo\|' files provide other ways to call a program on \fBcommit\fP.
+.SP
+`\|\fB\-o\fP \fIprog\fP\|' allows you to specify a program \fIprog\fP
+to run whenever files in a module are checked out. \fIprog\fP runs
+with a single argument, the module name.
+.SP
+`\|\fB\-e\fP \fIprog\fP\|' allows you to specify a program \fIprog\fP
+to run whenever files in a module are exported. \fIprog\fP runs
+with a single argument, the module name.
+.SP
+`\|\fB\-t\fP \fIprog\fP\|' allows you to specify a program \fIprog\fP
+to run whenever files in a module are tagged. \fIprog\fP runs with two
+arguments: the module name and the symbolic tag specified to \fBrtag\fP.
+.SP
+`\|\fB\-u\fP \fIprog\fP\|' allows you to specify a program \fIprog\fP
+to run whenever `\|\fBcvs update\fP\|' is executed from the top-level
+directory of the checked-out module. \fIprog\fP runs with a
+single argument, the full path to the source repository for this module.
+.TP
+\&\fBcommitinfo\fP, \fBloginfo\fP, \fBrcsinfo\fP, \fBeditinfo\fP
+These files all specify programs to call at different points in the
+`\|\fBcvs commit\fP\|' process. They have a common structure.
+Each line is a pair of fields: a regular expression, separated by
+whitespace from a filename or command-line template.
+Whenever one of the regular expression matches a directory name in the
+repository, the rest of the line is used.
+If the line begins with a \fB#\fP character, the entire line is considered
+a comment and is ignored.
+Whitespace between the fields is also ignored.
+.SP
+For `\|loginfo\|', the rest of the
+line is a command-line template to execute.
+The templates can include not only
+a program name, but whatever list of arguments you wish. If you write
+`\|\fB%s\fP\|' somewhere on the argument list, \fBcvs\fP supplies, at
+that point, the list of files affected by the \fBcommit\fP.
+The first entry in the list is the relative path within the source
+repository where the change is being made.
+The remaining arguments list the files that are being modified, added, or
+removed by this \fBcommit\fP invocation.
+.SP
+For `\|taginfo\|', the rest of the
+line is a command-line template to execute.
+The arguments passed to the command are, in order, the
+.I tagname ,
+.I operation
+(i.e.
+.B add
+for `tag',
+.B mov
+for `tag -F', and
+.B del
+for `tag -d`),
+.I repository ,
+and any remaining are pairs of
+.B "filename revision" .
+A non-zero exit of the filter program will cause the tag to be aborted.
+.SP
+For `\|commitinfo\|', the rest of the line is a command-line template to
+execute.
+The template can include not only a program name, but whatever
+list of arguments you wish.
+The full path to the current source repository is appended to the template,
+followed by the file names of any files involved in the commit (added,
+removed, and modified files).
+.SP
+For `\|rcsinfo\|', the rest of the line is the full path to a file that
+should be loaded into the log message template.
+.SP
+For `\|editinfo\|', the rest of the line is a command-line template to
+execute.
+The template can include not only a program name, but whatever
+list of arguments you wish.
+The full path to the current log message template file is appended to the
+template.
+.SP
+You can use one of two special strings instead of a regular
+expression: `\|\fBALL\fP\|' specifies a command line template that
+must always be executed, and `\|\fBDEFAULT\fP\|' specifies a command
+line template to use if no regular expression is a match.
+.SP
+The `\|commitinfo\|' file contains commands to execute \fIbefore\fP any
+other \fBcommit\fP activity, to allow you to check any conditions that
+must be satisfied before \fBcommit\fP can proceed. The rest of the
+\fBcommit\fP will execute only if all selected commands from this file
+exit with exit status \fB0\fP.
+.SP
+The `\|rcsinfo\|' file allows you to specify \fIlog templates\fP for
+the \fBcommit\fP logging session; you can use this to provide a form
+to edit when filling out the \fBcommit\fP log. The field after the
+regular expression, in this file, contains filenames (of files
+containing the logging forms) rather than command templates.
+.SP
+The `\|editinfo\|' file allows you to execute a script \fIbefore the
+commit starts\fP, but after the log information is recorded. These
+"edit" scripts can verify information recorded in the log file. If
+the edit script exits wth a non-zero exit status, the commit is aborted.
+.SP
+The `\|loginfo\|' file contains commands to execute \fIat the end\fP
+of a commit. The text specified as a commit log message is piped
+through the command; typical uses include sending mail, filing an
+article in a newsgroup, or appending to a central file.
+.TP
+\&\fBcvsignore\fP, \fB.cvsignore\fP
+The default list of files (or
+.BR sh ( 1 )
+file name patterns) to ignore during `\|\fBcvs update\fP\|'.
+At startup time, \fBcvs\fP loads the compiled in default list of file name
+patterns (see
+.BR cvs ( 1 )).
+Then the per-repository list included in \fB$CVSROOT/CVSROOT/cvsignore\fP
+is loaded, if it exists.
+Then the per-user list is loaded from `\|$HOME/.cvsignore\|'.
+Finally, as \fBcvs\fP traverses through your directories, it will load any
+per-directory `\|.cvsignore\|' files whenever it finds one.
+These per-directory files are only valid for exactly the directory that
+contains them, not for any sub-directories.
+.TP
+.B history
+Create this file in \fB$CVSROOT/CVSROOT\fP to enable history logging
+(see the description of `\|\fBcvs history\fP\|').
+.SH "SEE ALSO"
+.BR cvs ( 1 ),
+.BR mkmodules ( 1 ).
+.SH COPYING
+Copyright \(co 1992 Cygnus Support, Brian Berliner, and Jeff Polk
+.PP
+Permission is granted to make and distribute verbatim copies of
+this manual provided the copyright notice and this permission notice
+are preserved on all copies.
+.PP
+Permission is granted to copy and distribute modified versions of this
+manual under the conditions for verbatim copying, provided that the
+entire resulting derived work is distributed under the terms of a
+permission notice identical to this one.
+.PP
+Permission is granted to copy and distribute translations of this
+manual into another language, under the above conditions for modified
+versions, except that this permission notice may be included in
+translations approved by the Free Software Foundation instead of in
+the original English.
diff --git a/gnu/usr.bin/cvs/cvs/cvs.h b/gnu/usr.bin/cvs/cvs/cvs.h
new file mode 100644
index 0000000..34c9d8c
--- /dev/null
+++ b/gnu/usr.bin/cvs/cvs/cvs.h
@@ -0,0 +1,570 @@
+/* $CVSid: @(#)cvs.h 1.86 94/10/22 $ */
+
+/*
+ * basic information used in all source files
+ *
+ */
+
+
+#include "config.h" /* this is stuff found via autoconf */
+#include "options.h" /* these are some larger questions which
+ can't easily be automatically checked
+ for */
+
+/* AIX requires this to be the first thing in the file. */
+#ifdef __GNUC__
+#define alloca __builtin_alloca
+#else /* not __GNUC__ */
+#if HAVE_ALLOCA_H
+#include <alloca.h>
+#else /* not HAVE_ALLOCA_H */
+#ifdef _AIX
+ #pragma alloca
+#else /* not _AIX */
+#ifdef ALLOCA_IN_STDLIB
+ /* then we need do nothing */
+#else
+char *alloca ();
+#endif /* not ALLOCA_IN_STDLIB */
+#endif /* not _AIX */
+#endif /* not HAVE_ALLOCA_H */
+#endif /* not __GNUC__ */
+
+/* Changed from if __STDC__ to ifdef __STDC__ because of Sun's acc compiler */
+
+#ifdef __STDC__
+#define PTR void *
+#else
+#define PTR char *
+#endif
+
+/* Add prototype support. */
+#ifndef PROTO
+#if defined (USE_PROTOTYPES) ? USE_PROTOTYPES : defined (__STDC__)
+#define PROTO(ARGS) ARGS
+#else
+#define PROTO(ARGS) ()
+#endif
+#endif
+
+#if __GNUC__ == 2
+#define USE(var) static const char sizeof##var = sizeof(sizeof##var) + sizeof(var)
+#else
+#define USE(var) static const char standalone_semis_illegal_sigh
+#endif
+
+
+#include <stdio.h>
+
+/* Under OS/2, <stdio.h> doesn't define popen()/pclose(). */
+#ifdef USE_OWN_POPEN
+#include "popen.h"
+#endif
+
+#ifdef STDC_HEADERS
+#include <stdlib.h>
+#else
+extern void exit ();
+extern char *getenv();
+#endif
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#ifdef HAVE_STRING_H
+#include <string.h>
+#else
+#include <strings.h>
+#endif
+
+#ifdef SERVER_SUPPORT
+/* If the system doesn't provide strerror, it won't be declared in
+ string.h. */
+char *strerror ();
+#endif
+
+#include <fnmatch.h> /* This is supposed to be available on Posix systems */
+
+#include <ctype.h>
+#include <pwd.h>
+#include <signal.h>
+
+#ifdef HAVE_ERRNO_H
+#include <errno.h>
+#else
+#ifndef errno
+extern int errno;
+#endif /* !errno */
+#endif /* HAVE_ERRNO_H */
+
+#include "system.h"
+
+#include "hash.h"
+#if defined(SERVER_SUPPORT) || defined(CLIENT_SUPPORT)
+#include "server.h"
+#include "client.h"
+#endif
+
+#ifdef AUTH_CLIENT_SUPPORT
+extern int use_authenticating_server;
+void connect_to_pserver();
+# ifndef CVS_AUTH_PORT
+# define CVS_AUTH_PORT 2401
+# endif /* CVS_AUTH_PORT */
+#endif /* AUTH_CLIENT_SUPPORT */
+
+#ifdef MY_NDBM
+#include "myndbm.h"
+#else
+#include <ndbm.h>
+#endif /* MY_NDBM */
+
+#include "regex.h"
+#include "getopt.h"
+#include "wait.h"
+
+/* Define to enable alternate death support (which uses the RCS state). */
+#define DEATH_STATE 1
+
+#define DEATH_SUPPORT 1
+
+#include "rcs.h"
+
+
+/* XXX - for now this is static */
+#ifndef PATH_MAX
+#ifdef MAXPATHLEN
+#define PATH_MAX MAXPATHLEN+2
+#else
+#define PATH_MAX 1024+2
+#endif
+#endif /* PATH_MAX */
+
+/* just in case this implementation does not define this */
+#ifndef L_tmpnam
+#define L_tmpnam 50
+#endif
+
+
+/*
+ * Copyright (c) 1992, Brian Berliner and Jeff Polk
+ * Copyright (c) 1989-1992, Brian Berliner
+ *
+ * You may distribute under the terms of the GNU General Public License as
+ * specified in the README file that comes with the CVS 1.4 kit.
+ *
+ * Definitions for the CVS Administrative directory and the files it contains.
+ * Here as #define's to make changing the names a simple task.
+ */
+#define CVSADM "CVS"
+#define CVSADM_ENT "CVS/Entries"
+#define CVSADM_ENTBAK "CVS/Entries.Backup"
+#define CVSADM_ENTLOG "CVS/Entries.Log"
+#define CVSADM_ENTSTAT "CVS/Entries.Static"
+#define CVSADM_REP "CVS/Repository"
+#define CVSADM_ROOT "CVS/Root"
+#define CVSADM_CIPROG "CVS/Checkin.prog"
+#define CVSADM_UPROG "CVS/Update.prog"
+#define CVSADM_TAG "CVS/Tag"
+
+/*
+ * Definitions for the CVSROOT Administrative directory and the files it
+ * contains. This directory is created as a sub-directory of the $CVSROOT
+ * environment variable, and holds global administration information for the
+ * entire source repository beginning at $CVSROOT.
+ */
+#define CVSROOTADM "CVSROOT"
+#define CVSROOTADM_MODULES "modules"
+#define CVSROOTADM_LOGINFO "loginfo"
+#define CVSROOTADM_RCSINFO "rcsinfo"
+#define CVSROOTADM_COMMITINFO "commitinfo"
+#define CVSROOTADM_TAGINFO "taginfo"
+#define CVSROOTADM_EDITINFO "editinfo"
+#define CVSROOTADM_HISTORY "history"
+#define CVSROOTADM_IGNORE "cvsignore"
+#define CVSROOTADM_CHECKOUTLIST "checkoutlist"
+#define CVSROOTADM_WRAPPER "cvswrappers"
+#define CVSNULLREPOS "Emptydir" /* an empty directory */
+
+/* support for the modules file (CVSROOTADM_MODULES) */
+#define CVSMODULE_OPTS "ad:i:lo:e:s:t:u:"/* options in modules file */
+#define CVSMODULE_SPEC '&' /* special delimiter */
+
+/* Other CVS file names */
+
+/* Files go in the attic if the head main branch revision is dead,
+ otherwise they go in the regular repository directories. The whole
+ concept of having an attic is sort of a relic from before death
+ support but on the other hand, it probably does help the speed of
+ some operations (such as main branch checkouts and updates). */
+#define CVSATTIC "Attic"
+
+#define CVSLCK "#cvs.lock"
+#define CVSTFL "#cvs.tfl"
+#define CVSRFL "#cvs.rfl"
+#define CVSWFL "#cvs.wfl"
+#define CVSRFLPAT "#cvs.rfl.*" /* wildcard expr to match read locks */
+#define CVSEXT_LOG ",t"
+#define CVSPREFIX ",,"
+#define CVSDOTIGNORE ".cvsignore"
+#define CVSDOTWRAPPER ".cvswrappers"
+
+/* miscellaneous CVS defines */
+#define CVSEDITPREFIX "CVS: "
+#define CVSLCKAGE (60*60) /* 1-hour old lock files cleaned up */
+#define CVSLCKSLEEP 30 /* wait 30 seconds before retrying */
+#define CVSBRANCH "1.1.1" /* RCS branch used for vendor srcs */
+#define BAKPREFIX ".#" /* when rcsmerge'ing */
+#ifndef DEVNULL
+#define DEVNULL "/dev/null"
+#endif
+
+#define FALSE 0
+#define TRUE 1
+
+/*
+ * Special tags. -rHEAD refers to the head of an RCS file, regardless of any
+ * sticky tags. -rBASE refers to the current revision the user has checked
+ * out This mimics the behaviour of RCS.
+ */
+#define TAG_HEAD "HEAD"
+#define TAG_BASE "BASE"
+
+/* Environment variable used by CVS */
+#define CVSREAD_ENV "CVSREAD" /* make files read-only */
+#define CVSREAD_DFLT FALSE /* writable files by default */
+
+#define RCSBIN_ENV "RCSBIN" /* RCS binary directory */
+/* #define RCSBIN_DFLT Set by config.h */
+
+#define EDITOR1_ENV "CVSEDITOR" /* which editor to use */
+#define EDITOR2_ENV "VISUAL" /* which editor to use */
+#define EDITOR3_ENV "EDITOR" /* which editor to use */
+/* #define EDITOR_DFLT Set by config.h */
+
+#define CVSROOT_ENV "CVSROOT" /* source directory root */
+#define CVSROOT_DFLT NULL /* No dflt; must set for checkout */
+
+#define IGNORE_ENV "CVSIGNORE" /* More files to ignore */
+#define WRAPPER_ENV "CVSWRAPPERS" /* name of the wrapper file */
+
+#define CVSUMASK_ENV "CVSUMASK" /* Effective umask for repository */
+/* #define CVSUMASK_DFLT Set by config.h */
+
+/*
+ * If the beginning of the Repository matches the following string, strip it
+ * so that the output to the logfile does not contain a full pathname.
+ *
+ * If the CVSROOT environment variable is set, it overrides this define.
+ */
+#define REPOS_STRIP "/master/"
+
+/*
+ * The maximum number of files per each CVS directory. This is mainly for
+ * sizing arrays statically rather than dynamically. 3000 seems plenty for
+ * now.
+ */
+#define MAXFILEPERDIR 3000
+#define MAXLINELEN 5000 /* max input line from a file */
+#define MAXPROGLEN 30000 /* max program length to system() */
+#define MAXLISTLEN 40000 /* For [A-Z]list holders */
+#define MAXDATELEN 50 /* max length for a date */
+
+/* structure of a entry record */
+struct entnode
+{
+ char *user;
+ char *version;
+ char *timestamp;
+ char *options;
+ char *tag;
+ char *date;
+ char *conflict;
+};
+typedef struct entnode Entnode;
+
+/* The type of request that is being done in do_module() */
+enum mtype
+{
+ CHECKOUT, TAG, PATCH, EXPORT
+};
+
+/*
+ * defines for Classify_File() to determine the current state of a file.
+ * These are also used as types in the data field for the list we make for
+ * Update_Logfile in commit, import, and add.
+ */
+enum classify_type
+{
+ T_UNKNOWN = 1, /* no old-style analog existed */
+ T_CONFLICT, /* C (conflict) list */
+ T_NEEDS_MERGE, /* G (needs merging) list */
+ T_MODIFIED, /* M (needs checked in) list */
+ T_CHECKOUT, /* O (needs checkout) list */
+ T_ADDED, /* A (added file) list */
+ T_REMOVED, /* R (removed file) list */
+ T_REMOVE_ENTRY, /* W (removed entry) list */
+ T_UPTODATE, /* File is up-to-date */
+#ifdef SERVER_SUPPORT
+ T_PATCH, /* P Like C, but can patch */
+#endif
+ T_TITLE /* title for node type */
+};
+typedef enum classify_type Ctype;
+
+/*
+ * a struct vers_ts contains all the information about a file including the
+ * user and rcs file names, and the version checked out and the head.
+ *
+ * this is usually obtained from a call to Version_TS which takes a tag argument
+ * for the RCS file if desired
+ */
+struct vers_ts
+{
+ char *vn_user; /* rcs version user file derives from
+ * it can have the following special
+ * values:
+ * empty = no user file
+ * 0 = user file is new
+ * -vers = user file to be removed */
+ char *vn_rcs; /* the version for the rcs file
+ * (tag version?) */
+ char *vn_tag; /* the symbolic tag name */
+ char *ts_user; /* the timestamp for the user file */
+ char *ts_rcs; /* the user timestamp from entries */
+ char *options; /* opts from Entries file
+ * (keyword expansion) */
+ char *ts_conflict; /* Holds time_stamp of conflict */
+ char *tag; /* tag stored in the Entries file */
+ char *date; /* date stored in the Entries file */
+ Entnode *entdata; /* pointer to entries file node */
+ RCSNode *srcfile; /* pointer to parsed src file info */
+};
+typedef struct vers_ts Vers_TS;
+
+/*
+ * structure used for list-private storage by Entries_Open() and
+ * Version_TS().
+ */
+struct stickydirtag
+{
+ int aflag;
+ char *tag;
+ char *date;
+ char *options;
+};
+
+/* Flags for find_{names,dirs} routines */
+#define W_LOCAL 0x01 /* look for files locally */
+#define W_REPOS 0x02 /* look for files in the repository */
+#define W_ATTIC 0x04 /* look for files in the attic */
+
+/* Flags for return values of direnter procs for the recursion processor */
+enum direnter_type
+{
+ R_PROCESS = 1, /* process files and maybe dirs */
+ R_SKIP_FILES, /* don't process files in this dir */
+ R_SKIP_DIRS, /* don't process sub-dirs */
+ R_SKIP_ALL /* don't process files or dirs */
+};
+typedef enum direnter_type Dtype;
+
+extern char *program_name, *program_path, *command_name;
+extern char *Rcsbin, *Editor, *CVSroot;
+#ifdef CVSADM_ROOT
+extern char *CVSADM_Root;
+extern int cvsadmin_root;
+#endif /* CVSADM_ROOT */
+extern char *CurDir;
+extern int really_quiet, quiet;
+extern int use_editor;
+extern int cvswrite;
+extern mode_t cvsumask;
+
+extern int trace; /* Show all commands */
+extern int noexec; /* Don't modify disk anywhere */
+extern int logoff; /* Don't write history entry */
+
+extern char hostname[];
+
+/* Externs that are included directly in the CVS sources */
+int RCS_settag PROTO((const char *, const char *, const char *));
+int RCS_deltag PROTO((const char *, const char *, int));
+int RCS_setbranch PROTO((const char *, const char *));
+int RCS_lock PROTO((const char *, const char *, int));
+int RCS_unlock PROTO((const char *, const char *, int));
+int RCS_merge PROTO((const char *, const char *, const char *, const char *));
+
+#include "error.h"
+
+DBM *open_module PROTO((void));
+FILE *open_file PROTO((const char *, const char *));
+List *Find_Dirs PROTO((char *repository, int which));
+void Entries_Close PROTO((List *entries));
+List *Entries_Open PROTO((int aflag));
+char *Make_Date PROTO((char *rawdate));
+char *Name_Repository PROTO((char *dir, char *update_dir));
+#ifdef CVSADM_ROOT
+char *Name_Root PROTO((char *dir, char *update_dir));
+void Create_Root PROTO((char *dir, char *rootdir));
+int same_directories PROTO((char *dir1, char *dir2));
+#endif /* CVSADM_ROOT */
+char *Short_Repository PROTO((char *repository));
+char *gca PROTO((char *rev1, char *rev2));
+char *getcaller PROTO((void));
+char *time_stamp PROTO((char *file));
+char *xmalloc PROTO((size_t bytes));
+char *xrealloc PROTO((char *ptr, size_t bytes));
+char *xstrdup PROTO((const char *str));
+void strip_trailing_newlines PROTO((char *str));
+int No_Difference PROTO((char *file, Vers_TS * vers, List * entries,
+ char *repository, char *update_dir));
+typedef int (*CALLPROC) PROTO((char *repository, char *value));
+int Parse_Info PROTO((char *infofile, char *repository, CALLPROC callproc, int all));
+int Reader_Lock PROTO((char *xrepository));
+typedef RETSIGTYPE (*SIGCLEANUPPROC) PROTO(());
+int SIG_register PROTO((int sig, SIGCLEANUPPROC sigcleanup));
+int Writer_Lock PROTO((List * list));
+int ign_name PROTO((char *name));
+int isdir PROTO((const char *file));
+int isfile PROTO((const char *file));
+int islink PROTO((const char *file));
+int isreadable PROTO((const char *file));
+int iswritable PROTO((const char *file));
+int isaccessible PROTO((const char *file, const int mode));
+int isabsolute PROTO((const char *filename));
+char *last_component PROTO((char *path));
+
+int joining PROTO((void));
+int numdots PROTO((const char *s));
+int unlink_file PROTO((const char *f));
+int unlink_file_dir PROTO((const char *f));
+int update PROTO((int argc, char *argv[]));
+int xcmp PROTO((const char *file1, const char *file2));
+int yesno PROTO((void));
+void *valloc PROTO((size_t bytes));
+time_t get_date PROTO((char *date, struct timeb *now));
+void Create_Admin PROTO((char *dir, char *update_dir,
+ char *repository, char *tag, char *date));
+void Lock_Cleanup PROTO((void));
+void ParseTag PROTO((char **tagp, char **datep));
+void Scratch_Entry PROTO((List * list, char *fname));
+void WriteTag PROTO((char *dir, char *tag, char *date));
+void cat_module PROTO((int status));
+void check_entries PROTO((char *dir));
+void close_module PROTO((DBM * db));
+void copy_file PROTO((const char *from, const char *to));
+void (*error_set_cleanup PROTO((void (*) (void)))) PROTO ((void));
+void fperror PROTO((FILE * fp, int status, int errnum, char *message,...));
+void free_names PROTO((int *pargc, char *argv[]));
+void freevers_ts PROTO((Vers_TS ** versp));
+void ign_add PROTO((char *ign, int hold));
+void ign_add_file PROTO((char *file, int hold));
+void ign_setup PROTO((void));
+void ign_dir_add PROTO((char *name));
+int ignore_directory PROTO((char *name));
+void line2argv PROTO((int *pargc, char *argv[], char *line));
+void make_directories PROTO((const char *name));
+void make_directory PROTO((const char *name));
+void rename_file PROTO((const char *from, const char *to));
+void strip_path PROTO((char *path));
+void strip_trailing_slashes PROTO((char *path));
+void update_delproc PROTO((Node * p));
+void usage PROTO((const char *const *cpp));
+void xchmod PROTO((char *fname, int writable));
+char *xgetwd PROTO((void));
+int Checkin PROTO((int type, char *file, char *update_dir,
+ char *repository, char *rcs, char *rev,
+ char *tag, char *options, char *message, List *entries));
+Ctype Classify_File PROTO((char *file, char *tag, char *date, char *options,
+ int force_tag_match, int aflag, char *repository,
+ List *entries, List *srcfiles, Vers_TS **versp,
+ char *update_dir, int pipeout));
+List *Find_Names PROTO((char *repository, int which, int aflag,
+ List ** optentries));
+void Register PROTO((List * list, char *fname, char *vn, char *ts,
+ char *options, char *tag, char *date, char *ts_conflict));
+void Update_Logfile PROTO((char *repository, char *xmessage, char *xrevision,
+ FILE * xlogfp, List * xchanges));
+Vers_TS *Version_TS PROTO((char *repository, char *options, char *tag,
+ char *date, char *user, int force_tag_match,
+ int set_time, List * entries, List * xfiles));
+void do_editor PROTO((char *dir, char **messagep,
+ char *repository, List * changes));
+
+typedef int (*CALLBACKPROC) PROTO((int *pargc, char *argv[], char *where,
+ char *mwhere, char *mfile, int horten, int local_specified,
+ char *omodule, char *msg));
+typedef int (*FILEPROC) PROTO((char *file, char *update_dir, char *repository,
+ List * entries, List * srcfiles));
+typedef int (*FILESDONEPROC) PROTO((int err, char *repository, char *update_dir));
+typedef Dtype (*DIRENTPROC) PROTO((char *dir, char *repos, char *update_dir));
+typedef int (*DIRLEAVEPROC) PROTO((char *dir, int err, char *update_dir));
+
+int do_module PROTO((DBM * db, char *mname, enum mtype m_type, char *msg,
+ CALLBACKPROC callback_proc, char *where, int shorten,
+ int local_specified, int run_module_prog, char *extra_arg));
+int do_recursion PROTO((FILEPROC xfileproc, FILESDONEPROC xfilesdoneproc,
+ DIRENTPROC xdirentproc, DIRLEAVEPROC xdirleaveproc,
+ Dtype xflags, int xwhich, int xaflag, int xreadlock,
+ int xdosrcs));
+int do_update PROTO((int argc, char *argv[], char *xoptions, char *xtag,
+ char *xdate, int xforce, int local, int xbuild,
+ int xaflag, int xprune, int xpipeout, int which,
+ char *xjoin_rev1, char *xjoin_rev2, char *preload_update_dir));
+void history_write PROTO((int type, char *update_dir, char *revs, char *name,
+ char *repository));
+int start_recursion PROTO((FILEPROC fileproc, FILESDONEPROC filesdoneproc,
+ DIRENTPROC direntproc, DIRLEAVEPROC dirleaveproc,
+ int argc, char *argv[], int local, int which,
+ int aflag, int readlock, char *update_preload,
+ int dosrcs, int wd_is_repos));
+void SIG_beginCrSect PROTO((void));
+void SIG_endCrSect PROTO((void));
+void read_cvsrc PROTO((int *argc, char ***argv));
+
+char *make_message_rcslegal PROTO((char *message));
+
+/* flags for run_exec(), the fast system() for CVS */
+#define RUN_NORMAL 0x0000 /* no special behaviour */
+#define RUN_COMBINED 0x0001 /* stdout is duped to stderr */
+#define RUN_REALLY 0x0002 /* do the exec, even if noexec is on */
+#define RUN_STDOUT_APPEND 0x0004 /* append to stdout, don't truncate */
+#define RUN_STDERR_APPEND 0x0008 /* append to stderr, don't truncate */
+#define RUN_SIGIGNORE 0x0010 /* ignore interrupts for command */
+#define RUN_TTY (char *)0 /* for the benefit of lint */
+
+void run_arg PROTO((const char *s));
+void run_print PROTO((FILE * fp));
+#ifdef HAVE_VPRINTF
+void run_setup PROTO((const char *fmt,...));
+void run_args PROTO((const char *fmt,...));
+#else
+void run_setup ();
+void run_args ();
+#endif
+int run_exec PROTO((char *stin, char *stout, char *sterr, int flags));
+
+/* other similar-minded stuff from run.c. */
+FILE *Popen PROTO((const char *, const char *));
+int piped_child PROTO((char **, int *, int *));
+void close_on_exec PROTO((int));
+int filter_stream_through_program PROTO((int, int, char **, pid_t *));
+
+pid_t waitpid PROTO((pid_t, int *, int));
+
+/* Wrappers. */
+
+typedef enum { WRAP_MERGE, WRAP_COPY } WrapMergeMethod;
+typedef enum { WRAP_TOCVS, WRAP_FROMCVS, WRAP_CONFLICT } WrapMergeHas;
+
+void wrap_setup PROTO((void));
+int wrap_name_has PROTO((const char *name,WrapMergeHas has));
+char *wrap_tocvs_process_file PROTO((const char *fileName));
+int wrap_merge_is_copy PROTO((const char *fileName));
+char *wrap_fromcvs_process_file PROTO((const char *fileName));
+/* Pathname expansion */
+char *expand_path PROTO((char *name));
+void wrap_add_file PROTO((const char *file,int temp));
+void wrap_add PROTO((char *line,int temp));
diff --git a/gnu/usr.bin/cvs/cvs/cvsrc.c b/gnu/usr.bin/cvs/cvs/cvsrc.c
new file mode 100644
index 0000000..5882afc
--- /dev/null
+++ b/gnu/usr.bin/cvs/cvs/cvsrc.c
@@ -0,0 +1,151 @@
+/*
+ * Copyright (c) 1993 david d zuhn
+ *
+ * written by david d `zoo' zuhn while at Cygnus Support
+ *
+ * You may distribute under the terms of the GNU General Public License
+ * as specified in the README file that comes with the CVS 1.4 kit.
+ *
+ */
+
+
+#include "cvs.h"
+#include "getline.h"
+
+#ifndef lint
+static const char rcsid[] = "$CVSid: @(#)cvsrc.c 1.9 94/09/30 $";
+USE(rcsid);
+#endif /* lint */
+
+/* this file is to be found in the user's home directory */
+
+#ifndef CVSRC_FILENAME
+#define CVSRC_FILENAME ".cvsrc"
+#endif
+char cvsrc[] = CVSRC_FILENAME;
+
+#define GROW 10
+
+extern char *strtok ();
+
+void
+read_cvsrc (argc, argv)
+ int *argc;
+ char ***argv;
+{
+ char *homedir;
+ char *homeinit;
+ FILE *cvsrcfile;
+
+ char *line;
+ int line_length;
+ size_t line_chars_allocated;
+
+ char *optstart;
+
+ int command_len;
+ int found = 0;
+
+ int i;
+
+ int new_argc;
+ int max_new_argv;
+ char **new_argv;
+
+ /* don't do anything if argc is -1, since that implies "help" mode */
+ if (*argc == -1)
+ return;
+
+ /* setup the new options list */
+
+ new_argc = 1;
+ max_new_argv = (*argc) + GROW;
+ new_argv = (char **) xmalloc (max_new_argv * sizeof (char*));
+ new_argv[0] = xstrdup ((*argv)[0]);
+
+ /* determine filename for ~/.cvsrc */
+
+ homedir = getenv ("HOME");
+ if (!homedir)
+ return;
+
+ homeinit = (char *) xmalloc (strlen (homedir) + strlen (cvsrc) + 10);
+ strcpy (homeinit, homedir);
+ strcat (homeinit, "/");
+ strcat (homeinit, cvsrc);
+
+ /* if it can't be read, there's no point to continuing */
+
+ if (!isreadable (homeinit))
+ {
+ free (homeinit);
+ return;
+ }
+
+ /* now scan the file until we find the line for the command in question */
+
+ line = NULL;
+ line_chars_allocated = 0;
+ command_len = strlen (command_name);
+ cvsrcfile = open_file (homeinit, "r");
+ while ((line_length = getline (&line, &line_chars_allocated, cvsrcfile))
+ >= 0)
+ {
+ /* skip over comment lines */
+ if (line[0] == '#')
+ continue;
+
+ /* stop if we match the current command */
+ if (!strncmp (line, command_name, command_len)
+ && isspace (*(line + command_len)))
+ {
+ found = 1;
+ break;
+ }
+ }
+
+ fclose (cvsrcfile);
+
+ if (found)
+ {
+ /* skip over command in the options line */
+ optstart = strtok (line + command_len, "\t \n");
+
+ do
+ {
+ new_argv [new_argc] = xstrdup (optstart);
+ new_argv [new_argc+1] = NULL;
+ new_argc += 1;
+
+ if (new_argc >= max_new_argv)
+ {
+ char **tmp_argv;
+ max_new_argv += GROW;
+ tmp_argv = (char **) xmalloc (max_new_argv * sizeof (char*));
+ for (i = 0; i <= new_argc; i++)
+ tmp_argv[i] = new_argv[i];
+ free(new_argv);
+ new_argv = tmp_argv;
+ }
+
+ }
+ while ((optstart = strtok (NULL, "\t \n")) != NULL);
+ }
+
+ if (line != NULL)
+ free (line);
+
+ /* now copy the remaining arguments */
+
+ for (i=1; i < *argc; i++)
+ {
+ new_argv [new_argc] = (*argv)[i];
+ new_argc += 1;
+ }
+
+ *argc = new_argc;
+ *argv = new_argv;
+
+ free (homeinit);
+ return;
+}
diff --git a/gnu/usr.bin/cvs/cvs/diff.c b/gnu/usr.bin/cvs/cvs/diff.c
new file mode 100644
index 0000000..22fda75
--- /dev/null
+++ b/gnu/usr.bin/cvs/cvs/diff.c
@@ -0,0 +1,633 @@
+/*
+ * Copyright (c) 1992, Brian Berliner and Jeff Polk
+ * Copyright (c) 1989-1992, Brian Berliner
+ *
+ * You may distribute under the terms of the GNU General Public License as
+ * specified in the README file that comes with the CVS 1.4 kit.
+ *
+ * Difference
+ *
+ * Run diff against versions in the repository. Options that are specified are
+ * passed on directly to "rcsdiff".
+ *
+ * Without any file arguments, runs diff against all the currently modified
+ * files.
+ */
+
+#include "cvs.h"
+
+#ifndef lint
+static const char rcsid[] = "$CVSid: @(#)diff.c 1.61 94/10/22 $";
+USE(rcsid);
+#endif
+
+static Dtype diff_dirproc PROTO((char *dir, char *pos_repos, char *update_dir));
+static int diff_filesdoneproc PROTO((int err, char *repos, char *update_dir));
+static int diff_dirleaveproc PROTO((char *dir, int err, char *update_dir));
+static int diff_file_nodiff PROTO((char *file, char *repository, List *entries,
+ List *srcfiles, Vers_TS *vers));
+static int diff_fileproc PROTO((char *file, char *update_dir, char *repository,
+ List * entries, List * srcfiles));
+static void diff_mark_errors PROTO((int err));
+
+static char *diff_rev1, *diff_rev2;
+static char *diff_date1, *diff_date2;
+static char *use_rev1, *use_rev2;
+
+#ifdef SERVER_SUPPORT
+/* Revision of the user file, if it is unchanged from something in the
+ repository and we want to use that fact. */
+static char *user_file_rev;
+#endif
+
+static char *options;
+static char opts[PATH_MAX];
+static int diff_errors;
+static int empty_files = 0;
+
+static const char *const diff_usage[] =
+{
+ "Usage: %s %s [-lN] [rcsdiff-options]\n",
+#ifdef CVS_DIFFDATE
+ " [[-r rev1 | -D date1] [-r rev2 | -D date2]] [files...] \n",
+#else
+ " [-r rev1 [-r rev2]] [files...] \n",
+#endif
+ "\t-l\tLocal directory only, not recursive\n",
+ "\t-D d1\tDiff revision for date against working file.\n",
+ "\t-D d2\tDiff rev1/date1 against date2.\n",
+ "\t-N\tinclude diffs for added and removed files.\n",
+ "\t-r rev1\tDiff revision for rev1 against working file.\n",
+ "\t-r rev2\tDiff rev1/date1 against rev2.\n",
+ NULL
+};
+
+int
+diff (argc, argv)
+ int argc;
+ char **argv;
+{
+ char tmp[50];
+ int c, err = 0;
+ int local = 0;
+ int which;
+
+ if (argc == -1)
+ usage (diff_usage);
+
+ /*
+ * Note that we catch all the valid arguments here, so that we can
+ * intercept the -r arguments for doing revision diffs; and -l/-R for a
+ * non-recursive/recursive diff.
+ */
+#ifdef SERVER_SUPPORT
+ /* Need to be able to do this command more than once (according to
+ the protocol spec, even if the current client doesn't use it). */
+ opts[0] = '\0';
+#endif
+ optind = 1;
+ while ((c = getopt (argc, argv,
+ "abcdefhilnpqtuw0123456789BHNQRTC:D:F:I:L:V:k:r:")) != -1)
+ {
+ switch (c)
+ {
+ case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
+ case 'h': case 'i': case 'n': case 'p': case 't': case 'u':
+ case 'w': case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9': case 'B':
+ case 'H': case 'T': case 'Q':
+ (void) sprintf (tmp, " -%c", (char) c);
+ (void) strcat (opts, tmp);
+ if (c == 'Q')
+ {
+ quiet = 1;
+ really_quiet = 1;
+ c = 'q';
+ }
+ break;
+ case 'C': case 'F': case 'I': case 'L': case 'V':
+#ifndef CVS_DIFFDATE
+ case 'D':
+#endif
+ (void) sprintf (tmp, " -%c%s", (char) c, optarg);
+ (void) strcat (opts, tmp);
+ break;
+ case 'R':
+ local = 0;
+ break;
+ case 'l':
+ local = 1;
+ break;
+ case 'q':
+ quiet = 1;
+ break;
+ case 'k':
+ if (options)
+ free (options);
+ options = RCS_check_kflag (optarg);
+ break;
+ case 'r':
+ if (diff_rev2 != NULL || diff_date2 != NULL)
+ error (1, 0,
+ "no more than two revisions/dates can be specified");
+ if (diff_rev1 != NULL || diff_date1 != NULL)
+ diff_rev2 = optarg;
+ else
+ diff_rev1 = optarg;
+ break;
+#ifdef CVS_DIFFDATE
+ case 'D':
+ if (diff_rev2 != NULL || diff_date2 != NULL)
+ error (1, 0,
+ "no more than two revisions/dates can be specified");
+ if (diff_rev1 != NULL || diff_date1 != NULL)
+ diff_date2 = Make_Date (optarg);
+ else
+ diff_date1 = Make_Date (optarg);
+ break;
+#endif
+ case 'N':
+ empty_files = 1;
+ break;
+ case '?':
+ default:
+ usage (diff_usage);
+ break;
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+ /* make sure options is non-null */
+ if (!options)
+ options = xstrdup ("");
+
+#ifdef CLIENT_SUPPORT
+ if (client_active) {
+ /* We're the client side. Fire up the remote server. */
+ start_server ();
+
+ ign_setup ();
+
+ if (local)
+ send_arg("-l");
+ if (empty_files)
+ send_arg("-N");
+ send_option_string (opts);
+ if (diff_rev1)
+ option_with_arg ("-r", diff_rev1);
+ if (diff_date1)
+ client_senddate (diff_date1);
+ if (diff_rev2)
+ option_with_arg ("-r", diff_rev2);
+ if (diff_date2)
+ client_senddate (diff_date2);
+
+#if 0
+/* FIXME: We shouldn't have to send current files to diff two revs, but it
+ doesn't work yet and I haven't debugged it. So send the files --
+ it's slower but it works. gnu@cygnus.com Apr94 */
+
+/* Idea: often times the changed region of a file is relatively small.
+ It would be cool if the client could just divide the file into 4k
+ blocks or whatever and send hash values for the blocks. Send hash
+ values for blocks aligned with the beginning of the file and the
+ end of the file. Then the server can tell how much of the head and
+ tail of the file is unchanged. Well, hash collisions will screw
+ things up, but MD5 has 128 bits of hash value... */
+
+ /* Send the current files unless diffing two revs from the archive */
+ if (diff_rev2 == NULL && diff_date2 == NULL)
+ send_files (argc, argv, local);
+ else
+ send_file_names (argc, argv);
+#else
+ send_files (argc, argv, local, 0);
+#endif
+
+ if (fprintf (to_server, "diff\n") < 0)
+ error (1, errno, "writing to server");
+ err = get_responses_and_close ();
+ free (options);
+ return (err);
+ }
+#endif
+
+ which = W_LOCAL;
+ if (diff_rev2 != NULL || diff_date2 != NULL)
+ which |= W_REPOS | W_ATTIC;
+
+ wrap_setup ();
+
+ /* start the recursion processor */
+ err = start_recursion (diff_fileproc, diff_filesdoneproc, diff_dirproc,
+ diff_dirleaveproc, argc, argv, local,
+ which, 0, 1, (char *) NULL, 1, 0);
+
+ /* clean up */
+ free (options);
+ return (err);
+}
+
+/*
+ * Do a file diff
+ */
+/* ARGSUSED */
+static int
+diff_fileproc (file, update_dir, repository, entries, srcfiles)
+ char *file;
+ char *update_dir;
+ char *repository;
+ List *entries;
+ List *srcfiles;
+{
+ int status, err = 2; /* 2 == trouble, like rcsdiff */
+ Vers_TS *vers;
+ enum {
+ DIFF_ERROR,
+ DIFF_ADDED,
+ DIFF_REMOVED,
+ DIFF_NEITHER
+ } empty_file = DIFF_NEITHER;
+ char tmp[L_tmpnam+1];
+ char *tocvsPath;
+ char fname[PATH_MAX];
+
+#ifdef SERVER_SUPPORT
+ user_file_rev = 0;
+#endif
+ vers = Version_TS (repository, (char *) NULL, (char *) NULL, (char *) NULL,
+ file, 1, 0, entries, srcfiles);
+
+ if (diff_rev2 != NULL || diff_date2 != NULL)
+ {
+ /* Skip all the following checks regarding the user file; we're
+ not using it. */
+ }
+ else if (vers->vn_user == NULL)
+ {
+ error (0, 0, "I know nothing about %s", file);
+ freevers_ts (&vers);
+ diff_mark_errors (err);
+ return (err);
+ }
+ else if (vers->vn_user[0] == '0' && vers->vn_user[1] == '\0')
+ {
+ if (empty_files)
+ empty_file = DIFF_ADDED;
+ else
+ {
+ error (0, 0, "%s is a new entry, no comparison available", file);
+ freevers_ts (&vers);
+ diff_mark_errors (err);
+ return (err);
+ }
+ }
+ else if (vers->vn_user[0] == '-')
+ {
+ if (empty_files)
+ empty_file = DIFF_REMOVED;
+ else
+ {
+ error (0, 0, "%s was removed, no comparison available", file);
+ freevers_ts (&vers);
+ diff_mark_errors (err);
+ return (err);
+ }
+ }
+ else
+ {
+ if (vers->vn_rcs == NULL && vers->srcfile == NULL)
+ {
+ error (0, 0, "cannot find revision control file for %s", file);
+ freevers_ts (&vers);
+ diff_mark_errors (err);
+ return (err);
+ }
+ else
+ {
+ if (vers->ts_user == NULL)
+ {
+ error (0, 0, "cannot find %s", file);
+ freevers_ts (&vers);
+ diff_mark_errors (err);
+ return (err);
+ }
+#ifdef SERVER_SUPPORT
+ else if (!strcmp (vers->ts_user, vers->ts_rcs))
+ {
+ /* The user file matches some revision in the repository
+ Diff against the repository (for remote CVS, we might not
+ have a copy of the user file around). */
+ user_file_rev = vers->vn_user;
+ }
+#endif
+ }
+ }
+
+ if (empty_file == DIFF_NEITHER && diff_file_nodiff (file, repository, entries, srcfiles, vers))
+ {
+ freevers_ts (&vers);
+ return (0);
+ }
+
+#ifdef DEATH_SUPPORT
+ /* FIXME: Check whether use_rev1 and use_rev2 are dead and deal
+ accordingly. */
+#endif
+
+ /* Output an "Index:" line for patch to use */
+ (void) fflush (stdout);
+ if (update_dir[0])
+ (void) printf ("Index: %s/%s\n", update_dir, file);
+ else
+ (void) printf ("Index: %s\n", file);
+ (void) fflush (stdout);
+
+ tocvsPath = wrap_tocvs_process_file(file);
+ if (tocvsPath)
+ {
+ /* Backup the current version of the file to CVS/,,filename */
+ sprintf(fname,"%s/%s%s",CVSADM, CVSPREFIX, file);
+ if (unlink_file_dir (fname) < 0)
+ if (! existence_error (errno))
+ error (1, errno, "cannot remove %s", file);
+ rename_file (file, fname);
+ /* Copy the wrapped file to the current directory then go to work */
+ copy_file (tocvsPath, file);
+ }
+
+ if (empty_file == DIFF_ADDED || empty_file == DIFF_REMOVED)
+ {
+ (void) printf ("===================================================================\nRCS file: %s\n",
+ file);
+ (void) printf ("diff -N %s\n", file);
+
+ if (empty_file == DIFF_ADDED)
+ {
+ run_setup ("%s %s %s %s", DIFF, opts, DEVNULL, file);
+ }
+ else
+ {
+ /*
+ * FIXME: Should be setting use_rev1 using the logic in
+ * diff_file_nodiff, and using that revision. This code
+ * is broken for "cvs diff -N -r foo".
+ */
+ run_setup ("%s%s -p -q %s -r%s", Rcsbin, RCS_CO,
+ *options ? options : vers->options, vers->vn_rcs);
+ run_arg (vers->srcfile->path);
+ if (run_exec (RUN_TTY, tmpnam (tmp), RUN_TTY, RUN_REALLY) == -1)
+ {
+ (void) unlink (tmp);
+ error (1, errno, "fork failed during checkout of %s",
+ vers->srcfile->path);
+ }
+
+ run_setup ("%s %s %s %s", DIFF, opts, tmp, DEVNULL);
+ }
+ }
+ else
+ {
+ if (use_rev2)
+ {
+ run_setup ("%s%s %s %s -r%s -r%s", Rcsbin, RCS_DIFF,
+ opts, *options ? options : vers->options,
+ use_rev1, use_rev2);
+ }
+ else
+ {
+ run_setup ("%s%s %s %s -r%s", Rcsbin, RCS_DIFF, opts,
+ *options ? options : vers->options, use_rev1);
+ }
+ run_arg (vers->srcfile->path);
+ }
+
+ switch ((status = run_exec (RUN_TTY, RUN_TTY, RUN_TTY,
+ RUN_REALLY|RUN_COMBINED)))
+ {
+ case -1: /* fork failed */
+ error (1, errno, "fork failed during rcsdiff of %s",
+ vers->srcfile->path);
+ case 0: /* everything ok */
+ err = 0;
+ break;
+ default: /* other error */
+ err = status;
+ break;
+ }
+
+ if (tocvsPath)
+ {
+ if (unlink_file_dir (file) < 0)
+ if (! existence_error (errno))
+ error (1, errno, "cannot remove %s", file);
+
+ rename_file (fname,file);
+ if (unlink_file (tocvsPath) < 0)
+ error (1, errno, "cannot remove %s", file);
+ }
+
+ if (empty_file == DIFF_REMOVED)
+ (void) unlink (tmp);
+
+ (void) fflush (stdout);
+ freevers_ts (&vers);
+ diff_mark_errors (err);
+ return (err);
+}
+
+/*
+ * Remember the exit status for each file.
+ */
+static void
+diff_mark_errors (err)
+ int err;
+{
+ if (err > diff_errors)
+ diff_errors = err;
+}
+
+/*
+ * Print a warm fuzzy message when we enter a dir
+ *
+ * Don't try to diff directories that don't exist! -- DW
+ */
+/* ARGSUSED */
+static Dtype
+diff_dirproc (dir, pos_repos, update_dir)
+ char *dir;
+ char *pos_repos;
+ char *update_dir;
+{
+ /* XXX - check for dirs we don't want to process??? */
+
+ /* YES ... for instance dirs that don't exist!!! -- DW */
+ if (!isdir (dir) )
+ return (R_SKIP_ALL);
+
+ if (!quiet)
+ error (0, 0, "Diffing %s", update_dir);
+ return (R_PROCESS);
+}
+
+/*
+ * Concoct the proper exit status - done with files
+ */
+/* ARGSUSED */
+static int
+diff_filesdoneproc (err, repos, update_dir)
+ int err;
+ char *repos;
+ char *update_dir;
+{
+ return (diff_errors);
+}
+
+/*
+ * Concoct the proper exit status - leaving directories
+ */
+/* ARGSUSED */
+static int
+diff_dirleaveproc (dir, err, update_dir)
+ char *dir;
+ int err;
+ char *update_dir;
+{
+ return (diff_errors);
+}
+
+/*
+ * verify that a file is different 0=same 1=different
+ */
+static int
+diff_file_nodiff (file, repository, entries, srcfiles, vers)
+ char *file;
+ char *repository;
+ List *entries;
+ List *srcfiles;
+ Vers_TS *vers;
+{
+ Vers_TS *xvers;
+ char tmp[L_tmpnam+1];
+
+ /* free up any old use_rev* variables and reset 'em */
+ if (use_rev1)
+ free (use_rev1);
+ if (use_rev2)
+ free (use_rev2);
+ use_rev1 = use_rev2 = (char *) NULL;
+
+ if (diff_rev1 || diff_date1)
+ {
+ /* special handling for TAG_HEAD */
+ if (diff_rev1 && strcmp (diff_rev1, TAG_HEAD) == 0)
+ use_rev1 = xstrdup (vers->vn_rcs);
+ else
+ {
+ xvers = Version_TS (repository, (char *) NULL, diff_rev1,
+ diff_date1, file, 1, 0, entries, srcfiles);
+ if (xvers->vn_rcs == NULL)
+ {
+ /* Don't gripe if it doesn't exist, just ignore! */
+ if (! isfile (file))
+ /* null statement */ ;
+ else if (diff_rev1)
+ error (0, 0, "tag %s is not in file %s", diff_rev1, file);
+ else
+ error (0, 0, "no revision for date %s in file %s",
+ diff_date1, file);
+ return (1);
+ }
+ use_rev1 = xstrdup (xvers->vn_rcs);
+ freevers_ts (&xvers);
+ }
+ }
+ if (diff_rev2 || diff_date2)
+ {
+ /* special handling for TAG_HEAD */
+ if (diff_rev2 && strcmp (diff_rev2, TAG_HEAD) == 0)
+ use_rev2 = xstrdup (vers->vn_rcs);
+ else
+ {
+ xvers = Version_TS (repository, (char *) NULL, diff_rev2,
+ diff_date2, file, 1, 0, entries, srcfiles);
+ if (xvers->vn_rcs == NULL)
+ {
+ /* Don't gripe if it doesn't exist, just ignore! */
+ if (! isfile (file))
+ /* null statement */ ;
+ else if (diff_rev1)
+ error (0, 0, "tag %s is not in file %s", diff_rev2, file);
+ else
+ error (0, 0, "no revision for date %s in file %s",
+ diff_date2, file);
+ return (1);
+ }
+ use_rev2 = xstrdup (xvers->vn_rcs);
+ freevers_ts (&xvers);
+ }
+
+ /* now, see if we really need to do the diff */
+ if (use_rev1 && use_rev2) {
+ return (strcmp (use_rev1, use_rev2) == 0);
+ } else {
+ error(0, 0, "No HEAD revision for file %s", file);
+ return (1);
+ }
+ }
+#ifdef SERVER_SUPPORT
+ if (user_file_rev)
+ {
+ /* drop user_file_rev into first unused use_rev */
+ if (!use_rev1)
+ use_rev1 = xstrdup (user_file_rev);
+ else if (!use_rev2)
+ use_rev2 = xstrdup (user_file_rev);
+ /* and if not, it wasn't needed anyhow */
+ user_file_rev = 0;
+ }
+
+ /* now, see if we really need to do the diff */
+ if (use_rev1 && use_rev2)
+ {
+ return (strcmp (use_rev1, use_rev2) == 0);
+ }
+#endif /* SERVER_SUPPORT */
+ if (use_rev1 == NULL || strcmp (use_rev1, vers->vn_user) == 0)
+ {
+ if (strcmp (vers->ts_rcs, vers->ts_user) == 0 &&
+ (!(*options) || strcmp (options, vers->options) == 0))
+ {
+ return (1);
+ }
+ if (use_rev1 == NULL)
+ use_rev1 = xstrdup (vers->vn_user);
+ }
+
+ /*
+ * with 0 or 1 -r option specified, run a quick diff to see if we
+ * should bother with it at all.
+ */
+ run_setup ("%s%s -p -q %s -r%s", Rcsbin, RCS_CO,
+ *options ? options : vers->options, use_rev1);
+ run_arg (vers->srcfile->path);
+ switch (run_exec (RUN_TTY, tmpnam (tmp), RUN_TTY, RUN_REALLY))
+ {
+ case 0: /* everything ok */
+ if (xcmp (file, tmp) == 0)
+ {
+ (void) unlink (tmp);
+ return (1);
+ }
+ break;
+ case -1: /* fork failed */
+ (void) unlink (tmp);
+ error (1, errno, "fork failed during checkout of %s",
+ vers->srcfile->path);
+ default:
+ break;
+ }
+ (void) unlink (tmp);
+ return (0);
+}
diff --git a/gnu/usr.bin/cvs/cvs/entries.c b/gnu/usr.bin/cvs/cvs/entries.c
new file mode 100644
index 0000000..7ae3e58
--- /dev/null
+++ b/gnu/usr.bin/cvs/cvs/entries.c
@@ -0,0 +1,555 @@
+/*
+ * Copyright (c) 1992, Brian Berliner and Jeff Polk
+ * Copyright (c) 1989-1992, Brian Berliner
+ *
+ * You may distribute under the terms of the GNU General Public License as
+ * specified in the README file that comes with the CVS 1.4 kit.
+ *
+ * Entries file to Files file
+ *
+ * Creates the file Files containing the names that comprise the project, from
+ * the Entries file.
+ */
+
+#include "cvs.h"
+#include "getline.h"
+
+#ifndef lint
+static const char rcsid[] = "$CVSid: @(#)entries.c 1.44 94/10/07 $";
+USE(rcsid);
+#endif
+
+static Node *AddEntryNode PROTO((List * list, Entnode *entnode));
+
+static Entnode *fgetentent PROTO((FILE *));
+static int fputentent PROTO((FILE *, Entnode *));
+
+static FILE *entfile;
+static char *entfilename; /* for error messages */
+
+/*
+ * Construct an Entnode
+ */
+Entnode *
+Entnode_Create(user, vn, ts, options, tag, date, ts_conflict)
+ const char *user;
+ const char *vn;
+ const char *ts;
+ const char *options;
+ const char *tag;
+ const char *date;
+ const char *ts_conflict;
+{
+ Entnode *ent;
+
+ /* Note that timestamp and options must be non-NULL */
+ ent = (Entnode *) xmalloc (sizeof (Entnode));
+ ent->user = xstrdup (user);
+ ent->version = xstrdup (vn);
+ ent->timestamp = xstrdup (ts ? ts : "");
+ ent->options = xstrdup (options ? options : "");
+ ent->tag = xstrdup (tag);
+ ent->date = xstrdup (date);
+ ent->conflict = xstrdup (ts_conflict);
+
+ return ent;
+}
+
+/*
+ * Destruct an Entnode
+ */
+void
+Entnode_Destroy (ent)
+ Entnode *ent;
+{
+ free (ent->user);
+ free (ent->version);
+ free (ent->timestamp);
+ free (ent->options);
+ if (ent->tag)
+ free (ent->tag);
+ if (ent->date)
+ free (ent->date);
+ if (ent->conflict)
+ free (ent->conflict);
+ free (ent);
+}
+
+/*
+ * Write out the line associated with a node of an entries file
+ */
+static int write_ent_proc PROTO ((Node *, void *));
+static int
+write_ent_proc (node, closure)
+ Node *node;
+ void *closure;
+{
+ if (fputentent(entfile, (Entnode *) node->data))
+ error (1, errno, "cannot write %s", entfilename);
+
+ return (0);
+}
+
+/*
+ * write out the current entries file given a list, making a backup copy
+ * first of course
+ */
+static void
+write_entries (list)
+ List *list;
+{
+ /* open the new one and walk the list writing entries */
+ entfilename = CVSADM_ENTBAK;
+ entfile = open_file (entfilename, "w+");
+ (void) walklist (list, write_ent_proc, NULL);
+ if (fclose (entfile) == EOF)
+ error (1, errno, "error closing %s", entfilename);
+
+ /* now, atomically (on systems that support it) rename it */
+ rename_file (entfilename, CVSADM_ENT);
+
+ /* now, remove the log file */
+ unlink_file (CVSADM_ENTLOG);
+}
+
+/*
+ * Removes the argument file from the Entries file if necessary.
+ */
+void
+Scratch_Entry (list, fname)
+ List *list;
+ char *fname;
+{
+ Node *node;
+
+ if (trace)
+#ifdef SERVER_SUPPORT
+ (void) fprintf (stderr, "%c-> Scratch_Entry(%s)\n",
+ (server_active) ? 'S' : ' ', fname);
+#else
+ (void) fprintf (stderr, "-> Scratch_Entry(%s)\n", fname);
+#endif
+
+ /* hashlookup to see if it is there */
+ if ((node = findnode (list, fname)) != NULL)
+ {
+ delnode (node); /* delete the node */
+#ifdef SERVER_SUPPORT
+ if (server_active)
+ server_scratch (fname);
+#endif
+ if (!noexec)
+ write_entries (list); /* re-write the file */
+ }
+}
+
+/*
+ * Enters the given file name/version/time-stamp into the Entries file,
+ * removing the old entry first, if necessary.
+ */
+void
+Register (list, fname, vn, ts, options, tag, date, ts_conflict)
+ List *list;
+ char *fname;
+ char *vn;
+ char *ts;
+ char *options;
+ char *tag;
+ char *date;
+ char *ts_conflict;
+{
+ Entnode *entnode;
+ Node *node;
+
+#ifdef SERVER_SUPPORT
+ if (server_active)
+ {
+ server_register (fname, vn, ts, options, tag, date, ts_conflict);
+ }
+#endif
+
+ if (trace)
+ {
+#ifdef SERVER_SUPPORT
+ (void) fprintf (stderr, "%c-> Register(%s, %s, %s%s%s, %s, %s %s)\n",
+ (server_active) ? 'S' : ' ',
+ fname, vn, ts ? ts : "",
+ ts_conflict ? "+" : "", ts_conflict ? ts_conflict : "",
+ options, tag ? tag : "", date ? date : "");
+#else
+ (void) fprintf (stderr, "-> Register(%s, %s, %s%s%s, %s, %s %s)\n",
+ fname, vn, ts ? ts : "",
+ ts_conflict ? "+" : "", ts_conflict ? ts_conflict : "",
+ options, tag ? tag : "", date ? date : "");
+#endif
+ }
+
+ entnode = Entnode_Create(fname, vn, ts, options, tag, date, ts_conflict);
+ node = AddEntryNode (list, entnode);
+
+ if (!noexec)
+ {
+ entfile = open_file (CVSADM_ENTLOG, "a");
+
+ write_ent_proc (node, NULL);
+
+ if (fclose (entfile) == EOF)
+ error (1, errno, "error closing %s", CVSADM_ENTLOG);
+ }
+}
+
+/*
+ * Node delete procedure for list-private sticky dir tag/date info
+ */
+static void
+freesdt (p)
+ Node *p;
+{
+ struct stickydirtag *sdtp;
+
+ sdtp = (struct stickydirtag *) p->data;
+ if (sdtp->tag)
+ free (sdtp->tag);
+ if (sdtp->date)
+ free (sdtp->date);
+ if (sdtp->options)
+ free (sdtp->options);
+ free ((char *) sdtp);
+}
+
+static Entnode *
+fgetentent(fpin)
+ FILE *fpin;
+{
+ Entnode *ent;
+ char *line;
+ size_t line_chars_allocated;
+ register char *cp;
+ char *user, *vn, *ts, *options;
+ char *tag_or_date, *tag, *date, *ts_conflict;
+
+ line = NULL;
+ line_chars_allocated = 0;
+
+ ent = NULL;
+ while (getline (&line, &line_chars_allocated, fpin) > 0)
+ {
+ if (line[0] != '/')
+ continue;
+
+ user = line + 1;
+ if ((cp = strchr (user, '/')) == NULL)
+ continue;
+ *cp++ = '\0';
+ vn = cp;
+ if ((cp = strchr (vn, '/')) == NULL)
+ continue;
+ *cp++ = '\0';
+ ts = cp;
+ if ((cp = strchr (ts, '/')) == NULL)
+ continue;
+ *cp++ = '\0';
+ options = cp;
+ if ((cp = strchr (options, '/')) == NULL)
+ continue;
+ *cp++ = '\0';
+ tag_or_date = cp;
+ if ((cp = strchr (tag_or_date, '\n')) == NULL)
+ continue;
+ *cp = '\0';
+ tag = (char *) NULL;
+ date = (char *) NULL;
+ if (*tag_or_date == 'T')
+ tag = tag_or_date + 1;
+ else if (*tag_or_date == 'D')
+ date = tag_or_date + 1;
+
+ if ((ts_conflict = strchr (ts, '+')))
+ *ts_conflict++ = '\0';
+
+ /*
+ * XXX - Convert timestamp from old format to new format.
+ *
+ * If the timestamp doesn't match the file's current
+ * mtime, we'd have to generate a string that doesn't
+ * match anyways, so cheat and base it on the existing
+ * string; it doesn't have to match the same mod time.
+ *
+ * For an unmodified file, write the correct timestamp.
+ */
+ {
+ struct stat sb;
+ if (strlen (ts) > 30 && stat (user, &sb) == 0)
+ {
+ char *c = ctime (&sb.st_mtime);
+
+ if (!strncmp (ts + 25, c, 24))
+ ts = time_stamp (user);
+ else
+ {
+ ts += 24;
+ ts[0] = '*';
+ }
+ }
+ }
+
+ ent = Entnode_Create(user, vn, ts, options, tag, date, ts_conflict);
+ break;
+ }
+
+ free (line);
+ return ent;
+}
+
+static int
+fputentent(fp, p)
+ FILE *fp;
+ Entnode *p;
+{
+ if (fprintf (fp, "/%s/%s/%s", p->user, p->version, p->timestamp) < 0)
+ return 1;
+ if (p->conflict)
+ {
+ if (fprintf (fp, "+%s", p->conflict) < 0)
+ return 1;
+ }
+ if (fprintf (fp, "/%s/", p->options) < 0)
+ return 1;
+
+ if (p->tag)
+ {
+ if (fprintf (fp, "T%s\n", p->tag) < 0)
+ return 1;
+ }
+ else if (p->date)
+ {
+ if (fprintf (fp, "D%s\n", p->date) < 0)
+ return 1;
+ }
+ else
+ {
+ if (fprintf (fp, "\n") < 0)
+ return 1;
+ }
+
+ return 0;
+}
+
+
+/*
+ * Read the entries file into a list, hashing on the file name.
+ */
+List *
+Entries_Open (aflag)
+ int aflag;
+{
+ List *entries;
+ Entnode *ent;
+ char *dirtag, *dirdate;
+ int do_rewrite = 0;
+ FILE *fpin;
+
+ /* get a fresh list... */
+ entries = getlist ();
+
+ /*
+ * Parse the CVS/Tag file, to get any default tag/date settings. Use
+ * list-private storage to tuck them away for Version_TS().
+ */
+ ParseTag (&dirtag, &dirdate);
+ if (aflag || dirtag || dirdate)
+ {
+ struct stickydirtag *sdtp;
+
+ sdtp = (struct stickydirtag *) xmalloc (sizeof (*sdtp));
+ memset ((char *) sdtp, 0, sizeof (*sdtp));
+ sdtp->aflag = aflag;
+ sdtp->tag = xstrdup (dirtag);
+ sdtp->date = xstrdup (dirdate);
+
+ /* feed it into the list-private area */
+ entries->list->data = (char *) sdtp;
+ entries->list->delproc = freesdt;
+ }
+
+ fpin = fopen (CVSADM_ENT, "r");
+ if (fpin == NULL)
+ error (0, errno, "cannot open %s for reading", CVSADM_ENT);
+ else
+ {
+ while ((ent = fgetentent (fpin)) != NULL)
+ {
+ (void) AddEntryNode (entries, ent);
+ }
+
+ fclose (fpin);
+ }
+
+ fpin = fopen (CVSADM_ENTLOG, "r");
+ if (fpin != NULL)
+ {
+ while ((ent = fgetentent (fpin)) != NULL)
+ {
+ (void) AddEntryNode (entries, ent);
+ }
+ do_rewrite = 1;
+ fclose (fpin);
+ }
+
+ if (do_rewrite && !noexec)
+ write_entries (entries);
+
+ /* clean up and return */
+ if (fpin)
+ (void) fclose (fpin);
+ if (dirtag)
+ free (dirtag);
+ if (dirdate)
+ free (dirdate);
+ return (entries);
+}
+
+void
+Entries_Close(list)
+ List *list;
+{
+ if (list)
+ {
+ if (!noexec)
+ {
+ if (isfile (CVSADM_ENTLOG))
+ write_entries (list);
+ }
+ dellist(&list);
+ }
+}
+
+
+/*
+ * Free up the memory associated with the data section of an ENTRIES type
+ * node
+ */
+static void
+Entries_delproc (node)
+ Node *node;
+{
+ Entnode *p;
+
+ p = (Entnode *) node->data;
+ Entnode_Destroy(p);
+}
+
+/*
+ * Get an Entries file list node, initialize it, and add it to the specified
+ * list
+ */
+static Node *
+AddEntryNode (list, entdata)
+ List *list;
+ Entnode *entdata;
+{
+ Node *p;
+
+ /* was it already there? */
+ if ((p = findnode (list, entdata->user)) != NULL)
+ {
+ /* take it out */
+ delnode (p);
+ }
+
+ /* get a node and fill in the regular stuff */
+ p = getnode ();
+ p->type = ENTRIES;
+ p->delproc = Entries_delproc;
+
+ /* this one gets a key of the name for hashing */
+ /* FIXME This results in duplicated data --- the hash package shouldn't
+ assume that the key is dynamically allocated. The user's free proc
+ should be responsible for freeing the key. */
+ p->key = xstrdup (entdata->user);
+ p->data = (char *) entdata;
+
+ /* put the node into the list */
+ addnode (list, p);
+ return (p);
+}
+
+/*
+ * Write out/Clear the CVS/Tag file.
+ */
+void
+WriteTag (dir, tag, date)
+ char *dir;
+ char *tag;
+ char *date;
+{
+ FILE *fout;
+ char tmp[PATH_MAX];
+
+ if (noexec)
+ return;
+
+ if (dir == NULL)
+ (void) strcpy (tmp, CVSADM_TAG);
+ else
+ (void) sprintf (tmp, "%s/%s", dir, CVSADM_TAG);
+
+ if (tag || date)
+ {
+ fout = open_file (tmp, "w+");
+ if (tag)
+ {
+ if (fprintf (fout, "T%s\n", tag) < 0)
+ error (1, errno, "write to %s failed", tmp);
+ }
+ else
+ {
+ if (fprintf (fout, "D%s\n", date) < 0)
+ error (1, errno, "write to %s failed", tmp);
+ }
+ if (fclose (fout) == EOF)
+ error (1, errno, "cannot close %s", tmp);
+ }
+ else
+ if (unlink_file (tmp) < 0 && ! existence_error (errno))
+ error (1, errno, "cannot remove %s", tmp);
+}
+
+/*
+ * Parse the CVS/Tag file for the current directory.
+ */
+void
+ParseTag (tagp, datep)
+ char **tagp;
+ char **datep;
+{
+ FILE *fp;
+
+ if (tagp)
+ *tagp = (char *) NULL;
+ if (datep)
+ *datep = (char *) NULL;
+ fp = fopen (CVSADM_TAG, "r");
+ if (fp)
+ {
+ char *line;
+ int line_length;
+ size_t line_chars_allocated;
+
+ line = NULL;
+ line_chars_allocated = 0;
+
+ if ((line_length = getline (&line, &line_chars_allocated, fp)) > 0)
+ {
+ /* Remove any trailing newline. */
+ if (line[line_length - 1] == '\n')
+ line[--line_length] = '\0';
+ if (*line == 'T' && tagp)
+ *tagp = xstrdup (line + 1);
+ else if (*line == 'D' && datep)
+ *datep = xstrdup (line + 1);
+ }
+ (void) fclose (fp);
+ free (line);
+ }
+}
diff --git a/gnu/usr.bin/cvs/cvs/expand_path.c b/gnu/usr.bin/cvs/cvs/expand_path.c
new file mode 100644
index 0000000..7cc939f
--- /dev/null
+++ b/gnu/usr.bin/cvs/cvs/expand_path.c
@@ -0,0 +1,139 @@
+/* expand_path.c -- expand environmental variables in passed in string
+ The main routine is expand_pathname, it is the routine
+ that handles the '~' character in four forms:
+ ~name
+ ~name/
+ ~/
+ ~
+ and handles environment variables contained within the pathname
+ which are defined by:
+ c is some character
+ ${var_name} var_name is the name of the environ variable
+ $var_name var_name ends with a non ascii character
+ char *expand_pathname(char *name)
+ This routine will expand the pathname to account for ~
+ and $ characters as described above.If an error occurs, NULL
+ is returned.
+ Will only expand Built in CVS variables all others are ignored.
+ */
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#include "cvs.h"
+#include <stdio.h>
+#include <ctype.h>
+#include <sys/types.h>
+#if HAVE_STRING_H
+#include <string.h>
+#else
+#include <strings.h>
+#endif
+static char *expand_variable PROTO((char *env));
+extern char *xmalloc ();
+extern void free ();
+char *
+expand_path (name)
+ char *name;
+{
+ char *s;
+ char *d;
+ char mybuf[PATH_MAX];
+ char buf[PATH_MAX];
+ char *result;
+ s = name;
+ d = mybuf;
+ while ((*d++ = *s))
+ if (*s++ == '$')
+ {
+ char *p = d;
+ char *e;
+ int flag = (*s == '{');
+
+ for (; (*d++ = *s); s++)
+ if (flag ? *s =='}' :
+ isalnum (*s) == 0 && *s!='_' )
+ break;
+ *--d = 0;
+ e = expand_variable (&p[flag]);
+
+ if (e)
+ {
+ for (d = &p[-1]; (*d++ = *e++);)
+ ;
+ --d;
+ if (flag && *s)
+ s++;
+ }
+ else
+ return NULL; /* no env variable */
+ }
+ *d = 0;
+ s = mybuf;
+ d = buf;
+ /* If you don't want ~username ~/ to be expanded simply remove
+ * This entire if statement including the else portion
+ */
+ if (*s++ == '~')
+ {
+ char *t;
+ char *p=s;
+ if (*s=='/' || *s==0)
+ t = getenv ("HOME");
+ else
+ {
+ struct passwd *ps;
+ for (; *p!='/' && *p; p++)
+ ;
+ *p = 0;
+ ps = getpwnam (s);
+ if (ps == 0)
+ return NULL; /* no such user */
+ t = ps->pw_dir;
+ }
+ while ((*d++ = *t++))
+ ;
+ --d;
+ if (*p == 0)
+ *p = '/'; /* always add / */
+ s=p;
+ }
+ else
+ --s;
+ /* Kill up to here */
+ while ((*d++ = *s++))
+ ;
+ *d=0;
+ result = xmalloc (sizeof(char) * strlen(buf)+1);
+ strcpy (result, buf);
+ return result;
+}
+static char *
+expand_variable (name)
+ char *name;
+{
+ /* There is nothing expanding this function to allow it
+ * to read a file in the $CVSROOT/CVSROOT directory that
+ * says which environmental variables could be expanded
+ * or just say everything is fair game to be expanded
+ */
+ if ( strcmp (name, CVSROOT_ENV) == 0 )
+ return CVSroot;
+ else
+ if ( strcmp (name, RCSBIN_ENV) == 0 )
+ return Rcsbin;
+ else
+ if ( strcmp (name, EDITOR1_ENV) == 0 )
+ return Editor;
+ else
+ if ( strcmp (name, EDITOR2_ENV) == 0 )
+ return Editor;
+ else
+ if ( strcmp (name, EDITOR3_ENV) == 0 )
+ return Editor;
+ else
+ return NULL;
+ /* The code here could also just
+ * return whatever getenv would
+ * return.
+ */
+}
diff --git a/gnu/usr.bin/cvs/cvs/find_names.c b/gnu/usr.bin/cvs/cvs/find_names.c
new file mode 100644
index 0000000..82959b5
--- /dev/null
+++ b/gnu/usr.bin/cvs/cvs/find_names.c
@@ -0,0 +1,275 @@
+/*
+ * Copyright (c) 1992, Brian Berliner and Jeff Polk
+ * Copyright (c) 1989-1992, Brian Berliner
+ *
+ * You may distribute under the terms of the GNU General Public License as
+ * specified in the README file that comes with the CVS 1.4 kit.
+ *
+ * Find Names
+ *
+ * Finds all the pertinent file names, both from the administration and from the
+ * repository
+ *
+ * Find Dirs
+ *
+ * Finds all pertinent sub-directories of the checked out instantiation and the
+ * repository (and optionally the attic)
+ */
+
+#include "cvs.h"
+
+#ifndef lint
+static const char rcsid[] = "$CVSid: @(#)find_names.c 1.45 94/10/22 $";
+USE(rcsid);
+#endif
+
+static int find_dirs PROTO((char *dir, List * list, int checkadm));
+static int find_rcs PROTO((char *dir, List * list));
+
+static List *filelist;
+
+/*
+ * add the key from entry on entries list to the files list
+ */
+static int add_entries_proc PROTO((Node *, void *));
+static int
+add_entries_proc (node, closure)
+ Node *node;
+ void *closure;
+{
+ Node *fnode;
+
+ fnode = getnode ();
+ fnode->type = FILES;
+ fnode->key = xstrdup (node->key);
+ if (addnode (filelist, fnode) != 0)
+ freenode (fnode);
+ return (0);
+}
+
+/*
+ * compare two files list node (for sort)
+ */
+static int fsortcmp PROTO ((const Node *, const Node *));
+static int
+fsortcmp (p, q)
+ const Node *p;
+ const Node *q;
+{
+ return (strcmp (p->key, q->key));
+}
+
+List *
+Find_Names (repository, which, aflag, optentries)
+ char *repository;
+ int which;
+ int aflag;
+ List **optentries;
+{
+ List *entries;
+ List *files;
+ char dir[PATH_MAX];
+
+ /* make a list for the files */
+ files = filelist = getlist ();
+
+ /* look at entries (if necessary) */
+ if (which & W_LOCAL)
+ {
+ /* parse the entries file (if it exists) */
+ entries = Entries_Open (aflag);
+ if (entries != NULL)
+ {
+ /* walk the entries file adding elements to the files list */
+ (void) walklist (entries, add_entries_proc, NULL);
+
+ /* if our caller wanted the entries list, return it; else free it */
+ if (optentries != NULL)
+ *optentries = entries;
+ else
+ Entries_Close (entries);
+ }
+ }
+
+ if ((which & W_REPOS) && repository && !isreadable (CVSADM_ENTSTAT))
+ {
+ /* search the repository */
+ if (find_rcs (repository, files) != 0)
+ error (1, errno, "cannot open directory %s", repository);
+
+ /* search the attic too */
+ if (which & W_ATTIC)
+ {
+ (void) sprintf (dir, "%s/%s", repository, CVSATTIC);
+ (void) find_rcs (dir, files);
+ }
+ }
+
+ /* sort the list into alphabetical order and return it */
+ sortlist (files, fsortcmp);
+ return (files);
+}
+
+/*
+ * create a list of directories to traverse from the current directory
+ */
+List *
+Find_Dirs (repository, which)
+ char *repository;
+ int which;
+{
+ List *dirlist;
+
+ /* make a list for the directories */
+ dirlist = getlist ();
+
+ /* find the local ones */
+ if (which & W_LOCAL)
+ {
+ /* look only for CVS controlled sub-directories */
+ if (find_dirs (".", dirlist, 1) != 0)
+ error (1, errno, "cannot open current directory");
+ }
+
+ /* look for sub-dirs in the repository */
+ if ((which & W_REPOS) && repository)
+ {
+ /* search the repository */
+ if (find_dirs (repository, dirlist, 0) != 0)
+ error (1, errno, "cannot open directory %s", repository);
+
+#ifdef ATTIC_DIR_SUPPORT /* XXX - FIXME */
+ /* search the attic too */
+ if (which & W_ATTIC)
+ {
+ char dir[PATH_MAX];
+
+ (void) sprintf (dir, "%s/%s", repository, CVSATTIC);
+ (void) find_dirs (dir, dirlist, 0);
+ }
+#endif
+ }
+
+ /* sort the list into alphabetical order and return it */
+ sortlist (dirlist, fsortcmp);
+ return (dirlist);
+}
+
+/*
+ * Finds all the ,v files in the argument directory, and adds them to the
+ * files list. Returns 0 for success and non-zero if the argument directory
+ * cannot be opened.
+ */
+static int
+find_rcs (dir, list)
+ char *dir;
+ List *list;
+{
+ Node *p;
+ struct dirent *dp;
+ DIR *dirp;
+
+ /* set up to read the dir */
+ if ((dirp = opendir (dir)) == NULL)
+ return (1);
+
+ /* read the dir, grabbing the ,v files */
+ while ((dp = readdir (dirp)) != NULL)
+ {
+ if (fnmatch (RCSPAT, dp->d_name, 0) == 0)
+ {
+ char *comma;
+
+ comma = strrchr (dp->d_name, ','); /* strip the ,v */
+ *comma = '\0';
+ p = getnode ();
+ p->type = FILES;
+ p->key = xstrdup (dp->d_name);
+ if (addnode (list, p) != 0)
+ freenode (p);
+ }
+ }
+ (void) closedir (dirp);
+ return (0);
+}
+
+/*
+ * Finds all the subdirectories of the argument dir and adds them to the
+ * specified list. Sub-directories without a CVS administration directory
+ * are optionally ignored Returns 0 for success or 1 on error.
+ */
+static int
+find_dirs (dir, list, checkadm)
+ char *dir;
+ List *list;
+ int checkadm;
+{
+ Node *p;
+ char tmp[PATH_MAX];
+ struct dirent *dp;
+ DIR *dirp;
+
+ /* set up to read the dir */
+ if ((dirp = opendir (dir)) == NULL)
+ return (1);
+
+ /* read the dir, grabbing sub-dirs */
+ while ((dp = readdir (dirp)) != NULL)
+ {
+ if (strcmp (dp->d_name, ".") == 0 ||
+ strcmp (dp->d_name, "..") == 0 ||
+ strcmp (dp->d_name, CVSATTIC) == 0 ||
+ strcmp (dp->d_name, CVSLCK) == 0)
+ continue;
+
+#ifdef DT_DIR
+ if (dp->d_type != DT_DIR)
+ {
+ if (dp->d_type != DT_UNKNOWN && dp->d_type != DT_LNK)
+ continue;
+#endif
+ /* don't bother stating ,v files */
+ if (fnmatch (RCSPAT, dp->d_name, 0) == 0)
+ continue;
+
+ sprintf (tmp, "%s/%s", dir, dp->d_name);
+ if (!isdir (tmp))
+ continue;
+
+#ifdef DT_DIR
+ }
+#endif
+
+ /* check for administration directories (if needed) */
+ if (checkadm)
+ {
+ /* blow off symbolic links to dirs in local dir */
+#ifdef DT_DIR
+ if (dp->d_type != DT_DIR)
+ {
+ /* we're either unknown or a symlink at this point */
+ if (dp->d_type == DT_LNK)
+ continue;
+#endif
+ if (islink (tmp))
+ continue;
+#ifdef DT_DIR
+ }
+#endif
+
+ /* check for new style */
+ (void) sprintf (tmp, "%s/%s/%s", dir, dp->d_name, CVSADM);
+ if (!isdir (tmp))
+ continue;
+ }
+
+ /* put it in the list */
+ p = getnode ();
+ p->type = DIRS;
+ p->key = xstrdup (dp->d_name);
+ if (addnode (list, p) != 0)
+ freenode (p);
+ }
+ (void) closedir (dirp);
+ return (0);
+}
diff --git a/gnu/usr.bin/cvs/cvs/history.c b/gnu/usr.bin/cvs/cvs/history.c
new file mode 100644
index 0000000..7a40b7b
--- /dev/null
+++ b/gnu/usr.bin/cvs/cvs/history.c
@@ -0,0 +1,1489 @@
+/*
+ *
+ * You may distribute under the terms of the GNU General Public License
+ * as specified in the README file that comes with the CVS 1.0 kit.
+ *
+ * **************** History of Users and Module ****************
+ *
+ * LOGGING: Append record to "${CVSROOT}/CVSROOTADM/CVSROOTADM_HISTORY".
+ *
+ * On For each Tag, Add, Checkout, Commit, Update or Release command,
+ * one line of text is written to a History log.
+ *
+ * X date | user | CurDir | special | rev(s) | argument '\n'
+ *
+ * where: [The spaces in the example line above are not in the history file.]
+ *
+ * X is a single character showing the type of event:
+ * T "Tag" cmd.
+ * O "Checkout" cmd.
+ * F "Release" cmd.
+ * W "Update" cmd - No User file, Remove from Entries file.
+ * U "Update" cmd - File was checked out over User file.
+ * G "Update" cmd - File was merged successfully.
+ * C "Update" cmd - File was merged and shows overlaps.
+ * M "Commit" cmd - "Modified" file.
+ * A "Commit" cmd - "Added" file.
+ * R "Commit" cmd - "Removed" file.
+ *
+ * date is a fixed length 8-char hex representation of a Unix time_t.
+ * [Starting here, variable fields are delimited by '|' chars.]
+ *
+ * user is the username of the person who typed the command.
+ *
+ * CurDir The directory where the action occurred. This should be the
+ * absolute path of the directory which is at the same level as
+ * the "Repository" field (for W,U,G,C & M,A,R).
+ *
+ * Repository For record types [W,U,G,C,M,A,R] this field holds the
+ * repository read from the administrative data where the
+ * command was typed.
+ * T "A" --> New Tag, "D" --> Delete Tag
+ * Otherwise it is the Tag or Date to modify.
+ * O,F A "" (null field)
+ *
+ * rev(s) Revision number or tag.
+ * T The Tag to apply.
+ * O The Tag or Date, if specified, else "" (null field).
+ * F "" (null field)
+ * W The Tag or Date, if specified, else "" (null field).
+ * U The Revision checked out over the User file.
+ * G,C The Revision(s) involved in merge.
+ * M,A,R RCS Revision affected.
+ *
+ * argument The module (for [TOUF]) or file (for [WUGCMAR]) affected.
+ *
+ *
+ *** Report categories: "User" and "Since" modifiers apply to all reports.
+ * [For "sort" ordering see the "sort_order" routine.]
+ *
+ * Extract list of record types
+ *
+ * -e, -x [TOFWUGCMAR]
+ *
+ * Extracted records are simply printed, No analysis is performed.
+ * All "field" modifiers apply. -e chooses all types.
+ *
+ * Checked 'O'ut modules
+ *
+ * -o, -w
+ * Checked out modules. 'F' and 'O' records are examined and if
+ * the last record for a repository/file is an 'O', a line is
+ * printed. "-w" forces the "working dir" to be used in the
+ * comparison instead of the repository.
+ *
+ * Committed (Modified) files
+ *
+ * -c, -l, -w
+ * All 'M'odified, 'A'dded and 'R'emoved records are examined.
+ * "Field" modifiers apply. -l forces a sort by file within user
+ * and shows only the last modifier. -w works as in Checkout.
+ *
+ * Warning: Be careful with what you infer from the output of
+ * "cvs hi -c -l". It means the last time *you*
+ * changed the file, not the list of files for which
+ * you were the last changer!!!
+ *
+ * Module history for named modules.
+ * -m module, -l
+ *
+ * This is special. If one or more modules are specified, the
+ * module names are remembered and the files making up the
+ * modules are remembered. Only records matching exactly those
+ * files and repositories are shown. Sorting by "module", then
+ * filename, is implied. If -l ("last modified") is specified,
+ * then "update" records (types WUCG), tag and release records
+ * are ignored and the last (by date) "modified" record.
+ *
+ * TAG history
+ *
+ * -T All Tag records are displayed.
+ *
+ *** Modifiers.
+ *
+ * Since ... [All records contain a timestamp, so any report
+ * category can be limited by date.]
+ *
+ * -D date - The "date" is parsed into a Unix "time_t" and
+ * records with an earlier time stamp are ignored.
+ * -r rev/tag - A "rev" begins with a digit. A "tag" does not. If
+ * you use this option, every file is searched for the
+ * indicated rev/tag.
+ * -t tag - The "tag" is searched for in the history file and no
+ * record is displayed before the tag is found. An
+ * error is printed if the tag is never found.
+ * -b string - Records are printed only back to the last reference
+ * to the string in the "module", "file" or
+ * "repository" fields.
+ *
+ * Field Selections [Simple comparisons on existing fields. All field
+ * selections are repeatable.]
+ *
+ * -a - All users.
+ * -u user - If no user is given and '-a' is not given, only
+ * records for the user typing the command are shown.
+ * ==> If -a or -u is not specified, just use "self".
+ *
+ * -f filematch - Only records in which the "file" field contains the
+ * string "filematch" are considered.
+ *
+ * -p repository - Only records in which the "repository" string is a
+ * prefix of the "repos" field are considered.
+ *
+ * -m modulename - Only records which contain "modulename" in the
+ * "module" field are considered.
+ *
+ *
+ * EXAMPLES: ("cvs history", "cvs his" or "cvs hi")
+ *
+ *** Checked out files for username. (default self, e.g. "dgg")
+ * cvs hi [equivalent to: "cvs hi -o -u dgg"]
+ * cvs hi -u user [equivalent to: "cvs hi -o -u user"]
+ * cvs hi -o [equivalent to: "cvs hi -o -u dgg"]
+ *
+ *** Committed (modified) files from the beginning of the file.
+ * cvs hi -c [-u user]
+ *
+ *** Committed (modified) files since Midnight, January 1, 1990:
+ * cvs hi -c -D 'Jan 1 1990' [-u user]
+ *
+ *** Committed (modified) files since tag "TAG" was stored in the history file:
+ * cvs hi -c -t TAG [-u user]
+ *
+ *** Committed (modified) files since tag "TAG" was placed on the files:
+ * cvs hi -c -r TAG [-u user]
+ *
+ *** Who last committed file/repository X?
+ * cvs hi -c -l -[fp] X
+ *
+ *** Modified files since tag/date/file/repos?
+ * cvs hi -c {-r TAG | -D Date | -b string}
+ *
+ *** Tag history
+ * cvs hi -T
+ *
+ *** History of file/repository/module X.
+ * cvs hi -[fpn] X
+ *
+ *** History of user "user".
+ * cvs hi -e -u user
+ *
+ *** Dump (eXtract) specified record types
+ * cvs hi -x [TOFWUGCMAR]
+ *
+ *
+ * FUTURE: J[Join], I[Import] (Not currently implemented.)
+ *
+ */
+
+#include "cvs.h"
+
+#ifndef lint
+static const char rcsid[] = "$CVSid: @(#)history.c 1.33 94/09/21 $";
+USE(rcsid);
+#endif
+
+static struct hrec
+{
+ char *type; /* Type of record (In history record) */
+ char *user; /* Username (In history record) */
+ char *dir; /* "Compressed" Working dir (In history record) */
+ char *repos; /* (Tag is special.) Repository (In history record) */
+ char *rev; /* Revision affected (In history record) */
+ char *file; /* Filename (In history record) */
+ char *end; /* Ptr into repository to copy at end of workdir */
+ char *mod; /* The module within which the file is contained */
+ time_t date; /* Calculated from date stored in record */
+ int idx; /* Index of record, for "stable" sort. */
+} *hrec_head;
+
+
+static char *fill_hrec PROTO((char *line, struct hrec * hr));
+static int accept_hrec PROTO((struct hrec * hr, struct hrec * lr));
+static int select_hrec PROTO((struct hrec * hr));
+static int sort_order PROTO((const PTR l, const PTR r));
+static int within PROTO((char *find, char *string));
+static time_t date_and_time PROTO((char *date_str));
+static void expand_modules PROTO((void));
+static void read_hrecs PROTO((char *fname));
+static void report_hrecs PROTO((void));
+static void save_file PROTO((char *dir, char *name, char *module));
+static void save_module PROTO((char *module));
+static void save_user PROTO((char *name));
+
+#define ALL_REC_TYPES "TOFWUCGMAR"
+#define USER_INCREMENT 2
+#define FILE_INCREMENT 128
+#define MODULE_INCREMENT 5
+#define HREC_INCREMENT 128
+
+static short report_count;
+
+static short extract;
+static short v_checkout;
+static short modified;
+static short tag_report;
+static short module_report;
+static short working;
+static short last_entry;
+static short all_users;
+
+static short user_sort;
+static short repos_sort;
+static short file_sort;
+static short module_sort;
+
+#ifdef HAVE_RCS5
+static short tz_local;
+static time_t tz_seconds_east_of_GMT;
+static char *tz_name = "+0000";
+#else
+static char tz_name[] = "LT";
+#endif
+
+static time_t since_date;
+static char since_rev[20]; /* Maxrev ~= 99.99.99.999 */
+static char since_tag[64];
+static struct hrec *last_since_tag;
+static char backto[128];
+static struct hrec *last_backto;
+static char rec_types[20];
+
+static int hrec_count;
+static int hrec_max;
+
+static char **user_list; /* Ptr to array of ptrs to user names */
+static int user_max; /* Number of elements allocated */
+static int user_count; /* Number of elements used */
+
+static struct file_list_str
+{
+ char *l_file;
+ char *l_module;
+} *file_list; /* Ptr to array file name structs */
+static int file_max; /* Number of elements allocated */
+static int file_count; /* Number of elements used */
+
+static char **mod_list; /* Ptr to array of ptrs to module names */
+static int mod_max; /* Number of elements allocated */
+static int mod_count; /* Number of elements used */
+
+static char *histfile; /* Ptr to the history file name */
+
+static const char *const history_usg[] =
+{
+ "Usage: %s %s [-report] [-flags] [-options args] [files...]\n\n",
+ " Reports:\n",
+ " -T Produce report on all TAGs\n",
+ " -c Committed (Modified) files\n",
+ " -o Checked out modules\n",
+ " -m <module> Look for specified module (repeatable)\n",
+ " -x [TOFWUCGMAR] Extract by record type\n",
+ " Flags:\n",
+ " -a All users (Default is self)\n",
+ " -e Everything (same as -x, but all record types)\n",
+ " -l Last modified (committed or modified report)\n",
+ " -w Working directory must match\n",
+ " Options:\n",
+ " -D <date> Since date (Many formats)\n",
+ " -b <str> Back to record with str in module/file/repos field\n",
+ " -f <file> Specified file (same as command line) (repeatable)\n",
+ " -n <modulename> In module (repeatable)\n",
+ " -p <repos> In repository (repeatable)\n",
+ " -r <rev/tag> Since rev or tag (looks inside RCS files!)\n",
+ " -t <tag> Since tag record placed in history file (by anyone).\n",
+ " -u <user> For user name (repeatable)\n",
+ " -z <tz> Output for time zone <tz> (e.g. -z -0700)\n",
+ NULL};
+
+/* Sort routine for qsort:
+ - If a user is selected at all, sort it first. User-within-file is useless.
+ - If a module was selected explicitly, sort next on module.
+ - Then sort by file. "File" is "repository/file" unless "working" is set,
+ then it is "workdir/file". (Revision order should always track date.)
+ - Always sort timestamp last.
+*/
+static int
+sort_order (l, r)
+ const PTR l;
+ const PTR r;
+{
+ int i;
+ const struct hrec *left = (const struct hrec *) l;
+ const struct hrec *right = (const struct hrec *) r;
+
+ if (user_sort) /* If Sort by username, compare users */
+ {
+ if ((i = strcmp (left->user, right->user)) != 0)
+ return (i);
+ }
+ if (module_sort) /* If sort by modules, compare module names */
+ {
+ if (left->mod && right->mod)
+ if ((i = strcmp (left->mod, right->mod)) != 0)
+ return (i);
+ }
+ if (repos_sort) /* If sort by repository, compare them. */
+ {
+ if ((i = strcmp (left->repos, right->repos)) != 0)
+ return (i);
+ }
+ if (file_sort) /* If sort by filename, compare files, NOT dirs. */
+ {
+ if ((i = strcmp (left->file, right->file)) != 0)
+ return (i);
+
+ if (working)
+ {
+ if ((i = strcmp (left->dir, right->dir)) != 0)
+ return (i);
+
+ if ((i = strcmp (left->end, right->end)) != 0)
+ return (i);
+ }
+ }
+
+ /*
+ * By default, sort by date, time
+ * XXX: This fails after 2030 when date slides into sign bit
+ */
+ if ((i = ((long) (left->date) - (long) (right->date))) != 0)
+ return (i);
+
+ /* For matching dates, keep the sort stable by using record index */
+ return (left->idx - right->idx);
+}
+
+static time_t
+date_and_time (date_str)
+ char *date_str;
+{
+ time_t t;
+
+ t = get_date (date_str, (struct timeb *) NULL);
+ if (t == (time_t) - 1)
+ error (1, 0, "Can't parse date/time: %s", date_str);
+ return (t);
+}
+
+int
+history (argc, argv)
+ int argc;
+ char **argv;
+{
+ int i, c;
+ char fname[PATH_MAX];
+
+ if (argc == -1)
+ usage (history_usg);
+
+ optind = 1;
+ while ((c = getopt (argc, argv, "Tacelow?D:b:f:m:n:p:r:t:u:x:X:z:")) != -1)
+ {
+ switch (c)
+ {
+ case 'T': /* Tag list */
+ report_count++;
+ tag_report++;
+ break;
+ case 'a': /* For all usernames */
+ all_users++;
+ break;
+ case 'c':
+ report_count++;
+ modified = 1;
+ break;
+ case 'e':
+ report_count++;
+ extract++;
+ (void) strcpy (rec_types, ALL_REC_TYPES);
+ break;
+ case 'l': /* Find Last file record */
+ last_entry = 1;
+ break;
+ case 'o':
+ report_count++;
+ v_checkout = 1;
+ break;
+ case 'w': /* Match Working Dir (CurDir) fields */
+ working = 1;
+ break;
+ case 'X': /* Undocumented debugging flag */
+ histfile = optarg;
+ break;
+ case 'D': /* Since specified date */
+ if (*since_rev || *since_tag || *backto)
+ {
+ error (0, 0, "date overriding rev/tag/backto");
+ *since_rev = *since_tag = *backto = '\0';
+ }
+ since_date = date_and_time (optarg);
+ break;
+ case 'b': /* Since specified file/Repos */
+ if (since_date || *since_rev || *since_tag)
+ {
+ error (0, 0, "backto overriding date/rev/tag");
+ *since_rev = *since_tag = '\0';
+ since_date = 0;
+ }
+ if (strlen (optarg) >= sizeof (backto))
+ {
+ error (0, 0, "backto truncated to %d bytes",
+ sizeof (backto) - 1);
+ optarg[sizeof (backto) - 1] = '\0';
+ }
+ (void) strcpy (backto, optarg);
+ break;
+ case 'f': /* For specified file */
+ save_file ("", optarg, (char *) NULL);
+ break;
+ case 'm': /* Full module report */
+ report_count++;
+ module_report++;
+ case 'n': /* Look for specified module */
+ save_module (optarg);
+ break;
+ case 'p': /* For specified directory */
+ save_file (optarg, "", (char *) NULL);
+ break;
+ case 'r': /* Since specified Tag/Rev */
+ if (since_date || *since_tag || *backto)
+ {
+ error (0, 0, "rev overriding date/tag/backto");
+ *since_tag = *backto = '\0';
+ since_date = 0;
+ }
+ (void) strcpy (since_rev, optarg);
+ break;
+ case 't': /* Since specified Tag/Rev */
+ if (since_date || *since_rev || *backto)
+ {
+ error (0, 0, "tag overriding date/marker/file/repos");
+ *since_rev = *backto = '\0';
+ since_date = 0;
+ }
+ (void) strcpy (since_tag, optarg); /* tag */
+ break;
+ case 'u': /* For specified username */
+ save_user (optarg);
+ break;
+ case 'x':
+ report_count++;
+ extract++;
+ {
+ char *cp;
+
+ for (cp = optarg; *cp; cp++)
+ if (!strchr (ALL_REC_TYPES, *cp))
+ error (1, 0, "%c is not a valid report type", *cp);
+ }
+ (void) strcpy (rec_types, optarg);
+ break;
+ case 'z':
+#ifndef HAVE_RCS5
+ error (0, 0, "-z not supported with RCS 4");
+#else
+ tz_local =
+ (optarg[0] == 'l' || optarg[0] == 'L')
+ && (optarg[1] == 't' || optarg[1] == 'T')
+ && !optarg[2];
+ if (tz_local)
+ tz_name = optarg;
+ else
+ {
+ /*
+ * Convert a known time with the given timezone to time_t.
+ * Use the epoch + 23 hours, so timezones east of GMT work.
+ */
+ static char f[] = "1/1/1970 23:00 %s";
+ char *buf = xmalloc (sizeof (f) - 2 + strlen (optarg));
+ time_t t;
+ sprintf (buf, f, optarg);
+ t = get_date (buf, (struct timeb *) NULL);
+ free (buf);
+ if (t == (time_t) -1)
+ error (0, 0, "%s is not a known time zone", optarg);
+ else
+ {
+ /*
+ * Convert to seconds east of GMT, removing the
+ * 23-hour offset mentioned above.
+ */
+ tz_seconds_east_of_GMT = (time_t)23 * 60 * 60 - t;
+ tz_name = optarg;
+ }
+ }
+#endif
+ break;
+ case '?':
+ default:
+ usage (history_usg);
+ break;
+ }
+ }
+ c = optind; /* Save the handled option count */
+
+ /* ================ Now analyze the arguments a bit */
+ if (!report_count)
+ v_checkout++;
+ else if (report_count > 1)
+ error (1, 0, "Only one report type allowed from: \"-Tcomx\".");
+
+#ifdef CLIENT_SUPPORT
+ if (client_active)
+ {
+ struct file_list_str *f1;
+ char **mod;
+
+ /* We're the client side. Fire up the remote server. */
+ start_server ();
+
+ ign_setup ();
+
+ if (tag_report)
+ send_arg("-T");
+ if (all_users)
+ send_arg("-a");
+ if (modified)
+ send_arg("-c");
+ if (last_entry)
+ send_arg("-l");
+ if (v_checkout)
+ send_arg("-o");
+ if (working)
+ send_arg("-w");
+ if (histfile)
+ send_arg("-X");
+ if (since_date)
+ option_with_arg ("-D", asctime (gmtime (&since_date)));
+ if (backto[0] != '\0')
+ option_with_arg ("-b", backto);
+ for (f1 = file_list; f1 < &file_list[file_count]; ++f1)
+ {
+ if (f1->l_file[0] == '*')
+ option_with_arg ("-p", f1->l_file + 1);
+ else
+ option_with_arg ("-f", f1->l_file);
+ }
+ if (module_report)
+ send_arg("-m");
+ for (mod = mod_list; mod < &mod_list[mod_count]; ++mod)
+ option_with_arg ("-n", *mod);
+ if (since_rev != NULL)
+ option_with_arg ("-r", since_rev);
+ if (since_tag != NULL)
+ option_with_arg ("-t", since_tag);
+ for (mod = user_list; mod < &user_list[user_count]; ++mod)
+ option_with_arg ("-u", *mod);
+ if (extract)
+ option_with_arg ("-x", rec_types);
+ option_with_arg ("-z", tz_name);
+
+ if (fprintf (to_server, "history\n") < 0)
+ error (1, errno, "writing to server");
+ return get_responses_and_close ();
+ }
+#endif
+
+ if (all_users)
+ save_user ("");
+
+ if (mod_list)
+ expand_modules ();
+
+ if (tag_report)
+ {
+ if (!strchr (rec_types, 'T'))
+ (void) strcat (rec_types, "T");
+ }
+ else if (extract)
+ {
+ if (user_list)
+ user_sort++;
+ }
+ else if (modified)
+ {
+ (void) strcpy (rec_types, "MAR");
+ /*
+ * If the user has not specified a date oriented flag ("Since"), sort
+ * by Repository/file before date. Default is "just" date.
+ */
+ if (!since_date && !*since_rev && !*since_tag && !*backto)
+ {
+ repos_sort++;
+ file_sort++;
+ /*
+ * If we are not looking for last_modified and the user specified
+ * one or more users to look at, sort by user before filename.
+ */
+ if (!last_entry && user_list)
+ user_sort++;
+ }
+ }
+ else if (module_report)
+ {
+ (void) strcpy (rec_types, last_entry ? "OMAR" : ALL_REC_TYPES);
+ module_sort++;
+ repos_sort++;
+ file_sort++;
+ working = 0; /* User's workdir doesn't count here */
+ }
+ else
+ /* Must be "checkout" or default */
+ {
+ (void) strcpy (rec_types, "OF");
+ /* See comments in "modified" above */
+ if (!last_entry && user_list)
+ user_sort++;
+ if (!since_date && !*since_rev && !*since_tag && !*backto)
+ file_sort++;
+ }
+
+ /* If no users were specified, use self (-a saves a universal ("") user) */
+ if (!user_list)
+ save_user (getcaller ());
+
+ /* If we're looking back to a Tag value, must consider "Tag" records */
+ if (*since_tag && !strchr (rec_types, 'T'))
+ (void) strcat (rec_types, "T");
+
+ argc -= c;
+ argv += c;
+ for (i = 0; i < argc; i++)
+ save_file ("", argv[i], (char *) NULL);
+
+ if (histfile)
+ (void) strcpy (fname, histfile);
+ else
+ (void) sprintf (fname, "%s/%s/%s", CVSroot,
+ CVSROOTADM, CVSROOTADM_HISTORY);
+
+ read_hrecs (fname);
+ qsort ((PTR) hrec_head, hrec_count, sizeof (struct hrec), sort_order);
+ report_hrecs ();
+
+ return (0);
+}
+
+void
+history_write (type, update_dir, revs, name, repository)
+ int type;
+ char *update_dir;
+ char *revs;
+ char *name;
+ char *repository;
+{
+ char fname[PATH_MAX], workdir[PATH_MAX], homedir[PATH_MAX];
+ static char username[20]; /* !!! Should be global */
+ int fd;
+ char *line;
+ char *slash = "", *cp, *cp2, *repos;
+ int i;
+ static char *tilde = "";
+ static char *PrCurDir = NULL;
+
+ if (logoff) /* History is turned off by cmd line switch */
+ return;
+ (void) sprintf (fname, "%s/%s/%s", CVSroot, CVSROOTADM, CVSROOTADM_HISTORY);
+
+ /* turn off history logging if the history file does not exist */
+ if (!isfile (fname))
+ {
+ logoff = 1;
+ return;
+ }
+
+ if (trace)
+#ifdef SERVER_SUPPORT
+ fprintf (stderr, "%c-> fopen(%s,a)\n",
+ (server_active) ? 'S' : ' ', fname);
+#else
+ fprintf (stderr, "-> fopen(%s,a)\n", fname);
+#endif
+ if (noexec)
+ return;
+ if ((fd = open (fname, O_WRONLY | O_APPEND | O_CREAT, 0666)) < 0)
+ error (1, errno, "cannot open history file: %s", fname);
+
+ repos = Short_Repository (repository);
+
+ if (!PrCurDir)
+ {
+ struct passwd *pw;
+
+ (void) strcpy (username, getcaller ());
+ PrCurDir = CurDir;
+ if (!(pw = (struct passwd *) getpwnam (username)))
+ error (0, 0, "cannot find own username");
+ else
+ {
+ /* Assumes neither CurDir nor pw->pw_dir ends in '/' */
+ i = strlen (pw->pw_dir);
+ if (!strncmp (CurDir, pw->pw_dir, i))
+ {
+ PrCurDir += i; /* Point to '/' separator */
+ tilde = "~";
+ }
+ else
+ {
+ /* Try harder to find a "homedir" */
+ if (!getwd (workdir))
+ error (1, errno, "can't getwd in history");
+ if (chdir (pw->pw_dir) < 0)
+ error (1, errno, "can't chdir(%s)", pw->pw_dir);
+ if (!getwd (homedir))
+ error (1, errno, "can't getwd in %s", pw->pw_dir);
+ (void) chdir (workdir);
+
+ i = strlen (homedir);
+ if (!strncmp (CurDir, homedir, i))
+ {
+ PrCurDir += i; /* Point to '/' separator */
+ tilde = "~";
+ }
+ }
+ }
+ }
+
+ if (type == 'T')
+ {
+ repos = update_dir;
+ update_dir = "";
+ }
+ else if (update_dir && *update_dir)
+ slash = "/";
+ else
+ update_dir = "";
+
+ (void) sprintf (workdir, "%s%s%s%s", tilde, PrCurDir, slash, update_dir);
+
+ /*
+ * "workdir" is the directory where the file "name" is. ("^~" == $HOME)
+ * "repos" is the Repository, relative to $CVSROOT where the RCS file is.
+ *
+ * "$workdir/$name" is the working file name.
+ * "$CVSROOT/$repos/$name,v" is the RCS file in the Repository.
+ *
+ * First, note that the history format was intended to save space, not
+ * to be human readable.
+ *
+ * The working file directory ("workdir") and the Repository ("repos")
+ * usually end with the same one or more directory elements. To avoid
+ * duplication (and save space), the "workdir" field ends with
+ * an integer offset into the "repos" field. This offset indicates the
+ * beginning of the "tail" of "repos", after which all characters are
+ * duplicates.
+ *
+ * In other words, if the "workdir" field has a '*' (a very stupid thing
+ * to put in a filename) in it, then every thing following the last '*'
+ * is a hex offset into "repos" of the first character from "repos" to
+ * append to "workdir" to finish the pathname.
+ *
+ * It might be easier to look at an example:
+ *
+ * M273b3463|dgg|~/work*9|usr/local/cvs/examples|1.2|loginfo
+ *
+ * Indicates that the workdir is really "~/work/cvs/examples", saving
+ * 10 characters, where "~/work*d" would save 6 characters and mean that
+ * the workdir is really "~/work/examples". It will mean more on
+ * directories like: usr/local/gnu/emacs/dist-19.17/lisp/term
+ *
+ * "workdir" is always an absolute pathname (~/xxx is an absolute path)
+ * "repos" is always a relative pathname. So we can assume that we will
+ * never run into the top of "workdir" -- there will always be a '/' or
+ * a '~' at the head of "workdir" that is not matched by anything in
+ * "repos". On the other hand, we *can* run off the top of "repos".
+ *
+ * Only "compress" if we save characters.
+ */
+
+ if (!repos)
+ repos = "";
+
+ cp = workdir + strlen (workdir) - 1;
+ cp2 = repos + strlen (repos) - 1;
+ for (i = 0; cp2 >= repos && cp > workdir && *cp == *cp2--; cp--)
+ i++;
+
+ if (i > 2)
+ {
+ i = strlen (repos) - i;
+ (void) sprintf ((cp + 1), "*%x", i);
+ }
+
+ if (!revs)
+ revs = "";
+ line = xmalloc (strlen (username) + strlen (workdir) + strlen (repos)
+ + strlen (revs) + strlen (name) + 100);
+ sprintf (line, "%c%08lx|%s|%s|%s|%s|%s\n",
+ type, (long) time ((time_t *) NULL),
+ username, workdir, repos, revs, name);
+
+ /* Lessen some race conditions on non-Posix-compliant hosts. */
+ if (lseek (fd, (off_t) 0, SEEK_END) == -1)
+ error (1, errno, "cannot seek to end of history file: %s", fname);
+
+ if (write (fd, line, strlen (line)) < 0)
+ error (1, errno, "cannot write to history file: %s", fname);
+ free (line);
+ if (close (fd) != 0)
+ error (1, errno, "cannot close history file: %s", fname);
+}
+
+/*
+ * save_user() adds a user name to the user list to select. Zero-length
+ * username ("") matches any user.
+ */
+static void
+save_user (name)
+ char *name;
+{
+ if (user_count == user_max)
+ {
+ user_max += USER_INCREMENT;
+ user_list = (char **) xrealloc ((char *) user_list,
+ (int) user_max * sizeof (char *));
+ }
+ user_list[user_count++] = xstrdup (name);
+}
+
+/*
+ * save_file() adds file name and associated module to the file list to select.
+ *
+ * If "dir" is null, store a file name as is.
+ * If "name" is null, store a directory name with a '*' on the front.
+ * Else, store concatenated "dir/name".
+ *
+ * Later, in the "select" stage:
+ * - if it starts with '*', it is prefix-matched against the repository.
+ * - if it has a '/' in it, it is matched against the repository/file.
+ * - else it is matched against the file name.
+ */
+static void
+save_file (dir, name, module)
+ char *dir;
+ char *name;
+ char *module;
+{
+ char *cp;
+ struct file_list_str *fl;
+
+ if (file_count == file_max)
+ {
+ file_max += FILE_INCREMENT;
+ file_list = (struct file_list_str *) xrealloc ((char *) file_list,
+ file_max * sizeof (*fl));
+ }
+ fl = &file_list[file_count++];
+ fl->l_file = cp = xmalloc (strlen (dir) + strlen (name) + 2);
+ fl->l_module = module;
+
+ if (dir && *dir)
+ {
+ if (name && *name)
+ {
+ (void) strcpy (cp, dir);
+ (void) strcat (cp, "/");
+ (void) strcat (cp, name);
+ }
+ else
+ {
+ *cp++ = '*';
+ (void) strcpy (cp, dir);
+ }
+ }
+ else
+ {
+ if (name && *name)
+ {
+ (void) strcpy (cp, name);
+ }
+ else
+ {
+ error (0, 0, "save_file: null dir and file name");
+ }
+ }
+}
+
+static void
+save_module (module)
+ char *module;
+{
+ if (mod_count == mod_max)
+ {
+ mod_max += MODULE_INCREMENT;
+ mod_list = (char **) xrealloc ((char *) mod_list,
+ mod_max * sizeof (char *));
+ }
+ mod_list[mod_count++] = xstrdup (module);
+}
+
+static void
+expand_modules ()
+{
+}
+
+/* fill_hrec
+ *
+ * Take a ptr to 7-part history line, ending with a newline, for example:
+ *
+ * M273b3463|dgg|~/work*9|usr/local/cvs/examples|1.2|loginfo
+ *
+ * Split it into 7 parts and drop the parts into a "struct hrec".
+ * Return a pointer to the character following the newline.
+ */
+
+#define NEXT_BAR(here) do { while (isspace(*line)) line++; hr->here = line; while ((c = *line++) && c != '|') ; if (!c) return(rtn); *(line - 1) = '\0'; } while (0)
+
+static char *
+fill_hrec (line, hr)
+ char *line;
+ struct hrec *hr;
+{
+ char *cp, *rtn;
+ int c;
+ int off;
+ static int idx = 0;
+
+ memset ((char *) hr, 0, sizeof (*hr));
+ while (isspace (*line))
+ line++;
+ if (!(rtn = strchr (line, '\n')))
+ return ("");
+ *rtn++ = '\0';
+
+ hr->type = line++;
+ (void) sscanf (line, "%x", &hr->date);
+ while (*line && strchr ("0123456789abcdefABCDEF", *line))
+ line++;
+ if (*line == '\0')
+ return (rtn);
+
+ line++;
+ NEXT_BAR (user);
+ NEXT_BAR (dir);
+ if ((cp = strrchr (hr->dir, '*')) != NULL)
+ {
+ *cp++ = '\0';
+ (void) sscanf (cp, "%x", &off);
+ hr->end = line + off;
+ }
+ else
+ hr->end = line - 1; /* A handy pointer to '\0' */
+ NEXT_BAR (repos);
+ NEXT_BAR (rev);
+ hr->idx = idx++;
+ if (strchr ("FOT", *(hr->type)))
+ hr->mod = line;
+
+ NEXT_BAR (file); /* This returns ptr to next line or final '\0' */
+ return (rtn); /* If it falls through, go on to next record */
+}
+
+/* read_hrecs's job is to read the history file and fill in all the "hrec"
+ * (history record) array elements with the ones we need to print.
+ *
+ * Logic:
+ * - Read the whole history file into a single buffer.
+ * - Walk through the buffer, parsing lines out of the buffer.
+ * 1. Split line into pointer and integer fields in the "next" hrec.
+ * 2. Apply tests to the hrec to see if it is wanted.
+ * 3. If it *is* wanted, bump the hrec pointer down by one.
+ */
+static void
+read_hrecs (fname)
+ char *fname;
+{
+ char *cp, *cp2;
+ int i, fd;
+ struct hrec *hr;
+ struct stat st_buf;
+
+ if ((fd = open (fname, O_RDONLY)) < 0)
+ error (1, errno, "cannot open history file: %s", fname);
+
+ if (fstat (fd, &st_buf) < 0)
+ error (1, errno, "can't stat history file");
+
+ /* Exactly enough space for lines data */
+ if (!(i = st_buf.st_size))
+ error (1, 0, "history file is empty");
+ cp = xmalloc (i + 2);
+
+ if (read (fd, cp, i) != i)
+ error (1, errno, "cannot read log file");
+ (void) close (fd);
+
+ if (*(cp + i - 1) != '\n')
+ {
+ *(cp + i) = '\n'; /* Make sure last line ends in '\n' */
+ i++;
+ }
+ *(cp + i) = '\0';
+ for (cp2 = cp; cp2 - cp < i; cp2++)
+ {
+ if (*cp2 != '\n' && !isprint (*cp2))
+ *cp2 = ' ';
+ }
+
+ hrec_max = HREC_INCREMENT;
+ hrec_head = (struct hrec *) xmalloc (hrec_max * sizeof (struct hrec));
+
+ while (*cp)
+ {
+ if (hrec_count == hrec_max)
+ {
+ struct hrec *old_head = hrec_head;
+
+ hrec_max += HREC_INCREMENT;
+ hrec_head = (struct hrec *) xrealloc ((char *) hrec_head,
+ hrec_max * sizeof (struct hrec));
+ if (hrec_head != old_head)
+ {
+ if (last_since_tag)
+ last_since_tag = hrec_head + (last_since_tag - old_head);
+ if (last_backto)
+ last_backto = hrec_head + (last_backto - old_head);
+ }
+ }
+
+ hr = hrec_head + hrec_count;
+ cp = fill_hrec (cp, hr); /* cp == next line or '\0' at end of buffer */
+
+ if (select_hrec (hr))
+ hrec_count++;
+ }
+
+ /* Special selection problem: If "since_tag" is set, we have saved every
+ * record from the 1st occurrence of "since_tag", when we want to save
+ * records since the *last* occurrence of "since_tag". So what we have
+ * to do is bump hrec_head forward and reduce hrec_count accordingly.
+ */
+ if (last_since_tag)
+ {
+ hrec_count -= (last_since_tag - hrec_head);
+ hrec_head = last_since_tag;
+ }
+
+ /* Much the same thing is necessary for the "backto" option. */
+ if (last_backto)
+ {
+ hrec_count -= (last_backto - hrec_head);
+ hrec_head = last_backto;
+ }
+}
+
+/* Utility program for determining whether "find" is inside "string" */
+static int
+within (find, string)
+ char *find, *string;
+{
+ int c, len;
+
+ if (!find || !string)
+ return (0);
+
+ c = *find++;
+ len = strlen (find);
+
+ while (*string)
+ {
+ if (!(string = strchr (string, c)))
+ return (0);
+ string++;
+ if (!strncmp (find, string, len))
+ return (1);
+ }
+ return (0);
+}
+
+/* The purpose of "select_hrec" is to apply the selection criteria based on
+ * the command arguments and defaults and return a flag indicating whether
+ * this record should be remembered for printing.
+ */
+static int
+select_hrec (hr)
+ struct hrec *hr;
+{
+ char **cpp, *cp, *cp2;
+ struct file_list_str *fl;
+ int count;
+
+ /* "Since" checking: The argument parser guarantees that only one of the
+ * following four choices is set:
+ *
+ * 1. If "since_date" is set, it contains a Unix time_t specified on the
+ * command line. hr->date fields earlier than "since_date" are ignored.
+ * 2. If "since_rev" is set, it contains either an RCS "dotted" revision
+ * number (which is of limited use) or a symbolic TAG. Each RCS file
+ * is examined and the date on the specified revision (or the revision
+ * corresponding to the TAG) in the RCS file (CVSROOT/repos/file) is
+ * compared against hr->date as in 1. above.
+ * 3. If "since_tag" is set, matching tag records are saved. The field
+ * "last_since_tag" is set to the last one of these. Since we don't
+ * know where the last one will be, all records are saved from the
+ * first occurrence of the TAG. Later, at the end of "select_hrec"
+ * records before the last occurrence of "since_tag" are skipped.
+ * 4. If "backto" is set, all records with a module name or file name
+ * matching "backto" are saved. In addition, all records with a
+ * repository field with a *prefix* matching "backto" are saved.
+ * The field "last_backto" is set to the last one of these. As in
+ * 3. above, "select_hrec" adjusts to include the last one later on.
+ */
+ if (since_date)
+ {
+ if (hr->date < since_date)
+ return (0);
+ }
+ else if (*since_rev)
+ {
+ Vers_TS *vers;
+ time_t t;
+
+ vers = Version_TS (hr->repos, (char *) NULL, since_rev, (char *) NULL,
+ hr->file, 1, 0, (List *) NULL, (List *) NULL);
+ if (vers->vn_rcs)
+ {
+ if ((t = RCS_getrevtime (vers->srcfile, vers->vn_rcs, (char *) 0, 0))
+ != (time_t) 0)
+ {
+ if (hr->date < t)
+ {
+ freevers_ts (&vers);
+ return (0);
+ }
+ }
+ }
+ freevers_ts (&vers);
+ }
+ else if (*since_tag)
+ {
+ if (*(hr->type) == 'T')
+ {
+ /*
+ * A 'T'ag record, the "rev" field holds the tag to be set,
+ * while the "repos" field holds "D"elete, "A"dd or a rev.
+ */
+ if (within (since_tag, hr->rev))
+ {
+ last_since_tag = hr;
+ return (1);
+ }
+ else
+ return (0);
+ }
+ if (!last_since_tag)
+ return (0);
+ }
+ else if (*backto)
+ {
+ if (within (backto, hr->file) || within (backto, hr->mod) ||
+ within (backto, hr->repos))
+ last_backto = hr;
+ else
+ return (0);
+ }
+
+ /* User checking:
+ *
+ * Run down "user_list", match username ("" matches anything)
+ * If "" is not there and actual username is not there, return failure.
+ */
+ if (user_list && hr->user)
+ {
+ for (cpp = user_list, count = user_count; count; cpp++, count--)
+ {
+ if (!**cpp)
+ break; /* null user == accept */
+ if (!strcmp (hr->user, *cpp)) /* found listed user */
+ break;
+ }
+ if (!count)
+ return (0); /* Not this user */
+ }
+
+ /* Record type checking:
+ *
+ * 1. If Record type is not in rec_types field, skip it.
+ * 2. If mod_list is null, keep everything. Otherwise keep only modules
+ * on mod_list.
+ * 3. If neither a 'T', 'F' nor 'O' record, run through "file_list". If
+ * file_list is null, keep everything. Otherwise, keep only files on
+ * file_list, matched appropriately.
+ */
+ if (!strchr (rec_types, *(hr->type)))
+ return (0);
+ if (!strchr ("TFO", *(hr->type))) /* Don't bother with "file" if "TFO" */
+ {
+ if (file_list) /* If file_list is null, accept all */
+ {
+ for (fl = file_list, count = file_count; count; fl++, count--)
+ {
+ /* 1. If file_list entry starts with '*', skip the '*' and
+ * compare it against the repository in the hrec.
+ * 2. If file_list entry has a '/' in it, compare it against
+ * the concatenation of the repository and file from hrec.
+ * 3. Else compare the file_list entry against the hrec file.
+ */
+ char cmpfile[PATH_MAX];
+
+ if (*(cp = fl->l_file) == '*')
+ {
+ cp++;
+ /* if argument to -p is a prefix of repository */
+ if (!strncmp (cp, hr->repos, strlen (cp)))
+ {
+ hr->mod = fl->l_module;
+ break;
+ }
+ }
+ else
+ {
+ if (strchr (cp, '/'))
+ {
+ (void) sprintf (cp2 = cmpfile, "%s/%s",
+ hr->repos, hr->file);
+ }
+ else
+ {
+ cp2 = hr->file;
+ }
+
+ /* if requested file is found within {repos}/file fields */
+ if (within (cp, cp2))
+ {
+ hr->mod = fl->l_module;
+ break;
+ }
+ }
+ }
+ if (!count)
+ return (0); /* String specified and no match */
+ }
+ }
+ if (mod_list)
+ {
+ for (cpp = mod_list, count = mod_count; count; cpp++, count--)
+ {
+ if (hr->mod && !strcmp (hr->mod, *cpp)) /* found module */
+ break;
+ }
+ if (!count)
+ return (0); /* Module specified & this record is not one of them. */
+ }
+
+ return (1); /* Select this record unless rejected above. */
+}
+
+/* The "sort_order" routine (when handed to qsort) has arranged for the
+ * hrecs files to be in the right order for the report.
+ *
+ * Most of the "selections" are done in the select_hrec routine, but some
+ * selections are more easily done after the qsort by "accept_hrec".
+ */
+static void
+report_hrecs ()
+{
+ struct hrec *hr, *lr;
+ struct tm *tm;
+ int i, count, ty;
+ char *cp;
+ int user_len, file_len, rev_len, mod_len, repos_len;
+
+ if (*since_tag && !last_since_tag)
+ {
+ (void) printf ("No tag found: %s\n", since_tag);
+ return;
+ }
+ else if (*backto && !last_backto)
+ {
+ (void) printf ("No module, file or repository with: %s\n", backto);
+ return;
+ }
+ else if (hrec_count < 1)
+ {
+ (void) printf ("No records selected.\n");
+ return;
+ }
+
+ user_len = file_len = rev_len = mod_len = repos_len = 0;
+
+ /* Run through lists and find maximum field widths */
+ hr = lr = hrec_head;
+ hr++;
+ for (count = hrec_count; count--; lr = hr, hr++)
+ {
+ char repos[PATH_MAX];
+
+ if (!count)
+ hr = NULL;
+ if (!accept_hrec (lr, hr))
+ continue;
+
+ ty = *(lr->type);
+ (void) strcpy (repos, lr->repos);
+ if ((cp = strrchr (repos, '/')) != NULL)
+ {
+ if (lr->mod && !strcmp (++cp, lr->mod))
+ {
+ (void) strcpy (cp, "*");
+ }
+ }
+ if ((i = strlen (lr->user)) > user_len)
+ user_len = i;
+ if ((i = strlen (lr->file)) > file_len)
+ file_len = i;
+ if (ty != 'T' && (i = strlen (repos)) > repos_len)
+ repos_len = i;
+ if (ty != 'T' && (i = strlen (lr->rev)) > rev_len)
+ rev_len = i;
+ if (lr->mod && (i = strlen (lr->mod)) > mod_len)
+ mod_len = i;
+ }
+
+ /* Walk through hrec array setting "lr" (Last Record) to each element.
+ * "hr" points to the record following "lr" -- It is NULL in the last
+ * pass.
+ *
+ * There are two sections in the loop below:
+ * 1. Based on the report type (e.g. extract, checkout, tag, etc.),
+ * decide whether the record should be printed.
+ * 2. Based on the record type, format and print the data.
+ */
+ for (lr = hrec_head, hr = (lr + 1); hrec_count--; lr = hr, hr++)
+ {
+ char workdir[PATH_MAX], repos[PATH_MAX];
+
+ if (!hrec_count)
+ hr = NULL;
+ if (!accept_hrec (lr, hr))
+ continue;
+
+ ty = *(lr->type);
+#ifdef HAVE_RCS5
+ if (!tz_local)
+ {
+ time_t t = lr->date + tz_seconds_east_of_GMT;
+ tm = gmtime (&t);
+ }
+ else
+#endif
+ tm = localtime (&(lr->date));
+ (void) printf ("%c %02d/%02d %02d:%02d %s %-*s", ty, tm->tm_mon + 1,
+ tm->tm_mday, tm->tm_hour, tm->tm_min, tz_name,
+ user_len, lr->user);
+
+ (void) sprintf (workdir, "%s%s", lr->dir, lr->end);
+ if ((cp = strrchr (workdir, '/')) != NULL)
+ {
+ if (lr->mod && !strcmp (++cp, lr->mod))
+ {
+ (void) strcpy (cp, "*");
+ }
+ }
+ (void) strcpy (repos, lr->repos);
+ if ((cp = strrchr (repos, '/')) != NULL)
+ {
+ if (lr->mod && !strcmp (++cp, lr->mod))
+ {
+ (void) strcpy (cp, "*");
+ }
+ }
+
+ switch (ty)
+ {
+ case 'T':
+ /* 'T'ag records: repository is a "tag type", rev is the tag */
+ (void) printf (" %-*s [%s:%s]", mod_len, lr->mod, lr->rev,
+ repos);
+ if (working)
+ (void) printf (" {%s}", workdir);
+ break;
+ case 'F':
+ case 'O':
+ if (lr->rev && *(lr->rev))
+ (void) printf (" [%s]", lr->rev);
+ (void) printf (" %-*s =%s%-*s %s", repos_len, repos, lr->mod,
+ mod_len + 1 - strlen (lr->mod), "=", workdir);
+ break;
+ case 'W':
+ case 'U':
+ case 'C':
+ case 'G':
+ case 'M':
+ case 'A':
+ case 'R':
+ (void) printf (" %-*s %-*s %-*s =%s= %s", rev_len, lr->rev,
+ file_len, lr->file, repos_len, repos,
+ lr->mod ? lr->mod : "", workdir);
+ break;
+ default:
+ (void) printf ("Hey! What is this junk? RecType[0x%2.2x]", ty);
+ break;
+ }
+ (void) putchar ('\n');
+ }
+}
+
+static int
+accept_hrec (lr, hr)
+ struct hrec *hr, *lr;
+{
+ int ty;
+
+ ty = *(lr->type);
+
+ if (last_since_tag && ty == 'T')
+ return (1);
+
+ if (v_checkout)
+ {
+ if (ty != 'O')
+ return (0); /* Only interested in 'O' records */
+
+ /* We want to identify all the states that cause the next record
+ * ("hr") to be different from the current one ("lr") and only
+ * print a line at the allowed boundaries.
+ */
+
+ if (!hr || /* The last record */
+ strcmp (hr->user, lr->user) || /* User has changed */
+ strcmp (hr->mod, lr->mod) ||/* Module has changed */
+ (working && /* If must match "workdir" */
+ (strcmp (hr->dir, lr->dir) || /* and the 1st parts or */
+ strcmp (hr->end, lr->end)))) /* the 2nd parts differ */
+
+ return (1);
+ }
+ else if (modified)
+ {
+ if (!last_entry || /* Don't want only last rec */
+ !hr || /* Last entry is a "last entry" */
+ strcmp (hr->repos, lr->repos) || /* Repository has changed */
+ strcmp (hr->file, lr->file))/* File has changed */
+ return (1);
+
+ if (working)
+ { /* If must match "workdir" */
+ if (strcmp (hr->dir, lr->dir) || /* and the 1st parts or */
+ strcmp (hr->end, lr->end)) /* the 2nd parts differ */
+ return (1);
+ }
+ }
+ else if (module_report)
+ {
+ if (!last_entry || /* Don't want only last rec */
+ !hr || /* Last entry is a "last entry" */
+ strcmp (hr->mod, lr->mod) ||/* Module has changed */
+ strcmp (hr->repos, lr->repos) || /* Repository has changed */
+ strcmp (hr->file, lr->file))/* File has changed */
+ return (1);
+ }
+ else
+ {
+ /* "extract" and "tag_report" always print selected records. */
+ return (1);
+ }
+
+ return (0);
+}
diff --git a/gnu/usr.bin/cvs/cvs/ignore.c b/gnu/usr.bin/cvs/cvs/ignore.c
new file mode 100644
index 0000000..f70fe78
--- /dev/null
+++ b/gnu/usr.bin/cvs/cvs/ignore.c
@@ -0,0 +1,286 @@
+/*
+ * .cvsignore file support contributed by David G. Grubbs <dgg@odi.com>
+ */
+
+#include "cvs.h"
+
+#ifndef lint
+static const char rcsid[] = "$CVSid: @(#)ignore.c 1.16 94/09/24 $";
+USE(rcsid);
+#endif
+
+/*
+ * Ignore file section.
+ *
+ * "!" may be included any time to reset the list (i.e. ignore nothing);
+ * "*" may be specified to ignore everything. It stays as the first
+ * element forever, unless a "!" clears it out.
+ */
+
+static char **ign_list; /* List of files to ignore in update
+ * and import */
+static char **s_ign_list = NULL;
+static int ign_count; /* Number of active entries */
+static int s_ign_count = 0;
+static int ign_size; /* This many slots available (plus
+ * one for a NULL) */
+static int ign_hold; /* Index where first "temporary" item
+ * is held */
+
+const char *ign_default = ". .. core RCSLOG tags TAGS RCS SCCS .make.state .nse_depinfo #* .#* cvslog.* ,* CVS* .del-* *.a *.o *.so *.Z *~ *.old *.elc *.ln *.bak *.BAK *.orig *.rej";
+
+#define IGN_GROW 16 /* grow the list by 16 elements at a
+ * time */
+
+/*
+ * To the "ignore list", add the hard-coded default ignored wildcards above,
+ * the wildcards found in $CVSROOT/CVSROOT/cvsignore, the wildcards found in
+ * ~/.cvsignore and the wildcards found in the CVSIGNORE environment
+ * variable.
+ */
+void
+ign_setup ()
+{
+ struct passwd *pw;
+ char file[PATH_MAX];
+ char *tmp;
+
+ /* Start with default list and special case */
+ tmp = xstrdup (ign_default);
+ ign_add (tmp, 0);
+ free (tmp);
+
+#ifdef CLIENT_SUPPORT
+ /* Chances are we should have some way to provide this feature
+ client/server, but I'm not sure how (surely not by introducing
+ another network turnaround to each operation--perhaps by
+ putting a file in the CVS directory on checkout, or with some
+ sort of "slave cvsroot" on the client). */
+ if (!client_active)
+#endif
+ {
+ /* Then add entries found in repository, if it exists */
+ (void) sprintf (file, "%s/%s/%s", CVSroot, CVSROOTADM,
+ CVSROOTADM_IGNORE);
+ ign_add_file (file, 0);
+ }
+
+ /* Then add entries found in home dir, (if user has one) and file exists */
+ if ((pw = (struct passwd *) getpwuid (getuid ())) && pw->pw_dir)
+ {
+ (void) sprintf (file, "%s/%s", pw->pw_dir, CVSDOTIGNORE);
+ ign_add_file (file, 0);
+ }
+
+ /* Then add entries found in CVSIGNORE environment variable. */
+ ign_add (getenv (IGNORE_ENV), 0);
+
+ /* Later, add ignore entries found in -I arguments */
+}
+
+/*
+ * Open a file and read lines, feeding each line to a line parser. Arrange
+ * for keeping a temporary list of wildcards at the end, if the "hold"
+ * argument is set.
+ */
+void
+ign_add_file (file, hold)
+ char *file;
+ int hold;
+{
+ FILE *fp;
+ char line[1024];
+
+ /* restore the saved list (if any) */
+ if (s_ign_list != NULL)
+ {
+ int i;
+
+ for (i = 0; i < s_ign_count; i++)
+ ign_list[i] = s_ign_list[i];
+ ign_count = s_ign_count;
+ ign_list[ign_count] = NULL;
+
+ s_ign_count = 0;
+ free (s_ign_list);
+ s_ign_list = NULL;
+ }
+
+ /* is this a temporary ignore file? */
+ if (hold)
+ {
+ /* re-set if we had already done a temporary file */
+ if (ign_hold)
+ {
+ int i;
+
+ for (i = ign_hold; i < ign_count; i++)
+ free (ign_list[i]);
+ ign_count = ign_hold;
+ ign_list[ign_count] = NULL;
+ }
+ else
+ {
+ ign_hold = ign_count;
+ }
+ }
+
+ /* load the file */
+ fp = fopen (file, "r");
+ if (fp == NULL)
+ {
+ if (! existence_error (errno))
+ error (0, errno, "cannot open %s", file);
+ return;
+ }
+ while (fgets (line, sizeof (line), fp))
+ ign_add (line, hold);
+ if (fclose (fp) < 0)
+ error (0, errno, "cannot close %s", file);
+}
+
+/* Parse a line of space-separated wildcards and add them to the list. */
+void
+ign_add (ign, hold)
+ char *ign;
+ int hold;
+{
+ if (!ign || !*ign)
+ return;
+
+ for (; *ign; ign++)
+ {
+ char *mark;
+ char save;
+
+ /* ignore whitespace before the token */
+ if (isspace (*ign))
+ continue;
+
+ /*
+ * if we find a single character !, we must re-set the ignore list
+ * (saving it if necessary). We also catch * as a special case in a
+ * global ignore file as an optimization
+ */
+ if ((!*(ign+1) || isspace (*(ign+1))) && (*ign == '!' || *ign == '*'))
+ {
+ if (!hold)
+ {
+ /* permanently reset the ignore list */
+ int i;
+
+ for (i = 0; i < ign_count; i++)
+ free (ign_list[i]);
+ ign_count = 0;
+ ign_list[0] = NULL;
+
+ /* if we are doing a '!', continue; otherwise add the '*' */
+ if (*ign == '!')
+ continue;
+ }
+ else if (*ign == '!')
+ {
+ /* temporarily reset the ignore list */
+ int i;
+
+ if (ign_hold)
+ {
+ for (i = ign_hold; i < ign_count; i++)
+ free (ign_list[i]);
+ ign_hold = 0;
+ }
+ s_ign_list = (char **) xmalloc (ign_count * sizeof (char *));
+ for (i = 0; i < ign_count; i++)
+ s_ign_list[i] = ign_list[i];
+ s_ign_count = ign_count;
+ ign_count = 0;
+ ign_list[0] = NULL;
+ continue;
+ }
+ }
+
+ /* If we have used up all the space, add some more */
+ if (ign_count >= ign_size)
+ {
+ ign_size += IGN_GROW;
+ ign_list = (char **) xrealloc ((char *) ign_list,
+ (ign_size + 1) * sizeof (char *));
+ }
+
+ /* find the end of this token */
+ for (mark = ign; *mark && !isspace (*mark); mark++)
+ /* do nothing */ ;
+
+ save = *mark;
+ *mark = '\0';
+
+ ign_list[ign_count++] = xstrdup (ign);
+ ign_list[ign_count] = NULL;
+
+ *mark = save;
+ if (save)
+ ign = mark;
+ else
+ ign = mark - 1;
+ }
+}
+
+/* Return 1 if the given filename should be ignored by update or import. */
+int
+ign_name (name)
+ char *name;
+{
+ char **cpp = ign_list;
+
+ if (cpp == NULL)
+ return (0);
+
+ while (*cpp)
+ if (fnmatch (*cpp++, name, 0) == 0)
+ return (1);
+ return (0);
+}
+
+
+static char **dir_ign_list = NULL;
+static int dir_ign_max = 0;
+static int dir_ign_current = 0;
+
+/* add a directory to list of dirs to ignore */
+void ign_dir_add (name)
+ char *name;
+{
+ /* make sure we've got the space for the entry */
+ if (dir_ign_current <= dir_ign_max)
+ {
+ dir_ign_max += IGN_GROW;
+ dir_ign_list = (char **) xrealloc ((char *) dir_ign_list, (dir_ign_max+1) * sizeof(char*));
+ }
+
+ dir_ign_list[dir_ign_current] = name;
+
+ dir_ign_current += 1 ;
+}
+
+
+/* this function returns 1 (true) if the given directory name is part of
+ * the list of directories to ignore
+ */
+
+int ignore_directory (name)
+ char *name;
+{
+ int i;
+
+ if (!dir_ign_list)
+ return 0;
+
+ i = dir_ign_current;
+ while (i--)
+ {
+ if (strncmp(name, dir_ign_list[i], strlen(dir_ign_list[i])) == 0)
+ return 1;
+ }
+
+ return 0;
+}
diff --git a/gnu/usr.bin/cvs/cvs/import.c b/gnu/usr.bin/cvs/cvs/import.c
new file mode 100644
index 0000000..9980763
--- /dev/null
+++ b/gnu/usr.bin/cvs/cvs/import.c
@@ -0,0 +1,1181 @@
+/*
+ * Copyright (c) 1992, Brian Berliner and Jeff Polk
+ * Copyright (c) 1989-1992, Brian Berliner
+ *
+ * You may distribute under the terms of the GNU General Public License as
+ * specified in the README file that comes with the CVS 1.4 kit.
+ *
+ * "import" checks in the vendor release located in the current directory into
+ * the CVS source repository. The CVS vendor branch support is utilized.
+ *
+ * At least three arguments are expected to follow the options:
+ * repository Where the source belongs relative to the CVSROOT
+ * VendorTag Vendor's major tag
+ * VendorReleTag Tag for this particular release
+ *
+ * Additional arguments specify more Vendor Release Tags.
+ */
+
+#include "cvs.h"
+#include "save-cwd.h"
+
+#ifndef lint
+static const char rcsid[] = "$CVSid: @(#)import.c 1.63 94/09/30 $";
+USE(rcsid);
+#endif
+
+#define FILE_HOLDER ".#cvsxxx"
+
+static char *get_comment PROTO((char *user));
+static int add_rcs_file PROTO((char *message, char *rcs, char *user, char *vtag,
+ int targc, char *targv[]));
+static int expand_at_signs PROTO((char *buf, off_t size, FILE *fp));
+static int add_rev PROTO((char *message, char *rcs, char *vfile, char *vers));
+static int add_tags PROTO((char *rcs, char *vfile, char *vtag, int targc,
+ char *targv[]));
+static int import_descend PROTO((char *message, char *vtag, int targc, char *targv[]));
+static int import_descend_dir PROTO((char *message, char *dir, char *vtag,
+ int targc, char *targv[]));
+static int process_import_file PROTO((char *message, char *vfile, char *vtag,
+ int targc, char *targv[]));
+static int update_rcs_file PROTO((char *message, char *vfile, char *vtag, int targc,
+ char *targv[], int inattic));
+static void add_log PROTO((int ch, char *fname));
+
+static int repos_len;
+static char vhead[50];
+static char vbranch[50];
+static FILE *logfp;
+static char repository[PATH_MAX];
+static int conflicts;
+static int use_file_modtime;
+static char *keyword_opt = NULL;
+
+static const char *const import_usage[] =
+{
+ "Usage: %s %s [-d] [-k subst] [-I ign] [-m msg] [-b branch]\n",
+ " [-W spec] repository vendor-tag release-tags...\n",
+ "\t-d\tUse the file's modification time as the time of import.\n",
+ "\t-k sub\tSet default RCS keyword substitution mode.\n",
+ "\t-I ign\tMore files to ignore (! to reset).\n",
+ "\t-b bra\tVendor branch id.\n",
+ "\t-m msg\tLog message.\n",
+ "\t-W spec\tWrappers specification line.\n",
+ NULL
+};
+
+int
+import (argc, argv)
+ int argc;
+ char **argv;
+{
+ char *message = NULL;
+ char tmpfile[L_tmpnam+1];
+ char *cp;
+ int i, c, msglen, err;
+ List *ulist;
+ Node *p;
+
+ if (argc == -1)
+ usage (import_usage);
+
+ ign_setup ();
+ wrap_setup ();
+
+ (void) strcpy (vbranch, CVSBRANCH);
+ optind = 1;
+ while ((c = getopt (argc, argv, "Qqdb:m:I:k:W:")) != -1)
+ {
+ switch (c)
+ {
+ case 'Q':
+ case 'q':
+#ifdef SERVER_SUPPORT
+ /* The CVS 1.5 client sends these options (in addition to
+ Global_option requests), so we must ignore them. */
+ if (!server_active)
+#endif
+ error (1, 0,
+ "-q or -Q must be specified before \"%s\"",
+ command_name);
+ break;
+ case 'd':
+ use_file_modtime = 1;
+ break;
+ case 'b':
+ (void) strcpy (vbranch, optarg);
+ break;
+ case 'm':
+#ifdef FORCE_USE_EDITOR
+ use_editor = TRUE;
+#else
+ use_editor = FALSE;
+#endif
+ message = xstrdup(optarg);
+ break;
+ case 'I':
+ ign_add (optarg, 0);
+ break;
+ case 'k':
+ /* RCS_check_kflag returns strings of the form -kxx. We
+ only use it for validation, so we can free the value
+ as soon as it is returned. */
+ free (RCS_check_kflag(optarg));
+ keyword_opt = optarg;
+ break;
+ case 'W':
+ wrap_add (optarg, 0);
+ break;
+ case '?':
+ default:
+ usage (import_usage);
+ break;
+ }
+ }
+ argc -= optind;
+ argv += optind;
+ if (argc < 3)
+ usage (import_usage);
+
+ for (i = 1; i < argc; i++) /* check the tags for validity */
+ RCS_check_tag (argv[i]);
+
+ /* XXX - this should be a module, not just a pathname */
+ if (! isabsolute (argv[0]))
+ {
+ if (CVSroot == NULL)
+ {
+ error (0, 0, "missing CVSROOT environment variable\n");
+ error (1, 0, "Set it or specify the '-d' option to %s.",
+ program_name);
+ }
+ (void) sprintf (repository, "%s/%s", CVSroot, argv[0]);
+ repos_len = strlen (CVSroot);
+ }
+ else
+ {
+ (void) strcpy (repository, argv[0]);
+ repos_len = 0;
+ }
+
+ /*
+ * Consistency checks on the specified vendor branch. It must be
+ * composed of only numbers and dots ('.'). Also, for now we only
+ * support branching to a single level, so the specified vendor branch
+ * must only have two dots in it (like "1.1.1").
+ */
+ for (cp = vbranch; *cp != '\0'; cp++)
+ if (!isdigit (*cp) && *cp != '.')
+ error (1, 0, "%s is not a numeric branch", vbranch);
+ if (numdots (vbranch) != 2)
+ error (1, 0, "Only branches with two dots are supported: %s", vbranch);
+ (void) strcpy (vhead, vbranch);
+ cp = strrchr (vhead, '.');
+ *cp = '\0';
+
+#ifdef CLIENT_SUPPORT
+ if (client_active)
+ {
+ /* Do this now; don't ask for a log message if we can't talk to the
+ server. But if there is a syntax error in the options, give
+ an error message without connecting. */
+ start_server ();
+ }
+#endif
+
+ if (use_editor)
+ {
+ do_editor ((char *) NULL, &message, repository,
+ (List *) NULL);
+ }
+
+ msglen = message == NULL ? 0 : strlen (message);
+ if (msglen == 0 || message[msglen - 1] != '\n')
+ {
+ char *nm = xmalloc (msglen + 2);
+ if (message != NULL)
+ {
+ (void) strcpy (nm, message);
+ free (message);
+ }
+ (void) strcat (nm + msglen, "\n");
+ message = nm;
+ }
+
+#ifdef CLIENT_SUPPORT
+ if (client_active)
+ {
+ int err;
+
+ ign_setup ();
+
+ if (use_file_modtime)
+ send_arg("-d");
+
+ if (vbranch[0] != '\0')
+ option_with_arg ("-b", vbranch);
+ if (message)
+ option_with_arg ("-m", message);
+ if (keyword_opt != NULL)
+ option_with_arg ("-k", keyword_opt);
+
+ {
+ int i;
+ for (i = 0; i < argc; ++i)
+ send_arg (argv[i]);
+ }
+
+ logfp = stdin;
+ client_import_setup (repository);
+ err = import_descend (message, argv[1], argc - 2, argv + 2);
+ client_import_done ();
+ if (fprintf (to_server, "import\n") < 0)
+ error (1, errno, "writing to server");
+ err += get_responses_and_close ();
+ return err;
+ }
+#endif
+
+ /*
+ * Make all newly created directories writable. Should really use a more
+ * sophisticated security mechanism here.
+ */
+ (void) umask (cvsumask);
+ make_directories (repository);
+
+ /* Create the logfile that will be logged upon completion */
+ if ((logfp = fopen (tmpnam (tmpfile), "w+")) == NULL)
+ error (1, errno, "cannot create temporary file `%s'", tmpfile);
+ (void) unlink (tmpfile); /* to be sure it goes away */
+ (void) fprintf (logfp, "\nVendor Tag:\t%s\n", argv[1]);
+ (void) fprintf (logfp, "Release Tags:\t");
+ for (i = 2; i < argc; i++)
+ (void) fprintf (logfp, "%s\n\t\t", argv[i]);
+ (void) fprintf (logfp, "\n");
+
+ /* Just Do It. */
+ err = import_descend (message, argv[1], argc - 2, argv + 2);
+ if (conflicts)
+ {
+ if (!really_quiet)
+ {
+ (void) printf ("\n%d conflicts created by this import.\n",
+ conflicts);
+ (void) printf ("Use the following command to help the merge:\n\n");
+ (void) printf ("\t%s checkout -j%s:yesterday -j%s %s\n\n",
+ program_name, argv[1], argv[1], argv[0]);
+ }
+
+ (void) fprintf (logfp, "\n%d conflicts created by this import.\n",
+ conflicts);
+ (void) fprintf (logfp,
+ "Use the following command to help the merge:\n\n");
+ (void) fprintf (logfp, "\t%s checkout -j%s:yesterday -j%s %s\n\n",
+ program_name, argv[1], argv[1], argv[0]);
+ }
+ else
+ {
+ if (!really_quiet)
+ (void) printf ("\nNo conflicts created by this import\n\n");
+ (void) fprintf (logfp, "\nNo conflicts created by this import\n\n");
+ }
+
+ /*
+ * Write out the logfile and clean up.
+ */
+ ulist = getlist ();
+ p = getnode ();
+ p->type = UPDATE;
+ p->delproc = update_delproc;
+ p->key = xstrdup ("- Imported sources");
+ p->data = (char *) T_TITLE;
+ (void) addnode (ulist, p);
+ Update_Logfile (repository, message, vbranch, logfp, ulist);
+ dellist (&ulist);
+ (void) fclose (logfp);
+
+ /* Make sure the temporary file goes away, even on systems that don't let
+ you delete a file that's in use. */
+ unlink (tmpfile);
+
+ if (message)
+ free (message);
+
+ return (err);
+}
+
+/*
+ * process all the files in ".", then descend into other directories.
+ */
+static int
+import_descend (message, vtag, targc, targv)
+ char *message;
+ char *vtag;
+ int targc;
+ char *targv[];
+{
+ DIR *dirp;
+ struct dirent *dp;
+ int err = 0;
+ List *dirlist = NULL;
+
+ /* first, load up any per-directory ignore lists */
+ ign_add_file (CVSDOTIGNORE, 1);
+ wrap_add_file (CVSDOTWRAPPER, 1);
+
+ if ((dirp = opendir (".")) == NULL)
+ {
+ err++;
+ }
+ else
+ {
+ while ((dp = readdir (dirp)) != NULL)
+ {
+ if (strcmp (dp->d_name, ".") == 0 || strcmp (dp->d_name, "..") == 0)
+ continue;
+ if (ign_name (dp->d_name))
+ {
+#ifdef SERVER_SUPPORT
+ /* CVS directories are created by server.c because it doesn't
+ special-case import. So don't print a message about them.
+ Do print a message about other ignored files (although
+ most of these will get ignored on the client side). */
+ if (server_active && strcmp (dp->d_name, CVSADM) == 0)
+ continue;
+#endif
+ add_log ('I', dp->d_name);
+ continue;
+ }
+
+ if (
+#ifdef DT_DIR
+ (dp->d_type == DT_DIR
+ || (dp->d_type == DT_UNKNOWN && isdir (dp->d_name)))
+#else
+ isdir (dp->d_name)
+#endif
+ && !wrap_name_has (dp->d_name, WRAP_TOCVS)
+ )
+ {
+ Node *n;
+
+ if (dirlist == NULL)
+ dirlist = getlist();
+
+ n = getnode();
+ n->key = xstrdup (dp->d_name);
+ addnode(dirlist, n);
+ }
+ else if (
+#ifdef DT_DIR
+ dp->d_type == DT_LNK || dp->d_type == DT_UNKNOWN &&
+#endif
+ islink (dp->d_name))
+ {
+ add_log ('L', dp->d_name);
+ err++;
+ }
+ else
+ {
+#ifdef CLIENT_SUPPORT
+ if (client_active)
+ err += client_process_import_file (message, dp->d_name,
+ vtag, targc, targv,
+ repository);
+ else
+#endif
+ err += process_import_file (message, dp->d_name,
+ vtag, targc, targv);
+ }
+ }
+ (void) closedir (dirp);
+ }
+
+ if (dirlist != NULL)
+ {
+ Node *head, *p;
+
+ head = dirlist->list;
+ for (p = head->next; p != head; p = p->next)
+ {
+ err += import_descend_dir (message, p->key, vtag, targc, targv);
+ }
+
+ dellist(&dirlist);
+ }
+
+ return (err);
+}
+
+/*
+ * Process the argument import file.
+ */
+static int
+process_import_file (message, vfile, vtag, targc, targv)
+ char *message;
+ char *vfile;
+ char *vtag;
+ int targc;
+ char *targv[];
+{
+ char attic_name[PATH_MAX];
+ char rcs[PATH_MAX];
+ int inattic = 0;
+
+ (void) sprintf (rcs, "%s/%s%s", repository, vfile, RCSEXT);
+ if (!isfile (rcs))
+ {
+ (void) sprintf (attic_name, "%s/%s/%s%s", repository, CVSATTIC,
+ vfile, RCSEXT);
+ if (!isfile (attic_name))
+ {
+
+ /*
+ * A new import source file; it doesn't exist as a ,v within the
+ * repository nor in the Attic -- create it anew.
+ */
+ add_log ('N', vfile);
+ return (add_rcs_file (message, rcs, vfile, vtag, targc, targv));
+ }
+ inattic = 1;
+ }
+
+ /*
+ * an rcs file exists. have to do things the official, slow, way.
+ */
+ return (update_rcs_file (message, vfile, vtag, targc, targv, inattic));
+}
+
+/*
+ * The RCS file exists; update it by adding the new import file to the
+ * (possibly already existing) vendor branch.
+ */
+static int
+update_rcs_file (message, vfile, vtag, targc, targv, inattic)
+ char *message;
+ char *vfile;
+ char *vtag;
+ int targc;
+ char *targv[];
+ int inattic;
+{
+ Vers_TS *vers;
+ int letter;
+ int ierrno;
+ char *tmpdir;
+ char *tocvsPath;
+
+ vers = Version_TS (repository, (char *) NULL, vbranch, (char *) NULL, vfile,
+ 1, 0, (List *) NULL, (List *) NULL);
+#ifdef DEATH_SUPPORT
+ if (vers->vn_rcs != NULL
+ && !RCS_isdead(vers->srcfile, vers->vn_rcs))
+#else
+ if (vers->vn_rcs != NULL)
+#endif
+ {
+ char xtmpfile[PATH_MAX];
+ int different;
+ int retcode = 0;
+
+ tmpdir = getenv ("TMPDIR");
+ if (tmpdir == NULL || tmpdir[0] == '\0')
+ tmpdir = "/tmp";
+
+ (void) sprintf (xtmpfile, "%s/cvs-imp%d", tmpdir, getpid());
+
+ /*
+ * The rcs file does have a revision on the vendor branch. Compare
+ * this revision with the import file; if they match exactly, there
+ * is no need to install the new import file as a new revision to the
+ * branch. Just tag the revision with the new import tags.
+ *
+ * This is to try to cut down the number of "C" conflict messages for
+ * locally modified import source files.
+ */
+#ifdef HAVE_RCS5
+ run_setup ("%s%s -q -f -r%s -p -ko", Rcsbin, RCS_CO, vers->vn_rcs);
+#else
+ run_setup ("%s%s -q -f -r%s -p", Rcsbin, RCS_CO, vers->vn_rcs);
+#endif
+ run_arg (vers->srcfile->path);
+ if ((retcode = run_exec (RUN_TTY, xtmpfile, RUN_TTY,
+ RUN_NORMAL|RUN_REALLY)) != 0)
+ {
+ ierrno = errno;
+ fperror (logfp, 0, retcode == -1 ? ierrno : 0,
+ "ERROR: cannot co revision %s of file %s", vers->vn_rcs,
+ vers->srcfile->path);
+ error (0, retcode == -1 ? ierrno : 0,
+ "ERROR: cannot co revision %s of file %s", vers->vn_rcs,
+ vers->srcfile->path);
+ (void) unlink_file (xtmpfile);
+ return (1);
+ }
+
+ tocvsPath = wrap_tocvs_process_file (vfile);
+ different = xcmp (xtmpfile, vfile);
+ if (tocvsPath)
+ if (unlink_file_dir (tocvsPath) < 0)
+ error (0, errno, "cannot remove %s", tocvsPath);
+
+ (void) unlink_file (xtmpfile);
+ if (!different)
+ {
+ int retval = 0;
+
+ /*
+ * The two files are identical. Just update the tags, print the
+ * "U", signifying that the file has changed, but needs no
+ * attention, and we're done.
+ */
+ if (add_tags (vers->srcfile->path, vfile, vtag, targc, targv))
+ retval = 1;
+ add_log ('U', vfile);
+ freevers_ts (&vers);
+ return (retval);
+ }
+ }
+
+ /* We may have failed to parse the RCS file; check just in case */
+ if (vers->srcfile == NULL ||
+ add_rev (message, vers->srcfile->path, vfile, vers->vn_rcs) ||
+ add_tags (vers->srcfile->path, vfile, vtag, targc, targv))
+ {
+ freevers_ts (&vers);
+ return (1);
+ }
+
+ if (vers->srcfile->branch == NULL || inattic ||
+ strcmp (vers->srcfile->branch, vbranch) != 0)
+ {
+ conflicts++;
+ letter = 'C';
+ }
+ else
+ letter = 'U';
+ add_log (letter, vfile);
+
+ freevers_ts (&vers);
+ return (0);
+}
+
+/*
+ * Add the revision to the vendor branch
+ */
+static int
+add_rev (message, rcs, vfile, vers)
+ char *message;
+ char *rcs;
+ char *vfile;
+ char *vers;
+{
+ int locked, status, ierrno;
+ char *tocvsPath;
+ struct stat vfile_stat;
+
+ if (noexec)
+ return (0);
+
+ locked = 0;
+ if (vers != NULL)
+ {
+ /* Before RCS_lock existed, we were directing stdout, as well as
+ stderr, from the RCS command, to DEVNULL. I wouldn't guess that
+ was necessary, but I don't know for sure. */
+ if (RCS_lock (rcs, vbranch, 1) != 0)
+ {
+ error (0, errno, "fork failed");
+ return (1);
+ }
+ locked = 1;
+ }
+ tocvsPath = wrap_tocvs_process_file (vfile);
+
+ /* We used to deposit the revision with -r; RCS would delete the
+ working file, but we'd keep a hard link to it, and rename it
+ back after running RCS (ooh, atomicity). However, that
+ strategy doesn't work on operating systems without hard links
+ (like Windows NT). Instead, let's deposit it using -u, and
+ restore its permission bits afterwards. This also means the
+ file always exists under its own name. */
+ if (! tocvsPath)
+ stat (vfile, &vfile_stat);
+
+ run_setup ("%s%s -q -f %s%s", Rcsbin, RCS_CI,
+ (tocvsPath ? "-r" : "-u"),
+ vbranch);
+ run_args ("-m%s", make_message_rcslegal (message));
+ if (use_file_modtime)
+ run_arg ("-d");
+ run_arg (tocvsPath == NULL ? vfile : tocvsPath);
+ run_arg (rcs);
+ status = run_exec (RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL);
+ ierrno = errno;
+
+ /* Restore the permissions on vfile. */
+ if (! tocvsPath)
+ chmod (vfile, vfile_stat.st_mode);
+
+ if (status)
+ {
+ if (!noexec)
+ {
+ fperror (logfp, 0, status == -1 ? ierrno : 0, "ERROR: Check-in of %s failed", rcs);
+ error (0, status == -1 ? ierrno : 0, "ERROR: Check-in of %s failed", rcs);
+ }
+ if (locked)
+ {
+ (void) RCS_unlock(rcs, vbranch, 0);
+ }
+ return (1);
+ }
+ return (0);
+}
+
+/*
+ * Add the vendor branch tag and all the specified import release tags to the
+ * RCS file. The vendor branch tag goes on the branch root (1.1.1) while the
+ * vendor release tags go on the newly added leaf of the branch (1.1.1.1,
+ * 1.1.1.2, ...).
+ */
+static int
+add_tags (rcs, vfile, vtag, targc, targv)
+ char *rcs;
+ char *vfile;
+ char *vtag;
+ int targc;
+ char *targv[];
+{
+ int i, ierrno;
+ Vers_TS *vers;
+ int retcode = 0;
+
+ if (noexec)
+ return (0);
+
+ if ((retcode = RCS_settag(rcs, vtag, vbranch)) != 0)
+ {
+ ierrno = errno;
+ fperror (logfp, 0, retcode == -1 ? ierrno : 0,
+ "ERROR: Failed to set tag %s in %s", vtag, rcs);
+ error (0, retcode == -1 ? ierrno : 0,
+ "ERROR: Failed to set tag %s in %s", vtag, rcs);
+ return (1);
+ }
+ vers = Version_TS (repository, (char *) NULL, vtag, (char *) NULL, vfile,
+ 1, 0, (List *) NULL, (List *) NULL);
+ for (i = 0; i < targc; i++)
+ {
+ if ((retcode = RCS_settag (rcs, targv[i], vers->vn_rcs)) != 0)
+ {
+ ierrno = errno;
+ fperror (logfp, 0, retcode == -1 ? ierrno : 0,
+ "WARNING: Couldn't add tag %s to %s", targv[i], rcs);
+ error (0, retcode == -1 ? ierrno : 0,
+ "WARNING: Couldn't add tag %s to %s", targv[i], rcs);
+ }
+ }
+ freevers_ts (&vers);
+ return (0);
+}
+
+/*
+ * Stolen from rcs/src/rcsfnms.c, and adapted/extended.
+ */
+struct compair
+{
+ char *suffix, *comlead;
+};
+
+static const struct compair comtable[] =
+{
+
+/*
+ * comtable pairs each filename suffix with a comment leader. The comment
+ * leader is placed before each line generated by the $Log keyword. This
+ * table is used to guess the proper comment leader from the working file's
+ * suffix during initial ci (see InitAdmin()). Comment leaders are needed for
+ * languages without multiline comments; for others they are optional.
+ */
+ {"a", "-- "}, /* Ada */
+ {"ada", "-- "},
+ {"adb", "-- "},
+ {"asm", ";; "}, /* assembler (MS-DOS) */
+ {"ads", "-- "}, /* Ada */
+ {"bat", ":: "}, /* batch (MS-DOS) */
+ {"body", "-- "}, /* Ada */
+ {"c", " * "}, /* C */
+ {"c++", "// "}, /* C++ in all its infinite guises */
+ {"cc", "// "},
+ {"cpp", "// "},
+ {"cxx", "// "},
+ {"m", "// "}, /* Objective-C */
+ {"cl", ";;; "}, /* Common Lisp */
+ {"cmd", ":: "}, /* command (OS/2) */
+ {"cmf", "c "}, /* CM Fortran */
+ {"cs", " * "}, /* C* */
+ {"csh", "# "}, /* shell */
+ {"e", "# "}, /* efl */
+ {"epsf", "% "}, /* encapsulated postscript */
+ {"epsi", "% "}, /* encapsulated postscript */
+ {"el", "; "}, /* Emacs Lisp */
+ {"f", "c "}, /* Fortran */
+ {"for", "c "},
+ {"h", " * "}, /* C-header */
+ {"hh", "// "}, /* C++ header */
+ {"hpp", "// "},
+ {"hxx", "// "},
+ {"in", "# "}, /* for Makefile.in */
+ {"l", " * "}, /* lex (conflict between lex and
+ * franzlisp) */
+ {"mac", ";; "}, /* macro (DEC-10, MS-DOS, PDP-11,
+ * VMS, etc) */
+ {"me", ".\\\" "}, /* me-macros t/nroff */
+ {"ml", "; "}, /* mocklisp */
+ {"mm", ".\\\" "}, /* mm-macros t/nroff */
+ {"ms", ".\\\" "}, /* ms-macros t/nroff */
+ {"man", ".\\\" "}, /* man-macros t/nroff */
+ {"1", ".\\\" "}, /* feeble attempt at man pages... */
+ {"2", ".\\\" "},
+ {"3", ".\\\" "},
+ {"4", ".\\\" "},
+ {"5", ".\\\" "},
+ {"6", ".\\\" "},
+ {"7", ".\\\" "},
+ {"8", ".\\\" "},
+ {"9", ".\\\" "},
+ {"p", " * "}, /* pascal */
+ {"pas", " * "},
+ {"pl", "# "}, /* perl (conflict with Prolog) */
+ {"ps", "% "}, /* postscript */
+ {"psw", "% "}, /* postscript wrap */
+ {"pswm", "% "}, /* postscript wrap */
+ {"r", "# "}, /* ratfor */
+ {"red", "% "}, /* psl/rlisp */
+#ifdef sparc
+ {"s", "! "}, /* assembler */
+#endif
+#ifdef mc68000
+ {"s", "| "}, /* assembler */
+#endif
+#ifdef pdp11
+ {"s", "/ "}, /* assembler */
+#endif
+#ifdef vax
+ {"s", "# "}, /* assembler */
+#endif
+#ifdef __ksr__
+ {"s", "# "}, /* assembler */
+ {"S", "# "}, /* Macro assembler */
+#endif
+ {"sh", "# "}, /* shell */
+ {"sl", "% "}, /* psl */
+ {"spec", "-- "}, /* Ada */
+ {"tex", "% "}, /* tex */
+ {"y", " * "}, /* yacc */
+ {"ye", " * "}, /* yacc-efl */
+ {"yr", " * "}, /* yacc-ratfor */
+#ifdef SYSTEM_COMMENT_TABLE
+ SYSTEM_COMMENT_TABLE
+#endif
+ {"", "# "}, /* default for empty suffix */
+ {NULL, "# "} /* default for unknown suffix; */
+/* must always be last */
+};
+
+static char *
+get_comment (user)
+ char *user;
+{
+ char *cp, *suffix;
+ char suffix_path[PATH_MAX];
+ int i;
+
+ cp = strrchr (user, '.');
+ if (cp != NULL)
+ {
+ cp++;
+
+ /*
+ * Convert to lower-case, since we are not concerned about the
+ * case-ness of the suffix.
+ */
+ (void) strcpy (suffix_path, cp);
+ for (cp = suffix_path; *cp; cp++)
+ if (isupper (*cp))
+ *cp = tolower (*cp);
+ suffix = suffix_path;
+ }
+ else
+ suffix = ""; /* will use the default */
+ for (i = 0;; i++)
+ {
+ if (comtable[i].suffix == NULL) /* default */
+ return (comtable[i].comlead);
+ if (strcmp (suffix, comtable[i].suffix) == 0)
+ return (comtable[i].comlead);
+ }
+}
+
+static int
+add_rcs_file (message, rcs, user, vtag, targc, targv)
+ char *message;
+ char *rcs;
+ char *user;
+ char *vtag;
+ int targc;
+ char *targv[];
+{
+ FILE *fprcs, *fpuser;
+ struct stat sb;
+ struct tm *ftm;
+ time_t now;
+ char altdate1[50];
+#ifndef HAVE_RCS5
+ char altdate2[50];
+#endif
+ char *author, *buf;
+ int i, ierrno, err = 0;
+ mode_t mode;
+ char *tocvsPath;
+ char *userfile;
+
+ if (noexec)
+ return (0);
+
+#ifdef LINES_CRLF_TERMINATED
+ /* There exits a port of RCS to such a system that stores files with
+ straight newlines. If we ever reach this point on such a system,
+ we'll need to decide what to do with the open_file call below. */
+ abort ();
+#endif
+ tocvsPath = wrap_tocvs_process_file (user);
+ userfile = (tocvsPath == NULL ? user : tocvsPath);
+ fpuser = fopen (userfile, "r");
+ if (fpuser == NULL) {
+ /* not fatal, continue import */
+ fperror (logfp, 0, errno, "ERROR: cannot read file %s", userfile);
+ error (0, errno, "ERROR: cannot read file %s", userfile);
+ goto read_error;
+ }
+ fprcs = fopen (rcs, "w+");
+ if (fprcs == NULL) {
+ ierrno = errno;
+ goto write_error_noclose;
+ }
+
+ /*
+ * putadmin()
+ */
+ if (fprintf (fprcs, "head %s;\n", vhead) < 0 ||
+ fprintf (fprcs, "branch %s;\n", vbranch) < 0 ||
+ fprintf (fprcs, "access ;\n") < 0 ||
+ fprintf (fprcs, "symbols ") < 0)
+ {
+ goto write_error;
+ }
+
+ for (i = targc - 1; i >= 0; i--) /* RCS writes the symbols backwards */
+ if (fprintf (fprcs, "%s:%s.1 ", targv[i], vbranch) < 0)
+ goto write_error;
+
+ if (fprintf (fprcs, "%s:%s;\n", vtag, vbranch) < 0 ||
+ fprintf (fprcs, "locks ; strict;\n") < 0 ||
+ /* XXX - make sure @@ processing works in the RCS file */
+ fprintf (fprcs, "comment @%s@;\n", get_comment (user)) < 0)
+ {
+ goto write_error;
+ }
+
+ if (keyword_opt != NULL)
+ if (fprintf (fprcs, "expand @%s@;\n", keyword_opt) < 0)
+ {
+ goto write_error;
+ }
+
+ if (fprintf (fprcs, "\n") < 0)
+ goto write_error;
+
+ /*
+ * puttree()
+ */
+ if (fstat (fileno (fpuser), &sb) < 0)
+ error (1, errno, "cannot fstat %s", user);
+ if (use_file_modtime)
+ now = sb.st_mtime;
+ else
+ (void) time (&now);
+#ifdef HAVE_RCS5
+ ftm = gmtime (&now);
+#else
+ ftm = localtime (&now);
+#endif
+ (void) sprintf (altdate1, DATEFORM,
+ ftm->tm_year + (ftm->tm_year < 100 ? 0 : 1900),
+ ftm->tm_mon + 1, ftm->tm_mday, ftm->tm_hour,
+ ftm->tm_min, ftm->tm_sec);
+#ifdef HAVE_RCS5
+#define altdate2 altdate1
+#else
+ /*
+ * If you don't have RCS V5 or later, you need to lie about the ci
+ * time, since RCS V4 and earlier insist that the times differ.
+ */
+ now++;
+ ftm = localtime (&now);
+ (void) sprintf (altdate2, DATEFORM,
+ ftm->tm_year + (ftm->tm_year < 100 ? 0 : 1900),
+ ftm->tm_mon + 1, ftm->tm_mday, ftm->tm_hour,
+ ftm->tm_min, ftm->tm_sec);
+#endif
+ author = getcaller ();
+
+ if (fprintf (fprcs, "\n%s\n", vhead) < 0 ||
+ fprintf (fprcs, "date %s; author %s; state Exp;\n",
+ altdate1, author) < 0 ||
+ fprintf (fprcs, "branches %s.1;\n", vbranch) < 0 ||
+ fprintf (fprcs, "next ;\n") < 0 ||
+ fprintf (fprcs, "\n%s.1\n", vbranch) < 0 ||
+ fprintf (fprcs, "date %s; author %s; state Exp;\n",
+ altdate2, author) < 0 ||
+ fprintf (fprcs, "branches ;\n") < 0 ||
+ fprintf (fprcs, "next ;\n\n") < 0 ||
+ /*
+ * putdesc()
+ */
+ fprintf (fprcs, "\ndesc\n") < 0 ||
+ fprintf (fprcs, "@@\n\n\n") < 0 ||
+ /*
+ * putdelta()
+ */
+ fprintf (fprcs, "\n%s\n", vhead) < 0 ||
+ fprintf (fprcs, "log\n") < 0 ||
+ fprintf (fprcs, "@Initial revision\n@\n") < 0 ||
+ fprintf (fprcs, "text\n@") < 0)
+ {
+ goto write_error;
+ }
+
+ if (sb.st_size > 0)
+ {
+ off_t size;
+
+ size = sb.st_size;
+ buf = xmalloc ((int) size);
+ if (fread (buf, (int) size, 1, fpuser) != 1)
+ error (1, errno, "cannot read file %s for copying", user);
+ if (expand_at_signs (buf, size, fprcs) < 0)
+ {
+ free (buf);
+ goto write_error;
+ }
+ free (buf);
+ }
+ if (fprintf (fprcs, "@\n\n") < 0 ||
+ fprintf (fprcs, "\n%s.1\n", vbranch) < 0 ||
+ fprintf (fprcs, "log\n@") < 0 ||
+ expand_at_signs (message, (off_t) strlen (message), fprcs) < 0 ||
+ fprintf (fprcs, "@\ntext\n") < 0 ||
+ fprintf (fprcs, "@@\n") < 0)
+ {
+ goto write_error;
+ }
+ if (fclose (fprcs) == EOF)
+ {
+ ierrno = errno;
+ goto write_error_noclose;
+ }
+ (void) fclose (fpuser);
+
+ /*
+ * Fix the modes on the RCS files. The user modes of the original
+ * user file are propagated to the group and other modes as allowed
+ * by the repository umask, except that all write permissions are
+ * turned off.
+ */
+ mode = (sb.st_mode |
+ (sb.st_mode & S_IRWXU) >> 3 |
+ (sb.st_mode & S_IRWXU) >> 6) &
+ ~cvsumask &
+ ~(S_IWRITE | S_IWGRP | S_IWOTH);
+ if (chmod (rcs, mode) < 0)
+ {
+ ierrno = errno;
+ fperror (logfp, 0, ierrno,
+ "WARNING: cannot change mode of file %s", rcs);
+ error (0, ierrno, "WARNING: cannot change mode of file %s", rcs);
+ err++;
+ }
+ if (tocvsPath)
+ if (unlink_file_dir (tocvsPath) < 0)
+ error (0, errno, "cannot remove %s", tocvsPath);
+ return (err);
+
+write_error:
+ ierrno = errno;
+ (void) fclose (fprcs);
+write_error_noclose:
+ (void) fclose (fpuser);
+ fperror (logfp, 0, ierrno, "ERROR: cannot write file %s", rcs);
+ error (0, ierrno, "ERROR: cannot write file %s", rcs);
+ if (ierrno == ENOSPC)
+ {
+ (void) unlink (rcs);
+ fperror (logfp, 0, 0, "ERROR: out of space - aborting");
+ error (1, 0, "ERROR: out of space - aborting");
+ }
+read_error:
+ if (tocvsPath)
+ if (unlink_file_dir (tocvsPath) < 0)
+ error (0, errno, "cannot remove %s", tocvsPath);
+
+ return (err + 1);
+}
+
+/*
+ * Write SIZE bytes at BUF to FP, expanding @ signs into double @
+ * signs. If an error occurs, return a negative value and set errno
+ * to indicate the error. If not, return a nonnegative value.
+ */
+static int
+expand_at_signs (buf, size, fp)
+ char *buf;
+ off_t size;
+ FILE *fp;
+{
+ char *cp, *end;
+
+ errno = 0;
+ for (cp = buf, end = buf + size; cp < end; cp++)
+ {
+ if (*cp == '@')
+ {
+ if (putc ('@', fp) == EOF && errno != 0)
+ return EOF;
+ }
+ if (putc (*cp, fp) == EOF && errno != 0)
+ return (EOF);
+ }
+ return (1);
+}
+
+/*
+ * Write an update message to (potentially) the screen and the log file.
+ */
+static void
+add_log (ch, fname)
+ int ch;
+ char *fname;
+{
+ if (!really_quiet) /* write to terminal */
+ {
+ if (repos_len)
+ (void) printf ("%c %s/%s\n", ch, repository + repos_len + 1, fname);
+ else if (repository[0])
+ (void) printf ("%c %s/%s\n", ch, repository, fname);
+ else
+ (void) printf ("%c %s\n", ch, fname);
+ }
+
+ if (repos_len) /* write to logfile */
+ (void) fprintf (logfp, "%c %s/%s\n", ch,
+ repository + repos_len + 1, fname);
+ else if (repository[0])
+ (void) fprintf (logfp, "%c %s/%s\n", ch, repository, fname);
+ else
+ (void) fprintf (logfp, "%c %s\n", ch, fname);
+}
+
+/*
+ * This is the recursive function that walks the argument directory looking
+ * for sub-directories that have CVS administration files in them and updates
+ * them recursively.
+ *
+ * Note that we do not follow symbolic links here, which is a feature!
+ */
+static int
+import_descend_dir (message, dir, vtag, targc, targv)
+ char *message;
+ char *dir;
+ char *vtag;
+ int targc;
+ char *targv[];
+{
+ struct saved_cwd cwd;
+ char *cp;
+ int ierrno, err;
+
+ if (islink (dir))
+ return (0);
+ if (save_cwd (&cwd))
+ {
+ fperror (logfp, 0, 0, "ERROR: cannot get working directory");
+ return (1);
+ }
+ if (repository[0] == '\0')
+ (void) strcpy (repository, dir);
+ else
+ {
+ (void) strcat (repository, "/");
+ (void) strcat (repository, dir);
+ }
+#ifdef CLIENT_SUPPORT
+ if (!quiet && !client_active)
+#else
+ if (!quiet)
+#endif
+#ifdef SERVER_SUPPORT
+ /* Needs to go on stdout, not stderr, to avoid being interspersed
+ with the add_log messages. */
+ printf ("%s %s: Importing %s\n",
+ program_name, command_name, repository);
+#else
+ error (0, 0, "Importing %s", repository);
+#endif
+
+ if (chdir (dir) < 0)
+ {
+ ierrno = errno;
+ fperror (logfp, 0, ierrno, "ERROR: cannot chdir to %s", repository);
+ error (0, ierrno, "ERROR: cannot chdir to %s", repository);
+ err = 1;
+ goto out;
+ }
+#ifdef CLIENT_SUPPORT
+ if (!client_active && !isdir (repository))
+#else
+ if (!isdir (repository))
+#endif
+ {
+ if (isfile (repository))
+ {
+ fperror (logfp, 0, 0, "ERROR: %s is a file, should be a directory!",
+ repository);
+ error (0, 0, "ERROR: %s is a file, should be a directory!",
+ repository);
+ err = 1;
+ goto out;
+ }
+ if (noexec == 0 && CVS_MKDIR (repository, 0777) < 0)
+ {
+ ierrno = errno;
+ fperror (logfp, 0, ierrno,
+ "ERROR: cannot mkdir %s -- not added", repository);
+ error (0, ierrno,
+ "ERROR: cannot mkdir %s -- not added", repository);
+ err = 1;
+ goto out;
+ }
+ }
+ err = import_descend (message, vtag, targc, targv);
+ out:
+ if ((cp = strrchr (repository, '/')) != NULL)
+ *cp = '\0';
+ else
+ repository[0] = '\0';
+ if (restore_cwd (&cwd, NULL))
+ exit (1);
+ free_cwd (&cwd);
+ return (err);
+}
diff --git a/gnu/usr.bin/cvs/cvs/lock.c b/gnu/usr.bin/cvs/cvs/lock.c
new file mode 100644
index 0000000..3e15fbb
--- /dev/null
+++ b/gnu/usr.bin/cvs/cvs/lock.c
@@ -0,0 +1,608 @@
+/*
+ * Copyright (c) 1992, Brian Berliner and Jeff Polk
+ * Copyright (c) 1989-1992, Brian Berliner
+ *
+ * You may distribute under the terms of the GNU General Public License as
+ * specified in the README file that comes with the CVS 1.4 kit.
+ *
+ * Set Lock
+ *
+ * Lock file support for CVS.
+ */
+
+#include "cvs.h"
+
+#ifndef lint
+static const char rcsid[] = "$CVSid: @(#)lock.c 1.50 94/09/30 $";
+USE(rcsid);
+#endif
+
+static int readers_exist PROTO((char *repository));
+static int set_lock PROTO((char *repository, int will_wait));
+static void clear_lock PROTO((void));
+static void set_lockers_name PROTO((struct stat *statp));
+static int set_writelock_proc PROTO((Node * p, void *closure));
+static int unlock_proc PROTO((Node * p, void *closure));
+static int write_lock PROTO((char *repository));
+static void unlock PROTO((char *repository));
+static void lock_wait PROTO((char *repository));
+static int Check_Owner PROTO((char *lockdir));
+
+static char lockers_name[20];
+static char *repository;
+static char readlock[PATH_MAX], writelock[PATH_MAX], masterlock[PATH_MAX];
+static int cleanup_lckdir;
+static List *locklist;
+
+#define L_OK 0 /* success */
+#define L_ERROR 1 /* error condition */
+#define L_LOCKED 2 /* lock owned by someone else */
+
+/*
+ * Clean up all outstanding locks
+ */
+void
+Lock_Cleanup ()
+{
+ /* clean up simple locks (if any) */
+ if (repository != NULL)
+ {
+ unlock (repository);
+ repository = (char *) NULL;
+ }
+
+ /* clean up multiple locks (if any) */
+ if (locklist != (List *) NULL)
+ {
+ (void) walklist (locklist, unlock_proc, NULL);
+ locklist = (List *) NULL;
+ }
+}
+
+/*
+ * walklist proc for removing a list of locks
+ */
+static int
+unlock_proc (p, closure)
+ Node *p;
+ void *closure;
+{
+ unlock (p->key);
+ return (0);
+}
+
+/*
+ * Remove the lock files (without complaining if they are not there),
+ */
+static void
+unlock (repository)
+ char *repository;
+{
+ char tmp[PATH_MAX];
+
+ if (readlock[0] != '\0')
+ {
+ (void) sprintf (tmp, "%s/%s", repository, readlock);
+ if (unlink (tmp) < 0 && ! existence_error (errno))
+ error (0, errno, "failed to remove lock %s", tmp);
+ }
+
+ if (writelock[0] != '\0')
+ {
+ (void) sprintf (tmp, "%s/%s", repository, writelock);
+ if (unlink (tmp) < 0 && ! existence_error (errno))
+ error (0, errno, "failed to remove lock %s", tmp);
+ }
+
+ /*
+ * Only remove the lock directory if it is ours, note that this does
+ * lead to the limitation that one user ID should not be committing
+ * files into the same Repository directory at the same time. Oh well.
+ */
+ if (writelock[0] != '\0' || (readlock[0] != '\0' && cleanup_lckdir))
+ {
+ (void) sprintf (tmp, "%s/%s", repository, CVSLCK);
+ if (Check_Owner(tmp))
+ {
+#ifdef AFSCVS
+ char rmuidlock[PATH_MAX];
+ sprintf(rmuidlock, "rm -f %s/uidlock%d", tmp, geteuid() );
+ system(rmuidlock);
+#endif
+ (void) rmdir (tmp);
+ }
+ }
+ cleanup_lckdir = 0;
+}
+
+/*
+ * Check the owner of a lock. Returns 1 if we own it, 0 otherwise.
+ */
+static int
+Check_Owner(lockdir)
+ char *lockdir;
+{
+ struct stat sb;
+
+#ifdef AFSCVS
+ /* In the Andrew File System (AFS), user ids from stat don't match
+ those from geteuid(). The AFSCVS code can deal with either AFS or
+ non-AFS repositories; the non-AFSCVS code is faster. */
+ char uidlock[PATH_MAX];
+
+ /* Check if the uidlock is in the lock directory */
+ sprintf(uidlock, "%s/uidlock%d", lockdir, geteuid() );
+ if( stat(uidlock, &sb) != -1)
+ return 1; /* The file exists, therefore we own the lock */
+ else
+ return 0; /* The file didn't exist or some other error.
+ * Assume that we don't own it.
+ */
+#else
+ if (stat (lockdir, &sb) != -1 && sb.st_uid == geteuid ())
+ return 1;
+ else
+ return 0;
+#endif
+} /* end Check_Owner() */
+
+
+/*
+ * Create a lock file for readers
+ */
+int
+Reader_Lock (xrepository)
+ char *xrepository;
+{
+ int err = 0;
+ FILE *fp;
+ char tmp[PATH_MAX];
+
+ if (noexec)
+ return (0);
+
+ /* we only do one directory at a time for read locks! */
+ if (repository != NULL)
+ {
+ error (0, 0, "Reader_Lock called while read locks set - Help!");
+ return (1);
+ }
+
+ if (readlock[0] == '\0')
+ (void) sprintf (readlock,
+#ifdef HAVE_LONG_FILE_NAMES
+ "%s.%s.%d", CVSRFL, hostname,
+#else
+ "%s.%d", CVSRFL,
+#endif
+ getpid ());
+
+ /* remember what we're locking (for lock_cleanup) */
+ repository = xrepository;
+
+#ifdef BOGUS_UNLESS_PROVEN_OTHERWISE
+ /* make sure we can write the repository */
+ (void) sprintf (tmp,
+#ifdef HAVE_LONG_FILE_NAMES
+ "%s/%s.%s.%d", xrepository, CVSTFL, hostname,
+#else
+ "%s/%s.%d", xrepository, CVSTFL,
+#endif
+ getpid());
+ if ((fp = fopen (tmp, "w+")) == NULL || fclose (fp) == EOF)
+ {
+ error (0, errno, "cannot create read lock in repository `%s'",
+ xrepository);
+ readlock[0] = '\0';
+ if (unlink (tmp) < 0 && ! existence_error (errno))
+ error (0, errno, "failed to remove lock %s", tmp);
+ return (1);
+ }
+ if (unlink (tmp) < 0)
+ error (0, errno, "failed to remove lock %s", tmp);
+#endif
+
+ /* get the lock dir for our own */
+ if (set_lock (xrepository, 1) != L_OK)
+ {
+ error (0, 0, "failed to obtain dir lock in repository `%s'",
+ xrepository);
+ readlock[0] = '\0';
+ return (1);
+ }
+
+ /* write a read-lock */
+ (void) sprintf (tmp, "%s/%s", xrepository, readlock);
+ if ((fp = fopen (tmp, "w+")) == NULL || fclose (fp) == EOF)
+ {
+ error (0, errno, "cannot create read lock in repository `%s'",
+ xrepository);
+ readlock[0] = '\0';
+ err = 1;
+ }
+
+ /* free the lock dir */
+ clear_lock();
+
+ return (err);
+}
+
+/*
+ * Lock a list of directories for writing
+ */
+static char *lock_error_repos;
+static int lock_error;
+int
+Writer_Lock (list)
+ List *list;
+{
+ if (noexec)
+ return (0);
+
+ /* We only know how to do one list at a time */
+ if (locklist != (List *) NULL)
+ {
+ error (0, 0, "Writer_Lock called while write locks set - Help!");
+ return (1);
+ }
+
+ for (;;)
+ {
+ /* try to lock everything on the list */
+ lock_error = L_OK; /* init for set_writelock_proc */
+ lock_error_repos = (char *) NULL; /* init for set_writelock_proc */
+ locklist = list; /* init for Lock_Cleanup */
+ (void) strcpy (lockers_name, "unknown");
+
+ (void) walklist (list, set_writelock_proc, NULL);
+
+ switch (lock_error)
+ {
+ case L_ERROR: /* Real Error */
+ Lock_Cleanup (); /* clean up any locks we set */
+ error (0, 0, "lock failed - giving up");
+ return (1);
+
+ case L_LOCKED: /* Someone already had a lock */
+ Lock_Cleanup (); /* clean up any locks we set */
+ lock_wait (lock_error_repos); /* sleep a while and try again */
+ continue;
+
+ case L_OK: /* we got the locks set */
+ return (0);
+
+ default:
+ error (0, 0, "unknown lock status %d in Writer_Lock",
+ lock_error);
+ return (1);
+ }
+ }
+}
+
+/*
+ * walklist proc for setting write locks
+ */
+static int
+set_writelock_proc (p, closure)
+ Node *p;
+ void *closure;
+{
+ /* if some lock was not OK, just skip this one */
+ if (lock_error != L_OK)
+ return (0);
+
+ /* apply the write lock */
+ lock_error_repos = p->key;
+ lock_error = write_lock (p->key);
+ return (0);
+}
+
+/*
+ * Create a lock file for writers returns L_OK if lock set ok, L_LOCKED if
+ * lock held by someone else or L_ERROR if an error occurred
+ */
+static int
+write_lock (repository)
+ char *repository;
+{
+ int status;
+ FILE *fp;
+ char tmp[PATH_MAX];
+
+ if (writelock[0] == '\0')
+ (void) sprintf (writelock,
+#ifdef HAVE_LONG_FILE_NAMES
+ "%s.%s.%d", CVSWFL, hostname,
+#else
+ "%s.%d", CVSWFL,
+#endif
+ getpid());
+
+#ifdef BOGUS_UNLESS_PROVEN_OTHERWISE
+ /* make sure we can write the repository */
+ (void) sprintf (tmp,
+#ifdef HAVE_LONG_FILE_NAMES
+ "%s/%s.%s.%d", repository, CVSTFL, hostname,
+#else
+ "%s/%s.%d", repository, CVSTFL,
+#endif
+ getpid ());
+ if ((fp = fopen (tmp, "w+")) == NULL || fclose (fp) == EOF)
+ {
+ error (0, errno, "cannot create write lock in repository `%s'",
+ repository);
+ if (unlink (tmp) < 0 && ! existence_error (errno))
+ error (0, errno, "failed to remove lock %s", tmp);
+ return (L_ERROR);
+ }
+ if (unlink (tmp) < 0)
+ error (0, errno, "failed to remove lock %s", tmp);
+#endif
+
+ /* make sure the lock dir is ours (not necessarily unique to us!) */
+ status = set_lock (repository, 0);
+ if (status == L_OK)
+ {
+ /* we now own a writer - make sure there are no readers */
+ if (readers_exist (repository))
+ {
+ /* clean up the lock dir if we created it */
+ if (status == L_OK)
+ {
+ clear_lock();
+ }
+
+ /* indicate we failed due to read locks instead of error */
+ return (L_LOCKED);
+ }
+
+ /* write the write-lock file */
+ (void) sprintf (tmp, "%s/%s", repository, writelock);
+ if ((fp = fopen (tmp, "w+")) == NULL || fclose (fp) == EOF)
+ {
+ int xerrno = errno;
+
+ if (unlink (tmp) < 0 && ! existence_error (errno))
+ error (0, errno, "failed to remove lock %s", tmp);
+
+ /* free the lock dir if we created it */
+ if (status == L_OK)
+ {
+ clear_lock();
+ }
+
+ /* return the error */
+ error (0, xerrno, "cannot create write lock in repository `%s'",
+ repository);
+ return (L_ERROR);
+ }
+ return (L_OK);
+ }
+ else
+ return (status);
+}
+
+/*
+ * readers_exist() returns 0 if there are no reader lock files remaining in
+ * the repository; else 1 is returned, to indicate that the caller should
+ * sleep a while and try again.
+ */
+static int
+readers_exist (repository)
+ char *repository;
+{
+ char line[MAXLINELEN];
+ DIR *dirp;
+ struct dirent *dp;
+ struct stat sb;
+ int ret = 0;
+
+#ifdef CVS_FUDGELOCKS
+again:
+#endif
+
+ if ((dirp = opendir (repository)) == NULL)
+ error (1, 0, "cannot open directory %s", repository);
+
+ errno = 0;
+ while ((dp = readdir (dirp)) != NULL)
+ {
+ if (fnmatch (CVSRFLPAT, dp->d_name, 0) == 0)
+ {
+#ifdef CVS_FUDGELOCKS
+ time_t now;
+ (void) time (&now);
+#endif
+
+ (void) sprintf (line, "%s/%s", repository, dp->d_name);
+ if (stat (line, &sb) != -1)
+ {
+#ifdef CVS_FUDGELOCKS
+ /*
+ * If the create time of the file is more than CVSLCKAGE
+ * seconds ago, try to clean-up the lock file, and if
+ * successful, re-open the directory and try again.
+ */
+ if (now >= (sb.st_ctime + CVSLCKAGE) && unlink (line) != -1)
+ {
+ (void) closedir (dirp);
+ goto again;
+ }
+#endif
+ set_lockers_name (&sb);
+ }
+
+ ret = 1;
+ break;
+ }
+ errno = 0;
+ }
+ if (errno != 0)
+ error (0, errno, "error reading directory %s", repository);
+
+ closedir (dirp);
+ return (ret);
+}
+
+/*
+ * Set the static variable lockers_name appropriately, based on the stat
+ * structure passed in.
+ */
+static void
+set_lockers_name (statp)
+ struct stat *statp;
+{
+ struct passwd *pw;
+
+ if ((pw = (struct passwd *) getpwuid (statp->st_uid)) !=
+ (struct passwd *) NULL)
+ {
+ (void) strcpy (lockers_name, pw->pw_name);
+ }
+ else
+ (void) sprintf (lockers_name, "uid%lu", (unsigned long) statp->st_uid);
+}
+
+/*
+ * Persistently tries to make the directory "lckdir",, which serves as a
+ * lock. If the create time on the directory is greater than CVSLCKAGE
+ * seconds old, just try to remove the directory.
+ */
+static int
+set_lock (repository, will_wait)
+ char *repository;
+ int will_wait;
+{
+ struct stat sb;
+ mode_t omask;
+#ifdef CVS_FUDGELOCKS
+ time_t now;
+#endif
+
+ (void) sprintf (masterlock, "%s/%s", repository, CVSLCK);
+
+ /*
+ * Note that it is up to the callers of set_lock() to arrange for signal
+ * handlers that do the appropriate things, like remove the lock
+ * directory before they exit.
+ */
+ cleanup_lckdir = 0;
+ for (;;)
+ {
+ int status = -1;
+ omask = umask (cvsumask);
+ SIG_beginCrSect ();
+ if (CVS_MKDIR (masterlock, 0777) == 0)
+ {
+#ifdef AFSCVS
+ char uidlock[PATH_MAX];
+ FILE *fp;
+
+ sprintf(uidlock, "%s/uidlock%d", masterlock, geteuid() );
+ if ((fp = fopen(uidlock, "w+")) == NULL)
+ {
+ /* We failed to create the uidlock,
+ so rm masterlock and leave */
+ rmdir(masterlock);
+ SIG_endCrSect ();
+ status = L_ERROR;
+ goto out;
+ }
+
+ /* We successfully created the uid lock, so close the file */
+ fclose(fp);
+#endif
+ cleanup_lckdir = 1;
+ SIG_endCrSect ();
+ status = L_OK;
+ goto out;
+ }
+ SIG_endCrSect ();
+ out:
+ (void) umask (omask);
+ if (status != -1)
+ return status;
+
+ if (errno != EEXIST)
+ {
+ error (0, errno,
+ "failed to create lock directory in repository `%s'",
+ repository);
+ return (L_ERROR);
+ }
+
+ /*
+ * stat the dir - if it is non-existent, re-try the loop since
+ * someone probably just removed it (thus releasing the lock)
+ */
+ if (stat (masterlock, &sb) < 0)
+ {
+ if (existence_error (errno))
+ continue;
+
+ error (0, errno, "couldn't stat lock directory `%s'", masterlock);
+ return (L_ERROR);
+ }
+
+#ifdef CVS_FUDGELOCKS
+ /*
+ * If the create time of the directory is more than CVSLCKAGE seconds
+ * ago, try to clean-up the lock directory, and if successful, just
+ * quietly retry to make it.
+ */
+ (void) time (&now);
+ if (now >= (sb.st_ctime + CVSLCKAGE))
+ {
+#ifdef AFSCVS
+ /* Remove the uidlock first */
+ char rmuidlock[PATH_MAX];
+ sprintf(rmuidlock, "rm -f %s/uidlock%d", masterlock, geteuid() );
+ system(rmuidlock);
+#endif
+ if (rmdir (masterlock) >= 0)
+ continue;
+ }
+#endif
+
+ /* set the lockers name */
+ set_lockers_name (&sb);
+
+ /* if he wasn't willing to wait, return an error */
+ if (!will_wait)
+ return (L_LOCKED);
+ lock_wait (repository);
+ }
+}
+
+/*
+ * Clear master lock. We don't have to recompute the lock name since
+ * clear_lock is never called except after a successful set_lock().
+ */
+static void
+clear_lock()
+{
+#ifdef AFSCVS
+ /* Remove the uidlock first */
+ char rmuidlock[PATH_MAX];
+ sprintf(rmuidlock, "rm -f %s/uidlock%d", masterlock, geteuid() );
+ system(rmuidlock);
+#endif
+ if (rmdir (masterlock) < 0)
+ error (0, errno, "failed to remove lock dir `%s'", masterlock);
+ cleanup_lckdir = 0;
+}
+
+/*
+ * Print out a message that the lock is still held, then sleep a while.
+ */
+static void
+lock_wait (repos)
+ char *repos;
+{
+ time_t now;
+
+ (void) time (&now);
+ error (0, 0, "[%8.8s] waiting for %s's lock in %s", ctime (&now) + 11,
+ lockers_name, repos);
+ (void) sleep (CVSLCKSLEEP);
+}
diff --git a/gnu/usr.bin/cvs/cvs/log.c b/gnu/usr.bin/cvs/cvs/log.c
new file mode 100644
index 0000000..88c9adc
--- /dev/null
+++ b/gnu/usr.bin/cvs/cvs/log.c
@@ -0,0 +1,178 @@
+/*
+ * Copyright (c) 1992, Brian Berliner and Jeff Polk
+ * Copyright (c) 1989-1992, Brian Berliner
+ *
+ * You may distribute under the terms of the GNU General Public License as
+ * specified in the README file that comes with the CVS 1.4 kit.
+ *
+ * Print Log Information
+ *
+ * This line exists solely to test some pcl-cvs/ChangeLog stuff. You
+ * can delete it, if indeed it's still here when you read it. -Karl
+ *
+ * Prints the RCS "log" (rlog) information for the specified files. With no
+ * argument, prints the log information for all the files in the directory
+ * (recursive by default).
+ */
+
+#include "cvs.h"
+
+#ifndef lint
+static const char rcsid[] = "$CVSid: @(#)log.c 1.44 94/09/30 $";
+USE(rcsid);
+#endif
+
+static Dtype log_dirproc PROTO((char *dir, char *repository, char *update_dir));
+static int log_fileproc PROTO((char *file, char *update_dir, char *repository,
+ List * entries, List * srcfiles));
+
+static const char *const log_usage[] =
+{
+ "Usage: %s %s [-l] [rlog-options] [files...]\n",
+ "\t-l\tLocal directory only, no recursion.\n",
+ NULL
+};
+
+static int ac;
+static char **av;
+
+int
+cvslog (argc, argv)
+ int argc;
+ char **argv;
+{
+ int i;
+ int err = 0;
+ int local = 0;
+
+ if (argc == -1)
+ usage (log_usage);
+
+ /*
+ * All 'log' command options except -l are passed directly on to 'rlog'
+ */
+ for (i = 1; i < argc && argv[i][0] == '-'; i++)
+ if (argv[i][1] == 'l')
+ local = 1;
+
+ wrap_setup ();
+
+#ifdef CLIENT_SUPPORT
+ if (client_active) {
+ /* We're the local client. Fire up the remote server. */
+ start_server ();
+
+ ign_setup ();
+
+ for (i = 1; i < argc && argv[i][0] == '-'; i++)
+ send_arg (argv[i]);
+
+#if 0
+/* FIXME: We shouldn't have to send current files to get log entries, but it
+ doesn't work yet and I haven't debugged it. So send the files --
+ it's slower but it works. gnu@cygnus.com Apr94 */
+ send_file_names (argc - i, argv + i);
+#else
+ send_files (argc - i, argv + i, local, 0);
+#endif
+
+ if (fprintf (to_server, "log\n") < 0)
+ error (1, errno, "writing to server");
+ err = get_responses_and_close ();
+ return err;
+ }
+
+ ac = argc;
+ av = argv;
+#endif
+
+ err = start_recursion (log_fileproc, (FILESDONEPROC) NULL, log_dirproc,
+ (DIRLEAVEPROC) NULL, argc - i, argv + i, local,
+ W_LOCAL | W_REPOS | W_ATTIC, 0, 1,
+ (char *) NULL, 1, 0);
+ return (err);
+}
+
+
+/*
+ * Do an rlog on a file
+ */
+/* ARGSUSED */
+static int
+log_fileproc (file, update_dir, repository, entries, srcfiles)
+ char *file;
+ char *update_dir;
+ char *repository;
+ List *entries;
+ List *srcfiles;
+{
+ Node *p;
+ RCSNode *rcsfile;
+ int retcode = 0;
+
+ p = findnode (srcfiles, file);
+ if (p == NULL || (rcsfile = (RCSNode *) p->data) == NULL)
+ {
+ /* no rcs file. What *do* we know about this file? */
+ p = findnode (entries, file);
+ if (p != NULL)
+ {
+ Entnode *e;
+
+ e = (Entnode *) p->data;
+ if (e->version[0] == '0' || e->version[1] == '\0')
+ {
+ if (!really_quiet)
+ error (0, 0, "%s has been added, but not committed",
+ file);
+ return(0);
+ }
+ }
+
+ if (!really_quiet)
+ error (0, 0, "nothing known about %s", file);
+
+ return (1);
+ }
+
+ run_setup ("%s%s", Rcsbin, RCS_RLOG);
+ {
+ int i;
+ for (i = 1; i < ac && av[i][0] == '-'; i++)
+ if (av[i][1] != 'l')
+ run_arg (av[i]);
+ }
+ run_arg (rcsfile->path);
+
+ if (*update_dir)
+ {
+ char *workfile = xmalloc (strlen (update_dir) + strlen (file) + 2);
+ sprintf (workfile, "%s/%s", update_dir, file);
+ run_arg (workfile);
+ free (workfile);
+ }
+
+ if ((retcode = run_exec (RUN_TTY, RUN_TTY, RUN_TTY, RUN_REALLY)) == -1)
+ {
+ error (1, errno, "fork failed for rlog on %s", file);
+ }
+ return (retcode);
+}
+
+/*
+ * Print a warm fuzzy message
+ */
+/* ARGSUSED */
+static Dtype
+log_dirproc (dir, repository, update_dir)
+ char *dir;
+ char *repository;
+ char *update_dir;
+{
+ if (!isdir (dir))
+ return (R_SKIP_ALL);
+
+ if (!quiet)
+ error (0, 0, "Logging %s", update_dir);
+ return (R_PROCESS);
+}
diff --git a/gnu/usr.bin/cvs/cvs/login.c b/gnu/usr.bin/cvs/cvs/login.c
new file mode 100644
index 0000000..ccb757c
--- /dev/null
+++ b/gnu/usr.bin/cvs/cvs/login.c
@@ -0,0 +1,287 @@
+/*
+ * Copyright (c) 1995, Cyclic Software, Bloomington, IN, USA
+ *
+ * You may distribute under the terms of the GNU General Public License as
+ * specified in the README file that comes with CVS.
+ *
+ * Allow user to log in for an authenticating server.
+ */
+
+#include "cvs.h"
+
+#ifdef AUTH_CLIENT_SUPPORT /* This covers the rest of the file. */
+
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netdb.h>
+
+#ifndef lint
+static const char rcsid[] = "$CVSid: @(#)login.c 1.1 95/10/01 $";
+USE(rcsid);
+#endif
+
+#ifndef CVS_PASSWORD_FILE
+#define CVS_PASSWORD_FILE ".cvspass"
+#endif
+
+
+/* The return value will need to be freed. */
+char *
+construct_cvspass_filename ()
+{
+ char *homedir;
+ char *passfile;
+
+ /* Construct absolute pathname to user's password file. */
+ /* todo: does this work under Win-NT and OS/2 ? */
+ homedir = getenv ("HOME");
+ if (! homedir)
+ {
+ error (1, errno, "could not find out home directory");
+ return (char *) NULL;
+ }
+
+ passfile =
+ (char *) xmalloc (strlen (homedir) + strlen (CVS_PASSWORD_FILE) + 3);
+ strcpy (passfile, homedir);
+ strcat (passfile, "/");
+ strcat (passfile, CVS_PASSWORD_FILE);
+
+ /* Safety first and last, Scouts. */
+ if (isfile (passfile))
+ /* xchmod() is too polite. */
+ chmod (passfile, 0600);
+
+ return passfile;
+}
+
+
+/* Prompt for a password, and store it in the file "CVS/.cvspass".
+ *
+ * Because the user might be accessing multiple repositories, with
+ * different passwords for each one, the format of ~/.cvspass is:
+ *
+ * user@host:/path cleartext_password
+ * user@host:/path cleartext_password
+ * ...
+ *
+ * Of course, the "user@" might be left off -- it's just based on the
+ * value of CVSroot.
+ *
+ * Like .netrc, the file's permissions are the only thing preventing
+ * it from being read by others. Unlike .netrc, we will not be
+ * fascist about it, at most issuing a warning, and never refusing to
+ * work.
+ */
+int
+login (argc, argv)
+ int argc;
+ char **argv;
+{
+ char *username;
+ int i;
+ char *passfile;
+ FILE *fp;
+ char *typed_password, *found_password;
+ char linebuf[MAXLINELEN];
+ int root_len, already_entered = 0;
+
+ /* Make this a "fully-qualified" CVSroot if necessary. */
+ if (! strchr (CVSroot, '@'))
+ {
+ /* We need to prepend "user@host:". */
+ char *tmp;
+
+ printf ("Repository \"%s\" not fully-qualified.\n", CVSroot);
+ printf ("Please enter \"user@host:/path\": ");
+ fflush (stdout);
+ fgets (linebuf, MAXLINELEN, stdin);
+
+ tmp = xmalloc (strlen (linebuf) + 1);
+
+ strcpy (tmp, linebuf);
+ tmp[strlen (linebuf) - 1] = '\0';
+ CVSroot = tmp;
+ }
+
+ /* Check to make sure it's fully-qualified before going on. */
+ if (! CVSroot)
+ {
+ error (1, 0, "CVSroot is NULL");
+ }
+ else if ((! strchr (CVSroot, '@')) && (! strchr (CVSroot, ':')))
+ {
+ error (1, 0, "CVSroot not fully-qualified: %s", CVSroot);
+ }
+
+
+ passfile = construct_cvspass_filename ();
+ typed_password = getpass ("Enter CVS password: ");
+
+ /* IF we have a password for this "[user@]host:/path" already
+ * THEN
+ * IF it's the same as the password we read from the prompt
+ * THEN
+ * do nothing
+ * ELSE
+ * replace the old password with the new one
+ * ELSE
+ * append new entry to the end of the file.
+ */
+
+ root_len = strlen (CVSroot);
+
+ /* Yes, the method below reads the user's password file twice. It's
+ inefficient, but we're not talking about a gig of data here. */
+
+ fp = fopen (passfile, "r");
+ if (fp == NULL)
+ {
+ error (1, errno, "unable to open %s", passfile);
+ return 1;
+ }
+
+ /* Check each line to see if we have this entry already. */
+ while (fgets (linebuf, MAXLINELEN, fp) != NULL)
+ {
+ if (! strncmp (CVSroot, linebuf, root_len))
+ {
+ already_entered = 1;
+ break;
+ }
+ }
+ fclose (fp);
+
+
+ if (already_entered)
+ {
+ /* This user/host has a password in the file already. */
+
+ /* todo: what about these charsets??? */
+ strtok (linebuf, " \n");
+ found_password = strtok (NULL, " \n");
+ if (strcmp (found_password, typed_password))
+ {
+ /* typed_password and found_password don't match, so we'll
+ * have to update passfile. We replace the old password
+ * with the new one by writing a tmp file whose contents are
+ * exactly the same as passfile except that this one entry
+ * gets typed_password instead of found_password. Then we
+ * rename the tmp file on top of passfile.
+ */
+ char *tmp_name;
+ FILE *tmp_fp;
+
+ tmp_name = tmpnam (NULL);
+ if ((tmp_fp = fopen (tmp_name, "w")) == NULL)
+ {
+ error (1, errno, "unable to open temp file %s", tmp_name);
+ return 1;
+ }
+ chmod (tmp_name, 0600);
+
+ fp = fopen (passfile, "r");
+ if (fp == NULL)
+ {
+ error (1, errno, "unable to open %s", passfile);
+ return 1;
+ }
+ /* I'm not paranoid, they really ARE out to get me: */
+ chmod (passfile, 0600);
+
+ while (fgets (linebuf, MAXLINELEN, fp) != NULL)
+ {
+ if (strncmp (CVSroot, linebuf, root_len))
+ fprintf (tmp_fp, "%s", linebuf);
+ else
+ fprintf (tmp_fp, "%s %s\n", CVSroot, typed_password);
+ }
+ fclose (tmp_fp);
+ fclose (fp);
+ rename_file (tmp_name, passfile);
+ chmod (passfile, 0600);
+ }
+ }
+ else
+ {
+ if ((fp = fopen (passfile, "a")) == NULL)
+ {
+ error (1, errno, "could not open %s", passfile);
+ free (passfile);
+ return 1;
+ }
+
+ /* It's safer this way, and blank lines in the file are OK. */
+ fprintf (fp, "\n%s %s\n", CVSroot, typed_password);
+ fclose (fp);
+ }
+
+ /* Utter, total, raving paranoia, I know. */
+ chmod (passfile, 0600);
+ memset (typed_password, 0, strlen (typed_password));
+
+ free (passfile);
+ return 0;
+}
+
+/* todo: "cvs logout" could erase an entry from the file.
+ * But to what purpose?
+ */
+
+
+char *
+get_cvs_password (user, host, cvsroot)
+{
+ int root_len;
+ int found_it = 0;
+ char *password;
+ char linebuf[MAXLINELEN];
+ FILE *fp;
+ char *passfile;
+
+ passfile = construct_cvspass_filename ();
+ fp = fopen (passfile, "r");
+ if (fp == NULL)
+ {
+ error (0, errno, "could not open %s", passfile);
+ free (passfile);
+ goto prompt_for_it;
+ }
+
+ root_len = strlen (CVSroot);
+
+ /* Check each line to see if we have this entry already. */
+ while (fgets (linebuf, MAXLINELEN, fp) != NULL)
+ {
+ if (strncmp (CVSroot, linebuf, root_len) == 0)
+ {
+ /* This is it! So break out and deal with linebuf. */
+ found_it = 1;
+ break;
+ }
+ }
+
+ if (found_it)
+ {
+ /* linebuf now contains the line with the password. */
+ char *tmp;
+
+ strtok (linebuf, " ");
+ password = strtok (NULL, "\n");
+
+ /* Give it permanent storage. */
+ tmp = xmalloc (strlen (password) + 1);
+ strcpy (tmp, password);
+ tmp[strlen (password)] = '\0';
+ memset (password, 0, strlen (password));
+ return tmp;
+ }
+ else
+ {
+ prompt_for_it:
+ return getpass ("CVS password: ");
+ }
+}
+
+#endif /* AUTH_CLIENT_SUPPORT from beginning of file. */
+
diff --git a/gnu/usr.bin/cvs/cvs/logmsg.c b/gnu/usr.bin/cvs/cvs/logmsg.c
new file mode 100644
index 0000000..7686a36
--- /dev/null
+++ b/gnu/usr.bin/cvs/cvs/logmsg.c
@@ -0,0 +1,486 @@
+/*
+ * Copyright (c) 1992, Brian Berliner and Jeff Polk
+ * Copyright (c) 1989-1992, Brian Berliner
+ *
+ * You may distribute under the terms of the GNU General Public License as
+ * specified in the README file that comes with the CVS 1.4 kit.
+ */
+
+#include "cvs.h"
+#include "getline.h"
+
+#ifndef lint
+static const char rcsid[] = "$CVSid: @(#)logmsg.c 1.48 94/09/29 $";
+USE(rcsid);
+#endif
+
+static int find_type PROTO((Node * p, void *closure));
+static int fmt_proc PROTO((Node * p, void *closure));
+static int logfile_write PROTO((char *repository, char *filter, char *title,
+ char *message, char *revision, FILE * logfp,
+ List * changes));
+static int rcsinfo_proc PROTO((char *repository, char *template));
+static int title_proc PROTO((Node * p, void *closure));
+static int update_logfile_proc PROTO((char *repository, char *filter));
+static void setup_tmpfile PROTO((FILE * xfp, char *xprefix, List * changes));
+static int editinfo_proc PROTO((char *repository, char *template));
+
+static FILE *fp;
+static char *str_list;
+static char *editinfo_editor;
+static Ctype type;
+
+/*
+ * Puts a standard header on the output which is either being prepared for an
+ * editor session, or being sent to a logfile program. The modified, added,
+ * and removed files are included (if any) and formatted to look pretty. */
+static char *prefix;
+static int col;
+static void
+setup_tmpfile (xfp, xprefix, changes)
+ FILE *xfp;
+ char *xprefix;
+ List *changes;
+{
+ /* set up statics */
+ fp = xfp;
+ prefix = xprefix;
+
+ type = T_MODIFIED;
+ if (walklist (changes, find_type, NULL) != 0)
+ {
+ (void) fprintf (fp, "%sModified Files:\n", prefix);
+ (void) fprintf (fp, "%s\t", prefix);
+ col = 8;
+ (void) walklist (changes, fmt_proc, NULL);
+ (void) fprintf (fp, "\n");
+ }
+ type = T_ADDED;
+ if (walklist (changes, find_type, NULL) != 0)
+ {
+ (void) fprintf (fp, "%sAdded Files:\n", prefix);
+ (void) fprintf (fp, "%s\t", prefix);
+ col = 8;
+ (void) walklist (changes, fmt_proc, NULL);
+ (void) fprintf (fp, "\n");
+ }
+ type = T_REMOVED;
+ if (walklist (changes, find_type, NULL) != 0)
+ {
+ (void) fprintf (fp, "%sRemoved Files:\n", prefix);
+ (void) fprintf (fp, "%s\t", prefix);
+ col = 8;
+ (void) walklist (changes, fmt_proc, NULL);
+ (void) fprintf (fp, "\n");
+ }
+}
+
+/*
+ * Looks for nodes of a specified type and returns 1 if found
+ */
+static int
+find_type (p, closure)
+ Node *p;
+ void *closure;
+{
+ if (p->data == (char *) type)
+ return (1);
+ else
+ return (0);
+}
+
+/*
+ * Breaks the files list into reasonable sized lines to avoid line wrap...
+ * all in the name of pretty output. It only works on nodes whose types
+ * match the one we're looking for
+ */
+static int
+fmt_proc (p, closure)
+ Node *p;
+ void *closure;
+{
+ if (p->data == (char *) type)
+ {
+ if ((col + (int) strlen (p->key)) > 70)
+ {
+ (void) fprintf (fp, "\n%s\t", prefix);
+ col = 8;
+ }
+ (void) fprintf (fp, "%s ", p->key);
+ col += strlen (p->key) + 1;
+ }
+ return (0);
+}
+
+/*
+ * Builds a temporary file using setup_tmpfile() and invokes the user's
+ * editor on the file. The header garbage in the resultant file is then
+ * stripped and the log message is stored in the "message" argument.
+ *
+ * rcsinfo - is the name of a file containing lines tacked onto the end of the
+ * RCS info offered to the user for editing. If specified, the '-m' flag to
+ * "commit" is disabled -- users are forced to run the editor.
+ *
+ */
+void
+do_editor (dir, messagep, repository, changes)
+ char *dir;
+ char **messagep;
+ char *repository;
+ List *changes;
+{
+ static int reuse_log_message = 0;
+ char *line;
+ int line_length;
+ size_t line_chars_allocated;
+ char fname[L_tmpnam+1];
+ struct stat pre_stbuf, post_stbuf;
+ int retcode = 0;
+ char *p;
+
+ if (noexec || reuse_log_message)
+ return;
+
+ /* Create a temporary file */
+ (void) tmpnam (fname);
+ again:
+ if ((fp = fopen (fname, "w+")) == NULL)
+ error (1, 0, "cannot create temporary file %s", fname);
+
+ if (*messagep)
+ {
+ (void) fprintf (fp, "%s", *messagep);
+
+ if ((*messagep)[strlen (*messagep) - 1] != '\n')
+ (void) fprintf (fp, "\n");
+ }
+ else
+ (void) fprintf (fp, "\n");
+
+ if (repository != NULL)
+ /* tack templates on if necessary */
+ (void) Parse_Info (CVSROOTADM_RCSINFO, repository, rcsinfo_proc, 1);
+
+ (void) fprintf (fp,
+ "%s----------------------------------------------------------------------\n",
+ CVSEDITPREFIX);
+ (void) fprintf (fp,
+ "%sEnter Log. Lines beginning with `%s' are removed automatically\n%s\n",
+ CVSEDITPREFIX, CVSEDITPREFIX, CVSEDITPREFIX);
+ if (dir != NULL && *dir)
+ (void) fprintf (fp, "%sCommitting in %s\n%s\n", CVSEDITPREFIX,
+ dir, CVSEDITPREFIX);
+ if (changes != NULL)
+ setup_tmpfile (fp, CVSEDITPREFIX, changes);
+ (void) fprintf (fp,
+ "%s----------------------------------------------------------------------\n",
+ CVSEDITPREFIX);
+
+ /* finish off the temp file */
+ if (fclose (fp) == EOF)
+ error (1, errno, "%s", fname);
+ if (stat (fname, &pre_stbuf) == -1)
+ pre_stbuf.st_mtime = 0;
+
+ if (editinfo_editor)
+ free (editinfo_editor);
+ editinfo_editor = (char *) NULL;
+ if (repository != NULL)
+ (void) Parse_Info (CVSROOTADM_EDITINFO, repository, editinfo_proc, 0);
+
+ /* run the editor */
+ run_setup ("%s", editinfo_editor ? editinfo_editor : Editor);
+ run_arg (fname);
+ if ((retcode = run_exec (RUN_TTY, RUN_TTY, RUN_TTY,
+ RUN_NORMAL | RUN_SIGIGNORE)) != 0)
+ error (editinfo_editor ? 1 : 0, retcode == -1 ? errno : 0,
+ editinfo_editor ? "Logfile verification failed" :
+ "warning: editor session failed");
+
+ /* put the entire message back into the *messagep variable */
+
+ fp = open_file (fname, "r");
+
+ if (*messagep)
+ free (*messagep);
+
+ if (stat (fname, &post_stbuf) != 0)
+ error (1, errno, "cannot find size of temp file %s", fname);
+
+ if (post_stbuf.st_size == 0)
+ *messagep = NULL;
+ else
+ {
+ *messagep = (char *) xmalloc (post_stbuf.st_size + 1);
+ *messagep[0] = '\0';
+ }
+
+ line = NULL;
+ line_chars_allocated = 0;
+
+ if (*messagep)
+ {
+ p = *messagep;
+ while (1)
+ {
+ line_length = getline (&line, &line_chars_allocated, fp);
+ if (line_length == -1)
+ {
+ if (ferror (fp))
+ error (0, errno, "warning: cannot read %s", fname);
+ break;
+ }
+ if (strncmp (line, CVSEDITPREFIX, sizeof (CVSEDITPREFIX) - 1) == 0)
+ continue;
+ (void) strcpy (p, line);
+ p += line_length;
+ }
+ }
+ if (fclose (fp) < 0)
+ error (0, errno, "warning: cannot close %s", fname);
+
+ if (pre_stbuf.st_mtime == post_stbuf.st_mtime ||
+ *messagep == NULL ||
+ strcmp (*messagep, "\n") == 0)
+ {
+ for (;;)
+ {
+ (void) printf ("\nLog message unchanged or not specified\n");
+ (void) printf ("a)bort, c)ontinue, e)dit, !)reuse this message unchanged for remaining dirs\n");
+ (void) printf ("Action: (continue) ");
+ (void) fflush (stdout);
+ line_length = getline (&line, &line_chars_allocated, stdin);
+ if (line_length <= 0
+ || *line == '\n' || *line == 'c' || *line == 'C')
+ break;
+ if (*line == 'a' || *line == 'A')
+ error (1, 0, "aborted by user");
+ if (*line == 'e' || *line == 'E')
+ goto again;
+ if (*line == '!')
+ {
+ reuse_log_message = 1;
+ break;
+ }
+ (void) printf ("Unknown input\n");
+ }
+ }
+ if (line)
+ free (line);
+ if (unlink_file (fname) < 0)
+ error (0, errno, "warning: cannot remove temp file %s", fname);
+}
+
+/*
+ * callback proc for Parse_Info for rcsinfo templates this routine basically
+ * copies the matching template onto the end of the tempfile we are setting
+ * up
+ */
+/* ARGSUSED */
+static int
+rcsinfo_proc (repository, template)
+ char *repository;
+ char *template;
+{
+ static char *last_template;
+ FILE *tfp;
+
+ /* nothing to do if the last one included is the same as this one */
+ if (last_template && strcmp (last_template, template) == 0)
+ return (0);
+ if (last_template)
+ free (last_template);
+ last_template = xstrdup (template);
+
+ if ((tfp = fopen (template, "r")) != NULL)
+ {
+ char *line = NULL;
+ size_t line_chars_allocated = 0;
+
+ while (getline (&line, &line_chars_allocated, tfp) >= 0)
+ (void) fputs (line, fp);
+ if (ferror (tfp))
+ error (0, errno, "warning: cannot read %s", template);
+ if (fclose (tfp) < 0)
+ error (0, errno, "warning: cannot close %s", template);
+ if (line)
+ free (line);
+ return (0);
+ }
+ else
+ {
+ error (0, errno, "Couldn't open rcsinfo template file %s", template);
+ return (1);
+ }
+}
+
+/*
+ * Uses setup_tmpfile() to pass the updated message on directly to any
+ * logfile programs that have a regular expression match for the checked in
+ * directory in the source repository. The log information is fed into the
+ * specified program as standard input.
+ */
+static char *title;
+static FILE *logfp;
+static char *message;
+static char *revision;
+static List *changes;
+
+void
+Update_Logfile (repository, xmessage, xrevision, xlogfp, xchanges)
+ char *repository;
+ char *xmessage;
+ char *xrevision;
+ FILE *xlogfp;
+ List *xchanges;
+{
+ char *srepos;
+
+ /* nothing to do if the list is empty */
+ if (xchanges == NULL || xchanges->list->next == xchanges->list)
+ return;
+
+ /* set up static vars for update_logfile_proc */
+ message = xmessage;
+ revision = xrevision;
+ logfp = xlogfp;
+ changes = xchanges;
+
+ /* figure out a good title string */
+ srepos = Short_Repository (repository);
+
+ /* allocate a chunk of memory to hold the title string */
+ if (!str_list)
+ str_list = xmalloc (MAXLISTLEN);
+ str_list[0] = '\0';
+
+ type = T_TITLE;
+ (void) walklist (changes, title_proc, NULL);
+ type = T_ADDED;
+ (void) walklist (changes, title_proc, NULL);
+ type = T_MODIFIED;
+ (void) walklist (changes, title_proc, NULL);
+ type = T_REMOVED;
+ (void) walklist (changes, title_proc, NULL);
+ title = xmalloc (strlen (srepos) + strlen (str_list) + 1 + 2); /* for 's */
+ (void) sprintf (title, "'%s%s'", srepos, str_list);
+
+ /* to be nice, free up this chunk of memory */
+ free (str_list);
+ str_list = (char *) NULL;
+
+ /* call Parse_Info to do the actual logfile updates */
+ (void) Parse_Info (CVSROOTADM_LOGINFO, repository, update_logfile_proc, 1);
+
+ /* clean up */
+ free (title);
+}
+
+/*
+ * callback proc to actually do the logfile write from Update_Logfile
+ */
+static int
+update_logfile_proc (repository, filter)
+ char *repository;
+ char *filter;
+{
+ return (logfile_write (repository, filter, title, message, revision,
+ logfp, changes));
+}
+
+/*
+ * concatenate each name onto str_list
+ */
+static int
+title_proc (p, closure)
+ Node *p;
+ void *closure;
+{
+ if (p->data == (char *) type)
+ {
+ (void) strcat (str_list, " ");
+ (void) strcat (str_list, p->key);
+ }
+ return (0);
+}
+
+/*
+ * Since some systems don't define this...
+ */
+#ifndef MAXHOSTNAMELEN
+#define MAXHOSTNAMELEN 256
+#endif
+
+/*
+ * Writes some stuff to the logfile "filter" and returns the status of the
+ * filter program.
+ */
+static int
+logfile_write (repository, filter, title, message, revision, logfp, changes)
+ char *repository;
+ char *filter;
+ char *title;
+ char *message;
+ char *revision;
+ FILE *logfp;
+ List *changes;
+{
+ char cwd[PATH_MAX];
+ FILE *pipefp, *Popen ();
+ char *prog = xmalloc (MAXPROGLEN);
+ char *cp;
+ int c;
+
+ /* XXX <woods@web.net> -- this is gross, ugly, and a hack! FIXME! */
+ /*
+ * A maximum of 6 %s arguments are supported in the filter
+ */
+ (void) sprintf (prog, filter, title, title, title, title, title, title);
+ if ((pipefp = Popen (prog, "w")) == NULL)
+ {
+ if (!noexec)
+ error (0, 0, "cannot write entry to log filter: %s", prog);
+ free (prog);
+ return (1);
+ }
+ (void) fprintf (pipefp, "Update of %s\n", repository);
+ (void) fprintf (pipefp, "In directory %s:%s\n\n", hostname,
+ ((cp = getwd (cwd)) != NULL) ? cp : cwd);
+ if (revision && *revision)
+ (void) fprintf (pipefp, "Revision/Branch: %s\n\n", revision);
+ setup_tmpfile (pipefp, "", changes);
+ (void) fprintf (pipefp, "Log Message:\n%s\n", message);
+ if (logfp != (FILE *) 0)
+ {
+ (void) fprintf (pipefp, "Status:\n");
+ rewind (logfp);
+ while ((c = getc (logfp)) != EOF)
+ (void) putc ((char) c, pipefp);
+ }
+ free (prog);
+ return (pclose (pipefp));
+}
+
+/*
+ * We choose to use the *last* match within the editinfo file for this
+ * repository. This allows us to have a global editinfo program for the
+ * root of some hierarchy, for example, and different ones within different
+ * sub-directories of the root (like a special checker for changes made to
+ * the "src" directory versus changes made to the "doc" or "test"
+ * directories.
+ */
+/* ARGSUSED */
+static int
+editinfo_proc(repository, editor)
+ char *repository;
+ char *editor;
+{
+ /* nothing to do if the last match is the same as this one */
+ if (editinfo_editor && strcmp (editinfo_editor, editor) == 0)
+ return (0);
+ if (editinfo_editor)
+ free (editinfo_editor);
+
+ editinfo_editor = xstrdup (editor);
+ return (0);
+}
diff --git a/gnu/usr.bin/cvs/cvs/main.c b/gnu/usr.bin/cvs/cvs/main.c
new file mode 100644
index 0000000..91e376d
--- /dev/null
+++ b/gnu/usr.bin/cvs/cvs/main.c
@@ -0,0 +1,769 @@
+/*
+ * Copyright (c) 1992, Brian Berliner and Jeff Polk
+ * Copyright (c) 1989-1992, Brian Berliner
+ *
+ * You may distribute under the terms of the GNU General Public License
+ * as specified in the README file that comes with the CVS 1.4 kit.
+ *
+ * This is the main C driver for the CVS system.
+ *
+ * Credit to Dick Grune, Vrije Universiteit, Amsterdam, for writing
+ * the shell-script CVS system that this is based on.
+ *
+ * Usage:
+ * cvs [options] command [options] [files/modules...]
+ *
+ * Where "command" is composed of:
+ * admin RCS command
+ * checkout Check out a module/dir/file
+ * export Like checkout, but used for exporting sources
+ * update Brings work tree in sync with repository
+ * commit Checks files into the repository
+ * diff Runs diffs between revisions
+ * log Prints "rlog" information for files
+ * login Record user, host, repos, password
+ * add Adds an entry to the repository
+ * remove Removes an entry from the repository
+ * status Status info on the revisions
+ * rdiff "patch" format diff listing between releases
+ * tag Add/delete a symbolic tag to the RCS file
+ * rtag Add/delete a symbolic tag to the RCS file
+ * import Import sources into CVS, using vendor branches
+ * release Indicate that Module is no longer in use.
+ * history Display history of Users and Modules.
+ */
+
+#include "cvs.h"
+#include "patchlevel.h"
+
+#if HAVE_KERBEROS
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <krb.h>
+#ifndef HAVE_KRB_GET_ERR_TEXT
+#define krb_get_err_text(status) krb_err_txt[status]
+#endif
+#endif
+
+#ifndef lint
+static const char rcsid[] = "$CVSid: @(#)main.c 1.78 94/10/07 $\n";
+USE(rcsid);
+#endif
+
+char *program_name;
+char *program_path;
+/*
+ * Initialize comamnd_name to "cvs" so that the first call to
+ * read_cvsrc tries to find global cvs options.
+ */
+char *command_name = "cvs";
+
+/*
+ * Since some systems don't define this...
+ */
+#ifndef MAXHOSTNAMELEN
+#define MAXHOSTNAMELEN 256
+#endif
+
+char hostname[MAXHOSTNAMELEN];
+
+#ifdef AUTH_CLIENT_SUPPORT
+int use_authenticating_server = FALSE;
+#endif /* AUTH_CLIENT_SUPPORT */
+int use_editor = TRUE;
+int use_cvsrc = TRUE;
+int cvswrite = !CVSREAD_DFLT;
+int really_quiet = FALSE;
+int quiet = FALSE;
+int trace = FALSE;
+int noexec = FALSE;
+int logoff = FALSE;
+mode_t cvsumask = UMASK_DFLT;
+
+char *CurDir;
+
+/*
+ * Defaults, for the environment variables that are not set
+ */
+char *Rcsbin = RCSBIN_DFLT;
+char *Editor = EDITOR_DFLT;
+char *CVSroot = CVSROOT_DFLT;
+#ifdef CVSADM_ROOT
+/*
+ * The path found in CVS/Root must match $CVSROOT and/or 'cvs -d root'
+ */
+char *CVSADM_Root = CVSROOT_DFLT;
+#endif /* CVSADM_ROOT */
+
+int add PROTO((int argc, char **argv));
+int admin PROTO((int argc, char **argv));
+int checkout PROTO((int argc, char **argv));
+int commit PROTO((int argc, char **argv));
+int diff PROTO((int argc, char **argv));
+int history PROTO((int argc, char **argv));
+int import PROTO((int argc, char **argv));
+int cvslog PROTO((int argc, char **argv));
+#ifdef AUTH_CLIENT_SUPPORT
+int login PROTO((int argc, char **argv));
+#endif /* AUTH_CLIENT_SUPPORT */
+int patch PROTO((int argc, char **argv));
+int release PROTO((int argc, char **argv));
+int cvsremove PROTO((int argc, char **argv));
+int rtag PROTO((int argc, char **argv));
+int status PROTO((int argc, char **argv));
+int tag PROTO((int argc, char **argv));
+int update PROTO((int argc, char **argv));
+
+const struct cmd
+{
+ char *fullname; /* Full name of the function (e.g. "commit") */
+ char *nick1; /* alternate name (e.g. "ci") */
+ char *nick2; /* another alternate names (e.g. "ci") */
+ int (*func) (); /* Function takes (argc, argv) arguments. */
+#ifdef CLIENT_SUPPORT
+ int (*client_func) (); /* Function to do it via the protocol. */
+#endif
+} cmds[] =
+
+{
+#ifdef CLIENT_SUPPORT
+#define CMD_ENTRY(n1, n2, n3, f1, f2) { n1, n2, n3, f1, f2 }
+#else
+#define CMD_ENTRY(n1, n2, n3, f1, f2) { n1, n2, n3, f1 }
+#endif
+
+ CMD_ENTRY("add", "ad", "new", add, client_add),
+#ifndef CVS_NOADMIN
+ CMD_ENTRY("admin", "adm", "rcs", admin, client_admin),
+#endif
+ CMD_ENTRY("checkout", "co", "get", checkout, client_checkout),
+ CMD_ENTRY("commit", "ci", "com", commit, client_commit),
+ CMD_ENTRY("diff", "di", "dif", diff, client_diff),
+ CMD_ENTRY("export", "exp", "ex", checkout, client_export),
+ CMD_ENTRY("history", "hi", "his", history, client_history),
+ CMD_ENTRY("import", "im", "imp", import, client_import),
+ CMD_ENTRY("log", "lo", "rlog", cvslog, client_log),
+#ifdef AUTH_CLIENT_SUPPORT
+ CMD_ENTRY("login", "logon", "lgn", login, login),
+#endif /* AUTH_CLIENT_SUPPORT */
+ CMD_ENTRY("rdiff", "patch", "pa", patch, client_rdiff),
+ CMD_ENTRY("release", "re", "rel", release, client_release),
+ CMD_ENTRY("remove", "rm", "delete", cvsremove, client_remove),
+ CMD_ENTRY("status", "st", "stat", status, client_status),
+ CMD_ENTRY("rtag", "rt", "rfreeze", rtag, client_rtag),
+ CMD_ENTRY("tag", "ta", "freeze", tag, client_tag),
+ CMD_ENTRY("update", "up", "upd", update, client_update),
+
+#ifdef SERVER_SUPPORT
+ /*
+ * The client_func is also server because we might have picked up a
+ * CVSROOT environment variable containing a colon. The client will send
+ * the real root later.
+ */
+ CMD_ENTRY("server", "server", "server", server, server),
+#endif
+ CMD_ENTRY(NULL, NULL, NULL, NULL, NULL),
+
+#undef CMD_ENTRY
+};
+
+static const char *const usg[] =
+{
+ "Usage: %s [cvs-options] command [command-options] [files...]\n",
+ " Where 'cvs-options' are:\n",
+ " -H Displays Usage information for command\n",
+ " -Q Cause CVS to be really quiet.\n",
+ " -q Cause CVS to be somewhat quiet.\n",
+#ifdef AUTH_CLIENT_SUPPORT
+ " -a Use the authenticating server, not rsh.\n",
+#endif /* AUTH_CLIENT_SUPPORT */
+ " -r Make checked-out files read-only\n",
+ " -w Make checked-out files read-write (default)\n",
+ " -l Turn History logging off\n",
+ " -n Do not execute anything that will change the disk\n",
+ " -t Show trace of program execution -- Try with -n\n",
+ " -v CVS version and copyright\n",
+ " -b bindir Find RCS programs in 'bindir'\n",
+ " -e editor Use 'editor' for editing log information\n",
+ " -d CVS_root Overrides $CVSROOT as the root of the CVS tree\n",
+ " -f Do not use the ~/.cvsrc file\n",
+#ifdef CLIENT_SUPPORT
+ " -z # Use 'gzip -#' for net traffic if possible.\n",
+#endif
+ "\n",
+ " and where 'command' is:\n",
+ " add Adds a new file/directory to the repository\n",
+ " admin Administration front end for rcs\n",
+ " checkout Checkout sources for editing\n",
+ " commit Checks files into the repository\n",
+ " diff Runs diffs between revisions\n",
+ " history Shows status of files and users\n",
+ " import Import sources into CVS, using vendor branches\n",
+ " export Export sources from CVS, similar to checkout\n",
+ " log Prints out 'rlog' information for files\n",
+#ifdef AUTH_CLIENT_SUPPORT
+ " login Prompt for password for authenticating server.\n",
+#endif /* AUTH_CLIENT_SUPPORT */
+ " rdiff 'patch' format diffs between releases\n",
+ " release Indicate that a Module is no longer in use\n",
+ " remove Removes an entry from the repository\n",
+ " status Status info on the revisions\n",
+ " tag Add a symbolic tag to checked out version of RCS file\n",
+ " rtag Add a symbolic tag to the RCS file\n",
+ " update Brings work tree in sync with repository\n",
+ NULL,
+};
+
+static RETSIGTYPE
+main_cleanup ()
+{
+ exit (1);
+}
+
+static void
+error_cleanup ()
+{
+ Lock_Cleanup();
+#ifdef SERVER_SUPPORT
+ if (server_active)
+ server_cleanup (0);
+#endif
+}
+
+int
+main (argc, argv)
+ int argc;
+ char **argv;
+{
+ extern char *version_string;
+ extern char *config_string;
+ char *cp, *end;
+ const struct cmd *cm;
+ int c, err = 0;
+ static int help = FALSE, version_flag = FALSE;
+ int rcsbin_update_env, cvs_update_env = 0;
+ char tmp[PATH_MAX];
+ static struct option long_options[] =
+ {
+ {"help", 0, &help, TRUE},
+ {"version", 0, &version_flag, TRUE},
+ {0, 0, 0, 0}
+ };
+ /* `getopt_long' stores the option index here, but right now we
+ don't use it. */
+ int option_index = 0;
+
+ error_set_cleanup (error_cleanup);
+
+/* The IBM TCP/IP library under OS/2 needs to be initialized: */
+#ifdef NEED_CALL_SOCKINIT
+ if (SockInit () != TRUE)
+ {
+ fprintf (stderr, "SockInit() failed!\n");
+ exit (1);
+ }
+#endif /* NEED_CALL_SOCKINIT */
+
+ /*
+ * Just save the last component of the path for error messages
+ */
+ program_path = xstrdup (argv[0]);
+ program_name = last_component (argv[0]);
+
+ CurDir = xmalloc (PATH_MAX);
+#ifndef SERVER_SUPPORT
+ if (!getwd (CurDir))
+ error (1, 0, "cannot get working directory: %s", CurDir);
+#endif
+
+ /*
+ * Query the environment variables up-front, so that
+ * they can be overridden by command line arguments
+ */
+ rcsbin_update_env = *Rcsbin; /* RCSBIN_DFLT must be set */
+ cvs_update_env = 0;
+ if ((cp = getenv (RCSBIN_ENV)) != NULL)
+ {
+ Rcsbin = cp;
+ rcsbin_update_env = 0; /* it's already there */
+ }
+ if ((cp = getenv (EDITOR1_ENV)) != NULL)
+ Editor = cp;
+ else if ((cp = getenv (EDITOR2_ENV)) != NULL)
+ Editor = cp;
+ else if ((cp = getenv (EDITOR3_ENV)) != NULL)
+ Editor = cp;
+ if ((cp = getenv (CVSROOT_ENV)) != NULL)
+ {
+ CVSroot = cp;
+ cvs_update_env = 0; /* it's already there */
+ }
+ if (getenv (CVSREAD_ENV) != NULL)
+ cvswrite = FALSE;
+ if ((cp = getenv (CVSUMASK_ENV)) != NULL)
+ {
+ /* FIXME: Should be accepting symbolic as well as numeric mask. */
+ cvsumask = strtol (cp, &end, 8) & 0777;
+ if (*end != '\0')
+ error (1, errno, "invalid umask value in %s (%s)",
+ CVSUMASK_ENV, cp);
+ }
+
+ /*
+ * Scan cvsrc file for global options.
+ */
+ read_cvsrc(&argc, &argv);
+
+ /* This has the effect of setting getopt's ordering to REQUIRE_ORDER,
+ which is what we need to distinguish between global options and
+ command options. FIXME: It would appear to be possible to do this
+ much less kludgily by passing "+" as the first character to the
+ option string we pass to getopt_long. */
+ optind = 1;
+
+ while ((c = getopt_long
+ (argc, argv, "Qqrawtnlvb:e:d:Hfz:", long_options, &option_index))
+ != EOF)
+ {
+ switch (c)
+ {
+ case 0:
+ /* getopt_long took care of setting the flag. */
+ break;
+ case 'Q':
+ really_quiet = TRUE;
+ /* FALL THROUGH */
+ case 'q':
+ quiet = TRUE;
+ break;
+ case 'r':
+ cvswrite = FALSE;
+ break;
+#ifdef AUTH_CLIENT_SUPPORT
+ case 'a':
+ use_authenticating_server = TRUE;
+ break;
+#endif /* AUTH_CLIENT_SUPPORT */
+ case 'w':
+ cvswrite = TRUE;
+ break;
+ case 't':
+ trace = TRUE;
+ break;
+ case 'n':
+ noexec = TRUE;
+ case 'l': /* Fall through */
+ logoff = TRUE;
+ break;
+ case 'v':
+ version_flag = TRUE;
+ break;
+ case 'b':
+ Rcsbin = optarg;
+ rcsbin_update_env = 1; /* need to update environment */
+ break;
+ case 'e':
+ Editor = optarg;
+ break;
+ case 'd':
+ CVSroot = optarg;
+ cvs_update_env = 1; /* need to update environment */
+ break;
+ case 'H':
+ use_cvsrc = FALSE; /* this ensure that cvs -H works */
+ help = TRUE;
+ break;
+ case 'f':
+ use_cvsrc = FALSE;
+ break;
+#ifdef CLIENT_SUPPORT
+ case 'z':
+ gzip_level = atoi (optarg);
+ if (gzip_level <= 0 || gzip_level > 9)
+ error (1, 0,
+ "gzip compression level must be between 1 and 9");
+ break;
+#endif
+ case '?':
+ default:
+ usage (usg);
+ }
+ }
+
+ if (version_flag == TRUE)
+ {
+ (void) fputs (version_string, stdout);
+ (void) fputs (config_string, stdout);
+ (void) sprintf (tmp, "Patch Level: %d\n", PATCHLEVEL);
+ (void) fputs (tmp, stdout);
+ (void) fputs ("\n", stdout);
+ (void) fputs ("Copyright (c) 1993-1994 Brian Berliner\n", stdout);
+ (void) fputs ("Copyright (c) 1993-1994 david d `zoo' zuhn\n", stdout);
+ (void) fputs ("Copyright (c) 1992, Brian Berliner and Jeff Polk\n", stdout);
+ (void) fputs ("Copyright (c) 1989-1992, Brian Berliner\n", stdout);
+ (void) fputs ("\n", stdout);
+ (void) fputs ("CVS may be copied only under the terms of the GNU General Public License,\n", stdout);
+ (void) fputs ("a copy of which can be found with the CVS distribution kit.\n", stdout);
+ exit (0);
+ }
+
+ argc -= optind;
+ argv += optind;
+ if (argc < 1)
+ usage (usg);
+
+#ifdef HAVE_KERBEROS
+ /* If we are invoked with a single argument "kserver", then we are
+ running as Kerberos server as root. Do the authentication as
+ the very first thing, to minimize the amount of time we are
+ running as root. */
+ if (strcmp (argv[0], "kserver") == 0)
+ {
+ int status;
+ char instance[INST_SZ];
+ struct sockaddr_in peer;
+ struct sockaddr_in laddr;
+ int len;
+ KTEXT_ST ticket;
+ AUTH_DAT auth;
+ char version[KRB_SENDAUTH_VLEN];
+ Key_schedule sched;
+ char user[ANAME_SZ];
+ struct passwd *pw;
+
+ strcpy (instance, "*");
+ len = sizeof peer;
+ if (getpeername (STDIN_FILENO, (struct sockaddr *) &peer, &len) < 0
+ || getsockname (STDIN_FILENO, (struct sockaddr *) &laddr,
+ &len) < 0)
+ {
+ printf ("E Fatal error, aborting.\n\
+error %s getpeername or getsockname failed\n", strerror (errno));
+ exit (1);
+ }
+
+ status = krb_recvauth (KOPT_DO_MUTUAL, STDIN_FILENO, &ticket, "rcmd",
+ instance, &peer, &laddr, &auth, "", sched,
+ version);
+ if (status != KSUCCESS)
+ {
+ printf ("E Fatal error, aborting.\n\
+error 0 kerberos: %s\n", krb_get_err_text(status));
+ exit (1);
+ }
+
+ /* Get the local name. */
+ status = krb_kntoln (&auth, user);
+ if (status != KSUCCESS)
+ {
+ printf ("E Fatal error, aborting.\n\
+error 0 kerberos: can't get local name: %s\n", krb_get_err_text(status));
+ exit (1);
+ }
+
+ pw = getpwnam (user);
+ if (pw == NULL)
+ {
+ printf ("E Fatal error, aborting.\n\
+error 0 %s: no such user\n", user);
+ exit (1);
+ }
+
+ initgroups (pw->pw_name, pw->pw_gid);
+ setgid (pw->pw_gid);
+ setuid (pw->pw_uid);
+ /* Inhibit access by randoms. Don't want people randomly
+ changing our temporary tree before we check things in. */
+ umask (077);
+
+#if HAVE_PUTENV
+ /* Set LOGNAME and USER in the environment, in case they are
+ already set to something else. */
+ {
+ char *env;
+
+ env = xmalloc (sizeof "LOGNAME=" + strlen (user));
+ (void) sprintf (env, "LOGNAME=%s", user);
+ (void) putenv (env);
+
+ env = xmalloc (sizeof "USER=" + strlen (user));
+ (void) sprintf (env, "USER=%s", user);
+ (void) putenv (env);
+ }
+#endif
+
+ /* Pretend we were invoked as a plain server. */
+ argv[0] = "server";
+ }
+#endif /* HAVE_KERBEROS */
+
+
+#if defined(AUTH_SERVER_SUPPORT) && defined(SERVER_SUPPORT)
+ if (strcmp (argv[0], "pserver") == 0)
+ {
+ /* Gets username and password from client, authenticates, then
+ switches to run as that user and sends an ACK back to the
+ client. */
+ authenticate_connection ();
+
+ /* Pretend we were invoked as a plain server. */
+ argv[0] = "server";
+ }
+#endif /* AUTH_SERVER_SUPPORT && SERVER_SUPPORT */
+
+
+#ifdef CVSADM_ROOT
+ /*
+ * See if we are able to find a 'better' value for CVSroot in the
+ * CVSADM_ROOT directory.
+ */
+#ifdef SERVER_SUPPORT
+ if (strcmp (argv[0], "server") == 0 && CVSroot == NULL)
+ CVSADM_Root = NULL;
+ else
+ CVSADM_Root = Name_Root((char *) NULL, (char *) NULL);
+#else /* No SERVER_SUPPORT */
+ CVSADM_Root = Name_Root((char *) NULL, (char *) NULL);
+#endif /* No SERVER_SUPPORT */
+ if (CVSADM_Root != NULL)
+ {
+ if (CVSroot == NULL || !cvs_update_env)
+ {
+ CVSroot = CVSADM_Root;
+ cvs_update_env = 1; /* need to update environment */
+ }
+#ifdef CLIENT_SUPPORT
+ else if (!getenv ("CVS_IGNORE_REMOTE_ROOT"))
+#else
+ else
+#endif
+ {
+ /*
+ * Now for the hard part, compare the two directories. If they
+ * are not identical, then abort this command.
+ */
+ if ((fncmp (CVSroot, CVSADM_Root) != 0) &&
+ !same_directories(CVSroot, CVSADM_Root))
+ {
+ error (0, 0, "%s value for CVS Root found in %s",
+ CVSADM_Root, CVSADM_ROOT);
+ error (0, 0, "does not match command line -d %s setting",
+ CVSroot);
+ error (1, 0,
+ "you may wish to try the cvs command again without the -d option ");
+ }
+ }
+ }
+#endif /* CVSADM_ROOT */
+
+ /*
+ * Specifying just the '-H' flag to the sub-command causes a Usage
+ * message to be displayed.
+ */
+ command_name = cp = argv[0];
+ if (help == TRUE || (argc > 1 && strcmp (argv[1], "-H") == 0))
+ argc = -1;
+ else
+ {
+ /*
+ * Check to see if we can write into the history file. If not,
+ * we assume that we can't work in the repository.
+ * BUT, only if the history file exists.
+ */
+#ifdef SERVER_SUPPORT
+ if (strcmp (command_name, "server") != 0 || CVSroot != NULL)
+#endif
+ {
+ char path[PATH_MAX];
+ int save_errno;
+
+ if (!CVSroot || !*CVSroot)
+ error (1, 0, "You don't have a %s environment variable",
+ CVSROOT_ENV);
+ (void) sprintf (path, "%s/%s", CVSroot, CVSROOTADM);
+ if (!isaccessible (path, R_OK | X_OK))
+ {
+ save_errno = errno;
+#ifdef CLIENT_SUPPORT
+ if (strchr (CVSroot, ':') == NULL)
+ {
+#endif
+ error (0, 0,
+ "Sorry, you don't have sufficient access to %s", CVSroot);
+ error (1, save_errno, "%s", path);
+#ifdef CLIENT_SUPPORT
+ }
+#endif
+ }
+ (void) strcat (path, "/");
+ (void) strcat (path, CVSROOTADM_HISTORY);
+ if (isfile (path) && !isaccessible (path, R_OK | W_OK))
+ {
+ save_errno = errno;
+ error (0, 0,
+ "Sorry, you don't have read/write access to the history file");
+ error (1, save_errno, "%s", path);
+ }
+ }
+ }
+
+#ifdef SERVER_SUPPORT
+ if (strcmp (command_name, "server") == 0)
+ /* This is only used for writing into the history file. Might
+ be nice to have hostname and/or remote path, on the other hand
+ I'm not sure whether it is worth the trouble. */
+ strcpy (CurDir, "<remote>");
+ else if (!getwd (CurDir))
+ error (1, 0, "cannot get working directory: %s", CurDir);
+#endif
+
+#ifdef HAVE_PUTENV
+ /* Now, see if we should update the environment with the Rcsbin value */
+ if (cvs_update_env)
+ {
+ char *env;
+
+ env = xmalloc (strlen (CVSROOT_ENV) + strlen (CVSroot) + 1 + 1);
+ (void) sprintf (env, "%s=%s", CVSROOT_ENV, CVSroot);
+ (void) putenv (env);
+ /* do not free env, as putenv has control of it */
+ }
+ if (rcsbin_update_env)
+ {
+ char *env;
+
+ env = xmalloc (strlen (RCSBIN_ENV) + strlen (Rcsbin) + 1 + 1);
+ (void) sprintf (env, "%s=%s", RCSBIN_ENV, Rcsbin);
+ (void) putenv (env);
+ /* do not free env, as putenv has control of it */
+ }
+#endif
+
+ /*
+ * If Rcsbin is set to something, make sure it is terminated with
+ * a slash character. If not, add one.
+ */
+ if (*Rcsbin)
+ {
+ int len = strlen (Rcsbin);
+ char *rcsbin;
+
+ if (Rcsbin[len - 1] != '/')
+ {
+ rcsbin = Rcsbin;
+ Rcsbin = xmalloc (len + 2); /* one for '/', one for NULL */
+ (void) strcpy (Rcsbin, rcsbin);
+ (void) strcat (Rcsbin, "/");
+ }
+ }
+
+ for (cm = cmds; cm->fullname; cm++)
+ {
+ if (cm->nick1 && !strcmp (cp, cm->nick1))
+ break;
+ if (cm->nick2 && !strcmp (cp, cm->nick2))
+ break;
+ if (!strcmp (cp, cm->fullname))
+ break;
+ }
+
+ if (!cm->fullname)
+ usage (usg); /* no match */
+ else
+ {
+ command_name = cm->fullname; /* Global pointer for later use */
+
+ /* make sure we clean up on error */
+#ifdef SIGHUP
+ (void) SIG_register (SIGHUP, main_cleanup);
+ (void) SIG_register (SIGHUP, Lock_Cleanup);
+#endif
+#ifdef SIGINT
+ (void) SIG_register (SIGINT, main_cleanup);
+ (void) SIG_register (SIGINT, Lock_Cleanup);
+#endif
+#ifdef SIGQUIT
+ (void) SIG_register (SIGQUIT, main_cleanup);
+ (void) SIG_register (SIGQUIT, Lock_Cleanup);
+#endif
+#ifdef SIGPIPE
+ (void) SIG_register (SIGPIPE, main_cleanup);
+ (void) SIG_register (SIGPIPE, Lock_Cleanup);
+#endif
+#ifdef SIGTERM
+ (void) SIG_register (SIGTERM, main_cleanup);
+ (void) SIG_register (SIGTERM, Lock_Cleanup);
+#endif
+
+ gethostname(hostname, sizeof (hostname));
+
+#ifdef HAVE_SETVBUF
+ /*
+ * Make stdout line buffered, so 'tail -f' can monitor progress.
+ * Patch creates too much output to monitor and it runs slowly.
+ */
+ if (strcmp (cm->fullname, "patch"))
+ (void) setvbuf (stdout, (char *) NULL, _IOLBF, 0);
+#endif
+
+ if (use_cvsrc)
+ read_cvsrc(&argc, &argv);
+
+#ifdef CLIENT_SUPPORT
+ /* If cvsroot contains a colon, try to do it via the protocol. */
+ {
+ char *p = CVSroot == NULL ? NULL : strchr (CVSroot, ':');
+ if (p)
+ err = (*(cm->client_func)) (argc, argv);
+ else
+ err = (*(cm->func)) (argc, argv);
+ }
+#else /* No CLIENT_SUPPORT */
+ err = (*(cm->func)) (argc, argv);
+
+#endif /* No CLIENT_SUPPORT */
+ }
+ /*
+ * If the command's error count is modulo 256, we need to change it
+ * so that we don't overflow the 8-bits we get to report exit status
+ */
+ if (err && (err % 256) == 0)
+ err = 1;
+ Lock_Cleanup ();
+ return (err);
+}
+
+char *
+Make_Date (rawdate)
+ char *rawdate;
+{
+ struct tm *ftm;
+ time_t unixtime;
+ char date[256]; /* XXX bigger than we'll ever need? */
+ char *ret;
+
+ unixtime = get_date (rawdate, (struct timeb *) NULL);
+ if (unixtime == (time_t) - 1)
+ error (1, 0, "Can't parse date/time: %s", rawdate);
+#ifdef HAVE_RCS5
+ ftm = gmtime (&unixtime);
+#else
+ ftm = localtime (&unixtime);
+#endif
+ (void) sprintf (date, DATEFORM,
+ ftm->tm_year + (ftm->tm_year < 100 ? 0 : 1900),
+ ftm->tm_mon + 1, ftm->tm_mday, ftm->tm_hour,
+ ftm->tm_min, ftm->tm_sec);
+ ret = xstrdup (date);
+ return (ret);
+}
+
+void
+usage (cpp)
+ register const char *const *cpp;
+{
+ (void) fprintf (stderr, *cpp++, program_name, command_name);
+ for (; *cpp; cpp++)
+ (void) fprintf (stderr, *cpp);
+ exit (1);
+}
diff --git a/gnu/usr.bin/cvs/cvs/modules.c b/gnu/usr.bin/cvs/cvs/modules.c
new file mode 100644
index 0000000..5946052
--- /dev/null
+++ b/gnu/usr.bin/cvs/cvs/modules.c
@@ -0,0 +1,884 @@
+/*
+ * Copyright (c) 1992, Brian Berliner and Jeff Polk
+ * Copyright (c) 1989-1992, Brian Berliner
+ *
+ * You may distribute under the terms of the GNU General Public License
+ * as specified in the README file that comes with the CVS 1.4 kit.
+ *
+ * Modules
+ *
+ * Functions for accessing the modules file.
+ *
+ * The modules file supports basically three formats of lines:
+ * key [options] directory files... [ -x directory [files] ] ...
+ * key [options] directory [ -x directory [files] ] ...
+ * key -a aliases...
+ *
+ * The -a option allows an aliasing step in the parsing of the modules
+ * file. The "aliases" listed on a line following the -a are
+ * processed one-by-one, as if they were specified as arguments on the
+ * command line.
+ */
+
+#include "cvs.h"
+#include "save-cwd.h"
+
+#ifndef lint
+static const char rcsid[] = "$CVSid: @(#)modules.c 1.62 94/09/29 $";
+USE(rcsid);
+#endif
+
+struct sortrec
+{
+ char *modname;
+ char *status;
+ char *rest;
+ char *comment;
+};
+
+static int sort_order PROTO((const PTR l, const PTR r));
+static void save_d PROTO((char *k, int ks, char *d, int ds));
+
+
+/*
+ * Open the modules file, and die if the CVSROOT environment variable
+ * was not set. If the modules file does not exist, that's fine, and
+ * a warning message is displayed and a NULL is returned.
+ */
+DBM *
+open_module ()
+{
+ char mfile[PATH_MAX];
+
+ if (CVSroot == NULL)
+ {
+ (void) fprintf (stderr,
+ "%s: must set the CVSROOT environment variable\n",
+ program_name);
+ error (1, 0, "or specify the '-d' option to %s", program_name);
+ }
+ (void) sprintf (mfile, "%s/%s/%s", CVSroot, CVSROOTADM, CVSROOTADM_MODULES);
+ return (dbm_open (mfile, O_RDONLY, 0666));
+}
+
+/*
+ * Close the modules file, if the open succeeded, that is
+ */
+void
+close_module (db)
+ DBM *db;
+{
+ if (db != NULL)
+ dbm_close (db);
+}
+
+/*
+ * This is the recursive function that processes a module name.
+ * It calls back the passed routine for each directory of a module
+ * It runs the post checkout or post tag proc from the modules file
+ */
+int
+do_module (db, mname, m_type, msg, callback_proc, where,
+ shorten, local_specified, run_module_prog, extra_arg)
+ DBM *db;
+ char *mname;
+ enum mtype m_type;
+ char *msg;
+ CALLBACKPROC callback_proc;
+ char *where;
+ int shorten;
+ int local_specified;
+ int run_module_prog;
+ char *extra_arg;
+{
+ char *checkin_prog = NULL;
+ char *checkout_prog = NULL;
+ char *export_prog = NULL;
+ char *tag_prog = NULL;
+ char *update_prog = NULL;
+ struct saved_cwd cwd;
+ char line[MAXLINELEN];
+ int modargc;
+ int xmodargc;
+ char **modargv;
+ char *xmodargv[MAXFILEPERDIR];
+ char *value;
+ char *zvalue;
+ char *mwhere = NULL;
+ char *mfile = NULL;
+ char *spec_opt = NULL;
+ char xvalue[PATH_MAX];
+ int alias = 0;
+ datum key, val;
+ char *cp;
+ int c, err = 0;
+
+#ifdef SERVER_SUPPORT
+ if (trace)
+ {
+ fprintf (stderr, "%c-> do_module (%s, %s, %s, %s)\n",
+ (server_active) ? 'S' : ' ',
+ mname, msg, where ? where : "",
+ extra_arg ? extra_arg : "");
+ }
+#endif
+
+ /* remember where we start */
+ if (save_cwd (&cwd))
+ exit (1);
+
+ /* if this is a directory to ignore, add it to that list */
+ if (mname[0] == '!' && mname[1] != '\0')
+ {
+ ign_dir_add (mname+1);
+ return(err);
+ }
+
+ /* strip extra stuff from the module name */
+ strip_path (mname);
+
+ /*
+ * Look up the module using the following scheme:
+ * 1) look for mname as a module name
+ * 2) look for mname as a directory
+ * 3) look for mname as a file
+ * 4) take mname up to the first slash and look it up as a module name
+ * (this is for checking out only part of a module)
+ */
+
+ /* look it up as a module name */
+ key.dptr = mname;
+ key.dsize = strlen (key.dptr);
+ if (db != NULL)
+ val = dbm_fetch (db, key);
+ else
+ val.dptr = NULL;
+ if (val.dptr != NULL)
+ {
+ /* null terminate the value XXX - is this space ours? */
+ val.dptr[val.dsize] = '\0';
+
+ /* If the line ends in a comment, strip it off */
+ if ((cp = strchr (val.dptr, '#')) != NULL)
+ {
+ do
+ *cp-- = '\0';
+ while (isspace (*cp));
+ }
+ else
+ {
+ /* Always strip trailing spaces */
+ cp = strchr (val.dptr, '\0');
+ while (cp > val.dptr && isspace(*--cp))
+ *cp = '\0';
+ }
+
+ value = val.dptr;
+ mwhere = xstrdup (mname);
+ goto found;
+ }
+ else
+ {
+ char file[PATH_MAX];
+ char attic_file[PATH_MAX];
+ char *acp;
+
+ /* check to see if mname is a directory or file */
+
+ (void) sprintf (file, "%s/%s", CVSroot, mname);
+ if ((acp = strrchr (mname, '/')) != NULL)
+ {
+ *acp = '\0';
+ (void) sprintf (attic_file, "%s/%s/%s/%s%s", CVSroot, mname,
+ CVSATTIC, acp + 1, RCSEXT);
+ *acp = '/';
+ }
+ else
+ (void) sprintf (attic_file, "%s/%s/%s%s", CVSroot, CVSATTIC,
+ mname, RCSEXT);
+
+ if (isdir (file))
+ {
+ value = mname;
+ goto found;
+ }
+ else
+ {
+ (void) strcat (file, RCSEXT);
+ if (isfile (file) || isfile (attic_file))
+ {
+ /* if mname was a file, we have to split it into "dir file" */
+ if ((cp = strrchr (mname, '/')) != NULL && cp != mname)
+ {
+ char *slashp;
+
+ /* put the ' ' in a copy so we don't mess up the original */
+ value = strcpy (xvalue, mname);
+ slashp = strrchr (value, '/');
+ *slashp = ' ';
+ }
+ else
+ {
+ /*
+ * the only '/' at the beginning or no '/' at all
+ * means the file we are interested in is in CVSROOT
+ * itself so the directory should be '.'
+ */
+ if (cp == mname)
+ {
+ /* drop the leading / if specified */
+ value = strcpy (xvalue, ". ");
+ (void) strcat (xvalue, mname + 1);
+ }
+ else
+ {
+ /* otherwise just copy it */
+ value = strcpy (xvalue, ". ");
+ (void) strcat (xvalue, mname);
+ }
+ }
+ goto found;
+ }
+ }
+ }
+
+ /* look up everything to the first / as a module */
+ if (mname[0] != '/' && (cp = strchr (mname, '/')) != NULL)
+ {
+ /* Make the slash the new end of the string temporarily */
+ *cp = '\0';
+ key.dptr = mname;
+ key.dsize = strlen (key.dptr);
+
+ /* do the lookup */
+ if (db != NULL)
+ val = dbm_fetch (db, key);
+ else
+ val.dptr = NULL;
+
+ /* if we found it, clean up the value and life is good */
+ if (val.dptr != NULL)
+ {
+ char *cp2;
+
+ /* null terminate the value XXX - is this space ours? */
+ val.dptr[val.dsize] = '\0';
+
+ /* If the line ends in a comment, strip it off */
+ if ((cp2 = strchr (val.dptr, '#')) != NULL)
+ {
+ do
+ *cp2-- = '\0';
+ while (isspace (*cp2));
+ }
+ value = val.dptr;
+
+ /* mwhere gets just the module name */
+ mwhere = xstrdup (mname);
+ mfile = cp + 1;
+
+ /* put the / back in mname */
+ *cp = '/';
+
+ goto found;
+ }
+
+ /* put the / back in mname */
+ *cp = '/';
+ }
+
+ /* if we got here, we couldn't find it using our search, so give up */
+ error (0, 0, "cannot find module `%s' - ignored", mname);
+ err++;
+ if (mwhere)
+ free (mwhere);
+ return (err);
+
+
+ /*
+ * At this point, we found what we were looking for in one
+ * of the many different forms.
+ */
+ found:
+
+ /* copy value to our own string since if we go recursive we'll be
+ really screwed if we do another dbm lookup */
+ zvalue = xstrdup (value);
+ value = zvalue;
+
+ /* search the value for the special delimiter and save for later */
+ if ((cp = strchr (value, CVSMODULE_SPEC)) != NULL)
+ {
+ *cp = '\0'; /* null out the special char */
+ spec_opt = cp + 1; /* save the options for later */
+
+ if (cp != value) /* strip whitespace if necessary */
+ while (isspace (*--cp))
+ *cp = '\0';
+
+ if (cp == value)
+ {
+ /*
+ * we had nothing but special options, so skip arg
+ * parsing and regular stuff entirely
+ *
+ * If there were only special ones though, we must
+ * make the appropriate directory and cd to it
+ */
+ char *dir;
+
+ /* XXX - XXX - MAJOR HACK - DO NOT SHIP - this needs to
+ be !pipeout, but we don't know that here yet */
+ if (!run_module_prog)
+ goto out;
+
+ dir = where ? where : mname;
+ /* XXX - think about making null repositories at each dir here
+ instead of just at the bottom */
+ make_directories (dir);
+ if (chdir (dir) < 0)
+ {
+ error (0, errno, "cannot chdir to %s", dir);
+ spec_opt = NULL;
+ err++;
+ goto out;
+ }
+ if (!isfile (CVSADM))
+ {
+ char nullrepos[PATH_MAX];
+
+ (void) sprintf (nullrepos, "%s/%s/%s", CVSroot,
+ CVSROOTADM, CVSNULLREPOS);
+ if (!isfile (nullrepos))
+ {
+ mode_t omask;
+ omask = umask (cvsumask);
+ (void) CVS_MKDIR (nullrepos, 0777);
+ (void) umask (omask);
+ }
+ if (!isdir (nullrepos))
+ error (1, 0, "there is no repository %s", nullrepos);
+
+ Create_Admin (".", dir,
+ nullrepos, (char *) NULL, (char *) NULL);
+ if (!noexec)
+ {
+ FILE *fp;
+
+ fp = open_file (CVSADM_ENTSTAT, "w+");
+ if (fclose (fp) == EOF)
+ error (1, errno, "cannot close %s", CVSADM_ENTSTAT);
+#ifdef SERVER_SUPPORT
+ if (server_active)
+ server_set_entstat (dir, nullrepos);
+#endif
+ }
+ }
+ out:
+ goto do_special;
+ }
+ }
+
+ /* don't do special options only part of a module was specified */
+ if (mfile != NULL)
+ spec_opt = NULL;
+
+ /*
+ * value now contains one of the following:
+ * 1) dir
+ * 2) dir file
+ * 3) the value from modules without any special args
+ * [ args ] dir [file] [file] ...
+ * or -a module [ module ] ...
+ */
+
+ /* Put the value on a line with XXX prepended for getopt to eat */
+ (void) sprintf (line, "%s %s", "XXX", value);
+
+ /* turn the line into an argv[] array */
+ line2argv (&xmodargc, xmodargv, line);
+ modargc = xmodargc;
+ modargv = xmodargv;
+
+ /* parse the args */
+ optind = 1;
+ while ((c = getopt (modargc, modargv, CVSMODULE_OPTS)) != -1)
+ {
+ switch (c)
+ {
+ case 'a':
+ alias = 1;
+ break;
+ case 'd':
+ if (mwhere)
+ free (mwhere);
+ mwhere = xstrdup (optarg);
+ break;
+ case 'i':
+ checkin_prog = optarg;
+ break;
+ case 'l':
+ local_specified = 1;
+ case 'o':
+ checkout_prog = optarg;
+ break;
+ case 'e':
+ export_prog = optarg;
+ break;
+ case 't':
+ tag_prog = optarg;
+ break;
+ case 'u':
+ update_prog = optarg;
+ break;
+ case '?':
+ error (0, 0,
+ "modules file has invalid option for key %s value %s",
+ key.dptr, val.dptr);
+ err++;
+ if (mwhere)
+ free (mwhere);
+ free (zvalue);
+ return (err);
+ }
+ }
+ modargc -= optind;
+ modargv += optind;
+ if (modargc == 0)
+ {
+ error (0, 0, "modules file missing directory for module %s", mname);
+ if (mwhere)
+ free (mwhere);
+ free (zvalue);
+ return (++err);
+ }
+
+ /* if this was an alias, call ourselves recursively for each module */
+ if (alias)
+ {
+ int i;
+
+ for (i = 0; i < modargc; i++)
+ {
+ if (strcmp (mname, modargv[i]) == 0)
+ error (0, 0,
+ "module `%s' in modules file contains infinite loop",
+ mname);
+ else
+ err += do_module (db, modargv[i], m_type, msg, callback_proc,
+ where, shorten, local_specified,
+ run_module_prog, extra_arg);
+ }
+ if (mwhere)
+ free (mwhere);
+ free (zvalue);
+ return (err);
+ }
+
+ /* otherwise, process this module */
+ err += callback_proc (&modargc, modargv, where, mwhere, mfile, shorten,
+ local_specified, mname, msg);
+
+#if 0
+ /* FIXME: I've fixed this so that the correct arguments are called,
+ but now this fails because there is code below this point that
+ uses optarg values extracted from the arg vector. */
+ free_names (&xmodargc, xmodargv);
+#endif
+
+ /* if there were special include args, process them now */
+
+ do_special:
+
+ /* blow off special options if -l was specified */
+ if (local_specified)
+ spec_opt = NULL;
+
+ while (spec_opt != NULL)
+ {
+ char *next_opt;
+
+ cp = strchr (spec_opt, CVSMODULE_SPEC);
+ if (cp != NULL)
+ {
+ /* save the beginning of the next arg */
+ next_opt = cp + 1;
+
+ /* strip whitespace off the end */
+ do
+ *cp = '\0';
+ while (isspace (*--cp));
+ }
+ else
+ next_opt = NULL;
+
+ /* strip whitespace from front */
+ while (isspace (*spec_opt))
+ spec_opt++;
+
+ if (*spec_opt == '\0')
+ error (0, 0, "Mal-formed %c option for module %s - ignored",
+ CVSMODULE_SPEC, mname);
+ else
+ err += do_module (db, spec_opt, m_type, msg, callback_proc,
+ (char *) NULL, 0, local_specified,
+ run_module_prog, extra_arg);
+ spec_opt = next_opt;
+ }
+
+ /* write out the checkin/update prog files if necessary */
+#ifdef SERVER_SUPPORT
+ if (err == 0 && !noexec && m_type == CHECKOUT && server_expanding)
+ {
+ if (checkin_prog != NULL)
+ server_prog (where ? where : mname, checkin_prog, PROG_CHECKIN);
+ if (update_prog != NULL)
+ server_prog (where ? where : mname, update_prog, PROG_UPDATE);
+ }
+ else
+#endif
+ if (err == 0 && !noexec && m_type == CHECKOUT && run_module_prog)
+ {
+ FILE *fp;
+
+ if (checkin_prog != NULL)
+ {
+ fp = open_file (CVSADM_CIPROG, "w+");
+ (void) fprintf (fp, "%s\n", checkin_prog);
+ if (fclose (fp) == EOF)
+ error (1, errno, "cannot close %s", CVSADM_CIPROG);
+ }
+ if (update_prog != NULL)
+ {
+ fp = open_file (CVSADM_UPROG, "w+");
+ (void) fprintf (fp, "%s\n", update_prog);
+ if (fclose (fp) == EOF)
+ error (1, errno, "cannot close %s", CVSADM_UPROG);
+ }
+ }
+
+ /* cd back to where we started */
+ if (restore_cwd (&cwd, NULL))
+ exit (1);
+ free_cwd (&cwd);
+
+ /* run checkout or tag prog if appropriate */
+ if (err == 0 && run_module_prog)
+ {
+ if ((m_type == TAG && tag_prog != NULL) ||
+ (m_type == CHECKOUT && checkout_prog != NULL) ||
+ (m_type == EXPORT && export_prog != NULL))
+ {
+ /*
+ * If a relative pathname is specified as the checkout, tag
+ * or export proc, try to tack on the current "where" value.
+ * if we can't find a matching program, just punt and use
+ * whatever is specified in the modules file.
+ */
+ char real_prog[PATH_MAX];
+ char *prog = (m_type == TAG ? tag_prog :
+ (m_type == CHECKOUT ? checkout_prog : export_prog));
+ char *real_where = (where != NULL ? where : mwhere);
+
+ if ((*prog != '/') && (*prog != '.'))
+ {
+ (void) sprintf (real_prog, "%s/%s", real_where, prog);
+ if (isfile (real_prog))
+ prog = real_prog;
+ }
+
+ run_setup ("%s %s", prog, real_where);
+ if (extra_arg)
+ run_arg (extra_arg);
+
+ if (!quiet)
+ {
+ (void) printf ("%s %s: Executing '", program_name,
+ command_name);
+ run_print (stdout);
+ (void) printf ("'\n");
+ }
+ err += run_exec (RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL);
+ }
+ }
+
+ /* clean up */
+ if (mwhere)
+ free (mwhere);
+ free (zvalue);
+
+ return (err);
+}
+
+/* - Read all the records from the modules database into an array.
+ - Sort the array depending on what format is desired.
+ - Print the array in the format desired.
+
+ Currently, there are only two "desires":
+
+ 1. Sort by module name and format the whole entry including switches,
+ files and the comment field: (Including aliases)
+
+ modulename -s switches, one per line, even if
+ -i it has many switches.
+ Directories and files involved, formatted
+ to cover multiple lines if necessary.
+ # Comment, also formatted to cover multiple
+ # lines if necessary.
+
+ 2. Sort by status field string and print: (*not* including aliases)
+
+ modulename STATUS Directories and files involved, formatted
+ to cover multiple lines if necessary.
+ # Comment, also formatted to cover multiple
+ # lines if necessary.
+*/
+
+static struct sortrec *s_head;
+
+static int s_max = 0; /* Number of elements allocated */
+static int s_count = 0; /* Number of elements used */
+
+static int Status; /* Nonzero if the user is
+ interested in status
+ information as well as
+ module name */
+static char def_status[] = "NONE";
+
+/* Sort routine for qsort:
+ - If we want the "Status" field to be sorted, check it first.
+ - Then compare the "module name" fields. Since they are unique, we don't
+ have to look further.
+*/
+static int
+sort_order (l, r)
+ const PTR l;
+ const PTR r;
+{
+ int i;
+ const struct sortrec *left = (const struct sortrec *) l;
+ const struct sortrec *right = (const struct sortrec *) r;
+
+ if (Status)
+ {
+ /* If Sort by status field, compare them. */
+ if ((i = strcmp (left->status, right->status)) != 0)
+ return (i);
+ }
+ return (strcmp (left->modname, right->modname));
+}
+
+static void
+save_d (k, ks, d, ds)
+ char *k;
+ int ks;
+ char *d;
+ int ds;
+{
+ char *cp, *cp2;
+ struct sortrec *s_rec;
+
+ if (Status && *d == '-' && *(d + 1) == 'a')
+ return; /* We want "cvs co -s" and it is an alias! */
+
+ if (s_count == s_max)
+ {
+ s_max += 64;
+ s_head = (struct sortrec *) xrealloc ((char *) s_head, s_max * sizeof (*s_head));
+ }
+ s_rec = &s_head[s_count];
+ s_rec->modname = cp = xmalloc (ks + 1);
+ (void) strncpy (cp, k, ks);
+ *(cp + ks) = '\0';
+
+ s_rec->rest = cp2 = xmalloc (ds + 1);
+ cp = d;
+ *(cp + ds) = '\0'; /* Assumes an extra byte at end of static dbm buffer */
+
+ while (isspace (*cp))
+ cp++;
+ /* Turn <spaces> into one ' ' -- makes the rest of this routine simpler */
+ while (*cp)
+ {
+ if (isspace (*cp))
+ {
+ *cp2++ = ' ';
+ while (isspace (*cp))
+ cp++;
+ }
+ else
+ *cp2++ = *cp++;
+ }
+ *cp2 = '\0';
+
+ /* Look for the "-s statusvalue" text */
+ if (Status)
+ {
+ s_rec->status = def_status;
+
+ /* Minor kluge, but general enough to maintain */
+ for (cp = s_rec->rest; (cp2 = strchr (cp, '-')) != NULL; cp = ++cp2)
+ {
+ if (*(cp2 + 1) == 's' && *(cp2 + 2) == ' ')
+ {
+ s_rec->status = (cp2 += 3);
+ while (*cp2 != ' ')
+ cp2++;
+ *cp2++ = '\0';
+ cp = cp2;
+ break;
+ }
+ }
+ }
+ else
+ cp = s_rec->rest;
+
+ /* Find comment field, clean up on all three sides & compress blanks */
+ if ((cp2 = cp = strchr (cp, '#')) != NULL)
+ {
+ if (*--cp2 == ' ')
+ *cp2 = '\0';
+ if (*++cp == ' ')
+ cp++;
+ s_rec->comment = cp;
+ }
+ else
+ s_rec->comment = "";
+
+ s_count++;
+}
+
+/* Print out the module database as we know it. If STATUS is
+ non-zero, print out status information for each module. */
+
+void
+cat_module (status)
+ int status;
+{
+ DBM *db;
+ datum key, val;
+ int i, c, wid, argc, cols = 80, indent, fill;
+ int moduleargc;
+ struct sortrec *s_h;
+ char *cp, *cp2, **argv;
+ char line[MAXLINELEN], *moduleargv[MAXFILEPERDIR];
+
+#ifdef sun
+#ifdef TIOCGSIZE
+ struct ttysize ts;
+
+ (void) ioctl (0, TIOCGSIZE, &ts);
+ cols = ts.ts_cols;
+#endif
+#else
+#ifdef TIOCGWINSZ
+ struct winsize ws;
+
+ (void) ioctl (0, TIOCGWINSZ, &ws);
+ cols = ws.ws_col;
+#endif
+#endif
+
+ Status = status;
+
+ /* Read the whole modules file into allocated records */
+ if (!(db = open_module ()))
+ error (1, 0, "failed to open the modules file");
+
+ for (key = dbm_firstkey (db); key.dptr != NULL; key = dbm_nextkey (db))
+ {
+ val = dbm_fetch (db, key);
+ if (val.dptr != NULL)
+ save_d (key.dptr, key.dsize, val.dptr, val.dsize);
+ }
+
+ /* Sort the list as requested */
+ qsort ((PTR) s_head, s_count, sizeof (struct sortrec), sort_order);
+
+ /*
+ * Run through the sorted array and format the entries
+ * indent = space for modulename + space for status field
+ */
+ indent = 12 + (status * 12);
+ fill = cols - (indent + 2);
+ for (s_h = s_head, i = 0; i < s_count; i++, s_h++)
+ {
+ /* Print module name (and status, if wanted) */
+ (void) printf ("%-12s", s_h->modname);
+ if (status)
+ {
+ (void) printf (" %-11s", s_h->status);
+ if (s_h->status != def_status)
+ *(s_h->status + strlen (s_h->status)) = ' ';
+ }
+
+ /* Parse module file entry as command line and print options */
+ (void) sprintf (line, "%s %s", s_h->modname, s_h->rest);
+ line2argv (&moduleargc, moduleargv, line);
+ argc = moduleargc;
+ argv = moduleargv;
+
+ optind = 0;
+ wid = 0;
+ while ((c = getopt (argc, argv, CVSMODULE_OPTS)) != -1)
+ {
+ if (!status)
+ {
+ if (c == 'a' || c == 'l')
+ {
+ (void) printf (" -%c", c);
+ wid += 3; /* Could just set it to 3 */
+ }
+ else
+ {
+ if (strlen (optarg) + 4 + wid > (unsigned) fill)
+ {
+ (void) printf ("\n%*s", indent, "");
+ wid = 0;
+ }
+ (void) printf (" -%c %s", c, optarg);
+ wid += strlen (optarg) + 4;
+ }
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+ /* Format and Print all the files and directories */
+ for (; argc--; argv++)
+ {
+ if (strlen (*argv) + wid > (unsigned) fill)
+ {
+ (void) printf ("\n%*s", indent, "");
+ wid = 0;
+ }
+ (void) printf (" %s", *argv);
+ wid += strlen (*argv) + 1;
+ }
+ (void) printf ("\n");
+
+ /* Format the comment field -- save_d (), compressed spaces */
+ for (cp2 = cp = s_h->comment; *cp; cp2 = cp)
+ {
+ (void) printf ("%*s # ", indent, "");
+ if (strlen (cp2) < (unsigned) (fill - 2))
+ {
+ (void) printf ("%s\n", cp2);
+ break;
+ }
+ cp += fill - 2;
+ while (*cp != ' ' && cp > cp2)
+ cp--;
+ if (cp == cp2)
+ {
+ (void) printf ("%s\n", cp2);
+ break;
+ }
+
+ *cp++ = '\0';
+ (void) printf ("%s\n", cp2);
+ }
+
+ free_names(&moduleargc, moduleargv);
+ }
+}
diff --git a/gnu/usr.bin/cvs/cvs/no_diff.c b/gnu/usr.bin/cvs/cvs/no_diff.c
new file mode 100644
index 0000000..281d348
--- /dev/null
+++ b/gnu/usr.bin/cvs/cvs/no_diff.c
@@ -0,0 +1,135 @@
+/*
+ * Copyright (c) 1992, Brian Berliner and Jeff Polk
+ * Copyright (c) 1989-1992, Brian Berliner
+ *
+ * You may distribute under the terms of the GNU General Public License as
+ * specified in the README file that comes with the CVS 1.4 kit.
+ *
+ * No Difference
+ *
+ * The user file looks modified judging from its time stamp; however it needn't
+ * be. No_difference() finds out whether it is or not. If it is not, it
+ * updates the administration.
+ *
+ * returns 0 if no differences are found and non-zero otherwise
+ */
+
+#include "cvs.h"
+
+#ifndef lint
+static const char rcsid[] = "$CVSid: @(#)no_diff.c 1.39 94/10/07 $";
+USE(rcsid);
+#endif
+
+int
+No_Difference (file, vers, entries, repository, update_dir)
+ char *file;
+ Vers_TS *vers;
+ List *entries;
+ char *repository;
+ char *update_dir;
+{
+ Node *p;
+ char tmp[L_tmpnam+1];
+ int ret;
+ char *ts, *options;
+ int retcode = 0;
+ char *tocvsPath;
+
+ if (!vers->srcfile || !vers->srcfile->path)
+ return (-1); /* different since we couldn't tell */
+
+ if (vers->entdata && vers->entdata->options)
+ options = xstrdup (vers->entdata->options);
+ else
+ options = xstrdup ("");
+
+ run_setup ("%s%s -p -q -r%s %s", Rcsbin, RCS_CO,
+ vers->vn_user ? vers->vn_user : "", options);
+ run_arg (vers->srcfile->path);
+ if ((retcode = run_exec (RUN_TTY, tmpnam (tmp), RUN_TTY, RUN_REALLY)) == 0)
+ {
+#if 0
+ /* Why would we want to munge the modes? And only if the timestamps
+ are different? And even for commands like "cvs status"???? */
+ if (!iswritable (file)) /* fix the modes as a side effect */
+ xchmod (file, 1);
+#endif
+
+ tocvsPath = wrap_tocvs_process_file (file);
+
+ /* do the byte by byte compare */
+ if (xcmp (tocvsPath == NULL ? file : tocvsPath, tmp) == 0)
+ {
+#if 0
+ /* Why would we want to munge the modes? And only if the
+ timestamps are different? And even for commands like
+ "cvs status"???? */
+ if (cvswrite == FALSE) /* fix the modes as a side effect */
+ xchmod (file, 0);
+#endif
+
+ /* no difference was found, so fix the entries file */
+ ts = time_stamp (file);
+ Register (entries, file,
+ vers->vn_user ? vers->vn_user : vers->vn_rcs, ts,
+ options, vers->tag, vers->date, (char *) 0);
+#ifdef SERVER_SUPPORT
+ if (server_active)
+ {
+ /* We need to update the entries line on the client side. */
+ server_update_entries
+ (file, update_dir, repository, SERVER_UPDATED);
+ }
+#endif
+ free (ts);
+
+ /* update the entdata pointer in the vers_ts structure */
+ p = findnode (entries, file);
+ vers->entdata = (Entnode *) p->data;
+
+ ret = 0;
+ }
+ else
+ ret = 1; /* files were really different */
+ if (tocvsPath)
+ {
+ /* Need to call unlink myself because the noexec variable
+ * has been set to 1. */
+ if (trace)
+ (void) fprintf (stderr, "%c-> unlink (%s)\n",
+#ifdef SERVER_SUPPORT
+ (server_active) ? 'S' : ' ',
+#else
+ ' ',
+#endif
+ tocvsPath);
+ if (unlink (tocvsPath) < 0)
+ error (0, errno, "could not remove %s", tocvsPath);
+ }
+ }
+ else
+ {
+ if (update_dir[0] == '\0')
+ error (0, retcode == -1 ? errno : 0,
+ "could not check out revision %s of %s",
+ vers->vn_user, file);
+ else
+ error (0, retcode == -1 ? errno : 0,
+ "could not check out revision %s of %s/%s",
+ vers->vn_user, update_dir, file);
+ ret = -1; /* different since we couldn't tell */
+ }
+
+ if (trace)
+#ifdef SERVER_SUPPORT
+ (void) fprintf (stderr, "%c-> unlink2 (%s)\n",
+ (server_active) ? 'S' : ' ', tmp);
+#else
+ (void) fprintf (stderr, "-> unlink (%s)\n", tmp);
+#endif
+ if (unlink (tmp) < 0)
+ error (0, errno, "could not remove %s", tmp);
+ free (options);
+ return (ret);
+}
diff --git a/gnu/usr.bin/cvs/cvs/options.h b/gnu/usr.bin/cvs/cvs/options.h
new file mode 100644
index 0000000..9944653
--- /dev/null
+++ b/gnu/usr.bin/cvs/cvs/options.h
@@ -0,0 +1,286 @@
+/*
+ * Copyright (c) 1992, Brian Berliner and Jeff Polk
+ * Copyright (c) 1989-1992, Brian Berliner
+ *
+ * You may distribute under the terms of the GNU General Public License as
+ * specified in the README file that comes with the CVS 1.4 kit.
+ *
+ * This file holds (most of) the configuration tweaks that can be made to
+ * customize CVS for your site. CVS comes configured for a typical SunOS 4.x
+ * environment. The comments for each configurable item are intended to be
+ * self-explanatory. All #defines are tested first to see if an over-riding
+ * option was specified on the "make" command line.
+ *
+ * If special libraries are needed, you will have to edit the Makefile.in file
+ * or the configure script directly. Sorry.
+ */
+
+/*
+ * CVS provides the most features when used in conjunction with the Version-5
+ * release of RCS. Thus, it is the default. This also assumes that GNU diff
+ * Version-1.15 is being used as well -- you will have to configure your RCS
+ * V5 release separately to make this the case. If you do not have RCS V5 and
+ * GNU diff V1.15, comment out this define. You should not try mixing and
+ * matching other combinations of these tools.
+ */
+#ifndef HAVE_RCS5
+#define HAVE_RCS5
+#endif
+
+/*
+ * If, before installing this version of CVS, you were running RCS V4 AND you
+ * are installing this CVS and RCS V5 and GNU diff 1.15 all at the same time,
+ * you should turn on the following define. It only exists to try to do
+ * reasonable things with your existing checked out files when you upgrade to
+ * RCS V5, since the keyword expansion formats have changed with RCS V5.
+ *
+ * If you already have been running with RCS5, or haven't been running with CVS
+ * yet at all, or are sticking with RCS V4 for now, leave the commented out.
+ */
+#ifndef HAD_RCS4
+/* #define HAD_RCS4 */
+#endif
+
+/*
+ * For portability and heterogeneity reasons, CVS is shipped by default using
+ * my own text-file version of the ndbm database library in the src/myndbm.c
+ * file. If you want better performance and are not concerned about
+ * heterogeneous hosts accessing your modules file, turn this option off.
+ */
+#ifndef MY_NDBM
+#define MY_NDBM
+#endif
+
+/*
+ * The "diff" program to execute when creating patch output. This "diff"
+ * must support the "-c" option for context diffing. Specify a full
+ * pathname if your site wants to use a particular diff. If you are
+ * using the GNU version of diff (version 1.15 or later), this should
+ * be "diff -a".
+ *
+ * NOTE: this program is only used for the ``patch'' sub-command (and
+ * for ``update'' if you are using the server). The other commands
+ * use rcsdiff which will use whatever version of diff was specified
+ * when rcsdiff was built on your system.
+ */
+
+#ifndef DIFF
+#define DIFF "/usr/bin/diff -a"
+#endif
+
+/*
+ * The "grep" program to execute when checking to see if a merged file had
+ * any conflicts. This "grep" must support a standard basic
+ * regular expression as an argument. Specify a full pathname if your site
+ * wants to use a particular grep.
+ */
+
+#ifndef GREP
+#define GREP "grep"
+#endif
+
+/*
+ * The "rm" program to execute when pruning directories that are not part of
+ * a release. This "rm" must support the "-fr" options. Specify a full
+ * pathname if your site wants to use a particular rm.
+ */
+#ifndef RM
+#define RM "rm"
+#endif
+
+/*
+ * The "sort" program to execute when displaying the module database. Specify
+ * a full pathname if your site wants to use a particular sort.
+ */
+#ifndef SORT
+#define SORT "sort"
+#endif
+
+/*
+ * The "patch" program to run when using the CVS server and accepting
+ * patches across the network. Specify a full pathname if your site
+ * wants to use a particular patch.
+ */
+#ifndef PATCH_PROGRAM
+#define PATCH_PROGRAM "patch"
+#endif
+
+/*
+ * By default, RCS programs are executed with the shell or through execlp(),
+ * so the user's PATH environment variable is searched. If you'd like to
+ * bind all RCS programs to a certain directory (perhaps one not in most
+ * people's PATH) then set the default in RCSBIN_DFLT. Note that setting
+ * this here will cause all RCS programs to be executed from this directory,
+ * unless the user overrides the default with the RCSBIN environment variable
+ * or the "-b" option to CVS.
+ *
+ * This define should be either the empty string ("") or a full pathname to the
+ * directory containing all the installed programs from the RCS distribution.
+ */
+#ifndef RCSBIN_DFLT
+#define RCSBIN_DFLT ""
+#endif
+
+/*
+ * The default editor to use, if one does not specify the "-e" option to cvs,
+ * or does not have an EDITOR environment variable. I set this to just "vi",
+ * and use the shell to find where "vi" actually is. This allows sites with
+ * /usr/bin/vi or /usr/ucb/vi to work equally well (assuming that your PATH
+ * is reasonable).
+ */
+#ifndef EDITOR_DFLT
+#define EDITOR_DFLT "vi"
+#endif
+
+/*
+ * The default umask to use when creating or otherwise setting file or
+ * directory permissions in the repository. Must be a value in the
+ * range of 0 through 0777. For example, a value of 002 allows group
+ * rwx access and world rx access; a value of 007 allows group rwx
+ * access but no world access. This value is overridden by the value
+ * of the CVSUMASK environment variable, which is interpreted as an
+ * octal number.
+ */
+#ifndef UMASK_DFLT
+#define UMASK_DFLT 002
+#endif
+
+/*
+ * The cvs admin command is restricted to the members of the group
+ * CVS_ADMIN_GROUP. If this group does not exist, all users are
+ * allowed to run cvs admin. To disable the cvs admin for all users,
+ * create an empty group CVS_ADMIN_GROUP. To disable access control for
+ * cvs admin, comment out the define below.
+ */
+#ifndef CVS_ADMIN_GROUP
+#define CVS_ADMIN_GROUP "cvsadmin"
+#endif
+
+/*
+ * The Repository file holds the path to the directory within the source
+ * repository that contains the RCS ,v files for each CVS working directory.
+ * This path is either a full-path or a path relative to CVSROOT.
+ *
+ * The only advantage that I can see to having a relative path is that One can
+ * change the physical location of the master source repository, change one's
+ * CVSROOT environment variable, and CVS will work without problems. I
+ * recommend using full-paths.
+ */
+#ifndef RELATIVE_REPOS
+/* #define RELATIVE_REPOS */
+#endif
+
+/*
+ * When committing or importing files, you must enter a log message.
+ * Normally, you can do this either via the -m flag on the command line or an
+ * editor will be started for you. If you like to use logging templates (the
+ * rcsinfo file within the $CVSROOT/CVSROOT directory), you might want to
+ * force people to use the editor even if they specify a message with -m.
+ * Enabling FORCE_USE_EDITOR will cause the -m message to be appended to the
+ * temp file when the editor is started.
+ */
+#ifndef FORCE_USE_EDITOR
+/* #define FORCE_USE_EDITOR */
+#endif
+
+/*
+ * When locking the repository, some sites like to remove locks and assume
+ * the program that created them went away if the lock has existed for a long
+ * time. This used to be the default for previous versions of CVS. CVS now
+ * attempts to be much more robust, so lock files should not be left around
+ * by mistake. The new behaviour will never remove old locks (they must now
+ * be removed by hand). Enabling CVS_FUDGELOCKS will cause CVS to remove
+ * locks that are older than CVSLCKAGE seconds.
+ * Use of this option is NOT recommended.
+ */
+#ifndef CVS_FUDGELOCKS
+/* #define CVS_FUDGELOCKS */
+#endif
+
+/*
+ * When committing a permanent change, CVS and RCS make a log entry of
+ * who committed the change. If you are committing the change logged in
+ * as "root" (not under "su" or other root-priv giving program), CVS/RCS
+ * cannot determine who is actually making the change.
+ *
+ * As such, by default, CVS disallows changes to be committed by users
+ * logged in as "root". You can disable this option by commenting
+ * out the lines below.
+ */
+#ifndef CVS_BADROOT
+#define CVS_BADROOT
+#endif
+
+/*
+ * The "cvs admin" command allows people to get around most of the logging
+ * and info procedures within CVS. For exmaple, "cvs tag tagname filename"
+ * will perform some validity checks on the tag, while "cvs admin -Ntagname"
+ * will not perform those checks. For this reason, some sites may wish to
+ * disable the admin function completely.
+ *
+ * To disable the admin function, uncomment the lines below.
+ */
+#ifndef CVS_NOADMIN
+/* #define CVS_NOADMIN */
+#endif
+
+/*
+ * The "cvs diff" command accepts all the single-character options that GNU
+ * diff (1.15) accepts. Except -D. GNU diff uses -D as a way to put
+ * cpp-style #define's around the output differences. CVS, by default, uses
+ * -D to specify a free-form date (like "cvs diff -D '1 week ago'"). If
+ * you would prefer that the -D option of "cvs diff" work like the GNU diff
+ * option, then comment out this define.
+ */
+#ifndef CVS_DIFFDATE
+#define CVS_DIFFDATE
+#endif
+
+/*
+ * define this to enable the SETXID support (see FAQ 4D.13)
+ */
+#ifndef SETXID_SUPPORT
+/* #define SETXID_SUPPORT */
+#endif
+
+/*
+ * The authenticated client/server is under construction. Don't
+ * define either of these unless you're testing them, in which case
+ * you're me and you already know that.
+ */
+/* #undef AUTH_CLIENT_SUPPORT */
+/* #undef AUTH_SERVER_SUPPORT */
+
+/*
+ * If you are working with a large remote repository and a 'cvs checkout' is
+ * swamping your network and memory, define these to enable flow control.
+ * You will end up with even less guarantees of a consistant checkout,
+ * but that may be better than no checkout at all. The master server process
+ * will monitor how far it is getting behind, if it reaches the high water
+ * mark, it will signal the child process to stop generating data when
+ * convenient (ie: no locks are held, currently at the beginning of a
+ * new directory). Once the buffer has drained sufficiently to reach the
+ * low water mark, it will be signalled to start again.
+ * -- EXPERIMENTAL! -- A better solution may be in the works.
+ * You may override the default hi/low watermarks here too.
+ */
+#ifndef SERVER_FLOWCONTROL
+# define SERVER_FLOWCONTROL
+# define SERVER_HI_WATER (2 * 1024 * 1024)
+# define SERVER_LO_WATER (1 * 1024 * 1024)
+#endif
+
+/* End of CVS configuration section */
+
+/*
+ * Externs that are included in libc, but are used frequently enough to
+ * warrant defining here.
+ */
+#ifndef STDC_HEADERS
+extern void exit ();
+#endif
+
+#ifndef getwd
+extern char *getwd ();
+#endif
+
diff --git a/gnu/usr.bin/cvs/cvs/parseinfo.c b/gnu/usr.bin/cvs/cvs/parseinfo.c
new file mode 100644
index 0000000..6d59884
--- /dev/null
+++ b/gnu/usr.bin/cvs/cvs/parseinfo.c
@@ -0,0 +1,171 @@
+/*
+ * Copyright (c) 1992, Brian Berliner and Jeff Polk
+ * Copyright (c) 1989-1992, Brian Berliner
+ *
+ * You may distribute under the terms of the GNU General Public License as
+ * specified in the README file that comes with the CVS 1.4 kit.
+ */
+
+#include "cvs.h"
+
+#ifndef lint
+static const char rcsid[] = "$CVSid: @(#)parseinfo.c 1.18 94/09/23 $";
+USE(rcsid);
+#endif
+
+/*
+ * Parse the INFOFILE file for the specified REPOSITORY. Invoke CALLPROC for
+ * the first line in the file that matches the REPOSITORY, or if ALL != 0, any lines
+ * matching "ALL", or if no lines match, the last line matching "DEFAULT".
+ *
+ * Return 0 for success, -1 if there was not an INFOFILE, and >0 for failure.
+ */
+int
+Parse_Info (infofile, repository, callproc, all)
+ char *infofile;
+ char *repository;
+ CALLPROC callproc;
+ int all;
+{
+ int err = 0;
+ FILE *fp_info;
+ char infopath[PATH_MAX];
+ char line[MAXLINELEN];
+ char *default_value = NULL;
+ char *expanded_value= NULL;
+ int callback_done, line_number;
+ char *cp, *exp, *value, *srepos;
+ const char *regex_err;
+
+ if (CVSroot == NULL)
+ {
+ /* XXX - should be error maybe? */
+ error (0, 0, "CVSROOT variable not set");
+ return (1);
+ }
+
+ /* find the info file and open it */
+ (void) sprintf (infopath, "%s/%s/%s", CVSroot,
+ CVSROOTADM, infofile);
+ if ((fp_info = fopen (infopath, "r")) == NULL)
+ return (0); /* no file -> nothing special done */
+
+ /* strip off the CVSROOT if repository was absolute */
+ srepos = Short_Repository (repository);
+
+ if (trace)
+ (void) fprintf (stderr, "-> ParseInfo(%s, %s, %s)\n",
+ infopath, srepos, all ? "ALL" : "not ALL");
+
+ /* search the info file for lines that match */
+ callback_done = line_number = 0;
+ while (fgets (line, sizeof (line), fp_info) != NULL)
+ {
+ line_number++;
+
+ /* skip lines starting with # */
+ if (line[0] == '#')
+ continue;
+
+ /* skip whitespace at beginning of line */
+ for (cp = line; *cp && isspace (*cp); cp++)
+ ;
+
+ /* if *cp is null, the whole line was blank */
+ if (*cp == '\0')
+ continue;
+
+ /* the regular expression is everything up to the first space */
+ for (exp = cp; *cp && !isspace (*cp); cp++)
+ ;
+ if (*cp != '\0')
+ *cp++ = '\0';
+
+ /* skip whitespace up to the start of the matching value */
+ while (*cp && isspace (*cp))
+ cp++;
+
+ /* no value to match with the regular expression is an error */
+ if (*cp == '\0')
+ {
+ error (0, 0, "syntax error at line %d file %s; ignored",
+ line_number, infofile);
+ continue;
+ }
+ value = cp;
+
+ /* strip the newline off the end of the value */
+ if ((cp = strrchr (value, '\n')) != NULL)
+ *cp = '\0';
+
+ expanded_value = expand_path (value);
+ if (!expanded_value)
+ {
+ error (0, 0,
+ "Invalid environmental variable at line %d in file %s",
+ line_number, infofile);
+ continue;
+
+ }
+
+ /*
+ * At this point, exp points to the regular expression, and value
+ * points to the value to call the callback routine with. Evaluate
+ * the regular expression against srepos and callback with the value
+ * if it matches.
+ */
+
+ /* save the default value so we have it later if we need it */
+ if (strcmp (exp, "DEFAULT") == 0)
+ {
+ default_value = xstrdup (expanded_value);
+ continue;
+ }
+
+ /*
+ * For a regular expression of "ALL", do the callback always We may
+ * execute lots of ALL callbacks in addition to *one* regular matching
+ * callback or default
+ */
+ if (strcmp (exp, "ALL") == 0)
+ {
+ if (all)
+ err += callproc (repository, expanded_value);
+ else
+ error(0, 0, "Keyword `ALL' is ignored at line %d in %s file",
+ line_number, infofile);
+ continue;
+ }
+
+ if (callback_done)
+ /* only first matching, plus "ALL"'s */
+ continue;
+
+ /* see if the repository matched this regular expression */
+ if ((regex_err = re_comp (exp)) != NULL)
+ {
+ error (0, 0, "bad regular expression at line %d file %s: %s",
+ line_number, infofile, regex_err);
+ continue;
+ }
+ if (re_exec (srepos) == 0)
+ continue; /* no match */
+
+ /* it did, so do the callback and note that we did one */
+ err += callproc (repository, expanded_value);
+ callback_done = 1;
+ }
+ (void) fclose (fp_info);
+
+ /* if we fell through and didn't callback at all, do the default */
+ if (callback_done == 0 && default_value != NULL)
+ err += callproc (repository, default_value);
+
+ /* free up space if necessary */
+ if (default_value != NULL)
+ free (default_value);
+ if (expanded_value != NULL)
+ free (expanded_value);
+
+ return (err);
+}
diff --git a/gnu/usr.bin/cvs/cvs/patch.c b/gnu/usr.bin/cvs/cvs/patch.c
new file mode 100644
index 0000000..560f4b4
--- /dev/null
+++ b/gnu/usr.bin/cvs/cvs/patch.c
@@ -0,0 +1,615 @@
+/*
+ * Copyright (c) 1992, Brian Berliner and Jeff Polk
+ * Copyright (c) 1989-1992, Brian Berliner
+ *
+ * You may distribute under the terms of the GNU General Public License as
+ * specified in the README file that comes with the CVS 1.4 kit.
+ *
+ * Patch
+ *
+ * Create a Larry Wall format "patch" file between a previous release and the
+ * current head of a module, or between two releases. Can specify the
+ * release as either a date or a revision number.
+ */
+
+#include "cvs.h"
+#include "getline.h"
+
+#ifndef lint
+static const char rcsid[] = "$CVSid: @(#)patch.c 1.57 94/09/30 $";
+USE(rcsid);
+#endif
+
+static RETSIGTYPE patch_cleanup PROTO((void));
+static Dtype patch_dirproc PROTO((char *dir, char *repos, char *update_dir));
+static int patch_fileproc PROTO((char *file, char *update_dir, char *repository,
+ List * entries, List * srcfiles));
+static int patch_proc PROTO((int *pargc, char **argv, char *xwhere,
+ char *mwhere, char *mfile, int shorten,
+ int local_specified, char *mname, char *msg));
+
+static int force_tag_match = 1;
+static int patch_short = 0;
+static int toptwo_diffs = 0;
+static int local = 0;
+static char *options = NULL;
+static char *rev1 = NULL;
+static char *rev2 = NULL;
+static char *date1 = NULL;
+static char *date2 = NULL;
+static char tmpfile1[L_tmpnam+1], tmpfile2[L_tmpnam+1], tmpfile3[L_tmpnam+1];
+static int unidiff = 0;
+
+static const char *const patch_usage[] =
+{
+ "Usage: %s %s [-fl] [-c|-u] [-s|-t] [-V %%d]\n",
+ " -r rev|-D date [-r rev2 | -D date2] modules...\n",
+ "\t-f\tForce a head revision match if tag/date not found.\n",
+ "\t-l\tLocal directory only, not recursive\n",
+ "\t-c\tContext diffs (default)\n",
+ "\t-u\tUnidiff format.\n",
+ "\t-s\tShort patch - one liner per file.\n",
+ "\t-t\tTop two diffs - last change made to the file.\n",
+ "\t-D date\tDate.\n",
+ "\t-r rev\tRevision - symbolic or numeric.\n",
+ "\t-V vers\tUse RCS Version \"vers\" for keyword expansion.\n",
+ NULL
+};
+
+int
+patch (argc, argv)
+ int argc;
+ char **argv;
+{
+ register int i;
+ int c;
+ int err = 0;
+ DBM *db;
+
+ if (argc == -1)
+ usage (patch_usage);
+
+ optind = 1;
+ while ((c = getopt (argc, argv, "V:k:cuftsQqlRD:r:")) != -1)
+ {
+ switch (c)
+ {
+ case 'Q':
+ case 'q':
+#ifdef SERVER_SUPPORT
+ /* The CVS 1.5 client sends these options (in addition to
+ Global_option requests), so we must ignore them. */
+ if (!server_active)
+#endif
+ error (1, 0,
+ "-q or -Q must be specified before \"%s\"",
+ command_name);
+ break;
+ case 'f':
+ force_tag_match = 0;
+ break;
+ case 'l':
+ local = 1;
+ break;
+ case 'R':
+ local = 0;
+ break;
+ case 't':
+ toptwo_diffs = 1;
+ break;
+ case 's':
+ patch_short = 1;
+ break;
+ case 'D':
+ if (rev2 != NULL || date2 != NULL)
+ error (1, 0,
+ "no more than two revisions/dates can be specified");
+ if (rev1 != NULL || date1 != NULL)
+ date2 = Make_Date (optarg);
+ else
+ date1 = Make_Date (optarg);
+ break;
+ case 'r':
+ if (rev2 != NULL || date2 != NULL)
+ error (1, 0,
+ "no more than two revisions/dates can be specified");
+ if (rev1 != NULL || date1 != NULL)
+ rev2 = optarg;
+ else
+ rev1 = optarg;
+ break;
+ case 'k':
+ if (options)
+ free (options);
+ options = RCS_check_kflag (optarg);
+ break;
+ case 'V':
+ if (atoi (optarg) <= 0)
+ error (1, 0, "must specify a version number to -V");
+ if (options)
+ free (options);
+ options = xmalloc (strlen (optarg) + 1 + 2); /* for the -V */
+ (void) sprintf (options, "-V%s", optarg);
+ break;
+ case 'u':
+ unidiff = 1; /* Unidiff */
+ break;
+ case 'c': /* Context diff */
+ unidiff = 0;
+ break;
+ case '?':
+ default:
+ usage (patch_usage);
+ break;
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+ /* Sanity checks */
+ if (argc < 1)
+ usage (patch_usage);
+
+ if (toptwo_diffs && patch_short)
+ error (1, 0, "-t and -s options are mutually exclusive");
+ if (toptwo_diffs && (date1 != NULL || date2 != NULL ||
+ rev1 != NULL || rev2 != NULL))
+ error (1, 0, "must not specify revisions/dates with -t option!");
+
+ if (!toptwo_diffs && (date1 == NULL && date2 == NULL &&
+ rev1 == NULL && rev2 == NULL))
+ error (1, 0, "must specify at least one revision/date!");
+ if (date1 != NULL && date2 != NULL)
+ if (RCS_datecmp (date1, date2) >= 0)
+ error (1, 0, "second date must come after first date!");
+
+ /* if options is NULL, make it a NULL string */
+ if (options == NULL)
+ options = xstrdup ("");
+
+#ifdef CLIENT_SUPPORT
+ if (client_active)
+ {
+ /* We're the client side. Fire up the remote server. */
+ start_server ();
+
+ ign_setup ();
+
+ if (local)
+ send_arg("-l");
+ if (force_tag_match)
+ send_arg("-f");
+ if (toptwo_diffs)
+ send_arg("-t");
+ if (patch_short)
+ send_arg("-s");
+ if (unidiff)
+ send_arg("-u");
+
+ if (rev1)
+ option_with_arg ("-r", rev1);
+ if (date1)
+ client_senddate (date1);
+ if (rev2)
+ option_with_arg ("-r", rev2);
+ if (date2)
+ client_senddate (date2);
+ if (options[0] != '\0')
+ send_arg (options);
+
+ {
+ int i;
+ for (i = 0; i < argc; ++i)
+ send_arg (argv[i]);
+ }
+
+ if (fprintf (to_server, "rdiff\n") < 0)
+ error (1, errno, "writing to server");
+ return get_responses_and_close ();
+ }
+#endif
+
+ /* clean up if we get a signal */
+#ifdef SIGHUP
+ (void) SIG_register (SIGHUP, patch_cleanup);
+#endif
+#ifdef SIGINT
+ (void) SIG_register (SIGINT, patch_cleanup);
+#endif
+#ifdef SIGQUIT
+ (void) SIG_register (SIGQUIT, patch_cleanup);
+#endif
+#ifdef SIGPIPE
+ (void) SIG_register (SIGPIPE, patch_cleanup);
+#endif
+#ifdef SIGTERM
+ (void) SIG_register (SIGTERM, patch_cleanup);
+#endif
+
+ db = open_module ();
+ for (i = 0; i < argc; i++)
+ err += do_module (db, argv[i], PATCH, "Patching", patch_proc,
+ (char *) NULL, 0, 0, 0, (char *) NULL);
+ close_module (db);
+ free (options);
+ patch_cleanup ();
+ return (err);
+}
+
+/*
+ * callback proc for doing the real work of patching
+ */
+/* ARGSUSED */
+static char where[PATH_MAX];
+static int
+patch_proc (pargc, argv, xwhere, mwhere, mfile, shorten, local_specified,
+ mname, msg)
+ int *pargc;
+ char **argv;
+ char *xwhere;
+ char *mwhere;
+ char *mfile;
+ int shorten;
+ int local_specified;
+ char *mname;
+ char *msg;
+{
+ int err = 0;
+ int which;
+ char repository[PATH_MAX];
+
+ (void) sprintf (repository, "%s/%s", CVSroot, argv[0]);
+ (void) strcpy (where, argv[0]);
+
+ /* if mfile isn't null, we need to set up to do only part of the module */
+ if (mfile != NULL)
+ {
+ char *cp;
+ char path[PATH_MAX];
+
+ /* if the portion of the module is a path, put the dir part on repos */
+ if ((cp = strrchr (mfile, '/')) != NULL)
+ {
+ *cp = '\0';
+ (void) strcat (repository, "/");
+ (void) strcat (repository, mfile);
+ (void) strcat (where, "/");
+ (void) strcat (where, mfile);
+ mfile = cp + 1;
+ }
+
+ /* take care of the rest */
+ (void) sprintf (path, "%s/%s", repository, mfile);
+ if (isdir (path))
+ {
+ /* directory means repository gets the dir tacked on */
+ (void) strcpy (repository, path);
+ (void) strcat (where, "/");
+ (void) strcat (where, mfile);
+ }
+ else
+ {
+ int i;
+
+ /* a file means muck argv */
+ for (i = 1; i < *pargc; i++)
+ free (argv[i]);
+ argv[1] = xstrdup (mfile);
+ (*pargc) = 2;
+ }
+ }
+
+ /* cd to the starting repository */
+ if (chdir (repository) < 0)
+ {
+ error (0, errno, "cannot chdir to %s", repository);
+ return (1);
+ }
+
+ if (force_tag_match)
+ which = W_REPOS | W_ATTIC;
+ else
+ which = W_REPOS;
+
+ /* start the recursion processor */
+ err = start_recursion (patch_fileproc, (FILESDONEPROC) NULL, patch_dirproc,
+ (DIRLEAVEPROC) NULL, *pargc - 1, argv + 1, local,
+ which, 0, 1, where, 1, 1);
+
+ return (err);
+}
+
+/*
+ * Called to examine a particular RCS file, as appropriate with the options
+ * that were set above.
+ */
+/* ARGSUSED */
+static int
+patch_fileproc (file, update_dir, repository, entries, srcfiles)
+ char *file;
+ char *update_dir;
+ char *repository;
+ List *entries;
+ List *srcfiles;
+{
+ struct utimbuf t;
+ char *vers_tag, *vers_head;
+ char rcsspace[PATH_MAX];
+ char *rcs = rcsspace;
+ Node *p;
+ RCSNode *rcsfile;
+ FILE *fp1, *fp2, *fp3;
+ int ret = 0;
+ int isattic = 0;
+ int retcode = 0;
+ char file1[PATH_MAX], file2[PATH_MAX], strippath[PATH_MAX];
+ char *line1, *line2;
+ size_t line1_chars_allocated;
+ size_t line2_chars_allocated;
+ char *cp1, *cp2, *commap;
+ FILE *fp;
+
+ /* find the parsed rcs file */
+ p = findnode (srcfiles, file);
+ if (p == NULL)
+ return (1);
+ rcsfile = (RCSNode *) p->data;
+ if ((rcsfile->flags & VALID) && (rcsfile->flags & INATTIC))
+ isattic = 1;
+
+ (void) sprintf (rcs, "%s%s", file, RCSEXT);
+
+ /* if vers_head is NULL, may have been removed from the release */
+ if (isattic && rev2 == NULL && date2 == NULL)
+ vers_head = NULL;
+ else
+ vers_head = RCS_getversion (rcsfile, rev2, date2, force_tag_match, 0);
+
+ if (toptwo_diffs)
+ {
+ if (vers_head == NULL)
+ return (1);
+
+ if (!date1)
+ date1 = xmalloc (50); /* plenty big :-) */
+ *date1 = '\0';
+ if (RCS_getrevtime (rcsfile, vers_head, date1, 1) == -1)
+ {
+ if (!really_quiet)
+ error (0, 0, "cannot find date in rcs file %s revision %s",
+ rcs, vers_head);
+ return (1);
+ }
+ }
+ vers_tag = RCS_getversion (rcsfile, rev1, date1, force_tag_match, 0);
+
+ if (vers_tag == NULL && (vers_head == NULL || isattic))
+ return (0); /* nothing known about specified revs */
+
+ if (vers_tag && vers_head && strcmp (vers_head, vers_tag) == 0)
+ return (0); /* not changed between releases */
+
+ if (patch_short)
+ {
+ (void) printf ("File ");
+ if (vers_tag == NULL)
+ (void) printf ("%s is new; current revision %s\n", rcs, vers_head);
+ else if (vers_head == NULL)
+#ifdef DEATH_SUPPORT
+ {
+ (void) printf ("%s is removed; not included in ", rcs);
+ if (rev2 != NULL)
+ (void) printf ("release tag %s", rev2);
+ else if (date2 != NULL)
+ (void) printf ("release date %s", date2);
+ else
+ (void) printf ("current release");
+ (void) printf ("\n");
+ }
+#else
+ (void) printf ("%s is removed; not included in release %s\n",
+ rcs, rev2 ? rev2 : date2);
+#endif
+ else
+ (void) printf ("%s changed from revision %s to %s\n",
+ rcs, vers_tag, vers_head);
+ return (0);
+ }
+ if ((fp1 = fopen (tmpnam (tmpfile1), "w+")) != NULL)
+ (void) fclose (fp1);
+ if ((fp2 = fopen (tmpnam (tmpfile2), "w+")) != NULL)
+ (void) fclose (fp2);
+ if ((fp3 = fopen (tmpnam (tmpfile3), "w+")) != NULL)
+ (void) fclose (fp3);
+ if (fp1 == NULL || fp2 == NULL || fp3 == NULL)
+ {
+ error (0, 0, "cannot create temporary files");
+ ret = 1;
+ goto out;
+ }
+ if (vers_tag != NULL)
+ {
+ run_setup ("%s%s %s -p -q -r%s", Rcsbin, RCS_CO, options, vers_tag);
+ run_arg (rcsfile->path);
+ if ((retcode = run_exec (RUN_TTY, tmpfile1, RUN_TTY, RUN_NORMAL)) != 0)
+ {
+ if (!really_quiet)
+ error (retcode == -1 ? 1 : 0, retcode == -1 ? errno : 0,
+ "co of revision %s in %s failed", vers_tag, rcs);
+ ret = 1;
+ goto out;
+ }
+ memset ((char *) &t, 0, sizeof (t));
+ if ((t.actime = t.modtime = RCS_getrevtime (rcsfile, vers_tag,
+ (char *) 0, 0)) != -1)
+ (void) utime (tmpfile1, &t);
+ }
+ else if (toptwo_diffs)
+ {
+ ret = 1;
+ goto out;
+ }
+ if (vers_head != NULL)
+ {
+ run_setup ("%s%s %s -p -q -r%s", Rcsbin, RCS_CO, options, vers_head);
+ run_arg (rcsfile->path);
+ if ((retcode = run_exec (RUN_TTY, tmpfile2, RUN_TTY, RUN_NORMAL)) != 0)
+ {
+ if (!really_quiet)
+ error (retcode == -1 ? 1 : 0, retcode == -1 ? errno : 0,
+ "co of revision %s in %s failed", vers_head, rcs);
+ ret = 1;
+ goto out;
+ }
+ if ((t.actime = t.modtime = RCS_getrevtime (rcsfile, vers_head,
+ (char *) 0, 0)) != -1)
+ (void) utime (tmpfile2, &t);
+ }
+ run_setup ("%s -%c", DIFF, unidiff ? 'u' : 'c');
+ run_arg (tmpfile1);
+ run_arg (tmpfile2);
+
+ line1 = NULL;
+ line1_chars_allocated = 0;
+ line2 = NULL;
+ line2_chars_allocated = 0;
+
+ switch (run_exec (RUN_TTY, tmpfile3, RUN_TTY, RUN_NORMAL))
+ {
+ case -1: /* fork/wait failure */
+ error (1, errno, "fork for diff failed on %s", rcs);
+ break;
+ case 0: /* nothing to do */
+ break;
+ case 1:
+ /*
+ * The two revisions are really different, so read the first two
+ * lines of the diff output file, and munge them to include more
+ * reasonable file names that "patch" will understand.
+ */
+
+ /* Output an "Index:" line for patch to use */
+ (void) fflush (stdout);
+ if (update_dir[0])
+ (void) printf ("Index: %s/%s\n", update_dir, file);
+ else
+ (void) printf ("Index: %s\n", file);
+ (void) fflush (stdout);
+
+ fp = open_file (tmpfile3, "r");
+ if (getline (&line1, &line1_chars_allocated, fp) < 0 ||
+ getline (&line2, &line2_chars_allocated, fp) < 0)
+ {
+ error (0, errno, "failed to read diff file header %s for %s",
+ tmpfile3, rcs);
+ ret = 1;
+ (void) fclose (fp);
+ goto out;
+ }
+ if (!unidiff)
+ {
+ if (strncmp (line1, "*** ", 4) != 0 ||
+ strncmp (line2, "--- ", 4) != 0 ||
+ (cp1 = strchr (line1, '\t')) == NULL ||
+ (cp2 = strchr (line2, '\t')) == NULL)
+ {
+ error (0, 0, "invalid diff header for %s", rcs);
+ ret = 1;
+ (void) fclose (fp);
+ goto out;
+ }
+ }
+ else
+ {
+ if (strncmp (line1, "--- ", 4) != 0 ||
+ strncmp (line2, "+++ ", 4) != 0 ||
+ (cp1 = strchr (line1, '\t')) == NULL ||
+ (cp2 = strchr (line2, '\t')) == NULL)
+ {
+ error (0, 0, "invalid unidiff header for %s", rcs);
+ ret = 1;
+ (void) fclose (fp);
+ goto out;
+ }
+ }
+ if (CVSroot != NULL)
+ (void) sprintf (strippath, "%s/", CVSroot);
+ else
+ (void) strcpy (strippath, REPOS_STRIP);
+ if (strncmp (rcs, strippath, strlen (strippath)) == 0)
+ rcs += strlen (strippath);
+ commap = strrchr (rcs, ',');
+ *commap = '\0';
+ if (vers_tag != NULL)
+ {
+ (void) sprintf (file1, "%s%s%s:%s", update_dir,
+ update_dir[0] ? "/" : "", rcs, vers_tag);
+ }
+ else
+ {
+ (void) strcpy (file1, DEVNULL);
+ }
+ (void) sprintf (file2, "%s%s%s:%s", update_dir,
+ update_dir[0] ? "/" : "", rcs,
+ vers_head ? vers_head : "removed");
+ if (unidiff)
+ {
+ (void) printf ("diff -u %s %s\n", file1, file2);
+ (void) printf ("--- %s%s+++ ", file1, cp1);
+ }
+ else
+ {
+ (void) printf ("diff -c %s %s\n", file1, file2);
+ (void) printf ("*** %s%s--- ", file1, cp1);
+ }
+
+ if (update_dir[0] != '\0')
+ (void) printf ("%s/", update_dir);
+ (void) printf ("%s%s", rcs, cp2);
+ /* spew the rest of the diff out */
+ while (getline (&line1, &line1_chars_allocated, fp) >= 0)
+ (void) fputs (line1, stdout);
+ (void) fclose (fp);
+ break;
+ default:
+ error (0, 0, "diff failed for %s", rcs);
+ }
+ out:
+ if (line1)
+ free (line1);
+ if (line2)
+ free (line2);
+ (void) unlink_file (tmpfile1);
+ (void) unlink_file (tmpfile2);
+ (void) unlink_file (tmpfile3);
+ return (ret);
+}
+
+/*
+ * Print a warm fuzzy message
+ */
+/* ARGSUSED */
+static Dtype
+patch_dirproc (dir, repos, update_dir)
+ char *dir;
+ char *repos;
+ char *update_dir;
+{
+ if (!quiet)
+ error (0, 0, "Diffing %s", update_dir);
+ return (R_PROCESS);
+}
+
+/*
+ * Clean up temporary files
+ */
+static RETSIGTYPE
+patch_cleanup ()
+{
+ if (tmpfile1[0] != '\0')
+ (void) unlink_file (tmpfile1);
+ if (tmpfile2[0] != '\0')
+ (void) unlink_file (tmpfile2);
+ if (tmpfile3[0] != '\0')
+ (void) unlink_file (tmpfile3);
+}
diff --git a/gnu/usr.bin/cvs/cvs/patchlevel.h b/gnu/usr.bin/cvs/cvs/patchlevel.h
new file mode 100644
index 0000000..50d3863
--- /dev/null
+++ b/gnu/usr.bin/cvs/cvs/patchlevel.h
@@ -0,0 +1 @@
+#define PATCHLEVEL 2
diff --git a/gnu/usr.bin/cvs/cvs/rcs.c b/gnu/usr.bin/cvs/cvs/rcs.c
new file mode 100644
index 0000000..43282a6
--- /dev/null
+++ b/gnu/usr.bin/cvs/cvs/rcs.c
@@ -0,0 +1,1726 @@
+/*
+ * Copyright (c) 1992, Brian Berliner and Jeff Polk
+ *
+ * You may distribute under the terms of the GNU General Public License as
+ * specified in the README file that comes with the CVS 1.4 kit.
+ *
+ * The routines contained in this file do all the rcs file parsing and
+ * manipulation
+ */
+
+#include <assert.h>
+#include "cvs.h"
+
+#ifndef lint
+static const char rcsid[] = "$CVSid: @(#)rcs.c 1.40 94/10/07 $";
+USE(rcsid);
+#endif
+
+static RCSNode *RCS_parsercsfile_i PROTO((FILE * fp, const char *rcsfile));
+static char *RCS_getdatebranch PROTO((RCSNode * rcs, char *date, char *branch));
+static int getrcskey PROTO((FILE * fp, char **keyp, char **valp));
+static int parse_rcs_proc PROTO((Node * file, void *closure));
+static int checkmagic_proc PROTO((Node *p, void *closure));
+static void do_branches PROTO((List * list, char *val));
+static void do_symbols PROTO((List * list, char *val));
+static void null_delproc PROTO((Node * p));
+static void rcsnode_delproc PROTO((Node * p));
+static void rcsvers_delproc PROTO((Node * p));
+
+static List *rcslist;
+static char *repository;
+
+/*
+ * We don't want to use isspace() from the C library because:
+ *
+ * 1. The definition of "whitespace" in RCS files includes ASCII
+ * backspace, but the C locale doesn't.
+ * 2. isspace is an very expensive function call in some implementations
+ * due to the addition of wide character support.
+ */
+static const char spacetab[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, /* 0x00 - 0x0f */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x10 - 0x1f */
+ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x20 - 0x2f */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x30 - 0x3f */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x40 - 0x4f */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x50 - 0x5f */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x60 - 0x8f */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x70 - 0x7f */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x80 - 0x8f */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x90 - 0x9f */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xa0 - 0xaf */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xb0 - 0xbf */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xc0 - 0xcf */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xd0 - 0xdf */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xe0 - 0xef */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 /* 0xf0 - 0xff */
+};
+
+#define whitespace(c) (spacetab[(unsigned char)c] != 0)
+
+/*
+ * Parse all the rcs files specified and return a list
+ */
+List *
+RCS_parsefiles (files, xrepos)
+ List *files;
+ char *xrepos;
+{
+ /* initialize */
+ repository = xrepos;
+ rcslist = getlist ();
+
+ /* walk the list parsing files */
+ if (walklist (files, parse_rcs_proc, NULL) != 0)
+ {
+ /* free the list and return NULL on error */
+ dellist (&rcslist);
+ return ((List *) NULL);
+ }
+ else
+ /* return the list we built */
+ return (rcslist);
+}
+
+/*
+ * Parse an rcs file into a node on the rcs list
+ */
+static int
+parse_rcs_proc (file, closure)
+ Node *file;
+ void *closure;
+{
+ RCSNode *rdata;
+
+ /* parse the rcs file into rdata */
+ rdata = RCS_parse (file->key, repository);
+
+ /* if we got a valid RCSNode back, put it on the list */
+ if (rdata != (RCSNode *) NULL)
+ RCS_addnode (file->key, rdata, rcslist);
+
+ return (0);
+}
+
+/*
+ * Add an RCSNode to a list of them.
+ */
+
+void
+RCS_addnode (file, rcs, list)
+ const char *file;
+ RCSNode *rcs;
+ List *list;
+{
+ Node *p;
+
+ p = getnode ();
+ p->key = xstrdup (file);
+ p->delproc = rcsnode_delproc;
+ p->type = RCSNODE;
+ p->data = (char *) rcs;
+ (void) addnode (list, p);
+}
+
+
+/*
+ * Parse an rcsfile given a user file name and a repository
+ */
+RCSNode *
+RCS_parse (file, repos)
+ const char *file;
+ const char *repos;
+{
+ RCSNode *rcs;
+ FILE *fp;
+ char rcsfile[PATH_MAX];
+
+#ifdef LINES_CRLF_TERMINATED
+ /* Some ports of RCS to Windows NT write RCS files with newline-
+ delimited lines. We would need to pass fopen a "binary" flag. */
+ abort ();
+#endif
+
+ (void) sprintf (rcsfile, "%s/%s%s", repos, file, RCSEXT);
+ if ((fp = fopen (rcsfile, "r")) != NULL)
+ {
+ rcs = RCS_parsercsfile_i(fp, rcsfile);
+ if (rcs != NULL)
+ rcs->flags |= VALID;
+
+ fclose (fp);
+ return (rcs);
+ }
+ else if (! existence_error (errno))
+ {
+ error (0, errno, "cannot open %s", rcsfile);
+ return NULL;
+ }
+
+#ifdef LINES_CRLF_TERMINATED
+ /* Some ports of RCS to Windows NT write RCS files with newline-
+ delimited lines. We would need to pass fopen a "binary" flag. */
+ abort ();
+#endif
+
+ (void) sprintf (rcsfile, "%s/%s/%s%s", repos, CVSATTIC, file, RCSEXT);
+ if ((fp = fopen (rcsfile, "r")) != NULL)
+ {
+ rcs = RCS_parsercsfile_i(fp, rcsfile);
+ if (rcs != NULL)
+ {
+ rcs->flags |= INATTIC;
+ rcs->flags |= VALID;
+ }
+
+ fclose (fp);
+ return (rcs);
+ }
+ else if (! existence_error (errno))
+ {
+ error (0, errno, "cannot open %s", rcsfile);
+ return NULL;
+ }
+
+ return (NULL);
+}
+
+/*
+ * Parse a specific rcsfile.
+ */
+RCSNode *
+RCS_parsercsfile (rcsfile)
+ char *rcsfile;
+{
+ FILE *fp;
+ RCSNode *rcs;
+
+#ifdef LINES_CRLF_TERMINATED
+ /* Some ports of RCS to Windows NT write RCS files with newline-
+ delimited lines. We would need to pass fopen a "binary" flag. */
+ abort ();
+#endif
+
+ /* open the rcsfile */
+ if ((fp = fopen (rcsfile, "r")) == NULL)
+ {
+ error (0, errno, "Couldn't open rcs file `%s'", rcsfile);
+ return (NULL);
+ }
+
+ rcs = RCS_parsercsfile_i (fp, rcsfile);
+
+ fclose (fp);
+ return (rcs);
+}
+
+
+/*
+ */
+static RCSNode *
+RCS_parsercsfile_i (fp, rcsfile)
+ FILE *fp;
+ const char *rcsfile;
+{
+ RCSNode *rdata;
+ char *key, *value;
+
+ /* make a node */
+ rdata = (RCSNode *) xmalloc (sizeof (RCSNode));
+ memset ((char *) rdata, 0, sizeof (RCSNode));
+ rdata->refcount = 1;
+ rdata->path = xstrdup (rcsfile);
+
+ /* Process HEAD and BRANCH keywords from the RCS header.
+ *
+ * Most cvs operatations on the main branch don't need any more
+ * information. Those that do call XXX to completely parse the
+ * RCS file. */
+
+ if (getrcskey (fp, &key, &value) == -1 || key == NULL)
+ goto l_error;
+
+ if (strcmp (RCSHEAD, key) == 0 && value != NULL)
+ rdata->head = xstrdup (value);
+
+ if (getrcskey (fp, &key, &value) == -1 || key == NULL)
+ goto l_error;
+
+ if (strcmp (RCSBRANCH, key) == 0 && value != NULL)
+ {
+ char *cp;
+
+ rdata->branch = xstrdup (value);
+ if ((numdots (rdata->branch) & 1) != 0)
+ {
+ /* turn it into a branch if it's a revision */
+ cp = strrchr (rdata->branch, '.');
+ *cp = '\0';
+ }
+ }
+
+ rdata->flags |= PARTIAL;
+ return rdata;
+
+l_error:
+ if (!really_quiet)
+ {
+ if (ferror(fp))
+ {
+ error (1, 0, "error reading `%s'", rcsfile);
+ }
+ else
+ {
+ error (0, 0, "`%s' does not appear to be a valid rcs file",
+ rcsfile);
+ }
+ }
+ freercsnode (&rdata);
+ return (NULL);
+}
+
+
+/*
+ * Do the real work of parsing an RCS file
+ *
+ * There are no allowances for error here.
+ */
+void
+RCS_reparsercsfile (rdata)
+ RCSNode *rdata;
+{
+ FILE *fp;
+ char *rcsfile;
+
+ Node *q, *r;
+ RCSVers *vnode;
+ int n;
+ char *cp;
+ char *key, *value;
+
+ rcsfile = rdata->path;
+
+#ifdef LINES_CRLF_TERMINATED
+ /* Some ports of RCS to Windows NT write RCS files with newline-
+ delimited lines. We would need to pass fopen a "binary" flag. */
+ abort ();
+#endif
+
+ fp = fopen(rcsfile, "r");
+ if (fp == NULL)
+ error (1, 0, "unable to reopen `%s'", rcsfile);
+
+ /* make a node */
+ rdata->versions = getlist ();
+ rdata->dates = getlist ();
+
+ /*
+ * process all the special header information, break out when we get to
+ * the first revision delta
+ */
+ for (;;)
+ {
+ /* get the next key/value pair */
+
+ /* if key is NULL here, then the file is missing some headers
+ or we had trouble reading the file. */
+ if (getrcskey (fp, &key, &value) == -1 || key == NULL)
+ {
+ if (ferror(fp))
+ {
+ error (1, 0, "error reading `%s'", rcsfile);
+ }
+ else
+ {
+ error (1, 0, "`%s' does not appear to be a valid rcs file",
+ rcsfile);
+ }
+ }
+
+ if (strcmp (RCSSYMBOLS, key) == 0)
+ {
+ if (value != NULL)
+ {
+ rdata->symbols_data = xstrdup(value);
+ continue;
+ }
+ }
+
+ if (strcmp (RCSEXPAND, key) == 0)
+ {
+ rdata->expand = xstrdup (value);
+ continue;
+ }
+
+ /*
+ * check key for '.''s and digits (probably a rev) if it is a
+ * revision, we are done with the headers and are down to the
+ * revision deltas, so we break out of the loop
+ */
+ for (cp = key; (isdigit (*cp) || *cp == '.') && *cp != '\0'; cp++)
+ /* do nothing */ ;
+ if (*cp == '\0' && strncmp (RCSDATE, value, strlen (RCSDATE)) == 0)
+ break;
+
+ /* if we haven't grabbed it yet, we didn't want it */
+ }
+
+ /*
+ * we got out of the loop, so we have the first part of the first
+ * revision delta in our hand key=the revision and value=the date key and
+ * its value
+ */
+ for (;;)
+ {
+ char *valp;
+ char date[MAXDATELEN];
+
+ /* grab the value of the date from value */
+ valp = value + strlen (RCSDATE);/* skip the "date" keyword */
+ while (whitespace (*valp)) /* take space off front of value */
+ valp++;
+ (void) strcpy (date, valp);
+
+ /* get the nodes (q is by version, r is by date) */
+ q = getnode ();
+ r = getnode ();
+ q->type = RCSVERS;
+ r->type = RCSVERS;
+ q->delproc = rcsvers_delproc;
+ r->delproc = null_delproc;
+ q->data = r->data = xmalloc (sizeof (RCSVers));
+ memset (q->data, 0, sizeof (RCSVers));
+ vnode = (RCSVers *) q->data;
+
+ /* fill in the version before we forget it */
+ q->key = vnode->version = xstrdup (key);
+
+ /* throw away the author field */
+ (void) getrcskey (fp, &key, &value);
+
+ /* throw away the state field */
+ (void) getrcskey (fp, &key, &value);
+#ifdef DEATH_SUPPORT
+ /* Accept this regardless of DEATH_STATE, so that we can read
+ repositories created with different versions of CVS. */
+ if (strcmp (key, "state") != 0)
+ error (1, 0, "\
+unable to parse rcs file; `state' not in the expected place");
+ if (strcmp (value, "dead") == 0)
+ {
+ vnode->dead = 1;
+ }
+#endif
+
+ /* fill in the date field */
+ r->key = vnode->date = xstrdup (date);
+
+ /* fill in the branch list (if any branches exist) */
+ (void) getrcskey (fp, &key, &value);
+ if (value != (char *) NULL)
+ {
+ vnode->branches = getlist ();
+ do_branches (vnode->branches, value);
+ }
+
+ /* fill in the next field if there is a next revision */
+ (void) getrcskey (fp, &key, &value);
+ if (value != (char *) NULL)
+ vnode->next = xstrdup (value);
+
+ /*
+ * at this point, we skip any user defined fields XXX - this is where
+ * we put the symbolic link stuff???
+ */
+ while ((n = getrcskey (fp, &key, &value)) >= 0)
+ {
+#ifdef DEATH_SUPPORT
+ /* Enable use of repositories created with a CVS which defines
+ DEATH_SUPPORT and not DEATH_STATE. */
+ if (strcmp(key, RCSDEAD) == 0)
+ {
+ vnode->dead = 1;
+ continue;
+ }
+#endif
+ /* if we have a revision, break and do it */
+ for (cp = key; (isdigit (*cp) || *cp == '.') && *cp != '\0'; cp++)
+ /* do nothing */ ;
+ if (*cp == '\0' && strncmp (RCSDATE, value, strlen (RCSDATE)) == 0)
+ break;
+ }
+
+ /* add the nodes to the lists */
+ (void) addnode (rdata->versions, q);
+ (void) addnode (rdata->dates, r);
+
+ /*
+ * if we left the loop because there were no more keys, we break out
+ * of the revision processing loop
+ */
+ if (n < 0)
+ break;
+ }
+
+ fclose (fp);
+ rdata->flags &= ~PARTIAL;
+}
+
+/*
+ * rcsnode_delproc - free up an RCS type node
+ */
+static void
+rcsnode_delproc (p)
+ Node *p;
+{
+ freercsnode ((RCSNode **) & p->data);
+}
+
+/*
+ * freercsnode - free up the info for an RCSNode
+ */
+void
+freercsnode (rnodep)
+ RCSNode **rnodep;
+{
+ if (rnodep == NULL || *rnodep == NULL)
+ return;
+
+ ((*rnodep)->refcount)--;
+ if ((*rnodep)->refcount != 0)
+ {
+ *rnodep = (RCSNode *) NULL;
+ return;
+ }
+ free ((*rnodep)->path);
+ dellist (&(*rnodep)->versions);
+ dellist (&(*rnodep)->dates);
+ if ((*rnodep)->symbols != (List *) NULL)
+ dellist (&(*rnodep)->symbols);
+ if ((*rnodep)->symbols_data != (char *) NULL)
+ free ((*rnodep)->symbols_data);
+ if ((*rnodep)->expand != NULL)
+ free ((*rnodep)->expand);
+ if ((*rnodep)->head != (char *) NULL)
+ free ((*rnodep)->head);
+ if ((*rnodep)->branch != (char *) NULL)
+ free ((*rnodep)->branch);
+ free ((char *) *rnodep);
+ *rnodep = (RCSNode *) NULL;
+}
+
+/*
+ * rcsvers_delproc - free up an RCSVers type node
+ */
+static void
+rcsvers_delproc (p)
+ Node *p;
+{
+ RCSVers *rnode;
+
+ rnode = (RCSVers *) p->data;
+
+ if (rnode->branches != (List *) NULL)
+ dellist (&rnode->branches);
+ if (rnode->next != (char *) NULL)
+ free (rnode->next);
+ free ((char *) rnode);
+}
+
+/*
+ * null_delproc - don't free anything since it will be free'd by someone else
+ */
+/* ARGSUSED */
+static void
+null_delproc (p)
+ Node *p;
+{
+ /* don't do anything */
+}
+
+/*
+ * getrcskey - fill in the key and value from the rcs file the algorithm is
+ * as follows
+ *
+ * o skip whitespace o fill in key with everything up to next white
+ * space or semicolon
+ * o if key == "desc" then key and data are NULL and return -1
+ * o if key wasn't terminated by a semicolon, skip white space and fill
+ * in value with everything up to a semicolon
+ * o compress all whitespace down to a single space
+ * o if a word starts with @, do funky rcs processing
+ * o strip whitespace off end of value or set value to NULL if it empty
+ * o return 0 since we found something besides "desc"
+ */
+
+static char *key = NULL;
+static char *value = NULL;
+static size_t keysize = 0;
+static size_t valsize = 0;
+
+#define ALLOCINCR 1024
+
+static int
+getrcskey (fp, keyp, valp)
+ FILE *fp;
+ char **keyp;
+ char **valp;
+{
+ char *cur, *max;
+ int c;
+
+ /* skip leading whitespace */
+ do
+ {
+ c = getc (fp);
+ if (c == EOF)
+ {
+ *keyp = (char *) NULL;
+ *valp = (char *) NULL;
+ return (-1);
+ }
+ } while (whitespace (c));
+
+ /* fill in key */
+ cur = key;
+ max = key + keysize;
+ while (!whitespace (c) && c != ';')
+ {
+ if (cur >= max)
+ {
+ key = xrealloc (key, keysize + ALLOCINCR);
+ cur = key + keysize;
+ keysize += ALLOCINCR;
+ max = key + keysize;
+ }
+ *cur++ = c;
+
+ c = getc (fp);
+ if (c == EOF)
+ {
+ *keyp = (char *) NULL;
+ *valp = (char *) NULL;
+ return (-1);
+ }
+ }
+ if (cur >= max)
+ {
+ key = xrealloc (key, keysize + ALLOCINCR);
+ cur = key + keysize;
+ keysize += ALLOCINCR;
+ max = key + keysize;
+ }
+ *cur = '\0';
+
+ /* if we got "desc", we are done with the file */
+ if (strcmp (RCSDESC, key) == 0)
+ {
+ *keyp = (char *) NULL;
+ *valp = (char *) NULL;
+ return (-1);
+ }
+
+ /* skip whitespace between key and val */
+ while (whitespace (c))
+ {
+ c = getc (fp);
+ if (c == EOF)
+ {
+ *keyp = (char *) NULL;
+ *valp = (char *) NULL;
+ return (-1);
+ }
+ }
+
+ /* if we ended key with a semicolon, there is no value */
+ if (c == ';')
+ {
+ *keyp = key;
+ *valp = (char *) NULL;
+ return (0);
+ }
+
+ /* otherwise, there might be a value, so fill it in */
+ cur = value;
+ max = value + valsize;
+
+ /* process the value */
+ for (;;)
+ {
+ /* handle RCS "strings" */
+ if (c == '@')
+ {
+ for (;;)
+ {
+ c = getc (fp);
+ if (c == EOF)
+ {
+ *keyp = (char *) NULL;
+ *valp = (char *) NULL;
+ return (-1);
+ }
+
+ if (c == '@')
+ {
+ c = getc (fp);
+ if (c == EOF)
+ {
+ *keyp = (char *) NULL;
+ *valp = (char *) NULL;
+ return (-1);
+ }
+
+ if (c != '@')
+ break;
+ }
+
+ if (cur >= max)
+ {
+ value = xrealloc (value, valsize + ALLOCINCR);
+ cur = value + valsize;
+ valsize += ALLOCINCR;
+ max = value + valsize;
+ }
+ *cur++ = c;
+ }
+ }
+
+ /* compress whitespace down to a single space */
+ if (whitespace (c))
+ {
+ do {
+ c = getc (fp);
+ if (c == EOF)
+ {
+ *keyp = (char *) NULL;
+ *valp = (char *) NULL;
+ return (-1);
+ }
+ } while (whitespace (c));
+
+ if (cur >= max)
+ {
+ value = xrealloc (value, valsize + ALLOCINCR);
+ cur = value + valsize;
+ valsize += ALLOCINCR;
+ max = value + valsize;
+ }
+ *cur++ = ' ';
+ }
+
+ /* if we got a semi-colon we are done with the entire value */
+ if (c == ';')
+ break;
+
+ if (cur >= max)
+ {
+ value = xrealloc (value, valsize + ALLOCINCR);
+ cur = value + valsize;
+ valsize += ALLOCINCR;
+ max = value + valsize;
+ }
+ *cur++ = c;
+
+ c = getc (fp);
+ if (c == EOF)
+ {
+ *keyp = (char *) NULL;
+ *valp = (char *) NULL;
+ return (-1);
+ }
+ }
+
+ /* terminate the string */
+ if (cur >= max)
+ {
+ value = xrealloc (value, valsize + ALLOCINCR);
+ cur = value + valsize;
+ valsize += ALLOCINCR;
+ max = value + valsize;
+ }
+ *cur = '\0';
+
+ /* if the string is empty, make it null */
+ if (value && *value != '\0')
+ *valp = value;
+ else
+ *valp = NULL;
+ *keyp = key;
+ return (0);
+}
+
+/*
+ * process the symbols list of the rcs file
+ */
+static void
+do_symbols (list, val)
+ List *list;
+ char *val;
+{
+ Node *p;
+ char *cp = val;
+ char *tag, *rev;
+
+ for (;;)
+ {
+ /* skip leading whitespace */
+ while (whitespace (*cp))
+ cp++;
+
+ /* if we got to the end, we are done */
+ if (*cp == '\0')
+ break;
+
+ /* split it up into tag and rev */
+ tag = cp;
+ cp = strchr (cp, ':');
+ *cp++ = '\0';
+ rev = cp;
+ while (!whitespace (*cp) && *cp != '\0')
+ cp++;
+ if (*cp != '\0')
+ *cp++ = '\0';
+
+ /* make a new node and add it to the list */
+ p = getnode ();
+ p->key = xstrdup (tag);
+ p->data = xstrdup (rev);
+ (void) addnode (list, p);
+ }
+}
+
+/*
+ * process the branches list of a revision delta
+ */
+static void
+do_branches (list, val)
+ List *list;
+ char *val;
+{
+ Node *p;
+ char *cp = val;
+ char *branch;
+
+ for (;;)
+ {
+ /* skip leading whitespace */
+ while (whitespace (*cp))
+ cp++;
+
+ /* if we got to the end, we are done */
+ if (*cp == '\0')
+ break;
+
+ /* find the end of this branch */
+ branch = cp;
+ while (!whitespace (*cp) && *cp != '\0')
+ cp++;
+ if (*cp != '\0')
+ *cp++ = '\0';
+
+ /* make a new node and add it to the list */
+ p = getnode ();
+ p->key = xstrdup (branch);
+ (void) addnode (list, p);
+ }
+}
+
+/*
+ * Version Number
+ *
+ * Returns the requested version number of the RCS file, satisfying tags and/or
+ * dates, and walking branches, if necessary.
+ *
+ * The result is returned; null-string if error.
+ */
+char *
+RCS_getversion (rcs, tag, date, force_tag_match, return_both)
+ RCSNode *rcs;
+ char *tag;
+ char *date;
+ int force_tag_match;
+ int return_both;
+{
+ /* make sure we have something to look at... */
+ assert (rcs != NULL);
+
+ if (tag && date)
+ {
+ char *cp, *rev, *tagrev;
+
+ /*
+ * first lookup the tag; if that works, turn the revision into
+ * a branch and lookup the date.
+ */
+ tagrev = RCS_gettag (rcs, tag, force_tag_match, 0);
+ if (tagrev == NULL)
+ return ((char *) NULL);
+
+ if ((cp = strrchr (tagrev, '.')) != NULL)
+ *cp = '\0';
+ rev = RCS_getdatebranch (rcs, date, tagrev);
+ free (tagrev);
+ return (rev);
+ }
+ else if (tag)
+ return (RCS_gettag (rcs, tag, force_tag_match, return_both));
+ else if (date)
+ return (RCS_getdate (rcs, date, force_tag_match));
+ else
+ return (RCS_head (rcs));
+
+}
+
+/*
+ * Find the revision for a specific tag.
+ * If force_tag_match is set, return NULL if an exact match is not
+ * possible otherwise return RCS_head (). We are careful to look for
+ * and handle "magic" revisions specially.
+ *
+ * If the matched tag is a branch tag, find the head of the branch.
+ */
+char *
+RCS_gettag (rcs, symtag, force_tag_match, return_both)
+ RCSNode *rcs;
+ char *symtag;
+ int force_tag_match;
+ int return_both;
+{
+ Node *p;
+ char *tag = symtag;
+
+ /* make sure we have something to look at... */
+ assert (rcs != NULL);
+
+ /* XXX this is probably not necessary, --jtc */
+ if (rcs->flags & PARTIAL)
+ RCS_reparsercsfile (rcs);
+
+ /* If tag is "HEAD", special case to get head RCS revision */
+ if (tag && (strcmp (tag, TAG_HEAD) == 0 || *tag == '\0'))
+#if 0 /* This #if 0 is only in the Cygnus code. Why? Death support? */
+ if (force_tag_match && (rcs->flags & VALID) && (rcs->flags & INATTIC))
+ return ((char *) NULL); /* head request for removed file */
+ else
+#endif
+ return (RCS_head (rcs));
+
+ if (!isdigit (tag[0]))
+ {
+ /* If we got a symbolic tag, resolve it to a numeric */
+ if (rcs == NULL)
+ p = NULL;
+ else {
+ p = findnode (RCS_symbols(rcs), tag);
+ }
+ if (p != NULL)
+ {
+ int dots;
+ char *magic, *branch, *cp;
+
+ tag = p->data;
+
+ /*
+ * If this is a magic revision, we turn it into either its
+ * physical branch equivalent (if one exists) or into
+ * its base revision, which we assume exists.
+ */
+ dots = numdots (tag);
+ if (dots > 2 && (dots & 1) != 0)
+ {
+ branch = strrchr (tag, '.');
+ cp = branch++ - 1;
+ while (*cp != '.')
+ cp--;
+
+ /* see if we have .magic-branch. (".0.") */
+ magic = xmalloc (strlen (tag) + 1);
+ (void) sprintf (magic, ".%d.", RCS_MAGIC_BRANCH);
+ if (strncmp (magic, cp, strlen (magic)) == 0)
+ {
+ char *xtag;
+
+ /* it's magic. See if the branch exists */
+ *cp = '\0'; /* turn it into a revision */
+ xtag = xstrdup (tag);
+ *cp = '.'; /* and back again */
+ (void) sprintf (magic, "%s.%s", xtag, branch);
+ branch = RCS_getbranch (rcs, magic, 1);
+ free (magic);
+ if (branch != NULL)
+ {
+ free (xtag);
+ return (branch);
+ }
+ return (xtag);
+ }
+ free (magic);
+ }
+ }
+ else
+ {
+ /* The tag wasn't there, so return the head or NULL */
+ if (force_tag_match)
+ return (NULL);
+ else
+ return (RCS_head (rcs));
+ }
+ }
+
+ /*
+ * numeric tag processing:
+ * 1) revision number - just return it
+ * 2) branch number - find head of branch
+ */
+
+ /* strip trailing dots */
+ while (tag[strlen (tag) - 1] == '.')
+ tag[strlen (tag) - 1] = '\0';
+
+ if ((numdots (tag) & 1) == 0)
+ {
+ /* we have a branch tag, so we need to walk the branch */
+ return (RCS_getbranch (rcs, tag, force_tag_match));
+ }
+ else
+ {
+ /* we have a revision tag, so make sure it exists */
+ if (rcs == NULL)
+ p = NULL;
+ else
+ p = findnode (rcs->versions, tag);
+ if (p != NULL)
+ {
+ /*
+ * we have found a numeric revision for the revision tag.
+ * To support expanding the RCS keyword Name, return both
+ * the numeric tag and the supplied tag (which might be
+ * symbolic). They are separated with a ':' which is not
+ * a valid tag char. The variable return_both is only set
+ * if this function is called through Version_TS ->
+ * RCS_getversion.
+ */
+ if (return_both)
+ {
+ char *both = xmalloc(strlen(tag) + 2 + strlen(symtag));
+ sprintf(both, "%s:%s", tag, symtag);
+ return both;
+ }
+ else
+ return (xstrdup (tag));
+ }
+ else
+ {
+ /* The revision wasn't there, so return the head or NULL */
+ if (force_tag_match)
+ return (NULL);
+ else
+ return (RCS_head (rcs));
+ }
+ }
+}
+
+/*
+ * Return a "magic" revision as a virtual branch off of REV for the RCS file.
+ * A "magic" revision is one which is unique in the RCS file. By unique, I
+ * mean we return a revision which:
+ * - has a branch of 0 (see rcs.h RCS_MAGIC_BRANCH)
+ * - has a revision component which is not an existing branch off REV
+ * - has a revision component which is not an existing magic revision
+ * - is an even-numbered revision, to avoid conflicts with vendor branches
+ * The first point is what makes it "magic".
+ *
+ * As an example, if we pass in 1.37 as REV, we will look for an existing
+ * branch called 1.37.2. If it did not exist, we would look for an
+ * existing symbolic tag with a numeric part equal to 1.37.0.2. If that
+ * didn't exist, then we know that the 1.37.2 branch can be reserved by
+ * creating a symbolic tag with 1.37.0.2 as the numeric part.
+ *
+ * This allows us to fork development with very little overhead -- just a
+ * symbolic tag is used in the RCS file. When a commit is done, a physical
+ * branch is dynamically created to hold the new revision.
+ *
+ * Note: We assume that REV is an RCS revision and not a branch number.
+ */
+static char *check_rev;
+char *
+RCS_magicrev (rcs, rev)
+ RCSNode *rcs;
+ char *rev;
+{
+ int rev_num;
+ char *xrev, *test_branch;
+
+ xrev = xmalloc (strlen (rev) + 14); /* enough for .0.number */
+ check_rev = xrev;
+
+ /* only look at even numbered branches */
+ for (rev_num = 2; ; rev_num += 2)
+ {
+ /* see if the physical branch exists */
+ (void) sprintf (xrev, "%s.%d", rev, rev_num);
+ test_branch = RCS_getbranch (rcs, xrev, 1);
+ if (test_branch != NULL) /* it did, so keep looking */
+ {
+ free (test_branch);
+ continue;
+ }
+
+ /* now, create a "magic" revision */
+ (void) sprintf (xrev, "%s.%d.%d", rev, RCS_MAGIC_BRANCH, rev_num);
+
+ /* walk the symbols list to see if a magic one already exists */
+ if (walklist (RCS_symbols(rcs), checkmagic_proc, NULL) != 0)
+ continue;
+
+ /* we found a free magic branch. Claim it as ours */
+ return (xrev);
+ }
+}
+
+/*
+ * walklist proc to look for a match in the symbols list.
+ * Returns 0 if the symbol does not match, 1 if it does.
+ */
+static int
+checkmagic_proc (p, closure)
+ Node *p;
+ void *closure;
+{
+ if (strcmp (check_rev, p->data) == 0)
+ return (1);
+ else
+ return (0);
+}
+
+/*
+ * Given a list of RCSNodes, returns non-zero if the specified
+ * revision number or symbolic tag resolves to a "branch" within the
+ * rcs file.
+ */
+int
+RCS_isbranch (file, rev, srcfiles)
+ char *file;
+ char *rev;
+ List *srcfiles;
+{
+ Node *p;
+ RCSNode *rcs;
+
+ /* numeric revisions are easy -- even number of dots is a branch */
+ if (isdigit (*rev))
+ return ((numdots (rev) & 1) == 0);
+
+ /* assume a revision if you can't find the RCS info */
+ p = findnode (srcfiles, file);
+ if (p == NULL)
+ return (0);
+
+ /* now, look for a match in the symbols list */
+ rcs = (RCSNode *) p->data;
+ return (RCS_nodeisbranch (rev, rcs));
+}
+
+/*
+ * Given an RCSNode, returns non-zero if the specified revision number
+ * or symbolic tag resolves to a "branch" within the rcs file. We do
+ * take into account any magic branches as well.
+ */
+int
+RCS_nodeisbranch (rev, rcs)
+ char *rev;
+ RCSNode *rcs;
+{
+ int dots;
+ Node *p;
+
+ /* numeric revisions are easy -- even number of dots is a branch */
+ if (isdigit (*rev))
+ return ((numdots (rev) & 1) == 0);
+
+ p = findnode (RCS_symbols(rcs), rev);
+ if (p == NULL)
+ return (0);
+ dots = numdots (p->data);
+ if ((dots & 1) == 0)
+ return (1);
+
+ /* got a symbolic tag match, but it's not a branch; see if it's magic */
+ if (dots > 2)
+ {
+ char *magic;
+ char *branch = strrchr (p->data, '.');
+ char *cp = branch - 1;
+ while (*cp != '.')
+ cp--;
+
+ /* see if we have .magic-branch. (".0.") */
+ magic = xmalloc (strlen (p->data) + 1);
+ (void) sprintf (magic, ".%d.", RCS_MAGIC_BRANCH);
+ if (strncmp (magic, cp, strlen (magic)) == 0)
+ {
+ free (magic);
+ return (1);
+ }
+ free (magic);
+ }
+ return (0);
+}
+
+/*
+ * Returns a pointer to malloc'ed memory which contains the branch
+ * for the specified *symbolic* tag. Magic branches are handled correctly.
+ */
+char *
+RCS_whatbranch (file, rev, srcfiles)
+ char *file;
+ char *rev;
+ List *srcfiles;
+{
+ int dots;
+ Node *p;
+ RCSNode *rcs;
+
+ /* assume no branch if you can't find the RCS info */
+ p = findnode (srcfiles, file);
+ if (p == NULL)
+ return ((char *) NULL);
+
+ /* now, look for a match in the symbols list */
+ rcs = (RCSNode *) p->data;
+ p = findnode (RCS_symbols(rcs), rev);
+ if (p == NULL)
+ return ((char *) NULL);
+ dots = numdots (p->data);
+ if ((dots & 1) == 0)
+ return (xstrdup (p->data));
+
+ /* got a symbolic tag match, but it's not a branch; see if it's magic */
+ if (dots > 2)
+ {
+ char *magic;
+ char *branch = strrchr (p->data, '.');
+ char *cp = branch++ - 1;
+ while (*cp != '.')
+ cp--;
+
+ /* see if we have .magic-branch. (".0.") */
+ magic = xmalloc (strlen (p->data) + 1);
+ (void) sprintf (magic, ".%d.", RCS_MAGIC_BRANCH);
+ if (strncmp (magic, cp, strlen (magic)) == 0)
+ {
+ /* yep. it's magic. now, construct the real branch */
+ *cp = '\0'; /* turn it into a revision */
+ (void) sprintf (magic, "%s.%s", p->data, branch);
+ *cp = '.'; /* and turn it back */
+ return (magic);
+ }
+ free (magic);
+ }
+ return ((char *) NULL);
+}
+
+/*
+ * Get the head of the specified branch. If the branch does not exist,
+ * return NULL or RCS_head depending on force_tag_match
+ */
+char *
+RCS_getbranch (rcs, tag, force_tag_match)
+ RCSNode *rcs;
+ char *tag;
+ int force_tag_match;
+{
+ Node *p, *head;
+ RCSVers *vn;
+ char *xtag;
+ char *nextvers;
+ char *cp;
+
+ /* make sure we have something to look at... */
+ assert (rcs != NULL);
+
+ if (rcs->flags & PARTIAL)
+ RCS_reparsercsfile (rcs);
+
+ /* find out if the tag contains a dot, or is on the trunk */
+ cp = strrchr (tag, '.');
+
+ /* trunk processing is the special case */
+ if (cp == NULL)
+ {
+ xtag = xmalloc (strlen (tag) + 1 + 1); /* +1 for an extra . */
+ (void) strcpy (xtag, tag);
+ (void) strcat (xtag, ".");
+ for (cp = rcs->head; cp != NULL;)
+ {
+ if (strncmp (xtag, cp, strlen (xtag)) == 0)
+ break;
+ p = findnode (rcs->versions, cp);
+ if (p == NULL)
+ {
+ free (xtag);
+ if (force_tag_match)
+ return (NULL);
+ else
+ return (RCS_head (rcs));
+ }
+ vn = (RCSVers *) p->data;
+ cp = vn->next;
+ }
+ free (xtag);
+ if (cp == NULL)
+ {
+ if (force_tag_match)
+ return (NULL);
+ else
+ return (RCS_head (rcs));
+ }
+ return (xstrdup (cp));
+ }
+
+ /* if it had a `.', terminate the string so we have the base revision */
+ *cp = '\0';
+
+ /* look up the revision this branch is based on */
+ p = findnode (rcs->versions, tag);
+
+ /* put the . back so we have the branch again */
+ *cp = '.';
+
+ if (p == NULL)
+ {
+ /* if the base revision didn't exist, return head or NULL */
+ if (force_tag_match)
+ return (NULL);
+ else
+ return (RCS_head (rcs));
+ }
+
+ /* find the first element of the branch we are looking for */
+ vn = (RCSVers *) p->data;
+ if (vn->branches == NULL)
+ return (NULL);
+ xtag = xmalloc (strlen (tag) + 1 + 1); /* 1 for the extra '.' */
+ (void) strcpy (xtag, tag);
+ (void) strcat (xtag, ".");
+ head = vn->branches->list;
+ for (p = head->next; p != head; p = p->next)
+ if (strncmp (p->key, xtag, strlen (xtag)) == 0)
+ break;
+ free (xtag);
+
+ if (p == head)
+ {
+ /* we didn't find a match so return head or NULL */
+ if (force_tag_match)
+ return (NULL);
+ else
+ return (RCS_head (rcs));
+ }
+
+ /* now walk the next pointers of the branch */
+ nextvers = p->key;
+ do
+ {
+ p = findnode (rcs->versions, nextvers);
+ if (p == NULL)
+ {
+ /* a link in the chain is missing - return head or NULL */
+ if (force_tag_match)
+ return (NULL);
+ else
+ return (RCS_head (rcs));
+ }
+ vn = (RCSVers *) p->data;
+ nextvers = vn->next;
+ } while (nextvers != NULL);
+
+ /* we have the version in our hand, so go for it */
+ return (xstrdup (vn->version));
+}
+
+/*
+ * Get the head of the RCS file. If branch is set, this is the head of the
+ * branch, otherwise the real head
+ */
+char *
+RCS_head (rcs)
+ RCSNode *rcs;
+{
+ /* make sure we have something to look at... */
+ assert (rcs != NULL);
+
+ /*
+ * NOTE: we call getbranch with force_tag_match set to avoid any
+ * possibility of recursion
+ */
+ if (rcs->branch)
+ return (RCS_getbranch (rcs, rcs->branch, 1));
+ else
+ return (xstrdup (rcs->head));
+}
+
+/*
+ * Get the most recent revision, based on the supplied date, but use some
+ * funky stuff and follow the vendor branch maybe
+ */
+char *
+RCS_getdate (rcs, date, force_tag_match)
+ RCSNode *rcs;
+ char *date;
+ int force_tag_match;
+{
+ char *cur_rev = NULL;
+ char *retval = NULL;
+ Node *p;
+ RCSVers *vers = NULL;
+
+ /* make sure we have something to look at... */
+ assert (rcs != NULL);
+
+ if (rcs->flags & PARTIAL)
+ RCS_reparsercsfile (rcs);
+
+ /* if the head is on a branch, try the branch first */
+ if (rcs->branch != NULL)
+ retval = RCS_getdatebranch (rcs, date, rcs->branch);
+
+ /* if we found a match, we are done */
+ if (retval != NULL)
+ return (retval);
+
+ /* otherwise if we have a trunk, try it */
+ if (rcs->head)
+ {
+ p = findnode (rcs->versions, rcs->head);
+ while (p != NULL)
+ {
+ /* if the date of this one is before date, take it */
+ vers = (RCSVers *) p->data;
+ if (RCS_datecmp (vers->date, date) <= 0)
+ {
+ cur_rev = vers->version;
+ break;
+ }
+
+ /* if there is a next version, find the node */
+ if (vers->next != NULL)
+ p = findnode (rcs->versions, vers->next);
+ else
+ p = (Node *) NULL;
+ }
+ }
+
+ /*
+ * at this point, either we have the revision we want, or we have the
+ * first revision on the trunk (1.1?) in our hands
+ */
+
+ /* if we found what we're looking for, and it's not 1.1 return it */
+ if (cur_rev != NULL && strcmp (cur_rev, "1.1") != 0)
+ return (xstrdup (cur_rev));
+
+ /* look on the vendor branch */
+ retval = RCS_getdatebranch (rcs, date, CVSBRANCH);
+
+ /*
+ * if we found a match, return it; otherwise, we return the first
+ * revision on the trunk or NULL depending on force_tag_match and the
+ * date of the first rev
+ */
+ if (retval != NULL)
+ return (retval);
+
+ if (!force_tag_match || RCS_datecmp (vers->date, date) <= 0)
+ return (xstrdup (vers->version));
+ else
+ return (NULL);
+}
+
+/*
+ * Look up the last element on a branch that was put in before the specified
+ * date (return the rev or NULL)
+ */
+static char *
+RCS_getdatebranch (rcs, date, branch)
+ RCSNode *rcs;
+ char *date;
+ char *branch;
+{
+ char *cur_rev = NULL;
+ char *cp;
+ char *xbranch, *xrev;
+ Node *p;
+ RCSVers *vers;
+
+ /* look up the first revision on the branch */
+ xrev = xstrdup (branch);
+ cp = strrchr (xrev, '.');
+ if (cp == NULL)
+ {
+ free (xrev);
+ return (NULL);
+ }
+ *cp = '\0'; /* turn it into a revision */
+
+ assert (rcs != NULL);
+
+ if (rcs->flags & PARTIAL)
+ RCS_reparsercsfile (rcs);
+
+ p = findnode (rcs->versions, xrev);
+ free (xrev);
+ if (p == NULL)
+ return (NULL);
+ vers = (RCSVers *) p->data;
+
+ /* if no branches list, return NULL */
+ if (vers->branches == NULL)
+ return (NULL);
+
+ /* walk the branches list looking for the branch number */
+ xbranch = xmalloc (strlen (branch) + 1 + 1); /* +1 for the extra dot */
+ (void) strcpy (xbranch, branch);
+ (void) strcat (xbranch, ".");
+ for (p = vers->branches->list->next; p != vers->branches->list; p = p->next)
+ if (strncmp (p->key, xbranch, strlen (xbranch)) == 0)
+ break;
+ free (xbranch);
+ if (p == vers->branches->list)
+ return (NULL);
+
+ p = findnode (rcs->versions, p->key);
+
+ /* walk the next pointers until you find the end, or the date is too late */
+ while (p != NULL)
+ {
+ vers = (RCSVers *) p->data;
+ if (RCS_datecmp (vers->date, date) <= 0)
+ cur_rev = vers->version;
+ else
+ break;
+
+ /* if there is a next version, find the node */
+ if (vers->next != NULL)
+ p = findnode (rcs->versions, vers->next);
+ else
+ p = (Node *) NULL;
+ }
+
+ /* if we found something acceptable, return it - otherwise NULL */
+ if (cur_rev != NULL)
+ return (xstrdup (cur_rev));
+ else
+ return (NULL);
+}
+
+/*
+ * Compare two dates in RCS format. Beware the change in format on January 1,
+ * 2000, when years go from 2-digit to full format.
+ */
+int
+RCS_datecmp (date1, date2)
+ char *date1, *date2;
+{
+ int length_diff = strlen (date1) - strlen (date2);
+
+ return (length_diff ? length_diff : strcmp (date1, date2));
+}
+
+/*
+ * Lookup the specified revision in the ,v file and return, in the date
+ * argument, the date specified for the revision *minus one second*, so that
+ * the logically previous revision will be found later.
+ *
+ * Returns zero on failure, RCS revision time as a Unix "time_t" on success.
+ */
+time_t
+RCS_getrevtime (rcs, rev, date, fudge)
+ RCSNode *rcs;
+ char *rev;
+ char *date;
+ int fudge;
+{
+ char tdate[MAXDATELEN];
+ struct tm xtm, *ftm;
+ time_t revdate = 0;
+ Node *p;
+ RCSVers *vers;
+
+ /* make sure we have something to look at... */
+ assert (rcs != NULL);
+
+ if (rcs->flags & PARTIAL)
+ RCS_reparsercsfile (rcs);
+
+ /* look up the revision */
+ p = findnode (rcs->versions, rev);
+ if (p == NULL)
+ return (-1);
+ vers = (RCSVers *) p->data;
+
+ /* split up the date */
+ ftm = &xtm;
+ (void) sscanf (vers->date, SDATEFORM, &ftm->tm_year, &ftm->tm_mon,
+ &ftm->tm_mday, &ftm->tm_hour, &ftm->tm_min,
+ &ftm->tm_sec);
+ if (ftm->tm_year > 1900)
+ ftm->tm_year -= 1900;
+
+ /* put the date in a form getdate can grok */
+#ifdef HAVE_RCS5
+ (void) sprintf (tdate, "%d/%d/%d GMT %d:%d:%d", ftm->tm_mon,
+ ftm->tm_mday, ftm->tm_year, ftm->tm_hour,
+ ftm->tm_min, ftm->tm_sec);
+#else
+ (void) sprintf (tdate, "%d/%d/%d %d:%d:%d", ftm->tm_mon,
+ ftm->tm_mday, ftm->tm_year, ftm->tm_hour,
+ ftm->tm_min, ftm->tm_sec);
+#endif
+
+ /* turn it into seconds since the epoch */
+ revdate = get_date (tdate, (struct timeb *) NULL);
+ if (revdate != (time_t) -1)
+ {
+ revdate -= fudge; /* remove "fudge" seconds */
+ if (date)
+ {
+ /* put an appropriate string into ``date'' if we were given one */
+#ifdef HAVE_RCS5
+ ftm = gmtime (&revdate);
+#else
+ ftm = localtime (&revdate);
+#endif
+ (void) sprintf (date, DATEFORM,
+ ftm->tm_year + (ftm->tm_year < 100 ? 0 : 1900),
+ ftm->tm_mon + 1, ftm->tm_mday, ftm->tm_hour,
+ ftm->tm_min, ftm->tm_sec);
+ }
+ }
+ return (revdate);
+}
+
+List *
+RCS_symbols(rcs)
+ RCSNode *rcs;
+{
+ assert(rcs != NULL);
+
+ if (rcs->flags & PARTIAL)
+ RCS_reparsercsfile (rcs);
+
+ if (rcs->symbols_data) {
+ rcs->symbols = getlist ();
+ do_symbols (rcs->symbols, rcs->symbols_data);
+ free(rcs->symbols_data);
+ rcs->symbols_data = NULL;
+ }
+
+ return rcs->symbols;
+}
+
+/*
+ * The argument ARG is the getopt remainder of the -k option specified on the
+ * command line. This function returns malloc'ed space that can be used
+ * directly in calls to RCS V5, with the -k flag munged correctly.
+ */
+char *
+RCS_check_kflag (arg)
+ const char *arg;
+{
+ static const char *const kflags[] =
+ {"kv", "kvl", "k", "v", "o", "b", (char *) NULL};
+ static const char *const keyword_usage[] =
+ {
+ "%s %s: invalid RCS keyword expansion mode\n",
+ "Valid expansion modes include:\n",
+ " -kkv\tGenerate keywords using the default form.\n",
+ " -kkvl\tLike -kkv, except locker's name inserted.\n",
+ " -kk\tGenerate only keyword names in keyword strings.\n",
+ " -kv\tGenerate only keyword values in keyword strings.\n",
+ " -ko\tGenerate the old keyword string (no changes from checked in file).\n",
+ " -kb\tGenerate binary file unmodified (merges not allowed) (RCS 5.7).\n",
+ NULL,
+ };
+ char karg[10];
+ char const *const *cpp = NULL;
+
+#ifndef HAVE_RCS5
+ error (1, 0, "%s %s: your version of RCS does not support the -k option",
+ program_name, command_name);
+#endif
+
+ if (arg)
+ {
+ for (cpp = kflags; *cpp != NULL; cpp++)
+ {
+ if (strcmp (arg, *cpp) == 0)
+ break;
+ }
+ }
+
+ if (arg == NULL || *cpp == NULL)
+ {
+ usage (keyword_usage);
+ }
+
+ (void) sprintf (karg, "-k%s", *cpp);
+ return (xstrdup (karg));
+}
+
+/*
+ * Do some consistency checks on the symbolic tag... These should equate
+ * pretty close to what RCS checks, though I don't know for certain.
+ */
+void
+RCS_check_tag (tag)
+ const char *tag;
+{
+ char *invalid = "$,.:;@"; /* invalid RCS tag characters */
+ const char *cp;
+
+ /*
+ * The first character must be an alphabetic letter. The remaining
+ * characters cannot be non-visible graphic characters, and must not be
+ * in the set of "invalid" RCS identifier characters.
+ */
+ if (isalpha (*tag))
+ {
+ for (cp = tag; *cp; cp++)
+ {
+ if (!isgraph (*cp))
+ error (1, 0, "tag `%s' has non-visible graphic characters",
+ tag);
+ if (strchr (invalid, *cp))
+ error (1, 0, "tag `%s' must not contain the characters `%s'",
+ tag, invalid);
+ }
+ }
+ else
+ error (1, 0, "tag `%s' must start with a letter", tag);
+}
+
+#ifdef DEATH_SUPPORT
+/*
+ * Return true if RCS revision with TAG is a dead revision.
+ */
+int
+RCS_isdead (rcs, tag)
+ RCSNode *rcs;
+ const char *tag;
+{
+ Node *p;
+ RCSVers *version;
+
+ if (rcs->flags & PARTIAL)
+ RCS_reparsercsfile (rcs);
+
+ p = findnode (rcs->versions, tag);
+ if (p == NULL)
+ return (0);
+
+ version = (RCSVers *) p->data;
+ return (version->dead);
+}
+#endif /* DEATH_SUPPORT */
diff --git a/gnu/usr.bin/cvs/cvs/rcs.h b/gnu/usr.bin/cvs/cvs/rcs.h
new file mode 100644
index 0000000..f64501d
--- /dev/null
+++ b/gnu/usr.bin/cvs/cvs/rcs.h
@@ -0,0 +1,107 @@
+/* $CVSid: @(#)rcs.h 1.18 94/09/23 $ */
+
+/*
+ * Copyright (c) 1992, Brian Berliner and Jeff Polk
+ * Copyright (c) 1989-1992, Brian Berliner
+ *
+ * You may distribute under the terms of the GNU General Public License as
+ * specified in the README file that comes with the CVS 1.4 kit.
+ *
+ * RCS source control definitions needed by rcs.c and friends
+ */
+
+#define RCS "rcs"
+#define RCS_CI "ci"
+#define RCS_CO "co"
+#define RCS_RLOG "rlog"
+#define RCS_DIFF "rcsdiff"
+#define RCS_MERGE "merge"
+#define RCS_RCSMERGE "rcsmerge"
+#define RCS_MERGE_PAT "^>>>>>>> " /* runs "grep" with this pattern */
+#define RCSEXT ",v"
+#define RCSPAT "*,v"
+#define RCSHEAD "head"
+#define RCSBRANCH "branch"
+#define RCSSYMBOLS "symbols"
+#define RCSDATE "date"
+#define RCSDESC "desc"
+#define RCSEXPAND "expand"
+
+/* Used by the version of death support which results if you define
+ DEATH_SUPPORT and not DEATH_STATE. Requires a hacked up RCS. Considered
+ obsolete. */
+#define RCSDEAD "dead"
+
+#define DATEFORM "%02d.%02d.%02d.%02d.%02d.%02d"
+#define SDATEFORM "%d.%d.%d.%d.%d.%d"
+
+/*
+ * Opaque structure definitions used by RCS specific lookup routines
+ */
+#define VALID 0x1 /* flags field contains valid data */
+#define INATTIC 0x2 /* RCS file is located in the Attic */
+#define PARTIAL 0x4 /* RCS file not completly parsed */
+
+struct rcsnode
+{
+ int refcount;
+ int flags;
+ char *path;
+ char *head;
+ char *branch;
+ char *symbols_data;
+ char *expand;
+ List *symbols;
+ List *versions;
+ List *dates;
+};
+
+typedef struct rcsnode RCSNode;
+
+struct rcsversnode
+{
+ char *version;
+ char *date;
+ char *next;
+ int dead;
+ List *branches;
+};
+typedef struct rcsversnode RCSVers;
+
+/*
+ * CVS reserves all even-numbered branches for its own use. "magic" branches
+ * (see rcs.c) are contained as virtual revision numbers (within symbolic
+ * tags only) off the RCS_MAGIC_BRANCH, which is 0. CVS also reserves the
+ * ".1" branch for vendor revisions. So, if you do your own branching, you
+ * should limit your use to odd branch numbers starting at 3.
+ */
+#define RCS_MAGIC_BRANCH 0
+
+/*
+ * exported interfaces
+ */
+List *RCS_parsefiles PROTO((List * files, char *xrepos));
+RCSNode *RCS_parse PROTO((const char *file, const char *repos));
+RCSNode *RCS_parsercsfile PROTO((char *rcsfile));
+char *RCS_check_kflag PROTO((const char *arg));
+char *RCS_getdate PROTO((RCSNode * rcs, char *date, int force_tag_match));
+char *RCS_gettag PROTO((RCSNode * rcs, char *symtag, int force_tag_match,
+ int return_both));
+char *RCS_getversion PROTO((RCSNode * rcs, char *tag, char *date,
+ int force_tag_match, int return_both));
+char *RCS_magicrev PROTO((RCSNode *rcs, char *rev));
+int RCS_isbranch PROTO((char *file, char *rev, List *srcfiles));
+int RCS_nodeisbranch PROTO((char *rev, RCSNode *rcs));
+char *RCS_whatbranch PROTO((char *file, char *tag, List *srcfiles));
+char *RCS_head PROTO((RCSNode * rcs));
+int RCS_datecmp PROTO((char *date1, char *date2));
+time_t RCS_getrevtime PROTO((RCSNode * rcs, char *rev, char *date, int fudge));
+List *RCS_symbols PROTO((RCSNode *rcs));
+void RCS_check_tag PROTO((const char *tag));
+void freercsnode PROTO((RCSNode ** rnodep));
+void RCS_addnode PROTO((const char *file, RCSNode *rcs, List *list));
+char *RCS_getbranch PROTO((RCSNode * rcs, char *tag, int force_tag_match));
+
+#ifdef DEATH_SUPPORT
+int RCS_isdead PROTO((RCSNode *, const char *));
+#endif
diff --git a/gnu/usr.bin/cvs/cvs/rcscmds.c b/gnu/usr.bin/cvs/cvs/rcscmds.c
new file mode 100644
index 0000000..af32cea
--- /dev/null
+++ b/gnu/usr.bin/cvs/cvs/rcscmds.c
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 1992, Brian Berliner and Jeff Polk
+ * Copyright (c) 1989-1992, Brian Berliner
+ *
+ * You may distribute under the terms of the GNU General Public License as
+ * specified in the README file that comes with the CVS 1.4 kit.
+ *
+ * The functions in this file provide an interface for performing
+ * operations directly on RCS files.
+ */
+
+#include "cvs.h"
+
+int
+RCS_settag(path, tag, rev)
+ const char *path;
+ const char *tag;
+ const char *rev;
+{
+ run_setup ("%s%s -q -N%s:%s", Rcsbin, RCS, tag, rev);
+ run_arg (path);
+ return run_exec (RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL);
+}
+
+/* NOERR is 1 to suppress errors--FIXME it would
+ be better to avoid the errors or some cleaner solution. */
+int
+RCS_deltag(path, tag, noerr)
+ const char *path;
+ const char *tag;
+ int noerr;
+{
+ run_setup ("%s%s -q -N%s", Rcsbin, RCS, tag);
+ run_arg (path);
+ return run_exec (RUN_TTY, RUN_TTY, noerr ? DEVNULL : RUN_TTY, RUN_NORMAL);
+}
+
+/* set RCS branch to REV */
+int
+RCS_setbranch(path, rev)
+ const char *path;
+ const char *rev;
+{
+ run_setup ("%s%s -q -b%s", Rcsbin, RCS, rev ? rev : "");
+ run_arg (path);
+ return run_exec (RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL);
+}
+
+/* Lock revision REV. NOERR is 1 to suppress errors--FIXME it would
+ be better to avoid the errors or some cleaner solution. */
+int
+RCS_lock(path, rev, noerr)
+ const char *path;
+ const char *rev;
+ int noerr;
+{
+ run_setup ("%s%s -q -l%s", Rcsbin, RCS, rev ? rev : "");
+ run_arg (path);
+ return run_exec (RUN_TTY, RUN_TTY, noerr ? DEVNULL : RUN_TTY, RUN_NORMAL);
+}
+
+/* Unlock revision REV. NOERR is 1 to suppress errors--FIXME it would
+ be better to avoid the errors or some cleaner solution. */
+int
+RCS_unlock(path, rev, noerr)
+ const char *path;
+ const char *rev;
+ int noerr;
+{
+ run_setup ("%s%s -q -u%s", Rcsbin, RCS, rev ? rev : "");
+ run_arg (path);
+ return run_exec (RUN_TTY, RUN_TTY, noerr ? DEVNULL : RUN_TTY, RUN_NORMAL);
+}
+
+/* Merge revisions REV1 and REV2. */
+int
+RCS_merge(path, options, rev1, rev2)
+ const char *path;
+ const char *options;
+ const char *rev1;
+ const char *rev2;
+{
+ int status;
+
+ /* XXX - Do merge by hand instead of using rcsmerge, due to -k handling */
+
+ run_setup ("%s%s %s -r%s -r%s %s", Rcsbin, RCS_RCSMERGE,
+ options, rev1, rev2, path);
+ status = run_exec (RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL);
+#ifndef HAVE_RCS5
+ if (status == 0)
+ {
+ /* Run GREP to see if there appear to be conflicts in the file */
+ run_setup ("%s", GREP);
+ run_arg (RCS_MERGE_PAT);
+ run_arg (path);
+ status = (run_exec (RUN_TTY, DEVNULL, RUN_TTY, RUN_NORMAL) == 0);
+
+ }
+#endif
+ return status;
+}
diff --git a/gnu/usr.bin/cvs/cvs/recurse.c b/gnu/usr.bin/cvs/cvs/recurse.c
new file mode 100644
index 0000000..f5d9433
--- /dev/null
+++ b/gnu/usr.bin/cvs/cvs/recurse.c
@@ -0,0 +1,646 @@
+/*
+ * Copyright (c) 1992, Brian Berliner and Jeff Polk
+ *
+ * You may distribute under the terms of the GNU General Public License as
+ * specified in the README file that comes with the CVS 1.4 kit.
+ *
+ * General recursion handler
+ *
+ */
+
+#include "cvs.h"
+#include "save-cwd.h"
+
+#ifndef lint
+static const char rcsid[] = "$CVSid: @(#)recurse.c 1.31 94/09/30 $";
+USE(rcsid);
+#endif
+
+static int do_dir_proc PROTO((Node * p, void *closure));
+static int do_file_proc PROTO((Node * p, void *closure));
+static void addlist PROTO((List ** listp, char *key));
+static int unroll_files_proc PROTO((Node *p, void *closure));
+static void addfile PROTO((List **listp, char *dir, char *file));
+
+
+/*
+ * Local static versions eliminates the need for globals
+ */
+static FILEPROC fileproc;
+static FILESDONEPROC filesdoneproc;
+static DIRENTPROC direntproc;
+static DIRLEAVEPROC dirleaveproc;
+static int which;
+static Dtype flags;
+static int aflag;
+static int readlock;
+static int dosrcs;
+static char update_dir[PATH_MAX];
+static char *repository = NULL;
+static List *entries = NULL;
+static List *srcfiles = NULL;
+
+static List *filelist = NULL; /* holds list of files on which to operate */
+static List *dirlist = NULL; /* holds list of directories on which to operate */
+
+struct recursion_frame {
+ FILEPROC fileproc;
+ FILESDONEPROC filesdoneproc;
+ DIRENTPROC direntproc;
+ DIRLEAVEPROC dirleaveproc;
+ Dtype flags;
+ int which;
+ int aflag;
+ int readlock;
+ int dosrcs;
+};
+
+/*
+ * Called to start a recursive command.
+ *
+ * Command line arguments dictate the directories and files on which
+ * we operate. In the special case of no arguments, we default to
+ * ".".
+ *
+ * The general algorithm is as follows.
+ */
+int
+start_recursion (fileproc, filesdoneproc, direntproc, dirleaveproc,
+ argc, argv, local, which, aflag, readlock,
+ update_preload, dosrcs, wd_is_repos)
+ FILEPROC fileproc;
+ FILESDONEPROC filesdoneproc;
+ DIRENTPROC direntproc;
+ DIRLEAVEPROC dirleaveproc;
+ int argc;
+ char **argv;
+ int local;
+ int which;
+ int aflag;
+ int readlock;
+ char *update_preload;
+ int dosrcs;
+ int wd_is_repos; /* Set if caller has already cd'd to the repository */
+{
+ int i, err = 0;
+ Dtype flags;
+ List *files_by_dir = NULL;
+ struct recursion_frame frame;
+
+ if (update_preload == NULL)
+ update_dir[0] = '\0';
+ else
+ (void) strcpy (update_dir, update_preload);
+
+ if (local)
+ flags = R_SKIP_DIRS;
+ else
+ flags = R_PROCESS;
+
+ /* clean up from any previous calls to start_recursion */
+ if (repository)
+ {
+ free (repository);
+ repository = (char *) NULL;
+ }
+ if (entries)
+ {
+ Entries_Close (entries);
+ entries = NULL;
+ }
+ if (srcfiles)
+ dellist (&srcfiles);
+ if (filelist)
+ dellist (&filelist); /* FIXME-krp: no longer correct. */
+/* FIXME-krp: clean up files_by_dir */
+ if (dirlist)
+ dellist (&dirlist);
+
+ if (argc == 0)
+ {
+
+ /*
+ * There were no arguments, so we'll probably just recurse. The
+ * exception to the rule is when we are called from a directory
+ * without any CVS administration files. That has always meant to
+ * process each of the sub-directories, so we pretend like we were
+ * called with the list of sub-dirs of the current dir as args
+ */
+ if ((which & W_LOCAL) && !isdir (CVSADM))
+ dirlist = Find_Dirs ((char *) NULL, W_LOCAL);
+ else
+ addlist (&dirlist, ".");
+
+ err += do_recursion (fileproc, filesdoneproc, direntproc,
+ dirleaveproc, flags, which, aflag,
+ readlock, dosrcs);
+ return(err);
+ }
+
+
+ /*
+ * There were arguments, so we have to handle them by hand. To do
+ * that, we set up the filelist and dirlist with the arguments and
+ * call do_recursion. do_recursion recognizes the fact that the
+ * lists are non-null when it starts and doesn't update them.
+ *
+ * explicitly named directories are stored in dirlist.
+ * explicitly named files are stored in filelist.
+ * other possibility is named entities whicha are not currently in
+ * the working directory.
+ */
+
+ for (i = 0; i < argc; i++)
+ {
+ /* if this argument is a directory, then add it to the list of
+ directories. */
+
+ if (!wrap_name_has (argv[i], WRAP_TOCVS) && isdir (argv[i]))
+ addlist (&dirlist, argv[i]);
+ else
+ {
+ /* otherwise, split argument into directory and component names. */
+ char *dir;
+ char *comp;
+ char tmp[PATH_MAX];
+ char *file_to_try;
+
+ dir = xstrdup (argv[i]);
+ if ((comp = strrchr (dir, '/')) == NULL)
+ {
+ /* no dir component. What we have is an implied "./" */
+ comp = dir;
+ dir = xstrdup(".");
+ }
+ else
+ {
+ char *p = comp;
+
+ *p++ = '\0';
+ comp = xstrdup (p);
+ }
+
+ /* if this argument exists as a file in the current
+ working directory tree, then add it to the files list. */
+
+ if (wd_is_repos)
+ {
+ /* If doing rtag, we've done a chdir to the repository. */
+ sprintf (tmp, "%s%s", argv[i], RCSEXT);
+ file_to_try = tmp;
+ }
+ else
+ file_to_try = argv[i];
+
+ if(isfile(file_to_try))
+ addfile (&files_by_dir, dir, comp);
+ else if (isdir (dir))
+ {
+ if (isdir (CVSADM))
+ {
+ /* otherwise, look for it in the repository. */
+ char *save_update_dir;
+ char *repos;
+
+ /* save & set (aka push) update_dir */
+ save_update_dir = xstrdup (update_dir);
+
+ if (*update_dir != '\0')
+ (void) strcat (update_dir, "/");
+
+ (void) strcat (update_dir, dir);
+
+ /* look for it in the repository. */
+ repos = Name_Repository (dir, update_dir);
+ (void) sprintf (tmp, "%s/%s", repos, comp);
+ free (repos);
+
+ if (!wrap_name_has (comp, WRAP_TOCVS) && isdir(tmp))
+ addlist (&dirlist, argv[i]);
+ else
+ addfile (&files_by_dir, dir, comp);
+
+ (void) sprintf (update_dir, "%s", save_update_dir);
+ free (save_update_dir);
+ }
+ else
+ addfile (&files_by_dir, dir, comp);
+ }
+ else
+ error (1, 0, "no such directory `%s'", dir);
+
+ free (dir);
+ free (comp);
+ }
+ }
+
+ /* At this point we have looped over all named arguments and built
+ a coupla lists. Now we unroll the lists, setting up and
+ calling do_recursion. */
+
+ frame.fileproc = fileproc;
+ frame.filesdoneproc = filesdoneproc;
+ frame.direntproc = direntproc;
+ frame.dirleaveproc = dirleaveproc;
+ frame.flags = flags;
+ frame.which = which;
+ frame.aflag = aflag;
+ frame.readlock = readlock;
+ frame.dosrcs = dosrcs;
+ err += walklist (files_by_dir, unroll_files_proc, (void *) &frame);
+
+ /* then do_recursion on the dirlist. */
+ if (dirlist != NULL)
+ err += do_recursion (frame.fileproc, frame.filesdoneproc,
+ frame.direntproc, frame.dirleaveproc,
+ frame.flags, frame.which, frame.aflag,
+ frame.readlock, frame.dosrcs);
+
+
+ return (err);
+}
+
+/*
+ * Implement the recursive policies on the local directory. This may be
+ * called directly, or may be called by start_recursion
+ */
+int
+do_recursion (xfileproc, xfilesdoneproc, xdirentproc, xdirleaveproc,
+ xflags, xwhich, xaflag, xreadlock, xdosrcs)
+ FILEPROC xfileproc;
+ FILESDONEPROC xfilesdoneproc;
+ DIRENTPROC xdirentproc;
+ DIRLEAVEPROC xdirleaveproc;
+ Dtype xflags;
+ int xwhich;
+ int xaflag;
+ int xreadlock;
+ int xdosrcs;
+{
+ int err = 0;
+ int dodoneproc = 1;
+ char *srepository;
+
+ /* do nothing if told */
+ if (xflags == R_SKIP_ALL)
+ return (0);
+
+ /* set up the static vars */
+ fileproc = xfileproc;
+ filesdoneproc = xfilesdoneproc;
+ direntproc = xdirentproc;
+ dirleaveproc = xdirleaveproc;
+ flags = xflags;
+ which = xwhich;
+ aflag = xaflag;
+ readlock = noexec ? 0 : xreadlock;
+ dosrcs = xdosrcs;
+
+#if defined(SERVER_SUPPORT) && defined(SERVER_FLOWCONTROL)
+ /*
+ * Now would be a good time to check to see if we need to stop
+ * generating data, to give the buffers a chance to drain to the
+ * remote client. We should not have locks active at this point.
+ */
+ if (server_active
+ /* If there are writelocks around, we cannot pause here. */
+ && (readlock || noexec))
+ server_pause_check();
+#endif
+
+ /*
+ * Fill in repository with the current repository
+ */
+ if (which & W_LOCAL)
+ {
+ if (isdir (CVSADM))
+ repository = Name_Repository ((char *) NULL, update_dir);
+ else
+ repository = NULL;
+ }
+ else
+ {
+ repository = xmalloc (PATH_MAX);
+ (void) getwd (repository);
+ }
+ srepository = repository; /* remember what to free */
+
+ /*
+ * The filesdoneproc needs to be called for each directory where files
+ * processed, or each directory that is processed by a call where no
+ * directories were passed in. In fact, the only time we don't want to
+ * call back the filesdoneproc is when we are processing directories that
+ * were passed in on the command line (or in the special case of `.' when
+ * we were called with no args
+ */
+ if (dirlist != NULL && filelist == NULL)
+ dodoneproc = 0;
+
+ /*
+ * If filelist or dirlist is already set, we don't look again. Otherwise,
+ * find the files and directories
+ */
+ if (filelist == NULL && dirlist == NULL)
+ {
+ /* both lists were NULL, so start from scratch */
+ if (fileproc != NULL && flags != R_SKIP_FILES)
+ {
+ int lwhich = which;
+
+ /* be sure to look in the attic if we have sticky tags/date */
+ if ((lwhich & W_ATTIC) == 0)
+ if (isreadable (CVSADM_TAG))
+ lwhich |= W_ATTIC;
+
+ /* find the files and fill in entries if appropriate */
+ filelist = Find_Names (repository, lwhich, aflag, &entries);
+ }
+
+ /* find sub-directories if we will recurse */
+ if (flags != R_SKIP_DIRS)
+ dirlist = Find_Dirs (repository, which);
+ }
+ else
+ {
+ /* something was passed on the command line */
+ if (filelist != NULL && fileproc != NULL)
+ {
+ /* we will process files, so pre-parse entries */
+ if (which & W_LOCAL)
+ entries = Entries_Open (aflag);
+ }
+ }
+
+ /* process the files (if any) */
+ if (filelist != NULL)
+ {
+ /* read lock it if necessary */
+ if (readlock && repository && Reader_Lock (repository) != 0)
+ error (1, 0, "read lock failed - giving up");
+
+ /* pre-parse the source files */
+ if (dosrcs && repository)
+ srcfiles = RCS_parsefiles (filelist, repository);
+ else
+ srcfiles = (List *) NULL;
+
+ /* process the files */
+ err += walklist (filelist, do_file_proc, NULL);
+
+ /* unlock it */
+ if (readlock)
+ Lock_Cleanup ();
+
+ /* clean up */
+ dellist (&filelist);
+ dellist (&srcfiles);
+ Entries_Close (entries);
+ entries = NULL;
+ }
+
+ /* call-back files done proc (if any) */
+ if (dodoneproc && filesdoneproc != NULL)
+ err = filesdoneproc (err, repository, update_dir[0] ? update_dir : ".");
+
+ /* process the directories (if necessary) */
+ if (dirlist != NULL)
+ err += walklist (dirlist, do_dir_proc, NULL);
+#ifdef notdef
+ else if (dirleaveproc != NULL)
+ err += dirleaveproc(".", err, ".");
+#endif
+ dellist (&dirlist);
+
+ /* free the saved copy of the pointer if necessary */
+ if (srepository)
+ {
+ free (srepository);
+ repository = (char *) NULL;
+ }
+
+ return (err);
+}
+
+/*
+ * Process each of the files in the list with the callback proc
+ */
+static int
+do_file_proc (p, closure)
+ Node *p;
+ void *closure;
+{
+ if (fileproc != NULL)
+ return (fileproc (p->key, update_dir, repository, entries, srcfiles));
+ else
+ return (0);
+}
+
+/*
+ * Process each of the directories in the list (recursing as we go)
+ */
+static int
+do_dir_proc (p, closure)
+ Node *p;
+ void *closure;
+{
+ char *dir = p->key;
+ char newrepos[PATH_MAX];
+ List *sdirlist;
+ char *srepository;
+ char *cp;
+ Dtype dir_return = R_PROCESS;
+ int stripped_dot = 0;
+ int err = 0;
+ struct saved_cwd cwd;
+
+ /* set up update_dir - skip dots if not at start */
+ if (strcmp (dir, ".") != 0)
+ {
+ if (update_dir[0] != '\0')
+ {
+ (void) strcat (update_dir, "/");
+ (void) strcat (update_dir, dir);
+ }
+ else
+ (void) strcpy (update_dir, dir);
+
+ /*
+ * Here we need a plausible repository name for the sub-directory. We
+ * create one by concatenating the new directory name onto the
+ * previous repository name. The only case where the name should be
+ * used is in the case where we are creating a new sub-directory for
+ * update -d and in that case the generated name will be correct.
+ */
+ if (repository == NULL)
+ newrepos[0] = '\0';
+ else
+ (void) sprintf (newrepos, "%s/%s", repository, dir);
+ }
+ else
+ {
+ if (update_dir[0] == '\0')
+ (void) strcpy (update_dir, dir);
+
+ if (repository == NULL)
+ newrepos[0] = '\0';
+ else
+ (void) strcpy (newrepos, repository);
+ }
+
+ /* call-back dir entry proc (if any) */
+ if (direntproc != NULL)
+ dir_return = direntproc (dir, newrepos, update_dir);
+
+ /* only process the dir if the return code was 0 */
+ if (dir_return != R_SKIP_ALL)
+ {
+ /* save our current directory and static vars */
+ if (save_cwd (&cwd))
+ exit (1);
+ sdirlist = dirlist;
+ srepository = repository;
+ dirlist = NULL;
+
+ /* cd to the sub-directory */
+ if (chdir (dir) < 0)
+ error (1, errno, "could not chdir to %s", dir);
+
+ /* honor the global SKIP_DIRS (a.k.a. local) */
+ if (flags == R_SKIP_DIRS)
+ dir_return = R_SKIP_DIRS;
+
+ /* remember if the `.' will be stripped for subsequent dirs */
+ if (strcmp (update_dir, ".") == 0)
+ {
+ update_dir[0] = '\0';
+ stripped_dot = 1;
+ }
+
+ /* make the recursive call */
+ err += do_recursion (fileproc, filesdoneproc, direntproc, dirleaveproc,
+ dir_return, which, aflag, readlock, dosrcs);
+
+ /* put the `.' back if necessary */
+ if (stripped_dot)
+ (void) strcpy (update_dir, ".");
+
+ /* call-back dir leave proc (if any) */
+ if (dirleaveproc != NULL)
+ err = dirleaveproc (dir, err, update_dir);
+
+ /* get back to where we started and restore state vars */
+ if (restore_cwd (&cwd, NULL))
+ exit (1);
+ free_cwd (&cwd);
+ dirlist = sdirlist;
+ repository = srepository;
+ }
+
+ /* put back update_dir */
+ if ((cp = strrchr (update_dir, '/')) != NULL)
+ *cp = '\0';
+ else
+ update_dir[0] = '\0';
+
+ return (err);
+}
+
+/*
+ * Add a node to a list allocating the list if necessary.
+ */
+static void
+addlist (listp, key)
+ List **listp;
+ char *key;
+{
+ Node *p;
+
+ if (*listp == NULL)
+ *listp = getlist ();
+ p = getnode ();
+ p->type = FILES;
+ p->key = xstrdup (key);
+ if (addnode (*listp, p) != 0)
+ freenode (p);
+}
+
+static void
+addfile (listp, dir, file)
+ List **listp;
+ char *dir;
+ char *file;
+{
+ Node *n;
+
+ /* add this dir. */
+ addlist (listp, dir);
+
+ n = findnode (*listp, dir);
+ if (n == NULL)
+ {
+ error (1, 0, "can't find recently added dir node `%s' in start_recursion.",
+ dir);
+ }
+
+ n->type = DIRS;
+ addlist ((List **) &n->data, file);
+ return;
+}
+
+static int
+unroll_files_proc (p, closure)
+ Node *p;
+ void *closure;
+{
+ Node *n;
+ struct recursion_frame *frame = (struct recursion_frame *) closure;
+ int err = 0;
+ List *save_dirlist;
+ char *save_update_dir = NULL;
+ struct saved_cwd cwd;
+
+ /* if this dir was also an explicitly named argument, then skip
+ it. We'll catch it later when we do dirs. */
+ n = findnode (dirlist, p->key);
+ if (n != NULL)
+ return (0);
+
+ /* otherwise, call dorecusion for this list of files. */
+ filelist = (List *) p->data;
+ save_dirlist = dirlist;
+ dirlist = NULL;
+
+ if (strcmp(p->key, ".") != 0)
+ {
+ if (save_cwd (&cwd))
+ exit (1);
+ if (chdir (p->key) < 0)
+ error (1, errno, "could not chdir to %s", p->key);
+
+ save_update_dir = xstrdup (update_dir);
+
+ if (*update_dir != '\0')
+ (void) strcat (update_dir, "/");
+
+ (void) strcat (update_dir, p->key);
+ }
+
+ err += do_recursion (frame->fileproc, frame->filesdoneproc,
+ frame->direntproc, frame->dirleaveproc,
+ frame->flags, frame->which, frame->aflag,
+ frame->readlock, frame->dosrcs);
+
+ if (save_update_dir != NULL)
+ {
+ (void) strcpy (update_dir, save_update_dir);
+ free (save_update_dir);
+
+ if (restore_cwd (&cwd, NULL))
+ exit (1);
+ free_cwd (&cwd);
+ }
+
+ dirlist = save_dirlist;
+ filelist = NULL;
+ return(err);
+}
diff --git a/gnu/usr.bin/cvs/cvs/release.c b/gnu/usr.bin/cvs/cvs/release.c
new file mode 100644
index 0000000..c768bd3
--- /dev/null
+++ b/gnu/usr.bin/cvs/cvs/release.c
@@ -0,0 +1,259 @@
+/*
+ * Release: "cancel" a checkout in the history log.
+ *
+ * - Don't allow release if anything is active - Don't allow release if not
+ * above or inside repository. - Don't allow release if ./CVS/Repository is
+ * not the same as the directory specified in the module database.
+ *
+ * - Enter a line in the history log indicating the "release". - If asked to,
+ * delete the local working directory.
+ */
+
+#include "cvs.h"
+
+#ifndef lint
+static const char rcsid[] = "$CVSid: @(#)release.c 1.23 94/09/21 $";
+USE(rcsid);
+#endif
+
+static void release_delete PROTO((char *dir));
+
+static const char *const release_usage[] =
+{
+ "Usage: %s %s [-d] modules...\n",
+ "\t-d\tDelete the given directory.\n",
+ NULL
+};
+
+static short delete;
+
+int
+release (argc, argv)
+ int argc;
+ char **argv;
+{
+ FILE *fp;
+ register int i, c;
+ char *repository, *srepos;
+ char line[PATH_MAX], update_cmd[PATH_MAX];
+ char *thisarg;
+ int arg_start_idx;
+
+#ifdef SERVER_SUPPORT
+ if (!server_active)
+ {
+#endif /* SERVER_SUPPORT */
+ if (argc == -1)
+ usage (release_usage);
+ optind = 1;
+ while ((c = getopt (argc, argv, "Qdq")) != -1)
+ {
+ switch (c)
+ {
+ case 'Q':
+ case 'q':
+#ifdef SERVER_SUPPORT
+ /* The CVS 1.5 client sends these options (in addition to
+ Global_option requests), so we must ignore them. */
+ if (!server_active)
+#endif
+ error (1, 0,
+ "-q or -Q must be specified before \"%s\"",
+ command_name);
+ break;
+ case 'd':
+ delete++;
+ break;
+ case '?':
+ default:
+ usage (release_usage);
+ break;
+ }
+ }
+ argc -= optind;
+ argv += optind;
+#ifdef SERVER_SUPPORT
+ }
+#endif /* SERVER_SUPPORT */
+
+ /* We're going to run "cvs -n -q update" and check its output; if
+ * the output is sufficiently unalarming, then we release with no
+ * questions asked. Else we prompt, then maybe release.
+ */
+ /* Construct the update command. */
+ sprintf (update_cmd, "%s -n -q -d %s update",
+ program_path, CVSroot);
+
+#ifdef CLIENT_SUPPORT
+ /* Start the server; we'll close it after looping. */
+ if (client_active)
+ {
+ start_server ();
+ ign_setup ();
+ }
+#endif /* CLIENT_SUPPORT */
+
+ /* If !server_active, we already skipped over argv[0] in the "argc
+ -= optind;" statement above. But if server_active, we need to
+ skip it now. */
+#ifdef SERVER_SUPPORT
+ if (server_active)
+ arg_start_idx = 1;
+ else
+ arg_start_idx = 0;
+#endif /* SERVER_SUPPORT */
+
+ for (i = arg_start_idx; i < argc; i++)
+ {
+ thisarg = argv[i];
+
+#ifdef SERVER_SUPPORT
+ if (server_active)
+ {
+ /* Just log the release -- all the interesting stuff happened
+ * on the client.
+ */
+ history_write ('F', thisarg, "", thisarg, ""); /* F == Free */
+ }
+ else
+ {
+#endif /* SERVER_SUPPORT */
+
+ /*
+ * If we are in a repository, do it. Else if we are in the parent of
+ * a directory with the same name as the module, "cd" into it and
+ * look for a repository there.
+ */
+ if (isdir (thisarg))
+ {
+ if (chdir (thisarg) < 0)
+ {
+ if (!really_quiet)
+ error (0, 0, "can't chdir to: %s", thisarg);
+ continue;
+ }
+ if (!isdir (CVSADM))
+ {
+ if (!really_quiet)
+ error (0, 0, "no repository module: %s", thisarg);
+ continue;
+ }
+ }
+ else
+ {
+ if (!really_quiet)
+ error (0, 0, "no such directory: %s", thisarg);
+ continue;
+ }
+
+ repository = Name_Repository ((char *) NULL, (char *) NULL);
+ srepos = Short_Repository (repository);
+
+ if (!really_quiet)
+ {
+ /* The "release" command piggybacks on "update", which
+ * does the real work of finding out if anything is not
+ * up-to-date with the repository. Then "release" prompts
+ * the user, telling her how many files have been
+ * modified, and asking if she still wants to do the
+ * release.
+ */
+ fp = Popen (update_cmd, "r");
+ c = 0;
+
+ while (fgets (line, sizeof (line), fp))
+ {
+ if (strchr ("MARCZ", *line))
+ c++;
+ (void) printf (line);
+ }
+
+ /* If the update exited with an error, then we just want to
+ * complain and go on to the next arg. Especially, we do
+ * not want to delete the local copy, since it's obviously
+ * not what the user thinks it is.
+ */
+ if ((pclose (fp)) != 0)
+ {
+ error (0, 0, "unable to release `%s'", thisarg);
+ continue;
+ }
+
+ (void) printf ("You have [%d] altered files in this repository.\n",
+ c);
+ (void) printf ("Are you sure you want to release %smodule `%s': ",
+ delete ? "(and delete) " : "", thisarg);
+ c = !yesno ();
+ if (c) /* "No" */
+ {
+ (void) fprintf (stderr, "** `%s' aborted by user choice.\n",
+ command_name);
+ free (repository);
+ continue;
+ }
+ }
+
+#ifdef CLIENT_SUPPORT
+ if (client_active)
+ {
+ if (fprintf (to_server, "Argument %s\n", thisarg) < 0)
+ error (1, errno, "writing to server");
+ if (fprintf (to_server, "release\n") < 0)
+ error (1, errno, "writing to server");
+ }
+ else
+ {
+#endif /* CLIENT_SUPPORT */
+ history_write ('F', thisarg, "", thisarg, ""); /* F == Free */
+#ifdef CLIENT_SUPPORT
+ } /* else client not active */
+#endif /* CLIENT_SUPPORT */
+
+ free (repository);
+ if (delete) release_delete (thisarg);
+
+#ifdef CLIENT_SUPPORT
+ if (client_active)
+ return get_responses_and_close ();
+ else
+#endif /* CLIENT_SUPPORT */
+ return (0);
+
+#ifdef SERVER_SUPPORT
+ } /* else server not active */
+#endif /* SERVER_SUPPORT */
+ } /* `for' loop */
+ return (0);
+}
+
+
+/* We want to "rm -r" the working directory, but let us be a little
+ paranoid. */
+static void
+release_delete (dir)
+ char *dir;
+{
+ struct stat st;
+ ino_t ino;
+ int retcode = 0;
+
+ (void) stat (".", &st);
+ ino = st.st_ino;
+ (void) chdir ("..");
+ (void) stat (dir, &st);
+ if (ino != st.st_ino)
+ {
+ error (0, 0,
+ "Parent dir on a different disk, delete of %s aborted", dir);
+ return;
+ }
+ /*
+ * XXX - shouldn't this just delete the CVS-controlled files and, perhaps,
+ * the files that would normally be ignored and leave everything else?
+ */
+ run_setup ("%s -fr", RM);
+ run_arg (dir);
+ if ((retcode = run_exec (RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL)) != 0)
+ error (0, retcode == -1 ? errno : 0,
+ "deletion of module %s failed.", dir);
+}
diff --git a/gnu/usr.bin/cvs/cvs/remove.c b/gnu/usr.bin/cvs/cvs/remove.c
new file mode 100644
index 0000000..a33c4f9
--- /dev/null
+++ b/gnu/usr.bin/cvs/cvs/remove.c
@@ -0,0 +1,213 @@
+/*
+ * Copyright (c) 1992, Brian Berliner and Jeff Polk
+ * Copyright (c) 1989-1992, Brian Berliner
+ *
+ * You may distribute under the terms of the GNU General Public License as
+ * specified in the README file that comes with the CVS 1.4 kit.
+ *
+ * Remove a File
+ *
+ * Removes entries from the present version. The entries will be removed from
+ * the RCS repository upon the next "commit".
+ *
+ * "remove" accepts no options, only file names that are to be removed. The
+ * file must not exist in the current directory for "remove" to work
+ * correctly.
+ */
+
+#include "cvs.h"
+
+#ifndef lint
+static const char rcsid[] = "$CVSid: @(#)remove.c 1.39 94/10/07 $";
+USE(rcsid);
+#endif
+
+static int remove_fileproc PROTO((char *file, char *update_dir,
+ char *repository, List *entries,
+ List *srcfiles));
+static Dtype remove_dirproc PROTO((char *dir, char *repos, char *update_dir));
+
+static int force;
+static int local;
+static int removed_files;
+static int existing_files;
+
+static const char *const remove_usage[] =
+{
+ "Usage: %s %s [-flR] [files...]\n",
+ "\t-f\tDelete the file before removing it.\n",
+ "\t-l\tProcess this directory only (not recursive).\n",
+ "\t-R\tProcess directories recursively.\n",
+ NULL
+};
+
+int
+cvsremove (argc, argv)
+ int argc;
+ char **argv;
+{
+ int c, err;
+
+ if (argc == -1)
+ usage (remove_usage);
+
+ optind = 1;
+ while ((c = getopt (argc, argv, "flR")) != -1)
+ {
+ switch (c)
+ {
+ case 'f':
+ force = 1;
+ break;
+ case 'l':
+ local = 1;
+ break;
+ case 'R':
+ local = 0;
+ break;
+ case '?':
+ default:
+ usage (remove_usage);
+ break;
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+ wrap_setup ();
+
+#ifdef CLIENT_SUPPORT
+ if (client_active) {
+ start_server ();
+ ign_setup ();
+ if (local)
+ send_arg("-l");
+ send_files (argc, argv, local, 0);
+ if (fprintf (to_server, "remove\n") < 0)
+ error (1, errno, "writing to server");
+ return get_responses_and_close ();
+ }
+#endif
+
+ /* start the recursion processor */
+ err = start_recursion (remove_fileproc, (int (*) ()) NULL, remove_dirproc,
+ (int (*) ()) NULL, argc, argv, local,
+ W_LOCAL, 0, 1, (char *) NULL, 1, 0);
+
+ if (removed_files)
+ error (0, 0, "use '%s commit' to remove %s permanently", program_name,
+ (removed_files == 1) ? "this file" : "these files");
+
+ if (existing_files)
+ error (0, 0,
+ ((existing_files == 1) ?
+ "%d file exists; use `%s' to remove it first" :
+ "%d files exist; use `%s' to remove them first"),
+ existing_files, RM);
+
+ return (err);
+}
+
+/*
+ * remove the file, only if it has already been physically removed
+ */
+/* ARGSUSED */
+static int
+remove_fileproc (file, update_dir, repository, entries, srcfiles)
+ char *file;
+ char *update_dir;
+ char *repository;
+ List *entries;
+ List *srcfiles;
+{
+ char fname[PATH_MAX];
+ Vers_TS *vers;
+
+ if (force)
+ {
+ if (!noexec)
+ {
+ if (unlink (file) < 0 && ! existence_error (errno))
+ {
+ if (update_dir[0] == '\0')
+ error (0, errno, "unable to remove %s", file);
+ else
+ error (0, errno, "unable to remove %s/%s", update_dir,
+ file);
+ }
+ }
+ /* else FIXME should probably act as if the file doesn't exist
+ in doing the following checks. */
+ }
+
+ vers = Version_TS (repository, (char *) NULL, (char *) NULL, (char *) NULL,
+ file, 0, 0, entries, srcfiles);
+
+ if (vers->ts_user != NULL)
+ {
+ existing_files++;
+ if (!quiet)
+ error (0, 0, "file `%s' still in working directory", file);
+ }
+ else if (vers->vn_user == NULL)
+ {
+ if (!quiet)
+ error (0, 0, "nothing known about `%s'", file);
+ }
+ else if (vers->vn_user[0] == '0' && vers->vn_user[1] == '\0')
+ {
+ /*
+ * It's a file that has been added, but not commited yet. So,
+ * remove the ,t file for it and scratch it from the
+ * entries file. */
+ Scratch_Entry (entries, file);
+ (void) sprintf (fname, "%s/%s%s", CVSADM, file, CVSEXT_LOG);
+ (void) unlink_file (fname);
+ if (!quiet)
+ error (0, 0, "removed `%s'", file);
+
+#ifdef SERVER_SUPPORT
+ if (server_active)
+ server_checked_in (file, update_dir, repository);
+#endif
+ }
+ else if (vers->vn_user[0] == '-')
+ {
+ if (!quiet)
+ error (0, 0, "file `%s' already scheduled for removal", file);
+ }
+ else
+ {
+ /* Re-register it with a negative version number. */
+ (void) strcpy (fname, "-");
+ (void) strcat (fname, vers->vn_user);
+ Register (entries, file, fname, vers->ts_rcs, vers->options,
+ vers->tag, vers->date, vers->ts_conflict);
+ if (!quiet)
+ error (0, 0, "scheduling `%s' for removal", file);
+ removed_files++;
+
+#ifdef SERVER_SUPPORT
+ if (server_active)
+ server_checked_in (file, update_dir, repository);
+#endif
+ }
+
+ freevers_ts (&vers);
+ return (0);
+}
+
+/*
+ * Print a warm fuzzy message
+ */
+/* ARGSUSED */
+static Dtype
+remove_dirproc (dir, repos, update_dir)
+ char *dir;
+ char *repos;
+ char *update_dir;
+{
+ if (!quiet)
+ error (0, 0, "Removing %s", update_dir);
+ return (R_PROCESS);
+}
diff --git a/gnu/usr.bin/cvs/cvs/repos.c b/gnu/usr.bin/cvs/cvs/repos.c
new file mode 100644
index 0000000..8566433
--- /dev/null
+++ b/gnu/usr.bin/cvs/cvs/repos.c
@@ -0,0 +1,147 @@
+/*
+ * Copyright (c) 1992, Brian Berliner and Jeff Polk
+ * Copyright (c) 1989-1992, Brian Berliner
+ *
+ * You may distribute under the terms of the GNU General Public License as
+ * specified in the README file that comes with the CVS 1.4 kit.
+ *
+ * Name of Repository
+ *
+ * Determine the name of the RCS repository and sets "Repository" accordingly.
+ */
+
+#include "cvs.h"
+
+#ifndef lint
+static const char rcsid[] = "$CVSid: @(#)repos.c 1.32 94/09/23 $";
+USE(rcsid);
+#endif
+
+char *
+Name_Repository (dir, update_dir)
+ char *dir;
+ char *update_dir;
+{
+ FILE *fpin;
+ char *ret, *xupdate_dir;
+ char repos[PATH_MAX];
+ char path[PATH_MAX];
+ char tmp[PATH_MAX];
+ char cvsadm[PATH_MAX];
+ char *cp;
+
+ if (update_dir && *update_dir)
+ xupdate_dir = update_dir;
+ else
+ xupdate_dir = ".";
+
+ if (dir != NULL)
+ (void) sprintf (cvsadm, "%s/%s", dir, CVSADM);
+ else
+ (void) strcpy (cvsadm, CVSADM);
+
+ /* sanity checks */
+ if (!isdir (cvsadm))
+ {
+ error (0, 0, "in directory %s:", xupdate_dir);
+ error (1, 0, "there is no version here; do '%s checkout' first",
+ program_name);
+ }
+
+ if (dir != NULL)
+ (void) sprintf (tmp, "%s/%s", dir, CVSADM_ENT);
+ else
+ (void) strcpy (tmp, CVSADM_ENT);
+
+ if (!isreadable (tmp))
+ {
+ error (0, 0, "in directory %s:", xupdate_dir);
+ error (1, 0, "*PANIC* administration files missing");
+ }
+
+ if (dir != NULL)
+ (void) sprintf (tmp, "%s/%s", dir, CVSADM_REP);
+ else
+ (void) strcpy (tmp, CVSADM_REP);
+
+ if (!isreadable (tmp))
+ {
+ error (0, 0, "in directory %s:", xupdate_dir);
+ error (1, 0, "*PANIC* administration files missing");
+ }
+
+ /*
+ * The assumption here is that the repository is always contained in the
+ * first line of the "Repository" file.
+ */
+ fpin = open_file (tmp, "r");
+
+ if (fgets (repos, PATH_MAX, fpin) == NULL)
+ {
+ error (0, 0, "in directory %s:", xupdate_dir);
+ error (1, errno, "cannot read %s", CVSADM_REP);
+ }
+ (void) fclose (fpin);
+ if ((cp = strrchr (repos, '\n')) != NULL)
+ *cp = '\0'; /* strip the newline */
+
+ /*
+ * If this is a relative repository pathname, turn it into an absolute
+ * one by tacking on the CVSROOT environment variable. If the CVSROOT
+ * environment variable is not set, die now.
+ */
+ if (strcmp (repos, "..") == 0 || strncmp (repos, "../", 3) == 0)
+ {
+ error (0, 0, "in directory %s:", xupdate_dir);
+ error (0, 0, "`..'-relative repositories are not supported.");
+ error (1, 0, "illegal source repository");
+ }
+ if (! isabsolute(repos))
+ {
+ if (CVSroot == NULL)
+ {
+ error (0, 0, "in directory %s:", xupdate_dir);
+ error (0, 0, "must set the CVSROOT environment variable\n");
+ error (0, 0, "or specify the '-d' option to %s.", program_name);
+ error (1, 0, "illegal repository setting");
+ }
+ (void) strcpy (path, repos);
+ (void) sprintf (repos, "%s/%s", CVSroot, path);
+ }
+#ifdef CLIENT_SUPPORT
+ if (!client_active && !isdir (repos))
+#else
+ if (!isdir (repos))
+#endif
+ {
+ error (0, 0, "in directory %s:", xupdate_dir);
+ error (1, 0, "there is no repository %s", repos);
+ }
+
+ /* allocate space to return and fill it in */
+ strip_path (repos);
+ ret = xstrdup (repos);
+ return (ret);
+}
+
+/*
+ * Return a pointer to the repository name relative to CVSROOT from a
+ * possibly fully qualified repository
+ */
+char *
+Short_Repository (repository)
+ char *repository;
+{
+ if (repository == NULL)
+ return (NULL);
+
+ /* If repository matches CVSroot at the beginning, strip off CVSroot */
+ /* And skip leading '/' in rep, in case CVSroot ended with '/'. */
+ if (strncmp (CVSroot, repository, strlen (CVSroot)) == 0)
+ {
+ char *rep = repository + strlen (CVSroot);
+ return (*rep == '/') ? rep+1 : rep;
+ }
+ else
+ return (repository);
+}
diff --git a/gnu/usr.bin/cvs/cvs/root.c b/gnu/usr.bin/cvs/cvs/root.c
new file mode 100644
index 0000000..e3cb979
--- /dev/null
+++ b/gnu/usr.bin/cvs/cvs/root.c
@@ -0,0 +1,182 @@
+/*
+ * Copyright (c) 1992, Mark D. Baushke
+ *
+ * You may distribute under the terms of the GNU General Public License as
+ * specified in the README file that comes with the CVS 1.4 kit.
+ *
+ * Name of Root
+ *
+ * Determine the path to the CVSROOT and set "Root" accordingly.
+ * If this looks like of modified clone of Name_Repository() in
+ * repos.c, it is...
+ */
+
+#include "cvs.h"
+
+#ifndef lint
+static const char rcsid[] = "$CVSid: @(#)root.c,v 1.2 1994/09/15 05:32:17 zoo Exp";
+USE(rcsid);
+#endif
+
+char *
+Name_Root(dir, update_dir)
+ char *dir;
+ char *update_dir;
+{
+ FILE *fpin;
+ char *ret, *xupdate_dir;
+ char root[PATH_MAX];
+ char tmp[PATH_MAX];
+ char cvsadm[PATH_MAX];
+ char *cp;
+
+ if (update_dir && *update_dir)
+ xupdate_dir = update_dir;
+ else
+ xupdate_dir = ".";
+
+ if (dir != NULL)
+ {
+ (void) sprintf (cvsadm, "%s/%s", dir, CVSADM);
+ (void) sprintf (tmp, "%s/%s", dir, CVSADM_ROOT);
+ }
+ else
+ {
+ (void) strcpy (cvsadm, CVSADM);
+ (void) strcpy (tmp, CVSADM_ROOT);
+ }
+
+ /*
+ * Do not bother looking for a readable file if there is no cvsadm
+ * directory present.
+ *
+ * It is possible that not all repositories will have a CVS/Root
+ * file. This is ok, but the user will need to specify -d
+ * /path/name or have the environment variable CVSROOT set in
+ * order to continue.
+ */
+ if ((!isdir (cvsadm)) || (!isreadable (tmp)))
+ {
+ if (CVSroot == NULL)
+ {
+ error (0, 0, "in directory %s:", xupdate_dir);
+ error (0, 0, "must set the CVSROOT environment variable");
+ error (0, 0, "or specify the '-d' option to %s.", program_name);
+ }
+ return (NULL);
+ }
+
+ /*
+ * The assumption here is that the CVS Root is always contained in the
+ * first line of the "Root" file.
+ */
+ fpin = open_file (tmp, "r");
+
+ if (fgets (root, PATH_MAX, fpin) == NULL)
+ {
+ error (0, 0, "in directory %s:", xupdate_dir);
+ error (0, errno, "cannot read %s", CVSADM_ROOT);
+ error (0, 0, "please correct this problem");
+ return (NULL);
+ }
+ (void) fclose (fpin);
+ if ((cp = strrchr (root, '\n')) != NULL)
+ *cp = '\0'; /* strip the newline */
+
+ /*
+ * root now contains a candidate for CVSroot. It must be an
+ * absolute pathname
+ */
+
+#ifdef CLIENT_SUPPORT
+ /* It must specify a server via remote CVS or be an absolute pathname. */
+ if ((strchr (root, ':') == NULL)
+ && ! isabsolute (root))
+#else
+ if (root[0] != '/')
+#endif
+ {
+ error (0, 0, "in directory %s:", xupdate_dir);
+ error (0, 0,
+ "ignoring %s because it does not contain an absolute pathname.",
+ CVSADM_ROOT);
+ return (NULL);
+ }
+
+#ifdef CLIENT_SUPPORT
+ if ((strchr (root, ':') == NULL) && !isdir (root))
+#else
+ if (!isdir (root))
+#endif
+ {
+ error (0, 0, "in directory %s:", xupdate_dir);
+ error (0, 0,
+ "ignoring %s because it specifies a non-existent repository %s",
+ CVSADM_ROOT, root);
+ return (NULL);
+ }
+
+ /* allocate space to return and fill it in */
+ strip_path (root);
+ ret = xstrdup (root);
+ return (ret);
+}
+
+/*
+ * Returns non-zero if the two directories have the same stat values
+ * which indicates that they are really the same directories.
+ */
+int
+same_directories (dir1, dir2)
+ char *dir1;
+ char *dir2;
+{
+ struct stat sb1;
+ struct stat sb2;
+ int ret;
+
+ if (stat (dir1, &sb1) < 0)
+ return (0);
+ if (stat (dir2, &sb2) < 0)
+ return (0);
+
+ ret = 0;
+ if ( (memcmp( &sb1.st_dev, &sb2.st_dev, sizeof(dev_t) ) == 0) &&
+ (memcmp( &sb1.st_ino, &sb2.st_ino, sizeof(ino_t) ) == 0))
+ ret = 1;
+
+ return (ret);
+}
+
+
+/*
+ * Write the CVS/Root file so that the environment variable CVSROOT
+ * and/or the -d option to cvs will be validated or not necessary for
+ * future work.
+ */
+void
+Create_Root (dir, rootdir)
+ char *dir;
+ char *rootdir;
+{
+ FILE *fout;
+ char tmp[PATH_MAX];
+
+ if (noexec)
+ return;
+
+ /* record the current cvs root */
+
+ if (rootdir != NULL)
+ {
+ if (dir != NULL)
+ (void) sprintf (tmp, "%s/%s", dir, CVSADM_ROOT);
+ else
+ (void) strcpy (tmp, CVSADM_ROOT);
+ fout = open_file (tmp, "w+");
+ if (fprintf (fout, "%s\n", rootdir) < 0)
+ error (1, errno, "write to %s failed", tmp);
+ if (fclose (fout) == EOF)
+ error (1, errno, "cannot close %s", tmp);
+ }
+}
diff --git a/gnu/usr.bin/cvs/cvs/rtag.c b/gnu/usr.bin/cvs/cvs/rtag.c
new file mode 100644
index 0000000..76e1776
--- /dev/null
+++ b/gnu/usr.bin/cvs/cvs/rtag.c
@@ -0,0 +1,692 @@
+/*
+ * Copyright (c) 1992, Brian Berliner and Jeff Polk
+ * Copyright (c) 1989-1992, Brian Berliner
+ *
+ * You may distribute under the terms of the GNU General Public License as
+ * specified in the README file that comes with the CVS 1.4 kit.
+ *
+ * Rtag
+ *
+ * Add or delete a symbolic name to an RCS file, or a collection of RCS files.
+ * Uses the modules database, if necessary.
+ */
+
+#include "cvs.h"
+
+#ifndef lint
+static const char rcsid[] = "$CVSid: @(#)rtag.c 1.61 94/09/30 $";
+USE(rcsid);
+#endif
+
+static int check_fileproc PROTO((char *file, char *update_dir,
+ char *repository, List * entries,
+ List * srcfiles));
+static int check_filesdoneproc PROTO((int err, char *repos, char *update_dir));
+static int pretag_proc PROTO((char *repository, char *filter));
+static void masterlist_delproc PROTO((Node *p));
+static void tag_delproc PROTO((Node *p));
+static int pretag_list_proc PROTO((Node *p, void *closure));
+
+static Dtype rtag_dirproc PROTO((char *dir, char *repos, char *update_dir));
+static int rtag_fileproc PROTO((char *file, char *update_dir,
+ char *repository, List * entries,
+ List * srcfiles));
+static int rtag_proc PROTO((int *pargc, char **argv, char *xwhere,
+ char *mwhere, char *mfile, int shorten,
+ int local_specified, char *mname, char *msg));
+static int rtag_delete PROTO((RCSNode *rcsfile));
+
+
+struct tag_info
+{
+ Ctype status;
+ char *rev;
+ char *tag;
+ char *options;
+};
+
+struct master_lists
+{
+ List *tlist;
+};
+
+static List *mtlist;
+static List *tlist;
+
+static char *symtag;
+static char *numtag;
+static int delete; /* adding a tag by default */
+static int attic_too; /* remove tag from Attic files */
+static int branch_mode; /* make an automagic "branch" tag */
+static char *date;
+static int local; /* recursive by default */
+static int force_tag_match = 1; /* force by default */
+static int force_tag_move; /* don't move existing tags by default */
+
+static const char *const rtag_usage[] =
+{
+ "Usage: %s %s [-aflRnF] [-b] [-d] [-r tag|-D date] tag modules...\n",
+ "\t-a\tClear tag from removed files that would not otherwise be tagged.\n",
+ "\t-f\tForce a head revision match if tag/date not found.\n",
+ "\t-l\tLocal directory only, not recursive\n",
+ "\t-R\tProcess directories recursively.\n",
+ "\t-n\tNo execution of 'tag program'\n",
+ "\t-d\tDelete the given Tag.\n",
+ "\t-b\tMake the tag a \"branch\" tag, allowing concurrent development.\n",
+ "\t-[rD]\tExisting tag or Date.\n",
+ "\t-F\tMove tag if it already exists\n",
+ NULL
+};
+
+int
+rtag (argc, argv)
+ int argc;
+ char **argv;
+{
+ register int i;
+ int c;
+ DBM *db;
+ int run_module_prog = 1;
+ int err = 0;
+
+ if (argc == -1)
+ usage (rtag_usage);
+
+ optind = 1;
+ while ((c = getopt (argc, argv, "FanfQqlRdbr:D:")) != -1)
+ {
+ switch (c)
+ {
+ case 'a':
+ attic_too = 1;
+ break;
+ case 'n':
+ run_module_prog = 0;
+ break;
+ case 'Q':
+ case 'q':
+#ifdef SERVER_SUPPORT
+ /* The CVS 1.5 client sends these options (in addition to
+ Global_option requests), so we must ignore them. */
+ if (!server_active)
+#endif
+ error (1, 0,
+ "-q or -Q must be specified before \"%s\"",
+ command_name);
+ break;
+ case 'l':
+ local = 1;
+ break;
+ case 'R':
+ local = 0;
+ break;
+ case 'd':
+ delete = 1;
+ break;
+ case 'f':
+ force_tag_match = 0;
+ break;
+ case 'b':
+ branch_mode = 1;
+ break;
+ case 'r':
+ numtag = optarg;
+ break;
+ case 'D':
+ if (date)
+ free (date);
+ date = Make_Date (optarg);
+ break;
+ case 'F':
+ force_tag_move = 1;
+ break;
+ case '?':
+ default:
+ usage (rtag_usage);
+ break;
+ }
+ }
+ argc -= optind;
+ argv += optind;
+ if (argc < 2)
+ usage (rtag_usage);
+ symtag = argv[0];
+ argc--;
+ argv++;
+
+ if (date && numtag)
+ error (1, 0, "-r and -D options are mutually exclusive");
+ if (delete && branch_mode)
+ error (0, 0, "warning: -b ignored with -d options");
+ RCS_check_tag (symtag);
+
+#ifdef CLIENT_SUPPORT
+ if (client_active)
+ {
+ /* We're the client side. Fire up the remote server. */
+ start_server ();
+
+ ign_setup ();
+
+ if (local)
+ send_arg("-l");
+ if (delete)
+ send_arg("-d");
+ if (branch_mode)
+ send_arg("-b");
+ if (force_tag_move)
+ send_arg("-F");
+ if (run_module_prog)
+ send_arg("-n");
+ if (attic_too)
+ send_arg("-a");
+
+ if (numtag)
+ option_with_arg ("-r", numtag);
+ if (date)
+ client_senddate (date);
+
+ send_arg (symtag);
+
+ {
+ int i;
+ for (i = 0; i < argc; ++i)
+ send_arg (argv[i]);
+ }
+
+ if (fprintf (to_server, "rtag\n") < 0)
+ error (1, errno, "writing to server");
+ return get_responses_and_close ();
+ }
+#endif
+
+ db = open_module ();
+ for (i = 0; i < argc; i++)
+ {
+ /* XXX last arg should be repository, but doesn't make sense here */
+ history_write ('T', (delete ? "D" : (numtag ? numtag :
+ (date ? date : "A"))), symtag, argv[i], "");
+ err += do_module (db, argv[i], TAG, delete ? "Untagging" : "Tagging",
+ rtag_proc, (char *) NULL, 0, 0, run_module_prog,
+ symtag);
+ }
+ close_module (db);
+ return (err);
+}
+
+/*
+ * callback proc for doing the real work of tagging
+ */
+/* ARGSUSED */
+static int
+rtag_proc (pargc, argv, xwhere, mwhere, mfile, shorten, local_specified,
+ mname, msg)
+ int *pargc;
+ char **argv;
+ char *xwhere;
+ char *mwhere;
+ char *mfile;
+ int shorten;
+ int local_specified;
+ char *mname;
+ char *msg;
+{
+ int err = 0;
+ int which;
+ char repository[PATH_MAX];
+ char where[PATH_MAX];
+
+ (void) sprintf (repository, "%s/%s", CVSroot, argv[0]);
+ (void) strcpy (where, argv[0]);
+
+ /* if mfile isn't null, we need to set up to do only part of the module */
+ if (mfile != NULL)
+ {
+ char *cp;
+ char path[PATH_MAX];
+
+ /* if the portion of the module is a path, put the dir part on repos */
+ if ((cp = strrchr (mfile, '/')) != NULL)
+ {
+ *cp = '\0';
+ (void) strcat (repository, "/");
+ (void) strcat (repository, mfile);
+ (void) strcat (where, "/");
+ (void) strcat (where, mfile);
+ mfile = cp + 1;
+ }
+
+ /* take care of the rest */
+ (void) sprintf (path, "%s/%s", repository, mfile);
+ if (isdir (path))
+ {
+ /* directory means repository gets the dir tacked on */
+ (void) strcpy (repository, path);
+ (void) strcat (where, "/");
+ (void) strcat (where, mfile);
+ }
+ else
+ {
+ int i;
+
+ /* a file means muck argv */
+ for (i = 1; i < *pargc; i++)
+ free (argv[i]);
+ argv[1] = xstrdup (mfile);
+ (*pargc) = 2;
+ }
+ }
+
+ /* chdir to the starting directory */
+ if (chdir (repository) < 0)
+ {
+ error (0, errno, "cannot chdir to %s", repository);
+ return (1);
+ }
+
+ if (delete || attic_too || (force_tag_match && numtag))
+ which = W_REPOS | W_ATTIC;
+ else
+ which = W_REPOS;
+
+ /* check to make sure they are authorized to tag all the
+ specified files in the repository */
+
+ mtlist = getlist();
+ err = start_recursion (check_fileproc, check_filesdoneproc,
+ (DIRENTPROC) NULL, (DIRLEAVEPROC) NULL,
+ *pargc - 1, argv + 1, local, which, 0, 1,
+ where, 1, 1);
+
+ if (err)
+ {
+ error (1, 0, "correct the above errors first!");
+ }
+
+ /* start the recursion processor */
+ err = start_recursion (rtag_fileproc, (FILESDONEPROC) NULL, rtag_dirproc,
+ (DIRLEAVEPROC) NULL, *pargc - 1, argv + 1, local,
+ which, 0, 1, where, 1, 1);
+
+ dellist(&mtlist);
+
+ return (err);
+}
+
+/* check file that is to be tagged */
+/* All we do here is add it to our list */
+
+static int
+check_fileproc(file, update_dir, repository, entries, srcfiles)
+ char *file;
+ char *update_dir;
+ char *repository;
+ List * entries;
+ List * srcfiles;
+{
+ char *xdir;
+ Node *p;
+ Vers_TS *vers;
+
+ if (update_dir[0] == '\0')
+ xdir = ".";
+ else
+ xdir = update_dir;
+ if ((p = findnode (mtlist, xdir)) != NULL)
+ {
+ tlist = ((struct master_lists *) p->data)->tlist;
+ }
+ else
+ {
+ struct master_lists *ml;
+
+ tlist = getlist ();
+ p = getnode ();
+ p->key = xstrdup (xdir);
+ p->type = UPDATE;
+ ml = (struct master_lists *)
+ xmalloc (sizeof (struct master_lists));
+ ml->tlist = tlist;
+ p->data = (char *) ml;
+ p->delproc = masterlist_delproc;
+ (void) addnode (mtlist, p);
+ }
+ /* do tlist */
+ p = getnode ();
+ p->key = xstrdup (file);
+ p->type = UPDATE;
+ p->delproc = tag_delproc;
+ vers = Version_TS (repository, (char *) NULL, (char *) NULL,
+ (char *) NULL, file, 0, 0, entries, srcfiles);
+ p->data = RCS_getversion(vers->srcfile, numtag, date, force_tag_match, 0);
+ if (p->data != NULL)
+ {
+ int addit = 1;
+ char *oversion;
+
+ oversion = RCS_getversion (vers->srcfile, symtag, (char *) NULL, 1, 0);
+ if (oversion == NULL)
+ {
+ if (delete)
+ {
+ addit = 0;
+ }
+ }
+ else if (strcmp(oversion, p->data) == 0)
+ {
+ addit = 0;
+ }
+ else if (!force_tag_move)
+ {
+ addit = 0;
+ }
+ if (oversion != NULL)
+ {
+ free(oversion);
+ }
+ if (!addit)
+ {
+ free(p->data);
+ p->data = NULL;
+ }
+ }
+ freevers_ts (&vers);
+ (void) addnode (tlist, p);
+ return (0);
+}
+
+static int
+check_filesdoneproc(err, repos, update_dir)
+ int err;
+ char *repos;
+ char *update_dir;
+{
+ int n;
+ Node *p;
+
+ p = findnode(mtlist, update_dir);
+ if (p != NULL)
+ {
+ tlist = ((struct master_lists *) p->data)->tlist;
+ }
+ else
+ {
+ tlist = (List *) NULL;
+ }
+ if ((tlist == NULL) || (tlist->list->next == tlist->list))
+ {
+ return (err);
+ }
+ if ((n = Parse_Info(CVSROOTADM_TAGINFO, repos, pretag_proc, 1)) > 0)
+ {
+ error (0, 0, "Pre-tag check failed");
+ err += n;
+ }
+ return (err);
+}
+
+static int
+pretag_proc(repository, filter)
+ char *repository;
+ char *filter;
+{
+ if (filter[0] == '/')
+ {
+ char *s, *cp;
+
+ s = xstrdup(filter);
+ for (cp=s; *cp; cp++)
+ {
+ if (isspace(*cp))
+ {
+ *cp = '\0';
+ break;
+ }
+ }
+ if (!isfile(s))
+ {
+ error (0, errno, "cannot find pre-tag filter '%s'", s);
+ free(s);
+ return (1);
+ }
+ free(s);
+ }
+ run_setup("%s %s %s %s",
+ filter,
+ symtag,
+ delete ? "del" : force_tag_move ? "mov" : "add",
+ repository);
+ walklist(tlist, pretag_list_proc, NULL);
+ return (run_exec(RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL|RUN_REALLY));
+}
+
+static void
+masterlist_delproc(p)
+ Node *p;
+{
+ struct master_lists *ml;
+
+ ml = (struct master_lists *)p->data;
+ dellist(&ml->tlist);
+ free(ml);
+ return;
+}
+
+static void
+tag_delproc(p)
+ Node *p;
+{
+ if (p->data != NULL)
+ {
+ free(p->data);
+ p->data = NULL;
+ }
+ return;
+}
+
+static int
+pretag_list_proc(p, closure)
+ Node *p;
+ void *closure;
+{
+ if (p->data != NULL)
+ {
+ run_arg(p->key);
+ run_arg(p->data);
+ }
+ return (0);
+}
+
+/*
+ * Called to tag a particular file, as appropriate with the options that were
+ * set above.
+ */
+/* ARGSUSED */
+static int
+rtag_fileproc (file, update_dir, repository, entries, srcfiles)
+ char *file;
+ char *update_dir;
+ char *repository;
+ List *entries;
+ List *srcfiles;
+{
+ Node *p;
+ RCSNode *rcsfile;
+ char *version, *rev;
+ int retcode = 0;
+
+ /* find the parsed RCS data */
+ p = findnode (srcfiles, file);
+ if (p == NULL)
+ return (1);
+ rcsfile = (RCSNode *) p->data;
+
+ /*
+ * For tagging an RCS file which is a symbolic link, you'd best be
+ * running with RCS 5.6, since it knows how to handle symbolic links
+ * correctly without breaking your link!
+ */
+
+ if (delete)
+ return (rtag_delete (rcsfile));
+
+ /*
+ * If we get here, we are adding a tag. But, if -a was specified, we
+ * need to check to see if a -r or -D option was specified. If neither
+ * was specified and the file is in the Attic, remove the tag.
+ */
+ if (attic_too && (!numtag && !date))
+ {
+ if ((rcsfile->flags & VALID) && (rcsfile->flags & INATTIC))
+ return (rtag_delete (rcsfile));
+ }
+
+ version = RCS_getversion (rcsfile, numtag, date, force_tag_match, 0);
+ if (version == NULL)
+ {
+ /* If -a specified, clean up any old tags */
+ if (attic_too)
+ (void) rtag_delete (rcsfile);
+
+ if (!quiet && !force_tag_match)
+ {
+ error (0, 0, "cannot find tag `%s' in `%s'",
+ numtag ? numtag : "head", rcsfile->path);
+ return (1);
+ }
+ return (0);
+ }
+ if (numtag && isdigit (*numtag) && strcmp (numtag, version) != 0)
+ {
+
+ /*
+ * We didn't find a match for the numeric tag that was specified, but
+ * that's OK. just pass the numeric tag on to rcs, to be tagged as
+ * specified. Could get here if one tried to tag "1.1.1" and there
+ * was a 1.1.1 branch with some head revision. In this case, we want
+ * the tag to reference "1.1.1" and not the revision at the head of
+ * the branch. Use a symbolic tag for that.
+ */
+ rev = branch_mode ? RCS_magicrev (rcsfile, version) : numtag;
+ retcode = RCS_settag(rcsfile->path, symtag, numtag);
+ }
+ else
+ {
+ char *oversion;
+
+ /*
+ * As an enhancement for the case where a tag is being re-applied to
+ * a large body of a module, make one extra call to Version_Number to
+ * see if the tag is already set in the RCS file. If so, check to
+ * see if it needs to be moved. If not, do nothing. This will
+ * likely save a lot of time when simply moving the tag to the
+ * "current" head revisions of a module -- which I have found to be a
+ * typical tagging operation.
+ */
+ rev = branch_mode ? RCS_magicrev (rcsfile, version) : version;
+ oversion = RCS_getversion (rcsfile, symtag, (char *) NULL, 1, 0);
+ if (oversion != NULL)
+ {
+ int isbranch = RCS_isbranch (file, symtag, srcfiles);
+
+ /*
+ * if versions the same and neither old or new are branches don't
+ * have to do anything
+ */
+ if (strcmp (version, oversion) == 0 && !branch_mode && !isbranch)
+ {
+ free (oversion);
+ free (version);
+ return (0);
+ }
+
+ if (!force_tag_move) { /* we're NOT going to move the tag */
+ if (update_dir[0])
+ (void) printf ("W %s/%s", update_dir, file);
+ else
+ (void) printf ("W %s", file);
+
+ (void) printf (" : %s already exists on %s %s",
+ symtag, isbranch ? "branch" : "version", oversion);
+ (void) printf (" : NOT MOVING tag to %s %s\n",
+ branch_mode ? "branch" : "version", rev);
+ free (oversion);
+ free (version);
+ return (0);
+ }
+ free (oversion);
+ }
+ retcode = RCS_settag(rcsfile->path, symtag, rev);
+ }
+
+ if (retcode != 0)
+ {
+ error (1, retcode == -1 ? errno : 0,
+ "failed to set tag `%s' to revision `%s' in `%s'",
+ symtag, rev, rcsfile->path);
+ free (version);
+ return (1);
+ }
+ free (version);
+ return (0);
+}
+
+/*
+ * If -d is specified, "force_tag_match" is set, so that this call to
+ * Version_Number() will return a NULL version string if the symbolic
+ * tag does not exist in the RCS file.
+ *
+ * If the -r flag was used, numtag is set, and we only delete the
+ * symtag from files that have numtag.
+ *
+ * This is done here because it's MUCH faster than just blindly calling
+ * "rcs" to remove the tag... trust me.
+ */
+static int
+rtag_delete (rcsfile)
+ RCSNode *rcsfile;
+{
+ char *version;
+ int retcode;
+
+ if (numtag)
+ {
+ version = RCS_getversion (rcsfile, numtag, (char *) NULL, 1, 0);
+ if (version == NULL)
+ return (0);
+ free (version);
+ }
+
+ version = RCS_getversion (rcsfile, symtag, (char *) NULL, 1, 0);
+ if (version == NULL)
+ return (0);
+ free (version);
+
+ if ((retcode = RCS_deltag(rcsfile->path, symtag, 1)) != 0)
+ {
+ if (!quiet)
+ error (0, retcode == -1 ? errno : 0,
+ "failed to remove tag `%s' from `%s'", symtag,
+ rcsfile->path);
+ return (1);
+ }
+ return (0);
+}
+
+/*
+ * Print a warm fuzzy message
+ */
+/* ARGSUSED */
+static Dtype
+rtag_dirproc (dir, repos, update_dir)
+ char *dir;
+ char *repos;
+ char *update_dir;
+{
+ if (!quiet)
+ error (0, 0, "%s %s", delete ? "Untagging" : "Tagging", update_dir);
+ return (R_PROCESS);
+}
+
+
+
diff --git a/gnu/usr.bin/cvs/cvs/sanity.sh b/gnu/usr.bin/cvs/cvs/sanity.sh
new file mode 100644
index 0000000..21aa454
--- /dev/null
+++ b/gnu/usr.bin/cvs/cvs/sanity.sh
@@ -0,0 +1,1674 @@
+#! /bin/sh
+:
+# sanity.sh -- a growing sanity test for cvs.
+#
+#ident "$CVSid$"
+#
+# Copyright (C) 1992, 1993 Cygnus Support
+#
+# Original Author: K. Richard Pixley
+
+# usage: sanity.sh [-r] @var{cvs-to-test} @var{tests-to-run}
+# -r means to test remote instead of local cvs.
+# @var{tests-to-run} are the names of the tests to run; if omitted run all
+# tests.
+
+# See TODO list at end of file.
+
+# required to make this script work properly.
+unset CVSREAD
+
+TESTDIR=/tmp/cvs-sanity
+
+# "debugger"
+#set -x
+
+echo 'This test should produce no other output than this line, and a final "OK".'
+
+if test x"$1" = x"-r"; then
+ shift
+ remote=yes
+else
+ remote=no
+fi
+
+# Use full path for CVS executable, so that CVS_SERVER gets set properly
+# for remote.
+case $1 in
+/*)
+ testcvs=$1
+ ;;
+*)
+ testcvs=`pwd`/$1
+ ;;
+esac
+
+shift
+
+# Use full path for mkmodules, so that the right one will be invoked
+#
+testmkmodules=`pwd`/mkmodules
+
+# FIXME: try things (what things? checkins?) without -m.
+#
+# Some of these tests are written to expect -Q. But testing with
+# -Q is kind of bogus, it is not the way users actually use CVS (usually).
+# So new tests probably should invoke ${testcvs} directly, rather than ${CVS}.
+# and then they've obviously got to do something with the output....
+#
+CVS="${testcvs} -Q -f"
+
+LOGFILE=`pwd`/check.log
+
+# Save the previous log in case the person running the tests decides
+# they want to look at it. The extension ".plog" is chosen for consistency
+# with dejagnu.
+if test -f check.log; then
+ mv check.log check.plog
+fi
+
+# clean any old remnants
+rm -rf ${TESTDIR}
+mkdir ${TESTDIR}
+cd ${TESTDIR}
+
+# Remaining arguments are the names of tests to run.
+#
+# FIXME: not all combinations are possible; basic3 depends on files set up
+# by previous tests, for example. This should be changed.
+# The goal is that tests can be run in manageably-sized chunks, so
+# that one can quickly get a result from a cvs or testsuite change,
+# and to facilitate understanding the tests.
+
+if test x"$*" = x; then
+ tests="basic0 basic1 basic2 basic3 rtags death import new conflicts modules mflag errmsg1"
+else
+ tests="$*"
+fi
+
+# this should die
+if ${CVS} -d `pwd`/cvsroot co cvs-sanity 2>> ${LOGFILE} ; then
+ echo "FAIL: test 1" | tee -a ${LOGFILE}
+ exit 1
+else
+ echo "PASS: test 1" >>${LOGFILE}
+fi
+
+# this should still die
+mkdir cvsroot
+if ${CVS} -d `pwd`/cvsroot co cvs-sanity 2>> ${LOGFILE} ; then
+ echo "FAIL: test 2" | tee -a ${LOGFILE}
+ exit 1
+else
+ echo "PASS: test 2" >>${LOGFILE}
+fi
+
+# this should still die
+mkdir cvsroot/CVSROOT
+if ${CVS} -d `pwd`/cvsroot co cvs-sanity 2>> ${LOGFILE} ; then
+ echo "FAIL: test 3" | tee -a ${LOGFILE}
+ exit 1
+else
+ echo "PASS: test 3" >>${LOGFILE}
+fi
+
+# This one should work, although it should spit a warning.
+mkdir tmp ; cd tmp
+${CVS} -d `pwd`/../cvsroot co CVSROOT 2>> ${LOGFILE}
+cd .. ; rm -rf tmp
+
+# set up a minimal modules file...
+echo "CVSROOT -i ${testmkmodules} CVSROOT" > cvsroot/CVSROOT/modules
+
+# This one should succeed. No warnings.
+mkdir tmp ; cd tmp
+if ${CVS} -d `pwd`/../cvsroot co CVSROOT ; then
+ echo "PASS: test 4" >>${LOGFILE}
+else
+ echo "FAIL: test 4" | tee -a ${LOGFILE}
+ exit 1
+fi
+
+if echo "yes" | ${CVS} -d `pwd`/../cvsroot release -d CVSROOT ; then
+ echo "PASS: test 4.5" >>${LOGFILE}
+else
+ echo "FAIL: test 4.5" | tee -a ${LOGFILE}
+ exit 1
+fi
+# this had better be empty
+cd ..; rmdir tmp
+if [ -d tmp ] ; then
+ echo "FAIL: test 4.75" | tee -a ${LOGFILE}
+ exit 1
+fi
+
+# a simple function to compare directory contents
+#
+# BTW, I don't care any more -- if you don't have a /bin/sh that handles
+# shell functions, well get one.
+#
+# Returns: ISDIFF := true|false
+#
+directory_cmp ()
+{
+ OLDPWD=`pwd`
+ DIR_1=$1
+ DIR_2=$2
+ ISDIFF=false
+
+ cd $DIR_1
+ find . -print | fgrep -v /CVS | sort > /tmp/dc$$d1
+
+ # go back where we were to avoid symlink hell...
+ cd $OLDPWD
+ cd $DIR_2
+ find . -print | fgrep -v /CVS | sort > /tmp/dc$$d2
+
+ if diff /tmp/dc$$d1 /tmp/dc$$d2 >/dev/null 2>&1
+ then
+ :
+ else
+ ISDIFF=true
+ return
+ fi
+ cd $OLDPWD
+ while read a
+ do
+ if [ -f $DIR_1/"$a" ] ; then
+ cmp -s $DIR_1/"$a" $DIR_2/"$a"
+ if [ $? -ne 0 ] ; then
+ ISDIFF=true
+ fi
+ fi
+ done < /tmp/dc$$d1
+### FIXME:
+### rm -f /tmp/dc$$*
+}
+
+# so much for the setup. Let's try something harder.
+
+# Try setting CVSROOT so we don't have to worry about it anymore. (now that
+# we've tested -d cvsroot.)
+CVSROOT_DIRNAME=${TESTDIR}/cvsroot
+CVSROOT=${CVSROOT_DIRNAME} ; export CVSROOT
+if test "x$remote" = xyes; then
+ CVSROOT=`hostname`:${CVSROOT_DIRNAME} ; export CVSROOT
+ # Use rsh so we can test it without having to muck with inetd or anything
+ # like that. Also needed to get CVS_SERVER to work.
+ CVS_CLIENT_PORT=-1; export CVS_CLIENT_PORT
+ CVS_SERVER=${testcvs}; export CVS_SERVER
+fi
+
+mkdir tmp ; cd tmp
+if ${CVS} co CVSROOT ; then
+ if [ -r CVSROOT/CVS/Entries ] ; then
+ echo "PASS: test 5" >>${LOGFILE}
+ else
+ echo "FAIL: test 5" | tee -a ${LOGFILE}
+ exit 1
+ fi
+else
+ echo "FAIL: test 5" | tee -a ${LOGFILE}; exit 1
+fi
+
+if echo "yes" | ${CVS} release -d CVSROOT ; then
+ echo "PASS: test 5.5" >>${LOGFILE}
+else
+ echo "FAIL: test 5.5" | tee -a ${LOGFILE}
+ exit 1
+fi
+# this had better etmpy now...
+cd ..; rmdir tmp
+if [ -d tmp ] ; then
+ echo "FAIL: test 5.75" | tee -a ${LOGFILE}
+ exit 1
+fi
+
+# start keeping history
+touch ${CVSROOT_DIRNAME}/CVSROOT/history
+
+### The big loop
+for what in $tests; do
+ case $what in
+ basic0) # Now, let's build something.
+# mkdir first-dir
+ # this doesn't yet work, though I think maybe it should. xoxorich.
+# if ${CVS} add first-dir ; then
+# true
+# else
+# echo cvs does not yet add top level directories cleanly.
+ mkdir ${CVSROOT_DIRNAME}/first-dir
+# fi
+# rm -rf first-dir
+
+ # check out an empty directory
+ if ${CVS} co first-dir ; then
+ if [ -r first-dir/CVS/Entries ] ; then
+ echo "PASS: test 6" >>${LOGFILE}
+ else
+ echo "FAIL: test 6" | tee -a ${LOGFILE}; exit 1
+ fi
+ else
+ echo "FAIL: test 6" | tee -a ${LOGFILE}; exit 1
+ fi
+
+ # update the empty directory
+ if ${CVS} update first-dir ; then
+ echo "PASS: test 7" >>${LOGFILE}
+ else
+ echo "FAIL: test 7" | tee -a ${LOGFILE}; exit 1
+ fi
+
+ # diff -u the empty directory
+ if ${CVS} diff -u first-dir ; then
+ echo "PASS: test 8" >>${LOGFILE}
+ else
+ echo "FAIL: test 8" | tee -a ${LOGFILE}; exit 1
+ fi
+
+ # diff -c the empty directory
+ if ${CVS} diff -c first-dir ; then
+ echo "PASS: test 9" >>${LOGFILE}
+ else
+ echo "FAIL: test 9" | tee -a ${LOGFILE}; exit 1
+ fi
+
+ # log the empty directory
+ if ${CVS} log first-dir ; then
+ echo "PASS: test 10" >>${LOGFILE}
+ else
+ echo "FAIL: test 10" | tee -a ${LOGFILE}; exit 1
+ fi
+
+ # status the empty directory
+ if ${CVS} status first-dir ; then
+ echo "PASS: test 11" >>${LOGFILE}
+ else
+ echo "FAIL: test 11" | tee -a ${LOGFILE}; exit 1
+ fi
+
+ # tag the empty directory
+ if ${CVS} tag first first-dir ; then
+ echo "PASS: test 12" >>${LOGFILE}
+ else
+ echo "FAIL: test 12" | tee -a ${LOGFILE}; exit 1
+ fi
+
+ # rtag the empty directory
+ if ${CVS} rtag empty first-dir ; then
+ echo "PASS: test 13" >>${LOGFILE}
+ else
+ echo "FAIL: test 13" | tee -a ${LOGFILE}; exit 1
+ fi
+ ;;
+
+ basic1) # first dive - add a files, first singly, then in a group.
+ rm -rf ${CVSROOT_DIRNAME}/first-dir
+ rm -rf first-dir
+ mkdir ${CVSROOT_DIRNAME}/first-dir
+ # check out an empty directory
+ if ${CVS} co first-dir ; then
+ echo "PASS: test 13a" >>${LOGFILE}
+ else
+ echo "FAIL: test 13a" | tee -a ${LOGFILE}; exit 1
+ fi
+
+ cd first-dir
+ files=first-file
+ for i in a b ; do
+ for j in ${files} ; do
+ echo $j > $j
+ done
+
+ for do in add rm ; do
+ for j in ${do} "commit -m test" ; do
+ # ${do}
+ if ${CVS} $j ${files} >> ${LOGFILE} 2>&1; then
+ echo "PASS: test 14-${do}-$j" >>${LOGFILE}
+ else
+ echo "FAIL: test 14-${do}-$j" | tee -a ${LOGFILE}; exit 1
+ fi
+
+ # update it.
+ if [ "${do}" = "rm" -a "$j" != "commit -m test" ] || ${CVS} update ${files} ; then
+ echo "PASS: test 15-${do}-$j" >>${LOGFILE}
+ else
+ echo "FAIL: test 15-${do}-$j" | tee -a ${LOGFILE}; exit 1
+ fi
+
+ # update all.
+ if ${CVS} update ; then
+ echo "PASS: test 16-${do}-$j" >>${LOGFILE}
+ else
+ echo "FAIL: test 16-${do}-$j" | tee -a ${LOGFILE}; exit 1
+ fi
+
+ # status all.
+ if ${CVS} status >> ${LOGFILE}; then
+ echo "PASS: test 17-${do}-$j" >>${LOGFILE}
+ else
+ echo "FAIL: test 17-${do}-$j" | tee -a ${LOGFILE}; exit 1
+ fi
+
+ # FIXME: this one doesn't work yet for added files.
+ # log all.
+ if ${CVS} log >> ${LOGFILE}; then
+ echo "PASS: test 18-${do}-$j" >>${LOGFILE}
+ else
+ echo "FAIL: test 18-${do}-$j" | tee -a ${LOGFILE}
+ fi
+
+ if test "x${do}-$j" = "xadd-add" || test "x${do}-$j" = "xrm-rm" ; then
+ true
+ else
+ # diff -c all
+ if ${CVS} diff -c >> ${LOGFILE} || [ $? = 1 ] ; then
+ echo "PASS: test 19-${do}-$j" >>${LOGFILE}
+ else
+ echo "FAIL: test 19-${do}-$j" | tee -a ${LOGFILE}
+ fi
+
+ # diff -u all
+ if ${CVS} diff -u >> ${LOGFILE} || [ $? = 1 ] ; then
+ echo "PASS: test 20-${do}-$j" >>${LOGFILE}
+ else
+ echo "FAIL: test 20-${do}-$j" | tee -a ${LOGFILE}
+ fi
+ fi
+
+ cd ..
+ # update all.
+ if ${CVS} update ; then
+ echo "PASS: test 21-${do}-$j" >>${LOGFILE}
+ else
+ echo "FAIL: test 21-${do}-$j" | tee -a ${LOGFILE}; exit 1
+ fi
+
+ # log all.
+ # FIXME: doesn't work right for added files.
+ if ${CVS} log first-dir >> ${LOGFILE}; then
+ echo "PASS: test 22-${do}-$j" >>${LOGFILE}
+ else
+ echo "FAIL: test 22-${do}-$j" | tee -a ${LOGFILE}
+ fi
+
+ # status all.
+ if ${CVS} status first-dir >> ${LOGFILE}; then
+ echo "PASS: test 23-${do}-$j" >>${LOGFILE}
+ else
+ echo "FAIL: test 23-${do}-$j" | tee -a ${LOGFILE}; exit 1
+ fi
+
+ # update all.
+ if ${CVS} update first-dir ; then
+ echo "PASS: test 24-${do}-$j" >>${LOGFILE}
+ else
+ echo "FAIL: test 24-${do}-$j" | tee -a ${LOGFILE} ; exit 1
+ fi
+
+ if test "x${do}-$j" = "xadd-add" || test "x${do}-$j" = "xrm-rm" ; then
+ echo "PASS: test 25-${do}-$j" >>${LOGFILE}
+ else
+ # diff all
+ if ${CVS} diff -u >> ${LOGFILE} || [ $? = 1 ] ; then
+ echo "PASS: test 25-${do}-$j" >>${LOGFILE}
+ else
+ echo "FAIL: test 25-${do}-$j" | tee -a ${LOGFILE}
+ # FIXME; exit 1
+ fi
+
+ # diff all
+ if ${CVS} diff -u first-dir >> ${LOGFILE} || [ $? = 1 ] ; then
+ echo "PASS: test 26-${do}-$j" >>${LOGFILE}
+ else
+ echo "FAIL: test 26-${do}-$j" | tee -a ${LOGFILE}
+ # FIXME; exit 1
+ fi
+ fi
+
+ # update all.
+ if ${CVS} co first-dir ; then
+ echo "PASS: test 27-${do}-$j" >>${LOGFILE}
+ else
+ echo "FAIL: test 27-${do}-$j" | tee -a ${LOGFILE} ; exit 1
+ fi
+
+ cd first-dir
+ done # j
+ rm -f ${files}
+ done # do
+
+ files="file2 file3 file4 file5"
+ done
+ if ${CVS} tag first-dive ; then
+ echo "PASS: test 28" >>${LOGFILE}
+ else
+ echo "FAIL: test 28" | tee -a ${LOGFILE} ; exit 1
+ fi
+ cd ..
+ ;;
+
+ basic2) # second dive - add bunch o' files in bunch o' added directories
+ for i in first-dir dir1 dir2 dir3 dir4 ; do
+ if [ ! -d $i ] ; then
+ mkdir $i
+ if ${CVS} add $i >> ${LOGFILE}; then
+ echo "PASS: test 29-$i" >>${LOGFILE}
+ else
+ echo "FAIL: test 29-$i" | tee -a ${LOGFILE} ; exit 1
+ fi
+ fi
+
+ cd $i
+
+ for j in file6 file7 file8 file9 file10 file11 file12 file13; do
+ echo $j > $j
+ done
+
+ if ${CVS} add file6 file7 file8 file9 file10 file11 file12 file13 2>> ${LOGFILE}; then
+ echo "PASS: test 30-$i-$j" >>${LOGFILE}
+ else
+ echo "FAIL: test 30-$i-$j" | tee -a ${LOGFILE} ; exit 1
+ fi
+ done
+ cd ../../../../..
+ if ${CVS} update first-dir ; then
+ echo "PASS: test 31" >>${LOGFILE}
+ else
+ echo "FAIL: test 31" | tee -a ${LOGFILE} ; exit 1
+ fi
+
+ # fixme: doesn't work right for added files.
+ if ${CVS} log first-dir >> ${LOGFILE}; then
+ echo "PASS: test 32" >>${LOGFILE}
+ else
+ echo "FAIL: test 32" | tee -a ${LOGFILE} # ; exit 1
+ fi
+
+ if ${CVS} status first-dir >> ${LOGFILE}; then
+ echo "PASS: test 33" >>${LOGFILE}
+ else
+ echo "FAIL: test 33" | tee -a ${LOGFILE} ; exit 1
+ fi
+
+# if ${CVS} diff -u first-dir >> ${LOGFILE} || [ $? = 1 ] ; then
+# echo "PASS: test 34" >>${LOGFILE}
+# else
+# echo "FAIL: test 34" | tee -a ${LOGFILE} # ; exit 1
+# fi
+
+ if ${CVS} ci -m "second dive" first-dir >> ${LOGFILE} 2>&1; then
+ echo "PASS: test 35" >>${LOGFILE}
+ else
+ echo "FAIL: test 35" | tee -a ${LOGFILE} ; exit 1
+ fi
+
+ if ${CVS} tag second-dive first-dir ; then
+ echo "PASS: test 36" >>${LOGFILE}
+ else
+ echo "FAIL: test 36" | tee -a ${LOGFILE} ; exit 1
+ fi
+ ;;
+
+ basic3) # third dive - in bunch o' directories, add bunch o' files, delete some, change some.
+ for i in first-dir dir1 dir2 dir3 dir4 ; do
+ cd $i
+
+ # modify some files
+ for j in file6 file8 file10 file12 ; do
+ echo $j >> $j
+ done
+
+ # delete some files
+ rm file7 file9 file11 file13
+
+ if ${CVS} rm file7 file9 file11 file13 2>> ${LOGFILE}; then
+ echo "PASS: test 37-$i" >>${LOGFILE}
+ else
+ echo "FAIL: test 37-$i" | tee -a ${LOGFILE} ; exit 1
+ fi
+
+ # and add some new ones
+ for j in file14 file15 file16 file17 ; do
+ echo $j > $j
+ done
+
+ if ${CVS} add file14 file15 file16 file17 2>> ${LOGFILE}; then
+ echo "PASS: test 38-$i" >>${LOGFILE}
+ else
+ echo "FAIL: test 38-$i" | tee -a ${LOGFILE} ; exit 1
+ fi
+ done
+ cd ../../../../..
+ if ${CVS} update first-dir ; then
+ echo "PASS: test 39" >>${LOGFILE}
+ else
+ echo "FAIL: test 39" | tee -a ${LOGFILE} ; exit 1
+ fi
+
+ # fixme: doesn't work right for added files
+ if ${CVS} log first-dir >> ${LOGFILE}; then
+ echo "PASS: test 40" >>${LOGFILE}
+ else
+ echo "FAIL: test 40" | tee -a ${LOGFILE} # ; exit 1
+ fi
+
+ if ${CVS} status first-dir >> ${LOGFILE}; then
+ echo "PASS: test 41" >>${LOGFILE}
+ else
+ echo "FAIL: test 41" | tee -a ${LOGFILE} ; exit 1
+ fi
+
+# if ${CVS} diff -u first-dir >> ${LOGFILE} || [ $? = 1 ] ; then
+# echo "PASS: test 42" >>${LOGFILE}
+# else
+# echo "FAIL: test 42" | tee -a ${LOGFILE} # ; exit 1
+# fi
+
+ if ${CVS} ci -m "third dive" first-dir >>${LOGFILE} 2>&1; then
+ echo "PASS: test 43" >>${LOGFILE}
+ else
+ echo "FAIL: test 43" | tee -a ${LOGFILE} ; exit 1
+ fi
+
+ if ${CVS} tag third-dive first-dir ; then
+ echo "PASS: test 44" >>${LOGFILE}
+ else
+ echo "FAIL: test 44" | tee -a ${LOGFILE} ; exit 1
+ fi
+
+ if echo "yes" | ${CVS} release -d first-dir ; then
+ echo "PASS: test 45" >>${LOGFILE}
+ else
+ echo "FAIL: test 45" | tee -a ${LOGFILE} ; exit 1
+ fi
+
+ # end of third dive
+ if [ -d test-dir ] ; then
+ echo "FAIL: test 45.5" | tee -a ${LOGFILE} ; exit 1
+ else
+ echo "PASS: test 45.5" >>${LOGFILE}
+ fi
+
+ ;;
+
+ rtags) # now try some rtags
+ # rtag HEADS
+ if ${CVS} rtag rtagged-by-head first-dir ; then
+ echo "PASS: test 46" >>${LOGFILE}
+ else
+ echo "FAIL: test 46" | tee -a ${LOGFILE} ; exit 1
+ fi
+
+ # tag by tag
+ if ${CVS} rtag -r rtagged-by-head rtagged-by-tag first-dir ; then
+ echo "PASS: test 47" >>${LOGFILE}
+ else
+ echo "FAIL: test 47" | tee -a ${LOGFILE} ; exit 1
+ fi
+
+ # tag by revision
+ if ${CVS} rtag -r1.1 rtagged-by-revision first-dir ; then
+ echo "PASS: test 48" >>${LOGFILE}
+ else
+ echo "FAIL: test 48" | tee -a ${LOGFILE} ; exit 1
+ fi
+
+ # rdiff by revision
+ if ${CVS} rdiff -r1.1 -rrtagged-by-head first-dir >> ${LOGFILE} || [ $? = 1 ] ; then
+ echo "PASS: test 49" >>${LOGFILE}
+ else
+ echo "FAIL: test 49" | tee -a ${LOGFILE} ; exit 1
+ fi
+
+ # now export by rtagged-by-head and rtagged-by-tag and compare.
+ rm -rf first-dir
+ if ${CVS} export -r rtagged-by-head first-dir ; then
+ echo "PASS: test 50" >>${LOGFILE}
+ else
+ echo "FAIL: test 50" | tee -a ${LOGFILE} ; exit 1
+ fi
+
+ mv first-dir 1dir
+ if ${CVS} export -r rtagged-by-tag first-dir ; then
+ echo "PASS: test 51" >>${LOGFILE}
+ else
+ echo "FAIL: test 51" | tee -a ${LOGFILE} ; exit 1
+ fi
+
+ directory_cmp 1dir first-dir
+
+ if $ISDIFF ; then
+ echo "FAIL: test 52" | tee -a ${LOGFILE} ; exit 1
+ else
+ echo "PASS: test 52" >>${LOGFILE}
+ fi
+ rm -rf 1dir first-dir
+
+ # checkout by revision vs export by rtagged-by-revision and compare.
+ if ${CVS} export -rrtagged-by-revision -d export-dir first-dir ; then
+ echo "PASS: test 53" >>${LOGFILE}
+ else
+ echo "FAIL: test 53" | tee -a ${LOGFILE} ; exit 1
+ fi
+
+ if ${CVS} co -r1.1 first-dir ; then
+ echo "PASS: test 54" >>${LOGFILE}
+ else
+ echo "FAIL: test 54" | tee -a ${LOGFILE} ; exit 1
+ fi
+
+ # directory copies are done in an oblique way in order to avoid a bug in sun's tmp filesystem.
+ mkdir first-dir.cpy ; (cd first-dir ; tar cf - * | (cd ../first-dir.cpy ; tar xf -))
+
+ directory_cmp first-dir export-dir
+
+ if $ISDIFF ; then
+ echo "FAIL: test 55" | tee -a ${LOGFILE} ; exit 1
+ else
+ echo "PASS: test 55" >>${LOGFILE}
+ fi
+
+ # interrupt, while we've got a clean 1.1 here, let's import it into another tree.
+ cd export-dir
+ if ${CVS} import -m "first-import" second-dir first-immigration immigration1 immigration1_0 ; then
+ echo "PASS: test 56" >>${LOGFILE}
+ else
+ echo "FAIL: test 56" | tee -a ${LOGFILE} ; exit 1
+ fi
+ cd ..
+
+ if ${CVS} export -r HEAD second-dir ; then
+ echo "PASS: test 57" >>${LOGFILE}
+ else
+ echo "FAIL: test 57" | tee -a ${LOGFILE} ; exit 1
+ fi
+
+ directory_cmp first-dir second-dir
+
+ if $ISDIFF ; then
+ echo "FAIL: test 58" | tee -a ${LOGFILE} ; exit 1
+ else
+ echo "PASS: test 58" >>${LOGFILE}
+ fi
+
+ rm -rf export-dir first-dir
+ mkdir first-dir
+ (cd first-dir.cpy ; tar cf - * | (cd ../first-dir ; tar xf -))
+
+ # update the top, cancelling sticky tags, retag, update other copy, compare.
+ cd first-dir
+ if ${CVS} update -A -l *file* 2>> ${LOGFILE}; then
+ echo "PASS: test 59" >>${LOGFILE}
+ else
+ echo "FAIL: test 59" | tee -a ${LOGFILE} ; exit 1
+ fi
+
+ # If we don't delete the tag first, cvs won't retag it.
+ # This would appear to be a feature.
+ if ${CVS} tag -l -d rtagged-by-revision ; then
+ echo "PASS: test 60a" >>${LOGFILE}
+ else
+ echo "FAIL: test 60a" | tee -a ${LOGFILE} ; exit 1
+ fi
+ if ${CVS} tag -l rtagged-by-revision ; then
+ echo "PASS: test 60b" >>${LOGFILE}
+ else
+ echo "FAIL: test 60b" | tee -a ${LOGFILE} ; exit 1
+ fi
+
+ cd ..
+ mv first-dir 1dir
+ mv first-dir.cpy first-dir
+ cd first-dir
+
+ if ${CVS} diff -u >> ${LOGFILE} || [ $? = 1 ] ; then
+ echo "PASS: test 61" >>${LOGFILE}
+ else
+ echo "FAIL: test 61" | tee -a ${LOGFILE} ; exit 1
+ fi
+
+ if ${CVS} update ; then
+ echo "PASS: test 62" >>${LOGFILE}
+ else
+ echo "FAIL: test 62" | tee -a ${LOGFILE} ; exit 1
+ fi
+
+ cd ..
+
+ #### FIXME: is this expected to work??? Need to investigate
+ #### and fix or remove the test.
+# directory_cmp 1dir first-dir
+#
+# if $ISDIFF ; then
+# echo "FAIL: test 63" | tee -a ${LOGFILE} # ; exit 1
+# else
+# echo "PASS: test 63" >>${LOGFILE}
+# fi
+ rm -rf 1dir first-dir
+
+ if ${CVS} his -e -a >> ${LOGFILE}; then
+ echo "PASS: test 64" >>${LOGFILE}
+ else
+ echo "FAIL: test 64" | tee -a ${LOGFILE} ; exit 1
+ fi
+ ;;
+
+ death) # next dive. test death support.
+ rm -rf ${CVSROOT_DIRNAME}/first-dir
+ mkdir ${CVSROOT_DIRNAME}/first-dir
+ if ${CVS} co first-dir ; then
+ echo "PASS: test 65" >>${LOGFILE}
+ else
+ echo "FAIL: test 65" | tee -a ${LOGFILE} ; exit 1
+ fi
+
+ cd first-dir
+
+ # add a file.
+ touch file1
+ if ${CVS} add file1 2>> ${LOGFILE}; then
+ echo "PASS: test 66" >>${LOGFILE}
+ else
+ echo "FAIL: test 66" | tee -a ${LOGFILE} ; exit 1
+ fi
+
+ # commit
+ if ${CVS} ci -m test >> ${LOGFILE} 2>&1; then
+ echo "PASS: test 67" >>${LOGFILE}
+ else
+ echo "FAIL: test 67" | tee -a ${LOGFILE} ; exit 1
+ fi
+
+ # remove
+ rm file1
+ if ${CVS} rm file1 2>> ${LOGFILE}; then
+ echo "PASS: test 68" >>${LOGFILE}
+ else
+ echo "FAIL: test 68" | tee -a ${LOGFILE} ; exit 1
+ fi
+
+ # commit
+ if ${CVS} ci -m test >>${LOGFILE} ; then
+ echo "PASS: test 69" >>${LOGFILE}
+ else
+ echo "FAIL: test 69" | tee -a ${LOGFILE} ; exit 1
+ fi
+
+ # add again and create second file
+ touch file1 file2
+ if ${CVS} add file1 file2 2>> ${LOGFILE}; then
+ echo "PASS: test 70" >>${LOGFILE}
+ else
+ echo "FAIL: test 70" | tee -a ${LOGFILE} ; exit 1
+ fi
+
+ # commit
+ if ${CVS} ci -m test >> ${LOGFILE} 2>&1; then
+ echo "PASS: test 71" >>${LOGFILE}
+ else
+ echo "FAIL: test 71" | tee -a ${LOGFILE} ; exit 1
+ fi
+
+ # log
+ if ${CVS} log file1 >> ${LOGFILE}; then
+ echo "PASS: test 72" >>${LOGFILE}
+ else
+ echo "FAIL: test 72" | tee -a ${LOGFILE} ; exit 1
+ fi
+
+
+ # branch1
+ if ${CVS} tag -b branch1 ; then
+ echo "PASS: test 73" >>${LOGFILE}
+ else
+ echo "FAIL: test 73" | tee -a ${LOGFILE} ; exit 1
+ fi
+
+ # and move to the branch.
+ if ${CVS} update -r branch1 ; then
+ echo "PASS: test 74" >>${LOGFILE}
+ else
+ echo "FAIL: test 74" | tee -a ${LOGFILE} ; exit 1
+ fi
+
+ # add a file in the branch
+ echo line1 from branch1 >> file3
+ if ${CVS} add file3 2>> ${LOGFILE}; then
+ echo "PASS: test 75" >>${LOGFILE}
+ else
+ echo "FAIL: test 75" | tee -a ${LOGFILE} ; exit 1
+ fi
+
+ # commit
+ if ${CVS} ci -m test >> ${LOGFILE} 2>&1; then
+ echo "PASS: test 76" >>${LOGFILE}
+ else
+ echo "FAIL: test 76" | tee -a ${LOGFILE} ; exit 1
+ fi
+
+ # remove
+ rm file3
+ if ${CVS} rm file3 2>> ${LOGFILE}; then
+ echo "PASS: test 77" >>${LOGFILE}
+ else
+ echo "FAIL: test 77" | tee -a ${LOGFILE} ; exit 1
+ fi
+
+ # commit
+ if ${CVS} ci -m test >>${LOGFILE} ; then
+ echo "PASS: test 78" >>${LOGFILE}
+ else
+ echo "FAIL: test 78" | tee -a ${LOGFILE} ; exit 1
+ fi
+
+ # add again
+ echo line1 from branch1 >> file3
+ if ${CVS} add file3 2>> ${LOGFILE}; then
+ echo "PASS: test 79" >>${LOGFILE}
+ else
+ echo "FAIL: test 79" | tee -a ${LOGFILE} ; exit 1
+ fi
+
+ # commit
+ if ${CVS} ci -m test >> ${LOGFILE} 2>&1; then
+ echo "PASS: test 80" >>${LOGFILE}
+ else
+ echo "FAIL: test 80" | tee -a ${LOGFILE} ; exit 1
+ fi
+
+ # change the first file
+ echo line2 from branch1 >> file1
+
+ # commit
+ if ${CVS} ci -m test >> ${LOGFILE} 2>&1; then
+ echo "PASS: test 81" >>${LOGFILE}
+ else
+ echo "FAIL: test 81" | tee -a ${LOGFILE} ; exit 1
+ fi
+
+ # remove the second
+ rm file2
+ if ${CVS} rm file2 2>> ${LOGFILE}; then
+ echo "PASS: test 82" >>${LOGFILE}
+ else
+ echo "FAIL: test 82" | tee -a ${LOGFILE} ; exit 1
+ fi
+
+ # commit
+ if ${CVS} ci -m test >>${LOGFILE}; then
+ echo "PASS: test 83" >>${LOGFILE}
+ else
+ echo "FAIL: test 83" | tee -a ${LOGFILE} ; exit 1
+ fi
+
+ # back to the trunk.
+ if ${CVS} update -A 2>> ${LOGFILE}; then
+ echo "PASS: test 84" >>${LOGFILE}
+ else
+ echo "FAIL: test 84" | tee -a ${LOGFILE} ; exit 1
+ fi
+
+ if [ -f file3 ] ; then
+ echo "FAIL: test 85" | tee -a ${LOGFILE} ; exit 1
+ else
+ echo "PASS: test 85" >>${LOGFILE}
+ fi
+
+ # join
+ if ${CVS} update -j branch1 >> ${LOGFILE} 2>&1; then
+ echo "PASS: test 86" >>${LOGFILE}
+ else
+ echo "FAIL: test 86" | tee -a ${LOGFILE} ; exit 1
+ fi
+
+ if [ -f file3 ] ; then
+ echo "PASS: test 87" >>${LOGFILE}
+ else
+ echo "FAIL: test 87" | tee -a ${LOGFILE} ; exit 1
+ fi
+
+ # Make sure that we joined the correct change to file1
+ if echo line2 from branch1 | cmp - file1 >/dev/null; then
+ echo 'PASS: test 87a' >>${LOGFILE}
+ else
+ echo 'FAIL: test 87a' | tee -a ${LOGFILE}
+ exit 1
+ fi
+
+ # update
+ if ${CVS} update ; then
+ echo "PASS: test 88" >>${LOGFILE}
+ else
+ echo "FAIL: test 88" | tee -a ${LOGFILE} ; exit 1
+ fi
+
+ # commit
+ if ${CVS} ci -m test >>${LOGFILE} 2>&1; then
+ echo "PASS: test 89" >>${LOGFILE}
+ else
+ echo "FAIL: test 89" | tee -a ${LOGFILE} ; exit 1
+ fi
+
+ # remove first file.
+ rm file1
+ if ${CVS} rm file1 2>> ${LOGFILE}; then
+ echo "PASS: test 90" >>${LOGFILE}
+ else
+ echo "FAIL: test 90" | tee -a ${LOGFILE} ; exit 1
+ fi
+
+ # commit
+ if ${CVS} ci -m test >>${LOGFILE}; then
+ echo "PASS: test 91" >>${LOGFILE}
+ else
+ echo "FAIL: test 91" | tee -a ${LOGFILE} ; exit 1
+ fi
+
+ if [ -f file1 ] ; then
+ echo "FAIL: test 92" | tee -a ${LOGFILE} ; exit 1
+ else
+ echo "PASS: test 92" >>${LOGFILE}
+ fi
+
+ # back to branch1
+ if ${CVS} update -r branch1 2>> ${LOGFILE}; then
+ echo "PASS: test 93" >>${LOGFILE}
+ else
+ echo "FAIL: test 93" | tee -a ${LOGFILE} ; exit 1
+ fi
+
+ if [ -f file1 ] ; then
+ echo "PASS: test 94" >>${LOGFILE}
+ else
+ echo "FAIL: test 94" | tee -a ${LOGFILE} ; exit 1
+ fi
+
+ # and join
+ if ${CVS} update -j HEAD >> ${LOGFILE} 2>&1; then
+ echo "PASS: test 95" >>${LOGFILE}
+ else
+ echo "FAIL: test 95" | tee -a ${LOGFILE} ; exit 1
+ fi
+
+ cd .. ; rm -rf first-dir ${CVSROOT_DIRNAME}/first-dir
+ ;;
+
+ import) # test death after import
+ # import
+ mkdir import-dir ; cd import-dir
+
+ for i in 1 2 3 4 ; do
+ echo imported file"$i" > imported-file"$i"
+ done
+
+ if ${CVS} import -m first-import first-dir vendor-branch junk-1_0 ; then
+ echo "PASS: test 96" >>${LOGFILE}
+ else
+ echo "FAIL: test 96" | tee -a ${LOGFILE} ; exit 1
+ fi
+ cd ..
+
+ # co
+ if ${CVS} co first-dir ; then
+ echo "PASS: test 97" >>${LOGFILE}
+ else
+ echo "FAIL: test 97" | tee -a ${LOGFILE} ; exit 1
+ fi
+
+ cd first-dir
+ for i in 1 2 3 4 ; do
+ if [ -f imported-file"$i" ] ; then
+ echo "PASS: test 98-$i" >>${LOGFILE}
+ else
+ echo "FAIL: test 98-$i" | tee -a ${LOGFILE} ; exit 1
+ fi
+ done
+
+ # remove
+ rm imported-file1
+ if ${CVS} rm imported-file1 2>> ${LOGFILE}; then
+ echo "PASS: test 99" >>${LOGFILE}
+ else
+ echo "FAIL: test 99" | tee -a ${LOGFILE} ; exit 1
+ fi
+
+ # change
+ # this sleep is significant. Otherwise, on some machines, things happen so
+ # fast that the file mod times do not differ.
+ sleep 1
+ echo local-change >> imported-file2
+
+ # commit
+ if ${CVS} ci -m local-changes >> ${LOGFILE} 2>&1; then
+ echo "PASS: test 100" >>${LOGFILE}
+ else
+ echo "FAIL: test 100" | tee -a ${LOGFILE} ; exit 1
+ fi
+
+ # log
+ if ${CVS} log imported-file1 | grep '1.1.1.2 (dead)' ; then
+ echo "FAIL: test 101" | tee -a ${LOGFILE} ; exit 1
+ else
+ echo "PASS: test 101" >>${LOGFILE}
+ fi
+
+ # update into the vendor branch.
+ if ${CVS} update -rvendor-branch ; then
+ echo "PASS: test 102" >>${LOGFILE}
+ else
+ echo "FAIL: test 102" | tee -a ${LOGFILE} ; exit 1
+ fi
+
+ # remove file4 on the vendor branch
+ rm imported-file4
+
+ if ${CVS} rm imported-file4 2>> ${LOGFILE}; then
+ echo "PASS: test 103" >>${LOGFILE}
+ else
+ echo "FAIL: test 103" | tee -a ${LOGFILE} ; exit 1
+ fi
+
+ # commit
+ if ${CVS} ci -m vendor-removed imported-file4 >>${LOGFILE}; then
+ echo "PASS: test 104" >>${LOGFILE}
+ else
+ echo "FAIL: test 104" | tee -a ${LOGFILE} ; exit 1
+ fi
+
+ # update to main line
+ if ${CVS} update -A 2>> ${LOGFILE}; then
+ echo "PASS: test 105" >>${LOGFILE}
+ else
+ echo "FAIL: test 105" | tee -a ${LOGFILE} ; exit 1
+ fi
+
+ # second import - file4 deliberately unchanged
+ cd ../import-dir
+ for i in 1 2 3 ; do
+ echo rev 2 of file $i >> imported-file"$i"
+ done
+
+ if ${CVS} import -m second-import first-dir vendor-branch junk-2_0 ; then
+ echo "PASS: test 106" >>${LOGFILE}
+ else
+ echo "FAIL: test 106" | tee -a ${LOGFILE} ; exit 1
+ fi
+ cd ..
+
+ # co
+ if ${CVS} co first-dir ; then
+ echo "PASS: test 107" >>${LOGFILE}
+ else
+ echo "FAIL: test 107" | tee -a ${LOGFILE} ; exit 1
+ fi
+
+ cd first-dir
+
+ if [ -f imported-file1 ] ; then
+ echo "FAIL: test 108" | tee -a ${LOGFILE} ; exit 1
+ else
+ echo "PASS: test 108" >>${LOGFILE}
+ fi
+
+ for i in 2 3 ; do
+ if [ -f imported-file"$i" ] ; then
+ echo "PASS: test 109-$i" >>${LOGFILE}
+ else
+ echo "FAIL: test 109-$i" | tee -a ${LOGFILE} ; exit 1
+ fi
+ done
+
+ # check vendor branch for file4
+ if ${CVS} update -rvendor-branch ; then
+ echo "PASS: test 110" >>${LOGFILE}
+ else
+ echo "FAIL: test 110" | tee -a ${LOGFILE} ; exit 1
+ fi
+
+ if [ -f imported-file4 ] ; then
+ echo "PASS: test 111" >>${LOGFILE}
+ else
+ echo "FAIL: test 111" | tee -a ${LOGFILE} ; exit 1
+ fi
+
+ # update to main line
+ if ${CVS} update -A 2>> ${LOGFILE}; then
+ echo "PASS: test 112" >>${LOGFILE}
+ else
+ echo "FAIL: test 112" | tee -a ${LOGFILE} ; exit 1
+ fi
+
+ cd ..
+
+ if ${CVS} co -jjunk-1_0 -jjunk-2_0 first-dir >>${LOGFILE} 2>&1; then
+ echo "PASS: test 113" >>${LOGFILE}
+ else
+ echo "FAIL: test 113" | tee -a ${LOGFILE} ; exit 1
+ fi
+
+ cd first-dir
+
+ if [ -f imported-file1 ] ; then
+ echo "FAIL: test 114" | tee -a ${LOGFILE} ; exit 1
+ else
+ echo "PASS: test 114" >>${LOGFILE}
+ fi
+
+ for i in 2 3 ; do
+ if [ -f imported-file"$i" ] ; then
+ echo "PASS: test 115-$i" >>${LOGFILE}
+ else
+ echo "FAIL: test 115-$i" | tee -a ${LOGFILE} ; exit 1
+ fi
+ done
+
+ if cat imported-file2 | grep '====' >> ${LOGFILE}; then
+ echo "PASS: test 116" >>${LOGFILE}
+ else
+ echo "FAIL: test 116" | tee -a ${LOGFILE} ; exit 1
+ fi
+ cd .. ; rm -rf first-dir ${CVSROOT_DIRNAME}/first-dir
+ ;;
+
+ new) # look for stray "no longer pertinent" messages.
+ rm -rf first-dir ${CVSROOT_DIRNAME}/first-dir
+ mkdir ${CVSROOT_DIRNAME}/first-dir
+
+ if ${CVS} co first-dir ; then
+ echo "PASS: test 117" >>${LOGFILE}
+ else
+ echo "FAIL: test 117" | tee -a ${LOGFILE} ; exit 1
+ fi
+
+ cd first-dir
+ touch a
+
+ if ${CVS} add a 2>>${LOGFILE}; then
+ echo "PASS: test 118" >>${LOGFILE}
+ else
+ echo "FAIL: test 118" | tee -a ${LOGFILE} ; exit 1
+ fi
+
+ if ${CVS} ci -m added >>${LOGFILE} 2>&1; then
+ echo "PASS: test 119" >>${LOGFILE}
+ else
+ echo "FAIL: test 119" | tee -a ${LOGFILE} ; exit 1
+ fi
+
+ rm a
+
+ if ${CVS} rm a 2>>${LOGFILE}; then
+ echo "PASS: test 120" >>${LOGFILE}
+ else
+ echo "FAIL: test 120" | tee -a ${LOGFILE} ; exit 1
+ fi
+
+ if ${CVS} ci -m removed >>${LOGFILE} ; then
+ echo "PASS: test 121" >>${LOGFILE}
+ else
+ echo "FAIL: test 121" | tee -a ${LOGFILE} ; exit 1
+ fi
+
+ if ${CVS} update -A 2>&1 | grep longer ; then
+ echo "FAIL: test 122" | tee -a ${LOGFILE} ; exit 1
+ else
+ echo "PASS: test 122" >>${LOGFILE}
+ fi
+
+ if ${CVS} update -rHEAD 2>&1 | grep longer ; then
+ echo "FAIL: test 123" | tee -a ${LOGFILE} ; exit 1
+ else
+ echo "PASS: test 123" >>${LOGFILE}
+ fi
+
+ cd .. ; rm -rf first-dir ; rm -rf ${CVSROOT_DIRNAME}/first-dir
+ ;;
+
+ conflicts)
+ rm -rf first-dir ${CVSROOT_DIRNAME}/first-dir
+ mkdir ${CVSROOT_DIRNAME}/first-dir
+
+ mkdir 1
+ cd 1
+
+ if ${CVS} co first-dir ; then
+ echo 'PASS: test 124' >>${LOGFILE}
+ else
+ echo 'FAIL: test 124' | tee -a ${LOGFILE}
+ fi
+
+ cd first-dir
+ touch a
+
+ if ${CVS} add a 2>>${LOGFILE} ; then
+ echo 'PASS: test 125' >>${LOGFILE}
+ else
+ echo 'FAIL: test 125' | tee -a ${LOGFILE}
+ fi
+
+ if ${CVS} ci -m added >>${LOGFILE} 2>&1; then
+ echo 'PASS: test 126' >>${LOGFILE}
+ else
+ echo 'FAIL: test 126' | tee -a ${LOGFILE}
+ fi
+
+ cd ../..
+ mkdir 2
+ cd 2
+
+ if ${CVS} co first-dir ; then
+ echo 'PASS: test 127' >>${LOGFILE}
+ else
+ echo 'FAIL: test 127' | tee -a ${LOGFILE}
+ fi
+ cd first-dir
+ if test -f a; then
+ echo 'PASS: test 127a' >>${LOGFILE}
+ else
+ echo 'FAIL: test 127a' | tee -a ${LOGFILE}
+ fi
+
+ cd ../../1/first-dir
+ echo add a line >>a
+ if ${CVS} ci -m changed >>${LOGFILE} 2>&1; then
+ echo 'PASS: test 128' >>${LOGFILE}
+ else
+ echo 'FAIL: test 128' | tee -a ${LOGFILE}
+ fi
+
+ cd ../../2/first-dir
+ echo add a conflicting line >>a
+ if ${CVS} ci -m changed >>${LOGFILE} 2>&1; then
+ echo 'FAIL: test 129' | tee -a ${LOGFILE}
+ else
+ # Should be printing `out of date check failed'.
+ echo 'PASS: test 129' >>${LOGFILE}
+ fi
+
+ if ${CVS} update 2>>${LOGFILE}; then
+ # We should get a conflict, but that doesn't affect
+ # exit status
+ echo 'PASS: test 130' >>${LOGFILE}
+ else
+ echo 'FAIL: test 130' | tee -a ${LOGFILE}
+ fi
+
+ # Try to check in the file with the conflict markers in it.
+ if ${CVS} ci -m try 2>>${LOGFILE}; then
+ echo 'FAIL: test 131' | tee -a ${LOGFILE}
+ else
+ # Should tell us to resolve conflict first
+ echo 'PASS: test 131' >>${LOGFILE}
+ fi
+
+ echo lame attempt at resolving it >>a
+ # Try to check in the file with the conflict markers in it.
+ if ${CVS} ci -m try >>${LOGFILE} 2>&1; then
+ echo 'FAIL: test 132' | tee -a ${LOGFILE}
+ else
+ # Should tell us to resolve conflict first
+ echo 'PASS: test 132' >>${LOGFILE}
+ fi
+
+ echo resolve conflict >a
+ if ${CVS} ci -m resolved >>${LOGFILE} 2>&1; then
+ echo 'PASS: test 133' >>${LOGFILE}
+ else
+ echo 'FAIL: test 133' | tee -a ${LOGFILE}
+ fi
+
+ # Now test that we can add a file in one working directory
+ # and have an update in another get it.
+ cd ../../1/first-dir
+ echo abc >abc
+ if ${testcvs} add abc >>${LOGFILE} 2>&1; then
+ echo 'PASS: test 134' >>${LOGFILE}
+ else
+ echo 'FAIL: test 134' | tee -a ${LOGFILE}
+ fi
+ if ${testcvs} ci -m 'add abc' abc >>${LOGFILE} 2>&1; then
+ echo 'PASS: test 135' >>${LOGFILE}
+ else
+ echo 'FAIL: test 135' | tee -a ${LOGFILE}
+ fi
+ cd ../../2
+ if ${testcvs} -q update >>${LOGFILE}; then
+ echo 'PASS: test 136' >>${LOGFILE}
+ else
+ echo 'FAIL: test 136' | tee -a ${LOGFILE}
+ fi
+ if test -f first-dir/abc; then
+ echo 'PASS: test 137' >>${LOGFILE}
+ else
+ echo 'FAIL: test 137' | tee -a ${LOGFILE}
+ fi
+
+ # Now test something similar, but in which the parent directory
+ # (not the directory in question) has the Entries.Static flag
+ # set.
+ cd ../1/first-dir
+ mkdir subdir
+ if ${testcvs} add subdir >>${LOGFILE}; then
+ echo 'PASS: test 138' >>${LOGFILE}
+ else
+ echo 'FAIL: test 138' | tee -a ${LOGFILE}
+ fi
+ cd ../..
+ mkdir 3
+ cd 3
+ if ${testcvs} -q co first-dir/abc first-dir/subdir \
+ >>${LOGFILE}; then
+ echo 'PASS: test 139' >>${LOGFILE}
+ else
+ echo 'FAIL: test 139' | tee -a ${LOGFILE}
+ fi
+ cd ../1/first-dir/subdir
+ echo sss >sss
+ if ${testcvs} add sss >>${LOGFILE} 2>&1; then
+ echo 'PASS: test 140' >>${LOGFILE}
+ else
+ echo 'FAIL: test 140' | tee -a ${LOGFILE}
+ fi
+ if ${testcvs} ci -m adding sss >>${LOGFILE} 2>&1; then
+ echo 'PASS: test 140' >>${LOGFILE}
+ else
+ echo 'FAIL: test 140' | tee -a ${LOGFILE}
+ fi
+ cd ../../../3/first-dir
+ if ${testcvs} -q update >>${LOGFILE}; then
+ echo 'PASS: test 141' >>${LOGFILE}
+ else
+ echo 'FAIL: test 141' | tee -a ${LOGFILE}
+ fi
+ if test -f subdir/sss; then
+ echo 'PASS: test 142' >>${LOGFILE}
+ else
+ echo 'FAIL: test 142' | tee -a ${LOGFILE}
+ fi
+
+ cd ../..
+ rm -rf 1 2 3 ; rm -rf ${CVSROOT_DIRNAME}/first-dir
+ ;;
+ modules)
+ # The following line stolen from cvsinit.sh. FIXME: create our
+ # repository via cvsinit.sh; that way we test it too.
+ (cd ${CVSROOT_DIRNAME}/CVSROOT; ci -q -u -t/dev/null \
+ -m'initial checkin of modules' modules)
+
+ rm -rf first-dir ${CVSROOT_DIRNAME}/first-dir
+ mkdir ${CVSROOT_DIRNAME}/first-dir
+
+ mkdir 1
+ cd 1
+
+ if ${testcvs} -q co first-dir; then
+ echo 'PASS: test 143' >>${LOGFILE}
+ else
+ echo 'FAIL: test 143' | tee -a ${LOGFILE}
+ exit 1
+ fi
+
+ cd first-dir
+ mkdir subdir
+ ${testcvs} add subdir >>${LOGFILE}
+ cd subdir
+
+ touch a
+
+ if ${testcvs} add a 2>>${LOGFILE} ; then
+ echo 'PASS: test 144' >>${LOGFILE}
+ else
+ echo 'FAIL: test 144' | tee -a ${LOGFILE}
+ exit 1
+ fi
+
+ if ${testcvs} ci -m added >>${LOGFILE} 2>&1; then
+ echo 'PASS: test 145' >>${LOGFILE}
+ else
+ echo 'FAIL: test 145' | tee -a ${LOGFILE}
+ exit 1
+ fi
+
+ cd ..
+ if ${testcvs} -q co CVSROOT >>${LOGFILE}; then
+ echo 'PASS: test 146' >>${LOGFILE}
+ else
+ echo 'FAIL: test 146' | tee -a ${LOGFILE}
+ exit 1
+ fi
+
+ # Here we test that CVS can deal with CVSROOT (whose repository
+ # is at top level) in the same directory as subdir (whose repository
+ # is a subdirectory of first-dir). TODO: Might want to check that
+ # files can actually get updated in this state.
+ if ${testcvs} -q update; then
+ echo 'PASS: test 147' >>${LOGFILE}
+ else
+ echo 'FAIL: test 147' | tee -a ${LOGFILE}
+ exit 1
+ fi
+
+ echo realmodule first-dir/subdir a >>CVSROOT/modules
+ echo aliasmodule -a first-dir/subdir/a >>CVSROOT/modules
+ if ${testcvs} ci -m 'add modules' CVSROOT/modules \
+ >>${LOGFILE} 2>&1; then
+ echo 'PASS: test 148' >>${LOGFILE}
+ else
+ echo 'FAIL: test 148' | tee -a ${LOGFILE}
+ exit 1
+ fi
+ cd ..
+ if ${testcvs} co realmodule >>${LOGFILE}; then
+ echo 'PASS: test 149' >>${LOGFILE}
+ else
+ echo 'FAIL: test 149' | tee -a ${LOGFILE}
+ exit 1
+ fi
+ if test -d realmodule && test -f realmodule/a; then
+ echo 'PASS: test 150' >>${LOGFILE}
+ else
+ echo 'FAIL: test 150' | tee -a ${LOGFILE}
+ exit 1
+ fi
+ if ${testcvs} co aliasmodule >>${LOGFILE}; then
+ echo 'PASS: test 151' >>${LOGFILE}
+ else
+ echo 'FAIL: test 151' | tee -a ${LOGFILE}
+ exit 1
+ fi
+ if test -d aliasmodule; then
+ echo 'FAIL: test 152' | tee -a ${LOGFILE}
+ exit 1
+ else
+ echo 'PASS: test 152' >>${LOGFILE}
+ fi
+ echo abc >>first-dir/subdir/a
+ if (${testcvs} -q co aliasmodule | tee test153.tmp) \
+ >>${LOGFILE}; then
+ echo 'PASS: test 153' >>${LOGFILE}
+ else
+ echo 'FAIL: test 153' | tee -a ${LOGFILE}
+ exit 1
+ fi
+ echo 'M first-dir/subdir/a' >ans153.tmp
+ if cmp test153.tmp ans153.tmp; then
+ echo 'PASS: test 154' >>${LOGFILE}
+ else
+ echo 'FAIL: test 154' | tee -a ${LOGFILE}
+ exit 1
+ fi
+ if ${testcvs} -q co realmodule; then
+ echo 'PASS: test 155' >>${LOGFILE}
+ else
+ echo 'FAIL: test 155' | tee -a ${LOGFILE}
+ exit 1
+ fi
+ cd ..
+ rm -rf 1 ; rm -rf ${CVSROOT_DIRNAME}/first-dir
+ ;;
+ mflag)
+ for message in '' ' ' '
+ ' ' test' ; do
+ # Set up
+ mkdir a-dir; cd a-dir
+ # Test handling of -m during import
+ echo testa >>test
+ if ${testcvs} import -m "$message" a-dir A A1 >>${LOGFILE} 2>&1;then
+ echo 'PASS: test 156' >>${LOGFILE}
+ else
+ echo 'FAIL: test 156' | tee -a ${LOGFILE}
+ exit 1
+ fi
+ # Must import twice since the first time uses inline code that
+ # avoids RCS call.
+ echo testb >>test
+ if ${testcvs} import -m "$message" a-dir A A2 >>${LOGFILE} 2>&1;then
+ echo 'PASS: test 157' >>${LOGFILE}
+ else
+ echo 'FAIL: test 157' | tee -a ${LOGFILE}
+ exit 1
+ fi
+ # Test handling of -m during ci
+ cd ..; rm -rf a-dir;
+ if ${testcvs} co a-dir >>${LOGFILE} 2>&1; then
+ echo 'PASS: test 158' >>${LOGFILE}
+ else
+ echo 'FAIL: test 158' | tee -a ${LOGFILE}
+ exit 1
+ fi
+ cd a-dir
+ echo testc >>test
+ if ${testcvs} ci -m "$message" >>${LOGFILE} 2>&1; then
+ echo 'PASS: test 159' >>${LOGFILE}
+ else
+ echo 'FAIL: test 159' | tee -a ${LOGFILE}
+ exit 1
+ fi
+ # Test handling of -m during rm/ci
+ rm test;
+ if ${testcvs} rm test >>${LOGFILE} 2>&1; then
+ echo 'PASS: test 160' >>${LOGFILE}
+ else
+ echo 'FAIL: test 160' | tee -a ${LOGFILE}
+ exit 1
+ fi
+ if ${testcvs} ci -m "$message" >>${LOGFILE} 2>&1; then
+ echo 'PASS: test 161' >>${LOGFILE}
+ else
+ echo 'FAIL: test 161' | tee -a ${LOGFILE}
+ exit 1
+ fi
+ # Clean up
+ cd ..; rm -rf a-dir ${CVSROOT_DIRNAME}/a-dir
+ done
+ ;;
+ errmsg1)
+ mkdir ${CVSROOT_DIRNAME}/1dir
+ mkdir 1
+ cd 1
+ if ${testcvs} -q co 1dir; then
+ echo 'PASS: test 162' >>${LOGFILE}
+ else
+ echo 'FAIL: test 162' | tee -a ${LOGFILE}
+ exit 1
+ fi
+ cd 1dir
+ touch foo
+ if ${testcvs} add foo 2>>${LOGFILE}; then
+ echo 'PASS: test 163' >>${LOGFILE}
+ else
+ echo 'FAIL: test 163' | tee -a ${LOGFILE}
+ exit 1
+ fi
+ if ${testcvs} ci -m added >>${LOGFILE} 2>&1; then
+ echo 'PASS: test 164' >>${LOGFILE}
+ else
+ echo 'FAIL: test 164' | tee -a ${LOGFILE}
+ exit 1
+ fi
+ cd ../..
+ mkdir 2
+ cd 2
+ if ${testcvs} -q co 1dir >>${LOGFILE}; then
+ echo 'PASS: test 165' >>${LOGFILE}
+ else
+ echo 'FAIL: test 165' | tee -a ${LOGFILE}
+ exit 1
+ fi
+ chmod a-w 1dir
+ cd ../1/1dir
+ rm foo;
+ if ${testcvs} rm foo >>${LOGFILE} 2>&1; then
+ echo 'PASS: test 166' >>${LOGFILE}
+ else
+ echo 'FAIL: test 166' | tee -a ${LOGFILE}
+ exit 1
+ fi
+ if ${testcvs} ci -m removed >>${LOGFILE} 2>&1; then
+ echo 'PASS: test 167' >>${LOGFILE}
+ else
+ echo 'FAIL: test 167' | tee -a ${LOGFILE}
+ exit 1
+ fi
+ cd ../../2/1dir
+ ${testcvs} -q update 2>../tst167.err
+ CVSBASE=`basename $testcvs` # Get basename of CVS executable.
+ cat <<EOF >../tst167.ans
+$CVSBASE server: warning: foo is not (any longer) pertinent
+$CVSBASE update: unable to remove ./foo: Permission denied
+EOF
+ if cmp ../tst167.ans ../tst167.err >/dev/null ||
+ ( echo "$CVSBASE [update aborted]: cannot rename file foo to CVS/,,foo: Permission denied" | cmp - ../tst167.err >/dev/null )
+ then
+ echo 'PASS: test 168' >>${LOGFILE}
+ else
+ echo 'FAIL: test 168' | tee -a ${LOGFILE}
+ exit 1
+ fi
+
+ cd ..
+ chmod u+w 1dir
+ cd ..
+ rm -rf 1 2 ${CVSROOT_DIRNAME}/1dir
+ ;;
+
+ *)
+ echo $what is not the name of a test -- ignored
+ ;;
+ esac
+done
+
+echo "OK, all tests completed."
+
+# TODO:
+# * Test `cvs admin'.
+# * Test `cvs update -d foo' (where foo does not exist).
+# * Test `cvs update foo bar' (where foo and bar are both from the same
+# repository). Suppose one is a branch--make sure that both directories
+# get updated with the respective correct thing.
+# * Zero length files (check in, check out).
+# * `cvs update ../foo'. Also ../../foo ./../foo foo/../../bar /foo/bar
+# foo/.././../bar foo/../bar etc.
+# * Test all flags in modules file.
+# Test that ciprog gets run both on checkin in that directory, or a
+# higher-level checkin which recurses into it.
+# * Test that $ followed by "Header" followed by $ gets expanded on checkin.
+# * Test operations on a directory that contains other directories but has
+# no files of its own.
+# * -t global option
+# * cvs rm followed by cvs add or vice versa (with no checkin in between).
+# * cvs rm twice (should be a nice error message).
+# * -P option to checkout--(a) refrains from checking out new empty dirs,
+# (b) prunes empty dirs already there.
+# * Test that cvs -d `hostname`:/tmp/cvs-sanity/non/existent co foo
+# gives an appropriate error (e.g.
+# Cannot access /tmp/cvs-sanity/non-existent/CVSROOT
+# No such file or directory).
+# End of TODO list.
+
+# Remove the test directory, but first change out of it.
+cd /tmp
+rm -rf ${TESTDIR}
+
+# end of sanity.sh
diff --git a/gnu/usr.bin/cvs/cvs/server.c b/gnu/usr.bin/cvs/cvs/server.c
new file mode 100644
index 0000000..fbfca86
--- /dev/null
+++ b/gnu/usr.bin/cvs/cvs/server.c
@@ -0,0 +1,3992 @@
+#include "cvs.h"
+
+#ifdef SERVER_SUPPORT
+
+/* for select */
+#include <sys/types.h>
+#ifdef HAVE_SYS_BSDTYPES_H
+#include <sys/bsdtypes.h>
+#endif
+#include <sys/time.h>
+
+#if HAVE_SYS_SELECT_H
+#include <sys/select.h>
+#endif
+
+#if HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
+
+#ifndef O_NONBLOCK
+#define O_NONBLOCK O_NDELAY
+#endif
+
+
+/* Functions which the server calls. */
+int add PROTO((int argc, char **argv));
+int admin PROTO((int argc, char **argv));
+int checkout PROTO((int argc, char **argv));
+int commit PROTO((int argc, char **argv));
+int diff PROTO((int argc, char **argv));
+int history PROTO((int argc, char **argv));
+int import PROTO((int argc, char **argv));
+int cvslog PROTO((int argc, char **argv));
+int patch PROTO((int argc, char **argv));
+int release PROTO((int argc, char **argv));
+int cvsremove PROTO((int argc, char **argv));
+int rtag PROTO((int argc, char **argv));
+int status PROTO((int argc, char **argv));
+int tag PROTO((int argc, char **argv));
+int update PROTO((int argc, char **argv));
+
+
+/*
+ * This is where we stash stuff we are going to use. Format string
+ * which expects a single directory within it, starting with a slash.
+ */
+static char *server_temp_dir;
+
+/* Nonzero if we should keep the temp directory around after we exit. */
+static int dont_delete_temp;
+
+static char no_mem_error;
+#define NO_MEM_ERROR (&no_mem_error)
+
+static void server_write_entries PROTO((void));
+
+/*
+ * Read a line from the stream "instream" without command line editing.
+ *
+ * Action is compatible with "readline", e.g. space for the result is
+ * malloc'd and should be freed by the caller.
+ *
+ * A NULL return means end of file. A return of NO_MEM_ERROR means
+ * that we are out of memory.
+ */
+static char *read_line PROTO((FILE *));
+
+static char *
+read_line (stream)
+ FILE *stream;
+{
+ int c;
+ char *result;
+ int input_index = 0;
+ int result_size = 80;
+
+ fflush (stdout);
+ result = (char *) malloc (result_size);
+ if (result == NULL)
+ return NO_MEM_ERROR;
+
+ while (1)
+ {
+ c = fgetc (stream);
+
+ if (c == EOF)
+ {
+ free (result);
+ return NULL;
+ }
+
+ if (c == '\n')
+ break;
+
+ result[input_index++] = c;
+ while (input_index >= result_size)
+ {
+ result_size *= 2;
+ result = (char *) realloc (result, result_size);
+ if (result == NULL)
+ return NO_MEM_ERROR;
+ }
+ }
+
+ result[input_index++] = '\0';
+ return result;
+}
+
+/*
+ * Make directory DIR, including all intermediate directories if necessary.
+ * Returns 0 for success or errno code.
+ */
+static int mkdir_p PROTO((char *));
+
+static int
+mkdir_p (dir)
+ char *dir;
+{
+ char *p;
+ char *q = malloc (strlen (dir) + 1);
+ int retval;
+
+ if (q == NULL)
+ return ENOMEM;
+
+ /*
+ * Skip over leading slash if present. We won't bother to try to
+ * make '/'.
+ */
+ p = dir + 1;
+ while (1)
+ {
+ while (*p != '/' && *p != '\0')
+ ++p;
+ if (*p == '/')
+ {
+ strncpy (q, dir, p - dir);
+ q[p - dir] = '\0';
+ if (CVS_MKDIR (q, 0777) < 0)
+ {
+ if (errno != EEXIST
+ && (errno != EACCES || !isdir(q)))
+ {
+ retval = errno;
+ goto done;
+ }
+ }
+ ++p;
+ }
+ else
+ {
+ if (CVS_MKDIR (dir, 0777) < 0)
+ retval = errno;
+ else
+ retval = 0;
+ goto done;
+ }
+ }
+ done:
+ free (q);
+ return retval;
+}
+
+/*
+ * Print the error response for error code STATUS. The caller is
+ * reponsible for making sure we get back to the command loop without
+ * any further output occuring.
+ */
+static void
+print_error (status)
+ int status;
+{
+ char *msg;
+ printf ("error ");
+ msg = strerror (status);
+ if (msg)
+ printf ("%s", msg);
+ printf ("\n");
+}
+
+static int pending_error;
+/*
+ * Malloc'd text for pending error. Each line must start with "E ". The
+ * last line should not end with a newline.
+ */
+static char *pending_error_text;
+
+/* If an error is pending, print it and return 1. If not, return 0. */
+static int
+print_pending_error ()
+{
+ if (pending_error_text)
+ {
+ printf ("%s\n", pending_error_text);
+ if (pending_error)
+ print_error (pending_error);
+ else
+ printf ("error \n");
+ pending_error = 0;
+ free (pending_error_text);
+ pending_error_text = NULL;
+ return 1;
+ }
+ else if (pending_error)
+ {
+ print_error (pending_error);
+ pending_error = 0;
+ return 1;
+ }
+ else
+ return 0;
+}
+
+/* Is an error pending? */
+#define error_pending() (pending_error || pending_error_text)
+
+int
+supported_response (name)
+ char *name;
+{
+ struct response *rs;
+
+ for (rs = responses; rs->name != NULL; ++rs)
+ if (strcmp (rs->name, name) == 0)
+ return rs->status == rs_supported;
+ error (1, 0, "internal error: testing support for unknown response?");
+}
+
+static void
+serve_valid_responses (arg)
+ char *arg;
+{
+ char *p = arg;
+ char *q;
+ struct response *rs;
+ do
+ {
+ q = strchr (p, ' ');
+ if (q != NULL)
+ *q++ = '\0';
+ for (rs = responses; rs->name != NULL; ++rs)
+ {
+ if (strcmp (rs->name, p) == 0)
+ break;
+ }
+ if (rs->name == NULL)
+ /*
+ * It is a response we have never heard of (and thus never
+ * will want to use). So don't worry about it.
+ */
+ ;
+ else
+ rs->status = rs_supported;
+ p = q;
+ } while (q != NULL);
+ for (rs = responses; rs->name != NULL; ++rs)
+ {
+ if (rs->status == rs_essential)
+ {
+ printf ("E response `%s' not supported by client\nerror \n",
+ rs->name);
+ exit (1);
+ }
+ else if (rs->status == rs_optional)
+ rs->status = rs_not_supported;
+ }
+}
+
+static int use_dir_and_repos = 0;
+
+static void
+serve_root (arg)
+ char *arg;
+{
+ char *env;
+ extern char *CVSroot;
+ char path[PATH_MAX];
+ int save_errno;
+
+ if (error_pending()) return;
+
+ (void) sprintf (path, "%s/%s", arg, CVSROOTADM);
+ if (!isaccessible (path, R_OK | X_OK))
+ {
+ save_errno = errno;
+ pending_error_text = malloc (80 + strlen (path));
+ if (pending_error_text != NULL)
+ sprintf (pending_error_text, "E Cannot access %s", path);
+ pending_error = save_errno;
+ }
+ (void) strcat (path, "/");
+ (void) strcat (path, CVSROOTADM_HISTORY);
+ if (isfile (path) && !isaccessible (path, R_OK | W_OK))
+ {
+ save_errno = errno;
+ pending_error_text = malloc (80 + strlen (path));
+ if (pending_error_text != NULL)
+ sprintf (pending_error_text, "E \
+Sorry, you don't have read/write access to the history file %s", path);
+ pending_error = save_errno;
+ }
+
+ CVSroot = malloc (strlen (arg) + 1);
+ if (CVSroot == NULL)
+ {
+ pending_error = ENOMEM;
+ return;
+ }
+ strcpy (CVSroot, arg);
+#ifdef HAVE_PUTENV
+ env = malloc (strlen (CVSROOT_ENV) + strlen (CVSroot) + 1 + 1);
+ if (env == NULL)
+ {
+ pending_error = ENOMEM;
+ return;
+ }
+ (void) sprintf (env, "%s=%s", CVSROOT_ENV, arg);
+ (void) putenv (env);
+ /* do not free env, as putenv has control of it */
+#endif
+}
+
+/*
+ * Add as many directories to the temp directory as the client tells us it
+ * will use "..", so we never try to access something outside the temp
+ * directory via "..".
+ */
+static void
+serve_max_dotdot (arg)
+ char *arg;
+{
+ int lim = atoi (arg);
+ int i;
+ char *p;
+
+ if (lim < 0)
+ return;
+ p = malloc (strlen (server_temp_dir) + 2 * lim + 10);
+ if (p == NULL)
+ {
+ pending_error = ENOMEM;
+ return;
+ }
+ strcpy (p, server_temp_dir);
+ for (i = 0; i < lim; ++i)
+ strcat (p, "/d");
+ free (server_temp_dir);
+ server_temp_dir = p;
+}
+
+static void
+dirswitch (dir, repos)
+ char *dir;
+ char *repos;
+{
+ char *dirname;
+ int status;
+ FILE *f;
+
+ server_write_entries ();
+
+ if (error_pending()) return;
+
+ dirname = malloc (strlen (server_temp_dir) + strlen (dir) + 40);
+ if (dirname == NULL)
+ {
+ pending_error = ENOMEM;
+ return;
+ }
+
+ strcpy (dirname, server_temp_dir);
+ strcat (dirname, "/");
+ strcat (dirname, dir);
+
+ status = mkdir_p (dirname);
+ if (status != 0
+ && status != EEXIST)
+ {
+ pending_error = status;
+ pending_error_text = malloc (80 + strlen(dirname));
+ sprintf(pending_error_text, "E cannot mkdir %s", dirname);
+ return;
+ }
+ if (chdir (dirname) < 0)
+ {
+ pending_error = errno;
+ pending_error_text = malloc (80 + strlen(dirname));
+ sprintf(pending_error_text, "E cannot change to %s", dirname);
+ return;
+ }
+ /*
+ * This is pretty much like calling Create_Admin, but Create_Admin doesn't
+ * report errors in the right way for us.
+ */
+ if (CVS_MKDIR (CVSADM, 0777) < 0)
+ {
+ if (errno == EEXIST)
+ /* Don't create the files again. */
+ return;
+ pending_error = errno;
+ return;
+ }
+ f = fopen (CVSADM_REP, "w");
+ if (f == NULL)
+ {
+ pending_error = errno;
+ return;
+ }
+ if (fprintf (f, "%s\n", repos) < 0)
+ {
+ pending_error = errno;
+ fclose (f);
+ return;
+ }
+ if (fclose (f) == EOF)
+ {
+ pending_error = errno;
+ return;
+ }
+ f = fopen (CVSADM_ENT, "w+");
+ if (f == NULL)
+ {
+ pending_error = errno;
+ pending_error_text = malloc (80 + strlen(CVSADM_ENT));
+ sprintf(pending_error_text, "E cannot open %s", CVSADM_ENT);
+ return;
+ }
+ if (fclose (f) == EOF)
+ {
+ pending_error = errno;
+ pending_error_text = malloc (80 + strlen(CVSADM_ENT));
+ sprintf(pending_error_text, "E cannot close %s", CVSADM_ENT);
+ return;
+ }
+ free (dirname);
+}
+
+static void
+serve_repository (arg)
+ char *arg;
+{
+ dirswitch (arg + 1, arg);
+}
+
+static void
+serve_directory (arg)
+ char *arg;
+{
+ char *repos;
+ use_dir_and_repos = 1;
+ repos = read_line (stdin);
+ if (repos == NULL)
+ {
+ pending_error_text = malloc (80 + strlen (arg));
+ if (pending_error_text)
+ {
+ if (feof (stdin))
+ sprintf (pending_error_text,
+ "E end of file reading mode for %s", arg);
+ else
+ {
+ sprintf (pending_error_text,
+ "E error reading mode for %s", arg);
+ pending_error = errno;
+ }
+ }
+ else
+ pending_error = ENOMEM;
+ }
+ else if (repos == NO_MEM_ERROR)
+ {
+ pending_error = ENOMEM;
+ }
+ else
+ {
+ dirswitch (arg, repos);
+ free (repos);
+ }
+}
+
+static void
+serve_static_directory (arg)
+ char *arg;
+{
+ FILE *f;
+ f = fopen (CVSADM_ENTSTAT, "w+");
+ if (f == NULL)
+ {
+ pending_error = errno;
+ pending_error_text = malloc (80 + strlen(CVSADM_ENTSTAT));
+ sprintf(pending_error_text, "E cannot open %s", CVSADM_ENTSTAT);
+ return;
+ }
+ if (fclose (f) == EOF)
+ {
+ pending_error = errno;
+ pending_error_text = malloc (80 + strlen(CVSADM_ENTSTAT));
+ sprintf(pending_error_text, "E cannot close %s", CVSADM_ENTSTAT);
+ return;
+ }
+}
+
+static void
+serve_sticky (arg)
+ char *arg;
+{
+ FILE *f;
+ f = fopen (CVSADM_TAG, "w+");
+ if (f == NULL)
+ {
+ pending_error = errno;
+ pending_error_text = malloc (80 + strlen(CVSADM_TAG));
+ sprintf(pending_error_text, "E cannot open %s", CVSADM_TAG);
+ return;
+ }
+ if (fprintf (f, "%s\n", arg) < 0)
+ {
+ pending_error = errno;
+ pending_error_text = malloc (80 + strlen(CVSADM_TAG));
+ sprintf(pending_error_text, "E cannot write to %s", CVSADM_TAG);
+ return;
+ }
+ if (fclose (f) == EOF)
+ {
+ pending_error = errno;
+ pending_error_text = malloc (80 + strlen(CVSADM_TAG));
+ sprintf(pending_error_text, "E cannot close %s", CVSADM_TAG);
+ return;
+ }
+}
+
+/*
+ * Read SIZE bytes from stdin, write them to FILE.
+ *
+ * Currently this isn't really used for receiving parts of a file --
+ * the file is still sent over in one chunk. But if/when we get
+ * spiffy in-process gzip support working, perhaps the compressed
+ * pieces could be sent over as they're ready, if the network is fast
+ * enough. Or something.
+ */
+static void
+receive_partial_file (size, file)
+ int size;
+ int file;
+{
+ char buf[16*1024], *bufp;
+ int toread, nread, nwrote;
+ while (size > 0)
+ {
+ toread = sizeof (buf);
+ if (toread > size)
+ toread = size;
+
+ nread = fread (buf, 1, toread, stdin);
+ if (nread <= 0)
+ {
+ if (feof (stdin))
+ {
+ pending_error_text = malloc (80);
+ if (pending_error_text)
+ {
+ sprintf (pending_error_text,
+ "E premature end of file from client");
+ pending_error = 0;
+ }
+ else
+ pending_error = ENOMEM;
+ }
+ else if (ferror (stdin))
+ {
+ pending_error_text = malloc (40);
+ if (pending_error_text)
+ sprintf (pending_error_text,
+ "E error reading from client");
+ pending_error = errno;
+ }
+ else
+ {
+ pending_error_text = malloc (40);
+ if (pending_error_text)
+ sprintf (pending_error_text,
+ "E short read from client");
+ pending_error = 0;
+ }
+ return;
+ }
+ size -= nread;
+ bufp = buf;
+ while (nread)
+ {
+ nwrote = write (file, bufp, nread);
+ if (nwrote < 0)
+ {
+ pending_error_text = malloc (40);
+ if (pending_error_text)
+ sprintf (pending_error_text, "E unable to write");
+ pending_error = errno;
+ return;
+ }
+ nread -= nwrote;
+ bufp += nwrote;
+ }
+ }
+}
+
+/* Receive SIZE bytes, write to filename FILE. */
+static void
+receive_file (size, file, gzipped)
+ int size;
+ char *file;
+ int gzipped;
+{
+ int fd;
+ char *arg = file;
+ pid_t gzip_pid = 0;
+ int gzip_status;
+
+ /* Write the file. */
+ fd = open (arg, O_WRONLY | O_CREAT | O_TRUNC, 0600);
+ if (fd < 0)
+ {
+ pending_error_text = malloc (40 + strlen (arg));
+ if (pending_error_text)
+ sprintf (pending_error_text, "E cannot open %s", arg);
+ pending_error = errno;
+ return;
+ }
+
+ /*
+ * FIXME: This doesn't do anything reasonable with gunzip's stderr, which
+ * means that if gunzip writes to stderr, it will cause all manner of
+ * protocol violations.
+ */
+ if (gzipped)
+ fd = filter_through_gunzip (fd, 0, &gzip_pid);
+
+ receive_partial_file (size, fd);
+
+ if (pending_error_text)
+ {
+ char *p = realloc (pending_error_text,
+ strlen (pending_error_text) + strlen (arg) + 30);
+ if (p)
+ {
+ pending_error_text = p;
+ sprintf (p + strlen (p), ", file %s", arg);
+ }
+ /* else original string is supposed to be unchanged */
+ }
+
+ if (close (fd) < 0 && !error_pending ())
+ {
+ pending_error_text = malloc (40 + strlen (arg));
+ if (pending_error_text)
+ sprintf (pending_error_text, "E cannot close %s", arg);
+ pending_error = errno;
+ if (gzip_pid)
+ waitpid (gzip_pid, (int *) 0, 0);
+ return;
+ }
+
+ if (gzip_pid)
+ {
+ if (waitpid (gzip_pid, &gzip_status, 0) != gzip_pid)
+ error (1, errno, "waiting for gunzip process %d", gzip_pid);
+ else if (gzip_status != 0)
+ error (1, 0, "gunzip exited %d", gzip_status);
+ }
+}
+
+static void
+serve_modified (arg)
+ char *arg;
+{
+ int size;
+ char *size_text;
+ char *mode_text;
+
+ int gzipped = 0;
+
+ if (error_pending ()) return;
+
+ mode_text = read_line (stdin);
+ if (mode_text == NULL)
+ {
+ pending_error_text = malloc (80 + strlen (arg));
+ if (pending_error_text)
+ {
+ if (feof (stdin))
+ sprintf (pending_error_text,
+ "E end of file reading mode for %s", arg);
+ else
+ {
+ sprintf (pending_error_text,
+ "E error reading mode for %s", arg);
+ pending_error = errno;
+ }
+ }
+ else
+ pending_error = ENOMEM;
+ return;
+ }
+ else if (mode_text == NO_MEM_ERROR)
+ {
+ pending_error = ENOMEM;
+ return;
+ }
+ size_text = read_line (stdin);
+ if (size_text == NULL)
+ {
+ pending_error_text = malloc (80 + strlen (arg));
+ if (pending_error_text)
+ {
+ if (feof (stdin))
+ sprintf (pending_error_text,
+ "E end of file reading size for %s", arg);
+ else
+ {
+ sprintf (pending_error_text,
+ "E error reading size for %s", arg);
+ pending_error = errno;
+ }
+ }
+ else
+ pending_error = ENOMEM;
+ return;
+ }
+ else if (size_text == NO_MEM_ERROR)
+ {
+ pending_error = ENOMEM;
+ return;
+ }
+ if (size_text[0] == 'z')
+ {
+ gzipped = 1;
+ size = atoi (size_text + 1);
+ }
+ else
+ size = atoi (size_text);
+ free (size_text);
+
+ if (size >= 0)
+ {
+ receive_file (size, arg, gzipped);
+ if (error_pending ()) return;
+ }
+
+ {
+ int status = change_mode (arg, mode_text);
+ free (mode_text);
+ if (status)
+ {
+ pending_error_text = malloc (40 + strlen (arg));
+ if (pending_error_text)
+ sprintf (pending_error_text,
+ "E cannot change mode for %s", arg);
+ pending_error = status;
+ return;
+ }
+ }
+}
+
+#endif /* SERVER_SUPPORT */
+
+#if defined(SERVER_SUPPORT) || defined(CLIENT_SUPPORT)
+
+int use_unchanged = 0;
+
+#endif
+#ifdef SERVER_SUPPORT
+
+static void
+serve_enable_unchanged (arg)
+ char *arg;
+{
+ use_unchanged = 1;
+}
+
+static void
+serve_lost (arg)
+ char *arg;
+{
+ if (use_unchanged)
+ {
+ /* A missing file already indicates it is nonexistent. */
+ return;
+ }
+ else
+ {
+ struct utimbuf ut;
+ int fd = open (arg, O_WRONLY | O_CREAT | O_TRUNC, 0666);
+ if (fd < 0 || close (fd) < 0)
+ {
+ pending_error = errno;
+ pending_error_text = malloc (80 + strlen(arg));
+ sprintf(pending_error_text, "E cannot open %s", arg);
+ return;
+ }
+ /*
+ * Set the times to the beginning of the epoch to tell time_stamp()
+ * that the file was lost.
+ */
+ ut.actime = 0;
+ ut.modtime = 0;
+ if (utime (arg, &ut) < 0)
+ {
+ pending_error = errno;
+ pending_error_text = malloc (80 + strlen(arg));
+ sprintf(pending_error_text, "E cannot utime %s", arg);
+ return;
+ }
+ }
+}
+
+struct an_entry {
+ struct an_entry *next;
+ char *entry;
+};
+
+static struct an_entry *entries;
+
+static void
+serve_unchanged (arg)
+ char *arg;
+{
+ if (error_pending ())
+ return;
+ if (!use_unchanged)
+ {
+ /* A missing file already indicates it is unchanged. */
+ return;
+ }
+ else
+ {
+ struct an_entry *p;
+ char *name;
+ char *cp;
+ char *timefield;
+
+ /* Rewrite entries file to have `=' in timestamp field. */
+ for (p = entries; p != NULL; p = p->next)
+ {
+ name = p->entry + 1;
+ cp = strchr (name, '/');
+ if (cp != NULL
+ && strlen (arg) == cp - name
+ && strncmp (arg, name, cp - name) == 0)
+ {
+ timefield = strchr (cp + 1, '/') + 1;
+ if (*timefield != '=')
+ {
+ cp = timefield + strlen (timefield);
+ cp[1] = '\0';
+ while (cp > timefield)
+ {
+ *cp = cp[-1];
+ --cp;
+ }
+ *timefield = '=';
+ }
+ break;
+ }
+ }
+ }
+}
+
+static void
+serve_entry (arg)
+ char *arg;
+{
+ struct an_entry *p;
+ char *cp;
+ if (error_pending()) return;
+ p = (struct an_entry *) malloc (sizeof (struct an_entry));
+ if (p == NULL)
+ {
+ pending_error = ENOMEM;
+ return;
+ }
+ /* Leave space for serve_unchanged to write '=' if it wants. */
+ cp = malloc (strlen (arg) + 2);
+ if (cp == NULL)
+ {
+ pending_error = ENOMEM;
+ return;
+ }
+ strcpy (cp, arg);
+ p->next = entries;
+ p->entry = cp;
+ entries = p;
+}
+
+static void
+server_write_entries ()
+{
+ FILE *f;
+ struct an_entry *p;
+ struct an_entry *q;
+
+ if (entries == NULL)
+ return;
+
+ f = NULL;
+ /* Note that we free all the entries regardless of errors. */
+ if (!error_pending ())
+ {
+ f = fopen (CVSADM_ENT, "w");
+ if (f == NULL)
+ {
+ pending_error = errno;
+ pending_error_text = malloc (80 + strlen(CVSADM_ENT));
+ sprintf(pending_error_text, "E cannot open %s", CVSADM_ENT);
+ }
+ }
+ for (p = entries; p != NULL;)
+ {
+ if (!error_pending ())
+ {
+ if (fprintf (f, "%s\n", p->entry) < 0)
+ {
+ pending_error = errno;
+ pending_error_text = malloc (80 + strlen(CVSADM_ENT));
+ sprintf(pending_error_text, "E cannot write to %s", CVSADM_ENT);
+ }
+ }
+ free (p->entry);
+ q = p->next;
+ free (p);
+ p = q;
+ }
+ entries = NULL;
+ if (f != NULL && fclose (f) == EOF && !error_pending ())
+ {
+ pending_error = errno;
+ pending_error_text = malloc (80 + strlen(CVSADM_ENT));
+ sprintf(pending_error_text, "E cannot close %s", CVSADM_ENT);
+ }
+}
+
+static int argument_count;
+static char **argument_vector;
+static int argument_vector_size;
+
+static void
+serve_argument (arg)
+ char *arg;
+{
+ char *p;
+
+ if (error_pending()) return;
+
+ if (argument_vector_size <= argument_count)
+ {
+ argument_vector_size *= 2;
+ argument_vector =
+ (char **) realloc ((char *)argument_vector,
+ argument_vector_size * sizeof (char *));
+ if (argument_vector == NULL)
+ {
+ pending_error = ENOMEM;
+ return;
+ }
+ }
+ p = malloc (strlen (arg) + 1);
+ if (p == NULL)
+ {
+ pending_error = ENOMEM;
+ return;
+ }
+ strcpy (p, arg);
+ argument_vector[argument_count++] = p;
+}
+
+static void
+serve_argumentx (arg)
+ char *arg;
+{
+ char *p;
+
+ if (error_pending()) return;
+
+ p = argument_vector[argument_count - 1];
+ p = realloc (p, strlen (p) + 1 + strlen (arg) + 1);
+ if (p == NULL)
+ {
+ pending_error = ENOMEM;
+ return;
+ }
+ strcat (p, "\n");
+ strcat (p, arg);
+ argument_vector[argument_count - 1] = p;
+}
+
+static void
+serve_global_option (arg)
+ char *arg;
+{
+ if (arg[0] != '-' || arg[1] == '\0' || arg[2] != '\0')
+ {
+ error_return:
+ pending_error_text = malloc (strlen (arg) + 80);
+ sprintf (pending_error_text, "E Protocol error: bad global option %s",
+ arg);
+ return;
+ }
+ switch (arg[1])
+ {
+ case 'n':
+ noexec = 1;
+ break;
+ case 'q':
+ quiet = 1;
+ break;
+ case 'r':
+ cvswrite = 0;
+ break;
+ case 'Q':
+ really_quiet = 1;
+ break;
+ case 'l':
+ logoff = 1;
+ break;
+ case 't':
+ trace = 1;
+ break;
+ default:
+ goto error_return;
+ }
+}
+
+/*
+ * We must read data from a child process and send it across the
+ * network. We do not want to block on writing to the network, so we
+ * store the data from the child process in memory. A BUFFER
+ * structure holds the status of one communication, and uses a linked
+ * list of buffer_data structures to hold data.
+ */
+
+struct buffer
+{
+ /* Data. */
+ struct buffer_data *data;
+
+ /* Last buffer on data chain. */
+ struct buffer_data *last;
+
+ /* File descriptor to write to or read from. */
+ int fd;
+
+ /* Nonzero if this is an output buffer (sanity check). */
+ int output;
+
+ /* Nonzero if the file descriptor is in nonblocking mode. */
+ int nonblocking;
+
+ /* Function to call if we can't allocate memory. */
+ void (*memory_error) PROTO((struct buffer *));
+};
+
+/* Data is stored in lists of these structures. */
+
+struct buffer_data
+{
+ /* Next buffer in linked list. */
+ struct buffer_data *next;
+
+ /*
+ * A pointer into the data area pointed to by the text field. This
+ * is where to find data that has not yet been written out.
+ */
+ char *bufp;
+
+ /* The number of data bytes found at BUFP. */
+ int size;
+
+ /*
+ * Actual buffer. This never changes after the structure is
+ * allocated. The buffer is BUFFER_DATA_SIZE bytes.
+ */
+ char *text;
+};
+
+/* The size we allocate for each buffer_data structure. */
+#define BUFFER_DATA_SIZE (4096)
+
+#ifdef SERVER_FLOWCONTROL
+/* The maximum we'll queue to the remote client before blocking. */
+# ifndef SERVER_HI_WATER
+# define SERVER_HI_WATER (2 * 1024 * 1024)
+# endif /* SERVER_HI_WATER */
+/* When the buffer drops to this, we restart the child */
+# ifndef SERVER_LO_WATER
+# define SERVER_LO_WATER (1 * 1024 * 1024)
+# endif /* SERVER_LO_WATER */
+#endif /* SERVER_FLOWCONTROL */
+
+/* Linked list of available buffer_data structures. */
+static struct buffer_data *free_buffer_data;
+
+static void allocate_buffer_datas PROTO((void));
+static inline struct buffer_data *get_buffer_data PROTO((void));
+static int buf_empty_p PROTO((struct buffer *));
+static void buf_output PROTO((struct buffer *, const char *, int));
+static void buf_output0 PROTO((struct buffer *, const char *));
+static inline void buf_append_char PROTO((struct buffer *, int));
+static int buf_send_output PROTO((struct buffer *));
+static int set_nonblock PROTO((struct buffer *));
+static int set_block PROTO((struct buffer *));
+static int buf_send_counted PROTO((struct buffer *));
+static inline void buf_append_data PROTO((struct buffer *,
+ struct buffer_data *,
+ struct buffer_data *));
+static int buf_read_file PROTO((FILE *, long, struct buffer_data **,
+ struct buffer_data **));
+static int buf_input_data PROTO((struct buffer *, int *));
+static void buf_copy_lines PROTO((struct buffer *, struct buffer *, int));
+static int buf_copy_counted PROTO((struct buffer *, struct buffer *));
+
+#ifdef SERVER_FLOWCONTROL
+static int buf_count_mem PROTO((struct buffer *));
+static int set_nonblock_fd PROTO((int));
+#endif /* SERVER_FLOWCONTROL */
+
+/* Allocate more buffer_data structures. */
+
+static void
+allocate_buffer_datas ()
+{
+ struct buffer_data *alc;
+ char *space;
+ int i;
+
+ /* Allocate buffer_data structures in blocks of 16. */
+#define ALLOC_COUNT (16)
+
+ alc = ((struct buffer_data *)
+ malloc (ALLOC_COUNT * sizeof (struct buffer_data)));
+ space = (char *) valloc (ALLOC_COUNT * BUFFER_DATA_SIZE);
+ if (alc == NULL || space == NULL)
+ return;
+ for (i = 0; i < ALLOC_COUNT; i++, alc++, space += BUFFER_DATA_SIZE)
+ {
+ alc->next = free_buffer_data;
+ free_buffer_data = alc;
+ alc->text = space;
+ }
+}
+
+/* Get a new buffer_data structure. */
+
+static inline struct buffer_data *
+get_buffer_data ()
+{
+ struct buffer_data *ret;
+
+ if (free_buffer_data == NULL)
+ {
+ allocate_buffer_datas ();
+ if (free_buffer_data == NULL)
+ return NULL;
+ }
+
+ ret = free_buffer_data;
+ free_buffer_data = ret->next;
+ return ret;
+}
+
+/* See whether a buffer is empty. */
+
+static int
+buf_empty_p (buf)
+ struct buffer *buf;
+{
+ struct buffer_data *data;
+
+ for (data = buf->data; data != NULL; data = data->next)
+ if (data->size > 0)
+ return 0;
+ return 1;
+}
+
+#ifdef SERVER_FLOWCONTROL
+/*
+ * Count how much data is stored in the buffer..
+ * Note that each buffer is a malloc'ed chunk BUFFER_DATA_SIZE.
+ */
+
+static int
+buf_count_mem (buf)
+ struct buffer *buf;
+{
+ struct buffer_data *data;
+ int mem = 0;
+
+ for (data = buf->data; data != NULL; data = data->next)
+ mem += BUFFER_DATA_SIZE;
+
+ return mem;
+}
+#endif /* SERVER_FLOWCONTROL */
+
+/* Add data DATA of length LEN to BUF. */
+
+static void
+buf_output (buf, data, len)
+ struct buffer *buf;
+ const char *data;
+ int len;
+{
+ if (! buf->output)
+ abort ();
+
+ if (buf->data != NULL
+ && (((buf->last->text + BUFFER_DATA_SIZE)
+ - (buf->last->bufp + buf->last->size))
+ >= len))
+ {
+ memcpy (buf->last->bufp + buf->last->size, data, len);
+ buf->last->size += len;
+ return;
+ }
+
+ while (1)
+ {
+ struct buffer_data *newdata;
+
+ newdata = get_buffer_data ();
+ if (newdata == NULL)
+ {
+ (*buf->memory_error) (buf);
+ return;
+ }
+
+ if (buf->data == NULL)
+ buf->data = newdata;
+ else
+ buf->last->next = newdata;
+ newdata->next = NULL;
+ buf->last = newdata;
+
+ newdata->bufp = newdata->text;
+
+ if (len <= BUFFER_DATA_SIZE)
+ {
+ newdata->size = len;
+ memcpy (newdata->text, data, len);
+ return;
+ }
+
+ newdata->size = BUFFER_DATA_SIZE;
+ memcpy (newdata->text, data, BUFFER_DATA_SIZE);
+
+ data += BUFFER_DATA_SIZE;
+ len -= BUFFER_DATA_SIZE;
+ }
+
+ /*NOTREACHED*/
+}
+
+/* Add a '\0' terminated string to BUF. */
+
+static void
+buf_output0 (buf, string)
+ struct buffer *buf;
+ const char *string;
+{
+ buf_output (buf, string, strlen (string));
+}
+
+/* Add a single character to BUF. */
+
+static inline void
+buf_append_char (buf, ch)
+ struct buffer *buf;
+ int ch;
+{
+ if (buf->data != NULL
+ && (buf->last->text + BUFFER_DATA_SIZE
+ != buf->last->bufp + buf->last->size))
+ {
+ *(buf->last->bufp + buf->last->size) = ch;
+ ++buf->last->size;
+ }
+ else
+ {
+ char b;
+
+ b = ch;
+ buf_output (buf, &b, 1);
+ }
+}
+
+/*
+ * Send all the output we've been saving up. Returns 0 for success or
+ * errno code. If the buffer has been set to be nonblocking, this
+ * will just write until the write would block.
+ */
+
+static int
+buf_send_output (buf)
+ struct buffer *buf;
+{
+ if (! buf->output)
+ abort ();
+
+ while (buf->data != NULL)
+ {
+ struct buffer_data *data;
+
+ data = buf->data;
+ while (data->size > 0)
+ {
+ int nbytes;
+
+ nbytes = write (buf->fd, data->bufp, data->size);
+ if (nbytes <= 0)
+ {
+ int status;
+
+ if (buf->nonblocking
+ && (nbytes == 0
+#ifdef EWOULDBLOCK
+ || errno == EWOULDBLOCK
+#endif
+ || errno == EAGAIN))
+ {
+ /*
+ * A nonblocking write failed to write any data.
+ * Just return.
+ */
+ return 0;
+ }
+
+ /*
+ * An error, or EOF. Throw away all the data and
+ * return.
+ */
+ if (nbytes == 0)
+ status = EIO;
+ else
+ status = errno;
+
+ buf->last->next = free_buffer_data;
+ free_buffer_data = buf->data;
+ buf->data = NULL;
+ buf->last = NULL;
+
+ return status;
+ }
+
+ data->size -= nbytes;
+ data->bufp += nbytes;
+ }
+
+ buf->data = data->next;
+ data->next = free_buffer_data;
+ free_buffer_data = data;
+ }
+
+ buf->last = NULL;
+
+ return 0;
+}
+
+#ifdef SERVER_FLOWCONTROL
+/*
+ * Set buffer BUF to non-blocking I/O. Returns 0 for success or errno
+ * code.
+ */
+
+static int
+set_nonblock_fd (fd)
+ int fd;
+{
+ int flags;
+
+ flags = fcntl (fd, F_GETFL, 0);
+ if (flags < 0)
+ return errno;
+ if (fcntl (fd, F_SETFL, flags | O_NONBLOCK) < 0)
+ return errno;
+ return 0;
+}
+#endif /* SERVER_FLOWCONTROL */
+
+static int
+set_nonblock (buf)
+ struct buffer *buf;
+{
+ int flags;
+
+ if (buf->nonblocking)
+ return 0;
+ flags = fcntl (buf->fd, F_GETFL, 0);
+ if (flags < 0)
+ return errno;
+ if (fcntl (buf->fd, F_SETFL, flags | O_NONBLOCK) < 0)
+ return errno;
+ buf->nonblocking = 1;
+ return 0;
+}
+
+/*
+ * Set buffer BUF to blocking I/O. Returns 0 for success or errno
+ * code.
+ */
+
+static int
+set_block (buf)
+ struct buffer *buf;
+{
+ int flags;
+
+ if (! buf->nonblocking)
+ return 0;
+ flags = fcntl (buf->fd, F_GETFL, 0);
+ if (flags < 0)
+ return errno;
+ if (fcntl (buf->fd, F_SETFL, flags & ~O_NONBLOCK) < 0)
+ return errno;
+ buf->nonblocking = 0;
+ return 0;
+}
+
+/*
+ * Send a character count and some output. Returns errno code or 0 for
+ * success.
+ *
+ * Sending the count in binary is OK since this is only used on a pipe
+ * within the same system.
+ */
+
+static int
+buf_send_counted (buf)
+ struct buffer *buf;
+{
+ int size;
+ struct buffer_data *data;
+
+ if (! buf->output)
+ abort ();
+
+ size = 0;
+ for (data = buf->data; data != NULL; data = data->next)
+ size += data->size;
+
+ data = get_buffer_data ();
+ if (data == NULL)
+ {
+ (*buf->memory_error) (buf);
+ return ENOMEM;
+ }
+
+ data->next = buf->data;
+ buf->data = data;
+ if (buf->last == NULL)
+ buf->last = data;
+
+ data->bufp = data->text;
+ data->size = sizeof (int);
+
+ *((int *) data->text) = size;
+
+ return buf_send_output (buf);
+}
+
+/* Append a list of buffer_data structures to an buffer. */
+
+static inline void
+buf_append_data (buf, data, last)
+ struct buffer *buf;
+ struct buffer_data *data;
+ struct buffer_data *last;
+{
+ if (data != NULL)
+ {
+ if (buf->data == NULL)
+ buf->data = data;
+ else
+ buf->last->next = data;
+ buf->last = last;
+ }
+}
+
+/*
+ * Copy the contents of file F into buffer_data structures. We can't
+ * copy directly into an buffer, because we want to handle failure and
+ * succeess differently. Returns 0 on success, or -2 if out of
+ * memory, or a status code on error. Since the caller happens to
+ * know the size of the file, it is passed in as SIZE. On success,
+ * this function sets *RETP and *LASTP, which may be passed to
+ * buf_append_data.
+ */
+
+static int
+buf_read_file (f, size, retp, lastp)
+ FILE *f;
+ long size;
+ struct buffer_data **retp;
+ struct buffer_data **lastp;
+{
+ int status;
+
+ *retp = NULL;
+ *lastp = NULL;
+
+ while (size > 0)
+ {
+ struct buffer_data *data;
+ int get;
+
+ data = get_buffer_data ();
+ if (data == NULL)
+ {
+ status = -2;
+ goto error_return;
+ }
+
+ if (*retp == NULL)
+ *retp = data;
+ else
+ (*lastp)->next = data;
+ data->next = NULL;
+ *lastp = data;
+
+ data->bufp = data->text;
+ data->size = 0;
+
+ if (size > BUFFER_DATA_SIZE)
+ get = BUFFER_DATA_SIZE;
+ else
+ get = size;
+
+ errno = EIO;
+ if (fread (data->text, get, 1, f) != 1)
+ {
+ status = errno;
+ goto error_return;
+ }
+
+ data->size += get;
+ size -= get;
+ }
+
+ return 0;
+
+ error_return:
+ if (*retp != NULL)
+ {
+ (*lastp)->next = free_buffer_data;
+ free_buffer_data = *retp;
+ }
+ return status;
+}
+
+static int
+buf_read_file_to_eof (f, retp, lastp)
+ FILE *f;
+ struct buffer_data **retp;
+ struct buffer_data **lastp;
+{
+ int status;
+
+ *retp = NULL;
+ *lastp = NULL;
+
+ while (!feof (f))
+ {
+ struct buffer_data *data;
+ int get, nread;
+
+ data = get_buffer_data ();
+ if (data == NULL)
+ {
+ status = -2;
+ goto error_return;
+ }
+
+ if (*retp == NULL)
+ *retp = data;
+ else
+ (*lastp)->next = data;
+ data->next = NULL;
+ *lastp = data;
+
+ data->bufp = data->text;
+ data->size = 0;
+
+ get = BUFFER_DATA_SIZE;
+
+ errno = EIO;
+ nread = fread (data->text, 1, get, f);
+ if (nread == 0 && !feof (f))
+ {
+ status = errno;
+ goto error_return;
+ }
+
+ data->size = nread;
+ }
+
+ return 0;
+
+ error_return:
+ if (*retp != NULL)
+ {
+ (*lastp)->next = free_buffer_data;
+ free_buffer_data = *retp;
+ }
+ return status;
+}
+
+static int
+buf_chain_length (buf)
+ struct buffer_data *buf;
+{
+ int size = 0;
+ while (buf)
+ {
+ size += buf->size;
+ buf = buf->next;
+ }
+ return size;
+}
+
+/*
+ * Read an arbitrary amount of data from a file descriptor into an
+ * input buffer. The file descriptor will be in nonblocking mode, and
+ * we just grab what we can. Return 0 on success, or -1 on end of
+ * file, or -2 if out of memory, or an error code. If COUNTP is not
+ * NULL, *COUNTP is set to the number of bytes read.
+ */
+
+static int
+buf_input_data (buf, countp)
+ struct buffer *buf;
+ int *countp;
+{
+ if (buf->output)
+ abort ();
+
+ if (countp != NULL)
+ *countp = 0;
+
+ while (1)
+ {
+ int get;
+ int nbytes;
+
+ if (buf->data == NULL
+ || (buf->last->bufp + buf->last->size
+ == buf->last->text + BUFFER_DATA_SIZE))
+ {
+ struct buffer_data *data;
+
+ data = get_buffer_data ();
+ if (data == NULL)
+ {
+ (*buf->memory_error) (buf);
+ return -2;
+ }
+
+ if (buf->data == NULL)
+ buf->data = data;
+ else
+ buf->last->next = data;
+ data->next = NULL;
+ buf->last = data;
+
+ data->bufp = data->text;
+ data->size = 0;
+ }
+
+ get = ((buf->last->text + BUFFER_DATA_SIZE)
+ - (buf->last->bufp + buf->last->size));
+ nbytes = read (buf->fd, buf->last->bufp + buf->last->size, get);
+ if (nbytes <= 0)
+ {
+ if (nbytes == 0)
+ {
+ /*
+ * This assumes that we are using POSIX or BSD style
+ * nonblocking I/O. On System V we will get a zero
+ * return if there is no data, even when not at EOF.
+ */
+ return -1;
+ }
+
+ if (errno == EAGAIN
+#ifdef EWOULDBLOCK
+ || errno == EWOULDBLOCK
+#endif
+ )
+ return 0;
+
+ return errno;
+ }
+
+ buf->last->size += nbytes;
+ if (countp != NULL)
+ *countp += nbytes;
+ }
+
+ /*NOTREACHED*/
+}
+
+/*
+ * Copy lines from an input buffer to an output buffer. This copies
+ * all complete lines (characters up to a newline) from INBUF to
+ * OUTBUF. Each line in OUTBUF is preceded by the character COMMAND
+ * and a space.
+ */
+
+static void
+buf_copy_lines (outbuf, inbuf, command)
+ struct buffer *outbuf;
+ struct buffer *inbuf;
+ int command;
+{
+ if (! outbuf->output || inbuf->output)
+ abort ();
+
+ while (1)
+ {
+ struct buffer_data *data;
+ struct buffer_data *nldata;
+ char *nl;
+ int len;
+
+ /* See if there is a newline in INBUF. */
+ nldata = NULL;
+ nl = NULL;
+ for (data = inbuf->data; data != NULL; data = data->next)
+ {
+ nl = memchr (data->bufp, '\n', data->size);
+ if (nl != NULL)
+ {
+ nldata = data;
+ break;
+ }
+ }
+
+ if (nldata == NULL)
+ {
+ /* There are no more lines in INBUF. */
+ return;
+ }
+
+ /* Put in the command. */
+ buf_append_char (outbuf, command);
+ buf_append_char (outbuf, ' ');
+
+ if (inbuf->data != nldata)
+ {
+ /*
+ * Simply move over all the buffers up to the one containing
+ * the newline.
+ */
+ for (data = inbuf->data; data->next != nldata; data = data->next)
+ ;
+ data->next = NULL;
+ buf_append_data (outbuf, inbuf->data, data);
+ inbuf->data = nldata;
+ }
+
+ /*
+ * If the newline is at the very end of the buffer, just move
+ * the buffer onto OUTBUF. Otherwise we must copy the data.
+ */
+ len = nl + 1 - nldata->bufp;
+ if (len == nldata->size)
+ {
+ inbuf->data = nldata->next;
+ if (inbuf->data == NULL)
+ inbuf->last = NULL;
+
+ nldata->next = NULL;
+ buf_append_data (outbuf, nldata, nldata);
+ }
+ else
+ {
+ buf_output (outbuf, nldata->bufp, len);
+ nldata->bufp += len;
+ nldata->size -= len;
+ }
+ }
+}
+
+/*
+ * Copy counted data from one buffer to another. The count is an
+ * integer, host size, host byte order (it is only used across a
+ * pipe). If there is enough data, it should be moved over. If there
+ * is not enough data, it should remain on the original buffer. This
+ * returns the number of bytes it needs to see in order to actually
+ * copy something over.
+ */
+
+static int
+buf_copy_counted (outbuf, inbuf)
+ struct buffer *outbuf;
+ struct buffer *inbuf;
+{
+ if (! outbuf->output || inbuf->output)
+ abort ();
+
+ while (1)
+ {
+ struct buffer_data *data;
+ int need;
+ union
+ {
+ char intbuf[sizeof (int)];
+ int i;
+ } u;
+ char *intp;
+ int count;
+ struct buffer_data *start;
+ int startoff;
+ struct buffer_data *stop;
+ int stopwant;
+
+ /* See if we have enough bytes to figure out the count. */
+ need = sizeof (int);
+ intp = u.intbuf;
+ for (data = inbuf->data; data != NULL; data = data->next)
+ {
+ if (data->size >= need)
+ {
+ memcpy (intp, data->bufp, need);
+ break;
+ }
+ memcpy (intp, data->bufp, data->size);
+ intp += data->size;
+ need -= data->size;
+ }
+ if (data == NULL)
+ {
+ /* We don't have enough bytes to form an integer. */
+ return need;
+ }
+
+ count = u.i;
+ start = data;
+ startoff = need;
+
+ /*
+ * We have an integer in COUNT. We have gotten all the data
+ * from INBUF in all buffers before START, and we have gotten
+ * STARTOFF bytes from START. See if we have enough bytes
+ * remaining in INBUF.
+ */
+ need = count - (start->size - startoff);
+ if (need <= 0)
+ {
+ stop = start;
+ stopwant = count;
+ }
+ else
+ {
+ for (data = start->next; data != NULL; data = data->next)
+ {
+ if (need <= data->size)
+ break;
+ need -= data->size;
+ }
+ if (data == NULL)
+ {
+ /* We don't have enough bytes. */
+ return need;
+ }
+ stop = data;
+ stopwant = need;
+ }
+
+ /*
+ * We have enough bytes. Free any buffers in INBUF before
+ * START, and remove STARTOFF bytes from START, so that we can
+ * forget about STARTOFF.
+ */
+ start->bufp += startoff;
+ start->size -= startoff;
+
+ if (start->size == 0)
+ start = start->next;
+
+ if (stop->size == stopwant)
+ {
+ stop = stop->next;
+ stopwant = 0;
+ }
+
+ while (inbuf->data != start)
+ {
+ data = inbuf->data;
+ inbuf->data = data->next;
+ data->next = free_buffer_data;
+ free_buffer_data = data;
+ }
+
+ /*
+ * We want to copy over the bytes from START through STOP. We
+ * only want STOPWANT bytes from STOP.
+ */
+
+ if (start != stop)
+ {
+ /* Attach the buffers from START through STOP to OUTBUF. */
+ for (data = start; data->next != stop; data = data->next)
+ ;
+ inbuf->data = stop;
+ data->next = NULL;
+ buf_append_data (outbuf, start, data);
+ }
+
+ if (stopwant > 0)
+ {
+ buf_output (outbuf, stop->bufp, stopwant);
+ stop->bufp += stopwant;
+ stop->size -= stopwant;
+ }
+ }
+
+ /*NOTREACHED*/
+}
+
+static struct buffer protocol;
+
+static void
+protocol_memory_error (buf)
+ struct buffer *buf;
+{
+ error (1, ENOMEM, "Virtual memory exhausted");
+}
+
+/*
+ * Process IDs of the subprocess, or negative if that subprocess
+ * does not exist.
+ */
+static pid_t command_pid;
+
+static void
+outbuf_memory_error (buf)
+ struct buffer *buf;
+{
+ static const char msg[] = "E Fatal server error\n\
+error ENOMEM Virtual memory exhausted.\n";
+ if (command_pid > 0)
+ kill (command_pid, SIGTERM);
+
+ /*
+ * We have arranged things so that printing this now either will
+ * be legal, or the "E fatal error" line will get glommed onto the
+ * end of an existing "E" or "M" response.
+ */
+
+ /* If this gives an error, not much we could do. syslog() it? */
+ write (STDOUT_FILENO, msg, sizeof (msg) - 1);
+ server_cleanup (0);
+ exit (1);
+}
+
+static void
+input_memory_error (buf)
+ struct buffer *buf;
+{
+ outbuf_memory_error (buf);
+}
+
+/* Execute COMMAND in a subprocess with the approriate funky things done. */
+
+static struct fd_set_wrapper { fd_set fds; } command_fds_to_drain;
+static int max_command_fd;
+
+#ifdef SERVER_FLOWCONTROL
+static int flowcontrol_pipe[2];
+#endif /* SERVER_FLOWCONTROL */
+
+static void
+do_cvs_command (command)
+ int (*command) PROTO((int argc, char **argv));
+{
+ /*
+ * The following file descriptors are set to -1 if that file is not
+ * currently open.
+ */
+
+ /* Data on these pipes is a series of '\n'-terminated lines. */
+ int stdout_pipe[2];
+ int stderr_pipe[2];
+
+ /*
+ * Data on this pipe is a series of counted (see buf_send_counted)
+ * packets. Each packet must be processed atomically (i.e. not
+ * interleaved with data from stdout_pipe or stderr_pipe).
+ */
+ int protocol_pipe[2];
+
+ int dev_null_fd = -1;
+
+ int errs;
+
+ command_pid = -1;
+ stdout_pipe[0] = -1;
+ stdout_pipe[1] = -1;
+ stderr_pipe[0] = -1;
+ stderr_pipe[1] = -1;
+ protocol_pipe[0] = -1;
+ protocol_pipe[1] = -1;
+
+ server_write_entries ();
+
+ if (print_pending_error ())
+ goto free_args_and_return;
+
+ /*
+ * We use a child process which actually does the operation. This
+ * is so we can intercept its standard output. Even if all of CVS
+ * were written to go to some special routine instead of writing
+ * to stdout or stderr, we would still need to do the same thing
+ * for the RCS commands.
+ */
+
+ if (pipe (stdout_pipe) < 0)
+ {
+ print_error (errno);
+ goto error_exit;
+ }
+ if (pipe (stderr_pipe) < 0)
+ {
+ print_error (errno);
+ goto error_exit;
+ }
+ if (pipe (protocol_pipe) < 0)
+ {
+ print_error (errno);
+ goto error_exit;
+ }
+#ifdef SERVER_FLOWCONTROL
+ if (pipe (flowcontrol_pipe) < 0)
+ {
+ print_error (errno);
+ goto error_exit;
+ }
+ set_nonblock_fd (flowcontrol_pipe[0]);
+ set_nonblock_fd (flowcontrol_pipe[1]);
+#endif /* SERVER_FLOWCONTROL */
+
+ dev_null_fd = open ("/dev/null", O_RDONLY);
+ if (dev_null_fd < 0)
+ {
+ print_error (errno);
+ goto error_exit;
+ }
+
+ /* Don't use vfork; we're not going to exec(). */
+ command_pid = fork ();
+ if (command_pid < 0)
+ {
+ print_error (errno);
+ goto error_exit;
+ }
+ if (command_pid == 0)
+ {
+ int exitstatus;
+
+ /* Since we're in the child, and the parent is going to take
+ care of packaging up our error messages, we can clear this
+ flag. */
+ error_use_protocol = 0;
+
+ protocol.data = protocol.last = NULL;
+ protocol.fd = protocol_pipe[1];
+ protocol.output = 1;
+ protocol.nonblocking = 0;
+ protocol.memory_error = protocol_memory_error;
+
+ if (dup2 (dev_null_fd, STDIN_FILENO) < 0)
+ error (1, errno, "can't set up pipes");
+ if (dup2 (stdout_pipe[1], STDOUT_FILENO) < 0)
+ error (1, errno, "can't set up pipes");
+ if (dup2 (stderr_pipe[1], STDERR_FILENO) < 0)
+ error (1, errno, "can't set up pipes");
+ close (stdout_pipe[0]);
+ close (stderr_pipe[0]);
+ close (protocol_pipe[0]);
+#ifdef SERVER_FLOWCONTROL
+ close (flowcontrol_pipe[1]);
+#endif /* SERVER_FLOWCONTROL */
+
+ /*
+ * Set this in .bashrc if you want to give yourself time to attach
+ * to the subprocess with a debugger.
+ */
+ if (getenv ("CVS_SERVER_SLEEP"))
+ {
+ int secs = atoi (getenv ("CVS_SERVER_SLEEP"));
+ sleep (secs);
+ }
+
+ exitstatus = (*command) (argument_count, argument_vector);
+
+ /*
+ * When we exit, that will close the pipes, giving an EOF to
+ * the parent.
+ */
+ exit (exitstatus);
+ }
+
+ /* OK, sit around getting all the input from the child. */
+ {
+ struct buffer outbuf;
+ struct buffer stdoutbuf;
+ struct buffer stderrbuf;
+ struct buffer protocol_inbuf;
+ /* Number of file descriptors to check in select (). */
+ int num_to_check;
+ int count_needed = 0;
+#ifdef SERVER_FLOWCONTROL
+ int have_flowcontrolled = 0;
+#endif /* SERVER_FLOWCONTROL */
+
+ FD_ZERO (&command_fds_to_drain.fds);
+ num_to_check = stdout_pipe[0];
+ FD_SET (stdout_pipe[0], &command_fds_to_drain.fds);
+ if (stderr_pipe[0] > num_to_check)
+ num_to_check = stderr_pipe[0];
+ FD_SET (stderr_pipe[0], &command_fds_to_drain.fds);
+ if (protocol_pipe[0] > num_to_check)
+ num_to_check = protocol_pipe[0];
+ FD_SET (protocol_pipe[0], &command_fds_to_drain.fds);
+ if (STDOUT_FILENO > num_to_check)
+ num_to_check = STDOUT_FILENO;
+ max_command_fd = num_to_check;
+ /*
+ * File descriptors are numbered from 0, so num_to_check needs to
+ * be one larger than the largest descriptor.
+ */
+ ++num_to_check;
+ if (num_to_check > FD_SETSIZE)
+ {
+ printf ("E internal error: FD_SETSIZE not big enough.\nerror \n");
+ goto error_exit;
+ }
+
+ outbuf.data = outbuf.last = NULL;
+ outbuf.fd = STDOUT_FILENO;
+ outbuf.output = 1;
+ outbuf.nonblocking = 0;
+ outbuf.memory_error = outbuf_memory_error;
+
+ stdoutbuf.data = stdoutbuf.last = NULL;
+ stdoutbuf.fd = stdout_pipe[0];
+ stdoutbuf.output = 0;
+ stdoutbuf.nonblocking = 0;
+ stdoutbuf.memory_error = input_memory_error;
+
+ stderrbuf.data = stderrbuf.last = NULL;
+ stderrbuf.fd = stderr_pipe[0];
+ stderrbuf.output = 0;
+ stderrbuf.nonblocking = 0;
+ stderrbuf.memory_error = input_memory_error;
+
+ protocol_inbuf.data = protocol_inbuf.last = NULL;
+ protocol_inbuf.fd = protocol_pipe[0];
+ protocol_inbuf.output = 0;
+ protocol_inbuf.nonblocking = 0;
+ protocol_inbuf.memory_error = input_memory_error;
+
+ set_nonblock (&outbuf);
+ set_nonblock (&stdoutbuf);
+ set_nonblock (&stderrbuf);
+ set_nonblock (&protocol_inbuf);
+
+ if (close (stdout_pipe[1]) < 0)
+ {
+ print_error (errno);
+ goto error_exit;
+ }
+ stdout_pipe[1] = -1;
+
+ if (close (stderr_pipe[1]) < 0)
+ {
+ print_error (errno);
+ goto error_exit;
+ }
+ stderr_pipe[1] = -1;
+
+ if (close (protocol_pipe[1]) < 0)
+ {
+ print_error (errno);
+ goto error_exit;
+ }
+ protocol_pipe[1] = -1;
+
+#ifdef SERVER_FLOWCONTROL
+ if (close (flowcontrol_pipe[0]) < 0)
+ {
+ print_error (errno);
+ goto error_exit;
+ }
+ flowcontrol_pipe[0] = -1;
+#endif /* SERVER_FLOWCONTROL */
+
+ if (close (dev_null_fd) < 0)
+ {
+ print_error (errno);
+ goto error_exit;
+ }
+ dev_null_fd = -1;
+
+ while (stdout_pipe[0] >= 0
+ || stderr_pipe[0] >= 0
+ || protocol_pipe[0] >= 0)
+ {
+ fd_set readfds;
+ fd_set writefds;
+ int numfds;
+#ifdef SERVER_FLOWCONTROL
+ int bufmemsize;
+
+ /*
+ * See if we are swamping the remote client and filling our VM.
+ * Tell child to hold off if we do.
+ */
+ bufmemsize = buf_count_mem (&outbuf);
+ if (!have_flowcontrolled && (bufmemsize > SERVER_HI_WATER))
+ {
+ if (write(flowcontrol_pipe[1], "S", 1) == 1)
+ have_flowcontrolled = 1;
+ }
+ else if (have_flowcontrolled && (bufmemsize < SERVER_LO_WATER))
+ {
+ if (write(flowcontrol_pipe[1], "G", 1) == 1)
+ have_flowcontrolled = 0;
+ }
+#endif /* SERVER_FLOWCONTROL */
+
+ FD_ZERO (&readfds);
+ FD_ZERO (&writefds);
+ if (! buf_empty_p (&outbuf))
+ FD_SET (STDOUT_FILENO, &writefds);
+
+ if (stdout_pipe[0] >= 0)
+ {
+ FD_SET (stdout_pipe[0], &readfds);
+ }
+ if (stderr_pipe[0] >= 0)
+ {
+ FD_SET (stderr_pipe[0], &readfds);
+ }
+ if (protocol_pipe[0] >= 0)
+ {
+ FD_SET (protocol_pipe[0], &readfds);
+ }
+
+ do {
+ /* This used to select on exceptions too, but as far
+ as I know there was never any reason to do that and
+ SCO doesn't let you select on exceptions on pipes. */
+ numfds = select (num_to_check, &readfds, &writefds,
+ (fd_set *)0, (struct timeval *)NULL);
+ if (numfds < 0
+ && errno != EINTR)
+ {
+ print_error (errno);
+ goto error_exit;
+ }
+ } while (numfds < 0);
+
+ if (FD_ISSET (STDOUT_FILENO, &writefds))
+ {
+ /* What should we do with errors? syslog() them? */
+ buf_send_output (&outbuf);
+ }
+
+ if (stdout_pipe[0] >= 0
+ && (FD_ISSET (stdout_pipe[0], &readfds)))
+ {
+ int status;
+
+ status = buf_input_data (&stdoutbuf, (int *) NULL);
+
+ buf_copy_lines (&outbuf, &stdoutbuf, 'M');
+
+ if (status == -1)
+ stdout_pipe[0] = -1;
+ else if (status > 0)
+ {
+ print_error (status);
+ goto error_exit;
+ }
+
+ /* What should we do with errors? syslog() them? */
+ buf_send_output (&outbuf);
+ }
+
+ if (stderr_pipe[0] >= 0
+ && (FD_ISSET (stderr_pipe[0], &readfds)))
+ {
+ int status;
+
+ status = buf_input_data (&stderrbuf, (int *) NULL);
+
+ buf_copy_lines (&outbuf, &stderrbuf, 'E');
+
+ if (status == -1)
+ stderr_pipe[0] = -1;
+ else if (status > 0)
+ {
+ print_error (status);
+ goto error_exit;
+ }
+
+ /* What should we do with errors? syslog() them? */
+ buf_send_output (&outbuf);
+ }
+
+ if (protocol_pipe[0] >= 0
+ && (FD_ISSET (protocol_pipe[0], &readfds)))
+ {
+ int status;
+ int count_read;
+
+ status = buf_input_data (&protocol_inbuf, &count_read);
+
+ /*
+ * We only call buf_copy_counted if we have read
+ * enough bytes to make it worthwhile. This saves us
+ * from continually recounting the amount of data we
+ * have.
+ */
+ count_needed -= count_read;
+ if (count_needed <= 0)
+ count_needed = buf_copy_counted (&outbuf, &protocol_inbuf);
+
+ if (status == -1)
+ protocol_pipe[0] = -1;
+ else if (status > 0)
+ {
+ print_error (status);
+ goto error_exit;
+ }
+
+ /* What should we do with errors? syslog() them? */
+ buf_send_output (&outbuf);
+ }
+ }
+
+ /*
+ * OK, we've gotten EOF on all the pipes. If there is
+ * anything left on stdoutbuf or stderrbuf (this could only
+ * happen if there was no trailing newline), send it over.
+ */
+ if (! buf_empty_p (&stdoutbuf))
+ {
+ buf_append_char (&stdoutbuf, '\n');
+ buf_copy_lines (&outbuf, &stdoutbuf, 'M');
+ }
+ if (! buf_empty_p (&stderrbuf))
+ {
+ buf_append_char (&stderrbuf, '\n');
+ buf_copy_lines (&outbuf, &stderrbuf, 'E');
+ }
+ if (! buf_empty_p (&protocol_inbuf))
+ buf_output0 (&outbuf,
+ "E Protocol error: uncounted data discarded\n");
+
+ errs = 0;
+
+ while (command_pid > 0)
+ {
+ int status;
+ pid_t waited_pid;
+ waited_pid = waitpid (command_pid, &status, 0);
+ if (waited_pid < 0)
+ {
+ /*
+ * Intentionally ignoring EINTR. Other errors
+ * "can't happen".
+ */
+ continue;
+ }
+
+ if (WIFEXITED (status))
+ errs += WEXITSTATUS (status);
+ else
+ {
+ int sig = WTERMSIG (status);
+ /*
+ * This is really evil, because signals might be numbered
+ * differently on the two systems. We should be using
+ * signal names (either of the "Terminated" or the "SIGTERM"
+ * variety). But cvs doesn't currently use libiberty...we
+ * could roll our own.... FIXME.
+ */
+ printf ("E Terminated with fatal signal %d\n", sig);
+
+ /* Test for a core dump. Is this portable? */
+ if (status & 0x80)
+ {
+ printf ("E Core dumped; preserving %s on server.\n\
+E CVS locks may need cleaning up.\n",
+ server_temp_dir);
+ dont_delete_temp = 1;
+ }
+ ++errs;
+ }
+ if (waited_pid == command_pid)
+ command_pid = -1;
+ }
+
+ /*
+ * OK, we've waited for the child. By now all CVS locks are free
+ * and it's OK to block on the network.
+ */
+ set_block (&outbuf);
+ buf_send_output (&outbuf);
+ }
+
+ if (errs)
+ /* We will have printed an error message already. */
+ printf ("error \n");
+ else
+ printf ("ok\n");
+ goto free_args_and_return;
+
+ error_exit:
+ if (command_pid > 0)
+ kill (command_pid, SIGTERM);
+
+ while (command_pid > 0)
+ {
+ pid_t waited_pid;
+ waited_pid = waitpid (command_pid, (int *) 0, 0);
+ if (waited_pid < 0 && errno == EINTR)
+ continue;
+ if (waited_pid == command_pid)
+ command_pid = -1;
+ }
+
+ close (dev_null_fd);
+ close (protocol_pipe[0]);
+ close (protocol_pipe[1]);
+ close (stderr_pipe[0]);
+ close (stderr_pipe[1]);
+ close (stdout_pipe[0]);
+ close (stdout_pipe[1]);
+
+ free_args_and_return:
+ /* Now free the arguments. */
+ {
+ /* argument_vector[0] is a dummy argument, we don't mess with it. */
+ char **cp;
+ for (cp = argument_vector + 1;
+ cp < argument_vector + argument_count;
+ ++cp)
+ free (*cp);
+
+ argument_count = 1;
+ }
+ return;
+}
+
+#ifdef SERVER_FLOWCONTROL
+/*
+ * Called by the child at convenient points in the server's execution for
+ * the server child to block.. ie: when it has no locks active.
+ */
+void
+server_pause_check()
+{
+ int paused = 0;
+ char buf[1];
+
+ while (read (flowcontrol_pipe[0], buf, 1) == 1)
+ {
+ if (*buf == 'S') /* Stop */
+ paused = 1;
+ else if (*buf == 'G') /* Go */
+ paused = 0;
+ else
+ return; /* ??? */
+ }
+ while (paused) {
+ int numfds, numtocheck;
+ fd_set fds;
+
+ FD_ZERO (&fds);
+ FD_SET (flowcontrol_pipe[0], &fds);
+ numtocheck = flowcontrol_pipe[0] + 1;
+
+ do {
+ numfds = select (numtocheck, &fds, (fd_set *)0,
+ (fd_set *)0, (struct timeval *)NULL);
+ if (numfds < 0
+ && errno != EINTR)
+ {
+ print_error (errno);
+ return;
+ }
+ } while (numfds < 0);
+
+ if (FD_ISSET (flowcontrol_pipe[0], &fds))
+ {
+ while (read (flowcontrol_pipe[0], buf, 1) == 1)
+ {
+ if (*buf == 'S') /* Stop */
+ paused = 1;
+ else if (*buf == 'G') /* Go */
+ paused = 0;
+ else
+ return; /* ??? */
+ }
+ }
+ }
+}
+#endif /* SERVER_FLOWCONTROL */
+
+static void output_dir PROTO((char *, char *));
+
+static void
+output_dir (update_dir, repository)
+ char *update_dir;
+ char *repository;
+{
+ if (use_dir_and_repos)
+ {
+ if (update_dir[0] == '\0')
+ buf_output0 (&protocol, ".");
+ else
+ buf_output0 (&protocol, update_dir);
+ buf_output0 (&protocol, "/\n");
+ }
+ buf_output0 (&protocol, repository);
+ buf_output0 (&protocol, "/");
+}
+
+/*
+ * Entries line that we are squirreling away to send to the client when
+ * we are ready.
+ */
+static char *entries_line;
+
+/*
+ * File which has been Scratch_File'd, we are squirreling away that fact
+ * to inform the client when we are ready.
+ */
+static char *scratched_file;
+
+/*
+ * The scratched_file will need to be removed as well as having its entry
+ * removed.
+ */
+static int kill_scratched_file;
+
+void
+server_register (name, version, timestamp, options, tag, date, conflict)
+ char *name;
+ char *version;
+ char *timestamp;
+ char *options;
+ char *tag;
+ char *date;
+ char *conflict;
+{
+ int len;
+
+ if (trace)
+ {
+ (void) fprintf (stderr,
+ "%c-> server_register(%s, %s, %s, %s, %s, %s, %s)\n",
+ (server_active) ? 'S' : ' ', /* silly */
+ name, version, timestamp, options, tag ? tag : "",
+ date ? date : "", conflict ? conflict : "");
+ }
+
+ if (options == NULL)
+ options = "";
+
+ if (entries_line != NULL)
+ {
+ /*
+ * If CVS decides to Register it more than once (which happens
+ * on "cvs update foo/foo.c" where foo and foo.c are already
+ * checked out), use the last of the entries lines Register'd.
+ */
+ free (entries_line);
+ }
+
+ /*
+ * I have reports of Scratch_Entry and Register both happening, in
+ * two different cases. Using the last one which happens is almost
+ * surely correct; I haven't tracked down why they both happen (or
+ * even verified that they are for the same file).
+ */
+ if (scratched_file != NULL)
+ {
+ free (scratched_file);
+ scratched_file = NULL;
+ }
+
+ len = (strlen (name) + strlen (version) + strlen (options) + 80);
+ if (tag)
+ len += strlen (tag);
+ if (date)
+ len += strlen (date);
+
+ entries_line = xmalloc (len);
+ sprintf (entries_line, "/%s/%s/", name, version);
+ if (conflict != NULL)
+ {
+ strcat (entries_line, "+=");
+ }
+ strcat (entries_line, "/");
+ strcat (entries_line, options);
+ strcat (entries_line, "/");
+ if (tag != NULL)
+ {
+ strcat (entries_line, "T");
+ strcat (entries_line, tag);
+ }
+ else if (date != NULL)
+ {
+ strcat (entries_line, "D");
+ strcat (entries_line, date);
+ }
+}
+
+void
+server_scratch (fname)
+ char *fname;
+{
+ /*
+ * I have reports of Scratch_Entry and Register both happening, in
+ * two different cases. Using the last one which happens is almost
+ * surely correct; I haven't tracked down why they both happen (or
+ * even verified that they are for the same file).
+ */
+ if (entries_line != NULL)
+ {
+ free (entries_line);
+ entries_line = NULL;
+ }
+
+ if (scratched_file != NULL)
+ {
+ buf_output0 (&protocol,
+ "E CVS server internal error: duplicate Scratch_Entry\n");
+ buf_send_counted (&protocol);
+ return;
+ }
+ scratched_file = xstrdup (fname);
+ kill_scratched_file = 1;
+}
+
+void
+server_scratch_entry_only ()
+{
+ kill_scratched_file = 0;
+}
+
+/* Print a new entries line, from a previous server_register. */
+static void
+new_entries_line ()
+{
+ if (entries_line)
+ {
+ buf_output0 (&protocol, entries_line);
+ buf_output (&protocol, "\n", 1);
+ }
+ else
+ /* Return the error message as the Entries line. */
+ buf_output0 (&protocol,
+ "CVS server internal error: Register missing\n");
+ free (entries_line);
+ entries_line = NULL;
+}
+
+static void
+serve_ci (arg)
+ char *arg;
+{
+ do_cvs_command (commit);
+}
+
+void
+server_checked_in (file, update_dir, repository)
+ char *file;
+ char *update_dir;
+ char *repository;
+{
+ if (noexec)
+ return;
+ if (scratched_file != NULL && entries_line == NULL)
+ {
+ /*
+ * This happens if we are now doing a "cvs remove" after a previous
+ * "cvs add" (without a "cvs ci" in between).
+ */
+ buf_output0 (&protocol, "Remove-entry ");
+ output_dir (update_dir, repository);
+ buf_output0 (&protocol, file);
+ buf_output (&protocol, "\n", 1);
+ free (scratched_file);
+ scratched_file = NULL;
+ }
+ else
+ {
+ buf_output0 (&protocol, "Checked-in ");
+ output_dir (update_dir, repository);
+ buf_output0 (&protocol, file);
+ buf_output (&protocol, "\n", 1);
+ new_entries_line ();
+ }
+ buf_send_counted (&protocol);
+}
+
+void
+server_update_entries (file, update_dir, repository, updated)
+ char *file;
+ char *update_dir;
+ char *repository;
+ enum server_updated_arg4 updated;
+{
+ if (noexec)
+ return;
+ if (updated == SERVER_UPDATED)
+ buf_output0 (&protocol, "Checked-in ");
+ else
+ {
+ if (!supported_response ("New-entry"))
+ return;
+ buf_output0 (&protocol, "New-entry ");
+ }
+
+ output_dir (update_dir, repository);
+ buf_output0 (&protocol, file);
+ buf_output (&protocol, "\n", 1);
+ new_entries_line ();
+ buf_send_counted (&protocol);
+}
+
+static void
+serve_update (arg)
+ char *arg;
+{
+ do_cvs_command (update);
+}
+
+static void
+serve_diff (arg)
+ char *arg;
+{
+ do_cvs_command (diff);
+}
+
+static void
+serve_log (arg)
+ char *arg;
+{
+ do_cvs_command (cvslog);
+}
+
+static void
+serve_add (arg)
+ char *arg;
+{
+ do_cvs_command (add);
+}
+
+static void
+serve_remove (arg)
+ char *arg;
+{
+ do_cvs_command (cvsremove);
+}
+
+static void
+serve_status (arg)
+ char *arg;
+{
+ do_cvs_command (status);
+}
+
+static void
+serve_rdiff (arg)
+ char *arg;
+{
+ do_cvs_command (patch);
+}
+
+static void
+serve_tag (arg)
+ char *arg;
+{
+ do_cvs_command (tag);
+}
+
+static void
+serve_rtag (arg)
+ char *arg;
+{
+ do_cvs_command (rtag);
+}
+
+static void
+serve_import (arg)
+ char *arg;
+{
+ do_cvs_command (import);
+}
+
+static void
+serve_admin (arg)
+ char *arg;
+{
+ do_cvs_command (admin);
+}
+
+static void
+serve_history (arg)
+ char *arg;
+{
+ do_cvs_command (history);
+}
+
+static void
+serve_release (arg)
+ char *arg;
+{
+ do_cvs_command (release);
+}
+
+static void
+serve_co (arg)
+ char *arg;
+{
+ char *tempdir;
+ int status;
+
+ if (print_pending_error ())
+ return;
+
+ if (!isdir (CVSADM))
+ {
+ /*
+ * The client has not sent a "Repository" line. Check out
+ * into a pristine directory.
+ */
+ tempdir = malloc (strlen (server_temp_dir) + 80);
+ if (tempdir == NULL)
+ {
+ printf ("E Out of memory\n");
+ return;
+ }
+ strcpy (tempdir, server_temp_dir);
+ strcat (tempdir, "/checkout-dir");
+ status = mkdir_p (tempdir);
+ if (status != 0 && status != EEXIST)
+ {
+ printf ("E Cannot create %s\n", tempdir);
+ print_error (errno);
+ free (tempdir);
+ return;
+ }
+
+ if (chdir (tempdir) < 0)
+ {
+ printf ("E Cannot change to directory %s\n", tempdir);
+ print_error (errno);
+ free (tempdir);
+ return;
+ }
+ free (tempdir);
+ }
+ do_cvs_command (checkout);
+}
+
+static void
+serve_export (arg)
+ char *arg;
+{
+ /* Tell checkout() to behave like export not checkout. */
+ command_name = "export";
+ serve_co (arg);
+}
+
+void
+server_copy_file (file, update_dir, repository, newfile)
+ char *file;
+ char *update_dir;
+ char *repository;
+ char *newfile;
+{
+ if (!supported_response ("Copy-file"))
+ return;
+ buf_output0 (&protocol, "Copy-file ");
+ output_dir (update_dir, repository);
+ buf_output0 (&protocol, file);
+ buf_output0 (&protocol, "\n");
+ buf_output0 (&protocol, newfile);
+ buf_output0 (&protocol, "\n");
+}
+
+void
+server_updated (file, update_dir, repository, updated, file_info, checksum)
+ char *file;
+ char *update_dir;
+ char *repository;
+ enum server_updated_arg4 updated;
+ struct stat *file_info;
+ unsigned char *checksum;
+{
+ char *short_pathname;
+
+ if (noexec)
+ return;
+
+ short_pathname = xmalloc (strlen (update_dir) + strlen (file) + 10);
+ if (update_dir[0] == '\0')
+ strcpy (short_pathname, file);
+ else
+ sprintf (short_pathname, "%s/%s", update_dir, file);
+
+ if (entries_line != NULL && scratched_file == NULL)
+ {
+ FILE *f;
+ struct stat sb;
+ struct buffer_data *list, *last;
+ unsigned long size;
+ char size_text[80];
+
+ if (stat (file, &sb) < 0)
+ {
+ if (existence_error (errno))
+ {
+ /*
+ * If we have a sticky tag for a branch on which the
+ * file is dead, and cvs update the directory, it gets
+ * a T_CHECKOUT but no file. So in this case just
+ * forget the whole thing.
+ */
+ free (entries_line);
+ entries_line = NULL;
+ goto done;
+ }
+ error (1, errno, "reading %s", short_pathname);
+ }
+
+ if (checksum != NULL)
+ {
+ static int checksum_supported = -1;
+
+ if (checksum_supported == -1)
+ {
+ checksum_supported = supported_response ("Checksum");
+ }
+
+ if (checksum_supported)
+ {
+ int i;
+ char buf[3];
+
+ buf_output0 (&protocol, "Checksum ");
+ for (i = 0; i < 16; i++)
+ {
+ sprintf (buf, "%02x", (unsigned int) checksum[i]);
+ buf_output0 (&protocol, buf);
+ }
+ buf_append_char (&protocol, '\n');
+ }
+ }
+
+ if (updated == SERVER_UPDATED)
+ buf_output0 (&protocol, "Updated ");
+ else if (updated == SERVER_MERGED)
+ buf_output0 (&protocol, "Merged ");
+ else if (updated == SERVER_PATCHED)
+ buf_output0 (&protocol, "Patched ");
+ else
+ abort ();
+ output_dir (update_dir, repository);
+ buf_output0 (&protocol, file);
+ buf_output (&protocol, "\n", 1);
+
+ new_entries_line ();
+
+ {
+ char *mode_string;
+
+ /* FIXME: When we check out files the umask of the server
+ (set in .bashrc if rsh is in use, or set in main.c in
+ the kerberos case, I think) affects what mode we send,
+ and it shouldn't. */
+ if (file_info != NULL)
+ mode_string = mode_to_string (file_info->st_mode);
+ else
+ mode_string = mode_to_string (sb.st_mode);
+ buf_output0 (&protocol, mode_string);
+ buf_output0 (&protocol, "\n");
+ free (mode_string);
+ }
+
+ list = last = NULL;
+ size = 0;
+ if (sb.st_size > 0)
+ {
+ if (gzip_level
+ /*
+ * For really tiny files, the gzip process startup
+ * time will outweigh the compression savings. This
+ * might be computable somehow; using 100 here is just
+ * a first approximation.
+ */
+ && sb.st_size > 100)
+ {
+ int status, fd, gzip_status;
+ pid_t gzip_pid;
+
+ fd = open (file, O_RDONLY, 0);
+ if (fd < 0)
+ error (1, errno, "reading %s", short_pathname);
+ fd = filter_through_gzip (fd, 1, gzip_level, &gzip_pid);
+ f = fdopen (fd, "r");
+ status = buf_read_file_to_eof (f, &list, &last);
+ size = buf_chain_length (list);
+ if (status == -2)
+ (*protocol.memory_error) (&protocol);
+ else if (status != 0)
+ error (1, ferror (f) ? errno : 0, "reading %s",
+ short_pathname);
+ if (fclose (f) == EOF)
+ error (1, errno, "reading %s", short_pathname);
+ if (waitpid (gzip_pid, &gzip_status, 0) == -1)
+ error (1, errno, "waiting for gzip process %d", gzip_pid);
+ else if (gzip_status != 0)
+ error (1, 0, "gzip exited %d", gzip_status);
+ /* Prepending length with "z" is flag for using gzip here. */
+ buf_output0 (&protocol, "z");
+ }
+ else
+ {
+ long status;
+
+ size = sb.st_size;
+ f = fopen (file, "r");
+ if (f == NULL)
+ error (1, errno, "reading %s", short_pathname);
+ status = buf_read_file (f, sb.st_size, &list, &last);
+ if (status == -2)
+ (*protocol.memory_error) (&protocol);
+ else if (status != 0)
+ error (1, ferror (f) ? errno : 0, "reading %s",
+ short_pathname);
+ if (fclose (f) == EOF)
+ error (1, errno, "reading %s", short_pathname);
+ }
+ }
+
+ sprintf (size_text, "%lu\n", size);
+ buf_output0 (&protocol, size_text);
+
+ buf_append_data (&protocol, list, last);
+ /* Note we only send a newline here if the file ended with one. */
+
+ /*
+ * Avoid using up too much disk space for temporary files.
+ * A file which does not exist indicates that the file is up-to-date,
+ * which is now the case. If this is SERVER_MERGED, the file is
+ * not up-to-date, and we indicate that by leaving the file there.
+ * I'm thinking of cases like "cvs update foo/foo.c foo".
+ */
+ if ((updated == SERVER_UPDATED || updated == SERVER_PATCHED)
+ /* But if we are joining, we'll need the file when we call
+ join_file. */
+ && !joining ())
+ unlink (file);
+ }
+ else if (scratched_file != NULL && entries_line == NULL)
+ {
+ if (strcmp (scratched_file, file) != 0)
+ error (1, 0,
+ "CVS server internal error: `%s' vs. `%s' scratched",
+ scratched_file,
+ file);
+ free (scratched_file);
+ scratched_file = NULL;
+
+ if (kill_scratched_file)
+ buf_output0 (&protocol, "Removed ");
+ else
+ buf_output0 (&protocol, "Remove-entry ");
+ output_dir (update_dir, repository);
+ buf_output0 (&protocol, file);
+ buf_output (&protocol, "\n", 1);
+ }
+ else if (scratched_file == NULL && entries_line == NULL)
+ {
+ /*
+ * This can happen with death support if we were processing
+ * a dead file in a checkout.
+ */
+ }
+ else
+ error (1, 0,
+ "CVS server internal error: Register *and* Scratch_Entry.\n");
+ buf_send_counted (&protocol);
+ done:
+ free (short_pathname);
+}
+
+void
+server_set_entstat (update_dir, repository)
+ char *update_dir;
+ char *repository;
+{
+ static int set_static_supported = -1;
+ if (set_static_supported == -1)
+ set_static_supported = supported_response ("Set-static-directory");
+ if (!set_static_supported) return;
+
+ buf_output0 (&protocol, "Set-static-directory ");
+ output_dir (update_dir, repository);
+ buf_output0 (&protocol, "\n");
+ buf_send_counted (&protocol);
+}
+
+void
+server_clear_entstat (update_dir, repository)
+ char *update_dir;
+ char *repository;
+{
+ static int clear_static_supported = -1;
+ if (clear_static_supported == -1)
+ clear_static_supported = supported_response ("Clear-static-directory");
+ if (!clear_static_supported) return;
+
+ if (noexec)
+ return;
+
+ buf_output0 (&protocol, "Clear-static-directory ");
+ output_dir (update_dir, repository);
+ buf_output0 (&protocol, "\n");
+ buf_send_counted (&protocol);
+}
+
+void
+server_set_sticky (update_dir, repository, tag, date)
+ char *update_dir;
+ char *repository;
+ char *tag;
+ char *date;
+{
+ static int set_sticky_supported = -1;
+ if (set_sticky_supported == -1)
+ set_sticky_supported = supported_response ("Set-sticky");
+ if (!set_sticky_supported) return;
+
+ if (noexec)
+ return;
+
+ if (tag == NULL && date == NULL)
+ {
+ buf_output0 (&protocol, "Clear-sticky ");
+ output_dir (update_dir, repository);
+ buf_output0 (&protocol, "\n");
+ }
+ else
+ {
+ buf_output0 (&protocol, "Set-sticky ");
+ output_dir (update_dir, repository);
+ buf_output0 (&protocol, "\n");
+ if (tag != NULL)
+ {
+ buf_output0 (&protocol, "T");
+ buf_output0 (&protocol, tag);
+ }
+ else
+ {
+ buf_output0 (&protocol, "D");
+ buf_output0 (&protocol, date);
+ }
+ buf_output0 (&protocol, "\n");
+ }
+ buf_send_counted (&protocol);
+}
+
+static void
+serve_gzip_contents (arg)
+ char *arg;
+{
+ int level;
+ level = atoi (arg);
+ if (level == 0)
+ level = 6;
+ gzip_level = level;
+}
+
+static void
+serve_ignore (arg)
+ char *arg;
+{
+ /*
+ * Just ignore this command. This is used to support the
+ * update-patches command, which is not a real command, but a signal
+ * to the client that update will accept the -u argument.
+ */
+}
+
+static int
+expand_proc (pargc, argv, where, mwhere, mfile, shorten,
+ local_specified, omodule, msg)
+ int *pargc;
+ char **argv;
+ char *where;
+ char *mwhere;
+ char *mfile;
+ int shorten;
+ int local_specified;
+ char *omodule;
+ char *msg;
+{
+ int i;
+ char *dir = argv[0];
+
+ /* If mwhere has been specified, the thing we're expanding is a
+ module -- just return its name so the client will ask for the
+ right thing later. If it is an alias or a real directory,
+ mwhere will not be set, so send out the appropriate
+ expansion. */
+
+ if (mwhere != NULL)
+ printf ("Module-expansion %s\n", mwhere);
+ else
+ {
+ /* We may not need to do this anymore -- check the definition
+ of aliases before removing */
+ if (*pargc == 1)
+ printf ("Module-expansion %s\n", dir);
+ else
+ for (i = 1; i < *pargc; ++i)
+ printf ("Module-expansion %s/%s\n", dir, argv[i]);
+ }
+ return 0;
+}
+
+static void
+serve_expand_modules (arg)
+ char *arg;
+{
+ int i;
+ int err;
+ DBM *db;
+ err = 0;
+
+ /*
+ * FIXME: error handling is bogus; do_module can write to stdout and/or
+ * stderr and we're not using do_cvs_command.
+ */
+
+ server_expanding = 1;
+ db = open_module ();
+ for (i = 1; i < argument_count; i++)
+ err += do_module (db, argument_vector[i],
+ CHECKOUT, "Updating", expand_proc,
+ NULL, 0, 0, 0,
+ (char *) NULL);
+ close_module (db);
+ server_expanding = 0;
+ {
+ /* argument_vector[0] is a dummy argument, we don't mess with it. */
+ char **cp;
+ for (cp = argument_vector + 1;
+ cp < argument_vector + argument_count;
+ ++cp)
+ free (*cp);
+
+ argument_count = 1;
+ }
+ if (err)
+ /* We will have printed an error message already. */
+ printf ("error \n");
+ else
+ printf ("ok\n");
+}
+
+void
+server_prog (dir, name, which)
+ char *dir;
+ char *name;
+ enum progs which;
+{
+ if (!supported_response ("Set-checkin-prog"))
+ {
+ printf ("E \
+warning: this client does not support -i or -u flags in the modules file.\n");
+ return;
+ }
+ switch (which)
+ {
+ case PROG_CHECKIN:
+ printf ("Set-checkin-prog ");
+ break;
+ case PROG_UPDATE:
+ printf ("Set-update-prog ");
+ break;
+ }
+ printf ("%s\n%s\n", dir, name);
+}
+
+static void
+serve_checkin_prog (arg)
+ char *arg;
+{
+ FILE *f;
+ f = fopen (CVSADM_CIPROG, "w+");
+ if (f == NULL)
+ {
+ pending_error = errno;
+ pending_error_text = malloc (80 + strlen(CVSADM_CIPROG));
+ sprintf(pending_error_text, "E cannot open %s", CVSADM_CIPROG);
+ return;
+ }
+ if (fprintf (f, "%s\n", arg) < 0)
+ {
+ pending_error = errno;
+ pending_error_text = malloc (80 + strlen(CVSADM_CIPROG));
+ sprintf(pending_error_text, "E cannot write to %s", CVSADM_CIPROG);
+ return;
+ }
+ if (fclose (f) == EOF)
+ {
+ pending_error = errno;
+ pending_error_text = malloc (80 + strlen(CVSADM_CIPROG));
+ sprintf(pending_error_text, "E cannot close %s", CVSADM_CIPROG);
+ return;
+ }
+}
+
+static void
+serve_update_prog (arg)
+ char *arg;
+{
+ FILE *f;
+ f = fopen (CVSADM_UPROG, "w+");
+ if (f == NULL)
+ {
+ pending_error = errno;
+ pending_error_text = malloc (80 + strlen(CVSADM_UPROG));
+ sprintf(pending_error_text, "E cannot open %s", CVSADM_UPROG);
+ return;
+ }
+ if (fprintf (f, "%s\n", arg) < 0)
+ {
+ pending_error = errno;
+ pending_error_text = malloc (80 + strlen(CVSADM_UPROG));
+ sprintf(pending_error_text, "E cannot write to %s", CVSADM_UPROG);
+ return;
+ }
+ if (fclose (f) == EOF)
+ {
+ pending_error = errno;
+ pending_error_text = malloc (80 + strlen(CVSADM_UPROG));
+ sprintf(pending_error_text, "E cannot close %s", CVSADM_UPROG);
+ return;
+ }
+}
+
+static void serve_valid_requests PROTO((char *arg));
+
+#endif /* SERVER_SUPPORT */
+#if defined(SERVER_SUPPORT) || defined(CLIENT_SUPPORT)
+
+/*
+ * Parts of this table are shared with the client code,
+ * but the client doesn't need to know about the handler
+ * functions.
+ */
+
+struct request requests[] =
+{
+#ifdef SERVER_SUPPORT
+#define REQ_LINE(n, f, s) {n, f, s}
+#else
+#define REQ_LINE(n, f, s) {n, s}
+#endif
+
+ REQ_LINE("Root", serve_root, rq_essential),
+ REQ_LINE("Valid-responses", serve_valid_responses, rq_essential),
+ REQ_LINE("valid-requests", serve_valid_requests, rq_essential),
+ REQ_LINE("Repository", serve_repository, rq_essential),
+ REQ_LINE("Directory", serve_directory, rq_optional),
+ REQ_LINE("Max-dotdot", serve_max_dotdot, rq_optional),
+ REQ_LINE("Static-directory", serve_static_directory, rq_optional),
+ REQ_LINE("Sticky", serve_sticky, rq_optional),
+ REQ_LINE("Checkin-prog", serve_checkin_prog, rq_optional),
+ REQ_LINE("Update-prog", serve_update_prog, rq_optional),
+ REQ_LINE("Entry", serve_entry, rq_essential),
+ REQ_LINE("Modified", serve_modified, rq_essential),
+ REQ_LINE("Lost", serve_lost, rq_optional),
+ REQ_LINE("UseUnchanged", serve_enable_unchanged, rq_enableme),
+ REQ_LINE("Unchanged", serve_unchanged, rq_optional),
+ REQ_LINE("Argument", serve_argument, rq_essential),
+ REQ_LINE("Argumentx", serve_argumentx, rq_essential),
+ REQ_LINE("Global_option", serve_global_option, rq_optional),
+ REQ_LINE("expand-modules", serve_expand_modules, rq_optional),
+ REQ_LINE("ci", serve_ci, rq_essential),
+ REQ_LINE("co", serve_co, rq_essential),
+ REQ_LINE("update", serve_update, rq_essential),
+ REQ_LINE("diff", serve_diff, rq_optional),
+ REQ_LINE("log", serve_log, rq_optional),
+ REQ_LINE("add", serve_add, rq_optional),
+ REQ_LINE("remove", serve_remove, rq_optional),
+ REQ_LINE("update-patches", serve_ignore, rq_optional),
+ REQ_LINE("gzip-file-contents", serve_gzip_contents, rq_optional),
+ REQ_LINE("status", serve_status, rq_optional),
+ REQ_LINE("rdiff", serve_rdiff, rq_optional),
+ REQ_LINE("tag", serve_tag, rq_optional),
+ REQ_LINE("rtag", serve_rtag, rq_optional),
+ REQ_LINE("import", serve_import, rq_optional),
+ REQ_LINE("admin", serve_admin, rq_optional),
+ REQ_LINE("export", serve_export, rq_optional),
+ REQ_LINE("history", serve_history, rq_optional),
+ REQ_LINE("release", serve_release, rq_optional),
+ REQ_LINE(NULL, NULL, rq_optional)
+
+#undef REQ_LINE
+};
+
+#endif /* SERVER_SUPPORT or CLIENT_SUPPORT */
+#ifdef SERVER_SUPPORT
+
+static void
+serve_valid_requests (arg)
+ char *arg;
+{
+ struct request *rq;
+ if (print_pending_error ())
+ return;
+ printf ("Valid-requests");
+ for (rq = requests; rq->name != NULL; rq++)
+ if (rq->func != NULL)
+ printf (" %s", rq->name);
+ printf ("\nok\n");
+}
+
+#ifdef sun
+/*
+ * Delete temporary files. SIG is the signal making this happen, or
+ * 0 if not called as a result of a signal.
+ */
+static int command_pid_is_dead;
+static void wait_sig (sig)
+ int sig;
+{
+ int status;
+ pid_t r = wait (&status);
+ if (r == command_pid)
+ command_pid_is_dead++;
+}
+#endif
+
+void
+server_cleanup (sig)
+ int sig;
+{
+ /* Do "rm -rf" on the temp directory. */
+ int len;
+ char *cmd;
+ char *temp_dir;
+
+ if (dont_delete_temp)
+ return;
+
+ /* What a bogus kludge. This disgusting code makes all kinds of
+ assumptions about SunOS, and is only for a bug in that system.
+ So only enable it on Suns. */
+#ifdef sun
+ if (command_pid > 0) {
+ /* To avoid crashes on SunOS due to bugs in SunOS tmpfs
+ triggered by the use of rename() in RCS, wait for the
+ subprocess to die. Unfortunately, this means draining output
+ while waiting for it to unblock the signal we sent it. Yuck! */
+ int status;
+ pid_t r;
+
+ signal (SIGCHLD, wait_sig);
+ if (sig)
+ /* Perhaps SIGTERM would be more correct. But the child
+ process will delay the SIGINT delivery until its own
+ children have exited. */
+ kill (command_pid, SIGINT);
+ /* The caller may also have sent a signal to command_pid, so
+ always try waiting. First, though, check and see if it's still
+ there.... */
+ do_waitpid:
+ r = waitpid (command_pid, &status, WNOHANG);
+ if (r == 0)
+ ;
+ else if (r == command_pid)
+ command_pid_is_dead++;
+ else if (r == -1)
+ switch (errno) {
+ case ECHILD:
+ command_pid_is_dead++;
+ break;
+ case EINTR:
+ goto do_waitpid;
+ }
+ else
+ /* waitpid should always return one of the above values */
+ abort ();
+ while (!command_pid_is_dead) {
+ struct timeval timeout;
+ struct fd_set_wrapper readfds;
+ char buf[100];
+ int i;
+
+ /* Use a non-zero timeout to avoid eating up CPU cycles. */
+ timeout.tv_sec = 2;
+ timeout.tv_usec = 0;
+ readfds = command_fds_to_drain;
+ switch (select (max_command_fd + 1, &readfds.fds,
+ (fd_set *)0, (fd_set *)0,
+ &timeout)) {
+ case -1:
+ if (errno != EINTR)
+ abort ();
+ case 0:
+ /* timeout */
+ break;
+ case 1:
+ for (i = 0; i <= max_command_fd; i++)
+ {
+ if (!FD_ISSET (i, &readfds.fds))
+ continue;
+ /* this fd is non-blocking */
+ while (read (i, buf, sizeof (buf)) >= 1)
+ ;
+ }
+ break;
+ default:
+ abort ();
+ }
+ }
+ }
+#endif
+
+ /* This might be set by the user in ~/.bashrc, ~/.cshrc, etc. */
+ temp_dir = getenv ("TMPDIR");
+ if (temp_dir == NULL || temp_dir[0] == '\0')
+ temp_dir = "/tmp";
+ chdir(temp_dir);
+
+ len = strlen (server_temp_dir) + 80;
+ cmd = malloc (len);
+ if (cmd == NULL)
+ {
+ printf ("E Cannot delete %s on server; out of memory\n",
+ server_temp_dir);
+ return;
+ }
+ sprintf (cmd, "rm -rf %s", server_temp_dir);
+ system (cmd);
+ free (cmd);
+}
+
+int server_active = 0;
+int server_expanding = 0;
+
+int
+server (argc, argv)
+ int argc;
+ char **argv;
+{
+ if (argc == -1)
+ {
+ static const char *const msg[] =
+ {
+ "Usage: %s %s\n",
+ " Normally invoked by a cvs client on a remote machine.\n",
+ NULL
+ };
+ usage (msg);
+ }
+ /* Ignore argc and argv. They might be from .cvsrc. */
+
+ /* Since we're in the server parent process, error should use the
+ protocol to report error messages. */
+ error_use_protocol = 1;
+
+ /*
+ * Put Rcsbin at the start of PATH, so that rcs programs can find
+ * themselves.
+ */
+#ifdef HAVE_PUTENV
+ if (Rcsbin != NULL && *Rcsbin)
+ {
+ char *p;
+ char *env;
+
+ p = getenv ("PATH");
+ if (p != NULL)
+ {
+ env = malloc (strlen (Rcsbin) + strlen (p) + sizeof "PATH=:");
+ if (env != NULL)
+ sprintf (env, "PATH=%s:%s", Rcsbin, p);
+ }
+ else
+ {
+ env = malloc (strlen (Rcsbin) + sizeof "PATH=");
+ if (env != NULL)
+ sprintf (env, "PATH=%s", Rcsbin);
+ }
+ if (env == NULL)
+ {
+ printf ("E Fatal server error, aborting.\n\
+error ENOMEM Virtual memory exhausted.\n");
+ exit (1);
+ }
+ putenv (env);
+ }
+#endif
+
+ /* OK, now figure out where we stash our temporary files. */
+ {
+ char *p;
+
+ /* This might be set by the user in ~/.bashrc, ~/.cshrc, etc. */
+ char *temp_dir = getenv ("TMPDIR");
+ if (temp_dir == NULL || temp_dir[0] == '\0')
+ temp_dir = "/tmp";
+
+ server_temp_dir = malloc (strlen (temp_dir) + 80);
+ if (server_temp_dir == NULL)
+ {
+ /*
+ * Strictly speaking, we're not supposed to output anything
+ * now. But we're about to exit(), give it a try.
+ */
+ printf ("E Fatal server error, aborting.\n\
+error ENOMEM Virtual memory exhausted.\n");
+ exit (1);
+ }
+ strcpy (server_temp_dir, temp_dir);
+
+ /* Remove a trailing slash from TMPDIR if present. */
+ p = server_temp_dir + strlen (server_temp_dir) - 1;
+ if (*p == '/')
+ *p = '\0';
+
+ /*
+ * I wanted to use cvs-serv/PID, but then you have to worry about
+ * the permissions on the cvs-serv directory being right. So
+ * use cvs-servPID.
+ */
+ strcat (server_temp_dir, "/cvs-serv");
+
+ p = server_temp_dir + strlen (server_temp_dir);
+ sprintf (p, "%d", getpid ());
+ }
+
+ (void) SIG_register (SIGHUP, server_cleanup);
+ (void) SIG_register (SIGINT, server_cleanup);
+ (void) SIG_register (SIGQUIT, server_cleanup);
+ (void) SIG_register (SIGPIPE, server_cleanup);
+ (void) SIG_register (SIGTERM, server_cleanup);
+
+ /* Now initialize our argument vector (for arguments from the client). */
+
+ /* Small for testing. */
+ argument_vector_size = 1;
+ argument_vector =
+ (char **) malloc (argument_vector_size * sizeof (char *));
+ if (argument_vector == NULL)
+ {
+ /*
+ * Strictly speaking, we're not supposed to output anything
+ * now. But we're about to exit(), give it a try.
+ */
+ printf ("E Fatal server error, aborting.\n\
+error ENOMEM Virtual memory exhausted.\n");
+ exit (1);
+ }
+
+ argument_count = 1;
+ argument_vector[0] = "Dummy argument 0";
+
+ server_active = 1;
+ while (1)
+ {
+ char *cmd, *orig_cmd;
+ struct request *rq;
+
+ orig_cmd = cmd = read_line (stdin);
+ if (cmd == NULL)
+ break;
+ if (cmd == NO_MEM_ERROR)
+ {
+ printf ("E Fatal server error, aborting.\n\
+error ENOMEM Virtual memory exhausted.\n");
+ break;
+ }
+ for (rq = requests; rq->name != NULL; ++rq)
+ if (strncmp (cmd, rq->name, strlen (rq->name)) == 0)
+ {
+ int len = strlen (rq->name);
+ if (cmd[len] == '\0')
+ cmd += len;
+ else if (cmd[len] == ' ')
+ cmd += len + 1;
+ else
+ /*
+ * The first len characters match, but it's a different
+ * command. e.g. the command is "cooperate" but we matched
+ * "co".
+ */
+ continue;
+ (*rq->func) (cmd);
+ break;
+ }
+ if (rq->name == NULL)
+ {
+ if (!print_pending_error ())
+ printf ("error unrecognized request `%s'\n", cmd);
+ }
+ free (orig_cmd);
+ }
+ server_cleanup (0);
+ return 0;
+}
+
+
+#ifdef AUTH_SERVER_SUPPORT
+
+/* This was test code, which we may need again. */
+#if 0
+ /* If we were invoked this way, then stdin comes from the
+ client and stdout/stderr writes to it. */
+ int c;
+ while ((c = getc (stdin)) != EOF && c != '*')
+ {
+ printf ("%c", toupper (c));
+ fflush (stdout);
+ }
+ exit (0);
+#endif /* 1/0 */
+
+
+/*
+ * 0 means no entry found for this user.
+ * 1 means entry found and password matches.
+ * 2 means entry found, but password does not match.
+ */
+int
+check_repository_password (username, password, repository)
+ char *username, *password, *repository;
+{
+ int retval = 0;
+ FILE *fp;
+ char *filename;
+ char linebuf[MAXLINELEN];
+ int found_it = 0, len;
+
+ filename = xmalloc (strlen (repository)
+ + 1
+ + strlen ("CVSROOT")
+ + 1
+ + strlen ("passwd")
+ + 1);
+
+ strcpy (filename, repository);
+ strcat (filename, "/CVSROOT");
+ strcat (filename, "/passwd");
+
+ fp = fopen (filename, "r");
+ if (fp == NULL)
+ {
+ /* This is ok -- the cvs passwd file might not exist. */
+ fclose (fp);
+ return 0;
+ }
+
+ /* Look for a relevant line -- one with this user's name. */
+ len = strlen (username);
+ while (fgets (linebuf, MAXPATHLEN - 1, fp))
+ {
+ if ((strncmp (linebuf, username, len) == 0)
+ && (linebuf[len] == ':'))
+ {
+ found_it = 1;
+ break;
+ }
+ }
+ fclose (fp);
+
+ /* If found_it != 0, then linebuf contains the information we need. */
+ if (found_it)
+ {
+ char *found_password;
+
+ strtok (linebuf, ":");
+ found_password = strtok (NULL, ": \n");
+
+ if (strcmp (found_password, crypt (password, found_password)) == 0)
+ retval = 1;
+ else
+ retval = 2;
+ }
+ else
+ retval = 0;
+
+ free (filename);
+
+ return retval;
+}
+
+
+/* Return 1 if password matches, else 0. */
+int
+check_password (username, password, repository)
+ char *username, *password, *repository;
+{
+ int rc;
+
+ /* First we see if this user has a password in the CVS-specific
+ password file. If so, that's enough to authenticate with. If
+ not, we'll check /etc/passwd. */
+
+ rc = check_repository_password (username, password, repository);
+
+ if (rc == 1)
+ return 1;
+ else if (rc == 2)
+ return 0;
+ else if (rc == 0)
+ {
+ /* No cvs password found, so try /etc/passwd. */
+
+ struct passwd *pw;
+ char *found_passwd;
+
+ pw = getpwnam (username);
+ if (pw == NULL)
+ {
+ printf ("E Fatal error, aborting.\n"
+ "error 0 %s: no such user\n", username);
+ exit (1);
+ }
+ found_passwd = pw->pw_passwd;
+
+ if (found_passwd && *found_passwd)
+ return (! strcmp (found_passwd, crypt (password, found_passwd)));
+ else if (password && *password)
+ return 1;
+ else
+ return 0;
+ }
+ else
+ {
+ /* Something strange happened. We don't know what it was, but
+ we certainly won't grant authorization. */
+ return 0;
+ }
+}
+
+
+/* Read username and password from client (i.e., stdin).
+ If correct, then switch to run as that user and send an ACK to the
+ client via stdout, else send NACK and die. */
+void
+authenticate_connection ()
+{
+ int len;
+ char tmp[PATH_MAX];
+ char repository[PATH_MAX];
+ char username[PATH_MAX];
+ char password[PATH_MAX];
+ char server_user[PATH_MAX];
+ struct passwd *pw;
+
+ /* The Authentication Protocol. Client sends:
+ *
+ * BEGIN AUTH REQUEST\n
+ * <REPOSITORY>\n
+ * <USERNAME>\n
+ * <PASSWORD>\n
+ * END AUTH REQUEST\n
+ *
+ * Server uses above information to authenticate, then sends
+ *
+ * I LOVE YOU\n
+ *
+ * if it grants access, else
+ *
+ * I HATE YOU\n
+ *
+ * if it denies access (and it exits if denying).
+ *
+ * Note that the actual client/server protocol has not started up
+ * yet, because we haven't authenticated! Therefore, there are
+ * certain things we can't take for granted. For example, don't use
+ * error() because `error_use_protocol' has not yet been set by
+ * server().
+ *
+ * We need to know where the repository is too, to look up the
+ * password in the special CVS passwd file before we try
+ * /etc/passwd. However, the repository is normally transmitted in
+ * the regular client/server protocol, which has not yet started,
+ * blah blah blah. This is why the client transmits the repository
+ * as part of the "authentication protocol". Thus, the repository
+ * will be redundantly retransmitted later, but that's no big deal.
+ */
+
+ /* Make sure the protocol starts off on the right foot... */
+ fgets (tmp, PATH_MAX, stdin);
+ if (strcmp (tmp, "BEGIN AUTH REQUEST\n"))
+ {
+ printf ("error: bad auth protocol start: %s", tmp);
+ fflush (stdout);
+ exit (1);
+ }
+
+ /* Get the three important pieces of information in order. */
+ fgets (repository, PATH_MAX, stdin);
+ fgets (username, PATH_MAX, stdin);
+ fgets (password, PATH_MAX, stdin);
+
+ /* Make them pure. */
+ strip_trailing_newlines (repository);
+ strip_trailing_newlines (username);
+ strip_trailing_newlines (password);
+
+ /* ... and make sure the protocol ends on the right foot. */
+ fgets (tmp, PATH_MAX, stdin);
+ if (strcmp (tmp, "END AUTH REQUEST\n"))
+ {
+ printf ("error: bad auth protocol end: %s", tmp);
+ fflush (stdout);
+ exit (1);
+ }
+
+ if (check_password (username, password, repository))
+ {
+ printf ("I LOVE YOU\n");
+ fflush (stdout);
+ }
+ else
+ {
+ printf ("I HATE YOU\n");
+ fflush (stdout);
+ exit (1);
+ }
+
+ /* Do everything that kerberos did. */
+ pw = getpwnam (username);
+ if (pw == NULL)
+ {
+ printf ("E Fatal error, aborting.\n"
+ "error 0 %s: no such user\n", username);
+ exit (1);
+ }
+
+ initgroups (pw->pw_name, pw->pw_gid);
+ setgid (pw->pw_gid);
+ setuid (pw->pw_uid);
+ /* Inhibit access by randoms. Don't want people randomly
+ changing our temporary tree before we check things in. */
+ umask (077);
+
+#if HAVE_PUTENV
+ /* Set LOGNAME and USER in the environment, in case they are
+ already set to something else. */
+ {
+ char *env;
+
+ env = xmalloc (sizeof "LOGNAME=" + strlen (username));
+ (void) sprintf (env, "LOGNAME=%s", username);
+ (void) putenv (env);
+
+ env = xmalloc (sizeof "USER=" + strlen (username));
+ (void) sprintf (env, "USER=%s", username);
+ (void) putenv (env);
+ }
+#endif /* HAVE_PUTENV */
+}
+
+#endif AUTH_SERVER_SUPPORT
+
+
+#endif /* SERVER_SUPPORT */
+
diff --git a/gnu/usr.bin/cvs/cvs/server.h b/gnu/usr.bin/cvs/cvs/server.h
new file mode 100644
index 0000000..cb49267
--- /dev/null
+++ b/gnu/usr.bin/cvs/cvs/server.h
@@ -0,0 +1,136 @@
+/* Interface between the server and the rest of CVS. */
+
+/* Miscellaneous stuff which isn't actually particularly server-specific. */
+#ifndef STDIN_FILENO
+#define STDIN_FILENO 0
+#define STDOUT_FILENO 1
+#define STDERR_FILENO 2
+#endif
+
+#ifdef SERVER_SUPPORT
+
+/*
+ * Nonzero if we are using the server. Used by various places to call
+ * server-specific functions.
+ */
+extern int server_active;
+extern int server_expanding;
+
+/* Server functions exported to the rest of CVS. */
+
+/* Run the server. */
+extern int server PROTO((int argc, char **argv));
+
+/* We have a new Entries line for a file. TAG or DATE can be NULL. */
+extern void server_register
+ PROTO((char *name, char *version, char *timestamp,
+ char *options, char *tag, char *date, char *conflict));
+
+/*
+ * We want to nuke the Entries line for a file, and (unless
+ * server_scratch_entry_only is subsequently called) the file itself.
+ */
+extern void server_scratch PROTO((char *name));
+
+/*
+ * The file which just had server_scratch called on it needs to have only
+ * the Entries line removed, not the file itself.
+ */
+extern void server_scratch_entry_only PROTO((void));
+
+/*
+ * We just successfully checked in FILE (which is just the bare
+ * filename, with no directory). REPOSITORY is the directory for the
+ * repository.
+ */
+extern void server_checked_in
+ PROTO((char *file, char *update_dir, char *repository));
+
+extern void server_copy_file
+ PROTO((char *file, char *update_dir, char *repository, char *newfile));
+
+/*
+ * We just successfully updated FILE (bare filename, no directory).
+ * REPOSITORY is the directory for the repository. This is called
+ * after server_register or server_scratch, in the latter case the
+ * file is to be removed. UPDATED indicates whether the file is now
+ * up to date (SERVER_UPDATED, yes, SERVER_MERGED, no, SERVER_PATCHED,
+ * yes, but file is a diff from user version to repository version).
+ */
+enum server_updated_arg4 {SERVER_UPDATED, SERVER_MERGED, SERVER_PATCHED};
+extern void server_updated
+ PROTO((char *file, char *update_dir, char *repository,
+ enum server_updated_arg4 updated, struct stat *,
+ unsigned char *checksum));
+
+/* Set the Entries.Static flag. */
+extern void server_set_entstat PROTO((char *update_dir, char *repository));
+/* Clear it. */
+extern void server_clear_entstat PROTO((char *update_dir, char *repository));
+
+/* Set or clear a per-directory sticky tag or date. */
+extern void server_set_sticky PROTO((char *update_dir, char *repository,
+ char *tag,
+ char *date));
+
+extern void server_update_entries
+ PROTO((char *file, char *update_dir, char *repository,
+ enum server_updated_arg4 updated));
+
+enum progs {PROG_CHECKIN, PROG_UPDATE};
+extern void server_prog PROTO((char *, char *, enum progs));
+extern void server_cleanup PROTO((int sig));
+
+#ifdef SERVER_FLOWCONTROL
+/* Pause if it's convenient to avoid memory blowout */
+extern void server_check_pause PROTO((void));
+#endif /* SERVER_FLOWCONTROL */
+
+#endif /* SERVER_SUPPORT */
+
+/* Stuff shared with the client. */
+struct request
+{
+ /* Name of the request. */
+ char *name;
+
+#ifdef SERVER_SUPPORT
+ /*
+ * Function to carry out the request. ARGS is the text of the command
+ * after name and, if present, a single space, have been stripped off.
+ */
+ void (*func) PROTO((char *args));
+#endif
+
+ /* Stuff for use by the client. */
+ enum {
+ /*
+ * Failure to implement this request can imply a fatal
+ * error. This should be set only for commands which were in the
+ * original version of the protocol; it should not be set for new
+ * commands.
+ */
+ rq_essential,
+
+ /* Some servers might lack this request. */
+ rq_optional,
+
+ /*
+ * Set by the client to one of the following based on what this
+ * server actually supports.
+ */
+ rq_supported,
+ rq_not_supported,
+
+ /*
+ * If the server supports this request, and we do too, tell the
+ * server by making the request.
+ */
+ rq_enableme
+ } status;
+};
+
+/* Table of requests ending with an entry with a NULL name. */
+extern struct request requests[];
+
+extern int use_unchanged;
diff --git a/gnu/usr.bin/cvs/cvs/status.c b/gnu/usr.bin/cvs/cvs/status.c
new file mode 100644
index 0000000..fe53bcb
--- /dev/null
+++ b/gnu/usr.bin/cvs/cvs/status.c
@@ -0,0 +1,282 @@
+/*
+ * Copyright (c) 1992, Brian Berliner and Jeff Polk
+ * Copyright (c) 1989-1992, Brian Berliner
+ *
+ * You may distribute under the terms of the GNU General Public License as
+ * specified in the README file that comes with the CVS 1.4 kit.
+ *
+ * Status Information
+ */
+
+#include "cvs.h"
+
+#ifndef lint
+static const char rcsid[] = "$CVSid: @(#)status.c 1.56 94/10/07 $";
+USE(rcsid);
+#endif
+
+static Dtype status_dirproc PROTO((char *dir, char *repos, char *update_dir));
+static int status_fileproc PROTO((char *file, char *update_dir,
+ char *repository, List * entries,
+ List * srcfiles));
+static int tag_list_proc PROTO((Node * p, void *closure));
+
+static int local = 0;
+static int long_format = 0;
+static char *xfile;
+static List *xsrcfiles;
+
+static const char *const status_usage[] =
+{
+ "Usage: %s %s [-vlR] [files...]\n",
+ "\t-v\tVerbose format; includes tag information for the file\n",
+ "\t-l\tProcess this directory only (not recursive).\n",
+ "\t-R\tProcess directories recursively.\n",
+ NULL
+};
+
+int
+status (argc, argv)
+ int argc;
+ char **argv;
+{
+ int c;
+ int err = 0;
+
+ if (argc == -1)
+ usage (status_usage);
+
+ optind = 1;
+ while ((c = getopt (argc, argv, "vlR")) != -1)
+ {
+ switch (c)
+ {
+ case 'v':
+ long_format = 1;
+ break;
+ case 'l':
+ local = 1;
+ break;
+ case 'R':
+ local = 0;
+ break;
+ case '?':
+ default:
+ usage (status_usage);
+ break;
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+ wrap_setup ();
+
+#ifdef CLIENT_SUPPORT
+ if (client_active) {
+ start_server ();
+
+ ign_setup ();
+
+ if (long_format)
+ send_arg("-v");
+ if (local)
+ send_arg("-l");
+
+ /* XXX This should only need to send file info; the file
+ contents themselves will not be examined. */
+ send_files (argc, argv, local, 0);
+
+ if (fprintf (to_server, "status\n") < 0)
+ error (1, errno, "writing to server");
+ err = get_responses_and_close ();
+
+ return err;
+ }
+#endif
+
+ /* start the recursion processor */
+ err = start_recursion (status_fileproc, (FILESDONEPROC) NULL, status_dirproc,
+ (DIRLEAVEPROC) NULL, argc, argv, local,
+ W_LOCAL, 0, 1, (char *) NULL, 1, 0);
+
+ return (err);
+}
+
+/*
+ * display the status of a file
+ */
+/* ARGSUSED */
+static int
+status_fileproc (file, update_dir, repository, entries, srcfiles)
+ char *file;
+ char *update_dir;
+ char *repository;
+ List *entries;
+ List *srcfiles;
+{
+ Ctype status;
+ char *sstat;
+ Vers_TS *vers;
+
+ status = Classify_File (file, (char *) NULL, (char *) NULL, (char *) NULL,
+ 1, 0, repository, entries, srcfiles, &vers,
+ update_dir, 0);
+ switch (status)
+ {
+ case T_UNKNOWN:
+ sstat = "Unknown";
+ break;
+ case T_CHECKOUT:
+ sstat = "Needs Checkout";
+ break;
+#ifdef SERVER_SUPPORT
+ case T_PATCH:
+ sstat = "Needs Patch";
+ break;
+#endif
+ case T_CONFLICT:
+ sstat = "Unresolved Conflict";
+ break;
+ case T_ADDED:
+ sstat = "Locally Added";
+ break;
+ case T_REMOVED:
+ sstat = "Locally Removed";
+ break;
+ case T_MODIFIED:
+ if (vers->ts_conflict)
+ sstat = "Unresolved Conflict";
+ else
+ sstat = "Locally Modified";
+ break;
+ case T_REMOVE_ENTRY:
+ sstat = "Entry Invalid";
+ break;
+ case T_UPTODATE:
+ sstat = "Up-to-date";
+ break;
+ case T_NEEDS_MERGE:
+ sstat = "Needs Merge";
+ break;
+ default:
+ sstat = "Classify Error";
+ break;
+ }
+
+ (void) printf ("===================================================================\n");
+ if (vers->ts_user == NULL)
+ (void) printf ("File: no file %s\t\tStatus: %s\n\n", file, sstat);
+ else
+ (void) printf ("File: %-17s\tStatus: %s\n\n", file, sstat);
+
+ if (vers->vn_user == NULL)
+ (void) printf (" Working revision:\tNo entry for %s\n", file);
+ else if (vers->vn_user[0] == '0' && vers->vn_user[1] == '\0')
+ (void) printf (" Working revision:\tNew file!\n");
+#ifdef SERVER_SUPPORT
+ else if (server_active)
+ (void) printf (" Working revision:\t%s\n", vers->vn_user);
+#endif
+ else
+ (void) printf (" Working revision:\t%s\t%s\n", vers->vn_user,
+ vers->ts_rcs);
+
+ if (vers->vn_rcs == NULL)
+ (void) printf (" Repository revision:\tNo revision control file\n");
+ else
+ (void) printf (" Repository revision:\t%s\t%s\n", vers->vn_rcs,
+ vers->srcfile->path);
+
+ if (vers->entdata)
+ {
+ Entnode *edata;
+
+ edata = vers->entdata;
+ if (edata->tag)
+ {
+ if (vers->vn_rcs == NULL)
+ (void) printf (
+ " Sticky Tag:\t\t%s - MISSING from RCS file!\n",
+ edata->tag);
+ else
+ {
+ if (isdigit (edata->tag[0]))
+ (void) printf (" Sticky Tag:\t\t%s\n", edata->tag);
+ else
+ {
+ int isbranch = RCS_isbranch (file, edata->tag, srcfiles);
+
+ (void) printf (" Sticky Tag:\t\t%s (%s: %s)\n",
+ edata->tag,
+ isbranch ? "branch" : "revision",
+ isbranch ?
+ RCS_whatbranch(file, edata->tag, srcfiles) :
+ vers->vn_rcs);
+ }
+ }
+ }
+ else if (!really_quiet)
+ (void) printf (" Sticky Tag:\t\t(none)\n");
+
+ if (edata->date)
+ (void) printf (" Sticky Date:\t\t%s\n", edata->date);
+ else if (!really_quiet)
+ (void) printf (" Sticky Date:\t\t(none)\n");
+
+ if (edata->options && edata->options[0])
+ (void) printf (" Sticky Options:\t%s\n", edata->options);
+ else if (!really_quiet)
+ (void) printf (" Sticky Options:\t(none)\n");
+
+ if (long_format && vers->srcfile)
+ {
+ List *symbols = RCS_symbols(vers->srcfile);
+
+ (void) printf ("\n Existing Tags:\n");
+ if (symbols)
+ {
+ xfile = file;
+ xsrcfiles = srcfiles;
+ (void) walklist (symbols, tag_list_proc, NULL);
+ }
+ else
+ (void) printf ("\tNo Tags Exist\n");
+ }
+ }
+
+ (void) printf ("\n");
+ freevers_ts (&vers);
+ return (0);
+}
+
+/*
+ * Print a warm fuzzy message
+ */
+/* ARGSUSED */
+static Dtype
+status_dirproc (dir, repos, update_dir)
+ char *dir;
+ char *repos;
+ char *update_dir;
+{
+ if (!quiet)
+ error (0, 0, "Examining %s", update_dir);
+ return (R_PROCESS);
+}
+
+/*
+ * Print out a tag and its type
+ */
+static int
+tag_list_proc (p, closure)
+ Node *p;
+ void *closure;
+{
+ int isbranch = RCS_isbranch (xfile, p->key, xsrcfiles);
+
+ (void) printf ("\t%-25.25s\t(%s: %s)\n", p->key,
+ isbranch ? "branch" : "revision",
+ isbranch ? RCS_whatbranch(xfile, p->key, xsrcfiles) :
+ p->data);
+ return (0);
+}
diff --git a/gnu/usr.bin/cvs/cvs/tag.c b/gnu/usr.bin/cvs/cvs/tag.c
new file mode 100644
index 0000000..55c8659
--- /dev/null
+++ b/gnu/usr.bin/cvs/cvs/tag.c
@@ -0,0 +1,582 @@
+/*
+ * Copyright (c) 1992, Brian Berliner and Jeff Polk
+ * Copyright (c) 1989-1992, Brian Berliner
+ *
+ * You may distribute under the terms of the GNU General Public License as
+ * specified in the README file that comes with the CVS 1.4 kit.
+ *
+ * Tag
+ *
+ * Add or delete a symbolic name to an RCS file, or a collection of RCS files.
+ * Uses the checked out revision in the current directory.
+ */
+
+#include "cvs.h"
+
+#ifndef lint
+static const char rcsid[] = "$CVSid: @(#)tag.c 1.60 94/09/30 $";
+USE(rcsid);
+#endif
+
+static int check_fileproc PROTO((char *file, char *update_dir,
+ char *repository, List * entries,
+ List * srcfiles));
+static int check_filesdoneproc PROTO((int err, char *repos, char *update_dir));
+static int pretag_proc PROTO((char *repository, char *filter));
+static void masterlist_delproc PROTO((Node *p));
+static void tag_delproc PROTO((Node *p));
+static int pretag_list_proc PROTO((Node *p, void *closure));
+
+static Dtype tag_dirproc PROTO((char *dir, char *repos, char *update_dir));
+static int tag_fileproc PROTO((char *file, char *update_dir,
+ char *repository, List * entries,
+ List * srcfiles));
+
+static char *numtag;
+static char *date = NULL;
+static char *symtag;
+static int delete; /* adding a tag by default */
+static int branch_mode; /* make an automagic "branch" tag */
+static int local; /* recursive by default */
+static int force_tag_match = 1; /* force tag to match by default */
+static int force_tag_move; /* don't force tag to move by default */
+
+struct tag_info
+{
+ Ctype status;
+ char *rev;
+ char *tag;
+ char *options;
+};
+
+struct master_lists
+{
+ List *tlist;
+};
+
+static List *mtlist;
+static List *tlist;
+
+static const char *const tag_usage[] =
+{
+ "Usage: %s %s [-lRF] [-b] [-d] tag [files...]\n",
+ "\t-l\tLocal directory only, not recursive.\n",
+ "\t-R\tProcess directories recursively.\n",
+ "\t-d\tDelete the given Tag.\n",
+ "\t-[rD]\tExisting tag or date.\n",
+ "\t-f\tForce a head revision if tag etc not found.\n",
+ "\t-b\tMake the tag a \"branch\" tag, allowing concurrent development.\n",
+ "\t-F\tMove tag if it already exists\n",
+ NULL
+};
+
+int
+tag (argc, argv)
+ int argc;
+ char **argv;
+{
+ int c;
+ int err = 0;
+
+ if (argc == -1)
+ usage (tag_usage);
+
+ optind = 1;
+ while ((c = getopt (argc, argv, "FQqlRdr:D:bf")) != -1)
+ {
+ switch (c)
+ {
+ case 'Q':
+ case 'q':
+#ifdef SERVER_SUPPORT
+ /* The CVS 1.5 client sends these options (in addition to
+ Global_option requests), so we must ignore them. */
+ if (!server_active)
+#endif
+ error (1, 0,
+ "-q or -Q must be specified before \"%s\"",
+ command_name);
+ break;
+ case 'l':
+ local = 1;
+ break;
+ case 'R':
+ local = 0;
+ break;
+ case 'd':
+ delete = 1;
+ break;
+ case 'r':
+ numtag = optarg;
+ break;
+ case 'D':
+ if (date)
+ free (date);
+ date = Make_Date (optarg);
+ break;
+ case 'f':
+ force_tag_match = 0;
+ break;
+ case 'b':
+ branch_mode = 1;
+ break;
+ case 'F':
+ force_tag_move = 1;
+ break;
+ case '?':
+ default:
+ usage (tag_usage);
+ break;
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (argc == 0)
+ usage (tag_usage);
+ symtag = argv[0];
+ argc--;
+ argv++;
+
+ if (delete && branch_mode)
+ error (0, 0, "warning: -b ignored with -d options");
+ RCS_check_tag (symtag);
+
+#ifdef CLIENT_SUPPORT
+ if (client_active)
+ {
+ /* We're the client side. Fire up the remote server. */
+ start_server ();
+
+ ign_setup ();
+
+ if (local)
+ send_arg("-l");
+ if (delete)
+ send_arg("-d");
+ if (branch_mode)
+ send_arg("-b");
+ if (force_tag_move)
+ send_arg("-F");
+
+ send_arg (symtag);
+
+#if 0
+ /* FIXME: We shouldn't have to send current files, but I'm not sure
+ whether it works. So send the files --
+ it's slower but it works. */
+ send_file_names (argc, argv);
+#else
+ send_files (argc, argv, local, 0);
+#endif
+ if (fprintf (to_server, "tag\n") < 0)
+ error (1, errno, "writing to server");
+ return get_responses_and_close ();
+ }
+#endif
+
+ /* check to make sure they are authorized to tag all the
+ specified files in the repository */
+
+ mtlist = getlist();
+ err = start_recursion (check_fileproc, check_filesdoneproc,
+ (DIRENTPROC) NULL, (DIRLEAVEPROC) NULL,
+ argc, argv, local, W_LOCAL, 0, 1,
+ (char *) NULL, 1, 0);
+
+ if (err)
+ {
+ error (1, 0, "correct the above errors first!");
+ }
+
+ /* start the recursion processor */
+ err = start_recursion (tag_fileproc, (FILESDONEPROC) NULL, tag_dirproc,
+ (DIRLEAVEPROC) NULL, argc, argv, local,
+ W_LOCAL, 0, 1, (char *) NULL, 1, 0);
+ dellist(&mtlist);
+ return (err);
+}
+
+/* check file that is to be tagged */
+/* All we do here is add it to our list */
+
+static int
+check_fileproc(file, update_dir, repository, entries, srcfiles)
+ char *file;
+ char *update_dir;
+ char *repository;
+ List * entries;
+ List * srcfiles;
+{
+ char *xdir;
+ Node *p;
+ Vers_TS *vers;
+
+ if (update_dir[0] == '\0')
+ xdir = ".";
+ else
+ xdir = update_dir;
+ if ((p = findnode (mtlist, xdir)) != NULL)
+ {
+ tlist = ((struct master_lists *) p->data)->tlist;
+ }
+ else
+ {
+ struct master_lists *ml;
+
+ tlist = getlist ();
+ p = getnode ();
+ p->key = xstrdup (xdir);
+ p->type = UPDATE;
+ ml = (struct master_lists *)
+ xmalloc (sizeof (struct master_lists));
+ ml->tlist = tlist;
+ p->data = (char *) ml;
+ p->delproc = masterlist_delproc;
+ (void) addnode (mtlist, p);
+ }
+ /* do tlist */
+ p = getnode ();
+ p->key = xstrdup (file);
+ p->type = UPDATE;
+ p->delproc = tag_delproc;
+ vers = Version_TS (repository, (char *) NULL, (char *) NULL, (char *) NULL,
+ file, 0, 0, entries, srcfiles);
+ p->data = RCS_getversion(vers->srcfile, numtag, date, force_tag_match, 0);
+ if (p->data != NULL)
+ {
+ int addit = 1;
+ char *oversion;
+
+ oversion = RCS_getversion (vers->srcfile, symtag, (char *) NULL, 1, 0);
+ if (oversion == NULL)
+ {
+ if (delete)
+ {
+ addit = 0;
+ }
+ }
+ else if (strcmp(oversion, p->data) == 0)
+ {
+ addit = 0;
+ }
+ else if (!force_tag_move)
+ {
+ addit = 0;
+ }
+ if (oversion != NULL)
+ {
+ free(oversion);
+ }
+ if (!addit)
+ {
+ free(p->data);
+ p->data = NULL;
+ }
+ }
+ freevers_ts(&vers);
+ (void) addnode (tlist, p);
+ return (0);
+}
+
+static int
+check_filesdoneproc(err, repos, update_dir)
+ int err;
+ char *repos;
+ char *update_dir;
+{
+ int n;
+ Node *p;
+
+ p = findnode(mtlist, update_dir);
+ if (p != NULL)
+ {
+ tlist = ((struct master_lists *) p->data)->tlist;
+ }
+ else
+ {
+ tlist = (List *) NULL;
+ }
+ if ((tlist == NULL) || (tlist->list->next == tlist->list))
+ {
+ return (err);
+ }
+ if ((n = Parse_Info(CVSROOTADM_TAGINFO, repos, pretag_proc, 1)) > 0)
+ {
+ error (0, 0, "Pre-tag check failed");
+ err += n;
+ }
+ return (err);
+}
+
+static int
+pretag_proc(repository, filter)
+ char *repository;
+ char *filter;
+{
+ if (filter[0] == '/')
+ {
+ char *s, *cp;
+
+ s = xstrdup(filter);
+ for (cp=s; *cp; cp++)
+ {
+ if (isspace(*cp))
+ {
+ *cp = '\0';
+ break;
+ }
+ }
+ if (!isfile(s))
+ {
+ error (0, errno, "cannot find pre-tag filter '%s'", s);
+ free(s);
+ return (1);
+ }
+ free(s);
+ }
+ run_setup("%s %s %s %s",
+ filter,
+ symtag,
+ delete ? "del" : force_tag_move ? "mov" : "add",
+ repository);
+ walklist(tlist, pretag_list_proc, NULL);
+ return (run_exec(RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL|RUN_REALLY));
+}
+
+static void
+masterlist_delproc(p)
+ Node *p;
+{
+ struct master_lists *ml;
+
+ ml = (struct master_lists *)p->data;
+ dellist(&ml->tlist);
+ free(ml);
+ return;
+}
+
+static void
+tag_delproc(p)
+ Node *p;
+{
+ if (p->data != NULL)
+ {
+ free(p->data);
+ p->data = NULL;
+ }
+ return;
+}
+
+static int
+pretag_list_proc(p, closure)
+ Node *p;
+ void *closure;
+{
+ if (p->data != NULL)
+ {
+ run_arg(p->key);
+ run_arg(p->data);
+ }
+ return (0);
+}
+
+
+/*
+ * Called to tag a particular file (the currently checked out version is
+ * tagged with the specified tag - or the specified tag is deleted).
+ */
+/* ARGSUSED */
+static int
+tag_fileproc (file, update_dir, repository, entries, srcfiles)
+ char *file;
+ char *update_dir;
+ char *repository;
+ List *entries;
+ List *srcfiles;
+{
+ char *version, *oversion;
+ char *nversion = NULL;
+ char *rev;
+ Vers_TS *vers;
+ int retcode = 0;
+
+ vers = Version_TS (repository, (char *) NULL, (char *) NULL, (char *) NULL,
+ file, 0, 0, entries, srcfiles);
+
+ if ((numtag != NULL) || (date != NULL))
+ {
+ nversion = RCS_getversion(vers->srcfile,
+ numtag,
+ date,
+ force_tag_match, 0);
+ if (nversion == NULL)
+ {
+ freevers_ts (&vers);
+ return (0);
+ }
+ }
+ if (delete)
+ {
+
+ /*
+ * If -d is specified, "force_tag_match" is set, so that this call to
+ * Version_Number() will return a NULL version string if the symbolic
+ * tag does not exist in the RCS file.
+ *
+ * This is done here because it's MUCH faster than just blindly calling
+ * "rcs" to remove the tag... trust me.
+ */
+
+ version = RCS_getversion (vers->srcfile, symtag, (char *) NULL, 1, 0);
+ if (version == NULL || vers->srcfile == NULL)
+ {
+ freevers_ts (&vers);
+ return (0);
+ }
+ free (version);
+
+ if ((retcode = RCS_deltag(vers->srcfile->path, symtag, 1)) != 0)
+ {
+ if (!quiet)
+ error (0, retcode == -1 ? errno : 0,
+ "failed to remove tag %s from %s", symtag,
+ vers->srcfile->path);
+ freevers_ts (&vers);
+ return (1);
+ }
+
+ /* warm fuzzies */
+ if (!really_quiet)
+ {
+ if (update_dir[0])
+ (void) printf ("D %s/%s\n", update_dir, file);
+ else
+ (void) printf ("D %s\n", file);
+ }
+
+ freevers_ts (&vers);
+ return (0);
+ }
+
+ /*
+ * If we are adding a tag, we need to know which version we have checked
+ * out and we'll tag that version.
+ */
+ if (nversion == NULL)
+ {
+ version = vers->vn_user;
+ }
+ else
+ {
+ version = nversion;
+ }
+ if (version == NULL)
+ {
+ freevers_ts (&vers);
+ return (0);
+ }
+ else if (strcmp (version, "0") == 0)
+ {
+ if (!quiet)
+ error (0, 0, "couldn't tag added but un-commited file `%s'", file);
+ freevers_ts (&vers);
+ return (0);
+ }
+ else if (version[0] == '-')
+ {
+ if (!quiet)
+ error (0, 0, "skipping removed but un-commited file `%s'", file);
+ freevers_ts (&vers);
+ return (0);
+ }
+ else if (vers->srcfile == NULL)
+ {
+ if (!quiet)
+ error (0, 0, "cannot find revision control file for `%s'", file);
+ freevers_ts (&vers);
+ return (0);
+ }
+
+ /*
+ * As an enhancement for the case where a tag is being re-applied to a
+ * large number of files, make one extra call to Version_Number to see if
+ * the tag is already set in the RCS file. If so, check to see if it
+ * needs to be moved. If not, do nothing. This will likely save a lot of
+ * time when simply moving the tag to the "current" head revisions of a
+ * module -- which I have found to be a typical tagging operation.
+ */
+ rev = branch_mode ? RCS_magicrev (vers->srcfile, version) : version;
+ oversion = RCS_getversion (vers->srcfile, symtag, (char *) NULL, 1, 0);
+ if (oversion != NULL)
+ {
+ int isbranch = RCS_isbranch (file, symtag, srcfiles);
+
+ /*
+ * if versions the same and neither old or new are branches don't have
+ * to do anything
+ */
+ if (strcmp (version, oversion) == 0 && !branch_mode && !isbranch)
+ {
+ free (oversion);
+ freevers_ts (&vers);
+ return (0);
+ }
+
+ if (!force_tag_move) { /* we're NOT going to move the tag */
+ if (update_dir[0])
+ (void) printf ("W %s/%s", update_dir, file);
+ else
+ (void) printf ("W %s", file);
+
+ (void) printf (" : %s already exists on %s %s",
+ symtag, isbranch ? "branch" : "version", oversion);
+ (void) printf (" : NOT MOVING tag to %s %s\n",
+ branch_mode ? "branch" : "version", rev);
+ free (oversion);
+ freevers_ts (&vers);
+ return (0);
+ }
+ free (oversion);
+ }
+
+ if ((retcode = RCS_settag(vers->srcfile->path, symtag, rev)) != 0)
+ {
+ error (1, retcode == -1 ? errno : 0,
+ "failed to set tag %s to revision %s in %s",
+ symtag, rev, vers->srcfile->path);
+ freevers_ts (&vers);
+ return (1);
+ }
+
+ /* more warm fuzzies */
+ if (!really_quiet)
+ {
+ if (update_dir[0])
+ (void) printf ("T %s/%s\n", update_dir, file);
+ else
+ (void) printf ("T %s\n", file);
+ }
+
+ freevers_ts (&vers);
+ if (nversion != NULL)
+ {
+ free(nversion);
+ }
+ return (0);
+}
+
+/*
+ * Print a warm fuzzy message
+ */
+/* ARGSUSED */
+static Dtype
+tag_dirproc (dir, repos, update_dir)
+ char *dir;
+ char *repos;
+ char *update_dir;
+{
+ if (!quiet)
+ error (0, 0, "%s %s", delete ? "Untagging" : "Tagging", update_dir);
+ return (R_PROCESS);
+}
diff --git a/gnu/usr.bin/cvs/cvs/update.c b/gnu/usr.bin/cvs/cvs/update.c
new file mode 100644
index 0000000..0dd0e1b
--- /dev/null
+++ b/gnu/usr.bin/cvs/cvs/update.c
@@ -0,0 +1,1908 @@
+/*
+ * Copyright (c) 1992, Brian Berliner and Jeff Polk
+ * Copyright (c) 1989-1992, Brian Berliner
+ *
+ * You may distribute under the terms of the GNU General Public License as
+ * specified in the README file that comes with the CVS 1.4 kit.
+ *
+ * "update" updates the version in the present directory with respect to the RCS
+ * repository. The present version must have been created by "checkout". The
+ * user can keep up-to-date by calling "update" whenever he feels like it.
+ *
+ * The present version can be committed by "commit", but this keeps the version
+ * in tact.
+ *
+ * Arguments following the options are taken to be file names to be updated,
+ * rather than updating the entire directory.
+ *
+ * Modified or non-existent RCS files are checked out and reported as U
+ * <user_file>
+ *
+ * Modified user files are reported as M <user_file>. If both the RCS file and
+ * the user file have been modified, the user file is replaced by the result
+ * of rcsmerge, and a backup file is written for the user in .#file.version.
+ * If this throws up irreconcilable differences, the file is reported as C
+ * <user_file>, and as M <user_file> otherwise.
+ *
+ * Files added but not yet committed are reported as A <user_file>. Files
+ * removed but not yet committed are reported as R <user_file>.
+ *
+ * If the current directory contains subdirectories that hold concurrent
+ * versions, these are updated too. If the -d option was specified, new
+ * directories added to the repository are automatically created and updated
+ * as well.
+ */
+
+#include "cvs.h"
+#ifdef CLIENT_SUPPORT
+#include "update.h"
+#endif
+#ifdef SERVER_SUPPORT
+#include "md5.h"
+#endif
+
+#ifndef lint
+static const char rcsid[] = "$CVSid: @(#)update.c 1.95 94/10/22 $";
+USE(rcsid);
+#endif
+
+static int checkout_file PROTO((char *file, char *repository, List *entries,
+ List *srcfiles, Vers_TS *vers_ts, char *update_dir));
+#ifdef SERVER_SUPPORT
+static int patch_file PROTO((char *file, char *repository, List *entries,
+ List *srcfiles, Vers_TS *vers_ts, char *update_dir,
+ int *docheckout, struct stat *file_info,
+ unsigned char *checksum));
+#endif
+static int isemptydir PROTO((char *dir));
+static int merge_file PROTO((char *file, char *repository, List *entries,
+ Vers_TS *vers, char *update_dir));
+static int scratch_file PROTO((char *file, char *repository, List * entries,
+ char *update_dir));
+static Dtype update_dirent_proc PROTO((char *dir, char *repository, char *update_dir));
+static int update_dirleave_proc PROTO((char *dir, int err, char *update_dir));
+static int update_file_proc PROTO((char *file, char *update_dir, char *repository,
+ List * entries, List * srcfiles));
+#ifndef CLIENT_SUPPORT
+static int update_filesdone_proc PROTO((int err, char *repository, char *update_dir));
+#endif
+static int write_letter PROTO((char *file, int letter, char *update_dir));
+static void ignore_files PROTO((List * ilist, char *update_dir));
+#ifdef SERVER_SUPPORT
+static void join_file PROTO((char *file, List *srcfiles, Vers_TS *vers_ts,
+ char *update_dir, List *entries, char *repository));
+#else
+static void join_file PROTO((char *file, List *srcfiles, Vers_TS *vers_ts,
+ char *update_dir, List *entries));
+#endif
+
+static char *options = NULL;
+static char *tag = NULL;
+static char *date = NULL;
+static char *join_rev1, *date_rev1;
+static char *join_rev2, *date_rev2;
+static int aflag = 0;
+static int force_tag_match = 1;
+static int update_build_dirs = 0;
+static int update_prune_dirs = 0;
+static int pipeout = 0;
+#ifdef SERVER_SUPPORT
+static int patches = 0;
+#endif
+#ifdef CLIENT_SUPPORT
+List *ignlist = (List *) NULL;
+#else
+static List *ignlist = (List *) NULL;
+#endif
+static time_t last_register_time;
+static const char *const update_usage[] =
+{
+ "Usage: %s %s [-APdflRp] [-k kopt] [-r rev|-D date] [-j rev]\n",
+ " [-I ign] [-W spec] [files...]\n",
+ "\t-A\tReset any sticky tags/date/kopts.\n",
+ "\t-P\tPrune empty directories.\n",
+ "\t-d\tBuild directories, like checkout does.\n",
+ "\t-f\tForce a head revision match if tag/date not found.\n",
+ "\t-l\tLocal directory only, no recursion.\n",
+ "\t-R\tProcess directories recursively.\n",
+ "\t-p\tSend updates to standard output.\n",
+ "\t-k kopt\tUse RCS kopt -k option on checkout.\n",
+ "\t-r rev\tUpdate using specified revision/tag.\n",
+ "\t-D date\tSet date to update from.\n",
+ "\t-j rev\tMerge in changes made between current revision and rev.\n",
+ "\t-I ign\tMore files to ignore (! to reset).\n",
+ "\t-W spec\tWrappers specification line.\n",
+ NULL
+};
+
+/*
+ * update is the argv,argc based front end for arg parsing
+ */
+int
+update (argc, argv)
+ int argc;
+ char **argv;
+{
+ int c, err;
+ int local = 0; /* recursive by default */
+ int which; /* where to look for files and dirs */
+
+ if (argc == -1)
+ usage (update_usage);
+
+ ign_setup ();
+ wrap_setup ();
+
+ /* parse the args */
+ optind = 1;
+ while ((c = getopt (argc, argv, "ApPflRQqduk:r:D:j:I:W:")) != -1)
+ {
+ switch (c)
+ {
+ case 'A':
+ aflag = 1;
+ break;
+ case 'I':
+ ign_add (optarg, 0);
+ break;
+ case 'W':
+ wrap_add (optarg, 0);
+ break;
+ case 'k':
+ if (options)
+ free (options);
+ options = RCS_check_kflag (optarg);
+ break;
+ case 'l':
+ local = 1;
+ break;
+ case 'R':
+ local = 0;
+ break;
+ case 'Q':
+ case 'q':
+#ifdef SERVER_SUPPORT
+ /* The CVS 1.5 client sends these options (in addition to
+ Global_option requests), so we must ignore them. */
+ if (!server_active)
+#endif
+ error (1, 0,
+ "-q or -Q must be specified before \"%s\"",
+ command_name);
+ break;
+ case 'd':
+ update_build_dirs = 1;
+ break;
+ case 'f':
+ force_tag_match = 0;
+ break;
+ case 'r':
+ tag = optarg;
+ break;
+ case 'D':
+ date = Make_Date (optarg);
+ break;
+ case 'P':
+ update_prune_dirs = 1;
+ break;
+ case 'p':
+ pipeout = 1;
+ noexec = 1; /* so no locks will be created */
+ break;
+ case 'j':
+ if (join_rev2)
+ error (1, 0, "only two -j options can be specified");
+ if (join_rev1)
+ join_rev2 = optarg;
+ else
+ join_rev1 = optarg;
+ break;
+ case 'u':
+#ifdef SERVER_SUPPORT
+ if (server_active)
+ patches = 1;
+ else
+#endif
+ usage (update_usage);
+ break;
+ case '?':
+ default:
+ usage (update_usage);
+ break;
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+#ifdef CLIENT_SUPPORT
+ if (client_active)
+ {
+ /* The first pass does the regular update. If we receive at least
+ one patch which failed, we do a second pass and just fetch
+ those files whose patches failed. */
+ do
+ {
+ int status;
+
+ start_server ();
+
+ ign_setup ();
+
+ if (local)
+ send_arg("-l");
+ if (update_build_dirs)
+ send_arg("-d");
+ if (pipeout)
+ send_arg("-p");
+ if (!force_tag_match)
+ send_arg("-f");
+ if (aflag)
+ send_arg("-A");
+ if (update_prune_dirs)
+ send_arg("-P");
+ client_prune_dirs = update_prune_dirs;
+ option_with_arg ("-r", tag);
+ if (date)
+ client_senddate (date);
+ if (join_rev1)
+ option_with_arg ("-j", join_rev1);
+ if (join_rev2)
+ option_with_arg ("-j", join_rev2);
+
+ /* If the server supports the command "update-patches", that means
+ that it knows how to handle the -u argument to update, which
+ means to send patches instead of complete files. */
+ if (failed_patches == NULL)
+ {
+ struct request *rq;
+
+ for (rq = requests; rq->name != NULL; rq++)
+ {
+ if (strcmp (rq->name, "update-patches") == 0)
+ {
+ if (rq->status == rq_supported)
+ {
+ send_arg("-u");
+ }
+ break;
+ }
+ }
+ }
+
+ if (failed_patches == NULL)
+ send_files (argc, argv, local, aflag);
+ else
+ {
+ int i;
+
+ (void) printf ("%s client: refetching unpatchable files\n",
+ program_name);
+
+ if (toplevel_wd[0] != '\0'
+ && chdir (toplevel_wd) < 0)
+ {
+ error (1, errno, "could not chdir to %s", toplevel_wd);
+ }
+
+ for (i = 0; i < failed_patches_count; i++)
+ (void) unlink_file (failed_patches[i]);
+ send_files (failed_patches_count, failed_patches, local,
+ aflag);
+ }
+
+ failed_patches = NULL;
+ failed_patches_count = 0;
+
+ if (fprintf (to_server, "update\n") < 0)
+ error (1, errno, "writing to server");
+
+ status = get_responses_and_close ();
+ if (status != 0)
+ return status;
+
+ } while (failed_patches != NULL);
+
+ return 0;
+ }
+#endif
+
+ /*
+ * If we are updating the entire directory (for real) and building dirs
+ * as we go, we make sure there is no static entries file and write the
+ * tag file as appropriate
+ */
+ if (argc <= 0 && !pipeout)
+ {
+ if (update_build_dirs)
+ {
+ if (unlink_file (CVSADM_ENTSTAT) < 0 && ! existence_error (errno))
+ error (1, errno, "cannot remove file %s", CVSADM_ENTSTAT);
+#ifdef SERVER_SUPPORT
+ if (server_active)
+ server_clear_entstat (".", Name_Repository (NULL, NULL));
+#endif
+ }
+
+ /* keep the CVS/Tag file current with the specified arguments */
+ if (aflag || tag || date)
+ {
+ WriteTag ((char *) NULL, tag, date);
+#ifdef SERVER_SUPPORT
+ if (server_active)
+ server_set_sticky (".", Name_Repository (NULL, NULL), tag, date);
+#endif
+ }
+ }
+
+ /* look for files/dirs locally and in the repository */
+ which = W_LOCAL | W_REPOS;
+
+ /* look in the attic too if a tag or date is specified */
+ if (tag != NULL || date != NULL || joining())
+ which |= W_ATTIC;
+
+ /* call the command line interface */
+ err = do_update (argc, argv, options, tag, date, force_tag_match,
+ local, update_build_dirs, aflag, update_prune_dirs,
+ pipeout, which, join_rev1, join_rev2, (char *) NULL);
+
+ /* free the space Make_Date allocated if necessary */
+ if (date != NULL)
+ free (date);
+
+ return (err);
+}
+
+/*
+ * Command line interface to update (used by checkout)
+ */
+int
+do_update (argc, argv, xoptions, xtag, xdate, xforce, local, xbuild, xaflag,
+ xprune, xpipeout, which, xjoin_rev1, xjoin_rev2, preload_update_dir)
+ int argc;
+ char **argv;
+ char *xoptions;
+ char *xtag;
+ char *xdate;
+ int xforce;
+ int local;
+ int xbuild;
+ int xaflag;
+ int xprune;
+ int xpipeout;
+ int which;
+ char *xjoin_rev1;
+ char *xjoin_rev2;
+ char *preload_update_dir;
+{
+ int err = 0;
+ char *cp;
+
+ /* fill in the statics */
+ options = xoptions;
+ tag = xtag;
+ date = xdate;
+ force_tag_match = xforce;
+ update_build_dirs = xbuild;
+ aflag = xaflag;
+ update_prune_dirs = xprune;
+ pipeout = xpipeout;
+
+ /* setup the join support */
+ join_rev1 = xjoin_rev1;
+ join_rev2 = xjoin_rev2;
+ if (join_rev1 && (cp = strchr (join_rev1, ':')) != NULL)
+ {
+ *cp++ = '\0';
+ date_rev1 = Make_Date (cp);
+ }
+ else
+ date_rev1 = (char *) NULL;
+ if (join_rev2 && (cp = strchr (join_rev2, ':')) != NULL)
+ {
+ *cp++ = '\0';
+ date_rev2 = Make_Date (cp);
+ }
+ else
+ date_rev2 = (char *) NULL;
+
+ /* call the recursion processor */
+ err = start_recursion (update_file_proc, update_filesdone_proc,
+ update_dirent_proc, update_dirleave_proc,
+ argc, argv, local, which, aflag, 1,
+ preload_update_dir, 1, 0);
+
+ /* see if we need to sleep before returning */
+ if (last_register_time)
+ {
+ time_t now;
+
+ (void) time (&now);
+ if (now == last_register_time)
+ sleep (1); /* to avoid time-stamp races */
+ }
+
+ return (err);
+}
+
+/*
+ * This is the callback proc for update. It is called for each file in each
+ * directory by the recursion code. The current directory is the local
+ * instantiation. file is the file name we are to operate on. update_dir is
+ * set to the path relative to where we started (for pretty printing).
+ * repository is the repository. entries and srcfiles are the pre-parsed
+ * entries and source control files.
+ *
+ * This routine decides what needs to be done for each file and does the
+ * appropriate magic for checkout
+ */
+static int
+update_file_proc (file, update_dir, repository, entries, srcfiles)
+ char *file;
+ char *update_dir;
+ char *repository;
+ List *entries;
+ List *srcfiles;
+{
+ int retval;
+ Ctype status;
+ Vers_TS *vers;
+
+ status = Classify_File (file, tag, date, options, force_tag_match,
+ aflag, repository, entries, srcfiles, &vers,
+ update_dir, pipeout);
+ if (pipeout)
+ {
+ /*
+ * We just return success without doing anything if any of the really
+ * funky cases occur
+ *
+ * If there is still a valid RCS file, do a regular checkout type
+ * operation
+ */
+ switch (status)
+ {
+ case T_UNKNOWN: /* unknown file was explicitly asked
+ * about */
+ case T_REMOVE_ENTRY: /* needs to be un-registered */
+ case T_ADDED: /* added but not committed */
+ retval = 0;
+ break;
+ case T_CONFLICT: /* old punt-type errors */
+ retval = 1;
+ break;
+ case T_UPTODATE: /* file was already up-to-date */
+ case T_NEEDS_MERGE: /* needs merging */
+ case T_MODIFIED: /* locally modified */
+ case T_REMOVED: /* removed but not committed */
+ case T_CHECKOUT: /* needs checkout */
+#ifdef SERVER_SUPPORT
+ case T_PATCH: /* needs patch */
+#endif
+ retval = checkout_file (file, repository, entries, srcfiles,
+ vers, update_dir);
+ break;
+
+ default: /* can't ever happen :-) */
+ error (0, 0,
+ "unknown file status %d for file %s", status, file);
+ retval = 0;
+ break;
+ }
+ }
+ else
+ {
+ switch (status)
+ {
+ case T_UNKNOWN: /* unknown file was explicitly asked
+ * about */
+ case T_UPTODATE: /* file was already up-to-date */
+ retval = 0;
+ break;
+ case T_CONFLICT: /* old punt-type errors */
+ retval = 1;
+ (void) write_letter (file, 'C', update_dir);
+ break;
+ case T_NEEDS_MERGE: /* needs merging */
+ if (noexec)
+ {
+ retval = 1;
+ (void) write_letter (file, 'C', update_dir);
+ }
+ else
+ {
+ if (wrap_merge_is_copy (file))
+ /* Should we be warning the user that we are
+ * overwriting the user's copy of the file? */
+ retval = checkout_file (file, repository, entries,
+ srcfiles, vers, update_dir);
+ else
+ retval = merge_file (file, repository, entries,
+ vers, update_dir);
+ }
+ break;
+ case T_MODIFIED: /* locally modified */
+ retval = 0;
+ if (vers->ts_conflict)
+ {
+ char *filestamp;
+ int retcode;
+
+ /*
+ * If the timestamp has changed and no conflict indicators
+ * are found, it isn't a 'C' any more.
+ */
+#ifdef SERVER_SUPPORT
+ if (server_active)
+ retcode = vers->ts_conflict[0] != '=';
+ else {
+ filestamp = time_stamp (file);
+ retcode = strcmp (vers->ts_conflict, filestamp);
+ free (filestamp);
+ }
+#else
+ filestamp = time_stamp (file);
+ retcode = strcmp (vers->ts_conflict, filestamp);
+ free (filestamp);
+#endif
+
+ if (retcode)
+ {
+ /*
+ * If the timestamps differ, look for Conflict
+ * indicators to see if 'C' anyway.
+ */
+ run_setup ("%s", GREP);
+ run_arg (RCS_MERGE_PAT);
+ run_arg (file);
+ retcode = run_exec (RUN_TTY, DEVNULL,
+ RUN_TTY,RUN_NORMAL);
+ if (retcode == -1)
+ {
+ if (update_dir[0] == '\0')
+ error (1, errno,
+ "fork failed while examining conflict in `%s'",
+ file);
+ else
+ error (1, errno,
+ "fork failed while examining conflict in `%s/%s'",
+ update_dir, file);
+ }
+ }
+ if (!retcode)
+ {
+ (void) write_letter (file, 'C', update_dir);
+ retval = 1;
+ }
+ else
+ {
+ /* Reregister to clear conflict flag. */
+ Register (entries, file, vers->vn_rcs, vers->ts_rcs,
+ vers->options, vers->tag,
+ vers->date, (char *)0);
+ }
+ }
+ if (!retval)
+ retval = write_letter (file, 'M', update_dir);
+ break;
+#ifdef SERVER_SUPPORT
+ case T_PATCH: /* needs patch */
+ if (patches)
+ {
+ int docheckout;
+ struct stat file_info;
+ unsigned char checksum[16];
+
+ retval = patch_file (file, repository, entries, srcfiles,
+ vers, update_dir, &docheckout,
+ &file_info, checksum);
+ if (! docheckout)
+ {
+ if (server_active && retval == 0)
+ server_updated (file, update_dir, repository,
+ SERVER_PATCHED, &file_info,
+ checksum);
+ break;
+ }
+ }
+ /* Fall through. */
+ /* If we're not running as a server, just check the
+ file out. It's simpler and faster than starting up
+ two new processes (diff and patch). */
+ /* Fall through. */
+#endif
+ case T_CHECKOUT: /* needs checkout */
+ retval = checkout_file (file, repository, entries, srcfiles,
+ vers, update_dir);
+#ifdef SERVER_SUPPORT
+ if (server_active && retval == 0)
+ server_updated (file, update_dir, repository,
+ SERVER_UPDATED, (struct stat *) NULL,
+ (unsigned char *) NULL);
+#endif
+ break;
+ case T_ADDED: /* added but not committed */
+ retval = write_letter (file, 'A', update_dir);
+ break;
+ case T_REMOVED: /* removed but not committed */
+ retval = write_letter (file, 'R', update_dir);
+ break;
+ case T_REMOVE_ENTRY: /* needs to be un-registered */
+ retval = scratch_file (file, repository, entries, update_dir);
+#ifdef SERVER_SUPPORT
+ if (server_active && retval == 0)
+ server_updated (file, update_dir, repository,
+ SERVER_UPDATED, (struct stat *) NULL,
+ (unsigned char *) NULL);
+#endif
+ break;
+ default: /* can't ever happen :-) */
+ error (0, 0,
+ "unknown file status %d for file %s", status, file);
+ retval = 0;
+ break;
+ }
+ }
+
+ /* only try to join if things have gone well thus far */
+ if (retval == 0 && join_rev1)
+#ifdef SERVER_SUPPORT
+ join_file (file, srcfiles, vers, update_dir, entries, repository);
+#else
+ join_file (file, srcfiles, vers, update_dir, entries);
+#endif
+
+ /* if this directory has an ignore list, add this file to it */
+ if (ignlist)
+ {
+ Node *p;
+
+ p = getnode ();
+ p->type = FILES;
+ p->key = xstrdup (file);
+ if (addnode (ignlist, p) != 0)
+ freenode (p);
+ }
+
+ freevers_ts (&vers);
+ return (retval);
+}
+
+/*
+ * update_filesdone_proc () is used
+ */
+/* ARGSUSED */
+#ifdef CLIENT_SUPPORT
+/* Also used by client.c */
+int
+#else
+static int
+#endif
+update_filesdone_proc (err, repository, update_dir)
+ int err;
+ char *repository;
+ char *update_dir;
+{
+ /* if this directory has an ignore list, process it then free it */
+ if (ignlist)
+ {
+ ignore_files (ignlist, update_dir);
+ dellist (&ignlist);
+ }
+
+ /* Clean up CVS admin dirs if we are export */
+#ifdef CLIENT_SUPPORT
+ /* In the client, we need to clean these up after we create them. Doing
+ it here might would clean up the user's previous contents even on
+ SIGINT which probably is bad. */
+ if (!client_active && strcmp (command_name, "export") == 0)
+#else
+ if (strcmp (command_name, "export") == 0)
+#endif
+ {
+ run_setup ("%s -fr", RM);
+ run_arg (CVSADM);
+ (void) run_exec (RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL);
+ }
+#ifdef CVSADM_ROOT
+#ifdef SERVER_SUPPORT
+ else if (!server_active && !pipeout)
+#else
+ else if (!pipeout)
+#endif /* SERVER_SUPPORT */
+ {
+ /* If there is no CVS/Root file, add one */
+#ifdef CLIENT_SUPPORT
+ if (!isfile (CVSADM_ROOT)
+ /* but only if we want it */
+ && ! (getenv ("CVS_IGNORE_REMOTE_ROOT") && strchr (CVSroot, ':'))
+ )
+#else /* No CLIENT_SUPPORT */
+ if (!isfile (CVSADM_ROOT))
+#endif /* No CLIENT_SUPPORT */
+ Create_Root( (char *) NULL, CVSroot );
+ }
+#endif /* CVSADM_ROOT */
+
+ return (err);
+}
+
+/*
+ * update_dirent_proc () is called back by the recursion processor before a
+ * sub-directory is processed for update. In this case, update_dirent proc
+ * will probably create the directory unless -d isn't specified and this is a
+ * new directory. A return code of 0 indicates the directory should be
+ * processed by the recursion code. A return of non-zero indicates the
+ * recursion code should skip this directory.
+ */
+static Dtype
+update_dirent_proc (dir, repository, update_dir)
+ char *dir;
+ char *repository;
+ char *update_dir;
+{
+ if (ignore_directory (update_dir))
+ {
+ /* print the warm fuzzy message */
+ if (!quiet)
+ error (0, 0, "Ignoring %s", update_dir);
+ return R_SKIP_ALL;
+ }
+
+ if (!isdir (dir))
+ {
+ /* if we aren't building dirs, blow it off */
+ if (!update_build_dirs)
+ return (R_SKIP_ALL);
+
+ if (noexec)
+ {
+ /* ignore the missing dir if -n is specified */
+ error (0, 0, "New directory `%s' -- ignored", dir);
+ return (R_SKIP_ALL);
+ }
+ else
+ {
+ /* otherwise, create the dir and appropriate adm files */
+ make_directory (dir);
+ Create_Admin (dir, update_dir, repository, tag, date);
+ }
+ }
+
+ /*
+ * If we are building dirs and not going to stdout, we make sure there is
+ * no static entries file and write the tag file as appropriate
+ */
+ if (!pipeout)
+ {
+ if (update_build_dirs)
+ {
+ char tmp[PATH_MAX];
+
+ (void) sprintf (tmp, "%s/%s", dir, CVSADM_ENTSTAT);
+ if (unlink_file (tmp) < 0 && ! existence_error (errno))
+ error (1, errno, "cannot remove file %s", tmp);
+#ifdef SERVER_SUPPORT
+ if (server_active)
+ server_clear_entstat (update_dir, repository);
+#endif
+ }
+
+ /* keep the CVS/Tag file current with the specified arguments */
+ if (aflag || tag || date)
+ {
+ WriteTag (dir, tag, date);
+#ifdef SERVER_SUPPORT
+ if (server_active)
+ server_set_sticky (update_dir, repository, tag, date);
+#endif
+ }
+
+ /* initialize the ignore list for this directory */
+ ignlist = getlist ();
+ }
+
+ /* print the warm fuzzy message */
+ if (!quiet)
+ error (0, 0, "Updating %s", update_dir);
+
+ return (R_PROCESS);
+}
+
+/*
+ * update_dirleave_proc () is called back by the recursion code upon leaving
+ * a directory. It will prune empty directories if needed and will execute
+ * any appropriate update programs.
+ */
+/* ARGSUSED */
+static int
+update_dirleave_proc (dir, err, update_dir)
+ char *dir;
+ int err;
+ char *update_dir;
+{
+ FILE *fp;
+
+ /* run the update_prog if there is one */
+ if (err == 0 && !pipeout && !noexec &&
+ (fp = fopen (CVSADM_UPROG, "r")) != NULL)
+ {
+ char *cp;
+ char *repository;
+ char line[MAXLINELEN];
+
+ repository = Name_Repository ((char *) NULL, update_dir);
+ if (fgets (line, sizeof (line), fp) != NULL)
+ {
+ if ((cp = strrchr (line, '\n')) != NULL)
+ *cp = '\0';
+ run_setup ("%s %s", line, repository);
+ (void) printf ("%s %s: Executing '", program_name, command_name);
+ run_print (stdout);
+ (void) printf ("'\n");
+ (void) run_exec (RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL);
+ }
+ (void) fclose (fp);
+ free (repository);
+ }
+
+ /* FIXME: chdir ("..") loses with symlinks. */
+ /* Prune empty dirs on the way out - if necessary */
+ (void) chdir ("..");
+ if (update_prune_dirs && isemptydir (dir))
+ {
+ run_setup ("%s -fr", RM);
+ run_arg (dir);
+ (void) run_exec (RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL);
+ }
+
+ return (err);
+}
+
+/*
+ * Returns 1 if the argument directory is completely empty, other than the
+ * existence of the CVS directory entry. Zero otherwise.
+ */
+static int
+isemptydir (dir)
+ char *dir;
+{
+ DIR *dirp;
+ struct dirent *dp;
+
+ if ((dirp = opendir (dir)) == NULL)
+ {
+ error (0, 0, "cannot open directory %s for empty check", dir);
+ return (0);
+ }
+ while ((dp = readdir (dirp)) != NULL)
+ {
+ if (strcmp (dp->d_name, ".") != 0 && strcmp (dp->d_name, "..") != 0 &&
+ strcmp (dp->d_name, CVSADM) != 0)
+ {
+ (void) closedir (dirp);
+ return (0);
+ }
+ }
+ (void) closedir (dirp);
+ return (1);
+}
+
+/*
+ * scratch the Entries file entry associated with a file
+ */
+static int
+scratch_file (file, repository, entries, update_dir)
+ char *file;
+ char *repository;
+ List *entries;
+ char *update_dir;
+{
+ history_write ('W', update_dir, "", file, repository);
+ Scratch_Entry (entries, file);
+ (void) unlink_file (file);
+ return (0);
+}
+
+/*
+ * check out a file - essentially returns the result of the fork on "co".
+ */
+static int
+checkout_file (file, repository, entries, srcfiles, vers_ts, update_dir)
+ char *file;
+ char *repository;
+ List *entries;
+ List *srcfiles;
+ Vers_TS *vers_ts;
+ char *update_dir;
+{
+ char backup[PATH_MAX];
+ int set_time, retval = 0;
+ int retcode = 0;
+#ifdef DEATH_SUPPORT
+ int file_is_dead;
+#endif
+
+ /* don't screw with backup files if we're going to stdout */
+ if (!pipeout)
+ {
+ (void) sprintf (backup, "%s/%s%s", CVSADM, CVSPREFIX, file);
+ if (isfile (file))
+ rename_file (file, backup);
+ else
+ (void) unlink_file (backup);
+ }
+
+#ifdef DEATH_SUPPORT
+ file_is_dead = RCS_isdead (vers_ts->srcfile, vers_ts->vn_rcs);
+
+ if (!file_is_dead) {
+#endif
+
+ run_setup ("%s%s -q -r%s %s", Rcsbin, RCS_CO, vers_ts->vn_tag,
+ vers_ts->options);
+
+ /*
+ * if we are checking out to stdout, print a nice message to stderr, and
+ * add the -p flag to the command
+ */
+ if (pipeout)
+ {
+ run_arg ("-p");
+ if (!quiet)
+ {
+ (void) fprintf (stderr, "===================================================================\n");
+ if (update_dir[0])
+ (void) fprintf (stderr, "Checking out %s/%s\n",
+ update_dir, file);
+ else
+ (void) fprintf (stderr, "Checking out %s\n", file);
+ (void) fprintf (stderr, "RCS: %s\n", vers_ts->srcfile->path);
+ (void) fprintf (stderr, "VERS: %s\n", vers_ts->vn_rcs);
+ (void) fprintf (stderr, "***************\n");
+ }
+ }
+
+ /* tack on the rcs and maybe the user file */
+ run_arg (vers_ts->srcfile->path);
+ if (!pipeout)
+ run_arg (file);
+
+#ifdef DEATH_SUPPORT
+ }
+ if (file_is_dead || (retcode = run_exec (RUN_TTY, RUN_TTY, RUN_TTY,
+#else
+ if ((retcode = run_exec (RUN_TTY, RUN_TTY, RUN_TTY,
+#endif
+ (pipeout ? (RUN_NORMAL|RUN_REALLY) : RUN_NORMAL))) == 0)
+ {
+ if (!pipeout)
+ {
+ Vers_TS *xvers_ts;
+#ifdef DEATH_SUPPORT
+ int resurrecting;
+
+ resurrecting = 0;
+
+ if (file_is_dead && joining())
+ {
+ /* when joining, we need to get dead files checked
+ out. Try harder. */
+ run_setup ("%s%s -q -r%s %s", Rcsbin, RCS_CO, vers_ts->vn_rcs,
+ vers_ts->options);
+
+ run_arg ("-f");
+ run_arg (vers_ts->srcfile->path);
+ run_arg (file);
+ if ((retcode = run_exec (RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL)) != 0)
+ {
+ error (retcode == -1 ? 1 : 0, retcode == -1 ? errno : 0,
+ "could not check out %s", file);
+ (void) unlink_file (backup);
+ return (retcode);
+ }
+ file_is_dead = 0;
+ resurrecting = 1;
+ }
+
+ if (cvswrite == TRUE && !file_is_dead)
+ xchmod (file, 1);
+#else /* No DEATH_SUPPORT */
+ if (cvswrite == TRUE)
+ xchmod (file, 1);
+#endif /* No DEATH_SUPPORT */
+
+ /* set the time from the RCS file iff it was unknown before */
+ if (vers_ts->vn_user == NULL ||
+ strncmp (vers_ts->ts_rcs, "Initial", 7) == 0)
+ {
+ set_time = 1;
+ }
+ else
+ set_time = 0;
+
+ wrap_fromcvs_process_file (file);
+
+ xvers_ts = Version_TS (repository, options, tag, date, file,
+ force_tag_match, set_time, entries, srcfiles);
+ if (strcmp (xvers_ts->options, "-V4") == 0)
+ xvers_ts->options[0] = '\0';
+ /* If no keyword expansion was specified on command line,
+ use whatever was in the file. This is how we tell the client
+ whether a file is binary. */
+ if (xvers_ts->options[0] == '\0')
+ {
+ if (vers_ts->srcfile->expand != NULL)
+ {
+ free (xvers_ts->options);
+ xvers_ts->options =
+ xmalloc (strlen (vers_ts->srcfile->expand) + 3);
+ strcpy (xvers_ts->options, "-k");
+ strcat (xvers_ts->options, vers_ts->srcfile->expand);
+ }
+ }
+
+ (void) time (&last_register_time);
+
+#ifdef DEATH_SUPPORT
+ if (file_is_dead)
+ {
+ if (xvers_ts->vn_user != NULL)
+ {
+ if (update_dir[0] == '\0')
+ error (0, 0,
+ "warning: %s is not (any longer) pertinent",
+ file);
+ else
+ error (0, 0,
+ "warning: %s/%s is not (any longer) pertinent",
+ update_dir, file);
+ }
+ Scratch_Entry (entries, file);
+ if (unlink_file (file) < 0 && ! existence_error (errno))
+ {
+ if (update_dir[0] == '\0')
+ error (0, errno, "cannot remove %s", file);
+ else
+ error (0, errno, "cannot remove %s/%s", update_dir,
+ file);
+ }
+ }
+ else
+ Register (entries, file,
+ resurrecting ? "0" : xvers_ts->vn_rcs,
+ xvers_ts->ts_user, xvers_ts->options,
+ xvers_ts->tag, xvers_ts->date,
+ (char *)0); /* Clear conflict flag on fresh checkout */
+#else /* No DEATH_SUPPORT */
+ Register (entries, file, xvers_ts->vn_rcs, xvers_ts->ts_user,
+ xvers_ts->options, xvers_ts->tag, xvers_ts->date,
+ (char *)0); /* Clear conflict flag on fresh checkout */
+#endif /* No DEATH_SUPPORT */
+
+ /* fix up the vers structure, in case it is used by join */
+ if (join_rev1)
+ {
+ if (vers_ts->vn_user != NULL)
+ free (vers_ts->vn_user);
+ if (vers_ts->vn_rcs != NULL)
+ free (vers_ts->vn_rcs);
+ vers_ts->vn_user = xstrdup (xvers_ts->vn_rcs);
+ vers_ts->vn_rcs = xstrdup (xvers_ts->vn_rcs);
+ }
+
+ /* If this is really Update and not Checkout, recode history */
+ if (strcmp (command_name, "update") == 0)
+ history_write ('U', update_dir, xvers_ts->vn_rcs, file,
+ repository);
+
+ freevers_ts (&xvers_ts);
+
+#ifdef DEATH_SUPPORT
+ if (!really_quiet && !file_is_dead)
+#else
+ if (!really_quiet)
+#endif
+ {
+ if (update_dir[0])
+ (void) printf ("U %s/%s\n", update_dir, file);
+ else
+ (void) printf ("U %s\n", file);
+ }
+ }
+ }
+ else
+ {
+ int old_errno = errno; /* save errno value over the rename */
+
+ if (!pipeout && isfile (backup))
+ rename_file (backup, file);
+
+ error (retcode == -1 ? 1 : 0, retcode == -1 ? old_errno : 0,
+ "could not check out %s", file);
+
+ retval = retcode;
+ }
+
+ if (!pipeout)
+ (void) unlink_file (backup);
+
+ return (retval);
+}
+
+#ifdef SERVER_SUPPORT
+/* Patch a file. Runs rcsdiff. This is only done when running as the
+ * server. The hope is that the diff will be smaller than the file
+ * itself.
+ */
+static int
+patch_file (file, repository, entries, srcfiles, vers_ts, update_dir,
+ docheckout, file_info, checksum)
+ char *file;
+ char *repository;
+ List *entries;
+ List *srcfiles;
+ Vers_TS *vers_ts;
+ char *update_dir;
+ int *docheckout;
+ struct stat *file_info;
+ unsigned char *checksum;
+{
+ char backup[PATH_MAX];
+ char file1[PATH_MAX];
+ char file2[PATH_MAX];
+ int retval = 0;
+ int retcode = 0;
+ int fail;
+ FILE *e;
+
+ *docheckout = 0;
+
+ if (pipeout || joining ())
+ {
+ *docheckout = 1;
+ return 0;
+ }
+
+ (void) sprintf (backup, "%s/%s%s", CVSADM, CVSPREFIX, file);
+ if (isfile (file))
+ rename_file (file, backup);
+ else
+ (void) unlink_file (backup);
+
+ (void) sprintf (file1, "%s/%s%s-1", CVSADM, CVSPREFIX, file);
+ (void) sprintf (file2, "%s/%s%s-2", CVSADM, CVSPREFIX, file);
+
+ fail = 0;
+
+ /* We need to check out both revisions first, to see if either one
+ has a trailing newline. Because of this, we don't use rcsdiff,
+ but just use diff. */
+ run_setup ("%s%s -q -p -r%s %s %s", Rcsbin, RCS_CO, vers_ts->vn_user,
+ vers_ts->options, vers_ts->srcfile->path);
+ if (run_exec (RUN_TTY, file1, RUN_TTY, RUN_NORMAL) != 0)
+ fail = 1;
+ else
+ {
+ e = fopen (file1, "r");
+ if (e == NULL)
+ fail = 1;
+ else
+ {
+ if (fseek (e, (long) -1, SEEK_END) == 0
+ && getc (e) != '\n')
+ {
+ fail = 1;
+ }
+ fclose (e);
+ }
+ }
+
+ if (! fail)
+ {
+ /* Check it out into file, and then move to file2, so that we
+ can get the right modes into *FILE_INFO. We can't check it
+ out directly into file2 because co doesn't understand how
+ to do that. */
+ run_setup ("%s%s -q -r%s %s %s %s", Rcsbin, RCS_CO, vers_ts->vn_rcs,
+ vers_ts->options, vers_ts->srcfile->path, file);
+ if (run_exec (RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL) != 0)
+ fail = 1;
+ else
+ {
+ if (!isreadable (file))
+ {
+ /* File is dead. */
+ fail = 1;
+ }
+ else
+ {
+ rename_file (file, file2);
+ if (cvswrite == TRUE)
+ xchmod (file2, 1);
+ e = fopen (file2, "r");
+ if (e == NULL)
+ fail = 1;
+ else
+ {
+ struct MD5Context context;
+ int nl;
+ unsigned char buf[8192];
+ unsigned len;
+
+ nl = 0;
+
+ /* Compute the MD5 checksum and make sure there is
+ a trailing newline. */
+ MD5Init (&context);
+ while ((len = fread (buf, 1, sizeof buf, e)) != 0)
+ {
+ nl = buf[len - 1] == '\n';
+ MD5Update (&context, buf, len);
+ }
+ MD5Final (checksum, &context);
+
+ if (ferror (e) || ! nl)
+ {
+ fail = 1;
+ }
+
+ fclose (e);
+ }
+ }
+ }
+ }
+
+ if (! fail)
+ {
+ /* FIXME: This whole thing with diff/patch is rather more
+ convoluted than necessary (lots of forks and execs, need to
+ worry about versions of diff and patch, etc.). Also, we
+ send context lines which aren't needed (in the rare case in
+ which the diff doesn't apply, the checksum would catches it).
+ Solution perhaps is to librarify the RCS routines which apply
+ deltas or something equivalent. */
+ /* This is -c, not -u, because we have no way of knowing which
+ DIFF is in use. */
+ run_setup ("%s -c %s %s", DIFF, file1, file2);
+
+ /* A retcode of 0 means no differences. 1 means some differences. */
+ if ((retcode = run_exec (RUN_TTY, file, RUN_TTY, RUN_NORMAL)) != 0
+ && retcode != 1)
+ {
+ fail = 1;
+ }
+ else
+ {
+#define BINARY "Binary"
+ char buf[sizeof BINARY];
+ unsigned int c;
+
+ /* Check the diff output to make sure patch will be handle it. */
+ e = fopen (file, "r");
+ if (e == NULL)
+ error (1, errno, "could not open diff output file %s", file);
+ c = fread (buf, 1, sizeof BINARY - 1, e);
+ buf[c] = '\0';
+ if (strcmp (buf, BINARY) == 0)
+ {
+ /* These are binary files. We could use diff -a, but
+ patch can't handle that. */
+ fail = 1;
+ }
+ fclose (e);
+ }
+ }
+
+ if (! fail)
+ {
+ Vers_TS *xvers_ts;
+
+ /* This stuff is just copied blindly from checkout_file. I
+ don't really know what it does. */
+ xvers_ts = Version_TS (repository, options, tag, date, file,
+ force_tag_match, 0, entries, srcfiles);
+ if (strcmp (xvers_ts->options, "-V4") == 0)
+ xvers_ts->options[0] = '\0';
+
+ Register (entries, file, xvers_ts->vn_rcs,
+ xvers_ts->ts_user, xvers_ts->options,
+ xvers_ts->tag, xvers_ts->date, NULL);
+
+ if (stat (file2, file_info) < 0)
+ error (1, errno, "could not stat %s", file2);
+
+ /* If this is really Update and not Checkout, recode history */
+ if (strcmp (command_name, "update") == 0)
+ history_write ('P', update_dir, xvers_ts->vn_rcs, file,
+ repository);
+
+ freevers_ts (&xvers_ts);
+
+ if (!really_quiet)
+ {
+ if (update_dir[0])
+ (void) printf ("P %s/%s\n", update_dir, file);
+ else
+ (void) printf ("P %s\n", file);
+ }
+ }
+ else
+ {
+ int old_errno = errno; /* save errno value over the rename */
+
+ if (isfile (backup))
+ rename_file (backup, file);
+
+ if (retcode != 0 && retcode != 1)
+ error (retcode == -1 ? 1 : 0, retcode == -1 ? old_errno : 0,
+ "could not diff %s", file);
+
+ *docheckout = 1;
+ retval = retcode;
+ }
+
+ (void) unlink_file (backup);
+ (void) unlink_file (file1);
+ (void) unlink_file (file2);
+
+ return (retval);
+}
+#endif
+
+/*
+ * Several of the types we process only print a bit of information consisting
+ * of a single letter and the name.
+ */
+static int
+write_letter (file, letter, update_dir)
+ char *file;
+ int letter;
+ char *update_dir;
+{
+ if (!really_quiet)
+ {
+ if (update_dir[0])
+ (void) printf ("%c %s/%s\n", letter, update_dir, file);
+ else
+ (void) printf ("%c %s\n", letter, file);
+ }
+ return (0);
+}
+
+/*
+ * Do all the magic associated with a file which needs to be merged
+ */
+static int
+merge_file (file, repository, entries, vers, update_dir)
+ char *file;
+ char *repository;
+ List *entries;
+ Vers_TS *vers;
+ char *update_dir;
+{
+ char user[PATH_MAX];
+ char backup[PATH_MAX];
+ int status;
+ int retcode = 0;
+
+ /*
+ * The users currently modified file is moved to a backup file name
+ * ".#filename.version", so that it will stay around for a few days
+ * before being automatically removed by some cron daemon. The "version"
+ * is the version of the file that the user was most up-to-date with
+ * before the merge.
+ */
+ (void) sprintf (backup, "%s%s.%s", BAKPREFIX, file, vers->vn_user);
+ if (update_dir[0])
+ (void) sprintf (user, "%s/%s", update_dir, file);
+ else
+ (void) strcpy (user, file);
+
+ (void) unlink_file (backup);
+ copy_file (file, backup);
+ xchmod (file, 1);
+
+ status = RCS_merge(vers->srcfile->path,
+ vers->options, vers->vn_user, vers->vn_rcs);
+ if (status != 0 && status != 1)
+ {
+ error (0, status == -1 ? errno : 0,
+ "could not merge revision %s of %s", vers->vn_user, user);
+ error (status == -1 ? 1 : 0, 0, "restoring %s from backup file %s",
+ user, backup);
+ rename_file (backup, file);
+ return (1);
+ }
+
+ if (strcmp (vers->options, "-V4") == 0)
+ vers->options[0] = '\0';
+ (void) time (&last_register_time);
+ {
+ char *cp = 0;
+
+ if (status)
+ cp = time_stamp (file);
+ Register (entries, file, vers->vn_rcs, vers->ts_rcs, vers->options,
+ vers->tag, vers->date, cp);
+ if (cp)
+ free (cp);
+ }
+
+ /* fix up the vers structure, in case it is used by join */
+ if (join_rev1)
+ {
+ if (vers->vn_user != NULL)
+ free (vers->vn_user);
+ vers->vn_user = xstrdup (vers->vn_rcs);
+ }
+
+#ifdef SERVER_SUPPORT
+ /* Send the new contents of the file before the message. If we
+ wanted to be totally correct, we would have the client write
+ the message only after the file has safely been written. */
+ if (server_active)
+ {
+ server_copy_file (file, update_dir, repository, backup);
+ server_updated (file, update_dir, repository, SERVER_MERGED,
+ (struct stat *) NULL, (unsigned char *) NULL);
+ }
+#endif
+
+ if (!noexec && !xcmp (backup, file))
+ {
+ printf ("%s already contains the differences between %s and %s\n",
+ user, vers->vn_user, vers->vn_rcs);
+ history_write ('G', update_dir, vers->vn_rcs, file, repository);
+ return (0);
+ }
+
+ if (status == 1)
+ {
+ if (!noexec)
+ error (0, 0, "conflicts found in %s", user);
+
+ if (!really_quiet)
+ (void) printf ("C %s\n", user);
+
+ history_write ('C', update_dir, vers->vn_rcs, file, repository);
+
+ }
+ else if (retcode == -1)
+ {
+ error (1, errno, "fork failed while examining update of %s", user);
+ }
+ else
+ {
+ if (!really_quiet)
+ (void) printf ("M %s\n", user);
+ history_write ('G', update_dir, vers->vn_rcs, file, repository);
+ }
+ return (0);
+}
+
+/*
+ * Do all the magic associated with a file which needs to be joined
+ * (-j option)
+ */
+static void
+#ifdef SERVER_SUPPORT
+join_file (file, srcfiles, vers, update_dir, entries, repository)
+ char *repository;
+#else
+join_file (file, srcfiles, vers, update_dir, entries)
+#endif
+ char *file;
+ List *srcfiles;
+ Vers_TS *vers;
+ char *update_dir;
+ List *entries;
+{
+ char user[PATH_MAX];
+ char backup[PATH_MAX];
+ char *options;
+ int status;
+
+ char *rev1;
+ char *rev2;
+ char *jrev1;
+ char *jrev2;
+ char *jdate1;
+ char *jdate2;
+
+ jrev1 = join_rev1;
+ jrev2 = join_rev2;
+ jdate1 = date_rev1;
+ jdate2 = date_rev2;
+
+ if (wrap_merge_is_copy (file))
+ {
+ /* FIXME: Should be including update_dir in message. */
+ error (0, 0,
+ "Cannot merge %s because it is a merge-by-copy file.", file);
+ return;
+ }
+
+ /* determine if we need to do anything at all */
+ if (vers->srcfile == NULL ||
+ vers->srcfile->path == NULL)
+ {
+ return;
+ }
+
+ /* in all cases, use two revs. */
+
+ /* if only one rev is specified, it becomes the second rev */
+ if (jrev2 == NULL)
+ {
+ jrev2 = jrev1;
+ jrev1 = NULL;
+ jdate2 = jdate1;
+ jdate1 = NULL;
+ }
+
+ /* The file in the working directory doesn't exist in CVS/Entries.
+ FIXME: Shouldn't this case result in additional processing (if
+ the file was added going from rev1 to rev2, then do the equivalent
+ of a "cvs add")? (yes; easier said than done.. :-) */
+ if (vers->vn_user == NULL)
+ {
+ /* No merge possible YET. */
+ if (jdate2 != NULL)
+ error (0, 0,
+ "file %s is present in revision %s as of %s",
+ file, jrev2, jdate2);
+ else
+ error (0, 0,
+ "file %s is present in revision %s",
+ file, jrev2);
+ return;
+ }
+
+ /* Fix for bug CVS/193:
+ * Used to dump core if the file had been removed on the current branch.
+ */
+ if (strcmp(vers->vn_user, "0") == 0)
+ {
+ error(0, 0,
+ "file %s has been deleted",
+ file);
+ return;
+ }
+
+ /* convert the second rev spec, walking branches and dates. */
+
+ rev2 = RCS_getversion (vers->srcfile, jrev2, jdate2, 1, 0);
+ if (rev2 == NULL)
+ {
+ if (!quiet)
+ {
+ if (jdate2 != NULL)
+ error (0, 0,
+ "cannot find revision %s as of %s in file %s",
+ jrev2, jdate2, file);
+ else
+ error (0, 0,
+ "cannot find revision %s in file %s",
+ jrev2, file);
+ }
+ return;
+ }
+
+ /* skip joining identical revs */
+ if (strcmp (rev2, vers->vn_user) == 0)
+ {
+ /* No merge necessary. */
+ free (rev2);
+ return;
+ }
+
+ if (jrev1 == NULL)
+ {
+ char *tst;
+ /* if the first rev is missing, then it is implied to be the
+ greatest common ancestor of both the join rev, and the
+ checked out rev. */
+
+ /* FIXME: What is this check for '!' about? If it is legal to
+ have '!' in the first character of vn_user, it isn't
+ documented at struct vers_ts in cvs.h. */
+ tst = vers->vn_user;
+ if (*tst == '!')
+ {
+ /* file was dead. merge anyway and pretend it's been
+ added. */
+ ++tst;
+ Register (entries, file, "0", vers->ts_user, vers->options,
+ vers->tag, (char *) 0, (char *) 0);
+ }
+ rev1 = gca (tst, rev2);
+ if (rev1 == NULL)
+ {
+ /* this should not be possible */
+ error (0, 0, "bad gca");
+ abort();
+ }
+
+ tst = RCS_gettag (vers->srcfile, rev2, 1, 0);
+ if (tst == NULL)
+ {
+ /* this should not be possible. */
+ error (0, 0, "cannot find gca");
+ abort();
+ }
+
+ free (tst);
+
+ /* these two cases are noops */
+ if (strcmp (rev1, rev2) == 0)
+ {
+ free (rev1);
+ free (rev2);
+ return;
+ }
+ }
+ else
+ {
+ /* otherwise, convert the first rev spec, walking branches and
+ dates. */
+
+ rev1 = RCS_getversion (vers->srcfile, jrev1, jdate1, 1, 0);
+ if (rev1 == NULL)
+ {
+ if (!quiet) {
+ if (jdate1 != NULL)
+ error (0, 0,
+ "cannot find revision %s as of %s in file %s",
+ jrev1, jdate1, file);
+ else
+ error (0, 0,
+ "cannot find revision %s in file %s",
+ jrev1, file);
+ }
+ return;
+ }
+ }
+
+ /* do the join */
+
+#if 0
+ dome {
+ /* special handling when two revisions are specified */
+ if (join_rev1 && join_rev2)
+ {
+ rev = RCS_getversion (vers->srcfile, join_rev2, date_rev2, 1, 0);
+ if (rev == NULL)
+ {
+ if (!quiet && date_rev2 == NULL)
+ error (0, 0,
+ "cannot find revision %s in file %s", join_rev2, file);
+ return;
+ }
+
+ baserev = RCS_getversion (vers->srcfile, join_rev1, date_rev1, 1, 0);
+ if (baserev == NULL)
+ {
+ if (!quiet && date_rev1 == NULL)
+ error (0, 0,
+ "cannot find revision %s in file %s", join_rev1, file);
+ free (rev);
+ return;
+ }
+
+ /*
+ * nothing to do if:
+ * second revision matches our BASE revision (vn_user) &&
+ * both revisions are on the same branch
+ */
+ if (strcmp (vers->vn_user, rev) == 0 &&
+ numdots (baserev) == numdots (rev))
+ {
+ /* might be the same branch. take a real look */
+ char *dot = strrchr (baserev, '.');
+ int len = (dot - baserev) + 1;
+
+ if (strncmp (baserev, rev, len) == 0)
+ return;
+ }
+ }
+ else
+ {
+ rev = RCS_getversion (vers->srcfile, join_rev1, date_rev1, 1, 0);
+ if (rev == NULL)
+ return;
+ if (strcmp (rev, vers->vn_user) == 0) /* no merge necessary */
+ {
+ free (rev);
+ return;
+ }
+
+ baserev = RCS_whatbranch (file, join_rev1, srcfiles);
+ if (baserev)
+ {
+ char *cp;
+
+ /* we get a branch -- turn it into a revision, or NULL if trunk */
+ if ((cp = strrchr (baserev, '.')) == NULL)
+ {
+ free (baserev);
+ baserev = (char *) NULL;
+ }
+ else
+ *cp = '\0';
+ }
+ }
+ if (baserev && strcmp (baserev, rev) == 0)
+ {
+ /* they match -> nothing to do */
+ free (rev);
+ free (baserev);
+ return;
+ }
+ }
+#endif
+
+ /* OK, so we have two revisions; continue on */
+
+#ifdef SERVER_SUPPORT
+ if (server_active && !isreadable (file))
+ {
+ int retcode;
+ /* The file is up to date. Need to check out the current contents. */
+ run_setup ("%s%s -q -r%s", Rcsbin, RCS_CO, vers->vn_user);
+ run_arg (vers->srcfile->path);
+ retcode = run_exec (RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL);
+ if (retcode != 0)
+ error (1, retcode == -1 ? errno : 0,
+ "failed to check out %s file", file);
+ }
+#endif
+
+ /*
+ * The users currently modified file is moved to a backup file name
+ * ".#filename.version", so that it will stay around for a few days
+ * before being automatically removed by some cron daemon. The "version"
+ * is the version of the file that the user was most up-to-date with
+ * before the merge.
+ */
+ (void) sprintf (backup, "%s%s.%s", BAKPREFIX, file, vers->vn_user);
+ if (update_dir[0])
+ (void) sprintf (user, "%s/%s", update_dir, file);
+ else
+ (void) strcpy (user, file);
+
+ (void) unlink_file (backup);
+ copy_file (file, backup);
+ xchmod (file, 1);
+
+ options = vers->options;
+#ifdef HAVE_RCS5
+#if 0
+ if (*options == '\0')
+ options = "-kk"; /* to ignore keyword expansions */
+#endif
+#endif
+
+ status = RCS_merge (vers->srcfile->path, options, rev1, rev2);
+ if (status != 0 && status != 1)
+ {
+ error (0, status == -1 ? errno : 0,
+ "could not merge revision %s of %s", rev2, user);
+ error (status == -1 ? 1 : 0, 0, "restoring %s from backup file %s",
+ user, backup);
+ rename_file (backup, file);
+ }
+ free (rev1);
+ free (rev2);
+
+#ifdef SERVER_SUPPORT
+ /*
+ * If we're in server mode, then we need to re-register the file
+ * even if there were no conflicts (status == 0).
+ * This tells server_updated() to send the modified file back to
+ * the client.
+ */
+ if (status == 1 || (status == 0 && server_active))
+#else
+ if (status == 1)
+#endif
+ {
+ char *cp = 0;
+
+ if (status)
+ cp = time_stamp (file);
+ Register (entries, file, vers->vn_rcs, vers->ts_rcs, vers->options,
+ vers->tag, vers->date, cp);
+ if (cp)
+ free(cp);
+ }
+
+#ifdef SERVER_SUPPORT
+ if (server_active)
+ {
+ server_copy_file (file, update_dir, repository, backup);
+ server_updated (file, update_dir, repository, SERVER_MERGED,
+ (struct stat *) NULL, (unsigned char *) NULL);
+ }
+#endif
+}
+
+/*
+ * Process the current directory, looking for files not in ILIST and not on
+ * the global ignore list for this directory.
+ */
+static void
+ignore_files (ilist, update_dir)
+ List *ilist;
+ char *update_dir;
+{
+ DIR *dirp;
+ struct dirent *dp;
+ struct stat sb;
+ char *file;
+ char *xdir;
+
+ /* we get called with update_dir set to "." sometimes... strip it */
+ if (strcmp (update_dir, ".") == 0)
+ xdir = "";
+ else
+ xdir = update_dir;
+
+ dirp = opendir (".");
+ if (dirp == NULL)
+ return;
+
+ ign_add_file (CVSDOTIGNORE, 1);
+ wrap_add_file (CVSDOTWRAPPER, 1);
+
+ while ((dp = readdir (dirp)) != NULL)
+ {
+ file = dp->d_name;
+ if (strcmp (file, ".") == 0 || strcmp (file, "..") == 0)
+ continue;
+ if (findnode (ilist, file) != NULL)
+ continue;
+
+ if (
+#ifdef DT_DIR
+ dp->d_type != DT_UNKNOWN ||
+#endif
+ lstat(file, &sb) != -1)
+ {
+
+ if (
+#ifdef DT_DIR
+ dp->d_type == DT_DIR || dp->d_type == DT_UNKNOWN &&
+#endif
+ S_ISDIR(sb.st_mode))
+ {
+ char temp[PATH_MAX];
+
+ (void) sprintf (temp, "%s/%s", file, CVSADM);
+ if (isdir (temp))
+ continue;
+ }
+#ifdef S_ISLNK
+ else if (
+#ifdef DT_DIR
+ dp->d_type == DT_LNK || dp->d_type == DT_UNKNOWN &&
+#endif
+ S_ISLNK(sb.st_mode))
+ {
+ continue;
+ }
+#endif
+ }
+
+ if (ign_name (file))
+ continue;
+ (void) write_letter (file, '?', xdir);
+ }
+ (void) closedir (dirp);
+}
+
+int
+joining ()
+{
+ return (join_rev1 != NULL);
+}
diff --git a/gnu/usr.bin/cvs/cvs/update.h b/gnu/usr.bin/cvs/cvs/update.h
new file mode 100644
index 0000000..68c91d5
--- /dev/null
+++ b/gnu/usr.bin/cvs/cvs/update.h
@@ -0,0 +1,9 @@
+/* Definitions of routines shared between local and client/server
+ "update" code. */
+
+/* List of files that we have either processed or are willing to
+ ignore. Any file not on this list gets a question mark printed. */
+extern List *ignlist;
+
+extern int
+update_filesdone_proc PROTO((int err, char *repository, char *update_dir));
diff --git a/gnu/usr.bin/cvs/cvs/vers_ts.c b/gnu/usr.bin/cvs/cvs/vers_ts.c
new file mode 100644
index 0000000..ebb7ca8
--- /dev/null
+++ b/gnu/usr.bin/cvs/cvs/vers_ts.c
@@ -0,0 +1,326 @@
+/*
+ * Copyright (c) 1992, Brian Berliner and Jeff Polk
+ * Copyright (c) 1989-1992, Brian Berliner
+ *
+ * You may distribute under the terms of the GNU General Public License as
+ * specified in the README file that comes with the CVS 1.4 kit.
+ */
+
+#include "cvs.h"
+
+#ifndef lint
+static const char rcsid[] = "$CVSid: @(#)vers_ts.c 1.45 94/10/07 $";
+USE(rcsid);
+#endif
+
+#ifdef SERVER_SUPPORT
+static void time_stamp_server PROTO((char *, Vers_TS *));
+#endif
+
+/*
+ * Fill in and return a Vers_TS structure "user" is the name of the local
+ * file; entries is the entries file - preparsed for our pleasure. xfiles is
+ * all source code control files, preparsed for our pleasure
+ */
+Vers_TS *
+Version_TS (repository, options, tag, date, user, force_tag_match,
+ set_time, entries, xfiles)
+ char *repository;
+ char *options;
+ char *tag;
+ char *date;
+ char *user;
+ int force_tag_match;
+ int set_time;
+ List *entries;
+ List *xfiles;
+{
+ Node *p;
+ RCSNode *rcsdata;
+ Vers_TS *vers_ts;
+ struct stickydirtag *sdtp;
+
+ /* get a new Vers_TS struct */
+ vers_ts = (Vers_TS *) xmalloc (sizeof (Vers_TS));
+ memset ((char *) vers_ts, 0, sizeof (*vers_ts));
+
+ /*
+ * look up the entries file entry and fill in the version and timestamp
+ * if entries is NULL, there is no entries file so don't bother trying to
+ * look it up (used by checkout -P)
+ */
+ if (entries == NULL)
+ {
+ sdtp = NULL;
+ p = NULL;
+ }
+ else
+ {
+ p = findnode (entries, user);
+ sdtp = (struct stickydirtag *) entries->list->data; /* list-private */
+ }
+
+ if (p != NULL)
+ {
+ Entnode *entdata = (Entnode *) p->data;
+
+ vers_ts->vn_user = xstrdup (entdata->version);
+ vers_ts->ts_rcs = xstrdup (entdata->timestamp);
+ vers_ts->ts_conflict = xstrdup (entdata->conflict);
+ if (!tag)
+ {
+ if (!(sdtp && sdtp->aflag))
+ vers_ts->tag = xstrdup (entdata->tag);
+ }
+ if (!date)
+ {
+ if (!(sdtp && sdtp->aflag))
+ vers_ts->date = xstrdup (entdata->date);
+ }
+ if (!options || (options && *options == '\0'))
+ {
+ if (!(sdtp && sdtp->aflag))
+ vers_ts->options = xstrdup (entdata->options);
+ }
+ vers_ts->entdata = entdata;
+ }
+
+ /*
+ * -k options specified on the command line override (and overwrite)
+ * options stored in the entries file
+ */
+ if (options)
+ vers_ts->options = xstrdup (options);
+ else if (sdtp && sdtp->aflag == 0)
+ {
+ if (!vers_ts->options)
+ vers_ts->options = xstrdup (sdtp->options);
+ }
+ if (!vers_ts->options)
+ vers_ts->options = xstrdup ("");
+
+ /*
+ * if tags were specified on the command line, they override what is in
+ * the Entries file
+ */
+ if (tag || date)
+ {
+ vers_ts->tag = xstrdup (tag);
+ vers_ts->date = xstrdup (date);
+ }
+ else if (!vers_ts->entdata && (sdtp && sdtp->aflag == 0))
+ {
+ if (!vers_ts->tag)
+ vers_ts->tag = xstrdup (sdtp->tag);
+ if (!vers_ts->date)
+ vers_ts->date = xstrdup (sdtp->date);
+ }
+
+ /* Now look up the info on the source controlled file */
+ if (xfiles != (List *) NULL)
+ {
+ p = findnode (xfiles, user);
+ if (p != NULL)
+ {
+ rcsdata = (RCSNode *) p->data;
+ rcsdata->refcount++;
+ }
+ else
+ rcsdata = NULL;
+ }
+ else if (repository != NULL)
+ rcsdata = RCS_parse (user, repository);
+ else
+ rcsdata = NULL;
+
+ if (rcsdata != NULL)
+ {
+ /* squirrel away the rcsdata pointer for others */
+ vers_ts->srcfile = rcsdata;
+
+#ifndef DEATH_SUPPORT
+ /* (is this indeed death support? I haven't looked carefully). */
+ /* get RCS version number into vn_rcs (if appropriate) */
+ if (((vers_ts->tag || vers_ts->date) && force_tag_match) ||
+ ((rcsdata->flags & VALID) && (rcsdata->flags & INATTIC) == 0))
+ {
+#endif
+ if (vers_ts->tag && strcmp (vers_ts->tag, TAG_BASE) == 0)
+ {
+ vers_ts->vn_rcs = xstrdup (vers_ts->vn_user);
+ vers_ts->vn_tag = xstrdup (vers_ts->vn_user);
+ }
+ else
+ {
+ vers_ts->vn_rcs = RCS_getversion (rcsdata, vers_ts->tag,
+ vers_ts->date, force_tag_match, 1);
+ if (vers_ts->vn_rcs == NULL)
+ vers_ts->vn_tag = NULL;
+ else
+ {
+ char *colon = strchr (vers_ts->vn_rcs, ':');
+ if (colon)
+ {
+ vers_ts->vn_tag = xstrdup (colon+1);
+ *colon = '\0';
+ }
+ else
+ vers_ts->vn_tag = xstrdup (vers_ts->vn_rcs);
+ }
+ }
+#ifndef DEATH_SUPPORT
+ }
+#endif
+
+ /*
+ * If the source control file exists and has the requested revision,
+ * get the Date the revision was checked in. If "user" exists, set
+ * its mtime.
+ */
+ if (set_time)
+ {
+ struct utimbuf t;
+
+ memset ((char *) &t, 0, sizeof (t));
+ if (vers_ts->vn_rcs &&
+ (t.actime = t.modtime = RCS_getrevtime (rcsdata,
+ vers_ts->vn_rcs, (char *) 0, 0)) != -1)
+ (void) utime (user, &t);
+ }
+ }
+
+ /* get user file time-stamp in ts_user */
+ if (entries != (List *) NULL)
+ {
+#ifdef SERVER_SUPPORT
+ if (server_active)
+ time_stamp_server (user, vers_ts);
+ else
+#endif
+ vers_ts->ts_user = time_stamp (user);
+ }
+
+ return (vers_ts);
+}
+
+#ifdef SERVER_SUPPORT
+
+/* Set VERS_TS->TS_USER to time stamp for FILE. */
+
+/* Separate these out to keep the logic below clearer. */
+#define mark_lost(V) ((V)->ts_user = 0)
+#define mark_unchanged(V) ((V)->ts_user = xstrdup ((V)->ts_rcs))
+
+static void
+time_stamp_server (file, vers_ts)
+ char *file;
+ Vers_TS *vers_ts;
+{
+ struct stat sb;
+ char *cp;
+
+ if (stat (file, &sb) < 0)
+ {
+ if (! existence_error (errno))
+ error (1, errno, "cannot stat temp file");
+ if (use_unchanged)
+ {
+ /* Missing file means lost or unmodified; check entries
+ file to see which.
+
+ XXX FIXME - If there's no entries file line, we
+ wouldn't be getting the file at all, so consider it
+ lost. I don't know that that's right, but it's not
+ clear to me that either choice is. Besides, would we
+ have an RCS string in that case anyways? */
+ if (vers_ts->entdata == NULL)
+ mark_lost (vers_ts);
+ else if (vers_ts->entdata->timestamp
+ && vers_ts->entdata->timestamp[0] == '=')
+ mark_unchanged (vers_ts);
+ else
+ mark_lost (vers_ts);
+ }
+ else
+ {
+ /* Missing file in the temp directory means that the file
+ was not modified. */
+ mark_unchanged (vers_ts);
+ }
+ }
+ else if (sb.st_mtime == 0)
+ {
+ if (use_unchanged)
+ /* We shouldn't reach this case any more! */
+ abort ();
+
+ /* Special code used by server.c to indicate the file was lost. */
+ mark_lost (vers_ts);
+ }
+ else
+ {
+ vers_ts->ts_user = xmalloc (25);
+ cp = asctime (gmtime (&sb.st_mtime)); /* copy in the modify time */
+ cp[24] = 0;
+ (void) strcpy (vers_ts->ts_user, cp);
+ }
+}
+
+#endif /* SERVER_SUPPORT */
+/*
+ * Gets the time-stamp for the file "file" and returns it in space it
+ * allocates
+ */
+char *
+time_stamp (file)
+ char *file;
+{
+ struct stat sb;
+ char *cp;
+ char *ts;
+
+ if (stat (file, &sb) < 0)
+ {
+ ts = NULL;
+ }
+ else
+ {
+ ts = xmalloc (25);
+ cp = asctime (gmtime (&sb.st_mtime)); /* copy in the modify time */
+ cp[24] = 0;
+ (void) strcpy (ts, cp);
+ }
+
+ return (ts);
+}
+
+/*
+ * free up a Vers_TS struct
+ */
+void
+freevers_ts (versp)
+ Vers_TS **versp;
+{
+ if ((*versp)->srcfile)
+ freercsnode (&((*versp)->srcfile));
+ if ((*versp)->vn_user)
+ free ((*versp)->vn_user);
+ if ((*versp)->vn_rcs)
+ free ((*versp)->vn_rcs);
+ if ((*versp)->vn_tag)
+ free ((*versp)->vn_tag);
+ if ((*versp)->ts_user)
+ free ((*versp)->ts_user);
+ if ((*versp)->ts_rcs)
+ free ((*versp)->ts_rcs);
+ if ((*versp)->options)
+ free ((*versp)->options);
+ if ((*versp)->tag)
+ free ((*versp)->tag);
+ if ((*versp)->date)
+ free ((*versp)->date);
+ if ((*versp)->ts_conflict)
+ free ((*versp)->ts_conflict);
+ free ((char *) *versp);
+ *versp = (Vers_TS *) NULL;
+}
diff --git a/gnu/usr.bin/cvs/cvs/wrapper.c b/gnu/usr.bin/cvs/cvs/wrapper.c
new file mode 100644
index 0000000..ec5f43e
--- /dev/null
+++ b/gnu/usr.bin/cvs/cvs/wrapper.c
@@ -0,0 +1,371 @@
+#include "cvs.h"
+
+/*
+ Original Author: athan@morgan.com <Andrew C. Athan> 2/1/94
+ Modified By: vdemarco@bou.shl.com
+
+ This package was written to support the NEXTSTEP concept of
+ "wrappers." These are essentially directories that are to be
+ treated as "files." This package allows such wrappers to be
+ "processed" on the way in and out of CVS. The intended use is to
+ wrap up a wrapper into a single tar, such that that tar can be
+ treated as a single binary file in CVS. To solve the problem
+ effectively, it was also necessary to be able to prevent rcsmerge
+ application at appropriate times.
+
+ ------------------
+ Format of wrapper file ($CVSROOT/CVSROOT/cvswrappers or .cvswrappers)
+
+ wildcard [option value][option value]...
+
+ where option is one of
+ -f from cvs filter value: path to filter
+ -t to cvs filter value: path to filter
+ -m update methodology value: MERGE or COPY
+
+ and value is a single-quote delimited value.
+
+ E.g:
+ *.nib -f 'gunzipuntar' -t 'targzip' -m 'COPY'
+*/
+
+
+typedef struct {
+ char *wildCard;
+ char *tocvsFilter;
+ char *fromcvsFilter;
+ char *conflictHook;
+ WrapMergeMethod mergeMethod;
+} WrapperEntry;
+
+static WrapperEntry **wrap_list=NULL;
+static WrapperEntry **wrap_saved_list=NULL;
+
+static int wrap_size=0;
+static int wrap_count=0;
+static int wrap_tempcount=0;
+static int wrap_saved_count=0;
+static int wrap_saved_tempcount=0;
+
+#define WRAPPER_GROW 8
+
+void wrap_add_entry PROTO((WrapperEntry *e,int temp));
+void wrap_kill PROTO((void));
+void wrap_kill_temp PROTO((void));
+void wrap_free_entry PROTO((WrapperEntry *e));
+void wrap_free_entry_internal PROTO((WrapperEntry *e));
+void wrap_restore_saved PROTO((void));
+
+void wrap_setup()
+{
+ char file[PATH_MAX];
+ struct passwd *pw;
+
+ /* Then add entries found in repository, if it exists */
+ (void) sprintf (file, "%s/%s/%s", CVSroot, CVSROOTADM, CVSROOTADM_WRAPPER);
+ if (isfile (file)){
+ wrap_add_file(file,0);
+ }
+
+ /* Then add entries found in home dir, (if user has one) and file exists */
+ if ((pw = (struct passwd *) getpwuid (getuid ())) && pw->pw_dir){
+ (void) sprintf (file, "%s/%s", pw->pw_dir, CVSDOTWRAPPER);
+ if (isfile (file)){
+ wrap_add_file (file, 0);
+ }
+ }
+
+ /* Then add entries found in CVSWRAPPERS environment variable. */
+ wrap_add (getenv (WRAPPER_ENV), 0);
+}
+
+/*
+ * Open a file and read lines, feeding each line to a line parser. Arrange
+ * for keeping a temporary list of wrappers at the end, if the "temp"
+ * argument is set.
+ */
+void
+wrap_add_file (file, temp)
+ const char *file;
+ int temp;
+{
+ FILE *fp;
+ char line[1024];
+
+ wrap_restore_saved();
+ wrap_kill_temp();
+
+ /* load the file */
+ if (!(fp = fopen (file, "r")))
+ return;
+ while (fgets (line, sizeof (line), fp))
+ wrap_add (line, temp);
+ (void) fclose (fp);
+}
+
+void
+wrap_kill()
+{
+ wrap_kill_temp();
+ while(wrap_count)
+ wrap_free_entry(wrap_list[--wrap_count]);
+}
+
+void
+wrap_kill_temp()
+{
+ WrapperEntry **temps=wrap_list+wrap_count;
+
+ while(wrap_tempcount)
+ wrap_free_entry(temps[--wrap_tempcount]);
+}
+
+void
+wrap_free_entry(e)
+ WrapperEntry *e;
+{
+ wrap_free_entry_internal(e);
+ free(e);
+}
+
+void
+wrap_free_entry_internal(e)
+ WrapperEntry *e;
+{
+ free(e->wildCard);
+ if(e->tocvsFilter)
+ free(e->tocvsFilter);
+ if(e->fromcvsFilter)
+ free(e->fromcvsFilter);
+ if(e->conflictHook)
+ free(e->conflictHook);
+}
+
+void
+wrap_restore_saved()
+{
+ if(!wrap_saved_list)
+ return;
+
+ wrap_kill();
+
+ free(wrap_list);
+
+ wrap_list=wrap_saved_list;
+ wrap_count=wrap_saved_count;
+ wrap_tempcount=wrap_saved_tempcount;
+
+ wrap_saved_list=NULL;
+ wrap_saved_count=0;
+ wrap_saved_tempcount=0;
+}
+
+void
+wrap_add (line, isTemp)
+ char *line;
+ int isTemp;
+{
+ char *temp;
+ char ctemp;
+ WrapperEntry e;
+ char opt;
+
+ if (!line || line[0] == '#')
+ return;
+
+ memset (&e, 0, sizeof(e));
+
+ /* Search for the wild card */
+ while(*line && isspace(*line))
+ ++line;
+ for(temp=line;*line && !isspace(*line);++line)
+ ;
+ if(temp==line)
+ return;
+
+ ctemp=*line;
+ *line='\0';
+
+ e.wildCard=xstrdup(temp);
+ *line=ctemp;
+
+ while(*line){
+ /* Search for the option */
+ while(*line && *line!='-')
+ ++line;
+ if(!*line)
+ break;
+ ++line;
+ if(!*line)
+ break;
+ opt=*line;
+
+ /* Search for the filter commandline */
+ for(++line;*line && *line!='\'';++line);
+ if(!*line)
+ break;
+
+ for(temp=++line;*line && (*line!='\'' || line[-1]=='\\');++line)
+ ;
+
+ if(line==temp+1)
+ break;
+
+ ctemp=*line;
+ *line='\0';
+ switch(opt){
+ case 'f':
+ if(e.fromcvsFilter)
+ free(e.fromcvsFilter);
+ e.fromcvsFilter=expand_path (temp);
+ if (!e.fromcvsFilter)
+ error (1, 0,
+ "Invalid environmental variable string '%s'",temp);
+ break;
+ case 't':
+ if(e.tocvsFilter)
+ free(e.tocvsFilter);
+ e.tocvsFilter=expand_path (temp);
+ if (!e.tocvsFilter)
+ error (1, 0,
+ "Invalid environmental variable string '%s'",temp);
+ break;
+ case 'c':
+ if(e.conflictHook)
+ free(e.conflictHook);
+ e.conflictHook=expand_path (temp);
+ if (!e.conflictHook)
+ error (1, 0,
+ "Invalid environmental variable string '%s'",temp);
+ break;
+ case 'm':
+ if(*temp=='C' || *temp=='c')
+ e.mergeMethod=WRAP_COPY;
+ else
+ e.mergeMethod=WRAP_MERGE;
+ break;
+ default:
+ break;
+ }
+ *line=ctemp;
+ if(!*line)break;
+ ++line;
+ }
+
+ wrap_add_entry(&e, isTemp);
+}
+
+void
+wrap_add_entry(e, temp)
+ WrapperEntry *e;
+ int temp;
+{
+ int x;
+ if(wrap_count+wrap_tempcount>=wrap_size){
+ wrap_size += WRAPPER_GROW;
+ wrap_list = (WrapperEntry **) xrealloc ((char *) wrap_list,
+ wrap_size *
+ sizeof (WrapperEntry *));
+ }
+
+ if(!temp && wrap_tempcount){
+ for(x=wrap_count+wrap_tempcount-1;x>=wrap_count;--x)
+ wrap_list[x+1]=wrap_list[x];
+ }
+
+ x=(temp ? wrap_count+(wrap_tempcount++):(wrap_count++));
+ wrap_list[x]=(WrapperEntry *)xmalloc(sizeof(WrapperEntry));
+ wrap_list[x]->wildCard=e->wildCard;
+ wrap_list[x]->fromcvsFilter=e->fromcvsFilter;
+ wrap_list[x]->tocvsFilter=e->tocvsFilter;
+ wrap_list[x]->conflictHook=e->conflictHook;
+ wrap_list[x]->mergeMethod=e->mergeMethod;
+}
+
+/* Return 1 if the given filename is a wrapper filename */
+int
+wrap_name_has (name,has)
+ const char *name;
+ WrapMergeHas has;
+{
+ int x,count=wrap_count+wrap_saved_count;
+ char *temp;
+
+ for(x=0;x<count;++x)
+ if (fnmatch (wrap_list[x]->wildCard, name, 0) == 0){
+ switch(has){
+ case WRAP_TOCVS:
+ temp=wrap_list[x]->tocvsFilter;
+ break;
+ case WRAP_FROMCVS:
+ temp=wrap_list[x]->fromcvsFilter;
+ break;
+ case WRAP_CONFLICT:
+ temp=wrap_list[x]->conflictHook;
+ break;
+ default:
+ abort ();
+ }
+ if(temp==NULL)
+ return (0);
+ else
+ return (1);
+ }
+ return (0);
+}
+
+WrapperEntry *
+wrap_matching_entry (name)
+ const char *name;
+{
+ int x,count=wrap_count+wrap_saved_count;
+
+ for(x=0;x<count;++x)
+ if (fnmatch (wrap_list[x]->wildCard, name, 0) == 0)
+ return wrap_list[x];
+ return (WrapperEntry *)NULL;
+}
+
+char *
+wrap_tocvs_process_file(fileName)
+ const char *fileName;
+{
+ WrapperEntry *e=wrap_matching_entry(fileName);
+ static char buf[L_tmpnam+1];
+
+ if(e==NULL || e->tocvsFilter==NULL)
+ return NULL;
+
+ tmpnam(buf);
+
+ run_setup(e->tocvsFilter,fileName,buf);
+ run_exec(RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL|RUN_REALLY );
+
+ return buf;
+}
+
+int
+wrap_merge_is_copy (fileName)
+ const char *fileName;
+{
+ WrapperEntry *e=wrap_matching_entry(fileName);
+ if(e==NULL || e->mergeMethod==WRAP_MERGE)
+ return 0;
+
+ return 1;
+}
+
+char *
+wrap_fromcvs_process_file(fileName)
+ const char *fileName;
+{
+ WrapperEntry *e=wrap_matching_entry(fileName);
+ static char buf[PATH_MAX];
+
+ if(e==NULL || e->fromcvsFilter==NULL)
+ return NULL;
+
+ run_setup(e->fromcvsFilter,fileName);
+ run_exec(RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL );
+ return buf;
+}
diff --git a/gnu/usr.bin/cvs/cvsbug/Makefile b/gnu/usr.bin/cvs/cvsbug/Makefile
new file mode 100644
index 0000000..336fd13
--- /dev/null
+++ b/gnu/usr.bin/cvs/cvsbug/Makefile
@@ -0,0 +1,25 @@
+# $Id: Makefile,v 1.2 1995/12/11 01:58:51 peter Exp $
+
+MAN8= cvsbug.8
+
+CLEANFILES+= cvsbug ver
+
+.SUFFIXES: .sh
+
+all: cvsbug
+
+.sh:
+ echo > ver cvs-`sed < ${.CURDIR}/../lib/version.c \
+ -e '/version_string/!d' \
+ -e 's/[^0-9.]*\([0-9.]*\).*/\1/' \
+ -e q`
+ sed -e "s,xVERSIONx,`cat ver`,g" ${.CURDIR}/$@.sh > $@
+
+
+beforeinstall:
+ ${INSTALL} -c -o ${BINOWN} -g ${BINGRP} -m ${BINMODE} \
+ cvsbug ${DESTDIR}${BINDIR}/cvsbug
+
+.include "../../Makefile.inc"
+.include <bsd.prog.mk>
+
diff --git a/gnu/usr.bin/cvs/cvsbug/cvsbug.8 b/gnu/usr.bin/cvs/cvsbug/cvsbug.8
new file mode 100644
index 0000000..496ef14
--- /dev/null
+++ b/gnu/usr.bin/cvs/cvsbug/cvsbug.8
@@ -0,0 +1,269 @@
+.\" -*- nroff -*-
+.\" ---------------------------------------------------------------------------
+.\" man page for send-pr (by Heinz G. Seidl, hgs@cygnus.com)
+.\" updated Feb 1993 for GNATS 3.00 by Jeffrey Osier, jeffrey@cygnus.com
+.\"
+.\" This file is part of the Problem Report Management System (GNATS)
+.\" Copyright 1992 Cygnus Support
+.\"
+.\" This program is free software; you can redistribute it and/or
+.\" modify it under the terms of the GNU General Public
+.\" License as published by the Free Software Foundation; either
+.\" version 2 of the License, or (at your option) any later version.
+.\"
+.\" This program is distributed in the hope that it will be useful,
+.\" but WITHOUT ANY WARRANTY; without even the implied warranty of
+.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+.\" General Public License for more details.
+.\"
+.\" You should have received a copy of the GNU Library General Public
+.\" License along with this program; if not, write to the Free
+.\" Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA
+.\"
+.\" ---------------------------------------------------------------------------
+.nh
+.TH CVSBUG 1 xVERSIONx "February 1993"
+.SH NAME
+cvsbug \- send problem report (PR) about CVS to a central support site
+.SH SYNOPSIS
+.B cvsbug
+[
+.I site
+]
+[
+.B \-f
+.I problem-report
+]
+[
+.B \-t
+.I mail-address
+]
+.br
+.in +0.8i
+[
+.B \-P
+]
+[
+.B \-L
+]
+[
+.B \-\-request-id
+]
+[
+.B \-v
+]
+.SH DESCRIPTION
+.B cvsbug
+is a tool used to submit
+.I problem reports
+.\" SITE ADMINISTRATORS - change this if you use a local default
+(PRs) to a central support site. In most cases the correct
+.I site
+will be the default. This argument indicates the support site which
+is responsible for the category of problem involved. Some sites may
+use a local address as a default.
+.I site
+values are defined by using the
+.BR aliases (5).
+.LP
+.B cvsbug
+invokes an editor on a problem report template (after trying to fill
+in some fields with reasonable default values). When you exit the
+editor,
+.B cvsbug
+sends the completed form to the
+.I Problem Report Management System
+(\fBGNATS\fR) at a central support site. At the support site, the PR
+is assigned a unique number and is stored in the \fBGNATS\fR database
+according to its category and submitter-id. \fBGNATS\fR automatically
+replies with an acknowledgement, citing the category and the PR
+number.
+.LP
+To ensure that a PR is handled promptly, it should contain your (unique)
+\fIsubmitter-id\fR and one of the available \fIcategories\fR to identify the
+problem area. (Use
+.B `cvsbug -L'
+to see a list of categories.)
+.LP
+The
+.B cvsbug
+template at your site should already be customized with your
+submitter-id (running `\|\fBinstall-sid\fP \fIsubmitter-id\fP\|' to
+accomplish this is part of the installation procedures for
+.BR cvsbug ).
+If this hasn't been done, see your system administrator for your
+submitter-id, or request one from your support site by invoking
+.B `cvsbug \-\-request\-id'.
+If your site does not distinguish between different user sites, or if
+you are not affiliated with the support site, use
+.B `net'
+for this field.
+.LP
+The more precise your problem description and the more complete your
+information, the faster your support team can solve your problems.
+.SH OPTIONS
+.TP
+.BI \-f " problem-report"
+specify a file (\fIproblem-report\fR) which already contains a
+complete problem report.
+.B cvsbug
+sends the contents of the file without invoking the editor. If
+the value for
+.I problem-report
+is
+.BR `\|\-\|' ,
+then
+.B cvsbug
+reads from standard input.
+.TP
+.BI \-t " mail-address"
+Change mail address at the support site for problem reports. The
+default
+.I mail-address
+is the address used for the default
+.IR site .
+Use the
+.I site
+argument rather than this option in nearly all cases.
+.TP
+.B \-P
+print the form specified by the environment variable
+.B PR_FORM
+on standard output. If
+.B PR_FORM
+is not set, print the standard blank PR template. No mail is sent.
+.TP
+.B -L
+print the list of available categories. No mail is sent.
+.TP
+.B \-\-request\-id
+sends mail to the default support site, or
+.I site
+if specified, with a request for your
+.IR submitter-id .
+If you are
+not affiliated with
+.IR site ,
+use a
+.I submitter-id
+of
+.BR net \|'.
+.TP
+.B \-v
+Display the
+.B cvsbug
+version number.
+.LP
+Note: use
+.B cvsbug
+to submit problem reports rather than mailing them directly. Using
+both the template and
+.B cvsbug
+itself will help ensure all necessary information will reach the
+support site.
+.SH ENVIRONMENT
+The environment variable
+.B EDITOR
+specifies the editor to invoke on the template.
+.br
+default:
+.B vi
+.sp
+If the environment variable
+.B PR_FORM
+is set, then its value is used as the file name of the template for
+your problem-report editing session. You can use this to start with a
+partially completed form (for example, a form with the identification
+fields already completed).
+.SH "HOW TO FILL OUT A PROBLEM REPORT"
+Problem reports have to be in a particular form so that a program can
+easily manage them. Please remember the following guidelines:
+.IP \(bu 3m
+describe only
+.B one problem
+with each problem report.
+.IP \(bu 3m
+For follow-up mail, use the same subject line as the one in the automatic
+acknowledgent. It consists of category, PR number and the original synopsis
+line. This allows the support site to relate several mail messages to a
+particular PR and to record them automatically.
+.IP \(bu 3m
+Please try to be as accurate as possible in the subject and/or synopsis line.
+.IP \(bu 3m
+The subject and the synopsis line are not confidential. This is
+because open-bugs lists are compiled from them. Avoid confidential
+information there.
+.LP
+See the GNU
+.B Info
+file
+.B cvsbug.info
+or the document \fIReporting Problems With cvsbug\fR\ for detailed
+information on reporting problems
+.SH "HOW TO SUBMIT TEST CASES, CODE, ETC."
+Submit small code samples with the PR. Contact the support site for
+instructions on submitting larger test cases and problematic source
+code.
+.SH FILES
+.ta \w'/tmp/pbad$$ 'u
+/tmp/p$$ copy of PR used in editing session
+.br
+/tmp/pf$$ copy of empty PR form, for testing purposes
+.br
+/tmp/pbad$$ file for rejected PRs
+.SH EMACS USER INTERFACE
+An Emacs user interface for
+.B cvsbug
+with completion of field values is part of the
+.B cvsbug
+distribution (invoked with
+.BR "M-x cvsbug" ).
+See the file
+.B cvsbug.info
+or the ASCII file
+.B INSTALL
+in the top level directory of the distribution for configuration and
+installation information. The Emacs LISP template file is
+.B cvsbug-el.in
+and is installed as
+.BR cvsbug.el .
+.SH INSTALLATION AND CONFIGURATION
+See
+.B cvsbug.info
+or
+.B INSTALL
+for installation instructions.
+.SH SEE ALSO
+.I Reporting Problems Using cvsbug
+(also installed as the GNU Info file
+.BR cvsbug.info ).
+.LP
+.BR gnats (l),
+.BR query-pr (1),
+.BR edit-pr (1),
+.BR gnats (8),
+.BR queue-pr (8),
+.BR at-pr (8),
+.BR mkcat (8),
+.BR mkdist (8).
+.SH AUTHORS
+Jeffrey Osier, Brendan Kehoe, Jason Merrill, Heinz G. Seidl (Cygnus
+Support)
+.SH COPYING
+Copyright (c) 1992, 1993 Free Software Foundation, Inc.
+.PP
+Permission is granted to make and distribute verbatim copies of
+this manual provided the copyright notice and this permission notice
+are preserved on all copies.
+.PP
+Permission is granted to copy and distribute modified versions of this
+manual under the conditions for verbatim copying, provided that the
+entire resulting derived work is distributed under the terms of a
+permission notice identical to this one.
+.PP
+Permission is granted to copy and distribute translations of this
+manual into another language, under the above conditions for modified
+versions, except that this permission notice may be included in
+translations approved by the Free Software Foundation instead of in
+the original English.
+
diff --git a/gnu/usr.bin/cvs/cvsbug/cvsbug.sh b/gnu/usr.bin/cvs/cvsbug/cvsbug.sh
new file mode 100644
index 0000000..ab26cfc
--- /dev/null
+++ b/gnu/usr.bin/cvs/cvsbug/cvsbug.sh
@@ -0,0 +1,528 @@
+#! /bin/sh
+# Submit a problem report to a GNATS site.
+# Copyright (C) 1993 Free Software Foundation, Inc.
+# Contributed by Brendan Kehoe (brendan@cygnus.com), based on a
+# version written by Heinz G. Seidl (hgs@ide.com).
+#
+# This file is part of GNU GNATS.
+# Modified by Berliner for CVS.
+#
+#ident "@(#)cvs/src:$Name: $:$Id: cvsbug.sh,v 1.10 1995/11/15 00:18:00 woods Exp $"
+#
+# GNU GNATS is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# GNU GNATS is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GNU GNATS; see the file COPYING. If not, write to
+# the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+# The version of this send-pr.
+VERSION=3.2
+
+# The submitter-id for your site.
+SUBMITTER=net
+
+## # Where the GNATS directory lives, if at all.
+## [ -z "$GNATS_ROOT" ] &&
+## GNATS_ROOT=/usr/local/lib/gnats/gnats-db
+
+# The default mail address for PR submissions.
+GNATS_ADDR=bug-cvs@prep.ai.mit.edu
+
+## # Where the gnats category tree lives.
+## DATADIR=/usr/local/lib
+
+## # If we've been moved around, try using GCC_EXEC_PREFIX.
+## [ ! -d $DATADIR/gnats -a -d "$GCC_EXEC_PREFIX" ] && DATADIR=${GCC_EXEC_PREFIX}..
+
+# The default release for this host.
+DEFAULT_RELEASE="xVERSIONx"
+
+# The default organization.
+DEFAULT_ORGANIZATION="net"
+
+## # The default site to look for.
+## GNATS_SITE=unknown
+
+## # Newer config information?
+## [ -f ${GNATS_ROOT}/gnats-adm/config ] && . ${GNATS_ROOT}/gnats-adm/config
+
+# What mailer to use. This must come after the config file, since it is
+# host-dependent.
+if [ -f /usr/sbin/sendmail ]; then
+ MAIL_AGENT="/usr/sbin/sendmail -oi -t"
+else
+ MAIL_AGENT="/usr/lib/sendmail -oi -t"
+fi
+MAILER=`echo $MAIL_AGENT | sed -e 's, .*,,'`
+if [ ! -f "$MAILER" ] ; then
+ echo "$COMMAND: Cannot file mail program \"$MAILER\"."
+ echo "$COMMAND: Please fix the MAIL_AGENT entry in the $COMMAND file."
+ exit 1
+fi
+
+if test "`echo -n foo`" = foo ; then
+ ECHON=bsd
+elif test "`echo 'foo\c'`" = foo ; then
+ ECHON=sysv
+else
+ ECHON=none
+fi
+
+if [ $ECHON = bsd ] ; then
+ ECHON1="echo -n"
+ ECHON2=
+elif [ $ECHON = sysv ] ; then
+ ECHON1=echo
+ ECHON2='\c'
+else
+ ECHON1=echo
+ ECHON2=
+fi
+
+#
+
+[ -z "$TMPDIR" ] && TMPDIR=/tmp
+
+TEMP=$TMPDIR/p$$
+BAD=$TMPDIR/pbad$$
+REF=$TMPDIR/pf$$
+
+if [ -z "$LOGNAME" -a -n "$USER" ]; then
+ LOGNAME=$USER
+fi
+
+FROM="$LOGNAME"
+REPLY_TO="$LOGNAME"
+
+# Find out the name of the originator of this PR.
+if [ -n "$NAME" ]; then
+ ORIGINATOR="$NAME"
+elif [ -f $HOME/.fullname ]; then
+ ORIGINATOR="`sed -e '1q' $HOME/.fullname`"
+elif [ -f /bin/domainname ]; then
+ if [ "`/bin/domainname`" != "" -a -f /usr/bin/ypcat ]; then
+ # Must use temp file due to incompatibilities in quoting behavior
+ # and to protect shell metacharacters in the expansion of $LOGNAME
+ /usr/bin/ypcat passwd 2>/dev/null | cat - /etc/passwd | grep "^$LOGNAME:" |
+ cut -f5 -d':' | sed -e 's/,.*//' > $TEMP
+ ORIGINATOR="`cat $TEMP`"
+ rm -f $TEMP
+ fi
+fi
+
+if [ "$ORIGINATOR" = "" ]; then
+ grep "^$LOGNAME:" /etc/passwd | cut -f5 -d':' | sed -e 's/,.*//' > $TEMP
+ ORIGINATOR="`cat $TEMP`"
+ rm -f $TEMP
+fi
+
+if [ -n "$ORGANIZATION" ]; then
+ if [ -f "$ORGANIZATION" ]; then
+ ORGANIZATION="`cat $ORGANIZATION`"
+ fi
+else
+ if [ -n "$DEFAULT_ORGANIZATION" ]; then
+ ORGANIZATION="$DEFAULT_ORGANIZATION"
+ elif [ -f $HOME/.organization ]; then
+ ORGANIZATION="`cat $HOME/.organization`"
+ elif [ -f $HOME/.signature ]; then
+ ORGANIZATION="`cat $HOME/.signature`"
+ fi
+fi
+
+# If they don't have a preferred editor set, then use
+if [ -z "$VISUAL" ]; then
+ if [ -z "$EDITOR" ]; then
+ EDIT=vi
+ else
+ EDIT="$EDITOR"
+ fi
+else
+ EDIT="$VISUAL"
+fi
+
+# Find out some information.
+SYSTEM=`( [ -f /bin/uname ] && /bin/uname -a ) || \
+ ( [ -f /usr/bin/uname ] && /usr/bin/uname -a ) || echo ""`
+ARCH=`[ -f /bin/arch ] && /bin/arch`
+MACHINE=`[ -f /bin/machine ] && /bin/machine`
+
+COMMAND=`echo $0 | sed -e 's,.*/,,'`
+## USAGE="Usage: $COMMAND [-PVL] [-t address] [-f filename] [--request-id]
+USAGE="Usage: $COMMAND [-PVL]
+[--version]"
+REMOVE=
+BATCH=
+
+while [ $# -gt 0 ]; do
+ case "$1" in
+ -r) ;; # Ignore for backward compat.
+## -t | --to) if [ $# -eq 1 ]; then echo "$USAGE"; exit 1; fi
+## shift ; GNATS_ADDR="$1"
+## EXPLICIT_GNATS_ADDR=true
+## ;;
+## -f | --file) if [ $# -eq 1 ]; then echo "$USAGE"; exit 1; fi
+## shift ; IN_FILE="$1"
+## if [ "$IN_FILE" != "-" -a ! -r "$IN_FILE" ]; then
+## echo "$COMMAND: cannot read $IN_FILE"
+## exit 1
+## fi
+## ;;
+ -b | --batch) BATCH=true ;;
+ -p | -P | --print) PRINT=true ;;
+ -L | --list) FORMAT=norm ;;
+ -l | -CL | --lisp) FORMAT=lisp ;;
+## --request-id) REQUEST_ID=true ;;
+ -h | --help) echo "$USAGE"; exit 0 ;;
+ -V | --version) echo "$VERSION"; exit 0 ;;
+ -*) echo "$USAGE" ; exit 1 ;;
+ *) echo "$USAGE" ; exit 1
+## if [ -z "$USER_GNATS_SITE" ]; then
+## if [ ! -r "$DATADIR/gnats/$1" ]; then
+## echo "$COMMAND: the GNATS site $1 does not have a categories list."
+## exit 1
+## else
+## # The site name is the alias they'll have to have created.
+## USER_GNATS_SITE=$1
+## fi
+## else
+## echo "$USAGE" ; exit 1
+## fi
+ ;;
+ esac
+ shift
+done
+
+if [ -n "$USER_GNATS_SITE" ]; then
+ GNATS_SITE=$USER_GNATS_SITE
+ GNATS_ADDR=$USER_GNATS_SITE-gnats
+fi
+
+if [ "$SUBMITTER" = "unknown" -a -z "$REQUEST_ID" -a -z "$IN_FILE" ]; then
+ cat << '__EOF__'
+It seems that send-pr is not installed with your unique submitter-id.
+You need to run
+
+ install-sid YOUR-SID
+
+where YOUR-SID is the identification code you received with `send-pr'.
+`send-pr' will automatically insert this value into the template field
+`>Submitter-Id'. If you've downloaded `send-pr' from the Net, use `net'
+for this value. If you do not know your id, run `send-pr --request-id' to
+get one from your support site.
+__EOF__
+ exit 1
+fi
+
+## if [ -r "$DATADIR/gnats/$GNATS_SITE" ]; then
+## CATEGORIES=`grep -v '^#' $DATADIR/gnats/$GNATS_SITE | sort`
+## else
+## echo "$COMMAND: could not read $DATADIR/gnats/$GNATS_SITE for categories list."
+## exit 1
+## fi
+CATEGORIES="contrib cvs doc pcl-cvs portability"
+
+if [ -z "$CATEGORIES" ]; then
+ echo "$COMMAND: the categories list for $GNATS_SITE was empty!"
+ exit 1
+fi
+
+case "$FORMAT" in
+ lisp) echo "$CATEGORIES" | \
+ awk 'BEGIN {printf "( "} {printf "(\"%s\") ",$0} END {printf ")\n"}'
+ exit 0
+ ;;
+ norm) l=`echo "$CATEGORIES" | \
+ awk 'BEGIN {max = 0; } { if (length($0) > max) { max = length($0); } }
+ END {print max + 1;}'`
+ c=`expr 70 / $l`
+ if [ $c -eq 0 ]; then c=1; fi
+ echo "$CATEGORIES" | \
+ awk 'BEGIN {print "Known categories:"; i = 0 }
+ { printf ("%-'$l'.'$l's", $0); if ((++i % '$c') == 0) { print "" } }
+ END { print ""; }'
+ exit 0
+ ;;
+esac
+
+ORIGINATOR_C='<name of the PR author (one line)>'
+ORGANIZATION_C='<organization of PR author (multiple lines)>'
+CONFIDENTIAL_C='<[ yes | no ] (one line)>'
+SYNOPSIS_C='<synopsis of the problem (one line)>'
+SEVERITY_C='<[ non-critical | serious | critical ] (one line)>'
+PRIORITY_C='<[ low | medium | high ] (one line)>'
+CATEGORY_C='<name of the product (one line)>'
+CLASS_C='<[ sw-bug | doc-bug | change-request | support ] (one line)>'
+RELEASE_C='<release number or tag (one line)>'
+ENVIRONMENT_C='<machine, os, target, libraries (multiple lines)>'
+DESCRIPTION_C='<precise description of the problem (multiple lines)>'
+HOW_TO_REPEAT_C='<code/input/activities to reproduce the problem (multiple lines)>'
+FIX_C='<how to correct or work around the problem, if known (multiple lines)>'
+
+# Catch some signals. ($xs kludge needed by Sun /bin/sh)
+xs=0
+trap 'rm -f $REF $TEMP; exit $xs' 0
+trap 'echo "$COMMAND: Aborting ..."; rm -f $REF $TEMP; xs=1; exit' 1 2 3 13 15
+
+# If they told us to use a specific file, then do so.
+if [ -n "$IN_FILE" ]; then
+ if [ "$IN_FILE" = "-" ]; then
+ # The PR is coming from the standard input.
+ if [ -n "$EXPLICIT_GNATS_ADDR" ]; then
+ sed -e "s;^[Tt][Oo]:.*;To: $GNATS_ADDR;" > $TEMP
+ else
+ cat > $TEMP
+ fi
+ else
+ # Use the file they named.
+ if [ -n "$EXPLICIT_GNATS_ADDR" ]; then
+ sed -e "s;^[Tt][Oo]:.*;To: $GNATS_ADDR;" $IN_FILE > $TEMP
+ else
+ cat $IN_FILE > $TEMP
+ fi
+ fi
+else
+
+ if [ -n "$PR_FORM" -a -z "$PRINT_INTERN" ]; then
+ # If their PR_FORM points to a bogus entry, then bail.
+ if [ ! -f "$PR_FORM" -o ! -r "$PR_FORM" -o ! -s "$PR_FORM" ]; then
+ echo "$COMMAND: can't seem to read your template file (\`$PR_FORM'), ignoring PR_FORM"
+ sleep 1
+ PRINT_INTERN=bad_prform
+ fi
+ fi
+
+ if [ -n "$PR_FORM" -a -z "$PRINT_INTERN" ]; then
+ cp $PR_FORM $TEMP ||
+ ( echo "$COMMAND: could not copy $PR_FORM" ; xs=1; exit )
+ else
+ for file in $TEMP $REF ; do
+ cat > $file << '__EOF__'
+SEND-PR: -*- send-pr -*-
+SEND-PR: Lines starting with `SEND-PR' will be removed automatically, as
+SEND-PR: will all comments (text enclosed in `<' and `>').
+SEND-PR:
+SEND-PR: Choose from the following categories:
+SEND-PR:
+__EOF__
+
+ # Format the categories so they fit onto lines.
+ l=`echo "$CATEGORIES" | \
+ awk 'BEGIN {max = 0; } { if (length($0) > max) { max = length($0); } }
+ END {print max + 1;}'`
+ c=`expr 61 / $l`
+ if [ $c -eq 0 ]; then c=1; fi
+ echo "$CATEGORIES" | \
+ awk 'BEGIN {printf "SEND-PR: "; i = 0 }
+ { printf ("%-'$l'.'$l's", $0);
+ if ((++i % '$c') == 0) { printf "\nSEND-PR: " } }
+ END { printf "\nSEND-PR:\n"; }' >> $file
+
+ cat >> $file << __EOF__
+To: $GNATS_ADDR
+Subject:
+From: $FROM
+Reply-To: $REPLY_TO
+X-send-pr-version: $VERSION
+
+
+>Submitter-Id: $SUBMITTER
+>Originator: $ORIGINATOR
+>Organization:
+${ORGANIZATION-$ORGANIZATION_C}
+>Confidential: $CONFIDENTIAL_C
+>Synopsis: $SYNOPSIS_C
+>Severity: $SEVERITY_C
+>Priority: $PRIORITY_C
+>Category: $CATEGORY_C
+>Class: $CLASS_C
+>Release: ${DEFAULT_RELEASE-$RELEASE_C}
+>Environment:
+ $ENVIRONMENT_C
+`[ -n "$SYSTEM" ] && echo System: $SYSTEM`
+`[ -n "$ARCH" ] && echo Architecture: $ARCH`
+`[ -n "$MACHINE" ] && echo Machine: $MACHINE`
+>Description:
+ $DESCRIPTION_C
+>How-To-Repeat:
+ $HOW_TO_REPEAT_C
+>Fix:
+ $FIX_C
+__EOF__
+ done
+ fi
+
+ if [ "$PRINT" = true -o "$PRINT_INTERN" = true ]; then
+ cat $TEMP
+ xs=0; exit
+ fi
+
+ chmod u+w $TEMP
+ if [ -z "$REQUEST_ID" ]; then
+ eval $EDIT $TEMP
+ else
+ ed -s $TEMP << '__EOF__'
+/^Subject/s/^Subject:.*/Subject: request for a customer id/
+/^>Category/s/^>Category:.*/>Category: send-pr/
+w
+q
+__EOF__
+ fi
+
+ if cmp -s $REF $TEMP ; then
+ echo "$COMMAND: problem report not filled out, therefore not sent"
+ xs=1; exit
+ fi
+fi
+
+#
+# Check the enumeration fields
+
+# This is a "sed-subroutine" with one keyword parameter
+# (with workaround for Sun sed bug)
+#
+SED_CMD='
+/$PATTERN/{
+s|||
+s|<.*>||
+s|^[ ]*||
+s|[ ]*$||
+p
+q
+}'
+
+
+while [ -z "$REQUEST_ID" ]; do
+ CNT=0
+
+ # 1) Confidential
+ #
+ PATTERN=">Confidential:"
+ CONFIDENTIAL=`eval sed -n -e "\"$SED_CMD\"" $TEMP`
+ case "$CONFIDENTIAL" in
+ ""|yes|no) CNT=`expr $CNT + 1` ;;
+ *) echo "$COMMAND: \`$CONFIDENTIAL' is not a valid value for \`Confidential'." ;;
+ esac
+ #
+ # 2) Severity
+ #
+ PATTERN=">Severity:"
+ SEVERITY=`eval sed -n -e "\"$SED_CMD\"" $TEMP`
+ case "$SEVERITY" in
+ ""|non-critical|serious|critical) CNT=`expr $CNT + 1` ;;
+ *) echo "$COMMAND: \`$SEVERITY' is not a valid value for \`Severity'."
+ esac
+ #
+ # 3) Priority
+ #
+ PATTERN=">Priority:"
+ PRIORITY=`eval sed -n -e "\"$SED_CMD\"" $TEMP`
+ case "$PRIORITY" in
+ ""|low|medium|high) CNT=`expr $CNT + 1` ;;
+ *) echo "$COMMAND: \`$PRIORITY' is not a valid value for \`Priority'."
+ esac
+ #
+ # 4) Category
+ #
+ PATTERN=">Category:"
+ CATEGORY=`eval sed -n -e "\"$SED_CMD\"" $TEMP`
+ FOUND=
+ for C in $CATEGORIES
+ do
+ if [ "$C" = "$CATEGORY" ]; then FOUND=true ; break ; fi
+ done
+ if [ -n "$FOUND" ]; then
+ CNT=`expr $CNT + 1`
+ else
+ if [ -z "$CATEGORY" ]; then
+ echo "$COMMAND: you must include a Category: field in your report."
+ else
+ echo "$COMMAND: \`$CATEGORY' is not a known category."
+ fi
+ fi
+ #
+ # 5) Class
+ #
+ PATTERN=">Class:"
+ CLASS=`eval sed -n -e "\"$SED_CMD\"" $TEMP`
+ case "$CLASS" in
+ ""|sw-bug|doc-bug|change-request|support) CNT=`expr $CNT + 1` ;;
+ *) echo "$COMMAND: \`$CLASS' is not a valid value for \`Class'."
+ esac
+
+ [ $CNT -lt 5 -a -z "$BATCH" ] &&
+ echo "Errors were found with the problem report."
+
+ while true; do
+ if [ -z "$BATCH" ]; then
+ $ECHON1 "a)bort, e)dit or s)end? $ECHON2"
+ read input
+ else
+ if [ $CNT -eq 5 ]; then
+ input=s
+ else
+ input=a
+ fi
+ fi
+ case "$input" in
+ a*)
+ if [ -z "$BATCH" ]; then
+ echo "$COMMAND: the problem report remains in $BAD and is not sent."
+ mv $TEMP $BAD
+ else
+ echo "$COMMAND: the problem report is not sent."
+ fi
+ xs=1; exit
+ ;;
+ e*)
+ eval $EDIT $TEMP
+ continue 2
+ ;;
+ s*)
+ break 2
+ ;;
+ esac
+ done
+done
+#
+# Remove comments and send the problem report
+# (we have to use patterns, where the comment contains regex chars)
+#
+# /^>Originator:/s;$ORIGINATOR;;
+sed -e "
+/^SEND-PR:/d
+/^>Organization:/,/^>[A-Za-z-]*:/s;$ORGANIZATION_C;;
+/^>Confidential:/s;<.*>;;
+/^>Synopsis:/s;$SYNOPSIS_C;;
+/^>Severity:/s;<.*>;;
+/^>Priority:/s;<.*>;;
+/^>Category:/s;$CATEGORY_C;;
+/^>Class:/s;<.*>;;
+/^>Release:/,/^>[A-Za-z-]*:/s;$RELEASE_C;;
+/^>Environment:/,/^>[A-Za-z-]*:/s;$ENVIRONMENT_C;;
+/^>Description:/,/^>[A-Za-z-]*:/s;$DESCRIPTION_C;;
+/^>How-To-Repeat:/,/^>[A-Za-z-]*:/s;$HOW_TO_REPEAT_C;;
+/^>Fix:/,/^>[A-Za-z-]*:/s;$FIX_C;;
+" $TEMP > $REF
+
+if $MAIL_AGENT < $REF; then
+ echo "$COMMAND: problem report sent"
+ xs=0; exit
+else
+ echo "$COMMAND: mysterious mail failure."
+ if [ -z "$BATCH" ]; then
+ echo "$COMMAND: the problem report remains in $BAD and is not sent."
+ mv $REF $BAD
+ else
+ echo "$COMMAND: the problem report is not sent."
+ fi
+ xs=1; exit
+fi
diff --git a/gnu/usr.bin/cvs/cvsinit/Makefile b/gnu/usr.bin/cvs/cvsinit/Makefile
new file mode 100644
index 0000000..7392114
--- /dev/null
+++ b/gnu/usr.bin/cvs/cvsinit/Makefile
@@ -0,0 +1,27 @@
+# $Id: Makefile,v 1.4 1995/12/11 01:58:53 peter Exp $
+
+MAN8= cvsinit.8
+
+EXAMPDIR= /usr/share/examples/cvs
+CLEANFILES+= cvsinit ver
+
+.SUFFIXES: .sh
+
+all: cvsinit
+
+.sh:
+ echo > ver \
+ cvs-`sed < ${.CURDIR}/../lib/version.c \
+ -e '/version_string/!d' \
+ -e 's/[^0-9.]*\([0-9.]*\).*/\1/' \
+ -e q`
+ sed -e 's,xLIBDIRx,$(EXAMPDIR),g' \
+ -e "s,xVERSIONx,`cat ver`,g" ${.CURDIR}/$@.sh > $@
+
+beforeinstall:
+ ${INSTALL} -c -o ${BINOWN} -g ${BINGRP} -m ${BINMODE} \
+ cvsinit ${DESTDIR}${BINDIR}/cvsinit
+
+.include "../../Makefile.inc"
+.include <bsd.prog.mk>
+
diff --git a/gnu/usr.bin/cvs/cvsinit/cvsinit.8 b/gnu/usr.bin/cvs/cvsinit/cvsinit.8
new file mode 100644
index 0000000..1012d62
--- /dev/null
+++ b/gnu/usr.bin/cvs/cvsinit/cvsinit.8
@@ -0,0 +1,142 @@
+.de Id
+.ds Rv \\$4
+.ds Dt \\$5
+..
+.Id @(#)ccvs/man:$Name: $:$Id: cvsinit.8,v 1.2 1995/11/14 20:48:54 woods Exp $
+.TH CVSINIT 8 "\*(Dt"
+.\" Full space in nroff; half space in troff
+.de SP
+.if n .sp
+.if t .sp .5
+..
+.\" quoted command
+.de `
+.RB ` "\|\\$1\|" '\\$2
+..
+.\"
+.SH "NAME"
+cvsinit \- Concurrent Versions System repository initialization script
+.SH "SYNOPSIS"
+.TP
+.B cvsinit
+.\"
+.SH "DESCRIPTION"
+.\"
+The
+.B cvsinit
+script initializes a repository in the location specified by the
+.SM CVSROOT
+environment variable.
+.SH "FILES"
+For more detailed information on
+.B cvs
+supporting files, see
+.BR cvs ( 5 ).
+.LP
+Files in source repositories (created by
+.BR cvsinit ):
+.TP
+$CVSROOT/CVSROOT
+Directory of global administrative files for repository.
+.TP
+$CVSROOT/commitinfo,v
+Records programs for filtering
+.` "cvs commit"
+requests.
+.TP
+$CVSROOT/history
+Log file of \fBcvs\fP transactions.
+.TP
+$CVSROOT/modules,v
+Definitions for modules in this repository.
+.TP
+$CVSROOT/loginfo,v
+Records programs for piping
+.` "cvs commit"
+log entries.
+.TP
+$CVSROOT/rcsinfo,v
+Records pathnames to templates used during a
+.` "cvs commit"
+operation.
+.TP
+$CVSROOT/editinfo,v
+Records programs for editing/validating
+.` "cvs commit"
+log entries.
+.TP
+$CVSROOT/log
+Sample logging script for use in
+.IR loginfo .
+.TP
+$CVSROOT/commit_prep
+Sample logging script for use in
+.I commitinfo
+with the
+.I log_accum
+script
+.TP
+$CVSROOT/log_accum
+Sample loggin script for use in
+.I loginfo
+with the
+.I commit_prep
+script
+.\"
+.SH "ENVIRONMENT VARIABLES"
+.TP
+.SM CVSROOT
+Should contain the full pathname to the root of the
+.B cvs
+source repository (where the
+.SM RCS
+files are kept). This information must be available to \fBcvs\fP for
+most commands to execute; if
+.SM CVSROOT
+is not set, or if you wish to override it for one invocation, you can
+supply it on the command line:
+.` "cvs \-d \fIcvsroot cvs_command\fP\|.\|.\|."
+You may not need to set
+.SM CVSROOT
+if your \fBcvs\fP binary has the right path compiled in; use
+.` "cvs \-v"
+to display all compiled-in paths.
+.\"
+.SH "AUTHORS"
+.TP
+Dick Grune
+Original author of the
+.B cvs
+shell script version posted to
+.B comp.sources.unix
+in the volume6 release of December, 1986.
+Credited with much of the
+.B cvs
+conflict resolution algorithms.
+.TP
+Brian Berliner
+Coder and designer of the
+.B cvs
+program itself in April, 1989, based on the original work done by Dick.
+.TP
+Jeff Polk
+Helped Brian with the design of the
+.B cvs
+module and vendor branch support and author of the
+.BR checkin ( 1 )
+shell script (the ancestor of
+.` "cvs import").
+.SH "SEE ALSO"
+.BR ci ( 1 ),
+.BR co ( 1 ),
+.BR cvs ( 5 ),
+.BR diff ( 1 ),
+.BR grep ( 1 ),
+.BR mkmodules ( 1 ),
+.BR patch ( 1 ),
+.BR rcs ( 1 ),
+.BR rcsdiff ( 1 ),
+.BR rcsmerge ( 1 ),
+.BR rlog ( 1 ),
+.BR rm ( 1 ),
+.BR sort ( 1 ).
diff --git a/gnu/usr.bin/cvs/cvsinit/cvsinit.sh b/gnu/usr.bin/cvs/cvsinit/cvsinit.sh
new file mode 100644
index 0000000..3fa58ad
--- /dev/null
+++ b/gnu/usr.bin/cvs/cvsinit/cvsinit.sh
@@ -0,0 +1,162 @@
+#! /bin/sh
+:
+#
+#ident "@(#)cvs:$Name: $:$Id: cvsinit.sh,v 1.4 1995/12/10 23:06:51 peter Exp $"
+# Copyright (c) 1992, Brian Berliner
+#
+# You may distribute under the terms of the GNU General Public License as
+# specified in the README file that comes with the CVS 1.4 kit.
+
+# This script should be run for each repository you create to help you
+# setup your site for CVS. You may also run it to update existing
+# repositories if you install a new version of CVS.
+
+# this line is edited by Makefile when creating cvsinit.inst
+CVSLIB="xLIBDIRx"
+
+CVS_VERSION="xVERSIONx"
+
+# All purpose usage message, also suffices for --help and --version.
+if test $# -gt 0; then
+ echo "cvsinit version $CVS_VERSION"
+ echo "usage: $0"
+ echo "(set CVSROOT to the repository that you want to initialize)"
+ exit 0
+fi
+
+# Make sure that the CVSROOT variable is set
+if [ "x$CVSROOT" = x ]; then
+ echo "The CVSROOT environment variable is not set."
+ echo ""
+ echo "You should choose a location for your source repository"
+ echo "that can be shared by many developers. It also helps to"
+ echo "place the source repository on a file system that has"
+ echo "plenty of free space."
+ echo ""
+ echo "Please enter the full path for your CVSROOT source repository:"
+ read CVSROOT junk
+ unset junk
+ remind_cvsroot=yes
+else
+ remind_cvsroot=no
+fi
+
+# Now, create the $CVSROOT if it is not already there
+if [ ! -d $CVSROOT ]; then
+ echo "Creating $CVSROOT..."
+ path=
+ for comp in `echo $CVSROOT | sed -e 's,/, ,g'`; do
+ path=$path/$comp
+ if [ ! -d $path ]; then
+ mkdir $path
+ fi
+ done
+else
+ true
+fi
+
+# Next, check for $CVSROOT/CVSROOT
+if [ ! -d $CVSROOT/CVSROOT ]; then
+ if [ -d $CVSROOT/CVSROOT.adm ]; then
+ echo "You have the old $CVSROOT/CVSROOT.adm directory."
+ echo "I will rename it to $CVSROOT/CVSROOT for you..."
+ mv $CVSROOT/CVSROOT.adm $CVSROOT/CVSROOT
+ else
+ echo "Creating the $CVSROOT/CVSROOT directory..."
+ mkdir $CVSROOT/CVSROOT
+ fi
+else
+ true
+fi
+if [ ! -d $CVSROOT/CVSROOT ]; then
+ echo "Unable to create $CVSROOT/CVSROOT."
+ echo "I give up."
+ exit 1
+fi
+
+# Create the special control files and templates within $CVSROOT/CVSROOT
+
+EXAMPLES="checkoutlist commitinfo cvswrappers editinfo loginfo modules
+rcsinfo rcstemplate taginfo wrap unwrap"
+
+NEWSAMPLE=false
+for info in $EXAMPLES; do
+ if [ -f $CVSROOT/CVSROOT/${info},v ]; then
+ if [ ! -f $CVSROOT/CVSROOT/$info ]; then
+ echo "Checking out $CVSROOT/CVSROOT/$info"
+ echo " from $CVSROOT/CVSROOT/${info},v..."
+ (cd $CVSROOT/CVSROOT; co -q $info)
+ fi
+ else
+ NEWSAMPLE=true
+ if [ -f $CVSROOT/CVSROOT/$info ]; then
+ echo "Checking in $CVSROOT/CVSROOT/${info},v"
+ echo " from $CVSROOT/CVSROOT/$info..."
+ else
+ echo "Creating a sample $CVSROOT/CVSROOT/$info file..."
+ case $info in
+ modules)
+ sed -n -e '/END_REQUIRED_CONTENT/q' \
+ -e p $CVSLIB/examples/modules | \
+ sed -e 's@/usr/local/bin@/usr/bin@' > $CVSROOT/CVSROOT/modules
+ ;;
+ rcstemplate)
+ cp $CVSLIB/examples/$info $CVSROOT/CVSROOT/$info
+ ;;
+ wrap|unwrap)
+ cp $CVSLIB/examples/$info $CVSROOT/CVSROOT/$info
+ chmod +x $CVSROOT/CVSROOT/$info
+ ;;
+ *)
+ # comment out everything in all the other examples....
+ sed -e 's/^\([^#]\)/#\1/' $CVSLIB/examples/$info > $CVSROOT/CVSROOT/$info
+ ;;
+ esac
+ fi
+ (cd $CVSROOT/CVSROOT; ci -q -u -t/dev/null -m"initial checkin of $info" $info)
+ fi
+done
+
+if $NEWSAMPLE ; then
+ echo "NOTE: You may wish to check out the CVSROOT module and edit any new"
+ echo "configuration files to match your local requirements."
+ echo ""
+fi
+
+# check to see if there are any references to the old CVSROOT.adm directory
+if grep CVSROOT.adm $CVSROOT/CVSROOT/modules >/dev/null 2>&1; then
+ echo "Warning: your $CVSROOT/CVSROOT/modules file still"
+ echo " contains references to the old CVSROOT.adm directory"
+ echo " You should really change these to the new CVSROOT directory"
+ echo ""
+fi
+
+# These files are generated from the contrib files.
+# FIXME: Is it really wise to overwrite possible local changes like this?
+# Normal folks will keep these up to date by modifying the source in
+# their CVS module and re-installing CVS, but is everyone OK with that?
+#
+#
+CONTRIBS="log commit_prep log_accum cln_hist"
+#
+for contrib in $CONTRIBS; do
+ echo "Copying the new version of '${contrib}'"
+ echo " to $CVSROOT/CVSROOT for you..."
+ cp $CVSLIB/contrib/$contrib $CVSROOT/CVSROOT/$contrib
+done
+
+# XXX - also add a stub for the cvsignore file
+
+# Turn on history logging by default
+if [ ! -f $CVSROOT/CVSROOT/history ]; then
+ echo "Enabling CVS history logging..."
+ touch $CVSROOT/CVSROOT/history
+ chmod g+w $CVSROOT/CVSROOT/history
+ echo "(Remove $CVSROOT/CVSROOT/history to disable.)"
+fi
+
+# finish up by running mkmodules
+echo "All done! Running 'mkmodules' as my final step..."
+mkmodules $CVSROOT/CVSROOT
+
+exit 0
diff --git a/gnu/usr.bin/cvs/doc/Makefile b/gnu/usr.bin/cvs/doc/Makefile
new file mode 100644
index 0000000..874cc46
--- /dev/null
+++ b/gnu/usr.bin/cvs/doc/Makefile
@@ -0,0 +1,5 @@
+# $Id$
+
+INFO = cvs cvsclient
+
+.include <bsd.info.mk>
diff --git a/gnu/usr.bin/cvs/doc/cvs-paper.ms b/gnu/usr.bin/cvs/doc/cvs-paper.ms
new file mode 100644
index 0000000..567179b
--- /dev/null
+++ b/gnu/usr.bin/cvs/doc/cvs-paper.ms
@@ -0,0 +1,1073 @@
+.\" soelim cvs.ms | pic | tbl | troff -ms
+.\" @(#)cvs.ms 1.2 92/01/30
+.\"
+.\" troff source to the cvs USENIX article, Winter 1990, Washington, D.C.
+.\" Copyright (c) 1989, Brian Berliner
+.\"
+.\" This program is free software; you can redistribute it and/or modify
+.\" it under the terms of the GNU General Public License as published by
+.\" the Free Software Foundation; either version 1, or (at your option)
+.\" any later version.
+.\"
+.\" This program is distributed in the hope that it will be useful,
+.\" but WITHOUT ANY WARRANTY; without even the implied warranty of
+.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+.\" GNU General Public License for more details.
+.\"
+.\" You should have received a copy of the GNU General Public License
+.\" along with this program; if not, write to the Free Software
+.\" Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+.\"
+.\" The author can be reached at: berliner@prisma.com
+.\"
+.de SP
+.if n .sp
+.if t .sp .5
+..
+.de hl
+.br
+.in +0.5i
+\l'\\n(LLu-1i'
+.in -0.5i
+.sp
+..
+.OH ""
+.nr PS 11
+.nr PO 1.25i
+.pl -0.2i
+.TL
+.ps 14
+.ft B
+.nf
+CVS II:
+Parallelizing Software Development
+.fi
+.ft
+.ps
+.AU
+.ps 12
+.ft I
+Brian Berliner
+.ft
+.ps
+.AI
+.ps 12
+.ft I
+Prisma, Inc.
+5465 Mark Dabling Blvd.
+Colorado Springs, CO 80918
+berliner@prisma.com
+.ft
+.ps
+.AB
+The program described in this paper fills a need in the UNIX
+community for a freely available tool to manage software revision and
+release control in a multi-developer, multi-directory, multi-group
+environment.
+This tool also addresses the increasing need for tracking third-party vendor
+source distributions while trying to maintain local modifications to
+earlier releases.
+.AE
+.NH
+Background
+.PP
+In large software development projects, it is usually necessary for more
+than one software developer to be modifying (usually different) modules of the
+code at the same time.
+Some of these code modifications are done in an
+experimental sense, at least until the code functions correctly, and some
+testing of the entire program is usually necessary.
+Then, the modifications are returned to a master source repository
+so that others in the project can
+enjoy the new bug-fix or functionality.
+In order to manage such a project, some sort of revision control system is
+necessary.
+.PP
+Specifically, UNIX\**
+.FS
+UNIX is a registered trademark of AT&T.
+.FE
+kernel development is an excellent example of the
+problems that an adequate revision control system must address.
+The SunOS\**
+.FS
+SunOS is a trademark of Sun Microsystems, Inc.
+.FE
+kernel is composed of over a thousand files spread across a
+hierarchy of dozens of directories.\**
+.FS
+Yes, the SunOS 4.0 kernel is composed of over a \fIthousand\fP files!
+.FE
+Pieces of the kernel must be edited
+by many software developers within an organization.
+While undesirable in
+theory, it is not uncommon to have two or more people making
+modifications to the same file within the kernel sources in
+order to facilitate a desired change.
+Existing revision control systems like
+.SM
+RCS
+.LG
+[Tichy] or
+.SM
+SCCS
+.LG
+[Bell] serialize file modifications by
+allowing only one developer to have a writable copy of a particular file at
+any one point in time.
+That developer is said to
+have \*Qlocked\*U the file for his exclusive use, and no other developer is
+allowed to check out a writable copy of the file until the locking
+developer has finished impeding others' productivity.
+Development pressures of productivity and deadlines
+often force organizations to require that multiple developers be able to
+simultaneously edit
+copies of the same revision controlled file.
+.PP
+The necessity for multiple developers to modify the same file concurrently
+questions the value of serialization-based policies in traditional revision
+control.
+This paper discusses the approach that
+Prisma took in adapting a standard revision control system,
+.SM
+RCS\c
+.LG
+, along with an existing public-domain collection of shell scripts that sits
+atop
+.SM
+RCS
+.LG
+and provides the basic conflict-resolution algorithms.
+The resulting
+program, \fBcvs\fP, addresses not only the issue of conflict-resolution in
+a multi-developer open-editing environment, but also the issues of
+software release control and vendor source support and integration.
+.NH
+The CVS Program
+.PP
+\fBcvs\fP
+(Concurrent Versions System)
+is a front end to the
+.SM
+RCS
+.LG
+revision control system which extends
+the notion of revision control from a collection of files in a single
+directory to a hierarchical collection of directories each containing
+revision controlled files.
+Directories and files in the \fBcvs\fP system can be combined together in
+many ways to form a software release.
+\fBcvs\fP
+provides the functions necessary to manage these software releases and to
+control the concurrent editing of source files among multiple software
+developers.
+.PP
+The six major features of \fBcvs\fP are listed below, and will be
+described in more detail in the following sections:
+.RS
+.IP 1.
+Concurrent access and conflict-resolution algorithms to guarantee that
+source changes are not \*Qlost.\*U
+.IP 2.
+Support for tracking third-party vendor source distributions while
+maintaining the local modifications made to those sources.
+.IP 3.
+A flexible module database that provides a symbolic mapping of names to
+components of a larger software distribution.
+This symbolic mapping provides for location independence within the software
+release and, for example, allows one to check out a copy of the \*Qdiff\*U
+program without ever knowing that the sources to \*Qdiff\*U actually reside
+in the \*Qbin/diff\*U directory.
+.IP 4.
+Configurable logging support allows all \*Qcommitted\*U source file changes
+to be logged using an arbitrary program to save the log messages in a file,
+notesfile, or news database.
+.IP 5.
+A software release can be symbolically tagged and checked out at any time
+based on that tag.
+An exact copy of a previous software release can be checked out at
+any time, \fIregardless\fP of whether files or directories have been
+added/removed from the \*Qcurrent\*U software release.
+As well,
+a \*Qdate\*U can be used to check out the \fIexact\fP version of the software
+release as of the specified date.
+.IP 6.
+A \*Qpatch\*U format file [Wall] can be produced between two software
+releases, even if the releases span multiple directories.
+.RE
+.PP
+The sources maintained by \fBcvs\fP are kept within a single directory
+hierarchy known as the \*Qsource repository.\*U
+This \*Qsource repository\*U holds the actual
+.SM
+RCS
+.LG
+\*Q,v\*U files directly, as well as a special per-repository directory
+(\c
+.SM
+CVSROOT.adm\c
+.LG
+) which contains a small number of administrative files that describe the
+repository and how it can be accessed.
+See Figure 1 for a picture of the \fBcvs\fP tree.
+.KF
+.hl
+.DS B
+.PS
+line from 4.112,9.200 to 5.550,8.887
+line from 5.447,8.884 to 5.550,8.887 to 5.458,8.933
+line from 4.112,9.200 to 4.550,8.950
+line from 4.451,8.978 to 4.550,8.950 to 4.476,9.021
+line from 4.112,9.200 to 3.737,8.887
+line from 3.798,8.971 to 3.737,8.887 to 3.830,8.932
+line from 3.612,8.762 to 4.737,8.137
+line from 4.638,8.164 to 4.737,8.137 to 4.662,8.208
+line from 3.612,8.762 to 3.737,8.137
+line from 3.693,8.231 to 3.737,8.137 to 3.742,8.240
+line from 3.612,8.762 to 2.612,8.200
+line from 2.687,8.271 to 2.612,8.200 to 2.712,8.227
+line from 2.362,9.262 to 2.737,8.950
+line from 2.645,8.995 to 2.737,8.950 to 2.677,9.033
+line from 2.362,9.262 to 1.925,8.950
+line from 1.992,9.028 to 1.925,8.950 to 2.021,8.988
+line from 3.362,9.762 to 4.050,9.387
+line from 3.950,9.413 to 4.050,9.387 to 3.974,9.457
+line from 3.362,9.762 to 2.487,9.387
+line from 2.570,9.450 to 2.487,9.387 to 2.589,9.404
+.ps 11
+"newfs.c,v" at 4.487,8.043 ljust
+.ps 11
+"mkfs.c,v" at 3.487,8.043 ljust
+.ps 11
+"Makefile,v" at 2.237,8.043 ljust
+.ps 11
+"newfs" at 3.487,8.793 ljust
+.ps 11
+"halt.c,v" at 5.487,8.793 ljust
+.ps 11
+"Makefile,v" at 4.237,8.793 ljust
+.ps 11
+"modules,v" at 2.487,8.793 ljust
+.ps 11
+"loginfo,v" at 1.488,8.793 ljust
+.ps 11
+"etc" at 3.987,9.293 ljust
+.ps 11
+"CVSROOT.adm" at 1.988,9.293 ljust
+.ps 11
+"/src/master" at 2.987,9.793 ljust
+.PE
+.DE
+.hl
+.ce 100
+.LG
+\fBFigure 1.\fP
+.SM
+\fBcvs\fP Source Repository
+.ce 0
+.sp
+.KE
+.NH 2
+Software Conflict Resolution\**
+.FS
+The basic conflict-resolution algorithms
+used in the \fBcvs\fP program find their roots
+in the original work done by Dick Grune at Vrije Universiteit in Amsterdam
+and posted to \fBcomp.sources.unix\fP in the volume 6 release sometime in 1986.
+This original version of \fBcvs\fP was a collection of shell scripts that
+combined to form a front end to the
+.SM
+RCS
+.LG
+programs.
+.FE
+.PP
+\fBcvs\fP allows several software developers to edit personal copies of a
+revision controlled file concurrently.
+The revision number of each checked out file is maintained independently
+for each user, and \fBcvs\fP forces the checked out file to be current with
+the \*Qhead\*U revision before it can be \*Qcommitted\*U as a permanent change.
+A checked out file is brought up-to-date with the \*Qhead\*U revision using
+the \*Qupdate\*U command of \fBcvs\fP.
+This command compares the \*Qhead\*U revision number with that of the user's
+file and performs an
+.SM
+RCS
+.LG
+merge operation if they are not the same.
+The result of the merge is a file that contains the user's modifications
+and those modifications that were \*Qcommitted\*U after the user
+checked out his version of the file (as well as a backup copy of the
+user's original file).
+\fBcvs\fP points out any conflicts during the merge.
+It is the user's responsibility to resolve these conflicts
+and to \*Qcommit\*U his/her changes when ready.
+.PP
+Although the \fBcvs\fP conflict-resolution algorithm was defined in 1986,
+it is remarkably similar to the \*QCopy-Modify-Merge\*U scenario included
+with NSE\**
+.FS
+NSE is the Network Software Environment, a product of Sun Microsystems, Inc.
+.FE
+and described in [Honda] and [Courington].
+The following explanation from [Honda] also applies to \fBcvs\fP:
+.QP
+Simply stated, a developer copies an object without locking it, modifies
+the copy, and then merges the modified copy with the original.
+This paradigm allows developers to work in isolation from one another since
+changes are made to copies of objects.
+Because locks are not used, development is not serialized and can proceed
+in parallel.
+Developers, however, must merge objects after the changes have been made.
+In particular, a developer must resolve conflicts when the same object has
+been modified by someone else.
+.PP
+In practice, Prisma has found that conflicts that occur when the same
+object has been modified by someone else are quite rare.
+When they do happen, the changes made by the other developer are usually
+easily resolved.
+This practical use has shown that the \*QCopy-Modify-Merge\*U paradigm is a
+correct and useful one.
+.NH 2
+Tracking Third-Party Source Distributions
+.PP
+Currently, a large amount of software is based on source
+distributions from a third-party distributor.
+It is often the case that local modifications are to be made to this
+distribution, \fIand\fP that the vendor's future releases should be
+tracked.
+Rolling your local modifications forward into the new vendor release is a
+time-consuming task, but \fBcvs\fP can ease this burden somewhat.
+The \fBcheckin\fP program of \fBcvs\fP initially sets up a source
+repository by integrating the source modules directly from the vendor's
+release, preserving the directory hierarchy of the vendor's distribution.
+The branch support of
+.SM
+RCS
+.LG
+is used to build this vendor release as a branch of the main
+.SM
+RCS
+.LG
+trunk.
+Figure 2 shows how the \*Qhead\*U tracks a sample vendor
+branch when no local modifications have been made to the file.
+.KF
+.hl
+.DS B
+.PS
+ellipse at 3.237,6.763 wid 1.000 ht 0.500
+dashwid = 0.050i
+line dashed from 3.237,7.513 to 3.737,7.513 to 3.737,9.762 to 4.237,9.762
+line from 4.138,9.737 to 4.237,9.762 to 4.138,9.787
+line dashed from 2.237,8.262 to 3.237,8.262 to 3.237,7.013
+line from 3.212,7.112 to 3.237,7.013 to 3.262,7.112
+line from 3.737,6.763 to 4.237,6.763
+line from 4.138,6.737 to 4.237,6.763 to 4.138,6.788
+line from 2.237,6.763 to 2.737,6.763
+line from 2.637,6.737 to 2.737,6.763 to 2.637,6.788
+line from 1.738,6.013 to 1.738,6.513
+line from 1.762,6.413 to 1.738,6.513 to 1.713,6.413
+line from 1.238,7.013 to 2.237,7.013 to 2.237,6.513 to 1.238,6.513 to 1.238,7.013
+line from 4.237,9.012 to 5.237,9.012 to 5.237,8.512 to 4.237,8.512 to 4.237,9.012
+line from 4.237,8.012 to 5.237,8.012 to 5.237,7.513 to 4.237,7.513 to 4.237,8.012
+line from 4.237,7.013 to 5.237,7.013 to 5.237,6.513 to 4.237,6.513 to 4.237,7.013
+line from 4.737,7.013 to 4.737,7.513
+line from 4.763,7.413 to 4.737,7.513 to 4.712,7.413
+line from 4.737,8.012 to 4.737,8.512
+line from 4.763,8.412 to 4.737,8.512 to 4.712,8.412
+line from 4.237,10.012 to 5.237,10.012 to 5.237,9.512 to 4.237,9.512 to 4.237,10.012
+line from 4.737,9.012 to 4.737,9.512
+line from 4.763,9.412 to 4.737,9.512 to 4.712,9.412
+line from 5.987,5.013 to 5.987,6.013 to 0.988,6.013 to 0.988,5.013 to 5.987,5.013
+.ps 11
+"\"HEAD\"" at 1.550,8.231 ljust
+.ps 11
+"'SunOS'" at 2.987,6.293 ljust
+.ps 11
+"1.1.1" at 3.050,6.793 ljust
+.ps 11
+"1.1" at 1.613,6.793 ljust
+.ps 11
+"1.1.1.1" at 4.487,6.793 ljust
+.ps 11
+"1.1.1.2" at 4.487,7.793 ljust
+.ps 11
+"1.1.1.3" at 4.487,8.793 ljust
+.ps 11
+"1.1.1.4" at 4.487,9.793 ljust
+.ps 11
+"'SunOS_4_0'" at 5.487,6.793 ljust
+.ps 11
+"'SunOS_4_0_1'" at 5.487,7.793 ljust
+.ps 11
+"'YAPT_5_5C'" at 5.487,8.793 ljust
+.ps 11
+"'SunOS_4_0_3'" at 5.487,9.793 ljust
+.ps 11
+"rcsfile.c,v" at 2.987,5.543 ljust
+.PE
+.DE
+.hl
+.ce 100
+.LG
+\fBFigure 2.\fP
+.SM
+\fBcvs\fP Vendor Branch Example
+.ce 0
+.sp .3
+.KE
+Once this is done, developers can check out files and make local changes to
+the vendor's source distribution.
+These local changes form a new branch to the tree which is then used as the
+source for future check outs.
+Figure 3 shows how the \*Qhead\*U moves to the main
+.SM
+RCS
+.LG
+trunk when a local modification is made.
+.KF
+.hl
+.DS B
+.PS
+ellipse at 3.237,6.763 wid 1.000 ht 0.500
+dashwid = 0.050i
+line dashed from 2.800,9.075 to 1.738,9.075 to 1.738,8.012
+line from 1.713,8.112 to 1.738,8.012 to 1.762,8.112
+line from 1.738,7.013 to 1.738,7.513
+line from 1.762,7.413 to 1.738,7.513 to 1.713,7.413
+line from 1.238,8.012 to 2.237,8.012 to 2.237,7.513 to 1.238,7.513 to 1.238,8.012
+line from 3.737,6.763 to 4.237,6.763
+line from 4.138,6.737 to 4.237,6.763 to 4.138,6.788
+line from 2.237,6.763 to 2.737,6.763
+line from 2.637,6.737 to 2.737,6.763 to 2.637,6.788
+line from 1.738,6.013 to 1.738,6.513
+line from 1.762,6.413 to 1.738,6.513 to 1.713,6.413
+line from 1.238,7.013 to 2.237,7.013 to 2.237,6.513 to 1.238,6.513 to 1.238,7.013
+line from 4.237,9.012 to 5.237,9.012 to 5.237,8.512 to 4.237,8.512 to 4.237,9.012
+line from 4.237,8.012 to 5.237,8.012 to 5.237,7.513 to 4.237,7.513 to 4.237,8.012
+line from 4.237,7.013 to 5.237,7.013 to 5.237,6.513 to 4.237,6.513 to 4.237,7.013
+line from 4.737,7.013 to 4.737,7.513
+line from 4.763,7.413 to 4.737,7.513 to 4.712,7.413
+line from 4.737,8.012 to 4.737,8.512
+line from 4.763,8.412 to 4.737,8.512 to 4.712,8.412
+line from 4.237,10.012 to 5.237,10.012 to 5.237,9.512 to 4.237,9.512 to 4.237,10.012
+line from 4.737,9.012 to 4.737,9.512
+line from 4.763,9.412 to 4.737,9.512 to 4.712,9.412
+line from 5.987,5.013 to 5.987,6.013 to 0.988,6.013 to 0.988,5.013 to 5.987,5.013
+.ps 11
+"1.2" at 1.613,7.793 ljust
+.ps 11
+"\"HEAD\"" at 2.862,9.043 ljust
+.ps 11
+"'SunOS'" at 2.987,6.293 ljust
+.ps 11
+"1.1.1" at 3.050,6.793 ljust
+.ps 11
+"1.1" at 1.613,6.793 ljust
+.ps 11
+"1.1.1.1" at 4.487,6.793 ljust
+.ps 11
+"1.1.1.2" at 4.487,7.793 ljust
+.ps 11
+"1.1.1.3" at 4.487,8.793 ljust
+.ps 11
+"1.1.1.4" at 4.487,9.793 ljust
+.ps 11
+"'SunOS_4_0'" at 5.487,6.793 ljust
+.ps 11
+"'SunOS_4_0_1'" at 5.487,7.793 ljust
+.ps 11
+"'YAPT_5_5C'" at 5.487,8.793 ljust
+.ps 11
+"'SunOS_4_0_3'" at 5.487,9.793 ljust
+.ps 11
+"rcsfile.c,v" at 2.987,5.543 ljust
+.PE
+.DE
+.hl
+.ce 100
+.LG
+\fBFigure 3.\fP
+.SM
+\fBcvs\fP Local Modification to Vendor Branch
+.ce 0
+.sp
+.KE
+.PP
+When a new version of the vendor's source distribution arrives, the
+\fBcheckin\fP program adds the new and changed vendor's files to the
+already existing source repository.
+For files that have not been changed locally, the new file from the
+vendor becomes the current \*Qhead\*U revision.
+For files that have been modified locally, \fBcheckin\fP warns that the
+file must be merged with the new vendor release.
+The \fBcvs\fP \*Qjoin\*U command is a useful tool that aids this process by
+performing the necessary
+.SM
+RCS
+.LG
+merge, as is done above when performing an \*Qupdate.\*U
+.PP
+There is also limited support for \*Qdual\*U derivations for source files.
+See Figure 4 for a sample dual-derived file.
+.KF
+.hl
+.DS B
+.PS
+ellipse at 2.337,8.575 wid 0.700 ht 0.375
+ellipse at 2.312,9.137 wid 0.700 ht 0.375
+line from 1.225,9.012 to 1.225,9.363
+line from 1.250,9.263 to 1.225,9.363 to 1.200,9.263
+line from 0.875,9.725 to 1.600,9.725 to 1.600,9.363 to 0.875,9.363 to 0.875,9.725
+line from 0.875,9.012 to 1.600,9.012 to 1.600,8.650 to 0.875,8.650 to 0.875,9.012
+line from 4.050,10.200 to 4.775,10.200 to 4.775,9.850 to 4.050,9.850 to 4.050,10.200
+line from 4.050,9.475 to 4.775,9.475 to 4.775,9.113 to 4.050,9.113 to 4.050,9.475
+line from 4.050,8.762 to 4.775,8.762 to 4.775,8.400 to 4.050,8.400 to 4.050,8.762
+line from 4.425,8.762 to 4.425,9.113
+line from 4.450,9.013 to 4.425,9.113 to 4.400,9.013
+line from 4.425,9.475 to 4.425,9.850
+line from 4.450,9.750 to 4.425,9.850 to 4.400,9.750
+line from 3.050,10.000 to 3.775,10.000 to 3.775,9.637 to 3.050,9.637 to 3.050,10.000
+line from 3.050,9.312 to 3.775,9.312 to 3.775,8.950 to 3.050,8.950 to 3.050,9.312
+line from 0.713,7.325 to 0.713,8.075 to 4.925,8.075 to 4.925,7.325 to 0.713,7.325
+line from 1.238,8.075 to 1.238,8.637
+line from 1.262,8.537 to 1.238,8.637 to 1.213,8.537
+line from 1.613,8.825 to 1.975,8.575
+line from 1.878,8.611 to 1.975,8.575 to 1.907,8.652
+line from 2.675,8.575 to 4.050,8.575
+line from 3.950,8.550 to 4.050,8.575 to 3.950,8.600
+line from 2.675,9.137 to 3.050,9.137
+line from 2.950,9.112 to 3.050,9.137 to 2.950,9.162
+line from 3.425,9.325 to 3.425,9.637
+line from 3.450,9.537 to 3.425,9.637 to 3.400,9.537
+line from 1.613,8.825 to 1.925,9.137
+line from 1.872,9.049 to 1.925,9.137 to 1.837,9.084
+.ps 11
+"'BSD'" at 2.138,9.481 ljust
+.ps 11
+"1.2" at 1.113,9.543 ljust
+.ps 11
+"1.1" at 1.125,8.831 ljust
+.ps 11
+"1.1.1.1" at 4.175,8.543 ljust
+.ps 11
+"1.1.1.2" at 4.175,9.281 ljust
+.ps 11
+"1.1.1.3" at 4.175,9.993 ljust
+.ps 11
+"1.1.2.2" at 3.175,9.793 ljust
+.ps 11
+"1.1.2.1" at 3.175,9.106 ljust
+.ps 11
+"rcsfile.c,v" at 2.425,7.706 ljust
+.ps 11
+"1.1.1" at 2.175,8.568 ljust
+.ps 11
+"'SunOS'" at 2.125,8.243 ljust
+.ps 11
+"1.1.2" at 2.163,9.131 ljust
+.PE
+.DE
+.hl
+.ce 100
+.LG
+\fBFigure 4.\fP
+.SM
+\fBcvs\fP Support For \*QDual\*U Derivations
+.ce 0
+.sp
+.KE
+This example tracks the SunOS distribution but includes major changes from
+Berkeley.
+These BSD files are saved directly in the
+.SM
+RCS
+.LG
+file off a new branch.
+.NH 2
+Location Independent Module Database
+.PP
+\fBcvs\fP contains support for a simple, yet powerful, \*Qmodule\*U database.
+For reasons of efficiency, this database is stored in \fBndbm\fP\|(3) format.
+The module database is used to apply names to collections of directories
+and files as a matter of convenience for checking out pieces of a large
+software distribution.
+The database records the physical location of the sources as a form of
+information hiding, allowing one to check out whole directory hierarchies
+or individual files without regard for their actual location within the
+global source distribution.
+.PP
+Consider the following small sample of a module database, which must be
+tailored manually to each specific source repository environment:
+.DS
+\f(CW #key [-option argument] directory [files...]
+ diff bin/diff
+ libc lib/libc
+ sys -o sys/tools/make_links sys
+ modules -i mkmodules CVSROOT.adm modules
+ kernel -a sys lang/adb
+ ps bin Makefile ps.c\fP
+.DE
+.PP
+The \*Qdiff\*U and \*Qlibc\*U modules refer to whole directory hierarchies that
+are extracted on check out.
+The \*Qsys\*U module extracts the \*Qsys\*U hierarchy, and runs the
+\*Qmake_links\*U program at the end of the check out process (the \fI-o\fP
+option specifies a program to run on check\fIo\fPut).
+The \*Qmodules\*U module allows one to edit the module database file and
+runs the \*Qmkmodules\*U program on check\fIi\fPn to regenerate the
+\fBndbm\fP database that \fBcvs\fP uses.
+The \*Qkernel\*U module is an alias (as the \fI-a\fP option specifies)
+which causes the remaining arguments after the \fI-a\fP to be interpreted
+exactly as if they had been specified on the command line.
+This is useful for objects that require shared pieces of code from far away
+places to be compiled (as is the case with the kernel debugger, \fBkadb\fP,
+which shares code with the standard \fBadb\fP debugger).
+The \*Qps\*U module shows that the source for \*Qps\*U lives in the \*Qbin\*U
+directory, but only \fIMakefile\fP and \fIps.c\fP are required to build the
+object.
+.PP
+The module database at Prisma is now populated for the entire UNIX
+distribution and thereby allows us to issue the
+following convenient commands to check out components of the UNIX
+distribution without regard for their actual location within the master source
+repository:
+.DS
+\f(CW example% cvs checkout diff
+ example% cvs checkout libc ps
+ example% cd diff; make\fP
+.DE
+.PP
+In building the module database file, it is quite possible to have name
+conflicts within a global software distribution.
+For example, SunOS provides two \fBcat\fP programs:
+one for the standard environment, \fI/bin/cat\fP, and one for the System V
+environment, \fI/usr/5bin/cat\fP.
+We resolved this conflict by naming the standard \fBcat\fP module
+\*Qcat\*U, and the System V \fBcat\fP module \*Q5cat\*U.
+Similar name modifications must be applied to other conflicting names, as
+might be found between a utility program and a library function, though
+Prisma chose not to include individual library functions within the module
+database at this time.
+.NH 2
+Configurable Logging Support
+.PP
+The \fBcvs\fP \*Qcommit\*U command is used to make a permanent change to the
+master source repository (where the
+.SM
+RCS
+.LG
+\*Q,v\*U files live).
+Whenever a \*Qcommit\*U is done, the log message for the change is carefully
+logged by an arbitrary program (in a file, notesfile, news database, or
+mail).
+For example, a collection of these updates can be used to produce release
+notices.
+\fBcvs\fP can be configured to send log updates through one or more filter
+programs, based on a regular expression match on the directory that is
+being changed.
+This allows multiple related or unrelated projects to exist within a single
+\fBcvs\fP source repository tree, with each different project sending its
+\*Qcommit\*U reports to a unique log device.
+.PP
+A sample logging configuration file might look as follows:
+.DS
+\f(CW #regex filter-program
+ DEFAULT /usr/local/bin/nfpipe -t %s utils.updates
+ ^diag /usr/local/bin/nfpipe -t %s diag.updates
+ ^local /usr/local/bin/nfpipe -t %s local.updates
+ ^perf /usr/local/bin/nfpipe -t %s perf.updates
+ ^sys /usr/local/bin/nfpipe -t %s kernel.updates\fP
+.DE
+.PP
+This sample allows the diagnostics and performance groups to
+share the same source repository with the kernel and utilities groups.
+Changes that they make are sent directly to their own notesfile [Essick]
+through the \*Qnfpipe\*U program.
+A sufficiently simple title is substituted for the \*Q%s\*U argument before
+the filter program is executed.
+This logging configuration file is tailored manually to each specific
+source repository environment.
+.NH 2
+Tagged Releases and Dates
+.PP
+Any release can be given a symbolic tag name that is stored directly in the
+.SM
+RCS
+.LG
+files.
+This tag can be used at any time to get an exact copy of any previous
+release.
+With equal ease, one can also extract an exact copy of the source files as
+of any arbitrary date in the past as well.
+Thus, all that's required to tag the current kernel, and to tag the kernel
+as of the Fourth of July is:
+.DS
+\f(CW example% cvs tag TEST_KERNEL kernel
+ example% cvs tag -D 'July 4' PATRIOTIC_KERNEL kernel\fP
+.DE
+The following command would retrieve an exact copy of the test kernel at
+some later date:
+.DS
+\f(CW example% cvs checkout -fp -rTEST_KERNEL kernel\fP
+.DE
+The \fI-f\fP option causes only files that match the specified tag to be
+extracted, while the \fI-p\fP option automatically prunes empty directories.
+Consequently, directories added to the kernel after the test kernel was
+tagged are not included in the newly extracted copy of the test kernel.
+.PP
+The \fBcvs\fP date support has exactly the same interface as that provided
+with
+.SM
+RCS\c
+.LG
+, however \fBcvs\fP must process the \*Q,v\*U files directly due to the
+special handling required by the vendor branch support.
+The standard
+.SM
+RCS
+.LG
+date handling only processes one branch (or the main trunk) when checking
+out based on a date specification.
+\fBcvs\fP must instead process the current \*Qhead\*U branch and, if a
+match is not found, proceed to look for a match on the vendor branch.
+This, combined with reasons of performance, is why \fBcvs\fP processes
+revision (symbolic and numeric) and date specifications directly from the
+\*Q,v\*U files.
+.NH 2
+Building \*Qpatch\*U Source Distributions
+.PP
+\fBcvs\fP can produce a \*Qpatch\*U format [Wall] output file which can be
+used to bring a previously released software distribution current with the
+newest release.
+This patch file supports an entire directory hierarchy within a single
+patch, as well as being able to add whole new files to the previous
+release.
+One can combine symbolic revisions and dates together to display changes in
+a very generic way:
+.DS
+\f(CW example% cvs patch -D 'December 1, 1988' \e
+ -D 'January 1, 1989' sys\fP
+.DE
+This example displays the kernel changes made in the month of December,
+1988.
+To release a patch file, for example, to take the \fBcvs\fP distribution
+from version 1.0 to version 1.4 might be done as follows:
+.DS
+\f(CW example% cvs patch -rCVS_1_0 -rCVS_1_4 cvs\fP
+.DE
+.NH
+CVS Experience
+.NH 2
+Statistics
+.PP
+A quick summary of the scale that \fBcvs\fP is addressing today
+can be found in Table 1.
+.KF
+.TS
+box center tab(:);
+c s
+c s
+c | c
+l | n .
+\fB\s+2Revision Control Statistics at Prisma
+as of 11/11/89\fP\s-2
+_
+How Many...:Total
+=
+Files:17243
+Directories:1005
+Lines of code:3927255
+Removed files:131
+Software developers:14
+Software groups:6
+Megabytes of source:128
+.TE
+.ce 100
+.LG
+\fBTable 1.\fP
+.SM
+\fBcvs\fP Statistics
+.ce 0
+.sp .3
+.KE
+Table 2 shows the history of files changed or added and the number
+of source lines affected by the change at Prisma.
+Only changes made to the kernel sources are included.
+.KF
+.TS
+box center tab(:);
+c s s s s
+c s s s s
+c || c | c || c | c
+c || c | c || c | c
+l || n | n || n | n.
+\fB\s+2Prisma Kernel Source File Changes
+By Month, 1988-1989\fP\s-2
+_
+Month:# Changed:# Lines:# Added:# Lines
+\^:Files:Changed:Files:Added
+=
+Dec:87:3619:68:9266
+Jan:39:4324:0:0
+Feb:73:1578:5:3550
+Mar:99:5301:18:11461
+Apr:112:7333:11:5759
+May:138:5371:17:13986
+Jun:65:2261:27:12875
+Jul:34:2000:1:58
+Aug:65:6378:8:4724
+Sep:266:23410:113:39965
+Oct:22:621:1:155
+Total:1000:62196:269:101799
+.TE
+.ce 100
+.LG
+\fBTable 2.\fP
+.SM
+\fBcvs\fP Usage History for the Kernel
+.ce 0
+.sp
+.KE
+The large number of source file changes made in September are the result of
+merging the SunOS 4.0.3 sources into the kernel.
+This merge process is described in section 3.3.
+.NH 2
+Performance
+.PP
+The performance of \fBcvs\fP is currently quite reasonable.
+Little effort has been expended on tuning \fBcvs\fP, although performance
+related decisions were made during the \fBcvs\fP design.
+For example, \fBcvs\fP parses the
+.SM
+RCS
+.LG
+\*Q,v\*U files directly instead of running an
+.SM
+RCS
+.LG
+process.
+This includes following branches as well as integrating with the vendor
+source branches and the main trunk when checking out files based on a date.
+.PP
+Checking out the entire kernel source tree (1223 files/59 directories)
+currently takes 16 wall clock minutes on a Sun-4/280.
+However, bringing the tree up-to-date with the current kernel sources, once
+it has been checked out, takes only 1.5 wall clock minutes.
+Updating the \fIcomplete\fP 128 MByte source tree under \fBcvs\fP control
+(17243 files/1005 directories) takes roughly 28 wall clock minutes and
+utilizes one-third of the machine.
+For now this is entirely acceptable; improvements on these numbers will
+possibly be made in the future.
+.NH 2
+The SunOS 4.0.3 Merge
+.PP
+The true test of the \fBcvs\fP vendor branch support came with the arrival
+of the SunOS 4.0.3 source upgrade tape.
+As described above, the \fBcheckin\fP program was used to install the new
+sources and the resulting output file listed the files that had been
+locally modified, needing to be merged manually.
+For the kernel, there were 94 files in conflict.
+The \fBcvs\fP \*Qjoin\*U command was used on each of the 94 conflicting
+files, and the remaining conflicts were resolved.
+.PP
+The \*Qjoin\*U command performs an \fBrcsmerge\fP operation.
+This in turn uses \fI/usr/lib/diff3\fP to produce a three-way diff file.
+As it happens, the \fBdiff3\fP program has a hard-coded limit of 200
+source-file changes maximum.
+This proved to be too small for a few of the kernel files that needed
+merging by hand, due to the large number of local changes that Prisma had
+made.
+The \fBdiff3\fP problem was solved by increasing the hard-coded limit by an
+order of magnitude.
+.PP
+The SunOS 4.0.3 kernel source upgrade distribution contained
+346 files, 233 of which were modifications to previously released files,
+and 113 of which were newly added files.
+\fBcheckin\fP added the 113 new files to the source repository
+without intervention.
+Of the 233 modified files, 139 dropped in cleanly by \fBcheckin\fP, since
+Prisma had not made any local changes to them, and 94 required manual
+merging due to local modifications.
+The 233 modified files consisted of 20,766 lines of differences.
+It took one developer two days to manually merge the 94 files using the
+\*Qjoin\*U command and resolving conflicts manually.
+An additional day was required for kernel debugging.
+The entire process of merging over 20,000 lines of differences was
+completed in less than a week.
+This one time-savings alone was justification enough for the \fBcvs\fP
+development effort; we expect to gain even more when tracking future SunOS
+releases.
+.NH
+Future Enhancements and Current Bugs
+.PP
+Since \fBcvs\fP was designed to be incomplete, for reasons of design
+simplicity, there are naturally a good
+number of enhancements that can be made to make it more useful.
+As well, some nuisances exist in the current implementation.
+.RS
+.IP \(bu 3
+\fBcvs\fP does not currently \*Qremember\*U who has a checked out a copy of a
+module.
+As a result, it is impossible to know who might be working on the same
+module that you are.
+A simple-minded database that is updated nightly would likely suffice.
+.IP \(bu 3
+Signal processing, keyboard interrupt handling in particular, is currently
+somewhat weak.
+This is due to the heavy use of the \fBsystem\fP\|(3) library
+function to execute
+.SM
+RCS
+.LG
+programs like \fBco\fP and \fBci\fP.
+It sometimes takes multiple interrupts to make \fBcvs\fP quit.
+This can be fixed by using a home-grown \fBsystem\fP\|() replacement.
+.IP \(bu 3
+Security of the source repository is currently not dealt with directly.
+The usual UNIX approach of user-group-other security permissions through
+the file system is utilized, but nothing else.
+\fBcvs\fP could likely be a set-group-id executable that checks a
+protected database to verify user access permissions for particular objects
+before allowing any operations to affect those objects.
+.IP \(bu 3
+With every checked-out directory, \fBcvs\fP maintains some administrative
+files that record the current revision numbers of the checked-out files as
+well as the location of the respective source repository.
+\fBcvs\fP does not recover nicely at all if these administrative files are
+removed.
+.IP \(bu 3
+The source code for \fBcvs\fP has been tested extensively on Sun-3 and
+Sun-4 systems, all running SunOS 4.0 or later versions of the operating
+system.
+Since the code has not yet been compiled under other platforms, the overall
+portability of the code is still questionable.
+.IP \(bu 3
+As witnessed in the previous section, the \fBcvs\fP method for tracking
+third party vendor source distributions can work quite nicely.
+However, if the vendor changes the directory structure or the file names
+within the source distribution, \fBcvs\fP has no way of matching the old
+release with the new one.
+It is currently unclear as to how to solve this, though it is certain to
+happen in practice.
+.RE
+.NH
+Availability
+.PP
+The \fBcvs\fP program sources can be found in a recent posting to the
+\fBcomp.sources.unix\fP newsgroup.
+It is also currently available via anonymous ftp from \*Qprisma.com\*U.
+Copying rights for \fBcvs\fP will be covered by the GNU General Public
+License.
+.NH
+Summary
+.PP
+Prisma has used \fBcvs\fP since December, 1988.
+It has evolved to meet our specific needs of revision and release control.
+We will make our code freely available so that others can
+benefit from our work, and can enhance \fBcvs\fP to meet broader needs yet.
+.PP
+Many of the other software release and revision control systems, like the
+one described in [Glew], appear to use a collection of tools that are
+geared toward specific environments \(em one set of tools for the kernel,
+one set for \*Qgeneric\*U software, one set for utilities, and one set for
+kernel and utilities.
+Each of these tool sets apparently handle some specific aspect of the
+problem uniquely.
+\fBcvs\fP took a somewhat different approach.
+File sharing through symbolic or hard links is not addressed; instead, the
+disk space is simply burned since it is \*Qcheap.\*U
+Support for producing objects for multiple architectures is not addressed;
+instead, a parallel checked-out source tree must be used for each
+architecture, again wasting disk space to simplify complexity and ease of
+use \(em punting on this issue allowed \fIMakefile\fPs to remain
+unchanged, unlike the approach taken in [Mahler], thereby maintaining closer
+compatibility with the third-party vendor sources.
+\fBcvs\fP is essentially a source-file server, making no assumptions or
+special handling of the sources that it controls.
+To \fBcvs\fP:
+.QP
+A source is a source, of course, of course, unless of course the source is
+Mr. Ed.\**
+.FS
+\fBcvs\fP, of course, does not really discriminate against Mr. Ed.\**
+.FE
+.FS
+Yet.
+.FE
+.LP
+Sources are maintained, saved, and retrievable at any time based on
+symbolic or numeric revision or date in the past.
+It is entirely up to \fBcvs\fP wrapper programs to provide for release
+environments and such.
+.PP
+The major advantage of \fBcvs\fP over the
+many other similar systems that have already been designed is the
+simplicity of \fBcvs\fP.
+\fBcvs\fP contains only three programs that do all the work of release
+and revision control, and two manually-maintained administrative
+files for each source repository.
+Of course, the deciding factor of any tool is whether people use it, and if
+they even \fIlike\fP to use it.
+At Prisma, \fBcvs\fP prevented members of the kernel
+group from killing each other.
+.NH
+Acknowledgements
+.PP
+Many thanks to Dick Grune at Vrije Universiteit in Amsterdam for his work
+on the original version of \fBcvs\fP and for making it available to the
+world.
+Thanks to Jeff Polk of Prisma for helping with the design of the module
+database, vendor branch support, and for writing the \fBcheckin\fP shell
+script.
+Thanks also to the entire software group at Prisma for taking the
+time to review the paper and correct my grammar.
+.NH
+References
+.IP [Bell] 12
+Bell Telephone Laboratories.
+\*QSource Code Control System User's Guide.\*U
+\fIUNIX System III Programmer's Manual\fP, October 1981.
+.IP [Courington] 12
+Courington, W.
+\fIThe Network Software Environment\fP,
+Sun Technical Report FE197-0, Sun Microsystems Inc, February 1989.
+.IP [Essick] 12
+Essick, Raymond B. and Robert Bruce Kolstad.
+\fINotesfile Reference Manual\fP,
+Department of Computer Science Technical Report #1081,
+University of Illinois at Urbana-Champaign, Urbana, Illinois,
+1982, p. 26.
+.IP [Glew] 12
+Glew, Andy.
+\*QBoxes, Links, and Parallel Trees:
+Elements of a Configuration Management System.\*U
+\fIWorkshop Proceedings of the Software Management Conference\fP, USENIX,
+New Orleans, April 1989.
+.IP [Grune] 12
+Grune, Dick.
+Distributed the original shell script version of \fBcvs\fP in the
+\fBcomp.sources.unix\fP volume 6 release in 1986.
+.IP [Honda] 12
+Honda, Masahiro and Terrence Miller.
+\*QSoftware Management Using a CASE Environment.\*U
+\fIWorkshop Proceedings of the Software Management Conference\fP, USENIX,
+New Orleans, April 1989.
+.IP [Mahler] 12
+Mahler, Alex and Andreas Lampen.
+\*QAn Integrated Toolset for Engineering Software Configurations.\*U
+\fIProceedings of the ACM SIGSOFT/SIGPLAN Software Engineering Symposium on
+Practical Software Development Environments\fP, ACM, Boston, November 1988.
+Described is the \fBshape\fP toolkit posted to the
+\fBcomp.sources.unix\fP newsgroup in the volume 19 release.
+.IP [Tichy] 12
+Tichy, Walter F.
+\*QDesign, Implementation, and Evaluation of a Revision Control System.\*U
+\fIProceedings of the 6th International Conference on Software
+Engineering\fP, IEEE, Tokyo, September 1982.
+.IP [Wall] 12
+Wall, Larry.
+The \fBpatch\fP program is an indispensable tool for applying a diff file
+to an original.
+Can be found on uunet.uu.net in ~ftp/pub/patch.tar.
diff --git a/gnu/usr.bin/cvs/doc/cvs.texinfo b/gnu/usr.bin/cvs/doc/cvs.texinfo
new file mode 100644
index 0000000..ef125f5
--- /dev/null
+++ b/gnu/usr.bin/cvs/doc/cvs.texinfo
@@ -0,0 +1,6931 @@
+\input texinfo @c -*-texinfo-*-
+@comment cvs.texinfo,v 1.6 1995/10/12 23:39:26 kfogel Exp
+@comment Documentation for CVS.
+@comment Copyright (C) 1992, 1993 Signum Support AB
+@comment Copyright (C) 1993 Free Software Foundation, Inc.
+
+@comment This file is part of the CVS distribution.
+
+@comment CVS is free software; you can redistribute it and/or modify
+@comment it under the terms of the GNU General Public License as published by
+@comment the Free Software Foundation; either version 1, or (at your option)
+@comment any later version.
+
+@comment CVS is distributed in the hope that it will be useful,
+@comment but WITHOUT ANY WARRANTY; without even the implied warranty of
+@comment MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+@comment GNU General Public License for more details.
+
+@comment You should have received a copy of the GNU General Public License
+@comment along with CVS; see the file COPYING. If not, write to
+@comment the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+@afourpaper
+@setfilename cvs.info
+@settitle CVS---Concurrent Versions System
+@setchapternewpage odd
+
+@c -- TODO list:
+@c -- Fix all lines that match "^@c -- "
+@c -- Document how CVS finds the binaries it executes.
+@c Things to include in the index:
+@c Finding RCS binaries
+@c Path to RCS binaries
+@c RCS, how CVS finds them
+@c s/RCS/diff/
+@c -- More on binary files
+
+@ifinfo
+Copyright @copyright{} 1992, 1993 Signum Support AB
+Copyright @copyright{} 1993, 1994 Free Software Foundation, Inc.
+
+Permission is granted to make and distribute verbatim copies of
+this manual provided the copyright notice and this permission notice
+are preserved on all copies.
+
+@ignore
+Permission is granted to process this file through Tex and print the
+results, provided the printed document carries copying permission
+notice identical to this one except for the removal of this paragraph
+(this paragraph not being relevant to the printed manual).
+
+@end ignore
+Permission is granted to copy and distribute modified versions of this
+manual under the conditions for verbatim copying, provided also that the
+section entitled ``GNU General Public License'' is included exactly as
+in the original, and provided that the entire resulting derived work is
+distributed under the terms of a permission notice identical to this one.
+
+Permission is granted to copy and distribute translations of this manual
+into another language, under the above conditions for modified versions,
+except that the section entitled ``GNU General Public License'' and
+this permission notice may be included in translations approved by the
+Free Software Foundation instead of in the original English.
+@end ifinfo
+
+@comment The titlepage section does not appear in the Info file.
+@titlepage
+@sp 4
+@comment The title is printed in a large font.
+@center @titlefont{Version Management}
+@sp
+@center @titlefont{with}
+@sp
+@center @titlefont{CVS}
+@sp 2
+@center for @sc{cvs} 1.6+
+@comment -release-
+@sp 3
+@center Per Cederqvist
+@sp 3
+@center last updated 12 Oct 1995
+@comment -date-
+
+@comment The following two commands start the copyright page
+@comment for the printed manual. This will not appear in the Info file.
+@page
+@vskip 0pt plus 1filll
+Copyright @copyright{} 1992, 1993 Signum Support AB
+
+Permission is granted to make and distribute verbatim copies of
+this manual provided the copyright notice and this permission notice
+are preserved on all copies.
+
+Permission is granted to copy and distribute modified versions of this
+manual under the conditions for verbatim copying, provided also that the
+section entitled ``GNU General Public License'' is included exactly as
+in the original, and provided that the entire resulting derived work is
+distributed under the terms of a permission notice identical to this one.
+
+Permission is granted to copy and distribute translations of this manual
+into another language, under the above conditions for modified versions,
+except that the section entitled ``GNU General Public License'' and
+this permission notice may be included in translations approved by the
+Free Software Foundation instead of in the original English.
+@end titlepage
+
+@comment ================================================================
+@comment The real text starts here
+@comment ================================================================
+
+@ifinfo
+@c ---------------------------------------------------------------------
+@node Top
+@top
+
+This info manual describes how to use and administer
+@sc{cvs} and is updated to release 1.4 or something
+similar.
+@end ifinfo
+
+@menu
+* Preface:: About this manual
+* What is CVS?:: What is CVS?
+* Basic concepts:: Basic concepts of revision management
+* A sample session:: A tour of basic CVS usage
+* Repository:: Where all your sources are stored
+* Starting a new project:: Starting a project with CVS
+* Multiple developers:: How CVS helps a group of developers
+* Branches:: Parallel development explained
+* Merging:: How to move changes between branches
+* Recursive behavior:: CVS descends directories
+* Adding files:: Adding files to a module
+* Removing files:: Removing files from a module
+* Tracking sources:: Tracking third-party sources
+* Moving files:: Moving and renaming files
+* Moving directories:: Moving and renaming directories
+* Keyword substitution:: CVS can include the revision inside the file
+* Revision management:: Policy questions for revision management
+* Invoking CVS:: Reference manual for CVS commands
+* Administrative files:: Reference manual for the Administrative files
+* Environment variables:: All environment variables which affect CVS
+* Troubleshooting:: Some tips when nothing works
+* Copying:: GNU GENERAL PUBLIC LICENSE
+* Index:: Index
+@end menu
+
+@c ---------------------------------------------------------------------
+@node Preface
+@unnumbered About this manual
+@cindex Preface
+@cindex About this manual
+
+Up to this point, one of the weakest parts of @sc{cvs}
+has been the documentation. @sc{cvs} is a complex
+program. Previous versions of the manual were written
+in the manual page format, which is not really well
+suited for such a complex program.
+
+When writing this manual, I had several goals in mind:
+
+@itemize @bullet
+@item
+No knowledge of @sc{rcs} should be necessary.
+
+@item
+No previous knowledge of revision control software
+should be necessary. All terms, such as @dfn{revision
+numbers}, @dfn{revision trees} and @dfn{merging} are
+explained as they are introduced.
+
+@item
+The manual should concentrate on the things @sc{cvs} users
+want to do, instead of what the @sc{cvs} commands can do.
+The first part of this manual leads you through things
+you might want to do while doing development, and
+introduces the relevant @sc{cvs} commands as they are
+needed.
+
+@item
+Information should be easy to find. In the reference
+manual in the appendices almost all information about
+every @sc{cvs} command is gathered together. There is also
+an extensive index, and a lot of cross references.
+@end itemize
+
+@cindex Signum Support
+@cindex Support, getting CVS support
+This manual was contributed by Signum Support AB in
+Sweden. Signum is yet another in the growing list of
+companies that support free software. You are free to
+copy both this manual and the @sc{cvs} program.
+@xref{Copying}, for the details. Signum Support offers
+@c -- Check this reference! It has been bogus in the past.
+support contracts and binary distribution for many
+programs, such as @sc{cvs}, @sc{gnu} Emacs, the
+@sc{gnu} C compiler and others. You can also buy
+hardcopies of this manual from us. Write to us for
+more information.
+
+@example
+Signum Support AB
+Box 2044
+S-580 02 Linkoping
+Sweden
+
+Email: info@@signum.se
+Phone: +46 (0)13 - 21 46 00
+Fax: +46 (0)13 - 21 47 00
+@end example
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@menu
+* Checklist::
+* Credits::
+* BUGS::
+@end menu
+
+@node Checklist
+@unnumberedsec Checklist for the impatient reader
+
+@sc{cvs} is a complex system. You will need to read
+the manual to be able to use all of its capabilities.
+There are dangers that can easily be avoided if you
+know about them, and this manual tries to warn you
+about them. This checklist is intended to help you
+avoid the dangers without reading the entire manual.
+If you intend to read the entire manual you can skip
+this table.
+
+@table @asis
+@item Binary files
+@sc{cvs} can handle binary files, but
+you must have @sc{rcs} release 5.5 or later and
+a release of @sc{gnu} diff that supports the @samp{-a}
+flag (release 1.15 and later are OK). You must also
+configure both @sc{rcs} and @sc{cvs} to handle binary
+files when you install them.
+
+Keword substitution can be a source of trouble with
+binary files. @xref{Keyword substitution}, for
+solutions.
+
+@item The @code{admin} command
+Uncareful use of the @code{admin} command can cause
+@sc{cvs} to cease working. @xref{admin}, before trying
+to use it.
+@end table
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@node Credits
+@unnumberedsec Credits
+
+@cindex Contributors (manual)
+@cindex Credits (manual)
+Roland Pesch, Cygnus Support <@t{pesch@@cygnus.com}>
+wrote the manual pages which were distributed with
+@sc{cvs} 1.3. Appendix A and B contain much text that
+was extracted from them. He also read an early draft
+of this manual and contributed many ideas and
+corrections.
+
+The mailing-list @code{info-cvs} is sometimes
+informative. I have included information from postings
+made by the following persons:
+David G. Grubbs <@t{dgg@@think.com}>.
+
+Some text has been extracted from the man pages for
+@sc{rcs}.
+
+The @sc{cvs} @sc{faq} (@pxref{What is CVS?}) by David
+G. Grubbs has been used as a check-list to make sure
+that this manual is as complete as possible. (This
+manual does however not include all of the material in
+the @sc{faq}). The @sc{faq} contains a lot of useful
+information.
+
+In addition, the following persons have helped by
+telling me about mistakes I've made:
+Roxanne Brunskill <@t{rbrunski@@datap.ca}>,
+Kathy Dyer <@t{dyer@@phoenix.ocf.llnl.gov}>,
+Karl Pingle <@t{pingle@@acuson.com}>,
+Thomas A Peterson <@t{tap@@src.honeywell.com}>,
+Inge Wallin <@t{ingwa@@signum.se}>,
+Dirk Koschuetzki <@t{koschuet@@fmi.uni-passau.de}>
+and Michael Brown <@t{brown@@wi.extrel.com}>.
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@node BUGS
+@unnumberedsec BUGS
+
+@cindex Bugs, known in this manual
+@cindex Known bugs in this manual
+This manual is known to have room for improvement.
+Here is a list of known deficiencies:
+
+@itemize @bullet
+@item
+In the examples, the output from @sc{cvs} is sometimes
+displayed, sometimes not.
+
+@item
+The input that you are supposed to type in the examples
+should have a different font than the output from the
+computer.
+
+@item
+This manual should be clearer about what file
+permissions you should set up in the repository, and
+about setuid/setgid.
+
+@item
+Some of the chapters are not yet complete. They are
+noted by comments in the @file{cvs.texinfo} file.
+
+@item
+@cindex Reporting bugs (manual)
+@cindex Bugs, reporting (manual)
+@cindex Errors, reporting (manual)
+This list is not complete. If you notice any error,
+omission, or something that is unclear, please send
+mail to @t{bug-cvs@@prep.ai.mit.edu}.
+@end itemize
+
+I hope that you will find this manual useful, despite
+the above-mentioned shortcomings.
+
+@flushright
+
+Linkoping, October 1993
+Per Cederqvist
+@end flushright
+
+@c ---------------------------------------------------------------------
+@node What is CVS?
+@chapter What is CVS?
+@cindex What is CVS?
+@cindex Introduction to CVS
+@cindex CVS, introduction to
+
+@sc{cvs} is a version control system. Using it, you can
+record the history of your source files.
+
+@c -- ///
+@c -- ///Those who cannot remember the past are condemned to repeat it.
+@c -- /// -- George Santayana
+@c -- //////
+
+@c -- Insert history quote here!
+For example, bugs sometimes creep in when
+software is modified, and you might not detect the bug
+until a long time after you make the modification.
+With @sc{cvs}, you can easily retrieve old versions to see
+exactly which change caused the bug. This can
+sometimes be a big help.
+
+You could of course save every version of every file
+you have ever created. This would
+however waste an enormous amount of disk space. @sc{cvs}
+stores all the versions of a file in a single file in a
+clever way that only stores the differences between
+versions.
+
+@sc{cvs} also helps you if you are part of a group of people working
+on the same project. It is all too easy to overwrite
+each others' changes unless you are extremely careful.
+Some editors, like @sc{gnu} Emacs, try to make sure that
+the same file is never modified by two people at the
+same time. Unfortunately, if someone is using another
+editor, that safeguard will not work. @sc{cvs} solves this problem
+by insulating the different developers from each other. Every
+developer works in his own directory, and @sc{cvs} merges
+the work when each developer is done.
+
+@cindex History of CVS
+@cindex CVS, history of
+@cindex Credits (CVS program)
+@cindex Contributors (CVS program)
+@sc{cvs} started out as a bunch of shell scripts written by
+Dick Grune, posted to @code{comp.sources.unix} in the volume 6
+release of December, 1986. While no actual code from
+these shell scripts is present in the current version
+of @sc{cvs} much of the @sc{cvs} conflict resolution algorithms
+come from them.
+
+In April, 1989, Brian Berliner designed and coded @sc{cvs}.
+Jeff Polk later helped Brian with the design of the @sc{cvs}
+module and vendor branch support.
+
+@cindex Source, getting CVS source
+You can get @sc{cvs} via anonymous ftp from a number of
+sites, for instance @t{prep.ai.mit.edu} in
+@file{pub/gnu}.
+
+@cindex Mailing list
+@cindex List, mailing list
+There is a mailing list for @sc{cvs} where bug reports
+can be sent, questions can be asked, an FAQ is posted,
+and discussion about future enhancements to @sc{cvs}
+take place. To submit a message to the list, write to
+<@t{info-cvs@@prep.ai.mit.edu}>. To subscribe or
+unsubscribe, write to
+<@t{info-cvs-request@@prep.ai.mit.edu}>. Please be
+specific about your email address.
+
+Work is in progress on creating a newsgroup for
+@sc{cvs}-related topics. It will appear somewhere
+under the @samp{gnu.} hierarchy. Gateways to and from
+the mailing list will be set up.
+@c -- Newsgroup? gnu.cvs.info?
+
+@cindex FTP site
+@cindex Patches to CVS
+@cindex CVS FTP site
+@cindex Fixes to CVS
+@cindex FAQ
+@cindex CVS FAQ
+The @sc{ftp} site @t{think.com} has some @sc{cvs}
+material in the @file{/pub/cvs} subdirectory.
+Currently (late summer 1993) it contains an excellent
+@sc{faq} (Frequently Asked Questions, with answers),
+and an improved (but unofficial) version of @sc{cvs}.
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@unnumberedsec CVS is not@dots{}
+
+@sc{cvs} can do a lot of things for you, but it does
+not try to be everything for everyone.
+
+@table @asis
+@item @sc{cvs} is not a build system.
+
+Though the structure of your repository and modules
+file interact with your build system
+(e.g. @file{Makefile}s), they are essentially
+independent.
+
+@sc{cvs} does not dictate how you build anything. It
+merely stores files for retrieval in a tree structure
+you devise.
+
+@sc{cvs} does not dictate how to use disk space in the
+checked out working directories. If you write your
+@file{Makefile}s or scripts in every directory so they
+have to know the relative positions of everything else,
+you wind up requiring the entire repository to be
+checked out. That's simply bad planning.
+
+If you modularize your work, and construct a build
+system that will share files (via links, mounts,
+@code{VPATH} in @file{Makefile}s, etc.), you can
+arrange your disk usage however you like.
+
+But you have to remember that @emph{any} such system is
+a lot of work to construct and maintain. @sc{cvs} does
+not address the issues involved. You must use your
+brain and a collection of other tools to provide a
+build scheme to match your plans.
+
+Of course, you should place the tools created to
+support such a build system (scripts, @file{Makefile}s,
+etc) under @sc{cvs}.
+
+@item @sc{cvs} is not a substitute for management.
+
+Your managers and project leaders are expected to talk
+to you frequently enough to make certain you are aware
+of schedules, merge points, branch names and release
+dates. If they don't, @sc{cvs} can't help.
+
+@sc{cvs} is an instrument for making sources dance to
+your tune. But you are the piper and the composer. No
+instrument plays itself or writes its own music.
+
+@item @sc{cvs} is not a substitute for developer communication.
+
+When faced with conflicts within a single file, most
+developers manage to resolve them without too much
+effort. But a more general definition of ``conflict''
+includes problems too difficult to solve without
+communication between developers.
+
+@sc{cvs} cannot determine when simultaneous changes
+within a single file, or across a whole collection of
+files, will logically conflict with one another. Its
+concept of a @dfn{conflict} is purely textual, arising
+when two changes to the same base file are near enough
+to spook the merge (i.e. @code{diff3}) command.
+
+@sc{cvs} does not claim to help at all in figuring out
+non-textual or distributed conflicts in program logic.
+
+For example: Say you change the arguments to function
+@code{X} defined in file @file{A}. At the same time,
+someone edits file @file{B}, adding new calls to
+function @code{X} using the old arguments. You are
+outside the realm of @sc{cvs}'s competence.
+
+Acquire the habit of reading specs and talking to your
+peers.
+
+
+@item @sc{cvs} is not a configuration management system.
+
+@sc{cvs} is a source control system. The phrase
+``configuration management'' is a marketing term, not
+an industry-recognized set of functions.
+
+A true ``configuration management system'' would contain
+elements of the following:
+
+@itemize @bullet
+@item Source control.
+@item Dependency tracking.
+@item Build systems (i.e. What to build and how to find
+things during a build. What is shared? What is local?)
+@item Bug tracking.
+@item Automated Testing procedures.
+@item Release Engineering documentation and procedures.
+@item Tape Construction.
+@item Customer Installation.
+@item A way for users to run different versions of the same
+software on the same host at the same time.
+@end itemize
+
+@sc{cvs} provides only the first.
+@end table
+
+This section is taken from release 2.3 of the @sc{cvs}
+@sc{faq}.
+
+@c ---------------------------------------------------------------------
+@node Basic concepts
+@chapter Basic concepts
+@cindex Modules (intro)
+@cindex Repository (intro)
+
+@sc{cvs} stores all files in a centralized
+@dfn{repository}: a directory (such as
+@file{/usr/local/cvsroot} or
+@file{user@@remotehost:/usr/local/cvsroot}) which is
+populated with a hierarchy of files and directories.
+(@pxref{Remote repositories} for information about
+keeping the repository on a remote machine.)
+
+Normally, you never access any of the files in the
+repository directly. Instead, you use @sc{cvs}
+commands to get your own copy of the files, and then
+work on that copy. When you've finished a set of
+changes, you check (or @dfn{commit}) them back into the
+repository.
+
+The files in the repository are organized in
+@dfn{modules}. Each module is made up of one or more
+files, and can include files from several directories.
+A typical usage is to define one module per project.
+
+@menu
+* Revision numbers:: The meaning of a revision number
+* Versions revisions releases:: Terminology used in this manual
+@end menu
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@node Revision numbers
+@section Revision numbers
+@cindex Revision numbers
+@cindex Revision tree
+@cindex Linear development
+@cindex Number, revision-
+@cindex Decimal revision number
+@cindex Main trunk (intro)
+@cindex Branch number
+@cindex Number, branch
+
+Each version of a file has a unique @dfn{revision
+number}. Revision numbers look like @samp{1.1},
+@samp{1.2}, @samp{1.3.2.2} or even @samp{1.3.2.2.4.5}.
+A revision number always has an even number of
+period-separated decimal integers. By default revision
+1.1 is the first revision of a file. Each successive
+revision is given a new number by increasing the
+rightmost number by one. The following figure displays
+a few revisions, with newer revisions to the right.
+
+@example
+ +-----+ +-----+ +-----+ +-----+ +-----+
+ ! 1.1 !----! 1.2 !----! 1.3 !----! 1.4 !----! 1.5 !
+ +-----+ +-----+ +-----+ +-----+ +-----+
+@end example
+
+@sc{cvs} is not limited to linear development. The
+@dfn{revision tree} can be split into @dfn{branches},
+where each branch is a self-maintained line of
+development. Changes made on one branch can easily be
+moved back to the main trunk.
+
+Each branch has a @dfn{branch number}, consisting of an
+odd number of period-separated decimal integers. The
+branch number is created by appending an integer to the
+revision number where the corresponding branch forked
+off. Having branch numbers allows more than one branch
+to be forked off from a certain revision.
+
+@need 3500
+All revisions on a branch have revision numbers formed
+by appending an ordinal number to the branch number.
+The following figure illustrates branching with an
+example.
+
+@example
+@group
+ +-------------+
+ Branch 1.2.2.3.2 -> ! 1.2.2.3.2.1 !
+ / +-------------+
+ /
+ /
+ +---------+ +---------+ +---------+ +---------+
+Branch 1.2.2 -> _! 1.2.2.1 !----! 1.2.2.2 !----! 1.2.2.3 !----! 1.2.2.4 !
+ / +---------+ +---------+ +---------+ +---------+
+ /
+ /
++-----+ +-----+ +-----+ +-----+ +-----+
+! 1.1 !----! 1.2 !----! 1.3 !----! 1.4 !----! 1.5 ! <- The main trunk
++-----+ +-----+ +-----+ +-----+ +-----+
+ !
+ !
+ ! +---------+ +---------+ +---------+
+Branch 1.2.4 -> +---! 1.2.4.1 !----! 1.2.4.2 !----! 1.2.4.3 !
+ +---------+ +---------+ +---------+
+
+@end group
+@end example
+
+@c -- However, at least for me the figure is not enough. I suggest more
+@c -- text to accompany it. "A picture is worth a thousand words", so you
+@c -- have to make sure the reader notices the couple of hundred words
+@c -- *you* had in mind more than the others!
+
+@c -- Why an even number of segments? This section implies that this is
+@c -- how the main trunk is distinguished from branch roots, but you never
+@c -- explicitly say that this is the purpose of the [by itself rather
+@c -- surprising] restriction to an even number of segments.
+
+The exact details of how the branch number is
+constructed is not something you normally need to be
+concerned about, but here is how it works: When
+@sc{cvs} creates a branch number it picks the first
+unused even integer, starting with 2. So when you want
+to create a branch from revision 6.4 it will be
+numbered 6.4.2. All branch numbers ending in a zero
+(such as 6.4.0) are used internally by @sc{cvs}
+(@pxref{Magic branch numbers}). The branch 1.1.1 has a
+special meaning. @xref{Tracking sources}.
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@node Versions revisions releases
+@section Versions, revisions and releases
+@cindex Revisions, versions and releases
+@cindex Versions, revisions and releases
+@cindex Releases, revisions and versions
+
+A file can have several versions, as described above.
+Likewise, a software product can have several versions.
+A software product is often given a version number such
+as @samp{4.1.1}.
+
+Versions in the first sense are called @dfn{revisions}
+in this document, and versions in the second sense are
+called @dfn{releases}. To avoid confusion, the word
+@dfn{version} is almost never used in this document.
+
+@c ---------------------------------------------------------------------
+@node A sample session
+@chapter A sample session
+@cindex A sample session
+@cindex Example of a work-session
+@cindex Getting started
+@cindex Work-session, example of
+@cindex tc, Trivial Compiler (example)
+@cindex Trivial Compiler (example)
+
+This section describes a typical work-session using
+@sc{cvs}. It assumes that a repository is set up
+(@pxref{Repository}).
+
+Suppose you are working on a simple compiler. The source
+consists of a handful of C files and a @file{Makefile}.
+The compiler is called @samp{tc} (Trivial Compiler),
+and the repository is set up so that there is a module
+called @samp{tc}.
+
+@menu
+* Getting the source:: Creating a workspace
+* Committing your changes:: Making your work available to others
+* Cleaning up:: Cleaning up
+* Viewing differences:: Viewing differences
+@end menu
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@node Getting the source
+@section Getting the source
+@cindex Getting the source
+@cindex Checking out source
+@cindex Fetching source
+@cindex Source, getting from CVS
+@cindex Checkout, example
+
+The first thing you must do is to get your own working copy of the
+source for @samp{tc}. For this, you use the @code{checkout} command:
+
+@example
+$ cvs checkout tc
+@end example
+
+@noindent
+This will create a new directory called @file{tc} and populate it with
+the source files.
+
+@example
+$ cd tc
+$ ls tc
+CVS Makefile backend.c driver.c frontend.c parser.c
+@end example
+
+The @file{CVS} directory is used internally by
+@sc{cvs}. Normally, you should not modify or remove
+any of the files in it.
+
+You start your favorite editor, hack away at @file{backend.c}, and a couple
+of hours later you have added an optimization pass to the compiler.
+A note to @sc{rcs} and @sc{sccs} users: There is no need to lock the files that
+you want to edit. @xref{Multiple developers} for an explanation.
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@node Committing your changes
+@section Committing your changes
+@cindex Committing changes
+@cindex Log message entry
+@cindex CVSEDITOR, environment variable
+@cindex EDITOR, environment variable
+
+When you have checked that the compiler is still compilable you decide
+to make a new version of @file{backend.c}.
+
+@example
+$ cvs commit backend.c
+@end example
+
+@noindent
+@sc{cvs} starts an editor, to allow you to enter a log
+message. You type in ``Added an optimization pass.'',
+save the temporary file, and exit the editor.
+
+The environment variable @code{$CVSEDITOR} determines
+which editor is started. If @code{$CVSEDITOR} is not
+set, then if the environment variable @code{$EDITOR} is
+set, it will be used. If both @code{$CVSEDITOR} and
+@code{$EDITOR} are not set then the editor defaults to
+@code{vi}. If you want to avoid the overhead of
+starting an editor you can specify the log message on
+the command line using the @samp{-m} flag instead, like
+this:
+
+@example
+$ cvs commit -m "Added an optimization pass" backend.c
+@end example
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@node Cleaning up
+@section Cleaning up
+@cindex Cleaning up
+@cindex Working copy, removing
+@cindex Removing your working copy
+@cindex Releasing your working copy
+
+Before you turn to other tasks you decide to remove your working copy of
+tc. One acceptable way to do that is of course
+
+@example
+$ cd ..
+$ rm -r tc
+@end example
+
+@noindent
+but a better way is to use the @code{release} command (@pxref{release}):
+
+@example
+$ cd ..
+$ cvs release -d tc
+M driver.c
+? tc
+You have [1] altered files in this repository.
+Are you sure you want to release (and delete) module `tc': n
+** `release' aborted by user choice.
+@end example
+
+The @code{release} command checks that all your modifications have been
+committed. If history logging is enabled it also makes a note in the
+history file. @xref{history file}.
+
+When you use the @samp{-d} flag with @code{release}, it
+also removes your working copy.
+
+In the example above, the @code{release} command wrote a couple of lines
+of output. @samp{? tc} means that the file @file{tc} is unknown to @sc{cvs}.
+That is nothing to worry about: @file{tc} is the executable compiler,
+and it should not be stored in the repository. @xref{cvsignore},
+for information about how to make that warning go away.
+@xref{release output}, for a complete explanation of
+all possible output from @code{release}.
+
+@samp{M driver.c} is more serious. It means that the
+file @file{driver.c} has been modified since it was
+checked out.
+
+The @code{release} command always finishes by telling
+you how many modified files you have in your working
+copy of the sources, and then asks you for confirmation
+before deleting any files or making any note in the
+history file.
+
+You decide to play it safe and answer @kbd{n @key{RET}}
+when @code{release} asks for confirmation.
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@node Viewing differences
+@section Viewing differences
+@cindex Viewing differences
+@cindex Diff
+
+You do not remember modifying @file{driver.c}, so you want to see what
+has happened to that file.
+
+@example
+$ cd tc
+$ cvs diff driver.c
+@end example
+
+This command runs @code{diff} to compare the version of @file{driver.c}
+that you checked out with your working copy. When you see the output
+you remember that you added a command line option that enabled the
+optimization pass. You check it in, and release the module.
+
+@example
+$ cvs commit -m "Added an optimization pass" driver.c
+Checking in driver.c;
+/usr/local/cvsroot/tc/driver.c,v <-- driver.c
+new revision: 1.2; previous revision: 1.1
+done
+$ cd ..
+$ cvs release -d tc
+? tc
+You have [0] altered files in this repository.
+Are you sure you want to release (and delete) module `tc': y
+@end example
+
+@c ---------------------------------------------------------------------
+@node Repository
+@chapter The Repository
+@cindex Repository, example
+@cindex Layout of repository
+@cindex Typical repository
+@cindex CVSROOT, environment variable
+@cindex .profile
+@cindex .cshrc
+@cindex .tcshrc
+@cindex .bashrc
+@cindex /usr/local/cvsroot
+@cindex cvsroot
+
+Figure 3 below shows a typical setup of a repository.
+Only directories are shown below.
+
+@example
+@t{/usr}
+ |
+ +--@t{local}
+ | |
+ | +--@t{cvsroot}
+ | | |
+ | | +--@t{CVSROOT}
+ | (administrative files)
+ |
+ +--@t{gnu}
+ | |
+ | +--@t{diff}
+ | | (source code to @sc{gnu} diff)
+ | |
+ | +--@t{rcs}
+ | | (source code to @sc{rcs})
+ | |
+ | +--@t{cvs}
+ | (source code to @sc{cvs})
+ |
+ +--@t{yoyodyne}
+ |
+ +--@t{tc}
+ | |
+ | +--@t{man}
+ | |
+ | +--@t{testing}
+ |
+ +--(other Yoyodyne software)
+@end example
+
+
+There are a couple of different ways to tell @sc{cvs}
+where to find the repository. You can name the
+repository on the command line explicitly, with the
+@code{-d} (for "directory") option:
+
+@example
+cvs -d /usr/local/cvsroot checkout yoyodyne/tc
+@end example
+
+ Or you can set the @code{$CVSROOT} environment
+variable to an absolute path to the root of the
+repository, @file{/usr/local/cvsroot} in this example.
+To set @code{$CVSROOT}, all @code{csh} and @code{tcsh}
+users should have this line in their @file{.cshrc} or
+@file{.tcshrc} files:
+
+@example
+setenv CVSROOT /usr/local/cvsroot
+@end example
+
+@noindent
+@code{sh} and @code{bash} users should instead have these lines in their
+@file{.profile} or @file{.bashrc}:
+
+@example
+CVSROOT=/usr/local/cvsroot
+export CVSROOT
+@end example
+
+ A repository specified with @code{-d} will
+override the @code{$CVSROOT} environment variable.
+Once you've checked a working copy out from the
+repository, it will remember where its repository is
+(the information is recorded in the
+@file{CVS/Root} file in the working copy).
+
+The @code{-d} option and the @file{CVS/Root} file
+both override the @code{$CVSROOT} environment variable;
+however, @sc{CVS} will complain if the @file{-d}
+argument and the @file{CVS/Root} file disagree.
+
+There is nothing magical about the name
+@file{/usr/local/cvsroot}. You can choose to place the
+repository anywhere you like.
+@xref{Remote repositories} to learn how the repository can be on a
+different machine than your working copy of the sources.
+
+The repository is split in two parts. @file{$CVSROOT/CVSROOT} contains
+administrative files for @sc{cvs}. The other directories contain the actual
+user-defined modules.
+
+@menu
+* User modules:: The structure of the repository
+* Intro administrative files:: Defining modules
+* Multiple repositories:: Multiple repositories
+* Creating a repository:: Creating a repository
+* Remote repositories:: Accessing repositories on remote machines
+@end menu
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@node User modules
+@section User modules
+@cindex User modules
+@cindex Repository, user parts
+
+@example
+ @code{$CVSROOT}
+ |
+ +--@t{yoyodyne}
+ | |
+ | +--@t{tc}
+ | | |
+ +--@t{Makefile,v}
+ +--@t{backend.c,v}
+ +--@t{driver.c,v}
+ +--@t{frontend.c,v}
+ +--@t{parser.c,v}
+ +--@t{man}
+ | |
+ | +--@t{tc.1,v}
+ |
+ +--@t{testing}
+ |
+ +--@t{testpgm.t,v}
+ +--@t{test2.t,v}
+@end example
+
+@cindex History files
+@cindex RCS history files
+@cindex RCS, CVS uses RCS
+The figure above shows the contents of the @samp{tc}
+module inside the repository. As you can see all file
+names end in @samp{,v}. The files are @dfn{history
+files}. They contain, among other things, enough
+information to recreate any revision of the file, a log
+of all commit messages and the user-name of the person
+who committed the revision. @sc{cvs} uses the
+facilities of @sc{rcs}, a simpler version control
+system, to maintain these files. For a full
+description of the file format, see the @code{man} page
+@cite{rcsfile(5)}.
+@c -- Use this format for all references to man pages,
+@c -- or use something better!
+
+@menu
+* File permissions:: File permissions
+@end menu
+
+@c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
+@node File permissions
+@subsection File permissions
+@c -- Move this to @node Setting up
+@cindex Security
+@cindex File permissions
+@cindex Group
+All @samp{,v} files are created read-only, and you
+should not change the permission of those files. The
+directories inside the repository should be writable by
+the persons that have permission to modify the files in
+each directory. This normally means that you must
+create a UNIX group (see group(5)) consisting of the
+persons that are to edit the files in a project, and
+set up the repository so that it is that group that
+owns the directory.
+
+This means that you can only control access to files on
+a per-directory basis.
+
+@sc{cvs} tries to set up reasonable file permissions
+for new directories that are added inside the tree, but
+you must fix the permissions manually when a new
+directory should have different permissions than its
+parent directory.
+
+@cindex setuid
+@cindex setgid
+Since @sc{cvs} was not written to be run setuid, it is
+unsafe to try to run it setuid. You cannot use the
+setuid features of @sc{rcs} together with @sc{cvs}.
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@node Intro administrative files
+@section The administrative files
+@cindex Administrative files (intro)
+@cindex Modules file
+@cindex CVSROOT, module name
+@cindex Defining modules (intro)
+
+The directory @file{$CVSROOT/CVSROOT} contains some @dfn{administrative
+files}. @xref{Administrative files}, for a complete description.
+You can use @sc{cvs} without any of these files, but
+some commands work better when at least the
+@file{modules} file is properly set up.
+
+The most important of these files is the @file{modules}
+file. It defines all modules in the repository. This
+is a sample @file{modules} file.
+
+@example
+CVSROOT -i mkmodules CVSROOT
+modules -i mkmodules CVSROOT modules
+cvs gnu/cvs
+rcs gnu/rcs
+diff gnu/diff
+tc yoyodyne/tc
+@end example
+
+The @file{modules} file is line oriented. In its simplest form each
+line contains the name of the module, whitespace, and the directory
+where the module resides. The directory is a path relative to
+@code{$CVSROOT}. The last for lines in the example
+above are examples of such lines.
+
+@cindex mkmodules
+Each module definition can contain options. The @samp{-i mkmodules} is
+an example of an option. It arranges for @sc{cvs} to run the
+@code{mkmodules} program whenever any file in the module CVSROOT is
+committed. That program is responsible for checking out read-only
+copies from the @sc{rcs} @dfn{history files} of all the administrative files.
+These read-only copies are used internally by @sc{cvs}. You
+should never edit them directly.
+
+The line that defines the module called @samp{modules}
+uses features that are not explained here.
+@xref{modules}, for a full explanation of all the
+available features.
+
+@subsection Editing administrative files
+@cindex Editing administrative files
+@cindex Administrative files, editing them
+
+You edit the administrative files in the same way that you would edit
+any other module. Use @samp{cvs checkout CVSROOT} to get a working
+copy, edit it, and commit your changes in the normal way.
+
+It is possible to commit an erroneous administrative
+file. You can often fix the error and check in a new
+revision, but sometimes a particularly bad error in the
+administrative file makes it impossible to commit new
+revisions.
+@c @xref{Bad administrative files} for a hint
+@c about how to solve such situations.
+@c -- administrative file checking--
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@node Multiple repositories
+@section Multiple repositories
+@cindex Multiple repositories
+@cindex Repositories, multiple
+@cindex Many repositories
+@cindex Parallel repositories
+@cindex Disjoint repositories
+@cindex CVSROOT, multiple repositories
+
+In some situations it is a good idea to have more than
+one repository, for instance if you have two
+development groups that work on separate projects
+without sharing any code. All you have to do to have
+several repositories is to specify the appropriate
+repository, using the @code{CVSROOT} environment
+variable, the @samp{-d} option to @sc{cvs}, or (once
+you have checked out a working directories) by
+simply allowing @sc{cvs} to use the repository that was
+used to check out the working directory (@pxref{Repository}).
+
+Notwithstanding, it can be confusing to have two or
+more repositories.
+
+None of the examples in this manual show multiple
+repositories.
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@node Creating a repository
+@section Creating a repository
+@c -- Well, how do you do?
+
+See the instructions in the @file{INSTALL} file in the
+@sc{cvs} distribution.
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@node Remote repositories
+@section Remote repositories
+@cindex Repositories, remote
+@cindex Remote repositories
+@cindex Client/Server Operation
+
+The repository and your working copy of the sources can
+be on different machines. To access a remote
+repository, use the following format for its name:
+
+@example
+ user@@hostname:/path/to/repository
+@end example
+
+(The @file{user@@} can be omitted if it's the same on
+both the local and remote hosts.)
+
+The details of exactly what needs to be set up depends
+on how you are connecting to the server.
+
+@menu
+* Connecting via rsh:: Using the rsh program to connect
+* Kerberos authenticated:: Direct connections with kerberos
+@end menu
+
+@node Connecting via rsh
+@subsection Connecting with rsh
+
+@cindex rsh
+CVS uses the @file{rsh} protocol to perform these
+operations, so the remote user host needs to have a
+@file{.rhosts} file which grants access to the local
+user.
+
+For example, suppose you are the user @file{mozart} on
+the local machine @file{anklet.grunge.com}, and the
+server machine is @file{chainsaw.brickyard.com}. On
+chainsaw, put the following line into the file
+@file{.rhosts} in @file{bach}'s home directory:
+
+@example
+anklet.grunge.com mozart
+@end example
+
+Then test that rsh is working with
+
+@example
+rsh -l bach chainsaw.brickyard.com echo $PATH
+@end example
+
+@cindex CVS_SERVER
+Next you have to make sure that rsh will be able to
+find the server. Make sure that the path which rsh
+printed in the above example includes the directory
+containing a program named @code{cvs} which is the
+server. You need to set the path in @file{.bashrc},
+@file{.cshrc}, etc., not @file{.login} or
+@file{.profile}. Alternately, you can set the
+environment variable @code{CVS_SERVER} on the client
+machine to the filename of the server you want to use,
+for example @file{/usr/local/bin/cvs-1.6}.
+
+There is no need to edit @code{inetd.conf} or start a
+@sc{cvs} server daemon.
+
+Continuing our example, supposing you want to access
+the module @file{foo} in the repository
+@file{/usr/local/cvsroot/}, on machine
+@file{chainsaw.brickyard.com}, you are ready to go:
+
+@example
+cvs -d bach@@chainsaw.brickyard.com:/user/local/cvsroot checkout foo
+@end example
+
+@node Kerberos authenticated
+@subsection Direct connection with kerberos
+
+@cindex kerberos
+The main disadvantage of using rsh is that all the data
+needs to pass through additional programs, so it may be
+slower. So if you have kerberos installed you can
+connect via a direct @sc{tcp} connection,
+authenticating with kerberos (note that the data
+transmitted is @emph{not} encrypted).
+
+To do this, @sc{cvs} needs to be compiled with kerberos
+support; when configuring @sc{cvs} it tries to detect
+whether kerberos is present or you can use the
+@file{--with-krb4} flag to configure.
+
+@cindex CVS_CLIENT_PORT
+You need to edit @code{inetd.conf} on the server
+machine to run @code{cvs kserver}. The client uses
+port 1999 by default; if you want to use another port
+specify it in the @code{CVS_CLIENT_PORT} environment
+variable on the client. Set @code{CVS_CLIENT_PORT} to
+@samp{-1} to force an rsh connection.
+
+@cindex kinit
+When you want to use @sc{cvs}, get a ticket in the
+usual way (generally @code{kinit}); it must be a ticket
+which allows you to log into the server machine. Then
+you are ready to go:
+
+@example
+cvs -d chainsaw.brickyard.com:/user/local/cvsroot checkout foo
+@end example
+
+If @sc{cvs} fails to connect, it will fall back to
+trying rsh.
+
+@c ---------------------------------------------------------------------
+@node Starting a new project
+@chapter Starting a project with CVS
+@cindex Starting a project with CVS
+@cindex Creating a project
+
+@comment --moduledb--
+Since @sc{cvs} 1.x is bad at renaming files and moving
+them between directories, the first thing you do when
+you start a new project should be to think through your
+file organization. It is not impossible---just
+awkward---to rename or move files.
+@xref{Moving files}.
+
+What to do next depends on the situation at hand.
+
+@menu
+* Setting up the files:: Getting the files into the repository
+* Defining the module:: How to make a module of the files
+@end menu
+@c -- File permissions!
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@node Setting up the files
+@section Setting up the files
+
+The first step is to create the files inside the repository. This can
+be done in a couple of different ways.
+
+@c -- The contributed scripts
+@menu
+* From files:: This method is useful with old projects
+ where files already exists.
+
+* From scratch:: Creating a module from scratch.
+@end menu
+
+@c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
+@node From files
+@subsection Creating a module from a number of files
+@cindex Importing files
+
+When you begin using @sc{cvs}, you will probably already have several
+projects that can be
+put under @sc{cvs} control. In these cases the easiest way is to use the
+@code{import} command. An example is probably the easiest way to
+explain how to use it. If the files you want to install in
+@sc{cvs} reside in @file{@var{dir}}, and you want them to appear in the
+repository as @file{$CVSROOT/yoyodyne/@var{dir}}, you can do this:
+
+@example
+$ cd @var{dir}
+$ cvs import -m "Imported sources" yoyodyne/@var{dir} yoyo start
+@end example
+
+Unless you supply a log message with the @samp{-m}
+flag, @sc{cvs} starts an editor and prompts for a
+message. The string @samp{yoyo} is a @dfn{vendor tag},
+and @samp{start} is a @dfn{release tag}. They may fill
+no purpose in this context, but since @sc{cvs} requires
+them they must be present. @xref{Tracking sources}, for
+more information about them.
+
+You can now verify that it worked, and remove your
+original source directory.
+
+@example
+$ cd ..
+$ mv @var{dir} @var{dir}.orig
+$ cvs checkout yoyodyne/@var{dir} # @r{Explanation below}
+$ ls -R yoyodyne
+$ rm -r @var{dir}.orig
+@end example
+
+@noindent
+Erasing the original sources is a good idea, to make sure that you do
+not accidentally edit them in @var{dir}, bypassing @sc{cvs}.
+Of course, it would be wise to make sure that you have
+a backup of the sources before you remove them.
+
+The @code{checkout} command can either take a module
+name as argument (as it has done in all previous
+examples) or a path name relative to @code{$CVSROOT},
+as it did in the example above.
+
+It is a good idea to check that the permissions
+@sc{cvs} sets on the directories inside @samp{$CVSROOT}
+are reasonable, and that they belong to the proper
+groups. @xref{File permissions}.
+
+@c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
+@node From scratch
+@subsection Creating a module from scratch
+
+For a new project, the easiest thing to do is probably
+to create an empty directory structure, like this:
+
+@example
+$ mkdir tc
+$ mkdir tc/man
+$ mkdir tc/testing
+@end example
+
+After that, you use the @code{import} command to create
+the corresponding (empty) directory structure inside
+the repository:
+
+@example
+$ cd tc
+$ cvs import -m "Created directory structure" yoyodyne/@var{dir} yoyo start
+@end example
+
+Then, use @code{add} to add files (and new directories)
+as they appear.
+
+Check that the permissions @sc{cvs} sets on the
+directories inside @samp{$CVSROOT} are reasonable.
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@node Defining the module
+@section Defining the module
+@cindex Defining a module
+@cindex Editing the modules file
+@cindex Module, defining
+@cindex Modules file, changing
+
+The next step is to define the module in the
+@file{modules} file. This is not strictly necessary,
+but modules can be convenient in grouping together
+related files and directories.
+
+In simple cases these steps are sufficient to define a module.
+
+@enumerate
+@item
+Get a working copy of the modules file.
+
+@example
+$ cvs checkout modules
+$ cd modules
+@end example
+
+@item
+Edit the file and insert a line that defines the module. @xref{Intro
+administrative files}, for an introduction. @xref{modules}, for a full
+description of the modules file. You can use the
+following line to define the module @samp{tc}:
+
+@example
+tc yoyodyne/tc
+@end example
+
+@item
+Commit your changes to the modules file.
+
+@example
+$ cvs commit -m "Added the tc module." modules
+@end example
+
+@item
+Release the modules module.
+
+@example
+$ cd ..
+$ cvs release -d modules
+@end example
+@end enumerate
+
+@c ---------------------------------------------------------------------
+@node Multiple developers
+@chapter Multiple developers
+@cindex Multiple developers
+@cindex Team of developers
+@cindex File locking
+@cindex Locking files
+@cindex Working copy
+
+When more than one person works on a software project
+things often get complicated. Often, two people try to
+edit the same file simultaneously. Some other version
+control systems (including @sc{rcs} and @sc{sccs})
+try to solve that particular problem by introducing
+@dfn{file locking}, so that only one person can edit
+each file at a time. Unfortunately, file locking can
+be very counter-productive. If two persons want
+to edit different parts of a file, there may be no
+reason to prevent either of them from doing so.
+
+@sc{cvs} does not use file locking. Instead, it allows many
+people to edit their own @dfn{working copy} of a file
+simultaneously. The first person that commits his
+changes has no automatic way of knowing that another has started to
+edit it. Others will get an error message when they
+try to commit the file. They must then use @sc{cvs}
+commands to bring their working copy up to date with
+the repository revision. This process is almost
+automatic, and explained in this chapter.
+
+There are many ways to organize a team of developers.
+@sc{cvs} does not try to enforce a certain
+organization. It is a tool that can be used in several
+ways. It is often useful to inform the group of
+commits you have done. @sc{cvs} has several ways of
+automating that process. @xref{Informing others}.
+@xref{Revision management}, for more tips on how to use
+@sc{cvs}.
+
+@menu
+* File status:: A file can be in several states
+* Updating a file:: Bringing a file up-to-date
+* Conflicts example:: An informative example
+* Informing others:: To cooperate you must inform
+* Concurrency:: Simultaneous repository access
+@end menu
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@node File status
+@section File status
+@cindex File status
+@cindex Status of a file
+@cindex Four states of a file
+
+After you have checked out a file out from @sc{cvs}, it is in
+one of these four states:
+
+@table @asis
+@cindex Up-to-date
+@item Up-to-date
+The file is identical with the latest revision in the
+repository.
+@c -- The above is not always true if branching is used.
+
+@item Locally modified
+@cindex Locally modified
+You have edited the file, and not yet committed your changes.
+
+@item Needing update
+@cindex Needing update
+Someone else has committed a newer revision to the repository.
+
+@item Needing merge
+@cindex Needing merge
+Someone else have committed a newer revision to the repository, and you
+have also made modifications to the file.
+@c -- What about "added" "removed" and so on?
+@end table
+
+You can use the @code{status} command to find out the status of a given
+file. @xref{status}.
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@node Updating a file
+@section Bringing a file up to date
+@cindex Bringing a file up to date
+@cindex Updating a file
+@cindex Merging a file
+@cindex update, introduction
+
+When you want to update or merge a file, use the @code{update}
+command. For files that are not up to date this is roughly equivalent
+to a @code{checkout} command: the newest revision of the file is
+extracted from the repository and put in your working copy of the
+module.
+
+Your modifications to a file are never lost when you
+use @code{update}. If no newer revision exists,
+running @code{update} has no effect. If you have
+edited the file, and a newer revision is available,
+@sc{cvs} will merge all changes into your working copy.
+
+For instance, imagine that you checked out revision 1.4 and started
+editing it. In the meantime someone else committed revision 1.5, and
+shortly after that revision 1.6. If you run @code{update} on the file
+now, @sc{cvs} will incorporate all changes between revision 1.4 and 1.6 into
+your file.
+
+@cindex Overlap
+If any of the changes between 1.4 and 1.6 were made too
+close to any of the changes you have made, an
+@dfn{overlap} occurs. In such cases a warning is
+printed, and the resulting file includes both
+versions of the lines that overlap, delimited by
+special markers.
+@xref{update}, for a complete description of the
+@code{update} command.
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@node Conflicts example
+@section Conflicts example
+@cindex Merge, an example
+@cindex Example of merge
+@cindex driver.c (merge example)
+
+Suppose revision 1.4 of @file{driver.c} contains this:
+
+@example
+#include <stdio.h>
+
+void main()
+@{
+ parse();
+ if (nerr == 0)
+ gencode();
+ else
+ fprintf(stderr, "No code generated.\n");
+ exit(nerr == 0 ? 0 : 1);
+@}
+@end example
+
+@noindent
+Revision 1.6 of @file{driver.c} contains this:
+
+@example
+#include <stdio.h>
+
+int main(int argc,
+ char **argv)
+@{
+ parse();
+ if (argc != 1)
+ @{
+ fprintf(stderr, "tc: No args expected.\n");
+ exit(1);
+ @}
+ if (nerr == 0)
+ gencode();
+ else
+ fprintf(stderr, "No code generated.\n");
+ exit(!!nerr);
+@}
+@end example
+
+@noindent
+Your working copy of @file{driver.c}, based on revision
+1.4, contains this before you run @samp{cvs update}:
+@c -- Really include "cvs"?
+
+@example
+#include <stdlib.h>
+#include <stdio.h>
+
+void main()
+@{
+ init_scanner();
+ parse();
+ if (nerr == 0)
+ gencode();
+ else
+ fprintf(stderr, "No code generated.\n");
+ exit(nerr == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
+@}
+@end example
+
+@noindent
+You run @samp{cvs update}:
+@c -- Really include "cvs"?
+
+@example
+$ cvs update driver.c
+RCS file: /usr/local/cvsroot/yoyodyne/tc/driver.c,v
+retrieving revision 1.4
+retrieving revision 1.6
+Merging differences between 1.4 and 1.6 into driver.c
+rcsmerge warning: overlaps during merge
+cvs update: conflicts found in driver.c
+C driver.c
+@end example
+
+@noindent
+@cindex Conflicts (merge example)
+@sc{cvs} tells you that there were some conflicts.
+Your original working file is saved unmodified in
+@file{.#driver.c.1.4}. The new version of
+@file{driver.c} contains this:
+
+@example
+#include <stdlib.h>
+#include <stdio.h>
+
+int main(int argc,
+ char **argv)
+@{
+ init_scanner();
+ parse();
+ if (argc != 1)
+ @{
+ fprintf(stderr, "tc: No args expected.\n");
+ exit(1);
+ @}
+ if (nerr == 0)
+ gencode();
+ else
+ fprintf(stderr, "No code generated.\n");
+<<<<<<< driver.c
+ exit(nerr == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
+=======
+ exit(!!nerr);
+>>>>>>> 1.6
+@}
+@end example
+
+@noindent
+@cindex Markers, conflict
+@cindex Conflict markers
+@cindex <<<<<<<
+@cindex >>>>>>>
+@cindex =======
+
+Note how all non-overlapping modifications are incorporated in your working
+copy, and that the overlapping section is clearly marked with
+@samp{<<<<<<<}, @samp{=======} and @samp{>>>>>>>}.
+
+@cindex Resolving a conflict
+@cindex Conflict resolution
+You resolve the conflict by editing the file, removing the markers and
+the erroneous line. Suppose you end up with this file:
+@c -- Add xref to the pcl-cvs manual when it talks
+@c -- about this.
+@example
+#include <stdlib.h>
+#include <stdio.h>
+
+int main(int argc,
+ char **argv)
+@{
+ init_scanner();
+ parse();
+ if (argc != 1)
+ @{
+ fprintf(stderr, "tc: No args expected.\n");
+ exit(1);
+ @}
+ if (nerr == 0)
+ gencode();
+ else
+ fprintf(stderr, "No code generated.\n");
+ exit(nerr == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
+@}
+@end example
+
+@noindent
+You can now go ahead and commit this as revision 1.7.
+
+@example
+$ cvs commit -m "Initialize scanner. Use symbolic exit values." driver.c
+Checking in driver.c;
+/usr/local/cvsroot/yoyodyne/tc/driver.c,v <-- driver.c
+new revision: 1.7; previous revision: 1.6
+done
+@end example
+
+@cindex emerge
+If you use release 1.04 or later of pcl-cvs (a @sc{gnu}
+Emacs front-end for @sc{cvs}) you can use an Emacs
+package called emerge to help you resolve conflicts.
+See the documentation for pcl-cvs.
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@node Informing others
+@section Informing others about commits
+@cindex Informing others
+@cindex Spreading information
+@cindex Mail, automatic mail on commit
+
+It is often useful to inform others when you commit a
+new revision of a file. The @samp{-i} option of the
+@file{modules} file, or the @file{loginfo} file, can be
+used to automate this process. @xref{modules}.
+@xref{loginfo}. You can use these features of @sc{cvs}
+to, for instance, instruct @sc{cvs} to mail a
+message to all developers, or post a message to a local
+newsgroup.
+@c -- More text would be nice here.
+
+@node Concurrency
+@section Several developers simultaneously attempting to run CVS
+
+@cindex locks, cvs
+If several developers try to run @sc{cvs} at the same
+time, one may get the following message:
+
+@example
+[11:43:23] waiting for bach's lock in /usr/local/cvsroot/foo
+@end example
+
+@sc{cvs} will try again every 30 seconds, and either
+continue with the operation or print the message again,
+if it still needs to wait. If a lock seems to stick
+around for an undue amount of time, find the person
+holding the lock and ask them about the cvs command
+they are running. If they aren't running a cvs
+command, look for and remove files starting with
+@file{#cvs.tfl}, @file{#cvs.rfl}, or @file{#cvs.wfl}
+from the repository.
+
+Note that these locks are to protect @sc{cvs}'s
+internal data structures and have no relationship to
+the word @dfn{lock} in the sense used by @sc{rcs}--a
+way to prevent other developers from working on a
+particular file.
+
+Any number of people can be reading from a given
+repository at a time; only when someone is writing do
+the locks prevent other people from reading or writing.
+
+One might hope for the following property
+
+@example
+If someone commits some changes in one cvs command,
+then an update by someone else will either get all the
+changes, or none of them.
+@end example
+
+but @sc{cvs} does @emph{not} have this property. For
+example, given the files
+
+@example
+a/one.c
+a/two.c
+b/three.c
+b/four.c
+@end example
+
+if someone runs
+
+@example
+cvs ci a/two.c b/three.c
+@end example
+
+and someone else runs @code{cvs update}, the person
+running update might get only the change to
+@file{b/three.c} and not the change to @file{a/two.c}.
+
+@c ---------------------------------------------------------------------
+@node Branches
+@chapter Branches
+@cindex Branches
+@cindex Main trunk and branches
+@cindex Revision tree, making branches
+
+So far, all revisions shown in this manual have been on
+the @dfn{main trunk}
+of the revision tree, i.e., all revision numbers
+have been of the form @var{x}.@var{y}. One useful
+feature, especially when maintaining several releases
+of a software product at once, is the ability to make
+branches on the revision tree. @dfn{Tags}, symbolic
+names for revisions, will also be
+introduced in this chapter.
+
+@menu
+* Tags:: Tags--Symbolic revisions
+* Branches motivation:: What branches are good for
+* Creating a branch:: Creating a branch
+* Sticky tags:: Sticky tags
+@end menu
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@node Tags
+@section Tags--Symbolic revisions
+@cindex Tags
+
+The revision numbers live a life of their own. They
+need not have anything at all to do with the release
+numbers of your software product. Depending
+on how you use @sc{cvs} the revision numbers might change several times
+between two releases. As an example, some of the
+source files that make up @sc{rcs} 5.6 have the following
+revision numbers:
+@cindex RCS revision numbers
+
+@example
+ci.c 5.21
+co.c 5.9
+ident.c 5.3
+rcs.c 5.12
+rcsbase.h 5.11
+rcsdiff.c 5.10
+rcsedit.c 5.11
+rcsfcmp.c 5.9
+rcsgen.c 5.10
+rcslex.c 5.11
+rcsmap.c 5.2
+rcsutil.c 5.10
+@end example
+
+@cindex tag, command, introduction
+@cindex Tag, symbolic name
+@cindex Symbolic name (tag)
+@cindex Name, symbolic (tag)
+You can use the @code{tag} command to give a symbolic name to a
+certain revision of a file. You can use the @samp{-v} flag to the
+@code{status} command to see all tags that a file has, and
+which revision numbers they represent.
+
+@cindex Adding a tag
+@cindex tag, example
+The following example shows how you can add a tag to a
+file. The commands must be issued inside your working
+copy of the module. That is, you should issue the
+command in the directory where @file{backend.c}
+resides.
+
+@example
+$ cvs tag release-0-4 backend.c
+T backend.c
+$ cvs status -v backend.c
+===================================================================
+File: backend.c Status: Up-to-date
+
+ Version: 1.4 Tue Dec 1 14:39:01 1992
+ RCS Version: 1.4 /usr/local/cvsroot/yoyodyne/tc/backend.c,v
+ Sticky Tag: (none)
+ Sticky Date: (none)
+ Sticky Options: (none)
+
+ Existing Tags:
+ release-0-4 (revision: 1.4)
+
+@end example
+
+There is seldom reason to tag a file in isolation. A more common use is
+to tag all the files that constitute a module with the same tag at
+strategic points in the development life-cycle, such as when a release
+is made.
+
+@example
+$ cvs tag release-1-0 .
+cvs tag: Tagging .
+T Makefile
+T backend.c
+T driver.c
+T frontend.c
+T parser.c
+@end example
+
+(When you give @sc{cvs} a directory as argument, it generally applies the
+operation to all the files in that directory, and (recursively), to any
+subdirectories that it may contain. @xref{Recursive behavior}.)
+
+@cindex Retrieving an old revision using tags
+@cindex Tag, retrieving old revisions
+The @code{checkout} command has a flag, @samp{-r}, that lets you check out
+a certain revision of a module. This flag makes it easy to
+retrieve the sources that make up release 1.0 of the module @samp{tc} at
+any time in the future:
+
+@example
+$ cvs checkout -r release-1-0 tc
+@end example
+
+@noindent
+This is useful, for instance, if someone claims that there is a bug in
+that release, but you cannot find the bug in the current working copy.
+
+You can also check out a module as it was at any given date.
+@xref{checkout options}.
+
+When you tag more than one file with the same tag you
+can think about the tag as "a curve drawn through a
+matrix of filename vs. revision number." Say we have 5
+files with the following revisions:
+
+@example
+@group
+ file1 file2 file3 file4 file5
+
+ 1.1 1.1 1.1 1.1 /--1.1* <-*- TAG
+ 1.2*- 1.2 1.2 -1.2*-
+ 1.3 \- 1.3*- 1.3 / 1.3
+ 1.4 \ 1.4 / 1.4
+ \-1.5*- 1.5
+ 1.6
+@end group
+@end example
+
+At some time in the past, the @code{*} versions were tagged.
+You can think of the tag as a handle attached to the curve
+drawn through the tagged revisions. When you pull on
+the handle, you get all the tagged revisions. Another
+way to look at it is that you "sight" through a set of
+revisions that is "flat" along the tagged revisions,
+like this:
+
+@example
+@group
+ file1 file2 file3 file4 file5
+
+ 1.1
+ 1.2
+ 1.1 1.3 _
+ 1.1 1.2 1.4 1.1 /
+ 1.2*----1.3*----1.5*----1.2*----1.1 (--- <--- Look here
+ 1.3 1.6 1.3 \_
+ 1.4 1.4
+ 1.5
+@end group
+@end example
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@node Branches motivation
+@section What branches are good for
+@cindex Branches motivation
+@cindex What branches are good for
+@cindex Motivation for branches
+
+Suppose that release 1.0 of tc has been made. You are continuing to
+develop tc, planning to create release 1.1 in a couple of months. After a
+while your customers start to complain about a fatal bug. You check
+out release 1.0 (@pxref{Tags}) and find the bug
+(which turns out to have a trivial fix). However, the current revision
+of the sources are in a state of flux and are not expected to be stable
+for at least another month. There is no way to make a
+bugfix release based on the newest sources.
+
+The thing to do in a situation like this is to create a @dfn{branch} on
+the revision trees for all the files that make up
+release 1.0 of tc. You can then make
+modifications to the branch without disturbing the main trunk. When the
+modifications are finished you can select to either incorporate them on
+the main trunk, or leave them on the branch.
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@node Creating a branch
+@section Creating a branch
+@cindex Creating a branch
+@cindex Branch, creating a
+@cindex rtag, creating a branch using
+
+The @code{rtag} command can be used to create a branch.
+The @code{rtag} command is much like @code{tag}, but it
+does not require that you have a working copy of the
+module. @xref{rtag}. (You can also use the @code{tag}
+command; @pxref{tag}).
+
+@example
+$ cvs rtag -b -r release-1-0 release-1-0-patches tc
+@end example
+
+The @samp{-b} flag makes @code{rtag} create a branch
+(rather than just a symbolic revision name). @samp{-r
+release-1-0} says that this branch should be rooted at the node (in
+the revision tree) that corresponds to the tag
+@samp{release-1-0}. Note that the numeric revision number that matches
+@samp{release-1-0} will probably be different from file to file. The
+name of the new branch is @samp{release-1-0-patches}, and the
+module affected is @samp{tc}.
+
+To fix the problem in release 1.0, you need a working
+copy of the branch you just created.
+
+@example
+$ cvs checkout -r release-1-0-patches tc
+$ cvs status -v driver.c backend.c
+===================================================================
+File: driver.c Status: Up-to-date
+
+ Version: 1.7 Sat Dec 5 18:25:54 1992
+ RCS Version: 1.7 /usr/local/cvsroot/yoyodyne/tc/driver.c,v
+ Sticky Tag: release-1-0-patches (branch: 1.7.2)
+ Sticky Date: (none)
+ Sticky Options: (none)
+
+ Existing Tags:
+ release-1-0-patches (branch: 1.7.2)
+ release-1-0 (revision: 1.7)
+
+===================================================================
+File: backend.c Status: Up-to-date
+
+ Version: 1.4 Tue Dec 1 14:39:01 1992
+ RCS Version: 1.4 /usr/local/cvsroot/yoyodyne/tc/backend.c,v
+ Sticky Tag: release-1-0-patches (branch: 1.4.2)
+ Sticky Date: (none)
+ Sticky Options: (none)
+
+ Existing Tags:
+ release-1-0-patches (branch: 1.4.2)
+ release-1-0 (revision: 1.4)
+ release-0-4 (revision: 1.4)
+
+@end example
+
+@cindex Branch numbers
+As the output from the @code{status} command shows the branch
+number is created by adding a digit at the tail of the revision number
+it is based on. (If @samp{release-1-0} corresponds to revision 1.4, the
+branch's revision number will be 1.4.2. For obscure reasons @sc{cvs} always
+gives branches even numbers, starting at 2.
+@xref{Revision numbers}).
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@node Sticky tags
+@section Sticky tags
+@cindex Sticky tags
+@cindex Tags, sticky
+@cindex Branches, sticky
+
+The @samp{-r release-1-0-patches} flag that was given to @code{checkout}
+is @dfn{sticky}, that is, it will apply to subsequent commands
+in this directory. If you commit any modifications, they are
+committed on the branch. You can later merge the modifications into
+the main trunk. @xref{Merging}.
+
+@example
+$ vi driver.c # @r{Fix the bugs}
+$ cvs commit -m "Fixed initialization bug" driver.c
+Checking in driver.c;
+/usr/local/cvsroot/yoyodyne/tc/driver.c,v <-- driver.c
+new revision: 1.7.2.1; previous revision: 1.7
+done
+$ cvs status -v driver.c
+===================================================================
+File: driver.c Status: Up-to-date
+
+ Version: 1.7.2.1 Sat Dec 5 19:35:03 1992
+ RCS Version: 1.7.2.1 /usr/local/cvsroot/yoyodyne/tc/driver.c,v
+ Sticky Tag: release-1-0-patches (branch: 1.7.2)
+ Sticky Date: (none)
+ Sticky Options: (none)
+
+ Existing Tags:
+ release-1-0-patches (branch: 1.7.2)
+ release-1-0 (revision: 1.7)
+
+@end example
+
+@cindex Resetting sticky tags
+@cindex Sticky tags, resetting
+@cindex Deleting sticky tags
+The sticky tags will remain on your working files until
+you delete them with @samp{cvs update -A}. @xref{update}.
+
+Sticky tags are not just for branches. If you check
+out a certain revision (such as 1.4) it will also
+become sticky. Subsequent @samp{cvs update} will not
+retrieve the latest revision until you reset the tag
+with @samp{cvs update -A}.
+
+See the descriptions in Appendix A for more information
+about sticky tags. Dates and some other options can
+also be sticky. Again, see Appendix A for details.
+@c -- xref to relevant part of App A.
+@c -- Re-evaluate this node.
+
+@c ---------------------------------------------------------------------
+@node Merging
+@chapter Merging
+@cindex Merging
+@cindex Copying changes
+@cindex Branches, copying changes between
+@cindex Changes, copying between branches
+@cindex Modifications, copying between branches
+
+You can include the changes made between any two
+revisions into your working copy, by @dfn{merging}.
+You can then commit that revision, and thus effectively
+copy the changes onto another branch.
+
+@menu
+* Merging a branch:: Merging an entire branch
+* Merging more than once:: Merging from a branch several times
+* Merging two revisions:: Merging differences between two revisions
+@end menu
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@node Merging a branch
+@section Merging an entire branch
+@cindex Merging a branch
+@cindex -j (merging branches)
+
+You can merge changes made on a branch into your working copy by giving
+the @samp{-j @var{branch}} flag to the @code{update} command. With one
+@samp{-j @var{branch}} option it merges the changes made between the
+point where the branch forked and newest revision on that branch (into
+your working copy).
+
+@cindex Join
+The @samp{-j} stands for ``join''.
+
+@cindex Branch merge example
+@cindex Example, branch merge
+@cindex Merge, branch example
+Consider this revision tree:
+
+@example
++-----+ +-----+ +-----+ +-----+
+! 1.1 !----! 1.2 !----! 1.3 !----! 1.4 ! <- The main trunk
++-----+ +-----+ +-----+ +-----+
+ !
+ !
+ ! +---------+ +---------+
+Branch R1fix -> +---! 1.2.2.1 !----! 1.2.2.2 !
+ +---------+ +---------+
+@end example
+
+@noindent
+The branch 1.2.2 has been given the tag (symbolic name) @samp{R1fix}. The
+following example assumes that the module @samp{mod} contains only one
+file, @file{m.c}.
+
+@example
+$ cvs checkout mod # @r{Retrieve the latest revision, 1.4}
+
+$ cvs update -j R1fix m.c # @r{Merge all changes made on the branch,}
+ # @r{i.e. the changes between revision 1.2}
+ # @r{and 1.2.2.2, into your working copy}
+ # @r{of the file.}
+
+$ cvs commit -m "Included R1fix" # @r{Create revision 1.5.}
+@end example
+
+A conflict can result from a merge operation. If that
+happens, you should resolve it before committing the
+new revision. @xref{Conflicts example}.
+
+The @code{checkout} command also supports the @samp{-j @var{branch}} flag. The
+same effect as above could be achieved with this:
+
+@example
+$ cvs checkout -j R1fix mod
+$ cvs commit -m "Included R1fix"
+@end example
+
+@node Merging more than once
+@section Merging from a branch several times
+
+Continuing our example, the revision tree now looks
+like this:
+
+@example
++-----+ +-----+ +-----+ +-----+ +-----+
+! 1.1 !----! 1.2 !----! 1.3 !----! 1.4 !----! 1.5 ! <- The main trunk
++-----+ +-----+ +-----+ +-----+ +-----+
+ ! *
+ ! *
+ ! +---------+ +---------+
+Branch R1fix -> +---! 1.2.2.1 !----! 1.2.2.2 !
+ +---------+ +---------+
+@end example
+
+where the starred line represents the merge from the
+@samp{R1fix} branch to the main trunk, as just
+discussed.
+
+Now suppose that development continues on the
+@samp{R1fix} branch:
+
+@example
++-----+ +-----+ +-----+ +-----+ +-----+
+! 1.1 !----! 1.2 !----! 1.3 !----! 1.4 !----! 1.5 ! <- The main trunk
++-----+ +-----+ +-----+ +-----+ +-----+
+ ! *
+ ! *
+ ! +---------+ +---------+ +---------+
+Branch R1fix -> +---! 1.2.2.1 !----! 1.2.2.2 !----! 1.2.2.3 !
+ +---------+ +---------+ +---------+
+@end example
+
+and then you want to merge those new changes onto the
+main trunk. If you just use the @code{cvs update -j
+R1fix m.c} command again, @sc{cvs} will attempt to
+merge again the changes which you have already merged,
+which can have undesirable side effects.
+
+So instead you need to specify that you only want to
+merge the changes on the branch which have not yet been
+merged into the trunk. To do that you specify two
+@samp{-j} options, and @sc{cvs} merges the changes from
+the first revision to the second revision. For
+example, in this case the simplest way would be
+
+@example
+cvs update -j 1.2.2.2 -j R1fix m.c # @r{Merge changes from 1.2.2.2 to the}
+ # @r{head of the R1fix branch}
+@end example
+
+The problem with this is that you need to specify the
+1.2.2.2 revision manually. A slightly better approach
+might be to use the date the last merge was done:
+
+@example
+cvs update -j R1fix:yesterday -j R1fix m.c
+@end example
+
+Better yet, tag the R1fix branch after every merge into
+the trunk, and then use that tag for subsequent merges:
+
+@example
+cvs update -j merged_from_R1fix_to_trunk -j R1fix m.c
+@end example
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@node Merging two revisions
+@section Merging differences between any two revisions
+@cindex Merging two revisions
+@cindex Revisions, merging differences between
+@cindex Differences, merging
+
+With two @samp{-j @var{revision}} flags, the @code{update}
+(and @code{checkout}) command can merge the differences
+between any two revisions into your working file.
+
+@cindex Undoing a change
+@cindex Removing a change
+@example
+$ cvs update -j 1.5 -j 1.3 backend.c
+@end example
+
+@noindent
+will @emph{remove} all changes made between revision
+1.3 and 1.5. Note the order of the revisions!
+
+If you try to use this option when operating on
+multiple files, remember that the numeric revisions will
+probably be very different between the various files
+that make up a module. You almost always use symbolic
+tags rather than revision numbers when operating on
+multiple files.
+
+@c ---------------------------------------------------------------------
+@node Recursive behavior
+@chapter Recursive behavior
+@cindex Recursive (directory descending)
+@cindex Directory, descending
+@cindex Descending directories
+@cindex Subdirectories
+
+Almost all of the subcommands of @sc{cvs} work
+recursively when you specify a directory as an
+argument. For instance, consider this directory
+structure:
+
+@example
+ @code{$HOME}
+ |
+ +--@t{tc}
+ | |
+ +--@t{CVS}
+ | (internal @sc{cvs} files)
+ +--@t{Makefile}
+ +--@t{backend.c}
+ +--@t{driver.c}
+ +--@t{frontend.c}
+ +--@t{parser.c}
+ +--@t{man}
+ | |
+ | +--@t{CVS}
+ | | (internal @sc{cvs} files)
+ | +--@t{tc.1}
+ |
+ +--@t{testing}
+ |
+ +--@t{CVS}
+ | (internal @sc{cvs} files)
+ +--@t{testpgm.t}
+ +--@t{test2.t}
+@end example
+
+@noindent
+If @file{tc} is the current working directory, the
+following is true:
+
+@itemize @bullet
+@item
+@samp{cvs update testing} is equivalent to @samp{cvs
+update testing/testpgm.t testing/test2.t}
+
+@item
+@samp{cvs update testing man} updates all files in the
+subdirectories
+
+@item
+@samp{cvs update .} or just @samp{cvs update} updates
+all files in the @code{tc} module
+@end itemize
+
+If no arguments are given to @code{update} it will
+update all files in the current working directory and
+all its subdirectories. In other words, @file{.} is a
+default argument to @code{update}. This is also true
+for most of the @sc{cvs} subcommands, not only the
+@code{update} command.
+
+The recursive behavior of the @sc{cvs} subcommands can be
+turned off with the @samp{-l} option.
+
+@example
+$ cvs update -l # @r{Don't update files in subdirectories}
+@end example
+
+@c ---------------------------------------------------------------------
+@node Adding files
+@chapter Adding files to a module
+@cindex Adding files
+
+To add a new file to a module, follow these steps.
+
+@itemize @bullet
+@item
+You must have a working copy of the module.
+@xref{Getting the source}.
+
+@item
+Create the new file inside your working copy of the module.
+
+@item
+Use @samp{cvs add @var{filename}} to tell @sc{cvs} that you
+want to version control the file.
+
+@item
+Use @samp{cvs commit @var{filename}} to actually check
+in the file into the repository. Other developers
+cannot see the file until you perform this step.
+
+@item
+If the file contains binary data it might be necessary
+to change the default keyword substitution.
+@xref{Keyword substitution}. @xref{admin examples}.
+@end itemize
+
+You can also use the @code{add} command to add a new
+directory inside a module.
+
+Unlike most other commands, the @code{add} command is
+not recursive. You cannot even type @samp{cvs add
+foo/bar}! Instead, you have to
+
+@example
+$ cd foo
+$ cvs add bar
+@end example
+
+@xref{add}, for a more complete description of the @code{add}
+command.
+
+@c ---------------------------------------------------------------------
+@node Removing files
+@chapter Removing files from a module
+@cindex Removing files
+@cindex Deleting files
+
+Modules change. New files are added, and old files
+disappear. Still, you want to be able to retrieve an
+exact copy of old releases of the module.
+
+Here is what you can do to remove a file from a module,
+but remain able to retrieve old revisions:
+
+@itemize @bullet
+@item
+Make sure that you have not made any uncommitted
+modifications to the file. @xref{Viewing differences},
+for one way to do that. You can also use the
+@code{status} or @code{update} command. If you remove
+the file without committing your changes, you will of
+course not be able to retrieve the file as it was
+immediately before you deleted it.
+
+@item
+Remove the file from your working copy of the module.
+You can for instance use @code{rm}.
+
+@item
+Use @samp{cvs remove @var{filename}} to tell @sc{cvs} that
+you really want to delete the file.
+
+@item
+Use @samp{cvs commit @var{filename}} to actually
+perform the removal of the file from the repository.
+@end itemize
+
+What happens when you commit the removal of the file is
+that inside the source repository, it is moved into a
+subdirectory called @file{Attic}. @sc{cvs} normally doesn't
+look in that directory when you run e.g.
+@code{checkout}. However, if you are retrieving a
+certain revision via e.g. @samp{cvs checkout -r
+@var{some-tag}}, it will look at the files inside the
+@file{Attic} and include any files that contain the
+specified tag.
+
+@c ---------------------------------------------------------------------
+@node Tracking sources
+@chapter Tracking third-party sources
+@cindex Third-party sources
+@cindex Tracking sources
+
+If you modify a program to better fit your site, you
+probably want to include your modifications when the next
+release of the program arrives. @sc{cvs} can help you with
+this task.
+
+@cindex Vendor
+@cindex Vendor branch
+@cindex Branch, vendor-
+In the terminology used in @sc{cvs}, the supplier of the
+program is called a @dfn{vendor}. The unmodified
+distribution from the vendor is checked in on its own
+branch, the @dfn{vendor branch}. @sc{cvs} reserves branch
+1.1.1 for this use.
+
+When you modify the source and commit it, your revision
+will end up on the main trunk. When a new release is
+made by the vendor, you commit it on the vendor branch
+and copy the modifications onto the main trunk.
+
+Use the @code{import} command to create and update
+the vendor branch. After a successful @code{import}
+the vendor branch is made the `head' revision, so
+anyone that checks out a copy of the file gets that
+revision. When a local modification is committed it is
+placed on the main trunk, and made the `head'
+revision.
+
+@menu
+* First import:: Importing a module for the first time
+* Update imports:: Updating a module with the import command
+@end menu
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@node First import
+@section Importing a module for the first time
+@cindex Importing modules
+
+Use the @code{import} command to check in the sources
+for the first time. When you use the @code{import}
+command to track third-party sources, the @dfn{vendor
+tag} and @dfn{release tags} are useful. The
+@dfn{vendor tag} is a symbolic name for the branch
+(which is always 1.1.1, unless you use the @samp{-b
+@var{branch}} flag---@xref{import options}). The
+@dfn{release tags} are symbolic names for a particular
+release, such as @samp{FSF_0_04}.
+
+@cindex Wdiff (import example)
+Suppose you use @code{wdiff} (a variant of @code{diff}
+that ignores changes that only involve whitespace), and
+are going to make private modifications that you want
+to be able to use even when new releases are made in
+the future. You start by importing the source to your
+repository:
+
+@example
+$ tar xfz wdiff-0.04.tar.gz
+$ cd wdiff-0.04
+$ cvs import -m "Import of FSF v. 0.04" fsf/wdiff FSF WDIFF_0_04
+@end example
+
+The vendor tag is named @samp{FSF} in the above
+example, and the only release tag assigned is
+@samp{WDIFF_0_04}.
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@node Update imports
+@section Updating a module with the import command
+
+When a new release of the source arrives, you import it into the
+repository with the same @code{import} command that you used to set up
+the repository in the first place. The only difference is that you
+specify a different release tag this time.
+
+@example
+$ tar xfz wdiff-0.05.tar.gz
+$ cd wdiff-0.05
+$ cvs import -m "Import of FSF v. 0.05" fsf/wdiff FSF WDIFF_0_05
+@end example
+
+For files that have not been modified locally, the newly created
+revision becomes the head revision. If you have made local
+changes, @code{import} will warn you that you must merge the changes
+into the main trunk, and tell you to use @samp{checkout -j} to do so.
+
+@example
+$ cvs checkout -jFSF:yesterday -jFSF wdiff
+@end example
+
+@noindent
+The above command will check out the latest revision of
+@samp{wdiff}, merging the changes made on the vendor branch @samp{FSF}
+since yesterday into the working copy. If any conflicts arise during
+the merge they should be resolved in the normal way (@pxref{Conflicts
+example}). Then, the modified files may be committed.
+
+Using a date, as suggested above, assumes that you do
+not import more than one release of a product per
+day. If you do, you can always use something like this
+instead:
+
+@example
+$ cvs checkout -jWDIFF_0_04 -jWDIFF_0_05 wdiff
+@end example
+
+@noindent
+In this case, the two above commands are equivalent.
+
+@c ---------------------------------------------------------------------
+@node Moving files
+@chapter Moving and renaming files
+@cindex Moving files
+@cindex Renaming files
+@cindex Files, moving
+
+Moving files to a different directory or renaming them
+is not difficult, but some of the ways in which this
+works may be non-obvious. (Moving or renaming a
+directory is even harder. @xref{Moving directories}).
+
+The examples below assume that the file @var{old} is renamed to
+@var{new}.
+
+@menu
+* Outside:: The normal way to Rename
+* Inside:: A tricky, alternative way
+* Rename by copying:: Another tricky, alternative way
+@end menu
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@node Outside
+@section The Normal way to Rename
+
+The normal way to move a file is to copy @var{old} to
+@var{new}, and then issue the normal @sc{cvs} commands
+to remove @var{old} from the repository, and add
+@var{new} to it. (Both @var{old} and @var{new} could
+contain relative paths, for example @file{foo/bar.c}).
+
+@example
+$ mv @var{old} @var{new}
+$ cvs remove @var{old}
+$ cvs add @var{new}
+$ cvs commit -m "Renamed @var{old} to @var{new}" @var{old} @var{new}
+@end example
+
+This is the simplest way to move a file, it is not
+error-prone, and it preserves the history of what was
+done. Note that to access the history of the file you
+must specify the old or the new name, depending on what
+portion of the history you are accessing. For example,
+@code{cvs log @var{old}} will give the log up until the
+time of the rename.
+
+When @var{new} is committed its revision numbers will
+start at 1.0 again, so if that bothers you, use the
+@samp{-r rev} option to commit (@pxref{commit options})
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@node Inside
+@section Moving the history file
+
+This method is more dangerous, since it involves moving
+files inside the repository. Read this entire section
+before trying it out!
+
+@example
+$ cd $CVSROOT/@var{module}
+$ mv @var{old},v @var{new},v
+@end example
+
+@noindent
+Advantages:
+
+@itemize @bullet
+@item
+The log of changes is maintained intact.
+
+@item
+The revision numbers are not affected.
+@end itemize
+
+@noindent
+Disadvantages:
+
+@itemize @bullet
+@item
+Old releases of the module cannot easily be fetched from the
+repository. (The file will show up as @var{new} even
+in revisions from the time before it was renamed).
+
+@item
+There is no log information of when the file was renamed.
+
+@item
+Nasty things might happen if someone accesses the history file
+while you are moving it. Make sure no one else runs any of the @sc{cvs}
+commands while you move it.
+@end itemize
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@node Rename by copying
+@section Copying the history file
+
+This way also involves direct modifications to the
+repository. It is safe, but not without drawbacks.
+
+@example
+# @r{Copy the @sc{rcs} file inside the repository}
+$ cd $CVSROOT/@var{module}
+$ cp @var{old},v @var{new},v
+# @r{Remove the old file}
+$ cd ~/@var{module}
+$ rm @var{old}
+$ cvs remove @var{old}
+$ cvs commit @var{old}
+# @r{Remove all tags from @var{new}}
+$ cvs update @var{new}
+$ cvs log @var{new} # @r{Remember the tag names}
+$ cvs tag -d @var{tag1}
+$ cvs tag -d @var{tag2}
+@dots{}
+@end example
+
+By removing the tags you will be able to check out old
+revisions of the module.
+
+@noindent
+Advantages:
+
+@itemize @bullet
+@item
+@c FIXME: Is this true about -D now that we have death
+@c support? See 5B.3 in the FAQ.
+Checking out old revisions works correctly, as long as
+you use @samp{-r@var{tag}} and not @samp{-D@var{date}}
+to retrieve the revisions.
+
+@item
+The log of changes is maintained intact.
+
+@item
+The revision numbers are not affected.
+@end itemize
+
+@noindent
+Disadvantages:
+
+@itemize @bullet
+@item
+You cannot easily see the history of the file across the rename.
+
+@item
+Unless you use the @samp{-r rev} (@pxref{commit
+options}) flag when @var{new} is committed its revision
+numbers will start at 1.0 again.
+@end itemize
+
+@c ---------------------------------------------------------------------
+@node Moving directories
+@chapter Moving and renaming directories
+@cindex Moving directories
+@cindex Renaming directories
+@cindex Directories, moving
+
+If you want to be able to retrieve old versions of the
+module, you must move each file in the directory
+with the @sc{cvs} commands. @xref{Outside}. The old, empty
+directory will remain inside the repository, but it
+will not appear in your workspace when you check out
+the module in the future.
+@c -- rephrase
+
+If you really want to rename or delete a directory, you
+can do it like this:
+
+@enumerate
+@item
+Inform everyone who has a copy of the module that the
+directory will be renamed. They should commit all
+their changes, and remove their working copies of the
+module, before you take the steps below.
+
+@item
+Rename the directory inside the repository.
+
+@example
+$ cd $CVSROOT/@var{module}
+$ mv @var{old-dir} @var{new-dir}
+@end example
+
+@item
+Fix the @sc{cvs} administrative files, if necessary (for
+instance if you renamed an entire module).
+
+@item
+Tell everyone that they can check out the module and continue
+working.
+
+@end enumerate
+
+If someone had a working copy of the module the @sc{cvs} commands will
+cease to work for him, until he removes the directory
+that disappeared inside the repository.
+
+It is almost always better to move the files in the
+directory instead of moving the directory. If you move the
+directory you are unlikely to be able to retrieve old
+releases correctly, since they probably depend on the
+name of the directories.
+
+@ignore
+@c ---------------------------------------------------------------------
+@c @node History browsing
+@chapter History browsing
+@cindex History browsing
+@cindex Traceability
+@cindex Isolation
+
+@c -- @quote{To lose ones history is to lose ones soul.}
+@c -- ///
+@c -- ///Those who cannot remember the past are condemned to repeat it.
+@c -- /// -- George Santayana
+@c -- ///
+
+@sc{cvs} tries to make it easy for a group of people to work
+together. This is done in two ways:
+
+@itemize @bullet
+@item
+Isolation---You have your own working copy of the
+source. You are not affected by modifications made by
+others until you decide to incorporate those changes
+(via the @code{update} command---@pxref{update}).
+
+@item
+Traceability---When something has changed, you can
+always see @emph{exactly} what changed.
+@end itemize
+
+There are several features of @sc{cvs} that together lead
+to traceability:
+
+@itemize @bullet
+@item
+Each revision of a file has an accompanying log
+message.
+
+@item
+All commits are optionally logged to a central history
+database.
+
+@item
+Logging information can be sent to a user-defined
+program (@pxref{loginfo}).
+@end itemize
+
+@c -- More text here.
+
+This chapter should talk about the history file, the
+@code{log} command, the usefulness of ChangeLogs
+even when you run @sc{cvs}, and things like that.
+
+@menu
+* log messages:: Log messages
+* history database:: The history database
+* user-defined logging:: User-defined logging
+@end menu
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@node log messages
+@section Log messages
+
+Whenever you commit a file you specify a log message. ///
+@c --
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@node history database
+@section The history database
+
+///
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@node user-defined logging
+@section User-defined logging
+
+///
+
+@end ignore
+
+@c ---------------------------------------------------------------------
+@node Keyword substitution
+@chapter Keyword substitution
+@cindex Keyword substitution
+@cindex Keyword expansion
+@cindex Identifying files
+
+@comment Be careful when editing this chapter.
+@comment Remember that this file is kept under
+@comment version control, so we must not accidentally
+@comment include a valid keyword in the running text.
+
+As long as you edit source files inside your working
+copy of a module you can always find out the state of
+your files via @samp{cvs status} and @samp{cvs log}.
+But as soon as you export the files from your
+development environment it becomes harder to identify
+which revisions they are.
+
+@sc{Rcs} uses a mechanism known as @dfn{keyword
+substitution} (or @dfn{keyword expansion}) to help
+identifying the files. Embedded strings of the form
+@code{$@var{keyword}$} and
+@code{$@var{keyword}:@dots{}$} in a file are replaced
+with strings of the form
+@code{$@var{keyword}:@var{value}$} whenever you obtain
+a new revision of the file.
+
+@menu
+* Keyword list:: RCS Keywords
+* Using keywords:: Using keywords
+* Avoiding substitution:: Avoiding substitution
+* Substitution modes:: Substitution modes
+* Log keyword:: Problems with the $@asis{}Log$ keyword.
+@end menu
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@node Keyword list
+@section RCS Keywords
+@cindex RCS keywords
+
+This is a list of the keywords that @sc{rcs} currently
+(in release 5.6.0.1) supports:
+
+@table @code
+@cindex Author keyword
+@item $@asis{Author}$
+The login name of the user who checked in the revision.
+
+@cindex Date keyword
+@item $@asis{Date}$
+The date and time (UTC) the revision was checked in.
+
+@cindex Header keyword
+@item $@asis{Header}$
+A standard header containing the full pathname of the
+@sc{rcs} file, the revision number, the date (UTC), the
+author, the state, and the locker (if locked). Files
+will normally never be locked when you use @sc{cvs}.
+
+@cindex Id keyword
+@item $@asis{Id}$
+Same as @code{$@asis{Header}$}, except that the @sc{rcs}
+filename is without a path.
+
+@cindex Locker keyword
+@item $@asis{Locker}$
+The login name of the user who locked the revision
+(empty if not locked, and thus almost always useless
+when you are using @sc{cvs}).
+
+@cindex Log keyword
+@item $@asis{Log}$
+The log message supplied during commit, preceded by a
+header containing the @sc{rcs} filename, the revision
+number, the author, and the date (UTC). Existing log
+messages are @emph{not} replaced. Instead, the new log
+message is inserted after @code{$@asis{Log:@dots{}}$}.
+Each new line is prefixed with a @dfn{comment leader}
+which @sc{rcs} guesses from the file name extension.
+It can be changed with @code{cvs admin -c}.
+@xref{admin options}. This keyword is useful for
+accumulating a complete change log in a source file,
+but for several reasons it can be problematic.
+@xref{Log keyword}.
+
+@cindex RCSfile keyword
+@item $@asis{RCSfile}$
+The name of the RCS file without a path.
+
+@cindex Revision keyword
+@item $@asis{Revision}$
+The revision number assigned to the revision.
+
+@cindex Source keyword
+@item $@asis{Source}$
+The full pathname of the RCS file.
+
+@cindex State keyword
+@item $@asis{State}$
+The state assigned to the revision. States can be
+assigned with @code{cvs admin -s}---@xref{admin options}.
+
+@end table
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@node Using keywords
+@section Using keywords
+
+To include a keyword string you simply include the
+relevant text string, such as @code{$@asis{Id}$}, inside the
+file, and commit the file. @sc{cvs} will automatically
+expand the string as part of the commit operation.
+
+@need 800
+It is common to embed @code{$@asis{}Id$} string in the
+C source code. This example shows the first few lines
+of a typical file, after keyword substitution has been
+performed:
+
+@example
+static char *rcsid="$@asis{}Id: samp.c,v 1.5 1993/10/19 14:57:32 ceder Exp $";
+/* @r{The following lines will prevent @code{gcc} version 2.@var{x}}
+ @r{from issuing an "unused variable" warning}. */
+#if __GNUC__ == 2
+#define USE(var) static void * use_##var = (&use_##var, (void *) &var)
+USE (rcsid);
+#endif
+@end example
+
+Even though a clever optimizing compiler could remove
+the unused variable @code{rcsid}, most compilers tend
+to include the string in the binary. Some compilers
+have a @code{#pragma} directive to include literal text
+in the binary.
+
+@cindex Ident (shell command)
+The @code{ident} command (which is part of the @sc{rcs}
+package) can be used to extract keywords and their
+values from a file. This can be handy for text files,
+but it is even more useful for extracting keywords from
+binary files.
+
+@example
+$ ident samp.c
+samp.c:
+ $@asis{}Id: samp.c,v 1.5 1993/10/19 14:57:32 ceder Exp $
+$ gcc samp.c
+$ ident a.out
+a.out:
+ $@asis{}Id: samp.c,v 1.5 1993/10/19 14:57:32 ceder Exp $
+@end example
+
+@cindex What (shell command)
+S@sc{ccs} is another popular revision control system.
+It has a command, @code{what}, which is very similar to
+@code{ident} and used for the same purpose. Many sites
+without @sc{rcs} have @sc{sccs}. Since @code{what}
+looks for the character sequence @code{@@(#)} it is
+easy to include keywords that are detected by either
+command. Simply prefix the @sc{rcs} keyword with the
+magic @sc{sccs} phrase, like this:
+
+@example
+static char *id="@@(#) $@asis{}Id: ab.c,v 1.5 1993/10/19 14:57:32 ceder Exp $";
+@end example
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@node Avoiding substitution
+@section Avoiding substitution
+
+Keyword substitution has its disadvantages. Sometimes
+you might want the literal text string
+@samp{$@asis{}Author$} to appear inside a file without
+@sc{rcs} interpreting it as a keyword and expanding it
+into something like @samp{$@asis{}Author: ceder $}.
+
+There is unfortunately no way to selectively turn off
+keyword substitution. You can use @samp{-ko}
+(@pxref{Substitution modes}) to turn off keyword
+substitution entirely. (If you put binaries under
+version control you are strongly encouraged to use that
+option, for obvious reasons).
+
+In many cases you can avoid using @sc{rcs} keywords in
+the source, even though they appear in the final
+product. For example, the source for this manual
+contains @samp{$@@asis@{@}Author$} whenever the text
+@samp{$@asis{}Author$} should appear. In @code{nroff}
+and @code{troff} you can embed the null-character
+@code{\&} inside the keyword for a similar effect.
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@node Substitution modes
+@section Substitution modes
+@cindex -k (RCS kflags)
+@cindex Kflag
+
+You can control how @sc{rcs} expands keywords
+through the use of the @samp{-k} option (@pxref{Common
+options}). The @samp{-k} option is available with the
+@code{add}, @code{checkout}, @code{diff} and
+@code{update} commands.
+
+Five different modes are available. They are:
+
+@table @samp
+@item -kkv
+Generate keyword strings using the default form, e.g.
+@code{$@asis{}Revision: 5.7 $} for the @code{Revision}
+keyword.
+
+@item -kkvl
+Like @samp{-kkv}, except that a locker's name is always
+inserted if the given revision is currently locked.
+This option is normally not useful when @sc{cvs} is used.
+
+@item -kk
+Generate only keyword names in keyword strings; omit
+their values. For example, for the @code{Revision}
+keyword, generate the string @code{$@asis{}Revision$}
+instead of @code{$@asis{}Revision: 5.7 $}. This option
+is useful to ignore differences due to keyword
+substitution when comparing different revisions of a
+file.
+
+@item -ko
+Generate the old keyword string, present in the working
+file just before it was checked in. For example, for
+the @code{Revision} keyword, generate the string
+@code{$@asis{}Revision: 1.1 $} instead of
+@code{$@asis{}Revision: 5.7 $} if that is how the
+string appeared when the file was checked in. This can
+be useful for binary file formats that cannot tolerate
+any changes to substrings that happen to take the form
+of keyword strings.
+
+@item -kv
+Generate only keyword values for keyword strings. For
+example, for the @code{Revision} keyword, generate the string
+@code{5.7} instead of @code{$@asis{}Revision: 5.7 $}.
+This can help generate files in programming languages
+where it is hard to strip keyword delimiters like
+@code{$@asis{}Revision: $} from a string. However,
+further keyword substitution cannot be performed once
+the keyword names are removed, so this option should be
+used with care.
+
+This option is always use by @code{cvs
+export}---@pxref{export}.
+
+@end table
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@node Log keyword
+@section Problems with the $@asis{}Log$ keyword.
+
+The @code{$@asis{}Log$} keyword is somewhat
+controversial. As long as you are working on your
+development system the information is easily accessible
+even if you do not use the @code{$@asis{}Log$}
+keyword---just do a @code{cvs log}. Once you export
+the file the history information might be useless
+anyhow.
+
+A more serious concern is that @sc{rcs} is not good at
+handling @code{$@asis{}Log$} entries when a branch is
+merged onto the main trunk. Conflicts often result
+from the merging operation.
+
+People also tend to "fix" the log entries in the file
+(correcting spelling mistakes and maybe even factual
+errors). If that is done the information from
+@code{cvs log} will not be consistent with the
+information inside the file. This may or may not be a
+problem in real life.
+
+It has been suggested that the @code{$@asis{}Log$}
+keyword should be inserted @emph{last} in the file, and
+not in the files header, if it is to be used at all.
+That way the long list of change messages will not
+interfere with everyday source file browsing.
+
+@c ---------------------------------------------------------------------
+@node Revision management
+@chapter Revision management
+@cindex Revision management
+
+@c -- This chapter could be expanded a lot.
+@c -- Experiences are very welcome!
+
+If you have read this far, you probably have a pretty
+good grasp on what @sc{cvs} can do for you. This
+chapter talks a little about things that you still have
+to decide.
+
+If you are doing development on your own using @sc{cvs}
+you could probably skip this chapter. The questions
+this chapter takes up become more important when more
+than one person is working in a repository.
+
+@menu
+* When to commit:: Some discussion on the subject
+@end menu
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@node When to commit
+@section When to commit?
+@cindex When to commit
+@cindex Commit, when to
+@cindex Policy
+
+Your group should decide which policy to use regarding
+commits. Several policies are possible, and as your
+experience with @sc{cvs} grows you will probably find
+out what works for you.
+
+If you commit files too quickly you might commit files
+that do not even compile. If your partner updates his
+working sources to include your buggy file, he will be
+unable to compile the code. On the other hand, other
+persons will not be able to benefit from the
+improvements you make to the code if you commit very
+seldom, and conflicts will probably be more common.
+
+It is common to only commit files after making sure
+that they can be compiled. Some sites require that the
+files pass a test suite. Policies like this can be
+enforced using the commitinfo file
+(@pxref{commitinfo}), but you should think twice before
+you enforce such a convention. By making the
+development environment too controlled it might become
+too regimented and thus counter-productive to the real
+goal, which is to get software written.
+
+@c ---------------------------------------------------------------------
+@node Invoking CVS
+@appendix Reference manual for CVS commands
+@cindex Command reference
+@cindex Reference, commands
+@cindex Invoking CVS
+
+This appendix describes every subcommand of @sc{cvs} in
+detail. It also describes how to invoke CVS.
+
+@menu
+* Structure:: Overall structure of CVS commands
+* ~/.cvsrc:: Default options with the ~/.csvrc file
+* Global options:: Options you give to the left of cvs_command
+* Common options:: Options you give to the right of cvs_command
+* add:: Add a new file/directory to the repository
+* admin:: Administration front end for rcs
+* checkout:: Checkout sources for editing
+* commit:: Check files into the repository
+* diff:: Run diffs between revisions
+* export:: Export sources from CVS, similar to checkout
+* history:: Show status of files and users
+* import:: Import sources into CVS, using vendor branches
+* log:: Print out 'rlog' information for files
+* rdiff:: 'patch' format diffs between releases
+* release:: Indicate that a Module is no longer in use
+* remove:: Remove an entry from the repository
+* rtag:: Add a tag to a module
+* status:: Status info on the revisions
+* tag:: Add a tag to checked out version
+* update:: Bring work tree in sync with repository
+@end menu
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@node Structure
+@appendixsec Overall structure of CVS commands
+@cindex Structure
+@cindex CVS command structure
+@cindex Command structure
+@cindex Format of CVS commands
+
+The first release of @sc{cvs} consisted of a number of shell-scripts.
+Today @sc{cvs} is implemented as a single program that is a front-end
+to @sc{rcs} and @code{diff}. The overall format of all
+@sc{cvs} commands is:
+
+@example
+cvs [ cvs_options ] cvs_command [ command_options ] [ command_args ]
+@end example
+
+@table @code
+@item cvs
+The program that is a front-end to @sc{rcs}.
+
+@item cvs_options
+Some options that affect all sub-commands of @sc{cvs}. These are
+described below.
+
+@item cvs_command
+One of several different sub-commands. Some of the commands have
+aliases that can be used instead; those aliases are noted in the
+reference manual for that command. There are only two situations
+where you may omit @samp{cvs_command}: @samp{cvs -H} elicits a
+list of available commands, and @samp{cvs -v} displays version
+information on @sc{cvs} itself.
+
+@item command_options
+Options that are specific for the command.
+
+@item command_args
+Arguments to the commands.
+@end table
+
+There is unfortunately some confusion between
+@code{cvs_options} and @code{command_options}.
+@samp{-l}, when given as a @code{cvs_option}, only
+affects some of the commands. When it is given as a
+@code{command_option} is has a different meaning, and
+is accepted by more commands. In other words, do not
+take the above categorization too seriously. Look at
+the documentation instead.
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@node ~/.cvsrc
+@appendixsec Default options and the ~/.cvsrc file
+@cindex .cvsrc file
+@cindex option defaults
+
+There are some @code{command_options} that are used so
+often that you might have set up an alias or some other
+means to make sure you always specify that option. One
+example (the one that drove the implementation of the
+.cvsrc support, actually) is that many people find the
+default output of the @samp{diff} command to be very
+hard to read, and that either context diffs or unidiffs
+are much easier to understand.
+
+The @file{~/.cvsrc} file is a way that you can add
+default options to @code{cvs_commands} within cvs,
+instead of relying on aliases or other shell scripts.
+
+The format of the @file{~/.cvsrc} file is simple. The
+file is searched for a line that begins with the same
+name as the @code{cvs_command} being executed. If a
+match is found, then the remainder of the line is split
+up (at whitespace characters) into separate options and
+added to the command arguments @emph{before} any
+options from the command line.
+
+If a command has two names (e.g., @code{checkout} and
+@code{co}), the official name, not necessarily the one
+used on the command line, will be used to match against
+the file. So if this is the contents of the user's
+@file{~/.cvsrc} file:
+
+@example
+log -N
+diff -u
+update -P
+co -P
+@end example
+
+@noindent
+the command @samp{cvs checkout foo} would have the
+@samp{-P} option added to the arguments, as well as
+@samp{cvs co foo}.
+
+With the example file above, the output from @samp{cvs
+diff foobar} will be in unidiff format. @samp{cvs diff
+-c foobar} will provide context diffs, as usual.
+Getting "old" format diffs would be slightly more
+complicated, because @code{diff} doesn't have an option
+to specify use of the "old" format, so you would need
+@samp{cvs -f diff foobar}.
+
+
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@node Global options
+@appendixsec Global options
+@cindex Options, global
+@cindex Global options
+@cindex Left-hand options
+
+The available @samp{cvs_options} (that are given to the
+left of @samp{cvs_command}) are:
+
+@table @code
+@cindex RCSBIN, overriding
+@cindex Overriding RCSBIN
+@item -b @var{bindir}
+Use @var{bindir} as the directory where @sc{rcs} programs are
+located. Overrides the setting of the @code{$RCSBIN} environment
+variable and any precompiled directory. This parameter should be
+specified as an absolute pathname.
+
+@cindex CVSROOT, overriding
+@cindex Overriding CVSROOT
+@item -d @var{cvs_root_directory}
+Use @var{cvs_root_directory} as the root directory
+pathname of the repository. Overrides the setting of
+the @code{$CVSROOT} environment variable. @xref{Repository}.
+
+@cindex EDITOR, overriding
+@cindex Overriding EDITOR
+@item -e @var{editor}
+Use @var{editor} to enter revision log information. Overrides the
+setting of the @code{$CVSEDITOR} and @code{$EDITOR} environment variables.
+
+@item -f
+Do not read the @file{~/.cvsrc} file. This
+option is most often used because of the
+non-orthogonality of the @sc{cvs} option set. For
+example, the @samp{cvs log} option @samp{-N} (turn off
+display of tag names) does not have a corresponding
+option to turn the display on. So if you have
+@samp{-N} in the @file{~/.cvsrc} entry for @samp{diff},
+you may need to use @samp{-f} to show the tag names.
+@footnote{Yes, this really should be fixed, and it's
+being worked on}
+
+@item -H
+Display usage information about the specified @samp{cvs_command}
+(but do not actually execute the command). If you don't specify
+a command name, @samp{cvs -H} displays a summary of all the
+commands available.
+
+@item -l
+Do not log the cvs_command in the command history (but execute it
+anyway). @xref{history}, for information on command history.
+
+@cindex Read-only mode
+@item -n
+Do not change any files. Attempt to execute the
+@samp{cvs_command}, but only to issue reports; do not remove,
+update, or merge any existing files, or create any new files.
+
+@item -Q
+Cause the command to be really quiet; the command will only
+generate output for serious problems.
+
+@item -q
+Cause the command to be somewhat quiet; informational messages,
+such as reports of recursion through subdirectories, are
+suppressed.
+
+@cindex Read-only files
+@item -r
+Make new working files files read-only. Same effect
+as if the @code{$CVSREAD} environment variable is set
+(@pxref{Environment variables}). The default is to
+make working files writable.
+
+@cindex Trace
+@item -t
+Trace program execution; display messages showing the steps of
+@sc{cvs} activity. Particularly useful with @samp{-n} to explore the
+potential impact of an unfamiliar command.
+
+@item -v
+Display version and copyright information for @sc{cvs}.
+
+@cindex CVSREAD, overriding
+@cindex Overriding CVSREAD
+@item -w
+Make new working files read-write. Overrides the
+setting of the @code{$CVSREAD} environment variable.
+Files are created read-write by default, unless @code{$CVSREAD} is
+set or @samp{-r} is given.
+
+@end table
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@node Common options
+@appendixsec Common command options
+@cindex Common options
+@cindex Right-hand options
+
+This section describes the @samp{command_options} that
+are available across several @sc{cvs} commands. These
+options are always given to the right of
+@samp{cvs_command}. Not all
+commands support all of these options; each option is
+only supported for commands where it makes sense.
+However, when a command has one of these options you
+can almost always count on the same behavior of the
+option as in other commands. (Other command options,
+which are listed with the individual commands, may have
+different behavior from one @sc{cvs} command to the other).
+
+@strong{Warning:} the @samp{history} command is an exception; it supports
+many options that conflict even with these standard options.
+
+@table @code
+@cindex Dates
+@cindex Time
+@cindex Specifying dates
+@item -D @var{date_spec}
+Use the most recent revision no later than @var{date_spec}.
+@var{date_spec} is a single argument, a date description
+specifying a date in the past.
+
+The specification is @dfn{sticky} when you use it to make a
+private copy of a source file; that is, when you get a working
+file using @samp{-D}, @sc{cvs} records the date you specified, so that
+further updates in the same directory will use the same date
+(unless you explicitly override it; @pxref{update}).
+
+A wide variety of date formats are supported by the underlying
+@sc{rcs} facilities, similar to those described in co(1), but not
+exactly the same. The @var{date_spec} is interpreted as being
+in the local timezone, unless a specific timezone is specified.
+Examples of valid date specifications include:
+
+@example
+ 1 month ago
+ 2 hours ago
+ 400000 seconds ago
+ last year
+ last Monday
+ yesterday
+ a fortnight ago
+ 3/31/92 10:00:07 PST
+ January 23, 1987 10:05pm
+ 22:00 GMT
+@end example
+
+@samp{-D} is available with the @code{checkout},
+@code{diff}, @code{export}, @code{history},
+@code{rdiff}, @code{rtag}, and @code{update} commands.
+(The @code{history} command uses this option in a
+slightly different way; @pxref{history options}).
+
+Remember to quote the argument to the @samp{-D}
+flag so that your shell doesn't interpret spaces as
+argument separators. A command using the @samp{-D}
+flag can look like this:
+
+@example
+$ cvs diff -D "1 hour ago" cvs.texinfo
+@end example
+
+@cindex Forcing a tag match
+@item -f
+When you specify a particular date or tag to @sc{cvs} commands, they
+normally ignore files that do not contain the tag (or did not
+exist prior to the date) that you specified. Use the @samp{-f} option
+if you want files retrieved even when there is no match for the
+tag or date. (The most recent revision of the file
+will be used).
+
+@need 800
+@samp{-f} is available with these commands: @code{checkout},
+@code{export}, @code{rdiff}, @code{rtag}, and @code{update}.
+
+@strong{Warning:} The @code{commit} command also has a
+@samp{-f} option, but it has a different behavior for
+that command. @xref{commit options}.
+
+@item -H
+Help; describe the options available for this command. This is
+the only option supported for all @sc{cvs} commands.
+
+@item -k @var{kflag}
+Alter the default @sc{rcs} processing of keywords.
+@xref{Keyword substitution}, for the meaning of
+@var{kflag}. Your @var{kflag} specification is
+@dfn{sticky} when you use it to create a private copy
+of a source file; that is, when you use this option
+with the @code{checkout} or @code{update} commands,
+@sc{cvs} associates your selected @var{kflag} with the
+file, and continues to use it with future update
+commands on the same file until you specify otherwise.
+
+The @samp{-k} option is available with the @code{add},
+@code{checkout}, @code{diff} and
+@code{update} commands.
+
+@item -l
+Local; run only in current working directory, rather than
+recursing through subdirectories.
+
+@strong{Warning:} this is not the same
+as the overall @samp{cvs -l} option, which you can specify to the
+left of a cvs command!
+
+Available with the following commands: @code{checkout},
+@code{commit}, @code{diff}, @code{export}, @code{log},
+@code{remove}, @code{rdiff}, @code{rtag},
+@code{status}, @code{tag}, and @code{update}.
+
+@cindex Editor, avoiding invocation of
+@cindex Avoiding editor invocation
+@item -m @var{message}
+Use @var{message} as log information, instead of
+invoking an editor.
+
+Available with the following commands: @code{add},
+@code{commit} and @code{import}.
+
+@item -n
+Do not run any checkout/commit/tag program. (A program can be
+specified to run on each of these activities, in the modules
+database (@pxref{modules}); this option bypasses it).
+
+@strong{Warning:} this is not the same as the overall @samp{cvs -n}
+option, which you can specify to the left of a cvs command!
+
+Available with the @code{checkout}, @code{commit}, @code{export},
+and @code{rtag} commands.
+
+@item -P
+Prune (remove) directories that are empty after being updated, on
+@code{checkout}, or @code{update}. Normally, an empty directory
+(one that is void of revision-controlled files) is left alone.
+Specifying @samp{-P} will cause these directories to be silently
+removed from your checked-out sources. This does not remove the
+directory from the repository, only from your checked out copy.
+Note that this option is implied by the @samp{-r} or @samp{-D}
+options of @code{checkout} and @code{export}.
+@c -- implied--
+
+@item -p
+Pipe the files retrieved from the repository to standard output,
+rather than writing them in the current directory. Available
+with the @code{checkout} and @code{update} commands.
+
+@item -W
+Specify file names that should be filtered. You can
+use this option repeatedly. The spec can be a file
+name pattern of the same type that you can specify in
+the @file{.cvswrappers} file.
+Avaliable with the following commands: @code{import},
+and @code{update}.
+
+@item -r @var{tag}
+Use the revision specified by the @var{tag} argument instead of the
+default @dfn{head} revision. As well as arbitrary tags defined
+with the @code{tag} or @code{rtag} command, two special tags are
+always available: @samp{HEAD} refers to the most recent version
+available in the repository, and @samp{BASE} refers to the
+revision you last checked out into the current working directory.
+
+The tag specification is sticky when you use this option
+with @code{checkout} or @code{update} to make your own
+copy of a file: @sc{cvs} remembers the tag and continues to use it on
+future update commands, until you specify otherwise. The
+tag can be either a symbolic or numeric tag.
+@xref{Tags}.
+
+Specifying the @samp{-q} global option along with the
+@samp{-r} command option is often useful, to suppress
+the warning messages when the @sc{rcs} history file
+does not contain the specified tag.
+
+@strong{Warning:} this is not the same as the overall `cvs -r' option,
+which you can specify to the left of a cvs command!
+
+@samp{-r} is available with the @code{checkout}, @code{commit},
+@code{diff}, @code{history}, @code{export}, @code{rdiff},
+@code{rtag}, and @code{update} commands.
+
+@end table
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@node add
+@appendixsec add---Add a new file/directory to the repository
+@cindex Add (subcommand)
+
+@itemize @bullet
+@item
+Synopsis: add [-k kflag] [-m 'message'] files@dots{}
+@item
+Requires: repository, working directory.
+@item
+Changes: working directory.
+@item
+Synonym: new
+@end itemize
+
+Use the @code{add} command to create a new file or directory in the
+source repository. The files or directories specified with @code{add}
+must already exist in the current directory (which must have been
+created with the @code{checkout} command). To add a whole new directory
+hierarchy to the source repository (for example, files received
+from a third-party vendor), use the @code{import} command
+instead. @xref{import}.
+
+If the argument to @code{add} refers to an immediate
+sub-directory, the directory is created at the correct place in
+the source repository, and the necessary @sc{cvs} administration
+files are created in your working directory. If the directory
+already exists in the source repository, @code{add} still creates
+the administration files in your version of the directory.
+This allows you to use @code{add} to add a particular directory
+to your private sources even if someone else created that
+directory after your checkout of the sources. You can do the
+following:
+
+@example
+$ mkdir new_directory
+$ cvs add new_directory
+$ cvs update new_directory
+@end example
+
+An alternate approach using @code{update} might be:
+
+@example
+$ cvs update -d new_directory
+@end example
+
+(To add any available new directories to your working directory,
+it's probably simpler to use @code{checkout} (@pxref{checkout})
+or @samp{update -d} (@pxref{update})).
+
+The added files are not placed in the source repository until you
+use @code{commit} to make the change permanent. Doing an
+@code{add} on a file that was removed with the @code{remove}
+command will resurrect the file, unless a @code{commit} command
+intervened.
+@xref{remove examples} for an example.
+
+
+Unlike most other commands @code{add} never recurses down
+directories. It cannot yet handle relative paths. Instead of
+
+@example
+$ cvs add foo/bar.c
+@end example
+
+you have to do
+
+@example
+$ cd foo
+$ cvs add bar.c
+@end example
+
+@menu
+* add options:: add options
+* add examples:: add examples
+@end menu
+
+@c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
+@node add options
+@appendixsubsec add options
+@cindex Add options
+
+There are only two options you can give to @samp{add}:
+
+@table @code
+@item -k @var{kflag}
+This option specifies the default way that this file
+will be checked out. See rcs(1) and co(1). The
+@var{kflag} argument (@pxref{Substitution modes}) is
+stored in the @sc{rcs} file and can be changed with
+@code{admin -k} (@pxref{admin options}). Specifying
+@samp{-ko} is useful for checking in binaries that
+should not have the @sc{rcs} id strings expanded.
+
+@strong{Warning:} this option is reported to be broken in
+version 1.3 and 1.3-s2 of @sc{cvs}. Use @samp{admin -k}
+after the commit instead. @xref{admin examples}.
+@c -- broken--
+
+@item -m @var{description}
+Using this option, you can give a description for the file. This
+description appears in the history log (if it is enabled,
+@pxref{history file}). It will also be saved in the @sc{rcs} history
+file inside the repository when the file is committed. The
+@code{log} command displays this description.
+
+The description can be changed using @samp{admin -t}.
+@xref{admin}.
+
+If you omit the @samp{-m @var{description}} flag, an empty string will be
+used. You will not be prompted for a description.
+@end table
+
+@c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
+@node add examples
+@appendixsubsec add examples
+
+To add the file @file{backend.c} to the repository, with a
+description, the following can be used.
+
+@example
+$ cvs add -m "Optimizer and code generation passes." backend.c
+$ cvs commit -m "Early version. Not yet compilable." backend.c
+@end example
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@node admin
+@appendixsec admin---Administration front end for rcs
+@cindex Admin (subcommand)
+
+@itemize @bullet
+@item
+Requires: repository, working directory.
+@item
+Changes: repository.
+@item
+Synonym: rcs
+@end itemize
+
+This is the @sc{cvs} interface to assorted administrative @sc{rcs}
+facilities, documented in rcs(1). @code{admin} simply passes
+all its options and arguments to the @code{rcs} command; it does
+no filtering or other processing. This command @emph{does} work
+recursively, however, so extreme care should be used.
+
+If there is a group whose name matches a compiled in
+value which defaults to @code{cvsadmin}, only members
+of that group can use @code{cvs admin}. To disallow
+@code{cvs admin} for all users, create a group with no
+users in it.
+
+@menu
+* admin options:: admin options
+* admin examples:: admin examples
+@end menu
+
+@c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
+@node admin options
+@appendixsubsec admin options
+
+Not all valid @code{rcs} options are useful together
+with @sc{cvs}. Some even makes it impossible to use
+@sc{cvs} until you undo the effect!
+
+This description of the available options is based on
+the @samp{rcs(1)} man page, but modified to suit
+readers that are more interrested in @sc{cvs} than
+@sc{rcs}.
+
+@table @code
+@item -A@var{oldfile}
+Might not work together with @sc{cvs}. Append the
+access list of @var{oldfile} to the access list of the
+@sc{rcs} file.
+
+@item -a@var{logins}
+Might not work together with @sc{cvs}. Append the
+login names appearing in the comma-separated list
+@var{logins} to the access list of the @sc{rcs} file.
+
+@item -b[@var{rev}]
+Breaks @sc{cvs}. When used with bare @sc{rcs}, this
+option sets the default branch to @var{rev}.
+If @var{rev} is omitted, the default branch is reset to
+the (dynamically) highest branch on the trunk. Use
+sticky tags instead, as in @code{cvs co -r}.
+@xref{Sticky tags}.
+
+@item -c@var{string}
+Useful with @sc{cvs}. Sets the comment leader to
+@var{string}. The comment leader is printed before
+every log message line generated by the keyword
+@code{$@asis{}Log$} (@pxref{Keyword substitution}).
+This is useful for programming languages without
+multi-line comments. @sc{Rcs} initially guesses the
+value of the comment leader from the file name
+extension when the file is first committed.
+
+@item -e[@var{logins}]
+Might not work together with @sc{cvs}. Erase the login
+names appearing in the comma-separated list
+@var{logins} from the access list of the RCS file. If
+@var{logins} is omitted, erase the entire access list.
+
+@item -I
+Run interactively, even if the standard input is not a
+terminal.
+
+@item -i
+Useless with @sc{cvs}. When using bare @sc{rcs}, this
+is used to create and initialize a new @sc{rcs} file,
+without depositing a revision.
+
+@item -k@var{subst}
+Useful with @sc{cvs}. Set the default keyword
+substitution to @var{subst}. @xref{Keyword
+substitution}. Giving an explicit @samp{-k} option to
+@code{cvs update} or @code{cvs checkout} overrides this
+default. @code{cvs export} always uses @code{-kv},
+regardless of which keyword substitution is set with
+@code{cvs admin}.
+
+@item -l[@var{rev}]
+Probably useless with @sc{cvs}. With bare @sc{rcs},
+this option can be used to lock the revision with
+number @var{rev}. If a branch is given, lock the
+latest revision on that branch. If @var{rev} is
+omitted, lock the latest revision on the default
+branch.
+
+@item -L
+Probably useless with @sc{cvs}. Used with bare
+@sc{rcs} to set locking to strict. Strict
+locking means that the owner of an RCS file is not
+exempt from locking for checkin.
+
+@cindex Changing a log message
+@cindex Replacing a log message
+@cindex Correcting a log message
+@cindex Fixing a log message
+@cindex Log message, correcting
+@item -m@var{rev}:@var{msg}
+Replace the log message of revision @var{rev} with
+@var{msg}.
+
+@item -N@var{name}[:[@var{rev}]]
+Act like @samp{-n}, except override any previous
+assignment of @var{name}.
+
+@item -n@var{name}[:[@var{rev}]]
+Associate the symbolic name @var{name} with the branch
+or revision @var{rev}. It is normally better to use
+@samp{cvs tag} or @samp{cvs rtag} instead. Delete the
+symbolic name if both @samp{:} and @var{rev} are
+omitted; otherwise, print an error message if
+@var{name} is already associated with another number.
+If @var{rev} is symbolic, it is expanded before
+association. A @var{rev} consisting of a branch number
+followed by a @samp{.} stands for the current latest
+revision in the branch. A @samp{:} with an empty
+@var{rev} stands for the current latest revision on the
+default branch, normally the trunk. For example,
+@samp{rcs -n@var{name}: RCS/*} associates @var{name} with the
+current latest revision of all the named RCS files;
+this contrasts with @samp{rcs -n@var{name}:$ RCS/*} which
+associates @var{name} with the revision numbers
+extracted from keyword strings in the corresponding
+working files.
+
+@cindex Deleting revisions
+@cindex Outdating revisions
+@cindex Saving space
+@item -o@var{range}
+Potentially useful, but dangerous, with @sc{cvs} (see below).
+Deletes (@dfn{outdates}) the revisions given by
+@var{range}. A range consisting of a single revision
+number means that revision. A range consisting of a
+branch number means the latest revision on that branch.
+A range of the form @samp{@var{rev1}:@var{rev2}} means
+revisions @var{rev1} to @var{rev2} on the same branch,
+@samp{:@var{rev}} means from the beginning of the
+branch containing @var{rev} up to and including
+@var{rev}, and @samp{@var{rev}:} means from revision
+@var{rev} to the end of the branch containing
+@var{rev}. None of the outdated revisions may have
+branches or locks.
+
+Due to the way @sc{cvs} handles branches @var{rev}
+cannot be specified symbolically if it is a branch.
+@xref{Magic branch numbers}, for an explanation.
+
+Make sure that no-one has checked out a copy of the
+revision you outdate. Strange things will happen if he
+starts to edit it and tries to check it back in. For
+this reason, this option is not a good way to take back
+a bogus commit; commit a new revision undoing the bogus
+change instead (@pxref{Merging two revisions}).
+
+@item -q
+Run quietly; do not print diagnostics.
+
+@item -s@var{state}[:@var{rev}]
+Useful with @sc{cvs}. Set the state attribute of the
+revision @var{rev} to @var{state}. If @var{rev} is a
+branch number, assume the latest revision on that
+branch. If @var{rev} is omitted, assume the latest
+revision on the default branch. Any identifier is
+acceptable for @var{state}. A useful set of states is
+@samp{Exp} (for experimental), @samp{Stab} (for
+stable), and @samp{Rel} (for released). By default,
+the state of a new revision is set to @samp{Exp} when
+it is created. The state is visible in the output from
+@var{cvs log} (@pxref{log}), and in the
+@samp{$@asis{}Log$} and @samp{$@asis{}State$} keywords
+(@pxref{Keyword substitution}).
+
+@item -t[@var{file}]
+Useful with @sc{cvs}. Write descriptive text from the
+contents of the named @var{file} into the RCS file,
+deleting the existing text. The @var{file} pathname
+may not begin with @samp{-}. If @var{file} is omitted,
+obtain the text from standard input, terminated by
+end-of-file or by a line containing @samp{.} by itself.
+Prompt for the text if interaction is possible; see
+@samp{-I}. The descriptive text can be seen in the
+output from @samp{cvs log} (@pxref{log}).
+
+@item -t-@var{string}
+Similar to @samp{-t@var{file}}. Write descriptive text
+from the @var{string} into the @sc{rcs} file, deleting
+the existing text.
+
+@item -U
+Probably useless with @sc{cvs}. Used with bare
+@sc{rcs} to set locking to non-strict. Non-strict
+locking means that the owner of a file need not lock a
+revision for checkin.
+
+@item -u[@var{rev}]
+Probably useless with @sc{cvs}. With bare @sc{rcs},
+unlock the revision with number @var{rev}. If a branch
+is given, unlock the latest revision on that branch.
+If @var{rev} is omitted, remove the latest lock held by
+the caller. Normally, only the locker of a revision
+may unlock it. Somebody else unlocking a revision
+breaks the lock. This causes a mail message to be sent
+to the original locker. The message contains a
+commentary solicited from the breaker. The commentary
+is terminated by end-of-file or by a line containing
+@code{.} by itself.
+
+@item -V@var{n}
+Emulate @sc{rcs} version @var{n}. Use -V@var{n} to make
+an @sc{rcs} file acceptable to @sc{rcs} version @var{n}
+by discarding information that would confuse version
+@var{n}.
+
+@item -x@var{suffixes}
+Useless with @sc{cvs}. Use @var{suffixes} to
+characterize RCS files.
+@end table
+
+
+@c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
+@node admin examples
+@appendixsubsec admin examples
+
+@appendixsubsubsec Outdating is dangerous
+
+First, an example of how @emph{not} to use the
+@code{admin} command. It is included to stress the
+fact that this command can be quite dangerous unless
+you know @emph{exactly} what you are doing.
+
+The @samp{-o} option can be used to @dfn{outdate} old revisions
+from the history file. If you are short on disc this option
+might help you. But think twice before using it---there is no
+way short of restoring the latest backup to undo this command!
+
+The next line is an example of a command that you would
+@emph{not} like to execute.
+
+@example
+$ cvs admin -o:R_1_02 .
+@end example
+
+The above command will delete all revisions up to, and
+including, the revision that corresponds to the tag
+R_1_02. But beware! If there are files that have not
+changed between R_1_02 and R_1_03 the file will have
+@emph{the same} numerical revision number assigned to
+the tags R_1_02 and R_1_03. So not only will it be
+impossible to retrieve R_1_02; R_1_03 will also have to
+be restored from the tapes!
+
+@need 1200
+@appendixsubsubsec Handling binary files
+@cindex Binary files (inhibit keyword expansion)
+@cindex Inhibiting keyword expansion
+@cindex Keyword expansion, inhibiting
+
+If you use @sc{cvs} to store binary files, where
+keyword strings (@pxref{Keyword substitution}) might
+accidentally appear inside the file, you should use
+@code{cvs admin -ko} to make sure that they are not
+modified automatically. Here is an example of how you
+can create a new file using the @samp{-ko} flag:
+
+@example
+$ echo '$@asis{}Id$' > kotest
+$ cvs add -m"A test file" kotest
+$ cvs ci -m"First checkin; contains a keyword" kotest
+$ cvs admin -ko kotest
+$ rm kotest
+$ cvs update kotest
+@end example
+
+When you check in the file @file{kotest} the keywords
+are expanded. (Try the above example, and do a
+@code{cat kotest} after every command!) The @code{cvs
+admin -ko} command sets the default keyword
+substitution method for this file, but it does not
+alter the working copy of the file that you have. The
+easiest way to get the unexpanded version of
+@file{kotest} is to remove it and check it out again.
+
+@appendixsubsubsec Comment leaders
+@cindex Comment leader
+@cindex Log keyword, selecting comment leader
+@cindex Nroff (selecting comment leader)
+
+If you use the @code{$@asis{}Log$} keyword and you do
+not agree with the guess for comment leader that
+@sc{cvs} has done, you can enforce your will with
+@code{cvs admin -c}. This might be suitable for
+@code{nroff} source:
+
+@example
+$ cvs admin -c'.\" ' *.man
+$ rm *.man
+$ cvs update
+@end example
+
+The two last steps are to make sure that you get the
+versions with correct comment leaders in your working
+files.
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@node checkout
+@appendixsec checkout---Check out sources for editing
+@cindex Checkout (subcommand)
+@cindex Co (subcommand)
+
+@itemize @bullet
+@item
+Synopsis: checkout [options] modules@dots{}
+@item
+Requires: repository.
+@item
+Changes: working directory.
+@item
+Synonyms: co, get
+@end itemize
+
+Make a working directory containing copies of the
+source files specified by @var{modules}. You must execute
+@code{checkout} before using most of the other @sc{cvs}
+commands, since most of them operate on your working
+directory.
+
+The @var{modules} part of the command are either
+symbolic names for some
+collection of source directories and files, or paths to
+directories or files in the repository. The symbolic
+names are defined in the @samp{modules} file.
+@xref{modules}.
+
+Depending on the modules you specify, @code{checkout} may
+recursively create directories and populate them with
+the appropriate source files. You can then edit these
+source files at any time (regardless of whether other
+software developers are editing their own copies of the
+sources); update them to include new changes applied by
+others to the source repository; or commit your work as
+a permanent change to the source repository.
+
+Note that @code{checkout} is used to create
+directories. The top-level directory created is always
+added to the directory where @code{checkout} is
+invoked, and usually has the same name as the specified
+module. In the case of a module alias, the created
+sub-directory may have a different name, but you can be
+sure that it will be a sub-directory, and that
+@code{checkout} will show the relative path leading to
+each file as it is extracted into your private work
+area (unless you specify the @samp{-Q} global option).
+
+Running @code{checkout} on a directory that was already
+built by a prior @code{checkout} is also permitted, and
+has the same effect as specifying the @samp{-d} option
+to the @code{update} command, that is, any new
+directories that have been created in the repository
+will appear in your work area. @xref{update}.
+
+@menu
+* checkout options:: checkout options
+* checkout examples:: checkout examples
+@end menu
+
+@c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
+@node checkout options
+@appendixsubsec checkout options
+
+These standard options are supported by @code{checkout}
+(@pxref{Common options}, for a complete description of
+them):
+
+@table @code
+@item -D @var{date}
+Use the most recent revision no later than @var{date}.
+This option is sticky, and implies @samp{-P}.
+
+@item -f
+Only useful with the @samp{-D @var{date}} or @samp{-r
+@var{tag}} flags. If no matching revision is found,
+retrieve the most recent revision (instead of ignoring
+the file).
+
+@item -k @var{kflag}
+Process @sc{rcs} keywords according to @var{kflag}. See
+co(1). This option is sticky; future updates of
+this file in this working directory will use the same
+@var{kflag}. The @code{status} command can be viewed
+to see the sticky options. @xref{status}.
+
+@item -l
+Local; run only in current working directory.
+
+@item -n
+Do not run any checkout program (as specified
+with the @samp{-o} option in the modules file;
+@pxref{modules}).
+
+@item -P
+Prune empty directories.
+
+@item -p
+Pipe files to the standard output.
+
+@item -r @var{tag}
+Use revision @var{tag}. This option is sticky, and implies @samp{-P}.
+@end table
+
+In addition to those, you can use these special command
+options with @code{checkout}:
+
+@table @code
+@item -A
+Reset any sticky tags, dates, or @samp{-k} options.
+(If you get a working file using one of the @samp{-r},
+@samp{-D}, or @samp{-k} options, @sc{cvs} remembers the
+corresponding tag, date, or @var{kflag} and continues using
+it for future updates; use the @samp{-A} option to make
+@sc{cvs} forget these specifications, and retrieve the
+`head' revision of the file).
+
+@item -c
+Copy the module file, sorted, to the standard output,
+instead of creating or modifying any files or
+directories in your working directory.
+
+@item -d @var{dir}
+Create a directory called @var{dir} for the working
+files, instead of using the module name. Unless you
+also use @samp{-N}, the paths created under @var{dir}
+will be as short as possible.
+
+@item -j @var{tag}
+With two @samp{-j} options, merge changes from the
+revision specified with the first @samp{-j} option to
+the revision specified with the second @samp{j} option,
+into the working directory.
+
+With one @samp{-j} option, merge changes from the
+ancestor revision to the revision specified with the
+@samp{-j} option, into the working directory. The
+ancestor revision is the common ancestor of the
+revision which the working directory is based on, and
+the revision specified in the @samp{-j} option.
+
+In addition, each -j option can contain an optional
+date specification which, when used with branches, can
+limit the chosen revision to one within a specific
+date. An optional date is specified by adding a colon
+(:) to the tag:
+@samp{-j@var{Symbolic_Tag}:@var{Date_Specifier}}.
+
+@xref{Merging}.
+
+@item -N
+Only useful together with @samp{-d @var{dir}}. With this
+option, @sc{cvs} will not shorten module paths in your
+working directory. (Normally, @sc{cvs} shortens paths as
+much as possible when you specify an explicit target
+directory).
+
+@item -s
+Like @samp{-c}, but include the status of all modules,
+and sort it by the status string. @xref{modules}, for
+info about the @samp{-s} option that is used inside the
+modules file to set the module status.
+@end table
+
+@c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
+@node checkout examples
+@appendixsubsec checkout examples
+
+Get a copy of the module @samp{tc}:
+
+@example
+$ cvs checkout tc
+@end example
+
+Get a copy of the module @samp{tc} as it looked one day
+ago:
+
+@example
+$ cvs checkout -D yesterday tc
+@end example
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@node commit
+@appendixsec commit---Check files into the repository
+@cindex Commit (subcommand)
+
+@itemize @bullet
+@item
+Version 1.3 Synopsis: commit [-lnR] [-m 'log_message' |
+-f file] [-r revision] [files@dots{}]
+@item
+Version 1.3.1 Synopsis: commit [-lnRf] [-m 'log_message' |
+-F file] [-r revision] [files@dots{}]
+@c -- rename-f-F--
+@item
+Requires: working directory, repository.
+@item
+Changes: repository.
+@item
+Synonym: ci
+@end itemize
+
+@strong{Warning:} The @samp{-f @var{file}} option will
+probably be renamed to @samp{-F @var{file}}, and @samp{-f}
+will be given a new behavior in future releases of @sc{cvs}.
+@c -- rename-f-F--
+
+Use @code{commit} when you want to incorporate changes
+from your working source files into the source
+repository.
+
+If you don't specify particular files to commit, all of
+the files in your working current directory are
+examined. @code{commit} is careful to change in the
+repository only those files that you have really
+changed. By default (or if you explicitly specify the
+@samp{-R} option), files in subdirectories are also
+examined and committed if they have changed; you can
+use the @samp{-l} option to limit @code{commit} to the
+current directory only.
+
+@code{commit} verifies that the selected files are up
+to date with the current revisions in the source
+repository; it will notify you, and exit without
+committing, if any of the specified files must be made
+current first with @code{update} (@pxref{update}).
+@code{commit} does not call the @code{update} command
+for you, but rather leaves that for you to do when the
+time is right.
+
+When all is well, an editor is invoked to allow you to
+enter a log message that will be written to one or more
+logging programs (@pxref{modules}, and @pxref{loginfo})
+and placed in the @sc{rcs} history file inside the
+repository. This log message can be retrieved with the
+@code{log} command; @xref{log}. You can specify the
+log message on the command line with the @samp{-m
+@var{message}} option, and thus avoid the editor invocation,
+or use the @samp{-f @var{file}} option to specify
+@c -- rename-f-F--
+that the argument file contains the log message.
+
+@menu
+* commit options:: commit options
+* commit examples:: commit examples
+@end menu
+
+@c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
+@node commit options
+@appendixsubsec commit options
+
+These standard options are supported by @code{commit}
+(@pxref{Common options}, for a complete description of
+them):
+
+@table @code
+@item -l
+Local; run only in current working directory.
+
+@item -n
+Do not run any module program.
+
+@item -R
+Commit directories recursively. This is on by default.
+
+@item -r @var{revision}
+Commit to @var{revision}. @var{revision} must be
+either a branch, or a revision on the main trunk that
+is higher than any existing revision number. You
+cannot commit to a specific revision on a branch.
+@end table
+
+@code{commit} also supports these options:
+
+@table @code
+@item -F @var{file}
+This option is present in @sc{cvs} releases 1.3-s3 and
+later. Read the log message from @var{file}, instead
+of invoking an editor.
+
+@item -f
+@c -- rename-f-F--
+This option is present in @sc{cvs} 1.3-s3 and later releases
+of @sc{cvs}. Note that this is not the standard behavior of
+the @samp{-f} option as defined in @xref{Common options}.
+
+Force @sc{cvs} to commit a new revision even if you haven't
+made any changes to the file. If the current revision
+of @var{file} is 1.7, then the following two commands
+are equivalent:
+
+@example
+$ cvs commit -f @var{file}
+$ cvs commit -r 1.8 @var{file}
+@end example
+
+@item -f @var{file}
+@c -- rename-f-F--
+This option is present in @sc{cvs} releases 1.3, 1.3-s1 and
+1.3-s2. Note that this is not the standard behavior of
+the @samp{-f} option as defined in @xref{Common options}.
+
+Read the log message from @var{file}, instead
+of invoking an editor.
+
+@item -m @var{message}
+Use @var{message} as the log message, instead of
+invoking an editor.
+@end table
+
+@need 2000
+@c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
+@node commit examples
+@appendixsubsec commit examples
+
+@appendixsubsubsec New major release number
+
+When you make a major release of your product, you
+might want the revision numbers to track your major
+release number. You should normally not care about
+the revision numbers, but this is a thing that many
+people want to do, and it can be done without doing any
+harm.
+
+To bring all your files up to the @sc{rcs} revision 3.0
+(including those that haven't changed), you might do:
+
+@example
+$ cvs commit -r 3.0
+@end example
+
+Note that it is generally a bad idea to try to make the
+@sc{rcs} revision number equal to the current release number
+of your product. You should think of the revision
+number as an internal number that the @sc{cvs} package
+maintains, and that you generally never need to care
+much about. Using the @code{tag} and @code{rtag}
+commands you can give symbolic names to the releases
+instead. @xref{tag} and @xref{rtag}.
+
+Note that the number you specify with @samp{-r} must be
+larger than any existing revision number. That is, if
+revision 3.0 exists, you cannot @samp{cvs commit
+-r 1.3}.
+
+@appendixsubsubsec Committing to a branch
+
+You can commit to a branch revision (one that has an
+even number of dots) with the @samp{-r} option. To
+create a branch revision, use the @samp{-b} option
+of the @code{rtag} or @code{tag} commands (@pxref{tag}
+or @pxref{rtag}). Then, either @code{checkout} or
+@code{update} can be used to base your sources on the
+newly created branch. From that point on, all
+@code{commit} changes made within these working sources
+will be automatically added to a branch revision,
+thereby not disturbing main-line development in any
+way. For example, if you had to create a patch to the
+1.2 version of the product, even though the 2.0 version
+is already under development, you might do:
+
+@example
+$ cvs rtag -b -r FCS1_2 FCS1_2_Patch product_module
+$ cvs checkout -r FCS1_2_Patch product_module
+$ cd product_module
+[[ hack away ]]
+$ cvs commit
+@end example
+
+@noindent
+This works automatically since the @samp{-r} option is
+sticky.
+
+@appendixsubsubsec Creating the branch after editing
+
+Say you have been working on some extremely
+experimental software, based on whatever revision you
+happened to checkout last week. If others in your
+group would like to work on this software with you, but
+without disturbing main-line development, you could
+commit your change to a new branch. Others can then
+checkout your experimental stuff and utilize the full
+benefit of @sc{cvs} conflict resolution. The scenario might
+look like:
+
+@example
+[[ hacked sources are present ]]
+$ cvs tag -b EXPR1
+$ cvs update -r EXPR1
+$ cvs commit
+@end example
+
+The @code{update} command will make the @samp{-r
+EXPR1} option sticky on all files. Note that your
+changes to the files will never be removed by the
+@code{update} command. The @code{commit} will
+automatically commit to the correct branch, because the
+@samp{-r} is sticky. You could also do like this:
+
+@example
+[[ hacked sources are present ]]
+$ cvs tag -b EXPR1
+$ cvs commit -r EXPR1
+@end example
+
+@noindent
+but then, only those files that were changed by you
+will have the @samp{-r EXPR1} sticky flag. If you hack
+away, and commit without specifying the @samp{-r EXPR1}
+flag, some files may accidentally end up on the main
+trunk.
+
+To work with you on the experimental change, others
+would simply do
+
+@example
+$ cvs checkout -r EXPR1 whatever_module
+@end example
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@node diff
+@appendixsec diff---Run diffs between revisions
+@cindex Diff (subcommand)
+
+@itemize @bullet
+@item
+Synopsis: diff [-l] [rcsdiff_options] [[-r rev1 | -D date1] [-r rev2 | -D date2]] [files@dots{}]
+@item
+Requires: working directory, repository.
+@item
+Changes: nothing.
+@end itemize
+
+The @code{diff} command is used to compare different
+revisions of files. The default action is to compare
+your working files with the revisions they were based
+on, and report any differences that are found.
+
+If any file names are given, only those files are
+compared. If any directories are given, all files
+under them will be compared.
+
+The exit status will be 0 if no differences were found,
+1 if some differences were found, and 2 if any error
+occurred.
+
+@menu
+* diff options:: diff options
+* diff examples:: diff examples
+@end menu
+
+@c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
+@node diff options
+@appendixsubsec diff options
+
+These standard options are supported by @code{diff}
+(@pxref{Common options}, for a complete description of
+them):
+
+@table @code
+@item -D @var{date}
+Use the most recent revision no later than @var{date}.
+See @samp{-r} for how this affects the comparison.
+
+@sc{cvs} can be configured to pass the @samp{-D} option
+through to @code{rcsdiff} (which in turn passes it on
+to @code{diff}. @sc{Gnu} diff uses @samp{-D} as a way to
+put @code{cpp}-style @samp{#define} statements around the output
+differences. There is no way short of testing to
+figure out how @sc{cvs} was configured. In the default
+configuration @sc{cvs} will use the @samp{-D @var{date}} option.
+
+@item -k @var{kflag}
+Process @sc{rcs} keywords according to @var{kflag}. See
+co(1).
+
+@item -l
+Local; run only in current working directory.
+
+@item -R
+Examine directories recursively. This option is on by
+default.
+
+@item -r @var{tag}
+Compare with revision @var{tag}. Zero, one or two
+@samp{-r} options can be present. With no @samp{-r}
+option, the working file will be compared with the
+revision it was based on. With one @samp{-r}, that
+revision will be compared to your current working file.
+With two @samp{-r} options those two revisions will be
+compared (and your working file will not affect the
+outcome in any way).
+
+One or both @samp{-r} options can be replaced by a
+@samp{-D @var{date}} option, described above.
+@end table
+
+Any other options that are found are passed through to
+@code{rcsdiff}, which in turn passes them to
+@code{diff}. The exact meaning of the options depends
+on which @code{diff} you are using. The long options
+introduced in @sc{gnu} diff 2.0 are not yet supported in
+@sc{cvs}. See the documentation for your @code{diff} to see
+which options are supported.
+
+@c -- Document some common useful diff options, such as
+@c -u and -c.
+@c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
+@node diff examples
+@appendixsubsec diff examples
+
+The following line produces a Unidiff (@samp{-u} flag)
+between revision 1.14 and 1.19 of
+@file{backend.c}. Due to the @samp{-kk} flag no
+keywords are substituted, so differences that only depend
+on keyword substitution are ignored.
+
+@example
+$ cvs diff -kk -u -r 1.14 -r 1.19 backend.c
+@end example
+
+Suppose the experimental branch EXPR1 was based on a
+set of files tagged RELEASE_1_0. To see what has
+happened on that branch, the following can be used:
+
+@example
+$ cvs diff -r RELEASE_1_0 -r EXPR1
+@end example
+
+A command like this can be used to produce a context
+diff between two releases:
+
+@example
+$ cvs diff -c -r RELEASE_1_0 -r RELEASE_1_1 > diffs
+@end example
+
+If you are maintaining ChangeLogs, a command like the following
+just before you commit your changes may help you write
+the ChangeLog entry. All local modifications that have
+not yet been committed will be printed.
+
+@example
+$ cvs diff -u | less
+@end example
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@node export
+@appendixsec export---Export sources from CVS, similar to checkout
+@cindex Export (subcommand)
+
+@itemize @bullet
+@item
+Synopsis: export [-flNn] -r rev|-D date [-d dir] module@dots{}
+@item
+Requires: repository.
+@item
+Changes: current directory.
+@end itemize
+
+This command is a variant of @code{checkout}; use it
+when you want a copy of the source for module without
+the @sc{cvs} administrative directories. For example, you
+might use @code{export} to prepare source for shipment
+off-site. This command requires that you specify a
+date or tag (with @samp{-D} or @samp{-r}), so that you
+can count on reproducing the source you ship to others.
+
+The keyword substitution option @samp{-kv} is always set when
+export is used. This causes any @sc{rcs} keywords to be
+expanded such that an import done at some other site
+will not lose the keyword revision information. There
+is no way to override this. Note that this breaks the
+@code{ident} command (which is part of the @sc{rcs}
+suite---see ident(1)) which looks for @sc{rcs} keyword
+strings. If you want to be able to use @code{ident}
+you must use @code{checkout} instead.
+
+@menu
+* export options:: export options
+@end menu
+
+@c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
+@node export options
+@appendixsubsec export options
+
+These standard options are supported by @code{export}
+(@pxref{Common options}, for a complete description of
+them):
+
+@table @code
+@item -D @var{date}
+Use the most recent revision no later than @var{date}.
+
+@item -f
+If no matching revision is found, retrieve the most
+recent revision (instead of ignoring the file).
+
+@item -l
+Local; run only in current working directory.
+
+@item -n
+Do not run any checkout program.
+
+@item -R
+Export directories recursively. This is on by default.
+
+@item -r @var{tag}
+Use revision @var{tag}.
+@end table
+
+In addition, these options (that are common to
+@code{checkout} and @code{export}) are also supported:
+
+@table @code
+@item -d @var{dir}
+Create a directory called @var{dir} for the working
+files, instead of using the module name. Unless you
+also use @samp{-N}, the paths created under @var{dir}
+will be as short as possible.
+
+@item -N
+Only useful together with @samp{-d @var{dir}}. With this
+option, @sc{cvs} will not shorten module paths in your
+working directory. (Normally, @sc{cvs} shortens paths as
+much as possible when you specify an explicit target
+directory.)
+@end table
+
+@ignore
+@c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
+@c @node export examples
+@appendixsubsec export examples
+
+Contributed examples are gratefully accepted.
+@c -- Examples here!!
+@end ignore
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@node history
+@appendixsec history---Show status of files and users
+@cindex History (subcommand)
+
+@itemize @bullet
+@item
+Synopsis: history [-report] [-flags] [-options args] [files@dots{}]
+@item
+Requires: the file @file{$CVSROOT/CVSROOT/history}
+@item
+Changes: nothing.
+@end itemize
+
+@sc{cvs} can keep a history file that tracks each use of the
+@code{checkout}, @code{commit}, @code{rtag},
+@code{update}, and @code{release} commands. You can
+use @code{history} to display this information in
+various formats.
+
+Logging must be enabled by creating the file
+@file{$CVSROOT/CVSROOT/history}.
+
+@strong{Warning:} @code{history} uses @samp{-f}, @samp{-l},
+@samp{-n}, and @samp{-p} in ways that conflict with the
+normal use inside @sc{cvs} (@pxref{Common options}).
+
+@menu
+* history options:: history options
+@end menu
+
+@c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
+@node history options
+@appendixsubsec history options
+
+Several options (shown above as @samp{-report}) control what
+kind of report is generated:
+
+@table @code
+@item -c
+Report on each time commit was used (i.e., each time
+the repository was modified).
+
+@item -e
+Everything (all record types); equivalent to specifying
+@samp{-xMACFROGWUT}.
+
+@item -m @var{module}
+Report on a particular module. (You can meaningfully
+use @samp{-m} more than once on the command line.)
+
+@item -o
+Report on checked-out modules.
+
+@item -T
+Report on all tags.
+
+@item -x @var{type}
+Extract a particular set of record types @var{type} from the @sc{cvs}
+history. The types are indicated by single letters,
+which you may specify in combination.
+
+Certain commands have a single record type:
+
+@table @code
+@item F
+release
+@item O
+checkout
+@item T
+rtag
+@end table
+
+@noindent
+One of four record types may result from an update:
+
+@table @code
+@item C
+A merge was necessary but collisions were
+detected (requiring manual merging).
+@item G
+A merge was necessary and it succeeded.
+@item U
+A working file was copied from the repository.
+@item W
+The working copy of a file was deleted during
+update (because it was gone from the repository).
+@end table
+
+@noindent
+One of three record types results from commit:
+
+@table @code
+@item A
+A file was added for the first time.
+@item M
+A file was modified.
+@item R
+A file was removed.
+@end table
+@end table
+
+The options shown as @samp{-flags} constrain or expand
+the report without requiring option arguments:
+
+@table @code
+@item -a
+Show data for all users (the default is to show data
+only for the user executing @code{history}).
+
+@item -l
+Show last modification only.
+
+@item -w
+Show only the records for modifications done from the
+same working directory where @code{history} is
+executing.
+@end table
+
+The options shown as @samp{-options @var{args}} constrain the report
+based on an argument:
+
+@table @code
+@item -b @var{str}
+Show data back to a record containing the string
+@var{str} in either the module name, the file name, or
+the repository path.
+
+@item -D @var{date}
+Show data since @var{date}. This is slightly different
+from the normal use of @samp{-D @var{date}}, which
+selects the newest revision older than @var{date}.
+
+@item -p @var{repository}
+Show data for a particular source repository (you
+can specify several @samp{-p} options on the same command
+line).
+
+@item -r @var{rev}
+Show records referring to revisions since the revision
+or tag named @var{rev} appears in individual @sc{rcs}
+files. Each @sc{rcs} file is searched for the revision or
+tag.
+
+@item -t @var{tag}
+Show records since tag @var{tag} was last added to the the
+history file. This differs from the @samp{-r} flag
+above in that it reads only the history file, not the
+@sc{rcs} files, and is much faster.
+
+@item -u @var{name}
+Show records for user @var{name}.
+@end table
+
+@ignore
+@c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
+@c @node history examples
+@appendixsubsec history examples
+
+Contributed examples will gratefully be accepted.
+@c -- Examples here!
+@end ignore
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@node import
+@appendixsec import---Import sources into CVS, using vendor branches
+@cindex Import (subcommand)
+
+@itemize @bullet
+@item
+Synopsis: import [-options] repository vendortag releasetag@dots{}
+@item
+Requires: Repository, source distribution directory.
+@item
+Changes: repository.
+@end itemize
+
+Use @code{import} to incorporate an entire source
+distribution from an outside source (e.g., a source
+vendor) into your source repository directory. You can
+use this command both for initial creation of a
+repository, and for wholesale updates to the module
+from the outside source. @xref{Tracking sources}, for
+a discussion on this subject.
+
+The @var{repository} argument gives a directory name
+(or a path to a directory) under the @sc{cvs} root directory
+for repositories; if the directory did not exist,
+import creates it.
+
+When you use import for updates to source that has been
+modified in your source repository (since a prior
+import), it will notify you of any files that conflict
+in the two branches of development; use @samp{checkout
+-j} to reconcile the differences, as import instructs
+you to do.
+
+By default, certain file names are ignored during
+@code{import}: names associated with @sc{cvs}
+administration, or with other common source control
+systems; common names for patch files, object files,
+archive files, and editor backup files; and other names
+that are usually artifacts of assorted utilities.
+Currently, the default list of ignored files includes
+files matching these names:
+
+@example
+ RCSLOG RCS SCCS
+ CVS* cvslog.*
+ tags TAGS
+ .make.state .nse_depinfo
+ *~ #* .#* ,*
+ *.old *.bak *.BAK *.orig *.rej .del-*
+ *.a *.o *.so *.Z *.elc *.ln
+ core
+@end example
+
+If the file @file{$CVSROOT/CVSROOT/cvsignore} exists,
+any files whose names match the specifications in that
+file will also be ignored.
+
+If the file @file{$CVSROOT/CVSROOT/cvswrappers} exists,
+any file whose names match the specifications in that
+file will be treated as packages and the appropriate
+filtering will be performed on the file/directory
+before being imported, @xref{Wrappers}.
+
+The outside source is saved in a first-level @sc{rcs}
+branch, by default 1.1.1. Updates are leaves of this
+branch; for example, files from the first imported
+collection of source will be revision 1.1.1.1, then
+files from the first imported update will be revision
+1.1.1.2, and so on.
+
+At least three arguments are required.
+@var{repository} is needed to identify the collection
+of source. @var{vendortag} is a tag for the entire
+branch (e.g., for 1.1.1). You must also specify at
+least one @var{releasetag} to identify the files at
+the leaves created each time you execute @code{import}.
+
+@menu
+* import options:: import options
+* import examples:: import examples
+@end menu
+
+@c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
+@node import options
+@appendixsubsec import options
+
+This standard option is supported by @code{import}
+(@pxref{Common options}, for a complete description):
+
+@table @code
+@item -m @var{message}
+Use @var{message} as log information, instead of
+invoking an editor.
+@end table
+
+There are three additional special options.
+
+@table @code
+@item -b @var{branch}
+Specify a first-level branch other than 1.1.1. Unless
+the @samp{-b @var{branch}} flag is given, revisions will
+@emph{always} be made to the branch 1.1.1---even if a
+@var{vendortag} that matches another branch is given!
+What happens in that case, is that the tag will be
+reset to 1.1.1. Warning: This behavior might change
+in the future.
+
+@item -k @var{subst}
+Indicate the RCS keyword expansion mode desired. This setting will
+apply to all files created during the import, but not to any files that
+previously existed in the repository. See co(1) for a complete list of
+valid @samp{-k} settings.
+
+If you are checking in sources that contain @sc{rcs} keywords, and you
+wish those keywords to remain intact, use the @samp{-ko} flag when
+importing the files. This setting indicates that no keyword expansion
+is to be performed by @sc{rcs} when checking files out. It is also
+useful for checking in binaries.
+
+@item -I @var{name}
+Specify file names that should be ignored during
+import. You can use this option repeatedly. To avoid
+ignoring any files at all (even those ignored by
+default), specify `-I !'.
+
+@var{name} can be a file name pattern of the same type
+that you can specify in the @file{.cvsignore} file.
+@xref{cvsignore}.
+@c -- Is this really true?
+
+@item -W @var{spec}
+Specify file names that should be filtered during
+import. You can use this option repeatedly.
+
+@var{spec} can be a file name pattern of the same type
+that you can specify in the @file{.cvswrappers}
+file. @xref{Wrappers}.
+@end table
+
+@c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
+@node import examples
+@appendixsubsec import examples
+
+@xref{Tracking sources}, and @xref{From files}.
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@node log
+@appendixsec log---Print out 'rlog' information for files
+@cindex Log (subcommand)
+
+@itemize @bullet
+@item
+Synopsis: log [-l] rlog-options [files@dots{}]
+@item
+Requires: repository, working directory.
+@item
+Changes: nothing.
+@item
+Synonym: rlog
+@end itemize
+
+Display log information for files. @code{log} calls
+the @sc{rcs} utility @code{rlog}, which prints all available
+information about the @sc{rcs} history file. This includes
+the location of the @sc{rcs} file, the @dfn{head} revision
+(the latest revision on the trunk), all symbolic names (tags)
+and some other things. For each revision, the revision
+number, the author, the number of lines added/deleted and
+the log message are printed. All times are displayed in
+Coordinated Universal Time (UTC). (Other parts of @sc{cvs}
+print times in the local timezone).
+@c -- timezone--
+
+@menu
+* log options:: log options
+* log examples:: log examples
+@end menu
+
+@c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
+@node log options
+@appendixsubsec log options
+
+Only one option is interpreted by @sc{cvs} and not passed on to @code{rlog}:
+
+@table @code
+@item -l
+Local; run only in current working directory. (Default
+is to run recursively).
+@end table
+
+By default, @code{rlog} prints all information that is
+available. All other options (including those that
+normally behave differently) are passed through to
+@code{rlog} and restrict the output. See rlog(1) for a
+complete description of options. This incomplete list
+(which is a slightly edited extract from rlog(1)) lists
+all options that are useful in conjunction with @sc{cvs}.
+
+@strong{Please note:} There can be no space between the option
+and its argument, since @code{rlog} parses its options
+in a different way than @sc{cvs}.
+
+@table @code
+@item -b
+Print information about the revisions on the default
+branch, normally the highest branch on the trunk.
+
+@item -d@var{dates}
+Print information about revisions with a checkin
+date/time in the range given by the
+semicolon-separated list of dates. The following table
+explains the available range formats:
+
+@table @code
+@item @var{d1}<@var{d2}
+@itemx @var{d2}>@var{d1}
+Select the revisions that were deposited between
+@var{d1} and @var{d2} inclusive.
+
+@item <@var{d}
+@itemx @var{d}>
+Select all revisions dated @var{d} or earlier.
+
+@item @var{d}<
+@itemx >@var{d}
+Select all revisions dated @var{d} or later.
+
+@item @var{d}
+Select the single, latest revision dated @var{d} or
+earlier.
+@end table
+
+The date/time strings @var{d}, @var{d1}, and @var{d2}
+are in the free format explained in co(1). Quoting is
+normally necessary, especially for < and >. Note that
+the separator is a semicolon (;).
+
+@item -h
+Print only the @sc{rcs} pathname, working pathname, head,
+default branch, access list, locks, symbolic names, and
+suffix.
+
+@item -N
+Do not print the list of tags for this file. This
+option can be very useful when your site uses a lot of
+tags, so rather than "more"'ing over 3 pages of tag
+information, the log information is presented without
+tags at all.
+
+@item -R
+Print only the name of the @sc{rcs} history file.
+
+@item -r@var{revisions}
+Print information about revisions given in the
+comma-separated list @var{revisions} of revisions and
+ranges. The following table explains the available
+range formats:
+
+@table @code
+@item @var{rev1}:@var{rev2}
+Revisions @var{rev1} to @var{rev2} (which must be on
+the same branch).
+
+@item :@var{rev}
+Revisions from the beginning of the branch up to
+and including @var{rev}.
+
+@item @var{rev}:
+Revisions starting with @var{rev} to the end of the
+branch containing @var{rev}.
+
+@item @var{branch}
+An argument that is a branch means all revisions on
+that branch. You can unfortunately not specify a
+symbolic branch here. You must specify the numeric
+branch number. @xref{Magic branch numbers}, for an
+explanation.
+
+@item @var{branch1}:@var{branch2}
+A range of branches means all revisions
+on the branches in that range.
+
+@item @var{branch}.
+The latest revision in @var{branch}.
+@end table
+
+A bare @samp{-r} with no revisions means the latest
+revision on the default branch, normally the trunk.
+
+@item -s@var{states}
+Print information about revisions whose state
+attributes match one of the states given in the
+comma-separated list @var{states}.
+
+@item -t
+Print the same as @samp{-h}, plus the descriptive text.
+
+@item -w@var{logins}
+Print information about revisions checked in by users
+with login names appearing in the comma-separated list
+@var{logins}. If @var{logins} is omitted, the user's
+login is assumed.
+@end table
+
+@code{rlog} prints the intersection of the revisions
+selected with the options @samp{-d}, @samp{-l},
+@samp{-s}, and @samp{-w}, intersected with the union of
+the revisions selected by @samp{-b} and @samp{-r}.
+
+@c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
+@node log examples
+@appendixsubsec log examples
+
+Contributed examples are gratefully accepted.
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@node rdiff
+@appendixsec rdiff---'patch' format diffs between releases
+@cindex Rdiff (subcommand)
+
+@itemize @bullet
+@item
+rdiff [-flags] [-V vn] [-r t|-D d [-r t2|-D d2]] modules@dots{}
+@item
+Requires: repository.
+@item
+Changes: nothing.
+@item
+Synonym: patch
+@end itemize
+
+Builds a Larry Wall format patch(1) file between two
+releases, that can be fed directly into the patch
+program to bring an old release up-to-date with the new
+release. (This is one of the few @sc{cvs} commands that
+operates directly from the repository, and doesn't
+require a prior checkout.) The diff output is sent to
+the standard output device.
+
+You can specify (using the standard @samp{-r} and
+@samp{-D} options) any combination of one or two
+revisions or dates. If only one revision or date is
+specified, the patch file reflects differences between
+that revision or date and the current head revisions in
+the @sc{rcs} file.
+
+Note that if the software release affected is contained
+in more than one directory, then it may be necessary to
+specify the @samp{-p} option to the patch command when
+patching the old sources, so that patch is able to find
+the files that are located in other directories.
+
+@menu
+* rdiff options:: rdiff options
+* rdiff examples:: rdiff examples
+@end menu
+
+@c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
+@node rdiff options
+@appendixsubsec rdiff options
+
+These standard options are supported by @code{rdiff}
+(@pxref{Common options}, for a complete description of
+them):
+
+@table @code
+@item -D @var{date}
+Use the most recent revision no later than @var{date}.
+
+@item -f
+If no matching revision is found, retrieve the most
+recent revision (instead of ignoring the file).
+
+@item -l
+Local; don't descend subdirectories.
+
+@item -r @var{tag}
+Use revision @var{tag}.
+@end table
+
+In addition to the above, these options are available:
+
+@table @code
+@item -c
+Use the context diff format. This is the default format.
+
+@item -s
+Create a summary change report instead of a patch. The
+summary includes information about files that were
+changed or added between the releases. It is sent to
+the standard output device. This is useful for finding
+out, for example, which files have changed between two
+dates or revisions.
+
+@item -t
+A diff of the top two revisions is sent to the standard
+output device. This is most useful for seeing what the
+last change to a file was.
+
+@item -u
+Use the unidiff format for the context diffs.
+This option is not available if your diff does not
+support the unidiff format. Remember that old versions
+of the @code{patch} program can't handle the unidiff
+format, so if you plan to post this patch to the net
+you should probably not use @samp{-u}.
+
+@item -V @var{vn}
+Expand @sc{rcs} keywords according to the rules current in
+@sc{rcs} version @var{vn} (the expansion format changed with
+@sc{rcs} version 5).
+@end table
+
+@c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
+@node rdiff examples
+@appendixsubsec rdiff examples
+
+Suppose you receive mail from @t{foo@@bar.com} asking for an
+update from release 1.2 to 1.4 of the tc compiler. You
+have no such patches on hand, but with @sc{cvs} that can
+easily be fixed with a command such as this:
+
+@example
+$ cvs rdiff -c -r FOO1_2 -r FOO1_4 tc | \
+$$ Mail -s 'The patches you asked for' foo@@bar.com
+@end example
+
+Suppose you have made release 1.3, and forked a branch
+called @samp{R_1_3fix} for bugfixes. @samp{R_1_3_1}
+corresponds to release 1.3.1, which was made some time
+ago. Now, you want to see how much development has been
+done on the branch. This command can be used:
+
+@example
+$ cvs patch -s -r R_1_3_1 -r R_1_3fix module-name
+cvs rdiff: Diffing module-name
+File ChangeLog,v changed from revision 1.52.2.5 to 1.52.2.6
+File foo.c,v changed from revision 1.52.2.3 to 1.52.2.4
+File bar.h,v changed from revision 1.29.2.1 to 1.2
+@end example
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@node release
+@appendixsec release---Indicate that a Module is no longer in use
+@cindex Release (subcommand)
+
+@itemize @bullet
+@item
+release [-d] modules@dots{}
+@item
+Requires: Working directory.
+@item
+Changes: Working directory, history log.
+@end itemize
+
+This command is meant to safely cancel the effect of
+@samp{cvs checkout}. Since @sc{cvs} doesn't lock files, it
+isn't strictly necessary to use this command. You can
+always simply delete your working directory, if you
+like; but you risk losing changes you may have
+forgotten, and you leave no trace in the @sc{cvs} history
+file (@pxref{history file}) that you've abandoned your
+checkout.
+
+Use @samp{cvs release} to avoid these problems. This
+command checks that no uncommitted changes are
+present; that you are executing it from immediately
+above a @sc{cvs} working directory; and that the repository
+recorded for your files is the same as the repository
+defined in the module database.
+
+If all these conditions are true, @samp{cvs release}
+leaves a record of its execution (attesting to your
+intentionally abandoning your checkout) in the @sc{cvs}
+history log.
+
+@menu
+* release options:: release options
+* release output:: release options
+* release examples:: release examples
+@end menu
+
+@c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
+@node release options
+@appendixsubsec release options
+
+The @code{release} command supports one command option:
+
+@table @code
+@item -d
+Delete your working copy of the file if the release
+succeeds. If this flag is not given your files will
+remain in your working directory.
+
+@strong{Warning:} The @code{release} command uses
+@samp{rm -r @file{module}} to delete your file. This
+has the very serious side-effect that any directory
+that you have created inside your checked-out sources,
+and not added to the repository (using the @code{add}
+command; @pxref{add}) will be silently deleted---even
+if it is non-empty!
+@end table
+
+@c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
+@node release output
+@appendixsubsec release output
+
+Before @code{release} releases your sources it will
+print a one-line message for any file that is not
+up-to-date.
+
+@strong{Warning:} Any new directories that you have
+created, but not added to the @sc{cvs} directory hierarchy
+with the @code{add} command (@pxref{add}) will be
+silently ignored (and deleted, if @samp{-d} is
+specified), even if they contain files.
+
+@table @code
+@item U @var{file}
+There exists a newer revision of this file in the
+repository, and you have not modified your local copy
+of the file.
+
+@item A @var{file}
+The file has been added to your private copy of the
+sources, but has not yet been committed to the
+repository. If you delete your copy of the sources
+this file will be lost.
+
+@item R @var{file}
+The file has been removed from your private copy of the
+sources, but has not yet been removed from the
+repository, since you have not yet committed the
+removal. @xref{commit}.
+
+@item M @var{file}
+The file is modified in your working directory. There
+might also be a newer revision inside the repository.
+
+@item ? @var{file}
+@var{file} is in your working directory, but does not
+correspond to anything in the source repository, and is
+not in the list of files for @sc{cvs} to ignore (see the
+description of the @samp{-I} option, and
+@pxref{cvsignore}). If you remove your working
+sources, this file will be lost.
+
+Note that no warning message like this is printed for
+spurious directories that @sc{cvs} encounters. The
+directory, and all its contents, are silently ignored.
+
+@c FIXME -- CVS should be fixed to print "? foo" for
+@c such spurious directories
+@end table
+
+@c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
+@node release examples
+@appendixsubsec release examples
+
+Release the module, and delete your local working copy
+of the files.
+
+@example
+$ cd .. # @r{You must stand immediately above the}
+ # @r{sources when you issue @samp{cvs release}.}
+$ cvs release -d tc
+You have [0] altered files in this repository.
+Are you sure you want to release (and delete) module `tc': y
+$
+@end example
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@node remove
+@appendixsec remove---Remove an entry from the repository
+@cindex Remove (subcommand)
+
+@itemize @bullet
+@item
+remove [-lR] [files@dots{}]
+@item
+Requires: Working directory.
+@item
+Changes: Working directory.
+@item
+Synonyms: rm, delete
+@end itemize
+
+Use this command to declare that you wish to remove
+files from the source repository. Like most @sc{cvs}
+commands, @samp{cvs remove} works on files in your working
+directory, not directly on the repository. As a
+safeguard, it also requires that you first erase the
+specified files from your working directory.
+
+The files are not actually removed until you apply your
+changes to the repository with @code{commit}; at that
+point, the corresponding @sc{rcs} files in the source
+repository are moved into the @file{Attic} directory
+(also within the source repository).
+
+This command is recursive by default, scheduling all
+physically removed files that it finds for removal by
+the next commit. Use the @samp{-l} option to avoid
+this recursion, or just specify the actual files that
+you wish removed.
+
+
+@menu
+* remove options:: remove options
+* remove examples:: remove examples
+@end menu
+
+@c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
+@node remove options
+@appendixsubsec remove options
+
+Two of the standard options are the only options
+supported by @code{remove}.
+
+@table @code
+@item -l
+Local; run only in current working directory.
+
+@item -R
+Commit directories recursively. This is on by default.
+@end table
+
+@c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
+@node remove examples
+@appendixsubsec remove examples
+
+@appendixsubsubsec Remove a couple of files.
+
+@example
+$ cd test
+$ rm ?.c
+$ cvs remove
+cvs remove: Removing .
+cvs remove: scheduling a.c for removal
+cvs remove: scheduling b.c for removal
+cvs remove: use 'cvs commit' to remove these files permanently
+$ cvs ci -m "Removed unneeded files"
+cvs commit: Examining .
+cvs commit: Committing .
+@end example
+
+@appendixsubsubsec Resurrecting removed files
+
+If you change your mind you can easily resurrect the
+file before you commit it, using the @code{add}
+command.
+
+@example
+$ ls
+CVS ja.h oj.c
+$ rm oj.c
+$ cvs remove oj.c
+cvs remove: scheduling oj.c for removal
+cvs remove: use 'cvs commit' to remove this file permanently
+$ cvs add oj.c
+U oj.c
+cvs add: oj.c, version 1.1.1.1, resurrected
+@end example
+
+If you realize your mistake before you run the
+@code{remove} command you can use @code{update} to
+resurrect the file:
+
+@example
+$ rm oj.c
+$ cvs update oj.c
+cvs update: warning: oj.c was lost
+U oj.c
+@end example
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@node rtag
+@appendixsec rtag---Add a tag to the RCS file
+@cindex Rtag (subcommand)
+
+@itemize @bullet
+@item
+rtag [-falnR] [-b] [-d] [-r tag | -Ddate] symbolic_tag modules@dots{}
+@item
+Requires: repository.
+@item
+Changes: repository.
+@item
+Synonym: rfreeze
+@end itemize
+
+You can use this command to assign symbolic tags to
+particular, explicitly specified source revisions in
+the repository. @code{rtag} works directly on the
+repository contents (and requires no prior checkout).
+Use @code{tag} instead (@pxref{tag}), to base the
+selection of revisions on the contents of your
+working directory.
+
+If you attempt to use a tag name that already exists,
+@sc{cvs} will complain and not overwrite that tag. Use
+the @samp{-F} option to force the new tag value.
+
+@menu
+* rtag options:: rtag options
+@end menu
+
+@c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
+@node rtag options
+@appendixsubsec rtag options
+
+These standard options are supported by @code{rtag}
+(@pxref{Common options}, for a complete description of
+them):
+
+@table @code
+@item -D @var{date}
+Tag the most recent revision no later than @var{date}.
+
+@item -f
+Only useful with the @samp{-D @var{date}} or @samp{-r @var{tag}}
+flags. If no matching revision is found, use the most
+recent revision (instead of ignoring the file).
+
+@item -F
+Overwrite an existing tag of the same name on a
+different revision. This option is new in @sc{cvs}
+1.4. The old behavior is matched by @samp{cvs tag -F}.
+
+@item -l
+Local; run only in current working directory.
+
+@item -n
+Do not run any tag program that was specified with the
+@samp{-t} flag inside the @file{modules} file.
+(@pxref{modules}).
+
+@item -R
+Commit directories recursively. This is on by default.
+
+@item -r @var{tag}
+Only tag those files that contain @var{tag}. This can
+be used to rename a tag: tag only the files identified
+by the old tag, then delete the old tag, leaving the
+new tag on exactly the same files as the old tag.
+@end table
+
+In addition to the above common options, these options
+are available:
+
+@table @code
+@item -a
+Use the @samp{-a} option to have @code{rtag} look in the
+@file{Attic} (@pxref{Removing files}) for removed files
+that contain the specified tag. The tag is removed from
+these files, which makes it convenient to re-use a
+symbolic tag as development continues (and files get
+removed from the up-coming distribution).
+
+@item -b
+Make the tag a branch tag. @xref{Branches}.
+
+@item -d
+Delete the tag instead of creating it.
+
+In general, tags (often the symbolic names of software
+distributions) should not be removed, but the @samp{-d}
+option is available as a means to remove completely
+obsolete symbolic names if necessary (as might be the
+case for an Alpha release, or if you mistagged a
+module).
+@end table
+
+@ignore
+@c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
+@c @node rtag examples
+@appendixsubsec rtag examples
+
+@c -- Examples here!
+@end ignore
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@node status
+@appendixsec status---Status info on the revisions
+@cindex Status (subcommand)
+
+@itemize @bullet
+@item
+status [-lR] [-v] [files@dots{}]
+@item
+Requires: working directory, repository.
+@item
+Changes: nothing.
+@end itemize
+
+Display a brief report on the current status of files
+with respect to the source repository, including any
+sticky tags, dates, or @samp{-k} options.
+
+You can also use this command to determine the
+potential impact of a @samp{cvs update} on your working
+source directory---but remember that things might
+change in the repository before you run @code{update}.
+
+@menu
+* status options:: status options
+@end menu
+
+@c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
+@node status options
+@appendixsubsec status options
+
+These standard options are supported by @code{status}
+(@pxref{Common options}, for a complete description of
+them):
+
+@table @code
+@item -l
+Local; run only in current working directory.
+
+@item -R
+Commit directories recursively. This is on by default.
+@end table
+
+There is one additional option:
+
+@table @code
+@item -v
+Verbose. In addition to the information normally
+displayed, print all symbolic tags, together with the
+numerical value of the revision or branch they refer
+to.
+@end table
+
+@ignore
+@c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
+@c @node status examples
+@appendixsubsec status examples
+
+@c -- FIXME
+@end ignore
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@node tag
+@appendixsec tag---Add a symbolic tag to checked out version of RCS file
+@c -- //////// - unnecessary. Also
+@c -- in a lot of other
+@c -- places.
+@cindex Tag (subcommand)
+
+@itemize @bullet
+@item
+tag [-lR] [-b] [-d] symbolic_tag [files@dots{}]
+@item
+Requires: working directory, repository.
+@item
+Changes: repository.
+@item
+Synonym: freeze
+@end itemize
+
+Use this command to assign symbolic tags to the nearest
+repository versions to your working sources. The tags
+are applied immediately to the repository, as with
+@code{rtag}, but the versions are supplied implicitly by the
+@sc{cvs} records of your working files' history rather than
+applied explicitly.
+
+One use for tags is to record a snapshot of the
+current sources when the software freeze date of a
+project arrives. As bugs are fixed after the freeze
+date, only those changed sources that are to be part of
+the release need be re-tagged.
+
+The symbolic tags are meant to permanently record which
+revisions of which files were used in creating a
+software distribution. The @code{checkout} and
+@code{update} commands allow you to extract an exact
+copy of a tagged release at any time in the future,
+regardless of whether files have been changed, added,
+or removed since the release was tagged.
+
+This command can also be used to delete a symbolic tag,
+or to create a branch. See the options section below.
+
+If you attempt to use a tag name that already exists,
+@sc{cvs} will complain and not overwrite that tag. Use
+the @samp{-F} option to force the new tag value.
+
+
+@menu
+* tag options:: tag options
+@end menu
+
+@c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
+@node tag options
+@appendixsubsec tag options
+
+These standard options are supported by @code{tag}
+(@pxref{Common options}, for a complete description of
+them):
+
+@table @code
+@item -F
+Overwrite an existing tag of the same name on a
+different revision. This option is new in @sc{cvs}
+1.4. The old behavior is matched by @samp{cvs tag -F}.
+
+@item -l
+Local; run only in current working directory.
+
+@item -R
+Commit directories recursively. This is on by default.
+@end table
+
+Two special options are available:
+
+@table @code
+@item -b
+The -b option makes the tag a branch tag
+(@pxref{Branches}), allowing concurrent, isolated
+development. This is most useful for creating a patch
+to a previously released software distribution.
+
+@item -d
+Delete a tag.
+
+If you use @samp{cvs tag -d symbolic_tag}, the symbolic
+tag you specify is deleted instead of being added.
+Warning: Be very certain of your ground before you
+delete a tag; doing this permanently discards some
+historical information, which may later turn out to
+be valuable.
+@end table
+
+@ignore
+@c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
+@c @node tag examples
+@appendixsubsec tag examples
+
+@c -- FIXME
+@end ignore
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@node update
+@appendixsec update---Bring work tree in sync with repository
+@cindex Update (subcommand)
+
+@itemize @bullet
+@item
+update [-AdflPpR] [-d] [-r tag|-D date] files@dots{}
+@item
+Requires: repository, working directory.
+@item
+Changes: working directory.
+@end itemize
+
+After you've run checkout to create your private copy
+of source from the common repository, other developers
+will continue changing the central source. From time
+to time, when it is convenient in your development
+process, you can use the @code{update} command from
+within your working directory to reconcile your work
+with any revisions applied to the source repository
+since your last checkout or update.
+
+@menu
+* update options:: update options
+* update output:: update output
+* update examples:: update examples
+@end menu
+
+@c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
+@node update options
+@appendixsubsec update options
+
+These standard options are available with @code{update}
+(@pxref{Common options}, for a complete description of
+them):
+
+@table @code
+@item -D date
+Use the most recent revision no later than @var{date}.
+This option is sticky, and implies @samp{-P}.
+
+@item -f
+Only useful with the @samp{-D @var{date}} or @samp{-r
+@var{tag}} flags. If no matching revision is found,
+retrieve the most recent revision (instead of ignoring
+the file).
+
+@item -k @var{kflag}
+Process @sc{rcs} keywords according to @var{kflag}. See
+co(1). This option is sticky; future updates of
+this file in this working directory will use the same
+@var{kflag}. The @code{status} command can be viewed
+to see the sticky options. @xref{status}.
+
+@item -l
+Local; run only in current working directory. @xref{Recursive behavior}.
+
+@item -P
+Prune empty directories.
+
+@item -p
+Pipe files to the standard output.
+
+@item -R
+Operate recursively. This is on by default.
+@xref{Recursive behavior}.
+
+@item -r tag
+Retrieve revision @var{tag}. This option is sticky,
+and implies @samp{-P}.
+@end table
+
+@need 800
+These special options are also available with
+@code{update}.
+
+@table @code
+@item -A
+Reset any sticky tags, dates, or @samp{-k} options.
+(If you get a working copy of a file by using one of
+the @samp{-r}, @samp{-D}, or @samp{-k} options, @sc{cvs}
+remembers the corresponding tag, date, or @var{kflag} and
+continues using it on future updates; use the @samp{-A}
+option to make @sc{cvs} forget these specifications, and
+retrieve the head revision of the file).
+
+@item -d
+Create any directories that exist in the repository if
+they're missing from the working directory. Normally,
+@code{update} acts only on directories and files that
+were already enrolled in your working directory.
+
+This is useful for updating directories that were
+created in the repository since the initial checkout;
+but it has an unfortunate side effect. If you
+deliberately avoided certain directories in the
+repository when you created your working directory
+(either through use of a module name or by listing
+explicitly the files and directories you wanted on the
+command line), then updating with @samp{-d} will create
+those directories, which may not be what you want.
+
+@item -I @var{name}
+Ignore files whose names match @var{name} (in your
+working directory) during the update. You can specify
+@samp{-I} more than once on the command line to specify
+several files to ignore. By default, @code{update}
+ignores files whose names match any of the following:
+
+@example
+ RCSLOG RCS SCCS
+ CVS* cvslog.*
+ tags TAGS
+ .make.state .nse_depinfo
+ *~ #* .#* ,*
+ *.old *.bak *.BAK *.orig *.rej .del-*
+ *.a *.o *.so *.Z *.elc *.ln
+ core
+@end example
+
+Use @samp{-I !} to avoid ignoring any files at all.
+@xref{cvsignore}, for other ways to make @sc{cvs} ignore
+some files.
+
+@item -W@var{spec}
+Specify file names that should be filtered during
+update. You can use this option repeatedly.
+
+@var{spec} can be a file name pattern of the same type
+that you can specify in the @file{.cvswrappers}
+file. @xref{Wrappers}.
+
+@item -j@var{revision}
+With two @samp{-j} options, merge changes from the
+revision specified with the first @samp{-j} option to
+the revision specified with the second @samp{j} option,
+into the working directory.
+
+With one @samp{-j} option, merge changes from the
+ancestor revision to the revision specified with the
+@samp{-j} option, into the working directory. The
+ancestor revision is the common ancestor of the
+revision which the working directory is based on, and
+the revision specified in the @samp{-j} option.
+
+In addition, each -j option can contain an optional
+date specification which, when used with branches, can
+limit the chosen revision to one within a specific
+date. An optional date is specified by adding a colon
+(:) to the tag:
+@samp{-j@var{Symbolic_Tag}:@var{Date_Specifier}}.
+
+@xref{Merging}.
+
+@end table
+
+@c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
+@node update output
+@appendixsubsec update output
+
+@code{update} keeps you informed of its progress by
+printing a line for each file, preceded by one
+character indicating the status of the file:
+
+@table @code
+@item U @var{file}
+The file was brought up to date with respect to the
+repository. This is done for any file that exists in
+the repository but not in your source, and for files
+that you haven't changed but are not the most recent
+versions available in the repository.
+
+@item A @var{file}
+The file has been added to your private copy of the
+sources, and will be added to the source repository
+when you run @code{commit} on the file. This is a
+reminder to you that the file needs to be committed.
+
+@item R @var{file}
+The file has been removed from your private copy of the
+sources, and will be removed from the source repository
+when you run @code{commit} on the file. This is a
+reminder to you that the file needs to be committed.
+
+@item M @var{file}
+The file is modified in your working directory.
+
+@samp{M} can indicate one of two states for a file
+you're working on: either there were no modifications
+to the same file in the repository, so that your file
+remains as you last saw it; or there were modifications
+in the repository as well as in your copy, but they
+were merged successfully, without conflict, in your
+working directory.
+
+@sc{cvs} will print some messages if it merges your work,
+and a backup copy of your working file (as it looked
+before you ran @code{update}) will be made. The exact
+name of that file is printed while @code{update} runs.
+
+@item C @var{file}
+A conflict was detected while trying to merge your
+changes to @var{file} with changes from the source
+repository. @var{file} (the copy in your working
+directory) is now the output of the rcsmerge(1) command
+on the two revisions; an unmodified copy of your file
+is also in your working directory, with the name
+@file{.#@var{file}.@var{revision}} where @var{revision}
+is the @sc{rcs} revision that your modified file started
+from. (Note that some systems automatically purge
+files that begin with @file{.#} if they have not been
+accessed for a few days. If you intend to keep a copy
+of your original file, it is a very good idea to rename
+it.)
+
+@item ? @var{file}
+@var{file} is in your working directory, but does not
+correspond to anything in the source repository, and is
+not in the list of files for @sc{cvs} to ignore (see the
+description of the @samp{-I} option, and
+@pxref{cvsignore}).
+
+Note that no warning message like this is printed for
+spurious directories that @sc{cvs} encounters. The
+directory, and all its contents, are silently ignored.
+@end table
+
+@c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
+@node update examples
+@appendixsubsec update examples
+
+The following line will display all files which are not
+up-to-date without actually change anything in your
+working directory. It can be used to check what has
+been going on with the project.
+
+@example
+$ cvs -n -q update
+@end example
+
+@c ---------------------------------------------------------------------
+@node Administrative files
+@appendix Reference manual for the Administrative files
+@cindex Administrative files (reference)
+@cindex Files, reference manual
+@cindex Reference manual (files)
+@cindex CVSROOT (file)
+
+Inside the repository, in the directory
+@file{$CVSROOT/CVSROOT}, there are a number of
+supportive files for @sc{cvs}. You can use @sc{cvs} in a limited
+fashion without any of them, but if they are set up
+properly they can help make life easier.
+
+The most important of these files is the @file{modules}
+file, which defines the modules inside the repository.
+
+@menu
+* modules:: Defining modules
+* Wrappers:: Treat directories as files
+* commit files:: The commit support files
+* commitinfo:: Pre-commit checking
+* editinfo:: Specifying how log messages are created
+* loginfo:: Where should log messages be sent?
+* rcsinfo:: Templates for the log messages
+* cvsignore:: Ignoring files via cvsignore
+* history file:: History information
+* Setting up:: Setting up the repository
+@end menu
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@node modules
+@appendixsec The modules file
+@cindex Modules (admin file)
+@cindex Defining modules (reference manual)
+
+The @file{modules} file records your definitions of
+names for collections of source code. @sc{cvs} will use
+these definitions if you create a file with the right
+format in @file{$CVSROOT/CVSROOT/modules,v}. The
+mkmodules(1) command should be run whenever the modules
+file changes, so that the appropriate files can be
+generated (depending on how you have configured @sc{cvs}
+operation).
+
+To allow convenient editing of the @file{modules} file
+itself, the file should include an entry like the
+following (where @var{localbin} represents the
+directory where your site installs programs like
+mkmodules(1)):
+
+@example
+modules -i /@var{localbin}/mkmodules CVSROOT modules
+@end example
+
+@noindent
+This defines the name @samp{modules} as the module name
+for the file itself, so that you can use
+
+@example
+$ cvs checkout modules
+@end example
+
+@noindent
+to get a copy of the file that you can edit. You should define
+similar module entries for the other configuration
+files described in this appendix, except
+@file{history}).
+
+The @file{modules} file may contain blank lines and
+comments (lines beginning with @samp{#}) as well as
+module definitions. Long lines can be continued on the
+next line by specifying a backslash (@samp{\}) as the
+last character on the line.
+
+A module definition is a single line of the
+@file{modules} file, in either of two formats. In both
+cases, @var{mname} represents the symbolic module name,
+and the remainder of the line is its definition.
+
+@table @code
+@item @var{mname} -a @var{aliases}@dots{}
+This represents the simplest way of defining a module
+@var{mname}. The @samp{-a} flags the definition as a
+simple alias: @sc{cvs} will treat any use of @var{mname} (as
+a command argument) as if the list of names
+@var{aliases} had been specified instead.
+@var{aliases} may contain either other module names or
+paths. When you use paths in aliases, @code{checkout}
+creates all intermediate directories in the working
+directory, just as if the path had been specified
+explicitly in the @sc{cvs} arguments.
+
+@item @var{mname} [ options ] @var{dir} [ @var{files}@dots{} ] [ &@var{module}@dots{} ]
+In the simplest case, this form of module definition
+reduces to @samp{@var{mname} @var{dir}}. This defines
+all the files in directory @var{dir} as module mname.
+@var{dir} is a relative path (from @code{$CVSROOT}) to a
+directory of source in the source repository. In this
+case, on checkout, a single directory called
+@var{mname} is created as a working directory; no
+intermediate directory levels are used by default, even
+if @var{dir} was a path involving several directory
+levels.
+
+By explicitly specifying files in the module definition
+after @var{dir}, you can select particular files from
+directory @var{dir}. The sample definition for
+@samp{modules} is an example of a module defined with a
+single file from a particular directory. Here is
+another example:
+
+@example
+m4test unsupported/gnu/m4 foreach.m4 forloop.m4
+@end example
+
+@noindent
+With this definition, executing @samp{cvs checkout
+m4test} will create a single working directory
+@file{m4test} containing the two files listed, which
+both come from a common directory several levels deep
+in the @sc{cvs} source repository.
+
+A module definition can refer to other modules by
+including @samp{&@var{module}} in its definition.
+@code{checkout} creates a subdirectory for each such
+module, in your working directory.
+@c -- Nope. "in your working directory" is wrong. What
+@c -- is right?
+
+@table @code
+@item -d @var{name}
+Name the working directory something other than the
+module name.
+
+@cindex Export program
+@item -e @var{prog}
+Specify a program @var{prog} to run whenever files in a
+module are exported. @var{prog} runs with a single
+argument, the module name.
+
+@cindex Checkin program
+@item -i @var{prog}
+Specify a program @var{prog} to run whenever files in a
+module are committed. @var{prog} runs with a single
+argument, the full pathname of the affected directory
+in a source repository. The @file{commitinfo},
+@file{loginfo}, and @file{editinfo} files provide other
+ways to call a program on commit.
+
+@cindex Checkout program
+@item -o @var{prog}
+Specify a program @var{prog} to run whenever files in a
+module are checked out. @var{prog} runs with a single
+argument, the module name.
+
+@cindex Status of a module
+@cindex Module status
+@item -s @var{status}
+Assign a status to the module. When the module file is
+printed with @samp{cvs checkout -s} the modules are
+sorted according to primarily module status, and
+secondarily according to the module name. This option
+has no other meaning. You can use this option for
+several things besides status: for instance, list the
+person that is responsible for this module.
+
+@cindex Tag program
+@item -t @var{prog}
+Specify a program @var{prog} to run whenever files in a
+module are tagged with @code{rtag}. @var{prog} runs
+with two arguments: the module name and the symbolic
+tag specified to @code{rtag}. There is no way to
+specify a program to run when @code{tag} is executed.
+
+@cindex Update program
+@item -u @var{prog}
+Specify a program @var{prog} to run whenever @samp{cvs
+update} is executed from the top-level directory of the
+checked-out module. @var{prog} runs with a single
+argument, the full path to the source repository for
+this module.
+@end table
+@end table
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@node Wrappers
+@appendixsec The cvswrappers file
+@cindex cvswrappers (admin file)
+@cindex CVSWRAPPERS, environment variable
+@cindex Wrappers
+
+Wrappers are essentially
+directories that are to be treated as "files." This
+package allows such wrappers to be "processed" on the
+way in and out of CVS. The intended use is to wrap up
+a wrapper into a single tar, such that that tar can be
+treated as a single binary file in CVS. Apparently
+this is particularly useful on NEXTSTEP. To solve
+the problem effectively, it was also necessary to be
+able to prevent rcsmerge application at appropriate
+times.
+
+The file @file{cvswrappers} defines the script that will be
+run on a file when its name matches a regular
+expresion. There are two scripts that can be run on a
+file or directory.
+@c FIXME: Is this talking about comb and uncom? If so,
+@c mention them by name
+A script to filter the directory/file before it gets
+checked in and another that is run when the
+file/directory gets checked out.
+
+The @file{cvswrappers} also specifies the merge
+methodology that should be used when the file is
+updated, that is should a MERGE or a straight COPY of
+the diferences be used when checking into the
+repository.
+
+The basic format of the file @file{cvswrappers} is given as
+such:
+
+@example
+wildcard [option value][option value]...
+
+where option is one of
+-f from cvs filter value: path tofilter
+-t to cvs filter value: path to filter
+-m update methodology value: MERGE or COPY
+
+and value is a single-quote delimited value.
+@end example
+
+@example
+*.nib -f 'uncom %s' -t 'comb %s %s' -m 'COPY'
+*.rtfd -f 'uncom %s' -t 'comb %s %s' -m 'COPY'
+@end example
+
+@noindent
+The above example of a @file{cvswrappers} file
+states that all files/directories that end with a @code{.nib}
+should be filtered with the @file{comb} program before
+checking the file into the repository. The file should
+be filtered though the @file{uncom} program when the
+file is checked out of the repository. The
+@file{cvswrappers} file also states that a @code{COPY}
+methodology should be used when updating the files in
+the repository (that is no merging should be performed).
+
+@noindent
+The @file{comb} filter is called with two arguments,
+the first is the name of the file/directory to filter
+and the second is the pathname to where the resulting
+filtered file should be placed.
+
+@noindent
+The @file{uncom} filter is called with one argument,
+which is the name of the file to filter from. The end
+result of the @file{uncom} filter will be a
+file/directory in the users current working directory,
+that represents the source before being filtered.
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@node commit files
+@appendixsec The commit support files
+@cindex Commit files
+
+The @samp{-i} flag in the @file{modules} file can be
+used to run a certain program whenever files are
+committed (@pxref{modules}). The files described in
+this section provide other, more flexible, ways to run
+programs whenever something is committed.
+
+There are three kind of programs that can be run on
+commit. They are specified in files in the repository,
+as described below. The following table summarizes the
+file names and the purpose of the corresponding
+programs.
+
+@table @file
+@item commitinfo
+The program is responsible for checking that the commit
+is allowed. If it exits with a non-zero exit status
+the commit will be aborted.
+
+@item editinfo
+The specified program is used to edit the log message,
+and possibly verify that it contains all required
+fields. This is most useful in combination with the
+@file{rcsinfo} file, which can hold a log message
+template (@pxref{rcsinfo}).
+
+@item loginfo
+The specified program is called when the commit is
+complete. It receives the log message and some
+additional information and can store the log message in
+a file, or mail it to appropriate persons, or maybe
+post it to a local newsgroup, or@dots{} Your
+imagination is the limit!
+@end table
+
+@menu
+* syntax:: The common syntax
+@end menu
+
+@c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
+@node syntax
+@appendixsubsec The common syntax
+@cindex Info files (syntax)
+@cindex Syntax of info files
+@cindex Common syntax of info files
+
+The four files @file{commitinfo}, @file{loginfo},
+@file{rcsinfo} and @file{editinfo} all have a common
+format. The purpose of the files are described later
+on. The common syntax is described here.
+
+Each line contains the following:
+@itemize @bullet
+@item
+A regular expression
+
+@item
+A whitespace separator---one or more spaces and/or tabs.
+
+@item
+A file name or command-line template.
+@end itemize
+
+@noindent
+Blank lines are ignored. Lines that start with the
+character @samp{#} are treated as comments. Long lines
+unfortunately can @emph{not} be broken in two parts in
+any way.
+
+The first regular expression that matches the current
+directory name in the repository is used. The rest of the line
+is used as a file name or command-line as appropriate.
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@node commitinfo
+@appendixsec Commitinfo
+@cindex Commitinfo
+@cindex Checking commits
+@cindex Precommit checking
+
+The @file{commitinfo} file defines programs to execute
+whenever @samp{cvs commit} is about to execute. These
+programs are used for pre-commit checking to verify
+that the modified, added and removed files are really
+ready to be committed. This could be used, for
+instance, to verify that the changed files conform to
+to your site's standards for coding practice.
+
+As mentioned earlier, each line in the
+@file{commitinfo} file consists of a regular expression
+and a command-line template. The template can include
+a program name and any number of arguments you wish to
+supply to it. The full path to the current source
+repository is appended to the template, followed by the
+file names of any files involved in the commit (added,
+removed, and modified files).
+
+The first line with a regular expression matching the
+relative path to the module will be used. If the
+command returns a non-zero exit status the commit will
+be aborted.
+
+@cindex DEFAULT in commitinfo
+If the repository name does not match any of the
+regular expressions in this file, the @samp{DEFAULT}
+line is used, if it is specified.
+
+@cindex ALL in commitinfo
+All occurances of the name @samp{ALL} appearing as a
+regular expression are used in addition to the first
+matching regular expression or the name @samp{DEFAULT}.
+
+Note: when @sc{CVS} is accessing a remote repository,
+@file{commitinfo} will be run on the @emph{remote}
+(i.e., server) side, not the client side (@pxref{Remote
+repositories}).
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@node editinfo
+@appendixsec Editinfo
+@cindex Editinfo
+@cindex Editor, specifying per module
+@cindex Per-module editor
+@cindex Log messages, editing
+
+If you want to make sure that all log messages look the
+same way, you can use the @file{editinfo} file to
+specify a program that is used to edit the log message.
+This program could be a custom-made editor that always
+enforces a certain style of the log message, or maybe a
+simple shell script that calls an editor, and checks
+that the entered message contains the required fields.
+
+If no matching line is found in the @file{editinfo}
+file, the editor specified in the environment variable
+@code{$CVSEDITOR} is used instead. If that variable is
+not set, then the environment variable @code{$EDITOR}
+is used instead. If that variable is not
+set a precompiled default, normally @code{vi}, will be
+used.
+
+The @file{editinfo} file is often most useful together
+with the @file{rcsinfo} file, which can be used to
+specify a log message template.
+
+Each line in the @file{editinfo} file consists of a
+regular expression and a command-line template. The
+template must include a program name, and can include
+any number of arguments. The full path to the current
+log message template file is appended to the template.
+
+One thing that should be noted is that the @samp{ALL}
+keyword is not supported. If more than one matching
+line is found, the first one is used. This can be
+useful for specifying a default edit script in a
+module, and then overriding it in a subdirectory.
+
+@cindex DEFAULT in editinfo
+If the repository name does not match any of the
+regular expressions in this file, the @samp{DEFAULT}
+line is used, if it is specified.
+
+If the edit script exits with a non-zero exit status,
+the commit is aborted.
+
+Note: when @sc{CVS} is accessing a remote repository,
+@file{editinfo} will be run on the @emph{remote}
+(i.e., server) side, not the client side (@pxref{Remote
+repositories}).
+
+@menu
+* editinfo example:: Editinfo example
+@end menu
+
+@c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
+@node editinfo example
+@appendixsubsec Editinfo example
+
+The following is a little silly example of a
+@file{editinfo} file, together with the corresponding
+@file{rcsinfo} file, the log message template and an
+editor script. We begin with the log message template.
+We want to always record a bug-id number on the first
+line of the log message. The rest of log message is
+free text. The following template is found in the file
+@file{/usr/cvssupport/tc.template}.
+
+@example
+BugId:
+@end example
+
+The script @file{/usr/cvssupport/bugid.edit} is used to
+edit the log message.
+
+@example
+#!/bin/sh
+#
+# bugid.edit filename
+#
+# Call $EDITOR on FILENAME, and verify that the
+# resulting file contains a valid bugid on the first
+# line.
+if [ "x$EDITOR" = "x" ]; then EDITOR=vi; fi
+if [ "x$CVSEDITOR" = "x" ]; then CVSEDITOR=$EDITOR; fi
+$CVSEDITOR $1
+until head -1|grep '^BugId:[ ]*[0-9][0-9]*$' < $1
+do echo -n "No BugId found. Edit again? ([y]/n)"
+ read ans
+ case $@{ans@} in
+ n*) exit 1;;
+ esac
+ $CVSEDITOR $1
+done
+@end example
+
+The @file{editinfo} file contains this line:
+
+@example
+^tc /usr/cvssupport/bugid.edit
+@end example
+
+The @file{rcsinfo} file contains this line:
+
+@example
+^tc /usr/cvssupport/tc.template
+@end example
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@node loginfo
+@appendixsec Loginfo
+@cindex Loginfo
+@cindex Storing log messages
+@cindex Mailing log messages
+@cindex Distributing log messages
+@cindex Log messages
+
+The @file{loginfo} file is used to control where
+@samp{cvs commit} log information is sent. The first
+entry on a line is a regular expression which is tested
+against the directory that the change is being made to,
+relative to the @code{$CVSROOT}. If a match is found, then
+the remainder of the line is a filter program that
+should expect log information on its standard input.
+
+The filter program may use one and only one % modifier
+(a la printf). If @samp{%s} is specified in the filter
+program, a brief title is included (enclosed in single
+quotes) showing the modified file names.
+
+If the repository name does not match any of the
+regular expressions in this file, the @samp{DEFAULT}
+line is used, if it is specified.
+
+All occurances of the name @samp{ALL} appearing as a
+regular expression are used in addition to the first
+matching regular expression or @samp{DEFAULT}.
+
+The first matching regular expression is used.
+
+@xref{commit files}, for a description of the syntax of
+the @file{loginfo} file.
+
+Note: when @sc{CVS} is accessing a remote repository,
+@file{loginfo} will be run on the @emph{remote}
+(i.e., server) side, not the client side (@pxref{Remote
+repositories}).
+
+@menu
+* loginfo example:: Loginfo example
+@end menu
+
+@c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
+@node loginfo example
+@appendixsubsec Loginfo example
+
+The following @file{loginfo} file, together with the
+tiny shell-script below, appends all log messages
+to the file @file{$CVSROOT/CVSROOT/commitlog},
+and any commits to the administrative files (inside
+the @file{CVSROOT} directory) are also logged in
+@file{/usr/adm/cvsroot-log} and mailed to @t{ceder}.
+
+@example
+ALL /usr/local/bin/cvs-log $CVSROOT/CVSROOT/commitlog
+^CVSROOT Mail -s %s ceder
+^CVSROOT /usr/local/bin/cvs-log /usr/adm/cvsroot-log
+@end example
+
+The shell-script @file{/usr/local/bin/cvs-log} looks
+like this:
+
+@example
+#!/bin/sh
+(echo "-----------------------------------------------------------------";
+ echo -n $USER" ";
+ date;
+ echo;
+ sed '1s+'$@{CVSROOT@}'++') >> $1
+@end example
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@node rcsinfo
+@appendixsec Rcsinfo
+@cindex Rcsinfo
+@cindex Form for log message
+@cindex Log message template
+@cindex Template for log message
+
+The @file{rcsinfo} file can be used to specify a form to
+edit when filling out the commit log. The
+@file{rcsinfo} file has a syntax similar to the
+@file{editinfo}, @file{commitinfo} and @file{loginfo}
+files. @xref{syntax}. Unlike the other files the second
+part is @emph{not} a command-line template. Instead,
+the part after the regular expression should be a full pathname to
+a file containing the log message template.
+
+If the repository name does not match any of the
+regular expressions in this file, the @samp{DEFAULT}
+line is used, if it is specified.
+
+All occurances of the name @samp{ALL} appearing as a
+regular expression are used in addition to the first
+matching regular expression or @samp{DEFAULT}.
+
+The log message template will be used as a default log
+message. If you specify a log message with @samp{cvs
+commit -m @var{message}} or @samp{cvs commit -f
+@var{file}} that log message will override the
+template.
+
+@xref{editinfo example}, for an example @file{rcsinfo}
+file.
+
+Note: when @sc{CVS} is accessing a remote repository,
+@file{rcsinfo} will be run on the @emph{remote}
+(i.e., server) side, not the client side (@pxref{Remote
+repositories}).
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@node cvsignore
+@appendixsec Ignoring files via cvsignore
+@cindex Cvsignore, global
+@cindex Global cvsignore
+@cindex Ignoring files
+@c -- This chapter should maybe be moved to the
+@c tutorial part of the manual?
+
+There are certain file names that frequently occur
+inside your working copy, but that you don't want to
+put under @sc{cvs} control. Examples are all the object
+files that you get while you compile your sources.
+Normally, when you run @samp{cvs update}, it prints a
+line for each file it encounters that it doesn't know
+about (@pxref{update output}).
+
+@sc{cvs} has a list of files (or sh(1) file name patterns)
+that it should ignore while running @code{update},
+@code{import} and @code{release}.
+@c -- Are those the only three commands affected?
+This list is constructed in the following way.
+
+@itemize @bullet
+@item
+The list is initialized to the following file name
+patterns:
+
+@cindex Ignored files
+@cindex Automatically ignored files
+@example
+ RCSLOG RCS SCCS
+ CVS* cvslog.*
+ tags TAGS
+ .make.state .nse_depinfo
+ *~ #* .#* ,*
+ *.old *.bak *.BAK *.orig *.rej .del-*
+ *.a *.o *.so *.Z *.elc *.ln
+ core
+@end example
+
+@item
+The per-repository list in
+@file{$CVSROOT/CVSROOT/cvsignore} is appended to
+the list, if that file exists.
+
+@item
+The per-user list in @file{.cvsignore} in your home
+directory is appended to the list, if it exists.
+
+@item
+Any entries in the environment variable
+@code{$CVSIGNORE} is appended to the list.
+
+@item
+Any @samp{-I} options given to @sc{cvs} is appended.
+
+@item
+As @sc{cvs} traverses through your directories, the contents
+of any @file{.cvsignore} will be appended to the list.
+The patterns found in @file{.cvsignore} are only valid
+for the directory that contains them, not for
+any sub-directories.
+@end itemize
+
+In any of the 5 places listed above, a single
+exclamation mark (@samp{!}) clears the ignore list.
+This can be used if you want to store any file which
+normally is ignored by @sc{cvs}.
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@node history file
+@appendixsec The history file
+@cindex History file
+@cindex Log information, saving
+
+The file @file{$CVSROOT/CVSROOT/history} is used
+to log information for the @code{history} command
+(@pxref{history}). This file must be created to turn
+on logging. This is done automatically if the
+@code{cvsinit} script is used to set up the repository.
+
+The file format of the @file{history} file is
+unfortunately not yet documented anywhere, but it is
+fairly easy to understand most of it.
+@c -- document it here?
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@node Setting up
+@appendixsec Setting up the repository
+@cindex Repository, setting up
+@cindex Creating a repository
+@cindex Setting up a repository
+
+When you install @sc{cvs} for the first time, you should
+follow the instructions in the @file{INSTALL} file to
+set up the repository.
+
+If you want to set up another repository, the easiest
+way to get a reasonable set of working administrative
+files is to run the @code{cvsinit} shell script. It
+will set up an empty repository in the directory
+defined by the environment variable @code{$CVSROOT}.
+(@code{cvsinit} is careful to never overwrite any
+existing files in the repository, so no harm is done if
+you run @code{cvsinit} on an already set-up
+repository. In fact, running it on an already set-up
+repository is the best way to update the various
+scripts from the @samp{contrib} directory.)
+
+@c ---------------------------------------------------------------------
+@node Environment variables
+@appendix All environment variables which affect CVS
+@cindex Environment variables
+@cindex Reference manual for variables
+
+This is a complete list of all environment variables
+that affect @sc{cvs}.
+
+@table @code
+@cindex CVSIGNORE
+@item $CVSIGNORE
+A whitespace-separated list of file name patterns that
+@sc{cvs} should ignore. @xref{cvsignore}.
+
+@item $CVSWRAPPERS
+A whitespace-separated list of file name patterns that
+@sc{cvs} should treat as wrappers. @xref{Wrappers}.
+
+@cindex CVSREAD
+@item $CVSREAD
+If this is set, @code{checkout} and @code{update} will
+try hard to make the files in your working directory
+read-only. When this is not set, the default behavior
+is to permit modification of your working files.
+
+@cindex CVSROOT
+@item $CVSROOT
+Should contain the full pathname to the root of the @sc{cvs}
+source repository (where the @sc{rcs} history files are
+kept). This information must be available to @sc{cvs} for
+most commands to execute; if @code{$CVSROOT} is not set,
+or if you wish to override it for one invocation, you
+can supply it on the command line: @samp{cvs -d cvsroot
+cvs_command@dots{}} Once you have checked out a working
+directory, @sc{cvs} stores the appropriate root (in
+the file @file{CVS/Root}), so normally you only need to
+worry about this when initially checking out a working
+directory.
+
+@cindex EDITOR
+@cindex CVSEDITOR
+@item $EDITOR
+@itemx $CVSEDITOR
+Specifies the program to use for recording log messages
+during commit. If not set, the default is
+@samp{/usr/ucb/vi}. @code{$CVSEDITOR} overrides
+@code{$EDITOR}. @code{$CVSEDITOR} does not exist in
+@sc{cvs} 1.3, but the next release will probably
+include it.
+
+@cindex PATH
+@item $PATH
+If @code{$RCSBIN} is not set, and no path is compiled
+into @sc{cvs}, it will use @code{$PATH} to try to find all
+programs it uses.
+
+@cindex RCSBIN
+@item $RCSBIN
+Specifies the full pathname of the location of @sc{rcs} programs,
+such as co(1) and ci(1). If not set, a compiled-in
+value is used, or your @code{$PATH} is searched.
+@end table
+
+@sc{cvs} is a front-end to @sc{rcs}. The following environment
+variables affect @sc{rcs}:
+
+@table @code
+@cindex LOGNAME
+@item $LOGNAME
+@cindex USER
+@itemx $USER
+If set, they affect who @sc{rcs} thinks you are. If you
+have trouble checking in files it might be because your
+login name differs from the setting of e.g.
+@code{$LOGNAME}.
+
+@cindex RCSINIT
+@item $RCSINIT
+Options prepended to the argument list, separated by
+spaces. A backslash escapes spaces within an option.
+The @code{$RCSINIT} options are prepended to the
+argument lists of most @sc{rcs} commands.
+
+@cindex TMPDIR
+@item $TMPDIR
+@cindex TMP
+@itemx $TMP
+@cindex TEMP
+@itemx $TEMP
+Name of the temporary directory. The environment
+variables are inspected in the order they appear above
+and the first value found is taken; if none of them are
+set, a host-dependent default is used, typically
+@file{/tmp}.
+@end table
+
+@c ---------------------------------------------------------------------
+@node Troubleshooting
+@appendix Troubleshooting
+
+@menu
+* Magic branch numbers:: Magic branch numbers
+@end menu
+
+@ignore
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@c @node Bad administrative files
+@appendixsec Bad administrative files
+
+@c -- Give hints on how to fix them
+@end ignore
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@node Magic branch numbers
+@appendixsec Magic branch numbers
+
+Externally, branch numbers consist of an odd number of
+dot-separated decimal integers. @xref{Revision
+numbers}. That is not the whole truth, however. For
+efficiency reasons @sc{cvs} sometimes inserts an extra 0
+in the second rightmost position (1.2.3 becomes
+1.2.0.3, 8.9.10.11.12 becomes 8.9.10.11.0.12 and so
+on).
+
+@sc{cvs} does a pretty good job at hiding these so
+called magic branches, but in at least four places the
+hiding is incomplete.
+
+@itemize @bullet
+@item
+The magic branch can appear in the output from
+@code{cvs status} in vanilla @sc{cvs} 1.3. This is
+fixed in @sc{cvs} 1.3-s2.
+
+@item
+The magic branch number appears in the output from
+@code{cvs log}. This is much harder to fix, since
+@code{cvs log} runs @code{rlog} (which is part of the
+@sc{rcs} distribution), and modifying @code{rlog} to
+know about magic branches would probably break someone's
+habits (if they use branch 0 for their own purposes).
+
+@item
+You cannot specify a symbolic branch name to @code{cvs log}.
+
+@item
+You cannot specify a symbolic branch name to @code{cvs
+admin}.
+
+@end itemize
+
+You can use the @code{admin} command to reassign a
+symbolic name to a branch the way @sc{rcs} expects it
+to be. If @code{R4patches} is assigned to the branch
+1.4.2 (magic branch number 1.4.0.2) in file
+@file{numbers.c} you can do this:
+
+@example
+$ cvs admin -NR4patches:1.4.2 numbers.c
+@end example
+
+It only works if at least one revision is already
+committed on the branch. Be very careful so that you
+do not assign the tag to the wrong number. (There is
+no way to see how the tag was assigned yesterday).
+
+@c ---------------------------------------------------------------------
+@node Copying
+@appendix GNU GENERAL PUBLIC LICENSE
+@c @include gpl.texinfo
+
+@c ---------------------------------------------------------------------
+@node Index
+@unnumbered Index
+@cindex Index
+
+@printindex cp
+
+@summarycontents
+
+@contents
+
+@bye
+
+Local Variables:
+fill-column: 55
+End:
diff --git a/gnu/usr.bin/cvs/doc/cvsclient.texi b/gnu/usr.bin/cvs/doc/cvsclient.texi
new file mode 100644
index 0000000..9c8f326
--- /dev/null
+++ b/gnu/usr.bin/cvs/doc/cvsclient.texi
@@ -0,0 +1,673 @@
+\input texinfo
+
+@setfilename cvsclient.info
+
+@node Top
+@top CVS Client/Server
+
+This manual describes the client/server protocol used by CVS. It does
+not describe how to use or administer client/server CVS; see the
+regular CVS manual for that.
+
+@menu
+* Goals:: Basic design decisions, requirements, scope, etc.
+* Notes:: Notes on the current implementation
+* How To:: How to remote your favorite CVS command
+* Protocol Notes:: Possible enhancements, limitations, etc. of the protocol
+* Protocol:: Complete description of the protocol
+@end menu
+
+@node Goals
+@chapter Goals
+
+@itemize @bullet
+@item
+Do not assume any access to the repository other than via this protocol.
+It does not depend on NFS, rdist, etc.
+
+@item
+Providing a reliable transport is outside this protocol. It is expected
+that it runs over TCP, UUCP, etc.
+
+@item
+Security and authentication are handled outside this protocol (but see
+below about @samp{cvs kserver}).
+
+@item
+This might be a first step towards adding transactions to CVS (i.e. a
+set of operations is either executed atomically or none of them is
+executed), improving the locking, or other features. The current server
+implementation is a long way from being able to do any of these
+things. The protocol, however, is not known to contain any defects
+which would preclude them.
+
+@item
+The server never has to have any CVS locks in place while it is waiting
+for communication with the client. This makes things robust in the face
+of flaky networks.
+
+@item
+Data is transferred in large chunks, which is necessary for good
+performance. In fact, currently the client uploads all the data
+(without waiting for server responses), and then waits for one server
+response (which consists of a massive download of all the data). There
+may be cases in which it is better to have a richer interraction, but
+the need for the server to release all locks whenever it waits for the
+client makes it complicated.
+@end itemize
+
+@node Notes
+@chapter Notes on the Current Implementation
+
+The client is built in to the normal @code{cvs} program, triggered by a
+@code{CVSROOT} variable containing a colon, for example
+@code{cygnus.com:/rel/cvsfiles}.
+
+The client stores what is stored in checked-out directories (including
+@file{CVS}). The way these are stored is totally compatible with
+standard CVS. The server requires no storage other than the repository,
+which also is totally compatible with standard CVS.
+
+The server is started by @code{cvs server}. There is no particularly
+compelling reason for this rather than making it a separate program
+which shares a lot of sources with cvs.
+
+The server can also be started by @code{cvs kserver}, in which case it
+does an initial Kerberos authentication on stdin. If the authentication
+succeeds, it subsequently runs identically to @code{cvs server}.
+
+The current server implementation can use up huge amounts of memory
+when transmitting a lot of data over a slow link (i.e. the network is
+slower than the server can generate the data). Avoiding this is
+tricky because of the goal of not having the server block on the
+network when it has locks open (this could lock the repository for
+hours if things are running smoothly or longer if not). Several
+solutions are possible. The two-pass design would involve first
+noting what versions of everything we need (with locks in place) and
+then sending the data, blocking on the network, with no locks needed.
+The lather-rinse-repeat design would involve doing things as it does
+now until a certain amount of server memory is being used (10M?), then
+releasing locks, and trying the whole update again (some of it is
+presumably already done). One problem with this is getting merges to
+work right. The two-pass design appears to be the more elegant of the
+two (it actually reduces the amount of time that locks need to be in
+place), but people have expressed concerns about whether it would be
+slower (because it traverses the repository twice). It is not clear
+whether this is a real problem (looking for whether a file needs to be
+updated and actually checking it out are done separately already), but
+I don't think anyone has investigated carefully. One hybrid approach
+which avoids the problem with merges would be to start out in one-pass
+mode and switch to two-pass mode if data is backing up--but this
+complicates the code and should be undertaken only if the pure
+two-pass design is shown to be flawed.
+
+@node How To
+@chapter How to add more remote commands
+
+It's the usual simple twelve step process. Let's say you're making
+the existing @code{cvs fix} command work remotely.
+
+@itemize @bullet
+@item
+Add a declaration for the @code{fix} function, which already implements
+the @code{cvs fix} command, to @file{server.c}.
+@item
+Now, the client side.
+Add a function @code{client_fix} to @file{client.c}, which calls
+@code{parse_cvsroot} and then calls the usual @code{fix} function.
+@item
+Add a declaration for @code{client_fix} to @file{client.h}.
+@item
+Add @code{client_fix} to the "fix" entry in the table of commands in
+@file{main.c}.
+@item
+Now for the server side.
+Add the @code{serve_fix} routine to @file{server.c}; make it do:
+@example @code
+static void
+serve_fix (arg)
+ char *arg;
+@{
+ do_cvs_command (fix);
+@}
+@end example
+@item
+Add the server command @code{"fix"} to the table of requests in @file{server.c}.
+@item
+The @code{fix} function can now be entered in three different situations:
+local (the old situation), client, and server. On the server side it probably
+will not need any changes to cope.
+Modify the @code{fix} function so that if it is run when the variable
+@code{client_active} is set, it starts the server, sends over parsed
+arguments and possibly files, sends a "fix" command to the server,
+and handles responses from the server. Sample code:
+@example @code
+ if (!client_active) @{
+ /* Do whatever you used to do */
+ @} else @{
+ /* We're the local client. Fire up the remote server. */
+ start_server ();
+
+ if (local)
+ if (fprintf (to_server, "Argument -l\n") == EOF)
+ error (1, errno, "writing to server");
+ send_option_string (options);
+
+ send_files (argc, argv, local);
+
+ if (fprintf (to_server, "fix\n") == EOF)
+ error (1, errno, "writing to server");
+ err = get_responses_and_close ();
+ @}
+@end example
+@item
+Build it locally. Copy the new version into somewhere on the
+remote system, in your path so that @code{rsh host cvs} finds it.
+Now you can test it.
+@item
+You may want to set the environment variable @code{CVS_CLIENT_PORT} to
+-1 to prevent the client from contacting the server via a direct TCP
+link. That will force the client to fall back to using @code{rsh},
+which will run your new binary.
+@item
+Set the environment variable @code{CVS_CLIENT_LOG} to a filename prefix
+such as @file{/tmp/cvslog}. Whenever you run a remote CVS command,
+the commands and responses sent across the client/server connection
+will be logged in @file{/tmp/cvslog.in} and @file{/tmp/cvslog.out}.
+Examine them for problems while you're testing.
+@end itemize
+
+This should produce a good first cut at a working remote @code{cvs fix}
+command. You may have to change exactly how arguments are passed,
+whether files or just their names are sent, and how some of the deeper
+infrastructure of your command copes with remoteness.
+
+@node Protocol Notes
+@chapter Notes on the Protocol
+
+A number of enhancements are possible:
+
+@itemize @bullet
+@item
+The @code{Modified} request could be speeded up by sending diffs rather
+than entire files. The client would need some way to keep the version
+of the file which was originally checked out, which would double client
+disk space requirements or require coordination with editors (e.g. maybe
+it could use emacs numbered backups). This would also allow local
+operation of @code{cvs diff} without arguments.
+
+@item
+Have the client keep a copy of some part of the repository. This allows
+all of @code{cvs diff} and large parts of @code{cvs update} and
+@code{cvs ci} to be local. The local copy could be made consistent with
+the master copy at night (but if the master copy has been updated since
+the latest nightly re-sync, then it would read what it needs to from the
+master).
+
+@item
+Provide encryption using kerberos.
+
+@item
+The current procedure for @code{cvs update} is highly sub-optimal if
+there are many modified files. One possible alternative would be to
+have the client send a first request without the contents of every
+modified file, then have the server tell it what files it needs. Note
+the server needs to do the what-needs-to-be-updated check twice (or
+more, if changes in the repository mean it has to ask the client for
+more files), because it can't keep locks open while waiting for the
+network. Perhaps this whole thing is irrelevant if client-side
+repositories are implemented, and the rcsmerge is done by the client.
+@end itemize
+
+@node Protocol
+@chapter The CVS client/server protocol
+
+@menu
+* Entries Lines::
+* Modes::
+* Requests::
+* Responses::
+* Example::
+@end menu
+
+@node Entries Lines
+@section Entries Lines
+
+Entries lines are transmitted as:
+
+@example
+/ @var{name} / @var{version} / @var{conflict} / @var{options} / @var{tag_or_date}
+@end example
+
+@var{tag_or_date} is either @samp{T} @var{tag} or @samp{D} @var{date}
+or empty. If it is followed by a slash, anything after the slash
+shall be silently ignored.
+
+@var{version} can be empty, or start with @samp{0} or @samp{-}, for no
+user file, new user file, or user file to be removed, respectively.
+
+@var{conflict}, if it starts with @samp{+}, indicates that the file had
+conflicts in it. The rest of @var{conflict} is @samp{=} if the
+timestamp matches the file, or anything else if it doesn't. If
+@var{conflict} does not start with a @samp{+}, it is silently ignored.
+
+@node Modes
+@section Modes
+
+A mode is any number of repetitions of
+
+@example
+@var{mode-type} = @var{data}
+@end example
+
+separated by @samp{,}.
+
+@var{mode-type} is an identifier composed of alphanumeric characters.
+Currently specified: @samp{u} for user, @samp{g} for group, @samp{o} for
+other, as specified in POSIX. If at all possible, give these their
+POSIX meaning and use other mode-types for other behaviors. For
+example, on VMS it shouldn't be hard to make the groups behave like
+POSIX, but you would need to use ACLs for some cases.
+
+@var{data} consists of any data not containing @samp{,}, @samp{\0} or
+@samp{\n}. For @samp{u}, @samp{g}, and @samp{o} mode types, data
+consists of alphanumeric characters, where @samp{r} means read, @samp{w}
+means write, @samp{x} means execute, and unrecognized letters are
+silently ignored.
+
+@node Requests
+@section Requests
+
+File contents (noted below as @var{file transmission}) can be sent in
+one of two forms. The simpler form is a number of bytes, followed by a
+newline, followed by the specified number of bytes of file contents.
+These are the entire contents of the specified file. Second, if both
+client and server support @samp{gzip-file-contents}, a @samp{z} may
+precede the length, and the `file contents' sent are actually compressed
+with @samp{gzip}. The length specified is that of the compressed
+version of the file.
+
+In neither case are the file content followed by any additional data.
+The transmission of a file will end with a newline iff that file (or its
+compressed form) ends with a newline.
+
+@table @code
+@item Root @var{pathname} \n
+Response expected: no.
+Tell the server which @code{CVSROOT} to use.
+
+@item Valid-responses @var{request-list} \n
+Response expected: no.
+Tell the server what responses the client will accept.
+request-list is a space separated list of tokens.
+
+@item valid-requests \n
+Response expected: yes.
+Ask the server to send back a @code{Valid-requests} response.
+
+@item Repository @var{repository} \n
+Response expected: no. Tell the server what repository to use. This
+should be a directory name from a previous server response. Note that
+this both gives a default for @code{Entry } and @code{Modified } and
+also for @code{ci} and the other commands; normal usage is to send a
+@code{Repository } for each directory in which there will be an
+@code{Entry } or @code{Modified }, and then a final @code{Repository }
+for the original directory, then the command.
+
+@item Directory @var{local-directory} \n
+Additional data: @var{repository} \n. This is like @code{Repository},
+but the local name of the directory may differ from the repository name.
+If the client uses this request, it affects the way the server returns
+pathnames; see @ref{Responses}. @var{local-directory} is relative to
+the top level at which the command is occurring (i.e. the last
+@code{Directory} or @code{Repository} which is sent before the command).
+
+@item Max-dotdot @var{level} \n
+Tell the server that @var{level} levels of directories above the
+directory which @code{Directory} requests are relative to will be
+needed. For example, if the client is planning to use a
+@code{Directory} request for @file{../../foo}, it must send a
+@code{Max-dotdot} request with a @var{level} of at least 2.
+@code{Max-dotdot} must be sent before the first @code{Directory}
+request.
+
+@item Static-directory \n
+Response expected: no. Tell the server that the directory most recently
+specified with @code{Repository} or @code{Directory} should not have
+additional files checked out unless explicitly requested. The client
+sends this if the @code{Entries.Static} flag is set, which is controlled
+by the @code{Set-static-directory} and @code{Clear-static-directory}
+responses.
+
+@item Sticky @var{tagspec} \n
+Response expected: no. Tell the server that the directory most recently
+specified with @code{Repository} has a sticky tag or date @var{tagspec}.
+The first character of @var{tagspec} is @samp{T} for a tag, or @samp{D}
+for a date. The remainder of @var{tagspec} contains the actual tag or
+date.
+
+@item Checkin-prog @var{program} \n
+Response expected: no. Tell the server that the directory most recently
+specified with @code{Directory} has a checkin program @var{program}.
+Such a program would have been previously set with the
+@code{Set-checkin-prog} response.
+
+@item Update-prog @var{program} \n
+Response expected: no. Tell the server that the directory most recently
+specified with @code{Directory} has an update program @var{program}.
+Such a program would have been previously set with the
+@code{Set-update-prog} response.
+
+@item Entry @var{entry-line} \n
+Response expected: no. Tell the server what version of a file is on the
+local machine. The name in @var{entry-line} is a name relative to the
+directory most recently specified with @code{Repository}. If the user
+is operating on only some files in a directory, @code{Entry} requests
+for only those files need be included. If an @code{Entry} request is
+sent without @code{Modified}, @code{Unchanged}, or @code{Lost} for that
+file the meaning depends on whether @code{UseUnchanged} has been sent;
+if it has been it means the file is lost, if not it means the file is
+unchanged.
+
+@item Modified @var{filename} \n
+Response expected: no. Additional data: mode, \n, file transmission.
+Send the server a copy of one locally modified file. @var{filename} is
+relative to the most recent repository sent with @code{Repository}. If
+the user is operating on only some files in a directory, only those
+files need to be included. This can also be sent without @code{Entry},
+if there is no entry for the file.
+
+@item Lost @var{filename} \n
+Response expected: no. Tell the server that @var{filename} no longer
+exists. The name is relative to the most recent repository sent with
+@code{Repository}. This is used for any case in which @code{Entry} is
+being sent but the file no longer exists. If the client has issued the
+@code{UseUnchanged} request, then this request is not used.
+
+@item Unchanged @var{filename} \n
+Response expected: no. Tell the server that @var{filename} has not been
+modified in the checked out directory. The name is relative to the most
+recent repository sent with @code{Repository}. This request can only be
+issued if @code{UseUnchanged} has been sent.
+
+@item UseUnchanged \n
+Response expected: no. Tell the server that the client will be
+indicating unmodified files with @code{Unchanged}, and that files for
+which no information is sent are nonexistent on the client side, not
+unchanged. This is necessary for correct behavior since only the server
+knows what possible files may exist, and thus what files are
+nonexistent.
+
+@item Argument @var{text} \n
+Response expected: no.
+Save argument for use in a subsequent command. Arguments
+accumulate until an argument-using command is given, at which point
+they are forgotten.
+
+@item Argumentx @var{text} \n
+Response expected: no. Append \n followed by text to the current
+argument being saved.
+
+@item Global_option @var{option} \n
+Transmit one of the global options @samp{-q}, @samp{-Q}, @samp{-l},
+@samp{-t}, @samp{-r}, or @samp{-n}. @var{option} must be one of those
+strings, no variations (such as combining of options) are allowed. For
+graceful handling of @code{valid-requests}, it is probably better to
+make new global options separate requests, rather than trying to add
+them to this request.
+
+@item expand-modules \n
+Response expected: yes. Expand the modules which are specified in the
+arguments. Returns the data in @code{Module-expansion} responses. Note
+that the server can assume that this is checkout or export, not rtag or
+rdiff; the latter do not access the working directory and thus have no
+need to expand modules on the client side.
+
+@item co \n
+@itemx update \n
+@itemx ci \n
+@itemx diff \n
+@itemx tag \n
+@itemx status \n
+@itemx log \n
+@itemx add \n
+@itemx remove \n
+@itemx rdiff \n
+@itemx rtag \n
+@itemx import \n
+@itemx admin \n
+@itemx export \n
+@itemx history \n
+@itemx release \n
+Response expected: yes. Actually do a cvs command. This uses any
+previous @code{Argument}, @code{Repository}, @code{Entry},
+@code{Modified}, or @code{Lost} requests, if they have been sent. The
+last @code{Repository} sent specifies the working directory at the time
+of the operation. No provision is made for any input from the user.
+This means that @code{ci} must use a @code{-m} argument if it wants to
+specify a log message.
+
+@item update-patches \n
+This request does not actually do anything. It is used as a signal that
+the server is able to generate patches when given an @code{update}
+request. The client must issue the @code{-u} argument to @code{update}
+in order to receive patches.
+
+@item gzip-file-contents @var{level} \n
+This request asks the server to filter files it sends to the client
+through the @samp{gzip} program, using the specified level of
+compression. If this request is not made, the server must not do any
+compression.
+
+This is only a hint to the server. It may still decide (for example, in
+the case of very small files, or files that already appear to be
+compressed) not to do the compression. Compression is indicated by a
+@samp{z} preceding the file length.
+
+Availability of this request in the server indicates to the client that
+it may compress files sent to the server, regardless of whether the
+client actually uses this request.
+
+@item @var{other-request} @var{text} \n
+Response expected: yes.
+Any unrecognized request expects a response, and does not
+contain any additional data. The response will normally be something like
+@samp{error unrecognized request}, but it could be a different error if
+a previous command which doesn't expect a response produced an error.
+@end table
+
+When the client is done, it drops the connection.
+
+@node Responses
+@section Responses
+
+After a command which expects a response, the server sends however many
+of the following responses are appropriate. Pathnames are of the actual
+files operated on (i.e. they do not contain @samp{,v} endings), and are
+suitable for use in a subsequent @code{Repository} request. However, if
+the client has used the @code{Directory} request, then it is instead a
+local directory name relative to the directory in which the command was
+given (i.e. the last @code{Directory} before the command). Then a
+newline and a repository name (the pathname which is sent if
+@code{Directory} is not used). Then the slash and the filename. For
+example, for a file @file{i386.mh} which is in the local directory
+@file{gas.clean/config} and for which the repository is
+@file{/rel/cvsfiles/devo/gas/config}:
+
+@example
+gas.clean/config/
+/rel/cvsfiles/devo/gas/config/i386.mh
+@end example
+
+Any response always ends with @samp{error} or @samp{ok}. This indicates
+that the response is over.
+
+@table @code
+@item Valid-requests @var{request-list} \n
+Indicate what requests the server will accept. @var{request-list}
+is a space separated list of tokens. If the server supports sending
+patches, it will include @samp{update-patches} in this list. The
+@samp{update-patches} request does not actually do anything.
+
+@item Checked-in @var{pathname} \n
+Additional data: New Entries line, \n. This means a file @var{pathname}
+has been successfully operated on (checked in, added, etc.). name in
+the Entries line is the same as the last component of @var{pathname}.
+
+@item New-entry @var{pathname} \n
+Additional data: New Entries line, \n. Like @code{Checked-in}, but the
+file is not up to date.
+
+@item Updated @var{pathname} \n
+Additional data: New Entries line, \n, mode, \n, file transmission. A
+new copy of the file is enclosed. This is used for a new revision of an
+existing file, or for a new file, or for any other case in which the
+local (client-side) copy of the file needs to be updated, and after
+being updated it will be up to date. If any directory in pathname does
+not exist, create it.
+
+@item Merged @var{pathname} \n
+This is just like @code{Updated} and takes the same additional data,
+with the one difference that after the new copy of the file is enclosed,
+it will still not be up to date. Used for the results of a merge, with
+or without conflicts.
+
+@item Patched @var{pathname} \n
+This is just like @code{Updated} and takes the same additional data,
+with the one difference that instead of sending a new copy of the file,
+the server sends a patch produced by @samp{diff -u}. This client must
+apply this patch, using the @samp{patch} program, to the existing file.
+This will only be used when the client has an exact copy of an earlier
+revision of a file. This response is only used if the @code{update}
+command is given the @samp{-u} argument.
+
+@item Checksum @var{checksum}\n
+The @var{checksum} applies to the next file sent over via
+@code{Updated}, @code{Merged}, or @code{Patched}. In the case of
+@code{Patched}, the checksum applies to the file after being patched,
+not to the patch itself. The client should compute the checksum itself,
+after receiving the file or patch, and signal an error if the checksums
+do not match. The checksum is the 128 bit MD5 checksum represented as
+32 hex digits. This response is optional, and is only used if the
+client supports it (as judged by the @code{Valid-responses} request).
+
+@item Copy-file @var{pathname} \n
+Additional data: @var{newname} \n. Copy file @var{pathname} to
+@var{newname} in the same directory where it already is. This does not
+affect @code{CVS/Entries}.
+
+@item Removed @var{pathname} \n
+The file has been removed from the repository (this is the case where
+cvs prints @samp{file foobar.c is no longer pertinent}).
+
+@item Remove-entry @var{pathname} \n
+The file needs its entry removed from @code{CVS/Entries}, but the file
+itself is already gone (this happens in response to a @code{ci} request
+which involves committing the removal of a file).
+
+@item Set-static-directory @var{pathname} \n
+This instructs the client to set the @code{Entries.Static} flag, which
+it should then send back to the server in a @code{Static-directory}
+request whenever the directory is operated on. @var{pathname} ends in a
+slash; its purpose is to specify a directory, not a file within a
+directory.
+
+@item Clear-static-directory @var{pathname} \n
+Like @code{Set-static-directory}, but clear, not set, the flag.
+
+@item Set-sticky @var{pathname} \n
+Additional data: @var{tagspec} \n. Tell the client to set a sticky tag
+or date, which should be supplied with the @code{Sticky} request for
+future operations. @var{pathname} ends in a slash; its purpose is to
+specify a directory, not a file within a directory. The first character
+of @var{tagspec} is @samp{T} for a tag, or @samp{D} for a date. The
+remainder of @var{tagspec} contains the actual tag or date.
+
+@item Clear-sticky @var{pathname} \n
+Clear any sticky tag or date set by @code{Set-sticky}.
+
+@item Set-checkin-prog @var{dir} \n
+Additional data: @var{prog} \n. Tell the client to set a checkin
+program, which should be supplied with the @code{Checkin-prog} request
+for future operations.
+
+@item Set-update-prog @var{dir} \n
+Additional data: @var{prog} \n. Tell the client to set an update
+program, which should be supplied with the @code{Update-prog} request
+for future operations.
+
+@item Module-expansion @var{pathname} \n
+Return a file or directory which is included in a particular module.
+@var{pathname} is relative to cvsroot, unlike most pathnames in
+responses.
+
+@item M @var{text} \n
+A one-line message for the user.
+
+@item E @var{text} \n
+Same as @code{M} but send to stderr not stdout.
+
+@item error @var{errno-code} @samp{ } @var{text} \n
+The command completed with an error. @var{errno-code} is a symbolic
+error code (e.g. @code{ENOENT}); if the server doesn't support this
+feature, or if it's not appropriate for this particular message, it just
+omits the errno-code (in that case there are two spaces after
+@samp{error}). Text is an error message such as that provided by
+strerror(), or any other message the server wants to use.
+
+@item ok \n
+The command completed successfully.
+@end table
+
+@node Example
+@section Example
+
+Lines beginning with @samp{c>} are sent by the client; lines beginning
+with @samp{s>} are sent by the server; lines beginning with @samp{#} are
+not part of the actual exchange.
+
+@example
+c> Root /rel/cvsfiles
+# In actual practice the lists of valid responses and requests would
+# be longer
+c> Valid-responses Updated Checked-in M ok error
+c> valid-requests
+s> Valid-requests Root co Modified Entry Repository ci Argument Argumentx
+s> ok
+# cvs co devo/foo
+c> Argument devo/foo
+c> co
+s> Updated /rel/cvsfiles/devo/foo/foo.c
+s> /foo.c/1.4/Mon Apr 19 15:36:47 1993 Mon Apr 19 15:36:47 1993//
+s> 26
+s> int mein () @{ abort (); @}
+s> Updated /rel/cvsfiles/devo/foo/Makefile
+s> /Makefile/1.2/Mon Apr 19 15:36:47 1993 Mon Apr 19 15:36:47 1993//
+s> 28
+s> foo: foo.c
+s> $(CC) -o foo $<
+s> ok
+# In actual practice the next part would be a separate connection.
+# Here it is shown as part of the same one.
+c> Repository /rel/cvsfiles/devo/foo
+# foo.c relative to devo/foo just set as Repository.
+c> Entry /foo.c/1.4/Mon Apr 19 15:36:47 1993 Mon Apr 19 15:36:47 1993//
+c> Entry /Makefile/1.2/Mon Apr 19 15:36:47 1993 Mon Apr 19 15:36:47 1993//
+c> Modified foo.c
+c> 26
+c> int main () @{ abort (); @}
+# cvs ci -m <log message> foo.c
+c> Argument -m
+c> Argument Well, you see, it took me hours and hours to find this typo and I
+c> Argumentx searched and searched and eventually had to ask John for help.
+c> Argument foo.c
+c> ci
+s> Checked-in /rel/cvsfiles/devo/foo/foo.c
+s> /foo.c/1.5/ Mon Apr 19 15:54:22 CDT 1993//
+s> M Checking in foo.c;
+s> M /cygint/rel/cvsfiles/devo/foo/foo.c,v <-- foo.c
+s> M new revision: 1.5; previous revision: 1.4
+s> M done
+s> ok
+@end example
+@bye
diff --git a/gnu/usr.bin/cvs/examples/Makefile b/gnu/usr.bin/cvs/examples/Makefile
new file mode 100644
index 0000000..1855b78
--- /dev/null
+++ b/gnu/usr.bin/cvs/examples/Makefile
@@ -0,0 +1,18 @@
+# $Id: Makefile,v 1.2 1995/07/25 00:31:56 bde Exp $
+
+CVSFILES= checkoutlist commitinfo cvswrappers editinfo loginfo modules \
+ rcsinfo rcstemplate taginfo unwrap wrap
+
+EXAMPDIR = /usr/share/examples/cvs
+
+NOMAN = noman
+NOOBJ = noobj
+
+all clean:
+ @echo -n
+
+install:
+ ${INSTALL} -c -o ${BINOWN} -g ${BINGRP} -m 444 ${CVSFILES} \
+ ${DESTDIR}${EXAMPDIR}/examples
+
+.include <bsd.prog.mk>
diff --git a/gnu/usr.bin/cvs/examples/checkoutlist b/gnu/usr.bin/cvs/examples/checkoutlist
new file mode 100644
index 0000000..45ee6dc
--- /dev/null
+++ b/gnu/usr.bin/cvs/examples/checkoutlist
@@ -0,0 +1,20 @@
+#
+#ident "@(#)cvs/examples:$Name: $:$Id: checkoutlist,v 1.2 1995/11/14 23:24:49 woods Exp $"
+#
+# The "checkoutlist" file is used to support additional version controlled
+# administrative files in $CVSROOT/CVSROOT, such as template files.
+#
+# The first entry on a line is a filename which will be checked out from
+# the corresponding RCS file in the $CVSROOT/CVSROOT directory.
+# The remainder of the line is an error message to use if the file cannot
+# be checked out.
+#
+# File format:
+#
+# [<whitespace>]<filename><whitespace><error message><end-of-line>
+#
+# comment lines begin with '#'
+#
+rcstemplate
+wrap
+unwrap
diff --git a/gnu/usr.bin/cvs/examples/commitinfo b/gnu/usr.bin/cvs/examples/commitinfo
new file mode 100644
index 0000000..3964798
--- /dev/null
+++ b/gnu/usr.bin/cvs/examples/commitinfo
@@ -0,0 +1,27 @@
+#
+#ident "@(#)cvs/examples:$Name: $:$Id: commitinfo,v 1.3 1995/11/14 23:30:05 woods Exp $"
+#
+# The "commitinfo" file is used to control pre-commit checks.
+# The filter on the right is invoked with the repository and a list
+# of files to check. A non-zero exit of the filter program will
+# cause the commit to be aborted.
+#
+# The first entry on a line is a regular expression which is tested
+# against the directory that the change is being committed to, relative
+# to the $CVSROOT. For the first match that is found, then the remainder
+# of the line is the name of the filter to run.
+#
+# If the repository name does not match any of the regular expressions in this
+# file, the "DEFAULT" line is used, if it is specified.
+#
+# If the name "ALL" appears as a regular expression it is always used
+# in addition to the first matching regex or "DEFAULT".
+#
+# NOTE: contrib/commit_prep usage:
+# -r - record directories affected by commit for use with contrib/log_accum
+# -c - check for things like "$Id" near head of file, no "$Log", etc.
+#
+^apc $CVSROOT/CVSROOT/commit_prep -r -c
+^misc $CVSROOT/CVSROOT/commit_prep -r
+CVSROOT $CVSROOT/CVSROOT/commit_prep -r -c
+DEFAULT $CVSROOT/CVSROOT/commit_prep
diff --git a/gnu/usr.bin/cvs/examples/cvswrappers b/gnu/usr.bin/cvs/examples/cvswrappers
new file mode 100644
index 0000000..c666292
--- /dev/null
+++ b/gnu/usr.bin/cvs/examples/cvswrappers
@@ -0,0 +1,29 @@
+#
+#ident "@(#)cvs/examples:$Name: $:$Id: cvswrappers,v 1.3 1995/11/14 23:23:11 woods Exp $"
+#
+# This file describes wrappers and other binary files to CVS.
+#
+# Wrappers are the concept where directories of files are to be
+# treated as a single file. The intended use is to wrap up a wrapper
+# into a single tar such that the tar archive can be treated as a
+# single binary file in CVS.
+#
+# To solve the problem effectively, it was also necessary to be able to
+# prevent rcsmerge from merging these files.
+#
+# Format of wrapper file ($CVSROOT/CVSROOT/cvswrappers or .cvswrappers)
+#
+# wildcard [option value][option value]...
+#
+# where option is one of
+# -f from cvs filter value: path to filter
+# -t to cvs filter value: path to filter
+# -m update methodology value: MERGE or COPY
+#
+# and value is a single-quote delimited value.
+#
+#
+*.nib -f '$CVSROOT/CVSROOT/unwrap %s' -t '$CVSROOT/CVSROOT/wrap %s %s'
+*.rtfd -f '$CVSROOT/CVSROOT/unwrap %s' -t '$CVSROOT/CVSROOT/wrap %s %s'
+*.draw -f '$CVSROOT/CVSROOT/unwrap %s' -t '$CVSROOT/CVSROOT/wrap %s %s'
+*.tiff -m 'COPY'
diff --git a/gnu/usr.bin/cvs/examples/editinfo b/gnu/usr.bin/cvs/examples/editinfo
new file mode 100644
index 0000000..976a986
--- /dev/null
+++ b/gnu/usr.bin/cvs/examples/editinfo
@@ -0,0 +1,32 @@
+#
+#ident "@(#)cvs/examples:$Name: $:$Id: editinfo,v 1.2 1995/11/14 23:30:07 woods Exp $"
+#
+# The "editinfo" file is used to allow verification of logging
+# information. It works best when a template (as specified in the
+# rcsinfo file) is provided for the logging procedure. Given a
+# template with locations for, a bug-id number, a list of people who
+# reviewed the code before it can be checked in, and an external
+# process to catalog the differences that were code reviewed, the
+# following test can be applied to the code:
+#
+# Making sure that the entered bug-id number is correct.
+# Validating that the code that was reviewed is indeed the code being
+# checked in (using the bug-id number or a seperate review
+# number to identify this particular code set.).
+#
+# If any of the above test failed, then the commit would be aborted.
+#
+# Actions such as mailing a copy of the report to each reviewer are
+# better handled by an entry in the loginfo file.
+#
+# Although these test could be handled by an interactive script being
+# called via an entry in commitinfo, The information reported in
+# such a script can't be easily merged into the report.
+#
+# One thing that should be noted is the the ALL keyword is not
+# supported. There can be only one entry that matches a given
+# repository.
+#
+# Note there is no "edit" example script currently available....
+#
+DEFAULT $CVSROOT/CVSROOT/edit "%s"
diff --git a/gnu/usr.bin/cvs/examples/loginfo b/gnu/usr.bin/cvs/examples/loginfo
new file mode 100644
index 0000000..1d68e7d
--- /dev/null
+++ b/gnu/usr.bin/cvs/examples/loginfo
@@ -0,0 +1,39 @@
+#
+#ident "@(#)cvs/examples:$Name: $:$Id: loginfo,v 1.4 1995/11/14 23:30:08 woods Exp $"
+#
+# The "loginfo" file is used to control where "cvs commit" log information
+# is sent. The first entry on a line is a regular expression which is tested
+# against the directory that the change is being made to, relative to the
+# $CVSROOT. For the first match that is found, then the remainder of the
+# line is a filter program that should expect log information on its standard
+# input.
+#
+# If the repository name does not match any of the regular expressions in the
+# first field of this file, the "DEFAULT" line is used, if it is specified.
+#
+# If the name "ALL" appears as a regular expression it is always used
+# in addition to the first matching regex or "DEFAULT".
+#
+# The filter program may use one and only one "%s" modifier (ala printf). If
+# such a "%s" is specified in the filter program, a brief title is included
+# (as one argument, enclosed in single quotes) showing the relative directory
+# name and listing the modified file names.
+#
+# NOTE: contrib/log usage: (currently requires perl)
+# -d - turn debugging on....
+# -m mailto - send mail to "mailto" (multiple -m's permitted)
+# -f logfile - required arg: save messages to logfile
+# %s - may follow other options at the end of the line
+#
+# NOTE: contrib/log_accum usage: (currently requires perl)
+# (must have 'commit_prep -r' in commitinfo)
+# -d - turn debugging on....
+# -M modulename - use this as the module name (necessary for sub-dirs)
+# -m mailto - send mail to "mailto" (multiple -m's permitted) [optional]
+# -f logfile - save messages to logfile [optional]
+# %s - must follow other options at the end of the line
+#
+# without perl you could do this:
+#DEFAULT (echo ""; who am i; date; cat) >> $CVSROOT/CVSROOT/commitlog
+#
+DEFAULT $CVSROOT/CVSROOT/log -f $CVSROOT/CVSROOT/commitlog %s
diff --git a/gnu/usr.bin/cvs/examples/modules b/gnu/usr.bin/cvs/examples/modules
new file mode 100644
index 0000000..ac8cd4d
--- /dev/null
+++ b/gnu/usr.bin/cvs/examples/modules
@@ -0,0 +1,581 @@
+#
+# The CVS Modules File
+#
+#ident "@(#)cvs/examples:$Name: $:$Id: modules,v 1.4 1995/11/14 23:28:48 woods Exp $"
+#
+# Three different line formats are valid:
+# key -a aliases...
+# key [options] directory
+# key [options] directory files...
+#
+# Where "options" are composed of:
+# -i prog Run "prog" on "cvs commit" from top-level of module.
+# -o prog Run "prog" on "cvs checkout" of module.
+# -e prog Run "prog" on "cvs export" of module.
+# -t prog Run "prog" on "cvs rtag" of module.
+# -u prog Run "prog" on "cvs update" of module.
+# -d dir Place module in directory "dir" instead of module name.
+# -l Top-level directory only -- do not recurse.
+#
+# And "directory" is a path to a directory relative to $CVSROOT.
+#
+# The "-a" option specifies an alias. An alias is interpreted as if
+# everything on the right of the "-a" had been typed on the command line.
+#
+# You can encode a module within a module by using the special '&'
+# character to interpose another module into the current module. This
+# can be useful for creating a module that consists of many directories
+# spread out over the entire source repository.
+#
+
+# Convenient aliases
+world -a .
+
+# CVSROOT support
+CVSROOT -i /usr/local/bin/mkmodules CVSROOT
+commitinfo -i /usr/local/bin/mkmodules CVSROOT commitinfo
+cvswrappers -i /usr/local/bin/mkmodules CVSROOT cvswrappers
+editinfo -i /usr/local/bin/mkmodules CVSROOT editinfo
+modules -i /usr/local/bin/mkmodules CVSROOT modules
+loginfo -i /usr/local/bin/mkmodules CVSROOT loginfo
+rcsinfo -i /usr/local/bin/mkmodules CVSROOT rcsinfo
+rcstemplate -i /usr/local/bin/mkmodules CVSROOT rcstemplate
+taginfo -i /usr/local/bin/mkmodules CVSROOT taginfo
+
+# Add more modules here
+#
+# END_REQUIRED_CONTENT (this comment for cvsinit)
+#
+# The remainder was for the Prisma OS sources
+#
+
+# another convenient alias
+kernel -a sys lang/adb sparcsim
+
+# The "sys" entry exists only to make symbolic links after checkout
+sys -o sys/tools/make_links sys
+
+# Sub-directories of "bin"
+awk bin/awk
+csh bin/csh
+diff bin/diff
+make bin/make
+sed bin/sed
+sh bin/sh
+
+# Programs that live in "bin"
+cat bin Makefile cat.c
+chgrp bin Makefile chgrp.c
+chmod bin Makefile chmod.c
+cmp bin Makefile cmp.c
+cp bin Makefile cp.c
+date bin Makefile date.c
+dd bin Makefile dd.c
+df bin Makefile df.c
+domainname bin Makefile domainname.c
+du bin Makefile du.c
+echo bin Makefile echo.c
+ed bin Makefile ed.c
+env bin Makefile env.c
+expr bin Makefile expr.c
+grep bin Makefile grep.c
+hostid bin Makefile hostid.c
+hostname bin Makefile hostname.c
+kill bin Makefile kill.c
+ldd bin Makefile ldd.c
+line bin Makefile line.c
+ln bin Makefile ln.c
+login bin Makefile login.c
+ls bin Makefile ls.c
+mail bin Makefile mail.c
+mkdir bin Makefile mkdir.c
+mt bin Makefile mt.c
+mv bin Makefile mv.c
+newgrp bin Makefile newgrp.c
+nice bin Makefile nice.c
+od bin Makefile od.c
+pagesize bin Makefile pagesize.c
+passwd bin Makefile passwd.c
+pr bin Makefile pr.c
+ps bin Makefile ps.c
+pwd bin Makefile pwd.c
+rm bin Makefile rm.c
+rmail bin Makefile rmail.c
+rmdir bin Makefile rmdir.c
+stty bin Makefile stty.c
+su bin Makefile su.c
+sync bin Makefile sync.c
+tar bin Makefile tar.c
+tee bin Makefile tee.c
+test bin Makefile test.c
+time bin Makefile time.c
+wall bin Makefile wall.c
+who bin Makefile who.c
+write bin Makefile write.c
+
+# Sub-directories of "etc"
+dump etc/dump
+files etc/files
+fsck etc/fsck
+getty etc/getty
+in.routed etc/in.routed
+restore etc/restore
+rpc.lockd etc/rpc.lockd
+rpc.statd etc/rpc.statd
+
+# Programs that live in "etc"
+arp etc Makefile arp.c
+biod etc Makefile biod.c
+chown etc Makefile chown.c
+clri etc Makefile clri.c
+dkinfo etc Makefile dkinfo.c
+dmesg etc Makefile dmesg.c
+fsirand etc Makefile fsirand.c
+halt etc Makefile halt.c
+ifconfig etc Makefile ifconfig.c
+in.rlogind etc Makefile in.rlogind.c
+in.rshd etc Makefile in.rshd.c
+inetd etc Makefile inetd.c
+init etc Makefile init.c
+mkfs etc Makefile mkfs.c
+mknod etc Makefile mknod.c
+mount etc Makefile mount.c
+newfs etc Makefile newfs.c
+nfsd etc Makefile nfsd.c
+portmap etc Makefile portmap.c
+pstat etc Makefile pstat.c
+reboot etc Makefile reboot.c
+renice etc Makefile renice.c
+rmt etc Makefile rmt.c
+shutdown etc Makefile shutdown.c
+syslogd etc Makefile syslogd.c
+umount etc Makefile umount.c
+update etc Makefile update.c
+vipw etc Makefile vipw.c
+ypbind etc Makefile ypbind.c
+
+# Sub-directories of "games"
+adventure games/adventure
+backgammon games/backgammon
+battlestar games/battlestar
+boggle games/boggle
+chess games/chess
+ching games/ching
+cribbage games/cribbage
+fortune games/fortune
+hack games/hack
+hangman games/hangman
+hunt games/hunt
+life games/life
+mille games/mille
+monop games/monop
+quiz games/quiz
+robots games/robots
+sail games/sail
+snake games/snake
+trek games/trek
+
+# Programs that live in "games"
+arithmetic games Makefile arithmetic.c
+banner games Makefile banner.c
+bcd games Makefile bcd.c
+bj games Makefile bj.c
+btlgammon games Makefile btlgammon.c
+canfield games Makefile canfield.c
+cfscores games Makefile cfscores.c
+craps games Makefile craps.c
+factor games Makefile factor.c
+fish games Makefile fish.c
+moo games Makefile moo.c
+number games Makefile number.c
+primes games Makefile primes.c
+rain games Makefile rain.c
+random games Makefile random.c
+worm games Makefile worm.c
+worms games Makefile worms.c
+wump games Makefile wump.c
+
+# Sub-directories of "lang"
+adb lang/adb
+as lang/as
+boot lang/boot
+c2 lang/c2
+cgrdr lang/cgrdr
+compile lang/compile
+cpp lang/cpp
+dbx lang/dbx
+f77 lang/f77
+inline lang/inline
+iropt lang/iropt
+ld lang/ld
+lint lang/lint
+m4 lang/m4
+pascal lang/pascal
+pcc lang/pcc
+ratfor lang/ratfor
+rtld lang/rtld
+tcov lang/tcov
+vroot lang/vroot
+
+# Programs that live in "lang"
+ar lang Makefile ar.c
+nm lang Makefile nm.c
+ranlib lang Makefile ranlib.c
+size lang Makefile size.c
+strip lang Makefile strip.c
+symorder lang Makefile symorder.c
+
+# Sub-directories of "lib"
+csu lib/csu
+libc lib/libc
+
+# Programs that live in "lib"
+# NONE
+
+# Sub-directories of "lib/libc"
+libc_compat lib/libc/compat
+libc_crt lib/libc/crt
+libc_des lib/libc/des
+libc_gen lib/libc/gen
+libc_net lib/libc/net
+libc_inet lib/libc/inet
+libc_rpc lib/libc/rpc
+libc_stdio lib/libc/stdio
+libc_sun lib/libc/sun
+libc_sys lib/libc/sys
+libc_yp lib/libc/yp
+
+# Programs that live in "lib/libc"
+# NONE
+
+#Sub-directories of "local"
+notes local/notes
+
+# Sub-directories of "man"
+man1 man/man1
+man2 man/man2
+man3 man/man3
+man4 man/man4
+man5 man/man5
+man6 man/man6
+man7 man/man7
+man8 man/man8
+manl man/manl
+
+# Programs that live in "man"
+# NONE
+
+# Sub-directories of "old"
+old_compact old/compact
+old_eyacc old/eyacc
+old_filemerge old/filemerge
+old_make old/make
+
+# Programs that live in "old"
+old_analyze old Makefile analyze.c
+old_prmail old Makefile prmail.c
+old_pti old Makefile pti.c
+old_syslog old Makefile syslog.c
+
+# Sub-directories of "ucb"
+Mail ucb/Mail
+compress ucb/compress
+error ucb/error
+ex ucb/ex
+ftp ucb/ftp
+gprof ucb/gprof
+indent ucb/indent
+lpr ucb/lpr
+more ucb/more
+msgs ucb/msgs
+netstat ucb/netstat
+rdist ucb/rdist
+talk ucb/talk
+tftp ucb/tftp
+tset ucb/tset
+vgrind ucb/vgrind
+
+# Programs that live in "ucb"
+biff ucb Makefile biff.c
+checknr ucb Makefile checknr.c
+clear ucb Makefile clear.c
+colcrt ucb Makefile colcrt.c
+colrm ucb Makefile colrm.c
+ctags ucb Makefile ctags.c
+expand ucb Makefile expand.c
+finger ucb Makefile finger.c
+fold ucb Makefile fold.c
+from ucb Makefile from.c
+fsplit ucb Makefile fsplit.c
+gcore ucb Makefile gcore.c
+groups ucb Makefile groups.c
+head ucb Makefile head.c
+last ucb Makefile last.c
+lastcomm ucb Makefile lastcomm.c
+leave ucb Makefile leave.c
+logger ucb Makefile logger.c
+man_prog ucb Makefile man.c
+mkstr ucb Makefile mkstr.c
+printenv ucb Makefile printenv.c
+quota ucb Makefile quota.c
+rcp ucb Makefile rcp.c
+rdate ucb Makefile rdate.c
+rlogin ucb Makefile rlogin.c
+rsh ucb Makefile rsh.c
+rup ucb Makefile rup.c
+ruptime ucb Makefile ruptime.c
+rusers ucb Makefile rusers.c
+rwho ucb Makefile rwho.c
+sccs ucb Makefile sccs.c
+script ucb Makefile script.c
+soelim ucb Makefile soelim.c
+strings ucb Makefile strings.c
+tail ucb Makefile tail.c
+tcopy ucb Makefile tcopy.c
+telnet ucb Makefile telnet.c
+ul ucb Makefile ul.c
+unexpand ucb Makefile unexpand.c
+unifdef ucb Makefile unifdef.c
+users ucb Makefile users.c
+vmstat ucb Makefile vmstat.c
+w ucb Makefile w.c
+wc ucb Makefile wc.c
+what ucb Makefile what.c
+whatis ucb Makefile whatis.c
+whereis ucb Makefile whereis.c
+whoami ucb Makefile whoami.c
+whois ucb Makefile whois.c
+xstr ucb Makefile xstr.c
+yes ucb Makefile yes.c
+
+# Sub-directories of "usr.bin"
+calendar usr.bin/calendar
+cflow usr.bin/cflow
+ctrace usr.bin/ctrace
+cxref usr.bin/cxref
+dc usr.bin/dc
+des usr.bin/des
+diff3 usr.bin/diff3
+sun_eqn usr.bin/eqn
+file usr.bin/file
+find usr.bin/find
+graph usr.bin/graph
+lex usr.bin/lex
+sun_neqn usr.bin/neqn
+sun_nroff usr.bin/nroff
+sun_plot usr.bin/plot
+prof usr.bin/prof
+refer usr.bin/refer
+rpcgen usr.bin/rpcgen
+spell usr.bin/spell
+sun_tbl usr.bin/tbl
+tip usr.bin/tip
+trace usr.bin/trace
+sun_troff usr.bin/troff
+uucp usr.bin/uucp
+xsend usr.bin/xsend
+yacc usr.bin/yacc
+
+# Programs that live in "usr.bin"
+basename usr.bin Makefile basename.c
+bc usr.bin Makefile bc.c
+cal usr.bin Makefile cal.c
+cb usr.bin Makefile cb.c
+checkeq usr.bin Makefile checkeq.c
+chkey usr.bin Makefile chkey.c
+click usr.bin Makefile click.c
+col usr.bin Makefile col.c
+comm usr.bin Makefile comm.c
+cpio usr.bin Makefile cpio.c
+crypt usr.bin Makefile crypt.c
+csplit usr.bin Makefile csplit.c
+cut usr.bin Makefile cut.c
+deroff usr.bin Makefile deroff.c
+egrep usr.bin Makefile egrep.c
+fgrep usr.bin Makefile fgrep.c
+getopt usr.bin Makefile getopt.c
+id usr.bin Makefile id.c
+installcmd usr.bin Makefile installcmd.c
+iostat usr.bin Makefile iostat.c
+ipcrm usr.bin Makefile ipcrm.c
+ipcs usr.bin Makefile ipcs.c
+join usr.bin Makefile join.c
+keylogin usr.bin Makefile keylogin.c
+logname usr.bin Makefile logname.c
+look usr.bin Makefile look.c
+mesg usr.bin Makefile mesg.c
+nl usr.bin Makefile nl.c
+pack usr.bin Makefile pack.c
+paste usr.bin Makefile paste.c
+ptx usr.bin Makefile ptx.c
+rev usr.bin Makefile rev.c
+screenblank usr.bin Makefile screenblank.c
+sdiff usr.bin Makefile sdiff.c
+sleep usr.bin Makefile sleep.c
+sort usr.bin Makefile sort.c
+spline usr.bin Makefile spline.c
+split usr.bin Makefile split.c
+sum usr.bin Makefile sum.c
+touch usr.bin Makefile touch.c
+tr usr.bin Makefile tr.c
+tsort usr.bin Makefile tsort.c
+tty usr.bin Makefile tty.c
+uniq usr.bin Makefile uniq.c
+units usr.bin Makefile units.c
+unpack usr.bin Makefile unpack.c
+xargs usr.bin Makefile xargs.c
+ypcat usr.bin Makefile ypcat.c
+ypmatch usr.bin Makefile ypmatch.c
+yppasswd usr.bin Makefile yppasswd.c
+ypwhich usr.bin Makefile ypwhich.c
+
+# Sub-directories of "usr.etc"
+automount usr.etc/automount
+c2convert usr.etc/c2convert
+config usr.etc/config
+cron usr.etc/cron
+eeprom usr.etc/eeprom
+etherfind usr.etc/etherfind
+format usr.etc/format
+htable usr.etc/htable
+implog usr.etc/implog
+in.ftpd -a usr.etc/in.ftpd ucb/ftp
+in.named usr.etc/in.named
+in.rwhod usr.etc/in.rwhod
+keyserv usr.etc/keyserv
+ndbootd usr.etc/ndbootd
+praudit usr.etc/praudit
+rexd usr.etc/rexd
+rpc.bootparamd usr.etc/rpc.bootparamd
+termcap usr.etc/termcap
+upgrade usr.etc/upgrade
+yp usr.etc/yp
+zic usr.etc/zic
+
+# Programs that live in "usr.etc"
+ac usr.etc Makefile ac.c
+accton usr.etc Makefile accton.c
+audit usr.etc Makefile audit.c
+auditd usr.etc Makefile auditd.c
+catman usr.etc Makefile catman.c
+chroot usr.etc Makefile chroot.c
+dcheck usr.etc Makefile dcheck.c
+devnm usr.etc Makefile devnm.c
+dumpfs usr.etc Makefile dumpfs.c
+edquota usr.etc Makefile edquota.c
+exportfs usr.etc Makefile exportfs.c
+foption usr.etc Makefile foption.c
+gettable usr.etc Makefile gettable.c
+grpck usr.etc Makefile grpck.c
+icheck usr.etc Makefile icheck.c
+in.comsat usr.etc Makefile in.comsat.c
+in.fingerd usr.etc Makefile in.fingerd.c
+in.rexecd usr.etc Makefile in.rexecd.c
+in.telnetd usr.etc Makefile in.telnetd.c
+in.tnamed usr.etc Makefile in.tnamed.c
+kgmon usr.etc Makefile kgmon.c
+link usr.etc Makefile link.c
+mkfile usr.etc Makefile mkfile.c
+mkproto usr.etc Makefile mkproto.c
+mount_lo usr.etc Makefile mount_lo.c
+ncheck usr.etc Makefile ncheck.c
+nfsstat usr.etc Makefile nfsstat.c
+ping usr.etc Makefile ping.c
+pwck usr.etc Makefile pwck.c
+quot usr.etc Makefile quot.c
+quotacheck usr.etc Makefile quotacheck.c
+quotaon usr.etc Makefile quotaon.c
+rarpd usr.etc Makefile rarpd.c
+repquota usr.etc Makefile repquota.c
+route usr.etc Makefile route.c
+rpc.etherd usr.etc Makefile rpc.etherd.c
+rpc.mountd usr.etc Makefile rpc.mountd.c
+rpc.pwdauthd usr.etc Makefile rpc.pwdauthd.c
+rpc.rquotad usr.etc Makefile rpc.rquotad.c
+rpc.rstatd usr.etc Makefile rpc.rstatd.c
+rpc.rusersd usr.etc Makefile rpc.rusersd.c
+rpc.rwalld usr.etc Makefile rpc.rwalld.c
+rpc.sprayd usr.etc Makefile rpc.sprayd.c
+rpc.yppasswdd usr.etc Makefile rpc.yppasswdd.c
+rpc.ypupdated usr.etc Makefile rpc.ypupdated.c
+rpcinfo usr.etc Makefile rpcinfo.c
+rwall usr.etc Makefile rwall.c
+sa usr.etc Makefile sa.c
+savecore usr.etc Makefile savecore.c
+showmount usr.etc Makefile showmount.c
+spray usr.etc Makefile spray.c
+swapon usr.etc Makefile swapon.c
+trpt usr.etc Makefile trpt.c
+tunefs usr.etc Makefile tunefs.c
+unlink usr.etc Makefile unlink.c
+
+# Sub-directories of "usr.lib"
+bb_count usr.lib/bb_count
+fixedwidthfonts usr.lib/fixedwidthfonts
+libcurses usr.lib/libcurses
+libdbm usr.lib/libdbm
+libg usr.lib/libg
+libkvm usr.lib/libkvm
+libln usr.lib/libln
+liblwp usr.lib/liblwp
+libm usr.lib/libm
+libmp usr.lib/libmp
+libpixrect usr.lib/libpixrect
+libplot usr.lib/libplot
+libresolv usr.lib/libresolv
+librpcsvc usr.lib/librpcsvc
+libtermlib usr.lib/libtermlib
+liby usr.lib/liby
+me usr.lib/me
+ms usr.lib/ms
+sendmail usr.lib/sendmail
+sun_tmac usr.lib/tmac
+vfont usr.lib/vfont
+
+# Programs that live in "usr.lib"
+getNAME usr.lib Makefile getNAME
+makekey usr.lib Makefile makekey
+
+# Sub-directories of "5bin"
+5diff3 5bin/diff3
+5m4 5bin/m4
+
+# Sub-directories of "5bin", but use sources from other places
+5cxref -a 5bin/cxref usr.bin/cxref
+5sed -a 5bin/sed bin/sed
+5lint -a 5bin/lint lang/pcc lang/lint
+
+# Programs that live in "5bin"
+5banner 5bin Makefile banner.c
+5cat 5bin Makefile cat.c
+5du 5bin Makefile du.c
+5echo 5bin Makefile echo.c
+5expr 5bin Makefile expr.c
+5ls 5bin Makefile ls.c
+5nohup 5bin Makefile nohup.c
+5od 5bin Makefile od.c
+5pg 5bin Makefile pg.c
+5pr 5bin Makefile pr.c
+5sum 5bin Makefile sum.c
+5tabs 5bin Makefile tabs.c
+5time 5bin Makefile time.c
+5tr 5bin Makefile tr.c
+5uname 5bin Makefile uname.c
+
+# Programs that live in "5bin", but use sources from other places
+5chmod -a 5bin/Makefile bin/chmod.c
+5date -a 5bin/Makefile bin/date.c
+5grep -a 5bin/Makefile bin/grep.c
+5stty -a 5bin/Makefile bin/stty.c
+5col -a 5bin/Makefile usr.bin/col.c
+5sort -a 5bin/Makefile usr.bin/sort.c
+5touch -a 5bin/Makefile usr.bin/touch.c
+
+# Sub-directories of "5lib"
+5compile 5lib/compile
+5libcurses 5lib/libcurses
+5liby 5lib/liby
+5terminfo 5lib/terminfo
+
+# Programs that live in "5lib"
+# NONE
diff --git a/gnu/usr.bin/cvs/examples/rcsinfo b/gnu/usr.bin/cvs/examples/rcsinfo
new file mode 100644
index 0000000..c90e9e0
--- /dev/null
+++ b/gnu/usr.bin/cvs/examples/rcsinfo
@@ -0,0 +1,18 @@
+#
+#ident "@(#)cvs/examples:$Name: $:$Id: rcsinfo,v 1.3 1995/11/14 23:30:10 woods Exp $"
+#
+# The "rcsinfo" file is used to control templates with which the editor
+# is invoked on commit and import.
+#
+# The first entry on a line is a regular expression which is tested
+# against the directory that the change is being made to, relative to the
+# $CVSROOT. For the first match that is found, then the remainder of the
+# line is the name of the file that contains the template.
+#
+# If the repository name does not match any of the regular expressions in this
+# file, the "DEFAULT" line is used, if it is specified.
+#
+# If the name "ALL" appears as a regular expression it is always used
+# in addition to the first matching regex or "DEFAULT".
+#
+DEFAULT $CVSROOT/CVSROOT/rcstemplate
diff --git a/gnu/usr.bin/cvs/examples/rcstemplate b/gnu/usr.bin/cvs/examples/rcstemplate
new file mode 100644
index 0000000..c9a2d1e
--- /dev/null
+++ b/gnu/usr.bin/cvs/examples/rcstemplate
@@ -0,0 +1,7 @@
+CVS:
+CVS: WARNING: You are commiting a change to the main source repository.
+CVS:
+CVS: This change will be immediately available to all other users
+CVS: of this repository! Please be sure your changes have been
+CVS: adequately tested.
+CVS:
diff --git a/gnu/usr.bin/cvs/examples/taginfo b/gnu/usr.bin/cvs/examples/taginfo
new file mode 100644
index 0000000..02de62b
--- /dev/null
+++ b/gnu/usr.bin/cvs/examples/taginfo
@@ -0,0 +1,25 @@
+#
+#ident "@(#)cvs/examples:$Name: $:$Id: taginfo,v 1.3 1995/11/14 23:27:52 woods Exp $"
+#
+# The "taginfo" file is used to control pre-tag checks.
+# The filter on the right is invoked with the following arguments:
+#
+# $1 -- tagname
+# $2 -- operation "add" for tag, "mov" for tag -F, and "del" for tag -d
+# $3 -- repository
+# $4-> file revision [file revision ...]
+#
+# A non-zero exit of the filter program will cause the tag to be aborted.
+#
+# The first entry on a line is a regular expression which is tested
+# against the directory that the change is being committed to, relative
+# to the $CVSROOT. For the first match that is found, then the remainder
+# of the line is the name of the filter to run.
+#
+# If the repository name does not match any of the regular expressions in this
+# file, the "DEFAULT" line is used, if it is specified.
+#
+# If the name "ALL" appears as a regular expression it is always used
+# in addition to the first matching regex or "DEFAULT".
+#
+DEFAULT $CVSROOT/CVSROOT/tag_logging_program
diff --git a/gnu/usr.bin/cvs/examples/unwrap b/gnu/usr.bin/cvs/examples/unwrap
new file mode 100644
index 0000000..def0561
--- /dev/null
+++ b/gnu/usr.bin/cvs/examples/unwrap
@@ -0,0 +1,21 @@
+#! /bin/sh
+#
+# unwrap - extract the combined package (created with wrap)
+#
+#ident "@(#)cvs/examples:$Name: $:$Id: unwrap,v 1.1 1995/11/14 23:20:30 woods Exp $"
+
+# move the file to a new name with an extension
+rm -rf $1.cvswrap
+mv $1 $1.cvswrap
+
+# untar the file
+
+if `gzip -t $1.cvswrap > /dev/null 2>&1`
+then
+ gzcat -d $1.cvswrap | gnutar --preserve --sparse -x -f -
+else
+ gnutar --preserve --sparse -x -f $1.cvswrap
+fi
+
+# remove the original
+rm -rf $1.cvswrap
diff --git a/gnu/usr.bin/cvs/examples/wrap b/gnu/usr.bin/cvs/examples/wrap
new file mode 100644
index 0000000..b6a6a77
--- /dev/null
+++ b/gnu/usr.bin/cvs/examples/wrap
@@ -0,0 +1,21 @@
+#! /bin/sh
+#
+# wrap - Combine a directory into a single tar package.
+#
+#ident "@(#)cvs/examples:$Name: $:$Id: wrap,v 1.1 1995/11/14 23:20:32 woods Exp $"
+
+# This script is always called with the current directory set to
+# where the file to be combined exists. but i may get called with a
+# path to where cvs first started executing. (this probably should be
+# fixed in cvs) so strip out all of the directory information. The
+# first sed expression will only work if the path has a leading /
+# if it doesn't the one in the if statement will work.
+DIRNAME=`echo $1 | sed -e "s|/.*/||g"`
+if [ ! -d $DIRNAME ] ; then
+ DIRNAME=`echo $1 | sed -e "s|.*/||g"`
+fi
+#
+# Now tar up the directory but we now will only get a relative path
+# even if the user did a cvs commit . at the top.
+#
+gnutar --preserve --sparse -cf - $DIRNAME | gzip --no-name --best -c > $2
diff --git a/gnu/usr.bin/cvs/lib/ChangeLog b/gnu/usr.bin/cvs/lib/ChangeLog
new file mode 100644
index 0000000..c8aa4a4
--- /dev/null
+++ b/gnu/usr.bin/cvs/lib/ChangeLog
@@ -0,0 +1,335 @@
+Mon Dec 4 10:54:04 1995 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * getdate.c: Remove #line directives. I know, this is a kludge,
+ but Visual C++ 2.1 seems to require it (why, I have no idea. It
+ has no trouble with the #line directives in getdate in CVS 1.6).
+
+Sat Nov 18 16:20:37 1995 Karl Fogel <kfogel@floss.cyclic.com>
+
+ * rename.c: same.
+
+ * mkdir.c: Use new macro `existence_error', instead of comparing
+ errno to ENOENT directly.
+
+ * system.h (existence_error): new macro, tries to portably ask if
+ errno represents a file-not-exist error.
+
+Fri Nov 17 20:08:58 1995 Karl Fogel <kfogel@floss.cyclic.com>
+
+ * system.h (NEED_DECOY_PERMISSIONS): moved this section to where
+ it belongs, duh.
+
+ * getdate.c: if STDC_HEADERS, then just include <stdlib.h> instead
+ of declaring malloc() and realloc() to be char *.
+
+ * system.h: ifdef NEED_DECOY_PERMISSIONS, then define the S_I*
+ permission masks for USR, GRP, and OTH in terms of the simpler
+ OS/2 masks.
+
+Wed Nov 15 15:36:03 1995 Karl Fogel <kfogel@floss.cyclic.com>
+
+ * system.h: ifdef USE_OWN_TCPIP_H, then include "tcpip.h". Only
+ OS/2 does this right now.
+
+Tue Nov 14 18:44:57 1995 Greg A. Woods <woods@most.weird.com>
+
+ * getdate.c: OK, this one is from SunOS-4.1 yacc and may be more
+ portable -- at least it compiles silently here! ;-)
+
+Mon Nov 13 03:53:45 1995 Karl Fogel <kfogel@floss.cyclic.com>
+
+ * fnmatch.c: conform to 80 column standard (yes, I'm a pedant).
+
+Wed Nov 8 11:10:59 1995 Karl Fogel <kfogel@floss.cyclic.com>
+
+ * system.h (STAT_MACROS): ifdef S_IFMT, then use it as before; but
+ if it's not defined, then just do a single mask and assume
+ acceptance any of non-zero result. Norbert, I trust you'll let me
+ know if this is unsatisfactory. :-)
+ Ifdef HAVE_SYS_UTIME_H, then include <sys/utime.h>. Only OS/2
+ defines this right now.
+
+Wed Nov 8 13:18:51 1995 Norbert Kiesel <nk@col.sw-ley.de>
+
+ * valloc.c: omit malloc declaration (it's already in system.h
+ which is included and conflicts with <stdlib.h> on some
+ systems).
+
+Tue Nov 7 19:38:48 1995 Norbert Kiesel <nk@col.sw-ley.de>
+
+ * system.h (STAT_MACROS_BROKEN): undo previous change, because
+ else all regular files will be identified as links (the mask for
+ links is S_IFREG|S_IFCHR).
+
+Mon Nov 6 19:20:56 1995 Karl Fogel <kfogel@floss.cyclic.com>
+
+ * system.h (STAT_MACROS_BROKEN): in defining the S_IF* macros,
+ don't fold to 1 or 0 by first masking with S_IFMT; not all
+ systems have that macro, and anyway it's only necessary that we
+ return non-zero.
+
+Fri Oct 27 13:43:35 1995 Karl Fogel <kfogel@floss.cyclic.com>
+
+ * save-cwd.c: use __PROTO instead of __P (see below).
+
+ * getline.h (__PROTO): same as below.
+
+ * save-cwd.h (__PROTO): replaces __P. New name, so don't ask if
+ already defined. The conflict was that OS/2 w/ IBM C/C++ uses
+ `__P' for something else, in <ctype.h> of all places.
+
+ * system.h: do nothing about alloca ifdef ALLOCA_IN_STDLIB (see
+ ../src/ChangeLog).
+
+Tue Oct 24 13:01:25 1995 Norbert Kiesel <nk@col.sw-ley.de>
+
+ * wait.h: include sys/resource.h if available. This is needed at
+ least under AIX-3.2 where <sys/wait.h> doesn't include it.
+
+Mon Oct 23 17:39:11 1995 Norbert Kiesel <nk@col.sw-ley.de>
+
+ * valloc.c (valloc): change parameter definition
+
+Sun Oct 22 14:15:44 1995 Jim Meyering (meyering@comco.com)
+
+ * getline.c, getline.h: New files.
+ * Makefile.in (SOURCES, OBJECTS, HEADERS): Add getline.c, getline.o,
+ and getline.h, respectively.
+
+Tue Oct 10 18:01:50 1995 Karl Fogel <kfogel@totoro.cyclic.com>
+
+ * Makefile.in (cvs_srcdir): define cvs_srcdir to be ../src, then
+ include it with -I so save_cwd.c can find error.h (for example).
+
+Sun Oct 8 12:27:57 1995 Peter Wemm <peter@haywire.DIALix.COM>
+
+ * system.h: define POSIX_SIGNALS or BSD_SIGNALS if configure has
+ located all the necessary functions for each "type".
+ * sighandle.c: detect/use POSIX/BSD reliable signals (especially
+ for blocking signals in critical sections). Helps prevent stray
+ locks on interruption.
+
+Mon Oct 2 18:11:23 1995 Jim Blandy <jimb@totoro.cyclic.com>
+
+ * system.h: Doc fix.
+
+Mon Oct 2 18:10:35 1995 Larry Jones <larry.jones@sdrc.com>
+
+ * regex.c: compile 4.2 BSD compatible functions even when
+ _POSIX_SOURCE is defined since we need them and we wouldn't be
+ compiling this file unless they don't exist.
+
+Mon Oct 2 10:32:20 1995 Michael Finken <finken@conware.de>
+
+ * strstr.c (strstr): new file and func.
+
+ * Makefile.in (SOURCES): added strstr.c.
+
+Sun Oct 1 21:03:40 1995 Karl Fogel <kfogel@totoro.cyclic.com>
+
+ * regex.c: reverted below change.
+
+Thu Sep 28 13:37:04 1995 Larry Jones <larry.jones@sdrc.com>
+
+ * regexp.c: check for ISC.
+
+Thu Sep 7 19:18:00 1995 Jim Blandy <jimb@cyclic.com>
+
+ * save-cwd.c: #include <direct.h> and <io.h>, on systems that
+ have them.
+
+ * getopt.c (_getopt_internal): Cast the return value of strlen,
+ which is unsigned, before comparing it with the difference between
+ two pointers, which is unsigned.
+
+Thu Aug 31 11:31:42 1995 Jim Blandy <jimb@totoro.cyclic.com>
+
+ * getdate.y [STDC_HEADERS]: #include <stdlib.h>, for abort.
+ [HAVE_ALLOCA_H]: #include <alloca.h>, for alloca on Windows NT.
+
+Wed Aug 30 18:48:44 1995 Jim Blandy <jimb@totoro.cyclic.com>
+
+ * system.h [HAVE_IO_H]: #include <io.h>, for Windows NT.
+ [HAVE_DIRECT_H]: #include <direct.h>, for Windows NT.
+ (CVS_MKDIR, FOLD_FN_CHAR, fnfold, fncmp, ISDIRSEP, OPEN_BINARY,
+ FOPEN_BINARY_READ, FOPEN_BINARY_WRITE): New macros/functions, for
+ use in system-sensitive code.
+
+ * regex.c (re_set_registers): start and end are pointers, not
+ integers. Cast the initializing value appropriately.
+
+ * getopt.c [HAVE_STRING_H]: #include <string.h>, to avoid
+ warnings.
+
+ * fnmatch.c (FOLD_FN_CHAR): Give this a dummy #definition if
+ config.h didn't #define it.
+ (fnmatch): Pass filename characters through FOLD_FN_CHAR before
+ comparing them.
+
+ * argmatch.c: #include <sys/types.h>.
+ (argmatch): Declare arglen to be a size_t, rather than an int,
+ to avoid signed/unsigned comparison "problems".
+
+ * .cvsignore: Remove getdate.c from this file. We want to
+ distribute it, for systems that don't have a Yacc-equivalent
+ installed (like Windows NT).
+
+Sat Aug 19 22:00:51 1995 Jim Blandy <jimb@totoro.cyclic.com>
+
+ * error.c: Don't #define CVS_SUPPORT here. config.h takes care of
+ that for us.
+ [CVS_SUPPORT] (error_use_protocol): New variable, with apology.
+ (error): If error_use_protocol is set, report errors using the
+ client/server protocol.
+ * error.h [CVS_SUPPORT]: Extern decl for error_use_protocol.
+
+Fri Aug 4 00:01:24 1995 Jim Meyering (meyering@comco.com)
+
+ * xgetwd.c: Don't declare free. A K&R style declaration gets
+ a conflict on some Sun systems when compiling with acc.
+
+ * save-cwd.c: New file.
+ * save-cwd.h: New file.
+ * Makefile.in (SOURCES): Add save-cwd.c
+ (OBJECTS): Add save-cwd.o.
+ (HEADERS): Add save-cwd.h.
+
+Thu Aug 3 00:55:54 1995 Jim Meyering (meyering@comco.com)
+
+ * error.h: New file.
+ * Makefile.in (HEADERS): Add error.h.
+
+Sat Jul 29 15:53:55 1995 James Kingdon <kingdon@harvey.cyclic.com>
+
+ * Makefile.in (SOURCES): Add getdate.c.
+
+Thu Jul 27 09:11:41 1995 Robert Lipe <robertl@rjlhome.arnet.com>
+
+ * system.h: Check for PATHSIZE before falling back to _POSIX_PATH_MAX.
+
+Thu Jul 20 12:38:03 1995 James Kingdon <kingdon@harvey.cyclic.com>
+
+ * error.c: Instead of calling cvs functions to clean up, allow cvs
+ to register a callback via error_set_cleanup. Avoids hassles with
+ include files and SERVER_SUPPORT and so on.
+
+Tue Jul 18 21:18:00 1995 Jim Blandy <jimb@cyclic.com>
+
+ * system.h: Include <sys/param.h> only if HAVE_SYS_PARAM_H
+ is #defined. We've added a test to configure.in to #define this
+ on most systems.
+
+Thu Jul 13 11:22:21 1995 Jim Meyering (meyering@comco.com)
+
+ * xgetwd.c: New file.
+ * Makefile.in (SOURCES): Add xgetwd.c
+ (OBJECTS): Add xgetwd.o.
+
+Wed Jul 12 09:18:49 1995 Jim Meyering (meyering@comco.com)
+
+ * Makefile.in (OBJECTS): Remove fnmatch.o. Now configure adds it
+ to LIBOBJS when necessary.
+
+Fri Jun 30 16:27:18 1995 James Kingdon <kingdon@harvey.cyclic.com>
+
+ * rename.c (rename): If MVDIR is not defined, just give an error
+ on attempt to rename a directory.
+
+Thu Jun 29 00:46:31 1995 James Kingdon <kingdon@harvey.cyclic.com>
+
+ * system.h: Check HAVE_SYS_TIMEB_H not non-existent HAVE_TIMEB_H.
+
+ * system.h: Don't define alloca if it is already defined.
+
+Wed Jun 28 15:24:51 1995 James Kingdon <kingdon@harvey.cyclic.com>
+
+ * system.h: If NeXT, define utimbuf ourself.
+
+Mon May 29 22:32:40 1995 J.T. Conklin <jtc@rtl.cygnus.com>
+
+ * system.h: Handle time and directory headers as recommended in
+ the autoconf manual.
+ Undefine the S_FOO() macros if STAT_MACROS_BROKEN is set.
+ Don't define mode_t, as it is handled by config.h.
+
+Sat May 27 08:46:00 1995 Jim Meyering (meyering@comco.com)
+
+ * Makefile.in (Makefile): Regenerate only Makefile in current
+ directory when Makefile.in is out of date. Depend on ../config.status.
+
+Fri Apr 28 22:49:25 1995 Jim Blandy <jimb@totoro.bio.indiana.edu>
+
+ * Makefile.in (SOURCES, OBJECTS): Updated.
+ (HEADERS): New variable.
+ (DISTFILES): Updated.
+ (dist-dir): Renamed from dist; changed to work with DISTDIR
+ variable passed from parent.
+
+Wed Feb 8 06:37:53 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
+
+ * system.h (S_IRUSR et al): Define if not already defined.
+
+ * waitpid.c [HAVE_CONFIG_H]: Include "config.h".
+ (ualloc): Return OLDPTR rather than running off the end.
+
+Mon Aug 22 22:48:19 1994 Ken Raeburn (raeburn@kr-pc.cygnus.com)
+
+ * error.c (strerror): Replaced conditional static definition
+ (always used, since the condition variable was never set) with an
+ extern declaration, since it's provided by libc or strerror.c.
+
+Wed Aug 10 14:54:25 1994 Ken Raeburn (raeburn@cujo.cygnus.com)
+
+ * Makefile.in (SOURCES): Add waitpid.c.
+ * waitpid.c: New file.
+
+Tue Aug 9 16:00:12 1994 Ken Raeburn (raeburn@cujo.cygnus.com)
+
+ * md5.h (uint32): If SIZEOF_LONG isn't 4, don't define this to be
+ "unsigned long"; try SIZEOF_INT and "unsigned int", otherwise
+ complain.
+
+ * md5.c: Include config.h.
+ (const): Don't bother defining here, config.h should take care of
+ it.
+
+ * valloc.c (malloc): Declare.
+
+Fri Jul 15 12:57:20 1994 Ian Lance Taylor (ian@sanguine.cygnus.com)
+
+ * getopt.c: Do not include <stdlib.h> unless __GNU_LIBRARY__ is
+ defined. On Irix 5.2, <stdlib.h> includes <getopt.h>, which
+ causes a multiple definition of struct option.
+
+Fri Jul 8 10:04:59 1994 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * md5.h, md5.c: Remove ANSI-isms.
+
+Thu Jul 7 20:24:18 1994 Ian Lance Taylor (ian@sanguine.cygnus.com)
+
+ * md5.h, md5.c: New files.
+ * Makefile.in (SOURCES): Add md5.c.
+ (OBJECTS): Add md5.o.
+ (DISTFILES): Add md5.h.
+ (md5.o): New target; depend upon md5.h.
+
+Fri May 27 18:15:34 1994 Ian Lance Taylor (ian@tweedledumb.cygnus.com)
+
+ * valloc.c: New file.
+
+Tue May 17 08:18:26 1994 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * error.c (error, fperror): If server_active, call server_cleanup
+ as well as Lock_Cleanup.
+
+Thu Jan 6 13:45:04 1994 Ken Raeburn (raeburn@cujo.cygnus.com)
+
+ * system.h: Fix Dec 27 change to work correctly. Makes Sep 9
+ change unnecessary, so backed that one out. Never define PATH_MAX
+ in terms of pathconf, because that doesn't produce a constant, and
+ PATH_MAX is used to set array sizes.
+
+Mon Dec 27 14:22:07 1993 Mark Eichin (eichin@cygnus.com)
+
+ * system.h: don't touch PATH_MAX or MAXPATHLEN if *both* of them
+ are already defined, as one may be defined in terms of the other.
diff --git a/gnu/usr.bin/cvs/lib/Makefile b/gnu/usr.bin/cvs/lib/Makefile
new file mode 100644
index 0000000..f61d748
--- /dev/null
+++ b/gnu/usr.bin/cvs/lib/Makefile
@@ -0,0 +1,17 @@
+# $Id: Makefile,v 1.9 1995/12/10 23:09:19 peter Exp $
+
+LIB = cvs
+NOPROFILE= yes
+CFLAGS += -I${.CURDIR} -I${.CURDIR}/../cvs -DHAVE_CONFIG_H
+SRCS = argmatch.c error.c filesubr.c getdate.y getline.c \
+ getopt.c getopt1.c hash.c myndbm.c run.c save-cwd.c \
+ sighandle.c strippath.c stripslash.c subr.c version.c \
+ xgetwd.c yesno.c
+
+CLEANFILES+= getdate.c y.tab.h
+
+install:
+ @echo -n
+
+.include <bsd.lib.mk>
+
diff --git a/gnu/usr.bin/cvs/lib/argmatch.c b/gnu/usr.bin/cvs/lib/argmatch.c
new file mode 100644
index 0000000..cc360ee
--- /dev/null
+++ b/gnu/usr.bin/cvs/lib/argmatch.c
@@ -0,0 +1,89 @@
+/* argmatch.c -- find a match for a string in an array
+ Copyright (C) 1990 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* Written by David MacKenzie <djm@ai.mit.edu> */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <sys/types.h>
+
+#include <stdio.h>
+#ifdef STDC_HEADERS
+#include <string.h>
+#endif
+
+extern char *program_name;
+
+/* If ARG is an unambiguous match for an element of the
+ null-terminated array OPTLIST, return the index in OPTLIST
+ of the matched element, else -1 if it does not match any element
+ or -2 if it is ambiguous (is a prefix of more than one element). */
+
+int
+argmatch (arg, optlist)
+ char *arg;
+ char **optlist;
+{
+ int i; /* Temporary index in OPTLIST. */
+ size_t arglen; /* Length of ARG. */
+ int matchind = -1; /* Index of first nonexact match. */
+ int ambiguous = 0; /* If nonzero, multiple nonexact match(es). */
+
+ arglen = strlen (arg);
+
+ /* Test all elements for either exact match or abbreviated matches. */
+ for (i = 0; optlist[i]; i++)
+ {
+ if (!strncmp (optlist[i], arg, arglen))
+ {
+ if (strlen (optlist[i]) == arglen)
+ /* Exact match found. */
+ return i;
+ else if (matchind == -1)
+ /* First nonexact match found. */
+ matchind = i;
+ else
+ /* Second nonexact match found. */
+ ambiguous = 1;
+ }
+ }
+ if (ambiguous)
+ return -2;
+ else
+ return matchind;
+}
+
+/* Error reporting for argmatch.
+ KIND is a description of the type of entity that was being matched.
+ VALUE is the invalid value that was given.
+ PROBLEM is the return value from argmatch. */
+
+void
+invalid_arg (kind, value, problem)
+ char *kind;
+ char *value;
+ int problem;
+{
+ fprintf (stderr, "%s: ", program_name);
+ if (problem == -1)
+ fprintf (stderr, "invalid");
+ else /* Assume -2. */
+ fprintf (stderr, "ambiguous");
+ fprintf (stderr, " %s `%s'\n", kind, value);
+}
diff --git a/gnu/usr.bin/cvs/lib/config.h b/gnu/usr.bin/cvs/lib/config.h
new file mode 100644
index 0000000..ce06c62
--- /dev/null
+++ b/gnu/usr.bin/cvs/lib/config.h
@@ -0,0 +1,233 @@
+/* config.h. Generated automatically by configure. */
+/* config.h.in. Generated automatically from configure.in by autoheader. */
+
+/* Define if on AIX 3.
+ System headers sometimes define this.
+ We just want to avoid a redefinition error message. */
+#ifndef _ALL_SOURCE
+/* #undef _ALL_SOURCE */
+#endif
+
+/* Define if using alloca.c. */
+/* #undef C_ALLOCA */
+
+/* Define if type char is unsigned and you are not using gcc. */
+#ifndef __CHAR_UNSIGNED__
+/* #undef __CHAR_UNSIGNED__ */
+#endif
+
+/* Define to empty if the keyword does not work. */
+/* #undef const */
+
+/* Define to one of _getb67, GETB67, getb67 for Cray-2 and Cray-YMP systems.
+ This function is required for alloca.c support on those systems. */
+/* #undef CRAY_STACKSEG_END */
+
+/* Define to `int' if <sys/types.h> doesn't define. */
+/* #undef gid_t */
+
+/* Define if you have alloca, as a function or macro. */
+#define HAVE_ALLOCA 1
+
+/* Define if you have <alloca.h> and it should be used (not on Ultrix). */
+/* #undef HAVE_ALLOCA_H */
+
+/* Define if you support file names longer than 14 characters. */
+#define HAVE_LONG_FILE_NAMES 1
+
+/* Define if you have <sys/wait.h> that is POSIX.1 compatible. */
+#define HAVE_SYS_WAIT_H 1
+
+/* Define if utime(file, NULL) sets file's timestamp to the present. */
+#define HAVE_UTIME_NULL 1
+
+/* Define as __inline if that's what the C compiler calls it. */
+/* #undef inline */
+
+/* Define if on MINIX. */
+/* #undef _MINIX */
+
+/* Define to `int' if <sys/types.h> doesn't define. */
+/* #undef mode_t */
+
+/* Define to `int' if <sys/types.h> doesn't define. */
+/* #undef pid_t */
+
+/* Define if the system does not provide POSIX.1 features except
+ with this defined. */
+/* #undef _POSIX_1_SOURCE */
+
+/* Define if you need to in order for stat and other things to work. */
+/* #undef _POSIX_SOURCE */
+
+/* Define as the return type of signal handlers (int or void). */
+#define RETSIGTYPE void
+
+/* Define to `unsigned' if <sys/types.h> doesn't define. */
+/* #undef size_t */
+
+/* If using the C implementation of alloca, define if you know the
+ direction of stack growth for your system; otherwise it will be
+ automatically deduced at run-time.
+ STACK_DIRECTION > 0 => grows toward higher addresses
+ STACK_DIRECTION < 0 => grows toward lower addresses
+ STACK_DIRECTION = 0 => direction of growth unknown
+ */
+/* #undef STACK_DIRECTION */
+
+/* Define if the `S_IS*' macros in <sys/stat.h> do not work properly. */
+/* #undef STAT_MACROS_BROKEN */
+
+/* Define if you have the ANSI C header files. */
+#define STDC_HEADERS 1
+
+/* Define if you can safely include both <sys/time.h> and <time.h>. */
+#define TIME_WITH_SYS_TIME 1
+
+/* Define to `int' if <sys/types.h> doesn't define. */
+/* #undef uid_t */
+
+/* Define if you have MIT Kerberos version 4 available. */
+/* #undef HAVE_KERBEROS */
+
+/* Define if you want CVS to be able to be a remote repository client. */
+#define CLIENT_SUPPORT 1
+
+/* Define if you want CVS to be able to serve repositories to remote
+ clients. */
+#define SERVER_SUPPORT 1
+
+/* the path to the gnu diff program on your system */
+#define DIFF "/usr/bin/diff -a"
+
+/* The number of bytes in a int. */
+#define SIZEOF_INT 4
+
+/* The number of bytes in a long. */
+#define SIZEOF_LONG 4
+
+/* Define if you have the connect function. */
+/* #undef HAVE_CONNECT */
+
+/* Define if you have the fchdir function. */
+#define HAVE_FCHDIR 1
+
+/* Define if you have the fchmod function. */
+#define HAVE_FCHMOD 1
+
+/* Define if you have the fsync function. */
+#define HAVE_FSYNC 1
+
+/* Define if you have the ftime function. */
+/* #undef HAVE_FTIME */
+
+/* Define if you have the ftruncate function. */
+#define HAVE_FTRUNCATE 1
+
+/* Define if you have the getpagesize function. */
+#define HAVE_GETPAGESIZE 1
+
+/* Define if you have the krb_get_err_text function. */
+/* #undef HAVE_KRB_GET_ERR_TEXT */
+
+/* Define if you have the mkfifo function. */
+#define HAVE_MKFIFO 1
+
+/* Define if you have the putenv function. */
+#define HAVE_PUTENV 1
+
+/* Define if you have the setvbuf function. */
+#define HAVE_SETVBUF 1
+
+/* Define if you have the sigaction function. */
+#define HAVE_SIGACTION 1
+
+/* Define if you have the sigblock function. */
+#define HAVE_SIGBLOCK 1
+
+/* Define if you have the sigprocmask function. */
+#define HAVE_SIGPROCMASK 1
+
+/* Define if you have the sigsetmask function. */
+#define HAVE_SIGSETMASK 1
+
+/* Define if you have the sigvec function. */
+#define HAVE_SIGVEC 1
+
+/* Define if you have the timezone function. */
+#define HAVE_TIMEZONE 1
+
+/* Define if you have the vfork function. */
+#define HAVE_VFORK 1
+
+/* Define if you have the vprintf function. */
+#define HAVE_VPRINTF 1
+
+/* Define if you have the <direct.h> header file. */
+/* #undef HAVE_DIRECT_H */
+
+/* Define if you have the <dirent.h> header file. */
+#define HAVE_DIRENT_H 1
+
+/* Define if you have the <errno.h> header file. */
+#define HAVE_ERRNO_H 1
+
+/* Define if you have the <fcntl.h> header file. */
+#define HAVE_FCNTL_H 1
+
+/* Define if you have the <io.h> header file. */
+/* #undef HAVE_IO_H */
+
+/* Define if you have the <memory.h> header file. */
+#define HAVE_MEMORY_H 1
+
+/* Define if you have the <ndbm.h> header file. */
+#define HAVE_NDBM_H 1
+
+/* Define if you have the <ndir.h> header file. */
+/* #undef HAVE_NDIR_H */
+
+/* Define if you have the <string.h> header file. */
+#define HAVE_STRING_H 1
+
+/* Define if you have the <sys/bsdtypes.h> header file. */
+/* #undef HAVE_SYS_BSDTYPES_H */
+
+/* Define if you have the <sys/dir.h> header file. */
+/* #undef HAVE_SYS_DIR_H */
+
+/* Define if you have the <sys/ndir.h> header file. */
+/* #undef HAVE_SYS_NDIR_H */
+
+/* Define if you have the <sys/param.h> header file. */
+#define HAVE_SYS_PARAM_H 1
+
+/* Define if you have the <sys/resource.h> header file. */
+#define HAVE_SYS_RESOURCE_H 1
+
+/* Define if you have the <sys/select.h> header file. */
+#define HAVE_SYS_SELECT_H 1
+
+/* Define if you have the <sys/time.h> header file. */
+#define HAVE_SYS_TIME_H 1
+
+/* Define if you have the <sys/timeb.h> header file. */
+#define HAVE_SYS_TIMEB_H 1
+
+/* Define if you have the <unistd.h> header file. */
+#define HAVE_UNISTD_H 1
+
+/* Define if you have the <utime.h> header file. */
+#define HAVE_UTIME_H 1
+
+/* Define if you have the inet library (-linet). */
+/* #undef HAVE_LIBINET */
+
+/* Define if you have the nsl library (-lnsl). */
+/* #undef HAVE_LIBNSL */
+
+/* Define if you have the nsl_s library (-lnsl_s). */
+/* #undef HAVE_LIBNSL_S */
+
+/* Define if you have the socket library (-lsocket). */
+/* #undef HAVE_LIBSOCKET */
diff --git a/gnu/usr.bin/cvs/lib/config.h.proto b/gnu/usr.bin/cvs/lib/config.h.proto
new file mode 100644
index 0000000..ce06c62
--- /dev/null
+++ b/gnu/usr.bin/cvs/lib/config.h.proto
@@ -0,0 +1,233 @@
+/* config.h. Generated automatically by configure. */
+/* config.h.in. Generated automatically from configure.in by autoheader. */
+
+/* Define if on AIX 3.
+ System headers sometimes define this.
+ We just want to avoid a redefinition error message. */
+#ifndef _ALL_SOURCE
+/* #undef _ALL_SOURCE */
+#endif
+
+/* Define if using alloca.c. */
+/* #undef C_ALLOCA */
+
+/* Define if type char is unsigned and you are not using gcc. */
+#ifndef __CHAR_UNSIGNED__
+/* #undef __CHAR_UNSIGNED__ */
+#endif
+
+/* Define to empty if the keyword does not work. */
+/* #undef const */
+
+/* Define to one of _getb67, GETB67, getb67 for Cray-2 and Cray-YMP systems.
+ This function is required for alloca.c support on those systems. */
+/* #undef CRAY_STACKSEG_END */
+
+/* Define to `int' if <sys/types.h> doesn't define. */
+/* #undef gid_t */
+
+/* Define if you have alloca, as a function or macro. */
+#define HAVE_ALLOCA 1
+
+/* Define if you have <alloca.h> and it should be used (not on Ultrix). */
+/* #undef HAVE_ALLOCA_H */
+
+/* Define if you support file names longer than 14 characters. */
+#define HAVE_LONG_FILE_NAMES 1
+
+/* Define if you have <sys/wait.h> that is POSIX.1 compatible. */
+#define HAVE_SYS_WAIT_H 1
+
+/* Define if utime(file, NULL) sets file's timestamp to the present. */
+#define HAVE_UTIME_NULL 1
+
+/* Define as __inline if that's what the C compiler calls it. */
+/* #undef inline */
+
+/* Define if on MINIX. */
+/* #undef _MINIX */
+
+/* Define to `int' if <sys/types.h> doesn't define. */
+/* #undef mode_t */
+
+/* Define to `int' if <sys/types.h> doesn't define. */
+/* #undef pid_t */
+
+/* Define if the system does not provide POSIX.1 features except
+ with this defined. */
+/* #undef _POSIX_1_SOURCE */
+
+/* Define if you need to in order for stat and other things to work. */
+/* #undef _POSIX_SOURCE */
+
+/* Define as the return type of signal handlers (int or void). */
+#define RETSIGTYPE void
+
+/* Define to `unsigned' if <sys/types.h> doesn't define. */
+/* #undef size_t */
+
+/* If using the C implementation of alloca, define if you know the
+ direction of stack growth for your system; otherwise it will be
+ automatically deduced at run-time.
+ STACK_DIRECTION > 0 => grows toward higher addresses
+ STACK_DIRECTION < 0 => grows toward lower addresses
+ STACK_DIRECTION = 0 => direction of growth unknown
+ */
+/* #undef STACK_DIRECTION */
+
+/* Define if the `S_IS*' macros in <sys/stat.h> do not work properly. */
+/* #undef STAT_MACROS_BROKEN */
+
+/* Define if you have the ANSI C header files. */
+#define STDC_HEADERS 1
+
+/* Define if you can safely include both <sys/time.h> and <time.h>. */
+#define TIME_WITH_SYS_TIME 1
+
+/* Define to `int' if <sys/types.h> doesn't define. */
+/* #undef uid_t */
+
+/* Define if you have MIT Kerberos version 4 available. */
+/* #undef HAVE_KERBEROS */
+
+/* Define if you want CVS to be able to be a remote repository client. */
+#define CLIENT_SUPPORT 1
+
+/* Define if you want CVS to be able to serve repositories to remote
+ clients. */
+#define SERVER_SUPPORT 1
+
+/* the path to the gnu diff program on your system */
+#define DIFF "/usr/bin/diff -a"
+
+/* The number of bytes in a int. */
+#define SIZEOF_INT 4
+
+/* The number of bytes in a long. */
+#define SIZEOF_LONG 4
+
+/* Define if you have the connect function. */
+/* #undef HAVE_CONNECT */
+
+/* Define if you have the fchdir function. */
+#define HAVE_FCHDIR 1
+
+/* Define if you have the fchmod function. */
+#define HAVE_FCHMOD 1
+
+/* Define if you have the fsync function. */
+#define HAVE_FSYNC 1
+
+/* Define if you have the ftime function. */
+/* #undef HAVE_FTIME */
+
+/* Define if you have the ftruncate function. */
+#define HAVE_FTRUNCATE 1
+
+/* Define if you have the getpagesize function. */
+#define HAVE_GETPAGESIZE 1
+
+/* Define if you have the krb_get_err_text function. */
+/* #undef HAVE_KRB_GET_ERR_TEXT */
+
+/* Define if you have the mkfifo function. */
+#define HAVE_MKFIFO 1
+
+/* Define if you have the putenv function. */
+#define HAVE_PUTENV 1
+
+/* Define if you have the setvbuf function. */
+#define HAVE_SETVBUF 1
+
+/* Define if you have the sigaction function. */
+#define HAVE_SIGACTION 1
+
+/* Define if you have the sigblock function. */
+#define HAVE_SIGBLOCK 1
+
+/* Define if you have the sigprocmask function. */
+#define HAVE_SIGPROCMASK 1
+
+/* Define if you have the sigsetmask function. */
+#define HAVE_SIGSETMASK 1
+
+/* Define if you have the sigvec function. */
+#define HAVE_SIGVEC 1
+
+/* Define if you have the timezone function. */
+#define HAVE_TIMEZONE 1
+
+/* Define if you have the vfork function. */
+#define HAVE_VFORK 1
+
+/* Define if you have the vprintf function. */
+#define HAVE_VPRINTF 1
+
+/* Define if you have the <direct.h> header file. */
+/* #undef HAVE_DIRECT_H */
+
+/* Define if you have the <dirent.h> header file. */
+#define HAVE_DIRENT_H 1
+
+/* Define if you have the <errno.h> header file. */
+#define HAVE_ERRNO_H 1
+
+/* Define if you have the <fcntl.h> header file. */
+#define HAVE_FCNTL_H 1
+
+/* Define if you have the <io.h> header file. */
+/* #undef HAVE_IO_H */
+
+/* Define if you have the <memory.h> header file. */
+#define HAVE_MEMORY_H 1
+
+/* Define if you have the <ndbm.h> header file. */
+#define HAVE_NDBM_H 1
+
+/* Define if you have the <ndir.h> header file. */
+/* #undef HAVE_NDIR_H */
+
+/* Define if you have the <string.h> header file. */
+#define HAVE_STRING_H 1
+
+/* Define if you have the <sys/bsdtypes.h> header file. */
+/* #undef HAVE_SYS_BSDTYPES_H */
+
+/* Define if you have the <sys/dir.h> header file. */
+/* #undef HAVE_SYS_DIR_H */
+
+/* Define if you have the <sys/ndir.h> header file. */
+/* #undef HAVE_SYS_NDIR_H */
+
+/* Define if you have the <sys/param.h> header file. */
+#define HAVE_SYS_PARAM_H 1
+
+/* Define if you have the <sys/resource.h> header file. */
+#define HAVE_SYS_RESOURCE_H 1
+
+/* Define if you have the <sys/select.h> header file. */
+#define HAVE_SYS_SELECT_H 1
+
+/* Define if you have the <sys/time.h> header file. */
+#define HAVE_SYS_TIME_H 1
+
+/* Define if you have the <sys/timeb.h> header file. */
+#define HAVE_SYS_TIMEB_H 1
+
+/* Define if you have the <unistd.h> header file. */
+#define HAVE_UNISTD_H 1
+
+/* Define if you have the <utime.h> header file. */
+#define HAVE_UTIME_H 1
+
+/* Define if you have the inet library (-linet). */
+/* #undef HAVE_LIBINET */
+
+/* Define if you have the nsl library (-lnsl). */
+/* #undef HAVE_LIBNSL */
+
+/* Define if you have the nsl_s library (-lnsl_s). */
+/* #undef HAVE_LIBNSL_S */
+
+/* Define if you have the socket library (-lsocket). */
+/* #undef HAVE_LIBSOCKET */
diff --git a/gnu/usr.bin/cvs/lib/error.c b/gnu/usr.bin/cvs/lib/error.c
new file mode 100644
index 0000000..0398103
--- /dev/null
+++ b/gnu/usr.bin/cvs/lib/error.c
@@ -0,0 +1,188 @@
+/* error.c -- error handler for noninteractive utilities
+ Copyright (C) 1990-1992 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* David MacKenzie */
+/* Brian Berliner added support for CVS */
+
+#include "cvs.h"
+
+#ifndef lint
+static const char rcsid[] = "$CVSid: @(#)error.c 1.13 94/09/30 $";
+USE(rcsid);
+#endif /* not lint */
+
+#include <stdio.h>
+
+/* If non-zero, error will use the CVS protocol to stdout to report error
+ messages. This will only be set in the CVS server parent process;
+ most other code is run via do_cvs_command, which forks off a child
+ process and packages up its stderr in the protocol. */
+int error_use_protocol;
+
+#ifdef HAVE_VPRINTF
+
+#if __STDC__
+#include <stdarg.h>
+#define VA_START(args, lastarg) va_start(args, lastarg)
+#else
+#include <varargs.h>
+#define VA_START(args, lastarg) va_start(args)
+#endif
+
+#else
+
+#ifdef HAVE_DOPRNT
+#define va_alist args
+#define va_dcl int args;
+#else
+#define va_alist a1, a2, a3, a4, a5, a6, a7, a8
+#define va_dcl char *a1, *a2, *a3, *a4, *a5, *a6, *a7, *a8;
+#endif
+
+#endif
+
+#if STDC_HEADERS
+#include <stdlib.h>
+#include <string.h>
+#else
+#if __STDC__
+void exit(int status);
+#else
+void exit ();
+#endif /* __STDC__ */
+#endif
+
+extern char *strerror ();
+
+typedef void (*fn_returning_void) ();
+
+/* Function to call before exiting. */
+static fn_returning_void cleanup_fn;
+
+fn_returning_void
+error_set_cleanup (arg)
+ fn_returning_void arg;
+{
+ fn_returning_void retval = cleanup_fn;
+ cleanup_fn = arg;
+ return retval;
+}
+
+/* Print the program name and error message MESSAGE, which is a printf-style
+ format string with optional args.
+ If ERRNUM is nonzero, print its corresponding system error message.
+ Exit with status STATUS if it is nonzero. */
+/* VARARGS */
+void
+#if defined (HAVE_VPRINTF) && __STDC__
+error (int status, int errnum, const char *message, ...)
+#else
+error (status, errnum, message, va_alist)
+ int status;
+ int errnum;
+ const char *message;
+ va_dcl
+#endif
+{
+ FILE *out = stderr;
+ extern char *program_name;
+ extern char *command_name;
+#ifdef HAVE_VPRINTF
+ va_list args;
+#endif
+
+ if (error_use_protocol)
+ {
+ out = stdout;
+ printf ("E ");
+ }
+
+ if (command_name && *command_name)
+ if (status)
+ fprintf (out, "%s [%s aborted]: ", program_name, command_name);
+ else
+ fprintf (out, "%s %s: ", program_name, command_name);
+ else
+ fprintf (out, "%s: ", program_name);
+#ifdef HAVE_VPRINTF
+ VA_START (args, message);
+ vfprintf (out, message, args);
+ va_end (args);
+#else
+#ifdef HAVE_DOPRNT
+ _doprnt (message, &args, out);
+#else
+ fprintf (out, message, a1, a2, a3, a4, a5, a6, a7, a8);
+#endif
+#endif
+ if (errnum)
+ fprintf (out, ": %s", strerror (errnum));
+ putc ('\n', out);
+ fflush (out);
+ if (status)
+ {
+ if (cleanup_fn)
+ (*cleanup_fn) ();
+ exit (status);
+ }
+}
+
+/* Print the program name and error message MESSAGE, which is a printf-style
+ format string with optional args to the file specified by FP.
+ If ERRNUM is nonzero, print its corresponding system error message.
+ Exit with status STATUS if it is nonzero. */
+/* VARARGS */
+void
+#if defined (HAVE_VPRINTF) && __STDC__
+fperror (FILE *fp, int status, int errnum, char *message, ...)
+#else
+fperror (fp, status, errnum, message, va_alist)
+ FILE *fp;
+ int status;
+ int errnum;
+ char *message;
+ va_dcl
+#endif
+{
+ extern char *program_name;
+#ifdef HAVE_VPRINTF
+ va_list args;
+#endif
+
+ fprintf (fp, "%s: ", program_name);
+#ifdef HAVE_VPRINTF
+ VA_START (args, message);
+ vfprintf (fp, message, args);
+ va_end (args);
+#else
+#ifdef HAVE_DOPRNT
+ _doprnt (message, &args, fp);
+#else
+ fprintf (fp, message, a1, a2, a3, a4, a5, a6, a7, a8);
+#endif
+#endif
+ if (errnum)
+ fprintf (fp, ": %s", strerror (errnum));
+ putc ('\n', fp);
+ fflush (fp);
+ if (status)
+ {
+ if (cleanup_fn)
+ (*cleanup_fn) ();
+ exit (status);
+ }
+}
diff --git a/gnu/usr.bin/cvs/lib/error.h b/gnu/usr.bin/cvs/lib/error.h
new file mode 100644
index 0000000..7d4f535
--- /dev/null
+++ b/gnu/usr.bin/cvs/lib/error.h
@@ -0,0 +1,47 @@
+/* error.h -- declaration for error-reporting function
+ Copyright (C) 1995 Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#ifndef _error_h_
+#define _error_h_
+
+#ifndef __attribute__
+/* This feature is available in gcc versions 2.5 and later. */
+# if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 5) || __STRICT_ANSI__
+# define __attribute__(Spec) /* empty */
+# endif
+/* The __-protected variants of `format' and `printf' attributes
+ are accepted by gcc versions 2.6.4 (effectively 2.7) and later. */
+# if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 7)
+# define __format__ format
+# define __printf__ printf
+# endif
+#endif
+
+#if __STDC__
+void error (int, int, const char *, ...) \
+ __attribute__ ((__format__ (__printf__, 3, 4)));
+#else
+void error ();
+#endif
+
+/* If non-zero, error will use the CVS protocol to report error
+ messages. This will only be set in the CVS server parent process;
+ most other code is run via do_cvs_command, which forks off a child
+ process and packages up its stderr in the protocol. */
+extern int error_use_protocol;
+
+#endif /* _error_h_ */
diff --git a/gnu/usr.bin/cvs/lib/filesubr.c b/gnu/usr.bin/cvs/lib/filesubr.c
new file mode 100644
index 0000000..3a52691
--- /dev/null
+++ b/gnu/usr.bin/cvs/lib/filesubr.c
@@ -0,0 +1,640 @@
+/* filesubr.c --- subroutines for dealing with files
+ Jim Blandy <jimb@cyclic.com>
+
+ This file is part of GNU CVS.
+
+ GNU CVS is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any
+ later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* These functions were moved out of subr.c because they need different
+ definitions under operating systems (like, say, Windows NT) with different
+ file system semantics. */
+
+#include "cvs.h"
+
+#ifndef lint
+static const char rcsid[] = "$CVSid:$";
+USE(rcsid);
+#endif
+
+/*
+ * I don't know of a convenient way to test this at configure time, or else
+ * I'd certainly do it there.
+ */
+#if defined(NeXT)
+#define LOSING_TMPNAM_FUNCTION
+#endif
+
+static int deep_remove_dir PROTO((const char *path));
+
+/*
+ * Copies "from" to "to".
+ */
+void
+copy_file (from, to)
+ const char *from;
+ const char *to;
+{
+ struct stat sb;
+ struct utimbuf t;
+ int fdin, fdout;
+
+ if (trace)
+#ifdef SERVER_SUPPORT
+ (void) fprintf (stderr, "%c-> copy(%s,%s)\n",
+ (server_active) ? 'S' : ' ', from, to);
+#else
+ (void) fprintf (stderr, "-> copy(%s,%s)\n", from, to);
+#endif
+ if (noexec)
+ return;
+
+ if ((fdin = open (from, O_RDONLY)) < 0)
+ error (1, errno, "cannot open %s for copying", from);
+ if (fstat (fdin, &sb) < 0)
+ error (1, errno, "cannot fstat %s", from);
+ if ((fdout = creat (to, (int) sb.st_mode & 07777)) < 0)
+ error (1, errno, "cannot create %s for copying", to);
+ if (sb.st_size > 0)
+ {
+ char buf[BUFSIZ];
+ int n;
+
+ for (;;)
+ {
+ n = read (fdin, buf, sizeof(buf));
+ if (n == -1)
+ {
+#ifdef EINTR
+ if (errno == EINTR)
+ continue;
+#endif
+ error (1, errno, "cannot read file %s for copying", from);
+ }
+ else if (n == 0)
+ break;
+
+ if (write(fdout, buf, n) != n) {
+ error (1, errno, "cannot write file %s for copying", to);
+ }
+ }
+
+#ifdef HAVE_FSYNC
+ if (fsync (fdout))
+ error (1, errno, "cannot fsync file %s after copying", to);
+#endif
+ }
+
+ if (close (fdin) < 0)
+ error (0, errno, "cannot close %s", from);
+ if (close (fdout) < 0)
+ error (1, errno, "cannot close %s", to);
+
+ /* now, set the times for the copied file to match those of the original */
+ memset ((char *) &t, 0, sizeof (t));
+ t.actime = sb.st_atime;
+ t.modtime = sb.st_mtime;
+ (void) utime (to, &t);
+}
+
+/* FIXME-krp: these functions would benefit from caching the char * &
+ stat buf. */
+
+/*
+ * Returns non-zero if the argument file is a directory, or is a symbolic
+ * link which points to a directory.
+ */
+int
+isdir (file)
+ const char *file;
+{
+ struct stat sb;
+
+ if (stat (file, &sb) < 0)
+ return (0);
+ return (S_ISDIR (sb.st_mode));
+}
+
+/*
+ * Returns non-zero if the argument file is a symbolic link.
+ */
+int
+islink (file)
+ const char *file;
+{
+#ifdef S_ISLNK
+ struct stat sb;
+
+ if (lstat (file, &sb) < 0)
+ return (0);
+ return (S_ISLNK (sb.st_mode));
+#else
+ return (0);
+#endif
+}
+
+/*
+ * Returns non-zero if the argument file exists.
+ */
+int
+isfile (file)
+ const char *file;
+{
+ return isaccessible(file, F_OK);
+}
+
+/*
+ * Returns non-zero if the argument file is readable.
+ */
+int
+isreadable (file)
+ const char *file;
+{
+ return isaccessible(file, R_OK);
+}
+
+/*
+ * Returns non-zero if the argument file is writable.
+ */
+int
+iswritable (file)
+ const char *file;
+{
+ return isaccessible(file, W_OK);
+}
+
+/*
+ * Returns non-zero if the argument file is accessable according to
+ * mode. If compiled with SETXID_SUPPORT also works if cvs has setxid
+ * bits set.
+ */
+int
+isaccessible (file, mode)
+ const char *file;
+ const int mode;
+{
+#ifdef SETXID_SUPPORT
+ struct stat sb;
+ int umask = 0;
+ int gmask = 0;
+ int omask = 0;
+ int uid;
+
+ if (stat(file, &sb) == -1)
+ return 0;
+ if (mode == F_OK)
+ return 1;
+
+ uid = geteuid();
+ if (uid == 0) /* superuser */
+ {
+ if (mode & X_OK)
+ return sb.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH);
+ else
+ return 1;
+ }
+
+ if (mode & R_OK)
+ {
+ umask |= S_IRUSR;
+ gmask |= S_IRGRP;
+ omask |= S_IROTH;
+ }
+ if (mode & W_OK)
+ {
+ umask |= S_IWUSR;
+ gmask |= S_IWGRP;
+ omask |= S_IWOTH;
+ }
+ if (mode & X_OK)
+ {
+ umask |= S_IXUSR;
+ gmask |= S_IXGRP;
+ omask |= S_IXOTH;
+ }
+
+ if (sb.st_uid == uid)
+ return (sb.st_mode & umask) == umask;
+ else if (sb.st_gid == getegid())
+ return (sb.st_mode & gmask) == gmask;
+ else
+ return (sb.st_mode & omask) == omask;
+#else
+ return access(file, mode) == 0;
+#endif
+}
+
+/*
+ * Open a file and die if it fails
+ */
+FILE *
+open_file (name, mode)
+ const char *name;
+ const char *mode;
+{
+ FILE *fp;
+
+ if ((fp = fopen (name, mode)) == NULL)
+ error (1, errno, "cannot open %s", name);
+ return (fp);
+}
+
+/*
+ * Make a directory and die if it fails
+ */
+void
+make_directory (name)
+ const char *name;
+{
+ struct stat sb;
+
+ if (stat (name, &sb) == 0 && (!S_ISDIR (sb.st_mode)))
+ error (0, 0, "%s already exists but is not a directory", name);
+ if (!noexec && mkdir (name, 0777) < 0)
+ error (1, errno, "cannot make directory %s", name);
+}
+
+/*
+ * Make a path to the argument directory, printing a message if something
+ * goes wrong.
+ */
+void
+make_directories (name)
+ const char *name;
+{
+ char *cp;
+
+ if (noexec)
+ return;
+
+ if (mkdir (name, 0777) == 0 || errno == EEXIST)
+ return;
+ if (! existence_error (errno))
+ {
+ error (0, errno, "cannot make path to %s", name);
+ return;
+ }
+ if ((cp = strrchr (name, '/')) == NULL)
+ return;
+ *cp = '\0';
+ make_directories (name);
+ *cp++ = '/';
+ if (*cp == '\0')
+ return;
+ (void) mkdir (name, 0777);
+}
+
+/*
+ * Change the mode of a file, either adding write permissions, or removing
+ * all write permissions. Either change honors the current umask setting.
+ */
+void
+xchmod (fname, writable)
+ char *fname;
+ int writable;
+{
+ struct stat sb;
+ mode_t mode, oumask;
+
+ if (stat (fname, &sb) < 0)
+ {
+ if (!noexec)
+ error (0, errno, "cannot stat %s", fname);
+ return;
+ }
+ oumask = umask (0);
+ (void) umask (oumask);
+ if (writable)
+ {
+ mode = sb.st_mode | (~oumask
+ & (((sb.st_mode & S_IRUSR) ? S_IWUSR : 0)
+ | ((sb.st_mode & S_IRGRP) ? S_IWGRP : 0)
+ | ((sb.st_mode & S_IROTH) ? S_IWOTH : 0)));
+ }
+ else
+ {
+ mode = sb.st_mode & ~(S_IWRITE | S_IWGRP | S_IWOTH) & ~oumask;
+ }
+
+ if (trace)
+#ifdef SERVER_SUPPORT
+ (void) fprintf (stderr, "%c-> chmod(%s,%o)\n",
+ (server_active) ? 'S' : ' ', fname, mode);
+#else
+ (void) fprintf (stderr, "-> chmod(%s,%o)\n", fname, mode);
+#endif
+ if (noexec)
+ return;
+
+ if (chmod (fname, mode) < 0)
+ error (0, errno, "cannot change mode of file %s", fname);
+}
+
+/*
+ * Rename a file and die if it fails
+ */
+void
+rename_file (from, to)
+ const char *from;
+ const char *to;
+{
+ if (trace)
+#ifdef SERVER_SUPPORT
+ (void) fprintf (stderr, "%c-> rename(%s,%s)\n",
+ (server_active) ? 'S' : ' ', from, to);
+#else
+ (void) fprintf (stderr, "-> rename(%s,%s)\n", from, to);
+#endif
+ if (noexec)
+ return;
+
+ if (rename (from, to) < 0)
+ error (1, errno, "cannot rename file %s to %s", from, to);
+}
+
+/*
+ * link a file, if possible.
+ */
+int
+link_file (from, to)
+ const char *from;
+ const char *to;
+{
+ if (trace)
+#ifdef SERVER_SUPPORT
+ (void) fprintf (stderr, "%c-> link(%s,%s)\n",
+ (server_active) ? 'S' : ' ', from, to);
+#else
+ (void) fprintf (stderr, "-> link(%s,%s)\n", from, to);
+#endif
+ if (noexec)
+ return (0);
+
+ return (link (from, to));
+}
+
+/*
+ * unlink a file, if possible.
+ */
+int
+unlink_file (f)
+ const char *f;
+{
+ if (trace)
+#ifdef SERVER_SUPPORT
+ (void) fprintf (stderr, "%c-> unlink(%s)\n",
+ (server_active) ? 'S' : ' ', f);
+#else
+ (void) fprintf (stderr, "-> unlink(%s)\n", f);
+#endif
+ if (noexec)
+ return (0);
+
+ return (unlink (f));
+}
+
+/*
+ * Unlink a file or dir, if possible. If it is a directory do a deep
+ * removal of all of the files in the directory. Return -1 on error
+ * (in which case errno is set).
+ */
+int
+unlink_file_dir (f)
+ const char *f;
+{
+ if (trace)
+#ifdef SERVER_SUPPORT
+ (void) fprintf (stderr, "%c-> unlink_file_dir(%s)\n",
+ (server_active) ? 'S' : ' ', f);
+#else
+ (void) fprintf (stderr, "-> unlink_file_dir(%s)\n", f);
+#endif
+ if (noexec)
+ return (0);
+
+ if (unlink (f) != 0)
+ {
+ /* under NEXTSTEP errno is set to return EPERM if
+ * the file is a directory,or if the user is not
+ * allowed to read or write to the file.
+ * [This is probably a bug in the O/S]
+ * other systems will return EISDIR to indicate
+ * that the path is a directory.
+ */
+ if (errno == EISDIR || errno == EPERM)
+ return deep_remove_dir (f);
+ else
+ /* The file wasn't a directory and some other
+ * error occured
+ */
+ return -1;
+ }
+ /* We were able to remove the file from the disk */
+ return 0;
+}
+
+/* Remove a directory and everything it contains. Returns 0 for
+ * success, -1 for failure (in which case errno is set).
+ */
+
+static int
+deep_remove_dir (path)
+ const char *path;
+{
+ DIR *dirp;
+ struct dirent *dp;
+ char buf[PATH_MAX];
+
+ if ( rmdir (path) != 0 && errno == ENOTEMPTY )
+ {
+ if ((dirp = opendir (path)) == NULL)
+ /* If unable to open the directory return
+ * an error
+ */
+ return -1;
+
+ while ((dp = readdir (dirp)) != NULL)
+ {
+ if (strcmp (dp->d_name, ".") == 0 ||
+ strcmp (dp->d_name, "..") == 0)
+ continue;
+
+ sprintf (buf, "%s/%s", path, dp->d_name);
+
+ if (unlink (buf) != 0 )
+ {
+ if (errno == EISDIR || errno == EPERM)
+ {
+ if (deep_remove_dir (buf))
+ {
+ closedir (dirp);
+ return -1;
+ }
+ }
+ else
+ {
+ /* buf isn't a directory, or there are
+ * some sort of permision problems
+ */
+ closedir (dirp);
+ return -1;
+ }
+ }
+ }
+ closedir (dirp);
+ return rmdir (path);
+ }
+ /* Was able to remove the directory return 0 */
+ return 0;
+}
+
+/* Read NCHARS bytes from descriptor FD into BUF.
+ Return the number of characters successfully read.
+ The number returned is always NCHARS unless end-of-file or error. */
+static size_t
+block_read (fd, buf, nchars)
+ int fd;
+ char *buf;
+ size_t nchars;
+{
+ char *bp = buf;
+ size_t nread;
+
+ do
+ {
+ nread = read (fd, bp, nchars);
+ if (nread == (size_t)-1)
+ {
+#ifdef EINTR
+ if (errno == EINTR)
+ continue;
+#endif
+ return (size_t)-1;
+ }
+
+ if (nread == 0)
+ break;
+
+ bp += nread;
+ nchars -= nread;
+ } while (nchars != 0);
+
+ return bp - buf;
+}
+
+
+/*
+ * Compare "file1" to "file2". Return non-zero if they don't compare exactly.
+ */
+int
+xcmp (file1, file2)
+ const char *file1;
+ const char *file2;
+{
+ char *buf1, *buf2;
+ struct stat sb1, sb2;
+ int fd1, fd2;
+ int ret;
+
+ if ((fd1 = open (file1, O_RDONLY)) < 0)
+ error (1, errno, "cannot open file %s for comparing", file1);
+ if ((fd2 = open (file2, O_RDONLY)) < 0)
+ error (1, errno, "cannot open file %s for comparing", file2);
+ if (fstat (fd1, &sb1) < 0)
+ error (1, errno, "cannot fstat %s", file1);
+ if (fstat (fd2, &sb2) < 0)
+ error (1, errno, "cannot fstat %s", file2);
+
+ /* A generic file compare routine might compare st_dev & st_ino here
+ to see if the two files being compared are actually the same file.
+ But that won't happen in CVS, so we won't bother. */
+
+ if (sb1.st_size != sb2.st_size)
+ ret = 1;
+ else if (sb1.st_size == 0)
+ ret = 0;
+ else
+ {
+ /* FIXME: compute the optimal buffer size by computing the least
+ common multiple of the files st_blocks field */
+ size_t buf_size = 8 * 1024;
+ size_t read1;
+ size_t read2;
+
+ buf1 = xmalloc (buf_size);
+ buf2 = xmalloc (buf_size);
+
+ do
+ {
+ read1 = block_read (fd1, buf1, buf_size);
+ if (read1 == (size_t)-1)
+ error (1, errno, "cannot read file %s for comparing", file1);
+
+ read2 = block_read (fd2, buf2, buf_size);
+ if (read2 == (size_t)-1)
+ error (1, errno, "cannot read file %s for comparing", file2);
+
+ /* assert (read1 == read2); */
+
+ ret = memcmp(buf1, buf2, read1);
+ } while (ret == 0 && read1 == buf_size);
+
+ free (buf1);
+ free (buf2);
+ }
+
+ (void) close (fd1);
+ (void) close (fd2);
+ return (ret);
+}
+
+#ifdef LOSING_TMPNAM_FUNCTION
+char *tmpnam(char *s)
+{
+ static char value[L_tmpnam+1];
+
+ if (s){
+ strcpy(s,"/tmp/cvsXXXXXX");
+ mktemp(s);
+ return s;
+ }else{
+ strcpy(value,"/tmp/cvsXXXXXX");
+ mktemp(s);
+ return value;
+ }
+}
+#endif
+
+/* Return non-zero iff FILENAME is absolute.
+ Trivial under Unix, but more complicated under other systems. */
+int
+isabsolute (filename)
+ const char *filename;
+{
+ return filename[0] == '/';
+}
+
+
+/* Return a pointer into PATH's last component. */
+char *
+last_component (path)
+ char *path;
+{
+ char *last = strrchr (path, '/');
+
+ if (last)
+ return last + 1;
+ else
+ return path;
+}
diff --git a/gnu/usr.bin/cvs/lib/getdate.y b/gnu/usr.bin/cvs/lib/getdate.y
new file mode 100644
index 0000000..baa1731
--- /dev/null
+++ b/gnu/usr.bin/cvs/lib/getdate.y
@@ -0,0 +1,996 @@
+%{
+/*
+** Originally written by Steven M. Bellovin <smb@research.att.com> while
+** at the University of North Carolina at Chapel Hill. Later tweaked by
+** a couple of people on Usenet. Completely overhauled by Rich $alz
+** <rsalz@bbn.com> and Jim Berets <jberets@bbn.com> in August, 1990;
+** send any email to Rich.
+**
+** This grammar has 10 shift/reduce conflicts.
+**
+** This code is in the public domain and has no copyright.
+*/
+/* SUPPRESS 287 on yaccpar_sccsid *//* Unused static variable */
+/* SUPPRESS 288 on yyerrlab *//* Label unused */
+
+#ifdef HAVE_CONFIG_H
+#if defined (emacs) || defined (CONFIG_BROKETS)
+#include <config.h>
+#else
+#include "config.h"
+#endif
+#endif
+
+/* Since the code of getdate.y is not included in the Emacs executable
+ itself, there is no need to #define static in this file. Even if
+ the code were included in the Emacs executable, it probably
+ wouldn't do any harm to #undef it here; this will only cause
+ problems if we try to write to a static variable, which I don't
+ think this code needs to do. */
+#ifdef emacs
+#undef static
+#endif
+
+#include <stdio.h>
+#include <ctype.h>
+
+/* The code at the top of get_date which figures out the offset of the
+ current time zone checks various CPP symbols to see if special
+ tricks are need, but defaults to using the gettimeofday system call.
+ Include <sys/time.h> if that will be used. */
+
+#if defined(vms)
+
+#include <types.h>
+#include <time.h>
+
+#else
+
+#include <sys/types.h>
+
+#ifdef TIME_WITH_SYS_TIME
+#include <sys/time.h>
+#include <time.h>
+#else
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#else
+#include <time.h>
+#endif
+#endif
+
+#ifdef timezone
+#undef timezone /* needed for sgi */
+#endif
+
+#if defined(HAVE_SYS_TIMEB_H)
+#include <sys/timeb.h>
+#else
+/*
+** We use the obsolete `struct timeb' as part of our interface!
+** Since the system doesn't have it, we define it here;
+** our callers must do likewise.
+*/
+struct timeb {
+ time_t time; /* Seconds since the epoch */
+ unsigned short millitm; /* Field not used */
+ short timezone; /* Minutes west of GMT */
+ short dstflag; /* Field not used */
+};
+#endif /* defined(HAVE_SYS_TIMEB_H) */
+
+#endif /* defined(vms) */
+
+#if defined (STDC_HEADERS) || defined (USG)
+#include <string.h>
+#endif
+
+/* Some old versions of bison generate parsers that use bcopy.
+ That loses on systems that don't provide the function, so we have
+ to redefine it here. */
+#if !defined (HAVE_BCOPY) && defined (HAVE_MEMCPY) && !defined (bcopy)
+#define bcopy(from, to, len) memcpy ((to), (from), (len))
+#endif
+
+#if defined (STDC_HEADERS)
+#include <stdlib.h>
+#endif
+
+#if defined (HAVE_ALLOCA_H)
+#include <alloca.h>
+#endif
+
+extern struct tm *gmtime();
+extern struct tm *localtime();
+
+#define yyparse getdate_yyparse
+#define yylex getdate_yylex
+#define yyerror getdate_yyerror
+
+#if !defined(lint) && !defined(SABER)
+static char RCS[] = "$CVSid: @(#)getdate.y 1.11 94/09/21 $";
+#endif /* !defined(lint) && !defined(SABER) */
+
+static int yylex ();
+static int yyerror ();
+
+#define EPOCH 1970
+#define HOUR(x) ((time_t)(x) * 60)
+#define SECSPERDAY (24L * 60L * 60L)
+
+
+/*
+** An entry in the lexical lookup table.
+*/
+typedef struct _TABLE {
+ char *name;
+ int type;
+ time_t value;
+} TABLE;
+
+
+/*
+** Daylight-savings mode: on, off, or not yet known.
+*/
+typedef enum _DSTMODE {
+ DSTon, DSToff, DSTmaybe
+} DSTMODE;
+
+/*
+** Meridian: am, pm, or 24-hour style.
+*/
+typedef enum _MERIDIAN {
+ MERam, MERpm, MER24
+} MERIDIAN;
+
+
+/*
+** Global variables. We could get rid of most of these by using a good
+** union as the yacc stack. (This routine was originally written before
+** yacc had the %union construct.) Maybe someday; right now we only use
+** the %union very rarely.
+*/
+static char *yyInput;
+static DSTMODE yyDSTmode;
+static time_t yyDayOrdinal;
+static time_t yyDayNumber;
+static int yyHaveDate;
+static int yyHaveDay;
+static int yyHaveRel;
+static int yyHaveTime;
+static int yyHaveZone;
+static time_t yyTimezone;
+static time_t yyDay;
+static time_t yyHour;
+static time_t yyMinutes;
+static time_t yyMonth;
+static time_t yySeconds;
+static time_t yyYear;
+static MERIDIAN yyMeridian;
+static time_t yyRelMonth;
+static time_t yyRelSeconds;
+
+%}
+
+%union {
+ time_t Number;
+ enum _MERIDIAN Meridian;
+}
+
+%token tAGO tDAY tDAYZONE tID tMERIDIAN tMINUTE_UNIT tMONTH tMONTH_UNIT
+%token tSEC_UNIT tSNUMBER tUNUMBER tZONE tDST
+
+%type <Number> tDAY tDAYZONE tMINUTE_UNIT tMONTH tMONTH_UNIT
+%type <Number> tSEC_UNIT tSNUMBER tUNUMBER tZONE
+%type <Meridian> tMERIDIAN o_merid
+
+%%
+
+spec : /* NULL */
+ | spec item
+ ;
+
+item : time {
+ yyHaveTime++;
+ }
+ | zone {
+ yyHaveZone++;
+ }
+ | date {
+ yyHaveDate++;
+ }
+ | day {
+ yyHaveDay++;
+ }
+ | rel {
+ yyHaveRel++;
+ }
+ | number
+ ;
+
+time : tUNUMBER tMERIDIAN {
+ yyHour = $1;
+ yyMinutes = 0;
+ yySeconds = 0;
+ yyMeridian = $2;
+ }
+ | tUNUMBER ':' tUNUMBER o_merid {
+ yyHour = $1;
+ yyMinutes = $3;
+ yySeconds = 0;
+ yyMeridian = $4;
+ }
+ | tUNUMBER ':' tUNUMBER tSNUMBER {
+ yyHour = $1;
+ yyMinutes = $3;
+ yyMeridian = MER24;
+ yyDSTmode = DSToff;
+ yyTimezone = - ($4 % 100 + ($4 / 100) * 60);
+ }
+ | tUNUMBER ':' tUNUMBER ':' tUNUMBER o_merid {
+ yyHour = $1;
+ yyMinutes = $3;
+ yySeconds = $5;
+ yyMeridian = $6;
+ }
+ | tUNUMBER ':' tUNUMBER ':' tUNUMBER tSNUMBER {
+ yyHour = $1;
+ yyMinutes = $3;
+ yySeconds = $5;
+ yyMeridian = MER24;
+ yyDSTmode = DSToff;
+ yyTimezone = - ($6 % 100 + ($6 / 100) * 60);
+ }
+ ;
+
+zone : tZONE {
+ yyTimezone = $1;
+ yyDSTmode = DSToff;
+ }
+ | tDAYZONE {
+ yyTimezone = $1;
+ yyDSTmode = DSTon;
+ }
+ |
+ tZONE tDST {
+ yyTimezone = $1;
+ yyDSTmode = DSTon;
+ }
+ ;
+
+day : tDAY {
+ yyDayOrdinal = 1;
+ yyDayNumber = $1;
+ }
+ | tDAY ',' {
+ yyDayOrdinal = 1;
+ yyDayNumber = $1;
+ }
+ | tUNUMBER tDAY {
+ yyDayOrdinal = $1;
+ yyDayNumber = $2;
+ }
+ ;
+
+date : tUNUMBER '/' tUNUMBER {
+ yyMonth = $1;
+ yyDay = $3;
+ }
+ | tUNUMBER '/' tUNUMBER '/' tUNUMBER {
+ yyMonth = $1;
+ yyDay = $3;
+ yyYear = $5;
+ }
+ | tUNUMBER tSNUMBER tSNUMBER {
+ /* ISO 8601 format. yyyy-mm-dd. */
+ yyYear = $1;
+ yyMonth = -$2;
+ yyDay = -$3;
+ }
+ | tUNUMBER tMONTH tSNUMBER {
+ /* e.g. 17-JUN-1992. */
+ yyDay = $1;
+ yyMonth = $2;
+ yyYear = -$3;
+ }
+ | tMONTH tUNUMBER {
+ yyMonth = $1;
+ yyDay = $2;
+ }
+ | tMONTH tUNUMBER ',' tUNUMBER {
+ yyMonth = $1;
+ yyDay = $2;
+ yyYear = $4;
+ }
+ | tUNUMBER tMONTH {
+ yyMonth = $2;
+ yyDay = $1;
+ }
+ | tUNUMBER tMONTH tUNUMBER {
+ yyMonth = $2;
+ yyDay = $1;
+ yyYear = $3;
+ }
+ ;
+
+rel : relunit tAGO {
+ yyRelSeconds = -yyRelSeconds;
+ yyRelMonth = -yyRelMonth;
+ }
+ | relunit
+ ;
+
+relunit : tUNUMBER tMINUTE_UNIT {
+ yyRelSeconds += $1 * $2 * 60L;
+ }
+ | tSNUMBER tMINUTE_UNIT {
+ yyRelSeconds += $1 * $2 * 60L;
+ }
+ | tMINUTE_UNIT {
+ yyRelSeconds += $1 * 60L;
+ }
+ | tSNUMBER tSEC_UNIT {
+ yyRelSeconds += $1;
+ }
+ | tUNUMBER tSEC_UNIT {
+ yyRelSeconds += $1;
+ }
+ | tSEC_UNIT {
+ yyRelSeconds++;
+ }
+ | tSNUMBER tMONTH_UNIT {
+ yyRelMonth += $1 * $2;
+ }
+ | tUNUMBER tMONTH_UNIT {
+ yyRelMonth += $1 * $2;
+ }
+ | tMONTH_UNIT {
+ yyRelMonth += $1;
+ }
+ ;
+
+number : tUNUMBER {
+ if (yyHaveTime && yyHaveDate && !yyHaveRel)
+ yyYear = $1;
+ else {
+ if($1>10000) {
+ yyHaveDate++;
+ yyDay= ($1)%100;
+ yyMonth= ($1/100)%100;
+ yyYear = $1/10000;
+ }
+ else {
+ yyHaveTime++;
+ if ($1 < 100) {
+ yyHour = $1;
+ yyMinutes = 0;
+ }
+ else {
+ yyHour = $1 / 100;
+ yyMinutes = $1 % 100;
+ }
+ yySeconds = 0;
+ yyMeridian = MER24;
+ }
+ }
+ }
+ ;
+
+o_merid : /* NULL */ {
+ $$ = MER24;
+ }
+ | tMERIDIAN {
+ $$ = $1;
+ }
+ ;
+
+%%
+
+/* Month and day table. */
+static TABLE const MonthDayTable[] = {
+ { "january", tMONTH, 1 },
+ { "february", tMONTH, 2 },
+ { "march", tMONTH, 3 },
+ { "april", tMONTH, 4 },
+ { "may", tMONTH, 5 },
+ { "june", tMONTH, 6 },
+ { "july", tMONTH, 7 },
+ { "august", tMONTH, 8 },
+ { "september", tMONTH, 9 },
+ { "sept", tMONTH, 9 },
+ { "october", tMONTH, 10 },
+ { "november", tMONTH, 11 },
+ { "december", tMONTH, 12 },
+ { "sunday", tDAY, 0 },
+ { "monday", tDAY, 1 },
+ { "tuesday", tDAY, 2 },
+ { "tues", tDAY, 2 },
+ { "wednesday", tDAY, 3 },
+ { "wednes", tDAY, 3 },
+ { "thursday", tDAY, 4 },
+ { "thur", tDAY, 4 },
+ { "thurs", tDAY, 4 },
+ { "friday", tDAY, 5 },
+ { "saturday", tDAY, 6 },
+ { NULL }
+};
+
+/* Time units table. */
+static TABLE const UnitsTable[] = {
+ { "year", tMONTH_UNIT, 12 },
+ { "month", tMONTH_UNIT, 1 },
+ { "fortnight", tMINUTE_UNIT, 14 * 24 * 60 },
+ { "week", tMINUTE_UNIT, 7 * 24 * 60 },
+ { "day", tMINUTE_UNIT, 1 * 24 * 60 },
+ { "hour", tMINUTE_UNIT, 60 },
+ { "minute", tMINUTE_UNIT, 1 },
+ { "min", tMINUTE_UNIT, 1 },
+ { "second", tSEC_UNIT, 1 },
+ { "sec", tSEC_UNIT, 1 },
+ { NULL }
+};
+
+/* Assorted relative-time words. */
+static TABLE const OtherTable[] = {
+ { "tomorrow", tMINUTE_UNIT, 1 * 24 * 60 },
+ { "yesterday", tMINUTE_UNIT, -1 * 24 * 60 },
+ { "today", tMINUTE_UNIT, 0 },
+ { "now", tMINUTE_UNIT, 0 },
+ { "last", tUNUMBER, -1 },
+ { "this", tMINUTE_UNIT, 0 },
+ { "next", tUNUMBER, 2 },
+ { "first", tUNUMBER, 1 },
+/* { "second", tUNUMBER, 2 }, */
+ { "third", tUNUMBER, 3 },
+ { "fourth", tUNUMBER, 4 },
+ { "fifth", tUNUMBER, 5 },
+ { "sixth", tUNUMBER, 6 },
+ { "seventh", tUNUMBER, 7 },
+ { "eighth", tUNUMBER, 8 },
+ { "ninth", tUNUMBER, 9 },
+ { "tenth", tUNUMBER, 10 },
+ { "eleventh", tUNUMBER, 11 },
+ { "twelfth", tUNUMBER, 12 },
+ { "ago", tAGO, 1 },
+ { NULL }
+};
+
+/* The timezone table. */
+/* Some of these are commented out because a time_t can't store a float. */
+static TABLE const TimezoneTable[] = {
+ { "gmt", tZONE, HOUR( 0) }, /* Greenwich Mean */
+ { "ut", tZONE, HOUR( 0) }, /* Universal (Coordinated) */
+ { "utc", tZONE, HOUR( 0) },
+ { "wet", tZONE, HOUR( 0) }, /* Western European */
+ { "bst", tDAYZONE, HOUR( 0) }, /* British Summer */
+ { "wat", tZONE, HOUR( 1) }, /* West Africa */
+ { "at", tZONE, HOUR( 2) }, /* Azores */
+#if 0
+ /* For completeness. BST is also British Summer, and GST is
+ * also Guam Standard. */
+ { "bst", tZONE, HOUR( 3) }, /* Brazil Standard */
+ { "gst", tZONE, HOUR( 3) }, /* Greenland Standard */
+#endif
+#if 0
+ { "nft", tZONE, HOUR(3.5) }, /* Newfoundland */
+ { "nst", tZONE, HOUR(3.5) }, /* Newfoundland Standard */
+ { "ndt", tDAYZONE, HOUR(3.5) }, /* Newfoundland Daylight */
+#endif
+ { "ast", tZONE, HOUR( 4) }, /* Atlantic Standard */
+ { "adt", tDAYZONE, HOUR( 4) }, /* Atlantic Daylight */
+ { "est", tZONE, HOUR( 5) }, /* Eastern Standard */
+ { "edt", tDAYZONE, HOUR( 5) }, /* Eastern Daylight */
+ { "cst", tZONE, HOUR( 6) }, /* Central Standard */
+ { "cdt", tDAYZONE, HOUR( 6) }, /* Central Daylight */
+ { "mst", tZONE, HOUR( 7) }, /* Mountain Standard */
+ { "mdt", tDAYZONE, HOUR( 7) }, /* Mountain Daylight */
+ { "pst", tZONE, HOUR( 8) }, /* Pacific Standard */
+ { "pdt", tDAYZONE, HOUR( 8) }, /* Pacific Daylight */
+ { "yst", tZONE, HOUR( 9) }, /* Yukon Standard */
+ { "ydt", tDAYZONE, HOUR( 9) }, /* Yukon Daylight */
+ { "hst", tZONE, HOUR(10) }, /* Hawaii Standard */
+ { "hdt", tDAYZONE, HOUR(10) }, /* Hawaii Daylight */
+ { "cat", tZONE, HOUR(10) }, /* Central Alaska */
+ { "ahst", tZONE, HOUR(10) }, /* Alaska-Hawaii Standard */
+ { "nt", tZONE, HOUR(11) }, /* Nome */
+ { "idlw", tZONE, HOUR(12) }, /* International Date Line West */
+ { "cet", tZONE, -HOUR(1) }, /* Central European */
+ { "met", tZONE, -HOUR(1) }, /* Middle European */
+ { "mewt", tZONE, -HOUR(1) }, /* Middle European Winter */
+ { "mest", tDAYZONE, -HOUR(1) }, /* Middle European Summer */
+ { "swt", tZONE, -HOUR(1) }, /* Swedish Winter */
+ { "sst", tDAYZONE, -HOUR(1) }, /* Swedish Summer */
+ { "fwt", tZONE, -HOUR(1) }, /* French Winter */
+ { "fst", tDAYZONE, -HOUR(1) }, /* French Summer */
+ { "eet", tZONE, -HOUR(2) }, /* Eastern Europe, USSR Zone 1 */
+ { "bt", tZONE, -HOUR(3) }, /* Baghdad, USSR Zone 2 */
+#if 0
+ { "it", tZONE, -HOUR(3.5) },/* Iran */
+#endif
+ { "zp4", tZONE, -HOUR(4) }, /* USSR Zone 3 */
+ { "zp5", tZONE, -HOUR(5) }, /* USSR Zone 4 */
+#if 0
+ { "ist", tZONE, -HOUR(5.5) },/* Indian Standard */
+#endif
+ { "zp6", tZONE, -HOUR(6) }, /* USSR Zone 5 */
+#if 0
+ /* For completeness. NST is also Newfoundland Stanard, and SST is
+ * also Swedish Summer. */
+ { "nst", tZONE, -HOUR(6.5) },/* North Sumatra */
+ { "sst", tZONE, -HOUR(7) }, /* South Sumatra, USSR Zone 6 */
+#endif /* 0 */
+ { "wast", tZONE, -HOUR(7) }, /* West Australian Standard */
+ { "wadt", tDAYZONE, -HOUR(7) }, /* West Australian Daylight */
+#if 0
+ { "jt", tZONE, -HOUR(7.5) },/* Java (3pm in Cronusland!) */
+#endif
+ { "cct", tZONE, -HOUR(8) }, /* China Coast, USSR Zone 7 */
+ { "jst", tZONE, -HOUR(9) }, /* Japan Standard, USSR Zone 8 */
+#if 0
+ { "cast", tZONE, -HOUR(9.5) },/* Central Australian Standard */
+ { "cadt", tDAYZONE, -HOUR(9.5) },/* Central Australian Daylight */
+#endif
+ { "east", tZONE, -HOUR(10) }, /* Eastern Australian Standard */
+ { "eadt", tDAYZONE, -HOUR(10) }, /* Eastern Australian Daylight */
+ { "gst", tZONE, -HOUR(10) }, /* Guam Standard, USSR Zone 9 */
+ { "nzt", tZONE, -HOUR(12) }, /* New Zealand */
+ { "nzst", tZONE, -HOUR(12) }, /* New Zealand Standard */
+ { "nzdt", tDAYZONE, -HOUR(12) }, /* New Zealand Daylight */
+ { "idle", tZONE, -HOUR(12) }, /* International Date Line East */
+ { NULL }
+};
+
+/* Military timezone table. */
+static TABLE const MilitaryTable[] = {
+ { "a", tZONE, HOUR( 1) },
+ { "b", tZONE, HOUR( 2) },
+ { "c", tZONE, HOUR( 3) },
+ { "d", tZONE, HOUR( 4) },
+ { "e", tZONE, HOUR( 5) },
+ { "f", tZONE, HOUR( 6) },
+ { "g", tZONE, HOUR( 7) },
+ { "h", tZONE, HOUR( 8) },
+ { "i", tZONE, HOUR( 9) },
+ { "k", tZONE, HOUR( 10) },
+ { "l", tZONE, HOUR( 11) },
+ { "m", tZONE, HOUR( 12) },
+ { "n", tZONE, HOUR(- 1) },
+ { "o", tZONE, HOUR(- 2) },
+ { "p", tZONE, HOUR(- 3) },
+ { "q", tZONE, HOUR(- 4) },
+ { "r", tZONE, HOUR(- 5) },
+ { "s", tZONE, HOUR(- 6) },
+ { "t", tZONE, HOUR(- 7) },
+ { "u", tZONE, HOUR(- 8) },
+ { "v", tZONE, HOUR(- 9) },
+ { "w", tZONE, HOUR(-10) },
+ { "x", tZONE, HOUR(-11) },
+ { "y", tZONE, HOUR(-12) },
+ { "z", tZONE, HOUR( 0) },
+ { NULL }
+};
+
+
+
+
+/* ARGSUSED */
+static int
+yyerror(s)
+ char *s;
+{
+ return 0;
+}
+
+
+static time_t
+ToSeconds(Hours, Minutes, Seconds, Meridian)
+ time_t Hours;
+ time_t Minutes;
+ time_t Seconds;
+ MERIDIAN Meridian;
+{
+ if (Minutes < 0 || Minutes > 59 || Seconds < 0 || Seconds > 59)
+ return -1;
+ switch (Meridian) {
+ case MER24:
+ if (Hours < 0 || Hours > 23)
+ return -1;
+ return (Hours * 60L + Minutes) * 60L + Seconds;
+ case MERam:
+ if (Hours < 1 || Hours > 12)
+ return -1;
+ return (Hours * 60L + Minutes) * 60L + Seconds;
+ case MERpm:
+ if (Hours < 1 || Hours > 12)
+ return -1;
+ return ((Hours + 12) * 60L + Minutes) * 60L + Seconds;
+ default:
+ abort ();
+ }
+ /* NOTREACHED */
+}
+
+
+static time_t
+Convert(Month, Day, Year, Hours, Minutes, Seconds, Meridian, DSTmode)
+ time_t Month;
+ time_t Day;
+ time_t Year;
+ time_t Hours;
+ time_t Minutes;
+ time_t Seconds;
+ MERIDIAN Meridian;
+ DSTMODE DSTmode;
+{
+ static int DaysInMonth[12] = {
+ 31, 0, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
+ };
+ time_t tod;
+ time_t Julian;
+ int i;
+
+ if (Year < 0)
+ Year = -Year;
+ if (Year < 100)
+ Year += 1900;
+ DaysInMonth[1] = Year % 4 == 0 && (Year % 100 != 0 || Year % 400 == 0)
+ ? 29 : 28;
+ if (Year < EPOCH || Year > 1999
+ || Month < 1 || Month > 12
+ /* Lint fluff: "conversion from long may lose accuracy" */
+ || Day < 1 || Day > DaysInMonth[(int)--Month])
+ return -1;
+
+ for (Julian = Day - 1, i = 0; i < Month; i++)
+ Julian += DaysInMonth[i];
+ for (i = EPOCH; i < Year; i++)
+ Julian += 365 + (i % 4 == 0);
+ Julian *= SECSPERDAY;
+ Julian += yyTimezone * 60L;
+ if ((tod = ToSeconds(Hours, Minutes, Seconds, Meridian)) < 0)
+ return -1;
+ Julian += tod;
+ if (DSTmode == DSTon
+ || (DSTmode == DSTmaybe && localtime(&Julian)->tm_isdst))
+ Julian -= 60 * 60;
+ return Julian;
+}
+
+
+static time_t
+DSTcorrect(Start, Future)
+ time_t Start;
+ time_t Future;
+{
+ time_t StartDay;
+ time_t FutureDay;
+
+ StartDay = (localtime(&Start)->tm_hour + 1) % 24;
+ FutureDay = (localtime(&Future)->tm_hour + 1) % 24;
+ return (Future - Start) + (StartDay - FutureDay) * 60L * 60L;
+}
+
+
+static time_t
+RelativeDate(Start, DayOrdinal, DayNumber)
+ time_t Start;
+ time_t DayOrdinal;
+ time_t DayNumber;
+{
+ struct tm *tm;
+ time_t now;
+
+ now = Start;
+ tm = localtime(&now);
+ now += SECSPERDAY * ((DayNumber - tm->tm_wday + 7) % 7);
+ now += 7 * SECSPERDAY * (DayOrdinal <= 0 ? DayOrdinal : DayOrdinal - 1);
+ return DSTcorrect(Start, now);
+}
+
+
+static time_t
+RelativeMonth(Start, RelMonth)
+ time_t Start;
+ time_t RelMonth;
+{
+ struct tm *tm;
+ time_t Month;
+ time_t Year;
+
+ if (RelMonth == 0)
+ return 0;
+ tm = localtime(&Start);
+ Month = 12 * tm->tm_year + tm->tm_mon + RelMonth;
+ Year = Month / 12;
+ Month = Month % 12 + 1;
+ return DSTcorrect(Start,
+ Convert(Month, (time_t)tm->tm_mday, Year,
+ (time_t)tm->tm_hour, (time_t)tm->tm_min, (time_t)tm->tm_sec,
+ MER24, DSTmaybe));
+}
+
+
+static int
+LookupWord(buff)
+ char *buff;
+{
+ register char *p;
+ register char *q;
+ register const TABLE *tp;
+ int i;
+ int abbrev;
+
+ /* Make it lowercase. */
+ for (p = buff; *p; p++)
+ if (isupper(*p))
+ *p = tolower(*p);
+
+ if (strcmp(buff, "am") == 0 || strcmp(buff, "a.m.") == 0) {
+ yylval.Meridian = MERam;
+ return tMERIDIAN;
+ }
+ if (strcmp(buff, "pm") == 0 || strcmp(buff, "p.m.") == 0) {
+ yylval.Meridian = MERpm;
+ return tMERIDIAN;
+ }
+
+ /* See if we have an abbreviation for a month. */
+ if (strlen(buff) == 3)
+ abbrev = 1;
+ else if (strlen(buff) == 4 && buff[3] == '.') {
+ abbrev = 1;
+ buff[3] = '\0';
+ }
+ else
+ abbrev = 0;
+
+ for (tp = MonthDayTable; tp->name; tp++) {
+ if (abbrev) {
+ if (strncmp(buff, tp->name, 3) == 0) {
+ yylval.Number = tp->value;
+ return tp->type;
+ }
+ }
+ else if (strcmp(buff, tp->name) == 0) {
+ yylval.Number = tp->value;
+ return tp->type;
+ }
+ }
+
+ for (tp = TimezoneTable; tp->name; tp++)
+ if (strcmp(buff, tp->name) == 0) {
+ yylval.Number = tp->value;
+ return tp->type;
+ }
+
+ if (strcmp(buff, "dst") == 0)
+ return tDST;
+
+ for (tp = UnitsTable; tp->name; tp++)
+ if (strcmp(buff, tp->name) == 0) {
+ yylval.Number = tp->value;
+ return tp->type;
+ }
+
+ /* Strip off any plural and try the units table again. */
+ i = strlen(buff) - 1;
+ if (buff[i] == 's') {
+ buff[i] = '\0';
+ for (tp = UnitsTable; tp->name; tp++)
+ if (strcmp(buff, tp->name) == 0) {
+ yylval.Number = tp->value;
+ return tp->type;
+ }
+ buff[i] = 's'; /* Put back for "this" in OtherTable. */
+ }
+
+ for (tp = OtherTable; tp->name; tp++)
+ if (strcmp(buff, tp->name) == 0) {
+ yylval.Number = tp->value;
+ return tp->type;
+ }
+
+ /* Military timezones. */
+ if (buff[1] == '\0' && isalpha(*buff)) {
+ for (tp = MilitaryTable; tp->name; tp++)
+ if (strcmp(buff, tp->name) == 0) {
+ yylval.Number = tp->value;
+ return tp->type;
+ }
+ }
+
+ /* Drop out any periods and try the timezone table again. */
+ for (i = 0, p = q = buff; *q; q++)
+ if (*q != '.')
+ *p++ = *q;
+ else
+ i++;
+ *p = '\0';
+ if (i)
+ for (tp = TimezoneTable; tp->name; tp++)
+ if (strcmp(buff, tp->name) == 0) {
+ yylval.Number = tp->value;
+ return tp->type;
+ }
+
+ return tID;
+}
+
+
+static int
+yylex()
+{
+ register char c;
+ register char *p;
+ char buff[20];
+ int Count;
+ int sign;
+
+ for ( ; ; ) {
+ while (isspace(*yyInput))
+ yyInput++;
+
+ if (isdigit(c = *yyInput) || c == '-' || c == '+') {
+ if (c == '-' || c == '+') {
+ sign = c == '-' ? -1 : 1;
+ if (!isdigit(*++yyInput))
+ /* skip the '-' sign */
+ continue;
+ }
+ else
+ sign = 0;
+ for (yylval.Number = 0; isdigit(c = *yyInput++); )
+ yylval.Number = 10 * yylval.Number + c - '0';
+ yyInput--;
+ if (sign < 0)
+ yylval.Number = -yylval.Number;
+ return sign ? tSNUMBER : tUNUMBER;
+ }
+ if (isalpha(c)) {
+ for (p = buff; isalpha(c = *yyInput++) || c == '.'; )
+ if (p < &buff[sizeof buff - 1])
+ *p++ = c;
+ *p = '\0';
+ yyInput--;
+ return LookupWord(buff);
+ }
+ if (c != '(')
+ return *yyInput++;
+ Count = 0;
+ do {
+ c = *yyInput++;
+ if (c == '\0')
+ return c;
+ if (c == '(')
+ Count++;
+ else if (c == ')')
+ Count--;
+ } while (Count > 0);
+ }
+}
+
+#define TM_YEAR_ORIGIN 1900
+
+/* Yield A - B, measured in seconds. */
+static long
+difftm (a, b)
+ struct tm *a, *b;
+{
+ int ay = a->tm_year + (TM_YEAR_ORIGIN - 1);
+ int by = b->tm_year + (TM_YEAR_ORIGIN - 1);
+ int days = (
+ /* difference in day of year */
+ a->tm_yday - b->tm_yday
+ /* + intervening leap days */
+ + ((ay >> 2) - (by >> 2))
+ - (ay/100 - by/100)
+ + ((ay/100 >> 2) - (by/100 >> 2))
+ /* + difference in years * 365 */
+ + (long)(ay-by) * 365
+ );
+ return (60*(60*(24*days + (a->tm_hour - b->tm_hour))
+ + (a->tm_min - b->tm_min))
+ + (a->tm_sec - b->tm_sec));
+}
+
+time_t
+get_date(p, now)
+ char *p;
+ struct timeb *now;
+{
+ struct tm *tm, gmt;
+ struct timeb ftz;
+ time_t Start;
+ time_t tod;
+
+ yyInput = p;
+ if (now == NULL) {
+ now = &ftz;
+ (void)time(&ftz.time);
+
+ if (! (tm = gmtime (&ftz.time)))
+ return -1;
+ gmt = *tm; /* Make a copy, in case localtime modifies *tm. */
+
+ if (! (tm = localtime (&ftz.time)))
+ return -1;
+
+ ftz.timezone = difftm (&gmt, tm) / 60;
+ if(tm->tm_isdst)
+ ftz.timezone += 60;
+ }
+
+ tm = localtime(&now->time);
+ yyYear = tm->tm_year;
+ yyMonth = tm->tm_mon + 1;
+ yyDay = tm->tm_mday;
+ yyTimezone = now->timezone;
+ yyDSTmode = DSTmaybe;
+ yyHour = 0;
+ yyMinutes = 0;
+ yySeconds = 0;
+ yyMeridian = MER24;
+ yyRelSeconds = 0;
+ yyRelMonth = 0;
+ yyHaveDate = 0;
+ yyHaveDay = 0;
+ yyHaveRel = 0;
+ yyHaveTime = 0;
+ yyHaveZone = 0;
+
+ if (yyparse()
+ || yyHaveTime > 1 || yyHaveZone > 1 || yyHaveDate > 1 || yyHaveDay > 1)
+ return -1;
+
+ if (yyHaveDate || yyHaveTime || yyHaveDay) {
+ Start = Convert(yyMonth, yyDay, yyYear, yyHour, yyMinutes, yySeconds,
+ yyMeridian, yyDSTmode);
+ if (Start < 0)
+ return -1;
+ }
+ else {
+ Start = now->time;
+ if (!yyHaveRel)
+ Start -= ((tm->tm_hour * 60L + tm->tm_min) * 60L) + tm->tm_sec;
+ }
+
+ Start += yyRelSeconds;
+ Start += RelativeMonth(Start, yyRelMonth);
+
+ if (yyHaveDay && !yyHaveDate) {
+ tod = RelativeDate(Start, yyDayOrdinal, yyDayNumber);
+ Start += tod;
+ }
+
+ /* Have to do *something* with a legitimate -1 so it's distinguishable
+ * from the error return value. (Alternately could set errno on error.) */
+ return Start == -1 ? 0 : Start;
+}
+
+
+#if defined(TEST)
+
+/* ARGSUSED */
+int
+main(ac, av)
+ int ac;
+ char *av[];
+{
+ char buff[128];
+ time_t d;
+
+ (void)printf("Enter date, or blank line to exit.\n\t> ");
+ (void)fflush(stdout);
+ while (gets(buff) && buff[0]) {
+ d = get_date(buff, (struct timeb *)NULL);
+ if (d == -1)
+ (void)printf("Bad format - couldn't convert.\n");
+ else
+ (void)printf("%s", ctime(&d));
+ (void)printf("\t> ");
+ (void)fflush(stdout);
+ }
+ exit(0);
+ /* NOTREACHED */
+}
+#endif /* defined(TEST) */
diff --git a/gnu/usr.bin/cvs/lib/getline.c b/gnu/usr.bin/cvs/lib/getline.c
new file mode 100644
index 0000000..c699461
--- /dev/null
+++ b/gnu/usr.bin/cvs/lib/getline.c
@@ -0,0 +1,126 @@
+/* getline.c -- Replacement for GNU C library function getline
+
+Copyright (C) 1993 Free Software Foundation, Inc.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 2 of the
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* Written by Jan Brittenson, bson@gnu.ai.mit.edu. */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <sys/types.h>
+#include <stdio.h>
+#define NDEBUG
+#include <assert.h>
+
+#if STDC_HEADERS
+#include <stdlib.h>
+#else
+char *malloc (), *realloc ();
+#endif
+
+/* Always add at least this many bytes when extending the buffer. */
+#define MIN_CHUNK 64
+
+/* Read up to (and including) a TERMINATOR from STREAM into *LINEPTR
+ + OFFSET (and null-terminate it). *LINEPTR is a pointer returned from
+ malloc (or NULL), pointing to *N characters of space. It is realloc'd
+ as necessary. Return the number of characters read (not including the
+ null terminator), or -1 on error or EOF. */
+
+int
+getstr (lineptr, n, stream, terminator, offset)
+ char **lineptr;
+ size_t *n;
+ FILE *stream;
+ char terminator;
+ int offset;
+{
+ int nchars_avail; /* Allocated but unused chars in *LINEPTR. */
+ char *read_pos; /* Where we're reading into *LINEPTR. */
+ int ret;
+
+ if (!lineptr || !n || !stream)
+ return -1;
+
+ if (!*lineptr)
+ {
+ *n = MIN_CHUNK;
+ *lineptr = malloc (*n);
+ if (!*lineptr)
+ return -1;
+ }
+
+ nchars_avail = *n - offset;
+ read_pos = *lineptr + offset;
+
+ for (;;)
+ {
+ register int c = getc (stream);
+
+ /* We always want at least one char left in the buffer, since we
+ always (unless we get an error while reading the first char)
+ NUL-terminate the line buffer. */
+
+ assert(*n - nchars_avail == read_pos - *lineptr);
+ if (nchars_avail < 2)
+ {
+ if (*n > MIN_CHUNK)
+ *n *= 2;
+ else
+ *n += MIN_CHUNK;
+
+ nchars_avail = *n + *lineptr - read_pos;
+ *lineptr = realloc (*lineptr, *n);
+ if (!*lineptr)
+ return -1;
+ read_pos = *n - nchars_avail + *lineptr;
+ assert(*n - nchars_avail == read_pos - *lineptr);
+ }
+
+ if (c == EOF || ferror (stream))
+ {
+ /* Return partial line, if any. */
+ if (read_pos == *lineptr)
+ return -1;
+ else
+ break;
+ }
+
+ *read_pos++ = c;
+ nchars_avail--;
+
+ if (c == terminator)
+ /* Return the line. */
+ break;
+ }
+
+ /* Done - NUL terminate and return the number of chars read. */
+ *read_pos = '\0';
+
+ ret = read_pos - (*lineptr + offset);
+ return ret;
+}
+
+int
+getline (lineptr, n, stream)
+ char **lineptr;
+ size_t *n;
+ FILE *stream;
+{
+ return getstr (lineptr, n, stream, '\n', 0);
+}
diff --git a/gnu/usr.bin/cvs/lib/getline.h b/gnu/usr.bin/cvs/lib/getline.h
new file mode 100644
index 0000000..30bcc25
--- /dev/null
+++ b/gnu/usr.bin/cvs/lib/getline.h
@@ -0,0 +1,15 @@
+#ifndef _getline_h_
+#define _getline_h_ 1
+
+#include <stdio.h>
+
+#if defined (__GNUC__) || (defined (__STDC__) && __STDC__)
+#define __PROTO(args) args
+#else
+#define __PROTO(args) ()
+#endif /* GCC. */
+
+int
+ getline __PROTO ((char **_lineptr, size_t *_n, FILE *_stream));
+
+#endif /* _getline_h_ */
diff --git a/gnu/usr.bin/cvs/lib/getopt.c b/gnu/usr.bin/cvs/lib/getopt.c
new file mode 100644
index 0000000..f1d8dfa
--- /dev/null
+++ b/gnu/usr.bin/cvs/lib/getopt.c
@@ -0,0 +1,763 @@
+/* Getopt for GNU.
+ NOTE: getopt is now part of the C library, so if you don't know what
+ "Keep this file name-space clean" means, talk to roland@gnu.ai.mit.edu
+ before changing it!
+
+ Copyright (C) 1987, 88, 89, 90, 91, 92, 93, 94
+ Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any
+ later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* This tells Alpha OSF/1 not to define a getopt prototype in <stdio.h>.
+ Ditto for AIX 3.2 and <stdlib.h>. */
+#ifndef _NO_PROTO
+#define _NO_PROTO
+#endif
+
+#ifdef HAVE_CONFIG_H
+#if defined (emacs) || defined (CONFIG_BROKETS)
+/* We use <config.h> instead of "config.h" so that a compilation
+ using -I. -I$srcdir will use ./config.h rather than $srcdir/config.h
+ (which it would do because it found this file in $srcdir). */
+#include <config.h>
+#else
+#include "config.h"
+#endif
+#endif
+
+#ifndef __STDC__
+/* This is a separate conditional since some stdc systems
+ reject `defined (const)'. */
+#ifndef const
+#define const
+#endif
+#endif
+
+#include <stdio.h>
+
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+
+/* Comment out all this code if we are using the GNU C Library, and are not
+ actually compiling the library itself. This code is part of the GNU C
+ Library, but also included in many other GNU distributions. Compiling
+ and linking in this code is a waste when using the GNU C library
+ (especially if it is a shared library). Rather than having every GNU
+ program understand `configure --with-gnu-libc' and omit the object files,
+ it is simpler to just do this in the source for each such file. */
+
+#if defined (_LIBC) || !defined (__GNU_LIBRARY__)
+
+
+/* This needs to come after some library #include
+ to get __GNU_LIBRARY__ defined. */
+#ifdef __GNU_LIBRARY__
+/* Don't include stdlib.h for non-GNU C libraries because some of them
+ contain conflicting prototypes for getopt. */
+#include <stdlib.h>
+#endif /* GNU C library. */
+
+/* This version of `getopt' appears to the caller like standard Unix `getopt'
+ but it behaves differently for the user, since it allows the user
+ to intersperse the options with the other arguments.
+
+ As `getopt' works, it permutes the elements of ARGV so that,
+ when it is done, all the options precede everything else. Thus
+ all application programs are extended to handle flexible argument order.
+
+ Setting the environment variable POSIXLY_CORRECT disables permutation.
+ Then the behavior is completely standard.
+
+ GNU application programs can use a third alternative mode in which
+ they can distinguish the relative order of options and other arguments. */
+
+#ifndef lint
+static char rcsid[] = "$CVSid: @(#)getopt.c 1.10 94/09/21 $";
+#endif
+
+#include "getopt.h"
+
+/* For communication from `getopt' to the caller.
+ When `getopt' finds an option that takes an argument,
+ the argument value is returned here.
+ Also, when `ordering' is RETURN_IN_ORDER,
+ each non-option ARGV-element is returned here. */
+
+char *optarg = NULL;
+
+/* Index in ARGV of the next element to be scanned.
+ This is used for communication to and from the caller
+ and for communication between successive calls to `getopt'.
+
+ On entry to `getopt', zero means this is the first call; initialize.
+
+ When `getopt' returns EOF, this is the index of the first of the
+ non-option elements that the caller should itself scan.
+
+ Otherwise, `optind' communicates from one call to the next
+ how much of ARGV has been scanned so far. */
+
+/* XXX 1003.2 says this must be 1 before any call. */
+int optind = 0;
+
+/* The next char to be scanned in the option-element
+ in which the last option character we returned was found.
+ This allows us to pick up the scan where we left off.
+
+ If this is zero, or a null string, it means resume the scan
+ by advancing to the next ARGV-element. */
+
+static char *nextchar;
+
+/* Callers store zero here to inhibit the error message
+ for unrecognized options. */
+
+int opterr = 1;
+
+/* Set to an option character which was unrecognized.
+ This must be initialized on some systems to avoid linking in the
+ system's own getopt implementation. */
+
+int optopt = '?';
+
+/* Describe how to deal with options that follow non-option ARGV-elements.
+
+ If the caller did not specify anything,
+ the default is REQUIRE_ORDER if the environment variable
+ POSIXLY_CORRECT is defined, PERMUTE otherwise.
+
+ REQUIRE_ORDER means don't recognize them as options;
+ stop option processing when the first non-option is seen.
+ This is what Unix does.
+ This mode of operation is selected by either setting the environment
+ variable POSIXLY_CORRECT, or using `+' as the first character
+ of the list of option characters.
+
+ PERMUTE is the default. We permute the contents of ARGV as we scan,
+ so that eventually all the non-options are at the end. This allows options
+ to be given in any order, even with programs that were not written to
+ expect this.
+
+ RETURN_IN_ORDER is an option available to programs that were written
+ to expect options and other ARGV-elements in any order and that care about
+ the ordering of the two. We describe each non-option ARGV-element
+ as if it were the argument of an option with character code 1.
+ Using `-' as the first character of the list of option characters
+ selects this mode of operation.
+
+ The special argument `--' forces an end of option-scanning regardless
+ of the value of `ordering'. In the case of RETURN_IN_ORDER, only
+ `--' can cause `getopt' to return EOF with `optind' != ARGC. */
+
+static enum
+{
+ REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER
+} ordering;
+
+/* Value of POSIXLY_CORRECT environment variable. */
+static char *posixly_correct;
+
+#ifdef __GNU_LIBRARY__
+/* We want to avoid inclusion of string.h with non-GNU libraries
+ because there are many ways it can cause trouble.
+ On some systems, it contains special magic macros that don't work
+ in GCC. */
+#include <string.h>
+#define my_index strchr
+#else
+
+/* Avoid depending on library functions or files
+ whose names are inconsistent. */
+
+char *getenv ();
+
+static char *
+my_index (str, chr)
+ const char *str;
+ int chr;
+{
+ while (*str)
+ {
+ if (*str == chr)
+ return (char *) str;
+ str++;
+ }
+ return 0;
+}
+
+/* If using GCC, we can safely declare strlen this way.
+ If not using GCC, it is ok not to declare it. */
+#ifdef __GNUC__
+/* Note that Motorola Delta 68k R3V7 comes with GCC but not stddef.h.
+ That was relevant to code that was here before. */
+#ifndef __STDC__
+/* gcc with -traditional declares the built-in strlen to return int,
+ and has done so at least since version 2.4.5. -- rms. */
+extern int strlen (const char *);
+#endif /* not __STDC__ */
+#endif /* __GNUC__ */
+
+#endif /* not __GNU_LIBRARY__ */
+
+/* Handle permutation of arguments. */
+
+/* Describe the part of ARGV that contains non-options that have
+ been skipped. `first_nonopt' is the index in ARGV of the first of them;
+ `last_nonopt' is the index after the last of them. */
+
+static int first_nonopt;
+static int last_nonopt;
+
+/* Exchange two adjacent subsequences of ARGV.
+ One subsequence is elements [first_nonopt,last_nonopt)
+ which contains all the non-options that have been skipped so far.
+ The other is elements [last_nonopt,optind), which contains all
+ the options processed since those non-options were skipped.
+
+ `first_nonopt' and `last_nonopt' are relocated so that they describe
+ the new indices of the non-options in ARGV after they are moved. */
+
+static void
+exchange (argv)
+ char **argv;
+{
+ int bottom = first_nonopt;
+ int middle = last_nonopt;
+ int top = optind;
+ char *tem;
+
+ /* Exchange the shorter segment with the far end of the longer segment.
+ That puts the shorter segment into the right place.
+ It leaves the longer segment in the right place overall,
+ but it consists of two parts that need to be swapped next. */
+
+ while (top > middle && middle > bottom)
+ {
+ if (top - middle > middle - bottom)
+ {
+ /* Bottom segment is the short one. */
+ int len = middle - bottom;
+ register int i;
+
+ /* Swap it with the top part of the top segment. */
+ for (i = 0; i < len; i++)
+ {
+ tem = argv[bottom + i];
+ argv[bottom + i] = argv[top - (middle - bottom) + i];
+ argv[top - (middle - bottom) + i] = tem;
+ }
+ /* Exclude the moved bottom segment from further swapping. */
+ top -= len;
+ }
+ else
+ {
+ /* Top segment is the short one. */
+ int len = top - middle;
+ register int i;
+
+ /* Swap it with the bottom part of the bottom segment. */
+ for (i = 0; i < len; i++)
+ {
+ tem = argv[bottom + i];
+ argv[bottom + i] = argv[middle + i];
+ argv[middle + i] = tem;
+ }
+ /* Exclude the moved top segment from further swapping. */
+ bottom += len;
+ }
+ }
+
+ /* Update records for the slots the non-options now occupy. */
+
+ first_nonopt += (optind - last_nonopt);
+ last_nonopt = optind;
+}
+
+/* Initialize the internal data when the first call is made. */
+
+static const char *
+_getopt_initialize (optstring)
+ const char *optstring;
+{
+ /* Start processing options with ARGV-element 1 (since ARGV-element 0
+ is the program name); the sequence of previously skipped
+ non-option ARGV-elements is empty. */
+
+ first_nonopt = last_nonopt = optind = 1;
+
+ nextchar = NULL;
+
+ posixly_correct = getenv ("POSIXLY_CORRECT");
+
+ /* Determine how to handle the ordering of options and nonoptions. */
+
+ if (optstring[0] == '-')
+ {
+ ordering = RETURN_IN_ORDER;
+ ++optstring;
+ }
+ else if (optstring[0] == '+')
+ {
+ ordering = REQUIRE_ORDER;
+ ++optstring;
+ }
+ else if (posixly_correct != NULL)
+ ordering = REQUIRE_ORDER;
+ else
+ ordering = PERMUTE;
+
+ return optstring;
+}
+
+/* Scan elements of ARGV (whose length is ARGC) for option characters
+ given in OPTSTRING.
+
+ If an element of ARGV starts with '-', and is not exactly "-" or "--",
+ then it is an option element. The characters of this element
+ (aside from the initial '-') are option characters. If `getopt'
+ is called repeatedly, it returns successively each of the option characters
+ from each of the option elements.
+
+ If `getopt' finds another option character, it returns that character,
+ updating `optind' and `nextchar' so that the next call to `getopt' can
+ resume the scan with the following option character or ARGV-element.
+
+ If there are no more option characters, `getopt' returns `EOF'.
+ Then `optind' is the index in ARGV of the first ARGV-element
+ that is not an option. (The ARGV-elements have been permuted
+ so that those that are not options now come last.)
+
+ OPTSTRING is a string containing the legitimate option characters.
+ If an option character is seen that is not listed in OPTSTRING,
+ return '?' after printing an error message. If you set `opterr' to
+ zero, the error message is suppressed but we still return '?'.
+
+ If a char in OPTSTRING is followed by a colon, that means it wants an arg,
+ so the following text in the same ARGV-element, or the text of the following
+ ARGV-element, is returned in `optarg'. Two colons mean an option that
+ wants an optional arg; if there is text in the current ARGV-element,
+ it is returned in `optarg', otherwise `optarg' is set to zero.
+
+ If OPTSTRING starts with `-' or `+', it requests different methods of
+ handling the non-option ARGV-elements.
+ See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above.
+
+ Long-named options begin with `--' instead of `-'.
+ Their names may be abbreviated as long as the abbreviation is unique
+ or is an exact match for some defined option. If they have an
+ argument, it follows the option name in the same ARGV-element, separated
+ from the option name by a `=', or else the in next ARGV-element.
+ When `getopt' finds a long-named option, it returns 0 if that option's
+ `flag' field is nonzero, the value of the option's `val' field
+ if the `flag' field is zero.
+
+ The elements of ARGV aren't really const, because we permute them.
+ But we pretend they're const in the prototype to be compatible
+ with other systems.
+
+ LONGOPTS is a vector of `struct option' terminated by an
+ element containing a name which is zero.
+
+ LONGIND returns the index in LONGOPT of the long-named option found.
+ It is only valid when a long-named option has been found by the most
+ recent call.
+
+ If LONG_ONLY is nonzero, '-' as well as '--' can introduce
+ long-named options. */
+
+int
+_getopt_internal (argc, argv, optstring, longopts, longind, long_only)
+ int argc;
+ char *const *argv;
+ const char *optstring;
+ const struct option *longopts;
+ int *longind;
+ int long_only;
+{
+ optarg = NULL;
+
+ if (optind == 0)
+ optstring = _getopt_initialize (optstring);
+
+ if (nextchar == NULL || *nextchar == '\0')
+ {
+ /* Advance to the next ARGV-element. */
+
+ if (ordering == PERMUTE)
+ {
+ /* If we have just processed some options following some non-options,
+ exchange them so that the options come first. */
+
+ if (first_nonopt != last_nonopt && last_nonopt != optind)
+ exchange ((char **) argv);
+ else if (last_nonopt != optind)
+ first_nonopt = optind;
+
+ /* Skip any additional non-options
+ and extend the range of non-options previously skipped. */
+
+ while (optind < argc
+ && (argv[optind][0] != '-' || argv[optind][1] == '\0'))
+ optind++;
+ last_nonopt = optind;
+ }
+
+ /* The special ARGV-element `--' means premature end of options.
+ Skip it like a null option,
+ then exchange with previous non-options as if it were an option,
+ then skip everything else like a non-option. */
+
+ if (optind != argc && !strcmp (argv[optind], "--"))
+ {
+ optind++;
+
+ if (first_nonopt != last_nonopt && last_nonopt != optind)
+ exchange ((char **) argv);
+ else if (first_nonopt == last_nonopt)
+ first_nonopt = optind;
+ last_nonopt = argc;
+
+ optind = argc;
+ }
+
+ /* If we have done all the ARGV-elements, stop the scan
+ and back over any non-options that we skipped and permuted. */
+
+ if (optind == argc)
+ {
+ /* Set the next-arg-index to point at the non-options
+ that we previously skipped, so the caller will digest them. */
+ if (first_nonopt != last_nonopt)
+ optind = first_nonopt;
+ return EOF;
+ }
+
+ /* If we have come to a non-option and did not permute it,
+ either stop the scan or describe it to the caller and pass it by. */
+
+ if ((argv[optind][0] != '-' || argv[optind][1] == '\0'))
+ {
+ if (ordering == REQUIRE_ORDER)
+ return EOF;
+ optarg = argv[optind++];
+ return 1;
+ }
+
+ /* We have found another option-ARGV-element.
+ Skip the initial punctuation. */
+
+ nextchar = (argv[optind] + 1
+ + (longopts != NULL && argv[optind][1] == '-'));
+ }
+
+ /* Decode the current option-ARGV-element. */
+
+ /* Check whether the ARGV-element is a long option.
+
+ If long_only and the ARGV-element has the form "-f", where f is
+ a valid short option, don't consider it an abbreviated form of
+ a long option that starts with f. Otherwise there would be no
+ way to give the -f short option.
+
+ On the other hand, if there's a long option "fubar" and
+ the ARGV-element is "-fu", do consider that an abbreviation of
+ the long option, just like "--fu", and not "-f" with arg "u".
+
+ This distinction seems to be the most useful approach. */
+
+ if (longopts != NULL
+ && (argv[optind][1] == '-'
+ || (long_only && (argv[optind][2] || !my_index (optstring, argv[optind][1])))))
+ {
+ char *nameend;
+ const struct option *p;
+ const struct option *pfound = NULL;
+ int exact = 0;
+ int ambig = 0;
+ int indfound;
+ int option_index;
+
+ for (nameend = nextchar; *nameend && *nameend != '='; nameend++)
+ /* Do nothing. */ ;
+
+ /* Test all long options for either exact match
+ or abbreviated matches. */
+ for (p = longopts, option_index = 0; p->name; p++, option_index++)
+ if (!strncmp (p->name, nextchar, nameend - nextchar))
+ {
+ if (nameend - nextchar == (int) strlen (p->name))
+ {
+ /* Exact match found. */
+ pfound = p;
+ indfound = option_index;
+ exact = 1;
+ break;
+ }
+ else if (pfound == NULL)
+ {
+ /* First nonexact match found. */
+ pfound = p;
+ indfound = option_index;
+ }
+ else
+ /* Second or later nonexact match found. */
+ ambig = 1;
+ }
+
+ if (ambig && !exact)
+ {
+ if (opterr)
+ fprintf (stderr, "%s: option `%s' is ambiguous\n",
+ argv[0], argv[optind]);
+ nextchar += strlen (nextchar);
+ optind++;
+ return '?';
+ }
+
+ if (pfound != NULL)
+ {
+ option_index = indfound;
+ optind++;
+ if (*nameend)
+ {
+ /* Don't test has_arg with >, because some C compilers don't
+ allow it to be used on enums. */
+ if (pfound->has_arg)
+ optarg = nameend + 1;
+ else
+ {
+ if (opterr)
+ {
+ if (argv[optind - 1][1] == '-')
+ /* --option */
+ fprintf (stderr,
+ "%s: option `--%s' doesn't allow an argument\n",
+ argv[0], pfound->name);
+ else
+ /* +option or -option */
+ fprintf (stderr,
+ "%s: option `%c%s' doesn't allow an argument\n",
+ argv[0], argv[optind - 1][0], pfound->name);
+ }
+ nextchar += strlen (nextchar);
+ return '?';
+ }
+ }
+ else if (pfound->has_arg == 1)
+ {
+ if (optind < argc)
+ optarg = argv[optind++];
+ else
+ {
+ if (opterr)
+ fprintf (stderr, "%s: option `%s' requires an argument\n",
+ argv[0], argv[optind - 1]);
+ nextchar += strlen (nextchar);
+ return optstring[0] == ':' ? ':' : '?';
+ }
+ }
+ nextchar += strlen (nextchar);
+ if (longind != NULL)
+ *longind = option_index;
+ if (pfound->flag)
+ {
+ *(pfound->flag) = pfound->val;
+ return 0;
+ }
+ return pfound->val;
+ }
+
+ /* Can't find it as a long option. If this is not getopt_long_only,
+ or the option starts with '--' or is not a valid short
+ option, then it's an error.
+ Otherwise interpret it as a short option. */
+ if (!long_only || argv[optind][1] == '-'
+ || my_index (optstring, *nextchar) == NULL)
+ {
+ if (opterr)
+ {
+ if (argv[optind][1] == '-')
+ /* --option */
+ fprintf (stderr, "%s: unrecognized option `--%s'\n",
+ argv[0], nextchar);
+ else
+ /* +option or -option */
+ fprintf (stderr, "%s: unrecognized option `%c%s'\n",
+ argv[0], argv[optind][0], nextchar);
+ }
+ nextchar = (char *) "";
+ optind++;
+ return '?';
+ }
+ }
+
+ /* Look at and handle the next short option-character. */
+
+ {
+ char c = *nextchar++;
+ char *temp = my_index (optstring, c);
+
+ /* Increment `optind' when we start to process its last character. */
+ if (*nextchar == '\0')
+ ++optind;
+
+ if (temp == NULL || c == ':')
+ {
+ if (opterr)
+ {
+ if (posixly_correct)
+ /* 1003.2 specifies the format of this message. */
+ fprintf (stderr, "%s: illegal option -- %c\n", argv[0], c);
+ else
+ fprintf (stderr, "%s: invalid option -- %c\n", argv[0], c);
+ }
+ optopt = c;
+ return '?';
+ }
+ if (temp[1] == ':')
+ {
+ if (temp[2] == ':')
+ {
+ /* This is an option that accepts an argument optionally. */
+ if (*nextchar != '\0')
+ {
+ optarg = nextchar;
+ optind++;
+ }
+ else
+ optarg = NULL;
+ nextchar = NULL;
+ }
+ else
+ {
+ /* This is an option that requires an argument. */
+ if (*nextchar != '\0')
+ {
+ optarg = nextchar;
+ /* If we end this ARGV-element by taking the rest as an arg,
+ we must advance to the next element now. */
+ optind++;
+ }
+ else if (optind == argc)
+ {
+ if (opterr)
+ {
+ /* 1003.2 specifies the format of this message. */
+ fprintf (stderr, "%s: option requires an argument -- %c\n",
+ argv[0], c);
+ }
+ optopt = c;
+ if (optstring[0] == ':')
+ c = ':';
+ else
+ c = '?';
+ }
+ else
+ /* We already incremented `optind' once;
+ increment it again when taking next ARGV-elt as argument. */
+ optarg = argv[optind++];
+ nextchar = NULL;
+ }
+ }
+ return c;
+ }
+}
+
+int
+getopt (argc, argv, optstring)
+ int argc;
+ char *const *argv;
+ const char *optstring;
+{
+ return _getopt_internal (argc, argv, optstring,
+ (const struct option *) 0,
+ (int *) 0,
+ 0);
+}
+
+#endif /* _LIBC or not __GNU_LIBRARY__. */
+
+#ifdef TEST
+
+/* Compile with -DTEST to make an executable for use in testing
+ the above definition of `getopt'. */
+
+int
+main (argc, argv)
+ int argc;
+ char **argv;
+{
+ int c;
+ int digit_optind = 0;
+
+ while (1)
+ {
+ int this_option_optind = optind ? optind : 1;
+
+ c = getopt (argc, argv, "abc:d:0123456789");
+ if (c == EOF)
+ break;
+
+ switch (c)
+ {
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ if (digit_optind != 0 && digit_optind != this_option_optind)
+ printf ("digits occur in two different argv-elements.\n");
+ digit_optind = this_option_optind;
+ printf ("option %c\n", c);
+ break;
+
+ case 'a':
+ printf ("option a\n");
+ break;
+
+ case 'b':
+ printf ("option b\n");
+ break;
+
+ case 'c':
+ printf ("option c with value `%s'\n", optarg);
+ break;
+
+ case '?':
+ break;
+
+ default:
+ printf ("?? getopt returned character code 0%o ??\n", c);
+ }
+ }
+
+ if (optind < argc)
+ {
+ printf ("non-option ARGV-elements: ");
+ while (optind < argc)
+ printf ("%s ", argv[optind++]);
+ printf ("\n");
+ }
+
+ exit (0);
+}
+
+#endif /* TEST */
diff --git a/gnu/usr.bin/cvs/lib/getopt.h b/gnu/usr.bin/cvs/lib/getopt.h
new file mode 100644
index 0000000..f644aa1
--- /dev/null
+++ b/gnu/usr.bin/cvs/lib/getopt.h
@@ -0,0 +1,131 @@
+/* Declarations for getopt.
+ Copyright (C) 1989, 1990, 1991, 1992, 1993 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any
+ later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* $CVSid: @(#)getopt.h 1.7 94/09/21 $ */
+
+#ifndef _GETOPT_H
+#define _GETOPT_H 1
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* For communication from `getopt' to the caller.
+ When `getopt' finds an option that takes an argument,
+ the argument value is returned here.
+ Also, when `ordering' is RETURN_IN_ORDER,
+ each non-option ARGV-element is returned here. */
+
+extern char *optarg;
+
+/* Index in ARGV of the next element to be scanned.
+ This is used for communication to and from the caller
+ and for communication between successive calls to `getopt'.
+
+ On entry to `getopt', zero means this is the first call; initialize.
+
+ When `getopt' returns EOF, this is the index of the first of the
+ non-option elements that the caller should itself scan.
+
+ Otherwise, `optind' communicates from one call to the next
+ how much of ARGV has been scanned so far. */
+
+extern int optind;
+
+/* Callers store zero here to inhibit the error message `getopt' prints
+ for unrecognized options. */
+
+extern int opterr;
+
+/* Set to an option character which was unrecognized. */
+
+extern int optopt;
+
+/* Describe the long-named options requested by the application.
+ The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector
+ of `struct option' terminated by an element containing a name which is
+ zero.
+
+ The field `has_arg' is:
+ no_argument (or 0) if the option does not take an argument,
+ required_argument (or 1) if the option requires an argument,
+ optional_argument (or 2) if the option takes an optional argument.
+
+ If the field `flag' is not NULL, it points to a variable that is set
+ to the value given in the field `val' when the option is found, but
+ left unchanged if the option is not found.
+
+ To have a long-named option do something other than set an `int' to
+ a compiled-in constant, such as set a value from `optarg', set the
+ option's `flag' field to zero and its `val' field to a nonzero
+ value (the equivalent single-letter option character, if there is
+ one). For long options that have a zero `flag' field, `getopt'
+ returns the contents of the `val' field. */
+
+struct option
+{
+#if __STDC__
+ const char *name;
+#else
+ char *name;
+#endif
+ /* has_arg can't be an enum because some compilers complain about
+ type mismatches in all the code that assumes it is an int. */
+ int has_arg;
+ int *flag;
+ int val;
+};
+
+/* Names for the values of the `has_arg' field of `struct option'. */
+
+#define no_argument 0
+#define required_argument 1
+#define optional_argument 2
+
+#if __STDC__
+#if defined(__GNU_LIBRARY__)
+/* Many other libraries have conflicting prototypes for getopt, with
+ differences in the consts, in stdlib.h. To avoid compilation
+ errors, only prototype getopt for the GNU C library. */
+extern int getopt (int argc, char *const *argv, const char *shortopts);
+#else /* not __GNU_LIBRARY__ */
+extern int getopt ();
+#endif /* not __GNU_LIBRARY__ */
+extern int getopt_long (int argc, char *const *argv, const char *shortopts,
+ const struct option *longopts, int *longind);
+extern int getopt_long_only (int argc, char *const *argv,
+ const char *shortopts,
+ const struct option *longopts, int *longind);
+
+/* Internal only. Users should not call this directly. */
+extern int _getopt_internal (int argc, char *const *argv,
+ const char *shortopts,
+ const struct option *longopts, int *longind,
+ int long_only);
+#else /* not __STDC__ */
+extern int getopt ();
+extern int getopt_long ();
+extern int getopt_long_only ();
+
+extern int _getopt_internal ();
+#endif /* not __STDC__ */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _GETOPT_H */
diff --git a/gnu/usr.bin/cvs/lib/getopt1.c b/gnu/usr.bin/cvs/lib/getopt1.c
new file mode 100644
index 0000000..f784b57
--- /dev/null
+++ b/gnu/usr.bin/cvs/lib/getopt1.c
@@ -0,0 +1,187 @@
+/* getopt_long and getopt_long_only entry points for GNU getopt.
+ Copyright (C) 1987, 88, 89, 90, 91, 92, 1993
+ Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any
+ later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#ifdef HAVE_CONFIG_H
+#if defined (emacs) || defined (CONFIG_BROKETS)
+/* We use <config.h> instead of "config.h" so that a compilation
+ using -I. -I$srcdir will use ./config.h rather than $srcdir/config.h
+ (which it would do because it found this file in $srcdir). */
+#include <config.h>
+#else
+#include "config.h"
+#endif
+#endif
+
+#include "getopt.h"
+
+#ifndef __STDC__
+/* This is a separate conditional since some stdc systems
+ reject `defined (const)'. */
+#ifndef const
+#define const
+#endif
+#endif
+
+#include <stdio.h>
+
+/* Comment out all this code if we are using the GNU C Library, and are not
+ actually compiling the library itself. This code is part of the GNU C
+ Library, but also included in many other GNU distributions. Compiling
+ and linking in this code is a waste when using the GNU C library
+ (especially if it is a shared library). Rather than having every GNU
+ program understand `configure --with-gnu-libc' and omit the object files,
+ it is simpler to just do this in the source for each such file. */
+
+#if defined (_LIBC) || !defined (__GNU_LIBRARY__)
+
+
+/* This needs to come after some library #include
+ to get __GNU_LIBRARY__ defined. */
+#ifdef __GNU_LIBRARY__
+#include <stdlib.h>
+#else
+char *getenv ();
+#endif
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+int
+getopt_long (argc, argv, options, long_options, opt_index)
+ int argc;
+ char *const *argv;
+ const char *options;
+ const struct option *long_options;
+ int *opt_index;
+{
+ return _getopt_internal (argc, argv, options, long_options, opt_index, 0);
+}
+
+/* Like getopt_long, but '-' as well as '--' can indicate a long option.
+ If an option that starts with '-' (not '--') doesn't match a long option,
+ but does match a short option, it is parsed as a short option
+ instead. */
+
+int
+getopt_long_only (argc, argv, options, long_options, opt_index)
+ int argc;
+ char *const *argv;
+ const char *options;
+ const struct option *long_options;
+ int *opt_index;
+{
+ return _getopt_internal (argc, argv, options, long_options, opt_index, 1);
+}
+
+
+#endif /* _LIBC or not __GNU_LIBRARY__. */
+
+#ifdef TEST
+
+#include <stdio.h>
+
+int
+main (argc, argv)
+ int argc;
+ char **argv;
+{
+ int c;
+ int digit_optind = 0;
+
+ while (1)
+ {
+ int this_option_optind = optind ? optind : 1;
+ int option_index = 0;
+ static struct option long_options[] =
+ {
+ {"add", 1, 0, 0},
+ {"append", 0, 0, 0},
+ {"delete", 1, 0, 0},
+ {"verbose", 0, 0, 0},
+ {"create", 0, 0, 0},
+ {"file", 1, 0, 0},
+ {0, 0, 0, 0}
+ };
+
+ c = getopt_long (argc, argv, "abc:d:0123456789",
+ long_options, &option_index);
+ if (c == EOF)
+ break;
+
+ switch (c)
+ {
+ case 0:
+ printf ("option %s", long_options[option_index].name);
+ if (optarg)
+ printf (" with arg %s", optarg);
+ printf ("\n");
+ break;
+
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ if (digit_optind != 0 && digit_optind != this_option_optind)
+ printf ("digits occur in two different argv-elements.\n");
+ digit_optind = this_option_optind;
+ printf ("option %c\n", c);
+ break;
+
+ case 'a':
+ printf ("option a\n");
+ break;
+
+ case 'b':
+ printf ("option b\n");
+ break;
+
+ case 'c':
+ printf ("option c with value `%s'\n", optarg);
+ break;
+
+ case 'd':
+ printf ("option d with value `%s'\n", optarg);
+ break;
+
+ case '?':
+ break;
+
+ default:
+ printf ("?? getopt returned character code 0%o ??\n", c);
+ }
+ }
+
+ if (optind < argc)
+ {
+ printf ("non-option ARGV-elements: ");
+ while (optind < argc)
+ printf ("%s ", argv[optind++]);
+ printf ("\n");
+ }
+
+ exit (0);
+}
+
+#endif /* TEST */
diff --git a/gnu/usr.bin/cvs/lib/hash.c b/gnu/usr.bin/cvs/lib/hash.c
new file mode 100644
index 0000000..8ac9323
--- /dev/null
+++ b/gnu/usr.bin/cvs/lib/hash.c
@@ -0,0 +1,400 @@
+/*
+ * Copyright (c) 1992, Brian Berliner and Jeff Polk
+ *
+ * You may distribute under the terms of the GNU General Public License as
+ * specified in the README file that comes with the CVS 1.4 kit.
+ *
+ * Polk's hash list manager. So cool.
+ */
+
+#include "cvs.h"
+
+#ifndef lint
+static const char rcsid[] = "$CVSid: @(#)hash.c 1.19 94/09/23 $";
+USE(rcsid);
+#endif
+
+/* global caches */
+static List *listcache = NULL;
+static Node *nodecache = NULL;
+
+static void freenode_mem PROTO((Node * p));
+
+/* hash function */
+static int
+hashp (key)
+ const char *key;
+{
+ unsigned int h = 0;
+ unsigned int g;
+
+ while (*key != 0)
+ {
+ h = (h << 4) + *key++;
+ if ((g = h & 0xf0000000) != 0)
+ h = (h ^ (g >> 24)) ^ g;
+ }
+
+ return (h % HASHSIZE);
+}
+
+/*
+ * create a new list (or get an old one from the cache)
+ */
+List *
+getlist ()
+{
+ int i;
+ List *list;
+ Node *node;
+
+ if (listcache != NULL)
+ {
+ /* get a list from the cache and clear it */
+ list = listcache;
+ listcache = listcache->next;
+ list->next = (List *) NULL;
+ for (i = 0; i < HASHSIZE; i++)
+ list->hasharray[i] = (Node *) NULL;
+ }
+ else
+ {
+ /* make a new list from scratch */
+ list = (List *) xmalloc (sizeof (List));
+ memset ((char *) list, 0, sizeof (List));
+ node = getnode ();
+ list->list = node;
+ node->type = HEADER;
+ node->next = node->prev = node;
+ }
+ return (list);
+}
+
+/*
+ * free up a list
+ */
+void
+dellist (listp)
+ List **listp;
+{
+ int i;
+ Node *p;
+
+ if (*listp == (List *) NULL)
+ return;
+
+ p = (*listp)->list;
+
+ /* free each node in the list (except header) */
+ while (p->next != p)
+ delnode (p->next);
+
+ /* free any list-private data, without freeing the actual header */
+ freenode_mem (p);
+
+ /* free up the header nodes for hash lists (if any) */
+ for (i = 0; i < HASHSIZE; i++)
+ {
+ if ((p = (*listp)->hasharray[i]) != (Node *) NULL)
+ {
+ /* put the nodes into the cache */
+ p->type = UNKNOWN;
+ p->next = nodecache;
+ nodecache = p;
+ }
+ }
+
+ /* put it on the cache */
+ (*listp)->next = listcache;
+ listcache = *listp;
+ *listp = (List *) NULL;
+}
+
+/*
+ * get a new list node
+ */
+Node *
+getnode ()
+{
+ Node *p;
+
+ if (nodecache != (Node *) NULL)
+ {
+ /* get one from the cache */
+ p = nodecache;
+ nodecache = p->next;
+ }
+ else
+ {
+ /* make a new one */
+ p = (Node *) xmalloc (sizeof (Node));
+ }
+
+ /* always make it clean */
+ memset ((char *) p, 0, sizeof (Node));
+ p->type = UNKNOWN;
+
+ return (p);
+}
+
+/*
+ * remove a node from it's list (maybe hash list too) and free it
+ */
+void
+delnode (p)
+ Node *p;
+{
+ if (p == (Node *) NULL)
+ return;
+
+ /* take it out of the list */
+ p->next->prev = p->prev;
+ p->prev->next = p->next;
+
+ /* if it was hashed, remove it from there too */
+ if (p->hashnext != (Node *) NULL)
+ {
+ p->hashnext->hashprev = p->hashprev;
+ p->hashprev->hashnext = p->hashnext;
+ }
+
+ /* free up the storage */
+ freenode (p);
+}
+
+/*
+ * free up the storage associated with a node
+ */
+static void
+freenode_mem (p)
+ Node *p;
+{
+ if (p->delproc != (void (*) ()) NULL)
+ p->delproc (p); /* call the specified delproc */
+ else
+ {
+ if (p->data != NULL) /* otherwise free() it if necessary */
+ free (p->data);
+ }
+ if (p->key != NULL) /* free the key if necessary */
+ free (p->key);
+
+ /* to be safe, re-initialize these */
+ p->key = p->data = (char *) NULL;
+ p->delproc = (void (*) ()) NULL;
+}
+
+/*
+ * free up the storage associated with a node and recycle it
+ */
+void
+freenode (p)
+ Node *p;
+{
+ /* first free the memory */
+ freenode_mem (p);
+
+ /* then put it in the cache */
+ p->type = UNKNOWN;
+ p->next = nodecache;
+ nodecache = p;
+}
+
+/*
+ * insert item p at end of list "list" (maybe hash it too) if hashing and it
+ * already exists, return -1 and don't actually put it in the list
+ *
+ * return 0 on success
+ */
+int
+addnode (list, p)
+ List *list;
+ Node *p;
+{
+ int hashval;
+ Node *q;
+
+ if (p->key != NULL) /* hash it too? */
+ {
+ hashval = hashp (p->key);
+ if (list->hasharray[hashval] == NULL) /* make a header for list? */
+ {
+ q = getnode ();
+ q->type = HEADER;
+ list->hasharray[hashval] = q->hashnext = q->hashprev = q;
+ }
+
+ /* put it into the hash list if it's not already there */
+ for (q = list->hasharray[hashval]->hashnext;
+ q != list->hasharray[hashval]; q = q->hashnext)
+ {
+ if (strcmp (p->key, q->key) == 0)
+ return (-1);
+ }
+ q = list->hasharray[hashval];
+ p->hashprev = q->hashprev;
+ p->hashnext = q;
+ p->hashprev->hashnext = p;
+ q->hashprev = p;
+ }
+
+ /* put it into the regular list */
+ p->prev = list->list->prev;
+ p->next = list->list;
+ list->list->prev->next = p;
+ list->list->prev = p;
+
+ return (0);
+}
+
+/*
+ * look up an entry in hash list table and return a pointer to the
+ * node. Return NULL on error or not found.
+ */
+Node *
+findnode (list, key)
+ List *list;
+ const char *key;
+{
+ Node *head, *p;
+
+ if (list == (List *) NULL)
+ return ((Node *) NULL);
+
+ head = list->hasharray[hashp (key)];
+ if (head == (Node *) NULL)
+ return ((Node *) NULL);
+
+ for (p = head->hashnext; p != head; p = p->hashnext)
+ if (strcmp (p->key, key) == 0)
+ return (p);
+ return ((Node *) NULL);
+}
+
+/*
+ * walk a list with a specific proc
+ */
+int
+walklist (list, proc, closure)
+ List *list;
+ int (*proc) PROTO ((Node *, void *));
+ void *closure;
+{
+ Node *head, *p;
+ int err = 0;
+
+ if (list == NULL)
+ return (0);
+
+ head = list->list;
+ for (p = head->next; p != head; p = p->next)
+ err += proc (p, closure);
+ return (err);
+}
+
+/*
+ * sort the elements of a list (in place)
+ */
+void
+sortlist (list, comp)
+ List *list;
+ int (*comp) PROTO ((const Node *, const Node *));
+{
+ Node *head, *remain, *p, *q;
+
+ /* save the old first element of the list */
+ head = list->list;
+ remain = head->next;
+
+ /* make the header node into a null list of it's own */
+ head->next = head->prev = head;
+
+ /* while there are nodes remaining, do insert sort */
+ while (remain != head)
+ {
+ /* take one from the list */
+ p = remain;
+ remain = remain->next;
+
+ /* traverse the sorted list looking for the place to insert it */
+ for (q = head->next; q != head; q = q->next)
+ {
+ if (comp (p, q) < 0)
+ {
+ /* p comes before q */
+ p->next = q;
+ p->prev = q->prev;
+ p->prev->next = p;
+ q->prev = p;
+ break;
+ }
+ }
+ if (q == head)
+ {
+ /* it belongs at the end of the list */
+ p->next = head;
+ p->prev = head->prev;
+ p->prev->next = p;
+ head->prev = p;
+ }
+ }
+}
+
+/* Debugging functions. Quite useful to call from within gdb. */
+
+char *
+nodetypestring (type)
+ Ntype type;
+{
+ switch (type) {
+ case UNKNOWN: return("UNKNOWN");
+ case HEADER: return("HEADER");
+ case ENTRIES: return("ENTRIES");
+ case FILES: return("FILES");
+ case LIST: return("LIST");
+ case RCSNODE: return("RCSNODE");
+ case RCSVERS: return("RCSVERS");
+ case DIRS: return("DIRS");
+ case UPDATE: return("UPDATE");
+ case LOCK: return("LOCK");
+ case NDBMNODE: return("NDBMNODE");
+ }
+
+ return("<trash>");
+}
+
+static int printnode PROTO ((Node *, void *));
+static int
+printnode (node, closure)
+ Node *node;
+ void *closure;
+{
+ if (node == NULL)
+ {
+ (void) printf("NULL node.\n");
+ return(0);
+ }
+
+ (void) printf("Node at 0x%p: type = %s, key = 0x%p = \"%s\", data = 0x%p, next = 0x%p, prev = 0x%p\n",
+ node, nodetypestring(node->type), node->key, node->key, node->data, node->next, node->prev);
+
+ return(0);
+}
+
+void
+printlist (list)
+ List *list;
+{
+ if (list == NULL)
+ {
+ (void) printf("NULL list.\n");
+ return;
+ }
+
+ (void) printf("List at 0x%p: list = 0x%p, HASHSIZE = %d, next = 0x%p\n",
+ list, list->list, HASHSIZE, list->next);
+
+ (void) walklist(list, printnode, NULL);
+
+ return;
+}
diff --git a/gnu/usr.bin/cvs/lib/hash.h b/gnu/usr.bin/cvs/lib/hash.h
new file mode 100644
index 0000000..e30511a
--- /dev/null
+++ b/gnu/usr.bin/cvs/lib/hash.h
@@ -0,0 +1,55 @@
+/* $CVSid: @(#)hash.h 1.23 94/10/07 $ */
+
+/*
+ * Copyright (c) 1992, Brian Berliner and Jeff Polk
+ *
+ * You may distribute under the terms of the GNU General Public License as
+ * specified in the README file that comes with the CVS 1.4 kit.
+ */
+
+/*
+ * The number of buckets for the hash table contained in each list. This
+ * should probably be prime.
+ */
+#define HASHSIZE 151
+
+/*
+ * Types of nodes
+ */
+enum ntype
+{
+ UNKNOWN, HEADER, ENTRIES, FILES, LIST, RCSNODE,
+ RCSVERS, DIRS, UPDATE, LOCK, NDBMNODE
+};
+typedef enum ntype Ntype;
+
+struct node
+{
+ Ntype type;
+ struct node *next;
+ struct node *prev;
+ struct node *hashnext;
+ struct node *hashprev;
+ char *key;
+ char *data;
+ void (*delproc) ();
+};
+typedef struct node Node;
+
+struct list
+{
+ Node *list;
+ Node *hasharray[HASHSIZE];
+ struct list *next;
+};
+typedef struct list List;
+
+List *getlist PROTO((void));
+Node *findnode PROTO((List * list, const char *key));
+Node *getnode PROTO((void));
+int addnode PROTO((List * list, Node * p));
+int walklist PROTO((List * list, int (*)(Node *n, void *closure), void *closure));
+void dellist PROTO((List ** listp));
+void delnode PROTO((Node * p));
+void freenode PROTO((Node * p));
+void sortlist PROTO((List * list, int (*)(const Node *, const Node *)));
diff --git a/gnu/usr.bin/cvs/lib/myndbm.c b/gnu/usr.bin/cvs/lib/myndbm.c
new file mode 100644
index 0000000..fef3265
--- /dev/null
+++ b/gnu/usr.bin/cvs/lib/myndbm.c
@@ -0,0 +1,213 @@
+/*
+ * Copyright (c) 1992, Brian Berliner
+ *
+ * You may distribute under the terms of the GNU General Public License as
+ * specified in the README file that comes with the CVS 1.4 kit.
+ *
+ * A simple ndbm-emulator for CVS. It parses a text file of the format:
+ *
+ * key value
+ *
+ * at dbm_open time, and loads the entire file into memory. As such, it is
+ * probably only good for fairly small modules files. Ours is about 30K in
+ * size, and this code works fine.
+ */
+
+#include "cvs.h"
+
+#ifdef MY_NDBM
+
+#ifndef lint
+static const char rcsid[] = "$CVSid: @(#)myndbm.c 1.7 94/09/23 $";
+USE(rcsid);
+#endif
+
+static void mydbm_load_file ();
+
+/* ARGSUSED */
+DBM *
+mydbm_open (file, flags, mode)
+ char *file;
+ int flags;
+ int mode;
+{
+ FILE *fp;
+ DBM *db;
+
+ if ((fp = fopen (file, "r")) == NULL)
+ return ((DBM *) 0);
+
+ db = (DBM *) xmalloc (sizeof (*db));
+ db->dbm_list = getlist ();
+
+ mydbm_load_file (fp, db->dbm_list);
+ (void) fclose (fp);
+ return (db);
+}
+
+void
+mydbm_close (db)
+ DBM *db;
+{
+ dellist (&db->dbm_list);
+ free ((char *) db);
+}
+
+datum
+mydbm_fetch (db, key)
+ DBM *db;
+ datum key;
+{
+ Node *p;
+ char *s;
+ datum val;
+
+ /* make sure it's null-terminated */
+ s = xmalloc (key.dsize + 1);
+ (void) strncpy (s, key.dptr, key.dsize);
+ s[key.dsize] = '\0';
+
+ p = findnode (db->dbm_list, s);
+ if (p)
+ {
+ val.dptr = p->data;
+ val.dsize = strlen (p->data);
+ }
+ else
+ {
+ val.dptr = (char *) NULL;
+ val.dsize = 0;
+ }
+ free (s);
+ return (val);
+}
+
+datum
+mydbm_firstkey (db)
+ DBM *db;
+{
+ Node *head, *p;
+ datum key;
+
+ head = db->dbm_list->list;
+ p = head->next;
+ if (p != head)
+ {
+ key.dptr = p->key;
+ key.dsize = strlen (p->key);
+ }
+ else
+ {
+ key.dptr = (char *) NULL;
+ key.dsize = 0;
+ }
+ db->dbm_next = p->next;
+ return (key);
+}
+
+datum
+mydbm_nextkey (db)
+ DBM *db;
+{
+ Node *head, *p;
+ datum key;
+
+ head = db->dbm_list->list;
+ p = db->dbm_next;
+ if (p != head)
+ {
+ key.dptr = p->key;
+ key.dsize = strlen (p->key);
+ }
+ else
+ {
+ key.dptr = (char *) NULL;
+ key.dsize = 0;
+ }
+ db->dbm_next = p->next;
+ return (key);
+}
+
+static void
+mydbm_load_file (fp, list)
+ FILE *fp;
+ List *list;
+{
+ char line[MAXLINELEN], value[MAXLINELEN];
+ char *cp, *vp;
+ int len, cont;
+
+ for (cont = 0; fgets (line, sizeof (line), fp) != NULL;)
+ {
+ if ((cp = strrchr (line, '\n')) != NULL)
+ *cp = '\0'; /* strip the newline */
+
+ /*
+ * Add the line to the value, at the end if this is a continuation
+ * line; otherwise at the beginning, but only after any trailing
+ * backslash is removed.
+ */
+ vp = value;
+ if (cont)
+ vp += strlen (value);
+
+ /*
+ * See if the line we read is a continuation line, and strip the
+ * backslash if so.
+ */
+ len = strlen (line);
+ if (len > 0)
+ cp = &line[len - 1];
+ else
+ cp = line;
+ if (*cp == '\\')
+ {
+ cont = 1;
+ *cp = '\0';
+ }
+ else
+ {
+ cont = 0;
+ }
+ (void) strcpy (vp, line);
+ if (value[0] == '#')
+ continue; /* comment line */
+ vp = value;
+ while (*vp && isspace (*vp))
+ vp++;
+ if (*vp == '\0')
+ continue; /* empty line */
+
+ /*
+ * If this was not a continuation line, add the entry to the database
+ */
+ if (!cont)
+ {
+ Node *p = getnode ();
+ char *kp;
+
+ kp = vp;
+ while (*vp && !isspace (*vp))
+ vp++;
+ *vp++ = '\0'; /* NULL terminate the key */
+ p->type = NDBMNODE;
+ p->key = xstrdup (kp);
+ while (*vp && isspace (*vp))
+ vp++; /* skip whitespace to value */
+ if (*vp == '\0')
+ {
+ error (0, 0, "warning: NULL value for key `%s'", p->key);
+ freenode (p);
+ continue;
+ }
+ p->data = xstrdup (vp);
+ if (addnode (list, p) == -1)
+ {
+ error (0, 0, "duplicate key found for `%s'", p->key);
+ freenode (p);
+ }
+ }
+ }
+}
+
+#endif /* MY_NDBM */
diff --git a/gnu/usr.bin/cvs/lib/myndbm.h b/gnu/usr.bin/cvs/lib/myndbm.h
new file mode 100644
index 0000000..3af31305
--- /dev/null
+++ b/gnu/usr.bin/cvs/lib/myndbm.h
@@ -0,0 +1,36 @@
+/* $CVSid: @(#)myndbm.h 1.4 94/09/21 $ */
+
+#ifdef MY_NDBM
+
+#define DBLKSIZ 4096
+
+typedef struct
+{
+ List *dbm_list; /* cached database */
+ Node *dbm_next; /* next key to return for nextkey() */
+} DBM;
+
+typedef struct
+{
+ char *dptr;
+ int dsize;
+} datum;
+
+/*
+ * So as not to conflict with other dbm_open, etc., routines that may
+ * be included by someone's libc, all of my emulation routines are prefixed
+ * by "my" and we define the "standard" ones to be "my" ones here.
+ */
+#define dbm_open mydbm_open
+#define dbm_close mydbm_close
+#define dbm_fetch mydbm_fetch
+#define dbm_firstkey mydbm_firstkey
+#define dbm_nextkey mydbm_nextkey
+
+DBM *mydbm_open PROTO((char *file, int flags, int mode));
+void mydbm_close PROTO((DBM * db));
+datum mydbm_fetch PROTO((DBM * db, datum key));
+datum mydbm_firstkey PROTO((DBM * db));
+datum mydbm_nextkey PROTO((DBM * db));
+
+#endif /* MY_NDBM */
diff --git a/gnu/usr.bin/cvs/lib/run.c b/gnu/usr.bin/cvs/lib/run.c
new file mode 100644
index 0000000..6a06a38
--- /dev/null
+++ b/gnu/usr.bin/cvs/lib/run.c
@@ -0,0 +1,533 @@
+/* run.c --- routines for executing subprocesses.
+
+ This file is part of GNU CVS.
+
+ GNU CVS is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any
+ later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "cvs.h"
+
+#ifdef HAVE_VPRINTF
+#if defined (USE_PROTOTYPES) ? USE_PROTOTYPES : defined (__STDC__)
+#include <stdarg.h>
+#define VA_START(args, lastarg) va_start(args, lastarg)
+#else
+#include <varargs.h>
+#define VA_START(args, lastarg) va_start(args)
+#endif
+#else
+#define va_alist a1, a2, a3, a4, a5, a6, a7, a8
+#define va_dcl char *a1, *a2, *a3, *a4, *a5, *a6, *a7, *a8;
+#endif
+
+static void run_add_arg PROTO((const char *s));
+static void run_init_prog PROTO((void));
+
+extern char *strtok ();
+
+/*
+ * To exec a program under CVS, first call run_setup() to setup any initial
+ * arguments. The options to run_setup are essentially like printf(). The
+ * arguments will be parsed into whitespace separated words and added to the
+ * global run_argv list.
+ *
+ * Then, optionally call run_arg() for each additional argument that you'd like
+ * to pass to the executed program.
+ *
+ * Finally, call run_exec() to execute the program with the specified arguments.
+ * The execvp() syscall will be used, so that the PATH is searched correctly.
+ * File redirections can be performed in the call to run_exec().
+ */
+static char *run_prog;
+static char **run_argv;
+static int run_argc;
+static int run_argc_allocated;
+
+/* VARARGS */
+#if defined (HAVE_VPRINTF) && (defined (USE_PROTOTYPES) ? USE_PROTOTYPES : defined (__STDC__))
+void
+run_setup (const char *fmt,...)
+#else
+void
+run_setup (fmt, va_alist)
+ char *fmt;
+ va_dcl
+#endif
+{
+#ifdef HAVE_VPRINTF
+ va_list args;
+#endif
+ char *cp;
+ int i;
+
+ run_init_prog ();
+
+ /* clean out any malloc'ed values from run_argv */
+ for (i = 0; i < run_argc; i++)
+ {
+ if (run_argv[i])
+ {
+ free (run_argv[i]);
+ run_argv[i] = (char *) 0;
+ }
+ }
+ run_argc = 0;
+
+ /* process the varargs into run_prog */
+#ifdef HAVE_VPRINTF
+ VA_START (args, fmt);
+ (void) vsprintf (run_prog, fmt, args);
+ va_end (args);
+#else
+ (void) sprintf (run_prog, fmt, a1, a2, a3, a4, a5, a6, a7, a8);
+#endif
+
+ /* put each word into run_argv, allocating it as we go */
+ for (cp = strtok (run_prog, " \t"); cp; cp = strtok ((char *) NULL, " \t"))
+ run_add_arg (cp);
+}
+
+void
+run_arg (s)
+ const char *s;
+{
+ run_add_arg (s);
+}
+
+/* VARARGS */
+#if defined (HAVE_VPRINTF) && (defined (USE_PROTOTYPES) ? USE_PROTOTYPES : defined (__STDC__))
+void
+run_args (const char *fmt,...)
+#else
+void
+run_args (fmt, va_alist)
+ char *fmt;
+ va_dcl
+#endif
+{
+#ifdef HAVE_VPRINTF
+ va_list args;
+#endif
+
+ run_init_prog ();
+
+ /* process the varargs into run_prog */
+#ifdef HAVE_VPRINTF
+ VA_START (args, fmt);
+ (void) vsprintf (run_prog, fmt, args);
+ va_end (args);
+#else
+ (void) sprintf (run_prog, fmt, a1, a2, a3, a4, a5, a6, a7, a8);
+#endif
+
+ /* and add the (single) argument to the run_argv list */
+ run_add_arg (run_prog);
+}
+
+static void
+run_add_arg (s)
+ const char *s;
+{
+ /* allocate more argv entries if we've run out */
+ if (run_argc >= run_argc_allocated)
+ {
+ run_argc_allocated += 50;
+ run_argv = (char **) xrealloc ((char *) run_argv,
+ run_argc_allocated * sizeof (char **));
+ }
+
+ if (s)
+ run_argv[run_argc++] = xstrdup (s);
+ else
+ run_argv[run_argc] = (char *) 0; /* not post-incremented on purpose! */
+}
+
+static void
+run_init_prog ()
+{
+ /* make sure that run_prog is allocated once */
+ if (run_prog == (char *) 0)
+ run_prog = xmalloc (10 * 1024); /* 10K of args for _setup and _arg */
+}
+
+int
+run_exec (stin, stout, sterr, flags)
+ char *stin;
+ char *stout;
+ char *sterr;
+ int flags;
+{
+ int shin, shout, sherr;
+ int mode_out, mode_err;
+ int status;
+ int rc = -1;
+ int rerrno = 0;
+ int pid, w;
+
+#ifdef POSIX_SIGNALS
+ sigset_t sigset_mask, sigset_omask;
+ struct sigaction act, iact, qact;
+
+#else
+#ifdef BSD_SIGNALS
+ int mask;
+ struct sigvec vec, ivec, qvec;
+
+#else
+ RETSIGTYPE (*istat) (), (*qstat) ();
+#endif
+#endif
+
+ if (trace)
+ {
+#ifdef SERVER_SUPPORT
+ (void) fprintf (stderr, "%c-> system(", (server_active) ? 'S' : ' ');
+#else
+ (void) fprintf (stderr, "-> system(");
+#endif
+ run_print (stderr);
+ (void) fprintf (stderr, ")\n");
+ }
+ if (noexec && (flags & RUN_REALLY) == 0)
+ return (0);
+
+ /* make sure that we are null terminated, since we didn't calloc */
+ run_add_arg ((char *) 0);
+
+ /* setup default file descriptor numbers */
+ shin = 0;
+ shout = 1;
+ sherr = 2;
+
+ /* set the file modes for stdout and stderr */
+ mode_out = mode_err = O_WRONLY | O_CREAT;
+ mode_out |= ((flags & RUN_STDOUT_APPEND) ? O_APPEND : O_TRUNC);
+ mode_err |= ((flags & RUN_STDERR_APPEND) ? O_APPEND : O_TRUNC);
+
+ if (stin && (shin = open (stin, O_RDONLY)) == -1)
+ {
+ rerrno = errno;
+ error (0, errno, "cannot open %s for reading (prog %s)",
+ stin, run_argv[0]);
+ goto out0;
+ }
+ if (stout && (shout = open (stout, mode_out, 0666)) == -1)
+ {
+ rerrno = errno;
+ error (0, errno, "cannot open %s for writing (prog %s)",
+ stout, run_argv[0]);
+ goto out1;
+ }
+ if (sterr && (flags & RUN_COMBINED) == 0)
+ {
+ if ((sherr = open (sterr, mode_err, 0666)) == -1)
+ {
+ rerrno = errno;
+ error (0, errno, "cannot open %s for writing (prog %s)",
+ sterr, run_argv[0]);
+ goto out2;
+ }
+ }
+
+ /* Make sure we don't flush this twice, once in the subprocess. */
+ fflush (stdout);
+ fflush (stderr);
+
+ /* The output files, if any, are now created. Do the fork and dups */
+#ifdef HAVE_VFORK
+ pid = vfork ();
+#else
+ pid = fork ();
+#endif
+ if (pid == 0)
+ {
+ if (shin != 0)
+ {
+ (void) dup2 (shin, 0);
+ (void) close (shin);
+ }
+ if (shout != 1)
+ {
+ (void) dup2 (shout, 1);
+ (void) close (shout);
+ }
+ if (flags & RUN_COMBINED)
+ (void) dup2 (1, 2);
+ else if (sherr != 2)
+ {
+ (void) dup2 (sherr, 2);
+ (void) close (sherr);
+ }
+
+ /* dup'ing is done. try to run it now */
+ (void) execvp (run_argv[0], run_argv);
+ error (0, errno, "cannot exec %s", run_argv[0]);
+ _exit (127);
+ }
+ else if (pid == -1)
+ {
+ rerrno = errno;
+ goto out;
+ }
+
+ /* the parent. Ignore some signals for now */
+#ifdef POSIX_SIGNALS
+ if (flags & RUN_SIGIGNORE)
+ {
+ act.sa_handler = SIG_IGN;
+ (void) sigemptyset (&act.sa_mask);
+ act.sa_flags = 0;
+ (void) sigaction (SIGINT, &act, &iact);
+ (void) sigaction (SIGQUIT, &act, &qact);
+ }
+ else
+ {
+ (void) sigemptyset (&sigset_mask);
+ (void) sigaddset (&sigset_mask, SIGINT);
+ (void) sigaddset (&sigset_mask, SIGQUIT);
+ (void) sigprocmask (SIG_SETMASK, &sigset_mask, &sigset_omask);
+ }
+#else
+#ifdef BSD_SIGNALS
+ if (flags & RUN_SIGIGNORE)
+ {
+ memset ((char *) &vec, 0, sizeof (vec));
+ vec.sv_handler = SIG_IGN;
+ (void) sigvec (SIGINT, &vec, &ivec);
+ (void) sigvec (SIGQUIT, &vec, &qvec);
+ }
+ else
+ mask = sigblock (sigmask (SIGINT) | sigmask (SIGQUIT));
+#else
+ istat = signal (SIGINT, SIG_IGN);
+ qstat = signal (SIGQUIT, SIG_IGN);
+#endif
+#endif
+
+ /* wait for our process to die and munge return status */
+#ifdef POSIX_SIGNALS
+ while ((w = waitpid (pid, &status, 0)) == -1 && errno == EINTR)
+ ;
+#else
+ while ((w = wait (&status)) != pid)
+ {
+ if (w == -1 && errno != EINTR)
+ break;
+ }
+#endif
+ if (w == -1)
+ {
+ rc = -1;
+ rerrno = errno;
+ }
+ else if (WIFEXITED (status))
+ rc = WEXITSTATUS (status);
+ else if (WIFSIGNALED (status))
+ {
+ if (WTERMSIG (status) == SIGPIPE)
+ error (1, 0, "broken pipe");
+ rc = 2;
+ }
+ else
+ rc = 1;
+
+ /* restore the signals */
+#ifdef POSIX_SIGNALS
+ if (flags & RUN_SIGIGNORE)
+ {
+ (void) sigaction (SIGINT, &iact, (struct sigaction *) NULL);
+ (void) sigaction (SIGQUIT, &qact, (struct sigaction *) NULL);
+ }
+ else
+ (void) sigprocmask (SIG_SETMASK, &sigset_omask, (sigset_t *) NULL);
+#else
+#ifdef BSD_SIGNALS
+ if (flags & RUN_SIGIGNORE)
+ {
+ (void) sigvec (SIGINT, &ivec, (struct sigvec *) NULL);
+ (void) sigvec (SIGQUIT, &qvec, (struct sigvec *) NULL);
+ }
+ else
+ (void) sigsetmask (mask);
+#else
+ (void) signal (SIGINT, istat);
+ (void) signal (SIGQUIT, qstat);
+#endif
+#endif
+
+ /* cleanup the open file descriptors */
+ out:
+ if (sterr)
+ (void) close (sherr);
+ out2:
+ if (stout)
+ (void) close (shout);
+ out1:
+ if (stin)
+ (void) close (shin);
+
+ out0:
+ if (rerrno)
+ errno = rerrno;
+ return (rc);
+}
+
+void
+run_print (fp)
+ FILE *fp;
+{
+ int i;
+
+ for (i = 0; i < run_argc; i++)
+ {
+ (void) fprintf (fp, "'%s'", run_argv[i]);
+ if (i != run_argc - 1)
+ (void) fprintf (fp, " ");
+ }
+}
+
+FILE *
+Popen (cmd, mode)
+ const char *cmd;
+ const char *mode;
+{
+ if (trace)
+#ifdef SERVER_SUPPORT
+ (void) fprintf (stderr, "%c-> Popen(%s,%s)\n",
+ (server_active) ? 'S' : ' ', cmd, mode);
+#else
+ (void) fprintf (stderr, "-> Popen(%s,%s)\n", cmd, mode);
+#endif
+ if (noexec)
+ return (NULL);
+
+ return (popen (cmd, mode));
+}
+
+extern int evecvp PROTO((char *file, char **argv));
+
+int
+piped_child (command, tofdp, fromfdp)
+ char **command;
+ int *tofdp;
+ int *fromfdp;
+{
+ int pid;
+ int to_child_pipe[2];
+ int from_child_pipe[2];
+
+ if (pipe (to_child_pipe) < 0)
+ error (1, errno, "cannot create pipe");
+ if (pipe (from_child_pipe) < 0)
+ error (1, errno, "cannot create pipe");
+
+ pid = fork ();
+ if (pid < 0)
+ error (1, errno, "cannot fork");
+ if (pid == 0)
+ {
+ if (dup2 (to_child_pipe[0], STDIN_FILENO) < 0)
+ error (1, errno, "cannot dup2");
+ if (close (to_child_pipe[1]) < 0)
+ error (1, errno, "cannot close");
+ if (close (from_child_pipe[0]) < 0)
+ error (1, errno, "cannot close");
+ if (dup2 (from_child_pipe[1], STDOUT_FILENO) < 0)
+ error (1, errno, "cannot dup2");
+
+ execvp (command[0], command);
+ error (1, errno, "cannot exec");
+ }
+ if (close (to_child_pipe[0]) < 0)
+ error (1, errno, "cannot close");
+ if (close (from_child_pipe[1]) < 0)
+ error (1, errno, "cannot close");
+
+ *tofdp = to_child_pipe[1];
+ *fromfdp = from_child_pipe[0];
+ return pid;
+}
+
+
+void
+close_on_exec (fd)
+ int fd;
+{
+#if defined (FD_CLOEXEC) && defined (F_SETFD)
+ if (fcntl (fd, F_SETFD, 1))
+ error (1, errno, "can't set close-on-exec flag on %d", fd);
+#endif
+}
+
+/*
+ * dir = 0 : main proc writes to new proc, which writes to oldfd
+ * dir = 1 : main proc reads from new proc, which reads from oldfd
+ */
+
+int
+filter_stream_through_program (oldfd, dir, prog, pidp)
+ int oldfd, dir;
+ char **prog;
+ pid_t *pidp;
+{
+ int p[2], newfd;
+ pid_t newpid;
+
+ if (pipe (p))
+ error (1, errno, "cannot create pipe");
+ newpid = fork ();
+ if (pidp)
+ *pidp = newpid;
+ switch (newpid)
+ {
+ case -1:
+ error (1, errno, "cannot fork");
+ case 0:
+ /* child */
+ if (dir)
+ {
+ /* write to new pipe */
+ close (p[0]);
+ dup2 (oldfd, 0);
+ dup2 (p[1], 1);
+ }
+ else
+ {
+ /* read from new pipe */
+ close (p[1]);
+ dup2 (p[0], 0);
+ dup2 (oldfd, 1);
+ }
+ /* Should I be blocking some signals here? */
+ execvp (prog[0], prog);
+ error (1, errno, "couldn't exec %s", prog[0]);
+ default:
+ /* parent */
+ close (oldfd);
+ if (dir)
+ {
+ /* read from new pipe */
+ close (p[1]);
+ newfd = p[0];
+ }
+ else
+ {
+ /* write to new pipe */
+ close (p[0]);
+ newfd = p[1];
+ }
+ close_on_exec (newfd);
+ return newfd;
+ }
+}
diff --git a/gnu/usr.bin/cvs/lib/save-cwd.c b/gnu/usr.bin/cvs/lib/save-cwd.c
new file mode 100644
index 0000000..1bdf791
--- /dev/null
+++ b/gnu/usr.bin/cvs/lib/save-cwd.c
@@ -0,0 +1,141 @@
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <stdio.h>
+
+#ifdef STDC_HEADERS
+# include <stdlib.h>
+#endif
+
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+#ifdef HAVE_FCNTL_H
+# include <fcntl.h>
+#else
+# include <sys/file.h>
+#endif
+
+#ifdef HAVE_DIRECT_H
+# include <direct.h>
+#endif
+
+#ifdef HAVE_IO_H
+# include <io.h>
+#endif
+
+#include <errno.h>
+# ifndef errno
+extern int errno;
+#endif
+
+#include "save-cwd.h"
+#include "error.h"
+
+char *xgetwd __PROTO((void));
+
+/* Record the location of the current working directory in CWD so that
+ the program may change to other directories and later use restore_cwd
+ to return to the recorded location. This function may allocate
+ space using malloc (via xgetwd) or leave a file descriptor open;
+ use free_cwd to perform the necessary free or close. Upon failure,
+ no memory is allocated, any locally opened file descriptors are
+ closed; return non-zero -- in that case, free_cwd need not be
+ called, but doing so is ok. Otherwise, return zero. */
+
+int
+save_cwd (cwd)
+ struct saved_cwd *cwd;
+{
+ static int have_working_fchdir = 1;
+
+ cwd->desc = -1;
+ cwd->name = NULL;
+
+ if (have_working_fchdir)
+ {
+#ifdef HAVE_FCHDIR
+ cwd->desc = open (".", O_RDONLY);
+ if (cwd->desc < 0)
+ {
+ error (0, errno, "cannot open current directory");
+ return 1;
+ }
+
+# if __sun__ || sun
+ /* On SunOS 4, fchdir returns EINVAL if accounting is enabled,
+ so we have to fall back to chdir. */
+ if (fchdir (cwd->desc))
+ {
+ if (errno == EINVAL)
+ {
+ close (cwd->desc);
+ cwd->desc = -1;
+ have_working_fchdir = 0;
+ }
+ else
+ {
+ error (0, errno, "current directory");
+ close (cwd->desc);
+ cwd->desc = -1;
+ return 1;
+ }
+ }
+# endif /* __sun__ || sun */
+#else
+#define fchdir(x) (abort (), 0)
+ have_working_fchdir = 0;
+#endif
+ }
+
+ if (!have_working_fchdir)
+ {
+ cwd->name = xgetwd ();
+ if (cwd->name == NULL)
+ {
+ error (0, errno, "cannot get current directory");
+ return 1;
+ }
+ }
+ return 0;
+}
+
+/* Change to recorded location, CWD, in directory hierarchy.
+ If "saved working directory", NULL))
+ */
+
+int
+restore_cwd (cwd, dest)
+ const struct saved_cwd *cwd;
+ const char *dest;
+{
+ int fail = 0;
+ if (cwd->desc >= 0)
+ {
+ if (fchdir (cwd->desc))
+ {
+ error (0, errno, "cannot return to %s",
+ (dest ? dest : "saved working directory"));
+ fail = 1;
+ }
+ }
+ else if (chdir (cwd->name) < 0)
+ {
+ error (0, errno, "%s", cwd->name);
+ fail = 1;
+ }
+ return fail;
+}
+
+void
+free_cwd (cwd)
+ struct saved_cwd *cwd;
+{
+ if (cwd->desc >= 0)
+ close (cwd->desc);
+ if (cwd->name)
+ free (cwd->name);
+}
+
diff --git a/gnu/usr.bin/cvs/lib/save-cwd.h b/gnu/usr.bin/cvs/lib/save-cwd.h
new file mode 100644
index 0000000..f9802f8
--- /dev/null
+++ b/gnu/usr.bin/cvs/lib/save-cwd.h
@@ -0,0 +1,20 @@
+#ifndef SAVE_CWD_H
+#define SAVE_CWD_H 1
+
+struct saved_cwd
+ {
+ int desc;
+ char *name;
+ };
+
+#if defined (__GNUC__) || (defined (__STDC__) && __STDC__)
+#define __PROTO(args) args
+#else
+#define __PROTO(args) ()
+#endif /* GCC. */
+
+int save_cwd __PROTO((struct saved_cwd *cwd));
+int restore_cwd __PROTO((const struct saved_cwd *cwd, const char *dest));
+void free_cwd __PROTO((struct saved_cwd *cwd));
+
+#endif /* SAVE_CWD_H */
diff --git a/gnu/usr.bin/cvs/lib/sighandle.c b/gnu/usr.bin/cvs/lib/sighandle.c
new file mode 100644
index 0000000..a225983
--- /dev/null
+++ b/gnu/usr.bin/cvs/lib/sighandle.c
@@ -0,0 +1,405 @@
+/* sighandle.c -- Library routines for manipulating chains of signal handlers
+ Copyright (C) 1992 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* Written by Paul Sander, HaL Computer Systems, Inc. <paul@hal.com>
+ Brian Berliner <berliner@Sun.COM> added POSIX support */
+
+/*************************************************************************
+ *
+ * signal.c -- This file contains code that manipulates chains of signal
+ * handlers.
+ *
+ * Facilities are provided to register a signal handler for
+ * any specific signal. When a signal is received, all of the
+ * registered signal handlers are invoked in the reverse order
+ * in which they are registered. Note that the signal handlers
+ * must not themselves make calls to the signal handling
+ * facilities.
+ *
+ * $CVSid: @(#)sighandle.c 1.13 94/10/07 $
+ *
+ *************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include "system.h"
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <signal.h>
+
+#ifdef STDC_HEADERS
+#include <stdlib.h>
+#else
+#if __STDC__
+char *calloc(unsigned nelem, unsigned size);
+char *malloc(unsigned size);
+#else
+char *calloc();
+char *malloc();
+#endif /* __STDC__ */
+#endif /* STDC_HEADERS */
+
+/* Define the highest signal number (usually) */
+#ifndef SIGMAX
+#define SIGMAX 64
+#endif
+
+/* Define linked list of signal handlers structure */
+struct SIG_hlist {
+ RETSIGTYPE (*handler)();
+ struct SIG_hlist *next;
+};
+
+/*
+ * Define array of lists of signal handlers. Note that this depends on
+ * the implementation to initialize each element to a null pointer.
+ */
+
+static struct SIG_hlist **SIG_handlers;
+
+/* Define array of default signal vectors */
+
+#ifdef POSIX_SIGNALS
+static struct sigaction *SIG_defaults;
+#else
+#ifdef BSD_SIGNALS
+static struct sigvec *SIG_defaults;
+#else
+static RETSIGTYPE (**SIG_defaults)();
+#endif
+#endif
+
+/* Critical section housekeeping */
+static int SIG_crSectNest = 0; /* Nesting level */
+#ifdef POSIX_SIGNALS
+static sigset_t SIG_crSectMask; /* Signal mask */
+#else
+static int SIG_crSectMask; /* Signal mask */
+#endif
+
+/*
+ * Initialize the signal handler arrays
+ */
+
+static int SIG_init()
+{
+ int i;
+#ifdef POSIX_SIGNALS
+ sigset_t sigset_test;
+#endif
+
+ if (SIG_defaults && SIG_handlers) /* already allocated */
+ return (0);
+
+#ifdef POSIX_SIGNALS
+ (void) sigfillset(&sigset_test);
+ for (i = 1; i < SIGMAX && sigismember(&sigset_test, i) == 1; i++)
+ ;
+ if (i < SIGMAX)
+ i = SIGMAX;
+ i++;
+ if (!SIG_defaults)
+ SIG_defaults = (struct sigaction *)
+ calloc(i, sizeof(struct sigaction));
+ (void) sigemptyset(&SIG_crSectMask);
+#else
+ i = SIGMAX+1;
+#ifdef BSD_SIGNALS
+ if (!SIG_defaults)
+ SIG_defaults = (struct sigvec *)
+ calloc(i, sizeof(struct sigvec));
+#else
+ if (!SIG_defaults)
+ SIG_defaults = (RETSIGTYPE (**)())
+ calloc(i, sizeof(RETSIGTYPE (**)()));
+#endif
+ SIG_crSectMask = 0;
+#endif
+ if (!SIG_handlers)
+ SIG_handlers = (struct SIG_hlist **)
+ calloc(i, sizeof(struct SIG_hlist *));
+ return (!SIG_defaults || !SIG_handlers);
+}
+
+/*
+ * The following invokes each signal handler in the reverse order in which
+ * they were registered.
+ */
+
+static RETSIGTYPE SIG_handle(sig)
+int sig;
+{
+ struct SIG_hlist *this;
+
+ /* Dispatch signal handlers */
+ this = SIG_handlers[sig];
+ while (this != (struct SIG_hlist *) NULL)
+ {
+ (*this->handler)(sig);
+ this = this->next;
+ }
+
+ return;
+}
+
+/*
+ * The following registers a signal handler. If the handler is already
+ * registered, it is not registered twice, nor is the order in which signal
+ * handlers are invoked changed. If this is the first signal handler
+ * registered for a given signal, the old sigvec structure is saved for
+ * restoration later.
+ */
+
+int SIG_register(sig,fn)
+int sig;
+RETSIGTYPE (*fn)();
+{
+ int val;
+ struct SIG_hlist *this;
+#ifdef POSIX_SIGNALS
+ struct sigaction act;
+ sigset_t sigset_mask, sigset_omask;
+#else
+#ifdef BSD_SIGNALS
+ struct sigvec vec;
+ int mask;
+#endif
+#endif
+
+ /* Initialize */
+ if (SIG_init() != 0)
+ return (-1);
+ val = 0;
+
+ /* Block this signal while we look at handler chain */
+#ifdef POSIX_SIGNALS
+ (void) sigemptyset(&sigset_mask);
+ (void) sigaddset(&sigset_mask, sig);
+ (void) sigprocmask(SIG_BLOCK, &sigset_mask, &sigset_omask);
+#else
+#ifdef BSD_SIGNALS
+ mask = sigblock(sigmask(sig));
+#endif
+#endif
+
+ /* See if this handler was already registered */
+ this = SIG_handlers[sig];
+ while (this != (struct SIG_hlist *) NULL)
+ {
+ if (this->handler == fn) break;
+ this = this->next;
+ }
+
+ /* Register the new handler only if it is not already registered. */
+ if (this == (struct SIG_hlist *) NULL)
+ {
+
+ /*
+ * If this is the first handler registered for this signal,
+ * set up the signal handler dispatcher
+ */
+
+ if (SIG_handlers[sig] == (struct SIG_hlist *) NULL)
+ {
+#ifdef POSIX_SIGNALS
+ act.sa_handler = SIG_handle;
+ (void) sigemptyset(&act.sa_mask);
+ act.sa_flags = 0;
+ val = sigaction(sig, &act, &SIG_defaults[sig]);
+#else
+#ifdef BSD_SIGNALS
+ bzero((char *)&vec, sizeof(vec));
+ vec.sv_handler = SIG_handle;
+ val = sigvec(sig, &vec, &SIG_defaults[sig]);
+#else
+ if ((SIG_defaults[sig] = signal(sig, SIG_handle)) ==
+ (RETSIGTYPE (*)()) -1)
+ val = -1;
+#endif
+#endif
+ }
+
+ /* If not, register it */
+ if ((val == 0) && (this == (struct SIG_hlist *) NULL))
+ {
+ this = (struct SIG_hlist *)
+ malloc(sizeof(struct SIG_hlist));
+ if (this == NULL)
+ {
+ val = -1;
+ }
+ else
+ {
+ this->handler = fn;
+ this->next = SIG_handlers[sig];
+ SIG_handlers[sig] = this;
+ }
+ }
+ }
+
+ /* Unblock the signal */
+#ifdef POSIX_SIGNALS
+ (void) sigprocmask(SIG_SETMASK, &sigset_omask, NULL);
+#else
+#ifdef BSD_SIGNALS
+ (void) sigsetmask(mask);
+#endif
+#endif
+
+ return val;
+}
+
+/*
+ * The following deregisters a signal handler. If the last signal handler for
+ * a given signal is deregistered, the default sigvec information is restored.
+ */
+
+int SIG_deregister(sig,fn)
+int sig;
+RETSIGTYPE (*fn)();
+{
+ int val;
+ struct SIG_hlist *this;
+ struct SIG_hlist *last;
+#ifdef POSIX_SIGNALS
+ sigset_t sigset_mask, sigset_omask;
+#else
+#ifdef BSD_SIGNALS
+ int mask;
+#endif
+#endif
+
+ /* Initialize */
+ if (SIG_init() != 0)
+ return (-1);
+ val = 0;
+ last = (struct SIG_hlist *) NULL;
+
+ /* Block this signal while we look at handler chain */
+#ifdef POSIX_SIGNALS
+ (void) sigemptyset(&sigset_mask);
+ (void) sigaddset(&sigset_mask, sig);
+ (void) sigprocmask(SIG_BLOCK, &sigset_mask, &sigset_omask);
+#else
+#ifdef BSD_SIGNALS
+ mask = sigblock(sigmask(sig));
+#endif
+#endif
+
+ /* Search for the signal handler */
+ this = SIG_handlers[sig];
+ while ((this != (struct SIG_hlist *) NULL) && (this->handler != fn))
+ {
+ last = this;
+ this = this->next;
+ }
+
+ /* If it was registered, remove it */
+ if (this != (struct SIG_hlist *) NULL)
+ {
+ if (last == (struct SIG_hlist *) NULL)
+ {
+ SIG_handlers[sig] = this->next;
+ }
+ else
+ {
+ last->next = this->next;
+ }
+ free((char *) this);
+ }
+
+ /* Restore default behavior if there are no registered handlers */
+ if (SIG_handlers[sig] == (struct SIG_hlist *) NULL)
+ {
+#ifdef POSIX_SIGNALS
+ val = sigaction(sig, &SIG_defaults[sig],
+ (struct sigaction *) NULL);
+#else
+#ifdef BSD_SIGNALS
+ val = sigvec(sig, &SIG_defaults[sig], (struct sigvec *) NULL);
+#else
+ if (signal(sig, SIG_defaults[sig]) == (RETSIGTYPE (*)()) -1)
+ val = -1;
+#endif
+#endif
+ }
+
+ /* Unblock the signal */
+#ifdef POSIX_SIGNALS
+ (void) sigprocmask(SIG_SETMASK, &sigset_omask, NULL);
+#else
+#ifdef BSD_SIGNALS
+ (void) sigsetmask(mask);
+#endif
+#endif
+
+ return val;
+}
+
+/*
+ * The following begins a critical section.
+ */
+
+void SIG_beginCrSect()
+{
+ if (SIG_init() == 0)
+ {
+ if (SIG_crSectNest == 0)
+ {
+#ifdef POSIX_SIGNALS
+ sigset_t sigset_mask;
+
+ (void) sigfillset(&sigset_mask);
+ (void) sigprocmask(SIG_SETMASK,
+ &sigset_mask, &SIG_crSectMask);
+#else
+#ifdef BSD_SIGNALS
+ SIG_crSectMask = sigblock(~0);
+#else
+ /* TBD */
+#endif
+#endif
+ }
+ SIG_crSectNest++;
+ }
+}
+
+/*
+ * The following ends a critical section.
+ */
+
+void SIG_endCrSect()
+{
+ if (SIG_init() == 0)
+ {
+ SIG_crSectNest--;
+ if (SIG_crSectNest == 0)
+ {
+#ifdef POSIX_SIGNALS
+ (void) sigprocmask(SIG_SETMASK, &SIG_crSectMask, NULL);
+#else
+#ifdef BSD_SIGNALS
+ (void) sigsetmask(SIG_crSectMask);
+#else
+ /* TBD */
+#endif
+#endif
+ }
+ }
+}
diff --git a/gnu/usr.bin/cvs/lib/strippath.c b/gnu/usr.bin/cvs/lib/strippath.c
new file mode 100644
index 0000000..39687f9
--- /dev/null
+++ b/gnu/usr.bin/cvs/lib/strippath.c
@@ -0,0 +1,80 @@
+/* strippath.c -- remove unnecessary components from a path specifier
+ Copyright (C) 1992 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#if STDC_HEADERS || HAVE_STRING_H
+#include <string.h>
+/* An ANSI string.h and pre-ANSI memory.h might conflict. */
+#if !STDC_HEADERS && HAVE_MEMORY_H
+#include <memory.h>
+#endif /* not STDC_HEADERS and HAVE_MEMORY_H */
+#else /* not STDC_HJEADERS and not HAVE_STRING_H */
+#include <strings.h>
+/* memory.h and strings.h conflict on some systems. */
+#endif /* not STDC_HEADERS and not HAVE_STRING_H */
+
+#include <stdio.h>
+
+#if __STDC__
+static void remove_component(char *beginc, char *endc);
+void strip_trailing_slashes(char *path);
+#else
+static void remove_component();
+void strip_trailing_slashes();
+#endif /* __STDC__ */
+
+/* Remove unnecessary components from PATH. */
+
+void
+strip_path (path)
+ char *path;
+{
+ int stripped = 0;
+ char *cp, *slash;
+
+ for (cp = path; (slash = strchr(cp, '/')) != NULL; cp = slash)
+ {
+ *slash = '\0';
+ if ((!*cp && (cp != path || stripped)) ||
+ strcmp(cp, ".") == 0 || strcmp(cp, "/") == 0)
+ {
+ stripped = 1;
+ remove_component(cp, slash);
+ slash = cp;
+ }
+ else
+ {
+ *slash++ = '/';
+ }
+ }
+ strip_trailing_slashes(path);
+}
+
+/* Remove the component delimited by BEGINC and ENDC from the path */
+
+static void
+remove_component (beginc, endc)
+ char *beginc;
+ char *endc;
+{
+ for (endc++; *endc; endc++)
+ *beginc++ = *endc;
+ *beginc = '\0';
+}
diff --git a/gnu/usr.bin/cvs/lib/stripslash.c b/gnu/usr.bin/cvs/lib/stripslash.c
new file mode 100644
index 0000000..265950e
--- /dev/null
+++ b/gnu/usr.bin/cvs/lib/stripslash.c
@@ -0,0 +1,44 @@
+/* stripslash.c -- remove trailing slashes from a string
+ Copyright (C) 1990 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#if STDC_HEADERS || HAVE_STRING_H
+#include <string.h>
+/* An ANSI string.h and pre-ANSI memory.h might conflict. */
+#if !STDC_HEADERS && HAVE_MEMORY_H
+#include <memory.h>
+#endif /* not STDC_HEADERS and HAVE_MEMORY_H */
+#else /* not STDC_HJEADERS and not HAVE_STRING_H */
+#include <strings.h>
+/* memory.h and strings.h conflict on some systems. */
+#endif /* not STDC_HEADERS and not HAVE_STRING_H */
+
+/* Remove trailing slashes from PATH. */
+
+void
+strip_trailing_slashes (path)
+ char *path;
+{
+ int last;
+
+ last = strlen (path) - 1;
+ while (last > 0 && path[last] == '/')
+ path[last--] = '\0';
+}
diff --git a/gnu/usr.bin/cvs/lib/subr.c b/gnu/usr.bin/cvs/lib/subr.c
new file mode 100644
index 0000000..228581c
--- /dev/null
+++ b/gnu/usr.bin/cvs/lib/subr.c
@@ -0,0 +1,322 @@
+/*
+ * Copyright (c) 1992, Brian Berliner and Jeff Polk
+ * Copyright (c) 1989-1992, Brian Berliner
+ *
+ * You may distribute under the terms of the GNU General Public License as
+ * specified in the README file that comes with the CVS 1.4 kit.
+ *
+ * Various useful functions for the CVS support code.
+ */
+
+#include "cvs.h"
+
+#ifndef lint
+static const char rcsid[] = "$CVSid: @(#)subr.c 1.64 94/10/07 $";
+USE(rcsid);
+#endif
+
+extern char *getlogin ();
+
+/*
+ * malloc some data and die if it fails
+ */
+char *
+xmalloc (bytes)
+ size_t bytes;
+{
+ char *cp;
+
+ /* Parts of CVS try to xmalloc zero bytes and then free it. Some
+ systems have a malloc which returns NULL for zero byte
+ allocations but a free which can't handle NULL, so compensate. */
+ if (bytes == 0)
+ bytes = 1;
+
+ cp = malloc (bytes);
+ if (cp == NULL)
+ error (1, 0, "can not allocate %lu bytes", (unsigned long) bytes);
+ return (cp);
+}
+
+/*
+ * realloc data and die if it fails [I've always wanted to have "realloc" do
+ * a "malloc" if the argument is NULL, but you can't depend on it. Here, I
+ * can *force* it.
+ */
+char *
+xrealloc (ptr, bytes)
+ char *ptr;
+ size_t bytes;
+{
+ char *cp;
+
+ if (!ptr)
+ cp = malloc (bytes);
+ else
+ cp = realloc (ptr, bytes);
+
+ if (cp == NULL)
+ error (1, 0, "can not reallocate %lu bytes", (unsigned long) bytes);
+ return (cp);
+}
+
+/*
+ * Duplicate a string, calling xmalloc to allocate some dynamic space
+ */
+char *
+xstrdup (str)
+ const char *str;
+{
+ char *s;
+
+ if (str == NULL)
+ return ((char *) NULL);
+ s = xmalloc (strlen (str) + 1);
+ (void) strcpy (s, str);
+ return (s);
+}
+
+/* Remove trailing newlines from STRING, destructively. */
+void
+strip_trailing_newlines (str)
+ char *str;
+{
+ int len;
+ len = strlen (str) - 1;
+
+ while (str[len] == '\n')
+ str[len--] = '\0';
+}
+
+/*
+ * Recover the space allocated by Find_Names() and line2argv()
+ */
+void
+free_names (pargc, argv)
+ int *pargc;
+ char **argv;
+{
+ register int i;
+
+ for (i = 0; i < *pargc; i++)
+ { /* only do through *pargc */
+ free (argv[i]);
+ }
+ *pargc = 0; /* and set it to zero when done */
+}
+
+/*
+ * Convert a line into argc/argv components and return the result in the
+ * arguments as passed. Use free_names() to return the memory allocated here
+ * back to the free pool.
+ */
+void
+line2argv (pargc, argv, line)
+ int *pargc;
+ char **argv;
+ char *line;
+{
+ char *cp;
+
+ *pargc = 0;
+ for (cp = strtok (line, " \t"); cp; cp = strtok ((char *) NULL, " \t"))
+ {
+ argv[*pargc] = xstrdup (cp);
+ (*pargc)++;
+ }
+}
+
+/*
+ * Returns the number of dots ('.') found in an RCS revision number
+ */
+int
+numdots (s)
+ const char *s;
+{
+ int dots = 0;
+
+ for (; *s; s++)
+ {
+ if (*s == '.')
+ dots++;
+ }
+ return (dots);
+}
+
+/*
+ * Get the caller's login from his uid. If the real uid is "root" try LOGNAME
+ * USER or getlogin(). If getlogin() and getpwuid() both fail, return
+ * the uid as a string.
+ */
+char *
+getcaller ()
+{
+ static char uidname[20];
+ struct passwd *pw;
+ char *name;
+ uid_t uid;
+
+ uid = getuid ();
+ if (uid == (uid_t) 0)
+ {
+ /* super-user; try getlogin() to distinguish */
+ if (((name = getlogin ()) || (name = getenv("LOGNAME")) ||
+ (name = getenv("USER"))) && *name)
+ return (name);
+ }
+ if ((pw = (struct passwd *) getpwuid (uid)) == NULL)
+ {
+ (void) sprintf (uidname, "uid%lu", (unsigned long) uid);
+ return (uidname);
+ }
+ return (pw->pw_name);
+}
+
+#ifdef lint
+#ifndef __GNUC__
+/* ARGSUSED */
+time_t
+get_date (date, now)
+ char *date;
+ struct timeb *now;
+{
+ time_t foo = 0;
+
+ return (foo);
+}
+#endif
+#endif
+
+/* Given two revisions, find their greatest common ancestor. If the
+ two input revisions exist, then rcs guarantees that the gca will
+ exist. */
+
+char *
+gca (rev1, rev2)
+ char *rev1;
+ char *rev2;
+{
+ int dots;
+ char gca[PATH_MAX];
+ char *p[2];
+ int j[2];
+
+ if (rev1 == NULL || rev2 == NULL)
+ {
+ error (0, 0, "sanity failure in gca");
+ abort();
+ }
+
+ /* walk the strings, reading the common parts. */
+ gca[0] = '\0';
+ p[0] = rev1;
+ p[1] = rev2;
+ do
+ {
+ int i;
+ char c[2];
+ char *s[2];
+
+ for (i = 0; i < 2; ++i)
+ {
+ /* swap out the dot */
+ s[i] = strchr (p[i], '.');
+ if (s[i] != NULL) {
+ c[i] = *s[i];
+ }
+
+ /* read an int */
+ j[i] = atoi (p[i]);
+
+ /* swap back the dot... */
+ if (s[i] != NULL) {
+ *s[i] = c[i];
+ p[i] = s[i] + 1;
+ }
+ else
+ {
+ /* or mark us at the end */
+ p[i] = NULL;
+ }
+
+ }
+
+ /* use the lowest. */
+ (void) sprintf (gca + strlen (gca), "%d.",
+ j[0] < j[1] ? j[0] : j[1]);
+
+ } while (j[0] == j[1]
+ && p[0] != NULL
+ && p[1] != NULL);
+
+ /* back up over that last dot. */
+ gca[strlen(gca) - 1] = '\0';
+
+ /* numbers differ, or we ran out of strings. we're done with the
+ common parts. */
+
+ dots = numdots (gca);
+ if (dots == 0)
+ {
+ /* revisions differ in trunk major number. */
+
+ char *q;
+ char *s;
+
+ s = (j[0] < j[1]) ? p[0] : p[1];
+
+ if (s == NULL)
+ {
+ /* we only got one number. this is strange. */
+ error (0, 0, "bad revisions %s or %s", rev1, rev2);
+ abort();
+ }
+ else
+ {
+ /* we have a minor number. use it. */
+ q = gca + strlen (gca);
+
+ *q++ = '.';
+ for ( ; *s != '.' && *s != '\0'; )
+ *q++ = *s++;
+
+ *q = '\0';
+ }
+ }
+ else if ((dots & 1) == 0)
+ {
+ /* if we have an even number of dots, then we have a branch.
+ remove the last number in order to make it a revision. */
+
+ char *s;
+
+ s = strrchr(gca, '.');
+ *s = '\0';
+ }
+
+ return (xstrdup (gca));
+}
+
+/*
+ * Sanity checks and any required fix-up on message passed to RCS via '-m'.
+ * RCS 5.7 requires that a non-total-whitespace, non-null message be provided
+ * with '-m'.
+ */
+char *
+make_message_rcslegal (message)
+ char *message;
+{
+ if ((message == NULL) || (*message == '\0') || isspace (*message))
+ {
+ char *t;
+
+ if (message)
+ for (t = message; *t; t++)
+ if (!isspace (*t))
+ return message;
+
+ return "*** empty log message ***\n";
+ }
+
+ return message;
+}
diff --git a/gnu/usr.bin/cvs/lib/system.h b/gnu/usr.bin/cvs/lib/system.h
new file mode 100644
index 0000000..20539de
--- /dev/null
+++ b/gnu/usr.bin/cvs/lib/system.h
@@ -0,0 +1,496 @@
+/* system-dependent definitions for CVS.
+ Copyright (C) 1989-1992 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* $CVSid: @(#)system.h 1.18 94/09/25 $ */
+
+#ifdef __GNUC__
+#ifndef alloca
+#define alloca __builtin_alloca
+#endif
+#else
+#ifdef HAVE_ALLOCA_H
+#include <alloca.h>
+#else
+#ifdef _AIX
+/* AIX alloca decl has to be the first thing in the file, bletch! */
+ #pragma alloca
+#else /* not _AIX */
+#ifdef ALLOCA_IN_STDLIB
+ /* then we need do nothing */
+#else
+char *alloca ();
+#endif /* not ALLOCA_IN_STDLIB */
+#endif /* not _AIX */
+#endif /* not HAVE_ALLOCA_H */
+#endif /* not __GNUS__ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#ifdef STAT_MACROS_BROKEN
+#undef S_ISBLK
+#undef S_ISCHR
+#undef S_ISDIR
+#undef S_ISREG
+#undef S_ISFIFO
+#undef S_ISLNK
+#undef S_ISSOCK
+#undef S_ISMPB
+#undef S_ISMPC
+#undef S_ISNWK
+#endif
+
+/* Not all systems have S_IFMT, but we probably want to use it if we
+ do. See ChangeLog for a more detailed discussion. */
+
+#if !defined(S_ISBLK) && defined(S_IFBLK)
+# if defined(S_IFMT)
+# define S_ISBLK(m) (((m) & S_IFMT) == S_IFBLK)
+# else
+# define S_ISBLK(m) ((m) & S_IFBLK)
+# endif
+#endif
+
+#if !defined(S_ISCHR) && defined(S_IFCHR)
+# if defined(S_IFMT)
+# define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR)
+# else
+# define S_ISCHR(m) ((m) & S_IFCHR)
+# endif
+#endif
+
+#if !defined(S_ISDIR) && defined(S_IFDIR)
+# if defined(S_IFMT)
+# define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
+# else
+# define S_ISDIR(m) ((m) & S_IFDIR)
+# endif
+#endif
+
+#if !defined(S_ISREG) && defined(S_IFREG)
+# if defined(S_IFMT)
+# define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
+# else
+# define S_ISREG(m) ((m) & S_IFREG)
+# endif
+#endif
+
+#if !defined(S_ISFIFO) && defined(S_IFIFO)
+# if defined(S_IFMT)
+# define S_ISFIFO(m) (((m) & S_IFMT) == S_IFIFO)
+# else
+# define S_ISFIFO(m) ((m) & S_IFIFO)
+# endif
+#endif
+
+#if !defined(S_ISLNK) && defined(S_IFLNK)
+# if defined(S_IFMT)
+# define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK)
+# else
+# define S_ISLNK(m) ((m) & S_IFLNK)
+# endif
+#endif
+
+#if !defined(S_ISSOCK) && defined(S_IFSOCK)
+# if defined(S_IFMT)
+# define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK)
+# else
+# define S_ISSOCK(m) ((m) & S_IFSOCK)
+# endif
+#endif
+
+#if !defined(S_ISMPB) && defined(S_IFMPB) /* V7 */
+# if defined(S_IFMT)
+# define S_ISMPB(m) (((m) & S_IFMT) == S_IFMPB)
+# define S_ISMPC(m) (((m) & S_IFMT) == S_IFMPC)
+# else
+# define S_ISMPB(m) ((m) & S_IFMPB)
+# define S_ISMPC(m) ((m) & S_IFMPC)
+# endif
+#endif
+
+#if !defined(S_ISNWK) && defined(S_IFNWK) /* HP/UX */
+# if defined(S_IFMT)
+# define S_ISNWK(m) (((m) & S_IFMT) == S_IFNWK)
+# else
+# define S_ISNWK(m) ((m) & S_IFNWK)
+# endif
+#endif
+
+#if !defined(HAVE_MKFIFO)
+#define mkfifo(path, mode) (mknod ((path), (mode) | S_IFIFO, 0))
+#endif
+
+#ifdef NEED_DECOY_PERMISSIONS /* OS/2, really */
+
+#define S_IRUSR S_IREAD
+#define S_IWUSR S_IWRITE
+#define S_IXUSR S_IEXEC
+#define S_IRWXU (S_IRUSR | S_IWUSR | S_IXUSR)
+#define S_IRGRP S_IREAD
+#define S_IWGRP S_IWRITE
+#define S_IXGRP S_IEXEC
+#define S_IRWXG (S_IRGRP | S_IWGRP | S_IXGRP)
+#define S_IROTH S_IREAD
+#define S_IWOTH S_IWRITE
+#define S_IXOTH S_IEXEC
+#define S_IRWXO (S_IROTH | S_IWOTH | S_IXOTH)
+
+#else /* ! NEED_DECOY_PERMISSIONS */
+
+#ifndef S_IRUSR
+#define S_IRUSR 0400
+#define S_IWUSR 0200
+#define S_IXUSR 0100
+/* Read, write, and execute by owner. */
+#define S_IRWXU (S_IRUSR|S_IWUSR|S_IXUSR)
+
+#define S_IRGRP (S_IRUSR >> 3) /* Read by group. */
+#define S_IWGRP (S_IWUSR >> 3) /* Write by group. */
+#define S_IXGRP (S_IXUSR >> 3) /* Execute by group. */
+/* Read, write, and execute by group. */
+#define S_IRWXG (S_IRWXU >> 3)
+
+#define S_IROTH (S_IRGRP >> 3) /* Read by others. */
+#define S_IWOTH (S_IWGRP >> 3) /* Write by others. */
+#define S_IXOTH (S_IXGRP >> 3) /* Execute by others. */
+/* Read, write, and execute by others. */
+#define S_IRWXO (S_IRWXG >> 3)
+#endif /* !def S_IRUSR */
+#endif /* NEED_DECOY_PERMISSIONS */
+
+#if defined(POSIX) || defined(HAVE_UNISTD_H)
+#include <unistd.h>
+#include <limits.h>
+#else
+off_t lseek ();
+#endif
+
+#if TIME_WITH_SYS_TIME
+# include <sys/time.h>
+# include <time.h>
+#else
+# if HAVE_SYS_TIME_H
+# include <sys/time.h>
+# else
+# include <time.h>
+# endif
+#endif
+
+#ifdef HAVE_IO_H
+#include <io.h>
+#endif
+
+#ifdef HAVE_DIRECT_H
+#include <direct.h>
+#endif
+
+#ifdef timezone
+#undef timezone /* needed for sgi */
+#endif
+
+#ifdef HAVE_SYS_TIMEB_H
+#include <sys/timeb.h>
+#else
+struct timeb {
+ time_t time; /* Seconds since the epoch */
+ unsigned short millitm; /* Field not used */
+ short timezone;
+ short dstflag; /* Field not used */
+};
+#endif
+
+#if !defined(HAVE_FTIME) && !defined(HAVE_TIMEZONE)
+#if !defined(timezone)
+extern long timezone;
+#endif
+#endif
+
+
+/*
+** MAXPATHLEN and PATH_MAX
+**
+** On most systems MAXPATHLEN is defined in sys/param.h to be 1024. Of
+** those that this is not true, again most define PATH_MAX in limits.h
+** or sys/limits.h which usually gets included by limits.h. On the few
+** remaining systems that neither statement is true, _POSIX_PATH_MAX
+** is defined.
+**
+** So:
+** 1. If PATH_MAX is defined just use it.
+** 2. If MAXPATHLEN is defined but not PATH_MAX, then define
+** PATH_MAX in terms of MAXPATHLEN.
+** 3. If neither is defined, include limits.h and check for
+** PATH_MAX again.
+** 3.1 If we now have PATHSIZE, define PATH_MAX in terms of that.
+** and ignore the rest. Since _POSIX_PATH_MAX (checked for
+** next) is the *most* restrictive (smallest) value, if we
+** trust _POSIX_PATH_MAX, several of our buffers are too small.
+** 4. If PATH_MAX is still not defined but _POSIX_PATH_MAX is,
+** then define PATH_MAX in terms of _POSIX_PATH_MAX.
+** 5. And if even _POSIX_PATH_MAX doesn't exist just put in
+** a reasonable value.
+** *. All in all, this is an excellent argument for using pathconf()
+** when at all possible. Or better yet, dynamically allocate
+** our buffers and use getcwd() not getwd().
+**
+** This works on:
+** Sun Sparc 10 SunOS 4.1.3 & Solaris 1.2
+** HP 9000/700 HP/UX 8.07 & HP/UX 9.01
+** Tektronix XD88/10 UTekV 3.2e
+** IBM RS6000 AIX 3.2
+** Dec Alpha OSF 1 ????
+** Intel 386 BSDI BSD/386
+** Intel 386 SCO OpenServer Release 5
+** Apollo Domain 10.4
+** NEC SVR4
+*/
+
+/* On MOST systems this will get you MAXPATHLEN.
+ Windows NT doesn't have this file, tho. */
+#ifdef HAVE_SYS_PARAM_H
+#include <sys/param.h>
+#endif
+
+#ifndef PATH_MAX
+# ifdef MAXPATHLEN
+# define PATH_MAX MAXPATHLEN
+# else
+# include <limits.h>
+# ifndef PATH_MAX
+# ifdef PATHSIZE
+# define PATH_MAX PATHSIZE
+# else /* no PATHSIZE */
+# ifdef _POSIX_PATH_MAX
+# define PATH_MAX _POSIX_PATH_MAX
+# else
+# define PATH_MAX 1024
+# endif /* no _POSIX_PATH_MAX */
+# endif /* no PATHSIZE */
+# endif /* no PATH_MAX */
+# endif /* MAXPATHLEN */
+#endif /* PATH_MAX */
+
+
+/* The NeXT (without _POSIX_SOURCE, which we don't want) has a utime.h
+ which doesn't define anything. It would be cleaner to have configure
+ check for struct utimbuf, but for now I'm checking NeXT here (so I don't
+ have to debug the configure check across all the machines). */
+#if defined (HAVE_UTIME_H) && !defined (NeXT)
+#include <utime.h>
+#elif defined (HAVE_SYS_UTIME_H)
+# include <sys/utime.h>
+#else
+#ifndef ALTOS
+struct utimbuf
+{
+ long actime;
+ long modtime;
+};
+#endif
+int utime ();
+#endif
+
+#if STDC_HEADERS || HAVE_STRING_H
+#include <string.h>
+/* An ANSI string.h and pre-ANSI memory.h might conflict. */
+#if !STDC_HEADERS && HAVE_MEMORY_H
+#include <memory.h>
+#endif /* not STDC_HEADERS and HAVE_MEMORY_H */
+
+#ifndef index
+#define index strchr
+#endif /* index */
+
+#ifndef rindex
+#define rindex strrchr
+#endif /* rindex */
+
+#ifndef bcmp
+#define bcmp(s1, s2, n) memcmp ((s1), (s2), (n))
+#endif /* bcmp */
+
+#ifndef bzero
+#define bzero(s, n) memset ((s), 0, (n))
+#endif /* bzero */
+
+#else /* not STDC_HEADERS and not HAVE_STRING_H */
+#include <strings.h>
+/* memory.h and strings.h conflict on some systems. */
+#endif /* not STDC_HEADERS and not HAVE_STRING_H */
+
+#include <errno.h>
+
+/* Not all systems set the same error code on a non-existent-file
+ error. This tries to ask the question somewhat portably.
+ On systems that don't have ENOTEXIST, this should behave just like
+ x == ENOENT. "x" is probably errno, of course. */
+
+#ifdef ENOTEXIST
+# ifdef EOS2ERR
+# define existence_error(x) \
+ (((x) == ENOTEXIST) || ((x) == ENOENT) || ((x) == EOS2ERR))
+# else
+# define existence_error(x) \
+ (((x) == ENOTEXIST) || ((x) == ENOENT))
+# endif
+#else
+# define existence_error(x) ((x) == ENOENT)
+#endif
+
+
+#ifdef STDC_HEADERS
+#include <stdlib.h>
+#else
+char *getenv ();
+char *malloc ();
+char *realloc ();
+char *calloc ();
+extern int errno;
+#endif
+
+#if defined(USG) || defined(POSIX)
+char *getcwd ();
+#else
+char *getwd ();
+#endif
+
+/* check for POSIX signals */
+#if defined(HAVE_SIGACTION) && defined(HAVE_SIGPROCMASK)
+# define POSIX_SIGNALS
+#endif
+
+/* MINIX 1.6 doesn't properly support sigaction */
+#if defined(_MINIX)
+# undef POSIX_SIGNALS
+#endif
+
+/* If !POSIX, try for BSD.. Reason: 4.4BSD implements these as wrappers */
+#if !defined(POSIX_SIGNALS)
+# if defined(HAVE_SIGVEC) && defined(HAVE_SIGSETMASK) && defined(HAVE_SIGBLOCK)
+# define BSD_SIGNALS
+# endif
+#endif
+
+/* Under OS/2, this must be included _after_ stdio.h; that's why we do
+ it here. */
+#ifdef USE_OWN_TCPIP_H
+#include "tcpip.h"
+#endif
+
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h>
+#else
+#include <sys/file.h>
+#endif
+
+#ifndef SEEK_SET
+#define SEEK_SET 0
+#define SEEK_CUR 1
+#define SEEK_END 2
+#endif
+
+#ifndef F_OK
+#define F_OK 0
+#define X_OK 1
+#define W_OK 2
+#define R_OK 4
+#endif
+
+#if HAVE_DIRENT_H
+# include <dirent.h>
+# define NAMLEN(dirent) strlen((dirent)->d_name)
+#else
+# define dirent direct
+# define NAMLEN(dirent) (dirent)->d_namlen
+# if HAVE_SYS_NDIR_H
+# include <sys/ndir.h>
+# endif
+# if HAVE_SYS_DIR_H
+# include <sys/dir.h>
+# endif
+# if HAVE_NDIR_H
+# include <ndir.h>
+# endif
+#endif
+
+/* Convert B 512-byte blocks to kilobytes if K is nonzero,
+ otherwise return it unchanged. */
+#define convert_blocks(b, k) ((k) ? ((b) + 1) / 2 : (b))
+
+#ifndef S_ISLNK
+#define lstat stat
+#endif
+
+/*
+ * Some UNIX distributions don't include these in their stat.h Defined here
+ * because "config.h" is always included last.
+ */
+#ifndef S_IWRITE
+#define S_IWRITE 0000200 /* write permission, owner */
+#endif
+#ifndef S_IWGRP
+#define S_IWGRP 0000020 /* write permission, grougroup */
+#endif
+#ifndef S_IWOTH
+#define S_IWOTH 0000002 /* write permission, other */
+#endif
+
+/* Under MS-DOS and its derivatives (like Windows NT), mkdir takes only one
+ argument; permission is handled very differently on those systems than in
+ in Unix. So we leave such systems a hook on which they can hang their
+ own definitions. */
+#ifndef CVS_MKDIR
+#define CVS_MKDIR mkdir
+#endif
+
+/* Some file systems are case-insensitive. If FOLD_FN_CHAR is
+ #defined, it maps the character C onto its "canonical" form. In a
+ case-insensitive system, it would map all alphanumeric characters
+ to lower case. Under Windows NT, / and \ are both path component
+ separators, so FOLD_FN_CHAR would map them both to /. */
+#ifndef FOLD_FN_CHAR
+#define FOLD_FN_CHAR(c) (c)
+#define fnfold(filename) (filename)
+#define fncmp strcmp
+#endif
+
+/* Different file systems have different path component separators.
+ For the VMS port we might need to abstract further back than this. */
+#ifndef ISDIRSEP
+#define ISDIRSEP(c) ((c) == '/')
+#endif
+
+
+/* On some systems, lines in text files should be terminated with CRLF,
+ not just LF, and the read and write routines do this translation
+ for you. LINES_CRLF_TERMINATED is #defined on such systems.
+ - OPEN_BINARY is the flag to pass to the open function for
+ untranslated I/O.
+ - FOPEN_BINARY_READ is the string to pass to fopen to get
+ untranslated reading.
+ - FOPEN_BINARY_WRITE is the string to pass to fopen to get
+ untranslated writing. */
+#if LINES_CRLF_TERMINATED
+#define OPEN_BINARY (O_BINARY)
+#define FOPEN_BINARY_READ ("rb")
+#define FOPEN_BINARY_WRITE ("wb")
+#else
+#define OPEN_BINARY (0)
+#define FOPEN_BINARY_READ ("r")
+#define FOPEN_BINARY_WRITE ("w")
+#endif
diff --git a/gnu/usr.bin/cvs/lib/version.c b/gnu/usr.bin/cvs/lib/version.c
new file mode 100644
index 0000000..2eb66cd
--- /dev/null
+++ b/gnu/usr.bin/cvs/lib/version.c
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 1994 david d `zoo' zuhn
+ * Copyright (c) 1994 Free Software Foundation, Inc.
+ * Copyright (c) 1992, Brian Berliner and Jeff Polk
+ * Copyright (c) 1989-1992, Brian Berliner
+ *
+ * You may distribute under the terms of the GNU General Public License as
+ * specified in the README file that comes with this CVS source distribution.
+ *
+ * version.c - the CVS version number
+ */
+
+#include "cvs.h"
+
+#ifndef lint
+static const char rcsid[] = "$CVSid: @(#)version.c 1.15 94/10/03 $";
+USE(rcsid);
+#endif
+
+char *version_string = "\nConcurrent Versions System (CVS) 1.6.3";
+
+#ifdef CLIENT_SUPPORT
+#ifdef SERVER_SUPPORT
+char *config_string = " (client/server)\n";
+#else
+char *config_string = " (client)\n";
+#endif
+#else
+#ifdef SERVER_SUPPORT
+char *config_string = " (server)\n";
+#else
+char *config_string = "\n";
+#endif
+#endif
diff --git a/gnu/usr.bin/cvs/lib/wait.h b/gnu/usr.bin/cvs/lib/wait.h
new file mode 100644
index 0000000..db60434
--- /dev/null
+++ b/gnu/usr.bin/cvs/lib/wait.h
@@ -0,0 +1,32 @@
+/* wait.h -- POSIX macros for evaluating exit statuses
+ Copyright (C) 1990 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#ifdef HAVE_SYS_WAIT_H
+#include <sys/types.h> /* For pid_t. */
+#ifdef HAVE_SYS_RESOURCE_H
+#include <sys/resource.h> /* for rusage */
+#endif
+#include <sys/wait.h>
+#else
+#define WIFSTOPPED(w) (((w) & 0xff) == 0x7f)
+#define WIFSIGNALED(w) (((w) & 0xff) != 0x7f && ((w) & 0xff) != 0)
+#define WIFEXITED(w) (((w) & 0xff) == 0)
+
+#define WSTOPSIG(w) (((w) >> 8) & 0xff)
+#define WTERMSIG(w) ((w) & 0x7f)
+#define WEXITSTATUS(w) (((w) >> 8) & 0xff)
+#endif
diff --git a/gnu/usr.bin/cvs/lib/xgetwd.c b/gnu/usr.bin/cvs/lib/xgetwd.c
new file mode 100644
index 0000000..8fe4ec1
--- /dev/null
+++ b/gnu/usr.bin/cvs/lib/xgetwd.c
@@ -0,0 +1,79 @@
+/* xgetwd.c -- return current directory with unlimited length
+ Copyright (C) 1992 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* Derived from xgetcwd.c in e.g. the GNU sh-utils. */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "system.h"
+
+#include <stdio.h>
+#include <errno.h>
+#ifndef errno
+extern int errno;
+#endif
+#include <sys/types.h>
+
+#ifndef HAVE_GETWD
+char *getwd ();
+#define GETWD(buf, max) getwd (buf)
+#else
+char *getcwd ();
+#define GETWD(buf, max) getcwd (buf, max)
+#endif
+
+/* Amount by which to increase buffer size when allocating more space. */
+#define PATH_INCR 32
+
+char *xmalloc ();
+char *xrealloc ();
+
+/* Return the current directory, newly allocated, arbitrarily long.
+ Return NULL and set errno on error. */
+
+char *
+xgetwd ()
+{
+ char *cwd;
+ char *ret;
+ unsigned path_max;
+
+ errno = 0;
+ path_max = (unsigned) PATH_MAX;
+ path_max += 2; /* The getcwd docs say to do this. */
+
+ cwd = xmalloc (path_max);
+
+ errno = 0;
+ while ((ret = GETWD (cwd, path_max)) == NULL && errno == ERANGE)
+ {
+ path_max += PATH_INCR;
+ cwd = xrealloc (cwd, path_max);
+ errno = 0;
+ }
+
+ if (ret == NULL)
+ {
+ int save_errno = errno;
+ free (cwd);
+ errno = save_errno;
+ return NULL;
+ }
+ return cwd;
+}
diff --git a/gnu/usr.bin/cvs/lib/yesno.c b/gnu/usr.bin/cvs/lib/yesno.c
new file mode 100644
index 0000000..7014803
--- /dev/null
+++ b/gnu/usr.bin/cvs/lib/yesno.c
@@ -0,0 +1,41 @@
+/* yesno.c -- read a yes/no response from stdin
+ Copyright (C) 1990 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdio.h>
+
+/* Read one line from standard input
+ and return nonzero if that line begins with y or Y,
+ otherwise return 0. */
+
+int
+yesno ()
+{
+ int c;
+ int rv;
+
+ fflush (stderr);
+ c = getchar ();
+ rv = (c == 'y') || (c == 'Y');
+ while (c != EOF && c != '\n')
+ c = getchar ();
+
+ return rv;
+}
diff --git a/gnu/usr.bin/cvs/mkmodules/Makefile b/gnu/usr.bin/cvs/mkmodules/Makefile
new file mode 100644
index 0000000..78c2bb9
--- /dev/null
+++ b/gnu/usr.bin/cvs/mkmodules/Makefile
@@ -0,0 +1,10 @@
+# $Id: Makefile,v 1.5 1995/03/31 07:55:30 nate Exp $
+
+PROG = mkmodules
+SRCS = mkmodules.c
+CFLAGS+= -I${.CURDIR}/../cvs -I${.CURDIR}/../lib -DHAVE_CONFIG_H
+DPADD+= ${LIBCVS}
+LDADD+= -lcvs
+
+.include "../../Makefile.inc"
+.include <bsd.prog.mk>
diff --git a/gnu/usr.bin/cvs/mkmodules/mkmodules.1 b/gnu/usr.bin/cvs/mkmodules/mkmodules.1
new file mode 100644
index 0000000..ff446ab
--- /dev/null
+++ b/gnu/usr.bin/cvs/mkmodules/mkmodules.1
@@ -0,0 +1,65 @@
+.\"
+.\" $CVSid: @(#)mkmodules.1 1.3 92/01/30 $
+.\"
+.TH MKMODULES 1 "12 October 1991"
+.SH "NAME"
+mkmodules \- Rebuild modules database for CVS
+.SH "SYNOPSIS"
+.B mkmodules
+.I directory
+.SH "DESCRIPTION"
+.B mkmodules
+rebuilds the modules database that
+.BR cvs (1)
+uses.
+The
+.I directory
+specified is expected to contain the
+.BR modules,v " and " loginfo,v
+files.
+.B mkmodules
+carefully checks out the current head revisions of each of these files and
+reuilds the
+.BR ndbm (3)
+format modules database.
+A warning is generated if the modules file contains a duplicate key.
+.SH "FILES"
+.TP
+modules,v
+The modules
+.SM RCS
+file.
+.TP
+modules
+The checked out modules file.
+.TP
+loginfo,v
+The loginfo
+.SM RCS
+file.
+.TP
+loginfo
+The checked out loginfo file.
+.TP
+modules.dir, modules.pag
+The
+.BR ndbm (1)
+format modules database.
+.SH "ENVIRONMENT VARIABLES"
+.TP
+.SM RCSBIN
+Specifies the full pathname where to find
+.SM RCS
+programs, such as
+.BR co (1)
+and
+.BR ci (1).
+If not set, the default is
+.BR /usr/local/bin .
+.SH "SEE ALSO"
+.BR ci (1),
+.BR co (1),
+.BR cvs (1),
+.\" .BR ndbm (3),
+.BR rcs (1),
+.SH "BUGS"
diff --git a/gnu/usr.bin/cvs/mkmodules/mkmodules.c b/gnu/usr.bin/cvs/mkmodules/mkmodules.c
new file mode 100644
index 0000000..9b0e7bd
--- /dev/null
+++ b/gnu/usr.bin/cvs/mkmodules/mkmodules.c
@@ -0,0 +1,435 @@
+/*
+ * Copyright (c) 1992, Brian Berliner and Jeff Polk
+ * Copyright (c) 1989-1992, Brian Berliner
+ *
+ * You may distribute under the terms of the GNU General Public License as
+ * specified in the README file that comes with the CVS 1.4 kit.
+ *
+ * mkmodules
+ *
+ * Re-build the modules database for the CVS system. Accepts one argument,
+ * which is the directory that the modules,v file lives in.
+ */
+
+#include "cvs.h"
+
+#ifndef lint
+static const char rcsid[] = "$CVSid: @(#)mkmodules.c 1.45 94/09/30 $";
+USE(rcsid);
+#endif
+
+#ifndef DBLKSIZ
+#define DBLKSIZ 4096 /* since GNU ndbm doesn't define it */
+#endif
+
+char *program_name, *command_name;
+
+char *Rcsbin = RCSBIN_DFLT;
+char *CVSroot = CVSROOT_DFLT;
+int noexec = 0; /* Here only to satisfy use in subr.c */
+int trace = 0; /* Here only to satisfy use in subr.c */
+
+static int checkout_file PROTO((char *file, char *temp));
+static void make_tempfile PROTO((char *temp));
+static void mkmodules_usage PROTO((void));
+static void rename_rcsfile PROTO((char *temp, char *real));
+
+#ifndef MY_NDBM
+static void rename_dbmfile PROTO((char *temp));
+static void write_dbmfile PROTO((char *temp));
+#endif /* !MY_NDBM */
+
+
+int
+main (argc, argv)
+ int argc;
+ char **argv;
+{
+ char temp[PATH_MAX];
+ char *cp, *last, *fname;
+#ifdef MY_NDBM
+ DBM *db;
+#endif
+ FILE *fp;
+ char line[512];
+ static struct _checkout_file {
+ char *filename;
+ char *errormsg;
+ } *fileptr, filelist[] = {
+ {CVSROOTADM_LOGINFO,
+ "no logging of 'cvs commit' messages is done without a %s file"},
+ {CVSROOTADM_RCSINFO,
+ "a %s file can be used to configure 'cvs commit' templates"},
+ {CVSROOTADM_EDITINFO,
+ "a %s file can be used to validate log messages"},
+ {CVSROOTADM_COMMITINFO,
+ "a %s file can be used to configure 'cvs commit' checking"},
+ {CVSROOTADM_TAGINFO,
+ "a %s file can be used to configure 'cvs tag' checking"},
+ {CVSROOTADM_IGNORE,
+ "a %s file can be used to specify files to ignore"},
+ {CVSROOTADM_CHECKOUTLIST,
+ "a %s file can specify extra CVSROOT files to auto-checkout"},
+ {CVSROOTADM_WRAPPER,
+ "a %s file can be used to specify files to treat as wrappers"},
+ {NULL, NULL}};
+
+ /*
+ * Just save the last component of the path for error messages
+ */
+ program_name = last_component (argv[0]);
+
+ if (argc != 2)
+ mkmodules_usage ();
+
+ if ((cp = getenv (RCSBIN_ENV)) != NULL)
+ Rcsbin = cp;
+
+ /*
+ * If Rcsbin is set to something, make sure it is terminated with a slash
+ * character. If not, add one.
+ */
+ if (Rcsbin[0] != '\0')
+ {
+ int len = strlen (Rcsbin);
+ char *rcsbin;
+
+ if (Rcsbin[len - 1] != '/')
+ {
+ rcsbin = Rcsbin;
+ Rcsbin = xmalloc (len + 2); /* one for '/', one for NULL */
+ (void) strcpy (Rcsbin, rcsbin);
+ (void) strcat (Rcsbin, "/");
+ }
+ }
+
+ if (chdir (argv[1]) < 0)
+ error (1, errno, "cannot chdir to %s", argv[1]);
+
+ /*
+ * First, do the work necessary to update the "modules" database.
+ */
+ make_tempfile (temp);
+ switch (checkout_file (CVSROOTADM_MODULES, temp))
+ {
+
+ case 0: /* everything ok */
+#ifdef MY_NDBM
+ /* open it, to generate any duplicate errors */
+ if ((db = dbm_open (temp, O_RDONLY, 0666)) != NULL)
+ dbm_close (db);
+#else
+ write_dbmfile (temp);
+ rename_dbmfile (temp);
+#endif
+ rename_rcsfile (temp, CVSROOTADM_MODULES);
+ break;
+
+ case -1: /* fork failed */
+ (void) unlink_file (temp);
+ exit (1);
+ /* NOTREACHED */
+
+ default:
+ error (0, 0,
+ "'cvs checkout' is less functional without a %s file",
+ CVSROOTADM_MODULES);
+ break;
+ } /* switch on checkout_file() */
+
+ (void) unlink_file (temp);
+
+ /* Checkout the files that need it in CVSROOT dir */
+ for (fileptr = filelist; fileptr && fileptr->filename; fileptr++) {
+ make_tempfile (temp);
+ if (checkout_file (fileptr->filename, temp) == 0)
+ rename_rcsfile (temp, fileptr->filename);
+#if 0
+ /*
+ * If there was some problem other than the file not existing,
+ * checkout_file already printed a real error message. If the
+ * file does not exist, it is harmless--it probably just means
+ * that the repository was created with an old version of CVS
+ * which didn't have so many files in CVSROOT.
+ */
+ else if (fileptr->errormsg)
+ error (0, 0, fileptr->errormsg, fileptr->filename);
+#endif
+ (void) unlink_file (temp);
+ }
+
+ /* Use 'fopen' instead of 'open_file' because we want to ignore error */
+ fp = fopen (CVSROOTADM_CHECKOUTLIST, "r");
+ if (fp)
+ {
+ /*
+ * File format:
+ * [<whitespace>]<filename><whitespace><error message><end-of-line>
+ *
+ * comment lines begin with '#'
+ */
+ while (fgets (line, sizeof (line), fp) != NULL)
+ {
+ /* skip lines starting with # */
+ if (line[0] == '#')
+ continue;
+
+ if ((last = strrchr (line, '\n')) != NULL)
+ *last = '\0'; /* strip the newline */
+
+ /* Skip leading white space. */
+ for (fname = line; *fname && isspace(*fname); fname++)
+ ;
+
+ /* Find end of filename. */
+ for (cp = fname; *cp && !isspace(*cp); cp++)
+ ;
+ *cp = '\0';
+
+ make_tempfile (temp);
+ if (checkout_file (fname, temp) == 0)
+ {
+ rename_rcsfile (temp, fname);
+ }
+ else
+ {
+ for (cp++; cp < last && *last && isspace(*last); cp++)
+ ;
+ if (cp < last && *cp)
+ error (0, 0, cp, fname);
+ }
+ }
+ (void) fclose (fp);
+ }
+
+ return (0);
+}
+
+/*
+ * Yeah, I know, there are NFS race conditions here.
+ */
+static void
+make_tempfile (temp)
+ char *temp;
+{
+ static int seed = 0;
+ int fd;
+
+ if (seed == 0)
+ seed = getpid ();
+ while (1)
+ {
+ (void) sprintf (temp, "%s%d", BAKPREFIX, seed++);
+ if ((fd = open (temp, O_CREAT|O_EXCL|O_RDWR, 0666)) != -1)
+ break;
+ if (errno != EEXIST)
+ error (1, errno, "cannot create temporary file %s", temp);
+ }
+ if (close(fd) < 0)
+ error(1, errno, "cannot close temporary file %s", temp);
+}
+
+static int
+checkout_file (file, temp)
+ char *file;
+ char *temp;
+{
+ char rcs[PATH_MAX];
+ int retcode = 0;
+
+ (void) sprintf (rcs, "%s%s", file, RCSEXT);
+ if (!isfile (rcs))
+ return (1);
+ run_setup ("%s%s -q -p", Rcsbin, RCS_CO);
+ run_arg (rcs);
+ if ((retcode = run_exec (RUN_TTY, temp, RUN_TTY, RUN_NORMAL)) != 0)
+ {
+ error (0, retcode == -1 ? errno : 0, "failed to check out %s file", file);
+ }
+ return (retcode);
+}
+
+#ifndef MY_NDBM
+
+static void
+write_dbmfile (temp)
+ char *temp;
+{
+ char line[DBLKSIZ], value[DBLKSIZ];
+ FILE *fp;
+ DBM *db;
+ char *cp, *vp;
+ datum key, val;
+ int len, cont, err = 0;
+
+ fp = open_file (temp, "r");
+ if ((db = dbm_open (temp, O_RDWR | O_CREAT | O_TRUNC, 0666)) == NULL)
+ error (1, errno, "cannot open dbm file %s for creation", temp);
+ for (cont = 0; fgets (line, sizeof (line), fp) != NULL;)
+ {
+ if ((cp = strrchr (line, '\n')) != NULL)
+ *cp = '\0'; /* strip the newline */
+
+ /*
+ * Add the line to the value, at the end if this is a continuation
+ * line; otherwise at the beginning, but only after any trailing
+ * backslash is removed.
+ */
+ vp = value;
+ if (cont)
+ vp += strlen (value);
+
+ /*
+ * See if the line we read is a continuation line, and strip the
+ * backslash if so.
+ */
+ len = strlen (line);
+ if (len > 0)
+ cp = &line[len - 1];
+ else
+ cp = line;
+ if (*cp == '\\')
+ {
+ cont = 1;
+ *cp = '\0';
+ }
+ else
+ {
+ cont = 0;
+ }
+ (void) strcpy (vp, line);
+ if (value[0] == '#')
+ continue; /* comment line */
+ vp = value;
+ while (*vp && isspace (*vp))
+ vp++;
+ if (*vp == '\0')
+ continue; /* empty line */
+
+ /*
+ * If this was not a continuation line, add the entry to the database
+ */
+ if (!cont)
+ {
+ key.dptr = vp;
+ while (*vp && !isspace (*vp))
+ vp++;
+ key.dsize = vp - key.dptr;
+ *vp++ = '\0'; /* NULL terminate the key */
+ while (*vp && isspace (*vp))
+ vp++; /* skip whitespace to value */
+ if (*vp == '\0')
+ {
+ error (0, 0, "warning: NULL value for key `%s'", key.dptr);
+ continue;
+ }
+ val.dptr = vp;
+ val.dsize = strlen (vp);
+ if (dbm_store (db, key, val, DBM_INSERT) == 1)
+ {
+ error (0, 0, "duplicate key found for `%s'", key.dptr);
+ err++;
+ }
+ }
+ }
+ dbm_close (db);
+ (void) fclose (fp);
+ if (err)
+ {
+ char dotdir[50], dotpag[50], dotdb[50];
+
+ (void) sprintf (dotdir, "%s.dir", temp);
+ (void) sprintf (dotpag, "%s.pag", temp);
+ (void) sprintf (dotdb, "%s.db", temp);
+ (void) unlink_file (dotdir);
+ (void) unlink_file (dotpag);
+ (void) unlink_file (dotdb);
+ error (1, 0, "DBM creation failed; correct above errors");
+ }
+}
+
+static void
+rename_dbmfile (temp)
+ char *temp;
+{
+ char newdir[50], newpag[50], newdb[50];
+ char dotdir[50], dotpag[50], dotdb[50];
+ char bakdir[50], bakpag[50], bakdb[50];
+
+ (void) sprintf (dotdir, "%s.dir", CVSROOTADM_MODULES);
+ (void) sprintf (dotpag, "%s.pag", CVSROOTADM_MODULES);
+ (void) sprintf (dotdb, "%s.db", CVSROOTADM_MODULES);
+ (void) sprintf (bakdir, "%s%s.dir", BAKPREFIX, CVSROOTADM_MODULES);
+ (void) sprintf (bakpag, "%s%s.pag", BAKPREFIX, CVSROOTADM_MODULES);
+ (void) sprintf (bakdb, "%s%s.db", BAKPREFIX, CVSROOTADM_MODULES);
+ (void) sprintf (newdir, "%s.dir", temp);
+ (void) sprintf (newpag, "%s.pag", temp);
+ (void) sprintf (newdb, "%s.db", temp);
+
+ (void) chmod (newdir, 0666);
+ (void) chmod (newpag, 0666);
+ (void) chmod (newdb, 0666);
+
+ /* don't mess with me */
+ SIG_beginCrSect ();
+
+ (void) unlink_file (bakdir); /* rm .#modules.dir .#modules.pag */
+ (void) unlink_file (bakpag);
+ (void) unlink_file (bakdb);
+ (void) rename (dotdir, bakdir); /* mv modules.dir .#modules.dir */
+ (void) rename (dotpag, bakpag); /* mv modules.pag .#modules.pag */
+ (void) rename (dotdb, bakdb); /* mv modules.db .#modules.db */
+ (void) rename (newdir, dotdir); /* mv "temp".dir modules.dir */
+ (void) rename (newpag, dotpag); /* mv "temp".pag modules.pag */
+ (void) rename (newdb, dotdb); /* mv "temp".db modules.db */
+
+ /* OK -- make my day */
+ SIG_endCrSect ();
+}
+
+#endif /* !MY_NDBM */
+
+static void
+rename_rcsfile (temp, real)
+ char *temp;
+ char *real;
+{
+ char bak[50];
+ struct stat statbuf;
+ char rcs[PATH_MAX];
+
+ /* Set "x" bits if set in original. */
+ (void) sprintf (rcs, "%s%s", real, RCSEXT);
+ statbuf.st_mode = 0; /* in case rcs file doesn't exist, but it should... */
+ (void) stat (rcs, &statbuf);
+
+ if (chmod (temp, 0444 | (statbuf.st_mode & 0111)) < 0)
+ error (0, errno, "warning: cannot chmod %s", temp);
+ (void) sprintf (bak, "%s%s", BAKPREFIX, real);
+ (void) unlink_file (bak); /* rm .#loginfo */
+ (void) rename (real, bak); /* mv loginfo .#loginfo */
+ (void) rename (temp, real); /* mv "temp" loginfo */
+}
+
+/*
+ * For error() only
+ */
+void
+Lock_Cleanup ()
+{
+}
+
+int server_active = 0;
+
+void
+server_cleanup (sig)
+ int sig;
+{
+}
+
+static void
+mkmodules_usage ()
+{
+ (void) fprintf (stderr, "Usage: %s modules-directory\n", program_name);
+ exit (1);
+}
diff --git a/gnu/usr.bin/dc/COPYING b/gnu/usr.bin/dc/COPYING
new file mode 100644
index 0000000..e77696a
--- /dev/null
+++ b/gnu/usr.bin/dc/COPYING
@@ -0,0 +1,339 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 675 Mass Ave, Cambridge, MA 02139, USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) 19yy <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) 19yy name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/gnu/usr.bin/dc/ChangeLog b/gnu/usr.bin/dc/ChangeLog
new file mode 100644
index 0000000..09aaf47
--- /dev/null
+++ b/gnu/usr.bin/dc/ChangeLog
@@ -0,0 +1,77 @@
+Fri May 21 15:02:52 1993 Noah Friedman (friedman@nutrimat.gnu.ai.mit.edu)
+
+ * Version 0.2 released.
+
+Fri May 21 11:48:11 1993 Richard Stallman (rms@mole.gnu.ai.mit.edu)
+
+ * decimal.c (decimal_rem): Update to match fixes in decimal_div.
+
+Thu May 20 03:12:41 1993 Noah Friedman (friedman@nutrimat.gnu.ai.mit.edu)
+
+ * Makefile.in (realclean): Delete dc.info* and configure.
+ (DISTFILES): Add `texinfo.tex' and `NEWS'.
+ texinfo.tex: New file (symlink to canonical source).
+ NEWS: New file.
+
+Wed May 19 11:30:09 1993 Richard Stallman (rms@mole.gnu.ai.mit.edu)
+
+ * dc.c (dec_read): Accept only A through F.
+
+Tue May 18 12:35:54 1993 Richard Stallman (rms@mole.gnu.ai.mit.edu)
+
+ * dc.c (read_string): New arg STARTC to handle nested brackets.
+ (execute): Change calls to read_string.
+ (condop): Don't assume result of decimal_compare has abs value <= 1.
+ (popmacro): If no macro in progress, exit.
+
+Sun May 2 00:42:47 1993 Richard Stallman (rms@mole.gnu.ai.mit.edu)
+
+ * decimal.c (decimal_div): Include in trial_dividend the digit
+ at length2 + i - 2, if there is one.
+
+Sat May 1 09:54:35 1993 Richard Stallman (rms@mole.gnu.ai.mit.edu)
+
+ * decimal.c (decimal_parse): Don't use digits without recalculation
+ if some digit exceeds the radix.
+
+ * dc.c (execute): Treat A...F as digits.
+ (dec_read): Treat A...F as digits.
+
+Thu Apr 29 14:17:30 1993 Richard Stallman (rms@mole.gnu.ai.mit.edu)
+
+ * decimal.h (bcopy): Use memcpy, not memmove.
+
+ * decimal.c (flush_trailing_digits): Use explicit loop, not bcopy.
+
+Tue Apr 20 17:21:27 1993 Noah Friedman (friedman@nutrimat.gnu.ai.mit.edu)
+
+ * dc.c (pushsqrt): `precision' is an argument to `decimal_sqrt', not
+ `push'.
+
+Sat Apr 17 15:47:55 1993 Noah Friedman (friedman@nutrimat.gnu.ai.mit.edu)
+
+ * All files: Updated GPL version number.
+
+ * decimal.c: Include decimal.h and delete duplicate declarations.
+
+ * decimal.h [!HAVE_BCOPY]: #define bcopy.
+ [!HAVE_BZERO]: #define bzero.
+
+Sun Feb 10 22:06:15 1991 Richard Stallman (rms at mole.ai.mit.edu)
+
+ * dc.c (execute): Insert break; in \n case.
+
+Sun Jul 29 17:50:14 1990 Richard Stallman (rms at sugar-bombs.ai.mit.edu)
+
+ * decimal.c (decimal_neg): New function.
+
+Fri Jul 27 04:11:34 1990 David J. MacKenzie (djm at albert.ai.mit.edu)
+
+ * bceval.c, bclex.c, bcprint.c, bcsym.c: Declare some functions
+ static.
+
+Mon Dec 25 03:01:49 1989 David J. MacKenzie (djm at hobbes.ai.mit.edu)
+
+ * Makefile: add some missing rules.
+
+ * decimal.c: change a 'max' to 'MAX'.
diff --git a/gnu/usr.bin/dc/Makefile b/gnu/usr.bin/dc/Makefile
new file mode 100644
index 0000000..57b2ebd
--- /dev/null
+++ b/gnu/usr.bin/dc/Makefile
@@ -0,0 +1,8 @@
+PROG= dc
+SRCS= dc.c decimal.c
+CFLAGS+=-I${.CURDIR} -DHAVE_BCOPY=1 -DHAVE_BZERO=1
+DPADD= ${LIBM}
+LDADD= -lm
+SUBDIR+= doc
+
+.include <bsd.prog.mk>
diff --git a/gnu/usr.bin/dc/NEWS b/gnu/usr.bin/dc/NEWS
new file mode 100644
index 0000000..6486afb
--- /dev/null
+++ b/gnu/usr.bin/dc/NEWS
@@ -0,0 +1,7 @@
+Changes between version 0.2 and 0.1:
+
+* You can now have nested square bracket pairs within a string.
+
+* The letters A-F can now be part of a number when the input radix is
+large enough to make them meaningful.
+
diff --git a/gnu/usr.bin/dc/README b/gnu/usr.bin/dc/README
new file mode 100644
index 0000000..c23cc66
--- /dev/null
+++ b/gnu/usr.bin/dc/README
@@ -0,0 +1,13 @@
+This is a preliminary release of GNU `dc', since people asked for it. GNU
+`bc' (which doesn't rely on a separate `dc') has been available separately
+for a couple of years. Eventually this version of `dc' will be merged with
+the bc package.
+
+See comments in the file decimal.c for some limitations in the arbitrary
+precision library. It's questionable whether it's worth fixing these
+problems since the merged dc will probably use bc's math library instead.
+However, you might want to be aware of known problems.
+
+See the file `INSTALL' for instructions on building and installing dc.
+
+Please report bugs to bug-gnu-utils@prep.ai.mit.edu.
diff --git a/gnu/usr.bin/dc/dc.1 b/gnu/usr.bin/dc/dc.1
new file mode 100644
index 0000000..17d9356
--- /dev/null
+++ b/gnu/usr.bin/dc/dc.1
@@ -0,0 +1,278 @@
+.TH DC 1 "03 Aug 1993" "GNU Project"
+.SH NAME
+dc, An Arbitrary Precision Calculator
+.SH SYNOPSIS
+.B dc
+.SH DESCRIPTION
+.PP
+DC is a reverse-polish desk calculator which supports unlimited
+precision arithmetic. It also allows you to define and call macros.
+Normally DC reads from the standard input; if any command arguments
+are given to it, they are filenames, and DC reads and executes the
+contents of the files before reading from standard input. All output
+is to standard output.
+
+A reverse-polish calculator stores numbers on a stack. Entering a
+number pushes it on the stack. Arithmetic operations pop arguments off
+the stack and push the results.
+
+To enter a number in DC, type the digits, with an optional decimal
+point. Exponential notation is not supported. To enter a negative
+number, begin the number with `_'. `-' cannot be used for this, as it
+is a binary operator for subtraction instead. To enter two numbers in
+succession, separate them with spaces or newlines. These have no
+meaning as commands.
+.PD
+.SH "Printing Commands"
+.PP
+.B p
+Prints the value on the top of the stack,
+without altering the stack. A newline is printed
+after the value.
+.PP
+.B P
+Prints the value on the top of the stack,
+popping it off, and does not print a newline after.
+.PP
+.B f
+Prints the entire contents of the stack
+and the contents of all of the registers,
+without altering anything. This is a good command
+to use if you are lost or want to figure out
+what the effect of some command has been.
+.PD
+.SH "Arithmetic"
+.PP
+.B +
+Pops two values off the stack, adds them,
+and pushes the result. The precision of the result
+is determined only by the values of the arguments,
+and is enough to be exact.
+.PP
+.B -
+Pops two values, subtracts the first one popped
+from the second one popped, and pushes the result.
+.PP
+.B *
+Pops two values, multiplies them, and pushes the result.
+The number of fraction digits in the result is controlled
+by the current precision flag (see below) and does not
+depend on the values being multiplied.
+.PP
+.B /
+Pops two values, divides the second one popped from
+the first one popped, and pushes the result.
+The number of fraction digits is specified by the precision flag.
+.PP
+.B %
+Pops two values, computes the remainder of the division
+that the \fB/\fR command would do, and pushes that.
+The division is done with as many fraction digits
+as the precision flag specifies, and the remainder
+is also computed with that many fraction digits.
+.PP
+.B ^
+Pops two values and exponentiates, using the first
+value popped as the exponent and the second popped as the base.
+The fraction part of the exponent is ignored.
+The precision flag specifies the number of fraction
+digits in the result.
+.PP
+.B v
+Pops one value, computes its square root, and pushes that.
+The precision flag specifies the number of fraction digits
+in the result.
+.PP
+Most arithmetic operations are affected by the "precision flag",
+which you can set with the
+.BR k
+command. The default precision
+value is zero, which means that all arithmetic except for
+addition and subtraction produces integer results.
+.PP
+The remainder operation
+.BR %
+requires some explanation: applied to
+arguments `a' and `b' it produces `a - (b * (a / b))',
+where `a / b' is computed in the current precision.
+.PP
+.SH "Stack Control"
+.PP
+.B c
+Clears the stack, rendering it empty.
+.PP
+.B d
+Duplicates the value on the top of the stack,
+pushing another copy of it. Thus,
+`4d*p' computes 4 squared and prints it.
+.SH "Registers"
+.PP
+DC provides 128 memory registers, each named by a single
+ASCII character. You can store a number in a register
+and retrieve it later.
+.PP
+.B s\fIr\fR
+Pop the value off the top of the stack and store
+it into register \fIr\fR.
+.PP
+.B l\fIr\fR
+Copy the value in register \fIr\fR and push it onto the stack. This
+does not alter the contents of \fIr\fR.
+.PP
+Each register also contains its own stack. The current
+register value is the top of the register's stack.
+.PP
+.B S\fIr\fR
+Pop the value off the top of the (main) stack and
+push it onto the stack of register \fIr\fR.
+The previous value of the register becomes inaccessible.
+.PP
+.B L\fIr\fR
+Pop the value off the top of register \fIr\fR's stack
+and push it onto the main stack. The previous value
+in register \fIr\fR's stack, if any, is now accessible
+via the
+.BR Ir
+command.
+.PP
+The
+.BR f
+command prints a list of all registers that have contents
+stored in them, together with their contents. Only the
+current contents of each register (the top of its stack)
+is printed.
+.PP
+.SH "Parameters"
+.PP
+DC has three parameters that control its operation: the precision, the
+input radix, and the output radix. The precision specifies the number
+of fraction digits to keep in the result of most arithmetic operations.
+The input radix controls the interpretation of numbers typed in;
+allnumbers typed in use this radix. The output radix is used
+for printing numbers.
+.PP
+The input and output radices are separate parameters; you can make them
+unequal, which can be useful or confusing. Each radix must be between 2
+and 36 inclusive. The precision must be zero or greater. The precision
+is always measured in decimal digits, regardless of the current input or
+output radix.
+.PP
+.B i
+Pops the value off the top of the stack
+and uses it to set the input radix.
+.PP
+.B o
+.PP
+.B k
+Similarly set the output radix and the precision.
+.PP
+.B I
+Pushes the current input radix on the stack.
+.PP
+.B O
+.PP
+.B K
+Similarly push the current output radix and the current precision.
+.PP
+.SH "Strings"
+.PP
+DC can operate on strings as well as on numbers. The only things you
+can do with strings are print them and execute them as macros (which
+means that the contents of the string are processed as DC commands).
+Both registers and the stack can hold strings, and DC always knows
+whether any given object is a string or a number. Some commands such as
+arithmetic operations demand numbers as arguments and print errors if
+given strings. Other commands can accept either a number or a string;
+for example, the
+.BR p
+command can accept either and prints the object
+according to its type.
+.PP
+.B [characters]
+Makes a string containing
+.BR characters
+and pushes it
+on the stack. For example,
+.BR [foo]p
+prints the
+characters \fBfoo\fR (with no newline).
+.PP
+.B x
+Pops a value off the stack and executes it as a macro.
+Normally it should be a string; if it is a number,
+it is simply pushed back onto the stack.
+For example,
+.BR [1p]x
+executes the macro
+.BR 1p
+which pushes \fB1\fR on the stack and prints \fB1\fR
+on a separate line.
+.PP
+Macros are most often stored in registers;
+\fB[1p]sa\fR stores a macro to print \fB1\fR into register \fBa\fR,
+and \fBlax\fR invokes the macro.
+.PP
+.B >\fIr\fR
+Pops two values off the stack and compares them
+assuming they are numbers, executing the contents
+of register \fIr\fR as a macro if the original top-of-stack
+is greater. Thus, \fB1 2>a\fR will invoke register \fBa\fR's contents
+and \fB2 1>a\fR will not.
+.PP
+.B <\fIr\fB
+Similar but invokes the macro if the original top-of-stack
+is less.
+.PP
+.B =\fIr\fR
+Similar but invokes the macro if the two numbers popped
+are equal. This can also be validly used to compare two
+strings for equality.
+.PP
+.B ?
+Reads a line from the terminal and executes it.
+This command allows a macro to request input from the user.
+.PP
+.B q
+During the execution of a macro, this comand
+does not exit DC. Instead, it exits from that
+macro and also from the macro which invoked it (if any).
+.PP
+.B Q
+Pops a value off the stack and uses it as a count
+of levels of macro execution to be exited. Thus,
+\fB3Q\fR exits three levels.
+.SH "Status Inquiry"
+.PP
+.B Z
+Pops a value off the stack, calculates the number of
+digits it has (or number of characters, if it is a string)
+and pushes that number.
+.PP
+.B X
+Pops a value off the stack, calculates the number of
+fraction digits it has, and pushes that number.
+For a string, the value pushed is -1.
+.PP
+.B z
+Pushes the current stack depth; the number of
+objects on the stack before the execution of the \fBz\fR command.
+.PP
+.B I
+Pushes the current value of the input radix.
+.PP
+.B O
+Pushes the current value of the output radix.
+.PP
+.B K
+Pushes the current value of the precision.
+.SH "Notes"
+.PP
+The \fB:\fR and \fB;\fR commands of the Unix DC program are
+not supported, as the documentation does not say what they do.
+The \fB!\fR command is not supported, but will be supported
+as soon as a library for executing a line as a command exists.
+.SH BUGS
+.PP
+Email bug reports to
+.BR bug-gnu-utils@prep.ai.mit.edu .
+Be sure to include the word ``dc'' somewhere in the ``Subject:'' field.
diff --git a/gnu/usr.bin/dc/dc.c b/gnu/usr.bin/dc/dc.c
new file mode 100644
index 0000000..a413253
--- /dev/null
+++ b/gnu/usr.bin/dc/dc.c
@@ -0,0 +1,908 @@
+/*
+ * `dc' desk calculator utility.
+ *
+ * Copyright (C) 1984, 1993 Free Software Foundation, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, you can either send email to this
+ * program's author (see below) or write to: The Free Software Foundation,
+ * Inc.; 675 Mass Ave. Cambridge, MA 02139, USA.
+ */
+
+#include <stdio.h>
+#include "decimal.h" /* definitions for our decimal arithmetic package */
+
+FILE *open_file; /* input file now open */
+int file_count; /* Number of input files not yet opened */
+char **next_file; /* Pointer to vector of names of input files left */
+
+struct regstack
+ {
+ decimal value; /* Saved value of register */
+ struct regstack *rest; /* Tail of list */
+ };
+
+typedef struct regstack *regstack;
+
+regstack freeregstacks; /* Chain of free regstack structures for fast realloc */
+
+decimal regs[128]; /* "registers", with single-character names */
+regstack regstacks[128]; /* For each register, a stack of previous values */
+
+int stacktop; /* index of last used element in stack */
+int stacksize; /* Current allocates size of stack */
+decimal *stack; /* Pointer to computation stack */
+
+/* A decimal number can be regarded as a string by
+ treating its contents as characters and ignoring the
+ position of its decimal point.
+ Decimal numbers are marked as strings by having an `after' field of -1
+ One use of strings is to execute them as macros.
+*/
+
+#define STRING -1
+
+int macrolevel; /* Current macro nesting; 0 if taking keyboard input */
+int macrostacksize; /* Current allocated size of macrostack and macroindex */
+decimal *macrostack; /* Pointer to macro stack array */
+int *macroindex; /* Pointer to index-within-macro stack array */
+ /* Note that an empty macro is popped from the stack
+ only when an trying to read a character from it
+ or trying to push another macro. */
+
+int ibase; /* Radix for numeric input. */
+int obase; /* Radix for numeric output. */
+int precision; /* Number of digits to keep in multiply and divide. */
+
+char *buffer; /* Address of buffer used for reading numbers */
+int bufsize; /* Current size of buffer (made bigger when nec) */
+
+decimal dec_read ();
+regstack get_regstack ();
+int fetch ();
+int fgetchar ();
+char *concat ();
+void pushsqrt ();
+void condop ();
+void setibase ();
+void setobase ();
+void setprecision ();
+void pushmacro ();
+decimal read_string ();
+void pushlength ();
+void pushscale ();
+void unfetch ();
+void popmacros ();
+void popmacro ();
+void popstack ();
+void print_obj ();
+void print_string ();
+void free_regstack ();
+void pushreg ();
+void execute ();
+void fputchar ();
+void push ();
+void incref ();
+void decref ();
+void binop ();
+
+main (argc, argv, env)
+ int argc;
+ char **argv, **env;
+{
+
+ ibase = 10;
+ obase = 10;
+ precision = 0;
+
+ freeregstacks = 0;
+
+ bzero (regs, sizeof regs);
+ bzero (regstacks, sizeof regstacks);
+
+ bufsize = 40;
+ buffer = (char *) xmalloc (40);
+
+ stacksize = 40;
+ stack = (decimal *) xmalloc (stacksize * sizeof (decimal));
+ stacktop = -1;
+
+ macrostacksize = 40;
+ macrostack = (decimal *) xmalloc (macrostacksize * sizeof (decimal));
+ macroindex = (int *) xmalloc (macrostacksize * sizeof (int));
+ macrolevel = 0;
+ /* Initialize for reading input files if any */
+
+ open_file = 0;
+
+ file_count = argc - 1;
+ next_file = argv + 1;
+
+
+ while (1)
+ {
+ execute ();
+ }
+}
+
+/* Read and execute one command from the current source of input */
+
+void
+execute ()
+{
+ int c = fetch ();
+
+ if (c < 0) exit (0);
+
+ {
+ switch (c)
+ {
+ case '+': /* Arithmetic operators... */
+ binop (decimal_add);
+ break;
+
+ case '-':
+ binop (decimal_sub);
+ break;
+
+ case '*':
+ binop (decimal_mul_dc); /* Like decimal_mul but hairy
+ way of deciding precision to keep */
+ break;
+
+ case '/':
+ binop (decimal_div);
+ break;
+
+ case '%':
+ binop (decimal_rem);
+ break;
+
+ case '^':
+ binop (decimal_expt);
+ break;
+
+ case '_': /* Begin a negative decimal constant */
+ {
+ decimal tem = dec_read (stdin);
+ tem->sign = !tem->sign;
+ push (tem);
+ }
+ break;
+
+ case '.':
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9': /* All these begin decimal constants */
+ unfetch (c);
+ push (dec_read (stdin));
+ break;
+
+ case 'A':
+ case 'B':
+ case 'C':
+ case 'D':
+ case 'E':
+ case 'F':
+ unfetch (c);
+ push (dec_read (stdin));
+ break;
+
+ case 'c': /* Clear the stack */
+ while (stacktop >= 0)
+ decref (stack[stacktop--]);
+ break;
+
+ case 'd': /* Duplicate top of stack */
+ if (stacktop < 0)
+ error ("stack empty", 0);
+ else push (stack[stacktop]);
+ break;
+
+ case 'f': /* Describe all registers and stack contents */
+ {
+ int regno;
+ int somereg = 0; /* set to 1 if we print any registers */
+ for (regno = 0; regno < 128; regno++)
+ {
+ if (regs[regno])
+ {
+ printf ("register %c: ", regno);
+ print_obj (regs[regno]);
+ somereg = 1;
+ printf ("\n");
+ }
+ }
+ if (somereg)
+ printf ("\n");
+ if (stacktop < 0)
+ printf ("stack empty\n");
+ else
+ {
+ int i;
+ printf ("stack:\n");
+ for (i = 0; i <= stacktop; i++)
+ {
+ print_obj (stack[stacktop - i]);
+ printf ("\n");
+ }
+ }
+ }
+ break;
+
+ case 'i': /* ibase <- top of stack */
+ popstack (setibase);
+ break;
+
+ case 'I': /* Push current ibase */
+ push (decimal_from_int (ibase));
+ break;
+
+ case 'k': /* like i, I but for precision instead of ibase */
+ popstack (setprecision);
+ break;
+
+ case 'K':
+ push (decimal_from_int (precision));
+ break;
+
+ case 'l': /* l<x> load register <x> onto stack */
+ {
+ char c1 = fetch ();
+ if (c1 < 0) exit (0);
+ if (!regs[c1])
+ error ("register %c empty", c1);
+ else
+ push (regs[c1]);
+ }
+ break;
+
+ case 'L': /* L<x> load register <x> to stack, pop <x>'s own stack */
+ {
+ char c1 = fetch ();
+ if (c1 < 0) exit (0);
+ if (!regstacks[c1])
+ error ("nothing pushed on register %c", c1);
+ else
+ {
+ regstack r = regstacks[c1];
+ if (!regs[c1])
+ error ("register %c empty after pop", c1);
+ else
+ push (regs[c1]);
+ regs[c1] = r->value;
+ regstacks[c1] = r->rest;
+ free_regstack (r);
+ }
+ }
+ break;
+
+ case 'o': /* o, O like i, I but for obase instead of ibase */
+ popstack (setobase);
+ break;
+
+ case 'O':
+ push (decimal_from_int (obase));
+ break;
+
+ case 'p': /* Print tos, don't pop, do print newline afterward */
+ if (stacktop < 0)
+ error ("stack empty", 0);
+ else
+ {
+ print_obj (stack[stacktop]);
+ printf ("\n");
+ }
+ break;
+
+ case 'P': /* Print tos, do pop, no newline afterward */
+ popstack (print_obj);
+ break;
+
+ case 'q': /* Exit */
+ if (macrolevel)
+ { popmacro (); popmacro (); } /* decrease recursion level by 2 */
+ else
+ exit (0); /* If not in a macro, exit the program. */
+
+ break;
+
+ case 'Q': /* Tos says how many levels to exit */
+ popstack (popmacros);
+ break;
+
+ case 's': /* s<x> -- Pop stack and set register <x> */
+ if (stacktop < 0)
+ empty ();
+ else
+ {
+ int c1 = fetch ();
+ if (c1 < 0) exit (0);
+ if (regs[c1]) decref (regs[c1]);
+ regs[c1] = stack[stacktop--];
+ }
+ break;
+
+ case 'S': /* S<x> -- pop stack and push as new value of register <x> */
+ if (stacktop < 0)
+ empty ();
+ else
+ {
+ int c1 = fetch ();
+ if (c1 < 0) exit (0);
+ pushreg (c1);
+ regs[c1] = stack[stacktop--];
+ }
+ break;
+
+ case 'v': /* tos gets square root of tos */
+ popstack (pushsqrt);
+ break;
+
+ case 'x': /* pop stack , call as macro */
+ popstack (pushmacro);
+ break;
+
+ case 'X': /* Pop stack, get # fraction digits, push that */
+ popstack (pushscale);
+ break;
+
+ case 'z': /* Compute depth of stack, push that */
+ push (decimal_from_int (stacktop + 1));
+ break;
+
+ case 'Z': /* Pop stack, get # digits, push that */
+ popstack (pushlength);
+ break;
+
+ case '<': /* Conditional: pop two numbers, compare, maybe execute register */
+ /* Note: for no obvious reason, the standard Unix `dc'
+ considers < to be true if the top of stack is less
+ than the next-to-top of stack,
+ and vice versa for >.
+ This seems backwards to me, but I am preserving compatibility. */
+ condop (1);
+ break;
+
+ case '>':
+ condop (-1);
+ break;
+
+ case '=':
+ condop (0);
+ break;
+
+ case '?': /* Read expression from terminal and execute it */
+ /* First ignore any leading newlines */
+ {
+ int c1;
+ while ((c1 = getchar ()) == '\n');
+ ungetc (c1, stdin);
+ }
+ /* Read a line from the terminal and execute it. */
+ pushmacro (read_string ('\n', fgetchar, 0));
+ break;
+
+ case '[': /* Begin string constant */
+ push (read_string (']', fetch, '['));
+ break;
+
+ case ' ':
+ case '\n':
+ break;
+
+ default:
+ error ("undefined command %c", c);
+ }
+ }
+}
+
+/* Functionals for performing arithmetic, etc */
+
+/* Call the function `op', with the top of stack value as argument,
+ and then pop the stack.
+ If the stack is empty, print a message and do not call `op'. */
+
+void
+popstack (op)
+ void (*op) ();
+{
+ if (stacktop < 0)
+ empty ();
+ else
+ {
+ decimal value = stack[stacktop--];
+ op (value);
+ decref (value);
+ }
+}
+
+/* Call the function `op' with two arguments taken from the stack top,
+ then pop those arguments and push the value returned by `op'.
+ `op' is assumed to return a decimal number.
+ If there are not two values on the stack, print a message
+ and do not call `op'. */
+
+void
+binop (op)
+ decimal (*op) ();
+{
+ if (stacktop < 1)
+ error ("stack empty", 0);
+ else if (stack[stacktop]->after == STRING || stack[stacktop - 1]->after == STRING)
+ error ("operands not both numeric");
+ else
+ {
+ decimal arg2 = stack [stacktop--];
+ decimal arg1 = stack [stacktop--];
+
+ push (op (arg1, arg2, precision));
+
+ decref (arg1);
+ decref (arg2);
+ }
+}
+
+void
+condop (cond)
+ int cond;
+{
+ int regno = fetch ();
+ if (!regs[regno])
+ error ("register %c is empty", regno);
+ else if (stacktop < 1)
+ empty ();
+ else
+ {
+ decimal arg2 = stack[stacktop--];
+ decimal arg1 = stack[stacktop--];
+ int relation = decimal_compare (arg1, arg2);
+ decref (arg1);
+ decref (arg2);
+ if (cond == relation
+ || (cond < 0 && relation < 0)
+ || (cond > 0 && relation > 0))
+ pushmacro (regs[regno]);
+ }
+}
+
+/* Handle the command input source */
+
+/* Fetch the next command character from a macro or from the terminal */
+
+int
+fetch()
+{
+ int c = -1;
+
+ while (macrolevel &&
+ LENGTH (macrostack[macrolevel-1]) == macroindex[macrolevel-1])
+ popmacro();
+ if (macrolevel)
+ return macrostack[macrolevel - 1]->contents[macroindex[macrolevel-1]++];
+ while (1)
+ {
+ if (open_file)
+ {
+ c = getc (open_file);
+ if (c >= 0) break;
+ fclose (open_file);
+ open_file = 0;
+ }
+ else if (file_count)
+ {
+ open_file = fopen (*next_file++, "r");
+ file_count--;
+ if (!open_file)
+ perror_with_name (*(next_file - 1));
+ }
+ else break;
+ }
+ if (c >= 0) return c;
+ return getc (stdin);
+}
+
+/* Unread character c on command input stream, whatever it is */
+
+void
+unfetch (c)
+ char c;
+{
+ if (macrolevel)
+ macroindex[macrolevel-1]--;
+ else if (open_file)
+ ungetc (c, open_file);
+ else
+ ungetc (c, stdin);
+}
+
+/* Begin execution of macro m. */
+
+void
+pushmacro (m)
+ decimal m;
+{
+ while (macrolevel &&
+ LENGTH (macrostack[macrolevel-1]) == macroindex[macrolevel-1])
+ popmacro();
+ if (m->after == STRING)
+ {
+ if (macrolevel == macrostacksize)
+ {
+ macrostacksize *= 2;
+ macrostack = (decimal *) xrealloc (macrostack, macrostacksize * sizeof (decimal));
+ macroindex = (int *) xrealloc (macroindex, macrostacksize * sizeof (int));
+ }
+ macroindex[macrolevel] = 0;
+ macrostack[macrolevel++] = m;
+ incref (m);
+ }
+ else
+ { /* Number supplied as a macro! */
+ push (m); /* Its effect wouyld be to push the number. */
+ }
+}
+
+/* Pop a specified number of levels of macro execution.
+ The number of levels is specified by a decimal number d. */
+
+void
+popmacros (d)
+ decimal d;
+{
+ int num_pops = decimal_to_int (d);
+ int i;
+ for (i = 0; i < num_pops; i++)
+ popmacro ();
+}
+/* Exit one level of macro execution. */
+
+void
+popmacro ()
+{
+ if (!macrolevel)
+ exit (0);
+ else
+ {
+ decref (macrostack[--macrolevel]);
+ }
+}
+
+void
+push (d)
+ decimal d;
+{
+ if (stacktop == stacksize - 1)
+ stack = (decimal *) xrealloc (stack, (stacksize *= 2) * sizeof (decimal));
+
+ incref (d);
+
+ stack[++stacktop] = d;
+}
+
+/* Reference counting and storage freeing */
+
+void
+decref (d)
+ decimal d;
+{
+ if (!--d->refcnt)
+ free (d);
+}
+
+void
+incref (d)
+ decimal d;
+{
+ d->refcnt++;
+}
+
+empty ()
+{
+ error ("stack empty", 0);
+}
+
+regstack
+get_regstack ()
+{
+ if (freeregstacks)
+ {
+ regstack r = freeregstacks;
+ freeregstacks = r ->rest;
+ return r;
+ }
+ else
+ return (regstack) xmalloc (sizeof (struct regstack));
+}
+
+void
+free_regstack (r)
+ regstack r;
+{
+ r->rest = freeregstacks;
+ freeregstacks = r;
+}
+
+void
+pushreg (c)
+ char c;
+{
+ regstack r = get_regstack ();
+
+ r->rest = regstacks[c];
+ r->value = regs[c];
+ regstacks[c] = r;
+ regs[c] = 0;
+}
+
+/* Input of numbers and strings */
+
+/* Return a character read from the terminal. */
+
+fgetchar ()
+{
+ return getchar ();
+}
+
+void
+fputchar (c)
+ char (c);
+{
+ putchar (c);
+}
+
+/* Read text from command input source up to a close-bracket,
+ make a string out of it, and return it.
+ If STARTC is nonzero, then it and STOPC must balance when nested. */
+
+decimal
+read_string (stopc, inputfn, startc)
+ char stopc;
+ int (*inputfn) ();
+ int startc;
+{
+ int c;
+ decimal result;
+ int i = 0;
+ int count = 0;
+
+ while (1)
+ {
+ c = inputfn ();
+ if (c < 0 || (c == stopc && count == 0))
+ {
+ if (count != 0)
+ error ("Unmatched `%c'", startc);
+ break;
+ }
+ if (c == stopc)
+ count--;
+ if (c == startc)
+ count++;
+ if (i + 1 >= bufsize)
+ buffer = (char *) xrealloc (buffer, bufsize *= 2);
+ buffer[i++] = c;
+ }
+ result = make_decimal (i, 0);
+ result->after = -1; /* Mark it as a string */
+ result->before++; /* but keep the length unchanged */
+ bcopy (buffer, result->contents, i);
+ return result;
+}
+
+/* Read a number from the current input source */
+
+decimal
+dec_read ()
+{
+ int c;
+ int i = 0;
+
+ while (1)
+ {
+ c = fetch ();
+ if (! ((c >= '0' && c <= '9')
+ || (c >= 'A' && c <= 'F')
+ || c == '.'))
+ break;
+ if (i + 1 >= bufsize)
+ buffer = (char *) xrealloc (buffer, bufsize *= 2);
+ buffer[i++] = c;
+ }
+ buffer[i++] = 0;
+ unfetch (c);
+
+ return decimal_parse (buffer, ibase);
+}
+
+/* Output of numbers and strings */
+
+/* Print the contents of obj, either numerically or as a string,
+ according to what obj says it is. */
+
+void
+print_obj (obj)
+ decimal obj;
+{
+ if (obj->after == STRING)
+ print_string (obj);
+ else
+ decimal_print (obj, fputchar, obase);
+}
+
+/* Print the contents of the decimal number `string', treated as a string. */
+
+void
+print_string (string)
+ decimal string;
+{
+ char *p = string->contents;
+ int len = LENGTH (string);
+ int i;
+
+ for (i = 0; i < len; i++)
+ {
+ putchar (*p++);
+ }
+}
+
+/* Set the input radix from the value of the decimal number d, if valid. */
+
+void
+setibase (d)
+ decimal d;
+{
+ int value = decimal_to_int (d);
+ if (value < 2 || value > 36)
+ error ("input radix must be from 2 to 36", 0);
+ else
+ ibase = value;
+}
+
+/* Set the output radix from the value of the decimal number d, if valid. */
+
+void
+setobase (d)
+ decimal d;
+{
+ int value = decimal_to_int (d);
+ if (value < 2 || value > 36)
+ error ("output radix must be from 2 to 36", 0);
+ else
+ obase = value;
+}
+
+/* Set the precision for mul and div from the value of the decimal number d, if valid. */
+
+void
+setprecision (d)
+ decimal d;
+{
+ int value = decimal_to_int (d);
+ if (value < 0 || value > 30000)
+ error ("precision must be nonnegative and < 30000", 0);
+ else
+ precision = value;
+}
+
+/* Push the number of digits in decimal number d, as a decimal number. */
+
+void
+pushlength (d)
+ decimal d;
+{
+ push (decimal_from_int (LENGTH (d)));
+}
+
+/* Push the number of fraction digits in d. */
+
+void
+pushscale (d)
+ decimal d;
+{
+ push (decimal_from_int (d->after));
+}
+
+/* Push the square root of decimal number d. */
+
+void
+pushsqrt (d)
+ decimal d;
+{
+ push (decimal_sqrt (d, precision));
+}
+
+/* Print error message and exit. */
+
+fatal (s1, s2)
+ char *s1, *s2;
+{
+ error (s1, s2);
+ exit (1);
+}
+
+/* Print error message. `s1' is printf control string, `s2' is arg for it. */
+
+error (s1, s2)
+ char *s1, *s2;
+{
+ printf ("dc: ");
+ printf (s1, s2);
+ printf ("\n");
+}
+
+decimal_error (s1, s2)
+ char *s1, *s2;
+{
+ error (s1, s2);
+}
+
+perror_with_name (name)
+ char *name;
+{
+ extern int errno, sys_nerr;
+ char *s;
+
+ if (errno < sys_nerr)
+ s = concat ("", sys_errlist[errno], " for %s");
+ else
+ s = "cannot open %s";
+ error (s, name);
+}
+
+/* Return a newly-allocated string whose contents concatenate those of s1, s2, s3. */
+
+char *
+concat (s1, s2, s3)
+ char *s1, *s2, *s3;
+{
+ int len1 = strlen (s1), len2 = strlen (s2), len3 = strlen (s3);
+ char *result = (char *) xmalloc (len1 + len2 + len3 + 1);
+
+ strcpy (result, s1);
+ strcpy (result + len1, s2);
+ strcpy (result + len1 + len2, s3);
+ *(result + len1 + len2 + len3) = 0;
+
+ return result;
+}
+
+/* Like malloc but get fatal error if memory is exhausted. */
+
+int
+xmalloc (size)
+ int size;
+{
+ int result = malloc (size);
+ if (!result)
+ fatal ("virtual memory exhausted", 0);
+ return result;
+}
+
+int
+xrealloc (ptr, size)
+ char *ptr;
+ int size;
+{
+ int result = realloc (ptr, size);
+ if (!result)
+ fatal ("virtual memory exhausted");
+ return result;
+}
diff --git a/gnu/usr.bin/dc/decimal.c b/gnu/usr.bin/dc/decimal.c
new file mode 100644
index 0000000..780de29
--- /dev/null
+++ b/gnu/usr.bin/dc/decimal.c
@@ -0,0 +1,1235 @@
+/*
+ * Arbitrary precision decimal arithmetic.
+ *
+ * Copyright (C) 1984 Free Software Foundation, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, you can either send email to this
+ * program's author (see below) or write to: The Free Software Foundation,
+ * Inc.; 675 Mass Ave. Cambridge, MA 02139, USA.
+ */
+
+/* Some known problems:
+
+ Another problem with decimal_div is found when you try to
+ divide a number with > scale fraction digits by 1. The
+ expected result is simply truncation, but all sorts of things
+ happen instead. An example is that the result of .99999998/1
+ with scale set to 6 is .000001
+
+ There are some problems in the behavior of the decimal package
+ related to printing and parsing. The
+ printer is weird about very large output radices, tending to want
+ to output single ASCII characters for any and all digits (even
+ in radices > 127). The UNIX bc approach is to print digit groups
+ separated by spaces. There is a rather overwrought workaround in
+ the function decputc() in bcmisc.c, but it would be better if
+ decimal.c got a fix for this. */
+
+/* For stand-alone testing, compile with -DTEST.
+ This DTESTable feature defines a `main' function
+ which is a simple loop that accepts input of the form
+ number space op space number newline
+ where op is +, -, *, /, %, p or r,
+ and performs the operation and prints the operands and result.
+ `p' means print the first number in the radix spec'd by the second.
+ `r' means read the first one in the radix specified by the second
+ (and print the result in decimal).
+ Divide in this test keeps three fraction digits. */
+
+#include "decimal.h"
+
+#define MAX(a, b) (((a) > (b) ? (a) : (b)))
+
+/* Some constant decimal numbers */
+
+struct decimal decimal_zero = {0, 0, 0, 0, 0};
+
+struct decimal decimal_one = {0, 0, 1, 0, 1};
+
+/*** Assumes RADIX is even ***/
+struct decimal decimal_half = {0, 1, 0, 0, RADIX / 2};
+
+decimal static decimal_add1 (), decimal_sub1 ();
+static void add_scaled ();
+static int subtract_scaled ();
+
+/* Create and return a decimal number that has `before' digits before
+ the decimal point and `after' digits after. The digits themselves are
+ initialized to zero. */
+
+decimal
+make_decimal (before, after)
+ int before, after;
+{
+ decimal result;
+ if (before >= 1<<16)
+ {
+ decimal_error ("%d too many decimal digits", before);
+ return 0;
+ }
+ if (after >= 1<<15)
+ {
+ decimal_error ("%d too many decimal digits", after);
+ return 0;
+ }
+ result = (decimal) malloc (sizeof (struct decimal) + before + after - 1);
+ result->sign = 0;
+ result->before = before;
+ result->after = after;
+ result->refcnt = 0;
+ bzero (result->contents, before + after);
+ return result;
+}
+
+/* Create a copy of the decimal number `b' and return it. */
+
+decimal
+decimal_copy (b)
+ decimal b;
+{
+ decimal result = make_decimal (b->before, b->after);
+ bcopy (b->contents, result->contents, LENGTH(b));
+ result->sign = b->sign;
+ return result;
+}
+
+/* Copy a decimal number `b' but extend or truncate to exactly
+ `digits' fraction digits. */
+
+static decimal
+decimal_copy_1 (b, digits)
+ decimal b;
+ int digits;
+{
+ if (digits > b->after)
+ {
+ decimal result = make_decimal (b->before, digits);
+ bcopy (b->contents, result->contents + (digits - (int) b->after), LENGTH(b));
+ return result;
+ }
+ else
+ return decimal_trunc_digits (b, digits);
+}
+
+/* flush specified number `digits' of trailing fraction digits,
+ and flush any trailing fraction zero digits exposed after they are gone.
+ The number `b' is actually modified; no new storage is allocated.
+ That is why this is not global. */
+
+static void
+flush_trailing_digits (b, digits)
+ decimal b;
+ int digits;
+{
+ int flush = digits;
+ int maxdig = b->after;
+
+ while (flush < maxdig && !b->contents [flush])
+ flush++;
+
+ if (flush)
+ {
+ int i;
+
+ b->after -= flush;
+ for (i = 0; i < LENGTH (b); i++)
+ b->contents[i] = b->contents[flush + i];
+ }
+
+}
+
+/* Return nonzero integer if the value of decimal number `b' is zero. */
+
+int
+decimal_zerop (b)
+ decimal b;
+{
+ return !LENGTH(b);
+}
+
+/* Compare two decimal numbers arithmetically.
+ The value is < 0 if b1 < b2, > 0 if b1 > b2, 0 if b1 = b2.
+ This is the same way that `strcmp' reports the result of comparing
+ strings. */
+
+int
+decimal_compare (b1, b2)
+ decimal b1, b2;
+{
+ int l1, l2;
+ char *p1, *p2, *s1, *s2;
+ int i;
+
+ /* If signs differ, deduce result from the signs */
+
+ if (b2->sign && !b1->sign) return 1;
+ if (b1->sign && !b2->sign) return -1;
+
+ /* If same sign but number of nonfraction digits differs,
+ the one with more of them is farther from zero. */
+
+ if (b1->before != b2->before)
+ if (b1->sign)
+ return (int) (b2->before - b1->before);
+ else
+ return (int) (b1->before - b2->before);
+
+ /* Else compare the numbers digit by digit from high end */
+ l1 = LENGTH(b1);
+ l2 = LENGTH(b2);
+ s1 = b1->contents; /* Start of number -- don't back up digit pointer past here */
+ s2 = b2->contents;
+ p1 = b1->contents + l1; /* Scanning pointer, for fetching digits. */
+ p2 = b2->contents + l2;
+ for (i = MAX(l1, l2); i >= 0; i--)
+ {
+ int r = ((p1 != s1) ? *--p1 : 0) - ((p2 != s2) ? *--p2 : 0);
+ if (r)
+ return b1->sign ? -r : r;
+ }
+ return 0;
+}
+
+/* Return the number of digits stored in decimal number `b' */
+
+int
+decimal_length (b)
+ decimal b;
+{
+ return LENGTH(b);
+}
+
+/* Return the number of fraction digits stored in decimal number `b'. */
+
+int
+decimal_after (b)
+ decimal b;
+{
+ return b->after;
+}
+
+/* Round decimal number `b' to have only `digits' fraction digits.
+ Result is rounded to nearest unit in the last remaining digit.
+ Return the result, another decimal number. */
+
+decimal
+decimal_round_digits (b, digits)
+ decimal b;
+ int digits;
+{
+ decimal result;
+ int old;
+
+ if (b->after <= digits) return decimal_copy (b);
+
+ if (digits < 0)
+ {
+ decimal_error ("request to keep negative number of digits %d", digits);
+ return decimal_copy (b);
+ }
+
+ result = make_decimal (b->before + 1, b->after);
+ result->sign = b->sign;
+ bcopy (b->contents, result->contents, LENGTH(b));
+
+ old = result->after;
+
+ /* Add .5 * last place to keep, so that we round rather than truncate */
+ /* Note this ignores sign of result, so if result is negative
+ it is subtracting */
+
+ add_scaled (result, DECIMAL_HALF, 1, old - digits - 1);
+
+ /* Flush desired digits, and any trailing zeros exposed by them. */
+
+ flush_trailing_digits (result, old - digits);
+
+ /* Flush leading digits -- always is one, unless was a carry into it */
+
+ while (result->before > 0
+ && result->contents[LENGTH(result) - 1] == 0)
+ result->before--;
+
+ return result;
+}
+
+/* Truncate decimal number `b' to have only `digits' fraction digits.
+ Any fraction digits in `b' beyond that are dropped and ignored.
+ Truncation is toward zero.
+ Return the result, another decimal number. */
+
+decimal
+decimal_trunc_digits (b, digits)
+ decimal b;
+ int digits;
+{
+ decimal result = decimal_copy (b);
+ int old = result->after;
+
+ if (old <= digits) return result;
+
+ if (digits < 0)
+ {
+ decimal_error ("request to keep negative number of digits %d", digits);
+ return result;
+ }
+
+ flush_trailing_digits (result, old - digits);
+
+ return result;
+}
+
+/* Return the fractional part of decimal number `b':
+ that is, `b' - decimal_trunc_digits (`b') */
+
+decimal
+decimal_fraction (b)
+ decimal b;
+{
+ decimal result = make_decimal (0, b->after);
+ bcopy (b->contents, result->contents, b->after);
+ return result;
+}
+
+/* return an integer whose value is that of decimal `b', sans its fraction. */
+
+int
+decimal_to_int (b)
+ decimal b;
+{
+ int result = 0;
+ int i;
+ int end = b->after;
+
+ for (i = LENGTH(b) - 1; i >= end; i--)
+ {
+ result *= RADIX;
+ result += b->contents[i];
+ }
+ return result;
+}
+
+/* return a decimal whose value is the integer i. */
+
+decimal
+decimal_from_int (i)
+ int i;
+{
+ int log, tem;
+ decimal result;
+
+ for (log = 0, tem = (i > 0 ? i : - i); tem; log++, tem /= RADIX);
+
+ result = make_decimal (log, 0);
+
+ for (log = 0, tem = (i > 0 ? i : - i); tem; log++, tem /= RADIX)
+ result->contents[log] = tem % RADIX;
+
+ if (i < 0) result->sign = 1;
+ return result;
+}
+
+/* Return (as an integer) the result of dividing decimal number `b' by
+ integer `divisor'.
+ This is used in printing decimal numbers in other radices. */
+
+int
+decimal_int_rem (b, divisor)
+ decimal b;
+ int divisor;
+{
+ int len = LENGTH(b);
+ int end = b->after;
+ int accum = 0;
+ int i;
+
+ for (i = len - 1; i >= end; i--)
+ {
+ accum %= divisor;
+ accum *= RADIX;
+ accum += b->contents[i];
+ }
+ return accum % divisor;
+}
+
+/* Convert digit `digit' to a character and output it by calling
+ `charout' with it as arg. */
+
+static void
+print_digit (digit, charout)
+ int digit;
+ void (*charout) ();
+{
+ if (digit < 10)
+ charout ('0' + digit);
+ else
+ charout ('A' + digit - 10);
+}
+
+/* print decimal number `b' in radix `radix', assuming it is an integer.
+ `r' is `radix' expressed as a decimal number. */
+
+static
+decimal_print_1 (b, r, radix, charout)
+ decimal b, r;
+ int radix;
+ void (*charout) ();
+{
+ int digit = decimal_int_rem (b, radix);
+ decimal rest = decimal_div (b, r, 0);
+
+ if (!decimal_zerop (rest))
+ decimal_print_1 (rest, r, radix, charout);
+
+ print_digit (digit, charout);
+
+ free (rest);
+}
+
+/* User entry: print decimal number `b' in radix `radix' (an integer),
+ outputting characters by calling `charout'. */
+
+void
+decimal_print (b, charout, radix)
+ decimal b;
+ void (*charout) ();
+ int radix;
+{
+ if (b->sign) charout ('-');
+
+ if (radix == RADIX)
+ {
+ /* decimal output => just print the digits, inserting a point in
+ the proper place. */
+ int i;
+ int before = b->before;
+ int len = before + b->after;
+ for (i = 0; i < len; i++)
+ {
+ if (i == before) charout ('.');
+ /* Broken if RADIX /= 10
+ charout ('0' + b->contents [len - 1 - i]); */
+ print_digit (b->contents [len - 1 - i], charout);
+ }
+ if (!len)
+ charout ('0');
+ }
+ else
+ {
+ /* nonstandard radix: must use multiply and divide to determine the
+ digits of the number in that radix. */
+
+ int i;
+ extern double log10 ();
+ /* Compute the number of fraction digits we want to have in the
+ new radix. They should contain the same amount of
+ information as the decimal digits we have. */
+ int nfrac = (b->after / log10 ((double) radix) + .99);
+ decimal r = decimal_from_int (radix);
+ decimal intpart = decimal_trunc_digits (b, 0);
+
+ /* print integer part */
+ decimal_print_1 (intpart, r, radix, charout);
+ free (intpart);
+
+ /* print fraction part */
+ if (nfrac)
+ {
+ decimal tem1, tem2;
+ tem1 = decimal_fraction (b);
+ charout ('.');
+ /* repeatedly multiply by `radix', print integer part as one digit,
+ and flush the integer part. */
+ for (i = 0; i < nfrac; i++)
+ {
+ tem2 = decimal_mul (tem1, r);
+ free (tem1);
+ print_digit (decimal_to_int (tem2), charout);
+ tem1 = decimal_fraction (tem2);
+ free (tem2);
+ }
+ free (tem1);
+ }
+ free (r);
+ }
+}
+
+static int
+decode_digit (digitchar)
+ char digitchar;
+{
+ if ('0' <= digitchar && digitchar <= '9')
+ return digitchar - '0';
+ if ('a' <= digitchar && digitchar <= 'z')
+ return digitchar - 'a' + 10;
+ if ('A' <= digitchar && digitchar <= 'Z')
+ return digitchar - 'A' + 10;
+ return -1;
+}
+
+/* Parse string `s' into a number using radix `radix'
+ and return result as a decimal number. */
+
+decimal
+decimal_parse (s, radix)
+ char *s;
+ int radix;
+{
+ int i, len, before = -1;
+ char *p;
+ char c;
+ decimal result;
+ int negative = 0;
+ int excess_digit = 0;
+
+ if (*s == '-')
+ {
+ s++;
+ negative = 1;
+ }
+
+ /* First scan for valid characters.
+ Count total num digits, and count num before the decimal point. */
+
+ p = s;
+ i = 0;
+ while (c = *p++)
+ {
+ if (c == '.')
+ {
+ if (before >= 0)
+ decimal_error ("two decimal points in %s", s);
+ before = i;
+ }
+ else if (c == '0' && !i && before < 0)
+ s++; /* Discard leading zeros */
+ else if (decode_digit (c) >= 0)
+ {
+ i++;
+ if (decode_digit (c) > RADIX)
+ excess_digit = 1;
+ }
+ else
+ decimal_error ("invalid number %s", s);
+ }
+
+ len = i;
+ if (before < 0) before = i;
+
+ p = s;
+
+ /* Now parse those digits */
+
+ if (radix != RADIX || excess_digit)
+ {
+ decimal r = decimal_from_int (radix);
+ extern double log10 ();
+ int digits = (len - before) * log10 ((double) radix) + .99;
+ result = decimal_copy (DECIMAL_ZERO);
+
+ /* Parse all the digits into an integer, ignoring decimal point,
+ by multiplying by `radix'. */
+
+ while (i > 0 && (c = *p++))
+ {
+ if (c != '.')
+ {
+ decimal newdig = decimal_from_int (decode_digit (c));
+ decimal prod = decimal_mul (result, r);
+ decimal newresult = decimal_add (newdig, prod);
+
+ free (newdig); free (prod); free (result);
+ result = newresult;
+ i--;
+ }
+ }
+
+ /* Now put decimal point in right place
+ by dividing by `radix' once for each digit
+ that really should have followed the decimal point. */
+
+ for (i = before; i < len; i++)
+ {
+ decimal newresult = decimal_div (result, r, digits);
+ free (result);
+ result = newresult;
+ }
+ free (r);
+ }
+ else
+ {
+ /* radix is standard - just copy the digits into a decimal number. */
+
+ int tem;
+ result = make_decimal (before, len - before);
+
+ while (i > 0 && (c = *p++))
+ {
+ if ((c != '.') &&
+ ((tem = decode_digit (c)) >= 0))
+ result->contents [--i] = tem;
+ }
+ }
+
+ if (negative) result->sign = 1;
+ flush_trailing_digits (result, 0);
+ return result;
+}
+
+/* Add b1 and b2, considering their signs */
+
+decimal
+decimal_add (b1, b2)
+ decimal b1, b2;
+{
+ decimal v;
+
+ if (b1->sign != b2->sign)
+ v = decimal_sub1 (b1, b2);
+ else
+ v = decimal_add1 (b1, b2);
+ if (b1->sign && !decimal_zerop (v))
+ v->sign = !v->sign;
+ return v;
+}
+
+/* Add b1 and minus b2, considering their signs */
+
+decimal
+decimal_sub (b1, b2)
+ decimal b1, b2;
+{
+ decimal v;
+
+ if (b1->sign != b2->sign)
+ v = decimal_add1 (b1, b2);
+ else
+ v = decimal_sub1 (b1, b2);
+ if (b1->sign && !decimal_zerop (v))
+ v->sign = !v->sign;
+ return v;
+}
+
+/* Return the negation of b2. */
+
+decimal
+decimal_neg (b2)
+ decimal b2;
+{
+ decimal v = decimal_copy (b2);
+
+ if (!decimal_zerop (v))
+ v->sign = !v->sign;
+ return v;
+}
+
+/* add magnitudes of b1 and b2, ignoring their signs. */
+
+static decimal
+decimal_add1 (b1, b2)
+ decimal b1, b2;
+{
+ int before = MAX (b1->before, b2->before);
+ int after = MAX (b1->after, b2->after);
+
+ int len = before+after+1;
+ decimal result = make_decimal (before+1, after);
+
+ int i;
+ char *s1 = b1->contents;
+ char *s2 = b2->contents;
+ char *p1 = s1 + b1->after - after;
+ char *p2 = s2 + b2->after - after;
+ char *e1 = s1 + b1->before + b1->after;
+ char *e2 = s2 + b2->before + b2->after;
+ char *pr = result->contents;
+ int accum = 0;
+
+ for (i = 0; i < len; i++, p1++, p2++)
+ {
+ accum /= RADIX;
+ if (p1 >= s1 && p1 < e1) accum += *p1;
+ if (p2 >= s2 && p2 < e2) accum += *p2;
+ *pr++ = accum % RADIX;
+ }
+ if (!accum)
+ (result->before)--;
+
+ flush_trailing_digits (result, 0);
+
+ return result;
+}
+
+/* subtract magnitude of b2 from that or b1, returning signed decimal
+ number. */
+
+static decimal
+decimal_sub1 (b1, b2)
+ decimal b1, b2;
+{
+ int before = MAX (b1->before, b2->before);
+ int after = MAX (b1->after, b2->after);
+
+ int len = before+after;
+ decimal result = make_decimal (before, after);
+
+ int i;
+ char *s1 = b1->contents;
+ char *s2 = b2->contents;
+ char *p1 = s1 + b1->after - after;
+ char *p2 = s2 + b2->after - after;
+ char *e1 = s1 + b1->before + b1->after;
+ char *e2 = s2 + b2->before + b2->after;
+ char *pr = result->contents;
+ int accum = 0;
+
+ for (i = 0; i < len; i++, p1++, p2++)
+ {
+ if (p1 >= s1 && p1 < e1) accum += *p1;
+ if (p2 >= s2 && p2 < e2) accum -= *p2;
+ if (accum < 0 && accum % RADIX)
+ *pr = RADIX - (- accum) % RADIX;
+ else
+ *pr = accum % RADIX;
+ accum -= *pr++;
+ accum /= RADIX;
+ }
+
+ /* If result is negative, subtract it from RADIX**length
+ so that we get the right digits for sign-magnitude
+ rather than RADIX-complement */
+
+ if (accum)
+ {
+ result->sign = 1;
+ pr = result->contents;
+ accum = 0;
+ for (i = 0; i < len; i++)
+ {
+ accum -= *pr;
+ if (accum)
+ *pr = accum + RADIX;
+ else
+ *pr = 0;
+ accum -= *pr++;
+ accum /= RADIX;
+ }
+ }
+
+ /* flush leading nonfraction zero digits */
+
+ while (result->before && *--pr == 0)
+ (result->before)--;
+
+ flush_trailing_digits (result, 0);
+
+ return result;
+}
+
+/* multiply b1 and b2 keeping `digits' fraction digits */
+
+decimal
+decimal_mul_rounded (b1, b2, digits)
+ decimal b1, b2;
+ int digits;
+{
+ decimal tem = decimal_mul (b1, b2);
+ decimal result = decimal_round_digits (tem, digits);
+ free (tem);
+ return result;
+}
+
+/* multiply b1 and b2 keeping the right number of fraction digits
+ for the `dc' program with precision = `digits'. */
+
+decimal
+decimal_mul_dc (b1, b2, digits)
+ decimal b1, b2;
+ int digits;
+{
+ decimal tem = decimal_mul (b1, b2);
+ decimal result
+ = decimal_round_digits (tem, MAX (digits, MAX (b1->after, b2->after)));
+ free (tem);
+ return result;
+}
+
+/* multiply b1 and b2 as decimal error-free values;
+ keep LENGTH(b1) plus LENGTH(b2) significant figures. */
+
+decimal
+decimal_mul (b1, b2)
+ decimal b1, b2;
+{
+ decimal result = make_decimal (b1->before + b2->before, b1->after + b2->after);
+ int i;
+ int length2 = LENGTH(b2);
+ char *pr;
+
+ for (i = 0; i < length2; i++)
+ add_scaled (result, b1, b2->contents[i], i);
+
+ /* flush leading nonfraction zero digits */
+
+ pr = result->contents + LENGTH(result);
+ while (result->before && *--pr == 0)
+ (result->before)--;
+
+ flush_trailing_digits (result, 0); /* flush trailing zeros */
+
+ /* Set sign properly */
+
+ if (b1->sign != b2->sign && LENGTH(result))
+ result->sign = 1;
+
+ return result;
+}
+
+/* Modify decimal number `into' by adding `from',
+ multiplied by `factor' (which should be nonnegative and less than RADIX)
+ and shifted left `scale' digits at the least significant end. */
+
+static void
+add_scaled (into, from, factor, scale)
+ decimal into, from;
+ int factor, scale;
+{
+ char *pf = from->contents;
+ char *pi = into->contents + scale;
+ int lengthf = LENGTH(from);
+ int lengthi = LENGTH(into) - scale;
+
+ int accum = 0;
+ int i;
+
+ for (i = 0; i < lengthi; i++)
+ {
+ accum /= RADIX;
+ if (i < lengthf)
+ accum += *pf++ * factor;
+ accum += *pi;
+ *pi++ = accum % RADIX;
+ }
+}
+
+/* Divide decimal number `b1' by `b2', keeping at most `digits'
+ fraction digits.
+ Returns the result as a decimal number.
+
+ When division is not exact, the quotient is truncated toward zero. */
+
+decimal
+decimal_div (b1, b2, digits)
+ decimal b1, b2;
+ int digits;
+{
+ decimal result = make_decimal (MAX(1, (int) (1 + b1->before - b2->before)), digits);
+
+ /* b1copy holds what is left of the dividend,
+ that is not accounted for by the quotient digits already known */
+
+ decimal b1copy = decimal_copy_1 (b1, b2->after + digits);
+ int length1 = LENGTH(b1copy);
+ int length2 = LENGTH(b2);
+ int lengthr = LENGTH(result);
+ int i;
+
+ /* leading_divisor_digits contains the first two divisor digits, as
+ an integer */
+
+ int leading_divisor_digits = b2->contents[length2-1]*RADIX;
+ if (length2 > 1)
+ leading_divisor_digits += b2->contents[length2-2];
+
+ if (decimal_zerop (b2))
+ {
+ decimal_error ("divisor is zero", 0);
+ return decimal_copy (DECIMAL_ZERO);
+ }
+
+/* if (lengthr <= (length1 - length2))
+ abort(); */ /* My reasoning says this cannot happen, I hope */
+
+ for (i = length1 - length2; i >= 0; i--)
+ {
+ /* Guess the next quotient digit (in order of decreasing significance)
+ using integer division */
+
+ int guess;
+ int trial_dividend = b1copy->contents[length2+i-1]*RADIX;
+ if (i != length1 - length2)
+ trial_dividend += b1copy->contents[length2+i]*RADIX*RADIX;
+ if (length2 + i > 1)
+ trial_dividend += b1copy->contents[length2+i-2];
+
+ guess = trial_dividend / leading_divisor_digits;
+
+ /* Remove the quotient times this digit from the dividend left */
+ /* We may find that the quotient digit is too large,
+ when we consider the entire divisor.
+ Then we decrement the quotient digit and add the divisor back in */
+
+ if (guess && 0 > subtract_scaled (b1copy, b2, guess, i))
+ {
+ guess--;
+ add_scaled (b1copy, b2, 1, i);
+ }
+
+ if (guess >= RADIX)
+ {
+ result->contents[i + 1] += guess / RADIX;
+ guess %= RADIX;
+ }
+ result->contents[i] = guess;
+ }
+
+ free (b1copy);
+
+ result->sign = (b1->sign != b2->sign);
+
+ /* flush leading nonfraction zero digits */
+
+ {
+ char *pr = result->contents + lengthr;
+ while (result->before && *--pr == 0)
+ (result->before)--;
+ }
+
+ flush_trailing_digits (result, 0); /* Flush trailing zero fraction digits */
+
+ return result;
+}
+
+/* The remainder for the above division.
+ Same as `b1' - (`b1' / `b2') * 'b2'.
+ Note that the value depends on the number of fraction digits
+ that were kept in computing `b1' / `b2';
+ the argument `digits' specifies this.
+
+ The remainder has the same sign as the dividend.
+ The divisor's sign is ignored. */
+
+decimal
+decimal_rem (b1, b2, digits)
+ decimal b1, b2;
+ int digits;
+{
+ decimal b1copy = decimal_copy_1 (b1, b2->after + digits);
+ int length1 = LENGTH(b1copy);
+ int length2 = LENGTH(b2);
+ int i;
+
+ int leading_divisor_digits = b2->contents[length2-1]*RADIX;
+
+ if (length2 > 1)
+ leading_divisor_digits += b2->contents[length2-2];
+
+ if (decimal_zerop (b2))
+ {
+ decimal_error ("divisor is zero", 0);
+ return decimal_copy (DECIMAL_ZERO);
+ }
+
+ /* Do like division, above, but throw away the quotient.
+ Keep only the final `rest of dividend', which becomes the remainder. */
+
+ for (i = length1 - length2; i >= 0; i--)
+ {
+ int guess;
+ int trial_dividend = b1copy->contents[length2+i-1]*RADIX;
+ if (i != length1 - length2)
+ trial_dividend += b1copy->contents[length2+i]*RADIX*RADIX;
+ if (length2 + i > 1)
+ trial_dividend += b1copy->contents[length2+i-2];
+
+ guess = trial_dividend / leading_divisor_digits;
+
+ if (guess && 0 > subtract_scaled (b1copy, b2, guess, i))
+ {
+ guess--;
+ add_scaled (b1copy, b2, 1, i);
+ }
+ /* No need to check whether guess exceeds RADIX
+ since we are not saving guess. */
+ }
+
+ /* flush leading nonfraction zero digits */
+
+ {
+ char *pr = b1copy->contents + length1;
+ while (b1copy->before && *--pr == 0)
+ (b1copy->before)--;
+ }
+
+ flush_trailing_digits (b1copy, 0);
+ return b1copy;
+}
+
+/* returns negative number if we chose factor too large */
+
+static int
+subtract_scaled (into, from, factor, scale)
+ decimal into, from;
+ int factor, scale;
+{
+ char *pf = from->contents;
+ char *pi = into->contents + scale;
+ int lengthf = LENGTH(from);
+ int lengthi = LENGTH(into) - scale;
+ int accum = 0;
+ int i;
+
+ for (i = 0; i < lengthi && i <= lengthf; i++)
+ {
+ if (i < lengthf)
+ accum -= *pf++ * factor;
+ accum += *pi;
+ if (accum < 0 && accum % RADIX)
+ *pi = RADIX - (- accum) % RADIX;
+ else
+ *pi = accum % RADIX;
+ accum -= *pi++;
+ accum /= RADIX;
+ }
+ return accum;
+}
+
+/* Return the square root of decimal number D, using Newton's method.
+ Number of fraction digits returned is max of FRAC_DIGITS
+ and D's number of fraction digits. */
+
+decimal
+decimal_sqrt (d, frac_digits)
+ decimal d;
+ int frac_digits;
+{
+ decimal guess;
+ int notdone = 1;
+
+ if (decimal_zerop (d)) return d;
+ if (d->sign)
+ {
+ decimal_error ("square root argument negative", 0);
+ return decimal_copy (DECIMAL_ZERO);
+ }
+
+ frac_digits = MAX (frac_digits, d->after);
+
+ /* Compute an initial guess by taking the square root
+ of a nearby power of RADIX. */
+
+ if (d->before)
+ {
+ guess = make_decimal ((d->before + 1) / 2, 0);
+ guess->contents[guess->before - 1] = 1;
+ }
+ else
+ {
+ /* Arg is less than 1; compute nearest power of RADIX */
+ char *p = d->contents + LENGTH(d);
+ char *sp = p;
+
+ while (!*--p); /* Find most significant nonzero digit */
+ if (sp - p == 1)
+ {
+ /* Arg is bigger than 1/RADIX; use 1 as a guess */
+ guess = decimal_copy (DECIMAL_ONE);
+ }
+ else
+ {
+ guess = make_decimal (0, (sp - p) / 2);
+ guess->contents[0] = 1;
+ }
+ }
+
+ /* Iterate doing guess = (guess + d/guess) / 2 */
+
+ while (notdone)
+ {
+ decimal tem1 = decimal_div (d, guess, frac_digits + 1);
+ decimal tem2 = decimal_add (guess, tem1);
+ decimal tem3 = decimal_mul_rounded (tem2, DECIMAL_HALF, frac_digits);
+ notdone = decimal_compare (guess, tem3);
+ free (tem1);
+ free (tem2);
+ free (guess);
+ guess = tem3;
+ if (decimal_zerop (guess)) return guess; /* Avoid divide-by-zero */
+ }
+
+ return guess;
+}
+
+/* Raise decimal number `base' to power of integer part of decimal
+ number `expt'.
+ This function depends on using radix 10.
+ It is too hard to write it to work for any value of RADIX,
+ so instead it is simply not available if RADIX is not ten. */
+
+#if !(RADIX - 10)
+
+decimal
+decimal_expt (base, expt, frac_digits)
+ decimal base, expt;
+ int frac_digits;
+{
+ decimal accum = decimal_copy (DECIMAL_ONE);
+ decimal basis1 = base;
+ int digits = expt->before;
+ int dig = 0; /* Expt digit being processed */
+
+ if (expt->sign)
+ /* If negative power, take reciprocal first thing
+ so that fraction digit truncation won't destroy
+ what will ultimately be nonfraction digits. */
+ basis1 = decimal_div (DECIMAL_ONE, base, frac_digits);
+ while (dig < digits)
+ {
+ decimal basis2, basis4, basis8, basis10;
+ int thisdigit = expt->contents[expt->after + dig];
+
+ /* Compute factors to multiply in for each bit of this digit */
+
+ basis2 = decimal_mul_rounded (basis1, basis1, frac_digits);
+ basis4 = decimal_mul_rounded (basis2, basis2, frac_digits);
+ basis8 = decimal_mul_rounded (basis4, basis4, frac_digits);
+
+ /* Now accumulate the factors this digit value selects */
+
+ if (thisdigit & 1)
+ {
+ decimal accum1 = decimal_mul_rounded (accum, basis1, frac_digits);
+ free (accum);
+ accum = accum1;
+ }
+
+ if (thisdigit & 2)
+ {
+ decimal accum1 = decimal_mul_rounded (accum, basis2, frac_digits);
+ free (accum);
+ accum = accum1;
+ }
+
+ if (thisdigit & 4)
+ {
+ decimal accum1 = decimal_mul_rounded (accum, basis4, frac_digits);
+ free (accum);
+ accum = accum1;
+ }
+
+ if (thisdigit & 8)
+ {
+ decimal accum1 = decimal_mul_rounded (accum, basis8, frac_digits);
+ free (accum);
+ accum = accum1;
+ }
+
+ /* If there are further digits, compute the basis1 for the next digit */
+
+ if (++dig < digits)
+ basis10 = decimal_mul_rounded (basis2, basis8, frac_digits);
+
+ /* Free intermediate results */
+
+ if (basis1 != base) free (basis1);
+ free (basis2);
+ free (basis4);
+ free (basis8);
+ basis1 = basis10;
+ }
+ return accum;
+}
+#endif
+
+#ifdef TEST
+
+fputchar (c)
+ char c;
+{
+ putchar (c);
+}
+
+/* Top level that can be used to test the arithmetic functions */
+
+main ()
+{
+ char s1[40], s2[40];
+ decimal b1, b2, b3;
+ char c;
+
+ while (1)
+ {
+ scanf ("%s %c %s", s1, &c, s2);
+ b1 = decimal_parse (s1, RADIX);
+ b2 = decimal_parse (s2, RADIX);
+ switch (c)
+ {
+ default:
+ c = '+';
+ case '+':
+ b3 = decimal_add (b1, b2);
+ break;
+ case '*':
+ b3 = decimal_mul (b1, b2);
+ break;
+ case '/':
+ b3 = decimal_div (b1, b2, 3);
+ break;
+ case '%':
+ b3 = decimal_rem (b1, b2, 3);
+ break;
+ case 'p':
+ decimal_print (b1, fputchar, RADIX);
+ printf (" printed in base %d is ", decimal_to_int (b2));
+ decimal_print (b1, fputchar, decimal_to_int (b2));
+ printf ("\n");
+ continue;
+ case 'r':
+ printf ("%s read in base %d is ", s1, decimal_to_int (b2));
+ decimal_print (decimal_parse (s1, decimal_to_int (b2)), fputchar, RADIX);
+ printf ("\n");
+ continue;
+ }
+ decimal_print (b1, fputchar, RADIX);
+ printf (" %c ", c);
+ decimal_print (b2, fputchar, RADIX);
+ printf (" = ");
+ decimal_print (b3, fputchar, RADIX);
+ printf ("\n");
+ }
+}
+
+decimal_error (s1, s2)
+ char *s1, *s2;
+{
+ printf ("\n");
+ printf (s1, s2);
+ printf ("\n");
+}
+
+static void
+pbi (b)
+ int b;
+{
+ decimal_print ((decimal) b, fputchar, RADIX);
+}
+
+static void
+pb (b)
+ decimal b;
+{
+ decimal_print (b, fputchar, RADIX);
+}
+
+#endif
diff --git a/gnu/usr.bin/dc/decimal.h b/gnu/usr.bin/dc/decimal.h
new file mode 100644
index 0000000..d2cab4d
--- /dev/null
+++ b/gnu/usr.bin/dc/decimal.h
@@ -0,0 +1,93 @@
+/*
+ * Header file for decimal.c (arbitrary precision decimal arithmetic)
+ *
+ * Copyright (C) 1984 Free Software Foundation, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, you can either send email to this
+ * program's author (see below) or write to: The Free Software Foundation,
+ * Inc.; 675 Mass Ave. Cambridge, MA 02139, USA.
+ */
+
+/* Autoconf stuff */
+#ifndef HAVE_BCOPY
+#undef bcopy
+#define bcopy(s2, s1, n) memcpy (s1, s2, n)
+#endif
+
+#ifndef HAVE_BZERO
+#undef bzero
+#define bzero(b, l) memset (b, 0, l)
+#endif
+
+/* Define the radix to use by default, and for representing the
+ numbers internally. This does not need to be decimal; that is just
+ the default for it. */
+
+/* Currently, this is required to be even for this program to work. */
+
+#ifndef RADIX
+#define RADIX 10
+#endif
+
+/* The user must define the external function `decimal_error'
+ which is called with two arguments to report errors in this package.
+ The two arguments may be passed to `printf' to print a message. */
+
+/* Structure that represents a decimal number */
+
+struct decimal
+{
+ unsigned int sign: 1; /* One for negative number */
+ /* The sign should always be zero for the number 0 */
+ int after: 15; /* number of fraction digits */
+ unsigned short before; /* number of non-fraction digits */
+ unsigned short refcnt; /* number of pointers to this number */
+ /* (used by calling program) */
+ char contents[1]; /* the digits themselves, least significant first. */
+ /* digits are just numbers 0 .. RADIX-1 */
+};
+
+/* There may never be leading nonfraction zeros or trailing fraction
+ zeros in a number. They must be removed by all the arithmetic
+ functions. Therefore, the number zero always has no digits stored. */
+
+typedef struct decimal *decimal;
+
+/* Decimal numbers are always passed around as pointers.
+ All the external entries in this file allocate new numbers
+ using `malloc' to store values in.
+ They never modify their arguments or any existing numbers. */
+
+/* Return the total number of digits stored in the number `b' */
+#define LENGTH(b) ((b)->before + (b)->after)
+
+/* Some constant decimal numbers */
+
+
+#define DECIMAL_ZERO &decimal_zero
+
+
+#define DECIMAL_ONE &decimal_one
+
+#define DECIMAL_HALF &decimal_half
+
+decimal decimal_add (), decimal_sub (), decimal_mul (), decimal_div ();
+decimal decimal_mul_dc (), decimal_mul_rounded (), decimal_rem ();
+decimal decimal_round_digits (), decimal_trunc_digits ();
+decimal make_decimal (), decimal_copy (), decimal_parse ();
+decimal decimal_sqrt (), decimal_expt ();
+
+void decimal_print ();
+
+/* End of decimal.h */
diff --git a/gnu/usr.bin/dc/doc/Makefile b/gnu/usr.bin/dc/doc/Makefile
new file mode 100644
index 0000000..c6ec3a9
--- /dev/null
+++ b/gnu/usr.bin/dc/doc/Makefile
@@ -0,0 +1,3 @@
+INFO = dc
+
+.include <bsd.info.mk>
diff --git a/gnu/usr.bin/dc/doc/dc.texinfo b/gnu/usr.bin/dc/doc/dc.texinfo
new file mode 100644
index 0000000..15b285f
--- /dev/null
+++ b/gnu/usr.bin/dc/doc/dc.texinfo
@@ -0,0 +1,381 @@
+\input texinfo @c -*-texinfo-*-
+@c %**start of header
+@setfilename dc.info
+@settitle DC, An Arbitrary Precision Calculator
+@c %**end of header
+
+@c This file has the new style title page commands.
+@c Run `makeinfo' rather than `texinfo-format-buffer'.
+
+@c smallbook
+
+@c tex
+@c \overfullrule=0pt
+@c end tex
+
+@c Combine indices.
+@synindex cp fn
+@syncodeindex vr fn
+@syncodeindex ky fn
+@syncodeindex pg fn
+@syncodeindex tp fn
+
+@ifinfo
+This file documents DC, an arbitrary precision calculator.
+
+Published by the Free Software Foundation,
+675 Massachusetts Avenue,
+Cambridge, MA 02139 USA
+
+Copyright (C) 1984 Free Software Foundation, Inc.
+
+Permission is granted to make and distribute verbatim copies of
+this manual provided the copyright notice and this permission notice
+are preserved on all copies.
+
+@ignore
+Permission is granted to process this file through TeX and print the
+results, provided the printed document carries copying permission
+notice identical to this one except for the removal of this paragraph
+(this paragraph not being relevant to the printed manual).
+
+@end ignore
+Permission is granted to copy and distribute modified versions of this
+manual under the conditions for verbatim copying, provided that the entire
+resulting derived work is distributed under the terms of a permission
+notice identical to this one.
+
+Permission is granted to copy and distribute translations of this manual
+into another language, under the above conditions for modified versions,
+except that this permission notice may be stated in a translation approved
+by the Foundation.
+@end ifinfo
+
+@setchapternewpage odd
+
+@titlepage
+@title DC, An Arbitrary Precision Calculator
+
+@author by Richard Stallman
+@page
+@vskip 0pt plus 1filll
+Copyright @copyright{} 1984 Free Software Foundation, Inc.
+
+@sp 2
+Published by the Free Software Foundation, @*
+675 Massachusetts Avenue, @*
+Cambridge, MA 02139 USA
+
+Permission is granted to make and distribute verbatim copies of
+this manual provided the copyright notice and this permission notice
+are preserved on all copies.
+
+Permission is granted to copy and distribute modified versions of this
+manual under the conditions for verbatim copying, provided that the entire
+resulting derived work is distributed under the terms of a permission
+notice identical to this one.
+
+Permission is granted to copy and distribute translations of this manual
+into another language, under the above conditions for modified versions,
+except that this permission notice may be stated in a translation approved
+by the Foundation.
+
+@end titlepage
+@page
+
+@node Top, Introduction, (dir), (dir)
+
+@menu
+* Introduction:: Introduction
+* Printing Commands:: Printing Commands
+* Arithmetic:: Arithmetic
+* Stack Control:: Stack Control
+* Registers:: Registers
+* Parameters:: Parameters
+* Strings:: Strings
+* Status Inquiry:: Status Inquiry
+* Notes:: Notes
+@end menu
+
+@node Introduction, Printing Commands, Top, Top
+@comment node-name, next, previous, up
+@chapter Introduction
+
+DC is a reverse-polish desk calculator which supports unlimited
+precision arithmetic. It also allows you to define and call macros.
+Normally DC reads from the standard input; if any command arguments
+are given to it, they are filenames, and DC reads and executes the
+contents of the files before reading from standard input. All output
+is to standard output.
+
+To exit, use @samp{q}. @kbd{C-c} does not exit; it is used to abort
+macros that are looping, etc. (Currently this is not true; @kbd{C-c}
+does exit.)
+
+A reverse-polish calculator stores numbers on a stack. Entering a
+number pushes it on the stack. Arithmetic operations pop arguments off
+the stack and push the results.
+
+To enter a number in DC, type the digits, with an optional decimal
+point. Exponential notation is not supported. To enter a negative
+number, begin the number with @samp{_}. @samp{-} cannot be used for
+this, as it is a binary operator for subtraction instead.
+To enter two numbers in succession, separate them with spaces or
+newlines. These have no meaning as commands.
+
+@node Printing Commands, Arithmetic, Introduction, Top
+@chapter Printing Commands
+
+@table @samp
+@item p
+Prints the value on the top of the stack,
+without altering the stack. A newline is printed
+after the value.
+
+@item P
+Prints the value on the top of the stack,
+popping it off, and does not print a newline after.
+
+@item f
+Prints the entire contents of the stack
+and the contents of all of the registers,
+without altering anything. This is a good command
+to use if you are lost or want to figure out
+what the effect of some command has been.
+@end table
+
+@node Arithmetic, Stack Control, Printing Commands, Top
+@chapter Arithmetic
+
+@table @samp
+@item +
+Pops two values off the stack, adds them,
+and pushes the result. The precision of the result
+is determined only by the values of the arguments,
+and is enough to be exact.
+
+@item -
+Pops two values, subtracts the first one popped
+from the second one popped, and pushes the result.
+
+@item *
+Pops two values, multiplies them, and pushes the result.
+The number of fraction digits in the result is controlled
+by the current precision flag (see below) and does not
+depend on the values being multiplied.
+
+@item /
+Pops two values, divides the second one popped from
+the first one popped, and pushes the result.
+The number of fraction digits is specified by the precision flag.
+
+@item %
+Pops two values, computes the remainder of the division
+that the @samp{/} command would do, and pushes that.
+The division is done with as many fraction digits
+as the precision flag specifies, and the remainder
+is also computed with that many fraction digits.
+
+@item ^
+Pops two values and exponentiates, using the first
+value popped as the exponent and the second popped as the base.
+The fraction part of the exponent is ignored.
+The precision flag specifies the number of fraction
+digits in the result.
+
+@item v
+Pops one value, computes its square root, and pushes that.
+The precision flag specifies the number of fraction digits
+in the result.
+@end table
+
+Most arithmetic operations are affected by the "precision flag",
+which you can set with the @samp{k} command. The default precision
+value is zero, which means that all arithmetic except for
+addition and subtraction produces integer results.
+
+The remainder operation (@samp{%}) requires some explanation: applied to
+arguments @samp{a} and @samp{b} it produces @samp{a - (b * (a / b))},
+where @samp{a / b} is computed in the current precision.
+
+@node Stack Control, Registers, Arithmetic, Top
+@chapter Stack Control
+
+@table @samp
+@item c
+Clears the stack, rendering it empty.
+
+@item d
+Duplicates the value on the top of the stack,
+pushing another copy of it. Thus,
+`4d*p' computes 4 squared and prints it.
+@end table
+
+@node Registers, Parameters, Stack Control, Top
+@chapter Registers
+
+DC provides 128 memory registers, each named by a single
+ASCII character. You can store a number in a register
+and retrieve it later.
+
+@table @samp
+@item s@var{r}
+Pop the value off the top of the stack and store
+it into register @var{r}.
+
+@item l@var{r}
+Copy the value in register @var{r}, and push it onto
+the stack. This does not alter the contents of @var{r}.
+
+Each register also contains its own stack. The current
+register value is the top of the register's stack.
+
+@item S@var{r}
+Pop the value off the top of the (main) stack and
+push it onto the stack of register @var{r}.
+The previous value of the register becomes inaccessible.
+
+@item L@var{r}
+Pop the value off the top of register @var{r}'s stack
+and push it onto the main stack. The previous value
+in register @var{r}'s stack, if any, is now accessible
+via the `l@var{r}' command.
+@end table
+
+The @samp{f} command prints a list of all registers that have contents
+stored in them, together with their contents. Only the
+current contents of each register (the top of its stack)
+is printed.
+
+@node Parameters, Strings, Registers, Top
+@chapter Parameters
+
+DC has three parameters that control its operation: the precision, the
+input radix, and the output radix. The precision specifies the number
+of fraction digits to keep in the result of most arithmetic operations.
+The input radix controls the interpretation of numbers typed in;
+@emph{all} numbers typed in use this radix. The output radix is used
+for printing numbers.
+
+The input and output radices are separate parameters; you can make them
+unequal, which can be useful or confusing. Each radix must be between 2
+and 36 inclusive. The precision must be zero or greater. The precision
+is always measured in decimal digits, regardless of the current input or
+output radix.
+
+@table @samp
+@item i
+Pops the value off the top of the stack
+and uses it to set the input radix.
+
+@item o
+@itemx k
+Similarly set the output radix and the precision.
+
+@item I
+Pushes the current input radix on the stack.
+
+@item O
+@itemx K
+Similarly push the current output radix and the current precision.
+@end table
+
+@node Strings, Status Inquiry, Parameters, Top
+@chapter Strings
+
+DC can operate on strings as well as on numbers. The only things you
+can do with strings are print them and execute them as macros (which
+means that the contents of the string are processed as DC commands).
+Both registers and the stack can hold strings, and DC always knows
+whether any given object is a string or a number. Some commands such as
+arithmetic operations demand numbers as arguments and print errors if
+given strings. Other commands can accept either a number or a string;
+for example, the @samp{p} command can accept either and prints the object
+according to its type.
+
+@table @samp
+@item [@var{characters}]
+Makes a string containing @var{characters} and pushes it
+on the stack. For example, @samp{[foo]P} prints the
+characters @samp{foo} (with no newline).
+
+@item x
+Pops a value off the stack and executes it as a macro.
+Normally it should be a string; if it is a number,
+it is simply pushed back onto the stack.
+For example, @samp{[1p]x} executes the macro @samp{1p}, which
+pushes 1 on the stack and prints @samp{1} on a separate line.
+
+Macros are most often stored in registers;
+@samp{[1p]sa} stores a macro to print @samp{1} into register @samp{a},
+and @samp{lax} invokes the macro.
+
+@item >@var{r}
+Pops two values off the stack and compares them
+assuming they are numbers, executing the contents
+of register @var{r} as a macro if the original top-of-stack
+is greater. Thus, @samp{1 2>a} will invoke register @samp{a}'s contents
+and @samp{2 1>a} will not.
+
+@item <@var{r}
+Similar but invokes the macro if the original top-of-stack
+is less.
+
+@item =@var{r}
+Similar but invokes the macro if the two numbers popped
+are equal. This can also be validly used to compare two
+strings for equality.
+
+@item ?
+Reads a line from the terminal and executes it.
+This command allows a macro to request input from the user.
+
+@item q
+During the execution of a macro, this comand
+does not exit DC. Instead, it exits from that
+macro and also from the macro which invoked it (if any).
+
+@item Q
+Pops a value off the stack and uses it as a count
+of levels of macro execution to be exited. Thus,
+@samp{3Q} exits three levels.
+@end table
+
+@node Status Inquiry, Notes, Strings, Top
+@chapter Status Inquiry
+
+@table @samp
+@item Z
+Pops a value off the stack, calculates the number of
+digits it has (or number of characters, if it is a string)
+and pushes that number.
+
+@item X
+Pops a value off the stack, calculates the number of
+fraction digits it has, and pushes that number.
+For a string, the value pushed is -1.
+
+@item z
+Pushes the current stack depth; the number of
+objects on the stack before the execution of the @samp{z} command.
+
+@item I
+Pushes the current value of the input radix.
+
+@item O
+Pushes the current value of the output radix.
+
+@item K
+Pushes the current value of the precision.
+@end table
+
+@node Notes, , Status Inquiry, Top
+@chapter Notes
+
+The @samp{:} and @samp{;} commands of the Unix DC program are
+not supported, as the documentation does not say what they do.
+The @samp{!} command is not supported, but will be supported
+as soon as a library for executing a line as a command exists.
+
+@contents
+@bye
diff --git a/gnu/usr.bin/dialog/COPYING b/gnu/usr.bin/dialog/COPYING
new file mode 100644
index 0000000..a43ea21
--- /dev/null
+++ b/gnu/usr.bin/dialog/COPYING
@@ -0,0 +1,339 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 675 Mass Ave, Cambridge, MA 02139, USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ Appendix: How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) 19yy <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) 19yy name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/gnu/usr.bin/dialog/Makefile b/gnu/usr.bin/dialog/Makefile
new file mode 100644
index 0000000..436519a
--- /dev/null
+++ b/gnu/usr.bin/dialog/Makefile
@@ -0,0 +1,12 @@
+# Makefile for dialog
+# $Id: Makefile,v 1.3 1994/10/11 23:51:06 ache Exp $
+
+PROG= dialog
+MAN1= dialog.1
+
+CFLAGS+= -Wall -Wstrict-prototypes
+
+DPADD+= $(LIBDIALOG) $(LIBNCURSES) $(LIBMYTINFO)
+LDADD+= -ldialog -lncurses -lmytinfo
+
+.include <bsd.prog.mk>
diff --git a/gnu/usr.bin/dialog/README b/gnu/usr.bin/dialog/README
new file mode 100644
index 0000000..975bdac
--- /dev/null
+++ b/gnu/usr.bin/dialog/README
@@ -0,0 +1,161 @@
+
+ dialog - Display dialog boxes in shell script (version 0.3)
+ ===========================================================
+
+This is a program that will enable you to present a variety of questions or
+display messages using dialog boxes from a shell script. Currently, these
+types of dialog boxes are implemented: yes/no box, menu box, input box,
+message box, text box, info box, checklist box. The idea of writing this
+program came from the fact that most questions asked in a shell script (and
+many interactive programs as well) can be classified into these few types:
+
+
+ 1) One that requires the user to answer either yes or no.
+
+ 2) One that presents a number of options for the user to choose.
+
+ 3) One that requires the user to input a string.
+
+ 4) One that displays a message and optionally wait for a key press
+ before continuing.
+
+ 5) One that presents a list of options that can be turned on or off.
+
+
+The program 'dialog' can, say for example, be called in a shell script to
+present the first type of questions like this:
+
+
+ if dialog --yesno <question text> <height> <width>
+ then
+ ...
+ fi
+
+
+ e.g. if dialog --yesno "Do you want to continue?" 7 51
+ then
+ echo "Continuing..."
+ else
+ echo "Aborting..."
+ fi
+
+
+I've included a sample shell script for each type of boxes in the directory
+samples. The program requires ncurses to compile. Running 'dialog' without
+arguments will display the usage.
+
+
+
+FEATURES
+--------
+
+ * Friendly dialog box interface with buttons, etc.
+
+ * Auto wrap around of question text if it's too long to fit on
+ one line.
+
+ * "\n" can be inserted in question text to control line breaking
+ explicitly. The real newline character '\n' can also be used.
+
+ * run-time configruation of color settings and other options using
+ a configuration file.
+
+
+
+WHAT'S NEW SINCE VERSION 0.21?
+------------------------------
+
+ * some changes for faster screen update.
+
+ * much more flexible color settings. Can use all 16 colors
+ (8 normal, 8 highlight) of the Linux console.
+
+ * added run-time configuration using configuration file.
+
+ * some minor bug fixes and cleanups for menubox, checklist and
+ textbox.
+
+ * added a man page.
+
+ * some changes for easier porting to other Unix systems (tested
+ on Ultrix, SunOS and HPUX)
+
+
+
+INSTALLATION
+------------
+
+ 1. cd ./src
+
+ 2. Go to step 3 if your system has ncurses (e.g. Linux).
+ Edit Makefile and remove -DHAVE_NCURSES from DEFS. Also
+ remove rc.c from SRCS and rc.o from OBJS. Change LIBS as
+ appropriate (Usually, it should be '-lcurses -ltermcap').
+ Go to step 6.
+
+ 3. Edit Makefile and remove -DBROKEN_WSCRL from DEFS if you
+ are using ncurses 1.8.3 or newer. Menu scrolling should
+ be faster. DON'T REMOVE IT IF YOU ARE NOT USING AT LEAST
+ VERSION 1.8.3 OF NCURSES.
+
+ 4. Edit dialog.h and change USE_SHADOW to FALSE if you don't
+ want shadowed dialog boxes. Also change USE_COLORS to
+ FALSE if you don't want colors. Note that 'dialog' will
+ check if the terminal supports colors, and will use mono
+ settings if it doesn't, so USE_COLORS won't do any harm
+ even if you have a mono display. Also note that USE_SHADOW
+ implies USE_COLORS. These two options can be changed at
+ run-time using the run-time configuration file (see below).
+
+ 5. Edit colors.h to change default color definitions if you
+ don't like the defaults. These are only compiled in defaults,
+ you can change them at run-time using the run-time
+ configuration file.
+
+ 6. 'make depend; make install' will compile and install the
+ binaries in /usr/local/bin (change BINDIR in Makefile if
+ you want to install elsewhere).
+
+ 7. 'make install.man' will install the man page to
+ /usr/local/man (change MANDIR in Makefile if you want to
+ install elsewhere).
+
+ 8. You can then try the sample shell scripts in the samples
+ directory (make sure the environment variable DIALOG is
+ not set, the scripts use it to find the dialog binary, if
+ it's not set, "../src/dialog" will be used).
+
+ 9. Don't forget to mail me (mail address at end of this file)
+ if you find any bugs, have some good color settings to
+ contribute or just want to tell me that you like it, Don't
+ mail me if you don't like it :-)
+
+
+
+RUN-TIME CONFIGURATION
+----------------------
+
+ 1. Create a sample configuration file by typing:
+
+ "dialog --create-rc <file>"
+
+ 2. At start, 'dialog' determines the settings to use as follows:
+
+ a) if environment variable DIALOGRC is set, it's value
+ determines the name of the configuration file.
+
+ b) if the file in (a) can't be found, use the file
+ $HOME/.dialogrc as the configuration file.
+
+ c) if the file in (b) can't be found, use compiled in
+ defaults.
+
+ 3. Edit the sample configuration file and copy it to some place
+ that 'dialog' can find, as stated in step 2 above.
+
+
+
+
+Comments and bug reports welcome.
+
+- Savio Lam (lam836@cs.cuhk.hk)
diff --git a/gnu/usr.bin/dialog/README.lib b/gnu/usr.bin/dialog/README.lib
new file mode 100644
index 0000000..472c206
--- /dev/null
+++ b/gnu/usr.bin/dialog/README.lib
@@ -0,0 +1,3 @@
+Now 'dialog' splitted to this sources and library of functions,
+see /usr/src/gnu/lib/libdialog for details.
+ Ache.
diff --git a/gnu/usr.bin/dialog/TESTS/checklist b/gnu/usr.bin/dialog/TESTS/checklist
new file mode 100755
index 0000000..008e874
--- /dev/null
+++ b/gnu/usr.bin/dialog/TESTS/checklist
@@ -0,0 +1,33 @@
+#!/bin/sh
+DIALOG=${DIALOG=/usr/bin/dialog}
+
+$DIALOG --title "CHECKLIST BOX" --clear \
+ --checklist "Hi, this is a checklist box. You can use this to \n\
+present a list of choices which can be turned on or \n\
+off. If there are more items than can fit on the \n\
+screen, the list will be scrolled. You can use the \n\
+UP/DOWN arrow keys, the first letter of the choice as a\n\
+hot key, or the number keys 1-9 to choose an option. \n\
+Press SPACE to toggle an option on/off. \n\n\
+ Which of the following are fruits?" -1 -1 5 \
+ "Apple" "It's an apple." off \
+ "Dog" "No, that's not my dog." ON \
+ "Orange" "Yeah, that's juicy." off \
+ "Cat" "No, never put a dog and a cat together!" oN \
+ "Fish" "Cats like fish." On \
+ "Lemon" "You know how it tastes." on 2> /tmp/checklist.tmp.$$
+
+retval=$?
+
+choice=`cat /tmp/checklist.tmp.$$`
+rm -f /tmp/checklist.tmp.$$
+
+case $retval in
+ 0)
+ echo "'$choice' chosen.";;
+ 1)
+ echo "Cancel pressed.";;
+ 255)
+ [ -z "$choice" ] || echo $choice ;
+ echo "ESC pressed.";;
+esac
diff --git a/gnu/usr.bin/dialog/TESTS/infobox b/gnu/usr.bin/dialog/TESTS/infobox
new file mode 100755
index 0000000..89d4736
--- /dev/null
+++ b/gnu/usr.bin/dialog/TESTS/infobox
@@ -0,0 +1,15 @@
+#!/bin/sh
+DIALOG=${DIALOG=/usr/bin/dialog}
+
+$DIALOG --title "INFO BOX" \
+ --infobox "Hi, this is an information box. It is
+different from a message box in that it will
+not pause waiting for input after displaying
+the message. The pause here is only introduced
+by the sleep command, not by dialog.
+
+You have 10 seconds to read this..." -1 -1
+
+stty -echo
+sleep 10
+stty echo
diff --git a/gnu/usr.bin/dialog/TESTS/inputbox b/gnu/usr.bin/dialog/TESTS/inputbox
new file mode 100755
index 0000000..2acb846
--- /dev/null
+++ b/gnu/usr.bin/dialog/TESTS/inputbox
@@ -0,0 +1,28 @@
+#!/bin/sh
+DIALOG=${DIALOG=/usr/bin/dialog}
+
+$DIALOG --title "INPUT BOX" --clear \
+ --inputbox "Hi, this is an input dialog box. You can use \n\
+this to ask questions that require the user \n\
+to input a string as the answer. You can \n\
+input strings of length longer than the \n\
+width of the input box, in that case, the \n\
+input field will be automatically scrolled. \n\
+You can use BACKSPACE, LEFT, RIGHT, HOME, END\n\
+to correct errors. \n\n\
+Try inputing your name below:" -1 -1 "John Smith" 2> /tmp/inputbox.tmp.$$
+
+retval=$?
+
+input=`cat /tmp/inputbox.tmp.$$`
+rm -f /tmp/inputbox.tmp.$$
+
+case $retval in
+ 0)
+ echo "Input string is '$input'";;
+ 1)
+ echo "Cancel pressed.";;
+ 255)
+ [ -z "$input" ] || echo $input ;
+ echo "ESC pressed.";;
+esac
diff --git a/gnu/usr.bin/dialog/TESTS/menubox b/gnu/usr.bin/dialog/TESTS/menubox
new file mode 100755
index 0000000..f5d4e92
--- /dev/null
+++ b/gnu/usr.bin/dialog/TESTS/menubox
@@ -0,0 +1,35 @@
+#!/bin/sh
+DIALOG=${DIALOG=/usr/bin/dialog}
+
+$DIALOG --clear --title "MENU BOX" \
+ --hline "Press 1-9, Up/Down, first letter or Enter" \
+ --menu "Hi, this is a menu box. You can use this to \n\
+present a list of choices for the user to \n\
+choose. If there are more items than can fit \n\
+on the screen, the menu will be scrolled. \n\
+You can use the UP/DOWN arrow keys, the first \n\
+letter of the choice as a hot key, or the \n\
+number keys 1-9 to choose an option.\n\
+Try it now!\n\n\
+ Choose the OS you like:" -1 -1 4 \
+ "FreeBSD 2.0" "A Real Operating System for Real Users" \
+ "Linux" "Another free Unix Clone for 386/486" \
+ "OS/2" "IBM OS/2" \
+ "WIN NT" "Microsoft Windows NT" \
+ "PCDOS" "IBM PC DOS" \
+ "MSDOS" "Microsoft DOS" 2> /tmp/menu.tmp.$$
+
+retval=$?
+
+choice=`cat /tmp/menu.tmp.$$`
+rm -f /tmp/menu.tmp.$$
+
+case $retval in
+ 0)
+ echo "'$choice' chosen.";;
+ 1)
+ echo "Cancel pressed.";;
+ 255)
+ [ -z "$choice" ] || echo $choice ;
+ echo "ESC pressed.";;
+esac
diff --git a/gnu/usr.bin/dialog/TESTS/msgbox b/gnu/usr.bin/dialog/TESTS/msgbox
new file mode 100755
index 0000000..7f1b1f8
--- /dev/null
+++ b/gnu/usr.bin/dialog/TESTS/msgbox
@@ -0,0 +1,14 @@
+#!/bin/sh
+DIALOG=${DIALOG=/usr/bin/dialog}
+
+$DIALOG --title "MESSAGE BOX" --clear \
+ --msgbox "Hi, this is a simple message box. You can use this to\n\
+display any message you like. The box will remain until\n\
+you press the ENTER key." -1 -1
+
+case $? in
+ 0)
+ echo "OK";;
+ 255)
+ echo "ESC pressed.";;
+esac
diff --git a/gnu/usr.bin/dialog/TESTS/prgbox b/gnu/usr.bin/dialog/TESTS/prgbox
new file mode 100755
index 0000000..5a631f5
--- /dev/null
+++ b/gnu/usr.bin/dialog/TESTS/prgbox
@@ -0,0 +1,12 @@
+#!/bin/sh
+DIALOG=${DIALOG=/usr/bin/dialog}
+
+$DIALOG --title "PROGRAM BOX: 'cal'" --clear \
+ --prgbox "cal" 13 27
+
+case $? in
+ 0)
+ echo "OK";;
+ *)
+ echo "Exit code:" $?;;
+esac
diff --git a/gnu/usr.bin/dialog/TESTS/radiolist b/gnu/usr.bin/dialog/TESTS/radiolist
new file mode 100755
index 0000000..7402790
--- /dev/null
+++ b/gnu/usr.bin/dialog/TESTS/radiolist
@@ -0,0 +1,33 @@
+#!/bin/sh
+DIALOG=${DIALOG=/usr/bin/dialog}
+
+$DIALOG --title "RADIOLIST BOX" --clear \
+ --radiolist "Hi, this is a radiolist box. You can use this to \n\
+present a list of choices, one of them can be turned \n\
+on or off. If there are more items than can fit on the \n\
+screen, the list will be scrolled. You can use the \n\
+UP/DOWN arrow keys, the first letter of the choice as a\n\
+hot key, or the number keys 1-9 to choose an option. \n\
+Press SPACE to toggle an option on/off. \n\n\
+ Which of the following are fruits?" -1 -1 5 \
+ "Apple" "It's an apple." off \
+ "Dog" "No, that's not my dog." ON \
+ "Orange" "Yeah, that's juicy." off \
+ "Cat" "No, never put a dog and a cat together!" oFF \
+ "Fish" "Cats like fish." OFF \
+ "Lemon" "You know how it tastes." oFF 2> /tmp/radiolist.tmp.$$
+
+retval=$?
+
+choice=`cat /tmp/radiolist.tmp.$$`
+rm -f /tmp/radiolist.tmp.$$
+
+case $retval in
+ 0)
+ echo "'$choice' chosen.";;
+ 1)
+ echo "Cancel pressed.";;
+ 255)
+ [ -z "$choice" ] || echo $choice ;
+ echo "ESC pressed.";;
+esac
diff --git a/gnu/usr.bin/dialog/TESTS/textbox b/gnu/usr.bin/dialog/TESTS/textbox
new file mode 100755
index 0000000..ed7c2d9
--- /dev/null
+++ b/gnu/usr.bin/dialog/TESTS/textbox
@@ -0,0 +1,42 @@
+#!/bin/sh
+DIALOG=${DIALOG=/usr/bin/dialog}
+
+cat << EOF > /tmp/textbox.tmp.$$
+Hi, this is a text dialog box. It can be used to display text from a file.
+The file should not contain any 'tab' characters, so you should 'expand'
+the file first if it contains 'tab' characters.
+
+It's like a simple text file viewer, with these keys implemented:
+
+PGDN/SPACE - Move down one page
+PGUP/'b' - Move up one page
+DOWN/'j' - Move down one line
+UP/'k' - Move up one line
+LEFT/'h' - Scroll left
+RIGHT/'l' - Scroll right
+'0' - Move to beginning of line
+HOME/'g' - Move to beginning of file
+END/'G' - Move to end of file
+'/' - Forward search
+'?' - Backward search
+'n' - Repeat last search (forward)
+'N' - Repeat last search (backward)
+
+
+The following is a sample text file:
+
+
+EOF
+
+cat ../COPYING | expand >> /tmp/textbox.tmp.$$
+
+$DIALOG --clear --title "TEXT BOX" --textbox "/tmp/textbox.tmp.$$" 22 77
+
+case $? in
+ 0)
+ echo "OK";;
+ 255)
+ echo "EXIT choosed.";;
+esac
+
+rm -f /tmp/textbox.tmp.$$
diff --git a/gnu/usr.bin/dialog/TESTS/yesno b/gnu/usr.bin/dialog/TESTS/yesno
new file mode 100755
index 0000000..36e95c8
--- /dev/null
+++ b/gnu/usr.bin/dialog/TESTS/yesno
@@ -0,0 +1,23 @@
+#!/bin/sh
+DIALOG=${DIALOG=/usr/bin/dialog}
+
+$DIALOG --title "YES/NO BOX" --clear \
+ --hline "Press F1 or ? to see GNU GPL" \
+ --hfile ../COPYING \
+ --yesno "Hi, this is a yes/no dialog box. You can use this to ask \
+ questions that have an answer of either yes or no. \
+ BTW, do you notice that long lines will be automatically \
+ wrapped around so that they can fit in the box? You can \
+ also control line breaking explicitly by inserting \
+ 'backslash n' at any place you like, but in this case, \
+ auto wrap around will be disabled and you will have to \
+ control line breaking yourself." 15 61
+
+case $? in
+ 0)
+ echo "Yes chosen.";;
+ 1)
+ echo "No chosen.";;
+ 255)
+ echo "ESC pressed.";;
+esac
diff --git a/gnu/usr.bin/dialog/dialog.1 b/gnu/usr.bin/dialog/dialog.1
new file mode 100644
index 0000000..aae60a3
--- /dev/null
+++ b/gnu/usr.bin/dialog/dialog.1
@@ -0,0 +1,239 @@
+.TH DIALOG 1 "10 January 1994"
+.SH NAME
+dialog \- display dialog boxes from shell scripts
+.SH SYNOPSIS
+.B dialog --clear
+.br
+.BI "dialog --create-rc " file
+.br
+.B dialog
+[
+.BI "\-\-title " title
+]
+[
+.B \-\-clear
+]
+[
+.BI "\-\-hline " line
+]
+[
+.BI "\-\-hfile " file
+]
+.B box-options
+.SH DESCRIPTION
+.B Dialog
+is a program which allows you to present a variety of questions or
+display messages in dialog box form from a shell script. The following
+types of dialog objects are currently supported:
+.LP
+.BR yes/no " box," " menu" " box," " input" " box,"
+.BR message " box," " text" " box," " info" " box,"
+.BR checklist " box and" " program" " box."
+.SH OPTIONS
+.TP
+.B \-\-clear
+The screen will be cleared to the
+.BR "screen attribute" " on exit."
+.TP
+.BI \-\-create-rc " file"
+.RB "Since " dialog " supports run-time configuration,"
+this can be used to dump a sample configuration file to the file specified
+by
+.IR file "."
+.TP
+.BI \-\-title " title"
+Specifies a
+.I title
+string to be displayed at the top of the dialog box.
+.TP
+.BI \-\-hline " line"
+Specifies a
+.I line
+string to be displayed at the bottom of the dialog box.
+.TP
+.BI \-\-hfile " file"
+Specifies a
+.I file
+to be displayed by pressing ? or F1.
+.TP
+.B Box Options
+.TP
+.BI \-\-yesno " text height width"
+.RB A " yes/no" " dialog box of size"
+.I height
+rows by
+.I width
+columns will be displayed. The string specified by
+.I text
+is displayed inside the dialog box. If this string is too long to fit
+in one line, it will be automatically divided into multiple lines at
+the appropriate points. The
+.I text
+string may also contain the sub-string
+.I
+"\en"
+or newline characters
+.I `\en\'
+to control line breaking explicitly. This dialog box is useful for
+asking questions that require the user to answer either yes or no.
+.RB "The dialog box has a" " Yes" " button and a " No
+button, in which the user can switch between by pressing the
+.IR TAB " key."
+.TP
+.BI \-\-msgbox " text height width"
+.RB A " message" " box is very similar to a" " yes/no" " box."
+The only difference between a
+.B message
+box and a
+.B yes/no
+box is that a
+.B message
+box has only a single
+.B OK
+button. You can use this dialog box to display any message you like.
+After reading the message, the user can press the
+.I ENTER
+key so that
+.B dialog
+will exit and the calling shell script can continue its operation.
+.TP
+.BI \-\-infobox " text height width"
+.RB An " info" " box is basically a" " message" " box."
+However, in this case,
+.B dialog
+will exit immediately after displaying the message to the user. The
+screen is not cleared when
+.B dialog
+exits, so that the message will remain on the screen until the calling
+shell script clears it later. This is useful when you want to inform
+the user that some operations are carrying on that may require some
+time to finish.
+.TP
+.BI \-\-inputbox " text height width"
+.RB "An " input " box is useful when you want to ask questions that"
+require the user to input a string as the answer. When inputing the
+string, the
+.I BACKSPACE
+key can be used to correct typing errors. If the input string is longer than
+can be fitted in the dialog box, the input field will be scrolled. On exit,
+the input string will be printed on
+.IR stderr "."
+.TP
+.BI \-\-textbox " file height width"
+.RB A " text" " box lets you display the contents of a text file in a"
+dialog box. It is like a simple text file viewer. The user can move
+through the file by using the
+.IR UP/DOWN ", " PGUP/PGDN
+.RI and " HOME/END" " keys available on most keyboards."
+If the lines are too long to be displayed in the box, the
+.I LEFT/RIGHT
+keys can be used to scroll the text region horizontally. For more
+convenience, forward and backward searching functions are also provided.
+.IP "\fB\-\-menu \fItext height width menu-height \fR[ \fItag item \fR] \fI..."
+As its name suggests, a
+.B menu
+box is a dialog box that can be used to present a list of choices in
+the form of a menu for the user to choose. Each menu entry consists of a
+.IR tag " string and an " item " string. The"
+.I tag
+gives the entry a name to distinguish it from the other entries in the
+menu. The
+.I item
+is a short description of the option that the entry represents. The
+user can move between the menu entries by pressing the
+.I UP/DOWN
+keys, the first letter of the
+.I tag
+as a hot-key, or the number keys
+.IR 1-9 ". There are"
+.I menu-height
+entries displayed in the menu at one time, but the menu will be
+scrolled if there are more entries than that. When
+.B dialog
+exits, the
+.I tag
+of the chosen menu entry will be printed on
+.IR stderr "."
+.TP
+.BI \-\-prgbox " command height width"
+.RB A " program" " box lets you display output of command in"
+dialog box.
+.IP "\fB\-\-checklist \fItext height width list-height \fR[ \fItag item status \fR] \fI..."
+.RB "A " checklist " box is similar to a " menu " box in that there are"
+multiple entries presented in the form of a menu. Instead of choosing
+one entry among the entries, each entry can be turned on or off by the
+user. The initial on/off state of each entry is specified by
+.IR status "."
+On exit, a list of the
+.I tag
+strings of those entries that are turned on will be printed on
+.IR stderr "."
+.SH "RUN-TIME CONFIGURATION"
+.TP 4
+1.
+Create a sample configuration file by typing:
+.LP
+.in +1i
+"dialog --create-rc <file>"
+.TP 4
+2.
+At start,
+.B dialog
+determines the settings to use as follows:
+.RS
+.TP 4
+a)
+if environment variable
+.B DIALOGRC
+is set, it's value determines the name of the configuration file.
+.TP 4
+b)
+if the file in (a) can't be found, use the file
+.I $HOME/.dialogrc
+as the configuration file.
+.TP 4
+c)
+if the file in (b) can't be found, use compiled in defaults.
+.RE
+.TP 4
+3.
+Edit the sample configuration file and copy it to some place that
+.B dialog
+can find, as stated in step 2 above.
+.SH ENVIROMENT
+.TP 15
+.B DIALOGRC
+Define this variable if you want to specify the name of the configuration file
+to use.
+.SH FILES
+.TP 20
+.I $HOME/.dialogrc
+default configuration file
+.SH DIAGNOSTICS
+Exit status is 0 if
+.BR dialog " is exited by pressing the " Yes " or " OK
+button, and 1 if the
+.BR No " or " Cancel
+button is pressed. Otherwise, if errors occur inside
+.B dialog
+or
+.B dialog
+is exited by pressing the
+.I ESC
+key, the exit status is -1.
+.SH SEE ALSO
+.Xr dialog 3
+
+.SH BUGS
+Text files containing
+.I tab
+characters may cause problems with
+.B text
+box.
+.I Tab
+characters in text files must first be expanded to spaces before being
+.RB "displayed by " text " box."
+.TP
+Screen update is too slow.
+.SH AUTHOR
+Savio Lam (lam836@cs.cuhk.hk)
diff --git a/gnu/usr.bin/dialog/dialog.c b/gnu/usr.bin/dialog/dialog.c
new file mode 100644
index 0000000..aafd777
--- /dev/null
+++ b/gnu/usr.bin/dialog/dialog.c
@@ -0,0 +1,372 @@
+/*
+ * dialog - Display simple dialog boxes from shell scripts
+ *
+ * AUTHOR: Savio Lam (lam836@cs.cuhk.hk)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *
+ * HISTORY:
+ *
+ * 17/12/93 - Version 0.1 released.
+ *
+ * 19/12/93 - menu will now scroll if there are more items than can fit
+ * on the screen.
+ * - added 'checklist', a dialog box with a list of options that
+ * can be turned on or off. A list of options that are on is
+ * returned on exit.
+ *
+ * 20/12/93 - Version 0.15 released.
+ *
+ * 29/12/93 - Incorporated patch from Patrick J. Volkerding
+ * (volkerdi@mhd1.moorhead.msus.edu) that made these changes:
+ * - increased MAX_LEN to 2048
+ * - added 'infobox', equivalent to a message box without pausing
+ * - added option '--clear' that will clear the screen
+ * - Explicit line breaking when printing prompt text can be
+ * invoked by real newline '\n' besides the string "\n"
+ * - an optional parameter '--title <string>' can be used to
+ * specify a title string for the dialog box
+ *
+ * 03/01/94 - added 'textbox', a dialog box for displaying text from a file.
+ * - Version 0.2 released.
+ *
+ * 04/01/94 - some fixes and improvements for 'textbox':
+ * - fixed a bug that will cause a segmentation violation when a
+ * line is longer than MAX_LEN characters. Lines will now be
+ * truncated if they are longer than MAX_LEN characters.
+ * - removed wrefresh() from print_line(). This will increase
+ * efficiency of print_page() which calls print_line().
+ * - display current position in the form of percentage into file.
+ * - Version 0.21 released.
+ *
+ * 05/01/94 - some changes for faster screen update.
+ *
+ * 07/01/94 - much more flexible color settings. Can use all 16 colors
+ * (8 normal, 8 highlight) of the Linux console.
+ *
+ * 08/01/94 - added run-time configuration using configuration file.
+ *
+ * 09/01/94 - some minor bug fixes and cleanups for menubox, checklist and
+ * textbox.
+ *
+ * 11/01/94 - added a man page.
+ *
+ * 13/01/94 - some changes for easier porting to other Unix systems (tested
+ * on Ultrix, SunOS and HPUX)
+ * - Version 0.3 released.
+ *
+ * 08/06/94 - Patches by Stuart Herbert - S.Herbert@shef.ac.uk
+ * Fixed attr_clear and the textbox stuff to work with ncurses 1.8.5
+ * Fixed the wordwrap routine - it'll actually wrap properly now
+ * Added a more 3D look to everything - having your own rc file could
+ * prove 'interesting' to say the least :-)
+ * Added radiolist option
+ * - Version 0.4 released.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/wait.h>
+#include <dialog.h>
+
+void Usage(unsigned char *name);
+
+int main(int argc, unsigned char *argv[])
+{
+ int offset = 0, clear_screen = 0, end_common_opts = 0, retval;
+ unsigned char *title = NULL;
+ unsigned char result[MAX_LEN];
+ char *hline = NULL, *hfile = NULL;
+
+ if (argc < 2) {
+ Usage(argv[0]);
+ exit(-1);
+ }
+ else if (!strcmp(argv[1], "--create-rc")) {
+#ifdef HAVE_NCURSES
+ if (argc != 3) {
+ Usage(argv[0]);
+ exit(-1);
+ }
+ dialog_create_rc(argv[2]);
+ return 0;
+#else
+ fprintf(stderr, "\nThis option is currently unsupported on your system.\n");
+ return -1;
+#endif
+ }
+
+ while (offset < argc-1 && !end_common_opts) { /* Common options */
+ if (!strcmp(argv[offset+1], "--title")) {
+ if (argc-offset < 3 || title != NULL) { /* No two "--title" please! */
+ Usage(argv[0]);
+ exit(-1);
+ }
+ else {
+ title = argv[offset+2];
+ offset += 2;
+ }
+ }
+ else if (!strcmp(argv[offset+1], "--hline")) {
+ if (argc-offset < 3 || hline != NULL) { /* No two "--hline" please! */
+ Usage(argv[0]);
+ exit(-1);
+ }
+ else {
+ hline = argv[offset+2];
+ use_helpline(hline);
+ offset += 2;
+ }
+ }
+ else if (!strcmp(argv[offset+1], "--hfile")) {
+ if (argc-offset < 3 || hfile != NULL) { /* No two "--hfile" please! */
+ Usage(argv[0]);
+ exit(-1);
+ }
+ else {
+ hfile = argv[offset+2];
+ use_helpfile(hfile);
+ offset += 2;
+ }
+ }
+ else if (!strcmp(argv[offset+1], "--clear")) {
+ if (clear_screen) { /* Hey, "--clear" can't appear twice! */
+ Usage(argv[0]);
+ exit(-1);
+ }
+ else if (argc == 2) { /* we only want to clear the screen */
+ init_dialog();
+ dialog_update(); /* init_dialog() will clear the screen for us */
+ end_dialog();
+ return 0;
+ }
+ else {
+ clear_screen = 1;
+ offset++;
+ }
+ }
+ else /* no more common options */
+ end_common_opts = 1;
+ }
+
+ if (argc-1 == offset) { /* no more options */
+ Usage(argv[0]);
+ exit(-1);
+ }
+
+ /* Box options */
+
+ if (!strcmp(argv[offset+1], "--yesno")) {
+ if (argc-offset != 5) {
+ Usage(argv[0]);
+ exit(-1);
+ }
+ init_dialog();
+ retval = dialog_yesno(title, argv[offset+2], atoi(argv[offset+3]),
+ atoi(argv[offset+4]));
+
+ dialog_update();
+ if (clear_screen) /* clear screen before exit */
+ dialog_clear();
+ end_dialog();
+ return retval;
+ }
+ else if (!strcmp(argv[offset+1], "--msgbox")) {
+ if (argc-offset != 5) {
+ Usage(argv[0]);
+ exit(-1);
+ }
+ init_dialog();
+ retval = dialog_msgbox(title, argv[offset+2], atoi(argv[offset+3]),
+ atoi(argv[offset+4]), 1);
+
+ dialog_update();
+ if (clear_screen) /* clear screen before exit */
+ dialog_clear();
+ end_dialog();
+ return retval;
+ }
+ else if (!strcmp(argv[offset+1], "--prgbox")) {
+ if (argc-offset != 5) {
+ Usage(argv[0]);
+ exit(-1);
+ }
+ init_dialog();
+ retval = dialog_prgbox(title, argv[offset+2], atoi(argv[offset+3]),
+ atoi(argv[offset+4]), TRUE, TRUE);
+
+ dialog_update();
+ if (clear_screen) /* clear screen before exit */
+ dialog_clear();
+ end_dialog();
+ return WEXITSTATUS(retval);
+ }
+ else if (!strcmp(argv[offset+1], "--infobox")) {
+ if (argc-offset != 5) {
+ Usage(argv[0]);
+ exit(-1);
+ }
+ init_dialog();
+ retval = dialog_msgbox(title, argv[offset+2], atoi(argv[offset+3]),
+ atoi(argv[offset+4]), 0);
+
+ dialog_update();
+ if (clear_screen) /* clear screen before exit */
+ dialog_clear();
+ end_dialog();
+ return retval;
+ }
+ else if (!strcmp(argv[offset+1], "--textbox")) {
+ if (argc-offset != 5) {
+ Usage(argv[0]);
+ exit(-1);
+ }
+ init_dialog();
+ retval = dialog_textbox(title, argv[offset+2], atoi(argv[offset+3]),
+ atoi(argv[offset+4]));
+
+ dialog_update();
+ if (clear_screen) /* clear screen before exit */
+ dialog_clear();
+ end_dialog();
+ return retval;
+ }
+ else if (!strcmp(argv[offset+1], "--menu")) {
+ if (argc-offset < 8 || ((argc-offset) % 2)) {
+ Usage(argv[0]);
+ exit(-1);
+ }
+ init_dialog();
+ retval = dialog_menu(title, argv[offset+2], atoi(argv[offset+3]),
+ atoi(argv[offset+4]), atoi(argv[offset+5]),
+ (argc-offset-6)/2, argv+offset + 6, result,
+ NULL, NULL);
+ dialog_update();
+ if (retval == 0)
+ fputs(result, stderr);
+ if (clear_screen) /* clear screen before exit */
+ dialog_clear();
+ end_dialog();
+ return retval;
+ }
+ else if (!strcmp(argv[offset+1], "--checklist")) {
+ if (argc-offset < 9 || ((argc-offset-6) % 3)) {
+ Usage(argv[0]);
+ exit(-1);
+ }
+ init_dialog();
+ retval = dialog_checklist(title, argv[offset+2], atoi(argv[offset+3]),
+ atoi(argv[offset+4]), atoi(argv[offset+5]),
+ (argc-offset-6)/3, argv+offset + 6, result);
+
+ dialog_update();
+ if (retval == 0) {
+ unsigned char *s, *h; int first;
+
+ h = result;
+ first = 1;
+ while ((s = strchr(h, '\n')) != NULL) {
+ *s++ = '\0';
+ if (!first)
+ fputc(' ', stderr);
+ else
+ first = 0;
+ fprintf(stderr, "\"%s\"", h);
+ h = s;
+ }
+ }
+ if (clear_screen) /* clear screen before exit */
+ dialog_clear();
+ end_dialog();
+ return retval;
+ }
+ else if (!strcmp(argv[offset+1], "--radiolist")) {
+ if (argc-offset < 9 || ((argc-offset-6) % 3)) {
+ Usage(argv[0]);
+ exit(-1);
+ }
+ init_dialog();
+ retval = dialog_radiolist(title, argv[offset+2], atoi(argv[offset+3]),
+ atoi(argv[offset+4]), atoi(argv[offset+5]),
+ (argc-offset-6)/3, argv+offset + 6, result);
+
+ dialog_update();
+ if (retval == 0)
+ fputs(result, stderr);
+ if (clear_screen) /* clear screen before exit */
+ dialog_clear();
+ end_dialog();
+ return retval;
+ }
+ else if (!strcmp(argv[offset+1], "--inputbox")) {
+ if (argc-offset != 5 && argc-offset != 6) {
+ Usage(argv[0]);
+ exit(-1);
+ }
+ if (argc-offset == 6)
+ strcpy(result, argv[offset+5]);
+ else
+ *result = '\0';
+ init_dialog();
+ retval = dialog_inputbox(title, argv[offset+2], atoi(argv[offset+3]),
+ atoi(argv[offset+4]), result);
+
+ dialog_update();
+ if (retval == 0)
+ fputs(result, stderr);
+ if (clear_screen) /* clear screen before exit */
+ dialog_clear();
+ end_dialog();
+ return retval;
+ }
+
+ Usage(argv[0]);
+ exit(-1);
+}
+/* End of main() */
+
+
+/*
+ * Print program usage
+ */
+void Usage(unsigned char *name)
+{
+ fprintf(stderr, "\
+\ndialog version 0.3, by Savio Lam (lam836@cs.cuhk.hk).\
+\n patched to version %s by Stuart Herbert (S.Herbert@shef.ac.uk)\
+\n Changes Copyright (C) 1995 by Andrey A. Chernov, Moscow, Russia\
+\n\
+\n* Display dialog boxes from shell scripts *\
+\n\
+\nUsage: %s --clear\
+\n %s --create-rc <file>\
+\n %s [--title <title>] [--clear] [--hline <line>] [--hfile <file>]\\\
+\n <Box options>\
+\n\
+\nBox options:\
+\n\
+\n --yesno <text> <height> <width>\
+\n --msgbox <text> <height> <width>\
+\n --prgbox \"<command line>\" <height> <width>\
+\n --infobox <text> <height> <width>\
+\n --inputbox <text> <height> <width> [<init string>]\
+\n --textbox <file> <height> <width>\
+\n --menu <text> <height> <width> <menu height> <tag1> <item1>...\
+\n --checklist <text> <height> <width> <list height> <tag1> <item1> <status1>...\
+\n --radiolist <text> <height> <width> <list height> <tag1> <item1> <status1>...\n", VERSION, name, name, name);
+}
+/* End of Usage() */
diff --git a/gnu/usr.bin/diff/COPYING b/gnu/usr.bin/diff/COPYING
new file mode 100644
index 0000000..a43ea21
--- /dev/null
+++ b/gnu/usr.bin/diff/COPYING
@@ -0,0 +1,339 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 675 Mass Ave, Cambridge, MA 02139, USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ Appendix: How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) 19yy <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) 19yy name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/gnu/usr.bin/diff/Makefile b/gnu/usr.bin/diff/Makefile
new file mode 100644
index 0000000..a6bc385
--- /dev/null
+++ b/gnu/usr.bin/diff/Makefile
@@ -0,0 +1,12 @@
+# $Id$
+PROG= diff
+SRCS= diff.c analyze.c io.c context.c ed.c normal.c ifdef.c util.c dir.c \
+ version.c getopt.c getopt1.c side.c cmpbuf.c
+CFLAGS+=-DHAVE_CONFIG_H
+
+SUBDIR+= doc
+
+DPADD+= ${LIBGNUREGEX}
+LDADD+= -lgnuregex
+
+.include <bsd.prog.mk>
diff --git a/gnu/usr.bin/diff/NEWS b/gnu/usr.bin/diff/NEWS
new file mode 100644
index 0000000..dcde122
--- /dev/null
+++ b/gnu/usr.bin/diff/NEWS
@@ -0,0 +1,126 @@
+User-visible changes in version 2.7:
+
+* New diff option: --binary (useful only on non-Posix hosts)
+* diff -b and -w now ignore line incompleteness; -B no longer does this.
+* cmp -c now uses locale to decide which output characters to quote.
+* Help and version messages are reorganized.
+
+
+User-visible changes in version 2.6:
+
+* New cmp, diff, diff3, sdiff option: --help
+* A new heuristic for diff greatly reduces the time needed to compare
+ large input files that contain many differences.
+* Partly as a result, GNU diff's output is not exactly the same as before.
+ Usually it is a bit smaller, but sometimes it is a bit larger.
+
+
+User-visible changes in version 2.5:
+
+* New cmp option: -v --version
+
+
+User-visible changes in version 2.4:
+
+* New cmp option: --ignore-initial=BYTES
+* New diff3 option: -T --initial-tab
+* New diff option: --line-format=FORMAT
+* New diff group format specifications:
+ <PRINTF_SPEC>[eflmnEFLMN]
+ A printf spec followed by one of the following letters
+ causes the integer corresponding to that letter to be
+ printed according to the printf specification.
+ E.g. `%5df' prints the number of the first line in the
+ group in the old file using the "%5d" format.
+ e: line number just before the group in old file; equals f - 1
+ f: first line number in group in the old file
+ l: last line number in group in the old file
+ m: line number just after the group in old file; equals l + 1
+ n: number of lines in group in the old file; equals l - f + 1
+ E, F, L, M, N: likewise, for lines in the new file
+ %(A=B?T:E)
+ If A equals B then T else E. A and B are each either a decimal
+ constant or a single letter interpreted as above. T and E are
+ arbitrary format strings. This format spec is equivalent to T if
+ A's value equals B's; otherwise it is equivalent to E. For
+ example, `%(N=0?no:%dN) line%(N=1?:s)' is equivalent to `no lines'
+ if N (the number of lines in the group in the the new file) is 0,
+ to `1 line' if N is 1, and to `%dN lines' otherwise.
+ %c'C'
+ where C is a single character, stands for the character C. C may not
+ be a backslash or an apostrophe. E.g. %c':' stands for a colon.
+ %c'\O'
+ where O is a string of 1, 2, or 3 octal digits, stands for the
+ character with octal code O. E.g. %c'\0' stands for a null character.
+* New diff line format specifications:
+ <PRINTF_SPEC>n
+ The line number, printed with <PRINTF_SPEC>.
+ E.g. `%5dn' prints the line number with a "%5d" format.
+ %c'C'
+ %c'\O'
+ The character C, or with octal code O, as above.
+* Supported <PRINTF_SPEC>s have the same meaning as with printf, but must
+ match the extended regular expression %-*[0-9]*(\.[0-9]*)?[doxX].
+* The format spec %0 introduced in version 2.1 has been removed, since it
+ is incompatible with printf specs like %02d. To represent a null char,
+ use %c'\0' instead.
+* cmp and diff now conform to Posix.2 (ISO/IEC 9945-2:1993)
+ if the underlying system conforms to Posix:
+ - Some messages' wordings are changed in minor ways.
+ - ``White space'' is now whatever C's `isspace' says it is.
+ - When comparing directories, if `diff' finds a file that is not a regular
+ file or a directory, it reports the file's type instead of diffing it.
+ (As usual, it follows symbolic links first.)
+ - When signaled, sdiff exits with the signal's status, not with status 2.
+* Now portable to hosts where int, long, pointer, etc. are not all the same
+ size.
+* `cmp - -' now works like `diff - -'.
+
+
+User-visible changes in version 2.3:
+
+* New diff option: --horizon-lines=lines
+
+
+User-visible changes in version 2.1:
+
+* New diff options:
+ --{old,new,unchanged}-line-format='format'
+ --{old,new,unchanged,changed}-group-format='format'
+ -U
+* New diff3 option:
+ -A --show-all
+* diff3 -m now defaults to -A, not -E.
+* diff3 now takes up to three -L or --label options, not just two.
+ If just two options are given, they refer to the first two input files,
+ not the first and third input files.
+* sdiff and diff -y handle incomplete lines.
+
+
+User-visible changes in version 2.0:
+
+* Add sdiff and cmp programs.
+* Add Texinfo documentation.
+* Add configure script.
+* Improve diff performance.
+* New diff options:
+-x --exclude
+-X --exclude-from
+-P --unidirectional-new-file
+-W --width
+-y --side-by-side
+--left-column
+--sdiff-merge-assist
+--suppress-common-lines
+* diff options renamed:
+--label renamed from --file-label
+--forward-ed renamed from --reversed-ed
+--paginate renamed from --print
+--entire-new-file renamed from --entire-new-files
+--new-file renamed from --new-files
+--all-text removed
+* New diff3 options:
+-v --version
+* Add long-named equivalents for other diff3 options.
+* diff options -F (--show-function-line) and -I (--ignore-matching-lines)
+ can now be given more than once.
diff --git a/gnu/usr.bin/diff/analyze.c b/gnu/usr.bin/diff/analyze.c
new file mode 100644
index 0000000..03f5647
--- /dev/null
+++ b/gnu/usr.bin/diff/analyze.c
@@ -0,0 +1,1084 @@
+/* Analyze file differences for GNU DIFF.
+ Copyright (C) 1988, 1989, 1992, 1993 Free Software Foundation, Inc.
+
+This file is part of GNU DIFF.
+
+GNU DIFF is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU DIFF is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU DIFF; see the file COPYING. If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* The basic algorithm is described in:
+ "An O(ND) Difference Algorithm and its Variations", Eugene Myers,
+ Algorithmica Vol. 1 No. 2, 1986, pp. 251-266;
+ see especially section 4.2, which describes the variation used below.
+ Unless the --minimal option is specified, this code uses the TOO_EXPENSIVE
+ heuristic, by Paul Eggert, to limit the cost to O(N**1.5 log N)
+ at the price of producing suboptimal output for large inputs with
+ many differences.
+
+ The basic algorithm was independently discovered as described in:
+ "Algorithms for Approximate String Matching", E. Ukkonen,
+ Information and Control Vol. 64, 1985, pp. 100-118. */
+
+#include "diff.h"
+#include "cmpbuf.h"
+
+extern int no_discards;
+
+static int *xvec, *yvec; /* Vectors being compared. */
+static int *fdiag; /* Vector, indexed by diagonal, containing
+ 1 + the X coordinate of the point furthest
+ along the given diagonal in the forward
+ search of the edit matrix. */
+static int *bdiag; /* Vector, indexed by diagonal, containing
+ the X coordinate of the point furthest
+ along the given diagonal in the backward
+ search of the edit matrix. */
+static int too_expensive; /* Edit scripts longer than this are too
+ expensive to compute. */
+
+#define SNAKE_LIMIT 20 /* Snakes bigger than this are considered `big'. */
+
+struct partition
+{
+ int xmid, ymid; /* Midpoints of this partition. */
+ int lo_minimal; /* Nonzero if low half will be analyzed minimally. */
+ int hi_minimal; /* Likewise for high half. */
+};
+
+static int diag PARAMS((int, int, int, int, int, struct partition *));
+static struct change *add_change PARAMS((int, int, int, int, struct change *));
+static struct change *build_reverse_script PARAMS((struct file_data const[]));
+static struct change *build_script PARAMS((struct file_data const[]));
+static void briefly_report PARAMS((int, struct file_data const[]));
+static void compareseq PARAMS((int, int, int, int, int));
+static void discard_confusing_lines PARAMS((struct file_data[]));
+static void shift_boundaries PARAMS((struct file_data[]));
+
+/* Find the midpoint of the shortest edit script for a specified
+ portion of the two files.
+
+ Scan from the beginnings of the files, and simultaneously from the ends,
+ doing a breadth-first search through the space of edit-sequence.
+ When the two searches meet, we have found the midpoint of the shortest
+ edit sequence.
+
+ If MINIMAL is nonzero, find the minimal edit script regardless
+ of expense. Otherwise, if the search is too expensive, use
+ heuristics to stop the search and report a suboptimal answer.
+
+ Set PART->(XMID,YMID) to the midpoint (XMID,YMID). The diagonal number
+ XMID - YMID equals the number of inserted lines minus the number
+ of deleted lines (counting only lines before the midpoint).
+ Return the approximate edit cost; this is the total number of
+ lines inserted or deleted (counting only lines before the midpoint),
+ unless a heuristic is used to terminate the search prematurely.
+
+ Set PART->LEFT_MINIMAL to nonzero iff the minimal edit script for the
+ left half of the partition is known; similarly for PART->RIGHT_MINIMAL.
+
+ This function assumes that the first lines of the specified portions
+ of the two files do not match, and likewise that the last lines do not
+ match. The caller must trim matching lines from the beginning and end
+ of the portions it is going to specify.
+
+ If we return the "wrong" partitions,
+ the worst this can do is cause suboptimal diff output.
+ It cannot cause incorrect diff output. */
+
+static int
+diag (xoff, xlim, yoff, ylim, minimal, part)
+ int xoff, xlim, yoff, ylim, minimal;
+ struct partition *part;
+{
+ int *const fd = fdiag; /* Give the compiler a chance. */
+ int *const bd = bdiag; /* Additional help for the compiler. */
+ int const *const xv = xvec; /* Still more help for the compiler. */
+ int const *const yv = yvec; /* And more and more . . . */
+ int const dmin = xoff - ylim; /* Minimum valid diagonal. */
+ int const dmax = xlim - yoff; /* Maximum valid diagonal. */
+ int const fmid = xoff - yoff; /* Center diagonal of top-down search. */
+ int const bmid = xlim - ylim; /* Center diagonal of bottom-up search. */
+ int fmin = fmid, fmax = fmid; /* Limits of top-down search. */
+ int bmin = bmid, bmax = bmid; /* Limits of bottom-up search. */
+ int c; /* Cost. */
+ int odd = (fmid - bmid) & 1; /* True if southeast corner is on an odd
+ diagonal with respect to the northwest. */
+
+ fd[fmid] = xoff;
+ bd[bmid] = xlim;
+
+ for (c = 1;; ++c)
+ {
+ int d; /* Active diagonal. */
+ int big_snake = 0;
+
+ /* Extend the top-down search by an edit step in each diagonal. */
+ fmin > dmin ? fd[--fmin - 1] = -1 : ++fmin;
+ fmax < dmax ? fd[++fmax + 1] = -1 : --fmax;
+ for (d = fmax; d >= fmin; d -= 2)
+ {
+ int x, y, oldx, tlo = fd[d - 1], thi = fd[d + 1];
+
+ if (tlo >= thi)
+ x = tlo + 1;
+ else
+ x = thi;
+ oldx = x;
+ y = x - d;
+ while (x < xlim && y < ylim && xv[x] == yv[y])
+ ++x, ++y;
+ if (x - oldx > SNAKE_LIMIT)
+ big_snake = 1;
+ fd[d] = x;
+ if (odd && bmin <= d && d <= bmax && bd[d] <= x)
+ {
+ part->xmid = x;
+ part->ymid = y;
+ part->lo_minimal = part->hi_minimal = 1;
+ return 2 * c - 1;
+ }
+ }
+
+ /* Similarly extend the bottom-up search. */
+ bmin > dmin ? bd[--bmin - 1] = INT_MAX : ++bmin;
+ bmax < dmax ? bd[++bmax + 1] = INT_MAX : --bmax;
+ for (d = bmax; d >= bmin; d -= 2)
+ {
+ int x, y, oldx, tlo = bd[d - 1], thi = bd[d + 1];
+
+ if (tlo < thi)
+ x = tlo;
+ else
+ x = thi - 1;
+ oldx = x;
+ y = x - d;
+ while (x > xoff && y > yoff && xv[x - 1] == yv[y - 1])
+ --x, --y;
+ if (oldx - x > SNAKE_LIMIT)
+ big_snake = 1;
+ bd[d] = x;
+ if (!odd && fmin <= d && d <= fmax && x <= fd[d])
+ {
+ part->xmid = x;
+ part->ymid = y;
+ part->lo_minimal = part->hi_minimal = 1;
+ return 2 * c;
+ }
+ }
+
+ if (minimal)
+ continue;
+
+ /* Heuristic: check occasionally for a diagonal that has made
+ lots of progress compared with the edit distance.
+ If we have any such, find the one that has made the most
+ progress and return it as if it had succeeded.
+
+ With this heuristic, for files with a constant small density
+ of changes, the algorithm is linear in the file size. */
+
+ if (c > 200 && big_snake && heuristic)
+ {
+ int best;
+
+ best = 0;
+ for (d = fmax; d >= fmin; d -= 2)
+ {
+ int dd = d - fmid;
+ int x = fd[d];
+ int y = x - d;
+ int v = (x - xoff) * 2 - dd;
+ if (v > 12 * (c + (dd < 0 ? -dd : dd)))
+ {
+ if (v > best
+ && xoff + SNAKE_LIMIT <= x && x < xlim
+ && yoff + SNAKE_LIMIT <= y && y < ylim)
+ {
+ /* We have a good enough best diagonal;
+ now insist that it end with a significant snake. */
+ int k;
+
+ for (k = 1; xv[x - k] == yv[y - k]; k++)
+ if (k == SNAKE_LIMIT)
+ {
+ best = v;
+ part->xmid = x;
+ part->ymid = y;
+ break;
+ }
+ }
+ }
+ }
+ if (best > 0)
+ {
+ part->lo_minimal = 1;
+ part->hi_minimal = 0;
+ return 2 * c - 1;
+ }
+
+ best = 0;
+ for (d = bmax; d >= bmin; d -= 2)
+ {
+ int dd = d - bmid;
+ int x = bd[d];
+ int y = x - d;
+ int v = (xlim - x) * 2 + dd;
+ if (v > 12 * (c + (dd < 0 ? -dd : dd)))
+ {
+ if (v > best
+ && xoff < x && x <= xlim - SNAKE_LIMIT
+ && yoff < y && y <= ylim - SNAKE_LIMIT)
+ {
+ /* We have a good enough best diagonal;
+ now insist that it end with a significant snake. */
+ int k;
+
+ for (k = 0; xv[x + k] == yv[y + k]; k++)
+ if (k == SNAKE_LIMIT - 1)
+ {
+ best = v;
+ part->xmid = x;
+ part->ymid = y;
+ break;
+ }
+ }
+ }
+ }
+ if (best > 0)
+ {
+ part->lo_minimal = 0;
+ part->hi_minimal = 1;
+ return 2 * c - 1;
+ }
+ }
+
+ /* Heuristic: if we've gone well beyond the call of duty,
+ give up and report halfway between our best results so far. */
+ if (c >= too_expensive)
+ {
+ int fxybest, fxbest;
+ int bxybest, bxbest;
+
+ fxbest = bxbest = 0; /* Pacify `gcc -Wall'. */
+
+ /* Find forward diagonal that maximizes X + Y. */
+ fxybest = -1;
+ for (d = fmax; d >= fmin; d -= 2)
+ {
+ int x = min (fd[d], xlim);
+ int y = x - d;
+ if (ylim < y)
+ x = ylim + d, y = ylim;
+ if (fxybest < x + y)
+ {
+ fxybest = x + y;
+ fxbest = x;
+ }
+ }
+
+ /* Find backward diagonal that minimizes X + Y. */
+ bxybest = INT_MAX;
+ for (d = bmax; d >= bmin; d -= 2)
+ {
+ int x = max (xoff, bd[d]);
+ int y = x - d;
+ if (y < yoff)
+ x = yoff + d, y = yoff;
+ if (x + y < bxybest)
+ {
+ bxybest = x + y;
+ bxbest = x;
+ }
+ }
+
+ /* Use the better of the two diagonals. */
+ if ((xlim + ylim) - bxybest < fxybest - (xoff + yoff))
+ {
+ part->xmid = fxbest;
+ part->ymid = fxybest - fxbest;
+ part->lo_minimal = 1;
+ part->hi_minimal = 0;
+ }
+ else
+ {
+ part->xmid = bxbest;
+ part->ymid = bxybest - bxbest;
+ part->lo_minimal = 0;
+ part->hi_minimal = 1;
+ }
+ return 2 * c - 1;
+ }
+ }
+}
+
+/* Compare in detail contiguous subsequences of the two files
+ which are known, as a whole, to match each other.
+
+ The results are recorded in the vectors files[N].changed_flag, by
+ storing a 1 in the element for each line that is an insertion or deletion.
+
+ The subsequence of file 0 is [XOFF, XLIM) and likewise for file 1.
+
+ Note that XLIM, YLIM are exclusive bounds.
+ All line numbers are origin-0 and discarded lines are not counted.
+
+ If MINIMAL is nonzero, find a minimal difference no matter how
+ expensive it is. */
+
+static void
+compareseq (xoff, xlim, yoff, ylim, minimal)
+ int xoff, xlim, yoff, ylim, minimal;
+{
+ int * const xv = xvec; /* Help the compiler. */
+ int * const yv = yvec;
+
+ /* Slide down the bottom initial diagonal. */
+ while (xoff < xlim && yoff < ylim && xv[xoff] == yv[yoff])
+ ++xoff, ++yoff;
+ /* Slide up the top initial diagonal. */
+ while (xlim > xoff && ylim > yoff && xv[xlim - 1] == yv[ylim - 1])
+ --xlim, --ylim;
+
+ /* Handle simple cases. */
+ if (xoff == xlim)
+ while (yoff < ylim)
+ files[1].changed_flag[files[1].realindexes[yoff++]] = 1;
+ else if (yoff == ylim)
+ while (xoff < xlim)
+ files[0].changed_flag[files[0].realindexes[xoff++]] = 1;
+ else
+ {
+ int c;
+ struct partition part;
+
+ /* Find a point of correspondence in the middle of the files. */
+
+ c = diag (xoff, xlim, yoff, ylim, minimal, &part);
+
+ if (c == 1)
+ {
+ /* This should be impossible, because it implies that
+ one of the two subsequences is empty,
+ and that case was handled above without calling `diag'.
+ Let's verify that this is true. */
+ abort ();
+#if 0
+ /* The two subsequences differ by a single insert or delete;
+ record it and we are done. */
+ if (part.xmid - part.ymid < xoff - yoff)
+ files[1].changed_flag[files[1].realindexes[part.ymid - 1]] = 1;
+ else
+ files[0].changed_flag[files[0].realindexes[part.xmid]] = 1;
+#endif
+ }
+ else
+ {
+ /* Use the partitions to split this problem into subproblems. */
+ compareseq (xoff, part.xmid, yoff, part.ymid, part.lo_minimal);
+ compareseq (part.xmid, xlim, part.ymid, ylim, part.hi_minimal);
+ }
+ }
+}
+
+/* Discard lines from one file that have no matches in the other file.
+
+ A line which is discarded will not be considered by the actual
+ comparison algorithm; it will be as if that line were not in the file.
+ The file's `realindexes' table maps virtual line numbers
+ (which don't count the discarded lines) into real line numbers;
+ this is how the actual comparison algorithm produces results
+ that are comprehensible when the discarded lines are counted.
+
+ When we discard a line, we also mark it as a deletion or insertion
+ so that it will be printed in the output. */
+
+static void
+discard_confusing_lines (filevec)
+ struct file_data filevec[];
+{
+ unsigned int f, i;
+ char *discarded[2];
+ int *equiv_count[2];
+ int *p;
+
+ /* Allocate our results. */
+ p = (int *) xmalloc ((filevec[0].buffered_lines + filevec[1].buffered_lines)
+ * (2 * sizeof (int)));
+ for (f = 0; f < 2; f++)
+ {
+ filevec[f].undiscarded = p; p += filevec[f].buffered_lines;
+ filevec[f].realindexes = p; p += filevec[f].buffered_lines;
+ }
+
+ /* Set up equiv_count[F][I] as the number of lines in file F
+ that fall in equivalence class I. */
+
+ p = (int *) xmalloc (filevec[0].equiv_max * (2 * sizeof (int)));
+ equiv_count[0] = p;
+ equiv_count[1] = p + filevec[0].equiv_max;
+ bzero (p, filevec[0].equiv_max * (2 * sizeof (int)));
+
+ for (i = 0; i < filevec[0].buffered_lines; ++i)
+ ++equiv_count[0][filevec[0].equivs[i]];
+ for (i = 0; i < filevec[1].buffered_lines; ++i)
+ ++equiv_count[1][filevec[1].equivs[i]];
+
+ /* Set up tables of which lines are going to be discarded. */
+
+ discarded[0] = xmalloc (sizeof (char)
+ * (filevec[0].buffered_lines
+ + filevec[1].buffered_lines));
+ discarded[1] = discarded[0] + filevec[0].buffered_lines;
+ bzero (discarded[0], sizeof (char) * (filevec[0].buffered_lines
+ + filevec[1].buffered_lines));
+
+ /* Mark to be discarded each line that matches no line of the other file.
+ If a line matches many lines, mark it as provisionally discardable. */
+
+ for (f = 0; f < 2; f++)
+ {
+ unsigned int end = filevec[f].buffered_lines;
+ char *discards = discarded[f];
+ int *counts = equiv_count[1 - f];
+ int *equivs = filevec[f].equivs;
+ unsigned int many = 5;
+ unsigned int tem = end / 64;
+
+ /* Multiply MANY by approximate square root of number of lines.
+ That is the threshold for provisionally discardable lines. */
+ while ((tem = tem >> 2) > 0)
+ many *= 2;
+
+ for (i = 0; i < end; i++)
+ {
+ int nmatch;
+ if (equivs[i] == 0)
+ continue;
+ nmatch = counts[equivs[i]];
+ if (nmatch == 0)
+ discards[i] = 1;
+ else if (nmatch > many)
+ discards[i] = 2;
+ }
+ }
+
+ /* Don't really discard the provisional lines except when they occur
+ in a run of discardables, with nonprovisionals at the beginning
+ and end. */
+
+ for (f = 0; f < 2; f++)
+ {
+ unsigned int end = filevec[f].buffered_lines;
+ register char *discards = discarded[f];
+
+ for (i = 0; i < end; i++)
+ {
+ /* Cancel provisional discards not in middle of run of discards. */
+ if (discards[i] == 2)
+ discards[i] = 0;
+ else if (discards[i] != 0)
+ {
+ /* We have found a nonprovisional discard. */
+ register int j;
+ unsigned int length;
+ unsigned int provisional = 0;
+
+ /* Find end of this run of discardable lines.
+ Count how many are provisionally discardable. */
+ for (j = i; j < end; j++)
+ {
+ if (discards[j] == 0)
+ break;
+ if (discards[j] == 2)
+ ++provisional;
+ }
+
+ /* Cancel provisional discards at end, and shrink the run. */
+ while (j > i && discards[j - 1] == 2)
+ discards[--j] = 0, --provisional;
+
+ /* Now we have the length of a run of discardable lines
+ whose first and last are not provisional. */
+ length = j - i;
+
+ /* If 1/4 of the lines in the run are provisional,
+ cancel discarding of all provisional lines in the run. */
+ if (provisional * 4 > length)
+ {
+ while (j > i)
+ if (discards[--j] == 2)
+ discards[j] = 0;
+ }
+ else
+ {
+ register unsigned int consec;
+ unsigned int minimum = 1;
+ unsigned int tem = length / 4;
+
+ /* MINIMUM is approximate square root of LENGTH/4.
+ A subrun of two or more provisionals can stand
+ when LENGTH is at least 16.
+ A subrun of 4 or more can stand when LENGTH >= 64. */
+ while ((tem = tem >> 2) > 0)
+ minimum *= 2;
+ minimum++;
+
+ /* Cancel any subrun of MINIMUM or more provisionals
+ within the larger run. */
+ for (j = 0, consec = 0; j < length; j++)
+ if (discards[i + j] != 2)
+ consec = 0;
+ else if (minimum == ++consec)
+ /* Back up to start of subrun, to cancel it all. */
+ j -= consec;
+ else if (minimum < consec)
+ discards[i + j] = 0;
+
+ /* Scan from beginning of run
+ until we find 3 or more nonprovisionals in a row
+ or until the first nonprovisional at least 8 lines in.
+ Until that point, cancel any provisionals. */
+ for (j = 0, consec = 0; j < length; j++)
+ {
+ if (j >= 8 && discards[i + j] == 1)
+ break;
+ if (discards[i + j] == 2)
+ consec = 0, discards[i + j] = 0;
+ else if (discards[i + j] == 0)
+ consec = 0;
+ else
+ consec++;
+ if (consec == 3)
+ break;
+ }
+
+ /* I advances to the last line of the run. */
+ i += length - 1;
+
+ /* Same thing, from end. */
+ for (j = 0, consec = 0; j < length; j++)
+ {
+ if (j >= 8 && discards[i - j] == 1)
+ break;
+ if (discards[i - j] == 2)
+ consec = 0, discards[i - j] = 0;
+ else if (discards[i - j] == 0)
+ consec = 0;
+ else
+ consec++;
+ if (consec == 3)
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ /* Actually discard the lines. */
+ for (f = 0; f < 2; f++)
+ {
+ char *discards = discarded[f];
+ unsigned int end = filevec[f].buffered_lines;
+ unsigned int j = 0;
+ for (i = 0; i < end; ++i)
+ if (no_discards || discards[i] == 0)
+ {
+ filevec[f].undiscarded[j] = filevec[f].equivs[i];
+ filevec[f].realindexes[j++] = i;
+ }
+ else
+ filevec[f].changed_flag[i] = 1;
+ filevec[f].nondiscarded_lines = j;
+ }
+
+ free (discarded[0]);
+ free (equiv_count[0]);
+}
+
+/* Adjust inserts/deletes of identical lines to join changes
+ as much as possible.
+
+ We do something when a run of changed lines include a
+ line at one end and have an excluded, identical line at the other.
+ We are free to choose which identical line is included.
+ `compareseq' usually chooses the one at the beginning,
+ but usually it is cleaner to consider the following identical line
+ to be the "change". */
+
+int inhibit;
+
+static void
+shift_boundaries (filevec)
+ struct file_data filevec[];
+{
+ int f;
+
+ if (inhibit)
+ return;
+
+ for (f = 0; f < 2; f++)
+ {
+ char *changed = filevec[f].changed_flag;
+ char const *other_changed = filevec[1-f].changed_flag;
+ int const *equivs = filevec[f].equivs;
+ int i = 0;
+ int j = 0;
+ int i_end = filevec[f].buffered_lines;
+
+ while (1)
+ {
+ int runlength, start, corresponding;
+
+ /* Scan forwards to find beginning of another run of changes.
+ Also keep track of the corresponding point in the other file. */
+
+ while (i < i_end && changed[i] == 0)
+ {
+ while (other_changed[j++])
+ continue;
+ i++;
+ }
+
+ if (i == i_end)
+ break;
+
+ start = i;
+
+ /* Find the end of this run of changes. */
+
+ while (changed[++i])
+ continue;
+ while (other_changed[j])
+ j++;
+
+ do
+ {
+ /* Record the length of this run of changes, so that
+ we can later determine whether the run has grown. */
+ runlength = i - start;
+
+ /* Move the changed region back, so long as the
+ previous unchanged line matches the last changed one.
+ This merges with previous changed regions. */
+
+ while (start && equivs[start - 1] == equivs[i - 1])
+ {
+ changed[--start] = 1;
+ changed[--i] = 0;
+ while (changed[start - 1])
+ start--;
+ while (other_changed[--j])
+ continue;
+ }
+
+ /* Set CORRESPONDING to the end of the changed run, at the last
+ point where it corresponds to a changed run in the other file.
+ CORRESPONDING == I_END means no such point has been found. */
+ corresponding = other_changed[j - 1] ? i : i_end;
+
+ /* Move the changed region forward, so long as the
+ first changed line matches the following unchanged one.
+ This merges with following changed regions.
+ Do this second, so that if there are no merges,
+ the changed region is moved forward as far as possible. */
+
+ while (i != i_end && equivs[start] == equivs[i])
+ {
+ changed[start++] = 0;
+ changed[i++] = 1;
+ while (changed[i])
+ i++;
+ while (other_changed[++j])
+ corresponding = i;
+ }
+ }
+ while (runlength != i - start);
+
+ /* If possible, move the fully-merged run of changes
+ back to a corresponding run in the other file. */
+
+ while (corresponding < i)
+ {
+ changed[--start] = 1;
+ changed[--i] = 0;
+ while (other_changed[--j])
+ continue;
+ }
+ }
+ }
+}
+
+/* Cons an additional entry onto the front of an edit script OLD.
+ LINE0 and LINE1 are the first affected lines in the two files (origin 0).
+ DELETED is the number of lines deleted here from file 0.
+ INSERTED is the number of lines inserted here in file 1.
+
+ If DELETED is 0 then LINE0 is the number of the line before
+ which the insertion was done; vice versa for INSERTED and LINE1. */
+
+static struct change *
+add_change (line0, line1, deleted, inserted, old)
+ int line0, line1, deleted, inserted;
+ struct change *old;
+{
+ struct change *new = (struct change *) xmalloc (sizeof (struct change));
+
+ new->line0 = line0;
+ new->line1 = line1;
+ new->inserted = inserted;
+ new->deleted = deleted;
+ new->link = old;
+ return new;
+}
+
+/* Scan the tables of which lines are inserted and deleted,
+ producing an edit script in reverse order. */
+
+static struct change *
+build_reverse_script (filevec)
+ struct file_data const filevec[];
+{
+ struct change *script = 0;
+ char *changed0 = filevec[0].changed_flag;
+ char *changed1 = filevec[1].changed_flag;
+ int len0 = filevec[0].buffered_lines;
+ int len1 = filevec[1].buffered_lines;
+
+ /* Note that changedN[len0] does exist, and contains 0. */
+
+ int i0 = 0, i1 = 0;
+
+ while (i0 < len0 || i1 < len1)
+ {
+ if (changed0[i0] || changed1[i1])
+ {
+ int line0 = i0, line1 = i1;
+
+ /* Find # lines changed here in each file. */
+ while (changed0[i0]) ++i0;
+ while (changed1[i1]) ++i1;
+
+ /* Record this change. */
+ script = add_change (line0, line1, i0 - line0, i1 - line1, script);
+ }
+
+ /* We have reached lines in the two files that match each other. */
+ i0++, i1++;
+ }
+
+ return script;
+}
+
+/* Scan the tables of which lines are inserted and deleted,
+ producing an edit script in forward order. */
+
+static struct change *
+build_script (filevec)
+ struct file_data const filevec[];
+{
+ struct change *script = 0;
+ char *changed0 = filevec[0].changed_flag;
+ char *changed1 = filevec[1].changed_flag;
+ int i0 = filevec[0].buffered_lines, i1 = filevec[1].buffered_lines;
+
+ /* Note that changedN[-1] does exist, and contains 0. */
+
+ while (i0 >= 0 || i1 >= 0)
+ {
+ if (changed0[i0 - 1] || changed1[i1 - 1])
+ {
+ int line0 = i0, line1 = i1;
+
+ /* Find # lines changed here in each file. */
+ while (changed0[i0 - 1]) --i0;
+ while (changed1[i1 - 1]) --i1;
+
+ /* Record this change. */
+ script = add_change (i0, i1, line0 - i0, line1 - i1, script);
+ }
+
+ /* We have reached lines in the two files that match each other. */
+ i0--, i1--;
+ }
+
+ return script;
+}
+
+/* If CHANGES, briefly report that two files differed. */
+static void
+briefly_report (changes, filevec)
+ int changes;
+ struct file_data const filevec[];
+{
+ if (changes)
+ message (no_details_flag ? "Files %s and %s differ\n"
+ : "Binary files %s and %s differ\n",
+ filevec[0].name, filevec[1].name);
+}
+
+/* Report the differences of two files. DEPTH is the current directory
+ depth. */
+int
+diff_2_files (filevec, depth)
+ struct file_data filevec[];
+ int depth;
+{
+ int diags;
+ int i;
+ struct change *e, *p;
+ struct change *script;
+ int changes;
+
+
+ /* If we have detected that either file is binary,
+ compare the two files as binary. This can happen
+ only when the first chunk is read.
+ Also, --brief without any --ignore-* options means
+ we can speed things up by treating the files as binary. */
+
+ if (read_files (filevec, no_details_flag & ~ignore_some_changes))
+ {
+ /* Files with different lengths must be different. */
+ if (filevec[0].stat.st_size != filevec[1].stat.st_size
+ && (filevec[0].desc < 0 || S_ISREG (filevec[0].stat.st_mode))
+ && (filevec[1].desc < 0 || S_ISREG (filevec[1].stat.st_mode)))
+ changes = 1;
+
+ /* Standard input equals itself. */
+ else if (filevec[0].desc == filevec[1].desc)
+ changes = 0;
+
+ else
+ /* Scan both files, a buffer at a time, looking for a difference. */
+ {
+ /* Allocate same-sized buffers for both files. */
+ size_t buffer_size = buffer_lcm (STAT_BLOCKSIZE (filevec[0].stat),
+ STAT_BLOCKSIZE (filevec[1].stat));
+ for (i = 0; i < 2; i++)
+ filevec[i].buffer = xrealloc (filevec[i].buffer, buffer_size);
+
+ for (;; filevec[0].buffered_chars = filevec[1].buffered_chars = 0)
+ {
+ /* Read a buffer's worth from both files. */
+ for (i = 0; i < 2; i++)
+ if (0 <= filevec[i].desc)
+ while (filevec[i].buffered_chars != buffer_size)
+ {
+ int r = read (filevec[i].desc,
+ filevec[i].buffer
+ + filevec[i].buffered_chars,
+ buffer_size - filevec[i].buffered_chars);
+ if (r == 0)
+ break;
+ if (r < 0)
+ pfatal_with_name (filevec[i].name);
+ filevec[i].buffered_chars += r;
+ }
+
+ /* If the buffers differ, the files differ. */
+ if (filevec[0].buffered_chars != filevec[1].buffered_chars
+ || (filevec[0].buffered_chars != 0
+ && memcmp (filevec[0].buffer,
+ filevec[1].buffer,
+ filevec[0].buffered_chars) != 0))
+ {
+ changes = 1;
+ break;
+ }
+
+ /* If we reach end of file, the files are the same. */
+ if (filevec[0].buffered_chars != buffer_size)
+ {
+ changes = 0;
+ break;
+ }
+ }
+ }
+
+ briefly_report (changes, filevec);
+ }
+ else
+ {
+ /* Allocate vectors for the results of comparison:
+ a flag for each line of each file, saying whether that line
+ is an insertion or deletion.
+ Allocate an extra element, always zero, at each end of each vector. */
+
+ size_t s = filevec[0].buffered_lines + filevec[1].buffered_lines + 4;
+ filevec[0].changed_flag = xmalloc (s);
+ bzero (filevec[0].changed_flag, s);
+ filevec[0].changed_flag++;
+ filevec[1].changed_flag = filevec[0].changed_flag
+ + filevec[0].buffered_lines + 2;
+
+ /* Some lines are obviously insertions or deletions
+ because they don't match anything. Detect them now, and
+ avoid even thinking about them in the main comparison algorithm. */
+
+ discard_confusing_lines (filevec);
+
+ /* Now do the main comparison algorithm, considering just the
+ undiscarded lines. */
+
+ xvec = filevec[0].undiscarded;
+ yvec = filevec[1].undiscarded;
+ diags = filevec[0].nondiscarded_lines + filevec[1].nondiscarded_lines + 3;
+ fdiag = (int *) xmalloc (diags * (2 * sizeof (int)));
+ bdiag = fdiag + diags;
+ fdiag += filevec[1].nondiscarded_lines + 1;
+ bdiag += filevec[1].nondiscarded_lines + 1;
+
+ /* Set TOO_EXPENSIVE to be approximate square root of input size,
+ bounded below by 256. */
+ too_expensive = 1;
+ for (i = filevec[0].nondiscarded_lines + filevec[1].nondiscarded_lines;
+ i != 0; i >>= 2)
+ too_expensive <<= 1;
+ too_expensive = max (256, too_expensive);
+
+ files[0] = filevec[0];
+ files[1] = filevec[1];
+
+ compareseq (0, filevec[0].nondiscarded_lines,
+ 0, filevec[1].nondiscarded_lines, no_discards);
+
+ free (fdiag - (filevec[1].nondiscarded_lines + 1));
+
+ /* Modify the results slightly to make them prettier
+ in cases where that can validly be done. */
+
+ shift_boundaries (filevec);
+
+ /* Get the results of comparison in the form of a chain
+ of `struct change's -- an edit script. */
+
+ if (output_style == OUTPUT_ED)
+ script = build_reverse_script (filevec);
+ else
+ script = build_script (filevec);
+
+ /* Set CHANGES if we had any diffs.
+ If some changes are ignored, we must scan the script to decide. */
+ if (ignore_blank_lines_flag || ignore_regexp_list)
+ {
+ struct change *next = script;
+ changes = 0;
+
+ while (next && changes == 0)
+ {
+ struct change *this, *end;
+ int first0, last0, first1, last1, deletes, inserts;
+
+ /* Find a set of changes that belong together. */
+ this = next;
+ end = find_change (next);
+
+ /* Disconnect them from the rest of the changes, making them
+ a hunk, and remember the rest for next iteration. */
+ next = end->link;
+ end->link = 0;
+
+ /* Determine whether this hunk is really a difference. */
+ analyze_hunk (this, &first0, &last0, &first1, &last1,
+ &deletes, &inserts);
+
+ /* Reconnect the script so it will all be freed properly. */
+ end->link = next;
+
+ if (deletes || inserts)
+ changes = 1;
+ }
+ }
+ else
+ changes = (script != 0);
+
+ if (no_details_flag)
+ briefly_report (changes, filevec);
+ else
+ {
+ if (changes || ! no_diff_means_no_output)
+ {
+ /* Record info for starting up output,
+ to be used if and when we have some output to print. */
+ setup_output (files[0].name, files[1].name, depth);
+
+ switch (output_style)
+ {
+ case OUTPUT_CONTEXT:
+ print_context_script (script, 0);
+ break;
+
+ case OUTPUT_UNIFIED:
+ print_context_script (script, 1);
+ break;
+
+ case OUTPUT_ED:
+ print_ed_script (script);
+ break;
+
+ case OUTPUT_FORWARD_ED:
+ pr_forward_ed_script (script);
+ break;
+
+ case OUTPUT_RCS:
+ print_rcs_script (script);
+ break;
+
+ case OUTPUT_NORMAL:
+ print_normal_script (script);
+ break;
+
+ case OUTPUT_IFDEF:
+ print_ifdef_script (script);
+ break;
+
+ case OUTPUT_SDIFF:
+ print_sdiff_script (script);
+ }
+
+ finish_output ();
+ }
+ }
+
+ free (filevec[0].undiscarded);
+
+ free (filevec[0].changed_flag - 1);
+
+ for (i = 1; i >= 0; --i)
+ free (filevec[i].equivs);
+
+ for (i = 0; i < 2; ++i)
+ free (filevec[i].linbuf + filevec[i].linbuf_base);
+
+ for (e = script; e; e = p)
+ {
+ p = e->link;
+ free (e);
+ }
+
+ if (! ROBUST_OUTPUT_STYLE (output_style))
+ for (i = 0; i < 2; ++i)
+ if (filevec[i].missing_newline)
+ {
+ error ("No newline at end of file %s", filevec[i].name, "");
+ changes = 2;
+ }
+ }
+
+ if (filevec[0].buffer != filevec[1].buffer)
+ free (filevec[0].buffer);
+ free (filevec[1].buffer);
+
+ return changes;
+}
diff --git a/gnu/usr.bin/diff/cmpbuf.c b/gnu/usr.bin/diff/cmpbuf.c
new file mode 100644
index 0000000..e95a8f9
--- /dev/null
+++ b/gnu/usr.bin/diff/cmpbuf.c
@@ -0,0 +1,40 @@
+/* Buffer primitives for comparison operations.
+ Copyright (C) 1993 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "system.h"
+#include "cmpbuf.h"
+
+/* Least common multiple of two buffer sizes A and B. */
+
+size_t
+buffer_lcm (a, b)
+ size_t a, b;
+{
+ size_t m, n, r;
+
+ /* Yield reasonable values if buffer sizes are zero. */
+ if (!a)
+ return b ? b : 8 * 1024;
+ if (!b)
+ return a;
+
+ /* n = gcd (a, b) */
+ for (m = a, n = b; (r = m % n) != 0; m = n, n = r)
+ continue;
+
+ return a/n * b;
+}
diff --git a/gnu/usr.bin/diff/cmpbuf.h b/gnu/usr.bin/diff/cmpbuf.h
new file mode 100644
index 0000000..e3852b7
--- /dev/null
+++ b/gnu/usr.bin/diff/cmpbuf.h
@@ -0,0 +1,20 @@
+/* Buffer primitives for comparison operations.
+ Copyright (C) 1993 Free Software Foundation, Inc.
+
+This file is part of GNU DIFF.
+
+GNU DIFF is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU DIFF is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU DIFF; see the file COPYING. If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+size_t buffer_lcm PARAMS((size_t, size_t));
diff --git a/gnu/usr.bin/diff/config.h b/gnu/usr.bin/diff/config.h
new file mode 100644
index 0000000..3d7e65b
--- /dev/null
+++ b/gnu/usr.bin/diff/config.h
@@ -0,0 +1,118 @@
+/* config.h. Generated automatically by configure. */
+/* config.hin. Generated automatically from configure.in by autoheader. */
+
+/* Define if using alloca.c. */
+/* #undef C_ALLOCA */
+
+/* Define if the closedir function returns void instead of int. */
+/* #undef CLOSEDIR_VOID */
+
+/* Define to empty if the keyword does not work. */
+/* #undef const */
+
+/* Define to one of _getb67, GETB67, getb67 for Cray-2 and Cray-YMP systems.
+ This function is required for alloca.c support on those systems. */
+/* #undef CRAY_STACKSEG_END */
+
+/* Define if you have <alloca.h> and it should be used (not on Ultrix). */
+/* #undef HAVE_ALLOCA_H */
+
+/* Define if you don't have vprintf but do have _doprnt. */
+/* #undef HAVE_DOPRNT */
+
+/* Define if your struct stat has st_blksize. */
+#define HAVE_ST_BLKSIZE 1
+
+/* Define if you have <vfork.h>. */
+/* #undef HAVE_VFORK_H */
+
+/* Define if you have the vprintf function. */
+#define HAVE_VPRINTF 1
+
+/* Define if on MINIX. */
+/* #undef _MINIX */
+
+/* Define to `int' if <sys/types.h> doesn't define. */
+/* #undef pid_t */
+
+/* Define if the system does not provide POSIX.1 features except
+ with this defined. */
+/* #undef _POSIX_1_SOURCE */
+
+/* Define if you need to in order for stat and other things to work. */
+/* #undef _POSIX_SOURCE */
+
+/* Define as the return type of signal handlers (int or void). */
+#define RETSIGTYPE void
+
+/* If using the C implementation of alloca, define if you know the
+ direction of stack growth for your system; otherwise it will be
+ automatically deduced at run-time.
+ STACK_DIRECTION > 0 => grows toward higher addresses
+ STACK_DIRECTION < 0 => grows toward lower addresses
+ STACK_DIRECTION = 0 => direction of growth unknown
+ */
+/* #undef STACK_DIRECTION */
+
+/* Define if the `S_IS*' macros in <sys/stat.h> do not work properly. */
+/* #undef STAT_MACROS_BROKEN */
+
+/* Define if you have the ANSI C header files. */
+#define STDC_HEADERS 1
+
+/* Define if <sys/wait.h> is compatible with Posix applications. */
+#define HAVE_SYS_WAIT_H 1
+
+/* Define vfork as fork if vfork does not work. */
+/* #undef vfork */
+
+/* Define if you have the dup2 function. */
+#define HAVE_DUP2 1
+
+/* Define if you have the memchr function. */
+#define HAVE_MEMCHR 1
+
+/* Define if you have the sigaction function. */
+#define HAVE_SIGACTION 1
+
+/* Define if you have the strchr function. */
+#define HAVE_STRCHR 1
+
+/* Define if you have the strerror function. */
+#define HAVE_STRERROR 1
+
+/* Define if you have the tmpnam function. */
+#define HAVE_TMPNAM 1
+
+/* Define if you have the <dirent.h> header file. */
+#define HAVE_DIRENT_H 1
+
+/* Define if you have the <fcntl.h> header file. */
+#define HAVE_FCNTL_H 1
+
+/* Define if you have the <limits.h> header file. */
+#define HAVE_LIMITS_H 1
+
+/* Define if you have the <ndir.h> header file. */
+/* #undef HAVE_NDIR_H */
+
+/* Define if you have the <stdlib.h> header file. */
+#define HAVE_STDLIB_H 1
+
+/* Define if you have the <string.h> header file. */
+#define HAVE_STRING_H 1
+
+/* Define if you have the <sys/dir.h> header file. */
+/* #undef HAVE_SYS_DIR_H */
+
+/* Define if you have the <sys/file.h> header file. */
+#define HAVE_SYS_FILE_H 1
+
+/* Define if you have the <sys/ndir.h> header file. */
+/* #undef HAVE_SYS_NDIR_H */
+
+/* Define if you have the <time.h> header file. */
+#define HAVE_TIME_H 1
+
+/* Define if you have the <unistd.h> header file. */
+#define HAVE_UNISTD_H 1
diff --git a/gnu/usr.bin/diff/context.c b/gnu/usr.bin/diff/context.c
new file mode 100644
index 0000000..14f950c
--- /dev/null
+++ b/gnu/usr.bin/diff/context.c
@@ -0,0 +1,468 @@
+/* Context-format output routines for GNU DIFF.
+ Copyright (C) 1988,1989,1991,1992,1993,1994 Free Software Foundation, Inc.
+
+This file is part of GNU DIFF.
+
+GNU DIFF is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU DIFF is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU DIFF; see the file COPYING. If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "diff.h"
+
+static struct change *find_hunk PARAMS((struct change *));
+static void find_function PARAMS((struct file_data const *, int, char const **, size_t *));
+static void mark_ignorable PARAMS((struct change *));
+static void pr_context_hunk PARAMS((struct change *));
+static void pr_unidiff_hunk PARAMS((struct change *));
+static void print_context_label PARAMS ((char const *, struct file_data *, char const *));
+static void print_context_number_range PARAMS((struct file_data const *, int, int));
+static void print_unidiff_number_range PARAMS((struct file_data const *, int, int));
+
+/* Last place find_function started searching from. */
+static int find_function_last_search;
+
+/* The value find_function returned when it started searching there. */
+static int find_function_last_match;
+
+/* Print a label for a context diff, with a file name and date or a label. */
+
+static void
+print_context_label (mark, inf, label)
+ char const *mark;
+ struct file_data *inf;
+ char const *label;
+{
+ if (label)
+ fprintf (outfile, "%s %s\n", mark, label);
+ else
+ {
+ char const *ct = ctime (&inf->stat.st_mtime);
+ if (!ct)
+ ct = "?\n";
+ /* See Posix.2 section 4.17.6.1.4 for this format. */
+ fprintf (outfile, "%s %s\t%s", mark, inf->name, ct);
+ }
+}
+
+/* Print a header for a context diff, with the file names and dates. */
+
+void
+print_context_header (inf, unidiff_flag)
+ struct file_data inf[];
+ int unidiff_flag;
+{
+ if (unidiff_flag)
+ {
+ print_context_label ("---", &inf[0], file_label[0]);
+ print_context_label ("+++", &inf[1], file_label[1]);
+ }
+ else
+ {
+ print_context_label ("***", &inf[0], file_label[0]);
+ print_context_label ("---", &inf[1], file_label[1]);
+ }
+}
+
+/* Print an edit script in context format. */
+
+void
+print_context_script (script, unidiff_flag)
+ struct change *script;
+ int unidiff_flag;
+{
+ if (ignore_blank_lines_flag || ignore_regexp_list)
+ mark_ignorable (script);
+ else
+ {
+ struct change *e;
+ for (e = script; e; e = e->link)
+ e->ignore = 0;
+ }
+
+ find_function_last_search = - files[0].prefix_lines;
+ find_function_last_match = find_function_last_search - 1;
+
+ if (unidiff_flag)
+ print_script (script, find_hunk, pr_unidiff_hunk);
+ else
+ print_script (script, find_hunk, pr_context_hunk);
+}
+
+/* Print a pair of line numbers with a comma, translated for file FILE.
+ If the second number is not greater, use the first in place of it.
+
+ Args A and B are internal line numbers.
+ We print the translated (real) line numbers. */
+
+static void
+print_context_number_range (file, a, b)
+ struct file_data const *file;
+ int a, b;
+{
+ int trans_a, trans_b;
+ translate_range (file, a, b, &trans_a, &trans_b);
+
+ /* Note: we can have B < A in the case of a range of no lines.
+ In this case, we should print the line number before the range,
+ which is B. */
+ if (trans_b > trans_a)
+ fprintf (outfile, "%d,%d", trans_a, trans_b);
+ else
+ fprintf (outfile, "%d", trans_b);
+}
+
+/* Print a portion of an edit script in context format.
+ HUNK is the beginning of the portion to be printed.
+ The end is marked by a `link' that has been nulled out.
+
+ Prints out lines from both files, and precedes each
+ line with the appropriate flag-character. */
+
+static void
+pr_context_hunk (hunk)
+ struct change *hunk;
+{
+ int first0, last0, first1, last1, show_from, show_to, i;
+ struct change *next;
+ char const *prefix;
+ char const *function;
+ size_t function_length;
+ FILE *out;
+
+ /* Determine range of line numbers involved in each file. */
+
+ analyze_hunk (hunk, &first0, &last0, &first1, &last1, &show_from, &show_to);
+
+ if (!show_from && !show_to)
+ return;
+
+ /* Include a context's width before and after. */
+
+ i = - files[0].prefix_lines;
+ first0 = max (first0 - context, i);
+ first1 = max (first1 - context, i);
+ last0 = min (last0 + context, files[0].valid_lines - 1);
+ last1 = min (last1 + context, files[1].valid_lines - 1);
+
+ /* If desired, find the preceding function definition line in file 0. */
+ function = 0;
+ if (function_regexp_list)
+ find_function (&files[0], first0, &function, &function_length);
+
+ begin_output ();
+ out = outfile;
+
+ /* If we looked for and found a function this is part of,
+ include its name in the header of the diff section. */
+ fprintf (out, "***************");
+
+ if (function)
+ {
+ fprintf (out, " ");
+ fwrite (function, 1, min (function_length - 1, 40), out);
+ }
+
+ fprintf (out, "\n*** ");
+ print_context_number_range (&files[0], first0, last0);
+ fprintf (out, " ****\n");
+
+ if (show_from)
+ {
+ next = hunk;
+
+ for (i = first0; i <= last0; i++)
+ {
+ /* Skip past changes that apply (in file 0)
+ only to lines before line I. */
+
+ while (next && next->line0 + next->deleted <= i)
+ next = next->link;
+
+ /* Compute the marking for line I. */
+
+ prefix = " ";
+ if (next && next->line0 <= i)
+ /* The change NEXT covers this line.
+ If lines were inserted here in file 1, this is "changed".
+ Otherwise it is "deleted". */
+ prefix = (next->inserted > 0 ? "!" : "-");
+
+ print_1_line (prefix, &files[0].linbuf[i]);
+ }
+ }
+
+ fprintf (out, "--- ");
+ print_context_number_range (&files[1], first1, last1);
+ fprintf (out, " ----\n");
+
+ if (show_to)
+ {
+ next = hunk;
+
+ for (i = first1; i <= last1; i++)
+ {
+ /* Skip past changes that apply (in file 1)
+ only to lines before line I. */
+
+ while (next && next->line1 + next->inserted <= i)
+ next = next->link;
+
+ /* Compute the marking for line I. */
+
+ prefix = " ";
+ if (next && next->line1 <= i)
+ /* The change NEXT covers this line.
+ If lines were deleted here in file 0, this is "changed".
+ Otherwise it is "inserted". */
+ prefix = (next->deleted > 0 ? "!" : "+");
+
+ print_1_line (prefix, &files[1].linbuf[i]);
+ }
+ }
+}
+
+/* Print a pair of line numbers with a comma, translated for file FILE.
+ If the second number is smaller, use the first in place of it.
+ If the numbers are equal, print just one number.
+
+ Args A and B are internal line numbers.
+ We print the translated (real) line numbers. */
+
+static void
+print_unidiff_number_range (file, a, b)
+ struct file_data const *file;
+ int a, b;
+{
+ int trans_a, trans_b;
+ translate_range (file, a, b, &trans_a, &trans_b);
+
+ /* Note: we can have B < A in the case of a range of no lines.
+ In this case, we should print the line number before the range,
+ which is B. */
+ if (trans_b <= trans_a)
+ fprintf (outfile, trans_b == trans_a ? "%d" : "%d,0", trans_b);
+ else
+ fprintf (outfile, "%d,%d", trans_a, trans_b - trans_a + 1);
+}
+
+/* Print a portion of an edit script in unidiff format.
+ HUNK is the beginning of the portion to be printed.
+ The end is marked by a `link' that has been nulled out.
+
+ Prints out lines from both files, and precedes each
+ line with the appropriate flag-character. */
+
+static void
+pr_unidiff_hunk (hunk)
+ struct change *hunk;
+{
+ int first0, last0, first1, last1, show_from, show_to, i, j, k;
+ struct change *next;
+ char const *function;
+ size_t function_length;
+ FILE *out;
+
+ /* Determine range of line numbers involved in each file. */
+
+ analyze_hunk (hunk, &first0, &last0, &first1, &last1, &show_from, &show_to);
+
+ if (!show_from && !show_to)
+ return;
+
+ /* Include a context's width before and after. */
+
+ i = - files[0].prefix_lines;
+ first0 = max (first0 - context, i);
+ first1 = max (first1 - context, i);
+ last0 = min (last0 + context, files[0].valid_lines - 1);
+ last1 = min (last1 + context, files[1].valid_lines - 1);
+
+ /* If desired, find the preceding function definition line in file 0. */
+ function = 0;
+ if (function_regexp_list)
+ find_function (&files[0], first0, &function, &function_length);
+
+ begin_output ();
+ out = outfile;
+
+ fprintf (out, "@@ -");
+ print_unidiff_number_range (&files[0], first0, last0);
+ fprintf (out, " +");
+ print_unidiff_number_range (&files[1], first1, last1);
+ fprintf (out, " @@");
+
+ /* If we looked for and found a function this is part of,
+ include its name in the header of the diff section. */
+
+ if (function)
+ {
+ putc (' ', out);
+ fwrite (function, 1, min (function_length - 1, 40), out);
+ }
+ putc ('\n', out);
+
+ next = hunk;
+ i = first0;
+ j = first1;
+
+ while (i <= last0 || j <= last1)
+ {
+
+ /* If the line isn't a difference, output the context from file 0. */
+
+ if (!next || i < next->line0)
+ {
+ putc (tab_align_flag ? '\t' : ' ', out);
+ print_1_line (0, &files[0].linbuf[i++]);
+ j++;
+ }
+ else
+ {
+ /* For each difference, first output the deleted part. */
+
+ k = next->deleted;
+ while (k--)
+ {
+ putc ('-', out);
+ if (tab_align_flag)
+ putc ('\t', out);
+ print_1_line (0, &files[0].linbuf[i++]);
+ }
+
+ /* Then output the inserted part. */
+
+ k = next->inserted;
+ while (k--)
+ {
+ putc ('+', out);
+ if (tab_align_flag)
+ putc ('\t', out);
+ print_1_line (0, &files[1].linbuf[j++]);
+ }
+
+ /* We're done with this hunk, so on to the next! */
+
+ next = next->link;
+ }
+ }
+}
+
+/* Scan a (forward-ordered) edit script for the first place that more than
+ 2*CONTEXT unchanged lines appear, and return a pointer
+ to the `struct change' for the last change before those lines. */
+
+static struct change *
+find_hunk (start)
+ struct change *start;
+{
+ struct change *prev;
+ int top0, top1;
+ int thresh;
+
+ do
+ {
+ /* Compute number of first line in each file beyond this changed. */
+ top0 = start->line0 + start->deleted;
+ top1 = start->line1 + start->inserted;
+ prev = start;
+ start = start->link;
+ /* Threshold distance is 2*CONTEXT between two non-ignorable changes,
+ but only CONTEXT if one is ignorable. */
+ thresh = ((prev->ignore || (start && start->ignore))
+ ? context
+ : 2 * context + 1);
+ /* It is not supposed to matter which file we check in the end-test.
+ If it would matter, crash. */
+ if (start && start->line0 - top0 != start->line1 - top1)
+ abort ();
+ } while (start
+ /* Keep going if less than THRESH lines
+ elapse before the affected line. */
+ && start->line0 < top0 + thresh);
+
+ return prev;
+}
+
+/* Set the `ignore' flag properly in each change in SCRIPT.
+ It should be 1 if all the lines inserted or deleted in that change
+ are ignorable lines. */
+
+static void
+mark_ignorable (script)
+ struct change *script;
+{
+ while (script)
+ {
+ struct change *next = script->link;
+ int first0, last0, first1, last1, deletes, inserts;
+
+ /* Turn this change into a hunk: detach it from the others. */
+ script->link = 0;
+
+ /* Determine whether this change is ignorable. */
+ analyze_hunk (script, &first0, &last0, &first1, &last1, &deletes, &inserts);
+ /* Reconnect the chain as before. */
+ script->link = next;
+
+ /* If the change is ignorable, mark it. */
+ script->ignore = (!deletes && !inserts);
+
+ /* Advance to the following change. */
+ script = next;
+ }
+}
+
+/* Find the last function-header line in FILE prior to line number LINENUM.
+ This is a line containing a match for the regexp in `function_regexp'.
+ Store the address of the line text into LINEP and the length of the
+ line into LENP.
+ Do not store anything if no function-header is found. */
+
+static void
+find_function (file, linenum, linep, lenp)
+ struct file_data const *file;
+ int linenum;
+ char const **linep;
+ size_t *lenp;
+{
+ int i = linenum;
+ int last = find_function_last_search;
+ find_function_last_search = i;
+
+ while (--i >= last)
+ {
+ /* See if this line is what we want. */
+ struct regexp_list *r;
+ char const *line = file->linbuf[i];
+ size_t len = file->linbuf[i + 1] - line;
+
+ for (r = function_regexp_list; r; r = r->next)
+ if (0 <= re_search (&r->buf, line, len, 0, len, 0))
+ {
+ *linep = line;
+ *lenp = len;
+ find_function_last_match = i;
+ return;
+ }
+ }
+ /* If we search back to where we started searching the previous time,
+ find the line we found last time. */
+ if (find_function_last_match >= - file->prefix_lines)
+ {
+ i = find_function_last_match;
+ *linep = file->linbuf[i];
+ *lenp = file->linbuf[i + 1] - *linep;
+ return;
+ }
+ return;
+}
diff --git a/gnu/usr.bin/diff/diff.1 b/gnu/usr.bin/diff/diff.1
new file mode 100644
index 0000000..e16f6d9
--- /dev/null
+++ b/gnu/usr.bin/diff/diff.1
@@ -0,0 +1,473 @@
+.TH DIFF 1 "22sep1993" "GNU Tools" "GNU Tools"
+.SH NAME
+diff \- find differences between two files
+.SH SYNOPSIS
+.B diff
+[options] from-file to-file
+.SH DESCRIPTION
+In the simplest case,
+.I diff
+compares the contents of the two files
+.I from-file
+and
+.IR to-file .
+A file name of
+.B \-
+stands for
+text read from the standard input. As a special case,
+.B "diff \- \-"
+compares a copy of standard input to itself.
+
+If
+.I from-file
+is a directory and
+.I to-file
+is not,
+.I diff
+compares the file in
+.I from-file
+whose file name is that of
+.IR to-file ,
+and vice versa. The non-directory file must not be
+.BR \- .
+
+If both
+.I from-file
+and
+.I to-file
+are directories,
+.I diff
+compares corresponding files in both directories, in
+alphabetical order; this comparison is not recursive unless the
+.B \-r
+or
+.B \-\-recursive
+option is given.
+.I diff
+never
+compares the actual contents of a directory as if it were a file. The
+file that is fully specified may not be standard input, because standard
+input is nameless and the notion of ``file with the same name'' does not
+apply.
+
+.B diff
+options begin with
+.BR \- ,
+so normally
+.I from-file
+and
+.I to-file
+may not begin with
+.BR \- .
+However,
+.B \-\-
+as an
+argument by itself treats the remaining arguments as file names even if
+they begin with
+.BR \- .
+.SS Options
+Below is a summary of all of the options that GNU
+.I diff
+accepts.
+Most options have two equivalent names, one of which is a single letter
+preceded by
+.BR \- ,
+and the other of which is a long name preceded by
+.BR \-\- .
+Multiple single letter options (unless they take an
+argument) can be combined into a single command line word:
+.B \-ac
+is
+equivalent to
+.BR "\-a \-c" .
+Long named options can be abbreviated to
+any unique prefix of their name. Brackets
+.RB ( [
+and
+.BR ] )
+indicate that an
+option takes an optional argument.
+.TP
+.BI \- lines
+Show
+.I lines
+(an integer) lines of context. This option does not
+specify an output format by itself; it has no effect unless it is
+combined with
+.B \-c
+or
+.BR \-u .
+This option is obsolete. For proper
+operation,
+.I patch
+typically needs at least two lines of context.
+.TP
+.B \-a
+Treat all files as text and compare them line-by-line, even if they
+do not seem to be text.
+.TP
+.B \-b
+Ignore changes in amount of white space.
+.TP
+.B \-B
+Ignore changes that just insert or delete blank lines.
+.TP
+.B \-\-brief
+Report only whether the files differ, not the details of the
+differences.
+.TP
+.B \-c
+Use the context output format.
+.TP
+.BI "\-C " lines
+.br
+.ns
+.TP
+.BI \-\-context[= lines ]
+Use the context output format, showing
+.I lines
+(an integer) lines of
+context, or three if
+.I lines
+is not given.
+For proper operation,
+.I patch
+typically needs at least two lines of
+context.
+.TP
+.BI \-\-changed\-group\-format= format
+Use
+.I format
+to output a line group containing differing lines from
+both files in if-then-else format.
+.TP
+.B \-d
+Change the algorithm to perhaps find a smaller set of changes. This makes
+.I diff
+slower (sometimes much slower).
+.TP
+.BI "\-D " name
+Make merged if-then-else format output, conditional on the preprocessor
+macro
+.IR name .
+.TP
+.B \-e
+.br
+.ns
+.TP
+.B \-\-ed
+Make output that is a valid
+.I ed
+script.
+.TP
+.BI \-\-exclude= pattern
+When comparing directories, ignore files and subdirectories whose basenames
+match
+.IR pattern .
+.TP
+.BI \-\-exclude\-from= file
+When comparing directories, ignore files and subdirectories whose basenames
+match any pattern contained in
+.IR file .
+.TP
+.B \-\-expand\-tabs
+Expand tabs to spaces in the output, to preserve the alignment of tabs
+in the input files.
+.TP
+.B \-f
+Make output that looks vaguely like an
+.I ed
+script but has changes
+in the order they appear in the file.
+.TP
+.BI "\-F " regexp
+In context and unified format, for each hunk of differences, show some
+of the last preceding line that matches
+.IR regexp .
+.TP
+.B \-\-forward\-ed
+Make output that looks vaguely like an
+.B ed
+script but has changes
+in the order they appear in the file.
+.TP
+.B \-h
+This option currently has no effect; it is present for Unix
+compatibility.
+.TP
+.B \-H
+Use heuristics to speed handling of large files that have numerous
+scattered small changes.
+.TP
+.BI \-\-horizon\-lines= lines
+Do not discard the last
+.I lines
+lines of the common prefix
+and the first
+.I lines
+lines of the common suffix.
+.TP
+.B \-i
+Ignore changes in case; consider upper- and lower-case letters
+equivalent.
+.TP
+.BI "\-I " regexp
+Ignore changes that just insert or delete lines that match
+.IR regexp .
+.TP
+.BI \-\-ifdef= name
+Make merged if-then-else format output, conditional on the preprocessor
+macro
+.IR name .
+.TP
+.B \-\-ignore\-all\-space
+Ignore white space when comparing lines.
+.TP
+.B \-\-ignore\-blank\-lines
+Ignore changes that just insert or delete blank lines.
+.TP
+.B \-\-ignore\-case
+Ignore changes in case; consider upper- and lower-case to be the same.
+.TP
+.BI \-\-ignore\-matching\-lines= regexp
+Ignore changes that just insert or delete lines that match
+.IR regexp .
+.TP
+.B \-\-ignore\-space\-change
+Ignore changes in amount of white space.
+.TP
+.B \-\-initial\-tab
+Output a tab rather than a space before the text of a line in normal or
+context format. This causes the alignment of tabs in the line to look
+normal.
+.TP
+.B \-l
+Pass the output through
+.I pr
+to paginate it.
+.TP
+.BI "\-L " label
+.br
+.ns
+.TP
+.BI \-\-label= label
+Use
+.I label
+instead of the file name in the context format
+and unified format
+headers.
+.TP
+.B \-\-left\-column
+Print only the left column of two common lines in side by side format.
+.TP
+.BI \-\-line\-format= format
+Use
+.I format
+to output all input lines in in-then-else format.
+.TP
+.B \-\-minimal
+Change the algorithm to perhaps find a smaller set of changes. This
+makes
+.I diff
+slower (sometimes much slower).
+.TP
+.B \-n
+Output RCS-format diffs; like
+.B \-f
+except that each command
+specifies the number of lines affected.
+.TP
+.B \-N
+.br
+.ns
+.TP
+.B \-\-new\-file
+In directory comparison, if a file is found in only one directory,
+treat it as present but empty in the other directory.
+.TP
+.BI \-\-new\-group\-format= format
+Use
+.I format
+to output a group of lines taken from just the second
+file in if-then-else format.
+.TP
+.BI \-\-new\-line\-format= format
+Use
+.I format
+to output a line taken from just the second file in
+if-then-else format.
+.TP
+.BI \-\-old\-group\-format= format
+Use
+.I format
+to output a group of lines taken from just the first
+file in if-then-else format.
+.TP
+.BI \-\-old\-line\-format= format
+Use
+.I format
+to output a line taken from just the first file in
+if-then-else format.
+.TP
+.B \-p
+Show which C function each change is in.
+.TP
+.B \-P
+When comparing directories, if a file appears only in the second
+directory of the two, treat it as present but empty in the other.
+.TP
+.B \-\-paginate
+Pass the output through
+.I pr
+to paginate it.
+.TP
+.B \-q
+Report only whether the files differ, not the details of the
+differences.
+.TP
+.B \-r
+When comparing directories, recursively compare any subdirectories
+found.
+.TP
+.B \-\-rcs
+Output RCS-format diffs; like
+.B \-f
+except that each command
+specifies the number of lines affected.
+.TP
+.B \-\-recursive
+When comparing directories, recursively compare any subdirectories
+found.
+.TP
+.B \-\-report\-identical\-files
+.br
+.ns
+.TP
+.B \-s
+Report when two files are the same.
+.TP
+.BI "\-S " file
+When comparing directories, start with the file
+.IR file .
+This is
+used for resuming an aborted comparison.
+.TP
+.B \-\-sdiff\-merge\-assist
+Print extra information to help
+.IR sdiff .
+.I sdiff
+uses this
+option when it runs
+.IR diff .
+This option is not intended for users
+to use directly.
+.TP
+.B \-\-show\-c\-function
+Show which C function each change is in.
+.TP
+.BI \-\-show\-function\-line= regexp
+In context and unified format, for each hunk of differences, show some
+of the last preceding line that matches
+.IR regexp .
+.TP
+.B \-\-side\-by\-side
+Use the side by side output format.
+.TP
+.B \-\-speed\-large\-files
+Use heuristics to speed handling of large files that have numerous
+scattered small changes.
+.TP
+.BI \-\-starting\-file= file
+When comparing directories, start with the file
+.IR file .
+This is
+used for resuming an aborted comparison.
+.TP
+.B \-\-suppress\-common\-lines
+Do not print common lines in side by side format.
+.TP
+.B \-t
+Expand tabs to spaces in the output, to preserve the alignment of tabs
+in the input files.
+.TP
+.B \-T
+Output a tab rather than a space before the text of a line in normal or
+context format. This causes the alignment of tabs in the line to look
+normal.
+.TP
+.B \-\-text
+Treat all files as text and compare them line-by-line, even if they
+do not appear to be text.
+.TP
+.B \-u
+Use the unified output format.
+.TP
+.BI \-\-unchanged\-group\-format= format
+Use
+.I format
+to output a group of common lines taken from both files
+in if-then-else format.
+.TP
+.BI \-\-unchanged\-line\-format= format
+Use
+.I format
+to output a line common to both files in if-then-else
+format.
+.TP
+.B \-\-unidirectional\-new\-file
+When comparing directories, if a file appears only in the second
+directory of the two, treat it as present but empty in the other.
+.TP
+.BI "\-U " lines
+.br
+.ns
+.TP
+.BI \-\-unified[= lines ]
+Use the unified output format, showing
+.I lines
+(an integer) lines of
+context, or three if
+.I lines
+is not given.
+For proper operation,
+.I patch
+typically needs at least two lines of
+context.
+.TP
+.B \-v
+.br
+.ns
+.TP
+.B \-\-version
+Output the version number of
+.IR diff .
+.TP
+.B \-w
+Ignore white space when comparing lines.
+.TP
+.BI "\-W " columns
+.br
+.ns
+.TP
+.BI \-\-width= columns
+Use an output width of
+.I columns
+in side by side format.
+.TP
+.BI "\-x " pattern
+When comparing directories, ignore files and subdirectories whose basenames
+match
+.IR pattern .
+.TP
+.BI "\-X " file
+When comparing directories, ignore files and subdirectories whose basenames
+match any pattern contained in
+.IR file .
+.TP
+.B \-y
+Use the side by side output format.
+.SH SEE ALSO
+cmp(1), comm(1), diff3(1), ed(1), patch(1), pr(1), sdiff(1).
+.SH DIAGNOSTICS
+An exit status of 0 means no differences were found, 1 means some
+differences were found, and 2 means trouble.
diff --git a/gnu/usr.bin/diff/diff.c b/gnu/usr.bin/diff/diff.c
new file mode 100644
index 0000000..c818208
--- /dev/null
+++ b/gnu/usr.bin/diff/diff.c
@@ -0,0 +1,1112 @@
+/* GNU DIFF main routine.
+ Copyright (C) 1988, 1989, 1992, 1993, 1994 Free Software Foundation, Inc.
+
+This file is part of GNU DIFF.
+
+GNU DIFF is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU DIFF is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU DIFF; see the file COPYING. If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* GNU DIFF was written by Mike Haertel, David Hayes,
+ Richard Stallman, Len Tower, and Paul Eggert. */
+
+#define GDIFF_MAIN
+#include "diff.h"
+#ifdef __FreeBSD__
+#include <locale.h>
+#endif
+#include <signal.h>
+#include "getopt.h"
+#include "fnmatch.h"
+
+#ifndef DEFAULT_WIDTH
+#define DEFAULT_WIDTH 130
+#endif
+
+#ifndef GUTTER_WIDTH_MINIMUM
+#define GUTTER_WIDTH_MINIMUM 3
+#endif
+
+static char const *filetype PARAMS((struct stat const *));
+static char *option_list PARAMS((char **, int));
+static int add_exclude_file PARAMS((char const *));
+static int ck_atoi PARAMS((char const *, int *));
+static int compare_files PARAMS((char const *, char const *, char const *, char const *, int));
+static int specify_format PARAMS((char **, char *));
+static void add_exclude PARAMS((char const *));
+static void add_regexp PARAMS((struct regexp_list **, char const *));
+static void specify_style PARAMS((enum output_style));
+static void try_help PARAMS((char const *));
+static void check_stdout PARAMS((void));
+static void usage PARAMS((void));
+
+/* Nonzero for -r: if comparing two directories,
+ compare their common subdirectories recursively. */
+
+static int recursive;
+
+/* For debugging: don't do discard_confusing_lines. */
+
+int no_discards;
+
+#if HAVE_SETMODE
+/* I/O mode: nonzero only if using binary input/output. */
+static int binary_I_O;
+#endif
+
+/* Return a string containing the command options with which diff was invoked.
+ Spaces appear between what were separate ARGV-elements.
+ There is a space at the beginning but none at the end.
+ If there were no options, the result is an empty string.
+
+ Arguments: OPTIONVEC, a vector containing separate ARGV-elements, and COUNT,
+ the length of that vector. */
+
+static char *
+option_list (optionvec, count)
+ char **optionvec; /* Was `vector', but that collides on Alliant. */
+ int count;
+{
+ int i;
+ size_t length = 0;
+ char *result;
+
+ for (i = 0; i < count; i++)
+ length += strlen (optionvec[i]) + 1;
+
+ result = xmalloc (length + 1);
+ result[0] = 0;
+
+ for (i = 0; i < count; i++)
+ {
+ strcat (result, " ");
+ strcat (result, optionvec[i]);
+ }
+
+ return result;
+}
+
+/* Convert STR to a positive integer, storing the result in *OUT.
+ If STR is not a valid integer, return -1 (otherwise 0). */
+static int
+ck_atoi (str, out)
+ char const *str;
+ int *out;
+{
+ char const *p;
+ for (p = str; *p; p++)
+ if (*p < '0' || *p > '9')
+ return -1;
+
+ *out = atoi (optarg);
+ return 0;
+}
+
+/* Keep track of excluded file name patterns. */
+
+static char const **exclude;
+static int exclude_alloc, exclude_count;
+
+int
+excluded_filename (f)
+ char const *f;
+{
+ int i;
+ for (i = 0; i < exclude_count; i++)
+ if (fnmatch (exclude[i], f, 0) == 0)
+ return 1;
+ return 0;
+}
+
+static void
+add_exclude (pattern)
+ char const *pattern;
+{
+ if (exclude_alloc <= exclude_count)
+ exclude = (char const **)
+ (exclude_alloc == 0
+ ? xmalloc ((exclude_alloc = 64) * sizeof (*exclude))
+ : xrealloc (exclude, (exclude_alloc *= 2) * sizeof (*exclude)));
+
+ exclude[exclude_count++] = pattern;
+}
+
+static int
+add_exclude_file (name)
+ char const *name;
+{
+ struct file_data f;
+ char *p, *q, *lim;
+
+ f.name = optarg;
+ f.desc = (strcmp (optarg, "-") == 0
+ ? STDIN_FILENO
+ : open (optarg, O_RDONLY, 0));
+ if (f.desc < 0 || fstat (f.desc, &f.stat) != 0)
+ return -1;
+
+ sip (&f, 1);
+ slurp (&f);
+
+ for (p = f.buffer, lim = p + f.buffered_chars; p < lim; p = q)
+ {
+ q = (char *) memchr (p, '\n', lim - p);
+ if (!q)
+ q = lim;
+ *q++ = 0;
+ add_exclude (p);
+ }
+
+ return close (f.desc);
+}
+
+/* The numbers 129- that appear in the fourth element of some entries
+ tell the big switch in `main' how to process those options. */
+
+static struct option const longopts[] =
+{
+ {"ignore-blank-lines", 0, 0, 'B'},
+ {"context", 2, 0, 'C'},
+ {"ifdef", 1, 0, 'D'},
+ {"show-function-line", 1, 0, 'F'},
+ {"speed-large-files", 0, 0, 'H'},
+ {"ignore-matching-lines", 1, 0, 'I'},
+ {"label", 1, 0, 'L'},
+ {"file-label", 1, 0, 'L'}, /* An alias, no longer recommended */
+ {"new-file", 0, 0, 'N'},
+ {"entire-new-file", 0, 0, 'N'}, /* An alias, no longer recommended */
+ {"unidirectional-new-file", 0, 0, 'P'},
+ {"starting-file", 1, 0, 'S'},
+ {"initial-tab", 0, 0, 'T'},
+ {"width", 1, 0, 'W'},
+ {"text", 0, 0, 'a'},
+ {"ascii", 0, 0, 'a'}, /* An alias, no longer recommended */
+ {"ignore-space-change", 0, 0, 'b'},
+ {"minimal", 0, 0, 'd'},
+ {"ed", 0, 0, 'e'},
+ {"forward-ed", 0, 0, 'f'},
+ {"ignore-case", 0, 0, 'i'},
+ {"paginate", 0, 0, 'l'},
+ {"print", 0, 0, 'l'}, /* An alias, no longer recommended */
+ {"rcs", 0, 0, 'n'},
+ {"show-c-function", 0, 0, 'p'},
+ {"brief", 0, 0, 'q'},
+ {"recursive", 0, 0, 'r'},
+ {"report-identical-files", 0, 0, 's'},
+ {"expand-tabs", 0, 0, 't'},
+ {"version", 0, 0, 'v'},
+ {"ignore-all-space", 0, 0, 'w'},
+ {"exclude", 1, 0, 'x'},
+ {"exclude-from", 1, 0, 'X'},
+ {"side-by-side", 0, 0, 'y'},
+ {"unified", 2, 0, 'U'},
+ {"left-column", 0, 0, 129},
+ {"suppress-common-lines", 0, 0, 130},
+ {"sdiff-merge-assist", 0, 0, 131},
+ {"old-line-format", 1, 0, 132},
+ {"new-line-format", 1, 0, 133},
+ {"unchanged-line-format", 1, 0, 134},
+ {"line-format", 1, 0, 135},
+ {"old-group-format", 1, 0, 136},
+ {"new-group-format", 1, 0, 137},
+ {"unchanged-group-format", 1, 0, 138},
+ {"changed-group-format", 1, 0, 139},
+ {"horizon-lines", 1, 0, 140},
+ {"help", 0, 0, 141},
+ {"binary", 0, 0, 142},
+ {0, 0, 0, 0}
+};
+
+int
+main (argc, argv)
+ int argc;
+ char *argv[];
+{
+ int val;
+ int c;
+ int prev = -1;
+ int width = DEFAULT_WIDTH;
+ int show_c_function = 0;
+
+#ifdef __FreeBSD__
+ (void) setlocale(LC_CTYPE, "");
+#endif
+ /* Do our initializations. */
+ initialize_main (&argc, &argv);
+ program_name = argv[0];
+ output_style = OUTPUT_NORMAL;
+ context = -1;
+
+ /* Decode the options. */
+
+ while ((c = getopt_long (argc, argv,
+ "0123456789abBcC:dD:efF:hHiI:lL:nNpPqrsS:tTuU:vwW:x:X:y",
+ longopts, 0)) != EOF)
+ {
+ switch (c)
+ {
+ /* All digits combine in decimal to specify the context-size. */
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ case '0':
+ if (context == -1)
+ context = 0;
+ /* If a context length has already been specified,
+ more digits allowed only if they follow right after the others.
+ Reject two separate runs of digits, or digits after -C. */
+ else if (prev < '0' || prev > '9')
+ fatal ("context length specified twice");
+
+ context = context * 10 + c - '0';
+ break;
+
+ case 'a':
+ /* Treat all files as text files; never treat as binary. */
+ always_text_flag = 1;
+ break;
+
+ case 'b':
+ /* Ignore changes in amount of white space. */
+ ignore_space_change_flag = 1;
+ ignore_some_changes = 1;
+ ignore_some_line_changes = 1;
+ break;
+
+ case 'B':
+ /* Ignore changes affecting only blank lines. */
+ ignore_blank_lines_flag = 1;
+ ignore_some_changes = 1;
+ break;
+
+ case 'C': /* +context[=lines] */
+ case 'U': /* +unified[=lines] */
+ if (optarg)
+ {
+ if (context >= 0)
+ fatal ("context length specified twice");
+
+ if (ck_atoi (optarg, &context))
+ fatal ("invalid context length argument");
+ }
+
+ /* Falls through. */
+ case 'c':
+ /* Make context-style output. */
+ specify_style (c == 'U' ? OUTPUT_UNIFIED : OUTPUT_CONTEXT);
+ break;
+
+ case 'd':
+ /* Don't discard lines. This makes things slower (sometimes much
+ slower) but will find a guaranteed minimal set of changes. */
+ no_discards = 1;
+ break;
+
+ case 'D':
+ /* Make merged #ifdef output. */
+ specify_style (OUTPUT_IFDEF);
+ {
+ int i, err = 0;
+ static char const C_ifdef_group_formats[] =
+ "#ifndef %s\n%%<#endif /* not %s */\n%c#ifdef %s\n%%>#endif /* %s */\n%c%%=%c#ifndef %s\n%%<#else /* %s */\n%%>#endif /* %s */\n";
+ char *b = xmalloc (sizeof (C_ifdef_group_formats)
+ + 7 * strlen(optarg) - 14 /* 7*"%s" */
+ - 8 /* 5*"%%" + 3*"%c" */);
+ sprintf (b, C_ifdef_group_formats,
+ optarg, optarg, 0,
+ optarg, optarg, 0, 0,
+ optarg, optarg, optarg);
+ for (i = 0; i < 4; i++)
+ {
+ err |= specify_format (&group_format[i], b);
+ b += strlen (b) + 1;
+ }
+ if (err)
+ error ("conflicting #ifdef formats", 0, 0);
+ }
+ break;
+
+ case 'e':
+ /* Make output that is a valid `ed' script. */
+ specify_style (OUTPUT_ED);
+ break;
+
+ case 'f':
+ /* Make output that looks vaguely like an `ed' script
+ but has changes in the order they appear in the file. */
+ specify_style (OUTPUT_FORWARD_ED);
+ break;
+
+ case 'F':
+ /* Show, for each set of changes, the previous line that
+ matches the specified regexp. Currently affects only
+ context-style output. */
+ add_regexp (&function_regexp_list, optarg);
+ break;
+
+ case 'h':
+ /* Split the files into chunks of around 1500 lines
+ for faster processing. Usually does not change the result.
+
+ This currently has no effect. */
+ break;
+
+ case 'H':
+ /* Turn on heuristics that speed processing of large files
+ with a small density of changes. */
+ heuristic = 1;
+ break;
+
+ case 'i':
+ /* Ignore changes in case. */
+ ignore_case_flag = 1;
+ ignore_some_changes = 1;
+ ignore_some_line_changes = 1;
+ break;
+
+ case 'I':
+ /* Ignore changes affecting only lines that match the
+ specified regexp. */
+ add_regexp (&ignore_regexp_list, optarg);
+ ignore_some_changes = 1;
+ break;
+
+ case 'l':
+ /* Pass the output through `pr' to paginate it. */
+ paginate_flag = 1;
+#if !defined(SIGCHLD) && defined(SIGCLD)
+#define SIGCHLD SIGCLD
+#endif
+#ifdef SIGCHLD
+ /* Pagination requires forking and waiting, and
+ System V fork+wait does not work if SIGCHLD is ignored. */
+ signal (SIGCHLD, SIG_DFL);
+#endif
+ break;
+
+ case 'L':
+ /* Specify file labels for `-c' output headers. */
+ if (!file_label[0])
+ file_label[0] = optarg;
+ else if (!file_label[1])
+ file_label[1] = optarg;
+ else
+ fatal ("too many file label options");
+ break;
+
+ case 'n':
+ /* Output RCS-style diffs, like `-f' except that each command
+ specifies the number of lines affected. */
+ specify_style (OUTPUT_RCS);
+ break;
+
+ case 'N':
+ /* When comparing directories, if a file appears only in one
+ directory, treat it as present but empty in the other. */
+ entire_new_file_flag = 1;
+ break;
+
+ case 'p':
+ /* Make context-style output and show name of last C function. */
+ show_c_function = 1;
+ add_regexp (&function_regexp_list, "^[_a-zA-Z$]");
+ break;
+
+ case 'P':
+ /* When comparing directories, if a file appears only in
+ the second directory of the two,
+ treat it as present but empty in the other. */
+ unidirectional_new_file_flag = 1;
+ break;
+
+ case 'q':
+ no_details_flag = 1;
+ break;
+
+ case 'r':
+ /* When comparing directories,
+ recursively compare any subdirectories found. */
+ recursive = 1;
+ break;
+
+ case 's':
+ /* Print a message if the files are the same. */
+ print_file_same_flag = 1;
+ break;
+
+ case 'S':
+ /* When comparing directories, start with the specified
+ file name. This is used for resuming an aborted comparison. */
+ dir_start_file = optarg;
+ break;
+
+ case 't':
+ /* Expand tabs to spaces in the output so that it preserves
+ the alignment of the input files. */
+ tab_expand_flag = 1;
+ break;
+
+ case 'T':
+ /* Use a tab in the output, rather than a space, before the
+ text of an input line, so as to keep the proper alignment
+ in the input line without changing the characters in it. */
+ tab_align_flag = 1;
+ break;
+
+ case 'u':
+ /* Output the context diff in unidiff format. */
+ specify_style (OUTPUT_UNIFIED);
+ break;
+
+ case 'v':
+ printf ("diff - GNU diffutils version %s\n", version_string);
+ exit (0);
+
+ case 'w':
+ /* Ignore horizontal white space when comparing lines. */
+ ignore_all_space_flag = 1;
+ ignore_some_changes = 1;
+ ignore_some_line_changes = 1;
+ break;
+
+ case 'x':
+ add_exclude (optarg);
+ break;
+
+ case 'X':
+ if (add_exclude_file (optarg) != 0)
+ pfatal_with_name (optarg);
+ break;
+
+ case 'y':
+ /* Use side-by-side (sdiff-style) columnar output. */
+ specify_style (OUTPUT_SDIFF);
+ break;
+
+ case 'W':
+ /* Set the line width for OUTPUT_SDIFF. */
+ if (ck_atoi (optarg, &width) || width <= 0)
+ fatal ("column width must be a positive integer");
+ break;
+
+ case 129:
+ sdiff_left_only = 1;
+ break;
+
+ case 130:
+ sdiff_skip_common_lines = 1;
+ break;
+
+ case 131:
+ /* sdiff-style columns output. */
+ specify_style (OUTPUT_SDIFF);
+ sdiff_help_sdiff = 1;
+ break;
+
+ case 132:
+ case 133:
+ case 134:
+ specify_style (OUTPUT_IFDEF);
+ if (specify_format (&line_format[c - 132], optarg) != 0)
+ error ("conflicting line format", 0, 0);
+ break;
+
+ case 135:
+ specify_style (OUTPUT_IFDEF);
+ {
+ int i, err = 0;
+ for (i = 0; i < sizeof (line_format) / sizeof (*line_format); i++)
+ err |= specify_format (&line_format[i], optarg);
+ if (err)
+ error ("conflicting line format", 0, 0);
+ }
+ break;
+
+ case 136:
+ case 137:
+ case 138:
+ case 139:
+ specify_style (OUTPUT_IFDEF);
+ if (specify_format (&group_format[c - 136], optarg) != 0)
+ error ("conflicting group format", 0, 0);
+ break;
+
+ case 140:
+ if (ck_atoi (optarg, &horizon_lines) || horizon_lines < 0)
+ fatal ("horizon must be a nonnegative integer");
+ break;
+
+ case 141:
+ usage ();
+ check_stdout ();
+ exit (0);
+
+ case 142:
+ /* Use binary I/O when reading and writing data.
+ On Posix hosts, this has no effect. */
+#if HAVE_SETMODE
+ binary_I_O = 1;
+ setmode (STDOUT_FILENO, O_BINARY);
+#endif
+ break;
+
+ default:
+ try_help (0);
+ }
+ prev = c;
+ }
+
+ if (argc - optind != 2)
+ try_help (argc - optind < 2 ? "missing operand" : "extra operand");
+
+
+ {
+ /*
+ * We maximize first the half line width, and then the gutter width,
+ * according to the following constraints:
+ * 1. Two half lines plus a gutter must fit in a line.
+ * 2. If the half line width is nonzero:
+ * a. The gutter width is at least GUTTER_WIDTH_MINIMUM.
+ * b. If tabs are not expanded to spaces,
+ * a half line plus a gutter is an integral number of tabs,
+ * so that tabs in the right column line up.
+ */
+ int t = tab_expand_flag ? 1 : TAB_WIDTH;
+ int off = (width + t + GUTTER_WIDTH_MINIMUM) / (2*t) * t;
+ sdiff_half_width = max (0, min (off - GUTTER_WIDTH_MINIMUM, width - off)),
+ sdiff_column2_offset = sdiff_half_width ? off : width;
+ }
+
+ if (show_c_function && output_style != OUTPUT_UNIFIED)
+ specify_style (OUTPUT_CONTEXT);
+
+ if (output_style != OUTPUT_CONTEXT && output_style != OUTPUT_UNIFIED)
+ context = 0;
+ else if (context == -1)
+ /* Default amount of context for -c. */
+ context = 3;
+
+ if (output_style == OUTPUT_IFDEF)
+ {
+ /* Format arrays are char *, not char const *,
+ because integer formats are temporarily modified.
+ But it is safe to assign a constant like "%=" to a format array,
+ since "%=" does not format any integers. */
+ int i;
+ for (i = 0; i < sizeof (line_format) / sizeof (*line_format); i++)
+ if (!line_format[i])
+ line_format[i] = "%l\n";
+ if (!group_format[OLD])
+ group_format[OLD]
+ = group_format[UNCHANGED] ? group_format[UNCHANGED] : "%<";
+ if (!group_format[NEW])
+ group_format[NEW]
+ = group_format[UNCHANGED] ? group_format[UNCHANGED] : "%>";
+ if (!group_format[UNCHANGED])
+ group_format[UNCHANGED] = "%=";
+ if (!group_format[CHANGED])
+ group_format[CHANGED] = concat (group_format[OLD],
+ group_format[NEW], "");
+ }
+
+ no_diff_means_no_output =
+ (output_style == OUTPUT_IFDEF ?
+ (!*group_format[UNCHANGED]
+ || (strcmp (group_format[UNCHANGED], "%=") == 0
+ && !*line_format[UNCHANGED]))
+ : output_style == OUTPUT_SDIFF ? sdiff_skip_common_lines : 1);
+
+ switch_string = option_list (argv + 1, optind - 1);
+
+ val = compare_files (0, argv[optind], 0, argv[optind + 1], 0);
+
+ /* Print any messages that were saved up for last. */
+ print_message_queue ();
+
+ check_stdout ();
+ exit (val);
+ return val;
+}
+
+/* Add the compiled form of regexp PATTERN to REGLIST. */
+
+static void
+add_regexp (reglist, pattern)
+ struct regexp_list **reglist;
+ char const *pattern;
+{
+ struct regexp_list *r;
+ char const *m;
+
+ r = (struct regexp_list *) xmalloc (sizeof (*r));
+ bzero (r, sizeof (*r));
+ r->buf.fastmap = xmalloc (256);
+ m = re_compile_pattern (pattern, strlen (pattern), &r->buf);
+ if (m != 0)
+ error ("%s: %s", pattern, m);
+
+ /* Add to the start of the list, since it's easier than the end. */
+ r->next = *reglist;
+ *reglist = r;
+}
+
+static void
+try_help (reason)
+ char const *reason;
+{
+ if (reason)
+ error ("%s", reason, 0);
+ error ("Try `%s --help' for more information.", program_name, 0);
+ exit (2);
+}
+
+static void
+check_stdout ()
+{
+ if (ferror (stdout) || fclose (stdout) != 0)
+ fatal ("write error");
+}
+
+static char const * const option_help[] = {
+"-i --ignore-case Consider upper- and lower-case to be the same.",
+"-w --ignore-all-space Ignore all white space.",
+"-b --ignore-space-change Ignore changes in the amount of white space.",
+"-B --ignore-blank-lines Ignore changes whose lines are all blank.",
+"-I RE --ignore-matching-lines=RE Ignore changes whose lines all match RE.",
+#if HAVE_SETMODE
+"--binary Read and write data in binary mode.",
+#endif
+"-a --text Treat all files as text.\n",
+"-c -C NUM --context[=NUM] Output NUM (default 2) lines of copied context.",
+"-u -U NUM --unified[=NUM] Output NUM (default 2) lines of unified context.",
+" -NUM Use NUM context lines.",
+" -L LABEL --label LABEL Use LABEL instead of file name.",
+" -p --show-c-function Show which C function each change is in.",
+" -F RE --show-function-line=RE Show the most recent line matching RE.",
+"-q --brief Output only whether files differ.",
+"-e --ed Output an ed script.",
+"-n --rcs Output an RCS format diff.",
+"-y --side-by-side Output in two columns.",
+" -w NUM --width=NUM Output at most NUM (default 130) characters per line.",
+" --left-column Output only the left column of common lines.",
+" --suppress-common-lines Do not output common lines.",
+"-DNAME --ifdef=NAME Output merged file to show `#ifdef NAME' diffs.",
+"--GTYPE-group-format=GFMT Similar, but format GTYPE input groups with GFMT.",
+"--line-format=LFMT Similar, but format all input lines with LFMT.",
+"--LTYPE-line-format=LFMT Similar, but format LTYPE input lines with LFMT.",
+" LTYPE is `old', `new', or `unchanged'. GTYPE is LTYPE or `changed'.",
+" GFMT may contain:",
+" %< lines from FILE1",
+" %> lines from FILE2",
+" %= lines common to FILE1 and FILE2",
+" %[-][WIDTH][.[PREC]]{doxX}LETTER printf-style spec for LETTER",
+" LETTERs are as follows for new group, lower case for old group:",
+" F first line number",
+" L last line number",
+" N number of lines = L-F+1",
+" E F-1",
+" M L+1",
+" LFMT may contain:",
+" %L contents of line",
+" %l contents of line, excluding any trailing newline",
+" %[-][WIDTH][.[PREC]]{doxX}n printf-style spec for input line number",
+" Either GFMT or LFMT may contain:",
+" %% %",
+" %c'C' the single character C",
+" %c'\\OOO' the character with octal code OOO\n",
+"-l --paginate Pass the output through `pr' to paginate it.",
+"-t --expand-tabs Expand tabs to spaces in output.",
+"-T --initial-tab Make tabs line up by prepending a tab.\n",
+"-r --recursive Recursively compare any subdirectories found.",
+"-N --new-file Treat absent files as empty.",
+"-P --unidirectional-new-file Treat absent first files as empty.",
+"-s --report-identical-files Report when two files are the same.",
+"-x PAT --exclude=PAT Exclude files that match PAT.",
+"-X FILE --exclude-from=FILE Exclude files that match any pattern in FILE.",
+"-S FILE --starting-file=FILE Start with FILE when comparing directories.\n",
+"--horizon-lines=NUM Keep NUM lines of the common prefix and suffix.",
+"-d --minimal Try hard to find a smaller set of changes.",
+"-H --speed-large-files Assume large files and many scattered small changes.\n",
+"-v --version Output version info.",
+"--help Output this help.",
+0
+};
+
+static void
+usage ()
+{
+ char const * const *p;
+
+ printf ("Usage: %s [OPTION]... FILE1 FILE2\n\n", program_name);
+ for (p = option_help; *p; p++)
+ printf (" %s\n", *p);
+ printf ("\nIf FILE1 or FILE2 is `-', read standard input.\n");
+}
+
+static int
+specify_format (var, value)
+ char **var;
+ char *value;
+{
+ int err = *var ? strcmp (*var, value) : 0;
+ *var = value;
+ return err;
+}
+
+static void
+specify_style (style)
+ enum output_style style;
+{
+ if (output_style != OUTPUT_NORMAL
+ && output_style != style)
+ error ("conflicting specifications of output style", 0, 0);
+ output_style = style;
+}
+
+static char const *
+filetype (st)
+ struct stat const *st;
+{
+ /* See Posix.2 section 4.17.6.1.1 and Table 5-1 for these formats.
+ To keep diagnostics grammatical, the returned string must start
+ with a consonant. */
+
+ if (S_ISREG (st->st_mode))
+ {
+ if (st->st_size == 0)
+ return "regular empty file";
+ /* Posix.2 section 5.14.2 seems to suggest that we must read the file
+ and guess whether it's C, Fortran, etc., but this is somewhat useless
+ and doesn't reflect historical practice. We're allowed to guess
+ wrong, so we don't bother to read the file. */
+ return "regular file";
+ }
+ if (S_ISDIR (st->st_mode)) return "directory";
+
+ /* other Posix.1 file types */
+#ifdef S_ISBLK
+ if (S_ISBLK (st->st_mode)) return "block special file";
+#endif
+#ifdef S_ISCHR
+ if (S_ISCHR (st->st_mode)) return "character special file";
+#endif
+#ifdef S_ISFIFO
+ if (S_ISFIFO (st->st_mode)) return "fifo";
+#endif
+
+ /* other Posix.1b file types */
+#ifdef S_TYPEISMQ
+ if (S_TYPEISMQ (st)) return "message queue";
+#endif
+#ifdef S_TYPEISSEM
+ if (S_TYPEISSEM (st)) return "semaphore";
+#endif
+#ifdef S_TYPEISSHM
+ if (S_TYPEISSHM (st)) return "shared memory object";
+#endif
+
+ /* other popular file types */
+ /* S_ISLNK is impossible with `fstat' and `stat'. */
+#ifdef S_ISSOCK
+ if (S_ISSOCK (st->st_mode)) return "socket";
+#endif
+
+ return "weird file";
+}
+
+/* Compare two files (or dirs) with specified names
+ DIR0/NAME0 and DIR1/NAME1, at level DEPTH in directory recursion.
+ (if DIR0 is 0, then the name is just NAME0, etc.)
+ This is self-contained; it opens the files and closes them.
+
+ Value is 0 if files are the same, 1 if different,
+ 2 if there is a problem opening them. */
+
+static int
+compare_files (dir0, name0, dir1, name1, depth)
+ char const *dir0, *dir1;
+ char const *name0, *name1;
+ int depth;
+{
+ struct file_data inf[2];
+ register int i;
+ int val;
+ int same_files;
+ int failed = 0;
+ char *free0 = 0, *free1 = 0;
+
+ /* If this is directory comparison, perhaps we have a file
+ that exists only in one of the directories.
+ If so, just print a message to that effect. */
+
+ if (! ((name0 != 0 && name1 != 0)
+ || (unidirectional_new_file_flag && name1 != 0)
+ || entire_new_file_flag))
+ {
+ char const *name = name0 == 0 ? name1 : name0;
+ char const *dir = name0 == 0 ? dir1 : dir0;
+ message ("Only in %s: %s\n", dir, name);
+ /* Return 1 so that diff_dirs will return 1 ("some files differ"). */
+ return 1;
+ }
+
+ bzero (inf, sizeof (inf));
+
+ /* Mark any nonexistent file with -1 in the desc field. */
+ /* Mark unopened files (e.g. directories) with -2. */
+
+ inf[0].desc = name0 == 0 ? -1 : -2;
+ inf[1].desc = name1 == 0 ? -1 : -2;
+
+ /* Now record the full name of each file, including nonexistent ones. */
+
+ if (name0 == 0)
+ name0 = name1;
+ if (name1 == 0)
+ name1 = name0;
+
+ inf[0].name = dir0 == 0 ? name0 : (free0 = dir_file_pathname (dir0, name0));
+ inf[1].name = dir1 == 0 ? name1 : (free1 = dir_file_pathname (dir1, name1));
+
+ /* Stat the files. Record whether they are directories. */
+
+ for (i = 0; i <= 1; i++)
+ {
+ if (inf[i].desc != -1)
+ {
+ int stat_result;
+
+ if (i && filename_cmp (inf[i].name, inf[0].name) == 0)
+ {
+ inf[i].stat = inf[0].stat;
+ stat_result = 0;
+ }
+ else if (strcmp (inf[i].name, "-") == 0)
+ {
+ inf[i].desc = STDIN_FILENO;
+ stat_result = fstat (STDIN_FILENO, &inf[i].stat);
+ if (stat_result == 0 && S_ISREG (inf[i].stat.st_mode))
+ {
+ off_t pos = lseek (STDIN_FILENO, (off_t) 0, SEEK_CUR);
+ if (pos == -1)
+ stat_result = -1;
+ else
+ {
+ if (pos <= inf[i].stat.st_size)
+ inf[i].stat.st_size -= pos;
+ else
+ inf[i].stat.st_size = 0;
+ /* Posix.2 4.17.6.1.4 requires current time for stdin. */
+ time (&inf[i].stat.st_mtime);
+ }
+ }
+ }
+ else
+ stat_result = stat (inf[i].name, &inf[i].stat);
+
+ if (stat_result != 0)
+ {
+ perror_with_name (inf[i].name);
+ failed = 1;
+ }
+ else
+ {
+ inf[i].dir_p = S_ISDIR (inf[i].stat.st_mode) && inf[i].desc != 0;
+ if (inf[1 - i].desc == -1)
+ {
+ inf[1 - i].dir_p = inf[i].dir_p;
+ inf[1 - i].stat.st_mode = inf[i].stat.st_mode;
+ }
+ }
+ }
+ }
+
+ if (! failed && depth == 0 && inf[0].dir_p != inf[1].dir_p)
+ {
+ /* If one is a directory, and it was specified in the command line,
+ use the file in that dir with the other file's basename. */
+
+ int fnm_arg = inf[0].dir_p;
+ int dir_arg = 1 - fnm_arg;
+ char const *fnm = inf[fnm_arg].name;
+ char const *dir = inf[dir_arg].name;
+ char const *p = filename_lastdirchar (fnm);
+ char const *filename = inf[dir_arg].name
+ = dir_file_pathname (dir, p ? p + 1 : fnm);
+
+ if (strcmp (fnm, "-") == 0)
+ fatal ("can't compare - to a directory");
+
+ if (stat (filename, &inf[dir_arg].stat) != 0)
+ {
+ perror_with_name (filename);
+ failed = 1;
+ }
+ else
+ inf[dir_arg].dir_p = S_ISDIR (inf[dir_arg].stat.st_mode);
+ }
+
+ if (failed)
+ {
+
+ /* If either file should exist but does not, return 2. */
+
+ val = 2;
+
+ }
+ else if ((same_files = inf[0].desc != -1 && inf[1].desc != -1
+ && 0 < same_file (&inf[0].stat, &inf[1].stat))
+ && no_diff_means_no_output)
+ {
+ /* The two named files are actually the same physical file.
+ We know they are identical without actually reading them. */
+
+ val = 0;
+ }
+ else if (inf[0].dir_p & inf[1].dir_p)
+ {
+ if (output_style == OUTPUT_IFDEF)
+ fatal ("-D option not supported with directories");
+
+ /* If both are directories, compare the files in them. */
+
+ if (depth > 0 && !recursive)
+ {
+ /* But don't compare dir contents one level down
+ unless -r was specified. */
+ message ("Common subdirectories: %s and %s\n",
+ inf[0].name, inf[1].name);
+ val = 0;
+ }
+ else
+ {
+ val = diff_dirs (inf, compare_files, depth);
+ }
+
+ }
+ else if ((inf[0].dir_p | inf[1].dir_p)
+ || (depth > 0
+ && (! S_ISREG (inf[0].stat.st_mode)
+ || ! S_ISREG (inf[1].stat.st_mode))))
+ {
+ /* Perhaps we have a subdirectory that exists only in one directory.
+ If so, just print a message to that effect. */
+
+ if (inf[0].desc == -1 || inf[1].desc == -1)
+ {
+ if ((inf[0].dir_p | inf[1].dir_p)
+ && recursive
+ && (entire_new_file_flag
+ || (unidirectional_new_file_flag && inf[0].desc == -1)))
+ val = diff_dirs (inf, compare_files, depth);
+ else
+ {
+ char const *dir = (inf[0].desc == -1) ? dir1 : dir0;
+ /* See Posix.2 section 4.17.6.1.1 for this format. */
+ message ("Only in %s: %s\n", dir, name0);
+ val = 1;
+ }
+ }
+ else
+ {
+ /* We have two files that are not to be compared. */
+
+ /* See Posix.2 section 4.17.6.1.1 for this format. */
+ message5 ("File %s is a %s while file %s is a %s\n",
+ inf[0].name, filetype (&inf[0].stat),
+ inf[1].name, filetype (&inf[1].stat));
+
+ /* This is a difference. */
+ val = 1;
+ }
+ }
+ else if ((no_details_flag & ~ignore_some_changes)
+ && inf[0].stat.st_size != inf[1].stat.st_size
+ && (inf[0].desc == -1 || S_ISREG (inf[0].stat.st_mode))
+ && (inf[1].desc == -1 || S_ISREG (inf[1].stat.st_mode)))
+ {
+ message ("Files %s and %s differ\n", inf[0].name, inf[1].name);
+ val = 1;
+ }
+ else
+ {
+ /* Both exist and neither is a directory. */
+
+ /* Open the files and record their descriptors. */
+
+ if (inf[0].desc == -2)
+ if ((inf[0].desc = open (inf[0].name, O_RDONLY, 0)) < 0)
+ {
+ perror_with_name (inf[0].name);
+ failed = 1;
+ }
+ if (inf[1].desc == -2)
+ if (same_files)
+ inf[1].desc = inf[0].desc;
+ else if ((inf[1].desc = open (inf[1].name, O_RDONLY, 0)) < 0)
+ {
+ perror_with_name (inf[1].name);
+ failed = 1;
+ }
+
+#if HAVE_SETMODE
+ if (binary_I_O)
+ for (i = 0; i <= 1; i++)
+ if (0 <= inf[i].desc)
+ setmode (inf[i].desc, O_BINARY);
+#endif
+
+ /* Compare the files, if no error was found. */
+
+ val = failed ? 2 : diff_2_files (inf, depth);
+
+ /* Close the file descriptors. */
+
+ if (inf[0].desc >= 0 && close (inf[0].desc) != 0)
+ {
+ perror_with_name (inf[0].name);
+ val = 2;
+ }
+ if (inf[1].desc >= 0 && inf[0].desc != inf[1].desc
+ && close (inf[1].desc) != 0)
+ {
+ perror_with_name (inf[1].name);
+ val = 2;
+ }
+ }
+
+ /* Now the comparison has been done, if no error prevented it,
+ and VAL is the value this function will return. */
+
+ if (val == 0 && !inf[0].dir_p)
+ {
+ if (print_file_same_flag)
+ message ("Files %s and %s are identical\n",
+ inf[0].name, inf[1].name);
+ }
+ else
+ fflush (stdout);
+
+ if (free0)
+ free (free0);
+ if (free1)
+ free (free1);
+
+ return val;
+}
diff --git a/gnu/usr.bin/diff/diff.h b/gnu/usr.bin/diff/diff.h
new file mode 100644
index 0000000..7a0644d
--- /dev/null
+++ b/gnu/usr.bin/diff/diff.h
@@ -0,0 +1,340 @@
+/* Shared definitions for GNU DIFF
+ Copyright (C) 1988, 89, 91, 92, 93 Free Software Foundation, Inc.
+
+This file is part of GNU DIFF.
+
+GNU DIFF is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU DIFF is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU DIFF; see the file COPYING. If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "system.h"
+#include <stdio.h>
+#include "gnuregex.h"
+
+#define TAB_WIDTH 8
+
+/* Variables for command line options */
+
+#ifndef GDIFF_MAIN
+#define EXTERN extern
+#else
+#define EXTERN
+#endif
+
+enum output_style {
+ /* Default output style. */
+ OUTPUT_NORMAL,
+ /* Output the differences with lines of context before and after (-c). */
+ OUTPUT_CONTEXT,
+ /* Output the differences in a unified context diff format (-u). */
+ OUTPUT_UNIFIED,
+ /* Output the differences as commands suitable for `ed' (-e). */
+ OUTPUT_ED,
+ /* Output the diff as a forward ed script (-f). */
+ OUTPUT_FORWARD_ED,
+ /* Like -f, but output a count of changed lines in each "command" (-n). */
+ OUTPUT_RCS,
+ /* Output merged #ifdef'd file (-D). */
+ OUTPUT_IFDEF,
+ /* Output sdiff style (-y). */
+ OUTPUT_SDIFF
+};
+
+/* True for output styles that are robust,
+ i.e. can handle a file that ends in a non-newline. */
+#define ROBUST_OUTPUT_STYLE(S) ((S) != OUTPUT_ED && (S) != OUTPUT_FORWARD_ED)
+
+EXTERN enum output_style output_style;
+
+/* Nonzero if output cannot be generated for identical files. */
+EXTERN int no_diff_means_no_output;
+
+/* Number of lines of context to show in each set of diffs.
+ This is zero when context is not to be shown. */
+EXTERN int context;
+
+/* Consider all files as text files (-a).
+ Don't interpret codes over 0177 as implying a "binary file". */
+EXTERN int always_text_flag;
+
+/* Number of lines to keep in identical prefix and suffix. */
+EXTERN int horizon_lines;
+
+/* Ignore changes in horizontal white space (-b). */
+EXTERN int ignore_space_change_flag;
+
+/* Ignore all horizontal white space (-w). */
+EXTERN int ignore_all_space_flag;
+
+/* Ignore changes that affect only blank lines (-B). */
+EXTERN int ignore_blank_lines_flag;
+
+/* 1 if lines may match even if their contents do not match exactly.
+ This depends on various options. */
+EXTERN int ignore_some_line_changes;
+
+/* 1 if files may match even if their contents are not byte-for-byte identical.
+ This depends on various options. */
+EXTERN int ignore_some_changes;
+
+/* Ignore differences in case of letters (-i). */
+EXTERN int ignore_case_flag;
+
+/* File labels for `-c' output headers (-L). */
+EXTERN char *file_label[2];
+
+struct regexp_list
+{
+ struct re_pattern_buffer buf;
+ struct regexp_list *next;
+};
+
+/* Regexp to identify function-header lines (-F). */
+EXTERN struct regexp_list *function_regexp_list;
+
+/* Ignore changes that affect only lines matching this regexp (-I). */
+EXTERN struct regexp_list *ignore_regexp_list;
+
+/* Say only whether files differ, not how (-q). */
+EXTERN int no_details_flag;
+
+/* Report files compared that match (-s).
+ Normally nothing is output when that happens. */
+EXTERN int print_file_same_flag;
+
+/* Output the differences with exactly 8 columns added to each line
+ so that any tabs in the text line up properly (-T). */
+EXTERN int tab_align_flag;
+
+/* Expand tabs in the output so the text lines up properly
+ despite the characters added to the front of each line (-t). */
+EXTERN int tab_expand_flag;
+
+/* In directory comparison, specify file to start with (-S).
+ All file names less than this name are ignored. */
+EXTERN char *dir_start_file;
+
+/* If a file is new (appears in only one dir)
+ include its entire contents (-N).
+ Then `patch' would create the file with appropriate contents. */
+EXTERN int entire_new_file_flag;
+
+/* If a file is new (appears in only the second dir)
+ include its entire contents (-P).
+ Then `patch' would create the file with appropriate contents. */
+EXTERN int unidirectional_new_file_flag;
+
+/* Pipe each file's output through pr (-l). */
+EXTERN int paginate_flag;
+
+enum line_class {
+ /* Lines taken from just the first file. */
+ OLD,
+ /* Lines taken from just the second file. */
+ NEW,
+ /* Lines common to both files. */
+ UNCHANGED,
+ /* A hunk containing both old and new lines (line groups only). */
+ CHANGED
+};
+
+/* Line group formats for old, new, unchanged, and changed groups. */
+EXTERN char *group_format[CHANGED + 1];
+
+/* Line formats for old, new, and unchanged lines. */
+EXTERN char *line_format[UNCHANGED + 1];
+
+/* If using OUTPUT_SDIFF print extra information to help the sdiff filter. */
+EXTERN int sdiff_help_sdiff;
+
+/* Tell OUTPUT_SDIFF to show only the left version of common lines. */
+EXTERN int sdiff_left_only;
+
+/* Tell OUTPUT_SDIFF to not show common lines. */
+EXTERN int sdiff_skip_common_lines;
+
+/* The half line width and column 2 offset for OUTPUT_SDIFF. */
+EXTERN unsigned sdiff_half_width;
+EXTERN unsigned sdiff_column2_offset;
+
+/* String containing all the command options diff received,
+ with spaces between and at the beginning but none at the end.
+ If there were no options given, this string is empty. */
+EXTERN char * switch_string;
+
+/* Nonzero means use heuristics for better speed. */
+EXTERN int heuristic;
+
+/* Name of program the user invoked (for error messages). */
+EXTERN char *program_name;
+
+/* The result of comparison is an "edit script": a chain of `struct change'.
+ Each `struct change' represents one place where some lines are deleted
+ and some are inserted.
+
+ LINE0 and LINE1 are the first affected lines in the two files (origin 0).
+ DELETED is the number of lines deleted here from file 0.
+ INSERTED is the number of lines inserted here in file 1.
+
+ If DELETED is 0 then LINE0 is the number of the line before
+ which the insertion was done; vice versa for INSERTED and LINE1. */
+
+struct change
+{
+ struct change *link; /* Previous or next edit command */
+ int inserted; /* # lines of file 1 changed here. */
+ int deleted; /* # lines of file 0 changed here. */
+ int line0; /* Line number of 1st deleted line. */
+ int line1; /* Line number of 1st inserted line. */
+ char ignore; /* Flag used in context.c */
+};
+
+/* Structures that describe the input files. */
+
+/* Data on one input file being compared. */
+
+struct file_data {
+ int desc; /* File descriptor */
+ char const *name; /* File name */
+ struct stat stat; /* File status from fstat() */
+ int dir_p; /* nonzero if file is a directory */
+
+ /* Buffer in which text of file is read. */
+ char * buffer;
+ /* Allocated size of buffer. */
+ size_t bufsize;
+ /* Number of valid characters now in the buffer. */
+ size_t buffered_chars;
+
+ /* Array of pointers to lines in the file. */
+ char const **linbuf;
+
+ /* linbuf_base <= buffered_lines <= valid_lines <= alloc_lines.
+ linebuf[linbuf_base ... buffered_lines - 1] are possibly differing.
+ linebuf[linbuf_base ... valid_lines - 1] contain valid data.
+ linebuf[linbuf_base ... alloc_lines - 1] are allocated. */
+ int linbuf_base, buffered_lines, valid_lines, alloc_lines;
+
+ /* Pointer to end of prefix of this file to ignore when hashing. */
+ char const *prefix_end;
+
+ /* Count of lines in the prefix.
+ There are this many lines in the file before linbuf[0]. */
+ int prefix_lines;
+
+ /* Pointer to start of suffix of this file to ignore when hashing. */
+ char const *suffix_begin;
+
+ /* Vector, indexed by line number, containing an equivalence code for
+ each line. It is this vector that is actually compared with that
+ of another file to generate differences. */
+ int *equivs;
+
+ /* Vector, like the previous one except that
+ the elements for discarded lines have been squeezed out. */
+ int *undiscarded;
+
+ /* Vector mapping virtual line numbers (not counting discarded lines)
+ to real ones (counting those lines). Both are origin-0. */
+ int *realindexes;
+
+ /* Total number of nondiscarded lines. */
+ int nondiscarded_lines;
+
+ /* Vector, indexed by real origin-0 line number,
+ containing 1 for a line that is an insertion or a deletion.
+ The results of comparison are stored here. */
+ char *changed_flag;
+
+ /* 1 if file ends in a line with no final newline. */
+ int missing_newline;
+
+ /* 1 more than the maximum equivalence value used for this or its
+ sibling file. */
+ int equiv_max;
+};
+
+/* Describe the two files currently being compared. */
+
+EXTERN struct file_data files[2];
+
+/* Stdio stream to output diffs to. */
+
+EXTERN FILE *outfile;
+
+/* Declare various functions. */
+
+/* analyze.c */
+int diff_2_files PARAMS((struct file_data[], int));
+
+/* context.c */
+void print_context_header PARAMS((struct file_data[], int));
+void print_context_script PARAMS((struct change *, int));
+
+/* diff.c */
+int excluded_filename PARAMS((char const *));
+
+/* dir.c */
+int diff_dirs PARAMS((struct file_data const[], int (*) PARAMS((char const *, char const *, char const *, char const *, int)), int));
+
+/* ed.c */
+void print_ed_script PARAMS((struct change *));
+void pr_forward_ed_script PARAMS((struct change *));
+
+/* ifdef.c */
+void print_ifdef_script PARAMS((struct change *));
+
+/* io.c */
+int read_files PARAMS((struct file_data[], int));
+int sip PARAMS((struct file_data *, int));
+void slurp PARAMS((struct file_data *));
+
+/* normal.c */
+void print_normal_script PARAMS((struct change *));
+
+/* rcs.c */
+void print_rcs_script PARAMS((struct change *));
+
+/* side.c */
+void print_sdiff_script PARAMS((struct change *));
+
+/* util.c */
+VOID *xmalloc PARAMS((size_t));
+VOID *xrealloc PARAMS((VOID *, size_t));
+char *concat PARAMS((char const *, char const *, char const *));
+char *dir_file_pathname PARAMS((char const *, char const *));
+int change_letter PARAMS((int, int));
+int line_cmp PARAMS((char const *, char const *));
+int translate_line_number PARAMS((struct file_data const *, int));
+struct change *find_change PARAMS((struct change *));
+struct change *find_reverse_change PARAMS((struct change *));
+void analyze_hunk PARAMS((struct change *, int *, int *, int *, int *, int *, int *));
+void begin_output PARAMS((void));
+void debug_script PARAMS((struct change *));
+void error PARAMS((char const *, char const *, char const *));
+void fatal PARAMS((char const *));
+void finish_output PARAMS((void));
+void message PARAMS((char const *, char const *, char const *));
+void message5 PARAMS((char const *, char const *, char const *, char const *, char const *));
+void output_1_line PARAMS((char const *, char const *, char const *, char const *));
+void perror_with_name PARAMS((char const *));
+void pfatal_with_name PARAMS((char const *));
+void print_1_line PARAMS((char const *, char const * const *));
+void print_message_queue PARAMS((void));
+void print_number_range PARAMS((int, struct file_data *, int, int));
+void print_script PARAMS((struct change *, struct change * (*) PARAMS((struct change *)), void (*) PARAMS((struct change *))));
+void setup_output PARAMS((char const *, char const *, int));
+void translate_range PARAMS((struct file_data const *, int, int, int *, int *));
+
+/* version.c */
+extern char const version_string[];
diff --git a/gnu/usr.bin/diff/diff.texi b/gnu/usr.bin/diff/diff.texi
new file mode 100644
index 0000000..7551acb
--- /dev/null
+++ b/gnu/usr.bin/diff/diff.texi
@@ -0,0 +1,3916 @@
+\input texinfo @c -*-texinfo-*-
+@c %**start of header
+@setfilename diff.info
+@settitle Comparing and Merging Files
+@setchapternewpage odd
+@c %**end of header
+
+@ifinfo
+This file documents the the GNU @code{diff}, @code{diff3}, @code{sdiff},
+and @code{cmp} commands for showing the differences between text files
+and the @code{patch} command for using their output to update files.
+
+Copyright (C) 1992, 1993, 1994 Free Software Foundation, Inc.
+
+Permission is granted to make and distribute verbatim copies of
+this manual provided the copyright notice and this permission notice
+are preserved on all copies.
+
+@ignore
+Permission is granted to process this file through TeX and print the
+results, provided the printed document carries copying permission
+notice identical to this one except for the removal of this paragraph
+(this paragraph not being relevant to the printed manual).
+
+@end ignore
+Permission is granted to copy and distribute modified versions of this
+manual under the conditions for verbatim copying, provided that the entire
+resulting derived work is distributed under the terms of a permission
+notice identical to this one.
+
+Permission is granted to copy and distribute translations of this manual
+into another language, under the above conditions for modified versions,
+except that this permission notice may be stated in a translation approved
+by the Foundation.
+@end ifinfo
+
+@titlepage
+@title Comparing and Merging Files
+@subtitle @code{diff}, @code{diff3}, @code{sdiff}, @code{cmp}, and @code{patch}
+@subtitle Edition 1.3, for @code{diff} 2.5 and @code{patch} 2.1
+@subtitle September 1993
+@author by David MacKenzie, Paul Eggert, and Richard Stallman
+
+@page
+@vskip 0pt plus 1filll
+Copyright @copyright{} 1992, 1993, 1994 Free Software Foundation, Inc.
+
+Permission is granted to make and distribute verbatim copies of
+this manual provided the copyright notice and this permission notice
+are preserved on all copies.
+
+Permission is granted to copy and distribute modified versions of this
+manual under the conditions for verbatim copying, provided that the entire
+resulting derived work is distributed under the terms of a permission
+notice identical to this one.
+
+Permission is granted to copy and distribute translations of this manual
+into another language, under the above conditions for modified versions,
+except that this permission notice may be stated in a translation approved
+by the Foundation.
+@end titlepage
+
+@node Top, , , (dir)
+
+@ifinfo
+This file documents the the GNU @code{diff}, @code{diff3}, @code{sdiff},
+and @code{cmp} commands for showing the differences between text files
+and the @code{patch} command for using their output to update files.
+
+This is Edition 1.2, for @code{diff} 2.4 and @code{patch} 2.1.
+@end ifinfo
+
+@menu
+* Overview:: Preliminary information.
+
+* Comparison:: What file comparison means.
+* Output Formats:: Formats for difference reports.
+* Comparing Directories:: Comparing files and directories.
+* Adjusting Output:: Making @code{diff} output prettier.
+* diff Performance:: Making @code{diff} smarter or faster.
+* Comparing Three Files:: Formats for three-way difference reports.
+
+* diff3 Merging:: Merging from a common ancestor.
+* Interactive Merging:: Interactive merging with @code{sdiff}.
+* Merging with patch:: Using @code{patch} to change old files into new ones.
+* Making Patches:: Tips for making patch distributions.
+
+* Invoking cmp:: How to run @code{cmp} and a summary of its options.
+* Invoking diff:: How to run @code{diff} and a summary of its options.
+* Invoking diff3:: How to run @code{diff3} and a summary of its options.
+* Invoking patch:: How to run @code{patch} and a summary of its options.
+* Invoking sdiff:: How to run @code{sdiff} and a summary of its options.
+
+* Incomplete Lines:: Lines that lack trailing newlines.
+* Projects:: If you think you've found a bug or other shortcoming.
+
+* Concept Index:: Index of concepts.
+@end menu
+
+@node Overview, Comparison, , Top
+@unnumbered Overview
+@cindex overview of @code{diff} and @code{patch}
+
+Computer users often find occasion to ask how two files differ. Perhaps
+one file is a newer version of the other file. Or maybe the two files
+started out as identical copies but were changed by different people.
+
+You can use the @code{diff} command to show differences between two
+files, or each corresponding file in two directories. @code{diff}
+outputs differences between files line by line in any of several
+formats, selectable by command line options. This set of differences is
+often called a @dfn{diff} or @dfn{patch}. For files that are identical,
+@code{diff} normally produces no output; for binary (non-text) files,
+@code{diff} normally reports only that they are different.
+
+You can use the @code{cmp} command to show the offsets and line numbers
+where two files differ. @code{cmp} can also show all the characters
+that differ between the two files, side by side. Another way to compare
+two files character by character is the Emacs command @kbd{M-x
+compare-windows}. @xref{Other Window, , Other Window, emacs, The GNU
+Emacs Manual}, for more information on that command.
+
+You can use the @code{diff3} command to show differences among three
+files. When two people have made independent changes to a common
+original, @code{diff3} can report the differences between the original
+and the two changed versions, and can produce a merged file that
+contains both persons' changes together with warnings about conflicts.
+
+You can use the @code{sdiff} command to merge two files interactively.
+
+You can use the set of differences produced by @code{diff} to distribute
+updates to text files (such as program source code) to other people.
+This method is especially useful when the differences are small compared
+to the complete files. Given @code{diff} output, you can use the
+@code{patch} program to update, or @dfn{patch}, a copy of the file. If you
+think of @code{diff} as subtracting one file from another to produce
+their difference, you can think of @code{patch} as adding the difference
+to one file to reproduce the other.
+
+This manual first concentrates on making diffs, and later shows how to
+use diffs to update files.
+
+GNU @code{diff} was written by Mike Haertel, David Hayes, Richard
+Stallman, Len Tower, and Paul Eggert. Wayne Davison designed and
+implemented the unified output format. The basic algorithm is described
+in ``An O(ND) Difference Algorithm and its Variations'', Eugene W. Myers,
+@cite{Algorithmica} Vol.@: 1 No.@: 2, 1986, pp.@: 251--266; and in ``A File
+Comparison Program'', Webb Miller and Eugene W. Myers,
+@cite{Software---Practice and Experience} Vol.@: 15 No.@: 11, 1985,
+pp.@: 1025--1040.
+@c From: "Gene Myers" <gene@cs.arizona.edu>
+@c They are about the same basic algorithm; the Algorithmica
+@c paper gives a rigorous treatment and the sub-algorithm for
+@c delivering scripts and should be the primary reference, but
+@c both should be mentioned.
+The algorithm was independently discovered as described in
+``Algorithms for Approximate String Matching'',
+E. Ukkonen, @cite{Information and Control} Vol.@: 64, 1985, pp.@: 100--118.
+@c From: "Gene Myers" <gene@cs.arizona.edu>
+@c Date: Wed, 29 Sep 1993 08:27:55 MST
+@c Ukkonen should be given credit for also discovering the algorithm used
+@c in GNU diff.
+
+GNU @code{diff3} was written by Randy Smith. GNU @code{sdiff} was
+written by Thomas Lord. GNU @code{cmp} was written by Torbjorn Granlund
+and David MacKenzie.
+
+@code{patch} was written mainly by Larry Wall; the GNU enhancements were
+written mainly by Wayne Davison and David MacKenzie. Parts of this
+manual are adapted from a manual page written by Larry Wall, with his
+permission.
+
+@node Comparison, Output Formats, Overview, Top
+@chapter What Comparison Means
+@cindex introduction
+
+There are several ways to think about the differences between two files.
+One way to think of the differences is as a series of lines that were
+deleted from, inserted in, or changed in one file to produce the other
+file. @code{diff} compares two files line by line, finds groups of
+lines that differ, and reports each group of differing lines. It can
+report the differing lines in several formats, which have different
+purposes.
+
+GNU @code{diff} can show whether files are different without detailing
+the differences. It also provides ways to suppress certain kinds of
+differences that are not important to you. Most commonly, such
+differences are changes in the amount of white space between words or
+lines. @code{diff} also provides ways to suppress differences in
+alphabetic case or in lines that match a regular expression that you
+provide. These options can accumulate; for example, you can ignore
+changes in both white space and alphabetic case.
+
+Another way to think of the differences between two files is as a
+sequence of pairs of characters that can be either identical or
+different. @code{cmp} reports the differences between two files
+character by character, instead of line by line. As a result, it is
+more useful than @code{diff} for comparing binary files. For text
+files, @code{cmp} is useful mainly when you want to know only whether
+two files are identical.
+
+To illustrate the effect that considering changes character by character
+can have compared with considering them line by line, think of what
+happens if a single newline character is added to the beginning of a
+file. If that file is then compared with an otherwise identical file
+that lacks the newline at the beginning, @code{diff} will report that a
+blank line has been added to the file, while @code{cmp} will report that
+almost every character of the two files differs.
+
+@code{diff3} normally compares three input files line by line, finds
+groups of lines that differ, and reports each group of differing lines.
+Its output is designed to make it easy to inspect two different sets of
+changes to the same file.
+
+@menu
+* Hunks:: Groups of differing lines.
+* White Space:: Suppressing differences in white space.
+* Blank Lines:: Suppressing differences in blank lines.
+* Case Folding:: Suppressing differences in alphabetic case.
+* Specified Folding:: Suppressing differences that match regular expressions.
+* Brief:: Summarizing which files are different.
+* Binary:: Comparing binary files or forcing text comparisons.
+@end menu
+
+@node Hunks, White Space, , Comparison
+@section Hunks
+@cindex hunks
+
+When comparing two files, @code{diff} finds sequences of lines common to
+both files, interspersed with groups of differing lines called
+@dfn{hunks}. Comparing two identical files yields one sequence of
+common lines and no hunks, because no lines differ. Comparing two
+entirely different files yields no common lines and one large hunk that
+contains all lines of both files. In general, there are many ways to
+match up lines between two given files. @code{diff} tries to minimize
+the total hunk size by finding large sequences of common lines
+interspersed with small hunks of differing lines.
+
+For example, suppose the file @file{F} contains the three lines
+@samp{a}, @samp{b}, @samp{c}, and the file @file{G} contains the same
+three lines in reverse order @samp{c}, @samp{b}, @samp{a}. If
+@code{diff} finds the line @samp{c} as common, then the command
+@samp{diff F G} produces this output:
+
+@example
+1,2d0
+< a
+< b
+3a2,3
+> b
+> a
+@end example
+
+@noindent
+But if @code{diff} notices the common line @samp{b} instead, it produces
+this output:
+
+@example
+1c1
+< a
+---
+> c
+3c3
+< c
+---
+> a
+@end example
+
+@noindent
+It is also possible to find @samp{a} as the common line. @code{diff}
+does not always find an optimal matching between the files; it takes
+shortcuts to run faster. But its output is usually close to the
+shortest possible. You can adjust this tradeoff with the
+@samp{--minimal} option (@pxref{diff Performance}).
+
+@node White Space, Blank Lines, Hunks, Comparison
+@section Suppressing Differences in Blank and Tab Spacing
+@cindex blank and tab difference suppression
+@cindex tab and blank difference suppression
+
+The @samp{-b} and @samp{--ignore-space-change} options ignore white space
+at line end, and considers all other sequences of one or more
+white space characters to be equivalent. With these options,
+@code{diff} considers the following two lines to be equivalent, where
+@samp{$} denotes the line end:
+
+@example
+Here lyeth muche rychnesse in lytell space. -- John Heywood$
+Here lyeth muche rychnesse in lytell space. -- John Heywood $
+@end example
+
+The @samp{-w} and @samp{--ignore-all-space} options are stronger than
+@samp{-b}. They ignore difference even if one file has white space where
+the other file has none. @dfn{White space} characters include
+tab, newline, vertical tab, form feed, carriage return, and space;
+some locales may define additional characters to be white space.
+With these options, @code{diff} considers the
+following two lines to be equivalent, where @samp{$} denotes the line
+end and @samp{^M} denotes a carriage return:
+
+@example
+Here lyeth muche rychnesse in lytell space.-- John Heywood$
+ He relyeth much erychnes seinly tells pace. --John Heywood ^M$
+@end example
+
+@node Blank Lines, Case Folding, White Space, Comparison
+@section Suppressing Differences in Blank Lines
+@cindex blank line difference suppression
+
+The @samp{-B} and @samp{--ignore-blank-lines} options ignore insertions
+or deletions of blank lines. These options normally affect only lines
+that are completely empty; they do not affect lines that look empty but
+contain space or tab characters. With these options, for example, a
+file containing
+@example
+1. A point is that which has no part.
+
+2. A line is breadthless length.
+-- Euclid, The Elements, I
+@end example
+@noindent
+is considered identical to a file containing
+@example
+1. A point is that which has no part.
+2. A line is breadthless length.
+
+
+-- Euclid, The Elements, I
+@end example
+
+@node Case Folding, Specified Folding, Blank Lines, Comparison
+@section Suppressing Case Differences
+@cindex case difference suppression
+
+GNU @code{diff} can treat lowercase letters as equivalent to their
+uppercase counterparts, so that, for example, it considers @samp{Funky
+Stuff}, @samp{funky STUFF}, and @samp{fUNKy stuFf} to all be the same.
+To request this, use the @samp{-i} or @samp{--ignore-case} option.
+
+@node Specified Folding, Brief, Case Folding, Comparison
+@section Suppressing Lines Matching a Regular Expression
+@cindex regular expression suppression
+
+To ignore insertions and deletions of lines that match a regular
+expression, use the @samp{-I @var{regexp}} or
+@samp{--ignore-matching-lines=@var{regexp}} option. You should escape
+regular expressions that contain shell metacharacters to prevent the
+shell from expanding them. For example, @samp{diff -I '^[0-9]'} ignores
+all changes to lines beginning with a digit.
+
+However, @samp{-I} only ignores the insertion or deletion of lines that
+contain the regular expression if every changed line in the hunk---every
+insertion and every deletion---matches the regular expression. In other
+words, for each nonignorable change, @code{diff} prints the complete set
+of changes in its vicinity, including the ignorable ones.
+
+You can specify more than one regular expression for lines to ignore by
+using more than one @samp{-I} option. @code{diff} tries to match each
+line against each regular expression, starting with the last one given.
+
+@node Brief, Binary, Specified Folding, Comparison
+@section Summarizing Which Files Differ
+@cindex summarizing which files differ
+@cindex brief difference reports
+
+When you only want to find out whether files are different, and you
+don't care what the differences are, you can use the summary output
+format. In this format, instead of showing the differences between the
+files, @code{diff} simply reports whether files differ. The @samp{-q}
+and @samp{--brief} options select this output format.
+
+This format is especially useful when comparing the contents of two
+directories. It is also much faster than doing the normal line by line
+comparisons, because @code{diff} can stop analyzing the files as soon as
+it knows that there are any differences.
+
+You can also get a brief indication of whether two files differ by using
+@code{cmp}. For files that are identical, @code{cmp} produces no
+output. When the files differ, by default, @code{cmp} outputs the byte
+offset and line number where the first difference occurs. You can use
+the @samp{-s} option to suppress that information, so that @code{cmp}
+produces no output and reports whether the files differ using only its
+exit status (@pxref{Invoking cmp}).
+
+@c Fix this.
+Unlike @code{diff}, @code{cmp} cannot compare directories; it can only
+compare two files.
+
+@node Binary, , Brief, Comparison
+@section Binary Files and Forcing Text Comparisons
+@cindex binary file diff
+@cindex text versus binary diff
+
+If @code{diff} thinks that either of the two files it is comparing is
+binary (a non-text file), it normally treats that pair of files much as
+if the summary output format had been selected (@pxref{Brief}), and
+reports only that the binary files are different. This is because line
+by line comparisons are usually not meaningful for binary files.
+
+@code{diff} determines whether a file is text or binary by checking the
+first few bytes in the file; the exact number of bytes is system
+dependent, but it is typically several thousand. If every character in
+that part of the file is non-null, @code{diff} considers the file to be
+text; otherwise it considers the file to be binary.
+
+Sometimes you might want to force @code{diff} to consider files to be
+text. For example, you might be comparing text files that contain
+null characters; @code{diff} would erroneously decide that those are
+non-text files. Or you might be comparing documents that are in a
+format used by a word processing system that uses null characters to
+indicate special formatting. You can force @code{diff} to consider all
+files to be text files, and compare them line by line, by using the
+@samp{-a} or @samp{--text} option. If the files you compare using this
+option do not in fact contain text, they will probably contain few
+newline characters, and the @code{diff} output will consist of hunks
+showing differences between long lines of whatever characters the files
+contain.
+
+You can also force @code{diff} to consider all files to be binary files,
+and report only whether they differ (but not how). Use the
+@samp{--brief} option for this.
+
+In operating systems that distinguish between text and binary files,
+@code{diff} normally reads and writes all data as text. Use the
+@samp{--binary} option to force @code{diff} to read and write binary
+data instead. This option has no effect on a Posix-compliant system
+like GNU or traditional Unix. However, many personal computer
+operating systems represent the end of a line with a carriage return
+followed by a newline. On such systems, @code{diff} normally ignores
+these carriage returns on input and generates them at the end of each
+output line, but with the @samp{--binary} option @code{diff} treats
+each carriage return as just another input character, and does not
+generate a carriage return at the end of each output line. This can be
+useful when dealing with non-text files that are meant to be
+interchanged with Posix-compliant systems.
+
+If you want to compare two files byte by byte, you can use the
+@code{cmp} program with the @samp{-l} option to show the values of each
+differing byte in the two files. With GNU @code{cmp}, you can also use
+the @samp{-c} option to show the ASCII representation of those bytes.
+@xref{Invoking cmp}, for more information.
+
+If @code{diff3} thinks that any of the files it is comparing is binary
+(a non-text file), it normally reports an error, because such
+comparisons are usually not useful. @code{diff3} uses the same test as
+@code{diff} to decide whether a file is binary. As with @code{diff}, if
+the input files contain a few non-text characters but otherwise are like
+text files, you can force @code{diff3} to consider all files to be text
+files and compare them line by line by using the @samp{-a} or
+@samp{--text} options.
+
+@node Output Formats, Comparing Directories, Comparison, Top
+@chapter @code{diff} Output Formats
+@cindex output formats
+@cindex format of @code{diff} output
+
+@code{diff} has several mutually exclusive options for output format.
+The following sections describe each format, illustrating how
+@code{diff} reports the differences between two sample input files.
+
+@menu
+* Sample diff Input:: Sample @code{diff} input files for examples.
+* Normal:: Showing differences without surrounding text.
+* Context:: Showing differences with the surrounding text.
+* Side by Side:: Showing differences in two columns.
+* Scripts:: Generating scripts for other programs.
+* If-then-else:: Merging files with if-then-else.
+@end menu
+
+@node Sample diff Input, Normal, , Output Formats
+@section Two Sample Input Files
+@cindex @code{diff} sample input
+@cindex sample input for @code{diff}
+
+Here are two sample files that we will use in numerous examples to
+illustrate the output of @code{diff} and how various options can change
+it.
+
+This is the file @file{lao}:
+
+@example
+The Way that can be told of is not the eternal Way;
+The name that can be named is not the eternal name.
+The Nameless is the origin of Heaven and Earth;
+The Named is the mother of all things.
+Therefore let there always be non-being,
+ so we may see their subtlety,
+And let there always be being,
+ so we may see their outcome.
+The two are the same,
+But after they are produced,
+ they have different names.
+@end example
+
+This is the file @file{tzu}:
+
+@example
+The Nameless is the origin of Heaven and Earth;
+The named is the mother of all things.
+
+Therefore let there always be non-being,
+ so we may see their subtlety,
+And let there always be being,
+ so we may see their outcome.
+The two are the same,
+But after they are produced,
+ they have different names.
+They both may be called deep and profound.
+Deeper and more profound,
+The door of all subtleties!
+@end example
+
+In this example, the first hunk contains just the first two lines of
+@file{lao}, the second hunk contains the fourth line of @file{lao}
+opposing the second and third lines of @file{tzu}, and the last hunk
+contains just the last three lines of @file{tzu}.
+
+@node Normal, Context, Sample diff Input, Output Formats
+@section Showing Differences Without Context
+@cindex normal output format
+@cindex @samp{<} output format
+
+The ``normal'' @code{diff} output format shows each hunk of differences
+without any surrounding context. Sometimes such output is the clearest
+way to see how lines have changed, without the clutter of nearby
+unchanged lines (although you can get similar results with the context
+or unified formats by using 0 lines of context). However, this format
+is no longer widely used for sending out patches; for that purpose, the
+context format (@pxref{Context Format}) and the unified format
+(@pxref{Unified Format}) are superior. Normal format is the default for
+compatibility with older versions of @code{diff} and the Posix standard.
+
+@menu
+* Detailed Normal:: A detailed description of normal output format.
+* Example Normal:: Sample output in the normal format.
+@end menu
+
+@node Detailed Normal, Example Normal, , Normal
+@subsection Detailed Description of Normal Format
+
+The normal output format consists of one or more hunks of differences;
+each hunk shows one area where the files differ. Normal format hunks
+look like this:
+
+@example
+@var{change-command}
+< @var{from-file-line}
+< @var{from-file-line}@dots{}
+---
+> @var{to-file-line}
+> @var{to-file-line}@dots{}
+@end example
+
+There are three types of change commands. Each consists of a line
+number or comma-separated range of lines in the first file, a single
+character indicating the kind of change to make, and a line number or
+comma-separated range of lines in the second file. All line numbers are
+the original line numbers in each file. The types of change commands
+are:
+
+@table @samp
+@item @var{l}a@var{r}
+Add the lines in range @var{r} of the second file after line @var{l} of
+the first file. For example, @samp{8a12,15} means append lines 12--15
+of file 2 after line 8 of file 1; or, if changing file 2 into file 1,
+delete lines 12--15 of file 2.
+
+@item @var{f}c@var{t}
+Replace the lines in range @var{f} of the first file with lines in range
+@var{t} of the second file. This is like a combined add and delete, but
+more compact. For example, @samp{5,7c8,10} means change lines 5--7 of
+file 1 to read as lines 8--10 of file 2; or, if changing file 2 into
+file 1, change lines 8--10 of file 2 to read as lines 5--7 of file 1.
+
+@item @var{r}d@var{l}
+Delete the lines in range @var{r} from the first file; line @var{l} is where
+they would have appeared in the second file had they not been deleted.
+For example, @samp{5,7d3} means delete lines 5--7 of file 1; or, if
+changing file 2 into file 1, append lines 5--7 of file 1 after line 3 of
+file 2.
+@end table
+
+@node Example Normal, , Detailed Normal, Normal
+@subsection An Example of Normal Format
+
+Here is the output of the command @samp{diff lao tzu}
+(@pxref{Sample diff Input}, for the complete contents of the two files).
+Notice that it shows only the lines that are different between the two
+files.
+
+@example
+1,2d0
+< The Way that can be told of is not the eternal Way;
+< The name that can be named is not the eternal name.
+4c2,3
+< The Named is the mother of all things.
+---
+> The named is the mother of all things.
+>
+11a11,13
+> They both may be called deep and profound.
+> Deeper and more profound,
+> The door of all subtleties!
+@end example
+
+@node Context, Side by Side, Normal, Output Formats
+@section Showing Differences in Their Context
+@cindex context output format
+@cindex @samp{!} output format
+
+Usually, when you are looking at the differences between files, you will
+also want to see the parts of the files near the lines that differ, to
+help you understand exactly what has changed. These nearby parts of the
+files are called the @dfn{context}.
+
+GNU @code{diff} provides two output formats that show context around the
+differing lines: @dfn{context format} and @dfn{unified format}. It can
+optionally show in which function or section of the file the differing
+lines are found.
+
+If you are distributing new versions of files to other people in the
+form of @code{diff} output, you should use one of the output formats
+that show context so that they can apply the diffs even if they have
+made small changes of their own to the files. @code{patch} can apply
+the diffs in this case by searching in the files for the lines of
+context around the differing lines; if those lines are actually a few
+lines away from where the diff says they are, @code{patch} can adjust
+the line numbers accordingly and still apply the diff correctly.
+@xref{Imperfect}, for more information on using @code{patch} to apply
+imperfect diffs.
+
+@menu
+* Context Format:: An output format that shows surrounding lines.
+* Unified Format:: A more compact output format that shows context.
+* Sections:: Showing which sections of the files differences are in.
+* Alternate Names:: Showing alternate file names in context headers.
+@end menu
+
+@node Context Format, Unified Format, , Context
+@subsection Context Format
+
+The context output format shows several lines of context around the
+lines that differ. It is the standard format for distributing updates
+to source code.
+
+To select this output format, use the @samp{-C @var{lines}},
+@samp{--context@r{[}=@var{lines}@r{]}}, or @samp{-c} option. The
+argument @var{lines} that some of these options take is the number of
+lines of context to show. If you do not specify @var{lines}, it
+defaults to three. For proper operation, @code{patch} typically needs
+at least two lines of context.
+
+@menu
+* Detailed Context:: A detailed description of the context output format.
+* Example Context:: Sample output in context format.
+* Less Context:: Another sample with less context.
+@end menu
+
+@node Detailed Context, Example Context, , Context Format
+@subsubsection Detailed Description of Context Format
+
+The context output format starts with a two-line header, which looks
+like this:
+
+@example
+*** @var{from-file} @var{from-file-modification-time}
+--- @var{to-file} @var{to-file-modification time}
+@end example
+
+@noindent
+You can change the header's content with the @samp{-L @var{label}} or
+@samp{--label=@var{label}} option; see @ref{Alternate Names}.
+
+Next come one or more hunks of differences; each hunk shows one area
+where the files differ. Context format hunks look like this:
+
+@example
+***************
+*** @var{from-file-line-range} ****
+ @var{from-file-line}
+ @var{from-file-line}@dots{}
+--- @var{to-file-line-range} ----
+ @var{to-file-line}
+ @var{to-file-line}@dots{}
+@end example
+
+The lines of context around the lines that differ start with two space
+characters. The lines that differ between the two files start with one
+of the following indicator characters, followed by a space character:
+
+@table @samp
+@item !
+A line that is part of a group of one or more lines that changed between
+the two files. There is a corresponding group of lines marked with
+@samp{!} in the part of this hunk for the other file.
+
+@item +
+An ``inserted'' line in the second file that corresponds to nothing in
+the first file.
+
+@item -
+A ``deleted'' line in the first file that corresponds to nothing in the
+second file.
+@end table
+
+If all of the changes in a hunk are insertions, the lines of
+@var{from-file} are omitted. If all of the changes are deletions, the
+lines of @var{to-file} are omitted.
+
+@node Example Context, Less Context, Detailed Context, Context Format
+@subsubsection An Example of Context Format
+
+Here is the output of @samp{diff -c lao tzu} (@pxref{Sample diff Input},
+for the complete contents of the two files). Notice that up to three
+lines that are not different are shown around each line that is
+different; they are the context lines. Also notice that the first two
+hunks have run together, because their contents overlap.
+
+@example
+*** lao Sat Jan 26 23:30:39 1991
+--- tzu Sat Jan 26 23:30:50 1991
+***************
+*** 1,7 ****
+- The Way that can be told of is not the eternal Way;
+- The name that can be named is not the eternal name.
+ The Nameless is the origin of Heaven and Earth;
+! The Named is the mother of all things.
+ Therefore let there always be non-being,
+ so we may see their subtlety,
+ And let there always be being,
+--- 1,6 ----
+ The Nameless is the origin of Heaven and Earth;
+! The named is the mother of all things.
+!
+ Therefore let there always be non-being,
+ so we may see their subtlety,
+ And let there always be being,
+***************
+*** 9,11 ****
+--- 8,13 ----
+ The two are the same,
+ But after they are produced,
+ they have different names.
++ They both may be called deep and profound.
++ Deeper and more profound,
++ The door of all subtleties!
+@end example
+
+@node Less Context, , Example Context, Context Format
+@subsubsection An Example of Context Format with Less Context
+
+Here is the output of @samp{diff --context=1 lao tzu} (@pxref{Sample
+diff Input}, for the complete contents of the two files). Notice that
+at most one context line is reported here.
+
+@example
+*** lao Sat Jan 26 23:30:39 1991
+--- tzu Sat Jan 26 23:30:50 1991
+***************
+*** 1,5 ****
+- The Way that can be told of is not the eternal Way;
+- The name that can be named is not the eternal name.
+ The Nameless is the origin of Heaven and Earth;
+! The Named is the mother of all things.
+ Therefore let there always be non-being,
+--- 1,4 ----
+ The Nameless is the origin of Heaven and Earth;
+! The named is the mother of all things.
+!
+ Therefore let there always be non-being,
+***************
+*** 11 ****
+--- 10,13 ----
+ they have different names.
++ They both may be called deep and profound.
++ Deeper and more profound,
++ The door of all subtleties!
+@end example
+
+@node Unified Format, Sections, Context Format, Context
+@subsection Unified Format
+@cindex unified output format
+@cindex @samp{+-} output format
+
+The unified output format is a variation on the context format that is
+more compact because it omits redundant context lines. To select this
+output format, use the @samp{-U @var{lines}},
+@samp{--unified@r{[}=@var{lines}@r{]}}, or @samp{-u}
+option. The argument @var{lines} is the number of lines of context to
+show. When it is not given, it defaults to three.
+
+At present, only GNU @code{diff} can produce this format and only GNU
+@code{patch} can automatically apply diffs in this format. For proper
+operation, @code{patch} typically needs at least two lines of context.
+
+@menu
+* Detailed Unified:: A detailed description of unified format.
+* Example Unified:: Sample output in unified format.
+@end menu
+
+@node Detailed Unified, Example Unified, , Unified Format
+@subsubsection Detailed Description of Unified Format
+
+The unified output format starts with a two-line header, which looks
+like this:
+
+@example
+--- @var{from-file} @var{from-file-modification-time}
++++ @var{to-file} @var{to-file-modification-time}
+@end example
+
+@noindent
+You can change the header's content with the @samp{-L @var{label}} or
+@samp{--label=@var{label}} option; see @xref{Alternate Names}.
+
+Next come one or more hunks of differences; each hunk shows one area
+where the files differ. Unified format hunks look like this:
+
+@example
+@@@@ @var{from-file-range} @var{to-file-range} @@@@
+ @var{line-from-either-file}
+ @var{line-from-either-file}@dots{}
+@end example
+
+The lines common to both files begin with a space character. The lines
+that actually differ between the two files have one of the following
+indicator characters in the left column:
+
+@table @samp
+@item +
+A line was added here to the first file.
+
+@item -
+A line was removed here from the first file.
+@end table
+
+@node Example Unified, , Detailed Unified, Unified Format
+@subsubsection An Example of Unified Format
+
+Here is the output of the command @samp{diff -u lao tzu}
+(@pxref{Sample diff Input}, for the complete contents of the two files):
+
+@example
+--- lao Sat Jan 26 23:30:39 1991
++++ tzu Sat Jan 26 23:30:50 1991
+@@@@ -1,7 +1,6 @@@@
+-The Way that can be told of is not the eternal Way;
+-The name that can be named is not the eternal name.
+ The Nameless is the origin of Heaven and Earth;
+-The Named is the mother of all things.
++The named is the mother of all things.
++
+ Therefore let there always be non-being,
+ so we may see their subtlety,
+ And let there always be being,
+@@@@ -9,3 +8,6 @@@@
+ The two are the same,
+ But after they are produced,
+ they have different names.
++They both may be called deep and profound.
++Deeper and more profound,
++The door of all subtleties!
+@end example
+
+@node Sections, Alternate Names, Unified Format, Context
+@subsection Showing Which Sections Differences Are in
+@cindex headings
+@cindex section headings
+
+Sometimes you might want to know which part of the files each change
+falls in. If the files are source code, this could mean which function
+was changed. If the files are documents, it could mean which chapter or
+appendix was changed. GNU @code{diff} can show this by displaying the
+nearest section heading line that precedes the differing lines. Which
+lines are ``section headings'' is determined by a regular expression.
+
+@menu
+* Specified Headings:: Showing headings that match regular expressions.
+* C Function Headings:: Showing headings of C functions.
+@end menu
+
+@node Specified Headings, C Function Headings, , Sections
+@subsubsection Showing Lines That Match Regular Expressions
+@cindex specified headings
+@cindex regular expression matching headings
+
+To show in which sections differences occur for files that are not
+source code for C or similar languages, use the @samp{-F @var{regexp}}
+or @samp{--show-function-line=@var{regexp}} option. @code{diff}
+considers lines that match the argument @var{regexp} to be the beginning
+of a section of the file. Here are suggested regular expressions for
+some common languages:
+
+@c Please add to this list, e.g. Fortran, Pascal.
+@table @samp
+@item ^[A-Za-z_]
+C, C++, Prolog
+@item ^(
+Lisp
+@item ^@@\(chapter\|appendix\|unnumbered\|chapheading\)
+Texinfo
+@end table
+
+This option does not automatically select an output format; in order to
+use it, you must select the context format (@pxref{Context Format}) or
+unified format (@pxref{Unified Format}). In other output formats it
+has no effect.
+
+The @samp{-F} and @samp{--show-function-line} options find the nearest
+unchanged line that precedes each hunk of differences and matches the
+given regular expression. Then they add that line to the end of the
+line of asterisks in the context format, or to the @samp{@@@@} line in
+unified format. If no matching line exists, they leave the output for
+that hunk unchanged. If that line is more than 40 characters long, they
+output only the first 40 characters. You can specify more than one
+regular expression for such lines; @code{diff} tries to match each line
+against each regular expression, starting with the last one given. This
+means that you can use @samp{-p} and @samp{-F} together, if you wish.
+
+@node C Function Headings, , Specified Headings, Sections
+@subsubsection Showing C Function Headings
+@cindex C function headings
+@cindex function headings, C
+
+To show in which functions differences occur for C and similar
+languages, you can use the @samp{-p} or @samp{--show-c-function} option.
+This option automatically defaults to the context output format
+(@pxref{Context Format}), with the default number of lines of context.
+You can override that number with @samp{-C @var{lines}} elsewhere in the
+command line. You can override both the format and the number with
+@samp{-U @var{lines}} elsewhere in the command line.
+
+The @samp{-p} and @samp{--show-c-function} options are equivalent to
+@samp{-F'^[_a-zA-Z$]'} if the unified format is specified, otherwise
+@samp{-c -F'^[_a-zA-Z$]'} (@pxref{Specified Headings}). GNU @code{diff}
+provides them for the sake of convenience.
+
+@node Alternate Names, , Sections, Context
+@subsection Showing Alternate File Names
+@cindex alternate file names
+@cindex file name alternates
+
+If you are comparing two files that have meaningless or uninformative
+names, you might want @code{diff} to show alternate names in the header
+of the context and unified output formats. To do this, use the @samp{-L
+@var{label}} or @samp{--label=@var{label}} option. The first time
+you give this option, its argument replaces the name and date of the
+first file in the header; the second time, its argument replaces the
+name and date of the second file. If you give this option more than
+twice, @code{diff} reports an error. The @samp{-L} option does not
+affect the file names in the @code{pr} header when the @samp{-l} or
+@samp{--paginate} option is used (@pxref{Pagination}).
+
+Here are the first two lines of the output from @samp{diff -C2
+-Loriginal -Lmodified lao tzu}:
+
+@example
+*** original
+--- modified
+@end example
+
+@node Side by Side, Scripts, Context, Output Formats
+@section Showing Differences Side by Side
+@cindex side by side
+@cindex two-column output
+@cindex columnar output
+
+@code{diff} can produce a side by side difference listing of two files.
+The files are listed in two columns with a gutter between them. The
+gutter contains one of the following markers:
+
+@table @asis
+@item white space
+The corresponding lines are in common. That is, either the lines are
+identical, or the difference is ignored because of one of the
+@samp{--ignore} options (@pxref{White Space}).
+
+@item @samp{|}
+The corresponding lines differ, and they are either both complete
+or both incomplete.
+
+@item @samp{<}
+The files differ and only the first file contains the line.
+
+@item @samp{>}
+The files differ and only the second file contains the line.
+
+@item @samp{(}
+Only the first file contains the line, but the difference is ignored.
+
+@item @samp{)}
+Only the second file contains the line, but the difference is ignored.
+
+@item @samp{\}
+The corresponding lines differ, and only the first line is incomplete.
+
+@item @samp{/}
+The corresponding lines differ, and only the second line is incomplete.
+@end table
+
+Normally, an output line is incomplete if and only if the lines that it
+contains are incomplete; @xref{Incomplete Lines}. However, when an
+output line represents two differing lines, one might be incomplete
+while the other is not. In this case, the output line is complete,
+but its the gutter is marked @samp{\} if the first line is incomplete,
+@samp{/} if the second line is.
+
+Side by side format is sometimes easiest to read, but it has limitations.
+It generates much wider output than usual, and truncates lines that are
+too long to fit. Also, it relies on lining up output more heavily than
+usual, so its output looks particularly bad if you use varying
+width fonts, nonstandard tab stops, or nonprinting characters.
+
+You can use the @code{sdiff} command to interactively merge side by side
+differences. @xref{Interactive Merging}, for more information on merging files.
+
+@menu
+* Side by Side Format:: Controlling side by side output format.
+* Example Side by Side:: Sample side by side output.
+@end menu
+
+@node Side by Side Format, Example Side by Side, , Side by Side
+@section Controlling Side by Side Format
+@cindex side by side format
+
+The @samp{-y} or @samp{--side-by-side} option selects side by side
+format. Because side by side output lines contain two input lines, they
+are wider than usual. They are normally 130 columns, which can fit onto
+a traditional printer line. You can set the length of output lines with
+the @samp{-W @var{columns}} or @samp{--width=@var{columns}} option. The
+output line is split into two halves of equal length, separated by a
+small gutter to mark differences; the right half is aligned to a tab
+stop so that tabs line up. Input lines that are too long to fit in half
+of an output line are truncated for output.
+
+The @samp{--left-column} option prints only the left column of two
+common lines. The @samp{--suppress-common-lines} option suppresses
+common lines entirely.
+
+@node Example Side by Side, , Side by Side Format, Side by Side
+@subsection An Example of Side by Side Format
+
+Here is the output of the command @samp{diff -y -W 72 lao tzu}
+(@pxref{Sample diff Input}, for the complete contents of the two files).
+
+@example
+The Way that can be told of is n <
+The name that can be named is no <
+The Nameless is the origin of He The Nameless is the origin of He
+The Named is the mother of all t | The named is the mother of all t
+ >
+Therefore let there always be no Therefore let there always be no
+ so we may see their subtlety, so we may see their subtlety,
+And let there always be being, And let there always be being,
+ so we may see their outcome. so we may see their outcome.
+The two are the same, The two are the same,
+But after they are produced, But after they are produced,
+ they have different names. they have different names.
+ > They both may be called deep and
+ > Deeper and more profound,
+ > The door of all subtleties!
+@end example
+
+@node Scripts, If-then-else, Side by Side, Output Formats
+@section Making Edit Scripts
+@cindex script output formats
+
+Several output modes produce command scripts for editing @var{from-file}
+to produce @var{to-file}.
+
+@menu
+* ed Scripts:: Using @code{diff} to produce commands for @code{ed}.
+* Forward ed:: Making forward @code{ed} scripts.
+* RCS:: A special @code{diff} output format used by RCS.
+@end menu
+
+@node ed Scripts, Forward ed, , Scripts
+@subsection @code{ed} Scripts
+@cindex @code{ed} script output format
+
+@code{diff} can produce commands that direct the @code{ed} text editor
+to change the first file into the second file. Long ago, this was the
+only output mode that was suitable for editing one file into another
+automatically; today, with @code{patch}, it is almost obsolete. Use the
+@samp{-e} or @samp{--ed} option to select this output format.
+
+Like the normal format (@pxref{Normal}), this output format does not
+show any context; unlike the normal format, it does not include the
+information necessary to apply the diff in reverse (to produce the first
+file if all you have is the second file and the diff).
+
+If the file @file{d} contains the output of @samp{diff -e old new}, then
+the command @samp{(cat d && echo w) | ed - old} edits @file{old} to make
+it a copy of @file{new}. More generally, if @file{d1}, @file{d2},
+@dots{}, @file{dN} contain the outputs of @samp{diff -e old new1},
+@samp{diff -e new1 new2}, @dots{}, @samp{diff -e newN-1 newN},
+respectively, then the command @samp{(cat d1 d2 @dots{} dN && echo w) |
+ed - old} edits @file{old} to make it a copy of @file{newN}.
+
+@menu
+* Detailed ed:: A detailed description of @code{ed} format.
+* Example ed:: A sample @code{ed} script.
+@end menu
+
+@node Detailed ed, Example ed, , ed Scripts
+@subsubsection Detailed Description of @code{ed} Format
+
+The @code{ed} output format consists of one or more hunks of
+differences. The changes closest to the ends of the files come first so
+that commands that change the number of lines do not affect how
+@code{ed} interprets line numbers in succeeding commands. @code{ed}
+format hunks look like this:
+
+@example
+@var{change-command}
+@var{to-file-line}
+@var{to-file-line}@dots{}
+.
+@end example
+
+Because @code{ed} uses a single period on a line to indicate the end of
+input, GNU @code{diff} protects lines of changes that contain a single
+period on a line by writing two periods instead, then writing a
+subsequent @code{ed} command to change the two periods into one. The
+@code{ed} format cannot represent an incomplete line, so if the second
+file ends in a changed incomplete line, @code{diff} reports an error and
+then pretends that a newline was appended.
+
+There are three types of change commands. Each consists of a line
+number or comma-separated range of lines in the first file and a single
+character indicating the kind of change to make. All line numbers are
+the original line numbers in the file. The types of change commands
+are:
+
+@table @samp
+@item @var{l}a
+Add text from the second file after line @var{l} in the first file. For
+example, @samp{8a} means to add the following lines after line 8 of file
+1.
+
+@item @var{r}c
+Replace the lines in range @var{r} in the first file with the following
+lines. Like a combined add and delete, but more compact. For example,
+@samp{5,7c} means change lines 5--7 of file 1 to read as the text file
+2.
+
+@item @var{r}d
+Delete the lines in range @var{r} from the first file. For example,
+@samp{5,7d} means delete lines 5--7 of file 1.
+@end table
+
+@node Example ed, , Detailed ed, ed Scripts
+@subsubsection Example @code{ed} Script
+
+Here is the output of @samp{diff -e lao tzu} (@pxref{Sample
+diff Input}, for the complete contents of the two files):
+
+@example
+11a
+They both may be called deep and profound.
+Deeper and more profound,
+The door of all subtleties!
+.
+4c
+The named is the mother of all things.
+
+.
+1,2d
+@end example
+
+@node Forward ed, RCS, ed Scripts, Scripts
+@subsection Forward @code{ed} Scripts
+@cindex forward @code{ed} script output format
+
+@code{diff} can produce output that is like an @code{ed} script, but
+with hunks in forward (front to back) order. The format of the commands
+is also changed slightly: command characters precede the lines they
+modify, spaces separate line numbers in ranges, and no attempt is made
+to disambiguate hunk lines consisting of a single period. Like
+@code{ed} format, forward @code{ed} format cannot represent incomplete
+lines.
+
+Forward @code{ed} format is not very useful, because neither @code{ed}
+nor @code{patch} can apply diffs in this format. It exists mainly for
+compatibility with older versions of @code{diff}. Use the @samp{-f} or
+@samp{--forward-ed} option to select it.
+
+@node RCS, , Forward ed, Scripts
+@subsection RCS Scripts
+@cindex RCS script output format
+
+The RCS output format is designed specifically for use by the Revision
+Control System, which is a set of free programs used for organizing
+different versions and systems of files. Use the @samp{-n} or
+@samp{--rcs} option to select this output format. It is like the
+forward @code{ed} format (@pxref{Forward ed}), but it can represent
+arbitrary changes to the contents of a file because it avoids the
+forward @code{ed} format's problems with lines consisting of a single
+period and with incomplete lines. Instead of ending text sections with
+a line consisting of a single period, each command specifies the number
+of lines it affects; a combination of the @samp{a} and @samp{d}
+commands are used instead of @samp{c}. Also, if the second file ends
+in a changed incomplete line, then the output also ends in an
+incomplete line.
+
+Here is the output of @samp{diff -n lao tzu} (@pxref{Sample
+diff Input}, for the complete contents of the two files):
+
+@example
+d1 2
+d4 1
+a4 2
+The named is the mother of all things.
+
+a11 3
+They both may be called deep and profound.
+Deeper and more profound,
+The door of all subtleties!
+@end example
+
+@node If-then-else, , Scripts, Output Formats
+@section Merging Files with If-then-else
+@cindex merged output format
+@cindex if-then-else output format
+@cindex C if-then-else output format
+@cindex @code{ifdef} output format
+
+You can use @code{diff} to merge two files of C source code. The output
+of @code{diff} in this format contains all the lines of both files.
+Lines common to both files are output just once; the differing parts are
+separated by the C preprocessor directives @code{#ifdef @var{name}} or
+@code{#ifndef @var{name}}, @code{#else}, and @code{#endif}. When
+compiling the output, you select which version to use by either defining
+or leaving undefined the macro @var{name}.
+
+To merge two files, use @code{diff} with the @samp{-D @var{name}} or
+@samp{--ifdef=@var{name}} option. The argument @var{name} is the C
+preprocessor identifier to use in the @code{#ifdef} and @code{#ifndef}
+directives.
+
+For example, if you change an instance of @code{wait (&s)} to
+@code{waitpid (-1, &s, 0)} and then merge the old and new files with
+the @samp{--ifdef=HAVE_WAITPID} option, then the affected part of your code
+might look like this:
+
+@example
+ do @{
+#ifndef HAVE_WAITPID
+ if ((w = wait (&s)) < 0 && errno != EINTR)
+#else /* HAVE_WAITPID */
+ if ((w = waitpid (-1, &s, 0)) < 0 && errno != EINTR)
+#endif /* HAVE_WAITPID */
+ return w;
+ @} while (w != child);
+@end example
+
+You can specify formats for languages other than C by using line group
+formats and line formats, as described in the next sections.
+
+@menu
+* Line Group Formats:: Formats for general if-then-else line groups.
+* Line Formats:: Formats for each line in a line group.
+* Detailed If-then-else:: A detailed description of if-then-else format.
+* Example If-then-else:: Sample if-then-else format output.
+@end menu
+
+@node Line Group Formats, Line Formats, , If-then-else
+@subsection Line Group Formats
+@cindex line group formats
+@cindex formats for if-then-else line groups
+
+Line group formats let you specify formats suitable for many
+applications that allow if-then-else input, including programming
+languages and text formatting languages. A line group format specifies
+the output format for a contiguous group of similar lines.
+
+For example, the following command compares the TeX files @file{old}
+and @file{new}, and outputs a merged file in which old regions are
+surrounded by @samp{\begin@{em@}}-@samp{\end@{em@}} lines, and new
+regions are surrounded by @samp{\begin@{bf@}}-@samp{\end@{bf@}} lines.
+
+@example
+diff \
+ --old-group-format='\begin@{em@}
+%<\end@{em@}
+' \
+ --new-group-format='\begin@{bf@}
+%>\end@{bf@}
+' \
+ old new
+@end example
+
+The following command is equivalent to the above example, but it is a
+little more verbose, because it spells out the default line group formats.
+
+@example
+diff \
+ --old-group-format='\begin@{em@}
+%<\end@{em@}
+' \
+ --new-group-format='\begin@{bf@}
+%>\end@{bf@}
+' \
+ --unchanged-group-format='%=' \
+ --changed-group-format='\begin@{em@}
+%<\end@{em@}
+\begin@{bf@}
+%>\end@{bf@}
+' \
+ old new
+@end example
+
+Here is a more advanced example, which outputs a diff listing with
+headers containing line numbers in a ``plain English'' style.
+
+@example
+diff \
+ --unchanged-group-format='' \
+ --old-group-format='-------- %dn line%(n=1?:s) deleted at %df:
+%<' \
+ --new-group-format='-------- %dN line%(N=1?:s) added after %de:
+%>' \
+ --changed-group-format='-------- %dn line%(n=1?:s) changed at %df:
+%<-------- to:
+%>' \
+ old new
+@end example
+
+To specify a line group format, use @code{diff} with one of the options
+listed below. You can specify up to four line group formats, one for
+each kind of line group. You should quote @var{format}, because it
+typically contains shell metacharacters.
+
+@table @samp
+@item --old-group-format=@var{format}
+These line groups are hunks containing only lines from the first file.
+The default old group format is the same as the changed group format if
+it is specified; otherwise it is a format that outputs the line group as-is.
+
+@item --new-group-format=@var{format}
+These line groups are hunks containing only lines from the second
+file. The default new group format is same as the the changed group
+format if it is specified; otherwise it is a format that outputs the
+line group as-is.
+
+@item --changed-group-format=@var{format}
+These line groups are hunks containing lines from both files. The
+default changed group format is the concatenation of the old and new
+group formats.
+
+@item --unchanged-group-format=@var{format}
+These line groups contain lines common to both files. The default
+unchanged group format is a format that outputs the line group as-is.
+@end table
+
+In a line group format, ordinary characters represent themselves;
+conversion specifications start with @samp{%} and have one of the
+following forms.
+
+@table @samp
+@item %<
+stands for the lines from the first file, including the trailing newline.
+Each line is formatted according to the old line format (@pxref{Line Formats}).
+
+@item %>
+stands for the lines from the second file, including the trailing newline.
+Each line is formatted according to the new line format.
+
+@item %=
+stands for the lines common to both files, including the trailing newline.
+Each line is formatted according to the unchanged line format.
+
+@item %%
+stands for @samp{%}.
+
+@item %c'@var{C}'
+where @var{C} is a single character, stands for @var{C}.
+@var{C} may not be a backslash or an apostrophe.
+For example, @samp{%c':'} stands for a colon, even inside
+the then-part of an if-then-else format, which a colon would
+normally terminate.
+
+@item %c'\@var{O}'
+where @var{O} is a string of 1, 2, or 3 octal digits,
+stands for the character with octal code @var{O}.
+For example, @samp{%c'\0'} stands for a null character.
+
+@item @var{F}@var{n}
+where @var{F} is a @code{printf} conversion specification and @var{n} is one
+of the following letters, stands for @var{n}'s value formatted with @var{F}.
+
+@table @samp
+@item e
+The line number of the line just before the group in the old file.
+
+@item f
+The line number of the first line in the group in the old file;
+equals @var{e} + 1.
+
+@item l
+The line number of the last line in the group in the old file.
+
+@item m
+The line number of the line just after the group in the old file;
+equals @var{l} + 1.
+
+@item n
+The number of lines in the group in the old file; equals @var{l} - @var{f} + 1.
+
+@item E, F, L, M, N
+Likewise, for lines in the new file.
+
+@end table
+
+The @code{printf} conversion specification can be @samp{%d},
+@samp{%o}, @samp{%x}, or @samp{%X}, specifying decimal, octal,
+lower case hexadecimal, or upper case hexadecimal output
+respectively. After the @samp{%} the following options can appear in
+sequence: a @samp{-} specifying left-justification; an integer
+specifying the minimum field width; and a period followed by an
+optional integer specifying the minimum number of digits.
+For example, @samp{%5dN} prints the number of new lines in the group
+in a field of width 5 characters, using the @code{printf} format @code{"%5d"}.
+
+@item (@var{A}=@var{B}?@var{T}:@var{E})
+If @var{A} equals @var{B} then @var{T} else @var{E}.
+@var{A} and @var{B} are each either a decimal constant
+or a single letter interpreted as above.
+This format spec is equivalent to @var{T} if
+@var{A}'s value equals @var{B}'s; otherwise it is equivalent to @var{E}.
+
+For example, @samp{%(N=0?no:%dN) line%(N=1?:s)} is equivalent to
+@samp{no lines} if @var{N} (the number of lines in the group in the the
+new file) is 0, to @samp{1 line} if @var{N} is 1, and to @samp{%dN lines}
+otherwise.
+@end table
+
+@node Line Formats, Detailed If-then-else, Line Group Formats, If-then-else
+@subsection Line Formats
+@cindex line formats
+
+Line formats control how each line taken from an input file is
+output as part of a line group in if-then-else format.
+
+For example, the following command outputs text with a one-column
+change indicator to the left of the text. The first column of output
+is @samp{-} for deleted lines, @samp{|} for added lines, and a space
+for unchanged lines. The formats contain newline characters where
+newlines are desired on output.
+
+@example
+diff \
+ --old-line-format='-%l
+' \
+ --new-line-format='|%l
+' \
+ --unchanged-line-format=' %l
+' \
+ old new
+@end example
+
+To specify a line format, use one of the following options. You should
+quote @var{format}, since it often contains shell metacharacters.
+
+@table @samp
+@item --old-line-format=@var{format}
+formats lines just from the first file.
+
+@item --new-line-format=@var{format}
+formats lines just from the second file.
+
+@item --unchanged-line-format=@var{format}
+formats lines common to both files.
+
+@item --line-format=@var{format}
+formats all lines; in effect, it sets all three above options simultaneously.
+@end table
+
+In a line format, ordinary characters represent themselves;
+conversion specifications start with @samp{%} and have one of the
+following forms.
+
+@table @samp
+@item %l
+stands for the the contents of the line, not counting its trailing
+newline (if any). This format ignores whether the line is incomplete;
+@xref{Incomplete Lines}.
+
+@item %L
+stands for the the contents of the line, including its trailing newline
+(if any). If a line is incomplete, this format preserves its
+incompleteness.
+
+@item %%
+stands for @samp{%}.
+
+@item %c'@var{C}'
+where @var{C} is a single character, stands for @var{C}.
+@var{C} may not be a backslash or an apostrophe.
+For example, @samp{%c':'} stands for a colon.
+
+@item %c'\@var{O}'
+where @var{O} is a string of 1, 2, or 3 octal digits,
+stands for the character with octal code @var{O}.
+For example, @samp{%c'\0'} stands for a null character.
+
+@item @var{F}n
+where @var{F} is a @code{printf} conversion specification,
+stands for the line number formatted with @var{F}.
+For example, @samp{%.5dn} prints the line number using the
+@code{printf} format @code{"%.5d"}. @xref{Line Group Formats}, for
+more about printf conversion specifications.
+
+@end table
+
+The default line format is @samp{%l} followed by a newline character.
+
+If the input contains tab characters and it is important that they line
+up on output, you should ensure that @samp{%l} or @samp{%L} in a line
+format is just after a tab stop (e.g.@: by preceding @samp{%l} or
+@samp{%L} with a tab character), or you should use the @samp{-t} or
+@samp{--expand-tabs} option.
+
+Taken together, the line and line group formats let you specify many
+different formats. For example, the following command uses a format
+similar to @code{diff}'s normal format. You can tailor this command
+to get fine control over @code{diff}'s output.
+
+@example
+diff \
+ --old-line-format='< %l
+' \
+ --new-line-format='> %l
+' \
+ --old-group-format='%df%(f=l?:,%dl)d%dE
+%<' \
+ --new-group-format='%dea%dF%(F=L?:,%dL)
+%>' \
+ --changed-group-format='%df%(f=l?:,%dl)c%dF%(F=L?:,%dL)
+%<---
+%>' \
+ --unchanged-group-format='' \
+ old new
+@end example
+
+@node Detailed If-then-else, Example If-then-else, Line Formats, If-then-else
+@subsection Detailed Description of If-then-else Format
+
+For lines common to both files, @code{diff} uses the unchanged line
+group format. For each hunk of differences in the merged output
+format, if the hunk contains only lines from the first file,
+@code{diff} uses the old line group format; if the hunk contains only
+lines from the second file, @code{diff} uses the new group format;
+otherwise, @code{diff} uses the changed group format.
+
+The old, new, and unchanged line formats specify the output format of
+lines from the first file, lines from the second file, and lines common
+to both files, respectively.
+
+The option @samp{--ifdef=@var{name}} is equivalent to
+the following sequence of options using shell syntax:
+
+@example
+--old-group-format='#ifndef @var{name}
+%<#endif /* not @var{name} */
+' \
+--new-group-format='#ifdef @var{name}
+%>#endif /* @var{name} */
+' \
+--unchanged-group-format='%=' \
+--changed-group-format='#ifndef @var{name}
+%<#else /* @var{name} */
+%>#endif /* @var{name} */
+'
+@end example
+
+You should carefully check the @code{diff} output for proper nesting.
+For example, when using the the @samp{-D @var{name}} or
+@samp{--ifdef=@var{name}} option, you should check that if the
+differing lines contain any of the C preprocessor directives
+@samp{#ifdef}, @samp{#ifndef}, @samp{#else}, @samp{#elif}, or
+@samp{#endif}, they are nested properly and match. If they don't, you
+must make corrections manually. It is a good idea to carefully check
+the resulting code anyway to make sure that it really does what you
+want it to; depending on how the input files were produced, the output
+might contain duplicate or otherwise incorrect code.
+
+The @code{patch} @samp{-D @var{name}} option behaves just like
+the @code{diff} @samp{-D @var{name}} option, except it operates on
+a file and a diff to produce a merged file; @xref{patch Options}.
+
+@node Example If-then-else, , Detailed If-then-else, If-then-else
+@subsection An Example of If-then-else Format
+
+Here is the output of @samp{diff -DTWO lao tzu} (@pxref{Sample
+diff Input}, for the complete contents of the two files):
+
+@example
+#ifndef TWO
+The Way that can be told of is not the eternal Way;
+The name that can be named is not the eternal name.
+#endif /* not TWO */
+The Nameless is the origin of Heaven and Earth;
+#ifndef TWO
+The Named is the mother of all things.
+#else /* TWO */
+The named is the mother of all things.
+
+#endif /* TWO */
+Therefore let there always be non-being,
+ so we may see their subtlety,
+And let there always be being,
+ so we may see their outcome.
+The two are the same,
+But after they are produced,
+ they have different names.
+#ifdef TWO
+They both may be called deep and profound.
+Deeper and more profound,
+The door of all subtleties!
+#endif /* TWO */
+@end example
+
+@node Comparing Directories, Adjusting Output, Output Formats, Top
+@chapter Comparing Directories
+
+You can use @code{diff} to compare some or all of the files in two
+directory trees. When both file name arguments to @code{diff} are
+directories, it compares each file that is contained in both
+directories, examining file names in alphabetical order. Normally
+@code{diff} is silent about pairs of files that contain no differences,
+but if you use the @samp{-s} or @samp{--report-identical-files} option,
+it reports pairs of identical files. Normally @code{diff} reports
+subdirectories common to both directories without comparing
+subdirectories' files, but if you use the @samp{-r} or
+@samp{--recursive} option, it compares every corresponding pair of files
+in the directory trees, as many levels deep as they go.
+
+For file names that are in only one of the directories, @code{diff}
+normally does not show the contents of the file that exists; it reports
+only that the file exists in that directory and not in the other. You
+can make @code{diff} act as though the file existed but was empty in the
+other directory, so that it outputs the entire contents of the file that
+actually exists. (It is output as either an insertion or a
+deletion, depending on whether it is in the first or the second
+directory given.) To do this, use the @samp{-N} or @samp{--new-file}
+option.
+
+If the older directory contains one or more large files that are not in
+the newer directory, you can make the patch smaller by using the
+@samp{-P} or @samp{--unidirectional-new-file} option instead of @samp{-N}.
+This option is like @samp{-N} except that it only inserts the contents
+of files that appear in the second directory but not the first (that is,
+files that were added). At the top of the patch, write instructions for
+the user applying the patch to remove the files that were deleted before
+applying the patch. @xref{Making Patches}, for more discussion of
+making patches for distribution.
+
+To ignore some files while comparing directories, use the @samp{-x
+@var{pattern}} or @samp{--exclude=@var{pattern}} option. This option
+ignores any files or subdirectories whose base names match the shell
+pattern @var{pattern}. Unlike in the shell, a period at the start of
+the base of a file name matches a wildcard at the start of a pattern.
+You should enclose @var{pattern} in quotes so that the shell does not
+expand it. For example, the option @samp{-x '*.[ao]'} ignores any file
+whose name ends with @samp{.a} or @samp{.o}.
+
+This option accumulates if you specify it more than once. For example,
+using the options @samp{-x 'RCS' -x '*,v'} ignores any file or
+subdirectory whose base name is @samp{RCS} or ends with @samp{,v}.
+
+If you need to give this option many times, you can instead put the
+patterns in a file, one pattern per line, and use the @samp{-X
+@var{file}} or @samp{--exclude-from=@var{file}} option.
+
+If you have been comparing two directories and stopped partway through,
+later you might want to continue where you left off. You can do this by
+using the @samp{-S @var{file}} or @samp{--starting-file=@var{file}}
+option. This compares only the file @var{file} and all alphabetically
+later files in the topmost directory level.
+
+@node Adjusting Output, diff Performance, Comparing Directories, Top
+@chapter Making @code{diff} Output Prettier
+
+@code{diff} provides several ways to adjust the appearance of its output.
+These adjustments can be applied to any output format.
+
+@menu
+* Tabs:: Preserving the alignment of tabstops.
+* Pagination:: Page numbering and timestamping @code{diff} output.
+@end menu
+
+@node Tabs, Pagination, , Adjusting Output
+@section Preserving Tabstop Alignment
+@cindex tabstop alignment
+@cindex aligning tabstops
+
+The lines of text in some of the @code{diff} output formats are preceded
+by one or two characters that indicate whether the text is inserted,
+deleted, or changed. The addition of those characters can cause tabs to
+move to the next tabstop, throwing off the alignment of columns in the
+line. GNU @code{diff} provides two ways to make tab-aligned columns
+line up correctly.
+
+The first way is to have @code{diff} convert all tabs into the correct
+number of spaces before outputting them; select this method with the
+@samp{-t} or @samp{--expand-tabs} option. @code{diff} assumes that
+tabstops are set every 8 columns. To use this form of output with
+@code{patch}, you must give @code{patch} the @samp{-l} or
+@samp{--ignore-white-space} option (@pxref{Changed White Space}, for more
+information).
+
+The other method for making tabs line up correctly is to add a tab
+character instead of a space after the indicator character at the
+beginning of the line. This ensures that all following tab characters
+are in the same position relative to tabstops that they were in the
+original files, so that the output is aligned correctly. Its
+disadvantage is that it can make long lines too long to fit on one line
+of the screen or the paper. It also does not work with the unified
+output format, which does not have a space character after the change
+type indicator character. Select this method with the @samp{-T} or
+@samp{--initial-tab} option.
+
+@node Pagination, , Tabs, Adjusting Output
+@section Paginating @code{diff} Output
+@cindex paginating @code{diff} output
+
+It can be convenient to have long output page-numbered and time-stamped.
+The @samp{-l} and @samp{--paginate} options do this by sending the
+@code{diff} output through the @code{pr} program. Here is what the page
+header might look like for @samp{diff -lc lao tzu}:
+
+@example
+Mar 11 13:37 1991 diff -lc lao tzu Page 1
+@end example
+
+@node diff Performance, Comparing Three Files, Adjusting Output, Top
+@chapter @code{diff} Performance Tradeoffs
+@cindex performance of @code{diff}
+
+GNU @code{diff} runs quite efficiently; however, in some circumstances
+you can cause it to run faster or produce a more compact set of changes.
+There are two ways that you can affect the performance of GNU
+@code{diff} by changing the way it compares files.
+
+Performance has more than one dimension. These options improve one
+aspect of performance at the cost of another, or they improve
+performance in some cases while hurting it in others.
+
+The way that GNU @code{diff} determines which lines have changed always
+comes up with a near-minimal set of differences. Usually it is good
+enough for practical purposes. If the @code{diff} output is large, you
+might want @code{diff} to use a modified algorithm that sometimes
+produces a smaller set of differences. The @samp{-d} or
+@samp{--minimal} option does this; however, it can also cause
+@code{diff} to run more slowly than usual, so it is not the default
+behavior.
+
+When the files you are comparing are large and have small groups of
+changes scattered throughout them, you can use the @samp{-H} or
+@samp{--speed-large-files} option to make a different modification to
+the algorithm that @code{diff} uses. If the input files have a constant
+small density of changes, this option speeds up the comparisons without
+changing the output. If not, @code{diff} might produce a larger set of
+differences; however, the output will still be correct.
+
+Normally @code{diff} discards the prefix and suffix that is common to
+both files before it attempts to find a minimal set of differences.
+This makes @code{diff} run faster, but occasionally it may produce
+non-minimal output. The @samp{--horizon-lines=@var{lines}} option
+prevents @code{diff} from discarding the last @var{lines} lines of the
+prefix and the first @var{lines} lines of the suffix. This gives
+@code{diff} further opportunities to find a minimal output.
+
+@node Comparing Three Files, diff3 Merging, diff Performance, Top
+@chapter Comparing Three Files
+@cindex comparing three files
+@cindex format of @code{diff3} output
+
+Use the program @code{diff3} to compare three files and show any
+differences among them. (@code{diff3} can also merge files; see
+@ref{diff3 Merging}).
+
+The ``normal'' @code{diff3} output format shows each hunk of
+differences without surrounding context. Hunks are labeled depending
+on whether they are two-way or three-way, and lines are annotated by
+their location in the input files.
+
+@xref{Invoking diff3}, for more information on how to run @code{diff3}.
+
+@menu
+* Sample diff3 Input:: Sample @code{diff3} input for examples.
+* Detailed diff3 Normal:: A detailed description of normal output format.
+* diff3 Hunks:: The format of normal output format.
+* Example diff3 Normal:: Sample output in the normal format.
+@end menu
+
+@node Sample diff3 Input, Detailed diff3 Normal, , Comparing Three Files
+@section A Third Sample Input File
+@cindex @code{diff3} sample input
+@cindex sample input for @code{diff3}
+
+Here is a third sample file that will be used in examples to illustrate
+the output of @code{diff3} and how various options can change it. The
+first two files are the same that we used for @code{diff} (@pxref{Sample
+diff Input}). This is the third sample file, called @file{tao}:
+
+@example
+The Way that can be told of is not the eternal Way;
+The name that can be named is not the eternal name.
+The Nameless is the origin of Heaven and Earth;
+The named is the mother of all things.
+
+Therefore let there always be non-being,
+ so we may see their subtlety,
+And let there always be being,
+ so we may see their result.
+The two are the same,
+But after they are produced,
+ they have different names.
+
+ -- The Way of Lao-Tzu, tr. Wing-tsit Chan
+@end example
+
+@node Detailed diff3 Normal, diff3 Hunks, Sample diff3 Input, Comparing Three Files
+@section Detailed Description of @code{diff3} Normal Format
+
+Each hunk begins with a line marked @samp{====}. Three-way hunks have
+plain @samp{====} lines, and two-way hunks have @samp{1}, @samp{2}, or
+@samp{3} appended to specify which of the three input files differ in
+that hunk. The hunks contain copies of two or three sets of input
+lines each preceded by one or two commands identifying where the lines
+came from.
+
+Normally, two spaces precede each copy of an input line to distinguish
+it from the commands. But with the @samp{-T} or @samp{--initial-tab}
+option, @code{diff3} uses a tab instead of two spaces; this lines up
+tabs correctly. @xref{Tabs}, for more information.
+
+Commands take the following forms:
+
+@table @samp
+@item @var{file}:@var{l}a
+This hunk appears after line @var{l} of file @var{file}, and
+contains no lines in that file. To edit this file to yield the other
+files, one must append hunk lines taken from the other files. For
+example, @samp{1:11a} means that the hunk follows line 11 in the first
+file and contains no lines from that file.
+
+@item @var{file}:@var{r}c
+This hunk contains the lines in the range @var{r} of file @var{file}.
+The range @var{r} is a comma-separated pair of line numbers, or just one
+number if the range is a singleton. To edit this file to yield the
+other files, one must change the specified lines to be the lines taken
+from the other files. For example, @samp{2:11,13c} means that the hunk
+contains lines 11 through 13 from the second file.
+@end table
+
+If the last line in a set of input lines is incomplete
+(@pxref{Incomplete Lines}), it is distinguished on output from a full
+line by a following line that starts with @samp{\}.
+
+@node diff3 Hunks, Example diff3 Normal, Detailed diff3 Normal, Comparing Three Files
+@section @code{diff3} Hunks
+@cindex hunks for @code{diff3}
+@cindex @code{diff3} hunks
+
+Groups of lines that differ in two or three of the input files are
+called @dfn{diff3 hunks}, by analogy with @code{diff} hunks
+(@pxref{Hunks}). If all three input files differ in a @code{diff3}
+hunk, the hunk is called a @dfn{three-way hunk}; if just two input files
+differ, it is a @dfn{two-way hunk}.
+
+As with @code{diff}, several solutions are possible. When comparing the
+files @samp{A}, @samp{B}, and @samp{C}, @code{diff3} normally finds
+@code{diff3} hunks by merging the two-way hunks output by the two
+commands @samp{diff A B} and @samp{diff A C}. This does not necessarily
+minimize the size of the output, but exceptions should be rare.
+
+For example, suppose @file{F} contains the three lines @samp{a},
+@samp{b}, @samp{f}, @file{G} contains the lines @samp{g}, @samp{b},
+@samp{g}, and @file{H} contains the lines @samp{a}, @samp{b},
+@samp{h}. @samp{diff3 F G H} might output the following:
+
+@example
+====2
+1:1c
+3:1c
+ a
+2:1c
+ g
+====
+1:3c
+ f
+2:3c
+ g
+3:3c
+ h
+@end example
+
+@noindent
+because it found a two-way hunk containing @samp{a} in the first and
+third files and @samp{g} in the second file, then the single line
+@samp{b} common to all three files, then a three-way hunk containing
+the last line of each file.
+
+@node Example diff3 Normal, , diff3 Hunks, Comparing Three Files
+@section An Example of @code{diff3} Normal Format
+
+Here is the output of the command @samp{diff3 lao tzu tao}
+(@pxref{Sample diff3 Input}, for the complete contents of the files).
+Notice that it shows only the lines that are different among the three
+files.
+
+@example
+====2
+1:1,2c
+3:1,2c
+ The Way that can be told of is not the eternal Way;
+ The name that can be named is not the eternal name.
+2:0a
+====1
+1:4c
+ The Named is the mother of all things.
+2:2,3c
+3:4,5c
+ The named is the mother of all things.
+
+====3
+1:8c
+2:7c
+ so we may see their outcome.
+3:9c
+ so we may see their result.
+====
+1:11a
+2:11,13c
+ They both may be called deep and profound.
+ Deeper and more profound,
+ The door of all subtleties!
+3:13,14c
+
+ -- The Way of Lao-Tzu, tr. Wing-tsit Chan
+@end example
+
+@node diff3 Merging, Interactive Merging, Comparing Three Files, Top
+@chapter Merging From a Common Ancestor
+@cindex merging from a common ancestor
+
+When two people have made changes to copies of the same file,
+@code{diff3} can produce a merged output that contains both sets of
+changes together with warnings about conflicts.
+
+One might imagine programs with names like @code{diff4} and @code{diff5}
+to compare more than three files simultaneously, but in practice the
+need rarely arises. You can use @code{diff3} to merge three or more
+sets of changes to a file by merging two change sets at a time.
+
+@code{diff3} can incorporate changes from two modified versions into a
+common preceding version. This lets you merge the sets of changes
+represented by the two newer files. Specify the common ancestor version
+as the second argument and the two newer versions as the first and third
+arguments, like this:
+
+@example
+diff3 @var{mine} @var{older} @var{yours}
+@end example
+
+@noindent
+You can remember the order of the arguments by noting that they are in
+alphabetical order.
+
+@cindex conflict
+@cindex overlap
+You can think of this as subtracting @var{older} from @var{yours} and
+adding the result to @var{mine}, or as merging into @var{mine} the
+changes that would turn @var{older} into @var{yours}. This merging is
+well-defined as long as @var{mine} and @var{older} match in the
+neighborhood of each such change. This fails to be true when all three
+input files differ or when only @var{older} differs; we call this
+a @dfn{conflict}. When all three input files differ, we call the
+conflict an @dfn{overlap}.
+
+@code{diff3} gives you several ways to handle overlaps and conflicts.
+You can omit overlaps or conflicts, or select only overlaps,
+or mark conflicts with special @samp{<<<<<<<} and @samp{>>>>>>>} lines.
+
+@code{diff3} can output the merge results as an @code{ed} script that
+that can be applied to the first file to yield the merged output.
+However, it is usually better to have @code{diff3} generate the merged
+output directly; this bypasses some problems with @code{ed}.
+
+@menu
+* Which Changes:: Selecting changes to incorporate.
+* Marking Conflicts:: Marking conflicts.
+* Bypassing ed:: Generating merged output directly.
+* Merging Incomplete Lines:: How @code{diff3} merges incomplete lines.
+* Saving the Changed File:: Emulating System V behavior.
+@end menu
+
+@node Which Changes, Marking Conflicts, , diff3 Merging
+@section Selecting Which Changes to Incorporate
+@cindex overlapping change, selection of
+@cindex unmerged change
+
+You can select all unmerged changes from @var{older} to @var{yours} for merging
+into @var{mine} with the @samp{-e} or @samp{--ed} option. You can
+select only the nonoverlapping unmerged changes with @samp{-3} or
+@samp{--easy-only}, and you can select only the overlapping changes with
+@samp{-x} or @samp{--overlap-only}.
+
+The @samp{-e}, @samp{-3} and @samp{-x} options select only
+@dfn{unmerged changes}, i.e.@: changes where @var{mine} and @var{yours}
+differ; they ignore changes from @var{older} to @var{yours} where
+@var{mine} and @var{yours} are identical, because they assume that such
+changes have already been merged. If this assumption is not a safe
+one, you can use the @samp{-A} or @samp{--show-all} option
+(@pxref{Marking Conflicts}).
+
+Here is the output of the command @code{diff3} with each of these three
+options (@pxref{Sample diff3 Input}, for the complete contents of the files).
+Notice that @samp{-e} outputs the union of the disjoint sets of changes
+output by @samp{-3} and @samp{-x}.
+
+Output of @samp{diff3 -e lao tzu tao}:
+@example
+11a
+
+ -- The Way of Lao-Tzu, tr. Wing-tsit Chan
+.
+8c
+ so we may see their result.
+.
+@end example
+
+Output of @samp{diff3 -3 lao tzu tao}:
+@example
+8c
+ so we may see their result.
+.
+@end example
+
+Output of @samp{diff3 -x lao tzu tao}:
+@example
+11a
+
+ -- The Way of Lao-Tzu, tr. Wing-tsit Chan
+.
+@end example
+
+@node Marking Conflicts, Bypassing ed, Which Changes, diff3 Merging
+@section Marking Conflicts
+@cindex conflict marking
+@cindex @samp{<<<<<<<} for marking conflicts
+
+@code{diff3} can mark conflicts in the merged output by
+bracketing them with special marker lines. A conflict
+that comes from two files @var{A} and @var{B} is marked as follows:
+
+@example
+<<<<<<< @var{A}
+@r{lines from @var{A}}
+=======
+@r{lines from @var{B}}
+>>>>>>> @var{B}
+@end example
+
+A conflict that comes from three files @var{A}, @var{B} and @var{C} is
+marked as follows:
+
+@example
+<<<<<<< @var{A}
+@r{lines from @var{A}}
+||||||| @var{B}
+@r{lines from @var{B}}
+=======
+@r{lines from @var{C}}
+>>>>>>> @var{C}
+@end example
+
+The @samp{-A} or @samp{--show-all} option acts like the @samp{-e}
+option, except that it brackets conflicts, and it outputs all changes
+from @var{older} to @var{yours}, not just the unmerged changes. Thus,
+given the sample input files (@pxref{Sample diff3 Input}), @samp{diff3
+-A lao tzu tao} puts brackets around the conflict where only @file{tzu}
+differs:
+
+@example
+<<<<<<< tzu
+=======
+The Way that can be told of is not the eternal Way;
+The name that can be named is not the eternal name.
+>>>>>>> tao
+@end example
+
+And it outputs the three-way conflict as follows:
+
+@example
+<<<<<<< lao
+||||||| tzu
+They both may be called deep and profound.
+Deeper and more profound,
+The door of all subtleties!
+=======
+
+ -- The Way of Lao-Tzu, tr. Wing-tsit Chan
+>>>>>>> tao
+@end example
+
+The @samp{-E} or @samp{--show-overlap} option outputs less information
+than the @samp{-A} or @samp{--show-all} option, because it outputs only
+unmerged changes, and it never outputs the contents of the second
+file. Thus the @samp{-E} option acts like the @samp{-e} option,
+except that it brackets the first and third files from three-way
+overlapping changes. Similarly, @samp{-X} acts like @samp{-x}, except
+it brackets all its (necessarily overlapping) changes. For example,
+for the three-way overlapping change above, the @samp{-E} and @samp{-X}
+options output the following:
+
+@example
+<<<<<<< lao
+=======
+
+ -- The Way of Lao-Tzu, tr. Wing-tsit Chan
+>>>>>>> tao
+@end example
+
+If you are comparing files that have meaningless or uninformative names,
+you can use the @samp{-L @var{label}} or @samp{--label=@var{label}}
+option to show alternate names in the @samp{<<<<<<<}, @samp{|||||||}
+and @samp{>>>>>>>} brackets. This option can be given up to three
+times, once for each input file. Thus @samp{diff3 -A -L X -L Y -L Z A
+B C} acts like @samp{diff3 -A A B C}, except that the output looks like
+it came from files named @samp{X}, @samp{Y} and @samp{Z} rather than
+from files named @samp{A}, @samp{B} and @samp{C}.
+
+@node Bypassing ed, Merging Incomplete Lines, Marking Conflicts, diff3 Merging
+@section Generating the Merged Output Directly
+@cindex merged @code{diff3} format
+
+With the @samp{-m} or @samp{--merge} option, @code{diff3} outputs the
+merged file directly. This is more efficient than using @code{ed} to
+generate it, and works even with non-text files that @code{ed} would
+reject. If you specify @samp{-m} without an @code{ed} script option,
+@samp{-A} (@samp{--show-all}) is assumed.
+
+For example, the command @samp{diff3 -m lao tzu tao}
+(@pxref{Sample diff3 Input} for a copy of the input files) would output
+the following:
+
+@example
+<<<<<<< tzu
+=======
+The Way that can be told of is not the eternal Way;
+The name that can be named is not the eternal name.
+>>>>>>> tao
+The Nameless is the origin of Heaven and Earth;
+The Named is the mother of all things.
+Therefore let there always be non-being,
+ so we may see their subtlety,
+And let there always be being,
+ so we may see their result.
+The two are the same,
+But after they are produced,
+ they have different names.
+<<<<<<< lao
+||||||| tzu
+They both may be called deep and profound.
+Deeper and more profound,
+The door of all subtleties!
+=======
+
+ -- The Way of Lao-Tzu, tr. Wing-tsit Chan
+>>>>>>> tao
+@end example
+
+@node Merging Incomplete Lines, Saving the Changed File, Bypassing ed, diff3 Merging
+@section How @code{diff3} Merges Incomplete Lines
+@cindex incomplete line merging
+
+With @samp{-m}, incomplete lines (@pxref{Incomplete Lines}) are simply
+copied to the output as they are found; if the merged output ends in an
+conflict and one of the input files ends in an incomplete
+line, succeeding @samp{|||||||}, @samp{=======} or @samp{>>>>>>>}
+brackets appear somewhere other than the start of a line because
+they are appended to the incomplete line.
+
+Without @samp{-m}, if an @code{ed} script option is specified and an
+incomplete line is found, @code{diff3} generates a warning and acts as
+if a newline had been present.
+
+@node Saving the Changed File, , Merging Incomplete Lines, diff3 Merging
+@section Saving the Changed File
+@cindex System V @code{diff3} compatibility
+
+Traditional Unix @code{diff3} generates an @code{ed} script without the
+trailing @samp{w} and and @samp{q} commands that save the changes.
+System V @code{diff3} generates these extra commands. GNU @code{diff3}
+normally behaves like traditional Unix @code{diff3}, but with the
+@samp{-i} option it behaves like System V @code{diff3} and appends the
+@samp{w} and @samp{q} commands.
+
+The @samp{-i} option requires one of the @code{ed} script options
+@samp{-AeExX3}, and is incompatible with the merged output option
+@samp{-m}.
+
+@node Interactive Merging, Merging with patch, diff3 Merging, Top
+@chapter Interactive Merging with @code{sdiff}
+@cindex diff merging
+@cindex interactive merging
+
+With @code{sdiff}, you can merge two files interactively based on a
+side-by-side @samp{-y} format comparison (@pxref{Side by Side}). Use
+@samp{-o @var{file}} or @samp{--output=@var{file}} to specify where to
+put the merged text. @xref{Invoking sdiff}, for more details on the
+options to @code{sdiff}.
+
+Another way to merge files interactively is to use the Emacs Lisp
+package @code{emerge}. @xref{emerge, , emerge, emacs, The GNU Emacs
+Manual}, for more information.
+
+@menu
+* sdiff Option Summary::Summary of @code{sdiff} options.
+* Merge Commands:: Merging two files interactively.
+@end menu
+
+@node sdiff Option Summary, Merge Commands, , Interactive Merging
+@section Specifying @code{diff} Options to @code{sdiff}
+@cindex @code{sdiff} output format
+
+The following @code{sdiff} options have the same meaning as for
+@code{diff}. @xref{diff Options}, for the use of these options.
+
+@example
+-a -b -d -i -t -v
+-B -H -I @var{regexp}
+
+--ignore-blank-lines --ignore-case
+--ignore-matching-lines=@var{regexp} --ignore-space-change
+--left-column --minimal --speed-large-files
+--suppress-common-lines --expand-tabs
+--text --version --width=@var{columns}
+@end example
+
+For historical reasons, @code{sdiff} has alternate names for some
+options. The @samp{-l} option is equivalent to the @samp{--left-column}
+option, and similarly @samp{-s} is equivalent to
+@samp{--suppress-common-lines}. The meaning of the @code{sdiff}
+@samp{-w} and @samp{-W} options is interchanged from that of
+@code{diff}: with @code{sdiff}, @samp{-w @var{columns}} is equivalent to
+@samp{--width=@var{columns}}, and @samp{-W} is equivalent to
+@samp{--ignore-all-space}. @code{sdiff} without the @samp{-o} option is
+equivalent to @code{diff} with the @samp{-y} or @samp{--side-by-side}
+option (@pxref{Side by Side}).
+
+@node Merge Commands, , sdiff Option Summary, Interactive Merging
+@section Merge Commands
+@cindex merge commands
+@cindex merging interactively
+
+Groups of common lines, with a blank gutter, are copied from the first
+file to the output. After each group of differing lines, @code{sdiff}
+prompts with @samp{%} and pauses, waiting for one of the following
+commands. Follow each command with @key{RET}.
+
+@table @samp
+@item e
+Discard both versions.
+Invoke a text editor on an empty temporary file,
+then copy the resulting file to the output.
+
+@item eb
+Concatenate the two versions, edit the result in a temporary file,
+then copy the edited result to the output.
+
+@item el
+Edit a copy of the left version, then copy the result to the output.
+
+@item er
+Edit a copy of the right version, then copy the result to the output.
+
+@item l
+Copy the left version to the output.
+
+@item q
+Quit.
+
+@item r
+Copy the right version to the output.
+
+@item s
+Silently copy common lines.
+
+@item v
+Verbosely copy common lines. This is the default.
+@end table
+
+The text editor invoked is specified by the @code{EDITOR} environment
+variable if it is set. The default is system-dependent.
+
+@node Merging with patch, Making Patches, Interactive Merging, Top
+@chapter Merging with @code{patch}
+
+@code{patch} takes comparison output produced by @code{diff} and applies
+the differences to a copy of the original file, producing a patched
+version. With @code{patch}, you can distribute just the changes to a
+set of files instead of distributing the entire file set; your
+correspondents can apply @code{patch} to update their copy of the files
+with your changes. @code{patch} automatically determines the diff
+format, skips any leading or trailing headers, and uses the headers to
+determine which file to patch. This lets your correspondents feed an
+article or message containing a difference listing directly to
+@code{patch}.
+
+@code{patch} detects and warns about common problems like forward
+patches. It saves the original version of the files it patches, and
+saves any patches that it could not apply. It can also maintain a
+@code{patchlevel.h} file to ensures that your correspondents apply
+diffs in the proper order.
+
+@code{patch} accepts a series of diffs in its standard input, usually
+separated by headers that specify which file to patch. It applies
+@code{diff} hunks (@pxref{Hunks}) one by one. If a hunk does not
+exactly match the original file, @code{patch} uses heuristics to try to
+patch the file as well as it can. If no approximate match can be found,
+@code{patch} rejects the hunk and skips to the next hunk. @code{patch}
+normally replaces each file @var{f} with its new version, saving the
+original file in @samp{@var{f}.orig}, and putting reject hunks (if any)
+into @samp{@var{f}.rej}.
+
+@xref{Invoking patch}, for detailed information on the options to
+@code{patch}. @xref{Backups}, for more information on how
+@code{patch} names backup files. @xref{Rejects}, for more information
+on where @code{patch} puts reject hunks.
+
+@menu
+* patch Input:: Selecting the type of @code{patch} input.
+* Imperfect:: Dealing with imperfect patches.
+* Empty Files:: Removing empty files after patching.
+* Multiple Patches:: Handling multiple patches in a file specially.
+* patch Messages:: Messages and questions @code{patch} can produce.
+@end menu
+
+@node patch Input, Imperfect, , Merging with patch
+@section Selecting the @code{patch} Input Format
+@cindex @code{patch} input format
+
+@code{patch} normally determines which @code{diff} format the patch
+file uses by examining its contents. For patch files that contain
+particularly confusing leading text, you might need to use one of the
+following options to force @code{patch} to interpret the patch file as a
+certain format of diff. The output formats listed here are the only
+ones that @code{patch} can understand.
+
+@table @samp
+@item -c
+@itemx --context
+context diff.
+
+@item -e
+@itemx --ed
+@code{ed} script.
+
+@item -n
+@itemx --normal
+normal diff.
+
+@item -u
+@itemx --unified
+unified diff.
+@end table
+
+@node Imperfect, Empty Files, patch Input, Merging with patch
+@section Applying Imperfect Patches
+@cindex imperfect patch application
+
+@code{patch} tries to skip any leading text in the patch file, apply the
+diff, and then skip any trailing text. Thus you can feed a news article
+or mail message directly to @code{patch}, and it should work. If the
+entire diff is indented by a constant amount of white space, @code{patch}
+automatically ignores the indentation.
+
+However, certain other types of imperfect input require user
+intervention.
+
+@menu
+* Changed White Space:: When tabs and spaces don't match exactly.
+* Reversed Patches:: Applying reversed patches correctly.
+* Inexact:: Helping @code{patch} find close matches.
+@end menu
+
+@node Changed White Space, Reversed Patches, , Imperfect
+@subsection Applying Patches with Changed White Space
+@cindex white space in patches
+
+Sometimes mailers, editors, or other programs change spaces into tabs,
+or vice versa. If this happens to a patch file or an input file, the
+files might look the same, but @code{patch} will not be able to match
+them properly. If this problem occurs, use the @samp{-l} or
+@samp{--ignore-white-space} option, which makes @code{patch} compare
+white space loosely so that any sequence of white space in the patch file
+matches any sequence of white space in the input files. Non-white-space
+characters must still match exactly. Each line of the context must
+still match a line in the input file.
+
+@node Reversed Patches, Inexact, Changed White Space, Imperfect
+@subsection Applying Reversed Patches
+@cindex reversed patches
+
+Sometimes people run @code{diff} with the new file first instead of
+second. This creates a diff that is ``reversed''. To apply such
+patches, give @code{patch} the @samp{-R} or @samp{--reverse} option.
+@code{patch} then attempts to swap each hunk around before applying it.
+Rejects come out in the swapped format. The @samp{-R} option does not
+work with @code{ed} scripts because there is too little information in
+them to reconstruct the reverse operation.
+
+Often @code{patch} can guess that the patch is reversed. If the first
+hunk of a patch fails, @code{patch} reverses the hunk to see if it can
+apply it that way. If it can, @code{patch} asks you if you want to have
+the @samp{-R} option set; if it can't, @code{patch} continues to apply
+the patch normally. This method cannot detect a reversed patch if it is
+a normal diff and the first command is an append (which should have been
+a delete) since appends always succeed, because a null context matches
+anywhere. But most patches add or change lines rather than delete them,
+so most reversed normal diffs begin with a delete, which fails, and
+@code{patch} notices.
+
+If you apply a patch that you have already applied, @code{patch} thinks
+it is a reversed patch and offers to un-apply the patch. This could be
+construed as a feature. If you did this inadvertently and you don't
+want to un-apply the patch, just answer @samp{n} to this offer and to
+the subsequent ``apply anyway'' question---or type @kbd{C-c} to kill the
+@code{patch} process.
+
+@node Inexact, , Reversed Patches, Imperfect
+@subsection Helping @code{patch} Find Inexact Matches
+@cindex inexact patches
+@cindex fuzz factor when patching
+
+For context diffs, and to a lesser extent normal diffs, @code{patch} can
+detect when the line numbers mentioned in the patch are incorrect, and
+it attempts to find the correct place to apply each hunk of the patch.
+As a first guess, it takes the line number mentioned in the hunk, plus
+or minus any offset used in applying the previous hunk. If that is not
+the correct place, @code{patch} scans both forward and backward for a
+set of lines matching the context given in the hunk.
+
+First @code{patch} looks for a place where all lines of the context
+match. If it cannot find such a place, and it is reading a context or
+unified diff, and the maximum fuzz factor is set to 1 or more, then
+@code{patch} makes another scan, ignoring the first and last line of
+context. If that fails, and the maximum fuzz factor is set to 2 or
+more, it makes another scan, ignoring the first two and last two lines
+of context are ignored. It continues similarly if the maximum fuzz
+factor is larger.
+
+The @samp{-F @var{lines}} or @samp{--fuzz=@var{lines}} option sets the
+maximum fuzz factor to @var{lines}. This option only applies to context
+and unified diffs; it ignores up to @var{lines} lines while looking for
+the place to install a hunk. Note that a larger fuzz factor increases
+the odds of making a faulty patch. The default fuzz factor is 2; it may
+not be set to more than the number of lines of context in the diff,
+ordinarily 3.
+
+If @code{patch} cannot find a place to install a hunk of the patch, it
+writes the hunk out to a reject file (@pxref{Rejects}, for information
+on how reject files are named). It writes out rejected hunks in context
+format no matter what form the input patch is in. If the input is a
+normal or @code{ed} diff, many of the contexts are simply null. The
+line numbers on the hunks in the reject file may be different from those
+in the patch file: they show the approximate location where @code{patch}
+thinks the failed hunks belong in the new file rather than in the old
+one.
+
+As it completes each hunk, @code{patch} tells you whether the hunk
+succeeded or failed, and if it failed, on which line (in the new file)
+@code{patch} thinks the hunk should go. If this is different from the
+line number specified in the diff, it tells you the offset. A single
+large offset @emph{may} indicate that @code{patch} installed a hunk in
+the wrong place. @code{patch} also tells you if it used a fuzz factor
+to make the match, in which case you should also be slightly suspicious.
+
+@code{patch} cannot tell if the line numbers are off in an @code{ed}
+script, and can only detect wrong line numbers in a normal diff when it
+finds a change or delete command. It may have the same problem with a
+context diff using a fuzz factor equal to or greater than the number of
+lines of context shown in the diff (typically 3). In these cases, you
+should probably look at a context diff between your original and patched
+input files to see if the changes make sense. Compiling without errors
+is a pretty good indication that the patch worked, but not a guarantee.
+
+@code{patch} usually produces the correct results, even when it must
+make many guesses. However, the results are guaranteed only when
+the patch is applied to an exact copy of the file that the patch was
+generated from.
+
+@node Empty Files, Multiple Patches, Imperfect, Merging with patch
+@section Removing Empty Files
+@cindex empty files, removing
+@cindex removing empty files
+
+Sometimes when comparing two directories, the first directory contains a
+file that the second directory does not. If you give @code{diff} the
+@samp{-N} or @samp{--new-file} option, it outputs a diff that deletes
+the contents of this file. By default, @code{patch} leaves an empty
+file after applying such a diff. The @samp{-E} or
+@samp{--remove-empty-files} option to @code{patch} deletes output files
+that are empty after applying the diff.
+
+@node Multiple Patches, patch Messages, Empty Files, Merging with patch
+@section Multiple Patches in a File
+@cindex multiple patches
+
+If the patch file contains more than one patch, @code{patch} tries to
+apply each of them as if they came from separate patch files. This
+means that it determines the name of the file to patch for each patch,
+and that it examines the leading text before each patch for file names
+and prerequisite revision level (@pxref{Making Patches}, for more on
+that topic).
+
+For the second and subsequent patches in the patch file, you can give
+options and another original file name by separating their argument
+lists with a @samp{+}. However, the argument list for a second or
+subsequent patch may not specify a new patch file, since that does not
+make sense.
+
+For example, to tell @code{patch} to strip the first three slashes from
+the name of the first patch in the patch file and none from subsequent
+patches, and to use @file{code.c} as the first input file, you can use:
+
+@example
+patch -p3 code.c + -p0 < patchfile
+@end example
+
+The @samp{-S} or @samp{--skip} option ignores the current patch from the
+patch file, but continue looking for the next patch in the file. Thus,
+to ignore the first and third patches in the patch file, you can use:
+
+@example
+patch -S + + -S + < patch file
+@end example
+
+@node patch Messages, , Multiple Patches, Merging with patch
+@section Messages and Questions from @code{patch}
+@cindex @code{patch} messages and questions
+@cindex diagnostics from @code{patch}
+@cindex messages from @code{patch}
+
+@code{patch} can produce a variety of messages, especially if it has
+trouble decoding its input. In a few situations where it's not sure how
+to proceed, @code{patch} normally prompts you for more information from
+the keyboard. There are options to suppress printing non-fatal messages
+and stopping for keyboard input.
+
+The message @samp{Hmm...} indicates that @code{patch} is reading text in
+the patch file, attempting to determine whether there is a patch in that
+text, and if so, what kind of patch it is.
+
+You can inhibit all terminal output from @code{patch}, unless an error
+occurs, by using the @samp{-s}, @samp{--quiet}, or @samp{--silent}
+option.
+
+There are two ways you can prevent @code{patch} from asking you any
+questions. The @samp{-f} or @samp{--force} option assumes that you know
+what you are doing. It assumes the following:
+
+@itemize @bullet
+@item
+skip patches that do not contain file names in their headers;
+
+@item
+patch files even though they have the wrong version for the
+@samp{Prereq:} line in the patch;
+
+@item
+assume that patches are not reversed even if they look like they are.
+@end itemize
+
+The @samp{-t} or @samp{--batch} option is similar to @samp{-f}, in that
+it suppresses questions, but it makes somewhat different assumptions:
+
+@itemize @bullet
+@item
+skip patches that do not contain file names in their headers
+(the same as @samp{-f});
+
+@item
+skip patches for which the file has the wrong version for the
+@samp{Prereq:} line in the patch;
+
+@item
+assume that patches are reversed if they look like they are.
+@end itemize
+
+@code{patch} exits with a non-zero status if it creates any reject
+files. When applying a set of patches in a loop, you should check the
+exit status, so you don't apply a later patch to a partially patched
+file.
+
+@node Making Patches, Invoking cmp, Merging with patch, Top
+@chapter Tips for Making Patch Distributions
+@cindex patch making tips
+@cindex tips for patch making
+
+Here are some things you should keep in mind if you are going to
+distribute patches for updating a software package.
+
+Make sure you have specified the file names correctly, either in a
+context diff header or with an @samp{Index:} line. If you are patching
+files in a subdirectory, be sure to tell the patch user to specify a
+@samp{-p} or @samp{--strip} option as needed. Take care to not send out
+reversed patches, since these make people wonder whether they have
+already applied the patch.
+
+To save people from partially applying a patch before other patches that
+should have gone before it, you can make the first patch in the patch
+file update a file with a name like @file{patchlevel.h} or
+@file{version.c}, which contains a patch level or version number. If
+the input file contains the wrong version number, @code{patch} will
+complain immediately.
+
+An even clearer way to prevent this problem is to put a @samp{Prereq:}
+line before the patch. If the leading text in the patch file contains a
+line that starts with @samp{Prereq:}, @code{patch} takes the next word
+from that line (normally a version number) and checks whether the next
+input file contains that word, preceded and followed by either
+white space or a newline. If not, @code{patch} prompts you for
+confirmation before proceeding. This makes it difficult to accidentally
+apply patches in the wrong order.
+
+Since @code{patch} does not handle incomplete lines properly, make sure
+that all the source files in your program end with a newline whenever
+you release a version.
+
+To create a patch that changes an older version of a package into a
+newer version, first make a copy of the older version in a scratch
+directory. Typically you do that by unpacking a @code{tar} or
+@code{shar} archive of the older version.
+
+You might be able to reduce the size of the patch by renaming or
+removing some files before making the patch. If the older version of
+the package contains any files that the newer version does not, or if
+any files have been renamed between the two versions, make a list of
+@code{rm} and @code{mv} commands for the user to execute in the old
+version directory before applying the patch. Then run those commands
+yourself in the scratch directory.
+
+If there are any files that you don't need to include in the patch
+because they can easily be rebuilt from other files (for example,
+@file{TAGS} and output from @code{yacc} and @code{makeinfo}), replace
+the versions in the scratch directory with the newer versions, using
+@code{rm} and @code{ln} or @code{cp}.
+
+Now you can create the patch. The de-facto standard @code{diff} format
+for patch distributions is context format with two lines of context,
+produced by giving @code{diff} the @samp{-C 2} option. Do not use less
+than two lines of context, because @code{patch} typically needs at
+least two lines for proper operation. Give @code{diff} the @samp{-P}
+option in case the newer version of the package contains any files that
+the older one does not. Make sure to specify the scratch directory
+first and the newer directory second.
+
+Add to the top of the patch a note telling the user any @code{rm} and
+@code{mv} commands to run before applying the patch. Then you can
+remove the scratch directory.
+
+@node Invoking cmp, Invoking diff, Making Patches, Top
+@chapter Invoking @code{cmp}
+@cindex invoking @code{cmp}
+@cindex @code{cmp} invocation
+
+The @code{cmp} command compares two files, and if they differ, tells the
+first byte and line number where they differ. Its arguments are as
+follows:
+
+@example
+cmp @var{options}@dots{} @var{from-file} @r{[}@var{to-file}@var{]}
+@end example
+
+The file name @samp{-} is always the standard input. @code{cmp} also
+uses the standard input if one file name is omitted.
+
+An exit status of 0 means no differences were found, 1 means some
+differences were found, and 2 means trouble.
+
+@menu
+* cmp Options:: Summary of options to @code{cmp}.
+@end menu
+
+@node cmp Options, , , Invoking cmp
+@section Options to @code{cmp}
+@cindex @code{cmp} options
+@cindex options for @code{cmp}
+
+Below is a summary of all of the options that GNU @code{cmp} accepts.
+Most options have two equivalent names, one of which is a single letter
+preceded by @samp{-}, and the other of which is a long name preceded by
+@samp{--}. Multiple single letter options (unless they take an
+argument) can be combined into a single command line word: @samp{-cl} is
+equivalent to @samp{-c -l}.
+
+@table @samp
+@item -c
+Print the differing characters. Display control characters as a
+@samp{^} followed by a letter of the alphabet and precede characters
+that have the high bit set with @samp{M-} (which stands for ``meta'').
+
+@item --ignore-initial=@var{bytes}
+Ignore any differences in the the first @var{bytes} bytes of the input files.
+Treat files with fewer than @var{bytes} bytes as if they are empty.
+
+@item -l
+Print the (decimal) offsets and (octal) values of all differing bytes.
+
+@item --print-chars
+Print the differing characters. Display control characters as a
+@samp{^} followed by a letter of the alphabet and precede characters
+that have the high bit set with @samp{M-} (which stands for ``meta'').
+
+@item --quiet
+@itemx -s
+@itemx --silent
+Do not print anything; only return an exit status indicating whether
+the files differ.
+
+@item --verbose
+Print the (decimal) offsets and (octal) values of all differing bytes.
+
+@item -v
+@item --version
+Output the version number of @code{cmp}.
+@end table
+
+@node Invoking diff, Invoking diff3, Invoking cmp, Top
+@chapter Invoking @code{diff}
+@cindex invoking @code{diff}
+@cindex @code{diff} invocation
+
+The format for running the @code{diff} command is:
+
+@example
+diff @var{options}@dots{} @var{from-file} @var{to-file}
+@end example
+
+In the simplest case, @code{diff} compares the contents of the two files
+@var{from-file} and @var{to-file}. A file name of @samp{-} stands for
+text read from the standard input. As a special case, @samp{diff - -}
+compares a copy of standard input to itself.
+
+If @var{from-file} is a directory and @var{to-file} is not, @code{diff}
+compares the file in @var{from-file} whose file name is that of @var{to-file},
+and vice versa. The non-directory file must not be @samp{-}.
+
+If both @var{from-file} and @var{to-file} are directories,
+@code{diff} compares corresponding files in both directories, in
+alphabetical order; this comparison is not recursive unless the
+@samp{-r} or @samp{--recursive} option is given. @code{diff} never
+compares the actual contents of a directory as if it were a file. The
+file that is fully specified may not be standard input, because standard
+input is nameless and the notion of ``file with the same name'' does not
+apply.
+
+@code{diff} options begin with @samp{-}, so normally @var{from-file} and
+@var{to-file} may not begin with @samp{-}. However, @samp{--} as an
+argument by itself treats the remaining arguments as file names even if
+they begin with @samp{-}.
+
+An exit status of 0 means no differences were found, 1 means some
+differences were found, and 2 means trouble.
+
+@menu
+* diff Options:: Summary of options to @code{diff}.
+@end menu
+
+@node diff Options, , , Invoking diff
+@section Options to @code{diff}
+@cindex @code{diff} options
+@cindex options for @code{diff}
+
+Below is a summary of all of the options that GNU @code{diff} accepts.
+Most options have two equivalent names, one of which is a single letter
+preceded by @samp{-}, and the other of which is a long name preceded by
+@samp{--}. Multiple single letter options (unless they take an
+argument) can be combined into a single command line word: @samp{-ac} is
+equivalent to @samp{-a -c}. Long named options can be abbreviated to
+any unique prefix of their name. Brackets ([ and ]) indicate that an
+option takes an optional argument.
+
+@table @samp
+@item -@var{lines}
+Show @var{lines} (an integer) lines of context. This option does not
+specify an output format by itself; it has no effect unless it is
+combined with @samp{-c} (@pxref{Context Format}) or @samp{-u}
+(@pxref{Unified Format}). This option is obsolete. For proper
+operation, @code{patch} typically needs at least two lines of context.
+
+@item -a
+Treat all files as text and compare them line-by-line, even if they
+do not seem to be text. @xref{Binary}.
+
+@item -b
+Ignore changes in amount of white space. @xref{White Space}.
+
+@item -B
+Ignore changes that just insert or delete blank lines. @xref{Blank
+Lines}.
+
+@item --binary
+Read and write data in binary mode. @xref{Binary}.
+
+@item --brief
+Report only whether the files differ, not the details of the
+differences. @xref{Brief}.
+
+@item -c
+Use the context output format. @xref{Context Format}.
+
+@item -C @var{lines}
+@itemx --context@r{[}=@var{lines}@r{]}
+Use the context output format, showing @var{lines} (an integer) lines of
+context, or three if @var{lines} is not given. @xref{Context Format}.
+For proper operation, @code{patch} typically needs at least two lines of
+context.
+
+@item --changed-group-format=@var{format}
+Use @var{format} to output a line group containing differing lines from
+both files in if-then-else format. @xref{Line Group Formats}.
+
+@item -d
+Change the algorithm perhaps find a smaller set of changes. This makes
+@code{diff} slower (sometimes much slower). @xref{diff Performance}.
+
+@item -D @var{name}
+Make merged @samp{#ifdef} format output, conditional on the preprocessor
+macro @var{name}. @xref{If-then-else}.
+
+@item -e
+@itemx --ed
+Make output that is a valid @code{ed} script. @xref{ed Scripts}.
+
+@item --exclude=@var{pattern}
+When comparing directories, ignore files and subdirectories whose basenames
+match @var{pattern}. @xref{Comparing Directories}.
+
+@item --exclude-from=@var{file}
+When comparing directories, ignore files and subdirectories whose basenames
+match any pattern contained in @var{file}. @xref{Comparing Directories}.
+
+@item --expand-tabs
+Expand tabs to spaces in the output, to preserve the alignment of tabs
+in the input files. @xref{Tabs}.
+
+@item -f
+Make output that looks vaguely like an @code{ed} script but has changes
+in the order they appear in the file. @xref{Forward ed}.
+
+@item -F @var{regexp}
+In context and unified format, for each hunk of differences, show some
+of the last preceding line that matches @var{regexp}. @xref{Specified
+Headings}.
+
+@item --forward-ed
+Make output that looks vaguely like an @code{ed} script but has changes
+in the order they appear in the file. @xref{Forward ed}.
+
+@item -h
+This option currently has no effect; it is present for Unix
+compatibility.
+
+@item -H
+Use heuristics to speed handling of large files that have numerous
+scattered small changes. @xref{diff Performance}.
+
+@item --horizon-lines=@var{lines}
+Do not discard the last @var{lines} lines of the common prefix
+and the first @var{lines} lines of the common suffix.
+@xref{diff Performance}.
+
+@item -i
+Ignore changes in case; consider upper- and lower-case letters
+equivalent. @xref{Case Folding}.
+
+@item -I @var{regexp}
+Ignore changes that just insert or delete lines that match @var{regexp}.
+@xref{Specified Folding}.
+
+@item --ifdef=@var{name}
+Make merged if-then-else output using @var{name}. @xref{If-then-else}.
+
+@item --ignore-all-space
+Ignore white space when comparing lines. @xref{White Space}.
+
+@item --ignore-blank-lines
+Ignore changes that just insert or delete blank lines. @xref{Blank
+Lines}.
+
+@item --ignore-case
+Ignore changes in case; consider upper- and lower-case to be the same.
+@xref{Case Folding}.
+
+@item --ignore-matching-lines=@var{regexp}
+Ignore changes that just insert or delete lines that match @var{regexp}.
+@xref{Specified Folding}.
+
+@item --ignore-space-change
+Ignore changes in amount of white space.
+@xref{White Space}.
+
+@item --initial-tab
+Output a tab rather than a space before the text of a line in normal or
+context format. This causes the alignment of tabs in the line to look
+normal. @xref{Tabs}.
+
+@item -l
+Pass the output through @code{pr} to paginate it. @xref{Pagination}.
+
+@item -L @var{label}
+Use @var{label} instead of the file name in the context format
+(@pxref{Context Format}) and unified format (@pxref{Unified Format})
+headers. @xref{RCS}.
+
+@item --label=@var{label}
+Use @var{label} instead of the file name in the context format
+(@pxref{Context Format}) and unified format (@pxref{Unified Format})
+headers.
+
+@item --left-column
+Print only the left column of two common lines in side by side format.
+@xref{Side by Side Format}.
+
+@item --line-format=@var{format}
+Use @var{format} to output all input lines in if-then-else format.
+@xref{Line Formats}.
+
+@item --minimal
+Change the algorithm to perhaps find a smaller set of changes. This
+makes @code{diff} slower (sometimes much slower). @xref{diff
+Performance}.
+
+@item -n
+Output RCS-format diffs; like @samp{-f} except that each command
+specifies the number of lines affected. @xref{RCS}.
+
+@item -N
+@itemx --new-file
+In directory comparison, if a file is found in only one directory,
+treat it as present but empty in the other directory. @xref{Comparing
+Directories}.
+
+@item --new-group-format=@var{format}
+Use @var{format} to output a group of lines taken from just the second
+file in if-then-else format. @xref{Line Group Formats}.
+
+@item --new-line-format=@var{format}
+Use @var{format} to output a line taken from just the second file in
+if-then-else format. @xref{Line Formats}.
+
+@item --old-group-format=@var{format}
+Use @var{format} to output a group of lines taken from just the first
+file in if-then-else format. @xref{Line Group Formats}.
+
+@item --old-line-format=@var{format}
+Use @var{format} to output a line taken from just the first file in
+if-then-else format. @xref{Line Formats}.
+
+@item -p
+Show which C function each change is in. @xref{C Function Headings}.
+
+@item -P
+When comparing directories, if a file appears only in the second
+directory of the two, treat it as present but empty in the other.
+@xref{Comparing Directories}.
+
+@item --paginate
+Pass the output through @code{pr} to paginate it. @xref{Pagination}.
+
+@item -q
+Report only whether the files differ, not the details of the
+differences. @xref{Brief}.
+
+@item -r
+When comparing directories, recursively compare any subdirectories
+found. @xref{Comparing Directories}.
+
+@item --rcs
+Output RCS-format diffs; like @samp{-f} except that each command
+specifies the number of lines affected. @xref{RCS}.
+
+@item --recursive
+When comparing directories, recursively compare any subdirectories
+found. @xref{Comparing Directories}.
+
+@item --report-identical-files
+Report when two files are the same. @xref{Comparing Directories}.
+
+@item -s
+Report when two files are the same. @xref{Comparing Directories}.
+
+@item -S @var{file}
+When comparing directories, start with the file @var{file}. This is
+used for resuming an aborted comparison. @xref{Comparing Directories}.
+
+@item --sdiff-merge-assist
+Print extra information to help @code{sdiff}. @code{sdiff} uses this
+option when it runs @code{diff}. This option is not intended for users
+to use directly.
+
+@item --show-c-function
+Show which C function each change is in. @xref{C Function Headings}.
+
+@item --show-function-line=@var{regexp}
+In context and unified format, for each hunk of differences, show some
+of the last preceding line that matches @var{regexp}. @xref{Specified
+Headings}.
+
+@item --side-by-side
+Use the side by side output format. @xref{Side by Side Format}.
+
+@item --speed-large-files
+Use heuristics to speed handling of large files that have numerous
+scattered small changes. @xref{diff Performance}.
+
+@item --starting-file=@var{file}
+When comparing directories, start with the file @var{file}. This is
+used for resuming an aborted comparison. @xref{Comparing Directories}.
+
+@item --suppress-common-lines
+Do not print common lines in side by side format.
+@xref{Side by Side Format}.
+
+@item -t
+Expand tabs to spaces in the output, to preserve the alignment of tabs
+in the input files. @xref{Tabs}.
+
+@item -T
+Output a tab rather than a space before the text of a line in normal or
+context format. This causes the alignment of tabs in the line to look
+normal. @xref{Tabs}.
+
+@item --text
+Treat all files as text and compare them line-by-line, even if they
+do not appear to be text. @xref{Binary}.
+
+@item -u
+Use the unified output format. @xref{Unified Format}.
+
+@item --unchanged-group-format=@var{format}
+Use @var{format} to output a group of common lines taken from both files
+in if-then-else format. @xref{Line Group Formats}.
+
+@item --unchanged-line-format=@var{format}
+Use @var{format} to output a line common to both files in if-then-else
+format. @xref{Line Formats}.
+
+@item --unidirectional-new-file
+When comparing directories, if a file appears only in the second
+directory of the two, treat it as present but empty in the other.
+@xref{Comparing Directories}.
+
+@item -U @var{lines}
+@itemx --unified@r{[}=@var{lines}@r{]}
+Use the unified output format, showing @var{lines} (an integer) lines of
+context, or three if @var{lines} is not given. @xref{Unified Format}.
+For proper operation, @code{patch} typically needs at least two lines of
+context.
+
+@item -v
+@itemx --version
+Output the version number of @code{diff}.
+
+@item -w
+Ignore white space when comparing lines. @xref{White Space}.
+
+@item -W @var{columns}
+@itemx --width=@var{columns}
+Use an output width of @var{columns} in side by side format.
+@xref{Side by Side Format}.
+
+@item -x @var{pattern}
+When comparing directories, ignore files and subdirectories whose basenames
+match @var{pattern}. @xref{Comparing Directories}.
+
+@item -X @var{file}
+When comparing directories, ignore files and subdirectories whose basenames
+match any pattern contained in @var{file}. @xref{Comparing Directories}.
+
+@item -y
+Use the side by side output format. @xref{Side by Side Format}.
+@end table
+
+@node Invoking diff3, Invoking patch, Invoking diff, Top
+@chapter Invoking @code{diff3}
+@cindex invoking @code{diff3}
+@cindex @code{diff3} invocation
+
+The @code{diff3} command compares three files and outputs descriptions
+of their differences. Its arguments are as follows:
+
+@example
+diff3 @var{options}@dots{} @var{mine} @var{older} @var{yours}
+@end example
+
+The files to compare are @var{mine}, @var{older}, and @var{yours}.
+At most one of these three file names may be @samp{-},
+which tells @code{diff3} to read the standard input for that file.
+
+An exit status of 0 means @code{diff3} was successful, 1 means some
+conflicts were found, and 2 means trouble.
+
+@menu
+* diff3 Options:: Summary of options to @code{diff3}.
+@end menu
+
+@node diff3 Options, , , Invoking diff3
+@section Options to @code{diff3}
+@cindex @code{diff3} options
+@cindex options for @code{diff3}
+
+Below is a summary of all of the options that GNU @code{diff3}
+accepts. Multiple single letter options (unless they take an argument)
+can be combined into a single command line argument.
+
+@table @samp
+@item -a
+Treat all files as text and compare them line-by-line, even if they
+do not appear to be text. @xref{Binary}.
+
+@item -A
+Incorporate all changes from @var{older} to @var{yours} into @var{mine},
+surrounding all conflicts with bracket lines.
+@xref{Marking Conflicts}.
+
+@item -e
+Generate an @code{ed} script that incorporates all the changes from
+@var{older} to @var{yours} into @var{mine}. @xref{Which Changes}.
+
+@item -E
+Like @samp{-e}, except bracket lines from overlapping changes' first
+and third files.
+@xref{Marking Conflicts}.
+With @samp{-e}, an overlapping change looks like this:
+
+@example
+<<<<<<< @var{mine}
+@r{lines from @var{mine}}
+=======
+@r{lines from @var{yours}}
+>>>>>>> @var{yours}
+@end example
+
+@item --ed
+Generate an @code{ed} script that incorporates all the changes from
+@var{older} to @var{yours} into @var{mine}. @xref{Which Changes}.
+
+@item --easy-only
+Like @samp{-e}, except output only the nonoverlapping changes.
+@xref{Which Changes}.
+
+@item -i
+Generate @samp{w} and @samp{q} commands at the end of the @code{ed}
+script for System V compatibility. This option must be combined with
+one of the @samp{-AeExX3} options, and may not be combined with @samp{-m}.
+@xref{Saving the Changed File}.
+
+@item --initial-tab
+Output a tab rather than two spaces before the text of a line in normal format.
+This causes the alignment of tabs in the line to look normal. @xref{Tabs}.
+
+@item -L @var{label}
+@itemx --label=@var{label}
+Use the label @var{label} for the brackets output by the @samp{-A},
+@samp{-E} and @samp{-X} options. This option may be given up to three
+times, one for each input file. The default labels are the names of
+the input files. Thus @samp{diff3 -L X -L Y -L Z -m A B C} acts like
+@samp{diff3 -m A B C}, except that the output looks like it came from
+files named @samp{X}, @samp{Y} and @samp{Z} rather than from files
+named @samp{A}, @samp{B} and @samp{C}. @xref{Marking Conflicts}.
+
+@item -m
+@itemx --merge
+Apply the edit script to the first file and send the result to standard
+output. Unlike piping the output from @code{diff3} to @code{ed}, this
+works even for binary files and incomplete lines. @samp{-A} is assumed
+if no edit script option is specified. @xref{Bypassing ed}.
+
+@item --overlap-only
+Like @samp{-e}, except output only the overlapping changes.
+@xref{Which Changes}.
+
+@item --show-all
+Incorporate all unmerged changes from @var{older} to @var{yours} into
+@var{mine}, surrounding all overlapping changes with bracket lines.
+@xref{Marking Conflicts}.
+
+@item --show-overlap
+Like @samp{-e}, except bracket lines from overlapping changes' first
+and third files.
+@xref{Marking Conflicts}.
+
+@item -T
+Output a tab rather than two spaces before the text of a line in normal format.
+This causes the alignment of tabs in the line to look normal. @xref{Tabs}.
+
+@item --text
+Treat all files as text and compare them line-by-line, even if they
+do not appear to be text. @xref{Binary}.
+
+@item -v
+@itemx --version
+Output the version number of @code{diff3}.
+
+@item -x
+Like @samp{-e}, except output only the overlapping changes.
+@xref{Which Changes}.
+
+@item -X
+Like @samp{-E}, except output only the overlapping changes.
+In other words, like @samp{-x}, except bracket changes as in @samp{-E}.
+@xref{Marking Conflicts}.
+
+@item -3
+Like @samp{-e}, except output only the nonoverlapping changes.
+@xref{Which Changes}.
+@end table
+
+@node Invoking patch, Invoking sdiff, Invoking diff3, Top
+@chapter Invoking @code{patch}
+@cindex invoking @code{patch}
+@cindex @code{patch} invocation
+
+Normally @code{patch} is invoked like this:
+
+@example
+patch <@var{patchfile}
+@end example
+
+The full format for invoking @code{patch} is:
+
+@example
+patch @var{options}@dots{} @r{[}@var{origfile} @r{[}@var{patchfile}@r{]}@r{]} @r{[}+ @var{options}@dots{} @r{[}@var{origfile}@r{]}@r{]}@dots{}
+@end example
+
+If you do not specify @var{patchfile}, or if @var{patchfile} is
+@samp{-}, @code{patch} reads the patch (that is, the @code{diff} output)
+from the standard input.
+
+You can specify one or more of the original files as @var{orig} arguments;
+each one and options for interpreting it is separated from the others with a
+@samp{+}. @xref{Multiple Patches}, for more information.
+
+If you do not specify an input file on the command line, @code{patch}
+tries to figure out from the @dfn{leading text} (any text in the patch
+that comes before the @code{diff} output) which file to edit. In the
+header of a context or unified diff, @code{patch} looks in lines
+beginning with @samp{***}, @samp{---}, or @samp{+++}; among those, it
+chooses the shortest name of an existing file. Otherwise, if there is
+an @samp{Index:} line in the leading text, @code{patch} tries to use the
+file name from that line. If @code{patch} cannot figure out the name of
+an existing file from the leading text, it prompts you for the name of
+the file to patch.
+
+If the input file does not exist or is read-only, and a suitable RCS or
+SCCS file exists, @code{patch} attempts to check out or get the file
+before proceeding.
+
+By default, @code{patch} replaces the original input file with the
+patched version, after renaming the original file into a backup file
+(@pxref{Backups}, for a description of how @code{patch} names backup
+files). You can also specify where to put the output with the @samp{-o
+@var{output-file}} or @samp{--output=@var{output-file}} option.
+
+@menu
+* patch Directories:: Changing directory and stripping directories.
+* Backups:: Backup file names.
+* Rejects:: Reject file names.
+* patch Options:: Summary table of options to @code{patch}.
+@end menu
+
+@node patch Directories, Backups, , Invoking patch
+@section Applying Patches in Other Directories
+@cindex directories and patch
+@cindex patching directories
+
+The @samp{-d @var{directory}} or @samp{--directory=@var{directory}}
+option to @code{patch} makes directory @var{directory} the current
+directory for interpreting both file names in the patch file, and file
+names given as arguments to other options (such as @samp{-B} and
+@samp{-o}). For example, while in a news reading program, you can patch
+a file in the @file{/usr/src/emacs} directory directly from the article
+containing the patch like this:
+
+@example
+| patch -d /usr/src/emacs
+@end example
+
+Sometimes the file names given in a patch contain leading directories,
+but you keep your files in a directory different from the one given in
+the patch. In those cases, you can use the
+@samp{-p@r{[}@var{number}@r{]}} or @samp{--strip@r{[}=@var{number}@r{]}}
+option to set the file name strip count to @var{number}. The strip
+count tells @code{patch} how many slashes, along with the directory
+names between them, to strip from the front of file names. @samp{-p}
+with no @var{number} given is equivalent to @samp{-p0}. By default,
+@code{patch} strips off all leading directories, leaving just the base file
+names, except that when a file name given in the patch is a relative
+file name and all of its leading directories already exist, @code{patch} does
+not strip off the leading directory. (A @dfn{relative} file name is one
+that does not start with a slash.)
+
+@code{patch} looks for each file (after any slashes have been stripped)
+in the current directory, or if you used the @samp{-d @var{directory}}
+option, in that directory.
+
+For example, suppose the file name in the patch file is
+@file{/gnu/src/emacs/etc/NEWS}. Using @samp{-p} or @samp{-p0} gives the
+entire file name unmodified, @samp{-p1} gives
+@file{gnu/src/emacs/etc/NEWS} (no leading slash), @samp{-p4} gives
+@file{etc/NEWS}, and not specifying @samp{-p} at all gives @file{NEWS}.
+
+@node Backups, Rejects, patch Directories, Invoking patch
+@section Backup File Names
+@cindex backup file names
+
+Normally, @code{patch} renames an original input file into a backup file
+by appending to its name the extension @samp{.orig}, or @samp{~} on
+systems that do not support long file names. The @samp{-b
+@var{backup-suffix}} or @samp{--suffix=@var{backup-suffix}} option uses
+@var{backup-suffix} as the backup extension instead.
+
+Alternately, you can specify the extension for backup files with the
+@code{SIMPLE_BACKUP_SUFFIX} environment variable, which the options
+override.
+
+@code{patch} can also create numbered backup files the way GNU Emacs
+does. With this method, instead of having a single backup of each file,
+@code{patch} makes a new backup file name each time it patches a file.
+For example, the backups of a file named @file{sink} would be called,
+successively, @file{sink.~1~}, @file{sink.~2~}, @file{sink.~3~}, etc.
+
+The @samp{-V @var{backup-style}} or
+@samp{--version-control=@var{backup-style}} option takes as an argument
+a method for creating backup file names. You can alternately control
+the type of backups that @code{patch} makes with the
+@code{VERSION_CONTROL} environment variable, which the @samp{-V} option
+overrides. The value of the @code{VERSION_CONTROL} environment variable
+and the argument to the @samp{-V} option are like the GNU Emacs
+@code{version-control} variable (@pxref{Backups,
+emacs, The GNU Emacs Manual}, for more information on backup versions in
+Emacs). They also recognize synonyms that are more descriptive. The
+valid values are listed below; unique abbreviations are acceptable.
+
+@table @samp
+@item t
+@itemx numbered
+Always make numbered backups.
+
+@item nil
+@itemx existing
+Make numbered backups of files that already have them, simple backups of
+the others. This is the default.
+
+@item never
+@itemx simple
+Always make simple backups.
+@end table
+
+Alternately, you can tell @code{patch} to prepend a prefix, such as a
+directory name, to produce backup file names. The @samp{-B
+@var{backup-prefix}} or @samp{--prefix=@var{backup-prefix}} option makes
+backup files by prepending @var{backup-prefix} to them. If you use this
+option, @code{patch} ignores any @samp{-b} option that you give.
+
+If the backup file already exists, @code{patch} creates a new backup
+file name by changing the first lowercase letter in the last component
+of the file name into uppercase. If there are no more lowercase letters
+in the name, it removes the first character from the name. It repeats
+this process until it comes up with a backup file name that does not
+already exist.
+
+If you specify the output file with the @samp{-o} option, that file is
+the one that is backed up, not the input file.
+
+@node Rejects, patch Options, Backups, Invoking patch
+@section Reject File Names
+@cindex reject file names
+
+The names for reject files (files containing patches that @code{patch}
+could not find a place to apply) are normally the name of the output
+file with @samp{.rej} appended (or @samp{#} on systems that do not
+support long file names).
+
+Alternatively, you can tell @code{patch} to place all of the rejected
+patches in a single file. The @samp{-r @var{reject-file}} or
+@samp{--reject-file=@var{reject-file}} option uses @var{reject-file} as
+the reject file name.
+
+@node patch Options, , Rejects, Invoking patch
+@section Options to @code{patch}
+@cindex @code{patch} options
+@cindex options for @code{patch}
+
+Here is a summary of all of the options that @code{patch} accepts.
+Older versions of @code{patch} do not accept long-named options or the
+@samp{-t}, @samp{-E}, or @samp{-V} options.
+
+Multiple single-letter options that do not take an argument can be
+combined into a single command line argument (with only one dash).
+Brackets ([ and ]) indicate that an option takes an optional argument.
+
+@table @samp
+@item -b @var{backup-suffix}
+Use @var{backup-suffix} as the backup extension instead of
+@samp{.orig} or @samp{~}. @xref{Backups}.
+
+@item -B @var{backup-prefix}
+Use @var{backup-prefix} as a prefix to the backup file name. If this
+option is specified, any @samp{-b} option is ignored. @xref{Backups}.
+
+@item --batch
+Do not ask any questions. @xref{patch Messages}.
+
+@item -c
+@itemx --context
+Interpret the patch file as a context diff. @xref{patch Input}.
+
+@item -d @var{directory}
+@itemx --directory=@var{directory}
+Makes directory @var{directory} the current directory for interpreting
+both file names in the patch file, and file names given as arguments to
+other options. @xref{patch Directories}.
+
+@item -D @var{name}
+Make merged if-then-else output using @var{format}. @xref{If-then-else}.
+
+@item --debug=@var{number}
+Set internal debugging flags. Of interest only to @code{patch}
+patchers.
+
+@item -e
+@itemx --ed
+Interpret the patch file as an @code{ed} script. @xref{patch Input}.
+
+@item -E
+Remove output files that are empty after the patches have been applied.
+@xref{Empty Files}.
+
+@item -f
+Assume that the user knows exactly what he or she is doing, and do not
+ask any questions. @xref{patch Messages}.
+
+@item -F @var{lines}
+Set the maximum fuzz factor to @var{lines}. @xref{Inexact}.
+
+@item --force
+Assume that the user knows exactly what he or she is doing, and do not
+ask any questions. @xref{patch Messages}.
+
+@item --forward
+Ignore patches that @code{patch} thinks are reversed or already applied.
+See also @samp{-R}. @xref{Reversed Patches}.
+
+@item --fuzz=@var{lines}
+Set the maximum fuzz factor to @var{lines}. @xref{Inexact}.
+
+@item --help
+Print a summary of the options that @code{patch} recognizes, then exit.
+
+@item --ifdef=@var{name}
+Make merged if-then-else output using @var{format}. @xref{If-then-else}.
+
+@item --ignore-white-space
+@itemx -l
+Let any sequence of white space in the patch file match any sequence of
+white space in the input file. @xref{Changed White Space}.
+
+@item -n
+@itemx --normal
+Interpret the patch file as a normal diff. @xref{patch Input}.
+
+@item -N
+Ignore patches that @code{patch} thinks are reversed or already applied.
+See also @samp{-R}. @xref{Reversed Patches}.
+
+@item -o @var{output-file}
+@itemx --output=@var{output-file}
+Use @var{output-file} as the output file name. @xref{patch Options}.
+
+@item -p@r{[}@var{number}@r{]}
+Set the file name strip count to @var{number}. @xref{patch Directories}.
+
+@item --prefix=@var{backup-prefix}
+Use @var{backup-prefix} as a prefix to the backup file name. If this
+option is specified, any @samp{-b} option is ignored. @xref{Backups}.
+
+@item --quiet
+Work silently unless an error occurs. @xref{patch Messages}.
+
+@item -r @var{reject-file}
+Use @var{reject-file} as the reject file name. @xref{Rejects}.
+
+@item -R
+Assume that this patch was created with the old and new files swapped.
+@xref{Reversed Patches}.
+
+@item --reject-file=@var{reject-file}
+Use @var{reject-file} as the reject file name. @xref{Rejects}.
+
+@item --remove-empty-files
+Remove output files that are empty after the patches have been applied.
+@xref{Empty Files}.
+
+@item --reverse
+Assume that this patch was created with the old and new files swapped.
+@xref{Reversed Patches}.
+
+@item -s
+Work silently unless an error occurs. @xref{patch Messages}.
+
+@item -S
+Ignore this patch from the patch file, but continue looking for the next
+patch in the file. @xref{Multiple Patches}.
+
+@item --silent
+Work silently unless an error occurs. @xref{patch Messages}.
+
+@item --skip
+Ignore this patch from the patch file, but continue looking for the next
+patch in the file. @xref{Multiple Patches}.
+
+@item --strip@r{[}=@var{number}@r{]}
+Set the file name strip count to @var{number}. @xref{patch Directories}.
+
+@item --suffix=@var{backup-suffix}
+Use @var{backup-suffix} as the backup extension instead of
+@samp{.orig} or @samp{~}. @xref{Backups}.
+
+@item -t
+Do not ask any questions. @xref{patch Messages}.
+
+@item -u
+@itemx --unified
+Interpret the patch file as a unified diff. @xref{patch Input}.
+
+@item -v
+Output the revision header and patch level of @code{patch}.
+
+@item -V @var{backup-style}
+Select the kind of backups to make. @xref{Backups}.
+
+@item --version
+Output the revision header and patch level of @code{patch}, then exit.
+
+@item --version=control=@var{backup-style}
+Select the kind of backups to make. @xref{Backups}.
+
+@item -x @var{number}
+Set internal debugging flags. Of interest only to @code{patch}
+patchers.
+@end table
+
+@node Invoking sdiff, Incomplete Lines, Invoking patch, Top
+@chapter Invoking @code{sdiff}
+@cindex invoking @code{sdiff}
+@cindex @code{sdiff} invocation
+
+The @code{sdiff} command merges two files and interactively outputs the
+results. Its arguments are as follows:
+
+@example
+sdiff -o @var{outfile} @var{options}@dots{} @var{from-file} @var{to-file}
+@end example
+
+This merges @var{from-file} with @var{to-file}, with output to @var{outfile}.
+If @var{from-file} is a directory and @var{to-file} is not, @code{sdiff}
+compares the file in @var{from-file} whose file name is that of @var{to-file},
+and vice versa. @var{from-file} and @var{to-file} may not both be
+directories.
+
+@code{sdiff} options begin with @samp{-}, so normally @var{from-file}
+and @var{to-file} may not begin with @samp{-}. However, @samp{--} as an
+argument by itself treats the remaining arguments as file names even if
+they begin with @samp{-}. You may not use @samp{-} as an input file.
+
+An exit status of 0 means no differences were found, 1 means some
+differences were found, and 2 means trouble.
+
+@code{sdiff} without @samp{-o} (or @samp{--output}) produces a
+side-by-side difference. This usage is obsolete; use @samp{diff
+--side-by-side} instead.
+
+@menu
+* sdiff Options:: Summary of options to @code{diff}.
+@end menu
+
+@node sdiff Options, , , Invoking sdiff
+@section Options to @code{sdiff}
+@cindex @code{sdiff} options
+@cindex options for @code{sdiff}
+
+Below is a summary of all of the options that GNU @code{sdiff} accepts.
+Each option has two equivalent names, one of which is a single
+letter preceded by @samp{-}, and the other of which is a long name
+preceded by @samp{--}. Multiple single letter options (unless they take
+an argument) can be combined into a single command line argument. Long
+named options can be abbreviated to any unique prefix of their name.
+
+@table @samp
+@item -a
+Treat all files as text and compare them line-by-line, even if they
+do not appear to be text. @xref{Binary}.
+
+@item -b
+Ignore changes in amount of white space. @xref{White Space}.
+
+@item -B
+Ignore changes that just insert or delete blank lines. @xref{Blank
+Lines}.
+
+@item -d
+Change the algorithm to perhaps find a smaller set of changes. This
+makes @code{sdiff} slower (sometimes much slower). @xref{diff
+Performance}.
+
+@item -H
+Use heuristics to speed handling of large files that have numerous
+scattered small changes. @xref{diff Performance}.
+
+@item --expand-tabs
+Expand tabs to spaces in the output, to preserve the alignment of tabs
+in the input files. @xref{Tabs}.
+
+@item -i
+Ignore changes in case; consider upper- and lower-case to be the same.
+@xref{Case Folding}.
+
+@item -I @var{regexp}
+Ignore changes that just insert or delete lines that match @var{regexp}.
+@xref{Specified Folding}.
+
+@item --ignore-all-space
+Ignore white space when comparing lines. @xref{White Space}.
+
+@item --ignore-blank-lines
+Ignore changes that just insert or delete blank lines. @xref{Blank
+Lines}.
+
+@item --ignore-case
+Ignore changes in case; consider upper- and lower-case to be the same.
+@xref{Case Folding}.
+
+@item --ignore-matching-lines=@var{regexp}
+Ignore changes that just insert or delete lines that match @var{regexp}.
+@xref{Specified Folding}.
+
+@item --ignore-space-change
+Ignore changes in amount of white space.
+@xref{White Space}.
+
+@item -l
+@itemx --left-column
+Print only the left column of two common lines.
+@xref{Side by Side Format}.
+
+@item --minimal
+Change the algorithm to perhaps find a smaller set of changes. This
+makes @code{sdiff} slower (sometimes much slower). @xref{diff
+Performance}.
+
+@item -o @var{file}
+@itemx --output=@var{file}
+Put merged output into @var{file}. This option is required for merging.
+
+@item -s
+@itemx --suppress-common-lines
+Do not print common lines. @xref{Side by Side Format}.
+
+@item --speed-large-files
+Use heuristics to speed handling of large files that have numerous
+scattered small changes. @xref{diff Performance}.
+
+@item -t
+Expand tabs to spaces in the output, to preserve the alignment of tabs
+in the input files. @xref{Tabs}.
+
+@item --text
+Treat all files as text and compare them line-by-line, even if they
+do not appear to be text. @xref{Binary}.
+
+@item -v
+@itemx --version
+Output the version number of @code{sdiff}.
+
+@item -w @var{columns}
+@itemx --width=@var{columns}
+Use an output width of @var{columns}. @xref{Side by Side Format}.
+Note that for historical reasons, this option is @samp{-W} in @code{diff},
+@samp{-w} in @code{sdiff}.
+
+@item -W
+Ignore horizontal white space when comparing lines. @xref{White Space}.
+Note that for historical reasons, this option is @samp{-w} in @code{diff},
+@samp{-W} in @code{sdiff}.
+@end table
+
+@node Incomplete Lines, Projects, Invoking sdiff, Top
+@chapter Incomplete Lines
+@cindex incomplete lines
+@cindex full lines
+@cindex newline treatment by @code{diff}
+
+When an input file ends in a non-newline character, its last line is
+called an @dfn{incomplete line} because its last character is not a
+newline. All other lines are called @dfn{full lines} and end in a
+newline character. Incomplete lines do not match full lines unless
+differences in white space are ignored (@pxref{White Space}).
+
+An incomplete line is normally distinguished on output from a full line
+by a following line that starts with @samp{\}. However, the RCS format
+(@pxref{RCS}) outputs the incomplete line as-is, without any trailing
+newline or following line. The side by side format normally represents
+incomplete lines as-is, but in some cases uses a @samp{\} or @samp{/}
+gutter marker; @xref{Side by Side}. The if-then-else line format
+preserves a line's incompleteness with @samp{%L}, and discards the
+newline with @samp{%l}; @xref{Line Formats}. Finally, with the
+@code{ed} and forward @code{ed} output formats (@pxref{Output Formats})
+@code{diff} cannot represent an incomplete line, so it pretends there
+was a newline and reports an error.
+
+For example, suppose @file{F} and @file{G} are one-byte files that
+contain just @samp{f} and @samp{g}, respectively. Then @samp{diff F G}
+outputs
+
+@example
+1c1
+< f
+\ No newline at end of file
+---
+> g
+\ No newline at end of file
+@end example
+
+@noindent
+(The exact message may differ in non-English locales.)
+@samp{diff -n F G} outputs the following without a trailing newline:
+
+@example
+d1 1
+a1 1
+g
+@end example
+
+@samp{diff -e F G} reports two errors and outputs the following:
+
+@example
+1c
+g
+.
+@end example
+
+@node Projects, Concept Index, Incomplete Lines, Top
+@chapter Future Projects
+
+Here are some ideas for improving GNU @code{diff} and @code{patch}. The
+GNU project has identified some improvements as potential programming
+projects for volunteers. You can also help by reporting any bugs that
+you find.
+
+If you are a programmer and would like to contribute something to the
+GNU project, please consider volunteering for one of these projects. If
+you are seriously contemplating work, please write to
+@samp{gnu@@prep.ai.mit.edu} to coordinate with other volunteers.
+
+@menu
+* Shortcomings:: Suggested projects for improvements.
+* Bugs:: Reporting bugs.
+@end menu
+
+@node Shortcomings, Bugs, , Projects
+@section Suggested Projects for Improving GNU @code{diff} and @code{patch}
+@cindex projects for directories
+
+One should be able to use GNU @code{diff} to generate a patch from any
+pair of directory trees, and given the patch and a copy of one such
+tree, use @code{patch} to generate a faithful copy of the other.
+Unfortunately, some changes to directory trees cannot be expressed using
+current patch formats; also, @code{patch} does not handle some of the
+existing formats. These shortcomings motivate the following suggested
+projects.
+
+@menu
+* Changing Structure:: Handling changes to the directory structure.
+* Special Files:: Handling symbolic links, device special files, etc.
+* Unusual File Names:: Handling file names that contain unusual characters.
+* Arbitrary Limits:: Patching non-text files.
+* Large Files:: Handling files that do not fit in memory.
+* Ignoring Changes:: Ignoring certain changes while showing others.
+@end menu
+
+@node Changing Structure, Special Files, , Shortcomings
+@subsection Handling Changes to the Directory Structure
+@cindex directory structure changes
+
+@code{diff} and @code{patch} do not handle some changes to directory
+structure. For example, suppose one directory tree contains a directory
+named @samp{D} with some subsidiary files, and another contains a file
+with the same name @samp{D}. @samp{diff -r} does not output enough
+information for @code{patch} to transform the the directory subtree into
+the file.
+
+There should be a way to specify that a file has been deleted without
+having to include its entire contents in the patch file. There should
+also be a way to tell @code{patch} that a file was renamed, even if
+there is no way for @code{diff} to generate such information.
+
+These problems can be fixed by extending the @code{diff} output format
+to represent changes in directory structure, and extending @code{patch}
+to understand these extensions.
+
+@node Special Files, Unusual File Names, Changing Structure, Shortcomings
+@subsection Files that are Neither Directories Nor Regular Files
+@cindex special files
+
+Some files are neither directories nor regular files: they are unusual
+files like symbolic links, device special files, named pipes, and
+sockets. Currently, @code{diff} treats symbolic links like regular files;
+it treats other special files like regular files if they are specified
+at the top level, but simply reports their presence when comparing
+directories. This means that @code{patch} cannot represent changes
+to such files. For example, if you change which file a symbolic link
+points to, @code{diff} outputs the difference between the two files,
+instead of the change to the symbolic link.
+
+@c This might not be a good idea; is it wise for root to install devices
+@c this way?
+@code{diff} should optionally report changes to special files specially,
+and @code{patch} should be extended to understand these extensions.
+
+@node Unusual File Names, Arbitrary Limits, Special Files, Shortcomings
+@subsection File Names that Contain Unusual Characters
+@cindex file names with unusual characters
+
+When a file name contains an unusual character like a newline or
+white space, @samp{diff -r} generates a patch that @code{patch} cannot
+parse. The problem is with format of @code{diff} output, not just with
+@code{patch}, because with odd enough file names one can cause
+@code{diff} to generate a patch that is syntactically correct but
+patches the wrong files. The format of @code{diff} output should be
+extended to handle all possible file names.
+
+@node Arbitrary Limits, Large Files, Unusual File Names, Shortcomings
+@subsection Arbitrary Limits
+@cindex binary file patching
+
+GNU @code{diff} can analyze files with arbitrarily long lines and files
+that end in incomplete lines. However, @code{patch} cannot patch such
+files. The @code{patch} internal limits on line lengths should be
+removed, and @code{patch} should be extended to parse @code{diff}
+reports of incomplete lines.
+
+@node Large Files, Ignoring Changes, Arbitrary Limits, Shortcomings
+@subsection Handling Files that Do Not Fit in Memory
+@cindex large files
+
+@code{diff} operates by reading both files into memory. This method
+fails if the files are too large, and @code{diff} should have a fallback.
+
+One way to do this is to scan the files sequentially to compute hash
+codes of the lines and put the lines in equivalence classes based only
+on hash code. Then compare the files normally. This does produce some
+false matches.
+
+Then scan the two files sequentially again, checking each match to see
+whether it is real. When a match is not real, mark both the
+``matching'' lines as changed. Then build an edit script as usual.
+
+The output routines would have to be changed to scan the files
+sequentially looking for the text to print.
+
+@node Ignoring Changes,, Large Files, Shortcomings
+@subsection Ignoring Certain Changes
+
+It would be nice to have a feature for specifying two strings, one in
+@var{from-file} and one in @var{to-file}, which should be considered to
+match. Thus, if the two strings are @samp{foo} and @samp{bar}, then if
+two lines differ only in that @samp{foo} in file 1 corresponds to
+@samp{bar} in file 2, the lines are treated as identical.
+
+It is not clear how general this feature can or should be, or
+what syntax should be used for it.
+
+@node Bugs, , Shortcomings, Projects
+@section Reporting Bugs
+@cindex bug reports
+@cindex reporting bugs
+
+If you think you have found a bug in GNU @code{cmp}, @code{diff},
+@code{diff3}, @code{sdiff}, or @code{patch}, please report it by
+electronic mail to @samp{bug-gnu-utils@@prep.ai.mit.edu}. Send as
+precise a description of the problem as you can, including sample input
+files that produce the bug, if applicable.
+
+Because Larry Wall has not released a new version of @code{patch} since
+mid 1988 and the GNU version of @code{patch} has been changed since
+then, please send bug reports for @code{patch} by electronic mail to
+both @samp{bug-gnu-utils@@prep.ai.mit.edu} and
+@samp{lwall@@netlabs.com}.
+
+@node Concept Index, , Projects, Top
+@unnumbered Concept Index
+
+@printindex cp
+
+@shortcontents
+@contents
+@bye
diff --git a/gnu/usr.bin/diff/diff3.c b/gnu/usr.bin/diff/diff3.c
new file mode 100644
index 0000000..5d94ab8
--- /dev/null
+++ b/gnu/usr.bin/diff/diff3.c
@@ -0,0 +1,1778 @@
+/* Three way file comparison program (diff3) for Project GNU.
+ Copyright (C) 1988, 1989, 1992, 1993, 1994 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* Written by Randy Smith */
+
+#include "system.h"
+#include <stdio.h>
+#include <signal.h>
+#include "getopt.h"
+
+extern char const version_string[];
+
+/*
+ * Internal data structures and macros for the diff3 program; includes
+ * data structures for both diff3 diffs and normal diffs.
+ */
+
+/* Different files within a three way diff. */
+#define FILE0 0
+#define FILE1 1
+#define FILE2 2
+
+/*
+ * A three way diff is built from two two-way diffs; the file which
+ * the two two-way diffs share is:
+ */
+#define FILEC FILE2
+
+/*
+ * Different files within a two way diff.
+ * FC is the common file, FO the other file.
+ */
+#define FO 0
+#define FC 1
+
+/* The ranges are indexed by */
+#define START 0
+#define END 1
+
+enum diff_type {
+ ERROR, /* Should not be used */
+ ADD, /* Two way diff add */
+ CHANGE, /* Two way diff change */
+ DELETE, /* Two way diff delete */
+ DIFF_ALL, /* All three are different */
+ DIFF_1ST, /* Only the first is different */
+ DIFF_2ND, /* Only the second */
+ DIFF_3RD /* Only the third */
+};
+
+/* Two way diff */
+struct diff_block {
+ int ranges[2][2]; /* Ranges are inclusive */
+ char **lines[2]; /* The actual lines (may contain nulls) */
+ size_t *lengths[2]; /* Line lengths (including newlines, if any) */
+ struct diff_block *next;
+};
+
+/* Three way diff */
+
+struct diff3_block {
+ enum diff_type correspond; /* Type of diff */
+ int ranges[3][2]; /* Ranges are inclusive */
+ char **lines[3]; /* The actual lines (may contain nulls) */
+ size_t *lengths[3]; /* Line lengths (including newlines, if any) */
+ struct diff3_block *next;
+};
+
+/*
+ * Access the ranges on a diff block.
+ */
+#define D_LOWLINE(diff, filenum) \
+ ((diff)->ranges[filenum][START])
+#define D_HIGHLINE(diff, filenum) \
+ ((diff)->ranges[filenum][END])
+#define D_NUMLINES(diff, filenum) \
+ (D_HIGHLINE (diff, filenum) - D_LOWLINE (diff, filenum) + 1)
+
+/*
+ * Access the line numbers in a file in a diff by relative line
+ * numbers (i.e. line number within the diff itself). Note that these
+ * are lvalues and can be used for assignment.
+ */
+#define D_RELNUM(diff, filenum, linenum) \
+ ((diff)->lines[filenum][linenum])
+#define D_RELLEN(diff, filenum, linenum) \
+ ((diff)->lengths[filenum][linenum])
+
+/*
+ * And get at them directly, when that should be necessary.
+ */
+#define D_LINEARRAY(diff, filenum) \
+ ((diff)->lines[filenum])
+#define D_LENARRAY(diff, filenum) \
+ ((diff)->lengths[filenum])
+
+/*
+ * Next block.
+ */
+#define D_NEXT(diff) ((diff)->next)
+
+/*
+ * Access the type of a diff3 block.
+ */
+#define D3_TYPE(diff) ((diff)->correspond)
+
+/*
+ * Line mappings based on diffs. The first maps off the top of the
+ * diff, the second off of the bottom.
+ */
+#define D_HIGH_MAPLINE(diff, fromfile, tofile, lineno) \
+ ((lineno) \
+ - D_HIGHLINE ((diff), (fromfile)) \
+ + D_HIGHLINE ((diff), (tofile)))
+
+#define D_LOW_MAPLINE(diff, fromfile, tofile, lineno) \
+ ((lineno) \
+ - D_LOWLINE ((diff), (fromfile)) \
+ + D_LOWLINE ((diff), (tofile)))
+
+/*
+ * General memory allocation function.
+ */
+#define ALLOCATE(number, type) \
+ (type *) xmalloc ((number) * sizeof (type))
+
+/* Options variables for flags set on command line. */
+
+/* If nonzero, treat all files as text files, never as binary. */
+static int always_text;
+
+/* If nonzero, write out an ed script instead of the standard diff3 format. */
+static int edscript;
+
+/* If nonzero, in the case of overlapping diffs (type DIFF_ALL),
+ preserve the lines which would normally be deleted from
+ file 1 with a special flagging mechanism. */
+static int flagging;
+
+/* Number of lines to keep in identical prefix and suffix. */
+static int horizon_lines = 10;
+
+/* Use a tab to align output lines (-T). */
+static int tab_align_flag;
+
+/* If nonzero, do not output information for overlapping diffs. */
+static int simple_only;
+
+/* If nonzero, do not output information for non-overlapping diffs. */
+static int overlap_only;
+
+/* If nonzero, show information for DIFF_2ND diffs. */
+static int show_2nd;
+
+/* If nonzero, include `:wq' at the end of the script
+ to write out the file being edited. */
+static int finalwrite;
+
+/* If nonzero, output a merged file. */
+static int merge;
+
+static char *program_name;
+
+static VOID *xmalloc PARAMS((size_t));
+static VOID *xrealloc PARAMS((VOID *, size_t));
+
+static char *read_diff PARAMS((char const *, char const *, char **));
+static char *scan_diff_line PARAMS((char *, char **, size_t *, char *, int));
+static enum diff_type process_diff_control PARAMS((char **, struct diff_block *));
+static int compare_line_list PARAMS((char * const[], size_t const[], char * const[], size_t const[], int));
+static int copy_stringlist PARAMS((char * const[], size_t const[], char *[], size_t[], int));
+static int dotlines PARAMS((FILE *, struct diff3_block *, int));
+static int output_diff3_edscript PARAMS((FILE *, struct diff3_block *, int const[3], int const[3], char const *, char const *, char const *));
+static int output_diff3_merge PARAMS((FILE *, FILE *, struct diff3_block *, int const[3], int const[3], char const *, char const *, char const *));
+static size_t myread PARAMS((int, char *, size_t));
+static struct diff3_block *create_diff3_block PARAMS((int, int, int, int, int, int));
+static struct diff3_block *make_3way_diff PARAMS((struct diff_block *, struct diff_block *));
+static struct diff3_block *reverse_diff3_blocklist PARAMS((struct diff3_block *));
+static struct diff3_block *using_to_diff3_block PARAMS((struct diff_block *[2], struct diff_block *[2], int, int, struct diff3_block const *));
+static struct diff_block *process_diff PARAMS((char const *, char const *, struct diff_block **));
+static void check_stdout PARAMS((void));
+static void fatal PARAMS((char const *));
+static void output_diff3 PARAMS((FILE *, struct diff3_block *, int const[3], int const[3]));
+static void perror_with_exit PARAMS((char const *));
+static void try_help PARAMS((char const *));
+static void undotlines PARAMS((FILE *, int, int, int));
+static void usage PARAMS((void));
+
+static char const diff_program[] = DIFF_PROGRAM;
+
+static struct option const longopts[] =
+{
+ {"text", 0, 0, 'a'},
+ {"show-all", 0, 0, 'A'},
+ {"ed", 0, 0, 'e'},
+ {"show-overlap", 0, 0, 'E'},
+ {"label", 1, 0, 'L'},
+ {"merge", 0, 0, 'm'},
+ {"initial-tab", 0, 0, 'T'},
+ {"overlap-only", 0, 0, 'x'},
+ {"easy-only", 0, 0, '3'},
+ {"version", 0, 0, 'v'},
+ {"help", 0, 0, 129},
+ {0, 0, 0, 0}
+};
+
+/*
+ * Main program. Calls diff twice on two pairs of input files,
+ * combines the two diffs, and outputs them.
+ */
+int
+main (argc, argv)
+ int argc;
+ char **argv;
+{
+ int c, i;
+ int mapping[3];
+ int rev_mapping[3];
+ int incompat = 0;
+ int conflicts_found;
+ struct diff_block *thread0, *thread1, *last_block;
+ struct diff3_block *diff3;
+ int tag_count = 0;
+ char *tag_strings[3];
+ char *commonname;
+ char **file;
+ struct stat statb;
+
+ initialize_main (&argc, &argv);
+ program_name = argv[0];
+
+ while ((c = getopt_long (argc, argv, "aeimvx3AEL:TX", longopts, 0)) != EOF)
+ {
+ switch (c)
+ {
+ case 'a':
+ always_text = 1;
+ break;
+ case 'A':
+ show_2nd = 1;
+ flagging = 1;
+ incompat++;
+ break;
+ case 'x':
+ overlap_only = 1;
+ incompat++;
+ break;
+ case '3':
+ simple_only = 1;
+ incompat++;
+ break;
+ case 'i':
+ finalwrite = 1;
+ break;
+ case 'm':
+ merge = 1;
+ break;
+ case 'X':
+ overlap_only = 1;
+ /* Falls through */
+ case 'E':
+ flagging = 1;
+ /* Falls through */
+ case 'e':
+ incompat++;
+ break;
+ case 'T':
+ tab_align_flag = 1;
+ break;
+ case 'v':
+ printf ("diff3 - GNU diffutils version %s\n", version_string);
+ exit (0);
+ case 129:
+ usage ();
+ check_stdout ();
+ exit (0);
+ case 'L':
+ /* Handle up to three -L options. */
+ if (tag_count < 3)
+ {
+ tag_strings[tag_count++] = optarg;
+ break;
+ }
+ try_help ("Too many labels were given. The limit is 3.");
+ default:
+ try_help (0);
+ }
+ }
+
+ edscript = incompat & ~merge; /* -AeExX3 without -m implies ed script. */
+ show_2nd |= ~incompat & merge; /* -m without -AeExX3 implies -A. */
+ flagging |= ~incompat & merge;
+
+ if (incompat > 1 /* Ensure at most one of -AeExX3. */
+ || finalwrite & merge /* -i -m would rewrite input file. */
+ || (tag_count && ! flagging)) /* -L requires one of -AEX. */
+ try_help ("incompatible options");
+
+ if (argc - optind != 3)
+ try_help (argc - optind < 3 ? "missing operand" : "extra operand");
+
+ file = &argv[optind];
+
+ for (i = tag_count; i < 3; i++)
+ tag_strings[i] = file[i];
+
+ /* Always compare file1 to file2, even if file2 is "-".
+ This is needed for -mAeExX3. Using the file0 as
+ the common file would produce wrong results, because if the
+ file0-file1 diffs didn't line up with the file0-file2 diffs
+ (which is entirely possible since we don't use diff's -n option),
+ diff3 might report phantom changes from file1 to file2. */
+
+ if (strcmp (file[2], "-") == 0)
+ {
+ /* Sigh. We've got standard input as the last arg. We can't
+ call diff twice on stdin. Use the middle arg as the common
+ file instead. */
+ if (strcmp (file[0], "-") == 0 || strcmp (file[1], "-") == 0)
+ fatal ("`-' specified for more than one input file");
+ mapping[0] = 0;
+ mapping[1] = 2;
+ mapping[2] = 1;
+ }
+ else
+ {
+ /* Normal, what you'd expect */
+ mapping[0] = 0;
+ mapping[1] = 1;
+ mapping[2] = 2;
+ }
+
+ for (i = 0; i < 3; i++)
+ rev_mapping[mapping[i]] = i;
+
+ for (i = 0; i < 3; i++)
+ if (strcmp (file[i], "-") != 0)
+ {
+ if (stat (file[i], &statb) < 0)
+ perror_with_exit (file[i]);
+ else if (S_ISDIR(statb.st_mode))
+ {
+ fprintf (stderr, "%s: %s: Is a directory\n",
+ program_name, file[i]);
+ exit (2);
+ }
+ }
+
+#if !defined(SIGCHLD) && defined(SIGCLD)
+#define SIGCHLD SIGCLD
+#endif
+#ifdef SIGCHLD
+ /* System V fork+wait does not work if SIGCHLD is ignored. */
+ signal (SIGCHLD, SIG_DFL);
+#endif
+
+ commonname = file[rev_mapping[FILEC]];
+ thread1 = process_diff (file[rev_mapping[FILE1]], commonname, &last_block);
+ if (thread1)
+ for (i = 0; i < 2; i++)
+ {
+ horizon_lines = max (horizon_lines, D_NUMLINES (thread1, i));
+ horizon_lines = max (horizon_lines, D_NUMLINES (last_block, i));
+ }
+ thread0 = process_diff (file[rev_mapping[FILE0]], commonname, &last_block);
+ diff3 = make_3way_diff (thread0, thread1);
+ if (edscript)
+ conflicts_found
+ = output_diff3_edscript (stdout, diff3, mapping, rev_mapping,
+ tag_strings[0], tag_strings[1], tag_strings[2]);
+ else if (merge)
+ {
+ if (! freopen (file[rev_mapping[FILE0]], "r", stdin))
+ perror_with_exit (file[rev_mapping[FILE0]]);
+ conflicts_found
+ = output_diff3_merge (stdin, stdout, diff3, mapping, rev_mapping,
+ tag_strings[0], tag_strings[1], tag_strings[2]);
+ if (ferror (stdin))
+ fatal ("read error");
+ }
+ else
+ {
+ output_diff3 (stdout, diff3, mapping, rev_mapping);
+ conflicts_found = 0;
+ }
+
+ check_stdout ();
+ exit (conflicts_found);
+ return conflicts_found;
+}
+
+static void
+try_help (reason)
+ char const *reason;
+{
+ if (reason)
+ fprintf (stderr, "%s: %s\n", program_name, reason);
+ fprintf (stderr, "%s: Try `%s --help' for more information.\n",
+ program_name, program_name);
+ exit (2);
+}
+
+static void
+check_stdout ()
+{
+ if (ferror (stdout) || fclose (stdout) != 0)
+ fatal ("write error");
+}
+
+/*
+ * Explain, patiently and kindly, how to use this program.
+ */
+static void
+usage ()
+{
+ printf ("Usage: %s [OPTION]... MYFILE OLDFILE YOURFILE\n\n", program_name);
+
+ printf ("%s", "\
+ -e --ed Output unmerged changes from OLDFILE to YOURFILE into MYFILE.\n\
+ -E --show-overlap Output unmerged changes, bracketing conflicts.\n\
+ -A --show-all Output all changes, bracketing conflicts.\n\
+ -x --overlap-only Output overlapping changes.\n\
+ -X Output overlapping changes, bracketing them.\n\
+ -3 --easy-only Output unmerged nonoverlapping changes.\n\n");
+ printf ("%s", "\
+ -m --merge Output merged file instead of ed script (default -A).\n\
+ -L LABEL --label=LABEL Use LABEL instead of file name.\n\
+ -i Append `w' and `q' commands to ed scripts.\n\
+ -a --text Treat all files as text.\n\
+ -T --initial-tab Make tabs line up by prepending a tab.\n\n");
+ printf ("%s", "\
+ -v --version Output version info.\n\
+ --help Output this help.\n\n");
+ printf ("If a FILE is `-', read standard input.\n");
+}
+
+/*
+ * Routines that combine the two diffs together into one. The
+ * algorithm used follows:
+ *
+ * File2 is shared in common between the two diffs.
+ * Diff02 is the diff between 0 and 2.
+ * Diff12 is the diff between 1 and 2.
+ *
+ * 1) Find the range for the first block in File2.
+ * a) Take the lowest of the two ranges (in File2) in the two
+ * current blocks (one from each diff) as being the low
+ * water mark. Assign the upper end of this block as
+ * being the high water mark and move the current block up
+ * one. Mark the block just moved over as to be used.
+ * b) Check the next block in the diff that the high water
+ * mark is *not* from.
+ *
+ * *If* the high water mark is above
+ * the low end of the range in that block,
+ *
+ * mark that block as to be used and move the current
+ * block up. Set the high water mark to the max of
+ * the high end of this block and the current. Repeat b.
+ *
+ * 2) Find the corresponding ranges in File0 (from the blocks
+ * in diff02; line per line outside of diffs) and in File1.
+ * Create a diff3_block, reserving space as indicated by the ranges.
+ *
+ * 3) Copy all of the pointers for file2 in. At least for now,
+ * do memcmp's between corresponding strings in the two diffs.
+ *
+ * 4) Copy all of the pointers for file0 and 1 in. Get what you
+ * need from file2 (when there isn't a diff block, it's
+ * identical to file2 within the range between diff blocks).
+ *
+ * 5) If the diff blocks you used came from only one of the two
+ * strings of diffs, then that file (i.e. the one other than
+ * the common file in that diff) is the odd person out. If you used
+ * diff blocks from both sets, check to see if files 0 and 1 match:
+ *
+ * Same number of lines? If so, do a set of memcmp's (if a
+ * memcmp matches; copy the pointer over; it'll be easier later
+ * if you have to do any compares). If they match, 0 & 1 are
+ * the same. If not, all three different.
+ *
+ * Then you do it again, until you run out of blocks.
+ *
+ */
+
+/*
+ * This routine makes a three way diff (chain of diff3_block's) from two
+ * two way diffs (chains of diff_block's). It is assumed that each of
+ * the two diffs passed are onto the same file (i.e. that each of the
+ * diffs were made "to" the same file). The three way diff pointer
+ * returned will have numbering FILE0--the other file in diff02,
+ * FILE1--the other file in diff12, and FILEC--the common file.
+ */
+static struct diff3_block *
+make_3way_diff (thread0, thread1)
+ struct diff_block *thread0, *thread1;
+{
+/*
+ * This routine works on the two diffs passed to it as threads.
+ * Thread number 0 is diff02, thread number 1 is diff12. The USING
+ * array is set to the base of the list of blocks to be used to
+ * construct each block of the three way diff; if no blocks from a
+ * particular thread are to be used, that element of the using array
+ * is set to 0. The elements LAST_USING array are set to the last
+ * elements on each of the using lists.
+ *
+ * The HIGH_WATER_MARK is set to the highest line number in the common file
+ * described in any of the diffs in either of the USING lists. The
+ * HIGH_WATER_THREAD names the thread. Similarly the BASE_WATER_MARK
+ * and BASE_WATER_THREAD describe the lowest line number in the common file
+ * described in any of the diffs in either of the USING lists. The
+ * HIGH_WATER_DIFF is the diff from which the HIGH_WATER_MARK was
+ * taken.
+ *
+ * The HIGH_WATER_DIFF should always be equal to LAST_USING
+ * [HIGH_WATER_THREAD]. The OTHER_DIFF is the next diff to check for
+ * higher water, and should always be equal to
+ * CURRENT[HIGH_WATER_THREAD ^ 0x1]. The OTHER_THREAD is the thread
+ * in which the OTHER_DIFF is, and hence should always be equal to
+ * HIGH_WATER_THREAD ^ 0x1.
+ *
+ * The variable LAST_DIFF is kept set to the last diff block produced
+ * by this routine, for line correspondence purposes between that diff
+ * and the one currently being worked on. It is initialized to
+ * ZERO_DIFF before any blocks have been created.
+ */
+
+ struct diff_block
+ *using[2],
+ *last_using[2],
+ *current[2];
+
+ int
+ high_water_mark;
+
+ int
+ high_water_thread,
+ base_water_thread,
+ other_thread;
+
+ struct diff_block
+ *high_water_diff,
+ *other_diff;
+
+ struct diff3_block
+ *result,
+ *tmpblock,
+ **result_end;
+
+ struct diff3_block const *last_diff3;
+
+ static struct diff3_block const zero_diff3;
+
+ /* Initialization */
+ result = 0;
+ result_end = &result;
+ current[0] = thread0; current[1] = thread1;
+ last_diff3 = &zero_diff3;
+
+ /* Sniff up the threads until we reach the end */
+
+ while (current[0] || current[1])
+ {
+ using[0] = using[1] = last_using[0] = last_using[1] = 0;
+
+ /* Setup low and high water threads, diffs, and marks. */
+ if (!current[0])
+ base_water_thread = 1;
+ else if (!current[1])
+ base_water_thread = 0;
+ else
+ base_water_thread =
+ (D_LOWLINE (current[0], FC) > D_LOWLINE (current[1], FC));
+
+ high_water_thread = base_water_thread;
+
+ high_water_diff = current[high_water_thread];
+
+#if 0
+ /* low and high waters start off same diff */
+ base_water_mark = D_LOWLINE (high_water_diff, FC);
+#endif
+
+ high_water_mark = D_HIGHLINE (high_water_diff, FC);
+
+ /* Make the diff you just got info from into the using class */
+ using[high_water_thread]
+ = last_using[high_water_thread]
+ = high_water_diff;
+ current[high_water_thread] = high_water_diff->next;
+ last_using[high_water_thread]->next = 0;
+
+ /* And mark the other diff */
+ other_thread = high_water_thread ^ 0x1;
+ other_diff = current[other_thread];
+
+ /* Shuffle up the ladder, checking the other diff to see if it
+ needs to be incorporated. */
+ while (other_diff
+ && D_LOWLINE (other_diff, FC) <= high_water_mark + 1)
+ {
+
+ /* Incorporate this diff into the using list. Note that
+ this doesn't take it off the current list */
+ if (using[other_thread])
+ last_using[other_thread]->next = other_diff;
+ else
+ using[other_thread] = other_diff;
+ last_using[other_thread] = other_diff;
+
+ /* Take it off the current list. Note that this following
+ code assumes that other_diff enters it equal to
+ current[high_water_thread ^ 0x1] */
+ current[other_thread] = current[other_thread]->next;
+ other_diff->next = 0;
+
+ /* Set the high_water stuff
+ If this comparison is equal, then this is the last pass
+ through this loop; since diff blocks within a given
+ thread cannot overlap, the high_water_mark will be
+ *below* the range_start of either of the next diffs. */
+
+ if (high_water_mark < D_HIGHLINE (other_diff, FC))
+ {
+ high_water_thread ^= 1;
+ high_water_diff = other_diff;
+ high_water_mark = D_HIGHLINE (other_diff, FC);
+ }
+
+ /* Set the other diff */
+ other_thread = high_water_thread ^ 0x1;
+ other_diff = current[other_thread];
+ }
+
+ /* The using lists contain a list of all of the blocks to be
+ included in this diff3_block. Create it. */
+
+ tmpblock = using_to_diff3_block (using, last_using,
+ base_water_thread, high_water_thread,
+ last_diff3);
+
+ if (!tmpblock)
+ fatal ("internal error: screwup in format of diff blocks");
+
+ /* Put it on the list. */
+ *result_end = tmpblock;
+ result_end = &tmpblock->next;
+
+ /* Set up corresponding lines correctly. */
+ last_diff3 = tmpblock;
+ }
+ return result;
+}
+
+/*
+ * using_to_diff3_block:
+ * This routine takes two lists of blocks (from two separate diff
+ * threads) and puts them together into one diff3 block.
+ * It then returns a pointer to this diff3 block or 0 for failure.
+ *
+ * All arguments besides using are for the convenience of the routine;
+ * they could be derived from the using array.
+ * LAST_USING is a pair of pointers to the last blocks in the using
+ * structure.
+ * LOW_THREAD and HIGH_THREAD tell which threads contain the lowest
+ * and highest line numbers for File0.
+ * last_diff3 contains the last diff produced in the calling routine.
+ * This is used for lines mappings which would still be identical to
+ * the state that diff ended in.
+ *
+ * A distinction should be made in this routine between the two diffs
+ * that are part of a normal two diff block, and the three diffs that
+ * are part of a diff3_block.
+ */
+static struct diff3_block *
+using_to_diff3_block (using, last_using, low_thread, high_thread, last_diff3)
+ struct diff_block
+ *using[2],
+ *last_using[2];
+ int low_thread, high_thread;
+ struct diff3_block const *last_diff3;
+{
+ int low[2], high[2];
+ struct diff3_block *result;
+ struct diff_block *ptr;
+ int d, i;
+
+ /* Find the range in the common file. */
+ int lowc = D_LOWLINE (using[low_thread], FC);
+ int highc = D_HIGHLINE (last_using[high_thread], FC);
+
+ /* Find the ranges in the other files.
+ If using[d] is null, that means that the file to which that diff
+ refers is equivalent to the common file over this range. */
+
+ for (d = 0; d < 2; d++)
+ if (using[d])
+ {
+ low[d] = D_LOW_MAPLINE (using[d], FC, FO, lowc);
+ high[d] = D_HIGH_MAPLINE (last_using[d], FC, FO, highc);
+ }
+ else
+ {
+ low[d] = D_HIGH_MAPLINE (last_diff3, FILEC, FILE0 + d, lowc);
+ high[d] = D_HIGH_MAPLINE (last_diff3, FILEC, FILE0 + d, highc);
+ }
+
+ /* Create a block with the appropriate sizes */
+ result = create_diff3_block (low[0], high[0], low[1], high[1], lowc, highc);
+
+ /* Copy information for the common file.
+ Return with a zero if any of the compares failed. */
+
+ for (d = 0; d < 2; d++)
+ for (ptr = using[d]; ptr; ptr = D_NEXT (ptr))
+ {
+ int result_offset = D_LOWLINE (ptr, FC) - lowc;
+
+ if (!copy_stringlist (D_LINEARRAY (ptr, FC),
+ D_LENARRAY (ptr, FC),
+ D_LINEARRAY (result, FILEC) + result_offset,
+ D_LENARRAY (result, FILEC) + result_offset,
+ D_NUMLINES (ptr, FC)))
+ return 0;
+ }
+
+ /* Copy information for file d. First deal with anything that might be
+ before the first diff. */
+
+ for (d = 0; d < 2; d++)
+ {
+ struct diff_block *u = using[d];
+ int lo = low[d], hi = high[d];
+
+ for (i = 0;
+ i + lo < (u ? D_LOWLINE (u, FO) : hi + 1);
+ i++)
+ {
+ D_RELNUM (result, FILE0 + d, i) = D_RELNUM (result, FILEC, i);
+ D_RELLEN (result, FILE0 + d, i) = D_RELLEN (result, FILEC, i);
+ }
+
+ for (ptr = u; ptr; ptr = D_NEXT (ptr))
+ {
+ int result_offset = D_LOWLINE (ptr, FO) - lo;
+ int linec;
+
+ if (!copy_stringlist (D_LINEARRAY (ptr, FO),
+ D_LENARRAY (ptr, FO),
+ D_LINEARRAY (result, FILE0 + d) + result_offset,
+ D_LENARRAY (result, FILE0 + d) + result_offset,
+ D_NUMLINES (ptr, FO)))
+ return 0;
+
+ /* Catch the lines between here and the next diff */
+ linec = D_HIGHLINE (ptr, FC) + 1 - lowc;
+ for (i = D_HIGHLINE (ptr, FO) + 1 - lo;
+ i < (D_NEXT (ptr) ? D_LOWLINE (D_NEXT (ptr), FO) : hi + 1) - lo;
+ i++)
+ {
+ D_RELNUM (result, FILE0 + d, i) = D_RELNUM (result, FILEC, linec);
+ D_RELLEN (result, FILE0 + d, i) = D_RELLEN (result, FILEC, linec);
+ linec++;
+ }
+ }
+ }
+
+ /* Set correspond */
+ if (!using[0])
+ D3_TYPE (result) = DIFF_2ND;
+ else if (!using[1])
+ D3_TYPE (result) = DIFF_1ST;
+ else
+ {
+ int nl0 = D_NUMLINES (result, FILE0);
+ int nl1 = D_NUMLINES (result, FILE1);
+
+ if (nl0 != nl1
+ || !compare_line_list (D_LINEARRAY (result, FILE0),
+ D_LENARRAY (result, FILE0),
+ D_LINEARRAY (result, FILE1),
+ D_LENARRAY (result, FILE1),
+ nl0))
+ D3_TYPE (result) = DIFF_ALL;
+ else
+ D3_TYPE (result) = DIFF_3RD;
+ }
+
+ return result;
+}
+
+/*
+ * This routine copies pointers from a list of strings to a different list
+ * of strings. If a spot in the second list is already filled, it
+ * makes sure that it is filled with the same string; if not it
+ * returns 0, the copy incomplete.
+ * Upon successful completion of the copy, it returns 1.
+ */
+static int
+copy_stringlist (fromptrs, fromlengths, toptrs, tolengths, copynum)
+ char * const fromptrs[];
+ char *toptrs[];
+ size_t const fromlengths[];
+ size_t tolengths[];
+ int copynum;
+{
+ register char * const *f = fromptrs;
+ register char **t = toptrs;
+ register size_t const *fl = fromlengths;
+ register size_t *tl = tolengths;
+
+ while (copynum--)
+ {
+ if (*t)
+ { if (*fl != *tl || memcmp (*f, *t, *fl)) return 0; }
+ else
+ { *t = *f ; *tl = *fl; }
+
+ t++; f++; tl++; fl++;
+ }
+ return 1;
+}
+
+/*
+ * Create a diff3_block, with ranges as specified in the arguments.
+ * Allocate the arrays for the various pointers (and zero them) based
+ * on the arguments passed. Return the block as a result.
+ */
+static struct diff3_block *
+create_diff3_block (low0, high0, low1, high1, low2, high2)
+ register int low0, high0, low1, high1, low2, high2;
+{
+ struct diff3_block *result = ALLOCATE (1, struct diff3_block);
+ int numlines;
+
+ D3_TYPE (result) = ERROR;
+ D_NEXT (result) = 0;
+
+ /* Assign ranges */
+ D_LOWLINE (result, FILE0) = low0;
+ D_HIGHLINE (result, FILE0) = high0;
+ D_LOWLINE (result, FILE1) = low1;
+ D_HIGHLINE (result, FILE1) = high1;
+ D_LOWLINE (result, FILE2) = low2;
+ D_HIGHLINE (result, FILE2) = high2;
+
+ /* Allocate and zero space */
+ numlines = D_NUMLINES (result, FILE0);
+ if (numlines)
+ {
+ D_LINEARRAY (result, FILE0) = ALLOCATE (numlines, char *);
+ D_LENARRAY (result, FILE0) = ALLOCATE (numlines, size_t);
+ bzero (D_LINEARRAY (result, FILE0), (numlines * sizeof (char *)));
+ bzero (D_LENARRAY (result, FILE0), (numlines * sizeof (size_t)));
+ }
+ else
+ {
+ D_LINEARRAY (result, FILE0) = 0;
+ D_LENARRAY (result, FILE0) = 0;
+ }
+
+ numlines = D_NUMLINES (result, FILE1);
+ if (numlines)
+ {
+ D_LINEARRAY (result, FILE1) = ALLOCATE (numlines, char *);
+ D_LENARRAY (result, FILE1) = ALLOCATE (numlines, size_t);
+ bzero (D_LINEARRAY (result, FILE1), (numlines * sizeof (char *)));
+ bzero (D_LENARRAY (result, FILE1), (numlines * sizeof (size_t)));
+ }
+ else
+ {
+ D_LINEARRAY (result, FILE1) = 0;
+ D_LENARRAY (result, FILE1) = 0;
+ }
+
+ numlines = D_NUMLINES (result, FILE2);
+ if (numlines)
+ {
+ D_LINEARRAY (result, FILE2) = ALLOCATE (numlines, char *);
+ D_LENARRAY (result, FILE2) = ALLOCATE (numlines, size_t);
+ bzero (D_LINEARRAY (result, FILE2), (numlines * sizeof (char *)));
+ bzero (D_LENARRAY (result, FILE2), (numlines * sizeof (size_t)));
+ }
+ else
+ {
+ D_LINEARRAY (result, FILE2) = 0;
+ D_LENARRAY (result, FILE2) = 0;
+ }
+
+ /* Return */
+ return result;
+}
+
+/*
+ * Compare two lists of lines of text.
+ * Return 1 if they are equivalent, 0 if not.
+ */
+static int
+compare_line_list (list1, lengths1, list2, lengths2, nl)
+ char * const list1[], * const list2[];
+ size_t const lengths1[], lengths2[];
+ int nl;
+{
+ char
+ * const *l1 = list1,
+ * const *l2 = list2;
+ size_t const
+ *lgths1 = lengths1,
+ *lgths2 = lengths2;
+
+ while (nl--)
+ if (!*l1 || !*l2 || *lgths1 != *lgths2++
+ || memcmp (*l1++, *l2++, *lgths1++))
+ return 0;
+ return 1;
+}
+
+/*
+ * Routines to input and parse two way diffs.
+ */
+
+extern char **environ;
+
+static struct diff_block *
+process_diff (filea, fileb, last_block)
+ char const *filea, *fileb;
+ struct diff_block **last_block;
+{
+ char *diff_contents;
+ char *diff_limit;
+ char *scan_diff;
+ enum diff_type dt;
+ int i;
+ struct diff_block *block_list, **block_list_end, *bptr;
+
+ diff_limit = read_diff (filea, fileb, &diff_contents);
+ scan_diff = diff_contents;
+ block_list_end = &block_list;
+ bptr = 0; /* Pacify `gcc -W'. */
+
+ while (scan_diff < diff_limit)
+ {
+ bptr = ALLOCATE (1, struct diff_block);
+ bptr->lines[0] = bptr->lines[1] = 0;
+ bptr->lengths[0] = bptr->lengths[1] = 0;
+
+ dt = process_diff_control (&scan_diff, bptr);
+ if (dt == ERROR || *scan_diff != '\n')
+ {
+ fprintf (stderr, "%s: diff error: ", program_name);
+ do
+ {
+ putc (*scan_diff, stderr);
+ }
+ while (*scan_diff++ != '\n');
+ exit (2);
+ }
+ scan_diff++;
+
+ /* Force appropriate ranges to be null, if necessary */
+ switch (dt)
+ {
+ case ADD:
+ bptr->ranges[0][0]++;
+ break;
+ case DELETE:
+ bptr->ranges[1][0]++;
+ break;
+ case CHANGE:
+ break;
+ default:
+ fatal ("internal error: invalid diff type in process_diff");
+ break;
+ }
+
+ /* Allocate space for the pointers for the lines from filea, and
+ parcel them out among these pointers */
+ if (dt != ADD)
+ {
+ int numlines = D_NUMLINES (bptr, 0);
+ bptr->lines[0] = ALLOCATE (numlines, char *);
+ bptr->lengths[0] = ALLOCATE (numlines, size_t);
+ for (i = 0; i < numlines; i++)
+ scan_diff = scan_diff_line (scan_diff,
+ &(bptr->lines[0][i]),
+ &(bptr->lengths[0][i]),
+ diff_limit,
+ '<');
+ }
+
+ /* Get past the separator for changes */
+ if (dt == CHANGE)
+ {
+ if (strncmp (scan_diff, "---\n", 4))
+ fatal ("invalid diff format; invalid change separator");
+ scan_diff += 4;
+ }
+
+ /* Allocate space for the pointers for the lines from fileb, and
+ parcel them out among these pointers */
+ if (dt != DELETE)
+ {
+ int numlines = D_NUMLINES (bptr, 1);
+ bptr->lines[1] = ALLOCATE (numlines, char *);
+ bptr->lengths[1] = ALLOCATE (numlines, size_t);
+ for (i = 0; i < numlines; i++)
+ scan_diff = scan_diff_line (scan_diff,
+ &(bptr->lines[1][i]),
+ &(bptr->lengths[1][i]),
+ diff_limit,
+ '>');
+ }
+
+ /* Place this block on the blocklist. */
+ *block_list_end = bptr;
+ block_list_end = &bptr->next;
+ }
+
+ *block_list_end = 0;
+ *last_block = bptr;
+ return block_list;
+}
+
+/*
+ * This routine will parse a normal format diff control string. It
+ * returns the type of the diff (ERROR if the format is bad). All of
+ * the other important information is filled into to the structure
+ * pointed to by db, and the string pointer (whose location is passed
+ * to this routine) is updated to point beyond the end of the string
+ * parsed. Note that only the ranges in the diff_block will be set by
+ * this routine.
+ *
+ * If some specific pair of numbers has been reduced to a single
+ * number, then both corresponding numbers in the diff block are set
+ * to that number. In general these numbers are interpetted as ranges
+ * inclusive, unless being used by the ADD or DELETE commands. It is
+ * assumed that these will be special cased in a superior routine.
+ */
+
+static enum diff_type
+process_diff_control (string, db)
+ char **string;
+ struct diff_block *db;
+{
+ char *s = *string;
+ int holdnum;
+ enum diff_type type;
+
+/* These macros are defined here because they can use variables
+ defined in this function. Don't try this at home kids, we're
+ trained professionals!
+
+ Also note that SKIPWHITE only recognizes tabs and spaces, and
+ that READNUM can only read positive, integral numbers */
+
+#define SKIPWHITE(s) { while (*s == ' ' || *s == '\t') s++; }
+#define READNUM(s, num) \
+ { unsigned char c = *s; if (!ISDIGIT (c)) return ERROR; holdnum = 0; \
+ do { holdnum = (c - '0' + holdnum * 10); } \
+ while (ISDIGIT (c = *++s)); (num) = holdnum; }
+
+ /* Read first set of digits */
+ SKIPWHITE (s);
+ READNUM (s, db->ranges[0][START]);
+
+ /* Was that the only digit? */
+ SKIPWHITE (s);
+ if (*s == ',')
+ {
+ /* Get the next digit */
+ s++;
+ READNUM (s, db->ranges[0][END]);
+ }
+ else
+ db->ranges[0][END] = db->ranges[0][START];
+
+ /* Get the letter */
+ SKIPWHITE (s);
+ switch (*s)
+ {
+ case 'a':
+ type = ADD;
+ break;
+ case 'c':
+ type = CHANGE;
+ break;
+ case 'd':
+ type = DELETE;
+ break;
+ default:
+ return ERROR; /* Bad format */
+ }
+ s++; /* Past letter */
+
+ /* Read second set of digits */
+ SKIPWHITE (s);
+ READNUM (s, db->ranges[1][START]);
+
+ /* Was that the only digit? */
+ SKIPWHITE (s);
+ if (*s == ',')
+ {
+ /* Get the next digit */
+ s++;
+ READNUM (s, db->ranges[1][END]);
+ SKIPWHITE (s); /* To move to end */
+ }
+ else
+ db->ranges[1][END] = db->ranges[1][START];
+
+ *string = s;
+ return type;
+}
+
+static char *
+read_diff (filea, fileb, output_placement)
+ char const *filea, *fileb;
+ char **output_placement;
+{
+ char *diff_result;
+ size_t bytes, current_chunk_size, total;
+ int fd, wstatus;
+ struct stat pipestat;
+
+ /* 302 / 1000 is log10(2.0) rounded up. Subtract 1 for the sign bit;
+ add 1 for integer division truncation; add 1 more for a minus sign. */
+#define INT_STRLEN_BOUND(type) ((sizeof(type)*CHAR_BIT - 1) * 302 / 1000 + 2)
+
+#if HAVE_FORK
+
+ char const *argv[7];
+ char horizon_arg[17 + INT_STRLEN_BOUND (int)];
+ char const **ap;
+ int fds[2];
+ pid_t pid;
+
+ ap = argv;
+ *ap++ = diff_program;
+ if (always_text)
+ *ap++ = "-a";
+ sprintf (horizon_arg, "--horizon-lines=%d", horizon_lines);
+ *ap++ = horizon_arg;
+ *ap++ = "--";
+ *ap++ = filea;
+ *ap++ = fileb;
+ *ap = 0;
+
+ if (pipe (fds) != 0)
+ perror_with_exit ("pipe");
+
+ pid = vfork ();
+ if (pid == 0)
+ {
+ /* Child */
+ close (fds[0]);
+ if (fds[1] != STDOUT_FILENO)
+ {
+ dup2 (fds[1], STDOUT_FILENO);
+ close (fds[1]);
+ }
+ execve (diff_program, (char **) argv, environ);
+ /* Avoid stdio, because the parent process's buffers are inherited. */
+ write (STDERR_FILENO, diff_program, strlen (diff_program));
+ write (STDERR_FILENO, ": not found\n", 12);
+ _exit (2);
+ }
+
+ if (pid == -1)
+ perror_with_exit ("fork failed");
+
+ close (fds[1]); /* Prevent erroneous lack of EOF */
+ fd = fds[0];
+
+#else /* ! HAVE_FORK */
+
+ FILE *fpipe;
+ char *command = xmalloc (sizeof (diff_program) + 30 + INT_STRLEN_BOUND (int)
+ + 4 * (strlen (filea) + strlen (fileb)));
+ char *p;
+ sprintf (command, "%s -a --horizon-lines=%d -- ",
+ diff_program, horizon_lines);
+ p = command + strlen (command);
+ SYSTEM_QUOTE_ARG (p, filea);
+ *p++ = ' ';
+ SYSTEM_QUOTE_ARG (p, fileb);
+ *p = '\0';
+ fpipe = popen (command, "r");
+ if (!fpipe)
+ perror_with_exit (command);
+ free (command);
+ fd = fileno (fpipe);
+
+#endif /* ! HAVE_FORK */
+
+ current_chunk_size = 8 * 1024;
+ if (fstat (fd, &pipestat) == 0)
+ current_chunk_size = max (current_chunk_size, STAT_BLOCKSIZE (pipestat));
+
+ diff_result = xmalloc (current_chunk_size);
+ total = 0;
+ do {
+ bytes = myread (fd,
+ diff_result + total,
+ current_chunk_size - total);
+ total += bytes;
+ if (total == current_chunk_size)
+ {
+ if (current_chunk_size < 2 * current_chunk_size)
+ current_chunk_size = 2 * current_chunk_size;
+ else if (current_chunk_size < (size_t) -1)
+ current_chunk_size = (size_t) -1;
+ else
+ fatal ("files are too large to fit into memory");
+ diff_result = xrealloc (diff_result, (current_chunk_size *= 2));
+ }
+ } while (bytes);
+
+ if (total != 0 && diff_result[total-1] != '\n')
+ fatal ("invalid diff format; incomplete last line");
+
+ *output_placement = diff_result;
+
+#if ! HAVE_FORK
+
+ wstatus = pclose (fpipe);
+
+#else /* HAVE_FORK */
+
+ if (close (fd) != 0)
+ perror_with_exit ("pipe close");
+ if (waitpid (pid, &wstatus, 0) < 0)
+ perror_with_exit ("waitpid failed");
+
+#endif /* HAVE_FORK */
+
+ if (! (WIFEXITED (wstatus) && WEXITSTATUS (wstatus) < 2))
+ fatal ("subsidiary diff failed");
+
+ return diff_result + total;
+}
+
+
+/*
+ * Scan a regular diff line (consisting of > or <, followed by a
+ * space, followed by text (including nulls) up to a newline.
+ *
+ * This next routine began life as a macro and many parameters in it
+ * are used as call-by-reference values.
+ */
+static char *
+scan_diff_line (scan_ptr, set_start, set_length, limit, leadingchar)
+ char *scan_ptr, **set_start;
+ size_t *set_length;
+ char *limit;
+ int leadingchar;
+{
+ char *line_ptr;
+
+ if (!(scan_ptr[0] == leadingchar
+ && scan_ptr[1] == ' '))
+ fatal ("invalid diff format; incorrect leading line chars");
+
+ *set_start = line_ptr = scan_ptr + 2;
+ while (*line_ptr++ != '\n')
+ ;
+
+ /* Include newline if the original line ended in a newline,
+ or if an edit script is being generated.
+ Copy any missing newline message to stderr if an edit script is being
+ generated, because edit scripts cannot handle missing newlines.
+ Return the beginning of the next line. */
+ *set_length = line_ptr - *set_start;
+ if (line_ptr < limit && *line_ptr == '\\')
+ {
+ if (edscript)
+ fprintf (stderr, "%s:", program_name);
+ else
+ --*set_length;
+ line_ptr++;
+ do
+ {
+ if (edscript)
+ putc (*line_ptr, stderr);
+ }
+ while (*line_ptr++ != '\n');
+ }
+
+ return line_ptr;
+}
+
+/*
+ * This routine outputs a three way diff passed as a list of
+ * diff3_block's.
+ * The argument MAPPING is indexed by external file number (in the
+ * argument list) and contains the internal file number (from the
+ * diff passed). This is important because the user expects his
+ * outputs in terms of the argument list number, and the diff passed
+ * may have been done slightly differently (if the last argument
+ * was "-", for example).
+ * REV_MAPPING is the inverse of MAPPING.
+ */
+static void
+output_diff3 (outputfile, diff, mapping, rev_mapping)
+ FILE *outputfile;
+ struct diff3_block *diff;
+ int const mapping[3], rev_mapping[3];
+{
+ int i;
+ int oddoneout;
+ char *cp;
+ struct diff3_block *ptr;
+ int line;
+ size_t length;
+ int dontprint;
+ static int skew_increment[3] = { 2, 3, 1 }; /* 0==>2==>1==>3 */
+ char const *line_prefix = tab_align_flag ? "\t" : " ";
+
+ for (ptr = diff; ptr; ptr = D_NEXT (ptr))
+ {
+ char x[2];
+
+ switch (ptr->correspond)
+ {
+ case DIFF_ALL:
+ x[0] = '\0';
+ dontprint = 3; /* Print them all */
+ oddoneout = 3; /* Nobody's odder than anyone else */
+ break;
+ case DIFF_1ST:
+ case DIFF_2ND:
+ case DIFF_3RD:
+ oddoneout = rev_mapping[(int) ptr->correspond - (int) DIFF_1ST];
+
+ x[0] = oddoneout + '1';
+ x[1] = '\0';
+ dontprint = oddoneout==0;
+ break;
+ default:
+ fatal ("internal error: invalid diff type passed to output");
+ }
+ fprintf (outputfile, "====%s\n", x);
+
+ /* Go 0, 2, 1 if the first and third outputs are equivalent. */
+ for (i = 0; i < 3;
+ i = (oddoneout == 1 ? skew_increment[i] : i + 1))
+ {
+ int realfile = mapping[i];
+ int
+ lowt = D_LOWLINE (ptr, realfile),
+ hight = D_HIGHLINE (ptr, realfile);
+
+ fprintf (outputfile, "%d:", i + 1);
+ switch (lowt - hight)
+ {
+ case 1:
+ fprintf (outputfile, "%da\n", lowt - 1);
+ break;
+ case 0:
+ fprintf (outputfile, "%dc\n", lowt);
+ break;
+ default:
+ fprintf (outputfile, "%d,%dc\n", lowt, hight);
+ break;
+ }
+
+ if (i == dontprint) continue;
+
+ if (lowt <= hight)
+ {
+ line = 0;
+ do
+ {
+ fprintf (outputfile, line_prefix);
+ cp = D_RELNUM (ptr, realfile, line);
+ length = D_RELLEN (ptr, realfile, line);
+ fwrite (cp, sizeof (char), length, outputfile);
+ }
+ while (++line < hight - lowt + 1);
+ if (cp[length - 1] != '\n')
+ fprintf (outputfile, "\n\\ No newline at end of file\n");
+ }
+ }
+ }
+}
+
+
+/*
+ * Output to OUTPUTFILE the lines of B taken from FILENUM.
+ * Double any initial '.'s; yield nonzero if any initial '.'s were doubled.
+ */
+static int
+dotlines (outputfile, b, filenum)
+ FILE *outputfile;
+ struct diff3_block *b;
+ int filenum;
+{
+ int i;
+ int leading_dot = 0;
+
+ for (i = 0;
+ i < D_NUMLINES (b, filenum);
+ i++)
+ {
+ char *line = D_RELNUM (b, filenum, i);
+ if (line[0] == '.')
+ {
+ leading_dot = 1;
+ fprintf (outputfile, ".");
+ }
+ fwrite (line, sizeof (char),
+ D_RELLEN (b, filenum, i), outputfile);
+ }
+
+ return leading_dot;
+}
+
+/*
+ * Output to OUTPUTFILE a '.' line. If LEADING_DOT is nonzero,
+ * also output a command that removes initial '.'s
+ * starting with line START and continuing for NUM lines.
+ */
+static void
+undotlines (outputfile, leading_dot, start, num)
+ FILE *outputfile;
+ int leading_dot, start, num;
+{
+ fprintf (outputfile, ".\n");
+ if (leading_dot)
+ if (num == 1)
+ fprintf (outputfile, "%ds/^\\.//\n", start);
+ else
+ fprintf (outputfile, "%d,%ds/^\\.//\n", start, start + num - 1);
+}
+
+/*
+ * This routine outputs a diff3 set of blocks as an ed script. This
+ * script applies the changes between file's 2 & 3 to file 1. It
+ * takes the precise format of the ed script to be output from global
+ * variables set during options processing. Note that it does
+ * destructive things to the set of diff3 blocks it is passed; it
+ * reverses their order (this gets around the problems involved with
+ * changing line numbers in an ed script).
+ *
+ * Note that this routine has the same problem of mapping as the last
+ * one did; the variable MAPPING maps from file number according to
+ * the argument list to file number according to the diff passed. All
+ * files listed below are in terms of the argument list.
+ * REV_MAPPING is the inverse of MAPPING.
+ *
+ * The arguments FILE0, FILE1 and FILE2 are the strings to print
+ * as the names of the three files. These may be the actual names,
+ * or may be the arguments specified with -L.
+ *
+ * Returns 1 if conflicts were found.
+ */
+
+static int
+output_diff3_edscript (outputfile, diff, mapping, rev_mapping,
+ file0, file1, file2)
+ FILE *outputfile;
+ struct diff3_block *diff;
+ int const mapping[3], rev_mapping[3];
+ char const *file0, *file1, *file2;
+{
+ int leading_dot;
+ int conflicts_found = 0, conflict;
+ struct diff3_block *b;
+
+ for (b = reverse_diff3_blocklist (diff); b; b = b->next)
+ {
+ /* Must do mapping correctly. */
+ enum diff_type type
+ = ((b->correspond == DIFF_ALL) ?
+ DIFF_ALL :
+ ((enum diff_type)
+ (((int) DIFF_1ST)
+ + rev_mapping[(int) b->correspond - (int) DIFF_1ST])));
+
+ /* If we aren't supposed to do this output block, skip it. */
+ switch (type)
+ {
+ default: continue;
+ case DIFF_2ND: if (!show_2nd) continue; conflict = 1; break;
+ case DIFF_3RD: if (overlap_only) continue; conflict = 0; break;
+ case DIFF_ALL: if (simple_only) continue; conflict = flagging; break;
+ }
+
+ if (conflict)
+ {
+ conflicts_found = 1;
+
+
+ /* Mark end of conflict. */
+
+ fprintf (outputfile, "%da\n", D_HIGHLINE (b, mapping[FILE0]));
+ leading_dot = 0;
+ if (type == DIFF_ALL)
+ {
+ if (show_2nd)
+ {
+ /* Append lines from FILE1. */
+ fprintf (outputfile, "||||||| %s\n", file1);
+ leading_dot = dotlines (outputfile, b, mapping[FILE1]);
+ }
+ /* Append lines from FILE2. */
+ fprintf (outputfile, "=======\n");
+ leading_dot |= dotlines (outputfile, b, mapping[FILE2]);
+ }
+ fprintf (outputfile, ">>>>>>> %s\n", file2);
+ undotlines (outputfile, leading_dot,
+ D_HIGHLINE (b, mapping[FILE0]) + 2,
+ (D_NUMLINES (b, mapping[FILE1])
+ + D_NUMLINES (b, mapping[FILE2]) + 1));
+
+
+ /* Mark start of conflict. */
+
+ fprintf (outputfile, "%da\n<<<<<<< %s\n",
+ D_LOWLINE (b, mapping[FILE0]) - 1,
+ type == DIFF_ALL ? file0 : file1);
+ leading_dot = 0;
+ if (type == DIFF_2ND)
+ {
+ /* Prepend lines from FILE1. */
+ leading_dot = dotlines (outputfile, b, mapping[FILE1]);
+ fprintf (outputfile, "=======\n");
+ }
+ undotlines (outputfile, leading_dot,
+ D_LOWLINE (b, mapping[FILE0]) + 1,
+ D_NUMLINES (b, mapping[FILE1]));
+ }
+ else if (D_NUMLINES (b, mapping[FILE2]) == 0)
+ /* Write out a delete */
+ {
+ if (D_NUMLINES (b, mapping[FILE0]) == 1)
+ fprintf (outputfile, "%dd\n",
+ D_LOWLINE (b, mapping[FILE0]));
+ else
+ fprintf (outputfile, "%d,%dd\n",
+ D_LOWLINE (b, mapping[FILE0]),
+ D_HIGHLINE (b, mapping[FILE0]));
+ }
+ else
+ /* Write out an add or change */
+ {
+ switch (D_NUMLINES (b, mapping[FILE0]))
+ {
+ case 0:
+ fprintf (outputfile, "%da\n",
+ D_HIGHLINE (b, mapping[FILE0]));
+ break;
+ case 1:
+ fprintf (outputfile, "%dc\n",
+ D_HIGHLINE (b, mapping[FILE0]));
+ break;
+ default:
+ fprintf (outputfile, "%d,%dc\n",
+ D_LOWLINE (b, mapping[FILE0]),
+ D_HIGHLINE (b, mapping[FILE0]));
+ break;
+ }
+
+ undotlines (outputfile, dotlines (outputfile, b, mapping[FILE2]),
+ D_LOWLINE (b, mapping[FILE0]),
+ D_NUMLINES (b, mapping[FILE2]));
+ }
+ }
+ if (finalwrite) fprintf (outputfile, "w\nq\n");
+ return conflicts_found;
+}
+
+/*
+ * Read from INFILE and output to OUTPUTFILE a set of diff3_ blocks DIFF
+ * as a merged file. This acts like 'ed file0 <[output_diff3_edscript]',
+ * except that it works even for binary data or incomplete lines.
+ *
+ * As before, MAPPING maps from arg list file number to diff file number,
+ * REV_MAPPING is its inverse,
+ * and FILE0, FILE1, and FILE2 are the names of the files.
+ *
+ * Returns 1 if conflicts were found.
+ */
+
+static int
+output_diff3_merge (infile, outputfile, diff, mapping, rev_mapping,
+ file0, file1, file2)
+ FILE *infile, *outputfile;
+ struct diff3_block *diff;
+ int const mapping[3], rev_mapping[3];
+ char const *file0, *file1, *file2;
+{
+ int c, i;
+ int conflicts_found = 0, conflict;
+ struct diff3_block *b;
+ int linesread = 0;
+
+ for (b = diff; b; b = b->next)
+ {
+ /* Must do mapping correctly. */
+ enum diff_type type
+ = ((b->correspond == DIFF_ALL) ?
+ DIFF_ALL :
+ ((enum diff_type)
+ (((int) DIFF_1ST)
+ + rev_mapping[(int) b->correspond - (int) DIFF_1ST])));
+ char const *format_2nd = "<<<<<<< %s\n";
+
+ /* If we aren't supposed to do this output block, skip it. */
+ switch (type)
+ {
+ default: continue;
+ case DIFF_2ND: if (!show_2nd) continue; conflict = 1; break;
+ case DIFF_3RD: if (overlap_only) continue; conflict = 0; break;
+ case DIFF_ALL: if (simple_only) continue; conflict = flagging;
+ format_2nd = "||||||| %s\n";
+ break;
+ }
+
+ /* Copy I lines from file 0. */
+ i = D_LOWLINE (b, FILE0) - linesread - 1;
+ linesread += i;
+ while (0 <= --i)
+ do
+ {
+ c = getc (infile);
+ if (c == EOF)
+ if (ferror (infile))
+ perror_with_exit ("input file");
+ else if (feof (infile))
+ fatal ("input file shrank");
+ putc (c, outputfile);
+ }
+ while (c != '\n');
+
+ if (conflict)
+ {
+ conflicts_found = 1;
+
+ if (type == DIFF_ALL)
+ {
+ /* Put in lines from FILE0 with bracket. */
+ fprintf (outputfile, "<<<<<<< %s\n", file0);
+ for (i = 0;
+ i < D_NUMLINES (b, mapping[FILE0]);
+ i++)
+ fwrite (D_RELNUM (b, mapping[FILE0], i), sizeof (char),
+ D_RELLEN (b, mapping[FILE0], i), outputfile);
+ }
+
+ if (show_2nd)
+ {
+ /* Put in lines from FILE1 with bracket. */
+ fprintf (outputfile, format_2nd, file1);
+ for (i = 0;
+ i < D_NUMLINES (b, mapping[FILE1]);
+ i++)
+ fwrite (D_RELNUM (b, mapping[FILE1], i), sizeof (char),
+ D_RELLEN (b, mapping[FILE1], i), outputfile);
+ }
+
+ fprintf (outputfile, "=======\n");
+ }
+
+ /* Put in lines from FILE2. */
+ for (i = 0;
+ i < D_NUMLINES (b, mapping[FILE2]);
+ i++)
+ fwrite (D_RELNUM (b, mapping[FILE2], i), sizeof (char),
+ D_RELLEN (b, mapping[FILE2], i), outputfile);
+
+ if (conflict)
+ fprintf (outputfile, ">>>>>>> %s\n", file2);
+
+ /* Skip I lines in file 0. */
+ i = D_NUMLINES (b, FILE0);
+ linesread += i;
+ while (0 <= --i)
+ while ((c = getc (infile)) != '\n')
+ if (c == EOF)
+ if (ferror (infile))
+ perror_with_exit ("input file");
+ else if (feof (infile))
+ {
+ if (i || b->next)
+ fatal ("input file shrank");
+ return conflicts_found;
+ }
+ }
+ /* Copy rest of common file. */
+ while ((c = getc (infile)) != EOF || !(ferror (infile) | feof (infile)))
+ putc (c, outputfile);
+ return conflicts_found;
+}
+
+/*
+ * Reverse the order of the list of diff3 blocks.
+ */
+static struct diff3_block *
+reverse_diff3_blocklist (diff)
+ struct diff3_block *diff;
+{
+ register struct diff3_block *tmp, *next, *prev;
+
+ for (tmp = diff, prev = 0; tmp; tmp = next)
+ {
+ next = tmp->next;
+ tmp->next = prev;
+ prev = tmp;
+ }
+
+ return prev;
+}
+
+static size_t
+myread (fd, ptr, size)
+ int fd;
+ char *ptr;
+ size_t size;
+{
+ size_t result = read (fd, ptr, size);
+ if (result == -1)
+ perror_with_exit ("read failed");
+ return result;
+}
+
+static VOID *
+xmalloc (size)
+ size_t size;
+{
+ VOID *result = (VOID *) malloc (size ? size : 1);
+ if (!result)
+ fatal ("memory exhausted");
+ return result;
+}
+
+static VOID *
+xrealloc (ptr, size)
+ VOID *ptr;
+ size_t size;
+{
+ VOID *result = (VOID *) realloc (ptr, size ? size : 1);
+ if (!result)
+ fatal ("memory exhausted");
+ return result;
+}
+
+static void
+fatal (string)
+ char const *string;
+{
+ fprintf (stderr, "%s: %s\n", program_name, string);
+ exit (2);
+}
+
+static void
+perror_with_exit (string)
+ char const *string;
+{
+ int e = errno;
+ fprintf (stderr, "%s: ", program_name);
+ errno = e;
+ perror (string);
+ exit (2);
+}
diff --git a/gnu/usr.bin/diff/dir.c b/gnu/usr.bin/diff/dir.c
new file mode 100644
index 0000000..036a86f
--- /dev/null
+++ b/gnu/usr.bin/diff/dir.c
@@ -0,0 +1,216 @@
+/* Read, sort and compare two directories. Used for GNU DIFF.
+ Copyright (C) 1988, 1989, 1992, 1993, 1994 Free Software Foundation, Inc.
+
+This file is part of GNU DIFF.
+
+GNU DIFF is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU DIFF is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU DIFF; see the file COPYING. If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "diff.h"
+
+/* Read the directory named by DIR and store into DIRDATA a sorted vector
+ of filenames for its contents. DIR->desc == -1 means this directory is
+ known to be nonexistent, so set DIRDATA to an empty vector.
+ Return -1 (setting errno) if error, 0 otherwise. */
+
+struct dirdata
+{
+ char const **names; /* Sorted names of files in dir, 0-terminated. */
+ char *data; /* Allocated storage for file names. */
+};
+
+static int compare_names PARAMS((void const *, void const *));
+static int dir_sort PARAMS((struct file_data const *, struct dirdata *));
+
+static int
+dir_sort (dir, dirdata)
+ struct file_data const *dir;
+ struct dirdata *dirdata;
+{
+ register struct dirent *next;
+ register int i;
+
+ /* Address of block containing the files that are described. */
+ char const **names;
+
+ /* Number of files in directory. */
+ size_t nnames;
+
+ /* Allocated and used storage for file name data. */
+ char *data;
+ size_t data_alloc, data_used;
+
+ dirdata->names = 0;
+ dirdata->data = 0;
+ nnames = 0;
+ data = 0;
+
+ if (dir->desc != -1)
+ {
+ /* Open the directory and check for errors. */
+ register DIR *reading = opendir (dir->name);
+ if (!reading)
+ return -1;
+
+ /* Initialize the table of filenames. */
+
+ data_alloc = max (1, (size_t) dir->stat.st_size);
+ data_used = 0;
+ dirdata->data = data = xmalloc (data_alloc);
+
+ /* Read the directory entries, and insert the subfiles
+ into the `data' table. */
+
+ while ((errno = 0, (next = readdir (reading)) != 0))
+ {
+ char *d_name = next->d_name;
+ size_t d_size = NAMLEN (next) + 1;
+
+ /* Ignore the files `.' and `..' */
+ if (d_name[0] == '.'
+ && (d_name[1] == 0 || (d_name[1] == '.' && d_name[2] == 0)))
+ continue;
+
+ if (excluded_filename (d_name))
+ continue;
+
+ while (data_alloc < data_used + d_size)
+ dirdata->data = data = xrealloc (data, data_alloc *= 2);
+ memcpy (data + data_used, d_name, d_size);
+ data_used += d_size;
+ nnames++;
+ }
+ if (errno)
+ {
+ int e = errno;
+ closedir (reading);
+ errno = e;
+ return -1;
+ }
+#if CLOSEDIR_VOID
+ closedir (reading);
+#else
+ if (closedir (reading) != 0)
+ return -1;
+#endif
+ }
+
+ /* Create the `names' table from the `data' table. */
+ dirdata->names = names = (char const **) xmalloc (sizeof (char *)
+ * (nnames + 1));
+ for (i = 0; i < nnames; i++)
+ {
+ names[i] = data;
+ data += strlen (data) + 1;
+ }
+ names[nnames] = 0;
+
+ /* Sort the table. */
+ qsort (names, nnames, sizeof (char *), compare_names);
+
+ return 0;
+}
+
+/* Sort the files now in the table. */
+
+static int
+compare_names (file1, file2)
+ void const *file1, *file2;
+{
+ return filename_cmp (* (char const *const *) file1,
+ * (char const *const *) file2);
+}
+
+/* Compare the contents of two directories named in FILEVEC[0] and FILEVEC[1].
+ This is a top-level routine; it does everything necessary for diff
+ on two directories.
+
+ FILEVEC[0].desc == -1 says directory FILEVEC[0] doesn't exist,
+ but pretend it is empty. Likewise for FILEVEC[1].
+
+ HANDLE_FILE is a caller-provided subroutine called to handle each file.
+ It gets five operands: dir and name (rel to original working dir) of file
+ in dir 0, dir and name pathname of file in dir 1, and the recursion depth.
+
+ For a file that appears in only one of the dirs, one of the name-args
+ to HANDLE_FILE is zero.
+
+ DEPTH is the current depth in recursion, used for skipping top-level
+ files by the -S option.
+
+ Returns the maximum of all the values returned by HANDLE_FILE,
+ or 2 if trouble is encountered in opening files. */
+
+int
+diff_dirs (filevec, handle_file, depth)
+ struct file_data const filevec[];
+ int (*handle_file) PARAMS((char const *, char const *, char const *, char const *, int));
+ int depth;
+{
+ struct dirdata dirdata[2];
+ int val = 0; /* Return value. */
+ int i;
+
+ /* Get sorted contents of both dirs. */
+ for (i = 0; i < 2; i++)
+ if (dir_sort (&filevec[i], &dirdata[i]) != 0)
+ {
+ perror_with_name (filevec[i].name);
+ val = 2;
+ }
+
+ if (val == 0)
+ {
+ register char const * const *names0 = dirdata[0].names;
+ register char const * const *names1 = dirdata[1].names;
+ char const *name0 = filevec[0].name;
+ char const *name1 = filevec[1].name;
+
+ /* If `-S name' was given, and this is the topmost level of comparison,
+ ignore all file names less than the specified starting name. */
+
+ if (dir_start_file && depth == 0)
+ {
+ while (*names0 && filename_cmp (*names0, dir_start_file) < 0)
+ names0++;
+ while (*names1 && filename_cmp (*names1, dir_start_file) < 0)
+ names1++;
+ }
+
+ /* Loop while files remain in one or both dirs. */
+ while (*names0 || *names1)
+ {
+ /* Compare next name in dir 0 with next name in dir 1.
+ At the end of a dir,
+ pretend the "next name" in that dir is very large. */
+ int nameorder = (!*names0 ? 1 : !*names1 ? -1
+ : filename_cmp (*names0, *names1));
+ int v1 = (*handle_file) (name0, 0 < nameorder ? 0 : *names0++,
+ name1, nameorder < 0 ? 0 : *names1++,
+ depth + 1);
+ if (v1 > val)
+ val = v1;
+ }
+ }
+
+ for (i = 0; i < 2; i++)
+ {
+ if (dirdata[i].names)
+ free (dirdata[i].names);
+ if (dirdata[i].data)
+ free (dirdata[i].data);
+ }
+
+ return val;
+}
diff --git a/gnu/usr.bin/diff/doc/Makefile b/gnu/usr.bin/diff/doc/Makefile
new file mode 100644
index 0000000..033d464
--- /dev/null
+++ b/gnu/usr.bin/diff/doc/Makefile
@@ -0,0 +1,7 @@
+# $Id$
+
+INFO = diff
+
+.PATH: ${.CURDIR}/..
+
+.include <bsd.info.mk>
diff --git a/gnu/usr.bin/diff/ed.c b/gnu/usr.bin/diff/ed.c
new file mode 100644
index 0000000..24f7270
--- /dev/null
+++ b/gnu/usr.bin/diff/ed.c
@@ -0,0 +1,200 @@
+/* Output routines for ed-script format.
+ Copyright (C) 1988, 89, 91, 92, 93 Free Software Foundation, Inc.
+
+This file is part of GNU DIFF.
+
+GNU DIFF is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU DIFF is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU DIFF; see the file COPYING. If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "diff.h"
+
+static void print_ed_hunk PARAMS((struct change *));
+static void print_rcs_hunk PARAMS((struct change *));
+static void pr_forward_ed_hunk PARAMS((struct change *));
+
+/* Print our script as ed commands. */
+
+void
+print_ed_script (script)
+ struct change *script;
+{
+ print_script (script, find_reverse_change, print_ed_hunk);
+}
+
+/* Print a hunk of an ed diff */
+
+static void
+print_ed_hunk (hunk)
+ struct change *hunk;
+{
+ int f0, l0, f1, l1;
+ int deletes, inserts;
+
+#if 0
+ hunk = flip_script (hunk);
+#endif
+#ifdef DEBUG
+ debug_script (hunk);
+#endif
+
+ /* Determine range of line numbers involved in each file. */
+ analyze_hunk (hunk, &f0, &l0, &f1, &l1, &deletes, &inserts);
+ if (!deletes && !inserts)
+ return;
+
+ begin_output ();
+
+ /* Print out the line number header for this hunk */
+ print_number_range (',', &files[0], f0, l0);
+ fprintf (outfile, "%c\n", change_letter (inserts, deletes));
+
+ /* Print new/changed lines from second file, if needed */
+ if (inserts)
+ {
+ int i;
+ int inserting = 1;
+ for (i = f1; i <= l1; i++)
+ {
+ /* Resume the insert, if we stopped. */
+ if (! inserting)
+ fprintf (outfile, "%da\n",
+ i - f1 + translate_line_number (&files[0], f0) - 1);
+ inserting = 1;
+
+ /* If the file's line is just a dot, it would confuse `ed'.
+ So output it with a double dot, and set the flag LEADING_DOT
+ so that we will output another ed-command later
+ to change the double dot into a single dot. */
+
+ if (files[1].linbuf[i][0] == '.'
+ && files[1].linbuf[i][1] == '\n')
+ {
+ fprintf (outfile, "..\n");
+ fprintf (outfile, ".\n");
+ /* Now change that double dot to the desired single dot. */
+ fprintf (outfile, "%ds/^\\.\\././\n",
+ i - f1 + translate_line_number (&files[0], f0));
+ inserting = 0;
+ }
+ else
+ /* Line is not `.', so output it unmodified. */
+ print_1_line ("", &files[1].linbuf[i]);
+ }
+
+ /* End insert mode, if we are still in it. */
+ if (inserting)
+ fprintf (outfile, ".\n");
+ }
+}
+
+/* Print change script in the style of ed commands,
+ but print the changes in the order they appear in the input files,
+ which means that the commands are not truly useful with ed. */
+
+void
+pr_forward_ed_script (script)
+ struct change *script;
+{
+ print_script (script, find_change, pr_forward_ed_hunk);
+}
+
+static void
+pr_forward_ed_hunk (hunk)
+ struct change *hunk;
+{
+ int i;
+ int f0, l0, f1, l1;
+ int deletes, inserts;
+
+ /* Determine range of line numbers involved in each file. */
+ analyze_hunk (hunk, &f0, &l0, &f1, &l1, &deletes, &inserts);
+ if (!deletes && !inserts)
+ return;
+
+ begin_output ();
+
+ fprintf (outfile, "%c", change_letter (inserts, deletes));
+ print_number_range (' ', files, f0, l0);
+ fprintf (outfile, "\n");
+
+ /* If deletion only, print just the number range. */
+
+ if (!inserts)
+ return;
+
+ /* For insertion (with or without deletion), print the number range
+ and the lines from file 2. */
+
+ for (i = f1; i <= l1; i++)
+ print_1_line ("", &files[1].linbuf[i]);
+
+ fprintf (outfile, ".\n");
+}
+
+/* Print in a format somewhat like ed commands
+ except that each insert command states the number of lines it inserts.
+ This format is used for RCS. */
+
+void
+print_rcs_script (script)
+ struct change *script;
+{
+ print_script (script, find_change, print_rcs_hunk);
+}
+
+/* Print a hunk of an RCS diff */
+
+static void
+print_rcs_hunk (hunk)
+ struct change *hunk;
+{
+ int i;
+ int f0, l0, f1, l1;
+ int deletes, inserts;
+ int tf0, tl0, tf1, tl1;
+
+ /* Determine range of line numbers involved in each file. */
+ analyze_hunk (hunk, &f0, &l0, &f1, &l1, &deletes, &inserts);
+ if (!deletes && !inserts)
+ return;
+
+ begin_output ();
+
+ translate_range (&files[0], f0, l0, &tf0, &tl0);
+
+ if (deletes)
+ {
+ fprintf (outfile, "d");
+ /* For deletion, print just the starting line number from file 0
+ and the number of lines deleted. */
+ fprintf (outfile, "%d %d\n",
+ tf0,
+ (tl0 >= tf0 ? tl0 - tf0 + 1 : 1));
+ }
+
+ if (inserts)
+ {
+ fprintf (outfile, "a");
+
+ /* Take last-line-number from file 0 and # lines from file 1. */
+ translate_range (&files[1], f1, l1, &tf1, &tl1);
+ fprintf (outfile, "%d %d\n",
+ tl0,
+ (tl1 >= tf1 ? tl1 - tf1 + 1 : 1));
+
+ /* Print the inserted lines. */
+ for (i = f1; i <= l1; i++)
+ print_1_line ("", &files[1].linbuf[i]);
+ }
+}
diff --git a/gnu/usr.bin/diff/getopt.c b/gnu/usr.bin/diff/getopt.c
new file mode 100644
index 0000000..c951bd4
--- /dev/null
+++ b/gnu/usr.bin/diff/getopt.c
@@ -0,0 +1,748 @@
+/* Getopt for GNU.
+ NOTE: getopt is now part of the C library, so if you don't know what
+ "Keep this file name-space clean" means, talk to roland@gnu.ai.mit.edu
+ before changing it!
+
+ Copyright (C) 1987, 88, 89, 90, 91, 92, 93, 94
+ Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any
+ later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* This tells Alpha OSF/1 not to define a getopt prototype in <stdio.h>.
+ Ditto for AIX 3.2 and <stdlib.h>. */
+#ifndef _NO_PROTO
+#define _NO_PROTO
+#endif
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifndef __STDC__
+/* This is a separate conditional since some stdc systems
+ reject `defined (const)'. */
+#ifndef const
+#define const
+#endif
+#endif
+
+#include <stdio.h>
+
+/* Comment out all this code if we are using the GNU C Library, and are not
+ actually compiling the library itself. This code is part of the GNU C
+ Library, but also included in many other GNU distributions. Compiling
+ and linking in this code is a waste when using the GNU C library
+ (especially if it is a shared library). Rather than having every GNU
+ program understand `configure --with-gnu-libc' and omit the object files,
+ it is simpler to just do this in the source for each such file. */
+
+#if defined (_LIBC) || !defined (__GNU_LIBRARY__)
+
+
+/* This needs to come after some library #include
+ to get __GNU_LIBRARY__ defined. */
+#ifdef __GNU_LIBRARY__
+/* Don't include stdlib.h for non-GNU C libraries because some of them
+ contain conflicting prototypes for getopt. */
+#include <stdlib.h>
+#endif /* GNU C library. */
+
+/* This version of `getopt' appears to the caller like standard Unix `getopt'
+ but it behaves differently for the user, since it allows the user
+ to intersperse the options with the other arguments.
+
+ As `getopt' works, it permutes the elements of ARGV so that,
+ when it is done, all the options precede everything else. Thus
+ all application programs are extended to handle flexible argument order.
+
+ Setting the environment variable POSIXLY_CORRECT disables permutation.
+ Then the behavior is completely standard.
+
+ GNU application programs can use a third alternative mode in which
+ they can distinguish the relative order of options and other arguments. */
+
+#include "getopt.h"
+
+/* For communication from `getopt' to the caller.
+ When `getopt' finds an option that takes an argument,
+ the argument value is returned here.
+ Also, when `ordering' is RETURN_IN_ORDER,
+ each non-option ARGV-element is returned here. */
+
+char *optarg = NULL;
+
+/* Index in ARGV of the next element to be scanned.
+ This is used for communication to and from the caller
+ and for communication between successive calls to `getopt'.
+
+ On entry to `getopt', zero means this is the first call; initialize.
+
+ When `getopt' returns EOF, this is the index of the first of the
+ non-option elements that the caller should itself scan.
+
+ Otherwise, `optind' communicates from one call to the next
+ how much of ARGV has been scanned so far. */
+
+/* XXX 1003.2 says this must be 1 before any call. */
+int optind = 0;
+
+/* The next char to be scanned in the option-element
+ in which the last option character we returned was found.
+ This allows us to pick up the scan where we left off.
+
+ If this is zero, or a null string, it means resume the scan
+ by advancing to the next ARGV-element. */
+
+static char *nextchar;
+
+/* Callers store zero here to inhibit the error message
+ for unrecognized options. */
+
+int opterr = 1;
+
+/* Set to an option character which was unrecognized.
+ This must be initialized on some systems to avoid linking in the
+ system's own getopt implementation. */
+
+int optopt = '?';
+
+/* Describe how to deal with options that follow non-option ARGV-elements.
+
+ If the caller did not specify anything,
+ the default is REQUIRE_ORDER if the environment variable
+ POSIXLY_CORRECT is defined, PERMUTE otherwise.
+
+ REQUIRE_ORDER means don't recognize them as options;
+ stop option processing when the first non-option is seen.
+ This is what Unix does.
+ This mode of operation is selected by either setting the environment
+ variable POSIXLY_CORRECT, or using `+' as the first character
+ of the list of option characters.
+
+ PERMUTE is the default. We permute the contents of ARGV as we scan,
+ so that eventually all the non-options are at the end. This allows options
+ to be given in any order, even with programs that were not written to
+ expect this.
+
+ RETURN_IN_ORDER is an option available to programs that were written
+ to expect options and other ARGV-elements in any order and that care about
+ the ordering of the two. We describe each non-option ARGV-element
+ as if it were the argument of an option with character code 1.
+ Using `-' as the first character of the list of option characters
+ selects this mode of operation.
+
+ The special argument `--' forces an end of option-scanning regardless
+ of the value of `ordering'. In the case of RETURN_IN_ORDER, only
+ `--' can cause `getopt' to return EOF with `optind' != ARGC. */
+
+static enum
+{
+ REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER
+} ordering;
+
+/* Value of POSIXLY_CORRECT environment variable. */
+static char *posixly_correct;
+
+#ifdef __GNU_LIBRARY__
+/* We want to avoid inclusion of string.h with non-GNU libraries
+ because there are many ways it can cause trouble.
+ On some systems, it contains special magic macros that don't work
+ in GCC. */
+#include <string.h>
+#define my_index strchr
+#else
+
+/* Avoid depending on library functions or files
+ whose names are inconsistent. */
+
+char *getenv ();
+
+static char *
+my_index (str, chr)
+ const char *str;
+ int chr;
+{
+ while (*str)
+ {
+ if (*str == chr)
+ return (char *) str;
+ str++;
+ }
+ return 0;
+}
+
+/* If using GCC, we can safely declare strlen this way.
+ If not using GCC, it is ok not to declare it. */
+#ifdef __GNUC__
+/* Note that Motorola Delta 68k R3V7 comes with GCC but not stddef.h.
+ That was relevant to code that was here before. */
+#ifndef __STDC__
+/* gcc with -traditional declares the built-in strlen to return int,
+ and has done so at least since version 2.4.5. -- rms. */
+extern int strlen (const char *);
+#endif /* not __STDC__ */
+#endif /* __GNUC__ */
+
+#endif /* not __GNU_LIBRARY__ */
+
+/* Handle permutation of arguments. */
+
+/* Describe the part of ARGV that contains non-options that have
+ been skipped. `first_nonopt' is the index in ARGV of the first of them;
+ `last_nonopt' is the index after the last of them. */
+
+static int first_nonopt;
+static int last_nonopt;
+
+/* Exchange two adjacent subsequences of ARGV.
+ One subsequence is elements [first_nonopt,last_nonopt)
+ which contains all the non-options that have been skipped so far.
+ The other is elements [last_nonopt,optind), which contains all
+ the options processed since those non-options were skipped.
+
+ `first_nonopt' and `last_nonopt' are relocated so that they describe
+ the new indices of the non-options in ARGV after they are moved. */
+
+static void
+exchange (argv)
+ char **argv;
+{
+ int bottom = first_nonopt;
+ int middle = last_nonopt;
+ int top = optind;
+ char *tem;
+
+ /* Exchange the shorter segment with the far end of the longer segment.
+ That puts the shorter segment into the right place.
+ It leaves the longer segment in the right place overall,
+ but it consists of two parts that need to be swapped next. */
+
+ while (top > middle && middle > bottom)
+ {
+ if (top - middle > middle - bottom)
+ {
+ /* Bottom segment is the short one. */
+ int len = middle - bottom;
+ register int i;
+
+ /* Swap it with the top part of the top segment. */
+ for (i = 0; i < len; i++)
+ {
+ tem = argv[bottom + i];
+ argv[bottom + i] = argv[top - (middle - bottom) + i];
+ argv[top - (middle - bottom) + i] = tem;
+ }
+ /* Exclude the moved bottom segment from further swapping. */
+ top -= len;
+ }
+ else
+ {
+ /* Top segment is the short one. */
+ int len = top - middle;
+ register int i;
+
+ /* Swap it with the bottom part of the bottom segment. */
+ for (i = 0; i < len; i++)
+ {
+ tem = argv[bottom + i];
+ argv[bottom + i] = argv[middle + i];
+ argv[middle + i] = tem;
+ }
+ /* Exclude the moved top segment from further swapping. */
+ bottom += len;
+ }
+ }
+
+ /* Update records for the slots the non-options now occupy. */
+
+ first_nonopt += (optind - last_nonopt);
+ last_nonopt = optind;
+}
+
+/* Initialize the internal data when the first call is made. */
+
+static const char *
+_getopt_initialize (optstring)
+ const char *optstring;
+{
+ /* Start processing options with ARGV-element 1 (since ARGV-element 0
+ is the program name); the sequence of previously skipped
+ non-option ARGV-elements is empty. */
+
+ first_nonopt = last_nonopt = optind = 1;
+
+ nextchar = NULL;
+
+ posixly_correct = getenv ("POSIXLY_CORRECT");
+
+ /* Determine how to handle the ordering of options and nonoptions. */
+
+ if (optstring[0] == '-')
+ {
+ ordering = RETURN_IN_ORDER;
+ ++optstring;
+ }
+ else if (optstring[0] == '+')
+ {
+ ordering = REQUIRE_ORDER;
+ ++optstring;
+ }
+ else if (posixly_correct != NULL)
+ ordering = REQUIRE_ORDER;
+ else
+ ordering = PERMUTE;
+
+ return optstring;
+}
+
+/* Scan elements of ARGV (whose length is ARGC) for option characters
+ given in OPTSTRING.
+
+ If an element of ARGV starts with '-', and is not exactly "-" or "--",
+ then it is an option element. The characters of this element
+ (aside from the initial '-') are option characters. If `getopt'
+ is called repeatedly, it returns successively each of the option characters
+ from each of the option elements.
+
+ If `getopt' finds another option character, it returns that character,
+ updating `optind' and `nextchar' so that the next call to `getopt' can
+ resume the scan with the following option character or ARGV-element.
+
+ If there are no more option characters, `getopt' returns `EOF'.
+ Then `optind' is the index in ARGV of the first ARGV-element
+ that is not an option. (The ARGV-elements have been permuted
+ so that those that are not options now come last.)
+
+ OPTSTRING is a string containing the legitimate option characters.
+ If an option character is seen that is not listed in OPTSTRING,
+ return '?' after printing an error message. If you set `opterr' to
+ zero, the error message is suppressed but we still return '?'.
+
+ If a char in OPTSTRING is followed by a colon, that means it wants an arg,
+ so the following text in the same ARGV-element, or the text of the following
+ ARGV-element, is returned in `optarg'. Two colons mean an option that
+ wants an optional arg; if there is text in the current ARGV-element,
+ it is returned in `optarg', otherwise `optarg' is set to zero.
+
+ If OPTSTRING starts with `-' or `+', it requests different methods of
+ handling the non-option ARGV-elements.
+ See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above.
+
+ Long-named options begin with `--' instead of `-'.
+ Their names may be abbreviated as long as the abbreviation is unique
+ or is an exact match for some defined option. If they have an
+ argument, it follows the option name in the same ARGV-element, separated
+ from the option name by a `=', or else the in next ARGV-element.
+ When `getopt' finds a long-named option, it returns 0 if that option's
+ `flag' field is nonzero, the value of the option's `val' field
+ if the `flag' field is zero.
+
+ The elements of ARGV aren't really const, because we permute them.
+ But we pretend they're const in the prototype to be compatible
+ with other systems.
+
+ LONGOPTS is a vector of `struct option' terminated by an
+ element containing a name which is zero.
+
+ LONGIND returns the index in LONGOPT of the long-named option found.
+ It is only valid when a long-named option has been found by the most
+ recent call.
+
+ If LONG_ONLY is nonzero, '-' as well as '--' can introduce
+ long-named options. */
+
+int
+_getopt_internal (argc, argv, optstring, longopts, longind, long_only)
+ int argc;
+ char *const *argv;
+ const char *optstring;
+ const struct option *longopts;
+ int *longind;
+ int long_only;
+{
+ optarg = NULL;
+
+ if (optind == 0)
+ optstring = _getopt_initialize (optstring);
+
+ if (nextchar == NULL || *nextchar == '\0')
+ {
+ /* Advance to the next ARGV-element. */
+
+ if (ordering == PERMUTE)
+ {
+ /* If we have just processed some options following some non-options,
+ exchange them so that the options come first. */
+
+ if (first_nonopt != last_nonopt && last_nonopt != optind)
+ exchange ((char **) argv);
+ else if (last_nonopt != optind)
+ first_nonopt = optind;
+
+ /* Skip any additional non-options
+ and extend the range of non-options previously skipped. */
+
+ while (optind < argc
+ && (argv[optind][0] != '-' || argv[optind][1] == '\0'))
+ optind++;
+ last_nonopt = optind;
+ }
+
+ /* The special ARGV-element `--' means premature end of options.
+ Skip it like a null option,
+ then exchange with previous non-options as if it were an option,
+ then skip everything else like a non-option. */
+
+ if (optind != argc && !strcmp (argv[optind], "--"))
+ {
+ optind++;
+
+ if (first_nonopt != last_nonopt && last_nonopt != optind)
+ exchange ((char **) argv);
+ else if (first_nonopt == last_nonopt)
+ first_nonopt = optind;
+ last_nonopt = argc;
+
+ optind = argc;
+ }
+
+ /* If we have done all the ARGV-elements, stop the scan
+ and back over any non-options that we skipped and permuted. */
+
+ if (optind == argc)
+ {
+ /* Set the next-arg-index to point at the non-options
+ that we previously skipped, so the caller will digest them. */
+ if (first_nonopt != last_nonopt)
+ optind = first_nonopt;
+ return EOF;
+ }
+
+ /* If we have come to a non-option and did not permute it,
+ either stop the scan or describe it to the caller and pass it by. */
+
+ if ((argv[optind][0] != '-' || argv[optind][1] == '\0'))
+ {
+ if (ordering == REQUIRE_ORDER)
+ return EOF;
+ optarg = argv[optind++];
+ return 1;
+ }
+
+ /* We have found another option-ARGV-element.
+ Skip the initial punctuation. */
+
+ nextchar = (argv[optind] + 1
+ + (longopts != NULL && argv[optind][1] == '-'));
+ }
+
+ /* Decode the current option-ARGV-element. */
+
+ /* Check whether the ARGV-element is a long option.
+
+ If long_only and the ARGV-element has the form "-f", where f is
+ a valid short option, don't consider it an abbreviated form of
+ a long option that starts with f. Otherwise there would be no
+ way to give the -f short option.
+
+ On the other hand, if there's a long option "fubar" and
+ the ARGV-element is "-fu", do consider that an abbreviation of
+ the long option, just like "--fu", and not "-f" with arg "u".
+
+ This distinction seems to be the most useful approach. */
+
+ if (longopts != NULL
+ && (argv[optind][1] == '-'
+ || (long_only && (argv[optind][2] || !my_index (optstring, argv[optind][1])))))
+ {
+ char *nameend;
+ const struct option *p;
+ const struct option *pfound = NULL;
+ int exact = 0;
+ int ambig = 0;
+ int indfound;
+ int option_index;
+
+ for (nameend = nextchar; *nameend && *nameend != '='; nameend++)
+ /* Do nothing. */ ;
+
+ /* Test all long options for either exact match
+ or abbreviated matches. */
+ for (p = longopts, option_index = 0; p->name; p++, option_index++)
+ if (!strncmp (p->name, nextchar, nameend - nextchar))
+ {
+ if (nameend - nextchar == strlen (p->name))
+ {
+ /* Exact match found. */
+ pfound = p;
+ indfound = option_index;
+ exact = 1;
+ break;
+ }
+ else if (pfound == NULL)
+ {
+ /* First nonexact match found. */
+ pfound = p;
+ indfound = option_index;
+ }
+ else
+ /* Second or later nonexact match found. */
+ ambig = 1;
+ }
+
+ if (ambig && !exact)
+ {
+ if (opterr)
+ fprintf (stderr, "%s: option `%s' is ambiguous\n",
+ argv[0], argv[optind]);
+ nextchar += strlen (nextchar);
+ optind++;
+ return '?';
+ }
+
+ if (pfound != NULL)
+ {
+ option_index = indfound;
+ optind++;
+ if (*nameend)
+ {
+ /* Don't test has_arg with >, because some C compilers don't
+ allow it to be used on enums. */
+ if (pfound->has_arg)
+ optarg = nameend + 1;
+ else
+ {
+ if (opterr)
+ {
+ if (argv[optind - 1][1] == '-')
+ /* --option */
+ fprintf (stderr,
+ "%s: option `--%s' doesn't allow an argument\n",
+ argv[0], pfound->name);
+ else
+ /* +option or -option */
+ fprintf (stderr,
+ "%s: option `%c%s' doesn't allow an argument\n",
+ argv[0], argv[optind - 1][0], pfound->name);
+ }
+ nextchar += strlen (nextchar);
+ return '?';
+ }
+ }
+ else if (pfound->has_arg == 1)
+ {
+ if (optind < argc)
+ optarg = argv[optind++];
+ else
+ {
+ if (opterr)
+ fprintf (stderr, "%s: option `%s' requires an argument\n",
+ argv[0], argv[optind - 1]);
+ nextchar += strlen (nextchar);
+ return optstring[0] == ':' ? ':' : '?';
+ }
+ }
+ nextchar += strlen (nextchar);
+ if (longind != NULL)
+ *longind = option_index;
+ if (pfound->flag)
+ {
+ *(pfound->flag) = pfound->val;
+ return 0;
+ }
+ return pfound->val;
+ }
+
+ /* Can't find it as a long option. If this is not getopt_long_only,
+ or the option starts with '--' or is not a valid short
+ option, then it's an error.
+ Otherwise interpret it as a short option. */
+ if (!long_only || argv[optind][1] == '-'
+ || my_index (optstring, *nextchar) == NULL)
+ {
+ if (opterr)
+ {
+ if (argv[optind][1] == '-')
+ /* --option */
+ fprintf (stderr, "%s: unrecognized option `--%s'\n",
+ argv[0], nextchar);
+ else
+ /* +option or -option */
+ fprintf (stderr, "%s: unrecognized option `%c%s'\n",
+ argv[0], argv[optind][0], nextchar);
+ }
+ nextchar = (char *) "";
+ optind++;
+ return '?';
+ }
+ }
+
+ /* Look at and handle the next short option-character. */
+
+ {
+ char c = *nextchar++;
+ char *temp = my_index (optstring, c);
+
+ /* Increment `optind' when we start to process its last character. */
+ if (*nextchar == '\0')
+ ++optind;
+
+ if (temp == NULL || c == ':')
+ {
+ if (opterr)
+ {
+ if (posixly_correct)
+ /* 1003.2 specifies the format of this message. */
+ fprintf (stderr, "%s: illegal option -- %c\n", argv[0], c);
+ else
+ fprintf (stderr, "%s: invalid option -- %c\n", argv[0], c);
+ }
+ optopt = c;
+ return '?';
+ }
+ if (temp[1] == ':')
+ {
+ if (temp[2] == ':')
+ {
+ /* This is an option that accepts an argument optionally. */
+ if (*nextchar != '\0')
+ {
+ optarg = nextchar;
+ optind++;
+ }
+ else
+ optarg = NULL;
+ nextchar = NULL;
+ }
+ else
+ {
+ /* This is an option that requires an argument. */
+ if (*nextchar != '\0')
+ {
+ optarg = nextchar;
+ /* If we end this ARGV-element by taking the rest as an arg,
+ we must advance to the next element now. */
+ optind++;
+ }
+ else if (optind == argc)
+ {
+ if (opterr)
+ {
+ /* 1003.2 specifies the format of this message. */
+ fprintf (stderr, "%s: option requires an argument -- %c\n",
+ argv[0], c);
+ }
+ optopt = c;
+ if (optstring[0] == ':')
+ c = ':';
+ else
+ c = '?';
+ }
+ else
+ /* We already incremented `optind' once;
+ increment it again when taking next ARGV-elt as argument. */
+ optarg = argv[optind++];
+ nextchar = NULL;
+ }
+ }
+ return c;
+ }
+}
+
+int
+getopt (argc, argv, optstring)
+ int argc;
+ char *const *argv;
+ const char *optstring;
+{
+ return _getopt_internal (argc, argv, optstring,
+ (const struct option *) 0,
+ (int *) 0,
+ 0);
+}
+
+#endif /* _LIBC or not __GNU_LIBRARY__. */
+
+#ifdef TEST
+
+/* Compile with -DTEST to make an executable for use in testing
+ the above definition of `getopt'. */
+
+int
+main (argc, argv)
+ int argc;
+ char **argv;
+{
+ int c;
+ int digit_optind = 0;
+
+ while (1)
+ {
+ int this_option_optind = optind ? optind : 1;
+
+ c = getopt (argc, argv, "abc:d:0123456789");
+ if (c == EOF)
+ break;
+
+ switch (c)
+ {
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ if (digit_optind != 0 && digit_optind != this_option_optind)
+ printf ("digits occur in two different argv-elements.\n");
+ digit_optind = this_option_optind;
+ printf ("option %c\n", c);
+ break;
+
+ case 'a':
+ printf ("option a\n");
+ break;
+
+ case 'b':
+ printf ("option b\n");
+ break;
+
+ case 'c':
+ printf ("option c with value `%s'\n", optarg);
+ break;
+
+ case '?':
+ break;
+
+ default:
+ printf ("?? getopt returned character code 0%o ??\n", c);
+ }
+ }
+
+ if (optind < argc)
+ {
+ printf ("non-option ARGV-elements: ");
+ while (optind < argc)
+ printf ("%s ", argv[optind++]);
+ printf ("\n");
+ }
+
+ exit (0);
+}
+
+#endif /* TEST */
diff --git a/gnu/usr.bin/diff/getopt.h b/gnu/usr.bin/diff/getopt.h
new file mode 100644
index 0000000..45541f5
--- /dev/null
+++ b/gnu/usr.bin/diff/getopt.h
@@ -0,0 +1,129 @@
+/* Declarations for getopt.
+ Copyright (C) 1989, 1990, 1991, 1992, 1993 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any
+ later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#ifndef _GETOPT_H
+#define _GETOPT_H 1
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* For communication from `getopt' to the caller.
+ When `getopt' finds an option that takes an argument,
+ the argument value is returned here.
+ Also, when `ordering' is RETURN_IN_ORDER,
+ each non-option ARGV-element is returned here. */
+
+extern char *optarg;
+
+/* Index in ARGV of the next element to be scanned.
+ This is used for communication to and from the caller
+ and for communication between successive calls to `getopt'.
+
+ On entry to `getopt', zero means this is the first call; initialize.
+
+ When `getopt' returns EOF, this is the index of the first of the
+ non-option elements that the caller should itself scan.
+
+ Otherwise, `optind' communicates from one call to the next
+ how much of ARGV has been scanned so far. */
+
+extern int optind;
+
+/* Callers store zero here to inhibit the error message `getopt' prints
+ for unrecognized options. */
+
+extern int opterr;
+
+/* Set to an option character which was unrecognized. */
+
+extern int optopt;
+
+/* Describe the long-named options requested by the application.
+ The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector
+ of `struct option' terminated by an element containing a name which is
+ zero.
+
+ The field `has_arg' is:
+ no_argument (or 0) if the option does not take an argument,
+ required_argument (or 1) if the option requires an argument,
+ optional_argument (or 2) if the option takes an optional argument.
+
+ If the field `flag' is not NULL, it points to a variable that is set
+ to the value given in the field `val' when the option is found, but
+ left unchanged if the option is not found.
+
+ To have a long-named option do something other than set an `int' to
+ a compiled-in constant, such as set a value from `optarg', set the
+ option's `flag' field to zero and its `val' field to a nonzero
+ value (the equivalent single-letter option character, if there is
+ one). For long options that have a zero `flag' field, `getopt'
+ returns the contents of the `val' field. */
+
+struct option
+{
+#if __STDC__
+ const char *name;
+#else
+ char *name;
+#endif
+ /* has_arg can't be an enum because some compilers complain about
+ type mismatches in all the code that assumes it is an int. */
+ int has_arg;
+ int *flag;
+ int val;
+};
+
+/* Names for the values of the `has_arg' field of `struct option'. */
+
+#define no_argument 0
+#define required_argument 1
+#define optional_argument 2
+
+#if __STDC__
+#if defined(__GNU_LIBRARY__)
+/* Many other libraries have conflicting prototypes for getopt, with
+ differences in the consts, in stdlib.h. To avoid compilation
+ errors, only prototype getopt for the GNU C library. */
+extern int getopt (int argc, char *const *argv, const char *shortopts);
+#else /* not __GNU_LIBRARY__ */
+extern int getopt ();
+#endif /* not __GNU_LIBRARY__ */
+extern int getopt_long (int argc, char *const *argv, const char *shortopts,
+ const struct option *longopts, int *longind);
+extern int getopt_long_only (int argc, char *const *argv,
+ const char *shortopts,
+ const struct option *longopts, int *longind);
+
+/* Internal only. Users should not call this directly. */
+extern int _getopt_internal (int argc, char *const *argv,
+ const char *shortopts,
+ const struct option *longopts, int *longind,
+ int long_only);
+#else /* not __STDC__ */
+extern int getopt ();
+extern int getopt_long ();
+extern int getopt_long_only ();
+
+extern int _getopt_internal ();
+#endif /* not __STDC__ */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _GETOPT_H */
diff --git a/gnu/usr.bin/diff/getopt1.c b/gnu/usr.bin/diff/getopt1.c
new file mode 100644
index 0000000..17ab331
--- /dev/null
+++ b/gnu/usr.bin/diff/getopt1.c
@@ -0,0 +1,180 @@
+/* getopt_long and getopt_long_only entry points for GNU getopt.
+ Copyright (C) 1987, 88, 89, 90, 91, 92, 1993
+ Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any
+ later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "getopt.h"
+
+#ifndef __STDC__
+/* This is a separate conditional since some stdc systems
+ reject `defined (const)'. */
+#ifndef const
+#define const
+#endif
+#endif
+
+#include <stdio.h>
+
+/* Comment out all this code if we are using the GNU C Library, and are not
+ actually compiling the library itself. This code is part of the GNU C
+ Library, but also included in many other GNU distributions. Compiling
+ and linking in this code is a waste when using the GNU C library
+ (especially if it is a shared library). Rather than having every GNU
+ program understand `configure --with-gnu-libc' and omit the object files,
+ it is simpler to just do this in the source for each such file. */
+
+#if defined (_LIBC) || !defined (__GNU_LIBRARY__)
+
+
+/* This needs to come after some library #include
+ to get __GNU_LIBRARY__ defined. */
+#ifdef __GNU_LIBRARY__
+#include <stdlib.h>
+#else
+char *getenv ();
+#endif
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+int
+getopt_long (argc, argv, options, long_options, opt_index)
+ int argc;
+ char *const *argv;
+ const char *options;
+ const struct option *long_options;
+ int *opt_index;
+{
+ return _getopt_internal (argc, argv, options, long_options, opt_index, 0);
+}
+
+/* Like getopt_long, but '-' as well as '--' can indicate a long option.
+ If an option that starts with '-' (not '--') doesn't match a long option,
+ but does match a short option, it is parsed as a short option
+ instead. */
+
+int
+getopt_long_only (argc, argv, options, long_options, opt_index)
+ int argc;
+ char *const *argv;
+ const char *options;
+ const struct option *long_options;
+ int *opt_index;
+{
+ return _getopt_internal (argc, argv, options, long_options, opt_index, 1);
+}
+
+
+#endif /* _LIBC or not __GNU_LIBRARY__. */
+
+#ifdef TEST
+
+#include <stdio.h>
+
+int
+main (argc, argv)
+ int argc;
+ char **argv;
+{
+ int c;
+ int digit_optind = 0;
+
+ while (1)
+ {
+ int this_option_optind = optind ? optind : 1;
+ int option_index = 0;
+ static struct option long_options[] =
+ {
+ {"add", 1, 0, 0},
+ {"append", 0, 0, 0},
+ {"delete", 1, 0, 0},
+ {"verbose", 0, 0, 0},
+ {"create", 0, 0, 0},
+ {"file", 1, 0, 0},
+ {0, 0, 0, 0}
+ };
+
+ c = getopt_long (argc, argv, "abc:d:0123456789",
+ long_options, &option_index);
+ if (c == EOF)
+ break;
+
+ switch (c)
+ {
+ case 0:
+ printf ("option %s", long_options[option_index].name);
+ if (optarg)
+ printf (" with arg %s", optarg);
+ printf ("\n");
+ break;
+
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ if (digit_optind != 0 && digit_optind != this_option_optind)
+ printf ("digits occur in two different argv-elements.\n");
+ digit_optind = this_option_optind;
+ printf ("option %c\n", c);
+ break;
+
+ case 'a':
+ printf ("option a\n");
+ break;
+
+ case 'b':
+ printf ("option b\n");
+ break;
+
+ case 'c':
+ printf ("option c with value `%s'\n", optarg);
+ break;
+
+ case 'd':
+ printf ("option d with value `%s'\n", optarg);
+ break;
+
+ case '?':
+ break;
+
+ default:
+ printf ("?? getopt returned character code 0%o ??\n", c);
+ }
+ }
+
+ if (optind < argc)
+ {
+ printf ("non-option ARGV-elements: ");
+ while (optind < argc)
+ printf ("%s ", argv[optind++]);
+ printf ("\n");
+ }
+
+ exit (0);
+}
+
+#endif /* TEST */
diff --git a/gnu/usr.bin/diff/ifdef.c b/gnu/usr.bin/diff/ifdef.c
new file mode 100644
index 0000000..2834cbd
--- /dev/null
+++ b/gnu/usr.bin/diff/ifdef.c
@@ -0,0 +1,428 @@
+/* #ifdef-format output routines for GNU DIFF.
+ Copyright (C) 1989, 1991, 1992, 1993, 1994 Free Software Foundation, Inc.
+
+This file is part of GNU DIFF.
+
+GNU DIFF is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY. No author or distributor
+accepts responsibility to anyone for the consequences of using it
+or for whether it serves any particular purpose or works at all,
+unless he says so in writing. Refer to the GNU DIFF General Public
+License for full details.
+
+Everyone is granted permission to copy, modify and redistribute
+GNU DIFF, but only under the conditions described in the
+GNU DIFF General Public License. A copy of this license is
+supposed to have been given to you along with GNU DIFF so you
+can know your rights and responsibilities. It should be in a
+file named COPYING. Among other things, the copyright notice
+and this notice must be preserved on all copies. */
+
+
+#include "diff.h"
+
+struct group
+{
+ struct file_data const *file;
+ int from, upto; /* start and limit lines for this group of lines */
+};
+
+static char *format_group PARAMS((FILE *, char *, int, struct group const *));
+static char *scan_char_literal PARAMS((char *, int *));
+static char *scan_printf_spec PARAMS((char *));
+static int groups_letter_value PARAMS((struct group const *, int));
+static void format_ifdef PARAMS((char *, int, int, int, int));
+static void print_ifdef_hunk PARAMS((struct change *));
+static void print_ifdef_lines PARAMS((FILE *, char *, struct group const *));
+
+static int next_line;
+
+/* Print the edit-script SCRIPT as a merged #ifdef file. */
+
+void
+print_ifdef_script (script)
+ struct change *script;
+{
+ next_line = - files[0].prefix_lines;
+ print_script (script, find_change, print_ifdef_hunk);
+ if (next_line < files[0].valid_lines)
+ {
+ begin_output ();
+ format_ifdef (group_format[UNCHANGED], next_line, files[0].valid_lines,
+ next_line - files[0].valid_lines + files[1].valid_lines,
+ files[1].valid_lines);
+ }
+}
+
+/* Print a hunk of an ifdef diff.
+ This is a contiguous portion of a complete edit script,
+ describing changes in consecutive lines. */
+
+static void
+print_ifdef_hunk (hunk)
+ struct change *hunk;
+{
+ int first0, last0, first1, last1, deletes, inserts;
+ char *format;
+
+ /* Determine range of line numbers involved in each file. */
+ analyze_hunk (hunk, &first0, &last0, &first1, &last1, &deletes, &inserts);
+ if (inserts)
+ format = deletes ? group_format[CHANGED] : group_format[NEW];
+ else if (deletes)
+ format = group_format[OLD];
+ else
+ return;
+
+ begin_output ();
+
+ /* Print lines up to this change. */
+ if (next_line < first0)
+ format_ifdef (group_format[UNCHANGED], next_line, first0,
+ next_line - first0 + first1, first1);
+
+ /* Print this change. */
+ next_line = last0 + 1;
+ format_ifdef (format, first0, next_line, first1, last1 + 1);
+}
+
+/* Print a set of lines according to FORMAT.
+ Lines BEG0 up to END0 are from the first file;
+ lines BEG1 up to END1 are from the second file. */
+
+static void
+format_ifdef (format, beg0, end0, beg1, end1)
+ char *format;
+ int beg0, end0, beg1, end1;
+{
+ struct group groups[2];
+
+ groups[0].file = &files[0];
+ groups[0].from = beg0;
+ groups[0].upto = end0;
+ groups[1].file = &files[1];
+ groups[1].from = beg1;
+ groups[1].upto = end1;
+ format_group (outfile, format, '\0', groups);
+}
+
+/* Print to file OUT a set of lines according to FORMAT.
+ The format ends at the first free instance of ENDCHAR.
+ Yield the address of the terminating character.
+ GROUPS specifies which lines to print.
+ If OUT is zero, do not actually print anything; just scan the format. */
+
+static char *
+format_group (out, format, endchar, groups)
+ register FILE *out;
+ char *format;
+ int endchar;
+ struct group const *groups;
+{
+ register char c;
+ register char *f = format;
+
+ while ((c = *f) != endchar && c != 0)
+ {
+ f++;
+ if (c == '%')
+ {
+ char *spec = f;
+ switch ((c = *f++))
+ {
+ case '%':
+ break;
+
+ case '(':
+ /* Print if-then-else format e.g. `%(n=1?thenpart:elsepart)'. */
+ {
+ int i, value[2];
+ FILE *thenout, *elseout;
+
+ for (i = 0; i < 2; i++)
+ {
+ unsigned char f0 = f[0];
+ if (ISDIGIT (f0))
+ {
+ value[i] = atoi (f);
+ while (ISDIGIT ((unsigned char) *++f))
+ continue;
+ }
+ else
+ {
+ value[i] = groups_letter_value (groups, f0);
+ if (value[i] < 0)
+ goto bad_format;
+ f++;
+ }
+ if (*f++ != "=?"[i])
+ goto bad_format;
+ }
+ if (value[0] == value[1])
+ thenout = out, elseout = 0;
+ else
+ thenout = 0, elseout = out;
+ f = format_group (thenout, f, ':', groups);
+ if (*f)
+ {
+ f = format_group (elseout, f + 1, ')', groups);
+ if (*f)
+ f++;
+ }
+ }
+ continue;
+
+ case '<':
+ /* Print lines deleted from first file. */
+ print_ifdef_lines (out, line_format[OLD], &groups[0]);
+ continue;
+
+ case '=':
+ /* Print common lines. */
+ print_ifdef_lines (out, line_format[UNCHANGED], &groups[0]);
+ continue;
+
+ case '>':
+ /* Print lines inserted from second file. */
+ print_ifdef_lines (out, line_format[NEW], &groups[1]);
+ continue;
+
+ default:
+ {
+ int value;
+ char *speclim;
+
+ f = scan_printf_spec (spec);
+ if (!f)
+ goto bad_format;
+ speclim = f;
+ c = *f++;
+ switch (c)
+ {
+ case '\'':
+ f = scan_char_literal (f, &value);
+ if (!f)
+ goto bad_format;
+ break;
+
+ default:
+ value = groups_letter_value (groups, c);
+ if (value < 0)
+ goto bad_format;
+ break;
+ }
+ if (out)
+ {
+ /* Temporarily replace e.g. "%3dnx" with "%3d\0x". */
+ *speclim = 0;
+ fprintf (out, spec - 1, value);
+ /* Undo the temporary replacement. */
+ *speclim = c;
+ }
+ }
+ continue;
+
+ bad_format:
+ c = '%';
+ f = spec;
+ break;
+ }
+ }
+ if (out)
+ putc (c, out);
+ }
+ return f;
+}
+
+/* For the line group pair G, return the number corresponding to LETTER.
+ Return -1 if LETTER is not a group format letter. */
+static int
+groups_letter_value (g, letter)
+ struct group const *g;
+ int letter;
+{
+ if (ISUPPER (letter))
+ {
+ g++;
+ letter = tolower (letter);
+ }
+ switch (letter)
+ {
+ case 'e': return translate_line_number (g->file, g->from) - 1;
+ case 'f': return translate_line_number (g->file, g->from);
+ case 'l': return translate_line_number (g->file, g->upto) - 1;
+ case 'm': return translate_line_number (g->file, g->upto);
+ case 'n': return g->upto - g->from;
+ default: return -1;
+ }
+}
+
+/* Print to file OUT, using FORMAT to print the line group GROUP.
+ But do nothing if OUT is zero. */
+static void
+print_ifdef_lines (out, format, group)
+ register FILE *out;
+ char *format;
+ struct group const *group;
+{
+ struct file_data const *file = group->file;
+ char const * const *linbuf = file->linbuf;
+ int from = group->from, upto = group->upto;
+
+ if (!out)
+ return;
+
+ /* If possible, use a single fwrite; it's faster. */
+ if (!tab_expand_flag && format[0] == '%')
+ {
+ if (format[1] == 'l' && format[2] == '\n' && !format[3])
+ {
+ fwrite (linbuf[from], sizeof (char),
+ linbuf[upto] + (linbuf[upto][-1] != '\n') - linbuf[from],
+ out);
+ return;
+ }
+ if (format[1] == 'L' && !format[2])
+ {
+ fwrite (linbuf[from], sizeof (char),
+ linbuf[upto] - linbuf[from], out);
+ return;
+ }
+ }
+
+ for (; from < upto; from++)
+ {
+ register char c;
+ register char *f = format;
+
+ while ((c = *f++) != 0)
+ {
+ if (c == '%')
+ {
+ char *spec = f;
+ switch ((c = *f++))
+ {
+ case '%':
+ break;
+
+ case 'l':
+ output_1_line (linbuf[from],
+ linbuf[from + 1]
+ - (linbuf[from + 1][-1] == '\n'), 0, 0);
+ continue;
+
+ case 'L':
+ output_1_line (linbuf[from], linbuf[from + 1], 0, 0);
+ continue;
+
+ default:
+ {
+ int value;
+ char *speclim;
+
+ f = scan_printf_spec (spec);
+ if (!f)
+ goto bad_format;
+ speclim = f;
+ c = *f++;
+ switch (c)
+ {
+ case '\'':
+ f = scan_char_literal (f, &value);
+ if (!f)
+ goto bad_format;
+ break;
+
+ case 'n':
+ value = translate_line_number (file, from);
+ break;
+
+ default:
+ goto bad_format;
+ }
+ /* Temporarily replace e.g. "%3dnx" with "%3d\0x". */
+ *speclim = 0;
+ fprintf (out, spec - 1, value);
+ /* Undo the temporary replacement. */
+ *speclim = c;
+ }
+ continue;
+
+ bad_format:
+ c = '%';
+ f = spec;
+ break;
+ }
+ }
+ putc (c, out);
+ }
+ }
+}
+
+/* Scan the character literal represented in the string LIT; LIT points just
+ after the initial apostrophe. Put the literal's value into *INTPTR.
+ Yield the address of the first character after the closing apostrophe,
+ or zero if the literal is ill-formed. */
+static char *
+scan_char_literal (lit, intptr)
+ char *lit;
+ int *intptr;
+{
+ register char *p = lit;
+ int value, digits;
+ char c = *p++;
+
+ switch (c)
+ {
+ case 0:
+ case '\'':
+ return 0;
+
+ case '\\':
+ value = 0;
+ while ((c = *p++) != '\'')
+ {
+ unsigned digit = c - '0';
+ if (8 <= digit)
+ return 0;
+ value = 8 * value + digit;
+ }
+ digits = p - lit - 2;
+ if (! (1 <= digits && digits <= 3))
+ return 0;
+ break;
+
+ default:
+ value = c;
+ if (*p++ != '\'')
+ return 0;
+ break;
+ }
+ *intptr = value;
+ return p;
+}
+
+/* Scan optional printf-style SPEC of the form `-*[0-9]*(.[0-9]*)?[cdoxX]'.
+ Return the address of the character following SPEC, or zero if failure. */
+static char *
+scan_printf_spec (spec)
+ register char *spec;
+{
+ register unsigned char c;
+
+ while ((c = *spec++) == '-')
+ continue;
+ while (ISDIGIT (c))
+ c = *spec++;
+ if (c == '.')
+ while (ISDIGIT (c = *spec++))
+ continue;
+ switch (c)
+ {
+ case 'c': case 'd': case 'o': case 'x': case 'X':
+ return spec;
+
+ default:
+ return 0;
+ }
+}
diff --git a/gnu/usr.bin/diff/io.c b/gnu/usr.bin/diff/io.c
new file mode 100644
index 0000000..6605915
--- /dev/null
+++ b/gnu/usr.bin/diff/io.c
@@ -0,0 +1,714 @@
+/* File I/O for GNU DIFF.
+ Copyright (C) 1988, 1989, 1992, 1993, 1994 Free Software Foundation, Inc.
+
+This file is part of GNU DIFF.
+
+GNU DIFF is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU DIFF is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU DIFF; see the file COPYING. If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "diff.h"
+
+/* Rotate a value n bits to the left. */
+#define UINT_BIT (sizeof (unsigned) * CHAR_BIT)
+#define ROL(v, n) ((v) << (n) | (v) >> (UINT_BIT - (n)))
+
+/* Given a hash value and a new character, return a new hash value. */
+#define HASH(h, c) ((c) + ROL (h, 7))
+
+/* Guess remaining number of lines from number N of lines so far,
+ size S so far, and total size T. */
+#define GUESS_LINES(n,s,t) (((t) - (s)) / ((n) < 10 ? 32 : (s) / ((n)-1)) + 5)
+
+/* Type used for fast prefix comparison in find_identical_ends. */
+#ifndef word
+#define word int
+#endif
+
+/* Lines are put into equivalence classes (of lines that match in line_cmp).
+ Each equivalence class is represented by one of these structures,
+ but only while the classes are being computed.
+ Afterward, each class is represented by a number. */
+struct equivclass
+{
+ int next; /* Next item in this bucket. */
+ unsigned hash; /* Hash of lines in this class. */
+ char const *line; /* A line that fits this class. */
+ size_t length; /* That line's length, not counting its newline. */
+};
+
+/* Hash-table: array of buckets, each being a chain of equivalence classes.
+ buckets[-1] is reserved for incomplete lines. */
+static int *buckets;
+
+/* Number of buckets in the hash table array, not counting buckets[-1]. */
+static int nbuckets;
+
+/* Array in which the equivalence classes are allocated.
+ The bucket-chains go through the elements in this array.
+ The number of an equivalence class is its index in this array. */
+static struct equivclass *equivs;
+
+/* Index of first free element in the array `equivs'. */
+static int equivs_index;
+
+/* Number of elements allocated in the array `equivs'. */
+static int equivs_alloc;
+
+static void find_and_hash_each_line PARAMS((struct file_data *));
+static void find_identical_ends PARAMS((struct file_data[]));
+static void prepare_text_end PARAMS((struct file_data *));
+
+/* Check for binary files and compare them for exact identity. */
+
+/* Return 1 if BUF contains a non text character.
+ SIZE is the number of characters in BUF. */
+
+#define binary_file_p(buf, size) (memchr (buf, '\0', size) != 0)
+
+/* Get ready to read the current file.
+ Return nonzero if SKIP_TEST is zero,
+ and if it appears to be a binary file. */
+
+int
+sip (current, skip_test)
+ struct file_data *current;
+ int skip_test;
+{
+ /* If we have a nonexistent file at this stage, treat it as empty. */
+ if (current->desc < 0)
+ {
+ /* Leave room for a sentinel. */
+ current->bufsize = sizeof (word);
+ current->buffer = xmalloc (current->bufsize);
+ }
+ else
+ {
+ current->bufsize = STAT_BLOCKSIZE (current->stat);
+ current->buffer = xmalloc (current->bufsize);
+
+ if (! skip_test)
+ {
+ /* Check first part of file to see if it's a binary file. */
+#if HAVE_SETMODE
+ int oldmode = setmode (current->desc, O_BINARY);
+#endif
+ size_t n = read (current->desc, current->buffer, current->bufsize);
+ if (n == -1)
+ pfatal_with_name (current->name);
+ current->buffered_chars = n;
+#if HAVE_SETMODE
+ if (oldmode != O_BINARY)
+ {
+ if (lseek (current->desc, - (off_t) n, SEEK_CUR) == -1)
+ pfatal_with_name (current->name);
+ setmode (current->desc, oldmode);
+ current->buffered_chars = 0;
+ }
+#endif
+ return binary_file_p (current->buffer, n);
+ }
+ }
+
+ current->buffered_chars = 0;
+ return 0;
+}
+
+/* Slurp the rest of the current file completely into memory. */
+
+void
+slurp (current)
+ struct file_data *current;
+{
+ size_t cc;
+
+ if (current->desc < 0)
+ /* The file is nonexistent. */
+ ;
+ else if (S_ISREG (current->stat.st_mode))
+ {
+ /* It's a regular file; slurp in the rest all at once. */
+
+ /* Get the size out of the stat block.
+ Allocate enough room for appended newline and sentinel. */
+ cc = current->stat.st_size + 1 + sizeof (word);
+ if (current->bufsize < cc)
+ {
+ current->bufsize = cc;
+ current->buffer = xrealloc (current->buffer, cc);
+ }
+
+ if (current->buffered_chars < current->stat.st_size)
+ {
+ cc = read (current->desc,
+ current->buffer + current->buffered_chars,
+ current->stat.st_size - current->buffered_chars);
+ if (cc == -1)
+ pfatal_with_name (current->name);
+ current->buffered_chars += cc;
+ }
+ }
+ /* It's not a regular file; read it, growing the buffer as needed. */
+ else if (always_text_flag || current->buffered_chars != 0)
+ {
+ for (;;)
+ {
+ if (current->buffered_chars == current->bufsize)
+ {
+ current->bufsize = current->bufsize * 2;
+ current->buffer = xrealloc (current->buffer, current->bufsize);
+ }
+ cc = read (current->desc,
+ current->buffer + current->buffered_chars,
+ current->bufsize - current->buffered_chars);
+ if (cc == 0)
+ break;
+ if (cc == -1)
+ pfatal_with_name (current->name);
+ current->buffered_chars += cc;
+ }
+ /* Allocate just enough room for appended newline and sentinel. */
+ current->bufsize = current->buffered_chars + 1 + sizeof (word);
+ current->buffer = xrealloc (current->buffer, current->bufsize);
+ }
+}
+
+/* Split the file into lines, simultaneously computing the equivalence class for
+ each line. */
+
+static void
+find_and_hash_each_line (current)
+ struct file_data *current;
+{
+ unsigned h;
+ unsigned char const *p = (unsigned char const *) current->prefix_end;
+ unsigned char c;
+ int i, *bucket;
+ size_t length;
+
+ /* Cache often-used quantities in local variables to help the compiler. */
+ char const **linbuf = current->linbuf;
+ int alloc_lines = current->alloc_lines;
+ int line = 0;
+ int linbuf_base = current->linbuf_base;
+ int *cureqs = (int *) xmalloc (alloc_lines * sizeof (int));
+ struct equivclass *eqs = equivs;
+ int eqs_index = equivs_index;
+ int eqs_alloc = equivs_alloc;
+ char const *suffix_begin = current->suffix_begin;
+ char const *bufend = current->buffer + current->buffered_chars;
+ int use_line_cmp = ignore_some_line_changes;
+
+ while ((char const *) p < suffix_begin)
+ {
+ char const *ip = (char const *) p;
+
+ /* Compute the equivalence class for this line. */
+
+ h = 0;
+
+ /* Hash this line until we find a newline. */
+ if (ignore_case_flag)
+ {
+ if (ignore_all_space_flag)
+ while ((c = *p++) != '\n')
+ {
+ if (! ISSPACE (c))
+ h = HASH (h, ISUPPER (c) ? tolower (c) : c);
+ }
+ else if (ignore_space_change_flag)
+ while ((c = *p++) != '\n')
+ {
+ if (ISSPACE (c))
+ {
+ for (;;)
+ {
+ c = *p++;
+ if (!ISSPACE (c))
+ break;
+ if (c == '\n')
+ goto hashing_done;
+ }
+ h = HASH (h, ' ');
+ }
+ /* C is now the first non-space. */
+ h = HASH (h, ISUPPER (c) ? tolower (c) : c);
+ }
+ else
+ while ((c = *p++) != '\n')
+ h = HASH (h, ISUPPER (c) ? tolower (c) : c);
+ }
+ else
+ {
+ if (ignore_all_space_flag)
+ while ((c = *p++) != '\n')
+ {
+ if (! ISSPACE (c))
+ h = HASH (h, c);
+ }
+ else if (ignore_space_change_flag)
+ while ((c = *p++) != '\n')
+ {
+ if (ISSPACE (c))
+ {
+ for (;;)
+ {
+ c = *p++;
+ if (!ISSPACE (c))
+ break;
+ if (c == '\n')
+ goto hashing_done;
+ }
+ h = HASH (h, ' ');
+ }
+ /* C is now the first non-space. */
+ h = HASH (h, c);
+ }
+ else
+ while ((c = *p++) != '\n')
+ h = HASH (h, c);
+ }
+ hashing_done:;
+
+ bucket = &buckets[h % nbuckets];
+ length = (char const *) p - ip - 1;
+
+ if ((char const *) p == bufend
+ && current->missing_newline
+ && ROBUST_OUTPUT_STYLE (output_style))
+ {
+ /* This line is incomplete. If this is significant,
+ put the line into bucket[-1]. */
+ if (! (ignore_space_change_flag | ignore_all_space_flag))
+ bucket = &buckets[-1];
+
+ /* Omit the inserted newline when computing linbuf later. */
+ p--;
+ bufend = suffix_begin = (char const *) p;
+ }
+
+ for (i = *bucket; ; i = eqs[i].next)
+ if (!i)
+ {
+ /* Create a new equivalence class in this bucket. */
+ i = eqs_index++;
+ if (i == eqs_alloc)
+ eqs = (struct equivclass *)
+ xrealloc (eqs, (eqs_alloc*=2) * sizeof(*eqs));
+ eqs[i].next = *bucket;
+ eqs[i].hash = h;
+ eqs[i].line = ip;
+ eqs[i].length = length;
+ *bucket = i;
+ break;
+ }
+ else if (eqs[i].hash == h)
+ {
+ char const *eqline = eqs[i].line;
+
+ /* Reuse existing equivalence class if the lines are identical.
+ This detects the common case of exact identity
+ faster than complete comparison would. */
+ if (eqs[i].length == length && memcmp (eqline, ip, length) == 0)
+ break;
+
+ /* Reuse existing class if line_cmp reports the lines equal. */
+ if (use_line_cmp && line_cmp (eqline, ip) == 0)
+ break;
+ }
+
+ /* Maybe increase the size of the line table. */
+ if (line == alloc_lines)
+ {
+ /* Double (alloc_lines - linbuf_base) by adding to alloc_lines. */
+ alloc_lines = 2 * alloc_lines - linbuf_base;
+ cureqs = (int *) xrealloc (cureqs, alloc_lines * sizeof (*cureqs));
+ linbuf = (char const **) xrealloc (linbuf + linbuf_base,
+ (alloc_lines - linbuf_base)
+ * sizeof (*linbuf))
+ - linbuf_base;
+ }
+ linbuf[line] = ip;
+ cureqs[line] = i;
+ ++line;
+ }
+
+ current->buffered_lines = line;
+
+ for (i = 0; ; i++)
+ {
+ /* Record the line start for lines in the suffix that we care about.
+ Record one more line start than lines,
+ so that we can compute the length of any buffered line. */
+ if (line == alloc_lines)
+ {
+ /* Double (alloc_lines - linbuf_base) by adding to alloc_lines. */
+ alloc_lines = 2 * alloc_lines - linbuf_base;
+ linbuf = (char const **) xrealloc (linbuf + linbuf_base,
+ (alloc_lines - linbuf_base)
+ * sizeof (*linbuf))
+ - linbuf_base;
+ }
+ linbuf[line] = (char const *) p;
+
+ if ((char const *) p == bufend)
+ break;
+
+ if (context <= i && no_diff_means_no_output)
+ break;
+
+ line++;
+
+ while (*p++ != '\n')
+ ;
+ }
+
+ /* Done with cache in local variables. */
+ current->linbuf = linbuf;
+ current->valid_lines = line;
+ current->alloc_lines = alloc_lines;
+ current->equivs = cureqs;
+ equivs = eqs;
+ equivs_alloc = eqs_alloc;
+ equivs_index = eqs_index;
+}
+
+/* Prepare the end of the text. Make sure it's initialized.
+ Make sure text ends in a newline,
+ but remember that we had to add one. */
+
+static void
+prepare_text_end (current)
+ struct file_data *current;
+{
+ size_t buffered_chars = current->buffered_chars;
+ char *p = current->buffer;
+
+ if (buffered_chars == 0 || p[buffered_chars - 1] == '\n')
+ current->missing_newline = 0;
+ else
+ {
+ p[buffered_chars++] = '\n';
+ current->buffered_chars = buffered_chars;
+ current->missing_newline = 1;
+ }
+
+ /* Don't use uninitialized storage when planting or using sentinels. */
+ if (p)
+ bzero (p + buffered_chars, sizeof (word));
+}
+
+/* Given a vector of two file_data objects, find the identical
+ prefixes and suffixes of each object. */
+
+static void
+find_identical_ends (filevec)
+ struct file_data filevec[];
+{
+ word *w0, *w1;
+ char *p0, *p1, *buffer0, *buffer1;
+ char const *end0, *beg0;
+ char const **linbuf0, **linbuf1;
+ int i, lines;
+ size_t n0, n1, tem;
+ int alloc_lines0, alloc_lines1;
+ int buffered_prefix, prefix_count, prefix_mask;
+
+ slurp (&filevec[0]);
+ if (filevec[0].desc != filevec[1].desc)
+ slurp (&filevec[1]);
+ else
+ {
+ filevec[1].buffer = filevec[0].buffer;
+ filevec[1].bufsize = filevec[0].bufsize;
+ filevec[1].buffered_chars = filevec[0].buffered_chars;
+ }
+ for (i = 0; i < 2; i++)
+ prepare_text_end (&filevec[i]);
+
+ /* Find identical prefix. */
+
+ p0 = buffer0 = filevec[0].buffer;
+ p1 = buffer1 = filevec[1].buffer;
+
+ n0 = filevec[0].buffered_chars;
+ n1 = filevec[1].buffered_chars;
+
+ if (p0 == p1)
+ /* The buffers are the same; sentinels won't work. */
+ p0 = p1 += n1;
+ else
+ {
+ /* Insert end sentinels, in this case characters that are guaranteed
+ to make the equality test false, and thus terminate the loop. */
+
+ if (n0 < n1)
+ p0[n0] = ~p1[n0];
+ else
+ p1[n1] = ~p0[n1];
+
+ /* Loop until first mismatch, or to the sentinel characters. */
+
+ /* Compare a word at a time for speed. */
+ w0 = (word *) p0;
+ w1 = (word *) p1;
+ while (*w0++ == *w1++)
+ ;
+ --w0, --w1;
+
+ /* Do the last few bytes of comparison a byte at a time. */
+ p0 = (char *) w0;
+ p1 = (char *) w1;
+ while (*p0++ == *p1++)
+ ;
+ --p0, --p1;
+
+ /* Don't mistakenly count missing newline as part of prefix. */
+ if (ROBUST_OUTPUT_STYLE (output_style)
+ && (buffer0 + n0 - filevec[0].missing_newline < p0)
+ !=
+ (buffer1 + n1 - filevec[1].missing_newline < p1))
+ --p0, --p1;
+ }
+
+ /* Now P0 and P1 point at the first nonmatching characters. */
+
+ /* Skip back to last line-beginning in the prefix,
+ and then discard up to HORIZON_LINES lines from the prefix. */
+ i = horizon_lines;
+ while (p0 != buffer0 && (p0[-1] != '\n' || i--))
+ --p0, --p1;
+
+ /* Record the prefix. */
+ filevec[0].prefix_end = p0;
+ filevec[1].prefix_end = p1;
+
+ /* Find identical suffix. */
+
+ /* P0 and P1 point beyond the last chars not yet compared. */
+ p0 = buffer0 + n0;
+ p1 = buffer1 + n1;
+
+ if (! ROBUST_OUTPUT_STYLE (output_style)
+ || filevec[0].missing_newline == filevec[1].missing_newline)
+ {
+ end0 = p0; /* Addr of last char in file 0. */
+
+ /* Get value of P0 at which we should stop scanning backward:
+ this is when either P0 or P1 points just past the last char
+ of the identical prefix. */
+ beg0 = filevec[0].prefix_end + (n0 < n1 ? 0 : n0 - n1);
+
+ /* Scan back until chars don't match or we reach that point. */
+ while (p0 != beg0)
+ if (*--p0 != *--p1)
+ {
+ /* Point at the first char of the matching suffix. */
+ ++p0, ++p1;
+ beg0 = p0;
+ break;
+ }
+
+ /* Are we at a line-beginning in both files? If not, add the rest of
+ this line to the main body. Discard up to HORIZON_LINES lines from
+ the identical suffix. Also, discard one extra line,
+ because shift_boundaries may need it. */
+ i = horizon_lines + !((buffer0 == p0 || p0[-1] == '\n')
+ &&
+ (buffer1 == p1 || p1[-1] == '\n'));
+ while (i-- && p0 != end0)
+ while (*p0++ != '\n')
+ ;
+
+ p1 += p0 - beg0;
+ }
+
+ /* Record the suffix. */
+ filevec[0].suffix_begin = p0;
+ filevec[1].suffix_begin = p1;
+
+ /* Calculate number of lines of prefix to save.
+
+ prefix_count == 0 means save the whole prefix;
+ we need this with for options like -D that output the whole file.
+ We also need it for options like -F that output some preceding line;
+ at least we will need to find the last few lines,
+ but since we don't know how many, it's easiest to find them all.
+
+ Otherwise, prefix_count != 0. Save just prefix_count lines at start
+ of the line buffer; they'll be moved to the proper location later.
+ Handle 1 more line than the context says (because we count 1 too many),
+ rounded up to the next power of 2 to speed index computation. */
+
+ if (no_diff_means_no_output && ! function_regexp_list)
+ {
+ for (prefix_count = 1; prefix_count < context + 1; prefix_count *= 2)
+ ;
+ prefix_mask = prefix_count - 1;
+ alloc_lines0
+ = prefix_count
+ + GUESS_LINES (0, 0, p0 - filevec[0].prefix_end)
+ + context;
+ }
+ else
+ {
+ prefix_count = 0;
+ prefix_mask = ~0;
+ alloc_lines0 = GUESS_LINES (0, 0, n0);
+ }
+
+ lines = 0;
+ linbuf0 = (char const **) xmalloc (alloc_lines0 * sizeof (*linbuf0));
+
+ /* If the prefix is needed, find the prefix lines. */
+ if (! (no_diff_means_no_output
+ && filevec[0].prefix_end == p0
+ && filevec[1].prefix_end == p1))
+ {
+ p0 = buffer0;
+ end0 = filevec[0].prefix_end;
+ while (p0 != end0)
+ {
+ int l = lines++ & prefix_mask;
+ if (l == alloc_lines0)
+ linbuf0 = (char const **) xrealloc (linbuf0, (alloc_lines0 *= 2)
+ * sizeof(*linbuf0));
+ linbuf0[l] = p0;
+ while (*p0++ != '\n')
+ ;
+ }
+ }
+ buffered_prefix = prefix_count && context < lines ? context : lines;
+
+ /* Allocate line buffer 1. */
+ tem = prefix_count ? filevec[1].suffix_begin - buffer1 : n1;
+
+ alloc_lines1
+ = (buffered_prefix
+ + GUESS_LINES (lines, filevec[1].prefix_end - buffer1, tem)
+ + context);
+ linbuf1 = (char const **) xmalloc (alloc_lines1 * sizeof (*linbuf1));
+
+ if (buffered_prefix != lines)
+ {
+ /* Rotate prefix lines to proper location. */
+ for (i = 0; i < buffered_prefix; i++)
+ linbuf1[i] = linbuf0[(lines - context + i) & prefix_mask];
+ for (i = 0; i < buffered_prefix; i++)
+ linbuf0[i] = linbuf1[i];
+ }
+
+ /* Initialize line buffer 1 from line buffer 0. */
+ for (i = 0; i < buffered_prefix; i++)
+ linbuf1[i] = linbuf0[i] - buffer0 + buffer1;
+
+ /* Record the line buffer, adjusted so that
+ linbuf*[0] points at the first differing line. */
+ filevec[0].linbuf = linbuf0 + buffered_prefix;
+ filevec[1].linbuf = linbuf1 + buffered_prefix;
+ filevec[0].linbuf_base = filevec[1].linbuf_base = - buffered_prefix;
+ filevec[0].alloc_lines = alloc_lines0 - buffered_prefix;
+ filevec[1].alloc_lines = alloc_lines1 - buffered_prefix;
+ filevec[0].prefix_lines = filevec[1].prefix_lines = lines;
+}
+
+/* Largest primes less than some power of two, for nbuckets. Values range
+ from useful to preposterous. If one of these numbers isn't prime
+ after all, don't blame it on me, blame it on primes (6) . . . */
+static int const primes[] =
+{
+ 509,
+ 1021,
+ 2039,
+ 4093,
+ 8191,
+ 16381,
+ 32749,
+#if 32767 < INT_MAX
+ 65521,
+ 131071,
+ 262139,
+ 524287,
+ 1048573,
+ 2097143,
+ 4194301,
+ 8388593,
+ 16777213,
+ 33554393,
+ 67108859, /* Preposterously large . . . */
+ 134217689,
+ 268435399,
+ 536870909,
+ 1073741789,
+ 2147483647,
+#endif
+ 0
+};
+
+/* Given a vector of two file_data objects, read the file associated
+ with each one, and build the table of equivalence classes.
+ Return 1 if either file appears to be a binary file.
+ If PRETEND_BINARY is nonzero, pretend they are binary regardless. */
+
+int
+read_files (filevec, pretend_binary)
+ struct file_data filevec[];
+ int pretend_binary;
+{
+ int i;
+ int skip_test = always_text_flag | pretend_binary;
+ int appears_binary = pretend_binary | sip (&filevec[0], skip_test);
+
+ if (filevec[0].desc != filevec[1].desc)
+ appears_binary |= sip (&filevec[1], skip_test | appears_binary);
+ else
+ {
+ filevec[1].buffer = filevec[0].buffer;
+ filevec[1].bufsize = filevec[0].bufsize;
+ filevec[1].buffered_chars = filevec[0].buffered_chars;
+ }
+ if (appears_binary)
+ {
+#if HAVE_SETMODE
+ setmode (filevec[0].desc, O_BINARY);
+ setmode (filevec[1].desc, O_BINARY);
+#endif
+ return 1;
+ }
+
+ find_identical_ends (filevec);
+
+ equivs_alloc = filevec[0].alloc_lines + filevec[1].alloc_lines + 1;
+ equivs = (struct equivclass *) xmalloc (equivs_alloc * sizeof (struct equivclass));
+ /* Equivalence class 0 is permanently safe for lines that were not
+ hashed. Real equivalence classes start at 1. */
+ equivs_index = 1;
+
+ for (i = 0; primes[i] < equivs_alloc / 3; i++)
+ if (! primes[i])
+ abort ();
+ nbuckets = primes[i];
+
+ buckets = (int *) xmalloc ((nbuckets + 1) * sizeof (*buckets));
+ bzero (buckets++, (nbuckets + 1) * sizeof (*buckets));
+
+ for (i = 0; i < 2; i++)
+ find_and_hash_each_line (&filevec[i]);
+
+ filevec[0].equiv_max = filevec[1].equiv_max = equivs_index;
+
+ free (equivs);
+ free (buckets - 1);
+
+ return 0;
+}
diff --git a/gnu/usr.bin/diff/normal.c b/gnu/usr.bin/diff/normal.c
new file mode 100644
index 0000000..4d9e23c
--- /dev/null
+++ b/gnu/usr.bin/diff/normal.c
@@ -0,0 +1,71 @@
+/* Normal-format output routines for GNU DIFF.
+ Copyright (C) 1988, 1989, 1993 Free Software Foundation, Inc.
+
+This file is part of GNU DIFF.
+
+GNU DIFF is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU DIFF is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU DIFF; see the file COPYING. If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+
+#include "diff.h"
+
+static void print_normal_hunk PARAMS((struct change *));
+
+/* Print the edit-script SCRIPT as a normal diff.
+ INF points to an array of descriptions of the two files. */
+
+void
+print_normal_script (script)
+ struct change *script;
+{
+ print_script (script, find_change, print_normal_hunk);
+}
+
+/* Print a hunk of a normal diff.
+ This is a contiguous portion of a complete edit script,
+ describing changes in consecutive lines. */
+
+static void
+print_normal_hunk (hunk)
+ struct change *hunk;
+{
+ int first0, last0, first1, last1, deletes, inserts;
+ register int i;
+
+ /* Determine range of line numbers involved in each file. */
+ analyze_hunk (hunk, &first0, &last0, &first1, &last1, &deletes, &inserts);
+ if (!deletes && !inserts)
+ return;
+
+ begin_output ();
+
+ /* Print out the line number header for this hunk */
+ print_number_range (',', &files[0], first0, last0);
+ fprintf (outfile, "%c", change_letter (inserts, deletes));
+ print_number_range (',', &files[1], first1, last1);
+ fprintf (outfile, "\n");
+
+ /* Print the lines that the first file has. */
+ if (deletes)
+ for (i = first0; i <= last0; i++)
+ print_1_line ("<", &files[0].linbuf[i]);
+
+ if (inserts && deletes)
+ fprintf (outfile, "---\n");
+
+ /* Print the lines that the second file has. */
+ if (inserts)
+ for (i = first1; i <= last1; i++)
+ print_1_line (">", &files[1].linbuf[i]);
+}
diff --git a/gnu/usr.bin/diff/sdiff.c b/gnu/usr.bin/diff/sdiff.c
new file mode 100644
index 0000000..b64f1d0
--- /dev/null
+++ b/gnu/usr.bin/diff/sdiff.c
@@ -0,0 +1,1180 @@
+/* SDIFF -- interactive merge front end to diff
+ Copyright (C) 1992, 1993, 1994 Free Software Foundation, Inc.
+
+This file is part of GNU DIFF.
+
+GNU DIFF is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU DIFF is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU DIFF; see the file COPYING. If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* GNU SDIFF was written by Thomas Lord. */
+
+#include "system.h"
+#include <stdio.h>
+#include <signal.h>
+#include "getopt.h"
+
+/* Size of chunks read from files which must be parsed into lines. */
+#define SDIFF_BUFSIZE ((size_t) 65536)
+
+/* Default name of the diff program */
+#ifndef DIFF_PROGRAM
+#define DIFF_PROGRAM "/usr/bin/diff"
+#endif
+
+/* Users' editor of nonchoice */
+#ifndef DEFAULT_EDITOR_PROGRAM
+#define DEFAULT_EDITOR_PROGRAM "ed"
+#endif
+
+extern char version_string[];
+static char const *program_name;
+static char const *diffbin = DIFF_PROGRAM;
+static char const *edbin = DEFAULT_EDITOR_PROGRAM;
+static char const **diffargv;
+
+static char *tmpname;
+static int volatile tmpmade;
+
+#if HAVE_FORK
+static pid_t volatile diffpid;
+#endif
+
+struct line_filter;
+
+static FILE *ck_fopen PARAMS((char const *, char const *));
+static RETSIGTYPE catchsig PARAMS((int));
+static VOID *xmalloc PARAMS((size_t));
+static char const *expand_name PARAMS((char *, int, char const *));
+static int edit PARAMS((struct line_filter *, int, struct line_filter *, int, FILE*));
+static int interact PARAMS((struct line_filter *, struct line_filter *, struct line_filter *, FILE*));
+static int lf_snarf PARAMS((struct line_filter *, char *, size_t));
+static int skip_white PARAMS((void));
+static size_t ck_fread PARAMS((char *, size_t, FILE *));
+static size_t lf_refill PARAMS((struct line_filter *));
+static void checksigs PARAMS((void));
+static void ck_fclose PARAMS((FILE *));
+static void ck_fflush PARAMS((FILE *));
+static void ck_fwrite PARAMS((char const *, size_t, FILE *));
+static void cleanup PARAMS((void));
+static void diffarg PARAMS((char const *));
+static void execdiff PARAMS((void));
+static void exiterr PARAMS((void));
+static void fatal PARAMS((char const *));
+static void flush_line PARAMS((void));
+static void give_help PARAMS((void));
+static void lf_copy PARAMS((struct line_filter *, int, FILE *));
+static void lf_init PARAMS((struct line_filter *, FILE *));
+static void lf_skip PARAMS((struct line_filter *, int));
+static void perror_fatal PARAMS((char const *));
+static void trapsigs PARAMS((void));
+static void try_help PARAMS((char const *));
+static void untrapsig PARAMS((int));
+static void usage PARAMS((void));
+
+/* this lossage until the gnu libc conquers the universe */
+#if HAVE_TMPNAM
+#define private_tempnam() tmpnam ((char *) 0)
+#else
+#ifndef PVT_tmpdir
+#define PVT_tmpdir "/tmp"
+#endif
+#ifndef TMPDIR_ENV
+#define TMPDIR_ENV "TMPDIR"
+#endif
+static char *private_tempnam PARAMS((void));
+static int exists PARAMS((char const *));
+#endif
+static int diraccess PARAMS((char const *));
+
+/* Options: */
+
+/* name of output file if -o spec'd */
+static char *out_file;
+
+/* do not print common lines if true, set by -s option */
+static int suppress_common_flag;
+
+static struct option const longopts[] =
+{
+ {"ignore-blank-lines", 0, 0, 'B'},
+ {"speed-large-files", 0, 0, 'H'},
+ {"ignore-matching-lines", 1, 0, 'I'},
+ {"ignore-all-space", 0, 0, 'W'}, /* swap W and w for historical reasons */
+ {"text", 0, 0, 'a'},
+ {"ignore-space-change", 0, 0, 'b'},
+ {"minimal", 0, 0, 'd'},
+ {"ignore-case", 0, 0, 'i'},
+ {"left-column", 0, 0, 'l'},
+ {"output", 1, 0, 'o'},
+ {"suppress-common-lines", 0, 0, 's'},
+ {"expand-tabs", 0, 0, 't'},
+ {"width", 1, 0, 'w'},
+ {"version", 0, 0, 'v'},
+ {"help", 0, 0, 129},
+ {0, 0, 0, 0}
+};
+
+static void
+try_help (reason)
+ char const *reason;
+{
+ if (reason)
+ fprintf (stderr, "%s: %s\n", program_name, reason);
+ fprintf (stderr, "%s: Try `%s --help' for more information.\n",
+ program_name, program_name);
+ exit (2);
+}
+
+static void
+usage ()
+{
+ printf ("Usage: %s [OPTIONS]... FILE1 FILE2\n\n", program_name);
+ printf ("%s", "\
+ -o FILE --output=FILE Operate interactively, sending output to FILE.\n\n");
+ printf ("%s", "\
+ -i --ignore-case Consider upper- and lower-case to be the same.\n\
+ -W --ignore-all-space Ignore all white space.\n\
+ -b --ignore-space-change Ignore changes in the amount of white space.\n\
+ -B --ignore-blank-lines Ignore changes whose lines are all blank.\n\
+ -I RE --ignore-matching-lines=RE Ignore changes whose lines all match RE.\n\
+ -a --text Treat all files as text.\n\n");
+ printf ("%s", "\
+ -w NUM --width=NUM Output at most NUM (default 130) characters per line.\n\
+ -l --left-column Output only the left column of common lines.\n\
+ -s --suppress-common-lines Do not output common lines.\n\n");
+ printf ("\
+ -t --expand-tabs Expand tabs to spaces in output.\n\n");
+ printf ("%s", "\
+ -d --minimal Try hard to find a smaller set of changes.\n\
+ -H --speed-large-files Assume large files and many scattered small changes.\n\n");
+ printf ("%s", "\
+ -v --version Output version info.\n\
+ --help Output this help.\n\n\
+If FILE1 or FILE2 is `-', read standard input.\n");
+}
+
+static void
+cleanup ()
+{
+#if HAVE_FORK
+ if (0 < diffpid)
+ kill (diffpid, SIGPIPE);
+#endif
+ if (tmpmade)
+ unlink (tmpname);
+}
+
+static void
+exiterr ()
+{
+ cleanup ();
+ untrapsig (0);
+ checksigs ();
+ exit (2);
+}
+
+static void
+fatal (msg)
+ char const *msg;
+{
+ fprintf (stderr, "%s: %s\n", program_name, msg);
+ exiterr ();
+}
+
+static void
+perror_fatal (msg)
+ char const *msg;
+{
+ int e = errno;
+ checksigs ();
+ fprintf (stderr, "%s: ", program_name);
+ errno = e;
+ perror (msg);
+ exiterr ();
+}
+
+
+/* malloc freely or DIE! */
+static VOID *
+xmalloc (size)
+ size_t size;
+{
+ VOID *r = (VOID *) malloc (size);
+ if (!r)
+ fatal ("memory exhausted");
+ return r;
+}
+
+static FILE *
+ck_fopen (fname, type)
+ char const *fname, *type;
+{
+ FILE *r = fopen (fname, type);
+ if (!r)
+ perror_fatal (fname);
+ return r;
+}
+
+static void
+ck_fclose (f)
+ FILE *f;
+{
+ if (fclose (f))
+ perror_fatal ("input/output error");
+}
+
+static size_t
+ck_fread (buf, size, f)
+ char *buf;
+ size_t size;
+ FILE *f;
+{
+ size_t r = fread (buf, sizeof (char), size, f);
+ if (r == 0 && ferror (f))
+ perror_fatal ("input error");
+ return r;
+}
+
+static void
+ck_fwrite (buf, size, f)
+ char const *buf;
+ size_t size;
+ FILE *f;
+{
+ if (fwrite (buf, sizeof (char), size, f) != size)
+ perror_fatal ("output error");
+}
+
+static void
+ck_fflush (f)
+ FILE *f;
+{
+ if (fflush (f) != 0)
+ perror_fatal ("output error");
+}
+
+static char const *
+expand_name (name, is_dir, other_name)
+ char *name;
+ int is_dir;
+ char const *other_name;
+{
+ if (strcmp (name, "-") == 0)
+ fatal ("cannot interactively merge standard input");
+ if (!is_dir)
+ return name;
+ else
+ {
+ /* Yield NAME/BASE, where BASE is OTHER_NAME's basename. */
+ char const *p = filename_lastdirchar (other_name);
+ char const *base = p ? p+1 : other_name;
+ size_t namelen = strlen (name), baselen = strlen (base);
+ char *r = xmalloc (namelen + baselen + 2);
+ memcpy (r, name, namelen);
+ r[namelen] = '/';
+ memcpy (r + namelen + 1, base, baselen + 1);
+ return r;
+ }
+}
+
+
+
+struct line_filter {
+ FILE *infile;
+ char *bufpos;
+ char *buffer;
+ char *buflim;
+};
+
+static void
+lf_init (lf, infile)
+ struct line_filter *lf;
+ FILE *infile;
+{
+ lf->infile = infile;
+ lf->bufpos = lf->buffer = lf->buflim = xmalloc (SDIFF_BUFSIZE + 1);
+ lf->buflim[0] = '\n';
+}
+
+/* Fill an exhausted line_filter buffer from its INFILE */
+static size_t
+lf_refill (lf)
+ struct line_filter *lf;
+{
+ size_t s = ck_fread (lf->buffer, SDIFF_BUFSIZE, lf->infile);
+ lf->bufpos = lf->buffer;
+ lf->buflim = lf->buffer + s;
+ lf->buflim[0] = '\n';
+ checksigs ();
+ return s;
+}
+
+/* Advance LINES on LF's infile, copying lines to OUTFILE */
+static void
+lf_copy (lf, lines, outfile)
+ struct line_filter *lf;
+ int lines;
+ FILE *outfile;
+{
+ char *start = lf->bufpos;
+
+ while (lines)
+ {
+ lf->bufpos = (char *) memchr (lf->bufpos, '\n', lf->buflim - lf->bufpos);
+ if (! lf->bufpos)
+ {
+ ck_fwrite (start, lf->buflim - start, outfile);
+ if (! lf_refill (lf))
+ return;
+ start = lf->bufpos;
+ }
+ else
+ {
+ --lines;
+ ++lf->bufpos;
+ }
+ }
+
+ ck_fwrite (start, lf->bufpos - start, outfile);
+}
+
+/* Advance LINES on LF's infile without doing output */
+static void
+lf_skip (lf, lines)
+ struct line_filter *lf;
+ int lines;
+{
+ while (lines)
+ {
+ lf->bufpos = (char *) memchr (lf->bufpos, '\n', lf->buflim - lf->bufpos);
+ if (! lf->bufpos)
+ {
+ if (! lf_refill (lf))
+ break;
+ }
+ else
+ {
+ --lines;
+ ++lf->bufpos;
+ }
+ }
+}
+
+/* Snarf a line into a buffer. Return EOF if EOF, 0 if error, 1 if OK. */
+static int
+lf_snarf (lf, buffer, bufsize)
+ struct line_filter *lf;
+ char *buffer;
+ size_t bufsize;
+{
+ char *start = lf->bufpos;
+
+ for (;;)
+ {
+ char *next = (char *) memchr (start, '\n', lf->buflim + 1 - start);
+ size_t s = next - start;
+ if (bufsize <= s)
+ return 0;
+ memcpy (buffer, start, s);
+ if (next < lf->buflim)
+ {
+ buffer[s] = 0;
+ lf->bufpos = next + 1;
+ return 1;
+ }
+ if (! lf_refill (lf))
+ return s ? 0 : EOF;
+ buffer += s;
+ bufsize -= s;
+ start = next;
+ }
+}
+
+
+
+int
+main (argc, argv)
+ int argc;
+ char *argv[];
+{
+ int opt;
+ char *editor;
+ char *differ;
+
+ initialize_main (&argc, &argv);
+ program_name = argv[0];
+
+ editor = getenv ("EDITOR");
+ if (editor)
+ edbin = editor;
+ differ = getenv ("DIFF");
+ if (differ)
+ diffbin = differ;
+
+ diffarg ("diff");
+
+ /* parse command line args */
+ while ((opt = getopt_long (argc, argv, "abBdHiI:lo:stvw:W", longopts, 0))
+ != EOF)
+ {
+ switch (opt)
+ {
+ case 'a':
+ diffarg ("-a");
+ break;
+
+ case 'b':
+ diffarg ("-b");
+ break;
+
+ case 'B':
+ diffarg ("-B");
+ break;
+
+ case 'd':
+ diffarg ("-d");
+ break;
+
+ case 'H':
+ diffarg ("-H");
+ break;
+
+ case 'i':
+ diffarg ("-i");
+ break;
+
+ case 'I':
+ diffarg ("-I");
+ diffarg (optarg);
+ break;
+
+ case 'l':
+ diffarg ("--left-column");
+ break;
+
+ case 'o':
+ out_file = optarg;
+ break;
+
+ case 's':
+ suppress_common_flag = 1;
+ break;
+
+ case 't':
+ diffarg ("-t");
+ break;
+
+ case 'v':
+ printf ("sdiff - GNU diffutils version %s\n", version_string);
+ exit (0);
+
+ case 'w':
+ diffarg ("-W");
+ diffarg (optarg);
+ break;
+
+ case 'W':
+ diffarg ("-w");
+ break;
+
+ case 129:
+ usage ();
+ if (ferror (stdout) || fclose (stdout) != 0)
+ fatal ("write error");
+ exit (0);
+
+ default:
+ try_help (0);
+ }
+ }
+
+ if (argc - optind != 2)
+ try_help (argc - optind < 2 ? "missing operand" : "extra operand");
+
+ if (! out_file)
+ {
+ /* easy case: diff does everything for us */
+ if (suppress_common_flag)
+ diffarg ("--suppress-common-lines");
+ diffarg ("-y");
+ diffarg ("--");
+ diffarg (argv[optind]);
+ diffarg (argv[optind + 1]);
+ diffarg (0);
+ execdiff ();
+ }
+ else
+ {
+ FILE *left, *right, *out, *diffout;
+ int interact_ok;
+ struct line_filter lfilt;
+ struct line_filter rfilt;
+ struct line_filter diff_filt;
+ int leftdir = diraccess (argv[optind]);
+ int rightdir = diraccess (argv[optind + 1]);
+
+ if (leftdir && rightdir)
+ fatal ("both files to be compared are directories");
+
+ left = ck_fopen (expand_name (argv[optind], leftdir, argv[optind + 1]), "r");
+ ;
+ right = ck_fopen (expand_name (argv[optind + 1], rightdir, argv[optind]), "r");
+ out = ck_fopen (out_file, "w");
+
+ diffarg ("--sdiff-merge-assist");
+ diffarg ("--");
+ diffarg (argv[optind]);
+ diffarg (argv[optind + 1]);
+ diffarg (0);
+
+ trapsigs ();
+
+#if ! HAVE_FORK
+ {
+ size_t cmdsize = 1;
+ char *p, *command;
+ int i;
+
+ for (i = 0; diffargv[i]; i++)
+ cmdsize += 4 * strlen (diffargv[i]) + 3;
+ command = p = xmalloc (cmdsize);
+ for (i = 0; diffargv[i]; i++)
+ {
+ char const *a = diffargv[i];
+ SYSTEM_QUOTE_ARG (p, a);
+ *p++ = ' ';
+ }
+ p[-1] = '\0';
+ diffout = popen (command, "r");
+ if (!diffout)
+ perror_fatal (command);
+ free (command);
+ }
+#else /* HAVE_FORK */
+ {
+ int diff_fds[2];
+
+ if (pipe (diff_fds) != 0)
+ perror_fatal ("pipe");
+
+ diffpid = vfork ();
+ if (diffpid < 0)
+ perror_fatal ("fork failed");
+ if (!diffpid)
+ {
+ signal (SIGINT, SIG_IGN); /* in case user interrupts editor */
+ signal (SIGPIPE, SIG_DFL);
+
+ close (diff_fds[0]);
+ if (diff_fds[1] != STDOUT_FILENO)
+ {
+ dup2 (diff_fds[1], STDOUT_FILENO);
+ close (diff_fds[1]);
+ }
+
+ execdiff ();
+ }
+
+ close (diff_fds[1]);
+ diffout = fdopen (diff_fds[0], "r");
+ if (!diffout)
+ perror_fatal ("fdopen");
+ }
+#endif /* HAVE_FORK */
+
+ lf_init (&diff_filt, diffout);
+ lf_init (&lfilt, left);
+ lf_init (&rfilt, right);
+
+ interact_ok = interact (&diff_filt, &lfilt, &rfilt, out);
+
+ ck_fclose (left);
+ ck_fclose (right);
+ ck_fclose (out);
+
+ {
+ int wstatus;
+
+#if ! HAVE_FORK
+ wstatus = pclose (diffout);
+#else
+ ck_fclose (diffout);
+ while (waitpid (diffpid, &wstatus, 0) < 0)
+ if (errno == EINTR)
+ checksigs ();
+ else
+ perror_fatal ("wait failed");
+ diffpid = 0;
+#endif
+
+ if (tmpmade)
+ {
+ unlink (tmpname);
+ tmpmade = 0;
+ }
+
+ if (! interact_ok)
+ exiterr ();
+
+ if (! (WIFEXITED (wstatus) && WEXITSTATUS (wstatus) < 2))
+ fatal ("Subsidiary diff failed");
+
+ untrapsig (0);
+ checksigs ();
+ exit (WEXITSTATUS (wstatus));
+ }
+ }
+ return 0; /* Fool -Wall . . . */
+}
+
+static void
+diffarg (a)
+ char const *a;
+{
+ static unsigned diffargs, diffargsmax;
+
+ if (diffargs == diffargsmax)
+ {
+ if (! diffargsmax)
+ {
+ diffargv = (char const **) xmalloc (sizeof (char));
+ diffargsmax = 8;
+ }
+ diffargsmax *= 2;
+ diffargv = (char const **) realloc (diffargv,
+ diffargsmax * sizeof (char const *));
+ if (! diffargv)
+ fatal ("out of memory");
+ }
+ diffargv[diffargs++] = a;
+}
+
+static void
+execdiff ()
+{
+ execvp (diffbin, (char **) diffargv);
+ write (STDERR_FILENO, diffbin, strlen (diffbin));
+ write (STDERR_FILENO, ": not found\n", 12);
+ _exit (2);
+}
+
+
+
+
+/* Signal handling */
+
+#define NUM_SIGS (sizeof (sigs) / sizeof (*sigs))
+static int const sigs[] = {
+#ifdef SIGHUP
+ SIGHUP,
+#endif
+#ifdef SIGQUIT
+ SIGQUIT,
+#endif
+#ifdef SIGTERM
+ SIGTERM,
+#endif
+#ifdef SIGXCPU
+ SIGXCPU,
+#endif
+#ifdef SIGXFSZ
+ SIGXFSZ,
+#endif
+ SIGINT,
+ SIGPIPE
+};
+
+/* Prefer `sigaction' if it is available, since `signal' can lose signals. */
+#if HAVE_SIGACTION
+static struct sigaction initial_action[NUM_SIGS];
+#define initial_handler(i) (initial_action[i].sa_handler)
+#else
+static RETSIGTYPE (*initial_action[NUM_SIGS]) ();
+#define initial_handler(i) (initial_action[i])
+#endif
+
+static int volatile ignore_SIGINT;
+static int volatile signal_received;
+static int sigs_trapped;
+
+static RETSIGTYPE
+catchsig (s)
+ int s;
+{
+#if ! HAVE_SIGACTION
+ signal (s, SIG_IGN);
+#endif
+ if (! (s == SIGINT && ignore_SIGINT))
+ signal_received = s;
+}
+
+static void
+trapsigs ()
+{
+ int i;
+
+#if HAVE_SIGACTION
+ struct sigaction catchaction;
+ bzero (&catchaction, sizeof (catchaction));
+ catchaction.sa_handler = catchsig;
+#ifdef SA_INTERRUPT
+ /* Non-Posix BSD-style systems like SunOS 4.1.x need this
+ so that `read' calls are interrupted properly. */
+ catchaction.sa_flags = SA_INTERRUPT;
+#endif
+ sigemptyset (&catchaction.sa_mask);
+ for (i = 0; i < NUM_SIGS; i++)
+ sigaddset (&catchaction.sa_mask, sigs[i]);
+ for (i = 0; i < NUM_SIGS; i++)
+ {
+ sigaction (sigs[i], 0, &initial_action[i]);
+ if (initial_handler (i) != SIG_IGN
+ && sigaction (sigs[i], &catchaction, 0) != 0)
+ fatal ("signal error");
+ }
+#else /* ! HAVE_SIGACTION */
+ for (i = 0; i < NUM_SIGS; i++)
+ {
+ initial_action[i] = signal (sigs[i], SIG_IGN);
+ if (initial_handler (i) != SIG_IGN
+ && signal (sigs[i], catchsig) != SIG_IGN)
+ fatal ("signal error");
+ }
+#endif /* ! HAVE_SIGACTION */
+
+#if !defined(SIGCHLD) && defined(SIGCLD)
+#define SIGCHLD SIGCLD
+#endif
+#ifdef SIGCHLD
+ /* System V fork+wait does not work if SIGCHLD is ignored. */
+ signal (SIGCHLD, SIG_DFL);
+#endif
+
+ sigs_trapped = 1;
+}
+
+/* Untrap signal S, or all trapped signals if S is zero. */
+static void
+untrapsig (s)
+ int s;
+{
+ int i;
+
+ if (sigs_trapped)
+ for (i = 0; i < NUM_SIGS; i++)
+ if ((!s || sigs[i] == s) && initial_handler (i) != SIG_IGN)
+#if HAVE_SIGACTION
+ sigaction (sigs[i], &initial_action[i], 0);
+#else
+ signal (sigs[i], initial_action[i]);
+#endif
+}
+
+/* Exit if a signal has been received. */
+static void
+checksigs ()
+{
+ int s = signal_received;
+ if (s)
+ {
+ cleanup ();
+
+ /* Yield an exit status indicating that a signal was received. */
+ untrapsig (s);
+ kill (getpid (), s);
+
+ /* That didn't work, so exit with error status. */
+ exit (2);
+ }
+}
+
+
+
+static void
+give_help ()
+{
+ fprintf (stderr,"l:\tuse the left version\n");
+ fprintf (stderr,"r:\tuse the right version\n");
+ fprintf (stderr,"e l:\tedit then use the left version\n");
+ fprintf (stderr,"e r:\tedit then use the right version\n");
+ fprintf (stderr,"e b:\tedit then use the left and right versions concatenated\n");
+ fprintf (stderr,"e:\tedit a new version\n");
+ fprintf (stderr,"s:\tsilently include common lines\n");
+ fprintf (stderr,"v:\tverbosely include common lines\n");
+ fprintf (stderr,"q:\tquit\n");
+}
+
+static int
+skip_white ()
+{
+ int c;
+ for (;;)
+ {
+ c = getchar ();
+ if (!ISSPACE (c) || c == '\n')
+ break;
+ checksigs ();
+ }
+ if (ferror (stdin))
+ perror_fatal ("input error");
+ return c;
+}
+
+static void
+flush_line ()
+{
+ int c;
+ while ((c = getchar ()) != '\n' && c != EOF)
+ ;
+ if (ferror (stdin))
+ perror_fatal ("input error");
+}
+
+
+/* interpret an edit command */
+static int
+edit (left, lenl, right, lenr, outfile)
+ struct line_filter *left;
+ int lenl;
+ struct line_filter *right;
+ int lenr;
+ FILE *outfile;
+{
+ for (;;)
+ {
+ int cmd0, cmd1;
+ int gotcmd = 0;
+
+ cmd1 = 0; /* Pacify `gcc -W'. */
+
+ while (!gotcmd)
+ {
+ if (putchar ('%') != '%')
+ perror_fatal ("output error");
+ ck_fflush (stdout);
+
+ cmd0 = skip_white ();
+ switch (cmd0)
+ {
+ case 'l': case 'r': case 's': case 'v': case 'q':
+ if (skip_white () != '\n')
+ {
+ give_help ();
+ flush_line ();
+ continue;
+ }
+ gotcmd = 1;
+ break;
+
+ case 'e':
+ cmd1 = skip_white ();
+ switch (cmd1)
+ {
+ case 'l': case 'r': case 'b':
+ if (skip_white () != '\n')
+ {
+ give_help ();
+ flush_line ();
+ continue;
+ }
+ gotcmd = 1;
+ break;
+ case '\n':
+ gotcmd = 1;
+ break;
+ default:
+ give_help ();
+ flush_line ();
+ continue;
+ }
+ break;
+ case EOF:
+ if (feof (stdin))
+ {
+ gotcmd = 1;
+ cmd0 = 'q';
+ break;
+ }
+ /* falls through */
+ default:
+ flush_line ();
+ /* falls through */
+ case '\n':
+ give_help ();
+ continue;
+ }
+ }
+
+ switch (cmd0)
+ {
+ case 'l':
+ lf_copy (left, lenl, outfile);
+ lf_skip (right, lenr);
+ return 1;
+ case 'r':
+ lf_copy (right, lenr, outfile);
+ lf_skip (left, lenl);
+ return 1;
+ case 's':
+ suppress_common_flag = 1;
+ break;
+ case 'v':
+ suppress_common_flag = 0;
+ break;
+ case 'q':
+ return 0;
+ case 'e':
+ if (! tmpname && ! (tmpname = private_tempnam ()))
+ perror_fatal ("temporary file name");
+
+ tmpmade = 1;
+
+ {
+ FILE *tmp = ck_fopen (tmpname, "w+");
+
+ if (cmd1 == 'l' || cmd1 == 'b')
+ lf_copy (left, lenl, tmp);
+ else
+ lf_skip (left, lenl);
+
+ if (cmd1 == 'r' || cmd1 == 'b')
+ lf_copy (right, lenr, tmp);
+ else
+ lf_skip (right, lenr);
+
+ ck_fflush (tmp);
+
+ {
+ int wstatus;
+#if ! HAVE_FORK
+ char *command = xmalloc (strlen (edbin) + strlen (tmpname) + 2);
+ sprintf (command, "%s %s", edbin, tmpname);
+ wstatus = system (command);
+ free (command);
+#else /* HAVE_FORK */
+ pid_t pid;
+
+ ignore_SIGINT = 1;
+ checksigs ();
+
+ pid = vfork ();
+ if (pid == 0)
+ {
+ char const *argv[3];
+ int i = 0;
+
+ argv[i++] = edbin;
+ argv[i++] = tmpname;
+ argv[i++] = 0;
+
+ execvp (edbin, (char **) argv);
+ write (STDERR_FILENO, edbin, strlen (edbin));
+ write (STDERR_FILENO, ": not found\n", 12);
+ _exit (1);
+ }
+
+ if (pid < 0)
+ perror_fatal ("fork failed");
+
+ while (waitpid (pid, &wstatus, 0) < 0)
+ if (errno == EINTR)
+ checksigs ();
+ else
+ perror_fatal ("wait failed");
+
+ ignore_SIGINT = 0;
+#endif /* HAVE_FORK */
+
+ if (wstatus != 0)
+ fatal ("Subsidiary editor failed");
+ }
+
+ if (fseek (tmp, 0L, SEEK_SET) != 0)
+ perror_fatal ("fseek");
+ {
+ /* SDIFF_BUFSIZE is too big for a local var
+ in some compilers, so we allocate it dynamically. */
+ char *buf = xmalloc (SDIFF_BUFSIZE);
+ size_t size;
+
+ while ((size = ck_fread (buf, SDIFF_BUFSIZE, tmp)) != 0)
+ {
+ checksigs ();
+ ck_fwrite (buf, size, outfile);
+ }
+ ck_fclose (tmp);
+
+ free (buf);
+ }
+ return 1;
+ }
+ default:
+ give_help ();
+ break;
+ }
+ }
+}
+
+
+
+/* Alternately reveal bursts of diff output and handle user commands. */
+static int
+interact (diff, left, right, outfile)
+ struct line_filter *diff;
+ struct line_filter *left;
+ struct line_filter *right;
+ FILE *outfile;
+{
+ for (;;)
+ {
+ char diff_help[256];
+ int snarfed = lf_snarf (diff, diff_help, sizeof (diff_help));
+
+ if (snarfed <= 0)
+ return snarfed;
+
+ checksigs ();
+
+ switch (diff_help[0])
+ {
+ case ' ':
+ puts (diff_help + 1);
+ break;
+ case 'i':
+ {
+ int lenl = atoi (diff_help + 1), lenr, lenmax;
+ char *p = strchr (diff_help, ',');
+
+ if (!p)
+ fatal (diff_help);
+ lenr = atoi (p + 1);
+ lenmax = max (lenl, lenr);
+
+ if (suppress_common_flag)
+ lf_skip (diff, lenmax);
+ else
+ lf_copy (diff, lenmax, stdout);
+
+ lf_copy (left, lenl, outfile);
+ lf_skip (right, lenr);
+ break;
+ }
+ case 'c':
+ {
+ int lenl = atoi (diff_help + 1), lenr;
+ char *p = strchr (diff_help, ',');
+
+ if (!p)
+ fatal (diff_help);
+ lenr = atoi (p + 1);
+ lf_copy (diff, max (lenl, lenr), stdout);
+ if (! edit (left, lenl, right, lenr, outfile))
+ return 0;
+ break;
+ }
+ default:
+ fatal (diff_help);
+ break;
+ }
+ }
+}
+
+
+
+/* temporary lossage: this is torn from gnu libc */
+/* Return nonzero if DIR is an existing directory. */
+static int
+diraccess (dir)
+ char const *dir;
+{
+ struct stat buf;
+ return stat (dir, &buf) == 0 && S_ISDIR (buf.st_mode);
+}
+
+#if ! HAVE_TMPNAM
+
+/* Return zero if we know that FILE does not exist. */
+static int
+exists (file)
+ char const *file;
+{
+ struct stat buf;
+ return stat (file, &buf) == 0 || errno != ENOENT;
+}
+
+/* These are the characters used in temporary filenames. */
+static char const letters[] =
+ "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
+
+/* Generate a temporary filename and return it (in a newly allocated buffer).
+ Use the prefix "dif" as in tempnam.
+ This goes through a cyclic pattern of all possible
+ filenames consisting of five decimal digits of the current pid and three
+ of the characters in `letters'. Each potential filename is
+ tested for an already-existing file of the same name, and no name of an
+ existing file will be returned. When the cycle reaches its end
+ return 0. */
+static char *
+private_tempnam ()
+{
+ char const *dir = getenv (TMPDIR_ENV);
+ static char const tmpdir[] = PVT_tmpdir;
+ size_t index;
+ char *buf;
+ pid_t pid = getpid ();
+ size_t dlen;
+
+ if (!dir)
+ dir = tmpdir;
+
+ dlen = strlen (dir);
+
+ /* Remove trailing slashes from the directory name. */
+ while (dlen && dir[dlen - 1] == '/')
+ --dlen;
+
+ buf = xmalloc (dlen + 1 + 3 + 5 + 1 + 3 + 1);
+
+ sprintf (buf, "%.*s/.", (int) dlen, dir);
+ if (diraccess (buf))
+ {
+ for (index = 0;
+ index < ((sizeof (letters) - 1) * (sizeof (letters) - 1)
+ * (sizeof (letters) - 1));
+ ++index)
+ {
+ /* Construct a file name and see if it already exists.
+
+ We use a single counter in INDEX to cycle each of three
+ character positions through each of 62 possible letters. */
+
+ sprintf (buf, "%.*s/dif%.5lu.%c%c%c", (int) dlen, dir,
+ (unsigned long) pid % 100000,
+ letters[index % (sizeof (letters) - 1)],
+ letters[(index / (sizeof (letters) - 1))
+ % (sizeof (letters) - 1)],
+ letters[index / ((sizeof (letters) - 1) *
+ (sizeof (letters) - 1))]);
+
+ if (!exists (buf))
+ return buf;
+ }
+ errno = EEXIST;
+ }
+
+ /* Don't free buf; `free' might change errno. We'll exit soon anyway. */
+ return 0;
+}
+
+#endif /* ! HAVE_TMPNAM */
diff --git a/gnu/usr.bin/diff/side.c b/gnu/usr.bin/diff/side.c
new file mode 100644
index 0000000..a150b5e
--- /dev/null
+++ b/gnu/usr.bin/diff/side.c
@@ -0,0 +1,284 @@
+/* sdiff-format output routines for GNU DIFF.
+ Copyright (C) 1991, 1992, 1993 Free Software Foundation, Inc.
+
+This file is part of GNU DIFF.
+
+GNU DIFF is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY. No author or distributor
+accepts responsibility to anyone for the consequences of using it
+or for whether it serves any particular purpose or works at all,
+unless he says so in writing. Refer to the GNU DIFF General Public
+License for full details.
+
+Everyone is granted permission to copy, modify and redistribute
+GNU DIFF, but only under the conditions described in the
+GNU DIFF General Public License. A copy of this license is
+supposed to have been given to you along with GNU DIFF so you
+can know your rights and responsibilities. It should be in a
+file named COPYING. Among other things, the copyright notice
+and this notice must be preserved on all copies. */
+
+
+#include "diff.h"
+
+static unsigned print_half_line PARAMS((char const * const *, unsigned, unsigned));
+static unsigned tab_from_to PARAMS((unsigned, unsigned));
+static void print_1sdiff_line PARAMS((char const * const *, int, char const * const *));
+static void print_sdiff_common_lines PARAMS((int, int));
+static void print_sdiff_hunk PARAMS((struct change *));
+
+/* Next line number to be printed in the two input files. */
+static int next0, next1;
+
+/* Print the edit-script SCRIPT as a sdiff style output. */
+
+void
+print_sdiff_script (script)
+ struct change *script;
+{
+ begin_output ();
+
+ next0 = next1 = - files[0].prefix_lines;
+ print_script (script, find_change, print_sdiff_hunk);
+
+ print_sdiff_common_lines (files[0].valid_lines, files[1].valid_lines);
+}
+
+/* Tab from column FROM to column TO, where FROM <= TO. Yield TO. */
+
+static unsigned
+tab_from_to (from, to)
+ unsigned from, to;
+{
+ FILE *out = outfile;
+ unsigned tab;
+
+ if (! tab_expand_flag)
+ for (tab = from + TAB_WIDTH - from % TAB_WIDTH; tab <= to; tab += TAB_WIDTH)
+ {
+ putc ('\t', out);
+ from = tab;
+ }
+ while (from++ < to)
+ putc (' ', out);
+ return to;
+}
+
+/*
+ * Print the text for half an sdiff line. This means truncate to width
+ * observing tabs, and trim a trailing newline. Returns the last column
+ * written (not the number of chars).
+ */
+static unsigned
+print_half_line (line, indent, out_bound)
+ char const * const *line;
+ unsigned indent, out_bound;
+{
+ FILE *out = outfile;
+ register unsigned in_position = 0, out_position = 0;
+ register char const
+ *text_pointer = line[0],
+ *text_limit = line[1];
+
+ while (text_pointer < text_limit)
+ {
+ register unsigned char c = *text_pointer++;
+
+ switch (c)
+ {
+ case '\t':
+ {
+ unsigned spaces = TAB_WIDTH - in_position % TAB_WIDTH;
+ if (in_position == out_position)
+ {
+ unsigned tabstop = out_position + spaces;
+ if (tab_expand_flag)
+ {
+ if (out_bound < tabstop)
+ tabstop = out_bound;
+ for (; out_position < tabstop; out_position++)
+ putc (' ', out);
+ }
+ else
+ if (tabstop < out_bound)
+ {
+ out_position = tabstop;
+ putc (c, out);
+ }
+ }
+ in_position += spaces;
+ }
+ break;
+
+ case '\r':
+ {
+ putc (c, out);
+ tab_from_to (0, indent);
+ in_position = out_position = 0;
+ }
+ break;
+
+ case '\b':
+ if (in_position != 0 && --in_position < out_bound)
+ if (out_position <= in_position)
+ /* Add spaces to make up for suppressed tab past out_bound. */
+ for (; out_position < in_position; out_position++)
+ putc (' ', out);
+ else
+ {
+ out_position = in_position;
+ putc (c, out);
+ }
+ break;
+
+ case '\f':
+ case '\v':
+ control_char:
+ if (in_position < out_bound)
+ putc (c, out);
+ break;
+
+ default:
+ if (! ISPRINT (c))
+ goto control_char;
+ /* falls through */
+ case ' ':
+ if (in_position++ < out_bound)
+ {
+ out_position = in_position;
+ putc (c, out);
+ }
+ break;
+
+ case '\n':
+ return out_position;
+ }
+ }
+
+ return out_position;
+}
+
+/*
+ * Print side by side lines with a separator in the middle.
+ * 0 parameters are taken to indicate white space text.
+ * Blank lines that can easily be caught are reduced to a single newline.
+ */
+
+static void
+print_1sdiff_line (left, sep, right)
+ char const * const *left;
+ int sep;
+ char const * const *right;
+{
+ FILE *out = outfile;
+ unsigned hw = sdiff_half_width, c2o = sdiff_column2_offset;
+ unsigned col = 0;
+ int put_newline = 0;
+
+ if (left)
+ {
+ if (left[1][-1] == '\n')
+ put_newline = 1;
+ col = print_half_line (left, 0, hw);
+ }
+
+ if (sep != ' ')
+ {
+ col = tab_from_to (col, (hw + c2o - 1) / 2) + 1;
+ if (sep == '|' && put_newline != (right[1][-1] == '\n'))
+ sep = put_newline ? '/' : '\\';
+ putc (sep, out);
+ }
+
+ if (right)
+ {
+ if (right[1][-1] == '\n')
+ put_newline = 1;
+ if (**right != '\n')
+ {
+ col = tab_from_to (col, c2o);
+ print_half_line (right, col, hw);
+ }
+ }
+
+ if (put_newline)
+ putc ('\n', out);
+}
+
+/* Print lines common to both files in side-by-side format. */
+static void
+print_sdiff_common_lines (limit0, limit1)
+ int limit0, limit1;
+{
+ int i0 = next0, i1 = next1;
+
+ if (! sdiff_skip_common_lines && (i0 != limit0 || i1 != limit1))
+ {
+ if (sdiff_help_sdiff)
+ fprintf (outfile, "i%d,%d\n", limit0 - i0, limit1 - i1);
+
+ if (! sdiff_left_only)
+ {
+ while (i0 != limit0 && i1 != limit1)
+ print_1sdiff_line (&files[0].linbuf[i0++], ' ', &files[1].linbuf[i1++]);
+ while (i1 != limit1)
+ print_1sdiff_line (0, ')', &files[1].linbuf[i1++]);
+ }
+ while (i0 != limit0)
+ print_1sdiff_line (&files[0].linbuf[i0++], '(', 0);
+ }
+
+ next0 = limit0;
+ next1 = limit1;
+}
+
+/* Print a hunk of an sdiff diff.
+ This is a contiguous portion of a complete edit script,
+ describing changes in consecutive lines. */
+
+static void
+print_sdiff_hunk (hunk)
+ struct change *hunk;
+{
+ int first0, last0, first1, last1, deletes, inserts;
+ register int i, j;
+
+ /* Determine range of line numbers involved in each file. */
+ analyze_hunk (hunk, &first0, &last0, &first1, &last1, &deletes, &inserts);
+ if (!deletes && !inserts)
+ return;
+
+ /* Print out lines up to this change. */
+ print_sdiff_common_lines (first0, first1);
+
+ if (sdiff_help_sdiff)
+ fprintf (outfile, "c%d,%d\n", last0 - first0 + 1, last1 - first1 + 1);
+
+ /* Print ``xxx | xxx '' lines */
+ if (inserts && deletes)
+ {
+ for (i = first0, j = first1; i <= last0 && j <= last1; ++i, ++j)
+ print_1sdiff_line (&files[0].linbuf[i], '|', &files[1].linbuf[j]);
+ deletes = i <= last0;
+ inserts = j <= last1;
+ next0 = first0 = i;
+ next1 = first1 = j;
+ }
+
+
+ /* Print `` > xxx '' lines */
+ if (inserts)
+ {
+ for (j = first1; j <= last1; ++j)
+ print_1sdiff_line (0, '>', &files[1].linbuf[j]);
+ next1 = j;
+ }
+
+ /* Print ``xxx < '' lines */
+ if (deletes)
+ {
+ for (i = first0; i <= last0; ++i)
+ print_1sdiff_line (&files[0].linbuf[i], '<', 0);
+ next0 = i;
+ }
+}
diff --git a/gnu/usr.bin/diff/system.h b/gnu/usr.bin/diff/system.h
new file mode 100644
index 0000000..47db287
--- /dev/null
+++ b/gnu/usr.bin/diff/system.h
@@ -0,0 +1,267 @@
+/* System dependent declarations.
+ Copyright (C) 1988, 1989, 1992, 1993, 1994 Free Software Foundation, Inc.
+
+This file is part of GNU DIFF.
+
+GNU DIFF is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU DIFF is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU DIFF; see the file COPYING. If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* We must define `volatile' and `const' first (the latter inside config.h),
+ so that they're used consistently in all system includes. */
+#if !__STDC__
+#ifndef volatile
+#define volatile
+#endif
+#endif
+#include "config.h"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#if __STDC__
+#define PARAMS(args) args
+#define VOID void
+#else
+#define PARAMS(args) ()
+#define VOID char
+#endif
+
+#if STAT_MACROS_BROKEN
+#undef S_ISBLK
+#undef S_ISCHR
+#undef S_ISDIR
+#undef S_ISFIFO
+#undef S_ISREG
+#undef S_ISSOCK
+#endif
+#ifndef S_ISDIR
+#define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR)
+#endif
+#ifndef S_ISREG
+#define S_ISREG(mode) (((mode) & S_IFMT) == S_IFREG)
+#endif
+#if !defined(S_ISBLK) && defined(S_IFBLK)
+#define S_ISBLK(mode) (((mode) & S_IFMT) == S_IFBLK)
+#endif
+#if !defined(S_ISCHR) && defined(S_IFCHR)
+#define S_ISCHR(mode) (((mode) & S_IFMT) == S_IFCHR)
+#endif
+#if !defined(S_ISFIFO) && defined(S_IFFIFO)
+#define S_ISFIFO(mode) (((mode) & S_IFMT) == S_IFFIFO)
+#endif
+#if !defined(S_ISSOCK) && defined(S_IFSOCK)
+#define S_ISSOCK(mode) (((mode) & S_IFMT) == S_IFSOCK)
+#endif
+
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#ifndef SEEK_SET
+#define SEEK_SET 0
+#endif
+#ifndef SEEK_CUR
+#define SEEK_CUR 1
+#endif
+
+#ifndef STDIN_FILENO
+#define STDIN_FILENO 0
+#endif
+#ifndef STDOUT_FILENO
+#define STDOUT_FILENO 1
+#endif
+#ifndef STDERR_FILENO
+#define STDERR_FILENO 2
+#endif
+
+#if HAVE_TIME_H
+#include <time.h>
+#else
+#include <sys/time.h>
+#endif
+
+#if HAVE_FCNTL_H
+#include <fcntl.h>
+#else
+#if HAVE_SYS_FILE_H
+#include <sys/file.h>
+#endif
+#endif
+
+#if !HAVE_DUP2
+#define dup2(f,t) (close (t), fcntl (f,F_DUPFD,t))
+#endif
+
+#ifndef O_RDONLY
+#define O_RDONLY 0
+#endif
+
+#if HAVE_SYS_WAIT_H
+#include <sys/wait.h>
+#endif
+#ifndef WEXITSTATUS
+#define WEXITSTATUS(stat_val) ((unsigned) (stat_val) >> 8)
+#endif
+#ifndef WIFEXITED
+#define WIFEXITED(stat_val) (((stat_val) & 255) == 0)
+#endif
+
+#ifndef STAT_BLOCKSIZE
+#if HAVE_ST_BLKSIZE
+#define STAT_BLOCKSIZE(s) (s).st_blksize
+#else
+#define STAT_BLOCKSIZE(s) (8 * 1024)
+#endif
+#endif
+
+#if HAVE_DIRENT_H
+# include <dirent.h>
+# define NAMLEN(dirent) strlen((dirent)->d_name)
+#else
+# define dirent direct
+# define NAMLEN(dirent) ((dirent)->d_namlen)
+# if HAVE_SYS_NDIR_H
+# include <sys/ndir.h>
+# endif
+# if HAVE_SYS_DIR_H
+# include <sys/dir.h>
+# endif
+# if HAVE_NDIR_H
+# include <ndir.h>
+# endif
+#endif
+
+#if HAVE_VFORK_H
+#include <vfork.h>
+#endif
+
+#if HAVE_STDLIB_H
+#include <stdlib.h>
+#else
+VOID *malloc ();
+VOID *realloc ();
+#endif
+#ifndef getenv
+char *getenv ();
+#endif
+
+#if HAVE_LIMITS_H
+#include <limits.h>
+#endif
+#ifndef INT_MAX
+#define INT_MAX 2147483647
+#endif
+#ifndef CHAR_BIT
+#define CHAR_BIT 8
+#endif
+
+#if STDC_HEADERS || HAVE_STRING_H
+# include <string.h>
+# ifndef bzero
+# define bzero(s, n) memset (s, 0, n)
+# endif
+#else
+# if !HAVE_STRCHR
+# define strchr index
+# define strrchr rindex
+# endif
+char *strchr (), *strrchr ();
+# if !HAVE_MEMCHR
+# define memcmp(s1, s2, n) bcmp (s1, s2, n)
+# define memcpy(d, s, n) bcopy (s, d, n)
+void *memchr ();
+# endif
+#endif
+
+#include <ctype.h>
+/* CTYPE_DOMAIN (C) is nonzero if the unsigned char C can safely be given
+ as an argument to <ctype.h> macros like `isspace'. */
+#if STDC_HEADERS
+#define CTYPE_DOMAIN(c) 1
+#else
+#define CTYPE_DOMAIN(c) ((unsigned) (c) <= 0177)
+#endif
+#ifndef ISPRINT
+#define ISPRINT(c) (CTYPE_DOMAIN (c) && isprint (c))
+#endif
+#ifndef ISSPACE
+#define ISSPACE(c) (CTYPE_DOMAIN (c) && isspace (c))
+#endif
+#ifndef ISUPPER
+#define ISUPPER(c) (CTYPE_DOMAIN (c) && isupper (c))
+#endif
+
+#ifndef ISDIGIT
+#define ISDIGIT(c) ((unsigned) (c) - '0' <= 9)
+#endif
+
+#include <errno.h>
+#if !STDC_HEADERS
+extern int errno;
+#endif
+
+#ifdef min
+#undef min
+#endif
+#ifdef max
+#undef max
+#endif
+#define min(a,b) ((a) <= (b) ? (a) : (b))
+#define max(a,b) ((a) >= (b) ? (a) : (b))
+
+/* This section contains Posix-compliant defaults for macros
+ that are meant to be overridden by hand in config.h as needed. */
+
+#ifndef filename_cmp
+#define filename_cmp(a, b) strcmp (a, b)
+#endif
+
+#ifndef filename_lastdirchar
+#define filename_lastdirchar(filename) strrchr (filename, '/')
+#endif
+
+#ifndef HAVE_FORK
+#define HAVE_FORK 1
+#endif
+
+#ifndef HAVE_SETMODE
+#define HAVE_SETMODE 0
+#endif
+
+#ifndef initialize_main
+#define initialize_main(argcp, argvp)
+#endif
+
+/* Do struct stat *S, *T describe the same file? Answer -1 if unknown. */
+#ifndef same_file
+#define same_file(s,t) ((s)->st_ino==(t)->st_ino && (s)->st_dev==(t)->st_dev)
+#endif
+
+/* Place into Q a quoted version of A suitable for `popen' or `system',
+ incrementing Q and junking A.
+ Do not increment Q by more than 4 * strlen (A) + 2. */
+#ifndef SYSTEM_QUOTE_ARG
+#define SYSTEM_QUOTE_ARG(q, a) \
+ { \
+ *(q)++ = '\''; \
+ for (; *(a); *(q)++ = *(a)++) \
+ if (*(a) == '\'') \
+ { \
+ *(q)++ = '\''; \
+ *(q)++ = '\\'; \
+ *(q)++ = '\''; \
+ } \
+ *(q)++ = '\''; \
+ }
+#endif
diff --git a/gnu/usr.bin/diff/util.c b/gnu/usr.bin/diff/util.c
new file mode 100644
index 0000000..4cdb9ea
--- /dev/null
+++ b/gnu/usr.bin/diff/util.c
@@ -0,0 +1,754 @@
+/* Support routines for GNU DIFF.
+ Copyright (C) 1988, 1989, 1992, 1993, 1994 Free Software Foundation, Inc.
+
+This file is part of GNU DIFF.
+
+GNU DIFF is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU DIFF is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU DIFF; see the file COPYING. If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "diff.h"
+
+#ifndef PR_PROGRAM
+#define PR_PROGRAM "/usr/bin/pr"
+#endif
+
+/* Queue up one-line messages to be printed at the end,
+ when -l is specified. Each message is recorded with a `struct msg'. */
+
+struct msg
+{
+ struct msg *next;
+ char const *format;
+ char const *arg1;
+ char const *arg2;
+ char const *arg3;
+ char const *arg4;
+};
+
+/* Head of the chain of queues messages. */
+
+static struct msg *msg_chain;
+
+/* Tail of the chain of queues messages. */
+
+static struct msg **msg_chain_end = &msg_chain;
+
+/* Use when a system call returns non-zero status.
+ TEXT should normally be the file name. */
+
+void
+perror_with_name (text)
+ char const *text;
+{
+ int e = errno;
+ fprintf (stderr, "%s: ", program_name);
+ errno = e;
+ perror (text);
+}
+
+/* Use when a system call returns non-zero status and that is fatal. */
+
+void
+pfatal_with_name (text)
+ char const *text;
+{
+ int e = errno;
+ print_message_queue ();
+ fprintf (stderr, "%s: ", program_name);
+ errno = e;
+ perror (text);
+ exit (2);
+}
+
+/* Print an error message from the format-string FORMAT
+ with args ARG1 and ARG2. */
+
+void
+error (format, arg, arg1)
+ char const *format, *arg, *arg1;
+{
+ fprintf (stderr, "%s: ", program_name);
+ fprintf (stderr, format, arg, arg1);
+ fprintf (stderr, "\n");
+}
+
+/* Print an error message containing the string TEXT, then exit. */
+
+void
+fatal (m)
+ char const *m;
+{
+ print_message_queue ();
+ error ("%s", m, 0);
+ exit (2);
+}
+
+/* Like printf, except if -l in effect then save the message and print later.
+ This is used for things like "binary files differ" and "Only in ...". */
+
+void
+message (format, arg1, arg2)
+ char const *format, *arg1, *arg2;
+{
+ message5 (format, arg1, arg2, 0, 0);
+}
+
+void
+message5 (format, arg1, arg2, arg3, arg4)
+ char const *format, *arg1, *arg2, *arg3, *arg4;
+{
+ if (paginate_flag)
+ {
+ struct msg *new = (struct msg *) xmalloc (sizeof (struct msg));
+ new->format = format;
+ new->arg1 = concat (arg1, "", "");
+ new->arg2 = concat (arg2, "", "");
+ new->arg3 = arg3 ? concat (arg3, "", "") : 0;
+ new->arg4 = arg4 ? concat (arg4, "", "") : 0;
+ new->next = 0;
+ *msg_chain_end = new;
+ msg_chain_end = &new->next;
+ }
+ else
+ {
+ if (sdiff_help_sdiff)
+ putchar (' ');
+ printf (format, arg1, arg2, arg3, arg4);
+ }
+}
+
+/* Output all the messages that were saved up by calls to `message'. */
+
+void
+print_message_queue ()
+{
+ struct msg *m;
+
+ for (m = msg_chain; m; m = m->next)
+ printf (m->format, m->arg1, m->arg2, m->arg3, m->arg4);
+}
+
+/* Call before outputting the results of comparing files NAME0 and NAME1
+ to set up OUTFILE, the stdio stream for the output to go to.
+
+ Usually, OUTFILE is just stdout. But when -l was specified
+ we fork off a `pr' and make OUTFILE a pipe to it.
+ `pr' then outputs to our stdout. */
+
+static char const *current_name0;
+static char const *current_name1;
+static int current_depth;
+
+void
+setup_output (name0, name1, depth)
+ char const *name0, *name1;
+ int depth;
+{
+ current_name0 = name0;
+ current_name1 = name1;
+ current_depth = depth;
+ outfile = 0;
+}
+
+#if HAVE_FORK
+static pid_t pr_pid;
+#endif
+
+void
+begin_output ()
+{
+ char *name;
+
+ if (outfile != 0)
+ return;
+
+ /* Construct the header of this piece of diff. */
+ name = xmalloc (strlen (current_name0) + strlen (current_name1)
+ + strlen (switch_string) + 7);
+ /* Posix.2 section 4.17.6.1.1 specifies this format. But there is a
+ bug in the first printing (IEEE Std 1003.2-1992 p 251 l 3304):
+ it says that we must print only the last component of the pathnames.
+ This requirement is silly and does not match historical practice. */
+ sprintf (name, "diff%s %s %s", switch_string, current_name0, current_name1);
+
+ if (paginate_flag)
+ {
+ /* Make OUTFILE a pipe to a subsidiary `pr'. */
+
+#if HAVE_FORK
+ int pipes[2];
+
+ if (pipe (pipes) != 0)
+ pfatal_with_name ("pipe");
+
+ fflush (stdout);
+
+ pr_pid = vfork ();
+ if (pr_pid < 0)
+ pfatal_with_name ("vfork");
+
+ if (pr_pid == 0)
+ {
+ close (pipes[1]);
+ if (pipes[0] != STDIN_FILENO)
+ {
+ if (dup2 (pipes[0], STDIN_FILENO) < 0)
+ pfatal_with_name ("dup2");
+ close (pipes[0]);
+ }
+
+ execl (PR_PROGRAM, PR_PROGRAM, "-F", "-h", name, 0);
+ pfatal_with_name (PR_PROGRAM);
+ }
+ else
+ {
+ close (pipes[0]);
+ outfile = fdopen (pipes[1], "w");
+ if (!outfile)
+ pfatal_with_name ("fdopen");
+ }
+#else /* ! HAVE_FORK */
+ char *command = xmalloc (4 * strlen (name) + strlen (PR_PROGRAM) + 10);
+ char *p;
+ char const *a = name;
+ sprintf (command, "%s -F -h ", PR_PROGRAM);
+ p = command + strlen (command);
+ SYSTEM_QUOTE_ARG (p, a);
+ *p = 0;
+ outfile = popen (command, "w");
+ if (!outfile)
+ pfatal_with_name (command);
+ free (command);
+#endif /* ! HAVE_FORK */
+ }
+ else
+ {
+
+ /* If -l was not specified, output the diff straight to `stdout'. */
+
+ outfile = stdout;
+
+ /* If handling multiple files (because scanning a directory),
+ print which files the following output is about. */
+ if (current_depth > 0)
+ printf ("%s\n", name);
+ }
+
+ free (name);
+
+ /* A special header is needed at the beginning of context output. */
+ switch (output_style)
+ {
+ case OUTPUT_CONTEXT:
+ print_context_header (files, 0);
+ break;
+
+ case OUTPUT_UNIFIED:
+ print_context_header (files, 1);
+ break;
+
+ default:
+ break;
+ }
+}
+
+/* Call after the end of output of diffs for one file.
+ Close OUTFILE and get rid of the `pr' subfork. */
+
+void
+finish_output ()
+{
+ if (outfile != 0 && outfile != stdout)
+ {
+ int wstatus;
+ if (ferror (outfile))
+ fatal ("write error");
+#if ! HAVE_FORK
+ wstatus = pclose (outfile);
+#else /* HAVE_FORK */
+ if (fclose (outfile) != 0)
+ pfatal_with_name ("write error");
+ if (waitpid (pr_pid, &wstatus, 0) < 0)
+ pfatal_with_name ("waitpid");
+#endif /* HAVE_FORK */
+ if (wstatus != 0)
+ fatal ("subsidiary pr failed");
+ }
+
+ outfile = 0;
+}
+
+/* Compare two lines (typically one from each input file)
+ according to the command line options.
+ For efficiency, this is invoked only when the lines do not match exactly
+ but an option like -i might cause us to ignore the difference.
+ Return nonzero if the lines differ. */
+
+int
+line_cmp (s1, s2)
+ char const *s1, *s2;
+{
+ register unsigned char const *t1 = (unsigned char const *) s1;
+ register unsigned char const *t2 = (unsigned char const *) s2;
+
+ while (1)
+ {
+ register unsigned char c1 = *t1++;
+ register unsigned char c2 = *t2++;
+
+ /* Test for exact char equality first, since it's a common case. */
+ if (c1 != c2)
+ {
+ /* Ignore horizontal white space if -b or -w is specified. */
+
+ if (ignore_all_space_flag)
+ {
+ /* For -w, just skip past any white space. */
+ while (ISSPACE (c1) && c1 != '\n') c1 = *t1++;
+ while (ISSPACE (c2) && c2 != '\n') c2 = *t2++;
+ }
+ else if (ignore_space_change_flag)
+ {
+ /* For -b, advance past any sequence of white space in line 1
+ and consider it just one Space, or nothing at all
+ if it is at the end of the line. */
+ if (ISSPACE (c1))
+ {
+ while (c1 != '\n')
+ {
+ c1 = *t1++;
+ if (! ISSPACE (c1))
+ {
+ --t1;
+ c1 = ' ';
+ break;
+ }
+ }
+ }
+
+ /* Likewise for line 2. */
+ if (ISSPACE (c2))
+ {
+ while (c2 != '\n')
+ {
+ c2 = *t2++;
+ if (! ISSPACE (c2))
+ {
+ --t2;
+ c2 = ' ';
+ break;
+ }
+ }
+ }
+
+ if (c1 != c2)
+ {
+ /* If we went too far when doing the simple test
+ for equality, go back to the first non-white-space
+ character in both sides and try again. */
+ if (c2 == ' ' && c1 != '\n'
+ && (unsigned char const *) s1 + 1 < t1
+ && ISSPACE(t1[-2]))
+ {
+ --t1;
+ continue;
+ }
+ if (c1 == ' ' && c2 != '\n'
+ && (unsigned char const *) s2 + 1 < t2
+ && ISSPACE(t2[-2]))
+ {
+ --t2;
+ continue;
+ }
+ }
+ }
+
+ /* Lowercase all letters if -i is specified. */
+
+ if (ignore_case_flag)
+ {
+ if (ISUPPER (c1))
+ c1 = tolower (c1);
+ if (ISUPPER (c2))
+ c2 = tolower (c2);
+ }
+
+ if (c1 != c2)
+ break;
+ }
+ if (c1 == '\n')
+ return 0;
+ }
+
+ return (1);
+}
+
+/* Find the consecutive changes at the start of the script START.
+ Return the last link before the first gap. */
+
+struct change *
+find_change (start)
+ struct change *start;
+{
+ return start;
+}
+
+struct change *
+find_reverse_change (start)
+ struct change *start;
+{
+ return start;
+}
+
+/* Divide SCRIPT into pieces by calling HUNKFUN and
+ print each piece with PRINTFUN.
+ Both functions take one arg, an edit script.
+
+ HUNKFUN is called with the tail of the script
+ and returns the last link that belongs together with the start
+ of the tail.
+
+ PRINTFUN takes a subscript which belongs together (with a null
+ link at the end) and prints it. */
+
+void
+print_script (script, hunkfun, printfun)
+ struct change *script;
+ struct change * (*hunkfun) PARAMS((struct change *));
+ void (*printfun) PARAMS((struct change *));
+{
+ struct change *next = script;
+
+ while (next)
+ {
+ struct change *this, *end;
+
+ /* Find a set of changes that belong together. */
+ this = next;
+ end = (*hunkfun) (next);
+
+ /* Disconnect them from the rest of the changes,
+ making them a hunk, and remember the rest for next iteration. */
+ next = end->link;
+ end->link = 0;
+#ifdef DEBUG
+ debug_script (this);
+#endif
+
+ /* Print this hunk. */
+ (*printfun) (this);
+
+ /* Reconnect the script so it will all be freed properly. */
+ end->link = next;
+ }
+}
+
+/* Print the text of a single line LINE,
+ flagging it with the characters in LINE_FLAG (which say whether
+ the line is inserted, deleted, changed, etc.). */
+
+void
+print_1_line (line_flag, line)
+ char const *line_flag;
+ char const * const *line;
+{
+ char const *text = line[0], *limit = line[1]; /* Help the compiler. */
+ FILE *out = outfile; /* Help the compiler some more. */
+ char const *flag_format = 0;
+
+ /* If -T was specified, use a Tab between the line-flag and the text.
+ Otherwise use a Space (as Unix diff does).
+ Print neither space nor tab if line-flags are empty. */
+
+ if (line_flag && *line_flag)
+ {
+ flag_format = tab_align_flag ? "%s\t" : "%s ";
+ fprintf (out, flag_format, line_flag);
+ }
+
+ output_1_line (text, limit, flag_format, line_flag);
+
+ if ((!line_flag || line_flag[0]) && limit[-1] != '\n')
+ fprintf (out, "\n\\ No newline at end of file\n");
+}
+
+/* Output a line from TEXT up to LIMIT. Without -t, output verbatim.
+ With -t, expand white space characters to spaces, and if FLAG_FORMAT
+ is nonzero, output it with argument LINE_FLAG after every
+ internal carriage return, so that tab stops continue to line up. */
+
+void
+output_1_line (text, limit, flag_format, line_flag)
+ char const *text, *limit, *flag_format, *line_flag;
+{
+ if (!tab_expand_flag)
+ fwrite (text, sizeof (char), limit - text, outfile);
+ else
+ {
+ register FILE *out = outfile;
+ register unsigned char c;
+ register char const *t = text;
+ register unsigned column = 0;
+
+ while (t < limit)
+ switch ((c = *t++))
+ {
+ case '\t':
+ {
+ unsigned spaces = TAB_WIDTH - column % TAB_WIDTH;
+ column += spaces;
+ do
+ putc (' ', out);
+ while (--spaces);
+ }
+ break;
+
+ case '\r':
+ putc (c, out);
+ if (flag_format && t < limit && *t != '\n')
+ fprintf (out, flag_format, line_flag);
+ column = 0;
+ break;
+
+ case '\b':
+ if (column == 0)
+ continue;
+ column--;
+ putc (c, out);
+ break;
+
+ default:
+ if (ISPRINT (c))
+ column++;
+ putc (c, out);
+ break;
+ }
+ }
+}
+
+int
+change_letter (inserts, deletes)
+ int inserts, deletes;
+{
+ if (!inserts)
+ return 'd';
+ else if (!deletes)
+ return 'a';
+ else
+ return 'c';
+}
+
+/* Translate an internal line number (an index into diff's table of lines)
+ into an actual line number in the input file.
+ The internal line number is LNUM. FILE points to the data on the file.
+
+ Internal line numbers count from 0 starting after the prefix.
+ Actual line numbers count from 1 within the entire file. */
+
+int
+translate_line_number (file, lnum)
+ struct file_data const *file;
+ int lnum;
+{
+ return lnum + file->prefix_lines + 1;
+}
+
+void
+translate_range (file, a, b, aptr, bptr)
+ struct file_data const *file;
+ int a, b;
+ int *aptr, *bptr;
+{
+ *aptr = translate_line_number (file, a - 1) + 1;
+ *bptr = translate_line_number (file, b + 1) - 1;
+}
+
+/* Print a pair of line numbers with SEPCHAR, translated for file FILE.
+ If the two numbers are identical, print just one number.
+
+ Args A and B are internal line numbers.
+ We print the translated (real) line numbers. */
+
+void
+print_number_range (sepchar, file, a, b)
+ int sepchar;
+ struct file_data *file;
+ int a, b;
+{
+ int trans_a, trans_b;
+ translate_range (file, a, b, &trans_a, &trans_b);
+
+ /* Note: we can have B < A in the case of a range of no lines.
+ In this case, we should print the line number before the range,
+ which is B. */
+ if (trans_b > trans_a)
+ fprintf (outfile, "%d%c%d", trans_a, sepchar, trans_b);
+ else
+ fprintf (outfile, "%d", trans_b);
+}
+
+/* Look at a hunk of edit script and report the range of lines in each file
+ that it applies to. HUNK is the start of the hunk, which is a chain
+ of `struct change'. The first and last line numbers of file 0 are stored in
+ *FIRST0 and *LAST0, and likewise for file 1 in *FIRST1 and *LAST1.
+ Note that these are internal line numbers that count from 0.
+
+ If no lines from file 0 are deleted, then FIRST0 is LAST0+1.
+
+ Also set *DELETES nonzero if any lines of file 0 are deleted
+ and set *INSERTS nonzero if any lines of file 1 are inserted.
+ If only ignorable lines are inserted or deleted, both are
+ set to 0. */
+
+void
+analyze_hunk (hunk, first0, last0, first1, last1, deletes, inserts)
+ struct change *hunk;
+ int *first0, *last0, *first1, *last1;
+ int *deletes, *inserts;
+{
+ int l0, l1, show_from, show_to;
+ int i;
+ int trivial = ignore_blank_lines_flag || ignore_regexp_list;
+ struct change *next;
+
+ show_from = show_to = 0;
+
+ *first0 = hunk->line0;
+ *first1 = hunk->line1;
+
+ next = hunk;
+ do
+ {
+ l0 = next->line0 + next->deleted - 1;
+ l1 = next->line1 + next->inserted - 1;
+ show_from += next->deleted;
+ show_to += next->inserted;
+
+ for (i = next->line0; i <= l0 && trivial; i++)
+ if (!ignore_blank_lines_flag || files[0].linbuf[i][0] != '\n')
+ {
+ struct regexp_list *r;
+ char const *line = files[0].linbuf[i];
+ int len = files[0].linbuf[i + 1] - line;
+
+ for (r = ignore_regexp_list; r; r = r->next)
+ if (0 <= re_search (&r->buf, line, len, 0, len, 0))
+ break; /* Found a match. Ignore this line. */
+ /* If we got all the way through the regexp list without
+ finding a match, then it's nontrivial. */
+ if (!r)
+ trivial = 0;
+ }
+
+ for (i = next->line1; i <= l1 && trivial; i++)
+ if (!ignore_blank_lines_flag || files[1].linbuf[i][0] != '\n')
+ {
+ struct regexp_list *r;
+ char const *line = files[1].linbuf[i];
+ int len = files[1].linbuf[i + 1] - line;
+
+ for (r = ignore_regexp_list; r; r = r->next)
+ if (0 <= re_search (&r->buf, line, len, 0, len, 0))
+ break; /* Found a match. Ignore this line. */
+ /* If we got all the way through the regexp list without
+ finding a match, then it's nontrivial. */
+ if (!r)
+ trivial = 0;
+ }
+ }
+ while ((next = next->link) != 0);
+
+ *last0 = l0;
+ *last1 = l1;
+
+ /* If all inserted or deleted lines are ignorable,
+ tell the caller to ignore this hunk. */
+
+ if (trivial)
+ show_from = show_to = 0;
+
+ *deletes = show_from;
+ *inserts = show_to;
+}
+
+/* malloc a block of memory, with fatal error message if we can't do it. */
+
+VOID *
+xmalloc (size)
+ size_t size;
+{
+ register VOID *value;
+
+ if (size == 0)
+ size = 1;
+
+ value = (VOID *) malloc (size);
+
+ if (!value)
+ fatal ("memory exhausted");
+ return value;
+}
+
+/* realloc a block of memory, with fatal error message if we can't do it. */
+
+VOID *
+xrealloc (old, size)
+ VOID *old;
+ size_t size;
+{
+ register VOID *value;
+
+ if (size == 0)
+ size = 1;
+
+ value = (VOID *) realloc (old, size);
+
+ if (!value)
+ fatal ("memory exhausted");
+ return value;
+}
+
+/* Concatenate three strings, returning a newly malloc'd string. */
+
+char *
+concat (s1, s2, s3)
+ char const *s1, *s2, *s3;
+{
+ size_t len = strlen (s1) + strlen (s2) + strlen (s3);
+ char *new = xmalloc (len + 1);
+ sprintf (new, "%s%s%s", s1, s2, s3);
+ return new;
+}
+
+/* Yield the newly malloc'd pathname
+ of the file in DIR whose filename is FILE. */
+
+char *
+dir_file_pathname (dir, file)
+ char const *dir, *file;
+{
+ char const *p = filename_lastdirchar (dir);
+ return concat (dir, "/" + (p && !p[1]), file);
+}
+
+void
+debug_script (sp)
+ struct change *sp;
+{
+ fflush (stdout);
+ for (; sp; sp = sp->link)
+ fprintf (stderr, "%3d %3d delete %d insert %d\n",
+ sp->line0, sp->line1, sp->deleted, sp->inserted);
+ fflush (stderr);
+}
diff --git a/gnu/usr.bin/diff/version.c b/gnu/usr.bin/diff/version.c
new file mode 100644
index 0000000..c2b6a8a
--- /dev/null
+++ b/gnu/usr.bin/diff/version.c
@@ -0,0 +1,5 @@
+/* Version number of GNU diff. */
+
+#include "config.h"
+
+char const version_string[] = "2.7";
diff --git a/gnu/usr.bin/diff/xmalloc.c b/gnu/usr.bin/diff/xmalloc.c
new file mode 100644
index 0000000..dc44ba4
--- /dev/null
+++ b/gnu/usr.bin/diff/xmalloc.c
@@ -0,0 +1,81 @@
+/* xmalloc.c -- malloc with out of memory checking
+ Copyright (C) 1990, 1991, 1993 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#if __STDC__
+#define VOID void
+#else
+#define VOID char
+#endif
+
+#include <sys/types.h>
+
+#if STDC_HEADERS
+#include <stdlib.h>
+#else
+VOID *malloc ();
+VOID *realloc ();
+void free ();
+#endif
+
+#if __STDC__ && defined (HAVE_VPRINTF)
+void error (int, int, char const *, ...);
+#else
+void error ();
+#endif
+
+/* Allocate N bytes of memory dynamically, with error checking. */
+
+VOID *
+xmalloc (n)
+ size_t n;
+{
+ VOID *p;
+
+ p = malloc (n);
+ if (p == 0)
+ /* Must exit with 2 for `cmp'. */
+ error (2, 0, "memory exhausted");
+ return p;
+}
+
+/* Change the size of an allocated block of memory P to N bytes,
+ with error checking.
+ If P is NULL, run xmalloc.
+ If N is 0, run free and return NULL. */
+
+VOID *
+xrealloc (p, n)
+ VOID *p;
+ size_t n;
+{
+ if (p == 0)
+ return xmalloc (n);
+ if (n == 0)
+ {
+ free (p);
+ return 0;
+ }
+ p = realloc (p, n);
+ if (p == 0)
+ /* Must exit with 2 for `cmp'. */
+ error (2, 0, "memory exhausted");
+ return p;
+}
diff --git a/gnu/usr.bin/diff3/Makefile b/gnu/usr.bin/diff3/Makefile
new file mode 100644
index 0000000..3d2b422
--- /dev/null
+++ b/gnu/usr.bin/diff3/Makefile
@@ -0,0 +1,8 @@
+PROG= diff3
+SRCS= diff3.c getopt.c getopt1.c version.c
+CFLAGS+= -I$(.CURDIR)/../diff -DHAVE_CONFIG_H \
+ -DDIFF_PROGRAM=\"/usr/bin/diff\"
+MAN= diff3.1
+
+.include <bsd.prog.mk>
+.PATH: $(.CURDIR)/../diff
diff --git a/gnu/usr.bin/diff3/diff3.1 b/gnu/usr.bin/diff3/diff3.1
new file mode 100644
index 0000000..9873b08
--- /dev/null
+++ b/gnu/usr.bin/diff3/diff3.1
@@ -0,0 +1,210 @@
+.TH DIFF3 1 "22sep1993" "GNU Tools" "GNU Tools"
+.SH NAME
+diff3 \- find differences between three files
+.SH SYNOPSIS
+.B diff3
+[options] mine older yours
+.SH DESCRIPTION
+The
+.I diff3
+command compares three files and outputs descriptions
+of their differences.
+
+The files to compare are
+.IR mine ,
+.IR older ,
+and
+.IR yours .
+At most one of these three file names may be
+.BR \- ,
+which tells
+.I diff3
+to read the standard input for that file.
+.SS Options
+Below is a summary of all of the options that GNU
+.I diff3
+accepts. Multiple single letter options (unless they take an argument)
+can be combined into a single command line argument.
+.TP
+.B \-a
+Treat all files as text and compare them line-by-line, even if they
+do not appear to be text.
+.TP
+.B \-A
+Incorporate all changes from
+.I older
+to
+.I yours
+into
+.IR mine ,
+surrounding all conflicts with bracket lines.
+.TP
+.B \-B
+Old behavior of -A. Shows non-conflicts.
+.TP
+.B \-e
+Generate an
+.I ed
+script that incorporates all the changes from
+.I older
+to
+.I yours
+into
+.IR mine .
+.TP
+.B \-E
+Like
+.BR \-e ,
+except bracket lines from overlapping changes' first
+and third files.
+With
+.BR \-e ,
+an overlapping change looks like this:
+.sp
+.nf
+<<<<<<< \fImine\fP
+lines from \fImine\fP
+=======
+lines from \fIyours\fP
+>>>>>>> \fIyours\fP
+.fi
+.TP
+.B \-\-ed
+Generate an
+.I ed
+script that incorporates all the changes from
+.I older
+to
+.I yours
+into
+.IR mine .
+.TP
+.B \-\-easy\-only
+Like
+.BR \-e ,
+except output only the nonoverlapping changes.
+.TP
+.B \-i
+Generate
+.B w
+and
+.B q
+commands at the end of the
+.I ed
+script for System V compatibility. This option must be combined with
+one of the
+.B \-AeExX3
+options, and may not be combined with
+.BR \-m .
+.TP
+.B \-\-initial\-tab
+Output a tab rather than two spaces before the text of a line in normal format.
+This causes the alignment of tabs in the line to look normal.
+.TP
+.BI "\-L " label
+.ns
+.TP
+.BI \-\-label= label
+Use the label
+.I label
+for the brackets output by the
+.BR \-A ,
+.B \-E
+and
+.B \-X
+options. This option may be given up to three
+times, one for each input file. The default labels are the names of
+the input files. Thus
+.B "diff3 \-L X \-L Y \-L Z \-m A B C"
+acts like
+.BR "diff3 \-m A B C ,
+except that the output looks like it came from
+files named
+.BR X ,
+.B Y
+and
+.B Z
+rather than from files
+named
+.BR A ,
+.B B
+and
+.BR C .
+.TP
+.B \-m
+.br
+.ns
+.TP
+.B \-\-merge
+Apply the edit script to the first file and send the result to standard
+output. Unlike piping the output from
+.I diff3
+to
+.IR ed ,
+this
+works even for binary files and incomplete lines.
+.B \-A
+is assumed
+if no edit script option is specified.
+.TP
+.B \-\-overlap\-only
+Like
+.BR \-e ,
+except output only the overlapping changes.
+.TP
+.B \-\-show\-all
+Incorporate all unmerged changes from
+.I older
+to
+.I yours
+into
+.IR mine ,
+surrounding all overlapping changes with bracket lines.
+.TP
+.B \-\-show\-overlap
+Like
+.BR \-e ,
+except bracket lines from overlapping changes' first
+and third files.
+.TP
+.B \-T
+Output a tab rather than two spaces before the text of a line in normal format.
+This causes the alignment of tabs in the line to look normal.
+.TP
+.B \-\-text
+Treat all files as text and compare them line-by-line, even if they
+do not appear to be text.
+.TP
+.B \-v
+.br
+.ns
+.TP
+.B \-\-version
+Output the version number of
+.IR diff3 .
+.TP
+.B \-x
+Like
+.BR \-e ,
+except output only the overlapping changes.
+.TP
+.B \-X
+Like
+.BR \-E ,
+except output only the overlapping changes.
+In other words, like
+.BR \-x ,
+except bracket changes as in
+.BR \-E .
+.TP
+.B \-3
+Like
+.BR \-e ,
+except output only the nonoverlapping changes.
+.SH SEE ALSO
+cmp(1), comm(1), diff(1), ed(1), patch(1), sdiff(1).
+.SH DIAGNOSTICS
+An exit status of 0 means
+.I diff3
+was successful, 1 means some
+conflicts were found, and 2 means trouble.
diff --git a/gnu/usr.bin/gdb/COPYING b/gnu/usr.bin/gdb/COPYING
new file mode 100644
index 0000000..a43ea21
--- /dev/null
+++ b/gnu/usr.bin/gdb/COPYING
@@ -0,0 +1,339 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 675 Mass Ave, Cambridge, MA 02139, USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ Appendix: How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) 19yy <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) 19yy name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/gnu/usr.bin/gdb/COPYING.LIB b/gnu/usr.bin/gdb/COPYING.LIB
new file mode 100644
index 0000000..eb685a5
--- /dev/null
+++ b/gnu/usr.bin/gdb/COPYING.LIB
@@ -0,0 +1,481 @@
+ GNU LIBRARY GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1991 Free Software Foundation, Inc.
+ 675 Mass Ave, Cambridge, MA 02139, USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the library GPL. It is
+ numbered 2 because it goes with version 2 of the ordinary GPL.]
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+ This license, the Library General Public License, applies to some
+specially designated Free Software Foundation software, and to any
+other libraries whose authors decide to use it. You can use it for
+your libraries, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if
+you distribute copies of the library, or if you modify it.
+
+ For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you. You must make sure that they, too, receive or can get the source
+code. If you link a program with the library, you must provide
+complete object files to the recipients so that they can relink them
+with the library, after making changes to the library and recompiling
+it. And you must show them these terms so they know their rights.
+
+ Our method of protecting your rights has two steps: (1) copyright
+the library, and (2) offer you this license which gives you legal
+permission to copy, distribute and/or modify the library.
+
+ Also, for each distributor's protection, we want to make certain
+that everyone understands that there is no warranty for this free
+library. If the library is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original
+version, so that any problems introduced by others will not reflect on
+the original authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that companies distributing free
+software will individually obtain patent licenses, thus in effect
+transforming the program into proprietary software. To prevent this,
+we have made it clear that any patent must be licensed for everyone's
+free use or not licensed at all.
+
+ Most GNU software, including some libraries, is covered by the ordinary
+GNU General Public License, which was designed for utility programs. This
+license, the GNU Library General Public License, applies to certain
+designated libraries. This license is quite different from the ordinary
+one; be sure to read it in full, and don't assume that anything in it is
+the same as in the ordinary license.
+
+ The reason we have a separate public license for some libraries is that
+they blur the distinction we usually make between modifying or adding to a
+program and simply using it. Linking a program with a library, without
+changing the library, is in some sense simply using the library, and is
+analogous to running a utility program or application program. However, in
+a textual and legal sense, the linked executable is a combined work, a
+derivative of the original library, and the ordinary General Public License
+treats it as such.
+
+ Because of this blurred distinction, using the ordinary General
+Public License for libraries did not effectively promote software
+sharing, because most developers did not use the libraries. We
+concluded that weaker conditions might promote sharing better.
+
+ However, unrestricted linking of non-free programs would deprive the
+users of those programs of all benefit from the free status of the
+libraries themselves. This Library General Public License is intended to
+permit developers of non-free programs to use free libraries, while
+preserving your freedom as a user of such programs to change the free
+libraries that are incorporated in them. (We have not seen how to achieve
+this as regards changes in header files, but we have achieved it as regards
+changes in the actual functions of the Library.) The hope is that this
+will lead to faster development of free libraries.
+
+ The precise terms and conditions for copying, distribution and
+modification follow. Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library". The
+former contains code derived from the library, while the latter only
+works together with the library.
+
+ Note that it is possible for a library to be covered by the ordinary
+General Public License rather than by this special one.
+
+ GNU LIBRARY GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License Agreement applies to any software library which
+contains a notice placed by the copyright holder or other authorized
+party saying it may be distributed under the terms of this Library
+General Public License (also called "this License"). Each licensee is
+addressed as "you".
+
+ A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+ The "Library", below, refers to any such software library or work
+which has been distributed under these terms. A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language. (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+ "Source code" for a work means the preferred form of the work for
+making modifications to it. For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+ Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it). Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+
+ 1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+ You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+
+ 2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) The modified work must itself be a software library.
+
+ b) You must cause the files modified to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ c) You must cause the whole of the work to be licensed at no
+ charge to all third parties under the terms of this License.
+
+ d) If a facility in the modified Library refers to a function or a
+ table of data to be supplied by an application program that uses
+ the facility, other than as an argument passed when the facility
+ is invoked, then you must make a good faith effort to ensure that,
+ in the event an application does not supply such function or
+ table, the facility still operates, and performs whatever part of
+ its purpose remains meaningful.
+
+ (For example, a function in a library to compute square roots has
+ a purpose that is entirely well-defined independent of the
+ application. Therefore, Subsection 2d requires that any
+ application-supplied function or table used by this function must
+ be optional: if the application does not supply it, the square
+ root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library. To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License. (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.) Do not make any other change in
+these notices.
+
+ Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+ This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+ 4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+ If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library". Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+ However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library". The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+ When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library. The
+threshold for this to be true is not precisely defined by law.
+
+ If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work. (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+ Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+
+ 6. As an exception to the Sections above, you may also compile or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+ You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License. You must supply a copy of this License. If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License. Also, you must do one
+of these things:
+
+ a) Accompany the work with the complete corresponding
+ machine-readable source code for the Library including whatever
+ changes were used in the work (which must be distributed under
+ Sections 1 and 2 above); and, if the work is an executable linked
+ with the Library, with the complete machine-readable "work that
+ uses the Library", as object code and/or source code, so that the
+ user can modify the Library and then relink to produce a modified
+ executable containing the modified Library. (It is understood
+ that the user who changes the contents of definitions files in the
+ Library will not necessarily be able to recompile the application
+ to use the modified definitions.)
+
+ b) Accompany the work with a written offer, valid for at
+ least three years, to give the same user the materials
+ specified in Subsection 6a, above, for a charge no more
+ than the cost of performing this distribution.
+
+ c) If distribution of the work is made by offering access to copy
+ from a designated place, offer equivalent access to copy the above
+ specified materials from the same place.
+
+ d) Verify that the user has already received a copy of these
+ materials or that you have already sent this user a copy.
+
+ For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it. However, as a special exception,
+the source code distributed need not include anything that is normally
+distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+ It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system. Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+
+ 7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+ a) Accompany the combined library with a copy of the same work
+ based on the Library, uncombined with any other library
+ facilities. This must be distributed under the terms of the
+ Sections above.
+
+ b) Give prominent notice with the combined library of the fact
+ that part of it is a work based on the Library, and explaining
+ where to find the accompanying uncombined form of the same work.
+
+ 8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License. Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License. However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+ 9. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Library or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+ 10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all. For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded. In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+ 13. The Free Software Foundation may publish revised and/or new
+versions of the Library General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation. If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+
+ 14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission. For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this. Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+ NO WARRANTY
+
+ 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ Appendix: How to Apply These Terms to Your New Libraries
+
+ If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change. You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+ To apply these terms, attach the following notices to the library. It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the library's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the
+ library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+ <signature of Ty Coon>, 1 April 1990
+ Ty Coon, President of Vice
+
+That's all there is to it!
diff --git a/gnu/usr.bin/gdb/Makefile b/gnu/usr.bin/gdb/Makefile
new file mode 100644
index 0000000..715db7c
--- /dev/null
+++ b/gnu/usr.bin/gdb/Makefile
@@ -0,0 +1,3 @@
+SUBDIR= bfd libiberty mmalloc gdb doc
+
+.include <bsd.subdir.mk>
diff --git a/gnu/usr.bin/gdb/README.FreeBSD b/gnu/usr.bin/gdb/README.FreeBSD
new file mode 100644
index 0000000..546d0cc
--- /dev/null
+++ b/gnu/usr.bin/gdb/README.FreeBSD
@@ -0,0 +1,21 @@
+This is a greatly pared down version of GDB-4.13 for FreeBSD 2.0. It
+also has support for kernel debugging a la the dearly beloved kgdb.
+Kernel debugging is enabled either using the -k flag or by linking gdb
+to kgdb and invoking it as kgdb. Linking is left up to the discretion
+of the user.
+
+The kernel debugging needs testing, I didn't have any useful crash dumps
+available. The new gdb produced the same output as the old kgdb with
+what I had available for testing, though.
+
+There's rudimentary support for attaching to a running process and
+debugging (attach/detach commands in gdb). This works best if the
+program being debugged was compiled with -g, of course.
+
+Note that a plain vanilla gdb-4.13 without kernal debugging or
+attach/detach support can be made by removing the
+ #define ATTACH_DETACH
+ #define KERNEL_DEBUG
+lines from gdb/nm.h.
+
+gj@freebsd.org
diff --git a/gnu/usr.bin/gdb/VERSION b/gnu/usr.bin/gdb/VERSION
new file mode 100644
index 0000000..8c3a015
--- /dev/null
+++ b/gnu/usr.bin/gdb/VERSION
@@ -0,0 +1 @@
+4.13
diff --git a/gnu/usr.bin/gdb/bfd/COPYING b/gnu/usr.bin/gdb/bfd/COPYING
new file mode 100644
index 0000000..a43ea21
--- /dev/null
+++ b/gnu/usr.bin/gdb/bfd/COPYING
@@ -0,0 +1,339 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 675 Mass Ave, Cambridge, MA 02139, USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ Appendix: How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) 19yy <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) 19yy name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/gnu/usr.bin/gdb/bfd/Makefile b/gnu/usr.bin/gdb/bfd/Makefile
new file mode 100644
index 0000000..24322af
--- /dev/null
+++ b/gnu/usr.bin/gdb/bfd/Makefile
@@ -0,0 +1,26 @@
+LIB = bfd
+
+SRCS = libbfd.c opncls.c bfd.c archive.c targets.c cache.c \
+ archures.c coff-i386.c aout32.c \
+ srec.c \
+ ecoff.c ecofflink.c \
+ coffgen.c format.c \
+ section.c core.c syms.c stab-syms.c reloc.c init.c ctor.c \
+ trad-core.c \
+ i386aout.c \
+ freebsd386.c \
+ cpu-i386.c \
+ elf.c elf32.c elf32-i386.c \
+ hash.c linker.c
+
+CFLAGS+= -I$(.CURDIR)/. -I$(.CURDIR)/../gdb/.
+CFLAGS+= -DDEFAULT_VECTOR=freebsd386_vec -DSELECT_VECS='&freebsd386_vec' \
+ -DSELECT_ARCHITECTURES='bfd_i386_arch' -DTRAD_CORE
+
+NOPROFILE=no
+NOPIC=no
+
+install:
+ @echo -n
+
+.include <bsd.lib.mk>
diff --git a/gnu/usr.bin/gdb/bfd/README.FreeBSD b/gnu/usr.bin/gdb/bfd/README.FreeBSD
new file mode 100644
index 0000000..033fa00
--- /dev/null
+++ b/gnu/usr.bin/gdb/bfd/README.FreeBSD
@@ -0,0 +1,4 @@
+This is a greatly pared down libbfd directory. Only what's required to build
+gdb-4.13 on FreeBSD 2.0 was kept.
+
+gj@freebsd.org
diff --git a/gnu/usr.bin/gdb/bfd/VERSION b/gnu/usr.bin/gdb/bfd/VERSION
new file mode 100644
index 0000000..ae7202b
--- /dev/null
+++ b/gnu/usr.bin/gdb/bfd/VERSION
@@ -0,0 +1 @@
+cygnus-2.3
diff --git a/gnu/usr.bin/gdb/bfd/aout-target.h b/gnu/usr.bin/gdb/bfd/aout-target.h
new file mode 100644
index 0000000..7e4a846
--- /dev/null
+++ b/gnu/usr.bin/gdb/bfd/aout-target.h
@@ -0,0 +1,555 @@
+/* Define a target vector and some small routines for a variant of a.out.
+ Copyright (C) 1990, 1991, 1992, 1993, 1994 Free Software Foundation, Inc.
+
+This file is part of BFD, the Binary File Descriptor library.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "aout/aout64.h"
+#include "aout/stab_gnu.h"
+#include "aout/ar.h"
+/*#include "libaout.h"*/
+
+extern CONST struct reloc_howto_struct * NAME(aout,reloc_type_lookup) ();
+
+/* Set parameters about this a.out file that are machine-dependent.
+ This routine is called from some_aout_object_p just before it returns. */
+#ifndef MY_callback
+static const bfd_target *
+MY(callback) (abfd)
+ bfd *abfd;
+{
+ struct internal_exec *execp = exec_hdr (abfd);
+ unsigned int arch_align_power;
+ unsigned long arch_align;
+
+ /* Calculate the file positions of the parts of a newly read aout header */
+ obj_textsec (abfd)->_raw_size = N_TXTSIZE(*execp);
+
+ /* The virtual memory addresses of the sections */
+ obj_textsec (abfd)->vma = N_TXTADDR(*execp);
+ obj_datasec (abfd)->vma = N_DATADDR(*execp);
+ obj_bsssec (abfd)->vma = N_BSSADDR(*execp);
+
+ /* The file offsets of the sections */
+ obj_textsec (abfd)->filepos = N_TXTOFF (*execp);
+ obj_datasec (abfd)->filepos = N_DATOFF (*execp);
+
+ /* The file offsets of the relocation info */
+ obj_textsec (abfd)->rel_filepos = N_TRELOFF(*execp);
+ obj_datasec (abfd)->rel_filepos = N_DRELOFF(*execp);
+
+ /* The file offsets of the string table and symbol table. */
+ obj_sym_filepos (abfd) = N_SYMOFF (*execp);
+ obj_str_filepos (abfd) = N_STROFF (*execp);
+
+ /* Determine the architecture and machine type of the object file. */
+#ifdef SET_ARCH_MACH
+ SET_ARCH_MACH(abfd, *execp);
+#else
+ bfd_default_set_arch_mach(abfd, DEFAULT_ARCH, 0);
+#endif
+
+ /* Now that we know the architecture, set the alignments of the
+ sections. This is normally done by NAME(aout,new_section_hook),
+ but when the initial sections were created the architecture had
+ not yet been set. However, for backward compatibility, we don't
+ set the alignment power any higher than as required by the size
+ of the section. */
+ arch_align_power = bfd_get_arch_info (abfd)->section_align_power;
+ arch_align = 1 << arch_align_power;
+ if ((BFD_ALIGN (obj_textsec (abfd)->_raw_size, arch_align)
+ == obj_textsec (abfd)->_raw_size)
+ && (BFD_ALIGN (obj_datasec (abfd)->_raw_size, arch_align)
+ == obj_datasec (abfd)->_raw_size)
+ && (BFD_ALIGN (obj_bsssec (abfd)->_raw_size, arch_align)
+ == obj_bsssec (abfd)->_raw_size))
+ {
+ obj_textsec (abfd)->alignment_power = arch_align_power;
+ obj_datasec (abfd)->alignment_power = arch_align_power;
+ obj_bsssec (abfd)->alignment_power = arch_align_power;
+ }
+
+ /* Don't set sizes now -- can't be sure until we know arch & mach.
+ Sizes get set in set_sizes callback, later. */
+#if 0
+ adata(abfd).page_size = PAGE_SIZE;
+#ifdef SEGMENT_SIZE
+ adata(abfd).segment_size = SEGMENT_SIZE;
+#else
+ adata(abfd).segment_size = PAGE_SIZE;
+#endif
+ adata(abfd).exec_bytes_size = EXEC_BYTES_SIZE;
+#endif
+
+ return abfd->xvec;
+}
+#endif
+
+#ifndef MY_object_p
+/* Finish up the reading of an a.out file header */
+
+static const bfd_target *
+MY(object_p) (abfd)
+ bfd *abfd;
+{
+ struct external_exec exec_bytes; /* Raw exec header from file */
+ struct internal_exec exec; /* Cleaned-up exec header */
+ const bfd_target *target;
+
+ if (bfd_read ((PTR) &exec_bytes, 1, EXEC_BYTES_SIZE, abfd)
+ != EXEC_BYTES_SIZE) {
+ if (bfd_get_error () != bfd_error_system_call)
+ bfd_set_error (bfd_error_wrong_format);
+ return 0;
+ }
+
+#ifdef SWAP_MAGIC
+ exec.a_info = SWAP_MAGIC (exec_bytes.e_info);
+#else
+ exec.a_info = bfd_h_get_32 (abfd, exec_bytes.e_info);
+#endif /* SWAP_MAGIC */
+
+ if (N_BADMAG (exec)) return 0;
+#ifdef MACHTYPE_OK
+ if (!(MACHTYPE_OK (N_MACHTYPE (exec)))) return 0;
+#endif
+
+ NAME(aout,swap_exec_header_in)(abfd, &exec_bytes, &exec);
+
+#ifdef SWAP_MAGIC
+ /* swap_exec_header_in read in a_info with the wrong byte order */
+ exec.a_info = SWAP_MAGIC (exec_bytes.e_info);
+#endif /* SWAP_MAGIC */
+
+ target = NAME(aout,some_aout_object_p) (abfd, &exec, MY(callback));
+
+#ifdef ENTRY_CAN_BE_ZERO
+ /* The NEWSOS3 entry-point is/was 0, which (amongst other lossage)
+ * means that it isn't obvious if EXEC_P should be set.
+ * All of the following must be true for an executable:
+ * There must be no relocations, the bfd can be neither an
+ * archive nor an archive element, and the file must be executable. */
+
+ if (exec.a_trsize + exec.a_drsize == 0
+ && bfd_get_format(abfd) == bfd_object && abfd->my_archive == NULL)
+ {
+ struct stat buf;
+#ifndef S_IXUSR
+#define S_IXUSR 0100 /* Execute by owner. */
+#endif
+ if (stat(abfd->filename, &buf) == 0 && (buf.st_mode & S_IXUSR))
+ abfd->flags |= EXEC_P;
+ }
+#endif /* ENTRY_CAN_BE_ZERO */
+
+ return target;
+}
+#define MY_object_p MY(object_p)
+#endif
+
+
+#ifndef MY_mkobject
+static boolean
+MY(mkobject) (abfd)
+ bfd *abfd;
+{
+ if (NAME(aout,mkobject)(abfd) == false)
+ return false;
+#if 0 /* Sizes get set in set_sizes callback, later, after we know
+ the architecture and machine. */
+ adata(abfd).page_size = PAGE_SIZE;
+#ifdef SEGMENT_SIZE
+ adata(abfd).segment_size = SEGMENT_SIZE;
+#else
+ adata(abfd).segment_size = PAGE_SIZE;
+#endif
+ adata(abfd).exec_bytes_size = EXEC_BYTES_SIZE;
+#endif
+ return true;
+}
+#define MY_mkobject MY(mkobject)
+#endif
+
+#ifndef MY_bfd_copy_private_section_data
+
+/* Copy private section data. This actually does nothing with the
+ sections. It copies the subformat field. We copy it here, because
+ we need to know whether this is a QMAGIC file before we set the
+ section contents, and copy_private_bfd_data is not called until
+ after the section contents have been set. */
+
+/*ARGSUSED*/
+static boolean
+MY_bfd_copy_private_section_data (ibfd, isec, obfd, osec)
+ bfd *ibfd;
+ asection *isec;
+ bfd *obfd;
+ asection *osec;
+{
+ obj_aout_subformat (obfd) = obj_aout_subformat (ibfd);
+ return true;
+}
+
+#endif
+
+/* Write an object file.
+ Section contents have already been written. We write the
+ file header, symbols, and relocation. */
+
+#ifndef MY_write_object_contents
+static boolean
+MY(write_object_contents) (abfd)
+ bfd *abfd;
+{
+ struct external_exec exec_bytes;
+ struct internal_exec *execp = exec_hdr (abfd);
+
+#if CHOOSE_RELOC_SIZE
+ CHOOSE_RELOC_SIZE(abfd);
+#else
+ obj_reloc_entry_size (abfd) = RELOC_STD_SIZE;
+#endif
+
+ WRITE_HEADERS(abfd, execp);
+
+ return true;
+}
+#define MY_write_object_contents MY(write_object_contents)
+#endif
+
+#ifndef MY_set_sizes
+static boolean
+MY(set_sizes) (abfd)
+ bfd *abfd;
+{
+ adata(abfd).page_size = PAGE_SIZE;
+
+#ifdef SEGMENT_SIZE
+ adata(abfd).segment_size = SEGMENT_SIZE;
+#else
+ adata(abfd).segment_size = PAGE_SIZE;
+#endif
+
+#ifdef ZMAGIC_DISK_BLOCK_SIZE
+ adata(abfd).zmagic_disk_block_size = ZMAGIC_DISK_BLOCK_SIZE;
+#else
+ adata(abfd).zmagic_disk_block_size = PAGE_SIZE;
+#endif
+
+ adata(abfd).exec_bytes_size = EXEC_BYTES_SIZE;
+ return true;
+}
+#define MY_set_sizes MY(set_sizes)
+#endif
+
+#ifndef MY_exec_hdr_flags
+#define MY_exec_hdr_flags 0
+#endif
+
+#ifndef MY_backend_data
+
+#ifndef MY_text_includes_header
+#define MY_text_includes_header 0
+#endif
+#ifndef MY_add_dynamic_symbols
+#define MY_add_dynamic_symbols 0
+#endif
+#ifndef MY_add_one_symbol
+#define MY_add_one_symbol 0
+#endif
+#ifndef MY_link_dynamic_object
+#define MY_link_dynamic_object 0
+#endif
+#ifndef MY_write_dynamic_symbol
+#define MY_write_dynamic_symbol 0
+#endif
+#ifndef MY_check_dynamic_reloc
+#define MY_check_dynamic_reloc 0
+#endif
+#ifndef MY_finish_dynamic_link
+#define MY_finish_dynamic_link 0
+#endif
+
+static CONST struct aout_backend_data MY(backend_data) = {
+ 0, /* zmagic contiguous */
+ MY_text_includes_header,
+ MY_exec_hdr_flags,
+ 0, /* text vma? */
+ MY_set_sizes,
+ 0, /* exec header is counted */
+ MY_add_dynamic_symbols,
+ MY_add_one_symbol,
+ MY_link_dynamic_object,
+ MY_write_dynamic_symbol,
+ MY_check_dynamic_reloc,
+ MY_finish_dynamic_link
+};
+#define MY_backend_data &MY(backend_data)
+#endif
+
+#ifndef MY_final_link_callback
+
+/* Callback for the final_link routine to set the section offsets. */
+
+static void MY_final_link_callback
+ PARAMS ((bfd *, file_ptr *, file_ptr *, file_ptr *));
+
+static void
+MY_final_link_callback (abfd, ptreloff, pdreloff, psymoff)
+ bfd *abfd;
+ file_ptr *ptreloff;
+ file_ptr *pdreloff;
+ file_ptr *psymoff;
+{
+ struct internal_exec *execp = exec_hdr (abfd);
+
+ *ptreloff = N_TRELOFF (*execp);
+ *pdreloff = N_DRELOFF (*execp);
+ *psymoff = N_SYMOFF (*execp);
+}
+
+#endif
+
+#ifndef MY_bfd_final_link
+
+/* Final link routine. We need to use a call back to get the correct
+ offsets in the output file. */
+
+static boolean
+MY_bfd_final_link (abfd, info)
+ bfd *abfd;
+ struct bfd_link_info *info;
+{
+ return NAME(aout,final_link) (abfd, info, MY_final_link_callback);
+}
+
+#endif
+
+/* We assume BFD generic archive files. */
+#ifndef MY_openr_next_archived_file
+#define MY_openr_next_archived_file bfd_generic_openr_next_archived_file
+#endif
+#ifndef MY_generic_stat_arch_elt
+#define MY_generic_stat_arch_elt bfd_generic_stat_arch_elt
+#endif
+#ifndef MY_slurp_armap
+#define MY_slurp_armap bfd_slurp_bsd_armap
+#endif
+#ifndef MY_slurp_extended_name_table
+#define MY_slurp_extended_name_table _bfd_slurp_extended_name_table
+#endif
+#ifndef MY_write_armap
+#define MY_write_armap bsd_write_armap
+#endif
+#ifndef MY_truncate_arname
+#define MY_truncate_arname bfd_bsd_truncate_arname
+#endif
+
+/* No core file defined here -- configure in trad-core.c separately. */
+#ifndef MY_core_file_failing_command
+#define MY_core_file_failing_command _bfd_nocore_core_file_failing_command
+#endif
+#ifndef MY_core_file_failing_signal
+#define MY_core_file_failing_signal _bfd_nocore_core_file_failing_signal
+#endif
+#ifndef MY_core_file_matches_executable_p
+#define MY_core_file_matches_executable_p \
+ _bfd_nocore_core_file_matches_executable_p
+#endif
+#ifndef MY_core_file_p
+#define MY_core_file_p _bfd_dummy_target
+#endif
+
+#ifndef MY_bfd_debug_info_start
+#define MY_bfd_debug_info_start bfd_void
+#endif
+#ifndef MY_bfd_debug_info_end
+#define MY_bfd_debug_info_end bfd_void
+#endif
+#ifndef MY_bfd_debug_info_accumulate
+#define MY_bfd_debug_info_accumulate \
+ (void (*) PARAMS ((bfd*, struct sec *))) bfd_void
+#endif
+
+#ifndef MY_core_file_failing_command
+#define MY_core_file_failing_command NAME(aout,core_file_failing_command)
+#endif
+#ifndef MY_core_file_failing_signal
+#define MY_core_file_failing_signal NAME(aout,core_file_failing_signal)
+#endif
+#ifndef MY_core_file_matches_executable_p
+#define MY_core_file_matches_executable_p NAME(aout,core_file_matches_executable_p)
+#endif
+#ifndef MY_set_section_contents
+#define MY_set_section_contents NAME(aout,set_section_contents)
+#endif
+#ifndef MY_get_section_contents
+#define MY_get_section_contents NAME(aout,get_section_contents)
+#endif
+#ifndef MY_new_section_hook
+#define MY_new_section_hook NAME(aout,new_section_hook)
+#endif
+#ifndef MY_get_symtab_upper_bound
+#define MY_get_symtab_upper_bound NAME(aout,get_symtab_upper_bound)
+#endif
+#ifndef MY_get_symtab
+#define MY_get_symtab NAME(aout,get_symtab)
+#endif
+#ifndef MY_get_reloc_upper_bound
+#define MY_get_reloc_upper_bound NAME(aout,get_reloc_upper_bound)
+#endif
+#ifndef MY_canonicalize_reloc
+#define MY_canonicalize_reloc NAME(aout,canonicalize_reloc)
+#endif
+#ifndef MY_make_empty_symbol
+#define MY_make_empty_symbol NAME(aout,make_empty_symbol)
+#endif
+#ifndef MY_print_symbol
+#define MY_print_symbol NAME(aout,print_symbol)
+#endif
+#ifndef MY_get_symbol_info
+#define MY_get_symbol_info NAME(aout,get_symbol_info)
+#endif
+#ifndef MY_get_lineno
+#define MY_get_lineno NAME(aout,get_lineno)
+#endif
+#ifndef MY_set_arch_mach
+#define MY_set_arch_mach NAME(aout,set_arch_mach)
+#endif
+#ifndef MY_find_nearest_line
+#define MY_find_nearest_line NAME(aout,find_nearest_line)
+#endif
+#ifndef MY_sizeof_headers
+#define MY_sizeof_headers NAME(aout,sizeof_headers)
+#endif
+#ifndef MY_bfd_get_relocated_section_contents
+#define MY_bfd_get_relocated_section_contents \
+ bfd_generic_get_relocated_section_contents
+#endif
+#ifndef MY_bfd_relax_section
+#define MY_bfd_relax_section bfd_generic_relax_section
+#endif
+#ifndef MY_bfd_reloc_type_lookup
+#define MY_bfd_reloc_type_lookup NAME(aout,reloc_type_lookup)
+#endif
+#ifndef MY_bfd_make_debug_symbol
+#define MY_bfd_make_debug_symbol 0
+#endif
+#ifndef MY_bfd_link_hash_table_create
+#define MY_bfd_link_hash_table_create NAME(aout,link_hash_table_create)
+#endif
+#ifndef MY_bfd_link_add_symbols
+#define MY_bfd_link_add_symbols NAME(aout,link_add_symbols)
+#endif
+
+#ifndef MY_bfd_copy_private_bfd_data
+#define MY_bfd_copy_private_bfd_data _bfd_generic_bfd_copy_private_bfd_data
+#endif
+
+#ifndef MY_bfd_is_local_label
+#define MY_bfd_is_local_label bfd_generic_is_local_label
+#endif
+
+#ifndef MY_bfd_free_cached_info
+#define MY_bfd_free_cached_info NAME(aout,bfd_free_cached_info)
+#endif
+
+#ifndef MY_close_and_cleanup
+#define MY_close_and_cleanup MY_bfd_free_cached_info
+#endif
+
+#ifndef MY_get_dynamic_symtab_upper_bound
+#define MY_get_dynamic_symtab_upper_bound \
+ _bfd_nodynamic_get_dynamic_symtab_upper_bound
+#endif
+#ifndef MY_canonicalize_dynamic_symtab
+#define MY_canonicalize_dynamic_symtab \
+ _bfd_nodynamic_canonicalize_dynamic_symtab
+#endif
+#ifndef MY_get_dynamic_reloc_upper_bound
+#define MY_get_dynamic_reloc_upper_bound \
+ _bfd_nodynamic_get_dynamic_reloc_upper_bound
+#endif
+#ifndef MY_canonicalize_dynamic_reloc
+#define MY_canonicalize_dynamic_reloc \
+ _bfd_nodynamic_canonicalize_dynamic_reloc
+#endif
+
+/* Aout symbols normally have leading underscores */
+#ifndef MY_symbol_leading_char
+#define MY_symbol_leading_char '_'
+#endif
+
+/* Aout archives normally use spaces for padding */
+#ifndef AR_PAD_CHAR
+#define AR_PAD_CHAR ' '
+#endif
+
+#ifndef MY_BFD_TARGET
+const bfd_target MY(vec) =
+{
+ TARGETNAME, /* name */
+ bfd_target_aout_flavour,
+#ifdef TARGET_IS_BIG_ENDIAN_P
+ true, /* target byte order (big) */
+ true, /* target headers byte order (big) */
+#else
+ false, /* target byte order (little) */
+ false, /* target headers byte order (little) */
+#endif
+ (HAS_RELOC | EXEC_P | /* object flags */
+ HAS_LINENO | HAS_DEBUG |
+ HAS_SYMS | HAS_LOCALS | DYNAMIC | WP_TEXT | D_PAGED),
+ (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC), /* section flags */
+ MY_symbol_leading_char,
+ AR_PAD_CHAR, /* ar_pad_char */
+ 15, /* ar_max_namelen */
+ 3, /* minimum alignment */
+#ifdef TARGET_IS_BIG_ENDIAN_P
+ bfd_getb64, bfd_getb_signed_64, bfd_putb64,
+ bfd_getb32, bfd_getb_signed_32, bfd_putb32,
+ bfd_getb16, bfd_getb_signed_16, bfd_putb16, /* data */
+ bfd_getb64, bfd_getb_signed_64, bfd_putb64,
+ bfd_getb32, bfd_getb_signed_32, bfd_putb32,
+ bfd_getb16, bfd_getb_signed_16, bfd_putb16, /* hdrs */
+#else
+ bfd_getl64, bfd_getl_signed_64, bfd_putl64,
+ bfd_getl32, bfd_getl_signed_32, bfd_putl32,
+ bfd_getl16, bfd_getl_signed_16, bfd_putl16, /* data */
+ bfd_getl64, bfd_getl_signed_64, bfd_putl64,
+ bfd_getl32, bfd_getl_signed_32, bfd_putl32,
+ bfd_getl16, bfd_getl_signed_16, bfd_putl16, /* hdrs */
+#endif
+ {_bfd_dummy_target, MY_object_p, /* bfd_check_format */
+ bfd_generic_archive_p, MY_core_file_p},
+ {bfd_false, MY_mkobject, /* bfd_set_format */
+ _bfd_generic_mkarchive, bfd_false},
+ {bfd_false, MY_write_object_contents, /* bfd_write_contents */
+ _bfd_write_archive_contents, bfd_false},
+
+ BFD_JUMP_TABLE_GENERIC (MY),
+ BFD_JUMP_TABLE_COPY (MY),
+ BFD_JUMP_TABLE_CORE (MY),
+ BFD_JUMP_TABLE_ARCHIVE (MY),
+ BFD_JUMP_TABLE_SYMBOLS (MY),
+ BFD_JUMP_TABLE_RELOCS (MY),
+ BFD_JUMP_TABLE_WRITE (MY),
+ BFD_JUMP_TABLE_LINK (MY),
+ BFD_JUMP_TABLE_DYNAMIC (MY),
+
+ (PTR) MY_backend_data,
+};
+#endif /* MY_BFD_TARGET */
diff --git a/gnu/usr.bin/gdb/bfd/aout32.c b/gnu/usr.bin/gdb/bfd/aout32.c
new file mode 100644
index 0000000..294dc1d
--- /dev/null
+++ b/gnu/usr.bin/gdb/bfd/aout32.c
@@ -0,0 +1,23 @@
+/* BFD back-end for 32-bit a.out files.
+ Copyright (C) 1990, 91, 92, 93, 94 Free Software Foundation, Inc.
+ Written by Cygnus Support.
+
+This file is part of BFD, the Binary File Descriptor library.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#define ARCH_SIZE 32
+
+#include "aoutx.h"
diff --git a/gnu/usr.bin/gdb/bfd/aoutx.h b/gnu/usr.bin/gdb/bfd/aoutx.h
new file mode 100644
index 0000000..5afed7a
--- /dev/null
+++ b/gnu/usr.bin/gdb/bfd/aoutx.h
@@ -0,0 +1,4994 @@
+/* BFD semi-generic back-end for a.out binaries.
+ Copyright 1990, 1991, 1992, 1993, 1994 Free Software Foundation, Inc.
+ Written by Cygnus Support.
+
+This file is part of BFD, the Binary File Descriptor library.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/*
+SECTION
+ a.out backends
+
+
+DESCRIPTION
+
+ BFD supports a number of different flavours of a.out format,
+ though the major differences are only the sizes of the
+ structures on disk, and the shape of the relocation
+ information.
+
+ The support is split into a basic support file @file{aoutx.h}
+ and other files which derive functions from the base. One
+ derivation file is @file{aoutf1.h} (for a.out flavour 1), and
+ adds to the basic a.out functions support for sun3, sun4, 386
+ and 29k a.out files, to create a target jump vector for a
+ specific target.
+
+ This information is further split out into more specific files
+ for each machine, including @file{sunos.c} for sun3 and sun4,
+ @file{newsos3.c} for the Sony NEWS, and @file{demo64.c} for a
+ demonstration of a 64 bit a.out format.
+
+ The base file @file{aoutx.h} defines general mechanisms for
+ reading and writing records to and from disk and various
+ other methods which BFD requires. It is included by
+ @file{aout32.c} and @file{aout64.c} to form the names
+ <<aout_32_swap_exec_header_in>>, <<aout_64_swap_exec_header_in>>, etc.
+
+ As an example, this is what goes on to make the back end for a
+ sun4, from @file{aout32.c}:
+
+| #define ARCH_SIZE 32
+| #include "aoutx.h"
+
+ Which exports names:
+
+| ...
+| aout_32_canonicalize_reloc
+| aout_32_find_nearest_line
+| aout_32_get_lineno
+| aout_32_get_reloc_upper_bound
+| ...
+
+ from @file{sunos.c}:
+
+| #define TARGET_NAME "a.out-sunos-big"
+| #define VECNAME sunos_big_vec
+| #include "aoutf1.h"
+
+ requires all the names from @file{aout32.c}, and produces the jump vector
+
+| sunos_big_vec
+
+ The file @file{host-aout.c} is a special case. It is for a large set
+ of hosts that use ``more or less standard'' a.out files, and
+ for which cross-debugging is not interesting. It uses the
+ standard 32-bit a.out support routines, but determines the
+ file offsets and addresses of the text, data, and BSS
+ sections, the machine architecture and machine type, and the
+ entry point address, in a host-dependent manner. Once these
+ values have been determined, generic code is used to handle
+ the object file.
+
+ When porting it to run on a new system, you must supply:
+
+| HOST_PAGE_SIZE
+| HOST_SEGMENT_SIZE
+| HOST_MACHINE_ARCH (optional)
+| HOST_MACHINE_MACHINE (optional)
+| HOST_TEXT_START_ADDR
+| HOST_STACK_END_ADDR
+
+ in the file @file{../include/sys/h-@var{XXX}.h} (for your host). These
+ values, plus the structures and macros defined in @file{a.out.h} on
+ your host system, will produce a BFD target that will access
+ ordinary a.out files on your host. To configure a new machine
+ to use @file{host-aout.c}, specify:
+
+| TDEFAULTS = -DDEFAULT_VECTOR=host_aout_big_vec
+| TDEPFILES= host-aout.o trad-core.o
+
+ in the @file{config/@var{XXX}.mt} file, and modify @file{configure.in}
+ to use the
+ @file{@var{XXX}.mt} file (by setting "<<bfd_target=XXX>>") when your
+ configuration is selected.
+
+*/
+
+/* Some assumptions:
+ * Any BFD with D_PAGED set is ZMAGIC, and vice versa.
+ Doesn't matter what the setting of WP_TEXT is on output, but it'll
+ get set on input.
+ * Any BFD with D_PAGED clear and WP_TEXT set is NMAGIC.
+ * Any BFD with both flags clear is OMAGIC.
+ (Just want to make these explicit, so the conditions tested in this
+ file make sense if you're more familiar with a.out than with BFD.) */
+
+#define KEEPIT flags
+#define KEEPITTYPE int
+
+#include <string.h> /* For strchr and friends */
+#include "bfd.h"
+#include <sysdep.h>
+#include "bfdlink.h"
+
+#include "libaout.h"
+#include "libbfd.h"
+#include "aout/aout64.h"
+#include "aout/stab_gnu.h"
+#include "aout/ar.h"
+
+static boolean aout_get_external_symbols PARAMS ((bfd *));
+static boolean translate_from_native_sym_flags
+ PARAMS ((bfd *, aout_symbol_type *));
+static boolean translate_to_native_sym_flags
+ PARAMS ((bfd *, asymbol *, struct external_nlist *));
+
+/*
+SUBSECTION
+ Relocations
+
+DESCRIPTION
+ The file @file{aoutx.h} provides for both the @emph{standard}
+ and @emph{extended} forms of a.out relocation records.
+
+ The standard records contain only an
+ address, a symbol index, and a type field. The extended records
+ (used on 29ks and sparcs) also have a full integer for an
+ addend.
+
+*/
+#ifndef CTOR_TABLE_RELOC_HOWTO
+#define CTOR_TABLE_RELOC_IDX 2
+#define CTOR_TABLE_RELOC_HOWTO(BFD) ((obj_reloc_entry_size(BFD) == RELOC_EXT_SIZE \
+ ? howto_table_ext : howto_table_std) \
+ + CTOR_TABLE_RELOC_IDX)
+#endif
+
+#ifndef MY_swap_std_reloc_in
+#define MY_swap_std_reloc_in NAME(aout,swap_std_reloc_in)
+#endif
+
+#ifndef MY_swap_std_reloc_out
+#define MY_swap_std_reloc_out NAME(aout,swap_std_reloc_out)
+#endif
+
+#define howto_table_ext NAME(aout,ext_howto_table)
+#define howto_table_std NAME(aout,std_howto_table)
+
+reloc_howto_type howto_table_ext[] =
+{
+ /* type rs size bsz pcrel bitpos ovrf sf name part_inpl readmask setmask pcdone */
+ HOWTO(RELOC_8, 0, 0, 8, false, 0, complain_overflow_bitfield,0,"8", false, 0,0x000000ff, false),
+ HOWTO(RELOC_16, 0, 1, 16, false, 0, complain_overflow_bitfield,0,"16", false, 0,0x0000ffff, false),
+ HOWTO(RELOC_32, 0, 2, 32, false, 0, complain_overflow_bitfield,0,"32", false, 0,0xffffffff, false),
+ HOWTO(RELOC_DISP8, 0, 0, 8, true, 0, complain_overflow_signed,0,"DISP8", false, 0,0x000000ff, false),
+ HOWTO(RELOC_DISP16, 0, 1, 16, true, 0, complain_overflow_signed,0,"DISP16", false, 0,0x0000ffff, false),
+ HOWTO(RELOC_DISP32, 0, 2, 32, true, 0, complain_overflow_signed,0,"DISP32", false, 0,0xffffffff, false),
+ HOWTO(RELOC_WDISP30,2, 2, 30, true, 0, complain_overflow_signed,0,"WDISP30", false, 0,0x3fffffff, false),
+ HOWTO(RELOC_WDISP22,2, 2, 22, true, 0, complain_overflow_signed,0,"WDISP22", false, 0,0x003fffff, false),
+ HOWTO(RELOC_HI22, 10, 2, 22, false, 0, complain_overflow_bitfield,0,"HI22", false, 0,0x003fffff, false),
+ HOWTO(RELOC_22, 0, 2, 22, false, 0, complain_overflow_bitfield,0,"22", false, 0,0x003fffff, false),
+ HOWTO(RELOC_13, 0, 2, 13, false, 0, complain_overflow_bitfield,0,"13", false, 0,0x00001fff, false),
+ HOWTO(RELOC_LO10, 0, 2, 10, false, 0, complain_overflow_dont,0,"LO10", false, 0,0x000003ff, false),
+ HOWTO(RELOC_SFA_BASE,0, 2, 32, false, 0, complain_overflow_bitfield,0,"SFA_BASE", false, 0,0xffffffff, false),
+ HOWTO(RELOC_SFA_OFF13,0,2, 32, false, 0, complain_overflow_bitfield,0,"SFA_OFF13",false, 0,0xffffffff, false),
+ HOWTO(RELOC_BASE10, 0, 2, 16, false, 0, complain_overflow_bitfield,0,"BASE10", false, 0,0x0000ffff, false),
+ HOWTO(RELOC_BASE13, 0, 2, 13, false, 0, complain_overflow_bitfield,0,"BASE13", false, 0,0x00001fff, false),
+ HOWTO(RELOC_BASE22, 0, 2, 0, false, 0, complain_overflow_bitfield,0,"BASE22", false, 0,0x00000000, false),
+ HOWTO(RELOC_PC10, 0, 2, 10, false, 0, complain_overflow_bitfield,0,"PC10", false, 0,0x000003ff, false),
+ HOWTO(RELOC_PC22, 0, 2, 22, false, 0, complain_overflow_bitfield,0,"PC22", false, 0,0x003fffff, false),
+ HOWTO(RELOC_JMP_TBL,0, 2, 32, false, 0, complain_overflow_bitfield,0,"JMP_TBL", false, 0,0xffffffff, false),
+ HOWTO(RELOC_SEGOFF16,0, 2, 0, false, 0, complain_overflow_bitfield,0,"SEGOFF16", false, 0,0x00000000, false),
+ HOWTO(RELOC_GLOB_DAT,0, 2, 0, false, 0, complain_overflow_bitfield,0,"GLOB_DAT", false, 0,0x00000000, false),
+ HOWTO(RELOC_JMP_SLOT,0, 2, 0, false, 0, complain_overflow_bitfield,0,"JMP_SLOT", false, 0,0x00000000, false),
+ HOWTO(RELOC_RELATIVE,0, 2, 0, false, 0, complain_overflow_bitfield,0,"RELATIVE", false, 0,0x00000000, false),
+};
+
+/* Convert standard reloc records to "arelent" format (incl byte swap). */
+
+reloc_howto_type howto_table_std[] = {
+ /* type rs size bsz pcrel bitpos ovrf sf name part_inpl readmask setmask pcdone */
+HOWTO( 0, 0, 0, 8, false, 0, complain_overflow_bitfield,0,"8", true, 0x000000ff,0x000000ff, false),
+HOWTO( 1, 0, 1, 16, false, 0, complain_overflow_bitfield,0,"16", true, 0x0000ffff,0x0000ffff, false),
+HOWTO( 2, 0, 2, 32, false, 0, complain_overflow_bitfield,0,"32", true, 0xffffffff,0xffffffff, false),
+HOWTO( 3, 0, 4, 64, false, 0, complain_overflow_bitfield,0,"64", true, 0xdeaddead,0xdeaddead, false),
+HOWTO( 4, 0, 0, 8, true, 0, complain_overflow_signed, 0,"DISP8", true, 0x000000ff,0x000000ff, false),
+HOWTO( 5, 0, 1, 16, true, 0, complain_overflow_signed, 0,"DISP16", true, 0x0000ffff,0x0000ffff, false),
+HOWTO( 6, 0, 2, 32, true, 0, complain_overflow_signed, 0,"DISP32", true, 0xffffffff,0xffffffff, false),
+HOWTO( 7, 0, 4, 64, true, 0, complain_overflow_signed, 0,"DISP64", true, 0xfeedface,0xfeedface, false),
+HOWTO( 8, 0, 2, 0, false, 0, complain_overflow_bitfield,0,"GOT_REL", false, 0,0x00000000, false),
+HOWTO( 9, 0, 1, 16, false, 0, complain_overflow_bitfield,0,"BASE16", false,0xffffffff,0xffffffff, false),
+HOWTO(10, 0, 2, 32, false, 0, complain_overflow_bitfield,0,"BASE32", false,0xffffffff,0xffffffff, false),
+{ -1 },
+{ -1 },
+{ -1 },
+{ -1 },
+{ -1 },
+ HOWTO(16, 0, 2, 0, false, 0, complain_overflow_bitfield,0,"JMP_TABLE", false, 0,0x00000000, false),
+{ -1 },
+{ -1 },
+{ -1 },
+{ -1 },
+{ -1 },
+{ -1 },
+{ -1 },
+{ -1 }, { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, { -1 },
+ HOWTO(32, 0, 2, 0, false, 0, complain_overflow_bitfield,0,"RELATIVE", false, 0,0x00000000, false),
+{ -1 },
+{ -1 },
+{ -1 },
+{ -1 },
+{ -1 },
+{ -1 },
+{ -1 },
+ HOWTO(40, 0, 2, 0, false, 0, complain_overflow_bitfield,0,"BASEREL", false, 0,0x00000000, false),
+};
+
+#define TABLE_SIZE(TABLE) (sizeof(TABLE)/sizeof(TABLE[0]))
+
+CONST struct reloc_howto_struct *
+NAME(aout,reloc_type_lookup) (abfd,code)
+ bfd *abfd;
+ bfd_reloc_code_real_type code;
+{
+#define EXT(i,j) case i: return &howto_table_ext[j]
+#define STD(i,j) case i: return &howto_table_std[j]
+ int ext = obj_reloc_entry_size (abfd) == RELOC_EXT_SIZE;
+ if (code == BFD_RELOC_CTOR)
+ switch (bfd_get_arch_info (abfd)->bits_per_address)
+ {
+ case 32:
+ code = BFD_RELOC_32;
+ break;
+ case 64:
+ code = BFD_RELOC_64;
+ break;
+ }
+ if (ext)
+ switch (code)
+ {
+ EXT (BFD_RELOC_32, 2);
+ EXT (BFD_RELOC_HI22, 8);
+ EXT (BFD_RELOC_LO10, 11);
+ EXT (BFD_RELOC_32_PCREL_S2, 6);
+ EXT (BFD_RELOC_SPARC_WDISP22, 7);
+ EXT (BFD_RELOC_SPARC13, 10);
+ EXT (BFD_RELOC_SPARC_BASE13, 15);
+ default: return (CONST struct reloc_howto_struct *) 0;
+ }
+ else
+ /* std relocs */
+ switch (code)
+ {
+ STD (BFD_RELOC_16, 1);
+ STD (BFD_RELOC_32, 2);
+ STD (BFD_RELOC_8_PCREL, 4);
+ STD (BFD_RELOC_16_PCREL, 5);
+ STD (BFD_RELOC_32_PCREL, 6);
+ STD (BFD_RELOC_16_BASEREL, 9);
+ STD (BFD_RELOC_32_BASEREL, 10);
+ default: return (CONST struct reloc_howto_struct *) 0;
+ }
+}
+
+/*
+SUBSECTION
+ Internal entry points
+
+DESCRIPTION
+ @file{aoutx.h} exports several routines for accessing the
+ contents of an a.out file, which are gathered and exported in
+ turn by various format specific files (eg sunos.c).
+
+*/
+
+/*
+FUNCTION
+ aout_@var{size}_swap_exec_header_in
+
+SYNOPSIS
+ void aout_@var{size}_swap_exec_header_in,
+ (bfd *abfd,
+ struct external_exec *raw_bytes,
+ struct internal_exec *execp);
+
+DESCRIPTION
+ Swap the information in an executable header @var{raw_bytes} taken
+ from a raw byte stream memory image into the internal exec header
+ structure @var{execp}.
+*/
+
+#ifndef NAME_swap_exec_header_in
+void
+NAME(aout,swap_exec_header_in) (abfd, raw_bytes, execp)
+ bfd *abfd;
+ struct external_exec *raw_bytes;
+ struct internal_exec *execp;
+{
+ struct external_exec *bytes = (struct external_exec *)raw_bytes;
+
+ /* The internal_exec structure has some fields that are unused in this
+ configuration (IE for i960), so ensure that all such uninitialized
+ fields are zero'd out. There are places where two of these structs
+ are memcmp'd, and thus the contents do matter. */
+ memset ((PTR) execp, 0, sizeof (struct internal_exec));
+ /* Now fill in fields in the execp, from the bytes in the raw data. */
+ execp->a_info = bfd_h_get_32 (abfd, bytes->e_info);
+ execp->a_text = GET_WORD (abfd, bytes->e_text);
+ execp->a_data = GET_WORD (abfd, bytes->e_data);
+ execp->a_bss = GET_WORD (abfd, bytes->e_bss);
+ execp->a_syms = GET_WORD (abfd, bytes->e_syms);
+ execp->a_entry = GET_WORD (abfd, bytes->e_entry);
+ execp->a_trsize = GET_WORD (abfd, bytes->e_trsize);
+ execp->a_drsize = GET_WORD (abfd, bytes->e_drsize);
+}
+#define NAME_swap_exec_header_in NAME(aout,swap_exec_header_in)
+#endif
+
+/*
+FUNCTION
+ aout_@var{size}_swap_exec_header_out
+
+SYNOPSIS
+ void aout_@var{size}_swap_exec_header_out
+ (bfd *abfd,
+ struct internal_exec *execp,
+ struct external_exec *raw_bytes);
+
+DESCRIPTION
+ Swap the information in an internal exec header structure
+ @var{execp} into the buffer @var{raw_bytes} ready for writing to disk.
+*/
+void
+NAME(aout,swap_exec_header_out) (abfd, execp, raw_bytes)
+ bfd *abfd;
+ struct internal_exec *execp;
+ struct external_exec *raw_bytes;
+{
+ struct external_exec *bytes = (struct external_exec *)raw_bytes;
+
+ /* Now fill in fields in the raw data, from the fields in the exec struct. */
+ bfd_h_put_32 (abfd, execp->a_info , bytes->e_info);
+ PUT_WORD (abfd, execp->a_text , bytes->e_text);
+ PUT_WORD (abfd, execp->a_data , bytes->e_data);
+ PUT_WORD (abfd, execp->a_bss , bytes->e_bss);
+ PUT_WORD (abfd, execp->a_syms , bytes->e_syms);
+ PUT_WORD (abfd, execp->a_entry , bytes->e_entry);
+ PUT_WORD (abfd, execp->a_trsize, bytes->e_trsize);
+ PUT_WORD (abfd, execp->a_drsize, bytes->e_drsize);
+}
+
+/* Make all the section for an a.out file. */
+
+boolean
+NAME(aout,make_sections) (abfd)
+ bfd *abfd;
+{
+ if (obj_textsec (abfd) == (asection *) NULL
+ && bfd_make_section (abfd, ".text") == (asection *) NULL)
+ return false;
+ if (obj_datasec (abfd) == (asection *) NULL
+ && bfd_make_section (abfd, ".data") == (asection *) NULL)
+ return false;
+ if (obj_bsssec (abfd) == (asection *) NULL
+ && bfd_make_section (abfd, ".bss") == (asection *) NULL)
+ return false;
+ return true;
+}
+
+/*
+FUNCTION
+ aout_@var{size}_some_aout_object_p
+
+SYNOPSIS
+ const bfd_target *aout_@var{size}_some_aout_object_p
+ (bfd *abfd,
+ const bfd_target *(*callback_to_real_object_p)());
+
+DESCRIPTION
+ Some a.out variant thinks that the file open in @var{abfd}
+ checking is an a.out file. Do some more checking, and set up
+ for access if it really is. Call back to the calling
+ environment's "finish up" function just before returning, to
+ handle any last-minute setup.
+*/
+
+const bfd_target *
+NAME(aout,some_aout_object_p) (abfd, execp, callback_to_real_object_p)
+ bfd *abfd;
+ struct internal_exec *execp;
+ const bfd_target *(*callback_to_real_object_p) PARAMS ((bfd *));
+{
+ struct aout_data_struct *rawptr, *oldrawptr;
+ const bfd_target *result;
+
+ rawptr = (struct aout_data_struct *) bfd_zalloc (abfd, sizeof (struct aout_data_struct ));
+ if (rawptr == NULL) {
+ bfd_set_error (bfd_error_no_memory);
+ return 0;
+ }
+
+ oldrawptr = abfd->tdata.aout_data;
+ abfd->tdata.aout_data = rawptr;
+
+ /* Copy the contents of the old tdata struct.
+ In particular, we want the subformat, since for hpux it was set in
+ hp300hpux.c:swap_exec_header_in and will be used in
+ hp300hpux.c:callback. */
+ if (oldrawptr != NULL)
+ *abfd->tdata.aout_data = *oldrawptr;
+
+ abfd->tdata.aout_data->a.hdr = &rawptr->e;
+ *(abfd->tdata.aout_data->a.hdr) = *execp; /* Copy in the internal_exec struct */
+ execp = abfd->tdata.aout_data->a.hdr;
+
+ /* Set the file flags */
+ abfd->flags = NO_FLAGS;
+ if (execp->a_drsize || execp->a_trsize)
+ abfd->flags |= HAS_RELOC;
+ /* Setting of EXEC_P has been deferred to the bottom of this function */
+ if (execp->a_syms)
+ abfd->flags |= HAS_LINENO | HAS_DEBUG | HAS_SYMS | HAS_LOCALS;
+ if (N_DYNAMIC(*execp))
+ abfd->flags |= DYNAMIC;
+
+ if (N_MAGIC (*execp) == ZMAGIC)
+ {
+ abfd->flags |= D_PAGED | WP_TEXT;
+ adata (abfd).magic = z_magic;
+ }
+ else if (N_MAGIC (*execp) == QMAGIC)
+ {
+ abfd->flags |= D_PAGED | WP_TEXT;
+ adata (abfd).magic = z_magic;
+ adata (abfd).subformat = q_magic_format;
+ }
+ else if (N_MAGIC (*execp) == NMAGIC)
+ {
+ abfd->flags |= WP_TEXT;
+ adata (abfd).magic = n_magic;
+ }
+ else if (N_MAGIC (*execp) == OMAGIC
+ || N_MAGIC (*execp) == BMAGIC)
+ adata (abfd).magic = o_magic;
+ else
+ {
+ /* Should have been checked with N_BADMAG before this routine
+ was called. */
+ abort ();
+ }
+
+ bfd_get_start_address (abfd) = execp->a_entry;
+
+ obj_aout_symbols (abfd) = (aout_symbol_type *)NULL;
+ bfd_get_symcount (abfd) = execp->a_syms / sizeof (struct external_nlist);
+
+ /* The default relocation entry size is that of traditional V7 Unix. */
+ obj_reloc_entry_size (abfd) = RELOC_STD_SIZE;
+
+ /* The default symbol entry size is that of traditional Unix. */
+ obj_symbol_entry_size (abfd) = EXTERNAL_NLIST_SIZE;
+
+ obj_aout_external_syms (abfd) = NULL;
+ obj_aout_external_strings (abfd) = NULL;
+ obj_aout_sym_hashes (abfd) = NULL;
+
+ if (! NAME(aout,make_sections) (abfd))
+ return NULL;
+
+ obj_datasec (abfd)->_raw_size = execp->a_data;
+ obj_bsssec (abfd)->_raw_size = execp->a_bss;
+
+ obj_textsec (abfd)->flags =
+ (execp->a_trsize != 0
+ ? (SEC_ALLOC | SEC_LOAD | SEC_CODE | SEC_HAS_CONTENTS | SEC_RELOC)
+ : (SEC_ALLOC | SEC_LOAD | SEC_CODE | SEC_HAS_CONTENTS));
+ obj_datasec (abfd)->flags =
+ (execp->a_drsize != 0
+ ? (SEC_ALLOC | SEC_LOAD | SEC_DATA | SEC_HAS_CONTENTS | SEC_RELOC)
+ : (SEC_ALLOC | SEC_LOAD | SEC_DATA | SEC_HAS_CONTENTS));
+ obj_bsssec (abfd)->flags = SEC_ALLOC;
+
+#ifdef THIS_IS_ONLY_DOCUMENTATION
+ /* The common code can't fill in these things because they depend
+ on either the start address of the text segment, the rounding
+ up of virtual addresses between segments, or the starting file
+ position of the text segment -- all of which varies among different
+ versions of a.out. */
+
+ /* Call back to the format-dependent code to fill in the rest of the
+ fields and do any further cleanup. Things that should be filled
+ in by the callback: */
+
+ struct exec *execp = exec_hdr (abfd);
+
+ obj_textsec (abfd)->size = N_TXTSIZE(*execp);
+ obj_textsec (abfd)->raw_size = N_TXTSIZE(*execp);
+ /* data and bss are already filled in since they're so standard */
+
+ /* The virtual memory addresses of the sections */
+ obj_textsec (abfd)->vma = N_TXTADDR(*execp);
+ obj_datasec (abfd)->vma = N_DATADDR(*execp);
+ obj_bsssec (abfd)->vma = N_BSSADDR(*execp);
+
+ /* The file offsets of the sections */
+ obj_textsec (abfd)->filepos = N_TXTOFF(*execp);
+ obj_datasec (abfd)->filepos = N_DATOFF(*execp);
+
+ /* The file offsets of the relocation info */
+ obj_textsec (abfd)->rel_filepos = N_TRELOFF(*execp);
+ obj_datasec (abfd)->rel_filepos = N_DRELOFF(*execp);
+
+ /* The file offsets of the string table and symbol table. */
+ obj_str_filepos (abfd) = N_STROFF (*execp);
+ obj_sym_filepos (abfd) = N_SYMOFF (*execp);
+
+ /* Determine the architecture and machine type of the object file. */
+ switch (N_MACHTYPE (*exec_hdr (abfd))) {
+ default:
+ abfd->obj_arch = bfd_arch_obscure;
+ break;
+ }
+
+ adata(abfd)->page_size = PAGE_SIZE;
+ adata(abfd)->segment_size = SEGMENT_SIZE;
+ adata(abfd)->exec_bytes_size = EXEC_BYTES_SIZE;
+
+ return abfd->xvec;
+
+ /* The architecture is encoded in various ways in various a.out variants,
+ or is not encoded at all in some of them. The relocation size depends
+ on the architecture and the a.out variant. Finally, the return value
+ is the bfd_target vector in use. If an error occurs, return zero and
+ set bfd_error to the appropriate error code.
+
+ Formats such as b.out, which have additional fields in the a.out
+ header, should cope with them in this callback as well. */
+#endif /* DOCUMENTATION */
+
+ result = (*callback_to_real_object_p)(abfd);
+
+#if defined(MACH) || defined(STAT_FOR_EXEC)
+ /* The original heuristic doesn't work in some important cases. The
+ * a.out file has no information about the text start address. For
+ * files (like kernels) linked to non-standard addresses (ld -Ttext
+ * nnn) the entry point may not be between the default text start
+ * (obj_textsec(abfd)->vma) and (obj_textsec(abfd)->vma) + text size
+ * This is not just a mach issue. Many kernels are loaded at non
+ * standard addresses.
+ */
+ {
+ struct stat stat_buf;
+ if (abfd->iostream
+ && (fstat(fileno((FILE *) (abfd->iostream)), &stat_buf) == 0)
+ && ((stat_buf.st_mode & 0111) != 0))
+ abfd->flags |= EXEC_P;
+ }
+#else /* ! MACH */
+ /* Now that the segment addresses have been worked out, take a better
+ guess at whether the file is executable. If the entry point
+ is within the text segment, assume it is. (This makes files
+ executable even if their entry point address is 0, as long as
+ their text starts at zero.)
+
+ At some point we should probably break down and stat the file and
+ declare it executable if (one of) its 'x' bits are on... */
+ if ((execp->a_entry >= obj_textsec(abfd)->vma) &&
+ (execp->a_entry < obj_textsec(abfd)->vma + obj_textsec(abfd)->_raw_size))
+ abfd->flags |= EXEC_P;
+#endif /* MACH */
+ if (result)
+ {
+#if 0 /* These should be set correctly anyways. */
+ abfd->sections = obj_textsec (abfd);
+ obj_textsec (abfd)->next = obj_datasec (abfd);
+ obj_datasec (abfd)->next = obj_bsssec (abfd);
+#endif
+ }
+ else
+ {
+ free (rawptr);
+ abfd->tdata.aout_data = oldrawptr;
+ }
+ return result;
+}
+
+/*
+FUNCTION
+ aout_@var{size}_mkobject
+
+SYNOPSIS
+ boolean aout_@var{size}_mkobject, (bfd *abfd);
+
+DESCRIPTION
+ Initialize BFD @var{abfd} for use with a.out files.
+*/
+
+boolean
+NAME(aout,mkobject) (abfd)
+ bfd *abfd;
+{
+ struct aout_data_struct *rawptr;
+
+ bfd_set_error (bfd_error_system_call);
+
+ /* Use an intermediate variable for clarity */
+ rawptr = (struct aout_data_struct *)bfd_zalloc (abfd, sizeof (struct aout_data_struct ));
+
+ if (rawptr == NULL) {
+ bfd_set_error (bfd_error_no_memory);
+ return false;
+ }
+
+ abfd->tdata.aout_data = rawptr;
+ exec_hdr (abfd) = &(rawptr->e);
+
+ obj_textsec (abfd) = (asection *)NULL;
+ obj_datasec (abfd) = (asection *)NULL;
+ obj_bsssec (abfd) = (asection *)NULL;
+
+ return true;
+}
+
+
+/*
+FUNCTION
+ aout_@var{size}_machine_type
+
+SYNOPSIS
+ enum machine_type aout_@var{size}_machine_type
+ (enum bfd_architecture arch,
+ unsigned long machine));
+
+DESCRIPTION
+ Keep track of machine architecture and machine type for
+ a.out's. Return the <<machine_type>> for a particular
+ architecture and machine, or <<M_UNKNOWN>> if that exact architecture
+ and machine can't be represented in a.out format.
+
+ If the architecture is understood, machine type 0 (default)
+ is always understood.
+*/
+
+enum machine_type
+NAME(aout,machine_type) (arch, machine, unknown)
+ enum bfd_architecture arch;
+ unsigned long machine;
+ boolean *unknown;
+{
+ enum machine_type arch_flags;
+
+ arch_flags = M_UNKNOWN;
+ *unknown = true;
+
+ switch (arch) {
+ case bfd_arch_sparc:
+ if (machine == 0) arch_flags = M_SPARC;
+ break;
+
+ case bfd_arch_m68k:
+ switch (machine) {
+ case 0: arch_flags = M_68010; break;
+ case 68000: arch_flags = M_UNKNOWN; *unknown = false; break;
+ case 68010: arch_flags = M_68010; break;
+ case 68020: arch_flags = M_68020; break;
+ default: arch_flags = M_UNKNOWN; break;
+ }
+ break;
+
+ case bfd_arch_i386:
+ if (machine == 0) arch_flags = M_386;
+ break;
+
+ case bfd_arch_a29k:
+ if (machine == 0) arch_flags = M_29K;
+ break;
+
+ case bfd_arch_mips:
+ switch (machine) {
+ case 0:
+ case 2000:
+ case 3000: arch_flags = M_MIPS1; break;
+ case 4000:
+ case 4400:
+ case 6000: arch_flags = M_MIPS2; break;
+ default: arch_flags = M_UNKNOWN; break;
+ }
+ break;
+
+ case bfd_arch_ns32k:
+ switch (machine) {
+ case 0: arch_flags = M_NS32532; break;
+ case 32032: arch_flags = M_NS32032; break;
+ case 32532: arch_flags = M_NS32532; break;
+ default: arch_flags = M_UNKNOWN; break;
+ }
+ break;
+
+ default:
+ arch_flags = M_UNKNOWN;
+ }
+
+ if (arch_flags != M_UNKNOWN)
+ *unknown = false;
+
+ return arch_flags;
+}
+
+
+/*
+FUNCTION
+ aout_@var{size}_set_arch_mach
+
+SYNOPSIS
+ boolean aout_@var{size}_set_arch_mach,
+ (bfd *,
+ enum bfd_architecture arch,
+ unsigned long machine));
+
+DESCRIPTION
+ Set the architecture and the machine of the BFD @var{abfd} to the
+ values @var{arch} and @var{machine}. Verify that @var{abfd}'s format
+ can support the architecture required.
+*/
+
+boolean
+NAME(aout,set_arch_mach) (abfd, arch, machine)
+ bfd *abfd;
+ enum bfd_architecture arch;
+ unsigned long machine;
+{
+ if (! bfd_default_set_arch_mach (abfd, arch, machine))
+ return false;
+
+ if (arch != bfd_arch_unknown)
+ {
+ boolean unknown;
+
+ NAME(aout,machine_type) (arch, machine, &unknown);
+ if (unknown)
+ return false;
+ }
+
+ /* Determine the size of a relocation entry */
+ switch (arch) {
+ case bfd_arch_sparc:
+ case bfd_arch_a29k:
+ case bfd_arch_mips:
+ obj_reloc_entry_size (abfd) = RELOC_EXT_SIZE;
+ break;
+ default:
+ obj_reloc_entry_size (abfd) = RELOC_STD_SIZE;
+ break;
+ }
+
+ return (*aout_backend_info(abfd)->set_sizes) (abfd);
+}
+
+static void
+adjust_o_magic (abfd, execp)
+ bfd *abfd;
+ struct internal_exec *execp;
+{
+ file_ptr pos = adata (abfd).exec_bytes_size;
+ bfd_vma vma = 0;
+ int pad = 0;
+
+ /* Text. */
+ obj_textsec(abfd)->filepos = pos;
+ pos += obj_textsec(abfd)->_raw_size;
+ vma += obj_textsec(abfd)->_raw_size;
+
+ /* Data. */
+ if (!obj_datasec(abfd)->user_set_vma)
+ {
+#if 0 /* ?? Does alignment in the file image really matter? */
+ pad = align_power (vma, obj_datasec(abfd)->alignment_power) - vma;
+#endif
+ obj_textsec(abfd)->_raw_size += pad;
+ pos += pad;
+ vma += pad;
+ obj_datasec(abfd)->vma = vma;
+ }
+ obj_datasec(abfd)->filepos = pos;
+ pos += obj_datasec(abfd)->_raw_size;
+ vma += obj_datasec(abfd)->_raw_size;
+
+ /* BSS. */
+ if (!obj_bsssec(abfd)->user_set_vma)
+ {
+#if 0
+ pad = align_power (vma, obj_bsssec(abfd)->alignment_power) - vma;
+#endif
+ obj_datasec(abfd)->_raw_size += pad;
+ pos += pad;
+ vma += pad;
+ obj_bsssec(abfd)->vma = vma;
+ }
+ obj_bsssec(abfd)->filepos = pos;
+
+ /* Fix up the exec header. */
+ execp->a_text = obj_textsec(abfd)->_raw_size;
+ execp->a_data = obj_datasec(abfd)->_raw_size;
+ execp->a_bss = obj_bsssec(abfd)->_raw_size;
+ N_SET_MAGIC (*execp, OMAGIC);
+}
+
+static void
+adjust_z_magic (abfd, execp)
+ bfd *abfd;
+ struct internal_exec *execp;
+{
+ bfd_size_type data_pad, text_pad;
+ file_ptr text_end;
+ CONST struct aout_backend_data *abdp;
+ int ztih; /* Nonzero if text includes exec header. */
+
+ abdp = aout_backend_info (abfd);
+
+ /* Text. */
+ ztih = (abdp != NULL
+ && (abdp->text_includes_header
+ || obj_aout_subformat (abfd) == q_magic_format));
+ obj_textsec(abfd)->filepos = (ztih
+ ? adata(abfd).exec_bytes_size
+ : adata(abfd).zmagic_disk_block_size);
+ if (! obj_textsec(abfd)->user_set_vma)
+ /* ?? Do we really need to check for relocs here? */
+ obj_textsec(abfd)->vma = ((abfd->flags & HAS_RELOC)
+ ? 0
+ : (ztih
+ ? (abdp->default_text_vma
+ + adata(abfd).exec_bytes_size)
+ : abdp->default_text_vma));
+ /* Could take strange alignment of text section into account here? */
+
+ /* Find start of data. */
+ if (ztih)
+ {
+ text_end = obj_textsec (abfd)->filepos + obj_textsec (abfd)->_raw_size;
+ text_pad = BFD_ALIGN (text_end, adata (abfd).page_size) - text_end;
+ }
+ else
+ {
+ /* Note that if page_size == zmagic_disk_block_size, then
+ filepos == page_size, and this case is the same as the ztih
+ case. */
+ text_end = obj_textsec (abfd)->_raw_size;
+ text_pad = BFD_ALIGN (text_end, adata (abfd).page_size) - text_end;
+ text_end += obj_textsec (abfd)->filepos;
+ }
+ obj_textsec(abfd)->_raw_size += text_pad;
+ text_end += text_pad;
+
+ /* Data. */
+ if (!obj_datasec(abfd)->user_set_vma)
+ {
+ bfd_vma vma;
+ vma = obj_textsec(abfd)->vma + obj_textsec(abfd)->_raw_size;
+ obj_datasec(abfd)->vma = BFD_ALIGN (vma, adata(abfd).segment_size);
+ }
+ if (abdp && abdp->zmagic_mapped_contiguous)
+ {
+ text_pad = (obj_datasec(abfd)->vma
+ - obj_textsec(abfd)->vma
+ - obj_textsec(abfd)->_raw_size);
+ obj_textsec(abfd)->_raw_size += text_pad;
+ }
+ obj_datasec(abfd)->filepos = (obj_textsec(abfd)->filepos
+ + obj_textsec(abfd)->_raw_size);
+
+ /* Fix up exec header while we're at it. */
+ execp->a_text = obj_textsec(abfd)->_raw_size;
+ if (ztih && (!abdp || (abdp && !abdp->exec_header_not_counted)))
+ execp->a_text += adata(abfd).exec_bytes_size;
+ if (obj_aout_subformat (abfd) == q_magic_format)
+ N_SET_MAGIC (*execp, QMAGIC);
+ else
+ N_SET_MAGIC (*execp, ZMAGIC);
+
+ /* Spec says data section should be rounded up to page boundary. */
+ obj_datasec(abfd)->_raw_size
+ = align_power (obj_datasec(abfd)->_raw_size,
+ obj_bsssec(abfd)->alignment_power);
+ execp->a_data = BFD_ALIGN (obj_datasec(abfd)->_raw_size,
+ adata(abfd).page_size);
+ data_pad = execp->a_data - obj_datasec(abfd)->_raw_size;
+
+ /* BSS. */
+ if (!obj_bsssec(abfd)->user_set_vma)
+ obj_bsssec(abfd)->vma = (obj_datasec(abfd)->vma
+ + obj_datasec(abfd)->_raw_size);
+ /* If the BSS immediately follows the data section and extra space
+ in the page is left after the data section, fudge data
+ in the header so that the bss section looks smaller by that
+ amount. We'll start the bss section there, and lie to the OS.
+ (Note that a linker script, as well as the above assignment,
+ could have explicitly set the BSS vma to immediately follow
+ the data section.) */
+ if (align_power (obj_bsssec(abfd)->vma, obj_bsssec(abfd)->alignment_power)
+ == obj_datasec(abfd)->vma + obj_datasec(abfd)->_raw_size)
+ execp->a_bss = (data_pad > obj_bsssec(abfd)->_raw_size) ? 0 :
+ obj_bsssec(abfd)->_raw_size - data_pad;
+ else
+ execp->a_bss = obj_bsssec(abfd)->_raw_size;
+}
+
+static void
+adjust_n_magic (abfd, execp)
+ bfd *abfd;
+ struct internal_exec *execp;
+{
+ file_ptr pos = adata(abfd).exec_bytes_size;
+ bfd_vma vma = 0;
+ int pad;
+
+ /* Text. */
+ obj_textsec(abfd)->filepos = pos;
+ if (!obj_textsec(abfd)->user_set_vma)
+ obj_textsec(abfd)->vma = vma;
+ else
+ vma = obj_textsec(abfd)->vma;
+ pos += obj_textsec(abfd)->_raw_size;
+ vma += obj_textsec(abfd)->_raw_size;
+
+ /* Data. */
+ obj_datasec(abfd)->filepos = pos;
+ if (!obj_datasec(abfd)->user_set_vma)
+ obj_datasec(abfd)->vma = BFD_ALIGN (vma, adata(abfd).segment_size);
+ vma = obj_datasec(abfd)->vma;
+
+ /* Since BSS follows data immediately, see if it needs alignment. */
+ vma += obj_datasec(abfd)->_raw_size;
+ pad = align_power (vma, obj_bsssec(abfd)->alignment_power) - vma;
+ obj_datasec(abfd)->_raw_size += pad;
+ pos += obj_datasec(abfd)->_raw_size;
+
+ /* BSS. */
+ if (!obj_bsssec(abfd)->user_set_vma)
+ obj_bsssec(abfd)->vma = vma;
+ else
+ vma = obj_bsssec(abfd)->vma;
+
+ /* Fix up exec header. */
+ execp->a_text = obj_textsec(abfd)->_raw_size;
+ execp->a_data = obj_datasec(abfd)->_raw_size;
+ execp->a_bss = obj_bsssec(abfd)->_raw_size;
+ N_SET_MAGIC (*execp, NMAGIC);
+}
+
+boolean
+NAME(aout,adjust_sizes_and_vmas) (abfd, text_size, text_end)
+ bfd *abfd;
+ bfd_size_type *text_size;
+ file_ptr *text_end;
+{
+ struct internal_exec *execp = exec_hdr (abfd);
+
+ if (! NAME(aout,make_sections) (abfd))
+ return false;
+
+ if (adata(abfd).magic != undecided_magic)
+ return true;
+
+ obj_textsec(abfd)->_raw_size =
+ align_power(obj_textsec(abfd)->_raw_size,
+ obj_textsec(abfd)->alignment_power);
+
+ *text_size = obj_textsec (abfd)->_raw_size;
+ /* Rule (heuristic) for when to pad to a new page. Note that there
+ are (at least) two ways demand-paged (ZMAGIC) files have been
+ handled. Most Berkeley-based systems start the text segment at
+ (PAGE_SIZE). However, newer versions of SUNOS start the text
+ segment right after the exec header; the latter is counted in the
+ text segment size, and is paged in by the kernel with the rest of
+ the text. */
+
+ /* This perhaps isn't the right way to do this, but made it simpler for me
+ to understand enough to implement it. Better would probably be to go
+ right from BFD flags to alignment/positioning characteristics. But the
+ old code was sloppy enough about handling the flags, and had enough
+ other magic, that it was a little hard for me to understand. I think
+ I understand it better now, but I haven't time to do the cleanup this
+ minute. */
+
+ if (abfd->flags & D_PAGED)
+ /* Whether or not WP_TEXT is set -- let D_PAGED override. */
+ adata(abfd).magic = z_magic;
+ else if (abfd->flags & WP_TEXT)
+ adata(abfd).magic = n_magic;
+ else
+ adata(abfd).magic = o_magic;
+
+#ifdef BFD_AOUT_DEBUG /* requires gcc2 */
+#if __GNUC__ >= 2
+ fprintf (stderr, "%s text=<%x,%x,%x> data=<%x,%x,%x> bss=<%x,%x,%x>\n",
+ ({ char *str;
+ switch (adata(abfd).magic) {
+ case n_magic: str = "NMAGIC"; break;
+ case o_magic: str = "OMAGIC"; break;
+ case z_magic: str = "ZMAGIC"; break;
+ default: abort ();
+ }
+ str;
+ }),
+ obj_textsec(abfd)->vma, obj_textsec(abfd)->_raw_size,
+ obj_textsec(abfd)->alignment_power,
+ obj_datasec(abfd)->vma, obj_datasec(abfd)->_raw_size,
+ obj_datasec(abfd)->alignment_power,
+ obj_bsssec(abfd)->vma, obj_bsssec(abfd)->_raw_size,
+ obj_bsssec(abfd)->alignment_power);
+#endif
+#endif
+
+ switch (adata(abfd).magic)
+ {
+ case o_magic:
+ adjust_o_magic (abfd, execp);
+ break;
+ case z_magic:
+ adjust_z_magic (abfd, execp);
+ break;
+ case n_magic:
+ adjust_n_magic (abfd, execp);
+ break;
+ default:
+ abort ();
+ }
+
+#ifdef BFD_AOUT_DEBUG
+ fprintf (stderr, " text=<%x,%x,%x> data=<%x,%x,%x> bss=<%x,%x>\n",
+ obj_textsec(abfd)->vma, obj_textsec(abfd)->_raw_size,
+ obj_textsec(abfd)->filepos,
+ obj_datasec(abfd)->vma, obj_datasec(abfd)->_raw_size,
+ obj_datasec(abfd)->filepos,
+ obj_bsssec(abfd)->vma, obj_bsssec(abfd)->_raw_size);
+#endif
+
+ return true;
+}
+
+/*
+FUNCTION
+ aout_@var{size}_new_section_hook
+
+SYNOPSIS
+ boolean aout_@var{size}_new_section_hook,
+ (bfd *abfd,
+ asection *newsect));
+
+DESCRIPTION
+ Called by the BFD in response to a @code{bfd_make_section}
+ request.
+*/
+boolean
+NAME(aout,new_section_hook) (abfd, newsect)
+ bfd *abfd;
+ asection *newsect;
+{
+ /* align to double at least */
+ newsect->alignment_power = bfd_get_arch_info(abfd)->section_align_power;
+
+
+ if (bfd_get_format (abfd) == bfd_object)
+ {
+ if (obj_textsec(abfd) == NULL && !strcmp(newsect->name, ".text")) {
+ obj_textsec(abfd)= newsect;
+ newsect->target_index = N_TEXT;
+ return true;
+ }
+
+ if (obj_datasec(abfd) == NULL && !strcmp(newsect->name, ".data")) {
+ obj_datasec(abfd) = newsect;
+ newsect->target_index = N_DATA;
+ return true;
+ }
+
+ if (obj_bsssec(abfd) == NULL && !strcmp(newsect->name, ".bss")) {
+ obj_bsssec(abfd) = newsect;
+ newsect->target_index = N_BSS;
+ return true;
+ }
+
+ }
+
+ /* We allow more than three sections internally */
+ return true;
+}
+
+boolean
+NAME(aout,set_section_contents) (abfd, section, location, offset, count)
+ bfd *abfd;
+ sec_ptr section;
+ PTR location;
+ file_ptr offset;
+ bfd_size_type count;
+{
+ file_ptr text_end;
+ bfd_size_type text_size;
+
+ if (abfd->output_has_begun == false)
+ {
+ if (NAME(aout,adjust_sizes_and_vmas) (abfd,
+ &text_size,
+ &text_end) == false)
+ return false;
+ }
+
+ /* regardless, once we know what we're doing, we might as well get going */
+ if (section != obj_bsssec(abfd))
+ {
+ if (bfd_seek (abfd, section->filepos + offset, SEEK_SET) != 0)
+ return false;
+
+ if (count) {
+ return (bfd_write ((PTR)location, 1, count, abfd) == count) ?
+ true : false;
+ }
+ return true;
+ }
+ return true;
+}
+
+/* Read the external symbols from an a.out file. */
+
+static boolean
+aout_get_external_symbols (abfd)
+ bfd *abfd;
+{
+ if (obj_aout_external_syms (abfd) == (struct external_nlist *) NULL)
+ {
+ bfd_size_type count;
+ struct external_nlist *syms;
+
+ count = exec_hdr (abfd)->a_syms / EXTERNAL_NLIST_SIZE;
+
+ /* We allocate using malloc to make the values easy to free
+ later on. If we put them on the obstack it might not be
+ possible to free them. */
+ syms = ((struct external_nlist *)
+ malloc ((size_t) count * EXTERNAL_NLIST_SIZE));
+ if (syms == (struct external_nlist *) NULL && count != 0)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ return false;
+ }
+
+ if (bfd_seek (abfd, obj_sym_filepos (abfd), SEEK_SET) != 0
+ || (bfd_read (syms, 1, exec_hdr (abfd)->a_syms, abfd)
+ != exec_hdr (abfd)->a_syms))
+ {
+ free (syms);
+ return false;
+ }
+
+ obj_aout_external_syms (abfd) = syms;
+ obj_aout_external_sym_count (abfd) = count;
+ }
+
+ if (obj_aout_external_strings (abfd) == NULL
+ && exec_hdr (abfd)->a_syms != 0)
+ {
+ unsigned char string_chars[BYTES_IN_WORD];
+ bfd_size_type stringsize;
+ char *strings;
+
+ /* Get the size of the strings. */
+ if (bfd_seek (abfd, obj_str_filepos (abfd), SEEK_SET) != 0
+ || (bfd_read ((PTR) string_chars, BYTES_IN_WORD, 1, abfd)
+ != BYTES_IN_WORD))
+ return false;
+ stringsize = GET_WORD (abfd, string_chars);
+
+ strings = (char *) malloc ((size_t) stringsize + 1);
+ if (strings == NULL)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ return false;
+ }
+
+ /* Skip space for the string count in the buffer for convenience
+ when using indexes. */
+ if (bfd_read (strings + BYTES_IN_WORD, 1, stringsize - BYTES_IN_WORD,
+ abfd)
+ != stringsize - BYTES_IN_WORD)
+ {
+ free (strings);
+ return false;
+ }
+
+ /* Sanity preservation. */
+ strings[stringsize] = '\0';
+
+ obj_aout_external_strings (abfd) = strings;
+ obj_aout_external_string_size (abfd) = stringsize;
+ }
+
+ return true;
+}
+
+/* Translate an a.out symbol into a BFD symbol. The desc, other, type
+ and symbol->value fields of CACHE_PTR will be set from the a.out
+ nlist structure. This function is responsible for setting
+ symbol->flags and symbol->section, and adjusting symbol->value. */
+
+static boolean
+translate_from_native_sym_flags (abfd, cache_ptr)
+ bfd *abfd;
+ aout_symbol_type *cache_ptr;
+{
+ flagword visible;
+
+ if ((cache_ptr->type & N_STAB) != 0
+ || cache_ptr->type == N_FN)
+ {
+ asection *sec;
+
+ /* This is a debugging symbol. */
+
+ cache_ptr->symbol.flags = BSF_DEBUGGING;
+
+ /* Work out the symbol section. */
+ switch (cache_ptr->type & N_TYPE)
+ {
+ case N_TEXT:
+ case N_FN:
+ sec = obj_textsec (abfd);
+ break;
+ case N_DATA:
+ sec = obj_datasec (abfd);
+ break;
+ case N_BSS:
+ sec = obj_bsssec (abfd);
+ break;
+ default:
+ case N_ABS:
+ sec = bfd_abs_section_ptr;
+ break;
+ }
+
+ cache_ptr->symbol.section = sec;
+ cache_ptr->symbol.value -= sec->vma;
+
+ return true;
+ }
+
+ /* Get the default visibility. This does not apply to all types, so
+ we just hold it in a local variable to use if wanted. */
+ if ((cache_ptr->type & N_EXT) == 0)
+ visible = BSF_LOCAL;
+ else
+ visible = BSF_GLOBAL;
+
+ switch (cache_ptr->type)
+ {
+ default:
+ case N_ABS: case N_ABS | N_EXT:
+ cache_ptr->symbol.section = bfd_abs_section_ptr;
+ cache_ptr->symbol.flags = visible;
+ break;
+
+ case N_UNDF | N_EXT:
+ if (cache_ptr->symbol.value != 0)
+ {
+ /* This is a common symbol. */
+ cache_ptr->symbol.flags = BSF_GLOBAL;
+ cache_ptr->symbol.section = bfd_com_section_ptr;
+ }
+ else
+ {
+ cache_ptr->symbol.flags = 0;
+ cache_ptr->symbol.section = bfd_und_section_ptr;
+ }
+ break;
+
+ case N_TEXT: case N_TEXT | N_EXT:
+ cache_ptr->symbol.section = obj_textsec (abfd);
+ cache_ptr->symbol.value -= cache_ptr->symbol.section->vma;
+ cache_ptr->symbol.flags = visible;
+ break;
+
+ /* N_SETV symbols used to represent set vectors placed in the
+ data section. They are no longer generated. Theoretically,
+ it was possible to extract the entries and combine them with
+ new ones, although I don't know if that was ever actually
+ done. Unless that feature is restored, treat them as data
+ symbols. */
+ case N_SETV: case N_SETV | N_EXT:
+ case N_DATA: case N_DATA | N_EXT:
+ cache_ptr->symbol.section = obj_datasec (abfd);
+ cache_ptr->symbol.value -= cache_ptr->symbol.section->vma;
+ cache_ptr->symbol.flags = visible;
+ break;
+
+ case N_BSS: case N_BSS | N_EXT:
+ cache_ptr->symbol.section = obj_bsssec (abfd);
+ cache_ptr->symbol.value -= cache_ptr->symbol.section->vma;
+ cache_ptr->symbol.flags = visible;
+ break;
+
+ case N_SETA: case N_SETA | N_EXT:
+ case N_SETT: case N_SETT | N_EXT:
+ case N_SETD: case N_SETD | N_EXT:
+ case N_SETB: case N_SETB | N_EXT:
+ {
+ asection *section;
+ arelent_chain *reloc;
+ asection *into_section;
+
+ /* This is a set symbol. The name of the symbol is the name
+ of the set (e.g., __CTOR_LIST__). The value of the symbol
+ is the value to add to the set. We create a section with
+ the same name as the symbol, and add a reloc to insert the
+ appropriate value into the section.
+
+ This action is actually obsolete; it used to make the
+ linker do the right thing, but the linker no longer uses
+ this function. */
+
+ section = bfd_get_section_by_name (abfd, cache_ptr->symbol.name);
+ if (section == NULL)
+ {
+ char *copy;
+
+ copy = bfd_alloc (abfd, strlen (cache_ptr->symbol.name) + 1);
+ if (copy == NULL)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ return false;
+ }
+
+ strcpy (copy, cache_ptr->symbol.name);
+ section = bfd_make_section (abfd, copy);
+ if (section == NULL)
+ return false;
+ }
+
+ reloc = (arelent_chain *) bfd_alloc (abfd, sizeof (arelent_chain));
+ if (reloc == NULL)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ return false;
+ }
+
+ /* Build a relocation entry for the constructor. */
+ switch (cache_ptr->type & N_TYPE)
+ {
+ case N_SETA:
+ into_section = bfd_abs_section_ptr;
+ cache_ptr->type = N_ABS;
+ break;
+ case N_SETT:
+ into_section = obj_textsec (abfd);
+ cache_ptr->type = N_TEXT;
+ break;
+ case N_SETD:
+ into_section = obj_datasec (abfd);
+ cache_ptr->type = N_DATA;
+ break;
+ case N_SETB:
+ into_section = obj_bsssec (abfd);
+ cache_ptr->type = N_BSS;
+ break;
+ }
+
+ /* Build a relocation pointing into the constructor section
+ pointing at the symbol in the set vector specified. */
+ reloc->relent.addend = cache_ptr->symbol.value;
+ cache_ptr->symbol.section = into_section;
+ reloc->relent.sym_ptr_ptr = into_section->symbol_ptr_ptr;
+
+ /* We modify the symbol to belong to a section depending upon
+ the name of the symbol, and add to the size of the section
+ to contain a pointer to the symbol. Build a reloc entry to
+ relocate to this symbol attached to this section. */
+ section->flags = SEC_CONSTRUCTOR | SEC_RELOC;
+
+ section->reloc_count++;
+ section->alignment_power = 2;
+
+ reloc->next = section->constructor_chain;
+ section->constructor_chain = reloc;
+ reloc->relent.address = section->_raw_size;
+ section->_raw_size += BYTES_IN_WORD;
+
+ reloc->relent.howto = CTOR_TABLE_RELOC_HOWTO(abfd);
+
+ cache_ptr->symbol.flags |= BSF_CONSTRUCTOR;
+ }
+ break;
+
+ case N_WARNING:
+ /* This symbol is the text of a warning message. The next
+ symbol is the symbol to associate the warning with. If a
+ reference is made to that symbol, a warning is issued. */
+ cache_ptr->symbol.flags = BSF_DEBUGGING | BSF_WARNING;
+
+ /* @@ Stuffing pointers into integers is a no-no. We can
+ usually get away with it if the integer is large enough
+ though. */
+ if (sizeof (cache_ptr + 1) > sizeof (bfd_vma))
+ abort ();
+ cache_ptr->symbol.value = (bfd_vma) (cache_ptr + 1);
+
+ cache_ptr->symbol.section = bfd_abs_section_ptr;
+
+ break;
+
+ case N_INDR: case N_INDR | N_EXT:
+ /* An indirect symbol. This consists of two symbols in a row.
+ The first symbol is the name of the indirection. The second
+ symbol is the name of the target. A reference to the first
+ symbol becomes a reference to the second. */
+ cache_ptr->symbol.flags = BSF_DEBUGGING | BSF_INDIRECT | visible;
+
+ /* @@ Stuffing pointers into integers is a no-no. We can
+ usually get away with it if the integer is large enough
+ though. */
+ if (sizeof (cache_ptr + 1) > sizeof (bfd_vma))
+ abort ();
+ cache_ptr->symbol.value = (bfd_vma) (cache_ptr + 1);
+
+ cache_ptr->symbol.section = bfd_ind_section_ptr;
+
+ break;
+
+ case N_WEAKU:
+ cache_ptr->symbol.section = bfd_und_section_ptr;
+ cache_ptr->symbol.flags = BSF_WEAK;
+ break;
+
+ case N_WEAKA:
+ cache_ptr->symbol.section = bfd_abs_section_ptr;
+ cache_ptr->symbol.flags = BSF_WEAK;
+ break;
+
+ case N_WEAKT:
+ cache_ptr->symbol.section = obj_textsec (abfd);
+ cache_ptr->symbol.value -= cache_ptr->symbol.section->vma;
+ cache_ptr->symbol.flags = BSF_WEAK;
+ break;
+
+ case N_WEAKD:
+ cache_ptr->symbol.section = obj_datasec (abfd);
+ cache_ptr->symbol.value -= cache_ptr->symbol.section->vma;
+ cache_ptr->symbol.flags = BSF_WEAK;
+ break;
+
+ case N_WEAKB:
+ cache_ptr->symbol.section = obj_bsssec (abfd);
+ cache_ptr->symbol.value -= cache_ptr->symbol.section->vma;
+ cache_ptr->symbol.flags = BSF_WEAK;
+ break;
+ }
+
+ return true;
+}
+
+/* Set the fields of SYM_POINTER according to CACHE_PTR. */
+
+static boolean
+translate_to_native_sym_flags (abfd, cache_ptr, sym_pointer)
+ bfd *abfd;
+ asymbol *cache_ptr;
+ struct external_nlist *sym_pointer;
+{
+ bfd_vma value = cache_ptr->value;
+
+ /* Mask out any existing type bits in case copying from one section
+ to another. */
+ sym_pointer->e_type[0] &= ~N_TYPE;
+
+ if (bfd_is_abs_section (bfd_get_section (cache_ptr)))
+ sym_pointer->e_type[0] |= N_ABS;
+ else if (bfd_get_section (cache_ptr) == obj_textsec (abfd)
+ || (bfd_get_section (cache_ptr)->output_section
+ == obj_textsec (abfd)))
+ sym_pointer->e_type[0] |= N_TEXT;
+ else if (bfd_get_section (cache_ptr) == obj_datasec (abfd)
+ || (bfd_get_section (cache_ptr)->output_section
+ == obj_datasec (abfd)))
+ sym_pointer->e_type[0] |= N_DATA;
+ else if (bfd_get_section (cache_ptr) == obj_bsssec (abfd)
+ || (bfd_get_section (cache_ptr)->output_section
+ == obj_bsssec (abfd)))
+ sym_pointer->e_type[0] |= N_BSS;
+ else if (bfd_get_section (cache_ptr) == NULL)
+ {
+ /* Protect the bfd_is_com_section call. This case occurs, e.g.,
+ for the *DEBUG* section of a COFF file. */
+ bfd_set_error (bfd_error_nonrepresentable_section);
+ return false;
+ }
+ else if (bfd_is_und_section (bfd_get_section (cache_ptr)))
+ sym_pointer->e_type[0] = N_UNDF | N_EXT;
+ else if (bfd_is_ind_section (bfd_get_section (cache_ptr)))
+ sym_pointer->e_type[0] = N_INDR;
+ else if (bfd_is_com_section (bfd_get_section (cache_ptr)))
+ sym_pointer->e_type[0] = N_UNDF | N_EXT;
+ else
+ {
+ bfd_set_error (bfd_error_nonrepresentable_section);
+ return false;
+ }
+
+ /* Turn the symbol from section relative to absolute again */
+ value += cache_ptr->section->vma;
+
+ if ((cache_ptr->flags & BSF_WARNING) != 0)
+ sym_pointer->e_type[0] = N_WARNING;
+
+ if ((cache_ptr->flags & BSF_DEBUGGING) != 0)
+ sym_pointer->e_type[0] = ((aout_symbol_type *) cache_ptr)->type;
+ else if ((cache_ptr->flags & BSF_GLOBAL) != 0)
+ sym_pointer->e_type[0] |= N_EXT;
+
+ if ((cache_ptr->flags & BSF_CONSTRUCTOR) != 0)
+ {
+ int type = ((aout_symbol_type *) cache_ptr)->type;
+ switch (type)
+ {
+ case N_ABS: type = N_SETA; break;
+ case N_TEXT: type = N_SETT; break;
+ case N_DATA: type = N_SETD; break;
+ case N_BSS: type = N_SETB; break;
+ }
+ sym_pointer->e_type[0] = type;
+ }
+
+ if ((cache_ptr->flags & BSF_WEAK) != 0)
+ {
+ int type;
+
+ switch (sym_pointer->e_type[0] & N_TYPE)
+ {
+ default:
+ case N_ABS: type = N_WEAKA; break;
+ case N_TEXT: type = N_WEAKT; break;
+ case N_DATA: type = N_WEAKD; break;
+ case N_BSS: type = N_WEAKB; break;
+ case N_UNDF: type = N_WEAKU; break;
+ }
+ sym_pointer->e_type[0] = type;
+ }
+
+ PUT_WORD(abfd, value, sym_pointer->e_value);
+
+ return true;
+}
+
+/* Native-level interface to symbols. */
+
+asymbol *
+NAME(aout,make_empty_symbol) (abfd)
+ bfd *abfd;
+{
+ aout_symbol_type *new =
+ (aout_symbol_type *)bfd_zalloc (abfd, sizeof (aout_symbol_type));
+ if (!new)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ return NULL;
+ }
+ new->symbol.the_bfd = abfd;
+
+ return &new->symbol;
+}
+
+/* Translate a set of internal symbols into external symbols. */
+
+boolean
+NAME(aout,translate_symbol_table) (abfd, in, ext, count, str, strsize, dynamic)
+ bfd *abfd;
+ aout_symbol_type *in;
+ struct external_nlist *ext;
+ bfd_size_type count;
+ char *str;
+ bfd_size_type strsize;
+ boolean dynamic;
+{
+ struct external_nlist *ext_end;
+
+ ext_end = ext + count;
+ for (; ext < ext_end; ext++, in++)
+ {
+ bfd_vma x;
+
+ x = GET_WORD (abfd, ext->e_strx);
+ in->symbol.the_bfd = abfd;
+
+ /* For the normal symbols, the zero index points at the number
+ of bytes in the string table but is to be interpreted as the
+ null string. For the dynamic symbols, the number of bytes in
+ the string table is stored in the __DYNAMIC structure and the
+ zero index points at an actual string. */
+ if (x == 0 && ! dynamic)
+ in->symbol.name = "";
+ else if (x < strsize)
+ in->symbol.name = str + x;
+ else
+ return false;
+
+ in->symbol.value = GET_SWORD (abfd, ext->e_value);
+ in->desc = bfd_h_get_16 (abfd, ext->e_desc);
+ in->other = bfd_h_get_8 (abfd, ext->e_other);
+ in->type = bfd_h_get_8 (abfd, ext->e_type);
+ in->symbol.udata = 0;
+
+ if (! translate_from_native_sym_flags (abfd, in))
+ return false;
+
+ if (dynamic)
+ in->symbol.flags |= BSF_DYNAMIC;
+ }
+
+ return true;
+}
+
+/* We read the symbols into a buffer, which is discarded when this
+ function exits. We read the strings into a buffer large enough to
+ hold them all plus all the cached symbol entries. */
+
+boolean
+NAME(aout,slurp_symbol_table) (abfd)
+ bfd *abfd;
+{
+ struct external_nlist *old_external_syms;
+ aout_symbol_type *cached;
+ size_t cached_size;
+
+ /* If there's no work to be done, don't do any */
+ if (obj_aout_symbols (abfd) != (aout_symbol_type *) NULL)
+ return true;
+
+ old_external_syms = obj_aout_external_syms (abfd);
+
+ if (! aout_get_external_symbols (abfd))
+ return false;
+
+ if (obj_aout_external_sym_count (abfd) == 0)
+ {
+ bfd_set_error (bfd_error_no_symbols);
+ return false;
+ }
+
+ cached_size = (obj_aout_external_sym_count (abfd)
+ * sizeof (aout_symbol_type));
+ cached = (aout_symbol_type *) malloc (cached_size);
+ if (cached == NULL)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ return false;
+ }
+ memset (cached, 0, cached_size);
+
+ /* Convert from external symbol information to internal. */
+ if (! (NAME(aout,translate_symbol_table)
+ (abfd, cached,
+ obj_aout_external_syms (abfd),
+ obj_aout_external_sym_count (abfd),
+ obj_aout_external_strings (abfd),
+ obj_aout_external_string_size (abfd),
+ false)))
+ {
+ free (cached);
+ return false;
+ }
+
+ bfd_get_symcount (abfd) = obj_aout_external_sym_count (abfd);
+
+ obj_aout_symbols (abfd) = cached;
+
+ /* It is very likely that anybody who calls this function will not
+ want the external symbol information, so if it was allocated
+ because of our call to aout_get_external_symbols, we free it up
+ right away to save space. */
+ if (old_external_syms == (struct external_nlist *) NULL
+ && obj_aout_external_syms (abfd) != (struct external_nlist *) NULL)
+ {
+ free (obj_aout_external_syms (abfd));
+ obj_aout_external_syms (abfd) = NULL;
+ }
+
+ return true;
+}
+
+/* We use a hash table when writing out symbols so that we only write
+ out a particular string once. This helps particularly when the
+ linker writes out stabs debugging entries, because each different
+ contributing object file tends to have many duplicate stabs
+ strings.
+
+ Possible improvements:
+ + look for strings matching trailing substrings of other strings
+ + better data structures? balanced trees?
+ + look at reducing memory use elsewhere -- maybe if we didn't have
+ to construct the entire symbol table at once, we could get by
+ with smaller amounts of VM? (What effect does that have on the
+ string table reductions?)
+
+ This hash table code breaks dbx on SunOS 4.1.3, so we don't do it
+ if BFD_TRADITIONAL_FORMAT is set. */
+
+/* An entry in the strtab hash table. */
+
+struct strtab_hash_entry
+{
+ struct bfd_hash_entry root;
+ /* Index in string table. */
+ bfd_size_type index;
+ /* Next string in strtab. */
+ struct strtab_hash_entry *next;
+};
+
+/* The strtab hash table. */
+
+struct strtab_hash
+{
+ struct bfd_hash_table table;
+ /* Size of strtab--also next available index. */
+ bfd_size_type size;
+ /* First string in strtab. */
+ struct strtab_hash_entry *first;
+ /* Last string in strtab. */
+ struct strtab_hash_entry *last;
+};
+
+static struct bfd_hash_entry *strtab_hash_newfunc
+ PARAMS ((struct bfd_hash_entry *, struct bfd_hash_table *, const char *));
+static boolean stringtab_init PARAMS ((struct strtab_hash *));
+static bfd_size_type add_to_stringtab
+ PARAMS ((bfd *, struct strtab_hash *, const char *, boolean));
+static boolean emit_stringtab PARAMS ((bfd *, struct strtab_hash *));
+
+/* Routine to create an entry in a strtab. */
+
+static struct bfd_hash_entry *
+strtab_hash_newfunc (entry, table, string)
+ struct bfd_hash_entry *entry;
+ struct bfd_hash_table *table;
+ const char *string;
+{
+ struct strtab_hash_entry *ret = (struct strtab_hash_entry *) entry;
+
+ /* Allocate the structure if it has not already been allocated by a
+ subclass. */
+ if (ret == (struct strtab_hash_entry *) NULL)
+ ret = ((struct strtab_hash_entry *)
+ bfd_hash_allocate (table, sizeof (struct strtab_hash_entry)));
+ if (ret == (struct strtab_hash_entry *) NULL)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ return NULL;
+ }
+
+ /* Call the allocation method of the superclass. */
+ ret = ((struct strtab_hash_entry *)
+ bfd_hash_newfunc ((struct bfd_hash_entry *) ret, table, string));
+
+ if (ret)
+ {
+ /* Initialize the local fields. */
+ ret->index = (bfd_size_type) -1;
+ ret->next = NULL;
+ }
+
+ return (struct bfd_hash_entry *) ret;
+}
+
+/* Look up an entry in an strtab. */
+
+#define strtab_hash_lookup(t, string, create, copy) \
+ ((struct strtab_hash_entry *) \
+ bfd_hash_lookup (&(t)->table, (string), (create), (copy)))
+
+/* Create a new strtab. */
+
+static boolean
+stringtab_init (table)
+ struct strtab_hash *table;
+{
+ if (! bfd_hash_table_init (&table->table, strtab_hash_newfunc))
+ return false;
+
+ /* Leave space for the size of the string table. */
+ table->size = BYTES_IN_WORD;
+
+ table->first = NULL;
+ table->last = NULL;
+
+ return true;
+}
+
+/* Free a strtab. */
+
+#define stringtab_free(tab) bfd_hash_table_free (&(tab)->table)
+
+/* Get the index of a string in a strtab, adding it if it is not
+ already present. If HASH is false, we don't really use the hash
+ table, and we don't eliminate duplicate strings. */
+
+static INLINE bfd_size_type
+add_to_stringtab (abfd, tab, str, copy)
+ bfd *abfd;
+ struct strtab_hash *tab;
+ const char *str;
+ boolean copy;
+{
+ register struct strtab_hash_entry *entry;
+
+ /* An index of 0 always means the empty string. */
+ if (*str == '\0')
+ return 0;
+
+ if ((abfd->flags & BFD_TRADITIONAL_FORMAT) == 0)
+ {
+ entry = strtab_hash_lookup (tab, str, true, copy);
+ if (entry == NULL)
+ return (bfd_size_type) -1;
+ }
+ else
+ {
+ entry = ((struct strtab_hash_entry *)
+ bfd_hash_allocate (&tab->table,
+ sizeof (struct strtab_hash_entry)));
+ if (entry == NULL)
+ return (bfd_size_type) -1;
+ if (! copy)
+ entry->root.string = str;
+ else
+ {
+ char *n;
+
+ n = (char *) bfd_hash_allocate (&tab->table, strlen (str) + 1);
+ if (n == NULL)
+ return (bfd_size_type) -1;
+ entry->root.string = n;
+ }
+ entry->index = (bfd_size_type) -1;
+ entry->next = NULL;
+ }
+
+ if (entry->index == (bfd_size_type) -1)
+ {
+ entry->index = tab->size;
+ tab->size += strlen (str) + 1;
+ if (tab->first == NULL)
+ tab->first = entry;
+ else
+ tab->last->next = entry;
+ tab->last = entry;
+ }
+
+ return entry->index;
+}
+
+/* Write out a strtab. ABFD is already at the right location in the
+ file. */
+
+static boolean
+emit_stringtab (abfd, tab)
+ register bfd *abfd;
+ struct strtab_hash *tab;
+{
+ bfd_byte buffer[BYTES_IN_WORD];
+ register struct strtab_hash_entry *entry;
+
+ PUT_WORD (abfd, tab->size, buffer);
+ if (bfd_write ((PTR) buffer, 1, BYTES_IN_WORD, abfd) != BYTES_IN_WORD)
+ return false;
+
+ for (entry = tab->first; entry != NULL; entry = entry->next)
+ {
+ register const char *str;
+ register size_t len;
+
+ str = entry->root.string;
+ len = strlen (str) + 1;
+ if (bfd_write ((PTR) str, 1, len, abfd) != len)
+ return false;
+ }
+
+ return true;
+}
+
+boolean
+NAME(aout,write_syms) (abfd)
+ bfd *abfd;
+{
+ unsigned int count ;
+ asymbol **generic = bfd_get_outsymbols (abfd);
+ struct strtab_hash strtab;
+
+ if (! stringtab_init (&strtab))
+ return false;
+
+ for (count = 0; count < bfd_get_symcount (abfd); count++)
+ {
+ asymbol *g = generic[count];
+ bfd_size_type indx;
+ struct external_nlist nsp;
+
+ indx = add_to_stringtab (abfd, &strtab, g->name, false);
+ if (indx == (bfd_size_type) -1)
+ goto error_return;
+ PUT_WORD (abfd, indx, (bfd_byte *) nsp.e_strx);
+
+ if (bfd_asymbol_flavour(g) == abfd->xvec->flavour)
+ {
+ bfd_h_put_16(abfd, aout_symbol(g)->desc, nsp.e_desc);
+ bfd_h_put_8(abfd, aout_symbol(g)->other, nsp.e_other);
+ bfd_h_put_8(abfd, aout_symbol(g)->type, nsp.e_type);
+ }
+ else
+ {
+ bfd_h_put_16(abfd,0, nsp.e_desc);
+ bfd_h_put_8(abfd, 0, nsp.e_other);
+ bfd_h_put_8(abfd, 0, nsp.e_type);
+ }
+
+ if (! translate_to_native_sym_flags (abfd, g, &nsp))
+ goto error_return;
+
+ if (bfd_write((PTR)&nsp,1,EXTERNAL_NLIST_SIZE, abfd)
+ != EXTERNAL_NLIST_SIZE)
+ goto error_return;
+
+ /* NB: `KEEPIT' currently overlays `flags', so set this only
+ here, at the end. */
+ g->KEEPIT = count;
+ }
+
+ if (! emit_stringtab (abfd, &strtab))
+ goto error_return;
+
+ stringtab_free (&strtab);
+
+ return true;
+
+error_return:
+ stringtab_free (&strtab);
+ return false;
+}
+
+
+long
+NAME(aout,get_symtab) (abfd, location)
+ bfd *abfd;
+ asymbol **location;
+{
+ unsigned int counter = 0;
+ aout_symbol_type *symbase;
+
+ if (!NAME(aout,slurp_symbol_table)(abfd))
+ return -1;
+
+ for (symbase = obj_aout_symbols(abfd); counter++ < bfd_get_symcount (abfd);)
+ *(location++) = (asymbol *)( symbase++);
+ *location++ =0;
+ return bfd_get_symcount (abfd);
+}
+
+
+/* Standard reloc stuff */
+/* Output standard relocation information to a file in target byte order. */
+
+void
+NAME(aout,swap_std_reloc_out) (abfd, g, natptr)
+ bfd *abfd;
+ arelent *g;
+ struct reloc_std_external *natptr;
+{
+ int r_index;
+ asymbol *sym = *(g->sym_ptr_ptr);
+ int r_extern;
+ unsigned int r_length;
+ int r_pcrel;
+ int r_baserel, r_jmptable, r_relative;
+ asection *output_section = sym->section->output_section;
+
+ PUT_WORD(abfd, g->address, natptr->r_address);
+
+ r_length = g->howto->size ; /* Size as a power of two */
+ r_pcrel = (int) g->howto->pc_relative; /* Relative to PC? */
+ /* XXX This relies on relocs coming from a.out files. */
+ r_baserel = (g->howto->type & 8) != 0;
+ r_jmptable = (g->howto->type & 16) != 0;
+ r_relative = (g->howto->type & 32) != 0;
+
+#if 0
+ /* For a standard reloc, the addend is in the object file. */
+ r_addend = g->addend + (*(g->sym_ptr_ptr))->section->output_section->vma;
+#endif
+
+ /* name was clobbered by aout_write_syms to be symbol index */
+
+ /* If this relocation is relative to a symbol then set the
+ r_index to the symbols index, and the r_extern bit.
+
+ Absolute symbols can come in in two ways, either as an offset
+ from the abs section, or as a symbol which has an abs value.
+ check for that here
+ */
+
+
+ if (bfd_is_com_section (output_section)
+ || bfd_is_abs_section (output_section)
+ || bfd_is_und_section (output_section))
+ {
+ if (bfd_abs_section_ptr->symbol == sym)
+ {
+ /* Whoops, looked like an abs symbol, but is really an offset
+ from the abs section */
+ r_index = 0;
+ r_extern = 0;
+ }
+ else
+ {
+ /* Fill in symbol */
+ r_extern = 1;
+ r_index = stoi((*(g->sym_ptr_ptr))->KEEPIT);
+
+ }
+ }
+ else
+ {
+ /* Just an ordinary section */
+ r_extern = 0;
+ r_index = output_section->target_index;
+ }
+
+ /* now the fun stuff */
+ if (abfd->xvec->header_byteorder_big_p != false) {
+ natptr->r_index[0] = r_index >> 16;
+ natptr->r_index[1] = r_index >> 8;
+ natptr->r_index[2] = r_index;
+ natptr->r_type[0] =
+ (r_extern? RELOC_STD_BITS_EXTERN_BIG: 0)
+ | (r_pcrel? RELOC_STD_BITS_PCREL_BIG: 0)
+ | (r_baserel? RELOC_STD_BITS_BASEREL_BIG: 0)
+ | (r_jmptable? RELOC_STD_BITS_JMPTABLE_BIG: 0)
+ | (r_relative? RELOC_STD_BITS_RELATIVE_BIG: 0)
+ | (r_length << RELOC_STD_BITS_LENGTH_SH_BIG);
+ } else {
+ natptr->r_index[2] = r_index >> 16;
+ natptr->r_index[1] = r_index >> 8;
+ natptr->r_index[0] = r_index;
+ natptr->r_type[0] =
+ (r_extern? RELOC_STD_BITS_EXTERN_LITTLE: 0)
+ | (r_pcrel? RELOC_STD_BITS_PCREL_LITTLE: 0)
+ | (r_baserel? RELOC_STD_BITS_BASEREL_LITTLE: 0)
+ | (r_jmptable? RELOC_STD_BITS_JMPTABLE_LITTLE: 0)
+ | (r_relative? RELOC_STD_BITS_RELATIVE_LITTLE: 0)
+ | (r_length << RELOC_STD_BITS_LENGTH_SH_LITTLE);
+ }
+}
+
+
+/* Extended stuff */
+/* Output extended relocation information to a file in target byte order. */
+
+void
+NAME(aout,swap_ext_reloc_out) (abfd, g, natptr)
+ bfd *abfd;
+ arelent *g;
+ register struct reloc_ext_external *natptr;
+{
+ int r_index;
+ int r_extern;
+ unsigned int r_type;
+ unsigned int r_addend;
+ asymbol *sym = *(g->sym_ptr_ptr);
+ asection *output_section = sym->section->output_section;
+
+ PUT_WORD (abfd, g->address, natptr->r_address);
+
+ r_type = (unsigned int) g->howto->type;
+
+ r_addend = g->addend + (*(g->sym_ptr_ptr))->section->output_section->vma;
+
+ /* If this relocation is relative to a symbol then set the
+ r_index to the symbols index, and the r_extern bit.
+
+ Absolute symbols can come in in two ways, either as an offset
+ from the abs section, or as a symbol which has an abs value.
+ check for that here. */
+
+ if (bfd_is_com_section (output_section)
+ || bfd_is_abs_section (output_section)
+ || bfd_is_und_section (output_section))
+ {
+ if (bfd_abs_section_ptr->symbol == sym)
+ {
+ /* Whoops, looked like an abs symbol, but is really an offset
+ from the abs section */
+ r_index = 0;
+ r_extern = 0;
+ }
+ else
+ {
+ r_extern = 1;
+ r_index = stoi((*(g->sym_ptr_ptr))->KEEPIT);
+ }
+ }
+ else
+ {
+ /* Just an ordinary section */
+ r_extern = 0;
+ r_index = output_section->target_index;
+ }
+
+ /* now the fun stuff */
+ if (abfd->xvec->header_byteorder_big_p != false) {
+ natptr->r_index[0] = r_index >> 16;
+ natptr->r_index[1] = r_index >> 8;
+ natptr->r_index[2] = r_index;
+ natptr->r_type[0] =
+ ((r_extern? RELOC_EXT_BITS_EXTERN_BIG: 0)
+ | (r_type << RELOC_EXT_BITS_TYPE_SH_BIG));
+ } else {
+ natptr->r_index[2] = r_index >> 16;
+ natptr->r_index[1] = r_index >> 8;
+ natptr->r_index[0] = r_index;
+ natptr->r_type[0] =
+ (r_extern? RELOC_EXT_BITS_EXTERN_LITTLE: 0)
+ | (r_type << RELOC_EXT_BITS_TYPE_SH_LITTLE);
+ }
+
+ PUT_WORD (abfd, r_addend, natptr->r_addend);
+}
+
+/* BFD deals internally with all things based from the section they're
+ in. so, something in 10 bytes into a text section with a base of
+ 50 would have a symbol (.text+10) and know .text vma was 50.
+
+ Aout keeps all it's symbols based from zero, so the symbol would
+ contain 60. This macro subs the base of each section from the value
+ to give the true offset from the section */
+
+
+#define MOVE_ADDRESS(ad) \
+ if (r_extern) { \
+ /* undefined symbol */ \
+ cache_ptr->sym_ptr_ptr = symbols + r_index; \
+ cache_ptr->addend = ad; \
+ } else { \
+ /* defined, section relative. replace symbol with pointer to \
+ symbol which points to section */ \
+ switch (r_index) { \
+ case N_TEXT: \
+ case N_TEXT | N_EXT: \
+ cache_ptr->sym_ptr_ptr = obj_textsec(abfd)->symbol_ptr_ptr; \
+ cache_ptr->addend = ad - su->textsec->vma; \
+ break; \
+ case N_DATA: \
+ case N_DATA | N_EXT: \
+ cache_ptr->sym_ptr_ptr = obj_datasec(abfd)->symbol_ptr_ptr; \
+ cache_ptr->addend = ad - su->datasec->vma; \
+ break; \
+ case N_BSS: \
+ case N_BSS | N_EXT: \
+ cache_ptr->sym_ptr_ptr = obj_bsssec(abfd)->symbol_ptr_ptr; \
+ cache_ptr->addend = ad - su->bsssec->vma; \
+ break; \
+ default: \
+ case N_ABS: \
+ case N_ABS | N_EXT: \
+ cache_ptr->sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr; \
+ cache_ptr->addend = ad; \
+ break; \
+ } \
+ } \
+
+void
+NAME(aout,swap_ext_reloc_in) (abfd, bytes, cache_ptr, symbols)
+ bfd *abfd;
+ struct reloc_ext_external *bytes;
+ arelent *cache_ptr;
+ asymbol **symbols;
+{
+ int r_index;
+ int r_extern;
+ unsigned int r_type;
+ struct aoutdata *su = &(abfd->tdata.aout_data->a);
+
+ cache_ptr->address = (GET_SWORD (abfd, bytes->r_address));
+
+ /* now the fun stuff */
+ if (abfd->xvec->header_byteorder_big_p != false) {
+ r_index = (bytes->r_index[0] << 16)
+ | (bytes->r_index[1] << 8)
+ | bytes->r_index[2];
+ r_extern = (0 != (bytes->r_type[0] & RELOC_EXT_BITS_EXTERN_BIG));
+ r_type = (bytes->r_type[0] & RELOC_EXT_BITS_TYPE_BIG)
+ >> RELOC_EXT_BITS_TYPE_SH_BIG;
+ } else {
+ r_index = (bytes->r_index[2] << 16)
+ | (bytes->r_index[1] << 8)
+ | bytes->r_index[0];
+ r_extern = (0 != (bytes->r_type[0] & RELOC_EXT_BITS_EXTERN_LITTLE));
+ r_type = (bytes->r_type[0] & RELOC_EXT_BITS_TYPE_LITTLE)
+ >> RELOC_EXT_BITS_TYPE_SH_LITTLE;
+ }
+
+ cache_ptr->howto = howto_table_ext + r_type;
+ MOVE_ADDRESS(GET_SWORD(abfd, bytes->r_addend));
+}
+
+void
+NAME(aout,swap_std_reloc_in) (abfd, bytes, cache_ptr, symbols)
+ bfd *abfd;
+ struct reloc_std_external *bytes;
+ arelent *cache_ptr;
+ asymbol **symbols;
+{
+ int r_index;
+ int r_extern;
+ unsigned int r_length;
+ int r_pcrel;
+ int r_baserel, r_jmptable, r_relative;
+ struct aoutdata *su = &(abfd->tdata.aout_data->a);
+ int howto_idx;
+
+ cache_ptr->address = bfd_h_get_32 (abfd, bytes->r_address);
+
+ /* now the fun stuff */
+ if (abfd->xvec->header_byteorder_big_p != false) {
+ r_index = (bytes->r_index[0] << 16)
+ | (bytes->r_index[1] << 8)
+ | bytes->r_index[2];
+ r_extern = (0 != (bytes->r_type[0] & RELOC_STD_BITS_EXTERN_BIG));
+ r_pcrel = (0 != (bytes->r_type[0] & RELOC_STD_BITS_PCREL_BIG));
+ r_baserel = (0 != (bytes->r_type[0] & RELOC_STD_BITS_BASEREL_BIG));
+ r_jmptable= (0 != (bytes->r_type[0] & RELOC_STD_BITS_JMPTABLE_BIG));
+ r_relative= (0 != (bytes->r_type[0] & RELOC_STD_BITS_RELATIVE_BIG));
+ r_length = (bytes->r_type[0] & RELOC_STD_BITS_LENGTH_BIG)
+ >> RELOC_STD_BITS_LENGTH_SH_BIG;
+ } else {
+ r_index = (bytes->r_index[2] << 16)
+ | (bytes->r_index[1] << 8)
+ | bytes->r_index[0];
+ r_extern = (0 != (bytes->r_type[0] & RELOC_STD_BITS_EXTERN_LITTLE));
+ r_pcrel = (0 != (bytes->r_type[0] & RELOC_STD_BITS_PCREL_LITTLE));
+ r_baserel = (0 != (bytes->r_type[0] & RELOC_STD_BITS_BASEREL_LITTLE));
+ r_jmptable= (0 != (bytes->r_type[0] & RELOC_STD_BITS_JMPTABLE_LITTLE));
+ r_relative= (0 != (bytes->r_type[0] & RELOC_STD_BITS_RELATIVE_LITTLE));
+ r_length = (bytes->r_type[0] & RELOC_STD_BITS_LENGTH_LITTLE)
+ >> RELOC_STD_BITS_LENGTH_SH_LITTLE;
+ }
+
+ howto_idx = r_length + 4 * r_pcrel + 8 * r_baserel
+ + 16 * r_jmptable + 32 * r_relative;
+ BFD_ASSERT (howto_idx < TABLE_SIZE (howto_table_std));
+ cache_ptr->howto = howto_table_std + howto_idx;
+ BFD_ASSERT (cache_ptr->howto->type != -1);
+
+ MOVE_ADDRESS(0);
+}
+
+/* Read and swap the relocs for a section. */
+
+boolean
+NAME(aout,slurp_reloc_table) (abfd, asect, symbols)
+ bfd *abfd;
+ sec_ptr asect;
+ asymbol **symbols;
+{
+ unsigned int count;
+ bfd_size_type reloc_size;
+ PTR relocs;
+ arelent *reloc_cache;
+ size_t each_size;
+ unsigned int counter = 0;
+ arelent *cache_ptr;
+
+ if (asect->relocation)
+ return true;
+
+ if (asect->flags & SEC_CONSTRUCTOR)
+ return true;
+
+ if (asect == obj_datasec (abfd))
+ reloc_size = exec_hdr(abfd)->a_drsize;
+ else if (asect == obj_textsec (abfd))
+ reloc_size = exec_hdr(abfd)->a_trsize;
+ else if (asect == obj_bsssec (abfd))
+ reloc_size = 0;
+ else
+ {
+ bfd_set_error (bfd_error_invalid_operation);
+ return false;
+ }
+
+ if (bfd_seek (abfd, asect->rel_filepos, SEEK_SET) != 0)
+ return false;
+
+ each_size = obj_reloc_entry_size (abfd);
+
+ count = reloc_size / each_size;
+
+ reloc_cache = (arelent *) malloc ((size_t) (count * sizeof (arelent)));
+ if (reloc_cache == NULL && count != 0)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ return false;
+ }
+ memset (reloc_cache, 0, count * sizeof (arelent));
+
+ relocs = malloc (reloc_size);
+ if (relocs == NULL && reloc_size != 0)
+ {
+ free (reloc_cache);
+ bfd_set_error (bfd_error_no_memory);
+ return false;
+ }
+
+ if (bfd_read (relocs, 1, reloc_size, abfd) != reloc_size)
+ {
+ free (relocs);
+ free (reloc_cache);
+ return false;
+ }
+
+ cache_ptr = reloc_cache;
+ if (each_size == RELOC_EXT_SIZE)
+ {
+ register struct reloc_ext_external *rptr =
+ (struct reloc_ext_external *) relocs;
+
+ for (; counter < count; counter++, rptr++, cache_ptr++)
+ NAME(aout,swap_ext_reloc_in) (abfd, rptr, cache_ptr, symbols);
+ }
+ else
+ {
+ register struct reloc_std_external *rptr =
+ (struct reloc_std_external *) relocs;
+
+ for (; counter < count; counter++, rptr++, cache_ptr++)
+ MY_swap_std_reloc_in(abfd, rptr, cache_ptr, symbols);
+ }
+
+ free (relocs);
+
+ asect->relocation = reloc_cache;
+ asect->reloc_count = cache_ptr - reloc_cache;
+
+ return true;
+}
+
+/* Write out a relocation section into an object file. */
+
+boolean
+NAME(aout,squirt_out_relocs) (abfd, section)
+ bfd *abfd;
+ asection *section;
+{
+ arelent **generic;
+ unsigned char *native, *natptr;
+ size_t each_size;
+
+ unsigned int count = section->reloc_count;
+ size_t natsize;
+
+ if (count == 0) return true;
+
+ each_size = obj_reloc_entry_size (abfd);
+ natsize = each_size * count;
+ native = (unsigned char *) bfd_zalloc (abfd, natsize);
+ if (!native) {
+ bfd_set_error (bfd_error_no_memory);
+ return false;
+ }
+
+ generic = section->orelocation;
+
+ if (each_size == RELOC_EXT_SIZE)
+ {
+ for (natptr = native;
+ count != 0;
+ --count, natptr += each_size, ++generic)
+ NAME(aout,swap_ext_reloc_out) (abfd, *generic, (struct reloc_ext_external *)natptr);
+ }
+ else
+ {
+ for (natptr = native;
+ count != 0;
+ --count, natptr += each_size, ++generic)
+ MY_swap_std_reloc_out(abfd, *generic, (struct reloc_std_external *)natptr);
+ }
+
+ if ( bfd_write ((PTR) native, 1, natsize, abfd) != natsize) {
+ bfd_release(abfd, native);
+ return false;
+ }
+ bfd_release (abfd, native);
+
+ return true;
+}
+
+/* This is stupid. This function should be a boolean predicate */
+long
+NAME(aout,canonicalize_reloc) (abfd, section, relptr, symbols)
+ bfd *abfd;
+ sec_ptr section;
+ arelent **relptr;
+ asymbol **symbols;
+{
+ arelent *tblptr = section->relocation;
+ unsigned int count;
+
+ if (section == obj_bsssec (abfd))
+ {
+ *relptr = NULL;
+ return 0;
+ }
+
+ if (!(tblptr || NAME(aout,slurp_reloc_table)(abfd, section, symbols)))
+ return -1;
+
+ if (section->flags & SEC_CONSTRUCTOR) {
+ arelent_chain *chain = section->constructor_chain;
+ for (count = 0; count < section->reloc_count; count ++) {
+ *relptr ++ = &chain->relent;
+ chain = chain->next;
+ }
+ }
+ else {
+ tblptr = section->relocation;
+
+ for (count = 0; count++ < section->reloc_count;)
+ {
+ *relptr++ = tblptr++;
+ }
+ }
+ *relptr = 0;
+
+ return section->reloc_count;
+}
+
+long
+NAME(aout,get_reloc_upper_bound) (abfd, asect)
+ bfd *abfd;
+ sec_ptr asect;
+{
+ if (bfd_get_format (abfd) != bfd_object) {
+ bfd_set_error (bfd_error_invalid_operation);
+ return -1;
+ }
+ if (asect->flags & SEC_CONSTRUCTOR) {
+ return (sizeof (arelent *) * (asect->reloc_count+1));
+ }
+
+ if (asect == obj_datasec (abfd))
+ return (sizeof (arelent *)
+ * ((exec_hdr(abfd)->a_drsize / obj_reloc_entry_size (abfd))
+ + 1));
+
+ if (asect == obj_textsec (abfd))
+ return (sizeof (arelent *)
+ * ((exec_hdr(abfd)->a_trsize / obj_reloc_entry_size (abfd))
+ + 1));
+
+ if (asect == obj_bsssec (abfd))
+ return sizeof (arelent *);
+
+ if (asect == obj_bsssec (abfd))
+ return 0;
+
+ bfd_set_error (bfd_error_invalid_operation);
+ return -1;
+}
+
+
+long
+NAME(aout,get_symtab_upper_bound) (abfd)
+ bfd *abfd;
+{
+ if (!NAME(aout,slurp_symbol_table)(abfd))
+ return -1;
+
+ return (bfd_get_symcount (abfd)+1) * (sizeof (aout_symbol_type *));
+}
+
+/*ARGSUSED*/
+ alent *
+NAME(aout,get_lineno) (ignore_abfd, ignore_symbol)
+ bfd *ignore_abfd;
+ asymbol *ignore_symbol;
+{
+return (alent *)NULL;
+}
+
+/*ARGSUSED*/
+void
+NAME(aout,get_symbol_info) (ignore_abfd, symbol, ret)
+ bfd *ignore_abfd;
+ asymbol *symbol;
+ symbol_info *ret;
+{
+ bfd_symbol_info (symbol, ret);
+
+ if (ret->type == '?')
+ {
+ int type_code = aout_symbol(symbol)->type & 0xff;
+ CONST char *stab_name = aout_stab_name(type_code);
+ static char buf[10];
+
+ if (stab_name == NULL)
+ {
+ sprintf(buf, "(%d)", type_code);
+ stab_name = buf;
+ }
+ ret->type = '-';
+ ret->stab_other = (unsigned)(aout_symbol(symbol)->other & 0xff);
+ ret->stab_desc = (unsigned)(aout_symbol(symbol)->desc & 0xffff);
+ ret->stab_name = stab_name;
+ }
+}
+
+/*ARGSUSED*/
+void
+NAME(aout,print_symbol) (ignore_abfd, afile, symbol, how)
+ bfd *ignore_abfd;
+ PTR afile;
+ asymbol *symbol;
+ bfd_print_symbol_type how;
+{
+ FILE *file = (FILE *)afile;
+
+ switch (how) {
+ case bfd_print_symbol_name:
+ if (symbol->name)
+ fprintf(file,"%s", symbol->name);
+ break;
+ case bfd_print_symbol_more:
+ fprintf(file,"%4x %2x %2x",(unsigned)(aout_symbol(symbol)->desc & 0xffff),
+ (unsigned)(aout_symbol(symbol)->other & 0xff),
+ (unsigned)(aout_symbol(symbol)->type));
+ break;
+ case bfd_print_symbol_all:
+ {
+ CONST char *section_name = symbol->section->name;
+
+
+ bfd_print_symbol_vandf((PTR)file,symbol);
+
+ fprintf(file," %-5s %04x %02x %02x",
+ section_name,
+ (unsigned)(aout_symbol(symbol)->desc & 0xffff),
+ (unsigned)(aout_symbol(symbol)->other & 0xff),
+ (unsigned)(aout_symbol(symbol)->type & 0xff));
+ if (symbol->name)
+ fprintf(file," %s", symbol->name);
+ }
+ break;
+ }
+}
+
+/*
+ provided a BFD, a section and an offset into the section, calculate
+ and return the name of the source file and the line nearest to the
+ wanted location.
+*/
+
+boolean
+NAME(aout,find_nearest_line)
+ (abfd, section, symbols, offset, filename_ptr, functionname_ptr, line_ptr)
+ bfd *abfd;
+ asection *section;
+ asymbol **symbols;
+ bfd_vma offset;
+ CONST char **filename_ptr;
+ CONST char **functionname_ptr;
+ unsigned int *line_ptr;
+{
+ /* Run down the file looking for the filename, function and linenumber */
+ asymbol **p;
+ static char buffer[100];
+ static char filename_buffer[200];
+ CONST char *directory_name = NULL;
+ CONST char *main_file_name = NULL;
+ CONST char *current_file_name = NULL;
+ CONST char *line_file_name = NULL; /* Value of current_file_name at line number. */
+ bfd_vma high_line_vma = ~0;
+ bfd_vma low_func_vma = 0;
+ asymbol *func = 0;
+ *filename_ptr = abfd->filename;
+ *functionname_ptr = 0;
+ *line_ptr = 0;
+ if (symbols != (asymbol **)NULL) {
+ for (p = symbols; *p; p++) {
+ aout_symbol_type *q = (aout_symbol_type *)(*p);
+ next:
+ switch (q->type){
+ case N_SO:
+ main_file_name = current_file_name = q->symbol.name;
+ /* Look ahead to next symbol to check if that too is an N_SO. */
+ p++;
+ if (*p == NULL)
+ break;
+ q = (aout_symbol_type *)(*p);
+ if (q->type != (int)N_SO)
+ goto next;
+
+ /* Found a second N_SO First is directory; second is filename. */
+ directory_name = current_file_name;
+ main_file_name = current_file_name = q->symbol.name;
+ if (obj_textsec(abfd) != section)
+ goto done;
+ break;
+ case N_SOL:
+ current_file_name = q->symbol.name;
+ break;
+
+ case N_SLINE:
+
+ case N_DSLINE:
+ case N_BSLINE:
+ /* We'll keep this if it resolves nearer than the one we have already */
+ if (q->symbol.value >= offset &&
+ q->symbol.value < high_line_vma) {
+ *line_ptr = q->desc;
+ high_line_vma = q->symbol.value;
+ line_file_name = current_file_name;
+ }
+ break;
+ case N_FUN:
+ {
+ /* We'll keep this if it is nearer than the one we have already */
+ if (q->symbol.value >= low_func_vma &&
+ q->symbol.value <= offset) {
+ low_func_vma = q->symbol.value;
+ func = (asymbol *)q;
+ }
+ if (*line_ptr && func) {
+ CONST char *function = func->name;
+ char *p;
+
+ /* The caller expects a symbol name. We actually have a
+ function name, without the leading underscore. Put the
+ underscore back in, so that the caller gets a symbol
+ name. */
+ if (bfd_get_symbol_leading_char (abfd) == '\0')
+ strncpy (buffer, function, sizeof (buffer) - 1);
+ else
+ {
+ buffer[0] = bfd_get_symbol_leading_char (abfd);
+ strncpy (buffer + 1, function, sizeof (buffer) - 2);
+ }
+ buffer[sizeof(buffer)-1] = 0;
+ /* Have to remove : stuff */
+ p = strchr(buffer,':');
+ if (p != NULL) { *p = '\0'; }
+ *functionname_ptr = buffer;
+ goto done;
+
+ }
+ }
+ break;
+ }
+ }
+ }
+
+ done:
+ if (*line_ptr)
+ main_file_name = line_file_name;
+ if (main_file_name) {
+ if (main_file_name[0] == '/' || directory_name == NULL)
+ *filename_ptr = main_file_name;
+ else {
+ sprintf(filename_buffer, "%.140s%.50s",
+ directory_name, main_file_name);
+ *filename_ptr = filename_buffer;
+ }
+ }
+ return true;
+
+}
+
+/*ARGSUSED*/
+int
+NAME(aout,sizeof_headers) (abfd, execable)
+ bfd *abfd;
+ boolean execable;
+{
+ return adata(abfd).exec_bytes_size;
+}
+
+/* Free all information we have cached for this BFD. We can always
+ read it again later if we need it. */
+
+boolean
+NAME(aout,bfd_free_cached_info) (abfd)
+ bfd *abfd;
+{
+ asection *o;
+
+ if (bfd_get_format (abfd) != bfd_object)
+ return true;
+
+#define BFCI_FREE(x) if (x != NULL) { free (x); x = NULL; }
+ BFCI_FREE (obj_aout_symbols (abfd));
+ BFCI_FREE (obj_aout_external_syms (abfd));
+ BFCI_FREE (obj_aout_external_strings (abfd));
+ for (o = abfd->sections; o != (asection *) NULL; o = o->next)
+ BFCI_FREE (o->relocation);
+#undef BFCI_FREE
+
+ return true;
+}
+
+/* a.out link code. */
+
+static boolean aout_link_add_object_symbols
+ PARAMS ((bfd *, struct bfd_link_info *));
+static boolean aout_link_check_archive_element
+ PARAMS ((bfd *, struct bfd_link_info *, boolean *));
+static boolean aout_link_free_symbols PARAMS ((bfd *));
+static boolean aout_link_check_ar_symbols
+ PARAMS ((bfd *, struct bfd_link_info *, boolean *pneeded));
+static boolean aout_link_add_symbols
+ PARAMS ((bfd *, struct bfd_link_info *));
+
+/* Routine to create an entry in an a.out link hash table. */
+
+struct bfd_hash_entry *
+NAME(aout,link_hash_newfunc) (entry, table, string)
+ struct bfd_hash_entry *entry;
+ struct bfd_hash_table *table;
+ const char *string;
+{
+ struct aout_link_hash_entry *ret = (struct aout_link_hash_entry *) entry;
+
+ /* Allocate the structure if it has not already been allocated by a
+ subclass. */
+ if (ret == (struct aout_link_hash_entry *) NULL)
+ ret = ((struct aout_link_hash_entry *)
+ bfd_hash_allocate (table, sizeof (struct aout_link_hash_entry)));
+ if (ret == (struct aout_link_hash_entry *) NULL)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ return (struct bfd_hash_entry *) ret;
+ }
+
+ /* Call the allocation method of the superclass. */
+ ret = ((struct aout_link_hash_entry *)
+ _bfd_link_hash_newfunc ((struct bfd_hash_entry *) ret,
+ table, string));
+ if (ret)
+ {
+ /* Set local fields. */
+ ret->written = false;
+ ret->indx = -1;
+ }
+
+ return (struct bfd_hash_entry *) ret;
+}
+
+/* Initialize an a.out link hash table. */
+
+boolean
+NAME(aout,link_hash_table_init) (table, abfd, newfunc)
+ struct aout_link_hash_table *table;
+ bfd *abfd;
+ struct bfd_hash_entry *(*newfunc) PARAMS ((struct bfd_hash_entry *,
+ struct bfd_hash_table *,
+ const char *));
+{
+ return _bfd_link_hash_table_init (&table->root, abfd, newfunc);
+}
+
+/* Create an a.out link hash table. */
+
+struct bfd_link_hash_table *
+NAME(aout,link_hash_table_create) (abfd)
+ bfd *abfd;
+{
+ struct aout_link_hash_table *ret;
+
+ ret = ((struct aout_link_hash_table *)
+ malloc (sizeof (struct aout_link_hash_table)));
+ if (ret == (struct aout_link_hash_table *) NULL)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ return (struct bfd_link_hash_table *) NULL;
+ }
+ if (! NAME(aout,link_hash_table_init) (ret, abfd,
+ NAME(aout,link_hash_newfunc)))
+ {
+ free (ret);
+ return (struct bfd_link_hash_table *) NULL;
+ }
+ return &ret->root;
+}
+
+/* Given an a.out BFD, add symbols to the global hash table as
+ appropriate. */
+
+boolean
+NAME(aout,link_add_symbols) (abfd, info)
+ bfd *abfd;
+ struct bfd_link_info *info;
+{
+ switch (bfd_get_format (abfd))
+ {
+ case bfd_object:
+ return aout_link_add_object_symbols (abfd, info);
+ case bfd_archive:
+ return _bfd_generic_link_add_archive_symbols
+ (abfd, info, aout_link_check_archive_element);
+ default:
+ bfd_set_error (bfd_error_wrong_format);
+ return false;
+ }
+}
+
+/* Add symbols from an a.out object file. */
+
+static boolean
+aout_link_add_object_symbols (abfd, info)
+ bfd *abfd;
+ struct bfd_link_info *info;
+{
+ if (! aout_get_external_symbols (abfd))
+ return false;
+ if (! aout_link_add_symbols (abfd, info))
+ return false;
+ if (! info->keep_memory)
+ {
+ if (! aout_link_free_symbols (abfd))
+ return false;
+ }
+ return true;
+}
+
+/* Check a single archive element to see if we need to include it in
+ the link. *PNEEDED is set according to whether this element is
+ needed in the link or not. This is called from
+ _bfd_generic_link_add_archive_symbols. */
+
+static boolean
+aout_link_check_archive_element (abfd, info, pneeded)
+ bfd *abfd;
+ struct bfd_link_info *info;
+ boolean *pneeded;
+{
+ if (! aout_get_external_symbols (abfd))
+ return false;
+
+ if (! aout_link_check_ar_symbols (abfd, info, pneeded))
+ return false;
+
+ if (*pneeded)
+ {
+ if (! aout_link_add_symbols (abfd, info))
+ return false;
+ }
+
+ /* We keep around the symbols even if we aren't going to use this
+ object file, because we may want to reread it. This doesn't
+ waste too much memory, because it isn't all that common to read
+ an archive element but not need it. */
+ if (! info->keep_memory)
+ {
+ if (! aout_link_free_symbols (abfd))
+ return false;
+ }
+
+ return true;
+}
+
+/* Free up the internal symbols read from an a.out file. */
+
+static boolean
+aout_link_free_symbols (abfd)
+ bfd *abfd;
+{
+ if (obj_aout_external_syms (abfd) != (struct external_nlist *) NULL)
+ {
+ free ((PTR) obj_aout_external_syms (abfd));
+ obj_aout_external_syms (abfd) = (struct external_nlist *) NULL;
+ }
+ if (obj_aout_external_strings (abfd) != (char *) NULL)
+ {
+ free ((PTR) obj_aout_external_strings (abfd));
+ obj_aout_external_strings (abfd) = (char *) NULL;
+ }
+ return true;
+}
+
+/* Look through the internal symbols to see if this object file should
+ be included in the link. We should include this object file if it
+ defines any symbols which are currently undefined. If this object
+ file defines a common symbol, then we may adjust the size of the
+ known symbol but we do not include the object file in the link
+ (unless there is some other reason to include it). */
+
+static boolean
+aout_link_check_ar_symbols (abfd, info, pneeded)
+ bfd *abfd;
+ struct bfd_link_info *info;
+ boolean *pneeded;
+{
+ register struct external_nlist *p;
+ struct external_nlist *pend;
+ char *strings;
+
+ *pneeded = false;
+
+ /* Look through all the symbols. */
+ p = obj_aout_external_syms (abfd);
+ pend = p + obj_aout_external_sym_count (abfd);
+ strings = obj_aout_external_strings (abfd);
+ for (; p < pend; p++)
+ {
+ int type = bfd_h_get_8 (abfd, p->e_type);
+ const char *name;
+ struct bfd_link_hash_entry *h;
+
+ /* Ignore symbols that are not externally visible. This is an
+ optimization only, as we check the type more thoroughly
+ below. */
+ if (((type & N_EXT) == 0
+ || (type & N_STAB) != 0
+ || type == N_FN)
+ && type != N_WEAKA
+ && type != N_WEAKT
+ && type != N_WEAKD
+ && type != N_WEAKB)
+ {
+ if (type == N_WARNING
+ || type == N_INDR)
+ ++p;
+ continue;
+ }
+
+ name = strings + GET_WORD (abfd, p->e_strx);
+ h = bfd_link_hash_lookup (info->hash, name, false, false, true);
+
+ /* We are only interested in symbols that are currently
+ undefined or common. */
+ if (h == (struct bfd_link_hash_entry *) NULL
+ || (h->type != bfd_link_hash_undefined
+ && h->type != bfd_link_hash_common))
+ {
+ if (type == (N_INDR | N_EXT))
+ ++p;
+ continue;
+ }
+
+ if (type == (N_TEXT | N_EXT)
+ || type == (N_DATA | N_EXT)
+ || type == (N_BSS | N_EXT)
+ || type == (N_ABS | N_EXT)
+ || type == (N_INDR | N_EXT))
+ {
+ /* This object file defines this symbol. We must link it
+ in. This is true regardless of whether the current
+ definition of the symbol is undefined or common. If the
+ current definition is common, we have a case in which we
+ have already seen an object file including
+ int a;
+ and this object file from the archive includes
+ int a = 5;
+ In such a case we must include this object file.
+
+ FIXME: The SunOS 4.1.3 linker will pull in the archive
+ element if the symbol is defined in the .data section,
+ but not if it is defined in the .text section. That
+ seems a bit crazy to me, and I haven't implemented it.
+ However, it might be correct. */
+ if (! (*info->callbacks->add_archive_element) (info, abfd, name))
+ return false;
+ *pneeded = true;
+ return true;
+ }
+
+ if (type == (N_UNDF | N_EXT))
+ {
+ bfd_vma value;
+
+ value = GET_WORD (abfd, p->e_value);
+ if (value != 0)
+ {
+ /* This symbol is common in the object from the archive
+ file. */
+ if (h->type == bfd_link_hash_undefined)
+ {
+ bfd *symbfd;
+
+ symbfd = h->u.undef.abfd;
+ if (symbfd == (bfd *) NULL)
+ {
+ /* This symbol was created as undefined from
+ outside BFD. We assume that we should link
+ in the object file. This is done for the -u
+ option in the linker. */
+ if (! (*info->callbacks->add_archive_element) (info,
+ abfd,
+ name))
+ return false;
+ *pneeded = true;
+ return true;
+ }
+ /* Turn the current link symbol into a common
+ symbol. It is already on the undefs list. */
+ h->type = bfd_link_hash_common;
+ h->u.c.size = value;
+ h->u.c.section = bfd_make_section_old_way (symbfd,
+ "COMMON");
+ }
+ else
+ {
+ /* Adjust the size of the common symbol if
+ necessary. */
+ if (value > h->u.c.size)
+ h->u.c.size = value;
+ }
+ }
+ }
+
+ if (type == N_WEAKA
+ || type == N_WEAKT
+ || type == N_WEAKD
+ || type == N_WEAKB)
+ {
+ /* This symbol is weak but defined. We must pull it in if
+ the current link symbol is undefined, but we don't want
+ it if the current link symbol is common. */
+ if (h->type == bfd_link_hash_undefined)
+ {
+ if (! (*info->callbacks->add_archive_element) (info, abfd, name))
+ return false;
+ *pneeded = true;
+ return true;
+ }
+ }
+ }
+
+ /* We do not need this object file. */
+ return true;
+}
+
+/* Add all symbols from an object file to the hash table. */
+
+static boolean
+aout_link_add_symbols (abfd, info)
+ bfd *abfd;
+ struct bfd_link_info *info;
+{
+ boolean (*add_one_symbol) PARAMS ((struct bfd_link_info *, bfd *,
+ const char *, flagword, asection *,
+ bfd_vma, const char *, boolean,
+ boolean,
+ struct bfd_link_hash_entry **));
+ bfd_size_type sym_count;
+ char *strings;
+ boolean copy;
+ struct aout_link_hash_entry **sym_hash;
+ register struct external_nlist *p;
+ struct external_nlist *pend;
+
+ sym_count = obj_aout_external_sym_count (abfd);
+ strings = obj_aout_external_strings (abfd);
+ if (info->keep_memory)
+ copy = false;
+ else
+ copy = true;
+
+ /* We keep a list of the linker hash table entries that correspond
+ to particular symbols. We could just look them up in the hash
+ table, but keeping the list is more efficient. Perhaps this
+ should be conditional on info->keep_memory. */
+ sym_hash = ((struct aout_link_hash_entry **)
+ bfd_alloc (abfd,
+ ((size_t) sym_count
+ * sizeof (struct aout_link_hash_entry *))));
+ if (sym_hash == NULL && sym_count != 0)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ return false;
+ }
+ obj_aout_sym_hashes (abfd) = sym_hash;
+
+ if ((abfd->flags & DYNAMIC) != 0
+ && aout_backend_info (abfd)->add_dynamic_symbols != NULL)
+ {
+ if (! (*aout_backend_info (abfd)->add_dynamic_symbols) (abfd, info))
+ return false;
+ }
+
+ add_one_symbol = aout_backend_info (abfd)->add_one_symbol;
+ if (add_one_symbol == NULL)
+ add_one_symbol = _bfd_generic_link_add_one_symbol;
+
+ p = obj_aout_external_syms (abfd);
+ pend = p + sym_count;
+ for (; p < pend; p++, sym_hash++)
+ {
+ int type;
+ const char *name;
+ bfd_vma value;
+ asection *section;
+ flagword flags;
+ const char *string;
+
+ *sym_hash = NULL;
+
+ type = bfd_h_get_8 (abfd, p->e_type);
+
+ /* Ignore debugging symbols. */
+ if ((type & N_STAB) != 0)
+ continue;
+
+ name = strings + GET_WORD (abfd, p->e_strx);
+ value = GET_WORD (abfd, p->e_value);
+ flags = BSF_GLOBAL;
+ string = NULL;
+ switch (type)
+ {
+ default:
+ abort ();
+
+ case N_UNDF:
+ case N_ABS:
+ case N_TEXT:
+ case N_DATA:
+ case N_BSS:
+ case N_FN_SEQ:
+ case N_COMM:
+ case N_SETV:
+ case N_FN:
+ /* Ignore symbols that are not externally visible. */
+ continue;
+ case N_INDR:
+ /* Ignore local indirect symbol. */
+ ++p;
+ ++sym_hash;
+ continue;
+
+ case N_UNDF | N_EXT:
+ if (value == 0)
+ {
+ section = bfd_und_section_ptr;
+ flags = 0;
+ }
+ else
+ section = bfd_com_section_ptr;
+ break;
+ case N_ABS | N_EXT:
+ section = bfd_abs_section_ptr;
+ break;
+ case N_TEXT | N_EXT:
+ section = obj_textsec (abfd);
+ value -= bfd_get_section_vma (abfd, section);
+ break;
+ case N_DATA | N_EXT:
+ case N_SETV | N_EXT:
+ /* Treat N_SETV symbols as N_DATA symbol; see comment in
+ translate_from_native_sym_flags. */
+ section = obj_datasec (abfd);
+ value -= bfd_get_section_vma (abfd, section);
+ break;
+ case N_BSS | N_EXT:
+ section = obj_bsssec (abfd);
+ value -= bfd_get_section_vma (abfd, section);
+ break;
+ case N_INDR | N_EXT:
+ /* An indirect symbol. The next symbol is the symbol
+ which this one really is. */
+ BFD_ASSERT (p + 1 < pend);
+ ++p;
+ string = strings + GET_WORD (abfd, p->e_strx);
+ section = bfd_ind_section_ptr;
+ flags |= BSF_INDIRECT;
+ break;
+ case N_COMM | N_EXT:
+ section = bfd_com_section_ptr;
+ break;
+ case N_SETA: case N_SETA | N_EXT:
+ section = bfd_abs_section_ptr;
+ flags |= BSF_CONSTRUCTOR;
+ break;
+ case N_SETT: case N_SETT | N_EXT:
+ section = obj_textsec (abfd);
+ flags |= BSF_CONSTRUCTOR;
+ value -= bfd_get_section_vma (abfd, section);
+ break;
+ case N_SETD: case N_SETD | N_EXT:
+ section = obj_datasec (abfd);
+ flags |= BSF_CONSTRUCTOR;
+ value -= bfd_get_section_vma (abfd, section);
+ break;
+ case N_SETB: case N_SETB | N_EXT:
+ section = obj_bsssec (abfd);
+ flags |= BSF_CONSTRUCTOR;
+ value -= bfd_get_section_vma (abfd, section);
+ break;
+ case N_WARNING:
+ /* A warning symbol. The next symbol is the one to warn
+ about. */
+ BFD_ASSERT (p + 1 < pend);
+ ++p;
+ string = name;
+ name = strings + GET_WORD (abfd, p->e_strx);
+ section = bfd_und_section_ptr;
+ flags |= BSF_WARNING;
+ break;
+ case N_WEAKU:
+ section = bfd_und_section_ptr;
+ flags = BSF_WEAK;
+ break;
+ case N_WEAKA:
+ section = bfd_abs_section_ptr;
+ flags = BSF_WEAK;
+ break;
+ case N_WEAKT:
+ section = obj_textsec (abfd);
+ value -= bfd_get_section_vma (abfd, section);
+ flags = BSF_WEAK;
+ break;
+ case N_WEAKD:
+ section = obj_datasec (abfd);
+ value -= bfd_get_section_vma (abfd, section);
+ flags = BSF_WEAK;
+ break;
+ case N_WEAKB:
+ section = obj_bsssec (abfd);
+ value -= bfd_get_section_vma (abfd, section);
+ flags = BSF_WEAK;
+ break;
+ }
+
+ if (! ((*add_one_symbol)
+ (info, abfd, name, flags, section, value, string, copy, false,
+ (struct bfd_link_hash_entry **) sym_hash)))
+ return false;
+
+ if (type == (N_INDR | N_EXT) || type == N_WARNING)
+ ++sym_hash;
+ }
+
+ return true;
+}
+
+/* During the final link step we need to pass around a bunch of
+ information, so we do it in an instance of this structure. */
+
+struct aout_final_link_info
+{
+ /* General link information. */
+ struct bfd_link_info *info;
+ /* Output bfd. */
+ bfd *output_bfd;
+ /* Reloc file positions. */
+ file_ptr treloff, dreloff;
+ /* File position of symbols. */
+ file_ptr symoff;
+ /* String table. */
+ struct strtab_hash strtab;
+};
+
+static boolean aout_link_input_bfd
+ PARAMS ((struct aout_final_link_info *, bfd *input_bfd));
+static boolean aout_link_write_symbols
+ PARAMS ((struct aout_final_link_info *, bfd *input_bfd, int *symbol_map));
+static boolean aout_link_write_other_symbol
+ PARAMS ((struct aout_link_hash_entry *, PTR));
+static boolean aout_link_input_section
+ PARAMS ((struct aout_final_link_info *, bfd *input_bfd,
+ asection *input_section, file_ptr *reloff_ptr,
+ bfd_size_type rel_size, int *symbol_map));
+static boolean aout_link_input_section_std
+ PARAMS ((struct aout_final_link_info *, bfd *input_bfd,
+ asection *input_section, struct reloc_std_external *,
+ bfd_size_type rel_size, bfd_byte *contents, int *symbol_map));
+static boolean aout_link_input_section_ext
+ PARAMS ((struct aout_final_link_info *, bfd *input_bfd,
+ asection *input_section, struct reloc_ext_external *,
+ bfd_size_type rel_size, bfd_byte *contents, int *symbol_map));
+static INLINE asection *aout_reloc_index_to_section
+ PARAMS ((bfd *, int));
+static boolean aout_link_reloc_link_order
+ PARAMS ((struct aout_final_link_info *, asection *,
+ struct bfd_link_order *));
+
+/* Do the final link step. This is called on the output BFD. The
+ INFO structure should point to a list of BFDs linked through the
+ link_next field which can be used to find each BFD which takes part
+ in the output. Also, each section in ABFD should point to a list
+ of bfd_link_order structures which list all the input sections for
+ the output section. */
+
+boolean
+NAME(aout,final_link) (abfd, info, callback)
+ bfd *abfd;
+ struct bfd_link_info *info;
+ void (*callback) PARAMS ((bfd *, file_ptr *, file_ptr *, file_ptr *));
+{
+ struct aout_final_link_info aout_info;
+ register bfd *sub;
+ bfd_size_type text_size;
+ file_ptr text_end;
+ register struct bfd_link_order *p;
+ asection *o;
+ boolean have_link_order_relocs;
+
+ aout_info.info = info;
+ aout_info.output_bfd = abfd;
+
+ if (! info->relocateable)
+ {
+ exec_hdr (abfd)->a_trsize = 0;
+ exec_hdr (abfd)->a_drsize = 0;
+ }
+ else
+ {
+ bfd_size_type trsize, drsize;
+
+ /* Count up the relocation sizes. */
+ trsize = 0;
+ drsize = 0;
+ for (sub = info->input_bfds; sub != (bfd *) NULL; sub = sub->link_next)
+ {
+ if (bfd_get_flavour (sub) == bfd_target_aout_flavour)
+ {
+ trsize += exec_hdr (sub)->a_trsize;
+ drsize += exec_hdr (sub)->a_drsize;
+ }
+ else
+ {
+ /* FIXME: We need to identify the .text and .data sections
+ and call get_reloc_upper_bound and canonicalize_reloc to
+ work out the number of relocs needed, and then multiply
+ by the reloc size. */
+ abort ();
+ }
+ }
+ if (obj_textsec (abfd) != (asection *) NULL)
+ trsize += (_bfd_count_link_order_relocs (obj_textsec (abfd)
+ ->link_order_head)
+ * obj_reloc_entry_size (abfd));
+ exec_hdr (abfd)->a_trsize = trsize;
+ if (obj_datasec (abfd) != (asection *) NULL)
+ drsize += (_bfd_count_link_order_relocs (obj_datasec (abfd)
+ ->link_order_head)
+ * obj_reloc_entry_size (abfd));
+ exec_hdr (abfd)->a_drsize = drsize;
+ }
+
+ exec_hdr (abfd)->a_entry = bfd_get_start_address (abfd);
+
+ /* Adjust the section sizes and vmas according to the magic number.
+ This sets a_text, a_data and a_bss in the exec_hdr and sets the
+ filepos for each section. */
+ if (! NAME(aout,adjust_sizes_and_vmas) (abfd, &text_size, &text_end))
+ return false;
+
+ /* The relocation and symbol file positions differ among a.out
+ targets. We are passed a callback routine from the backend
+ specific code to handle this.
+ FIXME: At this point we do not know how much space the symbol
+ table will require. This will not work for any (nonstandard)
+ a.out target that needs to know the symbol table size before it
+ can compute the relocation file positions. This may or may not
+ be the case for the hp300hpux target, for example. */
+ (*callback) (abfd, &aout_info.treloff, &aout_info.dreloff,
+ &aout_info.symoff);
+ obj_textsec (abfd)->rel_filepos = aout_info.treloff;
+ obj_datasec (abfd)->rel_filepos = aout_info.dreloff;
+ obj_sym_filepos (abfd) = aout_info.symoff;
+
+ /* We keep a count of the symbols as we output them. */
+ obj_aout_external_sym_count (abfd) = 0;
+
+ /* We accumulate the string table as we write out the symbols. */
+ if (! stringtab_init (&aout_info.strtab))
+ return false;
+
+ /* The most time efficient way to do the link would be to read all
+ the input object files into memory and then sort out the
+ information into the output file. Unfortunately, that will
+ probably use too much memory. Another method would be to step
+ through everything that composes the text section and write it
+ out, and then everything that composes the data section and write
+ it out, and then write out the relocs, and then write out the
+ symbols. Unfortunately, that requires reading stuff from each
+ input file several times, and we will not be able to keep all the
+ input files open simultaneously, and reopening them will be slow.
+
+ What we do is basically process one input file at a time. We do
+ everything we need to do with an input file once--copy over the
+ section contents, handle the relocation information, and write
+ out the symbols--and then we throw away the information we read
+ from it. This approach requires a lot of lseeks of the output
+ file, which is unfortunate but still faster than reopening a lot
+ of files.
+
+ We use the output_has_begun field of the input BFDs to see
+ whether we have already handled it. */
+ for (sub = info->input_bfds; sub != (bfd *) NULL; sub = sub->link_next)
+ sub->output_has_begun = false;
+
+ have_link_order_relocs = false;
+ for (o = abfd->sections; o != (asection *) NULL; o = o->next)
+ {
+ for (p = o->link_order_head;
+ p != (struct bfd_link_order *) NULL;
+ p = p->next)
+ {
+ if (p->type == bfd_indirect_link_order
+ && (bfd_get_flavour (p->u.indirect.section->owner)
+ == bfd_target_aout_flavour))
+ {
+ bfd *input_bfd;
+
+ input_bfd = p->u.indirect.section->owner;
+ if (! input_bfd->output_has_begun)
+ {
+ if (! aout_link_input_bfd (&aout_info, input_bfd))
+ return false;
+ input_bfd->output_has_begun = true;
+ }
+ }
+ else if (p->type == bfd_section_reloc_link_order
+ || p->type == bfd_symbol_reloc_link_order)
+ {
+ /* These are handled below. */
+ have_link_order_relocs = true;
+ }
+ else
+ {
+ if (! _bfd_default_link_order (abfd, info, o, p))
+ return false;
+ }
+ }
+ }
+
+ /* Write out any symbols that we have not already written out. */
+ aout_link_hash_traverse (aout_hash_table (info),
+ aout_link_write_other_symbol,
+ (PTR) &aout_info);
+
+ /* Now handle any relocs we were asked to create by the linker.
+ These did not come from any input file. We must do these after
+ we have written out all the symbols, so that we know the symbol
+ indices to use. */
+ if (have_link_order_relocs)
+ {
+ for (o = abfd->sections; o != (asection *) NULL; o = o->next)
+ {
+ for (p = o->link_order_head;
+ p != (struct bfd_link_order *) NULL;
+ p = p->next)
+ {
+ if (p->type == bfd_section_reloc_link_order
+ || p->type == bfd_symbol_reloc_link_order)
+ {
+ if (! aout_link_reloc_link_order (&aout_info, o, p))
+ return false;
+ }
+ }
+ }
+ }
+
+ /* Finish up any dynamic linking we may be doing. */
+ if (aout_backend_info (abfd)->finish_dynamic_link != NULL)
+ {
+ if (! (*aout_backend_info (abfd)->finish_dynamic_link) (abfd, info))
+ return false;
+ }
+
+ /* Update the header information. */
+ abfd->symcount = obj_aout_external_sym_count (abfd);
+ exec_hdr (abfd)->a_syms = abfd->symcount * EXTERNAL_NLIST_SIZE;
+ obj_str_filepos (abfd) = obj_sym_filepos (abfd) + exec_hdr (abfd)->a_syms;
+ obj_textsec (abfd)->reloc_count =
+ exec_hdr (abfd)->a_trsize / obj_reloc_entry_size (abfd);
+ obj_datasec (abfd)->reloc_count =
+ exec_hdr (abfd)->a_drsize / obj_reloc_entry_size (abfd);
+
+ /* Write out the string table. */
+ if (bfd_seek (abfd, obj_str_filepos (abfd), SEEK_SET) != 0)
+ return false;
+ return emit_stringtab (abfd, &aout_info.strtab);
+}
+
+/* Link an a.out input BFD into the output file. */
+
+static boolean
+aout_link_input_bfd (finfo, input_bfd)
+ struct aout_final_link_info *finfo;
+ bfd *input_bfd;
+{
+ bfd_size_type sym_count;
+ int *symbol_map = NULL;
+
+ BFD_ASSERT (bfd_get_format (input_bfd) == bfd_object);
+
+ /* If this is a dynamic object, it may need special handling. */
+ if ((input_bfd->flags & DYNAMIC) != 0
+ && aout_backend_info (input_bfd)->link_dynamic_object != NULL)
+ {
+ return ((*aout_backend_info (input_bfd)->link_dynamic_object)
+ (finfo->info, input_bfd));
+ }
+
+ /* Get the symbols. We probably have them already, unless
+ finfo->info->keep_memory is false. */
+ if (! aout_get_external_symbols (input_bfd))
+ return false;
+
+ sym_count = obj_aout_external_sym_count (input_bfd);
+ symbol_map = (int *) malloc ((size_t) sym_count * sizeof (int));
+ if (symbol_map == NULL && sym_count != 0)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ return false;
+ }
+
+ /* Write out the symbols and get a map of the new indices. */
+ if (! aout_link_write_symbols (finfo, input_bfd, symbol_map))
+ goto error_return;
+
+ /* Relocate and write out the sections. */
+ if (! aout_link_input_section (finfo, input_bfd,
+ obj_textsec (input_bfd),
+ &finfo->treloff,
+ exec_hdr (input_bfd)->a_trsize,
+ symbol_map)
+ || ! aout_link_input_section (finfo, input_bfd,
+ obj_datasec (input_bfd),
+ &finfo->dreloff,
+ exec_hdr (input_bfd)->a_drsize,
+ symbol_map))
+ goto error_return;
+
+ /* If we are not keeping memory, we don't need the symbols any
+ longer. We still need them if we are keeping memory, because the
+ strings in the hash table point into them. */
+ if (! finfo->info->keep_memory)
+ {
+ if (! aout_link_free_symbols (input_bfd))
+ goto error_return;
+ }
+
+ if (symbol_map != NULL)
+ free (symbol_map);
+ return true;
+ error_return:
+ if (symbol_map != NULL)
+ free (symbol_map);
+ return false;
+}
+
+/* Adjust and write out the symbols for an a.out file. Set the new
+ symbol indices into a symbol_map. */
+
+static boolean
+aout_link_write_symbols (finfo, input_bfd, symbol_map)
+ struct aout_final_link_info *finfo;
+ bfd *input_bfd;
+ int *symbol_map;
+{
+ bfd *output_bfd;
+ bfd_size_type sym_count;
+ char *strings;
+ enum bfd_link_strip strip;
+ enum bfd_link_discard discard;
+ struct external_nlist *output_syms = NULL;
+ struct external_nlist *outsym;
+ bfd_size_type strtab_index;
+ register struct external_nlist *sym;
+ struct external_nlist *sym_end;
+ struct aout_link_hash_entry **sym_hash;
+ boolean pass;
+ boolean skip_indirect;
+
+ output_bfd = finfo->output_bfd;
+ sym_count = obj_aout_external_sym_count (input_bfd);
+ strings = obj_aout_external_strings (input_bfd);
+ strip = finfo->info->strip;
+ discard = finfo->info->discard;
+ output_syms = ((struct external_nlist *)
+ malloc ((size_t) (sym_count + 1) * EXTERNAL_NLIST_SIZE));
+ if (output_syms == NULL)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ goto error_return;
+ }
+ outsym = output_syms;
+
+ /* First write out a symbol for this object file, unless we are
+ discarding such symbols. */
+ if (strip != strip_all
+ && (strip != strip_some
+ || bfd_hash_lookup (finfo->info->keep_hash, input_bfd->filename,
+ false, false) != NULL)
+ && discard != discard_all)
+ {
+ bfd_h_put_8 (output_bfd, N_TEXT, outsym->e_type);
+ bfd_h_put_8 (output_bfd, 0, outsym->e_other);
+ bfd_h_put_16 (output_bfd, (bfd_vma) 0, outsym->e_desc);
+ strtab_index = add_to_stringtab (output_bfd, &finfo->strtab,
+ input_bfd->filename, false);
+ if (strtab_index == (bfd_size_type) -1)
+ goto error_return;
+ PUT_WORD (output_bfd, strtab_index, outsym->e_strx);
+ PUT_WORD (output_bfd,
+ (bfd_get_section_vma (output_bfd,
+ obj_textsec (input_bfd)->output_section)
+ + obj_textsec (input_bfd)->output_offset),
+ outsym->e_value);
+ ++obj_aout_external_sym_count (output_bfd);
+ ++outsym;
+ }
+
+ pass = false;
+ skip_indirect = false;
+ sym = obj_aout_external_syms (input_bfd);
+ sym_end = sym + sym_count;
+ sym_hash = obj_aout_sym_hashes (input_bfd);
+ for (; sym < sym_end; sym++, sym_hash++, symbol_map++)
+ {
+ const char *name;
+ int type;
+ struct aout_link_hash_entry *h;
+ boolean skip;
+ asection *symsec;
+ bfd_vma val = 0;
+ boolean copy;
+
+ *symbol_map = -1;
+
+ type = bfd_h_get_8 (input_bfd, sym->e_type);
+ name = strings + GET_WORD (input_bfd, sym->e_strx);
+
+ h = NULL;
+
+ if (pass)
+ {
+ /* Pass this symbol through. It is the target of an
+ indirect or warning symbol. */
+ val = GET_WORD (input_bfd, sym->e_value);
+ pass = false;
+ }
+ else if (skip_indirect)
+ {
+ /* Skip this symbol, which is the target of an indirect
+ symbol that we have changed to no longer be an indirect
+ symbol. */
+ skip_indirect = false;
+ continue;
+ }
+ else
+ {
+ struct aout_link_hash_entry *hresolve;
+
+ /* We have saved the hash table entry for this symbol, if
+ there is one. Note that we could just look it up again
+ in the hash table, provided we first check that it is an
+ external symbol. */
+ h = *sym_hash;
+
+ /* If this is an indirect or warning symbol, then change
+ hresolve to the base symbol. We also change *sym_hash so
+ that the relocation routines relocate against the real
+ symbol. */
+ hresolve = h;
+ if (h != (struct aout_link_hash_entry *) NULL
+ && (h->root.type == bfd_link_hash_indirect
+ || h->root.type == bfd_link_hash_warning))
+ {
+ hresolve = (struct aout_link_hash_entry *) h->root.u.i.link;
+ while (hresolve->root.type == bfd_link_hash_indirect
+ || hresolve->root.type == bfd_link_hash_warning)
+ hresolve = ((struct aout_link_hash_entry *)
+ hresolve->root.u.i.link);
+ *sym_hash = hresolve;
+ }
+
+ /* If the symbol has already been written out, skip it. */
+ if (h != (struct aout_link_hash_entry *) NULL
+ && h->root.type != bfd_link_hash_warning
+ && h->written)
+ {
+ if ((type & N_TYPE) == N_INDR)
+ skip_indirect = true;
+ *symbol_map = h->indx;
+ continue;
+ }
+
+ /* See if we are stripping this symbol. */
+ skip = false;
+ switch (strip)
+ {
+ case strip_none:
+ break;
+ case strip_debugger:
+ if ((type & N_STAB) != 0)
+ skip = true;
+ break;
+ case strip_some:
+ if (bfd_hash_lookup (finfo->info->keep_hash, name, false, false)
+ == NULL)
+ skip = true;
+ break;
+ case strip_all:
+ skip = true;
+ break;
+ }
+ if (skip)
+ {
+ if (h != (struct aout_link_hash_entry *) NULL)
+ h->written = true;
+ continue;
+ }
+
+ /* Get the value of the symbol. */
+ if ((type & N_TYPE) == N_TEXT
+ || type == N_WEAKT)
+ symsec = obj_textsec (input_bfd);
+ else if ((type & N_TYPE) == N_DATA
+ || type == N_WEAKD)
+ symsec = obj_datasec (input_bfd);
+ else if ((type & N_TYPE) == N_BSS
+ || type == N_WEAKB)
+ symsec = obj_bsssec (input_bfd);
+ else if ((type & N_TYPE) == N_ABS
+ || type == N_WEAKA)
+ symsec = bfd_abs_section_ptr;
+ else if (((type & N_TYPE) == N_INDR
+ && (hresolve == (struct aout_link_hash_entry *) NULL
+ || (hresolve->root.type != bfd_link_hash_defined
+ && hresolve->root.type != bfd_link_hash_common)))
+ || type == N_WARNING)
+ {
+ /* Pass the next symbol through unchanged. The
+ condition above for indirect symbols is so that if
+ the indirect symbol was defined, we output it with
+ the correct definition so the debugger will
+ understand it. */
+ pass = true;
+ val = GET_WORD (input_bfd, sym->e_value);
+ symsec = NULL;
+ }
+ else if ((type & N_STAB) != 0)
+ {
+ val = GET_WORD (input_bfd, sym->e_value);
+ symsec = NULL;
+ }
+ else
+ {
+ /* If we get here with an indirect symbol, it means that
+ we are outputting it with a real definition. In such
+ a case we do not want to output the next symbol,
+ which is the target of the indirection. */
+ if ((type & N_TYPE) == N_INDR)
+ skip_indirect = true;
+
+ /* We need to get the value from the hash table. We use
+ hresolve so that if we have defined an indirect
+ symbol we output the final definition. */
+ if (h == (struct aout_link_hash_entry *) NULL)
+ val = 0;
+ else if (hresolve->root.type == bfd_link_hash_defined)
+ {
+ asection *input_section;
+ asection *output_section;
+
+ /* This case means a common symbol which was turned
+ into a defined symbol. */
+ input_section = hresolve->root.u.def.section;
+ output_section = input_section->output_section;
+ BFD_ASSERT (bfd_is_abs_section (output_section)
+ || output_section->owner == output_bfd);
+ val = (hresolve->root.u.def.value
+ + bfd_get_section_vma (output_bfd, output_section)
+ + input_section->output_offset);
+
+ /* Get the correct type based on the section. If
+ this is a constructed set, force it to be
+ globally visible. */
+ if (type == N_SETT
+ || type == N_SETD
+ || type == N_SETB
+ || type == N_SETA)
+ type |= N_EXT;
+
+ type &=~ N_TYPE;
+
+ if (output_section == obj_textsec (output_bfd))
+ type |= N_TEXT;
+ else if (output_section == obj_datasec (output_bfd))
+ type |= N_DATA;
+ else if (output_section == obj_bsssec (output_bfd))
+ type |= N_BSS;
+ else
+ type |= N_ABS;
+ }
+ else if (hresolve->root.type == bfd_link_hash_common)
+ val = hresolve->root.u.c.size;
+ else if (hresolve->root.type == bfd_link_hash_weak)
+ {
+ val = 0;
+ type = N_WEAKU;
+ }
+ else
+ val = 0;
+
+ symsec = NULL;
+ }
+ if (symsec != (asection *) NULL)
+ val = (symsec->output_section->vma
+ + symsec->output_offset
+ + (GET_WORD (input_bfd, sym->e_value)
+ - symsec->vma));
+
+ /* If this is a global symbol set the written flag, and if
+ it is a local symbol see if we should discard it. */
+ if (h != (struct aout_link_hash_entry *) NULL)
+ {
+ h->written = true;
+ h->indx = obj_aout_external_sym_count (output_bfd);
+ }
+ else
+ {
+ switch (discard)
+ {
+ case discard_none:
+ break;
+ case discard_l:
+ if (*name == *finfo->info->lprefix
+ && (finfo->info->lprefix_len == 1
+ || strncmp (name, finfo->info->lprefix,
+ finfo->info->lprefix_len) == 0))
+ skip = true;
+ break;
+ case discard_all:
+ skip = true;
+ break;
+ }
+ if (skip)
+ {
+ pass = false;
+ continue;
+ }
+ }
+ }
+
+ /* Copy this symbol into the list of symbols we are going to
+ write out. */
+ bfd_h_put_8 (output_bfd, type, outsym->e_type);
+ bfd_h_put_8 (output_bfd, bfd_h_get_8 (input_bfd, sym->e_other),
+ outsym->e_other);
+ bfd_h_put_16 (output_bfd, bfd_h_get_16 (input_bfd, sym->e_desc),
+ outsym->e_desc);
+ copy = false;
+ if (! finfo->info->keep_memory)
+ {
+ /* name points into a string table which we are going to
+ free. If there is a hash table entry, use that string.
+ Otherwise, copy name into memory. */
+ if (h != (struct aout_link_hash_entry *) NULL)
+ name = (*sym_hash)->root.root.string;
+ else
+ copy = true;
+ }
+ strtab_index = add_to_stringtab (output_bfd, &finfo->strtab,
+ name, copy);
+ if (strtab_index == (bfd_size_type) -1)
+ goto error_return;
+ PUT_WORD (output_bfd, strtab_index, outsym->e_strx);
+ PUT_WORD (output_bfd, val, outsym->e_value);
+ *symbol_map = obj_aout_external_sym_count (output_bfd);
+ ++obj_aout_external_sym_count (output_bfd);
+ ++outsym;
+ }
+
+ /* Write out the output symbols we have just constructed. */
+ if (outsym > output_syms)
+ {
+ bfd_size_type outsym_count;
+
+ if (bfd_seek (output_bfd, finfo->symoff, SEEK_SET) != 0)
+ goto error_return;
+ outsym_count = outsym - output_syms;
+ if (bfd_write ((PTR) output_syms, (bfd_size_type) EXTERNAL_NLIST_SIZE,
+ (bfd_size_type) outsym_count, output_bfd)
+ != outsym_count * EXTERNAL_NLIST_SIZE)
+ goto error_return;
+ finfo->symoff += outsym_count * EXTERNAL_NLIST_SIZE;
+ }
+
+ if (output_syms != NULL)
+ free (output_syms);
+ return true;
+ error_return:
+ if (output_syms != NULL)
+ free (output_syms);
+ return false;
+}
+
+/* Write out a symbol that was not associated with an a.out input
+ object. */
+
+static boolean
+aout_link_write_other_symbol (h, data)
+ struct aout_link_hash_entry *h;
+ PTR data;
+{
+ struct aout_final_link_info *finfo = (struct aout_final_link_info *) data;
+ bfd *output_bfd;
+ int type;
+ bfd_vma val;
+ struct external_nlist outsym;
+ bfd_size_type indx;
+
+ output_bfd = finfo->output_bfd;
+
+ if (aout_backend_info (output_bfd)->write_dynamic_symbol != NULL)
+ {
+ if (! ((*aout_backend_info (output_bfd)->write_dynamic_symbol)
+ (output_bfd, finfo->info, h)))
+ {
+ /* FIXME: No way to handle errors. */
+ abort ();
+ }
+ }
+
+ if (h->written)
+ return true;
+
+ h->written = true;
+
+ if (finfo->info->strip == strip_all
+ || (finfo->info->strip == strip_some
+ && bfd_hash_lookup (finfo->info->keep_hash, h->root.root.string,
+ false, false) == NULL))
+ return true;
+
+ switch (h->root.type)
+ {
+ default:
+ case bfd_link_hash_new:
+ abort ();
+ /* Avoid variable not initialized warnings. */
+ return true;
+ case bfd_link_hash_undefined:
+ type = N_UNDF | N_EXT;
+ val = 0;
+ break;
+ case bfd_link_hash_defined:
+ {
+ asection *sec;
+
+ sec = h->root.u.def.section->output_section;
+ BFD_ASSERT (bfd_is_abs_section (sec)
+ || sec->owner == output_bfd);
+ if (sec == obj_textsec (output_bfd))
+ type = N_TEXT | N_EXT;
+ else if (sec == obj_datasec (output_bfd))
+ type = N_DATA | N_EXT;
+ else if (sec == obj_bsssec (output_bfd))
+ type = N_BSS | N_EXT;
+ else
+ type = N_ABS | N_EXT;
+ val = (h->root.u.def.value
+ + sec->vma
+ + h->root.u.def.section->output_offset);
+ }
+ break;
+ case bfd_link_hash_common:
+ type = N_UNDF | N_EXT;
+ val = h->root.u.c.size;
+ break;
+ case bfd_link_hash_weak:
+ type = N_WEAKU;
+ val = 0;
+ case bfd_link_hash_indirect:
+ case bfd_link_hash_warning:
+ /* FIXME: Ignore these for now. The circumstances under which
+ they should be written out are not clear to me. */
+ return true;
+ }
+
+ bfd_h_put_8 (output_bfd, type, outsym.e_type);
+ bfd_h_put_8 (output_bfd, 0, outsym.e_other);
+ bfd_h_put_16 (output_bfd, 0, outsym.e_desc);
+ indx = add_to_stringtab (output_bfd, &finfo->strtab, h->root.root.string,
+ false);
+ if (indx == (bfd_size_type) -1)
+ {
+ /* FIXME: No way to handle errors. */
+ abort ();
+ }
+ PUT_WORD (output_bfd, indx, outsym.e_strx);
+ PUT_WORD (output_bfd, val, outsym.e_value);
+
+ if (bfd_seek (output_bfd, finfo->symoff, SEEK_SET) != 0
+ || bfd_write ((PTR) &outsym, (bfd_size_type) EXTERNAL_NLIST_SIZE,
+ (bfd_size_type) 1, output_bfd) != EXTERNAL_NLIST_SIZE)
+ {
+ /* FIXME: No way to handle errors. */
+ abort ();
+ }
+
+ finfo->symoff += EXTERNAL_NLIST_SIZE;
+ h->indx = obj_aout_external_sym_count (output_bfd);
+ ++obj_aout_external_sym_count (output_bfd);
+
+ return true;
+}
+
+/* Link an a.out section into the output file. */
+
+static boolean
+aout_link_input_section (finfo, input_bfd, input_section, reloff_ptr,
+ rel_size, symbol_map)
+ struct aout_final_link_info *finfo;
+ bfd *input_bfd;
+ asection *input_section;
+ file_ptr *reloff_ptr;
+ bfd_size_type rel_size;
+ int *symbol_map;
+{
+ bfd_size_type input_size;
+ bfd_byte *contents = NULL;
+ PTR relocs;
+ PTR free_relocs = NULL;
+
+ /* Get the section contents. */
+ input_size = bfd_section_size (input_bfd, input_section);
+ contents = (bfd_byte *) malloc (input_size);
+ if (contents == NULL && input_size != 0)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ goto error_return;
+ }
+ if (! bfd_get_section_contents (input_bfd, input_section, (PTR) contents,
+ (file_ptr) 0, input_size))
+ goto error_return;
+
+ /* Read in the relocs if we haven't already done it. */
+ if (aout_section_data (input_section) != NULL
+ && aout_section_data (input_section)->relocs != NULL)
+ relocs = aout_section_data (input_section)->relocs;
+ else
+ {
+ relocs = free_relocs = (PTR) malloc (rel_size);
+ if (relocs == NULL && rel_size != 0)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ goto error_return;
+ }
+ if (bfd_seek (input_bfd, input_section->rel_filepos, SEEK_SET) != 0
+ || bfd_read (relocs, 1, rel_size, input_bfd) != rel_size)
+ goto error_return;
+ }
+
+ /* Relocate the section contents. */
+ if (obj_reloc_entry_size (input_bfd) == RELOC_STD_SIZE)
+ {
+ if (! aout_link_input_section_std (finfo, input_bfd, input_section,
+ (struct reloc_std_external *) relocs,
+ rel_size, contents, symbol_map))
+ goto error_return;
+ }
+ else
+ {
+ if (! aout_link_input_section_ext (finfo, input_bfd, input_section,
+ (struct reloc_ext_external *) relocs,
+ rel_size, contents, symbol_map))
+ goto error_return;
+ }
+
+ /* Write out the section contents. */
+ if (! bfd_set_section_contents (finfo->output_bfd,
+ input_section->output_section,
+ (PTR) contents,
+ input_section->output_offset,
+ input_size))
+ goto error_return;
+
+ /* If we are producing relocateable output, the relocs were
+ modified, and we now write them out. */
+ if (finfo->info->relocateable)
+ {
+ if (bfd_seek (finfo->output_bfd, *reloff_ptr, SEEK_SET) != 0)
+ goto error_return;
+ if (bfd_write (relocs, (bfd_size_type) 1, rel_size, finfo->output_bfd)
+ != rel_size)
+ goto error_return;
+ *reloff_ptr += rel_size;
+
+ /* Assert that the relocs have not run into the symbols, and
+ that if these are the text relocs they have not run into the
+ data relocs. */
+ BFD_ASSERT (*reloff_ptr <= obj_sym_filepos (finfo->output_bfd)
+ && (reloff_ptr != &finfo->treloff
+ || (*reloff_ptr
+ <= obj_datasec (finfo->output_bfd)->rel_filepos)));
+ }
+
+ if (free_relocs != NULL)
+ free (free_relocs);
+ if (contents != NULL)
+ free (contents);
+ return true;
+ error_return:
+ if (free_relocs != NULL)
+ free (free_relocs);
+ if (contents != NULL)
+ free (contents);
+ return false;
+}
+
+/* Get the section corresponding to a reloc index. */
+
+static INLINE asection *
+aout_reloc_index_to_section (abfd, indx)
+ bfd *abfd;
+ int indx;
+{
+ switch (indx & N_TYPE)
+ {
+ case N_TEXT:
+ return obj_textsec (abfd);
+ case N_DATA:
+ return obj_datasec (abfd);
+ case N_BSS:
+ return obj_bsssec (abfd);
+ case N_ABS:
+ case N_UNDF:
+ return bfd_abs_section_ptr;
+ default:
+ abort ();
+ }
+}
+
+/* Relocate an a.out section using standard a.out relocs. */
+
+static boolean
+aout_link_input_section_std (finfo, input_bfd, input_section, relocs,
+ rel_size, contents, symbol_map)
+ struct aout_final_link_info *finfo;
+ bfd *input_bfd;
+ asection *input_section;
+ struct reloc_std_external *relocs;
+ bfd_size_type rel_size;
+ bfd_byte *contents;
+ int *symbol_map;
+{
+ boolean (*check_dynamic_reloc) PARAMS ((struct bfd_link_info *,
+ bfd *, asection *,
+ struct aout_link_hash_entry *,
+ PTR, boolean *));
+ bfd *output_bfd;
+ boolean relocateable;
+ struct external_nlist *syms;
+ char *strings;
+ struct aout_link_hash_entry **sym_hashes;
+ bfd_size_type reloc_count;
+ register struct reloc_std_external *rel;
+ struct reloc_std_external *rel_end;
+
+ output_bfd = finfo->output_bfd;
+ check_dynamic_reloc = aout_backend_info (output_bfd)->check_dynamic_reloc;
+
+ BFD_ASSERT (obj_reloc_entry_size (input_bfd) == RELOC_STD_SIZE);
+ BFD_ASSERT (input_bfd->xvec->header_byteorder_big_p
+ == output_bfd->xvec->header_byteorder_big_p);
+
+ relocateable = finfo->info->relocateable;
+ syms = obj_aout_external_syms (input_bfd);
+ strings = obj_aout_external_strings (input_bfd);
+ sym_hashes = obj_aout_sym_hashes (input_bfd);
+
+ reloc_count = rel_size / RELOC_STD_SIZE;
+ rel = relocs;
+ rel_end = rel + reloc_count;
+ for (; rel < rel_end; rel++)
+ {
+ bfd_vma r_addr;
+ int r_index;
+ int r_extern;
+ int r_pcrel;
+ int r_baserel;
+ int r_jmptable;
+ int r_relative;
+ int r_length;
+ int howto_idx;
+ reloc_howto_type *howto;
+ bfd_vma relocation;
+ bfd_reloc_status_type r;
+
+ r_addr = GET_SWORD (input_bfd, rel->r_address);
+
+#ifdef MY_reloc_howto
+ howto = MY_reloc_howto(input_bfd, rel, r_index, r_extern, r_pcrel);
+#else
+ if (input_bfd->xvec->header_byteorder_big_p)
+ {
+ r_index = ((rel->r_index[0] << 16)
+ | (rel->r_index[1] << 8)
+ | rel->r_index[2]);
+ r_extern = (0 != (rel->r_type[0] & RELOC_STD_BITS_EXTERN_BIG));
+ r_pcrel = (0 != (rel->r_type[0] & RELOC_STD_BITS_PCREL_BIG));
+ r_baserel = (0 != (rel->r_type[0] & RELOC_STD_BITS_BASEREL_BIG));
+ r_jmptable= (0 != (rel->r_type[0] & RELOC_STD_BITS_JMPTABLE_BIG));
+ r_relative= (0 != (rel->r_type[0] & RELOC_STD_BITS_RELATIVE_BIG));
+ r_length = ((rel->r_type[0] & RELOC_STD_BITS_LENGTH_BIG)
+ >> RELOC_STD_BITS_LENGTH_SH_BIG);
+ }
+ else
+ {
+ r_index = ((rel->r_index[2] << 16)
+ | (rel->r_index[1] << 8)
+ | rel->r_index[0]);
+ r_extern = (0 != (rel->r_type[0] & RELOC_STD_BITS_EXTERN_LITTLE));
+ r_pcrel = (0 != (rel->r_type[0] & RELOC_STD_BITS_PCREL_LITTLE));
+ r_baserel = (0 != (rel->r_type[0] & RELOC_STD_BITS_BASEREL_LITTLE));
+ r_jmptable= (0 != (rel->r_type[0] & RELOC_STD_BITS_JMPTABLE_LITTLE));
+ r_relative= (0 != (rel->r_type[0] & RELOC_STD_BITS_RELATIVE_LITTLE));
+ r_length = ((rel->r_type[0] & RELOC_STD_BITS_LENGTH_LITTLE)
+ >> RELOC_STD_BITS_LENGTH_SH_LITTLE);
+ }
+
+ howto_idx = r_length + 4 * r_pcrel + 8 * r_baserel
+ + 16 * r_jmptable + 32 * r_relative;
+ BFD_ASSERT (howto_idx < TABLE_SIZE (howto_table_std));
+ howto = howto_table_std + howto_idx;
+#endif
+
+ if (relocateable)
+ {
+ /* We are generating a relocateable output file, and must
+ modify the reloc accordingly. */
+ if (r_extern)
+ {
+ struct aout_link_hash_entry *h;
+
+ /* If we know the symbol this relocation is against,
+ convert it into a relocation against a section. This
+ is what the native linker does. */
+ h = sym_hashes[r_index];
+ if (h != (struct aout_link_hash_entry *) NULL
+ && h->root.type == bfd_link_hash_defined)
+ {
+ asection *output_section;
+
+ /* Change the r_extern value. */
+ if (output_bfd->xvec->header_byteorder_big_p)
+ rel->r_type[0] &=~ RELOC_STD_BITS_EXTERN_BIG;
+ else
+ rel->r_type[0] &=~ RELOC_STD_BITS_EXTERN_LITTLE;
+
+ /* Compute a new r_index. */
+ output_section = h->root.u.def.section->output_section;
+ if (output_section == obj_textsec (output_bfd))
+ r_index = N_TEXT;
+ else if (output_section == obj_datasec (output_bfd))
+ r_index = N_DATA;
+ else if (output_section == obj_bsssec (output_bfd))
+ r_index = N_BSS;
+ else
+ r_index = N_ABS;
+
+ /* Add the symbol value and the section VMA to the
+ addend stored in the contents. */
+ relocation = (h->root.u.def.value
+ + output_section->vma
+ + h->root.u.def.section->output_offset);
+ }
+ else
+ {
+ /* We must change r_index according to the symbol
+ map. */
+ r_index = symbol_map[r_index];
+
+ if (r_index == -1)
+ {
+ const char *name;
+
+ name = strings + GET_WORD (input_bfd,
+ syms[r_index].e_strx);
+ if (! ((*finfo->info->callbacks->unattached_reloc)
+ (finfo->info, name, input_bfd, input_section,
+ r_addr)))
+ return false;
+ r_index = 0;
+ }
+
+ relocation = 0;
+ }
+
+ /* Write out the new r_index value. */
+ if (output_bfd->xvec->header_byteorder_big_p)
+ {
+ rel->r_index[0] = r_index >> 16;
+ rel->r_index[1] = r_index >> 8;
+ rel->r_index[2] = r_index;
+ }
+ else
+ {
+ rel->r_index[2] = r_index >> 16;
+ rel->r_index[1] = r_index >> 8;
+ rel->r_index[0] = r_index;
+ }
+ }
+ else
+ {
+ asection *section;
+
+ /* This is a relocation against a section. We must
+ adjust by the amount that the section moved. */
+ section = aout_reloc_index_to_section (input_bfd, r_index);
+ relocation = (section->output_section->vma
+ + section->output_offset
+ - section->vma);
+ }
+
+ /* Change the address of the relocation. */
+ PUT_WORD (output_bfd,
+ r_addr + input_section->output_offset,
+ rel->r_address);
+
+ /* Adjust a PC relative relocation by removing the reference
+ to the original address in the section and including the
+ reference to the new address. */
+ if (r_pcrel)
+ relocation -= (input_section->output_section->vma
+ + input_section->output_offset
+ - input_section->vma);
+
+ if (relocation == 0)
+ r = bfd_reloc_ok;
+ else
+ r = _bfd_relocate_contents (howto,
+ input_bfd, relocation,
+ contents + r_addr);
+ }
+ else
+ {
+ /* We are generating an executable, and must do a full
+ relocation. */
+ if (r_extern)
+ {
+ struct aout_link_hash_entry *h;
+
+ h = sym_hashes[r_index];
+
+ if (check_dynamic_reloc != NULL)
+ {
+ boolean skip;
+
+ if (! ((*check_dynamic_reloc)
+ (finfo->info, input_bfd, input_section, h,
+ (PTR) rel, &skip)))
+ return false;
+ if (skip)
+ continue;
+ }
+
+ if (h != (struct aout_link_hash_entry *) NULL
+ && h->root.type == bfd_link_hash_defined)
+ {
+ relocation = (h->root.u.def.value
+ + h->root.u.def.section->output_section->vma
+ + h->root.u.def.section->output_offset);
+ }
+ else if (h != (struct aout_link_hash_entry *) NULL
+ && h->root.type == bfd_link_hash_weak)
+ relocation = 0;
+ else
+ {
+ const char *name;
+
+ name = strings + GET_WORD (input_bfd, syms[r_index].e_strx);
+ if (! ((*finfo->info->callbacks->undefined_symbol)
+ (finfo->info, name, input_bfd, input_section,
+ r_addr)))
+ return false;
+ relocation = 0;
+ }
+ }
+ else
+ {
+ asection *section;
+
+ section = aout_reloc_index_to_section (input_bfd, r_index);
+ relocation = (section->output_section->vma
+ + section->output_offset
+ - section->vma);
+ if (r_pcrel)
+ relocation += input_section->vma;
+ }
+
+ r = _bfd_final_link_relocate (howto,
+ input_bfd, input_section,
+ contents, r_addr, relocation,
+ (bfd_vma) 0);
+ }
+
+ if (r != bfd_reloc_ok)
+ {
+ switch (r)
+ {
+ default:
+ case bfd_reloc_outofrange:
+ abort ();
+ case bfd_reloc_overflow:
+ {
+ const char *name;
+
+ if (r_extern)
+ name = strings + GET_WORD (input_bfd,
+ syms[r_index].e_strx);
+ else
+ {
+ asection *s;
+
+ s = aout_reloc_index_to_section (input_bfd, r_index);
+ name = bfd_section_name (input_bfd, s);
+ }
+ if (! ((*finfo->info->callbacks->reloc_overflow)
+ (finfo->info, name, howto->name,
+ (bfd_vma) 0, input_bfd, input_section, r_addr)))
+ return false;
+ }
+ break;
+ }
+ }
+ }
+
+ return true;
+}
+
+/* Relocate an a.out section using extended a.out relocs. */
+
+static boolean
+aout_link_input_section_ext (finfo, input_bfd, input_section, relocs,
+ rel_size, contents, symbol_map)
+ struct aout_final_link_info *finfo;
+ bfd *input_bfd;
+ asection *input_section;
+ struct reloc_ext_external *relocs;
+ bfd_size_type rel_size;
+ bfd_byte *contents;
+ int *symbol_map;
+{
+ boolean (*check_dynamic_reloc) PARAMS ((struct bfd_link_info *,
+ bfd *, asection *,
+ struct aout_link_hash_entry *,
+ PTR, boolean *));
+ bfd *output_bfd;
+ boolean relocateable;
+ struct external_nlist *syms;
+ char *strings;
+ struct aout_link_hash_entry **sym_hashes;
+ bfd_size_type reloc_count;
+ register struct reloc_ext_external *rel;
+ struct reloc_ext_external *rel_end;
+
+ output_bfd = finfo->output_bfd;
+ check_dynamic_reloc = aout_backend_info (output_bfd)->check_dynamic_reloc;
+
+ BFD_ASSERT (obj_reloc_entry_size (input_bfd) == RELOC_EXT_SIZE);
+ BFD_ASSERT (input_bfd->xvec->header_byteorder_big_p
+ == output_bfd->xvec->header_byteorder_big_p);
+
+ relocateable = finfo->info->relocateable;
+ syms = obj_aout_external_syms (input_bfd);
+ strings = obj_aout_external_strings (input_bfd);
+ sym_hashes = obj_aout_sym_hashes (input_bfd);
+
+ reloc_count = rel_size / RELOC_EXT_SIZE;
+ rel = relocs;
+ rel_end = rel + reloc_count;
+ for (; rel < rel_end; rel++)
+ {
+ bfd_vma r_addr;
+ int r_index;
+ int r_extern;
+ int r_type;
+ bfd_vma r_addend;
+ bfd_vma relocation;
+
+ r_addr = GET_SWORD (input_bfd, rel->r_address);
+
+ if (input_bfd->xvec->header_byteorder_big_p)
+ {
+ r_index = ((rel->r_index[0] << 16)
+ | (rel->r_index[1] << 8)
+ | rel->r_index[2]);
+ r_extern = (0 != (rel->r_type[0] & RELOC_EXT_BITS_EXTERN_BIG));
+ r_type = ((rel->r_type[0] & RELOC_EXT_BITS_TYPE_BIG)
+ >> RELOC_EXT_BITS_TYPE_SH_BIG);
+ }
+ else
+ {
+ r_index = ((rel->r_index[2] << 16)
+ | (rel->r_index[1] << 8)
+ | rel->r_index[0]);
+ r_extern = (0 != (rel->r_type[0] & RELOC_EXT_BITS_EXTERN_LITTLE));
+ r_type = ((rel->r_type[0] & RELOC_EXT_BITS_TYPE_LITTLE)
+ >> RELOC_EXT_BITS_TYPE_SH_LITTLE);
+ }
+
+ r_addend = GET_SWORD (input_bfd, rel->r_addend);
+
+ BFD_ASSERT (r_type >= 0
+ && r_type < TABLE_SIZE (howto_table_ext));
+
+ if (relocateable)
+ {
+ /* We are generating a relocateable output file, and must
+ modify the reloc accordingly. */
+ if (r_extern)
+ {
+ struct aout_link_hash_entry *h;
+
+ /* If we know the symbol this relocation is against,
+ convert it into a relocation against a section. This
+ is what the native linker does. */
+ h = sym_hashes[r_index];
+ if (h != (struct aout_link_hash_entry *) NULL
+ && h->root.type == bfd_link_hash_defined)
+ {
+ asection *output_section;
+
+ /* Change the r_extern value. */
+ if (output_bfd->xvec->header_byteorder_big_p)
+ rel->r_type[0] &=~ RELOC_EXT_BITS_EXTERN_BIG;
+ else
+ rel->r_type[0] &=~ RELOC_EXT_BITS_EXTERN_LITTLE;
+
+ /* Compute a new r_index. */
+ output_section = h->root.u.def.section->output_section;
+ if (output_section == obj_textsec (output_bfd))
+ r_index = N_TEXT;
+ else if (output_section == obj_datasec (output_bfd))
+ r_index = N_DATA;
+ else if (output_section == obj_bsssec (output_bfd))
+ r_index = N_BSS;
+ else
+ r_index = N_ABS;
+
+ /* Add the symbol value and the section VMA to the
+ addend. */
+ relocation = (h->root.u.def.value
+ + output_section->vma
+ + h->root.u.def.section->output_offset);
+
+ /* Now RELOCATION is the VMA of the final
+ destination. If this is a PC relative reloc,
+ then ADDEND is the negative of the source VMA.
+ We want to set ADDEND to the difference between
+ the destination VMA and the source VMA, which
+ means we must adjust RELOCATION by the change in
+ the source VMA. This is done below. */
+ }
+ else
+ {
+ /* We must change r_index according to the symbol
+ map. */
+ r_index = symbol_map[r_index];
+
+ if (r_index == -1)
+ {
+ const char *name;
+
+ name = (strings
+ + GET_WORD (input_bfd, syms[r_index].e_strx));
+ if (! ((*finfo->info->callbacks->unattached_reloc)
+ (finfo->info, name, input_bfd, input_section,
+ r_addr)))
+ return false;
+ r_index = 0;
+ }
+
+ relocation = 0;
+
+ /* If this is a PC relative reloc, then the addend
+ is the negative of the source VMA. We must
+ adjust it by the change in the source VMA. This
+ is done below. */
+ }
+
+ /* Write out the new r_index value. */
+ if (output_bfd->xvec->header_byteorder_big_p)
+ {
+ rel->r_index[0] = r_index >> 16;
+ rel->r_index[1] = r_index >> 8;
+ rel->r_index[2] = r_index;
+ }
+ else
+ {
+ rel->r_index[2] = r_index >> 16;
+ rel->r_index[1] = r_index >> 8;
+ rel->r_index[0] = r_index;
+ }
+ }
+ else
+ {
+ asection *section;
+
+ /* This is a relocation against a section. We must
+ adjust by the amount that the section moved. */
+ section = aout_reloc_index_to_section (input_bfd, r_index);
+ relocation = (section->output_section->vma
+ + section->output_offset
+ - section->vma);
+
+ /* If this is a PC relative reloc, then the addend is
+ the difference in VMA between the destination and the
+ source. We have just adjusted for the change in VMA
+ of the destination, so we must also adjust by the
+ change in VMA of the source. This is done below. */
+ }
+
+ /* As described above, we must always adjust a PC relative
+ reloc by the change in VMA of the source. */
+ if (howto_table_ext[r_type].pc_relative)
+ relocation -= (input_section->output_section->vma
+ + input_section->output_offset
+ - input_section->vma);
+
+ /* Change the addend if necessary. */
+ if (relocation != 0)
+ PUT_WORD (output_bfd, r_addend + relocation, rel->r_addend);
+
+ /* Change the address of the relocation. */
+ PUT_WORD (output_bfd,
+ r_addr + input_section->output_offset,
+ rel->r_address);
+ }
+ else
+ {
+ bfd_reloc_status_type r;
+
+ /* We are generating an executable, and must do a full
+ relocation. */
+ if (r_extern)
+ {
+ struct aout_link_hash_entry *h;
+
+ h = sym_hashes[r_index];
+
+ if (check_dynamic_reloc != NULL)
+ {
+ boolean skip;
+
+ if (! ((*check_dynamic_reloc)
+ (finfo->info, input_bfd, input_section, h,
+ (PTR) rel, &skip)))
+ return false;
+ if (skip)
+ continue;
+ }
+
+ if (h != (struct aout_link_hash_entry *) NULL
+ && h->root.type == bfd_link_hash_defined)
+ {
+ relocation = (h->root.u.def.value
+ + h->root.u.def.section->output_section->vma
+ + h->root.u.def.section->output_offset);
+ }
+ else if (h != (struct aout_link_hash_entry *) NULL
+ && h->root.type == bfd_link_hash_weak)
+ relocation = 0;
+ else
+ {
+ const char *name;
+
+ name = strings + GET_WORD (input_bfd, syms[r_index].e_strx);
+ if (! ((*finfo->info->callbacks->undefined_symbol)
+ (finfo->info, name, input_bfd, input_section,
+ r_addr)))
+ return false;
+ relocation = 0;
+ }
+ }
+ else
+ {
+ asection *section;
+
+ section = aout_reloc_index_to_section (input_bfd, r_index);
+
+ /* If this is a PC relative reloc, then R_ADDEND is the
+ difference between the two vmas, or
+ old_dest_sec + old_dest_off - (old_src_sec + old_src_off)
+ where
+ old_dest_sec == section->vma
+ and
+ old_src_sec == input_section->vma
+ and
+ old_src_off == r_addr
+
+ _bfd_final_link_relocate expects RELOCATION +
+ R_ADDEND to be the VMA of the destination minus
+ r_addr (the minus r_addr is because this relocation
+ is not pcrel_offset, which is a bit confusing and
+ should, perhaps, be changed), or
+ new_dest_sec
+ where
+ new_dest_sec == output_section->vma + output_offset
+ We arrange for this to happen by setting RELOCATION to
+ new_dest_sec + old_src_sec - old_dest_sec
+
+ If this is not a PC relative reloc, then R_ADDEND is
+ simply the VMA of the destination, so we set
+ RELOCATION to the change in the destination VMA, or
+ new_dest_sec - old_dest_sec
+ */
+ relocation = (section->output_section->vma
+ + section->output_offset
+ - section->vma);
+ if (howto_table_ext[r_type].pc_relative)
+ relocation += input_section->vma;
+ }
+
+ r = _bfd_final_link_relocate (howto_table_ext + r_type,
+ input_bfd, input_section,
+ contents, r_addr, relocation,
+ r_addend);
+ if (r != bfd_reloc_ok)
+ {
+ switch (r)
+ {
+ default:
+ case bfd_reloc_outofrange:
+ abort ();
+ case bfd_reloc_overflow:
+ {
+ const char *name;
+
+ if (r_extern)
+ name = strings + GET_WORD (input_bfd,
+ syms[r_index].e_strx);
+ else
+ {
+ asection *s;
+
+ s = aout_reloc_index_to_section (input_bfd, r_index);
+ name = bfd_section_name (input_bfd, s);
+ }
+ if (! ((*finfo->info->callbacks->reloc_overflow)
+ (finfo->info, name, howto_table_ext[r_type].name,
+ r_addend, input_bfd, input_section, r_addr)))
+ return false;
+ }
+ break;
+ }
+ }
+ }
+ }
+
+ return true;
+}
+
+/* Handle a link order which is supposed to generate a reloc. */
+
+static boolean
+aout_link_reloc_link_order (finfo, o, p)
+ struct aout_final_link_info *finfo;
+ asection *o;
+ struct bfd_link_order *p;
+{
+ struct bfd_link_order_reloc *pr;
+ int r_index;
+ int r_extern;
+ const reloc_howto_type *howto;
+ file_ptr *reloff_ptr;
+ struct reloc_std_external srel;
+ struct reloc_ext_external erel;
+ PTR rel_ptr;
+
+ pr = p->u.reloc.p;
+
+ if (p->type == bfd_section_reloc_link_order)
+ {
+ r_extern = 0;
+ if (bfd_is_abs_section (pr->u.section))
+ r_index = N_ABS | N_EXT;
+ else
+ {
+ BFD_ASSERT (pr->u.section->owner == finfo->output_bfd);
+ r_index = pr->u.section->target_index;
+ }
+ }
+ else
+ {
+ struct aout_link_hash_entry *h;
+
+ BFD_ASSERT (p->type == bfd_symbol_reloc_link_order);
+ r_extern = 1;
+ h = aout_link_hash_lookup (aout_hash_table (finfo->info),
+ pr->u.name, false, false, true);
+ if (h != (struct aout_link_hash_entry *) NULL
+ && h->indx == -1)
+ r_index = h->indx;
+ else
+ {
+ if (! ((*finfo->info->callbacks->unattached_reloc)
+ (finfo->info, pr->u.name, (bfd *) NULL,
+ (asection *) NULL, (bfd_vma) 0)))
+ return false;
+ r_index = 0;
+ }
+ }
+
+ howto = bfd_reloc_type_lookup (finfo->output_bfd, pr->reloc);
+ if (howto == (const reloc_howto_type *) NULL)
+ {
+ bfd_set_error (bfd_error_bad_value);
+ return false;
+ }
+
+ if (o == obj_textsec (finfo->output_bfd))
+ reloff_ptr = &finfo->treloff;
+ else if (o == obj_datasec (finfo->output_bfd))
+ reloff_ptr = &finfo->dreloff;
+ else
+ abort ();
+
+ if (obj_reloc_entry_size (finfo->output_bfd) == RELOC_STD_SIZE)
+ {
+ int r_pcrel;
+ int r_baserel;
+ int r_jmptable;
+ int r_relative;
+ int r_length;
+
+#ifdef MY_put_reloc
+ MY_put_reloc(finfo->output_bfd, r_extern, r_index, p->offset, howto, &srel);
+#else
+ r_pcrel = howto->pc_relative;
+ r_baserel = (howto->type & 8) != 0;
+ r_jmptable = (howto->type & 16) != 0;
+ r_relative = (howto->type & 32) != 0;
+ r_length = howto->size;
+
+ PUT_WORD (finfo->output_bfd, p->offset, srel.r_address);
+ if (finfo->output_bfd->xvec->header_byteorder_big_p)
+ {
+ srel.r_index[0] = r_index >> 16;
+ srel.r_index[1] = r_index >> 8;
+ srel.r_index[2] = r_index;
+ srel.r_type[0] =
+ ((r_extern ? RELOC_STD_BITS_EXTERN_BIG : 0)
+ | (r_pcrel ? RELOC_STD_BITS_PCREL_BIG : 0)
+ | (r_baserel ? RELOC_STD_BITS_BASEREL_BIG : 0)
+ | (r_jmptable ? RELOC_STD_BITS_JMPTABLE_BIG : 0)
+ | (r_relative ? RELOC_STD_BITS_RELATIVE_BIG : 0)
+ | (r_length << RELOC_STD_BITS_LENGTH_SH_BIG));
+ }
+ else
+ {
+ srel.r_index[2] = r_index >> 16;
+ srel.r_index[1] = r_index >> 8;
+ srel.r_index[0] = r_index;
+ srel.r_type[0] =
+ ((r_extern ? RELOC_STD_BITS_EXTERN_LITTLE : 0)
+ | (r_pcrel ? RELOC_STD_BITS_PCREL_LITTLE : 0)
+ | (r_baserel ? RELOC_STD_BITS_BASEREL_LITTLE : 0)
+ | (r_jmptable ? RELOC_STD_BITS_JMPTABLE_LITTLE : 0)
+ | (r_relative ? RELOC_STD_BITS_RELATIVE_LITTLE : 0)
+ | (r_length << RELOC_STD_BITS_LENGTH_SH_LITTLE));
+ }
+#endif
+ rel_ptr = (PTR) &srel;
+
+ /* We have to write the addend into the object file, since
+ standard a.out relocs are in place. It would be more
+ reliable if we had the current contents of the file here,
+ rather than assuming zeroes, but we can't read the file since
+ it was opened using bfd_openw. */
+ if (pr->addend != 0)
+ {
+ bfd_size_type size;
+ bfd_reloc_status_type r;
+ bfd_byte *buf;
+ boolean ok;
+
+ size = bfd_get_reloc_size (howto);
+ buf = (bfd_byte *) bfd_zmalloc (size);
+ if (buf == (bfd_byte *) NULL)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ return false;
+ }
+ r = _bfd_relocate_contents (howto, finfo->output_bfd,
+ pr->addend, buf);
+ switch (r)
+ {
+ case bfd_reloc_ok:
+ break;
+ default:
+ case bfd_reloc_outofrange:
+ abort ();
+ case bfd_reloc_overflow:
+ if (! ((*finfo->info->callbacks->reloc_overflow)
+ (finfo->info,
+ (p->type == bfd_section_reloc_link_order
+ ? bfd_section_name (finfo->output_bfd,
+ pr->u.section)
+ : pr->u.name),
+ howto->name, pr->addend, (bfd *) NULL,
+ (asection *) NULL, (bfd_vma) 0)))
+ {
+ free (buf);
+ return false;
+ }
+ break;
+ }
+ ok = bfd_set_section_contents (finfo->output_bfd, o,
+ (PTR) buf,
+ (file_ptr) p->offset,
+ size);
+ free (buf);
+ if (! ok)
+ return false;
+ }
+ }
+ else
+ {
+ PUT_WORD (finfo->output_bfd, p->offset, erel.r_address);
+
+ if (finfo->output_bfd->xvec->header_byteorder_big_p)
+ {
+ erel.r_index[0] = r_index >> 16;
+ erel.r_index[1] = r_index >> 8;
+ erel.r_index[2] = r_index;
+ erel.r_type[0] =
+ ((r_extern ? RELOC_EXT_BITS_EXTERN_BIG : 0)
+ | (howto->type << RELOC_EXT_BITS_TYPE_SH_BIG));
+ }
+ else
+ {
+ erel.r_index[2] = r_index >> 16;
+ erel.r_index[1] = r_index >> 8;
+ erel.r_index[0] = r_index;
+ erel.r_type[0] =
+ (r_extern ? RELOC_EXT_BITS_EXTERN_LITTLE : 0)
+ | (howto->type << RELOC_EXT_BITS_TYPE_SH_LITTLE);
+ }
+
+ PUT_WORD (finfo->output_bfd, pr->addend, erel.r_addend);
+
+ rel_ptr = (PTR) &erel;
+ }
+
+ if (bfd_seek (finfo->output_bfd, *reloff_ptr, SEEK_SET) != 0
+ || (bfd_write (rel_ptr, (bfd_size_type) 1,
+ obj_reloc_entry_size (finfo->output_bfd),
+ finfo->output_bfd)
+ != obj_reloc_entry_size (finfo->output_bfd)))
+ return false;
+
+ *reloff_ptr += obj_reloc_entry_size (finfo->output_bfd);
+
+ /* Assert that the relocs have not run into the symbols, and that n
+ the text relocs have not run into the data relocs. */
+ BFD_ASSERT (*reloff_ptr <= obj_sym_filepos (finfo->output_bfd)
+ && (reloff_ptr != &finfo->treloff
+ || (*reloff_ptr
+ <= obj_datasec (finfo->output_bfd)->rel_filepos)));
+
+ return true;
+}
diff --git a/gnu/usr.bin/gdb/bfd/archive.c b/gnu/usr.bin/gdb/bfd/archive.c
new file mode 100644
index 0000000..a91b496
--- /dev/null
+++ b/gnu/usr.bin/gdb/bfd/archive.c
@@ -0,0 +1,2016 @@
+/* BFD back-end for archive files (libraries).
+ Copyright 1990, 91, 92, 93, 94 Free Software Foundation, Inc.
+ Written by Cygnus Support. Mostly Gumby Henkel-Wallace's fault.
+
+This file is part of BFD, the Binary File Descriptor library.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/*
+@setfilename archive-info
+SECTION
+ Archives
+
+DESCRIPTION
+ An archive (or library) is just another BFD. It has a symbol
+ table, although there's not much a user program will do with it.
+
+ The big difference between an archive BFD and an ordinary BFD
+ is that the archive doesn't have sections. Instead it has a
+ chain of BFDs that are considered its contents. These BFDs can
+ be manipulated like any other. The BFDs contained in an
+ archive opened for reading will all be opened for reading. You
+ may put either input or output BFDs into an archive opened for
+ output; they will be handled correctly when the archive is closed.
+
+ Use <<bfd_openr_next_archived_file>> to step through
+ the contents of an archive opened for input. You don't
+ have to read the entire archive if you don't want
+ to! Read it until you find what you want.
+
+ Archive contents of output BFDs are chained through the
+ <<next>> pointer in a BFD. The first one is findable through
+ the <<archive_head>> slot of the archive. Set it with
+ <<bfd_set_archive_head>> (q.v.). A given BFD may be in only one
+ open output archive at a time.
+
+ As expected, the BFD archive code is more general than the
+ archive code of any given environment. BFD archives may
+ contain files of different formats (e.g., a.out and coff) and
+ even different architectures. You may even place archives
+ recursively into archives!
+
+ This can cause unexpected confusion, since some archive
+ formats are more expressive than others. For instance, Intel
+ COFF archives can preserve long filenames; SunOS a.out archives
+ cannot. If you move a file from the first to the second
+ format and back again, the filename may be truncated.
+ Likewise, different a.out environments have different
+ conventions as to how they truncate filenames, whether they
+ preserve directory names in filenames, etc. When
+ interoperating with native tools, be sure your files are
+ homogeneous.
+
+ Beware: most of these formats do not react well to the
+ presence of spaces in filenames. We do the best we can, but
+ can't always handle this case due to restrictions in the format of
+ archives. Many Unix utilities are braindead in regards to
+ spaces and such in filenames anyway, so this shouldn't be much
+ of a restriction.
+
+ Archives are supported in BFD in <<archive.c>>.
+
+*/
+
+/* Assumes:
+ o - all archive elements start on an even boundary, newline padded;
+ o - all arch headers are char *;
+ o - all arch headers are the same size (across architectures).
+*/
+
+/* Some formats provide a way to cram a long filename into the short
+ (16 chars) space provided by a BSD archive. The trick is: make a
+ special "file" in the front of the archive, sort of like the SYMDEF
+ entry. If the filename is too long to fit, put it in the extended
+ name table, and use its index as the filename. To prevent
+ confusion prepend the index with a space. This means you can't
+ have filenames that start with a space, but then again, many Unix
+ utilities can't handle that anyway.
+
+ This scheme unfortunately requires that you stand on your head in
+ order to write an archive since you need to put a magic file at the
+ front, and need to touch every entry to do so. C'est la vie.
+
+ We support two variants of this idea:
+ The SVR4 format (extended name table is named "//"),
+ and an extended pseudo-BSD variant (extended name table is named
+ "ARFILENAMES/"). The origin of the latter format is uncertain.
+
+ BSD 4.4 uses a third scheme: It writes a long filename
+ directly after the header. This allows 'ar q' to work.
+ We currently can read BSD 4.4 archives, but not write them.
+*/
+
+/* Summary of archive member names:
+
+ Symbol table (must be first):
+ "__.SYMDEF " - Symbol table, Berkeley style, produced by ranlib.
+ "/ " - Symbol table, system 5 style.
+
+ Long name table (must be before regular file members):
+ "// " - Long name table, System 5 R4 style.
+ "ARFILENAMES/ " - Long name table, non-standard extended BSD (not BSD 4.4).
+
+ Regular file members with short names:
+ "filename.o/ " - Regular file, System 5 style (embedded spaces ok).
+ "filename.o " - Regular file, Berkeley style (no embedded spaces).
+
+ Regular files with long names (or embedded spaces, for BSD variants):
+ "/18 " - SVR4 style, name at offset 18 in name table.
+ "#1/23 " - Long name (or embedded paces) 23 characters long,
+ BSD 4.4 style, full name follows header.
+ Implemented for reading, not writing.
+ " 18 " - Long name 18 characters long, extended pseudo-BSD.
+ */
+
+#include "bfd.h"
+#include "sysdep.h"
+#include "libbfd.h"
+#include "aout/ar.h"
+#include "aout/ranlib.h"
+#include <errno.h>
+#include <string.h> /* For memchr, strrchr and friends */
+#include <ctype.h>
+
+#ifndef errno
+extern int errno;
+#endif
+
+#ifdef GNU960
+#define BFD_GNU960_ARMAG(abfd) (BFD_COFF_FILE_P((abfd)) ? ARMAG : ARMAGB)
+#endif
+
+/* Can't define this in hosts/foo.h, because (e.g. in gprof) the hosts file
+ is included, then obstack.h, which thinks if offsetof is defined, it
+ doesn't need to include stddef.h. */
+/* Define offsetof for those systems which lack it */
+
+#if !defined (offsetof)
+#define offsetof(TYPE, MEMBER) ((unsigned long) &((TYPE *)0)->MEMBER)
+#endif
+
+/* We keep a cache of archive filepointers to archive elements to
+ speed up searching the archive by filepos. We only add an entry to
+ the cache when we actually read one. We also don't sort the cache;
+ it's generally short enough to search linearly.
+ Note that the pointers here point to the front of the ar_hdr, not
+ to the front of the contents!
+*/
+struct ar_cache
+{
+ file_ptr ptr;
+ bfd *arelt;
+ struct ar_cache *next;
+};
+
+#define ar_padchar(abfd) ((abfd)->xvec->ar_pad_char)
+#define ar_maxnamelen(abfd) ((abfd)->xvec->ar_max_namelen)
+
+#define arch_eltdata(bfd) ((struct areltdata *)((bfd)->arelt_data))
+#define arch_hdr(bfd) ((struct ar_hdr *)arch_eltdata(bfd)->arch_header)
+
+static char *get_extended_arelt_filename PARAMS ((bfd *arch,
+ const char *name));
+static boolean do_slurp_bsd_armap PARAMS ((bfd *abfd));
+static boolean do_slurp_coff_armap PARAMS ((bfd *abfd));
+static const char *normalize PARAMS ((const char *file));
+static boolean bfd_construct_extended_name_table PARAMS ((bfd *abfd,
+ char **tabloc,
+ unsigned int *));
+static struct areltdata *bfd_ar_hdr_from_filesystem PARAMS ((bfd *abfd,
+ const char *));
+static boolean compute_and_write_armap PARAMS ((bfd *arch,
+ unsigned int elength));
+static boolean bsd_update_armap_timestamp PARAMS ((bfd *arch));
+
+boolean
+_bfd_generic_mkarchive (abfd)
+ bfd *abfd;
+{
+ abfd->tdata.aout_ar_data = ((struct artdata *)
+ bfd_zalloc (abfd, sizeof (struct artdata)));
+
+ if (bfd_ardata (abfd) == NULL)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ return false;
+ }
+
+ bfd_ardata (abfd)->cache = NULL;
+ bfd_ardata (abfd)->archive_head = NULL;
+ bfd_ardata (abfd)->symdefs = NULL;
+ bfd_ardata (abfd)->extended_names = NULL;
+ bfd_ardata (abfd)->tdata = NULL;
+
+ return true;
+}
+
+/*
+FUNCTION
+ bfd_get_next_mapent
+
+SYNOPSIS
+ symindex bfd_get_next_mapent(bfd *abfd, symindex previous, carsym **sym);
+
+DESCRIPTION
+ Step through archive @var{abfd}'s symbol table (if it
+ has one). Successively update @var{sym} with the next symbol's
+ information, returning that symbol's (internal) index into the
+ symbol table.
+
+ Supply <<BFD_NO_MORE_SYMBOLS>> as the @var{previous} entry to get
+ the first one; returns <<BFD_NO_MORE_SYMBOLS>> when you've already
+ got the last one.
+
+ A <<carsym>> is a canonical archive symbol. The only
+ user-visible element is its name, a null-terminated string.
+*/
+
+symindex
+bfd_get_next_mapent (abfd, prev, entry)
+ bfd *abfd;
+ symindex prev;
+ carsym **entry;
+{
+ if (!bfd_has_map (abfd))
+ {
+ bfd_set_error (bfd_error_invalid_operation);
+ return BFD_NO_MORE_SYMBOLS;
+ }
+
+ if (prev == BFD_NO_MORE_SYMBOLS)
+ prev = 0;
+ else if (++prev >= bfd_ardata (abfd)->symdef_count)
+ return BFD_NO_MORE_SYMBOLS;
+
+ *entry = (bfd_ardata (abfd)->symdefs + prev);
+ return prev;
+}
+
+/* To be called by backends only */
+
+bfd *
+_bfd_create_empty_archive_element_shell (obfd)
+ bfd *obfd;
+{
+ bfd *nbfd;
+
+ nbfd = _bfd_new_bfd_contained_in (obfd);
+ if (nbfd == NULL)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ return NULL;
+ }
+ return nbfd;
+}
+
+/*
+FUNCTION
+ bfd_set_archive_head
+
+SYNOPSIS
+ boolean bfd_set_archive_head(bfd *output, bfd *new_head);
+
+DESCRIPTION
+ Set the head of the chain of
+ BFDs contained in the archive @var{output} to @var{new_head}.
+*/
+
+boolean
+bfd_set_archive_head (output_archive, new_head)
+ bfd *output_archive;
+ bfd *new_head;
+{
+
+ output_archive->archive_head = new_head;
+ return true;
+}
+
+bfd *
+_bfd_look_for_bfd_in_cache (arch_bfd, filepos)
+ bfd *arch_bfd;
+ file_ptr filepos;
+{
+ struct ar_cache *current;
+
+ for (current = bfd_ardata (arch_bfd)->cache; current != NULL;
+ current = current->next)
+ if (current->ptr == filepos)
+ return current->arelt;
+
+ return NULL;
+}
+
+/* Kind of stupid to call cons for each one, but we don't do too many */
+boolean
+_bfd_add_bfd_to_archive_cache (arch_bfd, filepos, new_elt)
+ bfd *arch_bfd, *new_elt;
+ file_ptr filepos;
+{
+ struct ar_cache *new_cache = ((struct ar_cache *)
+ bfd_zalloc (arch_bfd,
+ sizeof (struct ar_cache)));
+
+ if (new_cache == NULL)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ return false;
+ }
+
+ new_cache->ptr = filepos;
+ new_cache->arelt = new_elt;
+ new_cache->next = (struct ar_cache *) NULL;
+ if (bfd_ardata (arch_bfd)->cache == NULL)
+ bfd_ardata (arch_bfd)->cache = new_cache;
+ else
+ {
+ struct ar_cache *current = bfd_ardata (arch_bfd)->cache;
+
+ while (current->next != NULL)
+ current = current->next;
+ current->next = new_cache;
+ }
+
+ return true;
+}
+
+/* The name begins with space. Hence the rest of the name is an index into
+ the string table. */
+
+static char *
+get_extended_arelt_filename (arch, name)
+ bfd *arch;
+ const char *name;
+{
+ unsigned long index = 0;
+
+ /* Should extract string so that I can guarantee not to overflow into
+ the next region, but I'm too lazy. */
+ errno = 0;
+ /* Skip first char, which is '/' in SVR4 or ' ' in some other variants. */
+ index = strtol (name + 1, NULL, 10);
+ if (errno != 0)
+ {
+ bfd_set_error (bfd_error_malformed_archive);
+ return NULL;
+ }
+
+ return bfd_ardata (arch)->extended_names + index;
+}
+
+/* This functions reads an arch header and returns an areltdata pointer, or
+ NULL on error.
+
+ Presumes the file pointer is already in the right place (ie pointing
+ to the ar_hdr in the file). Moves the file pointer; on success it
+ should be pointing to the front of the file contents; on failure it
+ could have been moved arbitrarily.
+*/
+
+struct areltdata *
+_bfd_snarf_ar_hdr (abfd)
+ bfd *abfd;
+{
+#ifndef errno
+ extern int errno;
+#endif
+
+ struct ar_hdr hdr;
+ char *hdrp = (char *) &hdr;
+ unsigned int parsed_size;
+ struct areltdata *ared;
+ char *filename = NULL;
+ unsigned int namelen = 0;
+ unsigned int allocsize = sizeof (struct areltdata) + sizeof (struct ar_hdr);
+ char *allocptr = 0;
+
+ if (bfd_read ((PTR) hdrp, 1, sizeof (struct ar_hdr), abfd)
+ != sizeof (struct ar_hdr))
+ {
+ if (bfd_get_error () != bfd_error_system_call)
+ bfd_set_error (bfd_error_no_more_archived_files);
+ return NULL;
+ }
+ if (strncmp (hdr.ar_fmag, ARFMAG, 2))
+ {
+ bfd_set_error (bfd_error_malformed_archive);
+ return NULL;
+ }
+
+ errno = 0;
+ parsed_size = strtol (hdr.ar_size, NULL, 10);
+ if (errno != 0)
+ {
+ bfd_set_error (bfd_error_malformed_archive);
+ return NULL;
+ }
+
+ /* Extract the filename from the archive - there are two ways to
+ specify an extendend name table, either the first char of the
+ name is a space, or it's a slash. */
+ if ((hdr.ar_name[0] == '/'
+ || (hdr.ar_name[0] == ' '
+ && memchr (hdr.ar_name, '/', ar_maxnamelen (abfd)) == NULL))
+ && bfd_ardata (abfd)->extended_names != NULL)
+ {
+ filename = get_extended_arelt_filename (abfd, hdr.ar_name);
+ if (filename == NULL)
+ {
+ bfd_set_error (bfd_error_malformed_archive);
+ return NULL;
+ }
+ }
+ /* BSD4.4-style long filename.
+ Only implemented for reading, so far! */
+ else if (hdr.ar_name[0] == '#' && hdr.ar_name[1] == '1'
+ && hdr.ar_name[2] == '/' && isdigit (hdr.ar_name[3]))
+ {
+ /* BSD-4.4 extended name */
+ namelen = atoi (&hdr.ar_name[3]);
+ allocsize += namelen + 1;
+ parsed_size -= namelen;
+
+ allocptr = bfd_zalloc (abfd, allocsize);
+ if (allocptr == NULL)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ return NULL;
+ }
+ filename = (allocptr
+ + sizeof (struct areltdata)
+ + sizeof (struct ar_hdr));
+ if (bfd_read (filename, 1, namelen, abfd) != namelen)
+ {
+ if (bfd_get_error () != bfd_error_system_call)
+ bfd_set_error (bfd_error_no_more_archived_files);
+ return NULL;
+ }
+ filename[namelen] = '\0';
+ }
+ else
+ {
+ /* We judge the end of the name by looking for '/' or ' '.
+ Note: The SYSV format (terminated by '/') allows embedded
+ spaces, so only look for ' ' if we don't find '/'. */
+
+ namelen = 0;
+ while (hdr.ar_name[namelen] != '\0' &&
+ hdr.ar_name[namelen] != '/')
+ {
+ namelen++;
+ if (namelen == (unsigned) ar_maxnamelen (abfd))
+ {
+ namelen = 0;
+ while (hdr.ar_name[namelen] != ' '
+ && namelen < (unsigned) ar_maxnamelen (abfd))
+ namelen++;
+ break;
+ }
+ }
+
+ allocsize += namelen + 1;
+ }
+
+ if (!allocptr)
+ {
+ allocptr = bfd_zalloc (abfd, allocsize);
+ if (allocptr == NULL)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ return NULL;
+ }
+ }
+
+ ared = (struct areltdata *) allocptr;
+
+ ared->arch_header = allocptr + sizeof (struct areltdata);
+ memcpy ((char *) ared->arch_header, (char *) &hdr, sizeof (struct ar_hdr));
+ ared->parsed_size = parsed_size;
+
+ if (filename != NULL)
+ ared->filename = filename;
+ else
+ {
+ ared->filename = allocptr + (sizeof (struct areltdata) +
+ sizeof (struct ar_hdr));
+ if (namelen)
+ memcpy (ared->filename, hdr.ar_name, namelen);
+ ared->filename[namelen] = '\0';
+ }
+
+ return ared;
+}
+
+/* This is an internal function; it's mainly used when indexing
+ through the archive symbol table, but also used to get the next
+ element, since it handles the bookkeeping so nicely for us. */
+
+bfd *
+_bfd_get_elt_at_filepos (archive, filepos)
+ bfd *archive;
+ file_ptr filepos;
+{
+ struct areltdata *new_areldata;
+ bfd *n_nfd;
+
+ n_nfd = _bfd_look_for_bfd_in_cache (archive, filepos);
+ if (n_nfd)
+ return n_nfd;
+
+ if (0 > bfd_seek (archive, filepos, SEEK_SET))
+ return NULL;
+
+ if ((new_areldata = _bfd_snarf_ar_hdr (archive)) == NULL)
+ return NULL;
+
+ n_nfd = _bfd_create_empty_archive_element_shell (archive);
+ if (n_nfd == NULL)
+ {
+ bfd_release (archive, (PTR) new_areldata);
+ return NULL;
+ }
+
+ n_nfd->origin = bfd_tell (archive);
+ n_nfd->arelt_data = (PTR) new_areldata;
+ n_nfd->filename = new_areldata->filename;
+
+ if (_bfd_add_bfd_to_archive_cache (archive, filepos, n_nfd))
+ return n_nfd;
+
+ /* huh? */
+ bfd_release (archive, (PTR) n_nfd);
+ bfd_release (archive, (PTR) new_areldata);
+ return NULL;
+}
+
+/*
+FUNCTION
+ bfd_get_elt_at_index
+
+SYNOPSIS
+ bfd *bfd_get_elt_at_index(bfd *archive, int index);
+
+DESCRIPTION
+ Return the BFD which is referenced by the symbol in @var{archive}
+ indexed by @var{index}. @var{index} should have been returned by
+ <<bfd_get_next_mapent>> (q.v.).
+
+*/
+bfd *
+bfd_get_elt_at_index (abfd, index)
+ bfd *abfd;
+ int index;
+{
+ carsym *entry;
+
+ entry = bfd_ardata (abfd)->symdefs + index;
+ return _bfd_get_elt_at_filepos (abfd, entry->file_offset);
+}
+
+/*
+FUNCTION
+ bfd_openr_next_archived_file
+
+SYNOPSIS
+ bfd *bfd_openr_next_archived_file(bfd *archive, bfd *previous);
+
+DESCRIPTION
+ Provided a BFD, @var{archive}, containing an archive and NULL, open
+ an input BFD on the first contained element and returns that.
+ Subsequent calls should pass
+ the archive and the previous return value to return a created
+ BFD to the next contained element. NULL is returned when there
+ are no more.
+
+*/
+
+bfd *
+bfd_openr_next_archived_file (archive, last_file)
+ bfd *archive;
+ bfd *last_file;
+{
+ if ((bfd_get_format (archive) != bfd_archive) ||
+ (archive->direction == write_direction))
+ {
+ bfd_set_error (bfd_error_invalid_operation);
+ return NULL;
+ }
+
+ return BFD_SEND (archive,
+ openr_next_archived_file,
+ (archive,
+ last_file));
+}
+
+bfd *
+bfd_generic_openr_next_archived_file (archive, last_file)
+ bfd *archive;
+ bfd *last_file;
+{
+ file_ptr filestart;
+
+ if (!last_file)
+ filestart = bfd_ardata (archive)->first_file_filepos;
+ else
+ {
+ unsigned int size = arelt_size (last_file);
+ /* Pad to an even boundary...
+ Note that last_file->origin can be odd in the case of
+ BSD-4.4-style element with a long odd size. */
+ filestart = last_file->origin + size;
+ filestart += filestart % 2;
+ }
+
+ return _bfd_get_elt_at_filepos (archive, filestart);
+}
+
+
+const bfd_target *
+bfd_generic_archive_p (abfd)
+ bfd *abfd;
+{
+ char armag[SARMAG + 1];
+
+ if (bfd_read ((PTR) armag, 1, SARMAG, abfd) != SARMAG)
+ {
+ if (bfd_get_error () != bfd_error_system_call)
+ bfd_set_error (bfd_error_wrong_format);
+ return NULL;
+ }
+
+#ifdef GNU960
+ if (strncmp (armag, BFD_GNU960_ARMAG (abfd), SARMAG) != 0)
+ return 0;
+#else
+ if (strncmp (armag, ARMAG, SARMAG) != 0 &&
+ strncmp (armag, ARMAGB, SARMAG) != 0)
+ return 0;
+#endif
+
+ /* We are setting bfd_ardata(abfd) here, but since bfd_ardata
+ involves a cast, we can't do it as the left operand of assignment. */
+ abfd->tdata.aout_ar_data = ((struct artdata *)
+ bfd_zalloc (abfd, sizeof (struct artdata)));
+
+ if (bfd_ardata (abfd) == NULL)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ return NULL;
+ }
+
+ bfd_ardata (abfd)->first_file_filepos = SARMAG;
+ bfd_ardata (abfd)->cache = NULL;
+ bfd_ardata (abfd)->archive_head = NULL;
+ bfd_ardata (abfd)->symdefs = NULL;
+ bfd_ardata (abfd)->extended_names = NULL;
+ bfd_ardata (abfd)->tdata = NULL;
+
+ if (!BFD_SEND (abfd, _bfd_slurp_armap, (abfd)))
+ {
+ bfd_release (abfd, bfd_ardata (abfd));
+ abfd->tdata.aout_ar_data = NULL;
+ return NULL;
+ }
+
+ if (!BFD_SEND (abfd, _bfd_slurp_extended_name_table, (abfd)))
+ {
+ bfd_release (abfd, bfd_ardata (abfd));
+ abfd->tdata.aout_ar_data = NULL;
+ return NULL;
+ }
+
+ return abfd->xvec;
+}
+
+/* Some constants for a 32 bit BSD archive structure. We do not
+ support 64 bit archives presently; so far as I know, none actually
+ exist. Supporting them would require changing these constants, and
+ changing some bfd_h_get_32 to bfd_h_get_64. */
+
+/* The size of an external symdef structure. */
+#define BSD_SYMDEF_SIZE 8
+
+/* The offset from the start of a symdef structure to the file offset. */
+#define BSD_SYMDEF_OFFSET_SIZE 4
+
+/* The size of the symdef count. */
+#define BSD_SYMDEF_COUNT_SIZE 4
+
+/* The size of the string count. */
+#define BSD_STRING_COUNT_SIZE 4
+
+/* Returns false on error, true otherwise */
+
+static boolean
+do_slurp_bsd_armap (abfd)
+ bfd *abfd;
+{
+ struct areltdata *mapdata;
+ unsigned int counter;
+ bfd_byte *raw_armap, *rbase;
+ struct artdata *ardata = bfd_ardata (abfd);
+ char *stringbase;
+ unsigned int parsed_size;
+ carsym *set;
+
+ mapdata = _bfd_snarf_ar_hdr (abfd);
+ if (mapdata == NULL)
+ return false;
+ parsed_size = mapdata->parsed_size;
+ bfd_release (abfd, (PTR) mapdata); /* Don't need it any more. */
+
+ raw_armap = (bfd_byte *) bfd_zalloc (abfd, parsed_size);
+ if (raw_armap == (bfd_byte *) NULL)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ return false;
+ }
+
+ if (bfd_read ((PTR) raw_armap, 1, parsed_size, abfd) != parsed_size)
+ {
+ if (bfd_get_error () != bfd_error_system_call)
+ bfd_set_error (bfd_error_malformed_archive);
+ byebye:
+ bfd_release (abfd, (PTR) raw_armap);
+ return false;
+ }
+
+ ardata->symdef_count = bfd_h_get_32 (abfd, raw_armap) / BSD_SYMDEF_SIZE;
+
+ if (ardata->symdef_count * BSD_SYMDEF_SIZE >
+ parsed_size - BSD_SYMDEF_COUNT_SIZE)
+ {
+ /* Probably we're using the wrong byte ordering. */
+ bfd_set_error (bfd_error_wrong_format);
+ goto byebye;
+ }
+
+ ardata->cache = 0;
+ rbase = raw_armap + BSD_SYMDEF_COUNT_SIZE;
+ stringbase = ((char *) rbase
+ + ardata->symdef_count * BSD_SYMDEF_SIZE
+ + BSD_STRING_COUNT_SIZE);
+ ardata->symdefs = (carsym *) bfd_alloc (abfd,
+ (ardata->symdef_count
+ * sizeof (carsym)));
+ if (!ardata->symdefs)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ return false;
+ }
+
+ for (counter = 0, set = ardata->symdefs;
+ counter < ardata->symdef_count;
+ counter++, set++, rbase += BSD_SYMDEF_SIZE)
+ {
+ set->name = bfd_h_get_32 (abfd, rbase) + stringbase;
+ set->file_offset = bfd_h_get_32 (abfd, rbase + BSD_SYMDEF_OFFSET_SIZE);
+ }
+
+ ardata->first_file_filepos = bfd_tell (abfd);
+ /* Pad to an even boundary if you have to */
+ ardata->first_file_filepos += (ardata->first_file_filepos) % 2;
+ /* FIXME, we should provide some way to free raw_ardata when
+ we are done using the strings from it. For now, it seems
+ to be allocated on an obstack anyway... */
+ bfd_has_map (abfd) = true;
+ return true;
+}
+
+/* Returns false on error, true otherwise */
+static boolean
+do_slurp_coff_armap (abfd)
+ bfd *abfd;
+{
+ struct areltdata *mapdata;
+ int *raw_armap, *rawptr;
+ struct artdata *ardata = bfd_ardata (abfd);
+ char *stringbase;
+ unsigned int stringsize;
+ unsigned int parsed_size;
+ carsym *carsyms;
+ unsigned int nsymz; /* Number of symbols in armap. */
+ bfd_vma (*swap) PARAMS ((const bfd_byte *));
+ char int_buf[sizeof (long)];
+ unsigned int carsym_size, ptrsize, i;
+
+ mapdata = _bfd_snarf_ar_hdr (abfd);
+ if (mapdata == NULL)
+ return false;
+ parsed_size = mapdata->parsed_size;
+ bfd_release (abfd, (PTR) mapdata); /* Don't need it any more. */
+
+ if (bfd_read ((PTR) int_buf, 1, 4, abfd) != 4)
+ {
+ if (bfd_get_error () != bfd_error_system_call)
+ bfd_set_error (bfd_error_malformed_archive);
+ return false;
+ }
+ /* It seems that all numeric information in a coff archive is always
+ in big endian format, nomatter the host or target. */
+ swap = bfd_getb32;
+ nsymz = bfd_getb32 ((PTR) int_buf);
+ stringsize = parsed_size - (4 * nsymz) - 4;
+
+#if 1
+ /* ... except that some archive formats are broken, and it may be our
+ fault - the i960 little endian coff sometimes has big and sometimes
+ little, because our tools changed. Here's a horrible hack to clean
+ up the crap. */
+
+ if (stringsize > 0xfffff)
+ {
+ /* This looks dangerous, let's do it the other way around */
+ nsymz = bfd_getl32 ((PTR) int_buf);
+ stringsize = parsed_size - (4 * nsymz) - 4;
+ swap = bfd_getl32;
+ }
+#endif
+
+ /* The coff armap must be read sequentially. So we construct a
+ bsd-style one in core all at once, for simplicity. */
+
+ carsym_size = (nsymz * sizeof (carsym));
+ ptrsize = (4 * nsymz);
+
+ ardata->symdefs = (carsym *) bfd_zalloc (abfd, carsym_size + stringsize + 1);
+ if (ardata->symdefs == NULL)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ return false;
+ }
+ carsyms = ardata->symdefs;
+ stringbase = ((char *) ardata->symdefs) + carsym_size;
+
+ /* Allocate and read in the raw offsets. */
+ raw_armap = (int *) bfd_alloc (abfd, ptrsize);
+ if (raw_armap == NULL)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ goto release_symdefs;
+ }
+ if (bfd_read ((PTR) raw_armap, 1, ptrsize, abfd) != ptrsize
+ || bfd_read ((PTR) stringbase, 1, stringsize, abfd) != stringsize)
+ {
+ if (bfd_get_error () != bfd_error_system_call)
+ bfd_set_error (bfd_error_malformed_archive);
+ goto release_raw_armap;
+ }
+
+ /* OK, build the carsyms */
+ for (i = 0; i < nsymz; i++)
+ {
+ rawptr = raw_armap + i;
+ carsyms->file_offset = swap ((PTR) rawptr);
+ carsyms->name = stringbase;
+ stringbase += strlen (stringbase) + 1;
+ carsyms++;
+ }
+ *stringbase = 0;
+
+ ardata->symdef_count = nsymz;
+ ardata->first_file_filepos = bfd_tell (abfd);
+ /* Pad to an even boundary if you have to */
+ ardata->first_file_filepos += (ardata->first_file_filepos) % 2;
+
+ bfd_has_map (abfd) = true;
+ bfd_release (abfd, (PTR) raw_armap);
+ return true;
+
+release_raw_armap:
+ bfd_release (abfd, (PTR) raw_armap);
+release_symdefs:
+ bfd_release (abfd, (PTR) (ardata)->symdefs);
+ return false;
+}
+
+/* This routine can handle either coff-style or bsd-style armaps.
+ Returns false on error, true otherwise */
+
+boolean
+bfd_slurp_armap (abfd)
+ bfd *abfd;
+{
+ char nextname[17];
+ int i = bfd_read ((PTR) nextname, 1, 16, abfd);
+
+ if (i == 0)
+ return true;
+ if (i != 16)
+ return false;
+
+ if (bfd_seek (abfd, (file_ptr) - 16, SEEK_CUR) != 0)
+ return false;
+
+ if (!strncmp (nextname, "__.SYMDEF ", 16)
+ || !strncmp (nextname, "__.SYMDEF/ ", 16)) /* old Linux archives */
+ return do_slurp_bsd_armap (abfd);
+ else if (!strncmp (nextname, "/ ", 16))
+ return do_slurp_coff_armap (abfd);
+
+ bfd_has_map (abfd) = false;
+ return true;
+}
+
+/* Returns false on error, true otherwise */
+/* flavor 2 of a bsd armap, similar to bfd_slurp_bsd_armap except the
+ header is in a slightly different order and the map name is '/'.
+ This flavour is used by hp300hpux. */
+
+#define HPUX_SYMDEF_COUNT_SIZE 2
+
+boolean
+bfd_slurp_bsd_armap_f2 (abfd)
+ bfd *abfd;
+{
+ struct areltdata *mapdata;
+ char nextname[17];
+ unsigned int counter;
+ bfd_byte *raw_armap, *rbase;
+ struct artdata *ardata = bfd_ardata (abfd);
+ char *stringbase;
+ unsigned int stringsize;
+ carsym *set;
+ int i = bfd_read ((PTR) nextname, 1, 16, abfd);
+
+ if (i == 0)
+ return true;
+ if (i != 16)
+ return false;
+
+ /* The archive has at least 16 bytes in it */
+ if (bfd_seek (abfd, -16L, SEEK_CUR) != 0)
+ return false;
+
+ if (!strncmp (nextname, "__.SYMDEF ", 16)
+ || !strncmp (nextname, "__.SYMDEF/ ", 16)) /* old Linux archives */
+ return do_slurp_bsd_armap (abfd);
+
+ if (strncmp (nextname, "/ ", 16))
+ {
+ bfd_has_map (abfd) = false;
+ return true;
+ }
+
+ mapdata = _bfd_snarf_ar_hdr (abfd);
+ if (mapdata == NULL)
+ return false;
+
+ raw_armap = (bfd_byte *) bfd_zalloc (abfd, mapdata->parsed_size);
+ if (raw_armap == NULL)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ byebye:
+ bfd_release (abfd, (PTR) mapdata);
+ return false;
+ }
+
+ if (bfd_read ((PTR) raw_armap, 1, mapdata->parsed_size, abfd) !=
+ mapdata->parsed_size)
+ {
+ if (bfd_get_error () != bfd_error_system_call)
+ bfd_set_error (bfd_error_malformed_archive);
+ byebyebye:
+ bfd_release (abfd, (PTR) raw_armap);
+ goto byebye;
+ }
+
+ ardata->symdef_count = bfd_h_get_16 (abfd, (PTR) raw_armap);
+
+ if (ardata->symdef_count * BSD_SYMDEF_SIZE
+ > mapdata->parsed_size - HPUX_SYMDEF_COUNT_SIZE)
+ {
+ /* Probably we're using the wrong byte ordering. */
+ bfd_set_error (bfd_error_wrong_format);
+ goto byebyebye;
+ }
+
+ ardata->cache = 0;
+
+ stringsize = bfd_h_get_32 (abfd, raw_armap + HPUX_SYMDEF_COUNT_SIZE);
+ /* skip sym count and string sz */
+ stringbase = ((char *) raw_armap
+ + HPUX_SYMDEF_COUNT_SIZE
+ + BSD_STRING_COUNT_SIZE);
+ rbase = (bfd_byte *) stringbase + stringsize;
+ ardata->symdefs = (carsym *) bfd_alloc (abfd,
+ (ardata->symdef_count
+ * BSD_SYMDEF_SIZE));
+ if (!ardata->symdefs)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ return false;
+ }
+
+ for (counter = 0, set = ardata->symdefs;
+ counter < ardata->symdef_count;
+ counter++, set++, rbase += BSD_SYMDEF_SIZE)
+ {
+ set->name = bfd_h_get_32 (abfd, rbase) + stringbase;
+ set->file_offset = bfd_h_get_32 (abfd, rbase + BSD_SYMDEF_OFFSET_SIZE);
+ }
+
+ ardata->first_file_filepos = bfd_tell (abfd);
+ /* Pad to an even boundary if you have to */
+ ardata->first_file_filepos += (ardata->first_file_filepos) % 2;
+ /* FIXME, we should provide some way to free raw_ardata when
+ we are done using the strings from it. For now, it seems
+ to be allocated on an obstack anyway... */
+ bfd_has_map (abfd) = true;
+ return true;
+}
+
+/** Extended name table.
+
+ Normally archives support only 14-character filenames.
+
+ Intel has extended the format: longer names are stored in a special
+ element (the first in the archive, or second if there is an armap);
+ the name in the ar_hdr is replaced by <space><index into filename
+ element>. Index is the P.R. of an int (decimal). Data General have
+ extended the format by using the prefix // for the special element */
+
+/* Returns false on error, true otherwise */
+boolean
+_bfd_slurp_extended_name_table (abfd)
+ bfd *abfd;
+{
+ char nextname[17];
+ struct areltdata *namedata;
+
+ /* FIXME: Formatting sucks here, and in case of failure of BFD_READ,
+ we probably don't want to return true. */
+ if (bfd_read ((PTR) nextname, 1, 16, abfd) == 16)
+ {
+
+ if (bfd_seek (abfd, (file_ptr) - 16, SEEK_CUR) != 0)
+ return false;
+
+ if (strncmp (nextname, "ARFILENAMES/ ", 16) != 0 &&
+ strncmp (nextname, "// ", 16) != 0)
+ {
+ bfd_ardata (abfd)->extended_names = NULL;
+ return true;
+ }
+
+ namedata = _bfd_snarf_ar_hdr (abfd);
+ if (namedata == NULL)
+ return false;
+
+ bfd_ardata (abfd)->extended_names =
+ bfd_zalloc (abfd, namedata->parsed_size);
+ if (bfd_ardata (abfd)->extended_names == NULL)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ byebye:
+ bfd_release (abfd, (PTR) namedata);
+ return false;
+ }
+
+ if (bfd_read ((PTR) bfd_ardata (abfd)->extended_names, 1,
+ namedata->parsed_size, abfd) != namedata->parsed_size)
+ {
+ if (bfd_get_error () != bfd_error_system_call)
+ bfd_set_error (bfd_error_malformed_archive);
+ bfd_release (abfd, (PTR) (bfd_ardata (abfd)->extended_names));
+ bfd_ardata (abfd)->extended_names = NULL;
+ goto byebye;
+ }
+
+ /* Since the archive is supposed to be printable if it contains
+ text, the entries in the list are newline-padded, not null
+ padded. In SVR4-style archives, the names also have a
+ trailing '/'. We'll fix both problems here.. */
+ {
+ char *temp = bfd_ardata (abfd)->extended_names;
+ char *limit = temp + namedata->parsed_size;
+ for (; temp < limit; ++temp)
+ if (*temp == '\012')
+ temp[temp[-1] == '/' ? -1 : 0] = '\0';
+ }
+
+ /* Pad to an even boundary if you have to */
+ bfd_ardata (abfd)->first_file_filepos = bfd_tell (abfd);
+ bfd_ardata (abfd)->first_file_filepos +=
+ (bfd_ardata (abfd)->first_file_filepos) % 2;
+
+ /* FIXME, we can't release namedata here because it was allocated
+ below extended_names on the obstack... */
+ /* bfd_release (abfd, namedata); */
+ }
+ return true;
+}
+
+#ifdef VMS
+
+/* Return a copy of the stuff in the filename between any :]> and a
+ semicolon */
+static const char *
+normalize (file)
+ const char *file;
+{
+ CONST char *first;
+ CONST char *last;
+ char *copy;
+
+ first = file + strlen (file) - 1;
+ last = first + 1;
+
+ while (first != file)
+ {
+ if (*first == ';')
+ last = first;
+ if (*first == ':' || *first == ']' || *first == '>')
+ {
+ first++;
+ break;
+ }
+ first--;
+ }
+
+
+ copy = malloc (last - first + 1);
+ if (!copy)
+ return copy;
+
+ memcpy (copy, first, last - first);
+ copy[last - first] = 0;
+
+ return copy;
+}
+
+#else
+static const char *
+normalize (file)
+ const char *file;
+{
+ CONST char *filename = strrchr (file, '/');
+
+ if (filename != (char *) NULL)
+ filename++;
+ else
+ filename = file;
+ return filename;
+}
+#endif
+
+/* Follows archive_head and produces an extended name table if
+ necessary. Returns (in tabloc) a pointer to an extended name
+ table, and in tablen the length of the table. If it makes an entry
+ it clobbers the filename so that the element may be written without
+ further massage. Returns true if it ran successfully, false if
+ something went wrong. A successful return may still involve a
+ zero-length tablen! */
+
+static boolean
+bfd_construct_extended_name_table (abfd, tabloc, tablen)
+ bfd *abfd;
+ char **tabloc;
+ unsigned int *tablen;
+{
+ unsigned int maxname = abfd->xvec->ar_max_namelen;
+ unsigned int total_namelen = 0;
+ bfd *current;
+ char *strptr;
+
+ *tablen = 0;
+
+ /* Figure out how long the table should be */
+ for (current = abfd->archive_head; current != NULL; current = current->next)
+ {
+ CONST char *normal = normalize (current->filename);
+ unsigned int thislen;
+
+ if (!normal)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ return false;
+ }
+ thislen = strlen (normal);
+ if (thislen > maxname)
+ total_namelen += thislen + 1; /* leave room for \n */
+ }
+
+ if (total_namelen == 0)
+ return true;
+
+ *tabloc = bfd_zalloc (abfd, total_namelen);
+ if (*tabloc == NULL)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ return false;
+ }
+
+ *tablen = total_namelen;
+ strptr = *tabloc;
+
+ for (current = abfd->archive_head; current != NULL; current =
+ current->next)
+ {
+ CONST char *normal = normalize (current->filename);
+ unsigned int thislen;
+
+ if (!normal)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ return false;
+ }
+ thislen = strlen (normal);
+ if (thislen > maxname)
+ {
+ /* Works for now; may need to be re-engineered if we
+ encounter an oddball archive format and want to
+ generalise this hack. */
+ struct ar_hdr *hdr = arch_hdr (current);
+ strcpy (strptr, normal);
+ strptr[thislen] = '\012';
+ hdr->ar_name[0] = ar_padchar (current);
+ /* We know there will always be enough room (one of the few
+ cases where you may safely use sprintf). */
+ sprintf ((hdr->ar_name) + 1, "%-d", (unsigned) (strptr - *tabloc));
+ /* Kinda Kludgy. We should just use the returned value of
+ sprintf but not all implementations get this right */
+ {
+ char *temp = hdr->ar_name + 2;
+ for (; temp < hdr->ar_name + maxname; temp++)
+ if (*temp == '\0')
+ *temp = ' ';
+ }
+ strptr += thislen + 1;
+ }
+ }
+
+ return true;
+}
+
+/** A couple of functions for creating ar_hdrs */
+
+/* Takes a filename, returns an arelt_data for it, or NULL if it can't
+ make one. The filename must refer to a filename in the filesystem.
+ The filename field of the ar_hdr will NOT be initialized */
+
+static struct areltdata *
+bfd_ar_hdr_from_filesystem (abfd, filename)
+ bfd *abfd;
+ const char *filename;
+{
+ struct stat status;
+ struct areltdata *ared;
+ struct ar_hdr *hdr;
+ char *temp, *temp1;
+
+ if (stat (filename, &status) != 0)
+ {
+ bfd_set_error (bfd_error_system_call);
+ return NULL;
+ }
+
+ ared = (struct areltdata *) bfd_zalloc (abfd, sizeof (struct ar_hdr) +
+ sizeof (struct areltdata));
+ if (ared == NULL)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ return NULL;
+ }
+ hdr = (struct ar_hdr *) (((char *) ared) + sizeof (struct areltdata));
+
+ /* ar headers are space padded, not null padded! */
+ memset ((PTR) hdr, ' ', sizeof (struct ar_hdr));
+
+ strncpy (hdr->ar_fmag, ARFMAG, 2);
+
+ /* Goddamned sprintf doesn't permit MAXIMUM field lengths */
+ sprintf ((hdr->ar_date), "%-12ld", (long) status.st_mtime);
+ sprintf ((hdr->ar_uid), "%ld", (long) status.st_uid);
+ sprintf ((hdr->ar_gid), "%ld", (long) status.st_gid);
+ sprintf ((hdr->ar_mode), "%-8o", (unsigned int) status.st_mode);
+ sprintf ((hdr->ar_size), "%-10ld", (long) status.st_size);
+ /* Correct for a lossage in sprintf whereby it null-terminates. I cannot
+ understand how these C losers could design such a ramshackle bunch of
+ IO operations */
+ temp = (char *) hdr;
+ temp1 = temp + sizeof (struct ar_hdr) - 2;
+ for (; temp < temp1; temp++)
+ {
+ if (*temp == '\0')
+ *temp = ' ';
+ }
+ strncpy (hdr->ar_fmag, ARFMAG, 2);
+ ared->parsed_size = status.st_size;
+ ared->arch_header = (char *) hdr;
+
+ return ared;
+}
+
+/* This is magic required by the "ar" program. Since it's
+ undocumented, it's undocumented. You may think that it would take
+ a strong stomach to write this, and it does, but it takes even a
+ stronger stomach to try to code around such a thing! */
+
+struct ar_hdr *
+bfd_special_undocumented_glue (abfd, filename)
+ bfd *abfd;
+ char *filename;
+{
+ struct areltdata *ar_elt = bfd_ar_hdr_from_filesystem (abfd, filename);
+ if (ar_elt == NULL)
+ return NULL;
+ return (struct ar_hdr *) ar_elt->arch_header;
+}
+
+
+/* Analogous to stat call */
+int
+bfd_generic_stat_arch_elt (abfd, buf)
+ bfd *abfd;
+ struct stat *buf;
+{
+ struct ar_hdr *hdr;
+ char *aloser;
+
+ if (abfd->arelt_data == NULL)
+ {
+ bfd_set_error (bfd_error_invalid_operation);
+ return -1;
+ }
+
+ hdr = arch_hdr (abfd);
+
+#define foo(arelt, stelt, size) \
+ buf->stelt = strtol (hdr->arelt, &aloser, size); \
+ if (aloser == hdr->arelt) return -1;
+
+ foo (ar_date, st_mtime, 10);
+ foo (ar_uid, st_uid, 10);
+ foo (ar_gid, st_gid, 10);
+ foo (ar_mode, st_mode, 8);
+
+ buf->st_size = arch_eltdata (abfd)->parsed_size;
+
+ return 0;
+}
+
+void
+bfd_dont_truncate_arname (abfd, pathname, arhdr)
+ bfd *abfd;
+ CONST char *pathname;
+ char *arhdr;
+{
+ /* FIXME: This interacts unpleasantly with ar's quick-append option.
+ Fortunately ic960 users will never use that option. Fixing this
+ is very hard; fortunately I know how to do it and will do so once
+ intel's release is out the door. */
+
+ struct ar_hdr *hdr = (struct ar_hdr *) arhdr;
+ int length;
+ CONST char *filename = normalize (pathname);
+ int maxlen = ar_maxnamelen (abfd);
+
+ length = strlen (filename);
+
+ if (length <= maxlen)
+ memcpy (hdr->ar_name, filename, length);
+
+ if (length < maxlen)
+ (hdr->ar_name)[length] = ar_padchar (abfd);
+}
+
+void
+bfd_bsd_truncate_arname (abfd, pathname, arhdr)
+ bfd *abfd;
+ CONST char *pathname;
+ char *arhdr;
+{
+ struct ar_hdr *hdr = (struct ar_hdr *) arhdr;
+ int length;
+ CONST char *filename = strrchr (pathname, '/');
+ int maxlen = ar_maxnamelen (abfd);
+
+ if (filename == NULL)
+ filename = pathname;
+ else
+ ++filename;
+
+ length = strlen (filename);
+
+ if (length <= maxlen)
+ memcpy (hdr->ar_name, filename, length);
+ else
+ {
+ /* pathname: meet procrustes */
+ memcpy (hdr->ar_name, filename, maxlen);
+ length = maxlen;
+ }
+
+ if (length < maxlen)
+ (hdr->ar_name)[length] = ar_padchar (abfd);
+}
+
+/* Store name into ar header. Truncates the name to fit.
+ 1> strip pathname to be just the basename.
+ 2> if it's short enuf to fit, stuff it in.
+ 3> If it doesn't end with .o, truncate it to fit
+ 4> truncate it before the .o, append .o, stuff THAT in. */
+
+/* This is what gnu ar does. It's better but incompatible with the
+ bsd ar. */
+
+void
+bfd_gnu_truncate_arname (abfd, pathname, arhdr)
+ bfd *abfd;
+ CONST char *pathname;
+ char *arhdr;
+{
+ struct ar_hdr *hdr = (struct ar_hdr *) arhdr;
+ int length;
+ CONST char *filename = strrchr (pathname, '/');
+ int maxlen = ar_maxnamelen (abfd);
+
+ if (filename == NULL)
+ filename = pathname;
+ else
+ ++filename;
+
+ length = strlen (filename);
+
+ if (length <= maxlen)
+ memcpy (hdr->ar_name, filename, length);
+ else
+ { /* pathname: meet procrustes */
+ memcpy (hdr->ar_name, filename, maxlen);
+ if ((filename[length - 2] == '.') && (filename[length - 1] == 'o'))
+ {
+ hdr->ar_name[maxlen - 2] = '.';
+ hdr->ar_name[maxlen - 1] = 'o';
+ }
+ length = maxlen;
+ }
+
+ if (length < 16)
+ (hdr->ar_name)[length] = ar_padchar (abfd);
+}
+
+/* The BFD is open for write and has its format set to bfd_archive */
+
+boolean
+_bfd_write_archive_contents (arch)
+ bfd *arch;
+{
+ bfd *current;
+ char *etable = NULL;
+ unsigned int elength = 0;
+ boolean makemap = bfd_has_map (arch);
+ boolean hasobjects = false; /* if no .o's, don't bother to make a map */
+ bfd_size_type wrote;
+ unsigned int i;
+ int tries;
+
+ /* Verify the viability of all entries; if any of them live in the
+ filesystem (as opposed to living in an archive open for input)
+ then construct a fresh ar_hdr for them. */
+ for (current = arch->archive_head; current; current = current->next)
+ {
+ if (bfd_write_p (current))
+ {
+ bfd_set_error (bfd_error_invalid_operation);
+ return false;
+ }
+ if (!current->arelt_data)
+ {
+ current->arelt_data =
+ (PTR) bfd_ar_hdr_from_filesystem (arch, current->filename);
+ if (!current->arelt_data)
+ return false;
+
+ /* Put in the file name */
+ BFD_SEND (arch, _bfd_truncate_arname, (arch,
+ current->filename,
+ (char *) arch_hdr (current)));
+ }
+
+ if (makemap && ! hasobjects)
+ { /* don't bother if we won't make a map! */
+ if ((bfd_check_format (current, bfd_object))
+#if 0 /* FIXME -- these are not set correctly */
+ && ((bfd_get_file_flags (current) & HAS_SYMS))
+#endif
+ )
+ hasobjects = true;
+ }
+ }
+
+ if (!bfd_construct_extended_name_table (arch, &etable, &elength))
+ return false;
+
+ if (bfd_seek (arch, (file_ptr) 0, SEEK_SET) != 0)
+ return false;
+#ifdef GNU960
+ wrote = bfd_write (BFD_GNU960_ARMAG (arch), 1, SARMAG, arch);
+#else
+ wrote = bfd_write (ARMAG, 1, SARMAG, arch);
+#endif
+ if (wrote != SARMAG)
+ return false;
+
+ if (makemap && hasobjects)
+ {
+ if (compute_and_write_armap (arch, elength) != true)
+ return false;
+ }
+
+ if (elength != 0)
+ {
+ struct ar_hdr hdr;
+
+ memset ((char *) (&hdr), 0, sizeof (struct ar_hdr));
+ if (ar_padchar (arch) == '/')
+ sprintf (&(hdr.ar_name[0]), "//");
+ else
+ sprintf (&(hdr.ar_name[0]), "ARFILENAMES/");
+ sprintf (&(hdr.ar_size[0]), "%-10d", (int) elength);
+ strncpy (hdr.ar_fmag, ARFMAG, 2);
+ for (i = 0; i < sizeof (struct ar_hdr); i++)
+ if (((char *) (&hdr))[i] == '\0')
+ (((char *) (&hdr))[i]) = ' ';
+ if ((bfd_write ((char *) &hdr, 1, sizeof (struct ar_hdr), arch)
+ != sizeof (struct ar_hdr))
+ || bfd_write (etable, 1, elength, arch) != elength)
+ return false;
+ if ((elength % 2) == 1)
+ {
+ if (bfd_write ("\012", 1, 1, arch) != 1)
+ return false;
+ }
+ }
+
+ for (current = arch->archive_head; current; current = current->next)
+ {
+ char buffer[DEFAULT_BUFFERSIZE];
+ unsigned int remaining = arelt_size (current);
+ struct ar_hdr *hdr = arch_hdr (current);
+
+ /* write ar header */
+ if (bfd_write ((char *) hdr, 1, sizeof (*hdr), arch) != sizeof (*hdr))
+ return false;
+ if (bfd_seek (current, (file_ptr) 0, SEEK_SET) != 0)
+ return false;
+ while (remaining)
+ {
+ unsigned int amt = DEFAULT_BUFFERSIZE;
+ if (amt > remaining)
+ amt = remaining;
+ errno = 0;
+ if (bfd_read (buffer, amt, 1, current) != amt)
+ {
+ if (bfd_get_error () != bfd_error_system_call)
+ bfd_set_error (bfd_error_malformed_archive);
+ return false;
+ }
+ if (bfd_write (buffer, amt, 1, arch) != amt)
+ return false;
+ remaining -= amt;
+ }
+ if ((arelt_size (current) % 2) == 1)
+ {
+ if (bfd_write ("\012", 1, 1, arch) != 1)
+ return false;
+ }
+ }
+
+ /* Verify the timestamp in the archive file. If it would not be
+ accepted by the linker, rewrite it until it would be. If
+ anything odd happens, break out and just return. (The Berkeley
+ linker checks the timestamp and refuses to read the
+ table-of-contents if it is >60 seconds less than the file's
+ modified-time. That painful hack requires this painful hack. */
+
+ tries = 1;
+ do
+ {
+ /* FIXME! This kludge is to avoid adding a member to the xvec,
+ while generating a small patch for Adobe. FIXME! The
+ update_armap_timestamp function call should be in the xvec,
+ thus:
+
+ if (bfd_update_armap_timestamp (arch) == true) break;
+ ^
+
+ Instead, we check whether in a BSD archive, and call
+ directly. */
+
+ if (arch->xvec->write_armap != bsd_write_armap)
+ break;
+ if (bsd_update_armap_timestamp (arch) == true) /* FIXME!!! Vector it */
+ break;
+ if (tries > 0)
+ fprintf (stderr,
+ "Warning: writing archive was slow: rewriting timestamp\n");
+ }
+ while (++tries < 6);
+
+ return true;
+}
+
+/* Note that the namidx for the first symbol is 0 */
+
+static boolean
+compute_and_write_armap (arch, elength)
+ bfd *arch;
+ unsigned int elength;
+{
+ char *first_name = NULL;
+ bfd *current;
+ file_ptr elt_no = 0;
+ struct orl *map = NULL;
+ int orl_max = 1024; /* fine initial default */
+ int orl_count = 0;
+ int stridx = 0; /* string index */
+ asymbol **syms = NULL;
+ long syms_max = 0;
+ boolean ret;
+
+ /* Dunno if this is the best place for this info... */
+ if (elength != 0)
+ elength += sizeof (struct ar_hdr);
+ elength += elength % 2;
+
+ map = (struct orl *) malloc (orl_max * sizeof (struct orl));
+ if (map == NULL)
+ goto no_memory_return;
+
+ /* We put the symbol names on the arch obstack, and then discard
+ them when done. */
+ first_name = bfd_alloc (arch, 1);
+ if (first_name == NULL)
+ goto no_memory_return;
+
+ /* Drop all the files called __.SYMDEF, we're going to make our
+ own */
+ while (arch->archive_head &&
+ strcmp (arch->archive_head->filename, "__.SYMDEF") == 0)
+ arch->archive_head = arch->archive_head->next;
+
+ /* Map over each element */
+ for (current = arch->archive_head;
+ current != (bfd *) NULL;
+ current = current->next, elt_no++)
+ {
+ if ((bfd_check_format (current, bfd_object) == true)
+ && ((bfd_get_file_flags (current) & HAS_SYMS)))
+ {
+ long storage;
+ long symcount;
+ long src_count;
+
+ storage = bfd_get_symtab_upper_bound (current);
+ if (storage < 0)
+ goto error_return;
+
+ if (storage != 0)
+ {
+ if (storage > syms_max)
+ {
+ if (syms_max > 0)
+ free (syms);
+ syms_max = storage;
+ syms = (asymbol **) malloc ((size_t) syms_max);
+ if (syms == NULL)
+ goto no_memory_return;
+ }
+ symcount = bfd_canonicalize_symtab (current, syms);
+ if (symcount < 0)
+ goto error_return;
+
+ /* Now map over all the symbols, picking out the ones we want */
+ for (src_count = 0; src_count < symcount; src_count++)
+ {
+ flagword flags = (syms[src_count])->flags;
+ asection *sec = syms[src_count]->section;
+
+ if ((flags & BSF_GLOBAL ||
+ flags & BSF_WEAK ||
+ flags & BSF_INDIRECT ||
+ bfd_is_com_section (sec))
+ && ! bfd_is_und_section (sec))
+ {
+ size_t namelen;
+ struct orl *new_map;
+
+ /* This symbol will go into the archive header */
+ if (orl_count == orl_max)
+ {
+ orl_max *= 2;
+ new_map = ((struct orl *)
+ realloc ((PTR) map,
+ orl_max * sizeof (struct orl)));
+ if (new_map == (struct orl *) NULL)
+ goto no_memory_return;
+
+ map = new_map;
+ }
+
+ namelen = strlen (syms[src_count]->name);
+ map[orl_count].name = ((char **)
+ bfd_alloc (arch,
+ sizeof (char *)));
+ if (map[orl_count].name == NULL)
+ goto no_memory_return;
+ *(map[orl_count].name) = bfd_alloc (arch, namelen + 1);
+ if (*(map[orl_count].name) == NULL)
+ goto no_memory_return;
+ strcpy (*(map[orl_count].name), syms[src_count]->name);
+ (map[orl_count]).pos = (file_ptr) current;
+ (map[orl_count]).namidx = stridx;
+
+ stridx += namelen + 1;
+ ++orl_count;
+ }
+ }
+ }
+
+ /* Now ask the BFD to free up any cached information, so we
+ don't fill all of memory with symbol tables. */
+ if (! bfd_free_cached_info (current))
+ goto error_return;
+ }
+ }
+
+ /* OK, now we have collected all the data, let's write them out */
+ ret = BFD_SEND (arch, write_armap,
+ (arch, elength, map, orl_count, stridx));
+
+ if (syms_max > 0)
+ free (syms);
+ if (map != NULL)
+ free (map);
+ if (first_name != NULL)
+ bfd_release (arch, first_name);
+
+ return ret;
+
+ no_memory_return:
+ bfd_set_error (bfd_error_no_memory);
+
+ error_return:
+ if (syms_max > 0)
+ free (syms);
+ if (map != NULL)
+ free (map);
+ if (first_name != NULL)
+ bfd_release (arch, first_name);
+
+ return false;
+}
+
+boolean
+bsd_write_armap (arch, elength, map, orl_count, stridx)
+ bfd *arch;
+ unsigned int elength;
+ struct orl *map;
+ unsigned int orl_count;
+ int stridx;
+{
+ int padit = stridx & 1;
+ unsigned int ranlibsize = orl_count * sizeof (struct ranlib);
+ unsigned int stringsize = stridx + padit;
+ /* Include 8 bytes to store ranlibsize and stringsize in output. */
+ unsigned int mapsize = ranlibsize + stringsize + 8;
+ file_ptr firstreal;
+ bfd *current = arch->archive_head;
+ bfd *last_elt = current; /* last element arch seen */
+ int temp;
+ int count;
+ struct ar_hdr hdr;
+ struct stat statbuf;
+ unsigned int i;
+
+ firstreal = mapsize + elength + sizeof (struct ar_hdr) + SARMAG;
+
+ stat (arch->filename, &statbuf);
+ memset ((char *) (&hdr), 0, sizeof (struct ar_hdr));
+ sprintf (hdr.ar_name, RANLIBMAG);
+ /* Remember the timestamp, to keep it holy. But fudge it a little. */
+ bfd_ardata (arch)->armap_timestamp = statbuf.st_mtime + ARMAP_TIME_OFFSET;
+ bfd_ardata (arch)->armap_datepos = (SARMAG
+ + offsetof (struct ar_hdr, ar_date[0]));
+ sprintf (hdr.ar_date, "%ld", bfd_ardata (arch)->armap_timestamp);
+ sprintf (hdr.ar_uid, "%d", getuid ());
+ sprintf (hdr.ar_gid, "%d", getgid ());
+ sprintf (hdr.ar_size, "%-10d", (int) mapsize);
+ strncpy (hdr.ar_fmag, ARFMAG, 2);
+ for (i = 0; i < sizeof (struct ar_hdr); i++)
+ if (((char *) (&hdr))[i] == '\0')
+ (((char *) (&hdr))[i]) = ' ';
+ if (bfd_write ((char *) &hdr, 1, sizeof (struct ar_hdr), arch)
+ != sizeof (struct ar_hdr))
+ return false;
+ bfd_h_put_32 (arch, (bfd_vma) ranlibsize, (PTR) &temp);
+ if (bfd_write (&temp, 1, sizeof (temp), arch) != sizeof (temp))
+ return false;
+
+ for (count = 0; count < orl_count; count++)
+ {
+ struct symdef outs;
+ struct symdef *outp = &outs;
+
+ if (((bfd *) (map[count]).pos) != last_elt)
+ {
+ do
+ {
+ firstreal += arelt_size (current) + sizeof (struct ar_hdr);
+ firstreal += firstreal % 2;
+ current = current->next;
+ }
+ while (current != (bfd *) (map[count]).pos);
+ } /* if new archive element */
+
+ last_elt = current;
+ bfd_h_put_32 (arch, ((map[count]).namidx), (PTR) &outs.s.string_offset);
+ bfd_h_put_32 (arch, firstreal, (PTR) &outs.file_offset);
+ if (bfd_write ((char *) outp, 1, sizeof (outs), arch) != sizeof (outs))
+ return false;
+ }
+
+ /* now write the strings themselves */
+ bfd_h_put_32 (arch, stringsize, (PTR) &temp);
+ if (bfd_write ((PTR) &temp, 1, sizeof (temp), arch) != sizeof (temp))
+ return false;
+ for (count = 0; count < orl_count; count++)
+ {
+ size_t len = strlen (*map[count].name) + 1;
+
+ if (bfd_write (*map[count].name, 1, len, arch) != len)
+ return false;
+ }
+
+ /* The spec sez this should be a newline. But in order to be
+ bug-compatible for sun's ar we use a null. */
+ if (padit)
+ {
+ if (bfd_write ("", 1, 1, arch) != 1)
+ return false;
+ }
+
+ return true;
+}
+
+/* At the end of archive file handling, update the timestamp in the
+ file, so the linker will accept it.
+
+ Return true if the timestamp was OK, or an unusual problem happened.
+ Return false if we updated the timestamp. */
+
+static boolean
+bsd_update_armap_timestamp (arch)
+ bfd *arch;
+{
+ struct stat archstat;
+ struct ar_hdr hdr;
+ int i;
+
+ /* Flush writes, get last-write timestamp from file, and compare it
+ to the timestamp IN the file. */
+ bfd_flush (arch);
+ if (bfd_stat (arch, &archstat) == -1)
+ {
+ perror ("Reading archive file mod timestamp");
+ return true; /* Can't read mod time for some reason */
+ }
+ if (archstat.st_mtime <= bfd_ardata (arch)->armap_timestamp)
+ return true; /* OK by the linker's rules */
+
+ /* Update the timestamp. */
+ bfd_ardata (arch)->armap_timestamp = archstat.st_mtime + ARMAP_TIME_OFFSET;
+
+ /* Prepare an ASCII version suitable for writing. */
+ memset (hdr.ar_date, 0, sizeof (hdr.ar_date));
+ sprintf (hdr.ar_date, "%ld", bfd_ardata (arch)->armap_timestamp);
+ for (i = 0; i < sizeof (hdr.ar_date); i++)
+ if (hdr.ar_date[i] == '\0')
+ (hdr.ar_date)[i] = ' ';
+
+ /* Write it into the file. */
+ if (bfd_seek (arch, bfd_ardata (arch)->armap_datepos, SEEK_SET) != 0
+ || (bfd_write (hdr.ar_date, sizeof (hdr.ar_date), 1, arch)
+ != sizeof (hdr.ar_date)))
+ {
+ /* FIXME: bfd can't call perror. */
+ perror ("Writing updated armap timestamp");
+ return true; /* Some error while writing */
+ }
+
+ return false; /* We updated the timestamp successfully. */
+}
+
+/* A coff armap looks like :
+ lARMAG
+ struct ar_hdr with name = '/'
+ number of symbols
+ offset of file for symbol 0
+ offset of file for symbol 1
+
+ offset of file for symbol n-1
+ symbol name 0
+ symbol name 1
+
+ symbol name n-1
+*/
+
+boolean
+coff_write_armap (arch, elength, map, symbol_count, stridx)
+ bfd *arch;
+ unsigned int elength;
+ struct orl *map;
+ unsigned int symbol_count;
+ int stridx;
+{
+ /* The size of the ranlib is the number of exported symbols in the
+ archive * the number of bytes in a int, + an int for the count */
+ unsigned int ranlibsize = (symbol_count * 4) + 4;
+ unsigned int stringsize = stridx;
+ unsigned int mapsize = stringsize + ranlibsize;
+ file_ptr archive_member_file_ptr;
+ bfd *current = arch->archive_head;
+ int count;
+ struct ar_hdr hdr;
+ unsigned int i;
+ int padit = mapsize & 1;
+
+ if (padit)
+ mapsize++;
+
+ /* work out where the first object file will go in the archive */
+ archive_member_file_ptr = (mapsize
+ + elength
+ + sizeof (struct ar_hdr)
+ + SARMAG);
+
+ memset ((char *) (&hdr), 0, sizeof (struct ar_hdr));
+ hdr.ar_name[0] = '/';
+ sprintf (hdr.ar_size, "%-10d", (int) mapsize);
+ sprintf (hdr.ar_date, "%ld", (long) time (NULL));
+ /* This, at least, is what Intel coff sets the values to.: */
+ sprintf ((hdr.ar_uid), "%d", 0);
+ sprintf ((hdr.ar_gid), "%d", 0);
+ sprintf ((hdr.ar_mode), "%-7o", (unsigned) 0);
+ strncpy (hdr.ar_fmag, ARFMAG, 2);
+
+ for (i = 0; i < sizeof (struct ar_hdr); i++)
+ if (((char *) (&hdr))[i] == '\0')
+ (((char *) (&hdr))[i]) = ' ';
+
+ /* Write the ar header for this item and the number of symbols */
+
+ if (bfd_write ((PTR) &hdr, 1, sizeof (struct ar_hdr), arch)
+ != sizeof (struct ar_hdr))
+ return false;
+
+ bfd_write_bigendian_4byte_int (arch, symbol_count);
+
+ /* Two passes, first write the file offsets for each symbol -
+ remembering that each offset is on a two byte boundary. */
+
+ /* Write out the file offset for the file associated with each
+ symbol, and remember to keep the offsets padded out. */
+
+ current = arch->archive_head;
+ count = 0;
+ while (current != (bfd *) NULL && count < symbol_count)
+ {
+ /* For each symbol which is used defined in this object, write out
+ the object file's address in the archive */
+
+ while (((bfd *) (map[count]).pos) == current)
+ {
+ bfd_write_bigendian_4byte_int (arch, archive_member_file_ptr);
+ count++;
+ }
+ /* Add size of this archive entry */
+ archive_member_file_ptr += (arelt_size (current)
+ + sizeof (struct ar_hdr));
+ /* remember aboout the even alignment */
+ archive_member_file_ptr += archive_member_file_ptr % 2;
+ current = current->next;
+ }
+
+ /* now write the strings themselves */
+ for (count = 0; count < symbol_count; count++)
+ {
+ size_t len = strlen (*map[count].name) + 1;
+
+ if (bfd_write (*map[count].name, 1, len, arch) != len)
+ return false;
+ }
+
+ /* The spec sez this should be a newline. But in order to be
+ bug-compatible for arc960 we use a null. */
+ if (padit)
+ {
+ if (bfd_write ("", 1, 1, arch) != 1)
+ return false;
+ }
+
+ return true;
+}
diff --git a/gnu/usr.bin/gdb/bfd/archures.c b/gnu/usr.bin/gdb/bfd/archures.c
new file mode 100644
index 0000000..1bff43a
--- /dev/null
+++ b/gnu/usr.bin/gdb/bfd/archures.c
@@ -0,0 +1,745 @@
+/* BFD library support routines for architectures.
+ Copyright (C) 1990, 91, 92, 93, 94 Free Software Foundation, Inc.
+ Hacked by John Gilmore and Steve Chamberlain of Cygnus Support.
+
+This file is part of BFD, the Binary File Descriptor library.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/*
+
+SECTION
+ Architectures
+
+ BFD keeps one atom in a BFD describing the
+ architecture of the data attached to the BFD: a pointer to a
+ <<bfd_arch_info_type>>.
+
+ Pointers to structures can be requested independently of a BFD
+ so that an architecture's information can be interrogated
+ without access to an open BFD.
+
+ The architecture information is provided by each architecture package.
+ The set of default architectures is selected by the macro
+ <<SELECT_ARCHITECTURES>>. This is normally set up in the
+ @file{config/@var{target}.mt} file of your choice. If the name is not
+ defined, then all the architectures supported are included.
+
+ When BFD starts up, all the architectures are called with an
+ initialize method. It is up to the architecture back end to
+ insert as many items into the list of architectures as it wants to;
+ generally this would be one for each machine and one for the
+ default case (an item with a machine field of 0).
+
+ BFD's idea of an architecture is implemented in @file{archures.c}.
+*/
+
+/*
+
+SUBSECTION
+ bfd_architecture
+
+DESCRIPTION
+ This enum gives the object file's CPU architecture, in a
+ global sense---i.e., what processor family does it belong to?
+ Another field indicates which processor within
+ the family is in use. The machine gives a number which
+ distinguishes different versions of the architecture,
+ containing, for example, 2 and 3 for Intel i960 KA and i960 KB,
+ and 68020 and 68030 for Motorola 68020 and 68030.
+
+.enum bfd_architecture
+.{
+. bfd_arch_unknown, {* File arch not known *}
+. bfd_arch_obscure, {* Arch known, not one of these *}
+. bfd_arch_m68k, {* Motorola 68xxx *}
+. bfd_arch_vax, {* DEC Vax *}
+. bfd_arch_i960, {* Intel 960 *}
+. {* The order of the following is important.
+. lower number indicates a machine type that
+. only accepts a subset of the instructions
+. available to machines with higher numbers.
+. The exception is the "ca", which is
+. incompatible with all other machines except
+. "core". *}
+.
+.#define bfd_mach_i960_core 1
+.#define bfd_mach_i960_ka_sa 2
+.#define bfd_mach_i960_kb_sb 3
+.#define bfd_mach_i960_mc 4
+.#define bfd_mach_i960_xa 5
+.#define bfd_mach_i960_ca 6
+.
+. bfd_arch_a29k, {* AMD 29000 *}
+. bfd_arch_sparc, {* SPARC *}
+. bfd_arch_mips, {* MIPS Rxxxx *}
+. bfd_arch_i386, {* Intel 386 *}
+. bfd_arch_we32k, {* AT&T WE32xxx *}
+. bfd_arch_tahoe, {* CCI/Harris Tahoe *}
+. bfd_arch_i860, {* Intel 860 *}
+. bfd_arch_romp, {* IBM ROMP PC/RT *}
+. bfd_arch_alliant, {* Alliant *}
+. bfd_arch_convex, {* Convex *}
+. bfd_arch_m88k, {* Motorola 88xxx *}
+. bfd_arch_pyramid, {* Pyramid Technology *}
+. bfd_arch_h8300, {* Hitachi H8/300 *}
+.#define bfd_mach_h8300 1
+.#define bfd_mach_h8300h 2
+. bfd_arch_powerpc, {* PowerPC *}
+. bfd_arch_rs6000, {* IBM RS/6000 *}
+. bfd_arch_hppa, {* HP PA RISC *}
+. bfd_arch_z8k, {* Zilog Z8000 *}
+.#define bfd_mach_z8001 1
+.#define bfd_mach_z8002 2
+. bfd_arch_h8500, {* Hitachi H8/500 *}
+. bfd_arch_sh, {* Hitachi SH *}
+. bfd_arch_alpha, {* Dec Alpha *}
+. bfd_arch_ns32k, {* National Semiconductors ns32000 *}
+. bfd_arch_last
+. };
+
+
+*/
+
+#include "bfd.h"
+#include "sysdep.h"
+#include "libbfd.h"
+
+/*
+
+SUBSECTION
+ bfd_arch_info
+
+DESCRIPTION
+ This structure contains information on architectures for use
+ within BFD.
+
+.
+.typedef struct bfd_arch_info
+.{
+. int bits_per_word;
+. int bits_per_address;
+. int bits_per_byte;
+. enum bfd_architecture arch;
+. long mach;
+. char *arch_name;
+. CONST char *printable_name;
+. unsigned int section_align_power;
+. {* true if this is the default machine for the architecture *}
+. boolean the_default;
+. CONST struct bfd_arch_info * (*compatible)
+. PARAMS ((CONST struct bfd_arch_info *a,
+. CONST struct bfd_arch_info *b));
+.
+. boolean (*scan) PARAMS ((CONST struct bfd_arch_info *, CONST char *));
+. {* How to disassemble an instruction, producing a printable
+. representation on a specified stdio stream. This isn't
+. defined for most processors at present, because of the size
+. of the additional tables it would drag in, and because gdb
+. wants to use a different interface. *}
+. unsigned int (*disassemble) PARAMS ((bfd_vma addr, CONST char *data,
+. PTR stream));
+.
+. struct bfd_arch_info *next;
+.} bfd_arch_info_type;
+*/
+
+bfd_arch_info_type *bfd_arch_info_list;
+
+
+/*
+FUNCTION
+ bfd_printable_name
+
+SYNOPSIS
+ CONST char *bfd_printable_name(bfd *abfd);
+
+DESCRIPTION
+ Return a printable string representing the architecture and machine
+ from the pointer to the architecture info structure.
+
+*/
+
+CONST char *
+bfd_printable_name (abfd)
+ bfd *abfd;
+{
+ return abfd->arch_info->printable_name;
+}
+
+
+
+/*
+FUNCTION
+ bfd_scan_arch
+
+SYNOPSIS
+ bfd_arch_info_type *bfd_scan_arch(CONST char *string);
+
+DESCRIPTION
+ Figure out if BFD supports any cpu which could be described with
+ the name @var{string}. Return a pointer to an <<arch_info>>
+ structure if a machine is found, otherwise NULL.
+
+*/
+
+bfd_arch_info_type *
+bfd_scan_arch (string)
+ CONST char *string;
+{
+ struct bfd_arch_info *ap;
+
+ /* Look through all the installed architectures */
+ for (ap = bfd_arch_info_list;
+ ap != (bfd_arch_info_type *)NULL;
+ ap = ap->next) {
+
+ if (ap->scan(ap, string))
+ return ap;
+ }
+ return (bfd_arch_info_type *)NULL;
+}
+
+
+
+/*
+FUNCTION
+ bfd_arch_get_compatible
+
+SYNOPSIS
+ CONST bfd_arch_info_type *bfd_arch_get_compatible(
+ CONST bfd *abfd,
+ CONST bfd *bbfd);
+
+DESCRIPTION
+ Determine whether two BFDs'
+ architectures and machine types are compatible. Calculates
+ the lowest common denominator between the two architectures
+ and machine types implied by the BFDs and returns a pointer to
+ an <<arch_info>> structure describing the compatible machine.
+*/
+
+CONST bfd_arch_info_type *
+bfd_arch_get_compatible (abfd, bbfd)
+ CONST bfd *abfd;
+ CONST bfd *bbfd;
+{
+ return abfd->arch_info->compatible(abfd->arch_info,bbfd->arch_info);
+}
+
+
+/*
+INTERNAL_DEFINITION
+ bfd_default_arch_struct
+
+DESCRIPTION
+ The <<bfd_default_arch_struct>> is an item of
+ <<bfd_arch_info_type>> which has been initialized to a fairly
+ generic state. A BFD starts life by pointing to this
+ structure, until the correct back end has determined the real
+ architecture of the file.
+
+.extern bfd_arch_info_type bfd_default_arch_struct;
+
+*/
+
+bfd_arch_info_type bfd_default_arch_struct =
+{
+ 32,32,8,bfd_arch_unknown,0,"unknown","unknown",2,true,
+ bfd_default_compatible,
+ bfd_default_scan,
+ 0,
+};
+
+/*
+FUNCTION
+ bfd_set_arch_info
+
+SYNOPSIS
+ void bfd_set_arch_info(bfd *abfd, bfd_arch_info_type *arg);
+
+DESCRIPTION
+ Set the architecture info of @var{abfd} to @var{arg}.
+*/
+
+void
+bfd_set_arch_info (abfd, arg)
+ bfd *abfd;
+ bfd_arch_info_type *arg;
+{
+ abfd->arch_info = arg;
+}
+
+/*
+INTERNAL_FUNCTION
+ bfd_default_set_arch_mach
+
+SYNOPSIS
+ boolean bfd_default_set_arch_mach(bfd *abfd,
+ enum bfd_architecture arch,
+ unsigned long mach);
+
+DESCRIPTION
+ Set the architecture and machine type in BFD @var{abfd}
+ to @var{arch} and @var{mach}. Find the correct
+ pointer to a structure and insert it into the <<arch_info>>
+ pointer.
+*/
+
+boolean
+bfd_default_set_arch_mach (abfd, arch, mach)
+ bfd *abfd;
+ enum bfd_architecture arch;
+ unsigned long mach;
+{
+ static struct bfd_arch_info *old_ptr = &bfd_default_arch_struct;
+ boolean found = false;
+ /* run through the table to find the one we want, we keep a little
+ cache to speed things up */
+ if (old_ptr == 0 || arch != old_ptr->arch || mach != old_ptr->mach) {
+ bfd_arch_info_type *ptr;
+ old_ptr = (bfd_arch_info_type *)NULL;
+ for (ptr = bfd_arch_info_list;
+ ptr != (bfd_arch_info_type *)NULL;
+ ptr= ptr->next) {
+ if (ptr->arch == arch &&
+ ((ptr->mach == mach) || (ptr->the_default && mach == 0))) {
+ old_ptr = ptr;
+ found = true;
+ break;
+ }
+ }
+ if (found==false) {
+ /*looked for it and it wasn't there, so put in the default */
+ old_ptr = &bfd_default_arch_struct;
+ bfd_set_error (bfd_error_bad_value);
+ }
+ }
+ else {
+ /* it was in the cache */
+ found = true;
+ }
+
+ abfd->arch_info = old_ptr;
+
+ return found;
+}
+
+
+/*
+FUNCTION
+ bfd_get_arch
+
+SYNOPSIS
+ enum bfd_architecture bfd_get_arch(bfd *abfd);
+
+DESCRIPTION
+ Return the enumerated type which describes the BFD @var{abfd}'s
+ architecture.
+
+*/
+
+enum bfd_architecture
+bfd_get_arch (abfd)
+ bfd *abfd;
+{
+ return abfd->arch_info->arch;
+}
+
+/*
+FUNCTION
+ bfd_get_mach
+
+SYNOPSIS
+ unsigned long bfd_get_mach(bfd *abfd);
+
+DESCRIPTION
+ Return the long type which describes the BFD @var{abfd}'s
+ machine.
+*/
+
+unsigned long
+bfd_get_mach (abfd)
+ bfd *abfd;
+{
+ return abfd->arch_info->mach;
+}
+
+/*
+FUNCTION
+ bfd_arch_bits_per_byte
+
+SYNOPSIS
+ unsigned int bfd_arch_bits_per_byte(bfd *abfd);
+
+DESCRIPTION
+ Return the number of bits in one of the BFD @var{abfd}'s
+ architecture's bytes.
+
+*/
+
+unsigned int
+bfd_arch_bits_per_byte (abfd)
+ bfd *abfd;
+{
+ return abfd->arch_info->bits_per_byte;
+}
+
+/*
+FUNCTION
+ bfd_arch_bits_per_address
+
+SYNOPSIS
+ unsigned int bfd_arch_bits_per_address(bfd *abfd);
+
+DESCRIPTION
+ Return the number of bits in one of the BFD @var{abfd}'s
+ architecture's addresses.
+*/
+
+unsigned int
+bfd_arch_bits_per_address (abfd)
+ bfd *abfd;
+{
+ return abfd->arch_info->bits_per_address;
+}
+
+
+extern void bfd_a29k_arch PARAMS ((void));
+extern void bfd_alpha_arch PARAMS ((void));
+extern void bfd_h8300_arch PARAMS ((void));
+extern void bfd_h8500_arch PARAMS ((void));
+extern void bfd_hppa_arch PARAMS ((void));
+extern void bfd_i386_arch PARAMS ((void));
+extern void bfd_i960_arch PARAMS ((void));
+extern void bfd_m68k_arch PARAMS ((void));
+extern void bfd_m88k_arch PARAMS ((void));
+extern void bfd_mips_arch PARAMS ((void));
+extern void bfd_powerpc_arch PARAMS ((void));
+extern void bfd_rs6000_arch PARAMS ((void));
+extern void bfd_sh_arch PARAMS ((void));
+extern void bfd_sparc_arch PARAMS ((void));
+extern void bfd_vax_arch PARAMS ((void));
+extern void bfd_we32k_arch PARAMS ((void));
+extern void bfd_z8k_arch PARAMS ((void));
+extern void bfd_ns32k_arch PARAMS ((void));
+
+static void (*archures_init_table[]) PARAMS ((void)) =
+{
+#ifdef SELECT_ARCHITECTURES
+ SELECT_ARCHITECTURES,
+#else
+ bfd_a29k_arch,
+ bfd_alpha_arch,
+ bfd_h8300_arch,
+ bfd_h8500_arch,
+ bfd_hppa_arch,
+ bfd_i386_arch,
+ bfd_i960_arch,
+ bfd_m68k_arch,
+ bfd_m88k_arch,
+ bfd_mips_arch,
+ bfd_powerpc_arch,
+ bfd_rs6000_arch,
+ bfd_sh_arch,
+ bfd_sparc_arch,
+ bfd_vax_arch,
+ bfd_we32k_arch,
+ bfd_z8k_arch,
+ bfd_ns32k_arch,
+#endif
+ 0
+ };
+
+
+
+/*
+INTERNAL_FUNCTION
+ bfd_arch_init
+
+SYNOPSIS
+ void bfd_arch_init(void);
+
+DESCRIPTION
+ Initialize the architecture dispatch table by
+ calling all installed architecture packages and getting them
+ to poke around.
+*/
+
+void
+bfd_arch_init ()
+{
+ void (**ptable) PARAMS ((void));
+ for (ptable = archures_init_table;
+ *ptable ;
+ ptable++)
+ {
+ (*ptable)();
+ }
+}
+
+
+/*
+INTERNAL_FUNCTION
+ bfd_arch_linkin
+
+SYNOPSIS
+ void bfd_arch_linkin(bfd_arch_info_type *ptr);
+
+DESCRIPTION
+ Link the architecture info structure @var{ptr} into the list.
+*/
+
+void
+bfd_arch_linkin (ptr)
+ bfd_arch_info_type *ptr;
+{
+ ptr->next = bfd_arch_info_list;
+ bfd_arch_info_list = ptr;
+}
+
+
+/*
+INTERNAL_FUNCTION
+ bfd_default_compatible
+
+SYNOPSIS
+ CONST bfd_arch_info_type *bfd_default_compatible
+ (CONST bfd_arch_info_type *a,
+ CONST bfd_arch_info_type *b);
+
+DESCRIPTION
+ The default function for testing for compatibility.
+*/
+
+CONST bfd_arch_info_type *
+bfd_default_compatible (a,b)
+ CONST bfd_arch_info_type *a;
+ CONST bfd_arch_info_type *b;
+{
+ if(a->arch != b->arch) return NULL;
+
+ if (a->mach > b->mach) {
+ return a;
+ }
+ if (b->mach > a->mach) {
+ return b;
+ }
+ return a;
+}
+
+
+/*
+INTERNAL_FUNCTION
+ bfd_default_scan
+
+SYNOPSIS
+ boolean bfd_default_scan(CONST struct bfd_arch_info *info, CONST char *string);
+
+DESCRIPTION
+ The default function for working out whether this is an
+ architecture hit and a machine hit.
+*/
+
+boolean
+bfd_default_scan (info, string)
+ CONST struct bfd_arch_info *info;
+ CONST char *string;
+{
+ CONST char *ptr_src;
+ CONST char *ptr_tst;
+ unsigned long number;
+ enum bfd_architecture arch;
+ /* First test for an exact match */
+ if (strcmp(string, info->printable_name) == 0) return true;
+
+ /* See how much of the supplied string matches with the
+ architecture, eg the string m68k:68020 would match the 68k entry
+ up to the :, then we get left with the machine number */
+
+ for (ptr_src = string,
+ ptr_tst = info->arch_name;
+ *ptr_src && *ptr_tst;
+ ptr_src++,
+ ptr_tst++)
+ {
+ if (*ptr_src != *ptr_tst) break;
+ }
+
+ /* Chewed up as much of the architecture as will match, skip any
+ colons */
+ if (*ptr_src == ':') ptr_src++;
+
+ if (*ptr_src == 0) {
+ /* nothing more, then only keep this one if it is the default
+ machine for this architecture */
+ return info->the_default;
+ }
+ number = 0;
+ while (isdigit(*ptr_src)) {
+ number = number * 10 + *ptr_src - '0';
+ ptr_src++;
+ }
+
+ switch (number)
+ {
+ case 300:
+ arch = bfd_arch_h8300;
+ break;
+
+ case 500:
+ arch = bfd_arch_h8500;
+ break;
+
+ case 68010:
+ case 68020:
+ case 68030:
+ case 68040:
+ case 68332:
+ case 68050:
+ case 68000:
+ arch = bfd_arch_m68k;
+ break;
+ case 386:
+ case 80386:
+ case 486:
+ case 80486:
+ arch = bfd_arch_i386;
+ break;
+ case 29000:
+ arch = bfd_arch_a29k;
+ break;
+
+ case 8000:
+ arch = bfd_arch_z8k;
+ break;
+
+ case 32000:
+ arch = bfd_arch_we32k;
+ break;
+
+ case 860:
+ case 80860:
+ arch = bfd_arch_i860;
+ break;
+ case 960:
+ case 80960:
+ arch = bfd_arch_i960;
+ break;
+
+ case 2000:
+ case 3000:
+ case 4000:
+ case 4400:
+ arch = bfd_arch_mips;
+ break;
+
+ case 6000:
+ arch = bfd_arch_rs6000;
+ break;
+
+ default:
+ return false;
+ }
+ if (arch != info->arch)
+ return false;
+
+ if (number != info->mach)
+ return false;
+
+ return true;
+}
+
+
+/*
+FUNCTION
+ bfd_get_arch_info
+
+SYNOPSIS
+ bfd_arch_info_type * bfd_get_arch_info(bfd *abfd);
+
+DESCRIPTION
+ Return the architecture info struct in @var{abfd}.
+*/
+
+bfd_arch_info_type *
+bfd_get_arch_info (abfd)
+ bfd *abfd;
+{
+ return abfd->arch_info;
+}
+
+
+/*
+FUNCTION
+ bfd_lookup_arch
+
+SYNOPSIS
+ bfd_arch_info_type *bfd_lookup_arch
+ (enum bfd_architecture
+ arch,
+ long machine);
+
+DESCRIPTION
+ Look for the architecure info structure which matches the
+ arguments @var{arch} and @var{machine}. A machine of 0 matches the
+ machine/architecture structure which marks itself as the
+ default.
+*/
+
+bfd_arch_info_type *
+bfd_lookup_arch (arch, machine)
+ enum bfd_architecture arch;
+ long machine;
+{
+ bfd_arch_info_type *ap;
+ bfd_check_init();
+ for (ap = bfd_arch_info_list;
+ ap != (bfd_arch_info_type *)NULL;
+ ap = ap->next) {
+ if (ap->arch == arch &&
+ ((ap->mach == machine)
+ || (ap->the_default && machine == 0))) {
+ return ap;
+ }
+ }
+ return (bfd_arch_info_type *)NULL;
+}
+
+
+/*
+FUNCTION
+ bfd_printable_arch_mach
+
+SYNOPSIS
+ CONST char *bfd_printable_arch_mach
+ (enum bfd_architecture arch, unsigned long machine);
+
+DESCRIPTION
+ Return a printable string representing the architecture and
+ machine type.
+
+ This routine is depreciated.
+*/
+
+CONST char *
+bfd_printable_arch_mach (arch, machine)
+ enum bfd_architecture arch;
+ unsigned long machine;
+{
+ bfd_arch_info_type *ap = bfd_lookup_arch(arch, machine);
+ if(ap) return ap->printable_name;
+ return "UNKNOWN!";
+}
diff --git a/gnu/usr.bin/gdb/bfd/bfd.c b/gnu/usr.bin/gdb/bfd/bfd.c
new file mode 100644
index 0000000..d6372ac
--- /dev/null
+++ b/gnu/usr.bin/gdb/bfd/bfd.c
@@ -0,0 +1,825 @@
+/* Generic BFD library interface and support routines.
+ Copyright (C) 1990, 91, 92, 93, 94 Free Software Foundation, Inc.
+ Written by Cygnus Support.
+
+This file is part of BFD, the Binary File Descriptor library.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/*
+SECTION
+ <<typedef bfd>>
+
+ A BFD has type <<bfd>>; objects of this type are the
+ cornerstone of any application using BFD. Using BFD
+ consists of making references though the BFD and to data in the BFD.
+
+ Here is the structure that defines the type <<bfd>>. It
+ contains the major data about the file and pointers
+ to the rest of the data.
+
+CODE_FRAGMENT
+.
+.struct _bfd
+.{
+. {* The filename the application opened the BFD with. *}
+. CONST char *filename;
+.
+. {* A pointer to the target jump table. *}
+. const struct bfd_target *xvec;
+.
+. {* To avoid dragging too many header files into every file that
+. includes `<<bfd.h>>', IOSTREAM has been declared as a "char
+. *", and MTIME as a "long". Their correct types, to which they
+. are cast when used, are "FILE *" and "time_t". The iostream
+. is the result of an fopen on the filename. *}
+. char *iostream;
+.
+. {* Is the file descriptor being cached? That is, can it be closed as
+. needed, and re-opened when accessed later? *}
+.
+. boolean cacheable;
+.
+. {* Marks whether there was a default target specified when the
+. BFD was opened. This is used to select which matching algorithm
+. to use to choose the back end. *}
+.
+. boolean target_defaulted;
+.
+. {* The caching routines use these to maintain a
+. least-recently-used list of BFDs *}
+.
+. struct _bfd *lru_prev, *lru_next;
+.
+. {* When a file is closed by the caching routines, BFD retains
+. state information on the file here: *}
+.
+. file_ptr where;
+.
+. {* and here: (``once'' means at least once) *}
+.
+. boolean opened_once;
+.
+. {* Set if we have a locally maintained mtime value, rather than
+. getting it from the file each time: *}
+.
+. boolean mtime_set;
+.
+. {* File modified time, if mtime_set is true: *}
+.
+. long mtime;
+.
+. {* Reserved for an unimplemented file locking extension.*}
+.
+. int ifd;
+.
+. {* The format which belongs to the BFD. (object, core, etc.) *}
+.
+. bfd_format format;
+.
+. {* The direction the BFD was opened with*}
+.
+. enum bfd_direction {no_direction = 0,
+. read_direction = 1,
+. write_direction = 2,
+. both_direction = 3} direction;
+.
+. {* Format_specific flags*}
+.
+. flagword flags;
+.
+. {* Currently my_archive is tested before adding origin to
+. anything. I believe that this can become always an add of
+. origin, with origin set to 0 for non archive files. *}
+.
+. file_ptr origin;
+.
+. {* Remember when output has begun, to stop strange things
+. from happening. *}
+. boolean output_has_begun;
+.
+. {* Pointer to linked list of sections*}
+. struct sec *sections;
+.
+. {* The number of sections *}
+. unsigned int section_count;
+.
+. {* Stuff only useful for object files:
+. The start address. *}
+. bfd_vma start_address;
+.
+. {* Used for input and output*}
+. unsigned int symcount;
+.
+. {* Symbol table for output BFD (with symcount entries) *}
+. struct symbol_cache_entry **outsymbols;
+.
+. {* Pointer to structure which contains architecture information*}
+. struct bfd_arch_info *arch_info;
+.
+. {* Stuff only useful for archives:*}
+. PTR arelt_data;
+. struct _bfd *my_archive; {* The containing archive BFD. *}
+. struct _bfd *next; {* The next BFD in the archive. *}
+. struct _bfd *archive_head; {* The first BFD in the archive. *}
+. boolean has_armap;
+.
+. {* A chain of BFD structures involved in a link. *}
+. struct _bfd *link_next;
+.
+. {* A field used by _bfd_generic_link_add_archive_symbols. This will
+. be used only for archive elements. *}
+. int archive_pass;
+.
+. {* Used by the back end to hold private data. *}
+.
+. union
+. {
+. struct aout_data_struct *aout_data;
+. struct artdata *aout_ar_data;
+. struct _oasys_data *oasys_obj_data;
+. struct _oasys_ar_data *oasys_ar_data;
+. struct coff_tdata *coff_obj_data;
+. struct ecoff_tdata *ecoff_obj_data;
+. struct ieee_data_struct *ieee_data;
+. struct ieee_ar_data_struct *ieee_ar_data;
+. struct srec_data_struct *srec_data;
+. struct tekhex_data_struct *tekhex_data;
+. struct elf_obj_tdata *elf_obj_data;
+. struct nlm_obj_tdata *nlm_obj_data;
+. struct bout_data_struct *bout_data;
+. struct sun_core_struct *sun_core_data;
+. struct trad_core_struct *trad_core_data;
+. struct som_data_struct *som_data;
+. struct hpux_core_struct *hpux_core_data;
+. struct hppabsd_core_struct *hppabsd_core_data;
+. struct sgi_core_struct *sgi_core_data;
+. struct lynx_core_struct *lynx_core_data;
+. struct osf_core_struct *osf_core_data;
+. struct cisco_core_struct *cisco_core_data;
+. PTR any;
+. } tdata;
+.
+. {* Used by the application to hold private data*}
+. PTR usrdata;
+.
+. {* Where all the allocated stuff under this BFD goes *}
+. struct obstack memory;
+.};
+.
+*/
+
+#include "bfd.h"
+#include "sysdep.h"
+#include "bfdlink.h"
+#include "libbfd.h"
+#include "coff/internal.h"
+#include "coff/sym.h"
+#include "libcoff.h"
+#include "libecoff.h"
+#undef obj_symbols
+#include "libelf.h"
+
+
+/*
+SECTION
+ Error reporting
+
+ Most BFD functions return nonzero on success (check their
+ individual documentation for precise semantics). On an error,
+ they call <<bfd_set_error>> to set an error condition that callers
+ can check by calling <<bfd_get_error>>.
+ If that returns <<bfd_error_system_call>>, then check
+ <<errno>>.
+
+ The easiest way to report a BFD error to the user is to
+ use <<bfd_perror>>.
+
+SUBSECTION
+ Type <<bfd_error_type>>
+
+ The values returned by <<bfd_get_error>> are defined by the
+ enumerated type <<bfd_error_type>>.
+
+CODE_FRAGMENT
+.
+.typedef enum bfd_error
+.{
+. bfd_error_no_error = 0,
+. bfd_error_system_call,
+. bfd_error_invalid_target,
+. bfd_error_wrong_format,
+. bfd_error_invalid_operation,
+. bfd_error_no_memory,
+. bfd_error_no_symbols,
+. bfd_error_no_more_archived_files,
+. bfd_error_malformed_archive,
+. bfd_error_file_not_recognized,
+. bfd_error_file_ambiguously_recognized,
+. bfd_error_no_contents,
+. bfd_error_nonrepresentable_section,
+. bfd_error_no_debug_section,
+. bfd_error_bad_value,
+. bfd_error_file_truncated,
+. bfd_error_invalid_error_code
+.} bfd_error_type;
+.
+*/
+
+#undef strerror
+extern char *strerror();
+
+static bfd_error_type bfd_error = bfd_error_no_error;
+
+CONST char *CONST bfd_errmsgs[] = {
+ "No error",
+ "System call error",
+ "Invalid bfd target",
+ "File in wrong format",
+ "Invalid operation",
+ "Memory exhausted",
+ "No symbols",
+ "No more archived files",
+ "Malformed archive",
+ "File format not recognized",
+ "File format is ambiguous",
+ "Section has no contents",
+ "Nonrepresentable section on output",
+ "Symbol needs debug section which does not exist",
+ "Bad value",
+ "File truncated",
+ "#<Invalid error code>"
+ };
+
+/*
+FUNCTION
+ bfd_get_error
+
+SYNOPSIS
+ bfd_error_type bfd_get_error (void);
+
+DESCRIPTION
+ Return the current BFD error condition.
+*/
+
+bfd_error_type
+bfd_get_error ()
+{
+ return bfd_error;
+}
+
+/*
+FUNCTION
+ bfd_set_error
+
+SYNOPSIS
+ void bfd_set_error (bfd_error_type error_tag);
+
+DESCRIPTION
+ Set the BFD error condition to be @var{error_tag}.
+*/
+
+void
+bfd_set_error (error_tag)
+ bfd_error_type error_tag;
+{
+ bfd_error = error_tag;
+}
+
+/*
+FUNCTION
+ bfd_errmsg
+
+SYNOPSIS
+ CONST char *bfd_errmsg (bfd_error_type error_tag);
+
+DESCRIPTION
+ Return a string describing the error @var{error_tag}, or
+ the system error if @var{error_tag} is <<bfd_error_system_call>>.
+*/
+
+CONST char *
+bfd_errmsg (error_tag)
+ bfd_error_type error_tag;
+{
+#ifndef errno
+ extern int errno;
+#endif
+ if (error_tag == bfd_error_system_call)
+ return strerror (errno);
+
+ if ((((int)error_tag <(int) bfd_error_no_error) ||
+ ((int)error_tag > (int)bfd_error_invalid_error_code)))
+ error_tag = bfd_error_invalid_error_code;/* sanity check */
+
+ return bfd_errmsgs [(int)error_tag];
+}
+
+/*
+FUNCTION
+ bfd_perror
+
+SYNOPSIS
+ void bfd_perror (CONST char *message);
+
+DESCRIPTION
+ Print to the standard error stream a string describing the
+ last BFD error that occurred, or the last system error if
+ the last BFD error was a system call failure. If @var{message}
+ is non-NULL and non-empty, the error string printed is preceded
+ by @var{message}, a colon, and a space. It is followed by a newline.
+*/
+
+void
+bfd_perror (message)
+ CONST char *message;
+{
+ if (bfd_get_error () == bfd_error_system_call)
+ perror((char *)message); /* must be system error then... */
+ else {
+ if (message == NULL || *message == '\0')
+ fprintf (stderr, "%s\n", bfd_errmsg (bfd_get_error ()));
+ else
+ fprintf (stderr, "%s: %s\n", message, bfd_errmsg (bfd_get_error ()));
+ }
+}
+
+
+/*
+SECTION
+ Symbols
+*/
+
+/*
+FUNCTION
+ bfd_get_reloc_upper_bound
+
+SYNOPSIS
+ long bfd_get_reloc_upper_bound(bfd *abfd, asection *sect);
+
+DESCRIPTION
+ Return the number of bytes required to store the
+ relocation information associated with section @var{sect}
+ attached to bfd @var{abfd}. If an error occurs, return -1.
+
+*/
+
+
+long
+bfd_get_reloc_upper_bound (abfd, asect)
+ bfd *abfd;
+ sec_ptr asect;
+{
+ if (abfd->format != bfd_object) {
+ bfd_set_error (bfd_error_invalid_operation);
+ return -1;
+ }
+
+ return BFD_SEND (abfd, _get_reloc_upper_bound, (abfd, asect));
+}
+
+/*
+FUNCTION
+ bfd_canonicalize_reloc
+
+SYNOPSIS
+ long bfd_canonicalize_reloc
+ (bfd *abfd,
+ asection *sec,
+ arelent **loc,
+ asymbol **syms);
+
+DESCRIPTION
+ Call the back end associated with the open BFD
+ @var{abfd} and translate the external form of the relocation
+ information attached to @var{sec} into the internal canonical
+ form. Place the table into memory at @var{loc}, which has
+ been preallocated, usually by a call to
+ <<bfd_get_reloc_upper_bound>>. Returns the number of relocs, or
+ -1 on error.
+
+ The @var{syms} table is also needed for horrible internal magic
+ reasons.
+
+
+*/
+long
+bfd_canonicalize_reloc (abfd, asect, location, symbols)
+ bfd *abfd;
+ sec_ptr asect;
+ arelent **location;
+ asymbol **symbols;
+{
+ if (abfd->format != bfd_object) {
+ bfd_set_error (bfd_error_invalid_operation);
+ return -1;
+ }
+ return BFD_SEND (abfd, _bfd_canonicalize_reloc,
+ (abfd, asect, location, symbols));
+}
+
+/*
+FUNCTION
+ bfd_set_reloc
+
+SYNOPSIS
+ void bfd_set_reloc
+ (bfd *abfd, asection *sec, arelent **rel, unsigned int count)
+
+DESCRIPTION
+ Set the relocation pointer and count within
+ section @var{sec} to the values @var{rel} and @var{count}.
+ The argument @var{abfd} is ignored.
+
+*/
+/*ARGSUSED*/
+void
+bfd_set_reloc (ignore_abfd, asect, location, count)
+ bfd *ignore_abfd;
+ sec_ptr asect;
+ arelent **location;
+ unsigned int count;
+{
+ asect->orelocation = location;
+ asect->reloc_count = count;
+}
+
+/*
+FUNCTION
+ bfd_set_file_flags
+
+SYNOPSIS
+ boolean bfd_set_file_flags(bfd *abfd, flagword flags);
+
+DESCRIPTION
+ Set the flag word in the BFD @var{abfd} to the value @var{flags}.
+
+ Possible errors are:
+ o <<bfd_error_wrong_format>> - The target bfd was not of object format.
+ o <<bfd_error_invalid_operation>> - The target bfd was open for reading.
+ o <<bfd_error_invalid_operation>> -
+ The flag word contained a bit which was not applicable to the
+ type of file. E.g., an attempt was made to set the <<D_PAGED>> bit
+ on a BFD format which does not support demand paging.
+
+*/
+
+boolean
+bfd_set_file_flags (abfd, flags)
+ bfd *abfd;
+ flagword flags;
+{
+ if (abfd->format != bfd_object) {
+ bfd_set_error (bfd_error_wrong_format);
+ return false;
+ }
+
+ if (bfd_read_p (abfd)) {
+ bfd_set_error (bfd_error_invalid_operation);
+ return false;
+ }
+
+ bfd_get_file_flags (abfd) = flags;
+ if ((flags & bfd_applicable_file_flags (abfd)) != flags) {
+ bfd_set_error (bfd_error_invalid_operation);
+ return false;
+ }
+
+return true;
+}
+
+void
+bfd_assert(file, line)
+char *file;
+int line;
+{
+ fprintf(stderr, "bfd assertion fail %s:%d\n",file,line);
+}
+
+
+/*
+FUNCTION
+ bfd_set_start_address
+
+SYNOPSIS
+ boolean bfd_set_start_address(bfd *abfd, bfd_vma vma);
+
+DESCRIPTION
+ Make @var{vma} the entry point of output BFD @var{abfd}.
+
+RETURNS
+ Returns <<true>> on success, <<false>> otherwise.
+*/
+
+boolean
+bfd_set_start_address(abfd, vma)
+bfd *abfd;
+bfd_vma vma;
+{
+ abfd->start_address = vma;
+ return true;
+}
+
+
+/*
+FUNCTION
+ bfd_get_mtime
+
+SYNOPSIS
+ long bfd_get_mtime(bfd *abfd);
+
+DESCRIPTION
+ Return the file modification time (as read from the file system, or
+ from the archive header for archive members).
+
+*/
+
+long
+bfd_get_mtime (abfd)
+ bfd *abfd;
+{
+ FILE *fp;
+ struct stat buf;
+
+ if (abfd->mtime_set)
+ return abfd->mtime;
+
+ fp = bfd_cache_lookup (abfd);
+ if (0 != fstat (fileno (fp), &buf))
+ return 0;
+
+ abfd->mtime = buf.st_mtime; /* Save value in case anyone wants it */
+ return buf.st_mtime;
+}
+
+/*
+FUNCTION
+ bfd_get_size
+
+SYNOPSIS
+ long bfd_get_size(bfd *abfd);
+
+DESCRIPTION
+ Return the file size (as read from file system) for the file
+ associated with BFD @var{abfd}.
+
+ The initial motivation for, and use of, this routine is not
+ so we can get the exact size of the object the BFD applies to, since
+ that might not be generally possible (archive members for example).
+ It would be ideal if someone could eventually modify
+ it so that such results were guaranteed.
+
+ Instead, we want to ask questions like "is this NNN byte sized
+ object I'm about to try read from file offset YYY reasonable?"
+ As as example of where we might do this, some object formats
+ use string tables for which the first <<sizeof(long)>> bytes of the
+ table contain the size of the table itself, including the size bytes.
+ If an application tries to read what it thinks is one of these
+ string tables, without some way to validate the size, and for
+ some reason the size is wrong (byte swapping error, wrong location
+ for the string table, etc.), the only clue is likely to be a read
+ error when it tries to read the table, or a "virtual memory
+ exhausted" error when it tries to allocate 15 bazillon bytes
+ of space for the 15 bazillon byte table it is about to read.
+ This function at least allows us to answer the quesion, "is the
+ size reasonable?".
+*/
+
+long
+bfd_get_size (abfd)
+ bfd *abfd;
+{
+ FILE *fp;
+ struct stat buf;
+
+ fp = bfd_cache_lookup (abfd);
+ if (0 != fstat (fileno (fp), &buf))
+ return 0;
+
+ return buf.st_size;
+}
+
+/*
+FUNCTION
+ bfd_get_gp_size
+
+SYNOPSIS
+ int bfd_get_gp_size(bfd *abfd);
+
+DESCRIPTION
+ Return the maximum size of objects to be optimized using the GP
+ register under MIPS ECOFF. This is typically set by the <<-G>>
+ argument to the compiler, assembler or linker.
+*/
+
+int
+bfd_get_gp_size (abfd)
+ bfd *abfd;
+{
+ if (abfd->format == bfd_object)
+ {
+ if (abfd->xvec->flavour == bfd_target_ecoff_flavour)
+ return ecoff_data (abfd)->gp_size;
+ else if (abfd->xvec->flavour == bfd_target_elf_flavour)
+ return elf_gp_size (abfd);
+ }
+ return 0;
+}
+
+/*
+FUNCTION
+ bfd_set_gp_size
+
+SYNOPSIS
+ void bfd_set_gp_size(bfd *abfd, int i);
+
+DESCRIPTION
+ Set the maximum size of objects to be optimized using the GP
+ register under ECOFF or MIPS ELF. This is typically set by
+ the <<-G>> argument to the compiler, assembler or linker.
+*/
+
+void
+bfd_set_gp_size (abfd, i)
+ bfd *abfd;
+ int i;
+{
+ /* Don't try to set GP size on an archive or core file! */
+ if (abfd->format != bfd_object)
+ return;
+ if (abfd->xvec->flavour == bfd_target_ecoff_flavour)
+ ecoff_data (abfd)->gp_size = i;
+ else if (abfd->xvec->flavour == bfd_target_elf_flavour)
+ elf_gp_size (abfd) = i;
+}
+
+/*
+FUNCTION
+ bfd_scan_vma
+
+SYNOPSIS
+ bfd_vma bfd_scan_vma(CONST char *string, CONST char **end, int base);
+
+DESCRIPTION
+ Convert, like <<strtoul>>, a numerical expression
+ @var{string} into a <<bfd_vma>> integer, and return that integer.
+ (Though without as many bells and whistles as <<strtoul>>.)
+ The expression is assumed to be unsigned (i.e., positive).
+ If given a @var{base}, it is used as the base for conversion.
+ A base of 0 causes the function to interpret the string
+ in hex if a leading "0x" or "0X" is found, otherwise
+ in octal if a leading zero is found, otherwise in decimal.
+
+ Overflow is not detected.
+*/
+
+bfd_vma
+bfd_scan_vma (string, end, base)
+ CONST char *string;
+ CONST char **end;
+ int base;
+{
+ bfd_vma value;
+ int digit;
+
+ /* Let the host do it if possible. */
+ if (sizeof(bfd_vma) <= sizeof(unsigned long))
+ return (bfd_vma) strtoul (string, 0, base);
+
+ /* A negative base makes no sense, and we only need to go as high as hex. */
+ if ((base < 0) || (base > 16))
+ return (bfd_vma) 0;
+
+ if (base == 0)
+ {
+ if (string[0] == '0')
+ {
+ if ((string[1] == 'x') || (string[1] == 'X'))
+ base = 16;
+ /* XXX should we also allow "0b" or "0B" to set base to 2? */
+ else
+ base = 8;
+ }
+ else
+ base = 10;
+ }
+ if ((base == 16) &&
+ (string[0] == '0') && ((string[1] == 'x') || (string[1] == 'X')))
+ string += 2;
+ /* XXX should we also skip over "0b" or "0B" if base is 2? */
+
+/* Speed could be improved with a table like hex_value[] in gas. */
+#define HEX_VALUE(c) \
+ (isxdigit(c) ? \
+ (isdigit(c) ? \
+ (c - '0') : \
+ (10 + c - (islower(c) ? 'a' : 'A'))) : \
+ 42)
+
+ for (value = 0; (digit = HEX_VALUE(*string)) < base; string++)
+ {
+ value = value * base + digit;
+ }
+
+ if (end)
+ *end = string;
+
+ return value;
+}
+
+/*
+FUNCTION
+ bfd_copy_private_bfd_data
+
+SYNOPSIS
+ boolean bfd_copy_private_bfd_data(bfd *ibfd, bfd *obfd);
+
+DESCRIPTION
+ Copy private BFD information from the BFD @var{ibfd} to the
+ the BFD @var{obfd}. Return <<true>> on success, <<false>> on error.
+ Possible error returns are:
+
+ o <<bfd_error_no_memory>> -
+ Not enough memory exists to create private data for @var{obfd}.
+
+.#define bfd_copy_private_bfd_data(ibfd, obfd) \
+. BFD_SEND (ibfd, _bfd_copy_private_bfd_data, \
+. (ibfd, obfd))
+
+*/
+
+/*
+FUNCTION
+ stuff
+
+DESCRIPTION
+ Stuff which should be documented:
+
+.#define bfd_sizeof_headers(abfd, reloc) \
+. BFD_SEND (abfd, _bfd_sizeof_headers, (abfd, reloc))
+.
+.#define bfd_find_nearest_line(abfd, sec, syms, off, file, func, line) \
+. BFD_SEND (abfd, _bfd_find_nearest_line, (abfd, sec, syms, off, file, func, line))
+.
+. {* Do these three do anything useful at all, for any back end? *}
+.#define bfd_debug_info_start(abfd) \
+. BFD_SEND (abfd, _bfd_debug_info_start, (abfd))
+.
+.#define bfd_debug_info_end(abfd) \
+. BFD_SEND (abfd, _bfd_debug_info_end, (abfd))
+.
+.#define bfd_debug_info_accumulate(abfd, section) \
+. BFD_SEND (abfd, _bfd_debug_info_accumulate, (abfd, section))
+.
+.
+.#define bfd_stat_arch_elt(abfd, stat) \
+. BFD_SEND (abfd, _bfd_stat_arch_elt,(abfd, stat))
+.
+.#define bfd_set_arch_mach(abfd, arch, mach)\
+. BFD_SEND ( abfd, _bfd_set_arch_mach, (abfd, arch, mach))
+.
+.#define bfd_get_relocated_section_contents(abfd, link_info, link_order, data, relocateable, symbols) \
+. BFD_SEND (abfd, _bfd_get_relocated_section_contents, \
+. (abfd, link_info, link_order, data, relocateable, symbols))
+.
+.#define bfd_relax_section(abfd, section, link_info, again) \
+. BFD_SEND (abfd, _bfd_relax_section, (abfd, section, link_info, again))
+.
+.#define bfd_link_hash_table_create(abfd) \
+. BFD_SEND (abfd, _bfd_link_hash_table_create, (abfd))
+.
+.#define bfd_link_add_symbols(abfd, info) \
+. BFD_SEND (abfd, _bfd_link_add_symbols, (abfd, info))
+.
+.#define bfd_final_link(abfd, info) \
+. BFD_SEND (abfd, _bfd_final_link, (abfd, info))
+.
+.#define bfd_free_cached_info(abfd) \
+. BFD_SEND (abfd, _bfd_free_cached_info, (abfd))
+.
+.#define bfd_get_dynamic_symtab_upper_bound(abfd) \
+. BFD_SEND (abfd, _bfd_get_dynamic_symtab_upper_bound, (abfd))
+.
+.#define bfd_canonicalize_dynamic_symtab(abfd, asymbols) \
+. BFD_SEND (abfd, _bfd_canonicalize_dynamic_symtab, (abfd, asymbols))
+.
+.#define bfd_get_dynamic_reloc_upper_bound(abfd) \
+. BFD_SEND (abfd, _bfd_get_dynamic_reloc_upper_bound, (abfd))
+.
+.#define bfd_canonicalize_dynamic_reloc(abfd, arels, asyms) \
+. BFD_SEND (abfd, _bfd_canonicalize_dynamic_reloc, (abfd, arels, asyms))
+.
+
+*/
diff --git a/gnu/usr.bin/gdb/bfd/bfd.h b/gnu/usr.bin/gdb/bfd/bfd.h
new file mode 100644
index 0000000..78b0e9f
--- /dev/null
+++ b/gnu/usr.bin/gdb/bfd/bfd.h
@@ -0,0 +1,2151 @@
+/* Main header file for the bfd library -- portable access to object files.
+ Copyright 1990, 1991, 1992, 1993, 1994 Free Software Foundation, Inc.
+ Contributed by Cygnus Support.
+
+** NOTE: bfd.h and bfd-in2.h are GENERATED files. Don't change them;
+** instead, change bfd-in.h or the other BFD source files processed to
+** generate these files.
+
+This file is part of BFD, the Binary File Descriptor library.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* bfd.h -- The only header file required by users of the bfd library
+
+The bfd.h file is generated from bfd-in.h and various .c files; if you
+change it, your changes will probably be lost.
+
+All the prototypes and definitions following the comment "THE FOLLOWING
+IS EXTRACTED FROM THE SOURCE" are extracted from the source files for
+BFD. If you change it, someone oneday will extract it from the source
+again, and your changes will be lost. To save yourself from this bind,
+change the definitions in the source in the bfd directory. Type "make
+docs" and then "make headers" in that directory, and magically this file
+will change to reflect your changes.
+
+If you don't have the tools to perform the extraction, then you are
+safe from someone on your system trampling over your header files.
+You should still maintain the equivalence between the source and this
+file though; every change you make to the .c file should be reflected
+here. */
+
+#ifndef __BFD_H_SEEN__
+#define __BFD_H_SEEN__
+
+#include "ansidecl.h"
+#include "obstack.h"
+
+/* These two lines get substitutions done by commands in Makefile.in. */
+#define BFD_VERSION "cygnus-2.3"
+#define BFD_ARCH_SIZE 32
+
+#if BFD_ARCH_SIZE >= 64
+#define BFD64
+#endif
+
+#ifndef INLINE
+#if __GNUC__ >= 2
+#define INLINE __inline__
+#else
+#define INLINE
+#endif
+#endif
+
+/* 64-bit type definition (if any) from bfd's sysdep.h goes here */
+
+
+/* forward declaration */
+typedef struct _bfd bfd;
+
+/* To squelch erroneous compiler warnings ("illegal pointer
+ combination") from the SVR3 compiler, we would like to typedef
+ boolean to int (it doesn't like functions which return boolean.
+ Making sure they are never implicitly declared to return int
+ doesn't seem to help). But this file is not configured based on
+ the host. */
+/* General rules: functions which are boolean return true on success
+ and false on failure (unless they're a predicate). -- bfd.doc */
+/* I'm sure this is going to break something and someone is going to
+ force me to change it. */
+/* typedef enum boolean {false, true} boolean; */
+/* Yup, SVR4 has a "typedef enum boolean" in <sys/types.h> -fnf */
+/* It gets worse if the host also defines a true/false enum... -sts */
+#ifndef TRUE_FALSE_ALREADY_DEFINED
+typedef enum bfd_boolean {false, true} boolean;
+#define BFD_TRUE_FALSE
+#else
+typedef enum bfd_boolean {bfd_false, bfd_true} boolean;
+#endif
+
+/* A pointer to a position in a file. */
+/* FIXME: This should be using off_t from <sys/types.h>.
+ For now, try to avoid breaking stuff by not including <sys/types.h> here.
+ This will break on systems with 64-bit file offsets (e.g. 4.4BSD).
+ Probably the best long-term answer is to avoid using file_ptr AND off_t
+ in this header file, and to handle this in the BFD implementation
+ rather than in its interface. */
+/* typedef off_t file_ptr; */
+typedef long int file_ptr;
+
+/* Support for different sizes of target format ints and addresses. If the
+ host implements 64-bit values, it defines BFD_HOST_64_BIT to be the appropriate
+ type. Otherwise, this code will fall back on gcc's "long long" type if gcc
+ is being used. BFD_HOST_64_BIT must be defined in such a way as to be a valid
+ type name by itself or with "unsigned" prefixed. It should be a signed
+ type by itself.
+
+ If neither is the case, then compilation will fail if 64-bit targets are
+ requested. If you don't request any 64-bit targets, you should be safe. */
+
+#ifdef BFD64
+
+#if defined (__GNUC__) && !defined (BFD_HOST_64_BIT)
+#define BFD_HOST_64_BIT long long
+typedef BFD_HOST_64_BIT int64_type;
+typedef unsigned BFD_HOST_64_BIT uint64_type;
+#endif
+
+#if !defined (uint64_type) && defined (__GNUC__)
+#define uint64_type unsigned long long
+#define int64_type long long
+#endif
+#ifndef uint64_typeLOW
+#define uint64_typeLOW(x) ((unsigned long)(((x) & 0xffffffff)))
+#define uint64_typeHIGH(x) ((unsigned long)(((x) >> 32) & 0xffffffff))
+#endif
+
+typedef unsigned BFD_HOST_64_BIT bfd_vma;
+typedef BFD_HOST_64_BIT bfd_signed_vma;
+typedef unsigned BFD_HOST_64_BIT bfd_size_type;
+typedef unsigned BFD_HOST_64_BIT symvalue;
+#ifndef fprintf_vma
+#define fprintf_vma(s,x) \
+ fprintf(s,"%08lx%08lx", uint64_typeHIGH(x), uint64_typeLOW(x))
+#define sprintf_vma(s,x) \
+ sprintf(s,"%08lx%08lx", uint64_typeHIGH(x), uint64_typeLOW(x))
+#endif
+#else /* not BFD64 */
+
+/* Represent a target address. Also used as a generic unsigned type
+ which is guaranteed to be big enough to hold any arithmetic types
+ we need to deal with. */
+typedef unsigned long bfd_vma;
+
+/* A generic signed type which is guaranteed to be big enough to hold any
+ arithmetic types we need to deal with. Can be assumed to be compatible
+ with bfd_vma in the same way that signed and unsigned ints are compatible
+ (as parameters, in assignment, etc). */
+typedef long bfd_signed_vma;
+
+typedef unsigned long symvalue;
+typedef unsigned long bfd_size_type;
+
+/* Print a bfd_vma x on stream s. */
+#define fprintf_vma(s,x) fprintf(s, "%08lx", x)
+#define sprintf_vma(s,x) sprintf(s, "%08lx", x)
+#endif /* not BFD64 */
+#define printf_vma(x) fprintf_vma(stdout,x)
+
+typedef unsigned int flagword; /* 32 bits of flags */
+
+/** File formats */
+
+typedef enum bfd_format {
+ bfd_unknown = 0, /* file format is unknown */
+ bfd_object, /* linker/assember/compiler output */
+ bfd_archive, /* object archive file */
+ bfd_core, /* core dump */
+ bfd_type_end} /* marks the end; don't use it! */
+ bfd_format;
+
+/* Values that may appear in the flags field of a BFD. These also
+ appear in the object_flags field of the bfd_target structure, where
+ they indicate the set of flags used by that backend (not all flags
+ are meaningful for all object file formats) (FIXME: at the moment,
+ the object_flags values have mostly just been copied from backend
+ to another, and are not necessarily correct). */
+
+/* No flags. */
+#define NO_FLAGS 0x00
+
+/* BFD contains relocation entries. */
+#define HAS_RELOC 0x01
+
+/* BFD is directly executable. */
+#define EXEC_P 0x02
+
+/* BFD has line number information (basically used for F_LNNO in a
+ COFF header). */
+#define HAS_LINENO 0x04
+
+/* BFD has debugging information. */
+#define HAS_DEBUG 0x08
+
+/* BFD has symbols. */
+#define HAS_SYMS 0x10
+
+/* BFD has local symbols (basically used for F_LSYMS in a COFF
+ header). */
+#define HAS_LOCALS 0x20
+
+/* BFD is a dynamic object. */
+#define DYNAMIC 0x40
+
+/* Text section is write protected (if D_PAGED is not set, this is
+ like an a.out NMAGIC file) (the linker sets this by default, but
+ clears it for -r or -N). */
+#define WP_TEXT 0x80
+
+/* BFD is dynamically paged (this is like an a.out ZMAGIC file) (the
+ linker sets this by default, but clears it for -r or -n or -N). */
+#define D_PAGED 0x100
+
+/* BFD is relaxable (this means that bfd_relax_section may be able to
+ do something). */
+#define BFD_IS_RELAXABLE 0x200
+
+/* This may be set before writing out a BFD to request using a
+ traditional format. For example, this is used to request that when
+ writing out an a.out object the symbols not be hashed to eliminate
+ duplicates. */
+#define BFD_TRADITIONAL_FORMAT 0x400
+
+/* symbols and relocation */
+
+/* A count of carsyms (canonical archive symbols). */
+typedef unsigned long symindex;
+
+#define BFD_NO_MORE_SYMBOLS ((symindex) ~0)
+
+/* General purpose part of a symbol X;
+ target specific parts are in libcoff.h, libaout.h, etc. */
+
+#define bfd_get_section(x) ((x)->section)
+#define bfd_get_output_section(x) ((x)->section->output_section)
+#define bfd_set_section(x,y) ((x)->section) = (y)
+#define bfd_asymbol_base(x) ((x)->section->vma)
+#define bfd_asymbol_value(x) (bfd_asymbol_base(x) + (x)->value)
+#define bfd_asymbol_name(x) ((x)->name)
+/*Perhaps future: #define bfd_asymbol_bfd(x) ((x)->section->owner)*/
+#define bfd_asymbol_bfd(x) ((x)->the_bfd)
+#define bfd_asymbol_flavour(x) (bfd_asymbol_bfd(x)->xvec->flavour)
+
+/* A canonical archive symbol. */
+/* This is a type pun with struct ranlib on purpose! */
+typedef struct carsym {
+ char *name;
+ file_ptr file_offset; /* look here to find the file */
+} carsym; /* to make these you call a carsymogen */
+
+
+/* Used in generating armaps (archive tables of contents).
+ Perhaps just a forward definition would do? */
+struct orl { /* output ranlib */
+ char **name; /* symbol name */
+ file_ptr pos; /* bfd* or file position */
+ int namidx; /* index into string table */
+};
+
+
+
+/* Linenumber stuff */
+typedef struct lineno_cache_entry {
+ unsigned int line_number; /* Linenumber from start of function*/
+ union {
+ struct symbol_cache_entry *sym; /* Function name */
+ unsigned long offset; /* Offset into section */
+ } u;
+} alent;
+
+/* object and core file sections */
+
+
+#define align_power(addr, align) \
+ ( ((addr) + ((1<<(align))-1)) & (-1 << (align)))
+
+typedef struct sec *sec_ptr;
+
+#define bfd_get_section_name(bfd, ptr) ((ptr)->name + 0)
+#define bfd_get_section_vma(bfd, ptr) ((ptr)->vma + 0)
+#define bfd_get_section_alignment(bfd, ptr) ((ptr)->alignment_power + 0)
+#define bfd_section_name(bfd, ptr) ((ptr)->name)
+#define bfd_section_size(bfd, ptr) (bfd_get_section_size_before_reloc(ptr))
+#define bfd_section_vma(bfd, ptr) ((ptr)->vma)
+#define bfd_section_alignment(bfd, ptr) ((ptr)->alignment_power)
+#define bfd_get_section_flags(bfd, ptr) ((ptr)->flags + 0)
+#define bfd_get_section_userdata(bfd, ptr) ((ptr)->userdata)
+
+#define bfd_is_com_section(ptr) (((ptr)->flags & SEC_IS_COMMON) != 0)
+
+#define bfd_set_section_vma(bfd, ptr, val) (((ptr)->vma = (ptr)->lma= (val)), ((ptr)->user_set_vma = true), true)
+#define bfd_set_section_alignment(bfd, ptr, val) (((ptr)->alignment_power = (val)),true)
+#define bfd_set_section_userdata(bfd, ptr, val) (((ptr)->userdata = (val)),true)
+
+typedef struct stat stat_type;
+
+typedef enum bfd_print_symbol
+{
+ bfd_print_symbol_name,
+ bfd_print_symbol_more,
+ bfd_print_symbol_all
+} bfd_print_symbol_type;
+
+/* Information about a symbol that nm needs. */
+
+typedef struct _symbol_info
+{
+ symvalue value;
+ char type;
+ CONST char *name; /* Symbol name. */
+ char stab_other; /* Unused. */
+ short stab_desc; /* Info for N_TYPE. */
+ CONST char *stab_name;
+} symbol_info;
+
+/* Hash table routines. There is no way to free up a hash table. */
+
+/* An element in the hash table. Most uses will actually use a larger
+ structure, and an instance of this will be the first field. */
+
+struct bfd_hash_entry
+{
+ /* Next entry for this hash code. */
+ struct bfd_hash_entry *next;
+ /* String being hashed. */
+ const char *string;
+ /* Hash code. This is the full hash code, not the index into the
+ table. */
+ unsigned long hash;
+};
+
+/* A hash table. */
+
+struct bfd_hash_table
+{
+ /* The hash array. */
+ struct bfd_hash_entry **table;
+ /* The number of slots in the hash table. */
+ unsigned int size;
+ /* A function used to create new elements in the hash table. The
+ first entry is itself a pointer to an element. When this
+ function is first invoked, this pointer will be NULL. However,
+ having the pointer permits a hierarchy of method functions to be
+ built each of which calls the function in the superclass. Thus
+ each function should be written to allocate a new block of memory
+ only if the argument is NULL. */
+ struct bfd_hash_entry *(*newfunc) PARAMS ((struct bfd_hash_entry *,
+ struct bfd_hash_table *,
+ const char *));
+ /* An obstack for this hash table. */
+ struct obstack memory;
+};
+
+/* Initialize a hash table. */
+extern boolean bfd_hash_table_init
+ PARAMS ((struct bfd_hash_table *,
+ struct bfd_hash_entry *(*) (struct bfd_hash_entry *,
+ struct bfd_hash_table *,
+ const char *)));
+
+/* Initialize a hash table specifying a size. */
+extern boolean bfd_hash_table_init_n
+ PARAMS ((struct bfd_hash_table *,
+ struct bfd_hash_entry *(*) (struct bfd_hash_entry *,
+ struct bfd_hash_table *,
+ const char *),
+ unsigned int size));
+
+/* Free up a hash table. */
+extern void bfd_hash_table_free PARAMS ((struct bfd_hash_table *));
+
+/* Look up a string in a hash table. If CREATE is true, a new entry
+ will be created for this string if one does not already exist. The
+ COPY argument must be true if this routine should copy the string
+ into newly allocated memory when adding an entry. */
+extern struct bfd_hash_entry *bfd_hash_lookup
+ PARAMS ((struct bfd_hash_table *, const char *, boolean create,
+ boolean copy));
+
+/* Base method for creating a hash table entry. */
+extern struct bfd_hash_entry *bfd_hash_newfunc
+ PARAMS ((struct bfd_hash_entry *, struct bfd_hash_table *,
+ const char *));
+
+/* Grab some space for a hash table entry. */
+extern PTR bfd_hash_allocate PARAMS ((struct bfd_hash_table *,
+ unsigned int));
+
+/* Traverse a hash table in a random order, calling a function on each
+ element. If the function returns false, the traversal stops. The
+ INFO argument is passed to the function. */
+extern void bfd_hash_traverse PARAMS ((struct bfd_hash_table *,
+ boolean (*) (struct bfd_hash_entry *,
+ PTR),
+ PTR info));
+
+/* Semi-portable string concatenation in cpp.
+ The CAT4 hack is to avoid a problem with some strict ANSI C preprocessors.
+ The problem is, "32_" is not a valid preprocessing token, and we don't
+ want extra underscores (e.g., "nlm_32_"). The XCAT2 macro will cause the
+ inner CAT macros to be evaluated first, producing still-valid pp-tokens.
+ Then the final concatenation can be done. (Sigh.) */
+#ifndef CAT
+#ifdef SABER
+#define CAT(a,b) a##b
+#define CAT3(a,b,c) a##b##c
+#define CAT4(a,b,c,d) a##b##c##d
+#else
+#if defined(__STDC__) || defined(ALMOST_STDC)
+#define CAT(a,b) a##b
+#define CAT3(a,b,c) a##b##c
+#define XCAT2(a,b) CAT(a,b)
+#define CAT4(a,b,c,d) XCAT2(CAT(a,b),CAT(c,d))
+#else
+#define CAT(a,b) a/**/b
+#define CAT3(a,b,c) a/**/b/**/c
+#define CAT4(a,b,c,d) a/**/b/**/c/**/d
+#endif
+#endif
+#endif
+
+#define COFF_SWAP_TABLE (PTR) &bfd_coff_std_swap_table
+
+/* User program access to BFD facilities */
+
+/* Cast from const char * to char * so that caller can assign to
+ a char * without a warning. */
+#define bfd_get_filename(abfd) ((char *) (abfd)->filename)
+#define bfd_get_cacheable(abfd) ((abfd)->cacheable)
+#define bfd_get_format(abfd) ((abfd)->format)
+#define bfd_get_target(abfd) ((abfd)->xvec->name)
+#define bfd_get_flavour(abfd) ((abfd)->xvec->flavour)
+#define bfd_get_file_flags(abfd) ((abfd)->flags)
+#define bfd_applicable_file_flags(abfd) ((abfd)->xvec->object_flags)
+#define bfd_applicable_section_flags(abfd) ((abfd)->xvec->section_flags)
+#define bfd_my_archive(abfd) ((abfd)->my_archive)
+#define bfd_has_map(abfd) ((abfd)->has_armap)
+
+#define bfd_valid_reloc_types(abfd) ((abfd)->xvec->valid_reloc_types)
+#define bfd_usrdata(abfd) ((abfd)->usrdata)
+
+#define bfd_get_start_address(abfd) ((abfd)->start_address)
+#define bfd_get_symcount(abfd) ((abfd)->symcount)
+#define bfd_get_outsymbols(abfd) ((abfd)->outsymbols)
+#define bfd_count_sections(abfd) ((abfd)->section_count)
+
+#define bfd_get_symbol_leading_char(abfd) ((abfd)->xvec->symbol_leading_char)
+
+#define bfd_set_cacheable(abfd,bool) (((abfd)->cacheable = (bool)), true)
+
+/* Byte swapping routines. */
+
+bfd_vma bfd_getb64 PARAMS ((const unsigned char *));
+bfd_vma bfd_getl64 PARAMS ((const unsigned char *));
+bfd_signed_vma bfd_getb_signed_64 PARAMS ((const unsigned char *));
+bfd_signed_vma bfd_getl_signed_64 PARAMS ((const unsigned char *));
+bfd_vma bfd_getb32 PARAMS ((const unsigned char *));
+bfd_vma bfd_getl32 PARAMS ((const unsigned char *));
+bfd_signed_vma bfd_getb_signed_32 PARAMS ((const unsigned char *));
+bfd_signed_vma bfd_getl_signed_32 PARAMS ((const unsigned char *));
+bfd_vma bfd_getb16 PARAMS ((const unsigned char *));
+bfd_vma bfd_getl16 PARAMS ((const unsigned char *));
+bfd_signed_vma bfd_getb_signed_16 PARAMS ((const unsigned char *));
+bfd_signed_vma bfd_getl_signed_16 PARAMS ((const unsigned char *));
+void bfd_putb64 PARAMS ((bfd_vma, unsigned char *));
+void bfd_putl64 PARAMS ((bfd_vma, unsigned char *));
+void bfd_putb32 PARAMS ((bfd_vma, unsigned char *));
+void bfd_putl32 PARAMS ((bfd_vma, unsigned char *));
+void bfd_putb16 PARAMS ((bfd_vma, unsigned char *));
+void bfd_putl16 PARAMS ((bfd_vma, unsigned char *));
+
+/* Externally visible ECOFF routines. */
+
+#if defined(__STDC__) || defined(ALMOST_STDC)
+struct ecoff_debug_info;
+struct ecoff_debug_swap;
+struct ecoff_extr;
+struct symbol_cache_entry;
+struct bfd_link_info;
+#endif
+extern bfd_vma bfd_ecoff_get_gp_value PARAMS ((bfd * abfd));
+extern boolean bfd_ecoff_set_gp_value PARAMS ((bfd *abfd, bfd_vma gp_value));
+extern boolean bfd_ecoff_set_regmasks
+ PARAMS ((bfd *abfd, unsigned long gprmask, unsigned long fprmask,
+ unsigned long *cprmask));
+extern PTR bfd_ecoff_debug_init
+ PARAMS ((bfd *output_bfd, struct ecoff_debug_info *output_debug,
+ const struct ecoff_debug_swap *output_swap,
+ struct bfd_link_info *));
+extern void bfd_ecoff_debug_free
+ PARAMS ((PTR handle, bfd *output_bfd, struct ecoff_debug_info *output_debug,
+ const struct ecoff_debug_swap *output_swap,
+ struct bfd_link_info *));
+extern boolean bfd_ecoff_debug_accumulate
+ PARAMS ((PTR handle, bfd *output_bfd, struct ecoff_debug_info *output_debug,
+ const struct ecoff_debug_swap *output_swap,
+ bfd *input_bfd, struct ecoff_debug_info *input_debug,
+ const struct ecoff_debug_swap *input_swap,
+ struct bfd_link_info *));
+extern boolean bfd_ecoff_debug_accumulate_other
+ PARAMS ((PTR handle, bfd *output_bfd, struct ecoff_debug_info *output_debug,
+ const struct ecoff_debug_swap *output_swap, bfd *input_bfd,
+ struct bfd_link_info *));
+extern boolean bfd_ecoff_debug_externals
+ PARAMS ((bfd *abfd, struct ecoff_debug_info *debug,
+ const struct ecoff_debug_swap *swap,
+ boolean relocateable,
+ boolean (*get_extr) (struct symbol_cache_entry *,
+ struct ecoff_extr *),
+ void (*set_index) (struct symbol_cache_entry *,
+ bfd_size_type)));
+extern boolean bfd_ecoff_debug_one_external
+ PARAMS ((bfd *abfd, struct ecoff_debug_info *debug,
+ const struct ecoff_debug_swap *swap,
+ const char *name, struct ecoff_extr *esym));
+extern bfd_size_type bfd_ecoff_debug_size
+ PARAMS ((bfd *abfd, struct ecoff_debug_info *debug,
+ const struct ecoff_debug_swap *swap));
+extern boolean bfd_ecoff_write_debug
+ PARAMS ((bfd *abfd, struct ecoff_debug_info *debug,
+ const struct ecoff_debug_swap *swap, file_ptr where));
+extern boolean bfd_ecoff_write_accumulated_debug
+ PARAMS ((PTR handle, bfd *abfd, struct ecoff_debug_info *debug,
+ const struct ecoff_debug_swap *swap,
+ struct bfd_link_info *info, file_ptr where));
+
+/* Externally visible ELF routines. */
+
+extern boolean bfd_elf32_record_link_assignment
+ PARAMS ((bfd *, struct bfd_link_info *, const char *));
+extern boolean bfd_elf64_record_link_assignment
+ PARAMS ((bfd *, struct bfd_link_info *, const char *));
+extern boolean bfd_elf32_size_dynamic_sections
+ PARAMS ((bfd *, struct bfd_link_info *, struct sec **));
+extern boolean bfd_elf64_size_dynamic_sections
+ PARAMS ((bfd *, struct bfd_link_info *, struct sec **));
+extern void bfd_elf_set_dt_needed_name PARAMS ((bfd *, const char *));
+
+/* SunOS shared library support routines for the linker. */
+
+extern boolean bfd_sunos_record_link_assignment
+ PARAMS ((bfd *, struct bfd_link_info *, const char *));
+extern boolean bfd_sunos_size_dynamic_sections
+ PARAMS ((bfd *, struct bfd_link_info *, struct sec **, struct sec **,
+ struct sec **));
+
+/* Linux shared library support routines for the linker. */
+
+extern boolean bfd_linux_size_dynamic_sections
+ PARAMS ((bfd *, struct bfd_link_info *));
+
+/* And more from the source. */
+void
+bfd_init PARAMS ((void));
+
+bfd *
+bfd_openr PARAMS ((CONST char *filename, CONST char *target));
+
+bfd *
+bfd_fdopenr PARAMS ((CONST char *filename, CONST char *target, int fd));
+
+bfd *
+bfd_openw PARAMS ((CONST char *filename, CONST char *target));
+
+boolean
+bfd_close PARAMS ((bfd *abfd));
+
+boolean
+bfd_close_all_done PARAMS ((bfd *));
+
+bfd_size_type
+bfd_alloc_size PARAMS ((bfd *abfd));
+
+bfd *
+bfd_create PARAMS ((CONST char *filename, bfd *templ));
+
+
+ /* Byte swapping macros for user section data. */
+
+#define bfd_put_8(abfd, val, ptr) \
+ (*((unsigned char *)(ptr)) = (unsigned char)(val))
+#define bfd_put_signed_8 \
+ bfd_put_8
+#define bfd_get_8(abfd, ptr) \
+ (*(unsigned char *)(ptr))
+#define bfd_get_signed_8(abfd, ptr) \
+ ((*(unsigned char *)(ptr) ^ 0x80) - 0x80)
+
+#define bfd_put_16(abfd, val, ptr) \
+ BFD_SEND(abfd, bfd_putx16, ((val),(ptr)))
+#define bfd_put_signed_16 \
+ bfd_put_16
+#define bfd_get_16(abfd, ptr) \
+ BFD_SEND(abfd, bfd_getx16, (ptr))
+#define bfd_get_signed_16(abfd, ptr) \
+ BFD_SEND (abfd, bfd_getx_signed_16, (ptr))
+
+#define bfd_put_32(abfd, val, ptr) \
+ BFD_SEND(abfd, bfd_putx32, ((val),(ptr)))
+#define bfd_put_signed_32 \
+ bfd_put_32
+#define bfd_get_32(abfd, ptr) \
+ BFD_SEND(abfd, bfd_getx32, (ptr))
+#define bfd_get_signed_32(abfd, ptr) \
+ BFD_SEND(abfd, bfd_getx_signed_32, (ptr))
+
+#define bfd_put_64(abfd, val, ptr) \
+ BFD_SEND(abfd, bfd_putx64, ((val), (ptr)))
+#define bfd_put_signed_64 \
+ bfd_put_64
+#define bfd_get_64(abfd, ptr) \
+ BFD_SEND(abfd, bfd_getx64, (ptr))
+#define bfd_get_signed_64(abfd, ptr) \
+ BFD_SEND(abfd, bfd_getx_signed_64, (ptr))
+
+
+ /* Byte swapping macros for file header data. */
+
+#define bfd_h_put_8(abfd, val, ptr) \
+ bfd_put_8 (abfd, val, ptr)
+#define bfd_h_put_signed_8(abfd, val, ptr) \
+ bfd_put_8 (abfd, val, ptr)
+#define bfd_h_get_8(abfd, ptr) \
+ bfd_get_8 (abfd, ptr)
+#define bfd_h_get_signed_8(abfd, ptr) \
+ bfd_get_signed_8 (abfd, ptr)
+
+#define bfd_h_put_16(abfd, val, ptr) \
+ BFD_SEND(abfd, bfd_h_putx16,(val,ptr))
+#define bfd_h_put_signed_16 \
+ bfd_h_put_16
+#define bfd_h_get_16(abfd, ptr) \
+ BFD_SEND(abfd, bfd_h_getx16,(ptr))
+#define bfd_h_get_signed_16(abfd, ptr) \
+ BFD_SEND(abfd, bfd_h_getx_signed_16, (ptr))
+
+#define bfd_h_put_32(abfd, val, ptr) \
+ BFD_SEND(abfd, bfd_h_putx32,(val,ptr))
+#define bfd_h_put_signed_32 \
+ bfd_h_put_32
+#define bfd_h_get_32(abfd, ptr) \
+ BFD_SEND(abfd, bfd_h_getx32,(ptr))
+#define bfd_h_get_signed_32(abfd, ptr) \
+ BFD_SEND(abfd, bfd_h_getx_signed_32, (ptr))
+
+#define bfd_h_put_64(abfd, val, ptr) \
+ BFD_SEND(abfd, bfd_h_putx64,(val, ptr))
+#define bfd_h_put_signed_64 \
+ bfd_h_put_64
+#define bfd_h_get_64(abfd, ptr) \
+ BFD_SEND(abfd, bfd_h_getx64,(ptr))
+#define bfd_h_get_signed_64(abfd, ptr) \
+ BFD_SEND(abfd, bfd_h_getx_signed_64, (ptr))
+
+typedef struct sec
+{
+ /* The name of the section; the name isn't a copy, the pointer is
+ the same as that passed to bfd_make_section. */
+
+ CONST char *name;
+
+ /* Which section is it; 0..nth. */
+
+ int index;
+
+ /* The next section in the list belonging to the BFD, or NULL. */
+
+ struct sec *next;
+
+ /* The field flags contains attributes of the section. Some
+ flags are read in from the object file, and some are
+ synthesized from other information. */
+
+ flagword flags;
+
+#define SEC_NO_FLAGS 0x000
+
+ /* Tells the OS to allocate space for this section when loading.
+ This is clear for a section containing debug information
+ only. */
+#define SEC_ALLOC 0x001
+
+ /* Tells the OS to load the section from the file when loading.
+ This is clear for a .bss section. */
+#define SEC_LOAD 0x002
+
+ /* The section contains data still to be relocated, so there is
+ some relocation information too. */
+#define SEC_RELOC 0x004
+
+#if 0 /* Obsolete ? */
+#define SEC_BALIGN 0x008
+#endif
+
+ /* A signal to the OS that the section contains read only
+ data. */
+#define SEC_READONLY 0x010
+
+ /* The section contains code only. */
+#define SEC_CODE 0x020
+
+ /* The section contains data only. */
+#define SEC_DATA 0x040
+
+ /* The section will reside in ROM. */
+#define SEC_ROM 0x080
+
+ /* The section contains constructor information. This section
+ type is used by the linker to create lists of constructors and
+ destructors used by <<g++>>. When a back end sees a symbol
+ which should be used in a constructor list, it creates a new
+ section for the type of name (e.g., <<__CTOR_LIST__>>), attaches
+ the symbol to it, and builds a relocation. To build the lists
+ of constructors, all the linker has to do is catenate all the
+ sections called <<__CTOR_LIST__>> and relocate the data
+ contained within - exactly the operations it would peform on
+ standard data. */
+#define SEC_CONSTRUCTOR 0x100
+
+ /* The section is a constuctor, and should be placed at the
+ end of the text, data, or bss section(?). */
+#define SEC_CONSTRUCTOR_TEXT 0x1100
+#define SEC_CONSTRUCTOR_DATA 0x2100
+#define SEC_CONSTRUCTOR_BSS 0x3100
+
+ /* The section has contents - a data section could be
+ <<SEC_ALLOC>> | <<SEC_HAS_CONTENTS>>; a debug section could be
+ <<SEC_HAS_CONTENTS>> */
+#define SEC_HAS_CONTENTS 0x200
+
+ /* An instruction to the linker to not output the section
+ even if it has information which would normally be written. */
+#define SEC_NEVER_LOAD 0x400
+
+ /* The section is a COFF shared library section. This flag is
+ only for the linker. If this type of section appears in
+ the input file, the linker must copy it to the output file
+ without changing the vma or size. FIXME: Although this
+ was originally intended to be general, it really is COFF
+ specific (and the flag was renamed to indicate this). It
+ might be cleaner to have some more general mechanism to
+ allow the back end to control what the linker does with
+ sections. */
+#define SEC_COFF_SHARED_LIBRARY 0x800
+
+ /* The section is a common section (symbols may be defined
+ multiple times, the value of a symbol is the amount of
+ space it requires, and the largest symbol value is the one
+ used). Most targets have exactly one of these (which we
+ translate to bfd_com_section_ptr), but ECOFF has two. */
+#define SEC_IS_COMMON 0x8000
+
+ /* The section contains only debugging information. For
+ example, this is set for ELF .debug and .stab sections.
+ strip tests this flag to see if a section can be
+ discarded. */
+#define SEC_DEBUGGING 0x10000
+
+ /* The contents of this section are held in memory pointed to
+ by the contents field. This is checked by
+ bfd_get_section_contents, and the data is retrieved from
+ memory if appropriate. */
+#define SEC_IN_MEMORY 0x20000
+
+ /* End of section flags. */
+
+ /* The virtual memory address of the section - where it will be
+ at run time. The symbols are relocated against this. The
+ user_set_vma flag is maintained by bfd; if it's not set, the
+ backend can assign addresses (for example, in <<a.out>>, where
+ the default address for <<.data>> is dependent on the specific
+ target and various flags). */
+
+ bfd_vma vma;
+ boolean user_set_vma;
+
+ /* The load address of the section - where it would be in a
+ rom image; really only used for writing section header
+ information. */
+
+ bfd_vma lma;
+
+ /* The size of the section in bytes, as it will be output.
+ contains a value even if the section has no contents (e.g., the
+ size of <<.bss>>). This will be filled in after relocation */
+
+ bfd_size_type _cooked_size;
+
+ /* The original size on disk of the section, in bytes. Normally this
+ value is the same as the size, but if some relaxing has
+ been done, then this value will be bigger. */
+
+ bfd_size_type _raw_size;
+
+ /* If this section is going to be output, then this value is the
+ offset into the output section of the first byte in the input
+ section. E.g., if this was going to start at the 100th byte in
+ the output section, this value would be 100. */
+
+ bfd_vma output_offset;
+
+ /* The output section through which to map on output. */
+
+ struct sec *output_section;
+
+ /* The alignment requirement of the section, as an exponent of 2 -
+ e.g., 3 aligns to 2^3 (or 8). */
+
+ unsigned int alignment_power;
+
+ /* If an input section, a pointer to a vector of relocation
+ records for the data in this section. */
+
+ struct reloc_cache_entry *relocation;
+
+ /* If an output section, a pointer to a vector of pointers to
+ relocation records for the data in this section. */
+
+ struct reloc_cache_entry **orelocation;
+
+ /* The number of relocation records in one of the above */
+
+ unsigned reloc_count;
+
+ /* Information below is back end specific - and not always used
+ or updated. */
+
+ /* File position of section data */
+
+ file_ptr filepos;
+
+ /* File position of relocation info */
+
+ file_ptr rel_filepos;
+
+ /* File position of line data */
+
+ file_ptr line_filepos;
+
+ /* Pointer to data for applications */
+
+ PTR userdata;
+
+ /* If the SEC_IN_MEMORY flag is set, this points to the actual
+ contents. */
+ unsigned char *contents;
+
+ /* Attached line number information */
+
+ alent *lineno;
+
+ /* Number of line number records */
+
+ unsigned int lineno_count;
+
+ /* When a section is being output, this value changes as more
+ linenumbers are written out */
+
+ file_ptr moving_line_filepos;
+
+ /* What the section number is in the target world */
+
+ int target_index;
+
+ PTR used_by_bfd;
+
+ /* If this is a constructor section then here is a list of the
+ relocations created to relocate items within it. */
+
+ struct relent_chain *constructor_chain;
+
+ /* The BFD which owns the section. */
+
+ bfd *owner;
+
+ boolean reloc_done;
+ /* A symbol which points at this section only */
+ struct symbol_cache_entry *symbol;
+ struct symbol_cache_entry **symbol_ptr_ptr;
+
+ struct bfd_link_order *link_order_head;
+ struct bfd_link_order *link_order_tail;
+} asection ;
+
+ /* These sections are global, and are managed by BFD. The application
+ and target back end are not permitted to change the values in
+ these sections. New code should use the section_ptr macros rather
+ than referring directly to the const sections. The const sections
+ may eventually vanish. */
+#define BFD_ABS_SECTION_NAME "*ABS*"
+#define BFD_UND_SECTION_NAME "*UND*"
+#define BFD_COM_SECTION_NAME "*COM*"
+#define BFD_IND_SECTION_NAME "*IND*"
+
+ /* the absolute section */
+extern const asection bfd_abs_section;
+#define bfd_abs_section_ptr ((asection *) &bfd_abs_section)
+#define bfd_is_abs_section(sec) ((sec) == bfd_abs_section_ptr)
+ /* Pointer to the undefined section */
+extern const asection bfd_und_section;
+#define bfd_und_section_ptr ((asection *) &bfd_und_section)
+#define bfd_is_und_section(sec) ((sec) == bfd_und_section_ptr)
+ /* Pointer to the common section */
+extern const asection bfd_com_section;
+#define bfd_com_section_ptr ((asection *) &bfd_com_section)
+ /* Pointer to the indirect section */
+extern const asection bfd_ind_section;
+#define bfd_ind_section_ptr ((asection *) &bfd_ind_section)
+#define bfd_is_ind_section(sec) ((sec) == bfd_ind_section_ptr)
+
+extern const struct symbol_cache_entry * const bfd_abs_symbol;
+extern const struct symbol_cache_entry * const bfd_com_symbol;
+extern const struct symbol_cache_entry * const bfd_und_symbol;
+extern const struct symbol_cache_entry * const bfd_ind_symbol;
+#define bfd_get_section_size_before_reloc(section) \
+ (section->reloc_done ? (abort(),1): (section)->_raw_size)
+#define bfd_get_section_size_after_reloc(section) \
+ ((section->reloc_done) ? (section)->_cooked_size: (abort(),1))
+asection *
+bfd_get_section_by_name PARAMS ((bfd *abfd, CONST char *name));
+
+asection *
+bfd_make_section_old_way PARAMS ((bfd *abfd, CONST char *name));
+
+asection *
+bfd_make_section_anyway PARAMS ((bfd *abfd, CONST char *name));
+
+asection *
+bfd_make_section PARAMS ((bfd *, CONST char *name));
+
+boolean
+bfd_set_section_flags PARAMS ((bfd *abfd, asection *sec, flagword flags));
+
+void
+bfd_map_over_sections PARAMS ((bfd *abfd,
+ void (*func)(bfd *abfd,
+ asection *sect,
+ PTR obj),
+ PTR obj));
+
+boolean
+bfd_set_section_size PARAMS ((bfd *abfd, asection *sec, bfd_size_type val));
+
+boolean
+bfd_set_section_contents
+ PARAMS ((bfd *abfd,
+ asection *section,
+ PTR data,
+ file_ptr offset,
+ bfd_size_type count));
+
+boolean
+bfd_get_section_contents
+ PARAMS ((bfd *abfd, asection *section, PTR location,
+ file_ptr offset, bfd_size_type count));
+
+boolean
+bfd_copy_private_section_data PARAMS ((bfd *ibfd, asection *isec, bfd *obfd, asection *osec));
+
+#define bfd_copy_private_section_data(ibfd, isection, obfd, osection) \
+ BFD_SEND (ibfd, _bfd_copy_private_section_data, \
+ (ibfd, isection, obfd, osection))
+enum bfd_architecture
+{
+ bfd_arch_unknown, /* File arch not known */
+ bfd_arch_obscure, /* Arch known, not one of these */
+ bfd_arch_m68k, /* Motorola 68xxx */
+ bfd_arch_vax, /* DEC Vax */
+ bfd_arch_i960, /* Intel 960 */
+ /* The order of the following is important.
+ lower number indicates a machine type that
+ only accepts a subset of the instructions
+ available to machines with higher numbers.
+ The exception is the "ca", which is
+ incompatible with all other machines except
+ "core". */
+
+#define bfd_mach_i960_core 1
+#define bfd_mach_i960_ka_sa 2
+#define bfd_mach_i960_kb_sb 3
+#define bfd_mach_i960_mc 4
+#define bfd_mach_i960_xa 5
+#define bfd_mach_i960_ca 6
+
+ bfd_arch_a29k, /* AMD 29000 */
+ bfd_arch_sparc, /* SPARC */
+ bfd_arch_mips, /* MIPS Rxxxx */
+ bfd_arch_i386, /* Intel 386 */
+ bfd_arch_we32k, /* AT&T WE32xxx */
+ bfd_arch_tahoe, /* CCI/Harris Tahoe */
+ bfd_arch_i860, /* Intel 860 */
+ bfd_arch_romp, /* IBM ROMP PC/RT */
+ bfd_arch_alliant, /* Alliant */
+ bfd_arch_convex, /* Convex */
+ bfd_arch_m88k, /* Motorola 88xxx */
+ bfd_arch_pyramid, /* Pyramid Technology */
+ bfd_arch_h8300, /* Hitachi H8/300 */
+#define bfd_mach_h8300 1
+#define bfd_mach_h8300h 2
+ bfd_arch_powerpc, /* PowerPC */
+ bfd_arch_rs6000, /* IBM RS/6000 */
+ bfd_arch_hppa, /* HP PA RISC */
+ bfd_arch_z8k, /* Zilog Z8000 */
+#define bfd_mach_z8001 1
+#define bfd_mach_z8002 2
+ bfd_arch_h8500, /* Hitachi H8/500 */
+ bfd_arch_sh, /* Hitachi SH */
+ bfd_arch_alpha, /* Dec Alpha */
+ bfd_arch_ns32k, /* National Semiconductors ns32000 */
+ bfd_arch_last
+ };
+
+typedef struct bfd_arch_info
+{
+ int bits_per_word;
+ int bits_per_address;
+ int bits_per_byte;
+ enum bfd_architecture arch;
+ long mach;
+ char *arch_name;
+ CONST char *printable_name;
+ unsigned int section_align_power;
+ /* true if this is the default machine for the architecture */
+ boolean the_default;
+ CONST struct bfd_arch_info * (*compatible)
+ PARAMS ((CONST struct bfd_arch_info *a,
+ CONST struct bfd_arch_info *b));
+
+ boolean (*scan) PARAMS ((CONST struct bfd_arch_info *, CONST char *));
+ /* How to disassemble an instruction, producing a printable
+ representation on a specified stdio stream. This isn't
+ defined for most processors at present, because of the size
+ of the additional tables it would drag in, and because gdb
+ wants to use a different interface. */
+ unsigned int (*disassemble) PARAMS ((bfd_vma addr, CONST char *data,
+ PTR stream));
+
+ struct bfd_arch_info *next;
+} bfd_arch_info_type;
+CONST char *
+bfd_printable_name PARAMS ((bfd *abfd));
+
+bfd_arch_info_type *
+bfd_scan_arch PARAMS ((CONST char *string));
+
+CONST bfd_arch_info_type *
+bfd_arch_get_compatible PARAMS ((
+ CONST bfd *abfd,
+ CONST bfd *bbfd));
+
+void
+bfd_set_arch_info PARAMS ((bfd *abfd, bfd_arch_info_type *arg));
+
+enum bfd_architecture
+bfd_get_arch PARAMS ((bfd *abfd));
+
+unsigned long
+bfd_get_mach PARAMS ((bfd *abfd));
+
+unsigned int
+bfd_arch_bits_per_byte PARAMS ((bfd *abfd));
+
+unsigned int
+bfd_arch_bits_per_address PARAMS ((bfd *abfd));
+
+bfd_arch_info_type *
+bfd_get_arch_info PARAMS ((bfd *abfd));
+
+bfd_arch_info_type *
+bfd_lookup_arch
+ PARAMS ((enum bfd_architecture
+ arch,
+ long machine));
+
+CONST char *
+bfd_printable_arch_mach
+ PARAMS ((enum bfd_architecture arch, unsigned long machine));
+
+typedef enum bfd_reloc_status
+{
+ /* No errors detected */
+ bfd_reloc_ok,
+
+ /* The relocation was performed, but there was an overflow. */
+ bfd_reloc_overflow,
+
+ /* The address to relocate was not within the section supplied. */
+ bfd_reloc_outofrange,
+
+ /* Used by special functions */
+ bfd_reloc_continue,
+
+ /* Unsupported relocation size requested. */
+ bfd_reloc_notsupported,
+
+ /* Unused */
+ bfd_reloc_other,
+
+ /* The symbol to relocate against was undefined. */
+ bfd_reloc_undefined,
+
+ /* The relocation was performed, but may not be ok - presently
+ generated only when linking i960 coff files with i960 b.out
+ symbols. If this type is returned, the error_message argument
+ to bfd_perform_relocation will be set. */
+ bfd_reloc_dangerous
+ }
+ bfd_reloc_status_type;
+
+
+typedef struct reloc_cache_entry
+{
+ /* A pointer into the canonical table of pointers */
+ struct symbol_cache_entry **sym_ptr_ptr;
+
+ /* offset in section */
+ bfd_size_type address;
+
+ /* addend for relocation value */
+ bfd_vma addend;
+
+ /* Pointer to how to perform the required relocation */
+ const struct reloc_howto_struct *howto;
+
+} arelent;
+enum complain_overflow
+{
+ /* Do not complain on overflow. */
+ complain_overflow_dont,
+
+ /* Complain if the bitfield overflows, whether it is considered
+ as signed or unsigned. */
+ complain_overflow_bitfield,
+
+ /* Complain if the value overflows when considered as signed
+ number. */
+ complain_overflow_signed,
+
+ /* Complain if the value overflows when considered as an
+ unsigned number. */
+ complain_overflow_unsigned
+};
+
+typedef unsigned char bfd_byte;
+typedef struct reloc_howto_struct reloc_howto_type;
+
+struct reloc_howto_struct
+{
+ /* The type field has mainly a documetary use - the back end can
+ do what it wants with it, though normally the back end's
+ external idea of what a reloc number is stored
+ in this field. For example, a PC relative word relocation
+ in a coff environment has the type 023 - because that's
+ what the outside world calls a R_PCRWORD reloc. */
+ unsigned int type;
+
+ /* The value the final relocation is shifted right by. This drops
+ unwanted data from the relocation. */
+ unsigned int rightshift;
+
+ /* The size of the item to be relocated. This is *not* a
+ power-of-two measure. To get the number of bytes operated
+ on by a type of relocation, use bfd_get_reloc_size. */
+ int size;
+
+ /* The number of bits in the item to be relocated. This is used
+ when doing overflow checking. */
+ unsigned int bitsize;
+
+ /* Notes that the relocation is relative to the location in the
+ data section of the addend. The relocation function will
+ subtract from the relocation value the address of the location
+ being relocated. */
+ boolean pc_relative;
+
+ /* The bit position of the reloc value in the destination.
+ The relocated value is left shifted by this amount. */
+ unsigned int bitpos;
+
+ /* What type of overflow error should be checked for when
+ relocating. */
+ enum complain_overflow complain_on_overflow;
+
+ /* If this field is non null, then the supplied function is
+ called rather than the normal function. This allows really
+ strange relocation methods to be accomodated (e.g., i960 callj
+ instructions). */
+ bfd_reloc_status_type (*special_function)
+ PARAMS ((bfd *abfd,
+ arelent *reloc_entry,
+ struct symbol_cache_entry *symbol,
+ PTR data,
+ asection *input_section,
+ bfd *output_bfd,
+ char **error_message));
+
+ /* The textual name of the relocation type. */
+ char *name;
+
+ /* When performing a partial link, some formats must modify the
+ relocations rather than the data - this flag signals this.*/
+ boolean partial_inplace;
+
+ /* The src_mask selects which parts of the read in data
+ are to be used in the relocation sum. E.g., if this was an 8 bit
+ bit of data which we read and relocated, this would be
+ 0x000000ff. When we have relocs which have an addend, such as
+ sun4 extended relocs, the value in the offset part of a
+ relocating field is garbage so we never use it. In this case
+ the mask would be 0x00000000. */
+ bfd_vma src_mask;
+
+ /* The dst_mask selects which parts of the instruction are replaced
+ into the instruction. In most cases src_mask == dst_mask,
+ except in the above special case, where dst_mask would be
+ 0x000000ff, and src_mask would be 0x00000000. */
+ bfd_vma dst_mask;
+
+ /* When some formats create PC relative instructions, they leave
+ the value of the pc of the place being relocated in the offset
+ slot of the instruction, so that a PC relative relocation can
+ be made just by adding in an ordinary offset (e.g., sun3 a.out).
+ Some formats leave the displacement part of an instruction
+ empty (e.g., m88k bcs); this flag signals the fact.*/
+ boolean pcrel_offset;
+
+};
+#define HOWTO(C, R,S,B, P, BI, O, SF, NAME, INPLACE, MASKSRC, MASKDST, PC) \
+ {(unsigned)C,R,S,B, P, BI, O,SF,NAME,INPLACE,MASKSRC,MASKDST,PC}
+#define NEWHOWTO( FUNCTION, NAME,SIZE,REL,IN) HOWTO(0,0,SIZE,0,REL,0,complain_overflow_dont,FUNCTION, NAME,false,0,0,IN)
+
+#define HOWTO_PREPARE(relocation, symbol) \
+ { \
+ if (symbol != (asymbol *)NULL) { \
+ if (bfd_is_com_section (symbol->section)) { \
+ relocation = 0; \
+ } \
+ else { \
+ relocation = symbol->value; \
+ } \
+ } \
+}
+int
+bfd_get_reloc_size PARAMS ((const reloc_howto_type *));
+
+typedef struct relent_chain {
+ arelent relent;
+ struct relent_chain *next;
+} arelent_chain;
+bfd_reloc_status_type
+
+bfd_perform_relocation
+ PARAMS ((bfd *abfd,
+ arelent *reloc_entry,
+ PTR data,
+ asection *input_section,
+ bfd *output_bfd,
+ char **error_message));
+
+typedef enum bfd_reloc_code_real
+{
+ /* Basic absolute relocations */
+ BFD_RELOC_64,
+ BFD_RELOC_32,
+ BFD_RELOC_26,
+ BFD_RELOC_16,
+ BFD_RELOC_14,
+ BFD_RELOC_8,
+
+ /* PC-relative relocations */
+ BFD_RELOC_64_PCREL,
+ BFD_RELOC_32_PCREL,
+ BFD_RELOC_24_PCREL, /* used by i960 */
+ BFD_RELOC_16_PCREL,
+ BFD_RELOC_8_PCREL,
+
+ /* Linkage-table relative */
+ BFD_RELOC_32_BASEREL,
+ BFD_RELOC_16_BASEREL,
+ BFD_RELOC_8_BASEREL,
+
+ /* The type of reloc used to build a contructor table - at the moment
+ probably a 32 bit wide abs address, but the cpu can choose. */
+ BFD_RELOC_CTOR,
+
+ /* 8 bits wide, but used to form an address like 0xffnn */
+ BFD_RELOC_8_FFnn,
+
+ /* 32-bit pc-relative, shifted right 2 bits (i.e., 30-bit
+ word displacement, e.g. for SPARC) */
+ BFD_RELOC_32_PCREL_S2,
+ /* signed 16-bit pc-relative, shifted right 2 bits (e.g. for MIPS) */
+ BFD_RELOC_16_PCREL_S2,
+ /* this is used on the Alpha */
+ BFD_RELOC_23_PCREL_S2,
+
+ /* High 22 bits of 32-bit value, placed into lower 22 bits of
+ target word; simple reloc. */
+ BFD_RELOC_HI22,
+ /* Low 10 bits. */
+ BFD_RELOC_LO10,
+
+ /* For systems that allocate a Global Pointer register, these are
+ displacements off that register. These relocation types are
+ handled specially, because the value the register will have is
+ decided relatively late. */
+ BFD_RELOC_GPREL16,
+ BFD_RELOC_GPREL32,
+
+ /* Reloc types used for i960/b.out. */
+ BFD_RELOC_I960_CALLJ,
+
+ /* now for the sparc/elf codes */
+ BFD_RELOC_NONE, /* actually used */
+ BFD_RELOC_SPARC_WDISP22,
+ BFD_RELOC_SPARC22,
+ BFD_RELOC_SPARC13,
+ BFD_RELOC_SPARC_GOT10,
+ BFD_RELOC_SPARC_GOT13,
+ BFD_RELOC_SPARC_GOT22,
+ BFD_RELOC_SPARC_PC10,
+ BFD_RELOC_SPARC_PC22,
+ BFD_RELOC_SPARC_WPLT30,
+ BFD_RELOC_SPARC_COPY,
+ BFD_RELOC_SPARC_GLOB_DAT,
+ BFD_RELOC_SPARC_JMP_SLOT,
+ BFD_RELOC_SPARC_RELATIVE,
+ BFD_RELOC_SPARC_UA32,
+
+ /* these are a.out specific? */
+ BFD_RELOC_SPARC_BASE13,
+ BFD_RELOC_SPARC_BASE22,
+
+ /* some relocations we're using for sparc v9
+ -- subject to change */
+ BFD_RELOC_SPARC_10,
+ BFD_RELOC_SPARC_11,
+#define BFD_RELOC_SPARC_64 BFD_RELOC_64
+ BFD_RELOC_SPARC_OLO10,
+ BFD_RELOC_SPARC_HH22,
+ BFD_RELOC_SPARC_HM10,
+ BFD_RELOC_SPARC_LM22,
+ BFD_RELOC_SPARC_PC_HH22,
+ BFD_RELOC_SPARC_PC_HM10,
+ BFD_RELOC_SPARC_PC_LM22,
+ BFD_RELOC_SPARC_WDISP16,
+ BFD_RELOC_SPARC_WDISP19,
+ BFD_RELOC_SPARC_GLOB_JMP,
+ BFD_RELOC_SPARC_LO7,
+
+ /* Alpha ECOFF relocations. Some of these treat the symbol or "addend"
+ in some special way. */
+ /* For GPDISP_HI16 ("gpdisp") relocations, the symbol is ignored when
+ writing; when reading, it will be the absolute section symbol. The
+ addend is the displacement in bytes of the "lda" instruction from
+ the "ldah" instruction (which is at the address of this reloc). */
+ BFD_RELOC_ALPHA_GPDISP_HI16,
+ /* For GPDISP_LO16 ("ignore") relocations, the symbol is handled as
+ with GPDISP_HI16 relocs. The addend is ignored when writing the
+ relocations out, and is filled in with the file's GP value on
+ reading, for convenience. */
+ BFD_RELOC_ALPHA_GPDISP_LO16,
+
+ /* The Alpha LITERAL/LITUSE relocs are produced by a symbol reference;
+ the assembler turns it into a LDQ instruction to load the address of
+ the symbol, and then fills in a register in the real instruction.
+
+ The LITERAL reloc, at the LDQ instruction, refers to the .lita
+ section symbol. The addend is ignored when writing, but is filled
+ in with the file's GP value on reading, for convenience, as with the
+ GPDISP_LO16 reloc.
+
+ The LITUSE reloc, on the instruction using the loaded address, gives
+ information to the linker that it might be able to use to optimize
+ away some literal section references. The symbol is ignored (read
+ as the absolute section symbol), and the "addend" indicates the type
+ of instruction using the register:
+ 1 - "memory" fmt insn
+ 2 - byte-manipulation (byte offset reg)
+ 3 - jsr (target of branch)
+
+ The GNU linker currently doesn't do any of this optimizing. */
+ BFD_RELOC_ALPHA_LITERAL,
+ BFD_RELOC_ALPHA_LITUSE,
+
+ /* The HINT relocation indicates a value that should be filled into the
+ "hint" field of a jmp/jsr/ret instruction, for possible branch-
+ prediction logic which may be provided on some processors. */
+ BFD_RELOC_ALPHA_HINT,
+
+ /* Bits 27..2 of the relocation address shifted right 2 bits;
+ simple reloc otherwise. */
+ BFD_RELOC_MIPS_JMP,
+
+ /* High 16 bits of 32-bit value; simple reloc. */
+ BFD_RELOC_HI16,
+ /* High 16 bits of 32-bit value but the low 16 bits will be sign
+ extended and added to form the final result. If the low 16
+ bits form a negative number, we need to add one to the high value
+ to compensate for the borrow when the low bits are added. */
+ BFD_RELOC_HI16_S,
+ /* Low 16 bits. */
+ BFD_RELOC_LO16,
+ /* Like BFD_RELOC_HI16_S, but PC relative. */
+ BFD_RELOC_PCREL_HI16_S,
+ /* Like BFD_RELOC_LO16, but PC relative. */
+ BFD_RELOC_PCREL_LO16,
+
+ /* relocation relative to the global pointer. */
+#define BFD_RELOC_MIPS_GPREL BFD_RELOC_GPREL16
+
+ /* Relocation against a MIPS literal section. */
+ BFD_RELOC_MIPS_LITERAL,
+
+ /* MIPS ELF relocations. */
+ BFD_RELOC_MIPS_GOT16,
+ BFD_RELOC_MIPS_CALL16,
+#define BFD_RELOC_MIPS_GPREL32 BFD_RELOC_GPREL32
+
+ /* i386/elf relocations */
+ BFD_RELOC_386_GOT32,
+ BFD_RELOC_386_PLT32,
+ BFD_RELOC_386_COPY,
+ BFD_RELOC_386_GLOB_DAT,
+ BFD_RELOC_386_JUMP_SLOT,
+ BFD_RELOC_386_RELATIVE,
+ BFD_RELOC_386_GOTOFF,
+ BFD_RELOC_386_GOTPC,
+
+ /* ns32k relocations */
+ BFD_RELOC_NS32K_IMM_8,
+ BFD_RELOC_NS32K_IMM_16,
+ BFD_RELOC_NS32K_IMM_32,
+ BFD_RELOC_NS32K_IMM_8_PCREL,
+ BFD_RELOC_NS32K_IMM_16_PCREL,
+ BFD_RELOC_NS32K_IMM_32_PCREL,
+ BFD_RELOC_NS32K_DISP_8,
+ BFD_RELOC_NS32K_DISP_16,
+ BFD_RELOC_NS32K_DISP_32,
+ BFD_RELOC_NS32K_DISP_8_PCREL,
+ BFD_RELOC_NS32K_DISP_16_PCREL,
+ BFD_RELOC_NS32K_DISP_32_PCREL,
+
+ /* PowerPC/POWER (RS/6000) relocs. */
+ /* 26 bit relative branch. Low two bits must be zero. High 24
+ bits installed in bits 6 through 29 of instruction. */
+ BFD_RELOC_PPC_B26,
+ /* 26 bit absolute branch, like BFD_RELOC_PPC_B26 but absolute. */
+ BFD_RELOC_PPC_BA26,
+ /* 16 bit TOC relative reference. */
+ BFD_RELOC_PPC_TOC16,
+
+ /* this must be the highest numeric value */
+ BFD_RELOC_UNUSED
+ } bfd_reloc_code_real_type;
+const struct reloc_howto_struct *
+
+bfd_reloc_type_lookup PARAMS ((bfd *abfd, bfd_reloc_code_real_type code));
+
+
+typedef struct symbol_cache_entry
+{
+ /* A pointer to the BFD which owns the symbol. This information
+ is necessary so that a back end can work out what additional
+ information (invisible to the application writer) is carried
+ with the symbol.
+
+ This field is *almost* redundant, since you can use section->owner
+ instead, except that some symbols point to the global sections
+ bfd_{abs,com,und}_section. This could be fixed by making
+ these globals be per-bfd (or per-target-flavor). FIXME. */
+
+ struct _bfd *the_bfd; /* Use bfd_asymbol_bfd(sym) to access this field. */
+
+ /* The text of the symbol. The name is left alone, and not copied; the
+ application may not alter it. */
+ CONST char *name;
+
+ /* The value of the symbol. This really should be a union of a
+ numeric value with a pointer, since some flags indicate that
+ a pointer to another symbol is stored here. */
+ symvalue value;
+
+ /* Attributes of a symbol: */
+
+#define BSF_NO_FLAGS 0x00
+
+ /* The symbol has local scope; <<static>> in <<C>>. The value
+ is the offset into the section of the data. */
+#define BSF_LOCAL 0x01
+
+ /* The symbol has global scope; initialized data in <<C>>. The
+ value is the offset into the section of the data. */
+#define BSF_GLOBAL 0x02
+
+ /* The symbol has global scope and is exported. The value is
+ the offset into the section of the data. */
+#define BSF_EXPORT BSF_GLOBAL /* no real difference */
+
+ /* A normal C symbol would be one of:
+ <<BSF_LOCAL>>, <<BSF_FORT_COMM>>, <<BSF_UNDEFINED>> or
+ <<BSF_GLOBAL>> */
+
+ /* The symbol is a debugging record. The value has an arbitary
+ meaning. */
+#define BSF_DEBUGGING 0x08
+
+ /* The symbol denotes a function entry point. Used in ELF,
+ perhaps others someday. */
+#define BSF_FUNCTION 0x10
+
+ /* Used by the linker. */
+#define BSF_KEEP 0x20
+#define BSF_KEEP_G 0x40
+
+ /* A weak global symbol, overridable without warnings by
+ a regular global symbol of the same name. */
+#define BSF_WEAK 0x80
+
+ /* This symbol was created to point to a section, e.g. ELF's
+ STT_SECTION symbols. */
+#define BSF_SECTION_SYM 0x100
+
+ /* The symbol used to be a common symbol, but now it is
+ allocated. */
+#define BSF_OLD_COMMON 0x200
+
+ /* The default value for common data. */
+#define BFD_FORT_COMM_DEFAULT_VALUE 0
+
+ /* In some files the type of a symbol sometimes alters its
+ location in an output file - ie in coff a <<ISFCN>> symbol
+ which is also <<C_EXT>> symbol appears where it was
+ declared and not at the end of a section. This bit is set
+ by the target BFD part to convey this information. */
+
+#define BSF_NOT_AT_END 0x400
+
+ /* Signal that the symbol is the label of constructor section. */
+#define BSF_CONSTRUCTOR 0x800
+
+ /* Signal that the symbol is a warning symbol. If the symbol
+ is a warning symbol, then the value field (I know this is
+ tacky) will point to the asymbol which when referenced will
+ cause the warning. */
+#define BSF_WARNING 0x1000
+
+ /* Signal that the symbol is indirect. The value of the symbol
+ is a pointer to an undefined asymbol which contains the
+ name to use instead. */
+#define BSF_INDIRECT 0x2000
+
+ /* BSF_FILE marks symbols that contain a file name. This is used
+ for ELF STT_FILE symbols. */
+#define BSF_FILE 0x4000
+
+ /* Symbol is from dynamic linking information. */
+#define BSF_DYNAMIC 0x8000
+
+ flagword flags;
+
+ /* A pointer to the section to which this symbol is
+ relative. This will always be non NULL, there are special
+ sections for undefined and absolute symbols */
+ struct sec *section;
+
+ /* Back end special data. This is being phased out in favour
+ of making this a union. */
+ PTR udata;
+
+} asymbol;
+#define bfd_get_symtab_upper_bound(abfd) \
+ BFD_SEND (abfd, _bfd_get_symtab_upper_bound, (abfd))
+boolean
+bfd_is_local_label PARAMS ((bfd *abfd, asymbol *sym));
+
+#define bfd_is_local_label(abfd, sym) \
+ BFD_SEND (abfd, _bfd_is_local_label,(abfd, sym))
+#define bfd_canonicalize_symtab(abfd, location) \
+ BFD_SEND (abfd, _bfd_canonicalize_symtab,\
+ (abfd, location))
+boolean
+bfd_set_symtab PARAMS ((bfd *abfd, asymbol **location, unsigned int count));
+
+void
+bfd_print_symbol_vandf PARAMS ((PTR file, asymbol *symbol));
+
+#define bfd_make_empty_symbol(abfd) \
+ BFD_SEND (abfd, _bfd_make_empty_symbol, (abfd))
+#define bfd_make_debug_symbol(abfd,ptr,size) \
+ BFD_SEND (abfd, _bfd_make_debug_symbol, (abfd, ptr, size))
+int
+bfd_decode_symclass PARAMS ((asymbol *symbol));
+
+void
+bfd_symbol_info PARAMS ((asymbol *symbol, symbol_info *ret));
+
+struct _bfd
+{
+ /* The filename the application opened the BFD with. */
+ CONST char *filename;
+
+ /* A pointer to the target jump table. */
+ const struct bfd_target *xvec;
+
+ /* To avoid dragging too many header files into every file that
+ includes `<<bfd.h>>', IOSTREAM has been declared as a "char
+ *", and MTIME as a "long". Their correct types, to which they
+ are cast when used, are "FILE *" and "time_t". The iostream
+ is the result of an fopen on the filename. */
+ char *iostream;
+
+ /* Is the file descriptor being cached? That is, can it be closed as
+ needed, and re-opened when accessed later? */
+
+ boolean cacheable;
+
+ /* Marks whether there was a default target specified when the
+ BFD was opened. This is used to select which matching algorithm
+ to use to choose the back end. */
+
+ boolean target_defaulted;
+
+ /* The caching routines use these to maintain a
+ least-recently-used list of BFDs */
+
+ struct _bfd *lru_prev, *lru_next;
+
+ /* When a file is closed by the caching routines, BFD retains
+ state information on the file here: */
+
+ file_ptr where;
+
+ /* and here: (``once'' means at least once) */
+
+ boolean opened_once;
+
+ /* Set if we have a locally maintained mtime value, rather than
+ getting it from the file each time: */
+
+ boolean mtime_set;
+
+ /* File modified time, if mtime_set is true: */
+
+ long mtime;
+
+ /* Reserved for an unimplemented file locking extension.*/
+
+ int ifd;
+
+ /* The format which belongs to the BFD. (object, core, etc.) */
+
+ bfd_format format;
+
+ /* The direction the BFD was opened with*/
+
+ enum bfd_direction {no_direction = 0,
+ read_direction = 1,
+ write_direction = 2,
+ both_direction = 3} direction;
+
+ /* Format_specific flags*/
+
+ flagword flags;
+
+ /* Currently my_archive is tested before adding origin to
+ anything. I believe that this can become always an add of
+ origin, with origin set to 0 for non archive files. */
+
+ file_ptr origin;
+
+ /* Remember when output has begun, to stop strange things
+ from happening. */
+ boolean output_has_begun;
+
+ /* Pointer to linked list of sections*/
+ struct sec *sections;
+
+ /* The number of sections */
+ unsigned int section_count;
+
+ /* Stuff only useful for object files:
+ The start address. */
+ bfd_vma start_address;
+
+ /* Used for input and output*/
+ unsigned int symcount;
+
+ /* Symbol table for output BFD (with symcount entries) */
+ struct symbol_cache_entry **outsymbols;
+
+ /* Pointer to structure which contains architecture information*/
+ struct bfd_arch_info *arch_info;
+
+ /* Stuff only useful for archives:*/
+ PTR arelt_data;
+ struct _bfd *my_archive; /* The containing archive BFD. */
+ struct _bfd *next; /* The next BFD in the archive. */
+ struct _bfd *archive_head; /* The first BFD in the archive. */
+ boolean has_armap;
+
+ /* A chain of BFD structures involved in a link. */
+ struct _bfd *link_next;
+
+ /* A field used by _bfd_generic_link_add_archive_symbols. This will
+ be used only for archive elements. */
+ int archive_pass;
+
+ /* Used by the back end to hold private data. */
+
+ union
+ {
+ struct aout_data_struct *aout_data;
+ struct artdata *aout_ar_data;
+ struct _oasys_data *oasys_obj_data;
+ struct _oasys_ar_data *oasys_ar_data;
+ struct coff_tdata *coff_obj_data;
+ struct ecoff_tdata *ecoff_obj_data;
+ struct ieee_data_struct *ieee_data;
+ struct ieee_ar_data_struct *ieee_ar_data;
+ struct srec_data_struct *srec_data;
+ struct tekhex_data_struct *tekhex_data;
+ struct elf_obj_tdata *elf_obj_data;
+ struct nlm_obj_tdata *nlm_obj_data;
+ struct bout_data_struct *bout_data;
+ struct sun_core_struct *sun_core_data;
+ struct trad_core_struct *trad_core_data;
+ struct som_data_struct *som_data;
+ struct hpux_core_struct *hpux_core_data;
+ struct hppabsd_core_struct *hppabsd_core_data;
+ struct sgi_core_struct *sgi_core_data;
+ struct lynx_core_struct *lynx_core_data;
+ struct osf_core_struct *osf_core_data;
+ struct cisco_core_struct *cisco_core_data;
+ PTR any;
+ } tdata;
+
+ /* Used by the application to hold private data*/
+ PTR usrdata;
+
+ /* Where all the allocated stuff under this BFD goes */
+ struct obstack memory;
+};
+
+typedef enum bfd_error
+{
+ bfd_error_no_error = 0,
+ bfd_error_system_call,
+ bfd_error_invalid_target,
+ bfd_error_wrong_format,
+ bfd_error_invalid_operation,
+ bfd_error_no_memory,
+ bfd_error_no_symbols,
+ bfd_error_no_more_archived_files,
+ bfd_error_malformed_archive,
+ bfd_error_file_not_recognized,
+ bfd_error_file_ambiguously_recognized,
+ bfd_error_no_contents,
+ bfd_error_nonrepresentable_section,
+ bfd_error_no_debug_section,
+ bfd_error_bad_value,
+ bfd_error_file_truncated,
+ bfd_error_invalid_error_code
+} bfd_error_type;
+
+bfd_error_type
+bfd_get_error PARAMS ((void));
+
+void
+bfd_set_error PARAMS ((bfd_error_type error_tag));
+
+CONST char *
+bfd_errmsg PARAMS ((bfd_error_type error_tag));
+
+void
+bfd_perror PARAMS ((CONST char *message));
+
+long
+bfd_get_reloc_upper_bound PARAMS ((bfd *abfd, asection *sect));
+
+long
+bfd_canonicalize_reloc
+ PARAMS ((bfd *abfd,
+ asection *sec,
+ arelent **loc,
+ asymbol **syms));
+
+void
+bfd_set_reloc
+ PARAMS ((bfd *abfd, asection *sec, arelent **rel, unsigned int count)
+
+ );
+
+boolean
+bfd_set_file_flags PARAMS ((bfd *abfd, flagword flags));
+
+boolean
+bfd_set_start_address PARAMS ((bfd *abfd, bfd_vma vma));
+
+long
+bfd_get_mtime PARAMS ((bfd *abfd));
+
+long
+bfd_get_size PARAMS ((bfd *abfd));
+
+int
+bfd_get_gp_size PARAMS ((bfd *abfd));
+
+void
+bfd_set_gp_size PARAMS ((bfd *abfd, int i));
+
+bfd_vma
+bfd_scan_vma PARAMS ((CONST char *string, CONST char **end, int base));
+
+boolean
+bfd_copy_private_bfd_data PARAMS ((bfd *ibfd, bfd *obfd));
+
+#define bfd_copy_private_bfd_data(ibfd, obfd) \
+ BFD_SEND (ibfd, _bfd_copy_private_bfd_data, \
+ (ibfd, obfd))
+#define bfd_sizeof_headers(abfd, reloc) \
+ BFD_SEND (abfd, _bfd_sizeof_headers, (abfd, reloc))
+
+#define bfd_find_nearest_line(abfd, sec, syms, off, file, func, line) \
+ BFD_SEND (abfd, _bfd_find_nearest_line, (abfd, sec, syms, off, file, func, line))
+
+ /* Do these three do anything useful at all, for any back end? */
+#define bfd_debug_info_start(abfd) \
+ BFD_SEND (abfd, _bfd_debug_info_start, (abfd))
+
+#define bfd_debug_info_end(abfd) \
+ BFD_SEND (abfd, _bfd_debug_info_end, (abfd))
+
+#define bfd_debug_info_accumulate(abfd, section) \
+ BFD_SEND (abfd, _bfd_debug_info_accumulate, (abfd, section))
+
+
+#define bfd_stat_arch_elt(abfd, stat) \
+ BFD_SEND (abfd, _bfd_stat_arch_elt,(abfd, stat))
+
+#define bfd_set_arch_mach(abfd, arch, mach)\
+ BFD_SEND ( abfd, _bfd_set_arch_mach, (abfd, arch, mach))
+
+#define bfd_get_relocated_section_contents(abfd, link_info, link_order, data, relocateable, symbols) \
+ BFD_SEND (abfd, _bfd_get_relocated_section_contents, \
+ (abfd, link_info, link_order, data, relocateable, symbols))
+
+#define bfd_relax_section(abfd, section, link_info, again) \
+ BFD_SEND (abfd, _bfd_relax_section, (abfd, section, link_info, again))
+
+#define bfd_link_hash_table_create(abfd) \
+ BFD_SEND (abfd, _bfd_link_hash_table_create, (abfd))
+
+#define bfd_link_add_symbols(abfd, info) \
+ BFD_SEND (abfd, _bfd_link_add_symbols, (abfd, info))
+
+#define bfd_final_link(abfd, info) \
+ BFD_SEND (abfd, _bfd_final_link, (abfd, info))
+
+#define bfd_free_cached_info(abfd) \
+ BFD_SEND (abfd, _bfd_free_cached_info, (abfd))
+
+#define bfd_get_dynamic_symtab_upper_bound(abfd) \
+ BFD_SEND (abfd, _bfd_get_dynamic_symtab_upper_bound, (abfd))
+
+#define bfd_canonicalize_dynamic_symtab(abfd, asymbols) \
+ BFD_SEND (abfd, _bfd_canonicalize_dynamic_symtab, (abfd, asymbols))
+
+#define bfd_get_dynamic_reloc_upper_bound(abfd) \
+ BFD_SEND (abfd, _bfd_get_dynamic_reloc_upper_bound, (abfd))
+
+#define bfd_canonicalize_dynamic_reloc(abfd, arels, asyms) \
+ BFD_SEND (abfd, _bfd_canonicalize_dynamic_reloc, (abfd, arels, asyms))
+
+symindex
+bfd_get_next_mapent PARAMS ((bfd *abfd, symindex previous, carsym **sym));
+
+boolean
+bfd_set_archive_head PARAMS ((bfd *output, bfd *new_head));
+
+bfd *
+bfd_get_elt_at_index PARAMS ((bfd *archive, int index));
+
+bfd *
+bfd_openr_next_archived_file PARAMS ((bfd *archive, bfd *previous));
+
+CONST char *
+bfd_core_file_failing_command PARAMS ((bfd *abfd));
+
+int
+bfd_core_file_failing_signal PARAMS ((bfd *abfd));
+
+boolean
+core_file_matches_executable_p
+ PARAMS ((bfd *core_bfd, bfd *exec_bfd));
+
+#define BFD_SEND(bfd, message, arglist) \
+ ((*((bfd)->xvec->message)) arglist)
+
+#ifdef DEBUG_BFD_SEND
+#undef BFD_SEND
+#define BFD_SEND(bfd, message, arglist) \
+ (((bfd) && (bfd)->xvec && (bfd)->xvec->message) ? \
+ ((*((bfd)->xvec->message)) arglist) : \
+ (bfd_assert (__FILE__,__LINE__), NULL))
+#endif
+#define BFD_SEND_FMT(bfd, message, arglist) \
+ (((bfd)->xvec->message[(int)((bfd)->format)]) arglist)
+
+#ifdef DEBUG_BFD_SEND
+#undef BFD_SEND_FMT
+#define BFD_SEND_FMT(bfd, message, arglist) \
+ (((bfd) && (bfd)->xvec && (bfd)->xvec->message) ? \
+ (((bfd)->xvec->message[(int)((bfd)->format)]) arglist) : \
+ (bfd_assert (__FILE__,__LINE__), NULL))
+#endif
+enum bfd_flavour {
+ bfd_target_unknown_flavour,
+ bfd_target_aout_flavour,
+ bfd_target_coff_flavour,
+ bfd_target_ecoff_flavour,
+ bfd_target_elf_flavour,
+ bfd_target_ieee_flavour,
+ bfd_target_nlm_flavour,
+ bfd_target_oasys_flavour,
+ bfd_target_tekhex_flavour,
+ bfd_target_srec_flavour,
+ bfd_target_som_flavour,
+ bfd_target_os9k_flavour};
+
+ /* Forward declaration. */
+typedef struct bfd_link_info _bfd_link_info;
+
+typedef struct bfd_target
+{
+ char *name;
+ enum bfd_flavour flavour;
+ boolean byteorder_big_p;
+ boolean header_byteorder_big_p;
+ flagword object_flags;
+ flagword section_flags;
+ char symbol_leading_char;
+ char ar_pad_char;
+ unsigned short ar_max_namelen;
+ unsigned int align_power_min;
+ bfd_vma (*bfd_getx64) PARAMS ((const bfd_byte *));
+ bfd_signed_vma (*bfd_getx_signed_64) PARAMS ((const bfd_byte *));
+ void (*bfd_putx64) PARAMS ((bfd_vma, bfd_byte *));
+ bfd_vma (*bfd_getx32) PARAMS ((const bfd_byte *));
+ bfd_signed_vma (*bfd_getx_signed_32) PARAMS ((const bfd_byte *));
+ void (*bfd_putx32) PARAMS ((bfd_vma, bfd_byte *));
+ bfd_vma (*bfd_getx16) PARAMS ((const bfd_byte *));
+ bfd_signed_vma (*bfd_getx_signed_16) PARAMS ((const bfd_byte *));
+ void (*bfd_putx16) PARAMS ((bfd_vma, bfd_byte *));
+ bfd_vma (*bfd_h_getx64) PARAMS ((const bfd_byte *));
+ bfd_signed_vma (*bfd_h_getx_signed_64) PARAMS ((const bfd_byte *));
+ void (*bfd_h_putx64) PARAMS ((bfd_vma, bfd_byte *));
+ bfd_vma (*bfd_h_getx32) PARAMS ((const bfd_byte *));
+ bfd_signed_vma (*bfd_h_getx_signed_32) PARAMS ((const bfd_byte *));
+ void (*bfd_h_putx32) PARAMS ((bfd_vma, bfd_byte *));
+ bfd_vma (*bfd_h_getx16) PARAMS ((const bfd_byte *));
+ bfd_signed_vma (*bfd_h_getx_signed_16) PARAMS ((const bfd_byte *));
+ void (*bfd_h_putx16) PARAMS ((bfd_vma, bfd_byte *));
+ const struct bfd_target *(*_bfd_check_format[bfd_type_end]) PARAMS ((bfd *));
+ boolean (*_bfd_set_format[bfd_type_end]) PARAMS ((bfd *));
+ boolean (*_bfd_write_contents[bfd_type_end]) PARAMS ((bfd *));
+
+ /* Generic entry points. */
+#define BFD_JUMP_TABLE_GENERIC(NAME)\
+CAT(NAME,_close_and_cleanup),\
+CAT(NAME,_bfd_free_cached_info),\
+CAT(NAME,_new_section_hook),\
+CAT(NAME,_get_section_contents)
+ /* Called when the BFD is being closed to do any necessary cleanup. */
+ boolean (*_close_and_cleanup) PARAMS ((bfd *));
+ /* Ask the BFD to free all cached information. */
+ boolean (*_bfd_free_cached_info) PARAMS ((bfd *));
+ /* Called when a new section is created. */
+ boolean (*_new_section_hook) PARAMS ((bfd *, sec_ptr));
+ /* Read the contents of a section. */
+ boolean (*_bfd_get_section_contents) PARAMS ((bfd *, sec_ptr, PTR,
+ file_ptr, bfd_size_type));
+
+ /* Entry points to copy private data. */
+#define BFD_JUMP_TABLE_COPY(NAME)\
+CAT(NAME,_bfd_copy_private_bfd_data),\
+CAT(NAME,_bfd_copy_private_section_data)
+ /* Called to copy BFD general private data from one object file
+ to another. */
+ boolean (*_bfd_copy_private_bfd_data) PARAMS ((bfd *, bfd *));
+ /* Called to copy BFD private section data from one object file
+ to another. */
+ boolean (*_bfd_copy_private_section_data) PARAMS ((bfd *, sec_ptr,
+ bfd *, sec_ptr));
+
+ /* Core file entry points. */
+#define BFD_JUMP_TABLE_CORE(NAME)\
+CAT(NAME,_core_file_failing_command),\
+CAT(NAME,_core_file_failing_signal),\
+CAT(NAME,_core_file_matches_executable_p)
+ char * (*_core_file_failing_command) PARAMS ((bfd *));
+ int (*_core_file_failing_signal) PARAMS ((bfd *));
+ boolean (*_core_file_matches_executable_p) PARAMS ((bfd *, bfd *));
+
+ /* Archive entry points. */
+#define BFD_JUMP_TABLE_ARCHIVE(NAME)\
+CAT(NAME,_slurp_armap),\
+CAT(NAME,_slurp_extended_name_table),\
+CAT(NAME,_truncate_arname),\
+CAT(NAME,_write_armap),\
+CAT(NAME,_openr_next_archived_file),\
+CAT(NAME,_generic_stat_arch_elt)
+ boolean (*_bfd_slurp_armap) PARAMS ((bfd *));
+ boolean (*_bfd_slurp_extended_name_table) PARAMS ((bfd *));
+ void (*_bfd_truncate_arname) PARAMS ((bfd *, CONST char *, char *));
+ boolean (*write_armap) PARAMS ((bfd *arch,
+ unsigned int elength,
+ struct orl *map,
+ unsigned int orl_count,
+ int stridx));
+ bfd * (*openr_next_archived_file) PARAMS ((bfd *arch, bfd *prev));
+ int (*_bfd_stat_arch_elt) PARAMS ((bfd *, struct stat *));
+
+ /* Entry points used for symbols. */
+#define BFD_JUMP_TABLE_SYMBOLS(NAME)\
+CAT(NAME,_get_symtab_upper_bound),\
+CAT(NAME,_get_symtab),\
+CAT(NAME,_make_empty_symbol),\
+CAT(NAME,_print_symbol),\
+CAT(NAME,_get_symbol_info),\
+CAT(NAME,_bfd_is_local_label),\
+CAT(NAME,_get_lineno),\
+CAT(NAME,_find_nearest_line),\
+CAT(NAME,_bfd_make_debug_symbol)
+ long (*_bfd_get_symtab_upper_bound) PARAMS ((bfd *));
+ long (*_bfd_canonicalize_symtab) PARAMS ((bfd *,
+ struct symbol_cache_entry **));
+ struct symbol_cache_entry *
+ (*_bfd_make_empty_symbol) PARAMS ((bfd *));
+ void (*_bfd_print_symbol) PARAMS ((bfd *, PTR,
+ struct symbol_cache_entry *,
+ bfd_print_symbol_type));
+#define bfd_print_symbol(b,p,s,e) BFD_SEND(b, _bfd_print_symbol, (b,p,s,e))
+ void (*_bfd_get_symbol_info) PARAMS ((bfd *,
+ struct symbol_cache_entry *,
+ symbol_info *));
+#define bfd_get_symbol_info(b,p,e) BFD_SEND(b, _bfd_get_symbol_info, (b,p,e))
+ boolean (*_bfd_is_local_label) PARAMS ((bfd *, asymbol *));
+
+ alent * (*_get_lineno) PARAMS ((bfd *, struct symbol_cache_entry *));
+ boolean (*_bfd_find_nearest_line) PARAMS ((bfd *abfd,
+ struct sec *section, struct symbol_cache_entry **symbols,
+ bfd_vma offset, CONST char **file, CONST char **func,
+ unsigned int *line));
+ /* Back-door to allow format-aware applications to create debug symbols
+ while using BFD for everything else. Currently used by the assembler
+ when creating COFF files. */
+ asymbol * (*_bfd_make_debug_symbol) PARAMS ((
+ bfd *abfd,
+ void *ptr,
+ unsigned long size));
+
+ /* Routines for relocs. */
+#define BFD_JUMP_TABLE_RELOCS(NAME)\
+CAT(NAME,_get_reloc_upper_bound),\
+CAT(NAME,_canonicalize_reloc),\
+CAT(NAME,_bfd_reloc_type_lookup)
+ long (*_get_reloc_upper_bound) PARAMS ((bfd *, sec_ptr));
+ long (*_bfd_canonicalize_reloc) PARAMS ((bfd *, sec_ptr, arelent **,
+ struct symbol_cache_entry **));
+ /* See documentation on reloc types. */
+ CONST struct reloc_howto_struct *
+ (*reloc_type_lookup) PARAMS ((bfd *abfd,
+ bfd_reloc_code_real_type code));
+
+ /* Routines used when writing an object file. */
+#define BFD_JUMP_TABLE_WRITE(NAME)\
+CAT(NAME,_set_arch_mach),\
+CAT(NAME,_set_section_contents)
+ boolean (*_bfd_set_arch_mach) PARAMS ((bfd *, enum bfd_architecture,
+ unsigned long));
+ boolean (*_bfd_set_section_contents) PARAMS ((bfd *, sec_ptr, PTR,
+ file_ptr, bfd_size_type));
+
+ /* Routines used by the linker. */
+#define BFD_JUMP_TABLE_LINK(NAME)\
+CAT(NAME,_sizeof_headers),\
+CAT(NAME,_bfd_get_relocated_section_contents),\
+CAT(NAME,_bfd_relax_section),\
+CAT(NAME,_bfd_link_hash_table_create),\
+CAT(NAME,_bfd_link_add_symbols),\
+CAT(NAME,_bfd_final_link)
+ int (*_bfd_sizeof_headers) PARAMS ((bfd *, boolean));
+ bfd_byte * (*_bfd_get_relocated_section_contents) PARAMS ((bfd *,
+ struct bfd_link_info *, struct bfd_link_order *,
+ bfd_byte *data, boolean relocateable,
+ struct symbol_cache_entry **));
+
+ boolean (*_bfd_relax_section) PARAMS ((bfd *, struct sec *,
+ struct bfd_link_info *, boolean *again));
+
+ /* Create a hash table for the linker. Different backends store
+ different information in this table. */
+ struct bfd_link_hash_table *(*_bfd_link_hash_table_create) PARAMS ((bfd *));
+
+ /* Add symbols from this object file into the hash table. */
+ boolean (*_bfd_link_add_symbols) PARAMS ((bfd *, struct bfd_link_info *));
+
+ /* Do a link based on the link_order structures attached to each
+ section of the BFD. */
+ boolean (*_bfd_final_link) PARAMS ((bfd *, struct bfd_link_info *));
+
+ /* Routines to handle dynamic symbols and relocs. */
+#define BFD_JUMP_TABLE_DYNAMIC(NAME)\
+CAT(NAME,_get_dynamic_symtab_upper_bound),\
+CAT(NAME,_canonicalize_dynamic_symtab),\
+CAT(NAME,_get_dynamic_reloc_upper_bound),\
+CAT(NAME,_canonicalize_dynamic_reloc)
+ /* Get the amount of memory required to hold the dynamic symbols. */
+ long (*_bfd_get_dynamic_symtab_upper_bound) PARAMS ((bfd *));
+ /* Read in the dynamic symbols. */
+ long (*_bfd_canonicalize_dynamic_symtab)
+ PARAMS ((bfd *, struct symbol_cache_entry **));
+ /* Get the amount of memory required to hold the dynamic relocs. */
+ long (*_bfd_get_dynamic_reloc_upper_bound) PARAMS ((bfd *));
+ /* Read in the dynamic relocs. */
+ long (*_bfd_canonicalize_dynamic_reloc)
+ PARAMS ((bfd *, arelent **, struct symbol_cache_entry **));
+
+ PTR backend_data;
+} bfd_target;
+const bfd_target *
+bfd_find_target PARAMS ((CONST char *target_name, bfd *abfd));
+
+const char **
+bfd_target_list PARAMS ((void));
+
+boolean
+bfd_check_format PARAMS ((bfd *abfd, bfd_format format));
+
+boolean
+bfd_check_format_matches PARAMS ((bfd *abfd, bfd_format format, char ***matching));
+
+boolean
+bfd_set_format PARAMS ((bfd *abfd, bfd_format format));
+
+CONST char *
+bfd_format_string PARAMS ((bfd_format format));
+
+#endif
diff --git a/gnu/usr.bin/gdb/bfd/cache.c b/gnu/usr.bin/gdb/bfd/cache.c
new file mode 100644
index 0000000..fc02122
--- /dev/null
+++ b/gnu/usr.bin/gdb/bfd/cache.c
@@ -0,0 +1,343 @@
+/* BFD library -- caching of file descriptors.
+ Copyright 1990, 1991, 1992, 1994 Free Software Foundation, Inc.
+ Hacked by Steve Chamberlain of Cygnus Support (steve@cygnus.com).
+
+This file is part of BFD, the Binary File Descriptor library.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/*
+SECTION
+ File caching
+
+ The file caching mechanism is embedded within BFD and allows
+ the application to open as many BFDs as it wants without
+ regard to the underlying operating system's file descriptor
+ limit (often as low as 20 open files). The module in
+ <<cache.c>> maintains a least recently used list of
+ <<BFD_CACHE_MAX_OPEN>> files, and exports the name
+ <<bfd_cache_lookup>>, which runs around and makes sure that
+ the required BFD is open. If not, then it chooses a file to
+ close, closes it and opens the one wanted, returning its file
+ handle.
+
+*/
+
+#include "bfd.h"
+#include "sysdep.h"
+#include "libbfd.h"
+
+static void insert PARAMS ((bfd *));
+static void snip PARAMS ((bfd *));
+static boolean close_one PARAMS ((void));
+static boolean bfd_cache_delete PARAMS ((bfd *));
+
+/*
+INTERNAL_FUNCTION
+ BFD_CACHE_MAX_OPEN macro
+
+DESCRIPTION
+ The maximum number of files which the cache will keep open at
+ one time.
+
+.#define BFD_CACHE_MAX_OPEN 10
+
+*/
+
+/* The number of BFD files we have open. */
+
+static int open_files;
+
+/*
+INTERNAL_FUNCTION
+ bfd_last_cache
+
+SYNOPSIS
+ extern bfd *bfd_last_cache;
+
+DESCRIPTION
+ Zero, or a pointer to the topmost BFD on the chain. This is
+ used by the <<bfd_cache_lookup>> macro in @file{libbfd.h} to
+ determine when it can avoid a function call.
+*/
+
+bfd *bfd_last_cache;
+
+/*
+ INTERNAL_FUNCTION
+ bfd_cache_lookup
+
+ DESCRIPTION
+ Check to see if the required BFD is the same as the last one
+ looked up. If so, then it can use the stream in the BFD with
+ impunity, since it can't have changed since the last lookup;
+ otherwise, it has to perform the complicated lookup function.
+
+ .#define bfd_cache_lookup(x) \
+ . ((x)==bfd_last_cache? \
+ . (FILE*)(bfd_last_cache->iostream): \
+ . bfd_cache_lookup_worker(x))
+
+
+ */
+
+/* Insert a BFD into the cache. */
+
+static INLINE void
+insert (abfd)
+ bfd *abfd;
+{
+ if (bfd_last_cache == NULL)
+ {
+ abfd->lru_next = abfd;
+ abfd->lru_prev = abfd;
+ }
+ else
+ {
+ abfd->lru_next = bfd_last_cache;
+ abfd->lru_prev = bfd_last_cache->lru_prev;
+ abfd->lru_prev->lru_next = abfd;
+ abfd->lru_next->lru_prev = abfd;
+ }
+ bfd_last_cache = abfd;
+}
+
+/* Remove a BFD from the cache. */
+
+static INLINE void
+snip (abfd)
+ bfd *abfd;
+{
+ abfd->lru_prev->lru_next = abfd->lru_next;
+ abfd->lru_next->lru_prev = abfd->lru_prev;
+ if (abfd == bfd_last_cache)
+ {
+ bfd_last_cache = abfd->lru_next;
+ if (abfd == bfd_last_cache)
+ bfd_last_cache = NULL;
+ }
+}
+
+/* We need to open a new file, and the cache is full. Find the least
+ recently used cacheable BFD and close it. */
+
+static boolean
+close_one ()
+{
+ register bfd *kill;
+
+ if (bfd_last_cache == NULL)
+ kill = NULL;
+ else
+ {
+ for (kill = bfd_last_cache->lru_prev;
+ ! kill->cacheable;
+ kill = kill->lru_prev)
+ {
+ if (kill == bfd_last_cache)
+ {
+ kill = NULL;
+ break;
+ }
+ }
+ }
+
+ if (kill == NULL)
+ {
+ /* There are no open cacheable BFD's. */
+ return true;
+ }
+
+ kill->where = ftell ((FILE *) kill->iostream);
+
+ return bfd_cache_delete (kill);
+}
+
+/* Close a BFD and remove it from the cache. */
+
+static boolean
+bfd_cache_delete (abfd)
+ bfd *abfd;
+{
+ boolean ret;
+
+ if (fclose ((FILE *) abfd->iostream) == 0)
+ ret = true;
+ else
+ {
+ ret = false;
+ bfd_set_error (bfd_error_system_call);
+ }
+
+ snip (abfd);
+
+ abfd->iostream = NULL;
+ --open_files;
+
+ return ret;
+}
+
+/*
+INTERNAL_FUNCTION
+ bfd_cache_init
+
+SYNOPSIS
+ boolean bfd_cache_init (bfd *abfd);
+
+DESCRIPTION
+ Add a newly opened BFD to the cache.
+*/
+
+boolean
+bfd_cache_init (abfd)
+ bfd *abfd;
+{
+ BFD_ASSERT (abfd->iostream != NULL);
+ if (open_files >= BFD_CACHE_MAX_OPEN)
+ {
+ if (! close_one ())
+ return false;
+ }
+ insert (abfd);
+ ++open_files;
+ return true;
+}
+
+/*
+INTERNAL_FUNCTION
+ bfd_cache_close
+
+SYNOPSIS
+ boolean bfd_cache_close (bfd *abfd);
+
+DESCRIPTION
+ Remove the BFD @var{abfd} from the cache. If the attached file is open,
+ then close it too.
+
+RETURNS
+ <<false>> is returned if closing the file fails, <<true>> is
+ returned if all is well.
+*/
+
+boolean
+bfd_cache_close (abfd)
+ bfd *abfd;
+{
+ if (abfd->iostream == NULL)
+ return true;
+
+ return bfd_cache_delete (abfd);
+}
+
+/*
+INTERNAL_FUNCTION
+ bfd_open_file
+
+SYNOPSIS
+ FILE* bfd_open_file(bfd *abfd);
+
+DESCRIPTION
+ Call the OS to open a file for @var{abfd}. Return the <<FILE *>>
+ (possibly <<NULL>>) that results from this operation. Set up the
+ BFD so that future accesses know the file is open. If the <<FILE *>>
+ returned is <<NULL>>, then it won't have been put in the
+ cache, so it won't have to be removed from it.
+*/
+
+FILE *
+bfd_open_file (abfd)
+ bfd *abfd;
+{
+ abfd->cacheable = true; /* Allow it to be closed later. */
+
+ if (open_files >= BFD_CACHE_MAX_OPEN)
+ {
+ if (! close_one ())
+ return NULL;
+ }
+
+ switch (abfd->direction)
+ {
+ case read_direction:
+ case no_direction:
+ abfd->iostream = (char *) fopen (abfd->filename, FOPEN_RB);
+ break;
+ case both_direction:
+ case write_direction:
+ if (abfd->opened_once == true)
+ {
+ abfd->iostream = (char *) fopen (abfd->filename, FOPEN_RUB);
+ if (abfd->iostream == NULL)
+ abfd->iostream = (char *) fopen (abfd->filename, FOPEN_WUB);
+ }
+ else
+ {
+ /*open for creat */
+ abfd->iostream = (char *) fopen (abfd->filename, FOPEN_WB);
+ abfd->opened_once = true;
+ }
+ break;
+ }
+
+ if (abfd->iostream != NULL)
+ {
+ if (! bfd_cache_init (abfd))
+ return NULL;
+ }
+
+ return (FILE *) abfd->iostream;
+}
+
+/*
+INTERNAL_FUNCTION
+ bfd_cache_lookup_worker
+
+SYNOPSIS
+ FILE *bfd_cache_lookup_worker(bfd *abfd);
+
+DESCRIPTION
+ Called when the macro <<bfd_cache_lookup>> fails to find a
+ quick answer. Find a file descriptor for @var{abfd}. If
+ necessary, it open it. If there are already more than
+ <<BFD_CACHE_MAX_OPEN>> files open, it tries to close one first, to
+ avoid running out of file descriptors.
+*/
+
+FILE *
+bfd_cache_lookup_worker (abfd)
+ bfd *abfd;
+{
+ if (abfd->my_archive)
+ abfd = abfd->my_archive;
+
+ if (abfd->iostream != NULL)
+ {
+ /* Move the file to the start of the cache. */
+ if (abfd != bfd_last_cache)
+ {
+ snip (abfd);
+ insert (abfd);
+ }
+ }
+ else
+ {
+ if (bfd_open_file (abfd) == NULL)
+ return NULL;
+ if (fseek ((FILE *) abfd->iostream, abfd->where, SEEK_SET) != 0)
+ return NULL;
+ }
+
+ return (FILE *) abfd->iostream;
+}
diff --git a/gnu/usr.bin/gdb/bfd/coff-i386.c b/gnu/usr.bin/gdb/bfd/coff-i386.c
new file mode 100644
index 0000000..aaac075
--- /dev/null
+++ b/gnu/usr.bin/gdb/bfd/coff-i386.c
@@ -0,0 +1,354 @@
+/* BFD back-end for Intel 386 COFF files.
+ Copyright 1990, 1991, 1992, 1993, 1994 Free Software Foundation, Inc.
+ Written by Cygnus Support.
+
+This file is part of BFD, the Binary File Descriptor library.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "bfd.h"
+#include "sysdep.h"
+#include "libbfd.h"
+#include "obstack.h"
+#include "coff/i386.h"
+#include "coff/internal.h"
+#include "libcoff.h"
+
+static bfd_reloc_status_type coff_i386_reloc PARAMS ((bfd *abfd,
+ arelent *reloc_entry,
+ asymbol *symbol,
+ PTR data,
+ asection *input_section,
+ bfd *output_bfd,
+ char **error_message));
+
+/* The page size is a guess based on ELF. */
+#define COFF_PAGE_SIZE 0x1000
+
+/* For some reason when using i386 COFF the value stored in the .text
+ section for a reference to a common symbol is the value itself plus
+ any desired offset. Ian Taylor, Cygnus Support. */
+
+/* If we are producing relocateable output, we need to do some
+ adjustments to the object file that are not done by the
+ bfd_perform_relocation function. This function is called by every
+ reloc type to make any required adjustments. */
+
+static bfd_reloc_status_type
+coff_i386_reloc (abfd, reloc_entry, symbol, data, input_section, output_bfd,
+ error_message)
+ bfd *abfd;
+ arelent *reloc_entry;
+ asymbol *symbol;
+ PTR data;
+ asection *input_section;
+ bfd *output_bfd;
+ char **error_message;
+{
+ symvalue diff;
+
+ if (output_bfd == (bfd *) NULL)
+ return bfd_reloc_continue;
+
+ if (bfd_is_com_section (symbol->section))
+ {
+ /* We are relocating a common symbol. The current value in the
+ object file is ORIG + OFFSET, where ORIG is the value of the
+ common symbol as seen by the object file when it was compiled
+ (this may be zero if the symbol was undefined) and OFFSET is
+ the offset into the common symbol (normally zero, but may be
+ non-zero when referring to a field in a common structure).
+ ORIG is the negative of reloc_entry->addend, which is set by
+ the CALC_ADDEND macro below. We want to replace the value in
+ the object file with NEW + OFFSET, where NEW is the value of
+ the common symbol which we are going to put in the final
+ object file. NEW is symbol->value. */
+ diff = symbol->value + reloc_entry->addend;
+ }
+ else
+ {
+ /* For some reason bfd_perform_relocation always effectively
+ ignores the addend for a COFF target when producing
+ relocateable output. This seems to be always wrong for 386
+ COFF, so we handle the addend here instead. */
+ diff = reloc_entry->addend;
+ }
+
+#define DOIT(x) \
+ x = ((x & ~howto->dst_mask) | (((x & howto->src_mask) + diff) & howto->dst_mask))
+
+ if (diff != 0)
+ {
+ const reloc_howto_type *howto = reloc_entry->howto;
+ unsigned char *addr = (unsigned char *) data + reloc_entry->address;
+
+ switch (howto->size)
+ {
+ case 0:
+ {
+ char x = bfd_get_8 (abfd, addr);
+ DOIT (x);
+ bfd_put_8 (abfd, x, addr);
+ }
+ break;
+
+ case 1:
+ {
+ short x = bfd_get_16 (abfd, addr);
+ DOIT (x);
+ bfd_put_16 (abfd, x, addr);
+ }
+ break;
+
+ case 2:
+ {
+ long x = bfd_get_32 (abfd, addr);
+ DOIT (x);
+ bfd_put_32 (abfd, x, addr);
+ }
+ break;
+
+ default:
+ abort ();
+ }
+ }
+
+ /* Now let bfd_perform_relocation finish everything up. */
+ return bfd_reloc_continue;
+}
+
+static reloc_howto_type howto_table[] =
+{
+ {0},
+ {1},
+ {2},
+ {3},
+ {4},
+ {5},
+ HOWTO (R_DIR32, /* type */
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 32, /* bitsize */
+ false, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_bitfield, /* complain_on_overflow */
+ coff_i386_reloc, /* special_function */
+ "dir32", /* name */
+ true, /* partial_inplace */
+ 0xffffffff, /* src_mask */
+ 0xffffffff, /* dst_mask */
+ false), /* pcrel_offset */
+ {7},
+ {010},
+ {011},
+ {012},
+ {013},
+ {014},
+ {015},
+ {016},
+ HOWTO (R_RELBYTE, /* type */
+ 0, /* rightshift */
+ 0, /* size (0 = byte, 1 = short, 2 = long) */
+ 8, /* bitsize */
+ false, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_bitfield, /* complain_on_overflow */
+ coff_i386_reloc, /* special_function */
+ "8", /* name */
+ true, /* partial_inplace */
+ 0x000000ff, /* src_mask */
+ 0x000000ff, /* dst_mask */
+ false), /* pcrel_offset */
+ HOWTO (R_RELWORD, /* type */
+ 0, /* rightshift */
+ 1, /* size (0 = byte, 1 = short, 2 = long) */
+ 16, /* bitsize */
+ false, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_bitfield, /* complain_on_overflow */
+ coff_i386_reloc, /* special_function */
+ "16", /* name */
+ true, /* partial_inplace */
+ 0x0000ffff, /* src_mask */
+ 0x0000ffff, /* dst_mask */
+ false), /* pcrel_offset */
+ HOWTO (R_RELLONG, /* type */
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 32, /* bitsize */
+ false, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_bitfield, /* complain_on_overflow */
+ coff_i386_reloc, /* special_function */
+ "32", /* name */
+ true, /* partial_inplace */
+ 0xffffffff, /* src_mask */
+ 0xffffffff, /* dst_mask */
+ false), /* pcrel_offset */
+ HOWTO (R_PCRBYTE, /* type */
+ 0, /* rightshift */
+ 0, /* size (0 = byte, 1 = short, 2 = long) */
+ 8, /* bitsize */
+ true, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_signed, /* complain_on_overflow */
+ coff_i386_reloc, /* special_function */
+ "DISP8", /* name */
+ true, /* partial_inplace */
+ 0x000000ff, /* src_mask */
+ 0x000000ff, /* dst_mask */
+ false), /* pcrel_offset */
+ HOWTO (R_PCRWORD, /* type */
+ 0, /* rightshift */
+ 1, /* size (0 = byte, 1 = short, 2 = long) */
+ 16, /* bitsize */
+ true, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_signed, /* complain_on_overflow */
+ coff_i386_reloc, /* special_function */
+ "DISP16", /* name */
+ true, /* partial_inplace */
+ 0x0000ffff, /* src_mask */
+ 0x0000ffff, /* dst_mask */
+ false), /* pcrel_offset */
+ HOWTO (R_PCRLONG, /* type */
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 32, /* bitsize */
+ true, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_signed, /* complain_on_overflow */
+ coff_i386_reloc, /* special_function */
+ "DISP32", /* name */
+ true, /* partial_inplace */
+ 0xffffffff, /* src_mask */
+ 0xffffffff, /* dst_mask */
+ false) /* pcrel_offset */
+};
+
+/* Turn a howto into a reloc nunmber */
+
+#define SELECT_RELOC(x,howto) { x.r_type = howto->type; }
+#define BADMAG(x) I386BADMAG(x)
+#define I386 1 /* Customize coffcode.h */
+
+#define RTYPE2HOWTO(cache_ptr, dst) \
+ cache_ptr->howto = howto_table + (dst)->r_type;
+
+/* On SCO Unix 3.2.2 the native assembler generates two .data
+ sections. We handle that by renaming the second one to .data2. It
+ does no harm to do this for any 386 COFF target. */
+#define TWO_DATA_SECS
+
+/* For 386 COFF a STYP_NOLOAD | STYP_BSS section is part of a shared
+ library. On some other COFF targets STYP_BSS is normally
+ STYP_NOLOAD. */
+#define BSS_NOLOAD_IS_SHARED_LIBRARY
+
+/* Compute the addend of a reloc. If the reloc is to a common symbol,
+ the object file contains the value of the common symbol. By the
+ time this is called, the linker may be using a different symbol
+ from a different object file with a different value. Therefore, we
+ hack wildly to locate the original symbol from this file so that we
+ can make the correct adjustment. This macro sets coffsym to the
+ symbol from the original file, and uses it to set the addend value
+ correctly. If this is not a common symbol, the usual addend
+ calculation is done, except that an additional tweak is needed for
+ PC relative relocs.
+ FIXME: This macro refers to symbols and asect; these are from the
+ calling function, not the macro arguments. */
+
+#define CALC_ADDEND(abfd, ptr, reloc, cache_ptr) \
+ { \
+ coff_symbol_type *coffsym = (coff_symbol_type *) NULL; \
+ if (ptr && bfd_asymbol_bfd (ptr) != abfd) \
+ coffsym = (obj_symbols (abfd) \
+ + (cache_ptr->sym_ptr_ptr - symbols)); \
+ else if (ptr) \
+ coffsym = coff_symbol_from (abfd, ptr); \
+ if (coffsym != (coff_symbol_type *) NULL \
+ && coffsym->native->u.syment.n_scnum == 0) \
+ cache_ptr->addend = - coffsym->native->u.syment.n_value; \
+ else if (ptr && bfd_asymbol_bfd (ptr) == abfd \
+ && ptr->section != (asection *) NULL) \
+ cache_ptr->addend = - (ptr->section->vma + ptr->value); \
+ else \
+ cache_ptr->addend = 0; \
+ if (ptr && howto_table[reloc.r_type].pc_relative) \
+ cache_ptr->addend += asect->vma; \
+ }
+
+#include "coffcode.h"
+
+static const bfd_target *
+i3coff_object_p(a)
+ bfd *a;
+{
+ return coff_object_p(a);
+}
+
+const bfd_target
+#ifdef TARGET_SYM
+ TARGET_SYM =
+#else
+ i386coff_vec =
+#endif
+{
+#ifdef TARGET_NAME
+ TARGET_NAME,
+#else
+ "coff-i386", /* name */
+#endif
+ bfd_target_coff_flavour,
+ false, /* data byte order is little */
+ false, /* header byte order is little */
+
+ (HAS_RELOC | EXEC_P | /* object flags */
+ HAS_LINENO | HAS_DEBUG |
+ HAS_SYMS | HAS_LOCALS | WP_TEXT | D_PAGED),
+
+ (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC), /* section flags */
+ 0, /* leading underscore */
+ '/', /* ar_pad_char */
+ 15, /* ar_max_namelen */
+
+ 2, /* minimum alignment power */
+ bfd_getl64, bfd_getl_signed_64, bfd_putl64,
+ bfd_getl32, bfd_getl_signed_32, bfd_putl32,
+ bfd_getl16, bfd_getl_signed_16, bfd_putl16, /* data */
+ bfd_getl64, bfd_getl_signed_64, bfd_putl64,
+ bfd_getl32, bfd_getl_signed_32, bfd_putl32,
+ bfd_getl16, bfd_getl_signed_16, bfd_putl16, /* hdrs */
+
+/* Note that we allow an object file to be treated as a core file as well. */
+ {_bfd_dummy_target, i3coff_object_p, /* bfd_check_format */
+ bfd_generic_archive_p, i3coff_object_p},
+ {bfd_false, coff_mkobject, _bfd_generic_mkarchive, /* bfd_set_format */
+ bfd_false},
+ {bfd_false, coff_write_object_contents, /* bfd_write_contents */
+ _bfd_write_archive_contents, bfd_false},
+
+ BFD_JUMP_TABLE_GENERIC (coff),
+ BFD_JUMP_TABLE_COPY (coff),
+ BFD_JUMP_TABLE_CORE (_bfd_nocore),
+ BFD_JUMP_TABLE_ARCHIVE (_bfd_archive_coff),
+ BFD_JUMP_TABLE_SYMBOLS (coff),
+ BFD_JUMP_TABLE_RELOCS (coff),
+ BFD_JUMP_TABLE_WRITE (coff),
+ BFD_JUMP_TABLE_LINK (coff),
+ BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic),
+
+ COFF_SWAP_TABLE,
+};
diff --git a/gnu/usr.bin/gdb/bfd/coffcode.h b/gnu/usr.bin/gdb/bfd/coffcode.h
new file mode 100644
index 0000000..206a381
--- /dev/null
+++ b/gnu/usr.bin/gdb/bfd/coffcode.h
@@ -0,0 +1,2544 @@
+/* Support for the generic parts of most COFF variants, for BFD.
+ Copyright 1990, 1991, 1992, 1993, 1994 Free Software Foundation, Inc.
+ Written by Cygnus Support.
+
+This file is part of BFD, the Binary File Descriptor library.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/*
+Most of this hacked by Steve Chamberlain,
+ sac@cygnus.com
+*/
+/*
+
+SECTION
+ coff backends
+
+ BFD supports a number of different flavours of coff format.
+ The major differences between formats are the sizes and
+ alignments of fields in structures on disk, and the occasional
+ extra field.
+
+ Coff in all its varieties is implemented with a few common
+ files and a number of implementation specific files. For
+ example, The 88k bcs coff format is implemented in the file
+ @file{coff-m88k.c}. This file @code{#include}s
+ @file{coff/m88k.h} which defines the external structure of the
+ coff format for the 88k, and @file{coff/internal.h} which
+ defines the internal structure. @file{coff-m88k.c} also
+ defines the relocations used by the 88k format
+ @xref{Relocations}.
+
+ The Intel i960 processor version of coff is implemented in
+ @file{coff-i960.c}. This file has the same structure as
+ @file{coff-m88k.c}, except that it includes @file{coff/i960.h}
+ rather than @file{coff-m88k.h}.
+
+SUBSECTION
+ Porting to a new version of coff
+
+ The recommended method is to select from the existing
+ implementations the version of coff which is most like the one
+ you want to use. For example, we'll say that i386 coff is
+ the one you select, and that your coff flavour is called foo.
+ Copy @file{i386coff.c} to @file{foocoff.c}, copy
+ @file{../include/coff/i386.h} to @file{../include/coff/foo.h},
+ and add the lines to @file{targets.c} and @file{Makefile.in}
+ so that your new back end is used. Alter the shapes of the
+ structures in @file{../include/coff/foo.h} so that they match
+ what you need. You will probably also have to add
+ @code{#ifdef}s to the code in @file{coff/internal.h} and
+ @file{coffcode.h} if your version of coff is too wild.
+
+ You can verify that your new BFD backend works quite simply by
+ building @file{objdump} from the @file{binutils} directory,
+ and making sure that its version of what's going on and your
+ host system's idea (assuming it has the pretty standard coff
+ dump utility, usually called @code{att-dump} or just
+ @code{dump}) are the same. Then clean up your code, and send
+ what you've done to Cygnus. Then your stuff will be in the
+ next release, and you won't have to keep integrating it.
+
+SUBSECTION
+ How the coff backend works
+
+SUBSUBSECTION
+ File layout
+
+ The Coff backend is split into generic routines that are
+ applicable to any Coff target and routines that are specific
+ to a particular target. The target-specific routines are
+ further split into ones which are basically the same for all
+ Coff targets except that they use the external symbol format
+ or use different values for certain constants.
+
+ The generic routines are in @file{coffgen.c}. These routines
+ work for any Coff target. They use some hooks into the target
+ specific code; the hooks are in a @code{bfd_coff_backend_data}
+ structure, one of which exists for each target.
+
+ The essentially similar target-specific routines are in
+ @file{coffcode.h}. This header file includes executable C code.
+ The various Coff targets first include the appropriate Coff
+ header file, make any special defines that are needed, and
+ then include @file{coffcode.h}.
+
+ Some of the Coff targets then also have additional routines in
+ the target source file itself.
+
+ For example, @file{coff-i960.c} includes
+ @file{coff/internal.h} and @file{coff/i960.h}. It then
+ defines a few constants, such as @code{I960}, and includes
+ @file{coffcode.h}. Since the i960 has complex relocation
+ types, @file{coff-i960.c} also includes some code to
+ manipulate the i960 relocs. This code is not in
+ @file{coffcode.h} because it would not be used by any other
+ target.
+
+SUBSUBSECTION
+ Bit twiddling
+
+ Each flavour of coff supported in BFD has its own header file
+ describing the external layout of the structures. There is also
+ an internal description of the coff layout, in
+ @file{coff/internal.h}. A major function of the
+ coff backend is swapping the bytes and twiddling the bits to
+ translate the external form of the structures into the normal
+ internal form. This is all performed in the
+ @code{bfd_swap}_@i{thing}_@i{direction} routines. Some
+ elements are different sizes between different versions of
+ coff; it is the duty of the coff version specific include file
+ to override the definitions of various packing routines in
+ @file{coffcode.h}. E.g., the size of line number entry in coff is
+ sometimes 16 bits, and sometimes 32 bits. @code{#define}ing
+ @code{PUT_LNSZ_LNNO} and @code{GET_LNSZ_LNNO} will select the
+ correct one. No doubt, some day someone will find a version of
+ coff which has a varying field size not catered to at the
+ moment. To port BFD, that person will have to add more @code{#defines}.
+ Three of the bit twiddling routines are exported to
+ @code{gdb}; @code{coff_swap_aux_in}, @code{coff_swap_sym_in}
+ and @code{coff_swap_linno_in}. @code{GDB} reads the symbol
+ table on its own, but uses BFD to fix things up. More of the
+ bit twiddlers are exported for @code{gas};
+ @code{coff_swap_aux_out}, @code{coff_swap_sym_out},
+ @code{coff_swap_lineno_out}, @code{coff_swap_reloc_out},
+ @code{coff_swap_filehdr_out}, @code{coff_swap_aouthdr_out},
+ @code{coff_swap_scnhdr_out}. @code{Gas} currently keeps track
+ of all the symbol table and reloc drudgery itself, thereby
+ saving the internal BFD overhead, but uses BFD to swap things
+ on the way out, making cross ports much safer. Doing so also
+ allows BFD (and thus the linker) to use the same header files
+ as @code{gas}, which makes one avenue to disaster disappear.
+
+SUBSUBSECTION
+ Symbol reading
+
+ The simple canonical form for symbols used by BFD is not rich
+ enough to keep all the information available in a coff symbol
+ table. The back end gets around this problem by keeping the original
+ symbol table around, "behind the scenes".
+
+ When a symbol table is requested (through a call to
+ @code{bfd_canonicalize_symtab}), a request gets through to
+ @code{coff_get_normalized_symtab}. This reads the symbol table from
+ the coff file and swaps all the structures inside into the
+ internal form. It also fixes up all the pointers in the table
+ (represented in the file by offsets from the first symbol in
+ the table) into physical pointers to elements in the new
+ internal table. This involves some work since the meanings of
+ fields change depending upon context: a field that is a
+ pointer to another structure in the symbol table at one moment
+ may be the size in bytes of a structure at the next. Another
+ pass is made over the table. All symbols which mark file names
+ (<<C_FILE>> symbols) are modified so that the internal
+ string points to the value in the auxent (the real filename)
+ rather than the normal text associated with the symbol
+ (@code{".file"}).
+
+ At this time the symbol names are moved around. Coff stores
+ all symbols less than nine characters long physically
+ within the symbol table; longer strings are kept at the end of
+ the file in the string table. This pass moves all strings
+ into memory and replaces them with pointers to the strings.
+
+
+ The symbol table is massaged once again, this time to create
+ the canonical table used by the BFD application. Each symbol
+ is inspected in turn, and a decision made (using the
+ @code{sclass} field) about the various flags to set in the
+ @code{asymbol}. @xref{Symbols}. The generated canonical table
+ shares strings with the hidden internal symbol table.
+
+ Any linenumbers are read from the coff file too, and attached
+ to the symbols which own the functions the linenumbers belong to.
+
+SUBSUBSECTION
+ Symbol writing
+
+ Writing a symbol to a coff file which didn't come from a coff
+ file will lose any debugging information. The @code{asymbol}
+ structure remembers the BFD from which the symbol was taken, and on
+ output the back end makes sure that the same destination target as
+ source target is present.
+
+ When the symbols have come from a coff file then all the
+ debugging information is preserved.
+
+ Symbol tables are provided for writing to the back end in a
+ vector of pointers to pointers. This allows applications like
+ the linker to accumulate and output large symbol tables
+ without having to do too much byte copying.
+
+ This function runs through the provided symbol table and
+ patches each symbol marked as a file place holder
+ (@code{C_FILE}) to point to the next file place holder in the
+ list. It also marks each @code{offset} field in the list with
+ the offset from the first symbol of the current symbol.
+
+ Another function of this procedure is to turn the canonical
+ value form of BFD into the form used by coff. Internally, BFD
+ expects symbol values to be offsets from a section base; so a
+ symbol physically at 0x120, but in a section starting at
+ 0x100, would have the value 0x20. Coff expects symbols to
+ contain their final value, so symbols have their values
+ changed at this point to reflect their sum with their owning
+ section. This transformation uses the
+ <<output_section>> field of the @code{asymbol}'s
+ @code{asection} @xref{Sections}.
+
+ o <<coff_mangle_symbols>>
+
+ This routine runs though the provided symbol table and uses
+ the offsets generated by the previous pass and the pointers
+ generated when the symbol table was read in to create the
+ structured hierachy required by coff. It changes each pointer
+ to a symbol into the index into the symbol table of the asymbol.
+
+ o <<coff_write_symbols>>
+
+ This routine runs through the symbol table and patches up the
+ symbols from their internal form into the coff way, calls the
+ bit twiddlers, and writes out the table to the file.
+
+*/
+
+/*
+INTERNAL_DEFINITION
+ coff_symbol_type
+
+DESCRIPTION
+ The hidden information for an <<asymbol>> is described in a
+ <<combined_entry_type>>:
+
+CODE_FRAGMENT
+.
+.typedef struct coff_ptr_struct
+.{
+.
+. {* Remembers the offset from the first symbol in the file for
+. this symbol. Generated by coff_renumber_symbols. *}
+.unsigned int offset;
+.
+. {* Should the value of this symbol be renumbered. Used for
+. XCOFF C_BSTAT symbols. Set by coff_slurp_symbol_table. *}
+.unsigned int fix_value : 1;
+.
+. {* Should the tag field of this symbol be renumbered.
+. Created by coff_pointerize_aux. *}
+.unsigned int fix_tag : 1;
+.
+. {* Should the endidx field of this symbol be renumbered.
+. Created by coff_pointerize_aux. *}
+.unsigned int fix_end : 1;
+.
+. {* Should the x_csect.x_scnlen field be renumbered.
+. Created by coff_slurp_symbol_table. *}
+.unsigned int fix_scnlen : 1;
+.
+. {* The container for the symbol structure as read and translated
+. from the file. *}
+.
+.union {
+. union internal_auxent auxent;
+. struct internal_syment syment;
+. } u;
+.} combined_entry_type;
+.
+.
+.{* Each canonical asymbol really looks like this: *}
+.
+.typedef struct coff_symbol_struct
+.{
+. {* The actual symbol which the rest of BFD works with *}
+.asymbol symbol;
+.
+. {* A pointer to the hidden information for this symbol *}
+.combined_entry_type *native;
+.
+. {* A pointer to the linenumber information for this symbol *}
+.struct lineno_cache_entry *lineno;
+.
+. {* Have the line numbers been relocated yet ? *}
+.boolean done_lineno;
+.} coff_symbol_type;
+
+
+*/
+
+#include "coffswap.h"
+
+/* void warning(); */
+
+/*
+ * Return a word with STYP_* (scnhdr.s_flags) flags set to represent the
+ * incoming SEC_* flags. The inverse of this function is styp_to_sec_flags().
+ * NOTE: If you add to/change this routine, you should mirror the changes
+ * in styp_to_sec_flags().
+ */
+static long
+sec_to_styp_flags (sec_name, sec_flags)
+ CONST char *sec_name;
+ flagword sec_flags;
+{
+ long styp_flags = 0;
+
+ if (!strcmp (sec_name, _TEXT))
+ {
+ styp_flags = STYP_TEXT;
+ }
+ else if (!strcmp (sec_name, _DATA))
+ {
+ styp_flags = STYP_DATA;
+#ifdef TWO_DATA_SECS
+ }
+ else if (!strcmp (sec_name, ".data2"))
+ {
+ styp_flags = STYP_DATA;
+#endif /* TWO_DATA_SECS */
+ }
+ else if (!strcmp (sec_name, _BSS))
+ {
+ styp_flags = STYP_BSS;
+#ifdef _COMMENT
+ }
+ else if (!strcmp (sec_name, _COMMENT))
+ {
+ styp_flags = STYP_INFO;
+#endif /* _COMMENT */
+#ifdef _LIB
+ }
+ else if (!strcmp (sec_name, _LIB))
+ {
+ styp_flags = STYP_LIB;
+#endif /* _LIB */
+#ifdef _LIT
+ }
+ else if (!strcmp (sec_name, _LIT))
+ {
+ styp_flags = STYP_LIT;
+#endif /* _LIT */
+ }
+ else if (!strcmp (sec_name, ".debug"))
+ {
+#ifdef STYP_DEBUG
+ styp_flags = STYP_DEBUG;
+#else
+ styp_flags = STYP_INFO;
+#endif
+ }
+ else if (!strcmp (sec_name, ".stab")
+ || !strncmp (sec_name, ".stabstr", 8))
+ {
+ styp_flags = STYP_INFO;
+ }
+ /* Try and figure out what it should be */
+ else if (sec_flags & SEC_CODE)
+ {
+ styp_flags = STYP_TEXT;
+ }
+ else if (sec_flags & SEC_DATA)
+ {
+ styp_flags = STYP_DATA;
+ }
+ else if (sec_flags & SEC_READONLY)
+ {
+#ifdef STYP_LIT /* 29k readonly text/data section */
+ styp_flags = STYP_LIT;
+#else
+ styp_flags = STYP_TEXT;
+#endif /* STYP_LIT */
+ }
+ else if (sec_flags & SEC_LOAD)
+ {
+ styp_flags = STYP_TEXT;
+ }
+ else if (sec_flags & SEC_ALLOC)
+ {
+ styp_flags = STYP_BSS;
+ }
+
+#ifdef STYP_NOLOAD
+ if ((sec_flags & (SEC_NEVER_LOAD | SEC_COFF_SHARED_LIBRARY)) != 0)
+ styp_flags |= STYP_NOLOAD;
+#endif
+
+ return (styp_flags);
+}
+/*
+ * Return a word with SEC_* flags set to represent the incoming
+ * STYP_* flags (from scnhdr.s_flags). The inverse of this
+ * function is sec_to_styp_flags().
+ * NOTE: If you add to/change this routine, you should mirror the changes
+ * in sec_to_styp_flags().
+ */
+static flagword
+styp_to_sec_flags (abfd, hdr)
+ bfd * abfd;
+ PTR hdr;
+{
+ struct internal_scnhdr *internal_s = (struct internal_scnhdr *) hdr;
+ long styp_flags = internal_s->s_flags;
+ flagword sec_flags = 0;
+
+#ifdef STYP_NOLOAD
+ if (styp_flags & STYP_NOLOAD)
+ {
+ sec_flags |= SEC_NEVER_LOAD;
+ }
+#endif /* STYP_NOLOAD */
+
+ /* For 386 COFF, at least, an unloadable text or data section is
+ actually a shared library section. */
+ if (styp_flags & STYP_TEXT)
+ {
+ if (sec_flags & SEC_NEVER_LOAD)
+ sec_flags |= SEC_CODE | SEC_COFF_SHARED_LIBRARY;
+ else
+ sec_flags |= SEC_CODE | SEC_LOAD | SEC_ALLOC;
+ }
+ else if (styp_flags & STYP_DATA)
+ {
+ if (sec_flags & SEC_NEVER_LOAD)
+ sec_flags |= SEC_DATA | SEC_COFF_SHARED_LIBRARY;
+ else
+ sec_flags |= SEC_DATA | SEC_LOAD | SEC_ALLOC;
+ }
+ else if (styp_flags & STYP_BSS)
+ {
+#ifdef BSS_NOLOAD_IS_SHARED_LIBRARY
+ if (sec_flags & SEC_NEVER_LOAD)
+ sec_flags |= SEC_ALLOC | SEC_COFF_SHARED_LIBRARY;
+ else
+#endif
+ sec_flags |= SEC_ALLOC;
+ }
+ else if (styp_flags & STYP_INFO)
+ {
+ /* We mark these as SEC_DEBUGGING, but only if COFF_PAGE_SIZE is
+ defined. coff_compute_section_file_positions uses
+ COFF_PAGE_SIZE to ensure that the low order bits of the
+ section VMA and the file offset match. If we don't know
+ COFF_PAGE_SIZE, we can't ensure the correct correspondence,
+ and demand page loading of the file will fail. */
+#ifdef COFF_PAGE_SIZE
+ sec_flags |= SEC_DEBUGGING;
+#endif
+ }
+ else
+ {
+ sec_flags |= SEC_ALLOC | SEC_LOAD;
+ }
+
+#ifdef STYP_LIT /* A29k readonly text/data section type */
+ if ((styp_flags & STYP_LIT) == STYP_LIT)
+ {
+ sec_flags = (SEC_LOAD | SEC_ALLOC | SEC_READONLY);
+ }
+#endif /* STYP_LIT */
+#ifdef STYP_OTHER_LOAD /* Other loaded sections */
+ if (styp_flags & STYP_OTHER_LOAD)
+ {
+ sec_flags = (SEC_LOAD | SEC_ALLOC);
+ }
+#endif /* STYP_SDATA */
+
+ return (sec_flags);
+}
+
+#define get_index(symbol) ((long) (symbol)->udata)
+
+/*
+INTERNAL_DEFINITION
+ bfd_coff_backend_data
+
+CODE_FRAGMENT
+
+Special entry points for gdb to swap in coff symbol table parts:
+.typedef struct
+.{
+. void (*_bfd_coff_swap_aux_in) PARAMS ((
+. bfd *abfd,
+. PTR ext,
+. int type,
+. int class,
+. int indaux,
+. int numaux,
+. PTR in));
+.
+. void (*_bfd_coff_swap_sym_in) PARAMS ((
+. bfd *abfd ,
+. PTR ext,
+. PTR in));
+.
+. void (*_bfd_coff_swap_lineno_in) PARAMS ((
+. bfd *abfd,
+. PTR ext,
+. PTR in));
+.
+
+Special entry points for gas to swap out coff parts:
+
+. unsigned int (*_bfd_coff_swap_aux_out) PARAMS ((
+. bfd *abfd,
+. PTR in,
+. int type,
+. int class,
+. int indaux,
+. int numaux,
+. PTR ext));
+.
+. unsigned int (*_bfd_coff_swap_sym_out) PARAMS ((
+. bfd *abfd,
+. PTR in,
+. PTR ext));
+.
+. unsigned int (*_bfd_coff_swap_lineno_out) PARAMS ((
+. bfd *abfd,
+. PTR in,
+. PTR ext));
+.
+. unsigned int (*_bfd_coff_swap_reloc_out) PARAMS ((
+. bfd *abfd,
+. PTR src,
+. PTR dst));
+.
+. unsigned int (*_bfd_coff_swap_filehdr_out) PARAMS ((
+. bfd *abfd,
+. PTR in,
+. PTR out));
+.
+. unsigned int (*_bfd_coff_swap_aouthdr_out) PARAMS ((
+. bfd *abfd,
+. PTR in,
+. PTR out));
+.
+. unsigned int (*_bfd_coff_swap_scnhdr_out) PARAMS ((
+. bfd *abfd,
+. PTR in,
+. PTR out));
+.
+
+Special entry points for generic COFF routines to call target
+dependent COFF routines:
+
+. unsigned int _bfd_filhsz;
+. unsigned int _bfd_aoutsz;
+. unsigned int _bfd_scnhsz;
+. unsigned int _bfd_symesz;
+. unsigned int _bfd_auxesz;
+. unsigned int _bfd_linesz;
+. boolean _bfd_coff_long_filenames;
+. void (*_bfd_coff_swap_filehdr_in) PARAMS ((
+. bfd *abfd,
+. PTR ext,
+. PTR in));
+. void (*_bfd_coff_swap_aouthdr_in) PARAMS ((
+. bfd *abfd,
+. PTR ext,
+. PTR in));
+. void (*_bfd_coff_swap_scnhdr_in) PARAMS ((
+. bfd *abfd,
+. PTR ext,
+. PTR in));
+. boolean (*_bfd_coff_bad_format_hook) PARAMS ((
+. bfd *abfd,
+. PTR internal_filehdr));
+. boolean (*_bfd_coff_set_arch_mach_hook) PARAMS ((
+. bfd *abfd,
+. PTR internal_filehdr));
+. PTR (*_bfd_coff_mkobject_hook) PARAMS ((
+. bfd *abfd,
+. PTR internal_filehdr,
+. PTR internal_aouthdr));
+. flagword (*_bfd_styp_to_sec_flags_hook) PARAMS ((
+. bfd *abfd,
+. PTR internal_scnhdr));
+. asection *(*_bfd_make_section_hook) PARAMS ((
+. bfd *abfd,
+. char *name));
+. void (*_bfd_set_alignment_hook) PARAMS ((
+. bfd *abfd,
+. asection *sec,
+. PTR internal_scnhdr));
+. boolean (*_bfd_coff_slurp_symbol_table) PARAMS ((
+. bfd *abfd));
+. boolean (*_bfd_coff_symname_in_debug) PARAMS ((
+. bfd *abfd,
+. struct internal_syment *sym));
+. void (*_bfd_coff_reloc16_extra_cases) PARAMS ((
+. bfd *abfd,
+. struct bfd_link_info *link_info,
+. struct bfd_link_order *link_order,
+. arelent *reloc,
+. bfd_byte *data,
+. unsigned int *src_ptr,
+. unsigned int *dst_ptr));
+. int (*_bfd_coff_reloc16_estimate) PARAMS ((
+. bfd *abfd,
+. asection *input_section,
+. arelent *r,
+. unsigned int shrink,
+. struct bfd_link_info *link_info));
+.
+.} bfd_coff_backend_data;
+.
+.#define coff_backend_info(abfd) ((bfd_coff_backend_data *) (abfd)->xvec->backend_data)
+.
+.#define bfd_coff_swap_aux_in(a,e,t,c,ind,num,i) \
+. ((coff_backend_info (a)->_bfd_coff_swap_aux_in) (a,e,t,c,ind,num,i))
+.
+.#define bfd_coff_swap_sym_in(a,e,i) \
+. ((coff_backend_info (a)->_bfd_coff_swap_sym_in) (a,e,i))
+.
+.#define bfd_coff_swap_lineno_in(a,e,i) \
+. ((coff_backend_info ( a)->_bfd_coff_swap_lineno_in) (a,e,i))
+.
+.#define bfd_coff_swap_reloc_out(abfd, i, o) \
+. ((coff_backend_info (abfd)->_bfd_coff_swap_reloc_out) (abfd, i, o))
+.
+.#define bfd_coff_swap_lineno_out(abfd, i, o) \
+. ((coff_backend_info (abfd)->_bfd_coff_swap_lineno_out) (abfd, i, o))
+.
+.#define bfd_coff_swap_aux_out(a,i,t,c,ind,num,o) \
+. ((coff_backend_info (a)->_bfd_coff_swap_aux_out) (a,i,t,c,ind,num,o))
+.
+.#define bfd_coff_swap_sym_out(abfd, i,o) \
+. ((coff_backend_info (abfd)->_bfd_coff_swap_sym_out) (abfd, i, o))
+.
+.#define bfd_coff_swap_scnhdr_out(abfd, i,o) \
+. ((coff_backend_info (abfd)->_bfd_coff_swap_scnhdr_out) (abfd, i, o))
+.
+.#define bfd_coff_swap_filehdr_out(abfd, i,o) \
+. ((coff_backend_info (abfd)->_bfd_coff_swap_filehdr_out) (abfd, i, o))
+.
+.#define bfd_coff_swap_aouthdr_out(abfd, i,o) \
+. ((coff_backend_info (abfd)->_bfd_coff_swap_aouthdr_out) (abfd, i, o))
+.
+.#define bfd_coff_filhsz(abfd) (coff_backend_info (abfd)->_bfd_filhsz)
+.#define bfd_coff_aoutsz(abfd) (coff_backend_info (abfd)->_bfd_aoutsz)
+.#define bfd_coff_scnhsz(abfd) (coff_backend_info (abfd)->_bfd_scnhsz)
+.#define bfd_coff_symesz(abfd) (coff_backend_info (abfd)->_bfd_symesz)
+.#define bfd_coff_auxesz(abfd) (coff_backend_info (abfd)->_bfd_auxesz)
+.#define bfd_coff_linesz(abfd) (coff_backend_info (abfd)->_bfd_linesz)
+.#define bfd_coff_long_filenames(abfd) (coff_backend_info (abfd)->_bfd_coff_long_filenames)
+.#define bfd_coff_swap_filehdr_in(abfd, i,o) \
+. ((coff_backend_info (abfd)->_bfd_coff_swap_filehdr_in) (abfd, i, o))
+.
+.#define bfd_coff_swap_aouthdr_in(abfd, i,o) \
+. ((coff_backend_info (abfd)->_bfd_coff_swap_aouthdr_in) (abfd, i, o))
+.
+.#define bfd_coff_swap_scnhdr_in(abfd, i,o) \
+. ((coff_backend_info (abfd)->_bfd_coff_swap_scnhdr_in) (abfd, i, o))
+.
+.#define bfd_coff_bad_format_hook(abfd, filehdr) \
+. ((coff_backend_info (abfd)->_bfd_coff_bad_format_hook) (abfd, filehdr))
+.
+.#define bfd_coff_set_arch_mach_hook(abfd, filehdr)\
+. ((coff_backend_info (abfd)->_bfd_coff_set_arch_mach_hook) (abfd, filehdr))
+.#define bfd_coff_mkobject_hook(abfd, filehdr, aouthdr)\
+. ((coff_backend_info (abfd)->_bfd_coff_mkobject_hook) (abfd, filehdr, aouthdr))
+.
+.#define bfd_coff_styp_to_sec_flags_hook(abfd, scnhdr)\
+. ((coff_backend_info (abfd)->_bfd_styp_to_sec_flags_hook) (abfd, scnhdr))
+.
+.#define bfd_coff_make_section_hook(abfd, name)\
+. ((coff_backend_info (abfd)->_bfd_make_section_hook) (abfd, name))
+.
+.#define bfd_coff_set_alignment_hook(abfd, sec, scnhdr)\
+. ((coff_backend_info (abfd)->_bfd_set_alignment_hook) (abfd, sec, scnhdr))
+.
+.#define bfd_coff_slurp_symbol_table(abfd)\
+. ((coff_backend_info (abfd)->_bfd_coff_slurp_symbol_table) (abfd))
+.
+.#define bfd_coff_symname_in_debug(abfd, sym)\
+. ((coff_backend_info (abfd)->_bfd_coff_symname_in_debug) (abfd, sym))
+.
+.#define bfd_coff_reloc16_extra_cases(abfd, link_info, link_order, reloc, data, src_ptr, dst_ptr)\
+. ((coff_backend_info (abfd)->_bfd_coff_reloc16_extra_cases)\
+. (abfd, link_info, link_order, reloc, data, src_ptr, dst_ptr))
+.
+.#define bfd_coff_reloc16_estimate(abfd, section, reloc, shrink, link_info)\
+. ((coff_backend_info (abfd)->_bfd_coff_reloc16_estimate)\
+. (abfd, section, reloc, shrink, link_info))
+.
+*/
+
+/* See whether the magic number matches. */
+
+static boolean
+coff_bad_format_hook (abfd, filehdr)
+ bfd * abfd;
+ PTR filehdr;
+{
+ struct internal_filehdr *internal_f = (struct internal_filehdr *) filehdr;
+
+ if (BADMAG (*internal_f))
+ return false;
+
+ /* if the optional header is NULL or not the correct size then
+ quit; the only difference I can see between m88k dgux headers (MC88DMAGIC)
+ and Intel 960 readwrite headers (I960WRMAGIC) is that the
+ optional header is of a different size.
+
+ But the mips keeps extra stuff in it's opthdr, so dont check
+ when doing that
+ */
+
+#if defined(M88) || defined(I960)
+ if (internal_f->f_opthdr != 0 && AOUTSZ != internal_f->f_opthdr)
+ return false;
+#endif
+
+ return true;
+}
+
+static asection *
+coff_make_section_hook (abfd, name)
+ bfd * abfd;
+ char *name;
+{
+#ifdef TWO_DATA_SECS
+ /* FIXME: This predates the call to bfd_make_section_anyway
+ in make_a_section_from_file, and can probably go away. */
+ /* On SCO a file created by the Microsoft assembler can have two
+ .data sections. We use .data2 for the second one. */
+ if (strcmp (name, _DATA) == 0)
+ return bfd_make_section (abfd, ".data2");
+#endif
+ return (asection *) NULL;
+}
+
+/*
+ initialize a section structure with information peculiar to this
+ particular implementation of coff
+*/
+
+static boolean
+coff_new_section_hook (abfd, section)
+ bfd * abfd;
+ asection * section;
+{
+ section->alignment_power = abfd->xvec->align_power_min;
+ /* Allocate aux records for section symbols, to store size and
+ related info.
+
+ @@ Shouldn't use constant multiplier here! */
+ coffsymbol (section->symbol)->native =
+ (combined_entry_type *) bfd_zalloc (abfd,
+ sizeof (combined_entry_type) * 10);
+
+#ifdef COFF_SPARC
+ /* This is to allow double-word operations on addresses in data or bss. */
+ if (strcmp (section->name, ".data") == 0
+ || strcmp (section->name, ".bss") == 0)
+ section->alignment_power = 3;
+#endif /* COFF_SPARC */
+
+ return true;
+}
+
+
+#ifdef I960
+
+/* Set the alignment of a BFD section. */
+
+static void
+coff_set_alignment_hook (abfd, section, scnhdr)
+ bfd * abfd;
+ asection * section;
+ PTR scnhdr;
+{
+ struct internal_scnhdr *hdr = (struct internal_scnhdr *) scnhdr;
+ unsigned int i;
+
+ for (i = 0; i < 32; i++)
+ if ((1 << i) >= hdr->s_align)
+ break;
+ section->alignment_power = i;
+}
+
+#else /* ! I960 */
+
+#define coff_set_alignment_hook \
+ ((void (*) PARAMS ((bfd *, asection *, PTR))) bfd_void)
+
+#endif /* ! I960 */
+
+static boolean
+coff_mkobject (abfd)
+ bfd * abfd;
+{
+ coff_data_type *coff;
+
+ abfd->tdata.coff_obj_data = (struct coff_tdata *) bfd_zalloc (abfd, sizeof (coff_data_type));
+ if (abfd->tdata.coff_obj_data == 0)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ return false;
+ }
+ coff = coff_data (abfd);
+ coff->symbols = (coff_symbol_type *) NULL;
+ coff->conversion_table = (unsigned int *) NULL;
+ coff->raw_syments = (struct coff_ptr_struct *) NULL;
+ coff->raw_linenos = (struct lineno *) NULL;
+ coff->relocbase = 0;
+/* make_abs_section(abfd);*/
+ return true;
+}
+
+/* Create the COFF backend specific information. */
+
+static PTR
+coff_mkobject_hook (abfd, filehdr, aouthdr)
+ bfd * abfd;
+ PTR filehdr;
+ PTR aouthdr;
+{
+ struct internal_filehdr *internal_f = (struct internal_filehdr *) filehdr;
+ coff_data_type *coff;
+
+ if (coff_mkobject (abfd) == false)
+ return NULL;
+
+ coff = coff_data (abfd);
+
+ coff->sym_filepos = internal_f->f_symptr;
+ coff->flags = internal_f->f_flags;
+
+ /* These members communicate important constants about the symbol
+ table to GDB's symbol-reading code. These `constants'
+ unfortunately vary among coff implementations... */
+ coff->local_n_btmask = N_BTMASK;
+ coff->local_n_btshft = N_BTSHFT;
+ coff->local_n_tmask = N_TMASK;
+ coff->local_n_tshift = N_TSHIFT;
+ coff->local_symesz = SYMESZ;
+ coff->local_auxesz = AUXESZ;
+ coff->local_linesz = LINESZ;
+
+ return (PTR) coff;
+}
+
+/* Determine the machine architecture and type. FIXME: This is target
+ dependent because the magic numbers are defined in the target
+ dependent header files. But there is no particular need for this.
+ If the magic numbers were moved to a separate file, this function
+ would be target independent and would also be much more successful
+ at linking together COFF files for different architectures. */
+
+static boolean
+coff_set_arch_mach_hook (abfd, filehdr)
+ bfd *abfd;
+ PTR filehdr;
+{
+ long machine;
+ enum bfd_architecture arch;
+ struct internal_filehdr *internal_f = (struct internal_filehdr *) filehdr;
+
+ machine = 0;
+ switch (internal_f->f_magic)
+ {
+#ifdef I386MAGIC
+ case I386MAGIC:
+ case I386PTXMAGIC:
+ case I386AIXMAGIC: /* Danbury PS/2 AIX C Compiler */
+ case LYNXCOFFMAGIC: /* shadows the m68k Lynx number below, sigh */
+ arch = bfd_arch_i386;
+ machine = 0;
+ break;
+#endif
+
+#ifdef A29K_MAGIC_BIG
+ case A29K_MAGIC_BIG:
+ case A29K_MAGIC_LITTLE:
+ arch = bfd_arch_a29k;
+ machine = 0;
+ break;
+#endif
+
+#ifdef MC68MAGIC
+ case MC68MAGIC:
+ case M68MAGIC:
+#ifdef MC68KBCSMAGIC
+ case MC68KBCSMAGIC:
+#endif
+#ifdef APOLLOM68KMAGIC
+ case APOLLOM68KMAGIC:
+#endif
+#ifdef LYNXCOFFMAGIC
+ case LYNXCOFFMAGIC:
+#endif
+ arch = bfd_arch_m68k;
+ machine = 68020;
+ break;
+#endif
+#ifdef MC88MAGIC
+ case MC88MAGIC:
+ case MC88DMAGIC:
+ case MC88OMAGIC:
+ arch = bfd_arch_m88k;
+ machine = 88100;
+ break;
+#endif
+#ifdef Z8KMAGIC
+ case Z8KMAGIC:
+ arch = bfd_arch_z8k;
+ switch (internal_f->f_flags & F_MACHMASK)
+ {
+ case F_Z8001:
+ machine = bfd_mach_z8001;
+ break;
+ case F_Z8002:
+ machine = bfd_mach_z8002;
+ break;
+ default:
+ return false;
+ }
+ break;
+#endif
+#ifdef I960
+#ifdef I960ROMAGIC
+ case I960ROMAGIC:
+ case I960RWMAGIC:
+ arch = bfd_arch_i960;
+ switch (F_I960TYPE & internal_f->f_flags)
+ {
+ default:
+ case F_I960CORE:
+ machine = bfd_mach_i960_core;
+ break;
+ case F_I960KB:
+ machine = bfd_mach_i960_kb_sb;
+ break;
+ case F_I960MC:
+ machine = bfd_mach_i960_mc;
+ break;
+ case F_I960XA:
+ machine = bfd_mach_i960_xa;
+ break;
+ case F_I960CA:
+ machine = bfd_mach_i960_ca;
+ break;
+ case F_I960KA:
+ machine = bfd_mach_i960_ka_sa;
+ break;
+ }
+ break;
+#endif
+#endif
+
+#ifdef U802ROMAGIC
+ case U802ROMAGIC:
+ case U802WRMAGIC:
+ case U802TOCMAGIC:
+ arch = bfd_arch_rs6000;
+ machine = 6000;
+ break;
+#endif
+
+#ifdef WE32KMAGIC
+ case WE32KMAGIC:
+ arch = bfd_arch_we32k;
+ machine = 0;
+ break;
+#endif
+
+#ifdef H8300MAGIC
+ case H8300MAGIC:
+ arch = bfd_arch_h8300;
+ machine = bfd_mach_h8300;
+ /* !! FIXME this probably isn't the right place for this */
+ abfd->flags |= BFD_IS_RELAXABLE;
+ break;
+#endif
+
+#ifdef H8300HMAGIC
+ case H8300HMAGIC:
+ arch = bfd_arch_h8300;
+ machine = bfd_mach_h8300h;
+ /* !! FIXME this probably isn't the right place for this */
+ abfd->flags |= BFD_IS_RELAXABLE;
+ break;
+#endif
+
+#ifdef SH_ARCH_MAGIC
+ case SH_ARCH_MAGIC:
+ arch = bfd_arch_sh;
+ machine = 0;
+ break;
+#endif
+
+#ifdef H8500MAGIC
+ case H8500MAGIC:
+ arch = bfd_arch_h8500;
+ machine = 0;
+ break;
+#endif
+
+#ifdef SPARCMAGIC
+ case SPARCMAGIC:
+#ifdef LYNXCOFFMAGIC
+ case LYNXCOFFMAGIC:
+#endif
+ arch = bfd_arch_sparc;
+ machine = 0;
+ break;
+#endif
+
+ default: /* Unreadable input file type */
+ arch = bfd_arch_obscure;
+ break;
+ }
+
+ bfd_default_set_arch_mach (abfd, arch, machine);
+ return true;
+}
+
+#ifdef SYMNAME_IN_DEBUG
+
+static boolean
+symname_in_debug_hook (abfd, sym)
+ bfd * abfd;
+ struct internal_syment *sym;
+{
+ return SYMNAME_IN_DEBUG (sym) ? true : false;
+}
+
+#else
+
+#define symname_in_debug_hook \
+ (boolean (*) PARAMS ((bfd *, struct internal_syment *))) bfd_false
+
+#endif
+
+/*
+SUBSUBSECTION
+ Writing relocations
+
+ To write relocations, the back end steps though the
+ canonical relocation table and create an
+ @code{internal_reloc}. The symbol index to use is removed from
+ the @code{offset} field in the symbol table supplied. The
+ address comes directly from the sum of the section base
+ address and the relocation offset; the type is dug directly
+ from the howto field. Then the @code{internal_reloc} is
+ swapped into the shape of an @code{external_reloc} and written
+ out to disk.
+
+*/
+
+static boolean
+coff_write_relocs (abfd)
+ bfd * abfd;
+{
+ asection *s;
+ for (s = abfd->sections; s != (asection *) NULL; s = s->next)
+ {
+ unsigned int i;
+ struct external_reloc dst;
+
+ arelent **p = s->orelocation;
+ if (bfd_seek (abfd, s->rel_filepos, SEEK_SET) != 0)
+ return false;
+ for (i = 0; i < s->reloc_count; i++)
+ {
+ struct internal_reloc n;
+ arelent *q = p[i];
+ memset ((PTR) & n, 0, sizeof (n));
+
+ n.r_vaddr = q->address + s->vma;
+
+#ifdef R_IHCONST
+ /* The 29k const/consth reloc pair is a real kludge. The consth
+ part doesn't have a symbol; it has an offset. So rebuilt
+ that here. */
+ if (q->howto->type == R_IHCONST)
+ n.r_symndx = q->addend;
+ else
+#endif
+ if (q->sym_ptr_ptr)
+ {
+ if (q->sym_ptr_ptr == bfd_abs_section_ptr->symbol_ptr_ptr)
+ /* This is a relocation relative to the absolute symbol. */
+ n.r_symndx = -1;
+ else
+ {
+ n.r_symndx = get_index ((*(q->sym_ptr_ptr)));
+ /* Take notice if the symbol reloc points to a symbol
+ we don't have in our symbol table. What should we
+ do for this?? */
+ if (n.r_symndx > obj_conv_table_size (abfd))
+ abort ();
+ }
+ }
+
+#ifdef SWAP_OUT_RELOC_OFFSET
+ n.r_offset = q->addend;
+#endif
+
+#ifdef SELECT_RELOC
+ /* Work out reloc type from what is required */
+ SELECT_RELOC (n, q->howto);
+#else
+ n.r_type = q->howto->type;
+#endif
+ coff_swap_reloc_out (abfd, &n, &dst);
+ if (bfd_write ((PTR) & dst, 1, RELSZ, abfd) != RELSZ)
+ return false;
+ }
+ }
+
+ return true;
+}
+
+/* Set flags and magic number of a coff file from architecture and machine
+ type. Result is true if we can represent the arch&type, false if not. */
+
+static boolean
+coff_set_flags (abfd, magicp, flagsp)
+ bfd * abfd;
+ unsigned *magicp;
+ unsigned short *flagsp;
+{
+ switch (bfd_get_arch (abfd))
+ {
+#ifdef Z8KMAGIC
+ case bfd_arch_z8k:
+ *magicp = Z8KMAGIC;
+ switch (bfd_get_mach (abfd))
+ {
+ case bfd_mach_z8001:
+ *flagsp = F_Z8001;
+ break;
+ case bfd_mach_z8002:
+ *flagsp = F_Z8002;
+ break;
+ default:
+ return false;
+ }
+ return true;
+#endif
+#ifdef I960ROMAGIC
+
+ case bfd_arch_i960:
+
+ {
+ unsigned flags;
+ *magicp = I960ROMAGIC;
+ /*
+ ((bfd_get_file_flags(abfd) & WP_TEXT) ? I960ROMAGIC :
+ I960RWMAGIC); FIXME???
+ */
+ switch (bfd_get_mach (abfd))
+ {
+ case bfd_mach_i960_core:
+ flags = F_I960CORE;
+ break;
+ case bfd_mach_i960_kb_sb:
+ flags = F_I960KB;
+ break;
+ case bfd_mach_i960_mc:
+ flags = F_I960MC;
+ break;
+ case bfd_mach_i960_xa:
+ flags = F_I960XA;
+ break;
+ case bfd_mach_i960_ca:
+ flags = F_I960CA;
+ break;
+ case bfd_mach_i960_ka_sa:
+ flags = F_I960KA;
+ break;
+ default:
+ return false;
+ }
+ *flagsp = flags;
+ return true;
+ }
+ break;
+#endif
+#ifdef I386MAGIC
+ case bfd_arch_i386:
+ *magicp = I386MAGIC;
+#ifdef LYNXOS
+ /* Just overwrite the usual value if we're doing Lynx. */
+ *magicp = LYNXCOFFMAGIC;
+#endif
+ return true;
+ break;
+#endif
+#ifdef MC68MAGIC
+ case bfd_arch_m68k:
+#ifdef APOLLOM68KMAGIC
+ *magicp = APOLLO_COFF_VERSION_NUMBER;
+#else
+ *magicp = MC68MAGIC;
+#endif
+#ifdef LYNXOS
+ /* Just overwrite the usual value if we're doing Lynx. */
+ *magicp = LYNXCOFFMAGIC;
+#endif
+ return true;
+ break;
+#endif
+
+#ifdef MC88MAGIC
+ case bfd_arch_m88k:
+ *magicp = MC88OMAGIC;
+ return true;
+ break;
+#endif
+#ifdef H8300MAGIC
+ case bfd_arch_h8300:
+ switch (bfd_get_mach (abfd))
+ {
+ case bfd_mach_h8300:
+ *magicp = H8300MAGIC;
+ return true;
+ case bfd_mach_h8300h:
+ *magicp = H8300HMAGIC;
+ return true;
+ }
+ break;
+#endif
+
+#ifdef SH_ARCH_MAGIC
+ case bfd_arch_sh:
+ *magicp = SH_ARCH_MAGIC;
+ return true;
+ break;
+#endif
+
+#ifdef SPARCMAGIC
+ case bfd_arch_sparc:
+ *magicp = SPARCMAGIC;
+#ifdef LYNXOS
+ /* Just overwrite the usual value if we're doing Lynx. */
+ *magicp = LYNXCOFFMAGIC;
+#endif
+ return true;
+ break;
+#endif
+
+#ifdef H8500MAGIC
+ case bfd_arch_h8500:
+ *magicp = H8500MAGIC;
+ return true;
+ break;
+#endif
+#ifdef A29K_MAGIC_BIG
+ case bfd_arch_a29k:
+ if (abfd->xvec->byteorder_big_p)
+ *magicp = A29K_MAGIC_BIG;
+ else
+ *magicp = A29K_MAGIC_LITTLE;
+ return true;
+ break;
+#endif
+
+#ifdef WE32KMAGIC
+ case bfd_arch_we32k:
+ *magicp = WE32KMAGIC;
+ return true;
+ break;
+#endif
+
+#ifdef U802TOCMAGIC
+ case bfd_arch_rs6000:
+ case bfd_arch_powerpc:
+ *magicp = U802TOCMAGIC;
+ return true;
+ break;
+#endif
+
+ default: /* Unknown architecture */
+ /* return false; -- fall through to "return false" below, to avoid
+ "statement never reached" errors on the one below. */
+ break;
+ }
+
+ return false;
+}
+
+
+static boolean
+coff_set_arch_mach (abfd, arch, machine)
+ bfd * abfd;
+ enum bfd_architecture arch;
+ unsigned long machine;
+{
+ unsigned dummy1;
+ unsigned short dummy2;
+
+ if (! bfd_default_set_arch_mach (abfd, arch, machine))
+ return false;
+
+ if (arch != bfd_arch_unknown &&
+ coff_set_flags (abfd, &dummy1, &dummy2) != true)
+ return false; /* We can't represent this type */
+
+ return true; /* We're easy ... */
+}
+
+
+/* Calculate the file position for each section. */
+
+static void
+coff_compute_section_file_positions (abfd)
+ bfd * abfd;
+{
+ asection *current;
+ asection *previous = (asection *) NULL;
+ file_ptr sofar = FILHSZ;
+#ifndef I960
+ file_ptr old_sofar;
+#endif
+ if (bfd_get_start_address (abfd))
+ {
+ /* A start address may have been added to the original file. In this
+ case it will need an optional header to record it. */
+ abfd->flags |= EXEC_P;
+ }
+
+ if (abfd->flags & EXEC_P)
+ sofar += AOUTSZ;
+
+ sofar += abfd->section_count * SCNHSZ;
+ for (current = abfd->sections;
+ current != (asection *) NULL;
+ current = current->next)
+ {
+
+ /* Only deal with sections which have contents */
+ if (!(current->flags & SEC_HAS_CONTENTS))
+ continue;
+
+ /* Align the sections in the file to the same boundary on
+ which they are aligned in virtual memory. I960 doesn't
+ do this (FIXME) so we can stay in sync with Intel. 960
+ doesn't yet page from files... */
+#ifndef I960
+ {
+ /* make sure this section is aligned on the right boundary - by
+ padding the previous section up if necessary */
+
+ old_sofar = sofar;
+ sofar = BFD_ALIGN (sofar, 1 << current->alignment_power);
+ if (previous != (asection *) NULL)
+ {
+ previous->_raw_size += sofar - old_sofar;
+ }
+ }
+
+#endif
+
+#ifdef COFF_PAGE_SIZE
+ /* In demand paged files the low order bits of the file offset
+ must match the low order bits of the virtual address. */
+ if ((abfd->flags & D_PAGED) != 0)
+ sofar += (current->vma - sofar) % COFF_PAGE_SIZE;
+#endif
+
+ current->filepos = sofar;
+
+ sofar += current->_raw_size;
+#ifndef I960
+ /* make sure that this section is of the right size too */
+ old_sofar = sofar;
+ sofar = BFD_ALIGN (sofar, 1 << current->alignment_power);
+ current->_raw_size += sofar - old_sofar;
+#endif
+
+#ifdef _LIB
+ /* Force .lib sections to start at zero. The vma is then
+ incremented in coff_set_section_contents. This is right for
+ SVR3.2. */
+ if (strcmp (current->name, _LIB) == 0)
+ bfd_set_section_vma (abfd, current, 0);
+#endif
+
+ previous = current;
+ }
+ obj_relocbase (abfd) = sofar;
+}
+
+#ifndef RS6000COFF_C
+
+/* If .file, .text, .data, .bss symbols are missing, add them. */
+/* @@ Should we only be adding missing symbols, or overriding the aux
+ values for existing section symbols? */
+static boolean
+coff_add_missing_symbols (abfd)
+ bfd *abfd;
+{
+ unsigned int nsyms = bfd_get_symcount (abfd);
+ asymbol **sympp = abfd->outsymbols;
+ asymbol **sympp2;
+ unsigned int i;
+ int need_text = 1, need_data = 1, need_bss = 1, need_file = 1;
+
+ for (i = 0; i < nsyms; i++)
+ {
+ coff_symbol_type *csym = coff_symbol_from (abfd, sympp[i]);
+ CONST char *name;
+ if (csym)
+ {
+ /* only do this if there is a coff representation of the input
+ symbol */
+ if (csym->native && csym->native->u.syment.n_sclass == C_FILE)
+ {
+ need_file = 0;
+ continue;
+ }
+ name = csym->symbol.name;
+ if (!name)
+ continue;
+ if (!strcmp (name, _TEXT))
+ need_text = 0;
+#ifdef APOLLO_M68
+ else if (!strcmp (name, ".wtext"))
+ need_text = 0;
+#endif
+ else if (!strcmp (name, _DATA))
+ need_data = 0;
+ else if (!strcmp (name, _BSS))
+ need_bss = 0;
+ }
+ }
+ /* Now i == bfd_get_symcount (abfd). */
+ /* @@ For now, don't deal with .file symbol. */
+ need_file = 0;
+
+ if (!need_text && !need_data && !need_bss && !need_file)
+ return true;
+ nsyms += need_text + need_data + need_bss + need_file;
+ sympp2 = (asymbol **) bfd_alloc_by_size_t (abfd, nsyms * sizeof (asymbol *));
+ if (!sympp2)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ return false;
+ }
+ memcpy (sympp2, sympp, i * sizeof (asymbol *));
+ if (need_file)
+ {
+ /* @@ Generate fake .file symbol, in sympp2[i], and increment i. */
+ abort ();
+ }
+ if (need_text)
+ sympp2[i++] = coff_section_symbol (abfd, _TEXT);
+ if (need_data)
+ sympp2[i++] = coff_section_symbol (abfd, _DATA);
+ if (need_bss)
+ sympp2[i++] = coff_section_symbol (abfd, _BSS);
+ BFD_ASSERT (i == nsyms);
+ bfd_set_symtab (abfd, sympp2, nsyms);
+ return true;
+}
+
+#endif /* ! defined (RS6000COFF_C) */
+
+/* SUPPRESS 558 */
+/* SUPPRESS 529 */
+static boolean
+coff_write_object_contents (abfd)
+ bfd * abfd;
+{
+ asection *current;
+ unsigned int count;
+
+ boolean hasrelocs = false;
+ boolean haslinno = false;
+ file_ptr reloc_base;
+ file_ptr lineno_base;
+ file_ptr sym_base;
+ file_ptr scn_base;
+ file_ptr data_base;
+ unsigned long reloc_size = 0;
+ unsigned long lnno_size = 0;
+ asection *text_sec = NULL;
+ asection *data_sec = NULL;
+ asection *bss_sec = NULL;
+
+ struct internal_filehdr internal_f;
+ struct internal_aouthdr internal_a;
+
+
+ bfd_set_error (bfd_error_system_call);
+ /* Number the output sections, starting from one on the first section
+ with a name which doesn't start with a *.
+ @@ The code doesn't make this check. Is it supposed to be done,
+ or isn't it?? */
+ count = 1;
+ for (current = abfd->sections; current != (asection *) NULL;
+ current = current->next)
+ {
+ current->target_index = count;
+ count++;
+ }
+
+ if (abfd->output_has_begun == false)
+ {
+ coff_compute_section_file_positions (abfd);
+ }
+
+ if (abfd->sections != (asection *) NULL)
+ {
+ scn_base = abfd->sections->filepos;
+ }
+ else
+ {
+ scn_base = 0;
+ }
+ if (bfd_seek (abfd, scn_base, SEEK_SET) != 0)
+ return false;
+ reloc_base = obj_relocbase (abfd);
+
+ /* Make a pass through the symbol table to count line number entries and
+ put them into the correct asections */
+
+ lnno_size = coff_count_linenumbers (abfd) * LINESZ;
+ data_base = scn_base;
+
+ /* Work out the size of the reloc and linno areas */
+
+ for (current = abfd->sections; current != NULL; current =
+ current->next)
+ {
+ /* We give section headers to +ve indexes */
+ if (current->target_index > 0)
+ {
+
+ reloc_size += current->reloc_count * RELSZ;
+ data_base += SCNHSZ;
+ }
+
+ }
+
+ lineno_base = reloc_base + reloc_size;
+ sym_base = lineno_base + lnno_size;
+
+ /* Indicate in each section->line_filepos its actual file address */
+ for (current = abfd->sections; current != NULL; current =
+ current->next)
+ {
+ if (current->target_index > 0)
+ {
+
+ if (current->lineno_count)
+ {
+ current->line_filepos = lineno_base;
+ current->moving_line_filepos = lineno_base;
+ lineno_base += current->lineno_count * LINESZ;
+ }
+ else
+ {
+ current->line_filepos = 0;
+ }
+ if (current->reloc_count)
+ {
+ current->rel_filepos = reloc_base;
+ reloc_base += current->reloc_count * RELSZ;
+ }
+ else
+ {
+ current->rel_filepos = 0;
+ }
+ }
+ }
+
+
+
+ /* Write section headers to the file. */
+ internal_f.f_nscns = 0;
+ if (bfd_seek (abfd,
+ (file_ptr) ((abfd->flags & EXEC_P) ?
+ (FILHSZ + AOUTSZ) : FILHSZ),
+ SEEK_SET)
+ != 0)
+ return false;
+
+ {
+#if 0
+ unsigned int pad = abfd->flags & D_PAGED ? data_base : 0;
+#endif
+ unsigned int pad = 0;
+
+ for (current = abfd->sections;
+ current != NULL;
+ current = current->next)
+ {
+ struct internal_scnhdr section;
+ if (current->target_index > 0)
+ {
+ internal_f.f_nscns++;
+ strncpy (&(section.s_name[0]), current->name, 8);
+#ifdef _LIB
+ /* Always set s_vaddr of .lib to 0. This is right for SVR3.2
+ Ian Taylor <ian@cygnus.com>. */
+ if (strcmp (current->name, _LIB) == 0)
+ section.s_vaddr = 0;
+ else
+#endif
+ section.s_vaddr = current->lma + pad;
+ section.s_paddr = current->lma + pad;
+ section.s_size = current->_raw_size - pad;
+ /*
+ If this section has no size or is unloadable then the scnptr
+ will be 0 too
+ */
+ if (current->_raw_size - pad == 0 ||
+ (current->flags & (SEC_LOAD | SEC_HAS_CONTENTS)) == 0)
+ {
+ section.s_scnptr = 0;
+ }
+ else
+ {
+ section.s_scnptr = current->filepos;
+ }
+ section.s_relptr = current->rel_filepos;
+ section.s_lnnoptr = current->line_filepos;
+ section.s_nreloc = current->reloc_count;
+ section.s_nlnno = current->lineno_count;
+ if (current->reloc_count != 0)
+ hasrelocs = true;
+ if (current->lineno_count != 0)
+ haslinno = true;
+
+ section.s_flags = sec_to_styp_flags (current->name, current->flags);
+
+ if (!strcmp (current->name, _TEXT))
+ {
+ text_sec = current;
+ }
+ else if (!strcmp (current->name, _DATA))
+ {
+ data_sec = current;
+#ifdef TWO_DATA_SECS
+ }
+ else if (!strcmp (current->name, ".data2"))
+ {
+ data_sec = current;
+#endif /* TWO_DATA_SECS */
+ }
+ else if (!strcmp (current->name, _BSS))
+ {
+ bss_sec = current;
+ }
+
+#ifdef I960
+ section.s_align = (current->alignment_power
+ ? 1 << current->alignment_power
+ : 0);
+
+#endif
+ {
+ SCNHDR buff;
+
+ coff_swap_scnhdr_out (abfd, &section, &buff);
+ if (bfd_write ((PTR) (&buff), 1, SCNHSZ, abfd) != SCNHSZ)
+ return false;
+
+ }
+
+ pad = 0;
+ }
+ }
+ }
+
+
+ /* OK, now set up the filehdr... */
+
+ /* Don't include the internal abs section in the section count */
+
+ /*
+ We will NOT put a fucking timestamp in the header here. Every time you
+ put it back, I will come in and take it out again. I'm sorry. This
+ field does not belong here. We fill it with a 0 so it compares the
+ same but is not a reasonable time. -- gnu@cygnus.com
+ */
+ internal_f.f_timdat = 0;
+
+ if (bfd_get_symcount (abfd) != 0)
+ internal_f.f_symptr = sym_base;
+ else
+ internal_f.f_symptr = 0;
+
+ internal_f.f_flags = 0;
+
+ if (abfd->flags & EXEC_P)
+ internal_f.f_opthdr = AOUTSZ;
+ else
+ internal_f.f_opthdr = 0;
+
+ if (!hasrelocs)
+ internal_f.f_flags |= F_RELFLG;
+ if (!haslinno)
+ internal_f.f_flags |= F_LNNO;
+ if (0 == bfd_get_symcount (abfd))
+ internal_f.f_flags |= F_LSYMS;
+ if (abfd->flags & EXEC_P)
+ internal_f.f_flags |= F_EXEC;
+
+ if (!abfd->xvec->byteorder_big_p)
+ internal_f.f_flags |= F_AR32WR;
+ else
+ internal_f.f_flags |= F_AR32W;
+
+ /*
+ FIXME, should do something about the other byte orders and
+ architectures.
+ */
+
+ memset (&internal_a, 0, sizeof internal_a);
+
+ /* Set up architecture-dependent stuff */
+
+ {
+ unsigned int magic = 0;
+ unsigned short flags = 0;
+ coff_set_flags (abfd, &magic, &flags);
+ internal_f.f_magic = magic;
+ internal_f.f_flags |= flags;
+ /* ...and the "opt"hdr... */
+
+#ifdef A29K
+#ifdef ULTRA3 /* NYU's machine */
+ /* FIXME: This is a bogus check. I really want to see if there
+ * is a .shbss or a .shdata section, if so then set the magic
+ * number to indicate a shared data executable.
+ */
+ if (internal_f.f_nscns >= 7)
+ internal_a.magic = SHMAGIC; /* Shared magic */
+ else
+#endif /* ULTRA3 */
+ internal_a.magic = NMAGIC;/* Assume separate i/d */
+#define __A_MAGIC_SET__
+#endif /* A29K */
+#ifdef I960
+ internal_a.magic = (magic == I960ROMAGIC ? NMAGIC : OMAGIC);
+#define __A_MAGIC_SET__
+#endif /* I960 */
+#if M88
+#define __A_MAGIC_SET__
+ internal_a.magic = PAGEMAGICBCS;
+#endif /* M88 */
+
+#if APOLLO_M68
+#define __A_MAGIC_SET__
+ internal_a.magic = APOLLO_COFF_VERSION_NUMBER;
+#endif
+
+#if M68 || WE32K
+#define __A_MAGIC_SET__
+ /* Never was anything here for the 68k */
+#endif /* M68 || WE32K */
+
+#if I386
+#define __A_MAGIC_SET__
+ internal_a.magic = ZMAGIC;
+#endif /* I386 */
+
+#if RS6000COFF_C
+#define __A_MAGIC_SET__
+ internal_a.magic = (abfd->flags & D_PAGED) ? RS6K_AOUTHDR_ZMAGIC :
+ (abfd->flags & WP_TEXT) ? RS6K_AOUTHDR_NMAGIC :
+ RS6K_AOUTHDR_OMAGIC;
+#endif
+
+#ifndef __A_MAGIC_SET__
+#include "Your aouthdr magic number is not being set!"
+#else
+#undef __A_MAGIC_SET__
+#endif
+ }
+ /* Now should write relocs, strings, syms */
+ obj_sym_filepos (abfd) = sym_base;
+
+ if (bfd_get_symcount (abfd) != 0)
+ {
+#ifndef RS6000COFF_C
+ if (!coff_add_missing_symbols (abfd))
+ return false;
+#endif
+ if (!coff_renumber_symbols (abfd))
+ return false;
+ coff_mangle_symbols (abfd);
+ if (! coff_write_symbols (abfd))
+ return false;
+ if (! coff_write_linenumbers (abfd))
+ return false;
+ if (! coff_write_relocs (abfd))
+ return false;
+ }
+ if (text_sec)
+ {
+ internal_a.tsize = bfd_get_section_size_before_reloc (text_sec);
+ internal_a.text_start = internal_a.tsize ? text_sec->vma : 0;
+ }
+ if (data_sec)
+ {
+ internal_a.dsize = bfd_get_section_size_before_reloc (data_sec);
+ internal_a.data_start = internal_a.dsize ? data_sec->vma : 0;
+ }
+ if (bss_sec)
+ {
+ internal_a.bsize = bfd_get_section_size_before_reloc (bss_sec);
+ }
+
+ internal_a.entry = bfd_get_start_address (abfd);
+ internal_f.f_nsyms = bfd_get_symcount (abfd);
+
+ /* now write them */
+ if (bfd_seek (abfd, (file_ptr) 0, SEEK_SET) != 0)
+ return false;
+ {
+ FILHDR buff;
+ coff_swap_filehdr_out (abfd, (PTR) & internal_f, (PTR) & buff);
+ if (bfd_write ((PTR) & buff, 1, FILHSZ, abfd) != FILHSZ)
+ return false;
+ }
+ if (abfd->flags & EXEC_P)
+ {
+ AOUTHDR buff;
+ coff_swap_aouthdr_out (abfd, (PTR) & internal_a, (PTR) & buff);
+ if (bfd_write ((PTR) & buff, 1, AOUTSZ, abfd) != AOUTSZ)
+ return false;
+ }
+ return true;
+}
+
+static boolean
+coff_set_section_contents (abfd, section, location, offset, count)
+ bfd * abfd;
+ sec_ptr section;
+ PTR location;
+ file_ptr offset;
+ bfd_size_type count;
+{
+ if (abfd->output_has_begun == false) /* set by bfd.c handler */
+ coff_compute_section_file_positions (abfd);
+
+#ifdef _LIB
+ /* If this is a .lib section, bump the vma address so that it
+ winds up being the number of .lib sections output. This is
+ right for SVR3.2. Shared libraries should probably get more
+ generic support. Ian Taylor <ian@cygnus.com>. */
+ if (strcmp (section->name, _LIB) == 0)
+ ++section->lma;
+#endif
+
+ /* Don't write out bss sections - one way to do this is to
+ see if the filepos has not been set. */
+ if (section->filepos == 0)
+ return true;
+
+ if (bfd_seek (abfd, (file_ptr) (section->filepos + offset), SEEK_SET) != 0)
+ return false;
+
+ if (count != 0)
+ {
+ return (bfd_write (location, 1, count, abfd) == count) ? true : false;
+ }
+ return true;
+}
+#if 0
+static boolean
+coff_close_and_cleanup (abfd)
+ bfd *abfd;
+{
+ if (!bfd_read_p (abfd))
+ switch (abfd->format)
+ {
+ case bfd_archive:
+ if (!_bfd_write_archive_contents (abfd))
+ return false;
+ break;
+ case bfd_object:
+ if (!coff_write_object_contents (abfd))
+ return false;
+ break;
+ default:
+ bfd_set_error (bfd_error_invalid_operation);
+ return false;
+ }
+
+ /* We depend on bfd_close to free all the memory on the obstack. */
+ /* FIXME if bfd_release is not using obstacks! */
+ return true;
+}
+
+#endif
+
+static PTR
+buy_and_read (abfd, where, seek_direction, size)
+ bfd *abfd;
+ file_ptr where;
+ int seek_direction;
+ size_t size;
+{
+ PTR area = (PTR) bfd_alloc (abfd, size);
+ if (!area)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ return (NULL);
+ }
+ if (bfd_seek (abfd, where, seek_direction) != 0
+ || bfd_read (area, 1, size, abfd) != size)
+ return (NULL);
+ return (area);
+} /* buy_and_read() */
+
+/*
+SUBSUBSECTION
+ Reading linenumbers
+
+ Creating the linenumber table is done by reading in the entire
+ coff linenumber table, and creating another table for internal use.
+
+ A coff linenumber table is structured so that each function
+ is marked as having a line number of 0. Each line within the
+ function is an offset from the first line in the function. The
+ base of the line number information for the table is stored in
+ the symbol associated with the function.
+
+ The information is copied from the external to the internal
+ table, and each symbol which marks a function is marked by
+ pointing its...
+
+ How does this work ?
+
+*/
+
+static boolean
+coff_slurp_line_table (abfd, asect)
+ bfd *abfd;
+ asection *asect;
+{
+ LINENO *native_lineno;
+ alent *lineno_cache;
+
+ BFD_ASSERT (asect->lineno == (alent *) NULL);
+
+ native_lineno = (LINENO *) buy_and_read (abfd,
+ asect->line_filepos,
+ SEEK_SET,
+ (size_t) (LINESZ *
+ asect->lineno_count));
+ lineno_cache =
+ (alent *) bfd_alloc (abfd, (size_t) ((asect->lineno_count + 1) * sizeof (alent)));
+ if (lineno_cache == NULL)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ return false;
+ }
+ else
+ {
+ unsigned int counter = 0;
+ alent *cache_ptr = lineno_cache;
+ LINENO *src = native_lineno;
+
+ while (counter < asect->lineno_count)
+ {
+ struct internal_lineno dst;
+ coff_swap_lineno_in (abfd, src, &dst);
+ cache_ptr->line_number = dst.l_lnno;
+
+ if (cache_ptr->line_number == 0)
+ {
+ coff_symbol_type *sym =
+ (coff_symbol_type *) (dst.l_addr.l_symndx
+ + obj_raw_syments (abfd))->u.syment._n._n_n._n_zeroes;
+ cache_ptr->u.sym = (asymbol *) sym;
+ sym->lineno = cache_ptr;
+ }
+ else
+ {
+ cache_ptr->u.offset = dst.l_addr.l_paddr
+ - bfd_section_vma (abfd, asect);
+ } /* If no linenumber expect a symbol index */
+
+ cache_ptr++;
+ src++;
+ counter++;
+ }
+ cache_ptr->line_number = 0;
+
+ }
+ asect->lineno = lineno_cache;
+ /* FIXME, free native_lineno here, or use alloca or something. */
+ return true;
+}
+
+static boolean
+coff_slurp_symbol_table (abfd)
+ bfd * abfd;
+{
+ combined_entry_type *native_symbols;
+ coff_symbol_type *cached_area;
+ unsigned int *table_ptr;
+
+ unsigned int number_of_symbols = 0;
+ if (obj_symbols (abfd))
+ return true;
+ if (bfd_seek (abfd, obj_sym_filepos (abfd), SEEK_SET) != 0)
+ return false;
+
+ /* Read in the symbol table */
+ if ((native_symbols = coff_get_normalized_symtab (abfd)) == NULL)
+ {
+ return (false);
+ } /* on error */
+
+ /* Allocate enough room for all the symbols in cached form */
+ cached_area =
+ (coff_symbol_type *)
+ bfd_alloc (abfd, (size_t) (bfd_get_symcount (abfd) * sizeof (coff_symbol_type)));
+
+ if (cached_area == NULL)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ return false;
+ } /* on error */
+ table_ptr =
+ (unsigned int *)
+ bfd_alloc (abfd, (size_t) (bfd_get_symcount (abfd) * sizeof (unsigned int)));
+
+ if (table_ptr == NULL)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ return false;
+ }
+ else
+ {
+ coff_symbol_type *dst = cached_area;
+ unsigned int last_native_index = bfd_get_symcount (abfd);
+ unsigned int this_index = 0;
+ while (this_index < last_native_index)
+ {
+ combined_entry_type *src = native_symbols + this_index;
+ table_ptr[this_index] = number_of_symbols;
+ dst->symbol.the_bfd = abfd;
+
+ dst->symbol.name = (char *) (src->u.syment._n._n_n._n_offset);
+ /* We use the native name field to point to the cached field. */
+ src->u.syment._n._n_n._n_zeroes = (long) dst;
+ dst->symbol.section = coff_section_from_bfd_index (abfd,
+ src->u.syment.n_scnum);
+ dst->symbol.flags = 0;
+ dst->done_lineno = false;
+
+ switch (src->u.syment.n_sclass)
+ {
+#ifdef I960
+ case C_LEAFEXT:
+#if 0
+ dst->symbol.value = src->u.syment.n_value - dst->symbol.section->vma;
+ dst->symbol.flags = BSF_EXPORT | BSF_GLOBAL;
+ dst->symbol.flags |= BSF_NOT_AT_END;
+#endif
+ /* Fall through to next case */
+
+#endif
+
+ case C_EXT:
+#ifdef RS6000COFF_C
+ case C_HIDEXT:
+#endif
+ if ((src->u.syment.n_scnum) == 0)
+ {
+ if ((src->u.syment.n_value) == 0)
+ {
+ dst->symbol.section = bfd_und_section_ptr;
+ dst->symbol.value = 0;
+ }
+ else
+ {
+ dst->symbol.section = bfd_com_section_ptr;
+ dst->symbol.value = (src->u.syment.n_value);
+ }
+ }
+ else
+ {
+ /*
+ Base the value as an index from the base of the
+ section
+ */
+
+ dst->symbol.flags = BSF_EXPORT | BSF_GLOBAL;
+ dst->symbol.value = src->u.syment.n_value - dst->symbol.section->vma;
+
+ if (ISFCN ((src->u.syment.n_type)))
+ {
+ /*
+ A function ext does not go at the end of a file
+ */
+ dst->symbol.flags |= BSF_NOT_AT_END;
+ }
+ }
+
+#ifdef RS6000COFF_C
+ /* If this symbol has a csect aux of type LD, the scnlen field
+ is actually the index of the containing csect symbol. We
+ need to pointerize it. */
+ if (src->u.syment.n_numaux > 0)
+ {
+ combined_entry_type *aux;
+
+ aux = src + src->u.syment.n_numaux - 1;
+ if (SMTYP_SMTYP (aux->u.auxent.x_csect.x_smtyp) == XTY_LD)
+ {
+ aux->u.auxent.x_csect.x_scnlen.p =
+ native_symbols + aux->u.auxent.x_csect.x_scnlen.l;
+ aux->fix_scnlen = 1;
+ }
+ }
+#endif
+
+ break;
+
+ case C_STAT: /* static */
+#ifdef I960
+ case C_LEAFSTAT: /* static leaf procedure */
+#endif
+ case C_LABEL: /* label */
+ if (src->u.syment.n_scnum == -2)
+ dst->symbol.flags = BSF_DEBUGGING;
+ else
+ dst->symbol.flags = BSF_LOCAL;
+ /*
+ Base the value as an index from the base of the section, if
+ there is one
+ */
+ if (dst->symbol.section)
+ dst->symbol.value = (src->u.syment.n_value) -
+ dst->symbol.section->vma;
+ else
+ dst->symbol.value = (src->u.syment.n_value);
+ break;
+
+ case C_MOS: /* member of structure */
+ case C_EOS: /* end of structure */
+#ifdef NOTDEF /* C_AUTOARG has the same value */
+#ifdef C_GLBLREG
+ case C_GLBLREG: /* A29k-specific storage class */
+#endif
+#endif
+ case C_REGPARM: /* register parameter */
+ case C_REG: /* register variable */
+#ifdef C_AUTOARG
+ case C_AUTOARG: /* 960-specific storage class */
+#endif
+ case C_TPDEF: /* type definition */
+ case C_ARG:
+ case C_AUTO: /* automatic variable */
+ case C_FIELD: /* bit field */
+ case C_ENTAG: /* enumeration tag */
+ case C_MOE: /* member of enumeration */
+ case C_MOU: /* member of union */
+ case C_UNTAG: /* union tag */
+ dst->symbol.flags = BSF_DEBUGGING;
+ dst->symbol.value = (src->u.syment.n_value);
+ break;
+
+ case C_FILE: /* file name */
+ case C_STRTAG: /* structure tag */
+#ifdef RS6000COFF_C
+ case C_BINCL: /* beginning of include file */
+ case C_EINCL: /* ending of include file */
+ case C_GSYM:
+ case C_LSYM:
+ case C_PSYM:
+ case C_RSYM:
+ case C_RPSYM:
+ case C_STSYM:
+ case C_DECL:
+ case C_ENTRY:
+ case C_FUN:
+ case C_ESTAT:
+#endif
+ dst->symbol.flags = BSF_DEBUGGING;
+ dst->symbol.value = (src->u.syment.n_value);
+ break;
+
+#ifdef RS6000COFF_C
+ case C_BSTAT:
+ dst->symbol.flags = BSF_DEBUGGING;
+ dst->symbol.value = src->u.syment.n_value;
+
+ /* The value is actually a symbol index. Save a pointer to
+ the symbol instead of the index. FIXME: This should use a
+ union. */
+ src->u.syment.n_value =
+ (long) (native_symbols + src->u.syment.n_value);
+ src->fix_value = 1;
+ break;
+#endif
+
+ case C_BLOCK: /* ".bb" or ".eb" */
+ case C_FCN: /* ".bf" or ".ef" */
+ case C_EFCN: /* physical end of function */
+ dst->symbol.flags = BSF_LOCAL;
+ /*
+ Base the value as an index from the base of the section
+ */
+ dst->symbol.value = (src->u.syment.n_value) - dst->symbol.section->vma;
+ break;
+
+ case C_NULL:
+ case C_EXTDEF: /* external definition */
+ case C_ULABEL: /* undefined label */
+ case C_USTATIC: /* undefined static */
+ case C_LINE: /* line # reformatted as symbol table entry */
+ case C_ALIAS: /* duplicate tag */
+ case C_HIDDEN: /* ext symbol in dmert public lib */
+ default:
+
+ fprintf (stderr, "Unrecognized storage class %d (assuming debugging)\n for %s symbol `%s'\n",
+ src->u.syment.n_sclass, dst->symbol.section->name,
+ dst->symbol.name);
+/* abort();*/
+ dst->symbol.flags = BSF_DEBUGGING;
+ dst->symbol.value = (src->u.syment.n_value);
+ break;
+ }
+
+/* BFD_ASSERT(dst->symbol.flags != 0);*/
+
+ dst->native = src;
+
+ dst->symbol.udata = 0;
+ dst->lineno = (alent *) NULL;
+ this_index += (src->u.syment.n_numaux) + 1;
+ dst++;
+ number_of_symbols++;
+ } /* walk the native symtab */
+ } /* bfdize the native symtab */
+
+ obj_symbols (abfd) = cached_area;
+ obj_raw_syments (abfd) = native_symbols;
+
+ obj_conv_table_size (abfd) = bfd_get_symcount (abfd);
+ bfd_get_symcount (abfd) = number_of_symbols;
+ obj_convert (abfd) = table_ptr;
+ /* Slurp the line tables for each section too */
+ {
+ asection *p;
+ p = abfd->sections;
+ while (p)
+ {
+ coff_slurp_line_table (abfd, p);
+ p = p->next;
+ }
+ }
+ return true;
+} /* coff_slurp_symbol_table() */
+
+/*
+SUBSUBSECTION
+ Reading relocations
+
+ Coff relocations are easily transformed into the internal BFD form
+ (@code{arelent}).
+
+ Reading a coff relocation table is done in the following stages:
+
+ o Read the entire coff relocation table into memory.
+
+ o Process each relocation in turn; first swap it from the
+ external to the internal form.
+
+ o Turn the symbol referenced in the relocation's symbol index
+ into a pointer into the canonical symbol table.
+ This table is the same as the one returned by a call to
+ @code{bfd_canonicalize_symtab}. The back end will call that
+ routine and save the result if a canonicalization hasn't been done.
+
+ o The reloc index is turned into a pointer to a howto
+ structure, in a back end specific way. For instance, the 386
+ and 960 use the @code{r_type} to directly produce an index
+ into a howto table vector; the 88k subtracts a number from the
+ @code{r_type} field and creates an addend field.
+
+
+*/
+
+#ifndef CALC_ADDEND
+#define CALC_ADDEND(abfd, ptr, reloc, cache_ptr) \
+ { \
+ coff_symbol_type *coffsym = (coff_symbol_type *) NULL; \
+ if (ptr && bfd_asymbol_bfd (ptr) != abfd) \
+ coffsym = (obj_symbols (abfd) \
+ + (cache_ptr->sym_ptr_ptr - symbols)); \
+ else if (ptr) \
+ coffsym = coff_symbol_from (abfd, ptr); \
+ if (coffsym != (coff_symbol_type *) NULL \
+ && coffsym->native->u.syment.n_scnum == 0) \
+ cache_ptr->addend = 0; \
+ else if (ptr && bfd_asymbol_bfd (ptr) == abfd \
+ && ptr->section != (asection *) NULL) \
+ cache_ptr->addend = - (ptr->section->vma + ptr->value); \
+ else \
+ cache_ptr->addend = 0; \
+ }
+#endif
+
+static boolean
+coff_slurp_reloc_table (abfd, asect, symbols)
+ bfd * abfd;
+ sec_ptr asect;
+ asymbol ** symbols;
+{
+ RELOC *native_relocs;
+ arelent *reloc_cache;
+ arelent *cache_ptr;
+
+ unsigned int idx;
+
+ if (asect->relocation)
+ return true;
+ if (asect->reloc_count == 0)
+ return true;
+ if (asect->flags & SEC_CONSTRUCTOR)
+ return true;
+ if (!coff_slurp_symbol_table (abfd))
+ return false;
+ native_relocs =
+ (RELOC *) buy_and_read (abfd,
+ asect->rel_filepos,
+ SEEK_SET,
+ (size_t) (RELSZ *
+ asect->reloc_count));
+ reloc_cache = (arelent *)
+ bfd_alloc (abfd, (size_t) (asect->reloc_count * sizeof (arelent)));
+
+ if (reloc_cache == NULL)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ return false;
+ }
+
+
+ for (idx = 0; idx < asect->reloc_count; idx++)
+ {
+#ifdef RELOC_PROCESSING
+ struct internal_reloc dst;
+ struct external_reloc *src;
+
+ cache_ptr = reloc_cache + idx;
+ src = native_relocs + idx;
+ bfd_swap_reloc_in (abfd, src, &dst);
+
+ RELOC_PROCESSING (cache_ptr, &dst, symbols, abfd, asect);
+#else
+ struct internal_reloc dst;
+ asymbol *ptr;
+ struct external_reloc *src;
+
+ cache_ptr = reloc_cache + idx;
+ src = native_relocs + idx;
+
+ bfd_swap_reloc_in (abfd, src, &dst);
+
+
+ cache_ptr->address = dst.r_vaddr;
+
+ if (dst.r_symndx != -1)
+ {
+ /* @@ Should never be greater than count of symbols! */
+ if (dst.r_symndx >= obj_conv_table_size (abfd))
+ abort ();
+ cache_ptr->sym_ptr_ptr = symbols + obj_convert (abfd)[dst.r_symndx];
+ ptr = *(cache_ptr->sym_ptr_ptr);
+ }
+ else
+ {
+ cache_ptr->sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr;
+ ptr = 0;
+ }
+
+ /* The symbols definitions that we have read in have been
+ relocated as if their sections started at 0. But the offsets
+ refering to the symbols in the raw data have not been
+ modified, so we have to have a negative addend to compensate.
+
+ Note that symbols which used to be common must be left alone */
+
+ /* Calculate any reloc addend by looking at the symbol */
+ CALC_ADDEND (abfd, ptr, dst, cache_ptr);
+
+ cache_ptr->address -= asect->vma;
+/* !! cache_ptr->section = (asection *) NULL;*/
+
+ /* Fill in the cache_ptr->howto field from dst.r_type */
+ RTYPE2HOWTO (cache_ptr, &dst);
+#endif
+
+ }
+
+ asect->relocation = reloc_cache;
+ return true;
+}
+
+
+/* This is stupid. This function should be a boolean predicate. */
+static long
+coff_canonicalize_reloc (abfd, section, relptr, symbols)
+ bfd * abfd;
+ sec_ptr section;
+ arelent ** relptr;
+ asymbol ** symbols;
+{
+ arelent *tblptr = section->relocation;
+ unsigned int count = 0;
+
+
+ if (section->flags & SEC_CONSTRUCTOR)
+ {
+ /* this section has relocs made up by us, they are not in the
+ file, so take them out of their chain and place them into
+ the data area provided */
+ arelent_chain *chain = section->constructor_chain;
+ for (count = 0; count < section->reloc_count; count++)
+ {
+ *relptr++ = &chain->relent;
+ chain = chain->next;
+ }
+
+ }
+ else
+ {
+ if (! coff_slurp_reloc_table (abfd, section, symbols))
+ return -1;
+
+ tblptr = section->relocation;
+
+ for (; count++ < section->reloc_count;)
+ *relptr++ = tblptr++;
+
+
+ }
+ *relptr = 0;
+ return section->reloc_count;
+}
+
+#ifdef GNU960
+file_ptr
+coff_sym_filepos (abfd)
+ bfd *abfd;
+{
+ return obj_sym_filepos (abfd);
+}
+#endif
+
+#ifndef coff_reloc16_estimate
+#define coff_reloc16_estimate dummy_reloc16_estimate
+
+static int
+dummy_reloc16_estimate (abfd, input_section, reloc, shrink, link_info)
+ bfd *abfd;
+ asection *input_section;
+ arelent *reloc;
+ unsigned int shrink;
+ struct bfd_link_info *link_info;
+{
+ abort ();
+}
+
+#endif
+
+#ifndef coff_reloc16_extra_cases
+#define coff_reloc16_extra_cases dummy_reloc16_extra_cases
+/* This works even if abort is not declared in any header file. */
+static void
+dummy_reloc16_extra_cases (abfd, link_info, link_order, reloc, data, src_ptr,
+ dst_ptr)
+ bfd *abfd;
+ struct bfd_link_info *link_info;
+ struct bfd_link_order *link_order;
+ arelent *reloc;
+ bfd_byte *data;
+ unsigned int *src_ptr;
+ unsigned int *dst_ptr;
+{
+ fprintf (stderr, "%s\n", reloc->howto->name);
+ abort ();
+}
+#endif
+
+static CONST bfd_coff_backend_data bfd_coff_std_swap_table =
+{
+ coff_swap_aux_in, coff_swap_sym_in, coff_swap_lineno_in,
+ coff_swap_aux_out, coff_swap_sym_out,
+ coff_swap_lineno_out, coff_swap_reloc_out,
+ coff_swap_filehdr_out, coff_swap_aouthdr_out,
+ coff_swap_scnhdr_out,
+ FILHSZ, AOUTSZ, SCNHSZ, SYMESZ, AUXESZ, LINESZ,
+#ifdef COFF_LONG_FILENAMES
+ true,
+#else
+ false,
+#endif
+ coff_swap_filehdr_in, coff_swap_aouthdr_in, coff_swap_scnhdr_in,
+ coff_bad_format_hook, coff_set_arch_mach_hook, coff_mkobject_hook,
+ styp_to_sec_flags, coff_make_section_hook, coff_set_alignment_hook,
+ coff_slurp_symbol_table, symname_in_debug_hook,
+ coff_reloc16_extra_cases, coff_reloc16_estimate
+};
+
+#define coff_close_and_cleanup _bfd_generic_close_and_cleanup
+#define coff_bfd_free_cached_info _bfd_generic_bfd_free_cached_info
+#define coff_get_section_contents _bfd_generic_get_section_contents
+
+#define coff_bfd_copy_private_section_data \
+ _bfd_generic_bfd_copy_private_section_data
+#define coff_bfd_copy_private_bfd_data _bfd_generic_bfd_copy_private_bfd_data
+
+#ifndef coff_bfd_is_local_label
+#define coff_bfd_is_local_label bfd_generic_is_local_label
+#endif
+
+/* The reloc lookup routine must be supplied by each individual COFF
+ backend. */
+#ifndef coff_bfd_reloc_type_lookup
+#define coff_bfd_reloc_type_lookup _bfd_norelocs_bfd_reloc_type_lookup
+#endif
+
+#define coff_bfd_get_relocated_section_contents \
+ bfd_generic_get_relocated_section_contents
+#define coff_bfd_relax_section bfd_generic_relax_section
+#define coff_bfd_link_hash_table_create _bfd_generic_link_hash_table_create
+#define coff_bfd_link_add_symbols _bfd_generic_link_add_symbols
+#define coff_bfd_final_link _bfd_generic_final_link
diff --git a/gnu/usr.bin/gdb/bfd/coffgen.c b/gnu/usr.bin/gdb/bfd/coffgen.c
new file mode 100644
index 0000000..e81f45b
--- /dev/null
+++ b/gnu/usr.bin/gdb/bfd/coffgen.c
@@ -0,0 +1,1693 @@
+/* Support for the generic parts of COFF, for BFD.
+ Copyright 1990, 1991, 1992, 1993, 1994 Free Software Foundation, Inc.
+ Written by Cygnus Support.
+
+This file is part of BFD, the Binary File Descriptor library.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* Most of this hacked by Steve Chamberlain, sac@cygnus.com.
+ Split out of coffcode.h by Ian Taylor, ian@cygnus.com. */
+
+/* This file contains COFF code that is not dependent on any
+ particular COFF target. There is only one version of this file in
+ libbfd.a, so no target specific code may be put in here. Or, to
+ put it another way,
+
+ ********** DO NOT PUT TARGET SPECIFIC CODE IN THIS FILE **********
+
+ If you need to add some target specific behaviour, add a new hook
+ function to bfd_coff_backend_data.
+
+ Some of these functions are also called by the ECOFF routines.
+ Those functions may not use any COFF specific information, such as
+ coff_data (abfd). */
+
+#include "bfd.h"
+#include "sysdep.h"
+#include "libbfd.h"
+#include "coff/internal.h"
+#include "libcoff.h"
+
+static boolean coff_write_symbol PARAMS ((bfd *, asymbol *,
+ combined_entry_type *,
+ unsigned int *));
+static boolean coff_write_alien_symbol PARAMS ((bfd *, asymbol *,
+ unsigned int *));
+static boolean coff_write_native_symbol PARAMS ((bfd *, coff_symbol_type *,
+ unsigned int *));
+
+static asection bfd_debug_section = { "*DEBUG*" };
+
+/* Take a section header read from a coff file (in HOST byte order),
+ and make a BFD "section" out of it. This is used by ECOFF. */
+static boolean
+make_a_section_from_file (abfd, hdr, target_index)
+ bfd *abfd;
+ struct internal_scnhdr *hdr;
+ unsigned int target_index;
+{
+ asection *return_section;
+ char *name;
+
+ /* Assorted wastage to null-terminate the name, thanks AT&T! */
+ name = bfd_alloc(abfd, sizeof (hdr->s_name)+1);
+ if (name == NULL) {
+ bfd_set_error (bfd_error_no_memory);
+ return false;
+ }
+ strncpy(name, (char *) &hdr->s_name[0], sizeof (hdr->s_name));
+ name[sizeof (hdr->s_name)] = 0;
+
+ return_section = bfd_make_section(abfd, name);
+ if (return_section == NULL)
+ return_section = bfd_coff_make_section_hook (abfd, name);
+
+ /* Handle several sections of the same name. For example, if an executable
+ has two .bss sections, GDB better be able to find both of them
+ (PR 3562). */
+ if (return_section == NULL)
+ return_section = bfd_make_section_anyway (abfd, name);
+
+ if (return_section == NULL)
+ return false;
+
+ /* s_paddr is presumed to be = to s_vaddr */
+
+ return_section->vma = hdr->s_vaddr;
+ return_section->_raw_size = hdr->s_size;
+ return_section->filepos = hdr->s_scnptr;
+ return_section->rel_filepos = hdr->s_relptr;
+ return_section->reloc_count = hdr->s_nreloc;
+
+ bfd_coff_set_alignment_hook (abfd, return_section, hdr);
+
+ return_section->line_filepos = hdr->s_lnnoptr;
+
+ return_section->lineno_count = hdr->s_nlnno;
+ return_section->userdata = NULL;
+ return_section->next = (asection *) NULL;
+ return_section->flags = bfd_coff_styp_to_sec_flags_hook (abfd, hdr);
+
+ return_section->target_index = target_index;
+
+ /* At least on i386-coff, the line number count for a shared library
+ section must be ignored. */
+ if ((return_section->flags & SEC_COFF_SHARED_LIBRARY) != 0)
+ return_section->lineno_count = 0;
+
+ if (hdr->s_nreloc != 0)
+ return_section->flags |= SEC_RELOC;
+ /* FIXME: should this check 'hdr->s_size > 0' */
+ if (hdr->s_scnptr != 0)
+ return_section->flags |= SEC_HAS_CONTENTS;
+ return true;
+}
+
+/* Read in a COFF object and make it into a BFD. This is used by
+ ECOFF as well. */
+
+static const bfd_target *
+coff_real_object_p (abfd, nscns, internal_f, internal_a)
+ bfd *abfd;
+ unsigned nscns;
+ struct internal_filehdr *internal_f;
+ struct internal_aouthdr *internal_a;
+{
+ PTR tdata;
+ size_t readsize; /* length of file_info */
+ unsigned int scnhsz;
+ char *external_sections;
+
+ /* Build a play area */
+ tdata = bfd_coff_mkobject_hook (abfd, (PTR) internal_f, (PTR) internal_a);
+ if (tdata == NULL)
+ return 0;
+
+ scnhsz = bfd_coff_scnhsz (abfd);
+ readsize = nscns * scnhsz;
+ external_sections = (char *)bfd_alloc(abfd, readsize);
+ if (!external_sections)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ goto fail;
+ }
+
+ if (bfd_read((PTR)external_sections, 1, readsize, abfd) != readsize) {
+ goto fail;
+ }
+
+ /* Now copy data as required; construct all asections etc */
+ if (nscns != 0) {
+ unsigned int i;
+ for (i = 0; i < nscns; i++) {
+ struct internal_scnhdr tmp;
+ bfd_coff_swap_scnhdr_in(abfd, (PTR) (external_sections + i * scnhsz),
+ (PTR) &tmp);
+ make_a_section_from_file(abfd,&tmp, i+1);
+ }
+ }
+
+/* make_abs_section(abfd);*/
+
+ if (bfd_coff_set_arch_mach_hook (abfd, (PTR) internal_f) == false)
+ goto fail;
+
+ if (!(internal_f->f_flags & F_RELFLG))
+ abfd->flags |= HAS_RELOC;
+ if ((internal_f->f_flags & F_EXEC))
+ abfd->flags |= EXEC_P;
+ if (!(internal_f->f_flags & F_LNNO))
+ abfd->flags |= HAS_LINENO;
+ if (!(internal_f->f_flags & F_LSYMS))
+ abfd->flags |= HAS_LOCALS;
+
+ /* FIXME: How can we set D_PAGED correctly? */
+ if ((internal_f->f_flags & F_EXEC) != 0)
+ abfd->flags |= D_PAGED;
+
+ bfd_get_symcount(abfd) = internal_f->f_nsyms;
+ if (internal_f->f_nsyms)
+ abfd->flags |= HAS_SYMS;
+
+ if (internal_a != (struct internal_aouthdr *) NULL)
+ bfd_get_start_address (abfd) = internal_a->entry;
+ else
+ bfd_get_start_address (abfd) = 0;
+
+ return abfd->xvec;
+ fail:
+ bfd_release(abfd, tdata);
+ return (const bfd_target *)NULL;
+}
+
+/* Turn a COFF file into a BFD, but fail with bfd_error_wrong_format if it is
+ not a COFF file. This is also used by ECOFF. */
+
+const bfd_target *
+coff_object_p (abfd)
+ bfd *abfd;
+{
+ unsigned int filhsz;
+ unsigned int aoutsz;
+ int nscns;
+ PTR filehdr;
+ struct internal_filehdr internal_f;
+ struct internal_aouthdr internal_a;
+
+ /* figure out how much to read */
+ filhsz = bfd_coff_filhsz (abfd);
+ aoutsz = bfd_coff_aoutsz (abfd);
+
+ filehdr = bfd_alloc (abfd, filhsz);
+ if (filehdr == NULL)
+ return 0;
+ if (bfd_read(filehdr, 1, filhsz, abfd) != filhsz)
+ {
+ if (bfd_get_error () != bfd_error_system_call)
+ bfd_set_error (bfd_error_wrong_format);
+ return 0;
+ }
+ bfd_coff_swap_filehdr_in(abfd, filehdr, &internal_f);
+ bfd_release (abfd, filehdr);
+
+ if (bfd_coff_bad_format_hook (abfd, &internal_f) == false) {
+ bfd_set_error (bfd_error_wrong_format);
+ return 0;
+ }
+ nscns =internal_f.f_nscns;
+
+ if (internal_f.f_opthdr) {
+ PTR opthdr;
+
+ opthdr = bfd_alloc (abfd, aoutsz);
+ if (opthdr == NULL)
+ return 0;;
+ if (bfd_read(opthdr, 1,aoutsz, abfd) != aoutsz) {
+ return 0;
+ }
+ bfd_coff_swap_aouthdr_in(abfd, opthdr, (PTR)&internal_a);
+ }
+
+ /* Seek past the opt hdr stuff */
+ if (bfd_seek(abfd, (file_ptr) (internal_f.f_opthdr + filhsz), SEEK_SET)
+ != 0)
+ return NULL;
+
+ return coff_real_object_p(abfd, nscns, &internal_f,
+ (internal_f.f_opthdr != 0
+ ? &internal_a
+ : (struct internal_aouthdr *) NULL));
+}
+
+/* Get the BFD section from a COFF symbol section number. */
+
+asection *
+coff_section_from_bfd_index (abfd, index)
+ bfd *abfd;
+ int index;
+{
+ struct sec *answer = abfd->sections;
+
+ if (index == N_ABS)
+ {
+ return bfd_abs_section_ptr;
+ }
+ if (index == N_UNDEF)
+ {
+ return bfd_und_section_ptr;
+ }
+ if(index == N_DEBUG)
+ {
+ return &bfd_debug_section;
+
+ }
+
+ while (answer) {
+ if (answer->target_index == index)
+ return answer;
+ answer = answer->next;
+ }
+
+ /* We should not reach this point, but the SCO 3.2v4 /lib/libc_s.a
+ has a bad symbol table in biglitpow.o. */
+ return bfd_und_section_ptr;
+}
+
+/* Get the upper bound of a COFF symbol table. */
+
+long
+coff_get_symtab_upper_bound(abfd)
+bfd *abfd;
+{
+ if (!bfd_coff_slurp_symbol_table(abfd))
+ return -1;
+
+ return (bfd_get_symcount(abfd) + 1) * (sizeof(coff_symbol_type *));
+}
+
+
+/* Canonicalize a COFF symbol table. */
+
+long
+coff_get_symtab (abfd, alocation)
+ bfd *abfd;
+ asymbol **alocation;
+{
+ unsigned int counter = 0;
+ coff_symbol_type *symbase;
+ coff_symbol_type **location = (coff_symbol_type **) (alocation);
+ if (!bfd_coff_slurp_symbol_table(abfd))
+ return -1;
+
+ symbase = obj_symbols(abfd);
+ while (counter < bfd_get_symcount(abfd))
+ {
+ /* This nasty code looks at the symbol to decide whether or
+ not it is descibes a constructor/destructor entry point. It
+ is structured this way to (hopefully) speed non matches */
+#if 0
+ if (0 && symbase->symbol.name[9] == '$')
+ {
+ bfd_constructor_entry(abfd,
+ (asymbol **)location,
+ symbase->symbol.name[10] == 'I' ?
+ "CTOR" : "DTOR");
+ }
+#endif
+ *(location++) = symbase++;
+ counter++;
+ }
+ *location++ = 0;
+ return bfd_get_symcount(abfd);
+}
+
+/* Set lineno_count for the output sections of a COFF file. */
+
+int
+coff_count_linenumbers (abfd)
+ bfd *abfd;
+{
+ unsigned int limit = bfd_get_symcount(abfd);
+ unsigned int i;
+ int total = 0;
+ asymbol **p;
+ {
+ asection *s = abfd->sections->output_section;
+ while (s) {
+ BFD_ASSERT(s->lineno_count == 0);
+ s = s->next;
+ }
+ }
+
+
+ for (p = abfd->outsymbols, i = 0; i < limit; i++, p++) {
+ asymbol *q_maybe = *p;
+ if (bfd_asymbol_flavour(q_maybe) == bfd_target_coff_flavour) {
+ coff_symbol_type *q = coffsymbol(q_maybe);
+ if (q->lineno) {
+ /*
+ This symbol has a linenumber, increment the owning
+ section's linenumber count
+ */
+ alent *l = q->lineno;
+ q->symbol.section->output_section->lineno_count++;
+ total ++;
+ l++;
+ while (l->line_number) {
+ total ++;
+ q->symbol.section->output_section->lineno_count++;
+ l++;
+ }
+ }
+ }
+ }
+ return total;
+}
+
+/* Takes a bfd and a symbol, returns a pointer to the coff specific
+ area of the symbol if there is one. */
+
+/*ARGSUSED*/
+coff_symbol_type *
+coff_symbol_from (ignore_abfd, symbol)
+ bfd *ignore_abfd;
+ asymbol *symbol;
+{
+ if (bfd_asymbol_flavour(symbol) != bfd_target_coff_flavour)
+ return (coff_symbol_type *)NULL;
+
+ if (bfd_asymbol_bfd(symbol)->tdata.coff_obj_data == (coff_data_type*)NULL)
+ return (coff_symbol_type *)NULL;
+
+ return (coff_symbol_type *) symbol;
+}
+
+static void
+fixup_symbol_value (coff_symbol_ptr, syment)
+ coff_symbol_type *coff_symbol_ptr;
+ struct internal_syment *syment;
+{
+
+ /* Normalize the symbol flags */
+ if (bfd_is_com_section (coff_symbol_ptr->symbol.section)) {
+ /* a common symbol is undefined with a value */
+ syment->n_scnum = N_UNDEF;
+ syment->n_value = coff_symbol_ptr->symbol.value;
+ }
+ else if (coff_symbol_ptr->symbol.flags & BSF_DEBUGGING) {
+ syment->n_value = coff_symbol_ptr->symbol.value;
+ }
+ else if (bfd_is_und_section (coff_symbol_ptr->symbol.section)) {
+ syment->n_scnum = N_UNDEF;
+ syment->n_value = 0;
+ }
+ else {
+ if (coff_symbol_ptr->symbol.section) {
+ syment->n_scnum =
+ coff_symbol_ptr->symbol.section->output_section->target_index;
+
+ syment->n_value =
+ coff_symbol_ptr->symbol.value +
+ coff_symbol_ptr->symbol.section->output_offset +
+ coff_symbol_ptr->symbol.section->output_section->vma;
+ }
+ else {
+ BFD_ASSERT(0);
+ /* This can happen, but I don't know why yet (steve@cygnus.com) */
+ syment->n_scnum = N_ABS;
+ syment->n_value = coff_symbol_ptr->symbol.value;
+ }
+ }
+}
+
+/* run through all the symbols in the symbol table and work out what
+ their indexes into the symbol table will be when output
+
+ Coff requires that each C_FILE symbol points to the next one in the
+ chain, and that the last one points to the first external symbol. We
+ do that here too.
+
+*/
+boolean
+coff_renumber_symbols (bfd_ptr)
+ bfd *bfd_ptr;
+{
+ unsigned int symbol_count = bfd_get_symcount(bfd_ptr);
+ asymbol **symbol_ptr_ptr = bfd_ptr->outsymbols;
+ unsigned int native_index = 0;
+ struct internal_syment *last_file = (struct internal_syment *)NULL;
+ unsigned int symbol_index;
+
+ /* COFF demands that undefined symbols come after all other symbols.
+ Since we don't need to impose this extra knowledge on all our client
+ programs, deal with that here. Sort the symbol table; just move the
+ undefined symbols to the end, leaving the rest alone. */
+ /* @@ Do we have some condition we could test for, so we don't always
+ have to do this? I don't think relocatability is quite right, but
+ I'm not certain. [raeburn:19920508.1711EST] */
+ {
+ asymbol **newsyms;
+ int i;
+
+ newsyms = (asymbol **) bfd_alloc_by_size_t (bfd_ptr,
+ sizeof (asymbol *)
+ * (symbol_count + 1));
+ if (!newsyms)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ return false;
+ }
+ bfd_ptr->outsymbols = newsyms;
+ for (i = 0; i < symbol_count; i++)
+ if (! bfd_is_und_section (symbol_ptr_ptr[i]->section))
+ *newsyms++ = symbol_ptr_ptr[i];
+ for (i = 0; i < symbol_count; i++)
+ if (bfd_is_und_section (symbol_ptr_ptr[i]->section))
+ *newsyms++ = symbol_ptr_ptr[i];
+ *newsyms = (asymbol *) NULL;
+ symbol_ptr_ptr = bfd_ptr->outsymbols;
+ }
+
+ for (symbol_index = 0; symbol_index < symbol_count; symbol_index++)
+ {
+ coff_symbol_type *coff_symbol_ptr = coff_symbol_from(bfd_ptr, symbol_ptr_ptr[symbol_index]);
+ if (coff_symbol_ptr && coff_symbol_ptr->native) {
+ combined_entry_type *s = coff_symbol_ptr->native;
+ int i;
+
+ if (s->u.syment.n_sclass == C_FILE)
+ {
+ if (last_file != (struct internal_syment *)NULL) {
+ last_file->n_value = native_index;
+ }
+ last_file = &(s->u.syment);
+ }
+ else {
+
+ /* Modify the symbol values according to their section and
+ type */
+
+ fixup_symbol_value(coff_symbol_ptr, &(s->u.syment));
+ }
+ for (i = 0; i < s->u.syment.n_numaux + 1; i++) {
+ s[i].offset = native_index ++;
+ }
+ }
+ else {
+ native_index++;
+ }
+ }
+ obj_conv_table_size (bfd_ptr) = native_index;
+ return true;
+}
+
+/*
+ Run thorough the symbol table again, and fix it so that all pointers to
+ entries are changed to the entries' index in the output symbol table.
+
+*/
+void
+coff_mangle_symbols (bfd_ptr)
+ bfd *bfd_ptr;
+{
+ unsigned int symbol_count = bfd_get_symcount (bfd_ptr);
+ asymbol **symbol_ptr_ptr = bfd_ptr->outsymbols;
+ unsigned int symbol_index;
+
+ for (symbol_index = 0; symbol_index < symbol_count; symbol_index++)
+ {
+ coff_symbol_type *coff_symbol_ptr =
+ coff_symbol_from (bfd_ptr, symbol_ptr_ptr[symbol_index]);
+
+ if (coff_symbol_ptr && coff_symbol_ptr->native)
+ {
+ int i;
+ combined_entry_type *s = coff_symbol_ptr->native;
+
+ if (s->fix_value)
+ {
+ /* FIXME: We should use a union here. */
+ s->u.syment.n_value =
+ ((combined_entry_type *) s->u.syment.n_value)->offset;
+ s->fix_value = 0;
+ }
+ for (i = 0; i < s->u.syment.n_numaux ; i++)
+ {
+ combined_entry_type *a = s + i + 1;
+ if (a->fix_tag)
+ {
+ a->u.auxent.x_sym.x_tagndx.l =
+ a->u.auxent.x_sym.x_tagndx.p->offset;
+ a->fix_tag = 0;
+ }
+ if (a->fix_end)
+ {
+ a->u.auxent.x_sym.x_fcnary.x_fcn.x_endndx.l =
+ a->u.auxent.x_sym.x_fcnary.x_fcn.x_endndx.p->offset;
+ a->fix_end = 0;
+ }
+ if (a->fix_scnlen)
+ {
+ a->u.auxent.x_csect.x_scnlen.l =
+ a->u.auxent.x_csect.x_scnlen.p->offset;
+ a->fix_scnlen = 0;
+ }
+ }
+ }
+ }
+}
+
+static bfd_size_type string_size;
+static bfd_size_type debug_string_size;
+static asection *debug_string_section;
+
+static void
+coff_fix_symbol_name (abfd, symbol, native)
+ bfd *abfd;
+ asymbol *symbol;
+ combined_entry_type *native;
+{
+ unsigned int name_length;
+ union internal_auxent *auxent;
+ char * name = ( char *)(symbol->name);
+
+ if (name == (char *) NULL) {
+ /* coff symbols always have names, so we'll make one up */
+ symbol->name = "strange";
+ name = (char *)symbol->name;
+ }
+ name_length = strlen(name);
+
+ if (native->u.syment.n_sclass == C_FILE) {
+ strncpy(native->u.syment._n._n_name, ".file", SYMNMLEN);
+ auxent = &(native+1)->u.auxent;
+
+ if (bfd_coff_long_filenames (abfd)) {
+ if (name_length <= FILNMLEN) {
+ strncpy(auxent->x_file.x_fname, name, FILNMLEN);
+ }
+ else {
+ auxent->x_file.x_n.x_offset = string_size + 4;
+ auxent->x_file.x_n.x_zeroes = 0;
+ string_size += name_length + 1;
+ }
+ }
+ else {
+ strncpy(auxent->x_file.x_fname, name, FILNMLEN);
+ if (name_length > FILNMLEN) {
+ name[FILNMLEN] = '\0';
+ }
+ }
+ }
+ else
+ { /* NOT A C_FILE SYMBOL */
+ if (name_length <= SYMNMLEN)
+ {
+ /* This name will fit into the symbol neatly */
+ strncpy(native->u.syment._n._n_name, symbol->name, SYMNMLEN);
+ }
+ else if (! bfd_coff_symname_in_debug (abfd, &native->u.syment))
+ {
+ native->u.syment._n._n_n._n_offset = string_size + 4;
+ native->u.syment._n._n_n._n_zeroes = 0;
+ string_size += name_length + 1;
+ }
+ else
+ {
+ long filepos;
+ bfd_byte buf[2];
+
+ /* This name should be written into the .debug section. For
+ some reason each name is preceded by a two byte length
+ and also followed by a null byte. FIXME: We assume that
+ the .debug section has already been created, and that it
+ is large enough. */
+ if (debug_string_section == (asection *) NULL)
+ debug_string_section = bfd_get_section_by_name (abfd, ".debug");
+ filepos = bfd_tell (abfd);
+ bfd_put_16 (abfd, name_length + 1, buf);
+ if (! bfd_set_section_contents (abfd,
+ debug_string_section,
+ (PTR) buf,
+ (file_ptr) debug_string_size,
+ (bfd_size_type) 2)
+ || ! bfd_set_section_contents (abfd,
+ debug_string_section,
+ (PTR) symbol->name,
+ (file_ptr) debug_string_size + 2,
+ (bfd_size_type) name_length + 1))
+ abort ();
+ if (bfd_seek (abfd, filepos, SEEK_SET) != 0)
+ abort ();
+ native->u.syment._n._n_n._n_offset = debug_string_size + 2;
+ native->u.syment._n._n_n._n_zeroes = 0;
+ debug_string_size += name_length + 3;
+ }
+ }
+}
+
+/* We need to keep track of the symbol index so that when we write out
+ the relocs we can get the index for a symbol. This method is a
+ hack. FIXME. */
+
+#define set_index(symbol, idx) ((symbol)->udata = (PTR) (idx))
+
+/* Write a symbol out to a COFF file. */
+
+static boolean
+coff_write_symbol (abfd, symbol, native, written)
+ bfd *abfd;
+ asymbol *symbol;
+ combined_entry_type *native;
+ unsigned int *written;
+{
+ unsigned int numaux = native->u.syment.n_numaux;
+ int type = native->u.syment.n_type;
+ int class = native->u.syment.n_sclass;
+ PTR buf;
+ bfd_size_type symesz;
+
+ /* @@ bfd_debug_section isn't accessible outside this file, but we
+ know that C_FILE symbols belong there. So move them. */
+ if (native->u.syment.n_sclass == C_FILE)
+ symbol->section = &bfd_debug_section;
+
+ if (bfd_is_abs_section (symbol->section))
+ {
+ native->u.syment.n_scnum = N_ABS;
+ }
+ else if (symbol->section == &bfd_debug_section)
+ {
+ native->u.syment.n_scnum = N_DEBUG;
+ }
+ else if (bfd_is_und_section (symbol->section))
+ {
+ native->u.syment.n_scnum = N_UNDEF;
+ }
+ else
+ {
+ native->u.syment.n_scnum =
+ symbol->section->output_section->target_index;
+ }
+
+ coff_fix_symbol_name (abfd, symbol, native);
+
+ symesz = bfd_coff_symesz (abfd);
+ buf = bfd_alloc (abfd, symesz);
+ if (!buf)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ return false;
+ }
+ bfd_coff_swap_sym_out (abfd, &native->u.syment, buf);
+ if (bfd_write (buf, 1, symesz, abfd) != symesz)
+ return false;
+ bfd_release (abfd, buf);
+
+ if (native->u.syment.n_numaux > 0)
+ {
+ bfd_size_type auxesz;
+ unsigned int j;
+
+ auxesz = bfd_coff_auxesz (abfd);
+ buf = bfd_alloc (abfd, auxesz);
+ if (!buf)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ return false;
+ }
+ for (j = 0; j < native->u.syment.n_numaux; j++)
+ {
+ bfd_coff_swap_aux_out (abfd,
+ &((native + j + 1)->u.auxent),
+ type,
+ class,
+ j,
+ native->u.syment.n_numaux,
+ buf);
+ if (bfd_write (buf, 1, auxesz, abfd)!= auxesz)
+ return false;
+ }
+ bfd_release (abfd, buf);
+ }
+
+ /* Store the index for use when we write out the relocs. */
+ set_index (symbol, *written);
+
+ *written += numaux + 1;
+ return true;
+}
+
+/* Write out a symbol to a COFF file that does not come from a COFF
+ file originally. This symbol may have been created by the linker,
+ or we may be linking a non COFF file to a COFF file. */
+
+static boolean
+coff_write_alien_symbol (abfd, symbol, written)
+ bfd *abfd;
+ asymbol *symbol;
+ unsigned int *written;
+{
+ combined_entry_type *native;
+ combined_entry_type dummy;
+
+ native = &dummy;
+ native->u.syment.n_type = T_NULL;
+ native->u.syment.n_flags = 0;
+ if (bfd_is_und_section (symbol->section))
+ {
+ native->u.syment.n_scnum = N_UNDEF;
+ native->u.syment.n_value = symbol->value;
+ }
+ else if (bfd_is_com_section (symbol->section))
+ {
+ native->u.syment.n_scnum = N_UNDEF;
+ native->u.syment.n_value = symbol->value;
+ }
+ else if (symbol->flags & BSF_DEBUGGING)
+ {
+ /* Remove the symbol name so that it does not take up any space.
+ COFF won't know what to do with it anyhow. */
+ symbol->name = "";
+ }
+ else
+ {
+ native->u.syment.n_scnum =
+ symbol->section->output_section->target_index;
+ native->u.syment.n_value = (symbol->value
+ + symbol->section->output_section->vma
+ + symbol->section->output_offset);
+
+ /* Copy the any flags from the the file header into the symbol.
+ FIXME: Why? */
+ {
+ coff_symbol_type *c = coff_symbol_from (abfd, symbol);
+ if (c != (coff_symbol_type *) NULL)
+ native->u.syment.n_flags = bfd_asymbol_bfd (&c->symbol)->flags;
+ }
+ }
+
+ native->u.syment.n_type = 0;
+ if (symbol->flags & BSF_LOCAL)
+ native->u.syment.n_sclass = C_STAT;
+ else
+ native->u.syment.n_sclass = C_EXT;
+ native->u.syment.n_numaux = 0;
+
+ return coff_write_symbol (abfd, symbol, native, written);
+}
+
+/* Write a native symbol to a COFF file. */
+
+static boolean
+coff_write_native_symbol (abfd, symbol, written)
+ bfd *abfd;
+ coff_symbol_type *symbol;
+ unsigned int *written;
+{
+ combined_entry_type *native = symbol->native;
+ alent *lineno = symbol->lineno;
+
+ /* If this symbol has an associated line number, we must store the
+ symbol index in the line number field. We also tag the auxent to
+ point to the right place in the lineno table. */
+ if (lineno && !symbol->done_lineno)
+ {
+ unsigned int count = 0;
+ lineno[count].u.offset = *written;
+ if (native->u.syment.n_numaux)
+ {
+ union internal_auxent *a = &((native+1)->u.auxent);
+
+ a->x_sym.x_fcnary.x_fcn.x_lnnoptr =
+ symbol->symbol.section->output_section->moving_line_filepos;
+ }
+
+ /* Count and relocate all other linenumbers. */
+ count++;
+ while (lineno[count].line_number != 0)
+ {
+#if 0
+ /* 13 april 92. sac
+ I've been told this, but still need proof:
+ > The second bug is also in `bfd/coffcode.h'. This bug
+ > causes the linker to screw up the pc-relocations for
+ > all the line numbers in COFF code. This bug isn't only
+ > specific to A29K implementations, but affects all
+ > systems using COFF format binaries. Note that in COFF
+ > object files, the line number core offsets output by
+ > the assembler are relative to the start of each
+ > procedure, not to the start of the .text section. This
+ > patch relocates the line numbers relative to the
+ > `native->u.syment.n_value' instead of the section
+ > virtual address.
+ > modular!olson@cs.arizona.edu (Jon Olson)
+ */
+ lineno[count].u.offset += native->u.syment.n_value;
+#else
+ lineno[count].u.offset +=
+ (symbol->symbol.section->output_section->vma
+ + symbol->symbol.section->output_offset);
+#endif
+ count++;
+ }
+ symbol->done_lineno = true;
+
+ symbol->symbol.section->output_section->moving_line_filepos +=
+ count * bfd_coff_linesz (abfd);
+ }
+
+ return coff_write_symbol (abfd, &(symbol->symbol), native, written);
+}
+
+/* Write out the COFF symbols. */
+
+boolean
+coff_write_symbols (abfd)
+ bfd *abfd;
+{
+ unsigned int i;
+ unsigned int limit = bfd_get_symcount(abfd);
+ unsigned int written = 0;
+ asymbol **p;
+
+ string_size = 0;
+ debug_string_size = 0;
+
+ /* Seek to the right place */
+ if (bfd_seek (abfd, obj_sym_filepos(abfd), SEEK_SET) != 0)
+ return false;
+
+ /* Output all the symbols we have */
+
+ written = 0;
+ for (p = abfd->outsymbols, i = 0; i < limit; i++, p++)
+ {
+ asymbol *symbol = *p;
+ coff_symbol_type *c_symbol = coff_symbol_from (abfd, symbol);
+
+ if (c_symbol == (coff_symbol_type *) NULL
+ || c_symbol->native == (combined_entry_type *)NULL)
+ {
+ if (! coff_write_alien_symbol (abfd, symbol, &written))
+ return false;
+ }
+ else
+ {
+ if (! coff_write_native_symbol (abfd, c_symbol, &written))
+ return false;
+ }
+ }
+
+ bfd_get_symcount (abfd) = written;
+
+ /* Now write out strings */
+
+ if (string_size != 0)
+ {
+ unsigned int size = string_size + 4;
+ bfd_byte buffer[4];
+
+ bfd_h_put_32 (abfd, size, buffer);
+ if (bfd_write ((PTR) buffer, 1, sizeof (buffer), abfd) != sizeof (buffer))
+ return false;
+ for (p = abfd->outsymbols, i = 0;
+ i < limit;
+ i++, p++)
+ {
+ asymbol *q = *p;
+ size_t name_length = strlen (q->name);
+ coff_symbol_type *c_symbol = coff_symbol_from (abfd, q);
+ size_t maxlen;
+
+ /* Figure out whether the symbol name should go in the string
+ table. Symbol names that are short enough are stored
+ directly in the syment structure. File names permit a
+ different, longer, length in the syment structure. On
+ XCOFF, some symbol names are stored in the .debug section
+ rather than in the string table. */
+
+ if (c_symbol == NULL
+ || c_symbol->native == NULL)
+ {
+ /* This is not a COFF symbol, so it certainly is not a
+ file name, nor does it go in the .debug section. */
+ maxlen = SYMNMLEN;
+ }
+ else if (bfd_coff_symname_in_debug (abfd,
+ &c_symbol->native->u.syment))
+ {
+ /* This symbol name is in the XCOFF .debug section.
+ Don't write it into the string table. */
+ maxlen = name_length;
+ }
+ else if (c_symbol->native->u.syment.n_sclass == C_FILE)
+ maxlen = FILNMLEN;
+ else
+ maxlen = SYMNMLEN;
+
+ if (name_length > maxlen)
+ {
+ if (bfd_write ((PTR) (q->name), 1, name_length + 1, abfd)
+ != name_length + 1)
+ return false;
+ }
+ }
+ }
+ else
+ {
+ /* We would normally not write anything here, but we'll write
+ out 4 so that any stupid coff reader which tries to read the
+ string table even when there isn't one won't croak. */
+ unsigned int size = 4;
+ bfd_byte buffer[4];
+
+ bfd_h_put_32 (abfd, size, buffer);
+ if (bfd_write ((PTR) buffer, 1, 4, abfd) != 4)
+ return false;
+ }
+
+ /* Make sure the .debug section was created to be the correct size.
+ We should create it ourselves on the fly, but we don't because
+ BFD won't let us write to any section until we know how large all
+ the sections are. We could still do it by making another pass
+ over the symbols. FIXME. */
+ BFD_ASSERT (debug_string_size == 0
+ || (debug_string_section != (asection *) NULL
+ && (BFD_ALIGN (debug_string_size,
+ 1 << debug_string_section->alignment_power)
+ == bfd_section_size (abfd, debug_string_section))));
+
+ return true;
+}
+
+boolean
+coff_write_linenumbers (abfd)
+ bfd *abfd;
+{
+ asection *s;
+ bfd_size_type linesz;
+ PTR buff;
+
+ linesz = bfd_coff_linesz (abfd);
+ buff = bfd_alloc (abfd, linesz);
+ if (!buff)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ return false;
+ }
+ for (s = abfd->sections; s != (asection *) NULL; s = s->next) {
+ if (s->lineno_count) {
+ asymbol **q = abfd->outsymbols;
+ if (bfd_seek(abfd, s->line_filepos, SEEK_SET) != 0)
+ return false;
+ /* Find all the linenumbers in this section */
+ while (*q) {
+ asymbol *p = *q;
+ if (p->section->output_section == s) {
+ alent *l =
+ BFD_SEND(bfd_asymbol_bfd(p), _get_lineno, (bfd_asymbol_bfd(p), p));
+ if (l) {
+ /* Found a linenumber entry, output */
+ struct internal_lineno out;
+ memset( (PTR)&out, 0, sizeof(out));
+ out.l_lnno = 0;
+ out.l_addr.l_symndx = l->u.offset;
+ bfd_coff_swap_lineno_out(abfd, &out, buff);
+ if (bfd_write(buff, 1, linesz, abfd) != linesz)
+ return false;
+ l++;
+ while (l->line_number) {
+ out.l_lnno = l->line_number;
+ out.l_addr.l_symndx = l->u.offset;
+ bfd_coff_swap_lineno_out(abfd, &out, buff);
+ if (bfd_write(buff, 1, linesz, abfd) != linesz)
+ return false;
+ l++;
+ }
+ }
+ }
+ q++;
+ }
+ }
+ }
+ bfd_release (abfd, buff);
+ return true;
+}
+
+/*ARGSUSED*/
+alent *
+coff_get_lineno (ignore_abfd, symbol)
+ bfd *ignore_abfd;
+ asymbol *symbol;
+{
+ return coffsymbol(symbol)->lineno;
+}
+
+asymbol *
+coff_section_symbol (abfd, name)
+ bfd *abfd;
+ char *name;
+{
+ asection *sec = bfd_make_section_old_way (abfd, name);
+ asymbol *sym;
+ combined_entry_type *csym;
+
+ sym = sec->symbol;
+ csym = coff_symbol_from (abfd, sym)->native;
+ /* Make sure back-end COFF stuff is there. */
+ if (csym == 0)
+ {
+ struct foo {
+ coff_symbol_type sym;
+ /* @@FIXME This shouldn't use a fixed size!! */
+ combined_entry_type e[10];
+ };
+ struct foo *f;
+ f = (struct foo *) bfd_alloc_by_size_t (abfd, sizeof (*f));
+ if (!f)
+ {
+ bfd_set_error (bfd_error_no_error);
+ return NULL;
+ }
+ memset ((char *) f, 0, sizeof (*f));
+ coff_symbol_from (abfd, sym)->native = csym = f->e;
+ }
+ csym[0].u.syment.n_sclass = C_STAT;
+ csym[0].u.syment.n_numaux = 1;
+/* SF_SET_STATICS (sym); @@ ??? */
+ csym[1].u.auxent.x_scn.x_scnlen = sec->_raw_size;
+ csym[1].u.auxent.x_scn.x_nreloc = sec->reloc_count;
+ csym[1].u.auxent.x_scn.x_nlinno = sec->lineno_count;
+
+ if (sec->output_section == NULL)
+ {
+ sec->output_section = sec;
+ sec->output_offset = 0;
+ }
+
+ return sym;
+}
+
+/* This function transforms the offsets into the symbol table into
+ pointers to syments. */
+
+static void
+coff_pointerize_aux (abfd, table_base, type, class, auxent)
+ bfd *abfd;
+ combined_entry_type *table_base;
+ int type;
+ int class;
+ combined_entry_type *auxent;
+{
+ /* Don't bother if this is a file or a section */
+ if (class == C_STAT && type == T_NULL) return;
+ if (class == C_FILE) return;
+
+ /* Otherwise patch up */
+#define N_TMASK coff_data (abfd)->local_n_tmask
+#define N_BTSHFT coff_data (abfd)->local_n_btshft
+ if (ISFCN(type) || ISTAG(class) || class == C_BLOCK) {
+ auxent->u.auxent.x_sym.x_fcnary.x_fcn.x_endndx.p = table_base +
+ auxent->u.auxent.x_sym.x_fcnary.x_fcn.x_endndx.l;
+ auxent->fix_end = 1;
+ }
+ /* A negative tagndx is meaningless, but the SCO 3.2v4 cc can
+ generate one, so we must be careful to ignore it. */
+ if (auxent->u.auxent.x_sym.x_tagndx.l > 0) {
+ auxent->u.auxent.x_sym.x_tagndx.p =
+ table_base + auxent->u.auxent.x_sym.x_tagndx.l;
+ auxent->fix_tag = 1;
+ }
+}
+
+static char *
+build_string_table (abfd)
+ bfd *abfd;
+{
+ char string_table_size_buffer[4];
+ unsigned int string_table_size;
+ char *string_table;
+
+ /* At this point we should be "seek"'d to the end of the
+ symbols === the symbol table size. */
+ if (bfd_read((char *) string_table_size_buffer,
+ sizeof(string_table_size_buffer),
+ 1, abfd) != sizeof(string_table_size))
+ return (NULL);
+
+ string_table_size = bfd_h_get_32(abfd, (bfd_byte *) string_table_size_buffer);
+
+ if ((string_table = (PTR) bfd_alloc(abfd, string_table_size -= 4)) == NULL) {
+ bfd_set_error (bfd_error_no_memory);
+ return (NULL);
+ } /* on mallocation error */
+ if (bfd_read(string_table, string_table_size, 1, abfd) != string_table_size)
+ return (NULL);
+ return string_table;
+}
+
+/* Allocate space for the ".debug" section, and read it.
+ We did not read the debug section until now, because
+ we didn't want to go to the trouble until someone needed it. */
+
+static char *
+build_debug_section (abfd)
+ bfd *abfd;
+{
+ char *debug_section;
+ long position;
+
+ asection *sect = bfd_get_section_by_name (abfd, ".debug");
+
+ if (!sect) {
+ bfd_set_error (bfd_error_no_debug_section);
+ return NULL;
+ }
+
+ debug_section = (PTR) bfd_alloc (abfd,
+ bfd_get_section_size_before_reloc (sect));
+ if (debug_section == NULL) {
+ bfd_set_error (bfd_error_no_memory);
+ return NULL;
+ }
+
+ /* Seek to the beginning of the `.debug' section and read it.
+ Save the current position first; it is needed by our caller.
+ Then read debug section and reset the file pointer. */
+
+ position = bfd_tell (abfd);
+ if (bfd_seek (abfd, sect->filepos, SEEK_SET) != 0
+ || (bfd_read (debug_section,
+ bfd_get_section_size_before_reloc (sect), 1, abfd)
+ != bfd_get_section_size_before_reloc(sect))
+ || bfd_seek (abfd, position, SEEK_SET) != 0)
+ return NULL;
+ return debug_section;
+}
+
+
+/* Return a pointer to a malloc'd copy of 'name'. 'name' may not be
+ \0-terminated, but will not exceed 'maxlen' characters. The copy *will*
+ be \0-terminated. */
+static char *
+copy_name (abfd, name, maxlen)
+ bfd *abfd;
+ char *name;
+ int maxlen;
+{
+ int len;
+ char *newname;
+
+ for (len = 0; len < maxlen; ++len) {
+ if (name[len] == '\0') {
+ break;
+ }
+ }
+
+ if ((newname = (PTR) bfd_alloc(abfd, len+1)) == NULL) {
+ bfd_set_error (bfd_error_no_memory);
+ return (NULL);
+ }
+ strncpy(newname, name, len);
+ newname[len] = '\0';
+ return newname;
+}
+
+/* Read a symbol table into freshly bfd_allocated memory, swap it, and
+ knit the symbol names into a normalized form. By normalized here I
+ mean that all symbols have an n_offset pointer that points to a null-
+ terminated string. */
+
+combined_entry_type *
+coff_get_normalized_symtab (abfd)
+ bfd *abfd;
+{
+ combined_entry_type *internal;
+ combined_entry_type *internal_ptr;
+ combined_entry_type *symbol_ptr;
+ combined_entry_type *internal_end;
+ bfd_size_type symesz;
+ PTR raw;
+ char *raw_src;
+ char *raw_end;
+ char *string_table = NULL;
+ char *debug_section = NULL;
+ unsigned long size;
+
+ unsigned int raw_size;
+ if (obj_raw_syments(abfd) != (combined_entry_type *)NULL) {
+ return obj_raw_syments(abfd);
+ }
+ if ((size = bfd_get_symcount(abfd) * sizeof(combined_entry_type)) == 0) {
+ bfd_set_error (bfd_error_no_symbols);
+ return (NULL);
+ }
+
+ internal = (combined_entry_type *)bfd_alloc(abfd, size);
+ if (!internal)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ return NULL;
+ }
+ internal_end = internal + bfd_get_symcount(abfd);
+
+ symesz = bfd_coff_symesz (abfd);
+ raw_size = bfd_get_symcount(abfd) * symesz;
+ raw = bfd_alloc(abfd,raw_size);
+ if (!raw)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ return NULL;
+ }
+
+ if (bfd_seek(abfd, obj_sym_filepos(abfd), SEEK_SET) == -1
+ || bfd_read(raw, raw_size, 1, abfd) != raw_size)
+ return (NULL);
+ /* mark the end of the symbols */
+ raw_end = (char *) raw + bfd_get_symcount(abfd) * symesz;
+ /*
+ FIXME SOMEDAY. A string table size of zero is very weird, but
+ probably possible. If one shows up, it will probably kill us.
+ */
+
+ /* Swap all the raw entries */
+ for (raw_src = (char *) raw, internal_ptr = internal;
+ raw_src < raw_end;
+ raw_src += symesz, internal_ptr++) {
+
+ unsigned int i;
+ bfd_coff_swap_sym_in(abfd, (PTR)raw_src, (PTR)&internal_ptr->u.syment);
+ internal_ptr->fix_value = 0;
+ internal_ptr->fix_tag = 0;
+ internal_ptr->fix_end = 0;
+ internal_ptr->fix_scnlen = 0;
+ symbol_ptr = internal_ptr;
+
+ for (i = 0;
+ i < symbol_ptr->u.syment.n_numaux;
+ i++)
+ {
+ internal_ptr++;
+ raw_src += symesz;
+
+ internal_ptr->fix_value = 0;
+ internal_ptr->fix_tag = 0;
+ internal_ptr->fix_end = 0;
+ internal_ptr->fix_scnlen = 0;
+ bfd_coff_swap_aux_in(abfd, (PTR) raw_src,
+ symbol_ptr->u.syment.n_type,
+ symbol_ptr->u.syment.n_sclass,
+ i, symbol_ptr->u.syment.n_numaux,
+ &(internal_ptr->u.auxent));
+ /* Remember that bal entries arn't pointerized */
+ if (i != 1 || symbol_ptr->u.syment.n_sclass != C_LEAFPROC)
+ {
+
+ coff_pointerize_aux(abfd,
+ internal,
+ symbol_ptr->u.syment.n_type,
+ symbol_ptr->u.syment.n_sclass,
+ internal_ptr);
+ }
+
+ }
+ }
+
+ /* Free all the raw stuff */
+ bfd_release(abfd, raw);
+
+ for (internal_ptr = internal; internal_ptr < internal_end;
+ internal_ptr ++)
+ {
+ if (internal_ptr->u.syment.n_sclass == C_FILE) {
+ /* make a file symbol point to the name in the auxent, since
+ the text ".file" is redundant */
+ if ((internal_ptr+1)->u.auxent.x_file.x_n.x_zeroes == 0) {
+ /* the filename is a long one, point into the string table */
+ if (string_table == NULL) {
+ string_table = build_string_table(abfd);
+ }
+
+ internal_ptr->u.syment._n._n_n._n_offset =
+ (long) (string_table - 4 +
+ (internal_ptr+1)->u.auxent.x_file.x_n.x_offset);
+ }
+ else {
+ /* ordinary short filename, put into memory anyway */
+ internal_ptr->u.syment._n._n_n._n_offset = (long)
+ copy_name(abfd, (internal_ptr+1)->u.auxent.x_file.x_fname,
+ FILNMLEN);
+ }
+ }
+ else {
+ if (internal_ptr->u.syment._n._n_n._n_zeroes != 0) {
+ /* This is a "short" name. Make it long. */
+ unsigned long i = 0;
+ char *newstring = NULL;
+
+ /* find the length of this string without walking into memory
+ that isn't ours. */
+ for (i = 0; i < 8; ++i) {
+ if (internal_ptr->u.syment._n._n_name[i] == '\0') {
+ break;
+ } /* if end of string */
+ } /* possible lengths of this string. */
+
+ if ((newstring = (PTR) bfd_alloc(abfd, ++i)) == NULL) {
+ bfd_set_error (bfd_error_no_memory);
+ return (NULL);
+ } /* on error */
+ memset(newstring, 0, i);
+ strncpy(newstring, internal_ptr->u.syment._n._n_name, i-1);
+ internal_ptr->u.syment._n._n_n._n_offset = (long int) newstring;
+ internal_ptr->u.syment._n._n_n._n_zeroes = 0;
+ }
+ else if (internal_ptr->u.syment._n._n_n._n_offset == 0)
+ internal_ptr->u.syment._n._n_n._n_offset = (long int) "";
+ else if (!bfd_coff_symname_in_debug(abfd, &internal_ptr->u.syment)) {
+ /* Long name already. Point symbol at the string in the table. */
+ if (string_table == NULL) {
+ string_table = build_string_table(abfd);
+ }
+ internal_ptr->u.syment._n._n_n._n_offset = (long int)
+ (string_table - 4 + internal_ptr->u.syment._n._n_n._n_offset);
+ }
+ else {
+ /* Long name in debug section. Very similar. */
+ if (debug_section == NULL) {
+ debug_section = build_debug_section(abfd);
+ }
+ internal_ptr->u.syment._n._n_n._n_offset = (long int)
+ (debug_section + internal_ptr->u.syment._n._n_n._n_offset);
+ }
+ }
+ internal_ptr += internal_ptr->u.syment.n_numaux;
+ }
+
+ obj_raw_syments(abfd) = internal;
+ obj_raw_syment_count(abfd) = internal_ptr - internal;
+
+ return (internal);
+} /* coff_get_normalized_symtab() */
+
+long
+coff_get_reloc_upper_bound (abfd, asect)
+ bfd *abfd;
+ sec_ptr asect;
+{
+ if (bfd_get_format(abfd) != bfd_object) {
+ bfd_set_error (bfd_error_invalid_operation);
+ return -1;
+ }
+ return (asect->reloc_count + 1) * sizeof(arelent *);
+}
+
+asymbol *
+coff_make_empty_symbol (abfd)
+ bfd *abfd;
+{
+ coff_symbol_type *new = (coff_symbol_type *) bfd_alloc(abfd, sizeof(coff_symbol_type));
+ if (new == NULL) {
+ bfd_set_error (bfd_error_no_memory);
+ return (NULL);
+ } /* on error */
+ memset (new, 0, sizeof *new);
+ new->symbol.section = 0;
+ new->native = 0;
+ new->lineno = (alent *) NULL;
+ new->done_lineno = false;
+ new->symbol.the_bfd = abfd;
+ return &new->symbol;
+}
+
+/* Make a debugging symbol. */
+
+asymbol *
+coff_bfd_make_debug_symbol (abfd, ptr, sz)
+ bfd *abfd;
+ PTR ptr;
+ unsigned long sz;
+{
+ coff_symbol_type *new = (coff_symbol_type *) bfd_alloc(abfd, sizeof(coff_symbol_type));
+ if (new == NULL) {
+ bfd_set_error (bfd_error_no_memory);
+ return (NULL);
+ } /* on error */
+ /* @@ This shouldn't be using a constant multiplier. */
+ new->native = (combined_entry_type *) bfd_zalloc (abfd, sizeof (combined_entry_type) * 10);
+ if (!new->native)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ return (NULL);
+ } /* on error */
+ new->symbol.section = &bfd_debug_section;
+ new->lineno = (alent *) NULL;
+ new->done_lineno = false;
+ new->symbol.the_bfd = abfd;
+ return &new->symbol;
+}
+
+/*ARGSUSED*/
+void
+coff_get_symbol_info (abfd, symbol, ret)
+ bfd *abfd;
+ asymbol *symbol;
+ symbol_info *ret;
+{
+ bfd_symbol_info (symbol, ret);
+}
+
+/* Print out information about COFF symbol. */
+
+void
+coff_print_symbol (abfd, filep, symbol, how)
+ bfd *abfd;
+ PTR filep;
+ asymbol *symbol;
+ bfd_print_symbol_type how;
+{
+ FILE *file = (FILE *) filep;
+
+ switch (how)
+ {
+ case bfd_print_symbol_name:
+ fprintf (file, "%s", symbol->name);
+ break;
+
+ case bfd_print_symbol_more:
+ fprintf (file, "coff %s %s",
+ coffsymbol(symbol)->native ? "n" : "g",
+ coffsymbol(symbol)->lineno ? "l" : " ");
+ break;
+
+ case bfd_print_symbol_all:
+ if (coffsymbol(symbol)->native)
+ {
+ unsigned int aux;
+ combined_entry_type *combined = coffsymbol (symbol)->native;
+ combined_entry_type *root = obj_raw_syments (abfd);
+ struct lineno_cache_entry *l = coffsymbol(symbol)->lineno;
+
+ fprintf (file,"[%3d]", combined - root);
+
+ fprintf (file,
+ "(sc %2d)(fl 0x%02x)(ty %3x)(sc %3d) (nx %d) 0x%08lx %s",
+ combined->u.syment.n_scnum,
+ combined->u.syment.n_flags,
+ combined->u.syment.n_type,
+ combined->u.syment.n_sclass,
+ combined->u.syment.n_numaux,
+ (unsigned long) combined->u.syment.n_value,
+ symbol->name);
+
+ for (aux = 0; aux < combined->u.syment.n_numaux; aux++)
+ {
+ combined_entry_type *auxp = combined + aux + 1;
+ long tagndx;
+
+ if (auxp->fix_tag)
+ tagndx = auxp->u.auxent.x_sym.x_tagndx.p - root;
+ else
+ tagndx = auxp->u.auxent.x_sym.x_tagndx.l;
+
+ fprintf (file, "\n");
+ switch (combined->u.syment.n_sclass)
+ {
+ case C_FILE:
+ fprintf (file, "File ");
+ break;
+ default:
+
+ fprintf (file, "AUX lnno %d size 0x%x tagndx %ld",
+ auxp->u.auxent.x_sym.x_misc.x_lnsz.x_lnno,
+ auxp->u.auxent.x_sym.x_misc.x_lnsz.x_size,
+ tagndx);
+ break;
+ }
+ }
+
+ if (l)
+ {
+ fprintf (file, "\n%s :", l->u.sym->name);
+ l++;
+ while (l->line_number)
+ {
+ fprintf (file, "\n%4d : 0x%lx",
+ l->line_number,
+ ((unsigned long)
+ (l->u.offset + symbol->section->vma)));
+ l++;
+ }
+ }
+ }
+ else
+ {
+ bfd_print_symbol_vandf ((PTR) file, symbol);
+ fprintf (file, " %-5s %s %s %s",
+ symbol->section->name,
+ coffsymbol(symbol)->native ? "n" : "g",
+ coffsymbol(symbol)->lineno ? "l" : " ",
+ symbol->name);
+ }
+ }
+}
+
+/* Provided a BFD, a section and an offset into the section, calculate
+ and return the name of the source file and the line nearest to the
+ wanted location. */
+
+/*ARGSUSED*/
+boolean
+coff_find_nearest_line (abfd, section, ignore_symbols, offset, filename_ptr,
+ functionname_ptr, line_ptr)
+ bfd *abfd;
+ asection *section;
+ asymbol **ignore_symbols;
+ bfd_vma offset;
+ CONST char **filename_ptr;
+ CONST char **functionname_ptr;
+ unsigned int *line_ptr;
+{
+ static bfd *cache_abfd;
+ static asection *cache_section;
+ static bfd_vma cache_offset;
+ static unsigned int cache_i;
+ static CONST char *cache_function;
+ static unsigned int line_base = 0;
+
+ unsigned int i = 0;
+ coff_data_type *cof = coff_data(abfd);
+ /* Run through the raw syments if available */
+ combined_entry_type *p;
+ alent *l;
+
+
+ *filename_ptr = 0;
+ *functionname_ptr = 0;
+ *line_ptr = 0;
+
+ /* Don't try and find line numbers in a non coff file */
+ if (abfd->xvec->flavour != bfd_target_coff_flavour)
+ return false;
+
+ if (cof == NULL)
+ return false;
+
+ p = cof->raw_syments;
+
+ for (i = 0; i < cof->raw_syment_count; i++) {
+ if (p->u.syment.n_sclass == C_FILE) {
+ /* File name has been moved into symbol */
+ *filename_ptr = (char *) p->u.syment._n._n_n._n_offset;
+ break;
+ }
+ p += 1 + p->u.syment.n_numaux;
+ }
+ /* Now wander though the raw linenumbers of the section */
+ /*
+ If this is the same BFD as we were previously called with and this is
+ the same section, and the offset we want is further down then we can
+ prime the lookup loop
+ */
+ if (abfd == cache_abfd &&
+ section == cache_section &&
+ offset >= cache_offset) {
+ i = cache_i;
+ *functionname_ptr = cache_function;
+ }
+ else {
+ i = 0;
+ }
+ l = &section->lineno[i];
+
+ for (; i < section->lineno_count; i++) {
+ if (l->line_number == 0) {
+ /* Get the symbol this line number points at */
+ coff_symbol_type *coff = (coff_symbol_type *) (l->u.sym);
+ if (coff->symbol.value > offset)
+ break;
+ *functionname_ptr = coff->symbol.name;
+ if (coff->native) {
+ combined_entry_type *s = coff->native;
+ s = s + 1 + s->u.syment.n_numaux;
+ /*
+ S should now point to the .bf of the function
+ */
+ if (s->u.syment.n_numaux) {
+ /*
+ The linenumber is stored in the auxent
+ */
+ union internal_auxent *a = &((s + 1)->u.auxent);
+ line_base = a->x_sym.x_misc.x_lnsz.x_lnno;
+ *line_ptr = line_base;
+ }
+ }
+ }
+ else {
+ if (l->u.offset > offset)
+ break;
+ *line_ptr = l->line_number + line_base - 1;
+ }
+ l++;
+ }
+
+ cache_abfd = abfd;
+ cache_section = section;
+ cache_offset = offset;
+ cache_i = i;
+ cache_function = *functionname_ptr;
+
+ return true;
+}
+
+int
+coff_sizeof_headers (abfd, reloc)
+ bfd *abfd;
+ boolean reloc;
+{
+ size_t size;
+
+ if (reloc == false) {
+ size = bfd_coff_filhsz (abfd) + bfd_coff_aoutsz (abfd);
+ }
+ else {
+ size = bfd_coff_filhsz (abfd);
+ }
+
+ size += abfd->section_count * bfd_coff_scnhsz (abfd);
+ return size;
+}
diff --git a/gnu/usr.bin/gdb/bfd/coffswap.h b/gnu/usr.bin/gdb/bfd/coffswap.h
new file mode 100644
index 0000000..f047a9a
--- /dev/null
+++ b/gnu/usr.bin/gdb/bfd/coffswap.h
@@ -0,0 +1,741 @@
+/* Generic COFF swapping routines, for BFD.
+ Copyright 1990, 1991, 1992, 1993 Free Software Foundation, Inc.
+ Written by Cygnus Support.
+
+This file is part of BFD, the Binary File Descriptor library.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* This file contains routines used to swap COFF data. It is a header
+ file because the details of swapping depend on the details of the
+ structures used by each COFF implementation. This is included by
+ coffcode.h, as well as by the ECOFF backend.
+
+ Any file which uses this must first include "coff/internal.h" and
+ "coff/CPU.h". The functions will then be correct for that CPU. */
+
+#define PUTWORD bfd_h_put_32
+#define PUTHALF bfd_h_put_16
+#define PUTBYTE bfd_h_put_8
+
+#ifndef GET_FCN_LNNOPTR
+#define GET_FCN_LNNOPTR(abfd, ext) bfd_h_get_32(abfd, (bfd_byte *) ext->x_sym.x_fcnary.x_fcn.x_lnnoptr)
+#endif
+
+#ifndef GET_FCN_ENDNDX
+#define GET_FCN_ENDNDX(abfd, ext) bfd_h_get_32(abfd, (bfd_byte *) ext->x_sym.x_fcnary.x_fcn.x_endndx)
+#endif
+
+#ifndef PUT_FCN_LNNOPTR
+#define PUT_FCN_LNNOPTR(abfd, in, ext) PUTWORD(abfd, in, (bfd_byte *) ext->x_sym.x_fcnary.x_fcn.x_lnnoptr)
+#endif
+#ifndef PUT_FCN_ENDNDX
+#define PUT_FCN_ENDNDX(abfd, in, ext) PUTWORD(abfd, in, (bfd_byte *) ext->x_sym.x_fcnary.x_fcn.x_endndx)
+#endif
+#ifndef GET_LNSZ_LNNO
+#define GET_LNSZ_LNNO(abfd, ext) bfd_h_get_16(abfd, (bfd_byte *) ext->x_sym.x_misc.x_lnsz.x_lnno)
+#endif
+#ifndef GET_LNSZ_SIZE
+#define GET_LNSZ_SIZE(abfd, ext) bfd_h_get_16(abfd, (bfd_byte *) ext->x_sym.x_misc.x_lnsz.x_size)
+#endif
+#ifndef PUT_LNSZ_LNNO
+#define PUT_LNSZ_LNNO(abfd, in, ext) bfd_h_put_16(abfd, in, (bfd_byte *)ext->x_sym.x_misc.x_lnsz.x_lnno)
+#endif
+#ifndef PUT_LNSZ_SIZE
+#define PUT_LNSZ_SIZE(abfd, in, ext) bfd_h_put_16(abfd, in, (bfd_byte*) ext->x_sym.x_misc.x_lnsz.x_size)
+#endif
+#ifndef GET_SCN_SCNLEN
+#define GET_SCN_SCNLEN(abfd, ext) bfd_h_get_32(abfd, (bfd_byte *) ext->x_scn.x_scnlen)
+#endif
+#ifndef GET_SCN_NRELOC
+#define GET_SCN_NRELOC(abfd, ext) bfd_h_get_16(abfd, (bfd_byte *)ext->x_scn.x_nreloc)
+#endif
+#ifndef GET_SCN_NLINNO
+#define GET_SCN_NLINNO(abfd, ext) bfd_h_get_16(abfd, (bfd_byte *)ext->x_scn.x_nlinno)
+#endif
+#ifndef PUT_SCN_SCNLEN
+#define PUT_SCN_SCNLEN(abfd,in, ext) bfd_h_put_32(abfd, in, (bfd_byte *) ext->x_scn.x_scnlen)
+#endif
+#ifndef PUT_SCN_NRELOC
+#define PUT_SCN_NRELOC(abfd,in, ext) bfd_h_put_16(abfd, in, (bfd_byte *)ext->x_scn.x_nreloc)
+#endif
+#ifndef PUT_SCN_NLINNO
+#define PUT_SCN_NLINNO(abfd,in, ext) bfd_h_put_16(abfd,in, (bfd_byte *) ext->x_scn.x_nlinno)
+#endif
+#ifndef GET_LINENO_LNNO
+#define GET_LINENO_LNNO(abfd, ext) bfd_h_get_16(abfd, (bfd_byte *) (ext->l_lnno));
+#endif
+#ifndef PUT_LINENO_LNNO
+#define PUT_LINENO_LNNO(abfd,val, ext) bfd_h_put_16(abfd,val, (bfd_byte *) (ext->l_lnno));
+#endif
+
+/* The f_symptr field in the filehdr is sometimes 64 bits. */
+#ifndef GET_FILEHDR_SYMPTR
+#define GET_FILEHDR_SYMPTR bfd_h_get_32
+#endif
+#ifndef PUT_FILEHDR_SYMPTR
+#define PUT_FILEHDR_SYMPTR bfd_h_put_32
+#endif
+
+/* Some fields in the aouthdr are sometimes 64 bits. */
+#ifndef GET_AOUTHDR_TSIZE
+#define GET_AOUTHDR_TSIZE bfd_h_get_32
+#endif
+#ifndef PUT_AOUTHDR_TSIZE
+#define PUT_AOUTHDR_TSIZE bfd_h_put_32
+#endif
+#ifndef GET_AOUTHDR_DSIZE
+#define GET_AOUTHDR_DSIZE bfd_h_get_32
+#endif
+#ifndef PUT_AOUTHDR_DSIZE
+#define PUT_AOUTHDR_DSIZE bfd_h_put_32
+#endif
+#ifndef GET_AOUTHDR_BSIZE
+#define GET_AOUTHDR_BSIZE bfd_h_get_32
+#endif
+#ifndef PUT_AOUTHDR_BSIZE
+#define PUT_AOUTHDR_BSIZE bfd_h_put_32
+#endif
+#ifndef GET_AOUTHDR_ENTRY
+#define GET_AOUTHDR_ENTRY bfd_h_get_32
+#endif
+#ifndef PUT_AOUTHDR_ENTRY
+#define PUT_AOUTHDR_ENTRY bfd_h_put_32
+#endif
+#ifndef GET_AOUTHDR_TEXT_START
+#define GET_AOUTHDR_TEXT_START bfd_h_get_32
+#endif
+#ifndef PUT_AOUTHDR_TEXT_START
+#define PUT_AOUTHDR_TEXT_START bfd_h_put_32
+#endif
+#ifndef GET_AOUTHDR_DATA_START
+#define GET_AOUTHDR_DATA_START bfd_h_get_32
+#endif
+#ifndef PUT_AOUTHDR_DATA_START
+#define PUT_AOUTHDR_DATA_START bfd_h_put_32
+#endif
+
+/* Some fields in the scnhdr are sometimes 64 bits. */
+#ifndef GET_SCNHDR_PADDR
+#define GET_SCNHDR_PADDR bfd_h_get_32
+#endif
+#ifndef PUT_SCNHDR_PADDR
+#define PUT_SCNHDR_PADDR bfd_h_put_32
+#endif
+#ifndef GET_SCNHDR_VADDR
+#define GET_SCNHDR_VADDR bfd_h_get_32
+#endif
+#ifndef PUT_SCNHDR_VADDR
+#define PUT_SCNHDR_VADDR bfd_h_put_32
+#endif
+#ifndef GET_SCNHDR_SIZE
+#define GET_SCNHDR_SIZE bfd_h_get_32
+#endif
+#ifndef PUT_SCNHDR_SIZE
+#define PUT_SCNHDR_SIZE bfd_h_put_32
+#endif
+#ifndef GET_SCNHDR_SCNPTR
+#define GET_SCNHDR_SCNPTR bfd_h_get_32
+#endif
+#ifndef PUT_SCNHDR_SCNPTR
+#define PUT_SCNHDR_SCNPTR bfd_h_put_32
+#endif
+#ifndef GET_SCNHDR_RELPTR
+#define GET_SCNHDR_RELPTR bfd_h_get_32
+#endif
+#ifndef PUT_SCNHDR_RELPTR
+#define PUT_SCNHDR_RELPTR bfd_h_put_32
+#endif
+#ifndef GET_SCNHDR_LNNOPTR
+#define GET_SCNHDR_LNNOPTR bfd_h_get_32
+#endif
+#ifndef PUT_SCNHDR_LNNOPTR
+#define PUT_SCNHDR_LNNOPTR bfd_h_put_32
+#endif
+
+#ifndef NO_COFF_RELOCS
+
+static void
+bfd_swap_reloc_in (abfd, reloc_src, reloc_dst)
+ bfd *abfd;
+ RELOC *reloc_src;
+ struct internal_reloc *reloc_dst;
+{
+ reloc_dst->r_vaddr = bfd_h_get_32(abfd, (bfd_byte *)reloc_src->r_vaddr);
+ reloc_dst->r_symndx = bfd_h_get_signed_32(abfd, (bfd_byte *) reloc_src->r_symndx);
+
+#ifdef RS6000COFF_C
+ reloc_dst->r_type = bfd_h_get_8(abfd, reloc_src->r_type);
+ reloc_dst->r_size = bfd_h_get_8(abfd, reloc_src->r_size);
+#else
+ reloc_dst->r_type = bfd_h_get_16(abfd, (bfd_byte *) reloc_src->r_type);
+#endif
+
+#ifdef SWAP_IN_RELOC_OFFSET
+ reloc_dst->r_offset = SWAP_IN_RELOC_OFFSET(abfd,
+ (bfd_byte *) reloc_src->r_offset);
+#endif
+}
+
+
+static unsigned int
+coff_swap_reloc_out (abfd, src, dst)
+ bfd *abfd;
+ PTR src;
+ PTR dst;
+{
+ struct internal_reloc *reloc_src = (struct internal_reloc *)src;
+ struct external_reloc *reloc_dst = (struct external_reloc *)dst;
+ bfd_h_put_32(abfd, reloc_src->r_vaddr, (bfd_byte *) reloc_dst->r_vaddr);
+ bfd_h_put_32(abfd, reloc_src->r_symndx, (bfd_byte *) reloc_dst->r_symndx);
+
+#ifdef RS6000COFF_C
+ bfd_h_put_8 (abfd, reloc_src->r_type, (bfd_byte *) reloc_dst->r_type);
+ bfd_h_put_8 (abfd, reloc_src->r_size, (bfd_byte *) reloc_dst->r_size);
+#else
+ bfd_h_put_16(abfd, reloc_src->r_type, (bfd_byte *)
+ reloc_dst->r_type);
+#endif
+
+#ifdef SWAP_OUT_RELOC_OFFSET
+ SWAP_OUT_RELOC_OFFSET(abfd,
+ reloc_src->r_offset,
+ (bfd_byte *) reloc_dst->r_offset);
+#endif
+#ifdef SWAP_OUT_RELOC_EXTRA
+ SWAP_OUT_RELOC_EXTRA(abfd,reloc_src, reloc_dst);
+#endif
+
+ return sizeof(struct external_reloc);
+}
+
+#endif /* NO_COFF_RELOCS */
+
+static void
+coff_swap_filehdr_in (abfd, src, dst)
+ bfd *abfd;
+ PTR src;
+ PTR dst;
+{
+ FILHDR *filehdr_src = (FILHDR *) src;
+ struct internal_filehdr *filehdr_dst = (struct internal_filehdr *) dst;
+ filehdr_dst->f_magic = bfd_h_get_16(abfd, (bfd_byte *) filehdr_src->f_magic);
+ filehdr_dst->f_nscns = bfd_h_get_16(abfd, (bfd_byte *)filehdr_src-> f_nscns);
+ filehdr_dst->f_timdat = bfd_h_get_32(abfd, (bfd_byte *)filehdr_src-> f_timdat);
+ filehdr_dst->f_symptr =
+ GET_FILEHDR_SYMPTR (abfd, (bfd_byte *) filehdr_src->f_symptr);
+ filehdr_dst->f_nsyms = bfd_h_get_32(abfd, (bfd_byte *)filehdr_src-> f_nsyms);
+ filehdr_dst->f_opthdr = bfd_h_get_16(abfd, (bfd_byte *)filehdr_src-> f_opthdr);
+ filehdr_dst->f_flags = bfd_h_get_16(abfd, (bfd_byte *)filehdr_src-> f_flags);
+}
+
+static unsigned int
+coff_swap_filehdr_out (abfd, in, out)
+ bfd *abfd;
+ PTR in;
+ PTR out;
+{
+ struct internal_filehdr *filehdr_in = (struct internal_filehdr *)in;
+ FILHDR *filehdr_out = (FILHDR *)out;
+ bfd_h_put_16(abfd, filehdr_in->f_magic, (bfd_byte *) filehdr_out->f_magic);
+ bfd_h_put_16(abfd, filehdr_in->f_nscns, (bfd_byte *) filehdr_out->f_nscns);
+ bfd_h_put_32(abfd, filehdr_in->f_timdat, (bfd_byte *) filehdr_out->f_timdat);
+ PUT_FILEHDR_SYMPTR (abfd, (bfd_vma) filehdr_in->f_symptr,
+ (bfd_byte *) filehdr_out->f_symptr);
+ bfd_h_put_32(abfd, filehdr_in->f_nsyms, (bfd_byte *) filehdr_out->f_nsyms);
+ bfd_h_put_16(abfd, filehdr_in->f_opthdr, (bfd_byte *) filehdr_out->f_opthdr);
+ bfd_h_put_16(abfd, filehdr_in->f_flags, (bfd_byte *) filehdr_out->f_flags);
+ return sizeof(FILHDR);
+}
+
+
+#ifndef NO_COFF_SYMBOLS
+
+static void
+coff_swap_sym_in (abfd, ext1, in1)
+ bfd *abfd;
+ PTR ext1;
+ PTR in1;
+{
+ SYMENT *ext = (SYMENT *)ext1;
+ struct internal_syment *in = (struct internal_syment *)in1;
+
+ if( ext->e.e_name[0] == 0) {
+ in->_n._n_n._n_zeroes = 0;
+ in->_n._n_n._n_offset = bfd_h_get_32(abfd, (bfd_byte *) ext->e.e.e_offset);
+ }
+ else {
+#if SYMNMLEN != E_SYMNMLEN
+ -> Error, we need to cope with truncating or extending SYMNMLEN!;
+#else
+ memcpy(in->_n._n_name, ext->e.e_name, SYMNMLEN);
+#endif
+ }
+ in->n_value = bfd_h_get_32(abfd, (bfd_byte *) ext->e_value);
+ in->n_scnum = bfd_h_get_16(abfd, (bfd_byte *) ext->e_scnum);
+ if (sizeof(ext->e_type) == 2){
+ in->n_type = bfd_h_get_16(abfd, (bfd_byte *) ext->e_type);
+ }
+ else {
+ in->n_type = bfd_h_get_32(abfd, (bfd_byte *) ext->e_type);
+ }
+ in->n_sclass = bfd_h_get_8(abfd, ext->e_sclass);
+ in->n_numaux = bfd_h_get_8(abfd, ext->e_numaux);
+}
+
+static unsigned int
+coff_swap_sym_out (abfd, inp, extp)
+ bfd *abfd;
+ PTR inp;
+ PTR extp;
+{
+ struct internal_syment *in = (struct internal_syment *)inp;
+ SYMENT *ext =(SYMENT *)extp;
+ if(in->_n._n_name[0] == 0) {
+ bfd_h_put_32(abfd, 0, (bfd_byte *) ext->e.e.e_zeroes);
+ bfd_h_put_32(abfd, in->_n._n_n._n_offset, (bfd_byte *) ext->e.e.e_offset);
+ }
+ else {
+#if SYMNMLEN != E_SYMNMLEN
+ -> Error, we need to cope with truncating or extending SYMNMLEN!;
+#else
+ memcpy(ext->e.e_name, in->_n._n_name, SYMNMLEN);
+#endif
+ }
+ bfd_h_put_32(abfd, in->n_value , (bfd_byte *) ext->e_value);
+ bfd_h_put_16(abfd, in->n_scnum , (bfd_byte *) ext->e_scnum);
+ if (sizeof(ext->e_type) == 2)
+ {
+ bfd_h_put_16(abfd, in->n_type , (bfd_byte *) ext->e_type);
+ }
+ else
+ {
+ bfd_h_put_32(abfd, in->n_type , (bfd_byte *) ext->e_type);
+ }
+ bfd_h_put_8(abfd, in->n_sclass , ext->e_sclass);
+ bfd_h_put_8(abfd, in->n_numaux , ext->e_numaux);
+ return sizeof(SYMENT);
+}
+
+static void
+coff_swap_aux_in (abfd, ext1, type, class, indx, numaux, in1)
+ bfd *abfd;
+ PTR ext1;
+ int type;
+ int class;
+ int indx;
+ int numaux;
+ PTR in1;
+{
+ AUXENT *ext = (AUXENT *)ext1;
+ union internal_auxent *in = (union internal_auxent *)in1;
+
+ switch (class) {
+ case C_FILE:
+ if (ext->x_file.x_fname[0] == 0) {
+ in->x_file.x_n.x_zeroes = 0;
+ in->x_file.x_n.x_offset =
+ bfd_h_get_32(abfd, (bfd_byte *) ext->x_file.x_n.x_offset);
+ } else {
+#if FILNMLEN != E_FILNMLEN
+ -> Error, we need to cope with truncating or extending FILNMLEN!;
+#else
+ memcpy (in->x_file.x_fname, ext->x_file.x_fname, FILNMLEN);
+#endif
+ }
+ return;
+
+ /* RS/6000 "csect" auxents */
+#ifdef RS6000COFF_C
+ case C_EXT:
+ case C_HIDEXT:
+ if (indx + 1 == numaux)
+ {
+ in->x_csect.x_scnlen.l = bfd_h_get_32 (abfd, ext->x_csect.x_scnlen);
+ in->x_csect.x_parmhash = bfd_h_get_32 (abfd,
+ ext->x_csect.x_parmhash);
+ in->x_csect.x_snhash = bfd_h_get_16 (abfd, ext->x_csect.x_snhash);
+ /* We don't have to hack bitfields in x_smtyp because it's
+ defined by shifts-and-ands, which are equivalent on all
+ byte orders. */
+ in->x_csect.x_smtyp = bfd_h_get_8 (abfd, ext->x_csect.x_smtyp);
+ in->x_csect.x_smclas = bfd_h_get_8 (abfd, ext->x_csect.x_smclas);
+ in->x_csect.x_stab = bfd_h_get_32 (abfd, ext->x_csect.x_stab);
+ in->x_csect.x_snstab = bfd_h_get_16 (abfd, ext->x_csect.x_snstab);
+ return;
+ }
+ break;
+#endif
+
+ case C_STAT:
+#ifdef C_LEAFSTAT
+ case C_LEAFSTAT:
+#endif
+ case C_HIDDEN:
+ if (type == T_NULL) {
+ in->x_scn.x_scnlen = GET_SCN_SCNLEN(abfd, ext);
+ in->x_scn.x_nreloc = GET_SCN_NRELOC(abfd, ext);
+ in->x_scn.x_nlinno = GET_SCN_NLINNO(abfd, ext);
+ return;
+ }
+ break;
+ }
+
+ in->x_sym.x_tagndx.l = bfd_h_get_32(abfd, (bfd_byte *) ext->x_sym.x_tagndx);
+#ifndef NO_TVNDX
+ in->x_sym.x_tvndx = bfd_h_get_16(abfd, (bfd_byte *) ext->x_sym.x_tvndx);
+#endif
+
+ if (ISARY(type)) {
+#if DIMNUM != E_DIMNUM
+ -> Error, we need to cope with truncating or extending DIMNUM!;
+#else
+ in->x_sym.x_fcnary.x_ary.x_dimen[0] = bfd_h_get_16(abfd, (bfd_byte *) ext->x_sym.x_fcnary.x_ary.x_dimen[0]);
+ in->x_sym.x_fcnary.x_ary.x_dimen[1] = bfd_h_get_16(abfd, (bfd_byte *) ext->x_sym.x_fcnary.x_ary.x_dimen[1]);
+ in->x_sym.x_fcnary.x_ary.x_dimen[2] = bfd_h_get_16(abfd, (bfd_byte *) ext->x_sym.x_fcnary.x_ary.x_dimen[2]);
+ in->x_sym.x_fcnary.x_ary.x_dimen[3] = bfd_h_get_16(abfd, (bfd_byte *) ext->x_sym.x_fcnary.x_ary.x_dimen[3]);
+#endif
+ }
+ if (class == C_BLOCK || ISFCN(type) || ISTAG(class)) {
+ in->x_sym.x_fcnary.x_fcn.x_lnnoptr = GET_FCN_LNNOPTR(abfd, ext);
+ in->x_sym.x_fcnary.x_fcn.x_endndx.l = GET_FCN_ENDNDX(abfd, ext);
+ }
+
+ if (ISFCN(type)) {
+ in->x_sym.x_misc.x_fsize = bfd_h_get_32(abfd, (bfd_byte *) ext->x_sym.x_misc.x_fsize);
+ }
+ else {
+ in->x_sym.x_misc.x_lnsz.x_lnno = GET_LNSZ_LNNO(abfd, ext);
+ in->x_sym.x_misc.x_lnsz.x_size = GET_LNSZ_SIZE(abfd, ext);
+ }
+}
+
+static unsigned int
+coff_swap_aux_out (abfd, inp, type, class, indx, numaux, extp)
+ bfd *abfd;
+ PTR inp;
+ int type;
+ int class;
+ int indx;
+ int numaux;
+ PTR extp;
+{
+ union internal_auxent *in = (union internal_auxent *)inp;
+ AUXENT *ext = (AUXENT *)extp;
+
+ memset((PTR)ext, 0, AUXESZ);
+ switch (class) {
+ case C_FILE:
+ if (in->x_file.x_fname[0] == 0) {
+ PUTWORD(abfd, 0, (bfd_byte *) ext->x_file.x_n.x_zeroes);
+ PUTWORD(abfd,
+ in->x_file.x_n.x_offset,
+ (bfd_byte *) ext->x_file.x_n.x_offset);
+ }
+ else {
+#if FILNMLEN != E_FILNMLEN
+ -> Error, we need to cope with truncating or extending FILNMLEN!;
+#else
+ memcpy (ext->x_file.x_fname, in->x_file.x_fname, FILNMLEN);
+#endif
+ }
+ return sizeof (AUXENT);
+
+#ifdef RS6000COFF_C
+ /* RS/6000 "csect" auxents */
+ case C_EXT:
+ case C_HIDEXT:
+ if (indx + 1 == numaux)
+ {
+ PUTWORD (abfd, in->x_csect.x_scnlen.l, ext->x_csect.x_scnlen);
+ PUTWORD (abfd, in->x_csect.x_parmhash, ext->x_csect.x_parmhash);
+ PUTHALF (abfd, in->x_csect.x_snhash, ext->x_csect.x_snhash);
+ /* We don't have to hack bitfields in x_smtyp because it's
+ defined by shifts-and-ands, which are equivalent on all
+ byte orders. */
+ PUTBYTE (abfd, in->x_csect.x_smtyp, ext->x_csect.x_smtyp);
+ PUTBYTE (abfd, in->x_csect.x_smclas, ext->x_csect.x_smclas);
+ PUTWORD (abfd, in->x_csect.x_stab, ext->x_csect.x_stab);
+ PUTHALF (abfd, in->x_csect.x_snstab, ext->x_csect.x_snstab);
+ return sizeof (AUXENT);
+ }
+ break;
+#endif
+
+ case C_STAT:
+#ifdef C_LEAFSTAT
+ case C_LEAFSTAT:
+#endif
+ case C_HIDDEN:
+ if (type == T_NULL) {
+ PUT_SCN_SCNLEN(abfd, in->x_scn.x_scnlen, ext);
+ PUT_SCN_NRELOC(abfd, in->x_scn.x_nreloc, ext);
+ PUT_SCN_NLINNO(abfd, in->x_scn.x_nlinno, ext);
+ return sizeof (AUXENT);
+ }
+ break;
+ }
+
+ PUTWORD(abfd, in->x_sym.x_tagndx.l, (bfd_byte *) ext->x_sym.x_tagndx);
+#ifndef NO_TVNDX
+ bfd_h_put_16(abfd, in->x_sym.x_tvndx , (bfd_byte *) ext->x_sym.x_tvndx);
+#endif
+
+ if (class == C_BLOCK || ISFCN(type) || ISTAG(class)) {
+ PUT_FCN_LNNOPTR(abfd, in->x_sym.x_fcnary.x_fcn.x_lnnoptr, ext);
+ PUT_FCN_ENDNDX(abfd, in->x_sym.x_fcnary.x_fcn.x_endndx.l, ext);
+ }
+
+ if (ISFCN(type)) {
+ PUTWORD(abfd, in->x_sym.x_misc.x_fsize, (bfd_byte *) ext->x_sym.x_misc.x_fsize);
+ }
+ else {
+ if (ISARY(type)) {
+#if DIMNUM != E_DIMNUM
+ -> Error, we need to cope with truncating or extending DIMNUM!;
+#else
+ bfd_h_put_16(abfd, in->x_sym.x_fcnary.x_ary.x_dimen[0], (bfd_byte *)ext->x_sym.x_fcnary.x_ary.x_dimen[0]);
+ bfd_h_put_16(abfd, in->x_sym.x_fcnary.x_ary.x_dimen[1], (bfd_byte *)ext->x_sym.x_fcnary.x_ary.x_dimen[1]);
+ bfd_h_put_16(abfd, in->x_sym.x_fcnary.x_ary.x_dimen[2], (bfd_byte *)ext->x_sym.x_fcnary.x_ary.x_dimen[2]);
+ bfd_h_put_16(abfd, in->x_sym.x_fcnary.x_ary.x_dimen[3], (bfd_byte *)ext->x_sym.x_fcnary.x_ary.x_dimen[3]);
+#endif
+ }
+ PUT_LNSZ_LNNO(abfd, in->x_sym.x_misc.x_lnsz.x_lnno, ext);
+ PUT_LNSZ_SIZE(abfd, in->x_sym.x_misc.x_lnsz.x_size, ext);
+ }
+ return sizeof(AUXENT);
+}
+
+#endif /* NO_COFF_SYMBOLS */
+
+#ifndef NO_COFF_LINENOS
+
+static void
+coff_swap_lineno_in (abfd, ext1, in1)
+ bfd *abfd;
+ PTR ext1;
+ PTR in1;
+{
+ LINENO *ext = (LINENO *)ext1;
+ struct internal_lineno *in = (struct internal_lineno *)in1;
+
+ in->l_addr.l_symndx = bfd_h_get_32(abfd, (bfd_byte *) ext->l_addr.l_symndx);
+ in->l_lnno = GET_LINENO_LNNO(abfd, ext);
+}
+
+static unsigned int
+coff_swap_lineno_out (abfd, inp, outp)
+ bfd *abfd;
+ PTR inp;
+ PTR outp;
+{
+ struct internal_lineno *in = (struct internal_lineno *)inp;
+ struct external_lineno *ext = (struct external_lineno *)outp;
+ PUTWORD(abfd, in->l_addr.l_symndx, (bfd_byte *)
+ ext->l_addr.l_symndx);
+
+ PUT_LINENO_LNNO (abfd, in->l_lnno, ext);
+ return sizeof(struct external_lineno);
+}
+
+#endif /* NO_COFF_LINENOS */
+
+
+static void
+coff_swap_aouthdr_in (abfd, aouthdr_ext1, aouthdr_int1)
+ bfd *abfd;
+ PTR aouthdr_ext1;
+ PTR aouthdr_int1;
+{
+ AOUTHDR *aouthdr_ext = (AOUTHDR *) aouthdr_ext1;
+ struct internal_aouthdr *aouthdr_int = (struct internal_aouthdr *)aouthdr_int1;
+
+ aouthdr_int->magic = bfd_h_get_16(abfd, (bfd_byte *) aouthdr_ext->magic);
+ aouthdr_int->vstamp = bfd_h_get_16(abfd, (bfd_byte *) aouthdr_ext->vstamp);
+ aouthdr_int->tsize =
+ GET_AOUTHDR_TSIZE (abfd, (bfd_byte *) aouthdr_ext->tsize);
+ aouthdr_int->dsize =
+ GET_AOUTHDR_DSIZE (abfd, (bfd_byte *) aouthdr_ext->dsize);
+ aouthdr_int->bsize =
+ GET_AOUTHDR_BSIZE (abfd, (bfd_byte *) aouthdr_ext->bsize);
+ aouthdr_int->entry =
+ GET_AOUTHDR_ENTRY (abfd, (bfd_byte *) aouthdr_ext->entry);
+ aouthdr_int->text_start =
+ GET_AOUTHDR_TEXT_START (abfd, (bfd_byte *) aouthdr_ext->text_start);
+ aouthdr_int->data_start =
+ GET_AOUTHDR_DATA_START (abfd, (bfd_byte *) aouthdr_ext->data_start);
+
+#ifdef I960
+ aouthdr_int->tagentries = bfd_h_get_32(abfd, (bfd_byte *) aouthdr_ext->tagentries);
+#endif
+
+#ifdef APOLLO_M68
+ bfd_h_put_32(abfd, aouthdr_int->o_inlib, (bfd_byte *) aouthdr_ext->o_inlib);
+ bfd_h_put_32(abfd, aouthdr_int->o_sri, (bfd_byte *) aouthdr_ext->o_sri);
+ bfd_h_put_32(abfd, aouthdr_int->vid[0], (bfd_byte *) aouthdr_ext->vid);
+ bfd_h_put_32(abfd, aouthdr_int->vid[1], (bfd_byte *) aouthdr_ext->vid + 4);
+#endif
+
+
+#ifdef RS6000COFF_C
+ aouthdr_int->o_toc = bfd_h_get_32(abfd, aouthdr_ext->o_toc);
+ aouthdr_int->o_snentry = bfd_h_get_16(abfd, aouthdr_ext->o_snentry);
+ aouthdr_int->o_sntext = bfd_h_get_16(abfd, aouthdr_ext->o_sntext);
+ aouthdr_int->o_sndata = bfd_h_get_16(abfd, aouthdr_ext->o_sndata);
+ aouthdr_int->o_sntoc = bfd_h_get_16(abfd, aouthdr_ext->o_sntoc);
+ aouthdr_int->o_snloader = bfd_h_get_16(abfd, aouthdr_ext->o_snloader);
+ aouthdr_int->o_snbss = bfd_h_get_16(abfd, aouthdr_ext->o_snbss);
+ aouthdr_int->o_algntext = bfd_h_get_16(abfd, aouthdr_ext->o_algntext);
+ aouthdr_int->o_algndata = bfd_h_get_16(abfd, aouthdr_ext->o_algndata);
+ aouthdr_int->o_modtype = bfd_h_get_16(abfd, aouthdr_ext->o_modtype);
+ aouthdr_int->o_maxstack = bfd_h_get_32(abfd, aouthdr_ext->o_maxstack);
+#endif
+
+#ifdef MIPSECOFF
+ aouthdr_int->bss_start = bfd_h_get_32(abfd, aouthdr_ext->bss_start);
+ aouthdr_int->gp_value = bfd_h_get_32(abfd, aouthdr_ext->gp_value);
+ aouthdr_int->gprmask = bfd_h_get_32(abfd, aouthdr_ext->gprmask);
+ aouthdr_int->cprmask[0] = bfd_h_get_32(abfd, aouthdr_ext->cprmask[0]);
+ aouthdr_int->cprmask[1] = bfd_h_get_32(abfd, aouthdr_ext->cprmask[1]);
+ aouthdr_int->cprmask[2] = bfd_h_get_32(abfd, aouthdr_ext->cprmask[2]);
+ aouthdr_int->cprmask[3] = bfd_h_get_32(abfd, aouthdr_ext->cprmask[3]);
+#endif
+
+#ifdef ALPHAECOFF
+ aouthdr_int->bss_start = bfd_h_get_64(abfd, aouthdr_ext->bss_start);
+ aouthdr_int->gp_value = bfd_h_get_64(abfd, aouthdr_ext->gp_value);
+ aouthdr_int->gprmask = bfd_h_get_32(abfd, aouthdr_ext->gprmask);
+ aouthdr_int->fprmask = bfd_h_get_32(abfd, aouthdr_ext->fprmask);
+#endif
+}
+
+static unsigned int
+coff_swap_aouthdr_out (abfd, in, out)
+ bfd *abfd;
+ PTR in;
+ PTR out;
+{
+ struct internal_aouthdr *aouthdr_in = (struct internal_aouthdr *)in;
+ AOUTHDR *aouthdr_out = (AOUTHDR *)out;
+
+ bfd_h_put_16(abfd, aouthdr_in->magic, (bfd_byte *) aouthdr_out->magic);
+ bfd_h_put_16(abfd, aouthdr_in->vstamp, (bfd_byte *) aouthdr_out->vstamp);
+ PUT_AOUTHDR_TSIZE (abfd, aouthdr_in->tsize, (bfd_byte *) aouthdr_out->tsize);
+ PUT_AOUTHDR_DSIZE (abfd, aouthdr_in->dsize, (bfd_byte *) aouthdr_out->dsize);
+ PUT_AOUTHDR_BSIZE (abfd, aouthdr_in->bsize, (bfd_byte *) aouthdr_out->bsize);
+ PUT_AOUTHDR_ENTRY (abfd, aouthdr_in->entry, (bfd_byte *) aouthdr_out->entry);
+ PUT_AOUTHDR_TEXT_START (abfd, aouthdr_in->text_start,
+ (bfd_byte *) aouthdr_out->text_start);
+ PUT_AOUTHDR_DATA_START (abfd, aouthdr_in->data_start,
+ (bfd_byte *) aouthdr_out->data_start);
+#ifdef I960
+ bfd_h_put_32(abfd, aouthdr_in->tagentries, (bfd_byte *) aouthdr_out->tagentries);
+#endif
+
+#ifdef MIPSECOFF
+ bfd_h_put_32(abfd, aouthdr_in->bss_start, (bfd_byte *) aouthdr_out->bss_start);
+ bfd_h_put_32(abfd, aouthdr_in->gp_value, (bfd_byte *) aouthdr_out->gp_value);
+ bfd_h_put_32(abfd, aouthdr_in->gprmask, (bfd_byte *) aouthdr_out->gprmask);
+ bfd_h_put_32(abfd, aouthdr_in->cprmask[0], (bfd_byte *) aouthdr_out->cprmask[0]);
+ bfd_h_put_32(abfd, aouthdr_in->cprmask[1], (bfd_byte *) aouthdr_out->cprmask[1]);
+ bfd_h_put_32(abfd, aouthdr_in->cprmask[2], (bfd_byte *) aouthdr_out->cprmask[2]);
+ bfd_h_put_32(abfd, aouthdr_in->cprmask[3], (bfd_byte *) aouthdr_out->cprmask[3]);
+#endif
+
+#ifdef ALPHAECOFF
+ /* FIXME: What does bldrev mean? */
+ bfd_h_put_16(abfd, (bfd_vma) 2, (bfd_byte *) aouthdr_out->bldrev);
+ bfd_h_put_16(abfd, (bfd_vma) 0, (bfd_byte *) aouthdr_out->padding);
+ bfd_h_put_64(abfd, aouthdr_in->bss_start, (bfd_byte *) aouthdr_out->bss_start);
+ bfd_h_put_64(abfd, aouthdr_in->gp_value, (bfd_byte *) aouthdr_out->gp_value);
+ bfd_h_put_32(abfd, aouthdr_in->gprmask, (bfd_byte *) aouthdr_out->gprmask);
+ bfd_h_put_32(abfd, aouthdr_in->fprmask, (bfd_byte *) aouthdr_out->fprmask);
+#endif
+
+ return sizeof(AOUTHDR);
+}
+
+static void
+coff_swap_scnhdr_in (abfd, ext, in)
+ bfd *abfd;
+ PTR ext;
+ PTR in;
+{
+ SCNHDR *scnhdr_ext = (SCNHDR *) ext;
+ struct internal_scnhdr *scnhdr_int = (struct internal_scnhdr *) in;
+
+ memcpy(scnhdr_int->s_name, scnhdr_ext->s_name, sizeof(scnhdr_int->s_name));
+ scnhdr_int->s_vaddr =
+ GET_SCNHDR_VADDR (abfd, (bfd_byte *) scnhdr_ext->s_vaddr);
+ scnhdr_int->s_paddr =
+ GET_SCNHDR_PADDR (abfd, (bfd_byte *) scnhdr_ext->s_paddr);
+ scnhdr_int->s_size =
+ GET_SCNHDR_SIZE (abfd, (bfd_byte *) scnhdr_ext->s_size);
+
+ scnhdr_int->s_scnptr =
+ GET_SCNHDR_SCNPTR (abfd, (bfd_byte *) scnhdr_ext->s_scnptr);
+ scnhdr_int->s_relptr =
+ GET_SCNHDR_RELPTR (abfd, (bfd_byte *) scnhdr_ext->s_relptr);
+ scnhdr_int->s_lnnoptr =
+ GET_SCNHDR_LNNOPTR (abfd, (bfd_byte *) scnhdr_ext->s_lnnoptr);
+ scnhdr_int->s_flags = bfd_h_get_32(abfd, (bfd_byte *) scnhdr_ext->s_flags);
+#if defined(M88)
+ scnhdr_int->s_nreloc = bfd_h_get_32(abfd, (bfd_byte *) scnhdr_ext->s_nreloc);
+ scnhdr_int->s_nlnno = bfd_h_get_32(abfd, (bfd_byte *) scnhdr_ext->s_nlnno);
+#else
+ scnhdr_int->s_nreloc = bfd_h_get_16(abfd, (bfd_byte *) scnhdr_ext->s_nreloc);
+ scnhdr_int->s_nlnno = bfd_h_get_16(abfd, (bfd_byte *) scnhdr_ext->s_nlnno);
+#endif
+#ifdef I960
+ scnhdr_int->s_align = bfd_h_get_32(abfd, (bfd_byte *) scnhdr_ext->s_align);
+#endif
+}
+
+static unsigned int
+coff_swap_scnhdr_out (abfd, in, out)
+ bfd *abfd;
+ PTR in;
+ PTR out;
+{
+ struct internal_scnhdr *scnhdr_int = (struct internal_scnhdr *)in;
+ SCNHDR *scnhdr_ext = (SCNHDR *)out;
+
+ memcpy(scnhdr_ext->s_name, scnhdr_int->s_name, sizeof(scnhdr_int->s_name));
+ PUT_SCNHDR_VADDR (abfd, scnhdr_int->s_vaddr,
+ (bfd_byte *) scnhdr_ext->s_vaddr);
+ PUT_SCNHDR_PADDR (abfd, scnhdr_int->s_paddr,
+ (bfd_byte *) scnhdr_ext->s_paddr);
+ PUT_SCNHDR_SIZE (abfd, scnhdr_int->s_size,
+ (bfd_byte *) scnhdr_ext->s_size);
+ PUT_SCNHDR_SCNPTR (abfd, scnhdr_int->s_scnptr,
+ (bfd_byte *) scnhdr_ext->s_scnptr);
+ PUT_SCNHDR_RELPTR (abfd, scnhdr_int->s_relptr,
+ (bfd_byte *) scnhdr_ext->s_relptr);
+ PUT_SCNHDR_LNNOPTR (abfd, scnhdr_int->s_lnnoptr,
+ (bfd_byte *) scnhdr_ext->s_lnnoptr);
+ PUTWORD(abfd, scnhdr_int->s_flags, (bfd_byte *) scnhdr_ext->s_flags);
+#if defined(M88)
+ PUTWORD(abfd, scnhdr_int->s_nlnno, (bfd_byte *) scnhdr_ext->s_nlnno);
+ PUTWORD(abfd, scnhdr_int->s_nreloc, (bfd_byte *) scnhdr_ext->s_nreloc);
+#else
+ PUTHALF(abfd, scnhdr_int->s_nlnno, (bfd_byte *) scnhdr_ext->s_nlnno);
+ PUTHALF(abfd, scnhdr_int->s_nreloc, (bfd_byte *) scnhdr_ext->s_nreloc);
+#endif
+
+#if defined(I960)
+ PUTWORD(abfd, scnhdr_int->s_align, (bfd_byte *) scnhdr_ext->s_align);
+#endif
+ return sizeof(SCNHDR);
+}
diff --git a/gnu/usr.bin/gdb/bfd/core.c b/gnu/usr.bin/gdb/bfd/core.c
new file mode 100644
index 0000000..5d88a49
--- /dev/null
+++ b/gnu/usr.bin/gdb/bfd/core.c
@@ -0,0 +1,106 @@
+/* Core file generic interface routines for BFD.
+ Copyright (C) 1990, 91, 92, 93, 94 Free Software Foundation, Inc.
+ Written by Cygnus Support.
+
+This file is part of BFD, the Binary File Descriptor library.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/*
+SECTION
+ Core files
+
+DESCRIPTION
+ These are functions pertaining to core files.
+*/
+
+#include "bfd.h"
+#include "sysdep.h"
+#include "libbfd.h"
+
+
+/*
+FUNCTION
+ bfd_core_file_failing_command
+
+SYNOPSIS
+ CONST char *bfd_core_file_failing_command(bfd *abfd);
+
+DESCRIPTION
+ Return a read-only string explaining which program was running
+ when it failed and produced the core file @var{abfd}.
+
+*/
+
+CONST char *
+bfd_core_file_failing_command (abfd)
+ bfd *abfd;
+{
+ if (abfd->format != bfd_core) {
+ bfd_set_error (bfd_error_invalid_operation);
+ return NULL;
+ }
+ return BFD_SEND (abfd, _core_file_failing_command, (abfd));
+}
+
+/*
+FUNCTION
+ bfd_core_file_failing_signal
+
+SYNOPSIS
+ int bfd_core_file_failing_signal(bfd *abfd);
+
+DESCRIPTION
+ Returns the signal number which caused the core dump which
+ generated the file the BFD @var{abfd} is attached to.
+*/
+
+int
+bfd_core_file_failing_signal (abfd)
+ bfd *abfd;
+{
+ if (abfd->format != bfd_core) {
+ bfd_set_error (bfd_error_invalid_operation);
+ return 0;
+ }
+ return BFD_SEND (abfd, _core_file_failing_signal, (abfd));
+}
+
+
+/*
+FUNCTION
+ core_file_matches_executable_p
+
+SYNOPSIS
+ boolean core_file_matches_executable_p
+ (bfd *core_bfd, bfd *exec_bfd);
+
+DESCRIPTION
+ Return <<true>> if the core file attached to @var{core_bfd}
+ was generated by a run of the executable file attached to
+ @var{exec_bfd}, <<false>> otherwise.
+*/
+boolean
+core_file_matches_executable_p (core_bfd, exec_bfd)
+ bfd *core_bfd, *exec_bfd;
+{
+ if ((core_bfd->format != bfd_core) || (exec_bfd->format != bfd_object)) {
+ bfd_set_error (bfd_error_wrong_format);
+ return false;
+ }
+
+ return BFD_SEND (core_bfd, _core_file_matches_executable_p,
+ (core_bfd, exec_bfd));
+}
diff --git a/gnu/usr.bin/gdb/bfd/cpu-i386.c b/gnu/usr.bin/gdb/bfd/cpu-i386.c
new file mode 100644
index 0000000..bf67df2
--- /dev/null
+++ b/gnu/usr.bin/gdb/bfd/cpu-i386.c
@@ -0,0 +1,44 @@
+/* BFD support for the Intel 386 architecture.
+ Copyright 1992 Free Software Foundation, Inc.
+
+This file is part of BFD, the Binary File Descriptor library.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "bfd.h"
+#include "sysdep.h"
+#include "libbfd.h"
+
+static bfd_arch_info_type arch_info_struct =
+ {
+ 32, /* 32 bits in a word */
+ 32, /* 32 bits in an address */
+ 8, /* 8 bits in a byte */
+ bfd_arch_i386,
+ 0, /* only 1 machine */
+ "i386",
+ "i386",
+ 3,
+ true, /* the one and only */
+ bfd_default_compatible,
+ bfd_default_scan ,
+ 0,
+ };
+
+void
+bfd_i386_arch ()
+{
+ bfd_arch_linkin(&arch_info_struct);
+}
diff --git a/gnu/usr.bin/gdb/bfd/ctor.c b/gnu/usr.bin/gdb/bfd/ctor.c
new file mode 100644
index 0000000..c9c2e32
--- /dev/null
+++ b/gnu/usr.bin/gdb/bfd/ctor.c
@@ -0,0 +1,155 @@
+/* BFD library support routines for constructors
+ Copyright (C) 1990, 91, 92, 93, 94 Free Software Foundation, Inc.
+
+ Hacked by Steve Chamberlain of Cygnus Support. With some help from
+ Judy Chamberlain too.
+
+
+This file is part of BFD, the Binary File Descriptor library.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/*
+SECTION
+ Constructors
+
+ Classes in C++ have @dfn{constructors} and @dfn{destructors}. These
+ are functions which are called automatically by the language
+ whenever data of a class is created or destroyed. Class data
+ which is static may also be have a type which requires
+ `construction'; the contructor must be called before the data
+ can be referenced, so the contructor must be called before the
+ program begins.
+
+ The common solution to this problem is for the compiler to
+ call a magic function as the first statement before <<main>>.
+ This magic function (often called <<__main>>) runs around
+ calling the constructors for all the things needing it.
+
+ With COFF, the compiler has a bargain with the linker et al.
+ All constructors are given strange names; for example,
+ <<__GLOBAL__$I$foo>> might be the label of a contructor for
+ the class @var{foo}. The solution on unfortunate systems
+ (most System V machines) is to perform a partial link on all
+ the <<.o>> files, do an <<nm>> on the result, run <<awk>> or some
+ such over the result looking for strange <<__GLOBAL__$>>
+ symbols, generate a C program from this, compile it, and link
+ with the partially linked input. This process is usually
+ called <<collect>>.
+
+ Some versions of <<a.out>> use something called the
+ <<set_vector>> mechanism. The constructor symbols are output
+ from the compiler with a special stab code saying that they
+ are constructors, and the linker can deal with them directly.
+
+ BFD allows applications (i.e., the linker) to deal with
+ constructor information independently of their external
+ implementation by providing a set of entry points for the
+ indiviual object back ends to call to maintain a database
+ of the contructor information. The application can
+ interrogate the database to find out what it wants. The
+ construction data essential for the linker to be able to
+ perform its job are:
+
+ o asymbol -
+ The asymbol of the contructor entry point contains all the
+ information necessary to call the function.
+
+ o table id -
+ The type of symbol, i.e., is it a constructor, a destructor or
+ something else someone dreamed up to make our lives difficult.
+
+ The constructor module takes this information and builds extra
+ sections attached to the BFDs which own the entry points. It
+ creates these sections as if they were tables of pointers to
+ the entry points, and builds relocation entries to go with
+ them so that the tables can be relocated along with the data
+ they reference.
+
+ These sections are marked with a special bit
+ (<<SEC_CONSTRUCTOR>>), which the linker notices and does with
+ what it wants.
+
+*/
+
+#include <bfd.h>
+#include <sysdep.h>
+#include <libbfd.h>
+
+
+
+/*
+INTERNAL_FUNCTION
+ bfd_constructor_entry
+
+SYNOPSIS
+ boolean bfd_constructor_entry(bfd *abfd,
+ asymbol **symbol_ptr_ptr,
+ CONST char*type);
+
+
+DESCRIPTION
+ @var{symbol_ptr_ptr} describes the
+ function to be called; @var{type} descibes the xtor type,
+ e.g., something like "CTOR" or "DTOR" would be fine. @var{abfd}
+ is the BFD which owns the function. Create a section
+ called "CTOR" or "DTOR" or whatever if the BFD doesn't already
+ have one, and grow a relocation table for the entry points as
+ they accumulate.
+
+ Return <<true>> if successful, <<false>> if out of memory.
+
+*/
+
+
+boolean
+bfd_constructor_entry (abfd, symbol_ptr_ptr, type)
+ bfd *abfd;
+ asymbol **symbol_ptr_ptr;
+ CONST char *type;
+{
+ /* Look up the section we're using to store the table in */
+ asection *rel_section = bfd_get_section_by_name (abfd, type);
+ if (rel_section == (asection *)NULL) {
+ rel_section = bfd_make_section (abfd, type);
+ rel_section->flags = SEC_CONSTRUCTOR;
+ rel_section->alignment_power = 2;
+ }
+
+ /* Create a relocation into the section which references the entry
+ point */
+ {
+ arelent_chain *reloc = (arelent_chain *)bfd_alloc(abfd,
+ sizeof(arelent_chain));
+ if (!reloc)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ return false;
+ }
+
+/* reloc->relent.section = (asection *)NULL;*/
+ reloc->relent.addend = 0;
+
+ reloc->relent.sym_ptr_ptr = symbol_ptr_ptr;
+ reloc->next = rel_section->constructor_chain;
+ rel_section->constructor_chain = reloc;
+ reloc->relent.address = rel_section->_cooked_size;
+ /* ask the cpu which howto to use */
+ reloc->relent.howto = bfd_reloc_type_lookup(abfd, BFD_RELOC_CTOR);
+ rel_section->_cooked_size += sizeof(int *);
+ rel_section->reloc_count++;
+ }
+ return true;
+}
diff --git a/gnu/usr.bin/gdb/bfd/ecoff.c b/gnu/usr.bin/gdb/bfd/ecoff.c
new file mode 100644
index 0000000..ca71e7e
--- /dev/null
+++ b/gnu/usr.bin/gdb/bfd/ecoff.c
@@ -0,0 +1,4953 @@
+/* Generic ECOFF (Extended-COFF) routines.
+ Copyright 1990, 1991, 1992, 1993 Free Software Foundation, Inc.
+ Original version by Per Bothner.
+ Full support added by Ian Lance Taylor, ian@cygnus.com.
+
+This file is part of BFD, the Binary File Descriptor library.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "bfd.h"
+#include "sysdep.h"
+#include "bfdlink.h"
+#include "libbfd.h"
+#include "aout/ar.h"
+#include "aout/ranlib.h"
+
+/* FIXME: We need the definitions of N_SET[ADTB], but aout64.h defines
+ some other stuff which we don't want and which conflicts with stuff
+ we do want. */
+#include "libaout.h"
+#include "aout/aout64.h"
+#undef N_ABS
+#undef exec_hdr
+#undef obj_sym_filepos
+
+#include "coff/internal.h"
+#include "coff/sym.h"
+#include "coff/symconst.h"
+#include "coff/ecoff.h"
+#include "libcoff.h"
+#include "libecoff.h"
+
+/* Prototypes for static functions. */
+
+static int ecoff_get_magic PARAMS ((bfd *abfd));
+static long ecoff_sec_to_styp_flags PARAMS ((const char *name,
+ flagword flags));
+static boolean ecoff_slurp_symbolic_header PARAMS ((bfd *abfd));
+static boolean ecoff_set_symbol_info PARAMS ((bfd *abfd, SYMR *ecoff_sym,
+ asymbol *asym, int ext,
+ asymbol **indirect_ptr_ptr));
+static void ecoff_emit_aggregate PARAMS ((bfd *abfd, FDR *fdr,
+ char *string,
+ RNDXR *rndx, long isym,
+ const char *which));
+static char *ecoff_type_to_string PARAMS ((bfd *abfd, FDR *fdr,
+ unsigned int indx));
+static boolean ecoff_slurp_reloc_table PARAMS ((bfd *abfd, asection *section,
+ asymbol **symbols));
+static void ecoff_compute_section_file_positions PARAMS ((bfd *abfd));
+static bfd_size_type ecoff_compute_reloc_file_positions PARAMS ((bfd *abfd));
+static boolean ecoff_get_extr PARAMS ((asymbol *, EXTR *));
+static void ecoff_set_index PARAMS ((asymbol *, bfd_size_type));
+static unsigned int ecoff_armap_hash PARAMS ((CONST char *s,
+ unsigned int *rehash,
+ unsigned int size,
+ unsigned int hlog));
+
+/* This stuff is somewhat copied from coffcode.h. */
+
+static asection bfd_debug_section = { "*DEBUG*" };
+
+/* Create an ECOFF object. */
+
+boolean
+_bfd_ecoff_mkobject (abfd)
+ bfd *abfd;
+{
+ abfd->tdata.ecoff_obj_data = ((struct ecoff_tdata *)
+ bfd_zalloc (abfd, sizeof (ecoff_data_type)));
+ if (abfd->tdata.ecoff_obj_data == NULL)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ return false;
+ }
+
+ return true;
+}
+
+/* This is a hook called by coff_real_object_p to create any backend
+ specific information. */
+
+PTR
+_bfd_ecoff_mkobject_hook (abfd, filehdr, aouthdr)
+ bfd *abfd;
+ PTR filehdr;
+ PTR aouthdr;
+{
+ struct internal_filehdr *internal_f = (struct internal_filehdr *) filehdr;
+ struct internal_aouthdr *internal_a = (struct internal_aouthdr *) aouthdr;
+ ecoff_data_type *ecoff;
+
+ if (_bfd_ecoff_mkobject (abfd) == false)
+ return NULL;
+
+ ecoff = ecoff_data (abfd);
+ ecoff->gp_size = 8;
+ ecoff->sym_filepos = internal_f->f_symptr;
+
+ if (internal_a != (struct internal_aouthdr *) NULL)
+ {
+ int i;
+
+ ecoff->text_start = internal_a->text_start;
+ ecoff->text_end = internal_a->text_start + internal_a->tsize;
+ ecoff->gp = internal_a->gp_value;
+ ecoff->gprmask = internal_a->gprmask;
+ for (i = 0; i < 4; i++)
+ ecoff->cprmask[i] = internal_a->cprmask[i];
+ ecoff->fprmask = internal_a->fprmask;
+ if (internal_a->magic == ECOFF_AOUT_ZMAGIC)
+ abfd->flags |= D_PAGED;
+ }
+
+ /* It turns out that no special action is required by the MIPS or
+ Alpha ECOFF backends. They have different information in the
+ a.out header, but we just copy it all (e.g., gprmask, cprmask and
+ fprmask) and let the swapping routines ensure that only relevant
+ information is written out. */
+
+ return (PTR) ecoff;
+}
+
+/* This is a hook needed by SCO COFF, but we have nothing to do. */
+
+/*ARGSUSED*/
+asection *
+_bfd_ecoff_make_section_hook (abfd, name)
+ bfd *abfd;
+ char *name;
+{
+ return (asection *) NULL;
+}
+
+/* Initialize a new section. */
+
+boolean
+_bfd_ecoff_new_section_hook (abfd, section)
+ bfd *abfd;
+ asection *section;
+{
+ /* For the .pdata section, which has a special meaning on the Alpha,
+ we set the alignment to 8. We correct this later in
+ ecoff_compute_section_file_positions. We do this hackery because
+ we need to know the exact unaligned size of the .pdata section in
+ order to set the lnnoptr field correctly. */
+ if (strcmp (section->name, _PDATA) == 0)
+ section->alignment_power = 3;
+ else
+ section->alignment_power = abfd->xvec->align_power_min;
+
+ if (strcmp (section->name, _TEXT) == 0)
+ section->flags |= SEC_CODE | SEC_LOAD | SEC_ALLOC;
+ else if (strcmp (section->name, _DATA) == 0
+ || strcmp (section->name, _SDATA) == 0)
+ section->flags |= SEC_DATA | SEC_LOAD | SEC_ALLOC;
+ else if (strcmp (section->name, _RDATA) == 0
+ || strcmp (section->name, _LIT8) == 0
+ || strcmp (section->name, _LIT4) == 0)
+ section->flags |= SEC_DATA | SEC_LOAD | SEC_ALLOC | SEC_READONLY;
+ else if (strcmp (section->name, _BSS) == 0
+ || strcmp (section->name, _SBSS) == 0)
+ section->flags |= SEC_ALLOC;
+ else if (strcmp (section->name, _LIB) == 0)
+ {
+ /* An Irix 4 shared libary. */
+ section->flags |= SEC_COFF_SHARED_LIBRARY;
+ }
+
+ /* Probably any other section name is SEC_NEVER_LOAD, but I'm
+ uncertain about .init on some systems and I don't know how shared
+ libraries work. */
+
+ return true;
+}
+
+/* Determine the machine architecture and type. This is called from
+ the generic COFF routines. It is the inverse of ecoff_get_magic,
+ below. This could be an ECOFF backend routine, with one version
+ for each target, but there aren't all that many ECOFF targets. */
+
+boolean
+_bfd_ecoff_set_arch_mach_hook (abfd, filehdr)
+ bfd *abfd;
+ PTR filehdr;
+{
+ struct internal_filehdr *internal_f = (struct internal_filehdr *) filehdr;
+ enum bfd_architecture arch;
+ unsigned long mach;
+
+ switch (internal_f->f_magic)
+ {
+ case MIPS_MAGIC_1:
+ case MIPS_MAGIC_LITTLE:
+ case MIPS_MAGIC_BIG:
+ arch = bfd_arch_mips;
+ mach = 3000;
+ break;
+
+ case MIPS_MAGIC_LITTLE2:
+ case MIPS_MAGIC_BIG2:
+ /* MIPS ISA level 2: the r6000 */
+ arch = bfd_arch_mips;
+ mach = 6000;
+ break;
+
+ case MIPS_MAGIC_LITTLE3:
+ case MIPS_MAGIC_BIG3:
+ /* MIPS ISA level 3: the r4000 */
+ arch = bfd_arch_mips;
+ mach = 4000;
+ break;
+
+ case ALPHA_MAGIC:
+ arch = bfd_arch_alpha;
+ mach = 0;
+ break;
+
+ default:
+ arch = bfd_arch_obscure;
+ mach = 0;
+ break;
+ }
+
+ return bfd_default_set_arch_mach (abfd, arch, mach);
+}
+
+/* Get the magic number to use based on the architecture and machine.
+ This is the inverse of _bfd_ecoff_set_arch_mach_hook, above. */
+
+static int
+ecoff_get_magic (abfd)
+ bfd *abfd;
+{
+ int big, little;
+
+ switch (bfd_get_arch (abfd))
+ {
+ case bfd_arch_mips:
+ switch (bfd_get_mach (abfd))
+ {
+ default:
+ case 0:
+ case 3000:
+ big = MIPS_MAGIC_BIG;
+ little = MIPS_MAGIC_LITTLE;
+ break;
+
+ case 6000:
+ big = MIPS_MAGIC_BIG2;
+ little = MIPS_MAGIC_LITTLE2;
+ break;
+
+ case 4000:
+ big = MIPS_MAGIC_BIG3;
+ little = MIPS_MAGIC_LITTLE3;
+ break;
+ }
+
+ return abfd->xvec->byteorder_big_p ? big : little;
+
+ case bfd_arch_alpha:
+ return ALPHA_MAGIC;
+
+ default:
+ abort ();
+ return 0;
+ }
+}
+
+/* Get the section s_flags to use for a section. */
+
+static long
+ecoff_sec_to_styp_flags (name, flags)
+ const char *name;
+ flagword flags;
+{
+ long styp;
+
+ styp = 0;
+
+ if (strcmp (name, _TEXT) == 0)
+ styp = STYP_TEXT;
+ else if (strcmp (name, _DATA) == 0)
+ styp = STYP_DATA;
+ else if (strcmp (name, _SDATA) == 0)
+ styp = STYP_SDATA;
+ else if (strcmp (name, _RDATA) == 0)
+ styp = STYP_RDATA;
+ else if (strcmp (name, _LITA) == 0)
+ styp = STYP_LITA;
+ else if (strcmp (name, _LIT8) == 0)
+ styp = STYP_LIT8;
+ else if (strcmp (name, _LIT4) == 0)
+ styp = STYP_LIT4;
+ else if (strcmp (name, _BSS) == 0)
+ styp = STYP_BSS;
+ else if (strcmp (name, _SBSS) == 0)
+ styp = STYP_SBSS;
+ else if (strcmp (name, _INIT) == 0)
+ styp = STYP_ECOFF_INIT;
+ else if (strcmp (name, _FINI) == 0)
+ styp = STYP_ECOFF_FINI;
+ else if (strcmp (name, _PDATA) == 0)
+ styp = STYP_PDATA;
+ else if (strcmp (name, _XDATA) == 0)
+ styp = STYP_XDATA;
+ else if (strcmp (name, _LIB) == 0)
+ styp = STYP_ECOFF_LIB;
+ else if (flags & SEC_CODE)
+ styp = STYP_TEXT;
+ else if (flags & SEC_DATA)
+ styp = STYP_DATA;
+ else if (flags & SEC_READONLY)
+ styp = STYP_RDATA;
+ else if (flags & SEC_LOAD)
+ styp = STYP_REG;
+ else
+ styp = STYP_BSS;
+
+ if (flags & SEC_NEVER_LOAD)
+ styp |= STYP_NOLOAD;
+
+ return styp;
+}
+
+/* Get the BFD flags to use for a section. */
+
+/*ARGSUSED*/
+flagword
+_bfd_ecoff_styp_to_sec_flags (abfd, hdr)
+ bfd *abfd;
+ PTR hdr;
+{
+ struct internal_scnhdr *internal_s = (struct internal_scnhdr *) hdr;
+ long styp_flags = internal_s->s_flags;
+ flagword sec_flags=0;
+
+ if (styp_flags & STYP_NOLOAD)
+ sec_flags |= SEC_NEVER_LOAD;
+
+ /* For 386 COFF, at least, an unloadable text or data section is
+ actually a shared library section. */
+ if ((styp_flags & STYP_TEXT)
+ || (styp_flags & STYP_ECOFF_INIT)
+ || (styp_flags & STYP_ECOFF_FINI))
+ {
+ if (sec_flags & SEC_NEVER_LOAD)
+ sec_flags |= SEC_CODE | SEC_COFF_SHARED_LIBRARY;
+ else
+ sec_flags |= SEC_CODE | SEC_LOAD | SEC_ALLOC;
+ }
+ else if ((styp_flags & STYP_DATA)
+ || (styp_flags & STYP_RDATA)
+ || (styp_flags & STYP_SDATA)
+ || styp_flags == STYP_PDATA
+ || styp_flags == STYP_XDATA)
+ {
+ if (sec_flags & SEC_NEVER_LOAD)
+ sec_flags |= SEC_DATA | SEC_COFF_SHARED_LIBRARY;
+ else
+ sec_flags |= SEC_DATA | SEC_LOAD | SEC_ALLOC;
+ if ((styp_flags & STYP_RDATA)
+ || styp_flags == STYP_PDATA)
+ sec_flags |= SEC_READONLY;
+ }
+ else if ((styp_flags & STYP_BSS)
+ || (styp_flags & STYP_SBSS))
+ {
+ sec_flags |= SEC_ALLOC;
+ }
+ else if ((styp_flags & STYP_INFO) || styp_flags == STYP_COMMENT)
+ {
+ sec_flags |= SEC_NEVER_LOAD;
+ }
+ else if ((styp_flags & STYP_LITA)
+ || (styp_flags & STYP_LIT8)
+ || (styp_flags & STYP_LIT4))
+ {
+ sec_flags |= SEC_DATA | SEC_LOAD | SEC_ALLOC | SEC_READONLY;
+ }
+ else if (styp_flags & STYP_ECOFF_LIB)
+ {
+ sec_flags |= SEC_COFF_SHARED_LIBRARY;
+ }
+ else
+ {
+ sec_flags |= SEC_ALLOC | SEC_LOAD;
+ }
+
+ return sec_flags;
+}
+
+/* Routines to swap auxiliary information in and out. I am assuming
+ that the auxiliary information format is always going to be target
+ independent. */
+
+/* Swap in a type information record.
+ BIGEND says whether AUX symbols are big-endian or little-endian; this
+ info comes from the file header record (fh-fBigendian). */
+
+void
+_bfd_ecoff_swap_tir_in (bigend, ext_copy, intern)
+ int bigend;
+ const struct tir_ext *ext_copy;
+ TIR *intern;
+{
+ struct tir_ext ext[1];
+
+ *ext = *ext_copy; /* Make it reasonable to do in-place. */
+
+ /* now the fun stuff... */
+ if (bigend) {
+ intern->fBitfield = 0 != (ext->t_bits1[0] & TIR_BITS1_FBITFIELD_BIG);
+ intern->continued = 0 != (ext->t_bits1[0] & TIR_BITS1_CONTINUED_BIG);
+ intern->bt = (ext->t_bits1[0] & TIR_BITS1_BT_BIG)
+ >> TIR_BITS1_BT_SH_BIG;
+ intern->tq4 = (ext->t_tq45[0] & TIR_BITS_TQ4_BIG)
+ >> TIR_BITS_TQ4_SH_BIG;
+ intern->tq5 = (ext->t_tq45[0] & TIR_BITS_TQ5_BIG)
+ >> TIR_BITS_TQ5_SH_BIG;
+ intern->tq0 = (ext->t_tq01[0] & TIR_BITS_TQ0_BIG)
+ >> TIR_BITS_TQ0_SH_BIG;
+ intern->tq1 = (ext->t_tq01[0] & TIR_BITS_TQ1_BIG)
+ >> TIR_BITS_TQ1_SH_BIG;
+ intern->tq2 = (ext->t_tq23[0] & TIR_BITS_TQ2_BIG)
+ >> TIR_BITS_TQ2_SH_BIG;
+ intern->tq3 = (ext->t_tq23[0] & TIR_BITS_TQ3_BIG)
+ >> TIR_BITS_TQ3_SH_BIG;
+ } else {
+ intern->fBitfield = 0 != (ext->t_bits1[0] & TIR_BITS1_FBITFIELD_LITTLE);
+ intern->continued = 0 != (ext->t_bits1[0] & TIR_BITS1_CONTINUED_LITTLE);
+ intern->bt = (ext->t_bits1[0] & TIR_BITS1_BT_LITTLE)
+ >> TIR_BITS1_BT_SH_LITTLE;
+ intern->tq4 = (ext->t_tq45[0] & TIR_BITS_TQ4_LITTLE)
+ >> TIR_BITS_TQ4_SH_LITTLE;
+ intern->tq5 = (ext->t_tq45[0] & TIR_BITS_TQ5_LITTLE)
+ >> TIR_BITS_TQ5_SH_LITTLE;
+ intern->tq0 = (ext->t_tq01[0] & TIR_BITS_TQ0_LITTLE)
+ >> TIR_BITS_TQ0_SH_LITTLE;
+ intern->tq1 = (ext->t_tq01[0] & TIR_BITS_TQ1_LITTLE)
+ >> TIR_BITS_TQ1_SH_LITTLE;
+ intern->tq2 = (ext->t_tq23[0] & TIR_BITS_TQ2_LITTLE)
+ >> TIR_BITS_TQ2_SH_LITTLE;
+ intern->tq3 = (ext->t_tq23[0] & TIR_BITS_TQ3_LITTLE)
+ >> TIR_BITS_TQ3_SH_LITTLE;
+ }
+
+#ifdef TEST
+ if (memcmp ((char *)ext, (char *)intern, sizeof (*intern)) != 0)
+ abort();
+#endif
+}
+
+/* Swap out a type information record.
+ BIGEND says whether AUX symbols are big-endian or little-endian; this
+ info comes from the file header record (fh-fBigendian). */
+
+void
+_bfd_ecoff_swap_tir_out (bigend, intern_copy, ext)
+ int bigend;
+ const TIR *intern_copy;
+ struct tir_ext *ext;
+{
+ TIR intern[1];
+
+ *intern = *intern_copy; /* Make it reasonable to do in-place. */
+
+ /* now the fun stuff... */
+ if (bigend) {
+ ext->t_bits1[0] = ((intern->fBitfield ? TIR_BITS1_FBITFIELD_BIG : 0)
+ | (intern->continued ? TIR_BITS1_CONTINUED_BIG : 0)
+ | ((intern->bt << TIR_BITS1_BT_SH_BIG)
+ & TIR_BITS1_BT_BIG));
+ ext->t_tq45[0] = (((intern->tq4 << TIR_BITS_TQ4_SH_BIG)
+ & TIR_BITS_TQ4_BIG)
+ | ((intern->tq5 << TIR_BITS_TQ5_SH_BIG)
+ & TIR_BITS_TQ5_BIG));
+ ext->t_tq01[0] = (((intern->tq0 << TIR_BITS_TQ0_SH_BIG)
+ & TIR_BITS_TQ0_BIG)
+ | ((intern->tq1 << TIR_BITS_TQ1_SH_BIG)
+ & TIR_BITS_TQ1_BIG));
+ ext->t_tq23[0] = (((intern->tq2 << TIR_BITS_TQ2_SH_BIG)
+ & TIR_BITS_TQ2_BIG)
+ | ((intern->tq3 << TIR_BITS_TQ3_SH_BIG)
+ & TIR_BITS_TQ3_BIG));
+ } else {
+ ext->t_bits1[0] = ((intern->fBitfield ? TIR_BITS1_FBITFIELD_LITTLE : 0)
+ | (intern->continued ? TIR_BITS1_CONTINUED_LITTLE : 0)
+ | ((intern->bt << TIR_BITS1_BT_SH_LITTLE)
+ & TIR_BITS1_BT_LITTLE));
+ ext->t_tq45[0] = (((intern->tq4 << TIR_BITS_TQ4_SH_LITTLE)
+ & TIR_BITS_TQ4_LITTLE)
+ | ((intern->tq5 << TIR_BITS_TQ5_SH_LITTLE)
+ & TIR_BITS_TQ5_LITTLE));
+ ext->t_tq01[0] = (((intern->tq0 << TIR_BITS_TQ0_SH_LITTLE)
+ & TIR_BITS_TQ0_LITTLE)
+ | ((intern->tq1 << TIR_BITS_TQ1_SH_LITTLE)
+ & TIR_BITS_TQ1_LITTLE));
+ ext->t_tq23[0] = (((intern->tq2 << TIR_BITS_TQ2_SH_LITTLE)
+ & TIR_BITS_TQ2_LITTLE)
+ | ((intern->tq3 << TIR_BITS_TQ3_SH_LITTLE)
+ & TIR_BITS_TQ3_LITTLE));
+ }
+
+#ifdef TEST
+ if (memcmp ((char *)ext, (char *)intern, sizeof (*intern)) != 0)
+ abort();
+#endif
+}
+
+/* Swap in a relative symbol record. BIGEND says whether it is in
+ big-endian or little-endian format.*/
+
+void
+_bfd_ecoff_swap_rndx_in (bigend, ext_copy, intern)
+ int bigend;
+ const struct rndx_ext *ext_copy;
+ RNDXR *intern;
+{
+ struct rndx_ext ext[1];
+
+ *ext = *ext_copy; /* Make it reasonable to do in-place. */
+
+ /* now the fun stuff... */
+ if (bigend) {
+ intern->rfd = (ext->r_bits[0] << RNDX_BITS0_RFD_SH_LEFT_BIG)
+ | ((ext->r_bits[1] & RNDX_BITS1_RFD_BIG)
+ >> RNDX_BITS1_RFD_SH_BIG);
+ intern->index = ((ext->r_bits[1] & RNDX_BITS1_INDEX_BIG)
+ << RNDX_BITS1_INDEX_SH_LEFT_BIG)
+ | (ext->r_bits[2] << RNDX_BITS2_INDEX_SH_LEFT_BIG)
+ | (ext->r_bits[3] << RNDX_BITS3_INDEX_SH_LEFT_BIG);
+ } else {
+ intern->rfd = (ext->r_bits[0] << RNDX_BITS0_RFD_SH_LEFT_LITTLE)
+ | ((ext->r_bits[1] & RNDX_BITS1_RFD_LITTLE)
+ << RNDX_BITS1_RFD_SH_LEFT_LITTLE);
+ intern->index = ((ext->r_bits[1] & RNDX_BITS1_INDEX_LITTLE)
+ >> RNDX_BITS1_INDEX_SH_LITTLE)
+ | (ext->r_bits[2] << RNDX_BITS2_INDEX_SH_LEFT_LITTLE)
+ | ((unsigned int) ext->r_bits[3]
+ << RNDX_BITS3_INDEX_SH_LEFT_LITTLE);
+ }
+
+#ifdef TEST
+ if (memcmp ((char *)ext, (char *)intern, sizeof (*intern)) != 0)
+ abort();
+#endif
+}
+
+/* Swap out a relative symbol record. BIGEND says whether it is in
+ big-endian or little-endian format.*/
+
+void
+_bfd_ecoff_swap_rndx_out (bigend, intern_copy, ext)
+ int bigend;
+ const RNDXR *intern_copy;
+ struct rndx_ext *ext;
+{
+ RNDXR intern[1];
+
+ *intern = *intern_copy; /* Make it reasonable to do in-place. */
+
+ /* now the fun stuff... */
+ if (bigend) {
+ ext->r_bits[0] = intern->rfd >> RNDX_BITS0_RFD_SH_LEFT_BIG;
+ ext->r_bits[1] = (((intern->rfd << RNDX_BITS1_RFD_SH_BIG)
+ & RNDX_BITS1_RFD_BIG)
+ | ((intern->index >> RNDX_BITS1_INDEX_SH_LEFT_BIG)
+ & RNDX_BITS1_INDEX_BIG));
+ ext->r_bits[2] = intern->index >> RNDX_BITS2_INDEX_SH_LEFT_BIG;
+ ext->r_bits[3] = intern->index >> RNDX_BITS3_INDEX_SH_LEFT_BIG;
+ } else {
+ ext->r_bits[0] = intern->rfd >> RNDX_BITS0_RFD_SH_LEFT_LITTLE;
+ ext->r_bits[1] = (((intern->rfd >> RNDX_BITS1_RFD_SH_LEFT_LITTLE)
+ & RNDX_BITS1_RFD_LITTLE)
+ | ((intern->index << RNDX_BITS1_INDEX_SH_LITTLE)
+ & RNDX_BITS1_INDEX_LITTLE));
+ ext->r_bits[2] = intern->index >> RNDX_BITS2_INDEX_SH_LEFT_LITTLE;
+ ext->r_bits[3] = intern->index >> RNDX_BITS3_INDEX_SH_LEFT_LITTLE;
+ }
+
+#ifdef TEST
+ if (memcmp ((char *)ext, (char *)intern, sizeof (*intern)) != 0)
+ abort();
+#endif
+}
+
+/* Read in the symbolic header for an ECOFF object file. */
+
+static boolean
+ecoff_slurp_symbolic_header (abfd)
+ bfd *abfd;
+{
+ const struct ecoff_backend_data * const backend = ecoff_backend (abfd);
+ bfd_size_type external_hdr_size;
+ PTR raw = NULL;
+ HDRR *internal_symhdr;
+
+ /* See if we've already read it in. */
+ if (ecoff_data (abfd)->debug_info.symbolic_header.magic ==
+ backend->debug_swap.sym_magic)
+ return true;
+
+ /* See whether there is a symbolic header. */
+ if (ecoff_data (abfd)->sym_filepos == 0)
+ {
+ bfd_get_symcount (abfd) = 0;
+ return true;
+ }
+
+ /* At this point bfd_get_symcount (abfd) holds the number of symbols
+ as read from the file header, but on ECOFF this is always the
+ size of the symbolic information header. It would be cleaner to
+ handle this when we first read the file in coffgen.c. */
+ external_hdr_size = backend->debug_swap.external_hdr_size;
+ if (bfd_get_symcount (abfd) != external_hdr_size)
+ {
+ bfd_set_error (bfd_error_bad_value);
+ return false;
+ }
+
+ /* Read the symbolic information header. */
+ raw = (PTR) malloc ((size_t) external_hdr_size);
+ if (raw == NULL)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ goto error_return;
+ }
+
+ if (bfd_seek (abfd, ecoff_data (abfd)->sym_filepos, SEEK_SET) == -1
+ || (bfd_read (raw, external_hdr_size, 1, abfd)
+ != external_hdr_size))
+ goto error_return;
+ internal_symhdr = &ecoff_data (abfd)->debug_info.symbolic_header;
+ (*backend->debug_swap.swap_hdr_in) (abfd, raw, internal_symhdr);
+
+ if (internal_symhdr->magic != backend->debug_swap.sym_magic)
+ {
+ bfd_set_error (bfd_error_bad_value);
+ goto error_return;
+ }
+
+ /* Now we can get the correct number of symbols. */
+ bfd_get_symcount (abfd) = (internal_symhdr->isymMax
+ + internal_symhdr->iextMax);
+
+ if (raw != NULL)
+ free (raw);
+ return true;
+ error_return:
+ if (raw != NULL)
+ free (raw);
+ return false;
+}
+
+/* Read in and swap the important symbolic information for an ECOFF
+ object file. This is called by gdb via the read_debug_info entry
+ point in the backend structure. */
+
+/*ARGSUSED*/
+boolean
+_bfd_ecoff_slurp_symbolic_info (abfd, ignore, debug)
+ bfd *abfd;
+ asection *ignore;
+ struct ecoff_debug_info *debug;
+{
+ const struct ecoff_backend_data * const backend = ecoff_backend (abfd);
+ HDRR *internal_symhdr;
+ bfd_size_type raw_base;
+ bfd_size_type raw_size;
+ PTR raw;
+ bfd_size_type external_fdr_size;
+ char *fraw_src;
+ char *fraw_end;
+ struct fdr *fdr_ptr;
+ bfd_size_type raw_end;
+ bfd_size_type cb_end;
+
+ BFD_ASSERT (debug == &ecoff_data (abfd)->debug_info);
+
+ /* Check whether we've already gotten it, and whether there's any to
+ get. */
+ if (ecoff_data (abfd)->raw_syments != (PTR) NULL)
+ return true;
+ if (ecoff_data (abfd)->sym_filepos == 0)
+ {
+ bfd_get_symcount (abfd) = 0;
+ return true;
+ }
+
+ if (! ecoff_slurp_symbolic_header (abfd))
+ return false;
+
+ internal_symhdr = &debug->symbolic_header;
+
+ /* Read all the symbolic information at once. */
+ raw_base = (ecoff_data (abfd)->sym_filepos
+ + backend->debug_swap.external_hdr_size);
+
+ /* Alpha ecoff makes the determination of raw_size difficult. It has
+ an undocumented debug data section between the symhdr and the first
+ documented section. And the ordering of the sections varies between
+ statically and dynamically linked executables.
+ If bfd supports SEEK_END someday, this code could be simplified. */
+
+ raw_end = 0;
+
+#define UPDATE_RAW_END(start, count, size) \
+ cb_end = internal_symhdr->start + internal_symhdr->count * (size); \
+ if (cb_end > raw_end) \
+ raw_end = cb_end
+
+ UPDATE_RAW_END (cbLineOffset, cbLine, sizeof (unsigned char));
+ UPDATE_RAW_END (cbDnOffset, idnMax, backend->debug_swap.external_dnr_size);
+ UPDATE_RAW_END (cbPdOffset, ipdMax, backend->debug_swap.external_pdr_size);
+ UPDATE_RAW_END (cbSymOffset, isymMax, backend->debug_swap.external_sym_size);
+ UPDATE_RAW_END (cbOptOffset, ioptMax, backend->debug_swap.external_opt_size);
+ UPDATE_RAW_END (cbAuxOffset, iauxMax, sizeof (union aux_ext));
+ UPDATE_RAW_END (cbSsOffset, issMax, sizeof (char));
+ UPDATE_RAW_END (cbSsExtOffset, issExtMax, sizeof (char));
+ UPDATE_RAW_END (cbFdOffset, ifdMax, backend->debug_swap.external_fdr_size);
+ UPDATE_RAW_END (cbRfdOffset, crfd, backend->debug_swap.external_rfd_size);
+ UPDATE_RAW_END (cbExtOffset, iextMax, backend->debug_swap.external_ext_size);
+
+#undef UPDATE_RAW_END
+
+ raw_size = raw_end - raw_base;
+ if (raw_size == 0)
+ {
+ ecoff_data (abfd)->sym_filepos = 0;
+ return true;
+ }
+ raw = (PTR) bfd_alloc (abfd, raw_size);
+ if (raw == NULL)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ return false;
+ }
+ if (bfd_seek (abfd,
+ (ecoff_data (abfd)->sym_filepos
+ + backend->debug_swap.external_hdr_size),
+ SEEK_SET) != 0
+ || bfd_read (raw, raw_size, 1, abfd) != raw_size)
+ {
+ bfd_release (abfd, raw);
+ return false;
+ }
+
+ ecoff_data (abfd)->raw_syments = raw;
+
+ /* Get pointers for the numeric offsets in the HDRR structure. */
+#define FIX(off1, off2, type) \
+ if (internal_symhdr->off1 == 0) \
+ debug->off2 = (type) NULL; \
+ else \
+ debug->off2 = (type) ((char *) raw \
+ + internal_symhdr->off1 \
+ - raw_base)
+ FIX (cbLineOffset, line, unsigned char *);
+ FIX (cbDnOffset, external_dnr, PTR);
+ FIX (cbPdOffset, external_pdr, PTR);
+ FIX (cbSymOffset, external_sym, PTR);
+ FIX (cbOptOffset, external_opt, PTR);
+ FIX (cbAuxOffset, external_aux, union aux_ext *);
+ FIX (cbSsOffset, ss, char *);
+ FIX (cbSsExtOffset, ssext, char *);
+ FIX (cbFdOffset, external_fdr, PTR);
+ FIX (cbRfdOffset, external_rfd, PTR);
+ FIX (cbExtOffset, external_ext, PTR);
+#undef FIX
+
+ /* I don't want to always swap all the data, because it will just
+ waste time and most programs will never look at it. The only
+ time the linker needs most of the debugging information swapped
+ is when linking big-endian and little-endian MIPS object files
+ together, which is not a common occurrence.
+
+ We need to look at the fdr to deal with a lot of information in
+ the symbols, so we swap them here. */
+ debug->fdr = (struct fdr *) bfd_alloc (abfd,
+ (internal_symhdr->ifdMax *
+ sizeof (struct fdr)));
+ if (debug->fdr == NULL)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ return false;
+ }
+ external_fdr_size = backend->debug_swap.external_fdr_size;
+ fdr_ptr = debug->fdr;
+ fraw_src = (char *) debug->external_fdr;
+ fraw_end = fraw_src + internal_symhdr->ifdMax * external_fdr_size;
+ for (; fraw_src < fraw_end; fraw_src += external_fdr_size, fdr_ptr++)
+ (*backend->debug_swap.swap_fdr_in) (abfd, (PTR) fraw_src, fdr_ptr);
+
+ return true;
+}
+
+/* ECOFF symbol table routines. The ECOFF symbol table is described
+ in gcc/mips-tfile.c. */
+
+/* ECOFF uses two common sections. One is the usual one, and the
+ other is for small objects. All the small objects are kept
+ together, and then referenced via the gp pointer, which yields
+ faster assembler code. This is what we use for the small common
+ section. */
+static asection ecoff_scom_section;
+static asymbol ecoff_scom_symbol;
+static asymbol *ecoff_scom_symbol_ptr;
+
+/* Create an empty symbol. */
+
+asymbol *
+_bfd_ecoff_make_empty_symbol (abfd)
+ bfd *abfd;
+{
+ ecoff_symbol_type *new;
+
+ new = (ecoff_symbol_type *) bfd_alloc (abfd, sizeof (ecoff_symbol_type));
+ if (new == (ecoff_symbol_type *) NULL)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ return (asymbol *) NULL;
+ }
+ memset ((PTR) new, 0, sizeof *new);
+ new->symbol.section = (asection *) NULL;
+ new->fdr = (FDR *) NULL;
+ new->local = false;
+ new->native = NULL;
+ new->symbol.the_bfd = abfd;
+ return &new->symbol;
+}
+
+/* Set the BFD flags and section for an ECOFF symbol. */
+
+static boolean
+ecoff_set_symbol_info (abfd, ecoff_sym, asym, ext, indirect_ptr_ptr)
+ bfd *abfd;
+ SYMR *ecoff_sym;
+ asymbol *asym;
+ int ext;
+ asymbol **indirect_ptr_ptr;
+{
+ asym->the_bfd = abfd;
+ asym->value = ecoff_sym->value;
+ asym->section = &bfd_debug_section;
+ asym->udata = NULL;
+
+ /* An indirect symbol requires two consecutive stabs symbols. */
+ if (*indirect_ptr_ptr != (asymbol *) NULL)
+ {
+ BFD_ASSERT (ECOFF_IS_STAB (ecoff_sym));
+
+ /* @@ Stuffing pointers into integers is a no-no.
+ We can usually get away with it if the integer is
+ large enough though. */
+ if (sizeof (asym) > sizeof (bfd_vma))
+ abort ();
+ (*indirect_ptr_ptr)->value = (bfd_vma) asym;
+
+ asym->flags = BSF_DEBUGGING;
+ asym->section = bfd_und_section_ptr;
+ *indirect_ptr_ptr = NULL;
+ return true;
+ }
+
+ if (ECOFF_IS_STAB (ecoff_sym)
+ && (ECOFF_UNMARK_STAB (ecoff_sym->index) | N_EXT) == (N_INDR | N_EXT))
+ {
+ asym->flags = BSF_DEBUGGING | BSF_INDIRECT;
+ asym->section = bfd_ind_section_ptr;
+ /* Pass this symbol on to the next call to this function. */
+ *indirect_ptr_ptr = asym;
+ return true;
+ }
+
+ /* Most symbol types are just for debugging. */
+ switch (ecoff_sym->st)
+ {
+ case stGlobal:
+ case stStatic:
+ case stLabel:
+ case stProc:
+ case stStaticProc:
+ break;
+ case stNil:
+ if (ECOFF_IS_STAB (ecoff_sym))
+ {
+ asym->flags = BSF_DEBUGGING;
+ return true;
+ }
+ break;
+ default:
+ asym->flags = BSF_DEBUGGING;
+ return true;
+ }
+
+ if (ext)
+ asym->flags = BSF_EXPORT | BSF_GLOBAL;
+ else
+ asym->flags = BSF_LOCAL;
+ switch (ecoff_sym->sc)
+ {
+ case scNil:
+ /* Used for compiler generated labels. Leave them in the
+ debugging section, and mark them as local. If BSF_DEBUGGING
+ is set, then nm does not display them for some reason. If no
+ flags are set then the linker whines about them. */
+ asym->flags = BSF_LOCAL;
+ break;
+ case scText:
+ asym->section = bfd_make_section_old_way (abfd, ".text");
+ asym->value -= asym->section->vma;
+ break;
+ case scData:
+ asym->section = bfd_make_section_old_way (abfd, ".data");
+ asym->value -= asym->section->vma;
+ break;
+ case scBss:
+ asym->section = bfd_make_section_old_way (abfd, ".bss");
+ asym->value -= asym->section->vma;
+ break;
+ case scRegister:
+ asym->flags = BSF_DEBUGGING;
+ break;
+ case scAbs:
+ asym->section = bfd_abs_section_ptr;
+ break;
+ case scUndefined:
+ asym->section = bfd_und_section_ptr;
+ asym->flags = 0;
+ asym->value = 0;
+ break;
+ case scCdbLocal:
+ case scBits:
+ case scCdbSystem:
+ case scRegImage:
+ case scInfo:
+ case scUserStruct:
+ asym->flags = BSF_DEBUGGING;
+ break;
+ case scSData:
+ asym->section = bfd_make_section_old_way (abfd, ".sdata");
+ asym->value -= asym->section->vma;
+ break;
+ case scSBss:
+ asym->section = bfd_make_section_old_way (abfd, ".sbss");
+ asym->value -= asym->section->vma;
+ break;
+ case scRData:
+ asym->section = bfd_make_section_old_way (abfd, ".rdata");
+ asym->value -= asym->section->vma;
+ break;
+ case scVar:
+ asym->flags = BSF_DEBUGGING;
+ break;
+ case scCommon:
+ if (asym->value > ecoff_data (abfd)->gp_size)
+ {
+ asym->section = bfd_com_section_ptr;
+ asym->flags = 0;
+ break;
+ }
+ /* Fall through. */
+ case scSCommon:
+ if (ecoff_scom_section.name == NULL)
+ {
+ /* Initialize the small common section. */
+ ecoff_scom_section.name = SCOMMON;
+ ecoff_scom_section.flags = SEC_IS_COMMON;
+ ecoff_scom_section.output_section = &ecoff_scom_section;
+ ecoff_scom_section.symbol = &ecoff_scom_symbol;
+ ecoff_scom_section.symbol_ptr_ptr = &ecoff_scom_symbol_ptr;
+ ecoff_scom_symbol.name = SCOMMON;
+ ecoff_scom_symbol.flags = BSF_SECTION_SYM;
+ ecoff_scom_symbol.section = &ecoff_scom_section;
+ ecoff_scom_symbol_ptr = &ecoff_scom_symbol;
+ }
+ asym->section = &ecoff_scom_section;
+ asym->flags = 0;
+ break;
+ case scVarRegister:
+ case scVariant:
+ asym->flags = BSF_DEBUGGING;
+ break;
+ case scSUndefined:
+ asym->section = bfd_und_section_ptr;
+ asym->flags = 0;
+ asym->value = 0;
+ break;
+ case scInit:
+ asym->section = bfd_make_section_old_way (abfd, ".init");
+ asym->value -= asym->section->vma;
+ break;
+ case scBasedVar:
+ case scXData:
+ case scPData:
+ asym->flags = BSF_DEBUGGING;
+ break;
+ case scFini:
+ asym->section = bfd_make_section_old_way (abfd, ".fini");
+ asym->value -= asym->section->vma;
+ break;
+ default:
+ break;
+ }
+
+ /* Look for special constructors symbols and make relocation entries
+ in a special construction section. These are produced by the
+ -fgnu-linker argument to g++. */
+ if (ECOFF_IS_STAB (ecoff_sym))
+ {
+ switch (ECOFF_UNMARK_STAB (ecoff_sym->index))
+ {
+ default:
+ break;
+
+ case N_SETA:
+ case N_SETT:
+ case N_SETD:
+ case N_SETB:
+ {
+ const char *name;
+ asection *section;
+ arelent_chain *reloc_chain;
+ unsigned int bitsize;
+
+ /* Get a section with the same name as the symbol (usually
+ __CTOR_LIST__ or __DTOR_LIST__). FIXME: gcc uses the
+ name ___CTOR_LIST (three underscores). We need
+ __CTOR_LIST (two underscores), since ECOFF doesn't use
+ a leading underscore. This should be handled by gcc,
+ but instead we do it here. Actually, this should all
+ be done differently anyhow. */
+ name = bfd_asymbol_name (asym);
+ if (name[0] == '_' && name[1] == '_' && name[2] == '_')
+ {
+ ++name;
+ asym->name = name;
+ }
+ section = bfd_get_section_by_name (abfd, name);
+ if (section == (asection *) NULL)
+ {
+ char *copy;
+
+ copy = (char *) bfd_alloc (abfd, strlen (name) + 1);
+ if (!copy)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ return false;
+ }
+ strcpy (copy, name);
+ section = bfd_make_section (abfd, copy);
+ }
+
+ /* Build a reloc pointing to this constructor. */
+ reloc_chain =
+ (arelent_chain *) bfd_alloc (abfd, sizeof (arelent_chain));
+ if (!reloc_chain)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ return false;
+ }
+ reloc_chain->relent.sym_ptr_ptr =
+ bfd_get_section (asym)->symbol_ptr_ptr;
+ reloc_chain->relent.address = section->_raw_size;
+ reloc_chain->relent.addend = asym->value;
+ reloc_chain->relent.howto =
+ ecoff_backend (abfd)->constructor_reloc;
+
+ /* Set up the constructor section to hold the reloc. */
+ section->flags = SEC_CONSTRUCTOR;
+ ++section->reloc_count;
+
+ /* Constructor sections must be rounded to a boundary
+ based on the bitsize. These are not real sections--
+ they are handled specially by the linker--so the ECOFF
+ 16 byte alignment restriction does not apply. */
+ bitsize = ecoff_backend (abfd)->constructor_bitsize;
+ section->alignment_power = 1;
+ while ((1 << section->alignment_power) < bitsize / 8)
+ ++section->alignment_power;
+
+ reloc_chain->next = section->constructor_chain;
+ section->constructor_chain = reloc_chain;
+ section->_raw_size += bitsize / 8;
+
+ /* Mark the symbol as a constructor. */
+ asym->flags |= BSF_CONSTRUCTOR;
+ }
+ break;
+ }
+ }
+ return true;
+}
+
+/* Read an ECOFF symbol table. */
+
+boolean
+_bfd_ecoff_slurp_symbol_table (abfd)
+ bfd *abfd;
+{
+ const struct ecoff_backend_data * const backend = ecoff_backend (abfd);
+ const bfd_size_type external_ext_size
+ = backend->debug_swap.external_ext_size;
+ const bfd_size_type external_sym_size
+ = backend->debug_swap.external_sym_size;
+ void (* const swap_ext_in) PARAMS ((bfd *, PTR, EXTR *))
+ = backend->debug_swap.swap_ext_in;
+ void (* const swap_sym_in) PARAMS ((bfd *, PTR, SYMR *))
+ = backend->debug_swap.swap_sym_in;
+ bfd_size_type internal_size;
+ ecoff_symbol_type *internal;
+ ecoff_symbol_type *internal_ptr;
+ asymbol *indirect_ptr;
+ char *eraw_src;
+ char *eraw_end;
+ FDR *fdr_ptr;
+ FDR *fdr_end;
+
+ /* If we've already read in the symbol table, do nothing. */
+ if (ecoff_data (abfd)->canonical_symbols != NULL)
+ return true;
+
+ /* Get the symbolic information. */
+ if (! _bfd_ecoff_slurp_symbolic_info (abfd, (asection *) NULL,
+ &ecoff_data (abfd)->debug_info))
+ return false;
+ if (bfd_get_symcount (abfd) == 0)
+ return true;
+
+ internal_size = bfd_get_symcount (abfd) * sizeof (ecoff_symbol_type);
+ internal = (ecoff_symbol_type *) bfd_alloc (abfd, internal_size);
+ if (internal == NULL)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ return false;
+ }
+
+ internal_ptr = internal;
+ indirect_ptr = NULL;
+ eraw_src = (char *) ecoff_data (abfd)->debug_info.external_ext;
+ eraw_end = (eraw_src
+ + (ecoff_data (abfd)->debug_info.symbolic_header.iextMax
+ * external_ext_size));
+ for (; eraw_src < eraw_end; eraw_src += external_ext_size, internal_ptr++)
+ {
+ EXTR internal_esym;
+
+ (*swap_ext_in) (abfd, (PTR) eraw_src, &internal_esym);
+ internal_ptr->symbol.name = (ecoff_data (abfd)->debug_info.ssext
+ + internal_esym.asym.iss);
+ if (!ecoff_set_symbol_info (abfd, &internal_esym.asym,
+ &internal_ptr->symbol, 1, &indirect_ptr))
+ return false;
+ /* The alpha uses a negative ifd field for section symbols. */
+ if (internal_esym.ifd >= 0)
+ internal_ptr->fdr = (ecoff_data (abfd)->debug_info.fdr
+ + internal_esym.ifd);
+ else
+ internal_ptr->fdr = NULL;
+ internal_ptr->local = false;
+ internal_ptr->native = (PTR) eraw_src;
+ }
+ BFD_ASSERT (indirect_ptr == (asymbol *) NULL);
+
+ /* The local symbols must be accessed via the fdr's, because the
+ string and aux indices are relative to the fdr information. */
+ fdr_ptr = ecoff_data (abfd)->debug_info.fdr;
+ fdr_end = fdr_ptr + ecoff_data (abfd)->debug_info.symbolic_header.ifdMax;
+ for (; fdr_ptr < fdr_end; fdr_ptr++)
+ {
+ char *lraw_src;
+ char *lraw_end;
+
+ lraw_src = ((char *) ecoff_data (abfd)->debug_info.external_sym
+ + fdr_ptr->isymBase * external_sym_size);
+ lraw_end = lraw_src + fdr_ptr->csym * external_sym_size;
+ for (;
+ lraw_src < lraw_end;
+ lraw_src += external_sym_size, internal_ptr++)
+ {
+ SYMR internal_sym;
+
+ (*swap_sym_in) (abfd, (PTR) lraw_src, &internal_sym);
+ internal_ptr->symbol.name = (ecoff_data (abfd)->debug_info.ss
+ + fdr_ptr->issBase
+ + internal_sym.iss);
+ if (!ecoff_set_symbol_info (abfd, &internal_sym,
+ &internal_ptr->symbol, 0, &indirect_ptr))
+ return false;
+ internal_ptr->fdr = fdr_ptr;
+ internal_ptr->local = true;
+ internal_ptr->native = (PTR) lraw_src;
+ }
+ }
+ BFD_ASSERT (indirect_ptr == (asymbol *) NULL);
+
+ ecoff_data (abfd)->canonical_symbols = internal;
+
+ return true;
+}
+
+/* Return the amount of space needed for the canonical symbols. */
+
+long
+_bfd_ecoff_get_symtab_upper_bound (abfd)
+ bfd *abfd;
+{
+ if (! _bfd_ecoff_slurp_symbolic_info (abfd, (asection *) NULL,
+ &ecoff_data (abfd)->debug_info))
+ return -1;
+
+ if (bfd_get_symcount (abfd) == 0)
+ return 0;
+
+ return (bfd_get_symcount (abfd) + 1) * (sizeof (ecoff_symbol_type *));
+}
+
+/* Get the canonical symbols. */
+
+long
+_bfd_ecoff_get_symtab (abfd, alocation)
+ bfd *abfd;
+ asymbol **alocation;
+{
+ unsigned int counter = 0;
+ ecoff_symbol_type *symbase;
+ ecoff_symbol_type **location = (ecoff_symbol_type **) alocation;
+
+ if (_bfd_ecoff_slurp_symbol_table (abfd) == false)
+ return -1;
+ if (bfd_get_symcount (abfd) == 0)
+ return 0;
+
+ symbase = ecoff_data (abfd)->canonical_symbols;
+ while (counter < bfd_get_symcount (abfd))
+ {
+ *(location++) = symbase++;
+ counter++;
+ }
+ *location++ = (ecoff_symbol_type *) NULL;
+ return bfd_get_symcount (abfd);
+}
+
+/* Turn ECOFF type information into a printable string.
+ ecoff_emit_aggregate and ecoff_type_to_string are from
+ gcc/mips-tdump.c, with swapping added and used_ptr removed. */
+
+/* Write aggregate information to a string. */
+
+static void
+ecoff_emit_aggregate (abfd, fdr, string, rndx, isym, which)
+ bfd *abfd;
+ FDR *fdr;
+ char *string;
+ RNDXR *rndx;
+ long isym;
+ const char *which;
+{
+ const struct ecoff_debug_swap * const debug_swap =
+ &ecoff_backend (abfd)->debug_swap;
+ struct ecoff_debug_info * const debug_info = &ecoff_data (abfd)->debug_info;
+ unsigned int ifd = rndx->rfd;
+ unsigned int indx = rndx->index;
+ const char *name;
+
+ if (ifd == 0xfff)
+ ifd = isym;
+
+ /* An ifd of -1 is an opaque type. An escaped index of 0 is a
+ struct return type of a procedure compiled without -g. */
+ if (ifd == 0xffffffff
+ || (rndx->rfd == 0xfff && indx == 0))
+ name = "<undefined>";
+ else if (indx == indexNil)
+ name = "<no name>";
+ else
+ {
+ SYMR sym;
+
+ if (debug_info->external_rfd == NULL)
+ fdr = debug_info->fdr + ifd;
+ else
+ {
+ RFDT rfd;
+
+ (*debug_swap->swap_rfd_in) (abfd,
+ ((char *) debug_info->external_rfd
+ + ((fdr->rfdBase + ifd)
+ * debug_swap->external_rfd_size)),
+ &rfd);
+ fdr = debug_info->fdr + rfd;
+ }
+
+ indx += fdr->isymBase;
+
+ (*debug_swap->swap_sym_in) (abfd,
+ ((char *) debug_info->external_sym
+ + indx * debug_swap->external_sym_size),
+ &sym);
+
+ name = debug_info->ss + fdr->issBase + sym.iss;
+ }
+
+ sprintf (string,
+ "%s %s { ifd = %u, index = %lu }",
+ which, name, ifd,
+ ((long) indx
+ + debug_info->symbolic_header.iextMax));
+}
+
+/* Convert the type information to string format. */
+
+static char *
+ecoff_type_to_string (abfd, fdr, indx)
+ bfd *abfd;
+ FDR *fdr;
+ unsigned int indx;
+{
+ union aux_ext *aux_ptr;
+ int bigendian;
+ AUXU u;
+ struct qual {
+ unsigned int type;
+ int low_bound;
+ int high_bound;
+ int stride;
+ } qualifiers[7];
+ unsigned int basic_type;
+ int i;
+ static char buffer1[1024];
+ static char buffer2[1024];
+ char *p1 = buffer1;
+ char *p2 = buffer2;
+ RNDXR rndx;
+
+ aux_ptr = ecoff_data (abfd)->debug_info.external_aux + fdr->iauxBase;
+ bigendian = fdr->fBigendian;
+
+ for (i = 0; i < 7; i++)
+ {
+ qualifiers[i].low_bound = 0;
+ qualifiers[i].high_bound = 0;
+ qualifiers[i].stride = 0;
+ }
+
+ if (AUX_GET_ISYM (bigendian, &aux_ptr[indx]) == -1)
+ return "-1 (no type)";
+ _bfd_ecoff_swap_tir_in (bigendian, &aux_ptr[indx++].a_ti, &u.ti);
+
+ basic_type = u.ti.bt;
+ qualifiers[0].type = u.ti.tq0;
+ qualifiers[1].type = u.ti.tq1;
+ qualifiers[2].type = u.ti.tq2;
+ qualifiers[3].type = u.ti.tq3;
+ qualifiers[4].type = u.ti.tq4;
+ qualifiers[5].type = u.ti.tq5;
+ qualifiers[6].type = tqNil;
+
+ /*
+ * Go get the basic type.
+ */
+ switch (basic_type)
+ {
+ case btNil: /* undefined */
+ strcpy (p1, "nil");
+ break;
+
+ case btAdr: /* address - integer same size as pointer */
+ strcpy (p1, "address");
+ break;
+
+ case btChar: /* character */
+ strcpy (p1, "char");
+ break;
+
+ case btUChar: /* unsigned character */
+ strcpy (p1, "unsigned char");
+ break;
+
+ case btShort: /* short */
+ strcpy (p1, "short");
+ break;
+
+ case btUShort: /* unsigned short */
+ strcpy (p1, "unsigned short");
+ break;
+
+ case btInt: /* int */
+ strcpy (p1, "int");
+ break;
+
+ case btUInt: /* unsigned int */
+ strcpy (p1, "unsigned int");
+ break;
+
+ case btLong: /* long */
+ strcpy (p1, "long");
+ break;
+
+ case btULong: /* unsigned long */
+ strcpy (p1, "unsigned long");
+ break;
+
+ case btFloat: /* float (real) */
+ strcpy (p1, "float");
+ break;
+
+ case btDouble: /* Double (real) */
+ strcpy (p1, "double");
+ break;
+
+ /* Structures add 1-2 aux words:
+ 1st word is [ST_RFDESCAPE, offset] pointer to struct def;
+ 2nd word is file index if 1st word rfd is ST_RFDESCAPE. */
+
+ case btStruct: /* Structure (Record) */
+ _bfd_ecoff_swap_rndx_in (bigendian, &aux_ptr[indx].a_rndx, &rndx);
+ ecoff_emit_aggregate (abfd, fdr, p1, &rndx,
+ (long) AUX_GET_ISYM (bigendian, &aux_ptr[indx+1]),
+ "struct");
+ indx++; /* skip aux words */
+ break;
+
+ /* Unions add 1-2 aux words:
+ 1st word is [ST_RFDESCAPE, offset] pointer to union def;
+ 2nd word is file index if 1st word rfd is ST_RFDESCAPE. */
+
+ case btUnion: /* Union */
+ _bfd_ecoff_swap_rndx_in (bigendian, &aux_ptr[indx].a_rndx, &rndx);
+ ecoff_emit_aggregate (abfd, fdr, p1, &rndx,
+ (long) AUX_GET_ISYM (bigendian, &aux_ptr[indx+1]),
+ "union");
+ indx++; /* skip aux words */
+ break;
+
+ /* Enumerations add 1-2 aux words:
+ 1st word is [ST_RFDESCAPE, offset] pointer to enum def;
+ 2nd word is file index if 1st word rfd is ST_RFDESCAPE. */
+
+ case btEnum: /* Enumeration */
+ _bfd_ecoff_swap_rndx_in (bigendian, &aux_ptr[indx].a_rndx, &rndx);
+ ecoff_emit_aggregate (abfd, fdr, p1, &rndx,
+ (long) AUX_GET_ISYM (bigendian, &aux_ptr[indx+1]),
+ "enum");
+ indx++; /* skip aux words */
+ break;
+
+ case btTypedef: /* defined via a typedef, isymRef points */
+ strcpy (p1, "typedef");
+ break;
+
+ case btRange: /* subrange of int */
+ strcpy (p1, "subrange");
+ break;
+
+ case btSet: /* pascal sets */
+ strcpy (p1, "set");
+ break;
+
+ case btComplex: /* fortran complex */
+ strcpy (p1, "complex");
+ break;
+
+ case btDComplex: /* fortran double complex */
+ strcpy (p1, "double complex");
+ break;
+
+ case btIndirect: /* forward or unnamed typedef */
+ strcpy (p1, "forward/unamed typedef");
+ break;
+
+ case btFixedDec: /* Fixed Decimal */
+ strcpy (p1, "fixed decimal");
+ break;
+
+ case btFloatDec: /* Float Decimal */
+ strcpy (p1, "float decimal");
+ break;
+
+ case btString: /* Varying Length Character String */
+ strcpy (p1, "string");
+ break;
+
+ case btBit: /* Aligned Bit String */
+ strcpy (p1, "bit");
+ break;
+
+ case btPicture: /* Picture */
+ strcpy (p1, "picture");
+ break;
+
+ case btVoid: /* Void */
+ strcpy (p1, "void");
+ break;
+
+ default:
+ sprintf (p1, "Unknown basic type %d", (int) basic_type);
+ break;
+ }
+
+ p1 += strlen (buffer1);
+
+ /*
+ * If this is a bitfield, get the bitsize.
+ */
+ if (u.ti.fBitfield)
+ {
+ int bitsize;
+
+ bitsize = AUX_GET_WIDTH (bigendian, &aux_ptr[indx++]);
+ sprintf (p1, " : %d", bitsize);
+ p1 += strlen (buffer1);
+ }
+
+
+ /*
+ * Deal with any qualifiers.
+ */
+ if (qualifiers[0].type != tqNil)
+ {
+ /*
+ * Snarf up any array bounds in the correct order. Arrays
+ * store 5 successive words in the aux. table:
+ * word 0 RNDXR to type of the bounds (ie, int)
+ * word 1 Current file descriptor index
+ * word 2 low bound
+ * word 3 high bound (or -1 if [])
+ * word 4 stride size in bits
+ */
+ for (i = 0; i < 7; i++)
+ {
+ if (qualifiers[i].type == tqArray)
+ {
+ qualifiers[i].low_bound =
+ AUX_GET_DNLOW (bigendian, &aux_ptr[indx+2]);
+ qualifiers[i].high_bound =
+ AUX_GET_DNHIGH (bigendian, &aux_ptr[indx+3]);
+ qualifiers[i].stride =
+ AUX_GET_WIDTH (bigendian, &aux_ptr[indx+4]);
+ indx += 5;
+ }
+ }
+
+ /*
+ * Now print out the qualifiers.
+ */
+ for (i = 0; i < 6; i++)
+ {
+ switch (qualifiers[i].type)
+ {
+ case tqNil:
+ case tqMax:
+ break;
+
+ case tqPtr:
+ strcpy (p2, "ptr to ");
+ p2 += sizeof ("ptr to ")-1;
+ break;
+
+ case tqVol:
+ strcpy (p2, "volatile ");
+ p2 += sizeof ("volatile ")-1;
+ break;
+
+ case tqFar:
+ strcpy (p2, "far ");
+ p2 += sizeof ("far ")-1;
+ break;
+
+ case tqProc:
+ strcpy (p2, "func. ret. ");
+ p2 += sizeof ("func. ret. ");
+ break;
+
+ case tqArray:
+ {
+ int first_array = i;
+ int j;
+
+ /* Print array bounds reversed (ie, in the order the C
+ programmer writes them). C is such a fun language.... */
+
+ while (i < 5 && qualifiers[i+1].type == tqArray)
+ i++;
+
+ for (j = i; j >= first_array; j--)
+ {
+ strcpy (p2, "array [");
+ p2 += sizeof ("array [")-1;
+ if (qualifiers[j].low_bound != 0)
+ sprintf (p2,
+ "%ld:%ld {%ld bits}",
+ (long) qualifiers[j].low_bound,
+ (long) qualifiers[j].high_bound,
+ (long) qualifiers[j].stride);
+
+ else if (qualifiers[j].high_bound != -1)
+ sprintf (p2,
+ "%ld {%ld bits}",
+ (long) (qualifiers[j].high_bound + 1),
+ (long) (qualifiers[j].stride));
+
+ else
+ sprintf (p2, " {%ld bits}", (long) (qualifiers[j].stride));
+
+ p2 += strlen (p2);
+ strcpy (p2, "] of ");
+ p2 += sizeof ("] of ")-1;
+ }
+ }
+ break;
+ }
+ }
+ }
+
+ strcpy (p2, buffer1);
+ return buffer2;
+}
+
+/* Return information about ECOFF symbol SYMBOL in RET. */
+
+/*ARGSUSED*/
+void
+_bfd_ecoff_get_symbol_info (abfd, symbol, ret)
+ bfd *abfd; /* Ignored. */
+ asymbol *symbol;
+ symbol_info *ret;
+{
+ bfd_symbol_info (symbol, ret);
+}
+
+/* Print information about an ECOFF symbol. */
+
+void
+_bfd_ecoff_print_symbol (abfd, filep, symbol, how)
+ bfd *abfd;
+ PTR filep;
+ asymbol *symbol;
+ bfd_print_symbol_type how;
+{
+ const struct ecoff_debug_swap * const debug_swap
+ = &ecoff_backend (abfd)->debug_swap;
+ FILE *file = (FILE *)filep;
+
+ switch (how)
+ {
+ case bfd_print_symbol_name:
+ fprintf (file, "%s", symbol->name);
+ break;
+ case bfd_print_symbol_more:
+ if (ecoffsymbol (symbol)->local)
+ {
+ SYMR ecoff_sym;
+
+ (*debug_swap->swap_sym_in) (abfd, ecoffsymbol (symbol)->native,
+ &ecoff_sym);
+ fprintf (file, "ecoff local ");
+ fprintf_vma (file, (bfd_vma) ecoff_sym.value);
+ fprintf (file, " %x %x", (unsigned) ecoff_sym.st,
+ (unsigned) ecoff_sym.sc);
+ }
+ else
+ {
+ EXTR ecoff_ext;
+
+ (*debug_swap->swap_ext_in) (abfd, ecoffsymbol (symbol)->native,
+ &ecoff_ext);
+ fprintf (file, "ecoff extern ");
+ fprintf_vma (file, (bfd_vma) ecoff_ext.asym.value);
+ fprintf (file, " %x %x", (unsigned) ecoff_ext.asym.st,
+ (unsigned) ecoff_ext.asym.sc);
+ }
+ break;
+ case bfd_print_symbol_all:
+ /* Print out the symbols in a reasonable way */
+ {
+ char type;
+ int pos;
+ EXTR ecoff_ext;
+ char jmptbl;
+ char cobol_main;
+ char weakext;
+
+ if (ecoffsymbol (symbol)->local)
+ {
+ (*debug_swap->swap_sym_in) (abfd, ecoffsymbol (symbol)->native,
+ &ecoff_ext.asym);
+ type = 'l';
+ pos = ((((char *) ecoffsymbol (symbol)->native
+ - (char *) ecoff_data (abfd)->debug_info.external_sym)
+ / debug_swap->external_sym_size)
+ + ecoff_data (abfd)->debug_info.symbolic_header.iextMax);
+ jmptbl = ' ';
+ cobol_main = ' ';
+ weakext = ' ';
+ }
+ else
+ {
+ (*debug_swap->swap_ext_in) (abfd, ecoffsymbol (symbol)->native,
+ &ecoff_ext);
+ type = 'e';
+ pos = (((char *) ecoffsymbol (symbol)->native
+ - (char *) ecoff_data (abfd)->debug_info.external_ext)
+ / debug_swap->external_ext_size);
+ jmptbl = ecoff_ext.jmptbl ? 'j' : ' ';
+ cobol_main = ecoff_ext.cobol_main ? 'c' : ' ';
+ weakext = ecoff_ext.weakext ? 'w' : ' ';
+ }
+
+ fprintf (file, "[%3d] %c ",
+ pos, type);
+ fprintf_vma (file, (bfd_vma) ecoff_ext.asym.value);
+ fprintf (file, " st %x sc %x indx %x %c%c%c %s",
+ (unsigned) ecoff_ext.asym.st,
+ (unsigned) ecoff_ext.asym.sc,
+ (unsigned) ecoff_ext.asym.index,
+ jmptbl, cobol_main, weakext,
+ symbol->name);
+
+ if (ecoffsymbol (symbol)->fdr != NULL
+ && ecoff_ext.asym.index != indexNil)
+ {
+ FDR *fdr;
+ unsigned int indx;
+ int bigendian;
+ bfd_size_type sym_base;
+ union aux_ext *aux_base;
+
+ fdr = ecoffsymbol (symbol)->fdr;
+ indx = ecoff_ext.asym.index;
+
+ /* sym_base is used to map the fdr relative indices which
+ appear in the file to the position number which we are
+ using. */
+ sym_base = fdr->isymBase;
+ if (ecoffsymbol (symbol)->local)
+ sym_base +=
+ ecoff_data (abfd)->debug_info.symbolic_header.iextMax;
+
+ /* aux_base is the start of the aux entries for this file;
+ asym.index is an offset from this. */
+ aux_base = (ecoff_data (abfd)->debug_info.external_aux
+ + fdr->iauxBase);
+
+ /* The aux entries are stored in host byte order; the
+ order is indicated by a bit in the fdr. */
+ bigendian = fdr->fBigendian;
+
+ /* This switch is basically from gcc/mips-tdump.c */
+ switch (ecoff_ext.asym.st)
+ {
+ case stNil:
+ case stLabel:
+ break;
+
+ case stFile:
+ case stBlock:
+ fprintf (file, "\n End+1 symbol: %ld",
+ (long) (indx + sym_base));
+ break;
+
+ case stEnd:
+ if (ecoff_ext.asym.sc == scText
+ || ecoff_ext.asym.sc == scInfo)
+ fprintf (file, "\n First symbol: %ld",
+ (long) (indx + sym_base));
+ else
+ fprintf (file, "\n First symbol: %ld",
+ ((long)
+ (AUX_GET_ISYM (bigendian,
+ &aux_base[ecoff_ext.asym.index])
+ + sym_base)));
+ break;
+
+ case stProc:
+ case stStaticProc:
+ if (ECOFF_IS_STAB (&ecoff_ext.asym))
+ ;
+ else if (ecoffsymbol (symbol)->local)
+ fprintf (file, "\n End+1 symbol: %-7ld Type: %s",
+ ((long)
+ (AUX_GET_ISYM (bigendian,
+ &aux_base[ecoff_ext.asym.index])
+ + sym_base)),
+ ecoff_type_to_string (abfd, fdr, indx + 1));
+ else
+ fprintf (file, "\n Local symbol: %ld",
+ ((long) indx
+ + (long) sym_base
+ + (ecoff_data (abfd)
+ ->debug_info.symbolic_header.iextMax)));
+ break;
+
+ case stStruct:
+ fprintf (file, "\n struct; End+1 symbol: %ld",
+ (long) (indx + sym_base));
+ break;
+
+ case stUnion:
+ fprintf (file, "\n union; End+1 symbol: %ld",
+ (long) (indx + sym_base));
+ break;
+
+ case stEnum:
+ fprintf (file, "\n enum; End+1 symbol: %ld",
+ (long) (indx + sym_base));
+ break;
+
+ default:
+ if (! ECOFF_IS_STAB (&ecoff_ext.asym))
+ fprintf (file, "\n Type: %s",
+ ecoff_type_to_string (abfd, fdr, indx));
+ break;
+ }
+ }
+ }
+ break;
+ }
+}
+
+/* Read in the relocs for a section. */
+
+static boolean
+ecoff_slurp_reloc_table (abfd, section, symbols)
+ bfd *abfd;
+ asection *section;
+ asymbol **symbols;
+{
+ const struct ecoff_backend_data * const backend = ecoff_backend (abfd);
+ arelent *internal_relocs;
+ bfd_size_type external_reloc_size;
+ bfd_size_type external_relocs_size;
+ char *external_relocs;
+ arelent *rptr;
+ unsigned int i;
+
+ if (section->relocation != (arelent *) NULL
+ || section->reloc_count == 0
+ || (section->flags & SEC_CONSTRUCTOR) != 0)
+ return true;
+
+ if (_bfd_ecoff_slurp_symbol_table (abfd) == false)
+ return false;
+
+ internal_relocs = (arelent *) bfd_alloc (abfd,
+ (sizeof (arelent)
+ * section->reloc_count));
+ external_reloc_size = backend->external_reloc_size;
+ external_relocs_size = external_reloc_size * section->reloc_count;
+ external_relocs = (char *) bfd_alloc (abfd, external_relocs_size);
+ if (internal_relocs == (arelent *) NULL
+ || external_relocs == (char *) NULL)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ return false;
+ }
+ if (bfd_seek (abfd, section->rel_filepos, SEEK_SET) != 0)
+ return false;
+ if (bfd_read (external_relocs, 1, external_relocs_size, abfd)
+ != external_relocs_size)
+ return false;
+
+ for (i = 0, rptr = internal_relocs; i < section->reloc_count; i++, rptr++)
+ {
+ struct internal_reloc intern;
+
+ (*backend->swap_reloc_in) (abfd,
+ external_relocs + i * external_reloc_size,
+ &intern);
+
+ if (intern.r_extern)
+ {
+ /* r_symndx is an index into the external symbols. */
+ BFD_ASSERT (intern.r_symndx >= 0
+ && (intern.r_symndx
+ < (ecoff_data (abfd)
+ ->debug_info.symbolic_header.iextMax)));
+ rptr->sym_ptr_ptr = symbols + intern.r_symndx;
+ rptr->addend = 0;
+ }
+ else if (intern.r_symndx == RELOC_SECTION_NONE
+ || intern.r_symndx == RELOC_SECTION_ABS)
+ {
+ rptr->sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr;
+ rptr->addend = 0;
+ }
+ else
+ {
+ CONST char *sec_name;
+ asection *sec;
+
+ /* r_symndx is a section key. */
+ switch (intern.r_symndx)
+ {
+ case RELOC_SECTION_TEXT: sec_name = ".text"; break;
+ case RELOC_SECTION_RDATA: sec_name = ".rdata"; break;
+ case RELOC_SECTION_DATA: sec_name = ".data"; break;
+ case RELOC_SECTION_SDATA: sec_name = ".sdata"; break;
+ case RELOC_SECTION_SBSS: sec_name = ".sbss"; break;
+ case RELOC_SECTION_BSS: sec_name = ".bss"; break;
+ case RELOC_SECTION_INIT: sec_name = ".init"; break;
+ case RELOC_SECTION_LIT8: sec_name = ".lit8"; break;
+ case RELOC_SECTION_LIT4: sec_name = ".lit4"; break;
+ case RELOC_SECTION_XDATA: sec_name = ".xdata"; break;
+ case RELOC_SECTION_PDATA: sec_name = ".pdata"; break;
+ case RELOC_SECTION_FINI: sec_name = ".fini"; break;
+ case RELOC_SECTION_LITA: sec_name = ".lita"; break;
+ default: abort ();
+ }
+
+ sec = bfd_get_section_by_name (abfd, sec_name);
+ if (sec == (asection *) NULL)
+ abort ();
+ rptr->sym_ptr_ptr = sec->symbol_ptr_ptr;
+
+ rptr->addend = - bfd_get_section_vma (abfd, sec);
+ }
+
+ rptr->address = intern.r_vaddr - bfd_get_section_vma (abfd, section);
+
+ /* Let the backend select the howto field and do any other
+ required processing. */
+ (*backend->adjust_reloc_in) (abfd, &intern, rptr);
+ }
+
+ bfd_release (abfd, external_relocs);
+
+ section->relocation = internal_relocs;
+
+ return true;
+}
+
+/* Get a canonical list of relocs. */
+
+long
+_bfd_ecoff_canonicalize_reloc (abfd, section, relptr, symbols)
+ bfd *abfd;
+ asection *section;
+ arelent **relptr;
+ asymbol **symbols;
+{
+ unsigned int count;
+
+ if (section->flags & SEC_CONSTRUCTOR)
+ {
+ arelent_chain *chain;
+
+ /* This section has relocs made up by us, not the file, so take
+ them out of their chain and place them into the data area
+ provided. */
+ for (count = 0, chain = section->constructor_chain;
+ count < section->reloc_count;
+ count++, chain = chain->next)
+ *relptr++ = &chain->relent;
+ }
+ else
+ {
+ arelent *tblptr;
+
+ if (ecoff_slurp_reloc_table (abfd, section, symbols) == false)
+ return -1;
+
+ tblptr = section->relocation;
+
+ for (count = 0; count < section->reloc_count; count++)
+ *relptr++ = tblptr++;
+ }
+
+ *relptr = (arelent *) NULL;
+
+ return section->reloc_count;
+}
+
+/* Provided a BFD, a section and an offset into the section, calculate
+ and return the name of the source file and the line nearest to the
+ wanted location. */
+
+/*ARGSUSED*/
+boolean
+_bfd_ecoff_find_nearest_line (abfd, section, ignore_symbols, offset,
+ filename_ptr, functionname_ptr, retline_ptr)
+ bfd *abfd;
+ asection *section;
+ asymbol **ignore_symbols;
+ bfd_vma offset;
+ CONST char **filename_ptr;
+ CONST char **functionname_ptr;
+ unsigned int *retline_ptr;
+{
+ const struct ecoff_debug_swap * const debug_swap
+ = &ecoff_backend (abfd)->debug_swap;
+ FDR *fdr_ptr;
+ FDR *fdr_start;
+ FDR *fdr_end;
+ FDR *fdr_hold;
+ bfd_size_type external_pdr_size;
+ char *pdr_ptr;
+ char *pdr_end;
+ PDR pdr;
+ bfd_vma first_off;
+ unsigned char *line_ptr;
+ unsigned char *line_end;
+ int lineno;
+
+ /* If we're not in the .text section, we don't have any line
+ numbers. */
+ if (strcmp (section->name, _TEXT) != 0
+ || offset < ecoff_data (abfd)->text_start
+ || offset >= ecoff_data (abfd)->text_end)
+ return false;
+
+ /* Make sure we have the FDR's. */
+ if (! _bfd_ecoff_slurp_symbolic_info (abfd, (asection *) NULL,
+ &ecoff_data (abfd)->debug_info)
+ || bfd_get_symcount (abfd) == 0)
+ return false;
+
+ /* Each file descriptor (FDR) has a memory address. Here we track
+ down which FDR we want. The FDR's are stored in increasing
+ memory order. If speed is ever important, this can become a
+ binary search. We must ignore FDR's with no PDR entries; they
+ will have the adr of the FDR before or after them. */
+ fdr_start = ecoff_data (abfd)->debug_info.fdr;
+ fdr_end = fdr_start + ecoff_data (abfd)->debug_info.symbolic_header.ifdMax;
+ fdr_hold = (FDR *) NULL;
+ for (fdr_ptr = fdr_start; fdr_ptr < fdr_end; fdr_ptr++)
+ {
+ if (fdr_ptr->cpd == 0)
+ continue;
+ if (offset < fdr_ptr->adr)
+ break;
+ fdr_hold = fdr_ptr;
+ }
+ if (fdr_hold == (FDR *) NULL)
+ return false;
+ fdr_ptr = fdr_hold;
+
+ /* Each FDR has a list of procedure descriptors (PDR). PDR's also
+ have an address, which is relative to the FDR address, and are
+ also stored in increasing memory order. */
+ offset -= fdr_ptr->adr;
+ external_pdr_size = debug_swap->external_pdr_size;
+ pdr_ptr = ((char *) ecoff_data (abfd)->debug_info.external_pdr
+ + fdr_ptr->ipdFirst * external_pdr_size);
+ pdr_end = pdr_ptr + fdr_ptr->cpd * external_pdr_size;
+ (*debug_swap->swap_pdr_in) (abfd, (PTR) pdr_ptr, &pdr);
+ if (offset < pdr.adr)
+ return false;
+
+ /* The address of the first PDR is an offset which applies to the
+ addresses of all the PDR's. */
+ first_off = pdr.adr;
+
+ for (pdr_ptr += external_pdr_size;
+ pdr_ptr < pdr_end;
+ pdr_ptr += external_pdr_size)
+ {
+ (*debug_swap->swap_pdr_in) (abfd, (PTR) pdr_ptr, &pdr);
+ if (offset < pdr.adr)
+ break;
+ }
+
+ /* Now we can look for the actual line number. The line numbers are
+ stored in a very funky format, which I won't try to describe.
+ Note that right here pdr_ptr and pdr hold the PDR *after* the one
+ we want; we need this to compute line_end. */
+ line_end = ecoff_data (abfd)->debug_info.line;
+ if (pdr_ptr == pdr_end)
+ line_end += fdr_ptr->cbLineOffset + fdr_ptr->cbLine;
+ else
+ line_end += fdr_ptr->cbLineOffset + pdr.cbLineOffset;
+
+ /* Now change pdr and pdr_ptr to the one we want. */
+ pdr_ptr -= external_pdr_size;
+ (*debug_swap->swap_pdr_in) (abfd, (PTR) pdr_ptr, &pdr);
+
+ offset -= pdr.adr - first_off;
+ lineno = pdr.lnLow;
+ line_ptr = (ecoff_data (abfd)->debug_info.line
+ + fdr_ptr->cbLineOffset
+ + pdr.cbLineOffset);
+ while (line_ptr < line_end)
+ {
+ int delta;
+ int count;
+
+ delta = *line_ptr >> 4;
+ if (delta >= 0x8)
+ delta -= 0x10;
+ count = (*line_ptr & 0xf) + 1;
+ ++line_ptr;
+ if (delta == -8)
+ {
+ delta = (((line_ptr[0]) & 0xff) << 8) + ((line_ptr[1]) & 0xff);
+ if (delta >= 0x8000)
+ delta -= 0x10000;
+ line_ptr += 2;
+ }
+ lineno += delta;
+ if (offset < count * 4)
+ break;
+ offset -= count * 4;
+ }
+
+ /* If fdr_ptr->rss is -1, then this file does not have full symbols,
+ at least according to gdb/mipsread.c. */
+ if (fdr_ptr->rss == -1)
+ {
+ *filename_ptr = NULL;
+ if (pdr.isym == -1)
+ *functionname_ptr = NULL;
+ else
+ {
+ EXTR proc_ext;
+
+ (*debug_swap->swap_ext_in)
+ (abfd,
+ ((char *) ecoff_data (abfd)->debug_info.external_ext
+ + pdr.isym * debug_swap->external_ext_size),
+ &proc_ext);
+ *functionname_ptr = (ecoff_data (abfd)->debug_info.ssext
+ + proc_ext.asym.iss);
+ }
+ }
+ else
+ {
+ SYMR proc_sym;
+
+ *filename_ptr = (ecoff_data (abfd)->debug_info.ss
+ + fdr_ptr->issBase
+ + fdr_ptr->rss);
+ (*debug_swap->swap_sym_in)
+ (abfd,
+ ((char *) ecoff_data (abfd)->debug_info.external_sym
+ + (fdr_ptr->isymBase + pdr.isym) * debug_swap->external_sym_size),
+ &proc_sym);
+ *functionname_ptr = (ecoff_data (abfd)->debug_info.ss
+ + fdr_ptr->issBase
+ + proc_sym.iss);
+ }
+ if (lineno == ilineNil)
+ lineno = 0;
+ *retline_ptr = lineno;
+ return true;
+}
+
+/* Copy private BFD data. This is called by objcopy and strip. We
+ use it to copy the ECOFF debugging information from one BFD to the
+ other. It would be theoretically possible to represent the ECOFF
+ debugging information in the symbol table. However, it would be a
+ lot of work, and there would be little gain (gas, gdb, and ld
+ already access the ECOFF debugging information via the
+ ecoff_debug_info structure, and that structure would have to be
+ retained in order to support ECOFF debugging in MIPS ELF).
+
+ The debugging information for the ECOFF external symbols comes from
+ the symbol table, so this function only handles the other debugging
+ information. */
+
+boolean
+_bfd_ecoff_bfd_copy_private_bfd_data (ibfd, obfd)
+ bfd *ibfd;
+ bfd *obfd;
+{
+ struct ecoff_debug_info *iinfo = &ecoff_data (ibfd)->debug_info;
+ struct ecoff_debug_info *oinfo = &ecoff_data (obfd)->debug_info;
+ register int i;
+ asymbol **sym_ptr_ptr;
+ size_t c;
+ boolean local;
+
+ /* This function is selected based on the input vector. We only
+ want to copy information over if the output BFD also uses ECOFF
+ format. */
+ if (bfd_get_flavour (obfd) != bfd_target_ecoff_flavour)
+ return true;
+
+ /* Copy the GP value and the register masks. */
+ ecoff_data (obfd)->gp = ecoff_data (ibfd)->gp;
+ ecoff_data (obfd)->gprmask = ecoff_data (ibfd)->gprmask;
+ ecoff_data (obfd)->fprmask = ecoff_data (ibfd)->fprmask;
+ for (i = 0; i < 3; i++)
+ ecoff_data (obfd)->cprmask[i] = ecoff_data (ibfd)->cprmask[i];
+
+ /* Copy the version stamp. */
+ oinfo->symbolic_header.vstamp = iinfo->symbolic_header.vstamp;
+
+ /* If there are no symbols, don't copy any debugging information. */
+ c = bfd_get_symcount (obfd);
+ sym_ptr_ptr = bfd_get_outsymbols (obfd);
+ if (c == 0 || sym_ptr_ptr == (asymbol **) NULL)
+ return true;
+
+ /* See if there are any local symbols. */
+ local = false;
+ for (; c > 0; c--, sym_ptr_ptr++)
+ {
+ if (ecoffsymbol (*sym_ptr_ptr)->local)
+ {
+ local = true;
+ break;
+ }
+ }
+
+ if (local)
+ {
+ /* There are some local symbols. We just bring over all the
+ debugging information. FIXME: This is not quite the right
+ thing to do. If the user has asked us to discard all
+ debugging information, then we are probably going to wind up
+ keeping it because there will probably be some local symbol
+ which objcopy did not discard. We should actually break
+ apart the debugging information and only keep that which
+ applies to the symbols we want to keep. */
+ oinfo->symbolic_header.ilineMax = iinfo->symbolic_header.ilineMax;
+ oinfo->symbolic_header.cbLine = iinfo->symbolic_header.cbLine;
+ oinfo->line = iinfo->line;
+
+ oinfo->symbolic_header.idnMax = iinfo->symbolic_header.idnMax;
+ oinfo->external_dnr = iinfo->external_dnr;
+
+ oinfo->symbolic_header.ipdMax = iinfo->symbolic_header.ipdMax;
+ oinfo->external_pdr = iinfo->external_pdr;
+
+ oinfo->symbolic_header.isymMax = iinfo->symbolic_header.isymMax;
+ oinfo->external_sym = iinfo->external_sym;
+
+ oinfo->symbolic_header.ioptMax = iinfo->symbolic_header.ioptMax;
+ oinfo->external_opt = iinfo->external_opt;
+
+ oinfo->symbolic_header.iauxMax = iinfo->symbolic_header.iauxMax;
+ oinfo->external_aux = iinfo->external_aux;
+
+ oinfo->symbolic_header.issMax = iinfo->symbolic_header.issMax;
+ oinfo->ss = iinfo->ss;
+
+ oinfo->symbolic_header.ifdMax = iinfo->symbolic_header.ifdMax;
+ oinfo->external_fdr = iinfo->external_fdr;
+
+ oinfo->symbolic_header.crfd = iinfo->symbolic_header.crfd;
+ oinfo->external_rfd = iinfo->external_rfd;
+ }
+ else
+ {
+ /* We are discarding all the local symbol information. Look
+ through the external symbols and remove all references to FDR
+ or aux information. */
+ c = bfd_get_symcount (obfd);
+ sym_ptr_ptr = bfd_get_outsymbols (obfd);
+ for (; c > 0; c--, sym_ptr_ptr++)
+ {
+ EXTR esym;
+
+ (*(ecoff_backend (obfd)->debug_swap.swap_ext_in))
+ (obfd, ecoffsymbol (*sym_ptr_ptr)->native, &esym);
+ esym.ifd = ifdNil;
+ esym.asym.index = indexNil;
+ (*(ecoff_backend (obfd)->debug_swap.swap_ext_out))
+ (obfd, &esym, ecoffsymbol (*sym_ptr_ptr)->native);
+ }
+ }
+
+ return true;
+}
+
+/* Set the architecture. The supported architecture is stored in the
+ backend pointer. We always set the architecture anyhow, since many
+ callers ignore the return value. */
+
+boolean
+_bfd_ecoff_set_arch_mach (abfd, arch, machine)
+ bfd *abfd;
+ enum bfd_architecture arch;
+ unsigned long machine;
+{
+ bfd_default_set_arch_mach (abfd, arch, machine);
+ return arch == ecoff_backend (abfd)->arch;
+}
+
+/* Get the size of the section headers. */
+
+/*ARGSUSED*/
+int
+_bfd_ecoff_sizeof_headers (abfd, reloc)
+ bfd *abfd;
+ boolean reloc;
+{
+ asection *current;
+ int c;
+ int ret;
+
+ c = 0;
+ for (current = abfd->sections;
+ current != (asection *)NULL;
+ current = current->next)
+ ++c;
+
+ ret = (bfd_coff_filhsz (abfd)
+ + bfd_coff_aoutsz (abfd)
+ + c * bfd_coff_scnhsz (abfd));
+ return BFD_ALIGN (ret, 16);
+}
+
+/* Get the contents of a section. */
+
+boolean
+_bfd_ecoff_get_section_contents (abfd, section, location, offset, count)
+ bfd *abfd;
+ asection *section;
+ PTR location;
+ file_ptr offset;
+ bfd_size_type count;
+{
+ return _bfd_generic_get_section_contents (abfd, section, location,
+ offset, count);
+}
+
+/* Calculate the file position for each section, and set
+ reloc_filepos. */
+
+static void
+ecoff_compute_section_file_positions (abfd)
+ bfd *abfd;
+{
+ asection *current;
+ file_ptr sofar;
+ file_ptr old_sofar;
+ boolean first_data;
+
+ sofar = _bfd_ecoff_sizeof_headers (abfd, false);
+
+ first_data = true;
+ for (current = abfd->sections;
+ current != (asection *) NULL;
+ current = current->next)
+ {
+ unsigned int alignment_power;
+
+ /* Only deal with sections which have contents */
+ if ((current->flags & (SEC_HAS_CONTENTS | SEC_LOAD)) == 0)
+ continue;
+
+ /* For the Alpha ECOFF .pdata section the lnnoptr field is
+ supposed to indicate the number of .pdata entries that are
+ really in the section. Each entry is 8 bytes. We store this
+ away in line_filepos before increasing the section size. */
+ if (strcmp (current->name, _PDATA) != 0)
+ alignment_power = current->alignment_power;
+ else
+ {
+ current->line_filepos = current->_raw_size / 8;
+ alignment_power = 4;
+ }
+
+ /* On Ultrix, the data sections in an executable file must be
+ aligned to a page boundary within the file. This does not
+ affect the section size, though. FIXME: Does this work for
+ other platforms? It requires some modification for the
+ Alpha, because .rdata on the Alpha goes with the text, not
+ the data. */
+ if ((abfd->flags & EXEC_P) != 0
+ && (abfd->flags & D_PAGED) != 0
+ && first_data != false
+ && (current->flags & SEC_CODE) == 0
+ && (! ecoff_backend (abfd)->rdata_in_text
+ || strcmp (current->name, _RDATA) != 0)
+ && strcmp (current->name, _PDATA) != 0)
+ {
+ const bfd_vma round = ecoff_backend (abfd)->round;
+
+ sofar = (sofar + round - 1) &~ (round - 1);
+ first_data = false;
+ }
+ else if (strcmp (current->name, _LIB) == 0)
+ {
+ const bfd_vma round = ecoff_backend (abfd)->round;
+ /* On Irix 4, the location of contents of the .lib section
+ from a shared library section is also rounded up to a
+ page boundary. */
+
+ sofar = (sofar + round - 1) &~ (round - 1);
+ }
+
+ /* Align the sections in the file to the same boundary on
+ which they are aligned in virtual memory. */
+ old_sofar = sofar;
+ sofar = BFD_ALIGN (sofar, 1 << alignment_power);
+
+ current->filepos = sofar;
+
+ sofar += current->_raw_size;
+
+ /* make sure that this section is of the right size too */
+ old_sofar = sofar;
+ sofar = BFD_ALIGN (sofar, 1 << alignment_power);
+ current->_raw_size += sofar - old_sofar;
+ }
+
+ ecoff_data (abfd)->reloc_filepos = sofar;
+}
+
+/* Determine the location of the relocs for all the sections in the
+ output file, as well as the location of the symbolic debugging
+ information. */
+
+static bfd_size_type
+ecoff_compute_reloc_file_positions (abfd)
+ bfd *abfd;
+{
+ const bfd_size_type external_reloc_size =
+ ecoff_backend (abfd)->external_reloc_size;
+ file_ptr reloc_base;
+ bfd_size_type reloc_size;
+ asection *current;
+ file_ptr sym_base;
+
+ if (! abfd->output_has_begun)
+ {
+ ecoff_compute_section_file_positions (abfd);
+ abfd->output_has_begun = true;
+ }
+
+ reloc_base = ecoff_data (abfd)->reloc_filepos;
+
+ reloc_size = 0;
+ for (current = abfd->sections;
+ current != (asection *)NULL;
+ current = current->next)
+ {
+ if (current->reloc_count == 0)
+ current->rel_filepos = 0;
+ else
+ {
+ bfd_size_type relsize;
+
+ current->rel_filepos = reloc_base;
+ relsize = current->reloc_count * external_reloc_size;
+ reloc_size += relsize;
+ reloc_base += relsize;
+ }
+ }
+
+ sym_base = ecoff_data (abfd)->reloc_filepos + reloc_size;
+
+ /* At least on Ultrix, the symbol table of an executable file must
+ be aligned to a page boundary. FIXME: Is this true on other
+ platforms? */
+ if ((abfd->flags & EXEC_P) != 0
+ && (abfd->flags & D_PAGED) != 0)
+ sym_base = ((sym_base + ecoff_backend (abfd)->round - 1)
+ &~ (ecoff_backend (abfd)->round - 1));
+
+ ecoff_data (abfd)->sym_filepos = sym_base;
+
+ return reloc_size;
+}
+
+/* Set the contents of a section. */
+
+boolean
+_bfd_ecoff_set_section_contents (abfd, section, location, offset, count)
+ bfd *abfd;
+ asection *section;
+ PTR location;
+ file_ptr offset;
+ bfd_size_type count;
+{
+ /* This must be done first, because bfd_set_section_contents is
+ going to set output_has_begun to true. */
+ if (abfd->output_has_begun == false)
+ ecoff_compute_section_file_positions (abfd);
+
+ /* If this is a .lib section, bump the vma address so that it winds
+ up being the number of .lib sections output. This is right for
+ Irix 4. Ian Taylor <ian@cygnus.com>. */
+ if (strcmp (section->name, _LIB) == 0)
+ ++section->vma;
+
+ if (count == 0)
+ return true;
+
+ if (bfd_seek (abfd, (file_ptr) (section->filepos + offset), SEEK_SET) != 0
+ || bfd_write (location, 1, count, abfd) != count)
+ return false;
+
+ return true;
+}
+
+/* Get the GP value for an ECOFF file. This is a hook used by
+ nlmconv. */
+
+bfd_vma
+bfd_ecoff_get_gp_value (abfd)
+ bfd *abfd;
+{
+ if (bfd_get_flavour (abfd) != bfd_target_ecoff_flavour
+ || bfd_get_format (abfd) != bfd_object)
+ {
+ bfd_set_error (bfd_error_invalid_operation);
+ return 0;
+ }
+
+ return ecoff_data (abfd)->gp;
+}
+
+/* Set the GP value for an ECOFF file. This is a hook used by the
+ assembler. */
+
+boolean
+bfd_ecoff_set_gp_value (abfd, gp_value)
+ bfd *abfd;
+ bfd_vma gp_value;
+{
+ if (bfd_get_flavour (abfd) != bfd_target_ecoff_flavour
+ || bfd_get_format (abfd) != bfd_object)
+ {
+ bfd_set_error (bfd_error_invalid_operation);
+ return false;
+ }
+
+ ecoff_data (abfd)->gp = gp_value;
+
+ return true;
+}
+
+/* Set the register masks for an ECOFF file. This is a hook used by
+ the assembler. */
+
+boolean
+bfd_ecoff_set_regmasks (abfd, gprmask, fprmask, cprmask)
+ bfd *abfd;
+ unsigned long gprmask;
+ unsigned long fprmask;
+ unsigned long *cprmask;
+{
+ ecoff_data_type *tdata;
+
+ if (bfd_get_flavour (abfd) != bfd_target_ecoff_flavour
+ || bfd_get_format (abfd) != bfd_object)
+ {
+ bfd_set_error (bfd_error_invalid_operation);
+ return false;
+ }
+
+ tdata = ecoff_data (abfd);
+ tdata->gprmask = gprmask;
+ tdata->fprmask = fprmask;
+ if (cprmask != (unsigned long *) NULL)
+ {
+ register int i;
+
+ for (i = 0; i < 3; i++)
+ tdata->cprmask[i] = cprmask[i];
+ }
+
+ return true;
+}
+
+/* Get ECOFF EXTR information for an external symbol. This function
+ is passed to bfd_ecoff_debug_externals. */
+
+static boolean
+ecoff_get_extr (sym, esym)
+ asymbol *sym;
+ EXTR *esym;
+{
+ ecoff_symbol_type *ecoff_sym_ptr;
+ bfd *input_bfd;
+
+ if (bfd_asymbol_flavour (sym) != bfd_target_ecoff_flavour
+ || ecoffsymbol (sym)->native == NULL)
+ {
+ /* Don't include debugging, local, or section symbols. */
+ if ((sym->flags & BSF_DEBUGGING) != 0
+ || (sym->flags & BSF_LOCAL) != 0
+ || (sym->flags & BSF_SECTION_SYM) != 0)
+ return false;
+
+ esym->jmptbl = 0;
+ esym->cobol_main = 0;
+ esym->weakext = 0;
+ esym->reserved = 0;
+ esym->ifd = ifdNil;
+ /* FIXME: we can do better than this for st and sc. */
+ esym->asym.st = stGlobal;
+ esym->asym.sc = scAbs;
+ esym->asym.reserved = 0;
+ esym->asym.index = indexNil;
+ return true;
+ }
+
+ ecoff_sym_ptr = ecoffsymbol (sym);
+
+ if (ecoff_sym_ptr->local)
+ return false;
+
+ input_bfd = bfd_asymbol_bfd (sym);
+ (*(ecoff_backend (input_bfd)->debug_swap.swap_ext_in))
+ (input_bfd, ecoff_sym_ptr->native, esym);
+
+ /* If the symbol was defined by the linker, then esym will be
+ undefined but sym will not be. Get a better class for such a
+ symbol. */
+ if ((esym->asym.sc == scUndefined
+ || esym->asym.sc == scSUndefined)
+ && ! bfd_is_und_section (bfd_get_section (sym)))
+ esym->asym.sc = scAbs;
+
+ /* Adjust the FDR index for the symbol by that used for the input
+ BFD. */
+ if (esym->ifd != -1)
+ {
+ struct ecoff_debug_info *input_debug;
+
+ input_debug = &ecoff_data (input_bfd)->debug_info;
+ BFD_ASSERT (esym->ifd < input_debug->symbolic_header.ifdMax);
+ if (input_debug->ifdmap != (RFDT *) NULL)
+ esym->ifd = input_debug->ifdmap[esym->ifd];
+ }
+
+ return true;
+}
+
+/* Set the external symbol index. This routine is passed to
+ bfd_ecoff_debug_externals. */
+
+static void
+ecoff_set_index (sym, indx)
+ asymbol *sym;
+ bfd_size_type indx;
+{
+ ecoff_set_sym_index (sym, indx);
+}
+
+/* Write out an ECOFF file. */
+
+boolean
+_bfd_ecoff_write_object_contents (abfd)
+ bfd *abfd;
+{
+ const struct ecoff_backend_data * const backend = ecoff_backend (abfd);
+ const bfd_vma round = backend->round;
+ const bfd_size_type filhsz = bfd_coff_filhsz (abfd);
+ const bfd_size_type aoutsz = bfd_coff_aoutsz (abfd);
+ const bfd_size_type scnhsz = bfd_coff_scnhsz (abfd);
+ const bfd_size_type external_hdr_size
+ = backend->debug_swap.external_hdr_size;
+ const bfd_size_type external_reloc_size = backend->external_reloc_size;
+ void (* const adjust_reloc_out) PARAMS ((bfd *,
+ const arelent *,
+ struct internal_reloc *))
+ = backend->adjust_reloc_out;
+ void (* const swap_reloc_out) PARAMS ((bfd *,
+ const struct internal_reloc *,
+ PTR))
+ = backend->swap_reloc_out;
+ struct ecoff_debug_info * const debug = &ecoff_data (abfd)->debug_info;
+ HDRR * const symhdr = &debug->symbolic_header;
+ asection *current;
+ unsigned int count;
+ bfd_size_type reloc_size;
+ bfd_size_type text_size;
+ bfd_vma text_start;
+ boolean set_text_start;
+ bfd_size_type data_size;
+ bfd_vma data_start;
+ boolean set_data_start;
+ bfd_size_type bss_size;
+ PTR buff = NULL;
+ PTR reloc_buff = NULL;
+ struct internal_filehdr internal_f;
+ struct internal_aouthdr internal_a;
+ int i;
+
+ /* Determine where the sections and relocs will go in the output
+ file. */
+ reloc_size = ecoff_compute_reloc_file_positions (abfd);
+
+ count = 1;
+ for (current = abfd->sections;
+ current != (asection *)NULL;
+ current = current->next)
+ {
+ current->target_index = count;
+ ++count;
+ }
+
+ if ((abfd->flags & D_PAGED) != 0)
+ text_size = _bfd_ecoff_sizeof_headers (abfd, false);
+ else
+ text_size = 0;
+ text_start = 0;
+ set_text_start = false;
+ data_size = 0;
+ data_start = 0;
+ set_data_start = false;
+ bss_size = 0;
+
+ /* Write section headers to the file. */
+
+ /* Allocate buff big enough to hold a section header,
+ file header, or a.out header. */
+ {
+ bfd_size_type siz;
+ siz = scnhsz;
+ if (siz < filhsz)
+ siz = filhsz;
+ if (siz < aoutsz)
+ siz = aoutsz;
+ buff = (PTR) malloc (siz);
+ if (buff == NULL)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ goto error_return;
+ }
+ }
+
+ internal_f.f_nscns = 0;
+ if (bfd_seek (abfd, (file_ptr) (filhsz + aoutsz), SEEK_SET) != 0)
+ goto error_return;
+ for (current = abfd->sections;
+ current != (asection *) NULL;
+ current = current->next)
+ {
+ struct internal_scnhdr section;
+ bfd_vma vma;
+
+ ++internal_f.f_nscns;
+
+ strncpy (section.s_name, current->name, sizeof section.s_name);
+
+ /* This seems to be correct for Irix 4 shared libraries. */
+ vma = bfd_get_section_vma (abfd, current);
+ if (strcmp (current->name, _LIB) == 0)
+ section.s_vaddr = 0;
+ else
+ section.s_vaddr = vma;
+
+ section.s_paddr = vma;
+ section.s_size = bfd_get_section_size_before_reloc (current);
+
+ /* If this section is unloadable then the scnptr will be 0. */
+ if ((current->flags & (SEC_LOAD | SEC_HAS_CONTENTS)) == 0)
+ section.s_scnptr = 0;
+ else
+ section.s_scnptr = current->filepos;
+ section.s_relptr = current->rel_filepos;
+
+ /* FIXME: the lnnoptr of the .sbss or .sdata section of an
+ object file produced by the assembler is supposed to point to
+ information about how much room is required by objects of
+ various different sizes. I think this only matters if we
+ want the linker to compute the best size to use, or
+ something. I don't know what happens if the information is
+ not present. */
+ if (strcmp (current->name, _PDATA) != 0)
+ section.s_lnnoptr = 0;
+ else
+ {
+ /* The Alpha ECOFF .pdata section uses the lnnoptr field to
+ hold the number of entries in the section (each entry is
+ 8 bytes). We stored this in the line_filepos field in
+ ecoff_compute_section_file_positions. */
+ section.s_lnnoptr = current->line_filepos;
+ }
+
+ section.s_nreloc = current->reloc_count;
+ section.s_nlnno = 0;
+ section.s_flags = ecoff_sec_to_styp_flags (current->name,
+ current->flags);
+
+ bfd_coff_swap_scnhdr_out (abfd, (PTR) &section, buff);
+ if (bfd_write (buff, 1, scnhsz, abfd) != scnhsz)
+ goto error_return;
+
+ if ((section.s_flags & STYP_TEXT) != 0
+ || ((section.s_flags & STYP_RDATA) != 0
+ && backend->rdata_in_text)
+ || strcmp (current->name, _PDATA) == 0)
+ {
+ text_size += bfd_get_section_size_before_reloc (current);
+ if (! set_text_start || text_start > vma)
+ {
+ text_start = vma;
+ set_text_start = true;
+ }
+ }
+ else if ((section.s_flags & STYP_RDATA) != 0
+ || (section.s_flags & STYP_DATA) != 0
+ || (section.s_flags & STYP_LITA) != 0
+ || (section.s_flags & STYP_LIT8) != 0
+ || (section.s_flags & STYP_LIT4) != 0
+ || (section.s_flags & STYP_SDATA) != 0
+ || strcmp (current->name, _XDATA) == 0)
+ {
+ data_size += bfd_get_section_size_before_reloc (current);
+ if (! set_data_start || data_start > vma)
+ {
+ data_start = vma;
+ set_data_start = true;
+ }
+ }
+ else if ((section.s_flags & STYP_BSS) != 0
+ || (section.s_flags & STYP_SBSS) != 0)
+ bss_size += bfd_get_section_size_before_reloc (current);
+ else if ((section.s_flags & STYP_ECOFF_LIB) != 0)
+ /* Do nothing */ ;
+ else
+ abort ();
+ }
+
+ /* Set up the file header. */
+
+ internal_f.f_magic = ecoff_get_magic (abfd);
+
+ /* We will NOT put a fucking timestamp in the header here. Every
+ time you put it back, I will come in and take it out again. I'm
+ sorry. This field does not belong here. We fill it with a 0 so
+ it compares the same but is not a reasonable time. --
+ gnu@cygnus.com. */
+ internal_f.f_timdat = 0;
+
+ if (bfd_get_symcount (abfd) != 0)
+ {
+ /* The ECOFF f_nsyms field is not actually the number of
+ symbols, it's the size of symbolic information header. */
+ internal_f.f_nsyms = external_hdr_size;
+ internal_f.f_symptr = ecoff_data (abfd)->sym_filepos;
+ }
+ else
+ {
+ internal_f.f_nsyms = 0;
+ internal_f.f_symptr = 0;
+ }
+
+ internal_f.f_opthdr = aoutsz;
+
+ internal_f.f_flags = F_LNNO;
+ if (reloc_size == 0)
+ internal_f.f_flags |= F_RELFLG;
+ if (bfd_get_symcount (abfd) == 0)
+ internal_f.f_flags |= F_LSYMS;
+ if (abfd->flags & EXEC_P)
+ internal_f.f_flags |= F_EXEC;
+
+ if (! abfd->xvec->byteorder_big_p)
+ internal_f.f_flags |= F_AR32WR;
+ else
+ internal_f.f_flags |= F_AR32W;
+
+ /* Set up the ``optional'' header. */
+ if ((abfd->flags & D_PAGED) != 0)
+ internal_a.magic = ECOFF_AOUT_ZMAGIC;
+ else
+ internal_a.magic = ECOFF_AOUT_OMAGIC;
+
+ /* FIXME: Is this really correct? */
+ internal_a.vstamp = symhdr->vstamp;
+
+ /* At least on Ultrix, these have to be rounded to page boundaries.
+ FIXME: Is this true on other platforms? */
+ if ((abfd->flags & D_PAGED) != 0)
+ {
+ internal_a.tsize = (text_size + round - 1) &~ (round - 1);
+ internal_a.text_start = text_start &~ (round - 1);
+ internal_a.dsize = (data_size + round - 1) &~ (round - 1);
+ internal_a.data_start = data_start &~ (round - 1);
+ }
+ else
+ {
+ internal_a.tsize = text_size;
+ internal_a.text_start = text_start;
+ internal_a.dsize = data_size;
+ internal_a.data_start = data_start;
+ }
+
+ /* On Ultrix, the initial portions of the .sbss and .bss segments
+ are at the end of the data section. The bsize field in the
+ optional header records how many bss bytes are required beyond
+ those in the data section. The value is not rounded to a page
+ boundary. */
+ if (bss_size < internal_a.dsize - data_size)
+ bss_size = 0;
+ else
+ bss_size -= internal_a.dsize - data_size;
+ internal_a.bsize = bss_size;
+ internal_a.bss_start = internal_a.data_start + internal_a.dsize;
+
+ internal_a.entry = bfd_get_start_address (abfd);
+
+ internal_a.gp_value = ecoff_data (abfd)->gp;
+
+ internal_a.gprmask = ecoff_data (abfd)->gprmask;
+ internal_a.fprmask = ecoff_data (abfd)->fprmask;
+ for (i = 0; i < 4; i++)
+ internal_a.cprmask[i] = ecoff_data (abfd)->cprmask[i];
+
+ /* Write out the file header and the optional header. */
+
+ if (bfd_seek (abfd, (file_ptr) 0, SEEK_SET) != 0)
+ goto error_return;
+
+ bfd_coff_swap_filehdr_out (abfd, (PTR) &internal_f, buff);
+ if (bfd_write (buff, 1, filhsz, abfd) != filhsz)
+ goto error_return;
+
+ bfd_coff_swap_aouthdr_out (abfd, (PTR) &internal_a, buff);
+ if (bfd_write (buff, 1, aoutsz, abfd) != aoutsz)
+ goto error_return;
+
+ /* Build the external symbol information. This must be done before
+ writing out the relocs so that we know the symbol indices. We
+ don't do this if this BFD was created by the backend linker,
+ since it will have already handled the symbols and relocs. */
+ if (! ecoff_data (abfd)->linker)
+ {
+ symhdr->iextMax = 0;
+ symhdr->issExtMax = 0;
+ debug->external_ext = debug->external_ext_end = NULL;
+ debug->ssext = debug->ssext_end = NULL;
+ if (bfd_ecoff_debug_externals (abfd, debug, &backend->debug_swap,
+ (((abfd->flags & EXEC_P) == 0)
+ ? true : false),
+ ecoff_get_extr, ecoff_set_index)
+ == false)
+ goto error_return;
+
+ /* Write out the relocs. */
+ for (current = abfd->sections;
+ current != (asection *) NULL;
+ current = current->next)
+ {
+ arelent **reloc_ptr_ptr;
+ arelent **reloc_end;
+ char *out_ptr;
+
+ if (current->reloc_count == 0)
+ continue;
+
+ reloc_buff =
+ bfd_alloc (abfd, current->reloc_count * external_reloc_size);
+ if (reloc_buff == NULL)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ goto error_return;
+ }
+
+ reloc_ptr_ptr = current->orelocation;
+ reloc_end = reloc_ptr_ptr + current->reloc_count;
+ out_ptr = (char *) reloc_buff;
+ for (;
+ reloc_ptr_ptr < reloc_end;
+ reloc_ptr_ptr++, out_ptr += external_reloc_size)
+ {
+ arelent *reloc;
+ asymbol *sym;
+ struct internal_reloc in;
+
+ memset ((PTR) &in, 0, sizeof in);
+
+ reloc = *reloc_ptr_ptr;
+ sym = *reloc->sym_ptr_ptr;
+
+ in.r_vaddr = (reloc->address
+ + bfd_get_section_vma (abfd, current));
+ in.r_type = reloc->howto->type;
+
+ if ((sym->flags & BSF_SECTION_SYM) == 0)
+ {
+ in.r_symndx = ecoff_get_sym_index (*reloc->sym_ptr_ptr);
+ in.r_extern = 1;
+ }
+ else
+ {
+ CONST char *name;
+
+ name = bfd_get_section_name (abfd, bfd_get_section (sym));
+ if (strcmp (name, ".text") == 0)
+ in.r_symndx = RELOC_SECTION_TEXT;
+ else if (strcmp (name, ".rdata") == 0)
+ in.r_symndx = RELOC_SECTION_RDATA;
+ else if (strcmp (name, ".data") == 0)
+ in.r_symndx = RELOC_SECTION_DATA;
+ else if (strcmp (name, ".sdata") == 0)
+ in.r_symndx = RELOC_SECTION_SDATA;
+ else if (strcmp (name, ".sbss") == 0)
+ in.r_symndx = RELOC_SECTION_SBSS;
+ else if (strcmp (name, ".bss") == 0)
+ in.r_symndx = RELOC_SECTION_BSS;
+ else if (strcmp (name, ".init") == 0)
+ in.r_symndx = RELOC_SECTION_INIT;
+ else if (strcmp (name, ".lit8") == 0)
+ in.r_symndx = RELOC_SECTION_LIT8;
+ else if (strcmp (name, ".lit4") == 0)
+ in.r_symndx = RELOC_SECTION_LIT4;
+ else if (strcmp (name, ".xdata") == 0)
+ in.r_symndx = RELOC_SECTION_XDATA;
+ else if (strcmp (name, ".pdata") == 0)
+ in.r_symndx = RELOC_SECTION_PDATA;
+ else if (strcmp (name, ".fini") == 0)
+ in.r_symndx = RELOC_SECTION_FINI;
+ else if (strcmp (name, ".lita") == 0)
+ in.r_symndx = RELOC_SECTION_LITA;
+ else if (strcmp (name, "*ABS*") == 0)
+ in.r_symndx = RELOC_SECTION_ABS;
+ else
+ abort ();
+ in.r_extern = 0;
+ }
+
+ (*adjust_reloc_out) (abfd, reloc, &in);
+
+ (*swap_reloc_out) (abfd, &in, (PTR) out_ptr);
+ }
+
+ if (bfd_seek (abfd, current->rel_filepos, SEEK_SET) != 0)
+ goto error_return;
+ if (bfd_write (reloc_buff,
+ external_reloc_size, current->reloc_count, abfd)
+ != external_reloc_size * current->reloc_count)
+ goto error_return;
+ bfd_release (abfd, reloc_buff);
+ reloc_buff = NULL;
+ }
+
+ /* Write out the symbolic debugging information. */
+ if (bfd_get_symcount (abfd) > 0)
+ {
+ /* Write out the debugging information. */
+ if (bfd_ecoff_write_debug (abfd, debug, &backend->debug_swap,
+ ecoff_data (abfd)->sym_filepos)
+ == false)
+ goto error_return;
+ }
+ }
+
+ /* The .bss section of a demand paged executable must receive an
+ entire page. If there are symbols, the symbols will start on the
+ next page. If there are no symbols, we must fill out the page by
+ hand. */
+ if (bfd_get_symcount (abfd) == 0
+ && (abfd->flags & EXEC_P) != 0
+ && (abfd->flags & D_PAGED) != 0)
+ {
+ char c;
+
+ if (bfd_seek (abfd, (file_ptr) ecoff_data (abfd)->sym_filepos - 1,
+ SEEK_SET) != 0)
+ goto error_return;
+ if (bfd_read (&c, 1, 1, abfd) == 0)
+ c = 0;
+ if (bfd_seek (abfd, (file_ptr) ecoff_data (abfd)->sym_filepos - 1,
+ SEEK_SET) != 0)
+ goto error_return;
+ if (bfd_write (&c, 1, 1, abfd) != 1)
+ goto error_return;
+ }
+
+ if (reloc_buff != NULL)
+ bfd_release (abfd, reloc_buff);
+ if (buff != NULL)
+ free (buff);
+ return true;
+ error_return:
+ if (reloc_buff != NULL)
+ bfd_release (abfd, reloc_buff);
+ if (buff != NULL)
+ free (buff);
+ return false;
+}
+
+/* Archive handling. ECOFF uses what appears to be a unique type of
+ archive header (armap). The byte ordering of the armap and the
+ contents are encoded in the name of the armap itself. At least for
+ now, we only support archives with the same byte ordering in the
+ armap and the contents.
+
+ The first four bytes in the armap are the number of symbol
+ definitions. This is always a power of two.
+
+ This is followed by the symbol definitions. Each symbol definition
+ occupies 8 bytes. The first four bytes are the offset from the
+ start of the armap strings to the null-terminated string naming
+ this symbol. The second four bytes are the file offset to the
+ archive member which defines this symbol. If the second four bytes
+ are 0, then this is not actually a symbol definition, and it should
+ be ignored.
+
+ The symbols are hashed into the armap with a closed hashing scheme.
+ See the functions below for the details of the algorithm.
+
+ After the symbol definitions comes four bytes holding the size of
+ the string table, followed by the string table itself. */
+
+/* The name of an archive headers looks like this:
+ __________E[BL]E[BL]_ (with a trailing space).
+ The trailing space is changed to an X if the archive is changed to
+ indicate that the armap is out of date.
+
+ The Alpha seems to use ________64E[BL]E[BL]_. */
+
+#define ARMAP_BIG_ENDIAN 'B'
+#define ARMAP_LITTLE_ENDIAN 'L'
+#define ARMAP_MARKER 'E'
+#define ARMAP_START_LENGTH 10
+#define ARMAP_HEADER_MARKER_INDEX 10
+#define ARMAP_HEADER_ENDIAN_INDEX 11
+#define ARMAP_OBJECT_MARKER_INDEX 12
+#define ARMAP_OBJECT_ENDIAN_INDEX 13
+#define ARMAP_END_INDEX 14
+#define ARMAP_END "_ "
+
+/* This is a magic number used in the hashing algorithm. */
+#define ARMAP_HASH_MAGIC 0x9dd68ab5
+
+/* This returns the hash value to use for a string. It also sets
+ *REHASH to the rehash adjustment if the first slot is taken. SIZE
+ is the number of entries in the hash table, and HLOG is the log
+ base 2 of SIZE. */
+
+static unsigned int
+ecoff_armap_hash (s, rehash, size, hlog)
+ CONST char *s;
+ unsigned int *rehash;
+ unsigned int size;
+ unsigned int hlog;
+{
+ unsigned int hash;
+
+ hash = *s++;
+ while (*s != '\0')
+ hash = ((hash >> 27) | (hash << 5)) + *s++;
+ hash *= ARMAP_HASH_MAGIC;
+ *rehash = (hash & (size - 1)) | 1;
+ return hash >> (32 - hlog);
+}
+
+/* Read in the armap. */
+
+boolean
+_bfd_ecoff_slurp_armap (abfd)
+ bfd *abfd;
+{
+ char nextname[17];
+ unsigned int i;
+ struct areltdata *mapdata;
+ bfd_size_type parsed_size;
+ char *raw_armap;
+ struct artdata *ardata;
+ unsigned int count;
+ char *raw_ptr;
+ struct symdef *symdef_ptr;
+ char *stringbase;
+
+ /* Get the name of the first element. */
+ i = bfd_read ((PTR) nextname, 1, 16, abfd);
+ if (i == 0)
+ return true;
+ if (i != 16)
+ return false;
+
+ if (bfd_seek (abfd, (file_ptr) -16, SEEK_CUR) != 0)
+ return false;
+
+ /* Irix 4.0.5F apparently can use either an ECOFF armap or a
+ standard COFF armap. We could move the ECOFF armap stuff into
+ bfd_slurp_armap, but that seems inappropriate since no other
+ target uses this format. Instead, we check directly for a COFF
+ armap. */
+ if (strncmp (nextname, "/ ", 16) == 0)
+ return bfd_slurp_armap (abfd);
+
+ /* See if the first element is an armap. */
+ if (strncmp (nextname, ecoff_backend (abfd)->armap_start,
+ ARMAP_START_LENGTH) != 0
+ || nextname[ARMAP_HEADER_MARKER_INDEX] != ARMAP_MARKER
+ || (nextname[ARMAP_HEADER_ENDIAN_INDEX] != ARMAP_BIG_ENDIAN
+ && nextname[ARMAP_HEADER_ENDIAN_INDEX] != ARMAP_LITTLE_ENDIAN)
+ || nextname[ARMAP_OBJECT_MARKER_INDEX] != ARMAP_MARKER
+ || (nextname[ARMAP_OBJECT_ENDIAN_INDEX] != ARMAP_BIG_ENDIAN
+ && nextname[ARMAP_OBJECT_ENDIAN_INDEX] != ARMAP_LITTLE_ENDIAN)
+ || strncmp (nextname + ARMAP_END_INDEX,
+ ARMAP_END, sizeof ARMAP_END - 1) != 0)
+ {
+ bfd_has_map (abfd) = false;
+ return true;
+ }
+
+ /* Make sure we have the right byte ordering. */
+ if (((nextname[ARMAP_HEADER_ENDIAN_INDEX] == ARMAP_BIG_ENDIAN)
+ ^ (abfd->xvec->header_byteorder_big_p != false))
+ || ((nextname[ARMAP_OBJECT_ENDIAN_INDEX] == ARMAP_BIG_ENDIAN)
+ ^ (abfd->xvec->byteorder_big_p != false)))
+ {
+ bfd_set_error (bfd_error_wrong_format);
+ return false;
+ }
+
+ /* Read in the armap. */
+ ardata = bfd_ardata (abfd);
+ mapdata = _bfd_snarf_ar_hdr (abfd);
+ if (mapdata == (struct areltdata *) NULL)
+ return false;
+ parsed_size = mapdata->parsed_size;
+ bfd_release (abfd, (PTR) mapdata);
+
+ raw_armap = (char *) bfd_alloc (abfd, parsed_size);
+ if (raw_armap == (char *) NULL)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ return false;
+ }
+
+ if (bfd_read ((PTR) raw_armap, 1, parsed_size, abfd) != parsed_size)
+ {
+ if (bfd_get_error () != bfd_error_system_call)
+ bfd_set_error (bfd_error_malformed_archive);
+ bfd_release (abfd, (PTR) raw_armap);
+ return false;
+ }
+
+ ardata->tdata = (PTR) raw_armap;
+
+ count = bfd_h_get_32 (abfd, (PTR) raw_armap);
+
+ ardata->symdef_count = 0;
+ ardata->cache = (struct ar_cache *) NULL;
+
+ /* This code used to overlay the symdefs over the raw archive data,
+ but that doesn't work on a 64 bit host. */
+
+ stringbase = raw_armap + count * 8 + 8;
+
+#ifdef CHECK_ARMAP_HASH
+ {
+ unsigned int hlog;
+
+ /* Double check that I have the hashing algorithm right by making
+ sure that every symbol can be looked up successfully. */
+ hlog = 0;
+ for (i = 1; i < count; i <<= 1)
+ hlog++;
+ BFD_ASSERT (i == count);
+
+ raw_ptr = raw_armap + 4;
+ for (i = 0; i < count; i++, raw_ptr += 8)
+ {
+ unsigned int name_offset, file_offset;
+ unsigned int hash, rehash, srch;
+
+ name_offset = bfd_h_get_32 (abfd, (PTR) raw_ptr);
+ file_offset = bfd_h_get_32 (abfd, (PTR) (raw_ptr + 4));
+ if (file_offset == 0)
+ continue;
+ hash = ecoff_armap_hash (stringbase + name_offset, &rehash, count,
+ hlog);
+ if (hash == i)
+ continue;
+
+ /* See if we can rehash to this location. */
+ for (srch = (hash + rehash) & (count - 1);
+ srch != hash && srch != i;
+ srch = (srch + rehash) & (count - 1))
+ BFD_ASSERT (bfd_h_get_32 (abfd, (PTR) (raw_armap + 8 + srch * 8))
+ != 0);
+ BFD_ASSERT (srch == i);
+ }
+ }
+
+#endif /* CHECK_ARMAP_HASH */
+
+ raw_ptr = raw_armap + 4;
+ for (i = 0; i < count; i++, raw_ptr += 8)
+ if (bfd_h_get_32 (abfd, (PTR) (raw_ptr + 4)) != 0)
+ ++ardata->symdef_count;
+
+ symdef_ptr = ((struct symdef *)
+ bfd_alloc (abfd,
+ ardata->symdef_count * sizeof (struct symdef)));
+ if (!symdef_ptr)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ return false;
+ }
+
+ ardata->symdefs = (carsym *) symdef_ptr;
+
+ raw_ptr = raw_armap + 4;
+ for (i = 0; i < count; i++, raw_ptr += 8)
+ {
+ unsigned int name_offset, file_offset;
+
+ file_offset = bfd_h_get_32 (abfd, (PTR) (raw_ptr + 4));
+ if (file_offset == 0)
+ continue;
+ name_offset = bfd_h_get_32 (abfd, (PTR) raw_ptr);
+ symdef_ptr->s.name = stringbase + name_offset;
+ symdef_ptr->file_offset = file_offset;
+ ++symdef_ptr;
+ }
+
+ ardata->first_file_filepos = bfd_tell (abfd);
+ /* Pad to an even boundary. */
+ ardata->first_file_filepos += ardata->first_file_filepos % 2;
+
+ bfd_has_map (abfd) = true;
+
+ return true;
+}
+
+/* Write out an armap. */
+
+boolean
+_bfd_ecoff_write_armap (abfd, elength, map, orl_count, stridx)
+ bfd *abfd;
+ unsigned int elength;
+ struct orl *map;
+ unsigned int orl_count;
+ int stridx;
+{
+ unsigned int hashsize, hashlog;
+ unsigned int symdefsize;
+ int padit;
+ unsigned int stringsize;
+ unsigned int mapsize;
+ file_ptr firstreal;
+ struct ar_hdr hdr;
+ struct stat statbuf;
+ unsigned int i;
+ bfd_byte temp[4];
+ bfd_byte *hashtable;
+ bfd *current;
+ bfd *last_elt;
+
+ /* Ultrix appears to use as a hash table size the least power of two
+ greater than twice the number of entries. */
+ for (hashlog = 0; (1 << hashlog) <= 2 * orl_count; hashlog++)
+ ;
+ hashsize = 1 << hashlog;
+
+ symdefsize = hashsize * 8;
+ padit = stridx % 2;
+ stringsize = stridx + padit;
+
+ /* Include 8 bytes to store symdefsize and stringsize in output. */
+ mapsize = symdefsize + stringsize + 8;
+
+ firstreal = SARMAG + sizeof (struct ar_hdr) + mapsize + elength;
+
+ memset ((PTR) &hdr, 0, sizeof hdr);
+
+ /* Work out the ECOFF armap name. */
+ strcpy (hdr.ar_name, ecoff_backend (abfd)->armap_start);
+ hdr.ar_name[ARMAP_HEADER_MARKER_INDEX] = ARMAP_MARKER;
+ hdr.ar_name[ARMAP_HEADER_ENDIAN_INDEX] =
+ (abfd->xvec->header_byteorder_big_p
+ ? ARMAP_BIG_ENDIAN
+ : ARMAP_LITTLE_ENDIAN);
+ hdr.ar_name[ARMAP_OBJECT_MARKER_INDEX] = ARMAP_MARKER;
+ hdr.ar_name[ARMAP_OBJECT_ENDIAN_INDEX] =
+ abfd->xvec->byteorder_big_p ? ARMAP_BIG_ENDIAN : ARMAP_LITTLE_ENDIAN;
+ memcpy (hdr.ar_name + ARMAP_END_INDEX, ARMAP_END, sizeof ARMAP_END - 1);
+
+ /* Write the timestamp of the archive header to be just a little bit
+ later than the timestamp of the file, otherwise the linker will
+ complain that the index is out of date. Actually, the Ultrix
+ linker just checks the archive name; the GNU linker may check the
+ date. */
+ stat (abfd->filename, &statbuf);
+ sprintf (hdr.ar_date, "%ld", (long) (statbuf.st_mtime + 60));
+
+ /* The DECstation uses zeroes for the uid, gid and mode of the
+ armap. */
+ hdr.ar_uid[0] = '0';
+ hdr.ar_gid[0] = '0';
+ hdr.ar_mode[0] = '0';
+
+ sprintf (hdr.ar_size, "%-10d", (int) mapsize);
+
+ hdr.ar_fmag[0] = '`';
+ hdr.ar_fmag[1] = '\012';
+
+ /* Turn all null bytes in the header into spaces. */
+ for (i = 0; i < sizeof (struct ar_hdr); i++)
+ if (((char *)(&hdr))[i] == '\0')
+ (((char *)(&hdr))[i]) = ' ';
+
+ if (bfd_write ((PTR) &hdr, 1, sizeof (struct ar_hdr), abfd)
+ != sizeof (struct ar_hdr))
+ return false;
+
+ bfd_h_put_32 (abfd, (bfd_vma) hashsize, temp);
+ if (bfd_write ((PTR) temp, 1, 4, abfd) != 4)
+ return false;
+
+ hashtable = (bfd_byte *) bfd_zalloc (abfd, symdefsize);
+ if (!hashtable)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ return false;
+ }
+
+ current = abfd->archive_head;
+ last_elt = current;
+ for (i = 0; i < orl_count; i++)
+ {
+ unsigned int hash, rehash;
+
+ /* Advance firstreal to the file position of this archive
+ element. */
+ if (((bfd *) map[i].pos) != last_elt)
+ {
+ do
+ {
+ firstreal += arelt_size (current) + sizeof (struct ar_hdr);
+ firstreal += firstreal % 2;
+ current = current->next;
+ }
+ while (current != (bfd *) map[i].pos);
+ }
+
+ last_elt = current;
+
+ hash = ecoff_armap_hash (*map[i].name, &rehash, hashsize, hashlog);
+ if (bfd_h_get_32 (abfd, (PTR) (hashtable + (hash * 8) + 4)) != 0)
+ {
+ unsigned int srch;
+
+ /* The desired slot is already taken. */
+ for (srch = (hash + rehash) & (hashsize - 1);
+ srch != hash;
+ srch = (srch + rehash) & (hashsize - 1))
+ if (bfd_h_get_32 (abfd, (PTR) (hashtable + (srch * 8) + 4)) == 0)
+ break;
+
+ BFD_ASSERT (srch != hash);
+
+ hash = srch;
+ }
+
+ bfd_h_put_32 (abfd, (bfd_vma) map[i].namidx,
+ (PTR) (hashtable + hash * 8));
+ bfd_h_put_32 (abfd, (bfd_vma) firstreal,
+ (PTR) (hashtable + hash * 8 + 4));
+ }
+
+ if (bfd_write ((PTR) hashtable, 1, symdefsize, abfd) != symdefsize)
+ return false;
+
+ bfd_release (abfd, hashtable);
+
+ /* Now write the strings. */
+ bfd_h_put_32 (abfd, (bfd_vma) stringsize, temp);
+ if (bfd_write ((PTR) temp, 1, 4, abfd) != 4)
+ return false;
+ for (i = 0; i < orl_count; i++)
+ {
+ bfd_size_type len;
+
+ len = strlen (*map[i].name) + 1;
+ if (bfd_write ((PTR) (*map[i].name), 1, len, abfd) != len)
+ return false;
+ }
+
+ /* The spec sez this should be a newline. But in order to be
+ bug-compatible for DECstation ar we use a null. */
+ if (padit)
+ {
+ if (bfd_write ("", 1, 1, abfd) != 1)
+ return false;
+ }
+
+ return true;
+}
+
+/* See whether this BFD is an archive. If it is, read in the armap
+ and the extended name table. */
+
+const bfd_target *
+_bfd_ecoff_archive_p (abfd)
+ bfd *abfd;
+{
+ char armag[SARMAG + 1];
+
+ if (bfd_read ((PTR) armag, 1, SARMAG, abfd) != SARMAG
+ || strncmp (armag, ARMAG, SARMAG) != 0)
+ {
+ if (bfd_get_error () != bfd_error_system_call)
+ bfd_set_error (bfd_error_wrong_format);
+ return (const bfd_target *) NULL;
+ }
+
+ /* We are setting bfd_ardata(abfd) here, but since bfd_ardata
+ involves a cast, we can't do it as the left operand of
+ assignment. */
+ abfd->tdata.aout_ar_data =
+ (struct artdata *) bfd_zalloc (abfd, sizeof (struct artdata));
+
+ if (bfd_ardata (abfd) == (struct artdata *) NULL)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ return (const bfd_target *) NULL;
+ }
+
+ bfd_ardata (abfd)->first_file_filepos = SARMAG;
+ bfd_ardata (abfd)->cache = NULL;
+ bfd_ardata (abfd)->archive_head = NULL;
+ bfd_ardata (abfd)->symdefs = NULL;
+ bfd_ardata (abfd)->extended_names = NULL;
+ bfd_ardata (abfd)->tdata = NULL;
+
+ if (_bfd_ecoff_slurp_armap (abfd) == false
+ || _bfd_ecoff_slurp_extended_name_table (abfd) == false)
+ {
+ bfd_release (abfd, bfd_ardata (abfd));
+ abfd->tdata.aout_ar_data = (struct artdata *) NULL;
+ return (const bfd_target *) NULL;
+ }
+
+ return abfd->xvec;
+}
+
+/* ECOFF linker code. */
+
+static struct bfd_hash_entry *ecoff_link_hash_newfunc
+ PARAMS ((struct bfd_hash_entry *entry,
+ struct bfd_hash_table *table,
+ const char *string));
+static boolean ecoff_link_add_archive_symbols
+ PARAMS ((bfd *, struct bfd_link_info *));
+static boolean ecoff_link_check_archive_element
+ PARAMS ((bfd *, struct bfd_link_info *, boolean *pneeded));
+static boolean ecoff_link_add_object_symbols
+ PARAMS ((bfd *, struct bfd_link_info *));
+static boolean ecoff_link_add_externals
+ PARAMS ((bfd *, struct bfd_link_info *, PTR, char *));
+
+/* Routine to create an entry in an ECOFF link hash table. */
+
+static struct bfd_hash_entry *
+ecoff_link_hash_newfunc (entry, table, string)
+ struct bfd_hash_entry *entry;
+ struct bfd_hash_table *table;
+ const char *string;
+{
+ struct ecoff_link_hash_entry *ret = (struct ecoff_link_hash_entry *) entry;
+
+ /* Allocate the structure if it has not already been allocated by a
+ subclass. */
+ if (ret == (struct ecoff_link_hash_entry *) NULL)
+ ret = ((struct ecoff_link_hash_entry *)
+ bfd_hash_allocate (table, sizeof (struct ecoff_link_hash_entry)));
+ if (ret == (struct ecoff_link_hash_entry *) NULL)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ return NULL;
+ }
+
+ /* Call the allocation method of the superclass. */
+ ret = ((struct ecoff_link_hash_entry *)
+ _bfd_link_hash_newfunc ((struct bfd_hash_entry *) ret,
+ table, string));
+
+ if (ret)
+ {
+ /* Set local fields. */
+ ret->indx = -1;
+ ret->abfd = NULL;
+ ret->written = 0;
+ ret->small = 0;
+ }
+ memset ((PTR) &ret->esym, 0, sizeof ret->esym);
+
+ return (struct bfd_hash_entry *) ret;
+}
+
+/* Create an ECOFF link hash table. */
+
+struct bfd_link_hash_table *
+_bfd_ecoff_bfd_link_hash_table_create (abfd)
+ bfd *abfd;
+{
+ struct ecoff_link_hash_table *ret;
+
+ ret = ((struct ecoff_link_hash_table *)
+ malloc (sizeof (struct ecoff_link_hash_table)));
+ if (!ret)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ return NULL;
+ }
+ if (! _bfd_link_hash_table_init (&ret->root, abfd,
+ ecoff_link_hash_newfunc))
+ {
+ free (ret);
+ return (struct bfd_link_hash_table *) NULL;
+ }
+ return &ret->root;
+}
+
+/* Look up an entry in an ECOFF link hash table. */
+
+#define ecoff_link_hash_lookup(table, string, create, copy, follow) \
+ ((struct ecoff_link_hash_entry *) \
+ bfd_link_hash_lookup (&(table)->root, (string), (create), (copy), (follow)))
+
+/* Traverse an ECOFF link hash table. */
+
+#define ecoff_link_hash_traverse(table, func, info) \
+ (bfd_link_hash_traverse \
+ (&(table)->root, \
+ (boolean (*) PARAMS ((struct bfd_link_hash_entry *, PTR))) (func), \
+ (info)))
+
+/* Get the ECOFF link hash table from the info structure. This is
+ just a cast. */
+
+#define ecoff_hash_table(p) ((struct ecoff_link_hash_table *) ((p)->hash))
+
+/* Given an ECOFF BFD, add symbols to the global hash table as
+ appropriate. */
+
+boolean
+_bfd_ecoff_bfd_link_add_symbols (abfd, info)
+ bfd *abfd;
+ struct bfd_link_info *info;
+{
+ switch (bfd_get_format (abfd))
+ {
+ case bfd_object:
+ return ecoff_link_add_object_symbols (abfd, info);
+ case bfd_archive:
+ return ecoff_link_add_archive_symbols (abfd, info);
+ default:
+ bfd_set_error (bfd_error_wrong_format);
+ return false;
+ }
+}
+
+/* Add the symbols from an archive file to the global hash table.
+ This looks through the undefined symbols, looks each one up in the
+ archive hash table, and adds any associated object file. We do not
+ use _bfd_generic_link_add_archive_symbols because ECOFF archives
+ already have a hash table, so there is no reason to construct
+ another one. */
+
+static boolean
+ecoff_link_add_archive_symbols (abfd, info)
+ bfd *abfd;
+ struct bfd_link_info *info;
+{
+ const bfd_byte *raw_armap;
+ struct bfd_link_hash_entry **pundef;
+ unsigned int armap_count;
+ unsigned int armap_log;
+ unsigned int i;
+ const bfd_byte *hashtable;
+ const char *stringbase;
+
+ if (! bfd_has_map (abfd))
+ {
+ bfd_set_error (bfd_error_no_symbols);
+ return false;
+ }
+
+ /* If we don't have any raw data for this archive, as can happen on
+ Irix 4.0.5F, we call the generic routine.
+ FIXME: We should be more clever about this, since someday tdata
+ may get to something for a generic archive. */
+ raw_armap = (const bfd_byte *) bfd_ardata (abfd)->tdata;
+ if (raw_armap == (bfd_byte *) NULL)
+ return (_bfd_generic_link_add_archive_symbols
+ (abfd, info, ecoff_link_check_archive_element));
+
+ armap_count = bfd_h_get_32 (abfd, raw_armap);
+
+ armap_log = 0;
+ for (i = 1; i < armap_count; i <<= 1)
+ armap_log++;
+ BFD_ASSERT (i == armap_count);
+
+ hashtable = raw_armap + 4;
+ stringbase = (const char *) raw_armap + armap_count * 8 + 8;
+
+ /* Look through the list of undefined symbols. */
+ pundef = &info->hash->undefs;
+ while (*pundef != (struct bfd_link_hash_entry *) NULL)
+ {
+ struct bfd_link_hash_entry *h;
+ unsigned int hash, rehash;
+ unsigned int file_offset;
+ const char *name;
+ bfd *element;
+
+ h = *pundef;
+
+ /* When a symbol is defined, it is not necessarily removed from
+ the list. */
+ if (h->type != bfd_link_hash_undefined
+ && h->type != bfd_link_hash_common)
+ {
+ /* Remove this entry from the list, for general cleanliness
+ and because we are going to look through the list again
+ if we search any more libraries. We can't remove the
+ entry if it is the tail, because that would lose any
+ entries we add to the list later on. */
+ if (*pundef != info->hash->undefs_tail)
+ *pundef = (*pundef)->next;
+ else
+ pundef = &(*pundef)->next;
+ continue;
+ }
+
+ /* Native ECOFF linkers do not pull in archive elements merely
+ to satisfy common definitions, so neither do we. We leave
+ them on the list, though, in case we are linking against some
+ other object format. */
+ if (h->type != bfd_link_hash_undefined)
+ {
+ pundef = &(*pundef)->next;
+ continue;
+ }
+
+ /* Look for this symbol in the archive hash table. */
+ hash = ecoff_armap_hash (h->root.string, &rehash, armap_count,
+ armap_log);
+
+ file_offset = bfd_h_get_32 (abfd, hashtable + (hash * 8) + 4);
+ if (file_offset == 0)
+ {
+ /* Nothing in this slot. */
+ pundef = &(*pundef)->next;
+ continue;
+ }
+
+ name = stringbase + bfd_h_get_32 (abfd, hashtable + (hash * 8));
+ if (name[0] != h->root.string[0]
+ || strcmp (name, h->root.string) != 0)
+ {
+ unsigned int srch;
+ boolean found;
+
+ /* That was the wrong symbol. Try rehashing. */
+ found = false;
+ for (srch = (hash + rehash) & (armap_count - 1);
+ srch != hash;
+ srch = (srch + rehash) & (armap_count - 1))
+ {
+ file_offset = bfd_h_get_32 (abfd, hashtable + (srch * 8) + 4);
+ if (file_offset == 0)
+ break;
+ name = stringbase + bfd_h_get_32 (abfd, hashtable + (srch * 8));
+ if (name[0] == h->root.string[0]
+ && strcmp (name, h->root.string) == 0)
+ {
+ found = true;
+ break;
+ }
+ }
+
+ if (! found)
+ {
+ pundef = &(*pundef)->next;
+ continue;
+ }
+
+ hash = srch;
+ }
+
+ element = _bfd_get_elt_at_filepos (abfd, file_offset);
+ if (element == (bfd *) NULL)
+ return false;
+
+ if (! bfd_check_format (element, bfd_object))
+ return false;
+
+ /* Unlike the generic linker, we know that this element provides
+ a definition for an undefined symbol and we know that we want
+ to include it. We don't need to check anything. */
+ if (! (*info->callbacks->add_archive_element) (info, element, name))
+ return false;
+ if (! ecoff_link_add_object_symbols (element, info))
+ return false;
+
+ pundef = &(*pundef)->next;
+ }
+
+ return true;
+}
+
+/* This is called if we used _bfd_generic_link_add_archive_symbols
+ because we were not dealing with an ECOFF archive. */
+
+static boolean
+ecoff_link_check_archive_element (abfd, info, pneeded)
+ bfd *abfd;
+ struct bfd_link_info *info;
+ boolean *pneeded;
+{
+ const struct ecoff_backend_data * const backend = ecoff_backend (abfd);
+ void (* const swap_ext_in) PARAMS ((bfd *, PTR, EXTR *))
+ = backend->debug_swap.swap_ext_in;
+ HDRR *symhdr;
+ bfd_size_type external_ext_size;
+ PTR external_ext = NULL;
+ size_t esize;
+ char *ssext = NULL;
+ char *ext_ptr;
+ char *ext_end;
+
+ *pneeded = false;
+
+ if (! ecoff_slurp_symbolic_header (abfd))
+ goto error_return;
+
+ /* If there are no symbols, we don't want it. */
+ if (bfd_get_symcount (abfd) == 0)
+ goto successful_return;
+
+ symhdr = &ecoff_data (abfd)->debug_info.symbolic_header;
+
+ /* Read in the external symbols and external strings. */
+ external_ext_size = backend->debug_swap.external_ext_size;
+ esize = symhdr->iextMax * external_ext_size;
+ external_ext = (PTR) malloc (esize);
+ if (external_ext == NULL && esize != 0)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ goto error_return;
+ }
+
+ if (bfd_seek (abfd, symhdr->cbExtOffset, SEEK_SET) != 0
+ || bfd_read (external_ext, 1, esize, abfd) != esize)
+ goto error_return;
+
+ ssext = (char *) malloc (symhdr->issExtMax);
+ if (ssext == NULL && symhdr->issExtMax != 0)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ goto error_return;
+ }
+
+ if (bfd_seek (abfd, symhdr->cbSsExtOffset, SEEK_SET) != 0
+ || bfd_read (ssext, 1, symhdr->issExtMax, abfd) != symhdr->issExtMax)
+ goto error_return;
+
+ /* Look through the external symbols to see if they define some
+ symbol that is currently undefined. */
+ ext_ptr = (char *) external_ext;
+ ext_end = ext_ptr + esize;
+ for (; ext_ptr < ext_end; ext_ptr += external_ext_size)
+ {
+ EXTR esym;
+ boolean def;
+ const char *name;
+ struct bfd_link_hash_entry *h;
+
+ (*swap_ext_in) (abfd, (PTR) ext_ptr, &esym);
+
+ /* See if this symbol defines something. */
+ if (esym.asym.st != stGlobal
+ && esym.asym.st != stLabel
+ && esym.asym.st != stProc)
+ continue;
+
+ switch (esym.asym.sc)
+ {
+ case scText:
+ case scData:
+ case scBss:
+ case scAbs:
+ case scSData:
+ case scSBss:
+ case scRData:
+ case scCommon:
+ case scSCommon:
+ case scInit:
+ case scFini:
+ def = true;
+ break;
+ default:
+ def = false;
+ break;
+ }
+
+ if (! def)
+ continue;
+
+ name = ssext + esym.asym.iss;
+ h = bfd_link_hash_lookup (info->hash, name, false, false, true);
+
+ /* Unlike the generic linker, we do not pull in elements because
+ of common symbols. */
+ if (h == (struct bfd_link_hash_entry *) NULL
+ || h->type != bfd_link_hash_undefined)
+ continue;
+
+ /* Include this element. */
+ if (! (*info->callbacks->add_archive_element) (info, abfd, name))
+ goto error_return;
+ if (! ecoff_link_add_externals (abfd, info, external_ext, ssext))
+ goto error_return;
+
+ *pneeded = true;
+ goto successful_return;
+ }
+
+ successful_return:
+ if (external_ext != NULL)
+ free (external_ext);
+ if (ssext != NULL)
+ free (ssext);
+ return true;
+ error_return:
+ if (external_ext != NULL)
+ free (external_ext);
+ if (ssext != NULL)
+ free (ssext);
+ return false;
+}
+
+/* Add symbols from an ECOFF object file to the global linker hash
+ table. */
+
+static boolean
+ecoff_link_add_object_symbols (abfd, info)
+ bfd *abfd;
+ struct bfd_link_info *info;
+{
+ HDRR *symhdr;
+ bfd_size_type external_ext_size;
+ PTR external_ext = NULL;
+ size_t esize;
+ char *ssext = NULL;
+ boolean result;
+
+ if (! ecoff_slurp_symbolic_header (abfd))
+ return false;
+
+ /* If there are no symbols, we don't want it. */
+ if (bfd_get_symcount (abfd) == 0)
+ return true;
+
+ symhdr = &ecoff_data (abfd)->debug_info.symbolic_header;
+
+ /* Read in the external symbols and external strings. */
+ external_ext_size = ecoff_backend (abfd)->debug_swap.external_ext_size;
+ esize = symhdr->iextMax * external_ext_size;
+ external_ext = (PTR) malloc (esize);
+ if (external_ext == NULL && esize != 0)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ goto error_return;
+ }
+
+ if (bfd_seek (abfd, symhdr->cbExtOffset, SEEK_SET) != 0
+ || bfd_read (external_ext, 1, esize, abfd) != esize)
+ goto error_return;
+
+ ssext = (char *) malloc (symhdr->issExtMax);
+ if (ssext == NULL && symhdr->issExtMax != 0)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ goto error_return;
+ }
+
+ if (bfd_seek (abfd, symhdr->cbSsExtOffset, SEEK_SET) != 0
+ || bfd_read (ssext, 1, symhdr->issExtMax, abfd) != symhdr->issExtMax)
+ goto error_return;
+
+ result = ecoff_link_add_externals (abfd, info, external_ext, ssext);
+
+ if (ssext != NULL)
+ free (ssext);
+ if (external_ext != NULL)
+ free (external_ext);
+ return result;
+
+ error_return:
+ if (ssext != NULL)
+ free (ssext);
+ if (external_ext != NULL)
+ free (external_ext);
+ return false;
+}
+
+/* Add the external symbols of an object file to the global linker
+ hash table. The external symbols and strings we are passed are
+ just allocated on the stack, and will be discarded. We must
+ explicitly save any information we may need later on in the link.
+ We do not want to read the external symbol information again. */
+
+static boolean
+ecoff_link_add_externals (abfd, info, external_ext, ssext)
+ bfd *abfd;
+ struct bfd_link_info *info;
+ PTR external_ext;
+ char *ssext;
+{
+ const struct ecoff_backend_data * const backend = ecoff_backend (abfd);
+ void (* const swap_ext_in) PARAMS ((bfd *, PTR, EXTR *))
+ = backend->debug_swap.swap_ext_in;
+ bfd_size_type external_ext_size = backend->debug_swap.external_ext_size;
+ unsigned long ext_count;
+ struct ecoff_link_hash_entry **sym_hash;
+ char *ext_ptr;
+ char *ext_end;
+
+ ext_count = ecoff_data (abfd)->debug_info.symbolic_header.iextMax;
+
+ sym_hash = ((struct ecoff_link_hash_entry **)
+ bfd_alloc (abfd,
+ ext_count * sizeof (struct bfd_link_hash_entry *)));
+ if (!sym_hash)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ return false;
+ }
+ ecoff_data (abfd)->sym_hashes = sym_hash;
+
+ ext_ptr = (char *) external_ext;
+ ext_end = ext_ptr + ext_count * external_ext_size;
+ for (; ext_ptr < ext_end; ext_ptr += external_ext_size, sym_hash++)
+ {
+ EXTR esym;
+ boolean skip;
+ bfd_vma value;
+ asection *section;
+ const char *name;
+ struct ecoff_link_hash_entry *h;
+
+ *sym_hash = NULL;
+
+ (*swap_ext_in) (abfd, (PTR) ext_ptr, &esym);
+
+ /* Skip debugging symbols. */
+ skip = false;
+ switch (esym.asym.st)
+ {
+ case stGlobal:
+ case stStatic:
+ case stLabel:
+ case stProc:
+ case stStaticProc:
+ break;
+ default:
+ skip = true;
+ break;
+ }
+
+ if (skip)
+ continue;
+
+ /* Get the information for this symbol. */
+ value = esym.asym.value;
+ switch (esym.asym.sc)
+ {
+ default:
+ case scNil:
+ case scRegister:
+ case scCdbLocal:
+ case scBits:
+ case scCdbSystem:
+ case scRegImage:
+ case scInfo:
+ case scUserStruct:
+ case scVar:
+ case scVarRegister:
+ case scVariant:
+ case scBasedVar:
+ case scXData:
+ case scPData:
+ section = NULL;
+ break;
+ case scText:
+ section = bfd_make_section_old_way (abfd, ".text");
+ value -= section->vma;
+ break;
+ case scData:
+ section = bfd_make_section_old_way (abfd, ".data");
+ value -= section->vma;
+ break;
+ case scBss:
+ section = bfd_make_section_old_way (abfd, ".bss");
+ value -= section->vma;
+ break;
+ case scAbs:
+ section = bfd_abs_section_ptr;
+ break;
+ case scUndefined:
+ section = bfd_und_section_ptr;
+ break;
+ case scSData:
+ section = bfd_make_section_old_way (abfd, ".sdata");
+ value -= section->vma;
+ break;
+ case scSBss:
+ section = bfd_make_section_old_way (abfd, ".sbss");
+ value -= section->vma;
+ break;
+ case scRData:
+ section = bfd_make_section_old_way (abfd, ".rdata");
+ value -= section->vma;
+ break;
+ case scCommon:
+ if (value > ecoff_data (abfd)->gp_size)
+ {
+ section = bfd_com_section_ptr;
+ break;
+ }
+ /* Fall through. */
+ case scSCommon:
+ if (ecoff_scom_section.name == NULL)
+ {
+ /* Initialize the small common section. */
+ ecoff_scom_section.name = SCOMMON;
+ ecoff_scom_section.flags = SEC_IS_COMMON;
+ ecoff_scom_section.output_section = &ecoff_scom_section;
+ ecoff_scom_section.symbol = &ecoff_scom_symbol;
+ ecoff_scom_section.symbol_ptr_ptr = &ecoff_scom_symbol_ptr;
+ ecoff_scom_symbol.name = SCOMMON;
+ ecoff_scom_symbol.flags = BSF_SECTION_SYM;
+ ecoff_scom_symbol.section = &ecoff_scom_section;
+ ecoff_scom_symbol_ptr = &ecoff_scom_symbol;
+ }
+ section = &ecoff_scom_section;
+ break;
+ case scSUndefined:
+ section = bfd_und_section_ptr;
+ break;
+ case scInit:
+ section = bfd_make_section_old_way (abfd, ".init");
+ value -= section->vma;
+ break;
+ case scFini:
+ section = bfd_make_section_old_way (abfd, ".fini");
+ value -= section->vma;
+ break;
+ }
+
+ if (section == (asection *) NULL)
+ continue;
+
+ name = ssext + esym.asym.iss;
+
+ h = NULL;
+ if (! (_bfd_generic_link_add_one_symbol
+ (info, abfd, name, BSF_GLOBAL, section, value,
+ (const char *) NULL, true, true,
+ (struct bfd_link_hash_entry **) &h)))
+ return false;
+
+ *sym_hash = h;
+
+ /* If we are building an ECOFF hash table, save the external
+ symbol information. */
+ if (info->hash->creator->flavour == bfd_get_flavour (abfd))
+ {
+ if (h->abfd == (bfd *) NULL
+ || (! bfd_is_und_section (section)
+ && (! bfd_is_com_section (section)
+ || h->root.type != bfd_link_hash_defined)))
+ {
+ h->abfd = abfd;
+ h->esym = esym;
+ }
+
+ /* Remember whether this symbol was small undefined. */
+ if (esym.asym.sc == scSUndefined)
+ h->small = 1;
+
+ /* If this symbol was ever small undefined, it needs to wind
+ up in a GP relative section. We can't control the
+ section of a defined symbol, but we can control the
+ section of a common symbol. This case is actually needed
+ on Ultrix 4.2 to handle the symbol cred in -lckrb. */
+ if (h->small
+ && h->root.type == bfd_link_hash_common
+ && strcmp (h->root.u.c.section->name, SCOMMON) != 0)
+ {
+ h->root.u.c.section = bfd_make_section_old_way (abfd, SCOMMON);
+ h->root.u.c.section->flags = SEC_ALLOC;
+ if (h->esym.asym.sc == scCommon)
+ h->esym.asym.sc = scSCommon;
+ }
+ }
+ }
+
+ return true;
+}
+
+/* ECOFF final link routines. */
+
+static boolean ecoff_final_link_debug_accumulate
+ PARAMS ((bfd *output_bfd, bfd *input_bfd, struct bfd_link_info *,
+ PTR handle));
+static boolean ecoff_link_write_external
+ PARAMS ((struct ecoff_link_hash_entry *, PTR));
+static boolean ecoff_indirect_link_order
+ PARAMS ((bfd *, struct bfd_link_info *, asection *,
+ struct bfd_link_order *));
+static boolean ecoff_reloc_link_order
+ PARAMS ((bfd *, struct bfd_link_info *, asection *,
+ struct bfd_link_order *));
+
+/* ECOFF final link routine. This looks through all the input BFDs
+ and gathers together all the debugging information, and then
+ processes all the link order information. This may cause it to
+ close and reopen some input BFDs; I'll see how bad this is. */
+
+boolean
+_bfd_ecoff_bfd_final_link (abfd, info)
+ bfd *abfd;
+ struct bfd_link_info *info;
+{
+ const struct ecoff_backend_data * const backend = ecoff_backend (abfd);
+ struct ecoff_debug_info * const debug = &ecoff_data (abfd)->debug_info;
+ HDRR *symhdr;
+ PTR handle;
+ register bfd *input_bfd;
+ asection *o;
+ struct bfd_link_order *p;
+
+ /* We accumulate the debugging information counts in the symbolic
+ header. */
+ symhdr = &debug->symbolic_header;
+ symhdr->vstamp = 0;
+ symhdr->ilineMax = 0;
+ symhdr->cbLine = 0;
+ symhdr->idnMax = 0;
+ symhdr->ipdMax = 0;
+ symhdr->isymMax = 0;
+ symhdr->ioptMax = 0;
+ symhdr->iauxMax = 0;
+ symhdr->issMax = 0;
+ symhdr->issExtMax = 0;
+ symhdr->ifdMax = 0;
+ symhdr->crfd = 0;
+ symhdr->iextMax = 0;
+
+ /* We accumulate the debugging information itself in the debug_info
+ structure. */
+ debug->line = NULL;
+ debug->external_dnr = NULL;
+ debug->external_pdr = NULL;
+ debug->external_sym = NULL;
+ debug->external_opt = NULL;
+ debug->external_aux = NULL;
+ debug->ss = NULL;
+ debug->ssext = debug->ssext_end = NULL;
+ debug->external_fdr = NULL;
+ debug->external_rfd = NULL;
+ debug->external_ext = debug->external_ext_end = NULL;
+
+ handle = bfd_ecoff_debug_init (abfd, debug, &backend->debug_swap, info);
+ if (handle == (PTR) NULL)
+ return false;
+
+ /* Accumulate the debugging symbols from each input BFD. */
+ for (input_bfd = info->input_bfds;
+ input_bfd != (bfd *) NULL;
+ input_bfd = input_bfd->link_next)
+ {
+ boolean ret;
+
+ if (bfd_get_flavour (input_bfd) == bfd_target_ecoff_flavour)
+ {
+ /* Abitrarily set the symbolic header vstamp to the vstamp
+ of the first object file in the link. */
+ if (symhdr->vstamp == 0)
+ symhdr->vstamp
+ = ecoff_data (input_bfd)->debug_info.symbolic_header.vstamp;
+ ret = ecoff_final_link_debug_accumulate (abfd, input_bfd, info,
+ handle);
+ }
+ else
+ ret = bfd_ecoff_debug_accumulate_other (handle, abfd,
+ debug, &backend->debug_swap,
+ input_bfd, info);
+ if (! ret)
+ return false;
+
+ /* Combine the register masks. */
+ ecoff_data (abfd)->gprmask |= ecoff_data (input_bfd)->gprmask;
+ ecoff_data (abfd)->fprmask |= ecoff_data (input_bfd)->fprmask;
+ ecoff_data (abfd)->cprmask[0] |= ecoff_data (input_bfd)->cprmask[0];
+ ecoff_data (abfd)->cprmask[1] |= ecoff_data (input_bfd)->cprmask[1];
+ ecoff_data (abfd)->cprmask[2] |= ecoff_data (input_bfd)->cprmask[2];
+ ecoff_data (abfd)->cprmask[3] |= ecoff_data (input_bfd)->cprmask[3];
+ }
+
+ /* Write out the external symbols. */
+ ecoff_link_hash_traverse (ecoff_hash_table (info),
+ ecoff_link_write_external,
+ (PTR) abfd);
+
+ if (info->relocateable)
+ {
+ /* We need to make a pass over the link_orders to count up the
+ number of relocations we will need to output, so that we know
+ how much space they will take up. */
+ for (o = abfd->sections; o != (asection *) NULL; o = o->next)
+ {
+ o->reloc_count = 0;
+ for (p = o->link_order_head;
+ p != (struct bfd_link_order *) NULL;
+ p = p->next)
+ if (p->type == bfd_indirect_link_order)
+ o->reloc_count += p->u.indirect.section->reloc_count;
+ else if (p->type == bfd_section_reloc_link_order
+ || p->type == bfd_symbol_reloc_link_order)
+ ++o->reloc_count;
+ }
+ }
+
+ /* Compute the reloc and symbol file positions. */
+ ecoff_compute_reloc_file_positions (abfd);
+
+ /* Write out the debugging information. */
+ if (! bfd_ecoff_write_accumulated_debug (handle, abfd, debug,
+ &backend->debug_swap, info,
+ ecoff_data (abfd)->sym_filepos))
+ return false;
+
+ bfd_ecoff_debug_free (handle, abfd, debug, &backend->debug_swap, info);
+
+ if (info->relocateable)
+ {
+ /* Now reset the reloc_count field of the sections in the output
+ BFD to 0, so that we can use them to keep track of how many
+ relocs we have output thus far. */
+ for (o = abfd->sections; o != (asection *) NULL; o = o->next)
+ o->reloc_count = 0;
+ }
+
+ /* Get a value for the GP register. */
+ if (ecoff_data (abfd)->gp == 0)
+ {
+ struct bfd_link_hash_entry *h;
+
+ h = bfd_link_hash_lookup (info->hash, "_gp", false, false, true);
+ if (h != (struct bfd_link_hash_entry *) NULL
+ && h->type == bfd_link_hash_defined)
+ ecoff_data (abfd)->gp = (h->u.def.value
+ + h->u.def.section->output_section->vma
+ + h->u.def.section->output_offset);
+ else if (info->relocateable)
+ {
+ bfd_vma lo;
+
+ /* Make up a value. */
+ lo = (bfd_vma) -1;
+ for (o = abfd->sections; o != (asection *) NULL; o = o->next)
+ {
+ if (o->vma < lo
+ && (strcmp (o->name, _SBSS) == 0
+ || strcmp (o->name, _SDATA) == 0
+ || strcmp (o->name, _LIT4) == 0
+ || strcmp (o->name, _LIT8) == 0
+ || strcmp (o->name, _LITA) == 0))
+ lo = o->vma;
+ }
+ ecoff_data (abfd)->gp = lo + 0x8000;
+ }
+ else
+ {
+ /* If the relocate_section function needs to do a reloc
+ involving the GP value, it should make a reloc_dangerous
+ callback to warn that GP is not defined. */
+ }
+ }
+
+ for (o = abfd->sections; o != (asection *) NULL; o = o->next)
+ {
+ for (p = o->link_order_head;
+ p != (struct bfd_link_order *) NULL;
+ p = p->next)
+ {
+ if (p->type == bfd_indirect_link_order
+ && (bfd_get_flavour (p->u.indirect.section->owner)
+ == bfd_target_ecoff_flavour))
+ {
+ if (! ecoff_indirect_link_order (abfd, info, o, p))
+ return false;
+ }
+ else if (p->type == bfd_section_reloc_link_order
+ || p->type == bfd_symbol_reloc_link_order)
+ {
+ if (! ecoff_reloc_link_order (abfd, info, o, p))
+ return false;
+ }
+ else
+ {
+ if (! _bfd_default_link_order (abfd, info, o, p))
+ return false;
+ }
+ }
+ }
+
+ bfd_get_symcount (abfd) = symhdr->iextMax + symhdr->isymMax;
+
+ ecoff_data (abfd)->linker = true;
+
+ return true;
+}
+
+/* Accumulate the debugging information for an input BFD into the
+ output BFD. This must read in the symbolic information of the
+ input BFD. */
+
+static boolean
+ecoff_final_link_debug_accumulate (output_bfd, input_bfd, info, handle)
+ bfd *output_bfd;
+ bfd *input_bfd;
+ struct bfd_link_info *info;
+ PTR handle;
+{
+ struct ecoff_debug_info * const debug = &ecoff_data (input_bfd)->debug_info;
+ const struct ecoff_debug_swap * const swap =
+ &ecoff_backend (input_bfd)->debug_swap;
+ HDRR *symhdr = &debug->symbolic_header;
+ boolean ret;
+
+#define READ(ptr, offset, count, size, type) \
+ if (symhdr->count == 0) \
+ debug->ptr = NULL; \
+ else \
+ { \
+ debug->ptr = (type) malloc (size * symhdr->count); \
+ if (debug->ptr == NULL) \
+ { \
+ bfd_set_error (bfd_error_no_memory); \
+ ret = false; \
+ goto return_something; \
+ } \
+ if ((bfd_seek (input_bfd, (file_ptr) symhdr->offset, SEEK_SET) \
+ != 0) \
+ || (bfd_read (debug->ptr, size, symhdr->count, \
+ input_bfd) != size * symhdr->count)) \
+ { \
+ ret = false; \
+ goto return_something; \
+ } \
+ }
+
+ /* If raw_syments is not NULL, then the data was already by read by
+ _bfd_ecoff_slurp_symbolic_info. */
+ if (ecoff_data (input_bfd)->raw_syments == NULL)
+ {
+ READ (line, cbLineOffset, cbLine, sizeof (unsigned char),
+ unsigned char *);
+ READ (external_dnr, cbDnOffset, idnMax, swap->external_dnr_size, PTR);
+ READ (external_pdr, cbPdOffset, ipdMax, swap->external_pdr_size, PTR);
+ READ (external_sym, cbSymOffset, isymMax, swap->external_sym_size, PTR);
+ READ (external_opt, cbOptOffset, ioptMax, swap->external_opt_size, PTR);
+ READ (external_aux, cbAuxOffset, iauxMax, sizeof (union aux_ext),
+ union aux_ext *);
+ READ (ss, cbSsOffset, issMax, sizeof (char), char *);
+ READ (external_fdr, cbFdOffset, ifdMax, swap->external_fdr_size, PTR);
+ READ (external_rfd, cbRfdOffset, crfd, swap->external_rfd_size, PTR);
+ }
+#undef READ
+
+ /* We do not read the external strings or the external symbols. */
+
+ ret = (bfd_ecoff_debug_accumulate
+ (handle, output_bfd, &ecoff_data (output_bfd)->debug_info,
+ &ecoff_backend (output_bfd)->debug_swap,
+ input_bfd, debug, swap, info));
+
+ return_something:
+ if (ecoff_data (input_bfd)->raw_syments == NULL)
+ {
+ if (debug->line != NULL)
+ free (debug->line);
+ if (debug->external_dnr != NULL)
+ free (debug->external_dnr);
+ if (debug->external_pdr != NULL)
+ free (debug->external_pdr);
+ if (debug->external_sym != NULL)
+ free (debug->external_sym);
+ if (debug->external_opt != NULL)
+ free (debug->external_opt);
+ if (debug->external_aux != NULL)
+ free (debug->external_aux);
+ if (debug->ss != NULL)
+ free (debug->ss);
+ if (debug->external_fdr != NULL)
+ free (debug->external_fdr);
+ if (debug->external_rfd != NULL)
+ free (debug->external_rfd);
+
+ /* Make sure we don't accidentally follow one of these pointers
+ into freed memory. */
+ debug->line = NULL;
+ debug->external_dnr = NULL;
+ debug->external_pdr = NULL;
+ debug->external_sym = NULL;
+ debug->external_opt = NULL;
+ debug->external_aux = NULL;
+ debug->ss = NULL;
+ debug->external_fdr = NULL;
+ debug->external_rfd = NULL;
+ }
+
+ return ret;
+}
+
+/* Put out information for an external symbol. These come only from
+ the hash table. */
+
+static boolean
+ecoff_link_write_external (h, data)
+ struct ecoff_link_hash_entry *h;
+ PTR data;
+{
+ bfd *output_bfd = (bfd *) data;
+
+ /* FIXME: We should check if this symbol is being stripped. */
+
+ if (h->written)
+ return true;
+
+ if (h->abfd == (bfd *) NULL)
+ {
+ h->esym.jmptbl = 0;
+ h->esym.cobol_main = 0;
+ h->esym.weakext = 0;
+ h->esym.reserved = 0;
+ h->esym.ifd = ifdNil;
+ h->esym.asym.value = 0;
+ h->esym.asym.st = stGlobal;
+
+ if (h->root.type != bfd_link_hash_defined)
+ h->esym.asym.sc = scAbs;
+ else
+ {
+ asection *output_section;
+ const char *name;
+
+ output_section = h->root.u.def.section->output_section;
+ name = bfd_section_name (output_section->owner, output_section);
+
+ if (strcmp (name, _TEXT) == 0)
+ h->esym.asym.sc = scText;
+ else if (strcmp (name, _DATA) == 0)
+ h->esym.asym.sc = scData;
+ else if (strcmp (name, _SDATA) == 0)
+ h->esym.asym.sc = scSData;
+ else if (strcmp (name, _RDATA) == 0)
+ h->esym.asym.sc = scRData;
+ else if (strcmp (name, _BSS) == 0)
+ h->esym.asym.sc = scBss;
+ else if (strcmp (name, _SBSS) == 0)
+ h->esym.asym.sc = scSBss;
+ else if (strcmp (name, _INIT) == 0)
+ h->esym.asym.sc = scInit;
+ else if (strcmp (name, _FINI) == 0)
+ h->esym.asym.sc = scFini;
+ else if (strcmp (name, _PDATA) == 0)
+ h->esym.asym.sc = scPData;
+ else if (strcmp (name, _XDATA) == 0)
+ h->esym.asym.sc = scXData;
+ else
+ h->esym.asym.sc = scAbs;
+ }
+
+ h->esym.asym.reserved = 0;
+ h->esym.asym.index = indexNil;
+ }
+ else if (h->esym.ifd != -1)
+ {
+ struct ecoff_debug_info *debug;
+
+ /* Adjust the FDR index for the symbol by that used for the
+ input BFD. */
+ debug = &ecoff_data (h->abfd)->debug_info;
+ BFD_ASSERT (h->esym.ifd >= 0
+ && h->esym.ifd < debug->symbolic_header.ifdMax);
+ h->esym.ifd = debug->ifdmap[h->esym.ifd];
+ }
+
+ switch (h->root.type)
+ {
+ default:
+ case bfd_link_hash_new:
+ abort ();
+ case bfd_link_hash_undefined:
+ case bfd_link_hash_weak:
+ if (h->esym.asym.sc != scUndefined
+ && h->esym.asym.sc != scSUndefined)
+ h->esym.asym.sc = scUndefined;
+ break;
+ case bfd_link_hash_defined:
+ if (h->esym.asym.sc == scUndefined
+ || h->esym.asym.sc == scSUndefined)
+ h->esym.asym.sc = scAbs;
+ else if (h->esym.asym.sc == scCommon)
+ h->esym.asym.sc = scBss;
+ else if (h->esym.asym.sc == scSCommon)
+ h->esym.asym.sc = scSBss;
+ h->esym.asym.value = (h->root.u.def.value
+ + h->root.u.def.section->output_section->vma
+ + h->root.u.def.section->output_offset);
+ break;
+ case bfd_link_hash_common:
+ if (h->esym.asym.sc != scCommon
+ && h->esym.asym.sc != scSCommon)
+ h->esym.asym.sc = scCommon;
+ h->esym.asym.value = h->root.u.c.size;
+ break;
+ case bfd_link_hash_indirect:
+ case bfd_link_hash_warning:
+ /* FIXME: Ignore these for now. The circumstances under which
+ they should be written out are not clear to me. */
+ return true;
+ }
+
+ /* bfd_ecoff_debug_one_external uses iextMax to keep track of the
+ symbol number. */
+ h->indx = ecoff_data (output_bfd)->debug_info.symbolic_header.iextMax;
+ h->written = 1;
+
+ return (bfd_ecoff_debug_one_external
+ (output_bfd, &ecoff_data (output_bfd)->debug_info,
+ &ecoff_backend (output_bfd)->debug_swap, h->root.root.string,
+ &h->esym));
+}
+
+/* Relocate and write an ECOFF section into an ECOFF output file. */
+
+static boolean
+ecoff_indirect_link_order (output_bfd, info, output_section, link_order)
+ bfd *output_bfd;
+ struct bfd_link_info *info;
+ asection *output_section;
+ struct bfd_link_order *link_order;
+{
+ asection *input_section;
+ bfd *input_bfd;
+ struct ecoff_section_tdata *section_tdata;
+ bfd_size_type raw_size;
+ bfd_size_type cooked_size;
+ bfd_byte *contents = NULL;
+ bfd_size_type external_reloc_size;
+ bfd_size_type external_relocs_size;
+ PTR external_relocs = NULL;
+
+ BFD_ASSERT ((output_section->flags & SEC_HAS_CONTENTS) != 0);
+
+ if (link_order->size == 0)
+ return true;
+
+ input_section = link_order->u.indirect.section;
+ input_bfd = input_section->owner;
+ section_tdata = ecoff_section_data (input_bfd, input_section);
+
+ raw_size = input_section->_raw_size;
+ cooked_size = input_section->_cooked_size;
+ if (cooked_size == 0)
+ cooked_size = raw_size;
+
+ BFD_ASSERT (input_section->output_section == output_section);
+ BFD_ASSERT (input_section->output_offset == link_order->offset);
+ BFD_ASSERT (cooked_size == link_order->size);
+
+ /* Get the section contents. We allocate memory for the larger of
+ the size before relocating and the size after relocating. */
+ contents = (bfd_byte *) malloc (raw_size >= cooked_size
+ ? raw_size
+ : cooked_size);
+ if (contents == NULL && raw_size != 0)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ goto error_return;
+ }
+
+ /* If we are relaxing, the contents may have already been read into
+ memory, in which case we copy them into our new buffer. We don't
+ simply reuse the old buffer in case cooked_size > raw_size. */
+ if (section_tdata != (struct ecoff_section_tdata *) NULL
+ && section_tdata->contents != (bfd_byte *) NULL)
+ memcpy (contents, section_tdata->contents, raw_size);
+ else
+ {
+ if (! bfd_get_section_contents (input_bfd, input_section,
+ (PTR) contents,
+ (file_ptr) 0, raw_size))
+ goto error_return;
+ }
+
+ /* Get the relocs. If we are relaxing MIPS code, they will already
+ have been read in. Otherwise, we read them in now. */
+ external_reloc_size = ecoff_backend (input_bfd)->external_reloc_size;
+ external_relocs_size = external_reloc_size * input_section->reloc_count;
+
+ if (section_tdata != (struct ecoff_section_tdata *) NULL)
+ external_relocs = section_tdata->external_relocs;
+ else
+ {
+ external_relocs = (PTR) malloc (external_relocs_size);
+ if (external_relocs == NULL && external_relocs_size != 0)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ goto error_return;
+ }
+
+ if (bfd_seek (input_bfd, input_section->rel_filepos, SEEK_SET) != 0
+ || (bfd_read (external_relocs, 1, external_relocs_size, input_bfd)
+ != external_relocs_size))
+ goto error_return;
+ }
+
+ /* Relocate the section contents. */
+ if (! ((*ecoff_backend (input_bfd)->relocate_section)
+ (output_bfd, info, input_bfd, input_section, contents,
+ external_relocs)))
+ goto error_return;
+
+ /* Write out the relocated section. */
+ if (! bfd_set_section_contents (output_bfd,
+ output_section,
+ (PTR) contents,
+ input_section->output_offset,
+ cooked_size))
+ goto error_return;
+
+ /* If we are producing relocateable output, the relocs were
+ modified, and we write them out now. We use the reloc_count
+ field of output_section to keep track of the number of relocs we
+ have output so far. */
+ if (info->relocateable)
+ {
+ if (bfd_seek (output_bfd,
+ (output_section->rel_filepos +
+ output_section->reloc_count * external_reloc_size),
+ SEEK_SET) != 0
+ || (bfd_write (external_relocs, 1, external_relocs_size, output_bfd)
+ != external_relocs_size))
+ goto error_return;
+ output_section->reloc_count += input_section->reloc_count;
+ }
+
+ if (contents != NULL)
+ free (contents);
+ if (external_relocs != NULL && section_tdata == NULL)
+ free (external_relocs);
+ return true;
+
+ error_return:
+ if (contents != NULL)
+ free (contents);
+ if (external_relocs != NULL && section_tdata == NULL)
+ free (external_relocs);
+ return false;
+}
+
+/* Generate a reloc when linking an ECOFF file. This is a reloc
+ requested by the linker, and does come from any input file. This
+ is used to build constructor and destructor tables when linking
+ with -Ur. */
+
+static boolean
+ecoff_reloc_link_order (output_bfd, info, output_section, link_order)
+ bfd *output_bfd;
+ struct bfd_link_info *info;
+ asection *output_section;
+ struct bfd_link_order *link_order;
+{
+ arelent rel;
+ struct internal_reloc in;
+ bfd_size_type external_reloc_size;
+ bfd_byte *rbuf;
+ boolean ok;
+
+ /* We set up an arelent to pass to the backend adjust_reloc_out
+ routine. */
+ rel.address = link_order->offset;
+
+ rel.howto = bfd_reloc_type_lookup (output_bfd, link_order->u.reloc.p->reloc);
+ if (rel.howto == (const reloc_howto_type *) NULL)
+ {
+ bfd_set_error (bfd_error_bad_value);
+ return false;
+ }
+
+ if (link_order->type == bfd_section_reloc_link_order)
+ rel.sym_ptr_ptr = link_order->u.reloc.p->u.section->symbol_ptr_ptr;
+ else
+ {
+ /* We can't set up a reloc against a symbol correctly, because
+ we have no asymbol structure. Currently no adjust_reloc_out
+ routine cases. */
+ rel.sym_ptr_ptr = (asymbol **) NULL;
+ }
+
+ /* All ECOFF relocs are in-place. Put the addend into the object
+ file. */
+
+ BFD_ASSERT (rel.howto->partial_inplace);
+ if (link_order->u.reloc.p->addend != 0)
+ {
+ bfd_size_type size;
+ bfd_reloc_status_type rstat;
+ bfd_byte *buf;
+ boolean ok;
+
+ size = bfd_get_reloc_size (rel.howto);
+ buf = (bfd_byte *) bfd_zmalloc (size);
+ if (buf == (bfd_byte *) NULL)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ return false;
+ }
+ rstat = _bfd_relocate_contents (rel.howto, output_bfd,
+ link_order->u.reloc.p->addend, buf);
+ switch (rstat)
+ {
+ case bfd_reloc_ok:
+ break;
+ default:
+ case bfd_reloc_outofrange:
+ abort ();
+ case bfd_reloc_overflow:
+ if (! ((*info->callbacks->reloc_overflow)
+ (info,
+ (link_order->type == bfd_section_reloc_link_order
+ ? bfd_section_name (output_bfd,
+ link_order->u.reloc.p->u.section)
+ : link_order->u.reloc.p->u.name),
+ rel.howto->name, link_order->u.reloc.p->addend,
+ (bfd *) NULL, (asection *) NULL, (bfd_vma) 0)))
+ {
+ free (buf);
+ return false;
+ }
+ break;
+ }
+ ok = bfd_set_section_contents (output_bfd, output_section, (PTR) buf,
+ (file_ptr) link_order->offset, size);
+ free (buf);
+ if (! ok)
+ return false;
+ }
+
+ rel.addend = 0;
+
+ /* Move the information into a internal_reloc structure. */
+ in.r_vaddr = (rel.address
+ + bfd_get_section_vma (output_bfd, output_section));
+ in.r_type = rel.howto->type;
+
+ if (link_order->type == bfd_symbol_reloc_link_order)
+ {
+ struct ecoff_link_hash_entry *h;
+
+ h = ecoff_link_hash_lookup (ecoff_hash_table (info),
+ link_order->u.reloc.p->u.name,
+ false, false, true);
+ if (h != (struct ecoff_link_hash_entry *) NULL
+ && h->indx != -1)
+ in.r_symndx = h->indx;
+ else
+ {
+ if (! ((*info->callbacks->unattached_reloc)
+ (info, link_order->u.reloc.p->u.name, (bfd *) NULL,
+ (asection *) NULL, (bfd_vma) 0)))
+ return false;
+ in.r_symndx = 0;
+ }
+ in.r_extern = 1;
+ }
+ else
+ {
+ CONST char *name;
+
+ name = bfd_get_section_name (output_bfd,
+ link_order->u.reloc.p->u.section);
+ if (strcmp (name, ".text") == 0)
+ in.r_symndx = RELOC_SECTION_TEXT;
+ else if (strcmp (name, ".rdata") == 0)
+ in.r_symndx = RELOC_SECTION_RDATA;
+ else if (strcmp (name, ".data") == 0)
+ in.r_symndx = RELOC_SECTION_DATA;
+ else if (strcmp (name, ".sdata") == 0)
+ in.r_symndx = RELOC_SECTION_SDATA;
+ else if (strcmp (name, ".sbss") == 0)
+ in.r_symndx = RELOC_SECTION_SBSS;
+ else if (strcmp (name, ".bss") == 0)
+ in.r_symndx = RELOC_SECTION_BSS;
+ else if (strcmp (name, ".init") == 0)
+ in.r_symndx = RELOC_SECTION_INIT;
+ else if (strcmp (name, ".lit8") == 0)
+ in.r_symndx = RELOC_SECTION_LIT8;
+ else if (strcmp (name, ".lit4") == 0)
+ in.r_symndx = RELOC_SECTION_LIT4;
+ else if (strcmp (name, ".xdata") == 0)
+ in.r_symndx = RELOC_SECTION_XDATA;
+ else if (strcmp (name, ".pdata") == 0)
+ in.r_symndx = RELOC_SECTION_PDATA;
+ else if (strcmp (name, ".fini") == 0)
+ in.r_symndx = RELOC_SECTION_FINI;
+ else if (strcmp (name, ".lita") == 0)
+ in.r_symndx = RELOC_SECTION_LITA;
+ else if (strcmp (name, "*ABS*") == 0)
+ in.r_symndx = RELOC_SECTION_ABS;
+ else
+ abort ();
+ in.r_extern = 0;
+ }
+
+ /* Let the BFD backend adjust the reloc. */
+ (*ecoff_backend (output_bfd)->adjust_reloc_out) (output_bfd, &rel, &in);
+
+ /* Get some memory and swap out the reloc. */
+ external_reloc_size = ecoff_backend (output_bfd)->external_reloc_size;
+ rbuf = (bfd_byte *) malloc (external_reloc_size);
+ if (rbuf == (bfd_byte *) NULL)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ return false;
+ }
+
+ (*ecoff_backend (output_bfd)->swap_reloc_out) (output_bfd, &in, (PTR) rbuf);
+
+ ok = (bfd_seek (output_bfd,
+ (output_section->rel_filepos +
+ output_section->reloc_count * external_reloc_size),
+ SEEK_SET) == 0
+ && (bfd_write ((PTR) rbuf, 1, external_reloc_size, output_bfd)
+ == external_reloc_size));
+
+ if (ok)
+ ++output_section->reloc_count;
+
+ free (rbuf);
+
+ return ok;
+}
diff --git a/gnu/usr.bin/gdb/bfd/ecofflink.c b/gnu/usr.bin/gdb/bfd/ecofflink.c
new file mode 100644
index 0000000..f42025e
--- /dev/null
+++ b/gnu/usr.bin/gdb/bfd/ecofflink.c
@@ -0,0 +1,1616 @@
+/* Routines to link ECOFF debugging information.
+ Copyright 1993 Free Software Foundation, Inc.
+ Written by Ian Lance Taylor, Cygnus Support, <ian@cygnus.com>.
+
+This file is part of BFD, the Binary File Descriptor library.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "bfd.h"
+#include "sysdep.h"
+#include "bfdlink.h"
+#include "libbfd.h"
+#include "obstack.h"
+#include "coff/internal.h"
+#include "coff/sym.h"
+#include "coff/symconst.h"
+#include "coff/ecoff.h"
+
+static boolean ecoff_add_bytes PARAMS ((char **buf, char **bufend,
+ size_t need));
+static struct bfd_hash_entry *string_hash_newfunc
+ PARAMS ((struct bfd_hash_entry *, struct bfd_hash_table *,
+ const char *));
+static void ecoff_align_debug PARAMS ((bfd *abfd,
+ struct ecoff_debug_info *debug,
+ const struct ecoff_debug_swap *swap));
+static boolean ecoff_write_symhdr PARAMS ((bfd *, struct ecoff_debug_info *,
+ const struct ecoff_debug_swap *,
+ file_ptr where));
+
+/* Obstack allocation and deallocation routines. */
+#define obstack_chunk_alloc malloc
+#define obstack_chunk_free free
+
+/* The minimum amount of data to allocate. */
+#define ALLOC_SIZE (4064)
+
+/* Add bytes to a buffer. Return success. */
+
+static boolean
+ecoff_add_bytes (buf, bufend, need)
+ char **buf;
+ char **bufend;
+ size_t need;
+{
+ size_t have;
+ size_t want;
+ char *newbuf;
+
+ have = *bufend - *buf;
+ if (have > need)
+ want = ALLOC_SIZE;
+ else
+ {
+ want = need - have;
+ if (want < ALLOC_SIZE)
+ want = ALLOC_SIZE;
+ }
+ if (*buf == NULL)
+ newbuf = (char *) malloc (have + want);
+ else
+ newbuf = (char *) realloc (*buf, have + want);
+ if (newbuf == NULL)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ return false;
+ }
+ *buf = newbuf;
+ *bufend = *buf + have + want;
+ return true;
+}
+
+/* We keep a hash table which maps strings to numbers. We use it to
+ map FDR names to indices in the output file, and to map local
+ strings when combining stabs debugging information. */
+
+struct string_hash_entry
+{
+ struct bfd_hash_entry root;
+ /* FDR index or string table offset. */
+ long val;
+ /* Next entry in string table. */
+ struct string_hash_entry *next;
+};
+
+struct string_hash_table
+{
+ struct bfd_hash_table table;
+};
+
+/* Routine to create an entry in a string hash table. */
+
+static struct bfd_hash_entry *
+string_hash_newfunc (entry, table, string)
+ struct bfd_hash_entry *entry;
+ struct bfd_hash_table *table;
+ const char *string;
+{
+ struct string_hash_entry *ret = (struct string_hash_entry *) entry;
+
+ /* Allocate the structure if it has not already been allocated by a
+ subclass. */
+ if (ret == (struct string_hash_entry *) NULL)
+ ret = ((struct string_hash_entry *)
+ bfd_hash_allocate (table, sizeof (struct string_hash_entry)));
+ if (ret == (struct string_hash_entry *) NULL)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ return NULL;
+ }
+
+ /* Call the allocation method of the superclass. */
+ ret = ((struct string_hash_entry *)
+ bfd_hash_newfunc ((struct bfd_hash_entry *) ret, table, string));
+
+ if (ret)
+ {
+ /* Initialize the local fields. */
+ ret->val = -1;
+ ret->next = NULL;
+ }
+
+ return (struct bfd_hash_entry *) ret;
+}
+
+/* Look up an entry in an string hash table. */
+
+#define string_hash_lookup(t, string, create, copy) \
+ ((struct string_hash_entry *) \
+ bfd_hash_lookup (&(t)->table, (string), (create), (copy)))
+
+/* We can't afford to read in all the debugging information when we do
+ a link. Instead, we build a list of these structures to show how
+ different parts of the input file map to the output file. */
+
+struct shuffle
+{
+ /* The next entry in this linked list. */
+ struct shuffle *next;
+ /* The length of the information. */
+ unsigned long size;
+ /* Whether this information comes from a file or not. */
+ boolean filep;
+ union
+ {
+ struct
+ {
+ /* The BFD the data comes from. */
+ bfd *input_bfd;
+ /* The offset within input_bfd. */
+ file_ptr offset;
+ } file;
+ /* The data to be written out. */
+ PTR memory;
+ } u;
+};
+
+/* This structure holds information across calls to
+ bfd_ecoff_debug_accumulate. */
+
+struct accumulate
+{
+ /* The FDR hash table. */
+ struct string_hash_table fdr_hash;
+ /* The strings hash table. */
+ struct string_hash_table str_hash;
+ /* Linked lists describing how to shuffle the input debug
+ information into the output file. We keep a pointer to both the
+ head and the tail. */
+ struct shuffle *line;
+ struct shuffle *line_end;
+ struct shuffle *pdr;
+ struct shuffle *pdr_end;
+ struct shuffle *sym;
+ struct shuffle *sym_end;
+ struct shuffle *opt;
+ struct shuffle *opt_end;
+ struct shuffle *aux;
+ struct shuffle *aux_end;
+ struct shuffle *ss;
+ struct shuffle *ss_end;
+ struct string_hash_entry *ss_hash;
+ struct string_hash_entry *ss_hash_end;
+ struct shuffle *fdr;
+ struct shuffle *fdr_end;
+ struct shuffle *rfd;
+ struct shuffle *rfd_end;
+ /* The size of the largest file shuffle. */
+ unsigned long largest_file_shuffle;
+ /* An obstack for debugging information. */
+ struct obstack memory;
+};
+
+/* Add a file entry to a shuffle list. */
+
+static boolean add_file_shuffle PARAMS ((struct accumulate *,
+ struct shuffle **,
+ struct shuffle **, bfd *, file_ptr,
+ unsigned long));
+
+static boolean
+add_file_shuffle (ainfo, head, tail, input_bfd, offset, size)
+ struct accumulate *ainfo;
+ struct shuffle **head;
+ struct shuffle **tail;
+ bfd *input_bfd;
+ file_ptr offset;
+ unsigned long size;
+{
+ struct shuffle *n;
+
+ if (*tail != (struct shuffle *) NULL
+ && (*tail)->filep
+ && (*tail)->u.file.input_bfd == input_bfd
+ && (*tail)->u.file.offset + (*tail)->size == offset)
+ {
+ /* Just merge this entry onto the existing one. */
+ (*tail)->size += size;
+ if ((*tail)->size > ainfo->largest_file_shuffle)
+ ainfo->largest_file_shuffle = (*tail)->size;
+ return true;
+ }
+
+ n = (struct shuffle *) obstack_alloc (&ainfo->memory,
+ sizeof (struct shuffle));
+ if (!n)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ return false;
+ }
+ n->next = NULL;
+ n->size = size;
+ n->filep = true;
+ n->u.file.input_bfd = input_bfd;
+ n->u.file.offset = offset;
+ if (*head == (struct shuffle *) NULL)
+ *head = n;
+ if (*tail != (struct shuffle *) NULL)
+ (*tail)->next = n;
+ *tail = n;
+ if (size > ainfo->largest_file_shuffle)
+ ainfo->largest_file_shuffle = size;
+ return true;
+}
+
+/* Add a memory entry to a shuffle list. */
+
+static boolean add_memory_shuffle PARAMS ((struct accumulate *,
+ struct shuffle **head,
+ struct shuffle **tail,
+ bfd_byte *data, unsigned long size));
+
+static boolean
+add_memory_shuffle (ainfo, head, tail, data, size)
+ struct accumulate *ainfo;
+ struct shuffle **head;
+ struct shuffle **tail;
+ bfd_byte *data;
+ unsigned long size;
+{
+ struct shuffle *n;
+
+ n = (struct shuffle *) obstack_alloc (&ainfo->memory,
+ sizeof (struct shuffle));
+ if (!n)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ return false;
+ }
+ n->next = NULL;
+ n->size = size;
+ n->filep = false;
+ n->u.memory = (PTR) data;
+ if (*head == (struct shuffle *) NULL)
+ *head = n;
+ if (*tail != (struct shuffle *) NULL)
+ (*tail)->next = n;
+ *tail = n;
+ return true;
+}
+
+/* Initialize the FDR hash table. This returns a handle which is then
+ passed in to bfd_ecoff_debug_accumulate, et. al. */
+
+/*ARGSUSED*/
+PTR
+bfd_ecoff_debug_init (output_bfd, output_debug, output_swap, info)
+ bfd *output_bfd;
+ struct ecoff_debug_info *output_debug;
+ const struct ecoff_debug_swap *output_swap;
+ struct bfd_link_info *info;
+{
+ struct accumulate *ainfo;
+
+ ainfo = (struct accumulate *) malloc (sizeof (struct accumulate));
+ if (!ainfo)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ return NULL;
+ }
+ if (! bfd_hash_table_init_n (&ainfo->fdr_hash.table, string_hash_newfunc,
+ 1021))
+ return NULL;
+
+ ainfo->line = NULL;
+ ainfo->line_end = NULL;
+ ainfo->pdr = NULL;
+ ainfo->pdr_end = NULL;
+ ainfo->sym = NULL;
+ ainfo->sym_end = NULL;
+ ainfo->opt = NULL;
+ ainfo->opt_end = NULL;
+ ainfo->aux = NULL;
+ ainfo->aux_end = NULL;
+ ainfo->ss = NULL;
+ ainfo->ss_end = NULL;
+ ainfo->ss_hash = NULL;
+ ainfo->ss_hash_end = NULL;
+ ainfo->fdr = NULL;
+ ainfo->fdr_end = NULL;
+ ainfo->rfd = NULL;
+ ainfo->rfd_end = NULL;
+
+ ainfo->largest_file_shuffle = 0;
+
+ if (! info->relocateable)
+ {
+ if (! bfd_hash_table_init (&ainfo->str_hash.table, string_hash_newfunc))
+ return NULL;
+
+ /* The first entry in the string table is the empty string. */
+ output_debug->symbolic_header.issMax = 1;
+ }
+
+ if (!obstack_begin (&ainfo->memory, 4050))
+ {
+ bfd_set_error (bfd_error_no_memory);
+ return NULL;
+ }
+
+ return (PTR) ainfo;
+}
+
+/* Free the accumulated debugging information. */
+
+/*ARGSUSED*/
+void
+bfd_ecoff_debug_free (handle, output_bfd, output_debug, output_swap, info)
+ PTR handle;
+ bfd *output_bfd;
+ struct ecoff_debug_info *output_debug;
+ const struct ecoff_debug_swap *output_swap;
+ struct bfd_link_info *info;
+{
+ struct accumulate *ainfo = (struct accumulate *) handle;
+
+ bfd_hash_table_free (&ainfo->fdr_hash.table);
+
+ if (! info->relocateable)
+ bfd_hash_table_free (&ainfo->str_hash.table);
+
+ obstack_free (&ainfo->memory, (PTR) NULL);
+
+ free (ainfo);
+}
+
+/* Accumulate the debugging information from INPUT_BFD into
+ OUTPUT_BFD. The INPUT_DEBUG argument points to some ECOFF
+ debugging information which we want to link into the information
+ pointed to by the OUTPUT_DEBUG argument. OUTPUT_SWAP and
+ INPUT_SWAP point to the swapping information needed. INFO is the
+ linker information structure. HANDLE is returned by
+ bfd_ecoff_debug_init. */
+
+/*ARGSUSED*/
+boolean
+bfd_ecoff_debug_accumulate (handle, output_bfd, output_debug, output_swap,
+ input_bfd, input_debug, input_swap,
+ info)
+ PTR handle;
+ bfd *output_bfd;
+ struct ecoff_debug_info *output_debug;
+ const struct ecoff_debug_swap *output_swap;
+ bfd *input_bfd;
+ struct ecoff_debug_info *input_debug;
+ const struct ecoff_debug_swap *input_swap;
+ struct bfd_link_info *info;
+{
+ struct accumulate *ainfo = (struct accumulate *) handle;
+ void (* const swap_sym_in) PARAMS ((bfd *, PTR, SYMR *))
+ = input_swap->swap_sym_in;
+ void (* const swap_rfd_in) PARAMS ((bfd *, PTR, RFDT *))
+ = input_swap->swap_rfd_in;
+ void (* const swap_sym_out) PARAMS ((bfd *, const SYMR *, PTR))
+ = output_swap->swap_sym_out;
+ void (* const swap_fdr_out) PARAMS ((bfd *, const FDR *, PTR))
+ = output_swap->swap_fdr_out;
+ void (* const swap_rfd_out) PARAMS ((bfd *, const RFDT *, PTR))
+ = output_swap->swap_rfd_out;
+ bfd_size_type external_pdr_size = output_swap->external_pdr_size;
+ bfd_size_type external_sym_size = output_swap->external_sym_size;
+ bfd_size_type external_opt_size = output_swap->external_opt_size;
+ bfd_size_type external_fdr_size = output_swap->external_fdr_size;
+ bfd_size_type external_rfd_size = output_swap->external_rfd_size;
+ HDRR * const output_symhdr = &output_debug->symbolic_header;
+ HDRR * const input_symhdr = &input_debug->symbolic_header;
+ bfd_vma section_adjust[scMax];
+ asection *sec;
+ bfd_byte *fdr_start;
+ bfd_byte *fdr_ptr;
+ bfd_byte *fdr_end;
+ bfd_size_type fdr_add;
+ unsigned int copied;
+ RFDT i;
+ unsigned long sz;
+ bfd_byte *rfd_out;
+ bfd_byte *rfd_in;
+ bfd_byte *rfd_end;
+ long newrfdbase = 0;
+ long oldrfdbase = 0;
+ bfd_byte *fdr_out;
+
+ /* Use section_adjust to hold the value to add to a symbol in a
+ particular section. */
+ memset ((PTR) section_adjust, 0, sizeof section_adjust);
+
+#define SET(name, indx) \
+ sec = bfd_get_section_by_name (input_bfd, name); \
+ if (sec != NULL) \
+ section_adjust[indx] = (sec->output_section->vma \
+ + sec->output_offset \
+ - sec->vma);
+
+ SET (".text", scText);
+ SET (".data", scData);
+ SET (".bss", scBss);
+ SET (".sdata", scSData);
+ SET (".sbss", scSBss);
+ /* scRdata section may be either .rdata or .rodata. */
+ SET (".rdata", scRData);
+ SET (".rodata", scRData);
+ SET (".init", scInit);
+ SET (".fini", scFini);
+
+#undef SET
+
+ /* Find all the debugging information based on the FDR's. We need
+ to handle them whether they are swapped or not. */
+ if (input_debug->fdr != (FDR *) NULL)
+ {
+ fdr_start = (bfd_byte *) input_debug->fdr;
+ fdr_add = sizeof (FDR);
+ }
+ else
+ {
+ fdr_start = (bfd_byte *) input_debug->external_fdr;
+ fdr_add = input_swap->external_fdr_size;
+ }
+ fdr_end = fdr_start + input_symhdr->ifdMax * fdr_add;
+
+ input_debug->ifdmap = (RFDT *) bfd_alloc (input_bfd,
+ (input_symhdr->ifdMax
+ * sizeof (RFDT)));
+
+ sz = (input_symhdr->crfd + input_symhdr->ifdMax) * external_rfd_size;
+ rfd_out = (bfd_byte *) obstack_alloc (&ainfo->memory, sz);
+ if (!input_debug->ifdmap || !rfd_out)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ return false;
+ }
+ if (!add_memory_shuffle (ainfo, &ainfo->rfd, &ainfo->rfd_end, rfd_out, sz))
+ return false;
+
+ copied = 0;
+
+ /* Look through the FDR's to see which ones we are going to include
+ in the final output. We do not want duplicate FDR information
+ for header files, because ECOFF debugging is often very large.
+ When we find an FDR with no line information which can be merged,
+ we look it up in a hash table to ensure that we only include it
+ once. We keep a table mapping FDR numbers to the final number
+ they get with the BFD, so that we can refer to it when we write
+ out the external symbols. */
+ for (fdr_ptr = fdr_start, i = 0;
+ fdr_ptr < fdr_end;
+ fdr_ptr += fdr_add, i++, rfd_out += external_rfd_size)
+ {
+ FDR fdr;
+
+ if (input_debug->fdr != (FDR *) NULL)
+ fdr = *(FDR *) fdr_ptr;
+ else
+ (*input_swap->swap_fdr_in) (input_bfd, (PTR) fdr_ptr, &fdr);
+
+ /* See if this FDR can be merged with an existing one. */
+ if (fdr.cbLine == 0 && fdr.rss != -1 && fdr.fMerge)
+ {
+ const char *name;
+ char *lookup;
+ struct string_hash_entry *fh;
+
+ /* We look up a string formed from the file name and the
+ number of symbols. Sometimes an include file will
+ conditionally define a typedef or something based on the
+ order of include files. Using the number of symbols as a
+ hash reduces the chance that we will merge symbol
+ information that should not be merged. */
+ name = input_debug->ss + fdr.issBase + fdr.rss;
+
+ lookup = (char *) malloc (strlen (name) + 20);
+ if (lookup == NULL)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ return false;
+ }
+ sprintf (lookup, "%s %lx", name, fdr.csym);
+
+ fh = string_hash_lookup (&ainfo->fdr_hash, lookup, true, true);
+ free (lookup);
+ if (fh == (struct string_hash_entry *) NULL)
+ return false;
+
+ if (fh->val != -1)
+ {
+ input_debug->ifdmap[i] = fh->val;
+ (*swap_rfd_out) (output_bfd, input_debug->ifdmap + i,
+ (PTR) rfd_out);
+
+ /* Don't copy this FDR. */
+ continue;
+ }
+
+ fh->val = output_symhdr->ifdMax + copied;
+ }
+
+ input_debug->ifdmap[i] = output_symhdr->ifdMax + copied;
+ (*swap_rfd_out) (output_bfd, input_debug->ifdmap + i, (PTR) rfd_out);
+ ++copied;
+ }
+
+ newrfdbase = output_symhdr->crfd;
+ output_symhdr->crfd += input_symhdr->ifdMax;
+
+ /* Copy over any existing RFD's. RFD's are only created by the
+ linker, so this will only happen for input files which are the
+ result of a partial link. */
+ rfd_in = (bfd_byte *) input_debug->external_rfd;
+ rfd_end = rfd_in + input_symhdr->crfd * input_swap->external_rfd_size;
+ for (;
+ rfd_in < rfd_end;
+ rfd_in += input_swap->external_rfd_size)
+ {
+ RFDT rfd;
+
+ (*swap_rfd_in) (input_bfd, (PTR) rfd_in, &rfd);
+ BFD_ASSERT (rfd >= 0 && rfd < input_symhdr->ifdMax);
+ rfd = input_debug->ifdmap[rfd];
+ (*swap_rfd_out) (output_bfd, &rfd, (PTR) rfd_out);
+ rfd_out += external_rfd_size;
+ }
+
+ oldrfdbase = output_symhdr->crfd;
+ output_symhdr->crfd += input_symhdr->crfd;
+
+ /* Look through the FDR's and copy over all associated debugging
+ information. */
+ sz = copied * external_fdr_size;
+ fdr_out = (bfd_byte *) obstack_alloc (&ainfo->memory, sz);
+ if (!fdr_out)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ return false;
+ }
+ if (!add_memory_shuffle (ainfo, &ainfo->fdr, &ainfo->fdr_end, fdr_out, sz))
+ return false;
+ for (fdr_ptr = fdr_start, i = 0;
+ fdr_ptr < fdr_end;
+ fdr_ptr += fdr_add, i++)
+ {
+ FDR fdr;
+ bfd_vma fdr_adr;
+ bfd_byte *sym_out;
+ bfd_byte *lraw_src;
+ bfd_byte *lraw_end;
+ boolean fgotfilename;
+
+ if (input_debug->ifdmap[i] < output_symhdr->ifdMax)
+ {
+ /* We are not copying this FDR. */
+ continue;
+ }
+
+ if (input_debug->fdr != (FDR *) NULL)
+ fdr = *(FDR *) fdr_ptr;
+ else
+ (*input_swap->swap_fdr_in) (input_bfd, (PTR) fdr_ptr, &fdr);
+
+ fdr_adr = fdr.adr;
+
+ /* Adjust the FDR address for any changes that may have been
+ made by relaxing. */
+ if (input_debug->adjust != (struct ecoff_value_adjust *) NULL)
+ {
+ struct ecoff_value_adjust *adjust;
+
+ for (adjust = input_debug->adjust;
+ adjust != (struct ecoff_value_adjust *) NULL;
+ adjust = adjust->next)
+ if (fdr_adr >= adjust->start
+ && fdr_adr < adjust->end)
+ fdr.adr += adjust->adjust;
+ }
+
+ /* FIXME: It is conceivable that this FDR points to the .init or
+ .fini section, in which case this will not do the right
+ thing. */
+ fdr.adr += section_adjust[scText];
+
+ /* Swap in the local symbols, adjust their values, and swap them
+ out again. */
+ fgotfilename = false;
+ sz = fdr.csym * external_sym_size;
+ sym_out = (bfd_byte *) obstack_alloc (&ainfo->memory, sz);
+ if (!sym_out)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ return false;
+ }
+ if (!add_memory_shuffle (ainfo, &ainfo->sym, &ainfo->sym_end, sym_out,
+ sz))
+ return false;
+ lraw_src = ((bfd_byte *) input_debug->external_sym
+ + fdr.isymBase * input_swap->external_sym_size);
+ lraw_end = lraw_src + fdr.csym * input_swap->external_sym_size;
+ for (; lraw_src < lraw_end; lraw_src += input_swap->external_sym_size)
+ {
+ SYMR internal_sym;
+
+ (*swap_sym_in) (input_bfd, (PTR) lraw_src, &internal_sym);
+
+ BFD_ASSERT (internal_sym.sc != scCommon
+ && internal_sym.sc != scSCommon);
+
+ /* Adjust the symbol value if appropriate. */
+ switch (internal_sym.st)
+ {
+ case stNil:
+ if (ECOFF_IS_STAB (&internal_sym))
+ break;
+ /* Fall through. */
+ case stGlobal:
+ case stStatic:
+ case stLabel:
+ case stProc:
+ case stStaticProc:
+ if (input_debug->adjust != (struct ecoff_value_adjust *) NULL)
+ {
+ bfd_vma value;
+ struct ecoff_value_adjust *adjust;
+
+ value = internal_sym.value;
+ for (adjust = input_debug->adjust;
+ adjust != (struct ecoff_value_adjust *) NULL;
+ adjust = adjust->next)
+ if (value >= adjust->start
+ && value < adjust->end)
+ internal_sym.value += adjust->adjust;
+ }
+ internal_sym.value += section_adjust[internal_sym.sc];
+ break;
+
+ default:
+ break;
+ }
+
+ /* If we are doing a final link, we hash all the strings in
+ the local symbol table together. This reduces the amount
+ of space required by debugging information. We don't do
+ this when performing a relocateable link because it would
+ prevent us from easily merging different FDR's. */
+ if (! info->relocateable)
+ {
+ boolean ffilename;
+ const char *name;
+
+ if (! fgotfilename && internal_sym.iss == fdr.rss)
+ ffilename = true;
+ else
+ ffilename = false;
+
+ /* Hash the name into the string table. */
+ name = input_debug->ss + fdr.issBase + internal_sym.iss;
+ if (*name == '\0')
+ internal_sym.iss = 0;
+ else
+ {
+ struct string_hash_entry *sh;
+
+ sh = string_hash_lookup (&ainfo->str_hash, name, true, true);
+ if (sh == (struct string_hash_entry *) NULL)
+ return false;
+ if (sh->val == -1)
+ {
+ sh->val = output_symhdr->issMax;
+ output_symhdr->issMax += strlen (name) + 1;
+ if (ainfo->ss_hash == (struct string_hash_entry *) NULL)
+ ainfo->ss_hash = sh;
+ if (ainfo->ss_hash_end
+ != (struct string_hash_entry *) NULL)
+ ainfo->ss_hash_end->next = sh;
+ ainfo->ss_hash_end = sh;
+ }
+ internal_sym.iss = sh->val;
+ }
+
+ if (ffilename)
+ {
+ fdr.rss = internal_sym.iss;
+ fgotfilename = true;
+ }
+ }
+
+ (*swap_sym_out) (output_bfd, &internal_sym, sym_out);
+ sym_out += external_sym_size;
+ }
+
+ fdr.isymBase = output_symhdr->isymMax;
+ output_symhdr->isymMax += fdr.csym;
+
+ /* Copy the information that does not need swapping. */
+
+ /* FIXME: If we are relaxing, we need to adjust the line
+ numbers. Frankly, forget it. Anybody using stabs debugging
+ information will not use this line number information, and
+ stabs are adjusted correctly. */
+ if (fdr.cbLine > 0)
+ {
+ if (!add_file_shuffle (ainfo, &ainfo->line, &ainfo->line_end,
+ input_bfd,
+ input_symhdr->cbLineOffset + fdr.cbLineOffset,
+ fdr.cbLine))
+ return false;
+ fdr.ilineBase = output_symhdr->ilineMax;
+ fdr.cbLineOffset = output_symhdr->cbLine;
+ output_symhdr->ilineMax += fdr.cline;
+ output_symhdr->cbLine += fdr.cbLine;
+ }
+ if (fdr.caux > 0)
+ {
+ if (!add_file_shuffle (ainfo, &ainfo->aux, &ainfo->aux_end,
+ input_bfd,
+ (input_symhdr->cbAuxOffset
+ + fdr.iauxBase * sizeof (union aux_ext)),
+ fdr.caux * sizeof (union aux_ext)))
+ return false;
+ fdr.iauxBase = output_symhdr->iauxMax;
+ output_symhdr->iauxMax += fdr.caux;
+ }
+ if (! info->relocateable)
+ {
+
+ /* When are are hashing strings, we lie about the number of
+ strings attached to each FDR. We need to set cbSs
+ because some versions of dbx apparently use it to decide
+ how much of the string table to read in. */
+ fdr.issBase = 0;
+ fdr.cbSs = output_symhdr->issMax;
+ }
+ else if (fdr.cbSs > 0)
+ {
+ if (!add_file_shuffle (ainfo, &ainfo->ss, &ainfo->ss_end,
+ input_bfd,
+ input_symhdr->cbSsOffset + fdr.issBase,
+ fdr.cbSs))
+ return false;
+ fdr.issBase = output_symhdr->issMax;
+ output_symhdr->issMax += fdr.cbSs;
+ }
+
+ if ((output_bfd->xvec->header_byteorder_big_p
+ == input_bfd->xvec->header_byteorder_big_p)
+ && input_debug->adjust == (struct ecoff_value_adjust *) NULL)
+ {
+ /* The two BFD's have the same endianness, and we don't have
+ to adjust the PDR addresses, so simply copying the
+ information will suffice. */
+ BFD_ASSERT (external_pdr_size == input_swap->external_pdr_size);
+ if (fdr.cpd > 0)
+ {
+ if (!add_file_shuffle (ainfo, &ainfo->pdr, &ainfo->pdr_end,
+ input_bfd,
+ (input_symhdr->cbPdOffset
+ + fdr.ipdFirst * external_pdr_size),
+ fdr.cpd * external_pdr_size))
+ return false;
+ }
+ BFD_ASSERT (external_opt_size == input_swap->external_opt_size);
+ if (fdr.copt > 0)
+ {
+ if (!add_file_shuffle (ainfo, &ainfo->opt, &ainfo->opt_end,
+ input_bfd,
+ (input_symhdr->cbOptOffset
+ + fdr.ioptBase * external_opt_size),
+ fdr.copt * external_opt_size))
+ return false;
+ }
+ }
+ else
+ {
+ bfd_size_type outsz, insz;
+ bfd_byte *in;
+ bfd_byte *end;
+ bfd_byte *out;
+
+ /* The two BFD's have different endianness, so we must swap
+ everything in and out. This code would always work, but
+ it would be unnecessarily slow in the normal case. */
+ outsz = external_pdr_size;
+ insz = input_swap->external_pdr_size;
+ in = ((bfd_byte *) input_debug->external_pdr
+ + fdr.ipdFirst * insz);
+ end = in + fdr.cpd * insz;
+ sz = fdr.cpd * outsz;
+ out = (bfd_byte *) obstack_alloc (&ainfo->memory, sz);
+ if (!out)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ return false;
+ }
+ if (!add_memory_shuffle (ainfo, &ainfo->pdr, &ainfo->pdr_end, out,
+ sz))
+ return false;
+ for (; in < end; in += insz, out += outsz)
+ {
+ PDR pdr;
+
+ (*input_swap->swap_pdr_in) (input_bfd, (PTR) in, &pdr);
+
+ /* If we have been relaxing, we may have to adjust the
+ address. */
+ if (input_debug->adjust != (struct ecoff_value_adjust *) NULL)
+ {
+ bfd_vma adr;
+ struct ecoff_value_adjust *adjust;
+
+ adr = fdr_adr + pdr.adr;
+ for (adjust = input_debug->adjust;
+ adjust != (struct ecoff_value_adjust *) NULL;
+ adjust = adjust->next)
+ if (adr >= adjust->start
+ && adr < adjust->end)
+ pdr.adr += adjust->adjust;
+ }
+
+ (*output_swap->swap_pdr_out) (output_bfd, &pdr, (PTR) out);
+ }
+
+ /* Swap over the optimization information. */
+ outsz = external_opt_size;
+ insz = input_swap->external_opt_size;
+ in = ((bfd_byte *) input_debug->external_opt
+ + fdr.ioptBase * insz);
+ end = in + fdr.copt * insz;
+ sz = fdr.copt * outsz;
+ out = (bfd_byte *) obstack_alloc (&ainfo->memory, sz);
+ if (!out)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ return false;
+ }
+ if (!add_memory_shuffle (ainfo, &ainfo->opt, &ainfo->opt_end, out,
+ sz))
+ return false;
+ for (; in < end; in += insz, out += outsz)
+ {
+ OPTR opt;
+
+ (*input_swap->swap_opt_in) (input_bfd, (PTR) in, &opt);
+ (*output_swap->swap_opt_out) (output_bfd, &opt, (PTR) out);
+ }
+ }
+
+ fdr.ipdFirst = output_symhdr->ipdMax;
+ output_symhdr->ipdMax += fdr.cpd;
+ fdr.ioptBase = output_symhdr->ioptMax;
+ output_symhdr->ioptMax += fdr.copt;
+
+ if (fdr.crfd <= 0)
+ {
+ /* Point this FDR at the table of RFD's we created. */
+ fdr.rfdBase = newrfdbase;
+ fdr.crfd = input_symhdr->ifdMax;
+ }
+ else
+ {
+ /* Point this FDR at the remapped RFD's. */
+ fdr.rfdBase += oldrfdbase;
+ }
+
+ (*swap_fdr_out) (output_bfd, &fdr, fdr_out);
+ fdr_out += external_fdr_size;
+ ++output_symhdr->ifdMax;
+ }
+
+ return true;
+}
+
+/* Add a string to the debugging information we are accumulating.
+ Return the offset from the fdr string base. */
+
+static long ecoff_add_string PARAMS ((struct accumulate *,
+ struct bfd_link_info *,
+ struct ecoff_debug_info *,
+ FDR *fdr, const char *string));
+
+static long
+ecoff_add_string (ainfo, info, debug, fdr, string)
+ struct accumulate *ainfo;
+ struct bfd_link_info *info;
+ struct ecoff_debug_info *debug;
+ FDR *fdr;
+ const char *string;
+{
+ HDRR *symhdr;
+ size_t len;
+ bfd_size_type ret;
+
+ symhdr = &debug->symbolic_header;
+ len = strlen (string);
+ if (info->relocateable)
+ {
+ if (!add_memory_shuffle (ainfo, &ainfo->ss, &ainfo->ss_end, (PTR) string,
+ len + 1))
+ return -1;
+ ret = symhdr->issMax;
+ symhdr->issMax += len + 1;
+ fdr->cbSs += len + 1;
+ }
+ else
+ {
+ struct string_hash_entry *sh;
+
+ sh = string_hash_lookup (&ainfo->str_hash, string, true, true);
+ if (sh == (struct string_hash_entry *) NULL)
+ return -1;
+ if (sh->val == -1)
+ {
+ sh->val = symhdr->issMax;
+ symhdr->issMax += len + 1;
+ if (ainfo->ss_hash == (struct string_hash_entry *) NULL)
+ ainfo->ss_hash = sh;
+ if (ainfo->ss_hash_end
+ != (struct string_hash_entry *) NULL)
+ ainfo->ss_hash_end->next = sh;
+ ainfo->ss_hash_end = sh;
+ }
+ ret = sh->val;
+ }
+
+ return ret;
+}
+
+/* Add debugging information from a non-ECOFF file. */
+
+boolean
+bfd_ecoff_debug_accumulate_other (handle, output_bfd, output_debug,
+ output_swap, input_bfd, info)
+ PTR handle;
+ bfd *output_bfd;
+ struct ecoff_debug_info *output_debug;
+ const struct ecoff_debug_swap *output_swap;
+ bfd *input_bfd;
+ struct bfd_link_info *info;
+{
+ struct accumulate *ainfo = (struct accumulate *) handle;
+ void (* const swap_sym_out) PARAMS ((bfd *, const SYMR *, PTR))
+ = output_swap->swap_sym_out;
+ HDRR *output_symhdr = &output_debug->symbolic_header;
+ FDR fdr;
+ asection *sec;
+ asymbol **symbols;
+ asymbol **sym_ptr;
+ asymbol **sym_end;
+ long symsize;
+ long symcount;
+ PTR external_fdr;
+
+ memset ((PTR) &fdr, 0, sizeof fdr);
+
+ sec = bfd_get_section_by_name (input_bfd, ".text");
+ if (sec != NULL)
+ fdr.adr = sec->output_section->vma + sec->output_offset;
+ else
+ {
+ /* FIXME: What about .init or .fini? */
+ fdr.adr = 0;
+ }
+
+ fdr.issBase = output_symhdr->issMax;
+ fdr.cbSs = 0;
+ fdr.rss = ecoff_add_string (ainfo, info, output_debug, &fdr,
+ bfd_get_filename (input_bfd));
+ if (fdr.rss == -1)
+ return false;
+ fdr.isymBase = output_symhdr->isymMax;
+
+ /* Get the local symbols from the input BFD. */
+ symsize = bfd_get_symtab_upper_bound (input_bfd);
+ if (symsize < 0)
+ return false;
+ symbols = (asymbol **) bfd_alloc (output_bfd, symsize);
+ if (symbols == (asymbol **) NULL)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ return false;
+ }
+ symcount = bfd_canonicalize_symtab (input_bfd, symbols);
+ if (symcount < 0)
+ return false;
+ sym_end = symbols + symcount;
+
+ /* Handle the local symbols. Any external symbols are handled
+ separately. */
+ fdr.csym = 0;
+ for (sym_ptr = symbols; sym_ptr != sym_end; sym_ptr++)
+ {
+ SYMR internal_sym;
+ PTR external_sym;
+
+ if (((*sym_ptr)->flags & BSF_EXPORT) != 0)
+ continue;
+ memset ((PTR) &internal_sym, 0, sizeof internal_sym);
+ internal_sym.iss = ecoff_add_string (ainfo, info, output_debug, &fdr,
+ (*sym_ptr)->name);
+
+ if (internal_sym.iss == -1)
+ return false;
+ if (bfd_is_com_section ((*sym_ptr)->section)
+ || bfd_is_und_section ((*sym_ptr)->section))
+ internal_sym.value = (*sym_ptr)->value;
+ else
+ internal_sym.value = ((*sym_ptr)->value
+ + (*sym_ptr)->section->output_offset
+ + (*sym_ptr)->section->output_section->vma);
+ internal_sym.st = stNil;
+ internal_sym.sc = scUndefined;
+ internal_sym.index = indexNil;
+
+ external_sym = (PTR) obstack_alloc (&ainfo->memory,
+ output_swap->external_sym_size);
+ if (!external_sym)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ return false;
+ }
+ (*swap_sym_out) (output_bfd, &internal_sym, external_sym);
+ add_memory_shuffle (ainfo, &ainfo->sym, &ainfo->sym_end,
+ external_sym, output_swap->external_sym_size);
+ ++fdr.csym;
+ ++output_symhdr->isymMax;
+ }
+
+ bfd_release (output_bfd, (PTR) symbols);
+
+ /* Leave everything else in the FDR zeroed out. This will cause
+ the lang field to be langC. The fBigendian field will
+ indicate little endian format, but it doesn't matter because
+ it only applies to aux fields and there are none. */
+ external_fdr = (PTR) obstack_alloc (&ainfo->memory,
+ output_swap->external_fdr_size);
+ if (!external_fdr)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ return false;
+ }
+ (*output_swap->swap_fdr_out) (output_bfd, &fdr, external_fdr);
+ add_memory_shuffle (ainfo, &ainfo->fdr, &ainfo->fdr_end,
+ external_fdr, output_swap->external_fdr_size);
+
+ ++output_symhdr->ifdMax;
+
+ return true;
+}
+
+/* Set up ECOFF debugging information for the external symbols.
+ FIXME: This is done using a memory buffer, but it should be
+ probably be changed to use a shuffle structure. The assembler uses
+ this interface, so that must be changed to do something else. */
+
+boolean
+bfd_ecoff_debug_externals (abfd, debug, swap, relocateable, get_extr,
+ set_index)
+ bfd *abfd;
+ struct ecoff_debug_info *debug;
+ const struct ecoff_debug_swap *swap;
+ boolean relocateable;
+ boolean (*get_extr) PARAMS ((asymbol *, EXTR *));
+ void (*set_index) PARAMS ((asymbol *, bfd_size_type));
+{
+ HDRR * const symhdr = &debug->symbolic_header;
+ asymbol **sym_ptr_ptr;
+ size_t c;
+
+ sym_ptr_ptr = bfd_get_outsymbols (abfd);
+ if (sym_ptr_ptr == NULL)
+ return true;
+
+ for (c = bfd_get_symcount (abfd); c > 0; c--, sym_ptr_ptr++)
+ {
+ asymbol *sym_ptr;
+ EXTR esym;
+
+ sym_ptr = *sym_ptr_ptr;
+
+ /* Get the external symbol information. */
+ if ((*get_extr) (sym_ptr, &esym) == false)
+ continue;
+
+ /* If we're producing an executable, move common symbols into
+ bss. */
+ if (relocateable == false)
+ {
+ if (esym.asym.sc == scCommon)
+ esym.asym.sc = scBss;
+ else if (esym.asym.sc == scSCommon)
+ esym.asym.sc = scSBss;
+ }
+
+ if (bfd_is_com_section (sym_ptr->section)
+ || bfd_is_und_section (sym_ptr->section)
+ || sym_ptr->section->output_section == (asection *) NULL)
+ {
+ /* FIXME: gas does not keep the value of a small undefined
+ symbol in the symbol itself, because of relocation
+ problems. */
+ if (esym.asym.sc != scSUndefined
+ || esym.asym.value == 0
+ || sym_ptr->value != 0)
+ esym.asym.value = sym_ptr->value;
+ }
+ else
+ esym.asym.value = (sym_ptr->value
+ + sym_ptr->section->output_offset
+ + sym_ptr->section->output_section->vma);
+
+ if (set_index)
+ (*set_index) (sym_ptr, (bfd_size_type) symhdr->iextMax);
+
+ if (! bfd_ecoff_debug_one_external (abfd, debug, swap,
+ sym_ptr->name, &esym))
+ return false;
+ }
+
+ return true;
+}
+
+/* Add a single external symbol to the debugging information. */
+
+boolean
+bfd_ecoff_debug_one_external (abfd, debug, swap, name, esym)
+ bfd *abfd;
+ struct ecoff_debug_info *debug;
+ const struct ecoff_debug_swap *swap;
+ const char *name;
+ EXTR *esym;
+{
+ const bfd_size_type external_ext_size = swap->external_ext_size;
+ void (* const swap_ext_out) PARAMS ((bfd *, const EXTR *, PTR))
+ = swap->swap_ext_out;
+ HDRR * const symhdr = &debug->symbolic_header;
+ size_t namelen;
+
+ namelen = strlen (name);
+
+ if (debug->ssext_end - debug->ssext
+ < symhdr->issExtMax + namelen + 1)
+ {
+ if (ecoff_add_bytes ((char **) &debug->ssext,
+ (char **) &debug->ssext_end,
+ symhdr->issExtMax + namelen + 1)
+ == false)
+ return false;
+ }
+ if ((char *) debug->external_ext_end - (char *) debug->external_ext
+ < (symhdr->iextMax + 1) * external_ext_size)
+ {
+ if (ecoff_add_bytes ((char **) &debug->external_ext,
+ (char **) &debug->external_ext_end,
+ (symhdr->iextMax + 1) * external_ext_size)
+ == false)
+ return false;
+ }
+
+ esym->asym.iss = symhdr->issExtMax;
+
+ (*swap_ext_out) (abfd, esym,
+ ((char *) debug->external_ext
+ + symhdr->iextMax * swap->external_ext_size));
+
+ ++symhdr->iextMax;
+
+ strcpy (debug->ssext + symhdr->issExtMax, name);
+ symhdr->issExtMax += namelen + 1;
+
+ return true;
+}
+
+/* Align the ECOFF debugging information. */
+
+/*ARGSUSED*/
+static void
+ecoff_align_debug (abfd, debug, swap)
+ bfd *abfd;
+ struct ecoff_debug_info *debug;
+ const struct ecoff_debug_swap *swap;
+{
+ HDRR * const symhdr = &debug->symbolic_header;
+ bfd_size_type debug_align, aux_align, rfd_align;
+ size_t add;
+
+ /* Adjust the counts so that structures are aligned. */
+ debug_align = swap->debug_align;
+ aux_align = debug_align / sizeof (union aux_ext);
+ rfd_align = debug_align / swap->external_rfd_size;
+
+ add = debug_align - (symhdr->cbLine & (debug_align - 1));
+ if (add != debug_align)
+ {
+ if (debug->line != (unsigned char *) NULL)
+ memset ((PTR) (debug->line + symhdr->cbLine), 0, add);
+ symhdr->cbLine += add;
+ }
+
+ add = debug_align - (symhdr->issMax & (debug_align - 1));
+ if (add != debug_align)
+ {
+ if (debug->ss != (char *) NULL)
+ memset ((PTR) (debug->ss + symhdr->issMax), 0, add);
+ symhdr->issMax += add;
+ }
+
+ add = debug_align - (symhdr->issExtMax & (debug_align - 1));
+ if (add != debug_align)
+ {
+ if (debug->ssext != (char *) NULL)
+ memset ((PTR) (debug->ssext + symhdr->issExtMax), 0, add);
+ symhdr->issExtMax += add;
+ }
+
+ add = aux_align - (symhdr->iauxMax & (aux_align - 1));
+ if (add != aux_align)
+ {
+ if (debug->external_aux != (union aux_ext *) NULL)
+ memset ((PTR) (debug->external_aux + symhdr->iauxMax), 0,
+ add * sizeof (union aux_ext));
+ symhdr->iauxMax += add;
+ }
+
+ add = rfd_align - (symhdr->crfd & (rfd_align - 1));
+ if (add != rfd_align)
+ {
+ if (debug->external_rfd != (PTR) NULL)
+ memset ((PTR) ((char *) debug->external_rfd
+ + symhdr->crfd * swap->external_rfd_size),
+ 0, add * swap->external_rfd_size);
+ symhdr->crfd += add;
+ }
+}
+
+/* Return the size required by the ECOFF debugging information. */
+
+bfd_size_type
+bfd_ecoff_debug_size (abfd, debug, swap)
+ bfd *abfd;
+ struct ecoff_debug_info *debug;
+ const struct ecoff_debug_swap *swap;
+{
+ bfd_size_type tot;
+
+ ecoff_align_debug (abfd, debug, swap);
+ tot = swap->external_hdr_size;
+
+#define ADD(count, size) \
+ tot += debug->symbolic_header.count * size
+
+ ADD (cbLine, sizeof (unsigned char));
+ ADD (idnMax, swap->external_dnr_size);
+ ADD (ipdMax, swap->external_pdr_size);
+ ADD (isymMax, swap->external_sym_size);
+ ADD (ioptMax, swap->external_opt_size);
+ ADD (iauxMax, sizeof (union aux_ext));
+ ADD (issMax, sizeof (char));
+ ADD (issExtMax, sizeof (char));
+ ADD (ifdMax, swap->external_fdr_size);
+ ADD (crfd, swap->external_rfd_size);
+ ADD (iextMax, swap->external_ext_size);
+
+#undef ADD
+
+ return tot;
+}
+
+/* Write out the ECOFF symbolic header, given the file position it is
+ going to be placed at. This assumes that the counts are set
+ correctly. */
+
+static boolean
+ecoff_write_symhdr (abfd, debug, swap, where)
+ bfd *abfd;
+ struct ecoff_debug_info *debug;
+ const struct ecoff_debug_swap *swap;
+ file_ptr where;
+{
+ HDRR * const symhdr = &debug->symbolic_header;
+ char *buff = NULL;
+
+ ecoff_align_debug (abfd, debug, swap);
+
+ /* Go to the right location in the file. */
+ if (bfd_seek (abfd, where, SEEK_SET) != 0)
+ return false;
+
+ where += swap->external_hdr_size;
+
+ symhdr->magic = swap->sym_magic;
+
+ /* Fill in the file offsets. */
+#define SET(offset, count, size) \
+ if (symhdr->count == 0) \
+ symhdr->offset = 0; \
+ else \
+ { \
+ symhdr->offset = where; \
+ where += symhdr->count * size; \
+ }
+
+ SET (cbLineOffset, cbLine, sizeof (unsigned char));
+ SET (cbDnOffset, idnMax, swap->external_dnr_size);
+ SET (cbPdOffset, ipdMax, swap->external_pdr_size);
+ SET (cbSymOffset, isymMax, swap->external_sym_size);
+ SET (cbOptOffset, ioptMax, swap->external_opt_size);
+ SET (cbAuxOffset, iauxMax, sizeof (union aux_ext));
+ SET (cbSsOffset, issMax, sizeof (char));
+ SET (cbSsExtOffset, issExtMax, sizeof (char));
+ SET (cbFdOffset, ifdMax, swap->external_fdr_size);
+ SET (cbRfdOffset, crfd, swap->external_rfd_size);
+ SET (cbExtOffset, iextMax, swap->external_ext_size);
+#undef SET
+
+ buff = (PTR) malloc (swap->external_hdr_size);
+ if (buff == NULL && swap->external_hdr_size != 0)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ goto error_return;
+ }
+
+ (*swap->swap_hdr_out) (abfd, symhdr, buff);
+ if (bfd_write (buff, 1, swap->external_hdr_size, abfd)
+ != swap->external_hdr_size)
+ goto error_return;
+
+ if (buff != NULL)
+ free (buff);
+ return true;
+ error_return:
+ if (buff != NULL)
+ free (buff);
+ return false;
+}
+
+/* Write out the ECOFF debugging information. This function assumes
+ that the information (the pointers and counts) in *DEBUG have been
+ set correctly. WHERE is the position in the file to write the
+ information to. This function fills in the file offsets in the
+ symbolic header. */
+
+boolean
+bfd_ecoff_write_debug (abfd, debug, swap, where)
+ bfd *abfd;
+ struct ecoff_debug_info *debug;
+ const struct ecoff_debug_swap *swap;
+ file_ptr where;
+{
+ HDRR * const symhdr = &debug->symbolic_header;
+
+ if (! ecoff_write_symhdr (abfd, debug, swap, where))
+ return false;
+
+#define WRITE(ptr, count, size, offset) \
+ BFD_ASSERT (symhdr->offset == 0 || bfd_tell (abfd) == symhdr->offset); \
+ if (bfd_write ((PTR) debug->ptr, size, symhdr->count, abfd) \
+ != size * symhdr->count) \
+ return false;
+
+ WRITE (line, cbLine, sizeof (unsigned char), cbLineOffset);
+ WRITE (external_dnr, idnMax, swap->external_dnr_size, cbDnOffset);
+ WRITE (external_pdr, ipdMax, swap->external_pdr_size, cbPdOffset);
+ WRITE (external_sym, isymMax, swap->external_sym_size, cbSymOffset);
+ WRITE (external_opt, ioptMax, swap->external_opt_size, cbOptOffset);
+ WRITE (external_aux, iauxMax, sizeof (union aux_ext), cbAuxOffset);
+ WRITE (ss, issMax, sizeof (char), cbSsOffset);
+ WRITE (ssext, issExtMax, sizeof (char), cbSsExtOffset);
+ WRITE (external_fdr, ifdMax, swap->external_fdr_size, cbFdOffset);
+ WRITE (external_rfd, crfd, swap->external_rfd_size, cbRfdOffset);
+ WRITE (external_ext, iextMax, swap->external_ext_size, cbExtOffset);
+#undef WRITE
+
+ return true;
+}
+
+/* Write out a shuffle list. */
+
+static boolean ecoff_write_shuffle PARAMS ((bfd *,
+ const struct ecoff_debug_swap *,
+ struct shuffle *, PTR space));
+
+static boolean
+ecoff_write_shuffle (abfd, swap, shuffle, space)
+ bfd *abfd;
+ const struct ecoff_debug_swap *swap;
+ struct shuffle *shuffle;
+ PTR space;
+{
+ register struct shuffle *l;
+ unsigned long total;
+
+ total = 0;
+ for (l = shuffle; l != (struct shuffle *) NULL; l = l->next)
+ {
+ if (! l->filep)
+ {
+ if (bfd_write (l->u.memory, 1, l->size, abfd) != l->size)
+ return false;
+ }
+ else
+ {
+ if (bfd_seek (l->u.file.input_bfd, l->u.file.offset, SEEK_SET) != 0
+ || bfd_read (space, 1, l->size, l->u.file.input_bfd) != l->size
+ || bfd_write (space, 1, l->size, abfd) != l->size)
+ return false;
+ }
+ total += l->size;
+ }
+
+ if ((total & (swap->debug_align - 1)) != 0)
+ {
+ int i;
+ bfd_byte *s;
+
+ i = swap->debug_align - (total & (swap->debug_align - 1));
+ s = (bfd_byte *) malloc (i);
+ if (s == NULL && i != 0)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ return false;
+ }
+
+ memset ((PTR) s, 0, i);
+ if (bfd_write ((PTR) s, 1, i, abfd) != i)
+ {
+ free (s);
+ return false;
+ }
+ free (s);
+ }
+
+ return true;
+}
+
+/* Write out debugging information using accumulated linker
+ information. */
+
+boolean
+bfd_ecoff_write_accumulated_debug (handle, abfd, debug, swap, info, where)
+ PTR handle;
+ bfd *abfd;
+ struct ecoff_debug_info *debug;
+ const struct ecoff_debug_swap *swap;
+ struct bfd_link_info *info;
+ file_ptr where;
+{
+ struct accumulate *ainfo = (struct accumulate *) handle;
+ PTR space = NULL;
+
+ if (! ecoff_write_symhdr (abfd, debug, swap, where))
+ goto error_return;
+
+ space = (PTR) malloc (ainfo->largest_file_shuffle);
+ if (space == NULL && ainfo->largest_file_shuffle != 0)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ goto error_return;
+ }
+
+ if (! ecoff_write_shuffle (abfd, swap, ainfo->line, space)
+ || ! ecoff_write_shuffle (abfd, swap, ainfo->pdr, space)
+ || ! ecoff_write_shuffle (abfd, swap, ainfo->sym, space)
+ || ! ecoff_write_shuffle (abfd, swap, ainfo->opt, space)
+ || ! ecoff_write_shuffle (abfd, swap, ainfo->aux, space))
+ goto error_return;
+
+ /* The string table is written out from the hash table if this is a
+ final link. */
+ if (info->relocateable)
+ {
+ BFD_ASSERT (ainfo->ss_hash == (struct string_hash_entry *) NULL);
+ if (! ecoff_write_shuffle (abfd, swap, ainfo->ss, space))
+ goto error_return;
+ }
+ else
+ {
+ unsigned long total;
+ bfd_byte null;
+ struct string_hash_entry *sh;
+
+ BFD_ASSERT (ainfo->ss == (struct shuffle *) NULL);
+ null = 0;
+ if (bfd_write ((PTR) &null, 1, 1, abfd) != 1)
+ goto error_return;
+ total = 1;
+ BFD_ASSERT (ainfo->ss_hash == NULL || ainfo->ss_hash->val == 1);
+ for (sh = ainfo->ss_hash;
+ sh != (struct string_hash_entry *) NULL;
+ sh = sh->next)
+ {
+ size_t len;
+
+ len = strlen (sh->root.string);
+ if (bfd_write ((PTR) sh->root.string, 1, len + 1, abfd) != len + 1)
+ goto error_return;
+ total += len + 1;
+ }
+
+ if ((total & (swap->debug_align - 1)) != 0)
+ {
+ int i;
+ bfd_byte *s;
+
+ i = swap->debug_align - (total & (swap->debug_align - 1));
+ s = (bfd_byte *) malloc (i);
+ if (s == NULL && i != 0)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ goto error_return;
+ }
+ memset ((PTR) s, 0, i);
+ if (bfd_write ((PTR) s, 1, i, abfd) != i)
+ {
+ free (s);
+ goto error_return;
+ }
+ free (s);
+ }
+ }
+
+ /* The external strings and symbol are not converted over to using
+ shuffles. FIXME: They probably should be. */
+ if (bfd_write (debug->ssext, 1, debug->symbolic_header.issExtMax, abfd)
+ != debug->symbolic_header.issExtMax)
+ goto error_return;
+ if ((debug->symbolic_header.issExtMax & (swap->debug_align - 1)) != 0)
+ {
+ int i;
+ bfd_byte *s;
+
+ i = (swap->debug_align
+ - (debug->symbolic_header.issExtMax & (swap->debug_align - 1)));
+ s = (bfd_byte *) malloc (i);
+ if (s == NULL && i != 0)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ goto error_return;
+ }
+ memset ((PTR) s, 0, i);
+ if (bfd_write ((PTR) s, 1, i, abfd) != i)
+ {
+ free (s);
+ goto error_return;
+ }
+ free (s);
+ }
+
+ if (! ecoff_write_shuffle (abfd, swap, ainfo->fdr, space)
+ || ! ecoff_write_shuffle (abfd, swap, ainfo->rfd, space))
+ goto error_return;
+
+ BFD_ASSERT (debug->symbolic_header.cbExtOffset == 0
+ || debug->symbolic_header.cbExtOffset == bfd_tell (abfd));
+
+ if (bfd_write (debug->external_ext, swap->external_ext_size,
+ debug->symbolic_header.iextMax, abfd)
+ != debug->symbolic_header.iextMax * swap->external_ext_size)
+ goto error_return;
+
+ if (space != NULL)
+ free (space);
+ return true;
+
+ error_return:
+ if (space != NULL)
+ free (space);
+ return false;
+}
diff --git a/gnu/usr.bin/gdb/bfd/elf.c b/gnu/usr.bin/gdb/bfd/elf.c
new file mode 100644
index 0000000..af3e202
--- /dev/null
+++ b/gnu/usr.bin/gdb/bfd/elf.c
@@ -0,0 +1,397 @@
+/* ELF executable support for BFD.
+ Copyright 1993 Free Software Foundation, Inc.
+
+This file is part of BFD, the Binary File Descriptor library.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/*
+
+SECTION
+ ELF backends
+
+ BFD support for ELF formats is being worked on.
+ Currently, the best supported back ends are for sparc and i386
+ (running svr4 or Solaris 2).
+
+ Documentation of the internals of the support code still needs
+ to be written. The code is changing quickly enough that we
+ haven't bothered yet.
+ */
+
+#include "bfd.h"
+#include "sysdep.h"
+#include "bfdlink.h"
+#include "libbfd.h"
+#define ARCH_SIZE 0
+#include "libelf.h"
+
+/* Standard ELF hash function. Do not change this function; you will
+ cause invalid hash tables to be generated. (Well, you would if this
+ were being used yet.) */
+unsigned long
+bfd_elf_hash (name)
+ CONST unsigned char *name;
+{
+ unsigned long h = 0;
+ unsigned long g;
+ int ch;
+
+ while ((ch = *name++) != '\0')
+ {
+ h = (h << 4) + ch;
+ if ((g = (h & 0xf0000000)) != 0)
+ {
+ h ^= g >> 24;
+ h &= ~g;
+ }
+ }
+ return h;
+}
+
+/* Read a specified number of bytes at a specified offset in an ELF
+ file, into a newly allocated buffer, and return a pointer to the
+ buffer. */
+
+static char *
+elf_read (abfd, offset, size)
+ bfd * abfd;
+ long offset;
+ int size;
+{
+ char *buf;
+
+ if ((buf = bfd_alloc (abfd, size)) == NULL)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ return NULL;
+ }
+ if (bfd_seek (abfd, offset, SEEK_SET) == -1)
+ return NULL;
+ if (bfd_read ((PTR) buf, size, 1, abfd) != size)
+ {
+ if (bfd_get_error () != bfd_error_system_call)
+ bfd_set_error (bfd_error_file_truncated);
+ return NULL;
+ }
+ return buf;
+}
+
+boolean
+elf_mkobject (abfd)
+ bfd * abfd;
+{
+ /* this just does initialization */
+ /* coff_mkobject zalloc's space for tdata.coff_obj_data ... */
+ elf_tdata (abfd) = (struct elf_obj_tdata *)
+ bfd_zalloc (abfd, sizeof (struct elf_obj_tdata));
+ if (elf_tdata (abfd) == 0)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ return false;
+ }
+ /* since everything is done at close time, do we need any
+ initialization? */
+
+ return true;
+}
+
+char *
+elf_get_str_section (abfd, shindex)
+ bfd * abfd;
+ unsigned int shindex;
+{
+ Elf_Internal_Shdr **i_shdrp;
+ char *shstrtab = NULL;
+ unsigned int offset;
+ unsigned int shstrtabsize;
+
+ i_shdrp = elf_elfsections (abfd);
+ if (i_shdrp == 0 || i_shdrp[shindex] == 0)
+ return 0;
+
+ shstrtab = i_shdrp[shindex]->rawdata;
+ if (shstrtab == NULL)
+ {
+ /* No cached one, attempt to read, and cache what we read. */
+ offset = i_shdrp[shindex]->sh_offset;
+ shstrtabsize = i_shdrp[shindex]->sh_size;
+ shstrtab = elf_read (abfd, offset, shstrtabsize);
+ i_shdrp[shindex]->rawdata = (void *) shstrtab;
+ }
+ return shstrtab;
+}
+
+char *
+elf_string_from_elf_section (abfd, shindex, strindex)
+ bfd * abfd;
+ unsigned int shindex;
+ unsigned int strindex;
+{
+ Elf_Internal_Shdr *hdr;
+
+ if (strindex == 0)
+ return "";
+
+ hdr = elf_elfsections (abfd)[shindex];
+
+ if (!hdr->rawdata
+ && elf_get_str_section (abfd, shindex) == NULL)
+ return NULL;
+
+ return ((char *) hdr->rawdata) + strindex;
+}
+
+/* Make a BFD section from an ELF section. We store a pointer to the
+ BFD section in the rawdata field of the header. */
+
+boolean
+_bfd_elf_make_section_from_shdr (abfd, hdr, name)
+ bfd *abfd;
+ Elf_Internal_Shdr *hdr;
+ const char *name;
+{
+ asection *newsect;
+ flagword flags;
+
+ if (hdr->rawdata != NULL)
+ {
+ BFD_ASSERT (strcmp (name, ((asection *) hdr->rawdata)->name) == 0);
+ return true;
+ }
+
+ newsect = bfd_make_section_anyway (abfd, name);
+ if (newsect == NULL)
+ return false;
+
+ newsect->filepos = hdr->sh_offset;
+
+ if (! bfd_set_section_vma (abfd, newsect, hdr->sh_addr)
+ || ! bfd_set_section_size (abfd, newsect, hdr->sh_size)
+ || ! bfd_set_section_alignment (abfd, newsect,
+ bfd_log2 (hdr->sh_addralign)))
+ return false;
+
+ flags = SEC_NO_FLAGS;
+ if (hdr->sh_type != SHT_NOBITS)
+ flags |= SEC_HAS_CONTENTS;
+ if ((hdr->sh_flags & SHF_ALLOC) != 0)
+ {
+ flags |= SEC_ALLOC;
+ if (hdr->sh_type != SHT_NOBITS)
+ flags |= SEC_LOAD;
+ }
+ if ((hdr->sh_flags & SHF_WRITE) == 0)
+ flags |= SEC_READONLY;
+ if ((hdr->sh_flags & SHF_EXECINSTR) != 0)
+ flags |= SEC_CODE;
+ else if ((flags & SEC_LOAD) != 0)
+ flags |= SEC_DATA;
+
+ /* The debugging sections appear to be recognized only by name, not
+ any sort of flag. */
+ if (strncmp (name, ".debug", sizeof ".debug" - 1) == 0
+ || strncmp (name, ".line", sizeof ".line" - 1) == 0
+ || strncmp (name, ".stab", sizeof ".stab" - 1) == 0)
+ flags |= SEC_DEBUGGING;
+
+ if (! bfd_set_section_flags (abfd, newsect, flags))
+ return false;
+
+ hdr->rawdata = (PTR) newsect;
+ elf_section_data (newsect)->this_hdr = *hdr;
+
+ return true;
+}
+
+/*
+INTERNAL_FUNCTION
+ bfd_elf_find_section
+
+SYNOPSIS
+ struct elf_internal_shdr *bfd_elf_find_section (bfd *abfd, char *name);
+
+DESCRIPTION
+ Helper functions for GDB to locate the string tables.
+ Since BFD hides string tables from callers, GDB needs to use an
+ internal hook to find them. Sun's .stabstr, in particular,
+ isn't even pointed to by the .stab section, so ordinary
+ mechanisms wouldn't work to find it, even if we had some.
+*/
+
+struct elf_internal_shdr *
+bfd_elf_find_section (abfd, name)
+ bfd * abfd;
+ char *name;
+{
+ Elf_Internal_Shdr **i_shdrp;
+ char *shstrtab;
+ unsigned int max;
+ unsigned int i;
+
+ i_shdrp = elf_elfsections (abfd);
+ if (i_shdrp != NULL)
+ {
+ shstrtab = elf_get_str_section (abfd, elf_elfheader (abfd)->e_shstrndx);
+ if (shstrtab != NULL)
+ {
+ max = elf_elfheader (abfd)->e_shnum;
+ for (i = 1; i < max; i++)
+ if (!strcmp (&shstrtab[i_shdrp[i]->sh_name], name))
+ return i_shdrp[i];
+ }
+ }
+ return 0;
+}
+
+const char *const bfd_elf_section_type_names[] = {
+ "SHT_NULL", "SHT_PROGBITS", "SHT_SYMTAB", "SHT_STRTAB",
+ "SHT_RELA", "SHT_HASH", "SHT_DYNAMIC", "SHT_NOTE",
+ "SHT_NOBITS", "SHT_REL", "SHT_SHLIB", "SHT_DYNSYM",
+};
+
+/* ELF relocs are against symbols. If we are producing relocateable
+ output, and the reloc is against an external symbol, and nothing
+ has given us any additional addend, the resulting reloc will also
+ be against the same symbol. In such a case, we don't want to
+ change anything about the way the reloc is handled, since it will
+ all be done at final link time. Rather than put special case code
+ into bfd_perform_relocation, all the reloc types use this howto
+ function. It just short circuits the reloc if producing
+ relocateable output against an external symbol. */
+
+/*ARGSUSED*/
+bfd_reloc_status_type
+bfd_elf_generic_reloc (abfd,
+ reloc_entry,
+ symbol,
+ data,
+ input_section,
+ output_bfd,
+ error_message)
+ bfd *abfd;
+ arelent *reloc_entry;
+ asymbol *symbol;
+ PTR data;
+ asection *input_section;
+ bfd *output_bfd;
+ char **error_message;
+{
+ if (output_bfd != (bfd *) NULL
+ && (symbol->flags & BSF_SECTION_SYM) == 0
+ && (! reloc_entry->howto->partial_inplace
+ || reloc_entry->addend == 0))
+ {
+ reloc_entry->address += input_section->output_offset;
+ return bfd_reloc_ok;
+ }
+
+ return bfd_reloc_continue;
+}
+
+/* Create an entry in an ELF linker hash table. */
+
+struct bfd_hash_entry *
+_bfd_elf_link_hash_newfunc (entry, table, string)
+ struct bfd_hash_entry *entry;
+ struct bfd_hash_table *table;
+ const char *string;
+{
+ struct elf_link_hash_entry *ret = (struct elf_link_hash_entry *) entry;
+
+ /* Allocate the structure if it has not already been allocated by a
+ subclass. */
+ if (ret == (struct elf_link_hash_entry *) NULL)
+ ret = ((struct elf_link_hash_entry *)
+ bfd_hash_allocate (table, sizeof (struct elf_link_hash_entry)));
+ if (ret == (struct elf_link_hash_entry *) NULL)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ return (struct bfd_hash_entry *) ret;
+ }
+
+ /* Call the allocation method of the superclass. */
+ ret = ((struct elf_link_hash_entry *)
+ _bfd_link_hash_newfunc ((struct bfd_hash_entry *) ret,
+ table, string));
+ if (ret != (struct elf_link_hash_entry *) NULL)
+ {
+ /* Set local fields. */
+ ret->indx = -1;
+ ret->size = 0;
+ ret->align = 0;
+ ret->dynindx = -1;
+ ret->dynstr_index = 0;
+ ret->weakdef = NULL;
+ ret->type = STT_NOTYPE;
+ ret->elf_link_hash_flags = 0;
+ }
+
+ return (struct bfd_hash_entry *) ret;
+}
+
+/* Initialize an ELF linker hash table. */
+
+boolean
+_bfd_elf_link_hash_table_init (table, abfd, newfunc)
+ struct elf_link_hash_table *table;
+ bfd *abfd;
+ struct bfd_hash_entry *(*newfunc) PARAMS ((struct bfd_hash_entry *,
+ struct bfd_hash_table *,
+ const char *));
+{
+ table->dynobj = NULL;
+ table->dynsymcount = 0;
+ table->dynstr = NULL;
+ table->bucketcount = 0;
+ return _bfd_link_hash_table_init (&table->root, abfd, newfunc);
+}
+
+/* Create an ELF linker hash table. */
+
+struct bfd_link_hash_table *
+_bfd_elf_link_hash_table_create (abfd)
+ bfd *abfd;
+{
+ struct elf_link_hash_table *ret;
+
+ ret = ((struct elf_link_hash_table *)
+ bfd_alloc (abfd, sizeof (struct elf_link_hash_table)));
+ if (ret == (struct elf_link_hash_table *) NULL)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ return NULL;
+ }
+
+ if (! _bfd_elf_link_hash_table_init (ret, abfd, _bfd_elf_link_hash_newfunc))
+ {
+ bfd_release (abfd, ret);
+ return NULL;
+ }
+
+ return &ret->root;
+}
+
+/* This is a hook for the ELF emulation code in the generic linker to
+ tell the backend linker what file name to use for the DT_NEEDED
+ entry for a dynamic object. */
+
+void
+bfd_elf_set_dt_needed_name (abfd, name)
+ bfd *abfd;
+ const char *name;
+{
+ elf_dt_needed_name (abfd) = name;
+}
diff --git a/gnu/usr.bin/gdb/bfd/elf32-i386.c b/gnu/usr.bin/gdb/bfd/elf32-i386.c
new file mode 100644
index 0000000..d2b1ebac
--- /dev/null
+++ b/gnu/usr.bin/gdb/bfd/elf32-i386.c
@@ -0,0 +1,931 @@
+/* Intel 80386/80486-specific support for 32-bit ELF
+ Copyright 1993 Free Software Foundation, Inc.
+
+This file is part of BFD, the Binary File Descriptor library.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "bfd.h"
+#include "sysdep.h"
+#include "bfdlink.h"
+#include "libbfd.h"
+#include "libelf.h"
+
+static CONST struct reloc_howto_struct *elf_i386_reloc_type_lookup
+ PARAMS ((bfd *, bfd_reloc_code_real_type));
+static void elf_i386_info_to_howto
+ PARAMS ((bfd *, arelent *, Elf32_Internal_Rela *));
+static void elf_i386_info_to_howto_rel
+ PARAMS ((bfd *, arelent *, Elf32_Internal_Rel *));
+static boolean elf_i386_create_dynamic_sections
+ PARAMS ((bfd *, struct bfd_link_info *));
+static boolean elf_i386_adjust_dynamic_symbol
+ PARAMS ((struct bfd_link_info *, struct elf_link_hash_entry *));
+static boolean elf_i386_allocate_dynamic_section
+ PARAMS ((bfd *, const char *));
+static boolean elf_i386_size_dynamic_sections
+ PARAMS ((bfd *, struct bfd_link_info *));
+static boolean elf_i386_relocate_section
+ PARAMS ((bfd *, struct bfd_link_info *, bfd *, asection *, bfd_byte *,
+ Elf_Internal_Rela *, Elf_Internal_Sym *, asection **, char *));
+static boolean elf_i386_finish_dynamic_symbol
+ PARAMS ((bfd *, struct bfd_link_info *, struct elf_link_hash_entry *,
+ Elf_Internal_Sym *));
+static boolean elf_i386_finish_dynamic_sections
+ PARAMS ((bfd *, struct bfd_link_info *));
+
+#define USE_REL 1 /* 386 uses REL relocations instead of RELA */
+
+enum reloc_type
+ {
+ R_386_NONE = 0,
+ R_386_32,
+ R_386_PC32,
+ R_386_GOT32,
+ R_386_PLT32,
+ R_386_COPY,
+ R_386_GLOB_DAT,
+ R_386_JUMP_SLOT,
+ R_386_RELATIVE,
+ R_386_GOTOFF,
+ R_386_GOTPC,
+ R_386_max
+ };
+
+#if 0
+static CONST char *CONST reloc_type_names[] =
+{
+ "R_386_NONE",
+ "R_386_32",
+ "R_386_PC32",
+ "R_386_GOT32",
+ "R_386_PLT32",
+ "R_386_COPY",
+ "R_386_GLOB_DAT",
+ "R_386_JUMP_SLOT",
+ "R_386_RELATIVE",
+ "R_386_GOTOFF",
+ "R_386_GOTPC",
+};
+#endif
+
+static reloc_howto_type elf_howto_table[]=
+{
+ HOWTO(R_386_NONE, 0,0, 0,false,0,complain_overflow_bitfield, bfd_elf_generic_reloc,"R_386_NONE", true,0x00000000,0x00000000,false),
+ HOWTO(R_386_32, 0,2,32,false,0,complain_overflow_bitfield, bfd_elf_generic_reloc,"R_386_32", true,0xffffffff,0xffffffff,false),
+ HOWTO(R_386_PC32, 0,2,32,true, 0,complain_overflow_bitfield, bfd_elf_generic_reloc,"R_386_PC32", true,0xffffffff,0xffffffff,true),
+ HOWTO(R_386_GOT32, 0,2,32,false,0,complain_overflow_bitfield, bfd_elf_generic_reloc,"R_386_GOT32", true,0xffffffff,0xffffffff,false),
+ HOWTO(R_386_PLT32, 0,2,32,false,0,complain_overflow_bitfield, bfd_elf_generic_reloc,"R_386_PLT32", true,0xffffffff,0xffffffff,false),
+ HOWTO(R_386_COPY, 0,2,32,false,0,complain_overflow_bitfield, bfd_elf_generic_reloc,"R_386_COPY", true,0xffffffff,0xffffffff,false),
+ HOWTO(R_386_GLOB_DAT, 0,2,32,false,0,complain_overflow_bitfield, bfd_elf_generic_reloc,"R_386_GLOB_DAT", true,0xffffffff,0xffffffff,false),
+ HOWTO(R_386_JUMP_SLOT, 0,2,32,false,0,complain_overflow_bitfield, bfd_elf_generic_reloc,"R_386_JUMP_SLOT",true,0xffffffff,0xffffffff,false),
+ HOWTO(R_386_RELATIVE, 0,2,32,false,0,complain_overflow_bitfield, bfd_elf_generic_reloc,"R_386_RELATIVE", true,0xffffffff,0xffffffff,false),
+ HOWTO(R_386_GOTOFF, 0,2,32,false,0,complain_overflow_bitfield, bfd_elf_generic_reloc,"R_386_GOTOFF", true,0xffffffff,0xffffffff,false),
+ HOWTO(R_386_GOTPC, 0,2,32,false,0,complain_overflow_bitfield, bfd_elf_generic_reloc,"R_386_GOTPC", true,0xffffffff,0xffffffff,false),
+};
+
+#ifdef DEBUG_GEN_RELOC
+#define TRACE(str) fprintf (stderr, "i386 bfd reloc lookup %d (%s)\n", code, str)
+#else
+#define TRACE(str)
+#endif
+
+static CONST struct reloc_howto_struct *
+elf_i386_reloc_type_lookup (abfd, code)
+ bfd *abfd;
+ bfd_reloc_code_real_type code;
+{
+ switch (code)
+ {
+ case BFD_RELOC_NONE:
+ TRACE ("BFD_RELOC_NONE");
+ return &elf_howto_table[ (int)R_386_NONE ];
+
+ case BFD_RELOC_32:
+ TRACE ("BFD_RELOC_32");
+ return &elf_howto_table[ (int)R_386_32 ];
+
+ case BFD_RELOC_32_PCREL:
+ TRACE ("BFD_RELOC_PC32");
+ return &elf_howto_table[ (int)R_386_PC32 ];
+
+ case BFD_RELOC_386_GOT32:
+ TRACE ("BFD_RELOC_386_GOT32");
+ return &elf_howto_table[ (int)R_386_GOT32 ];
+
+ case BFD_RELOC_386_PLT32:
+ TRACE ("BFD_RELOC_386_PLT32");
+ return &elf_howto_table[ (int)R_386_PLT32 ];
+
+ case BFD_RELOC_386_COPY:
+ TRACE ("BFD_RELOC_386_COPY");
+ return &elf_howto_table[ (int)R_386_COPY ];
+
+ case BFD_RELOC_386_GLOB_DAT:
+ TRACE ("BFD_RELOC_386_GLOB_DAT");
+ return &elf_howto_table[ (int)R_386_GLOB_DAT ];
+
+ case BFD_RELOC_386_JUMP_SLOT:
+ TRACE ("BFD_RELOC_386_JUMP_SLOT");
+ return &elf_howto_table[ (int)R_386_JUMP_SLOT ];
+
+ case BFD_RELOC_386_RELATIVE:
+ TRACE ("BFD_RELOC_386_RELATIVE");
+ return &elf_howto_table[ (int)R_386_RELATIVE ];
+
+ case BFD_RELOC_386_GOTOFF:
+ TRACE ("BFD_RELOC_386_GOTOFF");
+ return &elf_howto_table[ (int)R_386_GOTOFF ];
+
+ case BFD_RELOC_386_GOTPC:
+ TRACE ("BFD_RELOC_386_GOTPC");
+ return &elf_howto_table[ (int)R_386_GOTPC ];
+
+ default:
+ break;
+ }
+
+ TRACE ("Unknown");
+ return 0;
+}
+
+static void
+elf_i386_info_to_howto (abfd, cache_ptr, dst)
+ bfd *abfd;
+ arelent *cache_ptr;
+ Elf32_Internal_Rela *dst;
+{
+ BFD_ASSERT (ELF32_R_TYPE(dst->r_info) < (unsigned int) R_386_max);
+
+ cache_ptr->howto = &elf_howto_table[ELF32_R_TYPE(dst->r_info)];
+}
+
+static void
+elf_i386_info_to_howto_rel (abfd, cache_ptr, dst)
+ bfd *abfd;
+ arelent *cache_ptr;
+ Elf32_Internal_Rel *dst;
+{
+ BFD_ASSERT (ELF32_R_TYPE(dst->r_info) < (unsigned int) R_386_max);
+
+ cache_ptr->howto = &elf_howto_table[ELF32_R_TYPE(dst->r_info)];
+}
+
+/* Functions for the i386 ELF linker. */
+
+/* The name of the dynamic interpreter. This is put in the .interp
+ section. */
+
+#define ELF_DYNAMIC_INTERPRETER "/usr/lib/libc.so.1"
+
+/* The size in bytes of an entry in the procedure linkage table. */
+
+#define PLT_ENTRY_SIZE 16
+
+/* The first entry in an absolute procedure linkage table looks like
+ this. See the SVR4 ABI i386 supplement to see how this works. */
+
+static bfd_byte elf_i386_plt0_entry[PLT_ENTRY_SIZE] =
+{
+ 0xff, 0x35, /* pushl contents of address */
+ 0, 0, 0, 0, /* replaced with address of .got + 4. */
+ 0xff, 0x25, /* jmp indirect */
+ 0, 0, 0, 0, /* replaced with address of .got + 8. */
+ 0, 0, 0, 0 /* pad out to 16 bytes. */
+};
+
+/* Subsequent entries in an absolute procedure linkage table look like
+ this. */
+
+static bfd_byte elf_i386_plt_entry[PLT_ENTRY_SIZE] =
+{
+ 0xff, 0x25, /* jmp indirect */
+ 0, 0, 0, 0, /* replaced with address of this symbol in .got. */
+ 0x68, /* pushl immediate */
+ 0, 0, 0, 0, /* replaced with offset into relocation table. */
+ 0xe9, /* jmp relative */
+ 0, 0, 0, 0 /* replaced with offset to start of .plt. */
+};
+
+/* Create dynamic sections when linking against a dynamic object. */
+
+static boolean
+elf_i386_create_dynamic_sections (abfd, info)
+ bfd *abfd;
+ struct bfd_link_info *info;
+{
+ flagword flags;
+ register asection *s;
+ struct elf_link_hash_entry *h;
+
+ /* We need to create .plt, .rel.plt, .got, .dynbss, and .rel.bss
+ sections. */
+
+ flags = SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY;
+
+ s = bfd_make_section (abfd, ".plt");
+ if (s == NULL
+ || ! bfd_set_section_flags (abfd, s, flags | SEC_READONLY | SEC_CODE)
+ || ! bfd_set_section_alignment (abfd, s, 2))
+ return false;
+
+ s = bfd_make_section (abfd, ".rel.plt");
+ if (s == NULL
+ || ! bfd_set_section_flags (abfd, s, flags | SEC_READONLY)
+ || ! bfd_set_section_alignment (abfd, s, 2))
+ return false;
+
+ s = bfd_make_section (abfd, ".got");
+ if (s == NULL
+ || ! bfd_set_section_flags (abfd, s, flags)
+ || ! bfd_set_section_alignment (abfd, s, 2))
+ return false;
+
+ /* Define the symbol _GLOBAL_OFFSET_TABLE_ at the start of the .got
+ section. We don't do this in the linker script because we don't
+ want to define the symbol if we are not creating a global offset
+ table. */
+ h = NULL;
+ if (! (_bfd_generic_link_add_one_symbol
+ (info, abfd, "_GLOBAL_OFFSET_TABLE_", BSF_GLOBAL, s, (bfd_vma) 0,
+ (const char *) NULL, false, get_elf_backend_data (abfd)->collect,
+ (struct bfd_link_hash_entry **) &h)))
+ return false;
+ h->elf_link_hash_flags |= ELF_LINK_HASH_DEF_REGULAR;
+
+ /* The first three global offset table entries are reserved. */
+ s->_raw_size += 3 * 4;
+
+ /* The .dynbss section is a place to put symbols which are defined
+ by dynamic objects, are referenced by regular objects, and are
+ not functions. We must allocate space for them in the process
+ image and use a R_386_COPY reloc to tell the dynamic linker to
+ initialize them at run time. The linker script puts the .dynbss
+ section into the .bss section of the final image. */
+ s = bfd_make_section (abfd, ".dynbss");
+ if (s == NULL
+ || ! bfd_set_section_flags (abfd, s, SEC_ALLOC))
+ return false;
+
+ /* The .rel.bss section holds copy relocs. This section is not
+ normally needed. We need to create it here, though, so that the
+ linker will map it to an output section. If it turns out not to
+ be needed, we can discard it later. */
+ s = bfd_make_section (abfd, ".rel.bss");
+ if (s == NULL
+ || ! bfd_set_section_flags (abfd, s, flags | SEC_READONLY)
+ || ! bfd_set_section_alignment (abfd, s, 2))
+ return false;
+
+ return true;
+}
+
+/* Adjust a symbol defined by a dynamic object and referenced by a
+ regular object. The current definition is in some section of the
+ dynamic object, but we're not including those sections. We have to
+ change the definition to something the rest of the link can
+ understand. */
+
+static boolean
+elf_i386_adjust_dynamic_symbol (info, h)
+ struct bfd_link_info *info;
+ struct elf_link_hash_entry *h;
+{
+ bfd *dynobj;
+ asection *s;
+ unsigned int power_of_two;
+ size_t align;
+
+ dynobj = elf_hash_table (info)->dynobj;
+
+ /* Make sure we know what is going on here. */
+ BFD_ASSERT (dynobj != NULL
+ && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC) != 0
+ && (h->elf_link_hash_flags & ELF_LINK_HASH_REF_REGULAR) != 0
+ && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0
+ && h->root.type == bfd_link_hash_defined
+ && (bfd_get_flavour (h->root.u.def.section->owner)
+ == bfd_target_elf_flavour)
+ && (elf_elfheader (h->root.u.def.section->owner)->e_type
+ == ET_DYN)
+ && h->root.u.def.section->output_section == NULL);
+
+ /* If this is a function, put it in the procedure linkage table. We
+ will fill in the contents of the procedure linkage table later,
+ when we know the address of the .got section. */
+ if (h->type == STT_FUNC)
+ {
+ s = bfd_get_section_by_name (dynobj, ".plt");
+ BFD_ASSERT (s != NULL);
+
+ /* If this is the first .plt entry, make room for the special
+ first entry. */
+ if (s->_raw_size == 0)
+ s->_raw_size += PLT_ENTRY_SIZE;
+
+ /* Set the symbol to this location in the .plt. */
+ h->root.u.def.section = s;
+ h->root.u.def.value = s->_raw_size;
+
+ /* Make room for this entry. */
+ s->_raw_size += PLT_ENTRY_SIZE;
+
+ /* We also need to make an entry in the .got section. */
+
+ s = bfd_get_section_by_name (dynobj, ".got");
+ BFD_ASSERT (s != NULL);
+ s->_raw_size += 4;
+
+ /* We also need to make an entry in the .rel.plt section. */
+
+ s = bfd_get_section_by_name (dynobj, ".rel.plt");
+ BFD_ASSERT (s != NULL);
+ s->_raw_size += sizeof (Elf32_External_Rel);
+
+ return true;
+ }
+
+ /* If this is a weak symbol, and there is a real definition, the
+ processor independent code will have arranged for us to see the
+ real definition first, and we can just use the same value. */
+ if (h->weakdef != NULL)
+ {
+ BFD_ASSERT (h->weakdef->root.type == bfd_link_hash_defined);
+ h->root.u.def.section = h->weakdef->root.u.def.section;
+ h->root.u.def.value = h->weakdef->root.u.def.value;
+ h->align = (bfd_size_type) -1;
+ return true;
+ }
+
+ /* This is a reference to a symbol defined by a dynamic object which
+ is not a function. We must allocate it in our .dynbss section,
+ which will become part of the .bss section of the executable.
+ There will be an entry for this symbol in the .dynsym section.
+ The dynamic object will contain position independent code, so all
+ references from the dynamic object to this symbol will go through
+ the global offset table. The dynamic linker will use the .dynsym
+ entry to determine the address it must put in the global offset
+ table, so both the dynamic object and the regular object will
+ refer to the same memory location for the variable. */
+
+ s = bfd_get_section_by_name (dynobj, ".dynbss");
+ BFD_ASSERT (s != NULL);
+
+ /* If the symbol is currently defined in the .bss section of the
+ dynamic object, then it is OK to simply initialize it to zero.
+ If the symbol is in some other section, we must generate a
+ R_386_COPY reloc to tell the dynamic linker to copy the initial
+ value out of the dynamic object and into the runtime process
+ image. We need to remember the offset into the .rel.bss section
+ we are going to use, and we coopt the align field for this
+ purpose (the align field is only used for common symbols, and
+ these symbols are always defined). It would be cleaner to use a
+ new field, but that would waste memory. */
+ if ((h->root.u.def.section->flags & SEC_LOAD) == 0)
+ h->align = (bfd_size_type) -1;
+ else
+ {
+ asection *srel;
+
+ srel = bfd_get_section_by_name (dynobj, ".rel.bss");
+ BFD_ASSERT (srel != NULL);
+ h->align = srel->_raw_size;
+ srel->_raw_size += sizeof (Elf32_External_Rel);
+ }
+
+ /* We need to figure out the alignment required for this symbol. I
+ have no idea how ELF linkers handle this. */
+ switch (h->size)
+ {
+ case 0:
+ case 1:
+ power_of_two = 0;
+ align = 1;
+ break;
+ case 2:
+ power_of_two = 1;
+ align = 2;
+ break;
+ case 3:
+ case 4:
+ power_of_two = 2;
+ align = 4;
+ break;
+ case 5:
+ case 6:
+ case 7:
+ case 8:
+ power_of_two = 3;
+ align = 8;
+ break;
+ default:
+ power_of_two = 4;
+ align = 16;
+ break;
+ }
+
+ /* Apply the required alignment. */
+ s->_raw_size = BFD_ALIGN (s->_raw_size, align);
+ if (power_of_two > bfd_get_section_alignment (dynobj, s))
+ {
+ if (! bfd_set_section_alignment (dynobj, s, power_of_two))
+ return false;
+ }
+
+ /* Define the symbol as being at this point in the section. */
+ h->root.u.def.section = s;
+ h->root.u.def.value = s->_raw_size;
+
+ /* Increment the section size to make room for the symbol. */
+ s->_raw_size += h->size;
+
+ return true;
+}
+
+/* Allocate contents for a section. */
+
+static INLINE boolean
+elf_i386_allocate_dynamic_section (dynobj, name)
+ bfd *dynobj;
+ const char *name;
+{
+ register asection *s;
+
+ s = bfd_get_section_by_name (dynobj, name);
+ BFD_ASSERT (s != NULL);
+ s->contents = (bfd_byte *) bfd_alloc (dynobj, s->_raw_size);
+ if (s->contents == NULL && s->_raw_size != 0)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ return false;
+ }
+ return true;
+}
+
+/* Set the sizes of the dynamic sections. */
+
+static boolean
+elf_i386_size_dynamic_sections (output_bfd, info)
+ bfd *output_bfd;
+ struct bfd_link_info *info;
+{
+ bfd *dynobj;
+ asection *s;
+
+ dynobj = elf_hash_table (info)->dynobj;
+ BFD_ASSERT (dynobj != NULL);
+
+ /* Set the contents of the .interp section to the interpreter. */
+ if (! info->shared)
+ {
+ s = bfd_get_section_by_name (dynobj, ".interp");
+ BFD_ASSERT (s != NULL);
+ s->_raw_size = sizeof ELF_DYNAMIC_INTERPRETER;
+ s->contents = (unsigned char *) ELF_DYNAMIC_INTERPRETER;
+ }
+
+ /* The adjust_dynamic_symbol entry point has determined the sizes of
+ the various dynamic sections. Allocate some memory for them to
+ hold contents. */
+ if (! elf_i386_allocate_dynamic_section (dynobj, ".plt")
+ || ! elf_i386_allocate_dynamic_section (dynobj, ".rel.plt")
+ || ! elf_i386_allocate_dynamic_section (dynobj, ".got")
+ || ! elf_i386_allocate_dynamic_section (dynobj, ".rel.bss"))
+ return false;
+
+ /* Add some entries to the .dynamic section. We fill in the values
+ later, in elf_i386_finish_dynamic_sections, but we must add the
+ entries now so that we get the correct size for the .dynamic
+ section. The DT_DEBUG entry is filled in by the dynamic linker
+ and used by the debugger. */
+ if (! bfd_elf32_add_dynamic_entry (info, DT_DEBUG, 0)
+ || ! bfd_elf32_add_dynamic_entry (info, DT_PLTGOT, 0))
+ return false;
+
+ s = bfd_get_section_by_name (dynobj, ".plt");
+ BFD_ASSERT (s != NULL);
+ if (s->_raw_size != 0)
+ {
+ if (! bfd_elf32_add_dynamic_entry (info, DT_PLTRELSZ, 0)
+ || ! bfd_elf32_add_dynamic_entry (info, DT_PLTREL, DT_REL)
+ || ! bfd_elf32_add_dynamic_entry (info, DT_JMPREL, 0))
+ return false;
+ }
+
+ /* If we didn't need the .rel.bss section, then discard it from the
+ output file. This is a hack. We don't bother to do it for the
+ other sections because they normally are needed. */
+ s = bfd_get_section_by_name (dynobj, ".rel.bss");
+ BFD_ASSERT (s != NULL);
+ if (s->_raw_size == 0)
+ {
+ asection **spp;
+
+ for (spp = &s->output_section->owner->sections;
+ *spp != s->output_section;
+ spp = &(*spp)->next)
+ ;
+ *spp = s->output_section->next;
+ --s->output_section->owner->section_count;
+ }
+ else
+ {
+ if (! bfd_elf32_add_dynamic_entry (info, DT_REL, 0)
+ || ! bfd_elf32_add_dynamic_entry (info, DT_RELSZ, 0)
+ || ! bfd_elf32_add_dynamic_entry (info, DT_RELENT,
+ sizeof (Elf32_External_Rel)))
+ return false;
+ }
+
+ return true;
+}
+
+/* Relocate an i386 ELF section. */
+
+static boolean
+elf_i386_relocate_section (output_bfd, info, input_bfd, input_section,
+ contents, relocs, local_syms, local_sections,
+ output_names)
+ bfd *output_bfd;
+ struct bfd_link_info *info;
+ bfd *input_bfd;
+ asection *input_section;
+ bfd_byte *contents;
+ Elf_Internal_Rela *relocs;
+ Elf_Internal_Sym *local_syms;
+ asection **local_sections;
+ char *output_names;
+{
+ Elf_Internal_Shdr *symtab_hdr;
+ Elf_Internal_Rela *rel;
+ Elf_Internal_Rela *relend;
+
+ symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
+
+ rel = relocs;
+ relend = relocs + input_section->reloc_count;
+ for (; rel < relend; rel++)
+ {
+ int r_type;
+ const reloc_howto_type *howto;
+ long r_symndx;
+ struct elf_link_hash_entry *h;
+ Elf_Internal_Sym *sym;
+ asection *sec;
+ bfd_vma relocation;
+ bfd_reloc_status_type r;
+
+ r_type = ELF32_R_TYPE (rel->r_info);
+ if (r_type < 0 || r_type >= (int) R_386_max)
+ {
+ bfd_set_error (bfd_error_bad_value);
+ return false;
+ }
+ howto = elf_howto_table + r_type;
+
+ r_symndx = ELF32_R_SYM (rel->r_info);
+
+ if (info->relocateable)
+ {
+ /* This is a relocateable link. We don't have to change
+ anything, unless the reloc is against a section symbol,
+ in which case we have to adjust according to where the
+ section symbol winds up in the output section. */
+ if (r_symndx < symtab_hdr->sh_info)
+ {
+ sym = local_syms + r_symndx;
+ if (ELF_ST_TYPE (sym->st_info) == STT_SECTION)
+ {
+ bfd_vma val;
+
+ sec = local_sections[r_symndx];
+ val = bfd_get_32 (input_bfd, contents + rel->r_offset);
+ val += sec->output_offset + sym->st_value;
+ bfd_put_32 (input_bfd, val, contents + rel->r_offset);
+ }
+ }
+
+ continue;
+ }
+
+ /* This is a final link. */
+ h = NULL;
+ sym = NULL;
+ sec = NULL;
+ if (r_symndx < symtab_hdr->sh_info)
+ {
+ sym = local_syms + r_symndx;
+ sec = local_sections[r_symndx];
+ relocation = (sec->output_section->vma
+ + sec->output_offset
+ + sym->st_value);
+ }
+ else
+ {
+ long indx;
+
+ indx = r_symndx - symtab_hdr->sh_info;
+ h = elf_sym_hashes (input_bfd)[indx];
+ if (h->root.type == bfd_link_hash_defined)
+ {
+ sec = h->root.u.def.section;
+ relocation = (h->root.u.def.value
+ + sec->output_section->vma
+ + sec->output_offset);
+ }
+ else if (h->root.type == bfd_link_hash_weak)
+ relocation = 0;
+ else
+ {
+ if (! ((*info->callbacks->undefined_symbol)
+ (info, h->root.root.string, input_bfd,
+ input_section, rel->r_offset)))
+ return false;
+ relocation = 0;
+ }
+ }
+
+ r = _bfd_final_link_relocate (howto, input_bfd, input_section,
+ contents, rel->r_offset,
+ relocation, (bfd_vma) 0);
+
+ if (r != bfd_reloc_ok)
+ {
+ switch (r)
+ {
+ default:
+ case bfd_reloc_outofrange:
+ abort ();
+ case bfd_reloc_overflow:
+ {
+ const char *name;
+
+ if (h != NULL)
+ name = h->root.root.string;
+ else
+ {
+ name = output_names + sym->st_name;
+ if (name == NULL)
+ return false;
+ if (*name == '\0')
+ name = bfd_section_name (input_bfd, sec);
+ }
+ if (! ((*info->callbacks->reloc_overflow)
+ (info, name, howto->name, (bfd_vma) 0,
+ input_bfd, input_section, rel->r_offset)))
+ return false;
+ }
+ break;
+ }
+ }
+ }
+
+ return true;
+}
+
+/* Finish up dynamic symbol handling. We set the contents of various
+ dynamic sections here. */
+
+static boolean
+elf_i386_finish_dynamic_symbol (output_bfd, info, h, sym)
+ bfd *output_bfd;
+ struct bfd_link_info *info;
+ struct elf_link_hash_entry *h;
+ Elf_Internal_Sym *sym;
+{
+ /* If this symbol is not defined by a dynamic object, or is not
+ referenced by a regular object, ignore it. */
+ if ((h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) != 0
+ || (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC) == 0
+ || (h->elf_link_hash_flags & ELF_LINK_HASH_REF_REGULAR) == 0)
+ {
+ /* Mark _DYNAMIC and _GLOBAL_OFFSET_TABLE_ as absolute. */
+ if (strcmp (h->root.root.string, "_DYNAMIC") == 0
+ || strcmp (h->root.root.string, "_GLOBAL_OFFSET_TABLE_") == 0)
+ sym->st_shndx = SHN_ABS;
+ return true;
+ }
+
+ BFD_ASSERT (h->root.type == bfd_link_hash_defined);
+ BFD_ASSERT (h->dynindx != -1);
+
+ if (h->type == STT_FUNC)
+ {
+ asection *splt;
+ asection *sgot;
+ asection *srel;
+ bfd_vma plt_index;
+ bfd_vma got_offset;
+ Elf_Internal_Rel rel;
+
+ splt = h->root.u.def.section;
+ BFD_ASSERT (strcmp (bfd_get_section_name (splt->owner, splt), ".plt")
+ == 0);
+ sgot = bfd_get_section_by_name (splt->owner, ".got");
+ BFD_ASSERT (sgot != NULL);
+ srel = bfd_get_section_by_name (splt->owner, ".rel.plt");
+ BFD_ASSERT (srel != NULL);
+
+ /* FIXME: This only handles an absolute procedure linkage table.
+ When producing a dynamic object, we need to generate a
+ position independent procedure linkage table. */
+
+ /* Get the index in the procedure linkage table which
+ corresponds to this symbol. This is the index of this symbol
+ in all the symbols for which we are making plt entries. The
+ first entry in the procedure linkage table is reserved. */
+ plt_index = h->root.u.def.value / PLT_ENTRY_SIZE - 1;
+
+ /* Get the offset into the .got table of the entry that
+ corresponds to this function. Each .got entry is 4 bytes.
+ The first three are reserved. */
+ got_offset = (plt_index + 3) * 4;
+
+ /* Fill in the entry in the procedure linkage table. */
+ memcpy (splt->contents + h->root.u.def.value, elf_i386_plt_entry,
+ PLT_ENTRY_SIZE);
+ bfd_put_32 (output_bfd,
+ (sgot->output_section->vma
+ + sgot->output_offset
+ + got_offset),
+ splt->contents + h->root.u.def.value + 2);
+ bfd_put_32 (output_bfd, plt_index * sizeof (Elf32_External_Rel),
+ splt->contents + h->root.u.def.value + 7);
+ bfd_put_32 (output_bfd, - (h->root.u.def.value + PLT_ENTRY_SIZE),
+ splt->contents + h->root.u.def.value + 12);
+
+ /* Fill in the entry in the global offset table. */
+ bfd_put_32 (output_bfd,
+ (splt->output_section->vma
+ + splt->output_offset
+ + h->root.u.def.value
+ + 6),
+ sgot->contents + got_offset);
+
+ /* Fill in the entry in the .rel.plt section. */
+ rel.r_offset = (sgot->output_section->vma
+ + sgot->output_offset
+ + got_offset);
+ rel.r_info = ELF32_R_INFO (h->dynindx, R_386_JUMP_SLOT);
+ bfd_elf32_swap_reloc_out (output_bfd, &rel,
+ ((Elf32_External_Rel *) srel->contents
+ + plt_index));
+
+ /* Mark the symbol as undefined, rather than as defined in the
+ .plt section. Leave the value alone. */
+ sym->st_shndx = SHN_UNDEF;
+ }
+ else
+ {
+ /* This is not a function. We have already allocated memory for
+ it in the .bss section (via .dynbss). All we have to do here
+ is create a COPY reloc if required. */
+ if (h->align != (bfd_size_type) -1)
+ {
+ asection *s;
+ Elf_Internal_Rel rel;
+
+ s = bfd_get_section_by_name (h->root.u.def.section->owner,
+ ".rel.bss");
+ BFD_ASSERT (s != NULL);
+
+ rel.r_offset = (h->root.u.def.value
+ + h->root.u.def.section->output_section->vma
+ + h->root.u.def.section->output_offset);
+ rel.r_info = ELF32_R_INFO (h->dynindx, R_386_COPY);
+ bfd_elf32_swap_reloc_out (output_bfd, &rel,
+ ((Elf32_External_Rel *)
+ (s->contents + h->align)));
+ }
+ }
+
+ return true;
+}
+
+/* Finish up the dynamic sections. */
+
+static boolean
+elf_i386_finish_dynamic_sections (output_bfd, info)
+ bfd *output_bfd;
+ struct bfd_link_info *info;
+{
+ asection *splt;
+ asection *sgot;
+ asection *sdyn;
+ Elf32_External_Dyn *dyncon, *dynconend;
+
+ splt = bfd_get_section_by_name (elf_hash_table (info)->dynobj, ".plt");
+ sgot = bfd_get_section_by_name (elf_hash_table (info)->dynobj, ".got");
+ sdyn = bfd_get_section_by_name (elf_hash_table (info)->dynobj, ".dynamic");
+ BFD_ASSERT (splt != NULL && sgot != NULL && sdyn != NULL);
+
+ dyncon = (Elf32_External_Dyn *) sdyn->contents;
+ dynconend = (Elf32_External_Dyn *) (sdyn->contents + sdyn->_raw_size);
+ for (; dyncon < dynconend; dyncon++)
+ {
+ Elf_Internal_Dyn dyn;
+ const char *name;
+ boolean size;
+
+ bfd_elf32_swap_dyn_in (elf_hash_table (info)->dynobj, dyncon, &dyn);
+
+ /* My reading of the SVR4 ABI indicates that the procedure
+ linkage table relocs (DT_JMPREL) should be included in the
+ overall relocs (DT_REL). This is what Solaris does.
+ However, UnixWare can not handle that case. Therefore, we
+ override the DT_REL and DT_RELSZ entries here to make them
+ not include the JMPREL relocs. */
+
+ switch (dyn.d_tag)
+ {
+ case DT_PLTGOT: name = ".got"; size = false; break;
+ case DT_PLTRELSZ: name = ".rel.plt"; size = true; break;
+ case DT_JMPREL: name = ".rel.plt"; size = false; break;
+ case DT_REL: name = ".rel.bss"; size = false; break;
+ case DT_RELSZ: name = ".rel.bss"; size = true; break;
+ default: name = NULL; size = false; break;
+ }
+
+ if (name != NULL)
+ {
+ asection *s;
+
+ s = bfd_get_section_by_name (output_bfd, name);
+ BFD_ASSERT (s != NULL);
+ if (! size)
+ dyn.d_un.d_ptr = s->vma;
+ else
+ {
+ if (s->_cooked_size != 0)
+ dyn.d_un.d_val = s->_cooked_size;
+ else
+ dyn.d_un.d_val = s->_raw_size;
+ }
+ bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon);
+ }
+ }
+
+ /* Fill in the first entry in the procedure linkage table. */
+ if (splt->_raw_size > 0)
+ {
+ memcpy (splt->contents, elf_i386_plt0_entry, PLT_ENTRY_SIZE);
+ bfd_put_32 (output_bfd,
+ sgot->output_section->vma + sgot->output_offset + 4,
+ splt->contents + 2);
+ bfd_put_32 (output_bfd,
+ sgot->output_section->vma + sgot->output_offset + 8,
+ splt->contents + 8);
+ }
+
+ /* Fill in the first three entries in the global offset table. */
+ if (sgot->_raw_size > 0)
+ {
+ bfd_put_32 (output_bfd,
+ sdyn->output_section->vma + sdyn->output_offset,
+ sgot->contents);
+ bfd_put_32 (output_bfd, (bfd_vma) 0, sgot->contents + 4);
+ bfd_put_32 (output_bfd, (bfd_vma) 0, sgot->contents + 8);
+ }
+
+ elf_section_data (sgot->output_section)->this_hdr.sh_entsize = 4;
+
+ /* UnixWare sets the entsize of .plt to 4, although that doesn't
+ really seem like the right value. */
+ elf_section_data (splt->output_section)->this_hdr.sh_entsize = 4;
+
+ return true;
+}
+
+#define TARGET_LITTLE_SYM bfd_elf32_i386_vec
+#define TARGET_LITTLE_NAME "elf32-i386"
+#define ELF_ARCH bfd_arch_i386
+#define ELF_MACHINE_CODE EM_386
+#define elf_info_to_howto elf_i386_info_to_howto
+#define elf_info_to_howto_rel elf_i386_info_to_howto_rel
+#define bfd_elf32_bfd_reloc_type_lookup elf_i386_reloc_type_lookup
+#define ELF_MAXPAGESIZE 0x1000
+#define elf_backend_create_dynamic_sections \
+ elf_i386_create_dynamic_sections
+#define elf_backend_adjust_dynamic_symbol \
+ elf_i386_adjust_dynamic_symbol
+#define elf_backend_size_dynamic_sections \
+ elf_i386_size_dynamic_sections
+#define elf_backend_relocate_section elf_i386_relocate_section
+#define elf_backend_finish_dynamic_symbol \
+ elf_i386_finish_dynamic_symbol
+#define elf_backend_finish_dynamic_sections \
+ elf_i386_finish_dynamic_sections
+
+#include "elf32-target.h"
diff --git a/gnu/usr.bin/gdb/bfd/elf32-target.h b/gnu/usr.bin/gdb/bfd/elf32-target.h
new file mode 100644
index 0000000..344683e
--- /dev/null
+++ b/gnu/usr.bin/gdb/bfd/elf32-target.h
@@ -0,0 +1,358 @@
+/* Target definitions for 32-bit ELF
+ Copyright 1993, 1994 Free Software Foundation, Inc.
+
+This file is part of BFD, the Binary File Descriptor library.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* This structure contains everything that BFD knows about a target.
+ It includes things like its byte order, name, what routines to call
+ to do various operations, etc. Every BFD points to a target structure
+ with its "xvec" member.
+
+ There are two such structures here: one for big-endian machines and
+ one for little-endian machines. */
+
+#define bfd_elf32_close_and_cleanup _bfd_generic_close_and_cleanup
+#define bfd_elf32_bfd_free_cached_info _bfd_generic_bfd_free_cached_info
+#ifndef bfd_elf32_get_section_contents
+#define bfd_elf32_get_section_contents _bfd_generic_get_section_contents
+#endif
+
+#define bfd_elf32_bfd_get_relocated_section_contents \
+ bfd_generic_get_relocated_section_contents
+#define bfd_elf32_bfd_relax_section bfd_generic_relax_section
+#define bfd_elf32_bfd_make_debug_symbol \
+ ((asymbol *(*) PARAMS ((bfd *, void *, unsigned long))) bfd_nullvoidptr)
+
+#ifndef bfd_elf32_bfd_copy_private_section_data
+#define bfd_elf32_bfd_copy_private_section_data \
+ ((boolean (*) PARAMS ((bfd *, asection *, bfd *, asection *))) bfd_true)
+#endif
+#ifndef bfd_elf32_bfd_copy_private_bfd_data
+#define bfd_elf32_bfd_copy_private_bfd_data \
+ ((boolean (*) PARAMS ((bfd *, bfd *))) bfd_true)
+#endif
+#ifndef bfd_elf32_bfd_is_local_label
+#define bfd_elf32_bfd_is_local_label bfd_generic_is_local_label
+#endif
+
+#ifndef bfd_elf32_get_dynamic_reloc_upper_bound
+#define bfd_elf32_get_dynamic_reloc_upper_bound \
+ _bfd_nodynamic_get_dynamic_reloc_upper_bound
+#endif
+#ifndef bfd_elf32_canonicalize_dynamic_reloc
+#define bfd_elf32_canonicalize_dynamic_reloc \
+ _bfd_nodynamic_canonicalize_dynamic_reloc
+#endif
+
+#ifdef elf_backend_relocate_section
+#ifndef bfd_elf32_bfd_link_hash_table_create
+#define bfd_elf32_bfd_link_hash_table_create _bfd_elf_link_hash_table_create
+#endif
+#else /* ! defined (elf_backend_relocate_section) */
+/* If no backend relocate_section routine, use the generic linker. */
+#ifndef bfd_elf32_bfd_link_hash_table_create
+#define bfd_elf32_bfd_link_hash_table_create \
+ _bfd_generic_link_hash_table_create
+#endif
+#ifndef bfd_elf32_bfd_link_add_symbols
+#define bfd_elf32_bfd_link_add_symbols _bfd_generic_link_add_symbols
+#endif
+#ifndef bfd_elf32_bfd_final_link
+#define bfd_elf32_bfd_final_link _bfd_generic_final_link
+#endif
+#endif /* ! defined (elf_backend_relocate_section) */
+
+#ifndef elf_info_to_howto_rel
+#define elf_info_to_howto_rel 0
+#endif
+
+#ifndef ELF_MAXPAGESIZE
+#define ELF_MAXPAGESIZE 1
+#endif
+
+#ifndef elf_backend_collect
+#define elf_backend_collect false
+#endif
+
+#ifndef elf_backend_sym_is_global
+#define elf_backend_sym_is_global 0
+#endif
+#ifndef elf_backend_object_p
+#define elf_backend_object_p 0
+#endif
+#ifndef elf_backend_symbol_processing
+#define elf_backend_symbol_processing 0
+#endif
+#ifndef elf_backend_symbol_table_processing
+#define elf_backend_symbol_table_processing 0
+#endif
+#ifndef elf_backend_section_processing
+#define elf_backend_section_processing 0
+#endif
+#ifndef elf_backend_section_from_shdr
+#define elf_backend_section_from_shdr 0
+#endif
+#ifndef elf_backend_fake_sections
+#define elf_backend_fake_sections 0
+#endif
+#ifndef elf_backend_section_from_bfd_section
+#define elf_backend_section_from_bfd_section 0
+#endif
+#ifndef elf_backend_add_symbol_hook
+#define elf_backend_add_symbol_hook 0
+#endif
+#ifndef elf_backend_link_output_symbol_hook
+#define elf_backend_link_output_symbol_hook 0
+#endif
+#ifndef elf_backend_create_dynamic_sections
+#define elf_backend_create_dynamic_sections 0
+#endif
+#ifndef elf_backend_adjust_dynamic_symbol
+#define elf_backend_adjust_dynamic_symbol 0
+#endif
+#ifndef elf_backend_size_dynamic_sections
+#define elf_backend_size_dynamic_sections 0
+#endif
+#ifndef elf_backend_relocate_section
+#define elf_backend_relocate_section 0
+#endif
+#ifndef elf_backend_finish_dynamic_symbol
+#define elf_backend_finish_dynamic_symbol 0
+#endif
+#ifndef elf_backend_finish_dynamic_sections
+#define elf_backend_finish_dynamic_sections 0
+#endif
+#ifndef elf_backend_begin_write_processing
+#define elf_backend_begin_write_processing 0
+#endif
+#ifndef elf_backend_final_write_processing
+#define elf_backend_final_write_processing 0
+#endif
+#ifndef elf_backend_ecoff_debug_swap
+#define elf_backend_ecoff_debug_swap 0
+#endif
+
+static CONST struct elf_backend_data elf32_bed =
+{
+#ifdef USE_REL
+ 0, /* use_rela_p */
+#else
+ 1, /* use_rela_p */
+#endif
+ 0, /* elf_64_p */
+ ELF_ARCH, /* arch */
+ ELF_MACHINE_CODE, /* elf_machine_code */
+ ELF_MAXPAGESIZE, /* maxpagesize */
+ elf_backend_collect,
+ elf_info_to_howto,
+ elf_info_to_howto_rel,
+ elf_backend_sym_is_global,
+ elf_backend_object_p,
+ elf_backend_symbol_processing,
+ elf_backend_symbol_table_processing,
+ elf_backend_section_processing,
+ elf_backend_section_from_shdr,
+ elf_backend_fake_sections,
+ elf_backend_section_from_bfd_section,
+ elf_backend_add_symbol_hook,
+ elf_backend_link_output_symbol_hook,
+ elf_backend_create_dynamic_sections,
+ elf_backend_adjust_dynamic_symbol,
+ elf_backend_size_dynamic_sections,
+ elf_backend_relocate_section,
+ elf_backend_finish_dynamic_symbol,
+ elf_backend_finish_dynamic_sections,
+ elf_backend_begin_write_processing,
+ elf_backend_final_write_processing,
+ elf_backend_ecoff_debug_swap
+};
+
+#ifdef TARGET_BIG_SYM
+const bfd_target TARGET_BIG_SYM =
+{
+ /* name: identify kind of target */
+ TARGET_BIG_NAME,
+
+ /* flavour: general indication about file */
+ bfd_target_elf_flavour,
+
+ /* byteorder_big_p: data is big endian */
+ true,
+
+ /* header_byteorder_big_p: header is also big endian */
+ true,
+
+ /* object_flags: mask of all file flags */
+ (HAS_RELOC | EXEC_P | HAS_LINENO | HAS_DEBUG | HAS_SYMS | HAS_LOCALS |
+ DYNAMIC | WP_TEXT | D_PAGED),
+
+ /* section_flags: mask of all section flags */
+ (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC | SEC_READONLY |
+ SEC_CODE | SEC_DATA | SEC_DEBUGGING),
+
+ /* leading_symbol_char: is the first char of a user symbol
+ predictable, and if so what is it */
+ 0,
+
+ /* ar_pad_char: pad character for filenames within an archive header
+ FIXME: this really has nothing to do with ELF, this is a characteristic
+ of the archiver and/or os and should be independently tunable */
+ '/',
+
+ /* ar_max_namelen: maximum number of characters in an archive header
+ FIXME: this really has nothing to do with ELF, this is a characteristic
+ of the archiver and should be independently tunable. This value is
+ a WAG (wild a** guess) */
+ 14,
+
+ /* align_power_min: minimum alignment restriction for any section
+ FIXME: this value may be target machine dependent */
+ 3,
+
+ /* Routines to byte-swap various sized integers from the data sections */
+ bfd_getb64, bfd_getb_signed_64, bfd_putb64,
+ bfd_getb32, bfd_getb_signed_32, bfd_putb32,
+ bfd_getb16, bfd_getb_signed_16, bfd_putb16,
+
+ /* Routines to byte-swap various sized integers from the file headers */
+ bfd_getb64, bfd_getb_signed_64, bfd_putb64,
+ bfd_getb32, bfd_getb_signed_32, bfd_putb32,
+ bfd_getb16, bfd_getb_signed_16, bfd_putb16,
+
+ /* bfd_check_format: check the format of a file being read */
+ { _bfd_dummy_target, /* unknown format */
+ bfd_elf32_object_p, /* assembler/linker output (object file) */
+ bfd_generic_archive_p, /* an archive */
+ bfd_elf32_core_file_p /* a core file */
+ },
+
+ /* bfd_set_format: set the format of a file being written */
+ { bfd_false,
+ bfd_elf_mkobject,
+ _bfd_generic_mkarchive,
+ bfd_false
+ },
+
+ /* bfd_write_contents: write cached information into a file being written */
+ { bfd_false,
+ bfd_elf32_write_object_contents,
+ _bfd_write_archive_contents,
+ bfd_false
+ },
+
+ BFD_JUMP_TABLE_GENERIC (bfd_elf32),
+ BFD_JUMP_TABLE_COPY (bfd_elf32),
+ BFD_JUMP_TABLE_CORE (bfd_elf32),
+ BFD_JUMP_TABLE_ARCHIVE (_bfd_archive_coff),
+ BFD_JUMP_TABLE_SYMBOLS (bfd_elf32),
+ BFD_JUMP_TABLE_RELOCS (bfd_elf32),
+ BFD_JUMP_TABLE_WRITE (bfd_elf32),
+ BFD_JUMP_TABLE_LINK (bfd_elf32),
+ BFD_JUMP_TABLE_DYNAMIC (bfd_elf32),
+
+ /* backend_data: */
+ (PTR) &elf32_bed,
+};
+#endif
+
+#ifdef TARGET_LITTLE_SYM
+const bfd_target TARGET_LITTLE_SYM =
+{
+ /* name: identify kind of target */
+ TARGET_LITTLE_NAME,
+
+ /* flavour: general indication about file */
+ bfd_target_elf_flavour,
+
+ /* byteorder_big_p: data is big endian */
+ false, /* Nope -- this one's little endian */
+
+ /* header_byteorder_big_p: header is also big endian */
+ false, /* Nope -- this one's little endian */
+
+ /* object_flags: mask of all file flags */
+ (HAS_RELOC | EXEC_P | HAS_LINENO | HAS_DEBUG | HAS_SYMS | HAS_LOCALS |
+ DYNAMIC | WP_TEXT | D_PAGED),
+
+ /* section_flags: mask of all section flags */
+ (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC | SEC_READONLY |
+ SEC_CODE | SEC_DATA | SEC_DEBUGGING),
+
+ /* leading_symbol_char: is the first char of a user symbol
+ predictable, and if so what is it */
+ 0,
+
+ /* ar_pad_char: pad character for filenames within an archive header
+ FIXME: this really has nothing to do with ELF, this is a characteristic
+ of the archiver and/or os and should be independently tunable */
+ '/',
+
+ /* ar_max_namelen: maximum number of characters in an archive header
+ FIXME: this really has nothing to do with ELF, this is a characteristic
+ of the archiver and should be independently tunable. This value is
+ a WAG (wild a** guess) */
+ 14,
+
+ /* align_power_min: minimum alignment restriction for any section
+ FIXME: this value may be target machine dependent */
+ 3,
+
+ /* Routines to byte-swap various sized integers from the data sections */
+ bfd_getl64, bfd_getl_signed_64, bfd_putl64,
+ bfd_getl32, bfd_getl_signed_32, bfd_putl32,
+ bfd_getl16, bfd_getl_signed_16, bfd_putl16,
+
+ /* Routines to byte-swap various sized integers from the file headers */
+ bfd_getl64, bfd_getl_signed_64, bfd_putl64,
+ bfd_getl32, bfd_getl_signed_32, bfd_putl32,
+ bfd_getl16, bfd_getl_signed_16, bfd_putl16,
+
+ /* bfd_check_format: check the format of a file being read */
+ { _bfd_dummy_target, /* unknown format */
+ bfd_elf32_object_p, /* assembler/linker output (object file) */
+ bfd_generic_archive_p, /* an archive */
+ bfd_elf32_core_file_p /* a core file */
+ },
+
+ /* bfd_set_format: set the format of a file being written */
+ { bfd_false,
+ bfd_elf_mkobject,
+ _bfd_generic_mkarchive,
+ bfd_false
+ },
+
+ /* bfd_write_contents: write cached information into a file being written */
+ { bfd_false,
+ bfd_elf32_write_object_contents,
+ _bfd_write_archive_contents,
+ bfd_false
+ },
+
+ BFD_JUMP_TABLE_GENERIC (bfd_elf32),
+ BFD_JUMP_TABLE_COPY (bfd_elf32),
+ BFD_JUMP_TABLE_CORE (bfd_elf32),
+ BFD_JUMP_TABLE_ARCHIVE (_bfd_archive_coff),
+ BFD_JUMP_TABLE_SYMBOLS (bfd_elf32),
+ BFD_JUMP_TABLE_RELOCS (bfd_elf32),
+ BFD_JUMP_TABLE_WRITE (bfd_elf32),
+ BFD_JUMP_TABLE_LINK (bfd_elf32),
+ BFD_JUMP_TABLE_DYNAMIC (bfd_elf32),
+
+ /* backend_data: */
+ (PTR) &elf32_bed,
+};
+#endif
diff --git a/gnu/usr.bin/gdb/bfd/elf32.c b/gnu/usr.bin/gdb/bfd/elf32.c
new file mode 100644
index 0000000..862dd2d
--- /dev/null
+++ b/gnu/usr.bin/gdb/bfd/elf32.c
@@ -0,0 +1,23 @@
+/* ELF 32-bit executable support for BFD.
+ Copyright 1993 Free Software Foundation, Inc.
+
+This file is part of BFD, the Binary File Descriptor library.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#define ARCH_SIZE 32
+
+
+#include "elfcode.h"
diff --git a/gnu/usr.bin/gdb/bfd/elfcode.h b/gnu/usr.bin/gdb/bfd/elfcode.h
new file mode 100644
index 0000000..ab38ab9
--- /dev/null
+++ b/gnu/usr.bin/gdb/bfd/elfcode.h
@@ -0,0 +1,6351 @@
+/* ELF executable support for BFD.
+ Copyright 1991, 1992, 1993, 1994 Free Software Foundation, Inc.
+
+ Written by Fred Fish @ Cygnus Support, from information published
+ in "UNIX System V Release 4, Programmers Guide: ANSI C and
+ Programming Support Tools". Sufficient support for gdb.
+
+ Rewritten by Mark Eichin @ Cygnus Support, from information
+ published in "System V Application Binary Interface", chapters 4
+ and 5, as well as the various "Processor Supplement" documents
+ derived from it. Added support for assembler and other object file
+ utilities. Further work done by Ken Raeburn (Cygnus Support), Michael
+ Meissner (Open Software Foundation), and Peter Hoogenboom (University
+ of Utah) to finish and extend this.
+
+This file is part of BFD, the Binary File Descriptor library.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* Problems and other issues to resolve.
+
+ (1) BFD expects there to be some fixed number of "sections" in
+ the object file. I.E. there is a "section_count" variable in the
+ bfd structure which contains the number of sections. However, ELF
+ supports multiple "views" of a file. In particular, with current
+ implementations, executable files typically have two tables, a
+ program header table and a section header table, both of which
+ partition the executable.
+
+ In ELF-speak, the "linking view" of the file uses the section header
+ table to access "sections" within the file, and the "execution view"
+ uses the program header table to access "segments" within the file.
+ "Segments" typically may contain all the data from one or more
+ "sections".
+
+ Note that the section header table is optional in ELF executables,
+ but it is this information that is most useful to gdb. If the
+ section header table is missing, then gdb should probably try
+ to make do with the program header table. (FIXME)
+
+ (2) The code in this file is compiled twice, once in 32-bit mode and
+ once in 64-bit mode. More of it should be made size-independent
+ and moved into elf.c.
+
+ (3) ELF section symbols are handled rather sloppily now. This should
+ be cleaned up, and ELF section symbols reconciled with BFD section
+ symbols.
+
+ (4) We need a published spec for 64-bit ELF. We've got some stuff here
+ that we're using for SPARC V9 64-bit chips, but don't assume that
+ it's cast in stone.
+ */
+
+#include <string.h> /* For strrchr and friends */
+#include "bfd.h"
+#include "sysdep.h"
+#include "bfdlink.h"
+#include "libbfd.h"
+#include "libelf.h"
+
+/* Renaming structures, typedefs, macros and functions to be size-specific. */
+#define Elf_External_Ehdr NAME(Elf,External_Ehdr)
+#define Elf_External_Sym NAME(Elf,External_Sym)
+#define Elf_External_Shdr NAME(Elf,External_Shdr)
+#define Elf_External_Phdr NAME(Elf,External_Phdr)
+#define Elf_External_Rel NAME(Elf,External_Rel)
+#define Elf_External_Rela NAME(Elf,External_Rela)
+#define Elf_External_Dyn NAME(Elf,External_Dyn)
+
+#define elf_core_file_failing_command NAME(bfd_elf,core_file_failing_command)
+#define elf_core_file_failing_signal NAME(bfd_elf,core_file_failing_signal)
+#define elf_core_file_matches_executable_p \
+ NAME(bfd_elf,core_file_matches_executable_p)
+#define elf_object_p NAME(bfd_elf,object_p)
+#define elf_core_file_p NAME(bfd_elf,core_file_p)
+#define elf_get_symtab_upper_bound NAME(bfd_elf,get_symtab_upper_bound)
+#define elf_get_dynamic_symtab_upper_bound \
+ NAME(bfd_elf,get_dynamic_symtab_upper_bound)
+#define elf_swap_reloc_in NAME(bfd_elf,swap_reloc_in)
+#define elf_swap_reloca_in NAME(bfd_elf,swap_reloca_in)
+#define elf_swap_reloc_out NAME(bfd_elf,swap_reloc_out)
+#define elf_swap_reloca_out NAME(bfd_elf,swap_reloca_out)
+#define elf_swap_symbol_in NAME(bfd_elf,swap_symbol_in)
+#define elf_swap_symbol_out NAME(bfd_elf,swap_symbol_out)
+#define elf_swap_dyn_in NAME(bfd_elf,swap_dyn_in)
+#define elf_swap_dyn_out NAME(bfd_elf,swap_dyn_out)
+#define elf_get_reloc_upper_bound NAME(bfd_elf,get_reloc_upper_bound)
+#define elf_canonicalize_reloc NAME(bfd_elf,canonicalize_reloc)
+#define elf_get_symtab NAME(bfd_elf,get_symtab)
+#define elf_canonicalize_dynamic_symtab \
+ NAME(bfd_elf,canonicalize_dynamic_symtab)
+#define elf_make_empty_symbol NAME(bfd_elf,make_empty_symbol)
+#define elf_get_symbol_info NAME(bfd_elf,get_symbol_info)
+#define elf_print_symbol NAME(bfd_elf,print_symbol)
+#define elf_get_lineno NAME(bfd_elf,get_lineno)
+#define elf_set_arch_mach NAME(bfd_elf,set_arch_mach)
+#define elf_find_nearest_line NAME(bfd_elf,find_nearest_line)
+#define elf_sizeof_headers NAME(bfd_elf,sizeof_headers)
+#define elf_set_section_contents NAME(bfd_elf,set_section_contents)
+#define elf_no_info_to_howto NAME(bfd_elf,no_info_to_howto)
+#define elf_no_info_to_howto_rel NAME(bfd_elf,no_info_to_howto_rel)
+#define elf_new_section_hook NAME(bfd_elf,new_section_hook)
+#define write_relocs NAME(bfd_elf,_write_relocs)
+#define elf_find_section NAME(bfd_elf,find_section)
+#define elf_bfd_link_add_symbols NAME(bfd_elf,bfd_link_add_symbols)
+#define elf_add_dynamic_entry NAME(bfd_elf,add_dynamic_entry)
+#define elf_bfd_final_link NAME(bfd_elf,bfd_final_link)
+
+#if ARCH_SIZE == 64
+#define ELF_R_INFO(X,Y) ELF64_R_INFO(X,Y)
+#define ELF_R_SYM(X) ELF64_R_SYM(X)
+#define ELF_R_TYPE(X) ELF64_R_TYPE(X)
+#define ELFCLASS ELFCLASS64
+#define FILE_ALIGN 8
+#define LOG_FILE_ALIGN 3
+#endif
+#if ARCH_SIZE == 32
+#define ELF_R_INFO(X,Y) ELF32_R_INFO(X,Y)
+#define ELF_R_SYM(X) ELF32_R_SYM(X)
+#define ELF_R_TYPE(X) ELF32_R_TYPE(X)
+#define ELFCLASS ELFCLASS32
+#define FILE_ALIGN 4
+#define LOG_FILE_ALIGN 2
+#endif
+
+/* Forward declarations of static functions */
+
+static unsigned long bfd_add_to_strtab
+ PARAMS ((bfd *, struct strtab *, const char *));
+static asection *section_from_elf_index PARAMS ((bfd *, unsigned int));
+
+static int elf_section_from_bfd_section PARAMS ((bfd *, struct sec *));
+
+static long elf_slurp_symbol_table PARAMS ((bfd *, asymbol **, boolean));
+
+static boolean elf_slurp_reloc_table PARAMS ((bfd *, asection *, asymbol **));
+
+static int elf_symbol_from_bfd_symbol PARAMS ((bfd *,
+ struct symbol_cache_entry **));
+
+static boolean elf_compute_section_file_positions
+ PARAMS ((bfd *, struct bfd_link_info *));
+static boolean prep_headers PARAMS ((bfd *));
+static void elf_fake_sections PARAMS ((bfd *, asection *, PTR));
+static boolean assign_section_numbers PARAMS ((bfd *));
+static file_ptr align_file_position PARAMS ((file_ptr));
+static file_ptr assign_file_position_for_section
+ PARAMS ((Elf_Internal_Shdr *, file_ptr, boolean));
+static boolean assign_file_positions_except_relocs PARAMS ((bfd *, boolean));
+static void assign_file_positions_for_relocs PARAMS ((bfd *));
+static bfd_size_type get_program_header_size PARAMS ((bfd *));
+static file_ptr map_program_segments
+ PARAMS ((bfd *, file_ptr, Elf_Internal_Shdr *, bfd_size_type));
+
+static boolean elf_map_symbols PARAMS ((bfd *));
+static boolean swap_out_syms PARAMS ((bfd *));
+
+static boolean bfd_section_from_shdr PARAMS ((bfd *, unsigned int shindex));
+
+#ifdef DEBUG
+static void elf_debug_section PARAMS ((char *, int, Elf_Internal_Shdr *));
+static void elf_debug_file PARAMS ((Elf_Internal_Ehdr *));
+#endif
+
+#define elf_string_from_elf_strtab(abfd,strindex) \
+ elf_string_from_elf_section(abfd,elf_elfheader(abfd)->e_shstrndx,strindex)
+
+
+/* Structure swapping routines */
+
+/* Should perhaps use put_offset, put_word, etc. For now, the two versions
+ can be handled by explicitly specifying 32 bits or "the long type". */
+#if ARCH_SIZE == 64
+#define put_word bfd_h_put_64
+#define get_word bfd_h_get_64
+#endif
+#if ARCH_SIZE == 32
+#define put_word bfd_h_put_32
+#define get_word bfd_h_get_32
+#endif
+
+/* Translate an ELF symbol in external format into an ELF symbol in internal
+ format. */
+
+void
+elf_swap_symbol_in (abfd, src, dst)
+ bfd *abfd;
+ Elf_External_Sym *src;
+ Elf_Internal_Sym *dst;
+{
+ dst->st_name = bfd_h_get_32 (abfd, (bfd_byte *) src->st_name);
+ dst->st_value = get_word (abfd, (bfd_byte *) src->st_value);
+ dst->st_size = get_word (abfd, (bfd_byte *) src->st_size);
+ dst->st_info = bfd_h_get_8 (abfd, (bfd_byte *) src->st_info);
+ dst->st_other = bfd_h_get_8 (abfd, (bfd_byte *) src->st_other);
+ dst->st_shndx = bfd_h_get_16 (abfd, (bfd_byte *) src->st_shndx);
+}
+
+/* Translate an ELF symbol in internal format into an ELF symbol in external
+ format. */
+
+void
+elf_swap_symbol_out (abfd, src, dst)
+ bfd *abfd;
+ Elf_Internal_Sym *src;
+ Elf_External_Sym *dst;
+{
+ bfd_h_put_32 (abfd, src->st_name, dst->st_name);
+ put_word (abfd, src->st_value, dst->st_value);
+ put_word (abfd, src->st_size, dst->st_size);
+ bfd_h_put_8 (abfd, src->st_info, dst->st_info);
+ bfd_h_put_8 (abfd, src->st_other, dst->st_other);
+ bfd_h_put_16 (abfd, src->st_shndx, dst->st_shndx);
+}
+
+
+/* Translate an ELF file header in external format into an ELF file header in
+ internal format. */
+
+static void
+elf_swap_ehdr_in (abfd, src, dst)
+ bfd *abfd;
+ Elf_External_Ehdr *src;
+ Elf_Internal_Ehdr *dst;
+{
+ memcpy (dst->e_ident, src->e_ident, EI_NIDENT);
+ dst->e_type = bfd_h_get_16 (abfd, (bfd_byte *) src->e_type);
+ dst->e_machine = bfd_h_get_16 (abfd, (bfd_byte *) src->e_machine);
+ dst->e_version = bfd_h_get_32 (abfd, (bfd_byte *) src->e_version);
+ dst->e_entry = get_word (abfd, (bfd_byte *) src->e_entry);
+ dst->e_phoff = get_word (abfd, (bfd_byte *) src->e_phoff);
+ dst->e_shoff = get_word (abfd, (bfd_byte *) src->e_shoff);
+ dst->e_flags = bfd_h_get_32 (abfd, (bfd_byte *) src->e_flags);
+ dst->e_ehsize = bfd_h_get_16 (abfd, (bfd_byte *) src->e_ehsize);
+ dst->e_phentsize = bfd_h_get_16 (abfd, (bfd_byte *) src->e_phentsize);
+ dst->e_phnum = bfd_h_get_16 (abfd, (bfd_byte *) src->e_phnum);
+ dst->e_shentsize = bfd_h_get_16 (abfd, (bfd_byte *) src->e_shentsize);
+ dst->e_shnum = bfd_h_get_16 (abfd, (bfd_byte *) src->e_shnum);
+ dst->e_shstrndx = bfd_h_get_16 (abfd, (bfd_byte *) src->e_shstrndx);
+}
+
+/* Translate an ELF file header in internal format into an ELF file header in
+ external format. */
+
+static void
+elf_swap_ehdr_out (abfd, src, dst)
+ bfd *abfd;
+ Elf_Internal_Ehdr *src;
+ Elf_External_Ehdr *dst;
+{
+ memcpy (dst->e_ident, src->e_ident, EI_NIDENT);
+ /* note that all elements of dst are *arrays of unsigned char* already... */
+ bfd_h_put_16 (abfd, src->e_type, dst->e_type);
+ bfd_h_put_16 (abfd, src->e_machine, dst->e_machine);
+ bfd_h_put_32 (abfd, src->e_version, dst->e_version);
+ put_word (abfd, src->e_entry, dst->e_entry);
+ put_word (abfd, src->e_phoff, dst->e_phoff);
+ put_word (abfd, src->e_shoff, dst->e_shoff);
+ bfd_h_put_32 (abfd, src->e_flags, dst->e_flags);
+ bfd_h_put_16 (abfd, src->e_ehsize, dst->e_ehsize);
+ bfd_h_put_16 (abfd, src->e_phentsize, dst->e_phentsize);
+ bfd_h_put_16 (abfd, src->e_phnum, dst->e_phnum);
+ bfd_h_put_16 (abfd, src->e_shentsize, dst->e_shentsize);
+ bfd_h_put_16 (abfd, src->e_shnum, dst->e_shnum);
+ bfd_h_put_16 (abfd, src->e_shstrndx, dst->e_shstrndx);
+}
+
+
+/* Translate an ELF section header table entry in external format into an
+ ELF section header table entry in internal format. */
+
+static void
+elf_swap_shdr_in (abfd, src, dst)
+ bfd *abfd;
+ Elf_External_Shdr *src;
+ Elf_Internal_Shdr *dst;
+{
+ dst->sh_name = bfd_h_get_32 (abfd, (bfd_byte *) src->sh_name);
+ dst->sh_type = bfd_h_get_32 (abfd, (bfd_byte *) src->sh_type);
+ dst->sh_flags = get_word (abfd, (bfd_byte *) src->sh_flags);
+ dst->sh_addr = get_word (abfd, (bfd_byte *) src->sh_addr);
+ dst->sh_offset = get_word (abfd, (bfd_byte *) src->sh_offset);
+ dst->sh_size = get_word (abfd, (bfd_byte *) src->sh_size);
+ dst->sh_link = bfd_h_get_32 (abfd, (bfd_byte *) src->sh_link);
+ dst->sh_info = bfd_h_get_32 (abfd, (bfd_byte *) src->sh_info);
+ dst->sh_addralign = get_word (abfd, (bfd_byte *) src->sh_addralign);
+ dst->sh_entsize = get_word (abfd, (bfd_byte *) src->sh_entsize);
+ /* we haven't done any processing on it yet, so... */
+ dst->rawdata = (void *) 0;
+}
+
+/* Translate an ELF section header table entry in internal format into an
+ ELF section header table entry in external format. */
+
+static void
+elf_swap_shdr_out (abfd, src, dst)
+ bfd *abfd;
+ Elf_Internal_Shdr *src;
+ Elf_External_Shdr *dst;
+{
+ /* note that all elements of dst are *arrays of unsigned char* already... */
+ bfd_h_put_32 (abfd, src->sh_name, dst->sh_name);
+ bfd_h_put_32 (abfd, src->sh_type, dst->sh_type);
+ put_word (abfd, src->sh_flags, dst->sh_flags);
+ put_word (abfd, src->sh_addr, dst->sh_addr);
+ put_word (abfd, src->sh_offset, dst->sh_offset);
+ put_word (abfd, src->sh_size, dst->sh_size);
+ bfd_h_put_32 (abfd, src->sh_link, dst->sh_link);
+ bfd_h_put_32 (abfd, src->sh_info, dst->sh_info);
+ put_word (abfd, src->sh_addralign, dst->sh_addralign);
+ put_word (abfd, src->sh_entsize, dst->sh_entsize);
+}
+
+
+/* Translate an ELF program header table entry in external format into an
+ ELF program header table entry in internal format. */
+
+static void
+elf_swap_phdr_in (abfd, src, dst)
+ bfd *abfd;
+ Elf_External_Phdr *src;
+ Elf_Internal_Phdr *dst;
+{
+ dst->p_type = bfd_h_get_32 (abfd, (bfd_byte *) src->p_type);
+ dst->p_flags = bfd_h_get_32 (abfd, (bfd_byte *) src->p_flags);
+ dst->p_offset = get_word (abfd, (bfd_byte *) src->p_offset);
+ dst->p_vaddr = get_word (abfd, (bfd_byte *) src->p_vaddr);
+ dst->p_paddr = get_word (abfd, (bfd_byte *) src->p_paddr);
+ dst->p_filesz = get_word (abfd, (bfd_byte *) src->p_filesz);
+ dst->p_memsz = get_word (abfd, (bfd_byte *) src->p_memsz);
+ dst->p_align = get_word (abfd, (bfd_byte *) src->p_align);
+}
+
+static void
+elf_swap_phdr_out (abfd, src, dst)
+ bfd *abfd;
+ Elf_Internal_Phdr *src;
+ Elf_External_Phdr *dst;
+{
+ /* note that all elements of dst are *arrays of unsigned char* already... */
+ bfd_h_put_32 (abfd, src->p_type, dst->p_type);
+ put_word (abfd, src->p_offset, dst->p_offset);
+ put_word (abfd, src->p_vaddr, dst->p_vaddr);
+ put_word (abfd, src->p_paddr, dst->p_paddr);
+ put_word (abfd, src->p_filesz, dst->p_filesz);
+ put_word (abfd, src->p_memsz, dst->p_memsz);
+ bfd_h_put_32 (abfd, src->p_flags, dst->p_flags);
+ put_word (abfd, src->p_align, dst->p_align);
+}
+
+/* Translate an ELF reloc from external format to internal format. */
+INLINE void
+elf_swap_reloc_in (abfd, src, dst)
+ bfd *abfd;
+ Elf_External_Rel *src;
+ Elf_Internal_Rel *dst;
+{
+ dst->r_offset = get_word (abfd, (bfd_byte *) src->r_offset);
+ dst->r_info = get_word (abfd, (bfd_byte *) src->r_info);
+}
+
+INLINE void
+elf_swap_reloca_in (abfd, src, dst)
+ bfd *abfd;
+ Elf_External_Rela *src;
+ Elf_Internal_Rela *dst;
+{
+ dst->r_offset = get_word (abfd, (bfd_byte *) src->r_offset);
+ dst->r_info = get_word (abfd, (bfd_byte *) src->r_info);
+ dst->r_addend = get_word (abfd, (bfd_byte *) src->r_addend);
+}
+
+/* Translate an ELF reloc from internal format to external format. */
+INLINE void
+elf_swap_reloc_out (abfd, src, dst)
+ bfd *abfd;
+ Elf_Internal_Rel *src;
+ Elf_External_Rel *dst;
+{
+ put_word (abfd, src->r_offset, dst->r_offset);
+ put_word (abfd, src->r_info, dst->r_info);
+}
+
+INLINE void
+elf_swap_reloca_out (abfd, src, dst)
+ bfd *abfd;
+ Elf_Internal_Rela *src;
+ Elf_External_Rela *dst;
+{
+ put_word (abfd, src->r_offset, dst->r_offset);
+ put_word (abfd, src->r_info, dst->r_info);
+ put_word (abfd, src->r_addend, dst->r_addend);
+}
+
+INLINE void
+elf_swap_dyn_in (abfd, src, dst)
+ bfd *abfd;
+ const Elf_External_Dyn *src;
+ Elf_Internal_Dyn *dst;
+{
+ dst->d_tag = get_word (abfd, src->d_tag);
+ dst->d_un.d_val = get_word (abfd, src->d_un.d_val);
+}
+
+INLINE void
+elf_swap_dyn_out (abfd, src, dst)
+ bfd *abfd;
+ const Elf_Internal_Dyn *src;
+ Elf_External_Dyn *dst;
+{
+ put_word (abfd, src->d_tag, dst->d_tag);
+ put_word (abfd, src->d_un.d_val, dst->d_un.d_val);
+}
+
+/* String table creation/manipulation routines */
+
+static struct strtab *
+bfd_new_strtab (abfd)
+ bfd *abfd;
+{
+ struct strtab *ss;
+
+ ss = (struct strtab *) malloc (sizeof (struct strtab));
+ if (!ss)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ return NULL;
+ }
+ ss->tab = malloc (1);
+ if (!ss->tab)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ return NULL;
+ }
+ *ss->tab = 0;
+ ss->nentries = 0;
+ ss->length = 1;
+
+ return ss;
+}
+
+static unsigned long
+bfd_add_to_strtab (abfd, ss, str)
+ bfd *abfd;
+ struct strtab *ss;
+ const char *str;
+{
+ /* should search first, but for now: */
+ /* include the trailing NUL */
+ int ln = strlen (str) + 1;
+
+ /* FIXME: This is slow. Also, we could combine this with the a.out
+ string table building and use a hash table, although it might not
+ be worth it since ELF symbols don't include debugging information
+ and thus have much less overlap. */
+ ss->tab = realloc (ss->tab, ss->length + ln);
+ if (ss->tab == NULL)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ return (unsigned long) -1;
+ }
+
+ strcpy (ss->tab + ss->length, str);
+ ss->nentries++;
+ ss->length += ln;
+
+ return ss->length - ln;
+}
+
+static int
+bfd_add_2_to_strtab (abfd, ss, str, str2)
+ bfd *abfd;
+ struct strtab *ss;
+ char *str;
+ CONST char *str2;
+{
+ /* should search first, but for now: */
+ /* include the trailing NUL */
+ int ln = strlen (str) + strlen (str2) + 1;
+
+ /* should this be using obstacks? */
+ if (ss->length)
+ ss->tab = realloc (ss->tab, ss->length + ln);
+ else
+ ss->tab = malloc (ln);
+
+ BFD_ASSERT (ss->tab != 0); /* FIXME */
+ strcpy (ss->tab + ss->length, str);
+ strcpy (ss->tab + ss->length + strlen (str), str2);
+ ss->nentries++;
+ ss->length += ln;
+
+ return ss->length - ln;
+}
+
+/* ELF .o/exec file reading */
+
+/* Create a new bfd section from an ELF section header. */
+
+static boolean
+bfd_section_from_shdr (abfd, shindex)
+ bfd *abfd;
+ unsigned int shindex;
+{
+ Elf_Internal_Shdr *hdr = elf_elfsections (abfd)[shindex];
+ Elf_Internal_Ehdr *ehdr = elf_elfheader (abfd);
+ char *name;
+
+ name = elf_string_from_elf_strtab (abfd, hdr->sh_name);
+
+ switch (hdr->sh_type)
+ {
+ case SHT_NULL:
+ /* Inactive section. Throw it away. */
+ return true;
+
+ case SHT_PROGBITS: /* Normal section with contents. */
+ case SHT_DYNAMIC: /* Dynamic linking information. */
+ case SHT_NOBITS: /* .bss section. */
+ case SHT_HASH: /* .hash section. */
+ return _bfd_elf_make_section_from_shdr (abfd, hdr, name);
+
+ case SHT_SYMTAB: /* A symbol table */
+ if (elf_onesymtab (abfd) == shindex)
+ return true;
+
+ BFD_ASSERT (hdr->sh_entsize == sizeof (Elf_External_Sym));
+ BFD_ASSERT (elf_onesymtab (abfd) == 0);
+ elf_onesymtab (abfd) = shindex;
+ elf_tdata (abfd)->symtab_hdr = *hdr;
+ elf_elfsections (abfd)[shindex] = &elf_tdata (abfd)->symtab_hdr;
+ abfd->flags |= HAS_SYMS;
+ return true;
+
+ case SHT_DYNSYM: /* A dynamic symbol table */
+ if (elf_dynsymtab (abfd) == shindex)
+ return true;
+
+ BFD_ASSERT (hdr->sh_entsize == sizeof (Elf_External_Sym));
+ BFD_ASSERT (elf_dynsymtab (abfd) == 0);
+ elf_dynsymtab (abfd) = shindex;
+ elf_tdata (abfd)->dynsymtab_hdr = *hdr;
+ elf_elfsections (abfd)[shindex] = &elf_tdata (abfd)->dynsymtab_hdr;
+ abfd->flags |= HAS_SYMS;
+
+ /* Besides being a symbol table, we also treat this as a regular
+ section, so that objcopy can handle it. */
+ return _bfd_elf_make_section_from_shdr (abfd, hdr, name);
+
+ case SHT_STRTAB: /* A string table */
+ if (hdr->rawdata != NULL)
+ return true;
+ if (ehdr->e_shstrndx == shindex)
+ {
+ elf_tdata (abfd)->shstrtab_hdr = *hdr;
+ elf_elfsections (abfd)[shindex] = &elf_tdata (abfd)->shstrtab_hdr;
+ hdr->rawdata = (PTR) & elf_tdata (abfd)->shstrtab_hdr;
+ return true;
+ }
+ {
+ unsigned int i;
+
+ for (i = 1; i < ehdr->e_shnum; i++)
+ {
+ Elf_Internal_Shdr *hdr2 = elf_elfsections (abfd)[i];
+ if (hdr2->sh_link == shindex)
+ {
+ if (! bfd_section_from_shdr (abfd, i))
+ return false;
+ if (elf_onesymtab (abfd) == i)
+ {
+ elf_tdata (abfd)->strtab_hdr = *hdr;
+ elf_elfsections (abfd)[shindex] =
+ &elf_tdata (abfd)->strtab_hdr;
+ return true;
+ }
+ if (elf_dynsymtab (abfd) == i)
+ {
+ elf_tdata (abfd)->dynstrtab_hdr = *hdr;
+ elf_elfsections (abfd)[shindex] =
+ &elf_tdata (abfd)->dynstrtab_hdr;
+ /* We also treat this as a regular section, so
+ that objcopy can handle it. */
+ break;
+ }
+#if 0 /* Not handling other string tables specially right now. */
+ hdr2 = elf_elfsections (abfd)[i]; /* in case it moved */
+ /* We have a strtab for some random other section. */
+ newsect = (asection *) hdr2->rawdata;
+ if (!newsect)
+ break;
+ hdr->rawdata = (PTR) newsect;
+ hdr2 = &elf_section_data (newsect)->str_hdr;
+ *hdr2 = *hdr;
+ elf_elfsections (abfd)[shindex] = hdr2;
+#endif
+ }
+ }
+ }
+
+ return _bfd_elf_make_section_from_shdr (abfd, hdr, name);
+
+ case SHT_REL:
+ case SHT_RELA:
+ /* *These* do a lot of work -- but build no sections! */
+ {
+ asection *target_sect;
+ Elf_Internal_Shdr *hdr2;
+ int use_rela_p = get_elf_backend_data (abfd)->use_rela_p;
+
+ /* Get the symbol table. */
+ if (! bfd_section_from_shdr (abfd, hdr->sh_link))
+ return false;
+
+ /* If this reloc section does not use the main symbol table we
+ don't treat it as a reloc section. BFD can't adequately
+ represent such a section, so at least for now, we don't
+ try. We just present it as a normal section. */
+ if (hdr->sh_link != elf_onesymtab (abfd))
+ return _bfd_elf_make_section_from_shdr (abfd, hdr, name);
+
+ /* Don't allow REL relocations on a machine that uses RELA and
+ vice versa. */
+ /* @@ Actually, the generic ABI does suggest that both might be
+ used in one file. But the four ABI Processor Supplements I
+ have access to right now all specify that only one is used on
+ each of those architectures. It's conceivable that, e.g., a
+ bunch of absolute 32-bit relocs might be more compact in REL
+ form even on a RELA machine... */
+ BFD_ASSERT (use_rela_p
+ ? (hdr->sh_type == SHT_RELA
+ && hdr->sh_entsize == sizeof (Elf_External_Rela))
+ : (hdr->sh_type == SHT_REL
+ && hdr->sh_entsize == sizeof (Elf_External_Rel)));
+
+ if (! bfd_section_from_shdr (abfd, hdr->sh_info))
+ return false;
+ target_sect = section_from_elf_index (abfd, hdr->sh_info);
+ if (target_sect == NULL
+ || elf_section_data (target_sect) == NULL)
+ return false;
+
+ hdr2 = &elf_section_data (target_sect)->rel_hdr;
+ *hdr2 = *hdr;
+ elf_elfsections (abfd)[shindex] = hdr2;
+ target_sect->reloc_count = hdr->sh_size / hdr->sh_entsize;
+ target_sect->flags |= SEC_RELOC;
+ target_sect->relocation = NULL;
+ target_sect->rel_filepos = hdr->sh_offset;
+ abfd->flags |= HAS_RELOC;
+ return true;
+ }
+ break;
+
+ case SHT_NOTE:
+#if 0
+ fprintf (stderr, "Note Sections not yet supported.\n");
+ BFD_FAIL ();
+#endif
+ break;
+
+ case SHT_SHLIB:
+#if 0
+ fprintf (stderr, "SHLIB Sections not supported (and non conforming.)\n");
+#endif
+ return true;
+
+ default:
+ /* Check for any processor-specific section types. */
+ {
+ struct elf_backend_data *bed = get_elf_backend_data (abfd);
+
+ if (bed->elf_backend_section_from_shdr)
+ (*bed->elf_backend_section_from_shdr) (abfd, hdr, name);
+ }
+ break;
+ }
+
+ return true;
+}
+
+boolean
+elf_new_section_hook (abfd, sec)
+ bfd *abfd
+ ;
+ asection *sec;
+{
+ struct bfd_elf_section_data *sdata;
+
+ sdata = (struct bfd_elf_section_data *) bfd_alloc (abfd, sizeof (*sdata));
+ if (!sdata)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ return false;
+ }
+ sec->used_by_bfd = (PTR) sdata;
+ memset (sdata, 0, sizeof (*sdata));
+ return true;
+}
+
+/* Create a new bfd section from an ELF program header.
+
+ Since program segments have no names, we generate a synthetic name
+ of the form segment<NUM>, where NUM is generally the index in the
+ program header table. For segments that are split (see below) we
+ generate the names segment<NUM>a and segment<NUM>b.
+
+ Note that some program segments may have a file size that is different than
+ (less than) the memory size. All this means is that at execution the
+ system must allocate the amount of memory specified by the memory size,
+ but only initialize it with the first "file size" bytes read from the
+ file. This would occur for example, with program segments consisting
+ of combined data+bss.
+
+ To handle the above situation, this routine generates TWO bfd sections
+ for the single program segment. The first has the length specified by
+ the file size of the segment, and the second has the length specified
+ by the difference between the two sizes. In effect, the segment is split
+ into it's initialized and uninitialized parts.
+
+ */
+
+static boolean
+bfd_section_from_phdr (abfd, hdr, index)
+ bfd *abfd;
+ Elf_Internal_Phdr *hdr;
+ int index;
+{
+ asection *newsect;
+ char *name;
+ char namebuf[64];
+ int split;
+
+ split = ((hdr->p_memsz > 0) &&
+ (hdr->p_filesz > 0) &&
+ (hdr->p_memsz > hdr->p_filesz));
+ sprintf (namebuf, split ? "segment%da" : "segment%d", index);
+ name = bfd_alloc (abfd, strlen (namebuf) + 1);
+ if (!name)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ return false;
+ }
+ strcpy (name, namebuf);
+ newsect = bfd_make_section (abfd, name);
+ if (newsect == NULL)
+ return false;
+ newsect->vma = hdr->p_vaddr;
+ newsect->_raw_size = hdr->p_filesz;
+ newsect->filepos = hdr->p_offset;
+ newsect->flags |= SEC_HAS_CONTENTS;
+ if (hdr->p_type == PT_LOAD)
+ {
+ newsect->flags |= SEC_ALLOC;
+ newsect->flags |= SEC_LOAD;
+ if (hdr->p_flags & PF_X)
+ {
+ /* FIXME: all we known is that it has execute PERMISSION,
+ may be data. */
+ newsect->flags |= SEC_CODE;
+ }
+ }
+ if (!(hdr->p_flags & PF_W))
+ {
+ newsect->flags |= SEC_READONLY;
+ }
+
+ if (split)
+ {
+ sprintf (namebuf, "segment%db", index);
+ name = bfd_alloc (abfd, strlen (namebuf) + 1);
+ if (!name)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ return false;
+ }
+ strcpy (name, namebuf);
+ newsect = bfd_make_section (abfd, name);
+ if (newsect == NULL)
+ return false;
+ newsect->vma = hdr->p_vaddr + hdr->p_filesz;
+ newsect->_raw_size = hdr->p_memsz - hdr->p_filesz;
+ if (hdr->p_type == PT_LOAD)
+ {
+ newsect->flags |= SEC_ALLOC;
+ if (hdr->p_flags & PF_X)
+ newsect->flags |= SEC_CODE;
+ }
+ if (!(hdr->p_flags & PF_W))
+ newsect->flags |= SEC_READONLY;
+ }
+
+ return true;
+}
+
+/* Begin processing a given object.
+
+ First we validate the file by reading in the ELF header and checking
+ the magic number. */
+
+static INLINE boolean
+elf_file_p (x_ehdrp)
+ Elf_External_Ehdr *x_ehdrp;
+{
+ return ((x_ehdrp->e_ident[EI_MAG0] == ELFMAG0)
+ && (x_ehdrp->e_ident[EI_MAG1] == ELFMAG1)
+ && (x_ehdrp->e_ident[EI_MAG2] == ELFMAG2)
+ && (x_ehdrp->e_ident[EI_MAG3] == ELFMAG3));
+}
+
+/* Check to see if the file associated with ABFD matches the target vector
+ that ABFD points to.
+
+ Note that we may be called several times with the same ABFD, but different
+ target vectors, most of which will not match. We have to avoid leaving
+ any side effects in ABFD, or any data it points to (like tdata), if the
+ file does not match the target vector. */
+
+const bfd_target *
+elf_object_p (abfd)
+ bfd *abfd;
+{
+ Elf_External_Ehdr x_ehdr; /* Elf file header, external form */
+ Elf_Internal_Ehdr *i_ehdrp; /* Elf file header, internal form */
+ Elf_External_Shdr x_shdr; /* Section header table entry, external form */
+ Elf_Internal_Shdr *i_shdrp = NULL; /* Section header table, internal form */
+ unsigned int shindex;
+ char *shstrtab; /* Internal copy of section header stringtab */
+ struct elf_backend_data *ebd;
+ struct elf_obj_tdata *preserved_tdata = elf_tdata (abfd);
+ struct elf_obj_tdata *new_tdata = NULL;
+
+ /* Read in the ELF header in external format. */
+
+ if (bfd_read ((PTR) & x_ehdr, sizeof (x_ehdr), 1, abfd) != sizeof (x_ehdr))
+ {
+ if (bfd_get_error () != bfd_error_system_call)
+ goto got_wrong_format_error;
+ else
+ goto got_no_match;
+ }
+
+ /* Now check to see if we have a valid ELF file, and one that BFD can
+ make use of. The magic number must match, the address size ('class')
+ and byte-swapping must match our XVEC entry, and it must have a
+ section header table (FIXME: See comments re sections at top of this
+ file). */
+
+ if ((elf_file_p (&x_ehdr) == false) ||
+ (x_ehdr.e_ident[EI_VERSION] != EV_CURRENT) ||
+ (x_ehdr.e_ident[EI_CLASS] != ELFCLASS))
+ goto got_wrong_format_error;
+
+ /* Check that file's byte order matches xvec's */
+ switch (x_ehdr.e_ident[EI_DATA])
+ {
+ case ELFDATA2MSB: /* Big-endian */
+ if (!abfd->xvec->header_byteorder_big_p)
+ goto got_wrong_format_error;
+ break;
+ case ELFDATA2LSB: /* Little-endian */
+ if (abfd->xvec->header_byteorder_big_p)
+ goto got_wrong_format_error;
+ break;
+ case ELFDATANONE: /* No data encoding specified */
+ default: /* Unknown data encoding specified */
+ goto got_wrong_format_error;
+ }
+
+ /* Allocate an instance of the elf_obj_tdata structure and hook it up to
+ the tdata pointer in the bfd. */
+
+ new_tdata = ((struct elf_obj_tdata *)
+ bfd_zalloc (abfd, sizeof (struct elf_obj_tdata)));
+ if (new_tdata == NULL)
+ goto got_no_memory_error;
+ elf_tdata (abfd) = new_tdata;
+
+ /* Now that we know the byte order, swap in the rest of the header */
+ i_ehdrp = elf_elfheader (abfd);
+ elf_swap_ehdr_in (abfd, &x_ehdr, i_ehdrp);
+#if DEBUG & 1
+ elf_debug_file (i_ehdrp);
+#endif
+
+ /* If there is no section header table, we're hosed. */
+ if (i_ehdrp->e_shoff == 0)
+ goto got_wrong_format_error;
+
+ /* As a simple sanity check, verify that the what BFD thinks is the
+ size of each section header table entry actually matches the size
+ recorded in the file. */
+ if (i_ehdrp->e_shentsize != sizeof (x_shdr))
+ goto got_wrong_format_error;
+
+ ebd = get_elf_backend_data (abfd);
+
+ /* Check that the ELF e_machine field matches what this particular
+ BFD format expects. */
+ if (ebd->elf_machine_code != i_ehdrp->e_machine)
+ {
+ const bfd_target * const *target_ptr;
+
+ if (ebd->elf_machine_code != EM_NONE)
+ goto got_wrong_format_error;
+
+ /* This is the generic ELF target. Let it match any ELF target
+ for which we do not have a specific backend. */
+ for (target_ptr = bfd_target_vector; *target_ptr != NULL; target_ptr++)
+ {
+ struct elf_backend_data *back;
+
+ if ((*target_ptr)->flavour != bfd_target_elf_flavour)
+ continue;
+ back = (struct elf_backend_data *) (*target_ptr)->backend_data;
+ if (back->elf_machine_code == i_ehdrp->e_machine)
+ {
+ /* target_ptr is an ELF backend which matches this
+ object file, so reject the generic ELF target. */
+ goto got_wrong_format_error;
+ }
+ }
+ }
+
+ if (i_ehdrp->e_type == ET_EXEC)
+ abfd->flags |= EXEC_P;
+ else if (i_ehdrp->e_type == ET_DYN)
+ abfd->flags |= DYNAMIC;
+
+ if (i_ehdrp->e_phnum > 0)
+ abfd->flags |= D_PAGED;
+
+ if (! bfd_default_set_arch_mach (abfd, ebd->arch, 0))
+ goto got_no_match;
+
+ /* Remember the entry point specified in the ELF file header. */
+ bfd_get_start_address (abfd) = i_ehdrp->e_entry;
+
+ /* Allocate space for a copy of the section header table in
+ internal form, seek to the section header table in the file,
+ read it in, and convert it to internal form. */
+ i_shdrp = ((Elf_Internal_Shdr *)
+ bfd_alloc (abfd, sizeof (*i_shdrp) * i_ehdrp->e_shnum));
+ elf_elfsections (abfd) = ((Elf_Internal_Shdr **)
+ bfd_alloc (abfd,
+ sizeof (i_shdrp) * i_ehdrp->e_shnum));
+ if (!i_shdrp || !elf_elfsections (abfd))
+ goto got_no_memory_error;
+ if (bfd_seek (abfd, i_ehdrp->e_shoff, SEEK_SET) != 0)
+ goto got_no_match;
+ for (shindex = 0; shindex < i_ehdrp->e_shnum; shindex++)
+ {
+ if (bfd_read ((PTR) & x_shdr, sizeof x_shdr, 1, abfd) != sizeof (x_shdr))
+ goto got_no_match;
+ elf_swap_shdr_in (abfd, &x_shdr, i_shdrp + shindex);
+ elf_elfsections (abfd)[shindex] = i_shdrp + shindex;
+ }
+ if (i_ehdrp->e_shstrndx)
+ {
+ if (! bfd_section_from_shdr (abfd, i_ehdrp->e_shstrndx))
+ goto got_no_match;
+ }
+
+ /* Read in the string table containing the names of the sections. We
+ will need the base pointer to this table later. */
+ /* We read this inline now, so that we don't have to go through
+ bfd_section_from_shdr with it (since this particular strtab is
+ used to find all of the ELF section names.) */
+
+ shstrtab = elf_get_str_section (abfd, i_ehdrp->e_shstrndx);
+ if (!shstrtab)
+ goto got_no_match;
+
+ /* Once all of the section headers have been read and converted, we
+ can start processing them. Note that the first section header is
+ a dummy placeholder entry, so we ignore it. */
+
+ for (shindex = 1; shindex < i_ehdrp->e_shnum; shindex++)
+ {
+ if (! bfd_section_from_shdr (abfd, shindex))
+ goto got_no_match;
+ }
+
+ /* Let the backend double check the format and override global
+ information. */
+ if (ebd->elf_backend_object_p)
+ {
+ if ((*ebd->elf_backend_object_p) (abfd) == false)
+ goto got_wrong_format_error;
+ }
+
+ return (abfd->xvec);
+
+got_wrong_format_error:
+ bfd_set_error (bfd_error_wrong_format);
+ goto got_no_match;
+got_no_memory_error:
+ bfd_set_error (bfd_error_no_memory);
+ goto got_no_match;
+got_no_match:
+ if (new_tdata != NULL
+ && new_tdata->elf_sect_ptr != NULL)
+ bfd_release (abfd, new_tdata->elf_sect_ptr);
+ if (i_shdrp != NULL)
+ bfd_release (abfd, i_shdrp);
+ if (new_tdata != NULL)
+ bfd_release (abfd, new_tdata);
+ elf_tdata (abfd) = preserved_tdata;
+ return (NULL);
+}
+
+
+/* ELF .o/exec file writing */
+
+/* Takes a bfd and a symbol, returns a pointer to the elf specific area
+ of the symbol if there is one. */
+static INLINE elf_symbol_type *
+elf_symbol_from (ignore_abfd, symbol)
+ bfd *ignore_abfd;
+ asymbol *symbol;
+{
+ if (symbol->the_bfd->xvec->flavour != bfd_target_elf_flavour)
+ return 0;
+
+ if (symbol->the_bfd->tdata.elf_obj_data == (struct elf_obj_tdata *) NULL)
+ return 0;
+
+ return (elf_symbol_type *) symbol;
+}
+
+void
+write_relocs (abfd, sec, xxx)
+ bfd *abfd;
+ asection *sec;
+ PTR xxx;
+{
+ Elf_Internal_Shdr *rela_hdr;
+ Elf_External_Rela *outbound_relocas;
+ Elf_External_Rel *outbound_relocs;
+ int idx;
+ int use_rela_p = get_elf_backend_data (abfd)->use_rela_p;
+ asymbol *last_sym = 0;
+ int last_sym_idx = 9999999; /* should always be written before use */
+
+ if ((sec->flags & SEC_RELOC) == 0)
+ return;
+
+ /* The linker backend writes the relocs out itself, and sets the
+ reloc_count field to zero to inhibit writing them here. Also,
+ sometimes the SEC_RELOC flag gets set even when there aren't any
+ relocs. */
+ if (sec->reloc_count == 0)
+ return;
+
+ rela_hdr = &elf_section_data (sec)->rel_hdr;
+
+ rela_hdr->sh_size = rela_hdr->sh_entsize * sec->reloc_count;
+ rela_hdr->contents = (void *) bfd_alloc (abfd, rela_hdr->sh_size);
+ if (!rela_hdr->contents)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ abort (); /* FIXME */
+ }
+
+ /* orelocation has the data, reloc_count has the count... */
+ if (use_rela_p)
+ {
+ outbound_relocas = (Elf_External_Rela *) rela_hdr->contents;
+
+ for (idx = 0; idx < sec->reloc_count; idx++)
+ {
+ Elf_Internal_Rela dst_rela;
+ Elf_External_Rela *src_rela;
+ arelent *ptr;
+ asymbol *sym;
+ int n;
+
+ ptr = sec->orelocation[idx];
+ src_rela = outbound_relocas + idx;
+ if (!(abfd->flags & EXEC_P))
+ dst_rela.r_offset = ptr->address - sec->vma;
+ else
+ dst_rela.r_offset = ptr->address;
+
+ sym = *ptr->sym_ptr_ptr;
+ if (sym == last_sym)
+ n = last_sym_idx;
+ else
+ {
+ last_sym = sym;
+ last_sym_idx = n = elf_symbol_from_bfd_symbol (abfd, &sym);
+ }
+ dst_rela.r_info = ELF_R_INFO (n, ptr->howto->type);
+
+ dst_rela.r_addend = ptr->addend;
+ elf_swap_reloca_out (abfd, &dst_rela, src_rela);
+ }
+ }
+ else
+ /* REL relocations */
+ {
+ outbound_relocs = (Elf_External_Rel *) rela_hdr->contents;
+
+ for (idx = 0; idx < sec->reloc_count; idx++)
+ {
+ Elf_Internal_Rel dst_rel;
+ Elf_External_Rel *src_rel;
+ arelent *ptr;
+ int n;
+ asymbol *sym;
+
+ ptr = sec->orelocation[idx];
+ sym = *ptr->sym_ptr_ptr;
+ src_rel = outbound_relocs + idx;
+ if (!(abfd->flags & EXEC_P))
+ dst_rel.r_offset = ptr->address - sec->vma;
+ else
+ dst_rel.r_offset = ptr->address;
+
+ if (sym == last_sym)
+ n = last_sym_idx;
+ else
+ {
+ last_sym = sym;
+ last_sym_idx = n = elf_symbol_from_bfd_symbol (abfd, &sym);
+ }
+ dst_rel.r_info = ELF_R_INFO (n, ptr->howto->type);
+
+ elf_swap_reloc_out (abfd, &dst_rel, src_rel);
+ }
+ }
+}
+
+/* Set up an ELF internal section header for a section. */
+
+/*ARGSUSED*/
+static void
+elf_fake_sections (abfd, asect, ignore)
+ bfd *abfd;
+ asection *asect;
+ PTR ignore;
+{
+ Elf_Internal_Shdr *this_hdr;
+
+ this_hdr = &elf_section_data (asect)->this_hdr;
+
+ this_hdr->sh_name = bfd_add_to_strtab (abfd, elf_shstrtab (abfd),
+ asect->name);
+ if (this_hdr->sh_name == (unsigned long) -1)
+ abort (); /* FIXME */
+
+ this_hdr->sh_flags = 0;
+ if ((asect->flags & SEC_ALLOC) != 0)
+ this_hdr->sh_addr = asect->vma;
+ else
+ this_hdr->sh_addr = 0;
+ this_hdr->sh_offset = 0;
+ this_hdr->sh_size = asect->_raw_size;
+ this_hdr->sh_link = 0;
+ this_hdr->sh_info = 0;
+ this_hdr->sh_addralign = 1 << asect->alignment_power;
+ this_hdr->sh_entsize = 0;
+
+ this_hdr->rawdata = (PTR) asect;
+ this_hdr->contents = NULL;
+ this_hdr->size = 0;
+
+ /* FIXME: This should not be based on section names. */
+ if (strcmp (asect->name, ".dynstr") == 0)
+ this_hdr->sh_type = SHT_STRTAB;
+ else if (strcmp (asect->name, ".hash") == 0)
+ {
+ this_hdr->sh_type = SHT_HASH;
+ this_hdr->sh_entsize = ARCH_SIZE / 8;
+ }
+ else if (strcmp (asect->name, ".dynsym") == 0)
+ {
+ this_hdr->sh_type = SHT_DYNSYM;
+ this_hdr->sh_entsize = sizeof (Elf_External_Sym);
+ }
+ else if (strcmp (asect->name, ".dynamic") == 0)
+ {
+ this_hdr->sh_type = SHT_DYNAMIC;
+ this_hdr->sh_entsize = sizeof (Elf_External_Dyn);
+ }
+ else if (strncmp (asect->name, ".rel.", 5) == 0)
+ {
+ this_hdr->sh_type = SHT_REL;
+ this_hdr->sh_entsize = sizeof (Elf_External_Rel);
+ }
+ else if (strncmp (asect->name, ".rela.", 6) == 0)
+ {
+ this_hdr->sh_type = SHT_RELA;
+ this_hdr->sh_entsize = sizeof (Elf_External_Rela);
+ }
+ else if (strcmp (asect->name, ".note") == 0)
+ this_hdr->sh_type = SHT_NOTE;
+ else if (strncmp (asect->name, ".stab", 5) == 0
+ && strcmp (asect->name + strlen (asect->name) - 3, "str") == 0)
+ this_hdr->sh_type = SHT_STRTAB;
+ else if ((asect->flags & SEC_ALLOC) != 0
+ && (asect->flags & SEC_LOAD) != 0)
+ this_hdr->sh_type = SHT_PROGBITS;
+ else if ((asect->flags & SEC_ALLOC) != 0
+ && ((asect->flags & SEC_LOAD) == 0))
+ {
+ BFD_ASSERT (strcmp (asect->name, ".bss") == 0
+ || strcmp (asect->name, ".sbss") == 0);
+ this_hdr->sh_type = SHT_NOBITS;
+ }
+ else
+ {
+ /* Who knows? */
+ this_hdr->sh_type = SHT_PROGBITS;
+ }
+
+ if ((asect->flags & SEC_ALLOC) != 0)
+ this_hdr->sh_flags |= SHF_ALLOC;
+ if ((asect->flags & SEC_READONLY) == 0)
+ this_hdr->sh_flags |= SHF_WRITE;
+ if ((asect->flags & SEC_CODE) != 0)
+ this_hdr->sh_flags |= SHF_EXECINSTR;
+
+ /* Check for processor-specific section types. */
+ {
+ struct elf_backend_data *bed = get_elf_backend_data (abfd);
+
+ if (bed->elf_backend_fake_sections)
+ (*bed->elf_backend_fake_sections) (abfd, this_hdr, asect);
+ }
+
+ /* If the section has relocs, set up a section header for the
+ SHT_REL[A] section. */
+ if ((asect->flags & SEC_RELOC) != 0)
+ {
+ Elf_Internal_Shdr *rela_hdr;
+ int use_rela_p = get_elf_backend_data (abfd)->use_rela_p;
+
+ rela_hdr = &elf_section_data (asect)->rel_hdr;
+ rela_hdr->sh_name =
+ bfd_add_2_to_strtab (abfd, elf_shstrtab (abfd),
+ use_rela_p ? ".rela" : ".rel",
+ asect->name);
+ rela_hdr->sh_type = use_rela_p ? SHT_RELA : SHT_REL;
+ rela_hdr->sh_entsize = (use_rela_p
+ ? sizeof (Elf_External_Rela)
+ : sizeof (Elf_External_Rel));
+ rela_hdr->sh_addralign = FILE_ALIGN;
+ rela_hdr->sh_flags = 0;
+ rela_hdr->sh_addr = 0;
+ rela_hdr->sh_size = 0;
+ rela_hdr->sh_offset = 0;
+ rela_hdr->size = 0;
+ }
+}
+
+/* Assign all ELF section numbers. The dummy first section is handled here
+ too. The link/info pointers for the standard section types are filled
+ in here too, while we're at it. */
+
+static boolean
+assign_section_numbers (abfd)
+ bfd *abfd;
+{
+ struct elf_obj_tdata *t = elf_tdata (abfd);
+ asection *sec;
+ unsigned int section_number;
+ Elf_Internal_Shdr **i_shdrp;
+
+ section_number = 1;
+
+ for (sec = abfd->sections; sec; sec = sec->next)
+ {
+ struct bfd_elf_section_data *d = elf_section_data (sec);
+
+ d->this_idx = section_number++;
+ if ((sec->flags & SEC_RELOC) == 0)
+ d->rel_idx = 0;
+ else
+ d->rel_idx = section_number++;
+ }
+
+ t->shstrtab_section = section_number++;
+ elf_elfheader (abfd)->e_shstrndx = t->shstrtab_section;
+ t->shstrtab_hdr.sh_size = elf_shstrtab (abfd)->length;
+ t->shstrtab_hdr.contents = (PTR) elf_shstrtab (abfd)->tab;
+
+ if (abfd->symcount > 0)
+ {
+ t->symtab_section = section_number++;
+ t->strtab_section = section_number++;
+ }
+
+ elf_elfheader (abfd)->e_shnum = section_number;
+
+ /* Set up the list of section header pointers, in agreement with the
+ indices. */
+ i_shdrp = ((Elf_Internal_Shdr **)
+ bfd_alloc (abfd, section_number * sizeof (Elf_Internal_Shdr *)));
+ if (i_shdrp == NULL)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ return false;
+ }
+
+ i_shdrp[0] = ((Elf_Internal_Shdr *)
+ bfd_alloc (abfd, sizeof (Elf_Internal_Shdr)));
+ if (i_shdrp[0] == NULL)
+ {
+ bfd_release (abfd, i_shdrp);
+ bfd_set_error (bfd_error_no_memory);
+ return false;
+ }
+ memset (i_shdrp[0], 0, sizeof (Elf_Internal_Shdr));
+
+ elf_elfsections (abfd) = i_shdrp;
+
+ i_shdrp[t->shstrtab_section] = &t->shstrtab_hdr;
+ if (abfd->symcount > 0)
+ {
+ i_shdrp[t->symtab_section] = &t->symtab_hdr;
+ i_shdrp[t->strtab_section] = &t->strtab_hdr;
+ t->symtab_hdr.sh_link = t->strtab_section;
+ }
+ for (sec = abfd->sections; sec; sec = sec->next)
+ {
+ struct bfd_elf_section_data *d = elf_section_data (sec);
+ asection *s;
+ const char *name;
+
+ i_shdrp[d->this_idx] = &d->this_hdr;
+ if (d->rel_idx != 0)
+ i_shdrp[d->rel_idx] = &d->rel_hdr;
+
+ /* Fill in the sh_link and sh_info fields while we're at it. */
+
+ /* sh_link of a reloc section is the section index of the symbol
+ table. sh_info is the section index of the section to which
+ the relocation entries apply. */
+ if (d->rel_idx != 0)
+ {
+ d->rel_hdr.sh_link = t->symtab_section;
+ d->rel_hdr.sh_info = d->this_idx;
+ }
+
+ switch (d->this_hdr.sh_type)
+ {
+ case SHT_REL:
+ case SHT_RELA:
+ /* A reloc section which we are treating as a normal BFD
+ section. sh_link is the section index of the symbol
+ table. sh_info is the section index of the section to
+ which the relocation entries apply. We assume that an
+ allocated reloc section uses the dynamic symbol table.
+ FIXME: How can we be sure? */
+ s = bfd_get_section_by_name (abfd, ".dynsym");
+ if (s != NULL)
+ d->this_hdr.sh_link = elf_section_data (s)->this_idx;
+
+ /* We look up the section the relocs apply to by name. */
+ name = sec->name;
+ if (d->this_hdr.sh_type == SHT_REL)
+ name += 4;
+ else
+ name += 5;
+ s = bfd_get_section_by_name (abfd, name);
+ if (s != NULL)
+ d->this_hdr.sh_info = elf_section_data (s)->this_idx;
+ break;
+
+ case SHT_STRTAB:
+ /* We assume that a section named .stab*str is a stabs
+ string section. We look for a section with the same name
+ but without the trailing ``str'', and set its sh_link
+ field to point to this section. */
+ if (strncmp (sec->name, ".stab", sizeof ".stab" - 1) == 0
+ && strcmp (sec->name + strlen (sec->name) - 3, "str") == 0)
+ {
+ size_t len;
+ char *alc;
+
+ len = strlen (sec->name);
+ alc = (char *) malloc (len - 2);
+ if (alc == NULL)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ return false;
+ }
+ strncpy (alc, sec->name, len - 3);
+ alc[len - 3] = '\0';
+ s = bfd_get_section_by_name (abfd, alc);
+ free (alc);
+ if (s != NULL)
+ {
+ elf_section_data (s)->this_hdr.sh_link = d->this_idx;
+
+ /* This is a .stab section. */
+ elf_section_data (s)->this_hdr.sh_entsize =
+ 4 + 2 * (ARCH_SIZE / 8);
+ }
+ }
+ break;
+
+ case SHT_DYNAMIC:
+ case SHT_DYNSYM:
+ /* sh_link is the section header index of the string table
+ used for the dynamic entries or symbol table. */
+ s = bfd_get_section_by_name (abfd, ".dynstr");
+ if (s != NULL)
+ d->this_hdr.sh_link = elf_section_data (s)->this_idx;
+ break;
+
+ case SHT_HASH:
+ /* sh_link is the section header index of the symbol table
+ this hash table is for. */
+ s = bfd_get_section_by_name (abfd, ".dynsym");
+ if (s != NULL)
+ d->this_hdr.sh_link = elf_section_data (s)->this_idx;
+ break;
+ }
+ }
+
+ return true;
+}
+
+/* Map symbol from it's internal number to the external number, moving
+ all local symbols to be at the head of the list. */
+
+static INLINE int
+sym_is_global (abfd, sym)
+ bfd *abfd;
+ asymbol *sym;
+{
+ /* If the backend has a special mapping, use it. */
+ if (get_elf_backend_data (abfd)->elf_backend_sym_is_global)
+ return ((*get_elf_backend_data (abfd)->elf_backend_sym_is_global)
+ (abfd, sym));
+
+ if (sym->flags & (BSF_GLOBAL | BSF_WEAK))
+ {
+ if (sym->flags & BSF_LOCAL)
+ abort ();
+ return 1;
+ }
+ if (sym->section == 0)
+ {
+ /* Is this valid? */
+ abort ();
+
+ return 1;
+ }
+ if (bfd_is_und_section (sym->section))
+ return 1;
+ if (bfd_is_com_section (sym->section))
+ return 1;
+ if (sym->flags & (BSF_LOCAL | BSF_SECTION_SYM | BSF_FILE))
+ return 0;
+ return 0;
+}
+
+static boolean
+elf_map_symbols (abfd)
+ bfd *abfd;
+{
+ int symcount = bfd_get_symcount (abfd);
+ asymbol **syms = bfd_get_outsymbols (abfd);
+ asymbol **sect_syms;
+ int num_locals = 0;
+ int num_globals = 0;
+ int num_locals2 = 0;
+ int num_globals2 = 0;
+ int max_index = 0;
+ int num_sections = 0;
+ Elf_Sym_Extra *sym_extra;
+ int idx;
+ asection *asect;
+
+#ifdef DEBUG
+ fprintf (stderr, "elf_map_symbols\n");
+ fflush (stderr);
+#endif
+
+ /* Add local symbols for each section for which there are relocs.
+ FIXME: How can we tell which sections have relocs at this point?
+ Will reloc_count always be accurate? Actually, I think most ELF
+ targets create section symbols for all sections anyhow. */
+ for (asect = abfd->sections; asect; asect = asect->next)
+ {
+ if (max_index < asect->index)
+ max_index = asect->index;
+ }
+
+ max_index++;
+ elf_num_section_syms (abfd) = max_index;
+ sect_syms = (asymbol **) bfd_zalloc (abfd, max_index * sizeof (asymbol *));
+ elf_section_syms (abfd) = sect_syms;
+
+ if (sect_syms == 0)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ return false;
+ }
+
+ for (asect = abfd->sections; asect; asect = asect->next)
+ {
+ asymbol *sym = bfd_make_empty_symbol (abfd);
+ if (!sym)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ return false;
+ }
+ sym->the_bfd = abfd;
+ sym->name = asect->name;
+ sym->value = asect->vma;
+ sym->flags = BSF_SECTION_SYM;
+ sym->section = asect;
+ sect_syms[asect->index] = sym;
+ num_sections++;
+#ifdef DEBUG
+ fprintf (stderr,
+ "creating section symbol, name = %s, value = 0x%.8lx, index = %d, section = 0x%.8lx\n",
+ asect->name, (long) asect->vma, asect->index, (long) asect);
+#endif
+ }
+
+ if (num_sections)
+ {
+ if (syms)
+ syms = (asymbol **) bfd_realloc (abfd, syms,
+ ((symcount + num_sections + 1)
+ * sizeof (asymbol *)));
+ else
+ syms = (asymbol **) bfd_alloc (abfd,
+ (num_sections + 1) * sizeof (asymbol *));
+ if (!syms)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ return false;
+ }
+
+ for (asect = abfd->sections; asect; asect = asect->next)
+ {
+ if (sect_syms[asect->index])
+ syms[symcount++] = sect_syms[asect->index];
+ }
+
+ syms[symcount] = (asymbol *) 0;
+ bfd_set_symtab (abfd, syms, symcount);
+ }
+
+ elf_sym_extra (abfd) = sym_extra
+ = (Elf_Sym_Extra *) bfd_alloc (abfd, symcount * sizeof (Elf_Sym_Extra));
+ if (!sym_extra)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ return false;
+ }
+
+ /* Identify and classify all of the symbols. */
+ for (idx = 0; idx < symcount; idx++)
+ {
+ if (!sym_is_global (abfd, syms[idx]))
+ num_locals++;
+ else
+ num_globals++;
+ }
+
+ /* Now provide mapping information. Add +1 for skipping over the
+ dummy symbol. */
+ for (idx = 0; idx < symcount; idx++)
+ {
+ syms[idx]->udata = (PTR) & sym_extra[idx];
+ if (!sym_is_global (abfd, syms[idx]))
+ sym_extra[idx].elf_sym_num = 1 + num_locals2++;
+ else
+ sym_extra[idx].elf_sym_num = 1 + num_locals + num_globals2++;
+ }
+
+ elf_num_locals (abfd) = num_locals;
+ elf_num_globals (abfd) = num_globals;
+ return true;
+}
+
+/* Compute the file positions we are going to put the sections at, and
+ otherwise prepare to begin writing out the ELF file. If LINK_INFO
+ is not NULL, this is being called by the ELF backend linker. */
+
+static boolean
+elf_compute_section_file_positions (abfd, link_info)
+ bfd *abfd;
+ struct bfd_link_info *link_info;
+{
+ struct elf_backend_data *bed = get_elf_backend_data (abfd);
+ Elf_Internal_Shdr *shstrtab_hdr;
+
+ if (abfd->output_has_begun)
+ return true;
+
+ /* Do any elf backend specific processing first. */
+ if (bed->elf_backend_begin_write_processing)
+ (*bed->elf_backend_begin_write_processing) (abfd, link_info);
+
+ if (! prep_headers (abfd))
+ return false;
+
+ bfd_map_over_sections (abfd, elf_fake_sections, 0);
+
+ if (!assign_section_numbers (abfd))
+ return false;
+
+ /* The backend linker builds symbol table information itself. */
+ if (link_info == NULL)
+ {
+ if (! swap_out_syms (abfd))
+ return false;
+ }
+
+ shstrtab_hdr = &elf_tdata (abfd)->shstrtab_hdr;
+ /* sh_name was set in prep_headers. */
+ shstrtab_hdr->sh_type = SHT_STRTAB;
+ shstrtab_hdr->sh_flags = 0;
+ shstrtab_hdr->sh_addr = 0;
+ shstrtab_hdr->sh_size = elf_shstrtab (abfd)->length;
+ shstrtab_hdr->sh_entsize = 0;
+ shstrtab_hdr->sh_link = 0;
+ shstrtab_hdr->sh_info = 0;
+ /* sh_offset is set in assign_file_positions_for_symtabs_and_strtabs. */
+ shstrtab_hdr->sh_addralign = 1;
+ shstrtab_hdr->contents = (PTR) elf_shstrtab (abfd)->tab;
+
+ if (!assign_file_positions_except_relocs (abfd,
+ link_info == NULL ? true : false))
+ return false;
+
+ abfd->output_has_begun = true;
+
+ return true;
+}
+
+
+/* Align to the maximum file alignment that could be required for any
+ ELF data structure. */
+
+static INLINE file_ptr
+align_file_position (off)
+ file_ptr off;
+{
+ return (off + FILE_ALIGN - 1) & ~(FILE_ALIGN - 1);
+}
+
+/* Assign a file position to a section, optionally aligning to the
+ required section alignment. */
+
+static INLINE file_ptr
+assign_file_position_for_section (i_shdrp, offset, align)
+ Elf_Internal_Shdr *i_shdrp;
+ file_ptr offset;
+ boolean align;
+{
+ if (align)
+ {
+ unsigned int al;
+
+ al = i_shdrp->sh_addralign;
+ if (al > 1)
+ offset = BFD_ALIGN (offset, al);
+ }
+ i_shdrp->sh_offset = offset;
+ if (i_shdrp->rawdata != NULL)
+ ((asection *) i_shdrp->rawdata)->filepos = offset;
+ if (i_shdrp->sh_type != SHT_NOBITS)
+ offset += i_shdrp->sh_size;
+ return offset;
+}
+
+/* Get the size of the program header. This is called by the linker
+ before any of the section VMA's are set, so it can't calculate the
+ correct value for a strange memory layout. */
+
+static bfd_size_type
+get_program_header_size (abfd)
+ bfd *abfd;
+{
+ size_t segs;
+ asection *s;
+
+ /* Assume we will need exactly two PT_LOAD segments: one for text
+ and one for data. */
+ segs = 2;
+
+ s = bfd_get_section_by_name (abfd, ".interp");
+ if (s != NULL && (s->flags & SEC_LOAD) != 0)
+ {
+ /* If we have a loadable interpreter section, we need a
+ PT_INTERP segment. In this case, assume we also need a
+ PT_PHDR segment, although that may not be true for all
+ targets. */
+ segs += 2;
+ }
+
+ if (bfd_get_section_by_name (abfd, ".dynamic") != NULL)
+ {
+ /* We need a PT_DYNAMIC segment. */
+ ++segs;
+ }
+
+ return segs * sizeof (Elf_External_Phdr);
+}
+
+/* Create the program header. OFF is the file offset where the
+ program header should be written. FIRST is the first loadable ELF
+ section. PHDR_SIZE is the size of the program header as returned
+ by get_program_header_size. */
+
+static file_ptr
+map_program_segments (abfd, off, first, phdr_size)
+ bfd *abfd;
+ file_ptr off;
+ Elf_Internal_Shdr *first;
+ bfd_size_type phdr_size;
+{
+ Elf_Internal_Phdr phdrs[10];
+ unsigned int phdr_count;
+ Elf_Internal_Phdr *phdr;
+ int phdr_size_adjust;
+ unsigned int i;
+ Elf_Internal_Shdr **hdrpp;
+ asection *sinterp, *sdyn;
+ unsigned int last_type;
+ Elf_Internal_Ehdr *i_ehdrp;
+
+ BFD_ASSERT ((abfd->flags & EXEC_P) != 0);
+ BFD_ASSERT (phdr_size / sizeof (Elf_Internal_Phdr)
+ <= sizeof phdrs / sizeof (phdrs[0]));
+
+ phdr_count = 0;
+ phdr = phdrs;
+
+ phdr_size_adjust = 0;
+
+ /* If we have a loadable .interp section, we must create a PT_INTERP
+ segment which must precede all PT_LOAD segments. We assume that
+ we must also create a PT_PHDR segment, although that may not be
+ true for all targets. */
+ sinterp = bfd_get_section_by_name (abfd, ".interp");
+ if (sinterp != NULL && (sinterp->flags & SEC_LOAD) != 0)
+ {
+ BFD_ASSERT (first != NULL);
+
+ phdr->p_type = PT_PHDR;
+
+ phdr->p_offset = off;
+
+ /* Account for any adjustment made because of the alignment of
+ the first loadable section. */
+ phdr_size_adjust = (first->sh_offset - phdr_size) - off;
+ BFD_ASSERT (phdr_size_adjust >= 0 && phdr_size_adjust < 128);
+
+ /* The program header precedes all loadable sections. This lets
+ us compute its loadable address. This depends on the linker
+ script. */
+ phdr->p_vaddr = first->sh_addr - (phdr_size + phdr_size_adjust);
+
+ phdr->p_paddr = 0;
+ phdr->p_filesz = phdr_size;
+ phdr->p_memsz = phdr_size;
+
+ /* FIXME: UnixWare and Solaris set PF_X, Irix 5 does not. */
+ phdr->p_flags = PF_R | PF_X;
+
+ phdr->p_align = FILE_ALIGN;
+ BFD_ASSERT ((phdr->p_vaddr - phdr->p_offset) % FILE_ALIGN == 0);
+
+ /* Include the ELF header in the first loadable segment. */
+ phdr_size_adjust += off;
+
+ ++phdr_count;
+ ++phdr;
+
+ phdr->p_type = PT_INTERP;
+ phdr->p_offset = sinterp->filepos;
+ phdr->p_vaddr = sinterp->vma;
+ phdr->p_paddr = 0;
+ phdr->p_filesz = sinterp->_raw_size;
+ phdr->p_memsz = sinterp->_raw_size;
+ phdr->p_flags = PF_R;
+ phdr->p_align = 1 << bfd_get_section_alignment (abfd, sinterp);
+
+ ++phdr_count;
+ ++phdr;
+ }
+
+ /* Look through the sections to see how they will be divided into
+ program segments. The sections must be arranged in order by
+ sh_addr for this to work correctly. */
+ phdr->p_type = PT_NULL;
+ last_type = SHT_PROGBITS;
+ for (i = 1, hdrpp = elf_elfsections (abfd) + 1;
+ i < elf_elfheader (abfd)->e_shnum;
+ i++, hdrpp++)
+ {
+ Elf_Internal_Shdr *hdr;
+
+ hdr = *hdrpp;
+
+ /* Ignore any section which will not be part of the process
+ image. */
+ if ((hdr->sh_flags & SHF_ALLOC) == 0)
+ continue;
+
+ /* If this section fits in the segment we are constructing, add
+ it in. */
+ if (phdr->p_type != PT_NULL
+ && (hdr->sh_offset - (phdr->p_offset + phdr->p_memsz)
+ == hdr->sh_addr - (phdr->p_vaddr + phdr->p_memsz))
+ && (last_type != SHT_NOBITS || hdr->sh_type == SHT_NOBITS))
+ {
+ bfd_size_type adjust;
+
+ adjust = hdr->sh_addr - (phdr->p_vaddr + phdr->p_memsz);
+ phdr->p_memsz += hdr->sh_size + adjust;
+ if (hdr->sh_type != SHT_NOBITS)
+ phdr->p_filesz += hdr->sh_size + adjust;
+ if ((hdr->sh_flags & SHF_WRITE) != 0)
+ phdr->p_flags |= PF_W;
+ if ((hdr->sh_flags & SHF_EXECINSTR) != 0)
+ phdr->p_flags |= PF_X;
+ last_type = hdr->sh_type;
+ continue;
+ }
+
+ /* If we have a segment, move to the next one. */
+ if (phdr->p_type != PT_NULL)
+ {
+ ++phdr;
+ ++phdr_count;
+ }
+
+ /* Start a new segment. */
+ phdr->p_type = PT_LOAD;
+ phdr->p_offset = hdr->sh_offset;
+ phdr->p_vaddr = hdr->sh_addr;
+ phdr->p_paddr = 0;
+ if (hdr->sh_type == SHT_NOBITS)
+ phdr->p_filesz = 0;
+ else
+ phdr->p_filesz = hdr->sh_size;
+ phdr->p_memsz = hdr->sh_size;
+ phdr->p_flags = PF_R;
+ if ((hdr->sh_flags & SHF_WRITE) != 0)
+ phdr->p_flags |= PF_W;
+ if ((hdr->sh_flags & SHF_EXECINSTR) != 0)
+ phdr->p_flags |= PF_X;
+ phdr->p_align = get_elf_backend_data (abfd)->maxpagesize;
+
+ if (hdr == first
+ && sinterp != NULL
+ && (sinterp->flags & SEC_LOAD) != 0)
+ {
+ phdr->p_offset -= phdr_size + phdr_size_adjust;
+ phdr->p_vaddr -= phdr_size + phdr_size_adjust;
+ phdr->p_filesz += phdr_size + phdr_size_adjust;
+ phdr->p_memsz += phdr_size + phdr_size_adjust;
+ }
+
+ last_type = hdr->sh_type;
+ }
+
+ if (phdr->p_type != PT_NULL)
+ {
+ ++phdr;
+ ++phdr_count;
+ }
+
+ /* If we have a .dynamic section, create a PT_DYNAMIC segment. */
+ sdyn = bfd_get_section_by_name (abfd, ".dynamic");
+ if (sdyn != NULL && (sdyn->flags & SEC_LOAD) != 0)
+ {
+ phdr->p_type = PT_DYNAMIC;
+ phdr->p_offset = sdyn->filepos;
+ phdr->p_vaddr = sdyn->vma;
+ phdr->p_paddr = 0;
+ phdr->p_filesz = sdyn->_raw_size;
+ phdr->p_memsz = sdyn->_raw_size;
+ phdr->p_flags = PF_R;
+ if ((sdyn->flags & SEC_READONLY) == 0)
+ phdr->p_flags |= PF_W;
+ if ((sdyn->flags & SEC_CODE) != 0)
+ phdr->p_flags |= PF_X;
+ phdr->p_align = 1 << bfd_get_section_alignment (abfd, sdyn);
+
+ ++phdr;
+ ++phdr_count;
+ }
+
+ /* Make sure the return value from get_program_header_size matches
+ what we computed here. */
+ if (phdr_count != phdr_size / sizeof (Elf_External_Phdr))
+ abort ();
+
+ /* Set up program header information. */
+ i_ehdrp = elf_elfheader (abfd);
+ i_ehdrp->e_phentsize = sizeof (Elf_External_Phdr);
+ i_ehdrp->e_phoff = off;
+ i_ehdrp->e_phnum = phdr_count;
+
+ /* Save the program headers away. I don't think anybody uses this
+ information right now. */
+ elf_tdata (abfd)->phdr = ((Elf_Internal_Phdr *)
+ bfd_alloc (abfd,
+ (phdr_count
+ * sizeof (Elf_Internal_Phdr))));
+ if (elf_tdata (abfd)->phdr == NULL && phdr_count != 0)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ return (file_ptr) -1;
+ }
+ memcpy (elf_tdata (abfd)->phdr, phdrs,
+ phdr_count * sizeof (Elf_Internal_Phdr));
+
+ /* Write out the program headers. */
+ if (bfd_seek (abfd, off, SEEK_SET) != 0)
+ return (file_ptr) -1;
+
+ for (i = 0, phdr = phdrs; i < phdr_count; i++, phdr++)
+ {
+ Elf_External_Phdr extphdr;
+
+ elf_swap_phdr_out (abfd, phdr, &extphdr);
+ if (bfd_write (&extphdr, sizeof (Elf_External_Phdr), 1, abfd)
+ != sizeof (Elf_External_Phdr))
+ return (file_ptr) -1;
+ }
+
+ return off + phdr_count * sizeof (Elf_External_Phdr);
+}
+
+/* Work out the file positions of all the sections. This is called by
+ elf_compute_section_file_positions. All the section sizes and VMAs
+ must be known before this is called.
+
+ We do not consider reloc sections at this point, unless they form
+ part of the loadable image. Reloc sections are assigned file
+ positions in assign_file_positions_for_relocs, which is called by
+ write_object_contents and final_link.
+
+ If DOSYMS is false, we do not assign file positions for the symbol
+ table or the string table. */
+
+static boolean
+assign_file_positions_except_relocs (abfd, dosyms)
+ bfd *abfd;
+ boolean dosyms;
+{
+ struct elf_obj_tdata * const tdata = elf_tdata (abfd);
+ Elf_Internal_Ehdr * const i_ehdrp = elf_elfheader (abfd);
+ Elf_Internal_Shdr ** const i_shdrpp = elf_elfsections (abfd);
+ file_ptr off;
+
+ /* Start after the ELF header. */
+ off = i_ehdrp->e_ehsize;
+
+ if ((abfd->flags & EXEC_P) == 0)
+ {
+ Elf_Internal_Shdr **hdrpp;
+ unsigned int i;
+
+ /* We are not creating an executable, which means that we are
+ not creating a program header, and that the actual order of
+ the sections in the file is unimportant. */
+ for (i = 1, hdrpp = i_shdrpp + 1; i < i_ehdrp->e_shnum; i++, hdrpp++)
+ {
+ Elf_Internal_Shdr *hdr;
+
+ hdr = *hdrpp;
+ if (hdr->sh_type == SHT_REL || hdr->sh_type == SHT_RELA)
+ {
+ hdr->sh_offset = -1;
+ continue;
+ }
+ if (! dosyms
+ && (i == tdata->symtab_section
+ || i == tdata->strtab_section))
+ {
+ hdr->sh_offset = -1;
+ continue;
+ }
+
+ off = assign_file_position_for_section (hdr, off, true);
+ }
+ }
+ else
+ {
+ file_ptr phdr_off;
+ bfd_size_type phdr_size;
+ bfd_vma maxpagesize;
+ Elf_Internal_Shdr **hdrpp;
+ unsigned int i;
+ Elf_Internal_Shdr *first;
+ file_ptr phdr_map;
+
+ /* We are creating an executable. We must create a program
+ header. We can't actually create the program header until we
+ have set the file positions for the sections, but we can
+ figure out how big it is going to be. */
+ off = align_file_position (off);
+ phdr_size = get_program_header_size (abfd);
+ if (phdr_size == (file_ptr) -1)
+ return false;
+ phdr_off = off;
+ off += phdr_size;
+
+ maxpagesize = get_elf_backend_data (abfd)->maxpagesize;
+ if (maxpagesize == 0)
+ maxpagesize = 1;
+
+ /* FIXME: We might want to sort the sections on the sh_addr
+ field here. For now, we just assume that the linker will
+ create the sections in an appropriate order. */
+
+ /* Assign file positions in two passes. In the first pass, we
+ assign a file position to every section which forms part of
+ the executable image. */
+ first = NULL;
+ for (i = 1, hdrpp = i_shdrpp + 1; i < i_ehdrp->e_shnum; i++, hdrpp++)
+ {
+ Elf_Internal_Shdr *hdr;
+
+ hdr = *hdrpp;
+ if ((hdr->sh_flags & SHF_ALLOC) == 0)
+ continue;
+
+ if (first == NULL)
+ first = hdr;
+
+ if ((abfd->flags & D_PAGED) != 0)
+ {
+ /* The section VMA must equal the file position modulo
+ the page size. This is required by the program
+ header. */
+ off += (hdr->sh_addr - off) % maxpagesize;
+ }
+
+ off = assign_file_position_for_section (hdr, off, false);
+ }
+
+ /* Assign file positions to all the sections which do not form
+ part of the loadable image, except for the relocs. */
+ for (i = 1, hdrpp = i_shdrpp + 1; i < i_ehdrp->e_shnum; i++, hdrpp++)
+ {
+ Elf_Internal_Shdr *hdr;
+
+ hdr = *hdrpp;
+ if ((hdr->sh_flags & SHF_ALLOC) != 0)
+ continue;
+ if (hdr->sh_type == SHT_REL || hdr->sh_type == SHT_RELA)
+ {
+ hdr->sh_offset = -1;
+ continue;
+ }
+ if (! dosyms
+ && (i == tdata->symtab_section
+ || i == tdata->strtab_section))
+ {
+ hdr->sh_offset = -1;
+ continue;
+ }
+
+ off = assign_file_position_for_section (hdr, off, true);
+ }
+
+ phdr_map = map_program_segments (abfd, phdr_off, first, phdr_size);
+ if (phdr_map == (file_ptr) -1)
+ return false;
+ BFD_ASSERT (phdr_map == phdr_off + phdr_size);
+ }
+
+ /* Place the section headers. */
+ off = align_file_position (off);
+ i_ehdrp->e_shoff = off;
+ off += i_ehdrp->e_shnum * i_ehdrp->e_shentsize;
+
+ elf_tdata (abfd)->next_file_pos = off;
+
+ return true;
+}
+
+static boolean
+prep_headers (abfd)
+ bfd *abfd;
+{
+ Elf_Internal_Ehdr *i_ehdrp; /* Elf file header, internal form */
+ Elf_Internal_Phdr *i_phdrp = 0; /* Program header table, internal form */
+ Elf_Internal_Shdr **i_shdrp; /* Section header table, internal form */
+ int count;
+ struct strtab *shstrtab;
+
+ i_ehdrp = elf_elfheader (abfd);
+ i_shdrp = elf_elfsections (abfd);
+
+ shstrtab = bfd_new_strtab (abfd);
+ if (!shstrtab)
+ return false;
+
+ elf_shstrtab (abfd) = shstrtab;
+
+ i_ehdrp->e_ident[EI_MAG0] = ELFMAG0;
+ i_ehdrp->e_ident[EI_MAG1] = ELFMAG1;
+ i_ehdrp->e_ident[EI_MAG2] = ELFMAG2;
+ i_ehdrp->e_ident[EI_MAG3] = ELFMAG3;
+
+ i_ehdrp->e_ident[EI_CLASS] = ELFCLASS;
+ i_ehdrp->e_ident[EI_DATA] =
+ abfd->xvec->byteorder_big_p ? ELFDATA2MSB : ELFDATA2LSB;
+ i_ehdrp->e_ident[EI_VERSION] = EV_CURRENT;
+
+ for (count = EI_PAD; count < EI_NIDENT; count++)
+ i_ehdrp->e_ident[count] = 0;
+
+ if ((abfd->flags & DYNAMIC) != 0)
+ i_ehdrp->e_type = ET_DYN;
+ else if ((abfd->flags & EXEC_P) != 0)
+ i_ehdrp->e_type = ET_EXEC;
+ else
+ i_ehdrp->e_type = ET_REL;
+
+ switch (bfd_get_arch (abfd))
+ {
+ case bfd_arch_unknown:
+ i_ehdrp->e_machine = EM_NONE;
+ break;
+ case bfd_arch_sparc:
+#if ARCH_SIZE == 64
+ i_ehdrp->e_machine = EM_SPARC64;
+#else
+ i_ehdrp->e_machine = EM_SPARC;
+#endif
+ break;
+ case bfd_arch_i386:
+ i_ehdrp->e_machine = EM_386;
+ break;
+ case bfd_arch_m68k:
+ i_ehdrp->e_machine = EM_68K;
+ break;
+ case bfd_arch_m88k:
+ i_ehdrp->e_machine = EM_88K;
+ break;
+ case bfd_arch_i860:
+ i_ehdrp->e_machine = EM_860;
+ break;
+ case bfd_arch_mips: /* MIPS Rxxxx */
+ i_ehdrp->e_machine = EM_MIPS; /* only MIPS R3000 */
+ break;
+ case bfd_arch_hppa:
+ i_ehdrp->e_machine = EM_PARISC;
+ break;
+ case bfd_arch_powerpc:
+ i_ehdrp->e_machine = EM_CYGNUS_POWERPC;
+ break;
+ /* also note that EM_M32, AT&T WE32100 is unknown to bfd */
+ default:
+ i_ehdrp->e_machine = EM_NONE;
+ }
+ i_ehdrp->e_version = EV_CURRENT;
+ i_ehdrp->e_ehsize = sizeof (Elf_External_Ehdr);
+
+ /* no program header, for now. */
+ i_ehdrp->e_phoff = 0;
+ i_ehdrp->e_phentsize = 0;
+ i_ehdrp->e_phnum = 0;
+
+ /* each bfd section is section header entry */
+ i_ehdrp->e_entry = bfd_get_start_address (abfd);
+ i_ehdrp->e_shentsize = sizeof (Elf_External_Shdr);
+
+ /* if we're building an executable, we'll need a program header table */
+ if (abfd->flags & EXEC_P)
+ {
+ /* it all happens later */
+#if 0
+ i_ehdrp->e_phentsize = sizeof (Elf_External_Phdr);
+
+ /* elf_build_phdrs() returns a (NULL-terminated) array of
+ Elf_Internal_Phdrs */
+ i_phdrp = elf_build_phdrs (abfd, i_ehdrp, i_shdrp, &i_ehdrp->e_phnum);
+ i_ehdrp->e_phoff = outbase;
+ outbase += i_ehdrp->e_phentsize * i_ehdrp->e_phnum;
+#endif
+ }
+ else
+ {
+ i_ehdrp->e_phentsize = 0;
+ i_phdrp = 0;
+ i_ehdrp->e_phoff = 0;
+ }
+
+ elf_tdata (abfd)->symtab_hdr.sh_name = bfd_add_to_strtab (abfd, shstrtab,
+ ".symtab");
+ elf_tdata (abfd)->strtab_hdr.sh_name = bfd_add_to_strtab (abfd, shstrtab,
+ ".strtab");
+ elf_tdata (abfd)->shstrtab_hdr.sh_name = bfd_add_to_strtab (abfd, shstrtab,
+ ".shstrtab");
+ if (elf_tdata (abfd)->symtab_hdr.sh_name == (unsigned int) -1
+ || elf_tdata (abfd)->symtab_hdr.sh_name == (unsigned int) -1
+ || elf_tdata (abfd)->shstrtab_hdr.sh_name == (unsigned int) -1)
+ return false;
+
+ return true;
+}
+
+static boolean
+swap_out_syms (abfd)
+ bfd *abfd;
+{
+ if (!elf_map_symbols (abfd))
+ return false;
+
+ /* Dump out the symtabs. */
+ {
+ int symcount = bfd_get_symcount (abfd);
+ asymbol **syms = bfd_get_outsymbols (abfd);
+ struct strtab *stt = bfd_new_strtab (abfd);
+ Elf_Internal_Shdr *symtab_hdr;
+ Elf_Internal_Shdr *symstrtab_hdr;
+ Elf_External_Sym *outbound_syms;
+ int idx;
+
+ if (!stt)
+ return false;
+ symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
+ symtab_hdr->sh_type = SHT_SYMTAB;
+ symtab_hdr->sh_entsize = sizeof (Elf_External_Sym);
+ symtab_hdr->sh_size = symtab_hdr->sh_entsize * (symcount + 1);
+ symtab_hdr->sh_info = elf_num_locals (abfd) + 1;
+ symtab_hdr->sh_addralign = FILE_ALIGN;
+
+ symstrtab_hdr = &elf_tdata (abfd)->strtab_hdr;
+ symstrtab_hdr->sh_type = SHT_STRTAB;
+
+ outbound_syms = (Elf_External_Sym *)
+ bfd_alloc (abfd, (1 + symcount) * sizeof (Elf_External_Sym));
+ if (!outbound_syms)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ return false;
+ }
+ /* now generate the data (for "contents") */
+ {
+ /* Fill in zeroth symbol and swap it out. */
+ Elf_Internal_Sym sym;
+ sym.st_name = 0;
+ sym.st_value = 0;
+ sym.st_size = 0;
+ sym.st_info = 0;
+ sym.st_other = 0;
+ sym.st_shndx = SHN_UNDEF;
+ elf_swap_symbol_out (abfd, &sym, outbound_syms);
+ }
+ for (idx = 0; idx < symcount; idx++)
+ {
+ Elf_Internal_Sym sym;
+ bfd_vma value = syms[idx]->value;
+ elf_symbol_type *type_ptr;
+
+ if (syms[idx]->flags & BSF_SECTION_SYM)
+ /* Section symbols have no names. */
+ sym.st_name = 0;
+ else
+ {
+ sym.st_name = bfd_add_to_strtab (abfd, stt, syms[idx]->name);
+ if (sym.st_name == (unsigned long) -1)
+ return false;
+ }
+
+ type_ptr = elf_symbol_from (abfd, syms[idx]);
+
+ if (bfd_is_com_section (syms[idx]->section))
+ {
+ /* ELF common symbols put the alignment into the `value' field,
+ and the size into the `size' field. This is backwards from
+ how BFD handles it, so reverse it here. */
+ sym.st_size = value;
+ sym.st_value = type_ptr ? type_ptr->internal_elf_sym.st_value : 16;
+ sym.st_shndx = elf_section_from_bfd_section (abfd,
+ syms[idx]->section);
+ }
+ else
+ {
+ asection *sec = syms[idx]->section;
+ int shndx;
+
+ if (sec->output_section)
+ {
+ value += sec->output_offset;
+ sec = sec->output_section;
+ }
+ value += sec->vma;
+ sym.st_value = value;
+ sym.st_size = type_ptr ? type_ptr->internal_elf_sym.st_size : 0;
+ sym.st_shndx = shndx = elf_section_from_bfd_section (abfd, sec);
+ if (shndx == -1)
+ {
+ asection *sec2;
+ /* Writing this would be a hell of a lot easier if we had
+ some decent documentation on bfd, and knew what to expect
+ of the library, and what to demand of applications. For
+ example, it appears that `objcopy' might not set the
+ section of a symbol to be a section that is actually in
+ the output file. */
+ sec2 = bfd_get_section_by_name (abfd, sec->name);
+ BFD_ASSERT (sec2 != 0);
+ sym.st_shndx = shndx = elf_section_from_bfd_section (abfd, sec2);
+ BFD_ASSERT (shndx != -1);
+ }
+ }
+
+ if (bfd_is_com_section (syms[idx]->section))
+ sym.st_info = ELF_ST_INFO (STB_GLOBAL, STT_OBJECT);
+ else if (bfd_is_und_section (syms[idx]->section))
+ sym.st_info = ELF_ST_INFO (STB_GLOBAL, STT_NOTYPE);
+ else if (syms[idx]->flags & BSF_SECTION_SYM)
+ sym.st_info = ELF_ST_INFO (STB_LOCAL, STT_SECTION);
+ else if (syms[idx]->flags & BSF_FILE)
+ sym.st_info = ELF_ST_INFO (STB_LOCAL, STT_FILE);
+ else
+ {
+ int bind = STB_LOCAL;
+ int type = STT_OBJECT;
+ unsigned int flags = syms[idx]->flags;
+
+ if (flags & BSF_LOCAL)
+ bind = STB_LOCAL;
+ else if (flags & BSF_WEAK)
+ bind = STB_WEAK;
+ else if (flags & BSF_GLOBAL)
+ bind = STB_GLOBAL;
+
+ if (flags & BSF_FUNCTION)
+ type = STT_FUNC;
+
+ sym.st_info = ELF_ST_INFO (bind, type);
+ }
+
+ sym.st_other = 0;
+ elf_swap_symbol_out (abfd, &sym,
+ (outbound_syms
+ + elf_sym_extra (abfd)[idx].elf_sym_num));
+ }
+
+ symtab_hdr->contents = (PTR) outbound_syms;
+ symstrtab_hdr->contents = (PTR) stt->tab;
+ symstrtab_hdr->sh_size = stt->length;
+ symstrtab_hdr->sh_type = SHT_STRTAB;
+
+ symstrtab_hdr->sh_flags = 0;
+ symstrtab_hdr->sh_addr = 0;
+ symstrtab_hdr->sh_entsize = 0;
+ symstrtab_hdr->sh_link = 0;
+ symstrtab_hdr->sh_info = 0;
+ symstrtab_hdr->sh_addralign = 1;
+ symstrtab_hdr->size = 0;
+ }
+
+ return true;
+}
+
+static boolean
+write_shdrs_and_ehdr (abfd)
+ bfd *abfd;
+{
+ Elf_External_Ehdr x_ehdr; /* Elf file header, external form */
+ Elf_Internal_Ehdr *i_ehdrp; /* Elf file header, internal form */
+ Elf_External_Shdr *x_shdrp; /* Section header table, external form */
+ Elf_Internal_Shdr **i_shdrp; /* Section header table, internal form */
+ unsigned int count;
+ struct strtab *shstrtab;
+
+ i_ehdrp = elf_elfheader (abfd);
+ i_shdrp = elf_elfsections (abfd);
+ shstrtab = elf_shstrtab (abfd);
+
+ /* swap the header before spitting it out... */
+
+#if DEBUG & 1
+ elf_debug_file (i_ehdrp);
+#endif
+ elf_swap_ehdr_out (abfd, i_ehdrp, &x_ehdr);
+ if (bfd_seek (abfd, (file_ptr) 0, SEEK_SET) != 0
+ || (bfd_write ((PTR) & x_ehdr, sizeof (x_ehdr), 1, abfd)
+ != sizeof (x_ehdr)))
+ return false;
+
+ /* at this point we've concocted all the ELF sections... */
+ x_shdrp = (Elf_External_Shdr *)
+ bfd_alloc (abfd, sizeof (*x_shdrp) * (i_ehdrp->e_shnum));
+ if (!x_shdrp)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ return false;
+ }
+
+ for (count = 0; count < i_ehdrp->e_shnum; count++)
+ {
+#if DEBUG & 2
+ elf_debug_section (shstrtab->tab + i_shdrp[count]->sh_name, count,
+ i_shdrp[count]);
+#endif
+ elf_swap_shdr_out (abfd, i_shdrp[count], x_shdrp + count);
+ }
+ if (bfd_seek (abfd, (file_ptr) i_ehdrp->e_shoff, SEEK_SET) != 0
+ || (bfd_write ((PTR) x_shdrp, sizeof (*x_shdrp), i_ehdrp->e_shnum, abfd)
+ != sizeof (*x_shdrp) * i_ehdrp->e_shnum))
+ return false;
+
+ /* need to dump the string table too... */
+
+ return true;
+}
+
+/* Assign file positions for all the reloc sections which are not part
+ of the loadable file image. */
+
+static void
+assign_file_positions_for_relocs (abfd)
+ bfd *abfd;
+{
+ file_ptr off;
+ unsigned int i;
+ Elf_Internal_Shdr **shdrpp;
+
+ off = elf_tdata (abfd)->next_file_pos;
+
+ for (i = 1, shdrpp = elf_elfsections (abfd) + 1;
+ i < elf_elfheader (abfd)->e_shnum;
+ i++, shdrpp++)
+ {
+ Elf_Internal_Shdr *shdrp;
+
+ shdrp = *shdrpp;
+ if ((shdrp->sh_type == SHT_REL || shdrp->sh_type == SHT_RELA)
+ && shdrp->sh_offset == -1)
+ off = assign_file_position_for_section (shdrp, off, true);
+ }
+
+ elf_tdata (abfd)->next_file_pos = off;
+}
+
+boolean
+NAME(bfd_elf,write_object_contents) (abfd)
+ bfd *abfd;
+{
+ struct elf_backend_data *bed = get_elf_backend_data (abfd);
+ Elf_Internal_Ehdr *i_ehdrp;
+ Elf_Internal_Shdr **i_shdrp;
+ unsigned int count;
+
+ if (! abfd->output_has_begun
+ && ! elf_compute_section_file_positions (abfd,
+ (struct bfd_link_info *) NULL))
+ return false;
+
+ i_shdrp = elf_elfsections (abfd);
+ i_ehdrp = elf_elfheader (abfd);
+
+ bfd_map_over_sections (abfd, write_relocs, (PTR) 0);
+ assign_file_positions_for_relocs (abfd);
+
+ /* After writing the headers, we need to write the sections too... */
+ for (count = 1; count < i_ehdrp->e_shnum; count++)
+ {
+ if (bed->elf_backend_section_processing)
+ (*bed->elf_backend_section_processing) (abfd, i_shdrp[count]);
+ if (i_shdrp[count]->contents)
+ {
+ if (bfd_seek (abfd, i_shdrp[count]->sh_offset, SEEK_SET) != 0
+ || (bfd_write (i_shdrp[count]->contents, i_shdrp[count]->sh_size,
+ 1, abfd)
+ != i_shdrp[count]->sh_size))
+ return false;
+ }
+ }
+
+ if (bed->elf_backend_final_write_processing)
+ (*bed->elf_backend_final_write_processing) (abfd, NULL);
+
+ return write_shdrs_and_ehdr (abfd);
+}
+
+/* Given an index of a section, retrieve a pointer to it. Note
+ that for our purposes, sections are indexed by {1, 2, ...} with
+ 0 being an illegal index. */
+
+/* In the original, each ELF section went into exactly one BFD
+ section. This doesn't really make sense, so we need a real mapping.
+ The mapping has to hide in the Elf_Internal_Shdr since asection
+ doesn't have anything like a tdata field... */
+
+static asection *
+section_from_elf_index (abfd, index)
+ bfd *abfd;
+ unsigned int index;
+{
+ /* @@ Is bfd_com_section_ptr really correct in all the places it could
+ be returned from this routine? */
+
+ if (index == SHN_ABS)
+ return bfd_com_section_ptr; /* not abs? */
+ if (index == SHN_COMMON)
+ return bfd_com_section_ptr;
+
+ if (index >= elf_elfheader (abfd)->e_shnum)
+ return NULL;
+
+ {
+ Elf_Internal_Shdr *hdr = elf_elfsections (abfd)[index];
+
+ switch (hdr->sh_type)
+ {
+ /* ELF sections that map to BFD sections */
+ case SHT_PROGBITS:
+ case SHT_NOBITS:
+ case SHT_HASH:
+ case SHT_DYNAMIC:
+ if (hdr->rawdata == NULL)
+ {
+ if (! bfd_section_from_shdr (abfd, index))
+ return NULL;
+ }
+ return (struct sec *) hdr->rawdata;
+
+ default:
+ return bfd_abs_section_ptr;
+ }
+ }
+}
+
+/* given a section, search the header to find them... */
+static int
+elf_section_from_bfd_section (abfd, asect)
+ bfd *abfd;
+ struct sec *asect;
+{
+ Elf_Internal_Shdr **i_shdrp = elf_elfsections (abfd);
+ int index;
+ Elf_Internal_Shdr *hdr;
+ int maxindex = elf_elfheader (abfd)->e_shnum;
+
+ if (asect->owner == NULL)
+ {
+ if (bfd_is_abs_section (asect))
+ return SHN_ABS;
+ if (bfd_is_com_section (asect))
+ return SHN_COMMON;
+ if (bfd_is_und_section (asect))
+ return SHN_UNDEF;
+ return -1;
+ }
+
+ BFD_ASSERT (asect->owner == abfd);
+
+ for (index = 0; index < maxindex; index++)
+ {
+ hdr = i_shdrp[index];
+ switch (hdr->sh_type)
+ {
+ /* ELF sections that map to BFD sections */
+ case SHT_PROGBITS:
+ case SHT_NOBITS:
+ case SHT_NOTE:
+ case SHT_HASH:
+ case SHT_DYNAMIC:
+ case SHT_DYNSYM:
+ if (hdr->rawdata)
+ {
+ if (((struct sec *) (hdr->rawdata)) == asect)
+ return index;
+ }
+ break;
+
+ case SHT_REL:
+ case SHT_RELA:
+ /* We sometimes map a reloc section to a BFD section. */
+ if (hdr->sh_link != elf_onesymtab (abfd)
+ && (asection *) hdr->rawdata == asect)
+ return index;
+ break;
+
+ case SHT_STRTAB:
+ /* We map most string tables to BFD sections. */
+ if (index != elf_elfheader (abfd)->e_shstrndx
+ && index != elf_onesymtab (abfd)
+ && (asection *) hdr->rawdata == asect)
+ return index;
+
+ /* FALL THROUGH */
+ default:
+ {
+ struct elf_backend_data *bed = get_elf_backend_data (abfd);
+
+ if (bed->elf_backend_section_from_bfd_section)
+ {
+ int retval;
+
+ retval = index;
+ if ((*bed->elf_backend_section_from_bfd_section)
+ (abfd, hdr, asect, &retval))
+ return retval;
+ }
+ }
+ break;
+ }
+ }
+ return -1;
+}
+
+/* given a symbol, return the bfd index for that symbol. */
+static int
+elf_symbol_from_bfd_symbol (abfd, asym_ptr_ptr)
+ bfd *abfd;
+ struct symbol_cache_entry **asym_ptr_ptr;
+{
+ struct symbol_cache_entry *asym_ptr = *asym_ptr_ptr;
+ int idx;
+ flagword flags = asym_ptr->flags;
+
+ /* When gas creates relocations against local labels, it creates its
+ own symbol for the section, but does put the symbol into the
+ symbol chain, so udata is 0. When the linker is generating
+ relocatable output, this section symbol may be for one of the
+ input sections rather than the output section. */
+ if (asym_ptr->udata == (PTR) 0
+ && (flags & BSF_SECTION_SYM)
+ && asym_ptr->section)
+ {
+ int indx;
+
+ if (asym_ptr->section->output_section != NULL)
+ indx = asym_ptr->section->output_section->index;
+ else
+ indx = asym_ptr->section->index;
+ if (elf_section_syms (abfd)[indx])
+ asym_ptr->udata = elf_section_syms (abfd)[indx]->udata;
+ }
+
+ if (asym_ptr->udata)
+ idx = ((Elf_Sym_Extra *) asym_ptr->udata)->elf_sym_num;
+ else
+ {
+ abort ();
+ }
+
+#if DEBUG & 4
+ {
+
+ fprintf (stderr,
+ "elf_symbol_from_bfd_symbol 0x%.8lx, name = %s, sym num = %d, flags = 0x%.8lx %s\n",
+ (long) asym_ptr, asym_ptr->name, idx, flags, elf_symbol_flags (flags));
+ fflush (stderr);
+ }
+#endif
+
+ return idx;
+}
+
+static long
+elf_slurp_symbol_table (abfd, symptrs, dynamic)
+ bfd *abfd;
+ asymbol **symptrs; /* Buffer for generated bfd symbols */
+ boolean dynamic;
+{
+ Elf_Internal_Shdr *hdr;
+ long symcount; /* Number of external ELF symbols */
+ elf_symbol_type *sym; /* Pointer to current bfd symbol */
+ elf_symbol_type *symbase; /* Buffer for generated bfd symbols */
+ Elf_Internal_Sym i_sym;
+ Elf_External_Sym *x_symp = NULL;
+
+ /* Read each raw ELF symbol, converting from external ELF form to
+ internal ELF form, and then using the information to create a
+ canonical bfd symbol table entry.
+
+ Note that we allocate the initial bfd canonical symbol buffer
+ based on a one-to-one mapping of the ELF symbols to canonical
+ symbols. We actually use all the ELF symbols, so there will be no
+ space left over at the end. When we have all the symbols, we
+ build the caller's pointer vector. */
+
+ if (dynamic)
+ hdr = &elf_tdata (abfd)->dynsymtab_hdr;
+ else
+ hdr = &elf_tdata (abfd)->symtab_hdr;
+ if (bfd_seek (abfd, hdr->sh_offset, SEEK_SET) == -1)
+ return -1;
+
+ symcount = hdr->sh_size / sizeof (Elf_External_Sym);
+
+ if (symcount == 0)
+ sym = symbase = NULL;
+ else
+ {
+ long i;
+
+ if (bfd_seek (abfd, hdr->sh_offset, SEEK_SET) == -1)
+ return -1;
+
+ symbase = ((elf_symbol_type *)
+ bfd_zalloc (abfd, symcount * sizeof (elf_symbol_type)));
+ if (symbase == (elf_symbol_type *) NULL)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ return -1;
+ }
+ sym = symbase;
+
+ /* Temporarily allocate room for the raw ELF symbols. */
+ x_symp = ((Elf_External_Sym *)
+ malloc (symcount * sizeof (Elf_External_Sym)));
+ if (x_symp == NULL && symcount != 0)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ goto error_return;
+ }
+
+ if (bfd_read ((PTR) x_symp, sizeof (Elf_External_Sym), symcount, abfd)
+ != symcount * sizeof (Elf_External_Sym))
+ goto error_return;
+ /* Skip first symbol, which is a null dummy. */
+ for (i = 1; i < symcount; i++)
+ {
+ elf_swap_symbol_in (abfd, x_symp + i, &i_sym);
+ memcpy (&sym->internal_elf_sym, &i_sym, sizeof (Elf_Internal_Sym));
+#ifdef ELF_KEEP_EXTSYM
+ memcpy (&sym->native_elf_sym, x_symp + i, sizeof (Elf_External_Sym));
+#endif
+ sym->symbol.the_bfd = abfd;
+
+ sym->symbol.name = elf_string_from_elf_section (abfd, hdr->sh_link,
+ i_sym.st_name);
+
+ sym->symbol.value = i_sym.st_value;
+
+ if (i_sym.st_shndx > 0 && i_sym.st_shndx < SHN_LORESERVE)
+ {
+ sym->symbol.section = section_from_elf_index (abfd,
+ i_sym.st_shndx);
+ if (sym->symbol.section == NULL)
+ {
+ /* This symbol is in a section for which we did not
+ create a BFD section. Just use bfd_abs_section,
+ although it is wrong. FIXME. */
+ sym->symbol.section = bfd_abs_section_ptr;
+ }
+ }
+ else if (i_sym.st_shndx == SHN_ABS)
+ {
+ sym->symbol.section = bfd_abs_section_ptr;
+ }
+ else if (i_sym.st_shndx == SHN_COMMON)
+ {
+ sym->symbol.section = bfd_com_section_ptr;
+ /* Elf puts the alignment into the `value' field, and
+ the size into the `size' field. BFD wants to see the
+ size in the value field, and doesn't care (at the
+ moment) about the alignment. */
+ sym->symbol.value = i_sym.st_size;
+ }
+ else if (i_sym.st_shndx == SHN_UNDEF)
+ {
+ sym->symbol.section = bfd_und_section_ptr;
+ }
+ else
+ sym->symbol.section = bfd_abs_section_ptr;
+
+ sym->symbol.value -= sym->symbol.section->vma;
+
+ switch (ELF_ST_BIND (i_sym.st_info))
+ {
+ case STB_LOCAL:
+ sym->symbol.flags |= BSF_LOCAL;
+ break;
+ case STB_GLOBAL:
+ sym->symbol.flags |= BSF_GLOBAL;
+ break;
+ case STB_WEAK:
+ sym->symbol.flags |= BSF_WEAK;
+ break;
+ }
+
+ switch (ELF_ST_TYPE (i_sym.st_info))
+ {
+ case STT_SECTION:
+ sym->symbol.flags |= BSF_SECTION_SYM | BSF_DEBUGGING;
+ break;
+ case STT_FILE:
+ sym->symbol.flags |= BSF_FILE | BSF_DEBUGGING;
+ break;
+ case STT_FUNC:
+ sym->symbol.flags |= BSF_FUNCTION;
+ break;
+ }
+
+ if (dynamic)
+ sym->symbol.flags |= BSF_DYNAMIC;
+
+ /* Do some backend-specific processing on this symbol. */
+ {
+ struct elf_backend_data *ebd = get_elf_backend_data (abfd);
+ if (ebd->elf_backend_symbol_processing)
+ (*ebd->elf_backend_symbol_processing) (abfd, &sym->symbol);
+ }
+
+ sym++;
+ }
+ }
+
+ /* Do some backend-specific processing on this symbol table. */
+ {
+ struct elf_backend_data *ebd = get_elf_backend_data (abfd);
+ if (ebd->elf_backend_symbol_table_processing)
+ (*ebd->elf_backend_symbol_table_processing) (abfd, symbase, symcount);
+ }
+
+ /* We rely on the zalloc to clear out the final symbol entry. */
+
+ symcount = sym - symbase;
+
+ /* Fill in the user's symbol pointer vector if needed. */
+ if (symptrs)
+ {
+ long l = symcount;
+
+ sym = symbase;
+ while (l-- > 0)
+ {
+ *symptrs++ = &sym->symbol;
+ sym++;
+ }
+ *symptrs = 0; /* Final null pointer */
+ }
+
+ if (x_symp != NULL)
+ free (x_symp);
+ return symcount;
+error_return:
+ if (x_symp != NULL)
+ free (x_symp);
+ return -1;
+}
+
+/* Return the number of bytes required to hold the symtab vector.
+
+ Note that we base it on the count plus 1, since we will null terminate
+ the vector allocated based on this size. However, the ELF symbol table
+ always has a dummy entry as symbol #0, so it ends up even. */
+
+long
+elf_get_symtab_upper_bound (abfd)
+ bfd *abfd;
+{
+ long symcount;
+ long symtab_size;
+ Elf_Internal_Shdr *hdr = &elf_tdata (abfd)->symtab_hdr;
+
+ symcount = hdr->sh_size / sizeof (Elf_External_Sym);
+ symtab_size = (symcount - 1 + 1) * (sizeof (asymbol *));
+
+ return symtab_size;
+}
+
+long
+elf_get_dynamic_symtab_upper_bound (abfd)
+ bfd *abfd;
+{
+ long symcount;
+ long symtab_size;
+ Elf_Internal_Shdr *hdr = &elf_tdata (abfd)->dynsymtab_hdr;
+
+ if (elf_dynsymtab (abfd) == 0)
+ {
+ bfd_set_error (bfd_error_invalid_operation);
+ return -1;
+ }
+
+ symcount = hdr->sh_size / sizeof (Elf_External_Sym);
+ symtab_size = (symcount - 1 + 1) * (sizeof (asymbol *));
+
+ return symtab_size;
+}
+
+long
+elf_get_reloc_upper_bound (abfd, asect)
+ bfd *abfd;
+ sec_ptr asect;
+{
+ return (asect->reloc_count + 1) * sizeof (arelent *);
+}
+
+/* Read in and swap the external relocs. */
+
+static boolean
+elf_slurp_reloc_table (abfd, asect, symbols)
+ bfd *abfd;
+ asection *asect;
+ asymbol **symbols;
+{
+ struct elf_backend_data * const ebd = get_elf_backend_data (abfd);
+ struct bfd_elf_section_data * const d = elf_section_data (asect);
+ PTR allocated = NULL;
+ bfd_byte *native_relocs;
+ arelent *relents;
+ arelent *relent;
+ unsigned int i;
+ int entsize;
+
+ if (asect->relocation != NULL)
+ return true;
+
+ BFD_ASSERT (asect->rel_filepos == d->rel_hdr.sh_offset
+ && (asect->reloc_count
+ == d->rel_hdr.sh_size / d->rel_hdr.sh_entsize));
+
+ native_relocs = (bfd_byte *) elf_section_data (asect)->relocs;
+ if (native_relocs == NULL)
+ {
+ allocated = (PTR) malloc (d->rel_hdr.sh_size);
+ if (allocated == NULL)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ goto error_return;
+ }
+
+ if (bfd_seek (abfd, asect->rel_filepos, SEEK_SET) != 0
+ || (bfd_read (allocated, 1, d->rel_hdr.sh_size, abfd)
+ != d->rel_hdr.sh_size))
+ goto error_return;
+
+ native_relocs = (bfd_byte *) allocated;
+ }
+
+ relents = ((arelent *)
+ bfd_alloc (abfd, asect->reloc_count * sizeof (arelent)));
+ if (relents == NULL)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ goto error_return;
+ }
+
+ entsize = d->rel_hdr.sh_entsize;
+ BFD_ASSERT (entsize == sizeof (Elf_External_Rel)
+ || entsize == sizeof (Elf_External_Rela));
+
+ for (i = 0, relent = relents;
+ i < asect->reloc_count;
+ i++, relent++, native_relocs += entsize)
+ {
+ Elf_Internal_Rela rela;
+ Elf_Internal_Rel rel;
+
+ if (entsize == sizeof (Elf_External_Rela))
+ elf_swap_reloca_in (abfd, (Elf_External_Rela *) native_relocs, &rela);
+ else
+ {
+ elf_swap_reloc_in (abfd, (Elf_External_Rel *) native_relocs, &rel);
+ rela.r_offset = rel.r_offset;
+ rela.r_info = rel.r_info;
+ rela.r_addend = 0;
+ }
+
+ /* The address of an ELF reloc is section relative for an object
+ file, and absolute for an executable file or shared library.
+ The address of a BFD reloc is always section relative. */
+ if ((abfd->flags & (EXEC_P | DYNAMIC)) == 0)
+ relent->address = rela.r_offset;
+ else
+ relent->address = rela.r_offset - asect->vma;
+
+ if (ELF_R_SYM (rela.r_info) == 0)
+ relent->sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr;
+ else
+ {
+ asymbol **ps, *s;
+
+ ps = symbols + ELF_R_SYM (rela.r_info) - 1;
+ s = *ps;
+
+ /* Canonicalize ELF section symbols. FIXME: Why? */
+ if ((s->flags & BSF_SECTION_SYM) == 0)
+ relent->sym_ptr_ptr = ps;
+ else
+ relent->sym_ptr_ptr = s->section->symbol_ptr_ptr;
+ }
+
+ relent->addend = rela.r_addend;
+
+ if (entsize == sizeof (Elf_External_Rela))
+ (*ebd->elf_info_to_howto) (abfd, relent, &rela);
+ else
+ (*ebd->elf_info_to_howto_rel) (abfd, relent, &rel);
+ }
+
+ asect->relocation = relents;
+
+ if (allocated != NULL)
+ free (allocated);
+
+ return true;
+
+ error_return:
+ if (allocated != NULL)
+ free (allocated);
+ return false;
+}
+
+#ifdef DEBUG
+static void
+elf_debug_section (str, num, hdr)
+ char *str;
+ int num;
+ Elf_Internal_Shdr *hdr;
+{
+ fprintf (stderr, "\nSection#%d '%s' 0x%.8lx\n", num, str, (long) hdr);
+ fprintf (stderr,
+ "sh_name = %ld\tsh_type = %ld\tsh_flags = %ld\n",
+ (long) hdr->sh_name,
+ (long) hdr->sh_type,
+ (long) hdr->sh_flags);
+ fprintf (stderr,
+ "sh_addr = %ld\tsh_offset = %ld\tsh_size = %ld\n",
+ (long) hdr->sh_addr,
+ (long) hdr->sh_offset,
+ (long) hdr->sh_size);
+ fprintf (stderr,
+ "sh_link = %ld\tsh_info = %ld\tsh_addralign = %ld\n",
+ (long) hdr->sh_link,
+ (long) hdr->sh_info,
+ (long) hdr->sh_addralign);
+ fprintf (stderr, "sh_entsize = %ld\n",
+ (long) hdr->sh_entsize);
+ fprintf (stderr, "rawdata = 0x%.8lx\n", (long) hdr->rawdata);
+ fprintf (stderr, "contents = 0x%.8lx\n", (long) hdr->contents);
+ fprintf (stderr, "size = %ld\n", (long) hdr->size);
+ fflush (stderr);
+}
+
+static void
+elf_debug_file (ehdrp)
+ Elf_Internal_Ehdr *ehdrp;
+{
+ fprintf (stderr, "e_entry = 0x%.8lx\n", (long) ehdrp->e_entry);
+ fprintf (stderr, "e_phoff = %ld\n", (long) ehdrp->e_phoff);
+ fprintf (stderr, "e_phnum = %ld\n", (long) ehdrp->e_phnum);
+ fprintf (stderr, "e_phentsize = %ld\n", (long) ehdrp->e_phentsize);
+ fprintf (stderr, "e_shoff = %ld\n", (long) ehdrp->e_shoff);
+ fprintf (stderr, "e_shnum = %ld\n", (long) ehdrp->e_shnum);
+ fprintf (stderr, "e_shentsize = %ld\n", (long) ehdrp->e_shentsize);
+}
+#endif
+
+/* Canonicalize the relocs. */
+
+long
+elf_canonicalize_reloc (abfd, section, relptr, symbols)
+ bfd *abfd;
+ sec_ptr section;
+ arelent **relptr;
+ asymbol **symbols;
+{
+ arelent *tblptr;
+ unsigned int i;
+
+ if (! elf_slurp_reloc_table (abfd, section, symbols))
+ return -1;
+
+ tblptr = section->relocation;
+ for (i = 0; i < section->reloc_count; i++)
+ *relptr++ = tblptr++;
+
+ *relptr = NULL;
+
+ return section->reloc_count;
+}
+
+long
+elf_get_symtab (abfd, alocation)
+ bfd *abfd;
+ asymbol **alocation;
+{
+ long symcount = elf_slurp_symbol_table (abfd, alocation, false);
+
+ if (symcount >= 0)
+ bfd_get_symcount (abfd) = symcount;
+ return symcount;
+}
+
+long
+elf_canonicalize_dynamic_symtab (abfd, alocation)
+ bfd *abfd;
+ asymbol **alocation;
+{
+ return elf_slurp_symbol_table (abfd, alocation, true);
+}
+
+asymbol *
+elf_make_empty_symbol (abfd)
+ bfd *abfd;
+{
+ elf_symbol_type *newsym;
+
+ newsym = (elf_symbol_type *) bfd_zalloc (abfd, sizeof (elf_symbol_type));
+ if (!newsym)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ return NULL;
+ }
+ else
+ {
+ newsym->symbol.the_bfd = abfd;
+ return &newsym->symbol;
+ }
+}
+
+void
+elf_get_symbol_info (ignore_abfd, symbol, ret)
+ bfd *ignore_abfd;
+ asymbol *symbol;
+ symbol_info *ret;
+{
+ bfd_symbol_info (symbol, ret);
+}
+
+void
+elf_print_symbol (ignore_abfd, filep, symbol, how)
+ bfd *ignore_abfd;
+ PTR filep;
+ asymbol *symbol;
+ bfd_print_symbol_type how;
+{
+ FILE *file = (FILE *) filep;
+ switch (how)
+ {
+ case bfd_print_symbol_name:
+ fprintf (file, "%s", symbol->name);
+ break;
+ case bfd_print_symbol_more:
+ fprintf (file, "elf ");
+ fprintf_vma (file, symbol->value);
+ fprintf (file, " %lx", (long) symbol->flags);
+ break;
+ case bfd_print_symbol_all:
+ {
+ CONST char *section_name;
+ section_name = symbol->section ? symbol->section->name : "(*none*)";
+ bfd_print_symbol_vandf ((PTR) file, symbol);
+ fprintf (file, " %s\t%s",
+ section_name,
+ symbol->name);
+ }
+ break;
+ }
+
+}
+
+alent *
+elf_get_lineno (ignore_abfd, symbol)
+ bfd *ignore_abfd;
+ asymbol *symbol;
+{
+ fprintf (stderr, "elf_get_lineno unimplemented\n");
+ fflush (stderr);
+ BFD_FAIL ();
+ return NULL;
+}
+
+boolean
+elf_set_arch_mach (abfd, arch, machine)
+ bfd *abfd;
+ enum bfd_architecture arch;
+ unsigned long machine;
+{
+ /* If this isn't the right architecture for this backend, and this
+ isn't the generic backend, fail. */
+ if (arch != get_elf_backend_data (abfd)->arch
+ && arch != bfd_arch_unknown
+ && get_elf_backend_data (abfd)->arch != bfd_arch_unknown)
+ return false;
+
+ return bfd_default_set_arch_mach (abfd, arch, machine);
+}
+
+boolean
+elf_find_nearest_line (abfd,
+ section,
+ symbols,
+ offset,
+ filename_ptr,
+ functionname_ptr,
+ line_ptr)
+ bfd *abfd;
+ asection *section;
+ asymbol **symbols;
+ bfd_vma offset;
+ CONST char **filename_ptr;
+ CONST char **functionname_ptr;
+ unsigned int *line_ptr;
+{
+ return false;
+}
+
+int
+elf_sizeof_headers (abfd, reloc)
+ bfd *abfd;
+ boolean reloc;
+{
+ int ret;
+
+ ret = sizeof (Elf_External_Ehdr);
+ if (! reloc)
+ ret += get_program_header_size (abfd);
+ return ret;
+}
+
+boolean
+elf_set_section_contents (abfd, section, location, offset, count)
+ bfd *abfd;
+ sec_ptr section;
+ PTR location;
+ file_ptr offset;
+ bfd_size_type count;
+{
+ Elf_Internal_Shdr *hdr;
+
+ if (! abfd->output_has_begun
+ && ! elf_compute_section_file_positions (abfd,
+ (struct bfd_link_info *) NULL))
+ return false;
+
+ hdr = &elf_section_data (section)->this_hdr;
+
+ if (bfd_seek (abfd, hdr->sh_offset + offset, SEEK_SET) == -1)
+ return false;
+ if (bfd_write (location, 1, count, abfd) != count)
+ return false;
+
+ return true;
+}
+
+void
+elf_no_info_to_howto (abfd, cache_ptr, dst)
+ bfd *abfd;
+ arelent *cache_ptr;
+ Elf_Internal_Rela *dst;
+{
+ fprintf (stderr, "elf RELA relocation support for target machine unimplemented\n");
+ fflush (stderr);
+ BFD_FAIL ();
+}
+
+void
+elf_no_info_to_howto_rel (abfd, cache_ptr, dst)
+ bfd *abfd;
+ arelent *cache_ptr;
+ Elf_Internal_Rel *dst;
+{
+ fprintf (stderr, "elf REL relocation support for target machine unimplemented\n");
+ fflush (stderr);
+ BFD_FAIL ();
+}
+
+
+/* Core file support */
+
+#ifdef HAVE_PROCFS /* Some core file support requires host /proc files */
+#include <sys/procfs.h>
+#else
+#define bfd_prstatus(abfd, descdata, descsz, filepos) true
+#define bfd_fpregset(abfd, descdata, descsz, filepos) true
+#define bfd_prpsinfo(abfd, descdata, descsz, filepos) true
+#endif
+
+#ifdef HAVE_PROCFS
+
+static boolean
+bfd_prstatus (abfd, descdata, descsz, filepos)
+ bfd *abfd;
+ char *descdata;
+ int descsz;
+ long filepos;
+{
+ asection *newsect;
+ prstatus_t *status = (prstatus_t *) 0;
+
+ if (descsz == sizeof (prstatus_t))
+ {
+ newsect = bfd_make_section (abfd, ".reg");
+ if (newsect == NULL)
+ return false;
+ newsect->_raw_size = sizeof (status->pr_reg);
+ newsect->filepos = filepos + (long) &status->pr_reg;
+ newsect->flags = SEC_HAS_CONTENTS;
+ newsect->alignment_power = 2;
+ if ((core_prstatus (abfd) = bfd_alloc (abfd, descsz)) != NULL)
+ {
+ memcpy (core_prstatus (abfd), descdata, descsz);
+ }
+ }
+ return true;
+}
+
+/* Stash a copy of the prpsinfo structure away for future use. */
+
+static boolean
+bfd_prpsinfo (abfd, descdata, descsz, filepos)
+ bfd *abfd;
+ char *descdata;
+ int descsz;
+ long filepos;
+{
+ if (descsz == sizeof (prpsinfo_t))
+ {
+ if ((core_prpsinfo (abfd) = bfd_alloc (abfd, descsz)) == NULL)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ return false;
+ }
+ memcpy (core_prpsinfo (abfd), descdata, descsz);
+ }
+ return true;
+}
+
+static boolean
+bfd_fpregset (abfd, descdata, descsz, filepos)
+ bfd *abfd;
+ char *descdata;
+ int descsz;
+ long filepos;
+{
+ asection *newsect;
+
+ newsect = bfd_make_section (abfd, ".reg2");
+ if (newsect == NULL)
+ return false;
+ newsect->_raw_size = descsz;
+ newsect->filepos = filepos;
+ newsect->flags = SEC_HAS_CONTENTS;
+ newsect->alignment_power = 2;
+ return true;
+}
+
+#endif /* HAVE_PROCFS */
+
+/* Return a pointer to the args (including the command name) that were
+ seen by the program that generated the core dump. Note that for
+ some reason, a spurious space is tacked onto the end of the args
+ in some (at least one anyway) implementations, so strip it off if
+ it exists. */
+
+char *
+elf_core_file_failing_command (abfd)
+ bfd *abfd;
+{
+#ifdef HAVE_PROCFS
+ if (core_prpsinfo (abfd))
+ {
+ prpsinfo_t *p = core_prpsinfo (abfd);
+ char *scan = p->pr_psargs;
+ while (*scan++)
+ {;
+ }
+ scan -= 2;
+ if ((scan > p->pr_psargs) && (*scan == ' '))
+ {
+ *scan = '\000';
+ }
+ return p->pr_psargs;
+ }
+#endif
+ return NULL;
+}
+
+/* Return the number of the signal that caused the core dump. Presumably,
+ since we have a core file, we got a signal of some kind, so don't bother
+ checking the other process status fields, just return the signal number.
+ */
+
+int
+elf_core_file_failing_signal (abfd)
+ bfd *abfd;
+{
+#ifdef HAVE_PROCFS
+ if (core_prstatus (abfd))
+ {
+ return ((prstatus_t *) (core_prstatus (abfd)))->pr_cursig;
+ }
+#endif
+ return -1;
+}
+
+/* Check to see if the core file could reasonably be expected to have
+ come for the current executable file. Note that by default we return
+ true unless we find something that indicates that there might be a
+ problem.
+ */
+
+boolean
+elf_core_file_matches_executable_p (core_bfd, exec_bfd)
+ bfd *core_bfd;
+ bfd *exec_bfd;
+{
+#ifdef HAVE_PROCFS
+ char *corename;
+ char *execname;
+#endif
+
+ /* First, xvecs must match since both are ELF files for the same target. */
+
+ if (core_bfd->xvec != exec_bfd->xvec)
+ {
+ bfd_set_error (bfd_error_system_call);
+ return false;
+ }
+
+#ifdef HAVE_PROCFS
+
+ /* If no prpsinfo, just return true. Otherwise, grab the last component
+ of the exec'd pathname from the prpsinfo. */
+
+ if (core_prpsinfo (core_bfd))
+ {
+ corename = (((struct prpsinfo *) core_prpsinfo (core_bfd))->pr_fname);
+ }
+ else
+ {
+ return true;
+ }
+
+ /* Find the last component of the executable pathname. */
+
+ if ((execname = strrchr (exec_bfd->filename, '/')) != NULL)
+ {
+ execname++;
+ }
+ else
+ {
+ execname = (char *) exec_bfd->filename;
+ }
+
+ /* See if they match */
+
+ return strcmp (execname, corename) ? false : true;
+
+#else
+
+ return true;
+
+#endif /* HAVE_PROCFS */
+}
+
+/* ELF core files contain a segment of type PT_NOTE, that holds much of
+ the information that would normally be available from the /proc interface
+ for the process, at the time the process dumped core. Currently this
+ includes copies of the prstatus, prpsinfo, and fpregset structures.
+
+ Since these structures are potentially machine dependent in size and
+ ordering, bfd provides two levels of support for them. The first level,
+ available on all machines since it does not require that the host
+ have /proc support or the relevant include files, is to create a bfd
+ section for each of the prstatus, prpsinfo, and fpregset structures,
+ without any interpretation of their contents. With just this support,
+ the bfd client will have to interpret the structures itself. Even with
+ /proc support, it might want these full structures for it's own reasons.
+
+ In the second level of support, where HAVE_PROCFS is defined, bfd will
+ pick apart the structures to gather some additional information that
+ clients may want, such as the general register set, the name of the
+ exec'ed file and its arguments, the signal (if any) that caused the
+ core dump, etc.
+
+ */
+
+static boolean
+elf_corefile_note (abfd, hdr)
+ bfd *abfd;
+ Elf_Internal_Phdr *hdr;
+{
+ Elf_External_Note *x_note_p; /* Elf note, external form */
+ Elf_Internal_Note i_note; /* Elf note, internal form */
+ char *buf = NULL; /* Entire note segment contents */
+ char *namedata; /* Name portion of the note */
+ char *descdata; /* Descriptor portion of the note */
+ char *sectname; /* Name to use for new section */
+ long filepos; /* File offset to descriptor data */
+ asection *newsect;
+
+ if (hdr->p_filesz > 0
+ && (buf = (char *) malloc (hdr->p_filesz)) != NULL
+ && bfd_seek (abfd, hdr->p_offset, SEEK_SET) != -1
+ && bfd_read ((PTR) buf, hdr->p_filesz, 1, abfd) == hdr->p_filesz)
+ {
+ x_note_p = (Elf_External_Note *) buf;
+ while ((char *) x_note_p < (buf + hdr->p_filesz))
+ {
+ i_note.namesz = bfd_h_get_32 (abfd, (bfd_byte *) x_note_p->namesz);
+ i_note.descsz = bfd_h_get_32 (abfd, (bfd_byte *) x_note_p->descsz);
+ i_note.type = bfd_h_get_32 (abfd, (bfd_byte *) x_note_p->type);
+ namedata = x_note_p->name;
+ descdata = namedata + BFD_ALIGN (i_note.namesz, 4);
+ filepos = hdr->p_offset + (descdata - buf);
+ switch (i_note.type)
+ {
+ case NT_PRSTATUS:
+ /* process descdata as prstatus info */
+ if (! bfd_prstatus (abfd, descdata, i_note.descsz, filepos))
+ return false;
+ sectname = ".prstatus";
+ break;
+ case NT_FPREGSET:
+ /* process descdata as fpregset info */
+ if (! bfd_fpregset (abfd, descdata, i_note.descsz, filepos))
+ return false;
+ sectname = ".fpregset";
+ break;
+ case NT_PRPSINFO:
+ /* process descdata as prpsinfo */
+ if (! bfd_prpsinfo (abfd, descdata, i_note.descsz, filepos))
+ return false;
+ sectname = ".prpsinfo";
+ break;
+ default:
+ /* Unknown descriptor, just ignore it. */
+ sectname = NULL;
+ break;
+ }
+ if (sectname != NULL)
+ {
+ newsect = bfd_make_section (abfd, sectname);
+ if (newsect == NULL)
+ return false;
+ newsect->_raw_size = i_note.descsz;
+ newsect->filepos = filepos;
+ newsect->flags = SEC_ALLOC | SEC_HAS_CONTENTS;
+ newsect->alignment_power = 2;
+ }
+ x_note_p = (Elf_External_Note *)
+ (descdata + BFD_ALIGN (i_note.descsz, 4));
+ }
+ }
+ if (buf != NULL)
+ {
+ free (buf);
+ }
+ else if (hdr->p_filesz > 0)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ return false;
+ }
+ return true;
+
+}
+
+/* Core files are simply standard ELF formatted files that partition
+ the file using the execution view of the file (program header table)
+ rather than the linking view. In fact, there is no section header
+ table in a core file.
+
+ The process status information (including the contents of the general
+ register set) and the floating point register set are stored in a
+ segment of type PT_NOTE. We handcraft a couple of extra bfd sections
+ that allow standard bfd access to the general registers (.reg) and the
+ floating point registers (.reg2).
+
+ */
+
+const bfd_target *
+elf_core_file_p (abfd)
+ bfd *abfd;
+{
+ Elf_External_Ehdr x_ehdr; /* Elf file header, external form */
+ Elf_Internal_Ehdr *i_ehdrp; /* Elf file header, internal form */
+ Elf_External_Phdr x_phdr; /* Program header table entry, external form */
+ Elf_Internal_Phdr *i_phdrp; /* Program header table, internal form */
+ unsigned int phindex;
+ struct elf_backend_data *ebd;
+
+ /* Read in the ELF header in external format. */
+
+ if (bfd_read ((PTR) & x_ehdr, sizeof (x_ehdr), 1, abfd) != sizeof (x_ehdr))
+ {
+ if (bfd_get_error () != bfd_error_system_call)
+ bfd_set_error (bfd_error_wrong_format);
+ return NULL;
+ }
+
+ /* Now check to see if we have a valid ELF file, and one that BFD can
+ make use of. The magic number must match, the address size ('class')
+ and byte-swapping must match our XVEC entry, and it must have a
+ program header table (FIXME: See comments re segments at top of this
+ file). */
+
+ if (elf_file_p (&x_ehdr) == false)
+ {
+ wrong:
+ bfd_set_error (bfd_error_wrong_format);
+ return NULL;
+ }
+
+ /* FIXME, Check EI_VERSION here ! */
+
+ {
+#if ARCH_SIZE == 32
+ int desired_address_size = ELFCLASS32;
+#endif
+#if ARCH_SIZE == 64
+ int desired_address_size = ELFCLASS64;
+#endif
+
+ if (x_ehdr.e_ident[EI_CLASS] != desired_address_size)
+ goto wrong;
+ }
+
+ /* Switch xvec to match the specified byte order. */
+ switch (x_ehdr.e_ident[EI_DATA])
+ {
+ case ELFDATA2MSB: /* Big-endian */
+ if (abfd->xvec->byteorder_big_p == false)
+ goto wrong;
+ break;
+ case ELFDATA2LSB: /* Little-endian */
+ if (abfd->xvec->byteorder_big_p == true)
+ goto wrong;
+ break;
+ case ELFDATANONE: /* No data encoding specified */
+ default: /* Unknown data encoding specified */
+ goto wrong;
+ }
+
+ /* Allocate an instance of the elf_obj_tdata structure and hook it up to
+ the tdata pointer in the bfd. */
+
+ elf_tdata (abfd) =
+ (struct elf_obj_tdata *) bfd_zalloc (abfd, sizeof (struct elf_obj_tdata));
+ if (elf_tdata (abfd) == NULL)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ return NULL;
+ }
+
+ /* FIXME, `wrong' returns from this point onward, leak memory. */
+
+ /* Now that we know the byte order, swap in the rest of the header */
+ i_ehdrp = elf_elfheader (abfd);
+ elf_swap_ehdr_in (abfd, &x_ehdr, i_ehdrp);
+#if DEBUG & 1
+ elf_debug_file (i_ehdrp);
+#endif
+
+ ebd = get_elf_backend_data (abfd);
+
+ /* Check that the ELF e_machine field matches what this particular
+ BFD format expects. */
+ if (ebd->elf_machine_code != i_ehdrp->e_machine)
+ {
+ const bfd_target * const *target_ptr;
+
+ if (ebd->elf_machine_code != EM_NONE)
+ goto wrong;
+
+ /* This is the generic ELF target. Let it match any ELF target
+ for which we do not have a specific backend. */
+ for (target_ptr = bfd_target_vector; *target_ptr != NULL; target_ptr++)
+ {
+ struct elf_backend_data *back;
+
+ if ((*target_ptr)->flavour != bfd_target_elf_flavour)
+ continue;
+ back = (struct elf_backend_data *) (*target_ptr)->backend_data;
+ if (back->elf_machine_code == i_ehdrp->e_machine)
+ {
+ /* target_ptr is an ELF backend which matches this
+ object file, so reject the generic ELF target. */
+ goto wrong;
+ }
+ }
+ }
+
+ /* If there is no program header, or the type is not a core file, then
+ we are hosed. */
+ if (i_ehdrp->e_phoff == 0 || i_ehdrp->e_type != ET_CORE)
+ goto wrong;
+
+ /* Allocate space for a copy of the program header table in
+ internal form, seek to the program header table in the file,
+ read it in, and convert it to internal form. As a simple sanity
+ check, verify that the what BFD thinks is the size of each program
+ header table entry actually matches the size recorded in the file. */
+
+ if (i_ehdrp->e_phentsize != sizeof (x_phdr))
+ goto wrong;
+ i_phdrp = (Elf_Internal_Phdr *)
+ bfd_alloc (abfd, sizeof (*i_phdrp) * i_ehdrp->e_phnum);
+ if (!i_phdrp)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ return NULL;
+ }
+ if (bfd_seek (abfd, i_ehdrp->e_phoff, SEEK_SET) == -1)
+ return NULL;
+ for (phindex = 0; phindex < i_ehdrp->e_phnum; phindex++)
+ {
+ if (bfd_read ((PTR) & x_phdr, sizeof (x_phdr), 1, abfd)
+ != sizeof (x_phdr))
+ return NULL;
+ elf_swap_phdr_in (abfd, &x_phdr, i_phdrp + phindex);
+ }
+
+ /* Once all of the program headers have been read and converted, we
+ can start processing them. */
+
+ for (phindex = 0; phindex < i_ehdrp->e_phnum; phindex++)
+ {
+ bfd_section_from_phdr (abfd, i_phdrp + phindex, phindex);
+ if ((i_phdrp + phindex)->p_type == PT_NOTE)
+ {
+ if (! elf_corefile_note (abfd, i_phdrp + phindex))
+ return NULL;
+ }
+ }
+
+ /* Remember the entry point specified in the ELF file header. */
+
+ bfd_get_start_address (abfd) = i_ehdrp->e_entry;
+
+ return abfd->xvec;
+}
+
+/* ELF linker code. */
+
+static boolean elf_link_add_object_symbols
+ PARAMS ((bfd *, struct bfd_link_info *));
+static boolean elf_link_add_archive_symbols
+ PARAMS ((bfd *, struct bfd_link_info *));
+static INLINE boolean elf_link_record_dynamic_symbol
+ PARAMS ((struct bfd_link_info *, struct elf_link_hash_entry *));
+static boolean elf_link_create_dynamic_sections
+ PARAMS ((bfd *, struct bfd_link_info *));
+static boolean elf_adjust_dynamic_symbol
+ PARAMS ((struct elf_link_hash_entry *, PTR));
+
+/* Given an ELF BFD, add symbols to the global hash table as
+ appropriate. */
+
+boolean
+elf_bfd_link_add_symbols (abfd, info)
+ bfd *abfd;
+ struct bfd_link_info *info;
+{
+ switch (bfd_get_format (abfd))
+ {
+ case bfd_object:
+ return elf_link_add_object_symbols (abfd, info);
+ case bfd_archive:
+ return elf_link_add_archive_symbols (abfd, info);
+ default:
+ bfd_set_error (bfd_error_wrong_format);
+ return false;
+ }
+}
+
+/* Add symbols from an ELF archive file to the linker hash table. We
+ don't use _bfd_generic_link_add_archive_symbols because of a
+ problem which arises on UnixWare. The UnixWare libc.so is an
+ archive which includes an entry libc.so.1 which defines a bunch of
+ symbols. The libc.so archive also includes a number of other
+ object files, which also define symbols, some of which are the same
+ as those defined in libc.so.1. Correct linking requires that we
+ consider each object file in turn, and include it if it defines any
+ symbols we need. _bfd_generic_link_add_archive_symbols does not do
+ this; it looks through the list of undefined symbols, and includes
+ any object file which defines them. When this algorithm is used on
+ UnixWare, it winds up pulling in libc.so.1 early and defining a
+ bunch of symbols. This means that some of the other objects in the
+ archive are not included in the link, which is incorrect since they
+ precede libc.so.1 in the archive.
+
+ Fortunately, ELF archive handling is simpler than that done by
+ _bfd_generic_link_add_archive_symbols, which has to allow for a.out
+ oddities. In ELF, if we find a symbol in the archive map, and the
+ symbol is currently undefined, we know that we must pull in that
+ object file.
+
+ Unfortunately, we do have to make multiple passes over the symbol
+ table until nothing further is resolved. */
+
+static boolean
+elf_link_add_archive_symbols (abfd, info)
+ bfd *abfd;
+ struct bfd_link_info *info;
+{
+ symindex c;
+ boolean *defined = NULL;
+ boolean *included = NULL;
+ carsym *symdefs;
+ boolean loop;
+
+ if (! bfd_has_map (abfd))
+ {
+ bfd_set_error (bfd_error_no_symbols);
+ return false;
+ }
+
+ /* Keep track of all symbols we know to be already defined, and all
+ files we know to be already included. This is to speed up the
+ second and subsequent passes. */
+ c = bfd_ardata (abfd)->symdef_count;
+ if (c == 0)
+ return true;
+ defined = (boolean *) malloc (c * sizeof (boolean));
+ included = (boolean *) malloc (c * sizeof (boolean));
+ if (defined == (boolean *) NULL || included == (boolean *) NULL)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ goto error_return;
+ }
+ memset (defined, 0, c * sizeof (boolean));
+ memset (included, 0, c * sizeof (boolean));
+
+ symdefs = bfd_ardata (abfd)->symdefs;
+
+ do
+ {
+ file_ptr last;
+ symindex i;
+ carsym *symdef;
+ carsym *symdefend;
+
+ loop = false;
+ last = -1;
+
+ symdef = symdefs;
+ symdefend = symdef + c;
+ for (i = 0; symdef < symdefend; symdef++, i++)
+ {
+ struct elf_link_hash_entry *h;
+ bfd *element;
+ struct bfd_link_hash_entry *undefs_tail;
+ symindex mark;
+
+ if (defined[i] || included[i])
+ continue;
+ if (symdef->file_offset == last)
+ {
+ included[i] = true;
+ continue;
+ }
+
+ h = elf_link_hash_lookup (elf_hash_table (info), symdef->name,
+ false, false, false);
+ if (h == (struct elf_link_hash_entry *) NULL)
+ continue;
+ if (h->root.type != bfd_link_hash_undefined)
+ {
+ defined[i] = true;
+ continue;
+ }
+
+ /* We need to include this archive member. */
+
+ element = _bfd_get_elt_at_filepos (abfd, symdef->file_offset);
+ if (element == (bfd *) NULL)
+ goto error_return;
+
+ if (! bfd_check_format (element, bfd_object))
+ goto error_return;
+
+ /* Doublecheck that we have not included this object
+ already--it should be impossible, but there may be
+ something wrong with the archive. */
+ if (element->archive_pass != 0)
+ {
+ bfd_set_error (bfd_error_bad_value);
+ goto error_return;
+ }
+ element->archive_pass = 1;
+
+ undefs_tail = info->hash->undefs_tail;
+
+ if (! (*info->callbacks->add_archive_element) (info, element,
+ symdef->name))
+ goto error_return;
+ if (! elf_link_add_object_symbols (element, info))
+ goto error_return;
+
+ /* If there are any new undefined symbols, we need to make
+ another pass through the archive in order to see whether
+ they can be defined. FIXME: This isn't perfect, because
+ common symbols wind up on undefs_tail and because an
+ undefined symbol which is defined later on in this pass
+ does not require another pass. This isn't a bug, but it
+ does make the code less efficient than it could be. */
+ if (undefs_tail != info->hash->undefs_tail)
+ loop = true;
+
+ /* Look backward to mark all symbols from this object file
+ which we have already seen in this pass. */
+ mark = i;
+ do
+ {
+ included[mark] = true;
+ if (mark == 0)
+ break;
+ --mark;
+ }
+ while (symdefs[mark].file_offset == symdef->file_offset);
+
+ /* We mark subsequent symbols from this object file as we go
+ on through the loop. */
+ last = symdef->file_offset;
+ }
+ }
+ while (loop);
+
+ free (defined);
+ free (included);
+
+ return true;
+
+ error_return:
+ if (defined != (boolean *) NULL)
+ free (defined);
+ if (included != (boolean *) NULL)
+ free (included);
+ return false;
+}
+
+/* Record a new dynamic symbol. We record the dynamic symbols as we
+ read the input files, since we need to have a list of all of them
+ before we can determine the final sizes of the output sections. */
+
+static INLINE boolean
+elf_link_record_dynamic_symbol (info, h)
+ struct bfd_link_info *info;
+ struct elf_link_hash_entry *h;
+{
+ if (h->dynindx == -1)
+ {
+ h->dynindx = elf_hash_table (info)->dynsymcount;
+ ++elf_hash_table (info)->dynsymcount;
+ h->dynstr_index = bfd_add_to_strtab (elf_hash_table (info)->dynobj,
+ elf_hash_table (info)->dynstr,
+ h->root.root.string);
+ if (h->dynstr_index == (unsigned long) -1)
+ return false;
+ }
+
+ return true;
+}
+
+/* Add symbols from an ELF object file to the linker hash table. */
+
+static boolean
+elf_link_add_object_symbols (abfd, info)
+ bfd *abfd;
+ struct bfd_link_info *info;
+{
+ boolean (*add_symbol_hook) PARAMS ((bfd *, struct bfd_link_info *,
+ const Elf_Internal_Sym *,
+ const char **, flagword *,
+ asection **, bfd_vma *));
+ boolean collect;
+ Elf_Internal_Shdr *hdr;
+ size_t symcount;
+ size_t extsymcount;
+ size_t extsymoff;
+ Elf_External_Sym *buf = NULL;
+ struct elf_link_hash_entry **sym_hash;
+ boolean dynamic;
+ Elf_External_Dyn *dynbuf = NULL;
+ struct elf_link_hash_entry *weaks;
+ Elf_External_Sym *esym;
+ Elf_External_Sym *esymend;
+
+ add_symbol_hook = get_elf_backend_data (abfd)->elf_add_symbol_hook;
+ collect = get_elf_backend_data (abfd)->collect;
+
+ hdr = &elf_tdata (abfd)->symtab_hdr;
+ symcount = hdr->sh_size / sizeof (Elf_External_Sym);
+
+ /* The sh_info field of the symtab header tells us where the
+ external symbols start. We don't care about the local symbols at
+ this point. */
+ if (elf_bad_symtab (abfd))
+ {
+ extsymcount = symcount;
+ extsymoff = 0;
+ }
+ else
+ {
+ extsymcount = symcount - hdr->sh_info;
+ extsymoff = hdr->sh_info;
+ }
+
+ buf = (Elf_External_Sym *) malloc (extsymcount * sizeof (Elf_External_Sym));
+ if (buf == NULL && extsymcount != 0)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ goto error_return;
+ }
+
+ /* We store a pointer to the hash table entry for each external
+ symbol. */
+ sym_hash = ((struct elf_link_hash_entry **)
+ bfd_alloc (abfd,
+ extsymcount * sizeof (struct elf_link_hash_entry *)));
+ if (sym_hash == NULL)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ goto error_return;
+ }
+ elf_sym_hashes (abfd) = sym_hash;
+
+ if (elf_elfheader (abfd)->e_type != ET_DYN)
+ {
+ dynamic = false;
+
+ /* If we are creating a shared library, create all the dynamic
+ sections immediately. We need to attach them to something,
+ so we attach them to this BFD, provided it is the right
+ format. FIXME: If there are no input BFD's of the same
+ format as the output, we can't make a shared library. */
+ if (info->shared
+ && elf_hash_table (info)->dynobj == NULL
+ && abfd->xvec == info->hash->creator)
+ {
+ if (! elf_link_create_dynamic_sections (abfd, info))
+ goto error_return;
+ elf_hash_table (info)->dynobj = abfd;
+ }
+ }
+ else
+ {
+ asection *s;
+ const char *name;
+ unsigned long strindex;
+
+ dynamic = true;
+
+ /* You can't use -r against a dynamic object. There's no hope
+ of using a dynamic object which does not exactly match the
+ format of the output file. */
+ if (info->relocateable
+ || info->hash->creator != abfd->xvec)
+ {
+ bfd_set_error (bfd_error_invalid_operation);
+ goto error_return;
+ }
+
+ /* Find the name to use in a DT_NEEDED entry that refers to this
+ object. If the object has a DT_SONAME entry, we use it.
+ Otherwise, if the generic linker stuck something in
+ elf_dt_needed_name, we use that. Otherwise, we just use the
+ file name. */
+ name = bfd_get_filename (abfd);
+ if (elf_dt_needed_name (abfd) != NULL)
+ name = elf_dt_needed_name (abfd);
+ s = bfd_get_section_by_name (abfd, ".dynamic");
+ if (s != NULL)
+ {
+ Elf_External_Dyn *extdyn;
+ Elf_External_Dyn *extdynend;
+
+ dynbuf = (Elf_External_Dyn *) malloc (s->_raw_size);
+ if (dynbuf == NULL)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ goto error_return;
+ }
+
+ if (! bfd_get_section_contents (abfd, s, (PTR) dynbuf,
+ (file_ptr) 0, s->_raw_size))
+ goto error_return;
+
+ extdyn = dynbuf;
+ extdynend = extdyn + s->_raw_size / sizeof (Elf_External_Dyn);
+ for (; extdyn < extdynend; extdyn++)
+ {
+ Elf_Internal_Dyn dyn;
+
+ elf_swap_dyn_in (abfd, extdyn, &dyn);
+ if (dyn.d_tag == DT_SONAME)
+ {
+ int elfsec;
+ unsigned long link;
+
+ elfsec = elf_section_from_bfd_section (abfd, s);
+ if (elfsec == -1)
+ goto error_return;
+ link = elf_elfsections (abfd)[elfsec]->sh_link;
+ name = elf_string_from_elf_section (abfd, link,
+ dyn.d_un.d_val);
+ if (name == NULL)
+ goto error_return;
+
+ break;
+ }
+ }
+
+ free (dynbuf);
+ dynbuf = NULL;
+ }
+
+ /* We do not want to include any of the sections in a dynamic
+ object in the output file. We hack by simply clobbering the
+ list of sections in the BFD. This could be handled more
+ cleanly by, say, a new section flag; the existing
+ SEC_NEVER_LOAD flag is not the one we want, because that one
+ still implies that the section takes up space in the output
+ file. */
+ abfd->sections = NULL;
+
+ /* If this is the first dynamic object found in the link, create
+ the special sections required for dynamic linking. We need
+ to put them somewhere, and attaching them to the first
+ dynamic object is as good place as any. */
+ if (elf_hash_table (info)->dynobj == NULL)
+ {
+ if (! elf_link_create_dynamic_sections (abfd, info))
+ goto error_return;
+ elf_hash_table (info)->dynobj = abfd;
+ }
+
+ /* Add a DT_NEEDED entry for this dynamic object. */
+ strindex = bfd_add_to_strtab (abfd,
+ elf_hash_table (info)->dynstr,
+ name);
+
+ if (strindex == (unsigned long) -1)
+ goto error_return;
+ if (! elf_add_dynamic_entry (info, DT_NEEDED, strindex))
+ goto error_return;
+ }
+
+ if (bfd_seek (abfd,
+ hdr->sh_offset + extsymoff * sizeof (Elf_External_Sym),
+ SEEK_SET) != 0
+ || (bfd_read ((PTR) buf, sizeof (Elf_External_Sym), extsymcount, abfd)
+ != extsymcount * sizeof (Elf_External_Sym)))
+ goto error_return;
+
+ weaks = NULL;
+
+ esymend = buf + extsymcount;
+ for (esym = buf; esym < esymend; esym++, sym_hash++)
+ {
+ Elf_Internal_Sym sym;
+ int bind;
+ bfd_vma value;
+ asection *sec;
+ flagword flags;
+ const char *name;
+ struct elf_link_hash_entry *h = NULL;
+ boolean definition;
+
+ elf_swap_symbol_in (abfd, esym, &sym);
+
+ flags = BSF_NO_FLAGS;
+ sec = NULL;
+ value = sym.st_value;
+ *sym_hash = NULL;
+
+ bind = ELF_ST_BIND (sym.st_info);
+ if (bind == STB_LOCAL)
+ {
+ /* This should be impossible, since ELF requires that all
+ global symbols follow all local symbols, and that sh_info
+ point to the first global symbol. Unfortunatealy, Irix 5
+ screws this up. */
+ continue;
+ }
+ else if (bind == STB_GLOBAL)
+ flags = BSF_GLOBAL;
+ else if (bind == STB_WEAK)
+ flags = BSF_WEAK;
+ else
+ {
+ /* Leave it up to the processor backend. */
+ }
+
+ if (sym.st_shndx == SHN_UNDEF)
+ sec = bfd_und_section_ptr;
+ else if (sym.st_shndx > 0 && sym.st_shndx < SHN_LORESERVE)
+ {
+ sec = section_from_elf_index (abfd, sym.st_shndx);
+ if (sec == NULL)
+ goto error_return;
+ value -= sec->vma;
+ }
+ else if (sym.st_shndx == SHN_ABS)
+ sec = bfd_abs_section_ptr;
+ else if (sym.st_shndx == SHN_COMMON)
+ {
+ sec = bfd_com_section_ptr;
+ /* What ELF calls the size we call the value. What ELF
+ calls the value we call the alignment. */
+ value = sym.st_size;
+ }
+ else
+ {
+ /* Leave it up to the processor backend. */
+ }
+
+ name = elf_string_from_elf_section (abfd, hdr->sh_link, sym.st_name);
+ if (name == (const char *) NULL)
+ goto error_return;
+
+ if (add_symbol_hook)
+ {
+ if (! (*add_symbol_hook) (abfd, info, &sym, &name, &flags, &sec,
+ &value))
+ goto error_return;
+
+ /* The hook function sets the name to NULL if this symbol
+ should be skipped for some reason. */
+ if (name == (const char *) NULL)
+ continue;
+ }
+
+ /* Sanity check that all possibilities were handled. */
+ if (flags == BSF_NO_FLAGS || sec == (asection *) NULL)
+ {
+ bfd_set_error (bfd_error_bad_value);
+ goto error_return;
+ }
+
+ if (bfd_is_und_section (sec)
+ || bfd_is_com_section (sec))
+ definition = false;
+ else
+ definition = true;
+
+ if (info->hash->creator->flavour == bfd_target_elf_flavour)
+ {
+ /* We need to look up the symbol now in order to get some of
+ the dynamic object handling right. We pass the hash
+ table entry in to _bfd_generic_link_add_one_symbol so
+ that it does not have to look it up again. */
+ h = elf_link_hash_lookup (elf_hash_table (info), name,
+ true, false, false);
+ if (h == NULL)
+ goto error_return;
+ *sym_hash = h;
+
+ /* If we are looking at a dynamic object, and this is a
+ definition, we need to see if it has already been defined
+ by some other object. If it has, we want to use the
+ existing definition, and we do not want to report a
+ multiple symbol definition error; we do this by
+ clobbering sec to be bfd_und_section_ptr. */
+ if (dynamic && definition)
+ {
+ if (h->root.type == bfd_link_hash_defined)
+ sec = bfd_und_section_ptr;
+ }
+
+ /* Similarly, if we are not looking at a dynamic object, and
+ we have a definition, we want to override any definition
+ we may have from a dynamic object. Symbols from regular
+ files always take precedence over symbols from dynamic
+ objects, even if they are defined after the dynamic
+ object in the link. */
+ if (! dynamic
+ && definition
+ && h->root.type == bfd_link_hash_defined
+ && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC) != 0
+ && (bfd_get_flavour (h->root.u.def.section->owner)
+ == bfd_target_elf_flavour)
+ && (elf_elfheader (h->root.u.def.section->owner)->e_type
+ == ET_DYN))
+ {
+ /* Change the hash table entry to undefined, and let
+ _bfd_generic_link_add_one_symbol do the right thing
+ with the new definition. */
+ h->root.type = bfd_link_hash_undefined;
+ h->root.u.undef.abfd = h->root.u.def.section->owner;
+ h->elf_link_hash_flags &=~ ELF_LINK_HASH_DEFINED_WEAK;
+ }
+
+ /* If this is a weak definition which we are going to use,
+ and the symbol is currently undefined, record that the
+ definition is weak. */
+ if (definition
+ && (flags & BSF_WEAK) != 0
+ && ! bfd_is_und_section (sec)
+ && (h->root.type == bfd_link_hash_new
+ || h->root.type == bfd_link_hash_undefined
+ || h->root.type == bfd_link_hash_weak))
+ h->elf_link_hash_flags |= ELF_LINK_HASH_DEFINED_WEAK;
+ }
+
+ if (! (_bfd_generic_link_add_one_symbol
+ (info, abfd, name, flags, sec, value, (const char *) NULL,
+ false, collect, (struct bfd_link_hash_entry **) sym_hash)))
+ goto error_return;
+
+ if (dynamic
+ && definition
+ && (flags & BSF_WEAK) != 0
+ && ELF_ST_TYPE (sym.st_info) != STT_FUNC
+ && (*sym_hash)->weakdef == NULL)
+ {
+ /* Keep a list of all weak defined non function symbols from
+ a dynamic object, using the weakdef field. Later in this
+ function we will set the weakdef field to the correct
+ value. We only put non-function symbols from dynamic
+ objects on this list, because that happens to be the only
+ time we need to know the normal symbol corresponding to a
+ weak symbol, and the information is time consuming to
+ figure out. If the weakdef field is not already NULL,
+ then this symbol was already defined by some previous
+ dynamic object, and we will be using that previous
+ definition anyhow. */
+
+ (*sym_hash)->weakdef = weaks;
+ weaks = *sym_hash;
+ }
+
+ if (info->hash->creator->flavour == bfd_target_elf_flavour)
+ {
+ int old_flags;
+ boolean dynsym;
+ int new_flag;
+
+ /* Remember the symbol size, type and alignment. */
+ if (sym.st_size != 0)
+ {
+ /* FIXME: We should probably somehow give a warning if
+ the symbol size changes. */
+ h->size = sym.st_size;
+ }
+ if (sym.st_shndx == SHN_COMMON
+ && sym.st_value > h->align)
+ h->align = sym.st_value;
+ if (ELF_ST_TYPE (sym.st_info) != STT_NOTYPE)
+ {
+ /* FIXME: We should probably somehow give a warning if
+ the symbol type changes. */
+ h->type = ELF_ST_TYPE (sym.st_info);
+ }
+
+ /* Set a flag in the hash table entry indicating the type of
+ reference or definition we just found. Keep a count of
+ the number of dynamic symbols we find. A dynamic symbol
+ is one which is referenced or defined by both a regular
+ object and a shared object, or one which is referenced or
+ defined by more than one shared object. */
+ old_flags = h->elf_link_hash_flags;
+ dynsym = false;
+ if (! dynamic)
+ {
+ if (! definition)
+ new_flag = ELF_LINK_HASH_REF_REGULAR;
+ else
+ new_flag = ELF_LINK_HASH_DEF_REGULAR;
+ if ((old_flags & (ELF_LINK_HASH_DEF_DYNAMIC
+ | ELF_LINK_HASH_REF_DYNAMIC)) != 0)
+ dynsym = true;
+ }
+ else
+ {
+ if (! definition)
+ new_flag = ELF_LINK_HASH_REF_DYNAMIC;
+ else
+ new_flag = ELF_LINK_HASH_DEF_DYNAMIC;
+ if ((old_flags & new_flag) != 0)
+ {
+ if (! definition)
+ new_flag = ELF_LINK_HASH_REF_DYNAMIC_MULTIPLE;
+ else
+ new_flag = ELF_LINK_HASH_DEF_DYNAMIC_MULTIPLE;
+ dynsym = true;
+ }
+ else
+ {
+ if ((old_flags & (ELF_LINK_HASH_DEF_REGULAR
+ | ELF_LINK_HASH_REF_REGULAR)) != 0)
+ dynsym = true;
+ }
+ }
+
+ h->elf_link_hash_flags |= new_flag;
+ if (dynsym && h->dynindx == -1)
+ {
+ if (! elf_link_record_dynamic_symbol (info, h))
+ goto error_return;
+ }
+ }
+ }
+
+ /* Now set the weakdefs field correctly for all the weak defined
+ symbols we found. The only way to do this is to search all the
+ symbols. Since we only need the information for non functions in
+ dynamic objects, that's the only time we actually put anything on
+ the list WEAKS. We need this information so that if a regular
+ object refers to a symbol defined weakly in a dynamic object, the
+ real symbol in the dynamic object is also put in the dynamic
+ symbols; we also must arrange for both symbols to point to the
+ same memory location. We could handle the general case of symbol
+ aliasing, but a general symbol alias can only be generated in
+ assembler code, handling it correctly would be very time
+ consuming, and other ELF linkers don't handle general aliasing
+ either. */
+ while (weaks != NULL)
+ {
+ struct elf_link_hash_entry *hlook;
+ asection *slook;
+ bfd_vma vlook;
+ struct elf_link_hash_entry **hpp;
+ struct elf_link_hash_entry **hppend;
+
+ hlook = weaks;
+ weaks = hlook->weakdef;
+ hlook->weakdef = NULL;
+
+ BFD_ASSERT (hlook->root.type == bfd_link_hash_defined);
+ slook = hlook->root.u.def.section;
+ vlook = hlook->root.u.def.value;
+
+ hpp = elf_sym_hashes (abfd);
+ hppend = hpp + extsymcount;
+ for (; hpp < hppend; hpp++)
+ {
+ struct elf_link_hash_entry *h;
+
+ h = *hpp;
+ if (h != hlook
+ && h->root.type == bfd_link_hash_defined
+ && h->root.u.def.section == slook
+ && h->root.u.def.value == vlook)
+ {
+ hlook->weakdef = h;
+
+ /* If the weak definition is in the list of dynamic
+ symbols, make sure the real definition is put there
+ as well. */
+ if (hlook->dynindx != -1
+ && h->dynindx == -1)
+ {
+ if (! elf_link_record_dynamic_symbol (info, h))
+ goto error_return;
+ }
+
+ break;
+ }
+ }
+ }
+
+ if (buf != NULL)
+ free (buf);
+
+ return true;
+
+ error_return:
+ if (buf != NULL)
+ free (buf);
+ if (dynbuf != NULL)
+ free (dynbuf);
+ return false;
+}
+
+/* Create some sections which will be filled in with dynamic linking
+ information. The ABFD argument is an input file which is a dynamic
+ object. The dynamic sections take up virtual memory space when the
+ final executable is run, so we need to create them before addresses
+ are assigned to the output sections. We work out the actual
+ contents and size of these sections later. */
+
+static boolean
+elf_link_create_dynamic_sections (abfd, info)
+ bfd *abfd;
+ struct bfd_link_info *info;
+{
+ flagword flags;
+ register asection *s;
+ struct elf_link_hash_entry *h;
+ struct elf_backend_data *bed;
+
+ /* Note that we set the SEC_IN_MEMORY flag for all of these
+ sections. */
+ flags = SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY;
+
+ /* A dynamically linked executable has a .interp section, but a
+ shared library does not. */
+ if (! info->shared)
+ {
+ s = bfd_make_section (abfd, ".interp");
+ if (s == NULL
+ || ! bfd_set_section_flags (abfd, s, flags | SEC_READONLY))
+ return false;
+ }
+
+ s = bfd_make_section (abfd, ".dynamic");
+ if (s == NULL
+ || ! bfd_set_section_flags (abfd, s, flags)
+ || ! bfd_set_section_alignment (abfd, s, LOG_FILE_ALIGN))
+ return false;
+
+ /* The special symbol _DYNAMIC is always set to the start of the
+ .dynamic section. This call occurs before we have processed the
+ symbols for any dynamic object, so we don't have to worry about
+ overriding a dynamic definition. We could set _DYNAMIC in a
+ linker script, but we only want to define it if we are, in fact,
+ creating a .dynamic section. We don't want to define it if there
+ is no .dynamic section, since on some ELF platforms the start up
+ code examines it to decide how to initialize the process. */
+ h = NULL;
+ if (! (_bfd_generic_link_add_one_symbol
+ (info, abfd, "_DYNAMIC", BSF_GLOBAL, s, (bfd_vma) 0,
+ (const char *) NULL, false, get_elf_backend_data (abfd)->collect,
+ (struct bfd_link_hash_entry **) &h)))
+ return false;
+ h->elf_link_hash_flags |= ELF_LINK_HASH_DEF_REGULAR;
+
+ s = bfd_make_section (abfd, ".dynsym");
+ if (s == NULL
+ || ! bfd_set_section_flags (abfd, s, flags | SEC_READONLY)
+ || ! bfd_set_section_alignment (abfd, s, LOG_FILE_ALIGN))
+ return false;
+
+ /* The first .dynsym symbol is a dummy. */
+ elf_hash_table (info)->dynsymcount = 1;
+
+ s = bfd_make_section (abfd, ".dynstr");
+ if (s == NULL
+ || ! bfd_set_section_flags (abfd, s, flags | SEC_READONLY))
+ return false;
+
+ /* Create a strtab to hold the dynamic symbol names. */
+ elf_hash_table (info)->dynstr = bfd_new_strtab (abfd);
+ if (elf_hash_table (info)->dynstr == NULL)
+ return false;
+
+ s = bfd_make_section (abfd, ".hash");
+ if (s == NULL
+ || ! bfd_set_section_flags (abfd, s, flags | SEC_READONLY)
+ || ! bfd_set_section_alignment (abfd, s, LOG_FILE_ALIGN))
+ return false;
+
+ /* Let the backend create the rest of the sections. This lets the
+ backend set the right flags. The backend will normally create
+ the .got and .plt sections. */
+ bed = get_elf_backend_data (abfd);
+ return (*bed->elf_backend_create_dynamic_sections) (abfd, info);
+}
+
+/* Add an entry to the .dynamic table. */
+
+boolean
+elf_add_dynamic_entry (info, tag, val)
+ struct bfd_link_info *info;
+ bfd_vma tag;
+ bfd_vma val;
+{
+ Elf_Internal_Dyn dyn;
+ bfd *dynobj;
+ asection *s;
+ size_t newsize;
+ bfd_byte *newcontents;
+
+ dynobj = elf_hash_table (info)->dynobj;
+
+ s = bfd_get_section_by_name (dynobj, ".dynamic");
+ BFD_ASSERT (s != NULL);
+
+ newsize = s->_raw_size + sizeof (Elf_External_Dyn);
+ if (s->contents == NULL)
+ newcontents = (bfd_byte *) malloc (newsize);
+ else
+ newcontents = (bfd_byte *) realloc (s->contents, newsize);
+ if (newcontents == NULL)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ return false;
+ }
+
+ dyn.d_tag = tag;
+ dyn.d_un.d_val = val;
+ elf_swap_dyn_out (dynobj, &dyn,
+ (Elf_External_Dyn *) (newcontents + s->_raw_size));
+
+ s->_raw_size = newsize;
+ s->contents = newcontents;
+
+ return true;
+}
+
+/* Record an assignment to a symbol made by a linker script. We need
+ this in case some dynamic object refers to this symbol. */
+
+/*ARGSUSED*/
+boolean
+NAME(bfd_elf,record_link_assignment) (output_bfd, info, name)
+ bfd *output_bfd;
+ struct bfd_link_info *info;
+ const char *name;
+{
+ struct elf_link_hash_entry *h;
+
+ /* This is called after we have examined all the input objects. If
+ the symbol does not exist, it merely means that no object refers
+ to it, and we can just ignore it at this point. */
+ h = elf_link_hash_lookup (elf_hash_table (info), name,
+ false, false, false);
+ if (h == NULL)
+ return true;
+
+ h->elf_link_hash_flags |= ELF_LINK_HASH_DEF_REGULAR;
+
+ if ((h->elf_link_hash_flags & (ELF_LINK_HASH_DEF_DYNAMIC
+ | ELF_LINK_HASH_REF_DYNAMIC)) != 0
+ && h->dynindx == -1)
+ {
+ if (! elf_link_record_dynamic_symbol (info, h))
+ return false;
+
+ /* If this is a weak defined symbol, and we know a corresponding
+ real symbol from the same dynamic object, make sure the real
+ symbol is also made into a dynamic symbol. */
+ if (h->weakdef != NULL
+ && h->weakdef->dynindx == -1)
+ {
+ if (! elf_link_record_dynamic_symbol (info, h->weakdef))
+ return false;
+ }
+ }
+
+ return true;
+}
+
+/* Array used to determine the number of hash table buckets to use
+ based on the number of symbols there are. If there are fewer than
+ 3 symbols we use 1 bucket, fewer than 17 symbols we use 3 buckets,
+ fewer than 37 we use 17 buckets, and so forth. We never use more
+ than 521 buckets. */
+
+static const size_t elf_buckets[] =
+{
+ 1, 3, 17, 37, 67, 97, 131, 197, 263, 521, 0
+};
+
+/* Set up the sizes and contents of the ELF dynamic sections. This is
+ called by the ELF linker emulation before_allocation routine. We
+ must set the sizes of the sections before the linker sets the
+ addresses of the various sections. */
+
+boolean
+NAME(bfd_elf,size_dynamic_sections) (output_bfd, info, sinterpptr)
+ bfd *output_bfd;
+ struct bfd_link_info *info;
+ asection **sinterpptr;
+{
+ bfd *dynobj;
+ size_t dynsymcount;
+ asection *s;
+ Elf_Internal_Sym isym;
+ size_t i;
+ size_t bucketcount;
+ struct elf_backend_data *bed;
+
+ *sinterpptr = NULL;
+
+ dynobj = elf_hash_table (info)->dynobj;
+ dynsymcount = elf_hash_table (info)->dynsymcount;
+
+ /* If there were no dynamic objects in the link, there is nothing to
+ do here. */
+ if (dynobj == NULL)
+ return true;
+
+ *sinterpptr = bfd_get_section_by_name (dynobj, ".interp");
+ BFD_ASSERT (*sinterpptr != NULL || info->shared);
+
+ /* Set the size of the .dynsym and .hash sections. We counted the
+ number of dynamic symbols in elf_link_add_object_symbols. We
+ will build the contents of .dynsym and .hash when we build the
+ final symbol table, because until then we do not know the correct
+ value to give the symbols. We built the .dynstr section as we
+ went along in elf_link_add_object_symbols. */
+ s = bfd_get_section_by_name (dynobj, ".dynsym");
+ BFD_ASSERT (s != NULL);
+ s->_raw_size = dynsymcount * sizeof (Elf_External_Sym);
+ s->contents = (bfd_byte *) bfd_alloc (output_bfd, s->_raw_size);
+ if (s->contents == NULL && s->_raw_size != 0)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ return false;
+ }
+
+ /* The first entry in .dynsym is a dummy symbol. */
+ isym.st_value = 0;
+ isym.st_size = 0;
+ isym.st_name = 0;
+ isym.st_info = 0;
+ isym.st_other = 0;
+ isym.st_shndx = 0;
+ elf_swap_symbol_out (output_bfd, &isym,
+ (Elf_External_Sym *) s->contents);
+
+ for (i = 0; elf_buckets[i] != 0; i++)
+ {
+ bucketcount = elf_buckets[i];
+ if (dynsymcount < elf_buckets[i + 1])
+ break;
+ }
+
+ s = bfd_get_section_by_name (dynobj, ".hash");
+ BFD_ASSERT (s != NULL);
+ s->_raw_size = (2 + bucketcount + dynsymcount) * (ARCH_SIZE / 8);
+ s->contents = (bfd_byte *) bfd_alloc (output_bfd, s->_raw_size);
+ if (s->contents == NULL)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ return false;
+ }
+ memset (s->contents, 0, s->_raw_size);
+
+ put_word (output_bfd, bucketcount, s->contents);
+ put_word (output_bfd, dynsymcount, s->contents + (ARCH_SIZE / 8));
+
+ elf_hash_table (info)->bucketcount = bucketcount;
+
+ s = bfd_get_section_by_name (dynobj, ".dynstr");
+ BFD_ASSERT (s != NULL);
+ s->_raw_size = elf_hash_table (info)->dynstr->length;
+ s->contents = (unsigned char *) elf_hash_table (info)->dynstr->tab;
+
+ /* Find all symbols which were defined in a dynamic object and make
+ the backend pick a reasonable value for them. */
+ elf_link_hash_traverse (elf_hash_table (info),
+ elf_adjust_dynamic_symbol,
+ (PTR) info);
+
+ /* Add some entries to the .dynamic section. We fill in some of the
+ values later, in elf_bfd_final_link, but we must add the entries
+ now so that we know the final size of the .dynamic section. */
+ if (bfd_get_section_by_name (output_bfd, ".init") != NULL)
+ {
+ if (! elf_add_dynamic_entry (info, DT_INIT, 0))
+ return false;
+ }
+ if (bfd_get_section_by_name (output_bfd, ".fini") != NULL)
+ {
+ if (! elf_add_dynamic_entry (info, DT_FINI, 0))
+ return false;
+ }
+ if (! elf_add_dynamic_entry (info, DT_HASH, 0)
+ || ! elf_add_dynamic_entry (info, DT_STRTAB, 0)
+ || ! elf_add_dynamic_entry (info, DT_SYMTAB, 0)
+ || ! elf_add_dynamic_entry (info, DT_STRSZ,
+ elf_hash_table (info)->dynstr->length)
+ || ! elf_add_dynamic_entry (info, DT_SYMENT,
+ sizeof (Elf_External_Sym)))
+ return false;
+
+ /* The backend must work out the sizes of all the other dynamic
+ sections. */
+ bed = get_elf_backend_data (output_bfd);
+ if (! (*bed->elf_backend_size_dynamic_sections) (output_bfd, info))
+ return false;
+
+ return elf_add_dynamic_entry (info, DT_NULL, 0);
+}
+
+/* Make the backend pick a good value for a dynamic symbol. This is
+ called via elf_link_hash_traverse, and also calls itself
+ recursively. */
+
+static boolean
+elf_adjust_dynamic_symbol (h, data)
+ struct elf_link_hash_entry *h;
+ PTR data;
+{
+ struct bfd_link_info *info = (struct bfd_link_info *) data;
+ bfd *dynobj;
+ struct elf_backend_data *bed;
+
+ /* If this symbol is not defined by a dynamic object, or is not
+ referenced by a regular object, ignore it. FIXME: Do we need to
+ worry about symbols which are defined by one dynamic object and
+ referenced by another one? */
+ if ((h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) != 0
+ || (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC) == 0
+ || (h->elf_link_hash_flags & ELF_LINK_HASH_REF_REGULAR) == 0)
+ return true;
+
+ /* If we've already adjusted this symbol, don't do it again. This
+ can happen via a recursive call. */
+ if ((h->elf_link_hash_flags & ELF_LINK_HASH_DYNAMIC_ADJUSTED) != 0)
+ return true;
+
+ /* Don't look at this symbol again. Note that we must set this
+ after checking the above conditions, because we may look at a
+ symbol once, decide not to do anything, and then get called
+ recursively later after REF_REGULAR is set below. */
+ h->elf_link_hash_flags |= ELF_LINK_HASH_DYNAMIC_ADJUSTED;
+
+ /* If this is a weak definition, and we know a real definition, and
+ the real symbol is not itself defined by a regular object file,
+ then get a good value for the real definition. We handle the
+ real symbol first, for the convenience of the backend routine.
+
+ Note that there is a confusing case here. If the real definition
+ is defined by a regular object file, we don't get the real symbol
+ from the dynamic object, but we do get the weak symbol. If the
+ processor backend uses a COPY reloc, then if some routine in the
+ dynamic object changes the real symbol, we will not see that
+ change in the corresponding weak symbol. This is the way other
+ ELF linkers work as well, and seems to be a result of the shared
+ library model.
+
+ I will clarify this issue. Most SVR4 shared libraries define the
+ variable _timezone and define timezone as a weak synonym. The
+ tzset call changes _timezone. If you write
+ extern int timezone;
+ int _timezone = 5;
+ int main () { tzset (); printf ("%d %d\n", timezone, _timezone); }
+ you might expect that, since timezone is a synonym for _timezone,
+ the same number will print both times. However, if the processor
+ backend uses a COPY reloc, then actually timezone will be copied
+ into your process image, and, since you define _timezone
+ yourself, _timezone will not. Thus timezone and _timezone will
+ wind up at different memory locations. The tzset call will set
+ _timezone, leaving timezone unchanged. */
+
+ if (h->weakdef != NULL)
+ {
+ struct elf_link_hash_entry *weakdef;
+
+ BFD_ASSERT (h->root.type == bfd_link_hash_defined);
+ weakdef = h->weakdef;
+ BFD_ASSERT (weakdef->root.type == bfd_link_hash_defined);
+ BFD_ASSERT (weakdef->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC);
+ if ((weakdef->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) != 0
+ || (weakdef->elf_link_hash_flags & ELF_LINK_HASH_REF_REGULAR) == 0)
+ {
+ /* This symbol is defined or referenced by a regular object
+ file, so we will not do anything special. Clear weakdef
+ for the convenience of the processor backend. */
+ h->weakdef = NULL;
+ }
+ else
+ {
+ /* There is an implicit reference by a regular object file
+ via the weak symbol. */
+ weakdef->elf_link_hash_flags |= ELF_LINK_HASH_REF_REGULAR;
+ if (! elf_adjust_dynamic_symbol (weakdef, (PTR) info))
+ return false;
+ }
+ }
+
+ dynobj = elf_hash_table (info)->dynobj;
+ bed = get_elf_backend_data (dynobj);
+ if (! (*bed->elf_backend_adjust_dynamic_symbol) (info, h))
+ {
+ /* FIXME: No way to return error. */
+ abort ();
+ }
+
+ return true;
+}
+
+/* Final phase of ELF linker. */
+
+/* A structure we use to avoid passing large numbers of arguments. */
+
+struct elf_final_link_info
+{
+ /* General link information. */
+ struct bfd_link_info *info;
+ /* Output BFD. */
+ bfd *output_bfd;
+ /* Symbol string table. */
+ struct strtab *symstrtab;
+ /* .dynsym section. */
+ asection *dynsym_sec;
+ /* .hash section. */
+ asection *hash_sec;
+ /* Buffer large enough to hold contents of any section. */
+ bfd_byte *contents;
+ /* Buffer large enough to hold external relocs of any section. */
+ PTR external_relocs;
+ /* Buffer large enough to hold internal relocs of any section. */
+ Elf_Internal_Rela *internal_relocs;
+ /* Buffer large enough to hold external local symbols of any input
+ BFD. */
+ Elf_External_Sym *external_syms;
+ /* Buffer large enough to hold internal local symbols of any input
+ BFD. */
+ Elf_Internal_Sym *internal_syms;
+ /* Array large enough to hold a symbol index for each local symbol
+ of any input BFD. */
+ long *indices;
+ /* Array large enough to hold a section pointer for each local
+ symbol of any input BFD. */
+ asection **sections;
+ /* Buffer to hold swapped out symbols. */
+ Elf_External_Sym *symbuf;
+ /* Number of swapped out symbols in buffer. */
+ size_t symbuf_count;
+ /* Number of symbols which fit in symbuf. */
+ size_t symbuf_size;
+};
+
+static boolean elf_link_output_sym
+ PARAMS ((struct elf_final_link_info *, const char *,
+ Elf_Internal_Sym *, asection *));
+static boolean elf_link_flush_output_syms
+ PARAMS ((struct elf_final_link_info *));
+static boolean elf_link_output_extsym
+ PARAMS ((struct elf_link_hash_entry *, PTR));
+static boolean elf_link_input_bfd
+ PARAMS ((struct elf_final_link_info *, bfd *));
+static boolean elf_reloc_link_order
+ PARAMS ((bfd *, struct bfd_link_info *, asection *,
+ struct bfd_link_order *));
+
+/* Do the final step of an ELF link. */
+
+boolean
+elf_bfd_final_link (abfd, info)
+ bfd *abfd;
+ struct bfd_link_info *info;
+{
+ bfd *dynobj;
+ struct elf_final_link_info finfo;
+ register asection *o;
+ register struct bfd_link_order *p;
+ register bfd *sub;
+ size_t max_contents_size;
+ size_t max_external_reloc_size;
+ size_t max_internal_reloc_count;
+ size_t max_sym_count;
+ file_ptr off;
+ Elf_Internal_Sym elfsym;
+ unsigned int i;
+ Elf_Internal_Shdr *symtab_hdr;
+ Elf_Internal_Shdr *symstrtab_hdr;
+ struct elf_backend_data *bed = get_elf_backend_data (abfd);
+
+ if (info->shared)
+ {
+ fprintf (stderr,
+ "Generating ELF shared libraries is not yet supported\n");
+ bfd_set_error (bfd_error_invalid_operation);
+ return false;
+ }
+
+ dynobj = elf_hash_table (info)->dynobj;
+
+ finfo.info = info;
+ finfo.output_bfd = abfd;
+ finfo.symstrtab = bfd_new_strtab (abfd);
+ if (finfo.symstrtab == NULL)
+ return false;
+ if (dynobj == NULL)
+ {
+ finfo.dynsym_sec = NULL;
+ finfo.hash_sec = NULL;
+ }
+ else
+ {
+ finfo.dynsym_sec = bfd_get_section_by_name (dynobj, ".dynsym");
+ finfo.hash_sec = bfd_get_section_by_name (dynobj, ".hash");
+ if (finfo.dynsym_sec == NULL
+ || finfo.hash_sec == NULL)
+ abort ();
+ }
+ finfo.contents = NULL;
+ finfo.external_relocs = NULL;
+ finfo.internal_relocs = NULL;
+ finfo.external_syms = NULL;
+ finfo.internal_syms = NULL;
+ finfo.indices = NULL;
+ finfo.sections = NULL;
+ finfo.symbuf = NULL;
+ finfo.symbuf_count = 0;
+
+ /* Count up the number of relocations we will output for each output
+ section, so that we know the sizes of the reloc sections. We
+ also figure out some maximum sizes. */
+ max_contents_size = 0;
+ max_external_reloc_size = 0;
+ max_internal_reloc_count = 0;
+ max_sym_count = 0;
+ for (o = abfd->sections; o != (asection *) NULL; o = o->next)
+ {
+ o->reloc_count = 0;
+
+ for (p = o->link_order_head; p != NULL; p = p->next)
+ {
+ if (p->type == bfd_section_reloc_link_order
+ || p->type == bfd_symbol_reloc_link_order)
+ ++o->reloc_count;
+ else if (p->type == bfd_indirect_link_order)
+ {
+ asection *sec;
+
+ sec = p->u.indirect.section;
+
+ if (info->relocateable)
+ o->reloc_count += sec->reloc_count;
+
+ if (sec->_raw_size > max_contents_size)
+ max_contents_size = sec->_raw_size;
+ if (sec->_cooked_size > max_contents_size)
+ max_contents_size = sec->_cooked_size;
+
+ /* We are interested in just local symbols, not all
+ symbols. */
+ if (bfd_get_flavour (sec->owner) == bfd_target_elf_flavour)
+ {
+ size_t sym_count;
+
+ if (elf_bad_symtab (sec->owner))
+ sym_count = (elf_tdata (sec->owner)->symtab_hdr.sh_size
+ / sizeof (Elf_External_Sym));
+ else
+ sym_count = elf_tdata (sec->owner)->symtab_hdr.sh_info;
+
+ if (sym_count > max_sym_count)
+ max_sym_count = sym_count;
+
+ if ((sec->flags & SEC_RELOC) != 0)
+ {
+ size_t ext_size;
+
+ ext_size = elf_section_data (sec)->rel_hdr.sh_size;
+ if (ext_size > max_external_reloc_size)
+ max_external_reloc_size = ext_size;
+ if (sec->reloc_count > max_internal_reloc_count)
+ max_internal_reloc_count = sec->reloc_count;
+ }
+ }
+ }
+ }
+
+ if (o->reloc_count > 0)
+ o->flags |= SEC_RELOC;
+ else
+ {
+ /* Explicitly clear the SEC_RELOC flag. The linker tends to
+ set it (this is probably a bug) and if it is set
+ assign_section_numbers will create a reloc section. */
+ o->flags &=~ SEC_RELOC;
+ }
+ }
+
+ /* Figure out the file positions for everything but the symbol table
+ and the relocs. We set symcount to force assign_section_numbers
+ to create a symbol table. */
+ abfd->symcount = info->strip == strip_all ? 0 : 1;
+ BFD_ASSERT (! abfd->output_has_begun);
+ if (! elf_compute_section_file_positions (abfd, info))
+ goto error_return;
+
+ /* That created the reloc sections. Set their sizes, and assign
+ them file positions, and allocate some buffers. */
+ for (o = abfd->sections; o != NULL; o = o->next)
+ {
+ if ((o->flags & SEC_RELOC) != 0)
+ {
+ Elf_Internal_Shdr *rel_hdr;
+ register struct elf_link_hash_entry **p, **pend;
+
+ rel_hdr = &elf_section_data (o)->rel_hdr;
+
+ rel_hdr->sh_size = rel_hdr->sh_entsize * o->reloc_count;
+
+ /* The contents field must last into write_object_contents,
+ so we allocate it with bfd_alloc rather than malloc. */
+ rel_hdr->contents = (PTR) bfd_alloc (abfd, rel_hdr->sh_size);
+ if (rel_hdr->contents == NULL && rel_hdr->sh_size != 0)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ goto error_return;
+ }
+
+ p = ((struct elf_link_hash_entry **)
+ malloc (o->reloc_count
+ * sizeof (struct elf_link_hash_entry *)));
+ if (p == NULL && o->reloc_count != 0)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ goto error_return;
+ }
+ elf_section_data (o)->rel_hashes = p;
+ pend = p + o->reloc_count;
+ for (; p < pend; p++)
+ *p = NULL;
+
+ /* Use the reloc_count field as an index when outputting the
+ relocs. */
+ o->reloc_count = 0;
+ }
+ }
+
+ assign_file_positions_for_relocs (abfd);
+
+ /* We have now assigned file positions for all the sections except
+ .symtab and .strtab. We start the .symtab section at the current
+ file position, and write directly to it. We build the .strtab
+ section in memory. When we add .dynsym support, we will build
+ that in memory as well (.dynsym is smaller than .symtab). */
+ abfd->symcount = 0;
+ symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
+ /* sh_name is set in prep_headers. */
+ symtab_hdr->sh_type = SHT_SYMTAB;
+ symtab_hdr->sh_flags = 0;
+ symtab_hdr->sh_addr = 0;
+ symtab_hdr->sh_size = 0;
+ symtab_hdr->sh_entsize = sizeof (Elf_External_Sym);
+ /* sh_link is set in assign_section_numbers. */
+ /* sh_info is set below. */
+ /* sh_offset is set just below. */
+ symtab_hdr->sh_addralign = 4; /* FIXME: system dependent? */
+
+ off = elf_tdata (abfd)->next_file_pos;
+ off = assign_file_position_for_section (symtab_hdr, off, true);
+
+ /* Note that at this point elf_tdata (abfd)->next_file_pos is
+ incorrect. We do not yet know the size of the .symtab section.
+ We correct next_file_pos below, after we do know the size. */
+
+ /* Allocate a buffer to hold swapped out symbols. This is to avoid
+ continuously seeking to the right position in the file. */
+ if (! info->keep_memory || max_sym_count < 20)
+ finfo.symbuf_size = 20;
+ else
+ finfo.symbuf_size = max_sym_count;
+ finfo.symbuf = ((Elf_External_Sym *)
+ malloc (finfo.symbuf_size * sizeof (Elf_External_Sym)));
+ if (finfo.symbuf == NULL)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ goto error_return;
+ }
+
+ /* Start writing out the symbol table. The first symbol is always a
+ dummy symbol. */
+ elfsym.st_value = 0;
+ elfsym.st_size = 0;
+ elfsym.st_info = 0;
+ elfsym.st_other = 0;
+ elfsym.st_shndx = SHN_UNDEF;
+ if (! elf_link_output_sym (&finfo, (const char *) NULL,
+ &elfsym, bfd_und_section_ptr))
+ goto error_return;
+
+#if 0
+ /* Some standard ELF linkers do this, but we don't because it causes
+ bootstrap comparison failures. */
+ /* Output a file symbol for the output file as the second symbol.
+ We output this even if we are discarding local symbols, although
+ I'm not sure if this is correct. */
+ elfsym.st_value = 0;
+ elfsym.st_size = 0;
+ elfsym.st_info = ELF_ST_INFO (STB_LOCAL, STT_FILE);
+ elfsym.st_other = 0;
+ elfsym.st_shndx = SHN_ABS;
+ if (! elf_link_output_sym (&finfo, bfd_get_filename (abfd),
+ &elfsym, bfd_abs_section_ptr))
+ goto error_return;
+#endif
+
+ /* Output a symbol for each section. We output these even if we are
+ discarding local symbols, since they are used for relocs. These
+ symbols have no names. We store the index of each one in the
+ index field of the section, so that we can find it again when
+ outputting relocs. */
+ elfsym.st_value = 0;
+ elfsym.st_size = 0;
+ elfsym.st_info = ELF_ST_INFO (STB_LOCAL, STT_SECTION);
+ elfsym.st_other = 0;
+ for (i = 1; i < elf_elfheader (abfd)->e_shnum; i++)
+ {
+ o = section_from_elf_index (abfd, i);
+ if (! bfd_is_abs_section (o))
+ o->target_index = abfd->symcount;
+ elfsym.st_shndx = i;
+ if (! elf_link_output_sym (&finfo, (const char *) NULL,
+ &elfsym, o))
+ goto error_return;
+ }
+
+ /* Allocate some memory to hold information read in from the input
+ files. */
+ finfo.contents = (bfd_byte *) malloc (max_contents_size);
+ finfo.external_relocs = (PTR) malloc (max_external_reloc_size);
+ finfo.internal_relocs = ((Elf_Internal_Rela *)
+ malloc (max_internal_reloc_count
+ * sizeof (Elf_Internal_Rela)));
+ finfo.external_syms = ((Elf_External_Sym *)
+ malloc (max_sym_count * sizeof (Elf_External_Sym)));
+ finfo.internal_syms = ((Elf_Internal_Sym *)
+ malloc (max_sym_count * sizeof (Elf_Internal_Sym)));
+ finfo.indices = (long *) malloc (max_sym_count * sizeof (long));
+ finfo.sections = (asection **) malloc (max_sym_count * sizeof (asection *));
+ if ((finfo.contents == NULL && max_contents_size != 0)
+ || (finfo.external_relocs == NULL && max_external_reloc_size != 0)
+ || (finfo.internal_relocs == NULL && max_internal_reloc_count != 0)
+ || (finfo.external_syms == NULL && max_sym_count != 0)
+ || (finfo.internal_syms == NULL && max_sym_count != 0)
+ || (finfo.indices == NULL && max_sym_count != 0)
+ || (finfo.sections == NULL && max_sym_count != 0))
+ {
+ bfd_set_error (bfd_error_no_memory);
+ goto error_return;
+ }
+
+ /* Since ELF permits relocations to be against local symbols, we
+ must have the local symbols available when we do the relocations.
+ Since we would rather only read the local symbols once, and we
+ would rather not keep them in memory, we handle all the
+ relocations for a single input file at the same time.
+
+ Unfortunately, there is no way to know the total number of local
+ symbols until we have seen all of them, and the local symbol
+ indices precede the global symbol indices. This means that when
+ we are generating relocateable output, and we see a reloc against
+ a global symbol, we can not know the symbol index until we have
+ finished examining all the local symbols to see which ones we are
+ going to output. To deal with this, we keep the relocations in
+ memory, and don't output them until the end of the link. This is
+ an unfortunate waste of memory, but I don't see a good way around
+ it. Fortunately, it only happens when performing a relocateable
+ link, which is not the common case. FIXME: If keep_memory is set
+ we could write the relocs out and then read them again; I don't
+ know how bad the memory loss will be. */
+
+ for (sub = info->input_bfds; sub != NULL; sub = sub->next)
+ sub->output_has_begun = false;
+ for (o = abfd->sections; o != NULL; o = o->next)
+ {
+ for (p = o->link_order_head; p != NULL; p = p->next)
+ {
+ if (p->type == bfd_indirect_link_order
+ && (bfd_get_flavour (p->u.indirect.section->owner)
+ == bfd_target_elf_flavour))
+ {
+ sub = p->u.indirect.section->owner;
+ if (! sub->output_has_begun)
+ {
+ if (! elf_link_input_bfd (&finfo, sub))
+ goto error_return;
+ sub->output_has_begun = true;
+ }
+ }
+ else if (p->type == bfd_section_reloc_link_order
+ || p->type == bfd_symbol_reloc_link_order)
+ {
+ if (! elf_reloc_link_order (abfd, info, o, p))
+ goto error_return;
+ }
+ else
+ {
+ if (! _bfd_default_link_order (abfd, info, o, p))
+ goto error_return;
+ }
+ }
+ }
+
+ /* That wrote out all the local symbols. Finish up the symbol table
+ with the global symbols. */
+
+ /* The sh_info field records the index of the first non local
+ symbol. */
+ symtab_hdr->sh_info = abfd->symcount;
+ if (dynobj != NULL)
+ elf_section_data (finfo.dynsym_sec->output_section)->this_hdr.sh_info = 1;
+
+ /* We get the global symbols from the hash table. */
+ elf_link_hash_traverse (elf_hash_table (info), elf_link_output_extsym,
+ (PTR) &finfo);
+
+ /* Flush all symbols to the file. */
+ if (! elf_link_flush_output_syms (&finfo))
+ return false;
+
+ /* Now we know the size of the symtab section. */
+ off += symtab_hdr->sh_size;
+
+ /* Finish up the symbol string table (.strtab) section. */
+ symstrtab_hdr = &elf_tdata (abfd)->strtab_hdr;
+ /* sh_name was set in prep_headers. */
+ symstrtab_hdr->sh_type = SHT_STRTAB;
+ symstrtab_hdr->sh_flags = 0;
+ symstrtab_hdr->sh_addr = 0;
+ symstrtab_hdr->sh_size = finfo.symstrtab->length;
+ symstrtab_hdr->sh_entsize = 0;
+ symstrtab_hdr->sh_link = 0;
+ symstrtab_hdr->sh_info = 0;
+ /* sh_offset is set just below. */
+ symstrtab_hdr->sh_addralign = 1;
+ symstrtab_hdr->contents = (PTR) finfo.symstrtab->tab;
+
+ off = assign_file_position_for_section (symstrtab_hdr, off, true);
+ elf_tdata (abfd)->next_file_pos = off;
+
+ /* Adjust the relocs to have the correct symbol indices. */
+ for (o = abfd->sections; o != NULL; o = o->next)
+ {
+ struct elf_link_hash_entry **rel_hash;
+ Elf_Internal_Shdr *rel_hdr;
+
+ if ((o->flags & SEC_RELOC) == 0)
+ continue;
+
+ rel_hash = elf_section_data (o)->rel_hashes;
+ rel_hdr = &elf_section_data (o)->rel_hdr;
+ for (i = 0; i < o->reloc_count; i++, rel_hash++)
+ {
+ if (*rel_hash == NULL)
+ continue;
+
+ BFD_ASSERT ((*rel_hash)->indx >= 0);
+
+ if (rel_hdr->sh_entsize == sizeof (Elf_External_Rel))
+ {
+ Elf_External_Rel *erel;
+ Elf_Internal_Rel irel;
+
+ erel = (Elf_External_Rel *) rel_hdr->contents + i;
+ elf_swap_reloc_in (abfd, erel, &irel);
+ irel.r_info = ELF_R_INFO ((*rel_hash)->indx,
+ ELF_R_TYPE (irel.r_info));
+ elf_swap_reloc_out (abfd, &irel, erel);
+ }
+ else
+ {
+ Elf_External_Rela *erela;
+ Elf_Internal_Rela irela;
+
+ BFD_ASSERT (rel_hdr->sh_entsize
+ == sizeof (Elf_External_Rela));
+
+ erela = (Elf_External_Rela *) rel_hdr->contents + i;
+ elf_swap_reloca_in (abfd, erela, &irela);
+ irela.r_info = ELF_R_INFO ((*rel_hash)->indx,
+ ELF_R_TYPE (irela.r_info));
+ elf_swap_reloca_out (abfd, &irela, erela);
+ }
+ }
+
+ /* Set the reloc_count field to 0 to prevent write_relocs from
+ trying to swap the relocs out itself. */
+ o->reloc_count = 0;
+ }
+
+ /* If we are linking against a dynamic object, finish up the dynamic
+ linking information. */
+ if (dynobj != NULL)
+ {
+ Elf_External_Dyn *dyncon, *dynconend;
+
+ /* Fix up .dynamic entries. */
+ o = bfd_get_section_by_name (dynobj, ".dynamic");
+ BFD_ASSERT (o != NULL);
+
+ dyncon = (Elf_External_Dyn *) o->contents;
+ dynconend = (Elf_External_Dyn *) (o->contents + o->_raw_size);
+ for (; dyncon < dynconend; dyncon++)
+ {
+ Elf_Internal_Dyn dyn;
+ const char *name;
+ unsigned int type;
+
+ elf_swap_dyn_in (dynobj, dyncon, &dyn);
+
+ switch (dyn.d_tag)
+ {
+ default:
+ break;
+
+ case DT_INIT:
+ name = ".init";
+ goto get_vma;
+ case DT_FINI:
+ name = ".fini";
+ goto get_vma;
+ case DT_HASH:
+ name = ".hash";
+ goto get_vma;
+ case DT_STRTAB:
+ name = ".dynstr";
+ goto get_vma;
+ case DT_SYMTAB:
+ name = ".dynsym";
+ get_vma:
+ o = bfd_get_section_by_name (abfd, name);
+ BFD_ASSERT (o != NULL);
+ dyn.d_un.d_ptr = o->vma;
+ elf_swap_dyn_out (dynobj, &dyn, dyncon);
+ break;
+
+ case DT_REL:
+ case DT_RELA:
+ case DT_RELSZ:
+ case DT_RELASZ:
+ if (dyn.d_tag == DT_REL || dyn.d_tag == DT_RELSZ)
+ type = SHT_REL;
+ else
+ type = SHT_RELA;
+ dyn.d_un.d_val = 0;
+ for (i = 1; i < elf_elfheader (abfd)->e_shnum; i++)
+ {
+ Elf_Internal_Shdr *hdr;
+
+ hdr = elf_elfsections (abfd)[i];
+ if (hdr->sh_type == type
+ && (hdr->sh_flags & SHF_ALLOC) != 0)
+ {
+ if (dyn.d_tag == DT_RELSZ || dyn.d_tag == DT_RELASZ)
+ dyn.d_un.d_val += hdr->sh_size;
+ else
+ {
+ if (dyn.d_un.d_val == 0
+ || hdr->sh_addr < dyn.d_un.d_val)
+ dyn.d_un.d_val = hdr->sh_addr;
+ }
+ }
+ }
+ elf_swap_dyn_out (dynobj, &dyn, dyncon);
+ break;
+ }
+ }
+
+ if (! (*bed->elf_backend_finish_dynamic_sections) (abfd, info))
+ goto error_return;
+
+ for (o = dynobj->sections; o != NULL; o = o->next)
+ {
+ if ((o->flags & SEC_HAS_CONTENTS) == 0)
+ continue;
+ if ((o->flags & SEC_IN_MEMORY) == 0)
+ {
+ BFD_ASSERT (info->shared);
+ continue;
+ }
+ if (! bfd_set_section_contents (abfd, o->output_section,
+ o->contents, o->output_offset,
+ o->_raw_size))
+ goto error_return;
+ }
+ }
+
+ /* Now backend stuff. */
+ if (bed->elf_backend_final_write_processing)
+ (*bed->elf_backend_final_write_processing) (abfd, NULL);
+
+ if (finfo.contents != NULL)
+ free (finfo.contents);
+ if (finfo.external_relocs != NULL)
+ free (finfo.external_relocs);
+ if (finfo.internal_relocs != NULL)
+ free (finfo.internal_relocs);
+ if (finfo.external_syms != NULL)
+ free (finfo.external_syms);
+ if (finfo.internal_syms != NULL)
+ free (finfo.internal_syms);
+ if (finfo.indices != NULL)
+ free (finfo.indices);
+ if (finfo.sections != NULL)
+ free (finfo.sections);
+ if (finfo.symbuf != NULL)
+ free (finfo.symbuf);
+ for (o = abfd->sections; o != NULL; o = o->next)
+ {
+ if ((o->flags & SEC_RELOC) != 0
+ && elf_section_data (o)->rel_hashes != NULL)
+ free (elf_section_data (o)->rel_hashes);
+ }
+
+ return true;
+
+ error_return:
+ if (finfo.contents != NULL)
+ free (finfo.contents);
+ if (finfo.external_relocs != NULL)
+ free (finfo.external_relocs);
+ if (finfo.internal_relocs != NULL)
+ free (finfo.internal_relocs);
+ if (finfo.external_syms != NULL)
+ free (finfo.external_syms);
+ if (finfo.internal_syms != NULL)
+ free (finfo.internal_syms);
+ if (finfo.indices != NULL)
+ free (finfo.indices);
+ if (finfo.sections != NULL)
+ free (finfo.sections);
+ if (finfo.symbuf != NULL)
+ free (finfo.symbuf);
+ for (o = abfd->sections; o != NULL; o = o->next)
+ {
+ if ((o->flags & SEC_RELOC) != 0
+ && elf_section_data (o)->rel_hashes != NULL)
+ free (elf_section_data (o)->rel_hashes);
+ }
+
+ return false;
+}
+
+/* Add a symbol to the output symbol table. */
+
+static boolean
+elf_link_output_sym (finfo, name, elfsym, input_sec)
+ struct elf_final_link_info *finfo;
+ const char *name;
+ Elf_Internal_Sym *elfsym;
+ asection *input_sec;
+{
+ boolean (*output_symbol_hook) PARAMS ((bfd *,
+ struct bfd_link_info *info,
+ const char *,
+ Elf_Internal_Sym *,
+ asection *));
+
+ output_symbol_hook = get_elf_backend_data (finfo->output_bfd)->
+ elf_backend_link_output_symbol_hook;
+ if (output_symbol_hook != NULL)
+ {
+ if (! ((*output_symbol_hook)
+ (finfo->output_bfd, finfo->info, name, elfsym, input_sec)))
+ return false;
+ }
+
+ if (name == (const char *) NULL || *name == '\0')
+ elfsym->st_name = 0;
+ else
+ {
+ elfsym->st_name = bfd_add_to_strtab (finfo->output_bfd,
+ finfo->symstrtab, name);
+ if (elfsym->st_name == (unsigned long) -1)
+ return false;
+ }
+
+ if (finfo->symbuf_count >= finfo->symbuf_size)
+ {
+ if (! elf_link_flush_output_syms (finfo))
+ return false;
+ }
+
+ elf_swap_symbol_out (finfo->output_bfd, elfsym,
+ finfo->symbuf + finfo->symbuf_count);
+ ++finfo->symbuf_count;
+
+ ++finfo->output_bfd->symcount;
+
+ return true;
+}
+
+/* Flush the output symbols to the file. */
+
+static boolean
+elf_link_flush_output_syms (finfo)
+ struct elf_final_link_info *finfo;
+{
+ Elf_Internal_Shdr *symtab;
+
+ symtab = &elf_tdata (finfo->output_bfd)->symtab_hdr;
+
+ if (bfd_seek (finfo->output_bfd, symtab->sh_offset + symtab->sh_size,
+ SEEK_SET) != 0
+ || (bfd_write ((PTR) finfo->symbuf, finfo->symbuf_count,
+ sizeof (Elf_External_Sym), finfo->output_bfd)
+ != finfo->symbuf_count * sizeof (Elf_External_Sym)))
+ return false;
+
+ symtab->sh_size += finfo->symbuf_count * sizeof (Elf_External_Sym);
+
+ finfo->symbuf_count = 0;
+
+ return true;
+}
+
+/* Add an external symbol to the symbol table. This is called from
+ the hash table traversal routine. */
+
+static boolean
+elf_link_output_extsym (h, data)
+ struct elf_link_hash_entry *h;
+ PTR data;
+{
+ struct elf_final_link_info *finfo = (struct elf_final_link_info *) data;
+ boolean strip;
+ Elf_Internal_Sym sym;
+ asection *input_sec;
+
+ /* We don't want to output symbols that have never been mentioned by
+ a regular file, or that we have been told to strip. However, if
+ h->indx is set to -2, the symbol is used by a reloc and we must
+ output it. */
+ if (h->indx == -2)
+ strip = false;
+ else if (((h->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC) != 0
+ || (h->elf_link_hash_flags & ELF_LINK_HASH_REF_DYNAMIC) != 0)
+ && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0
+ && (h->elf_link_hash_flags & ELF_LINK_HASH_REF_REGULAR) == 0)
+ strip = true;
+ else if (finfo->info->strip == strip_all
+ || (finfo->info->strip == strip_some
+ && bfd_hash_lookup (finfo->info->keep_hash,
+ h->root.root.string,
+ false, false) == NULL))
+ strip = true;
+ else
+ strip = false;
+
+ /* If we're stripping it, and it's not a dynamic symbol, there's
+ nothing else to do. */
+ if (strip && h->dynindx == -1)
+ return true;
+
+ sym.st_value = 0;
+ sym.st_size = h->size;
+ sym.st_other = 0;
+ if (h->root.type == bfd_link_hash_weak
+ || (h->elf_link_hash_flags & ELF_LINK_HASH_DEFINED_WEAK) != 0)
+ sym.st_info = ELF_ST_INFO (STB_WEAK, h->type);
+ else
+ sym.st_info = ELF_ST_INFO (STB_GLOBAL, h->type);
+
+ switch (h->root.type)
+ {
+ default:
+ case bfd_link_hash_new:
+ abort ();
+ return false;
+
+ case bfd_link_hash_undefined:
+ input_sec = bfd_und_section_ptr;
+ sym.st_shndx = SHN_UNDEF;
+ break;
+
+ case bfd_link_hash_weak:
+ input_sec = bfd_und_section_ptr;
+ sym.st_shndx = SHN_UNDEF;
+ break;
+
+ case bfd_link_hash_defined:
+ {
+
+ input_sec = h->root.u.def.section;
+ if (input_sec->output_section != NULL)
+ {
+ sym.st_shndx = elf_section_from_bfd_section (finfo->output_bfd,
+ input_sec->output_section);
+ if (sym.st_shndx == (unsigned short) -1)
+ {
+ /* FIXME: No way to handle errors. */
+ abort ();
+ }
+
+ /* ELF symbols in relocateable files are section relative,
+ but in nonrelocateable files they are virtual
+ addresses. */
+ sym.st_value = h->root.u.def.value + input_sec->output_offset;
+ if (! finfo->info->relocateable)
+ sym.st_value += input_sec->output_section->vma;
+ }
+ else
+ {
+ BFD_ASSERT (bfd_get_flavour (input_sec->owner)
+ == bfd_target_elf_flavour
+ && elf_elfheader (input_sec->owner)->e_type == ET_DYN);
+ sym.st_shndx = SHN_UNDEF;
+ input_sec = bfd_und_section_ptr;
+ }
+ }
+ break;
+
+ case bfd_link_hash_common:
+ input_sec = bfd_com_section_ptr;
+ sym.st_shndx = SHN_COMMON;
+ if (h->align == 0)
+ sym.st_value = 1;
+ else
+ sym.st_value = h->align;
+ break;
+
+ case bfd_link_hash_indirect:
+ case bfd_link_hash_warning:
+ /* I have no idea how these should be handled. */
+ return true;
+ }
+
+ /* If this symbol should be put in the .dynsym section, then put it
+ there now. We have already know the symbol index. We also fill
+ in the entry in the .hash section. */
+ if (h->dynindx != -1)
+ {
+ struct elf_backend_data *bed;
+ size_t bucketcount;
+ size_t bucket;
+ bfd_byte *bucketpos;
+ bfd_vma chain;
+
+ sym.st_name = h->dynstr_index;
+
+ /* Give the processor backend a chance to tweak the symbol
+ value, and also to finish up anything that needs to be done
+ for this symbol. */
+ bed = get_elf_backend_data (finfo->output_bfd);
+ if (! ((*bed->elf_backend_finish_dynamic_symbol)
+ (finfo->output_bfd, finfo->info, h, &sym)))
+ {
+ /* FIXME: No way to return error. */
+ abort ();
+ }
+
+ elf_swap_symbol_out (finfo->output_bfd, &sym,
+ ((Elf_External_Sym *) finfo->dynsym_sec->contents
+ + h->dynindx));
+
+ bucketcount = elf_hash_table (finfo->info)->bucketcount;
+ bucket = bfd_elf_hash (h->root.root.string) % bucketcount;
+ bucketpos = ((bfd_byte *) finfo->hash_sec->contents
+ + (bucket + 2) * (ARCH_SIZE / 8));
+ chain = get_word (finfo->output_bfd, bucketpos);
+ put_word (finfo->output_bfd, h->dynindx, bucketpos);
+ put_word (finfo->output_bfd, chain,
+ ((bfd_byte *) finfo->hash_sec->contents
+ + (bucketcount + 2 + h->dynindx) * (ARCH_SIZE / 8)));
+ }
+
+ /* If we're stripping it, then it was just a dynamic symbol, and
+ there's nothing else to do. */
+ if (strip)
+ return true;
+
+ h->indx = finfo->output_bfd->symcount;
+
+ if (! elf_link_output_sym (finfo, h->root.root.string, &sym, input_sec))
+ {
+ /* FIXME: No way to return error. */
+ abort ();
+ }
+
+ return true;
+}
+
+/* Link an input file into the linker output file. This function
+ handles all the sections and relocations of the input file at once.
+ This is so that we only have to read the local symbols once, and
+ don't have to keep them in memory. */
+
+static boolean
+elf_link_input_bfd (finfo, input_bfd)
+ struct elf_final_link_info *finfo;
+ bfd *input_bfd;
+{
+ boolean (*relocate_section) PARAMS ((bfd *, struct bfd_link_info *,
+ bfd *, asection *, bfd_byte *,
+ Elf_Internal_Rela *,
+ Elf_Internal_Sym *,
+ asection **, char *));
+ bfd *output_bfd;
+ Elf_Internal_Shdr *symtab_hdr;
+ size_t locsymcount;
+ size_t extsymoff;
+ Elf_External_Sym *esym;
+ Elf_External_Sym *esymend;
+ Elf_Internal_Sym *isym;
+ long *pindex;
+ asection **ppsection;
+ asection *o;
+
+ output_bfd = finfo->output_bfd;
+ relocate_section =
+ get_elf_backend_data (output_bfd)->elf_backend_relocate_section;
+
+ /* If this is a dynamic object, we don't want to do anything here:
+ we don't want the local symbols, and we don't want the section
+ contents. */
+ if (elf_elfheader (input_bfd)->e_type == ET_DYN)
+ return true;
+
+ symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
+ if (elf_bad_symtab (input_bfd))
+ {
+ locsymcount = symtab_hdr->sh_size / sizeof (Elf_External_Sym);
+ extsymoff = 0;
+ }
+ else
+ {
+ locsymcount = symtab_hdr->sh_info;
+ extsymoff = symtab_hdr->sh_info;
+ }
+
+ /* Read the local symbols. */
+ if (locsymcount > 0
+ && (bfd_seek (input_bfd, symtab_hdr->sh_offset, SEEK_SET) != 0
+ || (bfd_read (finfo->external_syms, sizeof (Elf_External_Sym),
+ locsymcount, input_bfd)
+ != locsymcount * sizeof (Elf_External_Sym))))
+ return false;
+
+ /* Swap in the local symbols and write out the ones which we know
+ are going into the output file. */
+ esym = finfo->external_syms;
+ esymend = esym + locsymcount;
+ isym = finfo->internal_syms;
+ pindex = finfo->indices;
+ ppsection = finfo->sections;
+ for (; esym < esymend; esym++, isym++, pindex++, ppsection++)
+ {
+ asection *isec;
+ const char *name;
+ bfd_vma oldval;
+
+ elf_swap_symbol_in (input_bfd, esym, isym);
+ *pindex = -1;
+
+ if (elf_bad_symtab (input_bfd))
+ {
+ if (ELF_ST_BIND (isym->st_info) != STB_LOCAL)
+ {
+ *ppsection = NULL;
+ continue;
+ }
+ }
+
+ if (isym->st_shndx == SHN_UNDEF)
+ isec = bfd_und_section_ptr;
+ else if (isym->st_shndx > 0 && isym->st_shndx < SHN_LORESERVE)
+ {
+ isec = section_from_elf_index (input_bfd, isym->st_shndx);
+ if (isec == NULL)
+ return false;
+ }
+ else if (isym->st_shndx == SHN_ABS)
+ isec = bfd_abs_section_ptr;
+ else if (isym->st_shndx == SHN_COMMON)
+ isec = bfd_com_section_ptr;
+ else
+ {
+ /* Who knows? */
+ isec = NULL;
+ }
+
+ *ppsection = isec;
+
+ /* Don't output the first, undefined, symbol. */
+ if (esym == finfo->external_syms)
+ continue;
+
+ /* If we are stripping all symbols, we don't want to output this
+ one. */
+ if (finfo->info->strip == strip_all)
+ continue;
+
+ /* We never output section symbols. Instead, we use the section
+ symbol of the corresponding section in the output file. */
+ if (ELF_ST_TYPE (isym->st_info) == STT_SECTION)
+ continue;
+
+ /* If we are discarding all local symbols, we don't want to
+ output this one. If we are generating a relocateable output
+ file, then some of the local symbols may be required by
+ relocs; we output them below as we discover that they are
+ needed. */
+ if (finfo->info->discard == discard_all)
+ continue;
+
+ /* Get the name of the symbol. */
+ name = elf_string_from_elf_section (input_bfd, symtab_hdr->sh_link,
+ isym->st_name);
+ if (name == NULL)
+ return false;
+
+ /* See if we are discarding symbols with this name. */
+ if ((finfo->info->strip == strip_some
+ && (bfd_hash_lookup (finfo->info->keep_hash, name, false, false)
+ == NULL))
+ || (finfo->info->discard == discard_l
+ && strncmp (name, finfo->info->lprefix,
+ finfo->info->lprefix_len) == 0))
+ continue;
+
+ /* If we get here, we are going to output this symbol. */
+
+ /* Adjust the section index for the output file. */
+ isym->st_shndx = elf_section_from_bfd_section (output_bfd,
+ isec->output_section);
+ if (isym->st_shndx == (unsigned short) -1)
+ return false;
+
+ *pindex = output_bfd->symcount;
+
+ /* ELF symbols in relocateable files are section relative, but
+ in executable files they are virtual addresses. Note that
+ this code assumes that all ELF sections have an associated
+ BFD section with a reasonable value for output_offset; below
+ we assume that they also have a reasonable value for
+ output_section. Any special sections must be set up to meet
+ these requirements. */
+ oldval = isym->st_value;
+ isym->st_value += isec->output_offset;
+ if (! finfo->info->relocateable)
+ isym->st_value += isec->output_section->vma;
+
+ if (! elf_link_output_sym (finfo, name, isym, isec))
+ return false;
+
+ /* Restore the old value for reloc handling. */
+ isym->st_value = oldval;
+ }
+
+ /* Relocate the contents of each section. */
+ for (o = input_bfd->sections; o != NULL; o = o->next)
+ {
+ Elf_Internal_Shdr *input_rel_hdr;
+
+ if ((o->flags & SEC_HAS_CONTENTS) == 0)
+ continue;
+
+ if ((o->flags & SEC_IN_MEMORY) != 0
+ && input_bfd == elf_hash_table (finfo->info)->dynobj)
+ {
+ /* Section was created by elf_link_create_dynamic_sections.
+ FIXME: This test is fragile. */
+ continue;
+ }
+
+ /* Read the contents of the section. */
+ if (! bfd_get_section_contents (input_bfd, o, finfo->contents,
+ (file_ptr) 0, o->_raw_size))
+ return false;
+
+ if ((o->flags & SEC_RELOC) != 0)
+ {
+ PTR external_relocs;
+
+ /* Get the external relocs. They may have been cached. */
+ external_relocs = elf_section_data (o)->relocs;
+ if (external_relocs == NULL)
+ {
+ input_rel_hdr = &elf_section_data (o)->rel_hdr;
+ if ((bfd_seek (input_bfd, input_rel_hdr->sh_offset, SEEK_SET)
+ != 0)
+ || (bfd_read (finfo->external_relocs, 1,
+ input_rel_hdr->sh_size, input_bfd)
+ != input_rel_hdr->sh_size))
+ return false;
+ external_relocs = finfo->external_relocs;
+ }
+
+ /* Swap in the relocs. For convenience, we always produce
+ an Elf_Internal_Rela array; if the relocs are Rel, we set
+ the addend to 0. */
+ if (input_rel_hdr->sh_entsize == sizeof (Elf_External_Rel))
+ {
+ Elf_External_Rel *erel;
+ Elf_External_Rel *erelend;
+ Elf_Internal_Rela *irela;
+
+ erel = (Elf_External_Rel *) external_relocs;
+ erelend = erel + o->reloc_count;
+ irela = finfo->internal_relocs;
+ for (; erel < erelend; erel++, irela++)
+ {
+ Elf_Internal_Rel irel;
+
+ elf_swap_reloc_in (input_bfd, erel, &irel);
+ irela->r_offset = irel.r_offset;
+ irela->r_info = irel.r_info;
+ irela->r_addend = 0;
+ }
+ }
+ else
+ {
+ Elf_External_Rela *erela;
+ Elf_External_Rela *erelaend;
+ Elf_Internal_Rela *irela;
+
+ BFD_ASSERT (input_rel_hdr->sh_entsize
+ == sizeof (Elf_External_Rela));
+
+ erela = (Elf_External_Rela *) external_relocs;
+ erelaend = erela + o->reloc_count;
+ irela = finfo->internal_relocs;
+ for (; erela < erelaend; erela++, irela++)
+ elf_swap_reloca_in (input_bfd, erela, irela);
+ }
+
+ /* Relocate the section by invoking a back end routine.
+
+ The back end routine is responsible for adjusting the
+ section contents as necessary, and (if using Rela relocs
+ and generating a relocateable output file) adjusting the
+ reloc addend as necessary.
+
+ The back end routine does not have to worry about setting
+ the reloc address or the reloc symbol index.
+
+ The back end routine is given a pointer to the swapped in
+ internal symbols, and can access the hash table entries
+ for the external symbols via elf_sym_hashes (input_bfd).
+
+ When generating relocateable output, the back end routine
+ must handle STB_LOCAL/STT_SECTION symbols specially. The
+ output symbol is going to be a section symbol
+ corresponding to the output section, which will require
+ the addend to be adjusted. */
+
+ if (! (*relocate_section) (output_bfd, finfo->info,
+ input_bfd, o,
+ finfo->contents,
+ finfo->internal_relocs,
+ finfo->internal_syms,
+ finfo->sections,
+ finfo->symstrtab->tab))
+ return false;
+
+ if (finfo->info->relocateable)
+ {
+ Elf_Internal_Rela *irela;
+ Elf_Internal_Rela *irelaend;
+ struct elf_link_hash_entry **rel_hash;
+ Elf_Internal_Shdr *output_rel_hdr;
+
+ /* Adjust the reloc addresses and symbol indices. */
+
+ irela = finfo->internal_relocs;
+ irelaend = irela + o->reloc_count;
+ rel_hash = (elf_section_data (o->output_section)->rel_hashes
+ + o->output_section->reloc_count);
+ for (; irela < irelaend; irela++, rel_hash++)
+ {
+ long r_symndx;
+ Elf_Internal_Sym *isym;
+ asection *sec;
+
+ irela->r_offset += o->output_offset;
+
+ r_symndx = ELF_R_SYM (irela->r_info);
+
+ if (r_symndx == 0)
+ continue;
+
+ if (r_symndx >= locsymcount
+ || (elf_bad_symtab (input_bfd)
+ && finfo->sections[r_symndx] == NULL))
+ {
+ long indx;
+
+ /* This is a reloc against a global symbol. We
+ have not yet output all the local symbols, so
+ we do not know the symbol index of any global
+ symbol. We set the rel_hash entry for this
+ reloc to point to the global hash table entry
+ for this symbol. The symbol index is then
+ set at the end of elf_bfd_final_link. */
+ indx = r_symndx - extsymoff;
+ *rel_hash = elf_sym_hashes (input_bfd)[indx];
+
+ /* Setting the index to -2 tells
+ elf_link_output_extsym that this symbol is
+ used by a reloc. */
+ BFD_ASSERT ((*rel_hash)->indx < 0);
+ (*rel_hash)->indx = -2;
+
+ continue;
+ }
+
+ /* This is a reloc against a local symbol. */
+
+ *rel_hash = NULL;
+ isym = finfo->internal_syms + r_symndx;
+ sec = finfo->sections[r_symndx];
+ if (ELF_ST_TYPE (isym->st_info) == STT_SECTION)
+ {
+ /* I suppose the backend ought to fill in the
+ section of any STT_SECTION symbol against a
+ processor specific section. */
+ if (sec != NULL && bfd_is_abs_section (sec))
+ r_symndx = 0;
+ else if (sec == NULL || sec->owner == NULL)
+ {
+ bfd_set_error (bfd_error_bad_value);
+ return false;
+ }
+ else
+ {
+ r_symndx = sec->output_section->target_index;
+ if (r_symndx == 0)
+ abort ();
+ }
+ }
+ else
+ {
+ if (finfo->indices[r_symndx] == -1)
+ {
+ unsigned long link;
+ const char *name;
+ asection *osec;
+
+ if (finfo->info->strip == strip_all)
+ {
+ /* You can't do ld -r -s. */
+ bfd_set_error (bfd_error_invalid_operation);
+ return false;
+ }
+
+ /* This symbol was skipped earlier, but
+ since it is needed by a reloc, we
+ must output it now. */
+ link = symtab_hdr->sh_link;
+ name = elf_string_from_elf_section (input_bfd,
+ link,
+ isym->st_name);
+ if (name == NULL)
+ return false;
+
+ osec = sec->output_section;
+ isym->st_shndx =
+ elf_section_from_bfd_section (output_bfd,
+ osec);
+ if (isym->st_shndx == (unsigned short) -1)
+ return false;
+
+ isym->st_value += sec->output_offset;
+ if (! finfo->info->relocateable)
+ isym->st_value += osec->vma;
+
+ finfo->indices[r_symndx] = output_bfd->symcount;
+
+ if (! elf_link_output_sym (finfo, name, isym, sec))
+ return false;
+ }
+
+ r_symndx = finfo->indices[r_symndx];
+ }
+
+ irela->r_info = ELF_R_INFO (r_symndx,
+ ELF_R_TYPE (irela->r_info));
+ }
+
+ /* Swap out the relocs. */
+ output_rel_hdr = &elf_section_data (o->output_section)->rel_hdr;
+ BFD_ASSERT (output_rel_hdr->sh_entsize
+ == input_rel_hdr->sh_entsize);
+ irela = finfo->internal_relocs;
+ irelaend = irela + o->reloc_count;
+ if (input_rel_hdr->sh_entsize == sizeof (Elf_External_Rel))
+ {
+ Elf_External_Rel *erel;
+
+ erel = ((Elf_External_Rel *) output_rel_hdr->contents
+ + o->output_section->reloc_count);
+ for (; irela < irelaend; irela++, erel++)
+ {
+ Elf_Internal_Rel irel;
+
+ irel.r_offset = irela->r_offset;
+ irel.r_info = irela->r_info;
+ BFD_ASSERT (irela->r_addend == 0);
+ elf_swap_reloc_out (output_bfd, &irel, erel);
+ }
+ }
+ else
+ {
+ Elf_External_Rela *erela;
+
+ BFD_ASSERT (input_rel_hdr->sh_entsize
+ == sizeof (Elf_External_Rela));
+ erela = ((Elf_External_Rela *) output_rel_hdr->contents
+ + o->output_section->reloc_count);
+ for (; irela < irelaend; irela++, erela++)
+ elf_swap_reloca_out (output_bfd, irela, erela);
+ }
+
+ o->output_section->reloc_count += o->reloc_count;
+ }
+ }
+
+ /* Write out the modified section contents. */
+ if (! bfd_set_section_contents (output_bfd, o->output_section,
+ finfo->contents, o->output_offset,
+ (o->_cooked_size != 0
+ ? o->_cooked_size
+ : o->_raw_size)))
+ return false;
+ }
+
+ return true;
+}
+
+/* Generate a reloc when linking an ELF file. This is a reloc
+ requested by the linker, and does come from any input file. This
+ is used to build constructor and destructor tables when linking
+ with -Ur. */
+
+static boolean
+elf_reloc_link_order (output_bfd, info, output_section, link_order)
+ bfd *output_bfd;
+ struct bfd_link_info *info;
+ asection *output_section;
+ struct bfd_link_order *link_order;
+{
+ const reloc_howto_type *howto;
+ long indx;
+ bfd_vma offset;
+ struct elf_link_hash_entry **rel_hash_ptr;
+ Elf_Internal_Shdr *rel_hdr;
+
+ howto = bfd_reloc_type_lookup (output_bfd, link_order->u.reloc.p->reloc);
+ if (howto == NULL)
+ {
+ bfd_set_error (bfd_error_bad_value);
+ return false;
+ }
+
+ /* If this is an inplace reloc, we must write the addend into the
+ object file. */
+ if (howto->partial_inplace
+ && link_order->u.reloc.p->addend != 0)
+ {
+ bfd_size_type size;
+ bfd_reloc_status_type rstat;
+ bfd_byte *buf;
+ boolean ok;
+
+ size = bfd_get_reloc_size (howto);
+ buf = (bfd_byte *) bfd_zmalloc (size);
+ if (buf == (bfd_byte *) NULL)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ return false;
+ }
+ rstat = _bfd_relocate_contents (howto, output_bfd,
+ link_order->u.reloc.p->addend, buf);
+ switch (rstat)
+ {
+ case bfd_reloc_ok:
+ break;
+ default:
+ case bfd_reloc_outofrange:
+ abort ();
+ case bfd_reloc_overflow:
+ if (! ((*info->callbacks->reloc_overflow)
+ (info,
+ (link_order->type == bfd_section_reloc_link_order
+ ? bfd_section_name (output_bfd,
+ link_order->u.reloc.p->u.section)
+ : link_order->u.reloc.p->u.name),
+ howto->name, link_order->u.reloc.p->addend,
+ (bfd *) NULL, (asection *) NULL, (bfd_vma) 0)))
+ {
+ free (buf);
+ return false;
+ }
+ break;
+ }
+ ok = bfd_set_section_contents (output_bfd, output_section, (PTR) buf,
+ (file_ptr) link_order->offset, size);
+ free (buf);
+ if (! ok)
+ return false;
+ }
+
+ /* Figure out the symbol index. */
+ rel_hash_ptr = (elf_section_data (output_section)->rel_hashes
+ + output_section->reloc_count);
+ if (link_order->type == bfd_section_reloc_link_order)
+ {
+ indx = link_order->u.reloc.p->u.section->target_index;
+ if (indx == 0)
+ abort ();
+ *rel_hash_ptr = NULL;
+ }
+ else
+ {
+ struct elf_link_hash_entry *h;
+
+ h = elf_link_hash_lookup (elf_hash_table (info),
+ link_order->u.reloc.p->u.name,
+ false, false, true);
+ if (h != NULL)
+ {
+ /* Setting the index to -2 tells elf_link_output_extsym that
+ this symbol is used by a reloc. */
+ h->indx = -2;
+ *rel_hash_ptr = h;
+ indx = 0;
+ }
+ else
+ {
+ if (! ((*info->callbacks->unattached_reloc)
+ (info, link_order->u.reloc.p->u.name, (bfd *) NULL,
+ (asection *) NULL, (bfd_vma) 0)))
+ return false;
+ indx = 0;
+ }
+ }
+
+ /* The address of a reloc is relative to the section in a
+ relocateable file, and is a virtual address in an executable
+ file. */
+ offset = link_order->offset;
+ if (! info->relocateable)
+ offset += output_section->vma;
+
+ rel_hdr = &elf_section_data (output_section)->rel_hdr;
+
+ if (rel_hdr->sh_type == SHT_REL)
+ {
+ Elf_Internal_Rel irel;
+ Elf_External_Rel *erel;
+
+ irel.r_offset = offset;
+ irel.r_info = ELF_R_INFO (indx, howto->type);
+ erel = ((Elf_External_Rel *) rel_hdr->contents
+ + output_section->reloc_count);
+ elf_swap_reloc_out (output_bfd, &irel, erel);
+ }
+ else
+ {
+ Elf_Internal_Rela irela;
+ Elf_External_Rela *erela;
+
+ irela.r_offset = offset;
+ irela.r_info = ELF_R_INFO (indx, howto->type);
+ irela.r_addend = link_order->u.reloc.p->addend;
+ erela = ((Elf_External_Rela *) rel_hdr->contents
+ + output_section->reloc_count);
+ elf_swap_reloca_out (output_bfd, &irela, erela);
+ }
+
+ ++output_section->reloc_count;
+
+ return true;
+}
diff --git a/gnu/usr.bin/gdb/bfd/format.c b/gnu/usr.bin/gdb/bfd/format.c
new file mode 100644
index 0000000..adee048
--- /dev/null
+++ b/gnu/usr.bin/gdb/bfd/format.c
@@ -0,0 +1,318 @@
+/* Generic BFD support for file formats.
+ Copyright (C) 1990, 91, 92, 93, 94 Free Software Foundation, Inc.
+ Written by Cygnus Support.
+
+This file is part of BFD, the Binary File Descriptor library.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/*
+SECTION
+ File formats
+
+ A format is a BFD concept of high level file contents type. The
+ formats supported by BFD are:
+
+ o <<bfd_object>>
+
+ The BFD may contain data, symbols, relocations and debug info.
+
+ o <<bfd_archive>>
+
+ The BFD contains other BFDs and an optional index.
+
+ o <<bfd_core>>
+
+ The BFD contains the result of an executable core dump.
+
+
+*/
+
+#include "bfd.h"
+#include "sysdep.h"
+#include "libbfd.h"
+
+/* IMPORT from targets.c. */
+extern const size_t _bfd_target_vector_entries;
+
+/*
+FUNCTION
+ bfd_check_format
+
+SYNOPSIS
+ boolean bfd_check_format(bfd *abfd, bfd_format format);
+
+DESCRIPTION
+ Verify if the file attached to the BFD @var{abfd} is compatible
+ with the format @var{format} (i.e., one of <<bfd_object>>,
+ <<bfd_archive>> or <<bfd_core>>).
+
+ If the BFD has been set to a specific target before the
+ call, only the named target and format combination is
+ checked. If the target has not been set, or has been set to
+ <<default>>, then all the known target backends is
+ interrogated to determine a match. If the default target
+ matches, it is used. If not, exactly one target must recognize
+ the file, or an error results.
+
+ The function returns <<true>> on success, otherwise <<false>>
+ with one of the following error codes:
+
+ o <<bfd_error_invalid_operation>> -
+ if <<format>> is not one of <<bfd_object>>, <<bfd_archive>> or
+ <<bfd_core>>.
+
+ o <<bfd_error_system_call>> -
+ if an error occured during a read - even some file mismatches
+ can cause bfd_error_system_calls.
+
+ o <<file_not_recognised>> -
+ none of the backends recognised the file format.
+
+ o <<bfd_error_file_ambiguously_recognized>> -
+ more than one backend recognised the file format.
+*/
+
+boolean
+bfd_check_format (abfd, format)
+ bfd *abfd;
+ bfd_format format;
+{
+ return bfd_check_format_matches (abfd, format, NULL);
+}
+
+/*
+FUNCTION
+ bfd_check_format_matches
+
+SYNOPSIS
+ boolean bfd_check_format_matches(bfd *abfd, bfd_format format, char ***matching);
+
+DESCRIPTION
+ Like <<bfd_check_format>>, except when it returns false with
+ <<bfd_errno>> set to <<bfd_error_file_ambiguously_recognized>>. In that
+ case, if @var{matching} is not NULL, it will be filled in with
+ a NULL-terminated list of the names of the formats that matched,
+ allocated with <<malloc>>.
+ Then the user may choose a format and try again.
+
+ When done with the list that @var{matching} points to, the caller
+ should free it.
+*/
+
+boolean
+bfd_check_format_matches (abfd, format, matching)
+ bfd *abfd;
+ bfd_format format;
+ char ***matching;
+{
+ const bfd_target * const *target, *save_targ, *right_targ;
+ char **matching_vector = NULL;
+ int match_count;
+
+ if (!bfd_read_p (abfd) ||
+ ((int)(abfd->format) < (int)bfd_unknown) ||
+ ((int)(abfd->format) >= (int)bfd_type_end)) {
+ bfd_set_error (bfd_error_invalid_operation);
+ return false;
+ }
+
+ if (abfd->format != bfd_unknown)
+ return (abfd->format == format)? true: false;
+
+
+ /* Since the target type was defaulted, check them
+ all in the hope that one will be uniquely recognized. */
+
+ save_targ = abfd->xvec;
+ match_count = 0;
+ if (matching)
+ {
+ matching_vector =
+ (char **) malloc (sizeof (char *) *
+ (_bfd_target_vector_entries + 1));
+ if (!matching_vector)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ return false;
+ }
+ matching_vector[0] = NULL;
+ *matching = matching_vector;
+ }
+ right_targ = 0;
+
+
+ /* presume the answer is yes */
+ abfd->format = format;
+
+ /* If the target type was explicitly specified, just check that target. */
+
+ if (!abfd->target_defaulted) {
+ if (bfd_seek (abfd, (file_ptr)0, SEEK_SET) != 0) /* rewind! */
+ return false;
+ right_targ = BFD_SEND_FMT (abfd, _bfd_check_format, (abfd));
+ if (right_targ) {
+ abfd->xvec = right_targ; /* Set the target as returned */
+ if (matching)
+ free (matching_vector);
+ return true; /* File position has moved, BTW */
+ }
+ }
+
+ for (target = bfd_target_vector; *target != NULL; target++) {
+ const bfd_target *temp;
+
+ abfd->xvec = *target; /* Change BFD's target temporarily */
+ if (bfd_seek (abfd, (file_ptr)0, SEEK_SET) != 0)
+ return false;
+ /* If _bfd_check_format neglects to set bfd_error, assume bfd_error_wrong_format.
+ We didn't used to even pay any attention to bfd_error, so I suspect
+ that some _bfd_check_format might have this problem. */
+ bfd_set_error (bfd_error_wrong_format);
+ temp = BFD_SEND_FMT (abfd, _bfd_check_format, (abfd));
+ if (temp) { /* This format checks out as ok! */
+ right_targ = temp;
+ if (matching)
+ {
+ matching_vector[match_count] = temp->name;
+ matching_vector[match_count + 1] = NULL;
+ }
+ match_count++;
+ /* If this is the default target, accept it, even if other targets
+ might match. People who want those other targets have to set
+ the GNUTARGET variable. */
+ if (temp == bfd_default_vector[0])
+ {
+ if (matching)
+ {
+ matching_vector[0] = temp->name;
+ matching_vector[1] = NULL;
+ }
+ match_count = 1;
+ break;
+ }
+#ifdef GNU960
+ /* Big- and little-endian b.out archives look the same, but it doesn't
+ * matter: there is no difference in their headers, and member file byte
+ * orders will (I hope) be handled appropriately by bfd. Ditto for big
+ * and little coff archives. And the 4 coff/b.out object formats are
+ * unambiguous. So accept the first match we find.
+ */
+ break;
+#endif
+ } else if (bfd_get_error () != bfd_error_wrong_format) {
+ abfd->xvec = save_targ;
+ abfd->format = bfd_unknown;
+ if (matching && bfd_get_error () != bfd_error_file_ambiguously_recognized)
+ free (matching_vector);
+ return false;
+ }
+ }
+
+ if (match_count == 1) {
+ abfd->xvec = right_targ; /* Change BFD's target permanently */
+ if (matching)
+ free (matching_vector);
+ return true; /* File position has moved, BTW */
+ }
+
+ abfd->xvec = save_targ; /* Restore original target type */
+ abfd->format = bfd_unknown; /* Restore original format */
+ if (match_count == 0)
+ {
+ bfd_set_error (bfd_error_file_not_recognized);
+ if (matching)
+ free (matching_vector);
+ }
+ else
+ bfd_set_error (bfd_error_file_ambiguously_recognized);
+ return false;
+}
+
+/*
+FUNCTION
+ bfd_set_format
+
+SYNOPSIS
+ boolean bfd_set_format(bfd *abfd, bfd_format format);
+
+DESCRIPTION
+ This function sets the file format of the BFD @var{abfd} to the
+ format @var{format}. If the target set in the BFD does not
+ support the format requested, the format is invalid, or the BFD
+ is not open for writing, then an error occurs.
+
+*/
+
+boolean
+bfd_set_format (abfd, format)
+ bfd *abfd;
+ bfd_format format;
+{
+
+ if (bfd_read_p (abfd) ||
+ ((int)abfd->format < (int)bfd_unknown) ||
+ ((int)abfd->format >= (int)bfd_type_end)) {
+ bfd_set_error (bfd_error_invalid_operation);
+ return false;
+ }
+
+ if (abfd->format != bfd_unknown)
+ return (abfd->format == format) ? true:false;
+
+ /* presume the answer is yes */
+ abfd->format = format;
+
+ if (!BFD_SEND_FMT (abfd, _bfd_set_format, (abfd))) {
+ abfd->format = bfd_unknown;
+ return false;
+ }
+
+ return true;
+}
+
+
+/*
+FUNCTION
+ bfd_format_string
+
+SYNOPSIS
+ CONST char *bfd_format_string(bfd_format format);
+
+DESCRIPTION
+ Return a pointer to a const string
+ <<invalid>>, <<object>>, <<archive>>, <<core>>, or <<unknown>>,
+ depending upon the value of @var{format}.
+*/
+
+CONST char *
+bfd_format_string (format)
+ bfd_format format;
+{
+ if (((int)format <(int) bfd_unknown)
+ || ((int)format >=(int) bfd_type_end))
+ return "invalid";
+
+ switch (format) {
+ case bfd_object:
+ return "object"; /* linker/assember/compiler output */
+ case bfd_archive:
+ return "archive"; /* object archive file */
+ case bfd_core:
+ return "core"; /* core dump */
+ default:
+ return "unknown";
+ }
+}
diff --git a/gnu/usr.bin/gdb/bfd/freebsd386.c b/gnu/usr.bin/gdb/bfd/freebsd386.c
new file mode 100644
index 0000000..3b2633cf
--- /dev/null
+++ b/gnu/usr.bin/gdb/bfd/freebsd386.c
@@ -0,0 +1,113 @@
+/* BFD back-end for i386 a.out binaries under BSD.
+ Copyright (C) 1990, 1991, 1992 Free Software Foundation, Inc.
+
+This file is part of BFD, the Binary File Descriptor library.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* This data should be correct for the format used under all the various
+ BSD ports for 386 machines. */
+
+#define BYTES_IN_WORD 4
+#define ARCH 32
+
+/* ZMAGIC files never have the header in the text. */
+#define N_HEADER_IN_TEXT(x) 0
+
+/* ZMAGIC files start at address 0. This does not apply to QMAGIC. */
+#define TEXT_START_ADDR 0
+
+#if 0
+#define PAGE_SIZE 4096
+#endif
+#define SEGMENT_SIZE PAGE_SIZE
+
+#define DEFAULT_ARCH bfd_arch_i386
+#define MACHTYPE_OK(mtype) ((mtype) == M_386 || (mtype) == M_386_NETBSD || (mtype) == M_UNKNOWN)
+
+#define MY(OP) CAT(freebsd386_,OP)
+#define TARGETNAME "a.out-freebsd-386"
+
+#define N_MAGIC(ex) \
+ ((ex).a_info & 0xffff)
+#define N_MACHTYPE(ex) \
+ ( (N_GETMAGIC_NET(ex) == ZMAGIC) ? N_GETMID_NET(ex) : \
+ ((ex).a_info >> 16) & 0x03ff )
+#define N_FLAGS(ex) \
+ ( (N_GETMAGIC_NET(ex) == ZMAGIC) ? N_GETFLAG_NET(ex) : \
+ ((ex).a_info >> 26) & 0x3f )
+#define N_SET_INFO(ex,mag,mid,flag) \
+ ( (ex).a_info = (((flag) & 0x3f) <<26) | (((mid) & 0x03ff) << 16) | \
+ ((mag) & 0xffff) )
+
+#define N_GETMAGIC_NET(ex) \
+ (ntohl((ex).a_info) & 0xffff)
+#define N_GETMID_NET(ex) \
+ ((ntohl((ex).a_info) >> 16) & 0x03ff)
+#define N_GETFLAG_NET(ex) \
+ ((ntohl((ex).a_info) >> 26) & 0x3f)
+#define N_SETMAGIC_NET(ex,mag,mid,flag) \
+ ( (ex).a_info = htonl( (((flag)&0x3f)<<26) | (((mid)&0x03ff)<<16) | \
+ (((mag)&0xffff)) ) )
+
+#include "bfd.h"
+#include "sysdep.h"
+#include "libbfd.h"
+#include "libaout.h"
+
+#define N_ALIGN(ex,x) \
+ (N_MAGIC(ex) == ZMAGIC || N_MAGIC(ex) == QMAGIC || \
+ N_GETMAGIC_NET(ex) == ZMAGIC || N_GETMAGIC_NET(ex) == QMAGIC ? \
+ ((x) + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1) : (x))
+
+/* Valid magic number check. */
+#define N_BADMAG(ex) \
+ (N_MAGIC(ex) != OMAGIC && N_MAGIC(ex) != NMAGIC && \
+ N_MAGIC(ex) != ZMAGIC && N_MAGIC(ex) != QMAGIC && \
+ N_GETMAGIC_NET(ex) != OMAGIC && N_GETMAGIC_NET(ex) != NMAGIC && \
+ N_GETMAGIC_NET(ex) != ZMAGIC && N_GETMAGIC_NET(ex) != QMAGIC)
+
+/* Address of the bottom of the text segment. */
+#define N_TXTADDR(ex) \
+ ((N_MAGIC(ex) == OMAGIC || N_MAGIC(ex) == NMAGIC || \
+ N_MAGIC(ex) == ZMAGIC) ? 0 : PAGE_SIZE)
+
+/* Address of the bottom of the data segment. */
+#define N_DATADDR(ex) \
+ N_ALIGN(ex, N_TXTADDR(ex) + (ex).a_text)
+
+/* Text segment offset. */
+#define N_TXTOFF(ex) \
+ (N_MAGIC(ex) == ZMAGIC ? PAGE_SIZE : (N_MAGIC(ex) == QMAGIC || \
+ N_GETMAGIC_NET(ex) == ZMAGIC) ? 0 : EXEC_BYTES_SIZE)
+
+/* Data segment offset. */
+#define N_DATOFF(ex) \
+ N_ALIGN(ex, N_TXTOFF(ex) + (ex).a_text)
+
+/* Relocation table offset. */
+#define N_RELOFF(ex) \
+ N_ALIGN(ex, N_DATOFF(ex) + (ex).a_data)
+
+/* Symbol table offset. */
+#define N_SYMOFF(ex) \
+ (N_RELOFF(ex) + (ex).a_trsize + (ex).a_drsize)
+
+/* String table offset. */
+#define N_STROFF(ex) (N_SYMOFF(ex) + (ex).a_syms)
+
+#define NO_SWAP_MAGIC /* magic number already in correct endian format */
+
+#include "aout-target.h"
diff --git a/gnu/usr.bin/gdb/bfd/genlink.h b/gnu/usr.bin/gdb/bfd/genlink.h
new file mode 100644
index 0000000..06f6bfc
--- /dev/null
+++ b/gnu/usr.bin/gdb/bfd/genlink.h
@@ -0,0 +1,106 @@
+/* genlink.h -- interface to the BFD generic linker
+ Copyright 1993, 1994 Free Software Foundation, Inc.
+ Written by Ian Lance Taylor, Cygnus Support.
+
+This file is part of BFD, the Binary File Descriptor library.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#ifndef GENLINK_H
+#define GENLINK_H
+
+/* This header file is internal to BFD. It describes the internal
+ structures and functions used by the BFD generic linker, in case
+ any of the more specific linkers want to use or call them. Note
+ that some functions, such as _bfd_generic_link_hash_table_create,
+ are declared in libbfd.h, because they are expected to be widely
+ used. The functions and structures in this file will probably only
+ be used by a few files besides linker.c itself. In fact, this file
+ is not particularly complete; I have only put in the interfaces I
+ actually needed. */
+
+/* The generic linker uses a hash table which is a derived class of
+ the standard linker hash table, just as the other backend specific
+ linkers do. Do not confuse the generic linker hash table with the
+ standard BFD linker hash table it is built upon. */
+
+/* Generic linker hash table entries. */
+
+struct generic_link_hash_entry
+{
+ struct bfd_link_hash_entry root;
+ /* Whether this symbol has been written out. */
+ boolean written;
+ /* Symbol from input BFD. */
+ asymbol *sym;
+};
+
+/* Generic linker hash table. */
+
+struct generic_link_hash_table
+{
+ struct bfd_link_hash_table root;
+};
+
+/* Look up an entry in an generic link hash table. */
+
+#define _bfd_generic_link_hash_lookup(table, string, create, copy, follow) \
+ ((struct generic_link_hash_entry *) \
+ bfd_link_hash_lookup (&(table)->root, (string), (create), (copy), (follow)))
+
+/* Traverse an generic link hash table. */
+
+#define _bfd_generic_link_hash_traverse(table, func, info) \
+ (bfd_link_hash_traverse \
+ (&(table)->root, \
+ (boolean (*) PARAMS ((struct bfd_link_hash_entry *, PTR))) (func), \
+ (info)))
+
+/* Get the generic link hash table from the info structure. This is
+ just a cast. */
+
+#define _bfd_generic_hash_table(p) \
+ ((struct generic_link_hash_table *) ((p)->hash))
+
+/* The generic linker reads in the asymbol structures for an input BFD
+ and keeps them in the outsymbol and symcount fields. */
+
+#define _bfd_generic_link_get_symbols(abfd) ((abfd)->outsymbols)
+#define _bfd_generic_link_get_symcount(abfd) ((abfd)->symcount)
+
+/* Add the symbols of input_bfd to the symbols being built for
+ output_bfd. */
+extern boolean _bfd_generic_link_output_symbols
+ PARAMS ((bfd *output_bfd, bfd *input_bfd, struct bfd_link_info *,
+ size_t *psymalloc));
+
+/* This structure is used to pass information to
+ _bfd_generic_link_write_global_symbol, which may be called via
+ _bfd_generic_link_hash_traverse. */
+
+struct generic_write_global_symbol_info
+{
+ struct bfd_link_info *info;
+ bfd *output_bfd;
+ size_t *psymalloc;
+};
+
+/* Write out a single global symbol. This is expected to be called
+ via _bfd_generic_link_hash_traverse. The second argument must
+ actually be a struct generic_write_global_symbol_info *. */
+extern boolean _bfd_generic_link_write_global_symbol
+ PARAMS ((struct generic_link_hash_entry *, PTR));
+
+#endif
diff --git a/gnu/usr.bin/gdb/bfd/hash.c b/gnu/usr.bin/gdb/bfd/hash.c
new file mode 100644
index 0000000..28d364c
--- /dev/null
+++ b/gnu/usr.bin/gdb/bfd/hash.c
@@ -0,0 +1,470 @@
+/* hash.c -- hash table routines for BFD
+ Copyright (C) 1993, 94 Free Software Foundation, Inc.
+ Written by Steve Chamberlain <sac@cygnus.com>
+
+This file is part of BFD, the Binary File Descriptor library.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "bfd.h"
+#include "sysdep.h"
+#include "libbfd.h"
+#include "obstack.h"
+
+/*
+SECTION
+ Hash Tables
+
+@cindex Hash tables
+ BFD provides a simple set of hash table functions. Routines
+ are provided to initialize a hash table, to free a hash table,
+ to look up a string in a hash table and optionally create an
+ entry for it, and to traverse a hash table. There is
+ currently no routine to delete an string from a hash table.
+
+ The basic hash table does not permit any data to be stored
+ with a string. However, a hash table is designed to present a
+ base class from which other types of hash tables may be
+ derived. These derived types may store additional information
+ with the string. Hash tables were implemented in this way,
+ rather than simply providing a data pointer in a hash table
+ entry, because they were designed for use by the linker back
+ ends. The linker may create thousands of hash table entries,
+ and the overhead of allocating private data and storing and
+ following pointers becomes noticeable.
+
+ The basic hash table code is in <<hash.c>>.
+
+@menu
+@* Creating and Freeing a Hash Table::
+@* Looking Up or Entering a String::
+@* Traversing a Hash Table::
+@* Deriving a New Hash Table Type::
+@end menu
+
+INODE
+Creating and Freeing a Hash Table, Looking Up or Entering a String, Hash Tables, Hash Tables
+SUBSECTION
+ Creating and freeing a hash table
+
+@findex bfd_hash_table_init
+@findex bfd_hash_table_init_n
+ To create a hash table, create an instance of a <<struct
+ bfd_hash_table>> (defined in <<bfd.h>>) and call
+ <<bfd_hash_table_init>> (if you know approximately how many
+ entries you will need, the function <<bfd_hash_table_init_n>>,
+ which takes a @var{size} argument, may be used).
+ <<bfd_hash_table_init>> returns <<false>> if some sort of
+ error occurs.
+
+@findex bfd_hash_newfunc
+ The function <<bfd_hash_table_init>> take as an argument a
+ function to use to create new entries. For a basic hash
+ table, use the function <<bfd_hash_newfunc>>. @xref{Deriving
+ a New Hash Table Type} for why you would want to use a
+ different value for this argument.
+
+@findex bfd_hash_allocate
+ <<bfd_hash_table_init>> will create an obstack which will be
+ used to allocate new entries. You may allocate memory on this
+ obstack using <<bfd_hash_allocate>>.
+
+@findex bfd_hash_table_free
+ Use <<bfd_hash_table_free>> to free up all the memory that has
+ been allocated for a hash table. This will not free up the
+ <<struct bfd_hash_table>> itself, which you must provide.
+
+INODE
+Looking Up or Entering a String, Traversing a Hash Table, Creating and Freeing a Hash Table, Hash Tables
+SUBSECTION
+ Looking up or entering a string
+
+@findex bfd_hash_lookup
+ The function <<bfd_hash_lookup>> is used both to look up a
+ string in the hash table and to create a new entry.
+
+ If the @var{create} argument is <<false>>, <<bfd_hash_lookup>>
+ will look up a string. If the string is found, it will
+ returns a pointer to a <<struct bfd_hash_entry>>. If the
+ string is not found in the table <<bfd_hash_lookup>> will
+ return <<NULL>>. You should not modify any of the fields in
+ the returns <<struct bfd_hash_entry>>.
+
+ If the @var{create} argument is <<true>>, the string will be
+ entered into the hash table if it is not already there.
+ Either way a pointer to a <<struct bfd_hash_entry>> will be
+ returned, either to the existing structure or to a newly
+ created one. In this case, a <<NULL>> return means that an
+ error occurred.
+
+ If the @var{create} argument is <<true>>, and a new entry is
+ created, the @var{copy} argument is used to decide whether to
+ copy the string onto the hash table obstack or not. If
+ @var{copy} is passed as <<false>>, you must be careful not to
+ deallocate or modify the string as long as the hash table
+ exists.
+
+INODE
+Traversing a Hash Table, Deriving a New Hash Table Type, Looking Up or Entering a String, Hash Tables
+SUBSECTION
+ Traversing a hash table
+
+@findex bfd_hash_traverse
+ The function <<bfd_hash_traverse>> may be used to traverse a
+ hash table, calling a function on each element. The traversal
+ is done in a random order.
+
+ <<bfd_hash_traverse>> takes as arguments a function and a
+ generic <<void *>> pointer. The function is called with a
+ hash table entry (a <<struct bfd_hash_entry *>>) and the
+ generic pointer passed to <<bfd_hash_traverse>>. The function
+ must return a <<boolean>> value, which indicates whether to
+ continue traversing the hash table. If the function returns
+ <<false>>, <<bfd_hash_traverse>> will stop the traversal and
+ return immediately.
+
+INODE
+Deriving a New Hash Table Type, , Traversing a Hash Table, Hash Tables
+SUBSECTION
+ Deriving a new hash table type
+
+ Many uses of hash tables want to store additional information
+ which each entry in the hash table. Some also find it
+ convenient to store additional information with the hash table
+ itself. This may be done using a derived hash table.
+
+ Since C is not an object oriented language, creating a derived
+ hash table requires sticking together some boilerplate
+ routines with a few differences specific to the type of hash
+ table you want to create.
+
+ An example of a derived hash table is the linker hash table.
+ The structures for this are defined in <<bfdlink.h>>. The
+ functions are in <<linker.c>>.
+
+ You may also derive a hash table from an already derived hash
+ table. For example, the a.out linker backend code uses a hash
+ table derived from the linker hash table.
+
+@menu
+@* Define the Derived Structures::
+@* Write the Derived Creation Routine::
+@* Write Other Derived Routines::
+@end menu
+
+INODE
+Define the Derived Structures, Write the Derived Creation Routine, Deriving a New Hash Table Type, Deriving a New Hash Table Type
+SUBSUBSECTION
+ Define the derived structures
+
+ You must define a structure for an entry in the hash table,
+ and a structure for the hash table itself.
+
+ The first field in the structure for an entry in the hash
+ table must be of the type used for an entry in the hash table
+ you are deriving from. If you are deriving from a basic hash
+ table this is <<struct bfd_hash_entry>>, which is defined in
+ <<bfd.h>>. The first field in the structure for the hash
+ table itself must be of the type of the hash table you are
+ deriving from itself. If you are deriving from a basic hash
+ table, this is <<struct bfd_hash_table>>.
+
+ For example, the linker hash table defines <<struct
+ bfd_link_hash_entry>> (in <<bfdlink.h>>). The first field,
+ <<root>>, is of type <<struct bfd_hash_entry>>. Similarly,
+ the first field in <<struct bfd_link_hash_table>>, <<table>>,
+ is of type <<struct bfd_hash_table>>.
+
+INODE
+Write the Derived Creation Routine, Write Other Derived Routines, Define the Derived Structures, Deriving a New Hash Table Type
+SUBSUBSECTION
+ Write the derived creation routine
+
+ You must write a routine which will create and initialize an
+ entry in the hash table. This routine is passed as the
+ function argument to <<bfd_hash_table_init>>.
+
+ In order to permit other hash tables to be derived from the
+ hash table you are creating, this routine must be written in a
+ standard way.
+
+ The first argument to the creation routine is a pointer to a
+ hash table entry. This may be <<NULL>>, in which case the
+ routine should allocate the right amount of space. Otherwise
+ the space has already been allocated by a hash table type
+ derived from this one.
+
+ After allocating space, the creation routine must call the
+ creation routine of the hash table type it is derived from,
+ passing in a pointer to the space it just allocated. This
+ will initialize any fields used by the base hash table.
+
+ Finally the creation routine must initialize any local fields
+ for the new hash table type.
+
+ Here is a boilerplate example of a creation routine.
+ @var{function_name} is the name of the routine.
+ @var{entry_type} is the type of an entry in the hash table you
+ are creating. @var{base_newfunc} is the name of the creation
+ routine of the hash table type your hash table is derived
+ from.
+
+EXAMPLE
+
+.struct bfd_hash_entry *
+.@var{function_name} (entry, table, string)
+. struct bfd_hash_entry *entry;
+. struct bfd_hash_table *table;
+. const char *string;
+.{
+. struct @var{entry_type} *ret = (@var{entry_type} *) entry;
+.
+. {* Allocate the structure if it has not already been allocated by a
+. derived class. *}
+. if (ret == (@var{entry_type} *) NULL)
+. {
+. ret = ((@var{entry_type} *)
+. bfd_hash_allocate (table, sizeof (@var{entry_type})));
+. if (ret == (@var{entry_type} *) NULL)
+. return NULL;
+. }
+.
+. {* Call the allocation method of the base class. *}
+. ret = ((@var{entry_type} *)
+. @var{base_newfunc} ((struct bfd_hash_entry *) ret, table, string));
+.
+. {* Initialize the local fields here. *}
+.
+. return (struct bfd_hash_entry *) ret;
+.}
+
+DESCRIPTION
+ The creation routine for the linker hash table, which is in
+ <<linker.c>>, looks just like this example.
+ @var{function_name} is <<_bfd_link_hash_newfunc>>.
+ @var{entry_type} is <<struct bfd_link_hash_entry>>.
+ @var{base_newfunc} is <<bfd_hash_newfunc>>, the creation
+ routine for a basic hash table.
+
+ <<_bfd_link_hash_newfunc>> also initializes the local fields
+ in a linker hash table entry: <<type>>, <<written>> and
+ <<next>>.
+
+INODE
+Write Other Derived Routines, , Write the Derived Creation Routine, Deriving a New Hash Table Type
+SUBSUBSECTION
+ Write other derived routines
+
+ You will want to write other routines for your new hash table,
+ as well.
+
+ You will want an initialization routine which calls the
+ initialization routine of the hash table you are deriving from
+ and initializes any other local fields. For the linker hash
+ table, this is <<_bfd_link_hash_table_init>> in <<linker.c>>.
+
+ You will want a lookup routine which calls the lookup routine
+ of the hash table you are deriving from and casts the result.
+ The linker hash table uses <<bfd_link_hash_lookup>> in
+ <<linker.c>> (this actually takes an additional argument which
+ it uses to decide how to return the looked up value).
+
+ You may want a traversal routine. This should just call the
+ traversal routine of the hash table you are deriving from with
+ appropriate casts. The linker hash table uses
+ <<bfd_link_hash_traverse>> in <<linker.c>>.
+
+ These routines may simply be defined as macros. For example,
+ the a.out backend linker hash table, which is derived from the
+ linker hash table, uses macros for the lookup and traversal
+ routines. These are <<aout_link_hash_lookup>> and
+ <<aout_link_hash_traverse>> in aoutx.h.
+*/
+
+/* Obstack allocation and deallocation routines. */
+#define obstack_chunk_alloc malloc
+#define obstack_chunk_free free
+
+/* The default number of entries to use when creating a hash table. */
+#define DEFAULT_SIZE (4051)
+
+/* Create a new hash table, given a number of entries. */
+
+boolean
+bfd_hash_table_init_n (table, newfunc, size)
+ struct bfd_hash_table *table;
+ struct bfd_hash_entry *(*newfunc) PARAMS ((struct bfd_hash_entry *,
+ struct bfd_hash_table *,
+ const char *));
+ unsigned int size;
+{
+ unsigned int alloc;
+
+ alloc = size * sizeof (struct bfd_hash_entry *);
+ if (!obstack_begin (&table->memory, alloc))
+ {
+ bfd_set_error (bfd_error_no_memory);
+ return false;
+ }
+ table->table = ((struct bfd_hash_entry **)
+ obstack_alloc (&table->memory, alloc));
+ if (!table->table)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ return false;
+ }
+ memset ((PTR) table->table, 0, alloc);
+ table->size = size;
+ table->newfunc = newfunc;
+ return true;
+}
+
+/* Create a new hash table with the default number of entries. */
+
+boolean
+bfd_hash_table_init (table, newfunc)
+ struct bfd_hash_table *table;
+ struct bfd_hash_entry *(*newfunc) PARAMS ((struct bfd_hash_entry *,
+ struct bfd_hash_table *,
+ const char *));
+{
+ return bfd_hash_table_init_n (table, newfunc, DEFAULT_SIZE);
+}
+
+/* Free a hash table. */
+
+void
+bfd_hash_table_free (table)
+ struct bfd_hash_table *table;
+{
+ obstack_free (&table->memory, (PTR) NULL);
+}
+
+/* Look up a string in a hash table. */
+
+struct bfd_hash_entry *
+bfd_hash_lookup (table, string, create, copy)
+ struct bfd_hash_table *table;
+ const char *string;
+ boolean create;
+ boolean copy;
+{
+ register const unsigned char *s;
+ register unsigned long hash;
+ register unsigned int c;
+ struct bfd_hash_entry *hashp;
+ unsigned int len;
+ unsigned int index;
+
+ hash = 0;
+ len = 0;
+ s = (const unsigned char *) string;
+ while ((c = *s++) != '\0')
+ {
+ hash += c + (c << 17);
+ hash ^= hash >> 2;
+ ++len;
+ }
+ hash += len + (len << 17);
+ hash ^= hash >> 2;
+
+ index = hash % table->size;
+ for (hashp = table->table[index];
+ hashp != (struct bfd_hash_entry *) NULL;
+ hashp = hashp->next)
+ {
+ if (hashp->hash == hash
+ && strcmp (hashp->string, string) == 0)
+ return hashp;
+ }
+
+ if (! create)
+ return (struct bfd_hash_entry *) NULL;
+
+ hashp = (*table->newfunc) ((struct bfd_hash_entry *) NULL, table, string);
+ if (hashp == (struct bfd_hash_entry *) NULL)
+ return (struct bfd_hash_entry *) NULL;
+ if (copy)
+ {
+ char *new;
+
+ new = (char *) obstack_alloc (&table->memory, len + 1);
+ if (!new)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ return (struct bfd_hash_entry *) NULL;
+ }
+ strcpy (new, string);
+ string = new;
+ }
+ hashp->string = string;
+ hashp->hash = hash;
+ hashp->next = table->table[index];
+ table->table[index] = hashp;
+
+ return hashp;
+}
+
+/* Base method for creating a new hash table entry. */
+
+/*ARGSUSED*/
+struct bfd_hash_entry *
+bfd_hash_newfunc (entry, table, string)
+ struct bfd_hash_entry *entry;
+ struct bfd_hash_table *table;
+ const char *string;
+{
+ if (entry == (struct bfd_hash_entry *) NULL)
+ entry = ((struct bfd_hash_entry *)
+ bfd_hash_allocate (table, sizeof (struct bfd_hash_entry)));
+ return entry;
+}
+
+/* Allocate space in a hash table. */
+
+PTR
+bfd_hash_allocate (table, size)
+ struct bfd_hash_table *table;
+ unsigned int size;
+{
+ PTR ret;
+
+ ret = obstack_alloc (&table->memory, size);
+ if (ret == NULL && size != 0)
+ bfd_set_error (bfd_error_no_memory);
+ return ret;
+}
+
+/* Traverse a hash table. */
+
+void
+bfd_hash_traverse (table, func, info)
+ struct bfd_hash_table *table;
+ boolean (*func) PARAMS ((struct bfd_hash_entry *, PTR));
+ PTR info;
+{
+ unsigned int i;
+
+ for (i = 0; i < table->size; i++)
+ {
+ struct bfd_hash_entry *p;
+
+ for (p = table->table[i]; p != NULL; p = p->next)
+ {
+ if (! (*func) (p, info))
+ return;
+ }
+ }
+}
diff --git a/gnu/usr.bin/gdb/bfd/i386aout.c b/gnu/usr.bin/gdb/bfd/i386aout.c
new file mode 100644
index 0000000..4af12ba
--- /dev/null
+++ b/gnu/usr.bin/gdb/bfd/i386aout.c
@@ -0,0 +1,68 @@
+/* BFD back-end for i386 a.out binaries.
+ Copyright 1990, 1991, 1992 Free Software Foundation, Inc.
+
+This file is part of BFD, the Binary File Descriptor library.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+
+/* The only 386 aout system we have here is GO32 from DJ.
+ These numbers make BFD work with that. If your aout 386 system
+ doesn't work with these, we'll have to split them into different
+ files. Send me (sac@cygnus.com) the runes to make it work on your
+ system, and I'll stick it in for the next release. */
+
+#define N_HEADER_IN_TEXT(x) 0
+#define BYTES_IN_WORD 4
+
+#define N_TXTOFF(x) 0x20
+#define N_TXTADDR(x) (N_MAGIC(x)==ZMAGIC ? 0x1020 : 0)
+
+#define N_TXTSIZE(x) ((x).a_text)
+#if 0
+#define N_DATADDR(x) (N_MAGIC(x)==OMAGIC? (N_TXTADDR(x)+(x).a_text) : (SEGMENT_SIZE + ((0x1020+(x).a_text-1) & ~(SEGMENT_SIZE-1))))
+#define NOSUBEXECB
+
+#define PAGE_SIZE 4096
+#endif
+#define SEGMENT_SIZE 0x400000
+#define DEFAULT_ARCH bfd_arch_i386
+
+#define MY(OP) CAT(i386aout_,OP)
+#define TARGETNAME "a.out-i386"
+#define NO_WRITE_HEADER_KLUDGE 1
+
+#include "bfd.h"
+#include "sysdep.h"
+#include "libbfd.h"
+#include "libaout.h"
+static boolean MY(set_sizes)();
+#define MY_backend_data &MY(backend_data)
+static CONST struct aout_backend_data MY(backend_data) = {
+ 0, /* zmagic contiguous */
+ 1, /* text incl header */
+ 0, /* exec_hdr_flags */
+ 0, /* text vma? */
+ MY(set_sizes),
+ 1, /* exec header not counted */
+ 0, /* add_dynamic_symbols */
+ 0, /* add_one_symbol */
+ 0, /* link_dynamic_object */
+ 0, /* write_dynamic_symbol */
+ 0, /* check_dynamic_reloc */
+ 0 /* finish_dynamic_link */
+};
+
+#include "aout-target.h"
diff --git a/gnu/usr.bin/gdb/bfd/init.c b/gnu/usr.bin/gdb/bfd/init.c
new file mode 100644
index 0000000..3b93262
--- /dev/null
+++ b/gnu/usr.bin/gdb/bfd/init.c
@@ -0,0 +1,79 @@
+/* bfd initialization stuff
+ Copyright (C) 1990, 91, 92, 93, 94 Free Software Foundation, Inc.
+ Written by Steve Chamberlain of Cygnus Support.
+
+This file is part of BFD, the Binary File Descriptor library.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "bfd.h"
+#include "sysdep.h"
+#include "libbfd.h"
+
+extern void bfd_section_init ();
+
+static boolean initialized = false;
+
+/*
+SECTION
+ Initialization
+
+ These are the functions that handle initializing a BFD.
+*/
+
+/*
+FUNCTION
+ bfd_init
+
+SYNOPSIS
+ void bfd_init(void);
+
+DESCRIPTION
+ This routine must be called before any other BFD function to
+ initialize magical internal data structures.
+*/
+
+void
+bfd_init ()
+{
+ if (initialized == false) {
+ initialized = true;
+
+ bfd_arch_init();
+ }
+}
+
+
+/*
+INTERNAL_FUNCTION
+ bfd_check_init
+
+SYNOPSIS
+ void bfd_check_init(void);
+
+DESCRIPTION
+ This routine is called before any other BFD function using
+ initialized data. It ensures that the structures have
+ been initialized. Soon this function will go away, and the BFD
+ library will assume that <<bfd_init>> has been called.
+*/
+
+void
+bfd_check_init ()
+{
+ if (initialized == false) {
+ bfd_init();
+ }
+}
diff --git a/gnu/usr.bin/gdb/bfd/libaout.h b/gnu/usr.bin/gdb/bfd/libaout.h
new file mode 100644
index 0000000..7a66f65
--- /dev/null
+++ b/gnu/usr.bin/gdb/bfd/libaout.h
@@ -0,0 +1,578 @@
+/* BFD back-end data structures for a.out (and similar) files.
+ Copyright 1990, 1991, 1992 Free Software Foundation, Inc.
+ Written by Cygnus Support.
+
+This file is part of BFD, the Binary File Descriptor library.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#ifndef LIBAOUT_H
+#define LIBAOUT_H
+
+/* We try to encapsulate the differences in the various a.out file
+ variants in a few routines, and otherwise share large masses of code.
+ This means we only have to fix bugs in one place, most of the time. */
+
+#include "bfdlink.h"
+
+/* Parameterize the a.out code based on whether it is being built
+ for a 32-bit architecture or a 64-bit architecture. */
+#if ARCH_SIZE==64
+#define GET_WORD bfd_h_get_64
+#define GET_SWORD bfd_h_get_signed_64
+#define PUT_WORD bfd_h_put_64
+#ifndef NAME
+#define NAME(x,y) CAT3(x,_64_,y)
+#endif
+#define JNAME(x) CAT(x,_64)
+#define BYTES_IN_WORD 8
+#else /* ARCH_SIZE == 32 */
+#define GET_WORD bfd_h_get_32
+#define GET_SWORD bfd_h_get_signed_32
+#define PUT_WORD bfd_h_put_32
+#ifndef NAME
+#define NAME(x,y) CAT3(x,_32_,y)
+#endif
+#define JNAME(x) CAT(x,_32)
+#define BYTES_IN_WORD 4
+#endif /* ARCH_SIZE==32 */
+
+/* Declare at file level, since used in parameter lists, which have
+ weird scope. */
+struct external_exec;
+struct external_nlist;
+struct reloc_ext_external;
+struct reloc_std_external;
+
+/* a.out backend linker hash table entries. */
+
+struct aout_link_hash_entry
+{
+ struct bfd_link_hash_entry root;
+ /* Whether this symbol has been written out. */
+ boolean written;
+ /* Symbol index in output file. */
+ int indx;
+};
+
+/* a.out backend linker hash table. */
+
+struct aout_link_hash_table
+{
+ struct bfd_link_hash_table root;
+};
+
+/* Look up an entry in an a.out link hash table. */
+
+#define aout_link_hash_lookup(table, string, create, copy, follow) \
+ ((struct aout_link_hash_entry *) \
+ bfd_link_hash_lookup (&(table)->root, (string), (create), (copy), (follow)))
+
+/* Traverse an a.out link hash table. */
+
+#define aout_link_hash_traverse(table, func, info) \
+ (bfd_link_hash_traverse \
+ (&(table)->root, \
+ (boolean (*) PARAMS ((struct bfd_link_hash_entry *, PTR))) (func), \
+ (info)))
+
+/* Get the a.out link hash table from the info structure. This is
+ just a cast. */
+
+#define aout_hash_table(p) ((struct aout_link_hash_table *) ((p)->hash))
+
+/* Back-end information for various a.out targets. */
+struct aout_backend_data
+{
+ /* Are ZMAGIC files mapped contiguously? If so, the text section may
+ need more padding, if the segment size (granularity for memory access
+ control) is larger than the page size. */
+ unsigned char zmagic_mapped_contiguous;
+ /* If this flag is set, ZMAGIC/NMAGIC file headers get mapped in with the
+ text section, which starts immediately after the file header.
+ If not, the text section starts on the next page. */
+ unsigned char text_includes_header;
+
+ /* The value to pass to N_SET_FLAGS. */
+ unsigned char exec_hdr_flags;
+
+ /* If the text section VMA isn't specified, and we need an absolute
+ address, use this as the default. If we're producing a relocatable
+ file, zero is always used. */
+ /* ?? Perhaps a callback would be a better choice? Will this do anything
+ reasonable for a format that handles multiple CPUs with different
+ load addresses for each? */
+ bfd_vma default_text_vma;
+
+ /* Callback for setting the page and segment sizes, if they can't be
+ trivially determined from the architecture. */
+ boolean (*set_sizes) PARAMS ((bfd *));
+
+ /* zmagic files only. For go32, the length of the exec header contributes
+ to the size of the text section in the file for alignment purposes but
+ does *not* get counted in the length of the text section. */
+ unsigned char exec_header_not_counted;
+
+ /* Callback from the add symbols phase of the linker code to handle
+ a dynamic object. */
+ boolean (*add_dynamic_symbols) PARAMS ((bfd *, struct bfd_link_info *));
+
+ /* Callback from the add symbols phase of the linker code to handle
+ adding a single symbol to the global linker hash table. */
+ boolean (*add_one_symbol) PARAMS ((struct bfd_link_info *, bfd *,
+ const char *, flagword, asection *,
+ bfd_vma, const char *, boolean,
+ boolean,
+ struct bfd_link_hash_entry **));
+
+ /* Called to handle linking a dynamic object. */
+ boolean (*link_dynamic_object) PARAMS ((struct bfd_link_info *, bfd *));
+
+ /* Called for each global symbol being written out by the linker.
+ This should write out the dynamic symbol information. */
+ boolean (*write_dynamic_symbol) PARAMS ((bfd *, struct bfd_link_info *,
+ struct aout_link_hash_entry *));
+
+ /* This callback is called by the linker for each reloc against an
+ external symbol. RELOC is a pointer to the unswapped reloc. If
+ *SKIP is set to true, the reloc will be skipped. */
+ boolean (*check_dynamic_reloc) PARAMS ((struct bfd_link_info *info,
+ bfd *input_bfd,
+ asection *input_section,
+ struct aout_link_hash_entry *h,
+ PTR reloc, boolean *skip));
+
+ /* Called at the end of a link to finish up any dynamic linking
+ information. */
+ boolean (*finish_dynamic_link) PARAMS ((bfd *, struct bfd_link_info *));
+};
+#define aout_backend_info(abfd) \
+ ((CONST struct aout_backend_data *)((abfd)->xvec->backend_data))
+
+/* This is the layout in memory of a "struct exec" while we process it.
+ All 'lengths' are given as a number of bytes.
+ All 'alignments' are for relinkable files only; an alignment of
+ 'n' indicates the corresponding segment must begin at an
+ address that is a multiple of (2**n). */
+
+struct internal_exec
+{
+ long a_info; /* Magic number and flags, packed */
+ bfd_vma a_text; /* length of text, in bytes */
+ bfd_vma a_data; /* length of data, in bytes */
+ bfd_vma a_bss; /* length of uninitialized data area in mem */
+ bfd_vma a_syms; /* length of symbol table data in file */
+ bfd_vma a_entry; /* start address */
+ bfd_vma a_trsize; /* length of text's relocation info, in bytes */
+ bfd_vma a_drsize; /* length of data's relocation info, in bytes */
+ /* Added for i960 */
+ bfd_vma a_tload; /* Text runtime load address */
+ bfd_vma a_dload; /* Data runtime load address */
+ unsigned char a_talign; /* Alignment of text segment */
+ unsigned char a_dalign; /* Alignment of data segment */
+ unsigned char a_balign; /* Alignment of bss segment */
+ char a_relaxable; /* Enough info for linker relax */
+};
+
+/* Magic number is written
+< MSB >
+3130292827262524232221201918171615141312111009080706050403020100
+< FLAGS >< MACHINE TYPE >< MAGIC NUMBER >
+*/
+/* Magic number for NetBSD is
+<MSB >
+3130292827262524232221201918171615141312111009080706050403020100
+< FLAGS >< >< MAGIC NUMBER >
+*/
+
+enum machine_type {
+ M_UNKNOWN = 0,
+ M_68010 = 1,
+ M_68020 = 2,
+ M_SPARC = 3,
+ /* skip a bunch so we don't run into any of suns numbers */
+ /* make these up for the ns32k*/
+ M_NS32032 = (64), /* ns32032 running ? */
+ M_NS32532 = (64 + 5), /* ns32532 running mach */
+
+ M_386 = 100,
+ M_29K = 101, /* AMD 29000 */
+ M_386_DYNIX = 102, /* Sequent running dynix */
+ M_386_NETBSD = 134, /* NetBSD/386 binary */
+ M_532_NETBSD = 137, /* MetBSD/523 binary */
+ M_MIPS1 = 151, /* MIPS R2000/R3000 binary */
+ M_MIPS2 = 152, /* MIPS R4000/R6000 binary */
+ M_HP200 = 200, /* HP 200 (68010) BSD binary */
+ M_HP300 = (300 % 256), /* HP 300 (68020+68881) BSD binary */
+ M_HPUX = (0x20c % 256)/* HP 200/300 HPUX binary */
+};
+
+#define N_DYNAMIC(exec) ((exec).a_info & 0x80000000)
+
+#ifndef N_MAGIC
+# define N_MAGIC(exec) ((exec).a_info & 0xffff)
+#endif
+
+#ifndef N_MACHTYPE
+# define N_MACHTYPE(exec) ((enum machine_type)(((exec).a_info >> 16) & 0xff))
+#endif
+
+#ifndef N_FLAGS
+# define N_FLAGS(exec) (((exec).a_info >> 24) & 0xff)
+#endif
+
+#ifndef N_SET_INFO
+# define N_SET_INFO(exec, magic, type, flags) \
+((exec).a_info = ((magic) & 0xffff) \
+ | (((int)(type) & 0xff) << 16) \
+ | (((flags) & 0xff) << 24))
+#endif
+
+#ifndef N_SET_DYNAMIC
+# define N_SET_DYNAMIC(exec, dynamic) \
+((exec).a_info = (dynamic) ? ((exec).a_info | 0x80000000) : \
+((exec).a_info & 0x7fffffff))
+#endif
+
+#ifndef N_SET_MAGIC
+# define N_SET_MAGIC(exec, magic) \
+((exec).a_info = (((exec).a_info & 0xffff0000) | ((magic) & 0xffff)))
+#endif
+
+#ifndef N_SET_MACHTYPE
+# define N_SET_MACHTYPE(exec, machtype) \
+((exec).a_info = \
+ ((exec).a_info&0xff00ffff) | ((((int)(machtype))&0xff) << 16))
+#endif
+
+#ifndef N_SET_FLAGS
+# define N_SET_FLAGS(exec, flags) \
+((exec).a_info = \
+ ((exec).a_info&0x00ffffff) | (((flags) & 0xff) << 24))
+#endif
+
+typedef struct aout_symbol {
+ asymbol symbol;
+ short desc;
+ char other;
+ unsigned char type;
+} aout_symbol_type;
+
+/* The `tdata' struct for all a.out-like object file formats.
+ Various things depend on this struct being around any time an a.out
+ file is being handled. An example is dbxread.c in GDB. */
+
+struct aoutdata {
+ struct internal_exec *hdr; /* exec file header */
+ aout_symbol_type *symbols; /* symtab for input bfd */
+
+ /* For ease, we do this */
+ asection *textsec;
+ asection *datasec;
+ asection *bsssec;
+
+ /* We remember these offsets so that after check_file_format, we have
+ no dependencies on the particular format of the exec_hdr. */
+ file_ptr sym_filepos;
+ file_ptr str_filepos;
+
+ /* Size of a relocation entry in external form */
+ unsigned reloc_entry_size;
+
+ /* Size of a symbol table entry in external form */
+ unsigned symbol_entry_size;
+
+ /* Page size - needed for alignment of demand paged files. */
+ unsigned long page_size;
+
+ /* Segment size - needed for alignment of demand paged files. */
+ unsigned long segment_size;
+
+ /* Zmagic disk block size - need to align the start of the text
+ section in ZMAGIC binaries. Normally the same as page_size. */
+ unsigned long zmagic_disk_block_size;
+
+ unsigned exec_bytes_size;
+ unsigned vma_adjusted : 1;
+
+ /* used when a bfd supports several highly similar formats */
+ enum
+ {
+ default_format = 0,
+ /* Used on HP 9000/300 running HP/UX. See hp300hpux.c. */
+ gnu_encap_format,
+ /* Used on Linux, 386BSD, etc. See include/aout/aout64.h. */
+ q_magic_format
+ } subformat;
+
+ enum
+ {
+ undecided_magic = 0,
+ z_magic,
+ o_magic,
+ n_magic
+ } magic;
+
+ /* The external symbol information. */
+ struct external_nlist *external_syms;
+ bfd_size_type external_sym_count;
+ char *external_strings;
+ bfd_size_type external_string_size;
+ struct aout_link_hash_entry **sym_hashes;
+
+ /* A pointer for shared library information. */
+ PTR dynamic_info;
+};
+
+struct aout_data_struct {
+ struct aoutdata a;
+ struct internal_exec e;
+};
+
+#define adata(bfd) ((bfd)->tdata.aout_data->a)
+#define exec_hdr(bfd) (adata(bfd).hdr)
+#define obj_aout_symbols(bfd) (adata(bfd).symbols)
+#define obj_textsec(bfd) (adata(bfd).textsec)
+#define obj_datasec(bfd) (adata(bfd).datasec)
+#define obj_bsssec(bfd) (adata(bfd).bsssec)
+#define obj_sym_filepos(bfd) (adata(bfd).sym_filepos)
+#define obj_str_filepos(bfd) (adata(bfd).str_filepos)
+#define obj_reloc_entry_size(bfd) (adata(bfd).reloc_entry_size)
+#define obj_symbol_entry_size(bfd) (adata(bfd).symbol_entry_size)
+#define obj_aout_subformat(bfd) (adata(bfd).subformat)
+#define obj_aout_external_syms(bfd) (adata(bfd).external_syms)
+#define obj_aout_external_sym_count(bfd) (adata(bfd).external_sym_count)
+#define obj_aout_external_strings(bfd) (adata(bfd).external_strings)
+#define obj_aout_external_string_size(bfd) (adata(bfd).external_string_size)
+#define obj_aout_sym_hashes(bfd) (adata(bfd).sym_hashes)
+#define obj_aout_dynamic_info(bfd) (adata(bfd).dynamic_info)
+
+/* We take the address of the first element of an asymbol to ensure that the
+ macro is only ever applied to an asymbol */
+#define aout_symbol(asymbol) ((aout_symbol_type *)(&(asymbol)->the_bfd))
+
+/* Information we keep for each a.out section. This is currently only
+ used by the a.out backend linker. */
+
+struct aout_section_data_struct
+{
+ /* The unswapped relocation entries for this section. */
+ PTR relocs;
+};
+
+#define aout_section_data(s) \
+ ((struct aout_section_data_struct *) (s)->used_by_bfd)
+
+/* Prototype declarations for functions defined in aoutx.h */
+
+boolean
+NAME(aout,squirt_out_relocs) PARAMS ((bfd *abfd, asection *section));
+
+boolean
+NAME(aout,make_sections) PARAMS ((bfd *));
+
+const bfd_target *
+NAME(aout,some_aout_object_p) PARAMS ((bfd *abfd,
+ struct internal_exec *execp,
+ const bfd_target *(*callback)(bfd *)));
+
+boolean
+NAME(aout,mkobject) PARAMS ((bfd *abfd));
+
+enum machine_type
+NAME(aout,machine_type) PARAMS ((enum bfd_architecture arch,
+ unsigned long machine,
+ boolean *unknown));
+
+boolean
+NAME(aout,set_arch_mach) PARAMS ((bfd *abfd, enum bfd_architecture arch,
+ unsigned long machine));
+
+boolean
+NAME(aout,new_section_hook) PARAMS ((bfd *abfd, asection *newsect));
+
+boolean
+NAME(aout,set_section_contents) PARAMS ((bfd *abfd, sec_ptr section,
+ PTR location, file_ptr offset, bfd_size_type count));
+
+asymbol *
+NAME(aout,make_empty_symbol) PARAMS ((bfd *abfd));
+
+boolean
+NAME(aout,translate_symbol_table) PARAMS ((bfd *, aout_symbol_type *,
+ struct external_nlist *,
+ bfd_size_type, char *,
+ bfd_size_type,
+ boolean dynamic));
+
+boolean
+NAME(aout,slurp_symbol_table) PARAMS ((bfd *abfd));
+
+boolean
+NAME(aout,write_syms) PARAMS ((bfd *abfd));
+
+void
+NAME(aout,reclaim_symbol_table) PARAMS ((bfd *abfd));
+
+long
+NAME(aout,get_symtab_upper_bound) PARAMS ((bfd *abfd));
+
+long
+NAME(aout,get_symtab) PARAMS ((bfd *abfd, asymbol **location));
+
+void
+NAME(aout,swap_ext_reloc_in) PARAMS ((bfd *, struct reloc_ext_external *,
+ arelent *, asymbol **));
+void
+NAME(aout,swap_std_reloc_in) PARAMS ((bfd *, struct reloc_std_external *,
+ arelent *, asymbol **));
+
+boolean
+NAME(aout,slurp_reloc_table) PARAMS ((bfd *abfd, sec_ptr asect,
+ asymbol **symbols));
+
+long
+NAME(aout,canonicalize_reloc) PARAMS ((bfd *abfd, sec_ptr section,
+ arelent **relptr, asymbol **symbols));
+
+long
+NAME(aout,get_reloc_upper_bound) PARAMS ((bfd *abfd, sec_ptr asect));
+
+void
+NAME(aout,reclaim_reloc) PARAMS ((bfd *ignore_abfd, sec_ptr ignore));
+
+alent *
+NAME(aout,get_lineno) PARAMS ((bfd *ignore_abfd, asymbol *ignore_symbol));
+
+void
+NAME(aout,print_symbol) PARAMS ((bfd *ignore_abfd, PTR file,
+ asymbol *symbol, bfd_print_symbol_type how));
+
+void
+NAME(aout,get_symbol_info) PARAMS ((bfd *ignore_abfd,
+ asymbol *symbol, symbol_info *ret));
+
+boolean
+NAME(aout,find_nearest_line) PARAMS ((bfd *abfd, asection *section,
+ asymbol **symbols, bfd_vma offset, CONST char **filename_ptr,
+ CONST char **functionname_ptr, unsigned int *line_ptr));
+
+int
+NAME(aout,sizeof_headers) PARAMS ((bfd *abfd, boolean exec));
+
+boolean
+NAME(aout,adjust_sizes_and_vmas) PARAMS ((bfd *abfd,
+ bfd_size_type *text_size, file_ptr *text_end));
+
+void
+NAME(aout,swap_exec_header_in) PARAMS ((bfd *abfd,
+ struct external_exec *raw_bytes, struct internal_exec *execp));
+
+void
+NAME(aout,swap_exec_header_out) PARAMS ((bfd *abfd,
+ struct internal_exec *execp, struct external_exec *raw_bytes));
+
+struct bfd_hash_entry *
+NAME(aout,link_hash_newfunc)
+ PARAMS ((struct bfd_hash_entry *, struct bfd_hash_table *, const char *));
+
+boolean
+NAME(aout,link_hash_table_init)
+ PARAMS ((struct aout_link_hash_table *, bfd *,
+ struct bfd_hash_entry *(*) (struct bfd_hash_entry *,
+ struct bfd_hash_table *,
+ const char *)));
+
+struct bfd_link_hash_table *
+NAME(aout,link_hash_table_create) PARAMS ((bfd *));
+
+boolean
+NAME(aout,link_add_symbols) PARAMS ((bfd *, struct bfd_link_info *));
+
+boolean
+NAME(aout,final_link) PARAMS ((bfd *, struct bfd_link_info *,
+ void (*) (bfd *, file_ptr *, file_ptr *,
+ file_ptr *)));
+
+boolean
+NAME(aout,bfd_free_cached_info) PARAMS ((bfd *));
+
+/* Prototypes for functions in stab-syms.c. */
+
+CONST char *
+aout_stab_name PARAMS ((int code));
+
+/* A.out uses the generic versions of these routines... */
+
+#define aout_32_get_section_contents _bfd_generic_get_section_contents
+
+#define aout_64_get_section_contents _bfd_generic_get_section_contents
+#ifndef NO_WRITE_HEADER_KLUDGE
+#define NO_WRITE_HEADER_KLUDGE 0
+#endif
+
+#ifndef aout_32_bfd_is_local_label
+#define aout_32_bfd_is_local_label bfd_generic_is_local_label
+#endif
+
+#ifndef WRITE_HEADERS
+#define WRITE_HEADERS(abfd, execp) \
+ { \
+ bfd_size_type text_size; /* dummy vars */ \
+ file_ptr text_end; \
+ if (adata(abfd).magic == undecided_magic) \
+ NAME(aout,adjust_sizes_and_vmas) (abfd, &text_size, &text_end); \
+ \
+ execp->a_syms = bfd_get_symcount (abfd) * EXTERNAL_NLIST_SIZE; \
+ execp->a_entry = bfd_get_start_address (abfd); \
+ \
+ execp->a_trsize = ((obj_textsec (abfd)->reloc_count) * \
+ obj_reloc_entry_size (abfd)); \
+ execp->a_drsize = ((obj_datasec (abfd)->reloc_count) * \
+ obj_reloc_entry_size (abfd)); \
+ NAME(aout,swap_exec_header_out) (abfd, execp, &exec_bytes); \
+ \
+ if (bfd_seek (abfd, (file_ptr) 0, SEEK_SET) != 0) return false; \
+ if (bfd_write ((PTR) &exec_bytes, 1, EXEC_BYTES_SIZE, abfd) \
+ != EXEC_BYTES_SIZE) \
+ return false; \
+ /* Now write out reloc info, followed by syms and strings */ \
+ \
+ if (bfd_get_outsymbols (abfd) != (asymbol **) NULL \
+ && bfd_get_symcount (abfd) != 0) \
+ { \
+ if (bfd_seek (abfd, (file_ptr)(N_SYMOFF(*execp)), SEEK_SET) \
+ != 0) \
+ return false; \
+ \
+ if (! NAME(aout,write_syms)(abfd)) return false; \
+ \
+ if (bfd_seek (abfd, (file_ptr)(N_TRELOFF(*execp)), SEEK_SET) \
+ != 0) \
+ return false; \
+ \
+ if (!NAME(aout,squirt_out_relocs) (abfd, obj_textsec (abfd))) \
+ return false; \
+ if (bfd_seek (abfd, (file_ptr)(N_DRELOFF(*execp)), SEEK_SET) \
+ != 0) \
+ return false; \
+ \
+ if (!NAME(aout,squirt_out_relocs)(abfd, obj_datasec (abfd))) \
+ return false; \
+ } \
+ }
+#endif
+
+#endif /* ! defined (LIBAOUT_H) */
diff --git a/gnu/usr.bin/gdb/bfd/libbfd.c b/gnu/usr.bin/gdb/bfd/libbfd.c
new file mode 100644
index 0000000..031f08f
--- /dev/null
+++ b/gnu/usr.bin/gdb/bfd/libbfd.c
@@ -0,0 +1,880 @@
+/* Assorted BFD support routines, only used internally.
+ Copyright 1990, 91, 92, 93, 94 Free Software Foundation, Inc.
+ Written by Cygnus Support.
+
+This file is part of BFD, the Binary File Descriptor library.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "bfd.h"
+#include "sysdep.h"
+#include "libbfd.h"
+
+/*
+SECTION
+ Internal functions
+
+DESCRIPTION
+ These routines are used within BFD.
+ They are not intended for export, but are documented here for
+ completeness.
+*/
+
+/* A routine which is used in target vectors for unsupported
+ operations. */
+
+/*ARGSUSED*/
+boolean
+bfd_false (ignore)
+ bfd *ignore;
+{
+ bfd_set_error (bfd_error_invalid_operation);
+ return false;
+}
+
+/* A routine which is used in target vectors for supported operations
+ which do not actually do anything. */
+
+/*ARGSUSED*/
+boolean
+bfd_true (ignore)
+ bfd *ignore;
+{
+ return true;
+}
+
+/* A routine which is used in target vectors for unsupported
+ operations which return a pointer value. */
+
+/*ARGSUSED*/
+PTR
+bfd_nullvoidptr (ignore)
+ bfd *ignore;
+{
+ bfd_set_error (bfd_error_invalid_operation);
+ return NULL;
+}
+
+/*ARGSUSED*/
+int
+bfd_0 (ignore)
+ bfd *ignore;
+{
+ return 0;
+}
+
+/*ARGSUSED*/
+unsigned int
+bfd_0u (ignore)
+ bfd *ignore;
+{
+ return 0;
+}
+
+/*ARGUSED*/
+long
+bfd_0l (ignore)
+ bfd *ignore;
+{
+ return 0;
+}
+
+/* A routine which is used in target vectors for unsupported
+ operations which return -1 on error. */
+
+/*ARGSUSED*/
+long
+_bfd_n1 (ignore_abfd)
+ bfd *ignore_abfd;
+{
+ bfd_set_error (bfd_error_invalid_operation);
+ return -1;
+}
+
+/*ARGSUSED*/
+void
+bfd_void (ignore)
+ bfd *ignore;
+{
+}
+
+/*ARGSUSED*/
+boolean
+_bfd_nocore_core_file_matches_executable_p (ignore_core_bfd, ignore_exec_bfd)
+ bfd *ignore_core_bfd;
+ bfd *ignore_exec_bfd;
+{
+ bfd_set_error (bfd_error_invalid_operation);
+ return false;
+}
+
+/* Routine to handle core_file_failing_command entry point for targets
+ without core file support. */
+
+/*ARGSUSED*/
+char *
+_bfd_nocore_core_file_failing_command (ignore_abfd)
+ bfd *ignore_abfd;
+{
+ bfd_set_error (bfd_error_invalid_operation);
+ return (char *)NULL;
+}
+
+/* Routine to handle core_file_failing_signal entry point for targets
+ without core file support. */
+
+/*ARGSUSED*/
+int
+_bfd_nocore_core_file_failing_signal (ignore_abfd)
+ bfd *ignore_abfd;
+{
+ bfd_set_error (bfd_error_invalid_operation);
+ return 0;
+}
+
+/*ARGSUSED*/
+const bfd_target *
+_bfd_dummy_target (ignore_abfd)
+ bfd *ignore_abfd;
+{
+ bfd_set_error (bfd_error_wrong_format);
+ return 0;
+}
+
+
+#ifndef bfd_zmalloc
+/* allocate and clear storage */
+
+char *
+bfd_zmalloc (size)
+ bfd_size_type size;
+{
+ char *ptr = (char *) malloc ((size_t) size);
+
+ if (ptr && size)
+ memset(ptr, 0, (size_t) size);
+
+ return ptr;
+}
+#endif /* bfd_zmalloc */
+
+/* Some IO code */
+
+
+/* Note that archive entries don't have streams; they share their parent's.
+ This allows someone to play with the iostream behind BFD's back.
+
+ Also, note that the origin pointer points to the beginning of a file's
+ contents (0 for non-archive elements). For archive entries this is the
+ first octet in the file, NOT the beginning of the archive header. */
+
+static
+int
+real_read (where, a,b, file)
+ PTR where;
+ int a;
+ int b;
+ FILE *file;
+{
+ return fread(where, a,b,file);
+}
+
+/* Return value is amount read (FIXME: how are errors and end of file dealt
+ with? We never call bfd_set_error, which is probably a mistake). */
+
+bfd_size_type
+bfd_read (ptr, size, nitems, abfd)
+ PTR ptr;
+ bfd_size_type size;
+ bfd_size_type nitems;
+ bfd *abfd;
+{
+ int nread;
+ nread = real_read (ptr, 1, (int)(size*nitems), bfd_cache_lookup(abfd));
+#ifdef FILE_OFFSET_IS_CHAR_INDEX
+ if (nread > 0)
+ abfd->where += nread;
+#endif
+
+ /* Set bfd_error if we did not read as much data as we expected.
+
+ If the read failed due to an error set the bfd_error_system_call,
+ else set bfd_error_file_truncated.
+
+ A BFD backend may wish to override bfd_error_file_truncated to
+ provide something more useful (eg. no_symbols or wrong_format). */
+ if (nread < (int)(size * nitems))
+ {
+ if (ferror (bfd_cache_lookup (abfd)))
+ bfd_set_error (bfd_error_system_call);
+ else
+ bfd_set_error (bfd_error_file_truncated);
+ }
+
+ return nread;
+}
+
+bfd_size_type
+bfd_write (ptr, size, nitems, abfd)
+ CONST PTR ptr;
+ bfd_size_type size;
+ bfd_size_type nitems;
+ bfd *abfd;
+{
+ int nwrote = fwrite (ptr, 1, (int) (size * nitems), bfd_cache_lookup (abfd));
+#ifdef FILE_OFFSET_IS_CHAR_INDEX
+ if (nwrote > 0)
+ abfd->where += nwrote;
+#endif
+ if (nwrote != size * nitems)
+ {
+#ifdef ENOSPC
+ if (nwrote >= 0)
+ errno = ENOSPC;
+#endif
+ bfd_set_error (bfd_error_system_call);
+ }
+ return nwrote;
+}
+
+/*
+INTERNAL_FUNCTION
+ bfd_write_bigendian_4byte_int
+
+SYNOPSIS
+ void bfd_write_bigendian_4byte_int(bfd *abfd, int i);
+
+DESCRIPTION
+ Write a 4 byte integer @var{i} to the output BFD @var{abfd}, in big
+ endian order regardless of what else is going on. This is useful in
+ archives.
+
+*/
+void
+bfd_write_bigendian_4byte_int (abfd, i)
+ bfd *abfd;
+ int i;
+{
+ bfd_byte buffer[4];
+ bfd_putb32(i, buffer);
+ if (bfd_write((PTR)buffer, 4, 1, abfd) != 4)
+ abort ();
+}
+
+long
+bfd_tell (abfd)
+ bfd *abfd;
+{
+ file_ptr ptr;
+
+ ptr = ftell (bfd_cache_lookup(abfd));
+
+ if (abfd->my_archive)
+ ptr -= abfd->origin;
+ abfd->where = ptr;
+ return ptr;
+}
+
+int
+bfd_flush (abfd)
+ bfd *abfd;
+{
+ return fflush (bfd_cache_lookup(abfd));
+}
+
+int
+bfd_stat (abfd, statbuf)
+ bfd *abfd;
+ struct stat *statbuf;
+{
+ return fstat (fileno(bfd_cache_lookup(abfd)), statbuf);
+}
+
+/* Returns 0 for success, nonzero for failure (in which case bfd_get_error
+ can retrieve the error code). */
+
+int
+bfd_seek (abfd, position, direction)
+ bfd * CONST abfd;
+ CONST file_ptr position;
+ CONST int direction;
+{
+ int result;
+ FILE *f;
+ file_ptr file_position;
+ /* For the time being, a BFD may not seek to it's end. The problem
+ is that we don't easily have a way to recognize the end of an
+ element in an archive. */
+
+ BFD_ASSERT (direction == SEEK_SET || direction == SEEK_CUR);
+
+ if (direction == SEEK_CUR && position == 0)
+ return 0;
+#ifdef FILE_OFFSET_IS_CHAR_INDEX
+ if (abfd->format != bfd_archive && abfd->my_archive == 0)
+ {
+#if 0
+ /* Explanation for this code: I'm only about 95+% sure that the above
+ conditions are sufficient and that all i/o calls are properly
+ adjusting the `where' field. So this is sort of an `assert'
+ that the `where' field is correct. If we can go a while without
+ tripping the abort, we can probably safely disable this code,
+ so that the real optimizations happen. */
+ file_ptr where_am_i_now;
+ where_am_i_now = ftell (bfd_cache_lookup (abfd));
+ if (abfd->my_archive)
+ where_am_i_now -= abfd->origin;
+ if (where_am_i_now != abfd->where)
+ abort ();
+#endif
+ if (direction == SEEK_SET && position == abfd->where)
+ return 0;
+ }
+ else
+ {
+ /* We need something smarter to optimize access to archives.
+ Currently, anything inside an archive is read via the file
+ handle for the archive. Which means that a bfd_seek on one
+ component affects the `current position' in the archive, as
+ well as in any other component.
+
+ It might be sufficient to put a spike through the cache
+ abstraction, and look to the archive for the file position,
+ but I think we should try for something cleaner.
+
+ In the meantime, no optimization for archives. */
+ }
+#endif
+
+ f = bfd_cache_lookup (abfd);
+ file_position = position;
+ if (direction == SEEK_SET && abfd->my_archive != NULL)
+ file_position += abfd->origin;
+
+ result = fseek (f, file_position, direction);
+
+ if (result != 0)
+ {
+ /* Force redetermination of `where' field. */
+ bfd_tell (abfd);
+ bfd_set_error (bfd_error_system_call);
+ }
+ else
+ {
+#ifdef FILE_OFFSET_IS_CHAR_INDEX
+ /* Adjust `where' field. */
+ if (direction == SEEK_SET)
+ abfd->where = position;
+ else
+ abfd->where += position;
+#endif
+ }
+ return result;
+}
+
+/** Make a string table */
+
+/*>bfd.h<
+ Add string to table pointed to by table, at location starting with free_ptr.
+ resizes the table if necessary (if it's NULL, creates it, ignoring
+ table_length). Updates free_ptr, table, table_length */
+
+boolean
+bfd_add_to_string_table (table, new_string, table_length, free_ptr)
+ char **table;
+ char *new_string;
+ unsigned int *table_length;
+ char **free_ptr;
+{
+ size_t string_length = strlen (new_string) + 1; /* include null here */
+ char *base = *table;
+ size_t space_length = *table_length;
+ unsigned int offset = (base ? *free_ptr - base : 0);
+
+ if (base == NULL) {
+ /* Avoid a useless regrow if we can (but of course we still
+ take it next time). */
+ space_length = (string_length < DEFAULT_STRING_SPACE_SIZE ?
+ DEFAULT_STRING_SPACE_SIZE : string_length+1);
+ base = bfd_zmalloc ((bfd_size_type) space_length);
+
+ if (base == NULL) {
+ bfd_set_error (bfd_error_no_memory);
+ return false;
+ }
+ }
+
+ if ((size_t)(offset + string_length) >= space_length) {
+ /* Make sure we will have enough space */
+ while ((size_t)(offset + string_length) >= space_length)
+ space_length += space_length/2; /* grow by 50% */
+
+ base = (char *) realloc (base, space_length);
+ if (base == NULL) {
+ bfd_set_error (bfd_error_no_memory);
+ return false;
+ }
+
+ }
+
+ memcpy (base + offset, new_string, string_length);
+ *table = base;
+ *table_length = space_length;
+ *free_ptr = base + offset + string_length;
+
+ return true;
+}
+
+/** The do-it-yourself (byte) sex-change kit */
+
+/* The middle letter e.g. get<b>short indicates Big or Little endian
+ target machine. It doesn't matter what the byte order of the host
+ machine is; these routines work for either. */
+
+/* FIXME: Should these take a count argument?
+ Answer (gnu@cygnus.com): No, but perhaps they should be inline
+ functions in swap.h #ifdef __GNUC__.
+ Gprof them later and find out. */
+
+/*
+FUNCTION
+ bfd_put_size
+FUNCTION
+ bfd_get_size
+
+DESCRIPTION
+ These macros as used for reading and writing raw data in
+ sections; each access (except for bytes) is vectored through
+ the target format of the BFD and mangled accordingly. The
+ mangling performs any necessary endian translations and
+ removes alignment restrictions. Note that types accepted and
+ returned by these macros are identical so they can be swapped
+ around in macros---for example, @file{libaout.h} defines <<GET_WORD>>
+ to either <<bfd_get_32>> or <<bfd_get_64>>.
+
+ In the put routines, @var{val} must be a <<bfd_vma>>. If we are on a
+ system without prototypes, the caller is responsible for making
+ sure that is true, with a cast if necessary. We don't cast
+ them in the macro definitions because that would prevent <<lint>>
+ or <<gcc -Wall>> from detecting sins such as passing a pointer.
+ To detect calling these with less than a <<bfd_vma>>, use
+ <<gcc -Wconversion>> on a host with 64 bit <<bfd_vma>>'s.
+
+.
+.{* Byte swapping macros for user section data. *}
+.
+.#define bfd_put_8(abfd, val, ptr) \
+. (*((unsigned char *)(ptr)) = (unsigned char)(val))
+.#define bfd_put_signed_8 \
+. bfd_put_8
+.#define bfd_get_8(abfd, ptr) \
+. (*(unsigned char *)(ptr))
+.#define bfd_get_signed_8(abfd, ptr) \
+. ((*(unsigned char *)(ptr) ^ 0x80) - 0x80)
+.
+.#define bfd_put_16(abfd, val, ptr) \
+. BFD_SEND(abfd, bfd_putx16, ((val),(ptr)))
+.#define bfd_put_signed_16 \
+. bfd_put_16
+.#define bfd_get_16(abfd, ptr) \
+. BFD_SEND(abfd, bfd_getx16, (ptr))
+.#define bfd_get_signed_16(abfd, ptr) \
+. BFD_SEND (abfd, bfd_getx_signed_16, (ptr))
+.
+.#define bfd_put_32(abfd, val, ptr) \
+. BFD_SEND(abfd, bfd_putx32, ((val),(ptr)))
+.#define bfd_put_signed_32 \
+. bfd_put_32
+.#define bfd_get_32(abfd, ptr) \
+. BFD_SEND(abfd, bfd_getx32, (ptr))
+.#define bfd_get_signed_32(abfd, ptr) \
+. BFD_SEND(abfd, bfd_getx_signed_32, (ptr))
+.
+.#define bfd_put_64(abfd, val, ptr) \
+. BFD_SEND(abfd, bfd_putx64, ((val), (ptr)))
+.#define bfd_put_signed_64 \
+. bfd_put_64
+.#define bfd_get_64(abfd, ptr) \
+. BFD_SEND(abfd, bfd_getx64, (ptr))
+.#define bfd_get_signed_64(abfd, ptr) \
+. BFD_SEND(abfd, bfd_getx_signed_64, (ptr))
+.
+*/
+
+/*
+FUNCTION
+ bfd_h_put_size
+ bfd_h_get_size
+
+DESCRIPTION
+ These macros have the same function as their <<bfd_get_x>>
+ bretheren, except that they are used for removing information
+ for the header records of object files. Believe it or not,
+ some object files keep their header records in big endian
+ order and their data in little endian order.
+.
+.{* Byte swapping macros for file header data. *}
+.
+.#define bfd_h_put_8(abfd, val, ptr) \
+. bfd_put_8 (abfd, val, ptr)
+.#define bfd_h_put_signed_8(abfd, val, ptr) \
+. bfd_put_8 (abfd, val, ptr)
+.#define bfd_h_get_8(abfd, ptr) \
+. bfd_get_8 (abfd, ptr)
+.#define bfd_h_get_signed_8(abfd, ptr) \
+. bfd_get_signed_8 (abfd, ptr)
+.
+.#define bfd_h_put_16(abfd, val, ptr) \
+. BFD_SEND(abfd, bfd_h_putx16,(val,ptr))
+.#define bfd_h_put_signed_16 \
+. bfd_h_put_16
+.#define bfd_h_get_16(abfd, ptr) \
+. BFD_SEND(abfd, bfd_h_getx16,(ptr))
+.#define bfd_h_get_signed_16(abfd, ptr) \
+. BFD_SEND(abfd, bfd_h_getx_signed_16, (ptr))
+.
+.#define bfd_h_put_32(abfd, val, ptr) \
+. BFD_SEND(abfd, bfd_h_putx32,(val,ptr))
+.#define bfd_h_put_signed_32 \
+. bfd_h_put_32
+.#define bfd_h_get_32(abfd, ptr) \
+. BFD_SEND(abfd, bfd_h_getx32,(ptr))
+.#define bfd_h_get_signed_32(abfd, ptr) \
+. BFD_SEND(abfd, bfd_h_getx_signed_32, (ptr))
+.
+.#define bfd_h_put_64(abfd, val, ptr) \
+. BFD_SEND(abfd, bfd_h_putx64,(val, ptr))
+.#define bfd_h_put_signed_64 \
+. bfd_h_put_64
+.#define bfd_h_get_64(abfd, ptr) \
+. BFD_SEND(abfd, bfd_h_getx64,(ptr))
+.#define bfd_h_get_signed_64(abfd, ptr) \
+. BFD_SEND(abfd, bfd_h_getx_signed_64, (ptr))
+.
+*/
+
+/* Sign extension to bfd_signed_vma. */
+#define COERCE16(x) (((bfd_signed_vma) (x) ^ 0x8000) - 0x8000)
+#define COERCE32(x) (((bfd_signed_vma) (x) ^ 0x80000000) - 0x80000000)
+#define EIGHT_GAZILLION (((BFD_HOST_64_BIT)0x80000000) << 32)
+#define COERCE64(x) \
+ (((bfd_signed_vma) (x) ^ EIGHT_GAZILLION) - EIGHT_GAZILLION)
+
+bfd_vma
+bfd_getb16 (addr)
+ register const bfd_byte *addr;
+{
+ return (addr[0] << 8) | addr[1];
+}
+
+bfd_vma
+bfd_getl16 (addr)
+ register const bfd_byte *addr;
+{
+ return (addr[1] << 8) | addr[0];
+}
+
+bfd_signed_vma
+bfd_getb_signed_16 (addr)
+ register const bfd_byte *addr;
+{
+ return COERCE16((addr[0] << 8) | addr[1]);
+}
+
+bfd_signed_vma
+bfd_getl_signed_16 (addr)
+ register const bfd_byte *addr;
+{
+ return COERCE16((addr[1] << 8) | addr[0]);
+}
+
+void
+bfd_putb16 (data, addr)
+ bfd_vma data;
+ register bfd_byte *addr;
+{
+ addr[0] = (bfd_byte)(data >> 8);
+ addr[1] = (bfd_byte )data;
+}
+
+void
+bfd_putl16 (data, addr)
+ bfd_vma data;
+ register bfd_byte *addr;
+{
+ addr[0] = (bfd_byte )data;
+ addr[1] = (bfd_byte)(data >> 8);
+}
+
+bfd_vma
+bfd_getb32 (addr)
+ register const bfd_byte *addr;
+{
+ return (((((bfd_vma)addr[0] << 8) | addr[1]) << 8)
+ | addr[2]) << 8 | addr[3];
+}
+
+bfd_vma
+bfd_getl32 (addr)
+ register const bfd_byte *addr;
+{
+ return (((((bfd_vma)addr[3] << 8) | addr[2]) << 8)
+ | addr[1]) << 8 | addr[0];
+}
+
+bfd_signed_vma
+bfd_getb_signed_32 (addr)
+ register const bfd_byte *addr;
+{
+ return COERCE32((((((bfd_vma)addr[0] << 8) | addr[1]) << 8)
+ | addr[2]) << 8 | addr[3]);
+}
+
+bfd_signed_vma
+bfd_getl_signed_32 (addr)
+ register const bfd_byte *addr;
+{
+ return COERCE32((((((bfd_vma)addr[3] << 8) | addr[2]) << 8)
+ | addr[1]) << 8 | addr[0]);
+}
+
+bfd_vma
+bfd_getb64 (addr)
+ register const bfd_byte *addr;
+{
+#ifdef BFD64
+ bfd_vma low, high;
+
+ high= ((((((((addr[0]) << 8) |
+ addr[1]) << 8) |
+ addr[2]) << 8) |
+ addr[3]) );
+
+ low = (((((((((bfd_vma)addr[4]) << 8) |
+ addr[5]) << 8) |
+ addr[6]) << 8) |
+ addr[7]));
+
+ return high << 32 | low;
+#else
+ BFD_FAIL();
+ return 0;
+#endif
+}
+
+bfd_vma
+bfd_getl64 (addr)
+ register const bfd_byte *addr;
+{
+#ifdef BFD64
+ bfd_vma low, high;
+ high= (((((((addr[7] << 8) |
+ addr[6]) << 8) |
+ addr[5]) << 8) |
+ addr[4]));
+
+ low = ((((((((bfd_vma)addr[3] << 8) |
+ addr[2]) << 8) |
+ addr[1]) << 8) |
+ addr[0]) );
+
+ return high << 32 | low;
+#else
+ BFD_FAIL();
+ return 0;
+#endif
+
+}
+
+bfd_signed_vma
+bfd_getb_signed_64 (addr)
+ register const bfd_byte *addr;
+{
+#ifdef BFD64
+ bfd_vma low, high;
+
+ high= ((((((((addr[0]) << 8) |
+ addr[1]) << 8) |
+ addr[2]) << 8) |
+ addr[3]) );
+
+ low = (((((((((bfd_vma)addr[4]) << 8) |
+ addr[5]) << 8) |
+ addr[6]) << 8) |
+ addr[7]));
+
+ return COERCE64(high << 32 | low);
+#else
+ BFD_FAIL();
+ return 0;
+#endif
+}
+
+bfd_signed_vma
+bfd_getl_signed_64 (addr)
+ register const bfd_byte *addr;
+{
+#ifdef BFD64
+ bfd_vma low, high;
+ high= (((((((addr[7] << 8) |
+ addr[6]) << 8) |
+ addr[5]) << 8) |
+ addr[4]));
+
+ low = ((((((((bfd_vma)addr[3] << 8) |
+ addr[2]) << 8) |
+ addr[1]) << 8) |
+ addr[0]) );
+
+ return COERCE64(high << 32 | low);
+#else
+ BFD_FAIL();
+ return 0;
+#endif
+}
+
+void
+bfd_putb32 (data, addr)
+ bfd_vma data;
+ register bfd_byte *addr;
+{
+ addr[0] = (bfd_byte)(data >> 24);
+ addr[1] = (bfd_byte)(data >> 16);
+ addr[2] = (bfd_byte)(data >> 8);
+ addr[3] = (bfd_byte)data;
+}
+
+void
+bfd_putl32 (data, addr)
+ bfd_vma data;
+ register bfd_byte *addr;
+{
+ addr[0] = (bfd_byte)data;
+ addr[1] = (bfd_byte)(data >> 8);
+ addr[2] = (bfd_byte)(data >> 16);
+ addr[3] = (bfd_byte)(data >> 24);
+}
+
+void
+bfd_putb64 (data, addr)
+ bfd_vma data;
+ register bfd_byte *addr;
+{
+#ifdef BFD64
+ addr[0] = (bfd_byte)(data >> (7*8));
+ addr[1] = (bfd_byte)(data >> (6*8));
+ addr[2] = (bfd_byte)(data >> (5*8));
+ addr[3] = (bfd_byte)(data >> (4*8));
+ addr[4] = (bfd_byte)(data >> (3*8));
+ addr[5] = (bfd_byte)(data >> (2*8));
+ addr[6] = (bfd_byte)(data >> (1*8));
+ addr[7] = (bfd_byte)(data >> (0*8));
+#else
+ BFD_FAIL();
+#endif
+}
+
+void
+bfd_putl64 (data, addr)
+ bfd_vma data;
+ register bfd_byte *addr;
+{
+#ifdef BFD64
+ addr[7] = (bfd_byte)(data >> (7*8));
+ addr[6] = (bfd_byte)(data >> (6*8));
+ addr[5] = (bfd_byte)(data >> (5*8));
+ addr[4] = (bfd_byte)(data >> (4*8));
+ addr[3] = (bfd_byte)(data >> (3*8));
+ addr[2] = (bfd_byte)(data >> (2*8));
+ addr[1] = (bfd_byte)(data >> (1*8));
+ addr[0] = (bfd_byte)(data >> (0*8));
+#else
+ BFD_FAIL();
+#endif
+}
+
+/* Default implementation */
+
+boolean
+_bfd_generic_get_section_contents (abfd, section, location, offset, count)
+ bfd *abfd;
+ sec_ptr section;
+ PTR location;
+ file_ptr offset;
+ bfd_size_type count;
+{
+ if (count == 0)
+ return true;
+ if ((bfd_size_type)(offset+count) > section->_raw_size
+ || bfd_seek(abfd, (file_ptr)(section->filepos + offset), SEEK_SET) == -1
+ || bfd_read(location, (bfd_size_type)1, count, abfd) != count)
+ return (false); /* on error */
+ return (true);
+}
+
+/* This generic function can only be used in implementations where creating
+ NEW sections is disallowed. It is useful in patching existing sections
+ in read-write files, though. See other set_section_contents functions
+ to see why it doesn't work for new sections. */
+boolean
+_bfd_generic_set_section_contents (abfd, section, location, offset, count)
+ bfd *abfd;
+ sec_ptr section;
+ PTR location;
+ file_ptr offset;
+ bfd_size_type count;
+{
+ if (count == 0)
+ return true;
+
+ if (bfd_seek (abfd, (file_ptr) (section->filepos + offset), SEEK_SET) == -1
+ || bfd_write (location, (bfd_size_type) 1, count, abfd) != count)
+ return false;
+
+ return true;
+}
+
+/*
+INTERNAL_FUNCTION
+ bfd_log2
+
+SYNOPSIS
+ unsigned int bfd_log2(bfd_vma x);
+
+DESCRIPTION
+ Return the log base 2 of the value supplied, rounded up. E.g., an
+ @var{x} of 1025 returns 11.
+*/
+
+unsigned
+bfd_log2(x)
+ bfd_vma x;
+{
+ unsigned result = 0;
+ while ( (bfd_vma)(1<< result) < x)
+ result++;
+ return result;
+}
+
+boolean
+bfd_generic_is_local_label (abfd, sym)
+ bfd *abfd;
+ asymbol *sym;
+{
+ char locals_prefix = (bfd_get_symbol_leading_char (abfd) == '_') ? 'L' : '.';
+
+ return (sym->name[0] == locals_prefix);
+}
+
diff --git a/gnu/usr.bin/gdb/bfd/libbfd.h b/gnu/usr.bin/gdb/bfd/libbfd.h
new file mode 100644
index 0000000..89e4c81
--- /dev/null
+++ b/gnu/usr.bin/gdb/bfd/libbfd.h
@@ -0,0 +1,488 @@
+/* libbfd.h -- Declarations used by bfd library *implementation*.
+ (This include file is not for users of the library.)
+ Copyright 1990, 1991, 1992, 1993, 1994 Free Software Foundation, Inc.
+ Written by Cygnus Support.
+
+** NOTE: libbfd.h is a GENERATED file. Don't change it; instead,
+** change libbfd-in.h or the other BFD source files processed to
+** generate this file.
+
+This file is part of BFD, the Binary File Descriptor library.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* Align an address upward to a boundary, expressed as a number of bytes.
+ E.g. align to an 8-byte boundary with argument of 8. */
+#define BFD_ALIGN(this, boundary) \
+ ((( (this) + ((boundary) -1)) & (~((boundary)-1))))
+
+/* If you want to read and write large blocks, you might want to do it
+ in quanta of this amount */
+#define DEFAULT_BUFFERSIZE 8192
+
+/* Set a tdata field. Can't use the other macros for this, since they
+ do casts, and casting to the left of assignment isn't portable. */
+#define set_tdata(bfd, v) ((bfd)->tdata.any = (PTR) (v))
+
+/* tdata for an archive. For an input archive, cache
+ needs to be free()'d. For an output archive, symdefs do. */
+
+struct artdata {
+ file_ptr first_file_filepos;
+ /* Speed up searching the armap */
+ struct ar_cache *cache;
+ bfd *archive_head; /* Only interesting in output routines */
+ carsym *symdefs; /* the symdef entries */
+ symindex symdef_count; /* how many there are */
+ char *extended_names; /* clever intel extension */
+ /* when more compilers are standard C, this can be a time_t */
+ long armap_timestamp; /* Timestamp value written into armap.
+ This is used for BSD archives to check
+ that the timestamp is recent enough
+ for the BSD linker to not complain,
+ just before we finish writing an
+ archive. */
+ file_ptr armap_datepos; /* Position within archive to seek to
+ rewrite the date field. */
+ PTR tdata; /* Backend specific information. */
+};
+
+#define bfd_ardata(bfd) ((bfd)->tdata.aout_ar_data)
+
+/* Goes in bfd's arelt_data slot */
+struct areltdata {
+ char * arch_header; /* it's actually a string */
+ unsigned int parsed_size; /* octets of filesize not including ar_hdr */
+ char *filename; /* null-terminated */
+};
+
+#define arelt_size(bfd) (((struct areltdata *)((bfd)->arelt_data))->parsed_size)
+
+char *bfd_zmalloc PARAMS ((bfd_size_type size));
+
+/* These routines allocate and free things on the BFD's obstack. Note
+ that realloc can never occur in place. */
+
+PTR bfd_alloc PARAMS ((bfd *abfd, size_t size));
+PTR bfd_zalloc PARAMS ((bfd *abfd, size_t size));
+PTR bfd_realloc PARAMS ((bfd *abfd, PTR orig, size_t size));
+void bfd_alloc_grow PARAMS ((bfd *abfd, PTR thing, size_t size));
+PTR bfd_alloc_finish PARAMS ((bfd *abfd));
+PTR bfd_alloc_by_size_t PARAMS ((bfd *abfd, size_t wanted));
+
+#define bfd_release(x,y) (void) obstack_free(&(x->memory),y)
+
+
+bfd_size_type bfd_read PARAMS ((PTR ptr, bfd_size_type size,
+ bfd_size_type nitems, bfd *abfd));
+bfd_size_type bfd_write PARAMS ((CONST PTR ptr, bfd_size_type size,
+ bfd_size_type nitems, bfd *abfd));
+int bfd_seek PARAMS ((bfd* CONST abfd, CONST file_ptr fp,
+ CONST int direction));
+long bfd_tell PARAMS ((bfd *abfd));
+
+int bfd_flush PARAMS ((bfd *abfd));
+int bfd_stat PARAMS ((bfd *abfd, struct stat *));
+
+bfd * _bfd_create_empty_archive_element_shell PARAMS ((bfd *obfd));
+bfd * _bfd_look_for_bfd_in_cache PARAMS ((bfd *arch_bfd, file_ptr index));
+boolean _bfd_add_bfd_to_archive_cache PARAMS ((bfd *, file_ptr, bfd *));
+boolean _bfd_generic_mkarchive PARAMS ((bfd *abfd));
+struct areltdata *_bfd_snarf_ar_hdr PARAMS ((bfd *abfd));
+const bfd_target *bfd_generic_archive_p PARAMS ((bfd *abfd));
+boolean bfd_slurp_armap PARAMS ((bfd *abfd));
+boolean bfd_slurp_bsd_armap_f2 PARAMS ((bfd *abfd));
+#define bfd_slurp_bsd_armap bfd_slurp_armap
+#define bfd_slurp_coff_armap bfd_slurp_armap
+boolean _bfd_slurp_extended_name_table PARAMS ((bfd *abfd));
+boolean _bfd_write_archive_contents PARAMS ((bfd *abfd));
+bfd *_bfd_get_elt_at_filepos PARAMS ((bfd *archive, file_ptr filepos));
+bfd * _bfd_new_bfd PARAMS ((void));
+
+#define DEFAULT_STRING_SPACE_SIZE 0x2000
+boolean bfd_add_to_string_table PARAMS ((char **table, char *new_string,
+ unsigned int *table_length,
+ char **free_ptr));
+
+boolean bfd_false PARAMS ((bfd *ignore));
+boolean bfd_true PARAMS ((bfd *ignore));
+PTR bfd_nullvoidptr PARAMS ((bfd *ignore));
+int bfd_0 PARAMS ((bfd *ignore));
+unsigned int bfd_0u PARAMS ((bfd *ignore));
+long bfd_0l PARAMS ((bfd *ignore));
+long _bfd_n1 PARAMS ((bfd *ignore));
+void bfd_void PARAMS ((bfd *ignore));
+
+bfd *_bfd_new_bfd_contained_in PARAMS ((bfd *));
+const bfd_target *_bfd_dummy_target PARAMS ((bfd *abfd));
+
+void bfd_dont_truncate_arname PARAMS ((bfd *abfd, CONST char *filename,
+ char *hdr));
+void bfd_bsd_truncate_arname PARAMS ((bfd *abfd, CONST char *filename,
+ char *hdr));
+void bfd_gnu_truncate_arname PARAMS ((bfd *abfd, CONST char *filename,
+ char *hdr));
+
+boolean bsd_write_armap PARAMS ((bfd *arch, unsigned int elength,
+ struct orl *map, unsigned int orl_count, int stridx));
+
+boolean coff_write_armap PARAMS ((bfd *arch, unsigned int elength,
+ struct orl *map, unsigned int orl_count, int stridx));
+
+bfd * bfd_generic_openr_next_archived_file PARAMS ((bfd *archive,
+ bfd *last_file));
+
+int bfd_generic_stat_arch_elt PARAMS ((bfd *, struct stat *));
+
+
+/* Generic routines to use for BFD_JUMP_TABLE_GENERIC. Use
+ BFD_JUMP_TABLE_GENERIC (_bfd_generic). */
+
+#define _bfd_generic_close_and_cleanup bfd_true
+#define _bfd_generic_bfd_free_cached_info bfd_true
+#define _bfd_generic_new_section_hook \
+ ((boolean (*) PARAMS ((bfd *, asection *))) bfd_true)
+extern boolean _bfd_generic_get_section_contents
+ PARAMS ((bfd *, asection *, PTR location, file_ptr offset,
+ bfd_size_type count));
+
+/* Generic routines to use for BFD_JUMP_TABLE_COPY. Use
+ BFD_JUMP_TABLE_COPY (_bfd_generic). */
+
+#define _bfd_generic_bfd_copy_private_bfd_data \
+ ((boolean (*) PARAMS ((bfd *, bfd *))) bfd_true)
+#define _bfd_generic_bfd_copy_private_section_data \
+ ((boolean (*) PARAMS ((bfd *, asection *, bfd *, asection *))) bfd_true)
+
+/* Routines to use for BFD_JUMP_TABLE_CORE when there is no core file
+ support. Use BFD_JUMP_TABLE_CORE (_bfd_nocore). */
+
+extern char *_bfd_nocore_core_file_failing_command PARAMS ((bfd *));
+extern int _bfd_nocore_core_file_failing_signal PARAMS ((bfd *));
+extern boolean _bfd_nocore_core_file_matches_executable_p
+ PARAMS ((bfd *, bfd *));
+
+/* Routines to use for BFD_JUMP_TABLE_ARCHIVE when there is no archive
+ file support. Use BFD_JUMP_TABLE_ARCHIVE (_bfd_noarchive). */
+
+#define _bfd_noarchive_slurp_armap bfd_false
+#define _bfd_noarchive_slurp_extended_name_table bfd_false
+#define _bfd_noarchive_truncate_arname \
+ ((void (*) PARAMS ((bfd *, const char *, char *))) bfd_void)
+#define _bfd_noarchive_write_armap \
+ ((boolean (*) \
+ PARAMS ((bfd *, unsigned int, struct orl *, unsigned int, int))) \
+ bfd_false)
+#define _bfd_noarchive_openr_next_archived_file \
+ ((bfd *(*) PARAMS ((bfd *, bfd *))) bfd_nullvoidptr)
+#define _bfd_noarchive_generic_stat_arch_elt bfd_generic_stat_arch_elt
+
+/* Routines to use for BFD_JUMP_TABLE_ARCHIVE to get BSD style
+ archives. Use BFD_JUMP_TABLE_ARCHIVE (_bfd_archive_bsd). */
+
+#define _bfd_archive_bsd_slurp_armap bfd_slurp_bsd_armap
+#define _bfd_archive_bsd_slurp_extended_name_table \
+ _bfd_slurp_extended_name_table
+#define _bfd_archive_bsd_truncate_arname bfd_bsd_truncate_arname
+#define _bfd_archive_bsd_write_armap bsd_write_armap
+#define _bfd_archive_bsd_openr_next_archived_file \
+ bfd_generic_openr_next_archived_file
+#define _bfd_archive_bsd_generic_stat_arch_elt \
+ bfd_generic_stat_arch_elt
+
+/* Routines to use for BFD_JUMP_TABLE_ARCHIVE to get COFF style
+ archives. Use BFD_JUMP_TABLE_ARCHIVE (_bfd_archive_coff). */
+
+#define _bfd_archive_coff_slurp_armap bfd_slurp_coff_armap
+#define _bfd_archive_coff_slurp_extended_name_table \
+ _bfd_slurp_extended_name_table
+#define _bfd_archive_coff_truncate_arname bfd_dont_truncate_arname
+#define _bfd_archive_coff_write_armap coff_write_armap
+#define _bfd_archive_coff_openr_next_archived_file \
+ bfd_generic_openr_next_archived_file
+#define _bfd_archive_coff_generic_stat_arch_elt \
+ bfd_generic_stat_arch_elt
+
+/* Routines to use for BFD_JUMP_TABLE_SYMBOLS where there is no symbol
+ support. Use BFD_JUMP_TABLE_SYMBOLS (_bfd_nosymbols). */
+
+#define _bfd_nosymbols_get_symtab_upper_bound _bfd_n1
+#define _bfd_nosymbols_get_symtab \
+ ((long (*) PARAMS ((bfd *, asymbol **))) _bfd_n1)
+#define _bfd_nosymbols_make_empty_symbol \
+ ((asymbol *(*) PARAMS ((bfd *))) bfd_nullvoidptr)
+#define _bfd_nosymbols_print_symbol \
+ ((void (*) PARAMS ((bfd *, PTR, asymbol *, bfd_print_symbol_type))) bfd_void)
+#define _bfd_nosymbols_get_symbol_info \
+ ((void (*) PARAMS ((bfd *, asymbol *, symbol_info *))) bfd_void)
+#define _bfd_nosymbols_bfd_is_local_label \
+ ((boolean (*) PARAMS ((bfd *, asymbol *))) bfd_false)
+#define _bfd_nosymbols_get_lineno \
+ ((alent *(*) PARAMS ((bfd *, asymbol *))) bfd_nullvoidptr)
+#define _bfd_nosymbols_find_nearest_line \
+ ((boolean (*) \
+ PARAMS ((bfd *, asection *, asymbol **, bfd_vma, const char **, \
+ const char **, unsigned int *))) \
+ bfd_false)
+#define _bfd_nosymbols_bfd_make_debug_symbol \
+ ((asymbol *(*) PARAMS ((bfd *, PTR, unsigned long))) bfd_nullvoidptr)
+
+/* Routines to use for BFD_JUMP_TABLE_RELOCS when there is no reloc
+ support. Use BFD_JUMP_TABLE_RELOCS (_bfd_norelocs). */
+
+#define _bfd_norelocs_get_reloc_upper_bound \
+ ((long (*) PARAMS ((bfd *, asection *))) _bfd_n1)
+#define _bfd_norelocs_canonicalize_reloc \
+ ((long (*) PARAMS ((bfd *, asection *, arelent **, asymbol **))) _bfd_n1)
+#define _bfd_norelocs_bfd_reloc_type_lookup \
+ ((const reloc_howto_type *(*) PARAMS ((bfd *, bfd_reloc_code_real_type))) \
+ bfd_nullvoidptr)
+
+/* Routines to use for BFD_JUMP_TABLE_WRITE for targets which may not
+ be written. Use BFD_JUMP_TABLE_WRITE (_bfd_nowrite). */
+
+#define _bfd_nowrite_set_arch_mach \
+ ((boolean (*) PARAMS ((bfd *, enum bfd_architecture, unsigned long))) \
+ bfd_false)
+#define _bfd_nowrite_set_section_contents \
+ ((boolean (*) PARAMS ((bfd *, asection *, PTR, file_ptr, bfd_size_type))) \
+ bfd_false)
+
+/* Generic routines to use for BFD_JUMP_TABLE_WRITE. Use
+ BFD_JUMP_TABLE_WRITE (_bfd_generic). */
+
+#define _bfd_generic_set_arch_mach bfd_default_set_arch_mach
+extern boolean _bfd_generic_set_section_contents
+ PARAMS ((bfd *, asection *, PTR, file_ptr, bfd_size_type));
+
+/* Routines to use for BFD_JUMP_TABLE_LINK for targets which do not
+ support linking. Use BFD_JUMP_TABLE_LINK (_bfd_nolink). */
+
+#define _bfd_nolink_sizeof_headers ((int (*) PARAMS ((bfd *, boolean))) bfd_0)
+#define _bfd_nolink_bfd_get_relocated_section_contents \
+ ((bfd_byte *(*) \
+ PARAMS ((bfd *, struct bfd_link_info *, struct bfd_link_order *, \
+ bfd_byte *, boolean, asymbol **))) \
+ bfd_nullvoidptr)
+#define _bfd_nolink_bfd_relax_section \
+ ((boolean (*) \
+ PARAMS ((bfd *, asection *, struct bfd_link_info *, boolean *))) \
+ bfd_false)
+#define _bfd_nolink_bfd_link_hash_table_create \
+ ((struct bfd_link_hash_table *(*) PARAMS ((bfd *))) bfd_nullvoidptr)
+#define _bfd_nolink_bfd_link_add_symbols \
+ ((boolean (*) PARAMS ((bfd *, struct bfd_link_info *))) bfd_false)
+#define _bfd_nolink_bfd_final_link \
+ ((boolean (*) PARAMS ((bfd *, struct bfd_link_info *))) bfd_false)
+
+/* Routines to use for BFD_JUMP_TABLE_DYNAMIC for targets which do not
+ have dynamic symbols or relocs. Use BFD_JUMP_TABLE_DYNAMIC
+ (_bfd_nodynamic). */
+
+#define _bfd_nodynamic_get_dynamic_symtab_upper_bound _bfd_n1
+#define _bfd_nodynamic_canonicalize_dynamic_symtab \
+ ((long (*) PARAMS ((bfd *, asymbol **))) _bfd_n1)
+#define _bfd_nodynamic_get_dynamic_reloc_upper_bound _bfd_n1
+#define _bfd_nodynamic_canonicalize_dynamic_reloc \
+ ((long (*) PARAMS ((bfd *, arelent **, asymbol **))) _bfd_n1)
+
+/* Generic routine to determine of the given symbol is a local
+ label. */
+extern boolean bfd_generic_is_local_label PARAMS ((bfd *, asymbol *));
+
+/* A routine to create entries for a bfd_link_hash_table. */
+extern struct bfd_hash_entry *_bfd_link_hash_newfunc
+ PARAMS ((struct bfd_hash_entry *entry,
+ struct bfd_hash_table *table,
+ const char *string));
+
+/* Initialize a bfd_link_hash_table. */
+extern boolean _bfd_link_hash_table_init
+ PARAMS ((struct bfd_link_hash_table *, bfd *,
+ struct bfd_hash_entry *(*) (struct bfd_hash_entry *,
+ struct bfd_hash_table *,
+ const char *)));
+
+/* Generic link hash table creation routine. */
+extern struct bfd_link_hash_table *_bfd_generic_link_hash_table_create
+ PARAMS ((bfd *));
+
+/* Generic add symbol routine. */
+extern boolean _bfd_generic_link_add_symbols
+ PARAMS ((bfd *, struct bfd_link_info *));
+
+/* Generic add symbol routine. This version is used by targets for
+ which the linker must collect constructors and destructors by name,
+ as the collect2 program does. */
+extern boolean _bfd_generic_link_add_symbols_collect
+ PARAMS ((bfd *, struct bfd_link_info *));
+
+/* Generic archive add symbol routine. */
+extern boolean _bfd_generic_link_add_archive_symbols
+ PARAMS ((bfd *, struct bfd_link_info *,
+ boolean (*checkfn) (bfd *, struct bfd_link_info *, boolean *)));
+
+/* Forward declaration to avoid prototype errors. */
+typedef struct bfd_link_hash_entry _bfd_link_hash_entry;
+
+/* Generic routine to add a single symbol. */
+extern boolean _bfd_generic_link_add_one_symbol
+ PARAMS ((struct bfd_link_info *, bfd *, const char *name, flagword,
+ asection *, bfd_vma, const char *, boolean copy,
+ boolean constructor, struct bfd_link_hash_entry **));
+
+/* Generic link routine. */
+extern boolean _bfd_generic_final_link
+ PARAMS ((bfd *, struct bfd_link_info *));
+
+/* Generic reloc_link_order processing routine. */
+extern boolean _bfd_generic_reloc_link_order
+ PARAMS ((bfd *, struct bfd_link_info *, asection *,
+ struct bfd_link_order *));
+
+/* Default link order processing routine. */
+extern boolean _bfd_default_link_order
+ PARAMS ((bfd *, struct bfd_link_info *, asection *,
+ struct bfd_link_order *));
+
+/* Count the number of reloc entries in a link order list. */
+extern unsigned int _bfd_count_link_order_relocs
+ PARAMS ((struct bfd_link_order *));
+
+/* Final link relocation routine. */
+extern bfd_reloc_status_type _bfd_final_link_relocate
+ PARAMS ((const reloc_howto_type *, bfd *, asection *, bfd_byte *,
+ bfd_vma address, bfd_vma value, bfd_vma addend));
+
+/* Relocate a particular location by a howto and a value. */
+extern bfd_reloc_status_type _bfd_relocate_contents
+ PARAMS ((const reloc_howto_type *, bfd *, bfd_vma, bfd_byte *));
+
+/* Macros to tell if bfds are read or write enabled.
+
+ Note that bfds open for read may be scribbled into if the fd passed
+ to bfd_fdopenr is actually open both for read and write
+ simultaneously. However an output bfd will never be open for
+ read. Therefore sometimes you want to check bfd_read_p or
+ !bfd_read_p, and only sometimes bfd_write_p.
+*/
+
+#define bfd_read_p(abfd) ((abfd)->direction == read_direction || (abfd)->direction == both_direction)
+#define bfd_write_p(abfd) ((abfd)->direction == write_direction || (abfd)->direction == both_direction)
+
+void bfd_assert PARAMS ((char*,int));
+
+#define BFD_ASSERT(x) \
+{ if (!(x)) bfd_assert(__FILE__,__LINE__); }
+
+#define BFD_FAIL() \
+{ bfd_assert(__FILE__,__LINE__); }
+
+FILE * bfd_cache_lookup_worker PARAMS ((bfd *));
+
+extern bfd *bfd_last_cache;
+
+/* Now Steve, what's the story here? */
+#ifdef lint
+#define itos(x) "l"
+#define stoi(x) 1
+#else
+#define itos(x) ((char*)(x))
+#define stoi(x) ((int)(x))
+#endif
+
+/* List of supported target vectors, and the default vector (if
+ bfd_default_vector[0] is NULL, there is no default). */
+extern const bfd_target * const bfd_target_vector[];
+extern const bfd_target * const bfd_default_vector[];
+
+/* And more follows */
+
+void
+bfd_check_init PARAMS ((void));
+
+void
+bfd_write_bigendian_4byte_int PARAMS ((bfd *abfd, int i));
+
+unsigned int
+bfd_log2 PARAMS ((bfd_vma x));
+
+#define BFD_CACHE_MAX_OPEN 10
+extern bfd *bfd_last_cache;
+
+#define bfd_cache_lookup(x) \
+ ((x)==bfd_last_cache? \
+ (FILE*)(bfd_last_cache->iostream): \
+ bfd_cache_lookup_worker(x))
+boolean
+bfd_cache_init PARAMS ((bfd *abfd));
+
+boolean
+bfd_cache_close PARAMS ((bfd *abfd));
+
+FILE*
+bfd_open_file PARAMS ((bfd *abfd));
+
+FILE *
+bfd_cache_lookup_worker PARAMS ((bfd *abfd));
+
+boolean
+bfd_constructor_entry PARAMS ((bfd *abfd,
+ asymbol **symbol_ptr_ptr,
+ CONST char*type));
+
+const struct reloc_howto_struct *
+bfd_default_reloc_type_lookup
+ PARAMS ((bfd *abfd, bfd_reloc_code_real_type code));
+
+boolean
+bfd_generic_relax_section
+ PARAMS ((bfd *abfd,
+ asection *section,
+ struct bfd_link_info *,
+ boolean *));
+
+bfd_byte *
+
+bfd_generic_get_relocated_section_contents PARAMS ((bfd *abfd,
+ struct bfd_link_info *link_info,
+ struct bfd_link_order *link_order,
+ bfd_byte *data,
+ boolean relocateable,
+ asymbol **symbols));
+
+extern bfd_arch_info_type bfd_default_arch_struct;
+boolean
+bfd_default_set_arch_mach PARAMS ((bfd *abfd,
+ enum bfd_architecture arch,
+ unsigned long mach));
+
+void
+bfd_arch_init PARAMS ((void));
+
+void
+bfd_arch_linkin PARAMS ((bfd_arch_info_type *ptr));
+
+CONST bfd_arch_info_type *
+bfd_default_compatible
+ PARAMS ((CONST bfd_arch_info_type *a,
+ CONST bfd_arch_info_type *b));
+
+boolean
+bfd_default_scan PARAMS ((CONST struct bfd_arch_info *info, CONST char *string));
+
+struct elf_internal_shdr *
+bfd_elf_find_section PARAMS ((bfd *abfd, char *name));
+
diff --git a/gnu/usr.bin/gdb/bfd/libcoff.h b/gnu/usr.bin/gdb/bfd/libcoff.h
new file mode 100644
index 0000000..a564f11
--- /dev/null
+++ b/gnu/usr.bin/gdb/bfd/libcoff.h
@@ -0,0 +1,369 @@
+/* BFD COFF object file private structure.
+ Copyright (C) 1990, 1991, 1992, 1993, 1994 Free Software Foundation, Inc.
+ Written by Cygnus Support.
+
+This file is part of BFD, the Binary File Descriptor library.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+
+/* Object file tdata; access macros */
+
+#define coff_data(bfd) ((bfd)->tdata.coff_obj_data)
+#define exec_hdr(bfd) (coff_data(bfd)->hdr)
+#define obj_symbols(bfd) (coff_data(bfd)->symbols)
+#define obj_sym_filepos(bfd) (coff_data(bfd)->sym_filepos)
+
+#define obj_relocbase(bfd) (coff_data(bfd)->relocbase)
+#define obj_raw_syments(bfd) (coff_data(bfd)->raw_syments)
+#define obj_raw_syment_count(bfd) (coff_data(bfd)->raw_syment_count)
+#define obj_convert(bfd) (coff_data(bfd)->conversion_table)
+#define obj_conv_table_size(bfd) (coff_data(bfd)->conv_table_size)
+#if CFILE_STUFF
+#define obj_symbol_slew(bfd) (coff_data(bfd)->symbol_index_slew)
+#else
+#define obj_symbol_slew(bfd) 0
+#endif
+
+
+/* `Tdata' information kept for COFF files. */
+
+typedef struct coff_tdata
+{
+ struct coff_symbol_struct *symbols; /* symtab for input bfd */
+ unsigned int *conversion_table;
+ int conv_table_size;
+ file_ptr sym_filepos;
+
+ long symbol_index_slew; /* used during read to mark whether a
+ C_FILE symbol as been added. */
+
+ struct coff_ptr_struct *raw_syments;
+ struct lineno *raw_linenos;
+ unsigned int raw_syment_count;
+ unsigned short flags;
+
+ /* These are only valid once writing has begun */
+ long int relocbase;
+
+ /* These members communicate important constants about the symbol table
+ to GDB's symbol-reading code. These `constants' unfortunately vary
+ from coff implementation to implementation... */
+ unsigned local_n_btmask;
+ unsigned local_n_btshft;
+ unsigned local_n_tmask;
+ unsigned local_n_tshift;
+ unsigned local_symesz;
+ unsigned local_auxesz;
+ unsigned local_linesz;
+} coff_data_type;
+
+/* We take the address of the first element of a asymbol to ensure that the
+ * macro is only ever applied to an asymbol. */
+#define coffsymbol(asymbol) ((coff_symbol_type *)(&((asymbol)->the_bfd)))
+
+/* Functions in coffgen.c. */
+extern const bfd_target *coff_object_p PARAMS ((bfd *));
+extern struct sec *coff_section_from_bfd_index PARAMS ((bfd *, int));
+extern long coff_get_symtab_upper_bound PARAMS ((bfd *));
+extern long coff_get_symtab PARAMS ((bfd *, asymbol **));
+extern int coff_count_linenumbers PARAMS ((bfd *));
+extern struct coff_symbol_struct *coff_symbol_from PARAMS ((bfd *, asymbol *));
+extern boolean coff_renumber_symbols PARAMS ((bfd *));
+extern void coff_mangle_symbols PARAMS ((bfd *));
+extern boolean coff_write_symbols PARAMS ((bfd *));
+extern boolean coff_write_linenumbers PARAMS ((bfd *));
+extern alent *coff_get_lineno PARAMS ((bfd *, asymbol *));
+extern asymbol *coff_section_symbol PARAMS ((bfd *, char *));
+extern struct coff_ptr_struct *coff_get_normalized_symtab PARAMS ((bfd *));
+extern long coff_get_reloc_upper_bound PARAMS ((bfd *, sec_ptr));
+extern asymbol *coff_make_empty_symbol PARAMS ((bfd *));
+extern void coff_print_symbol PARAMS ((bfd *, PTR filep, asymbol *,
+ bfd_print_symbol_type how));
+extern void coff_get_symbol_info PARAMS ((bfd *, asymbol *,
+ symbol_info *ret));
+extern asymbol *coff_bfd_make_debug_symbol PARAMS ((bfd *, PTR,
+ unsigned long));
+extern boolean coff_find_nearest_line PARAMS ((bfd *,
+ asection *,
+ asymbol **,
+ bfd_vma offset,
+ CONST char **filename_ptr,
+ CONST char **functionname_ptr,
+ unsigned int *line_ptr));
+extern int coff_sizeof_headers PARAMS ((bfd *, boolean reloc));
+extern boolean bfd_coff_reloc16_relax_section
+ PARAMS ((bfd *, asection *, struct bfd_link_info *, boolean *));
+extern bfd_byte *bfd_coff_reloc16_get_relocated_section_contents
+ PARAMS ((bfd *, struct bfd_link_info *, struct bfd_link_order *,
+ bfd_byte *, boolean relocateable, asymbol **));
+extern bfd_vma bfd_coff_reloc16_get_value PARAMS ((arelent *,
+ struct bfd_link_info *,
+ asection *));
+extern void bfd_perform_slip PARAMS ((bfd *abfd, unsigned int slip,
+ asection *input_section,
+ bfd_vma val));
+
+/* And more taken from the source .. */
+
+typedef struct coff_ptr_struct
+{
+
+ /* Remembers the offset from the first symbol in the file for
+ this symbol. Generated by coff_renumber_symbols. */
+unsigned int offset;
+
+ /* Should the value of this symbol be renumbered. Used for
+ XCOFF C_BSTAT symbols. Set by coff_slurp_symbol_table. */
+unsigned int fix_value : 1;
+
+ /* Should the tag field of this symbol be renumbered.
+ Created by coff_pointerize_aux. */
+unsigned int fix_tag : 1;
+
+ /* Should the endidx field of this symbol be renumbered.
+ Created by coff_pointerize_aux. */
+unsigned int fix_end : 1;
+
+ /* Should the x_csect.x_scnlen field be renumbered.
+ Created by coff_slurp_symbol_table. */
+unsigned int fix_scnlen : 1;
+
+ /* The container for the symbol structure as read and translated
+ from the file. */
+
+union {
+ union internal_auxent auxent;
+ struct internal_syment syment;
+ } u;
+} combined_entry_type;
+
+
+ /* Each canonical asymbol really looks like this: */
+
+typedef struct coff_symbol_struct
+{
+ /* The actual symbol which the rest of BFD works with */
+asymbol symbol;
+
+ /* A pointer to the hidden information for this symbol */
+combined_entry_type *native;
+
+ /* A pointer to the linenumber information for this symbol */
+struct lineno_cache_entry *lineno;
+
+ /* Have the line numbers been relocated yet ? */
+boolean done_lineno;
+} coff_symbol_type;
+typedef struct
+{
+ void (*_bfd_coff_swap_aux_in) PARAMS ((
+ bfd *abfd,
+ PTR ext,
+ int type,
+ int class,
+ int indaux,
+ int numaux,
+ PTR in));
+
+ void (*_bfd_coff_swap_sym_in) PARAMS ((
+ bfd *abfd ,
+ PTR ext,
+ PTR in));
+
+ void (*_bfd_coff_swap_lineno_in) PARAMS ((
+ bfd *abfd,
+ PTR ext,
+ PTR in));
+
+ unsigned int (*_bfd_coff_swap_aux_out) PARAMS ((
+ bfd *abfd,
+ PTR in,
+ int type,
+ int class,
+ int indaux,
+ int numaux,
+ PTR ext));
+
+ unsigned int (*_bfd_coff_swap_sym_out) PARAMS ((
+ bfd *abfd,
+ PTR in,
+ PTR ext));
+
+ unsigned int (*_bfd_coff_swap_lineno_out) PARAMS ((
+ bfd *abfd,
+ PTR in,
+ PTR ext));
+
+ unsigned int (*_bfd_coff_swap_reloc_out) PARAMS ((
+ bfd *abfd,
+ PTR src,
+ PTR dst));
+
+ unsigned int (*_bfd_coff_swap_filehdr_out) PARAMS ((
+ bfd *abfd,
+ PTR in,
+ PTR out));
+
+ unsigned int (*_bfd_coff_swap_aouthdr_out) PARAMS ((
+ bfd *abfd,
+ PTR in,
+ PTR out));
+
+ unsigned int (*_bfd_coff_swap_scnhdr_out) PARAMS ((
+ bfd *abfd,
+ PTR in,
+ PTR out));
+
+ unsigned int _bfd_filhsz;
+ unsigned int _bfd_aoutsz;
+ unsigned int _bfd_scnhsz;
+ unsigned int _bfd_symesz;
+ unsigned int _bfd_auxesz;
+ unsigned int _bfd_linesz;
+ boolean _bfd_coff_long_filenames;
+ void (*_bfd_coff_swap_filehdr_in) PARAMS ((
+ bfd *abfd,
+ PTR ext,
+ PTR in));
+ void (*_bfd_coff_swap_aouthdr_in) PARAMS ((
+ bfd *abfd,
+ PTR ext,
+ PTR in));
+ void (*_bfd_coff_swap_scnhdr_in) PARAMS ((
+ bfd *abfd,
+ PTR ext,
+ PTR in));
+ boolean (*_bfd_coff_bad_format_hook) PARAMS ((
+ bfd *abfd,
+ PTR internal_filehdr));
+ boolean (*_bfd_coff_set_arch_mach_hook) PARAMS ((
+ bfd *abfd,
+ PTR internal_filehdr));
+ PTR (*_bfd_coff_mkobject_hook) PARAMS ((
+ bfd *abfd,
+ PTR internal_filehdr,
+ PTR internal_aouthdr));
+ flagword (*_bfd_styp_to_sec_flags_hook) PARAMS ((
+ bfd *abfd,
+ PTR internal_scnhdr));
+ asection *(*_bfd_make_section_hook) PARAMS ((
+ bfd *abfd,
+ char *name));
+ void (*_bfd_set_alignment_hook) PARAMS ((
+ bfd *abfd,
+ asection *sec,
+ PTR internal_scnhdr));
+ boolean (*_bfd_coff_slurp_symbol_table) PARAMS ((
+ bfd *abfd));
+ boolean (*_bfd_coff_symname_in_debug) PARAMS ((
+ bfd *abfd,
+ struct internal_syment *sym));
+ void (*_bfd_coff_reloc16_extra_cases) PARAMS ((
+ bfd *abfd,
+ struct bfd_link_info *link_info,
+ struct bfd_link_order *link_order,
+ arelent *reloc,
+ bfd_byte *data,
+ unsigned int *src_ptr,
+ unsigned int *dst_ptr));
+ int (*_bfd_coff_reloc16_estimate) PARAMS ((
+ bfd *abfd,
+ asection *input_section,
+ arelent *r,
+ unsigned int shrink,
+ struct bfd_link_info *link_info));
+
+} bfd_coff_backend_data;
+
+#define coff_backend_info(abfd) ((bfd_coff_backend_data *) (abfd)->xvec->backend_data)
+
+#define bfd_coff_swap_aux_in(a,e,t,c,ind,num,i) \
+ ((coff_backend_info (a)->_bfd_coff_swap_aux_in) (a,e,t,c,ind,num,i))
+
+#define bfd_coff_swap_sym_in(a,e,i) \
+ ((coff_backend_info (a)->_bfd_coff_swap_sym_in) (a,e,i))
+
+#define bfd_coff_swap_lineno_in(a,e,i) \
+ ((coff_backend_info ( a)->_bfd_coff_swap_lineno_in) (a,e,i))
+
+#define bfd_coff_swap_reloc_out(abfd, i, o) \
+ ((coff_backend_info (abfd)->_bfd_coff_swap_reloc_out) (abfd, i, o))
+
+#define bfd_coff_swap_lineno_out(abfd, i, o) \
+ ((coff_backend_info (abfd)->_bfd_coff_swap_lineno_out) (abfd, i, o))
+
+#define bfd_coff_swap_aux_out(a,i,t,c,ind,num,o) \
+ ((coff_backend_info (a)->_bfd_coff_swap_aux_out) (a,i,t,c,ind,num,o))
+
+#define bfd_coff_swap_sym_out(abfd, i,o) \
+ ((coff_backend_info (abfd)->_bfd_coff_swap_sym_out) (abfd, i, o))
+
+#define bfd_coff_swap_scnhdr_out(abfd, i,o) \
+ ((coff_backend_info (abfd)->_bfd_coff_swap_scnhdr_out) (abfd, i, o))
+
+#define bfd_coff_swap_filehdr_out(abfd, i,o) \
+ ((coff_backend_info (abfd)->_bfd_coff_swap_filehdr_out) (abfd, i, o))
+
+#define bfd_coff_swap_aouthdr_out(abfd, i,o) \
+ ((coff_backend_info (abfd)->_bfd_coff_swap_aouthdr_out) (abfd, i, o))
+
+#define bfd_coff_filhsz(abfd) (coff_backend_info (abfd)->_bfd_filhsz)
+#define bfd_coff_aoutsz(abfd) (coff_backend_info (abfd)->_bfd_aoutsz)
+#define bfd_coff_scnhsz(abfd) (coff_backend_info (abfd)->_bfd_scnhsz)
+#define bfd_coff_symesz(abfd) (coff_backend_info (abfd)->_bfd_symesz)
+#define bfd_coff_auxesz(abfd) (coff_backend_info (abfd)->_bfd_auxesz)
+#define bfd_coff_linesz(abfd) (coff_backend_info (abfd)->_bfd_linesz)
+#define bfd_coff_long_filenames(abfd) (coff_backend_info (abfd)->_bfd_coff_long_filenames)
+#define bfd_coff_swap_filehdr_in(abfd, i,o) \
+ ((coff_backend_info (abfd)->_bfd_coff_swap_filehdr_in) (abfd, i, o))
+
+#define bfd_coff_swap_aouthdr_in(abfd, i,o) \
+ ((coff_backend_info (abfd)->_bfd_coff_swap_aouthdr_in) (abfd, i, o))
+
+#define bfd_coff_swap_scnhdr_in(abfd, i,o) \
+ ((coff_backend_info (abfd)->_bfd_coff_swap_scnhdr_in) (abfd, i, o))
+
+#define bfd_coff_bad_format_hook(abfd, filehdr) \
+ ((coff_backend_info (abfd)->_bfd_coff_bad_format_hook) (abfd, filehdr))
+
+#define bfd_coff_set_arch_mach_hook(abfd, filehdr)\
+ ((coff_backend_info (abfd)->_bfd_coff_set_arch_mach_hook) (abfd, filehdr))
+#define bfd_coff_mkobject_hook(abfd, filehdr, aouthdr)\
+ ((coff_backend_info (abfd)->_bfd_coff_mkobject_hook) (abfd, filehdr, aouthdr))
+
+#define bfd_coff_styp_to_sec_flags_hook(abfd, scnhdr)\
+ ((coff_backend_info (abfd)->_bfd_styp_to_sec_flags_hook) (abfd, scnhdr))
+
+#define bfd_coff_make_section_hook(abfd, name)\
+ ((coff_backend_info (abfd)->_bfd_make_section_hook) (abfd, name))
+
+#define bfd_coff_set_alignment_hook(abfd, sec, scnhdr)\
+ ((coff_backend_info (abfd)->_bfd_set_alignment_hook) (abfd, sec, scnhdr))
+
+#define bfd_coff_slurp_symbol_table(abfd)\
+ ((coff_backend_info (abfd)->_bfd_coff_slurp_symbol_table) (abfd))
+
+#define bfd_coff_symname_in_debug(abfd, sym)\
+ ((coff_backend_info (abfd)->_bfd_coff_symname_in_debug) (abfd, sym))
+
+#define bfd_coff_reloc16_extra_cases(abfd, link_info, link_order, reloc, data, src_ptr, dst_ptr)\
+ ((coff_backend_info (abfd)->_bfd_coff_reloc16_extra_cases)\
+ (abfd, link_info, link_order, reloc, data, src_ptr, dst_ptr))
+
+#define bfd_coff_reloc16_estimate(abfd, section, reloc, shrink, link_info)\
+ ((coff_backend_info (abfd)->_bfd_coff_reloc16_estimate)\
+ (abfd, section, reloc, shrink, link_info))
+
diff --git a/gnu/usr.bin/gdb/bfd/libecoff.h b/gnu/usr.bin/gdb/bfd/libecoff.h
new file mode 100644
index 0000000..2f7b852
--- /dev/null
+++ b/gnu/usr.bin/gdb/bfd/libecoff.h
@@ -0,0 +1,297 @@
+/* BFD ECOFF object file private structure.
+ Copyright (C) 1993 Free Software Foundation, Inc.
+ Written by Ian Lance Taylor, Cygnus Support.
+
+This file is part of BFD, the Binary File Descriptor library.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "bfdlink.h"
+
+#ifndef ECOFF_H
+#include "coff/ecoff.h"
+#endif
+
+/* This is the backend information kept for ECOFF files. This
+ structure is constant for a particular backend. The first element
+ is the COFF backend data structure, so that ECOFF targets can use
+ the generic COFF code. */
+
+#define ecoff_backend(abfd) \
+ ((struct ecoff_backend_data *) (abfd)->xvec->backend_data)
+
+struct ecoff_backend_data
+{
+ /* COFF backend information. This must be the first field. */
+ bfd_coff_backend_data coff;
+ /* Supported architecture. */
+ enum bfd_architecture arch;
+ /* Initial portion of armap string. */
+ const char *armap_start;
+ /* The page boundary used to align sections in a demand-paged
+ executable file. E.g., 0x1000. */
+ bfd_vma round;
+ /* True if the .rdata section is part of the text segment, as on the
+ Alpha. False if .rdata is part of the data segment, as on the
+ MIPS. */
+ boolean rdata_in_text;
+ /* Bitsize of constructor entries. */
+ unsigned int constructor_bitsize;
+ /* Reloc to use for constructor entries. */
+ CONST struct reloc_howto_struct *constructor_reloc;
+ /* How to swap debugging information. */
+ struct ecoff_debug_swap debug_swap;
+ /* External reloc size. */
+ bfd_size_type external_reloc_size;
+ /* Reloc swapping functions. */
+ void (*swap_reloc_in) PARAMS ((bfd *, PTR, struct internal_reloc *));
+ void (*swap_reloc_out) PARAMS ((bfd *, const struct internal_reloc *, PTR));
+ /* Backend reloc tweaking. */
+ void (*adjust_reloc_in) PARAMS ((bfd *, const struct internal_reloc *,
+ arelent *));
+ void (*adjust_reloc_out) PARAMS ((bfd *, const arelent *,
+ struct internal_reloc *));
+ /* Relocate section contents while linking. */
+ boolean (*relocate_section) PARAMS ((bfd *output_bfd, struct bfd_link_info *,
+ bfd *input_bfd, asection *input_section,
+ bfd_byte *contents,
+ PTR external_relocs));
+};
+
+/* This is the target specific information kept for ECOFF files. */
+
+#define ecoff_data(abfd) ((abfd)->tdata.ecoff_obj_data)
+
+typedef struct ecoff_tdata
+{
+ /* The reloc file position, set by
+ ecoff_compute_section_file_positions. */
+ file_ptr reloc_filepos;
+
+ /* The symbol table file position, set by _bfd_ecoff_mkobject_hook. */
+ file_ptr sym_filepos;
+
+ /* The start and end of the text segment. Only valid for an
+ existing file, not for one we are creating. */
+ unsigned long text_start;
+ unsigned long text_end;
+
+ /* The cached gp value. This is used when relocating. */
+ bfd_vma gp;
+
+ /* The maximum size of objects to optimize using gp. This is
+ typically set by the -G option to the compiler, assembler or
+ linker. */
+ int gp_size;
+
+ /* The register masks. When linking, all the masks found in the
+ input files are combined into the masks of the output file.
+ These are not all used for all targets, but that's OK, because
+ the relevant ones are the only ones swapped in and out. */
+ unsigned long gprmask;
+ unsigned long fprmask;
+ unsigned long cprmask[4];
+
+ /* The ECOFF symbolic debugging information. */
+ struct ecoff_debug_info debug_info;
+
+ /* The unswapped ECOFF symbolic information. */
+ PTR raw_syments;
+
+ /* The canonical BFD symbols. */
+ struct ecoff_symbol_struct *canonical_symbols;
+
+ /* A mapping from external symbol numbers to entries in the linker
+ hash table, used when linking. */
+ struct ecoff_link_hash_entry **sym_hashes;
+
+ /* A mapping from reloc symbol indices to sections, used when
+ linking. */
+ asection **symndx_to_section;
+
+ /* True if this BFD was written by the backend linker. */
+ boolean linker;
+
+} ecoff_data_type;
+
+/* Each canonical asymbol really looks like this. */
+
+typedef struct ecoff_symbol_struct
+{
+ /* The actual symbol which the rest of BFD works with */
+ asymbol symbol;
+
+ /* The fdr for this symbol. */
+ FDR *fdr;
+
+ /* true if this is a local symbol rather than an external one. */
+ boolean local;
+
+ /* A pointer to the unswapped hidden information for this symbol.
+ This is either a struct sym_ext or a struct ext_ext, depending on
+ the value of the local field above. */
+ PTR native;
+} ecoff_symbol_type;
+
+/* We take the address of the first element of a asymbol to ensure that the
+ macro is only ever applied to an asymbol. */
+#define ecoffsymbol(asymbol) ((ecoff_symbol_type *) (&((asymbol)->the_bfd)))
+
+/* This is a hack borrowed from coffcode.h; we need to save the index
+ of an external symbol when we write it out so that can set the
+ symbol index correctly when we write out the relocs. */
+#define ecoff_get_sym_index(symbol) ((unsigned long) (symbol)->udata)
+#define ecoff_set_sym_index(symbol, idx) ((symbol)->udata = (PTR) (idx))
+
+/* When generating MIPS embedded PIC code, the linker relaxes the code
+ to turn PC relative branches into longer code sequences when the PC
+ relative branch is out of range. This involves reading the relocs
+ in bfd_relax_section as well as in bfd_final_link, and requires the
+ code to keep track of which relocs have been expanded. A pointer
+ to this structure is put in the used_by_bfd pointer of a section to
+ keep track of this information. The user_by_bfd pointer will be
+ NULL if the information was not needed. */
+
+struct ecoff_section_tdata
+{
+ /* The unswapped relocs for this section. These are stored in
+ memory so the input file does not have to be read twice. */
+ PTR external_relocs;
+
+ /* The contents of the section. These bytes may or may not be saved
+ in memory, but if it is this is a pointer to them. */
+ bfd_byte *contents;
+
+ /* Offset adjustments for PC relative branches. A number other than
+ 1 is an addend for a PC relative branch, or a switch table entry
+ which is the difference of two .text locations; this addend
+ arises because the branch or difference crosses one or more
+ branches which were expanded into a larger code sequence. A 1
+ means that this branch was itself expanded into a larger code
+ sequence. 1 is not a possible offset, since all offsets must be
+ multiples of the instruction size, which is 4; also, the only
+ relocs with non-zero offsets will be PC relative branches or
+ switch table entries within the same object file. If this field
+ is NULL, no branches were expanded and no offsets are required.
+ Otherwise there are as many entries as there are relocs in the
+ section, and the entry for any reloc that is not PC relative is
+ zero. */
+ long *offsets;
+};
+
+/* An accessor macro for the ecoff_section_tdata structure. */
+#define ecoff_section_data(abfd, sec) \
+ ((struct ecoff_section_tdata *) (sec)->used_by_bfd)
+
+/* ECOFF linker hash table entries. */
+
+struct ecoff_link_hash_entry
+{
+ struct bfd_link_hash_entry root;
+ /* Symbol index in output file. */
+ long indx;
+ /* BFD that ext field value came from. */
+ bfd *abfd;
+ /* ECOFF external symbol information. */
+ EXTR esym;
+ /* Nonzero if this symbol has been written out. */
+ char written;
+ /* Nonzero if this symbol was referred to as small undefined. */
+ char small;
+};
+
+/* ECOFF linker hash table. */
+
+struct ecoff_link_hash_table
+{
+ struct bfd_link_hash_table root;
+};
+
+/* Make an ECOFF object. */
+extern boolean _bfd_ecoff_mkobject PARAMS ((bfd *));
+
+/* Read in the ECOFF symbolic debugging information. */
+extern boolean _bfd_ecoff_slurp_symbolic_info
+ PARAMS ((bfd *, asection *, struct ecoff_debug_info *));
+
+/* Generic ECOFF BFD backend vectors. */
+
+extern boolean _bfd_ecoff_write_object_contents PARAMS ((bfd *abfd));
+extern const bfd_target *_bfd_ecoff_archive_p PARAMS ((bfd *abfd));
+
+#define _bfd_ecoff_close_and_cleanup _bfd_generic_close_and_cleanup
+#define _bfd_ecoff_bfd_free_cached_info _bfd_generic_bfd_free_cached_info
+extern boolean _bfd_ecoff_new_section_hook
+ PARAMS ((bfd *, asection *));
+extern boolean _bfd_ecoff_get_section_contents
+ PARAMS ((bfd *, asection *, PTR location, file_ptr, bfd_size_type));
+
+extern boolean _bfd_ecoff_bfd_copy_private_bfd_data PARAMS ((bfd *, bfd *));
+#define _bfd_ecoff_bfd_copy_private_section_data \
+ _bfd_generic_bfd_copy_private_section_data
+
+extern boolean _bfd_ecoff_slurp_armap PARAMS ((bfd *abfd));
+#define _bfd_ecoff_slurp_extended_name_table _bfd_slurp_extended_name_table
+#define _bfd_ecoff_truncate_arname bfd_dont_truncate_arname
+extern boolean _bfd_ecoff_write_armap
+ PARAMS ((bfd *, unsigned int, struct orl *, unsigned int, int));
+#define _bfd_ecoff_openr_next_archived_file \
+ bfd_generic_openr_next_archived_file
+#define _bfd_ecoff_generic_stat_arch_elt bfd_generic_stat_arch_elt
+
+extern long _bfd_ecoff_get_symtab_upper_bound PARAMS ((bfd *abfd));
+extern long _bfd_ecoff_get_symtab PARAMS ((bfd *abfd, asymbol **alocation));
+extern asymbol *_bfd_ecoff_make_empty_symbol PARAMS ((bfd *abfd));
+extern void _bfd_ecoff_print_symbol
+ PARAMS ((bfd *, PTR filep, asymbol *, bfd_print_symbol_type));
+extern void _bfd_ecoff_get_symbol_info
+ PARAMS ((bfd *, asymbol *, symbol_info *));
+#define _bfd_ecoff_bfd_is_local_label bfd_generic_is_local_label
+#define _bfd_ecoff_get_lineno _bfd_nosymbols_get_lineno
+extern boolean _bfd_ecoff_find_nearest_line
+ PARAMS ((bfd *, asection *, asymbol **, bfd_vma offset,
+ const char **filename_ptr, const char **fnname_ptr,
+ unsigned int *retline_ptr));
+#define _bfd_ecoff_bfd_make_debug_symbol _bfd_nosymbols_bfd_make_debug_symbol
+
+#define _bfd_ecoff_get_reloc_upper_bound coff_get_reloc_upper_bound
+extern long _bfd_ecoff_canonicalize_reloc
+ PARAMS ((bfd *, asection *, arelent **, asymbol **symbols));
+/* ecoff_bfd_reloc_type_lookup defined by backend. */
+
+extern boolean _bfd_ecoff_set_arch_mach
+ PARAMS ((bfd *, enum bfd_architecture, unsigned long machine));
+extern boolean _bfd_ecoff_set_section_contents
+ PARAMS ((bfd *, asection *, PTR location, file_ptr, bfd_size_type));
+
+extern int _bfd_ecoff_sizeof_headers PARAMS ((bfd *abfd, boolean reloc));
+/* ecoff_bfd_get_relocated_section_contents defined by backend. */
+/* ecoff_bfd_relax_section defined by backend. */
+extern struct bfd_link_hash_table *_bfd_ecoff_bfd_link_hash_table_create
+ PARAMS ((bfd *));
+extern boolean _bfd_ecoff_bfd_link_add_symbols
+ PARAMS ((bfd *, struct bfd_link_info *));
+extern boolean _bfd_ecoff_bfd_final_link
+ PARAMS ((bfd *, struct bfd_link_info *));
+
+/* Hook functions for the generic COFF section reading code. */
+
+extern PTR _bfd_ecoff_mkobject_hook PARAMS ((bfd *, PTR filehdr, PTR aouthdr));
+extern asection *_bfd_ecoff_make_section_hook PARAMS ((bfd *abfd, char *name));
+#define _bfd_ecoff_set_alignment_hook \
+ ((void (*) PARAMS ((bfd *, asection *, PTR))) bfd_void)
+extern boolean _bfd_ecoff_set_arch_mach_hook PARAMS ((bfd *abfd, PTR filehdr));
+extern flagword _bfd_ecoff_styp_to_sec_flags PARAMS ((bfd *abfd, PTR hdr));
+extern boolean _bfd_ecoff_slurp_symbol_table PARAMS ((bfd *abfd));
diff --git a/gnu/usr.bin/gdb/bfd/libelf.h b/gnu/usr.bin/gdb/bfd/libelf.h
new file mode 100644
index 0000000..cc6d8b8
--- /dev/null
+++ b/gnu/usr.bin/gdb/bfd/libelf.h
@@ -0,0 +1,633 @@
+/* BFD back-end data structures for ELF files.
+ Copyright (C) 1992, 1993 Free Software Foundation, Inc.
+ Written by Cygnus Support.
+
+This file is part of BFD, the Binary File Descriptor library.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#ifndef _LIBELF_H_
+#define _LIBELF_H_ 1
+
+#include "elf/common.h"
+#include "elf/internal.h"
+#include "elf/external.h"
+#include "bfdlink.h"
+
+/* If size isn't specified as 64 or 32, NAME macro should fail. */
+#ifndef NAME
+#if ARCH_SIZE==64
+#define NAME(x,y) CAT4(x,64,_,y)
+#endif
+#if ARCH_SIZE==32
+#define NAME(x,y) CAT4(x,32,_,y)
+#endif
+#endif
+
+#ifndef NAME
+#define NAME(x,y) CAT4(x,NOSIZE,_,y)
+#endif
+
+#define ElfNAME(X) NAME(Elf,X)
+#define elfNAME(X) NAME(elf,X)
+
+/* Information held for an ELF symbol. The first field is the
+ corresponding asymbol. Every symbol is an ELF file is actually a
+ pointer to this structure, although it is often handled as a
+ pointer to an asymbol. */
+
+typedef struct
+{
+ /* The BFD symbol. */
+ asymbol symbol;
+ /* ELF symbol information. */
+ Elf_Internal_Sym internal_elf_sym;
+ /* Backend specific information. */
+ union
+ {
+ unsigned int hppa_arg_reloc;
+ PTR mips_extr;
+ PTR any;
+ }
+ tc_data;
+} elf_symbol_type;
+
+/* ELF linker hash table entries. */
+
+struct elf_link_hash_entry
+{
+ struct bfd_link_hash_entry root;
+
+ /* Symbol index in output file. This is initialized to -1. It is
+ set to -2 if the symbol is used by a reloc. */
+ long indx;
+
+ /* Symbol size. */
+ bfd_size_type size;
+
+ /* Symbol alignment (common symbols only). */
+ bfd_size_type align;
+
+ /* Symbol index as a dynamic symbol. Initialized to -1, and remains
+ -1 if this is not a dynamic symbol. */
+ long dynindx;
+
+ /* String table index in .dynstr if this is a dynamic symbol. */
+ unsigned long dynstr_index;
+
+ /* If this is a weak defined symbol from a dynamic object, this
+ field points to a defined symbol with the same value, if there is
+ one. Otherwise it is NULL. */
+ struct elf_link_hash_entry *weakdef;
+
+ /* Symbol type (STT_NOTYPE, STT_OBJECT, etc.). */
+ char type;
+
+ /* Some flags; legal values follow. */
+ unsigned char elf_link_hash_flags;
+ /* Symbol is referenced by a non-shared object. */
+#define ELF_LINK_HASH_REF_REGULAR 01
+ /* Symbol is defined by a non-shared object. */
+#define ELF_LINK_HASH_DEF_REGULAR 02
+ /* Symbol is referenced by a shared object. */
+#define ELF_LINK_HASH_REF_DYNAMIC 04
+ /* Symbol is defined by a shared object. */
+#define ELF_LINK_HASH_DEF_DYNAMIC 010
+ /* Symbol is referenced by two or more shared objects. */
+#define ELF_LINK_HASH_REF_DYNAMIC_MULTIPLE 020
+ /* Symbol is defined by two or more shared objects. */
+#define ELF_LINK_HASH_DEF_DYNAMIC_MULTIPLE 040
+ /* Dynamic symbol has been adjustd. */
+#define ELF_LINK_HASH_DYNAMIC_ADJUSTED 0100
+ /* Symbol is defined as weak. */
+#define ELF_LINK_HASH_DEFINED_WEAK 0200
+};
+
+/* ELF linker hash table. */
+
+struct elf_link_hash_table
+{
+ struct bfd_link_hash_table root;
+ /* The first dynamic object found during a link. We create several
+ special input sections when linking against dynamic objects, and
+ we simply attach them to the first one found. */
+ bfd *dynobj;
+ /* The number of symbols found in the link which must be put into
+ the .dynsym section. */
+ size_t dynsymcount;
+ /* The string table of dynamic symbols, which becomes the .dynstr
+ section. */
+ struct strtab *dynstr;
+ /* The number of buckets in the hash table in the .hash section.
+ This is based on the number of dynamic symbols. */
+ size_t bucketcount;
+};
+
+/* Look up an entry in an ELF linker hash table. */
+
+#define elf_link_hash_lookup(table, string, create, copy, follow) \
+ ((struct elf_link_hash_entry *) \
+ bfd_link_hash_lookup (&(table)->root, (string), (create), \
+ (copy), (follow)))
+
+/* Traverse an ELF linker hash table. */
+
+#define elf_link_hash_traverse(table, func, info) \
+ (bfd_link_hash_traverse \
+ (&(table)->root, \
+ (boolean (*) PARAMS ((struct bfd_link_hash_entry *, PTR))) (func), \
+ (info)))
+
+/* Get the ELF linker hash table from a link_info structure. */
+
+#define elf_hash_table(p) ((struct elf_link_hash_table *) ((p)->hash))
+
+/* Constant information held for an ELF backend. */
+
+struct elf_backend_data
+{
+ /* Whether the backend uses REL or RELA relocations. FIXME: some
+ ELF backends use both. When we need to support one, this whole
+ approach will need to be changed. */
+ int use_rela_p;
+
+ /* Whether this backend is 64 bits or not. FIXME: Who cares? */
+ int elf_64_p;
+
+ /* The architecture for this backend. */
+ enum bfd_architecture arch;
+
+ /* The ELF machine code (EM_xxxx) for this backend. */
+ int elf_machine_code;
+
+ /* The maximum page size for this backend. */
+ bfd_vma maxpagesize;
+
+ /* This is true if the linker should act like collect and gather
+ global constructors and destructors by name. This is true for
+ MIPS ELF because the Irix 5 tools can not handle the .init
+ section. */
+ boolean collect;
+
+ /* A function to translate an ELF RELA relocation to a BFD arelent
+ structure. */
+ void (*elf_info_to_howto) PARAMS ((bfd *, arelent *,
+ Elf_Internal_Rela *));
+
+ /* A function to translate an ELF REL relocation to a BFD arelent
+ structure. */
+ void (*elf_info_to_howto_rel) PARAMS ((bfd *, arelent *,
+ Elf_Internal_Rel *));
+
+ /* A function to determine whether a symbol is global when
+ partitioning the symbol table into local and global symbols.
+ This should be NULL for most targets, in which case the correct
+ thing will be done. MIPS ELF, at least on the Irix 5, has
+ special requirements. */
+ boolean (*elf_backend_sym_is_global) PARAMS ((bfd *, asymbol *));
+
+ /* The remaining functions are hooks which are called only if they
+ are not NULL. */
+
+ /* A function to permit a backend specific check on whether a
+ particular BFD format is relevant for an object file, and to
+ permit the backend to set any global information it wishes. When
+ this is called elf_elfheader is set, but anything else should be
+ used with caution. If this returns false, the check_format
+ routine will return a bfd_error_wrong_format error. */
+ boolean (*elf_backend_object_p) PARAMS ((bfd *));
+
+ /* A function to do additional symbol processing when reading the
+ ELF symbol table. This is where any processor-specific special
+ section indices are handled. */
+ void (*elf_backend_symbol_processing) PARAMS ((bfd *, asymbol *));
+
+ /* A function to do additional symbol processing after reading the
+ entire ELF symbol table. */
+ boolean (*elf_backend_symbol_table_processing) PARAMS ((bfd *,
+ elf_symbol_type *,
+ int));
+
+ /* A function to do additional processing on the ELF section header
+ just before writing it out. This is used to set the flags and
+ type fields for some sections, or to actually write out data for
+ unusual sections. */
+ boolean (*elf_backend_section_processing) PARAMS ((bfd *,
+ Elf32_Internal_Shdr *));
+
+ /* A function to handle unusual section types when creating BFD
+ sections from ELF sections. */
+ boolean (*elf_backend_section_from_shdr) PARAMS ((bfd *,
+ Elf32_Internal_Shdr *,
+ char *));
+
+ /* A function to set up the ELF section header for a BFD section in
+ preparation for writing it out. This is where the flags and type
+ fields are set for unusual sections. */
+ boolean (*elf_backend_fake_sections) PARAMS ((bfd *, Elf32_Internal_Shdr *,
+ asection *));
+
+ /* A function to get the ELF section index for a BFD section. If
+ this returns true, the section was found. If it is a normal ELF
+ section, *RETVAL should be left unchanged. If it is not a normal
+ ELF section *RETVAL should be set to the SHN_xxxx index. */
+ boolean (*elf_backend_section_from_bfd_section)
+ PARAMS ((bfd *, Elf32_Internal_Shdr *, asection *, int *retval));
+
+ /* If this field is not NULL, it is called by the add_symbols phase
+ of a link just before adding a symbol to the global linker hash
+ table. It may modify any of the fields as it wishes. If *NAME
+ is set to NULL, the symbol will be skipped rather than being
+ added to the hash table. This function is responsible for
+ handling all processor dependent symbol bindings and section
+ indices, and must set at least *FLAGS and *SEC for each processor
+ dependent case; failure to do so will cause a link error. */
+ boolean (*elf_add_symbol_hook)
+ PARAMS ((bfd *abfd, struct bfd_link_info *info,
+ const Elf_Internal_Sym *, const char **name,
+ flagword *flags, asection **sec, bfd_vma *value));
+
+ /* If this field is not NULL, it is called by the elf_link_output_sym
+ phase of a link for each symbol which will appear in the object file. */
+ boolean (*elf_backend_link_output_symbol_hook)
+ PARAMS ((bfd *, struct bfd_link_info *info, const char *,
+ Elf_Internal_Sym *, asection *));
+
+ /* The CREATE_DYNAMIC_SECTIONS function is called by the ELF backend
+ linker the first time it encounters a dynamic object in the link.
+ This function must create any sections required for dynamic
+ linking. The ABFD argument is a dynamic object. The .interp,
+ .dynamic, .dynsym, .dynstr, and .hash functions have already been
+ created, and this function may modify the section flags if
+ desired. This function will normally create the .got and .plt
+ sections, but different backends have different requirements. */
+ boolean (*elf_backend_create_dynamic_sections)
+ PARAMS ((bfd *abfd, struct bfd_link_info *info));
+
+ /* The ADJUST_DYNAMIC_SYMBOL function is called by the ELF backend
+ linker for every symbol which is defined by a dynamic object and
+ referenced by a regular object. This is called after all the
+ input files have been seen, but before the SIZE_DYNAMIC_SECTIONS
+ function has been called. The hash table entry should be
+ bfd_link_hash_defined, and it should be defined in a section from
+ a dynamic object. Dynamic object sections are not included in
+ the final link, and this function is responsible for changing the
+ value to something which the rest of the link can deal with.
+ This will normally involve adding an entry to the .plt or .got or
+ some such section, and setting the symbol to point to that. */
+ boolean (*elf_backend_adjust_dynamic_symbol)
+ PARAMS ((struct bfd_link_info *info, struct elf_link_hash_entry *h));
+
+ /* The SIZE_DYNAMIC_SECTIONS function is called by the ELF backend
+ linker after all the linker input files have been seen but before
+ the sections sizes have been set. This is called after
+ ADJUST_DYNAMIC_SYMBOL has been called on all appropriate symbols.
+ It is only called when linking against a dynamic object. It must
+ set the sizes of the dynamic sections, and may fill in their
+ contents as well. The generic ELF linker can handle the .dynsym,
+ .dynstr and .hash sections. This function must handle the
+ .interp section and any sections created by the
+ CREATE_DYNAMIC_SECTIONS entry point. */
+ boolean (*elf_backend_size_dynamic_sections)
+ PARAMS ((bfd *output_bfd, struct bfd_link_info *info));
+
+ /* The RELOCATE_SECTION function is called by the ELF backend linker
+ to handle the relocations for a section.
+
+ The relocs are always passed as Rela structures; if the section
+ actually uses Rel structures, the r_addend field will always be
+ zero.
+
+ This function is responsible for adjust the section contents as
+ necessary, and (if using Rela relocs and generating a
+ relocateable output file) adjusting the reloc addend as
+ necessary.
+
+ This function does not have to worry about setting the reloc
+ address or the reloc symbol index.
+
+ LOCAL_SYMS is a pointer to the swapped in local symbols.
+
+ LOCAL_SECTIONS is an array giving the section in the input file
+ corresponding to the st_shndx field of each local symbol.
+
+ The global hash table entry for the global symbols can be found
+ via elf_sym_hashes (input_bfd).
+
+ When generating relocateable output, this function must handle
+ STB_LOCAL/STT_SECTION symbols specially. The output symbol is
+ going to be the section symbol corresponding to the output
+ section, which means that the addend must be adjusted
+ accordingly. */
+ boolean (*elf_backend_relocate_section)
+ PARAMS ((bfd *output_bfd, struct bfd_link_info *info,
+ bfd *input_bfd, asection *input_section, bfd_byte *contents,
+ Elf_Internal_Rela *relocs, Elf_Internal_Sym *local_syms,
+ asection **local_sections, char *output_names));
+
+ /* The FINISH_DYNAMIC_SYMBOL function is called by the ELF backend
+ linker just before it writes a symbol out to the .dynsym section.
+ The processor backend may make any required adjustment to the
+ symbol. It may also take the opportunity to set contents of the
+ dynamic sections. Note that FINISH_DYNAMIC_SYMBOL is called on
+ all .dynsym symbols, while ADJUST_DYNAMIC_SYMBOL is only called
+ on those symbols which are defined by a dynamic object. */
+ boolean (*elf_backend_finish_dynamic_symbol)
+ PARAMS ((bfd *output_bfd, struct bfd_link_info *info,
+ struct elf_link_hash_entry *h, Elf_Internal_Sym *sym));
+
+ /* The FINISH_DYNAMIC_SECTIONS function is called by the ELF backend
+ linker just before it writes all the dynamic sections out to the
+ output file. The FINISH_DYNAMIC_SYMBOL will have been called on
+ all dynamic symbols. */
+ boolean (*elf_backend_finish_dynamic_sections)
+ PARAMS ((bfd *output_bfd, struct bfd_link_info *info));
+
+ /* A function to do any beginning processing needed for the ELF file
+ before building the ELF headers and computing file positions. */
+ void (*elf_backend_begin_write_processing)
+ PARAMS ((bfd *, struct bfd_link_info *));
+
+ /* A function to do any final processing needed for the ELF file
+ before writing it out. */
+ void (*elf_backend_final_write_processing)
+ PARAMS ((bfd *, struct bfd_link_info *));
+
+ /* The swapping table to use when dealing with ECOFF information.
+ Used for the MIPS ELF .mdebug section. */
+ const struct ecoff_debug_swap *elf_backend_ecoff_debug_swap;
+};
+
+struct elf_sym_extra
+{
+ int elf_sym_num; /* sym# after locals/globals are reordered */
+};
+
+typedef struct elf_sym_extra Elf_Sym_Extra;
+
+/* Information stored for each BFD section in an ELF file. This
+ structure is allocated by elf_new_section_hook. */
+
+struct bfd_elf_section_data {
+ /* The ELF header for this section. */
+ Elf_Internal_Shdr this_hdr;
+ /* The ELF header for the reloc section associated with this
+ section, if any. */
+ Elf_Internal_Shdr rel_hdr;
+ /* The ELF section number of this section. Only used for an output
+ file. */
+ int this_idx;
+ /* The ELF section number of the reloc section associated with this
+ section, if any. Only used for an output file. */
+ int rel_idx;
+ /* Used by the backend linker to store the symbol hash table entries
+ associated with relocs against global symbols. */
+ struct elf_link_hash_entry **rel_hashes;
+ /* A pointer to the unswapped external relocs; this may be NULL. */
+ PTR relocs;
+};
+
+#define elf_section_data(sec) ((struct bfd_elf_section_data*)sec->used_by_bfd)
+
+#define get_elf_backend_data(abfd) \
+ ((struct elf_backend_data *) (abfd)->xvec->backend_data)
+
+struct strtab
+{
+ char *tab;
+ int nentries;
+ int length;
+};
+
+/* Some private data is stashed away for future use using the tdata pointer
+ in the bfd structure. */
+
+struct elf_obj_tdata
+{
+ Elf_Internal_Ehdr elf_header[1]; /* Actual data, but ref like ptr */
+ Elf_Internal_Shdr **elf_sect_ptr;
+ Elf_Internal_Phdr *phdr;
+ struct strtab *strtab_ptr;
+ int num_locals;
+ int num_globals;
+ Elf_Sym_Extra *sym_extra;
+ asymbol **section_syms; /* STT_SECTION symbols for each section */
+ int num_section_syms; /* number of section_syms allocated */
+ Elf_Internal_Shdr symtab_hdr;
+ Elf_Internal_Shdr shstrtab_hdr;
+ Elf_Internal_Shdr strtab_hdr;
+ Elf_Internal_Shdr dynsymtab_hdr;
+ Elf_Internal_Shdr dynstrtab_hdr;
+ int symtab_section, shstrtab_section, strtab_section, dynsymtab_section;
+ file_ptr next_file_pos;
+ void *prstatus; /* The raw /proc prstatus structure */
+ void *prpsinfo; /* The raw /proc prpsinfo structure */
+ bfd_vma gp; /* The gp value (MIPS only, for now) */
+ int gp_size; /* The gp size (MIPS only, for now) */
+
+ /* A mapping from external symbols to entries in the linker hash
+ table, used when linking. This is indexed by the symbol index
+ minus the sh_info field of the symbol table header. */
+ struct elf_link_hash_entry **sym_hashes;
+
+ /* The linker ELF emulation code needs to let the backend ELF linker
+ know what filename should be used for a dynamic object if the
+ dynamic object is found using a search. This field is used to
+ hold that information. */
+ const char *dt_needed_name;
+
+ /* Irix 5 often screws up the symbol table, sorting local symbols
+ after global symbols. This flag is set if the symbol table in
+ this BFD appears to be screwed up. If it is, we ignore the
+ sh_info field in the symbol table header, and always read all the
+ symbols. */
+ boolean bad_symtab;
+};
+
+#define elf_tdata(bfd) ((bfd) -> tdata.elf_obj_data)
+#define elf_elfheader(bfd) (elf_tdata(bfd) -> elf_header)
+#define elf_elfsections(bfd) (elf_tdata(bfd) -> elf_sect_ptr)
+#define elf_shstrtab(bfd) (elf_tdata(bfd) -> strtab_ptr)
+#define elf_onesymtab(bfd) (elf_tdata(bfd) -> symtab_section)
+#define elf_dynsymtab(bfd) (elf_tdata(bfd) -> dynsymtab_section)
+#define elf_num_locals(bfd) (elf_tdata(bfd) -> num_locals)
+#define elf_num_globals(bfd) (elf_tdata(bfd) -> num_globals)
+#define elf_sym_extra(bfd) (elf_tdata(bfd) -> sym_extra)
+#define elf_section_syms(bfd) (elf_tdata(bfd) -> section_syms)
+#define elf_num_section_syms(bfd) (elf_tdata(bfd) -> num_section_syms)
+#define core_prpsinfo(bfd) (elf_tdata(bfd) -> prpsinfo)
+#define core_prstatus(bfd) (elf_tdata(bfd) -> prstatus)
+#define elf_gp(bfd) (elf_tdata(bfd) -> gp)
+#define elf_gp_size(bfd) (elf_tdata(bfd) -> gp_size)
+#define elf_sym_hashes(bfd) (elf_tdata(bfd) -> sym_hashes)
+#define elf_dt_needed_name(bfd) (elf_tdata(bfd) -> dt_needed_name)
+#define elf_bad_symtab(bfd) (elf_tdata(bfd) -> bad_symtab)
+
+extern char * elf_string_from_elf_section PARAMS ((bfd *, unsigned, unsigned));
+extern char * elf_get_str_section PARAMS ((bfd *, unsigned));
+
+#define bfd_elf32_mkobject bfd_elf_mkobject
+#define bfd_elf64_mkobject bfd_elf_mkobject
+#define elf_mkobject bfd_elf_mkobject
+
+extern unsigned long bfd_elf_hash PARAMS ((CONST unsigned char *));
+
+extern bfd_reloc_status_type bfd_elf_generic_reloc PARAMS ((bfd *,
+ arelent *,
+ asymbol *,
+ PTR,
+ asection *,
+ bfd *,
+ char **));
+extern boolean bfd_elf_mkobject PARAMS ((bfd *));
+extern Elf_Internal_Shdr *bfd_elf_find_section PARAMS ((bfd *, char *));
+extern boolean _bfd_elf_make_section_from_shdr
+ PARAMS ((bfd *abfd, Elf_Internal_Shdr *hdr, const char *name));
+extern struct bfd_hash_entry *_bfd_elf_link_hash_newfunc
+ PARAMS ((struct bfd_hash_entry *, struct bfd_hash_table *, const char *));
+extern struct bfd_link_hash_table *_bfd_elf_link_hash_table_create
+ PARAMS ((bfd *));
+extern boolean _bfd_elf_link_hash_table_init
+ PARAMS ((struct elf_link_hash_table *, bfd *,
+ struct bfd_hash_entry *(*) (struct bfd_hash_entry *,
+ struct bfd_hash_table *,
+ const char *)));
+
+extern boolean bfd_elf32_write_object_contents PARAMS ((bfd *));
+extern boolean bfd_elf64_write_object_contents PARAMS ((bfd *));
+
+extern const bfd_target *bfd_elf32_object_p PARAMS ((bfd *));
+extern const bfd_target *bfd_elf32_core_file_p PARAMS ((bfd *));
+extern char *bfd_elf32_core_file_failing_command PARAMS ((bfd *));
+extern int bfd_elf32_core_file_failing_signal PARAMS ((bfd *));
+extern boolean bfd_elf32_core_file_matches_executable_p PARAMS ((bfd *,
+ bfd *));
+extern boolean bfd_elf32_set_section_contents PARAMS ((bfd *, sec_ptr, PTR,
+ file_ptr,
+ bfd_size_type));
+
+extern long bfd_elf32_get_symtab_upper_bound PARAMS ((bfd *));
+extern long bfd_elf32_get_symtab PARAMS ((bfd *, asymbol **));
+extern long bfd_elf32_get_dynamic_symtab_upper_bound PARAMS ((bfd *));
+extern long bfd_elf32_canonicalize_dynamic_symtab PARAMS ((bfd *, asymbol **));
+extern long bfd_elf32_get_reloc_upper_bound PARAMS ((bfd *, sec_ptr));
+extern long bfd_elf32_canonicalize_reloc PARAMS ((bfd *, sec_ptr,
+ arelent **, asymbol **));
+extern asymbol *bfd_elf32_make_empty_symbol PARAMS ((bfd *));
+extern void bfd_elf32_print_symbol PARAMS ((bfd *, PTR, asymbol *,
+ bfd_print_symbol_type));
+extern void bfd_elf32_get_symbol_info PARAMS ((bfd *, asymbol *,
+ symbol_info *));
+extern alent *bfd_elf32_get_lineno PARAMS ((bfd *, asymbol *));
+extern boolean bfd_elf32_set_arch_mach PARAMS ((bfd *, enum bfd_architecture,
+ unsigned long));
+extern boolean bfd_elf32_find_nearest_line PARAMS ((bfd *, asection *,
+ asymbol **,
+ bfd_vma, CONST char **,
+ CONST char **,
+ unsigned int *));
+extern int bfd_elf32_sizeof_headers PARAMS ((bfd *, boolean));
+extern void bfd_elf32__write_relocs PARAMS ((bfd *, asection *, PTR));
+extern boolean bfd_elf32_new_section_hook PARAMS ((bfd *, asection *));
+extern boolean bfd_elf32_bfd_link_add_symbols
+ PARAMS ((bfd *, struct bfd_link_info *));
+extern boolean bfd_elf32_bfd_final_link
+ PARAMS ((bfd *, struct bfd_link_info *));
+
+extern void bfd_elf32_swap_symbol_in
+ PARAMS ((bfd *, Elf32_External_Sym *, Elf_Internal_Sym *));
+extern void bfd_elf32_swap_symbol_out
+ PARAMS ((bfd *, Elf_Internal_Sym *, Elf32_External_Sym *));
+extern void bfd_elf32_swap_reloc_in
+ PARAMS ((bfd *, Elf32_External_Rel *, Elf_Internal_Rel *));
+extern void bfd_elf32_swap_reloc_out
+ PARAMS ((bfd *, Elf_Internal_Rel *, Elf32_External_Rel *));
+extern void bfd_elf32_swap_reloca_in
+ PARAMS ((bfd *, Elf32_External_Rela *, Elf_Internal_Rela *));
+extern void bfd_elf32_swap_reloca_out
+ PARAMS ((bfd *, Elf_Internal_Rela *, Elf32_External_Rela *));
+extern void bfd_elf32_swap_dyn_in
+ PARAMS ((bfd *, const Elf32_External_Dyn *, Elf_Internal_Dyn *));
+extern void bfd_elf32_swap_dyn_out
+ PARAMS ((bfd *, const Elf_Internal_Dyn *, Elf32_External_Dyn *));
+extern boolean bfd_elf32_add_dynamic_entry
+ PARAMS ((struct bfd_link_info *, bfd_vma, bfd_vma));
+
+/* If the target doesn't have reloc handling written yet: */
+extern void bfd_elf32_no_info_to_howto PARAMS ((bfd *, arelent *,
+ Elf32_Internal_Rela *));
+
+extern const bfd_target *bfd_elf64_object_p PARAMS ((bfd *));
+extern const bfd_target *bfd_elf64_core_file_p PARAMS ((bfd *));
+extern char *bfd_elf64_core_file_failing_command PARAMS ((bfd *));
+extern int bfd_elf64_core_file_failing_signal PARAMS ((bfd *));
+extern boolean bfd_elf64_core_file_matches_executable_p PARAMS ((bfd *,
+ bfd *));
+extern boolean bfd_elf64_set_section_contents PARAMS ((bfd *, sec_ptr, PTR,
+ file_ptr,
+ bfd_size_type));
+
+extern long bfd_elf64_get_symtab_upper_bound PARAMS ((bfd *));
+extern long bfd_elf64_get_symtab PARAMS ((bfd *, asymbol **));
+extern long bfd_elf64_get_dynamic_symtab_upper_bound PARAMS ((bfd *));
+extern long bfd_elf64_canonicalize_dynamic_symtab PARAMS ((bfd *, asymbol **));
+extern long bfd_elf64_get_reloc_upper_bound PARAMS ((bfd *, sec_ptr));
+extern long bfd_elf64_canonicalize_reloc PARAMS ((bfd *, sec_ptr,
+ arelent **, asymbol **));
+extern asymbol *bfd_elf64_make_empty_symbol PARAMS ((bfd *));
+extern void bfd_elf64_print_symbol PARAMS ((bfd *, PTR, asymbol *,
+ bfd_print_symbol_type));
+extern void bfd_elf64_get_symbol_info PARAMS ((bfd *, asymbol *,
+ symbol_info *));
+extern alent *bfd_elf64_get_lineno PARAMS ((bfd *, asymbol *));
+extern boolean bfd_elf64_set_arch_mach PARAMS ((bfd *, enum bfd_architecture,
+ unsigned long));
+extern boolean bfd_elf64_find_nearest_line PARAMS ((bfd *, asection *,
+ asymbol **,
+ bfd_vma, CONST char **,
+ CONST char **,
+ unsigned int *));
+extern int bfd_elf64_sizeof_headers PARAMS ((bfd *, boolean));
+extern void bfd_elf64__write_relocs PARAMS ((bfd *, asection *, PTR));
+extern boolean bfd_elf64_new_section_hook PARAMS ((bfd *, asection *));
+extern boolean bfd_elf64_bfd_link_add_symbols
+ PARAMS ((bfd *, struct bfd_link_info *));
+extern boolean bfd_elf64_bfd_final_link
+ PARAMS ((bfd *, struct bfd_link_info *));
+
+extern void bfd_elf64_swap_symbol_in
+ PARAMS ((bfd *, Elf64_External_Sym *, Elf_Internal_Sym *));
+extern void bfd_elf64_swap_symbol_out
+ PARAMS ((bfd *, Elf_Internal_Sym *, Elf64_External_Sym *));
+extern void bfd_elf64_swap_reloc_in
+ PARAMS ((bfd *, Elf64_External_Rel *, Elf_Internal_Rel *));
+extern void bfd_elf64_swap_reloc_out
+ PARAMS ((bfd *, Elf_Internal_Rel *, Elf64_External_Rel *));
+extern void bfd_elf64_swap_reloca_in
+ PARAMS ((bfd *, Elf64_External_Rela *, Elf_Internal_Rela *));
+extern void bfd_elf64_swap_reloca_out
+ PARAMS ((bfd *, Elf_Internal_Rela *, Elf64_External_Rela *));
+extern void bfd_elf64_swap_dyn_in
+ PARAMS ((bfd *, const Elf64_External_Dyn *, Elf_Internal_Dyn *));
+extern void bfd_elf64_swap_dyn_out
+ PARAMS ((bfd *, const Elf_Internal_Dyn *, Elf64_External_Dyn *));
+extern boolean bfd_elf64_add_dynamic_entry
+ PARAMS ((struct bfd_link_info *, bfd_vma, bfd_vma));
+
+/* If the target doesn't have reloc handling written yet: */
+extern void bfd_elf64_no_info_to_howto PARAMS ((bfd *, arelent *,
+ Elf64_Internal_Rela *));
+
+#endif /* _LIBELF_H_ */
diff --git a/gnu/usr.bin/gdb/bfd/linker.c b/gnu/usr.bin/gdb/bfd/linker.c
new file mode 100644
index 0000000..63391a2
--- /dev/null
+++ b/gnu/usr.bin/gdb/bfd/linker.c
@@ -0,0 +1,2442 @@
+/* linker.c -- BFD linker routines
+ Copyright (C) 1993, 94 Free Software Foundation, Inc.
+ Written by Steve Chamberlain and Ian Lance Taylor, Cygnus Support
+
+This file is part of BFD, the Binary File Descriptor library.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "bfd.h"
+#include "sysdep.h"
+#include "libbfd.h"
+#include "bfdlink.h"
+#include "genlink.h"
+
+/*
+SECTION
+ Linker Functions
+
+@cindex Linker
+ The linker uses three special entry points in the BFD target
+ vector. It is not necessary to write special routines for
+ these entry points when creating a new BFD back end, since
+ generic versions are provided. However, writing them can
+ speed up linking and make it use significantly less runtime
+ memory.
+
+ The first routine creates a hash table used by the other
+ routines. The second routine adds the symbols from an object
+ file to the hash table. The third routine takes all the
+ object files and links them together to create the output
+ file. These routines are designed so that the linker proper
+ does not need to know anything about the symbols in the object
+ files that it is linking. The linker merely arranges the
+ sections as directed by the linker script and lets BFD handle
+ the details of symbols and relocs.
+
+ The second routine and third routines are passed a pointer to
+ a <<struct bfd_link_info>> structure (defined in
+ <<bfdlink.h>>) which holds information relevant to the link,
+ including the linker hash table (which was created by the
+ first routine) and a set of callback functions to the linker
+ proper.
+
+ The generic linker routines are in <<linker.c>>, and use the
+ header file <<genlink.h>>. As of this writing, the only back
+ ends which have implemented versions of these routines are
+ a.out (in <<aoutx.h>>) and ECOFF (in <<ecoff.c>>). The a.out
+ routines are used as examples throughout this section.
+
+@menu
+@* Creating a Linker Hash Table::
+@* Adding Symbols to the Hash Table::
+@* Performing the Final Link::
+@end menu
+
+INODE
+Creating a Linker Hash Table, Adding Symbols to the Hash Table, Linker Functions, Linker Functions
+SUBSECTION
+ Creating a linker hash table
+
+@cindex _bfd_link_hash_table_create in target vector
+@cindex target vector (_bfd_link_hash_table_create)
+ The linker routines must create a hash table, which must be
+ derived from <<struct bfd_link_hash_table>> described in
+ <<bfdlink.c>>. @xref{Hash Tables} for information on how to
+ create a derived hash table. This entry point is called using
+ the target vector of the linker output file.
+
+ The <<_bfd_link_hash_table_create>> entry point must allocate
+ and initialize an instance of the desired hash table. If the
+ back end does not require any additional information to be
+ stored with the entries in the hash table, the entry point may
+ simply create a <<struct bfd_link_hash_table>>. Most likely,
+ however, some additional information will be needed.
+
+ For example, with each entry in the hash table the a.out
+ linker keeps the index the symbol has in the final output file
+ (this index number is used so that when doing a relocateable
+ link the symbol index used in the output file can be quickly
+ filled in when copying over a reloc). The a.out linker code
+ defines the required structures and functions for a hash table
+ derived from <<struct bfd_link_hash_table>>. The a.out linker
+ hash table is created by the function
+ <<NAME(aout,link_hash_table_create)>>; it simply allocates
+ space for the hash table, initializes it, and returns a
+ pointer to it.
+
+ When writing the linker routines for a new back end, you will
+ generally not know exactly which fields will be required until
+ you have finished. You should simply create a new hash table
+ which defines no additional fields, and then simply add fields
+ as they become necessary.
+
+INODE
+Adding Symbols to the Hash Table, Performing the Final Link, Creating a Linker Hash Table, Linker Functions
+SUBSECTION
+ Adding symbols to the hash table
+
+@cindex _bfd_link_add_symbols in target vector
+@cindex target vector (_bfd_link_add_symbols)
+ The linker proper will call the <<_bfd_link_add_symbols>>
+ entry point for each object file or archive which is to be
+ linked (typically these are the files named on the command
+ line, but some may also come from the linker script). The
+ entry point is responsible for examining the file. For an
+ object file, BFD must add any relevant symbol information to
+ the hash table. For an archive, BFD must determine which
+ elements of the archive should be used and adding them to the
+ link.
+
+ The a.out version of this entry point is
+ <<NAME(aout,link_add_symbols)>>.
+
+@menu
+@* Differing file formats::
+@* Adding symbols from an object file::
+@* Adding symbols from an archive::
+@end menu
+
+INODE
+Differing file formats, Adding symbols from an object file, Adding Symbols to the Hash Table, Adding Symbols to the Hash Table
+SUBSUBSECTION
+ Differing file formats
+
+ Normally all the files involved in a link will be of the same
+ format, but it is also possible to link together different
+ format object files, and the back end must support that. The
+ <<_bfd_link_add_symbols>> entry point is called via the target
+ vector of the file to be added. This has an important
+ consequence: the function may not assume that the hash table
+ is the type created by the corresponding
+ <<_bfd_link_hash_table_create>> vector. All the
+ <<_bfd_link_add_symbols>> function can assume about the hash
+ table is that it is derived from <<struct
+ bfd_link_hash_table>>.
+
+ Sometimes the <<_bfd_link_add_symbols>> function must store
+ some information in the hash table entry to be used by the
+ <<_bfd_final_link>> function. In such a case the <<creator>>
+ field of the hash table must be checked to make sure that the
+ hash table was created by an object file of the same format.
+
+ The <<_bfd_final_link>> routine must be prepared to handle a
+ hash entry without any extra information added by the
+ <<_bfd_link_add_symbols>> function. A hash entry without
+ extra information will also occur when the linker script
+ directs the linker to create a symbol. Note that, regardless
+ of how a hash table entry is added, all the fields will be
+ initialized to some sort of null value by the hash table entry
+ initialization function.
+
+ See <<ecoff_link_add_externals>> for an example of how to
+ check the <<creator>> field before saving information (in this
+ case, the ECOFF external symbol debugging information) in a
+ hash table entry.
+
+INODE
+Adding symbols from an object file, Adding symbols from an archive, Differing file formats, Adding Symbols to the Hash Table
+SUBSUBSECTION
+ Adding symbols from an object file
+
+ When the <<_bfd_link_add_symbols>> routine is passed an object
+ file, it must add all externally visible symbols in that
+ object file to the hash table. The actual work of adding the
+ symbol to the hash table is normally handled by the function
+ <<_bfd_generic_link_add_one_symbol>>. The
+ <<_bfd_link_add_symbols>> routine is responsible for reading
+ all the symbols from the object file and passing the correct
+ information to <<_bfd_generic_link_add_one_symbol>>.
+
+ The <<_bfd_link_add_symbols>> routine should not use
+ <<bfd_canonicalize_symtab>> to read the symbols. The point of
+ providing this routine is to avoid the overhead of converting
+ the symbols into generic <<asymbol>> structures.
+
+@findex _bfd_generic_link_add_one_symbol
+ <<_bfd_generic_link_add_one_symbol>> handles the details of
+ combining common symbols, warning about multiple definitions,
+ and so forth. It takes arguments which describe the symbol to
+ add, notably symbol flags, a section, and an offset. The
+ symbol flags include such things as <<BSF_WEAK>> or
+ <<BSF_INDIRECT>>. The section is a section in the object
+ file, or something like <<bfd_und_section_ptr>> for an undefined
+ symbol or <<bfd_com_section_ptr>> for a common symbol.
+
+ If the <<_bfd_final_link>> routine is also going to need to
+ read the symbol information, the <<_bfd_link_add_symbols>>
+ routine should save it somewhere attached to the object file
+ BFD. However, the information should only be saved if the
+ <<keep_memory>> field of the <<info>> argument is true, so
+ that the <<-no-keep-memory>> linker switch is effective.
+
+ The a.out function which adds symbols from an object file is
+ <<aout_link_add_object_symbols>>, and most of the interesting
+ work is in <<aout_link_add_symbols>>. The latter saves
+ pointers to the hash tables entries created by
+ <<_bfd_generic_link_add_one_symbol>> indexed by symbol number,
+ so that the <<_bfd_final_link>> routine does not have to call
+ the hash table lookup routine to locate the entry.
+
+INODE
+Adding symbols from an archive, , Adding symbols from an object file, Adding Symbols to the Hash Table
+SUBSUBSECTION
+ Adding symbols from an archive
+
+ When the <<_bfd_link_add_symbols>> routine is passed an
+ archive, it must look through the symbols defined by the
+ archive and decide which elements of the archive should be
+ included in the link. For each such element it must call the
+ <<add_archive_element>> linker callback, and it must add the
+ symbols from the object file to the linker hash table.
+
+@findex _bfd_generic_link_add_archive_symbols
+ In most cases the work of looking through the symbols in the
+ archive should be done by the
+ <<_bfd_generic_link_add_archive_symbols>> function. This
+ function builds a hash table from the archive symbol table and
+ looks through the list of undefined symbols to see which
+ elements should be included.
+ <<_bfd_generic_link_add_archive_symbols>> is passed a function
+ to call to make the final decision about adding an archive
+ element to the link and to do the actual work of adding the
+ symbols to the linker hash table.
+
+ The function passed to
+ <<_bfd_generic_link_add_archive_symbols>> must read the
+ symbols of the archive element and decide whether the archive
+ element should be included in the link. If the element is to
+ be included, the <<add_archive_element>> linker callback
+ routine must be called with the element as an argument, and
+ the elements symbols must be added to the linker hash table
+ just as though the element had itself been passed to the
+ <<_bfd_link_add_symbols>> function.
+
+ When the a.out <<_bfd_link_add_symbols>> function receives an
+ archive, it calls <<_bfd_generic_link_add_archive_symbols>>
+ passing <<aout_link_check_archive_element>> as the function
+ argument. <<aout_link_check_archive_element>> calls
+ <<aout_link_check_ar_symbols>>. If the latter decides to add
+ the element (an element is only added if it provides a real,
+ non-common, definition for a previously undefined or common
+ symbol) it calls the <<add_archive_element>> callback and then
+ <<aout_link_check_archive_element>> calls
+ <<aout_link_add_symbols>> to actually add the symbols to the
+ linker hash table.
+
+ The ECOFF back end is unusual in that it does not normally
+ call <<_bfd_generic_link_add_archive_symbols>>, because ECOFF
+ archives already contain a hash table of symbols. The ECOFF
+ back end searches the archive itself to avoid the overhead of
+ creating a new hash table.
+
+INODE
+Performing the Final Link, , Adding Symbols to the Hash Table, Linker Functions
+SUBSECTION
+ Performing the final link
+
+@cindex _bfd_link_final_link in target vector
+@cindex target vector (_bfd_final_link)
+ When all the input files have been processed, the linker calls
+ the <<_bfd_final_link>> entry point of the output BFD. This
+ routine is responsible for producing the final output file,
+ which has several aspects. It must relocate the contents of
+ the input sections and copy the data into the output sections.
+ It must build an output symbol table including any local
+ symbols from the input files and the global symbols from the
+ hash table. When producing relocateable output, it must
+ modify the input relocs and write them into the output file.
+ There may also be object format dependent work to be done.
+
+ The linker will also call the <<write_object_contents>> entry
+ point when the BFD is closed. The two entry points must work
+ together in order to produce the correct output file.
+
+ The details of how this works are inevitably dependent upon
+ the specific object file format. The a.out
+ <<_bfd_final_link>> routine is <<NAME(aout,final_link)>>.
+
+@menu
+@* Information provided by the linker::
+@* Relocating the section contents::
+@* Writing the symbol table::
+@end menu
+
+INODE
+Information provided by the linker, Relocating the section contents, Performing the Final Link, Performing the Final Link
+SUBSUBSECTION
+ Information provided by the linker
+
+ Before the linker calls the <<_bfd_final_link>> entry point,
+ it sets up some data structures for the function to use.
+
+ The <<input_bfds>> field of the <<bfd_link_info>> structure
+ will point to a list of all the input files included in the
+ link. These files are linked through the <<link_next>> field
+ of the <<bfd>> structure.
+
+ Each section in the output file will have a list of
+ <<link_order>> structures attached to the <<link_order_head>>
+ field (the <<link_order>> structure is defined in
+ <<bfdlink.h>>). These structures describe how to create the
+ contents of the output section in terms of the contents of
+ various input sections, fill constants, and, eventually, other
+ types of information. They also describe relocs that must be
+ created by the BFD backend, but do not correspond to any input
+ file; this is used to support -Ur, which builds constructors
+ while generating a relocateable object file.
+
+INODE
+Relocating the section contents, Writing the symbol table, Information provided by the linker, Performing the Final Link
+SUBSUBSECTION
+ Relocating the section contents
+
+ The <<_bfd_final_link>> function should look through the
+ <<link_order>> structures attached to each section of the
+ output file. Each <<link_order>> structure should either be
+ handled specially, or it should be passed to the function
+ <<_bfd_default_link_order>> which will do the right thing
+ (<<_bfd_default_link_order>> is defined in <<linker.c>>).
+
+ For efficiency, a <<link_order>> of type
+ <<bfd_indirect_link_order>> whose associated section belongs
+ to a BFD of the same format as the output BFD must be handled
+ specially. This type of <<link_order>> describes part of an
+ output section in terms of a section belonging to one of the
+ input files. The <<_bfd_final_link>> function should read the
+ contents of the section and any associated relocs, apply the
+ relocs to the section contents, and write out the modified
+ section contents. If performing a relocateable link, the
+ relocs themselves must also be modified and written out.
+
+@findex _bfd_relocate_contents
+@findex _bfd_final_link_relocate
+ The functions <<_bfd_relocate_contents>> and
+ <<_bfd_final_link_relocate>> provide some general support for
+ performing the actual relocations, notably overflow checking.
+ Their arguments include information about the symbol the
+ relocation is against and a <<reloc_howto_type>> argument
+ which describes the relocation to perform. These functions
+ are defined in <<reloc.c>>.
+
+ The a.out function which handles reading, relocating, and
+ writing section contents is <<aout_link_input_section>>. The
+ actual relocation is done in <<aout_link_input_section_std>>
+ and <<aout_link_input_section_ext>>.
+
+INODE
+Writing the symbol table, , Relocating the section contents, Performing the Final Link
+SUBSUBSECTION
+ Writing the symbol table
+
+ The <<_bfd_final_link>> function must gather all the symbols
+ in the input files and write them out. It must also write out
+ all the symbols in the global hash table. This must be
+ controlled by the <<strip>> and <<discard>> fields of the
+ <<bfd_link_info>> structure.
+
+ The local symbols of the input files will not have been
+ entered into the linker hash table. The <<_bfd_final_link>>
+ routine must consider each input file and include the symbols
+ in the output file. It may be convenient to do this when
+ looking through the <<link_order>> structures, or it may be
+ done by stepping through the <<input_bfds>> list.
+
+ The <<_bfd_final_link>> routine must also traverse the global
+ hash table to gather all the externally visible symbols. It
+ is possible that most of the externally visible symbols may be
+ written out when considering the symbols of each input file,
+ but it is still necessary to traverse the hash table since the
+ linker script may have defined some symbols that are not in
+ any of the input files. The <<written>> field in the
+ <<bfd_link_hash_entry>> structure may be used to determine
+ which entries in the hash table have not already been written
+ out.
+
+ The <<strip>> field of the <<bfd_link_info>> structure
+ controls which symbols are written out. The possible values
+ are listed in <<bfdlink.h>>. If the value is <<strip_some>>,
+ then the <<keep_hash>> field of the <<bfd_link_info>>
+ structure is a hash table of symbols to keep; each symbol
+ should be looked up in this hash table, and only symbols which
+ are present should be included in the output file.
+
+ If the <<strip>> field of the <<bfd_link_info>> structure
+ permits local symbols to be written out, the <<discard>> field
+ is used to further controls which local symbols are included
+ in the output file. If the value is <<discard_l>>, then all
+ local symbols which begin with a certain prefix are discarded;
+ this prefix is described by the <<lprefix>> and
+ <<lprefix_len>> fields of the <<bfd_link_info>> structure.
+
+ The a.out backend handles symbols by calling
+ <<aout_link_write_symbols>> on each input BFD and then
+ traversing the global hash table with the function
+ <<aout_link_write_other_symbol>>. It builds a string table
+ while writing out the symbols, which is written to the output
+ file at the end of <<NAME(aout,final_link)>>.
+*/
+
+static struct bfd_hash_entry *generic_link_hash_newfunc
+ PARAMS ((struct bfd_hash_entry *, struct bfd_hash_table *,
+ const char *));
+static boolean generic_link_read_symbols
+ PARAMS ((bfd *));
+static boolean generic_link_add_symbols
+ PARAMS ((bfd *, struct bfd_link_info *, boolean collect));
+static boolean generic_link_add_object_symbols
+ PARAMS ((bfd *, struct bfd_link_info *, boolean collect));
+static boolean generic_link_check_archive_element_no_collect
+ PARAMS ((bfd *, struct bfd_link_info *, boolean *pneeded));
+static boolean generic_link_check_archive_element_collect
+ PARAMS ((bfd *, struct bfd_link_info *, boolean *pneeded));
+static boolean generic_link_check_archive_element
+ PARAMS ((bfd *, struct bfd_link_info *, boolean *pneeded, boolean collect));
+static boolean generic_link_add_symbol_list
+ PARAMS ((bfd *, struct bfd_link_info *, bfd_size_type count, asymbol **,
+ boolean collect));
+static boolean generic_add_output_symbol
+ PARAMS ((bfd *, size_t *psymalloc, asymbol *));
+static boolean default_fill_link_order
+ PARAMS ((bfd *, struct bfd_link_info *, asection *,
+ struct bfd_link_order *));
+static boolean default_indirect_link_order
+ PARAMS ((bfd *, struct bfd_link_info *, asection *,
+ struct bfd_link_order *));
+
+/* The link hash table structure is defined in bfdlink.h. It provides
+ a base hash table which the backend specific hash tables are built
+ upon. */
+
+/* Routine to create an entry in the link hash table. */
+
+struct bfd_hash_entry *
+_bfd_link_hash_newfunc (entry, table, string)
+ struct bfd_hash_entry *entry;
+ struct bfd_hash_table *table;
+ const char *string;
+{
+ struct bfd_link_hash_entry *ret = (struct bfd_link_hash_entry *) entry;
+
+ /* Allocate the structure if it has not already been allocated by a
+ subclass. */
+ if (ret == (struct bfd_link_hash_entry *) NULL)
+ ret = ((struct bfd_link_hash_entry *)
+ bfd_hash_allocate (table, sizeof (struct bfd_link_hash_entry)));
+ if (ret == (struct bfd_link_hash_entry *) NULL)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ return NULL;
+ }
+
+ /* Call the allocation method of the superclass. */
+ ret = ((struct bfd_link_hash_entry *)
+ bfd_hash_newfunc ((struct bfd_hash_entry *) ret, table, string));
+
+ if (ret)
+ {
+ /* Initialize the local fields. */
+ ret->type = bfd_link_hash_new;
+ ret->next = NULL;
+ }
+
+ return (struct bfd_hash_entry *) ret;
+}
+
+/* Initialize a link hash table. The BFD argument is the one
+ responsible for creating this table. */
+
+boolean
+_bfd_link_hash_table_init (table, abfd, newfunc)
+ struct bfd_link_hash_table *table;
+ bfd *abfd;
+ struct bfd_hash_entry *(*newfunc) PARAMS ((struct bfd_hash_entry *,
+ struct bfd_hash_table *,
+ const char *));
+{
+ table->creator = abfd->xvec;
+ table->undefs = NULL;
+ table->undefs_tail = NULL;
+ return bfd_hash_table_init (&table->table, newfunc);
+}
+
+/* Look up a symbol in a link hash table. If follow is true, we
+ follow bfd_link_hash_indirect and bfd_link_hash_warning links to
+ the real symbol. */
+
+struct bfd_link_hash_entry *
+bfd_link_hash_lookup (table, string, create, copy, follow)
+ struct bfd_link_hash_table *table;
+ const char *string;
+ boolean create;
+ boolean copy;
+ boolean follow;
+{
+ struct bfd_link_hash_entry *ret;
+
+ ret = ((struct bfd_link_hash_entry *)
+ bfd_hash_lookup (&table->table, string, create, copy));
+
+ if (follow && ret != (struct bfd_link_hash_entry *) NULL)
+ {
+ while (ret->type == bfd_link_hash_indirect
+ || ret->type == bfd_link_hash_warning)
+ ret = ret->u.i.link;
+ }
+
+ return ret;
+}
+
+/* Traverse a generic link hash table. The only reason this is not a
+ macro is to do better type checking. This code presumes that an
+ argument passed as a struct bfd_hash_entry * may be caught as a
+ struct bfd_link_hash_entry * with no explicit cast required on the
+ call. */
+
+void
+bfd_link_hash_traverse (table, func, info)
+ struct bfd_link_hash_table *table;
+ boolean (*func) PARAMS ((struct bfd_link_hash_entry *, PTR));
+ PTR info;
+{
+ bfd_hash_traverse (&table->table,
+ ((boolean (*) PARAMS ((struct bfd_hash_entry *, PTR)))
+ func),
+ info);
+}
+
+/* Add a symbol to the linker hash table undefs list. */
+
+INLINE void
+bfd_link_add_undef (table, h)
+ struct bfd_link_hash_table *table;
+ struct bfd_link_hash_entry *h;
+{
+ BFD_ASSERT (h->next == NULL);
+ if (table->undefs_tail != (struct bfd_link_hash_entry *) NULL)
+ table->undefs_tail->next = h;
+ if (table->undefs == (struct bfd_link_hash_entry *) NULL)
+ table->undefs = h;
+ table->undefs_tail = h;
+}
+
+/* Routine to create an entry in an generic link hash table. */
+
+static struct bfd_hash_entry *
+generic_link_hash_newfunc (entry, table, string)
+ struct bfd_hash_entry *entry;
+ struct bfd_hash_table *table;
+ const char *string;
+{
+ struct generic_link_hash_entry *ret =
+ (struct generic_link_hash_entry *) entry;
+
+ /* Allocate the structure if it has not already been allocated by a
+ subclass. */
+ if (ret == (struct generic_link_hash_entry *) NULL)
+ ret = ((struct generic_link_hash_entry *)
+ bfd_hash_allocate (table, sizeof (struct generic_link_hash_entry)));
+ if (ret == (struct generic_link_hash_entry *) NULL)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ return NULL;
+ }
+
+ /* Call the allocation method of the superclass. */
+ ret = ((struct generic_link_hash_entry *)
+ _bfd_link_hash_newfunc ((struct bfd_hash_entry *) ret,
+ table, string));
+
+ if (ret)
+ {
+ /* Set local fields. */
+ ret->written = false;
+ ret->sym = NULL;
+ }
+
+ return (struct bfd_hash_entry *) ret;
+}
+
+/* Create an generic link hash table. */
+
+struct bfd_link_hash_table *
+_bfd_generic_link_hash_table_create (abfd)
+ bfd *abfd;
+{
+ struct generic_link_hash_table *ret;
+
+ ret = ((struct generic_link_hash_table *)
+ malloc (sizeof (struct generic_link_hash_table)));
+ if (!ret)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ return (struct bfd_link_hash_table *) NULL;
+ }
+ if (! _bfd_link_hash_table_init (&ret->root, abfd,
+ generic_link_hash_newfunc))
+ {
+ free (ret);
+ return (struct bfd_link_hash_table *) NULL;
+ }
+ return &ret->root;
+}
+
+/* Grab the symbols for an object file when doing a generic link. We
+ store the symbols in the outsymbols field. We need to keep them
+ around for the entire link to ensure that we only read them once.
+ If we read them multiple times, we might wind up with relocs and
+ the hash table pointing to different instances of the symbol
+ structure. */
+
+static boolean
+generic_link_read_symbols (abfd)
+ bfd *abfd;
+{
+ if (abfd->outsymbols == (asymbol **) NULL)
+ {
+ long symsize;
+ long symcount;
+
+ symsize = bfd_get_symtab_upper_bound (abfd);
+ if (symsize < 0)
+ return false;
+ abfd->outsymbols = (asymbol **) bfd_alloc (abfd, symsize);
+ if (abfd->outsymbols == NULL && symsize != 0)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ return false;
+ }
+ symcount = bfd_canonicalize_symtab (abfd, abfd->outsymbols);
+ if (symcount < 0)
+ return false;
+ abfd->symcount = symcount;
+ }
+
+ return true;
+}
+
+/* Generic function to add symbols to from an object file to the
+ global hash table. This version does not automatically collect
+ constructors by name. */
+
+boolean
+_bfd_generic_link_add_symbols (abfd, info)
+ bfd *abfd;
+ struct bfd_link_info *info;
+{
+ return generic_link_add_symbols (abfd, info, false);
+}
+
+/* Generic function to add symbols from an object file to the global
+ hash table. This version automatically collects constructors by
+ name, as the collect2 program does. It should be used for any
+ target which does not provide some other mechanism for setting up
+ constructors and destructors; these are approximately those targets
+ for which gcc uses collect2 and do not support stabs. */
+
+boolean
+_bfd_generic_link_add_symbols_collect (abfd, info)
+ bfd *abfd;
+ struct bfd_link_info *info;
+{
+ return generic_link_add_symbols (abfd, info, true);
+}
+
+/* Add symbols from an object file to the global hash table. */
+
+static boolean
+generic_link_add_symbols (abfd, info, collect)
+ bfd *abfd;
+ struct bfd_link_info *info;
+ boolean collect;
+{
+ boolean ret;
+
+ switch (bfd_get_format (abfd))
+ {
+ case bfd_object:
+ ret = generic_link_add_object_symbols (abfd, info, collect);
+ break;
+ case bfd_archive:
+ ret = (_bfd_generic_link_add_archive_symbols
+ (abfd, info,
+ (collect
+ ? generic_link_check_archive_element_collect
+ : generic_link_check_archive_element_no_collect)));
+ break;
+ default:
+ bfd_set_error (bfd_error_wrong_format);
+ ret = false;
+ }
+
+ return ret;
+}
+
+/* Add symbols from an object file to the global hash table. */
+
+static boolean
+generic_link_add_object_symbols (abfd, info, collect)
+ bfd *abfd;
+ struct bfd_link_info *info;
+ boolean collect;
+{
+ if (! generic_link_read_symbols (abfd))
+ return false;
+ return generic_link_add_symbol_list (abfd, info,
+ _bfd_generic_link_get_symcount (abfd),
+ _bfd_generic_link_get_symbols (abfd),
+ collect);
+}
+
+/* We build a hash table of all symbols defined in an archive. */
+
+/* An archive symbol may be defined by multiple archive elements.
+ This linked list is used to hold the elements. */
+
+struct archive_list
+{
+ struct archive_list *next;
+ int indx;
+};
+
+/* An entry in an archive hash table. */
+
+struct archive_hash_entry
+{
+ struct bfd_hash_entry root;
+ /* Where the symbol is defined. */
+ struct archive_list *defs;
+};
+
+/* An archive hash table itself. */
+
+struct archive_hash_table
+{
+ struct bfd_hash_table table;
+};
+
+static struct bfd_hash_entry *archive_hash_newfunc
+ PARAMS ((struct bfd_hash_entry *, struct bfd_hash_table *, const char *));
+static boolean archive_hash_table_init
+ PARAMS ((struct archive_hash_table *,
+ struct bfd_hash_entry *(*) (struct bfd_hash_entry *,
+ struct bfd_hash_table *,
+ const char *)));
+
+/* Create a new entry for an archive hash table. */
+
+static struct bfd_hash_entry *
+archive_hash_newfunc (entry, table, string)
+ struct bfd_hash_entry *entry;
+ struct bfd_hash_table *table;
+ const char *string;
+{
+ struct archive_hash_entry *ret = (struct archive_hash_entry *) entry;
+
+ /* Allocate the structure if it has not already been allocated by a
+ subclass. */
+ if (ret == (struct archive_hash_entry *) NULL)
+ ret = ((struct archive_hash_entry *)
+ bfd_hash_allocate (table, sizeof (struct archive_hash_entry)));
+ if (ret == (struct archive_hash_entry *) NULL)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ return NULL;
+ }
+
+ /* Call the allocation method of the superclass. */
+ ret = ((struct archive_hash_entry *)
+ bfd_hash_newfunc ((struct bfd_hash_entry *) ret, table, string));
+
+ if (ret)
+ {
+ /* Initialize the local fields. */
+ ret->defs = (struct archive_list *) NULL;
+ }
+
+ return (struct bfd_hash_entry *) ret;
+}
+
+/* Initialize an archive hash table. */
+
+static boolean
+archive_hash_table_init (table, newfunc)
+ struct archive_hash_table *table;
+ struct bfd_hash_entry *(*newfunc) PARAMS ((struct bfd_hash_entry *,
+ struct bfd_hash_table *,
+ const char *));
+{
+ return bfd_hash_table_init (&table->table, newfunc);
+}
+
+/* Look up an entry in an archive hash table. */
+
+#define archive_hash_lookup(t, string, create, copy) \
+ ((struct archive_hash_entry *) \
+ bfd_hash_lookup (&(t)->table, (string), (create), (copy)))
+
+/* Allocate space in an archive hash table. */
+
+#define archive_hash_allocate(t, size) bfd_hash_allocate (&(t)->table, (size))
+
+/* Free an archive hash table. */
+
+#define archive_hash_table_free(t) bfd_hash_table_free (&(t)->table)
+
+/* Generic function to add symbols from an archive file to the global
+ hash file. This function presumes that the archive symbol table
+ has already been read in (this is normally done by the
+ bfd_check_format entry point). It looks through the undefined and
+ common symbols and searches the archive symbol table for them. If
+ it finds an entry, it includes the associated object file in the
+ link.
+
+ The old linker looked through the archive symbol table for
+ undefined symbols. We do it the other way around, looking through
+ undefined symbols for symbols defined in the archive. The
+ advantage of the newer scheme is that we only have to look through
+ the list of undefined symbols once, whereas the old method had to
+ re-search the symbol table each time a new object file was added.
+
+ The CHECKFN argument is used to see if an object file should be
+ included. CHECKFN should set *PNEEDED to true if the object file
+ should be included, and must also call the bfd_link_info
+ add_archive_element callback function and handle adding the symbols
+ to the global hash table. CHECKFN should only return false if some
+ sort of error occurs.
+
+ For some formats, such as a.out, it is possible to look through an
+ object file but not actually include it in the link. The
+ archive_pass field in a BFD is used to avoid checking the symbols
+ of an object files too many times. When an object is included in
+ the link, archive_pass is set to -1. If an object is scanned but
+ not included, archive_pass is set to the pass number. The pass
+ number is incremented each time a new object file is included. The
+ pass number is used because when a new object file is included it
+ may create new undefined symbols which cause a previously examined
+ object file to be included. */
+
+boolean
+_bfd_generic_link_add_archive_symbols (abfd, info, checkfn)
+ bfd *abfd;
+ struct bfd_link_info *info;
+ boolean (*checkfn) PARAMS ((bfd *, struct bfd_link_info *,
+ boolean *pneeded));
+{
+ carsym *arsyms;
+ carsym *arsym_end;
+ register carsym *arsym;
+ int pass;
+ struct archive_hash_table arsym_hash;
+ int indx;
+ struct bfd_link_hash_entry **pundef;
+
+ if (! bfd_has_map (abfd))
+ {
+ bfd_set_error (bfd_error_no_symbols);
+ return false;
+ }
+
+ arsyms = bfd_ardata (abfd)->symdefs;
+ arsym_end = arsyms + bfd_ardata (abfd)->symdef_count;
+
+ /* In order to quickly determine whether an symbol is defined in
+ this archive, we build a hash table of the symbols. */
+ if (! archive_hash_table_init (&arsym_hash, archive_hash_newfunc))
+ return false;
+ for (arsym = arsyms, indx = 0; arsym < arsym_end; arsym++, indx++)
+ {
+ struct archive_hash_entry *arh;
+ struct archive_list *l, **pp;
+
+ arh = archive_hash_lookup (&arsym_hash, arsym->name, true, false);
+ if (arh == (struct archive_hash_entry *) NULL)
+ goto error_return;
+ l = ((struct archive_list *)
+ archive_hash_allocate (&arsym_hash, sizeof (struct archive_list)));
+ if (l == NULL)
+ goto error_return;
+ l->indx = indx;
+ for (pp = &arh->defs;
+ *pp != (struct archive_list *) NULL;
+ pp = &(*pp)->next)
+ ;
+ *pp = l;
+ l->next = NULL;
+ }
+
+ /* The archive_pass field in the archive itself is used to
+ initialize PASS, sine we may search the same archive multiple
+ times. */
+ pass = abfd->archive_pass;
+ if (pass == 0)
+ pass = 1;
+
+ /* New undefined symbols are added to the end of the list, so we
+ only need to look through it once. */
+ pundef = &info->hash->undefs;
+ while (*pundef != (struct bfd_link_hash_entry *) NULL)
+ {
+ struct bfd_link_hash_entry *h;
+ struct archive_hash_entry *arh;
+ struct archive_list *l;
+
+ h = *pundef;
+
+ /* When a symbol is defined, it is not necessarily removed from
+ the list. */
+ if (h->type != bfd_link_hash_undefined
+ && h->type != bfd_link_hash_common)
+ {
+ /* Remove this entry from the list, for general cleanliness
+ and because we are going to look through the list again
+ if we search any more libraries. We can't remove the
+ entry if it is the tail, because that would lose any
+ entries we add to the list later on (it would also cause
+ us to lose track of whether the symbol has been
+ referenced). */
+ if (*pundef != info->hash->undefs_tail)
+ *pundef = (*pundef)->next;
+ else
+ pundef = &(*pundef)->next;
+ continue;
+ }
+
+ /* Look for this symbol in the archive symbol map. */
+ arh = archive_hash_lookup (&arsym_hash, h->root.string, false, false);
+ if (arh == (struct archive_hash_entry *) NULL)
+ {
+ pundef = &(*pundef)->next;
+ continue;
+ }
+
+ /* Look at all the objects which define this symbol. */
+ for (l = arh->defs; l != (struct archive_list *) NULL; l = l->next)
+ {
+ bfd *element;
+ boolean needed;
+
+ /* If the symbol has gotten defined along the way, quit. */
+ if (h->type != bfd_link_hash_undefined
+ && h->type != bfd_link_hash_common)
+ break;
+
+ element = bfd_get_elt_at_index (abfd, l->indx);
+ if (element == (bfd *) NULL)
+ goto error_return;
+
+ /* If we've already included this element, or if we've
+ already checked it on this pass, continue. */
+ if (element->archive_pass == -1
+ || element->archive_pass == pass)
+ continue;
+
+ /* If we can't figure this element out, just ignore it. */
+ if (! bfd_check_format (element, bfd_object))
+ {
+ element->archive_pass = -1;
+ continue;
+ }
+
+ /* CHECKFN will see if this element should be included, and
+ go ahead and include it if appropriate. */
+ if (! (*checkfn) (element, info, &needed))
+ goto error_return;
+
+ if (! needed)
+ element->archive_pass = pass;
+ else
+ {
+ element->archive_pass = -1;
+
+ /* Increment the pass count to show that we may need to
+ recheck object files which were already checked. */
+ ++pass;
+ }
+ }
+
+ pundef = &(*pundef)->next;
+ }
+
+ archive_hash_table_free (&arsym_hash);
+
+ /* Save PASS in case we are called again. */
+ abfd->archive_pass = pass;
+
+ return true;
+
+ error_return:
+ archive_hash_table_free (&arsym_hash);
+ return false;
+}
+
+/* See if we should include an archive element. This version is used
+ when we do not want to automatically collect constructors based on
+ the symbol name, presumably because we have some other mechanism
+ for finding them. */
+
+static boolean
+generic_link_check_archive_element_no_collect (abfd, info, pneeded)
+ bfd *abfd;
+ struct bfd_link_info *info;
+ boolean *pneeded;
+{
+ return generic_link_check_archive_element (abfd, info, pneeded, false);
+}
+
+/* See if we should include an archive element. This version is used
+ when we want to automatically collect constructors based on the
+ symbol name, as collect2 does. */
+
+static boolean
+generic_link_check_archive_element_collect (abfd, info, pneeded)
+ bfd *abfd;
+ struct bfd_link_info *info;
+ boolean *pneeded;
+{
+ return generic_link_check_archive_element (abfd, info, pneeded, true);
+}
+
+/* See if we should include an archive element. Optionally collect
+ constructors. */
+
+static boolean
+generic_link_check_archive_element (abfd, info, pneeded, collect)
+ bfd *abfd;
+ struct bfd_link_info *info;
+ boolean *pneeded;
+ boolean collect;
+{
+ asymbol **pp, **ppend;
+
+ *pneeded = false;
+
+ if (! generic_link_read_symbols (abfd))
+ return false;
+
+ pp = _bfd_generic_link_get_symbols (abfd);
+ ppend = pp + _bfd_generic_link_get_symcount (abfd);
+ for (; pp < ppend; pp++)
+ {
+ asymbol *p;
+ struct bfd_link_hash_entry *h;
+
+ p = *pp;
+
+ /* We are only interested in globally visible symbols. */
+ if (! bfd_is_com_section (p->section)
+ && (p->flags & (BSF_GLOBAL | BSF_INDIRECT | BSF_WEAK)) == 0)
+ continue;
+
+ /* We are only interested if we know something about this
+ symbol, and it is undefined or common. An undefined weak
+ symbol (type bfd_link_hash_weak) is not considered to be a
+ reference when pulling files out of an archive. See the SVR4
+ ABI, p. 4-27. */
+ h = bfd_link_hash_lookup (info->hash, bfd_asymbol_name (p), false,
+ false, true);
+ if (h == (struct bfd_link_hash_entry *) NULL
+ || (h->type != bfd_link_hash_undefined
+ && h->type != bfd_link_hash_common))
+ continue;
+
+ /* P is a symbol we are looking for. */
+
+ if (! bfd_is_com_section (p->section))
+ {
+ bfd_size_type symcount;
+ asymbol **symbols;
+
+ /* This object file defines this symbol, so pull it in. */
+ if (! (*info->callbacks->add_archive_element) (info, abfd,
+ bfd_asymbol_name (p)))
+ return false;
+ symcount = _bfd_generic_link_get_symcount (abfd);
+ symbols = _bfd_generic_link_get_symbols (abfd);
+ if (! generic_link_add_symbol_list (abfd, info, symcount,
+ symbols, collect))
+ return false;
+ *pneeded = true;
+ return true;
+ }
+
+ /* P is a common symbol. */
+
+ if (h->type == bfd_link_hash_undefined)
+ {
+ bfd *symbfd;
+
+ symbfd = h->u.undef.abfd;
+ if (symbfd == (bfd *) NULL)
+ {
+ /* This symbol was created as undefined from outside
+ BFD. We assume that we should link in the object
+ file. This is for the -u option in the linker. */
+ if (! (*info->callbacks->add_archive_element)
+ (info, abfd, bfd_asymbol_name (p)))
+ return false;
+ *pneeded = true;
+ return true;
+ }
+
+ /* Turn the symbol into a common symbol but do not link in
+ the object file. This is how a.out works. Object
+ formats that require different semantics must implement
+ this function differently. This symbol is already on the
+ undefs list. We add the section to a common section
+ attached to symbfd to ensure that it is in a BFD which
+ will be linked in. */
+ h->type = bfd_link_hash_common;
+ h->u.c.size = bfd_asymbol_value (p);
+ if (p->section == bfd_com_section_ptr)
+ h->u.c.section = bfd_make_section_old_way (symbfd, "COMMON");
+ else
+ h->u.c.section = bfd_make_section_old_way (symbfd,
+ p->section->name);
+ h->u.c.section->flags = SEC_ALLOC;
+ }
+ else
+ {
+ /* Adjust the size of the common symbol if necessary. This
+ is how a.out works. Object formats that require
+ different semantics must implement this function
+ differently. */
+ if (bfd_asymbol_value (p) > h->u.c.size)
+ h->u.c.size = bfd_asymbol_value (p);
+ }
+ }
+
+ /* This archive element is not needed. */
+ return true;
+}
+
+/* Add the symbols from an object file to the global hash table. ABFD
+ is the object file. INFO is the linker information. SYMBOL_COUNT
+ is the number of symbols. SYMBOLS is the list of symbols. COLLECT
+ is true if constructors should be automatically collected by name
+ as is done by collect2. */
+
+static boolean
+generic_link_add_symbol_list (abfd, info, symbol_count, symbols, collect)
+ bfd *abfd;
+ struct bfd_link_info *info;
+ bfd_size_type symbol_count;
+ asymbol **symbols;
+ boolean collect;
+{
+ asymbol **pp, **ppend;
+
+ pp = symbols;
+ ppend = symbols + symbol_count;
+ for (; pp < ppend; pp++)
+ {
+ asymbol *p;
+
+ p = *pp;
+
+ if ((p->flags & (BSF_INDIRECT
+ | BSF_WARNING
+ | BSF_GLOBAL
+ | BSF_CONSTRUCTOR
+ | BSF_WEAK)) != 0
+ || bfd_is_und_section (bfd_get_section (p))
+ || bfd_is_com_section (bfd_get_section (p))
+ || bfd_is_ind_section (bfd_get_section (p)))
+ {
+ const char *name;
+ const char *string;
+ struct generic_link_hash_entry *h;
+
+ name = bfd_asymbol_name (p);
+ if ((p->flags & BSF_INDIRECT) != 0
+ || bfd_is_ind_section (p->section))
+ string = bfd_asymbol_name ((asymbol *) p->value);
+ else if ((p->flags & BSF_WARNING) != 0)
+ {
+ /* The name of P is actually the warning string, and the
+ value is actually a pointer to the symbol to warn
+ about. */
+ string = name;
+ name = bfd_asymbol_name ((asymbol *) p->value);
+ }
+ else
+ string = NULL;
+
+ h = NULL;
+ if (! (_bfd_generic_link_add_one_symbol
+ (info, abfd, name, p->flags, bfd_get_section (p),
+ p->value, string, false, collect,
+ (struct bfd_link_hash_entry **) &h)))
+ return false;
+
+ /* Save the BFD symbol so that we don't lose any backend
+ specific information that may be attached to it. We only
+ want this one if it gives more information than the
+ existing one; we don't want to replace a defined symbol
+ with an undefined one. This routine may be called with a
+ hash table other than the generic hash table, so we only
+ do this if we are certain that the hash table is a
+ generic one. */
+ if (info->hash->creator == abfd->xvec)
+ {
+ if (h->sym == (asymbol *) NULL
+ || (! bfd_is_und_section (bfd_get_section (p))
+ && (! bfd_is_com_section (bfd_get_section (p))
+ || bfd_is_und_section (bfd_get_section (h->sym)))))
+ {
+ h->sym = p;
+ /* BSF_OLD_COMMON is a hack to support COFF reloc
+ reading, and it should go away when the COFF
+ linker is switched to the new version. */
+ if (bfd_is_com_section (bfd_get_section (p)))
+ p->flags |= BSF_OLD_COMMON;
+ }
+
+ /* Store a back pointer from the symbol to the hash
+ table entry for the benefit of relaxation code until
+ it gets rewritten to not use asymbol structures. */
+ p->udata = (PTR) h;
+ }
+ }
+ }
+
+ return true;
+}
+
+/* We use a state table to deal with adding symbols from an object
+ file. The first index into the state table describes the symbol
+ from the object file. The second index into the state table is the
+ type of the symbol in the hash table. */
+
+/* The symbol from the object file is turned into one of these row
+ values. */
+
+enum link_row
+{
+ UNDEF_ROW, /* Undefined. */
+ UNDEFW_ROW, /* Weak undefined. */
+ DEF_ROW, /* Defined. */
+ DEFW_ROW, /* Weak defined. */
+ COMMON_ROW, /* Common. */
+ INDR_ROW, /* Indirect. */
+ WARN_ROW, /* Warning. */
+ SET_ROW /* Member of set. */
+};
+
+/* apparently needed for Hitachi 3050R(HI-UX/WE2)? */
+#undef FAIL
+
+/* The actions to take in the state table. */
+
+enum link_action
+{
+ FAIL, /* Abort. */
+ UND, /* Mark symbol undefined. */
+ WEAK, /* Mark symbol weak undefined. */
+ DEF, /* Mark symbol defined. */
+ COM, /* Mark symbol common. */
+ REF, /* Mark defined symbol referenced. */
+ CREF, /* Possibly warn about common reference to defined symbol. */
+ CDEF, /* Define existing common symbol. */
+ NOACT, /* No action. */
+ BIG, /* Mark symbol common using largest size. */
+ MDEF, /* Multiple definition error. */
+ MIND, /* Multiple indirect symbols. */
+ IND, /* Make indirect symbol. */
+ SET, /* Add value to set. */
+ MWARN, /* Make warning symbol. */
+ WARN, /* Issue warning. */
+ CWARN, /* Warn if referenced, else MWARN. */
+ CYCLE, /* Repeat with symbol pointed to. */
+ REFC, /* Mark indirect symbol referenced and then CYCLE. */
+ WARNC /* Issue warning and then CYCLE. */
+};
+
+/* The state table itself. The first index is a link_row and the
+ second index is a bfd_link_hash_type. */
+
+static const enum link_action link_action[8][7] =
+{
+ /* current\prev new undef weak def com indr warn */
+ /* UNDEF_ROW */ {UND, NOACT, NOACT, REF, NOACT, REFC, WARNC },
+ /* UNDEFW_ROW */ {WEAK, WEAK, NOACT, REF, NOACT, REFC, WARNC },
+ /* DEF_ROW */ {DEF, DEF, DEF, MDEF, CDEF, MDEF, CYCLE },
+ /* DEFW_ROW */ {DEF, DEF, DEF, NOACT, NOACT, NOACT, CYCLE },
+ /* COMMON_ROW */ {COM, COM, COM, CREF, BIG, MDEF, WARNC },
+ /* INDR_ROW */ {IND, IND, IND, MDEF, MDEF, MIND, CYCLE },
+ /* WARN_ROW */ {MWARN, WARN, WARN, CWARN, WARN, CWARN, CYCLE },
+ /* SET_ROW */ {SET, SET, SET, SET, SET, CYCLE, CYCLE }
+};
+
+/* Most of the entries in the LINK_ACTION table are straightforward,
+ but a few are somewhat subtle.
+
+ A reference to an indirect symbol (UNDEF_ROW/indr or
+ UNDEFW_ROW/indr) is counted as a reference both to the indirect
+ symbol and to the symbol the indirect symbol points to.
+
+ A reference to a warning symbol (UNDEF_ROW/warn or UNDEFW_ROW/warn)
+ causes the warning to be issued.
+
+ A common definition of an indirect symbol (COMMON_ROW/indr) is
+ treated as a multiple definition error. Likewise for an indirect
+ definition of a common symbol (INDR_ROW/com).
+
+ An indirect definition of a warning (INDR_ROW/warn) does not cause
+ the warning to be issued.
+
+ If a warning is created for an indirect symbol (WARN_ROW/indr) no
+ warning is created for the symbol the indirect symbol points to.
+
+ Adding an entry to a set does not count as a reference to a set,
+ and no warning is issued (SET_ROW/warn). */
+
+/* Add a symbol to the global hash table.
+ ABFD is the BFD the symbol comes from.
+ NAME is the name of the symbol.
+ FLAGS is the BSF_* bits associated with the symbol.
+ SECTION is the section in which the symbol is defined; this may be
+ bfd_und_section_ptr or bfd_com_section_ptr.
+ VALUE is the value of the symbol, relative to the section.
+ STRING is used for either an indirect symbol, in which case it is
+ the name of the symbol to indirect to, or a warning symbol, in
+ which case it is the warning string.
+ COPY is true if NAME or STRING must be copied into locally
+ allocated memory if they need to be saved.
+ COLLECT is true if we should automatically collect gcc constructor
+ or destructor names as collect2 does.
+ HASHP, if not NULL, is a place to store the created hash table
+ entry; if *HASHP is not NULL, the caller has already looked up
+ the hash table entry, and stored it in *HASHP. */
+
+boolean
+_bfd_generic_link_add_one_symbol (info, abfd, name, flags, section, value,
+ string, copy, collect, hashp)
+ struct bfd_link_info *info;
+ bfd *abfd;
+ const char *name;
+ flagword flags;
+ asection *section;
+ bfd_vma value;
+ const char *string;
+ boolean copy;
+ boolean collect;
+ struct bfd_link_hash_entry **hashp;
+{
+ enum link_row row;
+ struct bfd_link_hash_entry *h;
+ boolean cycle;
+
+ if (bfd_is_ind_section (section)
+ || (flags & BSF_INDIRECT) != 0)
+ row = INDR_ROW;
+ else if ((flags & BSF_WARNING) != 0)
+ row = WARN_ROW;
+ else if ((flags & BSF_CONSTRUCTOR) != 0)
+ row = SET_ROW;
+ else if (bfd_is_und_section (section))
+ {
+ if ((flags & BSF_WEAK) != 0)
+ row = UNDEFW_ROW;
+ else
+ row = UNDEF_ROW;
+ }
+ else if ((flags & BSF_WEAK) != 0)
+ row = DEFW_ROW;
+ else if (bfd_is_com_section (section))
+ row = COMMON_ROW;
+ else
+ row = DEF_ROW;
+
+ if (hashp != NULL && *hashp != NULL)
+ {
+ h = *hashp;
+ BFD_ASSERT (strcmp (h->root.string, name) == 0);
+ }
+ else
+ {
+ h = bfd_link_hash_lookup (info->hash, name, true, copy, false);
+ if (h == NULL)
+ {
+ if (hashp != NULL)
+ *hashp = NULL;
+ return false;
+ }
+ }
+
+ if (info->notice_hash != (struct bfd_hash_table *) NULL
+ && (bfd_hash_lookup (info->notice_hash, name, false, false)
+ != (struct bfd_hash_entry *) NULL))
+ {
+ if (! (*info->callbacks->notice) (info, name, abfd, section, value))
+ return false;
+ }
+
+ if (hashp != (struct bfd_link_hash_entry **) NULL)
+ *hashp = h;
+
+ do
+ {
+ enum link_action action;
+
+ cycle = false;
+ action = link_action[(int) row][(int) h->type];
+ switch (action)
+ {
+ case FAIL:
+ abort ();
+
+ case NOACT:
+ /* Do nothing. */
+ break;
+
+ case UND:
+ /* Make a new undefined symbol. */
+ h->type = bfd_link_hash_undefined;
+ h->u.undef.abfd = abfd;
+ bfd_link_add_undef (info->hash, h);
+ break;
+
+ case WEAK:
+ /* Make a new weak undefined symbol. */
+ h->type = bfd_link_hash_weak;
+ h->u.undef.abfd = abfd;
+ break;
+
+ case CDEF:
+ /* We have found a definition for a symbol which was
+ previously common. */
+ BFD_ASSERT (h->type == bfd_link_hash_common);
+ if (! ((*info->callbacks->multiple_common)
+ (info, name,
+ h->u.c.section->owner, bfd_link_hash_common, h->u.c.size,
+ abfd, bfd_link_hash_defined, (bfd_vma) 0)))
+ return false;
+ /* Fall through. */
+ case DEF:
+ /* Define a symbol. */
+ h->type = bfd_link_hash_defined;
+ h->u.def.section = section;
+ h->u.def.value = value;
+
+ /* If we have been asked to, we act like collect2 and
+ identify all functions that might be global constructors
+ and destructors and pass them up in a callback. We only
+ do this for certain object file types, since many object
+ file types can handle this automatically. */
+ if (collect && name[0] == '_')
+ {
+ const char *s;
+
+ /* A constructor or destructor name starts like this:
+ _+GLOBAL_[_.$][ID][_.$]
+ where the first [_.$] and the second are the same
+ character (we accept any character there, in case a
+ new object file format comes along with even worse
+ naming restrictions). */
+
+#define CONS_PREFIX "GLOBAL_"
+#define CONS_PREFIX_LEN (sizeof CONS_PREFIX - 1)
+
+ s = name + 1;
+ while (*s == '_')
+ ++s;
+ if (s[0] == 'G'
+ && strncmp (s, CONS_PREFIX, CONS_PREFIX_LEN - 1) == 0)
+ {
+ char c;
+
+ c = s[CONS_PREFIX_LEN + 1];
+ if ((c == 'I' || c == 'D')
+ && s[CONS_PREFIX_LEN] == s[CONS_PREFIX_LEN + 2])
+ {
+ if (! ((*info->callbacks->constructor)
+ (info,
+ c == 'I' ? true : false,
+ name, abfd, section, value)))
+ return false;
+ }
+ }
+ }
+
+ break;
+
+ case COM:
+ /* We have found a common definition for a symbol. */
+ if (h->type == bfd_link_hash_new)
+ bfd_link_add_undef (info->hash, h);
+ h->type = bfd_link_hash_common;
+ h->u.c.size = value;
+ if (section == bfd_com_section_ptr)
+ {
+ h->u.c.section = bfd_make_section_old_way (abfd, "COMMON");
+ h->u.c.section->flags = SEC_ALLOC;
+ }
+ else if (section->owner != abfd)
+ {
+ h->u.c.section = bfd_make_section_old_way (abfd, section->name);
+ h->u.c.section->flags = SEC_ALLOC;
+ }
+ else
+ h->u.c.section = section;
+ break;
+
+ case REF:
+ /* A reference to a defined symbol. */
+ if (h->next == NULL && info->hash->undefs_tail != h)
+ h->next = h;
+ break;
+
+ case BIG:
+ /* We have found a common definition for a symbol which
+ already had a common definition. Use the maximum of the
+ two sizes. */
+ BFD_ASSERT (h->type == bfd_link_hash_common);
+ if (! ((*info->callbacks->multiple_common)
+ (info, name,
+ h->u.c.section->owner, bfd_link_hash_common, h->u.c.size,
+ abfd, bfd_link_hash_common, value)))
+ return false;
+ if (value > h->u.c.size)
+ h->u.c.size = value;
+ break;
+
+ case CREF:
+ /* We have found a common definition for a symbol which was
+ already defined. */
+ BFD_ASSERT (h->type == bfd_link_hash_defined);
+ if (! ((*info->callbacks->multiple_common)
+ (info, name,
+ h->u.def.section->owner, bfd_link_hash_defined, (bfd_vma) 0,
+ abfd, bfd_link_hash_common, value)))
+ return false;
+ break;
+
+ case MIND:
+ /* Multiple indirect symbols. This is OK if they both point
+ to the same symbol. */
+ if (strcmp (h->u.i.link->root.string, string) == 0)
+ break;
+ /* Fall through. */
+ case MDEF:
+ /* Handle a multiple definition. */
+ {
+ asection *msec;
+ bfd_vma mval;
+
+ switch (h->type)
+ {
+ case bfd_link_hash_defined:
+ msec = h->u.def.section;
+ mval = h->u.def.value;
+ break;
+ case bfd_link_hash_common:
+ msec = bfd_com_section_ptr;
+ mval = h->u.c.size;
+ break;
+ case bfd_link_hash_indirect:
+ msec = bfd_ind_section_ptr;
+ mval = 0;
+ break;
+ default:
+ abort ();
+ }
+
+ if (! ((*info->callbacks->multiple_definition)
+ (info, name, msec->owner, msec, mval, abfd, section,
+ value)))
+ return false;
+ }
+ break;
+
+ case IND:
+ /* Create an indirect symbol. */
+ {
+ struct bfd_link_hash_entry *inh;
+
+ /* STRING is the name of the symbol we want to indirect
+ to. */
+ inh = bfd_link_hash_lookup (info->hash, string, true, copy,
+ false);
+ if (inh == (struct bfd_link_hash_entry *) NULL)
+ return false;
+ if (inh->type == bfd_link_hash_new)
+ {
+ inh->type = bfd_link_hash_undefined;
+ inh->u.undef.abfd = abfd;
+ bfd_link_add_undef (info->hash, inh);
+ }
+
+ /* If the indirect symbol has been referenced, we need to
+ push the reference down to the symbol we are
+ referencing. */
+ if (h->type != bfd_link_hash_new)
+ {
+ row = UNDEF_ROW;
+ cycle = true;
+ }
+
+ h->type = bfd_link_hash_indirect;
+ h->u.i.link = inh;
+ }
+ break;
+
+ case SET:
+ /* Add an entry to a set. */
+ if (! (*info->callbacks->add_to_set) (info, h, BFD_RELOC_CTOR,
+ abfd, section, value))
+ return false;
+ break;
+
+ case WARNC:
+ /* Issue a warning and cycle. */
+ if (h->u.i.warning != NULL)
+ {
+ if (! (*info->callbacks->warning) (info, h->u.i.warning))
+ return false;
+ /* Only issue a warning once. */
+ h->u.i.warning = NULL;
+ }
+ /* Fall through. */
+ case CYCLE:
+ /* Try again with the referenced symbol. */
+ h = h->u.i.link;
+ cycle = true;
+ break;
+
+ case REFC:
+ /* A reference to an indirect symbol. */
+ if (h->next == NULL && info->hash->undefs_tail != h)
+ h->next = h;
+ h = h->u.i.link;
+ cycle = true;
+ break;
+
+ case WARN:
+ /* Issue a warning. */
+ if (! (*info->callbacks->warning) (info, string))
+ return false;
+ break;
+
+ case CWARN:
+ /* Warn if this symbol has been referenced already,
+ otherwise either add a warning or cycle. A symbol has
+ been referenced if the next field is not NULL, or it is
+ the tail of the undefined symbol list. The REF case
+ above helps to ensure this. */
+ if (h->next != NULL || info->hash->undefs_tail == h)
+ {
+ if (! (*info->callbacks->warning) (info, string))
+ return false;
+ break;
+ }
+ /* Fall through. */
+ case MWARN:
+ /* Make a warning symbol. */
+ {
+ struct bfd_link_hash_entry *sub;
+
+ /* STRING is the warning to give. */
+ sub = ((struct bfd_link_hash_entry *)
+ bfd_hash_allocate (&info->hash->table,
+ sizeof (struct bfd_link_hash_entry)));
+ if (!sub)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ return false;
+ }
+ *sub = *h;
+ h->type = bfd_link_hash_warning;
+ h->u.i.link = sub;
+ if (! copy)
+ h->u.i.warning = string;
+ else
+ {
+ char *w;
+
+ w = bfd_hash_allocate (&info->hash->table,
+ strlen (string) + 1);
+ strcpy (w, string);
+ h->u.i.warning = w;
+ }
+ }
+ break;
+ }
+ }
+ while (cycle);
+
+ return true;
+}
+
+/* Generic final link routine. */
+
+boolean
+_bfd_generic_final_link (abfd, info)
+ bfd *abfd;
+ struct bfd_link_info *info;
+{
+ bfd *sub;
+ asection *o;
+ struct bfd_link_order *p;
+ size_t outsymalloc;
+ struct generic_write_global_symbol_info wginfo;
+
+ abfd->outsymbols = (asymbol **) NULL;
+ abfd->symcount = 0;
+ outsymalloc = 0;
+
+ /* Build the output symbol table. */
+ for (sub = info->input_bfds; sub != (bfd *) NULL; sub = sub->link_next)
+ if (! _bfd_generic_link_output_symbols (abfd, sub, info, &outsymalloc))
+ return false;
+
+ /* Accumulate the global symbols. */
+ wginfo.info = info;
+ wginfo.output_bfd = abfd;
+ wginfo.psymalloc = &outsymalloc;
+ _bfd_generic_link_hash_traverse (_bfd_generic_hash_table (info),
+ _bfd_generic_link_write_global_symbol,
+ (PTR) &wginfo);
+
+ if (info->relocateable)
+ {
+ /* Allocate space for the output relocs for each section. */
+ for (o = abfd->sections;
+ o != (asection *) NULL;
+ o = o->next)
+ {
+ o->reloc_count = 0;
+ for (p = o->link_order_head;
+ p != (struct bfd_link_order *) NULL;
+ p = p->next)
+ {
+ if (p->type == bfd_section_reloc_link_order
+ || p->type == bfd_symbol_reloc_link_order)
+ ++o->reloc_count;
+ else if (p->type == bfd_indirect_link_order)
+ {
+ asection *input_section;
+ bfd *input_bfd;
+ long relsize;
+ arelent **relocs;
+ asymbol **symbols;
+ long reloc_count;
+
+ input_section = p->u.indirect.section;
+ input_bfd = input_section->owner;
+ relsize = bfd_get_reloc_upper_bound (input_bfd,
+ input_section);
+ if (relsize < 0)
+ return false;
+ relocs = (arelent **) malloc ((size_t) relsize);
+ if (!relocs && relsize != 0)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ return false;
+ }
+ symbols = _bfd_generic_link_get_symbols (input_bfd);
+ reloc_count = bfd_canonicalize_reloc (input_bfd,
+ input_section,
+ relocs,
+ symbols);
+ if (reloc_count < 0)
+ return false;
+ BFD_ASSERT (reloc_count == input_section->reloc_count);
+ o->reloc_count += reloc_count;
+ free (relocs);
+ }
+ }
+ if (o->reloc_count > 0)
+ {
+ o->orelocation = ((arelent **)
+ bfd_alloc (abfd,
+ (o->reloc_count
+ * sizeof (arelent *))));
+ if (!o->orelocation)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ return false;
+ }
+ o->flags |= SEC_RELOC;
+ /* Reset the count so that it can be used as an index
+ when putting in the output relocs. */
+ o->reloc_count = 0;
+ }
+ }
+ }
+
+ /* Handle all the link order information for the sections. */
+ for (o = abfd->sections;
+ o != (asection *) NULL;
+ o = o->next)
+ {
+ for (p = o->link_order_head;
+ p != (struct bfd_link_order *) NULL;
+ p = p->next)
+ {
+ switch (p->type)
+ {
+ case bfd_section_reloc_link_order:
+ case bfd_symbol_reloc_link_order:
+ if (! _bfd_generic_reloc_link_order (abfd, info, o, p))
+ return false;
+ break;
+ default:
+ if (! _bfd_default_link_order (abfd, info, o, p))
+ return false;
+ break;
+ }
+ }
+ }
+
+ return true;
+}
+
+/* Add an output symbol to the output BFD. */
+
+static boolean
+generic_add_output_symbol (output_bfd, psymalloc, sym)
+ bfd *output_bfd;
+ size_t *psymalloc;
+ asymbol *sym;
+{
+ if (output_bfd->symcount >= *psymalloc)
+ {
+ asymbol **newsyms;
+
+ if (*psymalloc == 0)
+ *psymalloc = 124;
+ else
+ *psymalloc *= 2;
+ if (output_bfd->outsymbols == (asymbol **) NULL)
+ newsyms = (asymbol **) malloc (*psymalloc * sizeof (asymbol *));
+ else
+ newsyms = (asymbol **) realloc (output_bfd->outsymbols,
+ *psymalloc * sizeof (asymbol *));
+ if (newsyms == (asymbol **) NULL)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ return false;
+ }
+ output_bfd->outsymbols = newsyms;
+ }
+
+ output_bfd->outsymbols[output_bfd->symcount] = sym;
+ ++output_bfd->symcount;
+
+ return true;
+}
+
+/* Handle the symbols for an input BFD. */
+
+boolean
+_bfd_generic_link_output_symbols (output_bfd, input_bfd, info, psymalloc)
+ bfd *output_bfd;
+ bfd *input_bfd;
+ struct bfd_link_info *info;
+ size_t *psymalloc;
+{
+ asymbol **sym_ptr;
+ asymbol **sym_end;
+
+ if (! generic_link_read_symbols (input_bfd))
+ return false;
+
+ /* Create a filename symbol if we are supposed to. */
+ if (info->create_object_symbols_section != (asection *) NULL)
+ {
+ asection *sec;
+
+ for (sec = input_bfd->sections;
+ sec != (asection *) NULL;
+ sec = sec->next)
+ {
+ if (sec->output_section == info->create_object_symbols_section)
+ {
+ asymbol *newsym;
+
+ newsym = bfd_make_empty_symbol (input_bfd);
+ if (!newsym)
+ return false;
+ newsym->name = input_bfd->filename;
+ newsym->value = 0;
+ newsym->flags = BSF_LOCAL | BSF_FILE;
+ newsym->section = sec;
+
+ if (! generic_add_output_symbol (output_bfd, psymalloc,
+ newsym))
+ return false;
+
+ break;
+ }
+ }
+ }
+
+ /* Adjust the values of the globally visible symbols, and write out
+ local symbols. */
+ sym_ptr = _bfd_generic_link_get_symbols (input_bfd);
+ sym_end = sym_ptr + _bfd_generic_link_get_symcount (input_bfd);
+ for (; sym_ptr < sym_end; sym_ptr++)
+ {
+ asymbol *sym;
+ struct generic_link_hash_entry *h;
+ boolean output;
+
+ h = (struct generic_link_hash_entry *) NULL;
+ sym = *sym_ptr;
+ if ((sym->flags & (BSF_INDIRECT
+ | BSF_WARNING
+ | BSF_GLOBAL
+ | BSF_CONSTRUCTOR
+ | BSF_WEAK)) != 0
+ || bfd_is_und_section (bfd_get_section (sym))
+ || bfd_is_com_section (bfd_get_section (sym))
+ || bfd_is_ind_section (bfd_get_section (sym)))
+ {
+ h = _bfd_generic_link_hash_lookup (_bfd_generic_hash_table (info),
+ bfd_asymbol_name (sym),
+ false, false, true);
+ if (h != (struct generic_link_hash_entry *) NULL)
+ {
+ /* Force all references to this symbol to point to
+ the same area in memory. It is possible that
+ this routine will be called with a hash table
+ other than a generic hash table, so we double
+ check that. */
+ if (info->hash->creator == input_bfd->xvec)
+ {
+ if (h->sym != (asymbol *) NULL)
+ *sym_ptr = sym = h->sym;
+ }
+
+ switch (h->root.type)
+ {
+ default:
+ case bfd_link_hash_new:
+ abort ();
+ case bfd_link_hash_undefined:
+ case bfd_link_hash_weak:
+ break;
+ case bfd_link_hash_defined:
+ sym->value = h->root.u.def.value;
+ sym->section = h->root.u.def.section;
+ sym->flags |= BSF_GLOBAL;
+ break;
+ case bfd_link_hash_common:
+ sym->value = h->root.u.c.size;
+ sym->flags |= BSF_GLOBAL;
+ if (! bfd_is_com_section (sym->section))
+ {
+ BFD_ASSERT (bfd_is_und_section (sym->section));
+ sym->section = bfd_com_section_ptr;
+ }
+ /* We do not set the section of the symbol to
+ h->root.u.c.section. That value was saved so
+ that we would know where to allocate the symbol
+ if it was defined. In this case the type is
+ still bfd_link_hash_common, so we did not define
+ it, so we do not want to use that section. */
+ break;
+ }
+ }
+ }
+
+ /* This switch is straight from the old code in
+ write_file_locals in ldsym.c. */
+ if (info->strip == strip_some
+ && (bfd_hash_lookup (info->keep_hash, bfd_asymbol_name (sym),
+ false, false)
+ == (struct bfd_hash_entry *) NULL))
+ output = false;
+ else if ((sym->flags & (BSF_GLOBAL | BSF_WEAK)) != 0)
+ {
+ /* If this symbol is marked as occurring now, rather
+ than at the end, output it now. This is used for
+ COFF C_EXT FCN symbols. FIXME: There must be a
+ better way. */
+ if (bfd_asymbol_bfd (sym) == input_bfd
+ && (sym->flags & BSF_NOT_AT_END) != 0)
+ output = true;
+ else
+ output = false;
+ }
+ else if (bfd_is_ind_section (sym->section))
+ output = false;
+ else if ((sym->flags & BSF_DEBUGGING) != 0)
+ {
+ if (info->strip == strip_none)
+ output = true;
+ else
+ output = false;
+ }
+ else if (bfd_is_und_section (sym->section)
+ || bfd_is_com_section (sym->section))
+ output = false;
+ else if ((sym->flags & BSF_LOCAL) != 0)
+ {
+ if ((sym->flags & BSF_WARNING) != 0)
+ output = false;
+ else
+ {
+ switch (info->discard)
+ {
+ default:
+ case discard_all:
+ output = false;
+ break;
+ case discard_l:
+ if (bfd_asymbol_name (sym)[0] == info->lprefix[0]
+ && (info->lprefix_len == 1
+ || strncmp (bfd_asymbol_name (sym), info->lprefix,
+ info->lprefix_len) == 0))
+ output = false;
+ else
+ output = true;
+ break;
+ case discard_none:
+ output = true;
+ break;
+ }
+ }
+ }
+ else if ((sym->flags & BSF_CONSTRUCTOR))
+ {
+ if (info->strip != strip_all)
+ output = true;
+ else
+ output = false;
+ }
+ else
+ abort ();
+
+ if (output)
+ {
+ if (! generic_add_output_symbol (output_bfd, psymalloc, sym))
+ return false;
+ if (h != (struct generic_link_hash_entry *) NULL)
+ h->written = true;
+ }
+ }
+
+ return true;
+}
+
+/* Write out a global symbol, if it hasn't already been written out.
+ This is called for each symbol in the hash table. */
+
+boolean
+_bfd_generic_link_write_global_symbol (h, data)
+ struct generic_link_hash_entry *h;
+ PTR data;
+{
+ struct generic_write_global_symbol_info *wginfo =
+ (struct generic_write_global_symbol_info *) data;
+ asymbol *sym;
+
+ if (h->written)
+ return true;
+
+ h->written = true;
+
+ if (wginfo->info->strip == strip_all
+ || (wginfo->info->strip == strip_some
+ && bfd_hash_lookup (wginfo->info->keep_hash, h->root.root.string,
+ false, false) == NULL))
+ return true;
+
+ if (h->sym != (asymbol *) NULL)
+ {
+ sym = h->sym;
+ BFD_ASSERT (strcmp (bfd_asymbol_name (sym), h->root.root.string) == 0);
+ }
+ else
+ {
+ sym = bfd_make_empty_symbol (wginfo->output_bfd);
+ if (!sym)
+ return false;
+ sym->name = h->root.root.string;
+ sym->flags = 0;
+ }
+
+ switch (h->root.type)
+ {
+ default:
+ case bfd_link_hash_new:
+ abort ();
+ case bfd_link_hash_undefined:
+ sym->section = bfd_und_section_ptr;
+ sym->value = 0;
+ break;
+ case bfd_link_hash_weak:
+ sym->section = bfd_und_section_ptr;
+ sym->value = 0;
+ sym->flags |= BSF_WEAK;
+ break;
+ case bfd_link_hash_defined:
+ sym->section = h->root.u.def.section;
+ sym->value = h->root.u.def.value;
+ break;
+ case bfd_link_hash_common:
+ sym->value = h->root.u.c.size;
+ if (sym->section == NULL)
+ sym->section = bfd_com_section_ptr;
+ else if (! bfd_is_com_section (sym->section))
+ {
+ BFD_ASSERT (bfd_is_und_section (sym->section));
+ sym->section = bfd_com_section_ptr;
+ }
+ /* Do not set the section; see _bfd_generic_link_output_symbols. */
+ break;
+ case bfd_link_hash_indirect:
+ case bfd_link_hash_warning:
+ /* FIXME: What should we do here? */
+ break;
+ }
+
+ sym->flags |= BSF_GLOBAL;
+
+ if (! generic_add_output_symbol (wginfo->output_bfd, wginfo->psymalloc,
+ sym))
+ {
+ /* FIXME: No way to return failure. */
+ abort ();
+ }
+
+ return true;
+}
+
+/* Create a relocation. */
+
+boolean
+_bfd_generic_reloc_link_order (abfd, info, sec, link_order)
+ bfd *abfd;
+ struct bfd_link_info *info;
+ asection *sec;
+ struct bfd_link_order *link_order;
+{
+ arelent *r;
+
+ if (! info->relocateable)
+ abort ();
+ if (sec->orelocation == (arelent **) NULL)
+ abort ();
+
+ r = (arelent *) bfd_alloc (abfd, sizeof (arelent));
+ if (r == (arelent *) NULL)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ return false;
+ }
+
+ r->address = link_order->offset;
+ r->howto = bfd_reloc_type_lookup (abfd, link_order->u.reloc.p->reloc);
+ if (r->howto == (const reloc_howto_type *) NULL)
+ {
+ bfd_set_error (bfd_error_bad_value);
+ return false;
+ }
+
+ /* Get the symbol to use for the relocation. */
+ if (link_order->type == bfd_section_reloc_link_order)
+ r->sym_ptr_ptr = link_order->u.reloc.p->u.section->symbol_ptr_ptr;
+ else
+ {
+ struct generic_link_hash_entry *h;
+
+ h = _bfd_generic_link_hash_lookup (_bfd_generic_hash_table (info),
+ link_order->u.reloc.p->u.name,
+ false, false, true);
+ if (h == (struct generic_link_hash_entry *) NULL
+ || ! h->written)
+ {
+ if (! ((*info->callbacks->unattached_reloc)
+ (info, link_order->u.reloc.p->u.name,
+ (bfd *) NULL, (asection *) NULL, (bfd_vma) 0)))
+ return false;
+ bfd_set_error (bfd_error_bad_value);
+ return false;
+ }
+ r->sym_ptr_ptr = &h->sym;
+ }
+
+ /* If this is an inplace reloc, write the addend to the object file.
+ Otherwise, store it in the reloc addend. */
+ if (! r->howto->partial_inplace)
+ r->addend = link_order->u.reloc.p->addend;
+ else
+ {
+ bfd_size_type size;
+ bfd_reloc_status_type rstat;
+ bfd_byte *buf;
+ boolean ok;
+
+ size = bfd_get_reloc_size (r->howto);
+ buf = (bfd_byte *) bfd_zmalloc (size);
+ if (buf == (bfd_byte *) NULL)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ return false;
+ }
+ rstat = _bfd_relocate_contents (r->howto, abfd,
+ link_order->u.reloc.p->addend, buf);
+ switch (rstat)
+ {
+ case bfd_reloc_ok:
+ break;
+ default:
+ case bfd_reloc_outofrange:
+ abort ();
+ case bfd_reloc_overflow:
+ if (! ((*info->callbacks->reloc_overflow)
+ (info,
+ (link_order->type == bfd_section_reloc_link_order
+ ? bfd_section_name (abfd, link_order->u.reloc.p->u.section)
+ : link_order->u.reloc.p->u.name),
+ r->howto->name, link_order->u.reloc.p->addend,
+ (bfd *) NULL, (asection *) NULL, (bfd_vma) 0)))
+ {
+ free (buf);
+ return false;
+ }
+ break;
+ }
+ ok = bfd_set_section_contents (abfd, sec, (PTR) buf,
+ (file_ptr) link_order->offset, size);
+ free (buf);
+ if (! ok)
+ return false;
+
+ r->addend = 0;
+ }
+
+ sec->orelocation[sec->reloc_count] = r;
+ ++sec->reloc_count;
+
+ return true;
+}
+
+/* Allocate a new link_order for a section. */
+
+struct bfd_link_order *
+bfd_new_link_order (abfd, section)
+ bfd *abfd;
+ asection *section;
+{
+ struct bfd_link_order *new;
+
+ new = ((struct bfd_link_order *)
+ bfd_alloc_by_size_t (abfd, sizeof (struct bfd_link_order)));
+ if (!new)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ return NULL;
+ }
+
+ new->type = bfd_undefined_link_order;
+ new->offset = 0;
+ new->size = 0;
+ new->next = (struct bfd_link_order *) NULL;
+
+ if (section->link_order_tail != (struct bfd_link_order *) NULL)
+ section->link_order_tail->next = new;
+ else
+ section->link_order_head = new;
+ section->link_order_tail = new;
+
+ return new;
+}
+
+/* Default link order processing routine. Note that we can not handle
+ the reloc_link_order types here, since they depend upon the details
+ of how the particular backends generates relocs. */
+
+boolean
+_bfd_default_link_order (abfd, info, sec, link_order)
+ bfd *abfd;
+ struct bfd_link_info *info;
+ asection *sec;
+ struct bfd_link_order *link_order;
+{
+ switch (link_order->type)
+ {
+ case bfd_undefined_link_order:
+ case bfd_section_reloc_link_order:
+ case bfd_symbol_reloc_link_order:
+ default:
+ abort ();
+ case bfd_indirect_link_order:
+ return default_indirect_link_order (abfd, info, sec, link_order);
+ case bfd_fill_link_order:
+ return default_fill_link_order (abfd, info, sec, link_order);
+ case bfd_data_link_order:
+ return bfd_set_section_contents (abfd, sec,
+ (PTR) link_order->u.data.contents,
+ (file_ptr) link_order->offset,
+ link_order->size);
+ }
+}
+
+/* Default routine to handle a bfd_fill_link_order. */
+
+/*ARGSUSED*/
+static boolean
+default_fill_link_order (abfd, info, sec, link_order)
+ bfd *abfd;
+ struct bfd_link_info *info;
+ asection *sec;
+ struct bfd_link_order *link_order;
+{
+ size_t size;
+ char *space;
+ size_t i;
+ int fill;
+ boolean result;
+
+ BFD_ASSERT ((sec->flags & SEC_HAS_CONTENTS) != 0);
+
+ size = (size_t) link_order->size;
+ space = (char *) malloc (size);
+ if (space == NULL && size != 0)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ return false;
+ }
+
+ fill = link_order->u.fill.value;
+ for (i = 0; i < size; i += 2)
+ space[i] = fill >> 8;
+ for (i = 1; i < size; i += 2)
+ space[i] = fill;
+ result = bfd_set_section_contents (abfd, sec, space,
+ (file_ptr) link_order->offset,
+ link_order->size);
+ free (space);
+ return result;
+}
+
+/* Default routine to handle a bfd_indirect_link_order. */
+
+static boolean
+default_indirect_link_order (output_bfd, info, output_section, link_order)
+ bfd *output_bfd;
+ struct bfd_link_info *info;
+ asection *output_section;
+ struct bfd_link_order *link_order;
+{
+ asection *input_section;
+ bfd *input_bfd;
+ bfd_byte *contents = NULL;
+ bfd_byte *new_contents;
+
+ BFD_ASSERT ((output_section->flags & SEC_HAS_CONTENTS) != 0);
+
+ if (link_order->size == 0)
+ return true;
+
+ input_section = link_order->u.indirect.section;
+ input_bfd = input_section->owner;
+
+ BFD_ASSERT (input_section->output_section == output_section);
+ BFD_ASSERT (input_section->output_offset == link_order->offset);
+ BFD_ASSERT (input_section->_cooked_size == link_order->size);
+
+ if (info->relocateable
+ && input_section->reloc_count > 0
+ && output_section->orelocation == (arelent **) NULL)
+ {
+ /* Space has not been allocated for the output relocations.
+ This can happen when we are called by a specific backend
+ because somebody is attempting to link together different
+ types of object files. Handling this case correctly is
+ difficult, and sometimes impossible. */
+ abort ();
+ }
+
+ /* Get the canonical symbols. The generic linker will always have
+ retrieved them by this point, but we may be being called by a
+ specific linker when linking different types of object files
+ together. */
+ if (! generic_link_read_symbols (input_bfd))
+ return false;
+
+ /* Get and relocate the section contents. */
+ contents = (bfd_byte *) malloc (bfd_section_size (input_bfd, input_section));
+ if (contents == NULL && bfd_section_size (input_bfd, input_section) != 0)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ goto error_return;
+ }
+ new_contents = (bfd_get_relocated_section_contents
+ (output_bfd, info, link_order, contents, info->relocateable,
+ _bfd_generic_link_get_symbols (input_bfd)));
+ if (!new_contents)
+ goto error_return;
+
+ /* Output the section contents. */
+ if (! bfd_set_section_contents (output_bfd, output_section,
+ (PTR) new_contents,
+ link_order->offset, link_order->size))
+ goto error_return;
+
+ if (contents != NULL)
+ free (contents);
+ return true;
+
+ error_return:
+ if (contents != NULL)
+ free (contents);
+ return false;
+}
+
+/* A little routine to count the number of relocs in a link_order
+ list. */
+
+unsigned int
+_bfd_count_link_order_relocs (link_order)
+ struct bfd_link_order *link_order;
+{
+ register unsigned int c;
+ register struct bfd_link_order *l;
+
+ c = 0;
+ for (l = link_order; l != (struct bfd_link_order *) NULL; l = l->next)
+ {
+ if (l->type == bfd_section_reloc_link_order
+ || l->type == bfd_symbol_reloc_link_order)
+ ++c;
+ }
+
+ return c;
+}
diff --git a/gnu/usr.bin/gdb/bfd/opncls.c b/gnu/usr.bin/gdb/bfd/opncls.c
new file mode 100644
index 0000000..2d760a1
--- /dev/null
+++ b/gnu/usr.bin/gdb/bfd/opncls.c
@@ -0,0 +1,548 @@
+/* opncls.c -- open and close a BFD.
+ Copyright (C) 1990 91, 92, 93, 94 Free Software Foundation, Inc.
+ Written by Cygnus Support.
+
+This file is part of BFD, the Binary File Descriptor library.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "bfd.h"
+#include "sysdep.h"
+#include "libbfd.h"
+#include "obstack.h"
+
+/* fdopen is a loser -- we should use stdio exclusively. Unfortunately
+ if we do that we can't use fcntl. */
+
+
+#define obstack_chunk_alloc malloc
+#define obstack_chunk_free free
+
+/* Return a new BFD. All BFD's are allocated through this routine. */
+
+bfd *
+_bfd_new_bfd ()
+{
+ bfd *nbfd;
+
+ nbfd = (bfd *)bfd_zmalloc (sizeof (bfd));
+ if (!nbfd)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ return 0;
+ }
+
+ bfd_check_init();
+ if (!obstack_begin(&nbfd->memory, 128))
+ {
+ bfd_set_error (bfd_error_no_memory);
+ return 0;
+ }
+
+ nbfd->arch_info = &bfd_default_arch_struct;
+
+ nbfd->direction = no_direction;
+ nbfd->iostream = NULL;
+ nbfd->where = 0;
+ nbfd->sections = (asection *)NULL;
+ nbfd->format = bfd_unknown;
+ nbfd->my_archive = (bfd *)NULL;
+ nbfd->origin = 0;
+ nbfd->opened_once = false;
+ nbfd->output_has_begun = false;
+ nbfd->section_count = 0;
+ nbfd->usrdata = (PTR)NULL;
+ nbfd->cacheable = false;
+ nbfd->flags = NO_FLAGS;
+ nbfd->mtime_set = false;
+
+ return nbfd;
+}
+
+/* Allocate a new BFD as a member of archive OBFD. */
+
+bfd *
+_bfd_new_bfd_contained_in (obfd)
+ bfd *obfd;
+{
+ bfd *nbfd;
+
+ nbfd = _bfd_new_bfd();
+ nbfd->xvec = obfd->xvec;
+ nbfd->my_archive = obfd;
+ nbfd->direction = read_direction;
+ nbfd->target_defaulted = obfd->target_defaulted;
+ return nbfd;
+}
+
+/*
+SECTION
+ Opening and closing BFDs
+
+*/
+
+/*
+FUNCTION
+ bfd_openr
+
+SYNOPSIS
+ bfd *bfd_openr(CONST char *filename, CONST char *target);
+
+DESCRIPTION
+ Open the file @var{filename} (using <<fopen>>) with the target
+ @var{target}. Return a pointer to the created BFD.
+
+ Calls <<bfd_find_target>>, so @var{target} is interpreted as by
+ that function.
+
+ If <<NULL>> is returned then an error has occured. Possible errors
+ are <<bfd_error_no_memory>>, <<bfd_error_invalid_target>> or <<system_call>> error.
+*/
+
+bfd *
+bfd_openr (filename, target)
+ CONST char *filename;
+ CONST char *target;
+{
+ bfd *nbfd;
+ const bfd_target *target_vec;
+
+ nbfd = _bfd_new_bfd();
+ if (nbfd == NULL) {
+ bfd_set_error (bfd_error_no_memory);
+ return NULL;
+ }
+
+ target_vec = bfd_find_target (target, nbfd);
+ if (target_vec == NULL) {
+ bfd_set_error (bfd_error_invalid_target);
+ return NULL;
+ }
+
+ nbfd->filename = filename;
+ nbfd->direction = read_direction;
+
+ if (bfd_open_file (nbfd) == NULL) {
+ bfd_set_error (bfd_error_system_call); /* File didn't exist, or some such */
+ bfd_release(nbfd,0);
+ return NULL;
+ }
+ return nbfd;
+}
+
+
+/* Don't try to `optimize' this function:
+
+ o - We lock using stack space so that interrupting the locking
+ won't cause a storage leak.
+ o - We open the file stream last, since we don't want to have to
+ close it if anything goes wrong. Closing the stream means closing
+ the file descriptor too, even though we didn't open it.
+ */
+/*
+FUNCTION
+ bfd_fdopenr
+
+SYNOPSIS
+ bfd *bfd_fdopenr(CONST char *filename, CONST char *target, int fd);
+
+DESCRIPTION
+ <<bfd_fdopenr>> is to <<bfd_fopenr>> much like <<fdopen>> is to <<fopen>>.
+ It opens a BFD on a file already described by the @var{fd}
+ supplied.
+
+ When the file is later <<bfd_close>>d, the file descriptor will be closed.
+
+ If the caller desires that this file descriptor be cached by BFD
+ (opened as needed, closed as needed to free descriptors for
+ other opens), with the supplied @var{fd} used as an initial
+ file descriptor (but subject to closure at any time), call
+ bfd_set_cacheable(bfd, 1) on the returned BFD. The default is to
+ assume no cacheing; the file descriptor will remain open until
+ <<bfd_close>>, and will not be affected by BFD operations on other
+ files.
+
+ Possible errors are <<bfd_error_no_memory>>, <<bfd_error_invalid_target>> and <<bfd_error_system_call>>.
+*/
+
+bfd *
+bfd_fdopenr (filename, target, fd)
+ CONST char *filename;
+ CONST char *target;
+ int fd;
+{
+ bfd *nbfd;
+ const bfd_target *target_vec;
+ int fdflags;
+
+ bfd_set_error (bfd_error_system_call);
+
+#ifdef NO_FCNTL
+ fdflags = O_RDWR; /* Assume full access */
+#else
+ fdflags = fcntl (fd, F_GETFL, NULL);
+#endif
+ if (fdflags == -1) return NULL;
+
+ nbfd = _bfd_new_bfd();
+
+ if (nbfd == NULL) {
+ bfd_set_error (bfd_error_no_memory);
+ return NULL;
+ }
+
+ target_vec = bfd_find_target (target, nbfd);
+ if (target_vec == NULL) {
+ bfd_set_error (bfd_error_invalid_target);
+ return NULL;
+ }
+#if defined(VMS) || defined(__GO32__)
+ nbfd->iostream = (char *)fopen(filename, FOPEN_RB);
+#else
+ /* (O_ACCMODE) parens are to avoid Ultrix header file bug */
+ switch (fdflags & (O_ACCMODE)) {
+ case O_RDONLY: nbfd->iostream = (char *) fdopen (fd, FOPEN_RB); break;
+ case O_WRONLY: nbfd->iostream = (char *) fdopen (fd, FOPEN_RUB); break;
+ case O_RDWR: nbfd->iostream = (char *) fdopen (fd, FOPEN_RUB); break;
+ default: abort ();
+ }
+#endif
+ if (nbfd->iostream == NULL) {
+ (void) obstack_free (&nbfd->memory, (PTR)0);
+ return NULL;
+ }
+
+ /* OK, put everything where it belongs */
+
+ nbfd->filename = filename;
+
+ /* As a special case we allow a FD open for read/write to
+ be written through, although doing so requires that we end
+ the previous clause with a preposition. */
+ /* (O_ACCMODE) parens are to avoid Ultrix header file bug */
+ switch (fdflags & (O_ACCMODE)) {
+ case O_RDONLY: nbfd->direction = read_direction; break;
+ case O_WRONLY: nbfd->direction = write_direction; break;
+ case O_RDWR: nbfd->direction = both_direction; break;
+ default: abort ();
+ }
+
+ if (! bfd_cache_init (nbfd))
+ return NULL;
+
+ return nbfd;
+}
+
+/** bfd_openw -- open for writing.
+ Returns a pointer to a freshly-allocated BFD on success, or NULL.
+
+ See comment by bfd_fdopenr before you try to modify this function. */
+
+/*
+FUNCTION
+ bfd_openw
+
+SYNOPSIS
+ bfd *bfd_openw(CONST char *filename, CONST char *target);
+
+DESCRIPTION
+ Create a BFD, associated with file @var{filename}, using the
+ file format @var{target}, and return a pointer to it.
+
+ Possible errors are <<bfd_error_system_call>>, <<bfd_error_no_memory>>,
+ <<bfd_error_invalid_target>>.
+*/
+
+bfd *
+bfd_openw (filename, target)
+ CONST char *filename;
+ CONST char *target;
+{
+ bfd *nbfd;
+ const bfd_target *target_vec;
+
+ bfd_set_error (bfd_error_system_call);
+
+ /* nbfd has to point to head of malloc'ed block so that bfd_close may
+ reclaim it correctly. */
+
+ nbfd = _bfd_new_bfd();
+ if (nbfd == NULL) {
+ bfd_set_error (bfd_error_no_memory);
+ return NULL;
+ }
+
+ target_vec = bfd_find_target (target, nbfd);
+ if (target_vec == NULL) return NULL;
+
+ nbfd->filename = filename;
+ nbfd->direction = write_direction;
+
+ if (bfd_open_file (nbfd) == NULL) {
+ bfd_set_error (bfd_error_system_call); /* File not writeable, etc */
+ (void) obstack_free (&nbfd->memory, (PTR)0);
+ return NULL;
+ }
+ return nbfd;
+}
+
+/*
+
+FUNCTION
+ bfd_close
+
+SYNOPSIS
+ boolean bfd_close(bfd *abfd);
+
+DESCRIPTION
+
+ Close a BFD. If the BFD was open for writing,
+ then pending operations are completed and the file written out
+ and closed. If the created file is executable, then
+ <<chmod>> is called to mark it as such.
+
+ All memory attached to the BFD's obstacks is released.
+
+ The file descriptor associated with the BFD is closed (even
+ if it was passed in to BFD by <<bfd_fdopenr>>).
+
+RETURNS
+ <<true>> is returned if all is ok, otherwise <<false>>.
+*/
+
+
+boolean
+bfd_close (abfd)
+ bfd *abfd;
+{
+ boolean ret;
+
+ if (!bfd_read_p(abfd))
+ if (BFD_SEND_FMT (abfd, _bfd_write_contents, (abfd)) != true)
+ return false;
+
+ if (BFD_SEND (abfd, _close_and_cleanup, (abfd)) != true) return false;
+
+ ret = bfd_cache_close(abfd);
+
+ /* If the file was open for writing and is now executable,
+ make it so */
+ if (ret == true
+ && abfd->direction == write_direction
+ && abfd->flags & EXEC_P) {
+ struct stat buf;
+ stat(abfd->filename, &buf);
+#ifndef S_IXUSR
+#define S_IXUSR 0100 /* Execute by owner. */
+#endif
+#ifndef S_IXGRP
+#define S_IXGRP 0010 /* Execute by group. */
+#endif
+#ifndef S_IXOTH
+#define S_IXOTH 0001 /* Execute by others. */
+#endif
+
+ chmod(abfd->filename, 0777 & (buf.st_mode | S_IXUSR | S_IXGRP | S_IXOTH));
+ }
+ (void) obstack_free (&abfd->memory, (PTR)0);
+ (void) free(abfd);
+ return ret;
+}
+
+/*
+FUNCTION
+ bfd_close_all_done
+
+SYNOPSIS
+ boolean bfd_close_all_done(bfd *);
+
+DESCRIPTION
+ Close a BFD. Differs from <<bfd_close>>
+ since it does not complete any pending operations. This
+ routine would be used if the application had just used BFD for
+ swapping and didn't want to use any of the writing code.
+
+ If the created file is executable, then <<chmod>> is called
+ to mark it as such.
+
+ All memory attached to the BFD's obstacks is released.
+
+RETURNS
+ <<true>> is returned if all is ok, otherwise <<false>>.
+
+*/
+
+boolean
+bfd_close_all_done (abfd)
+ bfd *abfd;
+{
+ boolean ret;
+
+ ret = bfd_cache_close(abfd);
+
+ /* If the file was open for writing and is now executable,
+ make it so */
+ if (ret == true
+ && abfd->direction == write_direction
+ && abfd->flags & EXEC_P) {
+ struct stat buf;
+ stat(abfd->filename, &buf);
+#ifndef S_IXUSR
+#define S_IXUSR 0100 /* Execute by owner. */
+#endif
+#ifndef S_IXGRP
+#define S_IXGRP 0010 /* Execute by group. */
+#endif
+#ifndef S_IXOTH
+#define S_IXOTH 0001 /* Execute by others. */
+#endif
+
+ chmod(abfd->filename, 0x777 &(buf.st_mode | S_IXUSR | S_IXGRP | S_IXOTH));
+ }
+ (void) obstack_free (&abfd->memory, (PTR)0);
+ (void) free(abfd);
+ return ret;
+}
+
+
+/*
+FUNCTION
+ bfd_alloc_size
+
+SYNOPSIS
+ bfd_size_type bfd_alloc_size(bfd *abfd);
+
+DESCRIPTION
+ Return the number of bytes in the obstacks connected to @var{abfd}.
+
+*/
+
+bfd_size_type
+bfd_alloc_size (abfd)
+ bfd *abfd;
+{
+ struct _obstack_chunk *chunk = abfd->memory.chunk;
+ size_t size = 0;
+ while (chunk) {
+ size += chunk->limit - &(chunk->contents[0]);
+ chunk = chunk->prev;
+ }
+ return size;
+}
+
+
+
+/*
+FUNCTION
+ bfd_create
+
+SYNOPSIS
+ bfd *bfd_create(CONST char *filename, bfd *templ);
+
+DESCRIPTION
+ Create a new BFD in the manner of
+ <<bfd_openw>>, but without opening a file. The new BFD
+ takes the target from the target used by @var{template}. The
+ format is always set to <<bfd_object>>.
+
+*/
+
+bfd *
+bfd_create (filename, templ)
+ CONST char *filename;
+ bfd *templ;
+{
+ bfd *nbfd = _bfd_new_bfd();
+ if (nbfd == (bfd *)NULL) {
+ bfd_set_error (bfd_error_no_memory);
+ return (bfd *)NULL;
+ }
+ nbfd->filename = filename;
+ if(templ) {
+ nbfd->xvec = templ->xvec;
+ }
+ nbfd->direction = no_direction;
+ bfd_set_format(nbfd, bfd_object);
+ return nbfd;
+}
+
+/*
+INTERNAL_FUNCTION
+ bfd_alloc_by_size_t
+
+SYNOPSIS
+ PTR bfd_alloc_by_size_t(bfd *abfd, size_t wanted);
+
+DESCRIPTION
+ Allocate a block of @var{wanted} bytes of memory in the obstack
+ attatched to <<abfd>> and return a pointer to it.
+*/
+
+
+PTR
+bfd_alloc_by_size_t (abfd, size)
+ bfd *abfd;
+ size_t size;
+{
+ return obstack_alloc(&(abfd->memory), size);
+}
+
+void
+bfd_alloc_grow (abfd, ptr, size)
+ bfd *abfd;
+ PTR ptr;
+ size_t size;
+{
+ (void) obstack_grow(&(abfd->memory), ptr, size);
+}
+
+PTR
+bfd_alloc_finish (abfd)
+ bfd *abfd;
+{
+ return obstack_finish(&(abfd->memory));
+}
+
+PTR
+bfd_alloc (abfd, size)
+ bfd *abfd;
+ size_t size;
+{
+ return bfd_alloc_by_size_t(abfd, (size_t)size);
+}
+
+PTR
+bfd_zalloc (abfd, size)
+ bfd *abfd;
+ size_t size;
+{
+ PTR res;
+ res = bfd_alloc(abfd, size);
+ if (res)
+ memset(res, 0, (size_t)size);
+ return res;
+}
+
+PTR
+bfd_realloc (abfd, old, size)
+ bfd *abfd;
+ PTR old;
+ size_t size;
+{
+ PTR res = bfd_alloc(abfd, size);
+ if (res)
+ memcpy(res, old, (size_t)size);
+ return res;
+}
diff --git a/gnu/usr.bin/gdb/bfd/reloc.c b/gnu/usr.bin/gdb/bfd/reloc.c
new file mode 100644
index 0000000..edb8903
--- /dev/null
+++ b/gnu/usr.bin/gdb/bfd/reloc.c
@@ -0,0 +1,1635 @@
+/* BFD support for handling relocation entries.
+ Copyright (C) 1990, 1991, 1992, 1993 Free Software Foundation, Inc.
+ Written by Cygnus Support.
+
+This file is part of BFD, the Binary File Descriptor library.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/*
+SECTION
+ Relocations
+
+ BFD maintains relocations in much the same way it maintains
+ symbols: they are left alone until required, then read in
+ en-mass and translated into an internal form. A common
+ routine <<bfd_perform_relocation>> acts upon the
+ canonical form to do the fixup.
+
+ Relocations are maintained on a per section basis,
+ while symbols are maintained on a per BFD basis.
+
+ All that a back end has to do to fit the BFD interface is to create
+ a <<struct reloc_cache_entry>> for each relocation
+ in a particular section, and fill in the right bits of the structures.
+
+@menu
+@* typedef arelent::
+@* howto manager::
+@end menu
+
+*/
+#include "bfd.h"
+#include "sysdep.h"
+#include "bfdlink.h"
+#include "libbfd.h"
+/*
+DOCDD
+INODE
+ typedef arelent, howto manager, Relocations, Relocations
+
+SUBSECTION
+ typedef arelent
+
+ This is the structure of a relocation entry:
+
+CODE_FRAGMENT
+.
+.typedef enum bfd_reloc_status
+.{
+. {* No errors detected *}
+. bfd_reloc_ok,
+.
+. {* The relocation was performed, but there was an overflow. *}
+. bfd_reloc_overflow,
+.
+. {* The address to relocate was not within the section supplied. *}
+. bfd_reloc_outofrange,
+.
+. {* Used by special functions *}
+. bfd_reloc_continue,
+.
+. {* Unsupported relocation size requested. *}
+. bfd_reloc_notsupported,
+.
+. {* Unused *}
+. bfd_reloc_other,
+.
+. {* The symbol to relocate against was undefined. *}
+. bfd_reloc_undefined,
+.
+. {* The relocation was performed, but may not be ok - presently
+. generated only when linking i960 coff files with i960 b.out
+. symbols. If this type is returned, the error_message argument
+. to bfd_perform_relocation will be set. *}
+. bfd_reloc_dangerous
+. }
+. bfd_reloc_status_type;
+.
+.
+.typedef struct reloc_cache_entry
+.{
+. {* A pointer into the canonical table of pointers *}
+. struct symbol_cache_entry **sym_ptr_ptr;
+.
+. {* offset in section *}
+. bfd_size_type address;
+.
+. {* addend for relocation value *}
+. bfd_vma addend;
+.
+. {* Pointer to how to perform the required relocation *}
+. const struct reloc_howto_struct *howto;
+.
+.} arelent;
+
+*/
+
+/*
+DESCRIPTION
+
+ Here is a description of each of the fields within an <<arelent>>:
+
+ o <<sym_ptr_ptr>>
+
+ The symbol table pointer points to a pointer to the symbol
+ associated with the relocation request. It is
+ the pointer into the table returned by the back end's
+ <<get_symtab>> action. @xref{Symbols}. The symbol is referenced
+ through a pointer to a pointer so that tools like the linker
+ can fix up all the symbols of the same name by modifying only
+ one pointer. The relocation routine looks in the symbol and
+ uses the base of the section the symbol is attached to and the
+ value of the symbol as the initial relocation offset. If the
+ symbol pointer is zero, then the section provided is looked up.
+
+ o <<address>>
+
+ The <<address>> field gives the offset in bytes from the base of
+ the section data which owns the relocation record to the first
+ byte of relocatable information. The actual data relocated
+ will be relative to this point; for example, a relocation
+ type which modifies the bottom two bytes of a four byte word
+ would not touch the first byte pointed to in a big endian
+ world.
+
+ o <<addend>>
+
+ The <<addend>> is a value provided by the back end to be added (!)
+ to the relocation offset. Its interpretation is dependent upon
+ the howto. For example, on the 68k the code:
+
+
+| char foo[];
+| main()
+| {
+| return foo[0x12345678];
+| }
+
+ Could be compiled into:
+
+| linkw fp,#-4
+| moveb @@#12345678,d0
+| extbl d0
+| unlk fp
+| rts
+
+
+ This could create a reloc pointing to <<foo>>, but leave the
+ offset in the data, something like:
+
+
+|RELOCATION RECORDS FOR [.text]:
+|offset type value
+|00000006 32 _foo
+|
+|00000000 4e56 fffc ; linkw fp,#-4
+|00000004 1039 1234 5678 ; moveb @@#12345678,d0
+|0000000a 49c0 ; extbl d0
+|0000000c 4e5e ; unlk fp
+|0000000e 4e75 ; rts
+
+
+ Using coff and an 88k, some instructions don't have enough
+ space in them to represent the full address range, and
+ pointers have to be loaded in two parts. So you'd get something like:
+
+
+| or.u r13,r0,hi16(_foo+0x12345678)
+| ld.b r2,r13,lo16(_foo+0x12345678)
+| jmp r1
+
+
+ This should create two relocs, both pointing to <<_foo>>, and with
+ 0x12340000 in their addend field. The data would consist of:
+
+
+|RELOCATION RECORDS FOR [.text]:
+|offset type value
+|00000002 HVRT16 _foo+0x12340000
+|00000006 LVRT16 _foo+0x12340000
+|
+|00000000 5da05678 ; or.u r13,r0,0x5678
+|00000004 1c4d5678 ; ld.b r2,r13,0x5678
+|00000008 f400c001 ; jmp r1
+
+
+ The relocation routine digs out the value from the data, adds
+ it to the addend to get the original offset, and then adds the
+ value of <<_foo>>. Note that all 32 bits have to be kept around
+ somewhere, to cope with carry from bit 15 to bit 16.
+
+ One further example is the sparc and the a.out format. The
+ sparc has a similar problem to the 88k, in that some
+ instructions don't have room for an entire offset, but on the
+ sparc the parts are created in odd sized lumps. The designers of
+ the a.out format chose to not use the data within the section
+ for storing part of the offset; all the offset is kept within
+ the reloc. Anything in the data should be ignored.
+
+| save %sp,-112,%sp
+| sethi %hi(_foo+0x12345678),%g2
+| ldsb [%g2+%lo(_foo+0x12345678)],%i0
+| ret
+| restore
+
+ Both relocs contain a pointer to <<foo>>, and the offsets
+ contain junk.
+
+
+|RELOCATION RECORDS FOR [.text]:
+|offset type value
+|00000004 HI22 _foo+0x12345678
+|00000008 LO10 _foo+0x12345678
+|
+|00000000 9de3bf90 ; save %sp,-112,%sp
+|00000004 05000000 ; sethi %hi(_foo+0),%g2
+|00000008 f048a000 ; ldsb [%g2+%lo(_foo+0)],%i0
+|0000000c 81c7e008 ; ret
+|00000010 81e80000 ; restore
+
+
+ o <<howto>>
+
+ The <<howto>> field can be imagined as a
+ relocation instruction. It is a pointer to a structure which
+ contains information on what to do with all of the other
+ information in the reloc record and data section. A back end
+ would normally have a relocation instruction set and turn
+ relocations into pointers to the correct structure on input -
+ but it would be possible to create each howto field on demand.
+
+*/
+
+/*
+SUBSUBSECTION
+ <<enum complain_overflow>>
+
+ Indicates what sort of overflow checking should be done when
+ performing a relocation.
+
+CODE_FRAGMENT
+.
+.enum complain_overflow
+.{
+. {* Do not complain on overflow. *}
+. complain_overflow_dont,
+.
+. {* Complain if the bitfield overflows, whether it is considered
+. as signed or unsigned. *}
+. complain_overflow_bitfield,
+.
+. {* Complain if the value overflows when considered as signed
+. number. *}
+. complain_overflow_signed,
+.
+. {* Complain if the value overflows when considered as an
+. unsigned number. *}
+. complain_overflow_unsigned
+.};
+
+*/
+
+/*
+SUBSUBSECTION
+ <<reloc_howto_type>>
+
+ The <<reloc_howto_type>> is a structure which contains all the
+ information that libbfd needs to know to tie up a back end's data.
+
+CODE_FRAGMENT
+.struct symbol_cache_entry; {* Forward declaration *}
+.
+.typedef unsigned char bfd_byte;
+.typedef struct reloc_howto_struct reloc_howto_type;
+.
+.struct reloc_howto_struct
+.{
+. {* The type field has mainly a documetary use - the back end can
+. do what it wants with it, though normally the back end's
+. external idea of what a reloc number is stored
+. in this field. For example, a PC relative word relocation
+. in a coff environment has the type 023 - because that's
+. what the outside world calls a R_PCRWORD reloc. *}
+. unsigned int type;
+.
+. {* The value the final relocation is shifted right by. This drops
+. unwanted data from the relocation. *}
+. unsigned int rightshift;
+.
+. {* The size of the item to be relocated. This is *not* a
+. power-of-two measure. To get the number of bytes operated
+. on by a type of relocation, use bfd_get_reloc_size. *}
+. int size;
+.
+. {* The number of bits in the item to be relocated. This is used
+. when doing overflow checking. *}
+. unsigned int bitsize;
+.
+. {* Notes that the relocation is relative to the location in the
+. data section of the addend. The relocation function will
+. subtract from the relocation value the address of the location
+. being relocated. *}
+. boolean pc_relative;
+.
+. {* The bit position of the reloc value in the destination.
+. The relocated value is left shifted by this amount. *}
+. unsigned int bitpos;
+.
+. {* What type of overflow error should be checked for when
+. relocating. *}
+. enum complain_overflow complain_on_overflow;
+.
+. {* If this field is non null, then the supplied function is
+. called rather than the normal function. This allows really
+. strange relocation methods to be accomodated (e.g., i960 callj
+. instructions). *}
+. bfd_reloc_status_type (*special_function)
+. PARAMS ((bfd *abfd,
+. arelent *reloc_entry,
+. struct symbol_cache_entry *symbol,
+. PTR data,
+. asection *input_section,
+. bfd *output_bfd,
+. char **error_message));
+.
+. {* The textual name of the relocation type. *}
+. char *name;
+.
+. {* When performing a partial link, some formats must modify the
+. relocations rather than the data - this flag signals this.*}
+. boolean partial_inplace;
+.
+. {* The src_mask selects which parts of the read in data
+. are to be used in the relocation sum. E.g., if this was an 8 bit
+. bit of data which we read and relocated, this would be
+. 0x000000ff. When we have relocs which have an addend, such as
+. sun4 extended relocs, the value in the offset part of a
+. relocating field is garbage so we never use it. In this case
+. the mask would be 0x00000000. *}
+. bfd_vma src_mask;
+.
+. {* The dst_mask selects which parts of the instruction are replaced
+. into the instruction. In most cases src_mask == dst_mask,
+. except in the above special case, where dst_mask would be
+. 0x000000ff, and src_mask would be 0x00000000. *}
+. bfd_vma dst_mask;
+.
+. {* When some formats create PC relative instructions, they leave
+. the value of the pc of the place being relocated in the offset
+. slot of the instruction, so that a PC relative relocation can
+. be made just by adding in an ordinary offset (e.g., sun3 a.out).
+. Some formats leave the displacement part of an instruction
+. empty (e.g., m88k bcs); this flag signals the fact.*}
+. boolean pcrel_offset;
+.
+.};
+
+*/
+
+/*
+FUNCTION
+ The HOWTO Macro
+
+DESCRIPTION
+ The HOWTO define is horrible and will go away.
+
+
+.#define HOWTO(C, R,S,B, P, BI, O, SF, NAME, INPLACE, MASKSRC, MASKDST, PC) \
+. {(unsigned)C,R,S,B, P, BI, O,SF,NAME,INPLACE,MASKSRC,MASKDST,PC}
+
+DESCRIPTION
+ And will be replaced with the totally magic way. But for the
+ moment, we are compatible, so do it this way.
+
+
+.#define NEWHOWTO( FUNCTION, NAME,SIZE,REL,IN) HOWTO(0,0,SIZE,0,REL,0,complain_overflow_dont,FUNCTION, NAME,false,0,0,IN)
+.
+DESCRIPTION
+ Helper routine to turn a symbol into a relocation value.
+
+.#define HOWTO_PREPARE(relocation, symbol) \
+. { \
+. if (symbol != (asymbol *)NULL) { \
+. if (bfd_is_com_section (symbol->section)) { \
+. relocation = 0; \
+. } \
+. else { \
+. relocation = symbol->value; \
+. } \
+. } \
+.}
+
+*/
+
+/*
+FUNCTION
+ bfd_get_reloc_size
+
+SYNOPSIS
+ int bfd_get_reloc_size (const reloc_howto_type *);
+
+DESCRIPTION
+ For a reloc_howto_type that operates on a fixed number of bytes,
+ this returns the number of bytes operated on.
+ */
+
+int
+bfd_get_reloc_size (howto)
+ const reloc_howto_type *howto;
+{
+ switch (howto->size)
+ {
+ case 0: return 1;
+ case 1: return 2;
+ case 2: return 4;
+ case 3: return 0;
+ case 4: return 8;
+ case -2: return 4;
+ default: abort ();
+ }
+}
+
+/*
+TYPEDEF
+ arelent_chain
+
+DESCRIPTION
+
+ How relocs are tied together in an <<asection>>:
+
+.typedef struct relent_chain {
+. arelent relent;
+. struct relent_chain *next;
+.} arelent_chain;
+
+*/
+
+
+
+/*
+FUNCTION
+ bfd_perform_relocation
+
+SYNOPSIS
+ bfd_reloc_status_type
+ bfd_perform_relocation
+ (bfd *abfd,
+ arelent *reloc_entry,
+ PTR data,
+ asection *input_section,
+ bfd *output_bfd,
+ char **error_message);
+
+DESCRIPTION
+ If @var{output_bfd} is supplied to this function, the
+ generated image will be relocatable; the relocations are
+ copied to the output file after they have been changed to
+ reflect the new state of the world. There are two ways of
+ reflecting the results of partial linkage in an output file:
+ by modifying the output data in place, and by modifying the
+ relocation record. Some native formats (e.g., basic a.out and
+ basic coff) have no way of specifying an addend in the
+ relocation type, so the addend has to go in the output data.
+ This is no big deal since in these formats the output data
+ slot will always be big enough for the addend. Complex reloc
+ types with addends were invented to solve just this problem.
+ The @var{error_message} argument is set to an error message if
+ this return @code{bfd_reloc_dangerous}.
+
+*/
+
+
+bfd_reloc_status_type
+bfd_perform_relocation (abfd, reloc_entry, data, input_section, output_bfd,
+ error_message)
+ bfd *abfd;
+ arelent *reloc_entry;
+ PTR data;
+ asection *input_section;
+ bfd *output_bfd;
+ char **error_message;
+{
+ bfd_vma relocation;
+ bfd_reloc_status_type flag = bfd_reloc_ok;
+ bfd_size_type addr = reloc_entry->address;
+ bfd_vma output_base = 0;
+ const reloc_howto_type *howto = reloc_entry->howto;
+ asection *reloc_target_output_section;
+ asymbol *symbol;
+
+ symbol = *(reloc_entry->sym_ptr_ptr);
+ if (bfd_is_abs_section (symbol->section)
+ && output_bfd != (bfd *) NULL)
+ {
+ reloc_entry->address += input_section->output_offset;
+ return bfd_reloc_ok;
+ }
+
+ /* If we are not producing relocateable output, return an error if
+ the symbol is not defined. An undefined weak symbol is
+ considered to have a value of zero (SVR4 ABI, p. 4-27). */
+ if (bfd_is_und_section (symbol->section)
+ && (symbol->flags & BSF_WEAK) == 0
+ && output_bfd == (bfd *) NULL)
+ flag = bfd_reloc_undefined;
+
+ /* If there is a function supplied to handle this relocation type,
+ call it. It'll return `bfd_reloc_continue' if further processing
+ can be done. */
+ if (howto->special_function)
+ {
+ bfd_reloc_status_type cont;
+ cont = howto->special_function (abfd, reloc_entry, symbol, data,
+ input_section, output_bfd,
+ error_message);
+ if (cont != bfd_reloc_continue)
+ return cont;
+ }
+
+ /* Is the address of the relocation really within the section? */
+ if (reloc_entry->address > input_section->_cooked_size)
+ return bfd_reloc_outofrange;
+
+ /* Work out which section the relocation is targetted at and the
+ initial relocation command value. */
+
+ /* Get symbol value. (Common symbols are special.) */
+ if (bfd_is_com_section (symbol->section))
+ relocation = 0;
+ else
+ relocation = symbol->value;
+
+
+ reloc_target_output_section = symbol->section->output_section;
+
+ /* Convert input-section-relative symbol value to absolute. */
+ if (output_bfd && howto->partial_inplace == false)
+ output_base = 0;
+ else
+ output_base = reloc_target_output_section->vma;
+
+ relocation += output_base + symbol->section->output_offset;
+
+ /* Add in supplied addend. */
+ relocation += reloc_entry->addend;
+
+ /* Here the variable relocation holds the final address of the
+ symbol we are relocating against, plus any addend. */
+
+ if (howto->pc_relative == true)
+ {
+ /* This is a PC relative relocation. We want to set RELOCATION
+ to the distance between the address of the symbol and the
+ location. RELOCATION is already the address of the symbol.
+
+ We start by subtracting the address of the section containing
+ the location.
+
+ If pcrel_offset is set, we must further subtract the position
+ of the location within the section. Some targets arrange for
+ the addend to be the negative of the position of the location
+ within the section; for example, i386-aout does this. For
+ i386-aout, pcrel_offset is false. Some other targets do not
+ include the position of the location; for example, m88kbcs,
+ or ELF. For those targets, pcrel_offset is true.
+
+ If we are producing relocateable output, then we must ensure
+ that this reloc will be correctly computed when the final
+ relocation is done. If pcrel_offset is false we want to wind
+ up with the negative of the location within the section,
+ which means we must adjust the existing addend by the change
+ in the location within the section. If pcrel_offset is true
+ we do not want to adjust the existing addend at all.
+
+ FIXME: This seems logical to me, but for the case of
+ producing relocateable output it is not what the code
+ actually does. I don't want to change it, because it seems
+ far too likely that something will break. */
+
+ relocation -=
+ input_section->output_section->vma + input_section->output_offset;
+
+ if (howto->pcrel_offset == true)
+ relocation -= reloc_entry->address;
+ }
+
+ if (output_bfd != (bfd *) NULL)
+ {
+ if (howto->partial_inplace == false)
+ {
+ /* This is a partial relocation, and we want to apply the relocation
+ to the reloc entry rather than the raw data. Modify the reloc
+ inplace to reflect what we now know. */
+ reloc_entry->addend = relocation;
+ reloc_entry->address += input_section->output_offset;
+ return flag;
+ }
+ else
+ {
+ /* This is a partial relocation, but inplace, so modify the
+ reloc record a bit.
+
+ If we've relocated with a symbol with a section, change
+ into a ref to the section belonging to the symbol. */
+
+ reloc_entry->address += input_section->output_offset;
+
+ /* WTF?? */
+ if (abfd->xvec->flavour == bfd_target_coff_flavour
+ && strcmp (abfd->xvec->name, "aixcoff-rs6000") != 0
+ && strcmp (abfd->xvec->name, "coff-Intel-little") != 0
+ && strcmp (abfd->xvec->name, "coff-Intel-big") != 0)
+ {
+#if 1
+ /* For m68k-coff, the addend was being subtracted twice during
+ relocation with -r. Removing the line below this comment
+ fixes that problem; see PR 2953.
+
+However, Ian wrote the following, regarding removing the line below,
+which explains why it is still enabled: --djm
+
+If you put a patch like that into BFD you need to check all the COFF
+linkers. I am fairly certain that patch will break coff-i386 (e.g.,
+SCO); see coff_i386_reloc in coff-i386.c where I worked around the
+problem in a different way. There may very well be a reason that the
+code works as it does.
+
+Hmmm. The first obvious point is that bfd_perform_relocation should
+not have any tests that depend upon the flavour. It's seem like
+entirely the wrong place for such a thing. The second obvious point
+is that the current code ignores the reloc addend when producing
+relocateable output for COFF. That's peculiar. In fact, I really
+have no idea what the point of the line you want to remove is.
+
+A typical COFF reloc subtracts the old value of the symbol and adds in
+the new value to the location in the object file (if it's a pc
+relative reloc it adds the difference between the symbol value and the
+location). When relocating we need to preserve that property.
+
+BFD handles this by setting the addend to the negative of the old
+value of the symbol. Unfortunately it handles common symbols in a
+non-standard way (it doesn't subtract the old value) but that's a
+different story (we can't change it without losing backward
+compatibility with old object files) (coff-i386 does subtract the old
+value, to be compatible with existing coff-i386 targets, like SCO).
+
+So everything works fine when not producing relocateable output. When
+we are producing relocateable output, logically we should do exactly
+what we do when not producing relocateable output. Therefore, your
+patch is correct. In fact, it should probably always just set
+reloc_entry->addend to 0 for all cases, since it is, in fact, going to
+add the value into the object file. This won't hurt the COFF code,
+which doesn't use the addend; I'm not sure what it will do to other
+formats (the thing to check for would be whether any formats both use
+the addend and set partial_inplace).
+
+When I wanted to make coff-i386 produce relocateable output, I ran
+into the problem that you are running into: I wanted to remove that
+line. Rather than risk it, I made the coff-i386 relocs use a special
+function; it's coff_i386_reloc in coff-i386.c. The function
+specifically adds the addend field into the object file, knowing that
+bfd_perform_relocation is not going to. If you remove that line, then
+coff-i386.c will wind up adding the addend field in twice. It's
+trivial to fix; it just needs to be done.
+
+The problem with removing the line is just that it may break some
+working code. With BFD it's hard to be sure of anything. The right
+way to deal with this is simply to build and test at least all the
+supported COFF targets. It should be straightforward if time and disk
+space consuming. For each target:
+ 1) build the linker
+ 2) generate some executable, and link it using -r (I would
+ probably use paranoia.o and link against newlib/libc.a, which
+ for all the supported targets would be available in
+ /usr/cygnus/progressive/H-host/target/lib/libc.a).
+ 3) make the change to reloc.c
+ 4) rebuild the linker
+ 5) repeat step 2
+ 6) if the resulting object files are the same, you have at least
+ made it no worse
+ 7) if they are different you have to figure out which version is
+ right
+*/
+ relocation -= reloc_entry->addend;
+#endif
+ reloc_entry->addend = 0;
+ }
+ else
+ {
+ reloc_entry->addend = relocation;
+ }
+ }
+ }
+ else
+ {
+ reloc_entry->addend = 0;
+ }
+
+ /* FIXME: This overflow checking is incomplete, because the value
+ might have overflowed before we get here. For a correct check we
+ need to compute the value in a size larger than bitsize, but we
+ can't reasonably do that for a reloc the same size as a host
+ machine word.
+ FIXME: We should also do overflow checking on the result after
+ adding in the value contained in the object file. */
+ if (howto->complain_on_overflow != complain_overflow_dont)
+ {
+ bfd_vma check;
+
+ /* Get the value that will be used for the relocation, but
+ starting at bit position zero. */
+ if (howto->rightshift > howto->bitpos)
+ check = relocation >> (howto->rightshift - howto->bitpos);
+ else
+ check = relocation << (howto->bitpos - howto->rightshift);
+ switch (howto->complain_on_overflow)
+ {
+ case complain_overflow_signed:
+ {
+ /* Assumes two's complement. */
+ bfd_signed_vma reloc_signed_max = (1 << (howto->bitsize - 1)) - 1;
+ bfd_signed_vma reloc_signed_min = ~reloc_signed_max;
+
+ /* The above right shift is incorrect for a signed value.
+ Fix it up by forcing on the upper bits. */
+ if (howto->rightshift > howto->bitpos
+ && (bfd_signed_vma) relocation < 0)
+ check |= ((bfd_vma) - 1
+ & ~((bfd_vma) - 1
+ >> (howto->rightshift - howto->bitpos)));
+ if ((bfd_signed_vma) check > reloc_signed_max
+ || (bfd_signed_vma) check < reloc_signed_min)
+ flag = bfd_reloc_overflow;
+ }
+ break;
+ case complain_overflow_unsigned:
+ {
+ /* Assumes two's complement. This expression avoids
+ overflow if howto->bitsize is the number of bits in
+ bfd_vma. */
+ bfd_vma reloc_unsigned_max =
+ (((1 << (howto->bitsize - 1)) - 1) << 1) | 1;
+
+ if ((bfd_vma) check > reloc_unsigned_max)
+ flag = bfd_reloc_overflow;
+ }
+ break;
+ case complain_overflow_bitfield:
+ {
+ /* Assumes two's complement. This expression avoids
+ overflow if howto->bitsize is the number of bits in
+ bfd_vma. */
+ bfd_vma reloc_bits = (((1 << (howto->bitsize - 1)) - 1) << 1) | 1;
+
+ if (((bfd_vma) check & ~reloc_bits) != 0
+ && ((bfd_vma) check & ~reloc_bits) != (-1 & ~reloc_bits))
+ {
+ /* The above right shift is incorrect for a signed
+ value. See if turning on the upper bits fixes the
+ overflow. */
+ if (howto->rightshift > howto->bitpos
+ && (bfd_signed_vma) relocation < 0)
+ {
+ check |= ((bfd_vma) - 1
+ & ~((bfd_vma) - 1
+ >> (howto->rightshift - howto->bitpos)));
+ if (((bfd_vma) check & ~reloc_bits) != (-1 & ~reloc_bits))
+ flag = bfd_reloc_overflow;
+ }
+ else
+ flag = bfd_reloc_overflow;
+ }
+ }
+ break;
+ default:
+ abort ();
+ }
+ }
+
+ /*
+ Either we are relocating all the way, or we don't want to apply
+ the relocation to the reloc entry (probably because there isn't
+ any room in the output format to describe addends to relocs)
+ */
+
+ /* The cast to bfd_vma avoids a bug in the Alpha OSF/1 C compiler
+ (OSF version 1.3, compiler version 3.11). It miscompiles the
+ following program:
+
+ struct str
+ {
+ unsigned int i0;
+ } s = { 0 };
+
+ int
+ main ()
+ {
+ unsigned long x;
+
+ x = 0x100000000;
+ x <<= (unsigned long) s.i0;
+ if (x == 0)
+ printf ("failed\n");
+ else
+ printf ("succeeded (%lx)\n", x);
+ }
+ */
+
+ relocation >>= (bfd_vma) howto->rightshift;
+
+ /* Shift everything up to where it's going to be used */
+
+ relocation <<= (bfd_vma) howto->bitpos;
+
+ /* Wait for the day when all have the mask in them */
+
+ /* What we do:
+ i instruction to be left alone
+ o offset within instruction
+ r relocation offset to apply
+ S src mask
+ D dst mask
+ N ~dst mask
+ A part 1
+ B part 2
+ R result
+
+ Do this:
+ i i i i i o o o o o from bfd_get<size>
+ and S S S S S to get the size offset we want
+ + r r r r r r r r r r to get the final value to place
+ and D D D D D to chop to right size
+ -----------------------
+ A A A A A
+ And this:
+ ... i i i i i o o o o o from bfd_get<size>
+ and N N N N N get instruction
+ -----------------------
+ ... B B B B B
+
+ And then:
+ B B B B B
+ or A A A A A
+ -----------------------
+ R R R R R R R R R R put into bfd_put<size>
+ */
+
+#define DOIT(x) \
+ x = ( (x & ~howto->dst_mask) | (((x & howto->src_mask) + relocation) & howto->dst_mask))
+
+ switch (howto->size)
+ {
+ case 0:
+ {
+ char x = bfd_get_8 (abfd, (char *) data + addr);
+ DOIT (x);
+ bfd_put_8 (abfd, x, (unsigned char *) data + addr);
+ }
+ break;
+
+ case 1:
+ if (relocation)
+ {
+ short x = bfd_get_16 (abfd, (bfd_byte *) data + addr);
+ DOIT (x);
+ bfd_put_16 (abfd, x, (unsigned char *) data + addr);
+ }
+ break;
+ case 2:
+ if (relocation)
+ {
+ long x = bfd_get_32 (abfd, (bfd_byte *) data + addr);
+ DOIT (x);
+ bfd_put_32 (abfd, x, (bfd_byte *) data + addr);
+ }
+ break;
+ case -2:
+ {
+ long x = bfd_get_32 (abfd, (bfd_byte *) data + addr);
+ relocation = -relocation;
+ DOIT (x);
+ bfd_put_32 (abfd, x, (bfd_byte *) data + addr);
+ }
+ break;
+
+ case 3:
+ /* Do nothing */
+ break;
+
+ case 4:
+#ifdef BFD64
+ if (relocation)
+ {
+ bfd_vma x = bfd_get_64 (abfd, (bfd_byte *) data + addr);
+ DOIT (x);
+ bfd_put_64 (abfd, x, (bfd_byte *) data + addr);
+ }
+#else
+ abort ();
+#endif
+ break;
+ default:
+ return bfd_reloc_other;
+ }
+
+ return flag;
+}
+
+/* This relocation routine is used by some of the backend linkers.
+ They do not construct asymbol or arelent structures, so there is no
+ reason for them to use bfd_perform_relocation. Also,
+ bfd_perform_relocation is so hacked up it is easier to write a new
+ function than to try to deal with it.
+
+ This routine does a final relocation. It should not be used when
+ generating relocateable output.
+
+ FIXME: This routine ignores any special_function in the HOWTO,
+ since the existing special_function values have been written for
+ bfd_perform_relocation.
+
+ HOWTO is the reloc howto information.
+ INPUT_BFD is the BFD which the reloc applies to.
+ INPUT_SECTION is the section which the reloc applies to.
+ CONTENTS is the contents of the section.
+ ADDRESS is the address of the reloc within INPUT_SECTION.
+ VALUE is the value of the symbol the reloc refers to.
+ ADDEND is the addend of the reloc. */
+
+bfd_reloc_status_type
+_bfd_final_link_relocate (howto, input_bfd, input_section, contents, address,
+ value, addend)
+ const reloc_howto_type *howto;
+ bfd *input_bfd;
+ asection *input_section;
+ bfd_byte *contents;
+ bfd_vma address;
+ bfd_vma value;
+ bfd_vma addend;
+{
+ bfd_vma relocation;
+
+ /* Sanity check the address. */
+ if (address > input_section->_cooked_size)
+ return bfd_reloc_outofrange;
+
+ /* This function assumes that we are dealing with a basic relocation
+ against a symbol. We want to compute the value of the symbol to
+ relocate to. This is just VALUE, the value of the symbol, plus
+ ADDEND, any addend associated with the reloc. */
+ relocation = value + addend;
+
+ /* If the relocation is PC relative, we want to set RELOCATION to
+ the distance between the symbol (currently in RELOCATION) and the
+ location we are relocating. Some targets (e.g., i386-aout)
+ arrange for the contents of the section to be the negative of the
+ offset of the location within the section; for such targets
+ pcrel_offset is false. Other targets (e.g., m88kbcs or ELF)
+ simply leave the contents of the section as zero; for such
+ targets pcrel_offset is true. If pcrel_offset is false we do not
+ need to subtract out the offset of the location within the
+ section (which is just ADDRESS). */
+ if (howto->pc_relative)
+ {
+ relocation -= (input_section->output_section->vma
+ + input_section->output_offset);
+ if (howto->pcrel_offset)
+ relocation -= address;
+ }
+
+ return _bfd_relocate_contents (howto, input_bfd, relocation,
+ contents + address);
+}
+
+/* Relocate a given location using a given value and howto. */
+
+bfd_reloc_status_type
+_bfd_relocate_contents (howto, input_bfd, relocation, location)
+ const reloc_howto_type *howto;
+ bfd *input_bfd;
+ bfd_vma relocation;
+ bfd_byte *location;
+{
+ int size;
+ bfd_vma x;
+ boolean overflow;
+
+ /* If the size is negative, negate RELOCATION. This isn't very
+ general. */
+ if (howto->size < 0)
+ relocation = -relocation;
+
+ /* Get the value we are going to relocate. */
+ size = bfd_get_reloc_size (howto);
+ switch (size)
+ {
+ default:
+ case 0:
+ abort ();
+ case 1:
+ x = bfd_get_8 (input_bfd, location);
+ break;
+ case 2:
+ x = bfd_get_16 (input_bfd, location);
+ break;
+ case 4:
+ x = bfd_get_32 (input_bfd, location);
+ break;
+ case 8:
+#ifdef BFD64
+ x = bfd_get_64 (input_bfd, location);
+#else
+ abort ();
+#endif
+ break;
+ }
+
+ /* Check for overflow. FIXME: We may drop bits during the addition
+ which we don't check for. We must either check at every single
+ operation, which would be tedious, or we must do the computations
+ in a type larger than bfd_vma, which would be inefficient. */
+ overflow = false;
+ if (howto->complain_on_overflow != complain_overflow_dont)
+ {
+ bfd_vma check;
+ bfd_signed_vma signed_check;
+ bfd_vma add;
+ bfd_signed_vma signed_add;
+
+ if (howto->rightshift == 0)
+ {
+ check = relocation;
+ signed_check = (bfd_signed_vma) relocation;
+ }
+ else
+ {
+ /* Drop unwanted bits from the value we are relocating to. */
+ check = relocation >> howto->rightshift;
+
+ /* If this is a signed value, the rightshift just dropped
+ leading 1 bits (assuming twos complement). */
+ if ((bfd_signed_vma) relocation >= 0)
+ signed_check = check;
+ else
+ signed_check = (check
+ | ((bfd_vma) - 1
+ & ~((bfd_vma) - 1 >> howto->rightshift)));
+ }
+
+ /* Get the value from the object file. */
+ add = x & howto->src_mask;
+
+ /* Get the value from the object file with an appropriate sign.
+ The expression involving howto->src_mask isolates the upper
+ bit of src_mask. If that bit is set in the value we are
+ adding, it is negative, and we subtract out that number times
+ two. If src_mask includes the highest possible bit, then we
+ can not get the upper bit, but that does not matter since
+ signed_add needs no adjustment to become negative in that
+ case. */
+ signed_add = add;
+ if ((add & (((~howto->src_mask) >> 1) & howto->src_mask)) != 0)
+ signed_add -= (((~howto->src_mask) >> 1) & howto->src_mask) << 1;
+
+ /* Add the value from the object file, shifted so that it is a
+ straight number. */
+ if (howto->bitpos == 0)
+ {
+ check += add;
+ signed_check += signed_add;
+ }
+ else
+ {
+ check += add >> howto->bitpos;
+
+ /* For the signed case we use ADD, rather than SIGNED_ADD,
+ to avoid warnings from SVR4 cc. This is OK since we
+ explictly handle the sign bits. */
+ if (signed_add >= 0)
+ signed_check += add >> howto->bitpos;
+ else
+ signed_check += ((add >> howto->bitpos)
+ | ((bfd_vma) - 1
+ & ~((bfd_vma) - 1 >> howto->bitpos)));
+ }
+
+ switch (howto->complain_on_overflow)
+ {
+ case complain_overflow_signed:
+ {
+ /* Assumes two's complement. */
+ bfd_signed_vma reloc_signed_max = (1 << (howto->bitsize - 1)) - 1;
+ bfd_signed_vma reloc_signed_min = ~reloc_signed_max;
+
+ if (signed_check > reloc_signed_max
+ || signed_check < reloc_signed_min)
+ overflow = true;
+ }
+ break;
+ case complain_overflow_unsigned:
+ {
+ /* Assumes two's complement. This expression avoids
+ overflow if howto->bitsize is the number of bits in
+ bfd_vma. */
+ bfd_vma reloc_unsigned_max =
+ (((1 << (howto->bitsize - 1)) - 1) << 1) | 1;
+
+ if (check > reloc_unsigned_max)
+ overflow = true;
+ }
+ break;
+ case complain_overflow_bitfield:
+ {
+ /* Assumes two's complement. This expression avoids
+ overflow if howto->bitsize is the number of bits in
+ bfd_vma. */
+ bfd_vma reloc_bits = (((1 << (howto->bitsize - 1)) - 1) << 1) | 1;
+
+ if ((check & ~reloc_bits) != 0
+ && (((bfd_vma) signed_check & ~reloc_bits)
+ != (-1 & ~reloc_bits)))
+ overflow = true;
+ }
+ break;
+ default:
+ abort ();
+ }
+ }
+
+ /* Put RELOCATION in the right bits. */
+ relocation >>= (bfd_vma) howto->rightshift;
+ relocation <<= (bfd_vma) howto->bitpos;
+
+ /* Add RELOCATION to the right bits of X. */
+ x = ((x & ~howto->dst_mask)
+ | (((x & howto->src_mask) + relocation) & howto->dst_mask));
+
+ /* Put the relocated value back in the object file. */
+ switch (size)
+ {
+ default:
+ case 0:
+ abort ();
+ case 1:
+ bfd_put_8 (input_bfd, x, location);
+ break;
+ case 2:
+ bfd_put_16 (input_bfd, x, location);
+ break;
+ case 4:
+ bfd_put_32 (input_bfd, x, location);
+ break;
+ case 8:
+#ifdef BFD64
+ bfd_put_64 (input_bfd, x, location);
+#else
+ abort ();
+#endif
+ break;
+ }
+
+ return overflow ? bfd_reloc_overflow : bfd_reloc_ok;
+}
+
+/*
+DOCDD
+INODE
+ howto manager, , typedef arelent, Relocations
+
+SECTION
+ The howto manager
+
+ When an application wants to create a relocation, but doesn't
+ know what the target machine might call it, it can find out by
+ using this bit of code.
+
+*/
+
+/*
+TYPEDEF
+ bfd_reloc_code_type
+
+DESCRIPTION
+ The insides of a reloc code. The idea is that, eventually, there
+ will be one enumerator for every type of relocation we ever do.
+ Pass one of these values to <<bfd_reloc_type_lookup>>, and it'll
+ return a howto pointer.
+
+ This does mean that the application must determine the correct
+ enumerator value; you can't get a howto pointer from a random set
+ of attributes.
+
+CODE_FRAGMENT
+.
+.typedef enum bfd_reloc_code_real
+.{
+. {* Basic absolute relocations *}
+. BFD_RELOC_64,
+. BFD_RELOC_32,
+. BFD_RELOC_26,
+. BFD_RELOC_16,
+. BFD_RELOC_14,
+. BFD_RELOC_8,
+.
+. {* PC-relative relocations *}
+. BFD_RELOC_64_PCREL,
+. BFD_RELOC_32_PCREL,
+. BFD_RELOC_24_PCREL, {* used by i960 *}
+. BFD_RELOC_16_PCREL,
+. BFD_RELOC_8_PCREL,
+.
+. {* Linkage-table relative *}
+. BFD_RELOC_32_BASEREL,
+. BFD_RELOC_16_BASEREL,
+. BFD_RELOC_8_BASEREL,
+.
+. {* The type of reloc used to build a contructor table - at the moment
+. probably a 32 bit wide abs address, but the cpu can choose. *}
+. BFD_RELOC_CTOR,
+.
+. {* 8 bits wide, but used to form an address like 0xffnn *}
+. BFD_RELOC_8_FFnn,
+.
+. {* 32-bit pc-relative, shifted right 2 bits (i.e., 30-bit
+. word displacement, e.g. for SPARC) *}
+. BFD_RELOC_32_PCREL_S2,
+. {* signed 16-bit pc-relative, shifted right 2 bits (e.g. for MIPS) *}
+. BFD_RELOC_16_PCREL_S2,
+. {* this is used on the Alpha *}
+. BFD_RELOC_23_PCREL_S2,
+.
+. {* High 22 bits of 32-bit value, placed into lower 22 bits of
+. target word; simple reloc. *}
+. BFD_RELOC_HI22,
+. {* Low 10 bits. *}
+. BFD_RELOC_LO10,
+.
+. {* For systems that allocate a Global Pointer register, these are
+. displacements off that register. These relocation types are
+. handled specially, because the value the register will have is
+. decided relatively late. *}
+. BFD_RELOC_GPREL16,
+. BFD_RELOC_GPREL32,
+.
+. {* Reloc types used for i960/b.out. *}
+. BFD_RELOC_I960_CALLJ,
+.
+. {* now for the sparc/elf codes *}
+. BFD_RELOC_NONE, {* actually used *}
+. BFD_RELOC_SPARC_WDISP22,
+. BFD_RELOC_SPARC22,
+. BFD_RELOC_SPARC13,
+. BFD_RELOC_SPARC_GOT10,
+. BFD_RELOC_SPARC_GOT13,
+. BFD_RELOC_SPARC_GOT22,
+. BFD_RELOC_SPARC_PC10,
+. BFD_RELOC_SPARC_PC22,
+. BFD_RELOC_SPARC_WPLT30,
+. BFD_RELOC_SPARC_COPY,
+. BFD_RELOC_SPARC_GLOB_DAT,
+. BFD_RELOC_SPARC_JMP_SLOT,
+. BFD_RELOC_SPARC_RELATIVE,
+. BFD_RELOC_SPARC_UA32,
+.
+. {* these are a.out specific? *}
+. BFD_RELOC_SPARC_BASE13,
+. BFD_RELOC_SPARC_BASE22,
+.
+. {* some relocations we're using for sparc v9
+. -- subject to change *}
+. BFD_RELOC_SPARC_10,
+. BFD_RELOC_SPARC_11,
+.#define BFD_RELOC_SPARC_64 BFD_RELOC_64
+. BFD_RELOC_SPARC_OLO10,
+. BFD_RELOC_SPARC_HH22,
+. BFD_RELOC_SPARC_HM10,
+. BFD_RELOC_SPARC_LM22,
+. BFD_RELOC_SPARC_PC_HH22,
+. BFD_RELOC_SPARC_PC_HM10,
+. BFD_RELOC_SPARC_PC_LM22,
+. BFD_RELOC_SPARC_WDISP16,
+. BFD_RELOC_SPARC_WDISP19,
+. BFD_RELOC_SPARC_GLOB_JMP,
+. BFD_RELOC_SPARC_LO7,
+.
+. {* Alpha ECOFF relocations. Some of these treat the symbol or "addend"
+. in some special way. *}
+. {* For GPDISP_HI16 ("gpdisp") relocations, the symbol is ignored when
+. writing; when reading, it will be the absolute section symbol. The
+. addend is the displacement in bytes of the "lda" instruction from
+. the "ldah" instruction (which is at the address of this reloc). *}
+. BFD_RELOC_ALPHA_GPDISP_HI16,
+. {* For GPDISP_LO16 ("ignore") relocations, the symbol is handled as
+. with GPDISP_HI16 relocs. The addend is ignored when writing the
+. relocations out, and is filled in with the file's GP value on
+. reading, for convenience. *}
+. BFD_RELOC_ALPHA_GPDISP_LO16,
+.
+. {* The Alpha LITERAL/LITUSE relocs are produced by a symbol reference;
+. the assembler turns it into a LDQ instruction to load the address of
+. the symbol, and then fills in a register in the real instruction.
+.
+. The LITERAL reloc, at the LDQ instruction, refers to the .lita
+. section symbol. The addend is ignored when writing, but is filled
+. in with the file's GP value on reading, for convenience, as with the
+. GPDISP_LO16 reloc.
+.
+. The LITUSE reloc, on the instruction using the loaded address, gives
+. information to the linker that it might be able to use to optimize
+. away some literal section references. The symbol is ignored (read
+. as the absolute section symbol), and the "addend" indicates the type
+. of instruction using the register:
+. 1 - "memory" fmt insn
+. 2 - byte-manipulation (byte offset reg)
+. 3 - jsr (target of branch)
+.
+. The GNU linker currently doesn't do any of this optimizing. *}
+. BFD_RELOC_ALPHA_LITERAL,
+. BFD_RELOC_ALPHA_LITUSE,
+.
+. {* The HINT relocation indicates a value that should be filled into the
+. "hint" field of a jmp/jsr/ret instruction, for possible branch-
+. prediction logic which may be provided on some processors. *}
+. BFD_RELOC_ALPHA_HINT,
+.
+. {* Bits 27..2 of the relocation address shifted right 2 bits;
+. simple reloc otherwise. *}
+. BFD_RELOC_MIPS_JMP,
+.
+. {* High 16 bits of 32-bit value; simple reloc. *}
+. BFD_RELOC_HI16,
+. {* High 16 bits of 32-bit value but the low 16 bits will be sign
+. extended and added to form the final result. If the low 16
+. bits form a negative number, we need to add one to the high value
+. to compensate for the borrow when the low bits are added. *}
+. BFD_RELOC_HI16_S,
+. {* Low 16 bits. *}
+. BFD_RELOC_LO16,
+. {* Like BFD_RELOC_HI16_S, but PC relative. *}
+. BFD_RELOC_PCREL_HI16_S,
+. {* Like BFD_RELOC_LO16, but PC relative. *}
+. BFD_RELOC_PCREL_LO16,
+.
+. {* relocation relative to the global pointer. *}
+.#define BFD_RELOC_MIPS_GPREL BFD_RELOC_GPREL16
+.
+. {* Relocation against a MIPS literal section. *}
+. BFD_RELOC_MIPS_LITERAL,
+.
+. {* MIPS ELF relocations. *}
+. BFD_RELOC_MIPS_GOT16,
+. BFD_RELOC_MIPS_CALL16,
+.#define BFD_RELOC_MIPS_GPREL32 BFD_RELOC_GPREL32
+.
+. {* i386/elf relocations *}
+. BFD_RELOC_386_GOT32,
+. BFD_RELOC_386_PLT32,
+. BFD_RELOC_386_COPY,
+. BFD_RELOC_386_GLOB_DAT,
+. BFD_RELOC_386_JUMP_SLOT,
+. BFD_RELOC_386_RELATIVE,
+. BFD_RELOC_386_GOTOFF,
+. BFD_RELOC_386_GOTPC,
+.
+. {* ns32k relocations *}
+. BFD_RELOC_NS32K_IMM_8,
+. BFD_RELOC_NS32K_IMM_16,
+. BFD_RELOC_NS32K_IMM_32,
+. BFD_RELOC_NS32K_IMM_8_PCREL,
+. BFD_RELOC_NS32K_IMM_16_PCREL,
+. BFD_RELOC_NS32K_IMM_32_PCREL,
+. BFD_RELOC_NS32K_DISP_8,
+. BFD_RELOC_NS32K_DISP_16,
+. BFD_RELOC_NS32K_DISP_32,
+. BFD_RELOC_NS32K_DISP_8_PCREL,
+. BFD_RELOC_NS32K_DISP_16_PCREL,
+. BFD_RELOC_NS32K_DISP_32_PCREL,
+.
+. {* PowerPC/POWER (RS/6000) relocs. *}
+. {* 26 bit relative branch. Low two bits must be zero. High 24
+. bits installed in bits 6 through 29 of instruction. *}
+. BFD_RELOC_PPC_B26,
+. {* 26 bit absolute branch, like BFD_RELOC_PPC_B26 but absolute. *}
+. BFD_RELOC_PPC_BA26,
+. {* 16 bit TOC relative reference. *}
+. BFD_RELOC_PPC_TOC16,
+.
+. {* this must be the highest numeric value *}
+. BFD_RELOC_UNUSED
+. } bfd_reloc_code_real_type;
+*/
+
+
+/*
+FUNCTION
+ bfd_reloc_type_lookup
+
+SYNOPSIS
+ const struct reloc_howto_struct *
+ bfd_reloc_type_lookup (bfd *abfd, bfd_reloc_code_real_type code);
+
+DESCRIPTION
+ Return a pointer to a howto structure which, when
+ invoked, will perform the relocation @var{code} on data from the
+ architecture noted.
+
+*/
+
+
+const struct reloc_howto_struct *
+bfd_reloc_type_lookup (abfd, code)
+ bfd *abfd;
+ bfd_reloc_code_real_type code;
+{
+ return BFD_SEND (abfd, reloc_type_lookup, (abfd, code));
+}
+
+static reloc_howto_type bfd_howto_32 =
+HOWTO (0, 00, 2, 32, false, 0, complain_overflow_bitfield, 0, "VRT32", false, 0xffffffff, 0xffffffff, true);
+
+
+/*
+INTERNAL_FUNCTION
+ bfd_default_reloc_type_lookup
+
+SYNOPSIS
+ const struct reloc_howto_struct *bfd_default_reloc_type_lookup
+ (bfd *abfd, bfd_reloc_code_real_type code);
+
+DESCRIPTION
+ Provides a default relocation lookup routine for any architecture.
+
+
+*/
+
+const struct reloc_howto_struct *
+bfd_default_reloc_type_lookup (abfd, code)
+ bfd *abfd;
+ bfd_reloc_code_real_type code;
+{
+ switch (code)
+ {
+ case BFD_RELOC_CTOR:
+ /* The type of reloc used in a ctor, which will be as wide as the
+ address - so either a 64, 32, or 16 bitter. */
+ switch (bfd_get_arch_info (abfd)->bits_per_address)
+ {
+ case 64:
+ BFD_FAIL ();
+ case 32:
+ return &bfd_howto_32;
+ case 16:
+ BFD_FAIL ();
+ default:
+ BFD_FAIL ();
+ }
+ default:
+ BFD_FAIL ();
+ }
+ return (const struct reloc_howto_struct *) NULL;
+}
+
+
+/*
+INTERNAL_FUNCTION
+ bfd_generic_relax_section
+
+SYNOPSIS
+ boolean bfd_generic_relax_section
+ (bfd *abfd,
+ asection *section,
+ struct bfd_link_info *,
+ boolean *);
+
+DESCRIPTION
+ Provides default handling for relaxing for back ends which
+ don't do relaxing -- i.e., does nothing.
+*/
+
+/*ARGSUSED*/
+boolean
+bfd_generic_relax_section (abfd, section, link_info, again)
+ bfd *abfd;
+ asection *section;
+ struct bfd_link_info *link_info;
+ boolean *again;
+{
+ *again = false;
+ return true;
+}
+
+/*
+INTERNAL_FUNCTION
+ bfd_generic_get_relocated_section_contents
+
+SYNOPSIS
+ bfd_byte *
+ bfd_generic_get_relocated_section_contents (bfd *abfd,
+ struct bfd_link_info *link_info,
+ struct bfd_link_order *link_order,
+ bfd_byte *data,
+ boolean relocateable,
+ asymbol **symbols);
+
+DESCRIPTION
+ Provides default handling of relocation effort for back ends
+ which can't be bothered to do it efficiently.
+
+*/
+
+bfd_byte *
+bfd_generic_get_relocated_section_contents (abfd, link_info, link_order, data,
+ relocateable, symbols)
+ bfd *abfd;
+ struct bfd_link_info *link_info;
+ struct bfd_link_order *link_order;
+ bfd_byte *data;
+ boolean relocateable;
+ asymbol **symbols;
+{
+ /* Get enough memory to hold the stuff */
+ bfd *input_bfd = link_order->u.indirect.section->owner;
+ asection *input_section = link_order->u.indirect.section;
+
+ long reloc_size = bfd_get_reloc_upper_bound (input_bfd, input_section);
+ arelent **reloc_vector = NULL;
+ long reloc_count;
+
+ if (reloc_size < 0)
+ goto error_return;
+
+ reloc_vector = (arelent **) malloc (reloc_size);
+ if (reloc_vector == NULL && reloc_size != 0)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ goto error_return;
+ }
+
+ /* read in the section */
+ if (!bfd_get_section_contents (input_bfd,
+ input_section,
+ (PTR) data,
+ 0,
+ input_section->_raw_size))
+ goto error_return;
+
+ /* We're not relaxing the section, so just copy the size info */
+ input_section->_cooked_size = input_section->_raw_size;
+ input_section->reloc_done = true;
+
+ reloc_count = bfd_canonicalize_reloc (input_bfd,
+ input_section,
+ reloc_vector,
+ symbols);
+ if (reloc_count < 0)
+ goto error_return;
+
+ if (reloc_count > 0)
+ {
+ arelent **parent;
+ for (parent = reloc_vector; *parent != (arelent *) NULL;
+ parent++)
+ {
+ char *error_message = (char *) NULL;
+ bfd_reloc_status_type r =
+ bfd_perform_relocation (input_bfd,
+ *parent,
+ (PTR) data,
+ input_section,
+ relocateable ? abfd : (bfd *) NULL,
+ &error_message);
+
+ if (relocateable)
+ {
+ asection *os = input_section->output_section;
+
+ /* A partial link, so keep the relocs */
+ os->orelocation[os->reloc_count] = *parent;
+ os->reloc_count++;
+ }
+
+ if (r != bfd_reloc_ok)
+ {
+ switch (r)
+ {
+ case bfd_reloc_undefined:
+ if (!((*link_info->callbacks->undefined_symbol)
+ (link_info, bfd_asymbol_name (*(*parent)->sym_ptr_ptr),
+ input_bfd, input_section, (*parent)->address)))
+ goto error_return;
+ break;
+ case bfd_reloc_dangerous:
+ BFD_ASSERT (error_message != (char *) NULL);
+ if (!((*link_info->callbacks->reloc_dangerous)
+ (link_info, error_message, input_bfd, input_section,
+ (*parent)->address)))
+ goto error_return;
+ break;
+ case bfd_reloc_overflow:
+ if (!((*link_info->callbacks->reloc_overflow)
+ (link_info, bfd_asymbol_name (*(*parent)->sym_ptr_ptr),
+ (*parent)->howto->name, (*parent)->addend,
+ input_bfd, input_section, (*parent)->address)))
+ goto error_return;
+ break;
+ case bfd_reloc_outofrange:
+ default:
+ abort ();
+ break;
+ }
+
+ }
+ }
+ }
+ if (reloc_vector != NULL)
+ free (reloc_vector);
+ return data;
+
+error_return:
+ if (reloc_vector != NULL)
+ free (reloc_vector);
+ return NULL;
+}
diff --git a/gnu/usr.bin/gdb/bfd/section.c b/gnu/usr.bin/gdb/bfd/section.c
new file mode 100644
index 0000000..bfee4b9
--- /dev/null
+++ b/gnu/usr.bin/gdb/bfd/section.c
@@ -0,0 +1,969 @@
+/* Object file "section" support for the BFD library.
+ Copyright (C) 1990, 1991, 1992, 1993 Free Software Foundation, Inc.
+ Written by Cygnus Support.
+
+This file is part of BFD, the Binary File Descriptor library.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/*
+SECTION
+ Sections
+
+ The raw data contained within a BFD is maintained through the
+ section abstraction. A single BFD may have any number of
+ sections. It keeps hold of them by pointing to the first;
+ each one points to the next in the list.
+
+ Sections are supported in BFD in <<section.c>>.
+
+@menu
+@* Section Input::
+@* Section Output::
+@* typedef asection::
+@* section prototypes::
+@end menu
+
+INODE
+Section Input, Section Output, Sections, Sections
+SUBSECTION
+ Section input
+
+ When a BFD is opened for reading, the section structures are
+ created and attached to the BFD.
+
+ Each section has a name which describes the section in the
+ outside world---for example, <<a.out>> would contain at least
+ three sections, called <<.text>>, <<.data>> and <<.bss>>.
+
+ Names need not be unique; for example a COFF file may have several
+ sections named <<.data>>.
+
+ Sometimes a BFD will contain more than the ``natural'' number of
+ sections. A back end may attach other sections containing
+ constructor data, or an application may add a section (using
+ <<bfd_make_section>>) to the sections attached to an already open
+ BFD. For example, the linker creates an extra section
+ <<COMMON>> for each input file's BFD to hold information about
+ common storage.
+
+ The raw data is not necessarily read in when
+ the section descriptor is created. Some targets may leave the
+ data in place until a <<bfd_get_section_contents>> call is
+ made. Other back ends may read in all the data at once. For
+ example, an S-record file has to be read once to determine the
+ size of the data. An IEEE-695 file doesn't contain raw data in
+ sections, but data and relocation expressions intermixed, so
+ the data area has to be parsed to get out the data and
+ relocations.
+
+INODE
+Section Output, typedef asection, Section Input, Sections
+
+SUBSECTION
+ Section output
+
+ To write a new object style BFD, the various sections to be
+ written have to be created. They are attached to the BFD in
+ the same way as input sections; data is written to the
+ sections using <<bfd_set_section_contents>>.
+
+ Any program that creates or combines sections (e.g., the assembler
+ and linker) must use the <<asection>> fields <<output_section>> and
+ <<output_offset>> to indicate the file sections to which each
+ section must be written. (If the section is being created from
+ scratch, <<output_section>> should probably point to the section
+ itself and <<output_offset>> should probably be zero.)
+
+ The data to be written comes from input sections attached
+ (via <<output_section>> pointers) to
+ the output sections. The output section structure can be
+ considered a filter for the input section: the output section
+ determines the vma of the output data and the name, but the
+ input section determines the offset into the output section of
+ the data to be written.
+
+ E.g., to create a section "O", starting at 0x100, 0x123 long,
+ containing two subsections, "A" at offset 0x0 (i.e., at vma
+ 0x100) and "B" at offset 0x20 (i.e., at vma 0x120) the <<asection>>
+ structures would look like:
+
+| section name "A"
+| output_offset 0x00
+| size 0x20
+| output_section -----------> section name "O"
+| | vma 0x100
+| section name "B" | size 0x123
+| output_offset 0x20 |
+| size 0x103 |
+| output_section --------|
+
+
+SUBSECTION
+ Link orders
+
+ The data within a section is stored in a @dfn{link_order}.
+ These are much like the fixups in <<gas>>. The link_order
+ abstraction allows a section to grow and shrink within itself.
+
+ A link_order knows how big it is, and which is the next
+ link_order and where the raw data for it is; it also points to
+ a list of relocations which apply to it.
+
+ The link_order is used by the linker to perform relaxing on
+ final code. The compiler creates code which is as big as
+ necessary to make it work without relaxing, and the user can
+ select whether to relax. Sometimes relaxing takes a lot of
+ time. The linker runs around the relocations to see if any
+ are attached to data which can be shrunk, if so it does it on
+ a link_order by link_order basis.
+
+*/
+
+
+#include "bfd.h"
+#include "sysdep.h"
+#include "libbfd.h"
+
+
+/*
+DOCDD
+INODE
+typedef asection, section prototypes, Section Output, Sections
+SUBSECTION
+ typedef asection
+
+ Here is the section structure:
+
+CODE_FRAGMENT
+.
+.typedef struct sec
+.{
+. {* The name of the section; the name isn't a copy, the pointer is
+. the same as that passed to bfd_make_section. *}
+.
+. CONST char *name;
+.
+. {* Which section is it; 0..nth. *}
+.
+. int index;
+.
+. {* The next section in the list belonging to the BFD, or NULL. *}
+.
+. struct sec *next;
+.
+. {* The field flags contains attributes of the section. Some
+. flags are read in from the object file, and some are
+. synthesized from other information. *}
+.
+. flagword flags;
+.
+.#define SEC_NO_FLAGS 0x000
+.
+. {* Tells the OS to allocate space for this section when loading.
+. This is clear for a section containing debug information
+. only. *}
+.#define SEC_ALLOC 0x001
+.
+. {* Tells the OS to load the section from the file when loading.
+. This is clear for a .bss section. *}
+.#define SEC_LOAD 0x002
+.
+. {* The section contains data still to be relocated, so there is
+. some relocation information too. *}
+.#define SEC_RELOC 0x004
+.
+.#if 0 {* Obsolete ? *}
+.#define SEC_BALIGN 0x008
+.#endif
+.
+. {* A signal to the OS that the section contains read only
+. data. *}
+.#define SEC_READONLY 0x010
+.
+. {* The section contains code only. *}
+.#define SEC_CODE 0x020
+.
+. {* The section contains data only. *}
+.#define SEC_DATA 0x040
+.
+. {* The section will reside in ROM. *}
+.#define SEC_ROM 0x080
+.
+. {* The section contains constructor information. This section
+. type is used by the linker to create lists of constructors and
+. destructors used by <<g++>>. When a back end sees a symbol
+. which should be used in a constructor list, it creates a new
+. section for the type of name (e.g., <<__CTOR_LIST__>>), attaches
+. the symbol to it, and builds a relocation. To build the lists
+. of constructors, all the linker has to do is catenate all the
+. sections called <<__CTOR_LIST__>> and relocate the data
+. contained within - exactly the operations it would peform on
+. standard data. *}
+.#define SEC_CONSTRUCTOR 0x100
+.
+. {* The section is a constuctor, and should be placed at the
+. end of the text, data, or bss section(?). *}
+.#define SEC_CONSTRUCTOR_TEXT 0x1100
+.#define SEC_CONSTRUCTOR_DATA 0x2100
+.#define SEC_CONSTRUCTOR_BSS 0x3100
+.
+. {* The section has contents - a data section could be
+. <<SEC_ALLOC>> | <<SEC_HAS_CONTENTS>>; a debug section could be
+. <<SEC_HAS_CONTENTS>> *}
+.#define SEC_HAS_CONTENTS 0x200
+.
+. {* An instruction to the linker to not output the section
+. even if it has information which would normally be written. *}
+.#define SEC_NEVER_LOAD 0x400
+.
+. {* The section is a COFF shared library section. This flag is
+. only for the linker. If this type of section appears in
+. the input file, the linker must copy it to the output file
+. without changing the vma or size. FIXME: Although this
+. was originally intended to be general, it really is COFF
+. specific (and the flag was renamed to indicate this). It
+. might be cleaner to have some more general mechanism to
+. allow the back end to control what the linker does with
+. sections. *}
+.#define SEC_COFF_SHARED_LIBRARY 0x800
+.
+. {* The section is a common section (symbols may be defined
+. multiple times, the value of a symbol is the amount of
+. space it requires, and the largest symbol value is the one
+. used). Most targets have exactly one of these (which we
+. translate to bfd_com_section_ptr), but ECOFF has two. *}
+.#define SEC_IS_COMMON 0x8000
+.
+. {* The section contains only debugging information. For
+. example, this is set for ELF .debug and .stab sections.
+. strip tests this flag to see if a section can be
+. discarded. *}
+.#define SEC_DEBUGGING 0x10000
+.
+. {* The contents of this section are held in memory pointed to
+. by the contents field. This is checked by
+. bfd_get_section_contents, and the data is retrieved from
+. memory if appropriate. *}
+.#define SEC_IN_MEMORY 0x20000
+.
+. {* End of section flags. *}
+.
+. {* The virtual memory address of the section - where it will be
+. at run time. The symbols are relocated against this. The
+. user_set_vma flag is maintained by bfd; if it's not set, the
+. backend can assign addresses (for example, in <<a.out>>, where
+. the default address for <<.data>> is dependent on the specific
+. target and various flags). *}
+.
+. bfd_vma vma;
+. boolean user_set_vma;
+.
+. {* The load address of the section - where it would be in a
+. rom image; really only used for writing section header
+. information. *}
+.
+. bfd_vma lma;
+.
+. {* The size of the section in bytes, as it will be output.
+. contains a value even if the section has no contents (e.g., the
+. size of <<.bss>>). This will be filled in after relocation *}
+.
+. bfd_size_type _cooked_size;
+.
+. {* The original size on disk of the section, in bytes. Normally this
+. value is the same as the size, but if some relaxing has
+. been done, then this value will be bigger. *}
+.
+. bfd_size_type _raw_size;
+.
+. {* If this section is going to be output, then this value is the
+. offset into the output section of the first byte in the input
+. section. E.g., if this was going to start at the 100th byte in
+. the output section, this value would be 100. *}
+.
+. bfd_vma output_offset;
+.
+. {* The output section through which to map on output. *}
+.
+. struct sec *output_section;
+.
+. {* The alignment requirement of the section, as an exponent of 2 -
+. e.g., 3 aligns to 2^3 (or 8). *}
+.
+. unsigned int alignment_power;
+.
+. {* If an input section, a pointer to a vector of relocation
+. records for the data in this section. *}
+.
+. struct reloc_cache_entry *relocation;
+.
+. {* If an output section, a pointer to a vector of pointers to
+. relocation records for the data in this section. *}
+.
+. struct reloc_cache_entry **orelocation;
+.
+. {* The number of relocation records in one of the above *}
+.
+. unsigned reloc_count;
+.
+. {* Information below is back end specific - and not always used
+. or updated. *}
+.
+. {* File position of section data *}
+.
+. file_ptr filepos;
+.
+. {* File position of relocation info *}
+.
+. file_ptr rel_filepos;
+.
+. {* File position of line data *}
+.
+. file_ptr line_filepos;
+.
+. {* Pointer to data for applications *}
+.
+. PTR userdata;
+.
+. {* If the SEC_IN_MEMORY flag is set, this points to the actual
+. contents. *}
+. unsigned char *contents;
+.
+. {* Attached line number information *}
+.
+. alent *lineno;
+.
+. {* Number of line number records *}
+.
+. unsigned int lineno_count;
+.
+. {* When a section is being output, this value changes as more
+. linenumbers are written out *}
+.
+. file_ptr moving_line_filepos;
+.
+. {* What the section number is in the target world *}
+.
+. int target_index;
+.
+. PTR used_by_bfd;
+.
+. {* If this is a constructor section then here is a list of the
+. relocations created to relocate items within it. *}
+.
+. struct relent_chain *constructor_chain;
+.
+. {* The BFD which owns the section. *}
+.
+. bfd *owner;
+.
+. boolean reloc_done;
+. {* A symbol which points at this section only *}
+. struct symbol_cache_entry *symbol;
+. struct symbol_cache_entry **symbol_ptr_ptr;
+.
+. struct bfd_link_order *link_order_head;
+. struct bfd_link_order *link_order_tail;
+.} asection ;
+.
+. {* These sections are global, and are managed by BFD. The application
+. and target back end are not permitted to change the values in
+. these sections. New code should use the section_ptr macros rather
+. than referring directly to the const sections. The const sections
+. may eventually vanish. *}
+.#define BFD_ABS_SECTION_NAME "*ABS*"
+.#define BFD_UND_SECTION_NAME "*UND*"
+.#define BFD_COM_SECTION_NAME "*COM*"
+.#define BFD_IND_SECTION_NAME "*IND*"
+.
+. {* the absolute section *}
+.extern const asection bfd_abs_section;
+.#define bfd_abs_section_ptr ((asection *) &bfd_abs_section)
+.#define bfd_is_abs_section(sec) ((sec) == bfd_abs_section_ptr)
+. {* Pointer to the undefined section *}
+.extern const asection bfd_und_section;
+.#define bfd_und_section_ptr ((asection *) &bfd_und_section)
+.#define bfd_is_und_section(sec) ((sec) == bfd_und_section_ptr)
+. {* Pointer to the common section *}
+.extern const asection bfd_com_section;
+.#define bfd_com_section_ptr ((asection *) &bfd_com_section)
+. {* Pointer to the indirect section *}
+.extern const asection bfd_ind_section;
+.#define bfd_ind_section_ptr ((asection *) &bfd_ind_section)
+.#define bfd_is_ind_section(sec) ((sec) == bfd_ind_section_ptr)
+.
+.extern const struct symbol_cache_entry * const bfd_abs_symbol;
+.extern const struct symbol_cache_entry * const bfd_com_symbol;
+.extern const struct symbol_cache_entry * const bfd_und_symbol;
+.extern const struct symbol_cache_entry * const bfd_ind_symbol;
+.#define bfd_get_section_size_before_reloc(section) \
+. (section->reloc_done ? (abort(),1): (section)->_raw_size)
+.#define bfd_get_section_size_after_reloc(section) \
+. ((section->reloc_done) ? (section)->_cooked_size: (abort(),1))
+*/
+
+/* These symbols are global, not specific to any BFD. Therefore, anything
+ that tries to change them is broken, and should be repaired. */
+static const asymbol global_syms[] =
+{
+ /* the_bfd, name, value, attr, section [, udata] */
+ {0, BFD_COM_SECTION_NAME, 0, BSF_SECTION_SYM, (asection *) &bfd_com_section},
+ {0, BFD_UND_SECTION_NAME, 0, BSF_SECTION_SYM, (asection *) &bfd_und_section},
+ {0, BFD_ABS_SECTION_NAME, 0, BSF_SECTION_SYM, (asection *) &bfd_abs_section},
+ {0, BFD_IND_SECTION_NAME, 0, BSF_SECTION_SYM, (asection *) &bfd_ind_section},
+};
+
+#define STD_SECTION(SEC, FLAGS, SYM, NAME, IDX) \
+ const asymbol * const SYM = (asymbol *) &global_syms[IDX]; \
+ const asection SEC = \
+ { NAME, 0, 0, FLAGS, 0, false, 0, 0, 0, 0, (asection *) &SEC, \
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, (boolean) 0, \
+ (asymbol *) &global_syms[IDX], (asymbol **) &SYM, }
+
+STD_SECTION (bfd_com_section, SEC_IS_COMMON, bfd_com_symbol,
+ BFD_COM_SECTION_NAME, 0);
+STD_SECTION (bfd_und_section, 0, bfd_und_symbol, BFD_UND_SECTION_NAME, 1);
+STD_SECTION (bfd_abs_section, 0, bfd_abs_symbol, BFD_ABS_SECTION_NAME, 2);
+STD_SECTION (bfd_ind_section, 0, bfd_ind_symbol, BFD_IND_SECTION_NAME, 3);
+#undef STD_SECTION
+
+/*
+DOCDD
+INODE
+section prototypes, , typedef asection, Sections
+SUBSECTION
+ Section prototypes
+
+These are the functions exported by the section handling part of BFD.
+*/
+
+/*
+FUNCTION
+ bfd_get_section_by_name
+
+SYNOPSIS
+ asection *bfd_get_section_by_name(bfd *abfd, CONST char *name);
+
+DESCRIPTION
+ Run through @var{abfd} and return the one of the
+ <<asection>>s whose name matches @var{name}, otherwise <<NULL>>.
+ @xref{Sections}, for more information.
+
+ This should only be used in special cases; the normal way to process
+ all sections of a given name is to use <<bfd_map_over_sections>> and
+ <<strcmp>> on the name (or better yet, base it on the section flags
+ or something else) for each section.
+*/
+
+asection *
+bfd_get_section_by_name (abfd, name)
+ bfd *abfd;
+ CONST char *name;
+{
+ asection *sect;
+
+ for (sect = abfd->sections; sect != NULL; sect = sect->next)
+ if (!strcmp (sect->name, name))
+ return sect;
+ return NULL;
+}
+
+
+/*
+FUNCTION
+ bfd_make_section_old_way
+
+SYNOPSIS
+ asection *bfd_make_section_old_way(bfd *abfd, CONST char *name);
+
+DESCRIPTION
+ Create a new empty section called @var{name}
+ and attach it to the end of the chain of sections for the
+ BFD @var{abfd}. An attempt to create a section with a name which
+ is already in use returns its pointer without changing the
+ section chain.
+
+ It has the funny name since this is the way it used to be
+ before it was rewritten....
+
+ Possible errors are:
+ o <<bfd_error_invalid_operation>> -
+ If output has already started for this BFD.
+ o <<bfd_error_no_memory>> -
+ If obstack alloc fails.
+
+*/
+
+
+asection *
+bfd_make_section_old_way (abfd, name)
+ bfd *abfd;
+ CONST char *name;
+{
+ asection *sec = bfd_get_section_by_name (abfd, name);
+ if (sec == (asection *) NULL)
+ {
+ sec = bfd_make_section (abfd, name);
+ }
+ return sec;
+}
+
+/*
+FUNCTION
+ bfd_make_section_anyway
+
+SYNOPSIS
+ asection *bfd_make_section_anyway(bfd *abfd, CONST char *name);
+
+DESCRIPTION
+ Create a new empty section called @var{name} and attach it to the end of
+ the chain of sections for @var{abfd}. Create a new section even if there
+ is already a section with that name.
+
+ Return <<NULL>> and set <<bfd_error>> on error; possible errors are:
+ o <<bfd_error_invalid_operation>> - If output has already started for @var{abfd}.
+ o <<bfd_error_no_memory>> - If obstack alloc fails.
+*/
+
+sec_ptr
+bfd_make_section_anyway (abfd, name)
+ bfd *abfd;
+ CONST char *name;
+{
+ asection *newsect;
+ asection **prev = &abfd->sections;
+ asection *sect = abfd->sections;
+
+ if (abfd->output_has_begun)
+ {
+ bfd_set_error (bfd_error_invalid_operation);
+ return NULL;
+ }
+
+ while (sect)
+ {
+ prev = &sect->next;
+ sect = sect->next;
+ }
+
+ newsect = (asection *) bfd_zalloc (abfd, sizeof (asection));
+ if (newsect == NULL)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ return NULL;
+ }
+
+ newsect->name = name;
+ newsect->index = abfd->section_count++;
+ newsect->flags = SEC_NO_FLAGS;
+
+ newsect->userdata = NULL;
+ newsect->contents = NULL;
+ newsect->next = (asection *) NULL;
+ newsect->relocation = (arelent *) NULL;
+ newsect->reloc_count = 0;
+ newsect->line_filepos = 0;
+ newsect->owner = abfd;
+
+ /* Create a symbol whos only job is to point to this section. This is
+ useful for things like relocs which are relative to the base of a
+ section. */
+ newsect->symbol = bfd_make_empty_symbol (abfd);
+ if (!newsect)
+ return NULL;
+ newsect->symbol->name = name;
+ newsect->symbol->value = 0;
+ newsect->symbol->section = newsect;
+ newsect->symbol->flags = BSF_SECTION_SYM;
+
+ newsect->symbol_ptr_ptr = &newsect->symbol;
+
+ if (BFD_SEND (abfd, _new_section_hook, (abfd, newsect)) != true)
+ {
+ free (newsect);
+ return NULL;
+ }
+
+ *prev = newsect;
+ return newsect;
+}
+
+/*
+FUNCTION
+ bfd_make_section
+
+SYNOPSIS
+ asection *bfd_make_section(bfd *, CONST char *name);
+
+DESCRIPTION
+ Like <<bfd_make_section_anyway>>, but return <<NULL>> (without calling
+ bfd_set_error ()) without changing the section chain if there is already a
+ section named @var{name}. If there is an error, return <<NULL>> and set
+ <<bfd_error>>.
+*/
+
+asection *
+bfd_make_section (abfd, name)
+ bfd *abfd;
+ CONST char *name;
+{
+ asection *sect = abfd->sections;
+
+ if (strcmp (name, BFD_ABS_SECTION_NAME) == 0)
+ {
+ return bfd_abs_section_ptr;
+ }
+ if (strcmp (name, BFD_COM_SECTION_NAME) == 0)
+ {
+ return bfd_com_section_ptr;
+ }
+ if (strcmp (name, BFD_UND_SECTION_NAME) == 0)
+ {
+ return bfd_und_section_ptr;
+ }
+
+ if (strcmp (name, BFD_IND_SECTION_NAME) == 0)
+ {
+ return bfd_ind_section_ptr;
+ }
+
+ while (sect)
+ {
+ if (!strcmp (sect->name, name))
+ return NULL;
+ sect = sect->next;
+ }
+
+ /* The name is not already used; go ahead and make a new section. */
+ return bfd_make_section_anyway (abfd, name);
+}
+
+
+/*
+FUNCTION
+ bfd_set_section_flags
+
+SYNOPSIS
+ boolean bfd_set_section_flags(bfd *abfd, asection *sec, flagword flags);
+
+DESCRIPTION
+ Set the attributes of the section @var{sec} in the BFD
+ @var{abfd} to the value @var{flags}. Return <<true>> on success,
+ <<false>> on error. Possible error returns are:
+
+ o <<bfd_error_invalid_operation>> -
+ The section cannot have one or more of the attributes
+ requested. For example, a .bss section in <<a.out>> may not
+ have the <<SEC_HAS_CONTENTS>> field set.
+
+*/
+
+/*ARGSUSED*/
+boolean
+bfd_set_section_flags (abfd, section, flags)
+ bfd *abfd;
+ sec_ptr section;
+ flagword flags;
+{
+#if 0
+ /* If you try to copy a text section from an input file (where it
+ has the SEC_CODE flag set) to an output file, this loses big if
+ the bfd_applicable_section_flags (abfd) doesn't have the SEC_CODE
+ set - which it doesn't, at least not for a.out. FIXME */
+
+ if ((flags & bfd_applicable_section_flags (abfd)) != flags)
+ {
+ bfd_set_error (bfd_error_invalid_operation);
+ return false;
+ }
+#endif
+
+ section->flags = flags;
+ return true;
+}
+
+
+/*
+FUNCTION
+ bfd_map_over_sections
+
+SYNOPSIS
+ void bfd_map_over_sections(bfd *abfd,
+ void (*func)(bfd *abfd,
+ asection *sect,
+ PTR obj),
+ PTR obj);
+
+DESCRIPTION
+ Call the provided function @var{func} for each section
+ attached to the BFD @var{abfd}, passing @var{obj} as an
+ argument. The function will be called as if by
+
+| func(abfd, the_section, obj);
+
+ This is the prefered method for iterating over sections; an
+ alternative would be to use a loop:
+
+| section *p;
+| for (p = abfd->sections; p != NULL; p = p->next)
+| func(abfd, p, ...)
+
+
+*/
+
+/*VARARGS2*/
+void
+bfd_map_over_sections (abfd, operation, user_storage)
+ bfd *abfd;
+ void (*operation) PARAMS ((bfd * abfd, asection * sect, PTR obj));
+ PTR user_storage;
+{
+ asection *sect;
+ int i = 0;
+
+ for (sect = abfd->sections; sect != NULL; i++, sect = sect->next)
+ (*operation) (abfd, sect, user_storage);
+
+ if (i != abfd->section_count) /* Debugging */
+ abort ();
+}
+
+
+/*
+FUNCTION
+ bfd_set_section_size
+
+SYNOPSIS
+ boolean bfd_set_section_size(bfd *abfd, asection *sec, bfd_size_type val);
+
+DESCRIPTION
+ Set @var{sec} to the size @var{val}. If the operation is
+ ok, then <<true>> is returned, else <<false>>.
+
+ Possible error returns:
+ o <<bfd_error_invalid_operation>> -
+ Writing has started to the BFD, so setting the size is invalid.
+
+*/
+
+boolean
+bfd_set_section_size (abfd, ptr, val)
+ bfd *abfd;
+ sec_ptr ptr;
+ bfd_size_type val;
+{
+ /* Once you've started writing to any section you cannot create or change
+ the size of any others. */
+
+ if (abfd->output_has_begun)
+ {
+ bfd_set_error (bfd_error_invalid_operation);
+ return false;
+ }
+
+ ptr->_cooked_size = val;
+ ptr->_raw_size = val;
+
+ return true;
+}
+
+/*
+FUNCTION
+ bfd_set_section_contents
+
+SYNOPSIS
+ boolean bfd_set_section_contents
+ (bfd *abfd,
+ asection *section,
+ PTR data,
+ file_ptr offset,
+ bfd_size_type count);
+
+
+DESCRIPTION
+ Sets the contents of the section @var{section} in BFD
+ @var{abfd} to the data starting in memory at @var{data}. The
+ data is written to the output section starting at offset
+ @var{offset} for @var{count} bytes.
+
+
+
+ Normally <<true>> is returned, else <<false>>. Possible error
+ returns are:
+ o <<bfd_error_no_contents>> -
+ The output section does not have the <<SEC_HAS_CONTENTS>>
+ attribute, so nothing can be written to it.
+ o and some more too
+
+ This routine is front end to the back end function
+ <<_bfd_set_section_contents>>.
+
+
+*/
+
+#define bfd_get_section_size_now(abfd,sec) \
+(sec->reloc_done \
+ ? bfd_get_section_size_after_reloc (sec) \
+ : bfd_get_section_size_before_reloc (sec))
+
+boolean
+bfd_set_section_contents (abfd, section, location, offset, count)
+ bfd *abfd;
+ sec_ptr section;
+ PTR location;
+ file_ptr offset;
+ bfd_size_type count;
+{
+ bfd_size_type sz;
+
+ if (!(bfd_get_section_flags (abfd, section) & SEC_HAS_CONTENTS))
+ {
+ bfd_set_error (bfd_error_no_contents);
+ return (false);
+ }
+
+ if (offset < 0)
+ {
+ bad_val:
+ bfd_set_error (bfd_error_bad_value);
+ return false;
+ }
+ sz = bfd_get_section_size_now (abfd, section);
+ if (offset > sz
+ || count > sz
+ || offset + count > sz)
+ goto bad_val;
+
+ switch (abfd->direction)
+ {
+ case read_direction:
+ case no_direction:
+ bfd_set_error (bfd_error_invalid_operation);
+ return false;
+
+ case write_direction:
+ break;
+
+ case both_direction:
+ /* File is opened for update. `output_has_begun' some time ago when
+ the file was created. Do not recompute sections sizes or alignments
+ in _bfd_set_section_content. */
+ abfd->output_has_begun = true;
+ break;
+ }
+
+ if (BFD_SEND (abfd, _bfd_set_section_contents,
+ (abfd, section, location, offset, count)))
+ {
+ abfd->output_has_begun = true;
+ return true;
+ }
+
+ return false;
+}
+
+/*
+FUNCTION
+ bfd_get_section_contents
+
+SYNOPSIS
+ boolean bfd_get_section_contents
+ (bfd *abfd, asection *section, PTR location,
+ file_ptr offset, bfd_size_type count);
+
+DESCRIPTION
+ Read data from @var{section} in BFD @var{abfd}
+ into memory starting at @var{location}. The data is read at an
+ offset of @var{offset} from the start of the input section,
+ and is read for @var{count} bytes.
+
+ If the contents of a constructor with the <<SEC_CONSTRUCTOR>>
+ flag set are requested or if the section does not have the
+ <<SEC_HAS_CONTENTS>> flag set, then the @var{location} is filled
+ with zeroes. If no errors occur, <<true>> is returned, else
+ <<false>>.
+
+
+
+*/
+boolean
+bfd_get_section_contents (abfd, section, location, offset, count)
+ bfd *abfd;
+ sec_ptr section;
+ PTR location;
+ file_ptr offset;
+ bfd_size_type count;
+{
+ bfd_size_type sz;
+
+ if (section->flags & SEC_CONSTRUCTOR)
+ {
+ memset (location, 0, (unsigned) count);
+ return true;
+ }
+
+ if (offset < 0)
+ {
+ bad_val:
+ bfd_set_error (bfd_error_bad_value);
+ return false;
+ }
+ /* Even if reloc_done is true, this function reads unrelocated
+ contents, so we want the raw size. */
+ sz = section->_raw_size;
+ if (offset > sz || count > sz || offset + count > sz)
+ goto bad_val;
+
+ if (count == 0)
+ /* Don't bother. */
+ return true;
+
+ if ((section->flags & SEC_HAS_CONTENTS) == 0)
+ {
+ memset (location, 0, (unsigned) count);
+ return true;
+ }
+
+ if ((section->flags & SEC_IN_MEMORY) != 0)
+ {
+ memcpy (location, section->contents + offset, count);
+ return true;
+ }
+
+ return BFD_SEND (abfd, _bfd_get_section_contents,
+ (abfd, section, location, offset, count));
+}
+
+/*
+FUNCTION
+ bfd_copy_private_section_data
+
+SYNOPSIS
+ boolean bfd_copy_private_section_data(bfd *ibfd, asection *isec, bfd *obfd, asection *osec);
+
+DESCRIPTION
+ Copy private section information from @var{isec} in the BFD
+ @var{ibfd} to the section @var{osec} in the BFD @var{obfd}.
+ Return <<true>> on success, <<false>> on error. Possible error
+ returns are:
+
+ o <<bfd_error_no_memory>> -
+ Not enough memory exists to create private data for @var{osec}.
+
+.#define bfd_copy_private_section_data(ibfd, isection, obfd, osection) \
+. BFD_SEND (ibfd, _bfd_copy_private_section_data, \
+. (ibfd, isection, obfd, osection))
+*/
diff --git a/gnu/usr.bin/gdb/bfd/srec.c b/gnu/usr.bin/gdb/bfd/srec.c
new file mode 100644
index 0000000..2d82ffc
--- /dev/null
+++ b/gnu/usr.bin/gdb/bfd/srec.c
@@ -0,0 +1,1073 @@
+/* BFD back-end for s-record objects.
+ Copyright 1990, 1991, 1992, 1993, 1994 Free Software Foundation, Inc.
+ Written by Steve Chamberlain of Cygnus Support <sac@cygnus.com>.
+
+This file is part of BFD, the Binary File Descriptor library.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/*
+SUBSECTION
+ S-Record handling
+
+DESCRIPTION
+
+ Ordinary S-Records cannot hold anything but addresses and
+ data, so that's all that we implement.
+
+ The only interesting thing is that S-Records may come out of
+ order and there is no header, so an initial scan is required
+ to discover the minimum and maximum addresses used to create
+ the vma and size of the only section we create. We
+ arbitrarily call this section ".text".
+
+ When bfd_get_section_contents is called the file is read
+ again, and this time the data is placed into a bfd_alloc'd
+ area.
+
+ Any number of sections may be created for output, we save them
+ up and output them when it's time to close the bfd.
+
+ An s record looks like:
+
+EXAMPLE
+ S<type><length><address><data><checksum>
+
+DESCRIPTION
+ Where
+ o length
+ is the number of bytes following upto the checksum. Note that
+ this is not the number of chars following, since it takes two
+ chars to represent a byte.
+ o type
+ is one of:
+ 0) header record
+ 1) two byte address data record
+ 2) three byte address data record
+ 3) four byte address data record
+ 7) four byte address termination record
+ 8) three byte address termination record
+ 9) two byte address termination record
+
+ o address
+ is the start address of the data following, or in the case of
+ a termination record, the start address of the image
+ o data
+ is the data.
+ o checksum
+ is the sum of all the raw byte data in the record, from the length
+ upwards, modulo 256 and subtracted from 255.
+
+
+SUBSECTION
+ Symbol S-Record handling
+
+DESCRIPTION
+ Some ICE equipment understands an addition to the standard
+ S-Record format; symbols and their addresses can be sent
+ before the data.
+
+ The format of this is:
+ ($$ <modulename>
+ (<space> <symbol> <address>)*)
+ $$
+
+ so a short symbol table could look like:
+
+EXAMPLE
+ $$ flash.x
+ $$ flash.c
+ _port6 $0
+ _delay $4
+ _start $14
+ _etext $8036
+ _edata $8036
+ _end $8036
+ $$
+
+DESCRIPTION
+ We allow symbols to be anywhere in the data stream - the module names
+ are always ignored.
+
+*/
+
+#include "bfd.h"
+#include "sysdep.h"
+#include "libbfd.h"
+
+static boolean srec_write_record PARAMS ((bfd *, int, bfd_vma,
+ const unsigned char *,
+ const unsigned char *));
+static boolean srec_write_header PARAMS ((bfd *));
+static boolean srec_write_symbols PARAMS ((bfd *));
+
+/* Macros for converting between hex and binary. */
+
+static CONST char digs[] = "0123456789ABCDEF";
+
+/* Table that gets filled in with numbers corresponding to hex chars. */
+
+static char hex_value[256];
+
+#define NOT_HEX 20
+#define NIBBLE(x) hex_value[(unsigned char)(x)]
+#define HEX(buffer) ((NIBBLE((buffer)[0])<<4) + NIBBLE((buffer)[1]))
+#define TOHEX(d, x, ch) \
+ d[1] = digs[(x) & 0xf]; \
+ d[0] = digs[((x)>>4)&0xf]; \
+ ch += ((x) & 0xff);
+#define ISHEX(x) (hex_value[(unsigned char)(x)] != NOT_HEX)
+
+/* Initialize by filling in the hex conversion array. */
+
+static void
+srec_init ()
+{
+ unsigned int i;
+ static boolean inited = false;
+
+ if (inited == false)
+ {
+ inited = true;
+
+ for (i = 0; i < sizeof (hex_value); i++)
+ {
+ hex_value[i] = NOT_HEX;
+ }
+ for (i = 0; i < 10; i++)
+ {
+ hex_value[i + '0'] = i;
+ }
+ for (i = 0; i < 6; i++)
+ {
+ hex_value[i + 'a'] = i + 10;
+ hex_value[i + 'A'] = i + 10;
+ }
+ }
+}
+
+
+/* The maximum number of bytes on a line is FF */
+#define MAXCHUNK 0xff
+/* The number of bytes we fit onto a line on output */
+#define CHUNK 21
+
+/* We cannot output our srecords as we see them, we have to glue them
+ together, this is done in this structure : */
+
+struct srec_data_list_struct
+{
+ unsigned char *data;
+ bfd_vma where;
+ bfd_size_type size;
+ struct srec_data_list_struct *next;
+
+
+};
+typedef struct srec_data_list_struct srec_data_list_type;
+
+
+typedef struct srec_data_struct
+ {
+ srec_data_list_type *head;
+ unsigned int type;
+
+ int done_symbol_read;
+ int count;
+ asymbol *symbols;
+ char *strings;
+ int symbol_idx;
+ int string_size;
+ int string_idx;
+ }
+tdata_type;
+
+static boolean srec_write_section PARAMS ((bfd *, tdata_type *,
+ srec_data_list_type *));
+static boolean srec_write_terminator PARAMS ((bfd *, tdata_type *));
+
+/*
+ called once per input S-Record, used to work out vma and size of data.
+ */
+
+static bfd_vma low, high;
+
+/*ARGSUSED*/
+static void
+size_symbols (abfd, buf, len, val)
+ bfd *abfd;
+ char *buf;
+ int len;
+ int val;
+{
+ abfd->symcount++;
+ abfd->tdata.srec_data->string_size += len + 1;
+}
+
+static void
+fillup_symbols (abfd, buf, len, val)
+ bfd *abfd;
+ char *buf;
+ int len;
+ int val;
+{
+ if (!abfd->tdata.srec_data->done_symbol_read)
+ {
+ asymbol *p;
+ if (abfd->tdata.srec_data->symbols == 0)
+ {
+ abfd->tdata.srec_data->symbols = (asymbol *) bfd_alloc (abfd, abfd->symcount * sizeof (asymbol));
+ abfd->tdata.srec_data->strings = (char *) bfd_alloc (abfd, abfd->tdata.srec_data->string_size);
+ if (!abfd->tdata.srec_data->symbols || !abfd->tdata.srec_data->strings)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ abort (); /* FIXME */
+ }
+ abfd->tdata.srec_data->symbol_idx = 0;
+ abfd->tdata.srec_data->string_idx = 0;
+ }
+
+ p = abfd->tdata.srec_data->symbols + abfd->tdata.srec_data->symbol_idx++;
+ p->the_bfd = abfd;
+ p->name = abfd->tdata.srec_data->strings + abfd->tdata.srec_data->string_idx;
+ memcpy ((char *) (p->name), buf, len + 1);
+ abfd->tdata.srec_data->string_idx += len + 1;
+ p->value = val;
+ p->flags = BSF_EXPORT | BSF_GLOBAL;
+ p->section = bfd_abs_section_ptr;
+ p->udata = 0;
+ }
+}
+/*ARGSUSED*/
+static void
+size_srec (abfd, section, address, raw, length)
+ bfd *abfd;
+ asection *section;
+ bfd_vma address;
+ bfd_byte *raw;
+ unsigned int length;
+{
+ if (address < low)
+ low = address;
+ if (address + length > high)
+ high = address + length - 1;
+}
+
+
+/*
+ called once per input S-Record, copies data from input into bfd_alloc'd area
+ */
+
+/*ARGSUSED*/
+static void
+fillup (abfd, section, address, raw, length)
+ bfd *abfd;
+ asection *section;
+ bfd_vma address;
+ bfd_byte *raw;
+ unsigned int length;
+{
+ unsigned int i;
+ bfd_byte *dst =
+ (bfd_byte *) (section->used_by_bfd) + address - section->vma;
+ /* length -1 because we don't read in the checksum */
+ for (i = 0; i < length - 1; i++)
+ {
+ *dst = HEX (raw);
+ dst++;
+ raw += 2;
+ }
+}
+
+/* Pass over an S-Record file, calling one of the above functions on each
+ record. */
+
+static int
+white (x)
+ char x;
+{
+ return (x == ' ' || x == '\t' || x == '\n' || x == '\r');
+}
+static int
+skipwhite (src, abfd)
+ char *src;
+ bfd *abfd;
+{
+ int eof = 0;
+ while (white (*src) && !eof)
+ {
+ eof = (boolean) (bfd_read (src, 1, 1, abfd) != 1);
+ }
+ return eof;
+}
+
+static boolean
+srec_mkobject (abfd)
+ bfd *abfd;
+{
+ if (abfd->tdata.srec_data == 0)
+ {
+ tdata_type *tdata = (tdata_type *) bfd_alloc (abfd, sizeof (tdata_type));
+ if (!tdata)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ return false;
+ }
+ abfd->tdata.srec_data = tdata;
+ tdata->type = 1;
+ tdata->head = (srec_data_list_type *) NULL;
+ }
+ return true;
+
+}
+
+static void
+pass_over (abfd, func, symbolfunc, section)
+ bfd *abfd;
+ void (*func) ();
+ void (*symbolfunc) ();
+ asection *section;
+{
+ unsigned int bytes_on_line;
+ boolean eof = false;
+
+ srec_mkobject (abfd);
+ /* To the front of the file */
+ if (bfd_seek (abfd, (file_ptr) 0, SEEK_SET) != 0)
+ abort ();
+ while (eof == false)
+ {
+ char buffer[MAXCHUNK];
+ char *src = buffer;
+ char type;
+ bfd_vma address = 0;
+
+ /* Find first 'S' or $ */
+ eof = (boolean) (bfd_read (src, 1, 1, abfd) != 1);
+ switch (*src)
+ {
+ default:
+ if (eof)
+ return;
+ break;
+
+ case '$':
+ /* Inside a symbol definition - just ignore the module name */
+ while (*src != '\n' && !eof)
+ {
+ eof = (boolean) (bfd_read (src, 1, 1, abfd) != 1);
+ }
+ break;
+
+ case ' ':
+ /* spaces - maybe just before a symbol */
+ while (*src != '\n' && *src != '\r' && white (*src))
+ {
+ eof = skipwhite (src, abfd);
+
+ {
+ int val = 0;
+ int slen = 0;
+ char symbol[MAXCHUNK];
+
+ /* get the symbol part */
+ while (!eof && !white (*src) && slen < MAXCHUNK)
+ {
+ symbol[slen++] = *src;
+ eof = (boolean) (bfd_read (src, 1, 1, abfd) != 1);
+ }
+ symbol[slen] = 0;
+ eof = skipwhite (src, abfd);
+ /* skip the $ for the hex value */
+ if (*src == '$')
+ {
+ eof = (boolean) (bfd_read (src, 1, 1, abfd) != 1);
+ }
+
+ /* Scan off the hex number */
+ while (isxdigit (*src))
+ {
+ val *= 16;
+ if (isdigit (*src))
+ val += *src - '0';
+ else if (isupper (*src))
+ {
+ val += *src - 'A' + 10;
+ }
+ else
+ {
+ val += *src - 'a' + 10;
+ }
+ eof = (boolean) (bfd_read (src, 1, 1, abfd) != 1);
+ }
+ symbolfunc (abfd, symbol, slen, val);
+ }
+ }
+ break;
+ case 'S':
+ src++;
+
+ /* Fetch the type and the length */
+ if (bfd_read (src, 1, 3, abfd) != 3)
+ abort (); /* FIXME */
+
+ type = *src++;
+
+ if (!ISHEX (src[0]) || !ISHEX (src[1]))
+ break;
+
+ bytes_on_line = HEX (src);
+
+ if (bytes_on_line > MAXCHUNK / 2)
+ break;
+ src += 2;
+
+ if (bfd_read (src, 1, bytes_on_line * 2, abfd) != bytes_on_line * 2)
+ abort (); /* FIXME */
+
+ switch (type)
+ {
+ case '0':
+ case '5':
+ /* Prologue - ignore */
+ break;
+ case '3':
+ address = HEX (src);
+ src += 2;
+ bytes_on_line--;
+
+ case '2':
+ address = HEX (src) | (address << 8);
+ src += 2;
+ bytes_on_line--;
+ case '1':
+ address = HEX (src) | (address << 8);
+ src += 2;
+ address = HEX (src) | (address << 8);
+ src += 2;
+ bytes_on_line -= 2;
+ func (abfd, section, address, src, bytes_on_line);
+ break;
+ default:
+ return;
+ }
+ }
+ }
+
+}
+
+static const bfd_target *
+object_p (abfd)
+ bfd *abfd;
+{
+ asection *section;
+ /* We create one section called .text for all the contents,
+ and allocate enough room for the entire file. */
+
+ section = bfd_make_section (abfd, ".text");
+ section->_raw_size = 0;
+ section->vma = 0xffffffff;
+ low = 0xffffffff;
+ high = 0;
+ pass_over (abfd, size_srec, size_symbols, section);
+ section->_raw_size = high - low;
+ section->vma = low;
+ section->flags = SEC_HAS_CONTENTS | SEC_LOAD | SEC_ALLOC;
+
+ if (abfd->symcount)
+ abfd->flags |= HAS_SYMS;
+ return abfd->xvec;
+}
+
+static const bfd_target *
+srec_object_p (abfd)
+ bfd *abfd;
+{
+ char b[4];
+
+ srec_init ();
+
+ if (bfd_seek (abfd, (file_ptr) 0, SEEK_SET) != 0
+ || bfd_read (b, 1, 4, abfd) != 4)
+ return NULL;
+
+ if (b[0] != 'S' || !ISHEX (b[1]) || !ISHEX (b[2]) || !ISHEX (b[3]))
+ return (const bfd_target *) NULL;
+
+ /* We create one section called .text for all the contents,
+ and allocate enough room for the entire file. */
+
+ return object_p (abfd);
+}
+
+
+static const bfd_target *
+symbolsrec_object_p (abfd)
+ bfd *abfd;
+{
+ char b[4];
+
+ srec_init ();
+
+ if (bfd_seek (abfd, (file_ptr) 0, SEEK_SET) != 0
+ || bfd_read (b, 1, 4, abfd) != 4)
+ return NULL;
+
+ if (b[0] != '$' || b[1] != '$')
+ return (const bfd_target *) NULL;
+
+ return object_p (abfd);
+}
+
+
+static boolean
+srec_get_section_contents (abfd, section, location, offset, count)
+ bfd *abfd;
+ asection *section;
+ PTR location;
+ file_ptr offset;
+ bfd_size_type count;
+{
+ if (section->used_by_bfd == (PTR) NULL)
+ {
+ section->used_by_bfd = (PTR) bfd_alloc (abfd, section->_raw_size);
+ if (!section->used_by_bfd)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ return false;
+ }
+
+ pass_over (abfd, fillup, fillup_symbols, section);
+ }
+ memcpy ((PTR) location,
+ (PTR) ((char *) (section->used_by_bfd) + offset),
+ count);
+ return true;
+}
+
+
+
+boolean
+srec_set_arch_mach (abfd, arch, machine)
+ bfd *abfd;
+ enum bfd_architecture arch;
+ unsigned long machine;
+{
+ return bfd_default_set_arch_mach (abfd, arch, machine);
+}
+
+
+/* we have to save up all the Srecords for a splurge before output,
+ also remember */
+
+static boolean
+srec_set_section_contents (abfd, section, location, offset, bytes_to_do)
+ bfd *abfd;
+ sec_ptr section;
+ PTR location;
+ file_ptr offset;
+ bfd_size_type bytes_to_do;
+{
+ tdata_type *tdata = abfd->tdata.srec_data;
+ srec_data_list_type *entry = (srec_data_list_type *)
+ bfd_alloc (abfd, sizeof (srec_data_list_type));
+
+ if (!entry)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ return false;
+ }
+
+ if ((section->flags & SEC_ALLOC)
+ && (section->flags & SEC_LOAD))
+ {
+ unsigned char *data = (unsigned char *) bfd_alloc (abfd, bytes_to_do);
+ if (!data)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ return false;
+ }
+ memcpy ((PTR) data, location, bytes_to_do);
+
+ if ((section->lma + offset + bytes_to_do) <= 0xffff)
+ {
+
+ }
+ else if ((section->lma + offset + bytes_to_do) <= 0xffffff
+ && tdata->type < 2)
+ {
+ tdata->type = 2;
+ }
+ else
+ {
+ tdata->type = 3;
+ }
+
+ entry->data = data;
+ entry->where = section->lma + offset;
+ entry->size = bytes_to_do;
+ entry->next = tdata->head;
+ tdata->head = entry;
+ }
+ return true;
+}
+
+/* Write a record of type, of the supplied number of bytes. The
+ supplied bytes and length don't have a checksum. That's worked out
+ here
+*/
+static boolean
+srec_write_record (abfd, type, address, data, end)
+ bfd *abfd;
+ int type;
+ bfd_vma address;
+ const unsigned char *data;
+ const unsigned char *end;
+{
+ char buffer[MAXCHUNK];
+
+ unsigned int check_sum = 0;
+ CONST unsigned char *src = data;
+ char *dst = buffer;
+ char *length;
+
+
+ *dst++ = 'S';
+ *dst++ = '0' + type;
+
+ length = dst;
+ dst += 2; /* leave room for dst*/
+
+ switch (type)
+ {
+ case 3:
+ case 7:
+ TOHEX (dst, (address >> 24), check_sum);
+ dst += 2;
+ case 8:
+ case 2:
+ TOHEX (dst, (address >> 16), check_sum);
+ dst += 2;
+ case 9:
+ case 1:
+ case 0:
+ TOHEX (dst, (address >> 8), check_sum);
+ dst += 2;
+ TOHEX (dst, (address), check_sum);
+ dst += 2;
+ break;
+
+ }
+ for (src = data; src < end; src++)
+ {
+ TOHEX (dst, *src, check_sum);
+ dst += 2;
+ }
+
+ /* Fill in the length */
+ TOHEX (length, (dst - length) / 2, check_sum);
+ check_sum &= 0xff;
+ check_sum = 255 - check_sum;
+ TOHEX (dst, check_sum, check_sum);
+ dst += 2;
+
+ *dst++ = '\r';
+ *dst++ = '\n';
+ if (bfd_write ((PTR) buffer, 1, dst - buffer, abfd) != dst - buffer)
+ return false;
+ return true;
+}
+
+
+
+static boolean
+srec_write_header (abfd)
+ bfd *abfd;
+{
+ unsigned char buffer[MAXCHUNK];
+ unsigned char *dst = buffer;
+ unsigned int i;
+
+ /* I'll put an arbitary 40 char limit on header size */
+ for (i = 0; i < 40 && abfd->filename[i]; i++)
+ {
+ *dst++ = abfd->filename[i];
+ }
+ return srec_write_record (abfd, 0, 0, buffer, dst);
+}
+
+static boolean
+srec_write_section (abfd, tdata, list)
+ bfd *abfd;
+ tdata_type *tdata;
+ srec_data_list_type *list;
+{
+ unsigned int bytes_written = 0;
+ unsigned char *location = list->data;
+
+ while (bytes_written < list->size)
+ {
+ bfd_vma address;
+
+ unsigned int bytes_this_chunk = list->size - bytes_written;
+
+ if (bytes_this_chunk > CHUNK)
+ {
+ bytes_this_chunk = CHUNK;
+ }
+
+ address = list->where + bytes_written;
+
+ if (! srec_write_record (abfd,
+ tdata->type,
+ address,
+ location,
+ location + bytes_this_chunk))
+ return false;
+
+ bytes_written += bytes_this_chunk;
+ location += bytes_this_chunk;
+ }
+
+ return true;
+}
+
+static boolean
+srec_write_terminator (abfd, tdata)
+ bfd *abfd;
+ tdata_type *tdata;
+{
+ unsigned char buffer[2];
+
+ return srec_write_record (abfd, 10 - tdata->type,
+ abfd->start_address, buffer, buffer);
+}
+
+
+
+static boolean
+srec_write_symbols (abfd)
+ bfd *abfd;
+{
+ char buffer[MAXCHUNK];
+ /* Dump out the symbols of a bfd */
+ int i;
+ int count = bfd_get_symcount (abfd);
+
+ if (count)
+ {
+ size_t len;
+ asymbol **table = bfd_get_outsymbols (abfd);
+ sprintf (buffer, "$$ %s\r\n", abfd->filename);
+
+ len = strlen (buffer);
+ if (bfd_write (buffer, len, 1, abfd) != len)
+ return false;
+
+ for (i = 0; i < count; i++)
+ {
+ asymbol *s = table[i];
+#if 0
+ int len = strlen (s->name);
+
+ /* If this symbol has a .[ocs] in it, it's probably a file name
+ and we'll output that as the module name */
+
+ if (len > 3 && s->name[len - 2] == '.')
+ {
+ int l;
+ sprintf (buffer, "$$ %s\r\n", s->name);
+ l = strlen (buffer);
+ if (bfd_write (buffer, l, 1, abfd) != l)
+ return false;
+ }
+ else
+#endif
+ if (s->flags & (BSF_GLOBAL | BSF_LOCAL)
+ && (s->flags & BSF_DEBUGGING) == 0
+ && s->name[0] != '.'
+ && s->name[0] != 't')
+ {
+ /* Just dump out non debug symbols */
+
+ int l;
+ char buf2[40], *p;
+
+ sprintf_vma (buf2,
+ s->value + s->section->output_section->lma
+ + s->section->output_offset);
+ p = buf2;
+ while (p[0] == '0' && p[1] != 0)
+ p++;
+ sprintf (buffer, " %s $%s\r\n", s->name, p);
+ l = strlen (buffer);
+ if (bfd_write (buffer, l, 1, abfd) != l)
+ return false;
+ }
+ }
+ sprintf (buffer, "$$ \r\n");
+ len = strlen (buffer);
+ if (bfd_write (buffer, len, 1, abfd) != len)
+ return false;
+ }
+
+ return true;
+}
+
+static boolean
+internal_srec_write_object_contents (abfd, symbols)
+ bfd *abfd;
+ int symbols;
+{
+ tdata_type *tdata = abfd->tdata.srec_data;
+ srec_data_list_type *list;
+
+ if (symbols)
+ {
+ if (! srec_write_symbols (abfd))
+ return false;
+ }
+
+ if (! srec_write_header (abfd))
+ return false;
+
+ /* Now wander though all the sections provided and output them */
+ list = tdata->head;
+
+ while (list != (srec_data_list_type *) NULL)
+ {
+ if (! srec_write_section (abfd, tdata, list))
+ return false;
+ list = list->next;
+ }
+ return srec_write_terminator (abfd, tdata);
+}
+
+static boolean
+srec_write_object_contents (abfd)
+ bfd *abfd;
+{
+ return internal_srec_write_object_contents (abfd, 0);
+}
+
+static boolean
+symbolsrec_write_object_contents (abfd)
+ bfd *abfd;
+{
+ return internal_srec_write_object_contents (abfd, 1);
+}
+
+/*ARGSUSED*/
+static int
+srec_sizeof_headers (abfd, exec)
+ bfd *abfd;
+ boolean exec;
+{
+ return 0;
+}
+
+static asymbol *
+srec_make_empty_symbol (abfd)
+ bfd *abfd;
+{
+ asymbol *new = (asymbol *) bfd_zalloc (abfd, sizeof (asymbol));
+ if (new)
+ new->the_bfd = abfd;
+ return new;
+}
+
+static long
+srec_get_symtab_upper_bound (abfd)
+ bfd *abfd;
+{
+ /* Read in all the info */
+ if (! srec_get_section_contents (abfd, abfd->sections, 0, 0, 0))
+ return -1;
+ return (bfd_get_symcount (abfd) + 1) * (sizeof (asymbol *));
+}
+
+static long
+srec_get_symtab (abfd, alocation)
+ bfd *abfd;
+ asymbol **alocation;
+{
+ int lim = abfd->symcount;
+ int i;
+ for (i = 0; i < lim; i++)
+ {
+ alocation[i] = abfd->tdata.srec_data->symbols + i;
+ }
+ alocation[i] = 0;
+ return lim;
+}
+
+/*ARGSUSED*/
+void
+srec_get_symbol_info (ignore_abfd, symbol, ret)
+ bfd *ignore_abfd;
+ asymbol *symbol;
+ symbol_info *ret;
+{
+ bfd_symbol_info (symbol, ret);
+}
+
+/*ARGSUSED*/
+void
+srec_print_symbol (ignore_abfd, afile, symbol, how)
+ bfd *ignore_abfd;
+ PTR afile;
+ asymbol *symbol;
+ bfd_print_symbol_type how;
+{
+ FILE *file = (FILE *) afile;
+ switch (how)
+ {
+ case bfd_print_symbol_name:
+ fprintf (file, "%s", symbol->name);
+ break;
+ default:
+ bfd_print_symbol_vandf ((PTR) file, symbol);
+ fprintf (file, " %-5s %s",
+ symbol->section->name,
+ symbol->name);
+
+ }
+}
+
+#define srec_close_and_cleanup _bfd_generic_close_and_cleanup
+#define srec_bfd_free_cached_info _bfd_generic_bfd_free_cached_info
+#define srec_new_section_hook _bfd_generic_new_section_hook
+
+#define srec_bfd_is_local_label bfd_generic_is_local_label
+#define srec_get_lineno _bfd_nosymbols_get_lineno
+#define srec_find_nearest_line _bfd_nosymbols_find_nearest_line
+#define srec_bfd_make_debug_symbol _bfd_nosymbols_bfd_make_debug_symbol
+
+#define srec_bfd_get_relocated_section_contents \
+ bfd_generic_get_relocated_section_contents
+#define srec_bfd_relax_section bfd_generic_relax_section
+#define srec_bfd_link_hash_table_create _bfd_generic_link_hash_table_create
+#define srec_bfd_link_add_symbols _bfd_generic_link_add_symbols
+#define srec_bfd_final_link _bfd_generic_final_link
+
+const bfd_target srec_vec =
+{
+ "srec", /* name */
+ bfd_target_srec_flavour,
+ true, /* target byte order */
+ true, /* target headers byte order */
+ (HAS_RELOC | EXEC_P | /* object flags */
+ HAS_LINENO | HAS_DEBUG |
+ HAS_SYMS | HAS_LOCALS | WP_TEXT | D_PAGED),
+ (SEC_CODE | SEC_DATA | SEC_ROM | SEC_HAS_CONTENTS
+ | SEC_ALLOC | SEC_LOAD | SEC_RELOC), /* section flags */
+ 0, /* leading underscore */
+ ' ', /* ar_pad_char */
+ 16, /* ar_max_namelen */
+ 1, /* minimum alignment */
+ bfd_getb64, bfd_getb_signed_64, bfd_putb64,
+ bfd_getb32, bfd_getb_signed_32, bfd_putb32,
+ bfd_getb16, bfd_getb_signed_16, bfd_putb16, /* data */
+ bfd_getb64, bfd_getb_signed_64, bfd_putb64,
+ bfd_getb32, bfd_getb_signed_32, bfd_putb32,
+ bfd_getb16, bfd_getb_signed_16, bfd_putb16, /* hdrs */
+
+ {
+ _bfd_dummy_target,
+ srec_object_p, /* bfd_check_format */
+ _bfd_dummy_target,
+ _bfd_dummy_target,
+ },
+ {
+ bfd_false,
+ srec_mkobject,
+ _bfd_generic_mkarchive,
+ bfd_false,
+ },
+ { /* bfd_write_contents */
+ bfd_false,
+ srec_write_object_contents,
+ _bfd_write_archive_contents,
+ bfd_false,
+ },
+
+ BFD_JUMP_TABLE_GENERIC (srec),
+ BFD_JUMP_TABLE_COPY (_bfd_generic),
+ BFD_JUMP_TABLE_CORE (_bfd_nocore),
+ BFD_JUMP_TABLE_ARCHIVE (_bfd_noarchive),
+ BFD_JUMP_TABLE_SYMBOLS (srec),
+ BFD_JUMP_TABLE_RELOCS (_bfd_norelocs),
+ BFD_JUMP_TABLE_WRITE (srec),
+ BFD_JUMP_TABLE_LINK (srec),
+ BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic),
+
+ (PTR) 0
+};
+
+
+
+const bfd_target symbolsrec_vec =
+{
+ "symbolsrec", /* name */
+ bfd_target_srec_flavour,
+ true, /* target byte order */
+ true, /* target headers byte order */
+ (HAS_RELOC | EXEC_P | /* object flags */
+ HAS_LINENO | HAS_DEBUG |
+ HAS_SYMS | HAS_LOCALS | WP_TEXT | D_PAGED),
+ (SEC_CODE | SEC_DATA | SEC_ROM | SEC_HAS_CONTENTS
+ | SEC_ALLOC | SEC_LOAD | SEC_RELOC), /* section flags */
+ 0, /* leading underscore */
+ ' ', /* ar_pad_char */
+ 16, /* ar_max_namelen */
+ 1, /* minimum alignment */
+ bfd_getb64, bfd_getb_signed_64, bfd_putb64,
+ bfd_getb32, bfd_getb_signed_32, bfd_putb32,
+ bfd_getb16, bfd_getb_signed_16, bfd_putb16, /* data */
+ bfd_getb64, bfd_getb_signed_64, bfd_putb64,
+ bfd_getb32, bfd_getb_signed_32, bfd_putb32,
+ bfd_getb16, bfd_getb_signed_16, bfd_putb16, /* hdrs */
+
+ {
+ _bfd_dummy_target,
+ symbolsrec_object_p, /* bfd_check_format */
+ _bfd_dummy_target,
+ _bfd_dummy_target,
+ },
+ {
+ bfd_false,
+ srec_mkobject,
+ _bfd_generic_mkarchive,
+ bfd_false,
+ },
+ { /* bfd_write_contents */
+ bfd_false,
+ symbolsrec_write_object_contents,
+ _bfd_write_archive_contents,
+ bfd_false,
+ },
+
+ BFD_JUMP_TABLE_GENERIC (srec),
+ BFD_JUMP_TABLE_COPY (_bfd_generic),
+ BFD_JUMP_TABLE_CORE (_bfd_nocore),
+ BFD_JUMP_TABLE_ARCHIVE (_bfd_noarchive),
+ BFD_JUMP_TABLE_SYMBOLS (srec),
+ BFD_JUMP_TABLE_RELOCS (_bfd_norelocs),
+ BFD_JUMP_TABLE_WRITE (srec),
+ BFD_JUMP_TABLE_LINK (srec),
+ BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic),
+
+ (PTR) 0
+};
diff --git a/gnu/usr.bin/gdb/bfd/stab-syms.c b/gnu/usr.bin/gdb/bfd/stab-syms.c
new file mode 100644
index 0000000..4cc9332
--- /dev/null
+++ b/gnu/usr.bin/gdb/bfd/stab-syms.c
@@ -0,0 +1,64 @@
+/* Table of stab names for the BFD library.
+ Copyright (C) 1990, 91, 92, 93, 94 Free Software Foundation, Inc.
+ Written by Cygnus Support.
+
+This file is part of BFD, the Binary File Descriptor library.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "bfd.h"
+
+#define ARCH_SIZE 32 /* Value doesn't matter. */
+#include "libaout.h"
+#include "aout/aout64.h"
+
+/* Create a table of debugging stab-codes and corresponding names. */
+
+#define __define_name(CODE, STRING) {(int)CODE, STRING},
+#define __define_stab(NAME, CODE, STRING) __define_name(CODE, STRING)
+CONST struct
+ {
+ short code;
+ char string[10];
+ }
+aout_stab_names[] =
+{
+#include "aout/stab.def"
+
+/* These are not really stab symbols, but it is
+ convenient to have them here for the sake of nm.
+ For completeness, we could also add N_TEXT etc, but those
+ are never needed, since nm treats those specially. */
+ __define_name (N_SETA, "SETA")/* Absolute set element symbol */
+ __define_name (N_SETT, "SETT")/* Text set element symbol */
+ __define_name (N_SETD, "SETD")/* Data set element symbol */
+ __define_name (N_SETB, "SETB")/* Bss set element symbol */
+ __define_name (N_SETV, "SETV")/* Pointer to set vector in data area. */
+ __define_name (N_INDR, "INDR")
+ __define_name (N_WARNING, "WARNING")
+};
+#undef __define_stab
+#undef GNU_EXTRA_STABS
+
+CONST char *
+aout_stab_name (code)
+ int code;
+{
+ register int i = sizeof (aout_stab_names) / sizeof (aout_stab_names[0]);
+ while (--i >= 0)
+ if (aout_stab_names[i].code == code)
+ return aout_stab_names[i].string;
+ return 0;
+}
diff --git a/gnu/usr.bin/gdb/bfd/syms.c b/gnu/usr.bin/gdb/bfd/syms.c
new file mode 100644
index 0000000..23a70f5
--- /dev/null
+++ b/gnu/usr.bin/gdb/bfd/syms.c
@@ -0,0 +1,557 @@
+/* Generic symbol-table support for the BFD library.
+ Copyright (C) 1990, 1991, 1992, 1993 Free Software Foundation, Inc.
+ Written by Cygnus Support.
+
+This file is part of BFD, the Binary File Descriptor library.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/*
+SECTION
+ Symbols
+
+ BFD tries to maintain as much symbol information as it can when
+ it moves information from file to file. BFD passes information
+ to applications though the <<asymbol>> structure. When the
+ application requests the symbol table, BFD reads the table in
+ the native form and translates parts of it into the internal
+ format. To maintain more than the information passed to
+ applications, some targets keep some information ``behind the
+ scenes'' in a structure only the particular back end knows
+ about. For example, the coff back end keeps the original
+ symbol table structure as well as the canonical structure when
+ a BFD is read in. On output, the coff back end can reconstruct
+ the output symbol table so that no information is lost, even
+ information unique to coff which BFD doesn't know or
+ understand. If a coff symbol table were read, but were written
+ through an a.out back end, all the coff specific information
+ would be lost. The symbol table of a BFD
+ is not necessarily read in until a canonicalize request is
+ made. Then the BFD back end fills in a table provided by the
+ application with pointers to the canonical information. To
+ output symbols, the application provides BFD with a table of
+ pointers to pointers to <<asymbol>>s. This allows applications
+ like the linker to output a symbol as it was read, since the ``behind
+ the scenes'' information will be still available.
+@menu
+@* Reading Symbols::
+@* Writing Symbols::
+@* typedef asymbol::
+@* symbol handling functions::
+@end menu
+
+INODE
+Reading Symbols, Writing Symbols, Symbols, Symbols
+SUBSECTION
+ Reading symbols
+
+ There are two stages to reading a symbol table from a BFD:
+ allocating storage, and the actual reading process. This is an
+ excerpt from an application which reads the symbol table:
+
+| long storage_needed;
+| asymbol **symbol_table;
+| long number_of_symbols;
+| long i;
+|
+| storage_needed = bfd_get_symtab_upper_bound (abfd);
+|
+| if (storage_needed < 0)
+| FAIL
+|
+| if (storage_needed == 0) {
+| return ;
+| }
+| symbol_table = (asymbol **) xmalloc (storage_needed);
+| ...
+| number_of_symbols =
+| bfd_canonicalize_symtab (abfd, symbol_table);
+|
+| if (number_of_symbols < 0)
+| FAIL
+|
+| for (i = 0; i < number_of_symbols; i++) {
+| process_symbol (symbol_table[i]);
+| }
+
+ All storage for the symbols themselves is in an obstack
+ connected to the BFD; it is freed when the BFD is closed.
+
+
+INODE
+Writing Symbols, typedef asymbol, Reading Symbols, Symbols
+SUBSECTION
+ Writing symbols
+
+ Writing of a symbol table is automatic when a BFD open for
+ writing is closed. The application attaches a vector of
+ pointers to pointers to symbols to the BFD being written, and
+ fills in the symbol count. The close and cleanup code reads
+ through the table provided and performs all the necessary
+ operations. The BFD output code must always be provided with an
+ ``owned'' symbol: one which has come from another BFD, or one
+ which has been created using <<bfd_make_empty_symbol>>. Here is an
+ example showing the creation of a symbol table with only one element:
+
+| #include "bfd.h"
+| main()
+| {
+| bfd *abfd;
+| asymbol *ptrs[2];
+| asymbol *new;
+|
+| abfd = bfd_openw("foo","a.out-sunos-big");
+| bfd_set_format(abfd, bfd_object);
+| new = bfd_make_empty_symbol(abfd);
+| new->name = "dummy_symbol";
+| new->section = bfd_make_section_old_way(abfd, ".text");
+| new->flags = BSF_GLOBAL;
+| new->value = 0x12345;
+|
+| ptrs[0] = new;
+| ptrs[1] = (asymbol *)0;
+|
+| bfd_set_symtab(abfd, ptrs, 1);
+| bfd_close(abfd);
+| }
+|
+| ./makesym
+| nm foo
+| 00012345 A dummy_symbol
+
+ Many formats cannot represent arbitary symbol information; for
+ instance, the <<a.out>> object format does not allow an
+ arbitary number of sections. A symbol pointing to a section
+ which is not one of <<.text>>, <<.data>> or <<.bss>> cannot
+ be described.
+
+*/
+
+
+
+/*
+DOCDD
+INODE
+typedef asymbol, symbol handling functions, Writing Symbols, Symbols
+
+*/
+/*
+SUBSECTION
+ typedef asymbol
+
+ An <<asymbol>> has the form:
+
+*/
+
+/*
+CODE_FRAGMENT
+
+.
+.typedef struct symbol_cache_entry
+.{
+. {* A pointer to the BFD which owns the symbol. This information
+. is necessary so that a back end can work out what additional
+. information (invisible to the application writer) is carried
+. with the symbol.
+.
+. This field is *almost* redundant, since you can use section->owner
+. instead, except that some symbols point to the global sections
+. bfd_{abs,com,und}_section. This could be fixed by making
+. these globals be per-bfd (or per-target-flavor). FIXME. *}
+.
+. struct _bfd *the_bfd; {* Use bfd_asymbol_bfd(sym) to access this field. *}
+.
+. {* The text of the symbol. The name is left alone, and not copied; the
+. application may not alter it. *}
+. CONST char *name;
+.
+. {* The value of the symbol. This really should be a union of a
+. numeric value with a pointer, since some flags indicate that
+. a pointer to another symbol is stored here. *}
+. symvalue value;
+.
+. {* Attributes of a symbol: *}
+.
+.#define BSF_NO_FLAGS 0x00
+.
+. {* The symbol has local scope; <<static>> in <<C>>. The value
+. is the offset into the section of the data. *}
+.#define BSF_LOCAL 0x01
+.
+. {* The symbol has global scope; initialized data in <<C>>. The
+. value is the offset into the section of the data. *}
+.#define BSF_GLOBAL 0x02
+.
+. {* The symbol has global scope and is exported. The value is
+. the offset into the section of the data. *}
+.#define BSF_EXPORT BSF_GLOBAL {* no real difference *}
+.
+. {* A normal C symbol would be one of:
+. <<BSF_LOCAL>>, <<BSF_FORT_COMM>>, <<BSF_UNDEFINED>> or
+. <<BSF_GLOBAL>> *}
+.
+. {* The symbol is a debugging record. The value has an arbitary
+. meaning. *}
+.#define BSF_DEBUGGING 0x08
+.
+. {* The symbol denotes a function entry point. Used in ELF,
+. perhaps others someday. *}
+.#define BSF_FUNCTION 0x10
+.
+. {* Used by the linker. *}
+.#define BSF_KEEP 0x20
+.#define BSF_KEEP_G 0x40
+.
+. {* A weak global symbol, overridable without warnings by
+. a regular global symbol of the same name. *}
+.#define BSF_WEAK 0x80
+.
+. {* This symbol was created to point to a section, e.g. ELF's
+. STT_SECTION symbols. *}
+.#define BSF_SECTION_SYM 0x100
+.
+. {* The symbol used to be a common symbol, but now it is
+. allocated. *}
+.#define BSF_OLD_COMMON 0x200
+.
+. {* The default value for common data. *}
+.#define BFD_FORT_COMM_DEFAULT_VALUE 0
+.
+. {* In some files the type of a symbol sometimes alters its
+. location in an output file - ie in coff a <<ISFCN>> symbol
+. which is also <<C_EXT>> symbol appears where it was
+. declared and not at the end of a section. This bit is set
+. by the target BFD part to convey this information. *}
+.
+.#define BSF_NOT_AT_END 0x400
+.
+. {* Signal that the symbol is the label of constructor section. *}
+.#define BSF_CONSTRUCTOR 0x800
+.
+. {* Signal that the symbol is a warning symbol. If the symbol
+. is a warning symbol, then the value field (I know this is
+. tacky) will point to the asymbol which when referenced will
+. cause the warning. *}
+.#define BSF_WARNING 0x1000
+.
+. {* Signal that the symbol is indirect. The value of the symbol
+. is a pointer to an undefined asymbol which contains the
+. name to use instead. *}
+.#define BSF_INDIRECT 0x2000
+.
+. {* BSF_FILE marks symbols that contain a file name. This is used
+. for ELF STT_FILE symbols. *}
+.#define BSF_FILE 0x4000
+.
+. {* Symbol is from dynamic linking information. *}
+.#define BSF_DYNAMIC 0x8000
+.
+. flagword flags;
+.
+. {* A pointer to the section to which this symbol is
+. relative. This will always be non NULL, there are special
+. sections for undefined and absolute symbols *}
+. struct sec *section;
+.
+. {* Back end special data. This is being phased out in favour
+. of making this a union. *}
+. PTR udata;
+.
+.} asymbol;
+*/
+
+#include "bfd.h"
+#include "sysdep.h"
+
+#include "libbfd.h"
+#include "aout/stab_gnu.h"
+
+/*
+DOCDD
+INODE
+symbol handling functions, , typedef asymbol, Symbols
+SUBSECTION
+ Symbol handling functions
+*/
+
+/*
+FUNCTION
+ bfd_get_symtab_upper_bound
+
+DESCRIPTION
+ Return the number of bytes required to store a vector of pointers
+ to <<asymbols>> for all the symbols in the BFD @var{abfd},
+ including a terminal NULL pointer. If there are no symbols in
+ the BFD, then return 0. If an error occurs, return -1.
+
+.#define bfd_get_symtab_upper_bound(abfd) \
+. BFD_SEND (abfd, _bfd_get_symtab_upper_bound, (abfd))
+
+*/
+
+/*
+FUNCTION
+ bfd_is_local_label
+
+SYNOPSIS
+ boolean bfd_is_local_label(bfd *abfd, asymbol *sym);
+
+DESCRIPTION
+ Return true if the given symbol @var{sym} in the BFD @var{abfd} is
+ a compiler generated local label, else return false.
+.#define bfd_is_local_label(abfd, sym) \
+. BFD_SEND (abfd, _bfd_is_local_label,(abfd, sym))
+*/
+
+/*
+FUNCTION
+ bfd_canonicalize_symtab
+
+DESCRIPTION
+ Read the symbols from the BFD @var{abfd}, and fills in
+ the vector @var{location} with pointers to the symbols and
+ a trailing NULL.
+ Return the actual number of symbol pointers, not
+ including the NULL.
+
+
+.#define bfd_canonicalize_symtab(abfd, location) \
+. BFD_SEND (abfd, _bfd_canonicalize_symtab,\
+. (abfd, location))
+
+*/
+
+
+/*
+FUNCTION
+ bfd_set_symtab
+
+SYNOPSIS
+ boolean bfd_set_symtab (bfd *abfd, asymbol **location, unsigned int count);
+
+DESCRIPTION
+ Arrange that when the output BFD @var{abfd} is closed,
+ the table @var{location} of @var{count} pointers to symbols
+ will be written.
+*/
+
+boolean
+bfd_set_symtab (abfd, location, symcount)
+ bfd *abfd;
+ asymbol **location;
+ unsigned int symcount;
+{
+ if ((abfd->format != bfd_object) || (bfd_read_p (abfd)))
+ {
+ bfd_set_error (bfd_error_invalid_operation);
+ return false;
+ }
+
+ bfd_get_outsymbols (abfd) = location;
+ bfd_get_symcount (abfd) = symcount;
+ return true;
+}
+
+/*
+FUNCTION
+ bfd_print_symbol_vandf
+
+SYNOPSIS
+ void bfd_print_symbol_vandf(PTR file, asymbol *symbol);
+
+DESCRIPTION
+ Print the value and flags of the @var{symbol} supplied to the
+ stream @var{file}.
+*/
+void
+bfd_print_symbol_vandf (arg, symbol)
+ PTR arg;
+ asymbol *symbol;
+{
+ FILE *file = (FILE *) arg;
+ flagword type = symbol->flags;
+ if (symbol->section != (asection *) NULL)
+ {
+ fprintf_vma (file, symbol->value + symbol->section->vma);
+ }
+ else
+ {
+ fprintf_vma (file, symbol->value);
+ }
+
+ /* This presumes that a symbol can not be both BSF_DEBUGGING and
+ BSF_DYNAMIC. */
+ fprintf (file, " %c%c%c%c%c%c%c",
+ (type & BSF_LOCAL) ? 'l' : ' ',
+ (type & BSF_GLOBAL) ? 'g' : ' ',
+ (type & BSF_WEAK) ? 'w' : ' ',
+ (type & BSF_CONSTRUCTOR) ? 'C' : ' ',
+ (type & BSF_WARNING) ? 'W' : ' ',
+ (type & BSF_INDIRECT) ? 'I' : ' ',
+ (type & BSF_DEBUGGING) ? 'd'
+ : (type & BSF_DYNAMIC) ? 'D' : ' ');
+}
+
+
+/*
+FUNCTION
+ bfd_make_empty_symbol
+
+DESCRIPTION
+ Create a new <<asymbol>> structure for the BFD @var{abfd}
+ and return a pointer to it.
+
+ This routine is necessary because each back end has private
+ information surrounding the <<asymbol>>. Building your own
+ <<asymbol>> and pointing to it will not create the private
+ information, and will cause problems later on.
+
+.#define bfd_make_empty_symbol(abfd) \
+. BFD_SEND (abfd, _bfd_make_empty_symbol, (abfd))
+*/
+
+/*
+FUNCTION
+ bfd_make_debug_symbol
+
+DESCRIPTION
+ Create a new <<asymbol>> structure for the BFD @var{abfd},
+ to be used as a debugging symbol. Further details of its use have
+ yet to be worked out.
+
+.#define bfd_make_debug_symbol(abfd,ptr,size) \
+. BFD_SEND (abfd, _bfd_make_debug_symbol, (abfd, ptr, size))
+*/
+
+struct section_to_type
+{
+ CONST char *section;
+ char type;
+};
+
+/* Map section names to POSIX/BSD single-character symbol types.
+ This table is probably incomplete. It is sorted for convenience of
+ adding entries. Since it is so short, a linear search is used. */
+static CONST struct section_to_type stt[] =
+{
+ {"*DEBUG*", 'N'},
+ {".bss", 'b'},
+ {".data", 'd'},
+ {".sbss", 's'}, /* Small BSS (uninitialized data) */
+ {".scommon", 'c'}, /* Small common */
+ {".sdata", 'g'}, /* Small initialized data */
+ {".text", 't'},
+ {0, 0}
+};
+
+/* Return the single-character symbol type corresponding to
+ section S, or '?' for an unknown COFF section. */
+
+static char
+coff_section_type (s)
+ char *s;
+{
+ CONST struct section_to_type *t;
+
+ for (t = &stt[0]; t->section; t++)
+ if (!strcmp (s, t->section))
+ return t->type;
+ return '?';
+}
+
+#ifndef islower
+#define islower(c) ((c) >= 'a' && (c) <= 'z')
+#endif
+#ifndef toupper
+#define toupper(c) (islower(c) ? ((c) & ~0x20) : (c))
+#endif
+
+/*
+FUNCTION
+ bfd_decode_symclass
+
+DESCRIPTION
+ Return a character corresponding to the symbol
+ class of @var{symbol}, or '?' for an unknown class.
+
+SYNOPSIS
+ int bfd_decode_symclass(asymbol *symbol);
+*/
+int
+bfd_decode_symclass (symbol)
+ asymbol *symbol;
+{
+ char c;
+
+ if (bfd_is_com_section (symbol->section))
+ return 'C';
+ if (bfd_is_und_section (symbol->section))
+ return 'U';
+ if (bfd_is_ind_section (symbol->section))
+ return 'I';
+ if (!(symbol->flags & (BSF_GLOBAL | BSF_LOCAL)))
+ return '?';
+
+ if (bfd_is_abs_section (symbol->section))
+ c = 'a';
+ else if (symbol->section)
+ c = coff_section_type (symbol->section->name);
+ else
+ return '?';
+ if (symbol->flags & BSF_GLOBAL)
+ c = toupper (c);
+ return c;
+
+ /* We don't have to handle these cases just yet, but we will soon:
+ N_SETV: 'v';
+ N_SETA: 'l';
+ N_SETT: 'x';
+ N_SETD: 'z';
+ N_SETB: 's';
+ N_INDR: 'i';
+ */
+}
+
+/*
+FUNCTION
+ bfd_symbol_info
+
+DESCRIPTION
+ Fill in the basic info about symbol that nm needs.
+ Additional info may be added by the back-ends after
+ calling this function.
+
+SYNOPSIS
+ void bfd_symbol_info(asymbol *symbol, symbol_info *ret);
+*/
+
+void
+bfd_symbol_info (symbol, ret)
+ asymbol *symbol;
+ symbol_info *ret;
+{
+ ret->type = bfd_decode_symclass (symbol);
+ if (ret->type != 'U')
+ ret->value = symbol->value + symbol->section->vma;
+ else
+ ret->value = 0;
+ ret->name = symbol->name;
+}
+
+void
+bfd_symbol_is_absolute ()
+{
+ abort ();
+}
diff --git a/gnu/usr.bin/gdb/bfd/sysdep.h b/gnu/usr.bin/gdb/bfd/sysdep.h
new file mode 100644
index 0000000..f57363b
--- /dev/null
+++ b/gnu/usr.bin/gdb/bfd/sysdep.h
@@ -0,0 +1,47 @@
+#ifndef hosts_i386bsd_H
+/* Intel 386 running any BSD Unix */
+#include <fcntl.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <ctype.h>
+#include <string.h>
+#include <sys/file.h>
+#include <machine/param.h>
+#include <machine/vmparam.h>
+
+#ifndef O_ACCMODE
+#define O_ACCMODE (O_RDONLY | O_WRONLY | O_RDWR)
+#endif
+
+#define SEEK_SET 0
+#define SEEK_CUR 1
+
+#define HOST_PAGE_SIZE NBPG
+#define HOST_MACHINE_ARCH bfd_arch_i386
+#define HOST_TEXT_START_ADDR USRTEXT
+
+/* Jolitz suggested defining HOST_STACK_END_ADDR to
+ (u.u_kproc.kp_eproc.e_vm.vm_maxsaddr + MAXSSIZ), which should work on
+ both BSDI and 386BSD, but that is believed not to work for BSD 4.4. */
+
+#if defined (__bsdi__) || defined (__FreeBSD__)
+/* This seems to be the right thing for BSDI and FreeBSD. */
+#define HOST_STACK_END_ADDR USRSTACK
+#else
+/* This seems to be the right thing for 386BSD release 0.1. */
+#define HOST_STACK_END_ADDR (USRSTACK - MAXSSIZ)
+#endif
+
+#define HOST_DATA_START_ADDR ((bfd_vma)u.u_kproc.kp_eproc.e_vm.vm_daddr)
+
+#define TRAD_UNIX_CORE_FILE_FAILING_SIGNAL(core_bfd) \
+ ((core_bfd)->tdata.trad_core_data->u.u_sig)
+#define u_comm u_kproc.kp_proc.p_comm
+
+#include "fopen-same.h"
+
+#define hosts_i386bsd_H
+#endif
diff --git a/gnu/usr.bin/gdb/bfd/targets.c b/gnu/usr.bin/gdb/bfd/targets.c
new file mode 100644
index 0000000..f6115a8
--- /dev/null
+++ b/gnu/usr.bin/gdb/bfd/targets.c
@@ -0,0 +1,770 @@
+/* Generic target-file-type support for the BFD library.
+ Copyright 1990, 91, 92, 93, 1994 Free Software Foundation, Inc.
+ Written by Cygnus Support.
+
+This file is part of BFD, the Binary File Descriptor library.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "bfd.h"
+#include "sysdep.h"
+#include "libbfd.h"
+
+/*
+SECTION
+ Targets
+
+DESCRIPTION
+ Each port of BFD to a different machine requries the creation
+ of a target back end. All the back end provides to the root
+ part of BFD is a structure containing pointers to functions
+ which perform certain low level operations on files. BFD
+ translates the applications's requests through a pointer into
+ calls to the back end routines.
+
+ When a file is opened with <<bfd_openr>>, its format and
+ target are unknown. BFD uses various mechanisms to determine
+ how to interpret the file. The operations performed are:
+
+ o Create a BFD by calling the internal routine
+ <<_bfd_new_bfd>>, then call <<bfd_find_target>> with the
+ target string supplied to <<bfd_openr>> and the new BFD pointer.
+
+ o If a null target string was provided to <<bfd_find_target>>,
+ look up the environment variable <<GNUTARGET>> and use
+ that as the target string.
+
+ o If the target string is still <<NULL>>, or the target string is
+ <<default>>, then use the first item in the target vector
+ as the target type, and set <<target_defaulted>> in the BFD to
+ cause <<bfd_check_format>> to loop through all the targets.
+ @xref{bfd_target}. @xref{Formats}.
+
+ o Otherwise, inspect the elements in the target vector
+ one by one, until a match on target name is found. When found,
+ use it.
+
+ o Otherwise return the error <<bfd_error_invalid_target>> to
+ <<bfd_openr>>.
+
+ o <<bfd_openr>> attempts to open the file using
+ <<bfd_open_file>>, and returns the BFD.
+
+ Once the BFD has been opened and the target selected, the file
+ format may be determined. This is done by calling
+ <<bfd_check_format>> on the BFD with a suggested format.
+ If <<target_defaulted>> has been set, each possible target
+ type is tried to see if it recognizes the specified format.
+ <<bfd_check_format>> returns <<true>> when the caller guesses right.
+@menu
+@* bfd_target::
+@end menu
+*/
+
+
+/*
+
+INODE
+ bfd_target, , Targets, Targets
+DOCDD
+SUBSECTION
+ bfd_target
+
+DESCRIPTION
+ This structure contains everything that BFD knows about a
+ target. It includes things like its byte order, name, and which
+ routines to call to do various operations.
+
+ Every BFD points to a target structure with its <<xvec>>
+ member.
+
+ The macros below are used to dispatch to functions through the
+ <<bfd_target>> vector. They are used in a number of macros further
+ down in @file{bfd.h}, and are also used when calling various
+ routines by hand inside the BFD implementation. The @var{arglist}
+ argument must be parenthesized; it contains all the arguments
+ to the called function.
+
+ They make the documentation (more) unpleasant to read, so if
+ someone wants to fix this and not break the above, please do.
+
+.#define BFD_SEND(bfd, message, arglist) \
+. ((*((bfd)->xvec->message)) arglist)
+.
+.#ifdef DEBUG_BFD_SEND
+.#undef BFD_SEND
+.#define BFD_SEND(bfd, message, arglist) \
+. (((bfd) && (bfd)->xvec && (bfd)->xvec->message) ? \
+. ((*((bfd)->xvec->message)) arglist) : \
+. (bfd_assert (__FILE__,__LINE__), NULL))
+.#endif
+
+ For operations which index on the BFD format:
+
+.#define BFD_SEND_FMT(bfd, message, arglist) \
+. (((bfd)->xvec->message[(int)((bfd)->format)]) arglist)
+.
+.#ifdef DEBUG_BFD_SEND
+.#undef BFD_SEND_FMT
+.#define BFD_SEND_FMT(bfd, message, arglist) \
+. (((bfd) && (bfd)->xvec && (bfd)->xvec->message) ? \
+. (((bfd)->xvec->message[(int)((bfd)->format)]) arglist) : \
+. (bfd_assert (__FILE__,__LINE__), NULL))
+.#endif
+
+ This is the structure which defines the type of BFD this is. The
+ <<xvec>> member of the struct <<bfd>> itself points here. Each
+ module that implements access to a different target under BFD,
+ defines one of these.
+
+
+ FIXME, these names should be rationalised with the names of
+ the entry points which call them. Too bad we can't have one
+ macro to define them both!
+
+.enum bfd_flavour {
+. bfd_target_unknown_flavour,
+. bfd_target_aout_flavour,
+. bfd_target_coff_flavour,
+. bfd_target_ecoff_flavour,
+. bfd_target_elf_flavour,
+. bfd_target_ieee_flavour,
+. bfd_target_nlm_flavour,
+. bfd_target_oasys_flavour,
+. bfd_target_tekhex_flavour,
+. bfd_target_srec_flavour,
+. bfd_target_som_flavour,
+. bfd_target_os9k_flavour};
+.
+.{* Forward declaration. *}
+.typedef struct bfd_link_info _bfd_link_info;
+.
+.typedef struct bfd_target
+.{
+
+Identifies the kind of target, e.g., SunOS4, Ultrix, etc.
+
+. char *name;
+
+The "flavour" of a back end is a general indication about the contents
+of a file.
+
+. enum bfd_flavour flavour;
+
+The order of bytes within the data area of a file.
+
+. boolean byteorder_big_p;
+
+The order of bytes within the header parts of a file.
+
+. boolean header_byteorder_big_p;
+
+A mask of all the flags which an executable may have set -
+from the set <<NO_FLAGS>>, <<HAS_RELOC>>, ...<<D_PAGED>>.
+
+. flagword object_flags;
+
+A mask of all the flags which a section may have set - from
+the set <<SEC_NO_FLAGS>>, <<SEC_ALLOC>>, ...<<SET_NEVER_LOAD>>.
+
+. flagword section_flags;
+
+The character normally found at the front of a symbol
+(if any), perhaps `_'.
+
+. char symbol_leading_char;
+
+The pad character for file names within an archive header.
+
+. char ar_pad_char;
+
+The maximum number of characters in an archive header.
+
+. unsigned short ar_max_namelen;
+
+The minimum alignment restriction for any section.
+
+. unsigned int align_power_min;
+
+Entries for byte swapping for data. These are different from the other
+entry points, since they don't take a BFD asthe first argument.
+Certain other handlers could do the same.
+
+. bfd_vma (*bfd_getx64) PARAMS ((const bfd_byte *));
+. bfd_signed_vma (*bfd_getx_signed_64) PARAMS ((const bfd_byte *));
+. void (*bfd_putx64) PARAMS ((bfd_vma, bfd_byte *));
+. bfd_vma (*bfd_getx32) PARAMS ((const bfd_byte *));
+. bfd_signed_vma (*bfd_getx_signed_32) PARAMS ((const bfd_byte *));
+. void (*bfd_putx32) PARAMS ((bfd_vma, bfd_byte *));
+. bfd_vma (*bfd_getx16) PARAMS ((const bfd_byte *));
+. bfd_signed_vma (*bfd_getx_signed_16) PARAMS ((const bfd_byte *));
+. void (*bfd_putx16) PARAMS ((bfd_vma, bfd_byte *));
+
+Byte swapping for the headers
+
+. bfd_vma (*bfd_h_getx64) PARAMS ((const bfd_byte *));
+. bfd_signed_vma (*bfd_h_getx_signed_64) PARAMS ((const bfd_byte *));
+. void (*bfd_h_putx64) PARAMS ((bfd_vma, bfd_byte *));
+. bfd_vma (*bfd_h_getx32) PARAMS ((const bfd_byte *));
+. bfd_signed_vma (*bfd_h_getx_signed_32) PARAMS ((const bfd_byte *));
+. void (*bfd_h_putx32) PARAMS ((bfd_vma, bfd_byte *));
+. bfd_vma (*bfd_h_getx16) PARAMS ((const bfd_byte *));
+. bfd_signed_vma (*bfd_h_getx_signed_16) PARAMS ((const bfd_byte *));
+. void (*bfd_h_putx16) PARAMS ((bfd_vma, bfd_byte *));
+
+Format dependent routines: these are vectors of entry points
+within the target vector structure, one for each format to check.
+
+Check the format of a file being read. Return a <<bfd_target *>> or zero.
+
+. const struct bfd_target *(*_bfd_check_format[bfd_type_end]) PARAMS ((bfd *));
+
+Set the format of a file being written.
+
+. boolean (*_bfd_set_format[bfd_type_end]) PARAMS ((bfd *));
+
+Write cached information into a file being written, at <<bfd_close>>.
+
+. boolean (*_bfd_write_contents[bfd_type_end]) PARAMS ((bfd *));
+
+The general target vector.
+
+.
+. {* Generic entry points. *}
+.#define BFD_JUMP_TABLE_GENERIC(NAME)\
+.CAT(NAME,_close_and_cleanup),\
+.CAT(NAME,_bfd_free_cached_info),\
+.CAT(NAME,_new_section_hook),\
+.CAT(NAME,_get_section_contents)
+. {* Called when the BFD is being closed to do any necessary cleanup. *}
+. boolean (*_close_and_cleanup) PARAMS ((bfd *));
+. {* Ask the BFD to free all cached information. *}
+. boolean (*_bfd_free_cached_info) PARAMS ((bfd *));
+. {* Called when a new section is created. *}
+. boolean (*_new_section_hook) PARAMS ((bfd *, sec_ptr));
+. {* Read the contents of a section. *}
+. boolean (*_bfd_get_section_contents) PARAMS ((bfd *, sec_ptr, PTR,
+. file_ptr, bfd_size_type));
+.
+. {* Entry points to copy private data. *}
+.#define BFD_JUMP_TABLE_COPY(NAME)\
+.CAT(NAME,_bfd_copy_private_bfd_data),\
+.CAT(NAME,_bfd_copy_private_section_data)
+. {* Called to copy BFD general private data from one object file
+. to another. *}
+. boolean (*_bfd_copy_private_bfd_data) PARAMS ((bfd *, bfd *));
+. {* Called to copy BFD private section data from one object file
+. to another. *}
+. boolean (*_bfd_copy_private_section_data) PARAMS ((bfd *, sec_ptr,
+. bfd *, sec_ptr));
+.
+. {* Core file entry points. *}
+.#define BFD_JUMP_TABLE_CORE(NAME)\
+.CAT(NAME,_core_file_failing_command),\
+.CAT(NAME,_core_file_failing_signal),\
+.CAT(NAME,_core_file_matches_executable_p)
+. char * (*_core_file_failing_command) PARAMS ((bfd *));
+. int (*_core_file_failing_signal) PARAMS ((bfd *));
+. boolean (*_core_file_matches_executable_p) PARAMS ((bfd *, bfd *));
+.
+. {* Archive entry points. *}
+.#define BFD_JUMP_TABLE_ARCHIVE(NAME)\
+.CAT(NAME,_slurp_armap),\
+.CAT(NAME,_slurp_extended_name_table),\
+.CAT(NAME,_truncate_arname),\
+.CAT(NAME,_write_armap),\
+.CAT(NAME,_openr_next_archived_file),\
+.CAT(NAME,_generic_stat_arch_elt)
+. boolean (*_bfd_slurp_armap) PARAMS ((bfd *));
+. boolean (*_bfd_slurp_extended_name_table) PARAMS ((bfd *));
+. void (*_bfd_truncate_arname) PARAMS ((bfd *, CONST char *, char *));
+. boolean (*write_armap) PARAMS ((bfd *arch,
+. unsigned int elength,
+. struct orl *map,
+. unsigned int orl_count,
+. int stridx));
+. bfd * (*openr_next_archived_file) PARAMS ((bfd *arch, bfd *prev));
+. int (*_bfd_stat_arch_elt) PARAMS ((bfd *, struct stat *));
+.
+. {* Entry points used for symbols. *}
+.#define BFD_JUMP_TABLE_SYMBOLS(NAME)\
+.CAT(NAME,_get_symtab_upper_bound),\
+.CAT(NAME,_get_symtab),\
+.CAT(NAME,_make_empty_symbol),\
+.CAT(NAME,_print_symbol),\
+.CAT(NAME,_get_symbol_info),\
+.CAT(NAME,_bfd_is_local_label),\
+.CAT(NAME,_get_lineno),\
+.CAT(NAME,_find_nearest_line),\
+.CAT(NAME,_bfd_make_debug_symbol)
+. long (*_bfd_get_symtab_upper_bound) PARAMS ((bfd *));
+. long (*_bfd_canonicalize_symtab) PARAMS ((bfd *,
+. struct symbol_cache_entry **));
+. struct symbol_cache_entry *
+. (*_bfd_make_empty_symbol) PARAMS ((bfd *));
+. void (*_bfd_print_symbol) PARAMS ((bfd *, PTR,
+. struct symbol_cache_entry *,
+. bfd_print_symbol_type));
+.#define bfd_print_symbol(b,p,s,e) BFD_SEND(b, _bfd_print_symbol, (b,p,s,e))
+. void (*_bfd_get_symbol_info) PARAMS ((bfd *,
+. struct symbol_cache_entry *,
+. symbol_info *));
+.#define bfd_get_symbol_info(b,p,e) BFD_SEND(b, _bfd_get_symbol_info, (b,p,e))
+. boolean (*_bfd_is_local_label) PARAMS ((bfd *, asymbol *));
+.
+. alent * (*_get_lineno) PARAMS ((bfd *, struct symbol_cache_entry *));
+. boolean (*_bfd_find_nearest_line) PARAMS ((bfd *abfd,
+. struct sec *section, struct symbol_cache_entry **symbols,
+. bfd_vma offset, CONST char **file, CONST char **func,
+. unsigned int *line));
+. {* Back-door to allow format-aware applications to create debug symbols
+. while using BFD for everything else. Currently used by the assembler
+. when creating COFF files. *}
+. asymbol * (*_bfd_make_debug_symbol) PARAMS ((
+. bfd *abfd,
+. void *ptr,
+. unsigned long size));
+.
+. {* Routines for relocs. *}
+.#define BFD_JUMP_TABLE_RELOCS(NAME)\
+.CAT(NAME,_get_reloc_upper_bound),\
+.CAT(NAME,_canonicalize_reloc),\
+.CAT(NAME,_bfd_reloc_type_lookup)
+. long (*_get_reloc_upper_bound) PARAMS ((bfd *, sec_ptr));
+. long (*_bfd_canonicalize_reloc) PARAMS ((bfd *, sec_ptr, arelent **,
+. struct symbol_cache_entry **));
+. {* See documentation on reloc types. *}
+. CONST struct reloc_howto_struct *
+. (*reloc_type_lookup) PARAMS ((bfd *abfd,
+. bfd_reloc_code_real_type code));
+.
+. {* Routines used when writing an object file. *}
+.#define BFD_JUMP_TABLE_WRITE(NAME)\
+.CAT(NAME,_set_arch_mach),\
+.CAT(NAME,_set_section_contents)
+. boolean (*_bfd_set_arch_mach) PARAMS ((bfd *, enum bfd_architecture,
+. unsigned long));
+. boolean (*_bfd_set_section_contents) PARAMS ((bfd *, sec_ptr, PTR,
+. file_ptr, bfd_size_type));
+.
+. {* Routines used by the linker. *}
+.#define BFD_JUMP_TABLE_LINK(NAME)\
+.CAT(NAME,_sizeof_headers),\
+.CAT(NAME,_bfd_get_relocated_section_contents),\
+.CAT(NAME,_bfd_relax_section),\
+.CAT(NAME,_bfd_link_hash_table_create),\
+.CAT(NAME,_bfd_link_add_symbols),\
+.CAT(NAME,_bfd_final_link)
+. int (*_bfd_sizeof_headers) PARAMS ((bfd *, boolean));
+. bfd_byte * (*_bfd_get_relocated_section_contents) PARAMS ((bfd *,
+. struct bfd_link_info *, struct bfd_link_order *,
+. bfd_byte *data, boolean relocateable,
+. struct symbol_cache_entry **));
+.
+. boolean (*_bfd_relax_section) PARAMS ((bfd *, struct sec *,
+. struct bfd_link_info *, boolean *again));
+.
+. {* Create a hash table for the linker. Different backends store
+. different information in this table. *}
+. struct bfd_link_hash_table *(*_bfd_link_hash_table_create) PARAMS ((bfd *));
+.
+. {* Add symbols from this object file into the hash table. *}
+. boolean (*_bfd_link_add_symbols) PARAMS ((bfd *, struct bfd_link_info *));
+.
+. {* Do a link based on the link_order structures attached to each
+. section of the BFD. *}
+. boolean (*_bfd_final_link) PARAMS ((bfd *, struct bfd_link_info *));
+.
+. {* Routines to handle dynamic symbols and relocs. *}
+.#define BFD_JUMP_TABLE_DYNAMIC(NAME)\
+.CAT(NAME,_get_dynamic_symtab_upper_bound),\
+.CAT(NAME,_canonicalize_dynamic_symtab),\
+.CAT(NAME,_get_dynamic_reloc_upper_bound),\
+.CAT(NAME,_canonicalize_dynamic_reloc)
+. {* Get the amount of memory required to hold the dynamic symbols. *}
+. long (*_bfd_get_dynamic_symtab_upper_bound) PARAMS ((bfd *));
+. {* Read in the dynamic symbols. *}
+. long (*_bfd_canonicalize_dynamic_symtab)
+. PARAMS ((bfd *, struct symbol_cache_entry **));
+. {* Get the amount of memory required to hold the dynamic relocs. *}
+. long (*_bfd_get_dynamic_reloc_upper_bound) PARAMS ((bfd *));
+. {* Read in the dynamic relocs. *}
+. long (*_bfd_canonicalize_dynamic_reloc)
+. PARAMS ((bfd *, arelent **, struct symbol_cache_entry **));
+.
+
+Data for use by back-end routines, which isn't generic enough to belong
+in this structure.
+
+. PTR backend_data;
+.} bfd_target;
+
+*/
+
+/* All known xvecs (even those that don't compile on all systems).
+ Alphabetized for easy reference.
+ They are listed a second time below, since
+ we can't intermix extern's and initializers. */
+extern const bfd_target a29kcoff_big_vec;
+extern const bfd_target a_out_adobe_vec;
+extern const bfd_target aout_mips_big_vec;
+extern const bfd_target aout_mips_little_vec;
+extern const bfd_target aout0_big_vec;
+extern const bfd_target apollocoff_vec;
+extern const bfd_target b_out_vec_big_host;
+extern const bfd_target b_out_vec_little_host;
+extern const bfd_target bfd_elf32_big_generic_vec;
+extern const bfd_target bfd_elf32_bigmips_vec;
+extern const bfd_target bfd_elf32_hppa_vec;
+extern const bfd_target bfd_elf32_i386_vec;
+extern const bfd_target bfd_elf32_i860_vec;
+extern const bfd_target bfd_elf32_little_generic_vec;
+extern const bfd_target bfd_elf32_littlemips_vec;
+extern const bfd_target bfd_elf32_m68k_vec;
+extern const bfd_target bfd_elf32_m88k_vec;
+extern const bfd_target bfd_elf32_powerpc_vec;
+extern const bfd_target bfd_elf32_sparc_vec;
+extern const bfd_target bfd_elf64_big_generic_vec;
+extern const bfd_target bfd_elf64_little_generic_vec;
+extern const bfd_target bfd_elf64_sparc_vec;
+extern const bfd_target demo_64_vec;
+extern const bfd_target ecoff_big_vec;
+extern const bfd_target ecoff_little_vec;
+extern const bfd_target ecoffalpha_little_vec;
+extern const bfd_target h8300coff_vec;
+extern const bfd_target h8500coff_vec;
+extern const bfd_target host_aout_vec;
+extern const bfd_target hp300bsd_vec;
+extern const bfd_target hp300hpux_vec;
+extern const bfd_target som_vec;
+extern const bfd_target i386aout_vec;
+extern const bfd_target i386bsd_vec;
+extern const bfd_target i386dynix_vec;
+extern const bfd_target i386os9k_vec;
+extern const bfd_target netbsd386_vec;
+extern const bfd_target freebsd386_vec;
+extern const bfd_target i386coff_vec;
+extern const bfd_target go32coff_vec;
+extern const bfd_target i386linux_vec;
+extern const bfd_target i386lynx_aout_vec;
+extern const bfd_target i386lynx_coff_vec;
+extern const bfd_target i386mach3_vec;
+extern const bfd_target icoff_big_vec;
+extern const bfd_target icoff_little_vec;
+extern const bfd_target ieee_vec;
+extern const bfd_target m68kcoff_vec;
+extern const bfd_target m68kcoffun_vec;
+extern const bfd_target m68klynx_aout_vec;
+extern const bfd_target m68klynx_coff_vec;
+extern const bfd_target m88kbcs_vec;
+extern const bfd_target m88kmach3_vec;
+extern const bfd_target netbsd532_vec;
+extern const bfd_target newsos3_vec;
+extern const bfd_target nlm32_i386_vec;
+extern const bfd_target nlm32_sparc_vec;
+extern const bfd_target nlm32_alpha_vec;
+extern const bfd_target nlm32_powerpc_vec;
+extern const bfd_target oasys_vec;
+extern const bfd_target pc532mach_vec;
+extern const bfd_target rs6000coff_vec;
+extern const bfd_target shcoff_vec;
+extern const bfd_target sparclynx_aout_vec;
+extern const bfd_target sparclynx_coff_vec;
+extern const bfd_target sparccoff_vec;
+extern const bfd_target sunos_big_vec;
+extern const bfd_target tekhex_vec;
+extern const bfd_target we32kcoff_vec;
+extern const bfd_target z8kcoff_vec;
+
+/* srec is always included. */
+extern const bfd_target srec_vec;
+extern const bfd_target symbolsrec_vec;
+
+/* All of the xvecs for core files. */
+extern const bfd_target aix386_core_vec;
+extern const bfd_target cisco_core_vec;
+extern const bfd_target hpux_core_vec;
+extern const bfd_target hppabsd_core_vec;
+extern const bfd_target irix_core_vec;
+extern const bfd_target osf_core_vec;
+extern const bfd_target sco_core_vec;
+extern const bfd_target trad_core_vec;
+extern const bfd_target ptrace_core_vec;
+
+const bfd_target * const bfd_target_vector[] = {
+
+#ifdef SELECT_VECS
+
+ SELECT_VECS,
+
+#else /* not SELECT_VECS */
+
+#ifdef DEFAULT_VECTOR
+ &DEFAULT_VECTOR,
+#endif
+ /* This list is alphabetized to make it easy to compare
+ with other vector lists -- the decls above and
+ the case statement in configure.in.
+ Vectors that don't compile on all systems, or aren't finished,
+ should have an entry here with #if 0 around it, to show that
+ it wasn't omitted by mistake. */
+ &a29kcoff_big_vec,
+ &a_out_adobe_vec,
+#if 0 /* No one seems to use this. */
+ &aout_mips_big_vec,
+#endif
+ &aout_mips_little_vec,
+ &b_out_vec_big_host,
+ &b_out_vec_little_host,
+
+ /* This, and other vectors, may not be used in any *.mt configuration.
+ But that does not mean they are unnecessary. If configured with
+ --enable-targets=all, objdump or gdb should be able to examine
+ the file even if we don't recognize the machine type. */
+ &bfd_elf32_big_generic_vec,
+ &bfd_elf32_bigmips_vec,
+ &bfd_elf32_hppa_vec,
+ &bfd_elf32_i386_vec,
+ &bfd_elf32_i860_vec,
+ &bfd_elf32_little_generic_vec,
+ &bfd_elf32_littlemips_vec,
+ &bfd_elf32_m68k_vec,
+ &bfd_elf32_m88k_vec,
+ &bfd_elf32_sparc_vec,
+ &bfd_elf32_powerpc_vec,
+#ifdef BFD64 /* No one seems to use this. */
+ &bfd_elf64_big_generic_vec,
+ &bfd_elf64_little_generic_vec,
+#endif
+#if 0
+ &bfd_elf64_sparc_vec,
+#endif
+ /* We don't include cisco_core_vec. Although it has a magic number,
+ the magic number isn't at the beginning of the file, and thus
+ might spuriously match other kinds of files. */
+#ifdef BFD64
+ &demo_64_vec, /* Only compiled if host has long-long support */
+#endif
+ &ecoff_big_vec,
+ &ecoff_little_vec,
+#if 0
+ &ecoffalpha_little_vec,
+#endif
+ &h8300coff_vec,
+ &h8500coff_vec,
+#if 0
+ /* Since a.out files lack decent magic numbers, no way to recognize
+ which kind of a.out file it is. */
+ &host_aout_vec,
+#endif
+#if 0 /* Clashes with sunos_big_vec magic no. */
+ &hp300bsd_vec,
+#endif
+ &hp300hpux_vec,
+#if defined (HOST_HPPAHPUX) || defined (HOST_HPPABSD) || defined (HOST_HPPAOSF)
+ &som_vec,
+#endif
+ &i386aout_vec,
+ &i386bsd_vec,
+ &i386coff_vec,
+ &go32coff_vec,
+#if 0
+ /* Since a.out files lack decent magic numbers, no way to recognize
+ which kind of a.out file it is. */
+ &i386linux_vec,
+#endif
+ &i386lynx_aout_vec,
+ &i386lynx_coff_vec,
+#if 0
+ /* No distinguishing features for Mach 3 executables. */
+ &i386mach3_vec,
+#endif
+ &i386os9k_vec,
+ &icoff_big_vec,
+ &icoff_little_vec,
+ &ieee_vec,
+ &m68kcoff_vec,
+ &m68kcoffun_vec,
+ &m68klynx_aout_vec,
+ &m68klynx_coff_vec,
+ &m88kbcs_vec,
+ &m88kmach3_vec,
+ &newsos3_vec,
+ &netbsd386_vec,
+ &netbsd532_vec,
+ &nlm32_i386_vec,
+ &nlm32_sparc_vec,
+#ifdef BFD64
+ &nlm32_alpha_vec,
+#endif
+#if 0
+ /* We have no oasys tools anymore, so we can't test any of this
+ anymore. If you want to test the stuff yourself, go ahead...
+ steve@cygnus.com
+ Worse, since there is no magic number for archives, there
+ can be annoying target mis-matches. */
+ &oasys_vec,
+#endif
+ &pc532machaout_vec,
+ &rs6000coff_vec,
+ &shcoff_vec,
+ &sparclynx_aout_vec,
+ &sparclynx_coff_vec,
+ &sunos_big_vec,
+ &aout0_big_vec,
+#if 0
+ &tekhex_vec,
+#endif
+ &we32kcoff_vec,
+ &z8kcoff_vec,
+
+#endif /* not SELECT_VECS */
+
+/* Always support S-records, for convenience. */
+ &srec_vec,
+ &symbolsrec_vec,
+
+/* Add any required traditional-core-file-handler. */
+
+#ifdef AIX386_CORE
+ &aix386_core_vec,
+#endif
+#ifdef HPUX_CORE
+ &hpux_core_vec,
+#endif
+#ifdef HPPABSD_CORE
+ &hppabsd_core_vec,
+#endif
+#ifdef IRIX_CORE
+ &irix_core_vec,
+#endif
+#ifdef OSF_CORE
+ &osf_core_vec,
+#endif
+#ifdef TRAD_CORE
+ &trad_core_vec,
+#endif
+
+#ifdef PTRACE_CORE
+ &ptrace_core_vec,
+#endif
+
+ NULL /* end of list marker */
+};
+
+/* bfd_default_vector[0] contains either the address of the default vector,
+ if there is one, or zero if there isn't. */
+
+const bfd_target * const bfd_default_vector[] = {
+#ifdef DEFAULT_VECTOR
+ &DEFAULT_VECTOR,
+#endif
+ NULL
+};
+
+/* When there is an ambiguous match, bfd_check_format_matches puts the
+ names of the matching targets in an array. This variable is the maximum
+ number of entries that the array could possibly need. */
+const size_t _bfd_target_vector_entries = sizeof(bfd_target_vector)/sizeof(*bfd_target_vector);
+
+/*
+FUNCTION
+ bfd_find_target
+
+SYNOPSIS
+ const bfd_target *bfd_find_target(CONST char *target_name, bfd *abfd);
+
+DESCRIPTION
+ Return a pointer to the transfer vector for the object target
+ named @var{target_name}. If @var{target_name} is <<NULL>>, choose the
+ one in the environment variable <<GNUTARGET>>; if that is null or not
+ defined, then choose the first entry in the target list.
+ Passing in the string "default" or setting the environment
+ variable to "default" will cause the first entry in the target
+ list to be returned, and "target_defaulted" will be set in the
+ BFD. This causes <<bfd_check_format>> to loop over all the
+ targets to find the one that matches the file being read.
+*/
+
+const bfd_target *
+bfd_find_target (target_name, abfd)
+ CONST char *target_name;
+ bfd *abfd;
+{
+ const bfd_target * const *target;
+ extern char *getenv ();
+ CONST char *targname = (target_name ? target_name :
+ (CONST char *) getenv ("GNUTARGET"));
+
+ /* This is safe; the vector cannot be null */
+ if (targname == NULL || !strcmp (targname, "default")) {
+ abfd->target_defaulted = true;
+ return abfd->xvec = bfd_target_vector[0];
+ }
+
+ abfd->target_defaulted = false;
+
+ for (target = &bfd_target_vector[0]; *target != NULL; target++) {
+ if (!strcmp (targname, (*target)->name))
+ return abfd->xvec = *target;
+ }
+
+ bfd_set_error (bfd_error_invalid_target);
+ return NULL;
+}
+
+
+/*
+FUNCTION
+ bfd_target_list
+
+SYNOPSIS
+ const char **bfd_target_list(void);
+
+DESCRIPTION
+ Return a freshly malloced NULL-terminated
+ vector of the names of all the valid BFD targets. Do not
+ modify the names.
+
+*/
+
+const char **
+bfd_target_list ()
+{
+ int vec_length= 0;
+#ifdef NATIVE_HPPAHPUX_COMPILER
+ /* The native compiler on the HP9000/700 has a bug which causes it
+ to loop endlessly when compiling this file. This avoids it. */
+ volatile
+#endif
+ const bfd_target * const *target;
+ CONST char **name_list, **name_ptr;
+
+ for (target = &bfd_target_vector[0]; *target != NULL; target++)
+ vec_length++;
+
+ name_ptr = name_list = (CONST char **)
+ bfd_zmalloc ((vec_length + 1) * sizeof (char **));
+
+ if (name_list == NULL) {
+ bfd_set_error (bfd_error_no_memory);
+ return NULL;
+ }
+
+ for (target = &bfd_target_vector[0]; *target != NULL; target++)
+ *(name_ptr++) = (*target)->name;
+
+ return name_list;
+}
diff --git a/gnu/usr.bin/gdb/bfd/trad-core.c b/gnu/usr.bin/gdb/bfd/trad-core.c
new file mode 100644
index 0000000..dc3d843
--- /dev/null
+++ b/gnu/usr.bin/gdb/bfd/trad-core.c
@@ -0,0 +1,340 @@
+/* BFD back end for traditional Unix core files (U-area and raw sections)
+ Copyright 1988, 1989, 1991, 1992, 1993, 1994 Free Software Foundation, Inc.
+ Written by John Gilmore of Cygnus Support.
+
+This file is part of BFD, the Binary File Descriptor library.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* To use this file on a particular host, configure the host with these
+ parameters in the config/h-HOST file:
+
+ HDEFINES=-DTRAD_CORE
+ HDEPFILES=trad-core.o
+
+ */
+
+#include "bfd.h"
+#include "sysdep.h"
+#include "libbfd.h"
+#include "libaout.h" /* BFD a.out internal data structures */
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/dir.h>
+#include <signal.h>
+
+#include <sys/user.h> /* After a.out.h */
+#if 0
+/* file.h is included by std-host.h. So we better not try to include it
+ twice; on some systems (dpx2) it is not protected against multiple
+ inclusion. I have checked that all the hosts which use this file
+ include sys/file.h in the hosts file. */
+#include <sys/file.h>
+#endif
+
+#include <errno.h>
+
+ struct trad_core_struct
+ {
+ asection *data_section;
+ asection *stack_section;
+ asection *reg_section;
+ struct user u;
+ } *rawptr;
+
+#define core_upage(bfd) (&((bfd)->tdata.trad_core_data->u))
+#define core_datasec(bfd) ((bfd)->tdata.trad_core_data->data_section)
+#define core_stacksec(bfd) ((bfd)->tdata.trad_core_data->stack_section)
+#define core_regsec(bfd) ((bfd)->tdata.trad_core_data->reg_section)
+
+/* forward declarations */
+
+const bfd_target *trad_unix_core_file_p PARAMS ((bfd *abfd));
+char * trad_unix_core_file_failing_command PARAMS ((bfd *abfd));
+int trad_unix_core_file_failing_signal PARAMS ((bfd *abfd));
+boolean trad_unix_core_file_matches_executable_p
+ PARAMS ((bfd *core_bfd, bfd *exec_bfd));
+
+/* Handle 4.2-style (and perhaps also sysV-style) core dump file. */
+
+/* ARGSUSED */
+const bfd_target *
+trad_unix_core_file_p (abfd)
+ bfd *abfd;
+
+{
+ int val;
+ struct user u;
+
+#ifdef TRAD_CORE_USER_OFFSET
+ /* If defined, this macro is the file position of the user struct. */
+ if (bfd_seek (abfd, TRAD_CORE_USER_OFFSET, SEEK_SET) != 0)
+ return 0;
+#endif
+
+ val = bfd_read ((void *)&u, 1, sizeof u, abfd);
+ if (val != sizeof u)
+ {
+ /* Too small to be a core file */
+ bfd_set_error (bfd_error_wrong_format);
+ return 0;
+ }
+
+ /* Sanity check perhaps??? */
+ if (u.u_dsize > 0x1000000) /* Remember, it's in pages... */
+ {
+ bfd_set_error (bfd_error_wrong_format);
+ return 0;
+ }
+ if (u.u_ssize > 0x1000000)
+ {
+ bfd_set_error (bfd_error_wrong_format);
+ return 0;
+ }
+
+ /* Check that the size claimed is no greater than the file size. */
+ {
+ FILE *stream = bfd_cache_lookup (abfd);
+ struct stat statbuf;
+ if (stream == NULL)
+ return 0;
+ if (fstat (fileno (stream), &statbuf) < 0)
+ {
+ bfd_set_error (bfd_error_system_call);
+ return 0;
+ }
+ if (NBPG * (UPAGES + u.u_dsize
+#ifdef TRAD_CORE_DSIZE_INCLUDES_TSIZE
+ - u.u_tsize
+#endif
+ + u.u_ssize) > statbuf.st_size)
+ {
+ bfd_set_error (bfd_error_file_truncated);
+ return 0;
+ }
+#ifndef TRAD_CORE_ALLOW_ANY_EXTRA_SIZE
+ if (NBPG * (UPAGES + u.u_dsize + u.u_ssize)
+#ifdef TRAD_CORE_EXTRA_SIZE_ALLOWED
+ /* Some systems write the file too big. */
+ + TRAD_CORE_EXTRA_SIZE_ALLOWED
+#endif
+ < statbuf.st_size)
+ {
+ /* The file is too big. Maybe it's not a core file
+ or we otherwise have bad values for u_dsize and u_ssize). */
+ bfd_set_error (bfd_error_wrong_format);
+ return 0;
+ }
+#endif
+ }
+
+ /* OK, we believe you. You're a core file (sure, sure). */
+
+ /* Allocate both the upage and the struct core_data at once, so
+ a single free() will free them both. */
+ rawptr = (struct trad_core_struct *)
+ bfd_zmalloc (sizeof (struct trad_core_struct));
+ if (rawptr == NULL) {
+ bfd_set_error (bfd_error_no_memory);
+ return 0;
+ }
+
+ abfd->tdata.trad_core_data = rawptr;
+
+ rawptr->u = u; /*Copy the uarea into the tdata part of the bfd */
+
+ /* Create the sections. This is raunchy, but bfd_close wants to free
+ them separately. */
+
+ core_stacksec(abfd) = (asection *) bfd_zmalloc (sizeof (asection));
+ if (core_stacksec (abfd) == NULL) {
+ loser:
+ bfd_set_error (bfd_error_no_memory);
+ free ((void *)rawptr);
+ return 0;
+ }
+ core_datasec (abfd) = (asection *) bfd_zmalloc (sizeof (asection));
+ if (core_datasec (abfd) == NULL) {
+ loser1:
+ free ((void *)core_stacksec (abfd));
+ goto loser;
+ }
+ core_regsec (abfd) = (asection *) bfd_zmalloc (sizeof (asection));
+ if (core_regsec (abfd) == NULL) {
+ free ((void *)core_datasec (abfd));
+ goto loser1;
+ }
+
+ core_stacksec (abfd)->name = ".stack";
+ core_datasec (abfd)->name = ".data";
+ core_regsec (abfd)->name = ".reg";
+
+ core_stacksec (abfd)->flags = SEC_ALLOC + SEC_LOAD + SEC_HAS_CONTENTS;
+ core_datasec (abfd)->flags = SEC_ALLOC + SEC_LOAD + SEC_HAS_CONTENTS;
+ core_regsec (abfd)->flags = SEC_HAS_CONTENTS;
+
+ core_datasec (abfd)->_raw_size = NBPG * u.u_dsize
+#ifdef TRAD_CORE_DSIZE_INCLUDES_TSIZE
+ - NBPG * u.u_tsize
+#endif
+ ;
+ core_stacksec (abfd)->_raw_size = NBPG * u.u_ssize;
+ core_regsec (abfd)->_raw_size = NBPG * UPAGES; /* Larger than sizeof struct u */
+
+ /* What a hack... we'd like to steal it from the exec file,
+ since the upage does not seem to provide it. FIXME. */
+#ifdef HOST_DATA_START_ADDR
+ core_datasec (abfd)->vma = HOST_DATA_START_ADDR;
+#else
+ core_datasec (abfd)->vma = HOST_TEXT_START_ADDR + (NBPG * u.u_tsize);
+#endif
+
+#ifdef HOST_STACK_START_ADDR
+ core_stacksec (abfd)->vma = HOST_STACK_START_ADDR;
+#else
+ core_stacksec (abfd)->vma = HOST_STACK_END_ADDR - (NBPG * u.u_ssize);
+#endif
+
+ /* This is tricky. As the "register section", we give them the entire
+ upage and stack. u.u_ar0 points to where "register 0" is stored.
+ There are two tricks with this, though. One is that the rest of the
+ registers might be at positive or negative (or both) displacements
+ from *u_ar0. The other is that u_ar0 is sometimes an absolute address
+ in kernel memory, and on other systems it is an offset from the beginning
+ of the `struct user'.
+
+ As a practical matter, we don't know where the registers actually are,
+ so we have to pass the whole area to GDB. We encode the value of u_ar0
+ by setting the .regs section up so that its virtual memory address
+ 0 is at the place pointed to by u_ar0 (by setting the vma of the start
+ of the section to -u_ar0). GDB uses this info to locate the regs,
+ using minor trickery to get around the offset-or-absolute-addr problem. */
+ core_regsec (abfd)->vma = 0 - (int) u.u_ar0;
+
+ core_datasec (abfd)->filepos = NBPG * UPAGES;
+ core_stacksec (abfd)->filepos = (NBPG * UPAGES) + NBPG * u.u_dsize
+#ifdef TRAD_CORE_DSIZE_INCLUDES_TSIZE
+ - NBPG * u.u_tsize
+#endif
+ ;
+ core_regsec (abfd)->filepos = 0; /* Register segment is the upage */
+
+ /* Align to word at least */
+ core_stacksec (abfd)->alignment_power = 2;
+ core_datasec (abfd)->alignment_power = 2;
+ core_regsec (abfd)->alignment_power = 2;
+
+ abfd->sections = core_stacksec (abfd);
+ core_stacksec (abfd)->next = core_datasec (abfd);
+ core_datasec (abfd)->next = core_regsec (abfd);
+ abfd->section_count = 3;
+
+ return abfd->xvec;
+}
+
+char *
+trad_unix_core_file_failing_command (abfd)
+ bfd *abfd;
+{
+#ifndef NO_CORE_COMMAND
+ char *com = abfd->tdata.trad_core_data->u.u_comm;
+ if (*com)
+ return com;
+ else
+#endif
+ return 0;
+}
+
+/* ARGSUSED */
+int
+trad_unix_core_file_failing_signal (ignore_abfd)
+ bfd *ignore_abfd;
+{
+#ifdef TRAD_UNIX_CORE_FILE_FAILING_SIGNAL
+ return TRAD_UNIX_CORE_FILE_FAILING_SIGNAL(ignore_abfd);
+#else
+ return -1; /* FIXME, where is it? */
+#endif
+}
+
+/* ARGSUSED */
+boolean
+trad_unix_core_file_matches_executable_p (core_bfd, exec_bfd)
+ bfd *core_bfd, *exec_bfd;
+{
+ return true; /* FIXME, We have no way of telling at this point */
+}
+
+/* If somebody calls any byte-swapping routines, shoot them. */
+void
+swap_abort()
+{
+ abort(); /* This way doesn't require any declaration for ANSI to fuck up */
+}
+#define NO_GET ((bfd_vma (*) PARAMS (( const bfd_byte *))) swap_abort )
+#define NO_PUT ((void (*) PARAMS ((bfd_vma, bfd_byte *))) swap_abort )
+#define NO_SIGNED_GET \
+ ((bfd_signed_vma (*) PARAMS ((const bfd_byte *))) swap_abort )
+
+const bfd_target trad_core_vec =
+ {
+ "trad-core",
+ bfd_target_unknown_flavour,
+ true, /* target byte order */
+ true, /* target headers byte order */
+ (HAS_RELOC | EXEC_P | /* object flags */
+ HAS_LINENO | HAS_DEBUG |
+ HAS_SYMS | HAS_LOCALS | WP_TEXT | D_PAGED),
+ (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC), /* section flags */
+ 0, /* symbol prefix */
+ ' ', /* ar_pad_char */
+ 16, /* ar_max_namelen */
+ 3, /* minimum alignment power */
+ NO_GET, NO_SIGNED_GET, NO_PUT, /* 64 bit data */
+ NO_GET, NO_SIGNED_GET, NO_PUT, /* 32 bit data */
+ NO_GET, NO_SIGNED_GET, NO_PUT, /* 16 bit data */
+ NO_GET, NO_SIGNED_GET, NO_PUT, /* 64 bit hdrs */
+ NO_GET, NO_SIGNED_GET, NO_PUT, /* 32 bit hdrs */
+ NO_GET, NO_SIGNED_GET, NO_PUT, /* 16 bit hdrs */
+
+ { /* bfd_check_format */
+ _bfd_dummy_target, /* unknown format */
+ _bfd_dummy_target, /* object file */
+ _bfd_dummy_target, /* archive */
+ trad_unix_core_file_p /* a core file */
+ },
+ { /* bfd_set_format */
+ bfd_false, bfd_false,
+ bfd_false, bfd_false
+ },
+ { /* bfd_write_contents */
+ bfd_false, bfd_false,
+ bfd_false, bfd_false
+ },
+
+ BFD_JUMP_TABLE_GENERIC (_bfd_generic),
+ BFD_JUMP_TABLE_COPY (_bfd_generic),
+ BFD_JUMP_TABLE_CORE (trad_unix),
+ BFD_JUMP_TABLE_ARCHIVE (_bfd_noarchive),
+ BFD_JUMP_TABLE_SYMBOLS (_bfd_nosymbols),
+ BFD_JUMP_TABLE_RELOCS (_bfd_norelocs),
+ BFD_JUMP_TABLE_WRITE (_bfd_generic),
+ BFD_JUMP_TABLE_LINK (_bfd_nolink),
+ BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic),
+
+ (PTR) 0 /* backend_data */
+};
diff --git a/gnu/usr.bin/gdb/doc/GDBvn.texi b/gnu/usr.bin/gdb/doc/GDBvn.texi
new file mode 100644
index 0000000..c891e56
--- /dev/null
+++ b/gnu/usr.bin/gdb/doc/GDBvn.texi
@@ -0,0 +1 @@
+@set GDBVN 4.13
diff --git a/gnu/usr.bin/gdb/doc/Makefile b/gnu/usr.bin/gdb/doc/Makefile
new file mode 100644
index 0000000..af61ced
--- /dev/null
+++ b/gnu/usr.bin/gdb/doc/Makefile
@@ -0,0 +1,4 @@
+INFO = gdb gdbint stabs annotate
+MAKEINFOFLAGS += -I ${.CURDIR}/../../../lib/libreadline/doc
+
+.include <bsd.info.mk>
diff --git a/gnu/usr.bin/gdb/doc/all-cfg.texi b/gnu/usr.bin/gdb/doc/all-cfg.texi
new file mode 100644
index 0000000..ec64da1
--- /dev/null
+++ b/gnu/usr.bin/gdb/doc/all-cfg.texi
@@ -0,0 +1,117 @@
+@c GDB MANUAL configuration file.
+@c Copyright (c) 1993 Free Software Foundation, Inc.
+@c
+@c NOTE: While the GDB manual is configurable (by changing these
+@c switches), its configuration is ***NOT*** automatically tied in to
+@c source configuration---because the authors expect that, save in
+@c unusual cases, the most inclusive form of the manual is appropriate
+@c no matter how the program itself is configured.
+@c
+@c The only automatically-varying variable is the GDB version number,
+@c which the Makefile rewrites based on the VERSION variable from
+@c `../Makefile.in'.
+@c
+@c GDB version number is recorded in the variable GDBVN
+@include GDBvn.texi
+@c
+@c ----------------------------------------------------------------------
+@c PLATFORM FLAGS:
+@set GENERIC
+@c
+@c Hitachi H8/300 target:
+@set H8
+@c Hitachi H8/300 target ONLY:
+@clear H8EXCLUSIVE
+@c
+@c remote MIPS target:
+@set MIPS
+@c
+@c SPARC target:
+@set SPARC
+@c
+@c AMD 29000 target:
+@set AMD29K
+@c
+@c Intel 960 target:
+@set I960
+@c
+@c Tandem ST2000 (phone switch) target:
+@set ST2000
+@c
+@c Zilog 8000 target:
+@set Z8K
+@c
+@c Lucid "Energize" environment:
+@clear LUCID
+@c
+@c Wind River Systems VxWorks environment:
+@set VXWORKS
+@c
+@c ----------------------------------------------------------------------
+@c DOC FEATURE FLAGS:
+@c
+@c Include change-from-old?
+@set NOVEL
+@c
+@c Bare-board target?
+@clear BARETARGET
+@c
+@c Restrict languages discussed to C?
+@c This is backward. As time permits, change this to language-specific
+@c switches for what to include.
+@clear CONLY
+@c Discuss Fortran?
+@set FORTRAN
+@c
+@c Discuss Modula 2?
+@set MOD2
+@c
+@c Specifically for host machine running DOS?
+@clear DOSHOST
+@c
+@c Talk about CPU simulator targets?
+@set SIMS
+@c
+@c Is manual stand-alone, or part of an agglomeration, with overall GPL?
+@clear AGGLOMERATION
+@c
+@c Remote serial line settings of interest?
+@set SERIAL
+@c
+@c Discuss features requiring Posix or similar OS environment?
+@set POSIX
+@c
+@c Discuss remote serial debugging stub?
+@set REMOTESTUB
+@c
+@c Discuss gdbserver?
+@set GDBSERVER
+@c
+@c Refrain from discussing how to configure sw and format doc?
+@clear PRECONFIGURED
+@c
+@c Refrain from referring to unfree publications?
+@set FSFDOC
+@c
+@c ----------------------------------------------------------------------
+@c STRINGS:
+@c
+@c Name of GDB program. Used also for (gdb) prompt string.
+@set GDBP gdb
+@c
+@c Name of GDB product. Used in running text.
+@set GDBN GDB
+@c
+@c Name of GDB initialization file.
+@set GDBINIT .gdbinit
+@c
+@c Name of host. Should not be used in generic configs, but generic
+@c value may catch some flubs.
+@set HOST machine specific
+@c
+@c Name of GCC product
+@set NGCC GCC
+@c
+@c Name of GCC program
+@set GCC gcc
+
diff --git a/gnu/usr.bin/gdb/doc/annotate.texi b/gnu/usr.bin/gdb/doc/annotate.texi
new file mode 100644
index 0000000..7716535
--- /dev/null
+++ b/gnu/usr.bin/gdb/doc/annotate.texi
@@ -0,0 +1,708 @@
+\input texinfo @c -*-texinfo-*-
+@c %**start of header
+@setfilename annotate.info
+@settitle GDB Annotations
+@setchapternewpage off
+@c %**end of header
+
+@set EDITION 0.5
+@set DATE May 1994
+
+@ifinfo
+This file documents GDB annotations.
+
+This is Edition @value{EDITION}, @value{DATE}, of @cite{GDB
+Annotations}. Copyright 1994 Free Software Foundation
+
+Permission is granted to make and distribute verbatim copies of
+this manual provided the copyright notice and this permission notice
+are preserved on all copies.
+
+@ignore
+Permission is granted to process this file through TeX and print the
+results, provided the printed document carries copying permission
+notice identical to this one except for the removal of this paragraph
+(this paragraph not being relevant to the printed manual).
+
+@end ignore
+Permission is granted to copy and distribute modified versions of this
+manual under the conditions for verbatim copying, provided also that the
+entire resulting derived work is distributed under the terms of a
+permission notice identical to this one.
+
+Permission is granted to copy and distribute translations of this manual
+into another language, under the above conditions for modified versions.
+@end ifinfo
+
+@titlepage
+@title GDB Annotations
+@subtitle Edition @value{EDITION}
+@subtitle @value{DATE}
+@author Cygnus Support
+@page
+@vskip 0pt plus 1filll
+Permission is granted to make and distribute verbatim copies of
+this manual provided the copyright notice and this permission notice
+are preserved on all copies.
+
+Copyright @copyright{} 1994 Free Software Foundation
+@end titlepage
+
+@ifinfo
+@node Top
+@top GDB Annotations
+
+This file describes annotations in GDB, the GNU symbolic debugger.
+Annotations are designed to interface GDB to graphical user interfaces
+or other similar programs which want to interact with GDB at a
+relatively high level.
+
+This is Edition @value{EDITION}, @value{DATE}.
+
+@menu
+* General:: What annotations are; the general syntax.
+* Server:: Issuing a command without affecting user state.
+* Values:: Values are marked as such.
+* Frames:: Stack frames are annotated.
+* Displays:: GDB can be told to display something periodically.
+* Prompting:: Annotations marking GDB's need for input.
+* Errors:: Annotations for error messages.
+* Breakpoint Info:: Information on breakpoints.
+* Invalidation:: Some annotations describe things now invalid.
+* Running:: Whether the program is running, how it stopped, etc.
+* Source:: Annotations describing source code.
+* TODO:: Annotations which might be added in the future.
+* Index:: Index
+@end menu
+@end ifinfo
+
+@node General
+@chapter What is an Annotation?
+
+To produce annotations, start GDB with the @code{--annotate=2} option.
+
+Annotations start with a newline character, two @samp{control-z}
+characters, and the name of the annotation. If there is no additional
+information associated with this annotation, the name of the annotation
+is followed immediately by a newline. If there is additional
+information, the name of the annotation is followed by a space, the
+additional information, and a newline. The additional information
+cannot contain newline characters.
+
+Any output not beginning with a newline and two @samp{control-z}
+characters denotes literal output from GDB. Currently there is no need
+for GDB to output a newline followed by two @samp{control-z} characters,
+but if there was such a need, the annotations could be extended with an
+@samp{escape} annotation which means those three characters as output.
+
+A simple example of starting up GDB with annotations is:
+
+@example
+$ gdb --annotate=2
+GDB is free software and you are welcome to distribute copies of it
+ under certain conditions; type "show copying" to see the conditions.
+There is absolutely no warranty for GDB; type "show warranty" for details.
+GDB 4.12.3 (sparc-sun-sunos4.1.3),
+Copyright 1994 Free Software Foundation, Inc.
+
+^Z^Zpre-prompt
+(gdb)
+^Z^Zprompt
+quit
+
+^Z^Zpost-prompt
+$
+@end example
+
+Here @samp{quit} is input to GDB; the rest is output from GDB. The three
+lines beginning @samp{^Z^Z} (where @samp{^Z} denotes a @samp{control-z}
+character) are annotations; the rest is output from GDB.
+
+@node Server
+@chapter The Server Prefix
+
+To issue a command to GDB without affecting certain aspects of the state
+which is seen by users, prefix it with @samp{server }. This means that
+this command will not affect the command history, nor will it affect
+GDB's notion of which command to repeat if @key{RET} is pressed on a
+line by itself.
+
+The server prefix does not affect the recording of values into the value
+history; to print a value without recording it into the value history,
+use the @code{output} command instead of the @code{print} command.
+
+@node Values
+@chapter Values
+
+When a value is printed in various contexts, GDB uses annotations to
+delimit the value from the surrounding text.
+
+@findex value-history-begin
+@findex value-history-value
+@findex value-history-end
+If a value is printed using @code{print} and added to the value history,
+the annotation looks like
+
+@example
+^Z^Zvalue-history-begin @var{history-number} @var{value-flags}
+@var{history-string}
+^Z^Zvalue-history-value
+@var{the-value}
+^Z^Zvalue-history-end
+@end example
+
+where @var{history-number} is the number it is getting in the value
+history, @var{history-string} is a string, such as @samp{$5 = }, which
+introduces the value to the user, @var{the-value} is the output
+corresponding to the value itself, and @var{value-flags} is @samp{*} for
+a value which can be dereferenced and @samp{-} for a value which cannot.
+
+@findex value-begin
+@findex value-end
+If the value is not added to the value history (it is an invalid float
+or it is printed with the @code{output} command), the annotation is similar:
+
+@example
+^Z^Zvalue-begin @var{value-flags}
+@var{the-value}
+^Z^Zvalue-end
+@end example
+
+@findex arg-begin
+@findex arg-name-end
+@findex arg-value
+@findex arg-end
+When GDB prints an argument to a function (for example, in the output
+from the @code{backtrace} command), it annotates it as follows:
+
+@example
+^Z^Zarg-begin
+@var{argument-name}
+^Z^Zarg-name-end
+@var{separator-string}
+^Z^Zarg-value @var{value-flags}
+@var{the-value}
+^Z^Zarg-end
+@end example
+
+where @var{argument-name} is the name of the argument,
+@var{separator-string} is text which separates the name from the value
+for the user's benefit (such as @samp{=}), and @var{value-flags} and
+@var{the-value} have the same meanings as in a
+@code{value-history-begin} annotation.
+
+@findex field-begin
+@findex field-name-end
+@findex field-value
+@findex field-end
+When printing a structure, GDB annotates it as follows:
+
+@example
+^Z^Zfield-begin @var{value-flags}
+@var{field-name}
+^Z^Zfield-name-end
+@var{separator-string}
+^Z^Zfield-value
+@var{the-value}
+^Z^Zfield-end
+@end example
+
+where @var{field-name} is the name of the field, @var{separator-string}
+is text which separates the name from the value for the user's benefit
+(such as @samp{=}), and @var{value-flags} and @var{the-value} have the
+same meanings as in a @code{value-history-begin} annotation.
+
+When printing an array, GDB annotates it as follows:
+
+@example
+^Z^Zarray-section-begin @var{array-index} @var{value-flags}
+@end example
+
+where @var{array-index} is the index of the first element being
+annotated and @var{value-flags} has the same meaning as in a
+@code{value-history-begin} annotation. This is followed by any number
+of elements, where is element can be either a single element:
+
+@findex elt
+@example
+@samp{,} @var{whitespace} ; @r{omitted for the first element}
+@var{the-value}
+^Z^Zelt
+@end example
+
+or a repeated element
+
+@findex elt-rep
+@findex elt-rep-end
+@example
+@samp{,} @var{whitespace} ; @r{omitted for the first element}
+@var{the-value}
+^Z^Zelt-rep @var{number-of-repititions}
+@var{repetition-string}
+^Z^Zelt-rep-end
+@end example
+
+In both cases, @var{the-value} is the output for the value of the
+element and @var{whitespace} can contain spaces, tabs, and newlines. In
+the repeated case, @var{number-of-repititons} is the number of
+consecutive array elements which contain that value, and
+@var{repetition-string} is a string which is designed to convey to the
+user that repitition is being depicted.
+
+@findex array-section-end
+Once all the array elements have been output, the array annotation is
+ended with
+
+@example
+^Z^Zarray-section-end
+@end example
+
+@node Frames
+@chapter Frames
+
+Whenever GDB prints a frame, it annotates it. For example, this applies
+to frames printed when GDB stops, output from commands such as
+@code{backtrace} or @code{up}, etc.
+
+@findex frame-begin
+The frame annotation begins with
+
+@example
+^Z^Zframe-begin @var{level} @var{address}
+@var{level-string}
+@end example
+
+where @var{level} is the number of the frame (0 is the innermost frame,
+and other frames have positive numbers), @var{address} is the address of
+the code executing in that frame, and @var{level-string} is a string
+designed to convey the level to the user. The frame ends with
+
+@findex frame-end
+@example
+^Z^Zframe-end
+@end example
+
+Between these annotations is the main body of the frame, which can
+consist of
+
+@itemize @bullet
+@item
+@findex function-call
+@example
+^Z^Zfunction-call
+@var{function-call-string}
+@end example
+
+where @var{function-call-string} is text designed to convey to the user
+that this frame is associated with a function call made by GDB to a
+function in the program being debugged.
+
+@item
+@findex signal-handler-caller
+@example
+^Z^Zsignal-handler-caller
+@var{signal-handler-caller-string}
+@end example
+
+where @var{signal-handler-caller-string} is text designed to convey to
+the user that this frame is associated with whatever mechanism is used
+by this operating system to call a signal handler (it is the frame which
+calls the signal handler, not the frame for the signal handler itself).
+
+@item
+A normal frame.
+
+@findex frame-address
+@findex frame-address-end
+This can optionally (depending on whether this is thought of as
+interesting information for the user to see) begin with
+
+@example
+^Z^Zframe-address
+@var{address}
+^Z^Zframe-address-end
+@var{separator-string}
+@end example
+
+where @var{address} is the address executing in the frame (the same
+address as in the @code{frame-begin} annotation), and
+@var{separator-string} is a string intended to separate this address
+from what follows for the user's benefit.
+
+@findex frame-function-name
+@findex frame-args
+Then comes
+
+@example
+^Z^Zframe-function-name
+@var{function-name}
+^Z^Zframe-args
+@var{arguments}
+@end example
+
+where @var{function-name} is the name of the function executing in the
+frame, or @samp{??} if not known, and @var{arguments} are the arguments
+to the frame, with parentheses around them (each argument is annotated
+individually as well @pxref{Values}).
+
+@findex frame-source-begin
+@findex frame-source-file
+@findex frame-source-file-end
+@findex frame-source-line
+@findex frame-source-end
+If source information is available, a reference to it is then printed:
+
+@example
+^Z^Zframe-source-begin
+@var{source-intro-string}
+^Z^Zframe-source-file
+@var{filename}
+^Z^Zframe-source-file-end
+:
+^Z^Zframe-source-line
+@var{line-number}
+^Z^Zframe-source-end
+@end example
+
+where @var{source-intro-string} separates for the user's benefit the
+reference from the text which precedes it, @var{filename} is the name of
+the source file, and @var{line-number} is the line number within that
+file (the first line is line 1).
+
+@findex frame-where
+If GDB prints some information about where the frame is from (which
+library, which load segment, etc.; currently only done on the RS/6000),
+it is annotated with
+
+@example
+^Z^Zframe-where
+@var{information}
+@end example
+
+Then, if source is to actually be displayed for this frame (for example,
+this is not true for output from the @code{backtrace} command), then a
+@code{source} annotation (@pxref{Source}) is displayed. Unlike most
+annotations, this is output instead of the normal text which would be
+output, not in addition.
+@end itemize
+
+@node Displays
+@chapter Displays
+
+@findex display-begin
+@findex display-number-end
+@findex display-format
+@findex display-expression
+@findex display-expression-end
+@findex display-value
+@findex display-end
+When GDB is told to display something using the @code{display} command,
+the results of the display are annotated:
+
+@example
+^Z^Zdisplay-begin
+@var{number}
+^Z^Zdisplay-number-end
+@var{number-separator}
+^Z^Zdisplay-format
+@var{format}
+^Z^Zdisplay-expression
+@var{expression}
+^Z^Zdisplay-expression-end
+@var{expression-separator}
+^Z^Zdisplay-value
+@var{value}
+^Z^Zdisplay-end
+@end example
+
+where @var{number} is the number of the display, @var{number-separator}
+is intended to separate the number from what follows for the user,
+@var{format} includes information such as the size, format, or other
+information about how the value is being displayed, @var{expression} is
+the expression being displayed, @var{expression-separator} is intended
+to separate the expression from the text that follows for the user,
+and @var{value} is the actual value being displayed.
+
+@node Prompting
+@chapter Annotation for GDB Input
+
+When GDB prompts for input, it annotates this fact so it is possible
+to know when to send output, when the output from a given command is
+over, etc.
+
+Different kinds of input each have a different @dfn{input type}. Each
+input type has three annotations: a @code{pre-} annotation, which
+denotes the beginning of any prompt which is being output, a plain
+annotation, which denotes the end of the prompt, and then a @code{post-}
+annotation which denotes the end of any echo which may (or may not) be
+associated with the input. For example, the @code{prompt} input type
+features the following annotations:
+
+@example
+^Z^Zpre-prompt
+^Z^Zprompt
+^Z^Zpost-prompt
+@end example
+
+The input types are
+
+@table @code
+@findex pre-prompt
+@findex prompt
+@findex post-prompt
+@item prompt
+When GDB is prompting for a command (the main GDB prompt).
+
+@findex pre-commands
+@findex commands
+@findex post-commands
+@item commands
+When GDB prompts for a set of commands, like in the @code{commands}
+command. The annotations are repeated for each command which is input.
+
+@findex pre-overload-choice
+@findex overload-choice
+@findex post-overload-choice
+@item overload-choice
+When GDB wants the user to select between various overloaded functions.
+
+@findex pre-query
+@findex query
+@findex post-query
+@item query
+When GDB wants the user to confirm a potentially dangerous operation.
+
+@findex pre-prompt-for-continue
+@findex prompt-for-continue
+@findex post-prompt-for-continue
+@item prompt-for-continue
+When GDB is asking the user to press return to continue. Note: Don't
+expect this to work well; instead use @code{set height 0} to disable
+prompting. This is because the counting of lines is buggy in the
+presence of annotations.
+@end table
+
+@node Errors
+@chapter Errors
+
+@findex quit
+@example
+^Z^Zquit
+@end example
+
+This annotation occurs right before GDB responds to an interrupt.
+
+@findex error
+@example
+^Z^Zerror
+@end example
+
+This annotation occurs right before GDB responds to an error.
+
+Quit and error annotations indicate that any annotations which GDB was
+in the middle of may end abruptly. For example, if a
+@code{value-history-begin} annotation is followed by a @code{error}, one
+cannot expect to receive the matching @code{value-history-end}. One
+cannot expect not to receive it either, however; an error annotation
+does not necessarily mean that GDB is immediately returning all the way
+to the top level.
+
+@findex error-begin
+A quit or error annotation may be preceded by
+
+@example
+^Z^Zerror-begin
+@end example
+
+Any output between that and the quit or error annotation is the error
+message.
+
+Warning messages are not yet annotated.
+@c If we want to change that, need to fix warning(), type_error(),
+@c range_error(), and possibly other places.
+
+@node Breakpoint Info
+@chapter Information on Breakpoints
+
+The output from the @code{info breakpoints} command is annotated as follows:
+
+@findex breakpoints-headers
+@findex breakpoints-table
+@example
+^Z^Zbreakpoints-headers
+@var{header-entry}
+^Z^Zbreakpoints-table
+@end example
+
+where @var{header-entry} has the same syntax as an entry (see below) but
+instead of containing data, it contains strings which are intended to
+convey the meaning of each field to the user. This is followed by any
+number of entries. If a field does not apply for this entry, it is
+omitted. Fields may contain trailing whitespace. Each entry consists
+of:
+
+@findex record
+@findex field
+@example
+^Z^Zrecord
+^Z^Zfield 0
+@var{number}
+^Z^Zfield 1
+@var{type}
+^Z^Zfield 2
+@var{disposition}
+^Z^Zfield 3
+@var{enable}
+^Z^Zfield 4
+@var{address}
+^Z^Zfield 5
+@var{what}
+^Z^Zfield 6
+@var{frame}
+^Z^Zfield 7
+@var{condition}
+^Z^Zfield 8
+@var{ignore-count}
+^Z^Zfield 9
+@var{commands}
+@end example
+
+The output ends with
+
+@findex breakpoints-table-end
+@example
+^Z^Zbreakpoints-table-end
+@end example
+
+@node Invalidation
+@chapter Invalidation Notices
+
+The following annotations say that certain pieces of state may have
+changed.
+
+@table @code
+@findex frames-invalid
+@item ^Z^Zframes-invalid
+
+The frames (for example, output from the @code{backtrace} command) may
+have changed.
+
+@findex breakpoints-invalid
+@item ^Z^Zbreakpoints-invalid
+
+The breakpoints may have changed. For example, the user just added or
+deleted a breakpoint.
+@end table
+
+@node Running
+@chapter Running the Program
+
+@findex starting
+@findex stopping
+When the program starts executing due to a GDB command such as
+@code{step} or @code{continue},
+
+@example
+^Z^Zstarting
+@end example
+
+is output. When the program stops,
+
+@example
+^Z^Zstopped
+@end example
+
+is output. Before the @code{stopped} annotation, a variety of
+annotations describe how the program stopped.
+
+@table @code
+@findex exited
+@item ^Z^Zexited @var{exit-status}
+The program exited, and @var{exit-status} is the exit status (zero for
+successful exit, otherwise nonzero).
+
+@findex signalled
+@findex signal-name
+@findex signal-name-end
+@findex signal-string
+@findex signal-string-end
+@item ^Z^Zsignalled
+The program exited with a signal. After the @code{^Z^Zsignalled}, the
+annotation continues:
+
+@example
+@var{intro-text}
+^Z^Zsignal-name
+@var{name}
+^Z^Zsignal-name-end
+@var{middle-text}
+^Z^Zsignal-string
+@var{string}
+^Z^Zsignal-string-end
+@var{end-text}
+@end example
+
+where @var{name} is the name of the signal, such as @code{SIGILL} or
+@code{SIGSEGV}, and @var{string} is the explanation of the signal, such
+as @code{Illegal Instruction} or @code{Segmentation fault}.
+@var{intro-text}, @var{middle-text}, and @var{end-text} are for the
+user's benefit and have no particular format.
+
+@findex signal
+@item ^Z^Zsignal
+The syntax of this annotation is just like @code{signalled}, but GDB is
+just saying that the program received the signal, not that it was
+terminated with it.
+
+@findex breakpoint
+@item ^Z^Zbreakpoint @var{number}
+The program hit breakpoint number @var{number}.
+
+@findex watchpoint
+@item ^Z^Zwatchpoint @var{number}
+The program hit watchpoint number @var{number}.
+@end table
+
+@node Source
+@chapter Displaying Source
+
+@findex source
+The following annotation is used instead of displaying source code:
+
+@example
+^Z^Zsource @var{filename}:@var{line}:@var{character}:@var{middle}:@var{addr}
+@end example
+
+where @var{filename} is an absolute file name indicating which source
+file, @var{line} is the line number within that file (where 1 is the
+first line in the file), @var{character} is the character position
+within the file (where 0 is the first character in the file) (for most
+debug formats this will necessarily point to the beginning of a line),
+@var{middle} is @samp{middle} if @var{addr} is in the middle of the
+line, or @samp{beg} if @var{addr} is at the beginning of the line, and
+@var{addr} is the address in the target program associated with the
+source which is being displayed.
+
+@node TODO
+@chapter Annotations We Might Want in the Future
+
+@format
+ - target-invalid
+ the target might have changed (registers, heap contents, or
+ execution status). For performance, we might eventually want
+ to hit `registers-invalid' and `all-registers-invalid' with
+ greater precision
+
+ - systematic annotation for set/show parameters (including
+ invalidation notices).
+
+ - similarly, `info' returns a list of candidates for invalidation
+ notices.
+@end format
+
+@node Index
+@unnumbered Index
+
+@printindex fn
+
+@bye
diff --git a/gnu/usr.bin/gdb/doc/gdb-cfg.texi b/gnu/usr.bin/gdb/doc/gdb-cfg.texi
new file mode 100644
index 0000000..ec64da1
--- /dev/null
+++ b/gnu/usr.bin/gdb/doc/gdb-cfg.texi
@@ -0,0 +1,117 @@
+@c GDB MANUAL configuration file.
+@c Copyright (c) 1993 Free Software Foundation, Inc.
+@c
+@c NOTE: While the GDB manual is configurable (by changing these
+@c switches), its configuration is ***NOT*** automatically tied in to
+@c source configuration---because the authors expect that, save in
+@c unusual cases, the most inclusive form of the manual is appropriate
+@c no matter how the program itself is configured.
+@c
+@c The only automatically-varying variable is the GDB version number,
+@c which the Makefile rewrites based on the VERSION variable from
+@c `../Makefile.in'.
+@c
+@c GDB version number is recorded in the variable GDBVN
+@include GDBvn.texi
+@c
+@c ----------------------------------------------------------------------
+@c PLATFORM FLAGS:
+@set GENERIC
+@c
+@c Hitachi H8/300 target:
+@set H8
+@c Hitachi H8/300 target ONLY:
+@clear H8EXCLUSIVE
+@c
+@c remote MIPS target:
+@set MIPS
+@c
+@c SPARC target:
+@set SPARC
+@c
+@c AMD 29000 target:
+@set AMD29K
+@c
+@c Intel 960 target:
+@set I960
+@c
+@c Tandem ST2000 (phone switch) target:
+@set ST2000
+@c
+@c Zilog 8000 target:
+@set Z8K
+@c
+@c Lucid "Energize" environment:
+@clear LUCID
+@c
+@c Wind River Systems VxWorks environment:
+@set VXWORKS
+@c
+@c ----------------------------------------------------------------------
+@c DOC FEATURE FLAGS:
+@c
+@c Include change-from-old?
+@set NOVEL
+@c
+@c Bare-board target?
+@clear BARETARGET
+@c
+@c Restrict languages discussed to C?
+@c This is backward. As time permits, change this to language-specific
+@c switches for what to include.
+@clear CONLY
+@c Discuss Fortran?
+@set FORTRAN
+@c
+@c Discuss Modula 2?
+@set MOD2
+@c
+@c Specifically for host machine running DOS?
+@clear DOSHOST
+@c
+@c Talk about CPU simulator targets?
+@set SIMS
+@c
+@c Is manual stand-alone, or part of an agglomeration, with overall GPL?
+@clear AGGLOMERATION
+@c
+@c Remote serial line settings of interest?
+@set SERIAL
+@c
+@c Discuss features requiring Posix or similar OS environment?
+@set POSIX
+@c
+@c Discuss remote serial debugging stub?
+@set REMOTESTUB
+@c
+@c Discuss gdbserver?
+@set GDBSERVER
+@c
+@c Refrain from discussing how to configure sw and format doc?
+@clear PRECONFIGURED
+@c
+@c Refrain from referring to unfree publications?
+@set FSFDOC
+@c
+@c ----------------------------------------------------------------------
+@c STRINGS:
+@c
+@c Name of GDB program. Used also for (gdb) prompt string.
+@set GDBP gdb
+@c
+@c Name of GDB product. Used in running text.
+@set GDBN GDB
+@c
+@c Name of GDB initialization file.
+@set GDBINIT .gdbinit
+@c
+@c Name of host. Should not be used in generic configs, but generic
+@c value may catch some flubs.
+@set HOST machine specific
+@c
+@c Name of GCC product
+@set NGCC GCC
+@c
+@c Name of GCC program
+@set GCC gcc
+
diff --git a/gnu/usr.bin/gdb/doc/gdb.texinfo b/gnu/usr.bin/gdb/doc/gdb.texinfo
new file mode 100644
index 0000000..5db9253
--- /dev/null
+++ b/gnu/usr.bin/gdb/doc/gdb.texinfo
@@ -0,0 +1,8921 @@
+\input texinfo @c -*-texinfo-*-
+@c Copyright 1988 1989 1990 1991 1992 1993 1994 Free Software Foundation, Inc.
+@c
+@c %**start of header
+@c makeinfo ignores cmds prev to setfilename, so its arg cannot make use
+@c of @set vars. However, you can override filename with makeinfo -o.
+@setfilename gdb.info
+@c
+@include gdb-cfg.texi
+@c
+@ifset GENERIC
+@settitle Debugging with @value{GDBN}
+@end ifset
+@ifclear GENERIC
+@settitle Debugging with @value{GDBN} (@value{TARGET})
+@end ifclear
+@setchapternewpage odd
+@c %**end of header
+
+@iftex
+@c @smallbook
+@c @cropmarks
+@end iftex
+
+@finalout
+@syncodeindex ky cp
+
+@c readline appendices use @vindex
+@syncodeindex vr cp
+
+@c !!set GDB manual's edition---not the same as GDB version!
+@set EDITION 4.12
+
+@c !!set GDB manual's revision date
+@set DATE January 1994
+
+@c GDB CHANGELOG CONSULTED BETWEEN:
+@c Fri Oct 11 23:27:06 1991 John Gilmore (gnu at cygnus.com)
+@c Sat Dec 22 02:51:40 1990 John Gilmore (gnu at cygint)
+
+@c THIS MANUAL REQUIRES TEXINFO-2 macros and info-makers to format properly.
+
+@ifinfo
+@c This is a dir.info fragment to support semi-automated addition of
+@c manuals to an info tree. zoo@cygnus.com is developing this facility.
+@format
+START-INFO-DIR-ENTRY
+* Gdb: (gdb). The GNU debugger.
+END-INFO-DIR-ENTRY
+@end format
+@end ifinfo
+@c
+@c
+@ifinfo
+This file documents the GNU debugger @value{GDBN}.
+
+
+This is Edition @value{EDITION}, @value{DATE},
+of @cite{Debugging with @value{GDBN}: the GNU Source-Level Debugger}
+for GDB Version @value{GDBVN}.
+
+Copyright (C) 1988, '89, '90, '91, '92, '93 Free Software Foundation, Inc.
+
+Permission is granted to make and distribute verbatim copies of
+this manual provided the copyright notice and this permission notice
+are preserved on all copies.
+
+@ignore
+Permission is granted to process this file through TeX and print the
+results, provided the printed document carries copying permission
+notice identical to this one except for the removal of this paragraph
+(this paragraph not being relevant to the printed manual).
+
+@end ignore
+Permission is granted to copy and distribute modified versions of this
+manual under the conditions for verbatim copying, provided also that the
+entire resulting derived work is distributed under the terms of a
+permission notice identical to this one.
+
+Permission is granted to copy and distribute translations of this manual
+into another language, under the above conditions for modified versions.
+@end ifinfo
+
+@titlepage
+@title Debugging with @value{GDBN}
+@subtitle The GNU Source-Level Debugger
+@ifclear GENERIC
+@subtitle (@value{TARGET})
+@end ifclear
+@sp 1
+@subtitle Edition @value{EDITION}, for @value{GDBN} version @value{GDBVN}
+@subtitle @value{DATE}
+@author Richard M. Stallman and Roland H. Pesch
+@page
+@tex
+{\parskip=0pt
+\hfill (Send bugs and comments on @value{GDBN} to bug-gdb\@prep.ai.mit.edu.)\par
+\hfill {\it Debugging with @value{GDBN}}\par
+\hfill \TeX{}info \texinfoversion\par
+\hfill pesch\@cygnus.com\par
+}
+@end tex
+
+@vskip 0pt plus 1filll
+Copyright @copyright{} 1988, '89, '90, '91, '92, '93 Free Software
+Foundation, Inc.
+@sp 2
+Published by the Free Software Foundation @*
+675 Massachusetts Avenue, @*
+Cambridge, MA 02139 USA @*
+Printed copies are available for $20 each. @*
+ISBN 1-882114-11-6 @*
+
+Permission is granted to make and distribute verbatim copies of
+this manual provided the copyright notice and this permission notice
+are preserved on all copies.
+
+Permission is granted to copy and distribute modified versions of this
+manual under the conditions for verbatim copying, provided also that the
+entire resulting derived work is distributed under the terms of a
+permission notice identical to this one.
+
+Permission is granted to copy and distribute translations of this manual
+into another language, under the above conditions for modified versions.
+@end titlepage
+@page
+
+@ifinfo
+@node Top
+@top Debugging with @value{GDBN}
+
+This file describes @value{GDBN}, the GNU symbolic debugger.
+
+This is Edition @value{EDITION}, @value{DATE}, for GDB Version @value{GDBVN}.
+
+@menu
+* Summary:: Summary of @value{GDBN}
+@ifset NOVEL
+* New Features:: New features since GDB version 3.5
+@end ifset
+@ifclear BARETARGET
+* Sample Session:: A sample @value{GDBN} session
+@end ifclear
+
+* Invocation:: Getting in and out of @value{GDBN}
+* Commands:: @value{GDBN} commands
+* Running:: Running programs under @value{GDBN}
+* Stopping:: Stopping and continuing
+* Stack:: Examining the stack
+* Source:: Examining source files
+* Data:: Examining data
+@ifclear CONLY
+* Languages:: Using @value{GDBN} with different languages
+@end ifclear
+@ifset CONLY
+* C:: C language support
+@end ifset
+@c remnant makeinfo bug, blank line needed after two end-ifs?
+
+* Symbols:: Examining the symbol table
+* Altering:: Altering execution
+* GDB Files:: @value{GDBN} files
+* Targets:: Specifying a debugging target
+* Controlling GDB:: Controlling @value{GDBN}
+* Sequences:: Canned sequences of commands
+@ifclear DOSHOST
+* Emacs:: Using @value{GDBN} under GNU Emacs
+@end ifclear
+
+* GDB Bugs:: Reporting bugs in @value{GDBN}
+* Command Line Editing:: Facilities of the readline library
+* Using History Interactively::
+@ifset NOVEL
+* Renamed Commands::
+@end ifset
+@ifclear PRECONFIGURED
+* Formatting Documentation:: How to format and print GDB documentation
+* Installing GDB:: Installing GDB
+@end ifclear
+
+* Index:: Index
+@end menu
+@end ifinfo
+
+@node Summary
+@unnumbered Summary of @value{GDBN}
+
+The purpose of a debugger such as @value{GDBN} is to allow you to see what is
+going on ``inside'' another program while it executes---or what another
+program was doing at the moment it crashed.
+
+@value{GDBN} can do four main kinds of things (plus other things in support of
+these) to help you catch bugs in the act:
+
+@itemize @bullet
+@item
+Start your program, specifying anything that might affect its behavior.
+
+@item
+Make your program stop on specified conditions.
+
+@item
+Examine what has happened, when your program has stopped.
+
+@item
+Change things in your program, so you can experiment with correcting the
+effects of one bug and go on to learn about another.
+@end itemize
+
+@ifclear CONLY
+You can use @value{GDBN} to debug programs written in C or C++.
+@c "MOD2" used as a "miscellaneous languages" flag here.
+@c This is acceptable while there is no real doc for Chill and Pascal.
+@ifclear MOD2
+For more information, see @ref{Support,,Supported languages}.
+@end ifclear
+@ifset MOD2
+For more information, see @ref{C,,C and C++}.
+
+Support for Modula-2 and Chill is partial. For information on Modula-2,
+see @ref{Modula-2,,Modula-2}. There is no further documentation on Chill yet.
+
+Debugging Pascal programs which use sets, subranges, file variables, or nested
+functions does not currently work. @value{GDBN} does not support
+entering expressions, printing values, or similar features using Pascal syntax.
+@end ifset
+@ifset FORTRAN
+@cindex Fortran
+@value{GDBN} can be used to debug programs written in Fortran, although
+it does not yet support entering expressions, printing values, or
+similar features using Fortran syntax. It may be necessary to refer to
+some variables with a trailing underscore.
+@end ifset
+@end ifclear
+
+@menu
+* Free Software:: Freely redistributable software
+* Contributors:: Contributors to GDB
+@end menu
+
+@node Free Software
+@unnumberedsec Free software
+
+@value{GDBN} is @dfn{free software}, protected by the GNU General Public License
+(GPL). The GPL gives you the freedom to copy or adapt a licensed
+program---but every person getting a copy also gets with it the
+freedom to modify that copy (which means that they must get access to
+the source code), and the freedom to distribute further copies.
+Typical software companies use copyrights to limit your freedoms; the
+Free Software Foundation uses the GPL to preserve these freedoms.
+
+Fundamentally, the General Public License is a license which says that
+you have these freedoms and that you cannot take these freedoms away
+from anyone else.
+
+@node Contributors
+@unnumberedsec Contributors to GDB
+
+Richard Stallman was the original author of GDB, and of many other GNU
+programs. Many others have contributed to its development. This
+section attempts to credit major contributors. One of the virtues of
+free software is that everyone is free to contribute to it; with
+regret, we cannot actually acknowledge everyone here. The file
+@file{ChangeLog} in the GDB distribution approximates a blow-by-blow
+account.
+
+Changes much prior to version 2.0 are lost in the mists of time.
+
+@quotation
+@emph{Plea:} Additions to this section are particularly welcome. If you
+or your friends (or enemies, to be evenhanded) have been unfairly
+omitted from this list, we would like to add your names!
+@end quotation
+
+So that they may not regard their long labor as thankless, we
+particularly thank those who shepherded GDB through major releases:
+Fred Fish (releases 4.12, 4.11, 4.10, and 4.9),
+Stu Grossman and John Gilmore (releases 4.8, 4.7, 4.6, 4.5, and 4.4),
+John Gilmore (releases 4.3, 4.2, 4.1, 4.0, and 3.9);
+Jim Kingdon (releases 3.5, 3.4, and 3.3);
+and Randy Smith (releases 3.2, 3.1, and 3.0).
+As major maintainer of GDB for some period, each
+contributed significantly to the structure, stability, and capabilities
+of the entire debugger.
+
+Richard Stallman, assisted at various times by Peter TerMaat, Chris
+Hanson, and Richard Mlynarik, handled releases through 2.8.
+
+@ifclear CONLY
+Michael Tiemann is the author of most of the GNU C++ support in GDB,
+with significant additional contributions from Per Bothner. James
+Clark wrote the GNU C++ demangler. Early work on C++ was by Peter
+TerMaat (who also did much general update work leading to release 3.0).
+@end ifclear
+
+GDB 4 uses the BFD subroutine library to examine multiple
+object-file formats; BFD was a joint project of David V.
+Henkel-Wallace, Rich Pixley, Steve Chamberlain, and John Gilmore.
+
+David Johnson wrote the original COFF support; Pace Willison did
+the original support for encapsulated COFF.
+
+Adam de Boor and Bradley Davis contributed the ISI Optimum V support.
+Per Bothner, Noboyuki Hikichi, and Alessandro Forin contributed MIPS
+support.
+Jean-Daniel Fekete contributed Sun 386i support.
+Chris Hanson improved the HP9000 support.
+Noboyuki Hikichi and Tomoyuki Hasei contributed Sony/News OS 3 support.
+David Johnson contributed Encore Umax support.
+Jyrki Kuoppala contributed Altos 3068 support.
+Jeff Law contributed HP PA and SOM support.
+Keith Packard contributed NS32K support.
+Doug Rabson contributed Acorn Risc Machine support.
+Bob Rusk contributed Harris Nighthawk CX-UX support.
+Chris Smith contributed Convex support (and Fortran debugging).
+Jonathan Stone contributed Pyramid support.
+Michael Tiemann contributed SPARC support.
+Tim Tucker contributed support for the Gould NP1 and Gould Powernode.
+Pace Willison contributed Intel 386 support.
+Jay Vosburgh contributed Symmetry support.
+
+Rich Schaefer and Peter Schauer helped with support of SunOS shared
+libraries.
+
+Jay Fenlason and Roland McGrath ensured that GDB and GAS agree about
+several machine instruction sets.
+
+Patrick Duval, Ted Goldstein, Vikram Koka and Glenn Engel helped
+develop remote debugging. Intel Corporation and Wind River Systems
+contributed remote debugging modules for their products.
+
+Brian Fox is the author of the readline libraries providing
+command-line editing and command history.
+
+Andrew Beers of SUNY Buffalo wrote the language-switching code,
+@ifset MOD2
+the Modula-2 support,
+@end ifset
+and contributed the Languages chapter of this manual.
+
+Fred Fish wrote most of the support for Unix System Vr4.
+@ifclear CONLY
+He also enhanced the command-completion support to cover C++ overloaded
+symbols.
+@end ifclear
+
+Hitachi America, Ltd. sponsored the support for Hitachi microprocessors.
+
+Kung Hsu, Jeff Law, and Rick Sladkey added support for hardware
+watchpoints.
+
+Stu Grossman wrote gdbserver.
+
+Jim Kingdon, Peter Schauer, Ian Taylor, and Stu Grossman made
+nearly innumerable bug fixes and cleanups throughout GDB.
+
+@ifset NOVEL
+@node New Features
+@unnumbered New Features since GDB Version 3.5
+
+@table @emph
+@item Targets
+Using the new command @code{target}, you can select at runtime whether
+you are debugging local files, local processes, standalone systems over
+a serial port, or realtime systems over a TCP/IP connection. The
+command @code{load} can download programs into a remote system. Serial
+stubs are available for Motorola 680x0, Intel 80386, and Sparc remote
+systems; GDB also supports debugging realtime processes running under
+VxWorks, using SunRPC Remote Procedure Calls over TCP/IP to talk to a
+debugger stub on the target system. Internally, GDB now uses a function
+vector to mediate access to different targets; if you need to add your
+own support for a remote protocol, this makes it much easier.
+
+@item Watchpoints
+GDB now sports watchpoints as well as breakpoints. You can use a
+watchpoint to stop execution whenever the value of an expression
+changes, without having to predict a particular place in your program
+where this may happen.
+
+@item Wide Output
+Commands that issue wide output now insert newlines at places designed
+to make the output more readable.
+
+@item Object Code Formats
+GDB uses a new library called the Binary File Descriptor (BFD) Library
+to permit it to switch dynamically, without reconfiguration or
+recompilation, between different object-file formats. Formats currently
+supported are COFF, ELF, a.out, Intel 960 b.out, MIPS ECOFF, HPPA SOM
+(with stabs debugging), and S-records; files may be read as .o files,
+archive libraries, or core dumps. BFD is available as a subroutine
+library so that other programs may take advantage of it, and the other
+GNU binary utilities are being converted to use it.
+
+@item Configuration and Ports
+Compile-time configuration (to select a particular architecture and
+operating system) is much easier. The script @code{configure} now
+allows you to configure GDB as either a native debugger or a
+cross-debugger. @xref{Installing GDB}, for details on how to
+configure.
+
+@item Interaction
+The user interface to the GDB control variables is simpler,
+and is consolidated in two commands, @code{set} and @code{show}. Output
+lines are now broken at readable places, rather than overflowing onto
+the next line. You can suppress output of machine-level addresses,
+displaying only source language information.
+
+@item C++
+GDB now supports C++ multiple inheritance (if used with a GCC
+version 2 compiler), and also has limited support for C++ exception
+handling, with the commands @code{catch} and @code{info catch}: GDB
+can break when an exception is raised, before the stack is peeled back
+to the exception handler's context.
+
+@ifset MOD2
+@item Modula-2
+GDB now has preliminary support for the GNU Modula-2 compiler, currently
+under development at the State University of New York at Buffalo.
+Coordinated development of both GDB and the GNU Modula-2 compiler will
+continue. Other Modula-2 compilers are currently not supported, and
+attempting to debug programs compiled with them will likely result in an
+error as the symbol table of the executable is read in.
+@end ifset
+
+@item Command Rationalization
+Many GDB commands have been renamed to make them easier to remember
+and use. In particular, the subcommands of @code{info} and
+@code{show}/@code{set} are grouped to make the former refer to the state
+of your program, and the latter refer to the state of GDB itself.
+@xref{Renamed Commands}, for details on what commands were renamed.
+
+@item Shared Libraries
+GDB 4 can debug programs and core files that use SunOS, SVR4, or IBM RS/6000
+shared libraries.
+
+@item Threads
+On some systems, GDB 4 has facilities to debug multi-thread programs.
+
+@item Reference Card
+GDB 4 has a reference card. @xref{Formatting Documentation,,Formatting
+the Documentation}, for instructions about how to print it.
+@end table
+@end ifset
+
+@ifclear BARETARGET
+@node Sample Session
+@chapter A Sample @value{GDBN} Session
+
+You can use this manual at your leisure to read all about @value{GDBN}.
+However, a handful of commands are enough to get started using the
+debugger. This chapter illustrates those commands.
+
+@iftex
+In this sample session, we emphasize user input like this: @b{input},
+to make it easier to pick out from the surrounding output.
+@end iftex
+
+@c FIXME: this example may not be appropriate for some configs, where
+@c FIXME...primary interest is in remote use.
+
+One of the preliminary versions of GNU @code{m4} (a generic macro
+processor) exhibits the following bug: sometimes, when we change its
+quote strings from the default, the commands used to capture one macro
+definition within another stop working. In the following short @code{m4}
+session, we define a macro @code{foo} which expands to @code{0000}; we
+then use the @code{m4} built-in @code{defn} to define @code{bar} as the
+same thing. However, when we change the open quote string to
+@code{<QUOTE>} and the close quote string to @code{<UNQUOTE>}, the same
+procedure fails to define a new synonym @code{baz}:
+
+@smallexample
+$ @b{cd gnu/m4}
+$ @b{./m4}
+@b{define(foo,0000)}
+
+@b{foo}
+0000
+@b{define(bar,defn(`foo'))}
+
+@b{bar}
+0000
+@b{changequote(<QUOTE>,<UNQUOTE>)}
+
+@b{define(baz,defn(<QUOTE>foo<UNQUOTE>))}
+@b{baz}
+@b{C-d}
+m4: End of input: 0: fatal error: EOF in string
+@end smallexample
+
+@noindent
+Let us use @value{GDBN} to try to see what is going on.
+
+@smallexample
+$ @b{@value{GDBP} m4}
+@c FIXME: this falsifies the exact text played out, to permit smallbook
+@c FIXME... format to come out better.
+GDB is free software and you are welcome to distribute copies
+ of it under certain conditions; type "show copying" to see
+ the conditions.
+There is absolutely no warranty for GDB; type "show warranty"
+ for details.
+GDB @value{GDBVN}, Copyright 1993 Free Software Foundation, Inc...
+(@value{GDBP})
+@end smallexample
+
+@noindent
+@value{GDBN} reads only enough symbol data to know where to find the
+rest when needed; as a result, the first prompt comes up very quickly.
+We now tell @value{GDBN} to use a narrower display width than usual, so
+that examples fit in this manual.
+
+@smallexample
+(@value{GDBP}) @b{set width 70}
+@end smallexample
+
+@noindent
+We need to see how the @code{m4} built-in @code{changequote} works.
+Having looked at the source, we know the relevant subroutine is
+@code{m4_changequote}, so we set a breakpoint there with the @value{GDBN}
+@code{break} command.
+
+@smallexample
+(@value{GDBP}) @b{break m4_changequote}
+Breakpoint 1 at 0x62f4: file builtin.c, line 879.
+@end smallexample
+
+@noindent
+Using the @code{run} command, we start @code{m4} running under @value{GDBN}
+control; as long as control does not reach the @code{m4_changequote}
+subroutine, the program runs as usual:
+
+@smallexample
+(@value{GDBP}) @b{run}
+Starting program: /work/Editorial/gdb/gnu/m4/m4
+@b{define(foo,0000)}
+
+@b{foo}
+0000
+@end smallexample
+
+@noindent
+To trigger the breakpoint, we call @code{changequote}. @value{GDBN}
+suspends execution of @code{m4}, displaying information about the
+context where it stops.
+
+@smallexample
+@b{changequote(<QUOTE>,<UNQUOTE>)}
+
+Breakpoint 1, m4_changequote (argc=3, argv=0x33c70)
+ at builtin.c:879
+879 if (bad_argc(TOKEN_DATA_TEXT(argv[0]),argc,1,3))
+@end smallexample
+
+@noindent
+Now we use the command @code{n} (@code{next}) to advance execution to
+the next line of the current function.
+
+@smallexample
+(@value{GDBP}) @b{n}
+882 set_quotes((argc >= 2) ? TOKEN_DATA_TEXT(argv[1])\
+ : nil,
+@end smallexample
+
+@noindent
+@code{set_quotes} looks like a promising subroutine. We can go into it
+by using the command @code{s} (@code{step}) instead of @code{next}.
+@code{step} goes to the next line to be executed in @emph{any}
+subroutine, so it steps into @code{set_quotes}.
+
+@smallexample
+(@value{GDBP}) @b{s}
+set_quotes (lq=0x34c78 "<QUOTE>", rq=0x34c88 "<UNQUOTE>")
+ at input.c:530
+530 if (lquote != def_lquote)
+@end smallexample
+
+@noindent
+The display that shows the subroutine where @code{m4} is now
+suspended (and its arguments) is called a stack frame display. It
+shows a summary of the stack. We can use the @code{backtrace}
+command (which can also be spelled @code{bt}), to see where we are
+in the stack as a whole: the @code{backtrace} command displays a
+stack frame for each active subroutine.
+
+@smallexample
+(@value{GDBP}) @b{bt}
+#0 set_quotes (lq=0x34c78 "<QUOTE>", rq=0x34c88 "<UNQUOTE>")
+ at input.c:530
+#1 0x6344 in m4_changequote (argc=3, argv=0x33c70)
+ at builtin.c:882
+#2 0x8174 in expand_macro (sym=0x33320) at macro.c:242
+#3 0x7a88 in expand_token (obs=0x0, t=209696, td=0xf7fffa30)
+ at macro.c:71
+#4 0x79dc in expand_input () at macro.c:40
+#5 0x2930 in main (argc=0, argv=0xf7fffb20) at m4.c:195
+@end smallexample
+
+@noindent
+We step through a few more lines to see what happens. The first two
+times, we can use @samp{s}; the next two times we use @code{n} to avoid
+falling into the @code{xstrdup} subroutine.
+
+@smallexample
+(@value{GDBP}) @b{s}
+0x3b5c 532 if (rquote != def_rquote)
+(@value{GDBP}) @b{s}
+0x3b80 535 lquote = (lq == nil || *lq == '\0') ? \
+def_lquote : xstrdup(lq);
+(@value{GDBP}) @b{n}
+536 rquote = (rq == nil || *rq == '\0') ? def_rquote\
+ : xstrdup(rq);
+(@value{GDBP}) @b{n}
+538 len_lquote = strlen(rquote);
+@end smallexample
+
+@noindent
+The last line displayed looks a little odd; we can examine the variables
+@code{lquote} and @code{rquote} to see if they are in fact the new left
+and right quotes we specified. We use the command @code{p}
+(@code{print}) to see their values.
+
+@smallexample
+(@value{GDBP}) @b{p lquote}
+$1 = 0x35d40 "<QUOTE>"
+(@value{GDBP}) @b{p rquote}
+$2 = 0x35d50 "<UNQUOTE>"
+@end smallexample
+
+@noindent
+@code{lquote} and @code{rquote} are indeed the new left and right quotes.
+To look at some context, we can display ten lines of source
+surrounding the current line with the @code{l} (@code{list}) command.
+
+@smallexample
+(@value{GDBP}) @b{l}
+533 xfree(rquote);
+534
+535 lquote = (lq == nil || *lq == '\0') ? def_lquote\
+ : xstrdup (lq);
+536 rquote = (rq == nil || *rq == '\0') ? def_rquote\
+ : xstrdup (rq);
+537
+538 len_lquote = strlen(rquote);
+539 len_rquote = strlen(lquote);
+540 @}
+541
+542 void
+@end smallexample
+
+@noindent
+Let us step past the two lines that set @code{len_lquote} and
+@code{len_rquote}, and then examine the values of those variables.
+
+@smallexample
+(@value{GDBP}) @b{n}
+539 len_rquote = strlen(lquote);
+(@value{GDBP}) @b{n}
+540 @}
+(@value{GDBP}) @b{p len_lquote}
+$3 = 9
+(@value{GDBP}) @b{p len_rquote}
+$4 = 7
+@end smallexample
+
+@noindent
+That certainly looks wrong, assuming @code{len_lquote} and
+@code{len_rquote} are meant to be the lengths of @code{lquote} and
+@code{rquote} respectively. We can set them to better values using
+the @code{p} command, since it can print the value of
+any expression---and that expression can include subroutine calls and
+assignments.
+
+@smallexample
+(@value{GDBP}) @b{p len_lquote=strlen(lquote)}
+$5 = 7
+(@value{GDBP}) @b{p len_rquote=strlen(rquote)}
+$6 = 9
+@end smallexample
+
+@noindent
+Is that enough to fix the problem of using the new quotes with the
+@code{m4} built-in @code{defn}? We can allow @code{m4} to continue
+executing with the @code{c} (@code{continue}) command, and then try the
+example that caused trouble initially:
+
+@smallexample
+(@value{GDBP}) @b{c}
+Continuing.
+
+@b{define(baz,defn(<QUOTE>foo<UNQUOTE>))}
+
+baz
+0000
+@end smallexample
+
+@noindent
+Success! The new quotes now work just as well as the default ones. The
+problem seems to have been just the two typos defining the wrong
+lengths. We allow @code{m4} exit by giving it an EOF as input:
+
+@smallexample
+@b{C-d}
+Program exited normally.
+@end smallexample
+
+@noindent
+The message @samp{Program exited normally.} is from @value{GDBN}; it
+indicates @code{m4} has finished executing. We can end our @value{GDBN}
+session with the @value{GDBN} @code{quit} command.
+
+@smallexample
+(@value{GDBP}) @b{quit}
+@end smallexample
+@end ifclear
+
+@node Invocation
+@chapter Getting In and Out of @value{GDBN}
+
+This chapter discusses how to start @value{GDBN}, and how to get out of it.
+(The essentials: type @samp{@value{GDBP}} to start GDB, and type @kbd{quit}
+or @kbd{C-d} to exit.)
+
+@menu
+* Invoking GDB:: How to start @value{GDBN}
+* Quitting GDB:: How to quit @value{GDBN}
+* Shell Commands:: How to use shell commands inside @value{GDBN}
+@end menu
+
+@node Invoking GDB
+@section Invoking @value{GDBN}
+
+@ifset H8EXCLUSIVE
+For details on starting up @value{GDBP} as a
+remote debugger attached to a Hitachi microprocessor, see @ref{Hitachi
+Remote,,@value{GDBN} and Hitachi Microprocessors}.
+@end ifset
+
+Invoke @value{GDBN} by running the program @code{@value{GDBP}}. Once started,
+@value{GDBN} reads commands from the terminal until you tell it to exit.
+
+You can also run @code{@value{GDBP}} with a variety of arguments and options,
+to specify more of your debugging environment at the outset.
+
+@ifset GENERIC
+The command-line options described here are designed
+to cover a variety of situations; in some environments, some of these
+options may effectively be unavailable.
+@end ifset
+
+The most usual way to start @value{GDBN} is with one argument,
+specifying an executable program:
+
+@example
+@value{GDBP} @var{program}
+@end example
+
+@ifclear BARETARGET
+@noindent
+You can also start with both an executable program and a core file
+specified:
+
+@example
+@value{GDBP} @var{program} @var{core}
+@end example
+
+You can, instead, specify a process ID as a second argument, if you want
+to debug a running process:
+
+@example
+@value{GDBP} @var{program} 1234
+@end example
+
+@noindent
+would attach @value{GDBN} to process @code{1234} (unless you also have a file
+named @file{1234}; @value{GDBN} does check for a core file first).
+
+Taking advantage of the second command-line argument requires a fairly
+complete operating system; when you use @value{GDBN} as a remote debugger
+attached to a bare board, there may not be any notion of ``process'',
+and there is often no way to get a core dump.
+@end ifclear
+
+@noindent
+You can further control how @value{GDBN} starts up by using command-line
+options. @value{GDBN} itself can remind you of the options available.
+
+@noindent
+Type
+
+@example
+@value{GDBP} -help
+@end example
+
+@noindent
+to display all available options and briefly describe their use
+(@samp{@value{GDBP} -h} is a shorter equivalent).
+
+All options and command line arguments you give are processed
+in sequential order. The order makes a difference when the
+@samp{-x} option is used.
+
+
+@menu
+@ifclear GENERIC
+@ifset REMOTESTUB
+* Remote Serial:: @value{GDBN} remote serial protocol
+@end ifset
+@ifset I960
+* i960-Nindy Remote:: @value{GDBN} with a remote i960 (Nindy)
+@end ifset
+@ifset AMD29K
+* UDI29K Remote:: The UDI protocol for AMD29K
+* EB29K Remote:: The EBMON protocol for AMD29K
+@end ifset
+@ifset VXWORKS
+* VxWorks Remote:: @value{GDBN} and VxWorks
+@end ifset
+@ifset ST2000
+* ST2000 Remote:: @value{GDBN} with a Tandem ST2000
+@end ifset
+@ifset H8
+* Hitachi Remote:: @value{GDBN} and Hitachi Microprocessors
+@end ifset
+@ifset MIPS
+* MIPS Remote:: @value{GDBN} and MIPS boards
+@end ifset
+@ifset SIMS
+* Simulator:: Simulated CPU target
+@end ifset
+@end ifclear
+@c remnant makeinfo bug requires this blank line after *two* end-ifblahs:
+
+* File Options:: Choosing files
+* Mode Options:: Choosing modes
+@end menu
+
+@ifclear GENERIC
+@include remote.texi
+@end ifclear
+
+@node File Options
+@subsection Choosing files
+
+@ifclear BARETARGET
+When @value{GDBN} starts, it reads any arguments other than options as
+specifying an executable file and core file (or process ID). This is
+the same as if the arguments were specified by the @samp{-se} and
+@samp{-c} options respectively. (@value{GDBN} reads the first argument
+that does not have an associated option flag as equivalent to the
+@samp{-se} option followed by that argument; and the second argument
+that does not have an associated option flag, if any, as equivalent to
+the @samp{-c} option followed by that argument.)
+@end ifclear
+@ifset BARETARGET
+When @value{GDBN} starts, it reads any argument other than options as
+specifying an executable file. This is the same as if the argument was
+specified by the @samp{-se} option.
+@end ifset
+
+Many options have both long and short forms; both are shown in the
+following list. @value{GDBN} also recognizes the long forms if you truncate
+them, so long as enough of the option is present to be unambiguous.
+(If you prefer, you can flag option arguments with @samp{--} rather
+than @samp{-}, though we illustrate the more usual convention.)
+
+@table @code
+@item -symbols @var{file}
+@itemx -s @var{file}
+Read symbol table from file @var{file}.
+
+@item -exec @var{file}
+@itemx -e @var{file}
+Use file @var{file} as the executable file to execute when
+@ifset BARETARGET
+appropriate.
+@end ifset
+@ifclear BARETARGET
+appropriate, and for examining pure data in conjunction with a core
+dump.
+@end ifclear
+
+@item -se @var{file}
+Read symbol table from file @var{file} and use it as the executable
+file.
+
+@ifclear BARETARGET
+@item -core @var{file}
+@itemx -c @var{file}
+Use file @var{file} as a core dump to examine.
+
+@item -c @var{number}
+Connect to process ID @var{number}, as with the @code{attach} command
+(unless there is a file in core-dump format named @var{number}, in which
+case @samp{-c} specifies that file as a core dump to read).
+@end ifclear
+
+@item -command @var{file}
+@itemx -x @var{file}
+Execute @value{GDBN} commands from file @var{file}. @xref{Command
+Files,, Command files}.
+
+@item -directory @var{directory}
+@itemx -d @var{directory}
+Add @var{directory} to the path to search for source files.
+
+@ifclear BARETARGET
+@item -m
+@itemx -mapped
+@emph{Warning: this option depends on operating system facilities that are not
+supported on all systems.}@*
+If memory-mapped files are available on your system through the @code{mmap}
+system call, you can use this option
+to have @value{GDBN} write the symbols from your
+program into a reusable file in the current directory. If the program you are debugging is
+called @file{/tmp/fred}, the mapped symbol file is @file{./fred.syms}.
+Future @value{GDBN} debugging sessions notice the presence of this file,
+and can quickly map in symbol information from it, rather than reading
+the symbol table from the executable program.
+
+@c FIXME! Really host, not target?
+The @file{.syms} file is specific to the host machine where @value{GDBN}
+is run. It holds an exact image of the internal @value{GDBN} symbol
+table. It cannot be shared across multiple host platforms.
+@end ifclear
+
+@item -r
+@itemx -readnow
+Read each symbol file's entire symbol table immediately, rather than
+the default, which is to read it incrementally as it is needed.
+This makes startup slower, but makes future operations faster.
+@end table
+
+@ifclear BARETARGET
+The @code{-mapped} and @code{-readnow} options are typically combined in
+order to build a @file{.syms} file that contains complete symbol
+information. (@xref{Files,,Commands to specify files}, for information
+on @file{.syms} files.) A simple GDB invocation to do nothing but build
+a @file{.syms} file for future use is:
+
+@example
+ gdb -batch -nx -mapped -readnow programname
+@end example
+@end ifclear
+
+@node Mode Options
+@subsection Choosing modes
+
+You can run @value{GDBN} in various alternative modes---for example, in
+batch mode or quiet mode.
+
+@table @code
+@item -nx
+@itemx -n
+Do not execute commands from any initialization files (normally called
+@file{@value{GDBINIT}}). Normally, the commands in these files are
+executed after all the command options and arguments have been
+processed. @xref{Command Files,,Command files}.
+
+@item -quiet
+@itemx -q
+``Quiet''. Do not print the introductory and copyright messages. These
+messages are also suppressed in batch mode.
+
+@item -batch
+Run in batch mode. Exit with status @code{0} after processing all the
+command files specified with @samp{-x} (and all commands from
+initialization files, if not inhibited with @samp{-n}). Exit with
+nonzero status if an error occurs in executing the @value{GDBN} commands
+in the command files.
+
+Batch mode may be useful for running @value{GDBN} as a filter, for example to
+download and run a program on another computer; in order to make this
+more useful, the message
+
+@example
+Program exited normally.
+@end example
+
+@noindent
+(which is ordinarily issued whenever a program running under @value{GDBN} control
+terminates) is not issued when running in batch mode.
+
+@item -cd @var{directory}
+Run @value{GDBN} using @var{directory} as its working directory,
+instead of the current directory.
+
+@ifset LUCID
+@item -context @var{authentication}
+When the Energize programming system starts up @value{GDBN}, it uses this
+option to trigger an alternate mode of interaction.
+@var{authentication} is a pair of numeric codes that identify @value{GDBN}
+as a client in the Energize environment. Avoid this option when you run
+@value{GDBN} directly from the command line. See @ref{Energize,,Using
+@value{GDBN} with Energize} for more discussion of using @value{GDBN} with Energize.
+@end ifset
+
+@ifclear DOSHOST
+@item -fullname
+@itemx -f
+Emacs sets this option when it runs @value{GDBN} as a subprocess. It tells @value{GDBN}
+to output the full file name and line number in a standard,
+recognizable fashion each time a stack frame is displayed (which
+includes each time your program stops). This recognizable format looks
+like two @samp{\032} characters, followed by the file name, line number
+and character position separated by colons, and a newline. The
+Emacs-to-@value{GDBN} interface program uses the two @samp{\032} characters as
+a signal to display the source code for the frame.
+@end ifclear
+
+@ifset SERIAL
+@item -b @var{bps}
+Set the line speed (baud rate or bits per second) of any serial
+interface used by @value{GDBN} for remote debugging.
+
+@item -tty @var{device}
+Run using @var{device} for your program's standard input and output.
+@c FIXME: kingdon thinks there is more to -tty. Investigate.
+@end ifset
+@end table
+
+@node Quitting GDB
+@section Quitting @value{GDBN}
+@cindex exiting @value{GDBN}
+@cindex leaving @value{GDBN}
+
+@table @code
+@item quit
+@kindex quit
+@kindex q
+To exit @value{GDBN}, use the @code{quit} command (abbreviated @code{q}), or type
+an end-of-file character (usually @kbd{C-d}).
+@end table
+
+@cindex interrupt
+An interrupt (often @kbd{C-c}) does not exit from @value{GDBN}, but rather
+terminates the action of any @value{GDBN} command that is in progress and
+returns to @value{GDBN} command level. It is safe to type the interrupt
+character at any time because @value{GDBN} does not allow it to take effect
+until a time when it is safe.
+
+@ifclear BARETARGET
+If you have been using @value{GDBN} to control an attached process or
+device, you can release it with the @code{detach} command
+(@pxref{Attach, ,Debugging an already-running process}).
+@end ifclear
+
+@node Shell Commands
+@section Shell commands
+
+If you need to execute occasional shell commands during your
+debugging session, there is no need to leave or suspend @value{GDBN}; you can
+just use the @code{shell} command.
+
+@table @code
+@item shell @var{command string}
+@kindex shell
+@cindex shell escape
+Invoke a the standard shell to execute @var{command string}.
+@ifclear DOSHOST
+If it exists, the environment variable @code{SHELL} determines which
+shell to run. Otherwise @value{GDBN} uses @code{/bin/sh}.
+@end ifclear
+@end table
+
+The utility @code{make} is often needed in development environments.
+You do not have to use the @code{shell} command for this purpose in
+@value{GDBN}:
+
+@table @code
+@item make @var{make-args}
+@kindex make
+@cindex calling make
+Execute the @code{make} program with the specified
+arguments. This is equivalent to @samp{shell make @var{make-args}}.
+@end table
+
+@node Commands
+@chapter @value{GDBN} Commands
+
+You can abbreviate a @value{GDBN} command to the first few letters of the command
+name, if that abbreviation is unambiguous; and you can repeat certain
+@value{GDBN} commands by typing just @key{RET}. You can also use the @key{TAB}
+key to get @value{GDBN} to fill out the rest of a word in a command (or to
+show you the alternatives available, if there is more than one possibility).
+
+@menu
+* Command Syntax:: How to give commands to @value{GDBN}
+* Completion:: Command completion
+* Help:: How to ask @value{GDBN} for help
+@end menu
+
+@node Command Syntax
+@section Command syntax
+
+A @value{GDBN} command is a single line of input. There is no limit on
+how long it can be. It starts with a command name, which is followed by
+arguments whose meaning depends on the command name. For example, the
+command @code{step} accepts an argument which is the number of times to
+step, as in @samp{step 5}. You can also use the @code{step} command
+with no arguments. Some command names do not allow any arguments.
+
+@cindex abbreviation
+@value{GDBN} command names may always be truncated if that abbreviation is
+unambiguous. Other possible command abbreviations are listed in the
+documentation for individual commands. In some cases, even ambiguous
+abbreviations are allowed; for example, @code{s} is specially defined as
+equivalent to @code{step} even though there are other commands whose
+names start with @code{s}. You can test abbreviations by using them as
+arguments to the @code{help} command.
+
+@cindex repeating commands
+@kindex RET
+A blank line as input to @value{GDBN} (typing just @key{RET}) means to
+repeat the previous command. Certain commands (for example, @code{run})
+will not repeat this way; these are commands whose unintentional
+repetition might cause trouble and which you are unlikely to want to
+repeat.
+
+The @code{list} and @code{x} commands, when you repeat them with
+@key{RET}, construct new arguments rather than repeating
+exactly as typed. This permits easy scanning of source or memory.
+
+@value{GDBN} can also use @key{RET} in another way: to partition lengthy
+output, in a way similar to the common utility @code{more}
+(@pxref{Screen Size,,Screen size}). Since it is easy to press one
+@key{RET} too many in this situation, @value{GDBN} disables command
+repetition after any command that generates this sort of display.
+
+@kindex #
+@cindex comment
+Any text from a @kbd{#} to the end of the line is a comment; it does
+nothing. This is useful mainly in command files (@pxref{Command
+Files,,Command files}).
+
+@node Completion
+@section Command completion
+
+@cindex completion
+@cindex word completion
+@value{GDBN} can fill in the rest of a word in a command for you, if there is
+only one possibility; it can also show you what the valid possibilities
+are for the next word in a command, at any time. This works for @value{GDBN}
+commands, @value{GDBN} subcommands, and the names of symbols in your program.
+
+Press the @key{TAB} key whenever you want @value{GDBN} to fill out the rest
+of a word. If there is only one possibility, @value{GDBN} fills in the
+word, and waits for you to finish the command (or press @key{RET} to
+enter it). For example, if you type
+
+@c FIXME "@key" does not distinguish its argument sufficiently to permit
+@c complete accuracy in these examples; space introduced for clarity.
+@c If texinfo enhancements make it unnecessary, it would be nice to
+@c replace " @key" by "@key" in the following...
+@example
+(@value{GDBP}) info bre @key{TAB}
+@end example
+
+@noindent
+@value{GDBN} fills in the rest of the word @samp{breakpoints}, since that is
+the only @code{info} subcommand beginning with @samp{bre}:
+
+@example
+(@value{GDBP}) info breakpoints
+@end example
+
+@noindent
+You can either press @key{RET} at this point, to run the @code{info
+breakpoints} command, or backspace and enter something else, if
+@samp{breakpoints} does not look like the command you expected. (If you
+were sure you wanted @code{info breakpoints} in the first place, you
+might as well just type @key{RET} immediately after @samp{info bre},
+to exploit command abbreviations rather than command completion).
+
+If there is more than one possibility for the next word when you press
+@key{TAB}, @value{GDBN} sounds a bell. You can either supply more
+characters and try again, or just press @key{TAB} a second time;
+@value{GDBN} displays all the possible completions for that word. For
+example, you might want to set a breakpoint on a subroutine whose name
+begins with @samp{make_}, but when you type @kbd{b make_@key{TAB}} @value{GDBN}
+just sounds the bell. Typing @key{TAB} again displays all the
+function names in your program that begin with those characters, for
+example:
+
+@example
+(@value{GDBP}) b make_ @key{TAB}
+@exdent @value{GDBN} sounds bell; press @key{TAB} again, to see:
+make_a_section_from_file make_environ
+make_abs_section make_function_type
+make_blockvector make_pointer_type
+make_cleanup make_reference_type
+make_command make_symbol_completion_list
+(@value{GDBP}) b make_
+@end example
+
+@noindent
+After displaying the available possibilities, @value{GDBN} copies your
+partial input (@samp{b make_} in the example) so you can finish the
+command.
+
+If you just want to see the list of alternatives in the first place, you
+can press @kbd{M-?} rather than pressing @key{TAB} twice. @kbd{M-?}
+means @kbd{@key{META} ?}. You can type this
+@ifclear DOSHOST
+either by holding down a
+key designated as the @key{META} shift on your keyboard (if there is
+one) while typing @kbd{?}, or
+@end ifclear
+as @key{ESC} followed by @kbd{?}.
+
+@cindex quotes in commands
+@cindex completion of quoted strings
+Sometimes the string you need, while logically a ``word'', may contain
+parentheses or other characters that @value{GDBN} normally excludes from its
+notion of a word. To permit word completion to work in this situation,
+you may enclose words in @code{'} (single quote marks) in @value{GDBN} commands.
+
+@ifclear CONLY
+The most likely situation where you might need this is in typing the
+name of a C++ function. This is because C++ allows function overloading
+(multiple definitions of the same function, distinguished by argument
+type). For example, when you want to set a breakpoint you may need to
+distinguish whether you mean the version of @code{name} that takes an
+@code{int} parameter, @code{name(int)}, or the version that takes a
+@code{float} parameter, @code{name(float)}. To use the word-completion
+facilities in this situation, type a single quote @code{'} at the
+beginning of the function name. This alerts @value{GDBN} that it may need to
+consider more information than usual when you press @key{TAB} or
+@kbd{M-?} to request word completion:
+
+@example
+(@value{GDBP}) b 'bubble( @key{M-?}
+bubble(double,double) bubble(int,int)
+(@value{GDBP}) b 'bubble(
+@end example
+
+In some cases, @value{GDBN} can tell that completing a name requires using
+quotes. When this happens, @value{GDBN} inserts the quote for you (while
+completing as much as it can) if you do not type the quote in the first
+place:
+
+@example
+(@value{GDBP}) b bub @key{TAB}
+@exdent @value{GDBN} alters your input line to the following, and rings a bell:
+(@value{GDBP}) b 'bubble(
+@end example
+
+@noindent
+In general, @value{GDBN} can tell that a quote is needed (and inserts it) if
+you have not yet started typing the argument list when you ask for
+completion on an overloaded symbol.
+@end ifclear
+
+
+@node Help
+@section Getting help
+@cindex online documentation
+@kindex help
+
+You can always ask @value{GDBN} itself for information on its commands, using the
+command @code{help}.
+
+@table @code
+@item help
+@itemx h
+@kindex h
+You can use @code{help} (abbreviated @code{h}) with no arguments to
+display a short list of named classes of commands:
+
+@smallexample
+(@value{GDBP}) help
+List of classes of commands:
+
+running -- Running the program
+stack -- Examining the stack
+data -- Examining data
+breakpoints -- Making program stop at certain points
+files -- Specifying and examining files
+status -- Status inquiries
+support -- Support facilities
+user-defined -- User-defined commands
+aliases -- Aliases of other commands
+obscure -- Obscure features
+
+Type "help" followed by a class name for a list of
+commands in that class.
+Type "help" followed by command name for full
+documentation.
+Command name abbreviations are allowed if unambiguous.
+(@value{GDBP})
+@end smallexample
+
+@item help @var{class}
+Using one of the general help classes as an argument, you can get a
+list of the individual commands in that class. For example, here is the
+help display for the class @code{status}:
+
+@smallexample
+(@value{GDBP}) help status
+Status inquiries.
+
+List of commands:
+
+@c Line break in "show" line falsifies real output, but needed
+@c to fit in smallbook page size.
+show -- Generic command for showing things set
+ with "set"
+info -- Generic command for printing status
+
+Type "help" followed by command name for full
+documentation.
+Command name abbreviations are allowed if unambiguous.
+(@value{GDBP})
+@end smallexample
+
+@item help @var{command}
+With a command name as @code{help} argument, @value{GDBN} displays a
+short paragraph on how to use that command.
+@end table
+
+In addition to @code{help}, you can use the @value{GDBN} commands @code{info}
+and @code{show} to inquire about the state of your program, or the state
+of @value{GDBN} itself. Each command supports many topics of inquiry; this
+manual introduces each of them in the appropriate context. The listings
+under @code{info} and under @code{show} in the Index point to
+all the sub-commands. @xref{Index}.
+
+@c @group
+@table @code
+@item info
+@kindex info
+@kindex i
+This command (abbreviated @code{i}) is for describing the state of your
+program. For example, you can list the arguments given to your program
+with @code{info args}, list the registers currently in use with @code{info
+registers}, or list the breakpoints you have set with @code{info breakpoints}.
+You can get a complete list of the @code{info} sub-commands with
+@w{@code{help info}}.
+
+@kindex show
+@item show
+In contrast, @code{show} is for describing the state of @value{GDBN} itself.
+You can change most of the things you can @code{show}, by using the
+related command @code{set}; for example, you can control what number
+system is used for displays with @code{set radix}, or simply inquire
+which is currently in use with @code{show radix}.
+
+@kindex info set
+To display all the settable parameters and their current
+values, you can use @code{show} with no arguments; you may also use
+@code{info set}. Both commands produce the same display.
+@c FIXME: "info set" violates the rule that "info" is for state of
+@c FIXME...program. Ck w/ GNU: "info set" to be called something else,
+@c FIXME...or change desc of rule---eg "state of prog and debugging session"?
+@end table
+@c @end group
+
+Here are three miscellaneous @code{show} subcommands, all of which are
+exceptional in lacking corresponding @code{set} commands:
+
+@table @code
+@kindex show version
+@cindex version number
+@item show version
+Show what version of @value{GDBN} is running. You should include this
+information in @value{GDBN} bug-reports. If multiple versions of @value{GDBN} are in
+use at your site, you may occasionally want to determine which version
+of @value{GDBN} you are running; as @value{GDBN} evolves, new commands are introduced,
+and old ones may wither away. The version number is also announced
+when you start @value{GDBN}.
+
+@kindex show copying
+@item show copying
+Display information about permission for copying @value{GDBN}.
+
+@kindex show warranty
+@item show warranty
+Display the GNU ``NO WARRANTY'' statement.
+@end table
+
+@node Running
+@chapter Running Programs Under @value{GDBN}
+
+When you run a program under @value{GDBN}, you must first generate
+debugging information when you compile it.
+@ifclear BARETARGET
+You may start it with its arguments, if any, in an environment of your
+choice. You may redirect your program's input and output, debug an
+already running process, or kill a child process.
+@end ifclear
+
+@menu
+* Compilation:: Compiling for debugging
+* Starting:: Starting your program
+@ifclear BARETARGET
+* Arguments:: Your program's arguments
+* Environment:: Your program's environment
+* Working Directory:: Your program's working directory
+* Input/Output:: Your program's input and output
+* Attach:: Debugging an already-running process
+* Kill Process:: Killing the child process
+* Process Information:: Additional process information
+* Threads:: Debugging programs with multiple threads
+@end ifclear
+@end menu
+
+@node Compilation
+@section Compiling for debugging
+
+In order to debug a program effectively, you need to generate
+debugging information when you compile it. This debugging information
+is stored in the object file; it describes the data type of each
+variable or function and the correspondence between source line numbers
+and addresses in the executable code.
+
+To request debugging information, specify the @samp{-g} option when you run
+the compiler.
+
+Many C compilers are unable to handle the @samp{-g} and @samp{-O}
+options together. Using those compilers, you cannot generate optimized
+executables containing debugging information.
+
+@value{NGCC}, the GNU C compiler, supports @samp{-g} with or without
+@samp{-O}, making it possible to debug optimized code. We recommend
+that you @emph{always} use @samp{-g} whenever you compile a program.
+You may think your program is correct, but there is no sense in pushing
+your luck.
+
+@cindex optimized code, debugging
+@cindex debugging optimized code
+When you debug a program compiled with @samp{-g -O}, remember that the
+optimizer is rearranging your code; the debugger shows you what is
+really there. Do not be too surprised when the execution path does not
+exactly match your source file! An extreme example: if you define a
+variable, but never use it, @value{GDBN} never sees that
+variable---because the compiler optimizes it out of existence.
+
+Some things do not work as well with @samp{-g -O} as with just
+@samp{-g}, particularly on machines with instruction scheduling. If in
+doubt, recompile with @samp{-g} alone, and if this fixes the problem,
+please report it as a bug (including a test case!).
+
+Older versions of the GNU C compiler permitted a variant option
+@w{@samp{-gg}} for debugging information. @value{GDBN} no longer supports this
+format; if your GNU C compiler has this option, do not use it.
+
+@need 2000
+@node Starting
+@section Starting your program
+@cindex starting
+@cindex running
+
+@table @code
+@item run
+@itemx r
+@kindex run
+Use the @code{run} command to start your program under @value{GDBN}. You must
+first specify the program name
+@ifset VXWORKS
+(except on VxWorks)
+@end ifset
+with an argument to @value{GDBN} (@pxref{Invocation, ,Getting In and
+Out of @value{GDBN}}), or by using the @code{file} or @code{exec-file}
+command (@pxref{Files, ,Commands to specify files}).
+
+@end table
+
+@ifclear BARETARGET
+If you are running your program in an execution environment that
+supports processes, @code{run} creates an inferior process and makes
+that process run your program. (In environments without processes,
+@code{run} jumps to the start of your program.)
+
+The execution of a program is affected by certain information it
+receives from its superior. @value{GDBN} provides ways to specify this
+information, which you must do @emph{before} starting your program. (You
+can change it after starting your program, but such changes only affect
+your program the next time you start it.) This information may be
+divided into four categories:
+
+@table @asis
+@item The @emph{arguments.}
+Specify the arguments to give your program as the arguments of the
+@code{run} command. If a shell is available on your target, the shell
+is used to pass the arguments, so that you may use normal conventions
+(such as wildcard expansion or variable substitution) in describing
+the arguments. In Unix systems, you can control which shell is used
+with the @code{SHELL} environment variable. @xref{Arguments, ,Your
+program's arguments}.
+
+@item The @emph{environment.}
+Your program normally inherits its environment from @value{GDBN}, but you can
+use the @value{GDBN} commands @code{set environment} and @code{unset
+environment} to change parts of the environment that affect
+your program. @xref{Environment, ,Your program's environment}.
+
+@item The @emph{working directory.}
+Your program inherits its working directory from @value{GDBN}. You can set
+the @value{GDBN} working directory with the @code{cd} command in @value{GDBN}.
+@xref{Working Directory, ,Your program's working directory}.
+
+@item The @emph{standard input and output.}
+Your program normally uses the same device for standard input and
+standard output as @value{GDBN} is using. You can redirect input and output
+in the @code{run} command line, or you can use the @code{tty} command to
+set a different device for your program.
+@xref{Input/Output, ,Your program's input and output}.
+
+@cindex pipes
+@emph{Warning:} While input and output redirection work, you cannot use
+pipes to pass the output of the program you are debugging to another
+program; if you attempt this, @value{GDBN} is likely to wind up debugging the
+wrong program.
+@end table
+@end ifclear
+
+When you issue the @code{run} command, your program begins to execute
+immediately. @xref{Stopping, ,Stopping and continuing}, for discussion
+of how to arrange for your program to stop. Once your program has
+stopped, you may call functions in your program, using the @code{print}
+or @code{call} commands. @xref{Data, ,Examining Data}.
+
+If the modification time of your symbol file has changed since the last
+time @value{GDBN} read its symbols, @value{GDBN} discards its symbol
+table, and reads it again. When it does this, @value{GDBN} tries to retain
+your current breakpoints.
+
+@ifclear BARETARGET
+@node Arguments
+@section Your program's arguments
+
+@cindex arguments (to your program)
+The arguments to your program can be specified by the arguments of the
+@code{run} command. They are passed to a shell, which expands wildcard
+characters and performs redirection of I/O, and thence to your program.
+Your @code{SHELL} environment variable (if it exists) specifies what
+shell @value{GDBN} uses. If you do not define @code{SHELL},
+@value{GDBN} uses @code{/bin/sh}.
+
+@code{run} with no arguments uses the same arguments used by the previous
+@code{run}, or those set by the @code{set args} command.
+
+@kindex set args
+@table @code
+@item set args
+Specify the arguments to be used the next time your program is run. If
+@code{set args} has no arguments, @code{run} executes your program
+with no arguments. Once you have run your program with arguments,
+using @code{set args} before the next @code{run} is the only way to run
+it again without arguments.
+
+@item show args
+@kindex show args
+Show the arguments to give your program when it is started.
+@end table
+
+@node Environment
+@section Your program's environment
+
+@cindex environment (of your program)
+The @dfn{environment} consists of a set of environment variables and
+their values. Environment variables conventionally record such things as
+your user name, your home directory, your terminal type, and your search
+path for programs to run. Usually you set up environment variables with
+the shell and they are inherited by all the other programs you run. When
+debugging, it can be useful to try running your program with a modified
+environment without having to start @value{GDBN} over again.
+
+@table @code
+@item path @var{directory}
+@kindex path
+Add @var{directory} to the front of the @code{PATH} environment variable
+(the search path for executables), for both @value{GDBN} and your program.
+You may specify several directory names, separated by @samp{:} or
+whitespace. If @var{directory} is already in the path, it is moved to
+the front, so it is searched sooner.
+
+You can use the string @samp{$cwd} to refer to whatever is the current
+working directory at the time @value{GDBN} searches the path. If you
+use @samp{.} instead, it refers to the directory where you executed the
+@code{path} command. @value{GDBN} replaces @samp{.} in the
+@var{directory} argument (with the current path) before adding
+@var{directory} to the search path.
+@c 'path' is explicitly nonrepeatable, but RMS points out it is silly to
+@c document that, since repeating it would be a no-op.
+
+@item show paths
+@kindex show paths
+Display the list of search paths for executables (the @code{PATH}
+environment variable).
+
+@item show environment @r{[}@var{varname}@r{]}
+@kindex show environment
+Print the value of environment variable @var{varname} to be given to
+your program when it starts. If you do not supply @var{varname},
+print the names and values of all environment variables to be given to
+your program. You can abbreviate @code{environment} as @code{env}.
+
+@item set environment @var{varname} @r{[}=@r{]} @var{value}
+@kindex set environment
+Set environment variable @var{varname} to @var{value}. The value
+changes for your program only, not for @value{GDBN} itself. @var{value} may
+be any string; the values of environment variables are just strings, and
+any interpretation is supplied by your program itself. The @var{value}
+parameter is optional; if it is eliminated, the variable is set to a
+null value.
+@c "any string" here does not include leading, trailing
+@c blanks. Gnu asks: does anyone care?
+
+For example, this command:
+
+@example
+set env USER = foo
+@end example
+
+@noindent
+tells a Unix program, when subsequently run, that its user is named
+@samp{foo}. (The spaces around @samp{=} are used for clarity here; they
+are not actually required.)
+
+@item unset environment @var{varname}
+@kindex unset environment
+Remove variable @var{varname} from the environment to be passed to your
+program. This is different from @samp{set env @var{varname} =};
+@code{unset environment} removes the variable from the environment,
+rather than assigning it an empty value.
+@end table
+
+@emph{Warning:} @value{GDBN} runs your program using the shell indicated
+by your @code{SHELL} environment variable if it exists (or
+@code{/bin/sh} if not). If your @code{SHELL} variable names a shell
+that runs an initialization file---such as @file{.cshrc} for C-shell, or
+@file{.bashrc} for BASH---any variables you set in that file affect
+your program. You may wish to move setting of environment variables to
+files that are only run when you sign on, such as @file{.login} or
+@file{.profile}.
+
+@node Working Directory
+@section Your program's working directory
+
+@cindex working directory (of your program)
+Each time you start your program with @code{run}, it inherits its
+working directory from the current working directory of @value{GDBN}.
+The @value{GDBN} working directory is initially whatever it inherited
+from its parent process (typically the shell), but you can specify a new
+working directory in @value{GDBN} with the @code{cd} command.
+
+The @value{GDBN} working directory also serves as a default for the commands
+that specify files for @value{GDBN} to operate on. @xref{Files, ,Commands to
+specify files}.
+
+@table @code
+@item cd @var{directory}
+@kindex cd
+Set the @value{GDBN} working directory to @var{directory}.
+
+@item pwd
+@kindex pwd
+Print the @value{GDBN} working directory.
+@end table
+
+@node Input/Output
+@section Your program's input and output
+
+@cindex redirection
+@cindex i/o
+@cindex terminal
+By default, the program you run under @value{GDBN} does input and output to
+the same terminal that @value{GDBN} uses. @value{GDBN} switches the terminal to
+its own terminal modes to interact with you, but it records the terminal
+modes your program was using and switches back to them when you continue
+running your program.
+
+@table @code
+@item info terminal
+@kindex info terminal
+Displays information recorded by @value{GDBN} about the terminal modes your
+program is using.
+@end table
+
+You can redirect your program's input and/or output using shell
+redirection with the @code{run} command. For example,
+
+@example
+run > outfile
+@end example
+
+@noindent
+starts your program, diverting its output to the file @file{outfile}.
+
+@kindex tty
+@cindex controlling terminal
+Another way to specify where your program should do input and output is
+with the @code{tty} command. This command accepts a file name as
+argument, and causes this file to be the default for future @code{run}
+commands. It also resets the controlling terminal for the child
+process, for future @code{run} commands. For example,
+
+@example
+tty /dev/ttyb
+@end example
+
+@noindent
+directs that processes started with subsequent @code{run} commands
+default to do input and output on the terminal @file{/dev/ttyb} and have
+that as their controlling terminal.
+
+An explicit redirection in @code{run} overrides the @code{tty} command's
+effect on the input/output device, but not its effect on the controlling
+terminal.
+
+When you use the @code{tty} command or redirect input in the @code{run}
+command, only the input @emph{for your program} is affected. The input
+for @value{GDBN} still comes from your terminal.
+
+@node Attach
+@section Debugging an already-running process
+@kindex attach
+@cindex attach
+
+@table @code
+@item attach @var{process-id}
+This command attaches to a running process---one that was started
+outside @value{GDBN}. (@code{info files} shows your active
+targets.) The command takes as argument a process ID. The usual way to
+find out the process-id of a Unix process is with the @code{ps} utility,
+or with the @samp{jobs -l} shell command.
+
+@code{attach} does not repeat if you press @key{RET} a second time after
+executing the command.
+@end table
+
+To use @code{attach}, your program must be running in an environment
+which supports processes; for example, @code{attach} does not work for
+programs on bare-board targets that lack an operating system. You must
+also have permission to send the process a signal.
+
+When using @code{attach}, you should first use the @code{file} command
+to specify the program running in the process and load its symbol table.
+@xref{Files, ,Commands to Specify Files}.
+
+The first thing @value{GDBN} does after arranging to debug the specified
+process is to stop it. You can examine and modify an attached process
+with all the @value{GDBN} commands that are ordinarily available when you start
+processes with @code{run}. You can insert breakpoints; you can step and
+continue; you can modify storage. If you would rather the process
+continue running, you may use the @code{continue} command after
+attaching @value{GDBN} to the process.
+
+@table @code
+@item detach
+@kindex detach
+When you have finished debugging the attached process, you can use the
+@code{detach} command to release it from @value{GDBN} control. Detaching
+the process continues its execution. After the @code{detach} command,
+that process and @value{GDBN} become completely independent once more, and you
+are ready to @code{attach} another process or start one with @code{run}.
+@code{detach} does not repeat if you press @key{RET} again after
+executing the command.
+@end table
+
+If you exit @value{GDBN} or use the @code{run} command while you have an
+attached process, you kill that process. By default, @value{GDBN} asks
+for confirmation if you try to do either of these things; you can
+control whether or not you need to confirm by using the @code{set
+confirm} command (@pxref{Messages/Warnings, ,Optional warnings and
+messages}).
+
+@node Kill Process
+@c @group
+@section Killing the child process
+
+@table @code
+@item kill
+@kindex kill
+Kill the child process in which your program is running under @value{GDBN}.
+@end table
+
+This command is useful if you wish to debug a core dump instead of a
+running process. @value{GDBN} ignores any core dump file while your program
+is running.
+@c @end group
+
+On some operating systems, a program cannot be executed outside @value{GDBN}
+while you have breakpoints set on it inside @value{GDBN}. You can use the
+@code{kill} command in this situation to permit running your program
+outside the debugger.
+
+The @code{kill} command is also useful if you wish to recompile and
+relink your program, since on many systems it is impossible to modify an
+executable file while it is running in a process. In this case, when you
+next type @code{run}, @value{GDBN} notices that the file has changed, and
+reads the symbol table again (while trying to preserve your current
+breakpoint settings).
+
+@node Process Information
+@section Additional process information
+
+@kindex /proc
+@cindex process image
+Some operating systems provide a facility called @samp{/proc} that can
+be used to examine the image of a running process using file-system
+subroutines. If @value{GDBN} is configured for an operating system with this
+facility, the command @code{info proc} is available to report on several
+kinds of information about the process running your program.
+
+@table @code
+@item info proc
+@kindex info proc
+Summarize available information about the process.
+
+@item info proc mappings
+@kindex info proc mappings
+Report on the address ranges accessible in the program, with information
+on whether your program may read, write, or execute each range.
+
+@item info proc times
+@kindex info proc times
+Starting time, user CPU time, and system CPU time for your program and
+its children.
+
+@item info proc id
+@kindex info proc id
+Report on the process IDs related to your program: its own process ID,
+the ID of its parent, the process group ID, and the session ID.
+
+@item info proc status
+@kindex info proc status
+General information on the state of the process. If the process is
+stopped, this report includes the reason for stopping, and any signal
+received.
+
+@item info proc all
+Show all the above information about the process.
+@end table
+
+@node Threads
+@section Debugging programs with multiple threads
+
+@cindex threads of execution
+@cindex multiple threads
+@cindex switching threads
+In some operating systems, a single program may have more than one
+@dfn{thread} of execution. The precise semantics of threads differ from
+one operating system to another, but in general the threads of a single
+program are akin to multiple processes---except that they share one
+address space (that is, they can all examine and modify the same
+variables). On the other hand, each thread has its own registers and
+execution stack, and perhaps private memory.
+
+@value{GDBN} provides these facilities for debugging multi-thread
+programs:
+
+@itemize @bullet
+@item automatic notification of new threads
+@item @samp{thread @var{threadno}}, a command to switch among threads
+@item @samp{info threads}, a command to inquire about existing threads
+@item thread-specific breakpoints
+@end itemize
+
+@quotation
+@emph{Warning:} These facilities are not yet available on every
+@value{GDBN} configuration where the operating system supports threads.
+If your @value{GDBN} does not support threads, these commands have no
+effect. For example, a system without thread support shows no output
+from @samp{info threads}, and always rejects the @code{thread} command,
+like this:
+
+@smallexample
+(@value{GDBP}) info threads
+(@value{GDBP}) thread 1
+Thread ID 1 not known. Use the "info threads" command to
+see the IDs of currently known threads.
+@end smallexample
+@c FIXME to implementors: how hard would it be to say "sorry, this GDB
+@c doesn't support threads"?
+@end quotation
+
+@cindex focus of debugging
+@cindex current thread
+The @value{GDBN} thread debugging facility allows you to observe all
+threads while your program runs---but whenever @value{GDBN} takes
+control, one thread in particular is always the focus of debugging.
+This thread is called the @dfn{current thread}. Debugging commands show
+program information from the perspective of the current thread.
+
+@kindex New @var{systag}
+@cindex thread identifier (system)
+@c FIXME-implementors!! It would be more helpful if the [New...] message
+@c included GDB's numeric thread handle, so you could just go to that
+@c thread without first checking `info threads'.
+Whenever @value{GDBN} detects a new thread in your program, it displays
+the target system's identification for the thread with a message in the
+form @samp{[New @var{systag}]}. @var{systag} is a thread identifier
+whose form varies depending on the particular system. For example, on
+LynxOS, you might see
+
+@example
+[New process 35 thread 27]
+@end example
+
+@noindent
+when @value{GDBN} notices a new thread. In contrast, on an SGI system,
+the @var{systag} is simply something like @samp{process 368}, with no
+further qualifier.
+
+@c FIXME!! (1) Does the [New...] message appear even for the very first
+@c thread of a program, or does it only appear for the
+@c second---i.e., when it becomes obvious we have a multithread
+@c program?
+@c (2) *Is* there necessarily a first thread always? Or do some
+@c multithread systems permit starting a program with multiple
+@c threads ab initio?
+
+@cindex thread number
+@cindex thread identifier (GDB)
+For debugging purposes, @value{GDBN} associates its own thread
+number---always a single integer---with each thread in your program.
+
+@table @code
+@item info threads
+@kindex info threads
+Display a summary of all threads currently in your
+program. @value{GDBN} displays for each thread (in this order):
+
+@enumerate
+@item the thread number assigned by @value{GDBN}
+
+@item the target system's thread identifier (@var{systag})
+
+@item the current stack frame summary for that thread
+@end enumerate
+
+@noindent
+An asterisk @samp{*} to the left of the @value{GDBN} thread number
+indicates the current thread.
+
+For example,
+@end table
+@c end table here to get a little more width for example
+
+@smallexample
+(@value{GDBP}) info threads
+ 3 process 35 thread 27 0x34e5 in sigpause ()
+ 2 process 35 thread 23 0x34e5 in sigpause ()
+* 1 process 35 thread 13 main (argc=1, argv=0x7ffffff8)
+ at threadtest.c:68
+@end smallexample
+
+@table @code
+@item thread @var{threadno}
+@kindex thread @var{threadno}
+Make thread number @var{threadno} the current thread. The command
+argument @var{threadno} is the internal @value{GDBN} thread number, as
+shown in the first field of the @samp{info threads} display.
+@value{GDBN} responds by displaying the system identifier of the thread
+you selected, and its current stack frame summary:
+
+@smallexample
+@c FIXME!! This example made up; find a GDB w/threads and get real one
+(@value{GDBP}) thread 2
+[Switching to process 35 thread 23]
+0x34e5 in sigpause ()
+@end smallexample
+
+@noindent
+As with the @samp{[New @dots{}]} message, the form of the text after
+@samp{Switching to} depends on your system's conventions for identifying
+threads.
+@end table
+
+@cindex automatic thread selection
+@cindex switching threads automatically
+@cindex threads, automatic switching
+Whenever @value{GDBN} stops your program, due to a breakpoint or a
+signal, it automatically selects the thread where that breakpoint or
+signal happened. @value{GDBN} alerts you to the context switch with a
+message of the form @samp{[Switching to @var{systag}]} to identify the
+thread.
+
+@xref{Thread Stops,,Stopping and starting multi-thread programs}, for
+more information about how @value{GDBN} behaves when you stop and start
+programs with multiple threads.
+
+@xref{Set Watchpoints,,Setting watchpoints}, for information about
+watchpoints in programs with multiple threads.
+@end ifclear
+
+@node Stopping
+@chapter Stopping and Continuing
+
+The principal purposes of using a debugger are so that you can stop your
+program before it terminates; or so that, if your program runs into
+trouble, you can investigate and find out why.
+
+Inside @value{GDBN}, your program may stop for any of several reasons, such
+as
+@ifclear BARETARGET
+a signal,
+@end ifclear
+a breakpoint, or reaching a new line after a @value{GDBN}
+command such as @code{step}. You may then examine and change
+variables, set new breakpoints or remove old ones, and then continue
+execution. Usually, the messages shown by @value{GDBN} provide ample
+explanation of the status of your program---but you can also explicitly
+request this information at any time.
+
+@table @code
+@item info program
+@kindex info program
+Display information about the status of your program: whether it is
+running or not,
+@ifclear BARETARGET
+what process it is,
+@end ifclear
+and why it stopped.
+@end table
+
+@menu
+@ifclear CONLY
+* Breakpoints:: Breakpoints, watchpoints, and exceptions
+@end ifclear
+@ifset CONLY
+* Breakpoints:: Breakpoints and watchpoints
+@end ifset
+@c Remnant makeinfo bug requires blank line after *successful* end-if in menu:
+
+* Continuing and Stepping:: Resuming execution
+@ifset POSIX
+* Signals:: Signals
+@end ifset
+@ifclear BARETARGET
+* Thread Stops:: Stopping and starting multi-thread programs
+@end ifclear
+@end menu
+
+@c makeinfo node-defaulting requires adjacency of @node and sectioning cmds
+@c ...hence distribute @node Breakpoints over two possible @if expansions.
+@c
+@ifclear CONLY
+@node Breakpoints
+@section Breakpoints, watchpoints, and exceptions
+@end ifclear
+@ifset CONLY
+@node Breakpoints
+@section Breakpoints and watchpoints
+@end ifset
+
+@cindex breakpoints
+A @dfn{breakpoint} makes your program stop whenever a certain point in
+the program is reached. For each breakpoint, you can add
+conditions to control in finer detail whether your program stops.
+You can set breakpoints with the @code{break} command and its variants
+(@pxref{Set Breaks, ,Setting breakpoints}), to specify the place where
+your program should stop by line number, function name or exact address
+in the program.
+@ifclear CONLY
+In languages with exception handling (such as GNU C++), you can also set
+breakpoints where an exception is raised (@pxref{Exception Handling,,
+Breakpoints and exceptions}).
+@end ifclear
+
+@cindex watchpoints
+@cindex memory tracing
+@cindex breakpoint on memory address
+@cindex breakpoint on variable modification
+A @dfn{watchpoint} is a special breakpoint that stops your program
+when the value of an expression changes. You must use a different
+command to set watchpoints (@pxref{Set Watchpoints, ,Setting
+watchpoints}), but aside from that, you can manage a watchpoint like
+any other breakpoint: you enable, disable, and delete both breakpoints
+and watchpoints using the same commands.
+
+You can arrange to have values from your program displayed automatically
+whenever @value{GDBN} stops at a breakpoint. @xref{Auto Display,,
+Automatic display}.
+
+@cindex breakpoint numbers
+@cindex numbers for breakpoints
+@value{GDBN} assigns a number to each breakpoint or watchpoint when you
+create it; these numbers are successive integers starting with one. In
+many of the commands for controlling various features of breakpoints you
+use the breakpoint number to say which breakpoint you want to change.
+Each breakpoint may be @dfn{enabled} or @dfn{disabled}; if disabled, it has
+no effect on your program until you enable it again.
+
+@menu
+* Set Breaks:: Setting breakpoints
+* Set Watchpoints:: Setting watchpoints
+@ifclear CONLY
+* Exception Handling:: Breakpoints and exceptions
+@end ifclear
+
+* Delete Breaks:: Deleting breakpoints
+* Disabling:: Disabling breakpoints
+* Conditions:: Break conditions
+* Break Commands:: Breakpoint command lists
+@ifclear CONLY
+* Breakpoint Menus:: Breakpoint menus
+@end ifclear
+@ifclear BARETARGET
+* Error in Breakpoints:: ``Cannot insert breakpoints''
+@end ifclear
+@end menu
+
+@node Set Breaks
+@subsection Setting breakpoints
+
+@c FIXME LMB what does GDB do if no code on line of breakpt?
+@c consider in particular declaration with/without initialization.
+@c
+@c FIXME 2 is there stuff on this already? break at fun start, already init?
+
+@kindex break
+@kindex b
+@kindex $bpnum
+@cindex latest breakpoint
+Breakpoints are set with the @code{break} command (abbreviated
+@code{b}). The debugger convenience variable @samp{$bpnum} records the
+number of the beakpoint you've set most recently; see @ref{Convenience
+Vars,, Convenience variables}, for a discussion of what you can do with
+convenience variables.
+
+You have several ways to say where the breakpoint should go.
+
+@table @code
+@item break @var{function}
+Set a breakpoint at entry to function @var{function}.
+@ifclear CONLY
+When using source languages that permit overloading of symbols, such as
+C++, @var{function} may refer to more than one possible place to break.
+@xref{Breakpoint Menus,,Breakpoint menus}, for a discussion of that situation.
+@end ifclear
+
+@item break +@var{offset}
+@itemx break -@var{offset}
+Set a breakpoint some number of lines forward or back from the position
+at which execution stopped in the currently selected frame.
+
+@item break @var{linenum}
+Set a breakpoint at line @var{linenum} in the current source file.
+That file is the last file whose source text was printed. This
+breakpoint stops your program just before it executes any of the
+code on that line.
+
+@item break @var{filename}:@var{linenum}
+Set a breakpoint at line @var{linenum} in source file @var{filename}.
+
+@item break @var{filename}:@var{function}
+Set a breakpoint at entry to function @var{function} found in file
+@var{filename}. Specifying a file name as well as a function name is
+superfluous except when multiple files contain similarly named
+functions.
+
+@item break *@var{address}
+Set a breakpoint at address @var{address}. You can use this to set
+breakpoints in parts of your program which do not have debugging
+information or source files.
+
+@item break
+When called without any arguments, @code{break} sets a breakpoint at
+the next instruction to be executed in the selected stack frame
+(@pxref{Stack, ,Examining the Stack}). In any selected frame but the
+innermost, this makes your program stop as soon as control
+returns to that frame. This is similar to the effect of a
+@code{finish} command in the frame inside the selected frame---except
+that @code{finish} does not leave an active breakpoint. If you use
+@code{break} without an argument in the innermost frame, @value{GDBN} stops
+the next time it reaches the current location; this may be useful
+inside loops.
+
+@value{GDBN} normally ignores breakpoints when it resumes execution, until at
+least one instruction has been executed. If it did not do this, you
+would be unable to proceed past a breakpoint without first disabling the
+breakpoint. This rule applies whether or not the breakpoint already
+existed when your program stopped.
+
+@item break @dots{} if @var{cond}
+Set a breakpoint with condition @var{cond}; evaluate the expression
+@var{cond} each time the breakpoint is reached, and stop only if the
+value is nonzero---that is, if @var{cond} evaluates as true.
+@samp{@dots{}} stands for one of the possible arguments described
+above (or no argument) specifying where to break. @xref{Conditions,
+,Break conditions}, for more information on breakpoint conditions.
+
+@item tbreak @var{args}
+@kindex tbreak
+Set a breakpoint enabled only for one stop. @var{args} are the
+same as for the @code{break} command, and the breakpoint is set in the same
+way, but the breakpoint is automatically deleted after the first time your
+program stops there. @xref{Disabling, ,Disabling breakpoints}.
+
+@item rbreak @var{regex}
+@kindex rbreak
+@cindex regular expression
+@c FIXME what kind of regexp?
+Set breakpoints on all functions matching the regular expression
+@var{regex}. This command
+sets an unconditional breakpoint on all matches, printing a list of all
+breakpoints it set. Once these breakpoints are set, they are treated
+just like the breakpoints set with the @code{break} command. You can
+delete them, disable them, or make them conditional the same way as any
+other breakpoint.
+
+@ifclear CONLY
+When debugging C++ programs, @code{rbreak} is useful for setting
+breakpoints on overloaded functions that are not members of any special
+classes.
+@end ifclear
+
+@kindex info breakpoints
+@cindex @code{$_} and @code{info breakpoints}
+@item info breakpoints @r{[}@var{n}@r{]}
+@itemx info break @r{[}@var{n}@r{]}
+@itemx info watchpoints @r{[}@var{n}@r{]}
+Print a table of all breakpoints and watchpoints set and not
+deleted, with the following columns for each breakpoint:
+
+@table @emph
+@item Breakpoint Numbers
+@item Type
+Breakpoint or watchpoint.
+@item Disposition
+Whether the breakpoint is marked to be disabled or deleted when hit.
+@item Enabled or Disabled
+Enabled breakpoints are marked with @samp{y}. @samp{n} marks breakpoints
+that are not enabled.
+@item Address
+Where the breakpoint is in your program, as a memory address
+@item What
+Where the breakpoint is in the source for your program, as a file and
+line number.
+@end table
+
+@noindent
+If a breakpoint is conditional, @code{info break} shows the condition on
+the line following the affected breakpoint; breakpoint commands, if any,
+are listed after that.
+
+@noindent
+@code{info break} with a breakpoint
+number @var{n} as argument lists only that breakpoint. The
+convenience variable @code{$_} and the default examining-address for
+the @code{x} command are set to the address of the last breakpoint
+listed (@pxref{Memory, ,Examining memory}).
+@end table
+
+@value{GDBN} allows you to set any number of breakpoints at the same place in
+your program. There is nothing silly or meaningless about this. When
+the breakpoints are conditional, this is even useful
+(@pxref{Conditions, ,Break conditions}).
+
+@cindex negative breakpoint numbers
+@cindex internal @value{GDBN} breakpoints
+@value{GDBN} itself sometimes sets breakpoints in your program for special
+purposes, such as proper handling of @code{longjmp} (in C programs).
+These internal breakpoints are assigned negative numbers, starting with
+@code{-1}; @samp{info breakpoints} does not display them.
+
+You can see these breakpoints with the @value{GDBN} maintenance command
+@samp{maint info breakpoints}.
+
+@table @code
+@kindex maint info breakpoints
+@item maint info breakpoints
+Using the same format as @samp{info breakpoints}, display both the
+breakpoints you've set explicitly, and those @value{GDBN} is using for
+internal purposes. Internal breakpoints are shown with negative
+breakpoint numbers. The type column identifies what kind of breakpoint
+is shown:
+
+@table @code
+@item breakpoint
+Normal, explicitly set breakpoint.
+
+@item watchpoint
+Normal, explicitly set watchpoint.
+
+@item longjmp
+Internal breakpoint, used to handle correctly stepping through
+@code{longjmp} calls.
+
+@item longjmp resume
+Internal breakpoint at the target of a @code{longjmp}.
+
+@item until
+Temporary internal breakpoint used by the @value{GDBN} @code{until} command.
+
+@item finish
+Temporary internal breakpoint used by the @value{GDBN} @code{finish} command.
+@end table
+
+@end table
+
+
+@node Set Watchpoints
+@subsection Setting watchpoints
+@cindex setting watchpoints
+
+You can use a watchpoint to stop execution whenever the value of an
+expression changes, without having to predict a particular place
+where this may happen.
+
+Watchpoints currently execute two orders of magnitude more slowly than
+other breakpoints, but this can be well worth it to catch errors where
+you have no clue what part of your program is the culprit.
+
+@ignore
+@c this "future releases" promise has been in too long, is getting
+@c embarrassing. But...
+@c FIXME: in future updates, check whether hardware watchpoints in on any
+@c platforms yet. As of 26jan94, they're very close on HPPA running
+@c Berkeley and on Irix 4.
+Some processors provide special hardware to support watchpoint
+evaluation; future releases of @value{GDBN} will use such hardware if it
+is available.
+@end ignore
+
+@table @code
+@kindex watch
+@item watch @var{expr}
+Set a watchpoint for an expression.
+
+@kindex info watchpoints
+@item info watchpoints
+This command prints a list of watchpoints and breakpoints; it is the
+same as @code{info break}.
+@end table
+
+@ifclear BARETARGET
+@quotation
+@cindex watchpoints and threads
+@cindex threads and watchpoints
+@emph{Warning:} in multi-thread programs, watchpoints have only limited
+usefulness. With the current watchpoint implementation, @value{GDBN}
+can only watch the value of an expression @emph{in a single thread}. If
+you are confident that the expression can only change due to the current
+thread's activity (and if you are also confident that no other thread
+can become current), then you can use watchpoints as usual. However,
+@value{GDBN} may not notice when a non-current thread's activity changes
+the expression.
+@end quotation
+@end ifclear
+
+@ifclear CONLY
+@node Exception Handling
+@subsection Breakpoints and exceptions
+@cindex exception handlers
+
+Some languages, such as GNU C++, implement exception handling. You can
+use @value{GDBN} to examine what caused your program to raise an exception,
+and to list the exceptions your program is prepared to handle at a
+given point in time.
+
+@table @code
+@item catch @var{exceptions}
+@kindex catch
+You can set breakpoints at active exception handlers by using the
+@code{catch} command. @var{exceptions} is a list of names of exceptions
+to catch.
+@end table
+
+You can use @code{info catch} to list active exception handlers.
+@xref{Frame Info, ,Information about a frame}.
+
+There are currently some limitations to exception handling in @value{GDBN}:
+
+@itemize @bullet
+@item
+If you call a function interactively, @value{GDBN} normally returns
+control to you when the function has finished executing. If the call
+raises an exception, however, the call may bypass the mechanism that
+returns control to you and cause your program to simply continue
+running until it hits a breakpoint, catches a signal that @value{GDBN} is
+listening for, or exits.
+
+@item
+You cannot raise an exception interactively.
+
+@item
+You cannot install an exception handler interactively.
+@end itemize
+
+@cindex raise exceptions
+Sometimes @code{catch} is not the best way to debug exception handling:
+if you need to know exactly where an exception is raised, it is better to
+stop @emph{before} the exception handler is called, since that way you
+can see the stack before any unwinding takes place. If you set a
+breakpoint in an exception handler instead, it may not be easy to find
+out where the exception was raised.
+
+To stop just before an exception handler is called, you need some
+knowledge of the implementation. In the case of GNU C++, exceptions are
+raised by calling a library function named @code{__raise_exception}
+which has the following ANSI C interface:
+
+@example
+ /* @var{addr} is where the exception identifier is stored.
+ ID is the exception identifier. */
+ void __raise_exception (void **@var{addr}, void *@var{id});
+@end example
+
+@noindent
+To make the debugger catch all exceptions before any stack
+unwinding takes place, set a breakpoint on @code{__raise_exception}
+(@pxref{Breakpoints, ,Breakpoints; watchpoints; and exceptions}).
+
+With a conditional breakpoint (@pxref{Conditions, ,Break conditions})
+that depends on the value of @var{id}, you can stop your program when
+a specific exception is raised. You can use multiple conditional
+breakpoints to stop your program when any of a number of exceptions are
+raised.
+@end ifclear
+
+@node Delete Breaks
+@subsection Deleting breakpoints
+
+@cindex clearing breakpoints, watchpoints
+@cindex deleting breakpoints, watchpoints
+It is often necessary to eliminate a breakpoint or watchpoint once it
+has done its job and you no longer want your program to stop there. This
+is called @dfn{deleting} the breakpoint. A breakpoint that has been
+deleted no longer exists; it is forgotten.
+
+With the @code{clear} command you can delete breakpoints according to
+where they are in your program. With the @code{delete} command you can
+delete individual breakpoints or watchpoints by specifying their
+breakpoint numbers.
+
+It is not necessary to delete a breakpoint to proceed past it. @value{GDBN}
+automatically ignores breakpoints on the first instruction to be executed
+when you continue execution without changing the execution address.
+
+@table @code
+@item clear
+@kindex clear
+Delete any breakpoints at the next instruction to be executed in the
+selected stack frame (@pxref{Selection, ,Selecting a frame}). When
+the innermost frame is selected, this is a good way to delete a
+breakpoint where your program just stopped.
+
+@item clear @var{function}
+@itemx clear @var{filename}:@var{function}
+Delete any breakpoints set at entry to the function @var{function}.
+
+@item clear @var{linenum}
+@itemx clear @var{filename}:@var{linenum}
+Delete any breakpoints set at or within the code of the specified line.
+
+@item delete @r{[}breakpoints@r{]} @r{[}@var{bnums}@dots{}@r{]}
+@cindex delete breakpoints
+@kindex delete
+@kindex d
+Delete the breakpoints or watchpoints of the numbers specified as
+arguments. If no argument is specified, delete all breakpoints (@value{GDBN}
+asks confirmation, unless you have @code{set confirm off}). You
+can abbreviate this command as @code{d}.
+@end table
+
+@node Disabling
+@subsection Disabling breakpoints
+
+@cindex disabled breakpoints
+@cindex enabled breakpoints
+Rather than deleting a breakpoint or watchpoint, you might prefer to
+@dfn{disable} it. This makes the breakpoint inoperative as if it had
+been deleted, but remembers the information on the breakpoint so that
+you can @dfn{enable} it again later.
+
+You disable and enable breakpoints and watchpoints with the
+@code{enable} and @code{disable} commands, optionally specifying one or
+more breakpoint numbers as arguments. Use @code{info break} or
+@code{info watch} to print a list of breakpoints or watchpoints if you
+do not know which numbers to use.
+
+A breakpoint or watchpoint can have any of four different states of
+enablement:
+
+@itemize @bullet
+@item
+Enabled. The breakpoint stops your program. A breakpoint set
+with the @code{break} command starts out in this state.
+@item
+Disabled. The breakpoint has no effect on your program.
+@item
+Enabled once. The breakpoint stops your program, but then becomes
+disabled. A breakpoint set with the @code{tbreak} command starts out in
+this state.
+@item
+Enabled for deletion. The breakpoint stops your program, but
+immediately after it does so it is deleted permanently.
+@end itemize
+
+You can use the following commands to enable or disable breakpoints and
+watchpoints:
+
+@table @code
+@item disable @r{[}breakpoints@r{]} @r{[}@var{bnums}@dots{}@r{]}
+@kindex disable breakpoints
+@kindex disable
+@kindex dis
+Disable the specified breakpoints---or all breakpoints, if none are
+listed. A disabled breakpoint has no effect but is not forgotten. All
+options such as ignore-counts, conditions and commands are remembered in
+case the breakpoint is enabled again later. You may abbreviate
+@code{disable} as @code{dis}.
+
+@item enable @r{[}breakpoints@r{]} @r{[}@var{bnums}@dots{}@r{]}
+@kindex enable breakpoints
+@kindex enable
+Enable the specified breakpoints (or all defined breakpoints). They
+become effective once again in stopping your program.
+
+@item enable @r{[}breakpoints@r{]} once @var{bnums}@dots{}
+Enable the specified breakpoints temporarily. @value{GDBN} disables any
+of these breakpoints immediately after stopping your program.
+
+@item enable @r{[}breakpoints@r{]} delete @var{bnums}@dots{}
+Enable the specified breakpoints to work once, then die. @value{GDBN}
+deletes any of these breakpoints as soon as your program stops there.
+@end table
+
+Save for a breakpoint set with @code{tbreak} (@pxref{Set Breaks,
+,Setting breakpoints}), breakpoints that you set are initially enabled;
+subsequently, they become disabled or enabled only when you use one of
+the commands above. (The command @code{until} can set and delete a
+breakpoint of its own, but it does not change the state of your other
+breakpoints; see @ref{Continuing and Stepping, ,Continuing and
+stepping}.)
+
+@node Conditions
+@subsection Break conditions
+@cindex conditional breakpoints
+@cindex breakpoint conditions
+
+@c FIXME what is scope of break condition expr? Context where wanted?
+@c in particular for a watchpoint?
+The simplest sort of breakpoint breaks every time your program reaches a
+specified place. You can also specify a @dfn{condition} for a
+breakpoint. A condition is just a Boolean expression in your
+programming language (@pxref{Expressions, ,Expressions}). A breakpoint with
+a condition evaluates the expression each time your program reaches it,
+and your program stops only if the condition is @emph{true}.
+
+This is the converse of using assertions for program validation; in that
+situation, you want to stop when the assertion is violated---that is,
+when the condition is false. In C, if you want to test an assertion expressed
+by the condition @var{assert}, you should set the condition
+@samp{! @var{assert}} on the appropriate breakpoint.
+
+Conditions are also accepted for watchpoints; you may not need them,
+since a watchpoint is inspecting the value of an expression anyhow---but
+it might be simpler, say, to just set a watchpoint on a variable name,
+and specify a condition that tests whether the new value is an interesting
+one.
+
+Break conditions can have side effects, and may even call functions in
+your program. This can be useful, for example, to activate functions
+that log program progress, or to use your own print functions to
+format special data structures. The effects are completely predictable
+unless there is another enabled breakpoint at the same address. (In
+that case, @value{GDBN} might see the other breakpoint first and stop your
+program without checking the condition of this one.) Note that
+breakpoint commands are usually more convenient and flexible for the
+purpose of performing side effects when a breakpoint is reached
+(@pxref{Break Commands, ,Breakpoint command lists}).
+
+Break conditions can be specified when a breakpoint is set, by using
+@samp{if} in the arguments to the @code{break} command. @xref{Set
+Breaks, ,Setting breakpoints}. They can also be changed at any time
+with the @code{condition} command. The @code{watch} command does not
+recognize the @code{if} keyword; @code{condition} is the only way to
+impose a further condition on a watchpoint.
+
+@table @code
+@item condition @var{bnum} @var{expression}
+@kindex condition
+Specify @var{expression} as the break condition for breakpoint or
+watchpoint number @var{bnum}. After you set a condition, breakpoint
+@var{bnum} stops your program only if the value of @var{expression} is
+true (nonzero, in C). When you use @code{condition}, @value{GDBN}
+checks @var{expression} immediately for syntactic correctness, and to
+determine whether symbols in it have referents in the context of your
+breakpoint.
+@c FIXME so what does GDB do if there is no referent? Moreover, what
+@c about watchpoints?
+@value{GDBN} does
+not actually evaluate @var{expression} at the time the @code{condition}
+command is given, however. @xref{Expressions, ,Expressions}.
+
+@item condition @var{bnum}
+Remove the condition from breakpoint number @var{bnum}. It becomes
+an ordinary unconditional breakpoint.
+@end table
+
+@cindex ignore count (of breakpoint)
+A special case of a breakpoint condition is to stop only when the
+breakpoint has been reached a certain number of times. This is so
+useful that there is a special way to do it, using the @dfn{ignore
+count} of the breakpoint. Every breakpoint has an ignore count, which
+is an integer. Most of the time, the ignore count is zero, and
+therefore has no effect. But if your program reaches a breakpoint whose
+ignore count is positive, then instead of stopping, it just decrements
+the ignore count by one and continues. As a result, if the ignore count
+value is @var{n}, the breakpoint does not stop the next @var{n} times
+your program reaches it.
+
+@table @code
+@item ignore @var{bnum} @var{count}
+@kindex ignore
+Set the ignore count of breakpoint number @var{bnum} to @var{count}.
+The next @var{count} times the breakpoint is reached, your program's
+execution does not stop; other than to decrement the ignore count, @value{GDBN}
+takes no action.
+
+To make the breakpoint stop the next time it is reached, specify
+a count of zero.
+
+When you use @code{continue} to resume execution of your program from a
+breakpoint, you can specify an ignore count directly as an argument to
+@code{continue}, rather than using @code{ignore}. @xref{Continuing and
+Stepping,,Continuing and stepping}.
+
+If a breakpoint has a positive ignore count and a condition, the
+condition is not checked. Once the ignore count reaches zero,
+@value{GDBN} resumes checking the condition.
+
+You could achieve the effect of the ignore count with a condition such
+as @w{@samp{$foo-- <= 0}} using a debugger convenience variable that
+is decremented each time. @xref{Convenience Vars, ,Convenience
+variables}.
+@end table
+
+@node Break Commands
+@subsection Breakpoint command lists
+
+@cindex breakpoint commands
+You can give any breakpoint (or watchpoint) a series of commands to
+execute when your program stops due to that breakpoint. For example, you
+might want to print the values of certain expressions, or enable other
+breakpoints.
+
+@table @code
+@item commands @r{[}@var{bnum}@r{]}
+@itemx @dots{} @var{command-list} @dots{}
+@itemx end
+@kindex commands
+@kindex end
+Specify a list of commands for breakpoint number @var{bnum}. The commands
+themselves appear on the following lines. Type a line containing just
+@code{end} to terminate the commands.
+
+To remove all commands from a breakpoint, type @code{commands} and
+follow it immediately with @code{end}; that is, give no commands.
+
+With no @var{bnum} argument, @code{commands} refers to the last
+breakpoint or watchpoint set (not to the breakpoint most recently
+encountered).
+@end table
+
+Pressing @key{RET} as a means of repeating the last @value{GDBN} command is
+disabled within a @var{command-list}.
+
+You can use breakpoint commands to start your program up again. Simply
+use the @code{continue} command, or @code{step}, or any other command
+that resumes execution.
+
+Any other commands in the command list, after a command that resumes
+execution, are ignored. This is because any time you resume execution
+(even with a simple @code{next} or @code{step}), you may encounter
+another breakpoint---which could have its own command list, leading to
+ambiguities about which list to execute.
+
+@kindex silent
+If the first command you specify in a command list is @code{silent}, the
+usual message about stopping at a breakpoint is not printed. This may
+be desirable for breakpoints that are to print a specific message and
+then continue. If none of the remaining commands print anything, you
+see no sign that the breakpoint was reached. @code{silent} is
+meaningful only at the beginning of a breakpoint command list.
+
+The commands @code{echo}, @code{output}, and @code{printf} allow you to
+print precisely controlled output, and are often useful in silent
+breakpoints. @xref{Output, ,Commands for controlled output}.
+
+For example, here is how you could use breakpoint commands to print the
+value of @code{x} at entry to @code{foo} whenever @code{x} is positive.
+
+@example
+break foo if x>0
+commands
+silent
+printf "x is %d\n",x
+cont
+end
+@end example
+
+One application for breakpoint commands is to compensate for one bug so
+you can test for another. Put a breakpoint just after the erroneous line
+of code, give it a condition to detect the case in which something
+erroneous has been done, and give it commands to assign correct values
+to any variables that need them. End with the @code{continue} command
+so that your program does not stop, and start with the @code{silent}
+command so that no output is produced. Here is an example:
+
+@example
+break 403
+commands
+silent
+set x = y + 4
+cont
+end
+@end example
+
+@ifclear CONLY
+@node Breakpoint Menus
+@subsection Breakpoint menus
+@cindex overloading
+@cindex symbol overloading
+
+Some programming languages (notably C++) permit a single function name
+to be defined several times, for application in different contexts.
+This is called @dfn{overloading}. When a function name is overloaded,
+@samp{break @var{function}} is not enough to tell @value{GDBN} where you want
+a breakpoint. If you realize this is a problem, you can use
+something like @samp{break @var{function}(@var{types})} to specify which
+particular version of the function you want. Otherwise, @value{GDBN} offers
+you a menu of numbered choices for different possible breakpoints, and
+waits for your selection with the prompt @samp{>}. The first two
+options are always @samp{[0] cancel} and @samp{[1] all}. Typing @kbd{1}
+sets a breakpoint at each definition of @var{function}, and typing
+@kbd{0} aborts the @code{break} command without setting any new
+breakpoints.
+
+For example, the following session excerpt shows an attempt to set a
+breakpoint at the overloaded symbol @code{String::after}.
+We choose three particular definitions of that function name:
+
+@c FIXME! This is likely to change to show arg type lists, at least
+@smallexample
+(@value{GDBP}) b String::after
+[0] cancel
+[1] all
+[2] file:String.cc; line number:867
+[3] file:String.cc; line number:860
+[4] file:String.cc; line number:875
+[5] file:String.cc; line number:853
+[6] file:String.cc; line number:846
+[7] file:String.cc; line number:735
+> 2 4 6
+Breakpoint 1 at 0xb26c: file String.cc, line 867.
+Breakpoint 2 at 0xb344: file String.cc, line 875.
+Breakpoint 3 at 0xafcc: file String.cc, line 846.
+Multiple breakpoints were set.
+Use the "delete" command to delete unwanted
+ breakpoints.
+(@value{GDBP})
+@end smallexample
+@end ifclear
+
+@ifclear BARETARGET
+@node Error in Breakpoints
+@subsection ``Cannot insert breakpoints''
+
+@c FIXME: "cannot insert breakpoints" error, v unclear.
+@c Q in pending mail to Gilmore. ---pesch@cygnus.com, 26mar91
+@c some light may be shed by looking at instances of
+@c ONE_PROCESS_WRITETEXT. But error message seems possible otherwise
+@c too. pesch, 20sep91
+Under some operating systems, breakpoints cannot be used in a program if
+any other process is running that program. In this situation,
+attempting to run or continue a program with a breakpoint causes @value{GDBN}
+to stop the other process.
+
+When this happens, you have three ways to proceed:
+
+@enumerate
+@item
+Remove or disable the breakpoints, then continue.
+
+@item
+Suspend @value{GDBN}, and copy the file containing your program to a new name.
+Resume @value{GDBN} and use the @code{exec-file} command to specify that @value{GDBN}
+should run your program under that name. Then start your program again.
+
+@c FIXME: RMS commented here "Show example". Maybe when someone
+@c explains the first FIXME: in this section...
+
+@item
+Relink your program so that the text segment is nonsharable, using the
+linker option @samp{-N}. The operating system limitation may not apply
+to nonsharable executables.
+@end enumerate
+@end ifclear
+
+@node Continuing and Stepping
+@section Continuing and stepping
+
+@cindex stepping
+@cindex continuing
+@cindex resuming execution
+@dfn{Continuing} means resuming program execution until your program
+completes normally. In contrast, @dfn{stepping} means executing just
+one more ``step'' of your program, where ``step'' may mean either one
+line of source code, or one machine instruction (depending on what
+particular command you use). Either when continuing
+or when stepping, your program may stop even sooner, due to
+@ifset BARETARGET
+a breakpoint.
+@end ifset
+@ifclear BARETARGET
+a breakpoint or a signal. (If due to a signal, you may want to use
+@code{handle}, or use @samp{signal 0} to resume execution.
+@xref{Signals, ,Signals}.)
+@end ifclear
+
+@table @code
+@item continue @r{[}@var{ignore-count}@r{]}
+@itemx c @r{[}@var{ignore-count}@r{]}
+@itemx fg @r{[}@var{ignore-count}@r{]}
+@kindex continue
+@kindex c
+@kindex fg
+Resume program execution, at the address where your program last stopped;
+any breakpoints set at that address are bypassed. The optional argument
+@var{ignore-count} allows you to specify a further number of times to
+ignore a breakpoint at this location; its effect is like that of
+@code{ignore} (@pxref{Conditions, ,Break conditions}).
+
+The argument @var{ignore-count} is meaningful only when your program
+stopped due to a breakpoint. At other times, the argument to
+@code{continue} is ignored.
+
+The synonyms @code{c} and @code{fg} are provided purely for convenience,
+and have exactly the same behavior as @code{continue}.
+@end table
+
+To resume execution at a different place, you can use @code{return}
+(@pxref{Returning, ,Returning from a function}) to go back to the
+calling function; or @code{jump} (@pxref{Jumping, ,Continuing at a
+different address}) to go to an arbitrary location in your program.
+
+A typical technique for using stepping is to set a breakpoint
+@ifclear CONLY
+(@pxref{Breakpoints, ,Breakpoints; watchpoints; and exceptions})
+@end ifclear
+@ifset CONLY
+(@pxref{Breakpoints, ,Breakpoints and watchpoints})
+@end ifset
+at the
+beginning of the function or the section of your program where a
+problem is believed to lie, run your program until it stops at that
+breakpoint, and then step through the suspect area, examining the
+variables that are interesting, until you see the problem happen.
+
+@table @code
+@item step
+@kindex step
+@kindex s
+Continue running your program until control reaches a different source
+line, then stop it and return control to @value{GDBN}. This command is
+abbreviated @code{s}.
+
+@quotation
+@c "without debugging information" is imprecise; actually "without line
+@c numbers in the debugging information". (gcc -g1 has debugging info but
+@c not line numbers). But it seems complex to try to make that
+@c distinction here.
+@emph{Warning:} If you use the @code{step} command while control is
+within a function that was compiled without debugging information,
+execution proceeds until control reaches a function that does have
+debugging information. Likewise, it will not step into a function which
+is compiled without debugging information. To step through functions
+without debugging information, use the @code{stepi} command, described
+below.
+@end quotation
+
+@item step @var{count}
+Continue running as in @code{step}, but do so @var{count} times. If a
+breakpoint is reached,
+@ifclear BARETARGET
+or a signal not related to stepping occurs before @var{count} steps,
+@end ifclear
+stepping stops right away.
+
+@item next @r{[}@var{count}@r{]}
+@kindex next
+@kindex n
+Continue to the next source line in the current (innermost) stack frame.
+Similar to @code{step}, but any function calls appearing within the line
+of code are executed without stopping. Execution stops when control
+reaches a different line of code at the stack level which was executing
+when the @code{next} command was given. This command is abbreviated
+@code{n}.
+
+An argument @var{count} is a repeat count, as for @code{step}.
+
+@code{next} within a function that lacks debugging information acts like
+@code{step}, but any function calls appearing within the code of the
+function are executed without stopping.
+
+@item finish
+@kindex finish
+Continue running until just after function in the selected stack frame
+returns. Print the returned value (if any).
+
+Contrast this with the @code{return} command (@pxref{Returning,
+,Returning from a function}).
+
+@item until
+@kindex until
+@itemx u
+@kindex u
+Continue running until a source line past the current line, in the
+current stack frame, is reached. This command is used to avoid single
+stepping through a loop more than once. It is like the @code{next}
+command, except that when @code{until} encounters a jump, it
+automatically continues execution until the program counter is greater
+than the address of the jump.
+
+This means that when you reach the end of a loop after single stepping
+though it, @code{until} makes your program continue execution until it
+exits the loop. In contrast, a @code{next} command at the end of a loop
+simply steps back to the beginning of the loop, which forces you to step
+through the next iteration.
+
+@code{until} always stops your program if it attempts to exit the current
+stack frame.
+
+@code{until} may produce somewhat counterintuitive results if the order
+of machine code does not match the order of the source lines. For
+example, in the following excerpt from a debugging session, the @code{f}
+(@code{frame}) command shows that execution is stopped at line
+@code{206}; yet when we use @code{until}, we get to line @code{195}:
+
+@example
+(@value{GDBP}) f
+#0 main (argc=4, argv=0xf7fffae8) at m4.c:206
+206 expand_input();
+(@value{GDBP}) until
+195 for ( ; argc > 0; NEXTARG) @{
+@end example
+
+This happened because, for execution efficiency, the compiler had
+generated code for the loop closure test at the end, rather than the
+start, of the loop---even though the test in a C @code{for}-loop is
+written before the body of the loop. The @code{until} command appeared
+to step back to the beginning of the loop when it advanced to this
+expression; however, it has not really gone to an earlier
+statement---not in terms of the actual machine code.
+
+@code{until} with no argument works by means of single
+instruction stepping, and hence is slower than @code{until} with an
+argument.
+
+@item until @var{location}
+@itemx u @var{location}
+Continue running your program until either the specified location is
+reached, or the current stack frame returns. @var{location} is any of
+the forms of argument acceptable to @code{break} (@pxref{Set Breaks,
+,Setting breakpoints}). This form of the command uses breakpoints,
+and hence is quicker than @code{until} without an argument.
+
+@item stepi
+@itemx si
+@kindex stepi
+@kindex si
+Execute one machine instruction, then stop and return to the debugger.
+
+It is often useful to do @samp{display/i $pc} when stepping by machine
+instructions. This makes @value{GDBN} automatically display the next
+instruction to be executed, each time your program stops. @xref{Auto
+Display,, Automatic display}.
+
+An argument is a repeat count, as in @code{step}.
+
+@need 750
+@item nexti
+@itemx ni
+@kindex nexti
+@kindex ni
+Execute one machine instruction, but if it is a function call,
+proceed until the function returns.
+
+An argument is a repeat count, as in @code{next}.
+@end table
+
+@ifset POSIX
+@node Signals
+@section Signals
+@cindex signals
+
+A signal is an asynchronous event that can happen in a program. The
+operating system defines the possible kinds of signals, and gives each
+kind a name and a number. For example, in Unix @code{SIGINT} is the
+signal a program gets when you type an interrupt (often @kbd{C-c});
+@code{SIGSEGV} is the signal a program gets from referencing a place in
+memory far away from all the areas in use; @code{SIGALRM} occurs when
+the alarm clock timer goes off (which happens only if your program has
+requested an alarm).
+
+@cindex fatal signals
+Some signals, including @code{SIGALRM}, are a normal part of the
+functioning of your program. Others, such as @code{SIGSEGV}, indicate
+errors; these signals are @dfn{fatal} (kill your program immediately) if the
+program has not specified in advance some other way to handle the signal.
+@code{SIGINT} does not indicate an error in your program, but it is normally
+fatal so it can carry out the purpose of the interrupt: to kill the program.
+
+@value{GDBN} has the ability to detect any occurrence of a signal in your
+program. You can tell @value{GDBN} in advance what to do for each kind of
+signal.
+
+@cindex handling signals
+Normally, @value{GDBN} is set up to ignore non-erroneous signals like @code{SIGALRM}
+(so as not to interfere with their role in the functioning of your program)
+but to stop your program immediately whenever an error signal happens.
+You can change these settings with the @code{handle} command.
+
+@table @code
+@item info signals
+@kindex info signals
+Print a table of all the kinds of signals and how @value{GDBN} has been told to
+handle each one. You can use this to see the signal numbers of all
+the defined types of signals.
+
+@item handle @var{signal} @var{keywords}@dots{}
+@kindex handle
+Change the way @value{GDBN} handles signal @var{signal}. @var{signal} can be the
+number of a signal or its name (with or without the @samp{SIG} at the
+beginning). The @var{keywords} say what change to make.
+@end table
+
+@c @group
+The keywords allowed by the @code{handle} command can be abbreviated.
+Their full names are:
+
+@table @code
+@item nostop
+@value{GDBN} should not stop your program when this signal happens. It may
+still print a message telling you that the signal has come in.
+
+@item stop
+@value{GDBN} should stop your program when this signal happens. This implies
+the @code{print} keyword as well.
+
+@item print
+@value{GDBN} should print a message when this signal happens.
+
+@item noprint
+@value{GDBN} should not mention the occurrence of the signal at all. This
+implies the @code{nostop} keyword as well.
+
+@item pass
+@value{GDBN} should allow your program to see this signal; your program
+can handle the signal, or else it may terminate if the signal is fatal
+and not handled.
+
+@item nopass
+@value{GDBN} should not allow your program to see this signal.
+@end table
+@c @end group
+
+When a signal stops your program, the signal is not visible until you
+continue. Your program sees the signal then, if @code{pass} is in
+effect for the signal in question @emph{at that time}. In other words,
+after @value{GDBN} reports a signal, you can use the @code{handle}
+command with @code{pass} or @code{nopass} to control whether your
+program sees that signal when you continue.
+
+You can also use the @code{signal} command to prevent your program from
+seeing a signal, or cause it to see a signal it normally would not see,
+or to give it any signal at any time. For example, if your program stopped
+due to some sort of memory reference error, you might store correct
+values into the erroneous variables and continue, hoping to see more
+execution; but your program would probably terminate immediately as
+a result of the fatal signal once it saw the signal. To prevent this,
+you can continue with @samp{signal 0}. @xref{Signaling, ,Giving your
+program a signal}.
+@end ifset
+
+@ifclear BARETARGET
+@node Thread Stops
+@section Stopping and starting multi-thread programs
+
+When your program has multiple threads (@pxref{Threads,, Debugging
+programs with multiple threads}), you can choose whether to set
+breakpoints on all threads, or on a particular thread.
+
+@table @code
+@cindex breakpoints and threads
+@cindex thread breakpoints
+@kindex break @dots{} thread @var{threadno}
+@item break @var{linespec} thread @var{threadno}
+@itemx break @var{linespec} thread @var{threadno} if @dots{}
+Use the qualifier @samp{thread @var{threadno}} with a breakpoint command
+to specify that you only want @value{GDBN} to stop the program when a
+particular thread reaches this breakpoint. @var{threadno} is one of the
+numeric thread identifiers assigned by @value{GDBN}, shown in the first
+column of the @samp{info threads} display.
+
+If you do not specify @samp{thread @var{threadno}} when you set a
+breakpoint, the breakpoint applies to @emph{all} threads of your
+program.
+
+You can use the @code{thread} qualifier on conditional breakpoints as
+well; in this case, place @samp{thread @var{threadno}} before the
+breakpoint condition, like this:
+
+@smallexample
+(gdb) break frik.c:13 thread 28 if bartab > lim
+@end smallexample
+@end table
+
+@cindex stopped threads
+@cindex threads, stopped
+Whenever your program stops under @value{GDBN} for any reason,
+@emph{all} threads of execution stop, not just the current thread. This
+allows you to examine the overall state of the program, including
+switching between threads, without worrying that things may change
+underfoot.
+
+@cindex continuing threads
+@cindex threads, continuing
+Conversely, whenever you restart the program, @emph{all} threads start
+executing. @emph{This is true even when single-stepping} with commands
+like @code{step} or @code{next}.
+
+In particular, @value{GDBN} cannot single-step all threads in lockstep.
+Since thread scheduling is up to your debugging target's operating
+system (not controlled by @value{GDBN}), other threads may
+execute more than one statement while the current thread completes a
+single step. Moreover, in general other threads stop in the middle of a
+statement, rather than at a clean statement boundary, when the program
+stops.
+
+You might even find your program stopped in another thread after
+continuing or even single-stepping. This happens whenever some other
+thread runs into a breakpoint, a signal, or an exception before the
+first thread completes whatever you requested.
+@end ifclear
+
+@node Stack
+@chapter Examining the Stack
+
+When your program has stopped, the first thing you need to know is where it
+stopped and how it got there.
+
+@cindex call stack
+Each time your program performs a function call, the information about
+where in your program the call was made from is saved in a block of data
+called a @dfn{stack frame}. The frame also contains the arguments of the
+call and the local variables of the function that was called. All the
+stack frames are allocated in a region of memory called the @dfn{call
+stack}.
+
+When your program stops, the @value{GDBN} commands for examining the
+stack allow you to see all of this information.
+
+@cindex selected frame
+One of the stack frames is @dfn{selected} by @value{GDBN} and many
+@value{GDBN} commands refer implicitly to the selected frame. In
+particular, whenever you ask @value{GDBN} for the value of a variable in
+your program, the value is found in the selected frame. There are
+special @value{GDBN} commands to select whichever frame you are
+interested in.
+
+When your program stops, @value{GDBN} automatically selects the
+currently executing frame and describes it briefly as the @code{frame}
+command does (@pxref{Frame Info, ,Information about a frame}).
+
+@menu
+* Frames:: Stack frames
+* Backtrace:: Backtraces
+* Selection:: Selecting a frame
+* Frame Info:: Information on a frame
+@ifset MIPS
+* MIPS Stack:: MIPS machines and the function stack
+@end ifset
+@end menu
+
+@node Frames
+@section Stack frames
+
+@cindex frame
+@cindex stack frame
+The call stack is divided up into contiguous pieces called @dfn{stack
+frames}, or @dfn{frames} for short; each frame is the data associated
+with one call to one function. The frame contains the arguments given
+to the function, the function's local variables, and the address at
+which the function is executing.
+
+@cindex initial frame
+@cindex outermost frame
+@cindex innermost frame
+When your program is started, the stack has only one frame, that of the
+function @code{main}. This is called the @dfn{initial} frame or the
+@dfn{outermost} frame. Each time a function is called, a new frame is
+made. Each time a function returns, the frame for that function invocation
+is eliminated. If a function is recursive, there can be many frames for
+the same function. The frame for the function in which execution is
+actually occurring is called the @dfn{innermost} frame. This is the most
+recently created of all the stack frames that still exist.
+
+@cindex frame pointer
+Inside your program, stack frames are identified by their addresses. A
+stack frame consists of many bytes, each of which has its own address; each
+kind of computer has a convention for choosing one of those bytes whose
+address serves as the address of the frame. Usually this address is kept
+in a register called the @dfn{frame pointer register} while execution is
+going on in that frame.
+
+@cindex frame number
+@value{GDBN} assigns numbers to all existing stack frames, starting with
+zero for the innermost frame, one for the frame that called it,
+and so on upward. These numbers do not really exist in your program;
+they are assigned by @value{GDBN} to give you a way of designating stack
+frames in @value{GDBN} commands.
+
+@c below produces an acceptable overful hbox. --mew 13aug1993
+@cindex frameless execution
+Some compilers provide a way to compile functions so that they operate
+without stack frames. (For example, the @code{@value{GCC}} option
+@samp{-fomit-frame-pointer} generates functions without a frame.)
+This is occasionally done with heavily used library functions to save
+the frame setup time. @value{GDBN} has limited facilities for dealing
+with these function invocations. If the innermost function invocation
+has no stack frame, @value{GDBN} nevertheless regards it as though
+it had a separate frame, which is numbered zero as usual, allowing
+correct tracing of the function call chain. However, @value{GDBN} has
+no provision for frameless functions elsewhere in the stack.
+
+@node Backtrace
+@section Backtraces
+
+A backtrace is a summary of how your program got where it is. It shows one
+line per frame, for many frames, starting with the currently executing
+frame (frame zero), followed by its caller (frame one), and on up the
+stack.
+
+@table @code
+@item backtrace
+@itemx bt
+@kindex backtrace
+@kindex bt
+Print a backtrace of the entire stack: one line per frame for all
+frames in the stack.
+
+You can stop the backtrace at any time by typing the system interrupt
+character, normally @kbd{C-c}.
+
+@item backtrace @var{n}
+@itemx bt @var{n}
+Similar, but print only the innermost @var{n} frames.
+
+@item backtrace -@var{n}
+@itemx bt -@var{n}
+Similar, but print only the outermost @var{n} frames.
+@end table
+
+@kindex where
+@kindex info stack
+@kindex info s
+The names @code{where} and @code{info stack} (abbreviated @code{info s})
+are additional aliases for @code{backtrace}.
+
+Each line in the backtrace shows the frame number and the function name.
+The program counter value is also shown---unless you use @code{set
+print address off}. The backtrace also shows the source file name and
+line number, as well as the arguments to the function. The program
+counter value is omitted if it is at the beginning of the code for that
+line number.
+
+Here is an example of a backtrace. It was made with the command
+@samp{bt 3}, so it shows the innermost three frames.
+
+@smallexample
+@group
+#0 m4_traceon (obs=0x24eb0, argc=1, argv=0x2b8c8)
+ at builtin.c:993
+#1 0x6e38 in expand_macro (sym=0x2b600) at macro.c:242
+#2 0x6840 in expand_token (obs=0x0, t=177664, td=0xf7fffb08)
+ at macro.c:71
+(More stack frames follow...)
+@end group
+@end smallexample
+
+@noindent
+The display for frame zero does not begin with a program counter
+value, indicating that your program has stopped at the beginning of the
+code for line @code{993} of @code{builtin.c}.
+
+@node Selection
+@section Selecting a frame
+
+Most commands for examining the stack and other data in your program work on
+whichever stack frame is selected at the moment. Here are the commands for
+selecting a stack frame; all of them finish by printing a brief description
+of the stack frame just selected.
+
+@table @code
+@item frame @var{n}
+@itemx f @var{n}
+@kindex frame
+@kindex f
+Select frame number @var{n}. Recall that frame zero is the innermost
+(currently executing) frame, frame one is the frame that called the
+innermost one, and so on. The highest-numbered frame is the one for
+@code{main}.
+
+@item frame @var{addr}
+@itemx f @var{addr}
+Select the frame at address @var{addr}. This is useful mainly if the
+chaining of stack frames has been damaged by a bug, making it
+impossible for @value{GDBN} to assign numbers properly to all frames. In
+addition, this can be useful when your program has multiple stacks and
+switches between them.
+
+@ifclear H8EXCLUSIVE
+On the SPARC architecture, @code{frame} needs two addresses to
+select an arbitrary frame: a frame pointer and a stack pointer.
+
+On the MIPS and Alpha architecture, it needs two addresses: a stack
+pointer and a program counter.
+
+On the 29k architecture, it needs three addresses: a register stack
+pointer, a program counter, and a memory stack pointer.
+@c note to future updaters: this is conditioned on a flag
+@c SETUP_ARBITRARY_FRAME in the tm-*.h files. The above is up to date
+@c as of 27 Jan 1994.
+@end ifclear
+
+@item up @var{n}
+@kindex up
+Move @var{n} frames up the stack. For positive numbers @var{n}, this
+advances toward the outermost frame, to higher frame numbers, to frames
+that have existed longer. @var{n} defaults to one.
+
+@item down @var{n}
+@kindex down
+@kindex do
+Move @var{n} frames down the stack. For positive numbers @var{n}, this
+advances toward the innermost frame, to lower frame numbers, to frames
+that were created more recently. @var{n} defaults to one. You may
+abbreviate @code{down} as @code{do}.
+@end table
+
+All of these commands end by printing two lines of output describing the
+frame. The first line shows the frame number, the function name, the
+arguments, and the source file and line number of execution in that
+frame. The second line shows the text of that source line.
+
+@need 1000
+For example:
+
+@smallexample
+@group
+(@value{GDBP}) up
+#1 0x22f0 in main (argc=1, argv=0xf7fffbf4, env=0xf7fffbfc)
+ at env.c:10
+10 read_input_file (argv[i]);
+@end group
+@end smallexample
+
+After such a printout, the @code{list} command with no arguments
+prints ten lines centered on the point of execution in the frame.
+@xref{List, ,Printing source lines}.
+
+@table @code
+@item up-silently @var{n}
+@itemx down-silently @var{n}
+@kindex down-silently
+@kindex up-silently
+These two commands are variants of @code{up} and @code{down},
+respectively; they differ in that they do their work silently, without
+causing display of the new frame. They are intended primarily for use
+in @value{GDBN} command scripts, where the output might be unnecessary and
+distracting.
+@end table
+
+@node Frame Info
+@section Information about a frame
+
+There are several other commands to print information about the selected
+stack frame.
+
+@table @code
+@item frame
+@itemx f
+When used without any argument, this command does not change which
+frame is selected, but prints a brief description of the currently
+selected stack frame. It can be abbreviated @code{f}. With an
+argument, this command is used to select a stack frame.
+@xref{Selection, ,Selecting a frame}.
+
+@item info frame
+@itemx info f
+@kindex info frame
+@kindex info f
+This command prints a verbose description of the selected stack frame,
+including the address of the frame, the addresses of the next frame down
+(called by this frame) and the next frame up (caller of this frame), the
+language that the source code corresponding to this frame was written in,
+the address of the frame's arguments, the program counter saved in it
+(the address of execution in the caller frame), and which registers
+were saved in the frame. The verbose description is useful when
+something has gone wrong that has made the stack format fail to fit
+the usual conventions.
+
+@item info frame @var{addr}
+@itemx info f @var{addr}
+Print a verbose description of the frame at address @var{addr}, without
+selecting that frame. The selected frame remains unchanged by this
+command. This requires the same kind of address (more than one for some
+architectures) that you specify in the @code{frame} command.
+@xref{Selection, ,Selecting a frame}.
+
+@item info args
+@kindex info args
+Print the arguments of the selected frame, each on a separate line.
+
+@item info locals
+@kindex info locals
+Print the local variables of the selected frame, each on a separate
+line. These are all variables (declared either static or automatic)
+accessible at the point of execution of the selected frame.
+
+@ifclear CONLY
+@item info catch
+@kindex info catch
+@cindex catch exceptions
+@cindex exception handlers
+Print a list of all the exception handlers that are active in the
+current stack frame at the current point of execution. To see other
+exception handlers, visit the associated frame (using the @code{up},
+@code{down}, or @code{frame} commands); then type @code{info catch}.
+@xref{Exception Handling, ,Breakpoints and exceptions}.
+@end ifclear
+@end table
+
+@ifset MIPS
+@node MIPS Stack
+@section MIPS machines and the function stack
+
+@cindex stack on MIPS
+@cindex MIPS stack
+MIPS based computers use an unusual stack frame, which sometimes
+requires @value{GDBN} to search backward in the object code to find the
+beginning of a function.
+
+@cindex response time, MIPS debugging
+To improve response time (especially for embedded applications, where
+@value{GDBN} may be restricted to a slow serial line for this search)
+you may want to limit the size of this search, using one of these
+commands:
+@c FIXME! So what happens when GDB does *not* find the beginning of a
+@c function?
+
+@cindex @code{heuristic-fence-post} (MIPS)
+@table @code
+@item set heuristic-fence-post @var{limit}
+Restrict @value{GDBN} to examining at most @var{limit} bytes in its search
+for the beginning of a function. A value of @code{0} (the default)
+means there is no limit.
+
+@item show heuristic-fence-post
+Display the current limit.
+@end table
+
+@noindent
+These commands are available @emph{only} when @value{GDBN} is configured
+for debugging programs on MIPS processors.
+@end ifset
+
+@node Source
+@chapter Examining Source Files
+
+@value{GDBN} can print parts of your program's source, since the debugging
+information recorded in the program tells @value{GDBN} what source files were
+used to build it. When your program stops, @value{GDBN} spontaneously prints
+the line where it stopped. Likewise, when you select a stack frame
+(@pxref{Selection, ,Selecting a frame}), @value{GDBN} prints the line where
+execution in that frame has stopped. You can print other portions of
+source files by explicit command.
+
+@ifclear DOSHOST
+If you use @value{GDBN} through its GNU Emacs interface, you may prefer to use
+Emacs facilities to view source; @pxref{Emacs, ,Using @value{GDBN} under GNU
+Emacs}.
+@end ifclear
+
+@menu
+* List:: Printing source lines
+@ifclear DOSHOST
+* Search:: Searching source files
+@end ifclear
+
+* Source Path:: Specifying source directories
+* Machine Code:: Source and machine code
+@end menu
+
+@node List
+@section Printing source lines
+
+@kindex list
+@kindex l
+To print lines from a source file, use the @code{list} command
+(abbreviated @code{l}). There are several ways to specify what part
+of the file you want to print.
+
+Here are the forms of the @code{list} command most commonly used:
+
+@table @code
+@item list @var{linenum}
+Print lines centered around line number @var{linenum} in the
+current source file.
+
+@item list @var{function}
+Print lines centered around the beginning of function
+@var{function}.
+
+@item list
+Print more lines. If the last lines printed were printed with a
+@code{list} command, this prints lines following the last lines
+printed; however, if the last line printed was a solitary line printed
+as part of displaying a stack frame (@pxref{Stack, ,Examining the
+Stack}), this prints lines centered around that line.
+
+@item list -
+Print lines just before the lines last printed.
+@end table
+
+By default, @value{GDBN} prints ten source lines with any of these forms of
+the @code{list} command. You can change this using @code{set listsize}:
+
+@table @code
+@item set listsize @var{count}
+@kindex set listsize
+Make the @code{list} command display @var{count} source lines (unless
+the @code{list} argument explicitly specifies some other number).
+
+@item show listsize
+@kindex show listsize
+Display the number of lines that @code{list} prints.
+@end table
+
+Repeating a @code{list} command with @key{RET} discards the argument,
+so it is equivalent to typing just @code{list}. This is more useful
+than listing the same lines again. An exception is made for an
+argument of @samp{-}; that argument is preserved in repetition so that
+each repetition moves up in the source file.
+
+@cindex linespec
+In general, the @code{list} command expects you to supply zero, one or two
+@dfn{linespecs}. Linespecs specify source lines; there are several ways
+of writing them but the effect is always to specify some source line.
+Here is a complete description of the possible arguments for @code{list}:
+
+@table @code
+@item list @var{linespec}
+Print lines centered around the line specified by @var{linespec}.
+
+@item list @var{first},@var{last}
+Print lines from @var{first} to @var{last}. Both arguments are
+linespecs.
+
+@item list ,@var{last}
+Print lines ending with @var{last}.
+
+@item list @var{first},
+Print lines starting with @var{first}.
+
+@item list +
+Print lines just after the lines last printed.
+
+@item list -
+Print lines just before the lines last printed.
+
+@item list
+As described in the preceding table.
+@end table
+
+Here are the ways of specifying a single source line---all the
+kinds of linespec.
+
+@table @code
+@item @var{number}
+Specifies line @var{number} of the current source file.
+When a @code{list} command has two linespecs, this refers to
+the same source file as the first linespec.
+
+@item +@var{offset}
+Specifies the line @var{offset} lines after the last line printed.
+When used as the second linespec in a @code{list} command that has
+two, this specifies the line @var{offset} lines down from the
+first linespec.
+
+@item -@var{offset}
+Specifies the line @var{offset} lines before the last line printed.
+
+@item @var{filename}:@var{number}
+Specifies line @var{number} in the source file @var{filename}.
+
+@item @var{function}
+@c FIXME: "of the open-brace" is C-centric. When we add other langs...
+Specifies the line of the open-brace that begins the body of the
+function @var{function}.
+
+@item @var{filename}:@var{function}
+Specifies the line of the open-brace that begins the body of the
+function @var{function} in the file @var{filename}. You only need the
+file name with a function name to avoid ambiguity when there are
+identically named functions in different source files.
+
+@item *@var{address}
+Specifies the line containing the program address @var{address}.
+@var{address} may be any expression.
+@end table
+
+@ifclear DOSHOST
+@node Search
+@section Searching source files
+@cindex searching
+@kindex reverse-search
+
+There are two commands for searching through the current source file for a
+regular expression.
+
+@table @code
+@item forward-search @var{regexp}
+@itemx search @var{regexp}
+@kindex search
+@kindex forward-search
+The command @samp{forward-search @var{regexp}} checks each line,
+starting with the one following the last line listed, for a match for
+@var{regexp}. It lists the line that is found. You can use
+synonym @samp{search @var{regexp}} or abbreviate the command name as
+@code{fo}.
+
+@item reverse-search @var{regexp}
+The command @samp{reverse-search @var{regexp}} checks each line, starting
+with the one before the last line listed and going backward, for a match
+for @var{regexp}. It lists the line that is found. You can abbreviate
+this command as @code{rev}.
+@end table
+@end ifclear
+
+@node Source Path
+@section Specifying source directories
+
+@cindex source path
+@cindex directories for source files
+Executable programs sometimes do not record the directories of the source
+files from which they were compiled, just the names. Even when they do,
+the directories could be moved between the compilation and your debugging
+session. @value{GDBN} has a list of directories to search for source files;
+this is called the @dfn{source path}. Each time @value{GDBN} wants a source file,
+it tries all the directories in the list, in the order they are present
+in the list, until it finds a file with the desired name. Note that
+the executable search path is @emph{not} used for this purpose. Neither is
+the current working directory, unless it happens to be in the source
+path.
+
+If @value{GDBN} cannot find a source file in the source path, and the
+object program records a directory, @value{GDBN} tries that directory
+too. If the source path is empty, and there is no record of the
+compilation directory, @value{GDBN} looks in the current directory as a
+last resort.
+
+Whenever you reset or rearrange the source path, @value{GDBN} clears out
+any information it has cached about where source files are found and where
+each line is in the file.
+
+@kindex directory
+When you start @value{GDBN}, its source path is empty.
+To add other directories, use the @code{directory} command.
+
+@table @code
+@item directory @var{dirname} @dots{}
+Add directory @var{dirname} to the front of the source path. Several
+directory names may be given to this command, separated by @samp{:} or
+whitespace. You may specify a directory that is already in the source
+path; this moves it forward, so @value{GDBN} searches it sooner.
+
+@kindex cdir
+@kindex cwd
+@kindex $cdir
+@kindex $cwd
+@cindex compilation directory
+@cindex current directory
+@cindex working directory
+@cindex directory, current
+@cindex directory, compilation
+You can use the string @samp{$cdir} to refer to the compilation
+directory (if one is recorded), and @samp{$cwd} to refer to the current
+working directory. @samp{$cwd} is not the same as @samp{.}---the former
+tracks the current working directory as it changes during your @value{GDBN}
+session, while the latter is immediately expanded to the current
+directory at the time you add an entry to the source path.
+
+@item directory
+Reset the source path to empty again. This requires confirmation.
+
+@c RET-repeat for @code{directory} is explicitly disabled, but since
+@c repeating it would be a no-op we do not say that. (thanks to RMS)
+
+@item show directories
+@kindex show directories
+Print the source path: show which directories it contains.
+@end table
+
+If your source path is cluttered with directories that are no longer of
+interest, @value{GDBN} may sometimes cause confusion by finding the wrong
+versions of source. You can correct the situation as follows:
+
+@enumerate
+@item
+Use @code{directory} with no argument to reset the source path to empty.
+
+@item
+Use @code{directory} with suitable arguments to reinstall the
+directories you want in the source path. You can add all the
+directories in one command.
+@end enumerate
+
+@node Machine Code
+@section Source and machine code
+
+You can use the command @code{info line} to map source lines to program
+addresses (and vice versa), and the command @code{disassemble} to display
+a range of addresses as machine instructions.
+
+@table @code
+@item info line @var{linespec}
+@kindex info line
+Print the starting and ending addresses of the compiled code for
+source line @var{linespec}. You can specify source lines in any of
+the ways understood by the @code{list} command (@pxref{List, ,Printing
+source lines}).
+@end table
+
+For example, we can use @code{info line} to discover the location of
+the object code for the first line of function
+@code{m4_changequote}:
+
+@smallexample
+(@value{GDBP}) info line m4_changecom
+Line 895 of "builtin.c" starts at pc 0x634c and ends at 0x6350.
+@end smallexample
+
+@noindent
+We can also inquire (using @code{*@var{addr}} as the form for
+@var{linespec}) what source line covers a particular address:
+@smallexample
+(@value{GDBP}) info line *0x63ff
+Line 926 of "builtin.c" starts at pc 0x63e4 and ends at 0x6404.
+@end smallexample
+
+@cindex @code{$_} and @code{info line}
+After @code{info line}, the default address for the @code{x} command
+is changed to the starting address of the line, so that @samp{x/i} is
+sufficient to begin examining the machine code (@pxref{Memory,
+,Examining memory}). Also, this address is saved as the value of the
+convenience variable @code{$_} (@pxref{Convenience Vars, ,Convenience
+variables}).
+
+@table @code
+@kindex disassemble
+@item disassemble
+@cindex assembly instructions
+@cindex instructions, assembly
+@cindex machine instructions
+@cindex listing machine instructions
+This specialized command dumps a range of memory as machine
+instructions. The default memory range is the function surrounding the
+program counter of the selected frame. A single argument to this
+command is a program counter value; @value{GDBN} dumps the function
+surrounding this value. Two arguments specify a range of addresses
+(first inclusive, second exclusive) to dump.
+@end table
+
+@ifclear H8EXCLUSIVE
+We can use @code{disassemble} to inspect the object code
+range shown in the last @code{info line} example (the example
+shows SPARC machine instructions):
+
+
+@smallexample
+(@value{GDBP}) disas 0x63e4 0x6404
+Dump of assembler code from 0x63e4 to 0x6404:
+0x63e4 <builtin_init+5340>: ble 0x63f8 <builtin_init+5360>
+0x63e8 <builtin_init+5344>: sethi %hi(0x4c00), %o0
+0x63ec <builtin_init+5348>: ld [%i1+4], %o0
+0x63f0 <builtin_init+5352>: b 0x63fc <builtin_init+5364>
+0x63f4 <builtin_init+5356>: ld [%o0+4], %o0
+0x63f8 <builtin_init+5360>: or %o0, 0x1a4, %o0
+0x63fc <builtin_init+5364>: call 0x9288 <path_search>
+0x6400 <builtin_init+5368>: nop
+End of assembler dump.
+@end smallexample
+@end ifclear
+
+@ifset H8EXCLUSIVE
+For example, here is the beginning of the output for the
+disassembly of a function @code{fact}:
+
+
+@smallexample
+(@value{GDBP}) disas fact
+Dump of assembler code for function fact:
+to 0x808c:
+0x802c <fact>: 6d f2 mov.w r2,@@-r7
+0x802e <fact+2>: 6d f3 mov.w r3,@@-r7
+0x8030 <fact+4>: 6d f6 mov.w r6,@@-r7
+0x8032 <fact+6>: 0d 76 mov.w r7,r6
+0x8034 <fact+8>: 6f 70 00 08 mov.w @@(0x8,r7),r0
+0x8038 <fact+12> 19 11 sub.w r1,r1
+ .
+ .
+ .
+@end smallexample
+@end ifset
+
+@node Data
+@chapter Examining Data
+
+@cindex printing data
+@cindex examining data
+@kindex print
+@kindex inspect
+@c "inspect" is not quite a synonym if you are using Epoch, which we do not
+@c document because it is nonstandard... Under Epoch it displays in a
+@c different window or something like that.
+The usual way to examine data in your program is with the @code{print}
+command (abbreviated @code{p}), or its synonym @code{inspect}.
+@ifclear CONLY
+It evaluates and prints the value of an expression of the language your
+program is written in (@pxref{Languages, ,Using @value{GDBN} with Different
+Languages}).
+@end ifclear
+
+@table @code
+@item print @var{exp}
+@itemx print /@var{f} @var{exp}
+@var{exp} is an expression (in the source language). By default the
+value of @var{exp} is printed in a format appropriate to its data type;
+you can choose a different format by specifying @samp{/@var{f}}, where
+@var{f} is a letter specifying the format; @pxref{Output Formats,,Output
+formats}.
+
+@item print
+@itemx print /@var{f}
+If you omit @var{exp}, @value{GDBN} displays the last value again (from the
+@dfn{value history}; @pxref{Value History, ,Value history}). This allows you to
+conveniently inspect the same value in an alternative format.
+@end table
+
+A more low-level way of examining data is with the @code{x} command.
+It examines data in memory at a specified address and prints it in a
+specified format. @xref{Memory, ,Examining memory}.
+
+If you are interested in information about types, or about how the fields
+of a struct
+@ifclear CONLY
+or class
+@end ifclear
+are declared, use the @code{ptype @var{exp}}
+command rather than @code{print}. @xref{Symbols, ,Examining the Symbol Table}.
+
+@menu
+* Expressions:: Expressions
+* Variables:: Program variables
+* Arrays:: Artificial arrays
+* Output Formats:: Output formats
+* Memory:: Examining memory
+* Auto Display:: Automatic display
+* Print Settings:: Print settings
+* Value History:: Value history
+* Convenience Vars:: Convenience variables
+* Registers:: Registers
+@ifclear HAVE-FLOAT
+* Floating Point Hardware:: Floating point hardware
+@end ifclear
+@end menu
+
+@node Expressions
+@section Expressions
+
+@cindex expressions
+@code{print} and many other @value{GDBN} commands accept an expression and
+compute its value. Any kind of constant, variable or operator defined
+by the programming language you are using is valid in an expression in
+@value{GDBN}. This includes conditional expressions, function calls, casts
+and string constants. It unfortunately does not include symbols defined
+by preprocessor @code{#define} commands.
+
+@ifclear CONLY
+Because C is so widespread, most of the expressions shown in examples in
+this manual are in C. @xref{Languages, , Using @value{GDBN} with Different
+Languages}, for information on how to use expressions in other
+languages.
+
+In this section, we discuss operators that you can use in @value{GDBN}
+expressions regardless of your programming language.
+
+Casts are supported in all languages, not just in C, because it is so
+useful to cast a number into a pointer so as to examine a structure
+at that address in memory.
+@c FIXME: casts supported---Mod2 true?
+@end ifclear
+
+@value{GDBN} supports these operators in addition to those of programming
+languages:
+
+@table @code
+@item @@
+@samp{@@} is a binary operator for treating parts of memory as arrays.
+@xref{Arrays, ,Artificial arrays}, for more information.
+
+@item ::
+@samp{::} allows you to specify a variable in terms of the file or
+function where it is defined. @xref{Variables, ,Program variables}.
+
+@item @{@var{type}@} @var{addr}
+@cindex @{@var{type}@}
+@cindex type casting memory
+@cindex memory, viewing as typed object
+@cindex casts, to view memory
+Refers to an object of type @var{type} stored at address @var{addr} in
+memory. @var{addr} may be any expression whose value is an integer or
+pointer (but parentheses are required around binary operators, just as in
+a cast). This construct is allowed regardless of what kind of data is
+normally supposed to reside at @var{addr}.
+@end table
+
+@node Variables
+@section Program variables
+
+The most common kind of expression to use is the name of a variable
+in your program.
+
+Variables in expressions are understood in the selected stack frame
+(@pxref{Selection, ,Selecting a frame}); they must either be global
+(or static) or be visible according to the scope rules of the
+programming language from the point of execution in that frame. This
+means that in the function
+
+@example
+foo (a)
+ int a;
+@{
+ bar (a);
+ @{
+ int b = test ();
+ bar (b);
+ @}
+@}
+@end example
+
+@noindent
+you can examine and use the variable @code{a} whenever your program is
+executing within the function @code{foo}, but you can only use or
+examine the variable @code{b} while your program is executing inside
+the block where @code{b} is declared.
+
+@cindex variable name conflict
+There is an exception: you can refer to a variable or function whose
+scope is a single source file even if the current execution point is not
+in this file. But it is possible to have more than one such variable or
+function with the same name (in different source files). If that
+happens, referring to that name has unpredictable effects. If you wish,
+you can specify a static variable in a particular function or file,
+using the colon-colon notation:
+
+@cindex colon-colon
+@iftex
+@c info cannot cope with a :: index entry, but why deprive hard copy readers?
+@kindex ::
+@end iftex
+@example
+@var{file}::@var{variable}
+@var{function}::@var{variable}
+@end example
+
+@noindent
+Here @var{file} or @var{function} is the name of the context for the
+static @var{variable}. In the case of file names, you can use quotes to
+make sure @value{GDBN} parses the file name as a single word---for example,
+to print a global value of @code{x} defined in @file{f2.c}:
+
+@example
+(@value{GDBP}) p 'f2.c'::x
+@end example
+
+@ifclear CONLY
+@cindex C++ scope resolution
+This use of @samp{::} is very rarely in conflict with the very similar
+use of the same notation in C++. @value{GDBN} also supports use of the C++
+scope resolution operator in @value{GDBN} expressions.
+@c FIXME: Um, so what happens in one of those rare cases where it's in
+@c conflict?? --mew
+@end ifclear
+
+@cindex wrong values
+@cindex variable values, wrong
+@quotation
+@emph{Warning:} Occasionally, a local variable may appear to have the
+wrong value at certain points in a function---just after entry to a new
+scope, and just before exit.
+@end quotation
+You may see this problem when you are stepping by machine instructions.
+This is because on most machines, it takes more than one instruction to
+set up a stack frame (including local variable definitions); if you are
+stepping by machine instructions, variables may appear to have the wrong
+values until the stack frame is completely built. On exit, it usually
+also takes more than one machine instruction to destroy a stack frame;
+after you begin stepping through that group of instructions, local
+variable definitions may be gone.
+
+@node Arrays
+@section Artificial arrays
+
+@cindex artificial array
+@kindex @@
+It is often useful to print out several successive objects of the
+same type in memory; a section of an array, or an array of
+dynamically determined size for which only a pointer exists in the
+program.
+
+You can do this by referring to a contiguous span of memory as an
+@dfn{artificial array}, using the binary operator @samp{@@}. The left
+operand of @samp{@@} should be the first element of the desired array,
+as an individual object. The right operand should be the desired length
+of the array. The result is an array value whose elements are all of
+the type of the left argument. The first element is actually the left
+argument; the second element comes from bytes of memory immediately
+following those that hold the first element, and so on. Here is an
+example. If a program says
+
+@example
+int *array = (int *) malloc (len * sizeof (int));
+@end example
+
+@noindent
+you can print the contents of @code{array} with
+
+@example
+p *array@@len
+@end example
+
+The left operand of @samp{@@} must reside in memory. Array values made
+with @samp{@@} in this way behave just like other arrays in terms of
+subscripting, and are coerced to pointers when used in expressions.
+Artificial arrays most often appear in expressions via the value history
+(@pxref{Value History, ,Value history}), after printing one out.
+
+Sometimes the artificial array mechanism is not quite enough; in
+moderately complex data structures, the elements of interest may not
+actually be adjacent---for example, if you are interested in the values
+of pointers in an array. One useful work-around in this situation is
+to use a convenience variable (@pxref{Convenience Vars, ,Convenience
+variables}) as a counter in an expression that prints the first
+interesting value, and then repeat that expression via @key{RET}. For
+instance, suppose you have an array @code{dtab} of pointers to
+structures, and you are interested in the values of a field @code{fv}
+in each structure. Here is an example of what you might type:
+
+@example
+set $i = 0
+p dtab[$i++]->fv
+@key{RET}
+@key{RET}
+@dots{}
+@end example
+
+@node Output Formats
+@section Output formats
+
+@cindex formatted output
+@cindex output formats
+By default, @value{GDBN} prints a value according to its data type. Sometimes
+this is not what you want. For example, you might want to print a number
+in hex, or a pointer in decimal. Or you might want to view data in memory
+at a certain address as a character string or as an instruction. To do
+these things, specify an @dfn{output format} when you print a value.
+
+The simplest use of output formats is to say how to print a value
+already computed. This is done by starting the arguments of the
+@code{print} command with a slash and a format letter. The format
+letters supported are:
+
+@table @code
+@item x
+Regard the bits of the value as an integer, and print the integer in
+hexadecimal.
+
+@item d
+Print as integer in signed decimal.
+
+@item u
+Print as integer in unsigned decimal.
+
+@item o
+Print as integer in octal.
+
+@item t
+Print as integer in binary. The letter @samp{t} stands for ``two''.
+@footnote{@samp{b} cannot be used because these format letters are also
+used with the @code{x} command, where @samp{b} stands for ``byte'';
+@pxref{Memory,,Examining memory}.}
+
+@item a
+@cindex unknown address, locating
+Print as an address, both absolute in hexadecimal and as an offset from
+the nearest preceding symbol. You can use this format used to discover
+where (in what function) an unknown address is located:
+
+@example
+(@value{GDBP}) p/a 0x54320
+$3 = 0x54320 <_initialize_vx+396>
+@end example
+
+@item c
+Regard as an integer and print it as a character constant.
+
+@item f
+Regard the bits of the value as a floating point number and print
+using typical floating point syntax.
+@end table
+
+For example, to print the program counter in hex (@pxref{Registers}), type
+
+@example
+p/x $pc
+@end example
+
+@noindent
+Note that no space is required before the slash; this is because command
+names in @value{GDBN} cannot contain a slash.
+
+To reprint the last value in the value history with a different format,
+you can use the @code{print} command with just a format and no
+expression. For example, @samp{p/x} reprints the last value in hex.
+
+@node Memory
+@section Examining memory
+
+You can use the command @code{x} (for ``examine'') to examine memory in
+any of several formats, independently of your program's data types.
+
+@cindex examining memory
+@table @code
+@kindex x
+@item x/@var{nfu} @var{addr}
+@itemx x @var{addr}
+@itemx x
+Use the @code{x} command to examine memory.
+@end table
+
+@var{n}, @var{f}, and @var{u} are all optional parameters that specify how
+much memory to display and how to format it; @var{addr} is an
+expression giving the address where you want to start displaying memory.
+If you use defaults for @var{nfu}, you need not type the slash @samp{/}.
+Several commands set convenient defaults for @var{addr}.
+
+@table @r
+@item @var{n}, the repeat count
+The repeat count is a decimal integer; the default is 1. It specifies
+how much memory (counting by units @var{u}) to display.
+@c This really is **decimal**; unaffected by 'set radix' as of GDB
+@c 4.1.2.
+
+@item @var{f}, the display format
+The display format is one of the formats used by @code{print},
+or @samp{s} (null-terminated string) or @samp{i} (machine instruction).
+The default is @samp{x} (hexadecimal) initially, or the format from the
+last time you used either @code{x} or @code{print}.
+
+@item @var{u}, the unit size
+The unit size is any of
+
+@table @code
+@item b
+Bytes.
+@item h
+Halfwords (two bytes).
+@item w
+Words (four bytes). This is the initial default.
+@item g
+Giant words (eight bytes).
+@end table
+
+Each time you specify a unit size with @code{x}, that size becomes the
+default unit the next time you use @code{x}. (For the @samp{s} and
+@samp{i} formats, the unit size is ignored and is normally not written.)
+
+@item @var{addr}, starting display address
+@var{addr} is the address where you want @value{GDBN} to begin displaying
+memory. The expression need not have a pointer value (though it may);
+it is always interpreted as an integer address of a byte of memory.
+@xref{Expressions, ,Expressions}, for more information on expressions. The default for
+@var{addr} is usually just after the last address examined---but several
+other commands also set the default address: @code{info breakpoints} (to
+the address of the last breakpoint listed), @code{info line} (to the
+starting address of a line), and @code{print} (if you use it to display
+a value from memory).
+@end table
+
+For example, @samp{x/3uh 0x54320} is a request to display three halfwords
+(@code{h}) of memory, formatted as unsigned decimal integers (@samp{u}),
+starting at address @code{0x54320}. @samp{x/4xw $sp} prints the four
+words (@samp{w}) of memory above the stack pointer (here, @samp{$sp};
+@pxref{Registers}) in hexadecimal (@samp{x}).
+
+Since the letters indicating unit sizes are all distinct from the
+letters specifying output formats, you do not have to remember whether
+unit size or format comes first; either order works. The output
+specifications @samp{4xw} and @samp{4wx} mean exactly the same thing.
+(However, the count @var{n} must come first; @samp{wx4} does not work.)
+
+Even though the unit size @var{u} is ignored for the formats @samp{s}
+and @samp{i}, you might still want to use a count @var{n}; for example,
+@samp{3i} specifies that you want to see three machine instructions,
+including any operands. The command @code{disassemble} gives an
+alternative way of inspecting machine instructions; @pxref{Machine
+Code,,Source and machine code}.
+
+All the defaults for the arguments to @code{x} are designed to make it
+easy to continue scanning memory with minimal specifications each time
+you use @code{x}. For example, after you have inspected three machine
+instructions with @samp{x/3i @var{addr}}, you can inspect the next seven
+with just @samp{x/7}. If you use @key{RET} to repeat the @code{x} command,
+the repeat count @var{n} is used again; the other arguments default as
+for successive uses of @code{x}.
+
+@cindex @code{$_}, @code{$__}, and value history
+The addresses and contents printed by the @code{x} command are not saved
+in the value history because there is often too much of them and they
+would get in the way. Instead, @value{GDBN} makes these values available for
+subsequent use in expressions as values of the convenience variables
+@code{$_} and @code{$__}. After an @code{x} command, the last address
+examined is available for use in expressions in the convenience variable
+@code{$_}. The contents of that address, as examined, are available in
+the convenience variable @code{$__}.
+
+If the @code{x} command has a repeat count, the address and contents saved
+are from the last memory unit printed; this is not the same as the last
+address printed if several units were printed on the last line of output.
+
+@node Auto Display
+@section Automatic display
+@cindex automatic display
+@cindex display of expressions
+
+If you find that you want to print the value of an expression frequently
+(to see how it changes), you might want to add it to the @dfn{automatic
+display list} so that @value{GDBN} prints its value each time your program stops.
+Each expression added to the list is given a number to identify it;
+to remove an expression from the list, you specify that number.
+The automatic display looks like this:
+
+@example
+2: foo = 38
+3: bar[5] = (struct hack *) 0x3804
+@end example
+
+@noindent
+This display shows item numbers, expressions and their current values. As with
+displays you request manually using @code{x} or @code{print}, you can
+specify the output format you prefer; in fact, @code{display} decides
+whether to use @code{print} or @code{x} depending on how elaborate your
+format specification is---it uses @code{x} if you specify a unit size,
+or one of the two formats (@samp{i} and @samp{s}) that are only
+supported by @code{x}; otherwise it uses @code{print}.
+
+@table @code
+@item display @var{exp}
+@kindex display
+Add the expression @var{exp} to the list of expressions to display
+each time your program stops. @xref{Expressions, ,Expressions}.
+
+@code{display} does not repeat if you press @key{RET} again after using it.
+
+@item display/@var{fmt} @var{exp}
+For @var{fmt} specifying only a display format and not a size or
+count, add the expression @var{exp} to the auto-display list but
+arrange to display it each time in the specified format @var{fmt}.
+@xref{Output Formats,,Output formats}.
+
+@item display/@var{fmt} @var{addr}
+For @var{fmt} @samp{i} or @samp{s}, or including a unit-size or a
+number of units, add the expression @var{addr} as a memory address to
+be examined each time your program stops. Examining means in effect
+doing @samp{x/@var{fmt} @var{addr}}. @xref{Memory, ,Examining memory}.
+@end table
+
+For example, @samp{display/i $pc} can be helpful, to see the machine
+instruction about to be executed each time execution stops (@samp{$pc}
+is a common name for the program counter; @pxref{Registers}).
+
+@table @code
+@item undisplay @var{dnums}@dots{}
+@itemx delete display @var{dnums}@dots{}
+@kindex delete display
+@kindex undisplay
+Remove item numbers @var{dnums} from the list of expressions to display.
+
+@code{undisplay} does not repeat if you press @key{RET} after using it.
+(Otherwise you would just get the error @samp{No display number @dots{}}.)
+
+@item disable display @var{dnums}@dots{}
+@kindex disable display
+Disable the display of item numbers @var{dnums}. A disabled display
+item is not printed automatically, but is not forgotten. It may be
+enabled again later.
+
+@item enable display @var{dnums}@dots{}
+@kindex enable display
+Enable display of item numbers @var{dnums}. It becomes effective once
+again in auto display of its expression, until you specify otherwise.
+
+@item display
+Display the current values of the expressions on the list, just as is
+done when your program stops.
+
+@item info display
+@kindex info display
+Print the list of expressions previously set up to display
+automatically, each one with its item number, but without showing the
+values. This includes disabled expressions, which are marked as such.
+It also includes expressions which would not be displayed right now
+because they refer to automatic variables not currently available.
+@end table
+
+If a display expression refers to local variables, then it does not make
+sense outside the lexical context for which it was set up. Such an
+expression is disabled when execution enters a context where one of its
+variables is not defined. For example, if you give the command
+@code{display last_char} while inside a function with an argument
+@code{last_char}, @value{GDBN} displays this argument while your program
+continues to stop inside that function. When it stops elsewhere---where
+there is no variable @code{last_char}---the display is disabled
+automatically. The next time your program stops where @code{last_char}
+is meaningful, you can enable the display expression once again.
+
+@node Print Settings
+@section Print settings
+
+@cindex format options
+@cindex print settings
+@value{GDBN} provides the following ways to control how arrays, structures,
+and symbols are printed.
+
+@noindent
+These settings are useful for debugging programs in any language:
+
+@table @code
+@item set print address
+@itemx set print address on
+@kindex set print address
+@value{GDBN} prints memory addresses showing the location of stack
+traces, structure values, pointer values, breakpoints, and so forth,
+even when it also displays the contents of those addresses. The default
+is @code{on}. For example, this is what a stack frame display looks like, with
+@code{set print address on}:
+
+@smallexample
+@group
+(@value{GDBP}) f
+#0 set_quotes (lq=0x34c78 "<<", rq=0x34c88 ">>")
+ at input.c:530
+530 if (lquote != def_lquote)
+@end group
+@end smallexample
+
+@item set print address off
+Do not print addresses when displaying their contents. For example,
+this is the same stack frame displayed with @code{set print address off}:
+
+@smallexample
+@group
+(@value{GDBP}) set print addr off
+(@value{GDBP}) f
+#0 set_quotes (lq="<<", rq=">>") at input.c:530
+530 if (lquote != def_lquote)
+@end group
+@end smallexample
+
+You can use @samp{set print address off} to eliminate all machine
+dependent displays from the @value{GDBN} interface. For example, with
+@code{print address off}, you should get the same text for backtraces on
+all machines---whether or not they involve pointer arguments.
+
+@item show print address
+@kindex show print address
+Show whether or not addresses are to be printed.
+@end table
+
+When @value{GDBN} prints a symbolic address, it normally prints the
+closest earlier symbol plus an offset. If that symbol does not uniquely
+identify the address (for example, it is a name whose scope is a single
+source file), you may need to disambiguate. One way to do this is with
+@code{info line}, for example @samp{info line *0x4537}. Alternately,
+you can set @value{GDBN} to print the source file and line number when
+it prints a symbolic address:
+
+@table @code
+@item set print symbol-filename on
+@kindex set print symbol-filename
+Tell @value{GDBN} to print the source file name and line number of a
+symbol in the symbolic form of an address.
+
+@item set print symbol-filename off
+Do not print source file name and line number of a symbol. This is the
+default.
+
+@item show print symbol-filename
+@kindex show print symbol-filename
+Show whether or not @value{GDBN} will print the source file name and
+line number of a symbol in the symbolic form of an address.
+@end table
+
+Another situation where it is helpful to show symbol filenames and line
+numbers is when disassembling code; @value{GDBN} shows you the line
+number and source file that corresponds to each instruction.
+
+Also, you may wish to see the symbolic form only if the address being
+printed is reasonably close to the closest earlier symbol:
+
+@table @code
+@item set print max-symbolic-offset @var{max-offset}
+@kindex set print max-symbolic-offset
+Tell @value{GDBN} to only display the symbolic form of an address if the
+offset between the closest earlier symbol and the address is less than
+@var{max-offset}. The default is 0, which means to always print the
+symbolic form of an address, if any symbol precedes it.
+
+@item show print max-symbolic-offset
+@kindex show print max-symbolic-offset
+Ask how large the maximum offset is that @value{GDBN} prints in a
+symbolic address.
+@end table
+
+@cindex wild pointer, interpreting
+@cindex pointer, finding referent
+If you have a pointer and you are not sure where it points, try
+@samp{set print symbol-filename on}. Then you can determine the name
+and source file location of the variable where it points, using
+@samp{p/a @var{pointer}}. This interprets the address in symbolic form.
+For example, here @value{GDBN} shows that a variable @code{ptt} points
+at another variable @code{t}, defined in @file{hi2.c}:
+
+@example
+(@value{GDBP}) set print symbol-filename on
+(@value{GDBP}) p/a ptt
+$4 = 0xe008 <t in hi2.c>
+@end example
+
+@quotation
+@emph{Warning:} For pointers that point to a local variable, @samp{p/a}
+does not show the symbol name and filename of the referent, even with
+the appropriate @code{set print} options turned on.
+@end quotation
+
+Other settings control how different kinds of objects are printed:
+
+@table @code
+@item set print array
+@itemx set print array on
+@kindex set print array
+Pretty-print arrays. This format is more convenient to read,
+but uses more space. The default is off.
+
+@item set print array off
+Return to compressed format for arrays.
+
+@item show print array
+@kindex show print array
+Show whether compressed or pretty format is selected for displaying
+arrays.
+
+@item set print elements @var{number-of-elements}
+@kindex set print elements
+If @value{GDBN} is printing a large array, it stops printing after it has
+printed the number of elements set by the @code{set print elements} command.
+This limit also applies to the display of strings.
+Setting the number of elements to zero means that the printing is unlimited.
+
+@item show print elements
+@kindex show print elements
+Display the number of elements of a large array that @value{GDBN} prints
+before losing patience.
+
+@item set print pretty on
+@kindex set print pretty
+Cause @value{GDBN} to print structures in an indented format with one member per
+line, like this:
+
+@smallexample
+@group
+$1 = @{
+ next = 0x0,
+ flags = @{
+ sweet = 1,
+ sour = 1
+ @},
+ meat = 0x54 "Pork"
+@}
+@end group
+@end smallexample
+
+@item set print pretty off
+Cause @value{GDBN} to print structures in a compact format, like this:
+
+@smallexample
+@group
+$1 = @{next = 0x0, flags = @{sweet = 1, sour = 1@}, \
+meat = 0x54 "Pork"@}
+@end group
+@end smallexample
+
+@noindent
+This is the default format.
+
+@item show print pretty
+@kindex show print pretty
+Show which format @value{GDBN} is using to print structures.
+
+@item set print sevenbit-strings on
+@kindex set print sevenbit-strings
+Print using only seven-bit characters; if this option is set,
+@value{GDBN} displays any eight-bit characters (in strings or
+character values) using the notation @code{\}@var{nnn}. This setting is
+best if you are working in English (@sc{ascii}) and you use the
+high-order bit of characters as a marker or ``meta'' bit.
+
+@item set print sevenbit-strings off
+Print full eight-bit characters. This allows the use of more
+international character sets, and is the default.
+
+@item show print sevenbit-strings
+@kindex show print sevenbit-strings
+Show whether or not @value{GDBN} is printing only seven-bit characters.
+
+@item set print union on
+@kindex set print union
+Tell @value{GDBN} to print unions which are contained in structures. This is the
+default setting.
+
+@item set print union off
+Tell @value{GDBN} not to print unions which are contained in structures.
+
+@item show print union
+@kindex show print union
+Ask @value{GDBN} whether or not it will print unions which are contained in
+structures.
+
+For example, given the declarations
+
+@smallexample
+typedef enum @{Tree, Bug@} Species;
+typedef enum @{Big_tree, Acorn, Seedling@} Tree_forms;
+typedef enum @{Caterpillar, Cocoon, Butterfly@}
+ Bug_forms;
+
+struct thing @{
+ Species it;
+ union @{
+ Tree_forms tree;
+ Bug_forms bug;
+ @} form;
+@};
+
+struct thing foo = @{Tree, @{Acorn@}@};
+@end smallexample
+
+@noindent
+with @code{set print union on} in effect @samp{p foo} would print
+
+@smallexample
+$1 = @{it = Tree, form = @{tree = Acorn, bug = Cocoon@}@}
+@end smallexample
+
+@noindent
+and with @code{set print union off} in effect it would print
+
+@smallexample
+$1 = @{it = Tree, form = @{...@}@}
+@end smallexample
+@end table
+
+@ifclear CONLY
+@need 1000
+@noindent
+These settings are of interest when debugging C++ programs:
+
+@table @code
+@item set print demangle
+@itemx set print demangle on
+@kindex set print demangle
+Print C++ names in their source form rather than in the encoded
+(``mangled'') form passed to the assembler and linker for type-safe
+linkage. The default is @samp{on}.
+
+@item show print demangle
+@kindex show print demangle
+Show whether C++ names are printed in mangled or demangled form.
+
+@item set print asm-demangle
+@itemx set print asm-demangle on
+@kindex set print asm-demangle
+Print C++ names in their source form rather than their mangled form, even
+in assembler code printouts such as instruction disassemblies.
+The default is off.
+
+@item show print asm-demangle
+@kindex show print asm-demangle
+Show whether C++ names in assembly listings are printed in mangled
+or demangled form.
+
+@item set demangle-style @var{style}
+@kindex set demangle-style
+@cindex C++ symbol decoding style
+@cindex symbol decoding style, C++
+Choose among several encoding schemes used by different compilers to
+represent C++ names. The choices for @var{style} are currently:
+
+@table @code
+@item auto
+Allow @value{GDBN} to choose a decoding style by inspecting your program.
+
+@item gnu
+Decode based on the GNU C++ compiler (@code{g++}) encoding algorithm.
+
+@item lucid
+Decode based on the Lucid C++ compiler (@code{lcc}) encoding algorithm.
+
+@item arm
+Decode using the algorithm in the @cite{C++ Annotated Reference Manual}.
+@strong{Warning:} this setting alone is not sufficient to allow
+debugging @code{cfront}-generated executables. @value{GDBN} would
+require further enhancement to permit that.
+@end table
+
+@item show demangle-style
+@kindex show demangle-style
+Display the encoding style currently in use for decoding C++ symbols.
+
+@item set print object
+@itemx set print object on
+@kindex set print object
+When displaying a pointer to an object, identify the @emph{actual}
+(derived) type of the object rather than the @emph{declared} type, using
+the virtual function table.
+
+@item set print object off
+Display only the declared type of objects, without reference to the
+virtual function table. This is the default setting.
+
+@item show print object
+@kindex show print object
+Show whether actual, or declared, object types are displayed.
+
+@item set print vtbl
+@itemx set print vtbl on
+@kindex set print vtbl
+Pretty print C++ virtual function tables. The default is off.
+
+@item set print vtbl off
+Do not pretty print C++ virtual function tables.
+
+@item show print vtbl
+@kindex show print vtbl
+Show whether C++ virtual function tables are pretty printed, or not.
+@end table
+@end ifclear
+
+@node Value History
+@section Value history
+
+@cindex value history
+Values printed by the @code{print} command are saved in the @value{GDBN} @dfn{value
+history} so that you can refer to them in other expressions. Values are
+kept until the symbol table is re-read or discarded (for example with
+the @code{file} or @code{symbol-file} commands). When the symbol table
+changes, the value history is discarded, since the values may contain
+pointers back to the types defined in the symbol table.
+
+@cindex @code{$}
+@cindex @code{$$}
+@cindex history number
+The values printed are given @dfn{history numbers} by which you can
+refer to them. These are successive integers starting with one.
+@code{print} shows you the history number assigned to a value by
+printing @samp{$@var{num} = } before the value; here @var{num} is the
+history number.
+
+To refer to any previous value, use @samp{$} followed by the value's
+history number. The way @code{print} labels its output is designed to
+remind you of this. Just @code{$} refers to the most recent value in
+the history, and @code{$$} refers to the value before that.
+@code{$$@var{n}} refers to the @var{n}th value from the end; @code{$$2}
+is the value just prior to @code{$$}, @code{$$1} is equivalent to
+@code{$$}, and @code{$$0} is equivalent to @code{$}.
+
+For example, suppose you have just printed a pointer to a structure and
+want to see the contents of the structure. It suffices to type
+
+@example
+p *$
+@end example
+
+If you have a chain of structures where the component @code{next} points
+to the next one, you can print the contents of the next one with this:
+
+@example
+p *$.next
+@end example
+
+@noindent
+You can print successive links in the chain by repeating this
+command---which you can do by just typing @key{RET}.
+
+Note that the history records values, not expressions. If the value of
+@code{x} is 4 and you type these commands:
+
+@example
+print x
+set x=5
+@end example
+
+@noindent
+then the value recorded in the value history by the @code{print} command
+remains 4 even though the value of @code{x} has changed.
+
+@table @code
+@kindex show values
+@item show values
+Print the last ten values in the value history, with their item numbers.
+This is like @samp{p@ $$9} repeated ten times, except that @code{show
+values} does not change the history.
+
+@item show values @var{n}
+Print ten history values centered on history item number @var{n}.
+
+@item show values +
+Print ten history values just after the values last printed. If no more
+values are available, produces no display.
+@end table
+
+Pressing @key{RET} to repeat @code{show values @var{n}} has exactly the
+same effect as @samp{show values +}.
+
+@node Convenience Vars
+@section Convenience variables
+
+@cindex convenience variables
+@value{GDBN} provides @dfn{convenience variables} that you can use within
+@value{GDBN} to hold on to a value and refer to it later. These variables
+exist entirely within @value{GDBN}; they are not part of your program, and
+setting a convenience variable has no direct effect on further execution
+of your program. That is why you can use them freely.
+
+Convenience variables are prefixed with @samp{$}. Any name preceded by
+@samp{$} can be used for a convenience variable, unless it is one of
+the predefined machine-specific register names (@pxref{Registers}).
+(Value history references, in contrast, are @emph{numbers} preceded
+by @samp{$}. @xref{Value History, ,Value history}.)
+
+You can save a value in a convenience variable with an assignment
+expression, just as you would set a variable in your program.
+For example:
+
+@example
+set $foo = *object_ptr
+@end example
+
+@noindent
+would save in @code{$foo} the value contained in the object pointed to by
+@code{object_ptr}.
+
+Using a convenience variable for the first time creates it, but its
+value is @code{void} until you assign a new value. You can alter the
+value with another assignment at any time.
+
+Convenience variables have no fixed types. You can assign a convenience
+variable any type of value, including structures and arrays, even if
+that variable already has a value of a different type. The convenience
+variable, when used as an expression, has the type of its current value.
+
+@table @code
+@item show convenience
+@kindex show convenience
+Print a list of convenience variables used so far, and their values.
+Abbreviated @code{show con}.
+@end table
+
+One of the ways to use a convenience variable is as a counter to be
+incremented or a pointer to be advanced. For example, to print
+a field from successive elements of an array of structures:
+
+@example
+set $i = 0
+print bar[$i++]->contents
+@i{@dots{} repeat that command by typing @key{RET}.}
+@end example
+
+Some convenience variables are created automatically by @value{GDBN} and given
+values likely to be useful.
+
+@table @code
+@item $_
+@kindex $_
+The variable @code{$_} is automatically set by the @code{x} command to
+the last address examined (@pxref{Memory, ,Examining memory}). Other
+commands which provide a default address for @code{x} to examine also
+set @code{$_} to that address; these commands include @code{info line}
+and @code{info breakpoint}. The type of @code{$_} is @code{void *}
+except when set by the @code{x} command, in which case it is a pointer
+to the type of @code{$__}.
+
+@item $__
+@kindex $__
+The variable @code{$__} is automatically set by the @code{x} command
+to the value found in the last address examined. Its type is chosen
+to match the format in which the data was printed.
+@end table
+
+@node Registers
+@section Registers
+
+@cindex registers
+You can refer to machine register contents, in expressions, as variables
+with names starting with @samp{$}. The names of registers are different
+for each machine; use @code{info registers} to see the names used on
+your machine.
+
+@table @code
+@item info registers
+@kindex info registers
+Print the names and values of all registers except floating-point
+registers (in the selected stack frame).
+
+@item info all-registers
+@kindex info all-registers
+@cindex floating point registers
+Print the names and values of all registers, including floating-point
+registers.
+
+@item info registers @var{regname} @dots{}
+Print the relativized value of each specified register @var{regname}.
+@var{regname} may be any register name valid on the machine you are using, with
+or without the initial @samp{$}.
+@end table
+
+@value{GDBN} has four ``standard'' register names that are available (in
+expressions) on most machines---whenever they do not conflict with an
+architecture's canonical mnemonics for registers. The register names
+@code{$pc} and @code{$sp} are used for the program counter register and
+the stack pointer. @code{$fp} is used for a register that contains a
+pointer to the current stack frame, and @code{$ps} is used for a
+register that contains the processor status. For example,
+you could print the program counter in hex with
+
+@example
+p/x $pc
+@end example
+
+@noindent
+or print the instruction to be executed next with
+
+@example
+x/i $pc
+@end example
+
+@noindent
+or add four to the stack pointer@footnote{This is a way of removing
+one word from the stack, on machines where stacks grow downward in
+memory (most machines, nowadays). This assumes that the innermost
+stack frame is selected; setting @code{$sp} is not allowed when other
+stack frames are selected. To pop entire frames off the stack,
+regardless of machine architecture, use @code{return};
+@pxref{Returning, ,Returning from a function}.} with
+
+@example
+set $sp += 4
+@end example
+
+Whenever possible, these four standard register names are available on
+your machine even though the machine has different canonical mnemonics,
+so long as there is no conflict. The @code{info registers} command
+shows the canonical names. For example, on the SPARC, @code{info
+registers} displays the processor status register as @code{$psr} but you
+can also refer to it as @code{$ps}.
+
+@value{GDBN} always considers the contents of an ordinary register as an
+integer when the register is examined in this way. Some machines have
+special registers which can hold nothing but floating point; these
+registers are considered to have floating point values. There is no way
+to refer to the contents of an ordinary register as floating point value
+(although you can @emph{print} it as a floating point value with
+@samp{print/f $@var{regname}}).
+
+Some registers have distinct ``raw'' and ``virtual'' data formats. This
+means that the data format in which the register contents are saved by
+the operating system is not the same one that your program normally
+sees. For example, the registers of the 68881 floating point
+coprocessor are always saved in ``extended'' (raw) format, but all C
+programs expect to work with ``double'' (virtual) format. In such
+cases, @value{GDBN} normally works with the virtual format only (the format that
+makes sense for your program), but the @code{info registers} command
+prints the data in both formats.
+
+Normally, register values are relative to the selected stack frame
+(@pxref{Selection, ,Selecting a frame}). This means that you get the
+value that the register would contain if all stack frames farther in
+were exited and their saved registers restored. In order to see the
+true contents of hardware registers, you must select the innermost
+frame (with @samp{frame 0}).
+
+However, @value{GDBN} must deduce where registers are saved, from the machine
+code generated by your compiler. If some registers are not saved, or if
+@value{GDBN} is unable to locate the saved registers, the selected stack
+frame makes no difference.
+
+@ifset AMD29K
+@table @code
+@item set rstack_high_address @var{address}
+@kindex set rstack_high_address
+@cindex AMD 29K register stack
+@cindex register stack, AMD29K
+On AMD 29000 family processors, registers are saved in a separate
+``register stack''. There is no way for @value{GDBN} to determine the extent
+of this stack. Normally, @value{GDBN} just assumes that the stack is ``large
+enough''. This may result in @value{GDBN} referencing memory locations that
+do not exist. If necessary, you can get around this problem by
+specifying the ending address of the register stack with the @code{set
+rstack_high_address} command. The argument should be an address, which
+you probably want to precede with @samp{0x} to specify in
+hexadecimal.
+
+@item show rstack_high_address
+@kindex show rstack_high_address
+Display the current limit of the register stack, on AMD 29000 family
+processors.
+@end table
+@end ifset
+
+@ifclear HAVE-FLOAT
+@node Floating Point Hardware
+@section Floating point hardware
+@cindex floating point
+
+@c FIXME! Really host, not target?
+Depending on the host machine architecture, @value{GDBN} may be able to give
+you more information about the status of the floating point hardware.
+
+@table @code
+@item info float
+@kindex info float
+Display hardware-dependent information about the floating
+point unit. The exact contents and layout vary depending on the
+floating point chip; on some platforms, @samp{info float} is not
+available at all.
+@end table
+@c FIXME: this is a cop-out. Try to get examples, explanations. Only
+@c FIXME...supported currently on arm's and 386's. Mark properly with
+@c FIXME... m4 macros to isolate general statements from hardware-dep,
+@c FIXME... at that point.
+@end ifclear
+
+@ifclear CONLY
+@node Languages
+@chapter Using @value{GDBN} with Different Languages
+@cindex languages
+
+@ifset MOD2
+Although programming languages generally have common aspects, they are
+rarely expressed in the same manner. For instance, in ANSI C,
+dereferencing a pointer @code{p} is accomplished by @code{*p}, but in
+Modula-2, it is accomplished by @code{p^}. Values can also be
+represented (and displayed) differently. Hex numbers in C are written
+like @samp{0x1ae}, while in Modula-2 they appear as @samp{1AEH}.
+@end ifset
+
+@cindex working language
+Language-specific information is built into @value{GDBN} for some languages,
+allowing you to express operations like the above in your program's
+native language, and allowing @value{GDBN} to output values in a manner
+consistent with the syntax of your program's native language. The
+language you use to build expressions, called the @dfn{working
+language}, can be selected manually, or @value{GDBN} can set it
+automatically.
+
+@menu
+* Setting:: Switching between source languages
+* Show:: Displaying the language
+@ifset MOD2
+* Checks:: Type and range checks
+@end ifset
+
+* Support:: Supported languages
+@end menu
+
+@node Setting
+@section Switching between source languages
+
+There are two ways to control the working language---either have @value{GDBN}
+set it automatically, or select it manually yourself. You can use the
+@code{set language} command for either purpose. On startup, @value{GDBN}
+defaults to setting the language automatically.
+
+@menu
+* Manually:: Setting the working language manually
+* Automatically:: Having @value{GDBN} infer the source language
+@end menu
+
+@node Manually
+@subsection Setting the working language
+
+If you allow @value{GDBN} to set the language automatically,
+expressions are interpreted the same way in your debugging session and
+your program.
+
+@kindex set language
+If you wish, you may set the language manually. To do this, issue the
+command @samp{set language @var{lang}}, where @var{lang} is the name of
+a language, such as
+@ifclear MOD2
+@code{c}.
+@end ifclear
+@ifset MOD2
+@code{c} or @code{modula-2}.
+@end ifset
+For a list of the supported languages, type @samp{set language}.
+@c FIXME: rms: eventually this command should be "help set language".
+
+@ifset MOD2
+Setting the language manually prevents @value{GDBN} from updating the working
+language automatically. This can lead to confusion if you try
+to debug a program when the working language is not the same as the
+source language, when an expression is acceptable to both
+languages---but means different things. For instance, if the current
+source file were written in C, and @value{GDBN} was parsing Modula-2, a
+command such as:
+
+@example
+print a = b + c
+@end example
+
+@noindent
+might not have the effect you intended. In C, this means to add
+@code{b} and @code{c} and place the result in @code{a}. The result
+printed would be the value of @code{a}. In Modula-2, this means to compare
+@code{a} to the result of @code{b+c}, yielding a @code{BOOLEAN} value.
+@end ifset
+
+@node Automatically
+@subsection Having @value{GDBN} infer the source language
+
+To have @value{GDBN} set the working language automatically, use @samp{set
+language local} or @samp{set language auto}. @value{GDBN} then infers the
+language that a program was written in by looking at the name of its
+source files, and examining their extensions:
+
+@table @file
+@ifset MOD2
+@item *.mod
+Modula-2 source file
+@end ifset
+
+@item *.c
+C source file
+
+@item *.C
+@itemx *.cc
+C++ source file
+@end table
+
+This information is recorded for each function or procedure in a source
+file. When your program stops in a frame (usually by encountering a
+breakpoint), @value{GDBN} sets the working language to the language recorded
+for the function in that frame. If the language for a frame is unknown
+(that is, if the function or block corresponding to the frame was
+defined in a source file that does not have a recognized extension), the
+current working language is not changed, and @value{GDBN} issues a warning.
+
+This may not seem necessary for most programs, which are written
+entirely in one source language. However, program modules and libraries
+written in one source language can be used by a main program written in
+a different source language. Using @samp{set language auto} in this
+case frees you from having to set the working language manually.
+
+@node Show
+@section Displaying the language
+
+The following commands help you find out which language is the
+working language, and also what language source files were written in.
+
+@kindex show language
+@kindex info frame
+@kindex info source
+@table @code
+@item show language
+Display the current working language. This is the
+language you can use with commands such as @code{print} to
+build and compute expressions that may involve variables in your program.
+
+@item info frame
+Among the other information listed here (@pxref{Frame Info, ,Information
+about a frame}) is the source language for this frame. This
+language becomes the working language if you use an
+identifier from this frame.
+
+@item info source
+Among the other information listed here (@pxref{Symbols, ,Examining the
+Symbol Table}) is the source language of this source file.
+@end table
+
+@ifset MOD2
+@node Checks
+@section Type and range checking
+
+@quotation
+@emph{Warning:} In this release, the @value{GDBN} commands for type and range
+checking are included, but they do not yet have any effect. This
+section documents the intended facilities.
+@end quotation
+@c FIXME remove warning when type/range code added
+
+Some languages are designed to guard you against making seemingly common
+errors through a series of compile- and run-time checks. These include
+checking the type of arguments to functions and operators, and making
+sure mathematical overflows are caught at run time. Checks such as
+these help to ensure a program's correctness once it has been compiled
+by eliminating type mismatches, and providing active checks for range
+errors when your program is running.
+
+@value{GDBN} can check for conditions like the above if you wish.
+Although @value{GDBN} does not check the statements in your program, it
+can check expressions entered directly into @value{GDBN} for evaluation via
+the @code{print} command, for example. As with the working language,
+@value{GDBN} can also decide whether or not to check automatically based on
+your program's source language. @xref{Support, ,Supported languages},
+for the default settings of supported languages.
+
+@menu
+* Type Checking:: An overview of type checking
+* Range Checking:: An overview of range checking
+@end menu
+
+@cindex type checking
+@cindex checks, type
+@node Type Checking
+@subsection An overview of type checking
+
+Some languages, such as Modula-2, are strongly typed, meaning that the
+arguments to operators and functions have to be of the correct type,
+otherwise an error occurs. These checks prevent type mismatch
+errors from ever causing any run-time problems. For example,
+
+@example
+1 + 2 @result{} 3
+@exdent but
+@error{} 1 + 2.3
+@end example
+
+The second example fails because the @code{CARDINAL} 1 is not
+type-compatible with the @code{REAL} 2.3.
+
+For expressions you use in @value{GDBN} commands, you can tell the @value{GDBN}
+type checker to skip checking; to treat any mismatches as errors and
+abandon the expression; or only issue warnings when type mismatches
+occur, but evaluate the expression anyway. When you choose the last of
+these, @value{GDBN} evaluates expressions like the second example above, but
+also issues a warning.
+
+Even though you may turn type checking off, other type-based reasons may
+prevent @value{GDBN} from evaluating an expression. For instance, @value{GDBN} does not
+know how to add an @code{int} and a @code{struct foo}. These particular
+type errors have nothing to do with the language in use, and usually
+arise from expressions, such as the one described above, which make
+little sense to evaluate anyway.
+
+Each language defines to what degree it is strict about type. For
+instance, both Modula-2 and C require the arguments to arithmetical
+operators to be numbers. In C, enumerated types and pointers can be
+represented as numbers, so that they are valid arguments to mathematical
+operators. @xref{Support, ,Supported languages}, for further
+details on specific languages.
+
+@value{GDBN} provides some additional commands for controlling the type checker:
+
+@kindex set check
+@kindex set check type
+@kindex show check type
+@table @code
+@item set check type auto
+Set type checking on or off based on the current working language.
+@xref{Support, ,Supported languages}, for the default settings for
+each language.
+
+@item set check type on
+@itemx set check type off
+Set type checking on or off, overriding the default setting for the
+current working language. Issue a warning if the setting does not
+match the language default. If any type mismatches occur in
+evaluating an expression while typechecking is on, @value{GDBN} prints a
+message and aborts evaluation of the expression.
+
+@item set check type warn
+Cause the type checker to issue warnings, but to always attempt to
+evaluate the expression. Evaluating the expression may still
+be impossible for other reasons. For example, @value{GDBN} cannot add
+numbers and structures.
+
+@item show type
+Show the current setting of the type checker, and whether or not @value{GDBN} is
+setting it automatically.
+@end table
+
+@cindex range checking
+@cindex checks, range
+@node Range Checking
+@subsection An overview of range checking
+
+In some languages (such as Modula-2), it is an error to exceed the
+bounds of a type; this is enforced with run-time checks. Such range
+checking is meant to ensure program correctness by making sure
+computations do not overflow, or indices on an array element access do
+not exceed the bounds of the array.
+
+For expressions you use in @value{GDBN} commands, you can tell
+@value{GDBN} to treat range errors in one of three ways: ignore them,
+always treat them as errors and abandon the expression, or issue
+warnings but evaluate the expression anyway.
+
+A range error can result from numerical overflow, from exceeding an
+array index bound, or when you type a constant that is not a member
+of any type. Some languages, however, do not treat overflows as an
+error. In many implementations of C, mathematical overflow causes the
+result to ``wrap around'' to lower values---for example, if @var{m} is
+the largest integer value, and @var{s} is the smallest, then
+
+@example
+@var{m} + 1 @result{} @var{s}
+@end example
+
+This, too, is specific to individual languages, and in some cases
+specific to individual compilers or machines. @xref{Support, ,
+Supported languages}, for further details on specific languages.
+
+@value{GDBN} provides some additional commands for controlling the range checker:
+
+@kindex set check
+@kindex set check range
+@kindex show check range
+@table @code
+@item set check range auto
+Set range checking on or off based on the current working language.
+@xref{Support, ,Supported languages}, for the default settings for
+each language.
+
+@item set check range on
+@itemx set check range off
+Set range checking on or off, overriding the default setting for the
+current working language. A warning is issued if the setting does not
+match the language default. If a range error occurs, then a message
+is printed and evaluation of the expression is aborted.
+
+@item set check range warn
+Output messages when the @value{GDBN} range checker detects a range error,
+but attempt to evaluate the expression anyway. Evaluating the
+expression may still be impossible for other reasons, such as accessing
+memory that the process does not own (a typical example from many Unix
+systems).
+
+@item show range
+Show the current setting of the range checker, and whether or not it is
+being set automatically by @value{GDBN}.
+@end table
+@end ifset
+
+@node Support
+@section Supported languages
+
+@ifset MOD2
+@value{GDBN} 4 supports C, C++, and Modula-2.
+@end ifset
+@ifclear MOD2
+@value{GDBN} 4 supports C, and C++.
+@end ifclear
+Some @value{GDBN} features may be used in expressions regardless of the
+language you use: the @value{GDBN} @code{@@} and @code{::} operators,
+and the @samp{@{type@}addr} construct (@pxref{Expressions,
+,Expressions}) can be used with the constructs of any supported
+language.
+
+The following sections detail to what degree each source language is
+supported by @value{GDBN}. These sections are not meant to be language
+tutorials or references, but serve only as a reference guide to what the
+@value{GDBN} expression parser accepts, and what input and output
+formats should look like for different languages. There are many good
+books written on each of these languages; please look to these for a
+language reference or tutorial.
+
+@ifset MOD2
+@menu
+* C:: C and C++
+* Modula-2:: Modula-2
+@end menu
+
+@node C
+@subsection C and C++
+@cindex C and C++
+@cindex expressions in C or C++
+
+Since C and C++ are so closely related, many features of @value{GDBN} apply
+to both languages. Whenever this is the case, we discuss both languages
+together.
+@end ifset
+@ifclear MOD2
+@c Cancel this below, under same condition, at end of this chapter!
+@raisesections
+@end ifclear
+
+@cindex C++
+@kindex g++
+@cindex GNU C++
+The C++ debugging facilities are jointly implemented by the GNU C++
+compiler and @value{GDBN}. Therefore, to debug your C++ code
+effectively, you must compile your C++ programs with the GNU C++
+compiler, @code{g++}.
+
+For best results when debugging C++ programs, use the stabs debugging
+format. You can select that format explicitly with the @code{g++}
+command-line options @samp{-gstabs} or @samp{-gstabs+}. See
+@ref{Debugging Options,,Options for Debugging Your Program or GNU CC,
+gcc.info, Using GNU CC}, for more information.
+@end ifclear
+@ifset CONLY
+@node C
+@chapter C Language Support
+@cindex C language
+@cindex expressions in C
+
+Information specific to the C language is built into @value{GDBN} so that you
+can use C expressions while degugging. This also permits @value{GDBN} to
+output values in a manner consistent with C conventions.
+
+@menu
+* C Operators:: C operators
+* C Constants:: C constants
+* Debugging C:: @value{GDBN} and C
+@end menu
+@end ifset
+@ifclear CONLY
+@menu
+* C Operators:: C and C++ operators
+* C Constants:: C and C++ constants
+* Cplus expressions:: C++ expressions
+* C Defaults:: Default settings for C and C++
+@ifset MOD2
+* C Checks:: C and C++ type and range checks
+@end ifset
+
+* Debugging C:: @value{GDBN} and C
+* Debugging C plus plus:: Special features for C++
+@end menu
+@end ifclear
+
+@ifclear CONLY
+@cindex C and C++ operators
+@node C Operators
+@subsubsection C and C++ operators
+@end ifclear
+@ifset CONLY
+@cindex C operators
+@node C Operators
+@section C operators
+@end ifset
+
+Operators must be defined on values of specific types. For instance,
+@code{+} is defined on numbers, but not on structures. Operators are
+often defined on groups of types.
+
+@ifclear CONLY
+For the purposes of C and C++, the following definitions hold:
+@end ifclear
+
+@itemize @bullet
+@item
+@emph{Integral types} include @code{int} with any of its storage-class
+specifiers; @code{char}; and @code{enum}.
+
+@item
+@emph{Floating-point types} include @code{float} and @code{double}.
+
+@item
+@emph{Pointer types} include all types defined as @code{(@var{type}
+*)}.
+
+@item
+@emph{Scalar types} include all of the above.
+@end itemize
+
+@noindent
+The following operators are supported. They are listed here
+in order of increasing precedence:
+
+@table @code
+@item ,
+The comma or sequencing operator. Expressions in a comma-separated list
+are evaluated from left to right, with the result of the entire
+expression being the last expression evaluated.
+
+@item =
+Assignment. The value of an assignment expression is the value
+assigned. Defined on scalar types.
+
+@item @var{op}=
+Used in an expression of the form @w{@code{@var{a} @var{op}= @var{b}}},
+and translated to @w{@code{@var{a} = @var{a op b}}}.
+@w{@code{@var{op}=}} and @code{=} have the same precendence.
+@var{op} is any one of the operators @code{|}, @code{^}, @code{&},
+@code{<<}, @code{>>}, @code{+}, @code{-}, @code{*}, @code{/}, @code{%}.
+
+@item ?:
+The ternary operator. @code{@var{a} ? @var{b} : @var{c}} can be thought
+of as: if @var{a} then @var{b} else @var{c}. @var{a} should be of an
+integral type.
+
+@item ||
+Logical @sc{or}. Defined on integral types.
+
+@item &&
+Logical @sc{and}. Defined on integral types.
+
+@item |
+Bitwise @sc{or}. Defined on integral types.
+
+@item ^
+Bitwise exclusive-@sc{or}. Defined on integral types.
+
+@item &
+Bitwise @sc{and}. Defined on integral types.
+
+@item ==@r{, }!=
+Equality and inequality. Defined on scalar types. The value of these
+expressions is 0 for false and non-zero for true.
+
+@item <@r{, }>@r{, }<=@r{, }>=
+Less than, greater than, less than or equal, greater than or equal.
+Defined on scalar types. The value of these expressions is 0 for false
+and non-zero for true.
+
+@item <<@r{, }>>
+left shift, and right shift. Defined on integral types.
+
+@item @@
+The @value{GDBN} ``artificial array'' operator (@pxref{Expressions, ,Expressions}).
+
+@item +@r{, }-
+Addition and subtraction. Defined on integral types, floating-point types and
+pointer types.
+
+@item *@r{, }/@r{, }%
+Multiplication, division, and modulus. Multiplication and division are
+defined on integral and floating-point types. Modulus is defined on
+integral types.
+
+@item ++@r{, }--
+Increment and decrement. When appearing before a variable, the
+operation is performed before the variable is used in an expression;
+when appearing after it, the variable's value is used before the
+operation takes place.
+
+@item *
+Pointer dereferencing. Defined on pointer types. Same precedence as
+@code{++}.
+
+@item &
+Address operator. Defined on variables. Same precedence as @code{++}.
+
+@ifclear CONLY
+For debugging C++, @value{GDBN} implements a use of @samp{&} beyond what is
+allowed in the C++ language itself: you can use @samp{&(&@var{ref})}
+(or, if you prefer, simply @samp{&&@var{ref}}) to examine the address
+where a C++ reference variable (declared with @samp{&@var{ref}}) is
+stored.
+@end ifclear
+
+@item -
+Negative. Defined on integral and floating-point types. Same
+precedence as @code{++}.
+
+@item !
+Logical negation. Defined on integral types. Same precedence as
+@code{++}.
+
+@item ~
+Bitwise complement operator. Defined on integral types. Same precedence as
+@code{++}.
+
+
+@item .@r{, }->
+Structure member, and pointer-to-structure member. For convenience,
+@value{GDBN} regards the two as equivalent, choosing whether to dereference a
+pointer based on the stored type information.
+Defined on @code{struct} and @code{union} data.
+
+@item []
+Array indexing. @code{@var{a}[@var{i}]} is defined as
+@code{*(@var{a}+@var{i})}. Same precedence as @code{->}.
+
+@item ()
+Function parameter list. Same precedence as @code{->}.
+
+@ifclear CONLY
+@item ::
+C++ scope resolution operator. Defined on
+@code{struct}, @code{union}, and @code{class} types.
+@end ifclear
+
+@item ::
+Doubled colons
+@ifclear CONLY
+also
+@end ifclear
+represent the @value{GDBN} scope operator (@pxref{Expressions,
+,Expressions}).
+@ifclear CONLY
+Same precedence as @code{::}, above.
+@end ifclear
+@end table
+
+@ifclear CONLY
+@cindex C and C++ constants
+@node C Constants
+@subsubsection C and C++ constants
+
+@value{GDBN} allows you to express the constants of C and C++ in the
+following ways:
+@end ifclear
+@ifset CONLY
+@cindex C constants
+@node C Constants
+@section C constants
+
+@value{GDBN} allows you to express the constants of C in the
+following ways:
+@end ifset
+
+@itemize @bullet
+@item
+Integer constants are a sequence of digits. Octal constants are
+specified by a leading @samp{0} (ie. zero), and hexadecimal constants by
+a leading @samp{0x} or @samp{0X}. Constants may also end with a letter
+@samp{l}, specifying that the constant should be treated as a
+@code{long} value.
+
+@item
+Floating point constants are a sequence of digits, followed by a decimal
+point, followed by a sequence of digits, and optionally followed by an
+exponent. An exponent is of the form:
+@samp{@w{e@r{[[}+@r{]|}-@r{]}@var{nnn}}}, where @var{nnn} is another
+sequence of digits. The @samp{+} is optional for positive exponents.
+
+@item
+Enumerated constants consist of enumerated identifiers, or their
+integral equivalents.
+
+@item
+Character constants are a single character surrounded by single quotes
+(@code{'}), or a number---the ordinal value of the corresponding character
+(usually its @sc{ASCII} value). Within quotes, the single character may
+be represented by a letter or by @dfn{escape sequences}, which are of
+the form @samp{\@var{nnn}}, where @var{nnn} is the octal representation
+of the character's ordinal value; or of the form @samp{\@var{x}}, where
+@samp{@var{x}} is a predefined special character---for example,
+@samp{\n} for newline.
+
+@item
+String constants are a sequence of character constants surrounded
+by double quotes (@code{"}).
+
+@item
+Pointer constants are an integral value. You can also write pointers
+to constants using the C operator @samp{&}.
+
+@item
+Array constants are comma-separated lists surrounded by braces @samp{@{}
+and @samp{@}}; for example, @samp{@{1,2,3@}} is a three-element array of
+integers, @samp{@{@{1,2@}, @{3,4@}, @{5,6@}@}} is a three-by-two array,
+and @samp{@{&"hi", &"there", &"fred"@}} is a three-element array of pointers.
+@end itemize
+
+@ifclear CONLY
+@node Cplus expressions
+@subsubsection C++ expressions
+
+@cindex expressions in C++
+@value{GDBN} expression handling has a number of extensions to
+interpret a significant subset of C++ expressions.
+
+@cindex C++ support, not in @sc{coff}
+@cindex @sc{coff} versus C++
+@cindex C++ and object formats
+@cindex object formats and C++
+@cindex a.out and C++
+@cindex @sc{ecoff} and C++
+@cindex @sc{xcoff} and C++
+@cindex @sc{elf}/stabs and C++
+@cindex @sc{elf}/@sc{dwarf} and C++
+@c FIXME!! GDB may eventually be able to debug C++ using DWARF; check
+@c periodically whether this has happened...
+@quotation
+@emph{Warning:} @value{GDBN} can only debug C++ code if you compile with
+the GNU C++ compiler. Moreover, C++ debugging depends on the use of
+additional debugging information in the symbol table, and thus requires
+special support. @value{GDBN} has this support @emph{only} with the
+stabs debug format. In particular, if your compiler generates a.out,
+MIPS @sc{ecoff}, RS/6000 @sc{xcoff}, or @sc{elf} with stabs extensions
+to the symbol table, these facilities are all available. (With GNU CC,
+you can use the @samp{-gstabs} option to request stabs debugging
+extensions explicitly.) Where the object code format is standard
+@sc{coff} or @sc{dwarf} in @sc{elf}, on the other hand, most of the C++
+support in @value{GDBN} does @emph{not} work.
+@end quotation
+
+@enumerate
+
+@cindex member functions
+@item
+Member function calls are allowed; you can use expressions like
+
+@example
+count = aml->GetOriginal(x, y)
+@end example
+
+@kindex this
+@cindex namespace in C++
+@item
+While a member function is active (in the selected stack frame), your
+expressions have the same namespace available as the member function;
+that is, @value{GDBN} allows implicit references to the class instance
+pointer @code{this} following the same rules as C++.
+
+@cindex call overloaded functions
+@cindex type conversions in C++
+@item
+You can call overloaded functions; @value{GDBN} resolves the function
+call to the right definition, with one restriction---you must use
+arguments of the type required by the function that you want to call.
+@value{GDBN} does not perform conversions requiring constructors or
+user-defined type operators.
+
+@cindex reference declarations
+@item
+@value{GDBN} understands variables declared as C++ references; you can use them in
+expressions just as you do in C++ source---they are automatically
+dereferenced.
+
+In the parameter list shown when @value{GDBN} displays a frame, the values of
+reference variables are not displayed (unlike other variables); this
+avoids clutter, since references are often used for large structures.
+The @emph{address} of a reference variable is always shown, unless
+you have specified @samp{set print address off}.
+
+@item
+@value{GDBN} supports the C++ name resolution operator @code{::}---your
+expressions can use it just as expressions in your program do. Since
+one scope may be defined in another, you can use @code{::} repeatedly if
+necessary, for example in an expression like
+@samp{@var{scope1}::@var{scope2}::@var{name}}. @value{GDBN} also allows
+resolving name scope by reference to source files, in both C and C++
+debugging (@pxref{Variables, ,Program variables}).
+@end enumerate
+
+@node C Defaults
+@subsubsection C and C++ defaults
+@cindex C and C++ defaults
+
+If you allow @value{GDBN} to set type and range checking automatically, they
+both default to @code{off} whenever the working language changes to
+C or C++. This happens regardless of whether you, or @value{GDBN},
+selected the working language.
+
+If you allow @value{GDBN} to set the language automatically, it sets the
+working language to C or C++ on entering code compiled from a source file
+whose name ends with @file{.c}, @file{.C}, or @file{.cc}.
+@xref{Automatically, ,Having @value{GDBN} infer the source language}, for
+further details.
+
+@ifset MOD2
+@c Type checking is (a) primarily motivated by Modula-2, and (b)
+@c unimplemented. If (b) changes, it might make sense to let this node
+@c appear even if Mod-2 does not, but meanwhile ignore it. pesch 16jul93.
+@node C Checks
+@subsubsection C and C++ type and range checks
+@cindex C and C++ checks
+
+By default, when @value{GDBN} parses C or C++ expressions, type checking
+is not used. However, if you turn type checking on, @value{GDBN}
+considers two variables type equivalent if:
+
+@itemize @bullet
+@item
+The two variables are structured and have the same structure, union, or
+enumerated tag.
+
+@item
+Two two variables have the same type name, or types that have been
+declared equivalent through @code{typedef}.
+
+@ignore
+@c leaving this out because neither J Gilmore nor R Pesch understand it.
+@c FIXME--beers?
+@item
+The two @code{struct}, @code{union}, or @code{enum} variables are
+declared in the same declaration. (Note: this may not be true for all C
+compilers.)
+@end ignore
+@end itemize
+
+Range checking, if turned on, is done on mathematical operations. Array
+indices are not checked, since they are often used to index a pointer
+that is not itself an array.
+@end ifset
+@end ifclear
+
+@ifclear CONLY
+@node Debugging C
+@subsubsection @value{GDBN} and C
+@end ifclear
+@ifset CONLY
+@node Debugging C
+@section @value{GDBN} and C
+@end ifset
+
+The @code{set print union} and @code{show print union} commands apply to
+the @code{union} type. When set to @samp{on}, any @code{union} that is
+inside a @code{struct}
+@ifclear CONLY
+or @code{class}
+@end ifclear
+is also printed.
+Otherwise, it appears as @samp{@{...@}}.
+
+The @code{@@} operator aids in the debugging of dynamic arrays, formed
+with pointers and a memory allocation function. @xref{Expressions,
+,Expressions}.
+
+@ifclear CONLY
+@node Debugging C plus plus
+@subsubsection @value{GDBN} features for C++
+
+@cindex commands for C++
+Some @value{GDBN} commands are particularly useful with C++, and some are
+designed specifically for use with C++. Here is a summary:
+
+@table @code
+@cindex break in overloaded functions
+@item @r{breakpoint menus}
+When you want a breakpoint in a function whose name is overloaded,
+@value{GDBN} breakpoint menus help you specify which function definition
+you want. @xref{Breakpoint Menus,,Breakpoint menus}.
+
+@cindex overloading in C++
+@item rbreak @var{regex}
+Setting breakpoints using regular expressions is helpful for setting
+breakpoints on overloaded functions that are not members of any special
+classes.
+@xref{Set Breaks, ,Setting breakpoints}.
+
+@cindex C++ exception handling
+@item catch @var{exceptions}
+@itemx info catch
+Debug C++ exception handling using these commands. @xref{Exception
+Handling, ,Breakpoints and exceptions}.
+
+@cindex inheritance
+@item ptype @var{typename}
+Print inheritance relationships as well as other information for type
+@var{typename}.
+@xref{Symbols, ,Examining the Symbol Table}.
+
+@cindex C++ symbol display
+@item set print demangle
+@itemx show print demangle
+@itemx set print asm-demangle
+@itemx show print asm-demangle
+Control whether C++ symbols display in their source form, both when
+displaying code as C++ source and when displaying disassemblies.
+@xref{Print Settings, ,Print settings}.
+
+@item set print object
+@itemx show print object
+Choose whether to print derived (actual) or declared types of objects.
+@xref{Print Settings, ,Print settings}.
+
+@item set print vtbl
+@itemx show print vtbl
+Control the format for printing virtual function tables.
+@xref{Print Settings, ,Print settings}.
+
+@item @r{Overloaded symbol names}
+You can specify a particular definition of an overloaded symbol, using
+the same notation that is used to declare such symbols in C++: type
+@code{@var{symbol}(@var{types})} rather than just @var{symbol}. You can
+also use the @value{GDBN} command-line word completion facilities to list the
+available choices, or to finish the type list for you.
+@xref{Completion,, Command completion}, for details on how to do this.
+@end table
+@ifclear MOD2
+@c cancels "raisesections" under same conditions near bgn of chapter
+@lowersections
+@end ifclear
+
+@ifset MOD2
+@node Modula-2
+@subsection Modula-2
+@cindex Modula-2
+
+The extensions made to @value{GDBN} to support Modula-2 only support
+output from the GNU Modula-2 compiler (which is currently being
+developed). Other Modula-2 compilers are not currently supported, and
+attempting to debug executables produced by them is most likely
+to give an error as @value{GDBN} reads in the executable's symbol
+table.
+
+@cindex expressions in Modula-2
+@menu
+* M2 Operators:: Built-in operators
+* Built-In Func/Proc:: Built-in functions and procedures
+* M2 Constants:: Modula-2 constants
+* M2 Defaults:: Default settings for Modula-2
+* Deviations:: Deviations from standard Modula-2
+* M2 Checks:: Modula-2 type and range checks
+* M2 Scope:: The scope operators @code{::} and @code{.}
+* GDB/M2:: @value{GDBN} and Modula-2
+@end menu
+
+@node M2 Operators
+@subsubsection Operators
+@cindex Modula-2 operators
+
+Operators must be defined on values of specific types. For instance,
+@code{+} is defined on numbers, but not on structures. Operators are
+often defined on groups of types. For the purposes of Modula-2, the
+following definitions hold:
+
+@itemize @bullet
+
+@item
+@emph{Integral types} consist of @code{INTEGER}, @code{CARDINAL}, and
+their subranges.
+
+@item
+@emph{Character types} consist of @code{CHAR} and its subranges.
+
+@item
+@emph{Floating-point types} consist of @code{REAL}.
+
+@item
+@emph{Pointer types} consist of anything declared as @code{POINTER TO
+@var{type}}.
+
+@item
+@emph{Scalar types} consist of all of the above.
+
+@item
+@emph{Set types} consist of @code{SET} and @code{BITSET} types.
+
+@item
+@emph{Boolean types} consist of @code{BOOLEAN}.
+@end itemize
+
+@noindent
+The following operators are supported, and appear in order of
+increasing precedence:
+
+@table @code
+@item ,
+Function argument or array index separator.
+
+@item :=
+Assignment. The value of @var{var} @code{:=} @var{value} is
+@var{value}.
+
+@item <@r{, }>
+Less than, greater than on integral, floating-point, or enumerated
+types.
+
+@item <=@r{, }>=
+Less than, greater than, less than or equal to, greater than or equal to
+on integral, floating-point and enumerated types, or set inclusion on
+set types. Same precedence as @code{<}.
+
+@item =@r{, }<>@r{, }#
+Equality and two ways of expressing inequality, valid on scalar types.
+Same precedence as @code{<}. In @value{GDBN} scripts, only @code{<>} is
+available for inequality, since @code{#} conflicts with the script
+comment character.
+
+@item IN
+Set membership. Defined on set types and the types of their members.
+Same precedence as @code{<}.
+
+@item OR
+Boolean disjunction. Defined on boolean types.
+
+@item AND@r{, }&
+Boolean conjuction. Defined on boolean types.
+
+@item @@
+The @value{GDBN} ``artificial array'' operator (@pxref{Expressions, ,Expressions}).
+
+@item +@r{, }-
+Addition and subtraction on integral and floating-point types, or union
+and difference on set types.
+
+@item *
+Multiplication on integral and floating-point types, or set intersection
+on set types.
+
+@item /
+Division on floating-point types, or symmetric set difference on set
+types. Same precedence as @code{*}.
+
+@item DIV@r{, }MOD
+Integer division and remainder. Defined on integral types. Same
+precedence as @code{*}.
+
+@item -
+Negative. Defined on @code{INTEGER} and @code{REAL} data.
+
+@item ^
+Pointer dereferencing. Defined on pointer types.
+
+@item NOT
+Boolean negation. Defined on boolean types. Same precedence as
+@code{^}.
+
+@item .
+@code{RECORD} field selector. Defined on @code{RECORD} data. Same
+precedence as @code{^}.
+
+@item []
+Array indexing. Defined on @code{ARRAY} data. Same precedence as @code{^}.
+
+@item ()
+Procedure argument list. Defined on @code{PROCEDURE} objects. Same precedence
+as @code{^}.
+
+@item ::@r{, }.
+@value{GDBN} and Modula-2 scope operators.
+@end table
+
+@quotation
+@emph{Warning:} Sets and their operations are not yet supported, so @value{GDBN}
+treats the use of the operator @code{IN}, or the use of operators
+@code{+}, @code{-}, @code{*}, @code{/}, @code{=}, , @code{<>}, @code{#},
+@code{<=}, and @code{>=} on sets as an error.
+@end quotation
+
+@cindex Modula-2 built-ins
+@node Built-In Func/Proc
+@subsubsection Built-in functions and procedures
+
+Modula-2 also makes available several built-in procedures and functions.
+In describing these, the following metavariables are used:
+
+@table @var
+
+@item a
+represents an @code{ARRAY} variable.
+
+@item c
+represents a @code{CHAR} constant or variable.
+
+@item i
+represents a variable or constant of integral type.
+
+@item m
+represents an identifier that belongs to a set. Generally used in the
+same function with the metavariable @var{s}. The type of @var{s} should
+be @code{SET OF @var{mtype}} (where @var{mtype} is the type of @var{m}).
+
+@item n
+represents a variable or constant of integral or floating-point type.
+
+@item r
+represents a variable or constant of floating-point type.
+
+@item t
+represents a type.
+
+@item v
+represents a variable.
+
+@item x
+represents a variable or constant of one of many types. See the
+explanation of the function for details.
+@end table
+
+All Modula-2 built-in procedures also return a result, described below.
+
+@table @code
+@item ABS(@var{n})
+Returns the absolute value of @var{n}.
+
+@item CAP(@var{c})
+If @var{c} is a lower case letter, it returns its upper case
+equivalent, otherwise it returns its argument
+
+@item CHR(@var{i})
+Returns the character whose ordinal value is @var{i}.
+
+@item DEC(@var{v})
+Decrements the value in the variable @var{v}. Returns the new value.
+
+@item DEC(@var{v},@var{i})
+Decrements the value in the variable @var{v} by @var{i}. Returns the
+new value.
+
+@item EXCL(@var{m},@var{s})
+Removes the element @var{m} from the set @var{s}. Returns the new
+set.
+
+@item FLOAT(@var{i})
+Returns the floating point equivalent of the integer @var{i}.
+
+@item HIGH(@var{a})
+Returns the index of the last member of @var{a}.
+
+@item INC(@var{v})
+Increments the value in the variable @var{v}. Returns the new value.
+
+@item INC(@var{v},@var{i})
+Increments the value in the variable @var{v} by @var{i}. Returns the
+new value.
+
+@item INCL(@var{m},@var{s})
+Adds the element @var{m} to the set @var{s} if it is not already
+there. Returns the new set.
+
+@item MAX(@var{t})
+Returns the maximum value of the type @var{t}.
+
+@item MIN(@var{t})
+Returns the minimum value of the type @var{t}.
+
+@item ODD(@var{i})
+Returns boolean TRUE if @var{i} is an odd number.
+
+@item ORD(@var{x})
+Returns the ordinal value of its argument. For example, the ordinal
+value of a character is its ASCII value (on machines supporting the
+ASCII character set). @var{x} must be of an ordered type, which include
+integral, character and enumerated types.
+
+@item SIZE(@var{x})
+Returns the size of its argument. @var{x} can be a variable or a type.
+
+@item TRUNC(@var{r})
+Returns the integral part of @var{r}.
+
+@item VAL(@var{t},@var{i})
+Returns the member of the type @var{t} whose ordinal value is @var{i}.
+@end table
+
+@quotation
+@emph{Warning:} Sets and their operations are not yet supported, so
+@value{GDBN} treats the use of procedures @code{INCL} and @code{EXCL} as
+an error.
+@end quotation
+
+@cindex Modula-2 constants
+@node M2 Constants
+@subsubsection Constants
+
+@value{GDBN} allows you to express the constants of Modula-2 in the following
+ways:
+
+@itemize @bullet
+
+@item
+Integer constants are simply a sequence of digits. When used in an
+expression, a constant is interpreted to be type-compatible with the
+rest of the expression. Hexadecimal integers are specified by a
+trailing @samp{H}, and octal integers by a trailing @samp{B}.
+
+@item
+Floating point constants appear as a sequence of digits, followed by a
+decimal point and another sequence of digits. An optional exponent can
+then be specified, in the form @samp{E@r{[}+@r{|}-@r{]}@var{nnn}}, where
+@samp{@r{[}+@r{|}-@r{]}@var{nnn}} is the desired exponent. All of the
+digits of the floating point constant must be valid decimal (base 10)
+digits.
+
+@item
+Character constants consist of a single character enclosed by a pair of
+like quotes, either single (@code{'}) or double (@code{"}). They may
+also be expressed by their ordinal value (their ASCII value, usually)
+followed by a @samp{C}.
+
+@item
+String constants consist of a sequence of characters enclosed by a
+pair of like quotes, either single (@code{'}) or double (@code{"}).
+Escape sequences in the style of C are also allowed. @xref{C
+Constants, ,C and C++ constants}, for a brief explanation of escape
+sequences.
+
+@item
+Enumerated constants consist of an enumerated identifier.
+
+@item
+Boolean constants consist of the identifiers @code{TRUE} and
+@code{FALSE}.
+
+@item
+Pointer constants consist of integral values only.
+
+@item
+Set constants are not yet supported.
+@end itemize
+
+@node M2 Defaults
+@subsubsection Modula-2 defaults
+@cindex Modula-2 defaults
+
+If type and range checking are set automatically by @value{GDBN}, they
+both default to @code{on} whenever the working language changes to
+Modula-2. This happens regardless of whether you, or @value{GDBN},
+selected the working language.
+
+If you allow @value{GDBN} to set the language automatically, then entering
+code compiled from a file whose name ends with @file{.mod} sets the
+working language to Modula-2. @xref{Automatically, ,Having @value{GDBN} set
+the language automatically}, for further details.
+
+@node Deviations
+@subsubsection Deviations from standard Modula-2
+@cindex Modula-2, deviations from
+
+A few changes have been made to make Modula-2 programs easier to debug.
+This is done primarily via loosening its type strictness:
+
+@itemize @bullet
+@item
+Unlike in standard Modula-2, pointer constants can be formed by
+integers. This allows you to modify pointer variables during
+debugging. (In standard Modula-2, the actual address contained in a
+pointer variable is hidden from you; it can only be modified
+through direct assignment to another pointer variable or expression that
+returned a pointer.)
+
+@item
+C escape sequences can be used in strings and characters to represent
+non-printable characters. @value{GDBN} prints out strings with these
+escape sequences embedded. Single non-printable characters are
+printed using the @samp{CHR(@var{nnn})} format.
+
+@item
+The assignment operator (@code{:=}) returns the value of its right-hand
+argument.
+
+@item
+All built-in procedures both modify @emph{and} return their argument.
+@end itemize
+
+@node M2 Checks
+@subsubsection Modula-2 type and range checks
+@cindex Modula-2 checks
+
+@quotation
+@emph{Warning:} in this release, @value{GDBN} does not yet perform type or
+range checking.
+@end quotation
+@c FIXME remove warning when type/range checks added
+
+@value{GDBN} considers two Modula-2 variables type equivalent if:
+
+@itemize @bullet
+@item
+They are of types that have been declared equivalent via a @code{TYPE
+@var{t1} = @var{t2}} statement
+
+@item
+They have been declared on the same line. (Note: This is true of the
+GNU Modula-2 compiler, but it may not be true of other compilers.)
+@end itemize
+
+As long as type checking is enabled, any attempt to combine variables
+whose types are not equivalent is an error.
+
+Range checking is done on all mathematical operations, assignment, array
+index bounds, and all built-in functions and procedures.
+
+@node M2 Scope
+@subsubsection The scope operators @code{::} and @code{.}
+@cindex scope
+@kindex .
+@cindex colon, doubled as scope operator
+@ifinfo
+@kindex colon-colon
+@c Info cannot handle :: but TeX can.
+@end ifinfo
+@iftex
+@kindex ::
+@end iftex
+
+There are a few subtle differences between the Modula-2 scope operator
+(@code{.}) and the @value{GDBN} scope operator (@code{::}). The two have
+similar syntax:
+
+@example
+
+@var{module} . @var{id}
+@var{scope} :: @var{id}
+@end example
+
+@noindent
+where @var{scope} is the name of a module or a procedure,
+@var{module} the name of a module, and @var{id} is any declared
+identifier within your program, except another module.
+
+Using the @code{::} operator makes @value{GDBN} search the scope
+specified by @var{scope} for the identifier @var{id}. If it is not
+found in the specified scope, then @value{GDBN} searches all scopes
+enclosing the one specified by @var{scope}.
+
+Using the @code{.} operator makes @value{GDBN} search the current scope for
+the identifier specified by @var{id} that was imported from the
+definition module specified by @var{module}. With this operator, it is
+an error if the identifier @var{id} was not imported from definition
+module @var{module}, or if @var{id} is not an identifier in
+@var{module}.
+
+@node GDB/M2
+@subsubsection @value{GDBN} and Modula-2
+
+Some @value{GDBN} commands have little use when debugging Modula-2 programs.
+Five subcommands of @code{set print} and @code{show print} apply
+specifically to C and C++: @samp{vtbl}, @samp{demangle},
+@samp{asm-demangle}, @samp{object}, and @samp{union}. The first four
+apply to C++, and the last to the C @code{union} type, which has no direct
+analogue in Modula-2.
+
+The @code{@@} operator (@pxref{Expressions, ,Expressions}), while available
+while using any language, is not useful with Modula-2. Its
+intent is to aid the debugging of @dfn{dynamic arrays}, which cannot be
+created in Modula-2 as they can in C or C++. However, because an
+address can be specified by an integral constant, the construct
+@samp{@{@var{type}@}@var{adrexp}} is still useful. (@pxref{Expressions, ,Expressions})
+
+@cindex @code{#} in Modula-2
+In @value{GDBN} scripts, the Modula-2 inequality operator @code{#} is
+interpreted as the beginning of a comment. Use @code{<>} instead.
+
+@end ifset
+@end ifclear
+
+@node Symbols
+@chapter Examining the Symbol Table
+
+The commands described in this section allow you to inquire about the
+symbols (names of variables, functions and types) defined in your
+program. This information is inherent in the text of your program and
+does not change as your program executes. @value{GDBN} finds it in your
+program's symbol table, in the file indicated when you started @value{GDBN}
+(@pxref{File Options, ,Choosing files}), or by one of the
+file-management commands (@pxref{Files, ,Commands to specify files}).
+
+@c FIXME! This might be intentionally specific to C and C++; if so, move
+@c to someplace in C section of lang chapter.
+@cindex symbol names
+@cindex names of symbols
+@cindex quoting names
+Occasionally, you may need to refer to symbols that contain unusual
+characters, which @value{GDBN} ordinarily treats as word delimiters. The
+most frequent case is in referring to static variables in other
+source files (@pxref{Variables,,Program variables}). File names
+are recorded in object files as debugging symbols, but @value{GDBN} would
+ordinarily parse a typical file name, like @file{foo.c}, as the three words
+@samp{foo} @samp{.} @samp{c}. To allow @value{GDBN} to recognize
+@samp{foo.c} as a single symbol, enclose it in single quotes; for example,
+
+@example
+p 'foo.c'::x
+@end example
+
+@noindent
+looks up the value of @code{x} in the scope of the file @file{foo.c}.
+
+@table @code
+@item info address @var{symbol}
+@kindex info address
+Describe where the data for @var{symbol} is stored. For a register
+variable, this says which register it is kept in. For a non-register
+local variable, this prints the stack-frame offset at which the variable
+is always stored.
+
+Note the contrast with @samp{print &@var{symbol}}, which does not work
+at all for a register variable, and for a stack local variable prints
+the exact address of the current instantiation of the variable.
+
+@item whatis @var{exp}
+@kindex whatis
+Print the data type of expression @var{exp}. @var{exp} is not
+actually evaluated, and any side-effecting operations (such as
+assignments or function calls) inside it do not take place.
+@xref{Expressions, ,Expressions}.
+
+@item whatis
+Print the data type of @code{$}, the last value in the value history.
+
+@item ptype @var{typename}
+@kindex ptype
+Print a description of data type @var{typename}. @var{typename} may be
+the name of a type, or for C code it may have the form
+@ifclear CONLY
+@samp{class @var{class-name}},
+@end ifclear
+@samp{struct @var{struct-tag}}, @samp{union @var{union-tag}} or
+@samp{enum @var{enum-tag}}.
+
+@item ptype @var{exp}
+@itemx ptype
+Print a description of the type of expression @var{exp}. @code{ptype}
+differs from @code{whatis} by printing a detailed description, instead
+of just the name of the type.
+
+For example, for this variable declaration:
+
+@example
+struct complex @{double real; double imag;@} v;
+@end example
+
+@noindent
+the two commands give this output:
+
+@example
+@group
+(@value{GDBP}) whatis v
+type = struct complex
+(@value{GDBP}) ptype v
+type = struct complex @{
+ double real;
+ double imag;
+@}
+@end group
+@end example
+
+@noindent
+As with @code{whatis}, using @code{ptype} without an argument refers to
+the type of @code{$}, the last value in the value history.
+
+@item info types @var{regexp}
+@itemx info types
+@kindex info types
+Print a brief description of all types whose name matches @var{regexp}
+(or all types in your program, if you supply no argument). Each
+complete typename is matched as though it were a complete line; thus,
+@samp{i type value} gives information on all types in your program whose
+name includes the string @code{value}, but @samp{i type ^value$} gives
+information only on types whose complete name is @code{value}.
+
+This command differs from @code{ptype} in two ways: first, like
+@code{whatis}, it does not print a detailed description; second, it
+lists all source files where a type is defined.
+
+@item info source
+@kindex info source
+Show the name of the current source file---that is, the source file for
+the function containing the current point of execution---and the language
+it was written in.
+
+@item info sources
+@kindex info sources
+Print the names of all source files in your program for which there is
+debugging information, organized into two lists: files whose symbols
+have already been read, and files whose symbols will be read when needed.
+
+@item info functions
+@kindex info functions
+Print the names and data types of all defined functions.
+
+@item info functions @var{regexp}
+Print the names and data types of all defined functions
+whose names contain a match for regular expression @var{regexp}.
+Thus, @samp{info fun step} finds all functions whose names
+include @code{step}; @samp{info fun ^step} finds those whose names
+start with @code{step}.
+
+@item info variables
+@kindex info variables
+Print the names and data types of all variables that are declared
+outside of functions (i.e., excluding local variables).
+
+@item info variables @var{regexp}
+Print the names and data types of all variables (except for local
+variables) whose names contain a match for regular expression
+@var{regexp}.
+
+@ignore
+This was never implemented.
+@item info methods
+@itemx info methods @var{regexp}
+@kindex info methods
+The @code{info methods} command permits the user to examine all defined
+methods within C++ program, or (with the @var{regexp} argument) a
+specific set of methods found in the various C++ classes. Many
+C++ classes provide a large number of methods. Thus, the output
+from the @code{ptype} command can be overwhelming and hard to use. The
+@code{info-methods} command filters the methods, printing only those
+which match the regular-expression @var{regexp}.
+@end ignore
+
+@item maint print symbols @var{filename}
+@itemx maint print psymbols @var{filename}
+@itemx maint print msymbols @var{filename}
+@kindex maint print symbols
+@cindex symbol dump
+@kindex maint print psymbols
+@cindex partial symbol dump
+Write a dump of debugging symbol data into the file @var{filename}.
+These commands are used to debug the @value{GDBN} symbol-reading code. Only
+symbols with debugging data are included. If you use @samp{maint print
+symbols}, @value{GDBN} includes all the symbols for which it has already
+collected full details: that is, @var{filename} reflects symbols for
+only those files whose symbols @value{GDBN} has read. You can use the
+command @code{info sources} to find out which files these are. If you
+use @samp{maint print psymbols} instead, the dump shows information about
+symbols that @value{GDBN} only knows partially---that is, symbols defined in
+files that @value{GDBN} has skimmed, but not yet read completely. Finally,
+@samp{maint print msymbols} dumps just the minimal symbol information
+required for each object file from which @value{GDBN} has read some symbols.
+@xref{Files, ,Commands to specify files}, for a discussion of how
+@value{GDBN} reads symbols (in the description of @code{symbol-file}).
+@end table
+
+@node Altering
+@chapter Altering Execution
+
+Once you think you have found an error in your program, you might want to
+find out for certain whether correcting the apparent error would lead to
+correct results in the rest of the run. You can find the answer by
+experiment, using the @value{GDBN} features for altering execution of the
+program.
+
+For example, you can store new values into variables or memory
+locations,
+@ifclear BARETARGET
+give your program a signal, restart it
+@end ifclear
+@ifset BARETARGET
+restart your program
+@end ifset
+at a different address, or even return prematurely from a function to
+its caller.
+
+@menu
+* Assignment:: Assignment to variables
+* Jumping:: Continuing at a different address
+@ifclear BARETARGET
+* Signaling:: Giving your program a signal
+@end ifclear
+
+* Returning:: Returning from a function
+* Calling:: Calling your program's functions
+* Patching:: Patching your program
+@end menu
+
+@node Assignment
+@section Assignment to variables
+
+@cindex assignment
+@cindex setting variables
+To alter the value of a variable, evaluate an assignment expression.
+@xref{Expressions, ,Expressions}. For example,
+
+@example
+print x=4
+@end example
+
+@noindent
+stores the value 4 into the variable @code{x}, and then prints the
+value of the assignment expression (which is 4).
+@ifclear CONLY
+@xref{Languages, ,Using @value{GDBN} with Different Languages}, for more
+information on operators in supported languages.
+@end ifclear
+
+@kindex set variable
+@cindex variables, setting
+If you are not interested in seeing the value of the assignment, use the
+@code{set} command instead of the @code{print} command. @code{set} is
+really the same as @code{print} except that the expression's value is
+not printed and is not put in the value history (@pxref{Value History,
+,Value history}). The expression is evaluated only for its effects.
+
+If the beginning of the argument string of the @code{set} command
+appears identical to a @code{set} subcommand, use the @code{set
+variable} command instead of just @code{set}. This command is identical
+to @code{set} except for its lack of subcommands. For example, if
+your program has a variable @code{width}, you get
+an error if you try to set a new value with just @samp{set width=13},
+because @value{GDBN} has the command @code{set width}:
+
+@example
+(@value{GDBP}) whatis width
+type = double
+(@value{GDBP}) p width
+$4 = 13
+(@value{GDBP}) set width=47
+Invalid syntax in expression.
+@end example
+
+@noindent
+The invalid expression, of course, is @samp{=47}. In
+order to actually set the program's variable @code{width}, use
+
+@example
+(@value{GDBP}) set var width=47
+@end example
+
+@value{GDBN} allows more implicit conversions in assignments than C; you can
+freely store an integer value into a pointer variable or vice versa,
+and you can convert any structure to any other structure that is the
+same length or shorter.
+@comment FIXME: how do structs align/pad in these conversions?
+@comment /pesch@cygnus.com 18dec1990
+
+To store values into arbitrary places in memory, use the @samp{@{@dots{}@}}
+construct to generate a value of specified type at a specified address
+(@pxref{Expressions, ,Expressions}). For example, @code{@{int@}0x83040} refers
+to memory location @code{0x83040} as an integer (which implies a certain size
+and representation in memory), and
+
+@example
+set @{int@}0x83040 = 4
+@end example
+
+@noindent
+stores the value 4 into that memory location.
+
+@node Jumping
+@section Continuing at a different address
+
+Ordinarily, when you continue your program, you do so at the place where
+it stopped, with the @code{continue} command. You can instead continue at
+an address of your own choosing, with the following commands:
+
+@table @code
+@item jump @var{linespec}
+@kindex jump
+Resume execution at line @var{linespec}. Execution stops again
+immediately if there is a breakpoint there. @xref{List, ,Printing
+source lines}, for a description of the different forms of
+@var{linespec}.
+
+The @code{jump} command does not change the current stack frame, or
+the stack pointer, or the contents of any memory location or any
+register other than the program counter. If line @var{linespec} is in
+a different function from the one currently executing, the results may
+be bizarre if the two functions expect different patterns of arguments or
+of local variables. For this reason, the @code{jump} command requests
+confirmation if the specified line is not in the function currently
+executing. However, even bizarre results are predictable if you are
+well acquainted with the machine-language code of your program.
+
+@item jump *@var{address}
+Resume execution at the instruction at address @var{address}.
+@end table
+
+You can get much the same effect as the @code{jump} command by storing a
+new value into the register @code{$pc}. The difference is that this
+does not start your program running; it only changes the address where it
+@emph{will} run when you continue. For example,
+
+@example
+set $pc = 0x485
+@end example
+
+@noindent
+makes the next @code{continue} command or stepping command execute at
+address @code{0x485}, rather than at the address where your program stopped.
+@xref{Continuing and Stepping, ,Continuing and stepping}.
+
+The most common occasion to use the @code{jump} command is to back up,
+perhaps with more breakpoints set, over a portion of a program that has
+already executed, in order to examine its execution in more detail.
+
+@ifclear BARETARGET
+@c @group
+@node Signaling
+@section Giving your program a signal
+
+@table @code
+@item signal @var{signal}
+@kindex signal
+Resume execution where your program stopped, but immediately give it the
+signal @var{signal}. @var{signal} can be the name or the number of a
+signal. For example, on many systems @code{signal 2} and @code{signal
+SIGINT} are both ways of sending an interrupt signal.
+
+Alternatively, if @var{signal} is zero, continue execution without
+giving a signal. This is useful when your program stopped on account of
+a signal and would ordinary see the signal when resumed with the
+@code{continue} command; @samp{signal 0} causes it to resume without a
+signal.
+
+@code{signal} does not repeat when you press @key{RET} a second time
+after executing the command.
+@end table
+@c @end group
+
+Invoking the @code{signal} command is not the same as invoking the
+@code{kill} utility from the shell. Sending a signal with @code{kill}
+causes @value{GDBN} to decide what to do with the signal depending on
+the signal handling tables (@pxref{Signals}). The @code{signal} command
+passes the signal directly to your program.
+
+@end ifclear
+
+@node Returning
+@section Returning from a function
+
+@table @code
+@item return
+@itemx return @var{expression}
+@cindex returning from a function
+@kindex return
+You can cancel execution of a function call with the @code{return}
+command. If you give an
+@var{expression} argument, its value is used as the function's return
+value.
+@end table
+
+When you use @code{return}, @value{GDBN} discards the selected stack frame
+(and all frames within it). You can think of this as making the
+discarded frame return prematurely. If you wish to specify a value to
+be returned, give that value as the argument to @code{return}.
+
+This pops the selected stack frame (@pxref{Selection, ,Selecting a
+frame}), and any other frames inside of it, leaving its caller as the
+innermost remaining frame. That frame becomes selected. The
+specified value is stored in the registers used for returning values
+of functions.
+
+The @code{return} command does not resume execution; it leaves the
+program stopped in the state that would exist if the function had just
+returned. In contrast, the @code{finish} command (@pxref{Continuing
+and Stepping, ,Continuing and stepping}) resumes execution until the
+selected stack frame returns naturally.
+
+@node Calling
+@section Calling program functions
+
+@cindex calling functions
+@kindex call
+@table @code
+@item call @var{expr}
+Evaluate the expression @var{expr} without displaying @code{void}
+returned values.
+@end table
+
+You can use this variant of the @code{print} command if you want to
+execute a function from your program, but without cluttering the output
+with @code{void} returned values. The result is printed and saved in
+the value history, if it is not void.
+
+@node Patching
+@section Patching programs
+@cindex patching binaries
+@cindex writing into executables
+@ifclear BARETARGET
+@cindex writing into corefiles
+@end ifclear
+
+By default, @value{GDBN} opens the file containing your program's executable
+code
+@ifclear BARETARGET
+(or the corefile)
+@end ifclear
+read-only. This prevents accidental alterations
+to machine code; but it also prevents you from intentionally patching
+your program's binary.
+
+If you'd like to be able to patch the binary, you can specify that
+explicitly with the @code{set write} command. For example, you might
+want to turn on internal debugging flags, or even to make emergency
+repairs.
+
+@table @code
+@item set write on
+@itemx set write off
+@kindex set write
+If you specify @samp{set write on}, @value{GDBN} opens executable
+@ifclear BARETARGET
+and core
+@end ifclear
+files for both reading and writing; if you specify @samp{set write
+off} (the default), @value{GDBN} opens them read-only.
+
+If you have already loaded a file, you must load it again (using the
+@code{exec-file}
+@ifclear BARETARGET
+or @code{core-file}
+@end ifclear
+command) after changing @code{set write}, for your new setting to take
+effect.
+
+@item show write
+@kindex show write
+Display whether executable files
+@ifclear BARETARGET
+and core files
+@end ifclear
+are opened for writing as well as reading.
+@end table
+
+@node GDB Files
+@chapter @value{GDBN} Files
+
+@value{GDBN} needs to know the file name of the program to be debugged, both in
+order to read its symbol table and in order to start your program.
+@ifclear BARETARGET
+To debug a core dump of a previous run, you must also tell @value{GDBN}
+the name of the core dump file.
+@end ifclear
+
+@menu
+* Files:: Commands to specify files
+* Symbol Errors:: Errors reading symbol files
+@end menu
+
+@node Files
+@section Commands to specify files
+@cindex symbol table
+
+@ifclear BARETARGET
+@cindex core dump file
+The usual way to specify executable and core dump file names is with
+the command arguments given when you start @value{GDBN} (@pxref{Invocation,
+,Getting In and Out of @value{GDBN}}.
+@end ifclear
+@ifset BARETARGET
+The usual way to specify an executable file name is with
+the command argument given when you start @value{GDBN}, (@pxref{Invocation,
+,Getting In and Out of @value{GDBN}}.
+@end ifset
+
+Occasionally it is necessary to change to a different file during a
+@value{GDBN} session. Or you may run @value{GDBN} and forget to specify
+a file you want to use. In these situations the @value{GDBN} commands
+to specify new files are useful.
+
+@table @code
+@item file @var{filename}
+@cindex executable file
+@kindex file
+Use @var{filename} as the program to be debugged. It is read for its
+symbols and for the contents of pure memory. It is also the program
+executed when you use the @code{run} command. If you do not specify a
+directory and the file is not found in the @value{GDBN} working directory, @value{GDBN}
+uses the environment variable @code{PATH} as a list of directories to
+search, just as the shell does when looking for a program to run. You
+can change the value of this variable, for both @value{GDBN} and your program,
+using the @code{path} command.
+
+On systems with memory-mapped files, an auxiliary file
+@file{@var{filename}.syms} may hold symbol table information for
+@var{filename}. If so, @value{GDBN} maps in the symbol table from
+@file{@var{filename}.syms}, starting up more quickly. See the
+descriptions of the options @samp{-mapped} and @samp{-readnow}
+(available on the command line, and with the commands @code{file},
+@code{symbol-file}, or @code{add-symbol-file}), for more information.
+
+@item file
+@code{file} with no argument makes @value{GDBN} discard any information it
+has on both executable file and the symbol table.
+
+@item exec-file @r{[} @var{filename} @r{]}
+@kindex exec-file
+Specify that the program to be run (but not the symbol table) is found
+in @var{filename}. @value{GDBN} searches the environment variable @code{PATH}
+if necessary to locate your program. Omitting @var{filename} means to
+discard information on the executable file.
+
+@item symbol-file @r{[} @var{filename} @r{]}
+@kindex symbol-file
+Read symbol table information from file @var{filename}. @code{PATH} is
+searched when necessary. Use the @code{file} command to get both symbol
+table and program to run from the same file.
+
+@code{symbol-file} with no argument clears out @value{GDBN} information on your
+program's symbol table.
+
+The @code{symbol-file} command causes @value{GDBN} to forget the contents of its
+convenience variables, the value history, and all breakpoints and
+auto-display expressions. This is because they may contain pointers to
+the internal data recording symbols and data types, which are part of
+the old symbol table data being discarded inside @value{GDBN}.
+
+@code{symbol-file} does not repeat if you press @key{RET} again after
+executing it once.
+
+When @value{GDBN} is configured for a particular environment, it
+understands debugging information in whatever format is the standard
+generated for that environment; you may use either a GNU compiler, or
+other compilers that adhere to the local conventions. Best results are
+usually obtained from GNU compilers; for example, using @code{@value{GCC}}
+you can generate debugging information for optimized code.
+
+On some kinds of object files, the @code{symbol-file} command does not
+normally read the symbol table in full right away. Instead, it scans
+the symbol table quickly to find which source files and which symbols
+are present. The details are read later, one source file at a time,
+as they are needed.
+
+The purpose of this two-stage reading strategy is to make @value{GDBN} start up
+faster. For the most part, it is invisible except for occasional
+pauses while the symbol table details for a particular source file are
+being read. (The @code{set verbose} command can turn these pauses
+into messages if desired. @xref{Messages/Warnings, ,Optional warnings
+and messages}.)
+
+We have not implemented the two-stage strategy for COFF yet. When the
+symbol table is stored in COFF format, @code{symbol-file} reads the
+symbol table data in full right away.
+
+@item symbol-file @var{filename} @r{[} -readnow @r{]} @r{[} -mapped @r{]}
+@itemx file @var{filename} @r{[} -readnow @r{]} @r{[} -mapped @r{]}
+@kindex readnow
+@cindex reading symbols immediately
+@cindex symbols, reading immediately
+@kindex mapped
+@cindex memory-mapped symbol file
+@cindex saving symbol table
+You can override the @value{GDBN} two-stage strategy for reading symbol
+tables by using the @samp{-readnow} option with any of the commands that
+load symbol table information, if you want to be sure @value{GDBN} has the
+entire symbol table available.
+
+@ifclear BARETARGET
+If memory-mapped files are available on your system through the
+@code{mmap} system call, you can use another option, @samp{-mapped}, to
+cause @value{GDBN} to write the symbols for your program into a reusable
+file. Future @value{GDBN} debugging sessions map in symbol information
+from this auxiliary symbol file (if the program has not changed), rather
+than spending time reading the symbol table from the executable
+program. Using the @samp{-mapped} option has the same effect as
+starting @value{GDBN} with the @samp{-mapped} command-line option.
+
+You can use both options together, to make sure the auxiliary symbol
+file has all the symbol information for your program.
+
+The auxiliary symbol file for a program called @var{myprog} is called
+@samp{@var{myprog}.syms}. Once this file exists (so long as it is newer
+than the corresponding executable), @value{GDBN} always attempts to use
+it when you debug @var{myprog}; no special options or commands are
+needed.
+
+The @file{.syms} file is specific to the host machine where you run
+@value{GDBN}. It holds an exact image of the internal @value{GDBN}
+symbol table. It cannot be shared across multiple host platforms.
+
+@c FIXME: for now no mention of directories, since this seems to be in
+@c flux. 13mar1992 status is that in theory GDB would look either in
+@c current dir or in same dir as myprog; but issues like competing
+@c GDB's, or clutter in system dirs, mean that in practice right now
+@c only current dir is used. FFish says maybe a special GDB hierarchy
+@c (eg rooted in val of env var GDBSYMS) could exist for mappable symbol
+@c files.
+
+@item core-file @r{[} @var{filename} @r{]}
+@kindex core
+@kindex core-file
+Specify the whereabouts of a core dump file to be used as the ``contents
+of memory''. Traditionally, core files contain only some parts of the
+address space of the process that generated them; @value{GDBN} can access the
+executable file itself for other parts.
+
+@code{core-file} with no argument specifies that no core file is
+to be used.
+
+Note that the core file is ignored when your program is actually running
+under @value{GDBN}. So, if you have been running your program and you wish to
+debug a core file instead, you must kill the subprocess in which the
+program is running. To do this, use the @code{kill} command
+(@pxref{Kill Process, ,Killing the child process}).
+@end ifclear
+
+@item load @var{filename}
+@kindex load
+@ifset GENERIC
+Depending on what remote debugging facilities are configured into
+@value{GDBN}, the @code{load} command may be available. Where it exists, it
+is meant to make @var{filename} (an executable) available for debugging
+on the remote system---by downloading, or dynamic linking, for example.
+@code{load} also records the @var{filename} symbol table in @value{GDBN}, like
+the @code{add-symbol-file} command.
+
+If your @value{GDBN} does not have a @code{load} command, attempting to
+execute it gets the error message ``@code{You can't do that when your
+target is @dots{}}''
+@end ifset
+
+The file is loaded at whatever address is specified in the executable.
+For some object file formats, you can specify the load address when you
+link the program; for other formats, like a.out, the object file format
+specifies a fixed address.
+@c FIXME! This would be a good place for an xref to the GNU linker doc.
+
+@ifset VXWORKS
+On VxWorks, @code{load} links @var{filename} dynamically on the
+current target system as well as adding its symbols in @value{GDBN}.
+@end ifset
+
+@ifset I960
+@cindex download to Nindy-960
+With the Nindy interface to an Intel 960 board, @code{load}
+downloads @var{filename} to the 960 as well as adding its symbols in
+@value{GDBN}.
+@end ifset
+
+@ifset H8
+@cindex download to H8/300 or H8/500
+@cindex H8/300 or H8/500 download
+@cindex download to Hitachi SH
+@cindex Hitachi SH download
+When you select remote debugging to a Hitachi SH, H8/300, or H8/500 board
+(@pxref{Hitachi Remote,,@value{GDBN} and Hitachi Microprocessors}),
+the @code{load} command downloads your program to the Hitachi board and also
+opens it as the current executable target for @value{GDBN} on your host
+(like the @code{file} command).
+@end ifset
+
+@code{load} does not repeat if you press @key{RET} again after using it.
+
+@ifclear BARETARGET
+@item add-symbol-file @var{filename} @var{address}
+@itemx add-symbol-file @var{filename} @var{address} @r{[} -readnow @r{]} @r{[} -mapped @r{]}
+@kindex add-symbol-file
+@cindex dynamic linking
+The @code{add-symbol-file} command reads additional symbol table information
+from the file @var{filename}. You would use this command when @var{filename}
+has been dynamically loaded (by some other means) into the program that
+is running. @var{address} should be the memory address at which the
+file has been loaded; @value{GDBN} cannot figure this out for itself.
+You can specify @var{address} as an expression.
+
+The symbol table of the file @var{filename} is added to the symbol table
+originally read with the @code{symbol-file} command. You can use the
+@code{add-symbol-file} command any number of times; the new symbol data thus
+read keeps adding to the old. To discard all old symbol data instead,
+use the @code{symbol-file} command.
+
+@code{add-symbol-file} does not repeat if you press @key{RET} after using it.
+
+You can use the @samp{-mapped} and @samp{-readnow} options just as with
+the @code{symbol-file} command, to change how @value{GDBN} manages the symbol
+table information for @var{filename}.
+@end ifclear
+
+@item info files
+@itemx info target
+@kindex info files
+@kindex info target
+@code{info files} and @code{info target} are synonymous; both print
+the current target (@pxref{Targets, ,Specifying a Debugging Target}),
+including the
+@ifclear BARETARGET
+names of the executable and core dump files
+@end ifclear
+@ifset BARETARGET
+name of the executable file
+@end ifset
+currently in use by @value{GDBN}, and the files from which symbols were
+loaded. The command @code{help target} lists all possible targets
+rather than current ones.
+@end table
+
+All file-specifying commands allow both absolute and relative file names
+as arguments. @value{GDBN} always converts the file name to an absolute file
+name and remembers it that way.
+
+@ifclear BARETARGET
+@cindex shared libraries
+@value{GDBN} supports SunOS, SVr4, Irix 5, and IBM RS/6000 shared libraries.
+@value{GDBN} automatically loads symbol definitions from shared libraries
+when you use the @code{run} command, or when you examine a core file.
+(Before you issue the @code{run} command, @value{GDBN} does not understand
+references to a function in a shared library, however---unless you are
+debugging a core file).
+@c FIXME: some @value{GDBN} release may permit some refs to undef
+@c FIXME...symbols---eg in a break cmd---assuming they are from a shared
+@c FIXME...lib; check this from time to time when updating manual
+
+@table @code
+@item info share
+@itemx info sharedlibrary
+@kindex info sharedlibrary
+@kindex info share
+Print the names of the shared libraries which are currently loaded.
+
+@item sharedlibrary @var{regex}
+@itemx share @var{regex}
+@kindex sharedlibrary
+@kindex share
+This is an obsolescent command; you can use it to explicitly load shared
+object library symbols for files matching a Unix regular expression, but
+as with files loaded automatically, it only loads shared libraries
+required by your program for a core file or after typing @code{run}. If
+@var{regex} is omitted all shared libraries required by your program are
+loaded.
+@end table
+@end ifclear
+
+@node Symbol Errors
+@section Errors reading symbol files
+
+While reading a symbol file, @value{GDBN} occasionally encounters problems,
+such as symbol types it does not recognize, or known bugs in compiler
+output. By default, @value{GDBN} does not notify you of such problems, since
+they are relatively common and primarily of interest to people
+debugging compilers. If you are interested in seeing information
+about ill-constructed symbol tables, you can either ask @value{GDBN} to print
+only one message about each such type of problem, no matter how many
+times the problem occurs; or you can ask @value{GDBN} to print more messages,
+to see how many times the problems occur, with the @code{set
+complaints} command (@pxref{Messages/Warnings, ,Optional warnings and
+messages}).
+
+The messages currently printed, and their meanings, include:
+
+@table @code
+@item inner block not inside outer block in @var{symbol}
+
+The symbol information shows where symbol scopes begin and end
+(such as at the start of a function or a block of statements). This
+error indicates that an inner scope block is not fully contained
+in its outer scope blocks.
+
+@value{GDBN} circumvents the problem by treating the inner block as if it had
+the same scope as the outer block. In the error message, @var{symbol}
+may be shown as ``@code{(don't know)}'' if the outer block is not a
+function.
+
+@item block at @var{address} out of order
+
+The symbol information for symbol scope blocks should occur in
+order of increasing addresses. This error indicates that it does not
+do so.
+
+@value{GDBN} does not circumvent this problem, and has trouble
+locating symbols in the source file whose symbols it is reading. (You
+can often determine what source file is affected by specifying
+@code{set verbose on}. @xref{Messages/Warnings, ,Optional warnings and
+messages}.)
+
+@item bad block start address patched
+
+The symbol information for a symbol scope block has a start address
+smaller than the address of the preceding source line. This is known
+to occur in the SunOS 4.1.1 (and earlier) C compiler.
+
+@value{GDBN} circumvents the problem by treating the symbol scope block as
+starting on the previous source line.
+
+@item bad string table offset in symbol @var{n}
+
+@cindex foo
+Symbol number @var{n} contains a pointer into the string table which is
+larger than the size of the string table.
+
+@value{GDBN} circumvents the problem by considering the symbol to have the
+name @code{foo}, which may cause other problems if many symbols end up
+with this name.
+
+@item unknown symbol type @code{0x@var{nn}}
+
+The symbol information contains new data types that @value{GDBN} does not yet
+know how to read. @code{0x@var{nn}} is the symbol type of the misunderstood
+information, in hexadecimal.
+
+@value{GDBN} circumvents the error by ignoring this symbol information. This
+usually allows you to debug your program, though certain symbols
+are not accessible. If you encounter such a problem and feel like
+debugging it, you can debug @code{@value{GDBP}} with itself, breakpoint on
+@code{complain}, then go up to the function @code{read_dbx_symtab} and
+examine @code{*bufp} to see the symbol.
+
+@item stub type has NULL name
+@value{GDBN} could not find the full definition for
+@ifclear CONLY
+a struct or class.
+@end ifclear
+@ifset CONLY
+a struct.
+@end ifset
+
+@ifclear CONLY
+@item const/volatile indicator missing (ok if using g++ v1.x), got@dots{}
+
+The symbol information for a C++ member function is missing some
+information that recent versions of the compiler should have output
+for it.
+@end ifclear
+
+@item info mismatch between compiler and debugger
+
+@value{GDBN} could not parse a type specification output by the compiler.
+@end table
+
+@node Targets
+@chapter Specifying a Debugging Target
+@cindex debugging target
+@kindex target
+
+A @dfn{target} is the execution environment occupied by your program.
+@ifclear BARETARGET
+Often, @value{GDBN} runs in the same host environment as your program; in
+that case, the debugging target is specified as a side effect when you
+use the @code{file} or @code{core} commands. When you need more
+flexibility---for example, running @value{GDBN} on a physically separate
+host, or controlling a standalone system over a serial port or a
+realtime system over a TCP/IP connection---you
+@end ifclear
+@ifset BARETARGET
+You
+@end ifset
+can use the @code{target} command to specify one of the target types
+configured for @value{GDBN} (@pxref{Target Commands, ,Commands for managing
+targets}).
+
+@menu
+* Active Targets:: Active targets
+* Target Commands:: Commands for managing targets
+* Remote:: Remote debugging
+@end menu
+
+@node Active Targets
+@section Active targets
+@cindex stacking targets
+@cindex active targets
+@cindex multiple targets
+
+@ifclear BARETARGET
+There are three classes of targets: processes, core files, and
+executable files. @value{GDBN} can work concurrently on up to three active
+targets, one in each class. This allows you to (for example) start a
+process and inspect its activity without abandoning your work on a core
+file.
+
+For example, if you execute @samp{gdb a.out}, then the executable file
+@code{a.out} is the only active target. If you designate a core file as
+well---presumably from a prior run that crashed and coredumped---then
+@value{GDBN} has two active targets and uses them in tandem, looking
+first in the corefile target, then in the executable file, to satisfy
+requests for memory addresses. (Typically, these two classes of target
+are complementary, since core files contain only a program's
+read-write memory---variables and so on---plus machine status, while
+executable files contain only the program text and initialized data.)
+@end ifclear
+
+When you type @code{run}, your executable file becomes an active process
+target as well. When a process target is active, all @value{GDBN} commands
+requesting memory addresses refer to that target; addresses in an
+@ifclear BARETARGET
+active core file or
+@end ifclear
+executable file target are obscured while the process
+target is active.
+
+@ifset BARETARGET
+Use the @code{exec-file} command to select a
+new executable target (@pxref{Files, ,Commands to specify
+files}).
+@end ifset
+@ifclear BARETARGET
+Use the @code{core-file} and @code{exec-file} commands to select a
+new core file or executable target (@pxref{Files, ,Commands to specify
+files}). To specify as a target a process that is already running, use
+the @code{attach} command (@pxref{Attach, ,Debugging an
+already-running process}).
+@end ifclear
+
+@node Target Commands
+@section Commands for managing targets
+
+@table @code
+@item target @var{type} @var{parameters}
+Connects the @value{GDBN} host environment to a target
+@ifset BARETARGET
+machine.
+@end ifset
+@ifclear BARETARGET
+machine or process. A target is typically a protocol for talking to
+debugging facilities. You use the argument @var{type} to specify the
+type or protocol of the target machine.
+
+Further @var{parameters} are interpreted by the target protocol, but
+typically include things like device names or host names to connect
+with, process numbers, and baud rates.
+@end ifclear
+
+The @code{target} command does not repeat if you press @key{RET} again
+after executing the command.
+
+@item help target
+@kindex help target
+Displays the names of all targets available. To display targets
+currently selected, use either @code{info target} or @code{info files}
+(@pxref{Files, ,Commands to specify files}).
+
+@item help target @var{name}
+Describe a particular target, including any parameters necessary to
+select it.
+@end table
+
+Here are some common targets (available, or not, depending on the GDB
+configuration):
+
+@table @code
+@item target exec @var{program}
+@kindex target exec
+An executable file. @samp{target exec @var{program}} is the same as
+@samp{exec-file @var{program}}.
+
+@ifclear BARETARGET
+@item target core @var{filename}
+@kindex target core
+A core dump file. @samp{target core @var{filename}} is the same as
+@samp{core-file @var{filename}}.
+@end ifclear
+
+@ifset REMOTESTUB
+@item target remote @var{dev}
+@kindex target remote
+Remote serial target in GDB-specific protocol. The argument @var{dev}
+specifies what serial device to use for the connection (e.g.
+@file{/dev/ttya}). @xref{Remote, ,Remote debugging}.
+@end ifset
+
+@ifset SIMS
+@item target sim
+@kindex target sim
+CPU simulator. @xref{Simulator,,Simulated CPU Target}.
+@end ifset
+
+@ifset AMD29K
+@item target udi @var{keyword}
+@kindex target udi
+Remote AMD29K target, using the AMD UDI protocol. The @var{keyword}
+argument specifies which 29K board or simulator to use. @xref{UDI29K
+Remote,,The UDI protocol for AMD29K}.
+
+@item target amd-eb @var{dev} @var{speed} @var{PROG}
+@kindex target amd-eb
+@cindex AMD EB29K
+Remote PC-resident AMD EB29K board, attached over serial lines.
+@var{dev} is the serial device, as for @code{target remote};
+@var{speed} allows you to specify the linespeed; and @var{PROG} is the
+name of the program to be debugged, as it appears to DOS on the PC.
+@xref{EB29K Remote, ,The EBMON protocol for AMD29K}.
+
+@end ifset
+@ifset H8
+@item target hms
+@kindex target hms
+A Hitachi SH, H8/300, or H8/500 board, attached via serial line to your host.
+@ifclear H8EXCLUSIVE
+@c Unix only, not currently of interest for H8-only manual
+Use special commands @code{device} and @code{speed} to control the serial
+line and the communications speed used.
+@end ifclear
+@xref{Hitachi Remote,,@value{GDBN} and Hitachi Microprocessors}.
+
+@end ifset
+@ifset I960
+@item target nindy @var{devicename}
+@kindex target nindy
+An Intel 960 board controlled by a Nindy Monitor. @var{devicename} is
+the name of the serial device to use for the connection, e.g.
+@file{/dev/ttya}. @xref{i960-Nindy Remote, ,@value{GDBN} with a remote i960 (Nindy)}.
+
+@end ifset
+@ifset ST2000
+@item target st2000 @var{dev} @var{speed}
+@kindex target st2000
+A Tandem ST2000 phone switch, running Tandem's STDBUG protocol. @var{dev}
+is the name of the device attached to the ST2000 serial line;
+@var{speed} is the communication line speed. The arguments are not used
+if @value{GDBN} is configured to connect to the ST2000 using TCP or Telnet.
+@xref{ST2000 Remote,,@value{GDBN} with a Tandem ST2000}.
+
+@end ifset
+@ifset VXWORKS
+@item target vxworks @var{machinename}
+@kindex target vxworks
+A VxWorks system, attached via TCP/IP. The argument @var{machinename}
+is the target system's machine name or IP address.
+@xref{VxWorks Remote, ,@value{GDBN} and VxWorks}.
+@end ifset
+@end table
+
+@ifset GENERIC
+Different targets are available on different configurations of @value{GDBN}; your
+configuration may have more or fewer targets.
+@end ifset
+
+@node Remote
+@section Remote debugging
+@cindex remote debugging
+
+If you are trying to debug a program running on a machine that cannot run
+GDB in the usual way, it is often useful to use remote debugging. For
+example, you might use remote debugging on an operating system kernel, or on
+a small system which does not have a general purpose operating system
+powerful enough to run a full-featured debugger.
+
+Some configurations of GDB have special serial or TCP/IP interfaces
+to make this work with particular debugging targets. In addition,
+GDB comes with a generic serial protocol (specific to GDB, but
+not specific to any particular target system) which you can use if you
+write the remote stubs---the code that runs on the remote system to
+communicate with GDB.
+
+Other remote targets may be available in your
+configuration of GDB; use @code{help target} to list them.
+
+@ifset GENERIC
+@c Text on starting up GDB in various specific cases; it goes up front
+@c in manuals configured for any of those particular situations, here
+@c otherwise.
+@menu
+@ifset REMOTESTUB
+* Remote Serial:: @value{GDBN} remote serial protocol
+@end ifset
+@ifset I960
+* i960-Nindy Remote:: @value{GDBN} with a remote i960 (Nindy)
+@end ifset
+@ifset AMD29K
+* UDI29K Remote:: The UDI protocol for AMD29K
+* EB29K Remote:: The EBMON protocol for AMD29K
+@end ifset
+@ifset VXWORKS
+* VxWorks Remote:: @value{GDBN} and VxWorks
+@end ifset
+@ifset ST2000
+* ST2000 Remote:: @value{GDBN} with a Tandem ST2000
+@end ifset
+@ifset H8
+* Hitachi Remote:: @value{GDBN} and Hitachi Microprocessors
+@end ifset
+@ifset MIPS
+* MIPS Remote:: @value{GDBN} and MIPS boards
+@end ifset
+@ifset SIMS
+* Simulator:: Simulated CPU target
+@end ifset
+@end menu
+
+@include remote.texi
+@end ifset
+
+@node Controlling GDB
+@chapter Controlling @value{GDBN}
+
+You can alter the way @value{GDBN} interacts with you by using
+the @code{set} command. For commands controlling how @value{GDBN} displays
+data, @pxref{Print Settings, ,Print settings}; other settings are described here.
+
+@menu
+* Prompt:: Prompt
+* Editing:: Command editing
+* History:: Command history
+* Screen Size:: Screen size
+* Numbers:: Numbers
+* Messages/Warnings:: Optional warnings and messages
+@end menu
+
+@node Prompt
+@section Prompt
+@cindex prompt
+
+@value{GDBN} indicates its readiness to read a command by printing a string
+called the @dfn{prompt}. This string is normally @samp{(@value{GDBP})}. You
+can change the prompt string with the @code{set prompt} command. For
+instance, when debugging @value{GDBN} with @value{GDBN}, it is useful to change
+the prompt in one of the @value{GDBN} sessions so that you can always tell which
+one you are talking to.
+
+@table @code
+@item set prompt @var{newprompt}
+@kindex set prompt
+Directs @value{GDBN} to use @var{newprompt} as its prompt string henceforth.
+@kindex show prompt
+@item show prompt
+Prints a line of the form: @samp{Gdb's prompt is: @var{your-prompt}}
+@end table
+
+@node Editing
+@section Command editing
+@cindex readline
+@cindex command line editing
+
+@value{GDBN} reads its input commands via the @dfn{readline} interface. This
+GNU library provides consistent behavior for programs which provide a
+command line interface to the user. Advantages are @code{emacs}-style
+or @code{vi}-style inline editing of commands, @code{csh}-like history
+substitution, and a storage and recall of command history across
+debugging sessions.
+
+You may control the behavior of command line editing in @value{GDBN} with the
+command @code{set}.
+
+@table @code
+@kindex set editing
+@cindex editing
+@item set editing
+@itemx set editing on
+Enable command line editing (enabled by default).
+
+@item set editing off
+Disable command line editing.
+
+@kindex show editing
+@item show editing
+Show whether command line editing is enabled.
+@end table
+
+@node History
+@section Command history
+
+@value{GDBN} can keep track of the commands you type during your
+debugging sessions, so that you can be certain of precisely what
+happened. Use these commands to manage the @value{GDBN} command
+history facility.
+
+@table @code
+@cindex history substitution
+@cindex history file
+@kindex set history filename
+@kindex GDBHISTFILE
+@item set history filename @var{fname}
+Set the name of the @value{GDBN} command history file to @var{fname}.
+This is the file where @value{GDBN} reads an initial command history
+list, and where it writes the command history from this session when it
+exits. You can access this list through history expansion or through
+the history command editing characters listed below. This file defaults
+to the value of the environment variable @code{GDBHISTFILE}, or to
+@file{./.gdb_history} if this variable is not set.
+
+@cindex history save
+@kindex set history save
+@item set history save
+@itemx set history save on
+Record command history in a file, whose name may be specified with the
+@code{set history filename} command. By default, this option is disabled.
+
+@item set history save off
+Stop recording command history in a file.
+
+@cindex history size
+@kindex set history size
+@item set history size @var{size}
+Set the number of commands which @value{GDBN} keeps in its history list.
+This defaults to the value of the environment variable
+@code{HISTSIZE}, or to 256 if this variable is not set.
+@end table
+
+@cindex history expansion
+History expansion assigns special meaning to the character @kbd{!}.
+@ifset have-readline-appendices
+@xref{Event Designators}.
+@end ifset
+
+Since @kbd{!} is also the logical not operator in C, history expansion
+is off by default. If you decide to enable history expansion with the
+@code{set history expansion on} command, you may sometimes need to
+follow @kbd{!} (when it is used as logical not, in an expression) with
+a space or a tab to prevent it from being expanded. The readline
+history facilities do not attempt substitution on the strings
+@kbd{!=} and @kbd{!(}, even when history expansion is enabled.
+
+The commands to control history expansion are:
+
+@table @code
+
+@kindex set history expansion
+@item set history expansion on
+@itemx set history expansion
+Enable history expansion. History expansion is off by default.
+
+@item set history expansion off
+Disable history expansion.
+
+The readline code comes with more complete documentation of
+editing and history expansion features. Users unfamiliar with @code{emacs}
+or @code{vi} may wish to read it.
+@ifset have-readline-appendices
+@xref{Command Line Editing}.
+@end ifset
+
+@c @group
+@kindex show history
+@item show history
+@itemx show history filename
+@itemx show history save
+@itemx show history size
+@itemx show history expansion
+These commands display the state of the @value{GDBN} history parameters.
+@code{show history} by itself displays all four states.
+@c @end group
+@end table
+
+@table @code
+@kindex show commands
+@item show commands
+Display the last ten commands in the command history.
+
+@item show commands @var{n}
+Print ten commands centered on command number @var{n}.
+
+@item show commands +
+Print ten commands just after the commands last printed.
+@end table
+
+@node Screen Size
+@section Screen size
+@cindex size of screen
+@cindex pauses in output
+
+Certain commands to @value{GDBN} may produce large amounts of
+information output to the screen. To help you read all of it,
+@value{GDBN} pauses and asks you for input at the end of each page of
+output. Type @key{RET} when you want to continue the output, or @kbd{q}
+to discard the remaining output. Also, the screen width setting
+determines when to wrap lines of output. Depending on what is being
+printed, @value{GDBN} tries to break the line at a readable place,
+rather than simply letting it overflow onto the following line.
+
+Normally @value{GDBN} knows the size of the screen from the termcap data base
+together with the value of the @code{TERM} environment variable and the
+@code{stty rows} and @code{stty cols} settings. If this is not correct,
+you can override it with the @code{set height} and @code{set
+width} commands:
+
+@table @code
+@item set height @var{lpp}
+@itemx show height
+@itemx set width @var{cpl}
+@itemx show width
+@kindex set height
+@kindex set width
+@kindex show width
+@kindex show height
+These @code{set} commands specify a screen height of @var{lpp} lines and
+a screen width of @var{cpl} characters. The associated @code{show}
+commands display the current settings.
+
+If you specify a height of zero lines, @value{GDBN} does not pause during output
+no matter how long the output is. This is useful if output is to a file
+or to an editor buffer.
+
+Likewise, you can specify @samp{set width 0} to prevent @value{GDBN}
+from wrapping its output.
+@end table
+
+@node Numbers
+@section Numbers
+@cindex number representation
+@cindex entering numbers
+
+You can always enter numbers in octal, decimal, or hexadecimal in @value{GDBN} by
+the usual conventions: octal numbers begin with @samp{0}, decimal
+numbers end with @samp{.}, and hexadecimal numbers begin with @samp{0x}.
+Numbers that begin with none of these are, by default, entered in base
+10; likewise, the default display for numbers---when no particular
+format is specified---is base 10. You can change the default base for
+both input and output with the @code{set radix} command.
+
+@table @code
+@kindex set radix
+@item set radix @var{base}
+Set the default base for numeric input and display. Supported choices
+for @var{base} are decimal 8, 10, or 16. @var{base} must itself be
+specified either unambiguously or using the current default radix; for
+example, any of
+
+@example
+set radix 012
+set radix 10.
+set radix 0xa
+@end example
+
+@noindent
+sets the base to decimal. On the other hand, @samp{set radix 10}
+leaves the radix unchanged no matter what it was.
+
+@kindex show radix
+@item show radix
+Display the current default base for numeric input and display.
+@end table
+
+@node Messages/Warnings
+@section Optional warnings and messages
+
+By default, @value{GDBN} is silent about its inner workings. If you are running
+on a slow machine, you may want to use the @code{set verbose} command.
+It makes @value{GDBN} tell you when it does a lengthy internal operation, so
+you will not think it has crashed.
+
+Currently, the messages controlled by @code{set verbose} are those
+which announce that the symbol table for a source file is being read;
+see @code{symbol-file} in @ref{Files, ,Commands to specify files}.
+
+@table @code
+@kindex set verbose
+@item set verbose on
+Enables @value{GDBN} output of certain informational messages.
+
+@item set verbose off
+Disables @value{GDBN} output of certain informational messages.
+
+@kindex show verbose
+@item show verbose
+Displays whether @code{set verbose} is on or off.
+@end table
+
+By default, if @value{GDBN} encounters bugs in the symbol table of an object
+file, it is silent; but if you are debugging a compiler, you may find
+this information useful (@pxref{Symbol Errors, ,Errors reading symbol files}).
+
+@table @code
+@kindex set complaints
+@item set complaints @var{limit}
+Permits @value{GDBN} to output @var{limit} complaints about each type of unusual
+symbols before becoming silent about the problem. Set @var{limit} to
+zero to suppress all complaints; set it to a large number to prevent
+complaints from being suppressed.
+
+@kindex show complaints
+@item show complaints
+Displays how many symbol complaints @value{GDBN} is permitted to produce.
+@end table
+
+By default, @value{GDBN} is cautious, and asks what sometimes seems to be a
+lot of stupid questions to confirm certain commands. For example, if
+you try to run a program which is already running:
+
+@example
+(@value{GDBP}) run
+The program being debugged has been started already.
+Start it from the beginning? (y or n)
+@end example
+
+If you are willing to unflinchingly face the consequences of your own
+commands, you can disable this ``feature'':
+
+@table @code
+@kindex set confirm
+@cindex flinching
+@cindex confirmation
+@cindex stupid questions
+@item set confirm off
+Disables confirmation requests.
+
+@item set confirm on
+Enables confirmation requests (the default).
+
+@item show confirm
+@kindex show confirm
+Displays state of confirmation requests.
+@end table
+
+@c FIXME this does not really belong here. But where *does* it belong?
+@cindex reloading symbols
+Some systems allow individual object files that make up your program to
+be replaced without stopping and restarting your program.
+@ifset VXWORKS
+For example, in VxWorks you can simply recompile a defective object file
+and keep on running.
+@end ifset
+If you are running on one of these systems, you can allow @value{GDBN} to
+reload the symbols for automatically relinked modules:
+
+@table @code
+@kindex set symbol-reloading
+@item set symbol-reloading on
+Replace symbol definitions for the corresponding source file when an
+object file with a particular name is seen again.
+
+@item set symbol-reloading off
+Do not replace symbol definitions when re-encountering object files of
+the same name. This is the default state; if you are not running on a
+system that permits automatically relinking modules, you should leave
+@code{symbol-reloading} off, since otherwise @value{GDBN} may discard symbols
+when linking large programs, that may contain several modules (from
+different directories or libraries) with the same name.
+
+@item show symbol-reloading
+Show the current @code{on} or @code{off} setting.
+@end table
+
+@node Sequences
+@chapter Canned Sequences of Commands
+
+Aside from breakpoint commands (@pxref{Break Commands, ,Breakpoint
+command lists}), @value{GDBN} provides two ways to store sequences of commands
+for execution as a unit: user-defined commands and command files.
+
+@menu
+* Define:: User-defined commands
+* Hooks:: User-defined command hooks
+* Command Files:: Command files
+* Output:: Commands for controlled output
+@end menu
+
+@node Define
+@section User-defined commands
+
+@cindex user-defined command
+A @dfn{user-defined command} is a sequence of @value{GDBN} commands to which you
+assign a new name as a command. This is done with the @code{define}
+command.
+
+@table @code
+@item define @var{commandname}
+@kindex define
+Define a command named @var{commandname}. If there is already a command
+by that name, you are asked to confirm that you want to redefine it.
+
+The definition of the command is made up of other @value{GDBN} command lines,
+which are given following the @code{define} command. The end of these
+commands is marked by a line containing @code{end}.
+
+@item document @var{commandname}
+@kindex document
+Give documentation to the user-defined command @var{commandname}. The
+command @var{commandname} must already be defined. This command reads
+lines of documentation just as @code{define} reads the lines of the
+command definition, ending with @code{end}. After the @code{document}
+command is finished, @code{help} on command @var{commandname} displays
+the documentation you have specified.
+
+You may use the @code{document} command again to change the
+documentation of a command. Redefining the command with @code{define}
+does not change the documentation.
+
+@item help user-defined
+@kindex help user-defined
+List all user-defined commands, with the first line of the documentation
+(if any) for each.
+
+@item show user
+@itemx show user @var{commandname}
+@kindex show user
+Display the @value{GDBN} commands used to define @var{commandname} (but not its
+documentation). If no @var{commandname} is given, display the
+definitions for all user-defined commands.
+@end table
+
+User-defined commands do not take arguments. When they are executed, the
+commands of the definition are not printed. An error in any command
+stops execution of the user-defined command.
+
+Commands that would ask for confirmation if used interactively proceed
+without asking when used inside a user-defined command. Many @value{GDBN} commands
+that normally print messages to say what they are doing omit the messages
+when used in a user-defined command.
+
+@node Hooks
+@section User-defined command hooks
+@cindex command files
+
+You may define @emph{hooks}, which are a special kind of user-defined
+command. Whenever you run the command @samp{foo}, if the user-defined
+command @samp{hook-foo} exists, it is executed (with no arguments)
+before that command.
+
+In addition, a pseudo-command, @samp{stop} exists. Defining
+(@samp{hook-stop}) makes the associated commands execute every time
+execution stops in your program: before breakpoint commands are run,
+displays are printed, or the stack frame is printed.
+
+@ifclear BARETARGET
+For example, to ignore @code{SIGALRM} signals while
+single-stepping, but treat them normally during normal execution,
+you could define:
+
+@example
+define hook-stop
+handle SIGALRM nopass
+end
+
+define hook-run
+handle SIGALRM pass
+end
+
+define hook-continue
+handle SIGLARM pass
+end
+@end example
+@end ifclear
+
+You can define a hook for any single-word command in @value{GDBN}, but
+not for command aliases; you should define a hook for the basic command
+name, e.g. @code{backtrace} rather than @code{bt}.
+@c FIXME! So how does Joe User discover whether a command is an alias
+@c or not?
+If an error occurs during the execution of your hook, execution of
+@value{GDBN} commands stops and @value{GDBN} issues a prompt
+(before the command that you actually typed had a chance to run).
+
+If you try to define a hook which does not match any known command, you
+get a warning from the @code{define} command.
+
+@node Command Files
+@section Command files
+
+@cindex command files
+A command file for @value{GDBN} is a file of lines that are @value{GDBN} commands. Comments
+(lines starting with @kbd{#}) may also be included. An empty line in a
+command file does nothing; it does not mean to repeat the last command, as
+it would from the terminal.
+
+@cindex init file
+@cindex @file{@value{GDBINIT}}
+When you start @value{GDBN}, it automatically executes commands from its
+@dfn{init files}. These are files named @file{@value{GDBINIT}}.
+@value{GDBN} reads the init file (if any) in your home directory, then
+processes command line options and operands, and then reads the init
+file (if any) in the current working directory. This is so the init
+file in your home directory can set options (such as @code{set
+complaints}) which affect the processing of the command line options and
+operands. The init files are not executed if you use the @samp{-nx}
+option; @pxref{Mode Options, ,Choosing modes}.
+
+@ifset GENERIC
+@cindex init file name
+On some configurations of @value{GDBN}, the init file is known by a
+different name (these are typically environments where a specialized
+form of GDB may need to coexist with other forms, hence a different name
+for the specialized version's init file). These are the environments
+with special init file names:
+
+@itemize @bullet
+@kindex .vxgdbinit
+@item
+VxWorks (Wind River Systems real-time OS): @samp{.vxgdbinit}
+
+@kindex .os68gdbinit
+@item
+OS68K (Enea Data Systems real-time OS): @samp{.os68gdbinit}
+
+@kindex .esgdbinit
+@item
+ES-1800 (Ericsson Telecom AB M68000 emulator): @samp{.esgdbinit}
+@end itemize
+@end ifset
+
+You can also request the execution of a command file with the
+@code{source} command:
+
+@table @code
+@item source @var{filename}
+@kindex source
+Execute the command file @var{filename}.
+@end table
+
+The lines in a command file are executed sequentially. They are not
+printed as they are executed. An error in any command terminates execution
+of the command file.
+
+Commands that would ask for confirmation if used interactively proceed
+without asking when used in a command file. Many @value{GDBN} commands that
+normally print messages to say what they are doing omit the messages
+when called from command files.
+
+@node Output
+@section Commands for controlled output
+
+During the execution of a command file or a user-defined command, normal
+@value{GDBN} output is suppressed; the only output that appears is what is
+explicitly printed by the commands in the definition. This section
+describes three commands useful for generating exactly the output you
+want.
+
+@table @code
+@item echo @var{text}
+@kindex echo
+@c I do not consider backslash-space a standard C escape sequence
+@c because it is not in ANSI.
+Print @var{text}. Nonprinting characters can be included in
+@var{text} using C escape sequences, such as @samp{\n} to print a
+newline. @strong{No newline is printed unless you specify one.}
+In addition to the standard C escape sequences, a backslash followed
+by a space stands for a space. This is useful for displaying a
+string with spaces at the beginning or the end, since leading and
+trailing spaces are otherwise trimmed from all arguments.
+To print @samp{@w{ }and foo =@w{ }}, use the command
+@samp{echo \@w{ }and foo = \@w{ }}.
+
+A backslash at the end of @var{text} can be used, as in C, to continue
+the command onto subsequent lines. For example,
+
+@example
+echo This is some text\n\
+which is continued\n\
+onto several lines.\n
+@end example
+
+produces the same output as
+
+@example
+echo This is some text\n
+echo which is continued\n
+echo onto several lines.\n
+@end example
+
+@item output @var{expression}
+@kindex output
+Print the value of @var{expression} and nothing but that value: no
+newlines, no @samp{$@var{nn} = }. The value is not entered in the
+value history either. @xref{Expressions, ,Expressions}, for more information on
+expressions.
+
+@item output/@var{fmt} @var{expression}
+Print the value of @var{expression} in format @var{fmt}. You can use
+the same formats as for @code{print}. @xref{Output Formats,,Output
+formats}, for more information.
+
+@item printf @var{string}, @var{expressions}@dots{}
+@kindex printf
+Print the values of the @var{expressions} under the control of
+@var{string}. The @var{expressions} are separated by commas and may be
+either numbers or pointers. Their values are printed as specified by
+@var{string}, exactly as if your program were to execute the C
+subroutine
+
+@example
+printf (@var{string}, @var{expressions}@dots{});
+@end example
+
+For example, you can print two values in hex like this:
+
+@smallexample
+printf "foo, bar-foo = 0x%x, 0x%x\n", foo, bar-foo
+@end smallexample
+
+The only backslash-escape sequences that you can use in the format
+string are the simple ones that consist of backslash followed by a
+letter.
+@end table
+
+@ifclear DOSHOST
+@node Emacs
+@chapter Using @value{GDBN} under GNU Emacs
+
+@cindex emacs
+A special interface allows you to use GNU Emacs to view (and
+edit) the source files for the program you are debugging with
+@value{GDBN}.
+
+To use this interface, use the command @kbd{M-x gdb} in Emacs. Give the
+executable file you want to debug as an argument. This command starts
+@value{GDBN} as a subprocess of Emacs, with input and output through a newly
+created Emacs buffer.
+
+Using @value{GDBN} under Emacs is just like using @value{GDBN} normally except for two
+things:
+
+@itemize @bullet
+@item
+All ``terminal'' input and output goes through the Emacs buffer.
+@end itemize
+
+This applies both to @value{GDBN} commands and their output, and to the input
+and output done by the program you are debugging.
+
+This is useful because it means that you can copy the text of previous
+commands and input them again; you can even use parts of the output
+in this way.
+
+All the facilities of Emacs' Shell mode are available for interacting
+with your program. In particular, you can send signals the usual
+way---for example, @kbd{C-c C-c} for an interrupt, @kbd{C-c C-z} for a
+stop.
+
+@itemize @bullet
+@item
+@value{GDBN} displays source code through Emacs.
+@end itemize
+
+Each time @value{GDBN} displays a stack frame, Emacs automatically finds the
+source file for that frame and puts an arrow (@samp{=>}) at the
+left margin of the current line. Emacs uses a separate buffer for
+source display, and splits the screen to show both your @value{GDBN} session
+and the source.
+
+Explicit @value{GDBN} @code{list} or search commands still produce output as
+usual, but you probably have no reason to use them from Emacs.
+
+@quotation
+@emph{Warning:} If the directory where your program resides is not your
+current directory, it can be easy to confuse Emacs about the location of
+the source files, in which case the auxiliary display buffer does not
+appear to show your source. @value{GDBN} can find programs by searching your
+environment's @code{PATH} variable, so the @value{GDBN} input and output
+session proceeds normally; but Emacs does not get enough information
+back from @value{GDBN} to locate the source files in this situation. To
+avoid this problem, either start @value{GDBN} mode from the directory where
+your program resides, or specify an absolute file name when prompted for the
+@kbd{M-x gdb} argument.
+
+A similar confusion can result if you use the @value{GDBN} @code{file} command to
+switch to debugging a program in some other location, from an existing
+@value{GDBN} buffer in Emacs.
+@end quotation
+
+By default, @kbd{M-x gdb} calls the program called @file{gdb}. If
+you need to call @value{GDBN} by a different name (for example, if you keep
+several configurations around, with different names) you can set the
+Emacs variable @code{gdb-command-name}; for example,
+
+@example
+(setq gdb-command-name "mygdb")
+@end example
+
+@noindent
+(preceded by @kbd{ESC ESC}, or typed in the @code{*scratch*} buffer, or
+in your @file{.emacs} file) makes Emacs call the program named
+``@code{mygdb}'' instead.
+
+In the @value{GDBN} I/O buffer, you can use these special Emacs commands in
+addition to the standard Shell mode commands:
+
+@table @kbd
+@item C-h m
+Describe the features of Emacs' @value{GDBN} Mode.
+
+@item M-s
+Execute to another source line, like the @value{GDBN} @code{step} command; also
+update the display window to show the current file and location.
+
+@item M-n
+Execute to next source line in this function, skipping all function
+calls, like the @value{GDBN} @code{next} command. Then update the display window
+to show the current file and location.
+
+@item M-i
+Execute one instruction, like the @value{GDBN} @code{stepi} command; update
+display window accordingly.
+
+@item M-x gdb-nexti
+Execute to next instruction, using the @value{GDBN} @code{nexti} command; update
+display window accordingly.
+
+@item C-c C-f
+Execute until exit from the selected stack frame, like the @value{GDBN}
+@code{finish} command.
+
+@item M-c
+Continue execution of your program, like the @value{GDBN} @code{continue}
+command.
+
+@emph{Warning:} In Emacs v19, this command is @kbd{C-c C-p}.
+
+@item M-u
+Go up the number of frames indicated by the numeric argument
+(@pxref{Arguments, , Numeric Arguments, emacs, The GNU Emacs Manual}),
+like the @value{GDBN} @code{up} command.
+
+@emph{Warning:} In Emacs v19, this command is @kbd{C-c C-u}.
+
+@item M-d
+Go down the number of frames indicated by the numeric argument, like the
+@value{GDBN} @code{down} command.
+
+@emph{Warning:} In Emacs v19, this command is @kbd{C-c C-d}.
+
+@item C-x &
+Read the number where the cursor is positioned, and insert it at the end
+of the @value{GDBN} I/O buffer. For example, if you wish to disassemble code
+around an address that was displayed earlier, type @kbd{disassemble};
+then move the cursor to the address display, and pick up the
+argument for @code{disassemble} by typing @kbd{C-x &}.
+
+You can customize this further by defining elements of the list
+@code{gdb-print-command}; once it is defined, you can format or
+otherwise process numbers picked up by @kbd{C-x &} before they are
+inserted. A numeric argument to @kbd{C-x &} indicates that you
+wish special formatting, and also acts as an index to pick an element of the
+list. If the list element is a string, the number to be inserted is
+formatted using the Emacs function @code{format}; otherwise the number
+is passed as an argument to the corresponding list element.
+@end table
+
+In any source file, the Emacs command @kbd{C-x SPC} (@code{gdb-break})
+tells @value{GDBN} to set a breakpoint on the source line point is on.
+
+If you accidentally delete the source-display buffer, an easy way to get
+it back is to type the command @code{f} in the @value{GDBN} buffer, to
+request a frame display; when you run under Emacs, this recreates
+the source buffer if necessary to show you the context of the current
+frame.
+
+The source files displayed in Emacs are in ordinary Emacs buffers
+which are visiting the source files in the usual way. You can edit
+the files with these buffers if you wish; but keep in mind that @value{GDBN}
+communicates with Emacs in terms of line numbers. If you add or
+delete lines from the text, the line numbers that @value{GDBN} knows cease
+to correspond properly with the code.
+
+@c The following dropped because Epoch is nonstandard. Reactivate
+@c if/when v19 does something similar. ---pesch@cygnus.com 19dec1990
+@ignore
+@kindex emacs epoch environment
+@kindex epoch
+@kindex inspect
+
+Version 18 of Emacs has a built-in window system called the @code{epoch}
+environment. Users of this environment can use a new command,
+@code{inspect} which performs identically to @code{print} except that
+each value is printed in its own window.
+@end ignore
+@end ifclear
+
+@ifset LUCID
+@node Energize
+@chapter Using @value{GDBN} with Energize
+
+@cindex Energize
+The Energize Programming System is an integrated development environment
+that includes a point-and-click interface to many programming tools.
+When you use @value{GDBN} in this environment, you can use the standard
+Energize graphical interface to drive @value{GDBN}; you can also, if you
+choose, type @value{GDBN} commands as usual in a debugging window. Even if
+you use the graphical interface, the debugging window (which uses Emacs,
+and resembles the standard Emacs interface to @value{GDBN}) displays the
+equivalent commands, so that the history of your debugging session is
+properly reflected.
+
+When Energize starts up a @value{GDBN} session, it uses one of the
+command-line options @samp{-energize} or @samp{-cadillac} (``cadillac''
+is the name of the communications protocol used by the Energize system).
+This option makes @value{GDBN} run as one of the tools in the Energize Tool
+Set: it sends all output to the Energize kernel, and accept input from
+it as well.
+
+See the user manual for the Energize Programming System for
+information on how to use the Energize graphical interface and the other
+development tools that Energize integrates with @value{GDBN}.
+
+@end ifset
+
+@node GDB Bugs
+@chapter Reporting Bugs in @value{GDBN}
+@cindex bugs in @value{GDBN}
+@cindex reporting bugs in @value{GDBN}
+
+Your bug reports play an essential role in making @value{GDBN} reliable.
+
+Reporting a bug may help you by bringing a solution to your problem, or it
+may not. But in any case the principal function of a bug report is to help
+the entire community by making the next version of @value{GDBN} work better. Bug
+reports are your contribution to the maintenance of @value{GDBN}.
+
+In order for a bug report to serve its purpose, you must include the
+information that enables us to fix the bug.
+
+@menu
+* Bug Criteria:: Have you found a bug?
+* Bug Reporting:: How to report bugs
+@end menu
+
+@node Bug Criteria
+@section Have you found a bug?
+@cindex bug criteria
+
+If you are not sure whether you have found a bug, here are some guidelines:
+
+@itemize @bullet
+@item
+@cindex fatal signal
+@cindex debugger crash
+@cindex crash of debugger
+If the debugger gets a fatal signal, for any input whatever, that is a
+@value{GDBN} bug. Reliable debuggers never crash.
+
+@item
+@cindex error on valid input
+If @value{GDBN} produces an error message for valid input, that is a bug.
+
+@item
+@cindex invalid input
+If @value{GDBN} does not produce an error message for invalid input,
+that is a bug. However, you should note that your idea of
+``invalid input'' might be our idea of ``an extension'' or ``support
+for traditional practice''.
+
+@item
+If you are an experienced user of debugging tools, your suggestions
+for improvement of @value{GDBN} are welcome in any case.
+@end itemize
+
+@node Bug Reporting
+@section How to report bugs
+@cindex bug reports
+@cindex @value{GDBN} bugs, reporting
+
+A number of companies and individuals offer support for GNU products.
+If you obtained @value{GDBN} from a support organization, we recommend you
+contact that organization first.
+
+You can find contact information for many support companies and
+individuals in the file @file{etc/SERVICE} in the GNU Emacs
+distribution.
+
+In any event, we also recommend that you send bug reports for @value{GDBN} to one
+of these addresses:
+
+@example
+bug-gdb@@prep.ai.mit.edu
+@{ucbvax|mit-eddie|uunet@}!prep.ai.mit.edu!bug-gdb
+@end example
+
+@strong{Do not send bug reports to @samp{info-gdb}, or to
+@samp{help-gdb}, or to any newsgroups.} Most users of @value{GDBN} do not want to
+receive bug reports. Those that do, have arranged to receive @samp{bug-gdb}.
+
+The mailing list @samp{bug-gdb} has a newsgroup @samp{gnu.gdb.bug} which
+serves as a repeater. The mailing list and the newsgroup carry exactly
+the same messages. Often people think of posting bug reports to the
+newsgroup instead of mailing them. This appears to work, but it has one
+problem which can be crucial: a newsgroup posting often lacks a mail
+path back to the sender. Thus, if we need to ask for more information,
+we may be unable to reach you. For this reason, it is better to send
+bug reports to the mailing list.
+
+As a last resort, send bug reports on paper to:
+
+@example
+GNU Debugger Bugs
+Free Software Foundation
+545 Tech Square
+Cambridge, MA 02139
+@end example
+
+The fundamental principle of reporting bugs usefully is this:
+@strong{report all the facts}. If you are not sure whether to state a
+fact or leave it out, state it!
+
+Often people omit facts because they think they know what causes the
+problem and assume that some details do not matter. Thus, you might
+assume that the name of the variable you use in an example does not matter.
+Well, probably it does not, but one cannot be sure. Perhaps the bug is a
+stray memory reference which happens to fetch from the location where that
+name is stored in memory; perhaps, if the name were different, the contents
+of that location would fool the debugger into doing the right thing despite
+the bug. Play it safe and give a specific, complete example. That is the
+easiest thing for you to do, and the most helpful.
+
+Keep in mind that the purpose of a bug report is to enable us to fix
+the bug if it is new to us. It is not as important as what happens if
+the bug is already known. Therefore, always write your bug reports on
+the assumption that the bug has not been reported previously.
+
+Sometimes people give a few sketchy facts and ask, ``Does this ring a
+bell?'' Those bug reports are useless, and we urge everyone to
+@emph{refuse to respond to them} except to chide the sender to report
+bugs properly.
+
+To enable us to fix the bug, you should include all these things:
+
+@itemize @bullet
+@item
+The version of @value{GDBN}. @value{GDBN} announces it if you start with no
+arguments; you can also print it at any time using @code{show version}.
+
+Without this, we will not know whether there is any point in looking for
+the bug in the current version of @value{GDBN}.
+
+@item
+The type of machine you are using, and the operating system name and
+version number.
+
+@item
+What compiler (and its version) was used to compile @value{GDBN}---e.g.
+``@value{GCC}--2.0''.
+
+@item
+What compiler (and its version) was used to compile the program you
+are debugging---e.g. ``@value{GCC}--2.0''.
+
+@item
+The command arguments you gave the compiler to compile your example and
+observe the bug. For example, did you use @samp{-O}? To guarantee
+you will not omit something important, list them all. A copy of the
+Makefile (or the output from make) is sufficient.
+
+If we were to try to guess the arguments, we would probably guess wrong
+and then we might not encounter the bug.
+
+@item
+A complete input script, and all necessary source files, that will
+reproduce the bug.
+
+@item
+A description of what behavior you observe that you believe is
+incorrect. For example, ``It gets a fatal signal.''
+
+Of course, if the bug is that @value{GDBN} gets a fatal signal, then we will
+certainly notice it. But if the bug is incorrect output, we might not
+notice unless it is glaringly wrong. We are human, after all. You
+might as well not give us a chance to make a mistake.
+
+Even if the problem you experience is a fatal signal, you should still
+say so explicitly. Suppose something strange is going on, such as,
+your copy of @value{GDBN} is out of synch, or you have encountered a
+bug in the C library on your system. (This has happened!) Your copy
+might crash and ours would not. If you told us to expect a crash,
+then when ours fails to crash, we would know that the bug was not
+happening for us. If you had not told us to expect a crash, then we
+would not be able to draw any conclusion from our observations.
+
+@item
+If you wish to suggest changes to the @value{GDBN} source, send us context
+diffs. If you even discuss something in the @value{GDBN} source, refer to
+it by context, not by line number.
+
+The line numbers in our development sources will not match those in your
+sources. Your line numbers would convey no useful information to us.
+@end itemize
+
+Here are some things that are not necessary:
+
+@itemize @bullet
+@item
+A description of the envelope of the bug.
+
+Often people who encounter a bug spend a lot of time investigating
+which changes to the input file will make the bug go away and which
+changes will not affect it.
+
+This is often time consuming and not very useful, because the way we
+will find the bug is by running a single example under the debugger
+with breakpoints, not by pure deduction from a series of examples.
+We recommend that you save your time for something else.
+
+Of course, if you can find a simpler example to report @emph{instead}
+of the original one, that is a convenience for us. Errors in the
+output will be easier to spot, running under the debugger will take
+less time, and so on.
+
+However, simplification is not vital; if you do not want to do this,
+report the bug anyway and send us the entire test case you used.
+
+@item
+A patch for the bug.
+
+A patch for the bug does help us if it is a good one. But do not omit
+the necessary information, such as the test case, on the assumption that
+a patch is all we need. We might see problems with your patch and decide
+to fix the problem another way, or we might not understand it at all.
+
+Sometimes with a program as complicated as @value{GDBN} it is very hard to
+construct an example that will make the program follow a certain path
+through the code. If you do not send us the example, we will not be able
+to construct one, so we will not be able to verify that the bug is fixed.
+
+And if we cannot understand what bug you are trying to fix, or why your
+patch should be an improvement, we will not install it. A test case will
+help us to understand.
+
+@item
+A guess about what the bug is or what it depends on.
+
+Such guesses are usually wrong. Even we cannot guess right about such
+things without first using the debugger to find the facts.
+@end itemize
+
+@c The readline documentation is distributed with the readline code
+@c and consists of the two following files:
+@c rluser.texinfo
+@c inc-hist.texi
+@c Use -I with makeinfo to point to the appropriate directory,
+@c environment var TEXINPUTS with TeX.
+@include rluser.texinfo
+@include inc-hist.texi
+
+@ifset NOVEL
+@node Renamed Commands
+@appendix Renamed Commands
+
+The following commands were renamed in GDB 4, in order to make the
+command set as a whole more consistent and easier to use and remember:
+
+@kindex add-syms
+@kindex delete environment
+@kindex info copying
+@kindex info convenience
+@kindex info directories
+@kindex info editing
+@kindex info history
+@kindex info targets
+@kindex info values
+@kindex info version
+@kindex info warranty
+@kindex set addressprint
+@kindex set arrayprint
+@kindex set prettyprint
+@kindex set screen-height
+@kindex set screen-width
+@kindex set unionprint
+@kindex set vtblprint
+@kindex set demangle
+@kindex set asm-demangle
+@kindex set sevenbit-strings
+@kindex set array-max
+@kindex set caution
+@kindex set history write
+@kindex show addressprint
+@kindex show arrayprint
+@kindex show prettyprint
+@kindex show screen-height
+@kindex show screen-width
+@kindex show unionprint
+@kindex show vtblprint
+@kindex show demangle
+@kindex show asm-demangle
+@kindex show sevenbit-strings
+@kindex show array-max
+@kindex show caution
+@kindex show history write
+@kindex unset
+
+@c TEXI2ROFF-KILL
+@ifinfo
+@c END TEXI2ROFF-KILL
+@example
+OLD COMMAND NEW COMMAND
+@c TEXI2ROFF-KILL
+--------------- -------------------------------
+@c END TEXI2ROFF-KILL
+add-syms add-symbol-file
+delete environment unset environment
+info convenience show convenience
+info copying show copying
+info directories show directories
+info editing show commands
+info history show values
+info targets help target
+info values show values
+info version show version
+info warranty show warranty
+set/show addressprint set/show print address
+set/show array-max set/show print elements
+set/show arrayprint set/show print array
+set/show asm-demangle set/show print asm-demangle
+set/show caution set/show confirm
+set/show demangle set/show print demangle
+set/show history write set/show history save
+set/show prettyprint set/show print pretty
+set/show screen-height set/show height
+set/show screen-width set/show width
+set/show sevenbit-strings set/show print sevenbit-strings
+set/show unionprint set/show print union
+set/show vtblprint set/show print vtbl
+
+unset [No longer an alias for delete]
+@end example
+@c TEXI2ROFF-KILL
+@end ifinfo
+
+@tex
+\vskip \parskip\vskip \baselineskip
+\halign{\tt #\hfil &\qquad#&\tt #\hfil\cr
+{\bf Old Command} &&{\bf New Command}\cr
+add-syms &&add-symbol-file\cr
+delete environment &&unset environment\cr
+info convenience &&show convenience\cr
+info copying &&show copying\cr
+info directories &&show directories \cr
+info editing &&show commands\cr
+info history &&show values\cr
+info targets &&help target\cr
+info values &&show values\cr
+info version &&show version\cr
+info warranty &&show warranty\cr
+set{\rm / }show addressprint &&set{\rm / }show print address\cr
+set{\rm / }show array-max &&set{\rm / }show print elements\cr
+set{\rm / }show arrayprint &&set{\rm / }show print array\cr
+set{\rm / }show asm-demangle &&set{\rm / }show print asm-demangle\cr
+set{\rm / }show caution &&set{\rm / }show confirm\cr
+set{\rm / }show demangle &&set{\rm / }show print demangle\cr
+set{\rm / }show history write &&set{\rm / }show history save\cr
+set{\rm / }show prettyprint &&set{\rm / }show print pretty\cr
+set{\rm / }show screen-height &&set{\rm / }show height\cr
+set{\rm / }show screen-width &&set{\rm / }show width\cr
+set{\rm / }show sevenbit-strings &&set{\rm / }show print sevenbit-strings\cr
+set{\rm / }show unionprint &&set{\rm / }show print union\cr
+set{\rm / }show vtblprint &&set{\rm / }show print vtbl\cr
+\cr
+unset &&\rm(No longer an alias for delete)\cr
+}
+@end tex
+@c END TEXI2ROFF-KILL
+@end ifset
+
+@ifclear PRECONFIGURED
+@node Formatting Documentation
+@appendix Formatting Documentation
+
+@cindex GDB reference card
+@cindex reference card
+The GDB 4 release includes an already-formatted reference card, ready
+for printing with PostScript or Ghostscript, in the @file{gdb}
+subdirectory of the main source directory@footnote{In
+@file{gdb-@value{GDBVN}/gdb/refcard.ps} of the version @value{GDBVN}
+release.}. If you can use PostScript or Ghostscript with your printer,
+you can print the reference card immediately with @file{refcard.ps}.
+
+The release also includes the source for the reference card. You
+can format it, using @TeX{}, by typing:
+
+@example
+make refcard.dvi
+@end example
+
+The GDB reference card is designed to print in landscape mode on US
+``letter'' size paper; that is, on a sheet 11 inches wide by 8.5 inches
+high. You will need to specify this form of printing as an option to
+your @sc{dvi} output program.
+
+@cindex documentation
+
+All the documentation for GDB comes as part of the machine-readable
+distribution. The documentation is written in Texinfo format, which is
+a documentation system that uses a single source file to produce both
+on-line information and a printed manual. You can use one of the Info
+formatting commands to create the on-line version of the documentation
+and @TeX{} (or @code{texi2roff}) to typeset the printed version.
+
+GDB includes an already formatted copy of the on-line Info version of
+this manual in the @file{gdb} subdirectory. The main Info file is
+@file{gdb-@var{version-number}/gdb/gdb.info}, and it refers to
+subordinate files matching @samp{gdb.info*} in the same directory. If
+necessary, you can print out these files, or read them with any editor;
+but they are easier to read using the @code{info} subsystem in GNU Emacs
+or the standalone @code{info} program, available as part of the GNU
+Texinfo distribution.
+
+If you want to format these Info files yourself, you need one of the
+Info formatting programs, such as @code{texinfo-format-buffer} or
+@code{makeinfo}.
+
+If you have @code{makeinfo} installed, and are in the top level GDB
+source directory (@file{gdb-@value{GDBVN}}, in the case of version @value{GDBVN}), you can
+make the Info file by typing:
+
+@example
+cd gdb
+make gdb.info
+@end example
+
+If you want to typeset and print copies of this manual, you need @TeX{},
+a program to print its @sc{dvi} output files, and @file{texinfo.tex}, the
+Texinfo definitions file.
+
+@TeX{} is a typesetting program; it does not print files directly, but
+produces output files called @sc{dvi} files. To print a typeset
+document, you need a program to print @sc{dvi} files. If your system
+has @TeX{} installed, chances are it has such a program. The precise
+command to use depends on your system; @kbd{lpr -d} is common; another
+(for PostScript devices) is @kbd{dvips}. The @sc{dvi} print command may
+require a file name without any extension or a @samp{.dvi} extension.
+
+@TeX{} also requires a macro definitions file called
+@file{texinfo.tex}. This file tells @TeX{} how to typeset a document
+written in Texinfo format. On its own, @TeX{} cannot read, much less
+typeset a Texinfo file. @file{texinfo.tex} is distributed with GDB
+and is located in the @file{gdb-@var{version-number}/texinfo}
+directory.
+
+If you have @TeX{} and a @sc{dvi} printer program installed, you can
+typeset and print this manual. First switch to the the @file{gdb}
+subdirectory of the main source directory (for example, to
+@file{gdb-@value{GDBVN}/gdb}) and then type:
+
+@example
+make gdb.dvi
+@end example
+
+@node Installing GDB
+@appendix Installing GDB
+@cindex configuring GDB
+@cindex installation
+
+GDB comes with a @code{configure} script that automates the process
+of preparing GDB for installation; you can then use @code{make} to
+build the @code{gdb} program.
+@iftex
+@c irrelevant in info file; it's as current as the code it lives with.
+@footnote{If you have a more recent version of GDB than @value{GDBVN},
+look at the @file{README} file in the sources; we may have improved the
+installation procedures since publishing this manual.}
+@end iftex
+
+The GDB distribution includes all the source code you need for GDB in
+a single directory, whose name is usually composed by appending the
+version number to @samp{gdb}.
+
+For example, the GDB version @value{GDBVN} distribution is in the
+@file{gdb-@value{GDBVN}} directory. That directory contains:
+
+@table @code
+@item gdb-@value{GDBVN}/configure @r{(and supporting files)}
+script for configuring GDB and all its supporting libraries.
+
+@item gdb-@value{GDBVN}/gdb
+the source specific to GDB itself
+
+@item gdb-@value{GDBVN}/bfd
+source for the Binary File Descriptor library
+
+@item gdb-@value{GDBVN}/include
+GNU include files
+
+@item gdb-@value{GDBVN}/libiberty
+source for the @samp{-liberty} free software library
+
+@item gdb-@value{GDBVN}/opcodes
+source for the library of opcode tables and disassemblers
+
+@item gdb-@value{GDBVN}/readline
+source for the GNU command-line interface
+
+@item gdb-@value{GDBVN}/glob
+source for the GNU filename pattern-matching subroutine
+
+@item gdb-@value{GDBVN}/mmalloc
+source for the GNU memory-mapped malloc package
+@end table
+
+The simplest way to configure and build GDB is to run @code{configure}
+from the @file{gdb-@var{version-number}} source directory, which in
+this example is the @file{gdb-@value{GDBVN}} directory.
+
+First switch to the @file{gdb-@var{version-number}} source directory
+if you are not already in it; then run @code{configure}. Pass the
+identifier for the platform on which GDB will run as an
+argument.
+
+For example:
+
+@example
+cd gdb-@value{GDBVN}
+./configure @var{host}
+make
+@end example
+
+@noindent
+where @var{host} is an identifier such as @samp{sun4} or
+@samp{decstation}, that identifies the platform where GDB will run.
+(You can often leave off @var{host}; @code{configure} tries to guess the
+correct value by examining your system.)
+
+Running @samp{configure @var{host}} and then running @code{make} builds the
+@file{bfd}, @file{readline}, @file{mmalloc}, and @file{libiberty}
+libraries, then @code{gdb} itself. The configured source files, and the
+binaries, are left in the corresponding source directories.
+
+@code{configure} is a Bourne-shell (@code{/bin/sh}) script; if your
+system does not recognize this automatically when you run a different
+shell, you may need to run @code{sh} on it explicitly:
+
+@example
+sh configure @var{host}
+@end example
+
+If you run @code{configure} from a directory that contains source
+directories for multiple libraries or programs, such as the
+@file{gdb-@value{GDBVN}} source directory for version @value{GDBVN}, @code{configure}
+creates configuration files for every directory level underneath (unless
+you tell it not to, with the @samp{--norecursion} option).
+
+You can run the @code{configure} script from any of the
+subordinate directories in the GDB distribution if you only want to
+configure that subdirectory, but be sure to specify a path to it.
+
+For example, with version @value{GDBVN}, type the following to configure only
+the @code{bfd} subdirectory:
+
+@example
+@group
+cd gdb-@value{GDBVN}/bfd
+../configure @var{host}
+@end group
+@end example
+
+You can install @code{@value{GDBP}} anywhere; it has no hardwired paths.
+However, you should make sure that the shell on your path (named by
+the @samp{SHELL} environment variable) is publicly readable. Remember
+that GDB uses the shell to start your program---some systems refuse to
+let GDB debug child processes whose programs are not readable.
+
+@menu
+* Separate Objdir:: Compiling GDB in another directory
+* Config Names:: Specifying names for hosts and targets
+* configure Options:: Summary of options for configure
+@end menu
+
+@node Separate Objdir
+@section Compiling GDB in another directory
+
+If you want to run GDB versions for several host or target machines,
+you need a different @code{gdb} compiled for each combination of
+host and target. @code{configure} is designed to make this easy by
+allowing you to generate each configuration in a separate subdirectory,
+rather than in the source directory. If your @code{make} program
+handles the @samp{VPATH} feature (GNU @code{make} does), running
+@code{make} in each of these directories builds the @code{gdb}
+program specified there.
+
+To build @code{gdb} in a separate directory, run @code{configure}
+with the @samp{--srcdir} option to specify where to find the source.
+(You also need to specify a path to find @code{configure}
+itself from your working directory. If the path to @code{configure}
+would be the same as the argument to @samp{--srcdir}, you can leave out
+the @samp{--srcdir} option; it is assumed.)
+
+For example, with version @value{GDBVN}, you can build GDB in a separate
+directory for a Sun 4 like this:
+
+@example
+@group
+cd gdb-@value{GDBVN}
+mkdir ../gdb-sun4
+cd ../gdb-sun4
+../gdb-@value{GDBVN}/configure sun4
+make
+@end group
+@end example
+
+When @code{configure} builds a configuration using a remote source
+directory, it creates a tree for the binaries with the same structure
+(and using the same names) as the tree under the source directory. In
+the example, you'd find the Sun 4 library @file{libiberty.a} in the
+directory @file{gdb-sun4/libiberty}, and GDB itself in
+@file{gdb-sun4/gdb}.
+
+One popular reason to build several GDB configurations in separate
+directories is to configure GDB for cross-compiling (where GDB
+runs on one machine---the host---while debugging programs that run on
+another machine---the target). You specify a cross-debugging target by
+giving the @samp{--target=@var{target}} option to @code{configure}.
+
+When you run @code{make} to build a program or library, you must run
+it in a configured directory---whatever directory you were in when you
+called @code{configure} (or one of its subdirectories).
+
+The @code{Makefile} that @code{configure} generates in each source
+directory also runs recursively. If you type @code{make} in a source
+directory such as @file{gdb-@value{GDBVN}} (or in a separate configured
+directory configured with @samp{--srcdir=@var{dirname}/gdb-@value{GDBVN}}), you
+will build all the required libraries, and then build GDB.
+
+When you have multiple hosts or targets configured in separate
+directories, you can run @code{make} on them in parallel (for example,
+if they are NFS-mounted on each of the hosts); they will not interfere
+with each other.
+
+@node Config Names
+@section Specifying names for hosts and targets
+
+The specifications used for hosts and targets in the @code{configure}
+script are based on a three-part naming scheme, but some short predefined
+aliases are also supported. The full naming scheme encodes three pieces
+of information in the following pattern:
+
+@example
+@var{architecture}-@var{vendor}-@var{os}
+@end example
+
+For example, you can use the alias @code{sun4} as a @var{host} argument,
+or as the value for @var{target} in a @code{--target=@var{target}}
+option. The equivalent full name is @samp{sparc-sun-sunos4}.
+
+The @code{configure} script accompanying GDB does not provide
+any query facility to list all supported host and target names or
+aliases. @code{configure} calls the Bourne shell script
+@code{config.sub} to map abbreviations to full names; you can read the
+script, if you wish, or you can use it to test your guesses on
+abbreviations---for example:
+
+@smallexample
+% sh config.sub sun4
+sparc-sun-sunos4.1.1
+% sh config.sub sun3
+m68k-sun-sunos4.1.1
+% sh config.sub decstation
+mips-dec-ultrix4.2
+% sh config.sub hp300bsd
+m68k-hp-bsd
+% sh config.sub i386v
+i386-unknown-sysv
+% sh config.sub i786v
+Invalid configuration `i786v': machine `i786v' not recognized
+@end smallexample
+
+@noindent
+@code{config.sub} is also distributed in the GDB source
+directory (@file{gdb-@value{GDBVN}}, for version @value{GDBVN}).
+
+@node configure Options
+@section @code{configure} options
+
+Here is a summary of the @code{configure} options and arguments that
+are most often useful for building @value{GDBN}. @code{configure} also has
+several other options not listed here. @inforef{What Configure
+Does,,configure.info}, for a full explanation of @code{configure}.
+@c FIXME: Would this be more, or less, useful as an xref (ref to printed
+@c manual in the printed manual, ref to info file only from the info file)?
+
+@example
+configure @r{[}--help@r{]}
+ @r{[}--prefix=@var{dir}@r{]}
+ @r{[}--srcdir=@var{dirname}@r{]}
+ @r{[}--norecursion@r{]} @r{[}--rm@r{]}
+ @r{[}--target=@var{target}@r{]} @var{host}
+@end example
+
+@noindent
+You may introduce options with a single @samp{-} rather than
+@samp{--} if you prefer; but you may abbreviate option names if you use
+@samp{--}.
+
+@table @code
+@item --help
+Display a quick summary of how to invoke @code{configure}.
+
+@item -prefix=@var{dir}
+Configure the source to install programs and files under directory
+@file{@var{dir}}.
+
+@c avoid splitting the warning from the explanation:
+@need 2000
+@item --srcdir=@var{dirname}
+@strong{Warning: using this option requires GNU @code{make}, or another
+@code{make} that implements the @code{VPATH} feature.}@*
+Use this option to make configurations in directories separate from the
+GDB source directories. Among other things, you can use this to
+build (or maintain) several configurations simultaneously, in separate
+directories. @code{configure} writes configuration specific files in
+the current directory, but arranges for them to use the source in the
+directory @var{dirname}. @code{configure} creates directories under
+the working directory in parallel to the source directories below
+@var{dirname}.
+
+@item --norecursion
+Configure only the directory level where @code{configure} is executed; do not
+propagate configuration to subdirectories.
+
+@item --rm
+@emph{Remove} files otherwise built during configuration.
+
+@c This does not work (yet if ever). FIXME.
+@c @item --parse=@var{lang} @dots{}
+@c Configure the GDB expression parser to parse the listed languages.
+@c @samp{all} configures GDB for all supported languages. To get a
+@c list of all supported languages, omit the argument. Without this
+@c option, GDB is configured to parse all supported languages.
+
+@item --target=@var{target}
+Configure GDB for cross-debugging programs running on the specified
+@var{target}. Without this option, GDB is configured to debug
+programs that run on the same machine (@var{host}) as GDB itself.
+
+There is no convenient way to generate a list of all available targets.
+
+@item @var{host} @dots{}
+Configure GDB to run on the specified @var{host}.
+
+There is no convenient way to generate a list of all available hosts.
+@end table
+
+@noindent
+@code{configure} accepts other options, for compatibility with
+configuring other GNU tools recursively; but these are the only
+options that affect GDB or its supporting libraries.
+@end ifclear
+
+@node Index
+@unnumbered Index
+
+@printindex cp
+
+@tex
+% I think something like @colophon should be in texinfo. In the
+% meantime:
+\long\def\colophon{\hbox to0pt{}\vfill
+\centerline{The body of this manual is set in}
+\centerline{\fontname\tenrm,}
+\centerline{with headings in {\bf\fontname\tenbf}}
+\centerline{and examples in {\tt\fontname\tentt}.}
+\centerline{{\it\fontname\tenit\/},}
+\centerline{{\bf\fontname\tenbf}, and}
+\centerline{{\sl\fontname\tensl\/}}
+\centerline{are used for emphasis.}\vfill}
+\page\colophon
+% Blame: pesch@cygnus.com, 1991.
+@end tex
+
+@contents
+@bye
diff --git a/gnu/usr.bin/gdb/doc/gdbint.texinfo b/gnu/usr.bin/gdb/doc/gdbint.texinfo
new file mode 100644
index 0000000..59e5a7f
--- /dev/null
+++ b/gnu/usr.bin/gdb/doc/gdbint.texinfo
@@ -0,0 +1,2669 @@
+\input texinfo
+@setfilename gdbint.info
+@c $Id: gdbint.texinfo,v 1.76 1994/07/17 21:17:18 shebs Exp $
+
+@ifinfo
+@format
+START-INFO-DIR-ENTRY
+* Gdb-Internals: (gdbint). The GNU debugger's internals.
+END-INFO-DIR-ENTRY
+@end format
+@end ifinfo
+
+@ifinfo
+This file documents the internals of the GNU debugger GDB.
+
+Copyright 1990, 1991, 1992, 1993, 1994 Free Software Foundation, Inc.
+Contributed by Cygnus Support. Written by John Gilmore.
+
+Permission is granted to make and distribute verbatim copies of
+this manual provided the copyright notice and this permission notice
+are preserved on all copies.
+
+@ignore
+Permission is granted to process this file through Tex and print the
+results, provided the printed document carries copying permission
+notice identical to this one except for the removal of this paragraph
+(this paragraph not being relevant to the printed manual).
+
+@end ignore
+Permission is granted to copy or distribute modified versions of this
+manual under the terms of the GPL (for which purpose this text may be
+regarded as a program in the language TeX).
+@end ifinfo
+
+@setchapternewpage off
+@settitle GDB Internals
+@titlepage
+@title{Working in GDB}
+@subtitle{A guide to the internals of the GNU debugger}
+@author John Gilmore
+@author Cygnus Support
+@page
+@tex
+\def\$#1${{#1}} % Kluge: collect RCS revision info without $...$
+\xdef\manvers{\$Revision: 1.76 $} % For use in headers, footers too
+{\parskip=0pt
+\hfill Cygnus Support\par
+\hfill \manvers\par
+\hfill \TeX{}info \texinfoversion\par
+}
+@end tex
+
+@vskip 0pt plus 1filll
+Copyright @copyright{} 1990, 1991, 1992, 1993, 1994 Free Software Foundation, Inc.
+
+Permission is granted to make and distribute verbatim copies of
+this manual provided the copyright notice and this permission notice
+are preserved on all copies.
+
+@end titlepage
+
+@node Top
+@c Perhaps this should be the title of the document (but only for info,
+@c not for TeX). Existing GNU manuals seem inconsistent on this point.
+@top Scope of this Document
+
+This document documents the internals of the GNU debugger, GDB. It is
+intended to document aspects of GDB which apply across many different
+parts of GDB (for example, @pxref{Coding Style}), or which are global
+aspects of design (for example, what are the major modules and which
+files document them in detail?). Information which pertains to specific
+data structures, functions, variables, etc., should be put in comments
+in the source code, not here. It is more likely to get noticed and kept
+up to date there. Some of the information in this document should
+probably be moved into comments.
+
+@menu
+* README:: The README File
+* Getting Started:: Getting started working on GDB
+* Debugging GDB:: Debugging GDB with itself
+* New Architectures:: Defining a New Host or Target Architecture
+* Config:: Adding a New Configuration
+* Host:: Adding a New Host
+* Native:: Adding a New Native Configuration
+* Target:: Adding a New Target
+* Languages:: Defining New Source Languages
+* Releases:: Configuring GDB for Release
+* Partial Symbol Tables:: How GDB reads symbols quickly at startup
+* Types:: How GDB keeps track of types
+* BFD support for GDB:: How BFD and GDB interface
+* Symbol Reading:: Defining New Symbol Readers
+* Cleanups:: Cleanups
+* Wrapping:: Wrapping Output Lines
+* Frames:: Keeping track of function calls
+* Remote Stubs:: Code that runs in targets and talks to GDB
+* Longjmp Support:: Stepping through longjmp's in the target
+* Coding Style:: Strunk and White for GDB maintainers
+* Clean Design:: Frank Lloyd Wright for GDB maintainers
+* Submitting Patches:: How to get your changes into GDB releases
+* Host Conditionals:: What features exist in the host
+* Target Conditionals:: What features exist in the target
+* Native Conditionals:: Conditionals for when host and target are same
+* Obsolete Conditionals:: Conditionals that don't exist any more
+* XCOFF:: The Object file format used on IBM's RS/6000
+@end menu
+
+@node README
+@chapter The @file{README} File
+
+Check the @file{README} file, it often has useful information that does not
+appear anywhere else in the directory.
+
+@node Getting Started
+@chapter Getting Started Working on GDB
+
+GDB is a large and complicated program, and if you first starting to
+work on it, it can be hard to know where to start. Fortunately, if you
+know how to go about it, there are ways to figure out what is going on:
+
+@itemize @bullet
+@item
+This manual, the GDB Internals manual, has information which applies
+generally to many parts of GDB.
+
+@item
+Information about particular functions or data structures are located in
+comments with those functions or data structures. If you run across a
+function or a global variable which does not have a comment correctly
+explaining what is does, this can be thought of as a bug in GDB; feel
+free to submit a bug report, with a suggested comment if you can figure
+out what the comment should say (@pxref{Submitting Patches}). If you
+find a comment which is actually wrong, be especially sure to report that.
+
+Comments explaining the function of macros defined in host, target, or
+native dependent files can be in several places. Sometimes they are
+repeated every place the macro is defined. Sometimes they are where the
+macro is used. Sometimes there is a header file which supplies a
+default definition of the macro, and the comment is there. This manual
+also has a list of macros (@pxref{Host Conditionals}, @pxref{Target
+Conditionals}, @pxref{Native Conditionals}, and @pxref{Obsolete
+Conditionals}) with some documentation.
+
+@item
+Start with the header files. Once you some idea of how GDB's internal
+symbol tables are stored (see @file{symtab.h}, @file{gdbtypes.h}), you
+will find it much easier to understand the code which uses and creates
+those symbol tables.
+
+@item
+You may wish to process the information you are getting somehow, to
+enhance your understanding of it. Summarize it, translate it to another
+language, add some (perhaps trivial or non-useful) feature to GDB, use
+the code to predict what a test case would do and write the test case
+and verify your prediction, etc. If you are reading code and your eyes
+are starting to glaze over, this is a sign you need to use a more active
+approach.
+
+@item
+Once you have a part of GDB to start with, you can find more
+specifically the part you are looking for by stepping through each
+function with the @code{next} command. Do not use @code{step} or you
+will quickly get distracted; when the function you are stepping through
+calls another function try only to get a big-picture understanding
+(perhaps using the comment at the beginning of the function being
+called) of what it does. This way you can identify which of the
+functions being called by the function you are stepping through is the
+one which you are interested in. You may need to examine the data
+structures generated at each stage, with reference to the comments in
+the header files explaining what the data structures are supposed to
+look like.
+
+Of course, this same technique can be used if you are just reading the
+code, rather than actually stepping through it. The same general
+principle applies---when the code you are looking at calls something
+else, just try to understand generally what the code being called does,
+rather than worrying about all its details.
+
+@item
+A good place to start when tracking down some particular area is with a
+command which invokes that feature. Suppose you want to know how
+single-stepping works. As a GDB user, you know that the @code{step}
+command invokes single-stepping. The command is invoked via command
+tables (see @file{command.h}); by convention the function which actually
+performs the command is formed by taking the name of the command and
+adding @samp{_command}, or in the case of an @code{info} subcommand,
+@samp{_info}. For example, the @code{step} command invokes the
+@code{step_command} function and the @code{info display} command invokes
+@code{display_info}. When this convention is not followed, you might
+have to use @code{grep} or @kbd{M-x tags-search} in emacs, or run GDB on
+itself and set a breakpoint in @code{execute_command}.
+
+@item
+If all of the above fail, it may be appropriate to ask for information
+on @code{bug-gdb}. But @emph{never} post a generic question like ``I was
+wondering if anyone could give me some tips about understanding
+GDB''---if we had some magic secret we would put it in this manual.
+Suggestions for improving the manual are always welcome, of course.
+@end itemize
+
+Good luck!
+
+@node Debugging GDB
+@chapter Debugging GDB with itself
+If GDB is limping on your machine, this is the preferred way to get it
+fully functional. Be warned that in some ancient Unix systems, like
+Ultrix 4.2, a program can't be running in one process while it is being
+debugged in another. Rather than typing the command @code{@w{./gdb
+./gdb}}, which works on Suns and such, you can copy @file{gdb} to
+@file{gdb2} and then type @code{@w{./gdb ./gdb2}}.
+
+When you run GDB in the GDB source directory, it will read a
+@file{.gdbinit} file that sets up some simple things to make debugging
+gdb easier. The @code{info} command, when executed without a subcommand
+in a GDB being debugged by gdb, will pop you back up to the top level
+gdb. See @file{.gdbinit} for details.
+
+If you use emacs, you will probably want to do a @code{make TAGS} after
+you configure your distribution; this will put the machine dependent
+routines for your local machine where they will be accessed first by
+@kbd{M-.}
+
+Also, make sure that you've either compiled GDB with your local cc, or
+have run @code{fixincludes} if you are compiling with gcc.
+
+@node New Architectures
+@chapter Defining a New Host or Target Architecture
+
+When building support for a new host and/or target, much of the work you
+need to do is handled by specifying configuration files;
+@pxref{Config,,Adding a New Configuration}. Further work can be
+divided into ``host-dependent'' (@pxref{Host,,Adding a New Host}) and
+``target-dependent'' (@pxref{Target,,Adding a New Target}). The
+following discussion is meant to explain the difference between hosts
+and targets.
+
+@heading What is considered ``host-dependent'' versus ``target-dependent''?
+
+@dfn{Host} refers to attributes of the system where GDB runs.
+@dfn{Target} refers to the system where the program being debugged
+executes. In most cases they are the same machine, in which case
+a third type of @dfn{Native} attributes come into play.
+
+Defines and include files needed to build on the host are host support.
+Examples are tty support, system defined types, host byte order, host
+float format.
+
+Defines and information needed to handle the target format are target
+dependent. Examples are the stack frame format, instruction set,
+breakpoint instruction, registers, and how to set up and tear down the stack
+to call a function.
+
+Information that is only needed when the host and target are the same,
+is native dependent. One example is Unix child process support; if the
+host and target are not the same, doing a fork to start the target
+process is a bad idea. The various macros needed for finding the
+registers in the @code{upage}, running @code{ptrace}, and such are all in the
+native-dependent files.
+
+Another example of native-dependent code is support for features
+that are really part of the target environment, but which require
+@code{#include} files that are only available on the host system.
+Core file handling and @code{setjmp} handling are two common cases.
+
+When you want to make GDB work ``native'' on a particular
+machine, you have to include all three kinds of information.
+
+The dependent information in GDB is organized into files by naming
+conventions.
+
+Host-Dependent Files
+@table @file
+@item config/*/*.mh
+Sets Makefile parameters
+@item config/*/xm-*.h
+Global #include's and #define's and definitions
+@item *-xdep.c
+Global variables and functions
+@end table
+
+Native-Dependent Files
+@table @file
+@item config/*/*.mh
+Sets Makefile parameters (for @emph{both} host and native)
+@item config/*/nm-*.h
+#include's and #define's and definitions. This file
+is only included by the small number of modules that need it,
+so beware of doing feature-test #define's from its macros.
+@item *-nat.c
+global variables and functions
+@end table
+
+Target-Dependent Files
+@table @file
+@item config/*/*.mt
+Sets Makefile parameters
+@item config/*/tm-*.h
+Global #include's and #define's and definitions
+@item *-tdep.c
+Global variables and functions
+@end table
+
+At this writing, most supported hosts have had their host and native
+dependencies sorted out properly. There are a few stragglers, which
+can be recognized by the absence of NATDEPFILES lines in their
+@file{config/*/*.mh}.
+
+@node Config
+@chapter Adding a New Configuration
+
+Most of the work in making GDB compile on a new machine is in specifying
+the configuration of the machine. This is done in a dizzying variety of
+header files and configuration scripts, which we hope to make more
+sensible soon. Let's say your new host is called an @var{xxx} (e.g.
+@samp{sun4}), and its full three-part configuration name is
+@code{@var{xarch}-@var{xvend}-@var{xos}} (e.g. @samp{sparc-sun-sunos4}). In
+particular:
+
+In the top level directory, edit @file{config.sub} and add @var{xarch},
+@var{xvend}, and @var{xos} to the lists of supported architectures,
+vendors, and operating systems near the bottom of the file. Also, add
+@var{xxx} as an alias that maps to
+@code{@var{xarch}-@var{xvend}-@var{xos}}. You can test your changes by
+running
+
+@example
+./config.sub @var{xxx}
+@end example
+@noindent
+and
+@example
+./config.sub @code{@var{xarch}-@var{xvend}-@var{xos}}
+@end example
+@noindent
+which should both respond with @code{@var{xarch}-@var{xvend}-@var{xos}}
+and no error messages.
+
+Now, go to the @file{bfd} directory and
+create a new file @file{bfd/hosts/h-@var{xxx}.h}. Examine the
+other @file{h-*.h} files as templates, and create one that brings in the
+right include files for your system, and defines any host-specific
+macros needed by BFD, the Binutils, GNU LD, or the Opcodes directories.
+(They all share the bfd @file{hosts} directory and the @file{configure.host}
+file.)
+
+Then edit @file{bfd/configure.host}. Add a line to recognize your
+@code{@var{xarch}-@var{xvend}-@var{xos}} configuration, and set
+@code{my_host} to @var{xxx} when you recognize it. This will cause your
+file @file{h-@var{xxx}.h} to be linked to @file{sysdep.h} at configuration
+time. When creating the line that recognizes your configuration,
+only match the fields that you really need to match; e.g. don't
+match the architecture or manufacturer if the OS is sufficient
+to distinguish the configuration that your @file{h-@var{xxx}.h} file supports.
+Don't match the manufacturer name unless you really need to.
+This should make future ports easier.
+
+Also, if this host requires any changes to the Makefile, create a file
+@file{bfd/config/@var{xxx}.mh}, which includes the required lines.
+
+It's possible that the @file{libiberty} and @file{readline} directories
+won't need any changes for your configuration, but if they do, you can
+change the @file{configure.in} file there to recognize your system and
+map to an @file{mh-@var{xxx}} file. Then add @file{mh-@var{xxx}}
+to the @file{config/} subdirectory, to set any makefile variables you
+need. The only current options in there are things like @samp{-DSYSV}.
+(This @file{mh-@var{xxx}} naming convention differs from elsewhere
+in GDB, by historical accident. It should be cleaned up so that all
+such files are called @file{@var{xxx}.mh}.)
+
+Aha! Now to configure GDB itself! Edit
+@file{gdb/configure.in} to recognize your system and set @code{gdb_host}
+to @var{xxx}, and (unless your desired target is already available) also
+set @code{gdb_target} to something appropriate (for instance,
+@var{xxx}). To handle new hosts, modify the segment after the comment
+@samp{# per-host}; to handle new targets, modify after @samp{#
+per-target}.
+@c Would it be simpler to just use different per-host and per-target
+@c *scripts*, and call them from {configure} ?
+
+Finally, you'll need to specify and define GDB's host-, native-, and
+target-dependent @file{.h} and @file{.c} files used for your
+configuration; the next two chapters discuss those.
+
+
+@node Host
+@chapter Adding a New Host
+
+Once you have specified a new configuration for your host
+(@pxref{Config,,Adding a New Configuration}), there are three remaining
+pieces to making GDB work on a new machine. First, you have to make it
+host on the new machine (compile there, handle that machine's terminals
+properly, etc). If you will be cross-debugging to some other kind of
+system that's already supported, you are done.
+
+If you want to use GDB to debug programs that run on the new machine,
+you have to get it to understand the machine's object files, symbol
+files, and interfaces to processes; @pxref{Target,,Adding a New Target}
+and @pxref{Native,,Adding a New Native Configuration}
+
+Several files control GDB's configuration for host systems:
+
+@table @file
+@item gdb/config/@var{arch}/@var{xxx}.mh
+Specifies Makefile fragments needed when hosting on machine @var{xxx}.
+In particular, this lists the required machine-dependent object files,
+by defining @samp{XDEPFILES=@dots{}}. Also
+specifies the header file which describes host @var{xxx}, by defining
+@code{XM_FILE= xm-@var{xxx}.h}. You can also define @code{CC},
+@code{REGEX} and @code{REGEX1}, @code{SYSV_DEFINE}, @code{XM_CFLAGS},
+@code{XM_ADD_FILES}, @code{XM_CLIBS}, @code{XM_CDEPS},
+etc.; see @file{Makefile.in}.
+
+@item gdb/config/@var{arch}/xm-@var{xxx}.h
+(@file{xm.h} is a link to this file, created by configure).
+Contains C macro definitions describing the host system environment,
+such as byte order, host C compiler and library, ptrace support,
+and core file structure. Crib from existing @file{xm-*.h} files
+to create a new one.
+
+@item gdb/@var{xxx}-xdep.c
+Contains any miscellaneous C code required for this machine
+as a host. On many machines it doesn't exist at all. If it does
+exist, put @file{@var{xxx}-xdep.o} into the @code{XDEPFILES} line
+in @file{gdb/config/mh-@var{xxx}}.
+@end table
+
+@subheading Generic Host Support Files
+
+There are some ``generic'' versions of routines that can be used by
+various systems. These can be customized in various ways by macros
+defined in your @file{xm-@var{xxx}.h} file. If these routines work for
+the @var{xxx} host, you can just include the generic file's name (with
+@samp{.o}, not @samp{.c}) in @code{XDEPFILES}.
+
+Otherwise, if your machine needs custom support routines, you will need
+to write routines that perform the same functions as the generic file.
+Put them into @code{@var{xxx}-xdep.c}, and put @code{@var{xxx}-xdep.o}
+into @code{XDEPFILES}.
+
+@table @file
+@item ser-bsd.c
+This contains serial line support for Berkeley-derived Unix systems.
+
+@item ser-go32.c
+This contains serial line support for 32-bit programs running under DOS
+using the GO32 execution environment.
+
+@item ser-termios.c
+This contains serial line support for System V-derived Unix systems.
+@end table
+
+Now, you are now ready to try configuring GDB to compile using your system
+as its host. From the top level (above @file{bfd}, @file{gdb}, etc), do:
+
+@example
+./configure @var{xxx} --target=vxworks960
+@end example
+
+This will configure your system to cross-compile for VxWorks on
+the Intel 960, which is probably not what you really want, but it's
+a test case that works at this stage. (You haven't set up to be
+able to debug programs that run @emph{on} @var{xxx} yet.)
+
+If this succeeds, you can try building it all with:
+
+@example
+make
+@end example
+
+Repeat until the program configures, compiles, links, and runs.
+When run, it won't be able to do much (unless you have a VxWorks/960
+board on your network) but you will know that the host support is
+pretty well done.
+
+Good luck! Comments and suggestions about this section are particularly
+welcome; send them to @samp{bug-gdb@@prep.ai.mit.edu}.
+
+@node Native
+@chapter Adding a New Native Configuration
+
+If you are making GDB run native on the @var{xxx} machine, you have
+plenty more work to do. Several files control GDB's configuration for
+native support:
+
+@table @file
+@item gdb/config/@var{xarch}/@var{xxx}.mh
+Specifies Makefile fragments needed when hosting @emph{or native}
+on machine @var{xxx}.
+In particular, this lists the required native-dependent object files,
+by defining @samp{NATDEPFILES=@dots{}}. Also
+specifies the header file which describes native support on @var{xxx},
+by defining @samp{NAT_FILE= nm-@var{xxx}.h}.
+You can also define @samp{NAT_CFLAGS},
+@samp{NAT_ADD_FILES}, @samp{NAT_CLIBS}, @samp{NAT_CDEPS},
+etc.; see @file{Makefile.in}.
+
+@item gdb/config/@var{arch}/nm-@var{xxx}.h
+(@file{nm.h} is a link to this file, created by configure).
+Contains C macro definitions describing the native system environment,
+such as child process control and core file support.
+Crib from existing @file{nm-*.h} files to create a new one.
+
+@item gdb/@var{xxx}-nat.c
+Contains any miscellaneous C code required for this native support
+of this machine. On some machines it doesn't exist at all.
+@end table
+
+@subheading Generic Native Support Files
+
+There are some ``generic'' versions of routines that can be used by
+various systems. These can be customized in various ways by macros
+defined in your @file{nm-@var{xxx}.h} file. If these routines work for
+the @var{xxx} host, you can just include the generic file's name (with
+@samp{.o}, not @samp{.c}) in @code{NATDEPFILES}.
+
+Otherwise, if your machine needs custom support routines, you will need
+to write routines that perform the same functions as the generic file.
+Put them into @code{@var{xxx}-nat.c}, and put @code{@var{xxx}-nat.o}
+into @code{NATDEPFILES}.
+
+@table @file
+
+@item inftarg.c
+This contains the @emph{target_ops vector} that supports Unix child
+processes on systems which use ptrace and wait to control the child.
+
+@item procfs.c
+This contains the @emph{target_ops vector} that supports Unix child
+processes on systems which use /proc to control the child.
+
+@item fork-child.c
+This does the low-level grunge that uses Unix system calls
+to do a "fork and exec" to start up a child process.
+
+@item infptrace.c
+This is the low level interface to inferior processes for systems
+using the Unix @code{ptrace} call in a vanilla way.
+
+@item coredep.c::fetch_core_registers()
+Support for reading registers out of a core file. This routine calls
+@code{register_addr()}, see below.
+Now that BFD is used to read core files, virtually all machines should
+use @code{coredep.c}, and should just provide @code{fetch_core_registers} in
+@code{@var{xxx}-nat.c} (or @code{REGISTER_U_ADDR} in @code{nm-@var{xxx}.h}).
+
+@item coredep.c::register_addr()
+If your @code{nm-@var{xxx}.h} file defines the macro
+@code{REGISTER_U_ADDR(addr, blockend, regno)}, it should be defined to
+set @code{addr} to the offset within the @samp{user}
+struct of GDB register number @code{regno}. @code{blockend} is the
+offset within the ``upage'' of @code{u.u_ar0}.
+If @code{REGISTER_U_ADDR} is defined,
+@file{coredep.c} will define the @code{register_addr()} function and use
+the macro in it. If you do not define @code{REGISTER_U_ADDR}, but you
+are using the standard @code{fetch_core_registers()}, you will need to
+define your own version of @code{register_addr()}, put it into your
+@code{@var{xxx}-nat.c} file, and be sure @code{@var{xxx}-nat.o} is in
+the @code{NATDEPFILES} list. If you have your own
+@code{fetch_core_registers()}, you may not need a separate
+@code{register_addr()}. Many custom @code{fetch_core_registers()}
+implementations simply locate the registers themselves.@refill
+@end table
+
+When making GDB run native on a new operating system,
+to make it possible to debug
+core files, you will need to either write specific code for parsing your
+OS's core files, or customize @file{bfd/trad-core.c}. First, use
+whatever @code{#include} files your machine uses to define the struct of
+registers that is accessible (possibly in the u-area) in a core file
+(rather than @file{machine/reg.h}), and an include file that defines whatever
+header exists on a core file (e.g. the u-area or a @samp{struct core}). Then
+modify @code{trad_unix_core_file_p()} to use these values to set up the
+section information for the data segment, stack segment, any other
+segments in the core file (perhaps shared library contents or control
+information), ``registers'' segment, and if there are two discontiguous
+sets of registers (e.g. integer and float), the ``reg2'' segment. This
+section information basically delimits areas in the core file in a
+standard way, which the section-reading routines in BFD know how to seek
+around in.
+
+Then back in GDB, you need a matching routine called
+@code{fetch_core_registers()}. If you can use the generic one, it's in
+@file{coredep.c}; if not, it's in your @file{@var{xxx}-nat.c} file.
+It will be passed a char pointer to the entire ``registers'' segment,
+its length, and a zero; or a char pointer to the entire ``regs2''
+segment, its length, and a 2. The routine should suck out the supplied
+register values and install them into GDB's ``registers'' array.
+(@xref{New Architectures,,Defining a New Host or Target Architecture},
+for more info about this.)
+
+If your system uses @file{/proc} to control processes, and uses ELF
+format core files, then you may be able to use the same routines
+for reading the registers out of processes and out of core files.
+
+@node Target
+@chapter Adding a New Target
+
+For a new target called @var{ttt}, first specify the configuration as
+described in @ref{Config,,Adding a New Configuration}. If your new
+target is the same as your new host, you've probably already done that.
+
+A variety of files specify attributes of the GDB target environment:
+
+@table @file
+@item gdb/config/@var{arch}/@var{ttt}.mt
+Contains a Makefile fragment specific to this target.
+Specifies what object files are needed for target @var{ttt}, by
+defining @samp{TDEPFILES=@dots{}}.
+Also specifies the header file which describes @var{ttt}, by defining
+@samp{TM_FILE= tm-@var{ttt}.h}. You can also define @samp{TM_CFLAGS},
+@samp{TM_CLIBS}, @samp{TM_CDEPS},
+and other Makefile variables here; see @file{Makefile.in}.
+
+@item gdb/config/@var{arch}/tm-@var{ttt}.h
+(@file{tm.h} is a link to this file, created by configure).
+Contains macro definitions about the target machine's
+registers, stack frame format and instructions.
+Crib from existing @file{tm-*.h} files when building a new one.
+
+@item gdb/@var{ttt}-tdep.c
+Contains any miscellaneous code required for this target machine.
+On some machines it doesn't exist at all. Sometimes the macros
+in @file{tm-@var{ttt}.h} become very complicated, so they are
+implemented as functions here instead, and the macro is simply
+defined to call the function.
+
+@item gdb/exec.c
+Defines functions for accessing files that are
+executable on the target system. These functions open and examine an
+exec file, extract data from one, write data to one, print information
+about one, etc. Now that executable files are handled with BFD, every
+target should be able to use the generic exec.c rather than its
+own custom code.
+
+@item gdb/@var{arch}-pinsn.c
+Prints (disassembles) the target machine's instructions.
+This file is usually shared with other target machines which use the
+same processor, which is why it is @file{@var{arch}-pinsn.c} rather
+than @file{@var{ttt}-pinsn.c}.
+
+@item gdb/@var{arch}-opcode.h
+Contains some large initialized
+data structures describing the target machine's instructions.
+This is a bit strange for a @file{.h} file, but it's OK since
+it is only included in one place. @file{@var{arch}-opcode.h} is shared
+between the debugger and the assembler, if the GNU assembler has been
+ported to the target machine.
+
+@item gdb/config/@var{arch}/tm-@var{arch}.h
+This often exists to describe the basic layout of the target machine's
+processor chip (registers, stack, etc).
+If used, it is included by @file{tm-@var{xxx}.h}. It can
+be shared among many targets that use the same processor.
+
+@item gdb/@var{arch}-tdep.c
+Similarly, there are often common subroutines that are shared by all
+target machines that use this particular architecture.
+@end table
+
+When adding support for a new target machine, there are various areas
+of support that might need change, or might be OK.
+
+If you are using an existing object file format (a.out or COFF),
+there is probably little to be done. See @file{bfd/doc/bfd.texinfo}
+for more information on writing new a.out or COFF versions.
+
+If you need to add a new object file format, you must first add it to
+BFD. This is beyond the scope of this document right now. Basically
+you must build a transfer vector (of type @code{bfd_target}), which will
+mean writing all the required routines, and add it to the list in
+@file{bfd/targets.c}.
+
+You must then arrange for the BFD code to provide access to the
+debugging symbols. Generally GDB will have to call swapping routines
+from BFD and a few other BFD internal routines to locate the debugging
+information. As much as possible, GDB should not depend on the BFD
+internal data structures.
+
+For some targets (e.g., COFF), there is a special transfer vector used
+to call swapping routines, since the external data structures on various
+platforms have different sizes and layouts. Specialized routines that
+will only ever be implemented by one object file format may be called
+directly. This interface should be described in a file
+@file{bfd/libxxx.h}, which is included by GDB.
+
+If you are adding a new operating system for an existing CPU chip, add a
+@file{tm-@var{xos}.h} file that describes the operating system
+facilities that are unusual (extra symbol table info; the breakpoint
+instruction needed; etc). Then write a
+@file{tm-@var{xarch}-@var{xos}.h} that just @code{#include}s
+@file{tm-@var{xarch}.h} and @file{tm-@var{xos}.h}. (Now that we have
+three-part configuration names, this will probably get revised to
+separate the @var{xos} configuration from the @var{xarch}
+configuration.)
+
+
+@node Languages
+@chapter Adding a Source Language to GDB
+
+To add other languages to GDB's expression parser, follow the following steps:
+
+@table @emph
+@item Create the expression parser.
+
+This should reside in a file @file{@var{lang}-exp.y}. Routines for building
+parsed expressions into a @samp{union exp_element} list are in @file{parse.c}.
+
+Since we can't depend upon everyone having Bison, and YACC produces
+parsers that define a bunch of global names, the following lines
+@emph{must} be included at the top of the YACC parser, to prevent
+the various parsers from defining the same global names:
+
+@example
+#define yyparse @var{lang}_parse
+#define yylex @var{lang}_lex
+#define yyerror @var{lang}_error
+#define yylval @var{lang}_lval
+#define yychar @var{lang}_char
+#define yydebug @var{lang}_debug
+#define yypact @var{lang}_pact
+#define yyr1 @var{lang}_r1
+#define yyr2 @var{lang}_r2
+#define yydef @var{lang}_def
+#define yychk @var{lang}_chk
+#define yypgo @var{lang}_pgo
+#define yyact @var{lang}_act
+#define yyexca @var{lang}_exca
+#define yyerrflag @var{lang}_errflag
+#define yynerrs @var{lang}_nerrs
+@end example
+
+At the bottom of your parser, define a @code{struct language_defn} and
+initialize it with the right values for your language. Define an
+@code{initialize_@var{lang}} routine and have it call
+@samp{add_language(@var{lang}_language_defn)} to tell the rest of GDB
+that your language exists. You'll need some other supporting variables
+and functions, which will be used via pointers from your
+@code{@var{lang}_language_defn}. See the declaration of @code{struct
+language_defn} in @file{language.h}, and the other @file{*-exp.y} files,
+for more information.
+
+@item Add any evaluation routines, if necessary
+
+If you need new opcodes (that represent the operations of the language),
+add them to the enumerated type in @file{expression.h}. Add support
+code for these operations in @code{eval.c:evaluate_subexp()}. Add cases
+for new opcodes in two functions from @file{parse.c}:
+@code{prefixify_subexp()} and @code{length_of_subexp()}. These compute
+the number of @code{exp_element}s that a given operation takes up.
+
+@item Update some existing code
+
+Add an enumerated identifier for your language to the enumerated type
+@code{enum language} in @file{defs.h}.
+
+Update the routines in @file{language.c} so your language is included. These
+routines include type predicates and such, which (in some cases) are
+language dependent. If your language does not appear in the switch
+statement, an error is reported.
+
+Also included in @file{language.c} is the code that updates the variable
+@code{current_language}, and the routines that translate the
+@code{language_@var{lang}} enumerated identifier into a printable
+string.
+
+Update the function @code{_initialize_language} to include your language. This
+function picks the default language upon startup, so is dependent upon
+which languages that GDB is built for.
+
+Update @code{allocate_symtab} in @file{symfile.c} and/or symbol-reading
+code so that the language of each symtab (source file) is set properly.
+This is used to determine the language to use at each stack frame level.
+Currently, the language is set based upon the extension of the source
+file. If the language can be better inferred from the symbol
+information, please set the language of the symtab in the symbol-reading
+code.
+
+Add helper code to @code{expprint.c:print_subexp()} to handle any new
+expression opcodes you have added to @file{expression.h}. Also, add the
+printed representations of your operators to @code{op_print_tab}.
+
+@item Add a place of call
+
+Add a call to @code{@var{lang}_parse()} and @code{@var{lang}_error} in
+@code{parse.c:parse_exp_1()}.
+
+@item Use macros to trim code
+
+The user has the option of building GDB for some or all of the
+languages. If the user decides to build GDB for the language
+@var{lang}, then every file dependent on @file{language.h} will have the
+macro @code{_LANG_@var{lang}} defined in it. Use @code{#ifdef}s to
+leave out large routines that the user won't need if he or she is not
+using your language.
+
+Note that you do not need to do this in your YACC parser, since if GDB
+is not build for @var{lang}, then @file{@var{lang}-exp.tab.o} (the
+compiled form of your parser) is not linked into GDB at all.
+
+See the file @file{configure.in} for how GDB is configured for different
+languages.
+
+@item Edit @file{Makefile.in}
+
+Add dependencies in @file{Makefile.in}. Make sure you update the macro
+variables such as @code{HFILES} and @code{OBJS}, otherwise your code may
+not get linked in, or, worse yet, it may not get @code{tar}red into the
+distribution!
+@end table
+
+
+@node Releases
+@chapter Configuring GDB for Release
+
+From the top level directory (containing @file{gdb}, @file{bfd},
+@file{libiberty}, and so on):
+@example
+make -f Makefile.in gdb.tar.Z
+@end example
+
+This will properly configure, clean, rebuild any files that are
+distributed pre-built (e.g. @file{c-exp.tab.c} or @file{refcard.ps}),
+and will then make a tarfile. (If the top level directory has already
+beenn configured, you can just do @code{make gdb.tar.Z} instead.)
+
+This procedure requires:
+@itemize @bullet
+@item symbolic links
+@item @code{makeinfo} (texinfo2 level)
+@item @TeX{}
+@item @code{dvips}
+@item @code{yacc} or @code{bison}
+@end itemize
+@noindent
+@dots{} and the usual slew of utilities (@code{sed}, @code{tar}, etc.).
+
+@subheading TEMPORARY RELEASE PROCEDURE FOR DOCUMENTATION
+
+@file{gdb.texinfo} is currently marked up using the texinfo-2 macros,
+which are not yet a default for anything (but we have to start using
+them sometime).
+
+For making paper, the only thing this implies is the right generation of
+@file{texinfo.tex} needs to be included in the distribution.
+
+For making info files, however, rather than duplicating the texinfo2
+distribution, generate @file{gdb-all.texinfo} locally, and include the files
+@file{gdb.info*} in the distribution. Note the plural; @code{makeinfo} will
+split the document into one overall file and five or so included files.
+
+
+@node Partial Symbol Tables
+@chapter Partial Symbol Tables
+
+GDB has three types of symbol tables.
+
+@itemize @bullet
+@item full symbol tables (symtabs). These contain the main
+information about symbols and addresses.
+@item partial symbol tables (psymtabs). These contain enough
+information to know when to read the corresponding
+part of the full symbol table.
+@item minimal symbol tables (msymtabs). These contain information
+gleaned from non-debugging symbols.
+@end itemize
+
+This section describes partial symbol tables.
+
+A psymtab is constructed by doing a very quick pass over an executable
+file's debugging information. Small amounts of information are
+extracted -- enough to identify which parts of the symbol table will
+need to be re-read and fully digested later, when the user needs the
+information. The speed of this pass causes GDB to start up very
+quickly. Later, as the detailed rereading occurs, it occurs in small
+pieces, at various times, and the delay therefrom is mostly invisible to
+the user. (@xref{Symbol Reading}.)
+
+The symbols that show up in a file's psymtab should be, roughly, those
+visible to the debugger's user when the program is not running code from
+that file. These include external symbols and types, static
+symbols and types, and enum values declared at file scope.
+
+The psymtab also contains the range of instruction addresses that the
+full symbol table would represent.
+
+The idea is that there are only two ways for the user (or much of
+the code in the debugger) to reference a symbol:
+
+@itemize @bullet
+
+@item by its address
+(e.g. execution stops at some address which is inside a function
+in this file). The address will be noticed to be in the
+range of this psymtab, and the full symtab will be read in.
+@code{find_pc_function}, @code{find_pc_line}, and other @code{find_pc_@dots{}}
+functions handle this.
+
+@item by its name
+(e.g. the user asks to print a variable, or set a breakpoint on a
+function). Global names and file-scope names will be found in the
+psymtab, which will cause the symtab to be pulled in. Local names will
+have to be qualified by a global name, or a file-scope name, in which
+case we will have already read in the symtab as we evaluated the
+qualifier. Or, a local symbol can be referenced when
+we are "in" a local scope, in which case the first case applies.
+@code{lookup_symbol} does most of the work here.
+
+@end itemize
+
+The only reason that psymtabs exist is to cause a symtab to be read in
+at the right moment. Any symbol that can be elided from a psymtab,
+while still causing that to happen, should not appear in it. Since
+psymtabs don't have the idea of scope, you can't put local symbols in
+them anyway. Psymtabs don't have the idea of the type of a symbol,
+either, so types need not appear, unless they will be referenced by
+name.
+
+It is a bug for GDB to behave one way when only a psymtab has been read,
+and another way if the corresponding symtab has been read in. Such
+bugs are typically caused by a psymtab that does not contain all the
+visible symbols, or which has the wrong instruction address ranges.
+
+The psymtab for a particular section of a symbol-file (objfile)
+could be thrown away after the symtab has been read in. The symtab
+should always be searched before the psymtab, so the psymtab will
+never be used (in a bug-free environment). Currently,
+psymtabs are allocated on an obstack, and all the psymbols themselves
+are allocated in a pair of large arrays on an obstack, so there is
+little to be gained by trying to free them unless you want to do a lot
+more work.
+
+@node Types
+@chapter Types
+
+Fundamental Types (e.g., FT_VOID, FT_BOOLEAN).
+
+These are the fundamental types that GDB uses internally. Fundamental
+types from the various debugging formats (stabs, ELF, etc) are mapped into
+one of these. They are basically a union of all fundamental types that
+gdb knows about for all the languages that GDB knows about.
+
+Type Codes (e.g., TYPE_CODE_PTR, TYPE_CODE_ARRAY).
+
+Each time GDB builds an internal type, it marks it with one of these
+types. The type may be a fundamental type, such as TYPE_CODE_INT, or
+a derived type, such as TYPE_CODE_PTR which is a pointer to another
+type. Typically, several FT_* types map to one TYPE_CODE_* type, and
+are distinguished by other members of the type struct, such as whether
+the type is signed or unsigned, and how many bits it uses.
+
+Builtin Types (e.g., builtin_type_void, builtin_type_char).
+
+These are instances of type structs that roughly correspond to fundamental
+types and are created as global types for GDB to use for various ugly
+historical reasons. We eventually want to eliminate these. Note for
+example that builtin_type_int initialized in gdbtypes.c is basically the
+same as a TYPE_CODE_INT type that is initialized in c-lang.c for an
+FT_INTEGER fundamental type. The difference is that the builtin_type is
+not associated with any particular objfile, and only one instance exists,
+while c-lang.c builds as many TYPE_CODE_INT types as needed, with each
+one associated with some particular objfile.
+
+@node BFD support for GDB
+@chapter Binary File Descriptor Library Support for GDB
+
+BFD provides support for GDB in several ways:
+
+@table @emph
+@item identifying executable and core files
+BFD will identify a variety of file types, including a.out, coff, and
+several variants thereof, as well as several kinds of core files.
+
+@item access to sections of files
+BFD parses the file headers to determine the names, virtual addresses,
+sizes, and file locations of all the various named sections in files
+(such as the text section or the data section). GDB simply calls
+BFD to read or write section X at byte offset Y for length Z.
+
+@item specialized core file support
+BFD provides routines to determine the failing command name stored
+in a core file, the signal with which the program failed, and whether
+a core file matches (i.e. could be a core dump of) a particular executable
+file.
+
+@item locating the symbol information
+GDB uses an internal interface of BFD to determine where to find the
+symbol information in an executable file or symbol-file. GDB itself
+handles the reading of symbols, since BFD does not ``understand'' debug
+symbols, but GDB uses BFD's cached information to find the symbols,
+string table, etc.
+@end table
+
+@c The interface for symbol reading is described in @ref{Symbol
+@c Reading,,Symbol Reading}.
+
+
+@node Symbol Reading
+@chapter Symbol Reading
+
+GDB reads symbols from "symbol files". The usual symbol file is the
+file containing the program which GDB is debugging. GDB can be directed
+to use a different file for symbols (with the ``symbol-file''
+command), and it can also read more symbols via the ``add-file'' and ``load''
+commands, or while reading symbols from shared libraries.
+
+Symbol files are initially opened by @file{symfile.c} using the BFD
+library. BFD identifies the type of the file by examining its header.
+@code{symfile_init} then uses this identification to locate a
+set of symbol-reading functions.
+
+Symbol reading modules identify themselves to GDB by calling
+@code{add_symtab_fns} during their module initialization. The argument
+to @code{add_symtab_fns} is a @code{struct sym_fns} which contains
+the name (or name prefix) of the symbol format, the length of the prefix,
+and pointers to four functions. These functions are called at various
+times to process symbol-files whose identification matches the specified
+prefix.
+
+The functions supplied by each module are:
+
+@table @code
+@item @var{xxx}_symfile_init(struct sym_fns *sf)
+
+Called from @code{symbol_file_add} when we are about to read a new
+symbol file. This function should clean up any internal state
+(possibly resulting from half-read previous files, for example)
+and prepare to read a new symbol file. Note that the symbol file
+which we are reading might be a new "main" symbol file, or might
+be a secondary symbol file whose symbols are being added to the
+existing symbol table.
+
+The argument to @code{@var{xxx}_symfile_init} is a newly allocated
+@code{struct sym_fns} whose @code{bfd} field contains the BFD
+for the new symbol file being read. Its @code{private} field
+has been zeroed, and can be modified as desired. Typically,
+a struct of private information will be @code{malloc}'d, and
+a pointer to it will be placed in the @code{private} field.
+
+There is no result from @code{@var{xxx}_symfile_init}, but it can call
+@code{error} if it detects an unavoidable problem.
+
+@item @var{xxx}_new_init()
+
+Called from @code{symbol_file_add} when discarding existing symbols.
+This function need only handle
+the symbol-reading module's internal state; the symbol table data
+structures visible to the rest of GDB will be discarded by
+@code{symbol_file_add}. It has no arguments and no result.
+It may be called after @code{@var{xxx}_symfile_init}, if a new symbol
+table is being read, or may be called alone if all symbols are
+simply being discarded.
+
+@item @var{xxx}_symfile_read(struct sym_fns *sf, CORE_ADDR addr, int mainline)
+
+Called from @code{symbol_file_add} to actually read the symbols from a
+symbol-file into a set of psymtabs or symtabs.
+
+@code{sf} points to the struct sym_fns originally passed to
+@code{@var{xxx}_sym_init} for possible initialization. @code{addr} is the
+offset between the file's specified start address and its true address
+in memory. @code{mainline} is 1 if this is the main symbol table being
+read, and 0 if a secondary symbol file (e.g. shared library or
+dynamically loaded file) is being read.@refill
+@end table
+
+In addition, if a symbol-reading module creates psymtabs when
+@var{xxx}_symfile_read is called, these psymtabs will contain a pointer to
+a function @code{@var{xxx}_psymtab_to_symtab}, which can be called from
+any point in the GDB symbol-handling code.
+
+@table @code
+@item @var{xxx}_psymtab_to_symtab (struct partial_symtab *pst)
+
+Called from @code{psymtab_to_symtab} (or the PSYMTAB_TO_SYMTAB
+macro) if the psymtab has not already been read in and had its
+@code{pst->symtab} pointer set. The argument is the psymtab
+to be fleshed-out into a symtab. Upon return, pst->readin
+should have been set to 1, and pst->symtab should contain a
+pointer to the new corresponding symtab, or zero if there
+were no symbols in that part of the symbol file.
+@end table
+
+
+@node Cleanups
+@chapter Cleanups
+
+Cleanups are a structured way to deal with things that need to be done
+later. When your code does something (like @code{malloc} some memory, or open
+a file) that needs to be undone later (e.g. free the memory or close
+the file), it can make a cleanup. The cleanup will be done at some
+future point: when the command is finished, when an error occurs, or
+when your code decides it's time to do cleanups.
+
+You can also discard cleanups, that is, throw them away without doing
+what they say. This is only done if you ask that it be done.
+
+Syntax:
+
+@table @code
+@item struct cleanup *@var{old_chain};
+Declare a variable which will hold a cleanup chain handle.
+
+@item @var{old_chain} = make_cleanup (@var{function}, @var{arg});
+Make a cleanup which will cause @var{function} to be called with @var{arg}
+(a @code{char *}) later. The result, @var{old_chain}, is a handle that can be
+passed to @code{do_cleanups} or @code{discard_cleanups} later. Unless you are
+going to call @code{do_cleanups} or @code{discard_cleanups} yourself,
+you can ignore the result from @code{make_cleanup}.
+
+
+@item do_cleanups (@var{old_chain});
+Perform all cleanups done since @code{make_cleanup} returned @var{old_chain}.
+E.g.:
+@example
+make_cleanup (a, 0);
+old = make_cleanup (b, 0);
+do_cleanups (old);
+@end example
+@noindent
+will call @code{b()} but will not call @code{a()}. The cleanup that calls @code{a()} will remain
+in the cleanup chain, and will be done later unless otherwise discarded.@refill
+
+@item discard_cleanups (@var{old_chain});
+Same as @code{do_cleanups} except that it just removes the cleanups from the
+chain and does not call the specified functions.
+
+@end table
+
+Some functions, e.g. @code{fputs_filtered()} or @code{error()}, specify that they
+``should not be called when cleanups are not in place''. This means
+that any actions you need to reverse in the case of an error or
+interruption must be on the cleanup chain before you call these functions,
+since they might never return to your code (they @samp{longjmp} instead).
+
+
+@node Wrapping
+@chapter Wrapping Output Lines
+
+Output that goes through @code{printf_filtered} or @code{fputs_filtered} or
+@code{fputs_demangled} needs only to have calls to @code{wrap_here} added
+in places that would be good breaking points. The utility routines
+will take care of actually wrapping if the line width is exceeded.
+
+The argument to @code{wrap_here} is an indentation string which is printed
+@emph{only} if the line breaks there. This argument is saved away and used
+later. It must remain valid until the next call to @code{wrap_here} or
+until a newline has been printed through the @code{*_filtered} functions.
+Don't pass in a local variable and then return!
+
+It is usually best to call @code{wrap_here()} after printing a comma or space.
+If you call it before printing a space, make sure that your indentation
+properly accounts for the leading space that will print if the line wraps
+there.
+
+Any function or set of functions that produce filtered output must finish
+by printing a newline, to flush the wrap buffer, before switching to
+unfiltered (``@code{printf}'') output. Symbol reading routines that print
+warnings are a good example.
+
+
+@node Frames
+@chapter Frames
+
+A frame is a construct that GDB uses to keep track of calling and called
+functions.
+
+@table @code
+@item FRAME_FP
+in the machine description has no meaning to the machine-independent
+part of GDB, except that it is used when setting up a new frame from
+scratch, as follows:
+
+@example
+ create_new_frame (read_register (FP_REGNUM), read_pc ()));
+@end example
+
+Other than that, all the meaning imparted to @code{FP_REGNUM} is imparted by
+the machine-dependent code. So, @code{FP_REGNUM} can have any value that
+is convenient for the code that creates new frames. (@code{create_new_frame}
+calls @code{INIT_EXTRA_FRAME_INFO} if it is defined; that is where you should
+use the @code{FP_REGNUM} value, if your frames are nonstandard.)
+
+@item FRAME_CHAIN
+Given a GDB frame, determine the address of the calling function's
+frame. This will be used to create a new GDB frame struct, and then
+@code{INIT_EXTRA_FRAME_INFO} and @code{INIT_FRAME_PC} will be called for
+the new frame.
+@end table
+
+@node Remote Stubs
+@chapter Remote Stubs
+
+GDB's file @file{remote.c} talks a serial protocol to code that runs
+in the target system. GDB provides several sample ``stubs'' that can
+be integrated into target programs or operating systems for this purpose;
+they are named @file{*-stub.c}.
+
+The GDB user's manual describes how to put such a stub into your target
+code. What follows is a discussion of integrating the SPARC stub
+into a complicated operating system (rather than a simple program),
+by Stu Grossman, the author of this stub.
+
+The trap handling code in the stub assumes the following upon entry to
+trap_low:
+
+@enumerate
+@item %l1 and %l2 contain pc and npc respectively at the time of the trap
+@item traps are disabled
+@item you are in the correct trap window
+@end enumerate
+
+As long as your trap handler can guarantee those conditions, then there is no
+reason why you shouldn't be able to `share' traps with the stub. The stub has
+no requirement that it be jumped to directly from the hardware trap vector.
+That is why it calls @code{exceptionHandler()}, which is provided by the external
+environment. For instance, this could setup the hardware traps to actually
+execute code which calls the stub first, and then transfers to its own trap
+handler.
+
+For the most point, there probably won't be much of an issue with `sharing'
+traps, as the traps we use are usually not used by the kernel, and often
+indicate unrecoverable error conditions. Anyway, this is all controlled by a
+table, and is trivial to modify.
+The most important trap for us is for @code{ta 1}. Without that, we
+can't single step or do breakpoints. Everything else is unnecessary
+for the proper operation of the debugger/stub.
+
+From reading the stub, it's probably not obvious how breakpoints work. They
+are simply done by deposit/examine operations from GDB.
+
+@node Longjmp Support
+@chapter Longjmp Support
+
+GDB has support for figuring out that the target is doing a
+@code{longjmp} and for stopping at the target of the jump, if we are
+stepping. This is done with a few specialized internal breakpoints,
+which are visible in the @code{maint info breakpoint} command.
+
+To make this work, you need to define a macro called
+@code{GET_LONGJMP_TARGET}, which will examine the @code{jmp_buf}
+structure and extract the longjmp target address. Since @code{jmp_buf}
+is target specific, you will need to define it in the appropriate
+@file{tm-xxx.h} file. Look in @file{tm-sun4os4.h} and
+@file{sparc-tdep.c} for examples of how to do this.
+
+@node Coding Style
+@chapter Coding Style
+
+GDB is generally written using the GNU coding standards, as described in
+@file{standards.texi}, which is available for anonymous FTP from GNU
+archive sites. There are some additional considerations for GDB
+maintainers that reflect the unique environment and style of GDB
+maintenance. If you follow these guidelines, GDB will be more
+consistent and easier to maintain.
+
+GDB's policy on the use of prototypes is that prototypes are used
+to @emph{declare} functions but never to @emph{define} them. Simple
+macros are used in the declarations, so that a non-ANSI compiler can
+compile GDB without trouble. The simple macro calls are used like
+this:
+
+@example @code
+extern int
+memory_remove_breakpoint PARAMS ((CORE_ADDR, char *));
+@end example
+
+Note the double parentheses around the parameter types. This allows
+an arbitrary number of parameters to be described, without freaking
+out the C preprocessor. When the function has no parameters, it
+should be described like:
+
+@example @code
+void
+noprocess PARAMS ((void));
+@end example
+
+The @code{PARAMS} macro expands to its argument in ANSI C, or to a simple
+@code{()} in traditional C.
+
+All external functions should have a @code{PARAMS} declaration in a
+header file that callers include. All static functions should have such
+a declaration near the top of their source file.
+
+We don't have a gcc option that will properly check that these rules
+have been followed, but it's GDB policy, and we periodically check it
+using the tools available (plus manual labor), and clean up any remnants.
+
+@node Clean Design
+@chapter Clean Design
+
+In addition to getting the syntax right, there's the little question of
+semantics. Some things are done in certain ways in GDB because long
+experience has shown that the more obvious ways caused various kinds of
+trouble. In particular:
+
+@table @bullet
+@item
+You can't assume the byte order of anything that comes from a
+target (including @var{value}s, object files, and instructions). Such
+things must be byte-swapped using @code{SWAP_TARGET_AND_HOST} in GDB,
+or one of the swap routines defined in @file{bfd.h}, such as @code{bfd_get_32}.
+
+@item
+You can't assume that you know what interface is being used to talk to
+the target system. All references to the target must go through the
+current @code{target_ops} vector.
+
+@item
+You can't assume that the host and target machines are the same machine
+(except in the ``native'' support modules).
+In particular, you can't assume that the target machine's header files
+will be available on the host machine. Target code must bring along its
+own header files -- written from scratch or explicitly donated by their
+owner, to avoid copyright problems.
+
+@item
+Insertion of new @code{#ifdef}'s will be frowned upon. It's much better
+to write the code portably than to conditionalize it for various systems.
+
+@item
+New @code{#ifdef}'s which test for specific compilers or manufacturers
+or operating systems are unacceptable. All @code{#ifdef}'s should test
+for features. The information about which configurations contain which
+features should be segregated into the configuration files. Experience
+has proven far too often that a feature unique to one particular system
+often creeps into other systems; and that a conditional based on
+some predefined macro for your current system will become worthless
+over time, as new versions of your system come out that behave differently
+with regard to this feature.
+
+@item
+Adding code that handles specific architectures, operating systems, target
+interfaces, or hosts, is not acceptable in generic code. If a hook
+is needed at that point, invent a generic hook and define it for your
+configuration, with something like:
+
+@example
+#ifdef WRANGLE_SIGNALS
+ WRANGLE_SIGNALS (signo);
+#endif
+@end example
+
+In your host, target, or native configuration file, as appropriate,
+define @code{WRANGLE_SIGNALS} to do the machine-dependent thing. Take
+a bit of care in defining the hook, so that it can be used by other
+ports in the future, if they need a hook in the same place.
+
+If the hook is not defined, the code should do whatever "most" machines
+want. Using @code{#ifdef}, as above, is the preferred way to do this,
+but sometimes that gets convoluted, in which case use
+
+@example
+#ifndef SPECIAL_FOO_HANDLING
+#define SPECIAL_FOO_HANDLING(pc, sp) (0)
+#endif
+@end example
+
+where the macro is used or in an appropriate header file.
+
+Whether to include a @dfn{small} hook, a hook around the exact pieces of
+code which are system-dependent, or whether to replace a whole function
+with a hook depends on the case. A good example of this dilemma can be
+found in @code{get_saved_register}. All machines that GDB 2.8 ran on
+just needed the @code{FRAME_FIND_SAVED_REGS} hook to find the saved
+registers. Then the SPARC and Pyramid came along, and
+@code{HAVE_REGISTER_WINDOWS} and @code{REGISTER_IN_WINDOW_P} were
+introduced. Then the 29k and 88k required the @code{GET_SAVED_REGISTER}
+hook. The first three are examples of small hooks; the latter replaces
+a whole function. In this specific case, it is useful to have both
+kinds; it would be a bad idea to replace all the uses of the small hooks
+with @code{GET_SAVED_REGISTER}, since that would result in much
+duplicated code. Other times, duplicating a few lines of code here or
+there is much cleaner than introducing a large number of small hooks.
+
+Another way to generalize GDB along a particular interface is with an
+attribute struct. For example, GDB has been generalized to handle
+multiple kinds of remote interfaces -- not by #ifdef's everywhere, but
+by defining the "target_ops" structure and having a current target (as
+well as a stack of targets below it, for memory references). Whenever
+something needs to be done that depends on which remote interface we are
+using, a flag in the current target_ops structure is tested (e.g.
+`target_has_stack'), or a function is called through a pointer in the
+current target_ops structure. In this way, when a new remote interface
+is added, only one module needs to be touched -- the one that actually
+implements the new remote interface. Other examples of
+attribute-structs are BFD access to multiple kinds of object file
+formats, or GDB's access to multiple source languages.
+
+Please avoid duplicating code. For example, in GDB 3.x all the code
+interfacing between @code{ptrace} and the rest of GDB was duplicated in
+@file{*-dep.c}, and so changing something was very painful. In GDB 4.x,
+these have all been consolidated into @file{infptrace.c}.
+@file{infptrace.c} can deal with variations between systems the same way
+any system-independent file would (hooks, #if defined, etc.), and
+machines which are radically different don't need to use infptrace.c at
+all.
+
+@item
+@emph{Do} write code that doesn't depend on the sizes of C data types,
+the format of the host's floating point numbers, the alignment of anything,
+or the order of evaluation of expressions. In short, follow good
+programming practices for writing portable C code.
+
+@end table
+
+@node Submitting Patches
+@chapter Submitting Patches
+
+Thanks for thinking of offering your changes back to the community of
+GDB users. In general we like to get well designed enhancements.
+Thanks also for checking in advance about the best way to transfer the
+changes.
+
+The two main problems with getting your patches in are,
+
+@table @bullet
+@item
+The GDB maintainers will only install ``cleanly designed'' patches.
+You may not always agree on what is clean design.
+@pxref{Coding Style}, @pxref{Clean Design}.
+
+@item
+If the maintainers don't have time to put the patch in when it
+arrives, or if there is any question about a patch, it
+goes into a large queue with everyone else's patches and
+bug reports.
+@end table
+
+I don't know how to get past these problems except by continuing to try.
+
+There are two issues here -- technical and legal.
+
+The legal issue is that to incorporate substantial changes requires a
+copyright assignment from you and/or your employer, granting ownership
+of the changes to the Free Software Foundation. You can get the
+standard document for doing this by sending mail to
+@code{gnu@@prep.ai.mit.edu} and asking for it. I recommend that people
+write in "All programs owned by the Free Software Foundation" as "NAME
+OF PROGRAM", so that changes in many programs (not just GDB, but GAS,
+Emacs, GCC, etc) can be contributed with only one piece of legalese
+pushed through the bureacracy and filed with the FSF. I can't start
+merging changes until this paperwork is received by the FSF (their
+rules, which I follow since I maintain it for them).
+
+Technically, the easiest way to receive changes is to receive each
+feature as a small context diff or unidiff, suitable for "patch".
+Each message sent to me should include the changes to C code and
+header files for a single feature, plus ChangeLog entries for each
+directory where files were modified, and diffs for any changes needed
+to the manuals (gdb/doc/gdb.texi or gdb/doc/gdbint.texi). If there
+are a lot of changes for a single feature, they can be split down
+into multiple messages.
+
+In this way, if I read and like the feature, I can add it to the
+sources with a single patch command, do some testing, and check it in.
+If you leave out the ChangeLog, I have to write one. If you leave
+out the doc, I have to puzzle out what needs documenting. Etc.
+
+The reason to send each change in a separate message is that I will
+not install some of the changes. They'll be returned to you with
+questions or comments. If I'm doing my job, my message back to you
+will say what you have to fix in order to make the change acceptable.
+The reason to have separate messages for separate features is so
+that other changes (which I @emph{am} willing to accept) can be installed
+while one or more changes are being reworked. If multiple features
+are sent in a single message, I tend to not put in the effort to sort
+out the acceptable changes from the unacceptable, so none of the
+features get installed until all are acceptable.
+
+If this sounds painful or authoritarian, well, it is. But I get a lot
+of bug reports and a lot of patches, and most of them don't get
+installed because I don't have the time to finish the job that the bug
+reporter or the contributor could have done. Patches that arrive
+complete, working, and well designed, tend to get installed on the day
+they arrive. The others go into a queue and get installed if and when
+I scan back over the queue -- which can literally take months
+sometimes. It's in both our interests to make patch installation easy
+-- you get your changes installed, and I make some forward progress on
+GDB in a normal 12-hour day (instead of them having to wait until I
+have a 14-hour or 16-hour day to spend cleaning up patches before I
+can install them).
+
+Please send patches to @code{bug-gdb@@prep.ai.mit.edu}, if they are less
+than about 25,000 characters. If longer than that, either make them
+available somehow (e.g. anonymous FTP), and announce it on
+@code{bug-gdb}, or send them directly to the GDB maintainers at
+@code{gdb-patches@@cygnus.com}.
+
+@node Host Conditionals
+@chapter Host Conditionals
+
+When GDB is configured and compiled, various macros are defined or left
+undefined, to control compilation based on the attributes of the host
+system. These macros and their meanings (or if the meaning is not
+documented here, then one of the source files where they are used is
+indicated) are:
+
+@emph{NOTE: For now, both host and target conditionals are here.
+Eliminate target conditionals from this list as they are identified.}
+
+@table @code
+
+@item BLOCK_ADDRESS_FUNCTION_RELATIVE
+dbxread.c
+
+@item GDBINIT_FILENAME
+The default name of GDB's initialization file (normally @file{.gdbinit}).
+
+@item KERNELDEBUG
+tm-hppa.h
+
+@item MEM_FNS_DECLARED
+Your host config file defines this if it includes
+declarations of @code{memcpy} and @code{memset}. Define this
+to avoid conflicts between the native include
+files and the declarations in @file{defs.h}.
+
+@item NO_SYS_FILE
+dbxread.c
+@item PYRAMID_CONTROL_FRAME_DEBUGGING
+pyr-xdep.c
+@item SIGWINCH_HANDLER_BODY
+utils.c
+@item ADDITIONAL_OPTIONS
+main.c
+@item ADDITIONAL_OPTION_CASES
+main.c
+@item ADDITIONAL_OPTION_HANDLER
+main.c
+@item ADDITIONAL_OPTION_HELP
+main.c
+@item ADDR_BITS_REMOVE
+defs.h
+@item AIX_BUGGY_PTRACE_CONTINUE
+infptrace.c
+@item ALIGN_STACK_ON_STARTUP
+main.c
+@item ALTOS
+altos-xdep.c
+@item ALTOS_AS
+xm-altos.h
+@item ASCII_COFF
+remote-adapt.c
+@item BCS
+tm-delta88.h
+@item BEFORE_MAIN_LOOP_HOOK
+main.c
+@item BELIEVE_PCC_PROMOTION
+coffread.c
+@item BELIEVE_PCC_PROMOTION_TYPE
+stabsread.c
+@item BITS_BIG_ENDIAN
+defs.h
+@item BKPT_AT_MAIN
+solib.c
+@item BLOCK_ADDRESS_ABSOLUTE
+dbxread.c
+@item BPT_VECTOR
+tm-m68k.h
+
+@item BROKEN_LARGE_ALLOCA
+Avoid large @code{alloca}'s. For example, on sun's, Large alloca's fail
+because the attempt to increase the stack limit in main() fails because
+shared libraries are allocated just below the initial stack limit. The
+SunOS kernel will not allow the stack to grow into the area occupied by
+the shared libraries.
+
+@item CALL_DUMMY
+valops.c
+@item CALL_DUMMY_LOCATION
+inferior.h
+@item CALL_DUMMY_STACK_ADJUST
+valops.c
+@item CFRONT_PRODUCER
+dwarfread.c
+@item CHILD_PREPARE_TO_STORE
+inftarg.c
+@item CLEAR_DEFERRED_STORES
+inflow.c
+@item CLEAR_SOLIB
+objfiles.c
+@item COFF_ENCAPSULATE
+hppabsd-tdep.c
+@item COFF_FORMAT
+symm-tdep.c
+@item CORE_NEEDS_RELOCATION
+stack.c
+@item CPLUS_MARKER
+cplus-dem.c
+@item C_ALLOCA
+regex.c
+@item C_GLBLREG
+coffread.c
+@item DBXREAD_ONLY
+partial-stab.h
+@item DBX_PARM_SYMBOL_CLASS
+stabsread.c
+@item DEBUG_INFO
+partial-stab.h
+@item DEBUG_PTRACE
+hppabsd-xdep.c
+@item DECR_PC_AFTER_BREAK
+breakpoint.c
+
+@item DEFAULT_PROMPT
+The default value of the prompt string (normally @code{"(gdb) "}).
+
+@item DELTA88
+m88k-xdep.c
+@item DEV_TTY
+symmisc.c
+@item DGUX
+m88k-xdep.c
+@item DISABLE_UNSETTABLE_BREAK
+breakpoint.c
+@item DONT_USE_REMOTE
+remote.c
+@item DO_DEFERRED_STORES
+infrun.c
+@item DO_REGISTERS_INFO
+infcmd.c
+@item EXTRACT_RETURN_VALUE
+tm-m68k.h
+@item EXTRACT_STRUCT_VALUE_ADDRESS
+values.c
+@item EXTRA_FRAME_INFO
+frame.h
+@item EXTRA_SYMTAB_INFO
+symtab.h
+@item FILES_INFO_HOOK
+target.c
+@item FLOAT_INFO
+infcmd.c
+@item FOPEN_RB
+defs.h
+@item FUNCTION_EPILOGUE_SIZE
+coffread.c
+@item F_OK
+xm-ultra3.h
+@item GCC2_COMPILED_FLAG_SYMBOL
+dbxread.c
+@item GCC_COMPILED_FLAG_SYMBOL
+dbxread.c
+@item GCC_MANGLE_BUG
+symtab.c
+@item GCC_PRODUCER
+dwarfread.c
+@item GET_SAVED_REGISTER
+findvar.c
+@item GPLUS_PRODUCER
+dwarfread.c
+@item HANDLE_RBRAC
+partial-stab.h
+
+@item HAVE_MMAP
+In some cases, use the system call @code{mmap} for reading symbol
+tables. For some machines this allows for sharing and quick updates.
+
+@item HAVE_REGISTER_WINDOWS
+findvar.c
+@item HAVE_SIGSETMASK
+main.c
+@item HAVE_TERMIO
+inflow.c
+@item HEADER_SEEK_FD
+arm-tdep.c
+@item HOSTING_ONLY
+xm-rtbsd.h
+@item HOST_BYTE_ORDER
+findvar.c
+@item HPUX_ASM
+xm-hp300hpux.h
+@item HPUX_VERSION_5
+hp300ux-xdep.c
+@item HP_OS_BUG
+infrun.c
+@item I80960
+remote-vx.c
+@item IEEE_FLOAT
+valprint.c
+@item IGNORE_SYMBOL
+dbxread.c
+@item INIT_EXTRA_FRAME_INFO
+blockframe.c
+@item INIT_EXTRA_SYMTAB_INFO
+symfile.c
+@item INIT_FRAME_PC
+blockframe.c
+@item INNER_THAN
+valops.c
+@item INT_MAX
+defs.h
+@item INT_MIN
+defs.h
+@item IN_GDB
+i960-pinsn.c
+@item IN_SIGTRAMP
+infrun.c
+@item IN_SOLIB_TRAMPOLINE
+infrun.c
+@item ISATTY
+main.c
+@item IS_TRAPPED_INTERNALVAR
+values.c
+@item KERNELDEBUG
+dbxread.c
+@item KERNEL_DEBUGGING
+tm-ultra3.h
+
+@item KERNEL_U_ADDR
+Define this to the address of the @code{u} structure (the ``user struct'',
+also known as the ``u-page'') in kernel virtual memory. GDB needs to know
+this so that it can subtract this address from absolute addresses in
+the upage, that are obtained via ptrace or from core files. On systems
+that don't need this value, set it to zero.
+
+@item KERNEL_U_ADDR_BSD
+Define this to cause GDB to determine the address of @code{u} at runtime,
+by using Berkeley-style @code{nlist} on the kernel's image in the root
+directory.
+
+@item KERNEL_U_ADDR_HPUX
+Define this to cause GDB to determine the address of @code{u} at runtime,
+by using HP-style @code{nlist} on the kernel's image in the root
+directory.
+
+@item LCC_PRODUCER
+dwarfread.c
+@item LOG_FILE
+remote-adapt.c
+@item LONGERNAMES
+cplus-dem.c
+@item LONGEST
+defs.h
+@item CC_HAS_LONG_LONG
+defs.h
+@item PRINTF_HAS_LONG_LONG
+defs.h
+@item LONG_MAX
+defs.h
+@item LSEEK_NOT_LINEAR
+source.c
+@item L_LNNO32
+coffread.c
+
+@item L_SET
+This macro is used as the argument to lseek (or, most commonly, bfd_seek).
+FIXME, should be replaced by SEEK_SET instead, which is the POSIX equivalent.
+
+@item MACHKERNELDEBUG
+hppabsd-tdep.c
+@item MAINTENANCE
+dwarfread.c
+
+@item MAINTENANCE_CMDS
+If the value of this is 1, then a number of optional maintenance commands
+are compiled in.
+
+@item MALLOC_INCOMPATIBLE
+Define this if the system's prototype for @code{malloc} differs from the
+@sc{ANSI} definition.
+
+@item MIPSEL
+mips-tdep.c
+
+@item MMAP_BASE_ADDRESS
+When using HAVE_MMAP, the first mapping should go at this address.
+
+@item MMAP_INCREMENT
+when using HAVE_MMAP, this is the increment between mappings.
+
+@item MONO
+ser-go32.c
+@item MOTOROLA
+xm-altos.h
+@item NBPG
+altos-xdep.c
+@item NEED_POSIX_SETPGID
+infrun.c
+@item NEED_TEXT_START_END
+exec.c
+@item NFAILURES
+regex.c
+
+@item NORETURN
+(in defs.h - is this really useful to define/undefine?)
+
+@item NOTDEF
+regex.c
+@item NOTDEF
+remote-adapt.c
+@item NOTDEF
+remote-mm.c
+@item NOTICE_SIGNAL_HANDLING_CHANGE
+infrun.c
+@item NO_HIF_SUPPORT
+remote-mm.c
+@item NO_JOB_CONTROL
+signals.h
+
+@item NO_MMALLOC
+GDB will use the @code{mmalloc} library for memory allocation for symbol
+reading, unless this symbol is defined. Define it on systems
+on which @code{mmalloc} does not
+work for some reason. One example is the DECstation, where its RPC
+library can't cope with our redefinition of @code{malloc} to call
+@code{mmalloc}. When defining @code{NO_MMALLOC}, you will also have
+to override the setting of @code{MMALLOC_LIB} to empty, in the Makefile.
+Therefore, this define is usually set on the command line by overriding
+@code{MMALLOC_DISABLE} in @file{config/*/*.mh}, rather than by defining
+it in @file{xm-*.h}.
+
+@item NO_MMALLOC_CHECK
+Define this if you are using @code{mmalloc}, but don't want the overhead
+of checking the heap with @code{mmcheck}.
+
+@item NO_SIGINTERRUPT
+remote-adapt.c
+@item NO_SINGLE_STEP
+infptrace.c
+@item NS32K_SVC_IMMED_OPERANDS
+ns32k-opcode.h
+@item NUMERIC_REG_NAMES
+mips-tdep.c
+@item N_SETV
+dbxread.c
+@item N_SET_MAGIC
+hppabsd-tdep.c
+@item NaN
+tm-umax.h
+@item ONE_PROCESS_WRITETEXT
+breakpoint.c
+@item O_BINARY
+exec.c
+@item O_RDONLY
+xm-ultra3.h
+@item PC
+convx-opcode.h
+@item PCC_SOL_BROKEN
+dbxread.c
+@item PC_IN_CALL_DUMMY
+inferior.h
+@item PC_LOAD_SEGMENT
+stack.c
+@item PRINT_RANDOM_SIGNAL
+infcmd.c
+@item PRINT_REGISTER_HOOK
+infcmd.c
+@item PRINT_TYPELESS_INTEGER
+valprint.c
+@item PROCESS_LINENUMBER_HOOK
+buildsym.c
+@item PROLOGUE_FIRSTLINE_OVERLAP
+infrun.c
+@item PSIGNAL_IN_SIGNAL_H
+defs.h
+@item PUSH_ARGUMENTS
+valops.c
+@item PYRAMID_CONTROL_FRAME_DEBUGGING
+pyr-xdep.c
+@item PYRAMID_CORE
+pyr-xdep.c
+@item PYRAMID_PTRACE
+pyr-xdep.c
+@item REGISTER_BYTES
+remote.c
+@item REGISTER_NAMES
+tm-a29k.h
+@item REG_STACK_SEGMENT
+exec.c
+@item REG_STRUCT_HAS_ADDR
+findvar.c
+@item RE_NREGS
+regex.h
+@item R_FP
+dwarfread.c
+@item R_OK
+xm-altos.h
+@item SEEK_END
+state.c
+@item SEEK_SET
+state.c
+@item SEM
+coffread.c
+
+@item SET_STACK_LIMIT_HUGE
+When defined, stack limits will be raised to their maximum. Use this
+if your host supports @code{setrlimit} and you have trouble with
+@code{stringtab} in @file{dbxread.c}.
+
+Also used in @file{fork-child.c} to return stack limits before child
+processes are forked.
+
+@item SHELL_COMMAND_CONCAT
+infrun.c
+@item SHELL_FILE
+infrun.c
+@item SHIFT_INST_REGS
+breakpoint.c
+@item SIGN_EXTEND_CHAR
+regex.c
+@item SIGTRAP_STOP_AFTER_LOAD
+infrun.c
+@item SKIP_TRAMPOLINE_CODE
+infrun.c
+@item SOLIB_ADD
+core.c
+@item STACK_ALIGN
+valops.c
+@item START_INFERIOR_TRAPS_EXPECTED
+infrun.c
+@item STOP_SIGNAL
+main.c
+@item SUN4_COMPILER_FEATURE
+infrun.c
+@item SUN_FIXED_LBRAC_BUG
+dbxread.c
+@item SVR4_SHARED_LIBS
+solib.c
+@item SWITCH_ENUM_BUG
+regex.c
+@item SYM1
+tm-ultra3.h
+@item SYMBOL_RELOADING_DEFAULT
+symfile.c
+@item SYNTAX_TABLE
+regex.c
+@item Sword
+regex.c
+@item TIOCGETC
+inflow.c
+@item TIOCGLTC
+inflow.c
+@item TIOCGPGRP
+inflow.c
+@item TIOCLGET
+inflow.c
+@item TIOCLSET
+inflow.c
+@item TIOCNOTTY
+inflow.c
+@item T_ARG
+coffread.c
+@item T_VOID
+coffread.c
+@item UINT_MAX
+defs.h
+@item UPAGES
+altos-xdep.c
+@item USER
+m88k-tdep.c
+@item USE_GAS
+xm-news.h
+@item USE_O_NOCTTY
+inflow.c
+@item USE_STRUCT_CONVENTION
+values.c
+
+@item USG
+Means that System V (prior to SVR4) include files are in use.
+(FIXME: This symbol is abused in @file{infrun.c}, @file{regex.c},
+@file{remote-nindy.c}, and @file{utils.c} for other things, at the moment.)
+
+@item USIZE
+xm-m88k.h
+@item U_FPSTATE
+i386-xdep.c
+@item VARIABLES_INSIDE_BLOCK
+dbxread.c
+@item WRS_ORIG
+remote-vx.c
+@item __GNUC__
+news-xdep.c
+@item __GO32__
+inflow.c
+@item __HPUX_ASM__
+xm-hp300hpux.h
+@item __INT_VARARGS_H
+printcmd.c
+@item __not_on_pyr_yet
+pyr-xdep.c
+@item alloca
+defs.h
+@item const
+defs.h
+@item GOULD_PN
+gould-pinsn.c
+@item hp800
+xm-hppabsd.h
+@item hpux
+hppabsd-core.c
+@item lint
+valarith.c
+@item longest_to_int
+defs.h
+@item mc68020
+m68k-stub.c
+@item notdef
+gould-pinsn.c
+@item ns32k_opcodeT
+ns32k-opcode.h
+@item sgi
+mips-tdep.c
+@item sparc
+regex.c
+@item sun
+m68k-tdep.c
+@item sun386
+tm-sun386.h
+@item test
+regex.c
+@item ultrix
+xm-mips.h
+@item volatile
+defs.h
+@end table
+
+@node Target Conditionals
+@chapter Target Conditionals
+
+When GDB is configured and compiled, various macros are defined or left
+undefined, to control compilation based on the attributes of the target
+system. These macros and their meanings are:
+
+@emph{NOTE: For now, both host and target conditionals are here.
+Eliminate host conditionals from this list as they are identified.}
+
+@table @code
+
+@item PUSH_DUMMY_FRAME
+Used in @samp{call_function_by_hand} to create an artificial stack frame.
+
+@item POP_FRAME
+Used in @samp{call_function_by_hand} to remove an artificial stack frame.
+
+@item BLOCK_ADDRESS_FUNCTION_RELATIVE
+dbxread.c
+@item KERNELDEBUG
+tm-hppa.h
+@item NO_SYS_FILE
+dbxread.c
+@item PYRAMID_CONTROL_FRAME_DEBUGGING
+pyr-xdep.c
+@item SIGWINCH_HANDLER_BODY
+utils.c
+@item ADDITIONAL_OPTIONS
+main.c
+@item ADDITIONAL_OPTION_CASES
+main.c
+@item ADDITIONAL_OPTION_HANDLER
+main.c
+@item ADDITIONAL_OPTION_HELP
+main.c
+@item ADDR_BITS_REMOVE
+defs.h
+@item ALIGN_STACK_ON_STARTUP
+main.c
+@item ALTOS
+altos-xdep.c
+@item ALTOS_AS
+xm-altos.h
+@item ASCII_COFF
+remote-adapt.c
+@item BCS
+tm-delta88.h
+@item BELIEVE_PCC_PROMOTION
+coffread.c
+@item BELIEVE_PCC_PROMOTION_TYPE
+stabsread.c
+@item BITS_BIG_ENDIAN
+defs.h
+@item BKPT_AT_MAIN
+solib.c
+@item BLOCK_ADDRESS_ABSOLUTE
+dbxread.c
+@item BPT_VECTOR
+tm-m68k.h
+@item BREAKPOINT
+tm-m68k.h
+@item CALL_DUMMY
+valops.c
+@item CALL_DUMMY_LOCATION
+inferior.h
+@item CALL_DUMMY_STACK_ADJUST
+valops.c
+
+@item CANNOT_FETCH_REGISTER (regno)
+A C expression that should be nonzero if @var{regno} cannot be
+fetched from an inferior process.
+This is only relevant if @code{FETCH_INFERIOR_REGISTERS} is not
+defined.
+
+@item CANNOT_STORE_REGISTER (regno)
+A C expression that should be nonzero if @var{regno} should not be
+written to the target. This is often the case for program counters,
+status words, and other special registers. If this is not defined,
+GDB will assume that all registers may be written.
+
+@item CFRONT_PRODUCER
+dwarfread.c
+@item CHILD_PREPARE_TO_STORE
+inftarg.c
+@item CLEAR_DEFERRED_STORES
+inflow.c
+@item CLEAR_SOLIB
+objfiles.c
+@item COFF_ENCAPSULATE
+hppabsd-tdep.c
+@item COFF_FORMAT
+symm-tdep.c
+@item CORE_NEEDS_RELOCATION
+stack.c
+@item CPLUS_MARKER
+cplus-dem.c
+@item C_GLBLREG
+coffread.c
+@item DBXREAD_ONLY
+partial-stab.h
+@item DBX_PARM_SYMBOL_CLASS
+stabsread.c
+@item DEBUG_INFO
+partial-stab.h
+@item DEBUG_PTRACE
+hppabsd-xdep.c
+@item DECR_PC_AFTER_BREAK
+breakpoint.c
+@item DELTA88
+m88k-xdep.c
+@item DEV_TTY
+symmisc.c
+@item DGUX
+m88k-xdep.c
+@item DISABLE_UNSETTABLE_BREAK
+breakpoint.c
+@item DONT_USE_REMOTE
+remote.c
+@item DO_DEFERRED_STORES
+infrun.c
+@item DO_REGISTERS_INFO
+infcmd.c
+
+@item END_OF_TEXT_DEFAULT
+This is an expression that should designate the end of the text section
+(? FIXME ?)
+
+@item EXTRACT_RETURN_VALUE
+tm-m68k.h
+@item EXTRACT_STRUCT_VALUE_ADDRESS
+values.c
+@item EXTRA_FRAME_INFO
+frame.h
+@item EXTRA_SYMTAB_INFO
+symtab.h
+@item FILES_INFO_HOOK
+target.c
+@item FLOAT_INFO
+infcmd.c
+@item FOPEN_RB
+defs.h
+@item FP0_REGNUM
+a68v-xdep.c
+@item FPC_REGNUM
+mach386-xdep.c
+@item FP_REGNUM
+parse.c
+@item FRAMELESS_FUNCTION_INVOCATION
+blockframe.c
+@item FRAME_ARGS_ADDRESS_CORRECT
+stack.c
+
+@item FRAME_CHAIN
+Given FRAME, return a pointer to the calling frame.
+
+@item FRAME_CHAIN_COMBINE
+blockframe.c
+@item FRAME_CHAIN_VALID
+frame.h
+@item FRAME_CHAIN_VALID_ALTERNATE
+frame.h
+@item FRAME_FIND_SAVED_REGS
+stack.c
+@item FRAME_GET_BASEREG_VALUE
+frame.h
+
+@item FRAME_NUM_ARGS (val, fi)
+For the frame described by fi, set val to the number of arguments
+that are being passed.
+
+@item FRAME_SPECIFICATION_DYADIC
+stack.c
+
+@item FRAME_SAVED_PC
+Given FRAME, return the pc saved there. That is, the return address.
+
+@item FUNCTION_EPILOGUE_SIZE
+coffread.c
+@item F_OK
+xm-ultra3.h
+@item GCC2_COMPILED_FLAG_SYMBOL
+dbxread.c
+@item GCC_COMPILED_FLAG_SYMBOL
+dbxread.c
+@item GCC_MANGLE_BUG
+symtab.c
+@item GCC_PRODUCER
+dwarfread.c
+
+@item GDB_TARGET_IS_HPPA
+This determines whether horrible kludge code in dbxread.c and partial-stab.h
+is used to mangle multiple-symbol-table files from HPPA's. This should all
+be ripped out, and a scheme like elfread.c used.
+
+@item GDB_TARGET_IS_MACH386
+mach386-xdep.c
+@item GDB_TARGET_IS_SUN3
+a68v-xdep.c
+@item GDB_TARGET_IS_SUN386
+sun386-xdep.c
+
+@item GET_LONGJMP_TARGET
+For most machines, this is a target-dependent parameter. On the DECstation
+and the Iris, this is a native-dependent parameter, since <setjmp.h> is
+needed to define it.
+
+This macro determines the target PC address that longjmp() will jump
+to, assuming that we have just stopped at a longjmp breakpoint. It
+takes a CORE_ADDR * as argument, and stores the target PC value through
+this pointer. It examines the current state of the machine as needed.
+
+@item GET_SAVED_REGISTER
+findvar.c
+@item GPLUS_PRODUCER
+dwarfread.c
+@item GR64_REGNUM
+remote-adapt.c
+@item GR64_REGNUM
+remote-mm.c
+@item HANDLE_RBRAC
+partial-stab.h
+@item HAVE_68881
+m68k-tdep.c
+@item HAVE_REGISTER_WINDOWS
+findvar.c
+@item HAVE_SIGSETMASK
+main.c
+@item HAVE_TERMIO
+inflow.c
+@item HEADER_SEEK_FD
+arm-tdep.c
+@item HOSTING_ONLY
+xm-rtbsd.h
+@item HPUX_ASM
+xm-hp300hpux.h
+@item HPUX_VERSION_5
+hp300ux-xdep.c
+@item HP_OS_BUG
+infrun.c
+@item I80960
+remote-vx.c
+
+@item IBM6000_TARGET
+Shows that we are configured for an IBM RS/6000 target. This conditional
+should be eliminated (FIXME) and replaced by feature-specific macros.
+It was introduced in haste and we are repenting at leisure.
+
+@item IEEE_FLOAT
+valprint.c
+@item IGNORE_SYMBOL
+dbxread.c
+@item INIT_EXTRA_FRAME_INFO
+blockframe.c
+@item INIT_EXTRA_SYMTAB_INFO
+symfile.c
+@item INIT_FRAME_PC
+blockframe.c
+@item INNER_THAN
+valops.c
+@item INT_MAX
+defs.h
+@item INT_MIN
+defs.h
+@item IN_GDB
+i960-pinsn.c
+@item IN_SIGTRAMP
+infrun.c
+@item IN_SOLIB_TRAMPOLINE
+infrun.c
+@item ISATTY
+main.c
+@item IS_TRAPPED_INTERNALVAR
+values.c
+@item KERNELDEBUG
+dbxread.c
+@item KERNEL_DEBUGGING
+tm-ultra3.h
+@item LCC_PRODUCER
+dwarfread.c
+@item LOG_FILE
+remote-adapt.c
+@item LONGERNAMES
+cplus-dem.c
+@item LONGEST
+defs.h
+@item CC_HAS_LONG_LONG
+defs.h
+@item PRINTF_HAS_LONG_LONG
+defs.h
+@item LONG_MAX
+defs.h
+@item L_LNNO32
+coffread.c
+@item MACHKERNELDEBUG
+hppabsd-tdep.c
+@item MAINTENANCE
+dwarfread.c
+@item MIPSEL
+mips-tdep.c
+@item MOTOROLA
+xm-altos.h
+@item NBPG
+altos-xdep.c
+@item NEED_POSIX_SETPGID
+infrun.c
+@item NEED_TEXT_START_END
+exec.c
+@item NNPC_REGNUM
+infrun.c
+@item NOTDEF
+remote-adapt.c
+@item NOTDEF
+remote-mm.c
+@item NOTICE_SIGNAL_HANDLING_CHANGE
+infrun.c
+@item NO_HIF_SUPPORT
+remote-mm.c
+@item NO_SIGINTERRUPT
+remote-adapt.c
+@item NO_SINGLE_STEP
+infptrace.c
+@item NPC_REGNUM
+infcmd.c
+@item NS32K_SVC_IMMED_OPERANDS
+ns32k-opcode.h
+@item NUMERIC_REG_NAMES
+mips-tdep.c
+@item N_SETV
+dbxread.c
+@item N_SET_MAGIC
+hppabsd-tdep.c
+@item NaN
+tm-umax.h
+@item ONE_PROCESS_WRITETEXT
+breakpoint.c
+@item PC
+convx-opcode.h
+@item PCC_SOL_BROKEN
+dbxread.c
+@item PC_IN_CALL_DUMMY
+inferior.h
+@item PC_LOAD_SEGMENT
+stack.c
+@item PC_REGNUM
+parse.c
+@item PRINT_RANDOM_SIGNAL
+infcmd.c
+@item PRINT_REGISTER_HOOK
+infcmd.c
+@item PRINT_TYPELESS_INTEGER
+valprint.c
+@item PROCESS_LINENUMBER_HOOK
+buildsym.c
+@item PROLOGUE_FIRSTLINE_OVERLAP
+infrun.c
+@item PSIGNAL_IN_SIGNAL_H
+defs.h
+@item PS_REGNUM
+parse.c
+@item PUSH_ARGUMENTS
+valops.c
+@item REGISTER_BYTES
+remote.c
+@item REGISTER_NAMES
+tm-a29k.h
+@item REG_STACK_SEGMENT
+exec.c
+@item REG_STRUCT_HAS_ADDR
+findvar.c
+@item R_FP
+dwarfread.c
+@item R_OK
+xm-altos.h
+
+@item SDB_REG_TO_REGNUM
+Define this to convert sdb register numbers
+into GDB regnums. If not defined, no conversion will be done.
+
+@item SEEK_END
+state.c
+@item SEEK_SET
+state.c
+@item SEM
+coffread.c
+@item SHELL_COMMAND_CONCAT
+infrun.c
+@item SHELL_FILE
+infrun.c
+@item SHIFT_INST_REGS
+breakpoint.c
+@item SIGTRAP_STOP_AFTER_LOAD
+infrun.c
+
+@item SKIP_PROLOGUE
+A C statement that advances the PC across any function entry
+prologue instructions so as to reach ``real'' code.
+
+@item SKIP_PROLOGUE_FRAMELESS_P
+A C statement that should behave similarly, but that can stop
+as soon as the function is known to have a frame.
+If not defined, @code{SKIP_PROLOGUE} will be used instead.
+
+@item SKIP_TRAMPOLINE_CODE
+infrun.c
+@item SOLIB_ADD
+core.c
+@item SP_REGNUM
+parse.c
+
+@item STAB_REG_TO_REGNUM
+Define this to convert stab register numbers (as gotten from `r' declarations)
+into GDB regnums. If not defined, no conversion will be done.
+
+@item STACK_ALIGN
+valops.c
+@item START_INFERIOR_TRAPS_EXPECTED
+infrun.c
+@item STOP_SIGNAL
+main.c
+
+@item STORE_RETURN_VALUE (type, valbuf)
+A C expression that stores a function return value of type @var{type},
+where @var{valbuf} is the address of the value to be stored.
+
+@item SUN4_COMPILER_FEATURE
+infrun.c
+@item SUN_FIXED_LBRAC_BUG
+dbxread.c
+@item SVR4_SHARED_LIBS
+solib.c
+@item SYM1
+tm-ultra3.h
+@item SYMBOL_RELOADING_DEFAULT
+symfile.c
+
+@item TARGET_BYTE_ORDER
+The ordering of bytes in the target.
+This must be defined to be either @code{BIG_ENDIAN} or @code{LITTLE_ENDIAN}.
+
+@item TARGET_CHAR_BIT
+Number of bits in a char; defaults to 8.
+
+@item TARGET_COMPLEX_BIT
+Number of bits in a complex number; defaults to @code{2 * TARGET_FLOAT_BIT}.
+
+@item TARGET_DOUBLE_BIT
+Number of bits in a double float; defaults to @code{8 * TARGET_CHAR_BIT}.
+
+@item TARGET_DOUBLE_COMPLEX_BIT
+Number of bits in a double complex; defaults to @code{2 * TARGET_DOUBLE_BIT}.
+
+@item TARGET_FLOAT_BIT
+Number of bits in a float; defaults to @code{4 * TARGET_CHAR_BIT}.
+
+@item TARGET_INT_BIT
+Number of bits in an integer; defaults to @code{4 * TARGET_CHAR_BIT}.
+
+@item TARGET_LONG_BIT
+Number of bits in a long integer; defaults to @code{4 * TARGET_CHAR_BIT}.
+
+@item TARGET_LONG_DOUBLE_BIT
+Number of bits in a long double float;
+defaults to @code{2 * TARGET_DOUBLE_BIT}.
+
+@item TARGET_LONG_LONG_BIT
+Number of bits in a long long integer; defaults to @code{2 * TARGET_LONG_BIT}.
+
+@item TARGET_PTR_BIT
+Number of bits in a pointer; defaults to @code{TARGET_INT_BIT}.
+
+@item TARGET_SHORT_BIT
+Number of bits in a short integer; defaults to @code{2 * TARGET_CHAR_BIT}.
+
+@item TARGET_READ_PC
+@item TARGET_WRITE_PC (val, pid)
+@item TARGET_READ_SP
+@item TARGET_WRITE_SP
+@item TARGET_READ_FP
+@item TARGET_WRITE_FP
+These change the behavior of @code{read_pc}, @code{write_pc},
+@code{read_sp}, @code{write_sp}, @code{read_fp} and @code{write_fp}.
+For most targets, these may be left undefined. GDB will call the
+read and write register functions with the relevant @code{_REGNUM} argument.
+
+These macros are useful when a target keeps one of these registers in a
+hard to get at place; for example, part in a segment register and part
+in an ordinary register.
+
+@item T_ARG
+coffread.c
+@item T_VOID
+coffread.c
+@item UINT_MAX
+defs.h
+@item USER
+m88k-tdep.c
+@item USE_GAS
+xm-news.h
+@item USE_STRUCT_CONVENTION
+values.c
+@item USIZE
+xm-m88k.h
+@item U_FPSTATE
+i386-xdep.c
+@item VARIABLES_INSIDE_BLOCK
+dbxread.c
+@item WRS_ORIG
+remote-vx.c
+@item __GO32__
+inflow.c
+@item __HPUX_ASM__
+xm-hp300hpux.h
+@item __INT_VARARGS_H
+printcmd.c
+@item __not_on_pyr_yet
+pyr-xdep.c
+@item GOULD_PN
+gould-pinsn.c
+@item hp800
+xm-hppabsd.h
+@item hpux
+hppabsd-core.c
+@item longest_to_int
+defs.h
+@item mc68020
+m68k-stub.c
+@item ns32k_opcodeT
+ns32k-opcode.h
+@item sgi
+mips-tdep.c
+@item sun
+m68k-tdep.c
+@item sun386
+tm-sun386.h
+
+@item test
+(Define this to enable testing code in regex.c.)
+
+@end table
+
+@node Native Conditionals
+@chapter Native Conditionals
+
+When GDB is configured and compiled, various macros are defined or left
+undefined, to control compilation when the host and target systems
+are the same. These macros should be defined (or left undefined)
+in @file{nm-@var{system}.h}.
+
+@table @code
+
+@item ATTACH_DETACH
+If defined, then GDB will include support for the @code{attach} and
+@code{detach} commands.
+
+@item FETCH_INFERIOR_REGISTERS
+Define this if the native-dependent code will provide its
+own routines
+@code{fetch_inferior_registers} and @code{store_inferior_registers} in
+@file{@var{HOST}-nat.c}.
+If this symbol is @emph{not} defined, and @file{infptrace.c}
+is included in this configuration, the default routines in
+@file{infptrace.c} are used for these functions.
+
+@item GET_LONGJMP_TARGET
+For most machines, this is a target-dependent parameter. On the DECstation
+and the Iris, this is a native-dependent parameter, since <setjmp.h> is
+needed to define it.
+
+This macro determines the target PC address that longjmp() will jump
+to, assuming that we have just stopped at a longjmp breakpoint. It
+takes a CORE_ADDR * as argument, and stores the target PC value through
+this pointer. It examines the current state of the machine as needed.
+
+@item PROC_NAME_FMT
+Defines the format for the name of a @file{/proc} device. Should be
+defined in @file{nm.h} @emph{only} in order to override the default
+definition in @file{procfs.c}.
+
+@item PTRACE_FP_BUG
+mach386-xdep.c
+
+@item PTRACE_ARG3_TYPE
+The type of the third argument to the @code{ptrace} system call, if it exists
+and is different from @code{int}.
+
+@item REGISTER_U_ADDR
+Defines the offset of the registers in the ``u area''; @pxref{Host}.
+
+@item SOLIB_CREATE_INFERIOR_HOOK
+Define this to expand into any shared-library-relocation code
+that you want to be run just after the child process has been forked.
+
+@item USE_PROC_FS
+This determines whether small routines in @file{*-tdep.c}, which
+translate register values
+between GDB's internal representation and the /proc representation,
+are compiled.
+
+@item U_REGS_OFFSET
+This is the offset of the registers in the upage. It need only be
+defined if the generic ptrace register access routines in
+@file{infptrace.c} are being used (that is,
+@file{infptrace.c} is configured in, and
+@code{FETCH_INFERIOR_REGISTERS} is not defined). If the default value
+from @file{infptrace.c} is good enough, leave it undefined.
+
+The default value means that u.u_ar0 @emph{points to} the location of the
+registers. I'm guessing that @code{#define U_REGS_OFFSET 0} means that
+u.u_ar0 @emph{is} the location of the registers.
+
+@end table
+
+@node Obsolete Conditionals
+@chapter Obsolete Conditionals
+
+Fragments of old code in GDB sometimes reference or set the following
+configuration macros. They should not be used by new code, and
+old uses should be removed as those parts of the debugger are
+otherwise touched.
+
+@table @code
+@item STACK_END_ADDR
+This macro used to define where the end of the stack appeared, for use
+in interpreting core file formats that don't record this address in the
+core file itself. This information is now configured in BFD, and GDB
+gets the info portably from there. The values in GDB's configuration
+files should be moved into BFD configuration files (if needed there),
+and deleted from all of GDB's config files.
+
+Any @file{@var{foo}-xdep.c} file that references STACK_END_ADDR
+is so old that it has never been converted to use BFD. Now that's old!
+@end table
+
+@node XCOFF
+@chapter The XCOFF Object File Format
+
+The IBM RS/6000 running AIX uses an object file format called xcoff.
+The COFF sections, symbols, and line numbers are used, but debugging
+symbols are dbx-style stabs whose strings are located in the
+@samp{.debug} section (rather than the string table). For more
+information, @xref{Top,,,stabs,The Stabs Debugging Format}, and search
+for XCOFF.
+
+The shared library scheme has a nice clean interface for figuring out
+what shared libraries are in use, but the catch is that everything which
+refers to addresses (symbol tables and breakpoints at least) needs to be
+relocated for both shared libraries and the main executable. At least
+using the standard mechanism this can only be done once the program has
+been run (or the core file has been read).
+
+@contents
+@bye
diff --git a/gnu/usr.bin/gdb/doc/h8-cfg.texi b/gnu/usr.bin/gdb/doc/h8-cfg.texi
new file mode 100644
index 0000000..823c7c2
--- /dev/null
+++ b/gnu/usr.bin/gdb/doc/h8-cfg.texi
@@ -0,0 +1,47 @@
+@c GDB version number is recorded in the variable GDBVN
+@include GDBvn.texi
+@c
+@set AGGLOMERATION
+@clear AMD29K
+@set BARETARGET
+@clear CONLY
+@set DOSHOST
+@clear FORTRAN
+@clear FSFDOC
+@clear GDBSERVER
+@clear GENERIC
+@set H8
+@set H8EXCLUSIVE
+@clear HAVE-FLOAT
+@clear I960
+@clear MOD2
+@clear NOVEL
+@clear POSIX
+@set PRECONFIGURED
+@clear REMOTESTUB
+@set SIMS
+@clear SERIAL
+@clear SPARC
+@clear ST2000
+@clear VXWORKS
+@clear Z8K
+@c ----------------------------------------------------------------------
+@c STRINGS:
+@c
+@c Name of GDB program. Used also for (gdb) prompt string.
+@set GDBP gdb
+@c
+@c Name of GDB product. Used in running text.
+@set GDBN GDB
+@c
+@c Name of GDB initialization file.
+@set GDBINIT .gdbinit
+@c
+@c Name of target.
+@set TARGET Hitachi Microprocessors
+@c
+@c Name of GCC product
+@set NGCC GCC
+@c
+@c Name of GCC program
+@set GCC gcc
diff --git a/gnu/usr.bin/gdb/doc/inc-hist.texi b/gnu/usr.bin/gdb/doc/inc-hist.texi
new file mode 100644
index 0000000..539e372
--- /dev/null
+++ b/gnu/usr.bin/gdb/doc/inc-hist.texi
@@ -0,0 +1,155 @@
+@ignore
+This file is completely identical to hsuser.texinfo, except that it has the
+reference to the programming manual removed. There are definately better ways
+to do this!
+
+This file documents the user interface to the GNU History library.
+
+Copyright (C) 1988, 1991 Free Software Foundation, Inc.
+Authored by Brian Fox.
+
+Permission is granted to make and distribute verbatim copies of this manual
+provided the copyright notice and this permission notice are preserved on
+all copies.
+
+Permission is granted to process this file through Tex and print the
+results, provided the printed document carries copying permission notice
+identical to this one except for the removal of this paragraph (this
+paragraph not being relevant to the printed manual).
+
+Permission is granted to copy and distribute modified versions of this
+manual under the conditions for verbatim copying, provided also that the
+GNU Copyright statement is available to the distributee, and provided that
+the entire resulting derived work is distributed under the terms of a
+permission notice identical to this one.
+
+Permission is granted to copy and distribute translations of this manual
+into another language, under the above conditions for modified versions.
+@end ignore
+
+@node Using History Interactively
+@appendix Using History Interactively
+
+This chapter describes how to use the GNU History Library interactively,
+from a user's standpoint.
+
+@menu
+* History Interaction:: What it feels like using History as a user.
+@end menu
+
+@node History Interaction
+@section History Interaction
+@cindex expansion
+
+The History library provides a history expansion feature that is similar
+to the history expansion in Csh. The following text describes the sytax
+that you use to manipulate the history information.
+
+History expansion takes place in two parts. The first is to determine
+which line from the previous history should be used during substitution.
+The second is to select portions of that line for inclusion into the
+current one. The line selected from the previous history is called the
+@dfn{event}, and the portions of that line that are acted upon are
+called @dfn{words}. The line is broken into words in the same fashion
+that the Bash shell does, so that several English (or Unix) words
+surrounded by quotes are considered as one word.
+
+@menu
+* Event Designators:: How to specify which history line to use.
+* Word Designators:: Specifying which words are of interest.
+* Modifiers:: Modifying the results of susbstitution.
+@end menu
+
+@node Event Designators
+@subsection Event Designators
+@cindex event designators
+
+An event designator is a reference to a command line entry in the
+history list.
+
+@table @asis
+
+@item @code{!}
+Start a history subsititution, except when followed by a space, tab, or
+the end of the line... @key{=} or @key{(}.
+
+@item @code{!!}
+Refer to the previous command. This is a synonym for @code{!-1}.
+
+@item @code{!n}
+Refer to command line @var{n}.
+
+@item @code{!-n}
+Refer to the command line @var{n} lines back.
+
+@item @code{!string}
+Refer to the most recent command starting with @var{string}.
+
+@item @code{!?string}[@code{?}]
+Refer to the most recent command containing @var{string}.
+
+@end table
+
+@node Word Designators
+@subsection Word Designators
+
+A @key{:} separates the event specification from the word designator. It
+can be omitted if the word designator begins with a @key{^}, @key{$},
+@key{*} or @key{%}. Words are numbered from the beginning of the line,
+with the first word being denoted by a 0 (zero).
+
+@table @code
+
+@item 0 (zero)
+The zero'th word. For many applications, this is the command word.
+
+@item n
+The @var{n}'th word.
+
+@item ^
+The first argument. that is, word 1.
+
+@item $
+The last argument.
+
+@item %
+The word matched by the most recent @code{?string?} search.
+
+@item x-y
+A range of words; @code{-@var{y}} Abbreviates @code{0-@var{y}}.
+
+@item *
+All of the words, excepting the zero'th. This is a synonym for @code{1-$}.
+It is not an error to use @key{*} if there is just one word in the event.
+The empty string is returned in that case.
+
+@end table
+
+@node Modifiers
+@subsection Modifiers
+
+After the optional word designator, you can add a sequence of one or more
+of the following modifiers, each preceded by a @key{:}.
+
+@table @code
+
+@item #
+The entire command line typed so far. This means the current command,
+not the previous command, so it really isn't a word designator, and doesn't
+belong in this section.
+
+@item h
+Remove a trailing pathname component, leaving only the head.
+
+@item r
+Remove a trailing suffix of the form @samp{.}@var{suffix}, leaving the basename.
+
+@item e
+Remove all but the suffix.
+
+@item t
+Remove all leading pathname components, leaving the tail.
+
+@item p
+Print the new command but do not execute it.
+@end table
diff --git a/gnu/usr.bin/gdb/doc/remote.texi b/gnu/usr.bin/gdb/doc/remote.texi
new file mode 100644
index 0000000..422379d
--- /dev/null
+++ b/gnu/usr.bin/gdb/doc/remote.texi
@@ -0,0 +1,1424 @@
+@c -*- Texinfo -*-
+@c Copyright (c) 1990 1991 1992 1993 Free Software Foundation, Inc.
+@c This file is part of the source for the GDB manual.
+@c This text diverted to "Remote Debugging" section in general case;
+@c however, if we're doing a manual specifically for one of these, it
+@c belongs up front (in "Getting In and Out" chapter).
+
+@ifset REMOTESTUB
+@node Remote Serial
+@subsection The @value{GDBN} remote serial protocol
+
+@cindex remote serial debugging, overview
+To debug a program running on another machine (the debugging
+@dfn{target} machine), you must first arrange for all the usual
+prerequisites for the program to run by itself. For example, for a C
+program, you need
+
+@enumerate
+@item
+A startup routine to set up the C runtime environment; these usually
+have a name like @file{crt0}. The startup routine may be supplied by
+your hardware supplier, or you may have to write your own.
+
+@item
+You probably need a C subroutine library to support your program's
+subroutine calls, notably managing input and output.
+
+@item
+A way of getting your program to the other machine---for example, a
+download program. These are often supplied by the hardware
+manufacturer, but you may have to write your own from hardware
+documentation.
+@end enumerate
+
+The next step is to arrange for your program to use a serial port to
+communicate with the machine where @value{GDBN} is running (the @dfn{host}
+machine). In general terms, the scheme looks like this:
+
+@table @emph
+@item On the host,
+@value{GDBN} already understands how to use this protocol; when everything
+else is set up, you can simply use the @samp{target remote} command
+(@pxref{Targets,,Specifying a Debugging Target}).
+
+@item On the target,
+you must link with your program a few special-purpose subroutines that
+implement the @value{GDBN} remote serial protocol. The file containing these
+subroutines is called a @dfn{debugging stub}.
+
+@ifset GDBSERVER
+On certain remote targets, you can use an auxiliary program
+@code{gdbserver} instead of linking a stub into your program.
+@xref{Server,,Using the @code{gdbserver} program}, for details.
+@end ifset
+@end table
+
+The debugging stub is specific to the architecture of the remote
+machine; for example, use @file{sparc-stub.c} to debug programs on
+@sc{sparc} boards.
+
+@cindex remote serial stub list
+These working remote stubs are distributed with @value{GDBN}:
+
+@table @code
+@item sparc-stub.c
+@kindex sparc-stub.c
+For @sc{sparc} architectures.
+
+@item m68k-stub.c
+@kindex m68k-stub.c
+@cindex Motorola 680x0
+@cindex m680x0
+For Motorola 680x0 architectures.
+
+@item i386-stub.c
+@kindex i386-stub.c
+@cindex Intel
+@cindex i386
+For Intel 386 and compatible architectures.
+@end table
+
+The @file{README} file in the @value{GDBN} distribution may list other
+recently added stubs.
+
+@menu
+* Stub Contents:: What the stub can do for you
+* Bootstrapping:: What you must do for the stub
+* Debug Session:: Putting it all together
+* Protocol:: Outline of the communication protocol
+@ifset GDBSERVER
+* Server:: Using the `gdbserver' program
+@end ifset
+@end menu
+
+@node Stub Contents
+@subsubsection What the stub can do for you
+
+@cindex remote serial stub
+The debugging stub for your architecture supplies these three
+subroutines:
+
+@table @code
+@item set_debug_traps
+@kindex set_debug_traps
+@cindex remote serial stub, initialization
+This routine arranges for @code{handle_exception} to run when your
+program stops. You must call this subroutine explicitly near the
+beginning of your program.
+
+@item handle_exception
+@kindex handle_exception
+@cindex remote serial stub, main routine
+This is the central workhorse, but your program never calls it
+explicitly---the setup code arranges for @code{handle_exception} to
+run when a trap is triggered.
+
+@code{handle_exception} takes control when your program stops during
+execution (for example, on a breakpoint), and mediates communications
+with @value{GDBN} on the host machine. This is where the communications
+protocol is implemented; @code{handle_exception} acts as the @value{GDBN}
+representative on the target machine; it begins by sending summary
+information on the state of your program, then continues to execute,
+retrieving and transmitting any information @value{GDBN} needs, until you
+execute a @value{GDBN} command that makes your program resume; at that point,
+@code{handle_exception} returns control to your own code on the target
+machine.
+
+@item breakpoint
+@cindex @code{breakpoint} subroutine, remote
+Use this auxiliary subroutine to make your program contain a
+breakpoint. Depending on the particular situation, this may be the only
+way for @value{GDBN} to get control. For instance, if your target
+machine has some sort of interrupt button, you won't need to call this;
+pressing the interrupt button transfers control to
+@code{handle_exception}---in effect, to @value{GDBN}. On some machines,
+simply receiving characters on the serial port may also trigger a trap;
+again, in that situation, you don't need to call @code{breakpoint} from
+your own program---simply running @samp{target remote} from the host
+@value{GDBN} session gets control.
+
+Call @code{breakpoint} if none of these is true, or if you simply want
+to make certain your program stops at a predetermined point for the
+start of your debugging session.
+@end table
+
+@node Bootstrapping
+@subsubsection What you must do for the stub
+
+@cindex remote stub, support routines
+The debugging stubs that come with @value{GDBN} are set up for a particular
+chip architecture, but they have no information about the rest of your
+debugging target machine.
+
+First of all you need to tell the stub how to communicate with the
+serial port.
+
+@table @code
+@item int getDebugChar()
+@kindex getDebugChar
+Write this subroutine to read a single character from the serial port.
+It may be identical to @code{getchar} for your target system; a
+different name is used to allow you to distinguish the two if you wish.
+
+@item void putDebugChar(int)
+@kindex putDebugChar
+Write this subroutine to write a single character to the serial port.
+It may be identical to @code{putchar} for your target system; a
+different name is used to allow you to distinguish the two if you wish.
+@end table
+
+@cindex control C, and remote debugging
+@cindex interrupting remote targets
+If you want @value{GDBN} to be able to stop your program while it is
+running, you need to use an interrupt-driven serial driver, and arrange
+for it to stop when it receives a @code{^C} (@samp{\003}, the control-C
+character). That is the character which @value{GDBN} uses to tell the
+remote system to stop.
+
+Getting the debugging target to return the proper status to @value{GDBN}
+probably requires changes to the standard stub; one quick and dirty way
+is to just execute a breakpoint instruction (the ``dirty'' part is that
+@value{GDBN} reports a @code{SIGTRAP} instead of a @code{SIGINT}).
+
+Other routines you need to supply are:
+
+@table @code
+@item void exceptionHandler (int @var{exception_number}, void *@var{exception_address})
+@kindex exceptionHandler
+Write this function to install @var{exception_address} in the exception
+handling tables. You need to do this because the stub does not have any
+way of knowing what the exception handling tables on your target system
+are like (for example, the processor's table might be in @sc{rom},
+containing entries which point to a table in @sc{ram}).
+@var{exception_number} is the exception number which should be changed;
+its meaning is architecture-dependent (for example, different numbers
+might represent divide by zero, misaligned access, etc). When this
+exception occurs, control should be transferred directly to
+@var{exception_address}, and the processor state (stack, registers,
+and so on) should be just as it is when a processor exception occurs. So if
+you want to use a jump instruction to reach @var{exception_address}, it
+should be a simple jump, not a jump to subroutine.
+
+For the 386, @var{exception_address} should be installed as an interrupt
+gate so that interrupts are masked while the handler runs. The gate
+should be at privilege level 0 (the most privileged level). The
+@sc{sparc} and 68k stubs are able to mask interrupts themself without
+help from @code{exceptionHandler}.
+
+@item void flush_i_cache()
+@kindex flush_i_cache
+Write this subroutine to flush the instruction cache, if any, on your
+target machine. If there is no instruction cache, this subroutine may
+be a no-op.
+
+On target machines that have instruction caches, @value{GDBN} requires this
+function to make certain that the state of your program is stable.
+@end table
+
+@noindent
+You must also make sure this library routine is available:
+
+@table @code
+@item void *memset(void *, int, int)
+@kindex memset
+This is the standard library function @code{memset} that sets an area of
+memory to a known value. If you have one of the free versions of
+@code{libc.a}, @code{memset} can be found there; otherwise, you must
+either obtain it from your hardware manufacturer, or write your own.
+@end table
+
+If you do not use the GNU C compiler, you may need other standard
+library subroutines as well; this varies from one stub to another,
+but in general the stubs are likely to use any of the common library
+subroutines which @code{gcc} generates as inline code.
+
+
+@node Debug Session
+@subsubsection Putting it all together
+
+@cindex remote serial debugging summary
+In summary, when your program is ready to debug, you must follow these
+steps.
+
+@enumerate
+@item
+Make sure you have the supporting low-level routines
+(@pxref{Bootstrapping,,What you must do for the stub}):
+@display
+@code{getDebugChar}, @code{putDebugChar},
+@code{flush_i_cache}, @code{memset}, @code{exceptionHandler}.
+@end display
+
+@item
+Insert these lines near the top of your program:
+
+@example
+set_debug_traps();
+breakpoint();
+@end example
+
+@item
+For the 680x0 stub only, you need to provide a variable called
+@code{exceptionHook}. Normally you just use
+
+@example
+void (*exceptionHook)() = 0;
+@end example
+
+but if before calling @code{set_debug_traps}, you set it to point to a
+function in your program, that function is called when
+@code{@value{GDBN}} continues after stopping on a trap (for example, bus
+error). The function indicated by @code{exceptionHook} is called with
+one parameter: an @code{int} which is the exception number.
+
+@item
+Compile and link together: your program, the @value{GDBN} debugging stub for
+your target architecture, and the supporting subroutines.
+
+@item
+Make sure you have a serial connection between your target machine and
+the @value{GDBN} host, and identify the serial port used for this on the host.
+
+@item
+@c The "remote" target now provides a `load' command, so we should
+@c document that. FIXME.
+Download your program to your target machine (or get it there by
+whatever means the manufacturer provides), and start it.
+
+@item
+To start remote debugging, run @value{GDBN} on the host machine, and specify
+as an executable file the program that is running in the remote machine.
+This tells @value{GDBN} how to find your program's symbols and the contents
+of its pure text.
+
+@cindex serial line, @code{target remote}
+Then establish communication using the @code{target remote} command.
+Its argument specifies how to communicate with the target
+machine---either via a devicename attached to a direct serial line, or a
+TCP port (usually to a terminal server which in turn has a serial line
+to the target). For example, to use a serial line connected to the
+device named @file{/dev/ttyb}:
+
+@example
+target remote /dev/ttyb
+@end example
+
+@cindex TCP port, @code{target remote}
+To use a TCP connection, use an argument of the form
+@code{@var{host}:port}. For example, to connect to port 2828 on a
+terminal server named @code{manyfarms}:
+
+@example
+target remote manyfarms:2828
+@end example
+@end enumerate
+
+Now you can use all the usual commands to examine and change data and to
+step and continue the remote program.
+
+To resume the remote program and stop debugging it, use the @code{detach}
+command.
+
+@cindex interrupting remote programs
+@cindex remote programs, interrupting
+Whenever @value{GDBN} is waiting for the remote program, if you type the
+interrupt character (often @key{C-C}), @value{GDBN} attempts to stop the
+program. This may or may not succeed, depending in part on the hardware
+and the serial drivers the remote system uses. If you type the
+interrupt character once again, @value{GDBN} displays this prompt:
+
+@example
+Interrupted while waiting for the program.
+Give up (and stop debugging it)? (y or n)
+@end example
+
+If you type @kbd{y}, @value{GDBN} abandons the remote debugging session.
+(If you decide you want to try again later, you can use @samp{target
+remote} again to connect once more.) If you type @kbd{n}, @value{GDBN}
+goes back to waiting.
+
+@node Protocol
+@subsubsection Communication protocol
+
+@cindex debugging stub, example
+@cindex remote stub, example
+@cindex stub example, remote debugging
+The stub files provided with @value{GDBN} implement the target side of the
+communication protocol, and the @value{GDBN} side is implemented in the
+@value{GDBN} source file @file{remote.c}. Normally, you can simply allow
+these subroutines to communicate, and ignore the details. (If you're
+implementing your own stub file, you can still ignore the details: start
+with one of the existing stub files. @file{sparc-stub.c} is the best
+organized, and therefore the easiest to read.)
+
+However, there may be occasions when you need to know something about
+the protocol---for example, if there is only one serial port to your
+target machine, you might want your program to do something special if
+it recognizes a packet meant for @value{GDBN}.
+
+@cindex protocol, @value{GDBN} remote serial
+@cindex serial protocol, @value{GDBN} remote
+@cindex remote serial protocol
+All @value{GDBN} commands and responses (other than acknowledgements, which
+are single characters) are sent as a packet which includes a
+checksum. A packet is introduced with the character @samp{$}, and ends
+with the character @samp{#} followed by a two-digit checksum:
+
+@example
+$@var{packet info}#@var{checksum}
+@end example
+
+@cindex checksum, for @value{GDBN} remote
+@noindent
+@var{checksum} is computed as the modulo 256 sum of the @var{packet
+info} characters.
+
+When either the host or the target machine receives a packet, the first
+response expected is an acknowledgement: a single character, either
+@samp{+} (to indicate the package was received correctly) or @samp{-}
+(to request retransmission).
+
+The host (@value{GDBN}) sends commands, and the target (the debugging stub
+incorporated in your program) sends data in response. The target also
+sends data when your program stops.
+
+Command packets are distinguished by their first character, which
+identifies the kind of command.
+
+These are the commands currently supported:
+
+@table @code
+@item g
+Requests the values of CPU registers.
+
+@item G
+Sets the values of CPU registers.
+
+@item m@var{addr},@var{count}
+Read @var{count} bytes at location @var{addr}.
+
+@item M@var{addr},@var{count}:@dots{}
+Write @var{count} bytes at location @var{addr}.
+
+@need 500
+@item c
+@itemx c@var{addr}
+Resume execution at the current address (or at @var{addr} if supplied).
+
+@need 500
+@item s
+@itemx s@var{addr}
+Step the target program for one instruction, from either the current
+program counter or from @var{addr} if supplied.
+
+@item k
+Kill the target program.
+
+@item ?
+Report the most recent signal. To allow you to take advantage of the
+@value{GDBN} signal handling commands, one of the functions of the debugging
+stub is to report CPU traps as the corresponding POSIX signal values.
+@end table
+
+@kindex set remotedebug
+@kindex show remotedebug
+@cindex packets, reporting on stdout
+@cindex serial connections, debugging
+If you have trouble with the serial connection, you can use the command
+@code{set remotedebug}. This makes @value{GDBN} report on all packets sent
+back and forth across the serial line to the remote machine. The
+packet-debugging information is printed on the @value{GDBN} standard output
+stream. @code{set remotedebug off} turns it off, and @code{show
+remotedebug} shows you its current state.
+
+@ifset GDBSERVER
+@node Server
+@subsubsection Using the @code{gdbserver} program
+
+@kindex gdbserver
+@cindex remote connection without stubs
+@code{gdbserver} is a control program for Unix-like systems, which
+allows you to connect your program with a remote @value{GDBN} via
+@code{target remote}---but without linking in the usual debugging stub.
+
+@code{gdbserver} is not a complete replacement for the debugging stubs,
+because it requires essentially the same operating-system facilities
+that @value{GDBN} itself does. In fact, a system that can run
+@code{gdbserver} to connect to a remote @value{GDBN} could also run
+@value{GDBN} locally! @code{gdbserver} is sometimes useful nevertheless,
+because it is a much smaller program than @value{GDBN} itself. It is
+also easier to port than all of @value{GDBN}, so you may be able to get
+started more quickly on a new system by using @code{gdbserver}.
+Finally, if you develop code for real-time systems, you may find that
+the tradeoffs involved in real-time operation make it more convenient to
+do as much development work as possible on another system, for example
+by cross-compiling. You can use @code{gdbserver} to make a similar
+choice for debugging.
+
+@value{GDBN} and @code{gdbserver} communicate via either a serial line
+or a TCP connection, using the standard @value{GDBN} remote serial
+protocol.
+
+@table @emph
+@item On the target machine,
+you need to have a copy of the program you want to debug.
+@code{gdbserver} does not need your program's symbol table, so you can
+strip the program if necessary to save space. @value{GDBN} on the host
+system does all the symbol handling.
+
+To use the server, you must tell it how to communicate with @value{GDBN};
+the name of your program; and the arguments for your program. The
+syntax is:
+
+@smallexample
+target> gdbserver @var{comm} @var{program} [ @var{args} @dots{} ]
+@end smallexample
+
+@var{comm} is either a device name (to use a serial line) or a TCP
+hostname and portnumber. For example, to debug Emacs with the argument
+@samp{foo.txt} and communicate with @value{GDBN} over the serial port
+@file{/dev/com1}:
+
+@smallexample
+target> gdbserver /dev/com1 emacs foo.txt
+@end smallexample
+
+@code{gdbserver} waits passively for the host @value{GDBN} to communicate
+with it.
+
+To use a TCP connection instead of a serial line:
+
+@smallexample
+target> gdbserver host:2345 emacs foo.txt
+@end smallexample
+
+The only difference from the previous example is the first argument,
+specifying that you are communicating with the host @value{GDBN} via
+TCP. The @samp{host:2345} argument means that @code{gdbserver} is to
+expect a TCP connection from machine @samp{host} to local TCP port 2345.
+(Currently, the @samp{host} part is ignored.) You can choose any number
+you want for the port number as long as it does not conflict with any
+TCP ports already in use on the target system (for example, @code{23} is
+reserved for @code{telnet}).@footnote{If you choose a port number that
+conflicts with another service, @code{gdbserver} prints an error message
+and exits.} You must use the same port number with the host @value{GDBN}
+@code{target remote} command.
+
+@item On the @value{GDBN} host machine,
+you need an unstripped copy of your program, since @value{GDBN} needs
+symbols and debugging information. Start up @value{GDBN} as usual,
+using the name of the local copy of your program as the first argument.
+(You may also need the @w{@samp{--baud}} option if the serial line is
+running at anything other than 9600 bps.) After that, use @code{target
+remote} to establish communications with @code{gdbserver}. Its argument
+is either a device name (usually a serial device, like
+@file{/dev/ttyb}), or a TCP port descriptor in the form
+@code{@var{host}:@var{PORT}}. For example:
+
+@smallexample
+(@value{GDBP}) target remote /dev/ttyb
+@end smallexample
+
+@noindent
+communicates with the server via serial line @file{/dev/ttyb}, and
+
+@smallexample
+(@value{GDBP}) target remote the-target:2345
+@end smallexample
+
+@noindent
+communicates via a TCP connection to port 2345 on host @w{@file{the-target}}.
+For TCP connections, you must start up @code{gdbserver} prior to using
+the @code{target remote} command. Otherwise you may get an error whose
+text depends on the host system, but which usually looks something like
+@samp{Connection refused}.
+@end table
+@end ifset
+
+@end ifset
+
+@ifset I960
+@node i960-Nindy Remote
+@subsection @value{GDBN} with a remote i960 (Nindy)
+
+@cindex Nindy
+@cindex i960
+@dfn{Nindy} is a ROM Monitor program for Intel 960 target systems. When
+@value{GDBN} is configured to control a remote Intel 960 using Nindy, you can
+tell @value{GDBN} how to connect to the 960 in several ways:
+
+@itemize @bullet
+@item
+Through command line options specifying serial port, version of the
+Nindy protocol, and communications speed;
+
+@item
+By responding to a prompt on startup;
+
+@item
+By using the @code{target} command at any point during your @value{GDBN}
+session. @xref{Target Commands, ,Commands for managing targets}.
+
+@end itemize
+
+@menu
+* Nindy Startup:: Startup with Nindy
+* Nindy Options:: Options for Nindy
+* Nindy Reset:: Nindy reset command
+@end menu
+
+@node Nindy Startup
+@subsubsection Startup with Nindy
+
+If you simply start @code{@value{GDBP}} without using any command-line
+options, you are prompted for what serial port to use, @emph{before} you
+reach the ordinary @value{GDBN} prompt:
+
+@example
+Attach /dev/ttyNN -- specify NN, or "quit" to quit:
+@end example
+
+@noindent
+Respond to the prompt with whatever suffix (after @samp{/dev/tty})
+identifies the serial port you want to use. You can, if you choose,
+simply start up with no Nindy connection by responding to the prompt
+with an empty line. If you do this and later wish to attach to Nindy,
+use @code{target} (@pxref{Target Commands, ,Commands for managing targets}).
+
+@node Nindy Options
+@subsubsection Options for Nindy
+
+These are the startup options for beginning your @value{GDBN} session with a
+Nindy-960 board attached:
+
+@table @code
+@item -r @var{port}
+Specify the serial port name of a serial interface to be used to connect
+to the target system. This option is only available when @value{GDBN} is
+configured for the Intel 960 target architecture. You may specify
+@var{port} as any of: a full pathname (e.g. @samp{-r /dev/ttya}), a
+device name in @file{/dev} (e.g. @samp{-r ttya}), or simply the unique
+suffix for a specific @code{tty} (e.g. @samp{-r a}).
+
+@item -O
+(An uppercase letter ``O'', not a zero.) Specify that @value{GDBN} should use
+the ``old'' Nindy monitor protocol to connect to the target system.
+This option is only available when @value{GDBN} is configured for the Intel 960
+target architecture.
+
+@quotation
+@emph{Warning:} if you specify @samp{-O}, but are actually trying to
+connect to a target system that expects the newer protocol, the connection
+fails, appearing to be a speed mismatch. @value{GDBN} repeatedly
+attempts to reconnect at several different line speeds. You can abort
+this process with an interrupt.
+@end quotation
+
+@item -brk
+Specify that @value{GDBN} should first send a @code{BREAK} signal to the target
+system, in an attempt to reset it, before connecting to a Nindy target.
+
+@quotation
+@emph{Warning:} Many target systems do not have the hardware that this
+requires; it only works with a few boards.
+@end quotation
+@end table
+
+The standard @samp{-b} option controls the line speed used on the serial
+port.
+
+@c @group
+@node Nindy Reset
+@subsubsection Nindy reset command
+
+@table @code
+@item reset
+@kindex reset
+For a Nindy target, this command sends a ``break'' to the remote target
+system; this is only useful if the target has been equipped with a
+circuit to perform a hard reset (or some other interesting action) when
+a break is detected.
+@end table
+@c @end group
+@end ifset
+
+@ifset AMD29K
+@node UDI29K Remote
+@subsection The UDI protocol for AMD29K
+
+@cindex UDI
+@cindex AMD29K via UDI
+@value{GDBN} supports AMD's UDI (``Universal Debugger Interface'')
+protocol for debugging the a29k processor family. To use this
+configuration with AMD targets running the MiniMON monitor, you need the
+program @code{MONTIP}, available from AMD at no charge. You can also
+use @value{GDBN} with the UDI conformant a29k simulator program
+@code{ISSTIP}, also available from AMD.
+
+@table @code
+@item target udi @var{keyword}
+@kindex udi
+Select the UDI interface to a remote a29k board or simulator, where
+@var{keyword} is an entry in the AMD configuration file @file{udi_soc}.
+This file contains keyword entries which specify parameters used to
+connect to a29k targets. If the @file{udi_soc} file is not in your
+working directory, you must set the environment variable @samp{UDICONF}
+to its pathname.
+@end table
+
+@node EB29K Remote
+@subsection The EBMON protocol for AMD29K
+
+@cindex EB29K board
+@cindex running 29K programs
+
+AMD distributes a 29K development board meant to fit in a PC, together
+with a DOS-hosted monitor program called @code{EBMON}. As a shorthand
+term, this development system is called the ``EB29K''. To use
+@value{GDBN} from a Unix system to run programs on the EB29K board, you
+must first connect a serial cable between the PC (which hosts the EB29K
+board) and a serial port on the Unix system. In the following, we
+assume you've hooked the cable between the PC's @file{COM1} port and
+@file{/dev/ttya} on the Unix system.
+
+@menu
+* Comms (EB29K):: Communications setup
+* gdb-EB29K:: EB29K cross-debugging
+* Remote Log:: Remote log
+@end menu
+
+@node Comms (EB29K)
+@subsubsection Communications setup
+
+The next step is to set up the PC's port, by doing something like this
+in DOS on the PC:
+
+@example
+C:\> MODE com1:9600,n,8,1,none
+@end example
+
+@noindent
+This example---run on an MS DOS 4.0 system---sets the PC port to 9600
+bps, no parity, eight data bits, one stop bit, and no ``retry'' action;
+you must match the communications parameters when establishing the Unix
+end of the connection as well.
+@c FIXME: Who knows what this "no retry action" crud from the DOS manual may
+@c mean? It's optional; leave it out? ---pesch@cygnus.com, 25feb91
+
+To give control of the PC to the Unix side of the serial line, type
+the following at the DOS console:
+
+@example
+C:\> CTTY com1
+@end example
+
+@noindent
+(Later, if you wish to return control to the DOS console, you can use
+the command @code{CTTY con}---but you must send it over the device that
+had control, in our example over the @file{COM1} serial line).
+
+From the Unix host, use a communications program such as @code{tip} or
+@code{cu} to communicate with the PC; for example,
+
+@example
+cu -s 9600 -l /dev/ttya
+@end example
+
+@noindent
+The @code{cu} options shown specify, respectively, the linespeed and the
+serial port to use. If you use @code{tip} instead, your command line
+may look something like the following:
+
+@example
+tip -9600 /dev/ttya
+@end example
+
+@noindent
+Your system may require a different name where we show
+@file{/dev/ttya} as the argument to @code{tip}. The communications
+parameters, including which port to use, are associated with the
+@code{tip} argument in the ``remote'' descriptions file---normally the
+system table @file{/etc/remote}.
+@c FIXME: What if anything needs doing to match the "n,8,1,none" part of
+@c the DOS side's comms setup? cu can support -o (odd
+@c parity), -e (even parity)---apparently no settings for no parity or
+@c for character size. Taken from stty maybe...? John points out tip
+@c can set these as internal variables, eg ~s parity=none; man stty
+@c suggests that it *might* work to stty these options with stdin or
+@c stdout redirected... ---pesch@cygnus.com, 25feb91
+
+@kindex EBMON
+Using the @code{tip} or @code{cu} connection, change the DOS working
+directory to the directory containing a copy of your 29K program, then
+start the PC program @code{EBMON} (an EB29K control program supplied
+with your board by AMD). You should see an initial display from
+@code{EBMON} similar to the one that follows, ending with the
+@code{EBMON} prompt @samp{#}---
+
+@example
+C:\> G:
+
+G:\> CD \usr\joe\work29k
+
+G:\USR\JOE\WORK29K> EBMON
+Am29000 PC Coprocessor Board Monitor, version 3.0-18
+Copyright 1990 Advanced Micro Devices, Inc.
+Written by Gibbons and Associates, Inc.
+
+Enter '?' or 'H' for help
+
+PC Coprocessor Type = EB29K
+I/O Base = 0x208
+Memory Base = 0xd0000
+
+Data Memory Size = 2048KB
+Available I-RAM Range = 0x8000 to 0x1fffff
+Available D-RAM Range = 0x80002000 to 0x801fffff
+
+PageSize = 0x400
+Register Stack Size = 0x800
+Memory Stack Size = 0x1800
+
+CPU PRL = 0x3
+Am29027 Available = No
+Byte Write Available = Yes
+
+# ~.
+@end example
+
+Then exit the @code{cu} or @code{tip} program (done in the example by
+typing @code{~.} at the @code{EBMON} prompt). @code{EBMON} keeps
+running, ready for @value{GDBN} to take over.
+
+For this example, we've assumed what is probably the most convenient
+way to make sure the same 29K program is on both the PC and the Unix
+system: a PC/NFS connection that establishes ``drive @code{G:}'' on the
+PC as a file system on the Unix host. If you do not have PC/NFS or
+something similar connecting the two systems, you must arrange some
+other way---perhaps floppy-disk transfer---of getting the 29K program
+from the Unix system to the PC; @value{GDBN} does @emph{not} download it over the
+serial line.
+
+@node gdb-EB29K
+@subsubsection EB29K cross-debugging
+
+Finally, @code{cd} to the directory containing an image of your 29K
+program on the Unix system, and start @value{GDBN}---specifying as argument the
+name of your 29K program:
+
+@example
+cd /usr/joe/work29k
+@value{GDBP} myfoo
+@end example
+
+@need 500
+Now you can use the @code{target} command:
+
+@example
+target amd-eb /dev/ttya 9600 MYFOO
+@c FIXME: test above 'target amd-eb' as spelled, with caps! caps are meant to
+@c emphasize that this is the name as seen by DOS (since I think DOS is
+@c single-minded about case of letters). ---pesch@cygnus.com, 25feb91
+@end example
+
+@noindent
+In this example, we've assumed your program is in a file called
+@file{myfoo}. Note that the filename given as the last argument to
+@code{target amd-eb} should be the name of the program as it appears to DOS.
+In our example this is simply @code{MYFOO}, but in general it can include
+a DOS path, and depending on your transfer mechanism may not resemble
+the name on the Unix side.
+
+At this point, you can set any breakpoints you wish; when you are ready
+to see your program run on the 29K board, use the @value{GDBN} command
+@code{run}.
+
+To stop debugging the remote program, use the @value{GDBN} @code{detach}
+command.
+
+To return control of the PC to its console, use @code{tip} or @code{cu}
+once again, after your @value{GDBN} session has concluded, to attach to
+@code{EBMON}. You can then type the command @code{q} to shut down
+@code{EBMON}, returning control to the DOS command-line interpreter.
+Type @code{CTTY con} to return command input to the main DOS console,
+and type @kbd{~.} to leave @code{tip} or @code{cu}.
+
+@node Remote Log
+@subsubsection Remote log
+@kindex eb.log
+@cindex log file for EB29K
+
+The @code{target amd-eb} command creates a file @file{eb.log} in the
+current working directory, to help debug problems with the connection.
+@file{eb.log} records all the output from @code{EBMON}, including echoes
+of the commands sent to it. Running @samp{tail -f} on this file in
+another window often helps to understand trouble with @code{EBMON}, or
+unexpected events on the PC side of the connection.
+
+@end ifset
+
+@ifset ST2000
+@node ST2000 Remote
+@subsection @value{GDBN} with a Tandem ST2000
+
+To connect your ST2000 to the host system, see the manufacturer's
+manual. Once the ST2000 is physically attached, you can run
+
+@example
+target st2000 @var{dev} @var{speed}
+@end example
+
+@noindent
+to establish it as your debugging environment. @var{dev} is normally
+the name of a serial device, such as @file{/dev/ttya}, connected to the
+ST2000 via a serial line. You can instead specify @var{dev} as a TCP
+connection (for example, to a serial line attached via a terminal
+concentrator) using the syntax @code{@var{hostname}:@var{portnumber}}.
+
+The @code{load} and @code{attach} commands are @emph{not} defined for
+this target; you must load your program into the ST2000 as you normally
+would for standalone operation. @value{GDBN} reads debugging information
+(such as symbols) from a separate, debugging version of the program
+available on your host computer.
+@c FIXME!! This is terribly vague; what little content is here is
+@c basically hearsay.
+
+@cindex ST2000 auxiliary commands
+These auxiliary @value{GDBN} commands are available to help you with the ST2000
+environment:
+
+@table @code
+@item st2000 @var{command}
+@kindex st2000 @var{cmd}
+@cindex STDBUG commands (ST2000)
+@cindex commands to STDBUG (ST2000)
+Send a @var{command} to the STDBUG monitor. See the manufacturer's
+manual for available commands.
+
+@item connect
+@cindex connect (to STDBUG)
+Connect the controlling terminal to the STDBUG command monitor. When
+you are done interacting with STDBUG, typing either of two character
+sequences gets you back to the @value{GDBN} command prompt:
+@kbd{@key{RET}~.} (Return, followed by tilde and period) or
+@kbd{@key{RET}~@key{C-d}} (Return, followed by tilde and control-D).
+@end table
+@end ifset
+
+@ifset VXWORKS
+@node VxWorks Remote
+@subsection @value{GDBN} and VxWorks
+@cindex VxWorks
+
+@value{GDBN} enables developers to spawn and debug tasks running on networked
+VxWorks targets from a Unix host. Already-running tasks spawned from
+the VxWorks shell can also be debugged. @value{GDBN} uses code that runs on
+both the Unix host and on the VxWorks target. The program
+@code{gdb} is installed and executed on the Unix host. (It may be
+installed with the name @code{vxgdb}, to distinguish it from a
+@value{GDBN} for debugging programs on the host itself.)
+
+The following information on connecting to VxWorks was current when
+this manual was produced; newer releases of VxWorks may use revised
+procedures.
+
+@kindex INCLUDE_RDB
+To use @value{GDBN} with VxWorks, you must rebuild your VxWorks kernel
+to include the remote debugging interface routines in the VxWorks
+library @file{rdb.a}. To do this, define @code{INCLUDE_RDB} in the
+VxWorks configuration file @file{configAll.h} and rebuild your VxWorks
+kernel. The resulting kernel contains @file{rdb.a}, and spawns the
+source debugging task @code{tRdbTask} when VxWorks is booted. For more
+information on configuring and remaking VxWorks, see the manufacturer's
+manual.
+@c VxWorks, see the @cite{VxWorks Programmer's Guide}.
+
+Once you have included @file{rdb.a} in your VxWorks system image and set
+your Unix execution search path to find @value{GDBN}, you are ready to
+run @value{GDBN}. From your Unix host, run @code{gdb} (or @code{vxgdb},
+depending on your installation).
+
+@value{GDBN} comes up showing the prompt:
+
+@example
+(vxgdb)
+@end example
+
+@menu
+* VxWorks Connection:: Connecting to VxWorks
+* VxWorks Download:: VxWorks download
+* VxWorks Attach:: Running tasks
+@end menu
+
+@node VxWorks Connection
+@subsubsection Connecting to VxWorks
+
+The @value{GDBN} command @code{target} lets you connect to a VxWorks target on the
+network. To connect to a target whose host name is ``@code{tt}'', type:
+
+@example
+(vxgdb) target vxworks tt
+@end example
+
+@need 750
+@value{GDBN} displays messages like these:
+
+@smallexample
+Attaching remote machine across net...
+Connected to tt.
+@end smallexample
+
+@need 1000
+@value{GDBN} then attempts to read the symbol tables of any object modules
+loaded into the VxWorks target since it was last booted. @value{GDBN} locates
+these files by searching the directories listed in the command search
+path (@pxref{Environment, ,Your program's environment}); if it fails
+to find an object file, it displays a message such as:
+
+@example
+prog.o: No such file or directory.
+@end example
+
+When this happens, add the appropriate directory to the search path with
+the @value{GDBN} command @code{path}, and execute the @code{target}
+command again.
+
+@node VxWorks Download
+@subsubsection VxWorks download
+
+@cindex download to VxWorks
+If you have connected to the VxWorks target and you want to debug an
+object that has not yet been loaded, you can use the @value{GDBN}
+@code{load} command to download a file from Unix to VxWorks
+incrementally. The object file given as an argument to the @code{load}
+command is actually opened twice: first by the VxWorks target in order
+to download the code, then by @value{GDBN} in order to read the symbol
+table. This can lead to problems if the current working directories on
+the two systems differ. If both systems have NFS mounted the same
+filesystems, you can avoid these problems by using absolute paths.
+Otherwise, it is simplest to set the working directory on both systems
+to the directory in which the object file resides, and then to reference
+the file by its name, without any path. For instance, a program
+@file{prog.o} may reside in @file{@var{vxpath}/vw/demo/rdb} in VxWorks
+and in @file{@var{hostpath}/vw/demo/rdb} on the host. To load this
+program, type this on VxWorks:
+
+@example
+-> cd "@var{vxpath}/vw/demo/rdb"
+@end example
+
+Then, in @value{GDBN}, type:
+
+@example
+(vxgdb) cd @var{hostpath}/vw/demo/rdb
+(vxgdb) load prog.o
+@end example
+
+@value{GDBN} displays a response similar to this:
+
+@smallexample
+Reading symbol data from wherever/vw/demo/rdb/prog.o... done.
+@end smallexample
+
+You can also use the @code{load} command to reload an object module
+after editing and recompiling the corresponding source file. Note that
+this makes @value{GDBN} delete all currently-defined breakpoints,
+auto-displays, and convenience variables, and to clear the value
+history. (This is necessary in order to preserve the integrity of
+debugger data structures that reference the target system's symbol
+table.)
+
+@node VxWorks Attach
+@subsubsection Running tasks
+
+@cindex running VxWorks tasks
+You can also attach to an existing task using the @code{attach} command as
+follows:
+
+@example
+(vxgdb) attach @var{task}
+@end example
+
+@noindent
+where @var{task} is the VxWorks hexadecimal task ID. The task can be running
+or suspended when you attach to it. Running tasks are suspended at
+the time of attachment.
+@end ifset
+
+@ifset H8
+@node Hitachi Remote
+@subsection @value{GDBN} and Hitachi microprocessors
+@value{GDBN} needs to know these things to talk to your
+Hitachi SH, H8/300, or H8/500:
+
+@enumerate
+@item
+that you want to use @samp{target hms}, the remote debugging interface
+for Hitachi microprocessors, or @samp{target e7000}, the in-circuit
+emulator for the Hitachi SH and the Hitachi 300H. (@samp{target hms} is
+the default when GDB is configured specifically for the Hitachi SH,
+H8/300, or H8/500.)
+
+@item
+what serial device connects your host to your Hitachi board (the first
+serial device available on your host is the default).
+
+@ifclear H8EXCLUSIVE
+@c this is only for Unix hosts, not of interest to Hitachi
+@item
+what speed to use over the serial device.
+@end ifclear
+@end enumerate
+
+@menu
+* Hitachi Boards:: Connecting to Hitachi boards.
+* Hitachi ICE:: Using the E7000 In-Circuit Emulator.
+* Hitachi Special:: Special @value{GDBN} commands for Hitachi micros.
+@end menu
+
+@node Hitachi Boards
+@subsubsection Connecting to Hitachi boards
+
+@ifclear H8EXCLUSIVE
+@c only for Unix hosts
+@kindex device
+@cindex serial device, Hitachi micros
+Use the special @code{@value{GDBP}} command @samp{device @var{port}} if you
+need to explicitly set the serial device. The default @var{port} is the
+first available port on your host. This is only necessary on Unix
+hosts, where it is typically something like @file{/dev/ttya}.
+
+@kindex speed
+@cindex serial line speed, Hitachi micros
+@code{@value{GDBP}} has another special command to set the communications
+speed: @samp{speed @var{bps}}. This command also is only used from Unix
+hosts; on DOS hosts, set the line speed as usual from outside GDB with
+the DOS @kbd{mode} command (for instance, @w{@samp{mode
+com2:9600,n,8,1,p}} for a 9600 bps connection).
+
+The @samp{device} and @samp{speed} commands are available only when you
+use a Unix host to debug your Hitachi microprocessor programs. If you
+use a DOS host,
+@end ifclear
+@value{GDBN} depends on an auxiliary terminate-and-stay-resident program
+called @code{asynctsr} to communicate with the development board
+through a PC serial port. You must also use the DOS @code{mode} command
+to set up the serial port on the DOS side.
+
+@ifset DOSHOST
+The following sample session illustrates the steps needed to start a
+program under @value{GDBN} control on an H8/300. The example uses a
+sample H8/300 program called @file{t.x}. The procedure is the same for
+the Hitachi SH and the H8/500.
+
+First hook up your development board. In this example, we use a
+board attached to serial port @code{COM2}; if you use a different serial
+port, substitute its name in the argument of the @code{mode} command.
+When you call @code{asynctsr}, the auxiliary comms program used by the
+degugger, you give it just the numeric part of the serial port's name;
+for example, @samp{asyncstr 2} below runs @code{asyncstr} on
+@code{COM2}.
+
+@example
+(eg-C:\H8300\TEST) mode com2:9600,n,8,1,p
+
+Resident portion of MODE loaded
+
+COM2: 9600, n, 8, 1, p
+
+(eg-C:\H8300\TEST) asynctsr 2
+@end example
+
+@quotation
+@emph{Warning:} We have noticed a bug in PC-NFS that conflicts with
+@code{asynctsr}. If you also run PC-NFS on your DOS host, you may need to
+disable it, or even boot without it, to use @code{asynctsr} to control
+your development board.
+@end quotation
+
+@kindex target hms
+Now that serial communications are set up, and the development board is
+connected, you can start up @value{GDBN}. Call @code{@value{GDBP}} with
+the name of your program as the argument. @code{@value{GDBP}} prompts
+you, as usual, with the prompt @samp{(@value{GDBP})}. Use two special
+commands to begin your debugging session: @samp{target hms} to specify
+cross-debugging to the Hitachi board, and the @code{load} command to
+download your program to the board. @code{load} displays the names of
+the program's sections, and a @samp{*} for each 2K of data downloaded.
+(If you want to refresh @value{GDBN} data on symbols or on the
+executable file without downloading, use the @value{GDBN} commands
+@code{file} or @code{symbol-file}. These commands, and @code{load}
+itself, are described in @ref{Files,,Commands to specify files}.)
+
+@smallexample
+(eg-C:\H8300\TEST) @value{GDBP} t.x
+GDB is free software and you are welcome to distribute copies
+ of it under certain conditions; type "show copying" to see
+ the conditions.
+There is absolutely no warranty for GDB; type "show warranty"
+for details.
+GDB @value{GDBVN}, Copyright 1992 Free Software Foundation, Inc...
+(gdb) target hms
+Connected to remote H8/300 HMS system.
+(gdb) load t.x
+.text : 0x8000 .. 0xabde ***********
+.data : 0xabde .. 0xad30 *
+.stack : 0xf000 .. 0xf014 *
+@end smallexample
+
+At this point, you're ready to run or debug your program. From here on,
+you can use all the usual @value{GDBN} commands. The @code{break} command
+sets breakpoints; the @code{run} command starts your program;
+@code{print} or @code{x} display data; the @code{continue} command
+resumes execution after stopping at a breakpoint. You can use the
+@code{help} command at any time to find out more about @value{GDBN} commands.
+
+Remember, however, that @emph{operating system} facilities aren't
+available on your development board; for example, if your program hangs,
+you can't send an interrupt---but you can press the @sc{reset} switch!
+
+Use the @sc{reset} button on the development board
+@itemize @bullet
+@item
+to interrupt your program (don't use @kbd{ctl-C} on the DOS host---it has
+no way to pass an interrupt signal to the development board); and
+
+@item
+to return to the @value{GDBN} command prompt after your program finishes
+normally. The communications protocol provides no other way for @value{GDBN}
+to detect program completion.
+@end itemize
+
+In either case, @value{GDBN} sees the effect of a @sc{reset} on the
+development board as a ``normal exit'' of your program.
+@end ifset
+
+@node Hitachi ICE
+@subsubsection Using the E7000 in-circuit emulator
+
+@kindex target e7000
+You can use the E7000 in-circuit emulator to develop code for either the
+Hitachi SH or the H8/300H. Use one of these forms of the @samp{target
+e7000} command to connect @value{GDBN} to your E7000:
+
+@table @code
+@item target e7000 @var{port} @var{speed}
+Use this form if your E7000 is connected to a serial port. The
+@var{port} argument identifies what serial port to use (for example,
+@samp{com2}). The third argument is the line speed in bits per second
+(for example, @samp{9600}).
+
+@item target e7000 @var{hostname}
+If your E7000 is installed as a host on a TCP/IP network, you can just
+specify its hostname; @value{GDBN} uses @code{telnet} to connect.
+@end table
+
+@node Hitachi Special
+@subsubsection Special @value{GDBN} commands for Hitachi micros
+
+Some @value{GDBN} commands are available only on the H8/300 or the
+H8/500 configurations:
+
+@table @code
+@kindex set machine
+@kindex show machine
+@item set machine h8300
+@itemx set machine h8300h
+Condition @value{GDBN} for one of the two variants of the H8/300
+architecture with @samp{set machine}. You can use @samp{show machine}
+to check which variant is currently in effect.
+
+@kindex set memory @var{mod}
+@cindex memory models, H8/500
+@item set memory @var{mod}
+@itemx show memory
+Specify which H8/500 memory model (@var{mod}) you are using with
+@samp{set memory}; check which memory model is in effect with @samp{show
+memory}. The accepted values for @var{mod} are @code{small},
+@code{big}, @code{medium}, and @code{compact}.
+@end table
+
+@end ifset
+
+@ifset MIPS
+@node MIPS Remote
+@subsection @value{GDBN} and remote MIPS boards
+
+@cindex MIPS boards
+@value{GDBN} can use the MIPS remote debugging protocol to talk to a
+MIPS board attached to a serial line. This is available when
+you configure @value{GDBN} with @samp{--target=mips-idt-ecoff}.
+
+@need 1000
+Use these @value{GDBN} commands to specify the connection to your target board:
+
+@table @code
+@item target mips @var{port}
+@kindex target mips @var{port}
+To run a program on the board, start up @code{@value{GDBP}} with the
+name of your program as the argument. To connect to the board, use the
+command @samp{target mips @var{port}}, where @var{port} is the name of
+the serial port connected to the board. If the program has not already
+been downloaded to the board, you may use the @code{load} command to
+download it. You can then use all the usual @value{GDBN} commands.
+
+For example, this sequence connects to the target board through a serial
+port, and loads and runs a program called @var{prog} through the
+debugger:
+
+@example
+host$ @value{GDBP} @var{prog}
+GDB is free software and @dots{}
+(gdb) target mips /dev/ttyb
+(gdb) load @var{prog}
+(gdb) run
+@end example
+
+@item target mips @var{hostname}:@var{portnumber}
+On some @value{GDBN} host configurations, you can specify a TCP
+connection (for instance, to a serial line managed by a terminal
+concentrator) instead of a serial port, using the syntax
+@samp{@var{hostname}:@var{portnumber}}.
+@end table
+
+@noindent
+@value{GDBN} also supports these special commands for MIPS targets:
+
+@table @code
+@item set mipsfpu off
+@itemx show mipsfpu
+@kindex set mipsfpu off
+@kindex show mipsfpu
+@cindex MIPS remote floating point
+@cindex floating point, MIPS remote
+If your target board does not support the MIPS floating point
+coprocessor, you should use the command @samp{set mipsfpu off} (if you
+need this, you may wish to put the command in your @value{GDBINIT}
+file). This tells @value{GDBN} how to find the return value of
+functions which return floating point values. It also allows
+@value{GDBN} to avoid saving the floating point registers when calling
+functions on the board. (As usual, you can inquire about the
+@code{mipsfpu} variable with @samp{show mipsfpu}.)
+
+@item set remotedebug @var{n}
+@itemx show remotedebug
+@kindex set remotedebug
+@kindex show remotedebug
+@cindex @code{remotedebug}, MIPS protocol
+@cindex MIPS @code{remotedebug} protocol
+@c FIXME! For this to be useful, you must know something about the MIPS
+@c FIXME...protocol. Where is it described?
+You can see some debugging information about communications with the board
+by setting the @code{remotedebug} variable. If you set it to @code{1} using
+@samp{set remotedebug 1}, every packet is displayed. If you set it
+to @code{2}, every character is displayed. You can check the current value
+at any time with the command @samp{show remotedebug}.
+
+@item set timeout @var{seconds}
+@itemx set retransmit-timeout @var{seconds}
+@itemx show timeout
+@itemx show retransmit-timeout
+@cindex @code{timeout}, MIPS protocol
+@cindex @code{retransmit-timeout}, MIPS protocol
+@kindex set timeout
+@kindex show timeout
+@kindex set retransmit-timeout
+@kindex show retransmit-timeout
+You can control the timeout used while waiting for a packet, in the MIPS
+remote protocol, with the @code{set timeout @var{seconds}} command. The
+default is 5 seconds. Similarly, you can control the timeout used while
+waiting for an acknowledgement of a packet with the @code{set
+retransmit-timeout @var{seconds}} command. The default is 3 seconds.
+You can inspect both values with @code{show timeout} and @code{show
+retransmit-timeout}. (These commands are @emph{only} available when
+@value{GDBN} is configured for @samp{--target=mips-idt-ecoff}.)
+
+The timeout set by @code{set timeout} does not apply when @value{GDBN}
+is waiting for your program to stop. In that case, @value{GDBN} waits
+forever because it has no way of knowing how long the program is going
+to run before stopping.
+@end table
+@end ifset
+
+@ifset SIMS
+@node Simulator
+@subsection Simulated CPU target
+
+@ifset GENERIC
+@cindex simulator
+@cindex simulator, Z8000
+@cindex Z8000 simulator
+@cindex simulator, H8/300 or H8/500
+@cindex H8/300 or H8/500 simulator
+@cindex simulator, Hitachi SH
+@cindex Hitachi SH simulator
+@cindex CPU simulator
+For some configurations, @value{GDBN} includes a CPU simulator that you
+can use instead of a hardware CPU to debug your programs. Currently,
+a simulator is available when @value{GDBN} is configured to debug Zilog
+Z8000 or Hitachi microprocessor targets.
+@end ifset
+
+@ifclear GENERIC
+@ifset H8
+@cindex simulator, H8/300 or H8/500
+@cindex Hitachi H8/300 or H8/500 simulator
+@cindex simulator, Hitachi SH
+@cindex Hitachi SH simulator
+When configured for debugging Hitachi microprocessor targets,
+@value{GDBN} includes a CPU simulator for the target chip (a Hitachi SH,
+H8/300, or H8/500).
+@end ifset
+
+@ifset Z8K
+@cindex simulator, Z8000
+@cindex Zilog Z8000 simulator
+When configured for debugging Zilog Z8000 targets, @value{GDBN} includes
+a Z8000 simulator.
+@end ifset
+@end ifclear
+
+@ifset Z8K
+For the Z8000 family, @samp{target sim} simulates either the Z8002 (the
+unsegmented variant of the Z8000 architecture) or the Z8001 (the
+segmented variant). The simulator recognizes which architecture is
+appropriate by inspecting the object code.
+@end ifset
+
+@table @code
+@item target sim
+@kindex sim
+@kindex target sim
+Debug programs on a simulated CPU
+@ifset GENERIC
+(which CPU depends on the @value{GDBN} configuration)
+@end ifset
+@end table
+
+@noindent
+After specifying this target, you can debug programs for the simulated
+CPU in the same style as programs for your host computer; use the
+@code{file} command to load a new program image, the @code{run} command
+to run your program, and so on.
+
+As well as making available all the usual machine registers (see
+@code{info reg}), this debugging target provides three additional items
+of information as specially named registers:
+
+@table @code
+@item cycles
+Counts clock-ticks in the simulator.
+
+@item insts
+Counts instructions run in the simulator.
+
+@item time
+Execution time in 60ths of a second.
+@end table
+
+You can refer to these values in @value{GDBN} expressions with the usual
+conventions; for example, @w{@samp{b fputc if $cycles>5000}} sets a
+conditional breakpoint that suspends only after at least 5000
+simulated clock ticks.
+@end ifset
diff --git a/gnu/usr.bin/gdb/doc/stabs.texinfo b/gnu/usr.bin/gdb/doc/stabs.texinfo
new file mode 100644
index 0000000..1c8d407
--- /dev/null
+++ b/gnu/usr.bin/gdb/doc/stabs.texinfo
@@ -0,0 +1,4035 @@
+\input texinfo
+@setfilename stabs.info
+
+@c @finalout
+
+@ifinfo
+@format
+START-INFO-DIR-ENTRY
+* Stabs: (stabs). The "stabs" debugging information format.
+END-INFO-DIR-ENTRY
+@end format
+@end ifinfo
+
+@ifinfo
+This document describes the stabs debugging symbol tables.
+
+Copyright 1992, 1993 Free Software Foundation, Inc.
+Contributed by Cygnus Support. Written by Julia Menapace, Jim Kingdon,
+and David MacKenzie.
+
+Permission is granted to make and distribute verbatim copies of
+this manual provided the copyright notice and this permission notice
+are preserved on all copies.
+
+@ignore
+Permission is granted to process this file through Tex and print the
+results, provided the printed document carries copying permission
+notice identical to this one except for the removal of this paragraph
+(this paragraph not being relevant to the printed manual).
+
+@end ignore
+Permission is granted to copy or distribute modified versions of this
+manual under the terms of the GPL (for which purpose this text may be
+regarded as a program in the language TeX).
+@end ifinfo
+
+@setchapternewpage odd
+@settitle STABS
+@titlepage
+@title The ``stabs'' debug format
+@author Julia Menapace, Jim Kingdon, David MacKenzie
+@author Cygnus Support
+@page
+@tex
+\def\$#1${{#1}} % Kluge: collect RCS revision info without $...$
+\xdef\manvers{\$Revision: 2.120 $} % For use in headers, footers too
+{\parskip=0pt
+\hfill Cygnus Support\par
+\hfill \manvers\par
+\hfill \TeX{}info \texinfoversion\par
+}
+@end tex
+
+@vskip 0pt plus 1filll
+Copyright @copyright{} 1992, 1993 Free Software Foundation, Inc.
+Contributed by Cygnus Support.
+
+Permission is granted to make and distribute verbatim copies of
+this manual provided the copyright notice and this permission notice
+are preserved on all copies.
+
+@end titlepage
+
+@ifinfo
+@node Top
+@top The "stabs" representation of debugging information
+
+This document describes the stabs debugging format.
+
+@menu
+* Overview:: Overview of stabs
+* Program Structure:: Encoding of the structure of the program
+* Constants:: Constants
+* Variables::
+* Types:: Type definitions
+* Symbol Tables:: Symbol information in symbol tables
+* Cplusplus:: Appendixes:
+* Stab Types:: Symbol types in a.out files
+* Symbol Descriptors:: Table of symbol descriptors
+* Type Descriptors:: Table of type descriptors
+* Expanded Reference:: Reference information by stab type
+* Questions:: Questions and anomolies
+* XCOFF Differences:: Differences between GNU stabs in a.out
+ and GNU stabs in XCOFF
+* Sun Differences:: Differences between GNU stabs and Sun
+ native stabs
+* Stab Sections:: In some object file formats, stabs are
+ in sections.
+* Symbol Types Index:: Index of symbolic stab symbol type names.
+@end menu
+@end ifinfo
+
+
+@node Overview
+@chapter Overview of Stabs
+
+@dfn{Stabs} refers to a format for information that describes a program
+to a debugger. This format was apparently invented by
+Peter Kessler at
+the University of California at Berkeley, for the @code{pdx} Pascal
+debugger; the format has spread widely since then.
+
+This document is one of the few published sources of documentation on
+stabs. It is believed to be comprehensive for stabs used by C. The
+lists of symbol descriptors (@pxref{Symbol Descriptors}) and type
+descriptors (@pxref{Type Descriptors}) are believed to be completely
+comprehensive. Stabs for COBOL-specific features and for variant
+records (used by Pascal and Modula-2) are poorly documented here.
+
+@c FIXME: Need to document all OS9000 stuff in GDB; see all references
+@c to os9k_stabs in stabsread.c.
+
+Other sources of information on stabs are @cite{Dbx and Dbxtool
+Interfaces}, 2nd edition, by Sun, 1988, and @cite{AIX Version 3.2 Files
+Reference}, Fourth Edition, September 1992, "dbx Stabstring Grammar" in
+the a.out section, page 2-31. This document is believed to incorporate
+the information from those two sources except where it explicitly directs
+you to them for more information.
+
+@menu
+* Flow:: Overview of debugging information flow
+* Stabs Format:: Overview of stab format
+* String Field:: The string field
+* C Example:: A simple example in C source
+* Assembly Code:: The simple example at the assembly level
+@end menu
+
+@node Flow
+@section Overview of Debugging Information Flow
+
+The GNU C compiler compiles C source in a @file{.c} file into assembly
+language in a @file{.s} file, which the assembler translates into
+a @file{.o} file, which the linker combines with other @file{.o} files and
+libraries to produce an executable file.
+
+With the @samp{-g} option, GCC puts in the @file{.s} file additional
+debugging information, which is slightly transformed by the assembler
+and linker, and carried through into the final executable. This
+debugging information describes features of the source file like line
+numbers, the types and scopes of variables, and function names,
+parameters, and scopes.
+
+For some object file formats, the debugging information is encapsulated
+in assembler directives known collectively as @dfn{stab} (symbol table)
+directives, which are interspersed with the generated code. Stabs are
+the native format for debugging information in the a.out and XCOFF
+object file formats. The GNU tools can also emit stabs in the COFF and
+ECOFF object file formats.
+
+The assembler adds the information from stabs to the symbol information
+it places by default in the symbol table and the string table of the
+@file{.o} file it is building. The linker consolidates the @file{.o}
+files into one executable file, with one symbol table and one string
+table. Debuggers use the symbol and string tables in the executable as
+a source of debugging information about the program.
+
+@node Stabs Format
+@section Overview of Stab Format
+
+There are three overall formats for stab assembler directives,
+differentiated by the first word of the stab. The name of the directive
+describes which combination of four possible data fields follows. It is
+either @code{.stabs} (string), @code{.stabn} (number), or @code{.stabd}
+(dot). IBM's XCOFF assembler uses @code{.stabx} (and some other
+directives such as @code{.file} and @code{.bi}) instead of
+@code{.stabs}, @code{.stabn} or @code{.stabd}.
+
+The overall format of each class of stab is:
+
+@example
+.stabs "@var{string}",@var{type},@var{other},@var{desc},@var{value}
+.stabn @var{type},@var{other},@var{desc},@var{value}
+.stabd @var{type},@var{other},@var{desc}
+.stabx "@var{string}",@var{value},@var{type},@var{sdb-type}
+@end example
+
+@c what is the correct term for "current file location"? My AIX
+@c assembler manual calls it "the value of the current location counter".
+For @code{.stabn} and @code{.stabd}, there is no @var{string} (the
+@code{n_strx} field is zero; see @ref{Symbol Tables}). For
+@code{.stabd}, the @var{value} field is implicit and has the value of
+the current file location. For @code{.stabx}, the @var{sdb-type} field
+is unused for stabs and can always be set to zero. The @var{other}
+field is almost always unused and can be set to zero.
+
+The number in the @var{type} field gives some basic information about
+which type of stab this is (or whether it @emph{is} a stab, as opposed
+to an ordinary symbol). Each valid type number defines a different stab
+type; further, the stab type defines the exact interpretation of, and
+possible values for, any remaining @var{string}, @var{desc}, or
+@var{value} fields present in the stab. @xref{Stab Types}, for a list
+in numeric order of the valid @var{type} field values for stab directives.
+
+@node String Field
+@section The String Field
+
+For most stabs the string field holds the meat of the
+debugging information. The flexible nature of this field
+is what makes stabs extensible. For some stab types the string field
+contains only a name. For other stab types the contents can be a great
+deal more complex.
+
+The overall format of the string field for most stab types is:
+
+@example
+"@var{name}:@var{symbol-descriptor} @var{type-information}"
+@end example
+
+@var{name} is the name of the symbol represented by the stab; it can
+contain a pair of colons (@pxref{Nested Symbols}). @var{name} can be
+omitted, which means the stab represents an unnamed object. For
+example, @samp{:t10=*2} defines type 10 as a pointer to type 2, but does
+not give the type a name. Omitting the @var{name} field is supported by
+AIX dbx and GDB after about version 4.8, but not other debuggers. GCC
+sometimes uses a single space as the name instead of omitting the name
+altogether; apparently that is supported by most debuggers.
+
+The @var{symbol-descriptor} following the @samp{:} is an alphabetic
+character that tells more specifically what kind of symbol the stab
+represents. If the @var{symbol-descriptor} is omitted, but type
+information follows, then the stab represents a local variable. For a
+list of symbol descriptors, see @ref{Symbol Descriptors}. The @samp{c}
+symbol descriptor is an exception in that it is not followed by type
+information. @xref{Constants}.
+
+@var{type-information} is either a @var{type-number}, or
+@samp{@var{type-number}=}. A @var{type-number} alone is a type
+reference, referring directly to a type that has already been defined.
+
+The @samp{@var{type-number}=} form is a type definition, where the
+number represents a new type which is about to be defined. The type
+definition may refer to other types by number, and those type numbers
+may be followed by @samp{=} and nested definitions. Also, the Lucid
+compiler will repeat @samp{@var{type-number}=} more than once if it
+wants to define several type numbers at once.
+
+In a type definition, if the character that follows the equals sign is
+non-numeric then it is a @var{type-descriptor}, and tells what kind of
+type is about to be defined. Any other values following the
+@var{type-descriptor} vary, depending on the @var{type-descriptor}.
+@xref{Type Descriptors}, for a list of @var{type-descriptor} values. If
+a number follows the @samp{=} then the number is a @var{type-reference}.
+For a full description of types, @ref{Types}.
+
+There is an AIX extension for type attributes. Following the @samp{=}
+are any number of type attributes. Each one starts with @samp{@@} and
+ends with @samp{;}. Debuggers, including AIX's dbx and GDB 4.10, skip
+any type attributes they do not recognize. GDB 4.9 and other versions
+of dbx may not do this. Because of a conflict with C++
+(@pxref{Cplusplus}), new attributes should not be defined which begin
+with a digit, @samp{(}, or @samp{-}; GDB may be unable to distinguish
+those from the C++ type descriptor @samp{@@}. The attributes are:
+
+@table @code
+@item a@var{boundary}
+@var{boundary} is an integer specifying the alignment. I assume it
+applies to all variables of this type.
+
+@item p@var{integer}
+Pointer class (for checking). Not sure what this means, or how
+@var{integer} is interpreted.
+
+@item P
+Indicate this is a packed type, meaning that structure fields or array
+elements are placed more closely in memory, to save memory at the
+expense of speed.
+
+@item s@var{size}
+Size in bits of a variable of this type. This is fully supported by GDB
+4.11 and later.
+
+@item S
+Indicate that this type is a string instead of an array of characters,
+or a bitstring instead of a set. It doesn't change the layout of the
+data being represented, but does enable the debugger to know which type
+it is.
+@end table
+
+All of this can make the string field quite long. All versions of GDB,
+and some versions of dbx, can handle arbitrarily long strings. But many
+versions of dbx (or assemblers or linkers, I'm not sure which)
+cretinously limit the strings to about 80 characters, so compilers which
+must work with such systems need to split the @code{.stabs} directive
+into several @code{.stabs} directives. Each stab duplicates every field
+except the string field. The string field of every stab except the last
+is marked as continued with a backslash at the end (in the assembly code
+this may be written as a double backslash, depending on the assembler).
+Removing the backslashes and concatenating the string fields of each
+stab produces the original, long string. Just to be incompatible (or so
+they don't have to worry about what the assembler does with
+backslashes), AIX can use @samp{?} instead of backslash.
+
+@node C Example
+@section A Simple Example in C Source
+
+To get the flavor of how stabs describe source information for a C
+program, let's look at the simple program:
+
+@example
+main()
+@{
+ printf("Hello world");
+@}
+@end example
+
+When compiled with @samp{-g}, the program above yields the following
+@file{.s} file. Line numbers have been added to make it easier to refer
+to parts of the @file{.s} file in the description of the stabs that
+follows.
+
+@node Assembly Code
+@section The Simple Example at the Assembly Level
+
+This simple ``hello world'' example demonstrates several of the stab
+types used to describe C language source files.
+
+@example
+1 gcc2_compiled.:
+2 .stabs "/cygint/s1/users/jcm/play/",100,0,0,Ltext0
+3 .stabs "hello.c",100,0,0,Ltext0
+4 .text
+5 Ltext0:
+6 .stabs "int:t1=r1;-2147483648;2147483647;",128,0,0,0
+7 .stabs "char:t2=r2;0;127;",128,0,0,0
+8 .stabs "long int:t3=r1;-2147483648;2147483647;",128,0,0,0
+9 .stabs "unsigned int:t4=r1;0;-1;",128,0,0,0
+10 .stabs "long unsigned int:t5=r1;0;-1;",128,0,0,0
+11 .stabs "short int:t6=r1;-32768;32767;",128,0,0,0
+12 .stabs "long long int:t7=r1;0;-1;",128,0,0,0
+13 .stabs "short unsigned int:t8=r1;0;65535;",128,0,0,0
+14 .stabs "long long unsigned int:t9=r1;0;-1;",128,0,0,0
+15 .stabs "signed char:t10=r1;-128;127;",128,0,0,0
+16 .stabs "unsigned char:t11=r1;0;255;",128,0,0,0
+17 .stabs "float:t12=r1;4;0;",128,0,0,0
+18 .stabs "double:t13=r1;8;0;",128,0,0,0
+19 .stabs "long double:t14=r1;8;0;",128,0,0,0
+20 .stabs "void:t15=15",128,0,0,0
+21 .align 4
+22 LC0:
+23 .ascii "Hello, world!\12\0"
+24 .align 4
+25 .global _main
+26 .proc 1
+27 _main:
+28 .stabn 68,0,4,LM1
+29 LM1:
+30 !#PROLOGUE# 0
+31 save %sp,-136,%sp
+32 !#PROLOGUE# 1
+33 call ___main,0
+34 nop
+35 .stabn 68,0,5,LM2
+36 LM2:
+37 LBB2:
+38 sethi %hi(LC0),%o1
+39 or %o1,%lo(LC0),%o0
+40 call _printf,0
+41 nop
+42 .stabn 68,0,6,LM3
+43 LM3:
+44 LBE2:
+45 .stabn 68,0,6,LM4
+46 LM4:
+47 L1:
+48 ret
+49 restore
+50 .stabs "main:F1",36,0,0,_main
+51 .stabn 192,0,0,LBB2
+52 .stabn 224,0,0,LBE2
+@end example
+
+@node Program Structure
+@chapter Encoding the Structure of the Program
+
+The elements of the program structure that stabs encode include the name
+of the main function, the names of the source and include files, the
+line numbers, procedure names and types, and the beginnings and ends of
+blocks of code.
+
+@menu
+* Main Program:: Indicate what the main program is
+* Source Files:: The path and name of the source file
+* Include Files:: Names of include files
+* Line Numbers::
+* Procedures::
+* Nested Procedures::
+* Block Structure::
+* Alternate Entry Points:: Entering procedures except at the beginning.
+@end menu
+
+@node Main Program
+@section Main Program
+
+@findex N_MAIN
+Most languages allow the main program to have any name. The
+@code{N_MAIN} stab type tells the debugger the name that is used in this
+program. Only the string field is significant; it is the name of
+a function which is the main program. Most C compilers do not use this
+stab (they expect the debugger to assume that the name is @code{main}),
+but some C compilers emit an @code{N_MAIN} stab for the @code{main}
+function.
+
+@node Source Files
+@section Paths and Names of the Source Files
+
+@findex N_SO
+Before any other stabs occur, there must be a stab specifying the source
+file. This information is contained in a symbol of stab type
+@code{N_SO}; the string field contains the name of the file. The
+value of the symbol is the start address of the portion of the
+text section corresponding to that file.
+
+With the Sun Solaris2 compiler, the desc field contains a
+source-language code.
+@c Do the debuggers use it? What are the codes? -djm
+
+Some compilers (for example, GCC2 and SunOS4 @file{/bin/cc}) also
+include the directory in which the source was compiled, in a second
+@code{N_SO} symbol preceding the one containing the file name. This
+symbol can be distinguished by the fact that it ends in a slash. Code
+from the @code{cfront} C++ compiler can have additional @code{N_SO} symbols for
+nonexistent source files after the @code{N_SO} for the real source file;
+these are believed to contain no useful information.
+
+For example:
+
+@example
+.stabs "/cygint/s1/users/jcm/play/",100,0,0,Ltext0 # @r{100 is N_SO}
+.stabs "hello.c",100,0,0,Ltext0
+ .text
+Ltext0:
+@end example
+
+Instead of @code{N_SO} symbols, XCOFF uses a @code{.file} assembler
+directive which assembles to a standard COFF @code{.file} symbol;
+explaining this in detail is outside the scope of this document.
+
+@node Include Files
+@section Names of Include Files
+
+There are several schemes for dealing with include files: the
+traditional @code{N_SOL} approach, Sun's @code{N_BINCL} approach, and the
+XCOFF @code{C_BINCL} approach (which despite the similar name has little in
+common with @code{N_BINCL}).
+
+@findex N_SOL
+An @code{N_SOL} symbol specifies which include file subsequent symbols
+refer to. The string field is the name of the file and the value is the
+text address corresponding to the end of the previous include file and
+the start of this one. To specify the main source file again, use an
+@code{N_SOL} symbol with the name of the main source file.
+
+@findex N_BINCL
+@findex N_EINCL
+@findex N_EXCL
+The @code{N_BINCL} approach works as follows. An @code{N_BINCL} symbol
+specifies the start of an include file. In an object file, only the
+string is significant; the Sun linker puts data into some of the
+other fields. The end of the include file is marked by an
+@code{N_EINCL} symbol (which has no string field). In an object
+file, there is no significant data in the @code{N_EINCL} symbol; the Sun
+linker puts data into some of the fields. @code{N_BINCL} and
+@code{N_EINCL} can be nested.
+
+If the linker detects that two source files have identical stabs between
+an @code{N_BINCL} and @code{N_EINCL} pair (as will generally be the case
+for a header file), then it only puts out the stabs once. Each
+additional occurance is replaced by an @code{N_EXCL} symbol. I believe
+the Sun (SunOS4, not sure about Solaris) linker is the only one which
+supports this feature.
+@c What do the fields of N_EXCL contain? -djm
+
+@findex C_BINCL
+@findex C_EINCL
+For the start of an include file in XCOFF, use the @file{.bi} assembler
+directive, which generates a @code{C_BINCL} symbol. A @file{.ei}
+directive, which generates a @code{C_EINCL} symbol, denotes the end of
+the include file. Both directives are followed by the name of the
+source file in quotes, which becomes the string for the symbol.
+The value of each symbol, produced automatically by the assembler
+and linker, is the offset into the executable of the beginning
+(inclusive, as you'd expect) or end (inclusive, as you would not expect)
+of the portion of the COFF line table that corresponds to this include
+file. @code{C_BINCL} and @code{C_EINCL} do not nest.
+
+@node Line Numbers
+@section Line Numbers
+
+@findex N_SLINE
+An @code{N_SLINE} symbol represents the start of a source line. The
+desc field contains the line number and the value contains the code
+address for the start of that source line. On most machines the address
+is absolute; for stabs in sections (@pxref{Stab Sections}), it is
+relative to the function in which the @code{N_SLINE} symbol occurs.
+
+@findex N_DSLINE
+@findex N_BSLINE
+GNU documents @code{N_DSLINE} and @code{N_BSLINE} symbols for line
+numbers in the data or bss segments, respectively. They are identical
+to @code{N_SLINE} but are relocated differently by the linker. They
+were intended to be used to describe the source location of a variable
+declaration, but I believe that GCC2 actually puts the line number in
+the desc field of the stab for the variable itself. GDB has been
+ignoring these symbols (unless they contain a string field) since
+at least GDB 3.5.
+
+For single source lines that generate discontiguous code, such as flow
+of control statements, there may be more than one line number entry for
+the same source line. In this case there is a line number entry at the
+start of each code range, each with the same line number.
+
+XCOFF does not use stabs for line numbers. Instead, it uses COFF line
+numbers (which are outside the scope of this document). Standard COFF
+line numbers cannot deal with include files, but in XCOFF this is fixed
+with the @code{C_BINCL} method of marking include files (@pxref{Include
+Files}).
+
+@node Procedures
+@section Procedures
+
+@findex N_FUN, for functions
+@findex N_FNAME
+@findex N_STSYM, for functions (Sun acc)
+@findex N_GSYM, for functions (Sun acc)
+All of the following stabs normally use the @code{N_FUN} symbol type.
+However, Sun's @code{acc} compiler on SunOS4 uses @code{N_GSYM} and
+@code{N_STSYM}, which means that the value of the stab for the function
+is useless and the debugger must get the address of the function from
+the non-stab symbols instead. BSD Fortran is said to use @code{N_FNAME}
+with the same restriction; the value of the symbol is not useful (I'm
+not sure it really does use this, because GDB doesn't handle this and no
+one has complained).
+
+A function is represented by an @samp{F} symbol descriptor for a global
+(extern) function, and @samp{f} for a static (local) function. The
+value is the address of the start of the function. For a.out, it
+is already relocated. For stabs in ELF, the SunPRO compiler version
+2.0.1 and GCC put out an address which gets relocated by the linker. In
+a future release SunPRO is planning to put out zero, in which case the
+address can be found from the ELF (non-stab) symbol. Because looking
+things up in the ELF symbols would probably be slow, I'm not sure how to
+find which symbol of that name is the right one, and this doesn't
+provide any way to deal with nested functions, it would probably be
+better to make the value of the stab an address relative to the start of
+the file, or just absolute. See @ref{ELF Linker Relocation} for more
+information on linker relocation of stabs in ELF files.
+
+The type information of the stab represents the return type of the
+function; thus @samp{foo:f5} means that foo is a function returning type
+5. There is no need to try to get the line number of the start of the
+function from the stab for the function; it is in the next
+@code{N_SLINE} symbol.
+
+@c FIXME: verify whether the "I suspect" below is true or not.
+Some compilers (such as Sun's Solaris compiler) support an extension for
+specifying the types of the arguments. I suspect this extension is not
+used for old (non-prototyped) function definitions in C. If the
+extension is in use, the type information of the stab for the function
+is followed by type information for each argument, with each argument
+preceded by @samp{;}. An argument type of 0 means that additional
+arguments are being passed, whose types and number may vary (@samp{...}
+in ANSI C). GDB has tolerated this extension (parsed the syntax, if not
+necessarily used the information) since at least version 4.8; I don't
+know whether all versions of dbx tolerate it. The argument types given
+here are not redundant with the symbols for the formal parameters
+(@pxref{Parameters}); they are the types of the arguments as they are
+passed, before any conversions might take place. For example, if a C
+function which is declared without a prototype takes a @code{float}
+argument, the value is passed as a @code{double} but then converted to a
+@code{float}. Debuggers need to use the types given in the arguments
+when printing values, but when calling the function they need to use the
+types given in the symbol defining the function.
+
+If the return type and types of arguments of a function which is defined
+in another source file are specified (i.e., a function prototype in ANSI
+C), traditionally compilers emit no stab; the only way for the debugger
+to find the information is if the source file where the function is
+defined was also compiled with debugging symbols. As an extension the
+Solaris compiler uses symbol descriptor @samp{P} followed by the return
+type of the function, followed by the arguments, each preceded by
+@samp{;}, as in a stab with symbol descriptor @samp{f} or @samp{F}.
+This use of symbol descriptor @samp{P} can be distinguished from its use
+for register parameters (@pxref{Register Parameters}) by the fact that it has
+symbol type @code{N_FUN}.
+
+The AIX documentation also defines symbol descriptor @samp{J} as an
+internal function. I assume this means a function nested within another
+function. It also says symbol descriptor @samp{m} is a module in
+Modula-2 or extended Pascal.
+
+Procedures (functions which do not return values) are represented as
+functions returning the @code{void} type in C. I don't see why this couldn't
+be used for all languages (inventing a @code{void} type for this purpose if
+necessary), but the AIX documentation defines @samp{I}, @samp{P}, and
+@samp{Q} for internal, global, and static procedures, respectively.
+These symbol descriptors are unusual in that they are not followed by
+type information.
+
+The following example shows a stab for a function @code{main} which
+returns type number @code{1}. The @code{_main} specified for the value
+is a reference to an assembler label which is used to fill in the start
+address of the function.
+
+@example
+.stabs "main:F1",36,0,0,_main # @r{36 is N_FUN}
+@end example
+
+The stab representing a procedure is located immediately following the
+code of the procedure. This stab is in turn directly followed by a
+group of other stabs describing elements of the procedure. These other
+stabs describe the procedure's parameters, its block local variables, and
+its block structure.
+
+@node Nested Procedures
+@section Nested Procedures
+
+For any of the symbol descriptors representing procedures, after the
+symbol descriptor and the type information is optionally a scope
+specifier. This consists of a comma, the name of the procedure, another
+comma, and the name of the enclosing procedure. The first name is local
+to the scope specified, and seems to be redundant with the name of the
+symbol (before the @samp{:}). This feature is used by GCC, and
+presumably Pascal, Modula-2, etc., compilers, for nested functions.
+
+If procedures are nested more than one level deep, only the immediately
+containing scope is specified. For example, this code:
+
+@example
+int
+foo (int x)
+@{
+ int bar (int y)
+ @{
+ int baz (int z)
+ @{
+ return x + y + z;
+ @}
+ return baz (x + 2 * y);
+ @}
+ return x + bar (3 * x);
+@}
+@end example
+
+@noindent
+produces the stabs:
+
+@example
+.stabs "baz:f1,baz,bar",36,0,0,_baz.15 # @r{36 is N_FUN}
+.stabs "bar:f1,bar,foo",36,0,0,_bar.12
+.stabs "foo:F1",36,0,0,_foo
+@end example
+
+@node Block Structure
+@section Block Structure
+
+@findex N_LBRAC
+@findex N_RBRAC
+@c For GCC 2.5.8 or so stabs-in-coff, these are absolute instead of
+@c function relative (as documented below). But GDB has never been able
+@c to deal with that (it had wanted them to be relative to the file, but
+@c I just fixed that (between GDB 4.12 and 4.13)), so it is function
+@c relative just like ELF and SOM and the below documentation.
+The program's block structure is represented by the @code{N_LBRAC} (left
+brace) and the @code{N_RBRAC} (right brace) stab types. The variables
+defined inside a block precede the @code{N_LBRAC} symbol for most
+compilers, including GCC. Other compilers, such as the Convex, Acorn
+RISC machine, and Sun @code{acc} compilers, put the variables after the
+@code{N_LBRAC} symbol. The values of the @code{N_LBRAC} and
+@code{N_RBRAC} symbols are the start and end addresses of the code of
+the block, respectively. For most machines, they are relative to the
+starting address of this source file. For the Gould NP1, they are
+absolute. For stabs in sections (@pxref{Stab Sections}), they are
+relative to the function in which they occur.
+
+The @code{N_LBRAC} and @code{N_RBRAC} stabs that describe the block
+scope of a procedure are located after the @code{N_FUN} stab that
+represents the procedure itself.
+
+Sun documents the desc field of @code{N_LBRAC} and
+@code{N_RBRAC} symbols as containing the nesting level of the block.
+However, dbx seems to not care, and GCC always sets desc to
+zero.
+
+@node Alternate Entry Points
+@section Alternate Entry Points
+
+Some languages, like Fortran, have the ability to enter procedures at
+some place other than the beginning. One can declare an alternate entry
+point. The @code{N_ENTRY} stab is for this; however, the Sun FORTRAN compiler
+doesn't use it. According to AIX documentation, only the name of a
+@code{C_ENTRY} stab is significant; the address of the alternate entry
+point comes from the corresponding external symbol. A previous revision
+of this document said that the value of an @code{N_ENTRY} stab was the
+address of the alternate entry point, but I don't know the source for
+that information.
+
+@node Constants
+@chapter Constants
+
+The @samp{c} symbol descriptor indicates that this stab represents a
+constant. This symbol descriptor is an exception to the general rule
+that symbol descriptors are followed by type information. Instead, it
+is followed by @samp{=} and one of the following:
+
+@table @code
+@item b @var{value}
+Boolean constant. @var{value} is a numeric value; I assume it is 0 for
+false or 1 for true.
+
+@item c @var{value}
+Character constant. @var{value} is the numeric value of the constant.
+
+@item e @var{type-information} , @var{value}
+Constant whose value can be represented as integral.
+@var{type-information} is the type of the constant, as it would appear
+after a symbol descriptor (@pxref{String Field}). @var{value} is the
+numeric value of the constant. GDB 4.9 does not actually get the right
+value if @var{value} does not fit in a host @code{int}, but it does not
+do anything violent, and future debuggers could be extended to accept
+integers of any size (whether unsigned or not). This constant type is
+usually documented as being only for enumeration constants, but GDB has
+never imposed that restriction; I don't know about other debuggers.
+
+@item i @var{value}
+Integer constant. @var{value} is the numeric value. The type is some
+sort of generic integer type (for GDB, a host @code{int}); to specify
+the type explicitly, use @samp{e} instead.
+
+@item r @var{value}
+Real constant. @var{value} is the real value, which can be @samp{INF}
+(optionally preceded by a sign) for infinity, @samp{QNAN} for a quiet
+NaN (not-a-number), or @samp{SNAN} for a signalling NaN. If it is a
+normal number the format is that accepted by the C library function
+@code{atof}.
+
+@item s @var{string}
+String constant. @var{string} is a string enclosed in either @samp{'}
+(in which case @samp{'} characters within the string are represented as
+@samp{\'} or @samp{"} (in which case @samp{"} characters within the
+string are represented as @samp{\"}).
+
+@item S @var{type-information} , @var{elements} , @var{bits} , @var{pattern}
+Set constant. @var{type-information} is the type of the constant, as it
+would appear after a symbol descriptor (@pxref{String Field}).
+@var{elements} is the number of elements in the set (does this means
+how many bits of @var{pattern} are actually used, which would be
+redundant with the type, or perhaps the number of bits set in
+@var{pattern}? I don't get it), @var{bits} is the number of bits in the
+constant (meaning it specifies the length of @var{pattern}, I think),
+and @var{pattern} is a hexadecimal representation of the set. AIX
+documentation refers to a limit of 32 bytes, but I see no reason why
+this limit should exist. This form could probably be used for arbitrary
+constants, not just sets; the only catch is that @var{pattern} should be
+understood to be target, not host, byte order and format.
+@end table
+
+The boolean, character, string, and set constants are not supported by
+GDB 4.9, but it ignores them. GDB 4.8 and earlier gave an error
+message and refused to read symbols from the file containing the
+constants.
+
+The above information is followed by @samp{;}.
+
+@node Variables
+@chapter Variables
+
+Different types of stabs describe the various ways that variables can be
+allocated: on the stack, globally, in registers, in common blocks,
+statically, or as arguments to a function.
+
+@menu
+* Stack Variables:: Variables allocated on the stack.
+* Global Variables:: Variables used by more than one source file.
+* Register Variables:: Variables in registers.
+* Common Blocks:: Variables statically allocated together.
+* Statics:: Variables local to one source file.
+* Based Variables:: Fortran pointer based variables.
+* Parameters:: Variables for arguments to functions.
+@end menu
+
+@node Stack Variables
+@section Automatic Variables Allocated on the Stack
+
+If a variable's scope is local to a function and its lifetime is only as
+long as that function executes (C calls such variables
+@dfn{automatic}), it can be allocated in a register (@pxref{Register
+Variables}) or on the stack.
+
+@findex N_LSYM
+Each variable allocated on the stack has a stab with the symbol
+descriptor omitted. Since type information should begin with a digit,
+@samp{-}, or @samp{(}, only those characters precluded from being used
+for symbol descriptors. However, the Acorn RISC machine (ARM) is said
+to get this wrong: it puts out a mere type definition here, without the
+preceding @samp{@var{type-number}=}. This is a bad idea; there is no
+guarantee that type descriptors are distinct from symbol descriptors.
+Stabs for stack variables use the @code{N_LSYM} stab type.
+
+The value of the stab is the offset of the variable within the
+local variables. On most machines this is an offset from the frame
+pointer and is negative. The location of the stab specifies which block
+it is defined in; see @ref{Block Structure}.
+
+For example, the following C code:
+
+@example
+int
+main ()
+@{
+ int x;
+@}
+@end example
+
+produces the following stabs:
+
+@example
+.stabs "main:F1",36,0,0,_main # @r{36 is N_FUN}
+.stabs "x:1",128,0,0,-12 # @r{128 is N_LSYM}
+.stabn 192,0,0,LBB2 # @r{192 is N_LBRAC}
+.stabn 224,0,0,LBE2 # @r{224 is N_RBRAC}
+@end example
+
+@xref{Procedures} for more information on the @code{N_FUN} stab, and
+@ref{Block Structure} for more information on the @code{N_LBRAC} and
+@code{N_RBRAC} stabs.
+
+@node Global Variables
+@section Global Variables
+
+@findex N_GSYM
+A variable whose scope is not specific to just one source file is
+represented by the @samp{G} symbol descriptor. These stabs use the
+@code{N_GSYM} stab type. The type information for the stab
+(@pxref{String Field}) gives the type of the variable.
+
+For example, the following source code:
+
+@example
+char g_foo = 'c';
+@end example
+
+@noindent
+yields the following assembly code:
+
+@example
+.stabs "g_foo:G2",32,0,0,0 # @r{32 is N_GSYM}
+ .global _g_foo
+ .data
+_g_foo:
+ .byte 99
+@end example
+
+The address of the variable represented by the @code{N_GSYM} is not
+contained in the @code{N_GSYM} stab. The debugger gets this information
+from the external symbol for the global variable. In the example above,
+the @code{.global _g_foo} and @code{_g_foo:} lines tell the assembler to
+produce an external symbol.
+
+Some compilers, like GCC, output @code{N_GSYM} stabs only once, where
+the variable is defined. Other compilers, like SunOS4 /bin/cc, output a
+@code{N_GSYM} stab for each compilation unit which references the
+variable.
+
+@node Register Variables
+@section Register Variables
+
+@findex N_RSYM
+@c According to an old version of this manual, AIX uses C_RPSYM instead
+@c of C_RSYM. I am skeptical; this should be verified.
+Register variables have their own stab type, @code{N_RSYM}, and their
+own symbol descriptor, @samp{r}. The stab's value is the
+number of the register where the variable data will be stored.
+@c .stabs "name:type",N_RSYM,0,RegSize,RegNumber (Sun doc)
+
+AIX defines a separate symbol descriptor @samp{d} for floating point
+registers. This seems unnecessary; why not just just give floating
+point registers different register numbers? I have not verified whether
+the compiler actually uses @samp{d}.
+
+If the register is explicitly allocated to a global variable, but not
+initialized, as in:
+
+@example
+register int g_bar asm ("%g5");
+@end example
+
+@noindent
+then the stab may be emitted at the end of the object file, with
+the other bss symbols.
+
+@node Common Blocks
+@section Common Blocks
+
+A common block is a statically allocated section of memory which can be
+referred to by several source files. It may contain several variables.
+I believe Fortran is the only language with this feature.
+
+@findex N_BCOMM
+@findex N_ECOMM
+@findex C_BCOMM
+@findex C_ECOMM
+A @code{N_BCOMM} stab begins a common block and an @code{N_ECOMM} stab
+ends it. The only field that is significant in these two stabs is the
+string, which names a normal (non-debugging) symbol that gives the
+address of the common block. According to IBM documentation, only the
+@code{N_BCOMM} has the name of the common block (even though their
+compiler actually puts it both places).
+
+@findex N_ECOML
+@findex C_ECOML
+The stabs for the members of the common block are between the
+@code{N_BCOMM} and the @code{N_ECOMM}; the value of each stab is the
+offset within the common block of that variable. IBM uses the
+@code{C_ECOML} stab type, and there is a corresponding @code{N_ECOML}
+stab type, but Sun's Fortran compiler uses @code{N_GSYM} instead. The
+variables within a common block use the @samp{V} symbol descriptor (I
+believe this is true of all Fortran variables). Other stabs (at least
+type declarations using @code{C_DECL}) can also be between the
+@code{N_BCOMM} and the @code{N_ECOMM}.
+
+@node Statics
+@section Static Variables
+
+Initialized static variables are represented by the @samp{S} and
+@samp{V} symbol descriptors. @samp{S} means file scope static, and
+@samp{V} means procedure scope static. One exception: in XCOFF, IBM's
+xlc compiler always uses @samp{V}, and whether it is file scope or not
+is distinguished by whether the stab is located within a function.
+
+@c This is probably not worth mentioning; it is only true on the sparc
+@c for `double' variables which although declared const are actually in
+@c the data segment (the text segment can't guarantee 8 byte alignment).
+@c (although GCC
+@c 2.4.5 has a bug in that it uses @code{N_FUN}, so neither dbx nor GDB can
+@c find the variables)
+@findex N_STSYM
+@findex N_LCSYM
+@findex N_FUN, for variables
+@findex N_ROSYM
+In a.out files, @code{N_STSYM} means the data section, @code{N_FUN}
+means the text section, and @code{N_LCSYM} means the bss section. For
+those systems with a read-only data section separate from the text
+section (Solaris), @code{N_ROSYM} means the read-only data section.
+
+For example, the source lines:
+
+@example
+static const int var_const = 5;
+static int var_init = 2;
+static int var_noinit;
+@end example
+
+@noindent
+yield the following stabs:
+
+@example
+.stabs "var_const:S1",36,0,0,_var_const # @r{36 is N_FUN}
+@dots{}
+.stabs "var_init:S1",38,0,0,_var_init # @r{38 is N_STSYM}
+@dots{}
+.stabs "var_noinit:S1",40,0,0,_var_noinit # @r{40 is N_LCSYM}
+@end example
+
+In XCOFF files, the stab type need not indicate the section;
+@code{C_STSYM} can be used for all statics. Also, each static variable
+is enclosed in a static block. A @code{C_BSTAT} (emitted with a
+@samp{.bs} assembler directive) symbol begins the static block; its
+value is the symbol number of the csect symbol whose value is the
+address of the static block, its section is the section of the variables
+in that static block, and its name is @samp{.bs}. A @code{C_ESTAT}
+(emitted with a @samp{.es} assembler directive) symbol ends the static
+block; its name is @samp{.es} and its value and section are ignored.
+
+In ECOFF files, the storage class is used to specify the section, so the
+stab type need not indicate the section.
+
+In ELF files, for the SunPRO compiler version 2.0.1, symbol descriptor
+@samp{S} means that the address is absolute (the linker relocates it)
+and symbol descriptor @samp{V} means that the address is relative to the
+start of the relevant section for that compilation unit. SunPRO has
+plans to have the linker stop relocating stabs; I suspect that their the
+debugger gets the address from the corresponding ELF (not stab) symbol.
+I'm not sure how to find which symbol of that name is the right one.
+The clean way to do all this would be to have a the value of a symbol
+descriptor @samp{S} symbol be an offset relative to the start of the
+file, just like everything else, but that introduces obvious
+compatibility problems. For more information on linker stab relocation,
+@xref{ELF Linker Relocation}.
+
+@node Based Variables
+@section Fortran Based Variables
+
+Fortran (at least, the Sun and SGI dialects of FORTRAN-77) has a feature
+which allows allocating arrays with @code{malloc}, but which avoids
+blurring the line between arrays and pointers the way that C does. In
+stabs such a variable uses the @samp{b} symbol descriptor.
+
+For example, the Fortran declarations
+
+@example
+real foo, foo10(10), foo10_5(10,5)
+pointer (foop, foo)
+pointer (foo10p, foo10)
+pointer (foo105p, foo10_5)
+@end example
+
+produce the stabs
+
+@example
+foo:b6
+foo10:bar3;1;10;6
+foo10_5:bar3;1;5;ar3;1;10;6
+@end example
+
+In this example, @code{real} is type 6 and type 3 is an integral type
+which is the type of the subscripts of the array (probably
+@code{integer}).
+
+The @samp{b} symbol descriptor is like @samp{V} in that it denotes a
+statically allocated symbol whose scope is local to a function; see
+@xref{Statics}. The value of the symbol, instead of being the address
+of the variable itself, is the address of a pointer to that variable.
+So in the above example, the value of the @code{foo} stab is the address
+of a pointer to a real, the value of the @code{foo10} stab is the
+address of a pointer to a 10-element array of reals, and the value of
+the @code{foo10_5} stab is the address of a pointer to a 5-element array
+of 10-element arrays of reals.
+
+@node Parameters
+@section Parameters
+
+Formal parameters to a function are represented by a stab (or sometimes
+two; see below) for each parameter. The stabs are in the order in which
+the debugger should print the parameters (i.e., the order in which the
+parameters are declared in the source file). The exact form of the stab
+depends on how the parameter is being passed.
+
+@findex N_PSYM
+Parameters passed on the stack use the symbol descriptor @samp{p} and
+the @code{N_PSYM} symbol type. The value of the symbol is an offset
+used to locate the parameter on the stack; its exact meaning is
+machine-dependent, but on most machines it is an offset from the frame
+pointer.
+
+As a simple example, the code:
+
+@example
+main (argc, argv)
+ int argc;
+ char **argv;
+@end example
+
+produces the stabs:
+
+@example
+.stabs "main:F1",36,0,0,_main # @r{36 is N_FUN}
+.stabs "argc:p1",160,0,0,68 # @r{160 is N_PSYM}
+.stabs "argv:p20=*21=*2",160,0,0,72
+@end example
+
+The type definition of @code{argv} is interesting because it contains
+several type definitions. Type 21 is pointer to type 2 (char) and
+@code{argv} (type 20) is pointer to type 21.
+
+@c FIXME: figure out what these mean and describe them coherently.
+The following symbol descriptors are also said to go with @code{N_PSYM}.
+The value of the symbol is said to be an offset from the argument
+pointer (I'm not sure whether this is true or not).
+
+@example
+pP (<<??>>)
+pF Fortran function parameter
+X (function result variable)
+@end example
+
+@menu
+* Register Parameters::
+* Local Variable Parameters::
+* Reference Parameters::
+* Conformant Arrays::
+@end menu
+
+@node Register Parameters
+@subsection Passing Parameters in Registers
+
+If the parameter is passed in a register, then traditionally there are
+two symbols for each argument:
+
+@example
+.stabs "arg:p1" . . . ; N_PSYM
+.stabs "arg:r1" . . . ; N_RSYM
+@end example
+
+Debuggers use the second one to find the value, and the first one to
+know that it is an argument.
+
+@findex C_RPSYM
+@findex N_RSYM, for parameters
+Because that approach is kind of ugly, some compilers use symbol
+descriptor @samp{P} or @samp{R} to indicate an argument which is in a
+register. Symbol type @code{C_RPSYM} is used with @samp{R} and
+@code{N_RSYM} is used with @samp{P}. The symbol's value is
+the register number. @samp{P} and @samp{R} mean the same thing; the
+difference is that @samp{P} is a GNU invention and @samp{R} is an IBM
+(XCOFF) invention. As of version 4.9, GDB should handle either one.
+
+There is at least one case where GCC uses a @samp{p} and @samp{r} pair
+rather than @samp{P}; this is where the argument is passed in the
+argument list and then loaded into a register.
+
+According to the AIX documentation, symbol descriptor @samp{D} is for a
+parameter passed in a floating point register. This seems
+unnecessary---why not just use @samp{R} with a register number which
+indicates that it's a floating point register? I haven't verified
+whether the system actually does what the documentation indicates.
+
+@c FIXME: On the hppa this is for any type > 8 bytes, I think, and not
+@c for small structures (investigate).
+On the sparc and hppa, for a @samp{P} symbol whose type is a structure
+or union, the register contains the address of the structure. On the
+sparc, this is also true of a @samp{p} and @samp{r} pair (using Sun
+@code{cc}) or a @samp{p} symbol. However, if a (small) structure is
+really in a register, @samp{r} is used. And, to top it all off, on the
+hppa it might be a structure which was passed on the stack and loaded
+into a register and for which there is a @samp{p} and @samp{r} pair! I
+believe that symbol descriptor @samp{i} is supposed to deal with this
+case (it is said to mean "value parameter by reference, indirect
+access"; I don't know the source for this information), but I don't know
+details or what compilers or debuggers use it, if any (not GDB or GCC).
+It is not clear to me whether this case needs to be dealt with
+differently than parameters passed by reference (@pxref{Reference Parameters}).
+
+@node Local Variable Parameters
+@subsection Storing Parameters as Local Variables
+
+There is a case similar to an argument in a register, which is an
+argument that is actually stored as a local variable. Sometimes this
+happens when the argument was passed in a register and then the compiler
+stores it as a local variable. If possible, the compiler should claim
+that it's in a register, but this isn't always done.
+
+If a parameter is passed as one type and converted to a smaller type by
+the prologue (for example, the parameter is declared as a @code{float},
+but the calling conventions specify that it is passed as a
+@code{double}), then GCC2 (sometimes) uses a pair of symbols. The first
+symbol uses symbol descriptor @samp{p} and the type which is passed.
+The second symbol has the type and location which the parameter actually
+has after the prologue. For example, suppose the following C code
+appears with no prototypes involved:
+
+@example
+void
+subr (f)
+ float f;
+@{
+@end example
+
+if @code{f} is passed as a double at stack offset 8, and the prologue
+converts it to a float in register number 0, then the stabs look like:
+
+@example
+.stabs "f:p13",160,0,3,8 # @r{160 is @code{N_PSYM}, here 13 is @code{double}}
+.stabs "f:r12",64,0,3,0 # @r{64 is @code{N_RSYM}, here 12 is @code{float}}
+@end example
+
+In both stabs 3 is the line number where @code{f} is declared
+(@pxref{Line Numbers}).
+
+@findex N_LSYM, for parameter
+GCC, at least on the 960, has another solution to the same problem. It
+uses a single @samp{p} symbol descriptor for an argument which is stored
+as a local variable but uses @code{N_LSYM} instead of @code{N_PSYM}. In
+this case, the value of the symbol is an offset relative to the local
+variables for that function, not relative to the arguments; on some
+machines those are the same thing, but not on all.
+
+@c This is mostly just background info; the part that logically belongs
+@c here is the last sentence.
+On the VAX or on other machines in which the calling convention includes
+the number of words of arguments actually passed, the debugger (GDB at
+least) uses the parameter symbols to keep track of whether it needs to
+print nameless arguments in addition to the formal parameters which it
+has printed because each one has a stab. For example, in
+
+@example
+extern int fprintf (FILE *stream, char *format, @dots{});
+@dots{}
+fprintf (stdout, "%d\n", x);
+@end example
+
+there are stabs for @code{stream} and @code{format}. On most machines,
+the debugger can only print those two arguments (because it has no way
+of knowing that additional arguments were passed), but on the VAX or
+other machines with a calling convention which indicates the number of
+words of arguments, the debugger can print all three arguments. To do
+so, the parameter symbol (symbol descriptor @samp{p}) (not necessarily
+@samp{r} or symbol descriptor omitted symbols) needs to contain the
+actual type as passed (for example, @code{double} not @code{float} if it
+is passed as a double and converted to a float).
+
+@node Reference Parameters
+@subsection Passing Parameters by Reference
+
+If the parameter is passed by reference (e.g., Pascal @code{VAR}
+parameters), then the symbol descriptor is @samp{v} if it is in the
+argument list, or @samp{a} if it in a register. Other than the fact
+that these contain the address of the parameter rather than the
+parameter itself, they are identical to @samp{p} and @samp{R},
+respectively. I believe @samp{a} is an AIX invention; @samp{v} is
+supported by all stabs-using systems as far as I know.
+
+@node Conformant Arrays
+@subsection Passing Conformant Array Parameters
+
+@c Is this paragraph correct? It is based on piecing together patchy
+@c information and some guesswork
+Conformant arrays are a feature of Modula-2, and perhaps other
+languages, in which the size of an array parameter is not known to the
+called function until run-time. Such parameters have two stabs: a
+@samp{x} for the array itself, and a @samp{C}, which represents the size
+of the array. The value of the @samp{x} stab is the offset in the
+argument list where the address of the array is stored (it this right?
+it is a guess); the value of the @samp{C} stab is the offset in the
+argument list where the size of the array (in elements? in bytes?) is
+stored.
+
+@node Types
+@chapter Defining Types
+
+The examples so far have described types as references to previously
+defined types, or defined in terms of subranges of or pointers to
+previously defined types. This chapter describes the other type
+descriptors that may follow the @samp{=} in a type definition.
+
+@menu
+* Builtin Types:: Integers, floating point, void, etc.
+* Miscellaneous Types:: Pointers, sets, files, etc.
+* Cross-References:: Referring to a type not yet defined.
+* Subranges:: A type with a specific range.
+* Arrays:: An aggregate type of same-typed elements.
+* Strings:: Like an array but also has a length.
+* Enumerations:: Like an integer but the values have names.
+* Structures:: An aggregate type of different-typed elements.
+* Typedefs:: Giving a type a name.
+* Unions:: Different types sharing storage.
+* Function Types::
+@end menu
+
+@node Builtin Types
+@section Builtin Types
+
+Certain types are built in (@code{int}, @code{short}, @code{void},
+@code{float}, etc.); the debugger recognizes these types and knows how
+to handle them. Thus, don't be surprised if some of the following ways
+of specifying builtin types do not specify everything that a debugger
+would need to know about the type---in some cases they merely specify
+enough information to distinguish the type from other types.
+
+The traditional way to define builtin types is convolunted, so new ways
+have been invented to describe them. Sun's @code{acc} uses special
+builtin type descriptors (@samp{b} and @samp{R}), and IBM uses negative
+type numbers. GDB accepts all three ways, as of version 4.8; dbx just
+accepts the traditional builtin types and perhaps one of the other two
+formats. The following sections describe each of these formats.
+
+@menu
+* Traditional Builtin Types:: Put on your seatbelts and prepare for kludgery
+* Builtin Type Descriptors:: Builtin types with special type descriptors
+* Negative Type Numbers:: Builtin types using negative type numbers
+@end menu
+
+@node Traditional Builtin Types
+@subsection Traditional Builtin Types
+
+This is the traditional, convoluted method for defining builtin types.
+There are several classes of such type definitions: integer, floating
+point, and @code{void}.
+
+@menu
+* Traditional Integer Types::
+* Traditional Other Types::
+@end menu
+
+@node Traditional Integer Types
+@subsubsection Traditional Integer Types
+
+Often types are defined as subranges of themselves. If the bounding values
+fit within an @code{int}, then they are given normally. For example:
+
+@example
+.stabs "int:t1=r1;-2147483648;2147483647;",128,0,0,0 # @r{128 is N_LSYM}
+.stabs "char:t2=r2;0;127;",128,0,0,0
+@end example
+
+Builtin types can also be described as subranges of @code{int}:
+
+@example
+.stabs "unsigned short:t6=r1;0;65535;",128,0,0,0
+@end example
+
+If the lower bound of a subrange is 0 and the upper bound is -1,
+the type is an unsigned integral type whose bounds are too
+big to describe in an @code{int}. Traditionally this is only used for
+@code{unsigned int} and @code{unsigned long}:
+
+@example
+.stabs "unsigned int:t4=r1;0;-1;",128,0,0,0
+@end example
+
+For larger types, GCC 2.4.5 puts out bounds in octal, with one or more
+leading zeroes. In this case a negative bound consists of a number
+which is a 1 bit (for the sign bit) followed by a 0 bit for each bit in
+the number (except the sign bit), and a positive bound is one which is a
+1 bit for each bit in the number (except possibly the sign bit). All
+known versions of dbx and GDB version 4 accept this (at least in the
+sense of not refusing to process the file), but GDB 3.5 refuses to read
+the whole file containing such symbols. So GCC 2.3.3 did not output the
+proper size for these types. As an example of octal bounds, the string
+fields of the stabs for 64 bit integer types look like:
+
+@c .stabs directives, etc., omitted to make it fit on the page.
+@example
+long int:t3=r1;001000000000000000000000;000777777777777777777777;
+long unsigned int:t5=r1;000000000000000000000000;001777777777777777777777;
+@end example
+
+If the lower bound of a subrange is 0 and the upper bound is negative,
+the type is an unsigned integral type whose size in bytes is the
+absolute value of the upper bound. I believe this is a Convex
+convention for @code{unsigned long long}.
+
+If the lower bound of a subrange is negative and the upper bound is 0,
+the type is a signed integral type whose size in bytes is
+the absolute value of the lower bound. I believe this is a Convex
+convention for @code{long long}. To distinguish this from a legitimate
+subrange, the type should be a subrange of itself. I'm not sure whether
+this is the case for Convex.
+
+@node Traditional Other Types
+@subsubsection Traditional Other Types
+
+If the upper bound of a subrange is 0 and the lower bound is positive,
+the type is a floating point type, and the lower bound of the subrange
+indicates the number of bytes in the type:
+
+@example
+.stabs "float:t12=r1;4;0;",128,0,0,0
+.stabs "double:t13=r1;8;0;",128,0,0,0
+@end example
+
+However, GCC writes @code{long double} the same way it writes
+@code{double}, so there is no way to distinguish.
+
+@example
+.stabs "long double:t14=r1;8;0;",128,0,0,0
+@end example
+
+Complex types are defined the same way as floating-point types; there is
+no way to distinguish a single-precision complex from a double-precision
+floating-point type.
+
+The C @code{void} type is defined as itself:
+
+@example
+.stabs "void:t15=15",128,0,0,0
+@end example
+
+I'm not sure how a boolean type is represented.
+
+@node Builtin Type Descriptors
+@subsection Defining Builtin Types Using Builtin Type Descriptors
+
+This is the method used by Sun's @code{acc} for defining builtin types.
+These are the type descriptors to define builtin types:
+
+@table @code
+@c FIXME: clean up description of width and offset, once we figure out
+@c what they mean
+@item b @var{signed} @var{char-flag} @var{width} ; @var{offset} ; @var{nbits} ;
+Define an integral type. @var{signed} is @samp{u} for unsigned or
+@samp{s} for signed. @var{char-flag} is @samp{c} which indicates this
+is a character type, or is omitted. I assume this is to distinguish an
+integral type from a character type of the same size, for example it
+might make sense to set it for the C type @code{wchar_t} so the debugger
+can print such variables differently (Solaris does not do this). Sun
+sets it on the C types @code{signed char} and @code{unsigned char} which
+arguably is wrong. @var{width} and @var{offset} appear to be for small
+objects stored in larger ones, for example a @code{short} in an
+@code{int} register. @var{width} is normally the number of bytes in the
+type. @var{offset} seems to always be zero. @var{nbits} is the number
+of bits in the type.
+
+Note that type descriptor @samp{b} used for builtin types conflicts with
+its use for Pascal space types (@pxref{Miscellaneous Types}); they can
+be distinguished because the character following the type descriptor
+will be a digit, @samp{(}, or @samp{-} for a Pascal space type, or
+@samp{u} or @samp{s} for a builtin type.
+
+@item w
+Documented by AIX to define a wide character type, but their compiler
+actually uses negative type numbers (@pxref{Negative Type Numbers}).
+
+@item R @var{fp-type} ; @var{bytes} ;
+Define a floating point type. @var{fp-type} has one of the following values:
+
+@table @code
+@item 1 (NF_SINGLE)
+IEEE 32-bit (single precision) floating point format.
+
+@item 2 (NF_DOUBLE)
+IEEE 64-bit (double precision) floating point format.
+
+@item 3 (NF_COMPLEX)
+@item 4 (NF_COMPLEX16)
+@item 5 (NF_COMPLEX32)
+@c "GDB source" really means @file{include/aout/stab_gnu.h}, but trying
+@c to put that here got an overfull hbox.
+These are for complex numbers. A comment in the GDB source describes
+them as Fortran @code{complex}, @code{double complex}, and
+@code{complex*16}, respectively, but what does that mean? (i.e., Single
+precision? Double precison?).
+
+@item 6 (NF_LDOUBLE)
+Long double. This should probably only be used for Sun format
+@code{long double}, and new codes should be used for other floating
+point formats (@code{NF_DOUBLE} can be used if a @code{long double} is
+really just an IEEE double, of course).
+@end table
+
+@var{bytes} is the number of bytes occupied by the type. This allows a
+debugger to perform some operations with the type even if it doesn't
+understand @var{fp-type}.
+
+@item g @var{type-information} ; @var{nbits}
+Documented by AIX to define a floating type, but their compiler actually
+uses negative type numbers (@pxref{Negative Type Numbers}).
+
+@item c @var{type-information} ; @var{nbits}
+Documented by AIX to define a complex type, but their compiler actually
+uses negative type numbers (@pxref{Negative Type Numbers}).
+@end table
+
+The C @code{void} type is defined as a signed integral type 0 bits long:
+@example
+.stabs "void:t19=bs0;0;0",128,0,0,0
+@end example
+The Solaris compiler seems to omit the trailing semicolon in this case.
+Getting sloppy in this way is not a swift move because if a type is
+embedded in a more complex expression it is necessary to be able to tell
+where it ends.
+
+I'm not sure how a boolean type is represented.
+
+@node Negative Type Numbers
+@subsection Negative Type Numbers
+
+This is the method used in XCOFF for defining builtin types.
+Since the debugger knows about the builtin types anyway, the idea of
+negative type numbers is simply to give a special type number which
+indicates the builtin type. There is no stab defining these types.
+
+There are several subtle issues with negative type numbers.
+
+One is the size of the type. A builtin type (for example the C types
+@code{int} or @code{long}) might have different sizes depending on
+compiler options, the target architecture, the ABI, etc. This issue
+doesn't come up for IBM tools since (so far) they just target the
+RS/6000; the sizes indicated below for each size are what the IBM
+RS/6000 tools use. To deal with differing sizes, either define separate
+negative type numbers for each size (which works but requires changing
+the debugger, and, unless you get both AIX dbx and GDB to accept the
+change, introduces an incompatibility), or use a type attribute
+(@pxref{String Field}) to define a new type with the appropriate size
+(which merely requires a debugger which understands type attributes,
+like AIX dbx). For example,
+
+@example
+.stabs "boolean:t10=@@s8;-16",128,0,0,0
+@end example
+
+defines an 8-bit boolean type, and
+
+@example
+.stabs "boolean:t10=@@s64;-16",128,0,0,0
+@end example
+
+defines a 64-bit boolean type.
+
+A similar issue is the format of the type. This comes up most often for
+floating-point types, which could have various formats (particularly
+extended doubles, which vary quite a bit even among IEEE systems).
+Again, it is best to define a new negative type number for each
+different format; changing the format based on the target system has
+various problems. One such problem is that the Alpha has both VAX and
+IEEE floating types. One can easily imagine one library using the VAX
+types and another library in the same executable using the IEEE types.
+Another example is that the interpretation of whether a boolean is true
+or false can be based on the least significant bit, most significant
+bit, whether it is zero, etc., and different compilers (or different
+options to the same compiler) might provide different kinds of boolean.
+
+The last major issue is the names of the types. The name of a given
+type depends @emph{only} on the negative type number given; these do not
+vary depending on the language, the target system, or anything else.
+One can always define separate type numbers---in the following list you
+will see for example separate @code{int} and @code{integer*4} types
+which are identical except for the name. But compatibility can be
+maintained by not inventing new negative type numbers and instead just
+defining a new type with a new name. For example:
+
+@example
+.stabs "CARDINAL:t10=-8",128,0,0,0
+@end example
+
+Here is the list of negative type numbers. The phrase @dfn{integral
+type} is used to mean twos-complement (I strongly suspect that all
+machines which use stabs use twos-complement; most machines use
+twos-complement these days).
+
+@table @code
+@item -1
+@code{int}, 32 bit signed integral type.
+
+@item -2
+@code{char}, 8 bit type holding a character. Both GDB and dbx on AIX
+treat this as signed. GCC uses this type whether @code{char} is signed
+or not, which seems like a bad idea. The AIX compiler (@code{xlc}) seems to
+avoid this type; it uses -5 instead for @code{char}.
+
+@item -3
+@code{short}, 16 bit signed integral type.
+
+@item -4
+@code{long}, 32 bit signed integral type.
+
+@item -5
+@code{unsigned char}, 8 bit unsigned integral type.
+
+@item -6
+@code{signed char}, 8 bit signed integral type.
+
+@item -7
+@code{unsigned short}, 16 bit unsigned integral type.
+
+@item -8
+@code{unsigned int}, 32 bit unsigned integral type.
+
+@item -9
+@code{unsigned}, 32 bit unsigned integral type.
+
+@item -10
+@code{unsigned long}, 32 bit unsigned integral type.
+
+@item -11
+@code{void}, type indicating the lack of a value.
+
+@item -12
+@code{float}, IEEE single precision.
+
+@item -13
+@code{double}, IEEE double precision.
+
+@item -14
+@code{long double}, IEEE double precision. The compiler claims the size
+will increase in a future release, and for binary compatibility you have
+to avoid using @code{long double}. I hope when they increase it they
+use a new negative type number.
+
+@item -15
+@code{integer}. 32 bit signed integral type.
+
+@item -16
+@code{boolean}. 32 bit type. GDB and GCC assume that zero is false,
+one is true, and other values have unspecified meaning. I hope this
+agrees with how the IBM tools use the type.
+
+@item -17
+@code{short real}. IEEE single precision.
+
+@item -18
+@code{real}. IEEE double precision.
+
+@item -19
+@code{stringptr}. @xref{Strings}.
+
+@item -20
+@code{character}, 8 bit unsigned character type.
+
+@item -21
+@code{logical*1}, 8 bit type. This Fortran type has a split
+personality in that it is used for boolean variables, but can also be
+used for unsigned integers. 0 is false, 1 is true, and other values are
+non-boolean.
+
+@item -22
+@code{logical*2}, 16 bit type. This Fortran type has a split
+personality in that it is used for boolean variables, but can also be
+used for unsigned integers. 0 is false, 1 is true, and other values are
+non-boolean.
+
+@item -23
+@code{logical*4}, 32 bit type. This Fortran type has a split
+personality in that it is used for boolean variables, but can also be
+used for unsigned integers. 0 is false, 1 is true, and other values are
+non-boolean.
+
+@item -24
+@code{logical}, 32 bit type. This Fortran type has a split
+personality in that it is used for boolean variables, but can also be
+used for unsigned integers. 0 is false, 1 is true, and other values are
+non-boolean.
+
+@item -25
+@code{complex}. A complex type consisting of two IEEE single-precision
+floating point values.
+
+@item -26
+@code{complex}. A complex type consisting of two IEEE double-precision
+floating point values.
+
+@item -27
+@code{integer*1}, 8 bit signed integral type.
+
+@item -28
+@code{integer*2}, 16 bit signed integral type.
+
+@item -29
+@code{integer*4}, 32 bit signed integral type.
+
+@item -30
+@code{wchar}. Wide character, 16 bits wide, unsigned (what format?
+Unicode?).
+@end table
+
+@node Miscellaneous Types
+@section Miscellaneous Types
+
+@table @code
+@item b @var{type-information} ; @var{bytes}
+Pascal space type. This is documented by IBM; what does it mean?
+
+This use of the @samp{b} type descriptor can be distinguished
+from its use for builtin integral types (@pxref{Builtin Type
+Descriptors}) because the character following the type descriptor is
+always a digit, @samp{(}, or @samp{-}.
+
+@item B @var{type-information}
+A volatile-qualified version of @var{type-information}. This is
+a Sun extension. References and stores to a variable with a
+volatile-qualified type must not be optimized or cached; they
+must occur as the user specifies them.
+
+@item d @var{type-information}
+File of type @var{type-information}. As far as I know this is only used
+by Pascal.
+
+@item k @var{type-information}
+A const-qualified version of @var{type-information}. This is a Sun
+extension. A variable with a const-qualified type cannot be modified.
+
+@item M @var{type-information} ; @var{length}
+Multiple instance type. The type seems to composed of @var{length}
+repetitions of @var{type-information}, for example @code{character*3} is
+represented by @samp{M-2;3}, where @samp{-2} is a reference to a
+character type (@pxref{Negative Type Numbers}). I'm not sure how this
+differs from an array. This appears to be a Fortran feature.
+@var{length} is a bound, like those in range types; see @ref{Subranges}.
+
+@item S @var{type-information}
+Pascal set type. @var{type-information} must be a small type such as an
+enumeration or a subrange, and the type is a bitmask whose length is
+specified by the number of elements in @var{type-information}.
+
+In CHILL, if it is a bitstring instead of a set, also use the @samp{S}
+type attribute (@pxref{String Field}).
+
+@item * @var{type-information}
+Pointer to @var{type-information}.
+@end table
+
+@node Cross-References
+@section Cross-References to Other Types
+
+A type can be used before it is defined; one common way to deal with
+that situation is just to use a type reference to a type which has not
+yet been defined.
+
+Another way is with the @samp{x} type descriptor, which is followed by
+@samp{s} for a structure tag, @samp{u} for a union tag, or @samp{e} for
+a enumerator tag, followed by the name of the tag, followed by @samp{:}.
+If the name contains @samp{::} between a @samp{<} and @samp{>} pair (for
+C++ templates), such a @samp{::} does not end the name---only a single
+@samp{:} ends the name; see @ref{Nested Symbols}.
+
+For example, the following C declarations:
+
+@example
+struct foo;
+struct foo *bar;
+@end example
+
+@noindent
+produce:
+
+@example
+.stabs "bar:G16=*17=xsfoo:",32,0,0,0
+@end example
+
+Not all debuggers support the @samp{x} type descriptor, so on some
+machines GCC does not use it. I believe that for the above example it
+would just emit a reference to type 17 and never define it, but I
+haven't verified that.
+
+Modula-2 imported types, at least on AIX, use the @samp{i} type
+descriptor, which is followed by the name of the module from which the
+type is imported, followed by @samp{:}, followed by the name of the
+type. There is then optionally a comma followed by type information for
+the type. This differs from merely naming the type (@pxref{Typedefs}) in
+that it identifies the module; I don't understand whether the name of
+the type given here is always just the same as the name we are giving
+it, or whether this type descriptor is used with a nameless stab
+(@pxref{String Field}), or what. The symbol ends with @samp{;}.
+
+@node Subranges
+@section Subrange Types
+
+The @samp{r} type descriptor defines a type as a subrange of another
+type. It is followed by type information for the type of which it is a
+subrange, a semicolon, an integral lower bound, a semicolon, an
+integral upper bound, and a semicolon. The AIX documentation does not
+specify the trailing semicolon, in an effort to specify array indexes
+more cleanly, but a subrange which is not an array index has always
+included a trailing semicolon (@pxref{Arrays}).
+
+Instead of an integer, either bound can be one of the following:
+
+@table @code
+@item A @var{offset}
+The bound is passed by reference on the stack at offset @var{offset}
+from the argument list. @xref{Parameters}, for more information on such
+offsets.
+
+@item T @var{offset}
+The bound is passed by value on the stack at offset @var{offset} from
+the argument list.
+
+@item a @var{register-number}
+The bound is pased by reference in register number
+@var{register-number}.
+
+@item t @var{register-number}
+The bound is passed by value in register number @var{register-number}.
+
+@item J
+There is no bound.
+@end table
+
+Subranges are also used for builtin types; see @ref{Traditional Builtin Types}.
+
+@node Arrays
+@section Array Types
+
+Arrays use the @samp{a} type descriptor. Following the type descriptor
+is the type of the index and the type of the array elements. If the
+index type is a range type, it ends in a semicolon; otherwise
+(for example, if it is a type reference), there does not
+appear to be any way to tell where the types are separated. In an
+effort to clean up this mess, IBM documents the two types as being
+separated by a semicolon, and a range type as not ending in a semicolon
+(but this is not right for range types which are not array indexes,
+@pxref{Subranges}). I think probably the best solution is to specify
+that a semicolon ends a range type, and that the index type and element
+type of an array are separated by a semicolon, but that if the index
+type is a range type, the extra semicolon can be omitted. GDB (at least
+through version 4.9) doesn't support any kind of index type other than a
+range anyway; I'm not sure about dbx.
+
+It is well established, and widely used, that the type of the index,
+unlike most types found in the stabs, is merely a type definition, not
+type information (@pxref{String Field}) (that is, it need not start with
+@samp{@var{type-number}=} if it is defining a new type). According to a
+comment in GDB, this is also true of the type of the array elements; it
+gives @samp{ar1;1;10;ar1;1;10;4} as a legitimate way to express a two
+dimensional array. According to AIX documentation, the element type
+must be type information. GDB accepts either.
+
+The type of the index is often a range type, expressed as the type
+descriptor @samp{r} and some parameters. It defines the size of the
+array. In the example below, the range @samp{r1;0;2;} defines an index
+type which is a subrange of type 1 (integer), with a lower bound of 0
+and an upper bound of 2. This defines the valid range of subscripts of
+a three-element C array.
+
+For example, the definition:
+
+@example
+char char_vec[3] = @{'a','b','c'@};
+@end example
+
+@noindent
+produces the output:
+
+@example
+.stabs "char_vec:G19=ar1;0;2;2",32,0,0,0
+ .global _char_vec
+ .align 4
+_char_vec:
+ .byte 97
+ .byte 98
+ .byte 99
+@end example
+
+If an array is @dfn{packed}, the elements are spaced more
+closely than normal, saving memory at the expense of speed. For
+example, an array of 3-byte objects might, if unpacked, have each
+element aligned on a 4-byte boundary, but if packed, have no padding.
+One way to specify that something is packed is with type attributes
+(@pxref{String Field}). In the case of arrays, another is to use the
+@samp{P} type descriptor instead of @samp{a}. Other than specifying a
+packed array, @samp{P} is identical to @samp{a}.
+
+@c FIXME-what is it? A pointer?
+An open array is represented by the @samp{A} type descriptor followed by
+type information specifying the type of the array elements.
+
+@c FIXME: what is the format of this type? A pointer to a vector of pointers?
+An N-dimensional dynamic array is represented by
+
+@example
+D @var{dimensions} ; @var{type-information}
+@end example
+
+@c Does dimensions really have this meaning? The AIX documentation
+@c doesn't say.
+@var{dimensions} is the number of dimensions; @var{type-information}
+specifies the type of the array elements.
+
+@c FIXME: what is the format of this type? A pointer to some offsets in
+@c another array?
+A subarray of an N-dimensional array is represented by
+
+@example
+E @var{dimensions} ; @var{type-information}
+@end example
+
+@c Does dimensions really have this meaning? The AIX documentation
+@c doesn't say.
+@var{dimensions} is the number of dimensions; @var{type-information}
+specifies the type of the array elements.
+
+@node Strings
+@section Strings
+
+Some languages, like C or the original Pascal, do not have string types,
+they just have related things like arrays of characters. But most
+Pascals and various other languages have string types, which are
+indicated as follows:
+
+@table @code
+@item n @var{type-information} ; @var{bytes}
+@var{bytes} is the maximum length. I'm not sure what
+@var{type-information} is; I suspect that it means that this is a string
+of @var{type-information} (thus allowing a string of integers, a string
+of wide characters, etc., as well as a string of characters). Not sure
+what the format of this type is. This is an AIX feature.
+
+@item z @var{type-information} ; @var{bytes}
+Just like @samp{n} except that this is a gstring, not an ordinary
+string. I don't know the difference.
+
+@item N
+Pascal Stringptr. What is this? This is an AIX feature.
+@end table
+
+Languages, such as CHILL which have a string type which is basically
+just an array of characters use the @samp{S} type attribute
+(@pxref{String Field}).
+
+@node Enumerations
+@section Enumerations
+
+Enumerations are defined with the @samp{e} type descriptor.
+
+@c FIXME: Where does this information properly go? Perhaps it is
+@c redundant with something we already explain.
+The source line below declares an enumeration type at file scope.
+The type definition is located after the @code{N_RBRAC} that marks the end of
+the previous procedure's block scope, and before the @code{N_FUN} that marks
+the beginning of the next procedure's block scope. Therefore it does not
+describe a block local symbol, but a file local one.
+
+The source line:
+
+@example
+enum e_places @{first,second=3,last@};
+@end example
+
+@noindent
+generates the following stab:
+
+@example
+.stabs "e_places:T22=efirst:0,second:3,last:4,;",128,0,0,0
+@end example
+
+The symbol descriptor (@samp{T}) says that the stab describes a
+structure, enumeration, or union tag. The type descriptor @samp{e},
+following the @samp{22=} of the type definition narrows it down to an
+enumeration type. Following the @samp{e} is a list of the elements of
+the enumeration. The format is @samp{@var{name}:@var{value},}. The
+list of elements ends with @samp{;}. The fact that @var{value} is
+specified as an integer can cause problems if the value is large. GCC
+2.5.2 tries to output it in octal in that case with a leading zero,
+which is probably a good thing, although GDB 4.11 supports octal only in
+cases where decimal is perfectly good. Negative decimal values are
+supported by both GDB and dbx.
+
+There is no standard way to specify the size of an enumeration type; it
+is determined by the architecture (normally all enumerations types are
+32 bits). Type attributes can be used to specify an enumeration type of
+another size for debuggers which support them; see @ref{String Field}.
+
+Enumeration types are unusual in that they define symbols for the
+enumeration values (@code{first}, @code{second}, and @code{third} in the
+above example), and even though these symbols are visible in the file as
+a whole (rather than being in a more local namespace like structure
+member names), they are defined in the type definition for the
+enumeration type rather than each having their own symbol. In order to
+be fast, GDB will only get symbols from such types (in its initial scan
+of the stabs) if the type is the first thing defined after a @samp{T} or
+@samp{t} symbol descriptor (the above example fulfills this
+requirement). If the type does not have a name, the compiler should
+emit it in a nameless stab (@pxref{String Field}); GCC does this.
+
+@node Structures
+@section Structures
+
+The encoding of structures in stabs can be shown with an example.
+
+The following source code declares a structure tag and defines an
+instance of the structure in global scope. Then a @code{typedef} equates the
+structure tag with a new type. Seperate stabs are generated for the
+structure tag, the structure @code{typedef}, and the structure instance. The
+stabs for the tag and the @code{typedef} are emited when the definitions are
+encountered. Since the structure elements are not initialized, the
+stab and code for the structure variable itself is located at the end
+of the program in the bss section.
+
+@example
+struct s_tag @{
+ int s_int;
+ float s_float;
+ char s_char_vec[8];
+ struct s_tag* s_next;
+@} g_an_s;
+
+typedef struct s_tag s_typedef;
+@end example
+
+The structure tag has an @code{N_LSYM} stab type because, like the
+enumeration, the symbol has file scope. Like the enumeration, the
+symbol descriptor is @samp{T}, for enumeration, structure, or tag type.
+The type descriptor @samp{s} following the @samp{16=} of the type
+definition narrows the symbol type to structure.
+
+Following the @samp{s} type descriptor is the number of bytes the
+structure occupies, followed by a description of each structure element.
+The structure element descriptions are of the form @var{name:type, bit
+offset from the start of the struct, number of bits in the element}.
+
+@c FIXME: phony line break. Can probably be fixed by using an example
+@c with fewer fields.
+@example
+# @r{128 is N_LSYM}
+.stabs "s_tag:T16=s20s_int:1,0,32;s_float:12,32,32;
+ s_char_vec:17=ar1;0;7;2,64,64;s_next:18=*16,128,32;;",128,0,0,0
+@end example
+
+In this example, the first two structure elements are previously defined
+types. For these, the type following the @samp{@var{name}:} part of the
+element description is a simple type reference. The other two structure
+elements are new types. In this case there is a type definition
+embedded after the @samp{@var{name}:}. The type definition for the
+array element looks just like a type definition for a standalone array.
+The @code{s_next} field is a pointer to the same kind of structure that
+the field is an element of. So the definition of structure type 16
+contains a type definition for an element which is a pointer to type 16.
+
+If a field is a static member (this is a C++ feature in which a single
+variable appears to be a field of every structure of a given type) it
+still starts out with the field name, a colon, and the type, but then
+instead of a comma, bit position, comma, and bit size, there is a colon
+followed by the name of the variable which each such field refers to.
+
+If the structure has methods (a C++ feature), they follow the non-method
+fields; see @ref{Cplusplus}.
+
+@node Typedefs
+@section Giving a Type a Name
+
+To give a type a name, use the @samp{t} symbol descriptor. The type
+is specified by the type information (@pxref{String Field}) for the stab.
+For example,
+
+@example
+.stabs "s_typedef:t16",128,0,0,0 # @r{128 is N_LSYM}
+@end example
+
+specifies that @code{s_typedef} refers to type number 16. Such stabs
+have symbol type @code{N_LSYM} (or @code{C_DECL} for XCOFF).
+
+If you are specifying the tag name for a structure, union, or
+enumeration, use the @samp{T} symbol descriptor instead. I believe C is
+the only language with this feature.
+
+If the type is an opaque type (I believe this is a Modula-2 feature),
+AIX provides a type descriptor to specify it. The type descriptor is
+@samp{o} and is followed by a name. I don't know what the name
+means---is it always the same as the name of the type, or is this type
+descriptor used with a nameless stab (@pxref{String Field})? There
+optionally follows a comma followed by type information which defines
+the type of this type. If omitted, a semicolon is used in place of the
+comma and the type information, and the type is much like a generic
+pointer type---it has a known size but little else about it is
+specified.
+
+@node Unions
+@section Unions
+
+@example
+union u_tag @{
+ int u_int;
+ float u_float;
+ char* u_char;
+@} an_u;
+@end example
+
+This code generates a stab for a union tag and a stab for a union
+variable. Both use the @code{N_LSYM} stab type. If a union variable is
+scoped locally to the procedure in which it is defined, its stab is
+located immediately preceding the @code{N_LBRAC} for the procedure's block
+start.
+
+The stab for the union tag, however, is located preceding the code for
+the procedure in which it is defined. The stab type is @code{N_LSYM}. This
+would seem to imply that the union type is file scope, like the struct
+type @code{s_tag}. This is not true. The contents and position of the stab
+for @code{u_type} do not convey any infomation about its procedure local
+scope.
+
+@c FIXME: phony line break. Can probably be fixed by using an example
+@c with fewer fields.
+@smallexample
+# @r{128 is N_LSYM}
+.stabs "u_tag:T23=u4u_int:1,0,32;u_float:12,0,32;u_char:21,0,32;;",
+ 128,0,0,0
+@end smallexample
+
+The symbol descriptor @samp{T}, following the @samp{name:} means that
+the stab describes an enumeration, structure, or union tag. The type
+descriptor @samp{u}, following the @samp{23=} of the type definition,
+narrows it down to a union type definition. Following the @samp{u} is
+the number of bytes in the union. After that is a list of union element
+descriptions. Their format is @var{name:type, bit offset into the
+union, number of bytes for the element;}.
+
+The stab for the union variable is:
+
+@example
+.stabs "an_u:23",128,0,0,-20 # @r{128 is N_LSYM}
+@end example
+
+@samp{-20} specifies where the variable is stored (@pxref{Stack
+Variables}).
+
+@node Function Types
+@section Function Types
+
+Various types can be defined for function variables. These types are
+not used in defining functions (@pxref{Procedures}); they are used for
+things like pointers to functions.
+
+The simple, traditional, type is type descriptor @samp{f} is followed by
+type information for the return type of the function, followed by a
+semicolon.
+
+This does not deal with functions for which the number and types of the
+parameters are part of the type, as in Modula-2 or ANSI C. AIX provides
+extensions to specify these, using the @samp{f}, @samp{F}, @samp{p}, and
+@samp{R} type descriptors.
+
+First comes the type descriptor. If it is @samp{f} or @samp{F}, this
+type involves a function rather than a procedure, and the type
+information for the return type of the function follows, followed by a
+comma. Then comes the number of parameters to the function and a
+semicolon. Then, for each parameter, there is the name of the parameter
+followed by a colon (this is only present for type descriptors @samp{R}
+and @samp{F} which represent Pascal function or procedure parameters),
+type information for the parameter, a comma, 0 if passed by reference or
+1 if passed by value, and a semicolon. The type definition ends with a
+semicolon.
+
+For example, this variable definition:
+
+@example
+int (*g_pf)();
+@end example
+
+@noindent
+generates the following code:
+
+@example
+.stabs "g_pf:G24=*25=f1",32,0,0,0
+ .common _g_pf,4,"bss"
+@end example
+
+The variable defines a new type, 24, which is a pointer to another new
+type, 25, which is a function returning @code{int}.
+
+@node Symbol Tables
+@chapter Symbol Information in Symbol Tables
+
+This chapter describes the format of symbol table entries
+and how stab assembler directives map to them. It also describes the
+transformations that the assembler and linker make on data from stabs.
+
+@menu
+* Symbol Table Format::
+* Transformations On Symbol Tables::
+@end menu
+
+@node Symbol Table Format
+@section Symbol Table Format
+
+Each time the assembler encounters a stab directive, it puts
+each field of the stab into a corresponding field in a symbol table
+entry of its output file. If the stab contains a string field, the
+symbol table entry for that stab points to a string table entry
+containing the string data from the stab. Assembler labels become
+relocatable addresses. Symbol table entries in a.out have the format:
+
+@c FIXME: should refer to external, not internal.
+@example
+struct internal_nlist @{
+ unsigned long n_strx; /* index into string table of name */
+ unsigned char n_type; /* type of symbol */
+ unsigned char n_other; /* misc info (usually empty) */
+ unsigned short n_desc; /* description field */
+ bfd_vma n_value; /* value of symbol */
+@};
+@end example
+
+If the stab has a string, the @code{n_strx} field holds the offset in
+bytes of the string within the string table. The string is terminated
+by a NUL character. If the stab lacks a string (for example, it was
+produced by a @code{.stabn} or @code{.stabd} directive), the
+@code{n_strx} field is zero.
+
+Symbol table entries with @code{n_type} field values greater than 0x1f
+originated as stabs generated by the compiler (with one random
+exception). The other entries were placed in the symbol table of the
+executable by the assembler or the linker.
+
+@node Transformations On Symbol Tables
+@section Transformations on Symbol Tables
+
+The linker concatenates object files and does fixups of externally
+defined symbols.
+
+You can see the transformations made on stab data by the assembler and
+linker by examining the symbol table after each pass of the build. To
+do this, use @samp{nm -ap}, which dumps the symbol table, including
+debugging information, unsorted. For stab entries the columns are:
+@var{value}, @var{other}, @var{desc}, @var{type}, @var{string}. For
+assembler and linker symbols, the columns are: @var{value}, @var{type},
+@var{string}.
+
+The low 5 bits of the stab type tell the linker how to relocate the
+value of the stab. Thus for stab types like @code{N_RSYM} and
+@code{N_LSYM}, where the value is an offset or a register number, the
+low 5 bits are @code{N_ABS}, which tells the linker not to relocate the
+value.
+
+Where the value of a stab contains an assembly language label,
+it is transformed by each build step. The assembler turns it into a
+relocatable address and the linker turns it into an absolute address.
+
+@menu
+* Transformations On Static Variables::
+* Transformations On Global Variables::
+* Stab Section Transformations:: For some object file formats,
+ things are a bit different.
+@end menu
+
+@node Transformations On Static Variables
+@subsection Transformations on Static Variables
+
+This source line defines a static variable at file scope:
+
+@example
+static int s_g_repeat
+@end example
+
+@noindent
+The following stab describes the symbol:
+
+@example
+.stabs "s_g_repeat:S1",38,0,0,_s_g_repeat
+@end example
+
+@noindent
+The assembler transforms the stab into this symbol table entry in the
+@file{.o} file. The location is expressed as a data segment offset.
+
+@example
+00000084 - 00 0000 STSYM s_g_repeat:S1
+@end example
+
+@noindent
+In the symbol table entry from the executable, the linker has made the
+relocatable address absolute.
+
+@example
+0000e00c - 00 0000 STSYM s_g_repeat:S1
+@end example
+
+@node Transformations On Global Variables
+@subsection Transformations on Global Variables
+
+Stabs for global variables do not contain location information. In
+this case, the debugger finds location information in the assembler or
+linker symbol table entry describing the variable. The source line:
+
+@example
+char g_foo = 'c';
+@end example
+
+@noindent
+generates the stab:
+
+@example
+.stabs "g_foo:G2",32,0,0,0
+@end example
+
+The variable is represented by two symbol table entries in the object
+file (see below). The first one originated as a stab. The second one
+is an external symbol. The upper case @samp{D} signifies that the
+@code{n_type} field of the symbol table contains 7, @code{N_DATA} with
+local linkage. The stab's value is zero since the value is not used for
+@code{N_GSYM} stabs. The value of the linker symbol is the relocatable
+address corresponding to the variable.
+
+@example
+00000000 - 00 0000 GSYM g_foo:G2
+00000080 D _g_foo
+@end example
+
+@noindent
+These entries as transformed by the linker. The linker symbol table
+entry now holds an absolute address:
+
+@example
+00000000 - 00 0000 GSYM g_foo:G2
+@dots{}
+0000e008 D _g_foo
+@end example
+
+@node Stab Section Transformations
+@subsection Transformations of Stabs in separate sections
+
+For object file formats using stabs in separate sections (@pxref{Stab
+Sections}), use @code{objdump --stabs} instead of @code{nm} to show the
+stabs in an object or executable file. @code{objdump} is a GNU utility;
+Sun does not provide any equivalent.
+
+The following example is for a stab whose value is an address is
+relative to the compilation unit (@pxref{ELF Linker Relocation}). For
+example, if the source line
+
+@example
+static int ld = 5;
+@end example
+
+appears within a function, then the assembly language output from the
+compiler contains:
+
+@example
+.Ddata.data:
+@dots{}
+ .stabs "ld:V(0,3)",0x26,0,4,.L18-Ddata.data # @r{0x26 is N_STSYM}
+@dots{}
+.L18:
+ .align 4
+ .word 0x5
+@end example
+
+Because the value is formed by subtracting one symbol from another, the
+value is absolute, not relocatable, and so the object file contains
+
+@example
+Symnum n_type n_othr n_desc n_value n_strx String
+31 STSYM 0 4 00000004 680 ld:V(0,3)
+@end example
+
+without any relocations, and the executable file also contains
+
+@example
+Symnum n_type n_othr n_desc n_value n_strx String
+31 STSYM 0 4 00000004 680 ld:V(0,3)
+@end example
+
+@node Cplusplus
+@chapter GNU C++ Stabs
+
+@menu
+* Class Names:: C++ class names are both tags and typedefs.
+* Nested Symbols:: C++ symbol names can be within other types.
+* Basic Cplusplus Types::
+* Simple Classes::
+* Class Instance::
+* Methods:: Method definition
+* Method Type Descriptor:: The @samp{#} type descriptor
+* Member Type Descriptor:: The @samp{@@} type descriptor
+* Protections::
+* Method Modifiers::
+* Virtual Methods::
+* Inheritence::
+* Virtual Base Classes::
+* Static Members::
+@end menu
+
+@node Class Names
+@section C++ Class Names
+
+In C++, a class name which is declared with @code{class}, @code{struct},
+or @code{union}, is not only a tag, as in C, but also a type name. Thus
+there should be stabs with both @samp{t} and @samp{T} symbol descriptors
+(@pxref{Typedefs}).
+
+To save space, there is a special abbreviation for this case. If the
+@samp{T} symbol descriptor is followed by @samp{t}, then the stab
+defines both a type name and a tag.
+
+For example, the C++ code
+
+@example
+struct foo @{int x;@};
+@end example
+
+can be represented as either
+
+@example
+.stabs "foo:T19=s4x:1,0,32;;",128,0,0,0 # @r{128 is N_LSYM}
+.stabs "foo:t19",128,0,0,0
+@end example
+
+or
+
+@example
+.stabs "foo:Tt19=s4x:1,0,32;;",128,0,0,0
+@end example
+
+@node Nested Symbols
+@section Defining a Symbol Within Another Type
+
+In C++, a symbol (such as a type name) can be defined within another type.
+@c FIXME: Needs example.
+
+In stabs, this is sometimes represented by making the name of a symbol
+which contains @samp{::}. Such a pair of colons does not end the name
+of the symbol, the way a single colon would (@pxref{String Field}). I'm
+not sure how consistently used or well thought out this mechanism is.
+So that a pair of colons in this position always has this meaning,
+@samp{:} cannot be used as a symbol descriptor.
+
+For example, if the string for a stab is @samp{foo::bar::baz:t5=*6},
+then @code{foo::bar::baz} is the name of the symbol, @samp{t} is the
+symbol descriptor, and @samp{5=*6} is the type information.
+
+@node Basic Cplusplus Types
+@section Basic Types For C++
+
+<< the examples that follow are based on a01.C >>
+
+
+C++ adds two more builtin types to the set defined for C. These are
+the unknown type and the vtable record type. The unknown type, type
+16, is defined in terms of itself like the void type.
+
+The vtable record type, type 17, is defined as a structure type and
+then as a structure tag. The structure has four fields: delta, index,
+pfn, and delta2. pfn is the function pointer.
+
+<< In boilerplate $vtbl_ptr_type, what are the fields delta,
+index, and delta2 used for? >>
+
+This basic type is present in all C++ programs even if there are no
+virtual methods defined.
+
+@display
+.stabs "struct_name:sym_desc(type)type_def(17)=type_desc(struct)struct_bytes(8)
+ elem_name(delta):type_ref(short int),bit_offset(0),field_bits(16);
+ elem_name(index):type_ref(short int),bit_offset(16),field_bits(16);
+ elem_name(pfn):type_def(18)=type_desc(ptr to)type_ref(void),
+ bit_offset(32),field_bits(32);
+ elem_name(delta2):type_def(short int);bit_offset(32),field_bits(16);;"
+ N_LSYM, NIL, NIL
+@end display
+
+@smallexample
+.stabs "$vtbl_ptr_type:t17=s8
+ delta:6,0,16;index:6,16,16;pfn:18=*15,32,32;delta2:6,32,16;;"
+ ,128,0,0,0
+@end smallexample
+
+@display
+.stabs "name:sym_dec(struct tag)type_ref($vtbl_ptr_type)",N_LSYM,NIL,NIL,NIL
+@end display
+
+@example
+.stabs "$vtbl_ptr_type:T17",128,0,0,0
+@end example
+
+@node Simple Classes
+@section Simple Class Definition
+
+The stabs describing C++ language features are an extension of the
+stabs describing C. Stabs representing C++ class types elaborate
+extensively on the stab format used to describe structure types in C.
+Stabs representing class type variables look just like stabs
+representing C language variables.
+
+Consider the following very simple class definition.
+
+@example
+class baseA @{
+public:
+ int Adat;
+ int Ameth(int in, char other);
+@};
+@end example
+
+The class @code{baseA} is represented by two stabs. The first stab describes
+the class as a structure type. The second stab describes a structure
+tag of the class type. Both stabs are of stab type @code{N_LSYM}. Since the
+stab is not located between an @code{N_FUN} and an @code{N_LBRAC} stab this indicates
+that the class is defined at file scope. If it were, then the @code{N_LSYM}
+would signify a local variable.
+
+A stab describing a C++ class type is similar in format to a stab
+describing a C struct, with each class member shown as a field in the
+structure. The part of the struct format describing fields is
+expanded to include extra information relevent to C++ class members.
+In addition, if the class has multiple base classes or virtual
+functions the struct format outside of the field parts is also
+augmented.
+
+In this simple example the field part of the C++ class stab
+representing member data looks just like the field part of a C struct
+stab. The section on protections describes how its format is
+sometimes extended for member data.
+
+The field part of a C++ class stab representing a member function
+differs substantially from the field part of a C struct stab. It
+still begins with @samp{name:} but then goes on to define a new type number
+for the member function, describe its return type, its argument types,
+its protection level, any qualifiers applied to the method definition,
+and whether the method is virtual or not. If the method is virtual
+then the method description goes on to give the vtable index of the
+method, and the type number of the first base class defining the
+method.
+
+When the field name is a method name it is followed by two colons rather
+than one. This is followed by a new type definition for the method.
+This is a number followed by an equal sign and the type of the method.
+Normally this will be a type declared using the @samp{#} type
+descriptor; see @ref{Method Type Descriptor}; static member functions
+are declared using the @samp{f} type descriptor instead; see
+@ref{Function Types}.
+
+The format of an overloaded operator method name differs from that of
+other methods. It is @samp{op$::@var{operator-name}.} where
+@var{operator-name} is the operator name such as @samp{+} or @samp{+=}.
+The name ends with a period, and any characters except the period can
+occur in the @var{operator-name} string.
+
+The next part of the method description represents the arguments to the
+method, preceeded by a colon and ending with a semi-colon. The types of
+the arguments are expressed in the same way argument types are expressed
+in C++ name mangling. In this example an @code{int} and a @code{char}
+map to @samp{ic}.
+
+This is followed by a number, a letter, and an asterisk or period,
+followed by another semicolon. The number indicates the protections
+that apply to the member function. Here the 2 means public. The
+letter encodes any qualifier applied to the method definition. In
+this case, @samp{A} means that it is a normal function definition. The dot
+shows that the method is not virtual. The sections that follow
+elaborate further on these fields and describe the additional
+information present for virtual methods.
+
+
+@display
+.stabs "class_name:sym_desc(type)type_def(20)=type_desc(struct)struct_bytes(4)
+ field_name(Adat):type(int),bit_offset(0),field_bits(32);
+
+ method_name(Ameth)::type_def(21)=type_desc(method)return_type(int);
+ :arg_types(int char);
+ protection(public)qualifier(normal)virtual(no);;"
+ N_LSYM,NIL,NIL,NIL
+@end display
+
+@smallexample
+.stabs "baseA:t20=s4Adat:1,0,32;Ameth::21=##1;:ic;2A.;;",128,0,0,0
+
+.stabs "class_name:sym_desc(struct tag)",N_LSYM,NIL,NIL,NIL
+
+.stabs "baseA:T20",128,0,0,0
+@end smallexample
+
+@node Class Instance
+@section Class Instance
+
+As shown above, describing even a simple C++ class definition is
+accomplished by massively extending the stab format used in C to
+describe structure types. However, once the class is defined, C stabs
+with no modifications can be used to describe class instances. The
+following source:
+
+@example
+main () @{
+ baseA AbaseA;
+@}
+@end example
+
+@noindent
+yields the following stab describing the class instance. It looks no
+different from a standard C stab describing a local variable.
+
+@display
+.stabs "name:type_ref(baseA)", N_LSYM, NIL, NIL, frame_ptr_offset
+@end display
+
+@example
+.stabs "AbaseA:20",128,0,0,-20
+@end example
+
+@node Methods
+@section Method Definition
+
+The class definition shown above declares Ameth. The C++ source below
+defines Ameth:
+
+@example
+int
+baseA::Ameth(int in, char other)
+@{
+ return in;
+@};
+@end example
+
+
+This method definition yields three stabs following the code of the
+method. One stab describes the method itself and following two describe
+its parameters. Although there is only one formal argument all methods
+have an implicit argument which is the @code{this} pointer. The @code{this}
+pointer is a pointer to the object on which the method was called. Note
+that the method name is mangled to encode the class name and argument
+types. Name mangling is described in the @sc{arm} (@cite{The Annotated
+C++ Reference Manual}, by Ellis and Stroustrup, @sc{isbn}
+0-201-51459-1); @file{gpcompare.texi} in Cygnus GCC distributions
+describes the differences between GNU mangling and @sc{arm}
+mangling.
+@c FIXME: Use @xref, especially if this is generally installed in the
+@c info tree.
+@c FIXME: This information should be in a net release, either of GCC or
+@c GDB. But gpcompare.texi doesn't seem to be in the FSF GCC.
+
+@example
+.stabs "name:symbol_desriptor(global function)return_type(int)",
+ N_FUN, NIL, NIL, code_addr_of_method_start
+
+.stabs "Ameth__5baseAic:F1",36,0,0,_Ameth__5baseAic
+@end example
+
+Here is the stab for the @code{this} pointer implicit argument. The
+name of the @code{this} pointer is always @code{this}. Type 19, the
+@code{this} pointer is defined as a pointer to type 20, @code{baseA},
+but a stab defining @code{baseA} has not yet been emited. Since the
+compiler knows it will be emited shortly, here it just outputs a cross
+reference to the undefined symbol, by prefixing the symbol name with
+@samp{xs}.
+
+@example
+.stabs "name:sym_desc(register param)type_def(19)=
+ type_desc(ptr to)type_ref(baseA)=
+ type_desc(cross-reference to)baseA:",N_RSYM,NIL,NIL,register_number
+
+.stabs "this:P19=*20=xsbaseA:",64,0,0,8
+@end example
+
+The stab for the explicit integer argument looks just like a parameter
+to a C function. The last field of the stab is the offset from the
+argument pointer, which in most systems is the same as the frame
+pointer.
+
+@example
+.stabs "name:sym_desc(value parameter)type_ref(int)",
+ N_PSYM,NIL,NIL,offset_from_arg_ptr
+
+.stabs "in:p1",160,0,0,72
+@end example
+
+<< The examples that follow are based on A1.C >>
+
+@node Method Type Descriptor
+@section The @samp{#} Type Descriptor
+
+This is like the @samp{f} type descriptor for functions (@pxref{Function
+Types}), except that a function which uses the @samp{#} type descriptor
+takes an extra argument as its first argument, for the @code{this}
+pointer. The @samp{#} type descriptor is optionally followed by the
+types of the arguments, then another @samp{#}. If the types of the
+arguments are omitted, so that the second @samp{#} immediately follows
+the @samp{#} which is the type descriptor, the arguments are being
+omitted (to save space) and can be deduced from the mangled name of the
+method. After the second @samp{#} there is type information for the
+return type of the method and a semicolon.
+
+Note that although such a type will normally be used to describe fields
+in structures, unions, or classes, for at least some versions of the
+compiler it can also be used in other contexts.
+
+@node Member Type Descriptor
+@section The @samp{@@} Type Descriptor
+
+The @samp{@@} type descriptor is for a member (class and variable) type.
+It is followed by type information for the offset basetype, a comma, and
+type information for the type of the field being pointed to. (FIXME:
+this is acknowledged to be gibberish. Can anyone say what really goes
+here?).
+
+Note that there is a conflict between this and type attributes
+(@pxref{String Field}); both use type descriptor @samp{@@}.
+Fortunately, the @samp{@@} type descriptor used in this C++ sense always
+will be followed by a digit, @samp{(}, or @samp{-}, and type attributes
+never start with those things.
+
+@node Protections
+@section Protections
+
+In the simple class definition shown above all member data and
+functions were publicly accessable. The example that follows
+contrasts public, protected and privately accessable fields and shows
+how these protections are encoded in C++ stabs.
+
+If the character following the @samp{@var{field-name}:} part of the
+string is @samp{/}, then the next character is the visibility. @samp{0}
+means private, @samp{1} means protected, and @samp{2} means public.
+Debuggers should ignore visibility characters they do not recognize, and
+assume a reasonable default (such as public) (GDB 4.11 does not, but
+this should be fixed in the next GDB release). If no visibility is
+specified the field is public. The visibility @samp{9} means that the
+field has been optimized out and is public (there is no way to specify
+an optimized out field with a private or protected visibility).
+Visibility @samp{9} is not supported by GDB 4.11; this should be fixed
+in the next GDB release.
+
+The following C++ source:
+
+@example
+class vis @{
+private:
+ int priv;
+protected:
+ char prot;
+public:
+ float pub;
+@};
+@end example
+
+@noindent
+generates the following stab:
+
+@example
+# @r{128 is N_LSYM}
+.stabs "vis:T19=s12priv:/01,0,32;prot:/12,32,8;pub:12,64,32;;",128,0,0,0
+@end example
+
+@samp{vis:T19=s12} indicates that type number 19 is a 12 byte structure
+named @code{vis} The @code{priv} field has public visibility
+(@samp{/0}), type int (@samp{1}), and offset and size @samp{,0,32;}.
+The @code{prot} field has protected visibility (@samp{/1}), type char
+(@samp{2}) and offset and size @samp{,32,8;}. The @code{pub} field has
+type float (@samp{12}), and offset and size @samp{,64,32;}.
+
+Protections for member functions are signified by one digit embeded in
+the field part of the stab describing the method. The digit is 0 if
+private, 1 if protected and 2 if public. Consider the C++ class
+definition below:
+
+@example
+class all_methods @{
+private:
+ int priv_meth(int in)@{return in;@};
+protected:
+ char protMeth(char in)@{return in;@};
+public:
+ float pubMeth(float in)@{return in;@};
+@};
+@end example
+
+It generates the following stab. The digit in question is to the left
+of an @samp{A} in each case. Notice also that in this case two symbol
+descriptors apply to the class name struct tag and struct type.
+
+@display
+.stabs "class_name:sym_desc(struct tag&type)type_def(21)=
+ sym_desc(struct)struct_bytes(1)
+ meth_name::type_def(22)=sym_desc(method)returning(int);
+ :args(int);protection(private)modifier(normal)virtual(no);
+ meth_name::type_def(23)=sym_desc(method)returning(char);
+ :args(char);protection(protected)modifier(normal)virual(no);
+ meth_name::type_def(24)=sym_desc(method)returning(float);
+ :args(float);protection(public)modifier(normal)virtual(no);;",
+ N_LSYM,NIL,NIL,NIL
+@end display
+
+@smallexample
+.stabs "all_methods:Tt21=s1priv_meth::22=##1;:i;0A.;protMeth::23=##2;:c;1A.;
+ pubMeth::24=##12;:f;2A.;;",128,0,0,0
+@end smallexample
+
+@node Method Modifiers
+@section Method Modifiers (@code{const}, @code{volatile}, @code{const volatile})
+
+<< based on a6.C >>
+
+In the class example described above all the methods have the normal
+modifier. This method modifier information is located just after the
+protection information for the method. This field has four possible
+character values. Normal methods use @samp{A}, const methods use
+@samp{B}, volatile methods use @samp{C}, and const volatile methods use
+@samp{D}. Consider the class definition below:
+
+@example
+class A @{
+public:
+ int ConstMeth (int arg) const @{ return arg; @};
+ char VolatileMeth (char arg) volatile @{ return arg; @};
+ float ConstVolMeth (float arg) const volatile @{return arg; @};
+@};
+@end example
+
+This class is described by the following stab:
+
+@display
+.stabs "class(A):sym_desc(struct)type_def(20)=type_desc(struct)struct_bytes(1)
+ meth_name(ConstMeth)::type_def(21)sym_desc(method)
+ returning(int);:arg(int);protection(public)modifier(const)virtual(no);
+ meth_name(VolatileMeth)::type_def(22)=sym_desc(method)
+ returning(char);:arg(char);protection(public)modifier(volatile)virt(no)
+ meth_name(ConstVolMeth)::type_def(23)=sym_desc(method)
+ returning(float);:arg(float);protection(public)modifer(const volatile)
+ virtual(no);;", @dots{}
+@end display
+
+@example
+.stabs "A:T20=s1ConstMeth::21=##1;:i;2B.;VolatileMeth::22=##2;:c;2C.;
+ ConstVolMeth::23=##12;:f;2D.;;",128,0,0,0
+@end example
+
+@node Virtual Methods
+@section Virtual Methods
+
+<< The following examples are based on a4.C >>
+
+The presence of virtual methods in a class definition adds additional
+data to the class description. The extra data is appended to the
+description of the virtual method and to the end of the class
+description. Consider the class definition below:
+
+@example
+class A @{
+public:
+ int Adat;
+ virtual int A_virt (int arg) @{ return arg; @};
+@};
+@end example
+
+This results in the stab below describing class A. It defines a new
+type (20) which is an 8 byte structure. The first field of the class
+struct is @samp{Adat}, an integer, starting at structure offset 0 and
+occupying 32 bits.
+
+The second field in the class struct is not explicitly defined by the
+C++ class definition but is implied by the fact that the class
+contains a virtual method. This field is the vtable pointer. The
+name of the vtable pointer field starts with @samp{$vf} and continues with a
+type reference to the class it is part of. In this example the type
+reference for class A is 20 so the name of its vtable pointer field is
+@samp{$vf20}, followed by the usual colon.
+
+Next there is a type definition for the vtable pointer type (21).
+This is in turn defined as a pointer to another new type (22).
+
+Type 22 is the vtable itself, which is defined as an array, indexed by
+a range of integers between 0 and 1, and whose elements are of type
+17. Type 17 was the vtable record type defined by the boilerplate C++
+type definitions, as shown earlier.
+
+The bit offset of the vtable pointer field is 32. The number of bits
+in the field are not specified when the field is a vtable pointer.
+
+Next is the method definition for the virtual member function @code{A_virt}.
+Its description starts out using the same format as the non-virtual
+member functions described above, except instead of a dot after the
+@samp{A} there is an asterisk, indicating that the function is virtual.
+Since is is virtual some addition information is appended to the end
+of the method description.
+
+The first number represents the vtable index of the method. This is a
+32 bit unsigned number with the high bit set, followed by a
+semi-colon.
+
+The second number is a type reference to the first base class in the
+inheritence hierarchy defining the virtual member function. In this
+case the class stab describes a base class so the virtual function is
+not overriding any other definition of the method. Therefore the
+reference is to the type number of the class that the stab is
+describing (20).
+
+This is followed by three semi-colons. One marks the end of the
+current sub-section, one marks the end of the method field, and the
+third marks the end of the struct definition.
+
+For classes containing virtual functions the very last section of the
+string part of the stab holds a type reference to the first base
+class. This is preceeded by @samp{~%} and followed by a final semi-colon.
+
+@display
+.stabs "class_name(A):type_def(20)=sym_desc(struct)struct_bytes(8)
+ field_name(Adat):type_ref(int),bit_offset(0),field_bits(32);
+ field_name(A virt func ptr):type_def(21)=type_desc(ptr to)type_def(22)=
+ sym_desc(array)index_type_ref(range of int from 0 to 1);
+ elem_type_ref(vtbl elem type),
+ bit_offset(32);
+ meth_name(A_virt)::typedef(23)=sym_desc(method)returning(int);
+ :arg_type(int),protection(public)normal(yes)virtual(yes)
+ vtable_index(1);class_first_defining(A);;;~%first_base(A);",
+ N_LSYM,NIL,NIL,NIL
+@end display
+
+@c FIXME: bogus line break.
+@example
+.stabs "A:t20=s8Adat:1,0,32;$vf20:21=*22=ar1;0;1;17,32;
+ A_virt::23=##1;:i;2A*-2147483647;20;;;~%20;",128,0,0,0
+@end example
+
+@node Inheritence
+@section Inheritence
+
+Stabs describing C++ derived classes include additional sections that
+describe the inheritence hierarchy of the class. A derived class stab
+also encodes the number of base classes. For each base class it tells
+if the base class is virtual or not, and if the inheritence is private
+or public. It also gives the offset into the object of the portion of
+the object corresponding to each base class.
+
+This additional information is embeded in the class stab following the
+number of bytes in the struct. First the number of base classes
+appears bracketed by an exclamation point and a comma.
+
+Then for each base type there repeats a series: a virtual character, a
+visibilty character, a number, a comma, another number, and a
+semi-colon.
+
+The virtual character is @samp{1} if the base class is virtual and
+@samp{0} if not. The visibility character is @samp{2} if the derivation
+is public, @samp{1} if it is protected, and @samp{0} if it is private.
+Debuggers should ignore virtual or visibility characters they do not
+recognize, and assume a reasonable default (such as public and
+non-virtual) (GDB 4.11 does not, but this should be fixed in the next
+GDB release).
+
+The number following the virtual and visibility characters is the offset
+from the start of the object to the part of the object pertaining to the
+base class.
+
+After the comma, the second number is a type_descriptor for the base
+type. Finally a semi-colon ends the series, which repeats for each
+base class.
+
+The source below defines three base classes @code{A}, @code{B}, and
+@code{C} and the derived class @code{D}.
+
+
+@example
+class A @{
+public:
+ int Adat;
+ virtual int A_virt (int arg) @{ return arg; @};
+@};
+
+class B @{
+public:
+ int B_dat;
+ virtual int B_virt (int arg) @{return arg; @};
+@};
+
+class C @{
+public:
+ int Cdat;
+ virtual int C_virt (int arg) @{return arg; @};
+@};
+
+class D : A, virtual B, public C @{
+public:
+ int Ddat;
+ virtual int A_virt (int arg ) @{ return arg+1; @};
+ virtual int B_virt (int arg) @{ return arg+2; @};
+ virtual int C_virt (int arg) @{ return arg+3; @};
+ virtual int D_virt (int arg) @{ return arg; @};
+@};
+@end example
+
+Class stabs similar to the ones described earlier are generated for
+each base class.
+
+@c FIXME!!! the linebreaks in the following example probably make the
+@c examples literally unusable, but I don't know any other way to get
+@c them on the page.
+@c One solution would be to put some of the type definitions into
+@c separate stabs, even if that's not exactly what the compiler actually
+@c emits.
+@smallexample
+.stabs "A:T20=s8Adat:1,0,32;$vf20:21=*22=ar1;0;1;17,32;
+ A_virt::23=##1;:i;2A*-2147483647;20;;;~%20;",128,0,0,0
+
+.stabs "B:Tt25=s8Bdat:1,0,32;$vf25:21,32;B_virt::26=##1;
+ :i;2A*-2147483647;25;;;~%25;",128,0,0,0
+
+.stabs "C:Tt28=s8Cdat:1,0,32;$vf28:21,32;C_virt::29=##1;
+ :i;2A*-2147483647;28;;;~%28;",128,0,0,0
+@end smallexample
+
+In the stab describing derived class @code{D} below, the information about
+the derivation of this class is encoded as follows.
+
+@display
+.stabs "derived_class_name:symbol_descriptors(struct tag&type)=
+ type_descriptor(struct)struct_bytes(32)!num_bases(3),
+ base_virtual(no)inheritence_public(no)base_offset(0),
+ base_class_type_ref(A);
+ base_virtual(yes)inheritence_public(no)base_offset(NIL),
+ base_class_type_ref(B);
+ base_virtual(no)inheritence_public(yes)base_offset(64),
+ base_class_type_ref(C); @dots{}
+@end display
+
+@c FIXME! fake linebreaks.
+@smallexample
+.stabs "D:Tt31=s32!3,000,20;100,25;0264,28;$vb25:24,128;Ddat:
+ 1,160,32;A_virt::32=##1;:i;2A*-2147483647;20;;B_virt:
+ :32:i;2A*-2147483647;25;;C_virt::32:i;2A*-2147483647;
+ 28;;D_virt::32:i;2A*-2147483646;31;;;~%20;",128,0,0,0
+@end smallexample
+
+@node Virtual Base Classes
+@section Virtual Base Classes
+
+A derived class object consists of a concatination in memory of the data
+areas defined by each base class, starting with the leftmost and ending
+with the rightmost in the list of base classes. The exception to this
+rule is for virtual inheritence. In the example above, class @code{D}
+inherits virtually from base class @code{B}. This means that an
+instance of a @code{D} object will not contain its own @code{B} part but
+merely a pointer to a @code{B} part, known as a virtual base pointer.
+
+In a derived class stab, the base offset part of the derivation
+information, described above, shows how the base class parts are
+ordered. The base offset for a virtual base class is always given as 0.
+Notice that the base offset for @code{B} is given as 0 even though
+@code{B} is not the first base class. The first base class @code{A}
+starts at offset 0.
+
+The field information part of the stab for class @code{D} describes the field
+which is the pointer to the virtual base class @code{B}. The vbase pointer
+name is @samp{$vb} followed by a type reference to the virtual base class.
+Since the type id for @code{B} in this example is 25, the vbase pointer name
+is @samp{$vb25}.
+
+@c FIXME!! fake linebreaks below
+@smallexample
+.stabs "D:Tt31=s32!3,000,20;100,25;0264,28;$vb25:24,128;Ddat:1,
+ 160,32;A_virt::32=##1;:i;2A*-2147483647;20;;B_virt::32:i;
+ 2A*-2147483647;25;;C_virt::32:i;2A*-2147483647;28;;D_virt:
+ :32:i;2A*-2147483646;31;;;~%20;",128,0,0,0
+@end smallexample
+
+Following the name and a semicolon is a type reference describing the
+type of the virtual base class pointer, in this case 24. Type 24 was
+defined earlier as the type of the @code{B} class @code{this} pointer. The
+@code{this} pointer for a class is a pointer to the class type.
+
+@example
+.stabs "this:P24=*25=xsB:",64,0,0,8
+@end example
+
+Finally the field offset part of the vbase pointer field description
+shows that the vbase pointer is the first field in the @code{D} object,
+before any data fields defined by the class. The layout of a @code{D}
+class object is a follows, @code{Adat} at 0, the vtable pointer for
+@code{A} at 32, @code{Cdat} at 64, the vtable pointer for C at 96, the
+virtual base pointer for @code{B} at 128, and @code{Ddat} at 160.
+
+
+@node Static Members
+@section Static Members
+
+The data area for a class is a concatenation of the space used by the
+data members of the class. If the class has virtual methods, a vtable
+pointer follows the class data. The field offset part of each field
+description in the class stab shows this ordering.
+
+<< How is this reflected in stabs? See Cygnus bug #677 for some info. >>
+
+@node Stab Types
+@appendix Table of Stab Types
+
+The following are all the possible values for the stab type field, for
+a.out files, in numeric order. This does not apply to XCOFF, but
+it does apply to stabs in sections (@pxref{Stab Sections}). Stabs in
+ECOFF use these values but add 0x8f300 to distinguish them from non-stab
+symbols.
+
+The symbolic names are defined in the file @file{include/aout/stabs.def}.
+
+@menu
+* Non-Stab Symbol Types:: Types from 0 to 0x1f
+* Stab Symbol Types:: Types from 0x20 to 0xff
+@end menu
+
+@node Non-Stab Symbol Types
+@appendixsec Non-Stab Symbol Types
+
+The following types are used by the linker and assembler, not by stab
+directives. Since this document does not attempt to describe aspects of
+object file format other than the debugging format, no details are
+given.
+
+@c Try to get most of these to fit on a single line.
+@iftex
+@tableindent=1.5in
+@end iftex
+
+@table @code
+@item 0x0 N_UNDF
+Undefined symbol
+
+@item 0x2 N_ABS
+File scope absolute symbol
+
+@item 0x3 N_ABS | N_EXT
+External absolute symbol
+
+@item 0x4 N_TEXT
+File scope text symbol
+
+@item 0x5 N_TEXT | N_EXT
+External text symbol
+
+@item 0x6 N_DATA
+File scope data symbol
+
+@item 0x7 N_DATA | N_EXT
+External data symbol
+
+@item 0x8 N_BSS
+File scope BSS symbol
+
+@item 0x9 N_BSS | N_EXT
+External BSS symbol
+
+@item 0x0c N_FN_SEQ
+Same as @code{N_FN}, for Sequent compilers
+
+@item 0x0a N_INDR
+Symbol is indirected to another symbol
+
+@item 0x12 N_COMM
+Common---visible after shared library dynamic link
+
+@item 0x14 N_SETA
+@itemx 0x15 N_SETA | N_EXT
+Absolute set element
+
+@item 0x16 N_SETT
+@itemx 0x17 N_SETT | N_EXT
+Text segment set element
+
+@item 0x18 N_SETD
+@itemx 0x19 N_SETD | N_EXT
+Data segment set element
+
+@item 0x1a N_SETB
+@itemx 0x1b N_SETB | N_EXT
+BSS segment set element
+
+@item 0x1c N_SETV
+@itemx 0x1d N_SETV | N_EXT
+Pointer to set vector
+
+@item 0x1e N_WARNING
+Print a warning message during linking
+
+@item 0x1f N_FN
+File name of a @file{.o} file
+@end table
+
+@node Stab Symbol Types
+@appendixsec Stab Symbol Types
+
+The following symbol types indicate that this is a stab. This is the
+full list of stab numbers, including stab types that are used in
+languages other than C.
+
+@table @code
+@item 0x20 N_GSYM
+Global symbol; see @ref{Global Variables}.
+
+@item 0x22 N_FNAME
+Function name (for BSD Fortran); see @ref{Procedures}.
+
+@item 0x24 N_FUN
+Function name (@pxref{Procedures}) or text segment variable
+(@pxref{Statics}).
+
+@item 0x26 N_STSYM
+Data segment file-scope variable; see @ref{Statics}.
+
+@item 0x28 N_LCSYM
+BSS segment file-scope variable; see @ref{Statics}.
+
+@item 0x2a N_MAIN
+Name of main routine; see @ref{Main Program}.
+
+@item 0x2c N_ROSYM
+Variable in @code{.rodata} section; see @ref{Statics}.
+
+@item 0x30 N_PC
+Global symbol (for Pascal); see @ref{N_PC}.
+
+@item 0x32 N_NSYMS
+Number of symbols (according to Ultrix V4.0); see @ref{N_NSYMS}.
+
+@item 0x34 N_NOMAP
+No DST map; see @ref{N_NOMAP}.
+
+@c FIXME: describe this solaris feature in the body of the text (see
+@c comments in include/aout/stab.def).
+@item 0x38 N_OBJ
+Object file (Solaris2).
+
+@c See include/aout/stab.def for (a little) more info.
+@item 0x3c N_OPT
+Debugger options (Solaris2).
+
+@item 0x40 N_RSYM
+Register variable; see @ref{Register Variables}.
+
+@item 0x42 N_M2C
+Modula-2 compilation unit; see @ref{N_M2C}.
+
+@item 0x44 N_SLINE
+Line number in text segment; see @ref{Line Numbers}.
+
+@item 0x46 N_DSLINE
+Line number in data segment; see @ref{Line Numbers}.
+
+@item 0x48 N_BSLINE
+Line number in bss segment; see @ref{Line Numbers}.
+
+@item 0x48 N_BROWS
+Sun source code browser, path to @file{.cb} file; see @ref{N_BROWS}.
+
+@item 0x4a N_DEFD
+GNU Modula2 definition module dependency; see @ref{N_DEFD}.
+
+@item 0x4c N_FLINE
+Function start/body/end line numbers (Solaris2).
+
+@item 0x50 N_EHDECL
+GNU C++ exception variable; see @ref{N_EHDECL}.
+
+@item 0x50 N_MOD2
+Modula2 info "for imc" (according to Ultrix V4.0); see @ref{N_MOD2}.
+
+@item 0x54 N_CATCH
+GNU C++ @code{catch} clause; see @ref{N_CATCH}.
+
+@item 0x60 N_SSYM
+Structure of union element; see @ref{N_SSYM}.
+
+@item 0x62 N_ENDM
+Last stab for module (Solaris2).
+
+@item 0x64 N_SO
+Path and name of source file; see @ref{Source Files}.
+
+@item 0x80 N_LSYM
+Stack variable (@pxref{Stack Variables}) or type (@pxref{Typedefs}).
+
+@item 0x82 N_BINCL
+Beginning of an include file (Sun only); see @ref{Include Files}.
+
+@item 0x84 N_SOL
+Name of include file; see @ref{Include Files}.
+
+@item 0xa0 N_PSYM
+Parameter variable; see @ref{Parameters}.
+
+@item 0xa2 N_EINCL
+End of an include file; see @ref{Include Files}.
+
+@item 0xa4 N_ENTRY
+Alternate entry point; see @ref{Alternate Entry Points}.
+
+@item 0xc0 N_LBRAC
+Beginning of a lexical block; see @ref{Block Structure}.
+
+@item 0xc2 N_EXCL
+Place holder for a deleted include file; see @ref{Include Files}.
+
+@item 0xc4 N_SCOPE
+Modula2 scope information (Sun linker); see @ref{N_SCOPE}.
+
+@item 0xe0 N_RBRAC
+End of a lexical block; see @ref{Block Structure}.
+
+@item 0xe2 N_BCOMM
+Begin named common block; see @ref{Common Blocks}.
+
+@item 0xe4 N_ECOMM
+End named common block; see @ref{Common Blocks}.
+
+@item 0xe8 N_ECOML
+Member of a common block; see @ref{Common Blocks}.
+
+@c FIXME: How does this really work? Move it to main body of document.
+@item 0xea N_WITH
+Pascal @code{with} statement: type,,0,0,offset (Solaris2).
+
+@item 0xf0 N_NBTEXT
+Gould non-base registers; see @ref{Gould}.
+
+@item 0xf2 N_NBDATA
+Gould non-base registers; see @ref{Gould}.
+
+@item 0xf4 N_NBBSS
+Gould non-base registers; see @ref{Gould}.
+
+@item 0xf6 N_NBSTS
+Gould non-base registers; see @ref{Gould}.
+
+@item 0xf8 N_NBLCS
+Gould non-base registers; see @ref{Gould}.
+@end table
+
+@c Restore the default table indent
+@iftex
+@tableindent=.8in
+@end iftex
+
+@node Symbol Descriptors
+@appendix Table of Symbol Descriptors
+
+The symbol descriptor is the character which follows the colon in many
+stabs, and which tells what kind of stab it is. @xref{String Field},
+for more information about their use.
+
+@c Please keep this alphabetical
+@table @code
+@c In TeX, this looks great, digit is in italics. But makeinfo insists
+@c on putting it in `', not realizing that @var should override @code.
+@c I don't know of any way to make makeinfo do the right thing. Seems
+@c like a makeinfo bug to me.
+@item @var{digit}
+@itemx (
+@itemx -
+Variable on the stack; see @ref{Stack Variables}.
+
+@item :
+C++ nested symbol; see @xref{Nested Symbols}
+
+@item a
+Parameter passed by reference in register; see @ref{Reference Parameters}.
+
+@item b
+Based variable; see @ref{Based Variables}.
+
+@item c
+Constant; see @ref{Constants}.
+
+@item C
+Conformant array bound (Pascal, maybe other languages); @ref{Conformant
+Arrays}. Name of a caught exception (GNU C++). These can be
+distinguished because the latter uses @code{N_CATCH} and the former uses
+another symbol type.
+
+@item d
+Floating point register variable; see @ref{Register Variables}.
+
+@item D
+Parameter in floating point register; see @ref{Register Parameters}.
+
+@item f
+File scope function; see @ref{Procedures}.
+
+@item F
+Global function; see @ref{Procedures}.
+
+@item G
+Global variable; see @ref{Global Variables}.
+
+@item i
+@xref{Register Parameters}.
+
+@item I
+Internal (nested) procedure; see @ref{Nested Procedures}.
+
+@item J
+Internal (nested) function; see @ref{Nested Procedures}.
+
+@item L
+Label name (documented by AIX, no further information known).
+
+@item m
+Module; see @ref{Procedures}.
+
+@item p
+Argument list parameter; see @ref{Parameters}.
+
+@item pP
+@xref{Parameters}.
+
+@item pF
+Fortran Function parameter; see @ref{Parameters}.
+
+@item P
+Unfortunately, three separate meanings have been independently invented
+for this symbol descriptor. At least the GNU and Sun uses can be
+distinguished by the symbol type. Global Procedure (AIX) (symbol type
+used unknown); see @ref{Procedures}. Register parameter (GNU) (symbol
+type @code{N_PSYM}); see @ref{Parameters}. Prototype of function
+referenced by this file (Sun @code{acc}) (symbol type @code{N_FUN}).
+
+@item Q
+Static Procedure; see @ref{Procedures}.
+
+@item R
+Register parameter; see @ref{Register Parameters}.
+
+@item r
+Register variable; see @ref{Register Variables}.
+
+@item S
+File scope variable; see @ref{Statics}.
+
+@item s
+Local variable (OS9000).
+
+@item t
+Type name; see @ref{Typedefs}.
+
+@item T
+Enumeration, structure, or union tag; see @ref{Typedefs}.
+
+@item v
+Parameter passed by reference; see @ref{Reference Parameters}.
+
+@item V
+Procedure scope static variable; see @ref{Statics}.
+
+@item x
+Conformant array; see @ref{Conformant Arrays}.
+
+@item X
+Function return variable; see @ref{Parameters}.
+@end table
+
+@node Type Descriptors
+@appendix Table of Type Descriptors
+
+The type descriptor is the character which follows the type number and
+an equals sign. It specifies what kind of type is being defined.
+@xref{String Field}, for more information about their use.
+
+@table @code
+@item @var{digit}
+@itemx (
+Type reference; see @ref{String Field}.
+
+@item -
+Reference to builtin type; see @ref{Negative Type Numbers}.
+
+@item #
+Method (C++); see @ref{Method Type Descriptor}.
+
+@item *
+Pointer; see @ref{Miscellaneous Types}.
+
+@item &
+Reference (C++).
+
+@item @@
+Type Attributes (AIX); see @ref{String Field}. Member (class and variable)
+type (GNU C++); see @ref{Member Type Descriptor}.
+
+@item a
+Array; see @ref{Arrays}.
+
+@item A
+Open array; see @ref{Arrays}.
+
+@item b
+Pascal space type (AIX); see @ref{Miscellaneous Types}. Builtin integer
+type (Sun); see @ref{Builtin Type Descriptors}. Const and volatile
+qualfied type (OS9000).
+
+@item B
+Volatile-qualified type; see @ref{Miscellaneous Types}.
+
+@item c
+Complex builtin type (AIX); see @ref{Builtin Type Descriptors}.
+Const-qualified type (OS9000).
+
+@item C
+COBOL Picture type. See AIX documentation for details.
+
+@item d
+File type; see @ref{Miscellaneous Types}.
+
+@item D
+N-dimensional dynamic array; see @ref{Arrays}.
+
+@item e
+Enumeration type; see @ref{Enumerations}.
+
+@item E
+N-dimensional subarray; see @ref{Arrays}.
+
+@item f
+Function type; see @ref{Function Types}.
+
+@item F
+Pascal function parameter; see @ref{Function Types}
+
+@item g
+Builtin floating point type; see @ref{Builtin Type Descriptors}.
+
+@item G
+COBOL Group. See AIX documentation for details.
+
+@item i
+Imported type (AIX); see @ref{Cross-References}. Volatile-qualified
+type (OS9000).
+
+@item k
+Const-qualified type; see @ref{Miscellaneous Types}.
+
+@item K
+COBOL File Descriptor. See AIX documentation for details.
+
+@item M
+Multiple instance type; see @ref{Miscellaneous Types}.
+
+@item n
+String type; see @ref{Strings}.
+
+@item N
+Stringptr; see @ref{Strings}.
+
+@item o
+Opaque type; see @ref{Typedefs}.
+
+@item p
+Procedure; see @ref{Function Types}.
+
+@item P
+Packed array; see @ref{Arrays}.
+
+@item r
+Range type; see @ref{Subranges}.
+
+@item R
+Builtin floating type; see @ref{Builtin Type Descriptors} (Sun). Pascal
+subroutine parameter; see @ref{Function Types} (AIX). Detecting this
+conflict is possible with careful parsing (hint: a Pascal subroutine
+parameter type will always contain a comma, and a builtin type
+descriptor never will).
+
+@item s
+Structure type; see @ref{Structures}.
+
+@item S
+Set type; see @ref{Miscellaneous Types}.
+
+@item u
+Union; see @ref{Unions}.
+
+@item v
+Variant record. This is a Pascal and Modula-2 feature which is like a
+union within a struct in C. See AIX documentation for details.
+
+@item w
+Wide character; see @ref{Builtin Type Descriptors}.
+
+@item x
+Cross-reference; see @ref{Cross-References}.
+
+@item Y
+Used by IBM's xlC C++ compiler (for structures, I think).
+
+@item z
+gstring; see @ref{Strings}.
+@end table
+
+@node Expanded Reference
+@appendix Expanded Reference by Stab Type
+
+@c FIXME: This appendix should go away; see N_PSYM or N_SO for an example.
+
+For a full list of stab types, and cross-references to where they are
+described, see @ref{Stab Types}. This appendix just duplicates certain
+information from the main body of this document; eventually the
+information will all be in one place.
+
+Format of an entry:
+
+The first line is the symbol type (see @file{include/aout/stab.def}).
+
+The second line describes the language constructs the symbol type
+represents.
+
+The third line is the stab format with the significant stab fields
+named and the rest NIL.
+
+Subsequent lines expand upon the meaning and possible values for each
+significant stab field.
+
+Finally, any further information.
+
+@menu
+* N_PC:: Pascal global symbol
+* N_NSYMS:: Number of symbols
+* N_NOMAP:: No DST map
+* N_M2C:: Modula-2 compilation unit
+* N_BROWS:: Path to .cb file for Sun source code browser
+* N_DEFD:: GNU Modula2 definition module dependency
+* N_EHDECL:: GNU C++ exception variable
+* N_MOD2:: Modula2 information "for imc"
+* N_CATCH:: GNU C++ "catch" clause
+* N_SSYM:: Structure or union element
+* N_SCOPE:: Modula2 scope information (Sun only)
+* Gould:: non-base register symbols used on Gould systems
+* N_LENG:: Length of preceding entry
+@end menu
+
+@node N_PC
+@section N_PC
+
+@deffn @code{.stabs} N_PC
+@findex N_PC
+Global symbol (for Pascal).
+
+@example
+"name" -> "symbol_name" <<?>>
+value -> supposedly the line number (stab.def is skeptical)
+@end example
+
+@display
+@file{stabdump.c} says:
+
+global pascal symbol: name,,0,subtype,line
+<< subtype? >>
+@end display
+@end deffn
+
+@node N_NSYMS
+@section N_NSYMS
+
+@deffn @code{.stabn} N_NSYMS
+@findex N_NSYMS
+Number of symbols (according to Ultrix V4.0).
+
+@display
+ 0, files,,funcs,lines (stab.def)
+@end display
+@end deffn
+
+@node N_NOMAP
+@section N_NOMAP
+
+@deffn @code{.stabs} N_NOMAP
+@findex N_NOMAP
+No DST map for symbol (according to Ultrix V4.0). I think this means a
+variable has been optimized out.
+
+@display
+ name, ,0,type,ignored (stab.def)
+@end display
+@end deffn
+
+@node N_M2C
+@section N_M2C
+
+@deffn @code{.stabs} N_M2C
+@findex N_M2C
+Modula-2 compilation unit.
+
+@example
+"string" -> "unit_name,unit_time_stamp[,code_time_stamp]"
+desc -> unit_number
+value -> 0 (main unit)
+ 1 (any other unit)
+@end example
+
+See @cite{Dbx and Dbxtool Interfaces}, 2nd edition, by Sun, 1988, for
+more information.
+
+@end deffn
+
+@node N_BROWS
+@section N_BROWS
+
+@deffn @code{.stabs} N_BROWS
+@findex N_BROWS
+Sun source code browser, path to @file{.cb} file
+
+<<?>>
+"path to associated @file{.cb} file"
+
+Note: N_BROWS has the same value as N_BSLINE.
+@end deffn
+
+@node N_DEFD
+@section N_DEFD
+
+@deffn @code{.stabn} N_DEFD
+@findex N_DEFD
+GNU Modula2 definition module dependency.
+
+GNU Modula-2 definition module dependency. The value is the
+modification time of the definition file. The other field is non-zero
+if it is imported with the GNU M2 keyword @code{%INITIALIZE}. Perhaps
+@code{N_M2C} can be used if there are enough empty fields?
+@end deffn
+
+@node N_EHDECL
+@section N_EHDECL
+
+@deffn @code{.stabs} N_EHDECL
+@findex N_EHDECL
+GNU C++ exception variable <<?>>.
+
+"@var{string} is variable name"
+
+Note: conflicts with @code{N_MOD2}.
+@end deffn
+
+@node N_MOD2
+@section N_MOD2
+
+@deffn @code{.stab?} N_MOD2
+@findex N_MOD2
+Modula2 info "for imc" (according to Ultrix V4.0)
+
+Note: conflicts with @code{N_EHDECL} <<?>>
+@end deffn
+
+@node N_CATCH
+@section N_CATCH
+
+@deffn @code{.stabn} N_CATCH
+@findex N_CATCH
+GNU C++ @code{catch} clause
+
+GNU C++ @code{catch} clause. The value is its address. The desc field
+is nonzero if this entry is immediately followed by a @code{CAUGHT} stab
+saying what exception was caught. Multiple @code{CAUGHT} stabs means
+that multiple exceptions can be caught here. If desc is 0, it means all
+exceptions are caught here.
+@end deffn
+
+@node N_SSYM
+@section N_SSYM
+
+@deffn @code{.stabn} N_SSYM
+@findex N_SSYM
+Structure or union element.
+
+The value is the offset in the structure.
+
+<<?looking at structs and unions in C I didn't see these>>
+@end deffn
+
+@node N_SCOPE
+@section N_SCOPE
+
+@deffn @code{.stab?} N_SCOPE
+@findex N_SCOPE
+Modula2 scope information (Sun linker)
+<<?>>
+@end deffn
+
+@node Gould
+@section Non-base registers on Gould systems
+
+@deffn @code{.stab?} N_NBTEXT
+@deffnx @code{.stab?} N_NBDATA
+@deffnx @code{.stab?} N_NBBSS
+@deffnx @code{.stab?} N_NBSTS
+@deffnx @code{.stab?} N_NBLCS
+@findex N_NBTEXT
+@findex N_NBDATA
+@findex N_NBBSS
+@findex N_NBSTS
+@findex N_NBLCS
+These are used on Gould systems for non-base registers syms.
+
+However, the following values are not the values used by Gould; they are
+the values which GNU has been documenting for these values for a long
+time, without actually checking what Gould uses. I include these values
+only because perhaps some someone actually did something with the GNU
+information (I hope not, why GNU knowingly assigned wrong values to
+these in the header file is a complete mystery to me).
+
+@example
+240 0xf0 N_NBTEXT ??
+242 0xf2 N_NBDATA ??
+244 0xf4 N_NBBSS ??
+246 0xf6 N_NBSTS ??
+248 0xf8 N_NBLCS ??
+@end example
+@end deffn
+
+@node N_LENG
+@section N_LENG
+
+@deffn @code{.stabn} N_LENG
+@findex N_LENG
+Second symbol entry containing a length-value for the preceding entry.
+The value is the length.
+@end deffn
+
+@node Questions
+@appendix Questions and Anomalies
+
+@itemize @bullet
+@item
+@c I think this is changed in GCC 2.4.5 to put the line number there.
+For GNU C stabs defining local and global variables (@code{N_LSYM} and
+@code{N_GSYM}), the desc field is supposed to contain the source
+line number on which the variable is defined. In reality the desc
+field is always 0. (This behavior is defined in @file{dbxout.c} and
+putting a line number in desc is controlled by @samp{#ifdef
+WINNING_GDB}, which defaults to false). GDB supposedly uses this
+information if you say @samp{list @var{var}}. In reality, @var{var} can
+be a variable defined in the program and GDB says @samp{function
+@var{var} not defined}.
+
+@item
+In GNU C stabs, there seems to be no way to differentiate tag types:
+structures, unions, and enums (symbol descriptor @samp{T}) and typedefs
+(symbol descriptor @samp{t}) defined at file scope from types defined locally
+to a procedure or other more local scope. They all use the @code{N_LSYM}
+stab type. Types defined at procedure scope are emited after the
+@code{N_RBRAC} of the preceding function and before the code of the
+procedure in which they are defined. This is exactly the same as
+types defined in the source file between the two procedure bodies.
+GDB overcompensates by placing all types in block #1, the block for
+symbols of file scope. This is true for default, @samp{-ansi} and
+@samp{-traditional} compiler options. (Bugs gcc/1063, gdb/1066.)
+
+@item
+What ends the procedure scope? Is it the proc block's @code{N_RBRAC} or the
+next @code{N_FUN}? (I believe its the first.)
+
+@item
+@c FIXME: This should go with the other stuff about global variables.
+Global variable stabs don't have location information. This comes
+from the external symbol for the same variable. The external symbol
+has a leading underbar on the _name of the variable and the stab does
+not. How do we know these two symbol table entries are talking about
+the same symbol when their names are different? (Answer: the debugger
+knows that external symbols have leading underbars).
+
+@c FIXME: This is absurdly vague; there all kinds of differences, some
+@c of which are the same between gnu & sun, and some of which aren't.
+@c In particular, I'm pretty sure GCC works with Sun dbx by default.
+@c @item
+@c Can GCC be configured to output stabs the way the Sun compiler
+@c does, so that their native debugging tools work? <NO?> It doesn't by
+@c default. GDB reads either format of stab. (GCC or SunC). How about
+@c dbx?
+@end itemize
+
+@node XCOFF Differences
+@appendix Differences Between GNU Stabs in a.out and GNU Stabs in XCOFF
+
+@c FIXME: Merge *all* these into the main body of the document.
+The AIX/RS6000 native object file format is XCOFF with stabs. This
+appendix only covers those differences which are not covered in the main
+body of this document.
+
+@itemize @bullet
+@item
+BSD a.out stab types correspond to AIX XCOFF storage classes. In general
+the mapping is @code{N_@var{stabtype}} becomes @code{C_@var{stabtype}}.
+Some stab types in a.out are not supported in XCOFF; most of these use
+@code{C_DECL}.
+
+@c FIXME: I think they are trying to say something about whether the
+@c assembler defaults the value to the location counter.
+@item
+If the XCOFF stab is an @code{N_FUN} (@code{C_FUN}) then follow the
+string field with @samp{,.} instead of just @samp{,}.
+@end itemize
+
+I think that's it for @file{.s} file differences. They could stand to be
+better presented. This is just a list of what I have noticed so far.
+There are a @emph{lot} of differences in the information in the symbol
+tables of the executable and object files.
+
+Mapping of a.out stab types to XCOFF storage classes:
+
+@example
+stab type storage class
+-------------------------------
+N_GSYM C_GSYM
+N_FNAME unused
+N_FUN C_FUN
+N_STSYM C_STSYM
+N_LCSYM C_STSYM
+N_MAIN unknown
+N_PC unknown
+N_RSYM C_RSYM
+unknown C_RPSYM
+N_M2C unknown
+N_SLINE unknown
+N_DSLINE unknown
+N_BSLINE unknown
+N_BROWSE unchanged
+N_CATCH unknown
+N_SSYM unknown
+N_SO unknown
+N_LSYM C_LSYM
+various C_DECL
+N_BINCL unknown
+N_SOL unknown
+N_PSYM C_PSYM
+N_EINCL unknown
+N_ENTRY C_ENTRY
+N_LBRAC unknown
+N_EXCL unknown
+N_SCOPE unknown
+N_RBRAC unknown
+N_BCOMM C_BCOMM
+N_ECOMM C_ECOMM
+N_ECOML C_ECOML
+
+N_LENG unknown
+@end example
+
+@node Sun Differences
+@appendix Differences Between GNU Stabs and Sun Native Stabs
+
+@c FIXME: Merge all this stuff into the main body of the document.
+
+@itemize @bullet
+@item
+GNU C stabs define @emph{all} types, file or procedure scope, as
+@code{N_LSYM}. Sun doc talks about using @code{N_GSYM} too.
+
+@item
+Sun C stabs use type number pairs in the format
+(@var{file-number},@var{type-number}) where @var{file-number} is a
+number starting with 1 and incremented for each sub-source file in the
+compilation. @var{type-number} is a number starting with 1 and
+incremented for each new type defined in the compilation. GNU C stabs
+use the type number alone, with no source file number.
+@end itemize
+
+@node Stab Sections
+@appendix Using Stabs in Their Own Sections
+
+Many object file formats allow tools to create object files with custom
+sections containing any arbitrary data. For any such object file
+format, stabs can be embedded in special sections. This is how stabs
+are used with ELF and SOM, and aside from ECOFF and XCOFF, is how stabs
+are used with COFF.
+
+@menu
+* Stab Section Basics:: How to embed stabs in sections
+* ELF Linker Relocation:: Sun ELF hacks
+@end menu
+
+@node Stab Section Basics
+@appendixsec How to Embed Stabs in Sections
+
+The assembler creates two custom sections, a section named @code{.stab}
+which contains an array of fixed length structures, one struct per stab,
+and a section named @code{.stabstr} containing all the variable length
+strings that are referenced by stabs in the @code{.stab} section. The
+byte order of the stabs binary data depends on the object file format.
+For ELF, it matches the byte order of the ELF file itself, as determined
+from the @code{EI_DATA} field in the @code{e_ident} member of the ELF
+header. For SOM, it is always big-endian (is this true??? FIXME). For
+COFF, it matches the byte order of the COFF headers. The meaning of the
+fields is the same as for a.out (@pxref{Symbol Table Format}), except
+that the @code{n_strx} field is relative to the strings for the current
+compilation unit (which can be found using the synthetic N_UNDF stab
+described below), rather than the entire string table.
+
+The first stab in the @code{.stab} section for each compilation unit is
+synthetic, generated entirely by the assembler, with no corresponding
+@code{.stab} directive as input to the assembler. This stab contains
+the following fields:
+
+@table @code
+@item n_strx
+Offset in the @code{.stabstr} section to the source filename.
+
+@item n_type
+@code{N_UNDF}.
+
+@item n_other
+Unused field, always zero.
+This may eventually be used to hold overflows from the count in
+the @code{n_desc} field.
+
+@item n_desc
+Count of upcoming symbols, i.e., the number of remaining stabs for this
+source file.
+
+@item n_value
+Size of the string table fragment associated with this source file, in
+bytes.
+@end table
+
+The @code{.stabstr} section always starts with a null byte (so that string
+offsets of zero reference a null string), followed by random length strings,
+each of which is null byte terminated.
+
+The ELF section header for the @code{.stab} section has its
+@code{sh_link} member set to the section number of the @code{.stabstr}
+section, and the @code{.stabstr} section has its ELF section
+header @code{sh_type} member set to @code{SHT_STRTAB} to mark it as a
+string table. SOM and COFF have no way of linking the sections together
+or marking them as string tables.
+
+For COFF, the @code{.stab} and @code{.stabstr} sections are simply
+concatenated by the linker. GDB then uses the @code{n_desc} fields to
+figure out the extent of the original sections. Similarly, the
+@code{n_value} fields of the header symbols are added together in order
+to get the actual position of the strings in a desired @code{.stabstr}
+section. Although this design obviates any need for the linker to relocate
+or otherwise manipulate @code{.stab} and @code{.stabstr} sections, it also
+requires some care to ensure that the offsets are calculated correctly.
+For instance, if the linker were to pad in between the @code{.stabstr}
+sections before concatenating, then the offsets to strings in the middle
+of the executable's @code{.stabstr} section would be wrong.
+
+@node ELF Linker Relocation
+@appendixsec Having the Linker Relocate Stabs in ELF
+
+This section describes some Sun hacks for Stabs in ELF; it does not
+apply to COFF or SOM.
+
+To keep linking fast, you don't want the linker to have to relocate very
+many stabs. Making sure this is done for @code{N_SLINE},
+@code{N_RBRAC}, and @code{N_LBRAC} stabs is the most important thing
+(see the descriptions of those stabs for more information). But Sun's
+stabs in ELF has taken this further, to make all addresses in the
+@code{n_value} field (functions and static variables) relative to the
+source file. For the @code{N_SO} symbol itself, Sun simply omits the
+address. To find the address of each section corresponding to a given
+source file, the compiler puts out symbols giving the address of each
+section for a given source file. Since these are ELF (not stab)
+symbols, the linker relocates them correctly without having to touch the
+stabs section. They are named @code{Bbss.bss} for the bss section,
+@code{Ddata.data} for the data section, and @code{Drodata.rodata} for
+the rodata section. For the text section, there is no such symbol (but
+there should be, see below). For an example of how these symbols work,
+@xref{Stab Section Transformations}. GCC does not provide these symbols;
+it instead relies on the stabs getting relocated. Thus addresses which
+would normally be relative to @code{Bbss.bss}, etc., are already
+relocated. The Sun linker provided with Solaris 2.2 and earlier
+relocates stabs using normal ELF relocation information, as it would do
+for any section. Sun has been threatening to kludge their linker to not
+do this (to speed up linking), even though the correct way to avoid
+having the linker do these relocations is to have the compiler no longer
+output relocatable values. Last I heard they had been talked out of the
+linker kludge. See Sun point patch 101052-01 and Sun bug 1142109. With
+the Sun compiler this affects @samp{S} symbol descriptor stabs
+(@pxref{Statics}) and functions (@pxref{Procedures}). In the latter
+case, to adopt the clean solution (making the value of the stab relative
+to the start of the compilation unit), it would be necessary to invent a
+@code{Ttext.text} symbol, analogous to the @code{Bbss.bss}, etc.,
+symbols. I recommend this rather than using a zero value and getting
+the address from the ELF symbols.
+
+Finding the correct @code{Bbss.bss}, etc., symbol is difficult, because
+the linker simply concatenates the @code{.stab} sections from each
+@file{.o} file without including any information about which part of a
+@code{.stab} section comes from which @file{.o} file. The way GDB does
+this is to look for an ELF @code{STT_FILE} symbol which has the same
+name as the last component of the file name from the @code{N_SO} symbol
+in the stabs (for example, if the file name is @file{../../gdb/main.c},
+it looks for an ELF @code{STT_FILE} symbol named @code{main.c}). This
+loses if different files have the same name (they could be in different
+directories, a library could have been copied from one system to
+another, etc.). It would be much cleaner to have the @code{Bbss.bss}
+symbols in the stabs themselves. Having the linker relocate them there
+is no more work than having the linker relocate ELF symbols, and it
+solves the problem of having to associate the ELF and stab symbols.
+However, no one has yet designed or implemented such a scheme.
+
+@node Symbol Types Index
+@unnumbered Symbol Types Index
+
+@printindex fn
+
+@contents
+@bye
diff --git a/gnu/usr.bin/gdb/gdb/COPYING b/gnu/usr.bin/gdb/gdb/COPYING
new file mode 100644
index 0000000..a43ea21
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/COPYING
@@ -0,0 +1,339 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 675 Mass Ave, Cambridge, MA 02139, USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ Appendix: How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) 19yy <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) 19yy name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/gnu/usr.bin/gdb/gdb/Makefile b/gnu/usr.bin/gdb/gdb/Makefile
new file mode 100644
index 0000000..68a86ae
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/Makefile
@@ -0,0 +1,75 @@
+PROG = gdb
+BINDIR= /usr/bin
+CLEANFILES+= y.tab.h c-exp.tab.c ch-exp.tab.c m2-exp.tab.c
+SRCS = annotate.c blockframe.c breakpoint.c buildsym.c c-lang.c \
+ c-typeprint.c c-valprint.c ch-lang.c ch-typeprint.c \
+ ch-valprint.c coffread.c command.c complaints.c copying.c core.c \
+ coredep.c corelow.c cp-valprint.c \
+ dcache.c dbxread.c demangle.c disassemble.c dis-buf.c dwarfread.c \
+ elfread.c environ.c eval.c exec.c expprint.c \
+ findvar.c fork-child.c freebsd-nat.c gdbtypes.c i386-dis.c \
+ i386-pinsn.c i386-tdep.c infcmd.c inflow.c infptrace.c \
+ infrun.c inftarg.c init.c kcorelow.c language.c \
+ m2-lang.c m2-typeprint.c m2-valprint.c main.c maint.c \
+ mem-break.c minsyms.c objfiles.c parse.c \
+ printcmd.c remote.c remote-utils.c solib.c source.c \
+ stabsread.c stack.c symfile.c symmisc.c \
+ symtab.c target.c thread.c top.c \
+ typeprint.c utils.c valarith.c valops.c \
+ valprint.c values.c version.c serial.c ser-unix.c mdebugread.c\
+ c-exp.tab.c ch-exp.tab.c m2-exp.tab.c compat_que.c
+
+c-exp.tab.c: $(.CURDIR)/c-exp.y
+ yacc -d -p c_ $(.CURDIR)/c-exp.y
+ sed -e '/extern.*malloc/d' -e '/extern.*realloc/d' -e '/extern.*free/d' \
+ -e '/include.*malloc.h/d' -e 's/malloc/xmalloc/g' \
+ -e 's/realloc/xrealloc/g' < y.tab.c > c-exp.new
+ rm y.tab.c
+ mv c-exp.new ./c-exp.tab.c
+
+ch-exp.tab.c: $(.CURDIR)/ch-exp.y
+ yacc -d -p ch_ $(.CURDIR)/ch-exp.y
+ sed -e '/extern.*malloc/d' -e '/extern.*realloc/d' -e '/extern.*free/d' \
+ -e '/include.*malloc.h/d' -e 's/malloc/xmalloc/g' \
+ -e 's/realloc/xrealloc/g' < y.tab.c > ch-exp.new
+ rm y.tab.c
+ mv ch-exp.new ./ch-exp.tab.c
+
+m2-exp.tab.c: $(.CURDIR)/m2-exp.y
+ yacc -d -p m2_ $(.CURDIR)/m2-exp.y
+ sed -e '/extern.*malloc/d' -e '/extern.*realloc/d' -e '/extern.*free/d' \
+ -e '/include.*malloc.h/d' -e 's/malloc/xmalloc/g' \
+ -e 's/realloc/xrealloc/g' < y.tab.c > m2-exp.new
+ rm y.tab.c
+ mv m2-exp.new ./m2-exp.tab.c
+
+
+CFLAGS+= -I$(.CURDIR)/. -I${DESTDIR}/usr/include/readline -I$(.CURDIR)/../bfd
+DPADD+= ${LIBREADLINE} ${LIBTERMCAP} ${LIBGNUREGEX}
+LDADD+= -lreadline -ltermcap -lgnuregex
+
+.if exists(${.CURDIR}/../libiberty/obj)
+LDADD+= -L${.CURDIR}/../libiberty/obj -liberty
+DPADD+= ${.CURDIR}/../libiberty/obj/libiberty.a
+.else
+LDADD+= -L${.CURDIR}/../libiberty/ -liberty
+DPADD+= ${.CURDIR}/../libiberty/libiberty.a
+.endif
+
+.if exists(${.CURDIR}/../bfd/obj)
+LDADD+= -L${.CURDIR}/../bfd/obj -lbfd
+DPADD+= ${.CURDIR}/../bfd/obj/libbfd.a
+.else
+LDADD+= -L${.CURDIR}/../bfd/ -lbfd
+DPADD+= ${.CURDIR}/../bfd/libbfd.a
+.endif
+
+.if exists(${.CURDIR}/../mmalloc/obj)
+LDADD+= -L${.CURDIR}/../mmalloc/obj -lmmalloc
+DPADD+= ${.CURDIR}/../mmalloc/obj/libmmalloc.a
+.else
+LDADD+= -L${.CURDIR}/../mmalloc/ -lmmalloc
+DPADD+= ${.CURDIR}/../mmalloc/libmmalloc.a
+.endif
+
+.include <bsd.prog.mk>
diff --git a/gnu/usr.bin/gdb/gdb/annotate.c b/gnu/usr.bin/gdb/gdb/annotate.c
new file mode 100644
index 0000000..0a73fb5
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/annotate.c
@@ -0,0 +1,521 @@
+/* Annotation routines for GDB.
+ Copyright 1986, 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "defs.h"
+#include "annotate.h"
+#include "value.h"
+#include "target.h"
+#include "gdbtypes.h"
+
+static void print_value_flags PARAMS ((struct type *));
+
+static void
+print_value_flags (t)
+ struct type *t;
+{
+ if (can_dereference (t))
+ printf_filtered ("*");
+ else
+ printf_filtered ("-");
+}
+
+void
+breakpoints_changed ()
+{
+ if (annotation_level > 1)
+ {
+ target_terminal_ours ();
+ printf_unfiltered ("\n\032\032breakpoints-invalid\n");
+ }
+}
+
+void
+annotate_breakpoint (num)
+ int num;
+{
+ if (annotation_level > 1)
+ printf_filtered ("\n\032\032breakpoint %d\n", num);
+}
+
+void
+annotate_watchpoint (num)
+ int num;
+{
+ if (annotation_level > 1)
+ printf_filtered ("\n\032\032watchpoint %d\n", num);
+}
+
+void
+annotate_starting ()
+{
+ if (annotation_level > 1)
+ printf_filtered ("\n\032\032starting\n");
+}
+
+void
+annotate_stopped ()
+{
+ if (annotation_level > 1)
+ printf_filtered ("\n\032\032stopped\n");
+}
+
+void
+annotate_exited (exitstatus)
+ int exitstatus;
+{
+ if (annotation_level > 1)
+ printf_filtered ("\n\032\032exited %d\n", exitstatus);
+}
+
+void
+annotate_signalled ()
+{
+ if (annotation_level > 1)
+ printf_filtered ("\n\032\032signalled\n");
+}
+
+void
+annotate_signal_name ()
+{
+ if (annotation_level > 1)
+ printf_filtered ("\n\032\032signal-name\n");
+}
+
+void
+annotate_signal_name_end ()
+{
+ if (annotation_level > 1)
+ printf_filtered ("\n\032\032signal-name-end\n");
+}
+
+void
+annotate_signal_string ()
+{
+ if (annotation_level > 1)
+ printf_filtered ("\n\032\032signal-string\n");
+}
+
+void
+annotate_signal_string_end ()
+{
+ if (annotation_level > 1)
+ printf_filtered ("\n\032\032signal-string-end\n");
+}
+
+void
+annotate_signal ()
+{
+ if (annotation_level > 1)
+ printf_filtered ("\n\032\032signal\n");
+}
+
+void
+annotate_breakpoints_headers ()
+{
+ if (annotation_level > 1)
+ printf_filtered ("\n\032\032breakpoints-headers\n");
+}
+
+void
+annotate_field (num)
+ int num;
+{
+ if (annotation_level > 1)
+ printf_filtered ("\n\032\032field %d\n", num);
+}
+
+void
+annotate_breakpoints_table ()
+{
+ if (annotation_level > 1)
+ printf_filtered ("\n\032\032breakpoints-table\n");
+}
+
+void
+annotate_record ()
+{
+ if (annotation_level > 1)
+ printf_filtered ("\n\032\032record\n");
+}
+
+void
+annotate_breakpoints_table_end ()
+{
+ if (annotation_level > 1)
+ printf_filtered ("\n\032\032breakpoints-table-end\n");
+}
+
+void
+annotate_frames_invalid ()
+{
+ if (annotation_level > 1)
+ {
+ target_terminal_ours ();
+ printf_unfiltered ("\n\032\032frames-invalid\n");
+ }
+}
+
+void
+annotate_field_begin (type)
+ struct type *type;
+{
+ if (annotation_level > 1)
+ {
+ printf_filtered ("\n\032\032field-begin ");
+ print_value_flags (type);
+ printf_filtered ("\n");
+ }
+}
+
+void
+annotate_field_name_end ()
+{
+ if (annotation_level > 1)
+ printf_filtered ("\n\032\032field-name-end\n");
+}
+
+void
+annotate_field_value ()
+{
+ if (annotation_level > 1)
+ printf_filtered ("\n\032\032field-value\n");
+}
+
+void
+annotate_field_end ()
+{
+ if (annotation_level > 1)
+ printf_filtered ("\n\032\032field-end\n");
+}
+
+void
+annotate_quit ()
+{
+ if (annotation_level > 1)
+ printf_filtered ("\n\032\032quit\n");
+}
+
+void
+annotate_error ()
+{
+ if (annotation_level > 1)
+ printf_filtered ("\n\032\032error\n");
+}
+
+void
+annotate_error_begin ()
+{
+ if (annotation_level > 1)
+ fprintf_filtered (gdb_stderr, "\n\032\032error-begin\n");
+}
+
+void
+annotate_value_history_begin (histindex, type)
+ int histindex;
+ struct type *type;
+{
+ if (annotation_level > 1)
+ {
+ printf_filtered ("\n\032\032value-history-begin %d ", histindex);
+ print_value_flags (type);
+ printf_filtered ("\n");
+ }
+}
+
+void
+annotate_value_begin (type)
+ struct type *type;
+{
+ if (annotation_level > 1)
+ {
+ printf_filtered ("\n\032\032value-begin ");
+ print_value_flags (type);
+ printf_filtered ("\n");
+ }
+}
+
+void
+annotate_value_history_value ()
+{
+ if (annotation_level > 1)
+ printf_filtered ("\n\032\032value-history-value\n");
+}
+
+void
+annotate_value_history_end ()
+{
+ if (annotation_level > 1)
+ printf_filtered ("\n\032\032value-history-end\n");
+}
+
+void
+annotate_value_end ()
+{
+ if (annotation_level > 1)
+ printf_filtered ("\n\032\032value-end\n");
+}
+
+void
+annotate_display_begin ()
+{
+ if (annotation_level > 1)
+ printf_filtered ("\n\032\032display-begin\n");
+}
+
+void
+annotate_display_number_end ()
+{
+ if (annotation_level > 1)
+ printf_filtered ("\n\032\032display-number-end\n");
+}
+
+void
+annotate_display_format ()
+{
+ if (annotation_level > 1)
+ printf_filtered ("\n\032\032display-format\n");
+}
+
+void
+annotate_display_expression ()
+{
+ if (annotation_level > 1)
+ printf_filtered ("\n\032\032display-expression\n");
+}
+
+void
+annotate_display_expression_end ()
+{
+ if (annotation_level > 1)
+ printf_filtered ("\n\032\032display-expression-end\n");
+}
+
+void
+annotate_display_value ()
+{
+ if (annotation_level > 1)
+ printf_filtered ("\n\032\032display-value\n");
+}
+
+void
+annotate_display_end ()
+{
+ if (annotation_level > 1)
+ printf_filtered ("\n\032\032display-end\n");
+}
+
+void
+annotate_arg_begin ()
+{
+ if (annotation_level > 1)
+ printf_filtered ("\n\032\032arg-begin\n");
+}
+
+void
+annotate_arg_name_end ()
+{
+ if (annotation_level > 1)
+ printf_filtered ("\n\032\032arg-name-end\n");
+}
+
+void
+annotate_arg_value (type)
+ struct type *type;
+{
+ if (annotation_level > 1)
+ {
+ printf_filtered ("\n\032\032arg-value ");
+ print_value_flags (type);
+ printf_filtered ("\n");
+ }
+}
+
+void
+annotate_arg_end ()
+{
+ if (annotation_level > 1)
+ printf_filtered ("\n\032\032arg-end\n");
+}
+
+void
+annotate_source (filename, line, character, mid, pc)
+ char *filename;
+ int line;
+ int character;
+ int mid;
+ CORE_ADDR pc;
+{
+ if (annotation_level > 1)
+ printf_filtered ("\n\032\032source ");
+ else
+ printf_filtered ("\032\032");
+
+ printf_filtered ("%s:%d:%d:%s:", filename,
+ line, character,
+ mid ? "middle" : "beg");
+ print_address_numeric (pc, 0, gdb_stdout);
+ printf_filtered ("\n");
+}
+
+void
+annotate_frame_begin (level, pc)
+ int level;
+ CORE_ADDR pc;
+{
+ if (annotation_level > 1)
+ {
+ printf_filtered ("\n\032\032frame-begin %d ", level);
+ print_address_numeric (pc, 0, gdb_stdout);
+ printf_filtered ("\n");
+ }
+}
+
+void
+annotate_function_call ()
+{
+ if (annotation_level > 1)
+ printf_filtered ("\n\032\032function-call\n");
+}
+
+void
+annotate_signal_handler_caller ()
+{
+ if (annotation_level > 1)
+ printf_filtered ("\n\032\032signal-handler-caller\n");
+}
+
+void
+annotate_frame_address ()
+{
+ if (annotation_level > 1)
+ printf_filtered ("\n\032\032frame-address\n");
+}
+
+void
+annotate_frame_address_end ()
+{
+ if (annotation_level > 1)
+ printf_filtered ("\n\032\032frame-address-end\n");
+}
+
+void
+annotate_frame_function_name ()
+{
+ if (annotation_level > 1)
+ printf_filtered ("\n\032\032frame-function-name\n");
+}
+
+void
+annotate_frame_args ()
+{
+ if (annotation_level > 1)
+ printf_filtered ("\n\032\032frame-args\n");
+}
+
+void
+annotate_frame_source_begin ()
+{
+ if (annotation_level > 1)
+ printf_filtered ("\n\032\032frame-source-begin\n");
+}
+
+void
+annotate_frame_source_file ()
+{
+ if (annotation_level > 1)
+ printf_filtered ("\n\032\032frame-source-file\n");
+}
+
+void
+annotate_frame_source_file_end ()
+{
+ if (annotation_level > 1)
+ printf_filtered ("\n\032\032frame-source-file-end\n");
+}
+
+void
+annotate_frame_source_line ()
+{
+ if (annotation_level > 1)
+ printf_filtered ("\n\032\032frame-source-line\n");
+}
+
+void
+annotate_frame_source_end ()
+{
+ if (annotation_level > 1)
+ printf_filtered ("\n\032\032frame-source-end\n");
+}
+
+void
+annotate_frame_where ()
+{
+ if (annotation_level > 1)
+ printf_filtered ("\n\032\032frame-where\n");
+}
+
+void
+annotate_frame_end ()
+{
+ if (annotation_level > 1)
+ printf_filtered ("\n\032\032frame-end\n");
+}
+
+void
+annotate_array_section_begin (index, elttype)
+ int index;
+ struct type *elttype;
+{
+ if (annotation_level > 1)
+ {
+ printf_filtered ("\n\032\032array-section-begin %d ", index);
+ print_value_flags (elttype);
+ printf_filtered ("\n");
+ }
+}
+
+void
+annotate_elt_rep (repcount)
+ unsigned int repcount;
+{
+ if (annotation_level > 1)
+ printf_filtered ("\n\032\032elt-rep %u\n", repcount);
+}
+
+void
+annotate_elt_rep_end ()
+{
+ if (annotation_level > 1)
+ printf_filtered ("\n\032\032elt-rep-end\n");
+}
+
+void
+annotate_elt ()
+{
+ if (annotation_level > 1)
+ printf_filtered ("\n\032\032elt\n");
+}
+
+void
+annotate_array_section_end ()
+{
+ if (annotation_level > 1)
+ printf_filtered ("\n\032\032array-section-end\n");
+}
+
diff --git a/gnu/usr.bin/gdb/gdb/annotate.h b/gnu/usr.bin/gdb/gdb/annotate.h
new file mode 100644
index 0000000..0ec9765
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/annotate.h
@@ -0,0 +1,95 @@
+/* Annotation routines for GDB.
+ Copyright 1986, 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+extern void breakpoints_changed PARAMS ((void));
+
+extern void annotate_breakpoint PARAMS ((int));
+extern void annotate_watchpoint PARAMS ((int));
+extern void annotate_starting PARAMS ((void));
+extern void annotate_stopped PARAMS ((void));
+extern void annotate_exited PARAMS ((int));
+extern void annotate_signalled PARAMS ((void));
+extern void annotate_signal_name PARAMS ((void));
+extern void annotate_signal_name_end PARAMS ((void));
+extern void annotate_signal_string PARAMS ((void));
+extern void annotate_signal_string_end PARAMS ((void));
+extern void annotate_signal PARAMS ((void));
+
+extern void annotate_breakpoints_headers PARAMS ((void));
+extern void annotate_field PARAMS ((int));
+extern void annotate_breakpoints_table PARAMS ((void));
+extern void annotate_record PARAMS ((void));
+extern void annotate_breakpoints_table_end PARAMS ((void));
+
+extern void annotate_frames_invalid PARAMS ((void));
+
+#ifdef __STDC__
+struct type;
+#endif
+
+extern void annotate_field_begin PARAMS ((struct type *));
+extern void annotate_field_name_end PARAMS ((void));
+extern void annotate_field_value PARAMS ((void));
+extern void annotate_field_end PARAMS ((void));
+
+extern void annotate_quit PARAMS ((void));
+extern void annotate_error PARAMS ((void));
+extern void annotate_error_begin PARAMS ((void));
+
+extern void annotate_value_history_begin PARAMS ((int, struct type *));
+extern void annotate_value_begin PARAMS ((struct type *));
+extern void annotate_value_history_value PARAMS ((void));
+extern void annotate_value_history_end PARAMS ((void));
+extern void annotate_value_end PARAMS ((void));
+
+extern void annotate_display_begin PARAMS ((void));
+extern void annotate_display_number_end PARAMS ((void));
+extern void annotate_display_format PARAMS ((void));
+extern void annotate_display_expression PARAMS ((void));
+extern void annotate_display_expression_end PARAMS ((void));
+extern void annotate_display_value PARAMS ((void));
+extern void annotate_display_end PARAMS ((void));
+
+extern void annotate_arg_begin PARAMS ((void));
+extern void annotate_arg_name_end PARAMS ((void));
+extern void annotate_arg_value PARAMS ((struct type *));
+extern void annotate_arg_end PARAMS ((void));
+
+extern void annotate_source PARAMS ((char *, int, int, int, CORE_ADDR));
+
+extern void annotate_frame_begin PARAMS ((int, CORE_ADDR));
+extern void annotate_function_call PARAMS ((void));
+extern void annotate_signal_handler_caller PARAMS ((void));
+extern void annotate_frame_address PARAMS ((void));
+extern void annotate_frame_address_end PARAMS ((void));
+extern void annotate_frame_function_name PARAMS ((void));
+extern void annotate_frame_args PARAMS ((void));
+extern void annotate_frame_source_begin PARAMS ((void));
+extern void annotate_frame_source_file PARAMS ((void));
+extern void annotate_frame_source_file_end PARAMS ((void));
+extern void annotate_frame_source_line PARAMS ((void));
+extern void annotate_frame_source_end PARAMS ((void));
+extern void annotate_frame_where PARAMS ((void));
+extern void annotate_frame_end PARAMS ((void));
+
+extern void annotate_array_section_begin PARAMS ((int, struct type *));
+extern void annotate_elt_rep PARAMS ((unsigned int));
+extern void annotate_elt_rep_end PARAMS ((void));
+extern void annotate_elt PARAMS ((void));
+extern void annotate_array_section_end PARAMS ((void));
diff --git a/gnu/usr.bin/gdb/gdb/ansidecl.h b/gnu/usr.bin/gdb/gdb/ansidecl.h
new file mode 100644
index 0000000..3c0dcb3
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/ansidecl.h
@@ -0,0 +1,141 @@
+/* ANSI and traditional C compatability macros
+ Copyright 1991, 1992 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* ANSI and traditional C compatibility macros
+
+ ANSI C is assumed if __STDC__ is #defined.
+
+ Macro ANSI C definition Traditional C definition
+ ----- ---- - ---------- ----------- - ----------
+ PTR `void *' `char *'
+ LONG_DOUBLE `long double' `double'
+ VOLATILE `volatile' `'
+ SIGNED `signed' `'
+ PTRCONST `void *const' `char *'
+ ANSI_PROTOTYPES 1 not defined
+
+ CONST is also defined, but is obsolete. Just use const.
+
+ DEFUN (name, arglist, args)
+
+ Defines function NAME.
+
+ ARGLIST lists the arguments, separated by commas and enclosed in
+ parentheses. ARGLIST becomes the argument list in traditional C.
+
+ ARGS list the arguments with their types. It becomes a prototype in
+ ANSI C, and the type declarations in traditional C. Arguments should
+ be separated with `AND'. For functions with a variable number of
+ arguments, the last thing listed should be `DOTS'.
+
+ DEFUN_VOID (name)
+
+ Defines a function NAME, which takes no arguments.
+
+ obsolete -- EXFUN (name, (prototype)) -- obsolete.
+
+ Replaced by PARAMS. Do not use; will disappear someday soon.
+ Was used in external function declarations.
+ In ANSI C it is `NAME PROTOTYPE' (so PROTOTYPE should be enclosed in
+ parentheses). In traditional C it is `NAME()'.
+ For a function that takes no arguments, PROTOTYPE should be `(void)'.
+
+ PARAMS ((args))
+
+ We could use the EXFUN macro to handle prototype declarations, but
+ the name is misleading and the result is ugly. So we just define a
+ simple macro to handle the parameter lists, as in:
+
+ static int foo PARAMS ((int, char));
+
+ This produces: `static int foo();' or `static int foo (int, char);'
+
+ EXFUN would have done it like this:
+
+ static int EXFUN (foo, (int, char));
+
+ but the function is not external...and it's hard to visually parse
+ the function name out of the mess. EXFUN should be considered
+ obsolete; new code should be written to use PARAMS.
+
+ For example:
+ extern int printf PARAMS ((CONST char *format DOTS));
+ int DEFUN(fprintf, (stream, format),
+ FILE *stream AND CONST char *format DOTS) { ... }
+ void DEFUN_VOID(abort) { ... }
+*/
+
+#ifndef _ANSIDECL_H
+
+#define _ANSIDECL_H 1
+
+
+/* Every source file includes this file,
+ so they will all get the switch for lint. */
+/* LINTLIBRARY */
+
+
+#if defined (__STDC__) || defined (_AIX) || (defined (__mips) && defined (_SYSTYPE_SVR4))
+/* All known AIX compilers implement these things (but don't always
+ define __STDC__). The RISC/OS MIPS compiler defines these things
+ in SVR4 mode, but does not define __STDC__. */
+
+#define PTR void *
+#define PTRCONST void *CONST
+#define LONG_DOUBLE long double
+
+#define AND ,
+#define NOARGS void
+#define CONST const
+#define VOLATILE volatile
+#define SIGNED signed
+#define DOTS , ...
+
+#define EXFUN(name, proto) name proto
+#define DEFUN(name, arglist, args) name(args)
+#define DEFUN_VOID(name) name(void)
+
+#define PROTO(type, name, arglist) type name arglist
+#define PARAMS(paramlist) paramlist
+#define ANSI_PROTOTYPES 1
+
+#else /* Not ANSI C. */
+
+#define PTR char *
+#define PTRCONST PTR
+#define LONG_DOUBLE double
+
+#define AND ;
+#define NOARGS
+#define CONST
+#ifndef const /* some systems define it in header files for non-ansi mode */
+#define const
+#endif
+#define VOLATILE
+#define SIGNED
+#define DOTS
+
+#define EXFUN(name, proto) name()
+#define DEFUN(name, arglist, args) name arglist args;
+#define DEFUN_VOID(name) name()
+#define PROTO(type, name, arglist) type name ()
+#define PARAMS(paramlist) ()
+
+#endif /* ANSI C. */
+
+#endif /* ansidecl.h */
diff --git a/gnu/usr.bin/gdb/gdb/aout/aout64.h b/gnu/usr.bin/gdb/gdb/aout/aout64.h
new file mode 100644
index 0000000..59588f7
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/aout/aout64.h
@@ -0,0 +1,473 @@
+/* `a.out' object-file definitions, including extensions to 64-bit fields */
+
+#ifndef __A_OUT_64_H__
+#define __A_OUT_64_H__
+
+/* This is the layout on disk of the 32-bit or 64-bit exec header. */
+
+#ifndef external_exec
+struct external_exec
+{
+ bfd_byte e_info[4]; /* magic number and stuff */
+ bfd_byte e_text[BYTES_IN_WORD]; /* length of text section in bytes */
+ bfd_byte e_data[BYTES_IN_WORD]; /* length of data section in bytes */
+ bfd_byte e_bss[BYTES_IN_WORD]; /* length of bss area in bytes */
+ bfd_byte e_syms[BYTES_IN_WORD]; /* length of symbol table in bytes */
+ bfd_byte e_entry[BYTES_IN_WORD]; /* start address */
+ bfd_byte e_trsize[BYTES_IN_WORD]; /* length of text relocation info */
+ bfd_byte e_drsize[BYTES_IN_WORD]; /* length of data relocation info */
+};
+
+#define EXEC_BYTES_SIZE (4 + BYTES_IN_WORD * 7)
+
+/* Magic numbers for a.out files */
+
+#if ARCH_SIZE==64
+#define OMAGIC 0x1001 /* Code indicating object file */
+#define ZMAGIC 0x1002 /* Code indicating demand-paged executable. */
+#define NMAGIC 0x1003 /* Code indicating pure executable. */
+
+/* There is no 64-bit QMAGIC as far as I know. */
+
+#define N_BADMAG(x) (N_MAGIC(x) != OMAGIC \
+ && N_MAGIC(x) != NMAGIC \
+ && N_MAGIC(x) != ZMAGIC)
+#else
+#define OMAGIC 0407 /* ...object file or impure executable. */
+#define NMAGIC 0410 /* Code indicating pure executable. */
+#define ZMAGIC 0413 /* Code indicating demand-paged executable. */
+#define BMAGIC 0415 /* Used by a b.out object. */
+
+/* This indicates a demand-paged executable with the header in the text.
+ It is used by 386BSD (and variants) and Linux, at least. */
+#define QMAGIC 0314
+# ifndef N_BADMAG
+# define N_BADMAG(x) (N_MAGIC(x) != OMAGIC \
+ && N_MAGIC(x) != NMAGIC \
+ && N_MAGIC(x) != ZMAGIC \
+ && N_MAGIC(x) != QMAGIC)
+# endif /* N_BADMAG */
+#endif
+
+#endif
+
+#ifdef QMAGIC
+#define N_IS_QMAGIC(x) (N_MAGIC (x) == QMAGIC)
+#else
+#define N_IS_QMAGIC(x) (0)
+#endif
+
+/* The difference between PAGE_SIZE and N_SEGSIZE is that PAGE_SIZE is
+ the finest granularity at which you can page something, thus it
+ controls the padding (if any) before the text segment of a ZMAGIC
+ file. N_SEGSIZE is the resolution at which things can be marked as
+ read-only versus read/write, so it controls the padding between the
+ text segment and the data segment (in memory; on disk the padding
+ between them is PAGE_SIZE). PAGE_SIZE and N_SEGSIZE are the same
+ for most machines, but different for sun3. */
+
+/* By default, segment size is constant. But some machines override this
+ to be a function of the a.out header (e.g. machine type). */
+
+#ifndef N_SEGSIZE
+#define N_SEGSIZE(x) SEGMENT_SIZE
+#endif
+
+/* Virtual memory address of the text section.
+ This is getting very complicated. A good reason to discard a.out format
+ for something that specifies these fields explicitly. But til then...
+
+ * OMAGIC and NMAGIC files:
+ (object files: text for "relocatable addr 0" right after the header)
+ start at 0, offset is EXEC_BYTES_SIZE, size as stated.
+ * The text address, offset, and size of ZMAGIC files depend
+ on the entry point of the file:
+ * entry point below TEXT_START_ADDR:
+ (hack for SunOS shared libraries)
+ start at 0, offset is 0, size as stated.
+ * If N_HEADER_IN_TEXT(x) is true (which defaults to being the
+ case when the entry point is EXEC_BYTES_SIZE or further into a page):
+ no padding is needed; text can start after exec header. Sun
+ considers the text segment of such files to include the exec header;
+ for BFD's purposes, we don't, which makes more work for us.
+ start at TEXT_START_ADDR + EXEC_BYTES_SIZE, offset is EXEC_BYTES_SIZE,
+ size as stated minus EXEC_BYTES_SIZE.
+ * If N_HEADER_IN_TEXT(x) is false (which defaults to being the case when
+ the entry point is less than EXEC_BYTES_SIZE into a page (e.g. page
+ aligned)): (padding is needed so that text can start at a page boundary)
+ start at TEXT_START_ADDR, offset PAGE_SIZE, size as stated.
+
+ Specific configurations may want to hardwire N_HEADER_IN_TEXT,
+ for efficiency or to allow people to play games with the entry point.
+ In that case, you would #define N_HEADER_IN_TEXT(x) as 1 for sunos,
+ and as 0 for most other hosts (Sony News, Vax Ultrix, etc).
+ (Do this in the appropriate bfd target file.)
+ (The default is a heuristic that will break if people try changing
+ the entry point, perhaps with the ld -e flag.)
+
+ * QMAGIC is always like a ZMAGIC for which N_HEADER_IN_TEXT is true,
+ and for which the starting address is PAGE_SIZE (or should this be
+ SEGMENT_SIZE?) (TEXT_START_ADDR only applies to ZMAGIC, not to QMAGIC).
+ */
+
+/* This macro is only relevant for ZMAGIC files; QMAGIC always has the header
+ in the text. */
+#ifndef N_HEADER_IN_TEXT
+#define N_HEADER_IN_TEXT(x) (((x).a_entry & (PAGE_SIZE-1)) >= EXEC_BYTES_SIZE)
+#endif
+
+/* Sun shared libraries, not linux. This macro is only relevant for ZMAGIC
+ files. */
+#ifndef N_SHARED_LIB
+#define N_SHARED_LIB(x) ((x).a_entry < TEXT_START_ADDR)
+#endif
+
+/* Returning 0 not TEXT_START_ADDR for OMAGIC and NMAGIC is based on
+ the assumption that we are dealing with a .o file, not an
+ executable. This is necessary for OMAGIC (but means we don't work
+ right on the output from ld -N); more questionable for NMAGIC. */
+
+#ifndef N_TXTADDR
+#define N_TXTADDR(x) \
+ (/* The address of a QMAGIC file is always one page in, */ \
+ /* with the header in the text. */ \
+ N_IS_QMAGIC (x) ? PAGE_SIZE + EXEC_BYTES_SIZE : \
+ N_MAGIC(x) != ZMAGIC ? 0 : /* object file or NMAGIC */\
+ N_SHARED_LIB(x) ? 0 : \
+ N_HEADER_IN_TEXT(x) ? \
+ TEXT_START_ADDR + EXEC_BYTES_SIZE : /* no padding */\
+ TEXT_START_ADDR /* a page of padding */\
+ )
+#endif
+
+/* If N_HEADER_IN_TEXT is not true for ZMAGIC, there is some padding
+ to make the text segment start at a certain boundary. For most
+ systems, this boundary is PAGE_SIZE. But for Linux, in the
+ time-honored tradition of crazy ZMAGIC hacks, it is 1024 which is
+ not what PAGE_SIZE needs to be for QMAGIC. */
+
+#ifndef ZMAGIC_DISK_BLOCK_SIZE
+#define ZMAGIC_DISK_BLOCK_SIZE PAGE_SIZE
+#endif
+
+#define N_DISK_BLOCK_SIZE(x) \
+ (N_MAGIC(x) == ZMAGIC ? ZMAGIC_DISK_BLOCK_SIZE : PAGE_SIZE)
+
+/* Offset in an a.out of the start of the text section. */
+#ifndef N_TXTOFF
+#define N_TXTOFF(x) \
+ (/* For {O,N,Q}MAGIC, no padding. */ \
+ N_MAGIC(x) != ZMAGIC ? EXEC_BYTES_SIZE : \
+ N_SHARED_LIB(x) ? 0 : \
+ N_HEADER_IN_TEXT(x) ? \
+ EXEC_BYTES_SIZE : /* no padding */\
+ ZMAGIC_DISK_BLOCK_SIZE /* a page of padding */\
+ )
+#endif
+/* Size of the text section. It's always as stated, except that we
+ offset it to `undo' the adjustment to N_TXTADDR and N_TXTOFF
+ for ZMAGIC files that nominally include the exec header
+ as part of the first page of text. (BFD doesn't consider the
+ exec header to be part of the text segment.) */
+#ifndef N_TXTSIZE
+#define N_TXTSIZE(x) \
+ (/* For QMAGIC, we don't consider the header part of the text section. */\
+ N_IS_QMAGIC (x) ? (x).a_text - EXEC_BYTES_SIZE : \
+ (N_MAGIC(x) != ZMAGIC || N_SHARED_LIB(x)) ? (x).a_text : \
+ N_HEADER_IN_TEXT(x) ? \
+ (x).a_text - EXEC_BYTES_SIZE: /* no padding */\
+ (x).a_text /* a page of padding */\
+ )
+#endif
+/* The address of the data segment in virtual memory.
+ It is the text segment address, plus text segment size, rounded
+ up to a N_SEGSIZE boundary for pure or pageable files. */
+#ifndef N_DATADDR
+#define N_DATADDR(x) \
+ (N_MAGIC(x)==OMAGIC? (N_TXTADDR(x)+N_TXTSIZE(x)) \
+ : (N_SEGSIZE(x) + ((N_TXTADDR(x)+N_TXTSIZE(x)-1) & ~(N_SEGSIZE(x)-1))))
+#endif
+/* The address of the BSS segment -- immediately after the data segment. */
+
+#define N_BSSADDR(x) (N_DATADDR(x) + (x).a_data)
+
+/* Offsets of the various portions of the file after the text segment. */
+
+/* For {Q,Z}MAGIC, there is padding to make the data segment start on
+ a page boundary. Most of the time the a_text field (and thus
+ N_TXTSIZE) already contains this padding. It is possible that for
+ BSDI and/or 386BSD it sometimes doesn't contain the padding, and
+ perhaps we should be adding it here. But this seems kind of
+ questionable and probably should be BSDI/386BSD-specific if we do
+ do it.
+
+ For NMAGIC (at least for hp300 BSD, probably others), there is
+ padding in memory only, not on disk, so we must *not* ever pad here
+ for NMAGIC. */
+
+#ifndef N_DATOFF
+#define N_DATOFF(x) \
+ (N_TXTOFF(x) + N_TXTSIZE(x))
+#endif
+
+#ifndef N_TRELOFF
+#define N_TRELOFF(x) ( N_DATOFF(x) + (x).a_data )
+#endif
+#ifndef N_DRELOFF
+#define N_DRELOFF(x) ( N_TRELOFF(x) + (x).a_trsize )
+#endif
+#ifndef N_SYMOFF
+#define N_SYMOFF(x) ( N_DRELOFF(x) + (x).a_drsize )
+#endif
+#ifndef N_STROFF
+#define N_STROFF(x) ( N_SYMOFF(x) + (x).a_syms )
+#endif
+
+/* Symbols */
+#ifndef external_nlist
+struct external_nlist {
+ bfd_byte e_strx[BYTES_IN_WORD]; /* index into string table of name */
+ bfd_byte e_type[1]; /* type of symbol */
+ bfd_byte e_other[1]; /* misc info (usually empty) */
+ bfd_byte e_desc[2]; /* description field */
+ bfd_byte e_value[BYTES_IN_WORD]; /* value of symbol */
+};
+#define EXTERNAL_NLIST_SIZE (BYTES_IN_WORD+4+BYTES_IN_WORD)
+#endif
+
+struct internal_nlist {
+ unsigned long n_strx; /* index into string table of name */
+ unsigned char n_type; /* type of symbol */
+ unsigned char n_other; /* misc info (usually empty) */
+ unsigned short n_desc; /* description field */
+ bfd_vma n_value; /* value of symbol */
+};
+
+/* The n_type field is the symbol type, containing: */
+
+#define N_UNDF 0 /* Undefined symbol */
+#define N_ABS 2 /* Absolute symbol -- defined at particular addr */
+#define N_TEXT 4 /* Text sym -- defined at offset in text seg */
+#define N_DATA 6 /* Data sym -- defined at offset in data seg */
+#define N_BSS 8 /* BSS sym -- defined at offset in zero'd seg */
+#define N_COMM 0x12 /* Common symbol (visible after shared lib dynlink) */
+#define N_FN 0x1f /* File name of .o file */
+#define N_FN_SEQ 0x0C /* N_FN from Sequent compilers (sigh) */
+/* Note: N_EXT can only be usefully OR-ed with N_UNDF, N_ABS, N_TEXT,
+ N_DATA, or N_BSS. When the low-order bit of other types is set,
+ (e.g. N_WARNING versus N_FN), they are two different types. */
+#define N_EXT 1 /* External symbol (as opposed to local-to-this-file) */
+#define N_TYPE 0x1e
+#define N_STAB 0xe0 /* If any of these bits are on, it's a debug symbol */
+
+#define N_INDR 0x0a
+
+/* The following symbols refer to set elements.
+ All the N_SET[ATDB] symbols with the same name form one set.
+ Space is allocated for the set in the text section, and each set
+ elements value is stored into one word of the space.
+ The first word of the space is the length of the set (number of elements).
+
+ The address of the set is made into an N_SETV symbol
+ whose name is the same as the name of the set.
+ This symbol acts like a N_DATA global symbol
+ in that it can satisfy undefined external references. */
+
+/* These appear as input to LD, in a .o file. */
+#define N_SETA 0x14 /* Absolute set element symbol */
+#define N_SETT 0x16 /* Text set element symbol */
+#define N_SETD 0x18 /* Data set element symbol */
+#define N_SETB 0x1A /* Bss set element symbol */
+
+/* This is output from LD. */
+#define N_SETV 0x1C /* Pointer to set vector in data area. */
+
+/* Warning symbol. The text gives a warning message, the next symbol
+ in the table will be undefined. When the symbol is referenced, the
+ message is printed. */
+
+#define N_WARNING 0x1e
+
+/* Weak symbols. These are a GNU extension to the a.out format. The
+ semantics are those of ELF weak symbols. Weak symbols are always
+ externally visible. The N_WEAK? values are squeezed into the
+ available slots. The value of a N_WEAKU symbol is 0. The values
+ of the other types are the definitions. */
+#define N_WEAKU 0x0d /* Weak undefined symbol. */
+#define N_WEAKA 0x0e /* Weak absolute symbol. */
+#define N_WEAKT 0x0f /* Weak text symbol. */
+#define N_WEAKD 0x10 /* Weak data symbol. */
+#define N_WEAKB 0x11 /* Weak bss symbol. */
+
+/* Relocations
+
+ There are two types of relocation flavours for a.out systems,
+ standard and extended. The standard form is used on systems where the
+ instruction has room for all the bits of an offset to the operand, whilst
+ the extended form is used when an address operand has to be split over n
+ instructions. Eg, on the 68k, each move instruction can reference
+ the target with a displacement of 16 or 32 bits. On the sparc, move
+ instructions use an offset of 14 bits, so the offset is stored in
+ the reloc field, and the data in the section is ignored.
+*/
+
+/* This structure describes a single relocation to be performed.
+ The text-relocation section of the file is a vector of these structures,
+ all of which apply to the text section.
+ Likewise, the data-relocation section applies to the data section. */
+
+struct reloc_std_external {
+ bfd_byte r_address[BYTES_IN_WORD]; /* offset of of data to relocate */
+ bfd_byte r_index[3]; /* symbol table index of symbol */
+ bfd_byte r_type[1]; /* relocation type */
+};
+
+#define RELOC_STD_BITS_PCREL_BIG ((unsigned int) 0x80)
+#define RELOC_STD_BITS_PCREL_LITTLE ((unsigned int) 0x01)
+
+#define RELOC_STD_BITS_LENGTH_BIG ((unsigned int) 0x60)
+#define RELOC_STD_BITS_LENGTH_SH_BIG 5
+#define RELOC_STD_BITS_LENGTH_LITTLE ((unsigned int) 0x06)
+#define RELOC_STD_BITS_LENGTH_SH_LITTLE 1
+
+#define RELOC_STD_BITS_EXTERN_BIG ((unsigned int) 0x10)
+#define RELOC_STD_BITS_EXTERN_LITTLE ((unsigned int) 0x08)
+
+#define RELOC_STD_BITS_BASEREL_BIG ((unsigned int) 0x08)
+#define RELOC_STD_BITS_BASEREL_LITTLE ((unsigned int) 0x10)
+
+#define RELOC_STD_BITS_JMPTABLE_BIG ((unsigned int) 0x04)
+#define RELOC_STD_BITS_JMPTABLE_LITTLE ((unsigned int) 0x20)
+
+#define RELOC_STD_BITS_RELATIVE_BIG ((unsigned int) 0x02)
+#define RELOC_STD_BITS_RELATIVE_LITTLE ((unsigned int) 0x40)
+
+#define RELOC_STD_SIZE (BYTES_IN_WORD + 3 + 1) /* Bytes per relocation entry */
+
+struct reloc_std_internal
+{
+ bfd_vma r_address; /* Address (within segment) to be relocated. */
+ /* The meaning of r_symbolnum depends on r_extern. */
+ unsigned int r_symbolnum:24;
+ /* Nonzero means value is a pc-relative offset
+ and it should be relocated for changes in its own address
+ as well as for changes in the symbol or section specified. */
+ unsigned int r_pcrel:1;
+ /* Length (as exponent of 2) of the field to be relocated.
+ Thus, a value of 2 indicates 1<<2 bytes. */
+ unsigned int r_length:2;
+ /* 1 => relocate with value of symbol.
+ r_symbolnum is the index of the symbol
+ in files the symbol table.
+ 0 => relocate with the address of a segment.
+ r_symbolnum is N_TEXT, N_DATA, N_BSS or N_ABS
+ (the N_EXT bit may be set also, but signifies nothing). */
+ unsigned int r_extern:1;
+ /* The next three bits are for SunOS shared libraries, and seem to
+ be undocumented. */
+ unsigned int r_baserel:1; /* Linkage table relative */
+ unsigned int r_jmptable:1; /* pc-relative to jump table */
+ unsigned int r_relative:1; /* "relative relocation" */
+ /* unused */
+ unsigned int r_pad:1; /* Padding -- set to zero */
+};
+
+
+/* EXTENDED RELOCS */
+
+struct reloc_ext_external {
+ bfd_byte r_address[BYTES_IN_WORD]; /* offset of of data to relocate */
+ bfd_byte r_index[3]; /* symbol table index of symbol */
+ bfd_byte r_type[1]; /* relocation type */
+ bfd_byte r_addend[BYTES_IN_WORD]; /* datum addend */
+};
+
+#define RELOC_EXT_BITS_EXTERN_BIG ((unsigned int) 0x80)
+#define RELOC_EXT_BITS_EXTERN_LITTLE ((unsigned int) 0x01)
+
+#define RELOC_EXT_BITS_TYPE_BIG ((unsigned int) 0x1F)
+#define RELOC_EXT_BITS_TYPE_SH_BIG 0
+#define RELOC_EXT_BITS_TYPE_LITTLE ((unsigned int) 0xF8)
+#define RELOC_EXT_BITS_TYPE_SH_LITTLE 3
+
+/* Bytes per relocation entry */
+#define RELOC_EXT_SIZE (BYTES_IN_WORD + 3 + 1 + BYTES_IN_WORD)
+
+enum reloc_type
+{
+ /* simple relocations */
+ RELOC_8, /* data[0:7] = addend + sv */
+ RELOC_16, /* data[0:15] = addend + sv */
+ RELOC_32, /* data[0:31] = addend + sv */
+ /* pc-rel displacement */
+ RELOC_DISP8, /* data[0:7] = addend - pc + sv */
+ RELOC_DISP16, /* data[0:15] = addend - pc + sv */
+ RELOC_DISP32, /* data[0:31] = addend - pc + sv */
+ /* Special */
+ RELOC_WDISP30, /* data[0:29] = (addend + sv - pc)>>2 */
+ RELOC_WDISP22, /* data[0:21] = (addend + sv - pc)>>2 */
+ RELOC_HI22, /* data[0:21] = (addend + sv)>>10 */
+ RELOC_22, /* data[0:21] = (addend + sv) */
+ RELOC_13, /* data[0:12] = (addend + sv) */
+ RELOC_LO10, /* data[0:9] = (addend + sv) */
+ RELOC_SFA_BASE,
+ RELOC_SFA_OFF13,
+ /* P.I.C. (base-relative) */
+ RELOC_BASE10, /* Not sure - maybe we can do this the */
+ RELOC_BASE13, /* right way now */
+ RELOC_BASE22,
+ /* for some sort of pc-rel P.I.C. (?) */
+ RELOC_PC10,
+ RELOC_PC22,
+ /* P.I.C. jump table */
+ RELOC_JMP_TBL,
+ /* reputedly for shared libraries somehow */
+ RELOC_SEGOFF16,
+ RELOC_GLOB_DAT,
+ RELOC_JMP_SLOT,
+ RELOC_RELATIVE,
+
+ RELOC_11,
+ RELOC_WDISP2_14,
+ RELOC_WDISP19,
+ RELOC_HHI22, /* data[0:21] = (addend + sv) >> 42 */
+ RELOC_HLO10, /* data[0:9] = (addend + sv) >> 32 */
+
+ /* 29K relocation types */
+ RELOC_JUMPTARG,
+ RELOC_CONST,
+ RELOC_CONSTH,
+
+ /* All the new ones I can think of, for sparc v9 */
+
+ RELOC_64, /* data[0:63] = addend + sv */
+ RELOC_DISP64, /* data[0:63] = addend - pc + sv */
+ RELOC_WDISP21, /* data[0:20] = (addend + sv - pc)>>2 */
+ RELOC_DISP21, /* data[0:20] = addend - pc + sv */
+ RELOC_DISP14, /* data[0:13] = addend - pc + sv */
+ /* Q .
+ What are the other ones,
+ Since this is a clean slate, can we throw away the ones we dont
+ understand ? Should we sort the values ? What about using a
+ microcode format like the 68k ?
+ */
+ NO_RELOC
+ };
+
+
+struct reloc_internal {
+ bfd_vma r_address; /* offset of of data to relocate */
+ long r_index; /* symbol table index of symbol */
+ enum reloc_type r_type; /* relocation type */
+ bfd_vma r_addend; /* datum addend */
+};
+
+/* Q.
+ Should the length of the string table be 4 bytes or 8 bytes ?
+
+ Q.
+ What about archive indexes ?
+
+ */
+
+#endif /* __A_OUT_64_H__ */
diff --git a/gnu/usr.bin/gdb/gdb/aout/ar.h b/gnu/usr.bin/gdb/gdb/aout/ar.h
new file mode 100644
index 0000000..1112af6
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/aout/ar.h
@@ -0,0 +1,36 @@
+/* archive file definition for GNU software */
+
+/* So far this is correct for BSDish archives. Don't forget that
+ files must begin on an even byte boundary. */
+
+#ifndef __GNU_AR_H__
+#define __GNU_AR_H__
+
+/* Note that the usual '\n' in magic strings may translate to different
+ characters, as allowed by ANSI. '\012' has a fixed value, and remains
+ compatible with existing BSDish archives. */
+
+#define ARMAG "!<arch>\012" /* For COFF and a.out archives */
+#define ARMAGB "!<bout>\012" /* For b.out archives */
+#define SARMAG 8
+#define ARFMAG "`\012"
+
+/* The ar_date field of the armap (__.SYMDEF) member of an archive
+ must be greater than the modified date of the entire file, or
+ BSD-derived linkers complain. We originally write the ar_date with
+ this offset from the real file's mod-time. After finishing the
+ file, we rewrite ar_date if it's not still greater than the mod date. */
+
+#define ARMAP_TIME_OFFSET 60
+
+struct ar_hdr {
+ char ar_name[16]; /* name of this member */
+ char ar_date[12]; /* file mtime */
+ char ar_uid[6]; /* owner uid; printed as decimal */
+ char ar_gid[6]; /* owner gid; printed as decimal */
+ char ar_mode[8]; /* file mode, printed as octal */
+ char ar_size[10]; /* file size, printed as decimal */
+ char ar_fmag[2]; /* should contain ARFMAG */
+};
+
+#endif /* __GNU_AR_H__ */
diff --git a/gnu/usr.bin/gdb/gdb/aout/encap.h b/gnu/usr.bin/gdb/gdb/aout/encap.h
new file mode 100644
index 0000000..fb79918
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/aout/encap.h
@@ -0,0 +1,135 @@
+/* Yet Another Try at encapsulating bsd object files in coff.
+ Copyright (C) 1988, 1989, 1991 Free Software Foundation, Inc.
+ Written by Pace Willisson 12/9/88
+
+ This file is obsolete. It needs to be converted to just define a bunch
+ of stuff that BFD can use to do coff-encapsulated files. --gnu@cygnus.com
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/*
+ * We only use the coff headers to tell the kernel
+ * how to exec the file. Therefore, the only fields that need to
+ * be filled in are the scnptr and vaddr for the text and data
+ * sections, and the vaddr for the bss. As far as coff is concerned,
+ * there is no symbol table, relocation, or line numbers.
+ *
+ * A normal bsd header (struct exec) is placed after the coff headers,
+ * and before the real text. I defined a the new fields 'a_machtype'
+ * and a_flags. If a_machtype is M_386, and a_flags & A_ENCAP is
+ * true, then the bsd header is preceeded by a coff header. Macros
+ * like N_TXTOFF and N_TXTADDR use this field to find the bsd header.
+ *
+ * The only problem is to track down the bsd exec header. The
+ * macros HEADER_OFFSET, etc do this.
+ */
+
+#define N_FLAGS_COFF_ENCAPSULATE 0x20 /* coff header precedes bsd header */
+
+/* Describe the COFF header used for encapsulation. */
+
+struct coffheader
+{
+ /* filehdr */
+ unsigned short f_magic;
+ unsigned short f_nscns;
+ long f_timdat;
+ long f_symptr;
+ long f_nsyms;
+ unsigned short f_opthdr;
+ unsigned short f_flags;
+ /* aouthdr */
+ short magic;
+ short vstamp;
+ long tsize;
+ long dsize;
+ long bsize;
+ long entry;
+ long text_start;
+ long data_start;
+ struct coffscn
+ {
+ char s_name[8];
+ long s_paddr;
+ long s_vaddr;
+ long s_size;
+ long s_scnptr;
+ long s_relptr;
+ long s_lnnoptr;
+ unsigned short s_nreloc;
+ unsigned short s_nlnno;
+ long s_flags;
+ } scns[3];
+};
+
+/* Describe some of the parameters of the encapsulation,
+ including how to find the encapsulated BSD header. */
+
+/* FIXME, this is dumb. The same tools can't handle a.outs for different
+ architectures, just because COFF_MAGIC is different; so you need a
+ separate GNU nm for every architecture!!? Unfortunately, it needs to
+ be this way, since the COFF_MAGIC value is determined by the kernel
+ we're trying to fool here. */
+
+#define COFF_MAGIC_I386 0514 /* I386MAGIC */
+#define COFF_MAGIC_M68K 0520 /* MC68MAGIC */
+#define COFF_MAGIC_A29K 0x17A /* Used by asm29k cross-tools */
+
+#ifdef COFF_MAGIC
+short __header_offset_temp;
+#define HEADER_OFFSET(f) \
+ (__header_offset_temp = 0, \
+ fread ((char *)&__header_offset_temp, sizeof (short), 1, (f)), \
+ fseek ((f), -sizeof (short), 1), \
+ __header_offset_temp==COFF_MAGIC ? sizeof(struct coffheader) : 0)
+#else
+#define HEADER_OFFSET(f) 0
+#endif
+
+#define HEADER_SEEK(f) (fseek ((f), HEADER_OFFSET((f)), 1))
+
+/* Describe the characteristics of the BSD header
+ that appears inside the encapsulation. */
+
+/* Encapsulated coff files that are linked ZMAGIC have a text segment
+ offset just past the header (and a matching TXTADDR), excluding
+ the headers from the text segment proper but keeping the physical
+ layout and the virtual memory layout page-aligned.
+
+ Non-encapsulated a.out files that are linked ZMAGIC have a text
+ segment that starts at 0 and an N_TXTADR similarly offset to 0.
+ They too are page-aligned with each other, but they include the
+ a.out header as part of the text.
+
+ The _N_HDROFF gets sizeof struct exec added to it, so we have
+ to compensate here. See <a.out.gnu.h>. */
+
+#undef _N_HDROFF
+#undef N_TXTADDR
+#undef N_DATADDR
+
+#define _N_HDROFF(x) ((N_FLAGS(x) & N_FLAGS_COFF_ENCAPSULATE) ? \
+ sizeof (struct coffheader) : 0)
+
+/* Address of text segment in memory after it is loaded. */
+#define N_TXTADDR(x) \
+ ((N_FLAGS(x) & N_FLAGS_COFF_ENCAPSULATE) ? \
+ sizeof (struct coffheader) + sizeof (struct exec) : 0)
+#define SEGMENT_SIZE 0x400000
+
+#define N_DATADDR(x) \
+ ((N_FLAGS(x) & N_FLAGS_COFF_ENCAPSULATE) ? \
+ (SEGMENT_SIZE + ((N_TXTADDR(x)+(x).a_text-1) & ~(SEGMENT_SIZE-1))) : \
+ (N_TXTADDR(x)+(x).a_text))
diff --git a/gnu/usr.bin/gdb/gdb/aout/host.h b/gnu/usr.bin/gdb/gdb/aout/host.h
new file mode 100644
index 0000000..5d3488a
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/aout/host.h
@@ -0,0 +1,22 @@
+/* Parameters about the a.out format, based on the host system on which
+ the program is compiled. */
+
+/* Address of data segment in memory after it is loaded.
+ It is up to you to define SEGMENT_SIZE
+ on machines not listed here. */
+#ifndef SEGMENT_SIZE
+#if defined(hp300) || defined(pyr)
+#define SEGMENT_SIZE page_size
+#endif
+#ifdef sony
+#define SEGMENT_SIZE 0x1000
+#endif /* Sony. */
+#ifdef is68k
+#define SEGMENT_SIZE 0x20000
+#endif
+#if defined(m68k) && defined(PORTAR)
+#define PAGE_SIZE 0x400
+#define SEGMENT_SIZE PAGE_SIZE
+#endif
+#endif /*!defined(SEGMENT_SIZE)*/
+
diff --git a/gnu/usr.bin/gdb/gdb/aout/ranlib.h b/gnu/usr.bin/gdb/gdb/aout/ranlib.h
new file mode 100644
index 0000000..43ea0b4
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/aout/ranlib.h
@@ -0,0 +1,62 @@
+/* ranlib.h -- archive library index member definition for GNU.
+ Copyright 1990-1991 Free Software Foundation, Inc.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* The Symdef member of an archive contains two things:
+ a table that maps symbol-string offsets to file offsets,
+ and a symbol-string table. All the symbol names are
+ run together (each with trailing null) in the symbol-string
+ table. There is a single longword bytecount on the front
+ of each of these tables. Thus if we have two symbols,
+ "foo" and "_bar", that are in archive members at offsets
+ 200 and 900, it would look like this:
+ 16 ; byte count of index table
+ 0 ; offset of "foo" in string table
+ 200 ; offset of foo-module in file
+ 4 ; offset of "bar" in string table
+ 900 ; offset of bar-module in file
+ 9 ; byte count of string table
+ "foo\0_bar\0" ; string table */
+
+#define RANLIBMAG "__.SYMDEF" /* Archive file name containing index */
+#define RANLIBSKEW 3 /* Creation time offset */
+
+/* Format of __.SYMDEF:
+ First, a longword containing the size of the 'symdef' data that follows.
+ Second, zero or more 'symdef' structures.
+ Third, a longword containing the length of symbol name strings.
+ Fourth, zero or more symbol name strings (each followed by a null). */
+
+struct symdef
+ {
+ union
+ {
+ unsigned long string_offset; /* In the file */
+ char *name; /* In memory, sometimes */
+ } s;
+ /* this points to the front of the file header (AKA member header --
+ a struct ar_hdr), not to the front of the file or into the file).
+ in other words it only tells you which file to read */
+ unsigned long file_offset;
+ };
+
+/* Compatability with BSD code */
+
+#define ranlib symdef
+#define ran_un s
+#define ran_strx string_offset
+#define ran_name name
+#define ran_off file_offset
diff --git a/gnu/usr.bin/gdb/gdb/aout/reloc.h b/gnu/usr.bin/gdb/gdb/aout/reloc.h
new file mode 100644
index 0000000..ec9fef8
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/aout/reloc.h
@@ -0,0 +1,66 @@
+/* reloc.h -- Header file for relocation information.
+ Copyright 1989-1991 Free Software Foundation, Inc.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* Relocation types for a.out files using reloc_info_extended
+ (SPARC and AMD 29000). */
+
+#ifndef _RELOC_H_READ_
+#define _RELOC_H_READ_ 1
+
+enum reloc_type
+ {
+ RELOC_8, RELOC_16, RELOC_32, /* simple relocations */
+ RELOC_DISP8, RELOC_DISP16, RELOC_DISP32, /* pc-rel displacement */
+ RELOC_WDISP30, RELOC_WDISP22,
+ RELOC_HI22, RELOC_22,
+ RELOC_13, RELOC_LO10,
+ RELOC_SFA_BASE, RELOC_SFA_OFF13,
+ RELOC_BASE10, RELOC_BASE13, RELOC_BASE22, /* P.I.C. (base-relative) */
+ RELOC_PC10, RELOC_PC22, /* for some sort of pc-rel P.I.C. (?) */
+ RELOC_JMP_TBL, /* P.I.C. jump table */
+ RELOC_SEGOFF16, /* reputedly for shared libraries somehow */
+ RELOC_GLOB_DAT, RELOC_JMP_SLOT, RELOC_RELATIVE,
+ RELOC_11,
+ RELOC_WDISP2_14,
+ RELOC_WDISP19,
+ RELOC_HHI22,
+ RELOC_HLO10,
+
+ /* 29K relocation types */
+ RELOC_JUMPTARG, RELOC_CONST, RELOC_CONSTH,
+
+ RELOC_WDISP14, RELOC_WDISP21,
+
+ NO_RELOC
+ };
+
+#define RELOC_TYPE_NAMES \
+"8", "16", "32", "DISP8", \
+"DISP16", "DISP32", "WDISP30", "WDISP22", \
+"HI22", "22", "13", "LO10", \
+"SFA_BASE", "SFAOFF13", "BASE10", "BASE13", \
+"BASE22", "PC10", "PC22", "JMP_TBL", \
+"SEGOFF16", "GLOB_DAT", "JMP_SLOT", "RELATIVE", \
+"11", "WDISP2_14", "WDISP19", "HHI22", \
+"HLO10", \
+"JUMPTARG", "CONST", "CONSTH", "WDISP14", \
+"WDISP21", \
+"NO_RELOC"
+
+#endif /* _RELOC_H_READ_ */
+
+/* end of reloc.h */
diff --git a/gnu/usr.bin/gdb/gdb/aout/stab.def b/gnu/usr.bin/gdb/gdb/aout/stab.def
new file mode 100644
index 0000000..ff19816
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/aout/stab.def
@@ -0,0 +1,264 @@
+/* Table of DBX symbol codes for the GNU system.
+ Copyright (C) 1988, 1991 Free Software Foundation, Inc.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* New stab from Solaris 2. This uses an n_type of 0, which in a.out files
+ overlaps the N_UNDF used for ordinary symbols. In ELF files, the
+ debug information is in a different file section, so there is no conflict.
+ This symbol's n_value gives the size of the string section associated
+ with this file. The symbol's n_strx (relative to the just-updated
+ string section start address) gives the name of the source file,
+ e.g. "foo.c", without any path information. The symbol's n_desc gives
+ the count of upcoming symbols associated with this file (not including
+ this one). */
+/* __define_stab (N_UNDF, 0x00, "UNDF") */
+
+/* Global variable. Only the name is significant.
+ To find the address, look in the corresponding external symbol. */
+__define_stab (N_GSYM, 0x20, "GSYM")
+
+/* Function name for BSD Fortran. Only the name is significant.
+ To find the address, look in the corresponding external symbol. */
+__define_stab (N_FNAME, 0x22, "FNAME")
+
+/* Function name or text-segment variable for C. Value is its address.
+ Desc is supposedly starting line number, but GCC doesn't set it
+ and DBX seems not to miss it. */
+__define_stab (N_FUN, 0x24, "FUN")
+
+/* Data-segment variable with internal linkage. Value is its address.
+ "Static Sym". */
+__define_stab (N_STSYM, 0x26, "STSYM")
+
+/* BSS-segment variable with internal linkage. Value is its address. */
+__define_stab (N_LCSYM, 0x28, "LCSYM")
+
+/* Name of main routine. Only the name is significant. */
+__define_stab (N_MAIN, 0x2a, "MAIN")
+
+/* Solaris2: Read-only data symbols. */
+__define_stab (N_ROSYM, 0x2c, "ROSYM")
+
+/* Global symbol in Pascal.
+ Supposedly the value is its line number; I'm skeptical. */
+__define_stab (N_PC, 0x30, "PC")
+
+/* Number of symbols: 0, files,,funcs,lines according to Ultrix V4.0. */
+__define_stab (N_NSYMS, 0x32, "NSYMS")
+
+/* "No DST map for sym: name, ,0,type,ignored" according to Ultrix V4.0. */
+__define_stab (N_NOMAP, 0x34, "NOMAP")
+
+/* New stab from Solaris 2. Like N_SO, but for the object file. Two in
+ a row provide the build directory and the relative path of the .o from it.
+ Solaris2 uses this to avoid putting the stabs info into the linked
+ executable; this stab goes into the ".stab.index" section, and the debugger
+ reads the real stabs directly from the .o files instead. */
+__define_stab (N_OBJ, 0x38, "OBJ")
+
+/* New stab from Solaris 2. Options for the debugger, related to the
+ source language for this module. E.g. whether to use ANSI
+ integral promotions or traditional integral promotions. */
+__define_stab (N_OPT, 0x3c, "OPT")
+
+/* Register variable. Value is number of register. */
+__define_stab (N_RSYM, 0x40, "RSYM")
+
+/* Modula-2 compilation unit. Can someone say what info it contains? */
+__define_stab (N_M2C, 0x42, "M2C")
+
+/* Line number in text segment. Desc is the line number;
+ value is corresponding address. On Solaris2, the line number is
+ relative to the start of the current function. */
+__define_stab (N_SLINE, 0x44, "SLINE")
+
+/* Similar, for data segment. */
+__define_stab (N_DSLINE, 0x46, "DSLINE")
+
+/* Similar, for bss segment. */
+__define_stab (N_BSLINE, 0x48, "BSLINE")
+
+/* Sun's source-code browser stabs. ?? Don't know what the fields are.
+ Supposedly the field is "path to associated .cb file". THIS VALUE
+ OVERLAPS WITH N_BSLINE! */
+__define_stab (N_BROWS, 0x48, "BROWS")
+
+/* GNU Modula-2 definition module dependency. Value is the modification time
+ of the definition file. Other is non-zero if it is imported with the
+ GNU M2 keyword %INITIALIZE. Perhaps N_M2C can be used if there
+ are enough empty fields? */
+__define_stab(N_DEFD, 0x4a, "DEFD")
+
+/* New in Solaris2. Function start/body/end line numbers. */
+__define_stab(N_FLINE, 0x4C, "FLINE")
+
+/* THE FOLLOWING TWO STAB VALUES CONFLICT. Happily, one is for Modula-2
+ and one is for C++. Still,... */
+/* GNU C++ exception variable. Name is variable name. */
+__define_stab (N_EHDECL, 0x50, "EHDECL")
+/* Modula2 info "for imc": name,,0,0,0 according to Ultrix V4.0. */
+__define_stab (N_MOD2, 0x50, "MOD2")
+
+/* GNU C++ `catch' clause. Value is its address. Desc is nonzero if
+ this entry is immediately followed by a CAUGHT stab saying what exception
+ was caught. Multiple CAUGHT stabs means that multiple exceptions
+ can be caught here. If Desc is 0, it means all exceptions are caught
+ here. */
+__define_stab (N_CATCH, 0x54, "CATCH")
+
+/* Structure or union element. Value is offset in the structure. */
+__define_stab (N_SSYM, 0x60, "SSYM")
+
+/* Solaris2: Last stab emitted for module. */
+__define_stab (N_ENDM, 0x62, "ENDM")
+
+/* Name of main source file.
+ Value is starting text address of the compilation.
+ If multiple N_SO's appear, the first to contain a trailing / is the
+ compilation directory. The first to not contain a trailing / is the
+ source file name, relative to the compilation directory. Others (perhaps
+ resulting from cfront) are ignored.
+ On Solaris2, value is undefined, but desc is a source-language code. */
+
+__define_stab (N_SO, 0x64, "SO")
+
+/* Automatic variable in the stack. Value is offset from frame pointer.
+ Also used for type descriptions. */
+__define_stab (N_LSYM, 0x80, "LSYM")
+
+/* Beginning of an include file. Only Sun uses this.
+ In an object file, only the name is significant.
+ The Sun linker puts data into some of the other fields. */
+__define_stab (N_BINCL, 0x82, "BINCL")
+
+/* Name of sub-source file (#include file).
+ Value is starting text address of the compilation. */
+__define_stab (N_SOL, 0x84, "SOL")
+
+/* Parameter variable. Value is offset from argument pointer.
+ (On most machines the argument pointer is the same as the frame pointer. */
+__define_stab (N_PSYM, 0xa0, "PSYM")
+
+/* End of an include file. No name.
+ This and N_BINCL act as brackets around the file's output.
+ In an object file, there is no significant data in this entry.
+ The Sun linker puts data into some of the fields. */
+__define_stab (N_EINCL, 0xa2, "EINCL")
+
+/* Alternate entry point. Value is its address. */
+__define_stab (N_ENTRY, 0xa4, "ENTRY")
+
+/* Beginning of lexical block.
+ The desc is the nesting level in lexical blocks.
+ The value is the address of the start of the text for the block.
+ The variables declared inside the block *precede* the N_LBRAC symbol.
+ On Solaris2, the value is relative to the start of the current function. */
+__define_stab (N_LBRAC, 0xc0, "LBRAC")
+
+/* Place holder for deleted include file. Replaces a N_BINCL and everything
+ up to the corresponding N_EINCL. The Sun linker generates these when
+ it finds multiple identical copies of the symbols from an include file.
+ This appears only in output from the Sun linker. */
+__define_stab (N_EXCL, 0xc2, "EXCL")
+
+/* Modula-2 scope information. Can someone say what info it contains? */
+__define_stab (N_SCOPE, 0xc4, "SCOPE")
+
+/* End of a lexical block. Desc matches the N_LBRAC's desc.
+ The value is the address of the end of the text for the block.
+ On Solaris2, the value is relative to the start of the current function. */
+__define_stab (N_RBRAC, 0xe0, "RBRAC")
+
+/* Begin named common block. Only the name is significant. */
+__define_stab (N_BCOMM, 0xe2, "BCOMM")
+
+/* End named common block. Only the name is significant
+ (and it should match the N_BCOMM). */
+__define_stab (N_ECOMM, 0xe4, "ECOMM")
+
+/* Member of a common block; value is offset within the common block.
+ This should occur within a BCOMM/ECOMM pair. */
+__define_stab (N_ECOML, 0xe8, "ECOML")
+
+/* Solaris2: Pascal "with" statement: type,,0,0,offset */
+__define_stab (N_WITH, 0xea, "WITH")
+
+/* These STAB's are used on Gould systems for Non-Base register symbols
+ or something like that. FIXME. I have assigned the values at random
+ since I don't have a Gould here. Fixups from Gould folk welcome... */
+__define_stab (N_NBTEXT, 0xF0, "NBTEXT")
+__define_stab (N_NBDATA, 0xF2, "NBDATA")
+__define_stab (N_NBBSS, 0xF4, "NBBSS")
+__define_stab (N_NBSTS, 0xF6, "NBSTS")
+__define_stab (N_NBLCS, 0xF8, "NBLCS")
+
+/* Second symbol entry containing a length-value for the preceding entry.
+ The value is the length. */
+__define_stab (N_LENG, 0xfe, "LENG")
+
+/* The above information, in matrix format.
+
+ STAB MATRIX
+ _________________________________________________
+ | 00 - 1F are not dbx stab symbols |
+ | In most cases, the low bit is the EXTernal bit|
+
+ | 00 UNDEF | 02 ABS | 04 TEXT | 06 DATA |
+ | 01 |EXT | 03 |EXT | 05 |EXT | 07 |EXT |
+
+ | 08 BSS | 0A INDR | 0C FN_SEQ | 0E WEAKA |
+ | 09 |EXT | 0B | 0D WEAKU | 0F WEAKT |
+
+ | 10 WEAKD | 12 COMM | 14 SETA | 16 SETT |
+ | 11 WEAKB | 13 | 15 | 17 |
+
+ | 18 SETD | 1A SETB | 1C SETV | 1E WARNING|
+ | 19 | 1B | 1D | 1F FN |
+
+ |_______________________________________________|
+ | Debug entries with bit 01 set are unused. |
+ | 20 GSYM | 22 FNAME | 24 FUN | 26 STSYM |
+ | 28 LCSYM | 2A MAIN | 2C ROSYM | 2E |
+ | 30 PC | 32 NSYMS | 34 NOMAP | 36 |
+ | 38 OBJ | 3A | 3C OPT | 3E |
+ | 40 RSYM | 42 M2C | 44 SLINE | 46 DSLINE |
+ | 48 BSLINE*| 4A DEFD | 4C FLINE | 4E |
+ | 50 EHDECL*| 52 | 54 CATCH | 56 |
+ | 58 | 5A | 5C | 5E |
+ | 60 SSYM | 62 ENDM | 64 SO | 66 |
+ | 68 | 6A | 6C | 6E |
+ | 70 | 72 | 74 | 76 |
+ | 78 | 7A | 7C | 7E |
+ | 80 LSYM | 82 BINCL | 84 SOL | 86 |
+ | 88 | 8A | 8C | 8E |
+ | 90 | 92 | 94 | 96 |
+ | 98 | 9A | 9C | 9E |
+ | A0 PSYM | A2 EINCL | A4 ENTRY | A6 |
+ | A8 | AA | AC | AE |
+ | B0 | B2 | B4 | B6 |
+ | B8 | BA | BC | BE |
+ | C0 LBRAC | C2 EXCL | C4 SCOPE | C6 |
+ | C8 | CA | CC | CE |
+ | D0 | D2 | D4 | D6 |
+ | D8 | DA | DC | DE |
+ | E0 RBRAC | E2 BCOMM | E4 ECOMM | E6 |
+ | E8 ECOML | EA WITH | EC | EE |
+ | F0 | F2 | F4 | F6 |
+ | F8 | FA | FC | FE LENG |
+ +-----------------------------------------------+
+ * 50 EHDECL is also MOD2.
+ * 48 BSLINE is also BROWS.
+ */
diff --git a/gnu/usr.bin/gdb/gdb/aout/stab_gnu.h b/gnu/usr.bin/gdb/gdb/aout/stab_gnu.h
new file mode 100644
index 0000000..477b87d
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/aout/stab_gnu.h
@@ -0,0 +1,36 @@
+#ifndef __GNU_STAB__
+
+/* Indicate the GNU stab.h is in use. */
+
+#define __GNU_STAB__
+
+#define __define_stab(NAME, CODE, STRING) NAME=CODE,
+
+enum __stab_debug_code
+{
+#include "aout/stab.def"
+LAST_UNUSED_STAB_CODE
+};
+
+#undef __define_stab
+
+/* Definitions of "desc" field for N_SO stabs in Solaris2. */
+
+#define N_SO_AS 1
+#define N_SO_C 2
+#define N_SO_ANSI_C 3
+#define N_SO_CC 4 /* C++ */
+#define N_SO_FORTRAN 5
+#define N_SO_PASCAL 6
+
+/* Solaris2: Floating point type values in basic types. */
+
+#define NF_NONE 0
+#define NF_SINGLE 1 /* IEEE 32-bit */
+#define NF_DOUBLE 2 /* IEEE 64-bit */
+#define NF_COMPLEX 3 /* Fortran complex */
+#define NF_COMPLEX16 4 /* Fortran double complex */
+#define NF_COMPLEX32 5 /* Fortran complex*16 */
+#define NF_LDOUBLE 6 /* Long double (whatever that is) */
+
+#endif /* __GNU_STAB_ */
diff --git a/gnu/usr.bin/gdb/gdb/bfdlink.h b/gnu/usr.bin/gdb/gdb/bfdlink.h
new file mode 100644
index 0000000..b46eb34
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/bfdlink.h
@@ -0,0 +1,411 @@
+/* bfdlink.h -- header file for BFD link routines
+ Copyright 1993 Free Software Foundation, Inc.
+ Written by Steve Chamberlain and Ian Lance Taylor, Cygnus Support.
+
+This file is part of BFD, the Binary File Descriptor library.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#ifndef BFDLINK_H
+#define BFDLINK_H
+
+/* Which symbols to strip during a link. */
+enum bfd_link_strip
+{
+ strip_none, /* Don't strip any symbols. */
+ strip_debugger, /* Strip debugging symbols. */
+ strip_some, /* keep_hash is the list of symbols to keep. */
+ strip_all /* Strip all symbols. */
+};
+
+/* Which local symbols to discard during a link. This is irrelevant
+ if strip_all is used. */
+enum bfd_link_discard
+{
+ discard_none, /* Don't discard any locals. */
+ discard_l, /* Discard locals with a certain prefix. */
+ discard_all /* Discard all locals. */
+};
+
+/* These are the possible types of an entry in the BFD link hash
+ table. */
+
+enum bfd_link_hash_type
+{
+ bfd_link_hash_new, /* Symbol is new. */
+ bfd_link_hash_undefined, /* Symbol seen before, but undefined. */
+ bfd_link_hash_weak, /* Symbol is weak and undefined. */
+ bfd_link_hash_defined, /* Symbol is defined. */
+ bfd_link_hash_common, /* Symbol is common. */
+ bfd_link_hash_indirect, /* Symbol is an indirect link. */
+ bfd_link_hash_warning /* Like indirect, but warn if referenced. */
+};
+
+/* The linking routines use a hash table which uses this structure for
+ its elements. */
+
+struct bfd_link_hash_entry
+{
+ /* Base hash table entry structure. */
+ struct bfd_hash_entry root;
+ /* Type of this entry. */
+ enum bfd_link_hash_type type;
+
+ /* Undefined and common symbols are kept in a linked list through
+ this field. This field is not in the union because that would
+ force us to remove entries from the list when we changed their
+ type, which would force the list to be doubly linked, which would
+ waste more memory. When an undefined or common symbol is
+ created, it should be added to this list, the head of which is in
+ the link hash table itself. As symbols are defined, they need
+ not be removed from the list; anything which reads the list must
+ doublecheck the symbol type.
+
+ Weak symbols are not kept on this list.
+
+ Defined symbols use this field as a reference marker. If the
+ field is not NULL, or this structure is the tail of the undefined
+ symbol list, the symbol has been referenced. If the symbol is
+ undefined and becomes defined, this field will automatically be
+ non-NULL since the symbol will have been on the undefined symbol
+ list. */
+ struct bfd_link_hash_entry *next;
+ /* A union of information depending upon the type. */
+ union
+ {
+ /* Nothing is kept for bfd_hash_new. */
+ /* bfd_link_hash_undefined, bfd_link_hash_weak. */
+ struct
+ {
+ bfd *abfd; /* BFD symbol was found in. */
+ } undef;
+ /* bfd_link_hash_defined. */
+ struct
+ {
+ bfd_vma value; /* Symbol value. */
+ asection *section; /* Symbol section. */
+ } def;
+ /* bfd_link_hash_indirect, bfd_link_hash_warning. */
+ struct
+ {
+ struct bfd_link_hash_entry *link; /* Real symbol. */
+ const char *warning; /* Warning (bfd_link_hash_warning only). */
+ } i;
+ /* bfd_link_hash_common. */
+ struct
+ {
+ bfd_vma size; /* Common symbol size. */
+ asection *section; /* Symbol section. */
+ } c;
+ } u;
+};
+
+/* This is the link hash table. It is a derived class of
+ bfd_hash_table. */
+
+struct bfd_link_hash_table
+{
+ /* The hash table itself. */
+ struct bfd_hash_table table;
+ /* The back end which created this hash table. This indicates the
+ type of the entries in the hash table, which is sometimes
+ important information when linking object files of different
+ types together. */
+ const bfd_target *creator;
+ /* A linked list of undefined and common symbols, linked through the
+ next field in the bfd_link_hash_entry structure. */
+ struct bfd_link_hash_entry *undefs;
+ /* Entries are added to the tail of the undefs list. */
+ struct bfd_link_hash_entry *undefs_tail;
+};
+
+/* Look up an entry in a link hash table. If FOLLOW is true, this
+ follows bfd_link_hash_indirect and bfd_link_hash_warning links to
+ the real symbol. */
+extern struct bfd_link_hash_entry *bfd_link_hash_lookup
+ PARAMS ((struct bfd_link_hash_table *, const char *, boolean create,
+ boolean copy, boolean follow));
+
+/* Traverse a link hash table. */
+extern void bfd_link_hash_traverse
+ PARAMS ((struct bfd_link_hash_table *,
+ boolean (*) (struct bfd_link_hash_entry *, PTR),
+ PTR));
+
+/* Add an entry to the undefs list. */
+extern void bfd_link_add_undef
+ PARAMS ((struct bfd_link_hash_table *, struct bfd_link_hash_entry *));
+
+/* This structure holds all the information needed to communicate
+ between BFD and the linker when doing a link. */
+
+struct bfd_link_info
+{
+ /* Function callbacks. */
+ const struct bfd_link_callbacks *callbacks;
+ /* true if BFD should generate a relocateable object file. */
+ boolean relocateable;
+ /* true if BFD should generate a shared object. */
+ boolean shared;
+ /* Which symbols to strip. */
+ enum bfd_link_strip strip;
+ /* Which local symbols to discard. */
+ enum bfd_link_discard discard;
+ /* The local symbol prefix to discard if using discard_l. */
+ unsigned int lprefix_len;
+ const char *lprefix;
+ /* true if symbols should be retained in memory, false if they
+ should be freed and reread. */
+ boolean keep_memory;
+ /* The list of input BFD's involved in the link. These are chained
+ together via the link_next field. */
+ bfd *input_bfds;
+ /* If a symbol should be created for each input BFD, this is section
+ where those symbols should be placed. It must be a section in
+ the output BFD. It may be NULL, in which case no such symbols
+ will be created. This is to support CREATE_OBJECT_SYMBOLS in the
+ linker command language. */
+ asection *create_object_symbols_section;
+ /* Hash table handled by BFD. */
+ struct bfd_link_hash_table *hash;
+ /* Hash table of symbols to keep. This is NULL unless strip is
+ strip_some. */
+ struct bfd_hash_table *keep_hash;
+ /* Hash table of symbols to report back via notice_callback. If
+ this is NULL no symbols are reported back. */
+ struct bfd_hash_table *notice_hash;
+};
+
+/* This structures holds a set of callback functions. These are
+ called by the BFD linker routines. The first argument to each
+ callback function is the bfd_link_info structure being used. Each
+ function returns a boolean value. If the function returns false,
+ then the BFD function which called it will return with a failure
+ indication. */
+
+struct bfd_link_callbacks
+{
+ /* A function which is called when an object is added from an
+ archive. ABFD is the archive element being added. NAME is the
+ name of the symbol which caused the archive element to be pulled
+ in. */
+ boolean (*add_archive_element) PARAMS ((struct bfd_link_info *,
+ bfd *abfd,
+ const char *name));
+ /* A function which is called when a symbol is found with multiple
+ definitions. NAME is the symbol which is defined multiple times.
+ OBFD is the old BFD, OSEC is the old section, OVAL is the old
+ value, NBFD is the new BFD, NSEC is the new section, and NVAL is
+ the new value. OBFD may be NULL. OSEC and NSEC may be
+ bfd_com_section or bfd_ind_section. */
+ boolean (*multiple_definition) PARAMS ((struct bfd_link_info *,
+ const char *name,
+ bfd *obfd,
+ asection *osec,
+ bfd_vma oval,
+ bfd *nbfd,
+ asection *nsec,
+ bfd_vma nval));
+ /* A function which is called when a common symbol is defined
+ multiple times. NAME is the symbol appearing multiple times.
+ OBFD is the BFD of the existing symbol. OTYPE is the type of the
+ existing symbol, either bfd_link_hash_defined or
+ bfd_link_hash_common. If OTYPE is bfd_link_hash_common, OSIZE is
+ the size of the existing symbol. NBFD is the BFD of the new
+ symbol. NTYPE is the type of the new symbol, either
+ bfd_link_hash_defined or bfd_link_hash_common. If NTYPE is
+ bfd_link_hash_common, NSIZE is the size of the new symbol. */
+ boolean (*multiple_common) PARAMS ((struct bfd_link_info *,
+ const char *name,
+ bfd *obfd,
+ enum bfd_link_hash_type otype,
+ bfd_vma osize,
+ bfd *nbfd,
+ enum bfd_link_hash_type ntype,
+ bfd_vma nsize));
+ /* A function which is called to add a symbol to a set. ENTRY is
+ the link hash table entry for the set itself (e.g.,
+ __CTOR_LIST__). RELOC is the relocation to use for an entry in
+ the set when generating a relocateable file, and is also used to
+ get the size of the entry when generating an executable file.
+ ABFD, SEC and VALUE identify the value to add to the set. */
+ boolean (*add_to_set) PARAMS ((struct bfd_link_info *,
+ struct bfd_link_hash_entry *entry,
+ bfd_reloc_code_real_type reloc,
+ bfd *abfd, asection *sec, bfd_vma value));
+ /* A function which is called when the name of a g++ constructor or
+ destructor is found. This is only called by some object file
+ formats. CONSTRUCTOR is true for a constructor, false for a
+ destructor. This will use BFD_RELOC_CTOR when generating a
+ relocateable file. NAME is the name of the symbol found. ABFD,
+ SECTION and VALUE are the value of the symbol. */
+ boolean (*constructor) PARAMS ((struct bfd_link_info *,
+ boolean constructor,
+ const char *name, bfd *abfd, asection *sec,
+ bfd_vma value));
+ /* A function which is called when there is a reference to a warning
+ symbol. WARNING is the warning to be issued. */
+ boolean (*warning) PARAMS ((struct bfd_link_info *,
+ const char *warning));
+ /* A function which is called when a relocation is attempted against
+ an undefined symbol. NAME is the symbol which is undefined.
+ ABFD, SECTION and ADDRESS identify the location from which the
+ reference is made. */
+ boolean (*undefined_symbol) PARAMS ((struct bfd_link_info *,
+ const char *name, bfd *abfd,
+ asection *section, bfd_vma address));
+ /* A function which is called when a reloc overflow occurs. NAME is
+ the name of the symbol or section the reloc is against,
+ RELOC_NAME is the name of the relocation, and ADDEND is any
+ addend that is used. ABFD, SECTION and ADDRESS identify the
+ location at which the overflow occurs; if this is the result of a
+ bfd_section_reloc_link_order or bfd_symbol_reloc_link_order, then
+ ABFD will be NULL. */
+ boolean (*reloc_overflow) PARAMS ((struct bfd_link_info *,
+ const char *name,
+ const char *reloc_name, bfd_vma addend,
+ bfd *abfd, asection *section,
+ bfd_vma address));
+ /* A function which is called when a dangerous reloc is performed.
+ The canonical example is an a29k IHCONST reloc which does not
+ follow an IHIHALF reloc. MESSAGE is an appropriate message.
+ ABFD, SECTION and ADDRESS identify the location at which the
+ problem occurred; if this is the result of a
+ bfd_section_reloc_link_order or bfd_symbol_reloc_link_order, then
+ ABFD will be NULL. */
+ boolean (*reloc_dangerous) PARAMS ((struct bfd_link_info *,
+ const char *message,
+ bfd *abfd, asection *section,
+ bfd_vma address));
+ /* A function which is called when a reloc is found to be attached
+ to a symbol which is not being written out. NAME is the name of
+ the symbol. ABFD, SECTION and ADDRESS identify the location of
+ the reloc; if this is the result of a
+ bfd_section_reloc_link_order or bfd_symbol_reloc_link_order, then
+ ABFD will be NULL. */
+ boolean (*unattached_reloc) PARAMS ((struct bfd_link_info *,
+ const char *name,
+ bfd *abfd, asection *section,
+ bfd_vma address));
+ /* A function which is called when a symbol in notice_hash is
+ defined or referenced. NAME is the symbol. ABFD, SECTION and
+ ADDRESS are the value of the symbol. If SECTION is
+ bfd_und_section, this is a reference. */
+ boolean (*notice) PARAMS ((struct bfd_link_info *, const char *name,
+ bfd *abfd, asection *section, bfd_vma address));
+};
+
+/* The linker builds link_order structures which tell the code how to
+ include input data in the output file. */
+
+/* These are the types of link_order structures. */
+
+enum bfd_link_order_type
+{
+ bfd_undefined_link_order, /* Undefined. */
+ bfd_indirect_link_order, /* Built from a section. */
+ bfd_fill_link_order, /* Fill with a 16 bit constant. */
+ bfd_data_link_order, /* Set to explicit data. */
+ bfd_section_reloc_link_order, /* Relocate against a section. */
+ bfd_symbol_reloc_link_order /* Relocate against a symbol. */
+};
+
+/* This is the link_order structure itself. These form a chain
+ attached to the section whose contents they are describing. */
+
+struct bfd_link_order
+{
+ /* Next link_order in chain. */
+ struct bfd_link_order *next;
+ /* Type of link_order. */
+ enum bfd_link_order_type type;
+ /* Offset within output section. */
+ bfd_vma offset;
+ /* Size within output section. */
+ bfd_size_type size;
+ /* Type specific information. */
+ union
+ {
+ struct
+ {
+ /* Section to include. If this is used, then
+ section->output_section must be the section the
+ link_order is attached to, section->output_offset must
+ equal the link_order offset field, and section->_raw_size
+ must equal the link_order size field. Maybe these
+ restrictions should be relaxed someday. */
+ asection *section;
+ } indirect;
+ struct
+ {
+ /* Value to fill with. */
+ unsigned int value;
+ } fill;
+ struct
+ {
+ /* Data to put into file. The size field gives the number
+ of bytes which this field points to. */
+ bfd_byte *contents;
+ } data;
+ struct
+ {
+ /* Description of reloc to generate. Used for
+ bfd_section_reloc_link_order and
+ bfd_symbol_reloc_link_order. */
+ struct bfd_link_order_reloc *p;
+ } reloc;
+ } u;
+};
+
+/* A linker order of type bfd_section_reloc_link_order or
+ bfd_symbol_reloc_link_order means to create a reloc against a
+ section or symbol, respectively. This is used to implement -Ur to
+ generate relocs for the constructor tables. The
+ bfd_link_order_reloc structure describes the reloc that BFD should
+ create. It is similar to a arelent, but I didn't use arelent
+ because the linker does not know anything about most symbols, and
+ any asymbol structure it creates will be partially meaningless.
+ This information could logically be in the bfd_link_order struct,
+ but I didn't want to waste the space since these types of relocs
+ are relatively rare. */
+
+struct bfd_link_order_reloc
+{
+ /* Reloc type. */
+ bfd_reloc_code_real_type reloc;
+
+ union
+ {
+ /* For type bfd_section_reloc_link_order, this is the section
+ the reloc should be against. This must be a section in the
+ output BFD, not any of the input BFDs. */
+ asection *section;
+ /* For type bfd_symbol_reloc_link_order, this is the name of the
+ symbol the reloc should be against. */
+ const char *name;
+ } u;
+
+ /* Addend to use. The object file should contain zero. The BFD
+ backend is responsible for filling in the contents of the object
+ file correctly. For some object file formats (e.g., COFF) the
+ addend must be stored into in the object file, and for some
+ (e.g., SPARC a.out) it is kept in the reloc. */
+ bfd_vma addend;
+};
+
+/* Allocate a new link_order for a section. */
+extern struct bfd_link_order *bfd_new_link_order PARAMS ((bfd *, asection *));
+
+#endif
diff --git a/gnu/usr.bin/gdb/gdb/blockframe.c b/gnu/usr.bin/gdb/gdb/blockframe.c
new file mode 100644
index 0000000..732bbdb
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/blockframe.c
@@ -0,0 +1,866 @@
+/* Get info from stack frames;
+ convert between frames, blocks, functions and pc values.
+ Copyright 1986, 1987, 1988, 1989, 1991 Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "defs.h"
+#include "symtab.h"
+#include "bfd.h"
+#include "symfile.h"
+#include "objfiles.h"
+#include "frame.h"
+#include "gdbcore.h"
+#include "value.h" /* for read_register */
+#include "target.h" /* for target_has_stack */
+#include "inferior.h" /* for read_pc */
+#include "annotate.h"
+
+/* Is ADDR inside the startup file? Note that if your machine
+ has a way to detect the bottom of the stack, there is no need
+ to call this function from FRAME_CHAIN_VALID; the reason for
+ doing so is that some machines have no way of detecting bottom
+ of stack.
+
+ A PC of zero is always considered to be the bottom of the stack. */
+
+int
+inside_entry_file (addr)
+ CORE_ADDR addr;
+{
+ if (addr == 0)
+ return 1;
+ if (symfile_objfile == 0)
+ return 0;
+#if CALL_DUMMY_LOCATION == AT_ENTRY_POINT
+ /* Do not stop backtracing if the pc is in the call dummy
+ at the entry point. */
+ if (PC_IN_CALL_DUMMY (addr, 0, 0))
+ return 0;
+#endif
+ return (addr >= symfile_objfile -> ei.entry_file_lowpc &&
+ addr < symfile_objfile -> ei.entry_file_highpc);
+}
+
+/* Test a specified PC value to see if it is in the range of addresses
+ that correspond to the main() function. See comments above for why
+ we might want to do this.
+
+ Typically called from FRAME_CHAIN_VALID.
+
+ A PC of zero is always considered to be the bottom of the stack. */
+
+int
+inside_main_func (pc)
+CORE_ADDR pc;
+{
+ if (pc == 0)
+ return 1;
+ if (symfile_objfile == 0)
+ return 0;
+ return (symfile_objfile -> ei.main_func_lowpc <= pc &&
+ symfile_objfile -> ei.main_func_highpc > pc);
+}
+
+/* Test a specified PC value to see if it is in the range of addresses
+ that correspond to the process entry point function. See comments
+ in objfiles.h for why we might want to do this.
+
+ Typically called from FRAME_CHAIN_VALID.
+
+ A PC of zero is always considered to be the bottom of the stack. */
+
+int
+inside_entry_func (pc)
+CORE_ADDR pc;
+{
+ if (pc == 0)
+ return 1;
+ if (symfile_objfile == 0)
+ return 0;
+#if CALL_DUMMY_LOCATION == AT_ENTRY_POINT
+ /* Do not stop backtracing if the pc is in the call dummy
+ at the entry point. */
+ if (PC_IN_CALL_DUMMY (pc, 0, 0))
+ return 0;
+#endif
+ return (symfile_objfile -> ei.entry_func_lowpc <= pc &&
+ symfile_objfile -> ei.entry_func_highpc > pc);
+}
+
+/* Address of innermost stack frame (contents of FP register) */
+
+static FRAME current_frame;
+
+/*
+ * Cache for frame addresses already read by gdb. Valid only while
+ * inferior is stopped. Control variables for the frame cache should
+ * be local to this module.
+ */
+struct obstack frame_cache_obstack;
+
+/* Return the innermost (currently executing) stack frame. */
+
+FRAME
+get_current_frame ()
+{
+ /* We assume its address is kept in a general register;
+ param.h says which register. */
+
+ return current_frame;
+}
+
+void
+set_current_frame (frame)
+ FRAME frame;
+{
+ current_frame = frame;
+}
+
+FRAME
+create_new_frame (addr, pc)
+ FRAME_ADDR addr;
+ CORE_ADDR pc;
+{
+ struct frame_info *fci; /* Same type as FRAME */
+ char *name;
+
+ fci = (struct frame_info *)
+ obstack_alloc (&frame_cache_obstack,
+ sizeof (struct frame_info));
+
+ /* Arbitrary frame */
+ fci->next = (struct frame_info *) 0;
+ fci->prev = (struct frame_info *) 0;
+ fci->frame = addr;
+ fci->pc = pc;
+ find_pc_partial_function (pc, &name, (CORE_ADDR *)NULL,(CORE_ADDR *)NULL);
+ fci->signal_handler_caller = IN_SIGTRAMP (fci->pc, name);
+
+#ifdef INIT_EXTRA_FRAME_INFO
+ INIT_EXTRA_FRAME_INFO (0, fci);
+#endif
+
+ return fci;
+}
+
+/* Return the frame that called FRAME.
+ If FRAME is the original frame (it has no caller), return 0. */
+
+FRAME
+get_prev_frame (frame)
+ FRAME frame;
+{
+ /* We're allowed to know that FRAME and "struct frame_info *" are
+ the same */
+ return get_prev_frame_info (frame);
+}
+
+/* Return the frame that FRAME calls (0 if FRAME is the innermost
+ frame). */
+
+FRAME
+get_next_frame (frame)
+ FRAME frame;
+{
+ /* We're allowed to know that FRAME and "struct frame_info *" are
+ the same */
+ return frame->next;
+}
+
+/*
+ * Flush the entire frame cache.
+ */
+void
+flush_cached_frames ()
+{
+ /* Since we can't really be sure what the first object allocated was */
+ obstack_free (&frame_cache_obstack, 0);
+ obstack_init (&frame_cache_obstack);
+
+ current_frame = (struct frame_info *) 0; /* Invalidate cache */
+ annotate_frames_invalid ();
+}
+
+/* Flush the frame cache, and start a new one if necessary. */
+void
+reinit_frame_cache ()
+{
+ flush_cached_frames ();
+ if (target_has_stack)
+ {
+ set_current_frame (create_new_frame (read_fp (), read_pc ()));
+ select_frame (get_current_frame (), 0);
+ }
+ else
+ {
+ set_current_frame (0);
+ select_frame ((FRAME) 0, -1);
+ }
+}
+
+/* Return a structure containing various interesting information
+ about a specified stack frame. */
+/* How do I justify including this function? Well, the FRAME
+ identifier format has gone through several changes recently, and
+ it's not completely inconceivable that it could happen again. If
+ it does, have this routine around will help */
+
+struct frame_info *
+get_frame_info (frame)
+ FRAME frame;
+{
+ return frame;
+}
+
+/* If a machine allows frameless functions, it should define a macro
+ FRAMELESS_FUNCTION_INVOCATION(FI, FRAMELESS) in param.h. FI is the struct
+ frame_info for the frame, and FRAMELESS should be set to nonzero
+ if it represents a frameless function invocation. */
+
+/* Return nonzero if the function for this frame lacks a prologue. Many
+ machines can define FRAMELESS_FUNCTION_INVOCATION to just call this
+ function. */
+
+int
+frameless_look_for_prologue (frame)
+ FRAME frame;
+{
+ CORE_ADDR func_start, after_prologue;
+ func_start = (get_pc_function_start (frame->pc) +
+ FUNCTION_START_OFFSET);
+ if (func_start)
+ {
+ after_prologue = func_start;
+#ifdef SKIP_PROLOGUE_FRAMELESS_P
+ /* This is faster, since only care whether there *is* a prologue,
+ not how long it is. */
+ SKIP_PROLOGUE_FRAMELESS_P (after_prologue);
+#else
+ SKIP_PROLOGUE (after_prologue);
+#endif
+ return after_prologue == func_start;
+ }
+ else
+ /* If we can't find the start of the function, we don't really
+ know whether the function is frameless, but we should be able
+ to get a reasonable (i.e. best we can do under the
+ circumstances) backtrace by saying that it isn't. */
+ return 0;
+}
+
+/* Default a few macros that people seldom redefine. */
+
+#if !defined (INIT_FRAME_PC)
+#define INIT_FRAME_PC(fromleaf, prev) \
+ prev->pc = (fromleaf ? SAVED_PC_AFTER_CALL (prev->next) : \
+ prev->next ? FRAME_SAVED_PC (prev->next) : read_pc ());
+#endif
+
+#ifndef FRAME_CHAIN_COMBINE
+#define FRAME_CHAIN_COMBINE(chain, thisframe) (chain)
+#endif
+
+/* Return a structure containing various interesting information
+ about the frame that called NEXT_FRAME. Returns NULL
+ if there is no such frame. */
+
+struct frame_info *
+get_prev_frame_info (next_frame)
+ FRAME next_frame;
+{
+ FRAME_ADDR address = 0;
+ struct frame_info *prev;
+ int fromleaf = 0;
+ char *name;
+
+ /* If the requested entry is in the cache, return it.
+ Otherwise, figure out what the address should be for the entry
+ we're about to add to the cache. */
+
+ if (!next_frame)
+ {
+#if 0
+ /* This screws value_of_variable, which just wants a nice clean
+ NULL return from block_innermost_frame if there are no frames.
+ I don't think I've ever seen this message happen otherwise.
+ And returning NULL here is a perfectly legitimate thing to do. */
+ if (!current_frame)
+ {
+ error ("You haven't set up a process's stack to examine.");
+ }
+#endif
+
+ return current_frame;
+ }
+
+ /* If we have the prev one, return it */
+ if (next_frame->prev)
+ return next_frame->prev;
+
+ /* On some machines it is possible to call a function without
+ setting up a stack frame for it. On these machines, we
+ define this macro to take two args; a frameinfo pointer
+ identifying a frame and a variable to set or clear if it is
+ or isn't leafless. */
+#ifdef FRAMELESS_FUNCTION_INVOCATION
+ /* Still don't want to worry about this except on the innermost
+ frame. This macro will set FROMLEAF if NEXT_FRAME is a
+ frameless function invocation. */
+ if (!(next_frame->next))
+ {
+ FRAMELESS_FUNCTION_INVOCATION (next_frame, fromleaf);
+ if (fromleaf)
+ address = next_frame->frame;
+ }
+#endif
+
+ if (!fromleaf)
+ {
+ /* Two macros defined in tm.h specify the machine-dependent
+ actions to be performed here.
+ First, get the frame's chain-pointer.
+ If that is zero, the frame is the outermost frame or a leaf
+ called by the outermost frame. This means that if start
+ calls main without a frame, we'll return 0 (which is fine
+ anyway).
+
+ Nope; there's a problem. This also returns when the current
+ routine is a leaf of main. This is unacceptable. We move
+ this to after the ffi test; I'd rather have backtraces from
+ start go curfluy than have an abort called from main not show
+ main. */
+ address = FRAME_CHAIN (next_frame);
+ if (!FRAME_CHAIN_VALID (address, next_frame))
+ return 0;
+ address = FRAME_CHAIN_COMBINE (address, next_frame);
+ }
+ if (address == 0)
+ return 0;
+
+ prev = (struct frame_info *)
+ obstack_alloc (&frame_cache_obstack,
+ sizeof (struct frame_info));
+
+ if (next_frame)
+ next_frame->prev = prev;
+ prev->next = next_frame;
+ prev->prev = (struct frame_info *) 0;
+ prev->frame = address;
+ prev->signal_handler_caller = 0;
+
+/* This change should not be needed, FIXME! We should
+ determine whether any targets *need* INIT_FRAME_PC to happen
+ after INIT_EXTRA_FRAME_INFO and come up with a simple way to
+ express what goes on here.
+
+ INIT_EXTRA_FRAME_INFO is called from two places: create_new_frame
+ (where the PC is already set up) and here (where it isn't).
+ INIT_FRAME_PC is only called from here, always after
+ INIT_EXTRA_FRAME_INFO.
+
+ The catch is the MIPS, where INIT_EXTRA_FRAME_INFO requires the PC
+ value (which hasn't been set yet). Some other machines appear to
+ require INIT_EXTRA_FRAME_INFO before they can do INIT_FRAME_PC. Phoo.
+
+ We shouldn't need INIT_FRAME_PC_FIRST to add more complication to
+ an already overcomplicated part of GDB. gnu@cygnus.com, 15Sep92.
+
+ To answer the question, yes the sparc needs INIT_FRAME_PC after
+ INIT_EXTRA_FRAME_INFO. Suggested scheme:
+
+ SETUP_INNERMOST_FRAME()
+ Default version is just create_new_frame (read_fp ()),
+ read_pc ()). Machines with extra frame info would do that (or the
+ local equivalent) and then set the extra fields.
+ SETUP_ARBITRARY_FRAME(argc, argv)
+ Only change here is that create_new_frame would no longer init extra
+ frame info; SETUP_ARBITRARY_FRAME would have to do that.
+ INIT_PREV_FRAME(fromleaf, prev)
+ Replace INIT_EXTRA_FRAME_INFO and INIT_FRAME_PC. This should
+ also return a flag saying whether to keep the new frame, or
+ whether to discard it, because on some machines (e.g. mips) it
+ is really awkward to have FRAME_CHAIN_VALID called *before*
+ INIT_EXTRA_FRAME_INFO (there is no good way to get information
+ deduced in FRAME_CHAIN_VALID into the extra fields of the new frame).
+ std_frame_pc(fromleaf, prev)
+ This is the default setting for INIT_PREV_FRAME. It just does what
+ the default INIT_FRAME_PC does. Some machines will call it from
+ INIT_PREV_FRAME (either at the beginning, the end, or in the middle).
+ Some machines won't use it.
+ kingdon@cygnus.com, 13Apr93, 31Jan94. */
+
+#ifdef INIT_FRAME_PC_FIRST
+ INIT_FRAME_PC_FIRST (fromleaf, prev);
+#endif
+
+#ifdef INIT_EXTRA_FRAME_INFO
+ INIT_EXTRA_FRAME_INFO(fromleaf, prev);
+#endif
+
+ /* This entry is in the frame queue now, which is good since
+ FRAME_SAVED_PC may use that queue to figure out its value
+ (see tm-sparc.h). We want the pc saved in the inferior frame. */
+ INIT_FRAME_PC(fromleaf, prev);
+
+ /* If ->frame and ->pc are unchanged, we are in the process of getting
+ ourselves into an infinite backtrace. Some architectures check this
+ in FRAME_CHAIN or thereabouts, but it seems like there is no reason
+ this can't be an architecture-independent check. */
+ if (next_frame != NULL)
+ {
+ if (prev->frame == next_frame->frame
+ && prev->pc == next_frame->pc)
+ {
+ next_frame->prev = NULL;
+ obstack_free (&frame_cache_obstack, prev);
+ return NULL;
+ }
+ }
+
+ find_pc_partial_function (prev->pc, &name,
+ (CORE_ADDR *)NULL,(CORE_ADDR *)NULL);
+ if (IN_SIGTRAMP (prev->pc, name))
+ prev->signal_handler_caller = 1;
+
+ return prev;
+}
+
+CORE_ADDR
+get_frame_pc (frame)
+ FRAME frame;
+{
+ struct frame_info *fi;
+ fi = get_frame_info (frame);
+ return fi->pc;
+}
+
+#if defined (FRAME_FIND_SAVED_REGS)
+/* Find the addresses in which registers are saved in FRAME. */
+
+void
+get_frame_saved_regs (frame_info_addr, saved_regs_addr)
+ struct frame_info *frame_info_addr;
+ struct frame_saved_regs *saved_regs_addr;
+{
+ FRAME_FIND_SAVED_REGS (frame_info_addr, *saved_regs_addr);
+}
+#endif
+
+/* Return the innermost lexical block in execution
+ in a specified stack frame. The frame address is assumed valid. */
+
+struct block *
+get_frame_block (frame)
+ FRAME frame;
+{
+ struct frame_info *fi;
+ CORE_ADDR pc;
+
+ fi = get_frame_info (frame);
+
+ pc = fi->pc;
+ if (fi->next != 0 && fi->next->signal_handler_caller == 0)
+ /* We are not in the innermost frame and we were not interrupted
+ by a signal. We need to subtract one to get the correct block,
+ in case the call instruction was the last instruction of the block.
+ If there are any machines on which the saved pc does not point to
+ after the call insn, we probably want to make fi->pc point after
+ the call insn anyway. */
+ --pc;
+ return block_for_pc (pc);
+}
+
+struct block *
+get_current_block ()
+{
+ return block_for_pc (read_pc ());
+}
+
+CORE_ADDR
+get_pc_function_start (pc)
+ CORE_ADDR pc;
+{
+ register struct block *bl;
+ register struct symbol *symbol;
+ register struct minimal_symbol *msymbol;
+ CORE_ADDR fstart;
+
+ if ((bl = block_for_pc (pc)) != NULL &&
+ (symbol = block_function (bl)) != NULL)
+ {
+ bl = SYMBOL_BLOCK_VALUE (symbol);
+ fstart = BLOCK_START (bl);
+ }
+ else if ((msymbol = lookup_minimal_symbol_by_pc (pc)) != NULL)
+ {
+ fstart = SYMBOL_VALUE_ADDRESS (msymbol);
+ }
+ else
+ {
+ fstart = 0;
+ }
+ return (fstart);
+}
+
+/* Return the symbol for the function executing in frame FRAME. */
+
+struct symbol *
+get_frame_function (frame)
+ FRAME frame;
+{
+ register struct block *bl = get_frame_block (frame);
+ if (bl == 0)
+ return 0;
+ return block_function (bl);
+}
+
+/* Return the blockvector immediately containing the innermost lexical block
+ containing the specified pc value, or 0 if there is none.
+ PINDEX is a pointer to the index value of the block. If PINDEX
+ is NULL, we don't pass this information back to the caller. */
+
+struct blockvector *
+blockvector_for_pc (pc, pindex)
+ register CORE_ADDR pc;
+ int *pindex;
+{
+ register struct block *b;
+ register int bot, top, half;
+ register struct symtab *s;
+ struct blockvector *bl;
+
+ /* First search all symtabs for one whose file contains our pc */
+ s = find_pc_symtab (pc);
+ if (s == 0)
+ return 0;
+
+ bl = BLOCKVECTOR (s);
+ b = BLOCKVECTOR_BLOCK (bl, 0);
+
+ /* Then search that symtab for the smallest block that wins. */
+ /* Use binary search to find the last block that starts before PC. */
+
+ bot = 0;
+ top = BLOCKVECTOR_NBLOCKS (bl);
+
+ while (top - bot > 1)
+ {
+ half = (top - bot + 1) >> 1;
+ b = BLOCKVECTOR_BLOCK (bl, bot + half);
+ if (BLOCK_START (b) <= pc)
+ bot += half;
+ else
+ top = bot + half;
+ }
+
+ /* Now search backward for a block that ends after PC. */
+
+ while (bot >= 0)
+ {
+ b = BLOCKVECTOR_BLOCK (bl, bot);
+ if (BLOCK_END (b) > pc)
+ {
+ if (pindex)
+ *pindex = bot;
+ return bl;
+ }
+ bot--;
+ }
+
+ return 0;
+}
+
+/* Return the innermost lexical block containing the specified pc value,
+ or 0 if there is none. */
+
+struct block *
+block_for_pc (pc)
+ register CORE_ADDR pc;
+{
+ register struct blockvector *bl;
+ int index;
+
+ bl = blockvector_for_pc (pc, &index);
+ if (bl)
+ return BLOCKVECTOR_BLOCK (bl, index);
+ return 0;
+}
+
+/* Return the function containing pc value PC.
+ Returns 0 if function is not known. */
+
+struct symbol *
+find_pc_function (pc)
+ CORE_ADDR pc;
+{
+ register struct block *b = block_for_pc (pc);
+ if (b == 0)
+ return 0;
+ return block_function (b);
+}
+
+/* These variables are used to cache the most recent result
+ * of find_pc_partial_function. */
+
+static CORE_ADDR cache_pc_function_low = 0;
+static CORE_ADDR cache_pc_function_high = 0;
+static char *cache_pc_function_name = 0;
+
+/* Clear cache, e.g. when symbol table is discarded. */
+
+void
+clear_pc_function_cache()
+{
+ cache_pc_function_low = 0;
+ cache_pc_function_high = 0;
+ cache_pc_function_name = (char *)0;
+}
+
+/* Finds the "function" (text symbol) that is smaller than PC but
+ greatest of all of the potential text symbols. Sets *NAME and/or
+ *ADDRESS conditionally if that pointer is non-null. If ENDADDR is
+ non-null, then set *ENDADDR to be the end of the function
+ (exclusive), but passing ENDADDR as non-null means that the
+ function might cause symbols to be read. This function either
+ succeeds or fails (not halfway succeeds). If it succeeds, it sets
+ *NAME, *ADDRESS, and *ENDADDR to real information and returns 1.
+ If it fails, it sets *NAME, *ADDRESS, and *ENDADDR to zero
+ and returns 0. */
+
+int
+find_pc_partial_function (pc, name, address, endaddr)
+ CORE_ADDR pc;
+ char **name;
+ CORE_ADDR *address;
+ CORE_ADDR *endaddr;
+{
+ struct partial_symtab *pst;
+ struct symbol *f;
+ struct minimal_symbol *msymbol;
+ struct partial_symbol *psb;
+ struct obj_section *sec;
+
+ if (pc >= cache_pc_function_low && pc < cache_pc_function_high)
+ goto return_cached_value;
+
+ /* If sigtramp is in the u area, it counts as a function (especially
+ important for step_1). */
+#if defined SIGTRAMP_START
+ if (IN_SIGTRAMP (pc, (char *)NULL))
+ {
+ cache_pc_function_low = SIGTRAMP_START;
+ cache_pc_function_high = SIGTRAMP_END;
+ cache_pc_function_name = "<sigtramp>";
+
+ goto return_cached_value;
+ }
+#endif
+
+ msymbol = lookup_minimal_symbol_by_pc (pc);
+ pst = find_pc_psymtab (pc);
+ if (pst)
+ {
+ /* Need to read the symbols to get a good value for the end address. */
+ if (endaddr != NULL && !pst->readin)
+ {
+ /* Need to get the terminal in case symbol-reading produces
+ output. */
+ target_terminal_ours_for_output ();
+ PSYMTAB_TO_SYMTAB (pst);
+ }
+
+ if (pst->readin)
+ {
+ /* Checking whether the msymbol has a larger value is for the
+ "pathological" case mentioned in print_frame_info. */
+ f = find_pc_function (pc);
+ if (f != NULL
+ && (msymbol == NULL
+ || (BLOCK_START (SYMBOL_BLOCK_VALUE (f))
+ >= SYMBOL_VALUE_ADDRESS (msymbol))))
+ {
+ cache_pc_function_low = BLOCK_START (SYMBOL_BLOCK_VALUE (f));
+ cache_pc_function_high = BLOCK_END (SYMBOL_BLOCK_VALUE (f));
+ cache_pc_function_name = SYMBOL_NAME (f);
+ goto return_cached_value;
+ }
+ }
+ else
+ {
+ /* Now that static symbols go in the minimal symbol table, perhaps
+ we could just ignore the partial symbols. But at least for now
+ we use the partial or minimal symbol, whichever is larger. */
+ psb = find_pc_psymbol (pst, pc);
+
+ if (psb
+ && (msymbol == NULL ||
+ (SYMBOL_VALUE_ADDRESS (psb)
+ >= SYMBOL_VALUE_ADDRESS (msymbol))))
+ {
+ /* This case isn't being cached currently. */
+ if (address)
+ *address = SYMBOL_VALUE_ADDRESS (psb);
+ if (name)
+ *name = SYMBOL_NAME (psb);
+ /* endaddr non-NULL can't happen here. */
+ return 1;
+ }
+ }
+ }
+
+ /* Not in the normal symbol tables, see if the pc is in a known section.
+ If it's not, then give up. This ensures that anything beyond the end
+ of the text seg doesn't appear to be part of the last function in the
+ text segment. */
+
+ sec = find_pc_section (pc);
+
+ if (!sec)
+ msymbol = NULL;
+
+ /* Must be in the minimal symbol table. */
+ if (msymbol == NULL)
+ {
+ /* No available symbol. */
+ if (name != NULL)
+ *name = 0;
+ if (address != NULL)
+ *address = 0;
+ if (endaddr != NULL)
+ *endaddr = 0;
+ return 0;
+ }
+
+ /* See if we're in a transfer table for Sun shared libs. */
+
+ if (msymbol -> type == mst_text || msymbol -> type == mst_file_text)
+ cache_pc_function_low = SYMBOL_VALUE_ADDRESS (msymbol);
+ else
+ /* It is a transfer table for Sun shared libraries. */
+ cache_pc_function_low = pc - FUNCTION_START_OFFSET;
+
+ cache_pc_function_name = SYMBOL_NAME (msymbol);
+
+ /* Use the lesser of the next minimal symbol, or the end of the section, as
+ the end of the function. */
+
+ if (SYMBOL_NAME (msymbol + 1) != NULL
+ && SYMBOL_VALUE_ADDRESS (msymbol + 1) < sec->endaddr)
+ cache_pc_function_high = SYMBOL_VALUE_ADDRESS (msymbol + 1);
+ else
+ /* We got the start address from the last msymbol in the objfile.
+ So the end address is the end of the section. */
+ cache_pc_function_high = sec->endaddr;
+
+ return_cached_value:
+ if (address)
+ *address = cache_pc_function_low;
+ if (name)
+ *name = cache_pc_function_name;
+ if (endaddr)
+ *endaddr = cache_pc_function_high;
+ return 1;
+}
+
+/* Return the innermost stack frame executing inside of BLOCK,
+ or NULL if there is no such frame. If BLOCK is NULL, just return NULL. */
+
+FRAME
+block_innermost_frame (block)
+ struct block *block;
+{
+ struct frame_info *fi;
+ register FRAME frame;
+ register CORE_ADDR start;
+ register CORE_ADDR end;
+
+ if (block == NULL)
+ return NULL;
+
+ start = BLOCK_START (block);
+ end = BLOCK_END (block);
+
+ frame = 0;
+ while (1)
+ {
+ frame = get_prev_frame (frame);
+ if (frame == 0)
+ return 0;
+ fi = get_frame_info (frame);
+ if (fi->pc >= start && fi->pc < end)
+ return frame;
+ }
+}
+
+/* Return the full FRAME which corresponds to the given FRAME_ADDR
+ or NULL if no FRAME on the chain corresponds to FRAME_ADDR. */
+
+FRAME
+find_frame_addr_in_frame_chain (frame_addr)
+ FRAME_ADDR frame_addr;
+{
+ FRAME frame = NULL;
+
+ if (frame_addr == (CORE_ADDR)0)
+ return NULL;
+
+ while (1)
+ {
+ frame = get_prev_frame (frame);
+ if (frame == NULL)
+ return NULL;
+
+ if (FRAME_FP (frame) == frame_addr)
+ return frame;
+ }
+}
+
+#ifdef SIGCONTEXT_PC_OFFSET
+/* Get saved user PC for sigtramp from sigcontext for BSD style sigtramp. */
+
+CORE_ADDR
+sigtramp_saved_pc (frame)
+ FRAME frame;
+{
+ CORE_ADDR sigcontext_addr;
+ char buf[TARGET_PTR_BIT / TARGET_CHAR_BIT];
+ int ptrbytes = TARGET_PTR_BIT / TARGET_CHAR_BIT;
+ int sigcontext_offs = (2 * TARGET_INT_BIT) / TARGET_CHAR_BIT;
+
+ /* Get sigcontext address, it is the third parameter on the stack. */
+ if (frame->next)
+ sigcontext_addr = read_memory_integer (FRAME_ARGS_ADDRESS (frame->next)
+ + FRAME_ARGS_SKIP + sigcontext_offs,
+ ptrbytes);
+ else
+ sigcontext_addr = read_memory_integer (read_register (SP_REGNUM)
+ + sigcontext_offs,
+ ptrbytes);
+
+ /* Don't cause a memory_error when accessing sigcontext in case the stack
+ layout has changed or the stack is corrupt. */
+ target_read_memory (sigcontext_addr + SIGCONTEXT_PC_OFFSET, buf, ptrbytes);
+ return extract_unsigned_integer (buf, ptrbytes);
+}
+#endif /* SIGCONTEXT_PC_OFFSET */
+
+void
+_initialize_blockframe ()
+{
+ obstack_init (&frame_cache_obstack);
+}
diff --git a/gnu/usr.bin/gdb/gdb/breakpoint.c b/gnu/usr.bin/gdb/gdb/breakpoint.c
new file mode 100644
index 0000000..fe75ed13
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/breakpoint.c
@@ -0,0 +1,4052 @@
+/* Everything about breakpoints, for GDB.
+ Copyright 1986, 1987, 1989, 1990, 1991, 1992, 1993, 1994
+ Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "defs.h"
+#include <ctype.h>
+#include "symtab.h"
+#include "frame.h"
+#include "breakpoint.h"
+#include "gdbtypes.h"
+#include "expression.h"
+#include "gdbcore.h"
+#include "gdbcmd.h"
+#include "value.h"
+#include "ctype.h"
+#include "command.h"
+#include "inferior.h"
+#include "thread.h"
+#include "target.h"
+#include "language.h"
+#include <string.h>
+#include "demangle.h"
+#include "annotate.h"
+
+/* local function prototypes */
+
+static void
+catch_command_1 PARAMS ((char *, int, int));
+
+static void
+enable_delete_command PARAMS ((char *, int));
+
+static void
+enable_delete_breakpoint PARAMS ((struct breakpoint *));
+
+static void
+enable_once_command PARAMS ((char *, int));
+
+static void
+enable_once_breakpoint PARAMS ((struct breakpoint *));
+
+static void
+disable_command PARAMS ((char *, int));
+
+static void
+disable_breakpoint PARAMS ((struct breakpoint *));
+
+static void
+enable_command PARAMS ((char *, int));
+
+static void
+enable_breakpoint PARAMS ((struct breakpoint *));
+
+static void
+map_breakpoint_numbers PARAMS ((char *, void (*)(struct breakpoint *)));
+
+static void
+ignore_command PARAMS ((char *, int));
+
+static int
+breakpoint_re_set_one PARAMS ((char *));
+
+static void
+delete_command PARAMS ((char *, int));
+
+static void
+clear_command PARAMS ((char *, int));
+
+static void
+catch_command PARAMS ((char *, int));
+
+static struct symtabs_and_lines
+get_catch_sals PARAMS ((int));
+
+static void
+watch_command PARAMS ((char *, int));
+
+static int
+can_use_hardware_watchpoint PARAMS ((struct value *));
+
+static void
+tbreak_command PARAMS ((char *, int));
+
+static void
+break_command_1 PARAMS ((char *, int, int));
+
+static void
+mention PARAMS ((struct breakpoint *));
+
+static struct breakpoint *
+set_raw_breakpoint PARAMS ((struct symtab_and_line));
+
+static void
+check_duplicates PARAMS ((CORE_ADDR));
+
+static void
+describe_other_breakpoints PARAMS ((CORE_ADDR));
+
+static void
+breakpoints_info PARAMS ((char *, int));
+
+static void
+breakpoint_1 PARAMS ((int, int));
+
+static bpstat
+bpstat_alloc PARAMS ((struct breakpoint *, bpstat));
+
+static int
+breakpoint_cond_eval PARAMS ((char *));
+
+static void
+cleanup_executing_breakpoints PARAMS ((int));
+
+static void
+commands_command PARAMS ((char *, int));
+
+static void
+condition_command PARAMS ((char *, int));
+
+static int
+get_number PARAMS ((char **));
+
+static void
+set_breakpoint_count PARAMS ((int));
+
+static int
+remove_breakpoint PARAMS ((struct breakpoint *));
+
+extern int addressprint; /* Print machine addresses? */
+
+/* Are we executing breakpoint commands? */
+static int executing_breakpoint_commands;
+
+/* Walk the following statement or block through all breakpoints.
+ ALL_BREAKPOINTS_SAFE does so even if the statment deletes the current
+ breakpoint. */
+
+#define ALL_BREAKPOINTS(b) for (b = breakpoint_chain; b; b = b->next)
+
+#define ALL_BREAKPOINTS_SAFE(b,tmp) \
+ for (b = breakpoint_chain; \
+ b? (tmp=b->next, 1): 0; \
+ b = tmp)
+
+/* By default no support for hardware watchpoints is assumed. */
+#ifndef TARGET_CAN_USE_HARDWARE_WATCHPOINT
+#define TARGET_CAN_USE_HARDWARE_WATCHPOINT(TYPE,CNT,OTHERTYPE) 0
+#define target_remove_watchpoint(ADDR,LEN,TYPE) -1
+#define target_insert_watchpoint(ADDR,LEN,TYPE) -1
+#endif
+
+#ifndef target_insert_hw_breakpoint
+#define target_remove_hw_breakpoint(ADDR,SHADOW) -1
+#define target_insert_hw_breakpoint(ADDR,SHADOW) -1
+#endif
+
+#ifndef target_stopped_data_address
+#define target_stopped_data_address() 0
+#endif
+
+/* True if breakpoint hit counts should be displayed in breakpoint info. */
+
+int show_breakpoint_hit_counts = 1;
+
+/* Chain of all breakpoints defined. */
+
+static struct breakpoint *breakpoint_chain;
+
+/* Number of last breakpoint made. */
+
+static int breakpoint_count;
+
+/* Set breakpoint count to NUM. */
+
+static void
+set_breakpoint_count (num)
+ int num;
+{
+ breakpoint_count = num;
+ set_internalvar (lookup_internalvar ("bpnum"),
+ value_from_longest (builtin_type_int, (LONGEST) num));
+}
+
+/* Used in run_command to zero the hit count when a new run starts. */
+
+void
+clear_breakpoint_hit_counts ()
+{
+ struct breakpoint *b;
+
+ ALL_BREAKPOINTS (b)
+ b->hit_count = 0;
+}
+
+/* Default address, symtab and line to put a breakpoint at
+ for "break" command with no arg.
+ if default_breakpoint_valid is zero, the other three are
+ not valid, and "break" with no arg is an error.
+
+ This set by print_stack_frame, which calls set_default_breakpoint. */
+
+int default_breakpoint_valid;
+CORE_ADDR default_breakpoint_address;
+struct symtab *default_breakpoint_symtab;
+int default_breakpoint_line;
+
+/* *PP is a string denoting a breakpoint. Get the number of the breakpoint.
+ Advance *PP after the string and any trailing whitespace.
+
+ Currently the string can either be a number or "$" followed by the name
+ of a convenience variable. Making it an expression wouldn't work well
+ for map_breakpoint_numbers (e.g. "4 + 5 + 6"). */
+static int
+get_number (pp)
+ char **pp;
+{
+ int retval;
+ char *p = *pp;
+
+ if (p == NULL)
+ /* Empty line means refer to the last breakpoint. */
+ return breakpoint_count;
+ else if (*p == '$')
+ {
+ /* Make a copy of the name, so we can null-terminate it
+ to pass to lookup_internalvar(). */
+ char *varname;
+ char *start = ++p;
+ value_ptr val;
+
+ while (isalnum (*p) || *p == '_')
+ p++;
+ varname = (char *) alloca (p - start + 1);
+ strncpy (varname, start, p - start);
+ varname[p - start] = '\0';
+ val = value_of_internalvar (lookup_internalvar (varname));
+ if (TYPE_CODE (VALUE_TYPE (val)) != TYPE_CODE_INT)
+ error (
+"Convenience variables used to specify breakpoints must have integer values."
+ );
+ retval = (int) value_as_long (val);
+ }
+ else
+ {
+ if (*p == '-')
+ ++p;
+ while (*p >= '0' && *p <= '9')
+ ++p;
+ if (p == *pp)
+ /* There is no number here. (e.g. "cond a == b"). */
+ error_no_arg ("breakpoint number");
+ retval = atoi (*pp);
+ }
+ if (!(isspace (*p) || *p == '\0'))
+ error ("breakpoint number expected");
+ while (isspace (*p))
+ p++;
+ *pp = p;
+ return retval;
+}
+
+/* condition N EXP -- set break condition of breakpoint N to EXP. */
+
+static void
+condition_command (arg, from_tty)
+ char *arg;
+ int from_tty;
+{
+ register struct breakpoint *b;
+ char *p;
+ register int bnum;
+
+ if (arg == 0)
+ error_no_arg ("breakpoint number");
+
+ p = arg;
+ bnum = get_number (&p);
+
+ ALL_BREAKPOINTS (b)
+ if (b->number == bnum)
+ {
+ if (b->cond)
+ {
+ free ((PTR)b->cond);
+ b->cond = 0;
+ }
+ if (b->cond_string != NULL)
+ free ((PTR)b->cond_string);
+
+ if (*p == 0)
+ {
+ b->cond = 0;
+ b->cond_string = NULL;
+ if (from_tty)
+ printf_filtered ("Breakpoint %d now unconditional.\n", bnum);
+ }
+ else
+ {
+ arg = p;
+ /* I don't know if it matters whether this is the string the user
+ typed in or the decompiled expression. */
+ b->cond_string = savestring (arg, strlen (arg));
+ b->cond = parse_exp_1 (&arg, block_for_pc (b->address), 0);
+ if (*arg)
+ error ("Junk at end of expression");
+ }
+ return;
+ }
+
+ error ("No breakpoint number %d.", bnum);
+}
+
+/* ARGSUSED */
+static void
+commands_command (arg, from_tty)
+ char *arg;
+ int from_tty;
+{
+ register struct breakpoint *b;
+ char *p;
+ register int bnum;
+ struct command_line *l;
+
+ /* If we allowed this, we would have problems with when to
+ free the storage, if we change the commands currently
+ being read from. */
+
+ if (executing_breakpoint_commands)
+ error ("Can't use the \"commands\" command among a breakpoint's commands.");
+
+ p = arg;
+ bnum = get_number (&p);
+ if (p && *p)
+ error ("Unexpected extra arguments following breakpoint number.");
+
+ ALL_BREAKPOINTS (b)
+ if (b->number == bnum)
+ {
+ if (from_tty && input_from_terminal_p ())
+ printf_filtered ("Type commands for when breakpoint %d is hit, one per line.\n\
+End with a line saying just \"end\".\n", bnum);
+ l = read_command_lines ();
+ free_command_lines (&b->commands);
+ b->commands = l;
+ breakpoints_changed ();
+ return;
+ }
+ error ("No breakpoint number %d.", bnum);
+}
+
+extern int memory_breakpoint_size; /* from mem-break.c */
+
+/* Like target_read_memory() but if breakpoints are inserted, return
+ the shadow contents instead of the breakpoints themselves.
+
+ Read "memory data" from whatever target or inferior we have.
+ Returns zero if successful, errno value if not. EIO is used
+ for address out of bounds. If breakpoints are inserted, returns
+ shadow contents, not the breakpoints themselves. From breakpoint.c. */
+
+int
+read_memory_nobpt (memaddr, myaddr, len)
+ CORE_ADDR memaddr;
+ char *myaddr;
+ unsigned len;
+{
+ int status;
+ struct breakpoint *b;
+
+ if (memory_breakpoint_size < 0)
+ /* No breakpoints on this machine. FIXME: This should be
+ dependent on the debugging target. Probably want
+ target_insert_breakpoint to return a size, saying how many
+ bytes of the shadow contents are used, or perhaps have
+ something like target_xfer_shadow. */
+ return target_read_memory (memaddr, myaddr, len);
+
+ ALL_BREAKPOINTS (b)
+ {
+ if (b->type == bp_watchpoint
+ || b->type == bp_hardware_watchpoint
+ || b->type == bp_read_watchpoint
+ || b->type == bp_access_watchpoint
+ || !b->inserted)
+ continue;
+ else if (b->address + memory_breakpoint_size <= memaddr)
+ /* The breakpoint is entirely before the chunk of memory
+ we are reading. */
+ continue;
+ else if (b->address >= memaddr + len)
+ /* The breakpoint is entirely after the chunk of memory we
+ are reading. */
+ continue;
+ else
+ {
+ /* Copy the breakpoint from the shadow contents, and recurse
+ for the things before and after. */
+
+ /* Addresses and length of the part of the breakpoint that
+ we need to copy. */
+ CORE_ADDR membpt = b->address;
+ unsigned int bptlen = memory_breakpoint_size;
+ /* Offset within shadow_contents. */
+ int bptoffset = 0;
+
+ if (membpt < memaddr)
+ {
+ /* Only copy the second part of the breakpoint. */
+ bptlen -= memaddr - membpt;
+ bptoffset = memaddr - membpt;
+ membpt = memaddr;
+ }
+
+ if (membpt + bptlen > memaddr + len)
+ {
+ /* Only copy the first part of the breakpoint. */
+ bptlen -= (membpt + bptlen) - (memaddr + len);
+ }
+
+ memcpy (myaddr + membpt - memaddr,
+ b->shadow_contents + bptoffset, bptlen);
+
+ if (membpt > memaddr)
+ {
+ /* Copy the section of memory before the breakpoint. */
+ status = read_memory_nobpt (memaddr, myaddr, membpt - memaddr);
+ if (status != 0)
+ return status;
+ }
+
+ if (membpt + bptlen < memaddr + len)
+ {
+ /* Copy the section of memory after the breakpoint. */
+ status = read_memory_nobpt
+ (membpt + bptlen,
+ myaddr + membpt + bptlen - memaddr,
+ memaddr + len - (membpt + bptlen));
+ if (status != 0)
+ return status;
+ }
+ return 0;
+ }
+ }
+ /* Nothing overlaps. Just call read_memory_noerr. */
+ return target_read_memory (memaddr, myaddr, len);
+}
+
+/* insert_breakpoints is used when starting or continuing the program.
+ remove_breakpoints is used when the program stops.
+ Both return zero if successful,
+ or an `errno' value if could not write the inferior. */
+
+int
+insert_breakpoints ()
+{
+ register struct breakpoint *b;
+ int val = 0;
+ int disabled_breaks = 0;
+
+ ALL_BREAKPOINTS (b)
+ if (b->type != bp_watchpoint
+ && b->type != bp_hardware_watchpoint
+ && b->type != bp_read_watchpoint
+ && b->type != bp_access_watchpoint
+ && b->enable != disabled
+ && ! b->inserted
+ && ! b->duplicate)
+ {
+ if (b->type == bp_hardware_breakpoint)
+ val = target_insert_hw_breakpoint(b->address, b->shadow_contents);
+ else
+ val = target_insert_breakpoint(b->address, b->shadow_contents);
+ if (val)
+ {
+ /* Can't set the breakpoint. */
+#if defined (DISABLE_UNSETTABLE_BREAK)
+ if (DISABLE_UNSETTABLE_BREAK (b->address))
+ {
+ val = 0;
+ b->enable = disabled;
+ if (!disabled_breaks)
+ {
+ target_terminal_ours_for_output ();
+ fprintf_unfiltered (gdb_stderr,
+ "Cannot insert breakpoint %d:\n", b->number);
+ printf_filtered ("Disabling shared library breakpoints:\n");
+ }
+ disabled_breaks = 1;
+ printf_filtered ("%d ", b->number);
+ }
+ else
+#endif
+ {
+ target_terminal_ours_for_output ();
+ fprintf_unfiltered (gdb_stderr, "Cannot insert breakpoint %d:\n", b->number);
+#ifdef ONE_PROCESS_WRITETEXT
+ fprintf_unfiltered (gdb_stderr,
+ "The same program may be running in another process.\n");
+#endif
+ memory_error (val, b->address); /* which bombs us out */
+ }
+ }
+ else
+ b->inserted = 1;
+ }
+ else if ((b->type == bp_hardware_watchpoint ||
+ b->type == bp_read_watchpoint ||
+ b->type == bp_access_watchpoint)
+ && b->enable == enabled
+ && ! b->inserted
+ && ! b->duplicate)
+ {
+ FRAME saved_frame;
+ int saved_level, within_current_scope;
+ value_ptr mark = value_mark ();
+ value_ptr v;
+
+ /* Save the current frame and level so we can restore it after
+ evaluating the watchpoint expression on its own frame. */
+ saved_frame = selected_frame;
+ saved_level = selected_frame_level;
+
+ /* Determine if the watchpoint is within scope. */
+ if (b->exp_valid_block == NULL)
+ within_current_scope = 1;
+ else
+ {
+ FRAME fr = find_frame_addr_in_frame_chain (b->watchpoint_frame);
+ within_current_scope = (fr != NULL);
+ if (within_current_scope)
+ select_frame (fr, -1);
+ }
+
+ if (within_current_scope)
+ {
+ /* Evaluate the expression and cut the chain of values
+ produced off from the value chain. */
+ v = evaluate_expression (b->exp);
+ value_release_to_mark (mark);
+
+ b->val_chain = v;
+ b->inserted = 1;
+
+ /* Look at each value on the value chain. */
+ for ( ; v; v=v->next)
+ {
+ /* If it's a memory location, then we must watch it. */
+ if (v->lval == lval_memory)
+ {
+ int addr, len, type;
+
+ addr = VALUE_ADDRESS (v) + VALUE_OFFSET (v);
+ len = TYPE_LENGTH (VALUE_TYPE (v));
+ type = 0;
+ if (b->type == bp_read_watchpoint)
+ type = 1;
+ else if (b->type == bp_access_watchpoint)
+ type = 2;
+
+ val = target_insert_watchpoint (addr, len, type);
+ if (val == -1)
+ {
+ b->inserted = 0;
+ break;
+ }
+ val = 0;
+ }
+ }
+ /* Failure to insert a watchpoint on any memory value in the
+ value chain brings us here. */
+ if (!b->inserted)
+ warning ("Hardware watchpoint %d: Could not insert watchpoint\n",
+ b->number);
+ }
+ else
+ {
+ printf_filtered ("\
+Hardware watchpoint %d deleted because the program has left the block in\n\
+which its expression is valid.\n", b->number);
+ if (b->related_breakpoint)
+ delete_breakpoint (b->related_breakpoint);
+ delete_breakpoint (b);
+ }
+
+ /* Restore the frame and level. */
+ select_frame (saved_frame, saved_level);
+ }
+ if (disabled_breaks)
+ printf_filtered ("\n");
+ return val;
+}
+
+
+int
+remove_breakpoints ()
+{
+ register struct breakpoint *b;
+ int val;
+
+ ALL_BREAKPOINTS (b)
+ {
+ if (b->inserted)
+ {
+ val = remove_breakpoint (b);
+ if (val != 0)
+ return val;
+ }
+ }
+ return 0;
+}
+
+
+static int
+remove_breakpoint (b)
+ struct breakpoint *b;
+{
+ int val;
+
+ if (b->type != bp_watchpoint
+ && b->type != bp_hardware_watchpoint
+ && b->type != bp_read_watchpoint
+ && b->type != bp_access_watchpoint)
+ {
+ if (b->type == bp_hardware_breakpoint)
+ val = target_remove_hw_breakpoint(b->address, b->shadow_contents);
+ else
+ val = target_remove_breakpoint(b->address, b->shadow_contents);
+ if (val)
+ return val;
+ b->inserted = 0;
+ }
+ else if ((b->type == bp_hardware_watchpoint ||
+ b->type == bp_read_watchpoint ||
+ b->type == bp_access_watchpoint)
+ && b->enable == enabled
+ && ! b->duplicate)
+ {
+ value_ptr v, n;
+
+ b->inserted = 0;
+ /* Walk down the saved value chain. */
+ for (v = b->val_chain; v; v = v->next)
+ {
+ /* For each memory reference remove the watchpoint
+ at that address. */
+ if (v->lval == lval_memory)
+ {
+ int addr, len;
+
+ addr = VALUE_ADDRESS (v) + VALUE_OFFSET (v);
+ len = TYPE_LENGTH (VALUE_TYPE (v));
+ val = target_remove_watchpoint (addr, len, b->type);
+ if (val == -1)
+ b->inserted = 1;
+ val = 0;
+ }
+ }
+ /* Failure to remove any of the hardware watchpoints comes here. */
+ if (b->inserted)
+ error ("Hardware watchpoint %d: Could not remove watchpoint\n",
+ b->number);
+
+ /* Free the saved value chain. We will construct a new one
+ the next time the watchpoint is inserted. */
+ for (v = b->val_chain; v; v = n)
+ {
+ n = v->next;
+ value_free (v);
+ }
+ b->val_chain = NULL;
+ }
+ return 0;
+}
+
+/* Clear the "inserted" flag in all breakpoints. */
+
+void
+mark_breakpoints_out ()
+{
+ register struct breakpoint *b;
+
+ ALL_BREAKPOINTS (b)
+ b->inserted = 0;
+}
+
+/* Clear the "inserted" flag in all breakpoints and delete any breakpoints
+ which should go away between runs of the program. */
+
+void
+breakpoint_init_inferior ()
+{
+ register struct breakpoint *b, *temp;
+
+ ALL_BREAKPOINTS_SAFE (b, temp)
+ {
+ b->inserted = 0;
+
+ /* If the call dummy breakpoint is at the entry point it will
+ cause problems when the inferior is rerun, so we better
+ get rid of it. */
+ if (b->type == bp_call_dummy)
+ delete_breakpoint (b);
+
+ /* Likewise for scope breakpoints. */
+ if (b->type == bp_watchpoint_scope)
+ delete_breakpoint (b);
+
+ /* Likewise for watchpoints on local expressions. */
+ if ((b->type == bp_watchpoint || b->type == bp_hardware_watchpoint ||
+ b->type == bp_read_watchpoint || b->type == bp_access_watchpoint)
+ && b->exp_valid_block != NULL)
+ delete_breakpoint (b);
+ }
+}
+
+/* breakpoint_here_p (PC) returns 1 if an enabled breakpoint exists at PC.
+ When continuing from a location with a breakpoint,
+ we actually single step once before calling insert_breakpoints. */
+
+int
+breakpoint_here_p (pc)
+ CORE_ADDR pc;
+{
+ register struct breakpoint *b;
+
+ ALL_BREAKPOINTS (b)
+ if (b->enable != disabled && b->address == pc)
+ return 1;
+
+ return 0;
+}
+
+/* Return nonzero if FRAME is a dummy frame. We can't use PC_IN_CALL_DUMMY
+ because figuring out the saved SP would take too much time, at least using
+ get_saved_register on the 68k. This means that for this function to
+ work right a port must use the bp_call_dummy breakpoint. */
+
+int
+frame_in_dummy (frame)
+ FRAME frame;
+{
+ struct breakpoint *b;
+
+#ifdef CALL_DUMMY
+ ALL_BREAKPOINTS (b)
+ {
+ static unsigned LONGEST dummy[] = CALL_DUMMY;
+
+ if (b->type == bp_call_dummy
+ && b->frame == frame->frame
+
+ /* We need to check the PC as well as the frame on the sparc,
+ for signals.exp in the testsuite. */
+ && (frame->pc
+ >= (b->address
+ - sizeof (dummy) / sizeof (LONGEST) * REGISTER_SIZE))
+ && frame->pc <= b->address)
+ return 1;
+ }
+#endif /* CALL_DUMMY */
+ return 0;
+}
+
+/* breakpoint_match_thread (PC, PID) returns true if the breakpoint at PC
+ is valid for process/thread PID. */
+
+int
+breakpoint_thread_match (pc, pid)
+ CORE_ADDR pc;
+ int pid;
+{
+ struct breakpoint *b;
+ int thread;
+
+ thread = pid_to_thread_id (pid);
+
+ ALL_BREAKPOINTS (b)
+ if (b->enable != disabled
+ && b->address == pc
+ && (b->thread == -1 || b->thread == thread))
+ return 1;
+
+ return 0;
+}
+
+
+/* bpstat stuff. External routines' interfaces are documented
+ in breakpoint.h. */
+
+/* Clear a bpstat so that it says we are not at any breakpoint.
+ Also free any storage that is part of a bpstat. */
+
+void
+bpstat_clear (bsp)
+ bpstat *bsp;
+{
+ bpstat p;
+ bpstat q;
+
+ if (bsp == 0)
+ return;
+ p = *bsp;
+ while (p != NULL)
+ {
+ q = p->next;
+ if (p->old_val != NULL)
+ value_free (p->old_val);
+ free ((PTR)p);
+ p = q;
+ }
+ *bsp = NULL;
+}
+
+/* Return a copy of a bpstat. Like "bs1 = bs2" but all storage that
+ is part of the bpstat is copied as well. */
+
+bpstat
+bpstat_copy (bs)
+ bpstat bs;
+{
+ bpstat p = NULL;
+ bpstat tmp;
+ bpstat retval = NULL;
+
+ if (bs == NULL)
+ return bs;
+
+ for (; bs != NULL; bs = bs->next)
+ {
+ tmp = (bpstat) xmalloc (sizeof (*tmp));
+ memcpy (tmp, bs, sizeof (*tmp));
+ if (p == NULL)
+ /* This is the first thing in the chain. */
+ retval = tmp;
+ else
+ p->next = tmp;
+ p = tmp;
+ }
+ p->next = NULL;
+ return retval;
+}
+
+/* Find the bpstat associated with this breakpoint */
+
+bpstat
+bpstat_find_breakpoint(bsp, breakpoint)
+ bpstat bsp;
+ struct breakpoint *breakpoint;
+{
+ if (bsp == NULL) return NULL;
+
+ for (;bsp != NULL; bsp = bsp->next) {
+ if (bsp->breakpoint_at == breakpoint) return bsp;
+ }
+ return NULL;
+}
+
+/* Return the breakpoint number of the first breakpoint we are stopped
+ at. *BSP upon return is a bpstat which points to the remaining
+ breakpoints stopped at (but which is not guaranteed to be good for
+ anything but further calls to bpstat_num).
+ Return 0 if passed a bpstat which does not indicate any breakpoints. */
+
+int
+bpstat_num (bsp)
+ bpstat *bsp;
+{
+ struct breakpoint *b;
+
+ if ((*bsp) == NULL)
+ return 0; /* No more breakpoint values */
+ else
+ {
+ b = (*bsp)->breakpoint_at;
+ *bsp = (*bsp)->next;
+ if (b == NULL)
+ return -1; /* breakpoint that's been deleted since */
+ else
+ return b->number; /* We have its number */
+ }
+}
+
+/* Modify BS so that the actions will not be performed. */
+
+void
+bpstat_clear_actions (bs)
+ bpstat bs;
+{
+ for (; bs != NULL; bs = bs->next)
+ {
+ bs->commands = NULL;
+ if (bs->old_val != NULL)
+ {
+ value_free (bs->old_val);
+ bs->old_val = NULL;
+ }
+ }
+}
+
+/* Stub for cleaning up our state if we error-out of a breakpoint command */
+/* ARGSUSED */
+static void
+cleanup_executing_breakpoints (ignore)
+ int ignore;
+{
+ executing_breakpoint_commands = 0;
+}
+
+/* Execute all the commands associated with all the breakpoints at this
+ location. Any of these commands could cause the process to proceed
+ beyond this point, etc. We look out for such changes by checking
+ the global "breakpoint_proceeded" after each command. */
+
+void
+bpstat_do_actions (bsp)
+ bpstat *bsp;
+{
+ bpstat bs;
+ struct cleanup *old_chain;
+
+ executing_breakpoint_commands = 1;
+ old_chain = make_cleanup (cleanup_executing_breakpoints, 0);
+
+top:
+ bs = *bsp;
+
+ breakpoint_proceeded = 0;
+ for (; bs != NULL; bs = bs->next)
+ {
+ while (bs->commands)
+ {
+ char *line = bs->commands->line;
+ bs->commands = bs->commands->next;
+ execute_command (line, 0);
+ /* If the inferior is proceeded by the command, bomb out now.
+ The bpstat chain has been blown away by wait_for_inferior.
+ But since execution has stopped again, there is a new bpstat
+ to look at, so start over. */
+ if (breakpoint_proceeded)
+ goto top;
+ }
+ }
+
+ executing_breakpoint_commands = 0;
+ discard_cleanups (old_chain);
+}
+
+/* This is the normal print_it function for a bpstat. In the future,
+ much of this logic could (should?) be moved to bpstat_stop_status,
+ by having it set different print_it functions. */
+
+static int
+print_it_normal (bs)
+ bpstat bs;
+{
+ /* bs->breakpoint_at can be NULL if it was a momentary breakpoint
+ which has since been deleted. */
+ if (bs->breakpoint_at == NULL
+ || (bs->breakpoint_at->type != bp_breakpoint
+ && bs->breakpoint_at->type != bp_hardware_breakpoint
+ && bs->breakpoint_at->type != bp_watchpoint
+ && bs->breakpoint_at->type != bp_read_watchpoint
+ && bs->breakpoint_at->type != bp_access_watchpoint
+ && bs->breakpoint_at->type != bp_hardware_watchpoint))
+ return 0;
+
+ if (bs->breakpoint_at->type == bp_breakpoint ||
+ bs->breakpoint_at->type == bp_hardware_breakpoint)
+ {
+ /* I think the user probably only wants to see one breakpoint
+ number, not all of them. */
+ annotate_breakpoint (bs->breakpoint_at->number);
+ printf_filtered ("\nBreakpoint %d, ", bs->breakpoint_at->number);
+ return 0;
+ }
+ else if ((bs->old_val != NULL) &&
+ (bs->breakpoint_at->type == bp_watchpoint ||
+ bs->breakpoint_at->type == bp_access_watchpoint ||
+ bs->breakpoint_at->type == bp_hardware_watchpoint))
+ {
+ annotate_watchpoint (bs->breakpoint_at->number);
+ mention (bs->breakpoint_at);
+ printf_filtered ("\nOld value = ");
+ value_print (bs->old_val, gdb_stdout, 0, Val_pretty_default);
+ printf_filtered ("\nNew value = ");
+ value_print (bs->breakpoint_at->val, gdb_stdout, 0,
+ Val_pretty_default);
+ printf_filtered ("\n");
+ value_free (bs->old_val);
+ bs->old_val = NULL;
+ /* More than one watchpoint may have been triggered. */
+ return -1;
+ }
+ else if (bs->breakpoint_at->type == bp_access_watchpoint ||
+ bs->breakpoint_at->type == bp_read_watchpoint)
+ {
+ mention (bs->breakpoint_at);
+ printf_filtered ("\nValue = ");
+ value_print (bs->breakpoint_at->val, gdb_stdout, 0,
+ Val_pretty_default);
+ printf_filtered ("\n");
+ return -1;
+ }
+ /* We can't deal with it. Maybe another member of the bpstat chain can. */
+ return -1;
+}
+
+/* Print a message indicating what happened. Returns nonzero to
+ say that only the source line should be printed after this (zero
+ return means print the frame as well as the source line). */
+/* Currently we always return zero. */
+int
+bpstat_print (bs)
+ bpstat bs;
+{
+ int val;
+
+ if (bs == NULL)
+ return 0;
+
+ val = (*bs->print_it) (bs);
+ if (val >= 0)
+ return val;
+
+ /* Maybe another breakpoint in the chain caused us to stop.
+ (Currently all watchpoints go on the bpstat whether hit or
+ not. That probably could (should) be changed, provided care is taken
+ with respect to bpstat_explains_signal). */
+ if (bs->next)
+ return bpstat_print (bs->next);
+
+ /* We reached the end of the chain without printing anything. */
+ return 0;
+}
+
+/* Evaluate the expression EXP and return 1 if value is zero.
+ This is used inside a catch_errors to evaluate the breakpoint condition.
+ The argument is a "struct expression *" that has been cast to char * to
+ make it pass through catch_errors. */
+
+static int
+breakpoint_cond_eval (exp)
+ char *exp;
+{
+ value_ptr mark = value_mark ();
+ int i = !value_true (evaluate_expression ((struct expression *)exp));
+ value_free_to_mark (mark);
+ return i;
+}
+
+/* Allocate a new bpstat and chain it to the current one. */
+
+static bpstat
+bpstat_alloc (b, cbs)
+ register struct breakpoint *b;
+ bpstat cbs; /* Current "bs" value */
+{
+ bpstat bs;
+
+ bs = (bpstat) xmalloc (sizeof (*bs));
+ cbs->next = bs;
+ bs->breakpoint_at = b;
+ /* If the condition is false, etc., don't do the commands. */
+ bs->commands = NULL;
+ bs->old_val = NULL;
+ bs->print_it = print_it_normal;
+ return bs;
+}
+
+/* Possible return values for watchpoint_check (this can't be an enum
+ because of check_errors). */
+/* The watchpoint has been deleted. */
+#define WP_DELETED 1
+/* The value has changed. */
+#define WP_VALUE_CHANGED 2
+/* The value has not changed. */
+#define WP_VALUE_NOT_CHANGED 3
+
+/* Check watchpoint condition. */
+
+static int
+watchpoint_check (p)
+ char *p;
+{
+ bpstat bs = (bpstat) p;
+ struct breakpoint *b;
+ FRAME saved_frame, fr;
+ int within_current_scope, saved_level;
+
+ /* Save the current frame and level so we can restore it after
+ evaluating the watchpoint expression on its own frame. */
+ saved_frame = selected_frame;
+ saved_level = selected_frame_level;
+
+ b = bs->breakpoint_at;
+
+ if (b->exp_valid_block == NULL)
+ within_current_scope = 1;
+ else
+ {
+ fr = find_frame_addr_in_frame_chain (b->watchpoint_frame);
+ within_current_scope = (fr != NULL);
+ if (within_current_scope)
+ /* If we end up stopping, the current frame will get selected
+ in normal_stop. So this call to select_frame won't affect
+ the user. */
+ select_frame (fr, -1);
+ }
+
+ if (within_current_scope)
+ {
+ /* We use value_{,free_to_}mark because it could be a
+ *long* time before we return to the command level and
+ call free_all_values. We can't call free_all_values because
+ we might be in the middle of evaluating a function call. */
+
+ value_ptr mark = value_mark ();
+ value_ptr new_val = evaluate_expression (bs->breakpoint_at->exp);
+ if (!value_equal (b->val, new_val))
+ {
+ release_value (new_val);
+ value_free_to_mark (mark);
+ bs->old_val = b->val;
+ b->val = new_val;
+ /* We will stop here */
+ select_frame (saved_frame, saved_level);
+ return WP_VALUE_CHANGED;
+ }
+ else
+ {
+ /* Nothing changed, don't do anything. */
+ value_free_to_mark (mark);
+ /* We won't stop here */
+ select_frame (saved_frame, saved_level);
+ return WP_VALUE_NOT_CHANGED;
+ }
+ }
+ else
+ {
+ /* This seems like the only logical thing to do because
+ if we temporarily ignored the watchpoint, then when
+ we reenter the block in which it is valid it contains
+ garbage (in the case of a function, it may have two
+ garbage values, one before and one after the prologue).
+ So we can't even detect the first assignment to it and
+ watch after that (since the garbage may or may not equal
+ the first value assigned). */
+ printf_filtered ("\
+Watchpoint %d deleted because the program has left the block in\n\
+which its expression is valid.\n", bs->breakpoint_at->number);
+ if (b->related_breakpoint)
+ delete_breakpoint (b->related_breakpoint);
+ delete_breakpoint (b);
+
+ select_frame (saved_frame, saved_level);
+ return WP_DELETED;
+ }
+}
+
+/* This is used when everything which needs to be printed has
+ already been printed. But we still want to print the frame. */
+static int
+print_it_done (bs)
+ bpstat bs;
+{
+ return 0;
+}
+
+/* This is used when nothing should be printed for this bpstat entry. */
+
+static int
+print_it_noop (bs)
+ bpstat bs;
+{
+ return -1;
+}
+
+/* Get a bpstat associated with having just stopped at address *PC
+ and frame address FRAME_ADDRESS. Update *PC to point at the
+ breakpoint (if we hit a breakpoint). NOT_A_BREAKPOINT is nonzero
+ if this is known to not be a real breakpoint (it could still be a
+ watchpoint, though). */
+
+/* Determine whether we stopped at a breakpoint, etc, or whether we
+ don't understand this stop. Result is a chain of bpstat's such that:
+
+ if we don't understand the stop, the result is a null pointer.
+
+ if we understand why we stopped, the result is not null.
+
+ Each element of the chain refers to a particular breakpoint or
+ watchpoint at which we have stopped. (We may have stopped for
+ several reasons concurrently.)
+
+ Each element of the chain has valid next, breakpoint_at,
+ commands, FIXME??? fields.
+
+ */
+
+bpstat
+bpstat_stop_status (pc, frame_address, not_a_breakpoint)
+ CORE_ADDR *pc;
+ FRAME_ADDR frame_address;
+ int not_a_breakpoint;
+{
+ register struct breakpoint *b;
+ CORE_ADDR bp_addr;
+#if DECR_PC_AFTER_BREAK != 0 || defined (SHIFT_INST_REGS)
+ /* True if we've hit a breakpoint (as opposed to a watchpoint). */
+ int real_breakpoint = 0;
+#endif
+ /* Root of the chain of bpstat's */
+ struct bpstat root_bs[1];
+ /* Pointer to the last thing in the chain currently. */
+ bpstat bs = root_bs;
+ static char message1[] =
+ "Error evaluating expression for watchpoint %d\n";
+ char message[sizeof (message1) + 30 /* slop */];
+
+ /* Get the address where the breakpoint would have been. */
+ bp_addr = *pc - DECR_PC_AFTER_BREAK;
+
+ ALL_BREAKPOINTS (b)
+ {
+ if (b->enable == disabled)
+ continue;
+
+ if (b->type != bp_watchpoint
+ && b->type != bp_hardware_watchpoint
+ && b->type != bp_read_watchpoint
+ && b->type != bp_access_watchpoint
+ && b->type != bp_hardware_breakpoint
+ && b->address != bp_addr)
+ continue;
+
+#ifndef DECR_PC_AFTER_HW_BREAK
+#define DECR_PC_AFTER_HW_BREAK 0
+#endif
+ if (b->type == bp_hardware_breakpoint
+ && b->address != (bp_addr - DECR_PC_AFTER_HW_BREAK))
+ continue;
+
+ if (b->type != bp_watchpoint
+ && b->type != bp_hardware_watchpoint
+ && b->type != bp_read_watchpoint
+ && b->type != bp_access_watchpoint
+ && not_a_breakpoint)
+ continue;
+
+ /* Come here if it's a watchpoint, or if the break address matches */
+
+ ++(b->hit_count);
+
+ bs = bpstat_alloc (b, bs); /* Alloc a bpstat to explain stop */
+
+ bs->stop = 1;
+ bs->print = 1;
+
+ sprintf (message, message1, b->number);
+ if (b->type == bp_watchpoint || b->type == bp_hardware_watchpoint)
+ {
+ switch (catch_errors (watchpoint_check, (char *) bs, message,
+ RETURN_MASK_ALL))
+ {
+ case WP_DELETED:
+ /* We've already printed what needs to be printed. */
+ bs->print_it = print_it_done;
+ /* Stop. */
+ break;
+ case WP_VALUE_CHANGED:
+ /* Stop. */
+ break;
+ case WP_VALUE_NOT_CHANGED:
+ /* Don't stop. */
+ bs->print_it = print_it_noop;
+ bs->stop = 0;
+ continue;
+ default:
+ /* Can't happen. */
+ /* FALLTHROUGH */
+ case 0:
+ /* Error from catch_errors. */
+ printf_filtered ("Watchpoint %d deleted.\n", b->number);
+ if (b->related_breakpoint)
+ delete_breakpoint (b->related_breakpoint);
+ delete_breakpoint (b);
+ /* We've already printed what needs to be printed. */
+ bs->print_it = print_it_done;
+
+ /* Stop. */
+ break;
+ }
+ }
+ else if (b->type == bp_read_watchpoint || b->type == bp_access_watchpoint)
+ {
+ CORE_ADDR addr;
+ value_ptr v;
+ int found = 0;
+
+ addr = target_stopped_data_address();
+ if (addr == 0) continue;
+ for (v = b->val_chain; v; v = v->next)
+ {
+ if (v->lval == lval_memory)
+ {
+ CORE_ADDR vaddr;
+
+ vaddr = VALUE_ADDRESS (v) + VALUE_OFFSET (v);
+ if (addr == vaddr)
+ found = 1;
+ }
+ }
+ if (found)
+ switch (catch_errors (watchpoint_check, (char *) bs, message,
+ RETURN_MASK_ALL))
+ {
+ case WP_DELETED:
+ /* We've already printed what needs to be printed. */
+ bs->print_it = print_it_done;
+ /* Stop. */
+ break;
+ case WP_VALUE_CHANGED:
+ case WP_VALUE_NOT_CHANGED:
+ /* Stop. */
+ break;
+ default:
+ /* Can't happen. */
+ case 0:
+ /* Error from catch_errors. */
+ printf_filtered ("Watchpoint %d deleted.\n", b->number);
+ if (b->related_breakpoint)
+ delete_breakpoint (b->related_breakpoint);
+ delete_breakpoint (b);
+ /* We've already printed what needs to be printed. */
+ bs->print_it = print_it_done;
+ break;
+ }
+ }
+#if DECR_PC_AFTER_BREAK != 0 || defined (SHIFT_INST_REGS)
+ else
+ real_breakpoint = 1;
+#endif
+
+ if (b->frame && b->frame != frame_address)
+ bs->stop = 0;
+ else
+ {
+ int value_is_zero = 0;
+
+ if (b->cond)
+ {
+ /* Need to select the frame, with all that implies
+ so that the conditions will have the right context. */
+ select_frame (get_current_frame (), 0);
+ value_is_zero
+ = catch_errors (breakpoint_cond_eval, (char *)(b->cond),
+ "Error in testing breakpoint condition:\n",
+ RETURN_MASK_ALL);
+ /* FIXME-someday, should give breakpoint # */
+ free_all_values ();
+ }
+ if (b->cond && value_is_zero)
+ {
+ bs->stop = 0;
+ }
+ else if (b->ignore_count > 0)
+ {
+ b->ignore_count--;
+ bs->stop = 0;
+ }
+ else
+ {
+ /* We will stop here */
+ if (b->disposition == disable)
+ b->enable = disabled;
+ bs->commands = b->commands;
+ if (b->silent)
+ bs->print = 0;
+ if (bs->commands && STREQ ("silent", bs->commands->line))
+ {
+ bs->commands = bs->commands->next;
+ bs->print = 0;
+ }
+ }
+ }
+ /* Print nothing for this entry if we dont stop or if we dont print. */
+ if (bs->stop == 0 || bs->print == 0)
+ bs->print_it = print_it_noop;
+ }
+
+ bs->next = NULL; /* Terminate the chain */
+ bs = root_bs->next; /* Re-grab the head of the chain */
+#if DECR_PC_AFTER_BREAK != 0 || defined (SHIFT_INST_REGS)
+ if (bs)
+ {
+ if (real_breakpoint)
+ {
+ *pc = bp_addr;
+#if defined (SHIFT_INST_REGS)
+ SHIFT_INST_REGS();
+#else /* No SHIFT_INST_REGS. */
+ write_pc (bp_addr);
+#endif /* No SHIFT_INST_REGS. */
+ }
+ }
+#endif /* DECR_PC_AFTER_BREAK != 0. */
+
+ /* The value of a hardware watchpoint hasn't changed, but the
+ intermediate memory locations we are watching may have. */
+ if (bs && ! bs->stop &&
+ (bs->breakpoint_at->type == bp_hardware_watchpoint ||
+ bs->breakpoint_at->type == bp_read_watchpoint ||
+ bs->breakpoint_at->type == bp_access_watchpoint))
+ {
+ remove_breakpoints ();
+ insert_breakpoints ();
+ }
+ return bs;
+}
+
+/* Tell what to do about this bpstat. */
+struct bpstat_what
+bpstat_what (bs)
+ bpstat bs;
+{
+ /* Classify each bpstat as one of the following. */
+ enum class {
+ /* This bpstat element has no effect on the main_action. */
+ no_effect = 0,
+
+ /* There was a watchpoint, stop but don't print. */
+ wp_silent,
+
+ /* There was a watchpoint, stop and print. */
+ wp_noisy,
+
+ /* There was a breakpoint but we're not stopping. */
+ bp_nostop,
+
+ /* There was a breakpoint, stop but don't print. */
+ bp_silent,
+
+ /* There was a breakpoint, stop and print. */
+ bp_noisy,
+
+ /* We hit the longjmp breakpoint. */
+ long_jump,
+
+ /* We hit the longjmp_resume breakpoint. */
+ long_resume,
+
+ /* We hit the step_resume breakpoint. */
+ step_resume,
+
+ /* We hit the through_sigtramp breakpoint. */
+ through_sig,
+
+ /* This is just used to count how many enums there are. */
+ class_last
+ };
+
+ /* Here is the table which drives this routine. So that we can
+ format it pretty, we define some abbreviations for the
+ enum bpstat_what codes. */
+#define keep_c BPSTAT_WHAT_KEEP_CHECKING
+#define stop_s BPSTAT_WHAT_STOP_SILENT
+#define stop_n BPSTAT_WHAT_STOP_NOISY
+#define single BPSTAT_WHAT_SINGLE
+#define setlr BPSTAT_WHAT_SET_LONGJMP_RESUME
+#define clrlr BPSTAT_WHAT_CLEAR_LONGJMP_RESUME
+#define clrlrs BPSTAT_WHAT_CLEAR_LONGJMP_RESUME_SINGLE
+#define sr BPSTAT_WHAT_STEP_RESUME
+#define ts BPSTAT_WHAT_THROUGH_SIGTRAMP
+
+/* "Can't happen." Might want to print an error message.
+ abort() is not out of the question, but chances are GDB is just
+ a bit confused, not unusable. */
+#define err BPSTAT_WHAT_STOP_NOISY
+
+ /* Given an old action and a class, come up with a new action. */
+ /* One interesting property of this table is that wp_silent is the same
+ as bp_silent and wp_noisy is the same as bp_noisy. That is because
+ after stopping, the check for whether to step over a breakpoint
+ (BPSTAT_WHAT_SINGLE type stuff) is handled in proceed() without
+ reference to how we stopped. We retain separate wp_silent and bp_silent
+ codes in case we want to change that someday. */
+
+ /* step_resume entries: a step resume breakpoint overrides another
+ breakpoint of signal handling (see comment in wait_for_inferior
+ at first IN_SIGTRAMP where we set the step_resume breakpoint). */
+ /* We handle the through_sigtramp_breakpoint the same way; having both
+ one of those and a step_resume_breakpoint is probably very rare (?). */
+
+ static const enum bpstat_what_main_action
+ table[(int)class_last][(int)BPSTAT_WHAT_LAST] =
+ {
+ /* old action */
+ /* keep_c stop_s stop_n single setlr clrlr clrlrs sr ts
+ */
+/*no_effect*/ {keep_c,stop_s,stop_n,single, setlr , clrlr , clrlrs, sr, ts},
+/*wp_silent*/ {stop_s,stop_s,stop_n,stop_s, stop_s, stop_s, stop_s, sr, ts},
+/*wp_noisy*/ {stop_n,stop_n,stop_n,stop_n, stop_n, stop_n, stop_n, sr, ts},
+/*bp_nostop*/ {single,stop_s,stop_n,single, setlr , clrlrs, clrlrs, sr, ts},
+/*bp_silent*/ {stop_s,stop_s,stop_n,stop_s, stop_s, stop_s, stop_s, sr, ts},
+/*bp_noisy*/ {stop_n,stop_n,stop_n,stop_n, stop_n, stop_n, stop_n, sr, ts},
+/*long_jump*/ {setlr ,stop_s,stop_n,setlr , err , err , err , sr, ts},
+/*long_resume*/ {clrlr ,stop_s,stop_n,clrlrs, err , err , err , sr, ts},
+/*step_resume*/ {sr ,sr ,sr ,sr , sr , sr , sr , sr, ts},
+/*through_sig*/ {ts ,ts ,ts ,ts , ts , ts , ts , ts, ts}
+ };
+#undef keep_c
+#undef stop_s
+#undef stop_n
+#undef single
+#undef setlr
+#undef clrlr
+#undef clrlrs
+#undef err
+#undef sr
+#undef ts
+ enum bpstat_what_main_action current_action = BPSTAT_WHAT_KEEP_CHECKING;
+ struct bpstat_what retval;
+
+ retval.call_dummy = 0;
+ for (; bs != NULL; bs = bs->next)
+ {
+ enum class bs_class = no_effect;
+ if (bs->breakpoint_at == NULL)
+ /* I suspect this can happen if it was a momentary breakpoint
+ which has since been deleted. */
+ continue;
+ switch (bs->breakpoint_at->type)
+ {
+ case bp_breakpoint:
+ case bp_hardware_breakpoint:
+ case bp_until:
+ case bp_finish:
+ if (bs->stop)
+ {
+ if (bs->print)
+ bs_class = bp_noisy;
+ else
+ bs_class = bp_silent;
+ }
+ else
+ bs_class = bp_nostop;
+ break;
+ case bp_watchpoint:
+ case bp_hardware_watchpoint:
+ case bp_read_watchpoint:
+ case bp_access_watchpoint:
+ if (bs->stop)
+ {
+ if (bs->print)
+ bs_class = wp_noisy;
+ else
+ bs_class = wp_silent;
+ }
+ else
+ /* There was a watchpoint, but we're not stopping. This requires
+ no further action. */
+ bs_class = no_effect;
+ break;
+ case bp_longjmp:
+ bs_class = long_jump;
+ break;
+ case bp_longjmp_resume:
+ bs_class = long_resume;
+ break;
+ case bp_step_resume:
+ if (bs->stop)
+ {
+ bs_class = step_resume;
+ }
+ else
+ /* It is for the wrong frame. */
+ bs_class = bp_nostop;
+ break;
+ case bp_through_sigtramp:
+ bs_class = through_sig;
+ break;
+ case bp_watchpoint_scope:
+ bs_class = bp_nostop;
+ break;
+
+ case bp_call_dummy:
+ /* Make sure the action is stop (silent or noisy), so infrun.c
+ pops the dummy frame. */
+ bs_class = bp_silent;
+ retval.call_dummy = 1;
+ break;
+ }
+ current_action = table[(int)bs_class][(int)current_action];
+ }
+ retval.main_action = current_action;
+ return retval;
+}
+
+/* Nonzero if we should step constantly (e.g. watchpoints on machines
+ without hardware support). This isn't related to a specific bpstat,
+ just to things like whether watchpoints are set. */
+
+int
+bpstat_should_step ()
+{
+ struct breakpoint *b;
+ ALL_BREAKPOINTS (b)
+ if (b->enable == enabled && b->type == bp_watchpoint)
+ return 1;
+ return 0;
+}
+
+/* Print information on breakpoint number BNUM, or -1 if all.
+ If WATCHPOINTS is zero, process only breakpoints; if WATCHPOINTS
+ is nonzero, process only watchpoints. */
+
+static void
+breakpoint_1 (bnum, allflag)
+ int bnum;
+ int allflag;
+{
+ register struct breakpoint *b;
+ register struct command_line *l;
+ register struct symbol *sym;
+ CORE_ADDR last_addr = (CORE_ADDR)-1;
+ int found_a_breakpoint = 0;
+ static char *bptypes[] = {"breakpoint", "hw breakpoint",
+ "until", "finish", "watchpoint",
+ "hw watchpoint", "read watchpoint",
+ "acc watchpoint", "longjmp",
+ "longjmp resume", "step resume",
+ "watchpoint scope", "call dummy" };
+ static char *bpdisps[] = {"del", "dis", "keep"};
+ static char bpenables[] = "ny";
+ char wrap_indent[80];
+
+ ALL_BREAKPOINTS (b)
+ if (bnum == -1
+ || bnum == b->number)
+ {
+/* We only print out user settable breakpoints unless the allflag is set. */
+ if (!allflag
+ && b->type != bp_breakpoint
+ && b->type != bp_hardware_breakpoint
+ && b->type != bp_watchpoint
+ && b->type != bp_read_watchpoint
+ && b->type != bp_access_watchpoint
+ && b->type != bp_hardware_watchpoint)
+ continue;
+
+ if (!found_a_breakpoint++)
+ {
+ annotate_breakpoints_headers ();
+
+ annotate_field (0);
+ printf_filtered ("Num ");
+ annotate_field (1);
+ printf_filtered ("Type ");
+ annotate_field (2);
+ printf_filtered ("Disp ");
+ annotate_field (3);
+ printf_filtered ("Enb ");
+ if (addressprint)
+ {
+ annotate_field (4);
+ printf_filtered ("Address ");
+ }
+ annotate_field (5);
+ printf_filtered ("What\n");
+
+ annotate_breakpoints_table ();
+ }
+
+ annotate_record ();
+ annotate_field (0);
+ printf_filtered ("%-3d ", b->number);
+ annotate_field (1);
+ printf_filtered ("%-14s ", bptypes[(int)b->type]);
+ annotate_field (2);
+ printf_filtered ("%-4s ", bpdisps[(int)b->disposition]);
+ annotate_field (3);
+ printf_filtered ("%-3c ", bpenables[(int)b->enable]);
+
+ strcpy (wrap_indent, " ");
+ if (addressprint)
+ strcat (wrap_indent, " ");
+ switch (b->type)
+ {
+ case bp_watchpoint:
+ case bp_hardware_watchpoint:
+ case bp_read_watchpoint:
+ case bp_access_watchpoint:
+ /* Field 4, the address, is omitted (which makes the columns
+ not line up too nicely with the headers, but the effect
+ is relatively readable). */
+ annotate_field (5);
+ print_expression (b->exp, gdb_stdout);
+ break;
+
+ case bp_breakpoint:
+ case bp_hardware_breakpoint:
+ case bp_until:
+ case bp_finish:
+ case bp_longjmp:
+ case bp_longjmp_resume:
+ case bp_step_resume:
+ case bp_through_sigtramp:
+ case bp_watchpoint_scope:
+ case bp_call_dummy:
+ if (addressprint)
+ {
+ annotate_field (4);
+ /* FIXME-32x64: need a print_address_numeric with
+ field width */
+ printf_filtered
+ ("%s ",
+ local_hex_string_custom
+ ((unsigned long) b->address, "08l"));
+ }
+
+ annotate_field (5);
+
+ last_addr = b->address;
+ if (b->source_file)
+ {
+ sym = find_pc_function (b->address);
+ if (sym)
+ {
+ fputs_filtered ("in ", gdb_stdout);
+ fputs_filtered (SYMBOL_SOURCE_NAME (sym), gdb_stdout);
+ wrap_here (wrap_indent);
+ fputs_filtered (" at ", gdb_stdout);
+ }
+ fputs_filtered (b->source_file, gdb_stdout);
+ printf_filtered (":%d", b->line_number);
+ }
+ else
+ print_address_symbolic (b->address, gdb_stdout, demangle, " ");
+ break;
+ }
+
+ printf_filtered ("\n");
+
+ if (b->frame)
+ {
+ annotate_field (6);
+
+ printf_filtered ("\tstop only in stack frame at ");
+ print_address_numeric (b->frame, 1, gdb_stdout);
+ printf_filtered ("\n");
+ }
+
+ if (b->cond)
+ {
+ annotate_field (7);
+
+ printf_filtered ("\tstop only if ");
+ print_expression (b->cond, gdb_stdout);
+ printf_filtered ("\n");
+ }
+
+ if (show_breakpoint_hit_counts && b->hit_count)
+ {
+ /* FIXME should make an annotation for this */
+
+ printf_filtered ("\tbreakpoint already hit %d times\n",
+ b->hit_count);
+ }
+
+ if (b->ignore_count)
+ {
+ annotate_field (8);
+
+ printf_filtered ("\tignore next %d hits\n", b->ignore_count);
+ }
+
+ if ((l = b->commands))
+ {
+ annotate_field (9);
+
+ while (l)
+ {
+ fputs_filtered ("\t", gdb_stdout);
+ fputs_filtered (l->line, gdb_stdout);
+ fputs_filtered ("\n", gdb_stdout);
+ l = l->next;
+ }
+ }
+ }
+
+ if (!found_a_breakpoint)
+ {
+ if (bnum == -1)
+ printf_filtered ("No breakpoints or watchpoints.\n");
+ else
+ printf_filtered ("No breakpoint or watchpoint number %d.\n", bnum);
+ }
+ else
+ /* Compare against (CORE_ADDR)-1 in case some compiler decides
+ that a comparison of an unsigned with -1 is always false. */
+ if (last_addr != (CORE_ADDR)-1)
+ set_next_address (last_addr);
+
+ annotate_breakpoints_table_end ();
+}
+
+/* ARGSUSED */
+static void
+breakpoints_info (bnum_exp, from_tty)
+ char *bnum_exp;
+ int from_tty;
+{
+ int bnum = -1;
+
+ if (bnum_exp)
+ bnum = parse_and_eval_address (bnum_exp);
+
+ breakpoint_1 (bnum, 0);
+}
+
+#if MAINTENANCE_CMDS
+
+/* ARGSUSED */
+static void
+maintenance_info_breakpoints (bnum_exp, from_tty)
+ char *bnum_exp;
+ int from_tty;
+{
+ int bnum = -1;
+
+ if (bnum_exp)
+ bnum = parse_and_eval_address (bnum_exp);
+
+ breakpoint_1 (bnum, 1);
+}
+
+#endif
+
+/* Print a message describing any breakpoints set at PC. */
+
+static void
+describe_other_breakpoints (pc)
+ register CORE_ADDR pc;
+{
+ register int others = 0;
+ register struct breakpoint *b;
+
+ ALL_BREAKPOINTS (b)
+ if (b->address == pc)
+ others++;
+ if (others > 0)
+ {
+ printf_filtered ("Note: breakpoint%s ", (others > 1) ? "s" : "");
+ ALL_BREAKPOINTS (b)
+ if (b->address == pc)
+ {
+ others--;
+ printf_filtered
+ ("%d%s%s ",
+ b->number,
+ (b->enable == disabled) ? " (disabled)" : "",
+ (others > 1) ? "," : ((others == 1) ? " and" : ""));
+ }
+ printf_filtered ("also set at pc ");
+ print_address_numeric (pc, 1, gdb_stdout);
+ printf_filtered (".\n");
+ }
+}
+
+/* Set the default place to put a breakpoint
+ for the `break' command with no arguments. */
+
+void
+set_default_breakpoint (valid, addr, symtab, line)
+ int valid;
+ CORE_ADDR addr;
+ struct symtab *symtab;
+ int line;
+{
+ default_breakpoint_valid = valid;
+ default_breakpoint_address = addr;
+ default_breakpoint_symtab = symtab;
+ default_breakpoint_line = line;
+}
+
+/* Rescan breakpoints at address ADDRESS,
+ marking the first one as "first" and any others as "duplicates".
+ This is so that the bpt instruction is only inserted once. */
+
+static void
+check_duplicates (address)
+ CORE_ADDR address;
+{
+ register struct breakpoint *b;
+ register int count = 0;
+
+ if (address == 0) /* Watchpoints are uninteresting */
+ return;
+
+ ALL_BREAKPOINTS (b)
+ if (b->enable != disabled && b->address == address)
+ {
+ count++;
+ b->duplicate = count > 1;
+ }
+}
+
+/* Low level routine to set a breakpoint.
+ Takes as args the three things that every breakpoint must have.
+ Returns the breakpoint object so caller can set other things.
+ Does not set the breakpoint number!
+ Does not print anything.
+
+ ==> This routine should not be called if there is a chance of later
+ error(); otherwise it leaves a bogus breakpoint on the chain. Validate
+ your arguments BEFORE calling this routine! */
+
+static struct breakpoint *
+set_raw_breakpoint (sal)
+ struct symtab_and_line sal;
+{
+ register struct breakpoint *b, *b1;
+
+ b = (struct breakpoint *) xmalloc (sizeof (struct breakpoint));
+ memset (b, 0, sizeof (*b));
+ b->address = sal.pc;
+ if (sal.symtab == NULL)
+ b->source_file = NULL;
+ else
+ b->source_file = savestring (sal.symtab->filename,
+ strlen (sal.symtab->filename));
+ b->thread = -1;
+ b->line_number = sal.line;
+ b->enable = enabled;
+ b->next = 0;
+ b->silent = 0;
+ b->ignore_count = 0;
+ b->commands = NULL;
+ b->frame = 0;
+
+ /* Add this breakpoint to the end of the chain
+ so that a list of breakpoints will come out in order
+ of increasing numbers. */
+
+ b1 = breakpoint_chain;
+ if (b1 == 0)
+ breakpoint_chain = b;
+ else
+ {
+ while (b1->next)
+ b1 = b1->next;
+ b1->next = b;
+ }
+
+ check_duplicates (sal.pc);
+ breakpoints_changed ();
+
+ return b;
+}
+
+static void
+create_longjmp_breakpoint(func_name)
+ char *func_name;
+{
+ struct symtab_and_line sal;
+ struct breakpoint *b;
+ static int internal_breakpoint_number = -1;
+
+ if (func_name != NULL)
+ {
+ struct minimal_symbol *m;
+
+ m = lookup_minimal_symbol(func_name, (struct objfile *)NULL);
+ if (m)
+ sal.pc = SYMBOL_VALUE_ADDRESS (m);
+ else
+ return;
+ }
+ else
+ sal.pc = 0;
+
+ sal.symtab = NULL;
+ sal.line = 0;
+
+ b = set_raw_breakpoint(sal);
+ if (!b) return;
+
+ b->type = func_name != NULL ? bp_longjmp : bp_longjmp_resume;
+ b->disposition = donttouch;
+ b->enable = disabled;
+ b->silent = 1;
+ if (func_name)
+ b->addr_string = strsave(func_name);
+ b->number = internal_breakpoint_number--;
+}
+
+/* Call this routine when stepping and nexting to enable a breakpoint if we do
+ a longjmp(). When we hit that breakpoint, call
+ set_longjmp_resume_breakpoint() to figure out where we are going. */
+
+void
+enable_longjmp_breakpoint()
+{
+ register struct breakpoint *b;
+
+ ALL_BREAKPOINTS (b)
+ if (b->type == bp_longjmp)
+ {
+ b->enable = enabled;
+ check_duplicates (b->address);
+ }
+}
+
+void
+disable_longjmp_breakpoint()
+{
+ register struct breakpoint *b;
+
+ ALL_BREAKPOINTS (b)
+ if ( b->type == bp_longjmp
+ || b->type == bp_longjmp_resume)
+ {
+ b->enable = disabled;
+ check_duplicates (b->address);
+ }
+}
+
+int
+hw_breakpoint_used_count()
+{
+ register struct breakpoint *b;
+ int i = 0;
+
+ ALL_BREAKPOINTS (b)
+ {
+ if (b->type == bp_hardware_breakpoint && b->enable == enabled)
+ i++;
+ }
+
+ return i;
+}
+
+int
+hw_watchpoint_used_count(type, other_type_used)
+ enum bptype type;
+ int *other_type_used;
+{
+ register struct breakpoint *b;
+ int i = 0;
+
+ *other_type_used = 0;
+ ALL_BREAKPOINTS (b)
+ {
+ if (b->enable == enabled)
+ {
+ if (b->type == type) i++;
+ else if ((b->type == bp_hardware_watchpoint ||
+ b->type == bp_read_watchpoint ||
+ b->type == bp_access_watchpoint)
+ && b->enable == enabled)
+ *other_type_used = 1;
+ }
+ }
+ return i;
+}
+
+/* Call this after hitting the longjmp() breakpoint. Use this to set a new
+ breakpoint at the target of the jmp_buf.
+
+ FIXME - This ought to be done by setting a temporary breakpoint that gets
+ deleted automatically...
+*/
+
+void
+set_longjmp_resume_breakpoint(pc, frame)
+ CORE_ADDR pc;
+ FRAME frame;
+{
+ register struct breakpoint *b;
+
+ ALL_BREAKPOINTS (b)
+ if (b->type == bp_longjmp_resume)
+ {
+ b->address = pc;
+ b->enable = enabled;
+ if (frame != NULL)
+ b->frame = FRAME_FP(frame);
+ else
+ b->frame = 0;
+ check_duplicates (b->address);
+ return;
+ }
+}
+
+/* Set a breakpoint that will evaporate an end of command
+ at address specified by SAL.
+ Restrict it to frame FRAME if FRAME is nonzero. */
+
+struct breakpoint *
+set_momentary_breakpoint (sal, frame, type)
+ struct symtab_and_line sal;
+ FRAME frame;
+ enum bptype type;
+{
+ register struct breakpoint *b;
+ b = set_raw_breakpoint (sal);
+ b->type = type;
+ b->enable = enabled;
+ b->disposition = donttouch;
+ b->frame = (frame ? FRAME_FP (frame) : 0);
+ return b;
+}
+
+#if 0
+void
+clear_momentary_breakpoints ()
+{
+ register struct breakpoint *b;
+ ALL_BREAKPOINTS (b)
+ if (b->disposition == delete)
+ {
+ delete_breakpoint (b);
+ break;
+ }
+}
+#endif
+
+/* Tell the user we have just set a breakpoint B. */
+
+static void
+mention (b)
+ struct breakpoint *b;
+{
+ int say_where = 0;
+
+ switch (b->type)
+ {
+ case bp_watchpoint:
+ printf_filtered ("Watchpoint %d: ", b->number);
+ print_expression (b->exp, gdb_stdout);
+ break;
+ case bp_hardware_watchpoint:
+ printf_filtered ("Hardware watchpoint %d: ", b->number);
+ print_expression (b->exp, gdb_stdout);
+ break;
+ case bp_read_watchpoint:
+ printf_filtered ("Hardware read watchpoint %d: ", b->number);
+ print_expression (b->exp, gdb_stdout);
+ break;
+ case bp_access_watchpoint:
+ printf_filtered ("Hardware access(read/write) watchpoint %d: ",b->number);
+ print_expression (b->exp, gdb_stdout);
+ break;
+ case bp_breakpoint:
+ printf_filtered ("Breakpoint %d", b->number);
+ say_where = 1;
+ break;
+ case bp_hardware_breakpoint:
+ printf_filtered ("Hardware assisted breakpoint %d", b->number);
+ say_where = 1;
+ break;
+ case bp_until:
+ case bp_finish:
+ case bp_longjmp:
+ case bp_longjmp_resume:
+ case bp_step_resume:
+ case bp_through_sigtramp:
+ case bp_call_dummy:
+ case bp_watchpoint_scope:
+ break;
+ }
+ if (say_where)
+ {
+ if (addressprint || b->source_file == NULL)
+ {
+ printf_filtered (" at ");
+ print_address_numeric (b->address, 1, gdb_stdout);
+ }
+ if (b->source_file)
+ printf_filtered (": file %s, line %d.",
+ b->source_file, b->line_number);
+ }
+ printf_filtered ("\n");
+}
+
+#if 0
+/* Nobody calls this currently. */
+/* Set a breakpoint from a symtab and line.
+ If TEMPFLAG is nonzero, it is a temporary breakpoint.
+ ADDR_STRING is a malloc'd string holding the name of where we are
+ setting the breakpoint. This is used later to re-set it after the
+ program is relinked and symbols are reloaded.
+ Print the same confirmation messages that the breakpoint command prints. */
+
+void
+set_breakpoint (s, line, tempflag, addr_string)
+ struct symtab *s;
+ int line;
+ int tempflag;
+ char *addr_string;
+{
+ register struct breakpoint *b;
+ struct symtab_and_line sal;
+
+ sal.symtab = s;
+ sal.line = line;
+ sal.pc = 0;
+ resolve_sal_pc (&sal); /* Might error out */
+ describe_other_breakpoints (sal.pc);
+
+ b = set_raw_breakpoint (sal);
+ set_breakpoint_count (breakpoint_count + 1);
+ b->number = breakpoint_count;
+ b->type = bp_breakpoint;
+ b->cond = 0;
+ b->addr_string = addr_string;
+ b->enable = enabled;
+ b->disposition = tempflag ? delete : donttouch;
+
+ mention (b);
+}
+#endif /* 0 */
+
+/* Set a breakpoint according to ARG (function, linenum or *address)
+ flag: first bit : 0 non-temporary, 1 temporary.
+ second bit : 0 normal breakpoint, 1 hardware breakpoint. */
+
+static void
+break_command_1 (arg, flag, from_tty)
+ char *arg;
+ int flag, from_tty;
+{
+ int tempflag, hardwareflag;
+ struct symtabs_and_lines sals;
+ struct symtab_and_line sal;
+ register struct expression *cond = 0;
+ register struct breakpoint *b;
+
+ /* Pointers in arg to the start, and one past the end, of the condition. */
+ char *cond_start = NULL;
+ char *cond_end = NULL;
+ /* Pointers in arg to the start, and one past the end,
+ of the address part. */
+ char *addr_start = NULL;
+ char *addr_end = NULL;
+ struct cleanup *old_chain;
+ struct cleanup *canonical_strings_chain = NULL;
+ char **canonical = (char **)NULL;
+ int i;
+ int thread;
+
+ hardwareflag = flag & 2;
+ tempflag = flag & 1;
+
+ sals.sals = NULL;
+ sals.nelts = 0;
+
+ sal.line = sal.pc = sal.end = 0;
+ sal.symtab = 0;
+
+ /* If no arg given, or if first arg is 'if ', use the default breakpoint. */
+
+ if (!arg || (arg[0] == 'i' && arg[1] == 'f'
+ && (arg[2] == ' ' || arg[2] == '\t')))
+ {
+ if (default_breakpoint_valid)
+ {
+ sals.sals = (struct symtab_and_line *)
+ xmalloc (sizeof (struct symtab_and_line));
+ sal.pc = default_breakpoint_address;
+ sal.line = default_breakpoint_line;
+ sal.symtab = default_breakpoint_symtab;
+ sals.sals[0] = sal;
+ sals.nelts = 1;
+ }
+ else
+ error ("No default breakpoint address now.");
+ }
+ else
+ {
+ addr_start = arg;
+
+ /* Force almost all breakpoints to be in terms of the
+ current_source_symtab (which is decode_line_1's default). This
+ should produce the results we want almost all of the time while
+ leaving default_breakpoint_* alone. */
+ if (default_breakpoint_valid
+ && (!current_source_symtab
+ || (arg && (*arg == '+' || *arg == '-'))))
+ sals = decode_line_1 (&arg, 1, default_breakpoint_symtab,
+ default_breakpoint_line, &canonical);
+ else
+ sals = decode_line_1 (&arg, 1, (struct symtab *)NULL, 0, &canonical);
+
+ addr_end = arg;
+ }
+
+ if (! sals.nelts)
+ return;
+
+ /* Make sure that all storage allocated in decode_line_1 gets freed in case
+ the following `for' loop errors out. */
+ old_chain = make_cleanup (free, sals.sals);
+ if (canonical != (char **)NULL)
+ {
+ make_cleanup (free, canonical);
+ canonical_strings_chain = make_cleanup (null_cleanup, 0);
+ for (i = 0; i < sals.nelts; i++)
+ {
+ if (canonical[i] != NULL)
+ make_cleanup (free, canonical[i]);
+ }
+ }
+
+ thread = -1; /* No specific thread yet */
+
+ /* Resolve all line numbers to PC's, and verify that conditions
+ can be parsed, before setting any breakpoints. */
+ for (i = 0; i < sals.nelts; i++)
+ {
+ char *tok, *end_tok;
+ int toklen;
+
+ resolve_sal_pc (&sals.sals[i]);
+
+ tok = arg;
+
+ while (tok && *tok)
+ {
+ while (*tok == ' ' || *tok == '\t')
+ tok++;
+
+ end_tok = tok;
+
+ while (*end_tok != ' ' && *end_tok != '\t' && *end_tok != '\000')
+ end_tok++;
+
+ toklen = end_tok - tok;
+
+ if (toklen >= 1 && strncmp (tok, "if", toklen) == 0)
+ {
+ tok = cond_start = end_tok + 1;
+ cond = parse_exp_1 (&tok, block_for_pc (sals.sals[i].pc), 0);
+ cond_end = tok;
+ }
+ else if (toklen >= 1 && strncmp (tok, "thread", toklen) == 0)
+ {
+ char *tmptok;
+
+ tok = end_tok + 1;
+ tmptok = tok;
+ thread = strtol (tok, &tok, 0);
+ if (tok == tmptok)
+ error ("Junk after thread keyword.");
+ if (!valid_thread_id (thread))
+ error ("Unknown thread %d\n", thread);
+ }
+ else
+ error ("Junk at end of arguments.");
+ }
+ }
+ if (hardwareflag)
+ {
+ int i, target_resources_ok;
+
+ i = hw_breakpoint_used_count ();
+ target_resources_ok = TARGET_CAN_USE_HARDWARE_WATCHPOINT (
+ bp_hardware_breakpoint, i + sals.nelts, 0);
+ if (target_resources_ok == 0)
+ error ("No hardware breakpoint support in the target.");
+ else if (target_resources_ok < 0)
+ error ("Hardware breakpoints used exceeds limit.");
+ }
+
+ /* Remove the canonical strings from the cleanup, they are needed below. */
+ if (canonical != (char **)NULL)
+ discard_cleanups (canonical_strings_chain);
+
+ /* Now set all the breakpoints. */
+ for (i = 0; i < sals.nelts; i++)
+ {
+ sal = sals.sals[i];
+
+ if (from_tty)
+ describe_other_breakpoints (sal.pc);
+
+ b = set_raw_breakpoint (sal);
+ set_breakpoint_count (breakpoint_count + 1);
+ b->number = breakpoint_count;
+ b->type = hardwareflag ? bp_hardware_breakpoint : bp_breakpoint;
+ b->cond = cond;
+ b->thread = thread;
+
+ /* If a canonical line spec is needed use that instead of the
+ command string. */
+ if (canonical != (char **)NULL && canonical[i] != NULL)
+ b->addr_string = canonical[i];
+ else if (addr_start)
+ b->addr_string = savestring (addr_start, addr_end - addr_start);
+ if (cond_start)
+ b->cond_string = savestring (cond_start, cond_end - cond_start);
+
+ b->enable = enabled;
+ b->disposition = tempflag ? delete : donttouch;
+
+ mention (b);
+ }
+
+ if (sals.nelts > 1)
+ {
+ printf_filtered ("Multiple breakpoints were set.\n");
+ printf_filtered ("Use the \"delete\" command to delete unwanted breakpoints.\n");
+ }
+ do_cleanups (old_chain);
+}
+
+/* Helper function for break_command_1 and disassemble_command. */
+
+void
+resolve_sal_pc (sal)
+ struct symtab_and_line *sal;
+{
+ CORE_ADDR pc;
+
+ if (sal->pc == 0 && sal->symtab != 0)
+ {
+ pc = find_line_pc (sal->symtab, sal->line);
+ if (pc == 0)
+ error ("No line %d in file \"%s\".",
+ sal->line, sal->symtab->filename);
+ sal->pc = pc;
+ }
+}
+
+#define BP_TEMPFLAG 1
+#define BP_HARDWAREFLAG 2
+void
+break_command (arg, from_tty)
+ char *arg;
+ int from_tty;
+{
+ break_command_1 (arg, 0, from_tty);
+}
+
+static void
+tbreak_command (arg, from_tty)
+ char *arg;
+ int from_tty;
+{
+ break_command_1 (arg, BP_TEMPFLAG, from_tty);
+}
+
+static void
+hbreak_command (arg, from_tty)
+ char *arg;
+ int from_tty;
+{
+ break_command_1 (arg, BP_HARDWAREFLAG, from_tty);
+}
+
+static void
+thbreak_command (arg, from_tty)
+ char *arg;
+ int from_tty;
+{
+ break_command_1 (arg, (BP_TEMPFLAG | BP_HARDWAREFLAG), from_tty);
+}
+
+/* ARGSUSED */
+/* accessflag: 0: watch write, 1: watch read, 2: watch access(read or write)
+*/
+static void
+watch_command_1 (arg, accessflag, from_tty)
+ char *arg;
+ int accessflag;
+ int from_tty;
+{
+ struct breakpoint *b;
+ struct symtab_and_line sal;
+ struct expression *exp;
+ struct block *exp_valid_block;
+ struct value *val, *mark;
+ FRAME frame, prev_frame;
+ char *exp_start = NULL;
+ char *exp_end = NULL;
+ char *tok, *end_tok;
+ int toklen;
+ char *cond_start = NULL;
+ char *cond_end = NULL;
+ struct expression *cond = NULL;
+ int i, other_type_used, target_resources_ok;
+ enum bptype bp_type;
+ int mem_cnt = 0;
+
+ sal.pc = 0;
+ sal.symtab = NULL;
+ sal.line = 0;
+
+ /* Parse arguments. */
+ innermost_block = NULL;
+ exp_start = arg;
+ exp = parse_exp_1 (&arg, 0, 0);
+ exp_end = arg;
+ exp_valid_block = innermost_block;
+ mark = value_mark ();
+ val = evaluate_expression (exp);
+ release_value (val);
+ if (VALUE_LAZY (val))
+ value_fetch_lazy (val);
+
+ tok = arg;
+ while (*tok == ' ' || *tok == '\t')
+ tok++;
+ end_tok = tok;
+
+ while (*end_tok != ' ' && *end_tok != '\t' && *end_tok != '\000')
+ end_tok++;
+
+ toklen = end_tok - tok;
+ if (toklen >= 1 && strncmp (tok, "if", toklen) == 0)
+ {
+ tok = cond_start = end_tok + 1;
+ cond = parse_exp_1 (&tok, 0, 0);
+ cond_end = tok;
+ }
+ if (*tok)
+ error("Junk at end of command.");
+
+ if (accessflag == 1) bp_type = bp_read_watchpoint;
+ else if (accessflag == 2) bp_type = bp_access_watchpoint;
+ else bp_type = bp_hardware_watchpoint;
+
+ mem_cnt = can_use_hardware_watchpoint (val);
+ if (mem_cnt == 0 && bp_type != bp_hardware_watchpoint)
+ error ("Expression cannot be implemented with read/access watchpoint.");
+ if (mem_cnt != 0) {
+ i = hw_watchpoint_used_count (bp_type, &other_type_used);
+ target_resources_ok = TARGET_CAN_USE_HARDWARE_WATCHPOINT(
+ bp_type, i + mem_cnt, other_type_used);
+ if (target_resources_ok == 0 && bp_type != bp_hardware_watchpoint)
+ error ("Target does not have this type of hardware watchpoint support.");
+ if (target_resources_ok < 0 && bp_type != bp_hardware_watchpoint)
+ error ("Target resources have been allocated for other types of watchpoints.");
+ }
+
+ /* Now set up the breakpoint. */
+ b = set_raw_breakpoint (sal);
+ set_breakpoint_count (breakpoint_count + 1);
+ b->number = breakpoint_count;
+ b->disposition = donttouch;
+ b->exp = exp;
+ b->exp_valid_block = exp_valid_block;
+ b->exp_string = savestring (exp_start, exp_end - exp_start);
+ b->val = val;
+ b->cond = cond;
+ if (cond_start)
+ b->cond_string = savestring (cond_start, cond_end - cond_start);
+ else
+ b->cond_string = 0;
+
+ frame = block_innermost_frame (exp_valid_block);
+ if (frame)
+ {
+ prev_frame = get_prev_frame (frame);
+ b->watchpoint_frame = FRAME_FP (frame);
+ }
+ else
+ b->watchpoint_frame = (CORE_ADDR)0;
+
+ if (mem_cnt && target_resources_ok > 0)
+ b->type = bp_type;
+ else
+ b->type = bp_watchpoint;
+
+ /* If the expression is "local", then set up a "watchpoint scope"
+ breakpoint at the point where we've left the scope of the watchpoint
+ expression. */
+ if (innermost_block)
+ {
+ struct breakpoint *scope_breakpoint;
+ struct symtab_and_line scope_sal;
+
+ if (prev_frame)
+ {
+ scope_sal.pc = get_frame_pc (prev_frame);
+ scope_sal.symtab = NULL;
+ scope_sal.line = 0;
+
+ scope_breakpoint = set_raw_breakpoint (scope_sal);
+ set_breakpoint_count (breakpoint_count + 1);
+ scope_breakpoint->number = breakpoint_count;
+
+ scope_breakpoint->type = bp_watchpoint_scope;
+ scope_breakpoint->enable = enabled;
+
+ /* Automatically delete the breakpoint when it hits. */
+ scope_breakpoint->disposition = delete;
+
+ /* Only break in the proper frame (help with recursion). */
+ scope_breakpoint->frame = prev_frame->frame;
+
+ /* Set the address at which we will stop. */
+ scope_breakpoint->address = get_frame_pc (prev_frame);
+
+ /* The scope breakpoint is related to the watchpoint. We
+ will need to act on them together. */
+ b->related_breakpoint = scope_breakpoint;
+ }
+ }
+ value_free_to_mark (mark);
+ mention (b);
+}
+
+/* Return count of locations need to be watched and can be handled
+ in hardware. If the watchpoint can not be handled
+ in hardware return zero. */
+
+static int
+can_use_hardware_watchpoint (v)
+ struct value *v;
+{
+ int found_memory_cnt = 0;
+
+ /* Make sure all the intermediate values are in memory. Also make sure
+ we found at least one memory expression. Guards against watch 0x12345,
+ which is meaningless, but could cause errors if one tries to insert a
+ hardware watchpoint for the constant expression. */
+ for ( ; v; v = v->next)
+ {
+ if (v->lval == lval_memory)
+ {
+ if (TYPE_LENGTH (VALUE_TYPE (v)) <= REGISTER_SIZE)
+ found_memory_cnt++;
+ }
+ else if (v->lval != not_lval && v->modifiable == 0)
+ return 0;
+ }
+
+ /* The expression itself looks suitable for using a hardware
+ watchpoint, but give the target machine a chance to reject it. */
+ return found_memory_cnt;
+}
+
+static void watch_command (arg, from_tty)
+ char *arg;
+ int from_tty;
+{
+ watch_command_1 (arg, 0, from_tty);
+}
+
+static void rwatch_command (arg, from_tty)
+ char *arg;
+ int from_tty;
+{
+ watch_command_1 (arg, 1, from_tty);
+}
+
+static void awatch_command (arg, from_tty)
+ char *arg;
+ int from_tty;
+{
+ watch_command_1 (arg, 2, from_tty);
+}
+
+
+/*
+ * Helper routine for the until_command routine in infcmd.c. Here
+ * because it uses the mechanisms of breakpoints.
+ */
+/* ARGSUSED */
+void
+until_break_command (arg, from_tty)
+ char *arg;
+ int from_tty;
+{
+ struct symtabs_and_lines sals;
+ struct symtab_and_line sal;
+ FRAME prev_frame = get_prev_frame (selected_frame);
+ struct breakpoint *breakpoint;
+ struct cleanup *old_chain;
+
+ clear_proceed_status ();
+
+ /* Set a breakpoint where the user wants it and at return from
+ this function */
+
+ if (default_breakpoint_valid)
+ sals = decode_line_1 (&arg, 1, default_breakpoint_symtab,
+ default_breakpoint_line, (char ***)NULL);
+ else
+ sals = decode_line_1 (&arg, 1, (struct symtab *)NULL, 0, (char ***)NULL);
+
+ if (sals.nelts != 1)
+ error ("Couldn't get information on specified line.");
+
+ sal = sals.sals[0];
+ free ((PTR)sals.sals); /* malloc'd, so freed */
+
+ if (*arg)
+ error ("Junk at end of arguments.");
+
+ resolve_sal_pc (&sal);
+
+ breakpoint = set_momentary_breakpoint (sal, selected_frame, bp_until);
+
+ old_chain = make_cleanup(delete_breakpoint, breakpoint);
+
+ /* Keep within the current frame */
+
+ if (prev_frame)
+ {
+ struct frame_info *fi;
+
+ fi = get_frame_info (prev_frame);
+ sal = find_pc_line (fi->pc, 0);
+ sal.pc = fi->pc;
+ breakpoint = set_momentary_breakpoint (sal, prev_frame, bp_until);
+ make_cleanup(delete_breakpoint, breakpoint);
+ }
+
+ proceed (-1, TARGET_SIGNAL_DEFAULT, 0);
+ do_cleanups(old_chain);
+}
+
+#if 0
+/* These aren't used; I don't konw what they were for. */
+/* Set a breakpoint at the catch clause for NAME. */
+static int
+catch_breakpoint (name)
+ char *name;
+{
+}
+
+static int
+disable_catch_breakpoint ()
+{
+}
+
+static int
+delete_catch_breakpoint ()
+{
+}
+
+static int
+enable_catch_breakpoint ()
+{
+}
+#endif /* 0 */
+
+struct sal_chain
+{
+ struct sal_chain *next;
+ struct symtab_and_line sal;
+};
+
+#if 0
+/* This isn't used; I don't know what it was for. */
+/* For each catch clause identified in ARGS, run FUNCTION
+ with that clause as an argument. */
+static struct symtabs_and_lines
+map_catch_names (args, function)
+ char *args;
+ int (*function)();
+{
+ register char *p = args;
+ register char *p1;
+ struct symtabs_and_lines sals;
+#if 0
+ struct sal_chain *sal_chain = 0;
+#endif
+
+ if (p == 0)
+ error_no_arg ("one or more catch names");
+
+ sals.nelts = 0;
+ sals.sals = NULL;
+
+ while (*p)
+ {
+ p1 = p;
+ /* Don't swallow conditional part. */
+ if (p1[0] == 'i' && p1[1] == 'f'
+ && (p1[2] == ' ' || p1[2] == '\t'))
+ break;
+
+ if (isalpha (*p1))
+ {
+ p1++;
+ while (isalnum (*p1) || *p1 == '_' || *p1 == '$')
+ p1++;
+ }
+
+ if (*p1 && *p1 != ' ' && *p1 != '\t')
+ error ("Arguments must be catch names.");
+
+ *p1 = 0;
+#if 0
+ if (function (p))
+ {
+ struct sal_chain *next
+ = (struct sal_chain *)alloca (sizeof (struct sal_chain));
+ next->next = sal_chain;
+ next->sal = get_catch_sal (p);
+ sal_chain = next;
+ goto win;
+ }
+#endif
+ printf_unfiltered ("No catch clause for exception %s.\n", p);
+#if 0
+ win:
+#endif
+ p = p1;
+ while (*p == ' ' || *p == '\t') p++;
+ }
+}
+#endif /* 0 */
+
+/* This shares a lot of code with `print_frame_label_vars' from stack.c. */
+
+static struct symtabs_and_lines
+get_catch_sals (this_level_only)
+ int this_level_only;
+{
+ register struct blockvector *bl;
+ register struct block *block;
+ int index, have_default = 0;
+ struct frame_info *fi;
+ CORE_ADDR pc;
+ struct symtabs_and_lines sals;
+ struct sal_chain *sal_chain = 0;
+ char *blocks_searched;
+
+ /* Not sure whether an error message is always the correct response,
+ but it's better than a core dump. */
+ if (selected_frame == NULL)
+ error ("No selected frame.");
+ block = get_frame_block (selected_frame);
+ fi = get_frame_info (selected_frame);
+ pc = fi->pc;
+
+ sals.nelts = 0;
+ sals.sals = NULL;
+
+ if (block == 0)
+ error ("No symbol table info available.\n");
+
+ bl = blockvector_for_pc (BLOCK_END (block) - 4, &index);
+ blocks_searched = (char *) alloca (BLOCKVECTOR_NBLOCKS (bl) * sizeof (char));
+ memset (blocks_searched, 0, BLOCKVECTOR_NBLOCKS (bl) * sizeof (char));
+
+ while (block != 0)
+ {
+ CORE_ADDR end = BLOCK_END (block) - 4;
+ int last_index;
+
+ if (bl != blockvector_for_pc (end, &index))
+ error ("blockvector blotch");
+ if (BLOCKVECTOR_BLOCK (bl, index) != block)
+ error ("blockvector botch");
+ last_index = BLOCKVECTOR_NBLOCKS (bl);
+ index += 1;
+
+ /* Don't print out blocks that have gone by. */
+ while (index < last_index
+ && BLOCK_END (BLOCKVECTOR_BLOCK (bl, index)) < pc)
+ index++;
+
+ while (index < last_index
+ && BLOCK_END (BLOCKVECTOR_BLOCK (bl, index)) < end)
+ {
+ if (blocks_searched[index] == 0)
+ {
+ struct block *b = BLOCKVECTOR_BLOCK (bl, index);
+ int nsyms;
+ register int i;
+ register struct symbol *sym;
+
+ nsyms = BLOCK_NSYMS (b);
+
+ for (i = 0; i < nsyms; i++)
+ {
+ sym = BLOCK_SYM (b, i);
+ if (STREQ (SYMBOL_NAME (sym), "default"))
+ {
+ if (have_default)
+ continue;
+ have_default = 1;
+ }
+ if (SYMBOL_CLASS (sym) == LOC_LABEL)
+ {
+ struct sal_chain *next = (struct sal_chain *)
+ alloca (sizeof (struct sal_chain));
+ next->next = sal_chain;
+ next->sal = find_pc_line (SYMBOL_VALUE_ADDRESS (sym), 0);
+ sal_chain = next;
+ }
+ }
+ blocks_searched[index] = 1;
+ }
+ index++;
+ }
+ if (have_default)
+ break;
+ if (sal_chain && this_level_only)
+ break;
+
+ /* After handling the function's top-level block, stop.
+ Don't continue to its superblock, the block of
+ per-file symbols. */
+ if (BLOCK_FUNCTION (block))
+ break;
+ block = BLOCK_SUPERBLOCK (block);
+ }
+
+ if (sal_chain)
+ {
+ struct sal_chain *tmp_chain;
+
+ /* Count the number of entries. */
+ for (index = 0, tmp_chain = sal_chain; tmp_chain;
+ tmp_chain = tmp_chain->next)
+ index++;
+
+ sals.nelts = index;
+ sals.sals = (struct symtab_and_line *)
+ xmalloc (index * sizeof (struct symtab_and_line));
+ for (index = 0; sal_chain; sal_chain = sal_chain->next, index++)
+ sals.sals[index] = sal_chain->sal;
+ }
+
+ return sals;
+}
+
+/* Commands to deal with catching exceptions. */
+
+static void
+catch_command_1 (arg, tempflag, from_tty)
+ char *arg;
+ int tempflag;
+ int from_tty;
+{
+ /* First, translate ARG into something we can deal with in terms
+ of breakpoints. */
+
+ struct symtabs_and_lines sals;
+ struct symtab_and_line sal;
+ register struct expression *cond = 0;
+ register struct breakpoint *b;
+ char *save_arg;
+ int i;
+
+ sal.line = sal.pc = sal.end = 0;
+ sal.symtab = 0;
+
+ /* If no arg given, or if first arg is 'if ', all active catch clauses
+ are breakpointed. */
+
+ if (!arg || (arg[0] == 'i' && arg[1] == 'f'
+ && (arg[2] == ' ' || arg[2] == '\t')))
+ {
+ /* Grab all active catch clauses. */
+ sals = get_catch_sals (0);
+ }
+ else
+ {
+ /* Grab selected catch clauses. */
+ error ("catch NAME not implemented");
+#if 0
+ /* This isn't used; I don't know what it was for. */
+ sals = map_catch_names (arg, catch_breakpoint);
+#endif
+ }
+
+ if (! sals.nelts)
+ return;
+
+ save_arg = arg;
+ for (i = 0; i < sals.nelts; i++)
+ {
+ resolve_sal_pc (&sals.sals[i]);
+
+ while (arg && *arg)
+ {
+ if (arg[0] == 'i' && arg[1] == 'f'
+ && (arg[2] == ' ' || arg[2] == '\t'))
+ cond = parse_exp_1 ((arg += 2, &arg),
+ block_for_pc (sals.sals[i].pc), 0);
+ else
+ error ("Junk at end of arguments.");
+ }
+ arg = save_arg;
+ }
+
+ for (i = 0; i < sals.nelts; i++)
+ {
+ sal = sals.sals[i];
+
+ if (from_tty)
+ describe_other_breakpoints (sal.pc);
+
+ b = set_raw_breakpoint (sal);
+ set_breakpoint_count (breakpoint_count + 1);
+ b->number = breakpoint_count;
+ b->type = bp_breakpoint;
+ b->cond = cond;
+ b->enable = enabled;
+ b->disposition = tempflag ? delete : donttouch;
+
+ mention (b);
+ }
+
+ if (sals.nelts > 1)
+ {
+ printf_unfiltered ("Multiple breakpoints were set.\n");
+ printf_unfiltered ("Use the \"delete\" command to delete unwanted breakpoints.\n");
+ }
+ free ((PTR)sals.sals);
+}
+
+#if 0
+/* These aren't used; I don't know what they were for. */
+/* Disable breakpoints on all catch clauses described in ARGS. */
+static void
+disable_catch (args)
+ char *args;
+{
+ /* Map the disable command to catch clauses described in ARGS. */
+}
+
+/* Enable breakpoints on all catch clauses described in ARGS. */
+static void
+enable_catch (args)
+ char *args;
+{
+ /* Map the disable command to catch clauses described in ARGS. */
+}
+
+/* Delete breakpoints on all catch clauses in the active scope. */
+static void
+delete_catch (args)
+ char *args;
+{
+ /* Map the delete command to catch clauses described in ARGS. */
+}
+#endif /* 0 */
+
+static void
+catch_command (arg, from_tty)
+ char *arg;
+ int from_tty;
+{
+ catch_command_1 (arg, 0, from_tty);
+}
+
+static void
+clear_command (arg, from_tty)
+ char *arg;
+ int from_tty;
+{
+ register struct breakpoint *b, *b1;
+ struct symtabs_and_lines sals;
+ struct symtab_and_line sal;
+ register struct breakpoint *found;
+ int i;
+
+ if (arg)
+ {
+ sals = decode_line_spec (arg, 1);
+ }
+ else
+ {
+ sals.sals = (struct symtab_and_line *) xmalloc (sizeof (struct symtab_and_line));
+ sal.line = default_breakpoint_line;
+ sal.symtab = default_breakpoint_symtab;
+ sal.pc = 0;
+ if (sal.symtab == 0)
+ error ("No source file specified.");
+
+ sals.sals[0] = sal;
+ sals.nelts = 1;
+ }
+
+ for (i = 0; i < sals.nelts; i++)
+ {
+ /* If exact pc given, clear bpts at that pc.
+ But if sal.pc is zero, clear all bpts on specified line. */
+ sal = sals.sals[i];
+ found = (struct breakpoint *) 0;
+ while (breakpoint_chain
+ && (sal.pc
+ ? breakpoint_chain->address == sal.pc
+ : (breakpoint_chain->source_file != NULL
+ && sal.symtab != NULL
+ && STREQ (breakpoint_chain->source_file,
+ sal.symtab->filename)
+ && breakpoint_chain->line_number == sal.line)))
+ {
+ b1 = breakpoint_chain;
+ breakpoint_chain = b1->next;
+ b1->next = found;
+ found = b1;
+ }
+
+ ALL_BREAKPOINTS (b)
+ while (b->next
+ && b->next->type != bp_watchpoint
+ && b->next->type != bp_hardware_watchpoint
+ && b->next->type != bp_read_watchpoint
+ && b->next->type != bp_access_watchpoint
+ && (sal.pc
+ ? b->next->address == sal.pc
+ : (b->next->source_file != NULL
+ && sal.symtab != NULL
+ && STREQ (b->next->source_file, sal.symtab->filename)
+ && b->next->line_number == sal.line)))
+ {
+ b1 = b->next;
+ b->next = b1->next;
+ b1->next = found;
+ found = b1;
+ }
+
+ if (found == 0)
+ {
+ if (arg)
+ error ("No breakpoint at %s.", arg);
+ else
+ error ("No breakpoint at this line.");
+ }
+
+ if (found->next) from_tty = 1; /* Always report if deleted more than one */
+ if (from_tty) printf_unfiltered ("Deleted breakpoint%s ", found->next ? "s" : "");
+ breakpoints_changed ();
+ while (found)
+ {
+ if (from_tty) printf_unfiltered ("%d ", found->number);
+ b1 = found->next;
+ delete_breakpoint (found);
+ found = b1;
+ }
+ if (from_tty) putchar_unfiltered ('\n');
+ }
+ free ((PTR)sals.sals);
+}
+
+/* Delete breakpoint in BS if they are `delete' breakpoints.
+ This is called after any breakpoint is hit, or after errors. */
+
+void
+breakpoint_auto_delete (bs)
+ bpstat bs;
+{
+ for (; bs; bs = bs->next)
+ if (bs->breakpoint_at && bs->breakpoint_at->disposition == delete
+ && bs->stop)
+ delete_breakpoint (bs->breakpoint_at);
+}
+
+/* Delete a breakpoint and clean up all traces of it in the data structures. */
+
+void
+delete_breakpoint (bpt)
+ struct breakpoint *bpt;
+{
+ register struct breakpoint *b;
+ register bpstat bs;
+
+ if (bpt->inserted)
+ remove_breakpoint (bpt);
+
+ if (breakpoint_chain == bpt)
+ breakpoint_chain = bpt->next;
+
+ ALL_BREAKPOINTS (b)
+ if (b->next == bpt)
+ {
+ b->next = bpt->next;
+ break;
+ }
+
+ check_duplicates (bpt->address);
+ /* If this breakpoint was inserted, and there is another breakpoint
+ at the same address, we need to insert the other breakpoint. */
+ if (bpt->inserted
+ && bpt->type != bp_hardware_watchpoint
+ && bpt->type != bp_read_watchpoint
+ && bpt->type != bp_access_watchpoint)
+ {
+ ALL_BREAKPOINTS (b)
+ if (b->address == bpt->address
+ && !b->duplicate
+ && b->enable != disabled)
+ {
+ int val;
+ val = target_insert_breakpoint (b->address, b->shadow_contents);
+ if (val != 0)
+ {
+ target_terminal_ours_for_output ();
+ fprintf_unfiltered (gdb_stderr, "Cannot insert breakpoint %d:\n", b->number);
+ memory_error (val, b->address); /* which bombs us out */
+ }
+ else
+ b->inserted = 1;
+ }
+ }
+
+ free_command_lines (&bpt->commands);
+ if (bpt->cond)
+ free (bpt->cond);
+ if (bpt->cond_string != NULL)
+ free (bpt->cond_string);
+ if (bpt->addr_string != NULL)
+ free (bpt->addr_string);
+ if (bpt->exp_string != NULL)
+ free (bpt->exp_string);
+ if (bpt->source_file != NULL)
+ free (bpt->source_file);
+
+ breakpoints_changed ();
+
+ /* Be sure no bpstat's are pointing at it after it's been freed. */
+ /* FIXME, how can we find all bpstat's?
+ We just check stop_bpstat for now. */
+ for (bs = stop_bpstat; bs; bs = bs->next)
+ if (bs->breakpoint_at == bpt)
+ bs->breakpoint_at = NULL;
+ free ((PTR)bpt);
+}
+
+static void
+delete_command (arg, from_tty)
+ char *arg;
+ int from_tty;
+{
+
+ if (arg == 0)
+ {
+ /* Ask user only if there are some breakpoints to delete. */
+ if (!from_tty
+ || (breakpoint_chain && query ("Delete all breakpoints? ", 0, 0)))
+ {
+ /* No arg; clear all breakpoints. */
+ while (breakpoint_chain)
+ delete_breakpoint (breakpoint_chain);
+ }
+ }
+ else
+ map_breakpoint_numbers (arg, delete_breakpoint);
+}
+
+/* Reset a breakpoint given it's struct breakpoint * BINT.
+ The value we return ends up being the return value from catch_errors.
+ Unused in this case. */
+
+static int
+breakpoint_re_set_one (bint)
+ char *bint;
+{
+ struct breakpoint *b = (struct breakpoint *)bint; /* get past catch_errs */
+ struct value *mark;
+ int i;
+ struct symtabs_and_lines sals;
+ char *s;
+ enum enable save_enable;
+
+ switch (b->type)
+ {
+ case bp_breakpoint:
+ case bp_hardware_breakpoint:
+ if (b->addr_string == NULL)
+ {
+ /* Anything without a string can't be re-set. */
+ delete_breakpoint (b);
+ return 0;
+ }
+ /* In case we have a problem, disable this breakpoint. We'll restore
+ its status if we succeed. */
+ save_enable = b->enable;
+ b->enable = disabled;
+
+ s = b->addr_string;
+ sals = decode_line_1 (&s, 1, (struct symtab *)NULL, 0, (char ***)NULL);
+ for (i = 0; i < sals.nelts; i++)
+ {
+ resolve_sal_pc (&sals.sals[i]);
+
+ /* Reparse conditions, they might contain references to the
+ old symtab. */
+ if (b->cond_string != NULL)
+ {
+ s = b->cond_string;
+ if (b->cond)
+ free ((PTR)b->cond);
+ b->cond = parse_exp_1 (&s, block_for_pc (sals.sals[i].pc), 0);
+ }
+
+ /* We need to re-set the breakpoint if the address changes...*/
+ if (b->address != sals.sals[i].pc
+ /* ...or new and old breakpoints both have source files, and
+ the source file name or the line number changes... */
+ || (b->source_file != NULL
+ && sals.sals[i].symtab != NULL
+ && (!STREQ (b->source_file, sals.sals[i].symtab->filename)
+ || b->line_number != sals.sals[i].line)
+ )
+ /* ...or we switch between having a source file and not having
+ one. */
+ || ((b->source_file == NULL) != (sals.sals[i].symtab == NULL))
+ )
+ {
+ if (b->source_file != NULL)
+ free (b->source_file);
+ if (sals.sals[i].symtab == NULL)
+ b->source_file = NULL;
+ else
+ b->source_file =
+ savestring (sals.sals[i].symtab->filename,
+ strlen (sals.sals[i].symtab->filename));
+ b->line_number = sals.sals[i].line;
+ b->address = sals.sals[i].pc;
+
+ check_duplicates (b->address);
+
+ mention (b);
+
+ /* Might be better to do this just once per breakpoint_re_set,
+ rather than once for every breakpoint. */
+ breakpoints_changed ();
+ }
+ b->enable = save_enable; /* Restore it, this worked. */
+ }
+ free ((PTR)sals.sals);
+ break;
+
+ case bp_watchpoint:
+ case bp_hardware_watchpoint:
+ case bp_read_watchpoint:
+ case bp_access_watchpoint:
+ innermost_block = NULL;
+ /* The issue arises of what context to evaluate this in. The same
+ one as when it was set, but what does that mean when symbols have
+ been re-read? We could save the filename and functionname, but
+ if the context is more local than that, the best we could do would
+ be something like how many levels deep and which index at that
+ particular level, but that's going to be less stable than filenames
+ or functionnames. */
+ /* So for now, just use a global context. */
+ b->exp = parse_expression (b->exp_string);
+ b->exp_valid_block = innermost_block;
+ mark = value_mark ();
+ b->val = evaluate_expression (b->exp);
+ release_value (b->val);
+ if (VALUE_LAZY (b->val))
+ value_fetch_lazy (b->val);
+
+ if (b->cond_string != NULL)
+ {
+ s = b->cond_string;
+ b->cond = parse_exp_1 (&s, (struct block *)0, 0);
+ }
+ if (b->enable == enabled)
+ mention (b);
+ value_free_to_mark (mark);
+ break;
+
+ default:
+ printf_filtered ("Deleting unknown breakpoint type %d\n", b->type);
+ /* fall through */
+ case bp_until:
+ case bp_finish:
+ case bp_longjmp:
+ case bp_longjmp_resume:
+ case bp_watchpoint_scope:
+ case bp_call_dummy:
+ delete_breakpoint (b);
+ break;
+ }
+
+ return 0;
+}
+
+/* Re-set all breakpoints after symbols have been re-loaded. */
+void
+breakpoint_re_set ()
+{
+ struct breakpoint *b, *temp;
+ static char message1[] = "Error in re-setting breakpoint %d:\n";
+ char message[sizeof (message1) + 30 /* slop */];
+
+ ALL_BREAKPOINTS_SAFE (b, temp)
+ {
+ sprintf (message, message1, b->number); /* Format possible error msg */
+ catch_errors (breakpoint_re_set_one, (char *) b, message,
+ RETURN_MASK_ALL);
+ }
+
+ create_longjmp_breakpoint("longjmp");
+ create_longjmp_breakpoint("_longjmp");
+ create_longjmp_breakpoint("siglongjmp");
+ create_longjmp_breakpoint(NULL);
+
+#if 0
+ /* Took this out (temporaliy at least), since it produces an extra
+ blank line at startup. This messes up the gdbtests. -PB */
+ /* Blank line to finish off all those mention() messages we just printed. */
+ printf_filtered ("\n");
+#endif
+}
+
+/* Set ignore-count of breakpoint number BPTNUM to COUNT.
+ If from_tty is nonzero, it prints a message to that effect,
+ which ends with a period (no newline). */
+
+void
+set_ignore_count (bptnum, count, from_tty)
+ int bptnum, count, from_tty;
+{
+ register struct breakpoint *b;
+
+ if (count < 0)
+ count = 0;
+
+ ALL_BREAKPOINTS (b)
+ if (b->number == bptnum)
+ {
+ b->ignore_count = count;
+ if (!from_tty)
+ return;
+ else if (count == 0)
+ printf_filtered ("Will stop next time breakpoint %d is reached.",
+ bptnum);
+ else if (count == 1)
+ printf_filtered ("Will ignore next crossing of breakpoint %d.",
+ bptnum);
+ else
+ printf_filtered ("Will ignore next %d crossings of breakpoint %d.",
+ count, bptnum);
+ breakpoints_changed ();
+ return;
+ }
+
+ error ("No breakpoint number %d.", bptnum);
+}
+
+/* Clear the ignore counts of all breakpoints. */
+void
+breakpoint_clear_ignore_counts ()
+{
+ struct breakpoint *b;
+
+ ALL_BREAKPOINTS (b)
+ b->ignore_count = 0;
+}
+
+/* Command to set ignore-count of breakpoint N to COUNT. */
+
+static void
+ignore_command (args, from_tty)
+ char *args;
+ int from_tty;
+{
+ char *p = args;
+ register int num;
+
+ if (p == 0)
+ error_no_arg ("a breakpoint number");
+
+ num = get_number (&p);
+
+ if (*p == 0)
+ error ("Second argument (specified ignore-count) is missing.");
+
+ set_ignore_count (num,
+ longest_to_int (value_as_long (parse_and_eval (p))),
+ from_tty);
+ printf_filtered ("\n");
+ breakpoints_changed ();
+}
+
+/* Call FUNCTION on each of the breakpoints
+ whose numbers are given in ARGS. */
+
+static void
+map_breakpoint_numbers (args, function)
+ char *args;
+ void (*function) PARAMS ((struct breakpoint *));
+{
+ register char *p = args;
+ char *p1;
+ register int num;
+ register struct breakpoint *b;
+
+ if (p == 0)
+ error_no_arg ("one or more breakpoint numbers");
+
+ while (*p)
+ {
+ p1 = p;
+
+ num = get_number (&p1);
+
+ ALL_BREAKPOINTS (b)
+ if (b->number == num)
+ {
+ struct breakpoint *related_breakpoint = b->related_breakpoint;
+ function (b);
+ if (related_breakpoint)
+ function (related_breakpoint);
+ goto win;
+ }
+ printf_unfiltered ("No breakpoint number %d.\n", num);
+ win:
+ p = p1;
+ }
+}
+
+static void
+enable_breakpoint (bpt)
+ struct breakpoint *bpt;
+{
+ FRAME save_selected_frame = NULL;
+ int save_selected_frame_level = -1;
+ int target_resources_ok, other_type_used;
+ struct value *mark;
+
+ if (bpt->type == bp_hardware_breakpoint)
+ {
+ int i;
+ i = hw_breakpoint_used_count();
+ target_resources_ok = TARGET_CAN_USE_HARDWARE_WATCHPOINT(
+ bp_hardware_breakpoint, i+1, 0);
+ if (target_resources_ok == 0)
+ error ("No hardware breakpoint support in the target.");
+ else if (target_resources_ok < 0)
+ error ("Hardware breakpoints used exceeds limit.");
+ }
+ bpt->enable = enabled;
+ breakpoints_changed ();
+ check_duplicates (bpt->address);
+
+ if (bpt->type == bp_watchpoint || bpt->type == bp_hardware_watchpoint ||
+ bpt->type == bp_read_watchpoint || bpt->type == bp_access_watchpoint)
+ {
+ if (bpt->exp_valid_block != NULL)
+ {
+ FRAME fr = find_frame_addr_in_frame_chain (bpt->watchpoint_frame);
+ if (fr == NULL)
+ {
+ printf_filtered ("\
+Cannot enable watchpoint %d because the block in which its expression\n\
+is valid is not currently in scope.\n", bpt->number);
+ bpt->enable = disabled;
+ return;
+ }
+
+ save_selected_frame = selected_frame;
+ save_selected_frame_level = selected_frame_level;
+ select_frame (fr, -1);
+ }
+
+ value_free (bpt->val);
+ mark = value_mark ();
+ bpt->val = evaluate_expression (bpt->exp);
+ release_value (bpt->val);
+ if (VALUE_LAZY (bpt->val))
+ value_fetch_lazy (bpt->val);
+
+ if (bpt->type == bp_hardware_watchpoint ||
+ bpt->type == bp_read_watchpoint ||
+ bpt->type == bp_access_watchpoint)
+ {
+ int i = hw_watchpoint_used_count (bpt->type, &other_type_used);
+ int mem_cnt = can_use_hardware_watchpoint (bpt->val);
+
+ target_resources_ok = TARGET_CAN_USE_HARDWARE_WATCHPOINT(
+ bpt->type, i + mem_cnt, other_type_used);
+ /* we can consider of type is bp_hardware_watchpoint, convert to
+ bp_watchpoint in the following condition */
+ if (target_resources_ok < 0)
+ {
+ printf_filtered("\
+Cannot enable watchpoint %d because target watch resources\n\
+have been allocated for other watchpoints.\n", bpt->number);
+ bpt->enable = disabled;
+ value_free_to_mark (mark);
+ return;
+ }
+ }
+
+ if (save_selected_frame_level >= 0)
+ select_frame (save_selected_frame, save_selected_frame_level);
+ value_free_to_mark (mark);
+ }
+}
+
+/* ARGSUSED */
+static void
+enable_command (args, from_tty)
+ char *args;
+ int from_tty;
+{
+ struct breakpoint *bpt;
+ if (args == 0)
+ ALL_BREAKPOINTS (bpt)
+ switch (bpt->type)
+ {
+ case bp_breakpoint:
+ case bp_hardware_breakpoint:
+ case bp_watchpoint:
+ case bp_hardware_watchpoint:
+ case bp_read_watchpoint:
+ case bp_access_watchpoint:
+ enable_breakpoint (bpt);
+ default:
+ continue;
+ }
+ else
+ map_breakpoint_numbers (args, enable_breakpoint);
+}
+
+static void
+disable_breakpoint (bpt)
+ struct breakpoint *bpt;
+{
+ /* Never disable a watchpoint scope breakpoint; we want to
+ hit them when we leave scope so we can delete both the
+ watchpoint and its scope breakpoint at that time. */
+ if (bpt->type == bp_watchpoint_scope)
+ return;
+
+ bpt->enable = disabled;
+
+ breakpoints_changed ();
+
+ check_duplicates (bpt->address);
+}
+
+/* ARGSUSED */
+static void
+disable_command (args, from_tty)
+ char *args;
+ int from_tty;
+{
+ register struct breakpoint *bpt;
+ if (args == 0)
+ ALL_BREAKPOINTS (bpt)
+ switch (bpt->type)
+ {
+ case bp_breakpoint:
+ case bp_hardware_breakpoint:
+ case bp_watchpoint:
+ case bp_hardware_watchpoint:
+ case bp_read_watchpoint:
+ case bp_access_watchpoint:
+ disable_breakpoint (bpt);
+ default:
+ continue;
+ }
+ else
+ map_breakpoint_numbers (args, disable_breakpoint);
+}
+
+static void
+enable_once_breakpoint (bpt)
+ struct breakpoint *bpt;
+{
+ FRAME save_selected_frame = NULL;
+ int save_selected_frame_level = -1;
+ int target_resources_ok, other_type_used;
+ struct value *mark;
+
+ if (bpt->type == bp_hardware_breakpoint)
+ {
+ int i;
+ i = hw_breakpoint_used_count();
+ target_resources_ok = TARGET_CAN_USE_HARDWARE_WATCHPOINT(
+ bp_hardware_breakpoint, i+1, 0);
+ if (target_resources_ok == 0)
+ error ("No hardware breakpoint support in the target.");
+ else if (target_resources_ok < 0)
+ error ("Hardware breakpoints used exceeds limit.");
+ }
+
+ bpt->enable = enabled;
+ bpt->disposition = disable;
+ check_duplicates (bpt->address);
+ breakpoints_changed ();
+
+ if (bpt->type == bp_watchpoint || bpt->type == bp_hardware_watchpoint ||
+ bpt->type == bp_read_watchpoint || bpt->type == bp_access_watchpoint)
+ {
+ if (bpt->exp_valid_block != NULL)
+ {
+ FRAME fr = find_frame_addr_in_frame_chain (bpt->watchpoint_frame);
+ if (fr == NULL)
+ {
+ printf_filtered ("\
+Cannot enable watchpoint %d because the block in which its expression\n\
+is valid is not currently in scope.\n", bpt->number);
+ bpt->enable = disabled;
+ return;
+ }
+
+ save_selected_frame = selected_frame;
+ save_selected_frame_level = selected_frame_level;
+ select_frame (fr, -1);
+ }
+
+ value_free (bpt->val);
+ mark = value_mark ();
+ bpt->val = evaluate_expression (bpt->exp);
+ release_value (bpt->val);
+ if (VALUE_LAZY (bpt->val))
+ value_fetch_lazy (bpt->val);
+
+ if (bpt->type == bp_hardware_watchpoint ||
+ bpt->type == bp_read_watchpoint ||
+ bpt->type == bp_access_watchpoint)
+ {
+ int i = hw_watchpoint_used_count (bpt->type, &other_type_used);
+ int mem_cnt = can_use_hardware_watchpoint(bpt->val);
+ target_resources_ok = TARGET_CAN_USE_HARDWARE_WATCHPOINT(
+ bpt->type, i+mem_cnt, other_type_used);
+ /* we can consider of type is bp_hardware_watchpoint, convert to
+ bp_watchpoint in the following condition */
+ if (target_resources_ok < 0)
+ {
+ printf_filtered("\
+Cannot enable watchpoint %d because target watch resources\n\
+have been allocated for other watchpoints.\n", bpt->number);
+ bpt->enable = disabled;
+ value_free_to_mark (mark);
+ }
+ }
+
+ if (save_selected_frame_level >= 0)
+ select_frame (save_selected_frame, save_selected_frame_level);
+ value_free_to_mark (mark);
+ }
+}
+
+/* ARGSUSED */
+static void
+enable_once_command (args, from_tty)
+ char *args;
+ int from_tty;
+{
+ map_breakpoint_numbers (args, enable_once_breakpoint);
+}
+
+static void
+enable_delete_breakpoint (bpt)
+ struct breakpoint *bpt;
+{
+ bpt->enable = enabled;
+ bpt->disposition = delete;
+
+ check_duplicates (bpt->address);
+ breakpoints_changed ();
+}
+
+/* ARGSUSED */
+static void
+enable_delete_command (args, from_tty)
+ char *args;
+ int from_tty;
+{
+ map_breakpoint_numbers (args, enable_delete_breakpoint);
+}
+
+/*
+ * Use default_breakpoint_'s, or nothing if they aren't valid.
+ */
+struct symtabs_and_lines
+decode_line_spec_1 (string, funfirstline)
+ char *string;
+ int funfirstline;
+{
+ struct symtabs_and_lines sals;
+ if (string == 0)
+ error ("Empty line specification.");
+ if (default_breakpoint_valid)
+ sals = decode_line_1 (&string, funfirstline,
+ default_breakpoint_symtab, default_breakpoint_line,
+ (char ***)NULL);
+ else
+ sals = decode_line_1 (&string, funfirstline,
+ (struct symtab *)NULL, 0, (char ***)NULL);
+ if (*string)
+ error ("Junk at end of line specification: %s", string);
+ return sals;
+}
+
+void
+_initialize_breakpoint ()
+{
+ breakpoint_chain = 0;
+ /* Don't bother to call set_breakpoint_count. $bpnum isn't useful
+ before a breakpoint is set. */
+ breakpoint_count = 0;
+
+ add_com ("ignore", class_breakpoint, ignore_command,
+ "Set ignore-count of breakpoint number N to COUNT.\n\
+Usage is `ignore N COUNT'.");
+
+ add_com ("commands", class_breakpoint, commands_command,
+ "Set commands to be executed when a breakpoint is hit.\n\
+Give breakpoint number as argument after \"commands\".\n\
+With no argument, the targeted breakpoint is the last one set.\n\
+The commands themselves follow starting on the next line.\n\
+Type a line containing \"end\" to indicate the end of them.\n\
+Give \"silent\" as the first line to make the breakpoint silent;\n\
+then no output is printed when it is hit, except what the commands print.");
+
+ add_com ("condition", class_breakpoint, condition_command,
+ "Specify breakpoint number N to break only if COND is true.\n\
+Usage is `condition N COND', where N is an integer and COND is an\n\
+expression to be evaluated whenever breakpoint N is reached. ");
+
+ add_com ("tbreak", class_breakpoint, tbreak_command,
+ "Set a temporary breakpoint. Args like \"break\" command.\n\
+Like \"break\" except the breakpoint is only temporary,\n\
+so it will be deleted when hit. Equivalent to \"break\" followed\n\
+by using \"enable delete\" on the breakpoint number.");
+
+ add_com ("hbreak", class_breakpoint, hbreak_command,
+ "Set a hardware assisted breakpoint. Args like \"break\" command.\n\
+Like \"break\" except the breakpoint requires hardware support,\n\
+some target hardware may not have this support.");
+
+ add_com ("thbreak", class_breakpoint, thbreak_command,
+ "Set a temporary hardware assisted breakpoint. Args like \"break\" command.\n\
+Like \"hbreak\" except the breakpoint is only temporary,\n\
+so it will be deleted when hit.");
+
+ add_prefix_cmd ("enable", class_breakpoint, enable_command,
+ "Enable some breakpoints.\n\
+Give breakpoint numbers (separated by spaces) as arguments.\n\
+With no subcommand, breakpoints are enabled until you command otherwise.\n\
+This is used to cancel the effect of the \"disable\" command.\n\
+With a subcommand you can enable temporarily.",
+ &enablelist, "enable ", 1, &cmdlist);
+
+ add_abbrev_prefix_cmd ("breakpoints", class_breakpoint, enable_command,
+ "Enable some breakpoints.\n\
+Give breakpoint numbers (separated by spaces) as arguments.\n\
+This is used to cancel the effect of the \"disable\" command.\n\
+May be abbreviated to simply \"enable\".\n",
+ &enablebreaklist, "enable breakpoints ", 1, &enablelist);
+
+ add_cmd ("once", no_class, enable_once_command,
+ "Enable breakpoints for one hit. Give breakpoint numbers.\n\
+If a breakpoint is hit while enabled in this fashion, it becomes disabled.",
+ &enablebreaklist);
+
+ add_cmd ("delete", no_class, enable_delete_command,
+ "Enable breakpoints and delete when hit. Give breakpoint numbers.\n\
+If a breakpoint is hit while enabled in this fashion, it is deleted.",
+ &enablebreaklist);
+
+ add_cmd ("delete", no_class, enable_delete_command,
+ "Enable breakpoints and delete when hit. Give breakpoint numbers.\n\
+If a breakpoint is hit while enabled in this fashion, it is deleted.",
+ &enablelist);
+
+ add_cmd ("once", no_class, enable_once_command,
+ "Enable breakpoints for one hit. Give breakpoint numbers.\n\
+If a breakpoint is hit while enabled in this fashion, it becomes disabled.",
+ &enablelist);
+
+ add_prefix_cmd ("disable", class_breakpoint, disable_command,
+ "Disable some breakpoints.\n\
+Arguments are breakpoint numbers with spaces in between.\n\
+To disable all breakpoints, give no argument.\n\
+A disabled breakpoint is not forgotten, but has no effect until reenabled.",
+ &disablelist, "disable ", 1, &cmdlist);
+ add_com_alias ("dis", "disable", class_breakpoint, 1);
+ add_com_alias ("disa", "disable", class_breakpoint, 1);
+
+ add_cmd ("breakpoints", class_alias, disable_command,
+ "Disable some breakpoints.\n\
+Arguments are breakpoint numbers with spaces in between.\n\
+To disable all breakpoints, give no argument.\n\
+A disabled breakpoint is not forgotten, but has no effect until reenabled.\n\
+This command may be abbreviated \"disable\".",
+ &disablelist);
+
+ add_prefix_cmd ("delete", class_breakpoint, delete_command,
+ "Delete some breakpoints or auto-display expressions.\n\
+Arguments are breakpoint numbers with spaces in between.\n\
+To delete all breakpoints, give no argument.\n\
+\n\
+Also a prefix command for deletion of other GDB objects.\n\
+The \"unset\" command is also an alias for \"delete\".",
+ &deletelist, "delete ", 1, &cmdlist);
+ add_com_alias ("d", "delete", class_breakpoint, 1);
+
+ add_cmd ("breakpoints", class_alias, delete_command,
+ "Delete some breakpoints or auto-display expressions.\n\
+Arguments are breakpoint numbers with spaces in between.\n\
+To delete all breakpoints, give no argument.\n\
+This command may be abbreviated \"delete\".",
+ &deletelist);
+
+ add_com ("clear", class_breakpoint, clear_command,
+ "Clear breakpoint at specified line or function.\n\
+Argument may be line number, function name, or \"*\" and an address.\n\
+If line number is specified, all breakpoints in that line are cleared.\n\
+If function is specified, breakpoints at beginning of function are cleared.\n\
+If an address is specified, breakpoints at that address are cleared.\n\n\
+With no argument, clears all breakpoints in the line that the selected frame\n\
+is executing in.\n\
+\n\
+See also the \"delete\" command which clears breakpoints by number.");
+
+ add_com ("break", class_breakpoint, break_command,
+ "Set breakpoint at specified line or function.\n\
+Argument may be line number, function name, or \"*\" and an address.\n\
+If line number is specified, break at start of code for that line.\n\
+If function is specified, break at start of code for that function.\n\
+If an address is specified, break at that exact address.\n\
+With no arg, uses current execution address of selected stack frame.\n\
+This is useful for breaking on return to a stack frame.\n\
+\n\
+Multiple breakpoints at one place are permitted, and useful if conditional.\n\
+\n\
+Do \"help breakpoints\" for info on other commands dealing with breakpoints.");
+ add_com_alias ("b", "break", class_run, 1);
+ add_com_alias ("br", "break", class_run, 1);
+ add_com_alias ("bre", "break", class_run, 1);
+ add_com_alias ("brea", "break", class_run, 1);
+
+ add_info ("breakpoints", breakpoints_info,
+ "Status of user-settable breakpoints, or breakpoint number NUMBER.\n\
+The \"Type\" column indicates one of:\n\
+\tbreakpoint - normal breakpoint\n\
+\twatchpoint - watchpoint\n\
+The \"Disp\" column contains one of \"keep\", \"del\", or \"dis\" to indicate\n\
+the disposition of the breakpoint after it gets hit. \"dis\" means that the\n\
+breakpoint will be disabled. The \"Address\" and \"What\" columns indicate the\n\
+address and file/line number respectively.\n\n\
+Convenience variable \"$_\" and default examine address for \"x\"\n\
+are set to the address of the last breakpoint listed.\n\n\
+Convenience variable \"$bpnum\" contains the number of the last\n\
+breakpoint set.");
+
+#if MAINTENANCE_CMDS
+
+ add_cmd ("breakpoints", class_maintenance, maintenance_info_breakpoints,
+ "Status of all breakpoints, or breakpoint number NUMBER.\n\
+The \"Type\" column indicates one of:\n\
+\tbreakpoint - normal breakpoint\n\
+\twatchpoint - watchpoint\n\
+\tlongjmp - internal breakpoint used to step through longjmp()\n\
+\tlongjmp resume - internal breakpoint at the target of longjmp()\n\
+\tuntil - internal breakpoint used by the \"until\" command\n\
+\tfinish - internal breakpoint used by the \"finish\" command\n\
+The \"Disp\" column contains one of \"keep\", \"del\", or \"dis\" to indicate\n\
+the disposition of the breakpoint after it gets hit. \"dis\" means that the\n\
+breakpoint will be disabled. The \"Address\" and \"What\" columns indicate the\n\
+address and file/line number respectively.\n\n\
+Convenience variable \"$_\" and default examine address for \"x\"\n\
+are set to the address of the last breakpoint listed.\n\n\
+Convenience variable \"$bpnum\" contains the number of the last\n\
+breakpoint set.",
+ &maintenanceinfolist);
+
+#endif /* MAINTENANCE_CMDS */
+
+ add_com ("catch", class_breakpoint, catch_command,
+ "Set breakpoints to catch exceptions that are raised.\n\
+Argument may be a single exception to catch, multiple exceptions\n\
+to catch, or the default exception \"default\". If no arguments\n\
+are given, breakpoints are set at all exception handlers catch clauses\n\
+within the current scope.\n\
+\n\
+A condition specified for the catch applies to all breakpoints set\n\
+with this command\n\
+\n\
+Do \"help breakpoints\" for info on other commands dealing with breakpoints.");
+
+ add_com ("watch", class_breakpoint, watch_command,
+ "Set a watchpoint for an expression.\n\
+A watchpoint stops execution of your program whenever the value of\n\
+an expression changes.");
+
+ add_com ("rwatch", class_breakpoint, rwatch_command,
+ "Set a read watchpoint for an expression.\n\
+A watchpoint stops execution of your program whenever the value of\n\
+an expression is read.");
+
+ add_com ("awatch", class_breakpoint, awatch_command,
+ "Set a watchpoint for an expression.\n\
+A watchpoint stops execution of your program whenever the value of\n\
+an expression is either read or written.");
+
+ add_info ("watchpoints", breakpoints_info,
+ "Synonym for ``info breakpoints''.");
+
+}
+
+/* OK, when we call objfile_relocate, we need to relocate breakpoints
+ too. breakpoint_re_set is not a good choice--for example, if
+ addr_string contains just a line number without a file name the
+ breakpoint might get set in a different file. In general, there is
+ no need to go all the way back to the user's string (though this might
+ work if some effort were made to canonicalize it), since symtabs and
+ everything except addresses are still valid.
+
+ Probably the best way to solve this is to have each breakpoint save
+ the objfile and the section number that was used to set it (if set
+ by "*addr", probably it is best to use find_pc_line to get a symtab
+ and use the objfile and block_line_section for that symtab). Then
+ objfile_relocate can call fixup_breakpoints with the objfile and
+ the new_offsets, and it can relocate only the appropriate breakpoints. */
+
+#ifdef IBM6000_TARGET
+/* But for now, just kludge it based on the concept that before an
+ objfile is relocated the breakpoint is below 0x10000000, and afterwards
+ it is higher, so that way we only relocate each breakpoint once. */
+
+void
+fixup_breakpoints (low, high, delta)
+ CORE_ADDR low;
+ CORE_ADDR high;
+ CORE_ADDR delta;
+{
+ struct breakpoint *b;
+
+ ALL_BREAKPOINTS (b)
+ {
+ if (b->address >= low && b->address <= high)
+ b->address += delta;
+ }
+}
+#endif
diff --git a/gnu/usr.bin/gdb/gdb/breakpoint.h b/gnu/usr.bin/gdb/gdb/breakpoint.h
new file mode 100644
index 0000000..8242c14
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/breakpoint.h
@@ -0,0 +1,419 @@
+/* Data structures associated with breakpoints in GDB.
+ Copyright (C) 1992, 1993, 1994 Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#if !defined (BREAKPOINT_H)
+#define BREAKPOINT_H 1
+
+#include "frame.h"
+#include "value.h"
+
+/* This is the maximum number of bytes a breakpoint instruction can take.
+ Feel free to increase it. It's just used in a few places to size
+ arrays that should be independent of the target architecture. */
+
+#define BREAKPOINT_MAX 16
+
+/* Type of breakpoint. */
+/* FIXME In the future, we should fold all other breakpoint-like things into
+ here. This includes:
+
+ * single-step (for machines where we have to simulate single stepping)
+ (probably, though perhaps it is better for it to look as much as
+ possible like a single-step to wait_for_inferior). */
+
+enum bptype {
+ bp_breakpoint, /* Normal breakpoint */
+ bp_hardware_breakpoint, /* Hardware assisted breakpoint */
+ bp_until, /* used by until command */
+ bp_finish, /* used by finish command */
+ bp_watchpoint, /* Watchpoint */
+ bp_hardware_watchpoint, /* Hardware assisted watchpoint */
+ bp_read_watchpoint, /* read watchpoint, (hardware assisted) */
+ bp_access_watchpoint, /* access watchpoint, (hardware assisted) */
+ bp_longjmp, /* secret breakpoint to find longjmp() */
+ bp_longjmp_resume, /* secret breakpoint to escape longjmp() */
+
+ /* Used by wait_for_inferior for stepping over subroutine calls, for
+ stepping over signal handlers, and for skipping prologues. */
+ bp_step_resume,
+
+ /* Used by wait_for_inferior for stepping over signal handlers. */
+ bp_through_sigtramp,
+
+ /* Used to detect when a watchpoint expression has gone out of
+ scope. These breakpoints are usually not visible to the user.
+
+ This breakpoint has some interesting properties:
+
+ 1) There's always a 1:1 mapping between watchpoints
+ on local variables and watchpoint_scope breakpoints.
+
+ 2) It automatically deletes itself and the watchpoint it's
+ associated with when hit.
+
+ 3) It can never be disabled. */
+ bp_watchpoint_scope,
+
+ /* The breakpoint at the end of a call dummy. */
+ /* FIXME: What if the function we are calling longjmp()s out of the
+ call, or the user gets out with the "return" command? We currently
+ have no way of cleaning up the breakpoint in these (obscure) situations.
+ (Probably can solve this by noticing longjmp, "return", etc., it's
+ similar to noticing when a watchpoint on a local variable goes out
+ of scope (with hardware support for watchpoints)). */
+ bp_call_dummy
+};
+
+/* States of enablement of breakpoint. */
+
+enum enable { disabled, enabled};
+
+/* Disposition of breakpoint. Ie: what to do after hitting it. */
+
+enum bpdisp {
+ delete, /* Delete it */
+ disable, /* Disable it */
+ donttouch /* Leave it alone */
+};
+
+/* Note that the ->silent field is not currently used by any commands
+ (though the code is in there if it was to be, and set_raw_breakpoint
+ does set it to 0). I implemented it because I thought it would be
+ useful for a hack I had to put in; I'm going to leave it in because
+ I can see how there might be times when it would indeed be useful */
+
+/* This is for a breakpoint or a watchpoint. */
+
+struct breakpoint
+{
+ struct breakpoint *next;
+ /* Type of breakpoint. */
+ enum bptype type;
+ /* Zero means disabled; remember the info but don't break here. */
+ enum enable enable;
+ /* What to do with this breakpoint after we hit it. */
+ enum bpdisp disposition;
+ /* Number assigned to distinguish breakpoints. */
+ int number;
+
+ /* Address to break at, or NULL if not a breakpoint. */
+ CORE_ADDR address;
+
+ /* Line number of this address. Only matters if address is
+ non-NULL. */
+
+ int line_number;
+
+ /* Source file name of this address. Only matters if address is
+ non-NULL. */
+
+ char *source_file;
+
+ /* Non-zero means a silent breakpoint (don't print frame info
+ if we stop here). */
+ unsigned char silent;
+ /* Number of stops at this breakpoint that should
+ be continued automatically before really stopping. */
+ int ignore_count;
+ /* "Real" contents of byte where breakpoint has been inserted.
+ Valid only when breakpoints are in the program. Under the complete
+ control of the target insert_breakpoint and remove_breakpoint routines.
+ No other code should assume anything about the value(s) here. */
+ char shadow_contents[BREAKPOINT_MAX];
+ /* Nonzero if this breakpoint is now inserted. Only matters if address
+ is non-NULL. */
+ char inserted;
+ /* Nonzero if this is not the first breakpoint in the list
+ for the given address. Only matters if address is non-NULL. */
+ char duplicate;
+ /* Chain of command lines to execute when this breakpoint is hit. */
+ struct command_line *commands;
+ /* Stack depth (address of frame). If nonzero, break only if fp
+ equals this. */
+ FRAME_ADDR frame;
+ /* Conditional. Break only if this expression's value is nonzero. */
+ struct expression *cond;
+
+ /* String we used to set the breakpoint (malloc'd). Only matters if
+ address is non-NULL. */
+ char *addr_string;
+ /* String form of the breakpoint condition (malloc'd), or NULL if there
+ is no condition. */
+ char *cond_string;
+ /* String form of exp (malloc'd), or NULL if none. */
+ char *exp_string;
+
+ /* The expression we are watching, or NULL if not a watchpoint. */
+ struct expression *exp;
+ /* The largest block within which it is valid, or NULL if it is
+ valid anywhere (e.g. consists just of global symbols). */
+ struct block *exp_valid_block;
+ /* Value of the watchpoint the last time we checked it. */
+ value_ptr val;
+
+ /* Holds the value chain for a hardware watchpoint expression. */
+ value_ptr val_chain;
+
+ /* Holds the address of the related watchpoint_scope breakpoint
+ when using watchpoints on local variables (might the concept
+ of a related breakpoint be useful elsewhere, if not just call
+ it the watchpoint_scope breakpoint or something like that. FIXME). */
+ struct breakpoint *related_breakpoint;
+
+ /* Holds the frame address which identifies the frame this watchpoint
+ should be evaluated in, or NULL if the watchpoint should be evaluated
+ on the outermost frame. */
+ FRAME_ADDR watchpoint_frame;
+
+ /* Thread number for thread-specific breakpoint, or -1 if don't care */
+ int thread;
+
+ /* Count of the number of times this breakpoint was taken, dumped
+ with the info, but not used for anything else. Useful for
+ seeing how many times you hit a break prior to the program
+ aborting, so you can back up to just before the abort. */
+ int hit_count;
+
+};
+
+/* The following stuff is an abstract data type "bpstat" ("breakpoint status").
+ This provides the ability to determine whether we have stopped at a
+ breakpoint, and what we should do about it. */
+
+typedef struct bpstat *bpstat;
+
+/* Interface: */
+/* Clear a bpstat so that it says we are not at any breakpoint.
+ Also free any storage that is part of a bpstat. */
+extern void bpstat_clear PARAMS ((bpstat *));
+
+/* Return a copy of a bpstat. Like "bs1 = bs2" but all storage that
+ is part of the bpstat is copied as well. */
+extern bpstat bpstat_copy PARAMS ((bpstat));
+
+/* FIXME: prototypes uses equivalence between FRAME_ADDR and CORE_ADDR */
+extern bpstat bpstat_stop_status PARAMS ((CORE_ADDR *, CORE_ADDR, int));
+
+/* This bpstat_what stuff tells wait_for_inferior what to do with a
+ breakpoint (a challenging task). */
+
+enum bpstat_what_main_action {
+ /* Perform various other tests; that is, this bpstat does not
+ say to perform any action (e.g. failed watchpoint and nothing
+ else). */
+ BPSTAT_WHAT_KEEP_CHECKING,
+
+ /* Rather than distinguish between noisy and silent stops here, it
+ might be cleaner to have bpstat_print make that decision (also
+ taking into account stop_print_frame and source_only). But the
+ implications are a bit scary (interaction with auto-displays, etc.),
+ so I won't try it. */
+
+ /* Stop silently. */
+ BPSTAT_WHAT_STOP_SILENT,
+
+ /* Stop and print. */
+ BPSTAT_WHAT_STOP_NOISY,
+
+ /* Remove breakpoints, single step once, then put them back in and
+ go back to what we were doing. It's possible that this should be
+ removed from the main_action and put into a separate field, to more
+ cleanly handle BPSTAT_WHAT_CLEAR_LONGJMP_RESUME_SINGLE. */
+ BPSTAT_WHAT_SINGLE,
+
+ /* Set longjmp_resume breakpoint, remove all other breakpoints,
+ and continue. The "remove all other breakpoints" part is required
+ if we are also stepping over another breakpoint as well as doing
+ the longjmp handling. */
+ BPSTAT_WHAT_SET_LONGJMP_RESUME,
+
+ /* Clear longjmp_resume breakpoint, then handle as
+ BPSTAT_WHAT_KEEP_CHECKING. */
+ BPSTAT_WHAT_CLEAR_LONGJMP_RESUME,
+
+ /* Clear longjmp_resume breakpoint, then handle as BPSTAT_WHAT_SINGLE. */
+ BPSTAT_WHAT_CLEAR_LONGJMP_RESUME_SINGLE,
+
+ /* Clear step resume breakpoint, and keep checking. */
+ BPSTAT_WHAT_STEP_RESUME,
+
+ /* Clear through_sigtramp breakpoint, muck with trap_expected, and keep
+ checking. */
+ BPSTAT_WHAT_THROUGH_SIGTRAMP,
+
+ /* This is just used to keep track of how many enums there are. */
+ BPSTAT_WHAT_LAST
+};
+
+struct bpstat_what {
+ enum bpstat_what_main_action main_action;
+
+ /* Did we hit a call dummy breakpoint? This only goes with a main_action
+ of BPSTAT_WHAT_STOP_SILENT or BPSTAT_WHAT_STOP_NOISY (the concept of
+ continuing from a call dummy without popping the frame is not a
+ useful one). */
+ int call_dummy;
+};
+
+/* Tell what to do about this bpstat. */
+struct bpstat_what bpstat_what PARAMS ((bpstat));
+
+/* Find the bpstat associated with a breakpoint. NULL otherwise. */
+bpstat bpstat_find_breakpoint PARAMS ((bpstat, struct breakpoint *));
+
+/* Nonzero if a signal that we got in wait() was due to circumstances
+ explained by the BS. */
+/* Currently that is true if we have hit a breakpoint, or if there is
+ a watchpoint enabled. */
+#define bpstat_explains_signal(bs) ((bs) != NULL)
+
+/* Nonzero if we should step constantly (e.g. watchpoints on machines
+ without hardware support). This isn't related to a specific bpstat,
+ just to things like whether watchpoints are set. */
+extern int bpstat_should_step PARAMS ((void));
+
+/* Print a message indicating what happened. Returns nonzero to
+ say that only the source line should be printed after this (zero
+ return means print the frame as well as the source line). */
+extern int bpstat_print PARAMS ((bpstat));
+
+/* Return the breakpoint number of the first breakpoint we are stopped
+ at. *BSP upon return is a bpstat which points to the remaining
+ breakpoints stopped at (but which is not guaranteed to be good for
+ anything but further calls to bpstat_num).
+ Return 0 if passed a bpstat which does not indicate any breakpoints. */
+extern int bpstat_num PARAMS ((bpstat *));
+
+/* Perform actions associated with having stopped at *BSP. Actually, we just
+ use this for breakpoint commands. Perhaps other actions will go here
+ later, but this is executed at a late time (from the command loop). */
+extern void bpstat_do_actions PARAMS ((bpstat *));
+
+/* Modify BS so that the actions will not be performed. */
+extern void bpstat_clear_actions PARAMS ((bpstat));
+
+/* Implementation: */
+struct bpstat
+{
+ /* Linked list because there can be two breakpoints at the
+ same place, and a bpstat reflects the fact that both have been hit. */
+ bpstat next;
+ /* Breakpoint that we are at. */
+ struct breakpoint *breakpoint_at;
+ /* Commands left to be done. */
+ struct command_line *commands;
+ /* Old value associated with a watchpoint. */
+ value_ptr old_val;
+
+ /* Nonzero if this breakpoint tells us to print the frame. */
+ char print;
+
+ /* Nonzero if this breakpoint tells us to stop. */
+ char stop;
+
+ /* Function called by bpstat_print to print stuff associated with
+ this element of the bpstat chain. Returns 0 or 1 just like
+ bpstat_print, or -1 if it can't deal with it. */
+ int (*print_it) PARAMS((bpstat bs));
+};
+
+/* Prototypes for breakpoint-related functions. */
+
+#ifdef __STDC__ /* Forward declarations for prototypes */
+struct frame_info;
+#endif
+
+extern int breakpoint_here_p PARAMS ((CORE_ADDR));
+
+extern int frame_in_dummy PARAMS ((struct frame_info *));
+
+extern int breakpoint_thread_match PARAMS ((CORE_ADDR, int));
+
+extern void
+until_break_command PARAMS ((char *, int));
+
+extern void
+breakpoint_re_set PARAMS ((void));
+
+extern void
+clear_momentary_breakpoints PARAMS ((void));
+
+/* FIXME: Prototype uses equivalence of "struct frame_info *" and FRAME */
+extern struct breakpoint *
+set_momentary_breakpoint PARAMS ((struct symtab_and_line,
+ struct frame_info *,
+ enum bptype));
+
+extern void
+set_ignore_count PARAMS ((int, int, int));
+
+extern void
+set_default_breakpoint PARAMS ((int, CORE_ADDR, struct symtab *, int));
+
+extern void
+mark_breakpoints_out PARAMS ((void));
+
+extern void
+breakpoint_init_inferior PARAMS ((void));
+
+extern void
+delete_breakpoint PARAMS ((struct breakpoint *));
+
+extern void
+breakpoint_auto_delete PARAMS ((bpstat));
+
+extern void
+breakpoint_clear_ignore_counts PARAMS ((void));
+
+extern void
+break_command PARAMS ((char *, int));
+
+extern int
+insert_breakpoints PARAMS ((void));
+
+extern int
+remove_breakpoints PARAMS ((void));
+
+extern void
+enable_longjmp_breakpoint PARAMS ((void));
+
+extern void
+disable_longjmp_breakpoint PARAMS ((void));
+
+extern void
+set_longjmp_resume_breakpoint PARAMS ((CORE_ADDR, FRAME));
+
+extern void clear_breakpoint_hit_counts PARAMS ((void));
+
+/* The following are for displays, which aren't really breakpoints, but
+ here is as good a place as any for them. */
+
+extern void
+disable_current_display PARAMS ((void));
+
+extern void
+do_displays PARAMS ((void));
+
+extern void
+disable_display PARAMS ((int));
+
+extern void
+clear_displays PARAMS ((void));
+
+#endif /* !defined (BREAKPOINT_H) */
diff --git a/gnu/usr.bin/gdb/gdb/buildsym.c b/gnu/usr.bin/gdb/gdb/buildsym.c
new file mode 100644
index 0000000..27f5634
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/buildsym.c
@@ -0,0 +1,964 @@
+/* Support routines for building symbol tables in GDB's internal format.
+ Copyright 1986, 1987, 1988, 1989, 1990, 1991, 1992
+ Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* This module provides subroutines used for creating and adding to
+ the symbol table. These routines are called from various symbol-
+ file-reading routines.
+
+ Routines to support specific debugging information formats (stabs,
+ DWARF, etc) belong somewhere else. */
+
+#include "defs.h"
+#include "bfd.h"
+#include "obstack.h"
+#include "symtab.h"
+#include "symfile.h" /* Needed for "struct complaint" */
+#include "objfiles.h"
+#include "complaints.h"
+#include <string.h>
+
+/* Ask buildsym.h to define the vars it normally declares `extern'. */
+#define EXTERN /**/
+#include "buildsym.h" /* Our own declarations */
+#undef EXTERN
+
+/* For cleanup_undefined_types and finish_global_stabs (somewhat
+ questionable--see comment where we call them). */
+#include "stabsread.h"
+
+static int
+compare_line_numbers PARAMS ((const void *, const void *));
+
+static struct blockvector *
+make_blockvector PARAMS ((struct objfile *));
+
+
+/* Initial sizes of data structures. These are realloc'd larger if needed,
+ and realloc'd down to the size actually used, when completed. */
+
+#define INITIAL_CONTEXT_STACK_SIZE 10
+#define INITIAL_LINE_VECTOR_LENGTH 1000
+
+
+/* Complaints about the symbols we have encountered. */
+
+struct complaint innerblock_complaint =
+ {"inner block not inside outer block in %s", 0, 0};
+
+struct complaint innerblock_anon_complaint =
+ {"inner block not inside outer block", 0, 0};
+
+struct complaint blockvector_complaint =
+ {"block at 0x%lx out of order", 0, 0};
+
+
+/* maintain the lists of symbols and blocks */
+
+/* Add a symbol to one of the lists of symbols. */
+
+void
+add_symbol_to_list (symbol, listhead)
+ struct symbol *symbol;
+ struct pending **listhead;
+{
+ register struct pending *link;
+
+ /* We keep PENDINGSIZE symbols in each link of the list.
+ If we don't have a link with room in it, add a new link. */
+ if (*listhead == NULL || (*listhead)->nsyms == PENDINGSIZE)
+ {
+ if (free_pendings)
+ {
+ link = free_pendings;
+ free_pendings = link->next;
+ }
+ else
+ {
+ link = (struct pending *) xmalloc (sizeof (struct pending));
+ }
+
+ link->next = *listhead;
+ *listhead = link;
+ link->nsyms = 0;
+ }
+
+ (*listhead)->symbol[(*listhead)->nsyms++] = symbol;
+}
+
+/* Find a symbol named NAME on a LIST. NAME need not be '\0'-terminated;
+ LENGTH is the length of the name. */
+
+struct symbol *
+find_symbol_in_list (list, name, length)
+ struct pending *list;
+ char *name;
+ int length;
+{
+ int j;
+ char *pp;
+
+ while (list != NULL)
+ {
+ for (j = list->nsyms; --j >= 0; )
+ {
+ pp = SYMBOL_NAME (list->symbol[j]);
+ if (*pp == *name && strncmp (pp, name, length) == 0 &&
+ pp[length] == '\0')
+ {
+ return (list->symbol[j]);
+ }
+ }
+ list = list->next;
+ }
+ return (NULL);
+}
+
+/* At end of reading syms, or in case of quit,
+ really free as many `struct pending's as we can easily find. */
+
+/* ARGSUSED */
+void
+really_free_pendings (foo)
+ int foo;
+{
+ struct pending *next, *next1;
+#if 0
+ struct pending_block *bnext, *bnext1;
+#endif
+
+ for (next = free_pendings; next; next = next1)
+ {
+ next1 = next->next;
+ free ((PTR)next);
+ }
+ free_pendings = NULL;
+
+#if 0 /* Now we make the links in the symbol_obstack, so don't free them. */
+ for (bnext = pending_blocks; bnext; bnext = bnext1)
+ {
+ bnext1 = bnext->next;
+ free ((PTR)bnext);
+ }
+#endif
+ pending_blocks = NULL;
+
+ for (next = file_symbols; next != NULL; next = next1)
+ {
+ next1 = next->next;
+ free ((PTR)next);
+ }
+ file_symbols = NULL;
+
+ for (next = global_symbols; next != NULL; next = next1)
+ {
+ next1 = next->next;
+ free ((PTR)next);
+ }
+ global_symbols = NULL;
+}
+
+/* Take one of the lists of symbols and make a block from it.
+ Keep the order the symbols have in the list (reversed from the input file).
+ Put the block on the list of pending blocks. */
+
+void
+finish_block (symbol, listhead, old_blocks, start, end, objfile)
+ struct symbol *symbol;
+ struct pending **listhead;
+ struct pending_block *old_blocks;
+ CORE_ADDR start, end;
+ struct objfile *objfile;
+{
+ register struct pending *next, *next1;
+ register struct block *block;
+ register struct pending_block *pblock;
+ struct pending_block *opblock;
+ register int i;
+ register int j;
+
+ /* Count the length of the list of symbols. */
+
+ for (next = *listhead, i = 0;
+ next;
+ i += next->nsyms, next = next->next)
+ {
+ /*EMPTY*/;
+ }
+
+ block = (struct block *) obstack_alloc (&objfile -> symbol_obstack,
+ (sizeof (struct block) + ((i - 1) * sizeof (struct symbol *))));
+
+ /* Copy the symbols into the block. */
+
+ BLOCK_NSYMS (block) = i;
+ for (next = *listhead; next; next = next->next)
+ {
+ for (j = next->nsyms - 1; j >= 0; j--)
+ {
+ BLOCK_SYM (block, --i) = next->symbol[j];
+ }
+ }
+
+ BLOCK_START (block) = start;
+ BLOCK_END (block) = end;
+ /* Superblock filled in when containing block is made */
+ BLOCK_SUPERBLOCK (block) = NULL;
+ BLOCK_GCC_COMPILED (block) = processing_gcc_compilation;
+
+ /* Put the block in as the value of the symbol that names it. */
+
+ if (symbol)
+ {
+ SYMBOL_BLOCK_VALUE (symbol) = block;
+ BLOCK_FUNCTION (block) = symbol;
+ }
+ else
+ {
+ BLOCK_FUNCTION (block) = NULL;
+ }
+
+ /* Now "free" the links of the list, and empty the list. */
+
+ for (next = *listhead; next; next = next1)
+ {
+ next1 = next->next;
+ next->next = free_pendings;
+ free_pendings = next;
+ }
+ *listhead = NULL;
+
+ /* Install this block as the superblock
+ of all blocks made since the start of this scope
+ that don't have superblocks yet. */
+
+ opblock = NULL;
+ for (pblock = pending_blocks; pblock != old_blocks; pblock = pblock->next)
+ {
+ if (BLOCK_SUPERBLOCK (pblock->block) == NULL)
+ {
+#if 1
+ /* Check to be sure the blocks are nested as we receive them.
+ If the compiler/assembler/linker work, this just burns a small
+ amount of time. */
+ if (BLOCK_START (pblock->block) < BLOCK_START (block) ||
+ BLOCK_END (pblock->block) > BLOCK_END (block))
+ {
+ if (symbol)
+ {
+ complain (&innerblock_complaint,
+ SYMBOL_SOURCE_NAME (symbol));
+ }
+ else
+ {
+ complain (&innerblock_anon_complaint);
+ }
+ BLOCK_START (pblock->block) = BLOCK_START (block);
+ BLOCK_END (pblock->block) = BLOCK_END (block);
+ }
+#endif
+ BLOCK_SUPERBLOCK (pblock->block) = block;
+ }
+ opblock = pblock;
+ }
+
+ /* Record this block on the list of all blocks in the file.
+ Put it after opblock, or at the beginning if opblock is 0.
+ This puts the block in the list after all its subblocks. */
+
+ /* Allocate in the symbol_obstack to save time.
+ It wastes a little space. */
+ pblock = (struct pending_block *)
+ obstack_alloc (&objfile -> symbol_obstack,
+ sizeof (struct pending_block));
+ pblock->block = block;
+ if (opblock)
+ {
+ pblock->next = opblock->next;
+ opblock->next = pblock;
+ }
+ else
+ {
+ pblock->next = pending_blocks;
+ pending_blocks = pblock;
+ }
+}
+
+static struct blockvector *
+make_blockvector (objfile)
+ struct objfile *objfile;
+{
+ register struct pending_block *next;
+ register struct blockvector *blockvector;
+ register int i;
+
+ /* Count the length of the list of blocks. */
+
+ for (next = pending_blocks, i = 0; next; next = next->next, i++) {;}
+
+ blockvector = (struct blockvector *)
+ obstack_alloc (&objfile -> symbol_obstack,
+ (sizeof (struct blockvector)
+ + (i - 1) * sizeof (struct block *)));
+
+ /* Copy the blocks into the blockvector.
+ This is done in reverse order, which happens to put
+ the blocks into the proper order (ascending starting address).
+ finish_block has hair to insert each block into the list
+ after its subblocks in order to make sure this is true. */
+
+ BLOCKVECTOR_NBLOCKS (blockvector) = i;
+ for (next = pending_blocks; next; next = next->next)
+ {
+ BLOCKVECTOR_BLOCK (blockvector, --i) = next->block;
+ }
+
+#if 0 /* Now we make the links in the obstack, so don't free them. */
+ /* Now free the links of the list, and empty the list. */
+
+ for (next = pending_blocks; next; next = next1)
+ {
+ next1 = next->next;
+ free (next);
+ }
+#endif
+ pending_blocks = NULL;
+
+#if 1 /* FIXME, shut this off after a while to speed up symbol reading. */
+ /* Some compilers output blocks in the wrong order, but we depend
+ on their being in the right order so we can binary search.
+ Check the order and moan about it. FIXME. */
+ if (BLOCKVECTOR_NBLOCKS (blockvector) > 1)
+ {
+ for (i = 1; i < BLOCKVECTOR_NBLOCKS (blockvector); i++)
+ {
+ if (BLOCK_START(BLOCKVECTOR_BLOCK (blockvector, i-1))
+ > BLOCK_START(BLOCKVECTOR_BLOCK (blockvector, i)))
+ {
+
+ /* FIXME-32x64: loses if CORE_ADDR doesn't fit in a
+ long. Possible solutions include a version of
+ complain which takes a callback, a
+ sprintf_address_numeric to match
+ print_address_numeric, or a way to set up a GDB_FILE
+ * which causes sprintf rather than fprintf to be
+ called. */
+
+ complain (&blockvector_complaint,
+ (unsigned long) BLOCK_START(BLOCKVECTOR_BLOCK (blockvector, i)));
+ }
+ }
+ }
+#endif
+
+ return (blockvector);
+}
+
+
+/* Start recording information about source code that came from an included
+ (or otherwise merged-in) source file with a different name. NAME is
+ the name of the file (cannot be NULL), DIRNAME is the directory in which
+ it resides (or NULL if not known). */
+
+void
+start_subfile (name, dirname)
+ char *name;
+ char *dirname;
+{
+ register struct subfile *subfile;
+
+ /* See if this subfile is already known as a subfile of the
+ current main source file. */
+
+ for (subfile = subfiles; subfile; subfile = subfile->next)
+ {
+ if (STREQ (subfile->name, name))
+ {
+ current_subfile = subfile;
+ return;
+ }
+ }
+
+ /* This subfile is not known. Add an entry for it.
+ Make an entry for this subfile in the list of all subfiles
+ of the current main source file. */
+
+ subfile = (struct subfile *) xmalloc (sizeof (struct subfile));
+ subfile->next = subfiles;
+ subfiles = subfile;
+ current_subfile = subfile;
+
+ /* Save its name and compilation directory name */
+ subfile->name = (name == NULL) ? NULL : savestring (name, strlen (name));
+ subfile->dirname =
+ (dirname == NULL) ? NULL : savestring (dirname, strlen (dirname));
+
+ /* Initialize line-number recording for this subfile. */
+ subfile->line_vector = NULL;
+
+ /* Default the source language to whatever can be deduced from
+ the filename. If nothing can be deduced (such as for a C/C++
+ include file with a ".h" extension), then inherit whatever
+ language the previous subfile had. This kludgery is necessary
+ because there is no standard way in some object formats to
+ record the source language. Also, when symtabs are allocated
+ we try to deduce a language then as well, but it is too late
+ for us to use that information while reading symbols, since
+ symtabs aren't allocated until after all the symbols have
+ been processed for a given source file. */
+
+ subfile->language = deduce_language_from_filename (subfile->name);
+ if (subfile->language == language_unknown &&
+ subfile->next != NULL)
+ {
+ subfile->language = subfile->next->language;
+ }
+
+ /* cfront output is a C program, so in most ways it looks like a C
+ program. But to demangle we need to set the language to C++. We
+ can distinguish cfront code by the fact that it has #line
+ directives which specify a file name ending in .C.
+
+ So if the filename of this subfile ends in .C, then change the language
+ of any pending subfiles from C to C++. We also accept any other C++
+ suffixes accepted by deduce_language_from_filename (in particular,
+ some people use .cxx with cfront). */
+
+ if (subfile->name)
+ {
+ struct subfile *s;
+
+ if (deduce_language_from_filename (subfile->name) == language_cplus)
+ for (s = subfiles; s != NULL; s = s->next)
+ if (s->language == language_c)
+ s->language = language_cplus;
+ }
+
+ /* And patch up this file if necessary. */
+ if (subfile->language == language_c
+ && subfile->next != NULL
+ && subfile->next->language == language_cplus)
+ {
+ subfile->language = language_cplus;
+ }
+}
+
+/* For stabs readers, the first N_SO symbol is assumed to be the source
+ file name, and the subfile struct is initialized using that assumption.
+ If another N_SO symbol is later seen, immediately following the first
+ one, then the first one is assumed to be the directory name and the
+ second one is really the source file name.
+
+ So we have to patch up the subfile struct by moving the old name value to
+ dirname and remembering the new name. Some sanity checking is performed
+ to ensure that the state of the subfile struct is reasonable and that the
+ old name we are assuming to be a directory name actually is (by checking
+ for a trailing '/'). */
+
+void
+patch_subfile_names (subfile, name)
+ struct subfile *subfile;
+ char *name;
+{
+ if (subfile != NULL && subfile->dirname == NULL && subfile->name != NULL
+ && subfile->name[strlen(subfile->name)-1] == '/')
+ {
+ subfile->dirname = subfile->name;
+ subfile->name = savestring (name, strlen (name));
+
+ /* Default the source language to whatever can be deduced from
+ the filename. If nothing can be deduced (such as for a C/C++
+ include file with a ".h" extension), then inherit whatever
+ language the previous subfile had. This kludgery is necessary
+ because there is no standard way in some object formats to
+ record the source language. Also, when symtabs are allocated
+ we try to deduce a language then as well, but it is too late
+ for us to use that information while reading symbols, since
+ symtabs aren't allocated until after all the symbols have
+ been processed for a given source file. */
+
+ subfile->language = deduce_language_from_filename (subfile->name);
+ if (subfile->language == language_unknown &&
+ subfile->next != NULL)
+ {
+ subfile->language = subfile->next->language;
+ }
+ }
+}
+
+
+/* Handle the N_BINCL and N_EINCL symbol types
+ that act like N_SOL for switching source files
+ (different subfiles, as we call them) within one object file,
+ but using a stack rather than in an arbitrary order. */
+
+void
+push_subfile ()
+{
+ register struct subfile_stack *tem
+ = (struct subfile_stack *) xmalloc (sizeof (struct subfile_stack));
+
+ tem->next = subfile_stack;
+ subfile_stack = tem;
+ if (current_subfile == NULL || current_subfile->name == NULL)
+ {
+ abort ();
+ }
+ tem->name = current_subfile->name;
+}
+
+char *
+pop_subfile ()
+{
+ register char *name;
+ register struct subfile_stack *link = subfile_stack;
+
+ if (link == NULL)
+ {
+ abort ();
+ }
+ name = link->name;
+ subfile_stack = link->next;
+ free ((PTR)link);
+ return (name);
+}
+
+
+/* Add a linetable entry for line number LINE and address PC to the line
+ vector for SUBFILE. */
+
+void
+record_line (subfile, line, pc)
+ register struct subfile *subfile;
+ int line;
+ CORE_ADDR pc;
+{
+ struct linetable_entry *e;
+ /* Ignore the dummy line number in libg.o */
+
+ if (line == 0xffff)
+ {
+ return;
+ }
+
+ /* Make sure line vector exists and is big enough. */
+ if (!subfile->line_vector)
+ {
+ subfile->line_vector_length = INITIAL_LINE_VECTOR_LENGTH;
+ subfile->line_vector = (struct linetable *)
+ xmalloc (sizeof (struct linetable)
+ + subfile->line_vector_length * sizeof (struct linetable_entry));
+ subfile->line_vector->nitems = 0;
+ }
+
+ if (subfile->line_vector->nitems + 1 >= subfile->line_vector_length)
+ {
+ subfile->line_vector_length *= 2;
+ subfile->line_vector = (struct linetable *)
+ xrealloc ((char *) subfile->line_vector, (sizeof (struct linetable)
+ + subfile->line_vector_length * sizeof (struct linetable_entry)));
+ }
+
+ e = subfile->line_vector->item + subfile->line_vector->nitems++;
+ e->line = line; e->pc = pc;
+}
+
+
+/* Needed in order to sort line tables from IBM xcoff files. Sigh! */
+
+static int
+compare_line_numbers (ln1p, ln2p)
+ const PTR ln1p;
+ const PTR ln2p;
+{
+ struct linetable_entry *ln1 = (struct linetable_entry *) ln1p;
+ struct linetable_entry *ln2 = (struct linetable_entry *) ln2p;
+
+ /* Note: this code does not assume that CORE_ADDRs can fit in ints.
+ Please keep it that way. */
+ if (ln1->pc < ln2->pc)
+ return -1;
+
+ if (ln1->pc > ln2->pc)
+ return 1;
+
+ /* If pc equal, sort by line. I'm not sure whether this is optimum
+ behavior (see comment at struct linetable in symtab.h). */
+ return ln1->line - ln2->line;
+}
+
+
+/* Start a new symtab for a new source file.
+ Called, for example, when a stabs symbol of type N_SO is seen, or when
+ a DWARF TAG_compile_unit DIE is seen.
+ It indicates the start of data for one original source file. */
+
+void
+start_symtab (name, dirname, start_addr)
+ char *name;
+ char *dirname;
+ CORE_ADDR start_addr;
+{
+
+ last_source_file = name;
+ last_source_start_addr = start_addr;
+ file_symbols = NULL;
+ global_symbols = NULL;
+ within_function = 0;
+
+ /* Context stack is initially empty. Allocate first one with room for
+ 10 levels; reuse it forever afterward. */
+ if (context_stack == NULL)
+ {
+ context_stack_size = INITIAL_CONTEXT_STACK_SIZE;
+ context_stack = (struct context_stack *)
+ xmalloc (context_stack_size * sizeof (struct context_stack));
+ }
+ context_stack_depth = 0;
+
+ /* Initialize the list of sub source files with one entry
+ for this file (the top-level source file). */
+
+ subfiles = NULL;
+ current_subfile = NULL;
+ start_subfile (name, dirname);
+}
+
+/* Finish the symbol definitions for one main source file,
+ close off all the lexical contexts for that file
+ (creating struct block's for them), then make the struct symtab
+ for that file and put it in the list of all such.
+
+ END_ADDR is the address of the end of the file's text.
+ SECTION is the section number (in objfile->section_offsets) of
+ the blockvector and linetable.
+
+ Note that it is possible for end_symtab() to return NULL. In particular,
+ for the DWARF case at least, it will return NULL when it finds a
+ compilation unit that has exactly one DIE, a TAG_compile_unit DIE. This
+ can happen when we link in an object file that was compiled from an empty
+ source file. Returning NULL is probably not the correct thing to do,
+ because then gdb will never know about this empty file (FIXME). */
+
+struct symtab *
+end_symtab (end_addr, sort_pending, sort_linevec, objfile, section)
+ CORE_ADDR end_addr;
+ int sort_pending;
+ int sort_linevec;
+ struct objfile *objfile;
+ int section;
+{
+ register struct symtab *symtab = NULL;
+ register struct blockvector *blockvector;
+ register struct subfile *subfile;
+ register struct context_stack *cstk;
+ struct subfile *nextsub;
+
+ /* Finish the lexical context of the last function in the file;
+ pop the context stack. */
+
+ if (context_stack_depth > 0)
+ {
+ context_stack_depth--;
+ cstk = &context_stack[context_stack_depth];
+ /* Make a block for the local symbols within. */
+ finish_block (cstk->name, &local_symbols, cstk->old_blocks,
+ cstk->start_addr, end_addr, objfile);
+
+ if (context_stack_depth > 0)
+ {
+ /* This is said to happen with SCO. The old coffread.c code
+ simply emptied the context stack, so we do the same. FIXME:
+ Find out why it is happening. This is not believed to happen
+ in most cases (even for coffread.c); it used to be an abort(). */
+ static struct complaint msg =
+ {"Context stack not empty in end_symtab", 0, 0};
+ complain (&msg);
+ context_stack_depth = 0;
+ }
+ }
+
+ /* It is unfortunate that in xcoff, pending blocks might not be ordered
+ in this stage. Especially, blocks for static functions will show up at
+ the end. We need to sort them, so tools like `find_pc_function' and
+ `find_pc_block' can work reliably. */
+
+ if (sort_pending && pending_blocks)
+ {
+ /* FIXME! Remove this horrid bubble sort and use qsort!!! */
+ int swapped;
+ do
+ {
+ struct pending_block *pb, *pbnext;
+
+ pb = pending_blocks;
+ pbnext = pb->next;
+ swapped = 0;
+
+ while (pbnext)
+ {
+ /* swap blocks if unordered! */
+
+ if (BLOCK_START(pb->block) < BLOCK_START(pbnext->block))
+ {
+ struct block *tmp = pb->block;
+ pb->block = pbnext->block;
+ pbnext->block = tmp;
+ swapped = 1;
+ }
+ pb = pbnext;
+ pbnext = pbnext->next;
+ }
+ } while (swapped);
+ }
+
+ /* Cleanup any undefined types that have been left hanging around
+ (this needs to be done before the finish_blocks so that
+ file_symbols is still good).
+
+ Both cleanup_undefined_types and finish_global_stabs are stabs
+ specific, but harmless for other symbol readers, since on gdb
+ startup or when finished reading stabs, the state is set so these
+ are no-ops. FIXME: Is this handled right in case of QUIT? Can
+ we make this cleaner? */
+
+ cleanup_undefined_types ();
+ finish_global_stabs (objfile);
+
+ if (pending_blocks == NULL
+ && file_symbols == NULL
+ && global_symbols == NULL)
+ {
+ /* Ignore symtabs that have no functions with real debugging info */
+ blockvector = NULL;
+ }
+ else
+ {
+ /* Define the STATIC_BLOCK & GLOBAL_BLOCK, and build the blockvector. */
+ finish_block (0, &file_symbols, 0, last_source_start_addr, end_addr,
+ objfile);
+ finish_block (0, &global_symbols, 0, last_source_start_addr, end_addr,
+ objfile);
+ blockvector = make_blockvector (objfile);
+ }
+
+#ifdef PROCESS_LINENUMBER_HOOK
+ PROCESS_LINENUMBER_HOOK (); /* Needed for xcoff. */
+#endif
+
+ /* Now create the symtab objects proper, one for each subfile. */
+ /* (The main file is the last one on the chain.) */
+
+ for (subfile = subfiles; subfile; subfile = nextsub)
+ {
+ int linetablesize = 0;
+ /* If we have blocks of symbols, make a symtab.
+ Otherwise, just ignore this file and any line number info in it. */
+ symtab = NULL;
+ if (blockvector)
+ {
+ if (subfile->line_vector)
+ {
+ linetablesize = sizeof (struct linetable) +
+ subfile->line_vector->nitems * sizeof (struct linetable_entry);
+#if 0
+ /* I think this is artifact from before it went on the obstack.
+ I doubt we'll need the memory between now and when we
+ free it later in this function. */
+ /* First, shrink the linetable to make more memory. */
+ subfile->line_vector = (struct linetable *)
+ xrealloc ((char *) subfile->line_vector, linetablesize);
+#endif
+ /* If sort_linevec is false, we might want just check to make
+ sure they are sorted and complain() if not, as a way of
+ tracking down compilers/symbol readers which don't get
+ them sorted right. */
+
+ if (sort_linevec)
+ qsort (subfile->line_vector->item,
+ subfile->line_vector->nitems,
+ sizeof (struct linetable_entry), compare_line_numbers);
+ }
+
+ /* Now, allocate a symbol table. */
+ symtab = allocate_symtab (subfile->name, objfile);
+
+ /* Fill in its components. */
+ symtab->blockvector = blockvector;
+ if (subfile->line_vector)
+ {
+ /* Reallocate the line table on the symbol obstack */
+ symtab->linetable = (struct linetable *)
+ obstack_alloc (&objfile -> symbol_obstack, linetablesize);
+ memcpy (symtab->linetable, subfile->line_vector, linetablesize);
+ }
+ else
+ {
+ symtab->linetable = NULL;
+ }
+ symtab->block_line_section = section;
+ if (subfile->dirname)
+ {
+ /* Reallocate the dirname on the symbol obstack */
+ symtab->dirname = (char *)
+ obstack_alloc (&objfile -> symbol_obstack,
+ strlen (subfile -> dirname) + 1);
+ strcpy (symtab->dirname, subfile->dirname);
+ }
+ else
+ {
+ symtab->dirname = NULL;
+ }
+ symtab->free_code = free_linetable;
+ symtab->free_ptr = NULL;
+
+ /* Use whatever language we have been using for this subfile,
+ not the one that was deduced in allocate_symtab from the
+ filename. We already did our own deducing when we created
+ the subfile, and we may have altered our opinion of what
+ language it is from things we found in the symbols. */
+ symtab->language = subfile->language;
+
+ /* All symtabs for the main file and the subfiles share a
+ blockvector, so we need to clear primary for everything but
+ the main file. */
+
+ symtab->primary = 0;
+ }
+ if (subfile->name != NULL)
+ {
+ free ((PTR) subfile->name);
+ }
+ if (subfile->dirname != NULL)
+ {
+ free ((PTR) subfile->dirname);
+ }
+ if (subfile->line_vector != NULL)
+ {
+ free ((PTR) subfile->line_vector);
+ }
+
+ nextsub = subfile->next;
+ free ((PTR)subfile);
+ }
+
+ /* Set this for the main source file. */
+ if (symtab)
+ {
+ symtab->primary = 1;
+ }
+
+ last_source_file = NULL;
+ current_subfile = NULL;
+
+ return (symtab);
+}
+
+
+/* Push a context block. Args are an identifying nesting level (checkable
+ when you pop it), and the starting PC address of this context. */
+
+struct context_stack *
+push_context (desc, valu)
+ int desc;
+ CORE_ADDR valu;
+{
+ register struct context_stack *new;
+
+ if (context_stack_depth == context_stack_size)
+ {
+ context_stack_size *= 2;
+ context_stack = (struct context_stack *)
+ xrealloc ((char *) context_stack,
+ (context_stack_size * sizeof (struct context_stack)));
+ }
+
+ new = &context_stack[context_stack_depth++];
+ new->depth = desc;
+ new->locals = local_symbols;
+ new->old_blocks = pending_blocks;
+ new->start_addr = valu;
+ new->name = NULL;
+
+ local_symbols = NULL;
+
+ return (new);
+}
+
+
+/* Compute a small integer hash code for the given name. */
+
+int
+hashname (name)
+ char *name;
+{
+ register char *p = name;
+ register int total = p[0];
+ register int c;
+
+ c = p[1];
+ total += c << 2;
+ if (c)
+ {
+ c = p[2];
+ total += c << 4;
+ if (c)
+ {
+ total += p[3] << 6;
+ }
+ }
+
+ /* Ensure result is positive. */
+ if (total < 0)
+ {
+ total += (1000 << 6);
+ }
+ return (total % HASHSIZE);
+}
+
+
+/* Initialize anything that needs initializing when starting to read
+ a fresh piece of a symbol file, e.g. reading in the stuff corresponding
+ to a psymtab. */
+
+void
+buildsym_init ()
+{
+ free_pendings = NULL;
+ file_symbols = NULL;
+ global_symbols = NULL;
+ pending_blocks = NULL;
+}
+
+/* Initialize anything that needs initializing when a completely new
+ symbol file is specified (not just adding some symbols from another
+ file, e.g. a shared library). */
+
+void
+buildsym_new_init ()
+{
+ buildsym_init ();
+}
+
+/* Initializer for this module */
+
+void
+_initialize_buildsym ()
+{
+}
diff --git a/gnu/usr.bin/gdb/gdb/buildsym.h b/gnu/usr.bin/gdb/gdb/buildsym.h
new file mode 100644
index 0000000..9c69a0e
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/buildsym.h
@@ -0,0 +1,259 @@
+/* Build symbol tables in GDB's internal format.
+ Copyright (C) 1986-1991 Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#if !defined (BUILDSYM_H)
+#define BUILDSYM_H 1
+
+/* This module provides definitions used for creating and adding to
+ the symbol table. These routines are called from various symbol-
+ file-reading routines.
+
+ They originated in dbxread.c of gdb-4.2, and were split out to
+ make xcoffread.c more maintainable by sharing code.
+
+ Variables declared in this file can be defined by #define-ing
+ the name EXTERN to null. It is used to declare variables that
+ are normally extern, but which get defined in a single module
+ using this technique. */
+
+#ifndef EXTERN
+#define EXTERN extern
+#endif
+
+#define HASHSIZE 127 /* Size of things hashed via hashname() */
+
+/* Name of source file whose symbol data we are now processing.
+ This comes from a symbol of type N_SO. */
+
+EXTERN char *last_source_file;
+
+/* Core address of start of text of current source file.
+ This too comes from the N_SO symbol. */
+
+EXTERN CORE_ADDR last_source_start_addr;
+
+/* The list of sub-source-files within the current individual compilation.
+ Each file gets its own symtab with its own linetable and associated info,
+ but they all share one blockvector. */
+
+struct subfile
+{
+ struct subfile *next;
+ char *name;
+ char *dirname;
+ struct linetable *line_vector;
+ int line_vector_length;
+ enum language language;
+};
+
+EXTERN struct subfile *subfiles;
+
+EXTERN struct subfile *current_subfile;
+
+/* Global variable which, when set, indicates that we are processing a
+ .o file compiled with gcc */
+
+EXTERN unsigned char processing_gcc_compilation;
+
+/* When set, we are processing a .o file compiled by sun acc. This is
+ misnamed; it refers to all stabs-in-elf implementations which use
+ N_UNDF the way Sun does, including Solaris gcc. Hopefully all
+ stabs-in-elf implementations ever invented will choose to be
+ compatible. */
+
+EXTERN unsigned char processing_acc_compilation;
+
+/* Count symbols as they are processed, for error messages. */
+
+EXTERN unsigned int symnum;
+
+/* Record the symbols defined for each context in a list.
+ We don't create a struct block for the context until we
+ know how long to make it. */
+
+#define PENDINGSIZE 100
+
+struct pending
+{
+ struct pending *next;
+ int nsyms;
+ struct symbol *symbol[PENDINGSIZE];
+};
+
+/* List of free `struct pending' structures for reuse. */
+
+EXTERN struct pending *free_pendings;
+
+/* Here are the three lists that symbols are put on. */
+
+EXTERN struct pending *file_symbols; /* static at top level, and types */
+
+EXTERN struct pending *global_symbols; /* global functions and variables */
+
+EXTERN struct pending *local_symbols; /* everything local to lexic context */
+
+/* Stack representing unclosed lexical contexts
+ (that will become blocks, eventually). */
+
+struct context_stack
+{
+ /* Outer locals at the time we entered */
+
+ struct pending *locals;
+
+ /* Pointer into blocklist as of entry */
+
+ struct pending_block *old_blocks;
+
+ /* Name of function, if any, defining context*/
+
+ struct symbol *name;
+
+ /* PC where this context starts */
+
+ CORE_ADDR start_addr;
+
+ /* Temp slot for exception handling. */
+
+ CORE_ADDR end_addr;
+
+ /* For error-checking matching push/pop */
+
+ int depth;
+
+};
+
+EXTERN struct context_stack *context_stack;
+
+/* Index of first unused entry in context stack. */
+
+EXTERN int context_stack_depth;
+
+/* Currently allocated size of context stack. */
+
+EXTERN int context_stack_size;
+
+/* Macro "function" for popping contexts from the stack. Pushing is done
+ by a real function, push_context. This returns a pointer to a struct
+ context_stack. */
+
+#define pop_context() (&context_stack[--context_stack_depth]);
+
+/* Nonzero if within a function (so symbols should be local,
+ if nothing says specifically). */
+
+EXTERN int within_function;
+
+/* List of blocks already made (lexical contexts already closed).
+ This is used at the end to make the blockvector. */
+
+struct pending_block
+{
+ struct pending_block *next;
+ struct block *block;
+};
+
+EXTERN struct pending_block *pending_blocks;
+
+
+struct subfile_stack
+{
+ struct subfile_stack *next;
+ char *name;
+};
+
+EXTERN struct subfile_stack *subfile_stack;
+
+#define next_symbol_text() (*next_symbol_text_func)()
+
+/* Function to invoke get the next symbol. Return the symbol name. */
+
+EXTERN char *(*next_symbol_text_func) PARAMS ((void));
+
+/* Vector of types defined so far, indexed by their type numbers.
+ Used for both stabs and coff.
+ (In newer sun systems, dbx uses a pair of numbers in parens,
+ as in "(SUBFILENUM,NUMWITHINSUBFILE)". Then these numbers must be
+ translated through the type_translations hash table to get
+ the index into the type vector.) */
+
+EXTERN struct type **type_vector;
+
+/* Number of elements allocated for type_vector currently. */
+
+EXTERN int type_vector_length;
+
+/* Initial size of type vector. Is realloc'd larger if needed,
+ and realloc'd down to the size actually used, when completed. */
+
+#define INITIAL_TYPE_VECTOR_LENGTH 160
+
+extern void
+add_symbol_to_list PARAMS ((struct symbol *, struct pending **));
+
+extern struct symbol *
+find_symbol_in_list PARAMS ((struct pending *, char *, int));
+
+extern void
+finish_block PARAMS ((struct symbol *, struct pending **,
+ struct pending_block *, CORE_ADDR, CORE_ADDR,
+ struct objfile *));
+
+extern void
+really_free_pendings PARAMS ((int foo));
+
+extern void
+start_subfile PARAMS ((char *, char *));
+
+extern void
+patch_subfile_names PARAMS ((struct subfile *subfile, char *name));
+
+extern void
+push_subfile PARAMS ((void));
+
+extern char *
+pop_subfile PARAMS ((void));
+
+extern struct symtab *
+end_symtab PARAMS ((CORE_ADDR, int, int, struct objfile *, int));
+
+extern void
+scan_file_globals PARAMS ((struct objfile *));
+
+extern void
+buildsym_new_init PARAMS ((void));
+
+extern void
+buildsym_init PARAMS ((void));
+
+extern struct context_stack *
+push_context PARAMS ((int, CORE_ADDR));
+
+extern void
+record_line PARAMS ((struct subfile *, int, CORE_ADDR));
+
+extern void
+start_symtab PARAMS ((char *, char *, CORE_ADDR));
+
+extern int
+hashname PARAMS ((char *));
+
+#undef EXTERN
+
+#endif /* defined (BUILDSYM_H) */
diff --git a/gnu/usr.bin/gdb/gdb/c-exp.y b/gnu/usr.bin/gdb/gdb/c-exp.y
new file mode 100644
index 0000000..0e7d39a
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/c-exp.y
@@ -0,0 +1,1601 @@
+/* YACC parser for C expressions, for GDB.
+ Copyright (C) 1986, 1989, 1990, 1991 Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* Parse a C expression from text in a string,
+ and return the result as a struct expression pointer.
+ That structure contains arithmetic operations in reverse polish,
+ with constants represented by operations that are followed by special data.
+ See expression.h for the details of the format.
+ What is important here is that it can be built up sequentially
+ during the process of parsing; the lower levels of the tree always
+ come first in the result.
+
+ Note that malloc's and realloc's in this file are transformed to
+ xmalloc and xrealloc respectively by the same sed command in the
+ makefile that remaps any other malloc/realloc inserted by the parser
+ generator. Doing this with #defines and trying to control the interaction
+ with include files (<malloc.h> and <stdlib.h> for example) just became
+ too messy, particularly when such includes can be inserted at random
+ times by the parser generator. */
+
+%{
+
+#include "defs.h"
+#include "expression.h"
+#include "parser-defs.h"
+#include "value.h"
+#include "language.h"
+#include "c-lang.h"
+
+/* Remap normal yacc parser interface names (yyparse, yylex, yyerror, etc),
+ as well as gratuitiously global symbol names, so we can have multiple
+ yacc generated parsers in gdb. Note that these are only the variables
+ produced by yacc. If other parser generators (bison, byacc, etc) produce
+ additional global names that conflict at link time, then those parser
+ generators need to be fixed instead of adding those names to this list. */
+
+#define yymaxdepth c_maxdepth
+#define yyparse c_parse
+#define yylex c_lex
+#define yyerror c_error
+#define yylval c_lval
+#define yychar c_char
+#define yydebug c_debug
+#define yypact c_pact
+#define yyr1 c_r1
+#define yyr2 c_r2
+#define yydef c_def
+#define yychk c_chk
+#define yypgo c_pgo
+#define yyact c_act
+#define yyexca c_exca
+#define yyerrflag c_errflag
+#define yynerrs c_nerrs
+#define yyps c_ps
+#define yypv c_pv
+#define yys c_s
+#define yy_yys c_yys
+#define yystate c_state
+#define yytmp c_tmp
+#define yyv c_v
+#define yy_yyv c_yyv
+#define yyval c_val
+#define yylloc c_lloc
+#define yyreds c_reds /* With YYDEBUG defined */
+#define yytoks c_toks /* With YYDEBUG defined */
+
+#ifndef YYDEBUG
+#define YYDEBUG 0 /* Default to no yydebug support */
+#endif
+
+int
+yyparse PARAMS ((void));
+
+static int
+yylex PARAMS ((void));
+
+void
+yyerror PARAMS ((char *));
+
+%}
+
+/* Although the yacc "value" of an expression is not used,
+ since the result is stored in the structure being created,
+ other node types do have values. */
+
+%union
+ {
+ LONGEST lval;
+ struct {
+ LONGEST val;
+ struct type *type;
+ } typed_val;
+ double dval;
+ struct symbol *sym;
+ struct type *tval;
+ struct stoken sval;
+ struct ttype tsym;
+ struct symtoken ssym;
+ int voidval;
+ struct block *bval;
+ enum exp_opcode opcode;
+ struct internalvar *ivar;
+
+ struct type **tvec;
+ int *ivec;
+ }
+
+%{
+/* YYSTYPE gets defined by %union */
+static int
+parse_number PARAMS ((char *, int, int, YYSTYPE *));
+%}
+
+%type <voidval> exp exp1 type_exp start variable qualified_name lcurly
+%type <lval> rcurly
+%type <tval> type typebase
+%type <tvec> nonempty_typelist
+/* %type <bval> block */
+
+/* Fancy type parsing. */
+%type <voidval> func_mod direct_abs_decl abs_decl
+%type <tval> ptype
+%type <lval> array_mod
+
+%token <typed_val> INT
+%token <dval> FLOAT
+
+/* Both NAME and TYPENAME tokens represent symbols in the input,
+ and both convey their data as strings.
+ But a TYPENAME is a string that happens to be defined as a typedef
+ or builtin type name (such as int or char)
+ and a NAME is any other symbol.
+ Contexts where this distinction is not important can use the
+ nonterminal "name", which matches either NAME or TYPENAME. */
+
+%token <sval> STRING
+%token <ssym> NAME /* BLOCKNAME defined below to give it higher precedence. */
+%token <tsym> TYPENAME
+%type <sval> name
+%type <ssym> name_not_typename
+%type <tsym> typename
+
+/* A NAME_OR_INT is a symbol which is not known in the symbol table,
+ but which would parse as a valid number in the current input radix.
+ E.g. "c" when input_radix==16. Depending on the parse, it will be
+ turned into a name or into a number. */
+
+%token <ssym> NAME_OR_INT
+
+%token STRUCT CLASS UNION ENUM SIZEOF UNSIGNED COLONCOLON
+%token TEMPLATE
+%token ERROR
+
+/* Special type cases, put in to allow the parser to distinguish different
+ legal basetypes. */
+%token SIGNED_KEYWORD LONG SHORT INT_KEYWORD CONST_KEYWORD VOLATILE_KEYWORD
+%token <lval> LAST REGNAME
+
+%token <ivar> VARIABLE
+
+%token <opcode> ASSIGN_MODIFY
+
+/* C++ */
+%token THIS
+
+%left ','
+%left ABOVE_COMMA
+%right '=' ASSIGN_MODIFY
+%right '?'
+%left OROR
+%left ANDAND
+%left '|'
+%left '^'
+%left '&'
+%left EQUAL NOTEQUAL
+%left '<' '>' LEQ GEQ
+%left LSH RSH
+%left '@'
+%left '+' '-'
+%left '*' '/' '%'
+%right UNARY INCREMENT DECREMENT
+%right ARROW '.' '[' '('
+%token <ssym> BLOCKNAME
+%type <bval> block
+%left COLONCOLON
+
+
+%%
+
+start : exp1
+ | type_exp
+ ;
+
+type_exp: type
+ { write_exp_elt_opcode(OP_TYPE);
+ write_exp_elt_type($1);
+ write_exp_elt_opcode(OP_TYPE);}
+ ;
+
+/* Expressions, including the comma operator. */
+exp1 : exp
+ | exp1 ',' exp
+ { write_exp_elt_opcode (BINOP_COMMA); }
+ ;
+
+/* Expressions, not including the comma operator. */
+exp : '*' exp %prec UNARY
+ { write_exp_elt_opcode (UNOP_IND); }
+
+exp : '&' exp %prec UNARY
+ { write_exp_elt_opcode (UNOP_ADDR); }
+
+exp : '-' exp %prec UNARY
+ { write_exp_elt_opcode (UNOP_NEG); }
+ ;
+
+exp : '!' exp %prec UNARY
+ { write_exp_elt_opcode (UNOP_LOGICAL_NOT); }
+ ;
+
+exp : '~' exp %prec UNARY
+ { write_exp_elt_opcode (UNOP_COMPLEMENT); }
+ ;
+
+exp : INCREMENT exp %prec UNARY
+ { write_exp_elt_opcode (UNOP_PREINCREMENT); }
+ ;
+
+exp : DECREMENT exp %prec UNARY
+ { write_exp_elt_opcode (UNOP_PREDECREMENT); }
+ ;
+
+exp : exp INCREMENT %prec UNARY
+ { write_exp_elt_opcode (UNOP_POSTINCREMENT); }
+ ;
+
+exp : exp DECREMENT %prec UNARY
+ { write_exp_elt_opcode (UNOP_POSTDECREMENT); }
+ ;
+
+exp : SIZEOF exp %prec UNARY
+ { write_exp_elt_opcode (UNOP_SIZEOF); }
+ ;
+
+exp : exp ARROW name
+ { write_exp_elt_opcode (STRUCTOP_PTR);
+ write_exp_string ($3);
+ write_exp_elt_opcode (STRUCTOP_PTR); }
+ ;
+
+exp : exp ARROW qualified_name
+ { /* exp->type::name becomes exp->*(&type::name) */
+ /* Note: this doesn't work if name is a
+ static member! FIXME */
+ write_exp_elt_opcode (UNOP_ADDR);
+ write_exp_elt_opcode (STRUCTOP_MPTR); }
+ ;
+exp : exp ARROW '*' exp
+ { write_exp_elt_opcode (STRUCTOP_MPTR); }
+ ;
+
+exp : exp '.' name
+ { write_exp_elt_opcode (STRUCTOP_STRUCT);
+ write_exp_string ($3);
+ write_exp_elt_opcode (STRUCTOP_STRUCT); }
+ ;
+
+exp : exp '.' qualified_name
+ { /* exp.type::name becomes exp.*(&type::name) */
+ /* Note: this doesn't work if name is a
+ static member! FIXME */
+ write_exp_elt_opcode (UNOP_ADDR);
+ write_exp_elt_opcode (STRUCTOP_MEMBER); }
+ ;
+
+exp : exp '.' '*' exp
+ { write_exp_elt_opcode (STRUCTOP_MEMBER); }
+ ;
+
+exp : exp '[' exp1 ']'
+ { write_exp_elt_opcode (BINOP_SUBSCRIPT); }
+ ;
+
+exp : exp '('
+ /* This is to save the value of arglist_len
+ being accumulated by an outer function call. */
+ { start_arglist (); }
+ arglist ')' %prec ARROW
+ { write_exp_elt_opcode (OP_FUNCALL);
+ write_exp_elt_longcst ((LONGEST) end_arglist ());
+ write_exp_elt_opcode (OP_FUNCALL); }
+ ;
+
+lcurly : '{'
+ { start_arglist (); }
+ ;
+
+arglist :
+ ;
+
+arglist : exp
+ { arglist_len = 1; }
+ ;
+
+arglist : arglist ',' exp %prec ABOVE_COMMA
+ { arglist_len++; }
+ ;
+
+rcurly : '}'
+ { $$ = end_arglist () - 1; }
+ ;
+exp : lcurly arglist rcurly %prec ARROW
+ { write_exp_elt_opcode (OP_ARRAY);
+ write_exp_elt_longcst ((LONGEST) 0);
+ write_exp_elt_longcst ((LONGEST) $3);
+ write_exp_elt_opcode (OP_ARRAY); }
+ ;
+
+exp : lcurly type rcurly exp %prec UNARY
+ { write_exp_elt_opcode (UNOP_MEMVAL);
+ write_exp_elt_type ($2);
+ write_exp_elt_opcode (UNOP_MEMVAL); }
+ ;
+
+exp : '(' type ')' exp %prec UNARY
+ { write_exp_elt_opcode (UNOP_CAST);
+ write_exp_elt_type ($2);
+ write_exp_elt_opcode (UNOP_CAST); }
+ ;
+
+exp : '(' exp1 ')'
+ { }
+ ;
+
+/* Binary operators in order of decreasing precedence. */
+
+exp : exp '@' exp
+ { write_exp_elt_opcode (BINOP_REPEAT); }
+ ;
+
+exp : exp '*' exp
+ { write_exp_elt_opcode (BINOP_MUL); }
+ ;
+
+exp : exp '/' exp
+ { write_exp_elt_opcode (BINOP_DIV); }
+ ;
+
+exp : exp '%' exp
+ { write_exp_elt_opcode (BINOP_REM); }
+ ;
+
+exp : exp '+' exp
+ { write_exp_elt_opcode (BINOP_ADD); }
+ ;
+
+exp : exp '-' exp
+ { write_exp_elt_opcode (BINOP_SUB); }
+ ;
+
+exp : exp LSH exp
+ { write_exp_elt_opcode (BINOP_LSH); }
+ ;
+
+exp : exp RSH exp
+ { write_exp_elt_opcode (BINOP_RSH); }
+ ;
+
+exp : exp EQUAL exp
+ { write_exp_elt_opcode (BINOP_EQUAL); }
+ ;
+
+exp : exp NOTEQUAL exp
+ { write_exp_elt_opcode (BINOP_NOTEQUAL); }
+ ;
+
+exp : exp LEQ exp
+ { write_exp_elt_opcode (BINOP_LEQ); }
+ ;
+
+exp : exp GEQ exp
+ { write_exp_elt_opcode (BINOP_GEQ); }
+ ;
+
+exp : exp '<' exp
+ { write_exp_elt_opcode (BINOP_LESS); }
+ ;
+
+exp : exp '>' exp
+ { write_exp_elt_opcode (BINOP_GTR); }
+ ;
+
+exp : exp '&' exp
+ { write_exp_elt_opcode (BINOP_BITWISE_AND); }
+ ;
+
+exp : exp '^' exp
+ { write_exp_elt_opcode (BINOP_BITWISE_XOR); }
+ ;
+
+exp : exp '|' exp
+ { write_exp_elt_opcode (BINOP_BITWISE_IOR); }
+ ;
+
+exp : exp ANDAND exp
+ { write_exp_elt_opcode (BINOP_LOGICAL_AND); }
+ ;
+
+exp : exp OROR exp
+ { write_exp_elt_opcode (BINOP_LOGICAL_OR); }
+ ;
+
+exp : exp '?' exp ':' exp %prec '?'
+ { write_exp_elt_opcode (TERNOP_COND); }
+ ;
+
+exp : exp '=' exp
+ { write_exp_elt_opcode (BINOP_ASSIGN); }
+ ;
+
+exp : exp ASSIGN_MODIFY exp
+ { write_exp_elt_opcode (BINOP_ASSIGN_MODIFY);
+ write_exp_elt_opcode ($2);
+ write_exp_elt_opcode (BINOP_ASSIGN_MODIFY); }
+ ;
+
+exp : INT
+ { write_exp_elt_opcode (OP_LONG);
+ write_exp_elt_type ($1.type);
+ write_exp_elt_longcst ((LONGEST)($1.val));
+ write_exp_elt_opcode (OP_LONG); }
+ ;
+
+exp : NAME_OR_INT
+ { YYSTYPE val;
+ parse_number ($1.stoken.ptr, $1.stoken.length, 0, &val);
+ write_exp_elt_opcode (OP_LONG);
+ write_exp_elt_type (val.typed_val.type);
+ write_exp_elt_longcst ((LONGEST)val.typed_val.val);
+ write_exp_elt_opcode (OP_LONG);
+ }
+ ;
+
+
+exp : FLOAT
+ { write_exp_elt_opcode (OP_DOUBLE);
+ write_exp_elt_type (builtin_type_double);
+ write_exp_elt_dblcst ($1);
+ write_exp_elt_opcode (OP_DOUBLE); }
+ ;
+
+exp : variable
+ ;
+
+exp : LAST
+ { write_exp_elt_opcode (OP_LAST);
+ write_exp_elt_longcst ((LONGEST) $1);
+ write_exp_elt_opcode (OP_LAST); }
+ ;
+
+exp : REGNAME
+ { write_exp_elt_opcode (OP_REGISTER);
+ write_exp_elt_longcst ((LONGEST) $1);
+ write_exp_elt_opcode (OP_REGISTER); }
+ ;
+
+exp : VARIABLE
+ { write_exp_elt_opcode (OP_INTERNALVAR);
+ write_exp_elt_intern ($1);
+ write_exp_elt_opcode (OP_INTERNALVAR); }
+ ;
+
+exp : SIZEOF '(' type ')' %prec UNARY
+ { write_exp_elt_opcode (OP_LONG);
+ write_exp_elt_type (builtin_type_int);
+ write_exp_elt_longcst ((LONGEST) TYPE_LENGTH ($3));
+ write_exp_elt_opcode (OP_LONG); }
+ ;
+
+exp : STRING
+ { /* C strings are converted into array constants with
+ an explicit null byte added at the end. Thus
+ the array upper bound is the string length.
+ There is no such thing in C as a completely empty
+ string. */
+ char *sp = $1.ptr; int count = $1.length;
+ while (count-- > 0)
+ {
+ write_exp_elt_opcode (OP_LONG);
+ write_exp_elt_type (builtin_type_char);
+ write_exp_elt_longcst ((LONGEST)(*sp++));
+ write_exp_elt_opcode (OP_LONG);
+ }
+ write_exp_elt_opcode (OP_LONG);
+ write_exp_elt_type (builtin_type_char);
+ write_exp_elt_longcst ((LONGEST)'\0');
+ write_exp_elt_opcode (OP_LONG);
+ write_exp_elt_opcode (OP_ARRAY);
+ write_exp_elt_longcst ((LONGEST) 0);
+ write_exp_elt_longcst ((LONGEST) ($1.length));
+ write_exp_elt_opcode (OP_ARRAY); }
+ ;
+
+/* C++. */
+exp : THIS
+ { write_exp_elt_opcode (OP_THIS);
+ write_exp_elt_opcode (OP_THIS); }
+ ;
+
+/* end of C++. */
+
+block : BLOCKNAME
+ {
+ if ($1.sym != 0)
+ $$ = SYMBOL_BLOCK_VALUE ($1.sym);
+ else
+ {
+ struct symtab *tem =
+ lookup_symtab (copy_name ($1.stoken));
+ if (tem)
+ $$ = BLOCKVECTOR_BLOCK
+ (BLOCKVECTOR (tem), STATIC_BLOCK);
+ else
+ error ("No file or function \"%s\".",
+ copy_name ($1.stoken));
+ }
+ }
+ ;
+
+block : block COLONCOLON name
+ { struct symbol *tem
+ = lookup_symbol (copy_name ($3), $1,
+ VAR_NAMESPACE, (int *) NULL,
+ (struct symtab **) NULL);
+ if (!tem || SYMBOL_CLASS (tem) != LOC_BLOCK)
+ error ("No function \"%s\" in specified context.",
+ copy_name ($3));
+ $$ = SYMBOL_BLOCK_VALUE (tem); }
+ ;
+
+variable: block COLONCOLON name
+ { struct symbol *sym;
+ sym = lookup_symbol (copy_name ($3), $1,
+ VAR_NAMESPACE, (int *) NULL,
+ (struct symtab **) NULL);
+ if (sym == 0)
+ error ("No symbol \"%s\" in specified context.",
+ copy_name ($3));
+
+ write_exp_elt_opcode (OP_VAR_VALUE);
+ /* block_found is set by lookup_symbol. */
+ write_exp_elt_block (block_found);
+ write_exp_elt_sym (sym);
+ write_exp_elt_opcode (OP_VAR_VALUE); }
+ ;
+
+qualified_name: typebase COLONCOLON name
+ {
+ struct type *type = $1;
+ if (TYPE_CODE (type) != TYPE_CODE_STRUCT
+ && TYPE_CODE (type) != TYPE_CODE_UNION)
+ error ("`%s' is not defined as an aggregate type.",
+ TYPE_NAME (type));
+
+ write_exp_elt_opcode (OP_SCOPE);
+ write_exp_elt_type (type);
+ write_exp_string ($3);
+ write_exp_elt_opcode (OP_SCOPE);
+ }
+ | typebase COLONCOLON '~' name
+ {
+ struct type *type = $1;
+ struct stoken tmp_token;
+ if (TYPE_CODE (type) != TYPE_CODE_STRUCT
+ && TYPE_CODE (type) != TYPE_CODE_UNION)
+ error ("`%s' is not defined as an aggregate type.",
+ TYPE_NAME (type));
+
+ if (!STREQ (type_name_no_tag (type), $4.ptr))
+ error ("invalid destructor `%s::~%s'",
+ type_name_no_tag (type), $4.ptr);
+
+ tmp_token.ptr = (char*) alloca ($4.length + 2);
+ tmp_token.length = $4.length + 1;
+ tmp_token.ptr[0] = '~';
+ memcpy (tmp_token.ptr+1, $4.ptr, $4.length);
+ tmp_token.ptr[tmp_token.length] = 0;
+ write_exp_elt_opcode (OP_SCOPE);
+ write_exp_elt_type (type);
+ write_exp_string (tmp_token);
+ write_exp_elt_opcode (OP_SCOPE);
+ }
+ ;
+
+variable: qualified_name
+ | COLONCOLON name
+ {
+ char *name = copy_name ($2);
+ struct symbol *sym;
+ struct minimal_symbol *msymbol;
+
+ sym =
+ lookup_symbol (name, (const struct block *) NULL,
+ VAR_NAMESPACE, (int *) NULL,
+ (struct symtab **) NULL);
+ if (sym)
+ {
+ write_exp_elt_opcode (OP_VAR_VALUE);
+ write_exp_elt_block (NULL);
+ write_exp_elt_sym (sym);
+ write_exp_elt_opcode (OP_VAR_VALUE);
+ break;
+ }
+
+ msymbol = lookup_minimal_symbol (name,
+ (struct objfile *) NULL);
+ if (msymbol != NULL)
+ {
+ write_exp_elt_opcode (OP_LONG);
+ write_exp_elt_type (builtin_type_long);
+ write_exp_elt_longcst ((LONGEST) SYMBOL_VALUE_ADDRESS (msymbol));
+ write_exp_elt_opcode (OP_LONG);
+ write_exp_elt_opcode (UNOP_MEMVAL);
+ if (msymbol -> type == mst_data ||
+ msymbol -> type == mst_bss)
+ write_exp_elt_type (builtin_type_int);
+ else if (msymbol -> type == mst_text)
+ write_exp_elt_type (lookup_function_type (builtin_type_int));
+ else
+ write_exp_elt_type (builtin_type_char);
+ write_exp_elt_opcode (UNOP_MEMVAL);
+ }
+ else
+ if (!have_full_symbols () && !have_partial_symbols ())
+ error ("No symbol table is loaded. Use the \"file\" command.");
+ else
+ error ("No symbol \"%s\" in current context.", name);
+ }
+ ;
+
+variable: name_not_typename
+ { struct symbol *sym = $1.sym;
+
+ if (sym)
+ {
+ if (symbol_read_needs_frame (sym))
+ {
+ if (innermost_block == 0 ||
+ contained_in (block_found,
+ innermost_block))
+ innermost_block = block_found;
+ }
+
+ write_exp_elt_opcode (OP_VAR_VALUE);
+ /* We want to use the selected frame, not
+ another more inner frame which happens to
+ be in the same block. */
+ write_exp_elt_block (NULL);
+ write_exp_elt_sym (sym);
+ write_exp_elt_opcode (OP_VAR_VALUE);
+ }
+ else if ($1.is_a_field_of_this)
+ {
+ /* C++: it hangs off of `this'. Must
+ not inadvertently convert from a method call
+ to data ref. */
+ if (innermost_block == 0 ||
+ contained_in (block_found, innermost_block))
+ innermost_block = block_found;
+ write_exp_elt_opcode (OP_THIS);
+ write_exp_elt_opcode (OP_THIS);
+ write_exp_elt_opcode (STRUCTOP_PTR);
+ write_exp_string ($1.stoken);
+ write_exp_elt_opcode (STRUCTOP_PTR);
+ }
+ else
+ {
+ struct minimal_symbol *msymbol;
+ register char *arg = copy_name ($1.stoken);
+
+ msymbol = lookup_minimal_symbol (arg,
+ (struct objfile *) NULL);
+ if (msymbol != NULL)
+ {
+ write_exp_elt_opcode (OP_LONG);
+ write_exp_elt_type (builtin_type_long);
+ write_exp_elt_longcst ((LONGEST) SYMBOL_VALUE_ADDRESS (msymbol));
+ write_exp_elt_opcode (OP_LONG);
+ write_exp_elt_opcode (UNOP_MEMVAL);
+ if (msymbol -> type == mst_data ||
+ msymbol -> type == mst_bss)
+ write_exp_elt_type (builtin_type_int);
+ else if (msymbol -> type == mst_text)
+ write_exp_elt_type (lookup_function_type (builtin_type_int));
+ else
+ write_exp_elt_type (builtin_type_char);
+ write_exp_elt_opcode (UNOP_MEMVAL);
+ }
+ else if (!have_full_symbols () && !have_partial_symbols ())
+ error ("No symbol table is loaded. Use the \"file\" command.");
+ else
+ error ("No symbol \"%s\" in current context.",
+ copy_name ($1.stoken));
+ }
+ }
+ ;
+
+
+/* shift/reduce conflict: "typebase ." and the token is '('. (Shows up
+ twice, once where qualified_name is a possibility and once where
+ it is not). */
+/* shift/reduce conflict: "typebase CONST_KEYWORD ." and the token is '('. */
+/* shift/reduce conflict: "typebase VOLATILE_KEYWORD ." and the token is
+ '('. */
+ptype : typebase
+ /* "const" and "volatile" are curently ignored. A type qualifier
+ before the type is currently handled in the typebase rule. */
+ | typebase CONST_KEYWORD
+ | typebase VOLATILE_KEYWORD
+ | typebase abs_decl
+ { $$ = follow_types ($1); }
+ | typebase CONST_KEYWORD abs_decl
+ { $$ = follow_types ($1); }
+ | typebase VOLATILE_KEYWORD abs_decl
+ { $$ = follow_types ($1); }
+ ;
+
+abs_decl: '*'
+ { push_type (tp_pointer); $$ = 0; }
+ | '*' abs_decl
+ { push_type (tp_pointer); $$ = $2; }
+ | '&'
+ { push_type (tp_reference); $$ = 0; }
+ | '&' abs_decl
+ { push_type (tp_reference); $$ = $2; }
+ | direct_abs_decl
+ ;
+
+direct_abs_decl: '(' abs_decl ')'
+ { $$ = $2; }
+ | direct_abs_decl array_mod
+ {
+ push_type_int ($2);
+ push_type (tp_array);
+ }
+ | array_mod
+ {
+ push_type_int ($1);
+ push_type (tp_array);
+ $$ = 0;
+ }
+
+ /* shift/reduce conflict. "direct_abs_decl . func_mod", and the token
+ is '('. */
+
+ | direct_abs_decl func_mod
+ { push_type (tp_function); }
+ | func_mod
+ { push_type (tp_function); }
+ ;
+
+array_mod: '[' ']'
+ { $$ = -1; }
+ | '[' INT ']'
+ { $$ = $2.val; }
+ ;
+
+func_mod: '(' ')'
+ { $$ = 0; }
+ | '(' nonempty_typelist ')'
+ { free ((PTR)$2); $$ = 0; }
+ ;
+
+/* shift/reduce conflict: "type '(' typebase COLONCOLON '*' ')' ." and the
+ token is '('. */
+type : ptype
+ | typebase COLONCOLON '*'
+ { $$ = lookup_member_type (builtin_type_int, $1); }
+ | type '(' typebase COLONCOLON '*' ')'
+ { $$ = lookup_member_type ($1, $3); }
+ | type '(' typebase COLONCOLON '*' ')' '(' ')'
+ { $$ = lookup_member_type
+ (lookup_function_type ($1), $3); }
+ | type '(' typebase COLONCOLON '*' ')' '(' nonempty_typelist ')'
+ { $$ = lookup_member_type
+ (lookup_function_type ($1), $3);
+ free ((PTR)$8); }
+ ;
+
+typebase /* Implements (approximately): (type-qualifier)* type-specifier */
+ : TYPENAME
+ { $$ = $1.type; }
+ | INT_KEYWORD
+ { $$ = builtin_type_int; }
+ | LONG
+ { $$ = builtin_type_long; }
+ | SHORT
+ { $$ = builtin_type_short; }
+ | LONG INT_KEYWORD
+ { $$ = builtin_type_long; }
+ | UNSIGNED LONG INT_KEYWORD
+ { $$ = builtin_type_unsigned_long; }
+ | LONG LONG
+ { $$ = builtin_type_long_long; }
+ | LONG LONG INT_KEYWORD
+ { $$ = builtin_type_long_long; }
+ | UNSIGNED LONG LONG
+ { $$ = builtin_type_unsigned_long_long; }
+ | UNSIGNED LONG LONG INT_KEYWORD
+ { $$ = builtin_type_unsigned_long_long; }
+ | SHORT INT_KEYWORD
+ { $$ = builtin_type_short; }
+ | UNSIGNED SHORT INT_KEYWORD
+ { $$ = builtin_type_unsigned_short; }
+ | STRUCT name
+ { $$ = lookup_struct (copy_name ($2),
+ expression_context_block); }
+ | CLASS name
+ { $$ = lookup_struct (copy_name ($2),
+ expression_context_block); }
+ | UNION name
+ { $$ = lookup_union (copy_name ($2),
+ expression_context_block); }
+ | ENUM name
+ { $$ = lookup_enum (copy_name ($2),
+ expression_context_block); }
+ | UNSIGNED typename
+ { $$ = lookup_unsigned_typename (TYPE_NAME($2.type)); }
+ | UNSIGNED
+ { $$ = builtin_type_unsigned_int; }
+ | SIGNED_KEYWORD typename
+ { $$ = lookup_signed_typename (TYPE_NAME($2.type)); }
+ | SIGNED_KEYWORD
+ { $$ = builtin_type_int; }
+ | TEMPLATE name '<' type '>'
+ { $$ = lookup_template_type(copy_name($2), $4,
+ expression_context_block);
+ }
+ /* "const" and "volatile" are curently ignored. A type qualifier
+ after the type is handled in the ptype rule. I think these could
+ be too. */
+ | CONST_KEYWORD typebase { $$ = $2; }
+ | VOLATILE_KEYWORD typebase { $$ = $2; }
+ ;
+
+typename: TYPENAME
+ | INT_KEYWORD
+ {
+ $$.stoken.ptr = "int";
+ $$.stoken.length = 3;
+ $$.type = builtin_type_int;
+ }
+ | LONG
+ {
+ $$.stoken.ptr = "long";
+ $$.stoken.length = 4;
+ $$.type = builtin_type_long;
+ }
+ | SHORT
+ {
+ $$.stoken.ptr = "short";
+ $$.stoken.length = 5;
+ $$.type = builtin_type_short;
+ }
+ ;
+
+nonempty_typelist
+ : type
+ { $$ = (struct type **) malloc (sizeof (struct type *) * 2);
+ $<ivec>$[0] = 1; /* Number of types in vector */
+ $$[1] = $1;
+ }
+ | nonempty_typelist ',' type
+ { int len = sizeof (struct type *) * (++($<ivec>1[0]) + 1);
+ $$ = (struct type **) realloc ((char *) $1, len);
+ $$[$<ivec>$[0]] = $3;
+ }
+ ;
+
+name : NAME { $$ = $1.stoken; }
+ | BLOCKNAME { $$ = $1.stoken; }
+ | TYPENAME { $$ = $1.stoken; }
+ | NAME_OR_INT { $$ = $1.stoken; }
+ ;
+
+name_not_typename : NAME
+ | BLOCKNAME
+/* These would be useful if name_not_typename was useful, but it is just
+ a fake for "variable", so these cause reduce/reduce conflicts because
+ the parser can't tell whether NAME_OR_INT is a name_not_typename (=variable,
+ =exp) or just an exp. If name_not_typename was ever used in an lvalue
+ context where only a name could occur, this might be useful.
+ | NAME_OR_INT
+ */
+ ;
+
+%%
+
+/* Take care of parsing a number (anything that starts with a digit).
+ Set yylval and return the token type; update lexptr.
+ LEN is the number of characters in it. */
+
+/*** Needs some error checking for the float case ***/
+
+static int
+parse_number (p, len, parsed_float, putithere)
+ register char *p;
+ register int len;
+ int parsed_float;
+ YYSTYPE *putithere;
+{
+ register LONGEST n = 0;
+ register LONGEST prevn = 0;
+ register int i = 0;
+ register int c;
+ register int base = input_radix;
+ int unsigned_p = 0;
+ int long_p = 0;
+ unsigned LONGEST high_bit;
+ struct type *signed_type;
+ struct type *unsigned_type;
+
+ if (parsed_float)
+ {
+ /* It's a float since it contains a point or an exponent. */
+ putithere->dval = atof (p);
+ return FLOAT;
+ }
+
+ /* Handle base-switching prefixes 0x, 0t, 0d, 0 */
+ if (p[0] == '0')
+ switch (p[1])
+ {
+ case 'x':
+ case 'X':
+ if (len >= 3)
+ {
+ p += 2;
+ base = 16;
+ len -= 2;
+ }
+ break;
+
+ case 't':
+ case 'T':
+ case 'd':
+ case 'D':
+ if (len >= 3)
+ {
+ p += 2;
+ base = 10;
+ len -= 2;
+ }
+ break;
+
+ default:
+ base = 8;
+ break;
+ }
+
+ while (len-- > 0)
+ {
+ c = *p++;
+ if (c >= 'A' && c <= 'Z')
+ c += 'a' - 'A';
+ if (c != 'l' && c != 'u')
+ n *= base;
+ if (c >= '0' && c <= '9')
+ n += i = c - '0';
+ else
+ {
+ if (base > 10 && c >= 'a' && c <= 'f')
+ n += i = c - 'a' + 10;
+ else if (len == 0 && c == 'l')
+ long_p = 1;
+ else if (len == 0 && c == 'u')
+ unsigned_p = 1;
+ else
+ return ERROR; /* Char not a digit */
+ }
+ if (i >= base)
+ return ERROR; /* Invalid digit in this base */
+
+ /* Portably test for overflow (only works for nonzero values, so make
+ a second check for zero). */
+ if((prevn >= n) && n != 0)
+ unsigned_p=1; /* Try something unsigned */
+ /* If range checking enabled, portably test for unsigned overflow. */
+ if(RANGE_CHECK && n!=0)
+ {
+ if((unsigned_p && (unsigned)prevn >= (unsigned)n))
+ range_error("Overflow on numeric constant.");
+ }
+ prevn=n;
+ }
+
+ /* If the number is too big to be an int, or it's got an l suffix
+ then it's a long. Work out if this has to be a long by
+ shifting right and and seeing if anything remains, and the
+ target int size is different to the target long size.
+
+ In the expression below, we could have tested
+ (n >> TARGET_INT_BIT)
+ to see if it was zero,
+ but too many compilers warn about that, when ints and longs
+ are the same size. So we shift it twice, with fewer bits
+ each time, for the same result. */
+
+ if ( (TARGET_INT_BIT != TARGET_LONG_BIT
+ && ((n >> 2) >> (TARGET_INT_BIT-2))) /* Avoid shift warning */
+ || long_p)
+ {
+ high_bit = ((unsigned LONGEST)1) << (TARGET_LONG_BIT-1);
+ unsigned_type = builtin_type_unsigned_long;
+ signed_type = builtin_type_long;
+ }
+ else
+ {
+ high_bit = ((unsigned LONGEST)1) << (TARGET_INT_BIT-1);
+ unsigned_type = builtin_type_unsigned_int;
+ signed_type = builtin_type_int;
+ }
+
+ putithere->typed_val.val = n;
+
+ /* If the high bit of the worked out type is set then this number
+ has to be unsigned. */
+
+ if (unsigned_p || (n & high_bit))
+ {
+ putithere->typed_val.type = unsigned_type;
+ }
+ else
+ {
+ putithere->typed_val.type = signed_type;
+ }
+
+ return INT;
+}
+
+struct token
+{
+ char *operator;
+ int token;
+ enum exp_opcode opcode;
+};
+
+static const struct token tokentab3[] =
+ {
+ {">>=", ASSIGN_MODIFY, BINOP_RSH},
+ {"<<=", ASSIGN_MODIFY, BINOP_LSH}
+ };
+
+static const struct token tokentab2[] =
+ {
+ {"+=", ASSIGN_MODIFY, BINOP_ADD},
+ {"-=", ASSIGN_MODIFY, BINOP_SUB},
+ {"*=", ASSIGN_MODIFY, BINOP_MUL},
+ {"/=", ASSIGN_MODIFY, BINOP_DIV},
+ {"%=", ASSIGN_MODIFY, BINOP_REM},
+ {"|=", ASSIGN_MODIFY, BINOP_BITWISE_IOR},
+ {"&=", ASSIGN_MODIFY, BINOP_BITWISE_AND},
+ {"^=", ASSIGN_MODIFY, BINOP_BITWISE_XOR},
+ {"++", INCREMENT, BINOP_END},
+ {"--", DECREMENT, BINOP_END},
+ {"->", ARROW, BINOP_END},
+ {"&&", ANDAND, BINOP_END},
+ {"||", OROR, BINOP_END},
+ {"::", COLONCOLON, BINOP_END},
+ {"<<", LSH, BINOP_END},
+ {">>", RSH, BINOP_END},
+ {"==", EQUAL, BINOP_END},
+ {"!=", NOTEQUAL, BINOP_END},
+ {"<=", LEQ, BINOP_END},
+ {">=", GEQ, BINOP_END}
+ };
+
+/* Read one token, getting characters through lexptr. */
+
+static int
+yylex ()
+{
+ int c;
+ int namelen;
+ unsigned int i;
+ char *tokstart;
+ char *tokptr;
+ int tempbufindex;
+ static char *tempbuf;
+ static int tempbufsize;
+
+ retry:
+
+ tokstart = lexptr;
+ /* See if it is a special token of length 3. */
+ for (i = 0; i < sizeof tokentab3 / sizeof tokentab3[0]; i++)
+ if (STREQN (tokstart, tokentab3[i].operator, 3))
+ {
+ lexptr += 3;
+ yylval.opcode = tokentab3[i].opcode;
+ return tokentab3[i].token;
+ }
+
+ /* See if it is a special token of length 2. */
+ for (i = 0; i < sizeof tokentab2 / sizeof tokentab2[0]; i++)
+ if (STREQN (tokstart, tokentab2[i].operator, 2))
+ {
+ lexptr += 2;
+ yylval.opcode = tokentab2[i].opcode;
+ return tokentab2[i].token;
+ }
+
+ switch (c = *tokstart)
+ {
+ case 0:
+ return 0;
+
+ case ' ':
+ case '\t':
+ case '\n':
+ lexptr++;
+ goto retry;
+
+ case '\'':
+ /* We either have a character constant ('0' or '\177' for example)
+ or we have a quoted symbol reference ('foo(int,int)' in C++
+ for example). */
+ lexptr++;
+ c = *lexptr++;
+ if (c == '\\')
+ c = parse_escape (&lexptr);
+
+ yylval.typed_val.val = c;
+ yylval.typed_val.type = builtin_type_char;
+
+ c = *lexptr++;
+ if (c != '\'')
+ {
+ namelen = skip_quoted (tokstart) - tokstart;
+ if (namelen > 2)
+ {
+ lexptr = tokstart + namelen;
+ if (lexptr[-1] != '\'')
+ error ("Unmatched single quote.");
+ namelen -= 2;
+ tokstart++;
+ goto tryname;
+ }
+ error ("Invalid character constant.");
+ }
+ return INT;
+
+ case '(':
+ paren_depth++;
+ lexptr++;
+ return c;
+
+ case ')':
+ if (paren_depth == 0)
+ return 0;
+ paren_depth--;
+ lexptr++;
+ return c;
+
+ case ',':
+ if (comma_terminates && paren_depth == 0)
+ return 0;
+ lexptr++;
+ return c;
+
+ case '.':
+ /* Might be a floating point number. */
+ if (lexptr[1] < '0' || lexptr[1] > '9')
+ goto symbol; /* Nope, must be a symbol. */
+ /* FALL THRU into number case. */
+
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ {
+ /* It's a number. */
+ int got_dot = 0, got_e = 0, toktype;
+ register char *p = tokstart;
+ int hex = input_radix > 10;
+
+ if (c == '0' && (p[1] == 'x' || p[1] == 'X'))
+ {
+ p += 2;
+ hex = 1;
+ }
+ else if (c == '0' && (p[1]=='t' || p[1]=='T' || p[1]=='d' || p[1]=='D'))
+ {
+ p += 2;
+ hex = 0;
+ }
+
+ for (;; ++p)
+ {
+ /* This test includes !hex because 'e' is a valid hex digit
+ and thus does not indicate a floating point number when
+ the radix is hex. */
+ if (!hex && !got_e && (*p == 'e' || *p == 'E'))
+ got_dot = got_e = 1;
+ /* This test does not include !hex, because a '.' always indicates
+ a decimal floating point number regardless of the radix. */
+ else if (!got_dot && *p == '.')
+ got_dot = 1;
+ else if (got_e && (p[-1] == 'e' || p[-1] == 'E')
+ && (*p == '-' || *p == '+'))
+ /* This is the sign of the exponent, not the end of the
+ number. */
+ continue;
+ /* We will take any letters or digits. parse_number will
+ complain if past the radix, or if L or U are not final. */
+ else if ((*p < '0' || *p > '9')
+ && ((*p < 'a' || *p > 'z')
+ && (*p < 'A' || *p > 'Z')))
+ break;
+ }
+ toktype = parse_number (tokstart, p - tokstart, got_dot|got_e, &yylval);
+ if (toktype == ERROR)
+ {
+ char *err_copy = (char *) alloca (p - tokstart + 1);
+
+ memcpy (err_copy, tokstart, p - tokstart);
+ err_copy[p - tokstart] = 0;
+ error ("Invalid number \"%s\".", err_copy);
+ }
+ lexptr = p;
+ return toktype;
+ }
+
+ case '+':
+ case '-':
+ case '*':
+ case '/':
+ case '%':
+ case '|':
+ case '&':
+ case '^':
+ case '~':
+ case '!':
+ case '@':
+ case '<':
+ case '>':
+ case '[':
+ case ']':
+ case '?':
+ case ':':
+ case '=':
+ case '{':
+ case '}':
+ symbol:
+ lexptr++;
+ return c;
+
+ case '"':
+
+ /* Build the gdb internal form of the input string in tempbuf,
+ translating any standard C escape forms seen. Note that the
+ buffer is null byte terminated *only* for the convenience of
+ debugging gdb itself and printing the buffer contents when
+ the buffer contains no embedded nulls. Gdb does not depend
+ upon the buffer being null byte terminated, it uses the length
+ string instead. This allows gdb to handle C strings (as well
+ as strings in other languages) with embedded null bytes */
+
+ tokptr = ++tokstart;
+ tempbufindex = 0;
+
+ do {
+ /* Grow the static temp buffer if necessary, including allocating
+ the first one on demand. */
+ if (tempbufindex + 1 >= tempbufsize)
+ {
+ tempbuf = (char *) realloc (tempbuf, tempbufsize += 64);
+ }
+ switch (*tokptr)
+ {
+ case '\0':
+ case '"':
+ /* Do nothing, loop will terminate. */
+ break;
+ case '\\':
+ tokptr++;
+ c = parse_escape (&tokptr);
+ if (c == -1)
+ {
+ continue;
+ }
+ tempbuf[tempbufindex++] = c;
+ break;
+ default:
+ tempbuf[tempbufindex++] = *tokptr++;
+ break;
+ }
+ } while ((*tokptr != '"') && (*tokptr != '\0'));
+ if (*tokptr++ != '"')
+ {
+ error ("Unterminated string in expression.");
+ }
+ tempbuf[tempbufindex] = '\0'; /* See note above */
+ yylval.sval.ptr = tempbuf;
+ yylval.sval.length = tempbufindex;
+ lexptr = tokptr;
+ return (STRING);
+ }
+
+ if (!(c == '_' || c == '$'
+ || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')))
+ /* We must have come across a bad character (e.g. ';'). */
+ error ("Invalid character '%c' in expression.", c);
+
+ /* It's a name. See how long it is. */
+ namelen = 0;
+ for (c = tokstart[namelen];
+ (c == '_' || c == '$' || (c >= '0' && c <= '9')
+ || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'));
+ c = tokstart[++namelen])
+ ;
+
+ /* The token "if" terminates the expression and is NOT
+ removed from the input stream. */
+ if (namelen == 2 && tokstart[0] == 'i' && tokstart[1] == 'f')
+ {
+ return 0;
+ }
+
+ lexptr += namelen;
+
+ /* Handle the tokens $digits; also $ (short for $0) and $$ (short for $$1)
+ and $$digits (equivalent to $<-digits> if you could type that).
+ Make token type LAST, and put the number (the digits) in yylval. */
+
+ tryname:
+ if (*tokstart == '$')
+ {
+ register int negate = 0;
+ c = 1;
+ /* Double dollar means negate the number and add -1 as well.
+ Thus $$ alone means -1. */
+ if (namelen >= 2 && tokstart[1] == '$')
+ {
+ negate = 1;
+ c = 2;
+ }
+ if (c == namelen)
+ {
+ /* Just dollars (one or two) */
+ yylval.lval = - negate;
+ return LAST;
+ }
+ /* Is the rest of the token digits? */
+ for (; c < namelen; c++)
+ if (!(tokstart[c] >= '0' && tokstart[c] <= '9'))
+ break;
+ if (c == namelen)
+ {
+ yylval.lval = atoi (tokstart + 1 + negate);
+ if (negate)
+ yylval.lval = - yylval.lval;
+ return LAST;
+ }
+ }
+
+ /* Handle tokens that refer to machine registers:
+ $ followed by a register name. */
+
+ if (*tokstart == '$') {
+ for (c = 0; c < NUM_REGS; c++)
+ if (namelen - 1 == strlen (reg_names[c])
+ && STREQN (tokstart + 1, reg_names[c], namelen - 1))
+ {
+ yylval.lval = c;
+ return REGNAME;
+ }
+ for (c = 0; c < num_std_regs; c++)
+ if (namelen - 1 == strlen (std_regs[c].name)
+ && STREQN (tokstart + 1, std_regs[c].name, namelen - 1))
+ {
+ yylval.lval = std_regs[c].regnum;
+ return REGNAME;
+ }
+ }
+ /* Catch specific keywords. Should be done with a data structure. */
+ switch (namelen)
+ {
+ case 8:
+ if (STREQN (tokstart, "unsigned", 8))
+ return UNSIGNED;
+ if (current_language->la_language == language_cplus
+ && STREQN (tokstart, "template", 8))
+ return TEMPLATE;
+ if (STREQN (tokstart, "volatile", 8))
+ return VOLATILE_KEYWORD;
+ break;
+ case 6:
+ if (STREQN (tokstart, "struct", 6))
+ return STRUCT;
+ if (STREQN (tokstart, "signed", 6))
+ return SIGNED_KEYWORD;
+ if (STREQN (tokstart, "sizeof", 6))
+ return SIZEOF;
+ break;
+ case 5:
+ if (current_language->la_language == language_cplus
+ && STREQN (tokstart, "class", 5))
+ return CLASS;
+ if (STREQN (tokstart, "union", 5))
+ return UNION;
+ if (STREQN (tokstart, "short", 5))
+ return SHORT;
+ if (STREQN (tokstart, "const", 5))
+ return CONST_KEYWORD;
+ break;
+ case 4:
+ if (STREQN (tokstart, "enum", 4))
+ return ENUM;
+ if (STREQN (tokstart, "long", 4))
+ return LONG;
+ if (current_language->la_language == language_cplus
+ && STREQN (tokstart, "this", 4))
+ {
+ static const char this_name[] =
+ { CPLUS_MARKER, 't', 'h', 'i', 's', '\0' };
+
+ if (lookup_symbol (this_name, expression_context_block,
+ VAR_NAMESPACE, (int *) NULL,
+ (struct symtab **) NULL))
+ return THIS;
+ }
+ break;
+ case 3:
+ if (STREQN (tokstart, "int", 3))
+ return INT_KEYWORD;
+ break;
+ default:
+ break;
+ }
+
+ yylval.sval.ptr = tokstart;
+ yylval.sval.length = namelen;
+
+ /* Any other names starting in $ are debugger internal variables. */
+
+ if (*tokstart == '$')
+ {
+ yylval.ivar = lookup_internalvar (copy_name (yylval.sval) + 1);
+ return VARIABLE;
+ }
+
+ /* Use token-type BLOCKNAME for symbols that happen to be defined as
+ functions or symtabs. If this is not so, then ...
+ Use token-type TYPENAME for symbols that happen to be defined
+ currently as names of types; NAME for other symbols.
+ The caller is not constrained to care about the distinction. */
+ {
+ char *tmp = copy_name (yylval.sval);
+ struct symbol *sym;
+ int is_a_field_of_this = 0;
+ int hextype;
+
+ sym = lookup_symbol (tmp, expression_context_block,
+ VAR_NAMESPACE,
+ current_language->la_language == language_cplus
+ ? &is_a_field_of_this : (int *) NULL,
+ (struct symtab **) NULL);
+ if ((sym && SYMBOL_CLASS (sym) == LOC_BLOCK) ||
+ lookup_partial_symtab (tmp))
+ {
+ yylval.ssym.sym = sym;
+ yylval.ssym.is_a_field_of_this = is_a_field_of_this;
+ return BLOCKNAME;
+ }
+ if (sym && SYMBOL_CLASS (sym) == LOC_TYPEDEF)
+ {
+ char *p;
+ char *namestart;
+ struct symbol *best_sym;
+
+ /* Look ahead to detect nested types. This probably should be
+ done in the grammar, but trying seemed to introduce a lot
+ of shift/reduce and reduce/reduce conflicts. It's possible
+ that it could be done, though. Or perhaps a non-grammar, but
+ less ad hoc, approach would work well. */
+
+ /* Since we do not currently have any way of distinguishing
+ a nested type from a non-nested one (the stabs don't tell
+ us whether a type is nested), we just ignore the
+ containing type. */
+
+ p = lexptr;
+ best_sym = sym;
+ while (1)
+ {
+ /* Skip whitespace. */
+ while (*p == ' ' || *p == '\t' || *p == '\n')
+ ++p;
+ if (*p == ':' && p[1] == ':')
+ {
+ /* Skip the `::'. */
+ p += 2;
+ /* Skip whitespace. */
+ while (*p == ' ' || *p == '\t' || *p == '\n')
+ ++p;
+ namestart = p;
+ while (*p == '_' || *p == '$' || (*p >= '0' && *p <= '9')
+ || (*p >= 'a' && *p <= 'z')
+ || (*p >= 'A' && *p <= 'Z'))
+ ++p;
+ if (p != namestart)
+ {
+ struct symbol *cur_sym;
+ /* As big as the whole rest of the expression, which is
+ at least big enough. */
+ char *tmp = alloca (strlen (namestart));
+
+ memcpy (tmp, namestart, p - namestart);
+ tmp[p - namestart] = '\0';
+ cur_sym = lookup_symbol (tmp, expression_context_block,
+ VAR_NAMESPACE, (int *) NULL,
+ (struct symtab **) NULL);
+ if (cur_sym)
+ {
+ if (SYMBOL_CLASS (cur_sym) == LOC_TYPEDEF)
+ {
+ best_sym = cur_sym;
+ lexptr = p;
+ }
+ else
+ break;
+ }
+ else
+ break;
+ }
+ else
+ break;
+ }
+ else
+ break;
+ }
+
+ yylval.tsym.type = SYMBOL_TYPE (best_sym);
+ return TYPENAME;
+ }
+ if ((yylval.tsym.type = lookup_primitive_typename (tmp)) != 0)
+ return TYPENAME;
+
+ /* Input names that aren't symbols but ARE valid hex numbers,
+ when the input radix permits them, can be names or numbers
+ depending on the parse. Note we support radixes > 16 here. */
+ if (!sym &&
+ ((tokstart[0] >= 'a' && tokstart[0] < 'a' + input_radix - 10) ||
+ (tokstart[0] >= 'A' && tokstart[0] < 'A' + input_radix - 10)))
+ {
+ YYSTYPE newlval; /* Its value is ignored. */
+ hextype = parse_number (tokstart, namelen, 0, &newlval);
+ if (hextype == INT)
+ {
+ yylval.ssym.sym = sym;
+ yylval.ssym.is_a_field_of_this = is_a_field_of_this;
+ return NAME_OR_INT;
+ }
+ }
+
+ /* Any other kind of symbol */
+ yylval.ssym.sym = sym;
+ yylval.ssym.is_a_field_of_this = is_a_field_of_this;
+ return NAME;
+ }
+}
+
+void
+yyerror (msg)
+ char *msg;
+{
+ error (msg ? msg : "Invalid syntax in expression.");
+}
diff --git a/gnu/usr.bin/gdb/gdb/c-lang.c b/gnu/usr.bin/gdb/gdb/c-lang.c
new file mode 100644
index 0000000..9b4b3ee
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/c-lang.c
@@ -0,0 +1,469 @@
+/* C language support routines for GDB, the GNU debugger.
+ Copyright 1992, 1993, 1994 Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "defs.h"
+#include "symtab.h"
+#include "gdbtypes.h"
+#include "expression.h"
+#include "parser-defs.h"
+#include "language.h"
+#include "c-lang.h"
+
+/* Print the character C on STREAM as part of the contents of a literal
+ string whose delimiter is QUOTER. Note that that format for printing
+ characters and strings is language specific. */
+
+static void
+emit_char (c, stream, quoter)
+ register int c;
+ GDB_FILE *stream;
+ int quoter;
+{
+
+ c &= 0xFF; /* Avoid sign bit follies */
+
+ if (PRINT_LITERAL_FORM (c))
+ {
+ if (c == '\\' || c == quoter)
+ {
+ fputs_filtered ("\\", stream);
+ }
+ fprintf_filtered (stream, "%c", c);
+ }
+ else
+ {
+ switch (c)
+ {
+ case '\n':
+ fputs_filtered ("\\n", stream);
+ break;
+ case '\b':
+ fputs_filtered ("\\b", stream);
+ break;
+ case '\t':
+ fputs_filtered ("\\t", stream);
+ break;
+ case '\f':
+ fputs_filtered ("\\f", stream);
+ break;
+ case '\r':
+ fputs_filtered ("\\r", stream);
+ break;
+ case '\033':
+ fputs_filtered ("\\e", stream);
+ break;
+ case '\007':
+ fputs_filtered ("\\a", stream);
+ break;
+ default:
+ fprintf_filtered (stream, "\\%.3o", (unsigned int) c);
+ break;
+ }
+ }
+}
+
+static void
+c_printchar (c, stream)
+ int c;
+ GDB_FILE *stream;
+{
+ fputs_filtered ("'", stream);
+ emit_char (c, stream, '\'');
+ fputs_filtered ("'", stream);
+}
+
+/* Print the character string STRING, printing at most LENGTH characters.
+ Printing stops early if the number hits print_max; repeat counts
+ are printed as appropriate. Print ellipses at the end if we
+ had to stop before printing LENGTH characters, or if FORCE_ELLIPSES. */
+
+static void
+c_printstr (stream, string, length, force_ellipses)
+ GDB_FILE *stream;
+ char *string;
+ unsigned int length;
+ int force_ellipses;
+{
+ register unsigned int i;
+ unsigned int things_printed = 0;
+ int in_quotes = 0;
+ int need_comma = 0;
+ extern int inspect_it;
+ extern int repeat_count_threshold;
+ extern int print_max;
+
+ /* If the string was not truncated due to `set print elements', and
+ the last byte of it is a null, we don't print that, in traditional C
+ style. */
+ if ((!force_ellipses) && length > 0 && string[length-1] == '\0')
+ length--;
+
+ if (length == 0)
+ {
+ fputs_filtered ("\"\"", stream);
+ return;
+ }
+
+ for (i = 0; i < length && things_printed < print_max; ++i)
+ {
+ /* Position of the character we are examining
+ to see whether it is repeated. */
+ unsigned int rep1;
+ /* Number of repetitions we have detected so far. */
+ unsigned int reps;
+
+ QUIT;
+
+ if (need_comma)
+ {
+ fputs_filtered (", ", stream);
+ need_comma = 0;
+ }
+
+ rep1 = i + 1;
+ reps = 1;
+ while (rep1 < length && string[rep1] == string[i])
+ {
+ ++rep1;
+ ++reps;
+ }
+
+ if (reps > repeat_count_threshold)
+ {
+ if (in_quotes)
+ {
+ if (inspect_it)
+ fputs_filtered ("\\\", ", stream);
+ else
+ fputs_filtered ("\", ", stream);
+ in_quotes = 0;
+ }
+ c_printchar (string[i], stream);
+ fprintf_filtered (stream, " <repeats %u times>", reps);
+ i = rep1 - 1;
+ things_printed += repeat_count_threshold;
+ need_comma = 1;
+ }
+ else
+ {
+ if (!in_quotes)
+ {
+ if (inspect_it)
+ fputs_filtered ("\\\"", stream);
+ else
+ fputs_filtered ("\"", stream);
+ in_quotes = 1;
+ }
+ emit_char (string[i], stream, '"');
+ ++things_printed;
+ }
+ }
+
+ /* Terminate the quotes if necessary. */
+ if (in_quotes)
+ {
+ if (inspect_it)
+ fputs_filtered ("\\\"", stream);
+ else
+ fputs_filtered ("\"", stream);
+ }
+
+ if (force_ellipses || i < length)
+ fputs_filtered ("...", stream);
+}
+
+/* Create a fundamental C type using default reasonable for the current
+ target machine.
+
+ Some object/debugging file formats (DWARF version 1, COFF, etc) do not
+ define fundamental types such as "int" or "double". Others (stabs or
+ DWARF version 2, etc) do define fundamental types. For the formats which
+ don't provide fundamental types, gdb can create such types using this
+ function.
+
+ FIXME: Some compilers distinguish explicitly signed integral types
+ (signed short, signed int, signed long) from "regular" integral types
+ (short, int, long) in the debugging information. There is some dis-
+ agreement as to how useful this feature is. In particular, gcc does
+ not support this. Also, only some debugging formats allow the
+ distinction to be passed on to a debugger. For now, we always just
+ use "short", "int", or "long" as the type name, for both the implicit
+ and explicitly signed types. This also makes life easier for the
+ gdb test suite since we don't have to account for the differences
+ in output depending upon what the compiler and debugging format
+ support. We will probably have to re-examine the issue when gdb
+ starts taking it's fundamental type information directly from the
+ debugging information supplied by the compiler. fnf@cygnus.com */
+
+static struct type *
+c_create_fundamental_type (objfile, typeid)
+ struct objfile *objfile;
+ int typeid;
+{
+ register struct type *type = NULL;
+
+ switch (typeid)
+ {
+ default:
+ /* FIXME: For now, if we are asked to produce a type not in this
+ language, create the equivalent of a C integer type with the
+ name "<?type?>". When all the dust settles from the type
+ reconstruction work, this should probably become an error. */
+ type = init_type (TYPE_CODE_INT,
+ TARGET_INT_BIT / TARGET_CHAR_BIT,
+ 0, "<?type?>", objfile);
+ warning ("internal error: no C/C++ fundamental type %d", typeid);
+ break;
+ case FT_VOID:
+ type = init_type (TYPE_CODE_VOID,
+ TARGET_CHAR_BIT / TARGET_CHAR_BIT,
+ 0, "void", objfile);
+ break;
+ case FT_CHAR:
+ type = init_type (TYPE_CODE_INT,
+ TARGET_CHAR_BIT / TARGET_CHAR_BIT,
+ 0, "char", objfile);
+ break;
+ case FT_SIGNED_CHAR:
+ type = init_type (TYPE_CODE_INT,
+ TARGET_CHAR_BIT / TARGET_CHAR_BIT,
+ 0, "signed char", objfile);
+ break;
+ case FT_UNSIGNED_CHAR:
+ type = init_type (TYPE_CODE_INT,
+ TARGET_CHAR_BIT / TARGET_CHAR_BIT,
+ TYPE_FLAG_UNSIGNED, "unsigned char", objfile);
+ break;
+ case FT_SHORT:
+ type = init_type (TYPE_CODE_INT,
+ TARGET_SHORT_BIT / TARGET_CHAR_BIT,
+ 0, "short", objfile);
+ break;
+ case FT_SIGNED_SHORT:
+ type = init_type (TYPE_CODE_INT,
+ TARGET_SHORT_BIT / TARGET_CHAR_BIT,
+ 0, "short", objfile); /* FIXME-fnf */
+ break;
+ case FT_UNSIGNED_SHORT:
+ type = init_type (TYPE_CODE_INT,
+ TARGET_SHORT_BIT / TARGET_CHAR_BIT,
+ TYPE_FLAG_UNSIGNED, "unsigned short", objfile);
+ break;
+ case FT_INTEGER:
+ type = init_type (TYPE_CODE_INT,
+ TARGET_INT_BIT / TARGET_CHAR_BIT,
+ 0, "int", objfile);
+ break;
+ case FT_SIGNED_INTEGER:
+ type = init_type (TYPE_CODE_INT,
+ TARGET_INT_BIT / TARGET_CHAR_BIT,
+ 0, "int", objfile); /* FIXME -fnf */
+ break;
+ case FT_UNSIGNED_INTEGER:
+ type = init_type (TYPE_CODE_INT,
+ TARGET_INT_BIT / TARGET_CHAR_BIT,
+ TYPE_FLAG_UNSIGNED, "unsigned int", objfile);
+ break;
+ case FT_LONG:
+ type = init_type (TYPE_CODE_INT,
+ TARGET_LONG_BIT / TARGET_CHAR_BIT,
+ 0, "long", objfile);
+ break;
+ case FT_SIGNED_LONG:
+ type = init_type (TYPE_CODE_INT,
+ TARGET_LONG_BIT / TARGET_CHAR_BIT,
+ 0, "long", objfile); /* FIXME -fnf */
+ break;
+ case FT_UNSIGNED_LONG:
+ type = init_type (TYPE_CODE_INT,
+ TARGET_LONG_BIT / TARGET_CHAR_BIT,
+ TYPE_FLAG_UNSIGNED, "unsigned long", objfile);
+ break;
+ case FT_LONG_LONG:
+ type = init_type (TYPE_CODE_INT,
+ TARGET_LONG_LONG_BIT / TARGET_CHAR_BIT,
+ 0, "long long", objfile);
+ break;
+ case FT_SIGNED_LONG_LONG:
+ type = init_type (TYPE_CODE_INT,
+ TARGET_LONG_LONG_BIT / TARGET_CHAR_BIT,
+ 0, "signed long long", objfile);
+ break;
+ case FT_UNSIGNED_LONG_LONG:
+ type = init_type (TYPE_CODE_INT,
+ TARGET_LONG_LONG_BIT / TARGET_CHAR_BIT,
+ TYPE_FLAG_UNSIGNED, "unsigned long long", objfile);
+ break;
+ case FT_FLOAT:
+ type = init_type (TYPE_CODE_FLT,
+ TARGET_FLOAT_BIT / TARGET_CHAR_BIT,
+ 0, "float", objfile);
+ break;
+ case FT_DBL_PREC_FLOAT:
+ type = init_type (TYPE_CODE_FLT,
+ TARGET_DOUBLE_BIT / TARGET_CHAR_BIT,
+ 0, "double", objfile);
+ break;
+ case FT_EXT_PREC_FLOAT:
+ type = init_type (TYPE_CODE_FLT,
+ TARGET_LONG_DOUBLE_BIT / TARGET_CHAR_BIT,
+ 0, "long double", objfile);
+ break;
+ }
+ return (type);
+}
+
+
+/* Table mapping opcodes into strings for printing operators
+ and precedences of the operators. */
+
+static const struct op_print c_op_print_tab[] =
+ {
+ {",", BINOP_COMMA, PREC_COMMA, 0},
+ {"=", BINOP_ASSIGN, PREC_ASSIGN, 1},
+ {"||", BINOP_LOGICAL_OR, PREC_LOGICAL_OR, 0},
+ {"&&", BINOP_LOGICAL_AND, PREC_LOGICAL_AND, 0},
+ {"|", BINOP_BITWISE_IOR, PREC_BITWISE_IOR, 0},
+ {"^", BINOP_BITWISE_XOR, PREC_BITWISE_XOR, 0},
+ {"&", BINOP_BITWISE_AND, PREC_BITWISE_AND, 0},
+ {"==", BINOP_EQUAL, PREC_EQUAL, 0},
+ {"!=", BINOP_NOTEQUAL, PREC_EQUAL, 0},
+ {"<=", BINOP_LEQ, PREC_ORDER, 0},
+ {">=", BINOP_GEQ, PREC_ORDER, 0},
+ {">", BINOP_GTR, PREC_ORDER, 0},
+ {"<", BINOP_LESS, PREC_ORDER, 0},
+ {">>", BINOP_RSH, PREC_SHIFT, 0},
+ {"<<", BINOP_LSH, PREC_SHIFT, 0},
+ {"+", BINOP_ADD, PREC_ADD, 0},
+ {"-", BINOP_SUB, PREC_ADD, 0},
+ {"*", BINOP_MUL, PREC_MUL, 0},
+ {"/", BINOP_DIV, PREC_MUL, 0},
+ {"%", BINOP_REM, PREC_MUL, 0},
+ {"@", BINOP_REPEAT, PREC_REPEAT, 0},
+ {"-", UNOP_NEG, PREC_PREFIX, 0},
+ {"!", UNOP_LOGICAL_NOT, PREC_PREFIX, 0},
+ {"~", UNOP_COMPLEMENT, PREC_PREFIX, 0},
+ {"*", UNOP_IND, PREC_PREFIX, 0},
+ {"&", UNOP_ADDR, PREC_PREFIX, 0},
+ {"sizeof ", UNOP_SIZEOF, PREC_PREFIX, 0},
+ {"++", UNOP_PREINCREMENT, PREC_PREFIX, 0},
+ {"--", UNOP_PREDECREMENT, PREC_PREFIX, 0},
+ /* C++ */
+ {"::", BINOP_SCOPE, PREC_PREFIX, 0},
+ {NULL, 0, 0, 0}
+};
+
+struct type ** const (c_builtin_types[]) =
+{
+ &builtin_type_int,
+ &builtin_type_long,
+ &builtin_type_short,
+ &builtin_type_char,
+ &builtin_type_float,
+ &builtin_type_double,
+ &builtin_type_void,
+ &builtin_type_long_long,
+ &builtin_type_signed_char,
+ &builtin_type_unsigned_char,
+ &builtin_type_unsigned_short,
+ &builtin_type_unsigned_int,
+ &builtin_type_unsigned_long,
+ &builtin_type_unsigned_long_long,
+ &builtin_type_long_double,
+ &builtin_type_complex,
+ &builtin_type_double_complex,
+ 0
+};
+
+const struct language_defn c_language_defn = {
+ "c", /* Language name */
+ language_c,
+ c_builtin_types,
+ range_check_off,
+ type_check_off,
+ c_parse,
+ c_error,
+ c_printchar, /* Print a character constant */
+ c_printstr, /* Function to print string constant */
+ c_create_fundamental_type, /* Create fundamental type in this language */
+ c_print_type, /* Print a type using appropriate syntax */
+ c_val_print, /* Print a value using appropriate syntax */
+ c_value_print, /* Print a top-level value */
+ &builtin_type_double, /* longest floating point type */ /*FIXME*/
+ {"", "", "", ""}, /* Binary format info */
+ {"0%lo", "0", "o", ""}, /* Octal format info */
+ {"%ld", "", "d", ""}, /* Decimal format info */
+ {"0x%lx", "0x", "x", ""}, /* Hex format info */
+ c_op_print_tab, /* expression operators for printing */
+ LANG_MAGIC
+};
+
+const struct language_defn cplus_language_defn = {
+ "c++", /* Language name */
+ language_cplus,
+ c_builtin_types,
+ range_check_off,
+ type_check_off,
+ c_parse,
+ c_error,
+ c_printchar, /* Print a character constant */
+ c_printstr, /* Function to print string constant */
+ c_create_fundamental_type, /* Create fundamental type in this language */
+ c_print_type, /* Print a type using appropriate syntax */
+ c_val_print, /* Print a value using appropriate syntax */
+ c_value_print, /* Print a top-level value */
+ &builtin_type_double, /* longest floating point type */ /*FIXME*/
+ {"", "", "", ""}, /* Binary format info */
+ {"0%lo", "0", "o", ""}, /* Octal format info */
+ {"%ld", "", "d", ""}, /* Decimal format info */
+ {"0x%lx", "0x", "x", ""}, /* Hex format info */
+ c_op_print_tab, /* expression operators for printing */
+ LANG_MAGIC
+};
+
+const struct language_defn asm_language_defn = {
+ "asm", /* Language name */
+ language_asm,
+ c_builtin_types,
+ range_check_off,
+ type_check_off,
+ c_parse,
+ c_error,
+ c_printchar, /* Print a character constant */
+ c_printstr, /* Function to print string constant */
+ c_create_fundamental_type, /* Create fundamental type in this language */
+ c_print_type, /* Print a type using appropriate syntax */
+ c_val_print, /* Print a value using appropriate syntax */
+ c_value_print, /* Print a top-level value */
+ &builtin_type_double, /* longest floating point type */ /*FIXME*/
+ {"", "", "", ""}, /* Binary format info */
+ {"0%lo", "0", "o", ""}, /* Octal format info */
+ {"%ld", "", "d", ""}, /* Decimal format info */
+ {"0x%lx", "0x", "x", ""}, /* Hex format info */
+ c_op_print_tab, /* expression operators for printing */
+ LANG_MAGIC
+};
+
+void
+_initialize_c_language ()
+{
+ add_language (&c_language_defn);
+ add_language (&cplus_language_defn);
+ add_language (&asm_language_defn);
+}
diff --git a/gnu/usr.bin/gdb/gdb/c-lang.h b/gnu/usr.bin/gdb/gdb/c-lang.h
new file mode 100644
index 0000000..0ea013d
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/c-lang.h
@@ -0,0 +1,38 @@
+/* C language support definitions for GDB, the GNU debugger.
+ Copyright 1992 Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#ifdef __STDC__ /* Forward decls for prototypes */
+struct value;
+#endif
+
+extern int
+c_parse PARAMS ((void)); /* Defined in c-exp.y */
+
+extern void
+c_error PARAMS ((char *)); /* Defined in c-exp.y */
+
+extern void /* Defined in c-typeprint.c */
+c_print_type PARAMS ((struct type *, char *, GDB_FILE *, int, int));
+
+extern int
+c_val_print PARAMS ((struct type *, char *, CORE_ADDR, GDB_FILE *, int, int,
+ int, enum val_prettyprint));
+
+extern int
+c_value_print PARAMS ((struct value *, GDB_FILE *, int, enum val_prettyprint));
diff --git a/gnu/usr.bin/gdb/gdb/c-typeprint.c b/gnu/usr.bin/gdb/gdb/c-typeprint.c
new file mode 100644
index 0000000..8d915df
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/c-typeprint.c
@@ -0,0 +1,795 @@
+/* Support for printing C and C++ types for GDB, the GNU debugger.
+ Copyright 1986, 1988, 1989, 1991 Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "defs.h"
+#include "obstack.h"
+#include "bfd.h" /* Binary File Description */
+#include "symtab.h"
+#include "gdbtypes.h"
+#include "expression.h"
+#include "value.h"
+#include "gdbcore.h"
+#include "target.h"
+#include "command.h"
+#include "gdbcmd.h"
+#include "language.h"
+#include "demangle.h"
+#include "c-lang.h"
+#include "typeprint.h"
+
+#include <string.h>
+#include <errno.h>
+
+static void
+c_type_print_args PARAMS ((struct type *, GDB_FILE *));
+
+static void
+c_type_print_varspec_suffix PARAMS ((struct type *, GDB_FILE *, int, int, int));
+
+static void
+cp_type_print_derivation_info PARAMS ((GDB_FILE *, struct type *));
+
+void
+c_type_print_varspec_prefix PARAMS ((struct type *, GDB_FILE *, int, int));
+
+void
+c_type_print_base PARAMS ((struct type *, GDB_FILE *, int, int));
+
+
+/* Print a description of a type in the format of a
+ typedef for the current language.
+ NEW is the new name for a type TYPE. */
+
+void
+c_typedef_print (type, new, stream)
+ struct type *type;
+ struct symbol *new;
+ GDB_FILE *stream;
+{
+ switch (current_language->la_language)
+ {
+#ifdef _LANG_c
+ case language_c:
+ case language_cplus:
+ fprintf_filtered(stream, "typedef ");
+ type_print(type,"",stream,0);
+ if(TYPE_NAME ((SYMBOL_TYPE (new))) == 0
+ || !STREQ (TYPE_NAME ((SYMBOL_TYPE (new))), SYMBOL_NAME (new)))
+ fprintf_filtered(stream, " %s", SYMBOL_SOURCE_NAME(new));
+ break;
+#endif
+#ifdef _LANG_m2
+ case language_m2:
+ fprintf_filtered(stream, "TYPE ");
+ if(!TYPE_NAME(SYMBOL_TYPE(new)) ||
+ !STREQ (TYPE_NAME(SYMBOL_TYPE(new)), SYMBOL_NAME(new)))
+ fprintf_filtered(stream, "%s = ", SYMBOL_SOURCE_NAME(new));
+ else
+ fprintf_filtered(stream, "<builtin> = ");
+ type_print(type,"",stream,0);
+ break;
+#endif
+#ifdef _LANG_chill
+ case language_chill:
+ error ("Missing Chill support in function c_typedef_print."); /*FIXME*/
+#endif
+ default:
+ error("Language not supported.");
+ }
+ fprintf_filtered(stream, ";\n");
+}
+
+
+/* LEVEL is the depth to indent lines by. */
+
+void
+c_print_type (type, varstring, stream, show, level)
+ struct type *type;
+ char *varstring;
+ GDB_FILE *stream;
+ int show;
+ int level;
+{
+ register enum type_code code;
+ int demangled_args;
+
+ c_type_print_base (type, stream, show, level);
+ code = TYPE_CODE (type);
+ if ((varstring != NULL && *varstring != '\0')
+ ||
+ /* Need a space if going to print stars or brackets;
+ but not if we will print just a type name. */
+ ((show > 0 || TYPE_NAME (type) == 0)
+ &&
+ (code == TYPE_CODE_PTR || code == TYPE_CODE_FUNC
+ || code == TYPE_CODE_METHOD
+ || code == TYPE_CODE_ARRAY
+ || code == TYPE_CODE_MEMBER
+ || code == TYPE_CODE_REF)))
+ fputs_filtered (" ", stream);
+ c_type_print_varspec_prefix (type, stream, show, 0);
+
+ fputs_filtered (varstring, stream);
+
+ /* For demangled function names, we have the arglist as part of the name,
+ so don't print an additional pair of ()'s */
+
+ demangled_args = varstring[strlen(varstring) - 1] == ')';
+ c_type_print_varspec_suffix (type, stream, show, 0, demangled_args);
+
+}
+
+/* Print the C++ method arguments ARGS to the file STREAM. */
+
+void
+cp_type_print_method_args (args, prefix, varstring, staticp, stream)
+ struct type **args;
+ char *prefix;
+ char *varstring;
+ int staticp;
+ GDB_FILE *stream;
+{
+ int i;
+
+ fprintf_symbol_filtered (stream, prefix, language_cplus, DMGL_ANSI);
+ fprintf_symbol_filtered (stream, varstring, language_cplus, DMGL_ANSI);
+ fputs_filtered (" (", stream);
+ if (args && args[!staticp] && args[!staticp]->code != TYPE_CODE_VOID)
+ {
+ i = !staticp; /* skip the class variable */
+ while (1)
+ {
+ type_print (args[i++], "", stream, 0);
+ if (!args[i])
+ {
+ fprintf_filtered (stream, " ...");
+ break;
+ }
+ else if (args[i]->code != TYPE_CODE_VOID)
+ {
+ fprintf_filtered (stream, ", ");
+ }
+ else break;
+ }
+ }
+ fprintf_filtered (stream, ")");
+}
+
+/* If TYPE is a derived type, then print out derivation information.
+ Print only the actual base classes of this type, not the base classes
+ of the base classes. I.E. for the derivation hierarchy:
+
+ class A { int a; };
+ class B : public A {int b; };
+ class C : public B {int c; };
+
+ Print the type of class C as:
+
+ class C : public B {
+ int c;
+ }
+
+ Not as the following (like gdb used to), which is not legal C++ syntax for
+ derived types and may be confused with the multiple inheritance form:
+
+ class C : public B : public A {
+ int c;
+ }
+
+ In general, gdb should try to print the types as closely as possible to
+ the form that they appear in the source code. */
+
+static void
+cp_type_print_derivation_info (stream, type)
+ GDB_FILE *stream;
+ struct type *type;
+{
+ char *name;
+ int i;
+
+ for (i = 0; i < TYPE_N_BASECLASSES (type); i++)
+ {
+ fputs_filtered (i == 0 ? ": " : ", ", stream);
+ fprintf_filtered (stream, "%s%s ",
+ BASETYPE_VIA_PUBLIC (type, i) ? "public" : "private",
+ BASETYPE_VIA_VIRTUAL(type, i) ? " virtual" : "");
+ name = type_name_no_tag (TYPE_BASECLASS (type, i));
+ fprintf_filtered (stream, "%s", name ? name : "(null)");
+ }
+ if (i > 0)
+ {
+ fputs_filtered (" ", stream);
+ }
+}
+
+/* Print any asterisks or open-parentheses needed before the
+ variable name (to describe its type).
+
+ On outermost call, pass 0 for PASSED_A_PTR.
+ On outermost call, SHOW > 0 means should ignore
+ any typename for TYPE and show its details.
+ SHOW is always zero on recursive calls. */
+
+void
+c_type_print_varspec_prefix (type, stream, show, passed_a_ptr)
+ struct type *type;
+ GDB_FILE *stream;
+ int show;
+ int passed_a_ptr;
+{
+ char *name;
+ if (type == 0)
+ return;
+
+ if (TYPE_NAME (type) && show <= 0)
+ return;
+
+ QUIT;
+
+ switch (TYPE_CODE (type))
+ {
+ case TYPE_CODE_PTR:
+ c_type_print_varspec_prefix (TYPE_TARGET_TYPE (type), stream, 0, 1);
+ fprintf_filtered (stream, "*");
+ break;
+
+ case TYPE_CODE_MEMBER:
+ if (passed_a_ptr)
+ fprintf_filtered (stream, "(");
+ c_type_print_varspec_prefix (TYPE_TARGET_TYPE (type), stream, 0, 0);
+ fprintf_filtered (stream, " ");
+ name = type_name_no_tag (TYPE_DOMAIN_TYPE (type));
+ if (name)
+ fputs_filtered (name, stream);
+ else
+ c_type_print_base (TYPE_DOMAIN_TYPE (type), stream, 0, passed_a_ptr);
+ fprintf_filtered (stream, "::");
+ break;
+
+ case TYPE_CODE_METHOD:
+ if (passed_a_ptr)
+ fprintf_unfiltered (stream, "(");
+ c_type_print_varspec_prefix (TYPE_TARGET_TYPE (type), stream, 0, 0);
+ if (passed_a_ptr)
+ {
+ fprintf_filtered (stream, " ");
+ c_type_print_base (TYPE_DOMAIN_TYPE (type), stream, 0, passed_a_ptr);
+ fprintf_filtered (stream, "::");
+ }
+ break;
+
+ case TYPE_CODE_REF:
+ c_type_print_varspec_prefix (TYPE_TARGET_TYPE (type), stream, 0, 1);
+ fprintf_filtered (stream, "&");
+ break;
+
+ case TYPE_CODE_FUNC:
+ c_type_print_varspec_prefix (TYPE_TARGET_TYPE (type), stream, 0, 0);
+ if (passed_a_ptr)
+ fprintf_filtered (stream, "(");
+ break;
+
+ case TYPE_CODE_ARRAY:
+ c_type_print_varspec_prefix (TYPE_TARGET_TYPE (type), stream, 0, 0);
+ if (passed_a_ptr)
+ fprintf_filtered (stream, "(");
+ break;
+
+ case TYPE_CODE_UNDEF:
+ case TYPE_CODE_STRUCT:
+ case TYPE_CODE_UNION:
+ case TYPE_CODE_ENUM:
+ case TYPE_CODE_INT:
+ case TYPE_CODE_FLT:
+ case TYPE_CODE_VOID:
+ case TYPE_CODE_ERROR:
+ case TYPE_CODE_CHAR:
+ case TYPE_CODE_BOOL:
+ case TYPE_CODE_SET:
+ case TYPE_CODE_RANGE:
+ case TYPE_CODE_STRING:
+ case TYPE_CODE_BITSTRING:
+ /* These types need no prefix. They are listed here so that
+ gcc -Wall will reveal any types that haven't been handled. */
+ break;
+ }
+}
+
+static void
+c_type_print_args (type, stream)
+ struct type *type;
+ GDB_FILE *stream;
+{
+ int i;
+ struct type **args;
+
+ fprintf_filtered (stream, "(");
+ args = TYPE_ARG_TYPES (type);
+ if (args != NULL)
+ {
+ if (args[1] == NULL)
+ {
+ fprintf_filtered (stream, "...");
+ }
+ else
+ {
+ for (i = 1;
+ args[i] != NULL && args[i]->code != TYPE_CODE_VOID;
+ i++)
+ {
+ c_print_type (args[i], "", stream, -1, 0);
+ if (args[i+1] == NULL)
+ {
+ fprintf_filtered (stream, "...");
+ }
+ else if (args[i+1]->code != TYPE_CODE_VOID)
+ {
+ fprintf_filtered (stream, ",");
+ wrap_here (" ");
+ }
+ }
+ }
+ }
+ fprintf_filtered (stream, ")");
+}
+
+/* Print any array sizes, function arguments or close parentheses
+ needed after the variable name (to describe its type).
+ Args work like c_type_print_varspec_prefix. */
+
+static void
+c_type_print_varspec_suffix (type, stream, show, passed_a_ptr, demangled_args)
+ struct type *type;
+ GDB_FILE *stream;
+ int show;
+ int passed_a_ptr;
+ int demangled_args;
+{
+ if (type == 0)
+ return;
+
+ if (TYPE_NAME (type) && show <= 0)
+ return;
+
+ QUIT;
+
+ switch (TYPE_CODE (type))
+ {
+ case TYPE_CODE_ARRAY:
+ if (passed_a_ptr)
+ fprintf_filtered (stream, ")");
+
+ fprintf_filtered (stream, "[");
+ if (TYPE_LENGTH (type) > 0 && TYPE_LENGTH (TYPE_TARGET_TYPE (type)) > 0)
+ fprintf_filtered (stream, "%d",
+ (TYPE_LENGTH (type)
+ / TYPE_LENGTH (TYPE_TARGET_TYPE (type))));
+ fprintf_filtered (stream, "]");
+
+ c_type_print_varspec_suffix (TYPE_TARGET_TYPE (type), stream, 0, 0, 0);
+ break;
+
+ case TYPE_CODE_MEMBER:
+ if (passed_a_ptr)
+ fprintf_filtered (stream, ")");
+ c_type_print_varspec_suffix (TYPE_TARGET_TYPE (type), stream, 0, 0, 0);
+ break;
+
+ case TYPE_CODE_METHOD:
+ if (passed_a_ptr)
+ fprintf_filtered (stream, ")");
+ c_type_print_varspec_suffix (TYPE_TARGET_TYPE (type), stream, 0, 0, 0);
+ if (passed_a_ptr)
+ {
+ c_type_print_args (type, stream);
+ }
+ break;
+
+ case TYPE_CODE_PTR:
+ case TYPE_CODE_REF:
+ c_type_print_varspec_suffix (TYPE_TARGET_TYPE (type), stream, 0, 1, 0);
+ break;
+
+ case TYPE_CODE_FUNC:
+ if (passed_a_ptr)
+ fprintf_filtered (stream, ")");
+ if (!demangled_args)
+ fprintf_filtered (stream, "()");
+ c_type_print_varspec_suffix (TYPE_TARGET_TYPE (type), stream, 0,
+ passed_a_ptr, 0);
+ break;
+
+ case TYPE_CODE_UNDEF:
+ case TYPE_CODE_STRUCT:
+ case TYPE_CODE_UNION:
+ case TYPE_CODE_ENUM:
+ case TYPE_CODE_INT:
+ case TYPE_CODE_FLT:
+ case TYPE_CODE_VOID:
+ case TYPE_CODE_ERROR:
+ case TYPE_CODE_CHAR:
+ case TYPE_CODE_BOOL:
+ case TYPE_CODE_SET:
+ case TYPE_CODE_RANGE:
+ case TYPE_CODE_STRING:
+ case TYPE_CODE_BITSTRING:
+ /* These types do not need a suffix. They are listed so that
+ gcc -Wall will report types that may not have been considered. */
+ break;
+ }
+}
+
+/* Print the name of the type (or the ultimate pointer target,
+ function value or array element), or the description of a
+ structure or union.
+
+ SHOW positive means print details about the type (e.g. enum values),
+ and print structure elements passing SHOW - 1 for show.
+ SHOW negative means just print the type name or struct tag if there is one.
+ If there is no name, print something sensible but concise like
+ "struct {...}".
+ SHOW zero means just print the type name or struct tag if there is one.
+ If there is no name, print something sensible but not as concise like
+ "struct {int x; int y;}".
+
+ LEVEL is the number of spaces to indent by.
+ We increase it for some recursive calls. */
+
+void
+c_type_print_base (type, stream, show, level)
+ struct type *type;
+ GDB_FILE *stream;
+ int show;
+ int level;
+{
+ register int i;
+ register int len;
+ register int lastval;
+ char *mangled_name;
+ char *demangled_name;
+ enum {s_none, s_public, s_private, s_protected} section_type;
+ QUIT;
+
+ wrap_here (" ");
+ if (type == NULL)
+ {
+ fputs_filtered ("<type unknown>", stream);
+ return;
+ }
+
+ /* When SHOW is zero or less, and there is a valid type name, then always
+ just print the type name directly from the type. */
+ /* If we have "typedef struct foo {. . .} bar;" do we want to print it
+ as "struct foo" or as "bar"? Pick the latter, because C++ folk tend
+ to expect things like "class5 *foo" rather than "struct class5 *foo". */
+
+ if (show <= 0
+ && TYPE_NAME (type) != NULL)
+ {
+ fputs_filtered (TYPE_NAME (type), stream);
+ return;
+ }
+
+ check_stub_type (type);
+
+ switch (TYPE_CODE (type))
+ {
+ case TYPE_CODE_ARRAY:
+ case TYPE_CODE_PTR:
+ case TYPE_CODE_MEMBER:
+ case TYPE_CODE_REF:
+ case TYPE_CODE_FUNC:
+ case TYPE_CODE_METHOD:
+ c_type_print_base (TYPE_TARGET_TYPE (type), stream, show, level);
+ break;
+
+ case TYPE_CODE_STRUCT:
+ if (HAVE_CPLUS_STRUCT (type))
+ {
+ fprintf_filtered (stream, "class ");
+ }
+ else
+ {
+ fprintf_filtered (stream, "struct ");
+ }
+ goto struct_union;
+
+ case TYPE_CODE_UNION:
+ fprintf_filtered (stream, "union ");
+
+ struct_union:
+ if (TYPE_TAG_NAME (type) != NULL)
+ {
+ fputs_filtered (TYPE_TAG_NAME (type), stream);
+ if (show > 0)
+ fputs_filtered (" ", stream);
+ }
+ wrap_here (" ");
+ if (show < 0)
+ {
+ /* If we just printed a tag name, no need to print anything else. */
+ if (TYPE_TAG_NAME (type) == NULL)
+ fprintf_filtered (stream, "{...}");
+ }
+ else if (show > 0 || TYPE_TAG_NAME (type) == NULL)
+ {
+ cp_type_print_derivation_info (stream, type);
+
+ fprintf_filtered (stream, "{\n");
+ if ((TYPE_NFIELDS (type) == 0) && (TYPE_NFN_FIELDS (type) == 0))
+ {
+ if (TYPE_FLAGS (type) & TYPE_FLAG_STUB)
+ fprintfi_filtered (level + 4, stream, "<incomplete type>\n");
+ else
+ fprintfi_filtered (level + 4, stream, "<no data fields>\n");
+ }
+
+ /* Start off with no specific section type, so we can print
+ one for the first field we find, and use that section type
+ thereafter until we find another type. */
+
+ section_type = s_none;
+
+ /* If there is a base class for this type,
+ do not print the field that it occupies. */
+
+ len = TYPE_NFIELDS (type);
+ for (i = TYPE_N_BASECLASSES (type); i < len; i++)
+ {
+ QUIT;
+ /* Don't print out virtual function table. */
+ if ((TYPE_FIELD_NAME (type, i))[5] == CPLUS_MARKER &&
+ !strncmp (TYPE_FIELD_NAME (type, i), "_vptr", 5))
+ continue;
+
+ /* If this is a C++ class we can print the various C++ section
+ labels. */
+
+ if (HAVE_CPLUS_STRUCT (type))
+ {
+ if (TYPE_FIELD_PROTECTED (type, i))
+ {
+ if (section_type != s_protected)
+ {
+ section_type = s_protected;
+ fprintfi_filtered (level + 2, stream,
+ "protected:\n");
+ }
+ }
+ else if (TYPE_FIELD_PRIVATE (type, i))
+ {
+ if (section_type != s_private)
+ {
+ section_type = s_private;
+ fprintfi_filtered (level + 2, stream, "private:\n");
+ }
+ }
+ else
+ {
+ if (section_type != s_public)
+ {
+ section_type = s_public;
+ fprintfi_filtered (level + 2, stream, "public:\n");
+ }
+ }
+ }
+
+ print_spaces_filtered (level + 4, stream);
+ if (TYPE_FIELD_STATIC (type, i))
+ {
+ fprintf_filtered (stream, "static ");
+ }
+ c_print_type (TYPE_FIELD_TYPE (type, i),
+ TYPE_FIELD_NAME (type, i),
+ stream, show - 1, level + 4);
+ if (!TYPE_FIELD_STATIC (type, i)
+ && TYPE_FIELD_PACKED (type, i))
+ {
+ /* It is a bitfield. This code does not attempt
+ to look at the bitpos and reconstruct filler,
+ unnamed fields. This would lead to misleading
+ results if the compiler does not put out fields
+ for such things (I don't know what it does). */
+ fprintf_filtered (stream, " : %d",
+ TYPE_FIELD_BITSIZE (type, i));
+ }
+ fprintf_filtered (stream, ";\n");
+ }
+
+ /* If there are both fields and methods, put a space between. */
+ len = TYPE_NFN_FIELDS (type);
+ if (len && section_type != s_none)
+ fprintf_filtered (stream, "\n");
+
+ /* C++: print out the methods */
+
+ for (i = 0; i < len; i++)
+ {
+ struct fn_field *f = TYPE_FN_FIELDLIST1 (type, i);
+ int j, len2 = TYPE_FN_FIELDLIST_LENGTH (type, i);
+ char *method_name = TYPE_FN_FIELDLIST_NAME (type, i);
+ char *name = type_name_no_tag (type);
+ int is_constructor = name && STREQ(method_name, name);
+ for (j = 0; j < len2; j++)
+ {
+ QUIT;
+ if (TYPE_FN_FIELD_PROTECTED (f, j))
+ {
+ if (section_type != s_protected)
+ {
+ section_type = s_protected;
+ fprintfi_filtered (level + 2, stream,
+ "protected:\n");
+ }
+ }
+ else if (TYPE_FN_FIELD_PRIVATE (f, j))
+ {
+ if (section_type != s_private)
+ {
+ section_type = s_private;
+ fprintfi_filtered (level + 2, stream, "private:\n");
+ }
+ }
+ else
+ {
+ if (section_type != s_public)
+ {
+ section_type = s_public;
+ fprintfi_filtered (level + 2, stream, "public:\n");
+ }
+ }
+
+ print_spaces_filtered (level + 4, stream);
+ if (TYPE_FN_FIELD_VIRTUAL_P (f, j))
+ fprintf_filtered (stream, "virtual ");
+ else if (TYPE_FN_FIELD_STATIC_P (f, j))
+ fprintf_filtered (stream, "static ");
+ if (TYPE_TARGET_TYPE (TYPE_FN_FIELD_TYPE (f, j)) == 0)
+ {
+ /* Keep GDB from crashing here. */
+ fprintf_unfiltered (stream, "<undefined type> %s;\n",
+ TYPE_FN_FIELD_PHYSNAME (f, j));
+ break;
+ }
+ else if (!is_constructor)
+ {
+ type_print (TYPE_TARGET_TYPE (TYPE_FN_FIELD_TYPE (f, j)),
+ "", stream, 0);
+ fputs_filtered (" ", stream);
+ }
+ if (TYPE_FN_FIELD_STUB (f, j))
+ {
+ /* Build something we can demangle. */
+ mangled_name = gdb_mangle_name (type, i, j);
+ demangled_name =
+ cplus_demangle (mangled_name,
+ DMGL_ANSI | DMGL_PARAMS);
+ if (demangled_name == NULL)
+ fprintf_filtered (stream, "<badly mangled name %s>",
+ mangled_name);
+ else
+ {
+ char *demangled_no_class =
+ strchr (demangled_name, ':');
+
+ if (demangled_no_class == NULL)
+ demangled_no_class = demangled_name;
+ else
+ {
+ if (*++demangled_no_class == ':')
+ ++demangled_no_class;
+ }
+ fputs_filtered (demangled_no_class, stream);
+ free (demangled_name);
+ }
+ free (mangled_name);
+ }
+ else if (TYPE_FN_FIELD_PHYSNAME (f, j)[0] == '_'
+ && TYPE_FN_FIELD_PHYSNAME (f, j)[1] == CPLUS_MARKER)
+ cp_type_print_method_args (TYPE_FN_FIELD_ARGS (f, j) + 1,
+ "~", method_name, 0, stream);
+ else
+ cp_type_print_method_args (TYPE_FN_FIELD_ARGS (f, j), "",
+ method_name,
+ TYPE_FN_FIELD_STATIC_P (f, j),
+ stream);
+
+ fprintf_filtered (stream, ";\n");
+ }
+ }
+
+ fprintfi_filtered (level, stream, "}");
+ }
+ break;
+
+ case TYPE_CODE_ENUM:
+ fprintf_filtered (stream, "enum ");
+ if (TYPE_TAG_NAME (type) != NULL)
+ {
+ fputs_filtered (TYPE_TAG_NAME (type), stream);
+ if (show > 0)
+ fputs_filtered (" ", stream);
+ }
+
+ wrap_here (" ");
+ if (show < 0)
+ {
+ /* If we just printed a tag name, no need to print anything else. */
+ if (TYPE_TAG_NAME (type) == NULL)
+ fprintf_filtered (stream, "{...}");
+ }
+ else if (show > 0 || TYPE_TAG_NAME (type) == NULL)
+ {
+ fprintf_filtered (stream, "{");
+ len = TYPE_NFIELDS (type);
+ lastval = 0;
+ for (i = 0; i < len; i++)
+ {
+ QUIT;
+ if (i) fprintf_filtered (stream, ", ");
+ wrap_here (" ");
+ fputs_filtered (TYPE_FIELD_NAME (type, i), stream);
+ if (lastval != TYPE_FIELD_BITPOS (type, i))
+ {
+ fprintf_filtered (stream, " = %d", TYPE_FIELD_BITPOS (type, i));
+ lastval = TYPE_FIELD_BITPOS (type, i);
+ }
+ lastval++;
+ }
+ fprintf_filtered (stream, "}");
+ }
+ break;
+
+ case TYPE_CODE_VOID:
+ fprintf_filtered (stream, "void");
+ break;
+
+ case TYPE_CODE_UNDEF:
+ fprintf_filtered (stream, "struct <unknown>");
+ break;
+
+ case TYPE_CODE_ERROR:
+ fprintf_filtered (stream, "<unknown type>");
+ break;
+
+ case TYPE_CODE_RANGE:
+ /* This should not occur */
+ fprintf_filtered (stream, "<range type>");
+ break;
+
+ default:
+ /* Handle types not explicitly handled by the other cases,
+ such as fundamental types. For these, just print whatever
+ the type name is, as recorded in the type itself. If there
+ is no type name, then complain. */
+ if (TYPE_NAME (type) != NULL)
+ {
+ fputs_filtered (TYPE_NAME (type), stream);
+ }
+ else
+ {
+ /* At least for dump_symtab, it is important that this not be
+ an error (). */
+ fprintf_filtered (stream, "<invalid type code %d>",
+ TYPE_CODE (type));
+ }
+ break;
+ }
+}
+
diff --git a/gnu/usr.bin/gdb/gdb/c-valprint.c b/gnu/usr.bin/gdb/gdb/c-valprint.c
new file mode 100644
index 0000000..3ba7e84
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/c-valprint.c
@@ -0,0 +1,513 @@
+/* Support for printing C values for GDB, the GNU debugger.
+ Copyright 1986, 1988, 1989, 1991, 1992, 1993, 1994
+ Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "defs.h"
+#include "symtab.h"
+#include "gdbtypes.h"
+#include "expression.h"
+#include "value.h"
+#include "demangle.h"
+#include "valprint.h"
+#include "language.h"
+
+/* BEGIN-FIXME */
+
+extern int vtblprint; /* Controls printing of vtbl's */
+
+extern void
+cp_print_class_member PARAMS ((char *, struct type *, GDB_FILE *, char *));
+
+extern void
+cp_print_class_method PARAMS ((char *, struct type *, GDB_FILE *));
+
+extern void
+cp_print_value_fields PARAMS ((struct type *, char *, GDB_FILE *, int, int,
+ enum val_prettyprint, struct type **));
+
+extern int
+cp_is_vtbl_ptr_type PARAMS ((struct type *));
+
+extern int
+cp_is_vtbl_member PARAMS ((struct type *));
+
+/* END-FIXME */
+
+
+/* BEGIN-FIXME: Hooks into c-typeprint.c */
+
+extern void
+c_type_print_varspec_prefix PARAMS ((struct type *, GDB_FILE *, int, int));
+
+extern void
+cp_type_print_method_args PARAMS ((struct type **, char *, char *, int,
+ GDB_FILE *));
+/* END-FIXME */
+
+
+extern struct obstack dont_print_obstack;
+
+
+/* Print data of type TYPE located at VALADDR (within GDB), which came from
+ the inferior at address ADDRESS, onto stdio stream STREAM according to
+ FORMAT (a letter or 0 for natural format). The data at VALADDR is in
+ target byte order.
+
+ If the data are a string pointer, returns the number of string characters
+ printed.
+
+ If DEREF_REF is nonzero, then dereference references, otherwise just print
+ them like pointers.
+
+ The PRETTY parameter controls prettyprinting. */
+
+int
+c_val_print (type, valaddr, address, stream, format, deref_ref, recurse,
+ pretty)
+ struct type *type;
+ char *valaddr;
+ CORE_ADDR address;
+ GDB_FILE *stream;
+ int format;
+ int deref_ref;
+ int recurse;
+ enum val_prettyprint pretty;
+{
+ register unsigned int i = 0; /* Number of characters printed */
+ unsigned len;
+ struct type *elttype;
+ unsigned eltlen;
+ LONGEST val;
+ CORE_ADDR addr;
+
+ switch (TYPE_CODE (type))
+ {
+ case TYPE_CODE_ARRAY:
+ if (TYPE_LENGTH (type) > 0 && TYPE_LENGTH (TYPE_TARGET_TYPE (type)) > 0)
+ {
+ elttype = TYPE_TARGET_TYPE (type);
+ eltlen = TYPE_LENGTH (elttype);
+ len = TYPE_LENGTH (type) / eltlen;
+ if (prettyprint_arrays)
+ {
+ print_spaces_filtered (2 + 2 * recurse, stream);
+ }
+ /* For an array of chars, print with string syntax. */
+ if (eltlen == 1 &&
+ ((TYPE_CODE (elttype) == TYPE_CODE_INT)
+ || ((current_language->la_language == language_m2)
+ && (TYPE_CODE (elttype) == TYPE_CODE_CHAR)))
+ && (format == 0 || format == 's'))
+ {
+ /* If requested, look for the first null char and only print
+ elements up to it. */
+ if (stop_print_at_null)
+ {
+ int temp_len;
+
+ /* Look for a NULL char. */
+ for (temp_len = 0;
+ valaddr[temp_len]
+ && temp_len < len && temp_len < print_max;
+ temp_len++);
+ len = temp_len;
+ }
+
+ LA_PRINT_STRING (stream, valaddr, len, 0);
+ i = len;
+ }
+ else
+ {
+ fprintf_filtered (stream, "{");
+ /* If this is a virtual function table, print the 0th
+ entry specially, and the rest of the members normally. */
+ if (cp_is_vtbl_ptr_type (elttype))
+ {
+ i = 1;
+ fprintf_filtered (stream, "%d vtable entries", len - 1);
+ }
+ else
+ {
+ i = 0;
+ }
+ val_print_array_elements (type, valaddr, address, stream,
+ format, deref_ref, recurse, pretty, i);
+ fprintf_filtered (stream, "}");
+ }
+ break;
+ }
+ /* Array of unspecified length: treat like pointer to first elt. */
+ addr = address;
+ goto print_unpacked_pointer;
+
+ case TYPE_CODE_PTR:
+ if (format && format != 's')
+ {
+ print_scalar_formatted (valaddr, type, format, 0, stream);
+ break;
+ }
+ if (vtblprint && cp_is_vtbl_ptr_type(type))
+ {
+ /* Print the unmangled name if desired. */
+ /* Print vtable entry - we only get here if we ARE using
+ -fvtable_thunks. (Otherwise, look under TYPE_CODE_STRUCT.) */
+ print_address_demangle(extract_address (valaddr, TYPE_LENGTH (type)),
+ stream, demangle);
+ break;
+ }
+ if (TYPE_CODE (TYPE_TARGET_TYPE (type)) == TYPE_CODE_METHOD)
+ {
+ cp_print_class_method (valaddr, type, stream);
+ }
+ else if (TYPE_CODE (TYPE_TARGET_TYPE (type)) == TYPE_CODE_MEMBER)
+ {
+ cp_print_class_member (valaddr,
+ TYPE_DOMAIN_TYPE (TYPE_TARGET_TYPE (type)),
+ stream, "&");
+ }
+ else
+ {
+ addr = unpack_pointer (type, valaddr);
+ print_unpacked_pointer:
+ elttype = TYPE_TARGET_TYPE (type);
+
+ if (TYPE_CODE (elttype) == TYPE_CODE_FUNC)
+ {
+ /* Try to print what function it points to. */
+ print_address_demangle (addr, stream, demangle);
+ /* Return value is irrelevant except for string pointers. */
+ return (0);
+ }
+
+ if (addressprint && format != 's')
+ {
+ print_address_numeric (addr, 1, stream);
+ }
+
+ /* For a pointer to char or unsigned char, also print the string
+ pointed to, unless pointer is null. */
+ if (TYPE_LENGTH (elttype) == 1
+ && TYPE_CODE (elttype) == TYPE_CODE_INT
+ && (format == 0 || format == 's')
+ && addr != 0)
+ {
+ i = val_print_string (addr, 0, stream);
+ }
+ else if (cp_is_vtbl_member(type))
+ {
+ /* print vtbl's nicely */
+ CORE_ADDR vt_address = unpack_pointer (type, valaddr);
+
+ struct minimal_symbol *msymbol =
+ lookup_minimal_symbol_by_pc (vt_address);
+ if ((msymbol != NULL) &&
+ (vt_address == SYMBOL_VALUE_ADDRESS (msymbol)))
+ {
+ fputs_filtered (" <", stream);
+ fputs_filtered (SYMBOL_SOURCE_NAME (msymbol), stream);
+ fputs_filtered (">", stream);
+ }
+ if (vt_address && vtblprint)
+ {
+ value_ptr vt_val;
+ struct symbol *wsym = (struct symbol *)NULL;
+ struct type *wtype;
+ struct symtab *s;
+ struct block *block = (struct block *)NULL;
+ int is_this_fld;
+
+ if (msymbol != NULL)
+ wsym = lookup_symbol (SYMBOL_NAME(msymbol), block,
+ VAR_NAMESPACE, &is_this_fld, &s);
+
+ if (wsym)
+ {
+ wtype = SYMBOL_TYPE(wsym);
+ }
+ else
+ {
+ wtype = TYPE_TARGET_TYPE(type);
+ }
+ vt_val = value_at (wtype, vt_address);
+ val_print (VALUE_TYPE (vt_val), VALUE_CONTENTS (vt_val),
+ VALUE_ADDRESS (vt_val), stream, format,
+ deref_ref, recurse + 1, pretty);
+ if (pretty)
+ {
+ fprintf_filtered (stream, "\n");
+ print_spaces_filtered (2 + 2 * recurse, stream);
+ }
+ }
+ }
+
+ /* Return number of characters printed, including the terminating
+ '\0' if we reached the end. val_print_string takes care including
+ the terminating '\0' if necessary. */
+ return i;
+ }
+ break;
+
+ case TYPE_CODE_MEMBER:
+ error ("not implemented: member type in c_val_print");
+ break;
+
+ case TYPE_CODE_REF:
+ if (TYPE_CODE (TYPE_TARGET_TYPE (type)) == TYPE_CODE_MEMBER)
+ {
+ cp_print_class_member (valaddr,
+ TYPE_DOMAIN_TYPE (TYPE_TARGET_TYPE (type)),
+ stream, "");
+ break;
+ }
+ if (addressprint)
+ {
+ fprintf_filtered (stream, "@");
+ print_address_numeric
+ (extract_address (valaddr,
+ TARGET_PTR_BIT / HOST_CHAR_BIT), 1, stream);
+ if (deref_ref)
+ fputs_filtered (": ", stream);
+ }
+ /* De-reference the reference. */
+ if (deref_ref)
+ {
+ if (TYPE_CODE (TYPE_TARGET_TYPE (type)) != TYPE_CODE_UNDEF)
+ {
+ value_ptr deref_val =
+ value_at
+ (TYPE_TARGET_TYPE (type),
+ unpack_pointer (lookup_pointer_type (builtin_type_void),
+ valaddr));
+ val_print (VALUE_TYPE (deref_val),
+ VALUE_CONTENTS (deref_val),
+ VALUE_ADDRESS (deref_val), stream, format,
+ deref_ref, recurse + 1, pretty);
+ }
+ else
+ fputs_filtered ("???", stream);
+ }
+ break;
+
+ case TYPE_CODE_UNION:
+ if (recurse && !unionprint)
+ {
+ fprintf_filtered (stream, "{...}");
+ break;
+ }
+ /* Fall through. */
+ case TYPE_CODE_STRUCT:
+ if (vtblprint && cp_is_vtbl_ptr_type(type))
+ {
+ /* Print the unmangled name if desired. */
+ /* Print vtable entry - we only get here if NOT using
+ -fvtable_thunks. (Otherwise, look under TYPE_CODE_PTR.) */
+ print_address_demangle(*((int *) (valaddr + /* FIXME bytesex */
+ TYPE_FIELD_BITPOS (type, VTBL_FNADDR_OFFSET) / 8)),
+ stream, demangle);
+ break;
+ }
+ cp_print_value_fields (type, valaddr, stream, format, recurse, pretty,
+ 0);
+ break;
+
+ case TYPE_CODE_ENUM:
+ if (format)
+ {
+ print_scalar_formatted (valaddr, type, format, 0, stream);
+ break;
+ }
+ len = TYPE_NFIELDS (type);
+ val = unpack_long (type, valaddr);
+ for (i = 0; i < len; i++)
+ {
+ QUIT;
+ if (val == TYPE_FIELD_BITPOS (type, i))
+ {
+ break;
+ }
+ }
+ if (i < len)
+ {
+ fputs_filtered (TYPE_FIELD_NAME (type, i), stream);
+ }
+ else
+ {
+ print_longest (stream, 'd', 0, val);
+ }
+ break;
+
+ case TYPE_CODE_FUNC:
+ if (format)
+ {
+ print_scalar_formatted (valaddr, type, format, 0, stream);
+ break;
+ }
+ /* FIXME, we should consider, at least for ANSI C language, eliminating
+ the distinction made between FUNCs and POINTERs to FUNCs. */
+ fprintf_filtered (stream, "{");
+ type_print (type, "", stream, -1);
+ fprintf_filtered (stream, "} ");
+ /* Try to print what function it points to, and its address. */
+ print_address_demangle (address, stream, demangle);
+ break;
+
+ case TYPE_CODE_BOOL:
+ /* Do something at least vaguely reasonable, for example if the
+ language is set wrong. */
+
+ case TYPE_CODE_RANGE:
+ /* FIXME: create_range_type does not set the unsigned bit in a
+ range type (I think it probably should copy it from the target
+ type), so we won't print values which are too large to
+ fit in a signed integer correctly. */
+ /* FIXME: Doesn't handle ranges of enums correctly. (Can't just
+ print with the target type, though, because the size of our type
+ and the target type might differ). */
+ /* FALLTHROUGH */
+
+ case TYPE_CODE_INT:
+ format = format ? format : output_format;
+ if (format)
+ {
+ print_scalar_formatted (valaddr, type, format, 0, stream);
+ }
+ else
+ {
+ val_print_type_code_int (type, valaddr, stream);
+ /* C and C++ has no single byte int type, char is used instead.
+ Since we don't know whether the value is really intended to
+ be used as an integer or a character, print the character
+ equivalent as well. */
+ if (TYPE_LENGTH (type) == 1)
+ {
+ fputs_filtered (" ", stream);
+ LA_PRINT_CHAR ((unsigned char) unpack_long (type, valaddr),
+ stream);
+ }
+ }
+ break;
+
+ case TYPE_CODE_CHAR:
+ format = format ? format : output_format;
+ if (format)
+ {
+ print_scalar_formatted (valaddr, type, format, 0, stream);
+ }
+ else
+ {
+ fprintf_filtered (stream, TYPE_UNSIGNED (type) ? "%u" : "%d",
+ unpack_long (type, valaddr));
+ fputs_filtered (" ", stream);
+ LA_PRINT_CHAR ((unsigned char) unpack_long (type, valaddr), stream);
+ }
+ break;
+
+ case TYPE_CODE_FLT:
+ if (format)
+ {
+ print_scalar_formatted (valaddr, type, format, 0, stream);
+ }
+ else
+ {
+ print_floating (valaddr, type, stream);
+ }
+ break;
+
+ case TYPE_CODE_VOID:
+ fprintf_filtered (stream, "void");
+ break;
+
+ case TYPE_CODE_ERROR:
+ fprintf_filtered (stream, "<error type>");
+ break;
+
+ case TYPE_CODE_UNDEF:
+ /* This happens (without TYPE_FLAG_STUB set) on systems which don't use
+ dbx xrefs (NO_DBX_XREFS in gcc) if a file has a "struct foo *bar"
+ and no complete type for struct foo in that file. */
+ fprintf_filtered (stream, "<incomplete type>");
+ break;
+
+ default:
+ error ("Invalid C/C++ type code %d in symbol table.", TYPE_CODE (type));
+ }
+ gdb_flush (stream);
+ return (0);
+}
+
+int
+c_value_print (val, stream, format, pretty)
+ value_ptr val;
+ GDB_FILE *stream;
+ int format;
+ enum val_prettyprint pretty;
+{
+ /* A "repeated" value really contains several values in a row.
+ They are made by the @ operator.
+ Print such values as if they were arrays. */
+
+ if (VALUE_REPEATED (val))
+ {
+ register unsigned int n = VALUE_REPETITIONS (val);
+ register unsigned int typelen = TYPE_LENGTH (VALUE_TYPE (val));
+ fprintf_filtered (stream, "{");
+ /* Print arrays of characters using string syntax. */
+ if (typelen == 1 && TYPE_CODE (VALUE_TYPE (val)) == TYPE_CODE_INT
+ && format == 0)
+ LA_PRINT_STRING (stream, VALUE_CONTENTS (val), n, 0);
+ else
+ {
+ value_print_array_elements (val, stream, format, pretty);
+ }
+ fprintf_filtered (stream, "}");
+ return (n * typelen);
+ }
+ else
+ {
+ struct type *type = VALUE_TYPE (val);
+
+ /* If it is a pointer, indicate what it points to.
+
+ Print type also if it is a reference.
+
+ C++: if it is a member pointer, we will take care
+ of that when we print it. */
+ if (TYPE_CODE (type) == TYPE_CODE_PTR ||
+ TYPE_CODE (type) == TYPE_CODE_REF)
+ {
+ /* Hack: remove (char *) for char strings. Their
+ type is indicated by the quoted string anyway. */
+ if (TYPE_CODE (type) == TYPE_CODE_PTR &&
+ TYPE_LENGTH (TYPE_TARGET_TYPE (type)) == sizeof(char) &&
+ TYPE_CODE (TYPE_TARGET_TYPE (type)) == TYPE_CODE_INT &&
+ !TYPE_UNSIGNED (TYPE_TARGET_TYPE (type)))
+ {
+ /* Print nothing */
+ }
+ else
+ {
+ fprintf_filtered (stream, "(");
+ type_print (type, "", stream, -1);
+ fprintf_filtered (stream, ") ");
+ }
+ }
+ return (val_print (type, VALUE_CONTENTS (val),
+ VALUE_ADDRESS (val), stream, format, 1, 0, pretty));
+ }
+}
diff --git a/gnu/usr.bin/gdb/gdb/call-cmds.h b/gnu/usr.bin/gdb/gdb/call-cmds.h
new file mode 100644
index 0000000..9030d84
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/call-cmds.h
@@ -0,0 +1,28 @@
+/* Prototypes for GDB commands that are called internally by other functions.
+ Copyright 1992 Free Software Foundation, Inc.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+extern void
+initialize_all_files PARAMS ((void));
+
+extern void
+exec_file_command PARAMS ((char *, int));
+
+extern void
+core_file_command PARAMS ((char *, int));
+
+extern void
+break_command PARAMS ((char *, int));
diff --git a/gnu/usr.bin/gdb/gdb/ch-exp.y b/gnu/usr.bin/gdb/gdb/ch-exp.y
new file mode 100644
index 0000000..b6370f3
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/ch-exp.y
@@ -0,0 +1,1997 @@
+/* YACC grammar for Chill expressions, for GDB.
+ Copyright 1992, 1993 Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* Parse a Chill expression from text in a string,
+ and return the result as a struct expression pointer.
+ That structure contains arithmetic operations in reverse polish,
+ with constants represented by operations that are followed by special data.
+ See expression.h for the details of the format.
+ What is important here is that it can be built up sequentially
+ during the process of parsing; the lower levels of the tree always
+ come first in the result.
+
+ Note that malloc's and realloc's in this file are transformed to
+ xmalloc and xrealloc respectively by the same sed command in the
+ makefile that remaps any other malloc/realloc inserted by the parser
+ generator. Doing this with #defines and trying to control the interaction
+ with include files (<malloc.h> and <stdlib.h> for example) just became
+ too messy, particularly when such includes can be inserted at random
+ times by the parser generator.
+
+ Also note that the language accepted by this parser is more liberal
+ than the one accepted by an actual Chill compiler. For example, the
+ language rule that a simple name string can not be one of the reserved
+ simple name strings is not enforced (e.g "case" is not treated as a
+ reserved name). Another example is that Chill is a strongly typed
+ language, and certain expressions that violate the type constraints
+ may still be evaluated if gdb can do so in a meaningful manner, while
+ such expressions would be rejected by the compiler. The reason for
+ this more liberal behavior is the philosophy that the debugger
+ is intended to be a tool that is used by the programmer when things
+ go wrong, and as such, it should provide as few artificial barriers
+ to it's use as possible. If it can do something meaningful, even
+ something that violates language contraints that are enforced by the
+ compiler, it should do so without complaint.
+
+ */
+
+%{
+
+#include "defs.h"
+#include <ctype.h>
+#include "expression.h"
+#include "language.h"
+#include "value.h"
+#include "parser-defs.h"
+#include "ch-lang.h"
+
+/* Remap normal yacc parser interface names (yyparse, yylex, yyerror, etc),
+ as well as gratuitiously global symbol names, so we can have multiple
+ yacc generated parsers in gdb. Note that these are only the variables
+ produced by yacc. If other parser generators (bison, byacc, etc) produce
+ additional global names that conflict at link time, then those parser
+ generators need to be fixed instead of adding those names to this list. */
+
+#define yymaxdepth chill_maxdepth
+#define yyparse chill_parse
+#define yylex chill_lex
+#define yyerror chill_error
+#define yylval chill_lval
+#define yychar chill_char
+#define yydebug chill_debug
+#define yypact chill_pact
+#define yyr1 chill_r1
+#define yyr2 chill_r2
+#define yydef chill_def
+#define yychk chill_chk
+#define yypgo chill_pgo
+#define yyact chill_act
+#define yyexca chill_exca
+#define yyerrflag chill_errflag
+#define yynerrs chill_nerrs
+#define yyps chill_ps
+#define yypv chill_pv
+#define yys chill_s
+#define yy_yys chill_yys
+#define yystate chill_state
+#define yytmp chill_tmp
+#define yyv chill_v
+#define yy_yyv chill_yyv
+#define yyval chill_val
+#define yylloc chill_lloc
+#define yyreds chill_reds /* With YYDEBUG defined */
+#define yytoks chill_toks /* With YYDEBUG defined */
+
+#ifndef YYDEBUG
+#define YYDEBUG 0 /* Default to no yydebug support */
+#endif
+
+int
+yyparse PARAMS ((void));
+
+static int
+yylex PARAMS ((void));
+
+void
+yyerror PARAMS ((char *));
+
+%}
+
+/* Although the yacc "value" of an expression is not used,
+ since the result is stored in the structure being created,
+ other node types do have values. */
+
+%union
+ {
+ LONGEST lval;
+ unsigned LONGEST ulval;
+ struct {
+ LONGEST val;
+ struct type *type;
+ } typed_val;
+ double dval;
+ struct symbol *sym;
+ struct type *tval;
+ struct stoken sval;
+ struct ttype tsym;
+ struct symtoken ssym;
+ int voidval;
+ struct block *bval;
+ enum exp_opcode opcode;
+ struct internalvar *ivar;
+
+ struct type **tvec;
+ int *ivec;
+ }
+
+%token <voidval> FIXME_01
+%token <voidval> FIXME_02
+%token <voidval> FIXME_03
+%token <voidval> FIXME_04
+%token <voidval> FIXME_05
+%token <voidval> FIXME_06
+%token <voidval> FIXME_07
+%token <voidval> FIXME_08
+%token <voidval> FIXME_09
+%token <voidval> FIXME_10
+%token <voidval> FIXME_11
+%token <voidval> FIXME_12
+%token <voidval> FIXME_13
+%token <voidval> FIXME_14
+%token <voidval> FIXME_15
+%token <voidval> FIXME_16
+%token <voidval> FIXME_17
+%token <voidval> FIXME_18
+%token <voidval> FIXME_19
+%token <voidval> FIXME_20
+%token <voidval> FIXME_21
+%token <voidval> FIXME_22
+%token <voidval> FIXME_24
+%token <voidval> FIXME_25
+%token <voidval> FIXME_26
+%token <voidval> FIXME_27
+%token <voidval> FIXME_28
+%token <voidval> FIXME_29
+%token <voidval> FIXME_30
+
+%token <typed_val> INTEGER_LITERAL
+%token <ulval> BOOLEAN_LITERAL
+%token <typed_val> CHARACTER_LITERAL
+%token <dval> FLOAT_LITERAL
+%token <ssym> GENERAL_PROCEDURE_NAME
+%token <ssym> LOCATION_NAME
+%token <voidval> SET_LITERAL
+%token <voidval> EMPTINESS_LITERAL
+%token <sval> CHARACTER_STRING_LITERAL
+%token <sval> BIT_STRING_LITERAL
+%token <tsym> TYPENAME
+%token <sval> FIELD_NAME
+
+%token <voidval> '.'
+%token <voidval> ';'
+%token <voidval> ':'
+%token <voidval> CASE
+%token <voidval> OF
+%token <voidval> ESAC
+%token <voidval> LOGIOR
+%token <voidval> ORIF
+%token <voidval> LOGXOR
+%token <voidval> LOGAND
+%token <voidval> ANDIF
+%token <voidval> '='
+%token <voidval> NOTEQUAL
+%token <voidval> '>'
+%token <voidval> GTR
+%token <voidval> '<'
+%token <voidval> LEQ
+%token <voidval> IN
+%token <voidval> '+'
+%token <voidval> '-'
+%token <voidval> '*'
+%token <voidval> '/'
+%token <voidval> SLASH_SLASH
+%token <voidval> MOD
+%token <voidval> REM
+%token <voidval> NOT
+%token <voidval> POINTER
+%token <voidval> RECEIVE
+%token <voidval> '['
+%token <voidval> ']'
+%token <voidval> '('
+%token <voidval> ')'
+%token <voidval> UP
+%token <voidval> IF
+%token <voidval> THEN
+%token <voidval> ELSE
+%token <voidval> FI
+%token <voidval> ELSIF
+%token <voidval> ILLEGAL_TOKEN
+%token <voidval> NUM
+%token <voidval> PRED
+%token <voidval> SUCC
+%token <voidval> ABS
+%token <voidval> CARD
+%token <voidval> MAX_TOKEN
+%token <voidval> MIN_TOKEN
+%token <voidval> SIZE
+%token <voidval> UPPER
+%token <voidval> LOWER
+%token <voidval> LENGTH
+
+/* Tokens which are not Chill tokens used in expressions, but rather GDB
+ specific things that we recognize in the same context as Chill tokens
+ (register names for example). */
+
+%token <lval> GDB_REGNAME /* Machine register name */
+%token <lval> GDB_LAST /* Value history */
+%token <ivar> GDB_VARIABLE /* Convenience variable */
+%token <voidval> GDB_ASSIGNMENT /* Assign value to somewhere */
+
+%type <voidval> location
+%type <voidval> access_name
+%type <voidval> primitive_value
+%type <voidval> location_contents
+%type <voidval> value_name
+%type <voidval> literal
+%type <voidval> tuple
+%type <voidval> value_string_element
+%type <voidval> value_string_slice
+%type <voidval> value_array_element
+%type <voidval> value_array_slice
+%type <voidval> value_structure_field
+%type <voidval> expression_conversion
+%type <voidval> value_procedure_call
+%type <voidval> value_built_in_routine_call
+%type <voidval> chill_value_built_in_routine_call
+%type <voidval> start_expression
+%type <voidval> zero_adic_operator
+%type <voidval> parenthesised_expression
+%type <voidval> value
+%type <voidval> undefined_value
+%type <voidval> expression
+%type <voidval> conditional_expression
+%type <voidval> then_alternative
+%type <voidval> else_alternative
+%type <voidval> sub_expression
+%type <voidval> value_case_alternative
+%type <voidval> operand_0
+%type <voidval> operand_1
+%type <voidval> operand_2
+%type <voidval> operand_3
+%type <voidval> operand_4
+%type <voidval> operand_5
+%type <voidval> operand_6
+%type <voidval> synonym_name
+%type <voidval> value_enumeration_name
+%type <voidval> value_do_with_name
+%type <voidval> value_receive_name
+%type <voidval> string_primitive_value
+%type <voidval> start_element
+%type <voidval> left_element
+%type <voidval> right_element
+%type <voidval> slice_size
+%type <voidval> array_primitive_value
+%type <voidval> expression_list
+%type <voidval> lower_element
+%type <voidval> upper_element
+%type <voidval> first_element
+%type <voidval> mode_argument
+%type <voidval> upper_lower_argument
+%type <voidval> length_argument
+%type <voidval> array_mode_name
+%type <voidval> string_mode_name
+%type <voidval> variant_structure_mode_name
+%type <voidval> boolean_expression
+%type <voidval> case_selector_list
+%type <voidval> subexpression
+%type <voidval> case_label_specification
+%type <voidval> buffer_location
+%type <voidval> single_assignment_action
+%type <tsym> mode_name
+
+%%
+
+/* Z.200, 5.3.1 */
+
+start : value { }
+ | mode_name
+ { write_exp_elt_opcode(OP_TYPE);
+ write_exp_elt_type($1.type);
+ write_exp_elt_opcode(OP_TYPE);}
+ ;
+
+value : expression
+ {
+ $$ = 0; /* FIXME */
+ }
+ | undefined_value
+ {
+ $$ = 0; /* FIXME */
+ }
+ ;
+
+undefined_value : FIXME_01
+ {
+ $$ = 0; /* FIXME */
+ }
+ ;
+
+/* Z.200, 4.2.1 */
+
+location : access_name
+ | primitive_value POINTER
+ {
+ write_exp_elt_opcode (UNOP_IND);
+ }
+ ;
+
+/* Z.200, 4.2.2 */
+
+access_name : LOCATION_NAME
+ {
+ write_exp_elt_opcode (OP_VAR_VALUE);
+ write_exp_elt_block (NULL);
+ write_exp_elt_sym ($1.sym);
+ write_exp_elt_opcode (OP_VAR_VALUE);
+ }
+ | GDB_LAST /* gdb specific */
+ {
+ write_exp_elt_opcode (OP_LAST);
+ write_exp_elt_longcst ($1);
+ write_exp_elt_opcode (OP_LAST);
+ }
+ | GDB_REGNAME /* gdb specific */
+ {
+ write_exp_elt_opcode (OP_REGISTER);
+ write_exp_elt_longcst ($1);
+ write_exp_elt_opcode (OP_REGISTER);
+ }
+ | GDB_VARIABLE /* gdb specific */
+ {
+ write_exp_elt_opcode (OP_INTERNALVAR);
+ write_exp_elt_intern ($1);
+ write_exp_elt_opcode (OP_INTERNALVAR);
+ }
+ | FIXME_03
+ {
+ $$ = 0; /* FIXME */
+ }
+ ;
+
+/* Z.200, 4.2.8 */
+
+expression_list : expression
+ {
+ arglist_len = 1;
+ }
+ | expression_list ',' expression
+ {
+ arglist_len++;
+ }
+
+/* Z.200, 5.2.1 */
+
+primitive_value : location_contents
+ {
+ $$ = 0; /* FIXME */
+ }
+ | value_name
+ {
+ $$ = 0; /* FIXME */
+ }
+ | literal
+ {
+ $$ = 0; /* FIXME */
+ }
+ | tuple
+ {
+ $$ = 0; /* FIXME */
+ }
+ | value_string_element
+ {
+ $$ = 0; /* FIXME */
+ }
+ | value_string_slice
+ {
+ $$ = 0; /* FIXME */
+ }
+ | value_array_element
+ {
+ $$ = 0; /* FIXME */
+ }
+ | value_array_slice
+ {
+ $$ = 0; /* FIXME */
+ }
+ | value_structure_field
+ {
+ $$ = 0; /* FIXME */
+ }
+ | expression_conversion
+ {
+ $$ = 0; /* FIXME */
+ }
+ | value_procedure_call
+ {
+ $$ = 0; /* FIXME */
+ }
+ | value_built_in_routine_call
+ {
+ $$ = 0; /* FIXME */
+ }
+ | start_expression
+ {
+ $$ = 0; /* FIXME */
+ }
+ | zero_adic_operator
+ {
+ $$ = 0; /* FIXME */
+ }
+ | parenthesised_expression
+ {
+ $$ = 0; /* FIXME */
+ }
+ ;
+
+/* Z.200, 5.2.2 */
+
+location_contents: location
+ {
+ $$ = 0; /* FIXME */
+ }
+ ;
+
+/* Z.200, 5.2.3 */
+
+value_name : synonym_name
+ {
+ $$ = 0; /* FIXME */
+ }
+ | value_enumeration_name
+ {
+ $$ = 0; /* FIXME */
+ }
+ | value_do_with_name
+ {
+ $$ = 0; /* FIXME */
+ }
+ | value_receive_name
+ {
+ $$ = 0; /* FIXME */
+ }
+ | GENERAL_PROCEDURE_NAME
+ {
+ write_exp_elt_opcode (OP_VAR_VALUE);
+ write_exp_elt_block (NULL);
+ write_exp_elt_sym ($1.sym);
+ write_exp_elt_opcode (OP_VAR_VALUE);
+ }
+ ;
+
+/* Z.200, 5.2.4.1 */
+
+literal : INTEGER_LITERAL
+ {
+ write_exp_elt_opcode (OP_LONG);
+ write_exp_elt_type ($1.type);
+ write_exp_elt_longcst ((LONGEST) ($1.val));
+ write_exp_elt_opcode (OP_LONG);
+ }
+ | BOOLEAN_LITERAL
+ {
+ write_exp_elt_opcode (OP_BOOL);
+ write_exp_elt_longcst ((LONGEST) $1);
+ write_exp_elt_opcode (OP_BOOL);
+ }
+ | CHARACTER_LITERAL
+ {
+ write_exp_elt_opcode (OP_LONG);
+ write_exp_elt_type ($1.type);
+ write_exp_elt_longcst ((LONGEST) ($1.val));
+ write_exp_elt_opcode (OP_LONG);
+ }
+ | FLOAT_LITERAL
+ {
+ write_exp_elt_opcode (OP_DOUBLE);
+ write_exp_elt_type (builtin_type_double);
+ write_exp_elt_dblcst ($1);
+ write_exp_elt_opcode (OP_DOUBLE);
+ }
+ | SET_LITERAL
+ {
+ $$ = 0; /* FIXME */
+ }
+ | EMPTINESS_LITERAL
+ {
+ $$ = 0; /* FIXME */
+ }
+ | CHARACTER_STRING_LITERAL
+ {
+ write_exp_elt_opcode (OP_STRING);
+ write_exp_string ($1);
+ write_exp_elt_opcode (OP_STRING);
+ }
+ | BIT_STRING_LITERAL
+ {
+ write_exp_elt_opcode (OP_BITSTRING);
+ write_exp_bitstring ($1);
+ write_exp_elt_opcode (OP_BITSTRING);
+ }
+ ;
+
+/* Z.200, 5.2.5 */
+
+tuple : FIXME_04
+ {
+ $$ = 0; /* FIXME */
+ }
+ ;
+
+
+/* Z.200, 5.2.6 */
+
+value_string_element: string_primitive_value '(' start_element ')'
+ {
+ $$ = 0; /* FIXME */
+ }
+ ;
+
+/* Z.200, 5.2.7 */
+
+value_string_slice: string_primitive_value '(' left_element ':' right_element ')'
+ {
+ $$ = 0; /* FIXME */
+ }
+ | string_primitive_value '(' start_element UP slice_size ')'
+ {
+ $$ = 0; /* FIXME */
+ }
+ ;
+
+/* Z.200, 5.2.8 */
+
+value_array_element: array_primitive_value '('
+ /* This is to save the value of arglist_len
+ being accumulated for each dimension. */
+ { start_arglist (); }
+ expression_list ')'
+ {
+ write_exp_elt_opcode (MULTI_SUBSCRIPT);
+ write_exp_elt_longcst ((LONGEST) end_arglist ());
+ write_exp_elt_opcode (MULTI_SUBSCRIPT);
+ }
+ ;
+
+/* Z.200, 5.2.9 */
+
+value_array_slice: array_primitive_value '(' lower_element ':' upper_element ')'
+ {
+ $$ = 0; /* FIXME */
+ }
+ | array_primitive_value '(' first_element UP slice_size ')'
+ {
+ $$ = 0; /* FIXME */
+ }
+ ;
+
+/* Z.200, 5.2.10 */
+
+value_structure_field: primitive_value FIELD_NAME
+ { write_exp_elt_opcode (STRUCTOP_STRUCT);
+ write_exp_string ($2);
+ write_exp_elt_opcode (STRUCTOP_STRUCT);
+ }
+ ;
+
+/* Z.200, 5.2.11 */
+
+expression_conversion: mode_name parenthesised_expression
+ {
+ write_exp_elt_opcode (UNOP_CAST);
+ write_exp_elt_type ($1.type);
+ write_exp_elt_opcode (UNOP_CAST);
+ }
+ ;
+
+/* Z.200, 5.2.12 */
+
+value_procedure_call: FIXME_05
+ {
+ $$ = 0; /* FIXME */
+ }
+ ;
+
+/* Z.200, 5.2.13 */
+
+value_built_in_routine_call: chill_value_built_in_routine_call
+ {
+ $$ = 0; /* FIXME */
+ }
+ ;
+
+/* Z.200, 5.2.14 */
+
+start_expression: FIXME_06
+ {
+ $$ = 0; /* FIXME */
+ } /* Not in GNU-Chill */
+ ;
+
+/* Z.200, 5.2.15 */
+
+zero_adic_operator: FIXME_07
+ {
+ $$ = 0; /* FIXME */
+ }
+ ;
+
+/* Z.200, 5.2.16 */
+
+parenthesised_expression: '(' expression ')'
+ {
+ $$ = 0; /* FIXME */
+ }
+ ;
+
+/* Z.200, 5.3.2 */
+
+expression : operand_0
+ {
+ $$ = 0; /* FIXME */
+ }
+ | single_assignment_action
+ {
+ $$ = 0; /* FIXME */
+ }
+ | conditional_expression
+ {
+ $$ = 0; /* FIXME */
+ }
+ ;
+
+conditional_expression : IF boolean_expression then_alternative else_alternative FI
+ {
+ $$ = 0; /* FIXME */
+ }
+ | CASE case_selector_list OF value_case_alternative '[' ELSE sub_expression ']' ESAC
+ {
+ $$ = 0; /* FIXME */
+ }
+ ;
+
+then_alternative: THEN subexpression
+ {
+ $$ = 0; /* FIXME */
+ }
+ ;
+
+else_alternative: ELSE subexpression
+ {
+ $$ = 0; /* FIXME */
+ }
+ | ELSIF boolean_expression then_alternative else_alternative
+ {
+ $$ = 0; /* FIXME */
+ }
+ ;
+
+sub_expression : expression
+ {
+ $$ = 0; /* FIXME */
+ }
+ ;
+
+value_case_alternative: case_label_specification ':' sub_expression ';'
+ {
+ $$ = 0; /* FIXME */
+ }
+ ;
+
+/* Z.200, 5.3.3 */
+
+operand_0 : operand_1
+ {
+ $$ = 0; /* FIXME */
+ }
+ | operand_0 LOGIOR operand_1
+ {
+ write_exp_elt_opcode (BINOP_BITWISE_IOR);
+ }
+ | operand_0 ORIF operand_1
+ {
+ $$ = 0; /* FIXME */
+ }
+ | operand_0 LOGXOR operand_1
+ {
+ write_exp_elt_opcode (BINOP_BITWISE_XOR);
+ }
+ ;
+
+/* Z.200, 5.3.4 */
+
+operand_1 : operand_2
+ {
+ $$ = 0; /* FIXME */
+ }
+ | operand_1 LOGAND operand_2
+ {
+ write_exp_elt_opcode (BINOP_BITWISE_AND);
+ }
+ | operand_1 ANDIF operand_2
+ {
+ $$ = 0; /* FIXME */
+ }
+ ;
+
+/* Z.200, 5.3.5 */
+
+operand_2 : operand_3
+ {
+ $$ = 0; /* FIXME */
+ }
+ | operand_2 '=' operand_3
+ {
+ write_exp_elt_opcode (BINOP_EQUAL);
+ }
+ | operand_2 NOTEQUAL operand_3
+ {
+ write_exp_elt_opcode (BINOP_NOTEQUAL);
+ }
+ | operand_2 '>' operand_3
+ {
+ write_exp_elt_opcode (BINOP_GTR);
+ }
+ | operand_2 GTR operand_3
+ {
+ write_exp_elt_opcode (BINOP_GEQ);
+ }
+ | operand_2 '<' operand_3
+ {
+ write_exp_elt_opcode (BINOP_LESS);
+ }
+ | operand_2 LEQ operand_3
+ {
+ write_exp_elt_opcode (BINOP_LEQ);
+ }
+ | operand_2 IN operand_3
+ {
+ $$ = 0; /* FIXME */
+ }
+ ;
+
+
+/* Z.200, 5.3.6 */
+
+operand_3 : operand_4
+ {
+ $$ = 0; /* FIXME */
+ }
+ | operand_3 '+' operand_4
+ {
+ write_exp_elt_opcode (BINOP_ADD);
+ }
+ | operand_3 '-' operand_4
+ {
+ write_exp_elt_opcode (BINOP_SUB);
+ }
+ | operand_3 SLASH_SLASH operand_4
+ {
+ write_exp_elt_opcode (BINOP_CONCAT);
+ }
+ ;
+
+/* Z.200, 5.3.7 */
+
+operand_4 : operand_5
+ {
+ $$ = 0; /* FIXME */
+ }
+ | operand_4 '*' operand_5
+ {
+ write_exp_elt_opcode (BINOP_MUL);
+ }
+ | operand_4 '/' operand_5
+ {
+ write_exp_elt_opcode (BINOP_DIV);
+ }
+ | operand_4 MOD operand_5
+ {
+ write_exp_elt_opcode (BINOP_MOD);
+ }
+ | operand_4 REM operand_5
+ {
+ write_exp_elt_opcode (BINOP_REM);
+ }
+ ;
+
+/* Z.200, 5.3.8 */
+
+operand_5 : operand_6
+ {
+ $$ = 0; /* FIXME */
+ }
+ | '-' operand_6
+ {
+ write_exp_elt_opcode (UNOP_NEG);
+ }
+ | NOT operand_6
+ {
+ write_exp_elt_opcode (UNOP_LOGICAL_NOT);
+ }
+ | parenthesised_expression literal
+/* We require the string operand to be a literal, to avoid some
+ nasty parsing ambiguities. */
+ {
+ write_exp_elt_opcode (BINOP_CONCAT);
+ }
+ ;
+
+/* Z.200, 5.3.9 */
+
+operand_6 : POINTER location
+ {
+ write_exp_elt_opcode (UNOP_ADDR);
+ }
+ | RECEIVE buffer_location
+ {
+ $$ = 0; /* FIXME */
+ }
+ | primitive_value
+ {
+ $$ = 0; /* FIXME */
+ }
+ ;
+
+
+/* Z.200, 6.2 */
+
+single_assignment_action :
+ location GDB_ASSIGNMENT value
+ {
+ write_exp_elt_opcode (BINOP_ASSIGN);
+ }
+ ;
+
+/* Z.200, 6.20.3 */
+
+chill_value_built_in_routine_call :
+ NUM '(' expression ')'
+ {
+ $$ = 0; /* FIXME */
+ }
+ | PRED '(' expression ')'
+ {
+ $$ = 0; /* FIXME */
+ }
+ | SUCC '(' expression ')'
+ {
+ $$ = 0; /* FIXME */
+ }
+ | ABS '(' expression ')'
+ {
+ $$ = 0; /* FIXME */
+ }
+ | CARD '(' expression ')'
+ {
+ $$ = 0; /* FIXME */
+ }
+ | MAX_TOKEN '(' expression ')'
+ {
+ $$ = 0; /* FIXME */
+ }
+ | MIN_TOKEN '(' expression ')'
+ {
+ $$ = 0; /* FIXME */
+ }
+ | SIZE '(' location ')'
+ {
+ $$ = 0; /* FIXME */
+ }
+ | SIZE '(' mode_argument ')'
+ {
+ $$ = 0; /* FIXME */
+ }
+ | UPPER '(' upper_lower_argument ')'
+ {
+ $$ = 0; /* FIXME */
+ }
+ | LOWER '(' upper_lower_argument ')'
+ {
+ $$ = 0; /* FIXME */
+ }
+ | LENGTH '(' length_argument ')'
+ {
+ $$ = 0; /* FIXME */
+ }
+ ;
+
+mode_argument : mode_name
+ {
+ $$ = 0; /* FIXME */
+ }
+ | array_mode_name '(' expression ')'
+ {
+ $$ = 0; /* FIXME */
+ }
+ | string_mode_name '(' expression ')'
+ {
+ $$ = 0; /* FIXME */
+ }
+ | variant_structure_mode_name '(' expression_list ')'
+ {
+ $$ = 0; /* FIXME */
+ }
+ ;
+
+mode_name : TYPENAME
+ ;
+
+upper_lower_argument : expression
+ {
+ $$ = 0; /* FIXME */
+ }
+ | mode_name
+ {
+ $$ = 0; /* FIXME */
+ }
+ ;
+
+length_argument : expression
+ {
+ $$ = 0; /* FIXME */
+ }
+ ;
+
+/* Z.200, 12.4.3 */
+
+array_primitive_value : primitive_value
+ {
+ $$ = 0;
+ }
+ ;
+
+
+/* Things which still need productions... */
+
+array_mode_name : FIXME_08 { $$ = 0; }
+string_mode_name : FIXME_09 { $$ = 0; }
+variant_structure_mode_name: FIXME_10 { $$ = 0; }
+synonym_name : FIXME_11 { $$ = 0; }
+value_enumeration_name : FIXME_12 { $$ = 0; }
+value_do_with_name : FIXME_13 { $$ = 0; }
+value_receive_name : FIXME_14 { $$ = 0; }
+string_primitive_value : FIXME_15 { $$ = 0; }
+start_element : FIXME_16 { $$ = 0; }
+left_element : FIXME_17 { $$ = 0; }
+right_element : FIXME_18 { $$ = 0; }
+slice_size : FIXME_19 { $$ = 0; }
+lower_element : FIXME_20 { $$ = 0; }
+upper_element : FIXME_21 { $$ = 0; }
+first_element : FIXME_22 { $$ = 0; }
+boolean_expression : FIXME_26 { $$ = 0; }
+case_selector_list : FIXME_27 { $$ = 0; }
+subexpression : FIXME_28 { $$ = 0; }
+case_label_specification: FIXME_29 { $$ = 0; }
+buffer_location : FIXME_30 { $$ = 0; }
+
+%%
+
+/* Implementation of a dynamically expandable buffer for processing input
+ characters acquired through lexptr and building a value to return in
+ yylval. */
+
+static char *tempbuf; /* Current buffer contents */
+static int tempbufsize; /* Size of allocated buffer */
+static int tempbufindex; /* Current index into buffer */
+
+#define GROWBY_MIN_SIZE 64 /* Minimum amount to grow buffer by */
+
+#define CHECKBUF(size) \
+ do { \
+ if (tempbufindex + (size) >= tempbufsize) \
+ { \
+ growbuf_by_size (size); \
+ } \
+ } while (0);
+
+/* Grow the static temp buffer if necessary, including allocating the first one
+ on demand. */
+
+static void
+growbuf_by_size (count)
+ int count;
+{
+ int growby;
+
+ growby = max (count, GROWBY_MIN_SIZE);
+ tempbufsize += growby;
+ if (tempbuf == NULL)
+ {
+ tempbuf = (char *) malloc (tempbufsize);
+ }
+ else
+ {
+ tempbuf = (char *) realloc (tempbuf, tempbufsize);
+ }
+}
+
+/* Try to consume a simple name string token. If successful, returns
+ a pointer to a nullbyte terminated copy of the name that can be used
+ in symbol table lookups. If not successful, returns NULL. */
+
+static char *
+match_simple_name_string ()
+{
+ char *tokptr = lexptr;
+
+ if (isalpha (*tokptr))
+ {
+ char *result;
+ do {
+ tokptr++;
+ } while (isalnum (*tokptr) || (*tokptr == '_'));
+ yylval.sval.ptr = lexptr;
+ yylval.sval.length = tokptr - lexptr;
+ lexptr = tokptr;
+ result = copy_name (yylval.sval);
+ for (tokptr = result; *tokptr; tokptr++)
+ if (isupper (*tokptr))
+ *tokptr = tolower(*tokptr);
+ return result;
+ }
+ return (NULL);
+}
+
+/* Start looking for a value composed of valid digits as set by the base
+ in use. Note that '_' characters are valid anywhere, in any quantity,
+ and are simply ignored. Since we must find at least one valid digit,
+ or reject this token as an integer literal, we keep track of how many
+ digits we have encountered. */
+
+static int
+decode_integer_value (base, tokptrptr, ivalptr)
+ int base;
+ char **tokptrptr;
+ int *ivalptr;
+{
+ char *tokptr = *tokptrptr;
+ int temp;
+ int digits = 0;
+
+ while (*tokptr != '\0')
+ {
+ temp = tolower (*tokptr);
+ tokptr++;
+ switch (temp)
+ {
+ case '_':
+ continue;
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ temp -= '0';
+ break;
+ case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
+ temp -= 'a';
+ temp += 10;
+ break;
+ default:
+ temp = base;
+ break;
+ }
+ if (temp < base)
+ {
+ digits++;
+ *ivalptr *= base;
+ *ivalptr += temp;
+ }
+ else
+ {
+ /* Found something not in domain for current base. */
+ tokptr--; /* Unconsume what gave us indigestion. */
+ break;
+ }
+ }
+
+ /* If we didn't find any digits, then we don't have a valid integer
+ value, so reject the entire token. Otherwise, update the lexical
+ scan pointer, and return non-zero for success. */
+
+ if (digits == 0)
+ {
+ return (0);
+ }
+ else
+ {
+ *tokptrptr = tokptr;
+ return (1);
+ }
+}
+
+static int
+decode_integer_literal (valptr, tokptrptr)
+ int *valptr;
+ char **tokptrptr;
+{
+ char *tokptr = *tokptrptr;
+ int base = 0;
+ int ival = 0;
+ int explicit_base = 0;
+
+ /* Look for an explicit base specifier, which is optional. */
+
+ switch (*tokptr)
+ {
+ case 'd':
+ case 'D':
+ explicit_base++;
+ base = 10;
+ tokptr++;
+ break;
+ case 'b':
+ case 'B':
+ explicit_base++;
+ base = 2;
+ tokptr++;
+ break;
+ case 'h':
+ case 'H':
+ explicit_base++;
+ base = 16;
+ tokptr++;
+ break;
+ case 'o':
+ case 'O':
+ explicit_base++;
+ base = 8;
+ tokptr++;
+ break;
+ default:
+ base = 10;
+ break;
+ }
+
+ /* If we found an explicit base ensure that the character after the
+ explicit base is a single quote. */
+
+ if (explicit_base && (*tokptr++ != '\''))
+ {
+ return (0);
+ }
+
+ /* Attempt to decode whatever follows as an integer value in the
+ indicated base, updating the token pointer in the process and
+ computing the value into ival. Also, if we have an explicit
+ base, then the next character must not be a single quote, or we
+ have a bitstring literal, so reject the entire token in this case.
+ Otherwise, update the lexical scan pointer, and return non-zero
+ for success. */
+
+ if (!decode_integer_value (base, &tokptr, &ival))
+ {
+ return (0);
+ }
+ else if (explicit_base && (*tokptr == '\''))
+ {
+ return (0);
+ }
+ else
+ {
+ *valptr = ival;
+ *tokptrptr = tokptr;
+ return (1);
+ }
+}
+
+/* If it wasn't for the fact that floating point values can contain '_'
+ characters, we could just let strtod do all the hard work by letting it
+ try to consume as much of the current token buffer as possible and
+ find a legal conversion. Unfortunately we need to filter out the '_'
+ characters before calling strtod, which we do by copying the other
+ legal chars to a local buffer to be converted. However since we also
+ need to keep track of where the last unconsumed character in the input
+ buffer is, we have transfer only as many characters as may compose a
+ legal floating point value. */
+
+static int
+match_float_literal ()
+{
+ char *tokptr = lexptr;
+ char *buf;
+ char *copy;
+ double dval;
+ extern double strtod ();
+
+ /* Make local buffer in which to build the string to convert. This is
+ required because underscores are valid in chill floating point numbers
+ but not in the string passed to strtod to convert. The string will be
+ no longer than our input string. */
+
+ copy = buf = (char *) alloca (strlen (tokptr) + 1);
+
+ /* Transfer all leading digits to the conversion buffer, discarding any
+ underscores. */
+
+ while (isdigit (*tokptr) || *tokptr == '_')
+ {
+ if (*tokptr != '_')
+ {
+ *copy++ = *tokptr;
+ }
+ tokptr++;
+ }
+
+ /* Now accept either a '.', or one of [eEdD]. Dot is legal regardless
+ of whether we found any leading digits, and we simply accept it and
+ continue on to look for the fractional part and/or exponent. One of
+ [eEdD] is legal only if we have seen digits, and means that there
+ is no fractional part. If we find neither of these, then this is
+ not a floating point number, so return failure. */
+
+ switch (*tokptr++)
+ {
+ case '.':
+ /* Accept and then look for fractional part and/or exponent. */
+ *copy++ = '.';
+ break;
+
+ case 'e':
+ case 'E':
+ case 'd':
+ case 'D':
+ if (copy == buf)
+ {
+ return (0);
+ }
+ *copy++ = 'e';
+ goto collect_exponent;
+ break;
+
+ default:
+ return (0);
+ break;
+ }
+
+ /* We found a '.', copy any fractional digits to the conversion buffer, up
+ to the first nondigit, non-underscore character. */
+
+ while (isdigit (*tokptr) || *tokptr == '_')
+ {
+ if (*tokptr != '_')
+ {
+ *copy++ = *tokptr;
+ }
+ tokptr++;
+ }
+
+ /* Look for an exponent, which must start with one of [eEdD]. If none
+ is found, jump directly to trying to convert what we have collected
+ so far. */
+
+ switch (*tokptr)
+ {
+ case 'e':
+ case 'E':
+ case 'd':
+ case 'D':
+ *copy++ = 'e';
+ tokptr++;
+ break;
+ default:
+ goto convert_float;
+ break;
+ }
+
+ /* Accept an optional '-' or '+' following one of [eEdD]. */
+
+ collect_exponent:
+ if (*tokptr == '+' || *tokptr == '-')
+ {
+ *copy++ = *tokptr++;
+ }
+
+ /* Now copy an exponent into the conversion buffer. Note that at the
+ moment underscores are *not* allowed in exponents. */
+
+ while (isdigit (*tokptr))
+ {
+ *copy++ = *tokptr++;
+ }
+
+ /* If we transfered any chars to the conversion buffer, try to interpret its
+ contents as a floating point value. If any characters remain, then we
+ must not have a valid floating point string. */
+
+ convert_float:
+ *copy = '\0';
+ if (copy != buf)
+ {
+ dval = strtod (buf, &copy);
+ if (*copy == '\0')
+ {
+ yylval.dval = dval;
+ lexptr = tokptr;
+ return (FLOAT_LITERAL);
+ }
+ }
+ return (0);
+}
+
+/* Recognize a string literal. A string literal is a nonzero sequence
+ of characters enclosed in matching single or double quotes, except that
+ a single character inside single quotes is a character literal, which
+ we reject as a string literal. To embed the terminator character inside
+ a string, it is simply doubled (I.E. "this""is""one""string") */
+
+static int
+match_string_literal ()
+{
+ char *tokptr = lexptr;
+
+ for (tempbufindex = 0, tokptr++; *tokptr != '\0'; tokptr++)
+ {
+ CHECKBUF (1);
+ if (*tokptr == *lexptr)
+ {
+ if (*(tokptr + 1) == *lexptr)
+ {
+ tokptr++;
+ }
+ else
+ {
+ break;
+ }
+ }
+ tempbuf[tempbufindex++] = *tokptr;
+ }
+ if (*tokptr == '\0' /* no terminator */
+ || tempbufindex == 0 /* no string */
+ || (tempbufindex == 1 && *tokptr == '\'')) /* char literal */
+ {
+ return (0);
+ }
+ else
+ {
+ tempbuf[tempbufindex] = '\0';
+ yylval.sval.ptr = tempbuf;
+ yylval.sval.length = tempbufindex;
+ lexptr = ++tokptr;
+ return (CHARACTER_STRING_LITERAL);
+ }
+}
+
+/* Recognize a character literal. A character literal is single character
+ or a control sequence, enclosed in single quotes. A control sequence
+ is a comma separated list of one or more integer literals, enclosed
+ in parenthesis and introduced with a circumflex character.
+
+ EX: 'a' '^(7)' '^(7,8)'
+
+ As a GNU chill extension, the syntax C'xx' is also recognized as a
+ character literal, where xx is a hex value for the character.
+
+ Note that more than a single character, enclosed in single quotes, is
+ a string literal.
+
+ Also note that the control sequence form is not in GNU Chill since it
+ is ambiguous with the string literal form using single quotes. I.E.
+ is '^(7)' a character literal or a string literal. In theory it it
+ possible to tell by context, but GNU Chill doesn't accept the control
+ sequence form, so neither do we (for now the code is disabled).
+
+ Returns CHARACTER_LITERAL if a match is found.
+ */
+
+static int
+match_character_literal ()
+{
+ char *tokptr = lexptr;
+ int ival = 0;
+
+ if ((tolower (*tokptr) == 'c') && (*(tokptr + 1) == '\''))
+ {
+ /* We have a GNU chill extension form, so skip the leading "C'",
+ decode the hex value, and then ensure that we have a trailing
+ single quote character. */
+ tokptr += 2;
+ if (!decode_integer_value (16, &tokptr, &ival) || (*tokptr != '\''))
+ {
+ return (0);
+ }
+ tokptr++;
+ }
+ else if (*tokptr == '\'')
+ {
+ tokptr++;
+
+ /* Determine which form we have, either a control sequence or the
+ single character form. */
+
+ if ((*tokptr == '^') && (*(tokptr + 1) == '('))
+ {
+#if 0 /* Disable, see note above. -fnf */
+ /* Match and decode a control sequence. Return zero if we don't
+ find a valid integer literal, or if the next unconsumed character
+ after the integer literal is not the trailing ')'.
+ FIXME: We currently don't handle the multiple integer literal
+ form. */
+ tokptr += 2;
+ if (!decode_integer_literal (&ival, &tokptr) || (*tokptr++ != ')'))
+ {
+ return (0);
+ }
+#else
+ return (0);
+#endif
+ }
+ else
+ {
+ ival = *tokptr++;
+ }
+
+ /* The trailing quote has not yet been consumed. If we don't find
+ it, then we have no match. */
+
+ if (*tokptr++ != '\'')
+ {
+ return (0);
+ }
+ }
+ else
+ {
+ /* Not a character literal. */
+ return (0);
+ }
+ yylval.typed_val.val = ival;
+ yylval.typed_val.type = builtin_type_chill_char;
+ lexptr = tokptr;
+ return (CHARACTER_LITERAL);
+}
+
+/* Recognize an integer literal, as specified in Z.200 sec 5.2.4.2.
+ Note that according to 5.2.4.2, a single "_" is also a valid integer
+ literal, however GNU-chill requires there to be at least one "digit"
+ in any integer literal. */
+
+static int
+match_integer_literal ()
+{
+ char *tokptr = lexptr;
+ int ival;
+
+ if (!decode_integer_literal (&ival, &tokptr))
+ {
+ return (0);
+ }
+ else
+ {
+ yylval.typed_val.val = ival;
+ yylval.typed_val.type = builtin_type_int;
+ lexptr = tokptr;
+ return (INTEGER_LITERAL);
+ }
+}
+
+/* Recognize a bit-string literal, as specified in Z.200 sec 5.2.4.8
+ Note that according to 5.2.4.8, a single "_" is also a valid bit-string
+ literal, however GNU-chill requires there to be at least one "digit"
+ in any bit-string literal. */
+
+static int
+match_bitstring_literal ()
+{
+ char *tokptr = lexptr;
+ int mask;
+ int bitoffset = 0;
+ int bitcount = 0;
+ int base;
+ int digit;
+
+ tempbufindex = 0;
+
+ /* Look for the required explicit base specifier. */
+
+ switch (*tokptr++)
+ {
+ case 'b':
+ case 'B':
+ base = 2;
+ break;
+ case 'o':
+ case 'O':
+ base = 8;
+ break;
+ case 'h':
+ case 'H':
+ base = 16;
+ break;
+ default:
+ return (0);
+ break;
+ }
+
+ /* Ensure that the character after the explicit base is a single quote. */
+
+ if (*tokptr++ != '\'')
+ {
+ return (0);
+ }
+
+ while (*tokptr != '\0' && *tokptr != '\'')
+ {
+ digit = tolower (*tokptr);
+ tokptr++;
+ switch (digit)
+ {
+ case '_':
+ continue;
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ digit -= '0';
+ break;
+ case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
+ digit -= 'a';
+ digit += 10;
+ break;
+ default:
+ return (0);
+ break;
+ }
+ if (digit >= base)
+ {
+ /* Found something not in domain for current base. */
+ return (0);
+ }
+ else
+ {
+ /* Extract bits from digit, starting with the msbit appropriate for
+ the current base, and packing them into the bitstring byte,
+ starting at the lsbit. */
+ for (mask = (base >> 1); mask > 0; mask >>= 1)
+ {
+ bitcount++;
+ CHECKBUF (1);
+ if (digit & mask)
+ {
+ tempbuf[tempbufindex] |= (1 << bitoffset);
+ }
+ bitoffset++;
+ if (bitoffset == HOST_CHAR_BIT)
+ {
+ bitoffset = 0;
+ tempbufindex++;
+ }
+ }
+ }
+ }
+
+ /* Verify that we consumed everything up to the trailing single quote,
+ and that we found some bits (IE not just underbars). */
+
+ if (*tokptr++ != '\'')
+ {
+ return (0);
+ }
+ else
+ {
+ yylval.sval.ptr = tempbuf;
+ yylval.sval.length = bitcount;
+ lexptr = tokptr;
+ return (BIT_STRING_LITERAL);
+ }
+}
+
+/* Recognize tokens that start with '$'. These include:
+
+ $regname A native register name or a "standard
+ register name".
+ Return token GDB_REGNAME.
+
+ $variable A convenience variable with a name chosen
+ by the user.
+ Return token GDB_VARIABLE.
+
+ $digits Value history with index <digits>, starting
+ from the first value which has index 1.
+ Return GDB_LAST.
+
+ $$digits Value history with index <digits> relative
+ to the last value. I.E. $$0 is the last
+ value, $$1 is the one previous to that, $$2
+ is the one previous to $$1, etc.
+ Return token GDB_LAST.
+
+ $ | $0 | $$0 The last value in the value history.
+ Return token GDB_LAST.
+
+ $$ An abbreviation for the second to the last
+ value in the value history, I.E. $$1
+ Return token GDB_LAST.
+
+ Note that we currently assume that register names and convenience
+ variables follow the convention of starting with a letter or '_'.
+
+ */
+
+static int
+match_dollar_tokens ()
+{
+ char *tokptr;
+ int regno;
+ int namelength;
+ int negate;
+ int ival;
+
+ /* We will always have a successful match, even if it is just for
+ a single '$', the abbreviation for $$0. So advance lexptr. */
+
+ tokptr = ++lexptr;
+
+ if (*tokptr == '_' || isalpha (*tokptr))
+ {
+ /* Look for a match with a native register name, usually something
+ like "r0" for example. */
+
+ for (regno = 0; regno < NUM_REGS; regno++)
+ {
+ namelength = strlen (reg_names[regno]);
+ if (STREQN (tokptr, reg_names[regno], namelength)
+ && !isalnum (tokptr[namelength]))
+ {
+ yylval.lval = regno;
+ lexptr += namelength + 1;
+ return (GDB_REGNAME);
+ }
+ }
+
+ /* Look for a match with a standard register name, usually something
+ like "pc", which gdb always recognizes as the program counter
+ regardless of what the native register name is. */
+
+ for (regno = 0; regno < num_std_regs; regno++)
+ {
+ namelength = strlen (std_regs[regno].name);
+ if (STREQN (tokptr, std_regs[regno].name, namelength)
+ && !isalnum (tokptr[namelength]))
+ {
+ yylval.lval = std_regs[regno].regnum;
+ lexptr += namelength;
+ return (GDB_REGNAME);
+ }
+ }
+
+ /* Attempt to match against a convenience variable. Note that
+ this will always succeed, because if no variable of that name
+ already exists, the lookup_internalvar will create one for us.
+ Also note that both lexptr and tokptr currently point to the
+ start of the input string we are trying to match, and that we
+ have already tested the first character for non-numeric, so we
+ don't have to treat it specially. */
+
+ while (*tokptr == '_' || isalnum (*tokptr))
+ {
+ tokptr++;
+ }
+ yylval.sval.ptr = lexptr;
+ yylval.sval.length = tokptr - lexptr;
+ yylval.ivar = lookup_internalvar (copy_name (yylval.sval));
+ lexptr = tokptr;
+ return (GDB_VARIABLE);
+ }
+
+ /* Since we didn't match against a register name or convenience
+ variable, our only choice left is a history value. */
+
+ if (*tokptr == '$')
+ {
+ negate = 1;
+ ival = 1;
+ tokptr++;
+ }
+ else
+ {
+ negate = 0;
+ ival = 0;
+ }
+
+ /* Attempt to decode more characters as an integer value giving
+ the index in the history list. If successful, the value will
+ overwrite ival (currently 0 or 1), and if not, ival will be
+ left alone, which is good since it is currently correct for
+ the '$' or '$$' case. */
+
+ decode_integer_literal (&ival, &tokptr);
+ yylval.lval = negate ? -ival : ival;
+ lexptr = tokptr;
+ return (GDB_LAST);
+}
+
+struct token
+{
+ char *operator;
+ int token;
+};
+
+static const struct token idtokentab[] =
+{
+ { "length", LENGTH },
+ { "lower", LOWER },
+ { "upper", UPPER },
+ { "andif", ANDIF },
+ { "pred", PRED },
+ { "succ", SUCC },
+ { "card", CARD },
+ { "size", SIZE },
+ { "orif", ORIF },
+ { "num", NUM },
+ { "abs", ABS },
+ { "max", MAX_TOKEN },
+ { "min", MIN_TOKEN },
+ { "mod", MOD },
+ { "rem", REM },
+ { "not", NOT },
+ { "xor", LOGXOR },
+ { "and", LOGAND },
+ { "in", IN },
+ { "or", LOGIOR }
+};
+
+static const struct token tokentab2[] =
+{
+ { ":=", GDB_ASSIGNMENT },
+ { "//", SLASH_SLASH },
+ { "->", POINTER },
+ { "/=", NOTEQUAL },
+ { "<=", LEQ },
+ { ">=", GTR }
+};
+
+/* Read one token, getting characters through lexptr. */
+/* This is where we will check to make sure that the language and the
+ operators used are compatible. */
+
+static int
+yylex ()
+{
+ unsigned int i;
+ int token;
+ char *simplename;
+ struct symbol *sym;
+
+ /* Skip over any leading whitespace. */
+ while (isspace (*lexptr))
+ {
+ lexptr++;
+ }
+ /* Look for special single character cases which can't be the first
+ character of some other multicharacter token. */
+ switch (*lexptr)
+ {
+ case '\0':
+ return (0);
+ case ',':
+ case '=':
+ case ';':
+ case '!':
+ case '+':
+ case '*':
+ case '(':
+ case ')':
+ case '[':
+ case ']':
+ return (*lexptr++);
+ }
+ /* Look for characters which start a particular kind of multicharacter
+ token, such as a character literal, register name, convenience
+ variable name, string literal, etc. */
+ switch (*lexptr)
+ {
+ case '\'':
+ case '\"':
+ /* First try to match a string literal, which is any nonzero
+ sequence of characters enclosed in matching single or double
+ quotes, except that a single character inside single quotes
+ is a character literal, so we have to catch that case also. */
+ token = match_string_literal ();
+ if (token != 0)
+ {
+ return (token);
+ }
+ if (*lexptr == '\'')
+ {
+ token = match_character_literal ();
+ if (token != 0)
+ {
+ return (token);
+ }
+ }
+ break;
+ case 'C':
+ case 'c':
+ token = match_character_literal ();
+ if (token != 0)
+ {
+ return (token);
+ }
+ break;
+ case '$':
+ token = match_dollar_tokens ();
+ if (token != 0)
+ {
+ return (token);
+ }
+ break;
+ }
+ /* See if it is a special token of length 2. */
+ for (i = 0; i < sizeof (tokentab2) / sizeof (tokentab2[0]); i++)
+ {
+ if (STREQN (lexptr, tokentab2[i].operator, 2))
+ {
+ lexptr += 2;
+ return (tokentab2[i].token);
+ }
+ }
+ /* Look for single character cases which which could be the first
+ character of some other multicharacter token, but aren't, or we
+ would already have found it. */
+ switch (*lexptr)
+ {
+ case '-':
+ case ':':
+ case '/':
+ case '<':
+ case '>':
+ return (*lexptr++);
+ }
+ /* Look for a float literal before looking for an integer literal, so
+ we match as much of the input stream as possible. */
+ token = match_float_literal ();
+ if (token != 0)
+ {
+ return (token);
+ }
+ token = match_bitstring_literal ();
+ if (token != 0)
+ {
+ return (token);
+ }
+ token = match_integer_literal ();
+ if (token != 0)
+ {
+ return (token);
+ }
+
+ /* Try to match a simple name string, and if a match is found, then
+ further classify what sort of name it is and return an appropriate
+ token. Note that attempting to match a simple name string consumes
+ the token from lexptr, so we can't back out if we later find that
+ we can't classify what sort of name it is. */
+
+ simplename = match_simple_name_string ();
+
+ if (simplename != NULL)
+ {
+ /* See if it is a reserved identifier. */
+ for (i = 0; i < sizeof (idtokentab) / sizeof (idtokentab[0]); i++)
+ {
+ if (STREQ (simplename, idtokentab[i].operator))
+ {
+ return (idtokentab[i].token);
+ }
+ }
+
+ /* Look for other special tokens. */
+ if (STREQ (simplename, "true"))
+ {
+ yylval.ulval = 1;
+ return (BOOLEAN_LITERAL);
+ }
+ if (STREQ (simplename, "false"))
+ {
+ yylval.ulval = 0;
+ return (BOOLEAN_LITERAL);
+ }
+
+ sym = lookup_symbol (simplename, expression_context_block,
+ VAR_NAMESPACE, (int *) NULL,
+ (struct symtab **) NULL);
+ if (sym != NULL)
+ {
+ yylval.ssym.stoken.ptr = NULL;
+ yylval.ssym.stoken.length = 0;
+ yylval.ssym.sym = sym;
+ yylval.ssym.is_a_field_of_this = 0; /* FIXME, C++'ism */
+ switch (SYMBOL_CLASS (sym))
+ {
+ case LOC_BLOCK:
+ /* Found a procedure name. */
+ return (GENERAL_PROCEDURE_NAME);
+ case LOC_STATIC:
+ /* Found a global or local static variable. */
+ return (LOCATION_NAME);
+ case LOC_REGISTER:
+ case LOC_ARG:
+ case LOC_REF_ARG:
+ case LOC_REGPARM:
+ case LOC_REGPARM_ADDR:
+ case LOC_LOCAL:
+ case LOC_LOCAL_ARG:
+ case LOC_BASEREG:
+ case LOC_BASEREG_ARG:
+ if (innermost_block == NULL
+ || contained_in (block_found, innermost_block))
+ {
+ innermost_block = block_found;
+ }
+ return (LOCATION_NAME);
+ break;
+ case LOC_CONST:
+ case LOC_LABEL:
+ return (LOCATION_NAME);
+ break;
+ case LOC_TYPEDEF:
+ yylval.tsym.type = SYMBOL_TYPE (sym);
+ return TYPENAME;
+ case LOC_UNDEF:
+ case LOC_CONST_BYTES:
+ case LOC_OPTIMIZED_OUT:
+ error ("Symbol \"%s\" names no location.", simplename);
+ break;
+ }
+ }
+ else if (!have_full_symbols () && !have_partial_symbols ())
+ {
+ error ("No symbol table is loaded. Use the \"file\" command.");
+ }
+ else
+ {
+ error ("No symbol \"%s\" in current context.", simplename);
+ }
+ }
+
+ /* Catch single character tokens which are not part of some
+ longer token. */
+
+ switch (*lexptr)
+ {
+ case '.': /* Not float for example. */
+ lexptr++;
+ while (isspace (*lexptr)) lexptr++;
+ simplename = match_simple_name_string ();
+ if (!simplename)
+ return '.';
+ return FIELD_NAME;
+ }
+
+ return (ILLEGAL_TOKEN);
+}
+
+void
+yyerror (msg)
+ char *msg; /* unused */
+{
+ printf ("Parsing: %s\n", lexptr);
+ if (yychar < 256)
+ {
+ error ("Invalid syntax in expression near character '%c'.", yychar);
+ }
+ else
+ {
+ error ("Invalid syntax in expression");
+ }
+}
diff --git a/gnu/usr.bin/gdb/gdb/ch-lang.c b/gnu/usr.bin/gdb/gdb/ch-lang.c
new file mode 100644
index 0000000..1ffb8d7
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/ch-lang.c
@@ -0,0 +1,355 @@
+/* Chill language support routines for GDB, the GNU debugger.
+ Copyright 1992 Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "defs.h"
+#include "symtab.h"
+#include "gdbtypes.h"
+#include "expression.h"
+#include "parser-defs.h"
+#include "language.h"
+#include "ch-lang.h"
+
+
+/* For now, Chill uses a simple mangling algorithm whereby you simply
+ discard everything after the occurance of two successive CPLUS_MARKER
+ characters to derive the demangled form. */
+
+char *
+chill_demangle (mangled)
+ const char *mangled;
+{
+ char *joiner;
+ char *demangled;
+
+ joiner = strchr (mangled, CPLUS_MARKER);
+ if (joiner != NULL && *(joiner + 1) == CPLUS_MARKER)
+ {
+ demangled = savestring (mangled, joiner - mangled);
+ }
+ else
+ {
+ demangled = NULL;
+ }
+ return (demangled);
+}
+
+static void
+chill_printchar (c, stream)
+ register int c;
+ GDB_FILE *stream;
+{
+ c &= 0xFF; /* Avoid sign bit follies */
+
+ if (PRINT_LITERAL_FORM (c))
+ {
+ fprintf_filtered (stream, "'%c'", c);
+ }
+ else
+ {
+ fprintf_filtered (stream, "C'%.2x'", (unsigned int) c);
+ }
+}
+
+/* Print the character string STRING, printing at most LENGTH characters.
+ Printing stops early if the number hits print_max; repeat counts
+ are printed as appropriate. Print ellipses at the end if we
+ had to stop before printing LENGTH characters, or if FORCE_ELLIPSES.
+ Note that gdb maintains the length of strings without counting the
+ terminating null byte, while chill strings are typically written with
+ an explicit null byte. So we always assume an implied null byte
+ until gdb is able to maintain non-null terminated strings as well
+ as null terminated strings (FIXME).
+ */
+
+static void
+chill_printstr (stream, string, length, force_ellipses)
+ GDB_FILE *stream;
+ char *string;
+ unsigned int length;
+ int force_ellipses;
+{
+ register unsigned int i;
+ unsigned int things_printed = 0;
+ int in_literal_form = 0;
+ int in_control_form = 0;
+ int need_slashslash = 0;
+ unsigned int c;
+ extern int repeat_count_threshold;
+ extern int print_max;
+
+ if (length == 0)
+ {
+ fputs_filtered ("\"\"", stream);
+ return;
+ }
+
+ for (i = 0; i < length && things_printed < print_max; ++i)
+ {
+ /* Position of the character we are examining
+ to see whether it is repeated. */
+ unsigned int rep1;
+ /* Number of repetitions we have detected so far. */
+ unsigned int reps;
+
+ QUIT;
+
+ if (need_slashslash)
+ {
+ fputs_filtered ("//", stream);
+ need_slashslash = 0;
+ }
+
+ rep1 = i + 1;
+ reps = 1;
+ while (rep1 < length && string[rep1] == string[i])
+ {
+ ++rep1;
+ ++reps;
+ }
+
+ c = string[i];
+ if (reps > repeat_count_threshold)
+ {
+ if (in_control_form || in_literal_form)
+ {
+ fputs_filtered ("\"//", stream);
+ in_control_form = in_literal_form = 0;
+ }
+ chill_printchar (c, stream);
+ fprintf_filtered (stream, "<repeats %u times>", reps);
+ i = rep1 - 1;
+ things_printed += repeat_count_threshold;
+ need_slashslash = 1;
+ }
+ else
+ {
+ if (PRINT_LITERAL_FORM (c))
+ {
+ if (!in_literal_form)
+ {
+ if (in_control_form)
+ {
+ fputs_filtered ("\"//", stream);
+ in_control_form = 0;
+ }
+ fputs_filtered ("\"", stream);
+ in_literal_form = 1;
+ }
+ fprintf_filtered (stream, "%c", c);
+ }
+ else
+ {
+ if (!in_control_form)
+ {
+ if (in_literal_form)
+ {
+ fputs_filtered ("\"//", stream);
+ in_literal_form = 0;
+ }
+ fputs_filtered ("c\"", stream);
+ in_control_form = 1;
+ }
+ fprintf_filtered (stream, "%.2x", c);
+ }
+ ++things_printed;
+ }
+ }
+
+ /* Terminate the quotes if necessary. */
+ if (in_literal_form || in_control_form)
+ {
+ fputs_filtered ("\"", stream);
+ }
+ if (force_ellipses || (i < length))
+ {
+ fputs_filtered ("...", stream);
+ }
+}
+
+/* Return 1 if TYPE is a varying string or array. */
+
+int
+chill_is_varying_struct (type)
+ struct type *type;
+{
+ if (TYPE_CODE (type) != TYPE_CODE_STRUCT)
+ return 0;
+ if (TYPE_NFIELDS (type) != 2)
+ return 0;
+ if (strcmp (TYPE_FIELD_NAME (type, 0), "__var_length") != 0)
+ return 0;
+ return 1;
+}
+
+static struct type *
+chill_create_fundamental_type (objfile, typeid)
+ struct objfile *objfile;
+ int typeid;
+{
+ register struct type *type = NULL;
+
+ switch (typeid)
+ {
+ default:
+ /* FIXME: For now, if we are asked to produce a type not in this
+ language, create the equivalent of a C integer type with the
+ name "<?type?>". When all the dust settles from the type
+ reconstruction work, this should probably become an error. */
+ type = init_type (TYPE_CODE_INT, 2, 0, "<?type?>", objfile);
+ warning ("internal error: no chill fundamental type %d", typeid);
+ break;
+ case FT_VOID:
+ /* FIXME: Currently the GNU Chill compiler emits some DWARF entries for
+ typedefs, unrelated to anything directly in the code being compiled,
+ that have some FT_VOID types. Just fake it for now. */
+ type = init_type (TYPE_CODE_VOID, 0, 0, "<?VOID?>", objfile);
+ break;
+ case FT_BOOLEAN:
+ type = init_type (TYPE_CODE_BOOL, 1, TYPE_FLAG_UNSIGNED, "BOOL", objfile);
+ break;
+ case FT_CHAR:
+ type = init_type (TYPE_CODE_CHAR, 1, TYPE_FLAG_UNSIGNED, "CHAR", objfile);
+ break;
+ case FT_SIGNED_CHAR:
+ type = init_type (TYPE_CODE_INT, 1, 0, "BYTE", objfile);
+ break;
+ case FT_UNSIGNED_CHAR:
+ type = init_type (TYPE_CODE_INT, 1, TYPE_FLAG_UNSIGNED, "UBYTE", objfile);
+ break;
+ case FT_SHORT: /* Chill ints are 2 bytes */
+ type = init_type (TYPE_CODE_INT, 2, 0, "INT", objfile);
+ break;
+ case FT_UNSIGNED_SHORT: /* Chill ints are 2 bytes */
+ type = init_type (TYPE_CODE_INT, 2, TYPE_FLAG_UNSIGNED, "UINT", objfile);
+ break;
+ case FT_INTEGER: /* FIXME? */
+ case FT_SIGNED_INTEGER: /* FIXME? */
+ case FT_LONG: /* Chill longs are 4 bytes */
+ case FT_SIGNED_LONG: /* Chill longs are 4 bytes */
+ type = init_type (TYPE_CODE_INT, 4, 0, "LONG", objfile);
+ break;
+ case FT_UNSIGNED_INTEGER: /* FIXME? */
+ case FT_UNSIGNED_LONG: /* Chill longs are 4 bytes */
+ type = init_type (TYPE_CODE_INT, 4, TYPE_FLAG_UNSIGNED, "ULONG", objfile);
+ break;
+ case FT_FLOAT:
+ type = init_type (TYPE_CODE_FLT, 4, 0, "REAL", objfile);
+ break;
+ case FT_DBL_PREC_FLOAT:
+ type = init_type (TYPE_CODE_FLT, 8, 0, "LONG_REAL", objfile);
+ break;
+ }
+ return (type);
+}
+
+
+/* Table of operators and their precedences for printing expressions. */
+
+static const struct op_print chill_op_print_tab[] = {
+ {"AND", BINOP_LOGICAL_AND, PREC_LOGICAL_AND, 0},
+ {"OR", BINOP_LOGICAL_OR, PREC_LOGICAL_OR, 0},
+ {"NOT", UNOP_LOGICAL_NOT, PREC_PREFIX, 0},
+ {"MOD", BINOP_MOD, PREC_MUL, 0},
+ {"REM", BINOP_REM, PREC_MUL, 0},
+ {":=", BINOP_ASSIGN, PREC_ASSIGN, 1},
+ {"=", BINOP_EQUAL, PREC_EQUAL, 0},
+ {"/=", BINOP_NOTEQUAL, PREC_EQUAL, 0},
+ {"<=", BINOP_LEQ, PREC_ORDER, 0},
+ {">=", BINOP_GEQ, PREC_ORDER, 0},
+ {">", BINOP_GTR, PREC_ORDER, 0},
+ {"<", BINOP_LESS, PREC_ORDER, 0},
+ {"+", BINOP_ADD, PREC_ADD, 0},
+ {"-", BINOP_SUB, PREC_ADD, 0},
+ {"*", BINOP_MUL, PREC_MUL, 0},
+ {"/", BINOP_DIV, PREC_MUL, 0},
+ {"//", BINOP_CONCAT, PREC_PREFIX, 0}, /* FIXME: precedence? */
+ {"-", UNOP_NEG, PREC_PREFIX, 0},
+ {NULL, 0, 0, 0}
+};
+
+
+/* The built-in types of Chill. */
+
+struct type *builtin_type_chill_bool;
+struct type *builtin_type_chill_char;
+struct type *builtin_type_chill_long;
+struct type *builtin_type_chill_ulong;
+struct type *builtin_type_chill_real;
+
+struct type ** const (chill_builtin_types[]) =
+{
+ &builtin_type_chill_bool,
+ &builtin_type_chill_char,
+ &builtin_type_chill_long,
+ &builtin_type_chill_ulong,
+ &builtin_type_chill_real,
+ 0
+};
+
+const struct language_defn chill_language_defn = {
+ "chill",
+ language_chill,
+ chill_builtin_types,
+ range_check_on,
+ type_check_on,
+ chill_parse, /* parser */
+ chill_error, /* parser error function */
+ chill_printchar, /* print a character constant */
+ chill_printstr, /* function to print a string constant */
+ chill_create_fundamental_type,/* Create fundamental type in this language */
+ chill_print_type, /* Print a type using appropriate syntax */
+ chill_val_print, /* Print a value using appropriate syntax */
+ chill_value_print, /* Print a top-levl value */
+ &builtin_type_chill_real, /* longest floating point type */
+ {"", "B'", "", ""}, /* Binary format info */
+ {"O'%lo", "O'", "o", ""}, /* Octal format info */
+ {"D'%ld", "D'", "d", ""}, /* Decimal format info */
+ {"H'%lx", "H'", "x", ""}, /* Hex format info */
+ chill_op_print_tab, /* expression operators for printing */
+ LANG_MAGIC
+};
+
+/* Initialization for Chill */
+
+void
+_initialize_chill_language ()
+{
+ builtin_type_chill_bool =
+ init_type (TYPE_CODE_BOOL, TARGET_CHAR_BIT / TARGET_CHAR_BIT,
+ TYPE_FLAG_UNSIGNED,
+ "BOOL", (struct objfile *) NULL);
+ builtin_type_chill_char =
+ init_type (TYPE_CODE_CHAR, TARGET_CHAR_BIT / TARGET_CHAR_BIT,
+ TYPE_FLAG_UNSIGNED,
+ "CHAR", (struct objfile *) NULL);
+ builtin_type_chill_long =
+ init_type (TYPE_CODE_INT, TARGET_LONG_BIT / TARGET_CHAR_BIT,
+ 0,
+ "LONG", (struct objfile *) NULL);
+ builtin_type_chill_ulong =
+ init_type (TYPE_CODE_INT, TARGET_LONG_BIT / TARGET_CHAR_BIT,
+ TYPE_FLAG_UNSIGNED,
+ "ULONG", (struct objfile *) NULL);
+ builtin_type_chill_real =
+ init_type (TYPE_CODE_FLT, TARGET_DOUBLE_BIT / TARGET_CHAR_BIT,
+ 0,
+ "LONG_REAL", (struct objfile *) NULL);
+
+ add_language (&chill_language_defn);
+}
diff --git a/gnu/usr.bin/gdb/gdb/ch-lang.h b/gnu/usr.bin/gdb/gdb/ch-lang.h
new file mode 100644
index 0000000..0fcb8d6
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/ch-lang.h
@@ -0,0 +1,44 @@
+/* Chill language support definitions for GDB, the GNU debugger.
+ Copyright 1992 Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#ifdef __STDC__ /* Forward decls for prototypes */
+struct value;
+#endif
+
+extern int
+chill_parse PARAMS ((void)); /* Defined in ch-exp.y */
+
+extern void
+chill_error PARAMS ((char *)); /* Defined in ch-exp.y */
+
+extern void /* Defined in ch-typeprint.c */
+chill_print_type PARAMS ((struct type *, char *, GDB_FILE *, int, int));
+
+extern int
+chill_val_print PARAMS ((struct type *, char *, CORE_ADDR, GDB_FILE *, int, int,
+ int, enum val_prettyprint));
+
+extern int
+chill_value_print PARAMS ((struct value *, GDB_FILE *,
+ int, enum val_prettyprint));
+
+extern int
+chill_is_varying_struct PARAMS ((struct type *type));
+
+
diff --git a/gnu/usr.bin/gdb/gdb/ch-typeprint.c b/gnu/usr.bin/gdb/gdb/ch-typeprint.c
new file mode 100644
index 0000000..9bc4303
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/ch-typeprint.c
@@ -0,0 +1,315 @@
+/* Support for printing Chill types for GDB, the GNU debugger.
+ Copyright 1986, 1988, 1989, 1991 Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "defs.h"
+#include "obstack.h"
+#include "bfd.h" /* Binary File Description */
+#include "symtab.h"
+#include "gdbtypes.h"
+#include "expression.h"
+#include "value.h"
+#include "gdbcore.h"
+#include "target.h"
+#include "command.h"
+#include "gdbcmd.h"
+#include "language.h"
+#include "demangle.h"
+#include "ch-lang.h"
+#include "typeprint.h"
+
+#include <string.h>
+#include <errno.h>
+
+static void
+chill_type_print_base PARAMS ((struct type *, GDB_FILE *, int, int));
+
+void
+chill_print_type (type, varstring, stream, show, level)
+ struct type *type;
+ char *varstring;
+ GDB_FILE *stream;
+ int show;
+ int level;
+{
+ if (varstring != NULL && *varstring != '\0')
+ {
+ fputs_filtered (varstring, stream);
+ fputs_filtered (" ", stream);
+ }
+ chill_type_print_base (type, stream, show, level);
+}
+
+/* Print the name of the type (or the ultimate pointer target,
+ function value or array element).
+
+ SHOW nonzero means don't print this type as just its name;
+ show its real definition even if it has a name.
+ SHOW zero means print just typename or tag if there is one
+ SHOW negative means abbreviate structure elements.
+ SHOW is decremented for printing of structure elements.
+
+ LEVEL is the depth to indent by.
+ We increase it for some recursive calls. */
+
+static void
+chill_type_print_base (type, stream, show, level)
+ struct type *type;
+ GDB_FILE *stream;
+ int show;
+ int level;
+{
+ register int len;
+ register int i;
+ struct type *index_type;
+ struct type *range_type;
+ LONGEST low_bound;
+ LONGEST high_bound;
+
+ QUIT;
+
+ wrap_here (" ");
+ if (type == NULL)
+ {
+ fputs_filtered ("<type unknown>", stream);
+ return;
+ }
+
+ /* When SHOW is zero or less, and there is a valid type name, then always
+ just print the type name directly from the type. */
+
+ if ((show <= 0) && (TYPE_NAME (type) != NULL))
+ {
+ fputs_filtered (TYPE_NAME (type), stream);
+ return;
+ }
+
+ check_stub_type (type);
+
+ switch (TYPE_CODE (type))
+ {
+ case TYPE_CODE_PTR:
+ if (TYPE_CODE (TYPE_TARGET_TYPE (type)) == TYPE_CODE_VOID)
+ {
+ fprintf_filtered (stream, "PTR");
+ break;
+ }
+ fprintf_filtered (stream, "REF ");
+ chill_type_print_base (TYPE_TARGET_TYPE (type), stream, show, level);
+ break;
+
+ case TYPE_CODE_BOOL:
+ /* FIXME: we should probably just print the TYPE_NAME, in case
+ anyone ever fixes the compiler to give us the real names
+ in the presence of the chill equivalent of typedef (assuming
+ there is one). */
+ fprintf_filtered (stream, "BOOL");
+ break;
+
+ case TYPE_CODE_ARRAY:
+ range_type = TYPE_FIELD_TYPE (type, 0);
+ index_type = TYPE_TARGET_TYPE (range_type);
+ low_bound = TYPE_FIELD_BITPOS (range_type, 0);
+ high_bound = TYPE_FIELD_BITPOS (range_type, 1);
+ fputs_filtered ("ARRAY (", stream);
+ print_type_scalar (index_type, low_bound, stream);
+ fputs_filtered (":", stream);
+ print_type_scalar (index_type, high_bound, stream);
+ fputs_filtered (") ", stream);
+ chill_print_type (TYPE_TARGET_TYPE (type), "", stream, show, level);
+ break;
+
+ case TYPE_CODE_BITSTRING:
+ fprintf_filtered (stream, "BOOLS (%d)",
+ TYPE_FIELD_BITPOS (TYPE_FIELD_TYPE(type,0), 1) + 1);
+ break;
+
+ case TYPE_CODE_SET:
+ fputs_filtered ("POWERSET ", stream);
+ chill_print_type (TYPE_FIELD_TYPE (type, 0), "", stream,
+ show - 1, level);
+ break;
+
+ case TYPE_CODE_STRING:
+ range_type = TYPE_FIELD_TYPE (type, 0);
+ index_type = TYPE_TARGET_TYPE (range_type);
+ high_bound = TYPE_FIELD_BITPOS (range_type, 1);
+ fputs_filtered ("CHARS (", stream);
+ print_type_scalar (index_type, high_bound + 1, stream);
+ fputs_filtered (")", stream);
+ break;
+
+ case TYPE_CODE_MEMBER:
+ fprintf_filtered (stream, "MEMBER ");
+ chill_type_print_base (TYPE_TARGET_TYPE (type), stream, show, level);
+ break;
+ case TYPE_CODE_REF:
+ fprintf_filtered (stream, "/*LOC*/ ");
+ chill_type_print_base (TYPE_TARGET_TYPE (type), stream, show, level);
+ break;
+ case TYPE_CODE_FUNC:
+ fprintf_filtered (stream, "PROC (?)");
+ chill_type_print_base (TYPE_TARGET_TYPE (type), stream, show, level);
+ break;
+
+ case TYPE_CODE_STRUCT:
+ if (chill_is_varying_struct (type))
+ {
+ chill_type_print_base (TYPE_FIELD_TYPE (type, 1),
+ stream, show, level);
+ fputs_filtered (" VARYING", stream);
+ }
+ else
+ {
+ fprintf_filtered (stream, "STRUCT ");
+
+ fprintf_filtered (stream, "(\n");
+ if ((TYPE_NFIELDS (type) == 0) && (TYPE_NFN_FIELDS (type) == 0))
+ {
+ if (TYPE_FLAGS (type) & TYPE_FLAG_STUB)
+ {
+ fprintfi_filtered (level + 4, stream, "<incomplete type>\n");
+ }
+ else
+ {
+ fprintfi_filtered (level + 4, stream, "<no data fields>\n");
+ }
+ }
+ else
+ {
+ len = TYPE_NFIELDS (type);
+ for (i = TYPE_N_BASECLASSES (type); i < len; i++)
+ {
+ struct type *field_type = TYPE_FIELD_TYPE (type, i);
+ QUIT;
+ print_spaces_filtered (level + 4, stream);
+ if (TYPE_CODE (field_type) == TYPE_CODE_UNION)
+ { int j; /* variant number */
+ fputs_filtered ("CASE OF\n", stream);
+ for (j = 0; j < TYPE_NFIELDS (field_type); j++)
+ { int k; /* variant field index */
+ struct type *variant_type
+ = TYPE_FIELD_TYPE (field_type, j);
+ int var_len = TYPE_NFIELDS (variant_type);
+ print_spaces_filtered (level + 4, stream);
+ if (strcmp (TYPE_FIELD_NAME (field_type, j),
+ "else") == 0)
+ fputs_filtered ("ELSE\n", stream);
+ else
+ fputs_filtered (":\n", stream);
+ if (TYPE_CODE (variant_type) != TYPE_CODE_STRUCT)
+ error ("variant record confusion");
+ for (k = 0; k < var_len; k++)
+ {
+ print_spaces_filtered (level + 8, stream);
+ chill_print_type (TYPE_FIELD_TYPE (variant_type, k),
+ TYPE_FIELD_NAME (variant_type, k),
+ stream, show - 1, level + 8);
+ if (k < (var_len - 1))
+ fputs_filtered (",", stream);
+ fputs_filtered ("\n", stream);
+ }
+ }
+ fputs_filtered ("ESAC\n", stream);
+ }
+ else
+ chill_print_type (field_type,
+ TYPE_FIELD_NAME (type, i),
+ stream, show - 1, level + 4);
+ if (i < (len - 1))
+ {
+ fputs_filtered (",", stream);
+ }
+ fputs_filtered ("\n", stream);
+ }
+ }
+ fprintfi_filtered (level, stream, ")");
+ }
+ break;
+
+ case TYPE_CODE_RANGE:
+ if (TYPE_DUMMY_RANGE (type))
+ chill_type_print_base (TYPE_TARGET_TYPE (type),
+ stream, show, level);
+ else if (TYPE_TARGET_TYPE (type))
+ {
+ chill_type_print_base (TYPE_TARGET_TYPE (type),
+ stream, show, level);
+ fputs_filtered (" (", stream);
+ print_type_scalar (TYPE_TARGET_TYPE (type),
+ TYPE_FIELD_BITPOS (type, 0), stream);
+ fputs_filtered (":", stream);
+ print_type_scalar (TYPE_TARGET_TYPE (type),
+ TYPE_FIELD_BITPOS (type, 1), stream);
+ fputs_filtered (")", stream);
+ }
+ else
+ fprintf_filtered (stream, "RANGE? (%s : %d)",
+ TYPE_FIELD_BITPOS (type, 0),
+ TYPE_FIELD_BITPOS (type, 1));
+ break;
+
+ case TYPE_CODE_ENUM:
+ {
+ register int lastval = 0;
+ fprintf_filtered (stream, "SET (");
+ len = TYPE_NFIELDS (type);
+ for (i = 0; i < len; i++)
+ {
+ QUIT;
+ if (i) fprintf_filtered (stream, ", ");
+ wrap_here (" ");
+ fputs_filtered (TYPE_FIELD_NAME (type, i), stream);
+ if (lastval != TYPE_FIELD_BITPOS (type, i))
+ {
+ fprintf_filtered (stream, " = %d", TYPE_FIELD_BITPOS (type, i));
+ lastval = TYPE_FIELD_BITPOS (type, i);
+ }
+ lastval++;
+ }
+ fprintf_filtered (stream, ")");
+ }
+ break;
+
+ case TYPE_CODE_VOID:
+ case TYPE_CODE_UNDEF:
+ case TYPE_CODE_ERROR:
+ case TYPE_CODE_UNION:
+ case TYPE_CODE_METHOD:
+ error ("missing language support in chill_type_print_base");
+ break;
+
+ default:
+
+ /* Handle types not explicitly handled by the other cases,
+ such as fundamental types. For these, just print whatever
+ the type name is, as recorded in the type itself. If there
+ is no type name, then complain. */
+
+ if (TYPE_NAME (type) != NULL)
+ {
+ fputs_filtered (TYPE_NAME (type), stream);
+ }
+ else
+ {
+ error ("Unrecognized type code (%d) in symbol table.",
+ TYPE_CODE (type));
+ }
+ break;
+ }
+}
diff --git a/gnu/usr.bin/gdb/gdb/ch-valprint.c b/gnu/usr.bin/gdb/gdb/ch-valprint.c
new file mode 100644
index 0000000..074329b
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/ch-valprint.c
@@ -0,0 +1,581 @@
+/* Support for printing Chill values for GDB, the GNU debugger.
+ Copyright 1986, 1988, 1989, 1991, 1992, 1993, 1994
+ Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "defs.h"
+#include "obstack.h"
+#include "symtab.h"
+#include "gdbtypes.h"
+#include "valprint.h"
+#include "expression.h"
+#include "value.h"
+#include "language.h"
+#include "demangle.h"
+#include "c-lang.h" /* For c_val_print */
+#include "typeprint.h"
+#include "ch-lang.h"
+
+static void
+chill_print_value_fields PARAMS ((struct type *, char *, GDB_FILE *, int, int,
+ enum val_prettyprint, struct type **));
+
+
+/* Print the elements of an array.
+ Similar to val_print_array_elements, but prints
+ element indexes (in Chill syntax). */
+
+static void
+chill_val_print_array_elements (type, valaddr, address, stream,
+ format, deref_ref, recurse, pretty)
+ struct type *type;
+ char *valaddr;
+ CORE_ADDR address;
+ GDB_FILE *stream;
+ int format;
+ int deref_ref;
+ int recurse;
+ enum val_prettyprint pretty;
+{
+ unsigned int i = 0;
+ unsigned int things_printed = 0;
+ unsigned len;
+ struct type *elttype;
+ struct type *range_type = TYPE_FIELD_TYPE (type, 0);
+ struct type *index_type = TYPE_TARGET_TYPE (range_type);
+ unsigned eltlen;
+ /* Position of the array element we are examining to see
+ whether it is repeated. */
+ unsigned int rep1;
+ /* Number of repetitions we have detected so far. */
+ unsigned int reps;
+ LONGEST low_bound = TYPE_FIELD_BITPOS (range_type, 0);
+ LONGEST high_bound = TYPE_FIELD_BITPOS (range_type, 1);
+
+ elttype = TYPE_TARGET_TYPE (type);
+ eltlen = TYPE_LENGTH (elttype);
+ len = TYPE_LENGTH (type) / eltlen;
+
+ annotate_array_section_begin (i, elttype);
+
+ for (; i < len && things_printed < print_max; i++)
+ {
+ if (i != 0)
+ {
+ if (prettyprint_arrays)
+ {
+ fprintf_filtered (stream, ",\n");
+ print_spaces_filtered (2 + 2 * recurse, stream);
+ }
+ else
+ {
+ fprintf_filtered (stream, ", ");
+ }
+ }
+ wrap_here (n_spaces (2 + 2 * recurse));
+
+ rep1 = i + 1;
+ reps = 1;
+ while ((rep1 < len) &&
+ !memcmp (valaddr + i * eltlen, valaddr + rep1 * eltlen, eltlen))
+ {
+ ++reps;
+ ++rep1;
+ }
+
+ fputs_filtered ("(", stream);
+ print_type_scalar (index_type, low_bound + i, stream);
+ if (reps > 1)
+ {
+ fputs_filtered (":", stream);
+ print_type_scalar (index_type, low_bound + i + reps - 1, stream);
+ fputs_filtered ("): ", stream);
+ val_print (elttype, valaddr + i * eltlen, 0, stream, format,
+ deref_ref, recurse + 1, pretty);
+
+ i = rep1 - 1;
+ things_printed += 1;
+ }
+ else
+ {
+ fputs_filtered ("): ", stream);
+ val_print (elttype, valaddr + i * eltlen, 0, stream, format,
+ deref_ref, recurse + 1, pretty);
+ annotate_elt ();
+ things_printed++;
+ }
+ }
+ annotate_array_section_end ();
+ if (i < len)
+ {
+ fprintf_filtered (stream, "...");
+ }
+}
+
+/* Print data of type TYPE located at VALADDR (within GDB), which came from
+ the inferior at address ADDRESS, onto stdio stream STREAM according to
+ FORMAT (a letter or 0 for natural format). The data at VALADDR is in
+ target byte order.
+
+ If the data are a string pointer, returns the number of string characters
+ printed.
+
+ If DEREF_REF is nonzero, then dereference references, otherwise just print
+ them like pointers.
+
+ The PRETTY parameter controls prettyprinting. */
+
+int
+chill_val_print (type, valaddr, address, stream, format, deref_ref, recurse,
+ pretty)
+ struct type *type;
+ char *valaddr;
+ CORE_ADDR address;
+ GDB_FILE *stream;
+ int format;
+ int deref_ref;
+ int recurse;
+ enum val_prettyprint pretty;
+{
+ LONGEST val;
+ unsigned int i = 0; /* Number of characters printed. */
+ struct type *elttype;
+ CORE_ADDR addr;
+
+ switch (TYPE_CODE (type))
+ {
+ case TYPE_CODE_ARRAY:
+ if (TYPE_LENGTH (type) > 0 && TYPE_LENGTH (TYPE_TARGET_TYPE (type)) > 0)
+ {
+ if (prettyprint_arrays)
+ {
+ print_spaces_filtered (2 + 2 * recurse, stream);
+ }
+ fprintf_filtered (stream, "[");
+ chill_val_print_array_elements (type, valaddr, address, stream,
+ format, deref_ref, recurse, pretty);
+ fprintf_filtered (stream, "]");
+ }
+ else
+ {
+ error ("unimplemented in chill_val_print; unspecified array length");
+ }
+ break;
+
+ case TYPE_CODE_INT:
+ format = format ? format : output_format;
+ if (format)
+ {
+ print_scalar_formatted (valaddr, type, format, 0, stream);
+ }
+ else
+ {
+ val_print_type_code_int (type, valaddr, stream);
+ }
+ break;
+
+ case TYPE_CODE_CHAR:
+ format = format ? format : output_format;
+ if (format)
+ {
+ print_scalar_formatted (valaddr, type, format, 0, stream);
+ }
+ else
+ {
+ LA_PRINT_CHAR ((unsigned char) unpack_long (type, valaddr),
+ stream);
+ }
+ break;
+
+ case TYPE_CODE_FLT:
+ if (format)
+ {
+ print_scalar_formatted (valaddr, type, format, 0, stream);
+ }
+ else
+ {
+ print_floating (valaddr, type, stream);
+ }
+ break;
+
+ case TYPE_CODE_BOOL:
+ format = format ? format : output_format;
+ if (format)
+ {
+ print_scalar_formatted (valaddr, type, format, 0, stream);
+ }
+ else
+ {
+ /* FIXME: Why is this using builtin_type_chill_bool not type? */
+ val = unpack_long (builtin_type_chill_bool, valaddr);
+ fprintf_filtered (stream, val ? "TRUE" : "FALSE");
+ }
+ break;
+
+ case TYPE_CODE_UNDEF:
+ /* This happens (without TYPE_FLAG_STUB set) on systems which don't use
+ dbx xrefs (NO_DBX_XREFS in gcc) if a file has a "struct foo *bar"
+ and no complete type for struct foo in that file. */
+ fprintf_filtered (stream, "<incomplete type>");
+ break;
+
+ case TYPE_CODE_PTR:
+ if (format && format != 's')
+ {
+ print_scalar_formatted (valaddr, type, format, 0, stream);
+ break;
+ }
+ addr = unpack_pointer (type, valaddr);
+ elttype = TYPE_TARGET_TYPE (type);
+
+ /* We assume a NULL pointer is all zeros ... */
+ if (addr == 0)
+ {
+ fputs_filtered ("NULL", stream);
+ return 0;
+ }
+
+ if (TYPE_CODE (elttype) == TYPE_CODE_FUNC)
+ {
+ /* Try to print what function it points to. */
+ print_address_demangle (addr, stream, demangle);
+ /* Return value is irrelevant except for string pointers. */
+ return (0);
+ }
+ if (addressprint && format != 's')
+ {
+ print_address_numeric (addr, 1, stream);
+ }
+
+ /* For a pointer to char or unsigned char, also print the string
+ pointed to, unless pointer is null. */
+ if (TYPE_LENGTH (elttype) == 1
+ && TYPE_CODE (elttype) == TYPE_CODE_CHAR
+ && (format == 0 || format == 's')
+ && addr != 0
+ && /* If print_max is UINT_MAX, the alloca below will fail.
+ In that case don't try to print the string. */
+ print_max < UINT_MAX)
+ {
+ i = val_print_string (addr, 0, stream);
+ }
+ /* Return number of characters printed, plus one for the
+ terminating null if we have "reached the end". */
+ return (i + (print_max && i != print_max));
+ break;
+
+ case TYPE_CODE_STRING:
+ if (format && format != 's')
+ {
+ print_scalar_formatted (valaddr, type, format, 0, stream);
+ break;
+ }
+ i = TYPE_LENGTH (type);
+ LA_PRINT_STRING (stream, valaddr, i, 0);
+ /* Return number of characters printed, plus one for the terminating
+ null if we have "reached the end". */
+ return (i + (print_max && i != print_max));
+ break;
+
+ case TYPE_CODE_BITSTRING:
+ case TYPE_CODE_SET:
+ elttype = TYPE_FIELD_TYPE (type, 0);
+ check_stub_type (elttype);
+ if (TYPE_FLAGS (elttype) & TYPE_FLAG_STUB)
+ {
+ fprintf_filtered (stream, "<incomplete type>");
+ gdb_flush (stream);
+ break;
+ }
+ {
+ struct type *range = elttype;
+ int low_bound = TYPE_LOW_BOUND (range);
+ int high_bound = TYPE_HIGH_BOUND (range);
+ int i;
+ int is_bitstring = TYPE_CODE (type) == TYPE_CODE_BITSTRING;
+ int need_comma = 0;
+
+ if (is_bitstring)
+ fputs_filtered ("B'", stream);
+ else
+ fputs_filtered ("[", stream);
+ for (i = low_bound; i <= high_bound; i++)
+ {
+ int element = value_bit_index (type, valaddr, i);
+ if (is_bitstring)
+ fprintf_filtered (stream, "%d", element);
+ else if (element)
+ {
+ if (need_comma)
+ fputs_filtered (", ", stream);
+ print_type_scalar (TYPE_TARGET_TYPE (range), i, stream);
+ need_comma = 1;
+
+ /* Look for a continuous range of true elements. */
+ if (i+1 <= high_bound && value_bit_index (type, valaddr, ++i))
+ {
+ int j = i; /* j is the upper bound so far of the range */
+ fputs_filtered (":", stream);
+ while (i+1 <= high_bound
+ && value_bit_index (type, valaddr, ++i))
+ j = i;
+ print_type_scalar (TYPE_TARGET_TYPE (range), j, stream);
+ }
+ }
+ }
+ if (is_bitstring)
+ fputs_filtered ("'", stream);
+ else
+ fputs_filtered ("]", stream);
+ }
+ break;
+
+ case TYPE_CODE_STRUCT:
+ if (chill_is_varying_struct (type))
+ {
+ struct type *inner = TYPE_FIELD_TYPE (type, 1);
+ long length = unpack_long (TYPE_FIELD_TYPE (type, 0), valaddr);
+ char *data_addr = valaddr + TYPE_FIELD_BITPOS (type, 1) / 8;
+
+ switch (TYPE_CODE (inner))
+ {
+ case TYPE_CODE_STRING:
+ if (length > TYPE_LENGTH (type))
+ {
+ fprintf_filtered (stream,
+ "<dynamic length %d > static length %d>",
+ length, TYPE_LENGTH (type));
+ }
+ LA_PRINT_STRING (stream, data_addr, length, 0);
+ return length;
+ default:
+ break;
+ }
+ }
+ chill_print_value_fields (type, valaddr, stream, format, recurse, pretty,
+ 0);
+ break;
+
+ case TYPE_CODE_REF:
+ if (addressprint)
+ {
+ fprintf_filtered (stream, "LOC(");
+ print_address_numeric
+ (extract_address (valaddr, TARGET_PTR_BIT / HOST_CHAR_BIT),
+ 1,
+ stream);
+ fprintf_filtered (stream, ")");
+ if (deref_ref)
+ fputs_filtered (": ", stream);
+ }
+ /* De-reference the reference. */
+ if (deref_ref)
+ {
+ if (TYPE_CODE (TYPE_TARGET_TYPE (type)) != TYPE_CODE_UNDEF)
+ {
+ value_ptr deref_val =
+ value_at
+ (TYPE_TARGET_TYPE (type),
+ unpack_pointer (lookup_pointer_type (builtin_type_void),
+ valaddr));
+ val_print (VALUE_TYPE (deref_val),
+ VALUE_CONTENTS (deref_val),
+ VALUE_ADDRESS (deref_val), stream, format,
+ deref_ref, recurse + 1, pretty);
+ }
+ else
+ fputs_filtered ("???", stream);
+ }
+ break;
+
+ case TYPE_CODE_ENUM:
+ c_val_print (type, valaddr, address, stream, format,
+ deref_ref, recurse, pretty);
+ break;
+
+ case TYPE_CODE_RANGE:
+ if (TYPE_TARGET_TYPE (type))
+ chill_val_print (TYPE_TARGET_TYPE (type), valaddr, address, stream,
+ format, deref_ref, recurse, pretty);
+ break;
+
+ case TYPE_CODE_MEMBER:
+ case TYPE_CODE_UNION:
+ case TYPE_CODE_FUNC:
+ case TYPE_CODE_VOID:
+ case TYPE_CODE_ERROR:
+ default:
+ /* Let's defer printing to the C printer, rather than
+ print an error message. FIXME! */
+ c_val_print (type, valaddr, address, stream, format,
+ deref_ref, recurse, pretty);
+ }
+ gdb_flush (stream);
+ return (0);
+}
+
+/* Mutually recursive subroutines of cplus_print_value and c_val_print to
+ print out a structure's fields: cp_print_value_fields and cplus_print_value.
+
+ TYPE, VALADDR, STREAM, RECURSE, and PRETTY have the
+ same meanings as in cplus_print_value and c_val_print.
+
+ DONT_PRINT is an array of baseclass types that we
+ should not print, or zero if called from top level. */
+
+static void
+chill_print_value_fields (type, valaddr, stream, format, recurse, pretty,
+ dont_print)
+ struct type *type;
+ char *valaddr;
+ GDB_FILE *stream;
+ int format;
+ int recurse;
+ enum val_prettyprint pretty;
+ struct type **dont_print;
+{
+ int i, len;
+ int fields_seen = 0;
+
+ check_stub_type (type);
+
+ fprintf_filtered (stream, "[");
+ len = TYPE_NFIELDS (type);
+ if (len == 0)
+ {
+ fprintf_filtered (stream, "<No data fields>");
+ }
+ else
+ {
+ for (i = 0; i < len; i++)
+ {
+ if (fields_seen)
+ {
+ fprintf_filtered (stream, ", ");
+ }
+ fields_seen = 1;
+ if (pretty)
+ {
+ fprintf_filtered (stream, "\n");
+ print_spaces_filtered (2 + 2 * recurse, stream);
+ }
+ else
+ {
+ wrap_here (n_spaces (2 + 2 * recurse));
+ }
+ fputs_filtered (".", stream);
+ fprintf_symbol_filtered (stream, TYPE_FIELD_NAME (type, i),
+ language_chill, DMGL_NO_OPTS);
+ fputs_filtered (": ", stream);
+ if (TYPE_FIELD_PACKED (type, i))
+ {
+ value_ptr v;
+
+ /* Bitfields require special handling, especially due to byte
+ order problems. */
+ v = value_from_longest (TYPE_FIELD_TYPE (type, i),
+ unpack_field_as_long (type, valaddr, i));
+
+ chill_val_print (TYPE_FIELD_TYPE (type, i), VALUE_CONTENTS (v), 0,
+ stream, format, 0, recurse + 1, pretty);
+ }
+ else
+ {
+ chill_val_print (TYPE_FIELD_TYPE (type, i),
+ valaddr + TYPE_FIELD_BITPOS (type, i) / 8,
+ 0, stream, format, 0, recurse + 1, pretty);
+ }
+ }
+ if (pretty)
+ {
+ fprintf_filtered (stream, "\n");
+ print_spaces_filtered (2 * recurse, stream);
+ }
+ }
+ fprintf_filtered (stream, "]");
+}
+
+int
+chill_value_print (val, stream, format, pretty)
+ value_ptr val;
+ GDB_FILE *stream;
+ int format;
+ enum val_prettyprint pretty;
+{
+ /* A "repeated" value really contains several values in a row.
+ They are made by the @ operator.
+ Print such values as if they were arrays. */
+
+ if (VALUE_REPEATED (val))
+ {
+ register unsigned int n = VALUE_REPETITIONS (val);
+ register unsigned int typelen = TYPE_LENGTH (VALUE_TYPE (val));
+ fprintf_filtered (stream, "[");
+ /* Print arrays of characters using string syntax. */
+ if (typelen == 1 && TYPE_CODE (VALUE_TYPE (val)) == TYPE_CODE_INT
+ && format == 0)
+ LA_PRINT_STRING (stream, VALUE_CONTENTS (val), n, 0);
+ else
+ {
+ value_print_array_elements (val, stream, format, pretty);
+ }
+ fprintf_filtered (stream, "]");
+ return (n * typelen);
+ }
+ else
+ {
+ struct type *type = VALUE_TYPE (val);
+
+ /* If it is a pointer, indicate what it points to.
+
+ Print type also if it is a reference.
+
+ C++: if it is a member pointer, we will take care
+ of that when we print it. */
+ if (TYPE_CODE (type) == TYPE_CODE_PTR ||
+ TYPE_CODE (type) == TYPE_CODE_REF)
+ {
+ char *valaddr = VALUE_CONTENTS (val);
+ CORE_ADDR addr = unpack_pointer (type, valaddr);
+ if (TYPE_CODE (type) != TYPE_CODE_PTR || addr != 0)
+ {
+ int i;
+ char *name = TYPE_NAME (type);
+ if (name)
+ fputs_filtered (name, stream);
+ else if (TYPE_CODE (TYPE_TARGET_TYPE (type)) == TYPE_CODE_VOID)
+ fputs_filtered ("PTR", stream);
+ else
+ {
+ fprintf_filtered (stream, "(");
+ type_print (type, "", stream, -1);
+ fprintf_filtered (stream, ")");
+ }
+ fprintf_filtered (stream, "(");
+ i = val_print (type, valaddr, VALUE_ADDRESS (val),
+ stream, format, 1, 0, pretty);
+ fprintf_filtered (stream, ")");
+ return i;
+ }
+ }
+ return (val_print (type, VALUE_CONTENTS (val),
+ VALUE_ADDRESS (val), stream, format, 1, 0, pretty));
+ }
+}
+
+
diff --git a/gnu/usr.bin/gdb/gdb/coff/ecoff.h b/gnu/usr.bin/gdb/gdb/coff/ecoff.h
new file mode 100644
index 0000000..7f149eb
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/coff/ecoff.h
@@ -0,0 +1,369 @@
+#ifndef ECOFF_H
+#define ECOFF_H
+
+/* Generic ECOFF support.
+ This does not include symbol information, found in sym.h and
+ symconst.h. */
+
+/* Mips magic numbers used in filehdr. MIPS_MAGIC_LITTLE is used on
+ little endian machines. MIPS_MAGIC_BIG is used on big endian
+ machines. Where is MIPS_MAGIC_1 from? */
+#define MIPS_MAGIC_1 0x0180
+#define MIPS_MAGIC_LITTLE 0x0162
+#define MIPS_MAGIC_BIG 0x0160
+
+/* These are the magic numbers used for MIPS code compiled at ISA
+ level 2. */
+#define MIPS_MAGIC_LITTLE2 0x0166
+#define MIPS_MAGIC_BIG2 0x0163
+
+/* These are the magic numbers used for MIPS code compiled at ISA
+ level 3. */
+#define MIPS_MAGIC_LITTLE3 0x142
+#define MIPS_MAGIC_BIG3 0x140
+
+/* Alpha magic numbers used in filehdr. */
+#define ALPHA_MAGIC 0x183
+
+/* Magic numbers used in a.out header. */
+#define ECOFF_AOUT_OMAGIC 0407 /* not demand paged (ld -N). */
+#define ECOFF_AOUT_ZMAGIC 0413 /* demand load format, eg normal ld output */
+
+/* Names of special sections. */
+#define _TEXT ".text"
+#define _DATA ".data"
+#define _BSS ".bss"
+#define _RDATA ".rdata"
+#define _SDATA ".sdata"
+#define _SBSS ".sbss"
+#define _LITA ".lita"
+#define _LIT4 ".lit4"
+#define _LIT8 ".lit8"
+#define _LIB ".lib"
+#define _INIT ".init"
+#define _FINI ".fini"
+#define _PDATA ".pdata"
+#define _XDATA ".xdata"
+
+/* ECOFF uses some additional section flags. */
+#define STYP_RDATA 0x100
+#define STYP_SDATA 0x200
+#define STYP_SBSS 0x400
+#define STYP_ECOFF_FINI 0x1000000
+#define STYP_EXTENDESC 0x2000000 /* 0x02FFF000 bits => scn type, rest clr */
+#define STYP_LITA 0x4000000
+#define STYP_LIT8 0x8000000
+#define STYP_LIT4 0x10000000
+#define STYP_ECOFF_LIB 0x40000000
+#define STYP_ECOFF_INIT 0x80000000
+#define STYP_OTHER_LOAD (STYP_ECOFF_INIT | STYP_ECOFF_FINI)
+
+/* extended section types */
+#define STYP_COMMENT 0x2100000
+#define STYP_XDATA 0x2400000
+#define STYP_PDATA 0x2800000
+
+/* The linker needs a section to hold small common variables while
+ linking. There is no convenient way to create it when the linker
+ needs it, so we always create one for each BFD. We then avoid
+ writing it out. */
+#define SCOMMON ".scommon"
+
+/* If the extern bit in a reloc is 1, then r_symndx is an index into
+ the external symbol table. If the extern bit is 0, then r_symndx
+ indicates a section, and is one of the following values. */
+#define RELOC_SECTION_NONE 0
+#define RELOC_SECTION_TEXT 1
+#define RELOC_SECTION_RDATA 2
+#define RELOC_SECTION_DATA 3
+#define RELOC_SECTION_SDATA 4
+#define RELOC_SECTION_SBSS 5
+#define RELOC_SECTION_BSS 6
+#define RELOC_SECTION_INIT 7
+#define RELOC_SECTION_LIT8 8
+#define RELOC_SECTION_LIT4 9
+#define RELOC_SECTION_XDATA 10
+#define RELOC_SECTION_PDATA 11
+#define RELOC_SECTION_FINI 12
+#define RELOC_SECTION_LITA 13
+#define RELOC_SECTION_ABS 14
+
+#define NUM_RELOC_SECTIONS 15
+
+/********************** STABS **********************/
+
+/* gcc uses mips-tfile to output type information in special stabs
+ entries. These must match the corresponding definition in
+ gcc/config/mips.h. At some point, these should probably go into a
+ shared include file, but currently gcc and gdb do not share any
+ directories. */
+#define CODE_MASK 0x8F300
+#define ECOFF_IS_STAB(sym) (((sym)->index & 0xFFF00) == CODE_MASK)
+#define ECOFF_MARK_STAB(code) ((code)+CODE_MASK)
+#define ECOFF_UNMARK_STAB(code) ((code)-CODE_MASK)
+#define STABS_SYMBOL "@stabs"
+
+/********************** COFF **********************/
+
+/* gcc also uses mips-tfile to output COFF debugging information.
+ These are the values it uses when outputting the .type directive.
+ These should also be in a shared include file. */
+#define N_BTMASK (017)
+#define N_TMASK (060)
+#define N_BTSHFT (4)
+#define N_TSHIFT (2)
+
+/********************** AUX **********************/
+
+/* The auxiliary type information is the same on all known ECOFF
+ targets. I can't see any reason that it would ever change, so I am
+ going to gamble and define the external structures here, in the
+ target independent ECOFF header file. The internal forms are
+ defined in coff/sym.h, which was originally donated by MIPS
+ Computer Systems. */
+
+/* Type information external record */
+
+struct tir_ext {
+ unsigned char t_bits1[1];
+ unsigned char t_tq45[1];
+ unsigned char t_tq01[1];
+ unsigned char t_tq23[1];
+};
+
+#define TIR_BITS1_FBITFIELD_BIG ((unsigned int) 0x80)
+#define TIR_BITS1_FBITFIELD_LITTLE ((unsigned int) 0x01)
+
+#define TIR_BITS1_CONTINUED_BIG ((unsigned int) 0x40)
+#define TIR_BITS1_CONTINUED_LITTLE ((unsigned int) 0x02)
+
+#define TIR_BITS1_BT_BIG ((unsigned int) 0x3F)
+#define TIR_BITS1_BT_SH_BIG 0
+#define TIR_BITS1_BT_LITTLE ((unsigned int) 0xFC)
+#define TIR_BITS1_BT_SH_LITTLE 2
+
+#define TIR_BITS_TQ4_BIG ((unsigned int) 0xF0)
+#define TIR_BITS_TQ4_SH_BIG 4
+#define TIR_BITS_TQ5_BIG ((unsigned int) 0x0F)
+#define TIR_BITS_TQ5_SH_BIG 0
+#define TIR_BITS_TQ4_LITTLE ((unsigned int) 0x0F)
+#define TIR_BITS_TQ4_SH_LITTLE 0
+#define TIR_BITS_TQ5_LITTLE ((unsigned int) 0xF0)
+#define TIR_BITS_TQ5_SH_LITTLE 4
+
+#define TIR_BITS_TQ0_BIG ((unsigned int) 0xF0)
+#define TIR_BITS_TQ0_SH_BIG 4
+#define TIR_BITS_TQ1_BIG ((unsigned int) 0x0F)
+#define TIR_BITS_TQ1_SH_BIG 0
+#define TIR_BITS_TQ0_LITTLE ((unsigned int) 0x0F)
+#define TIR_BITS_TQ0_SH_LITTLE 0
+#define TIR_BITS_TQ1_LITTLE ((unsigned int) 0xF0)
+#define TIR_BITS_TQ1_SH_LITTLE 4
+
+#define TIR_BITS_TQ2_BIG ((unsigned int) 0xF0)
+#define TIR_BITS_TQ2_SH_BIG 4
+#define TIR_BITS_TQ3_BIG ((unsigned int) 0x0F)
+#define TIR_BITS_TQ3_SH_BIG 0
+#define TIR_BITS_TQ2_LITTLE ((unsigned int) 0x0F)
+#define TIR_BITS_TQ2_SH_LITTLE 0
+#define TIR_BITS_TQ3_LITTLE ((unsigned int) 0xF0)
+#define TIR_BITS_TQ3_SH_LITTLE 4
+
+/* Relative symbol external record */
+
+struct rndx_ext {
+ unsigned char r_bits[4];
+};
+
+#define RNDX_BITS0_RFD_SH_LEFT_BIG 4
+#define RNDX_BITS1_RFD_BIG ((unsigned int) 0xF0)
+#define RNDX_BITS1_RFD_SH_BIG 4
+
+#define RNDX_BITS0_RFD_SH_LEFT_LITTLE 0
+#define RNDX_BITS1_RFD_LITTLE ((unsigned int) 0x0F)
+#define RNDX_BITS1_RFD_SH_LEFT_LITTLE 8
+
+#define RNDX_BITS1_INDEX_BIG ((unsigned int) 0x0F)
+#define RNDX_BITS1_INDEX_SH_LEFT_BIG 16
+#define RNDX_BITS2_INDEX_SH_LEFT_BIG 8
+#define RNDX_BITS3_INDEX_SH_LEFT_BIG 0
+
+#define RNDX_BITS1_INDEX_LITTLE ((unsigned int) 0xF0)
+#define RNDX_BITS1_INDEX_SH_LITTLE 4
+#define RNDX_BITS2_INDEX_SH_LEFT_LITTLE 4
+#define RNDX_BITS3_INDEX_SH_LEFT_LITTLE 12
+
+/* Auxiliary symbol information external record */
+
+union aux_ext {
+ struct tir_ext a_ti;
+ struct rndx_ext a_rndx;
+ unsigned char a_dnLow[4];
+ unsigned char a_dnHigh[4];
+ unsigned char a_isym[4];
+ unsigned char a_iss[4];
+ unsigned char a_width[4];
+ unsigned char a_count[4];
+};
+
+#define AUX_GET_ANY(bigend, ax, field) \
+ ((bigend) ? bfd_getb32 ((ax)->field) : bfd_getl32 ((ax)->field))
+
+#define AUX_GET_DNLOW(bigend, ax) AUX_GET_ANY ((bigend), (ax), a_dnLow)
+#define AUX_GET_DNHIGH(bigend, ax) AUX_GET_ANY ((bigend), (ax), a_dnHigh)
+#define AUX_GET_ISYM(bigend, ax) AUX_GET_ANY ((bigend), (ax), a_isym)
+#define AUX_GET_ISS(bigend, ax) AUX_GET_ANY ((bigend), (ax), a_iss)
+#define AUX_GET_WIDTH(bigend, ax) AUX_GET_ANY ((bigend), (ax), a_width)
+#define AUX_GET_COUNT(bigend, ax) AUX_GET_ANY ((bigend), (ax), a_count)
+
+#define AUX_PUT_ANY(bigend, val, ax, field) \
+ ((bigend) \
+ ? (bfd_putb32 ((bfd_vma) (val), (ax)->field), 0) \
+ : (bfd_putl32 ((bfd_vma) (val), (ax)->field), 0))
+
+#define AUX_PUT_DNLOW(bigend, val, ax) \
+ AUX_PUT_ANY ((bigend), (val), (ax), a_dnLow)
+#define AUX_PUT_DNHIGH(bigend, val, ax) \
+ AUX_PUT_ANY ((bigend), (val), (ax), a_dnHigh)
+#define AUX_PUT_ISYM(bigend, val, ax) \
+ AUX_PUT_ANY ((bigend), (val), (ax), a_isym)
+#define AUX_PUT_ISS(bigend, val, ax) \
+ AUX_PUT_ANY ((bigend), (val), (ax), a_iss)
+#define AUX_PUT_WIDTH(bigend, val, ax) \
+ AUX_PUT_ANY ((bigend), (val), (ax), a_width)
+#define AUX_PUT_COUNT(bigend, val, ax) \
+ AUX_PUT_ANY ((bigend), (val), (ax), a_count)
+
+/********************** SYMBOLS **********************/
+
+/* For efficiency, gdb deals directly with the unswapped symbolic
+ information (that way it only takes the time to swap information
+ that it really needs to read). gdb originally retrieved the
+ information directly from the BFD backend information, but that
+ strategy, besides being sort of ugly, does not work for MIPS ELF,
+ which also uses ECOFF debugging information. This structure holds
+ pointers to the (mostly) unswapped symbolic information. */
+
+struct ecoff_debug_info
+{
+ /* The swapped ECOFF symbolic header. */
+ HDRR symbolic_header;
+
+ /* Pointers to the unswapped symbolic information. Note that the
+ pointers to external structures point to different sorts of
+ information on different ECOFF targets. The ecoff_debug_swap
+ structure provides the sizes of the structures and the functions
+ needed to swap the information in and out. These pointers are
+ all pointers to arrays, not single structures. They will be NULL
+ if there are no instances of the relevant structure. These
+ fields are also used by the assembler to output ECOFF debugging
+ information. */
+ unsigned char *line;
+ PTR external_dnr; /* struct dnr_ext */
+ PTR external_pdr; /* struct pdr_ext */
+ PTR external_sym; /* struct sym_ext */
+ PTR external_opt; /* struct opt_ext */
+ union aux_ext *external_aux;
+ char *ss;
+ char *ssext;
+ PTR external_fdr; /* struct fdr_ext */
+ PTR external_rfd; /* struct rfd_ext */
+ PTR external_ext; /* struct ext_ext */
+
+ /* These fields are used when linking. They may disappear at some
+ point. */
+ char *ssext_end;
+ PTR external_ext_end;
+
+ /* When linking, this field holds a mapping from the input FDR
+ numbers to the output numbers, and is used when writing out the
+ external symbols. It is NULL if no mapping is required. */
+ RFDT *ifdmap;
+
+ /* The swapped FDR information. Currently this is never NULL, but
+ code using this structure should probably double-check in case
+ this changes in the future. This is a pointer to an array, not a
+ single structure. */
+ FDR *fdr;
+
+ /* When relaxing MIPS embedded PIC code, we may need to adjust
+ symbol values when they are output. This is a linked list of
+ structures indicating how values should be adjusted. There is no
+ requirement that the entries be in any order, or that they not
+ overlap. This field is normally NULL, in which case no
+ adjustments need to be made. */
+ struct ecoff_value_adjust *adjust;
+};
+
+/* This structure describes how to adjust symbol values when
+ outputting MIPS embedded PIC code. These adjustments only apply to
+ the internal symbols, as the external symbol values will come from
+ the hash table and have already been adjusted. */
+
+struct ecoff_value_adjust
+{
+ /* Next entry on adjustment list. */
+ struct ecoff_value_adjust *next;
+ /* Starting VMA of adjustment. This is the VMA in the ECOFF file,
+ not the offset from the start of the section. Thus it should
+ indicate a particular section. */
+ bfd_vma start;
+ /* Ending VMA of adjustment. */
+ bfd_vma end;
+ /* Adjustment. This should be added to the value of the symbol, or
+ FDR. This is zero for the last entry in the array. */
+ long adjust;
+};
+
+/********************** SWAPPING **********************/
+
+/* The generic ECOFF code needs to be able to swap debugging
+ information in and out in the specific format used by a particular
+ ECOFF implementation. This structure provides the information
+ needed to do this. */
+
+struct ecoff_debug_swap
+{
+ /* Symbol table magic number. */
+ int sym_magic;
+ /* Alignment of debugging information. E.g., 4. */
+ bfd_size_type debug_align;
+ /* Sizes of external symbolic information. */
+ bfd_size_type external_hdr_size;
+ bfd_size_type external_dnr_size;
+ bfd_size_type external_pdr_size;
+ bfd_size_type external_sym_size;
+ bfd_size_type external_opt_size;
+ bfd_size_type external_fdr_size;
+ bfd_size_type external_rfd_size;
+ bfd_size_type external_ext_size;
+ /* Functions to swap in external symbolic data. */
+ void (*swap_hdr_in) PARAMS ((bfd *, PTR, HDRR *));
+ void (*swap_dnr_in) PARAMS ((bfd *, PTR, DNR *));
+ void (*swap_pdr_in) PARAMS ((bfd *, PTR, PDR *));
+ void (*swap_sym_in) PARAMS ((bfd *, PTR, SYMR *));
+ void (*swap_opt_in) PARAMS ((bfd *, PTR, OPTR *));
+ void (*swap_fdr_in) PARAMS ((bfd *, PTR, FDR *));
+ void (*swap_rfd_in) PARAMS ((bfd *, PTR, RFDT *));
+ void (*swap_ext_in) PARAMS ((bfd *, PTR, EXTR *));
+ void (*swap_tir_in) PARAMS ((int, const struct tir_ext *, TIR *));
+ void (*swap_rndx_in) PARAMS ((int, const struct rndx_ext *, RNDXR *));
+ /* Functions to swap out external symbolic data. */
+ void (*swap_hdr_out) PARAMS ((bfd *, const HDRR *, PTR));
+ void (*swap_dnr_out) PARAMS ((bfd *, const DNR *, PTR));
+ void (*swap_pdr_out) PARAMS ((bfd *, const PDR *, PTR));
+ void (*swap_sym_out) PARAMS ((bfd *, const SYMR *, PTR));
+ void (*swap_opt_out) PARAMS ((bfd *, const OPTR *, PTR));
+ void (*swap_fdr_out) PARAMS ((bfd *, const FDR *, PTR));
+ void (*swap_rfd_out) PARAMS ((bfd *, const RFDT *, PTR));
+ void (*swap_ext_out) PARAMS ((bfd *, const EXTR *, PTR));
+ void (*swap_tir_out) PARAMS ((int, const TIR *, struct tir_ext *));
+ void (*swap_rndx_out) PARAMS ((int, const RNDXR *, struct rndx_ext *));
+ /* Function to read symbol data and set up pointers in
+ ecoff_debug_info structure. The section argument is used for
+ ELF, not straight ECOFF. */
+ boolean (*read_debug_info) PARAMS ((bfd *, asection *,
+ struct ecoff_debug_info *));
+};
+
+#endif /* ! defined (ECOFF_H) */
diff --git a/gnu/usr.bin/gdb/gdb/coff/i386.h b/gnu/usr.bin/gdb/gdb/coff/i386.h
new file mode 100644
index 0000000..3c82229
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/coff/i386.h
@@ -0,0 +1,221 @@
+/*** coff information for Intel 386/486. */
+
+
+/********************** FILE HEADER **********************/
+
+struct external_filehdr {
+ char f_magic[2]; /* magic number */
+ char f_nscns[2]; /* number of sections */
+ char f_timdat[4]; /* time & date stamp */
+ char f_symptr[4]; /* file pointer to symtab */
+ char f_nsyms[4]; /* number of symtab entries */
+ char f_opthdr[2]; /* sizeof(optional hdr) */
+ char f_flags[2]; /* flags */
+};
+
+
+/* Bits for f_flags:
+ * F_RELFLG relocation info stripped from file
+ * F_EXEC file is executable (no unresolved external references)
+ * F_LNNO line numbers stripped from file
+ * F_LSYMS local symbols stripped from file
+ * F_AR32WR file has byte ordering of an AR32WR machine (e.g. vax)
+ */
+
+#define F_RELFLG (0x0001)
+#define F_EXEC (0x0002)
+#define F_LNNO (0x0004)
+#define F_LSYMS (0x0008)
+
+
+
+#define I386MAGIC 0x14c
+#define I386PTXMAGIC 0x154
+#define I386AIXMAGIC 0x175
+
+/* This is Lynx's all-platform magic number for executables. */
+
+#define LYNXCOFFMAGIC 0415
+
+#define I386BADMAG(x) (((x).f_magic != I386MAGIC) \
+ && (x).f_magic != I386AIXMAGIC \
+ && (x).f_magic != I386PTXMAGIC \
+ && (x).f_magic != LYNXCOFFMAGIC)
+
+#define FILHDR struct external_filehdr
+#define FILHSZ sizeof(FILHDR)
+
+
+/********************** AOUT "OPTIONAL HEADER" **********************/
+
+
+typedef struct
+{
+ char magic[2]; /* type of file */
+ char vstamp[2]; /* version stamp */
+ char tsize[4]; /* text size in bytes, padded to FW bdry*/
+ char dsize[4]; /* initialized data " " */
+ char bsize[4]; /* uninitialized data " " */
+ char entry[4]; /* entry pt. */
+ char text_start[4]; /* base of text used for this file */
+ char data_start[4]; /* base of data used for this file */
+}
+AOUTHDR;
+
+
+#define AOUTSZ (sizeof(AOUTHDR))
+
+#define OMAGIC 0404 /* object files, eg as output */
+#define ZMAGIC 0413 /* demand load format, eg normal ld output */
+#define STMAGIC 0401 /* target shlib */
+#define SHMAGIC 0443 /* host shlib */
+
+
+/********************** SECTION HEADER **********************/
+
+
+struct external_scnhdr {
+ char s_name[8]; /* section name */
+ char s_paddr[4]; /* physical address, aliased s_nlib */
+ char s_vaddr[4]; /* virtual address */
+ char s_size[4]; /* section size */
+ char s_scnptr[4]; /* file ptr to raw data for section */
+ char s_relptr[4]; /* file ptr to relocation */
+ char s_lnnoptr[4]; /* file ptr to line numbers */
+ char s_nreloc[2]; /* number of relocation entries */
+ char s_nlnno[2]; /* number of line number entries*/
+ char s_flags[4]; /* flags */
+};
+
+#define SCNHDR struct external_scnhdr
+#define SCNHSZ sizeof(SCNHDR)
+
+/*
+ * names of "special" sections
+ */
+#define _TEXT ".text"
+#define _DATA ".data"
+#define _BSS ".bss"
+#define _COMMENT ".comment"
+#define _LIB ".lib"
+
+/********************** LINE NUMBERS **********************/
+
+/* 1 line number entry for every "breakpointable" source line in a section.
+ * Line numbers are grouped on a per function basis; first entry in a function
+ * grouping will have l_lnno = 0 and in place of physical address will be the
+ * symbol table index of the function name.
+ */
+struct external_lineno {
+ union {
+ char l_symndx[4]; /* function name symbol index, iff l_lnno == 0*/
+ char l_paddr[4]; /* (physical) address of line number */
+ } l_addr;
+ char l_lnno[2]; /* line number */
+};
+
+
+#define LINENO struct external_lineno
+#define LINESZ 6
+
+
+/********************** SYMBOLS **********************/
+
+#define E_SYMNMLEN 8 /* # characters in a symbol name */
+#define E_FILNMLEN 14 /* # characters in a file name */
+#define E_DIMNUM 4 /* # array dimensions in auxiliary entry */
+
+struct external_syment
+{
+ union {
+ char e_name[E_SYMNMLEN];
+ struct {
+ char e_zeroes[4];
+ char e_offset[4];
+ } e;
+ } e;
+ char e_value[4];
+ char e_scnum[2];
+ char e_type[2];
+ char e_sclass[1];
+ char e_numaux[1];
+};
+
+#define N_BTMASK (0xf)
+#define N_TMASK (0x30)
+#define N_BTSHFT (4)
+#define N_TSHIFT (2)
+
+union external_auxent {
+ struct {
+ char x_tagndx[4]; /* str, un, or enum tag indx */
+ union {
+ struct {
+ char x_lnno[2]; /* declaration line number */
+ char x_size[2]; /* str/union/array size */
+ } x_lnsz;
+ char x_fsize[4]; /* size of function */
+ } x_misc;
+ union {
+ struct { /* if ISFCN, tag, or .bb */
+ char x_lnnoptr[4]; /* ptr to fcn line # */
+ char x_endndx[4]; /* entry ndx past block end */
+ } x_fcn;
+ struct { /* if ISARY, up to 4 dimen. */
+ char x_dimen[E_DIMNUM][2];
+ } x_ary;
+ } x_fcnary;
+ char x_tvndx[2]; /* tv index */
+ } x_sym;
+
+ union {
+ char x_fname[E_FILNMLEN];
+ struct {
+ char x_zeroes[4];
+ char x_offset[4];
+ } x_n;
+ } x_file;
+
+ struct {
+ char x_scnlen[4]; /* section length */
+ char x_nreloc[2]; /* # relocation entries */
+ char x_nlinno[2]; /* # line numbers */
+ } x_scn;
+
+ struct {
+ char x_tvfill[4]; /* tv fill value */
+ char x_tvlen[2]; /* length of .tv */
+ char x_tvran[2][2]; /* tv range */
+ } x_tv; /* info about .tv section (in auxent of symbol .tv)) */
+
+
+};
+
+#define SYMENT struct external_syment
+#define SYMESZ 18
+#define AUXENT union external_auxent
+#define AUXESZ 18
+
+
+# define _ETEXT "etext"
+
+
+/********************** RELOCATION DIRECTIVES **********************/
+
+
+
+struct external_reloc {
+ char r_vaddr[4];
+ char r_symndx[4];
+ char r_type[2];
+};
+
+
+#define RELOC struct external_reloc
+#define RELSZ 10
+
+#define DEFAULT_DATA_SECTION_ALIGNMENT 4
+#define DEFAULT_BSS_SECTION_ALIGNMENT 4
+#define DEFAULT_TEXT_SECTION_ALIGNMENT 4
+/* For new sections we havn't heard of before */
+#define DEFAULT_SECTION_ALIGNMENT 4
diff --git a/gnu/usr.bin/gdb/gdb/coff/internal.h b/gnu/usr.bin/gdb/gdb/coff/internal.h
new file mode 100644
index 0000000..78d7b93
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/coff/internal.h
@@ -0,0 +1,542 @@
+/* Internal format of COFF object file data structures, for GNU BFD.
+ This file is part of BFD, the Binary File Descriptor library. */
+
+/* First, make "signed char" work, even on old compilers. */
+#ifndef signed
+#ifndef __STDC__
+#define signed /**/
+#endif
+#endif
+
+/********************** FILE HEADER **********************/
+struct internal_filehdr
+{
+ unsigned short f_magic; /* magic number */
+ unsigned short f_nscns; /* number of sections */
+ long f_timdat; /* time & date stamp */
+ bfd_vma f_symptr; /* file pointer to symtab */
+ long f_nsyms; /* number of symtab entries */
+ unsigned short f_opthdr; /* sizeof(optional hdr) */
+ unsigned short f_flags; /* flags */
+};
+
+/* Bits for f_flags:
+ * F_RELFLG relocation info stripped from file
+ * F_EXEC file is executable (no unresolved external references)
+ * F_LNNO line numbers stripped from file
+ * F_LSYMS local symbols stripped from file
+ * F_AR16WR file is 16-bit little-endian
+ * F_AR32WR file is 32-bit little-endian
+ * F_AR32W file is 32-bit big-endian
+ * F_DYNLOAD rs/6000 aix: dynamically loadable w/imports & exports
+ * F_SHROBJ rs/6000 aix: file is a shared object
+ */
+
+#define F_RELFLG (0x0001)
+#define F_EXEC (0x0002)
+#define F_LNNO (0x0004)
+#define F_LSYMS (0x0008)
+#define F_AR16WR (0x0080)
+#define F_AR32WR (0x0100)
+#define F_AR32W (0x0200)
+#define F_DYNLOAD (0x1000)
+#define F_SHROBJ (0x2000)
+
+/********************** AOUT "OPTIONAL HEADER" **********************/
+struct internal_aouthdr
+{
+ short magic; /* type of file */
+ short vstamp; /* version stamp */
+ bfd_vma tsize; /* text size in bytes, padded to FW bdry*/
+ bfd_vma dsize; /* initialized data " " */
+ bfd_vma bsize; /* uninitialized data " " */
+ bfd_vma entry; /* entry pt. */
+ bfd_vma text_start; /* base of text used for this file */
+ bfd_vma data_start; /* base of data used for this file */
+
+ /* i960 stuff */
+ unsigned long tagentries; /* number of tag entries to follow */
+
+ /* RS/6000 stuff */
+ unsigned long o_toc; /* address of TOC */
+ short o_snentry; /* section number for entry point */
+ short o_sntext; /* section number for text */
+ short o_sndata; /* section number for data */
+ short o_sntoc; /* section number for toc */
+ short o_snloader; /* section number for loader section */
+ short o_snbss; /* section number for bss */
+ short o_algntext; /* max alignment for text */
+ short o_algndata; /* max alignment for data */
+ short o_modtype; /* Module type field, 1R,RE,RO */
+ unsigned long o_maxstack; /* max stack size allowed. */
+
+ /* ECOFF stuff */
+ bfd_vma bss_start; /* Base of bss section. */
+ bfd_vma gp_value; /* GP register value. */
+ unsigned long gprmask; /* General registers used. */
+ unsigned long cprmask[4]; /* Coprocessor registers used. */
+ unsigned long fprmask; /* Floating pointer registers used. */
+
+ /* Apollo stuff */
+ long o_inlib; /* inlib data */
+ long o_sri; /* Static Resource Information */
+ long vid[2]; /* Version id */
+};
+
+/********************** STORAGE CLASSES **********************/
+
+/* This used to be defined as -1, but now n_sclass is unsigned. */
+#define C_EFCN 0xff /* physical end of function */
+#define C_NULL 0
+#define C_AUTO 1 /* automatic variable */
+#define C_EXT 2 /* external symbol */
+#define C_STAT 3 /* static */
+#define C_REG 4 /* register variable */
+#define C_EXTDEF 5 /* external definition */
+#define C_LABEL 6 /* label */
+#define C_ULABEL 7 /* undefined label */
+#define C_MOS 8 /* member of structure */
+#define C_ARG 9 /* function argument */
+#define C_STRTAG 10 /* structure tag */
+#define C_MOU 11 /* member of union */
+#define C_UNTAG 12 /* union tag */
+#define C_TPDEF 13 /* type definition */
+#define C_USTATIC 14 /* undefined static */
+#define C_ENTAG 15 /* enumeration tag */
+#define C_MOE 16 /* member of enumeration */
+#define C_REGPARM 17 /* register parameter */
+#define C_FIELD 18 /* bit field */
+#define C_AUTOARG 19 /* auto argument */
+#define C_LASTENT 20 /* dummy entry (end of block) */
+#define C_BLOCK 100 /* ".bb" or ".eb" */
+#define C_FCN 101 /* ".bf" or ".ef" */
+#define C_EOS 102 /* end of structure */
+#define C_FILE 103 /* file name */
+#define C_LINE 104 /* line # reformatted as symbol table entry */
+#define C_ALIAS 105 /* duplicate tag */
+#define C_HIDDEN 106 /* ext symbol in dmert public lib */
+
+ /* New storage classes for 80960 */
+
+/* C_LEAFPROC is obsolete. Use C_LEAFEXT or C_LEAFSTAT */
+#define C_LEAFPROC 108 /* Leaf procedure, "call" via BAL */
+
+#define C_SCALL 107 /* Procedure reachable via system call */
+#define C_LEAFEXT 108 /* External leaf */
+#define C_LEAFSTAT 113 /* Static leaf */
+#define C_OPTVAR 109 /* Optimized variable */
+#define C_DEFINE 110 /* Preprocessor #define */
+#define C_PRAGMA 111 /* Advice to compiler or linker */
+#define C_SEGMENT 112 /* 80960 segment name */
+
+ /* Storage classes for m88k */
+#define C_SHADOW 107 /* shadow symbol */
+#define C_VERSION 108 /* coff version symbol */
+
+ /* New storage classes for RS/6000 */
+#define C_HIDEXT 107 /* Un-named external symbol */
+#define C_BINCL 108 /* Marks beginning of include file */
+#define C_EINCL 109 /* Marks ending of include file */
+
+ /* storage classes for stab symbols for RS/6000 */
+#define C_GSYM (0x80)
+#define C_LSYM (0x81)
+#define C_PSYM (0x82)
+#define C_RSYM (0x83)
+#define C_RPSYM (0x84)
+#define C_STSYM (0x85)
+#define C_TCSYM (0x86)
+#define C_BCOMM (0x87)
+#define C_ECOML (0x88)
+#define C_ECOMM (0x89)
+#define C_DECL (0x8c)
+#define C_ENTRY (0x8d)
+#define C_FUN (0x8e)
+#define C_BSTAT (0x8f)
+#define C_ESTAT (0x90)
+
+/********************** SECTION HEADER **********************/
+struct internal_scnhdr
+{
+ char s_name[8]; /* section name */
+ bfd_vma s_paddr; /* physical address, aliased s_nlib */
+ bfd_vma s_vaddr; /* virtual address */
+ bfd_vma s_size; /* section size */
+ bfd_vma s_scnptr; /* file ptr to raw data for section */
+ bfd_vma s_relptr; /* file ptr to relocation */
+ bfd_vma s_lnnoptr; /* file ptr to line numbers */
+ unsigned long s_nreloc; /* number of relocation entries */
+ unsigned long s_nlnno; /* number of line number entries*/
+ long s_flags; /* flags */
+ long s_align; /* used on I960 */
+};
+
+/*
+ * s_flags "type"
+ */
+#define STYP_REG (0x0000) /* "regular": allocated, relocated, loaded */
+#define STYP_DSECT (0x0001) /* "dummy": relocated only*/
+#define STYP_NOLOAD (0x0002) /* "noload": allocated, relocated, not loaded */
+#define STYP_GROUP (0x0004) /* "grouped": formed of input sections */
+#define STYP_PAD (0x0008) /* "padding": not allocated, not relocated, loaded */
+#define STYP_COPY (0x0010) /* "copy": for decision function used by field update; not allocated, not relocated,
+ loaded; reloc & lineno entries processed normally */
+#define STYP_TEXT (0x0020) /* section contains text only */
+#define S_SHRSEG (0x0020) /* In 3b Update files (output of ogen), sections which appear in SHARED segments of the Pfile
+ will have the S_SHRSEG flag set by ogen, to inform dufr that updating 1 copy of the proc. will
+ update all process invocations. */
+#define STYP_DATA (0x0040) /* section contains data only */
+#define STYP_BSS (0x0080) /* section contains bss only */
+#define S_NEWFCN (0x0100) /* In a minimal file or an update file, a new function (as compared with a replaced function) */
+#define STYP_INFO (0x0200) /* comment: not allocated not relocated, not loaded */
+#define STYP_OVER (0x0400) /* overlay: relocated not allocated or loaded */
+#define STYP_LIB (0x0800) /* for .lib: same as INFO */
+#define STYP_MERGE (0x2000) /* merge section -- combines with text, data or bss sections only */
+#define STYP_REVERSE_PAD (0x4000) /* section will be padded with no-op instructions wherever padding is necessary and there is a
+
+ word of contiguous bytes
+ beginning on a word boundary. */
+
+#define STYP_LIT 0x8020 /* Literal data (like STYP_TEXT) */
+/********************** LINE NUMBERS **********************/
+
+/* 1 line number entry for every "breakpointable" source line in a section.
+ * Line numbers are grouped on a per function basis; first entry in a function
+ * grouping will have l_lnno = 0 and in place of physical address will be the
+ * symbol table index of the function name.
+ */
+
+struct internal_lineno
+{
+ union
+ {
+ long l_symndx; /* function name symbol index, iff l_lnno == 0*/
+ long l_paddr; /* (physical) address of line number */
+ } l_addr;
+ unsigned long l_lnno; /* line number */
+};
+
+/********************** SYMBOLS **********************/
+
+#define SYMNMLEN 8 /* # characters in a symbol name */
+#define FILNMLEN 14 /* # characters in a file name */
+#define DIMNUM 4 /* # array dimensions in auxiliary entry */
+
+struct internal_syment
+{
+ union
+ {
+ char _n_name[SYMNMLEN]; /* old COFF version */
+ struct
+ {
+ long _n_zeroes; /* new == 0 */
+ long _n_offset; /* offset into string table */
+ } _n_n;
+ char *_n_nptr[2]; /* allows for overlaying */
+ } _n;
+ long n_value; /* value of symbol */
+ short n_scnum; /* section number */
+ unsigned short n_flags; /* copy of flags from filhdr */
+ unsigned short n_type; /* type and derived type */
+ unsigned char n_sclass; /* storage class */
+ char n_numaux; /* number of aux. entries */
+};
+
+#define n_name _n._n_name
+#define n_zeroes _n._n_n._n_zeroes
+#define n_offset _n._n_n._n_offset
+
+
+/* Relocatable symbols have number of the section in which they are defined,
+ or one of the following: */
+
+#define N_UNDEF ((short)0) /* undefined symbol */
+#define N_ABS ((short)-1) /* value of symbol is absolute */
+#define N_DEBUG ((short)-2) /* debugging symbol -- value is meaningless */
+#define N_TV ((short)-3) /* indicates symbol needs preload transfer vector */
+#define P_TV ((short)-4) /* indicates symbol needs postload transfer vector*/
+
+/*
+ * Type of a symbol, in low N bits of the word
+ */
+#define T_NULL 0
+#define T_VOID 1 /* function argument (only used by compiler) */
+#define T_CHAR 2 /* character */
+#define T_SHORT 3 /* short integer */
+#define T_INT 4 /* integer */
+#define T_LONG 5 /* long integer */
+#define T_FLOAT 6 /* floating point */
+#define T_DOUBLE 7 /* double word */
+#define T_STRUCT 8 /* structure */
+#define T_UNION 9 /* union */
+#define T_ENUM 10 /* enumeration */
+#define T_MOE 11 /* member of enumeration*/
+#define T_UCHAR 12 /* unsigned character */
+#define T_USHORT 13 /* unsigned short */
+#define T_UINT 14 /* unsigned integer */
+#define T_ULONG 15 /* unsigned long */
+#define T_LNGDBL 16 /* long double */
+
+/*
+ * derived types, in n_type
+*/
+#define DT_NON (0) /* no derived type */
+#define DT_PTR (1) /* pointer */
+#define DT_FCN (2) /* function */
+#define DT_ARY (3) /* array */
+
+#define BTYPE(x) ((x) & N_BTMASK)
+
+#define ISPTR(x) (((x) & N_TMASK) == (DT_PTR << N_BTSHFT))
+#define ISFCN(x) (((x) & N_TMASK) == (DT_FCN << N_BTSHFT))
+#define ISARY(x) (((x) & N_TMASK) == (DT_ARY << N_BTSHFT))
+#define ISTAG(x) ((x)==C_STRTAG||(x)==C_UNTAG||(x)==C_ENTAG)
+#define DECREF(x) ((((x)>>N_TSHIFT)&~N_BTMASK)|((x)&N_BTMASK))
+
+
+union internal_auxent
+{
+ struct
+ {
+
+ union
+ {
+ long l; /* str, un, or enum tag indx */
+ struct coff_ptr_struct *p;
+ } x_tagndx;
+
+ union
+ {
+ struct
+ {
+ unsigned short x_lnno; /* declaration line number */
+ unsigned short x_size; /* str/union/array size */
+ } x_lnsz;
+ long x_fsize; /* size of function */
+ } x_misc;
+
+ union
+ {
+ struct
+ { /* if ISFCN, tag, or .bb */
+ long x_lnnoptr; /* ptr to fcn line # */
+ union
+ { /* entry ndx past block end */
+ long l;
+ struct coff_ptr_struct *p;
+ } x_endndx;
+ } x_fcn;
+
+ struct
+ { /* if ISARY, up to 4 dimen. */
+ unsigned short x_dimen[DIMNUM];
+ } x_ary;
+ } x_fcnary;
+
+ unsigned short x_tvndx; /* tv index */
+ } x_sym;
+
+ union
+ {
+ char x_fname[FILNMLEN];
+ struct
+ {
+ long x_zeroes;
+ long x_offset;
+ } x_n;
+ } x_file;
+
+ struct
+ {
+ long x_scnlen; /* section length */
+ unsigned short x_nreloc; /* # relocation entries */
+ unsigned short x_nlinno; /* # line numbers */
+ } x_scn;
+
+ struct
+ {
+ long x_tvfill; /* tv fill value */
+ unsigned short x_tvlen; /* length of .tv */
+ unsigned short x_tvran[2]; /* tv range */
+ } x_tv; /* info about .tv section (in auxent of symbol .tv)) */
+
+ /******************************************
+ * RS/6000-specific auxent - last auxent for every external symbol
+ ******************************************/
+ struct
+ {
+ union
+ { /* csect length or enclosing csect */
+ long l;
+ struct coff_ptr_struct *p;
+ } x_scnlen;
+ long x_parmhash; /* parm type hash index */
+ unsigned short x_snhash; /* sect num with parm hash */
+ unsigned char x_smtyp; /* symbol align and type */
+ /* 0-4 - Log 2 of alignment */
+ /* 5-7 - symbol type */
+ unsigned char x_smclas; /* storage mapping class */
+ long x_stab; /* dbx stab info index */
+ unsigned short x_snstab; /* sect num with dbx stab */
+ } x_csect; /* csect definition information */
+
+/* x_smtyp values: */
+
+#define SMTYP_ALIGN(x) ((x) >> 3) /* log2 of alignment */
+#define SMTYP_SMTYP(x) ((x) & 0x7) /* symbol type */
+/* Symbol type values: */
+#define XTY_ER 0 /* External reference */
+#define XTY_SD 1 /* Csect definition */
+#define XTY_LD 2 /* Label definition */
+#define XTY_CM 3 /* .BSS */
+#define XTY_EM 4 /* Error message */
+#define XTY_US 5 /* "Reserved for internal use" */
+
+/* x_smclas values: */
+
+#define XMC_PR 0 /* Read-only program code */
+#define XMC_RO 1 /* Read-only constant */
+#define XMC_DB 2 /* Read-only debug dictionary table */
+#define XMC_TC 3 /* Read-write general TOC entry */
+#define XMC_UA 4 /* Read-write unclassified */
+#define XMC_RW 5 /* Read-write data */
+#define XMC_GL 6 /* Read-only global linkage */
+#define XMC_XO 7 /* Read-only extended operation (simulated insn) */
+#define XMC_SV 8 /* Read-only supervisor call */
+#define XMC_BS 9 /* Read-write BSS */
+#define XMC_DS 10 /* Read-write descriptor csect */
+#define XMC_UC 11 /* Read-write unnamed Fortran common */
+#define XMC_TI 12 /* Read-only traceback index csect */
+#define XMC_TB 13 /* Read-only traceback table csect */
+/* 14 ??? */
+#define XMC_TC0 15 /* Read-write TOC anchor for TOC addressability */
+
+
+ /******************************************
+ * I960-specific *2nd* aux. entry formats
+ ******************************************/
+ struct
+ {
+ /* This is a very old typo that keeps getting propagated. */
+#define x_stdindx x_stindx
+ long x_stindx; /* sys. table entry */
+ } x_sc; /* system call entry */
+
+ struct
+ {
+ unsigned long x_balntry; /* BAL entry point */
+ } x_bal; /* BAL-callable function */
+
+ struct
+ {
+ unsigned long x_timestamp; /* time stamp */
+ char x_idstring[20]; /* producer identity string */
+ } x_ident; /* Producer ident info */
+
+};
+
+/********************** RELOCATION DIRECTIVES **********************/
+
+struct internal_reloc
+{
+ bfd_vma r_vaddr; /* Virtual address of reference */
+ long r_symndx; /* Index into symbol table */
+ unsigned short r_type; /* Relocation type */
+ unsigned char r_size; /* Used by RS/6000 and ECOFF */
+ unsigned char r_extern; /* Used by ECOFF */
+ unsigned long r_offset; /* Used by Alpha ECOFF, SPARC, others */
+};
+
+#define R_RELBYTE 017
+#define R_RELWORD 020
+#define R_PCRBYTE 022
+#define R_PCRWORD 023
+#define R_PCRLONG 024
+
+#define R_DIR16 01
+#define R_DIR32 06
+#define R_PCLONG 020
+#define R_RELBYTE 017
+#define R_RELWORD 020
+
+
+
+#define R_PCR16L 128
+#define R_PCR26L 129
+#define R_VRT16 130
+#define R_HVRT16 131
+#define R_LVRT16 132
+#define R_VRT32 133
+#define R_RELLONG (0x11) /* Direct 32-bit relocation */
+#define R_IPRSHORT (0x18)
+#define R_IPRMED (0x19) /* 24-bit ip-relative relocation */
+#define R_IPRLONG (0x1a)
+#define R_OPTCALL (0x1b) /* 32-bit optimizable call (leafproc/sysproc) */
+#define R_OPTCALLX (0x1c) /* 64-bit optimizable call (leafproc/sysproc) */
+#define R_GETSEG (0x1d)
+#define R_GETPA (0x1e)
+#define R_TAGWORD (0x1f)
+#define R_JUMPTARG 0x20 /* strange 29k 00xx00xx reloc */
+
+
+#define R_MOVB1 0x41 /* Special h8 16bit or 8 bit reloc for mov.b */
+#define R_MOVB2 0x42 /* Special h8 opcode for 8bit which could be 16 */
+#define R_JMP1 0x43 /* Special h8 16bit jmp which could be pcrel */
+#define R_JMP2 0x44 /* a branch which used to be a jmp */
+#define R_RELLONG_NEG 0x45
+
+#define R_JMPL1 0x46 /* Special h8 24bit jmp which could be pcrel */
+#define R_JMPL_B8 0x47 /* a 8 bit pcrel which used to be a jmp */
+
+#define R_MOVLB1 0x48 /* Special h8 24bit or 8 bit reloc for mov.b */
+#define R_MOVLB2 0x49 /* Special h8 opcode for 8bit which could be 24 */
+
+/* Z8k modes */
+#define R_IMM16 0x01 /* 16 bit abs */
+#define R_JR 0x02 /* jr 8 bit disp */
+#define R_IMM4L 0x23 /* low nibble */
+#define R_IMM8 0x22 /* 8 bit abs */
+#define R_IMM32 R_RELLONG /* 32 bit abs */
+#define R_CALL R_DA /* Absolute address which could be a callr */
+#define R_JP R_DA /* Absolute address which could be a jp */
+#define R_REL16 0x04 /* 16 bit PC rel */
+#define R_CALLR 0x05 /* callr 12 bit disp */
+#define R_SEG 0x10 /* set if in segmented mode */
+#define R_IMM4H 0x24 /* high nibble */
+#define R_DISP7 0x25 /* djnz displacement */
+
+/* H8500 modes */
+
+#define R_H8500_IMM8 1 /* 8 bit immediate */
+#define R_H8500_IMM16 2 /* 16 bit immediate */
+#define R_H8500_PCREL8 3 /* 8 bit pcrel */
+#define R_H8500_PCREL16 4 /* 16 bit pcrel */
+#define R_H8500_HIGH8 5 /* high 8 bits of 24 bit address */
+#define R_H8500_LOW16 7 /* low 16 bits of 24 bit immediate */
+#define R_H8500_IMM24 6 /* 24 bit immediate */
+#define R_H8500_IMM32 8 /* 32 bit immediate */
+#define R_H8500_HIGH16 9 /* high 16 bits of 32 bit immediate */
+
+/* SH modes */
+
+#define R_SH_PCREL8 3 /* 8 bit pcrel */
+#define R_SH_PCREL16 4 /* 16 bit pcrel */
+#define R_SH_HIGH8 5 /* high 8 bits of 24 bit address */
+#define R_SH_LOW16 7 /* low 16 bits of 24 bit immediate */
+#define R_SH_IMM24 6 /* 24 bit immediate */
+#define R_SH_PCDISP8BY4 9 /* PC rel 8 bits *4 +ve */
+#define R_SH_PCDISP8BY2 10 /* PC rel 8 bits *2 +ve */
+#define R_SH_PCDISP8 11 /* 8 bit branch */
+#define R_SH_PCDISP 12 /* 12 bit branch */
+#define R_SH_IMM32 14 /* 32 bit immediate */
+#define R_SH_IMM8 16
+#define R_SH_IMM8BY2 17
+#define R_SH_IMM8BY4 18
+#define R_SH_IMM4 19
+#define R_SH_IMM4BY2 20
+#define R_SH_IMM4BY4 21
+#define R_SH_PCRELIMM8BY2 22
+#define R_SH_PCRELIMM8BY4 23
+#define R_SH_IMM16 24 /* 16 bit immediate */
+
+
diff --git a/gnu/usr.bin/gdb/gdb/coff/sym.h b/gnu/usr.bin/gdb/gdb/coff/sym.h
new file mode 100644
index 0000000..e84caed
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/coff/sym.h
@@ -0,0 +1,477 @@
+/* Declarations of internal format of MIPS ECOFF symbols.
+ Originally contributed by MIPS Computer Systems and Third Eye Software.
+ Changes contributed by Cygnus Support are in the public domain.
+
+ This file is just aggregated with the files that make up the GNU
+ release; it is not considered part of GAS, GDB, or other GNU
+ programs. */
+
+/*
+ * |-----------------------------------------------------------|
+ * | Copyright (c) 1992, 1991, 1990 MIPS Computer Systems, Inc.|
+ * | MIPS Computer Systems, Inc. grants reproduction and use |
+ * | rights to all parties, PROVIDED that this comment is |
+ * | maintained in the copy. |
+ * |-----------------------------------------------------------|
+ */
+#ifndef _SYM_H
+#define _SYM_H
+
+/* (C) Copyright 1984 by Third Eye Software, Inc.
+ *
+ * Third Eye Software, Inc. grants reproduction and use rights to
+ * all parties, PROVIDED that this comment is maintained in the copy.
+ *
+ * Third Eye makes no claims about the applicability of this
+ * symbol table to a particular use.
+ */
+
+/*
+ * This file contains the definition of the Third Eye Symbol Table.
+ *
+ * Symbols are assumed to be in 'encounter order' - i.e. the order that
+ * the things they represent were encountered by the compiler/assembler/loader.
+ * EXCEPT for globals! These are assumed to be bunched together,
+ * probably right after the last 'normal' symbol. Globals ARE sorted
+ * in ascending order.
+ *
+ * -----------------------------------------------------------------------
+ * A brief word about Third Eye naming/use conventions:
+ *
+ * All arrays and index's are 0 based.
+ * All "ifooMax" values are the highest legal value PLUS ONE. This makes
+ * them good for allocating arrays, etc. All checks are "ifoo < ifooMax".
+ *
+ * "isym" Index into the SYMbol table.
+ * "ipd" Index into the Procedure Descriptor array.
+ * "ifd" Index into the File Descriptor array.
+ * "iss" Index into String Space.
+ * "cb" Count of Bytes.
+ * "rgPd" array whose domain is "0..ipdMax-1" and RanGe is PDR.
+ * "rgFd" array whose domain is "0..ifdMax-1" and RanGe is FDR.
+ */
+
+
+/*
+ * Symbolic Header (HDR) structure.
+ * As long as all the pointers are set correctly,
+ * we don't care WHAT order the various sections come out in!
+ *
+ * A file produced solely for the use of CDB will probably NOT have
+ * any instructions or data areas in it, as these are available
+ * in the original.
+ */
+
+typedef struct {
+ short magic; /* to verify validity of the table */
+ short vstamp; /* version stamp */
+ long ilineMax; /* number of line number entries */
+ bfd_vma cbLine; /* number of bytes for line number entries */
+ bfd_vma cbLineOffset; /* offset to start of line number entries*/
+ long idnMax; /* max index into dense number table */
+ bfd_vma cbDnOffset; /* offset to start dense number table */
+ long ipdMax; /* number of procedures */
+ bfd_vma cbPdOffset; /* offset to procedure descriptor table */
+ long isymMax; /* number of local symbols */
+ bfd_vma cbSymOffset; /* offset to start of local symbols*/
+ long ioptMax; /* max index into optimization symbol entries */
+ bfd_vma cbOptOffset; /* offset to optimization symbol entries */
+ long iauxMax; /* number of auxillary symbol entries */
+ bfd_vma cbAuxOffset; /* offset to start of auxillary symbol entries*/
+ long issMax; /* max index into local strings */
+ bfd_vma cbSsOffset; /* offset to start of local strings */
+ long issExtMax; /* max index into external strings */
+ bfd_vma cbSsExtOffset; /* offset to start of external strings */
+ long ifdMax; /* number of file descriptor entries */
+ bfd_vma cbFdOffset; /* offset to file descriptor table */
+ long crfd; /* number of relative file descriptor entries */
+ bfd_vma cbRfdOffset; /* offset to relative file descriptor table */
+ long iextMax; /* max index into external symbols */
+ bfd_vma cbExtOffset; /* offset to start of external symbol entries*/
+ /* If you add machine dependent fields, add them here */
+ } HDRR, *pHDRR;
+#define cbHDRR sizeof(HDRR)
+#define hdrNil ((pHDRR)0)
+
+/*
+ * The FDR and PDR structures speed mapping of address <-> name.
+ * They are sorted in ascending memory order and are kept in
+ * memory by CDB at runtime.
+ */
+
+/*
+ * File Descriptor
+ *
+ * There is one of these for EVERY FILE, whether compiled with
+ * full debugging symbols or not. The name of a file should be
+ * the path name given to the compiler. This allows the user
+ * to simply specify the names of the directories where the COMPILES
+ * were done, and we will be able to find their files.
+ * A field whose comment starts with "R - " indicates that it will be
+ * setup at runtime.
+ */
+typedef struct fdr {
+ bfd_vma adr; /* memory address of beginning of file */
+ long rss; /* file name (of source, if known) */
+ long issBase; /* file's string space */
+ bfd_vma cbSs; /* number of bytes in the ss */
+ long isymBase; /* beginning of symbols */
+ long csym; /* count file's of symbols */
+ long ilineBase; /* file's line symbols */
+ long cline; /* count of file's line symbols */
+ long ioptBase; /* file's optimization entries */
+ long copt; /* count of file's optimization entries */
+ unsigned short ipdFirst;/* start of procedures for this file */
+ short cpd; /* count of procedures for this file */
+ long iauxBase; /* file's auxiliary entries */
+ long caux; /* count of file's auxiliary entries */
+ long rfdBase; /* index into the file indirect table */
+ long crfd; /* count file indirect entries */
+ unsigned lang: 5; /* language for this file */
+ unsigned fMerge : 1; /* whether this file can be merged */
+ unsigned fReadin : 1; /* true if it was read in (not just created) */
+ unsigned fBigendian : 1;/* if set, was compiled on big endian machine */
+ /* aux's will be in compile host's sex */
+ unsigned glevel : 2; /* level this file was compiled with */
+ unsigned reserved : 22; /* reserved for future use */
+ bfd_vma cbLineOffset; /* byte offset from header for this file ln's */
+ bfd_vma cbLine; /* size of lines for this file */
+ } FDR, *pFDR;
+#define cbFDR sizeof(FDR)
+#define fdNil ((pFDR)0)
+#define ifdNil -1
+#define ifdTemp 0
+#define ilnNil -1
+
+
+/*
+ * Procedure Descriptor
+ *
+ * There is one of these for EVERY TEXT LABEL.
+ * If a procedure is in a file with full symbols, then isym
+ * will point to the PROC symbols, else it will point to the
+ * global symbol for the label.
+ */
+
+typedef struct pdr {
+ bfd_vma adr; /* memory address of start of procedure */
+ long isym; /* start of local symbol entries */
+ long iline; /* start of line number entries*/
+ long regmask; /* save register mask */
+ long regoffset; /* save register offset */
+ long iopt; /* start of optimization symbol entries*/
+ long fregmask; /* save floating point register mask */
+ long fregoffset; /* save floating point register offset */
+ long frameoffset; /* frame size */
+ short framereg; /* frame pointer register */
+ short pcreg; /* offset or reg of return pc */
+ long lnLow; /* lowest line in the procedure */
+ long lnHigh; /* highest line in the procedure */
+ bfd_vma cbLineOffset; /* byte offset for this procedure from the fd base */
+ /* These fields are new for 64 bit ECOFF. */
+ unsigned gp_prologue : 8; /* byte size of GP prologue */
+ unsigned gp_used : 1; /* true if the procedure uses GP */
+ unsigned reg_frame : 1; /* true if register frame procedure */
+ unsigned reserved : 14; /* reserved: must be zero */
+ unsigned localoff : 8; /* offset of local variables from vfp */
+ } PDR, *pPDR;
+#define cbPDR sizeof(PDR)
+#define pdNil ((pPDR) 0)
+#define ipdNil -1
+
+/*
+ * The structure of the runtime procedure descriptor created by the loader
+ * for use by the static exception system.
+ */
+typedef struct runtime_pdr {
+ bfd_vma adr; /* memory address of start of procedure */
+ long regmask; /* save register mask */
+ long regoffset; /* save register offset */
+ long fregmask; /* save floating point register mask */
+ long fregoffset; /* save floating point register offset */
+ long frameoffset; /* frame size */
+ short framereg; /* frame pointer register */
+ short pcreg; /* offset or reg of return pc */
+ long irpss; /* index into the runtime string table */
+ long reserved;
+ struct exception_info *exception_info;/* pointer to exception array */
+} RPDR, *pRPDR;
+#define cbRPDR sizeof(RPDR)
+#define rpdNil ((pRPDR) 0)
+
+/*
+ * Line Numbers
+ *
+ * Line Numbers are segregated from the normal symbols because they
+ * are [1] smaller , [2] are of no interest to your
+ * average loader, and [3] are never needed in the middle of normal
+ * scanning and therefore slow things down.
+ *
+ * By definition, the first LINER for any given procedure will have
+ * the first line of a procedure and represent the first address.
+ */
+
+typedef long LINER, *pLINER;
+#define lineNil ((pLINER)0)
+#define cbLINER sizeof(LINER)
+#define ilineNil -1
+
+
+
+/*
+ * The Symbol Structure (GFW, to those who Know!)
+ */
+
+typedef struct {
+ long iss; /* index into String Space of name */
+ bfd_vma value; /* value of symbol */
+ unsigned st : 6; /* symbol type */
+ unsigned sc : 5; /* storage class - text, data, etc */
+ unsigned reserved : 1; /* reserved */
+ unsigned index : 20; /* index into sym/aux table */
+ } SYMR, *pSYMR;
+#define symNil ((pSYMR)0)
+#define cbSYMR sizeof(SYMR)
+#define isymNil -1
+#define indexNil 0xfffff
+#define issNil -1
+#define issNull 0
+
+
+/* The following converts a memory resident string to an iss.
+ * This hack is recognized in SbFIss, in sym.c of the debugger.
+ */
+#define IssFSb(sb) (0x80000000 | ((unsigned long)(sb)))
+
+/* E X T E R N A L S Y M B O L R E C O R D
+ *
+ * Same as the SYMR except it contains file context to determine where
+ * the index is.
+ */
+typedef struct ecoff_extr {
+ unsigned jmptbl:1; /* symbol is a jump table entry for shlibs */
+ unsigned cobol_main:1; /* symbol is a cobol main procedure */
+ unsigned weakext:1; /* symbol is weak external */
+ unsigned reserved:13; /* reserved for future use */
+ int ifd; /* where the iss and index fields point into */
+ SYMR asym; /* symbol for the external */
+ } EXTR, *pEXTR;
+#define extNil ((pEXTR)0)
+#define cbEXTR sizeof(EXTR)
+
+
+/* A U X I L L A R Y T Y P E I N F O R M A T I O N */
+
+/*
+ * Type Information Record
+ */
+typedef struct {
+ unsigned fBitfield : 1; /* set if bit width is specified */
+ unsigned continued : 1; /* indicates additional TQ info in next AUX */
+ unsigned bt : 6; /* basic type */
+ unsigned tq4 : 4;
+ unsigned tq5 : 4;
+ /* ---- 16 bit boundary ---- */
+ unsigned tq0 : 4;
+ unsigned tq1 : 4; /* 6 type qualifiers - tqPtr, etc. */
+ unsigned tq2 : 4;
+ unsigned tq3 : 4;
+ } TIR, *pTIR;
+#define cbTIR sizeof(TIR)
+#define tiNil ((pTIR)0)
+#define itqMax 6
+
+/*
+ * Relative symbol record
+ *
+ * If the rfd field is 4095, the index field indexes into the global symbol
+ * table.
+ */
+
+typedef struct {
+ unsigned rfd : 12; /* index into the file indirect table */
+ unsigned index : 20; /* index int sym/aux/iss tables */
+ } RNDXR, *pRNDXR;
+#define cbRNDXR sizeof(RNDXR)
+#define rndxNil ((pRNDXR)0)
+
+/* dense numbers or sometimes called block numbers are stored in this type,
+ * a rfd of 0xffffffff is an index into the global table.
+ */
+typedef struct {
+ unsigned long rfd; /* index into the file table */
+ unsigned long index; /* index int sym/aux/iss tables */
+ } DNR, *pDNR;
+#define cbDNR sizeof(DNR)
+#define dnNil ((pDNR)0)
+
+
+
+/*
+ * Auxillary information occurs only if needed.
+ * It ALWAYS occurs in this order when present.
+
+ isymMac used by stProc only
+ TIR type info
+ TIR additional TQ info (if first TIR was not enough)
+ rndx if (bt == btStruct,btUnion,btEnum,btSet,btRange,
+ btTypedef):
+ rsym.index == iaux for btSet or btRange
+ else rsym.index == isym
+ dimLow btRange, btSet
+ dimMac btRange, btSet
+ rndx0 As many as there are tq arrays
+ dimLow0
+ dimHigh0
+ ...
+ rndxMax-1
+ dimLowMax-1
+ dimHighMax-1
+ width in bits if (bit field), width in bits.
+ */
+#define cAuxMax (6 + (idimMax*3))
+
+/* a union of all possible info in the AUX universe */
+typedef union {
+ TIR ti; /* type information record */
+ RNDXR rndx; /* relative index into symbol table */
+ long dnLow; /* low dimension */
+ long dnHigh; /* high dimension */
+ long isym; /* symbol table index (end of proc) */
+ long iss; /* index into string space (not used) */
+ long width; /* width for non-default sized struc fields */
+ long count; /* count of ranges for variant arm */
+ } AUXU, *pAUXU;
+#define cbAUXU sizeof(AUXU)
+#define auxNil ((pAUXU)0)
+#define iauxNil -1
+
+
+/*
+ * Optimization symbols
+ *
+ * Optimization symbols contain some overlap information with the normal
+ * symbol table. In particular, the proc information
+ * is somewhat redundant but necessary to easily find the other information
+ * present.
+ *
+ * All of the offsets are relative to the beginning of the last otProc
+ */
+
+typedef struct {
+ unsigned ot: 8; /* optimization type */
+ unsigned value: 24; /* address where we are moving it to */
+ RNDXR rndx; /* points to a symbol or opt entry */
+ unsigned long offset; /* relative offset this occured */
+ } OPTR, *pOPTR;
+#define optNil ((pOPTR) 0)
+#define cbOPTR sizeof(OPTR)
+#define ioptNil -1
+
+/*
+ * File Indirect
+ *
+ * When a symbol is referenced across files the following procedure is used:
+ * 1) use the file index to get the File indirect entry.
+ * 2) use the file indirect entry to get the File descriptor.
+ * 3) add the sym index to the base of that file's sym table
+ *
+ */
+
+typedef long RFDT, *pRFDT;
+#define cbRFDT sizeof(RFDT)
+#define rfdNil -1
+
+/*
+ * The file indirect table in the mips loader is known as an array of FITs.
+ * This is done to keep the code in the loader readable in the area where
+ * these tables are merged. Note this is only a name change.
+ */
+typedef long FIT, *pFIT;
+#define cbFIT sizeof(FIT)
+#define ifiNil -1
+#define fiNil ((pFIT) 0)
+
+#ifdef _LANGUAGE_PASCAL
+#define ifdNil -1
+#define ilnNil -1
+#define ipdNil -1
+#define ilineNil -1
+#define isymNil -1
+#define indexNil 16#fffff
+#define issNil -1
+#define issNull 0
+#define itqMax 6
+#define iauxNil -1
+#define ioptNil -1
+#define rfdNil -1
+#define ifiNil -1
+#endif /* _LANGUAGE_PASCAL */
+
+
+/* Dense numbers
+ *
+ * Rather than use file index, symbol index pairs to represent symbols
+ * and globals, we use dense number so that they can be easily embeded
+ * in intermediate code and the programs that process them can
+ * use direct access tabls instead of hash table (which would be
+ * necesary otherwise because of the sparse name space caused by
+ * file index, symbol index pairs. Dense number are represented
+ * by RNDXRs.
+ */
+
+/*
+ * The following table defines the meaning of each SYM field as
+ * a function of the "st". (scD/B == scData OR scBss)
+ *
+ * Note: the value "isymMac" is used by symbols that have the concept
+ * of enclosing a block of related information. This value is the
+ * isym of the first symbol AFTER the end associated with the primary
+ * symbol. For example if a procedure was at isym==90 and had an
+ * isymMac==155, the associated end would be at isym==154, and the
+ * symbol at 155 would probably (although not necessarily) be the
+ * symbol for the next procedure. This allows rapid skipping over
+ * internal information of various sorts. "stEnd"s ALWAYS have the
+ * isym of the primary symbol that started the block.
+ *
+
+ST SC VALUE INDEX
+-------- ------ -------- ------
+stFile scText address isymMac
+stLabel scText address ---
+stGlobal scD/B address iaux
+stStatic scD/B address iaux
+stParam scAbs offset iaux
+stLocal scAbs offset iaux
+stProc scText address iaux (isymMac is first AUX)
+stStaticProc scText address iaux (isymMac is first AUX)
+
+stMember scNil ordinal --- (if member of enum)
+ (mipsread thinks the case below has a bit, not byte, offset.)
+stMember scNil byte offset iaux (if member of struct/union)
+stMember scBits bit offset iaux (bit field spec)
+
+stBlock scText address isymMac (text block)
+ (the code seems to think that rather than scNil, we see scInfo for
+ the two cases below.)
+stBlock scNil cb isymMac (struct/union member define)
+stBlock scNil cMembers isymMac (enum member define)
+
+ (New types added by SGI to simplify things:)
+stStruct scInfo cb isymMac (struct type define)
+stUnion scInfo cb isymMac (union type define)
+stEnum scInfo cMembers isymMac (enum type define)
+
+stEnd scText address isymStart
+stEnd scNil ------- isymStart (struct/union/enum)
+
+stTypedef scNil ------- iaux
+stRegReloc sc??? value old register number
+stForward sc??? new address isym to original symbol
+
+stConstant scInfo value --- (scalar)
+stConstant scInfo iss --- (complex, e.g. string)
+
+ *
+ */
+#endif
diff --git a/gnu/usr.bin/gdb/gdb/coff/symconst.h b/gnu/usr.bin/gdb/gdb/coff/symconst.h
new file mode 100644
index 0000000..54bd0fb
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/coff/symconst.h
@@ -0,0 +1,176 @@
+/* Declarations of constants for internal format of MIPS ECOFF symbols.
+ Originally contributed by MIPS Computer Systems and Third Eye Software.
+ Changes contributed by Cygnus Support are in the public domain.
+
+ This file is just aggregated with the files that make up the GNU
+ release; it is not considered part of GAS, GDB, or other GNU
+ programs. */
+
+/*
+ * |-----------------------------------------------------------|
+ * | Copyright (c) 1992, 1991, 1990 MIPS Computer Systems, Inc.|
+ * | MIPS Computer Systems, Inc. grants reproduction and use |
+ * | rights to all parties, PROVIDED that this comment is |
+ * | maintained in the copy. |
+ * |-----------------------------------------------------------|
+ */
+
+/* (C) Copyright 1984 by Third Eye Software, Inc.
+ *
+ * Third Eye Software, Inc. grants reproduction and use rights to
+ * all parties, PROVIDED that this comment is maintained in the copy.
+ *
+ * Third Eye makes no claims about the applicability of this
+ * symbol table to a particular use.
+ */
+
+/* glevels for field in FDR */
+#define GLEVEL_0 2
+#define GLEVEL_1 1
+#define GLEVEL_2 0 /* for upward compat reasons. */
+#define GLEVEL_3 3
+
+/* magic number fo symheader */
+#define magicSym 0x7009
+/* The Alpha uses this value instead, for some reason. */
+#define magicSym2 0x1992
+
+/* Language codes */
+#define langC 0
+#define langPascal 1
+#define langFortran 2
+#define langAssembler 3 /* one Assembley inst might map to many mach */
+#define langMachine 4
+#define langNil 5
+#define langAda 6
+#define langPl1 7
+#define langCobol 8
+#define langStdc 9 /* FIXME: Collides with SGI langCplusplus */
+#define langCplusplus 9 /* FIXME: Collides with langStdc */
+#define langCplusplusV2 10 /* SGI addition */
+#define langMax 11 /* maximun allowed 32 -- 5 bits */
+
+/* The following are value definitions for the fields in the SYMR */
+
+/*
+ * Storage Classes
+ */
+
+#define scNil 0
+#define scText 1 /* text symbol */
+#define scData 2 /* initialized data symbol */
+#define scBss 3 /* un-initialized data symbol */
+#define scRegister 4 /* value of symbol is register number */
+#define scAbs 5 /* value of symbol is absolute */
+#define scUndefined 6 /* who knows? */
+#define scCdbLocal 7 /* variable's value is IN se->va.?? */
+#define scBits 8 /* this is a bit field */
+#define scCdbSystem 9 /* variable's value is IN CDB's address space */
+#define scDbx 9 /* overlap dbx internal use */
+#define scRegImage 10 /* register value saved on stack */
+#define scInfo 11 /* symbol contains debugger information */
+#define scUserStruct 12 /* address in struct user for current process */
+#define scSData 13 /* load time only small data */
+#define scSBss 14 /* load time only small common */
+#define scRData 15 /* load time only read only data */
+#define scVar 16 /* Var parameter (fortran,pascal) */
+#define scCommon 17 /* common variable */
+#define scSCommon 18 /* small common */
+#define scVarRegister 19 /* Var parameter in a register */
+#define scVariant 20 /* Variant record */
+#define scSUndefined 21 /* small undefined(external) data */
+#define scInit 22 /* .init section symbol */
+#define scBasedVar 23 /* Fortran or PL/1 ptr based var */
+#define scXData 24 /* exception handling data */
+#define scPData 25 /* Procedure section */
+#define scFini 26 /* .fini section */
+#define scMax 32
+
+
+/*
+ * Symbol Types
+ */
+
+#define stNil 0 /* Nuthin' special */
+#define stGlobal 1 /* external symbol */
+#define stStatic 2 /* static */
+#define stParam 3 /* procedure argument */
+#define stLocal 4 /* local variable */
+#define stLabel 5 /* label */
+#define stProc 6 /* " " Procedure */
+#define stBlock 7 /* beginnning of block */
+#define stEnd 8 /* end (of anything) */
+#define stMember 9 /* member (of anything - struct/union/enum */
+#define stTypedef 10 /* type definition */
+#define stFile 11 /* file name */
+#define stRegReloc 12 /* register relocation */
+#define stForward 13 /* forwarding address */
+#define stStaticProc 14 /* load time only static procs */
+#define stConstant 15 /* const */
+#define stStaParam 16 /* Fortran static parameters */
+ /* These new symbol types have been recently added to SGI machines. */
+#define stStruct 26 /* Beginning of block defining a struct type */
+#define stUnion 27 /* Beginning of block defining a union type */
+#define stEnum 28 /* Beginning of block defining an enum type */
+#define stIndirect 34 /* Indirect type specification */
+ /* Pseudo-symbols - internal to debugger */
+#define stStr 60 /* string */
+#define stNumber 61 /* pure number (ie. 4 NOR 2+2) */
+#define stExpr 62 /* 2+2 vs. 4 */
+#define stType 63 /* post-coersion SER */
+#define stMax 64
+
+/* definitions for fields in TIR */
+
+/* type qualifiers for ti.tq0 -> ti.(itqMax-1) */
+#define tqNil 0 /* bt is what you see */
+#define tqPtr 1 /* pointer */
+#define tqProc 2 /* procedure */
+#define tqArray 3 /* duh */
+#define tqFar 4 /* longer addressing - 8086/8 land */
+#define tqVol 5 /* volatile */
+#define tqConst 6 /* const */
+#define tqMax 8
+
+/* basic types as seen in ti.bt */
+#define btNil 0 /* undefined (also, enum members) */
+#define btAdr 1 /* address - integer same size as pointer */
+#define btChar 2 /* character */
+#define btUChar 3 /* unsigned character */
+#define btShort 4 /* short */
+#define btUShort 5 /* unsigned short */
+#define btInt 6 /* int */
+#define btUInt 7 /* unsigned int */
+#define btLong 8 /* long */
+#define btULong 9 /* unsigned long */
+#define btFloat 10 /* float (real) */
+#define btDouble 11 /* Double (real) */
+#define btStruct 12 /* Structure (Record) */
+#define btUnion 13 /* Union (variant) */
+#define btEnum 14 /* Enumerated */
+#define btTypedef 15 /* defined via a typedef, isymRef points */
+#define btRange 16 /* subrange of int */
+#define btSet 17 /* pascal sets */
+#define btComplex 18 /* fortran complex */
+#define btDComplex 19 /* fortran double complex */
+#define btIndirect 20 /* forward or unnamed typedef */
+#define btFixedDec 21 /* Fixed Decimal */
+#define btFloatDec 22 /* Float Decimal */
+#define btString 23 /* Varying Length Character String */
+#define btBit 24 /* Aligned Bit String */
+#define btPicture 25 /* Picture */
+#define btVoid 26 /* void */
+#define btLongLong 27 /* long long */
+#define btULongLong 28 /* unsigned long long */
+#define btMax 64
+
+#if (_MFG == _MIPS)
+/* optimization type codes */
+#define otNil 0
+#define otReg 1 /* move var to reg */
+#define otBlock 2 /* begin basic block */
+#define otProc 3 /* procedure */
+#define otInline 4 /* inline procedure */
+#define otEnd 5 /* whatever you started */
+#define otMax 6 /* KEEP UP TO DATE */
+#endif /* (_MFG == _MIPS) */
diff --git a/gnu/usr.bin/gdb/gdb/coffread.c b/gnu/usr.bin/gdb/gdb/coffread.c
new file mode 100644
index 0000000..b0830c9
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/coffread.c
@@ -0,0 +1,2101 @@
+/* Read coff symbol tables and convert to internal format, for GDB.
+ Contributed by David D. Johnson, Brown University (ddj@cs.brown.edu).
+ Copyright 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994
+ Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "defs.h"
+#include "symtab.h"
+#include "gdbtypes.h"
+#include "breakpoint.h"
+
+#include "bfd.h"
+#include <obstack.h>
+
+#include <string.h>
+
+#include <time.h> /* For time_t in libbfd.h. */
+#include <sys/types.h> /* For time_t, if not in time.h. */
+#include "libbfd.h" /* FIXME secret internal data from BFD */
+#include "coff/internal.h" /* Internal format of COFF symbols in BFD */
+#include "libcoff.h" /* FIXME secret internal data from BFD */
+
+#include "symfile.h"
+#include "objfiles.h"
+#include "buildsym.h"
+#include "gdb-stabs.h"
+#include "stabsread.h"
+#include "complaints.h"
+
+struct coff_symfile_info {
+ file_ptr min_lineno_offset; /* Where in file lowest line#s are */
+ file_ptr max_lineno_offset; /* 1+last byte of line#s in file */
+
+ asection *stabsect; /* Section pointer for .stab section */
+ asection *stabstrsect; /* Section pointer for .stab section */
+ asection *stabindexsect; /* Section pointer for .stab.index section */
+ char *stabstrdata;
+};
+
+/* Translate an external name string into a user-visible name. */
+#define EXTERNAL_NAME(string, abfd) \
+ (string[0] == bfd_get_symbol_leading_char(abfd)? string+1: string)
+
+/* To be an sdb debug type, type must have at least a basic or primary
+ derived type. Using this rather than checking against T_NULL is
+ said to prevent core dumps if we try to operate on Michael Bloom
+ dbx-in-coff file. */
+
+#define SDB_TYPE(type) (BTYPE(type) | (type & N_TMASK))
+
+/*
+ * Convert from an sdb register number to an internal gdb register number.
+ * This should be defined in tm.h, if REGISTER_NAMES is not set up
+ * to map one to one onto the sdb register numbers.
+ */
+#ifndef SDB_REG_TO_REGNUM
+# define SDB_REG_TO_REGNUM(value) (value)
+#endif
+
+/* Core address of start and end of text of current source file.
+ This comes from a ".text" symbol where x_nlinno > 0. */
+
+static CORE_ADDR cur_src_start_addr;
+static CORE_ADDR cur_src_end_addr;
+
+/* The addresses of the symbol table stream and number of symbols
+ of the object file we are reading (as copied into core). */
+
+static GDB_FILE *nlist_stream_global;
+static int nlist_nsyms_global;
+
+/* Vector of line number information. */
+
+static struct linetable *line_vector;
+
+/* Index of next entry to go in line_vector_index. */
+
+static int line_vector_index;
+
+/* Last line number recorded in the line vector. */
+
+static int prev_line_number;
+
+/* Number of elements allocated for line_vector currently. */
+
+static int line_vector_length;
+
+/* Pointers to scratch storage, used for reading raw symbols and auxents. */
+
+static char *temp_sym;
+static char *temp_aux;
+
+/* Local variables that hold the shift and mask values for the
+ COFF file that we are currently reading. These come back to us
+ from BFD, and are referenced by their macro names, as well as
+ internally to the BTYPE, ISPTR, ISFCN, ISARY, ISTAG, and DECREF
+ macros from ../internalcoff.h . */
+
+static unsigned local_n_btmask;
+static unsigned local_n_btshft;
+static unsigned local_n_tmask;
+static unsigned local_n_tshift;
+
+#define N_BTMASK local_n_btmask
+#define N_BTSHFT local_n_btshft
+#define N_TMASK local_n_tmask
+#define N_TSHIFT local_n_tshift
+
+/* Local variables that hold the sizes in the file of various COFF structures.
+ (We only need to know this to read them from the file -- BFD will then
+ translate the data in them, into `internal_xxx' structs in the right
+ byte order, alignment, etc.) */
+
+static unsigned local_linesz;
+static unsigned local_symesz;
+static unsigned local_auxesz;
+
+
+/* Chain of typedefs of pointers to empty struct/union types.
+ They are chained thru the SYMBOL_VALUE_CHAIN. */
+
+static struct symbol *opaque_type_chain[HASHSIZE];
+
+#if 0
+/* The type of the function we are currently reading in. This is
+ used by define_symbol to record the type of arguments to a function. */
+
+struct type *in_function_type;
+#endif
+
+/* Complaints about various problems in the file being read */
+
+struct complaint ef_complaint =
+ {"Unmatched .ef symbol(s) ignored starting at symnum %d", 0, 0};
+
+struct complaint bf_no_aux_complaint =
+ {"`.bf' symbol %d has no aux entry", 0, 0};
+
+struct complaint ef_no_aux_complaint =
+ {"`.ef' symbol %d has no aux entry", 0, 0};
+
+struct complaint lineno_complaint =
+ {"Line number pointer %d lower than start of line numbers", 0, 0};
+
+struct complaint unexpected_type_complaint =
+ {"Unexpected type for symbol %s", 0, 0};
+
+struct complaint bad_sclass_complaint =
+ {"Bad n_sclass for symbol %s", 0, 0};
+
+struct complaint misordered_blocks_complaint =
+ {"Blocks out of order at address %x", 0, 0};
+
+struct complaint tagndx_bad_complaint =
+ {"Symbol table entry for %s has bad tagndx value", 0, 0};
+
+struct complaint eb_complaint =
+ {"Mismatched .eb symbol ignored starting at symnum %d", 0, 0};
+
+/* Simplified internal version of coff symbol table information */
+
+struct coff_symbol {
+ char *c_name;
+ int c_symnum; /* symbol number of this entry */
+ int c_naux; /* 0 if syment only, 1 if syment + auxent, etc */
+ long c_value;
+ int c_sclass;
+ int c_secnum;
+ unsigned int c_type;
+};
+
+static struct type *
+coff_read_struct_type PARAMS ((int, int, int));
+
+static struct type *
+decode_base_type PARAMS ((struct coff_symbol *, unsigned int,
+ union internal_auxent *));
+
+static struct type *
+decode_type PARAMS ((struct coff_symbol *, unsigned int,
+ union internal_auxent *));
+
+static struct type *
+decode_function_type PARAMS ((struct coff_symbol *, unsigned int,
+ union internal_auxent *));
+
+static struct type *
+coff_read_enum_type PARAMS ((int, int, int));
+
+static struct symbol *
+process_coff_symbol PARAMS ((struct coff_symbol *, union internal_auxent *,
+ struct objfile *));
+
+static void
+patch_opaque_types PARAMS ((struct symtab *));
+
+static void
+patch_type PARAMS ((struct type *, struct type *));
+
+static void
+enter_linenos PARAMS ((long, int, int));
+
+static void
+free_linetab PARAMS ((void));
+
+static int
+init_lineno PARAMS ((int, long, int));
+
+static char *
+getsymname PARAMS ((struct internal_syment *));
+
+static void
+free_stringtab PARAMS ((void));
+
+static int
+init_stringtab PARAMS ((int, long));
+
+static void
+read_one_sym PARAMS ((struct coff_symbol *, struct internal_syment *,
+ union internal_auxent *));
+
+static void
+read_coff_symtab PARAMS ((long, int, struct objfile *));
+
+static void
+find_linenos PARAMS ((bfd *, sec_ptr, PTR));
+
+static void
+coff_symfile_init PARAMS ((struct objfile *));
+
+static void
+coff_new_init PARAMS ((struct objfile *));
+
+static void
+coff_symfile_read PARAMS ((struct objfile *, struct section_offsets *, int));
+
+static void
+coff_symfile_finish PARAMS ((struct objfile *));
+
+static void record_minimal_symbol
+ PARAMS ((char *, CORE_ADDR, enum minimal_symbol_type, struct objfile *));
+
+static void
+coff_end_symtab PARAMS ((struct objfile *));
+
+static void
+complete_symtab PARAMS ((char *, CORE_ADDR, unsigned int));
+
+static void
+coff_start_symtab PARAMS ((void));
+
+static void
+coff_record_line PARAMS ((int, CORE_ADDR));
+
+static struct type *
+coff_alloc_type PARAMS ((int));
+
+static struct type **
+coff_lookup_type PARAMS ((int));
+
+
+static void
+coff_locate_sections PARAMS ((bfd *, asection *, PTR));
+
+/* We are called once per section from coff_symfile_read. We
+ need to examine each section we are passed, check to see
+ if it is something we are interested in processing, and
+ if so, stash away some access information for the section.
+
+ FIXME: The section names should not be hardwired strings (what
+ should they be? I don't think most object file formats have enough
+ section flags to specify what kind of debug section it is
+ -kingdon). */
+
+static void
+coff_locate_sections (ignore_abfd, sectp, csip)
+ bfd *ignore_abfd;
+ asection *sectp;
+ PTR csip;
+{
+ register struct coff_symfile_info *csi;
+
+ csi = (struct coff_symfile_info *) csip;
+ if (STREQ (sectp->name, ".stab"))
+ {
+ csi->stabsect = sectp;
+ }
+ else if (STREQ (sectp->name, ".stabstr"))
+ {
+ csi->stabstrsect = sectp;
+ }
+ else if (STREQ (sectp->name, ".stab.index"))
+ {
+ csi->stabindexsect = sectp;
+ }
+}
+
+/* Look up a coff type-number index. Return the address of the slot
+ where the type for that index is stored.
+ The type-number is in INDEX.
+
+ This can be used for finding the type associated with that index
+ or for associating a new type with the index. */
+
+static struct type **
+coff_lookup_type (index)
+ register int index;
+{
+ if (index >= type_vector_length)
+ {
+ int old_vector_length = type_vector_length;
+
+ type_vector_length *= 2;
+ if (index /* is still */ >= type_vector_length) {
+ type_vector_length = index * 2;
+ }
+ type_vector = (struct type **)
+ xrealloc ((char *) type_vector,
+ type_vector_length * sizeof (struct type *));
+ memset (&type_vector[old_vector_length], 0,
+ (type_vector_length - old_vector_length) * sizeof(struct type *));
+ }
+ return &type_vector[index];
+}
+
+/* Make sure there is a type allocated for type number index
+ and return the type object.
+ This can create an empty (zeroed) type object. */
+
+static struct type *
+coff_alloc_type (index)
+ int index;
+{
+ register struct type **type_addr = coff_lookup_type (index);
+ register struct type *type = *type_addr;
+
+ /* If we are referring to a type not known at all yet,
+ allocate an empty type for it.
+ We will fill it in later if we find out how. */
+ if (type == NULL)
+ {
+ type = alloc_type (current_objfile);
+ *type_addr = type;
+ }
+ return type;
+}
+
+/* Record a line number entry for line LINE at address PC.
+ FIXME: Use record_line instead. */
+
+static void
+coff_record_line (line, pc)
+ int line;
+ CORE_ADDR pc;
+{
+ struct linetable_entry *e;
+ /* Make sure line vector is big enough. */
+
+ if (line_vector_index + 2 >= line_vector_length)
+ {
+ line_vector_length *= 2;
+ line_vector = (struct linetable *)
+ xrealloc ((char *) line_vector, sizeof (struct linetable)
+ + (line_vector_length
+ * sizeof (struct linetable_entry)));
+ }
+
+ e = line_vector->item + line_vector_index++;
+ e->line = line; e->pc = pc;
+}
+
+/* Start a new symtab for a new source file.
+ This is called when a COFF ".file" symbol is seen;
+ it indicates the start of data for one original source file. */
+
+static void
+coff_start_symtab ()
+{
+ start_symtab (
+ /* We fill in the filename later. start_symtab
+ puts this pointer into last_source file and in
+ coff_end_symtab we assume we can free() it.
+ FIXME: leaks memory. */
+ savestring ("", 0),
+ /* We never know the directory name for COFF. */
+ NULL,
+ /* The start address is irrelevant, since we set
+ last_source_start_addr in coff_end_symtab. */
+ 0);
+
+ /* Initialize the source file line number information for this file. */
+
+ if (line_vector) /* Unlikely, but maybe possible? */
+ free ((PTR)line_vector);
+ line_vector_index = 0;
+ line_vector_length = 1000;
+ prev_line_number = -2; /* Force first line number to be explicit */
+ line_vector = (struct linetable *)
+ xmalloc (sizeof (struct linetable)
+ + line_vector_length * sizeof (struct linetable_entry));
+}
+
+/* Save the vital information from when starting to read a file,
+ for use when closing off the current file.
+ NAME is the file name the symbols came from, START_ADDR is the first
+ text address for the file, and SIZE is the number of bytes of text. */
+
+static void
+complete_symtab (name, start_addr, size)
+ char *name;
+ CORE_ADDR start_addr;
+ unsigned int size;
+{
+ last_source_file = savestring (name, strlen (name));
+ cur_src_start_addr = start_addr;
+ cur_src_end_addr = start_addr + size;
+
+ if (current_objfile -> ei.entry_point >= cur_src_start_addr &&
+ current_objfile -> ei.entry_point < cur_src_end_addr)
+ {
+ current_objfile -> ei.entry_file_lowpc = cur_src_start_addr;
+ current_objfile -> ei.entry_file_highpc = cur_src_end_addr;
+ }
+}
+
+/* Finish the symbol definitions for one main source file,
+ close off all the lexical contexts for that file
+ (creating struct block's for them), then make the
+ struct symtab for that file and put it in the list of all such. */
+
+static void
+coff_end_symtab (objfile)
+ struct objfile *objfile;
+{
+ struct symtab *symtab;
+
+ last_source_start_addr = cur_src_start_addr;
+
+ /* For no good reason, this file stores the number of entries in a
+ separate variable instead of in line_vector->nitems. Fix it. */
+ if (line_vector)
+ line_vector->nitems = line_vector_index;
+
+ /* For COFF, we only have one subfile, so we can just look at
+ subfiles and not worry about there being other elements in the
+ chain. We fill in various fields now because we didn't know them
+ before (or because doing it now is simply an artifact of how this
+ file used to be written). */
+ subfiles->line_vector = line_vector;
+ subfiles->name = last_source_file;
+
+ /* sort_pending is needed for amdcoff, at least.
+ sort_linevec is needed for the SCO compiler. */
+ symtab = end_symtab (cur_src_end_addr, 1, 1, objfile, 0);
+
+ if (symtab != NULL)
+ free_named_symtabs (symtab->filename);
+
+ /* Reinitialize for beginning of new file. */
+ line_vector = 0;
+ line_vector_length = -1;
+ last_source_file = NULL;
+}
+
+static void
+record_minimal_symbol (name, address, type, objfile)
+ char *name;
+ CORE_ADDR address;
+ enum minimal_symbol_type type;
+ struct objfile *objfile;
+{
+ /* We don't want TDESC entry points in the minimal symbol table */
+ if (name[0] == '@') return;
+
+ prim_record_minimal_symbol (savestring (name, strlen (name)), address, type,
+ objfile);
+}
+
+/* coff_symfile_init ()
+ is the coff-specific initialization routine for reading symbols.
+ It is passed a struct objfile which contains, among other things,
+ the BFD for the file whose symbols are being read, and a slot for
+ a pointer to "private data" which we fill with cookies and other
+ treats for coff_symfile_read ().
+
+ We will only be called if this is a COFF or COFF-like file.
+ BFD handles figuring out the format of the file, and code in symtab.c
+ uses BFD's determination to vector to us.
+
+ The ultimate result is a new symtab (or, FIXME, eventually a psymtab). */
+
+static int text_bfd_scnum;
+
+static void
+coff_symfile_init (objfile)
+ struct objfile *objfile;
+{
+ asection *section;
+ bfd *abfd = objfile->obfd;
+
+ /* Allocate struct to keep track of stab reading. */
+ objfile->sym_stab_info = (PTR)
+ xmmalloc (objfile -> md, sizeof (struct dbx_symfile_info));
+
+ memset ((PTR) objfile->sym_stab_info, 0, sizeof (struct dbx_symfile_info));
+
+ /* Allocate struct to keep track of the symfile */
+ objfile -> sym_private = xmmalloc (objfile -> md,
+ sizeof (struct coff_symfile_info));
+
+ memset (objfile->sym_private, 0, sizeof (struct coff_symfile_info));
+
+ init_entry_point_info (objfile);
+
+ /* Save the section number for the text section */
+ section = bfd_get_section_by_name (abfd, ".text");
+ if (section)
+ text_bfd_scnum = section->index;
+ else
+ text_bfd_scnum = -1;
+}
+
+/* This function is called for every section; it finds the outer limits
+ of the line table (minimum and maximum file offset) so that the
+ mainline code can read the whole thing for efficiency. */
+
+/* ARGSUSED */
+static void
+find_linenos (abfd, asect, vpinfo)
+ bfd *abfd;
+ sec_ptr asect;
+ PTR vpinfo;
+{
+ struct coff_symfile_info *info;
+ int size, count;
+ file_ptr offset, maxoff;
+
+/* WARNING WILL ROBINSON! ACCESSING BFD-PRIVATE DATA HERE! FIXME! */
+ count = asect->lineno_count;
+/* End of warning */
+
+ if (count == 0)
+ return;
+ size = count * local_linesz;
+
+ info = (struct coff_symfile_info *)vpinfo;
+/* WARNING WILL ROBINSON! ACCESSING BFD-PRIVATE DATA HERE! FIXME! */
+ offset = asect->line_filepos;
+/* End of warning */
+
+ if (offset < info->min_lineno_offset || info->min_lineno_offset == 0)
+ info->min_lineno_offset = offset;
+
+ maxoff = offset + size;
+ if (maxoff > info->max_lineno_offset)
+ info->max_lineno_offset = maxoff;
+}
+
+
+/* The BFD for this file -- only good while we're actively reading
+ symbols into a psymtab or a symtab. */
+
+static bfd *symfile_bfd;
+
+/* Read a symbol file, after initialization by coff_symfile_init. */
+/* FIXME! Addr and Mainline are not used yet -- this will not work for
+ shared libraries or add_file! */
+
+/* ARGSUSED */
+static void
+coff_symfile_read (objfile, section_offsets, mainline)
+ struct objfile *objfile;
+ struct section_offsets *section_offsets;
+ int mainline;
+{
+ struct coff_symfile_info *info;
+ struct dbx_symfile_info *dbxinfo;
+ bfd *abfd = objfile->obfd;
+ coff_data_type *cdata = coff_data (abfd);
+ char *name = bfd_get_filename (abfd);
+ int desc;
+ register int val;
+ int num_symbols;
+ int symtab_offset;
+ int stringtab_offset;
+ struct cleanup *back_to;
+ int stabsize, stabstrsize;
+
+ info = (struct coff_symfile_info *) objfile -> sym_private;
+ dbxinfo = (struct dbx_symfile_info *) objfile->sym_stab_info;
+ symfile_bfd = abfd; /* Kludge for swap routines */
+
+/* WARNING WILL ROBINSON! ACCESSING BFD-PRIVATE DATA HERE! FIXME! */
+ desc = fileno ((GDB_FILE *)(abfd->iostream)); /* File descriptor */
+ num_symbols = bfd_get_symcount (abfd); /* How many syms */
+ symtab_offset = cdata->sym_filepos; /* Symbol table file offset */
+ stringtab_offset = symtab_offset + /* String table file offset */
+ num_symbols * cdata->local_symesz;
+
+ /* Set a few file-statics that give us specific information about
+ the particular COFF file format we're reading. */
+ local_linesz = cdata->local_linesz;
+ local_n_btmask = cdata->local_n_btmask;
+ local_n_btshft = cdata->local_n_btshft;
+ local_n_tmask = cdata->local_n_tmask;
+ local_n_tshift = cdata->local_n_tshift;
+ local_linesz = cdata->local_linesz;
+ local_symesz = cdata->local_symesz;
+ local_auxesz = cdata->local_auxesz;
+
+ /* Allocate space for raw symbol and aux entries, based on their
+ space requirements as reported by BFD. */
+ temp_sym = (char *) xmalloc
+ (cdata->local_symesz + cdata->local_auxesz);
+ temp_aux = temp_sym + cdata->local_symesz;
+ back_to = make_cleanup (free_current_contents, &temp_sym);
+/* End of warning */
+
+ /* Read the line number table, all at once. */
+ info->min_lineno_offset = 0;
+ info->max_lineno_offset = 0;
+ bfd_map_over_sections (abfd, find_linenos, (PTR) info);
+
+ make_cleanup (free_linetab, 0);
+ val = init_lineno (desc, info->min_lineno_offset,
+ info->max_lineno_offset - info->min_lineno_offset);
+ if (val < 0)
+ error ("\"%s\": error reading line numbers\n", name);
+
+ /* Now read the string table, all at once. */
+
+ make_cleanup (free_stringtab, 0);
+ val = init_stringtab (desc, stringtab_offset);
+ if (val < 0)
+ error ("\"%s\": can't get string table", name);
+
+ init_minimal_symbol_collection ();
+ make_cleanup (discard_minimal_symbols, 0);
+
+ /* Now that the executable file is positioned at symbol table,
+ process it and define symbols accordingly. */
+
+ read_coff_symtab ((long)symtab_offset, num_symbols, objfile);
+
+ /* Sort symbols alphabetically within each block. */
+
+ {
+ struct symtab *s;
+ for (s = objfile -> symtabs; s != NULL; s = s -> next)
+ {
+ sort_symtab_syms (s);
+ }
+ }
+
+ /* Install any minimal symbols that have been collected as the current
+ minimal symbols for this objfile. */
+
+ install_minimal_symbols (objfile);
+
+ bfd_map_over_sections (abfd, coff_locate_sections, (PTR) info);
+
+ if (info->stabsect)
+ {
+ /* FIXME: dubious. Why can't we use something normal like
+ bfd_get_section_contents? */
+ fseek ((GDB_FILE *) abfd->iostream, abfd->where, 0);
+
+ stabsize = bfd_section_size (abfd, info->stabsect);
+ stabstrsize = bfd_section_size (abfd, info->stabstrsect);
+
+ coffstab_build_psymtabs (objfile,
+ section_offsets,
+ mainline,
+ info->stabsect->filepos, stabsize,
+ info->stabstrsect->filepos, stabstrsize);
+ }
+
+ do_cleanups (back_to);
+}
+
+static void
+coff_new_init (ignore)
+ struct objfile *ignore;
+{
+}
+
+/* Perform any local cleanups required when we are done with a particular
+ objfile. I.E, we are in the process of discarding all symbol information
+ for an objfile, freeing up all memory held for it, and unlinking the
+ objfile struct from the global list of known objfiles. */
+
+static void
+coff_symfile_finish (objfile)
+ struct objfile *objfile;
+{
+ if (objfile -> sym_private != NULL)
+ {
+ mfree (objfile -> md, objfile -> sym_private);
+ }
+}
+
+
+/* Given pointers to a symbol table in coff style exec file,
+ analyze them and create struct symtab's describing the symbols.
+ NSYMS is the number of symbols in the symbol table.
+ We read them one at a time using read_one_sym (). */
+
+static void
+read_coff_symtab (symtab_offset, nsyms, objfile)
+ long symtab_offset;
+ int nsyms;
+ struct objfile *objfile;
+{
+ GDB_FILE *stream;
+ register struct context_stack *new;
+ struct coff_symbol coff_symbol;
+ register struct coff_symbol *cs = &coff_symbol;
+ static struct internal_syment main_sym;
+ static union internal_auxent main_aux;
+ struct coff_symbol fcn_cs_saved;
+ static struct internal_syment fcn_sym_saved;
+ static union internal_auxent fcn_aux_saved;
+ struct symtab *s;
+
+ /* A .file is open. */
+ int in_source_file = 0;
+ int next_file_symnum = -1;
+
+ /* Name of the current file. */
+ char *filestring = "";
+ int depth = 0;
+ int fcn_first_line = 0;
+ int fcn_last_line = 0;
+ int fcn_start_addr = 0;
+ long fcn_line_ptr = 0;
+ int val;
+
+ stream = bfd_cache_lookup(objfile->obfd);
+ if (!stream)
+ perror_with_name(objfile->name);
+
+ /* Work around a stdio bug in SunOS4.1.1 (this makes me nervous....
+ it's hard to know I've really worked around it. The fix should be
+ harmless, anyway). The symptom of the bug is that the first
+ fread (in read_one_sym), will (in my example) actually get data
+ from file offset 268, when the fseek was to 264 (and ftell shows
+ 264). This causes all hell to break loose. I was unable to
+ reproduce this on a short test program which operated on the same
+ file, performing (I think) the same sequence of operations.
+
+ It stopped happening when I put in this rewind().
+
+ FIXME: Find out if this has been reported to Sun, whether it has
+ been fixed in a later release, etc. */
+
+ rewind (stream);
+
+ /* Position to read the symbol table. */
+ val = fseek (stream, (long)symtab_offset, 0);
+ if (val < 0)
+ perror_with_name (objfile->name);
+
+ current_objfile = objfile;
+ nlist_stream_global = stream;
+ nlist_nsyms_global = nsyms;
+ last_source_file = NULL;
+ memset (opaque_type_chain, 0, sizeof opaque_type_chain);
+
+ if (type_vector) /* Get rid of previous one */
+ free ((PTR)type_vector);
+ type_vector_length = 160;
+ type_vector = (struct type **)
+ xmalloc (type_vector_length * sizeof (struct type *));
+ memset (type_vector, 0, type_vector_length * sizeof (struct type *));
+
+ coff_start_symtab ();
+
+ symnum = 0;
+ while (symnum < nsyms)
+ {
+ QUIT; /* Make this command interruptable. */
+ read_one_sym (cs, &main_sym, &main_aux);
+
+#ifdef SEM
+ temp_sem_val = cs->c_name[0] << 24 | cs->c_name[1] << 16 |
+ cs->c_name[2] << 8 | cs->c_name[3];
+ if (int_sem_val == temp_sem_val)
+ last_coffsem = (int) strtol (cs->c_name+4, (char **) NULL, 10);
+#endif
+
+ if (cs->c_symnum == next_file_symnum && cs->c_sclass != C_FILE)
+ {
+ if (last_source_file)
+ coff_end_symtab (objfile);
+
+ coff_start_symtab ();
+ complete_symtab ("_globals_", 0, 0);
+ /* done with all files, everything from here on out is globals */
+ }
+
+ /* Special case for file with type declarations only, no text. */
+ if (!last_source_file && SDB_TYPE (cs->c_type)
+ && cs->c_secnum == N_DEBUG)
+ complete_symtab (filestring, 0, 0);
+
+ /* Typedefs should not be treated as symbol definitions. */
+ if (ISFCN (cs->c_type) && cs->c_sclass != C_TPDEF)
+ {
+ /* Record all functions -- external and static -- in minsyms. */
+ record_minimal_symbol (cs->c_name, cs->c_value, mst_text, objfile);
+
+ fcn_line_ptr = main_aux.x_sym.x_fcnary.x_fcn.x_lnnoptr;
+ fcn_start_addr = cs->c_value;
+ fcn_cs_saved = *cs;
+ fcn_sym_saved = main_sym;
+ fcn_aux_saved = main_aux;
+ continue;
+ }
+
+ switch (cs->c_sclass)
+ {
+ case C_EFCN:
+ case C_EXTDEF:
+ case C_ULABEL:
+ case C_USTATIC:
+ case C_LINE:
+ case C_ALIAS:
+ case C_HIDDEN:
+ complain (&bad_sclass_complaint, cs->c_name);
+ break;
+
+ case C_FILE:
+ /*
+ * c_value field contains symnum of next .file entry in table
+ * or symnum of first global after last .file.
+ */
+ next_file_symnum = cs->c_value;
+ if (cs->c_naux > 0)
+ filestring = coff_getfilename (&main_aux);
+ else
+ filestring = "";
+
+ /*
+ * Complete symbol table for last object file
+ * containing debugging information.
+ */
+ if (last_source_file)
+ {
+ coff_end_symtab (objfile);
+ coff_start_symtab ();
+ }
+ in_source_file = 1;
+ break;
+
+ case C_STAT:
+ if (cs->c_name[0] == '.') {
+ if (STREQ (cs->c_name, ".text")) {
+ /* FIXME: don't wire in ".text" as section name
+ or symbol name! */
+ /* Check for in_source_file deals with case of
+ a file with debugging symbols
+ followed by a later file with no symbols. */
+ if (in_source_file)
+ complete_symtab (filestring, cs->c_value,
+ main_aux.x_scn.x_scnlen);
+ in_source_file = 0;
+ }
+ /* flush rest of '.' symbols */
+ break;
+ }
+ else if (!SDB_TYPE (cs->c_type)
+ && cs->c_name[0] == 'L'
+ && (strncmp (cs->c_name, "LI%", 3) == 0
+ || strncmp (cs->c_name, "LF%", 3) == 0
+ || strncmp (cs->c_name,"LC%",3) == 0
+ || strncmp (cs->c_name,"LP%",3) == 0
+ || strncmp (cs->c_name,"LPB%",4) == 0
+ || strncmp (cs->c_name,"LBB%",4) == 0
+ || strncmp (cs->c_name,"LBE%",4) == 0
+ || strncmp (cs->c_name,"LPBX%",5) == 0))
+ /* At least on a 3b1, gcc generates swbeg and string labels
+ that look like this. Ignore them. */
+ break;
+ /* fall in for static symbols that don't start with '.' */
+ case C_EXT:
+ /* Record it in the minimal symbols regardless of SDB_TYPE.
+ This parallels what we do for other debug formats, and
+ probably is needed to make print_address_symbolic work right
+ without the "set fast-symbolic-addr off" kludge. */
+
+ /* FIXME: This bogusly assumes the sections are in a certain
+ order, text (SEC_CODE) sections are before data sections,
+ etc. */
+ if (cs->c_secnum <= text_bfd_scnum+1)
+ {
+ /* text or absolute. (FIXME, should use mst_abs if
+ absolute). */
+ record_minimal_symbol
+ (cs->c_name, cs->c_value,
+ cs->c_sclass == C_STAT ? mst_file_text : mst_text,
+ objfile);
+ }
+ else
+ {
+ record_minimal_symbol
+ (cs->c_name, cs->c_value,
+ cs->c_sclass == C_STAT ? mst_file_data : mst_data,
+ objfile);
+ }
+ if (SDB_TYPE (cs->c_type))
+ process_coff_symbol (cs, &main_aux, objfile);
+ break;
+
+ case C_FCN:
+ if (STREQ (cs->c_name, ".bf"))
+ {
+ within_function = 1;
+
+ /* value contains address of first non-init type code */
+ /* main_aux.x_sym.x_misc.x_lnsz.x_lnno
+ contains line number of '{' } */
+ if (cs->c_naux != 1)
+ complain (&bf_no_aux_complaint, cs->c_symnum);
+ fcn_first_line = main_aux.x_sym.x_misc.x_lnsz.x_lnno;
+
+ /* Might want to check that locals are 0 and
+ context_stack_depth is zero, and complain if not. */
+
+ depth = 0;
+ new = push_context (depth, fcn_start_addr);
+ fcn_cs_saved.c_name = getsymname (&fcn_sym_saved);
+ new->name = process_coff_symbol (&fcn_cs_saved,
+ &fcn_aux_saved, objfile);
+ }
+ else if (STREQ (cs->c_name, ".ef"))
+ {
+ /* the value of .ef is the address of epilogue code;
+ not useful for gdb. */
+ /* { main_aux.x_sym.x_misc.x_lnsz.x_lnno
+ contains number of lines to '}' */
+ new = pop_context ();
+ /* Stack must be empty now. */
+ if (context_stack_depth > 0 || new == NULL)
+ {
+ complain (&ef_complaint, cs->c_symnum);
+ within_function = 0;
+ break;
+ }
+ if (cs->c_naux != 1)
+ {
+ complain (&ef_no_aux_complaint, cs->c_symnum);
+ fcn_last_line = 0x7FFFFFFF;
+ }
+ else
+ {
+ fcn_last_line = main_aux.x_sym.x_misc.x_lnsz.x_lnno;
+ }
+ enter_linenos (fcn_line_ptr, fcn_first_line, fcn_last_line);
+
+ finish_block (new->name, &local_symbols, new->old_blocks,
+ new->start_addr,
+#if defined (FUNCTION_EPILOGUE_SIZE)
+ /* This macro should be defined only on
+ machines where the
+ fcn_aux_saved.x_sym.x_misc.x_fsize
+ field is always zero.
+ So use the .bf record information that
+ points to the epilogue and add the size
+ of the epilogue. */
+ cs->c_value + FUNCTION_EPILOGUE_SIZE,
+#else
+ fcn_cs_saved.c_value +
+ fcn_aux_saved.x_sym.x_misc.x_fsize,
+#endif
+ objfile
+ );
+ within_function = 0;
+ }
+ break;
+
+ case C_BLOCK:
+ if (STREQ (cs->c_name, ".bb"))
+ {
+ push_context (++depth, cs->c_value);
+ }
+ else if (STREQ (cs->c_name, ".eb"))
+ {
+ new = pop_context ();
+ if (depth-- != new->depth)
+ {
+ complain (&eb_complaint, symnum);
+ break;
+ }
+ if (local_symbols && context_stack_depth > 0)
+ {
+ /* Make a block for the local symbols within. */
+ finish_block (0, &local_symbols, new->old_blocks,
+ new->start_addr, cs->c_value, objfile);
+ }
+ /* Now pop locals of block just finished. */
+ local_symbols = new->locals;
+ }
+ break;
+
+ default:
+ process_coff_symbol (cs, &main_aux, objfile);
+ break;
+ }
+ }
+
+ if (last_source_file)
+ coff_end_symtab (objfile);
+
+ /* Patch up any opaque types (references to types that are not defined
+ in the file where they are referenced, e.g. "struct foo *bar"). */
+ ALL_OBJFILE_SYMTABS (objfile, s)
+ patch_opaque_types (s);
+
+ current_objfile = NULL;
+}
+
+/* Routines for reading headers and symbols from executable. */
+
+#ifdef FIXME
+/* Move these XXXMAGIC symbol defns into BFD! */
+
+/* Read COFF file header, check magic number,
+ and return number of symbols. */
+read_file_hdr (chan, file_hdr)
+ int chan;
+ FILHDR *file_hdr;
+{
+ lseek (chan, 0L, 0);
+ if (myread (chan, (char *)file_hdr, FILHSZ) < 0)
+ return -1;
+
+ switch (file_hdr->f_magic)
+ {
+#ifdef MC68MAGIC
+ case MC68MAGIC:
+#endif
+#ifdef NS32GMAGIC
+ case NS32GMAGIC:
+ case NS32SMAGIC:
+#endif
+#ifdef I386MAGIC
+ case I386MAGIC:
+#endif
+#ifdef CLIPPERMAGIC
+ case CLIPPERMAGIC:
+#endif
+#if defined (MC68KWRMAGIC) \
+ && (!defined (MC68MAGIC) || MC68KWRMAGIC != MC68MAGIC)
+ case MC68KWRMAGIC:
+#endif
+#ifdef MC68KROMAGIC
+ case MC68KROMAGIC:
+ case MC68KPGMAGIC:
+#endif
+#ifdef MC88DGMAGIC
+ case MC88DGMAGIC:
+#endif
+#ifdef MC88MAGIC
+ case MC88MAGIC:
+#endif
+#ifdef I960ROMAGIC
+ case I960ROMAGIC: /* Intel 960 */
+#endif
+#ifdef I960RWMAGIC
+ case I960RWMAGIC: /* Intel 960 */
+#endif
+ return file_hdr->f_nsyms;
+
+ default:
+#ifdef BADMAG
+ if (BADMAG(file_hdr))
+ return -1;
+ else
+ return file_hdr->f_nsyms;
+#else
+ return -1;
+#endif
+ }
+}
+#endif
+
+/* Read the next symbol, swap it, and return it in both internal_syment
+ form, and coff_symbol form. Also return its first auxent, if any,
+ in internal_auxent form, and skip any other auxents. */
+
+static void
+read_one_sym (cs, sym, aux)
+ register struct coff_symbol *cs;
+ register struct internal_syment *sym;
+ register union internal_auxent *aux;
+{
+ int i;
+
+ cs->c_symnum = symnum;
+ fread (temp_sym, local_symesz, 1, nlist_stream_global);
+ bfd_coff_swap_sym_in (symfile_bfd, temp_sym, (char *)sym);
+ cs->c_naux = sym->n_numaux & 0xff;
+ if (cs->c_naux >= 1)
+ {
+ fread (temp_aux, local_auxesz, 1, nlist_stream_global);
+ bfd_coff_swap_aux_in (symfile_bfd, temp_aux, sym->n_type, sym->n_sclass,
+ 0, cs->c_naux, (char *)aux);
+ /* If more than one aux entry, read past it (only the first aux
+ is important). */
+ for (i = 1; i < cs->c_naux; i++)
+ fread (temp_aux, local_auxesz, 1, nlist_stream_global);
+ }
+ cs->c_name = getsymname (sym);
+ cs->c_value = sym->n_value;
+ cs->c_sclass = (sym->n_sclass & 0xff);
+ cs->c_secnum = sym->n_scnum;
+ cs->c_type = (unsigned) sym->n_type;
+ if (!SDB_TYPE (cs->c_type))
+ cs->c_type = 0;
+
+ symnum += 1 + cs->c_naux;
+}
+
+/* Support for string table handling */
+
+static char *stringtab = NULL;
+
+static int
+init_stringtab (chan, offset)
+ int chan;
+ long offset;
+{
+ long length;
+ int val;
+ unsigned char lengthbuf[4];
+
+ free_stringtab ();
+
+ /* If the file is stripped, the offset might be zero, indicating no
+ string table. Just return with `stringtab' set to null. */
+ if (offset == 0)
+ return 0;
+
+ if (lseek (chan, offset, 0) < 0)
+ return -1;
+
+ val = myread (chan, (char *)lengthbuf, sizeof lengthbuf);
+ length = bfd_h_get_32 (symfile_bfd, lengthbuf);
+
+ /* If no string table is needed, then the file may end immediately
+ after the symbols. Just return with `stringtab' set to null. */
+ if (val != sizeof lengthbuf || length < sizeof lengthbuf)
+ return 0;
+
+ stringtab = (char *) xmalloc (length);
+ memcpy (stringtab, &length, sizeof length);
+ if (length == sizeof length) /* Empty table -- just the count */
+ return 0;
+
+ val = myread (chan, stringtab + sizeof lengthbuf, length - sizeof lengthbuf);
+ if (val != length - sizeof lengthbuf || stringtab[length - 1] != '\0')
+ return -1;
+
+ return 0;
+}
+
+static void
+free_stringtab ()
+{
+ if (stringtab)
+ free (stringtab);
+ stringtab = NULL;
+}
+
+static char *
+getsymname (symbol_entry)
+ struct internal_syment *symbol_entry;
+{
+ static char buffer[SYMNMLEN+1];
+ char *result;
+
+ if (symbol_entry->_n._n_n._n_zeroes == 0)
+ {
+ result = stringtab + symbol_entry->_n._n_n._n_offset;
+ }
+ else
+ {
+ strncpy (buffer, symbol_entry->_n._n_name, SYMNMLEN);
+ buffer[SYMNMLEN] = '\0';
+ result = buffer;
+ }
+ return result;
+}
+
+/* Extract the file name from the aux entry of a C_FILE symbol. Return
+ only the last component of the name. Result is in static storage and
+ is only good for temporary use. */
+
+char *
+coff_getfilename (aux_entry)
+ union internal_auxent *aux_entry;
+{
+ static char buffer[BUFSIZ];
+ register char *temp;
+ char *result;
+
+ if (aux_entry->x_file.x_n.x_zeroes == 0)
+ strcpy (buffer, stringtab + aux_entry->x_file.x_n.x_offset);
+ else
+ {
+ strncpy (buffer, aux_entry->x_file.x_fname, FILNMLEN);
+ buffer[FILNMLEN] = '\0';
+ }
+ result = buffer;
+ if ((temp = strrchr (result, '/')) != NULL)
+ result = temp + 1;
+ return (result);
+}
+
+/* Support for line number handling */
+static char *linetab = NULL;
+static long linetab_offset;
+static unsigned long linetab_size;
+
+/* Read in all the line numbers for fast lookups later. Leave them in
+ external (unswapped) format in memory; we'll swap them as we enter
+ them into GDB's data structures. */
+
+static int
+init_lineno (chan, offset, size)
+ int chan;
+ long offset;
+ int size;
+{
+ int val;
+
+ linetab_offset = offset;
+ linetab_size = size;
+
+ free_linetab();
+
+ if (size == 0)
+ return 0;
+
+ if (lseek (chan, offset, 0) < 0)
+ return -1;
+
+ /* Allocate the desired table, plus a sentinel */
+ linetab = (char *) xmalloc (size + local_linesz);
+
+ val = myread (chan, linetab, size);
+ if (val != size)
+ return -1;
+
+ /* Terminate it with an all-zero sentinel record */
+ memset (linetab + size, 0, local_linesz);
+
+ return 0;
+}
+
+static void
+free_linetab ()
+{
+ if (linetab)
+ free (linetab);
+ linetab = NULL;
+}
+
+#if !defined (L_LNNO32)
+#define L_LNNO32(lp) ((lp)->l_lnno)
+#endif
+
+static void
+enter_linenos (file_offset, first_line, last_line)
+ long file_offset;
+ register int first_line;
+ register int last_line;
+{
+ register char *rawptr;
+ struct internal_lineno lptr;
+
+ if (file_offset < linetab_offset)
+ {
+ complain (&lineno_complaint, file_offset);
+ if (file_offset > linetab_size) /* Too big to be an offset? */
+ return;
+ file_offset += linetab_offset; /* Try reading at that linetab offset */
+ }
+
+ rawptr = &linetab[file_offset - linetab_offset];
+
+ /* skip first line entry for each function */
+ rawptr += local_linesz;
+ /* line numbers start at one for the first line of the function */
+ first_line--;
+
+ for (;;) {
+ bfd_coff_swap_lineno_in (symfile_bfd, rawptr, &lptr);
+ rawptr += local_linesz;
+ /* The next function, or the sentinel, will have L_LNNO32 zero; we exit. */
+ if (L_LNNO32 (&lptr) && L_LNNO32 (&lptr) <= last_line)
+ coff_record_line (first_line + L_LNNO32 (&lptr), lptr.l_addr.l_paddr);
+ else
+ break;
+ }
+}
+
+static void
+patch_type (type, real_type)
+ struct type *type;
+ struct type *real_type;
+{
+ register struct type *target = TYPE_TARGET_TYPE (type);
+ register struct type *real_target = TYPE_TARGET_TYPE (real_type);
+ int field_size = TYPE_NFIELDS (real_target) * sizeof (struct field);
+
+ TYPE_LENGTH (target) = TYPE_LENGTH (real_target);
+ TYPE_NFIELDS (target) = TYPE_NFIELDS (real_target);
+ TYPE_FIELDS (target) = (struct field *) TYPE_ALLOC (target, field_size);
+
+ memcpy (TYPE_FIELDS (target), TYPE_FIELDS (real_target), field_size);
+
+ if (TYPE_NAME (real_target))
+ {
+ if (TYPE_NAME (target))
+ free (TYPE_NAME (target));
+ TYPE_NAME (target) = concat (TYPE_NAME (real_target), NULL);
+ }
+}
+
+/* Patch up all appropriate typedef symbols in the opaque_type_chains
+ so that they can be used to print out opaque data structures properly. */
+
+static void
+patch_opaque_types (s)
+ struct symtab *s;
+{
+ register struct block *b;
+ register int i;
+ register struct symbol *real_sym;
+
+ /* Go through the per-file symbols only */
+ b = BLOCKVECTOR_BLOCK (BLOCKVECTOR (s), STATIC_BLOCK);
+ for (i = BLOCK_NSYMS (b) - 1; i >= 0; i--)
+ {
+ /* Find completed typedefs to use to fix opaque ones.
+ Remove syms from the chain when their types are stored,
+ but search the whole chain, as there may be several syms
+ from different files with the same name. */
+ real_sym = BLOCK_SYM (b, i);
+ if (SYMBOL_CLASS (real_sym) == LOC_TYPEDEF &&
+ SYMBOL_NAMESPACE (real_sym) == VAR_NAMESPACE &&
+ TYPE_CODE (SYMBOL_TYPE (real_sym)) == TYPE_CODE_PTR &&
+ TYPE_LENGTH (TYPE_TARGET_TYPE (SYMBOL_TYPE (real_sym))) != 0)
+ {
+ register char *name = SYMBOL_NAME (real_sym);
+ register int hash = hashname (name);
+ register struct symbol *sym, *prev;
+
+ prev = 0;
+ for (sym = opaque_type_chain[hash]; sym;)
+ {
+ if (name[0] == SYMBOL_NAME (sym)[0] &&
+ STREQ (name + 1, SYMBOL_NAME (sym) + 1))
+ {
+ if (prev)
+ {
+ SYMBOL_VALUE_CHAIN (prev) = SYMBOL_VALUE_CHAIN (sym);
+ }
+ else
+ {
+ opaque_type_chain[hash] = SYMBOL_VALUE_CHAIN (sym);
+ }
+
+ patch_type (SYMBOL_TYPE (sym), SYMBOL_TYPE (real_sym));
+
+ if (prev)
+ {
+ sym = SYMBOL_VALUE_CHAIN (prev);
+ }
+ else
+ {
+ sym = opaque_type_chain[hash];
+ }
+ }
+ else
+ {
+ prev = sym;
+ sym = SYMBOL_VALUE_CHAIN (sym);
+ }
+ }
+ }
+ }
+}
+
+static struct symbol *
+process_coff_symbol (cs, aux, objfile)
+ register struct coff_symbol *cs;
+ register union internal_auxent *aux;
+ struct objfile *objfile;
+{
+ register struct symbol *sym
+ = (struct symbol *) obstack_alloc (&objfile->symbol_obstack,
+ sizeof (struct symbol));
+ char *name;
+
+ memset (sym, 0, sizeof (struct symbol));
+ name = cs->c_name;
+ name = EXTERNAL_NAME (name, objfile->obfd);
+ SYMBOL_NAME (sym) = obstack_copy0 (&objfile->symbol_obstack, name,
+ strlen (name));
+
+ /* default assumptions */
+ SYMBOL_VALUE (sym) = cs->c_value;
+ SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE;
+
+ if (ISFCN (cs->c_type))
+ {
+#if 0
+ /* FIXME: This has NOT been tested. The DBX version has.. */
+ /* Generate a template for the type of this function. The
+ types of the arguments will be added as we read the symbol
+ table. */
+ struct type *new = (struct type *)
+ obstack_alloc (&objfile->symbol_obstack, sizeof (struct type));
+
+ memcpy (new, lookup_function_type (decode_function_type (cs, cs->c_type, aux)),
+ sizeof(struct type));
+ SYMBOL_TYPE (sym) = new;
+ in_function_type = SYMBOL_TYPE(sym);
+#else
+ SYMBOL_TYPE(sym) =
+ lookup_function_type (decode_function_type (cs, cs->c_type, aux));
+#endif
+
+ SYMBOL_CLASS (sym) = LOC_BLOCK;
+ if (cs->c_sclass == C_STAT)
+ add_symbol_to_list (sym, &file_symbols);
+ else if (cs->c_sclass == C_EXT)
+ add_symbol_to_list (sym, &global_symbols);
+ }
+ else
+ {
+ SYMBOL_TYPE (sym) = decode_type (cs, cs->c_type, aux);
+ switch (cs->c_sclass)
+ {
+ case C_NULL:
+ break;
+
+ case C_AUTO:
+ SYMBOL_CLASS (sym) = LOC_LOCAL;
+ add_symbol_to_list (sym, &local_symbols);
+ break;
+
+ case C_EXT:
+ SYMBOL_CLASS (sym) = LOC_STATIC;
+ SYMBOL_VALUE_ADDRESS (sym) = (CORE_ADDR) cs->c_value;
+ add_symbol_to_list (sym, &global_symbols);
+ break;
+
+ case C_STAT:
+ SYMBOL_CLASS (sym) = LOC_STATIC;
+ SYMBOL_VALUE_ADDRESS (sym) = (CORE_ADDR) cs->c_value;
+ if (within_function) {
+ /* Static symbol of local scope */
+ add_symbol_to_list (sym, &local_symbols);
+ }
+ else {
+ /* Static symbol at top level of file */
+ add_symbol_to_list (sym, &file_symbols);
+ }
+ break;
+
+#ifdef C_GLBLREG /* AMD coff */
+ case C_GLBLREG:
+#endif
+ case C_REG:
+ SYMBOL_CLASS (sym) = LOC_REGISTER;
+ SYMBOL_VALUE (sym) = SDB_REG_TO_REGNUM(cs->c_value);
+ add_symbol_to_list (sym, &local_symbols);
+ break;
+
+ case C_LABEL:
+ break;
+
+ case C_ARG:
+ SYMBOL_CLASS (sym) = LOC_ARG;
+#if 0
+ /* FIXME: This has not been tested. */
+ /* Add parameter to function. */
+ add_param_to_type(&in_function_type,sym);
+#endif
+ add_symbol_to_list (sym, &local_symbols);
+#if !defined (BELIEVE_PCC_PROMOTION) && (TARGET_BYTE_ORDER == BIG_ENDIAN)
+ {
+ /* If PCC says a parameter is a short or a char,
+ aligned on an int boundary, realign it to the "little end"
+ of the int. */
+ struct type *temptype;
+ temptype = lookup_fundamental_type (current_objfile, FT_INTEGER);
+ if (TYPE_LENGTH (SYMBOL_TYPE (sym)) < TYPE_LENGTH (temptype)
+ && TYPE_CODE (SYMBOL_TYPE (sym)) == TYPE_CODE_INT
+ && 0 == SYMBOL_VALUE (sym) % TYPE_LENGTH (temptype))
+ {
+ SYMBOL_VALUE (sym) +=
+ TYPE_LENGTH (temptype)
+ - TYPE_LENGTH (SYMBOL_TYPE (sym));
+ }
+ }
+#endif
+ break;
+
+ case C_REGPARM:
+ SYMBOL_CLASS (sym) = LOC_REGPARM;
+ SYMBOL_VALUE (sym) = SDB_REG_TO_REGNUM(cs->c_value);
+ add_symbol_to_list (sym, &local_symbols);
+#if !defined (BELIEVE_PCC_PROMOTION)
+ /* FIXME: This should retain the current type, since it's just
+ a register value. gnu@adobe, 26Feb93 */
+ {
+ /* If PCC says a parameter is a short or a char,
+ it is really an int. */
+ struct type *temptype;
+ temptype =
+ lookup_fundamental_type (current_objfile, FT_INTEGER);
+ if (TYPE_LENGTH (SYMBOL_TYPE (sym)) < TYPE_LENGTH (temptype)
+ && TYPE_CODE (SYMBOL_TYPE (sym)) == TYPE_CODE_INT)
+ {
+ SYMBOL_TYPE (sym) =
+ (TYPE_UNSIGNED (SYMBOL_TYPE (sym))
+ ? lookup_fundamental_type (current_objfile,
+ FT_UNSIGNED_INTEGER)
+ : temptype);
+ }
+ }
+#endif
+ break;
+
+ case C_TPDEF:
+ SYMBOL_CLASS (sym) = LOC_TYPEDEF;
+ SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE;
+
+ /* If type has no name, give it one */
+ if (TYPE_NAME (SYMBOL_TYPE (sym)) == 0)
+ {
+ if (TYPE_CODE (SYMBOL_TYPE (sym)) == TYPE_CODE_PTR
+ || TYPE_CODE (SYMBOL_TYPE (sym)) == TYPE_CODE_FUNC)
+ {
+ /* If we are giving a name to a type such as "pointer to
+ foo" or "function returning foo", we better not set
+ the TYPE_NAME. If the program contains "typedef char
+ *caddr_t;", we don't want all variables of type char
+ * to print as caddr_t. This is not just a
+ consequence of GDB's type management; CC and GCC (at
+ least through version 2.4) both output variables of
+ either type char * or caddr_t with the type
+ refering to the C_TPDEF symbol for caddr_t. If a future
+ compiler cleans this up it GDB is not ready for it
+ yet, but if it becomes ready we somehow need to
+ disable this check (without breaking the PCC/GCC2.4
+ case).
+
+ Sigh.
+
+ Fortunately, this check seems not to be necessary
+ for anything except pointers or functions. */
+ ;
+ }
+ else
+ TYPE_NAME (SYMBOL_TYPE (sym)) =
+ concat (SYMBOL_NAME (sym), NULL);
+ }
+
+ /* Keep track of any type which points to empty structured type,
+ so it can be filled from a definition from another file. A
+ simple forward reference (TYPE_CODE_UNDEF) is not an
+ empty structured type, though; the forward references
+ work themselves out via the magic of coff_lookup_type. */
+ if (TYPE_CODE (SYMBOL_TYPE (sym)) == TYPE_CODE_PTR &&
+ TYPE_LENGTH (TYPE_TARGET_TYPE (SYMBOL_TYPE (sym))) == 0 &&
+ TYPE_CODE (TYPE_TARGET_TYPE (SYMBOL_TYPE (sym))) !=
+ TYPE_CODE_UNDEF)
+ {
+ register int i = hashname (SYMBOL_NAME (sym));
+
+ SYMBOL_VALUE_CHAIN (sym) = opaque_type_chain[i];
+ opaque_type_chain[i] = sym;
+ }
+ add_symbol_to_list (sym, &file_symbols);
+ break;
+
+ case C_STRTAG:
+ case C_UNTAG:
+ case C_ENTAG:
+ SYMBOL_CLASS (sym) = LOC_TYPEDEF;
+ SYMBOL_NAMESPACE (sym) = STRUCT_NAMESPACE;
+
+ /* Some compilers try to be helpful by inventing "fake"
+ names for anonymous enums, structures, and unions, like
+ "~0fake" or ".0fake". Thanks, but no thanks... */
+ if (TYPE_TAG_NAME (SYMBOL_TYPE (sym)) == 0)
+ if (SYMBOL_NAME(sym) != NULL
+ && *SYMBOL_NAME(sym) != '~'
+ && *SYMBOL_NAME(sym) != '.')
+ TYPE_TAG_NAME (SYMBOL_TYPE (sym)) =
+ concat (SYMBOL_NAME (sym), NULL);
+
+ add_symbol_to_list (sym, &file_symbols);
+ break;
+
+ default:
+ break;
+ }
+ }
+ return sym;
+}
+
+/* Decode a coff type specifier;
+ return the type that is meant. */
+
+static
+struct type *
+decode_type (cs, c_type, aux)
+ register struct coff_symbol *cs;
+ unsigned int c_type;
+ register union internal_auxent *aux;
+{
+ register struct type *type = 0;
+ unsigned int new_c_type;
+
+ if (c_type & ~N_BTMASK)
+ {
+ new_c_type = DECREF (c_type);
+ if (ISPTR (c_type))
+ {
+ type = decode_type (cs, new_c_type, aux);
+ type = lookup_pointer_type (type);
+ }
+ else if (ISFCN (c_type))
+ {
+ type = decode_type (cs, new_c_type, aux);
+ type = lookup_function_type (type);
+ }
+ else if (ISARY (c_type))
+ {
+ int i, n;
+ register unsigned short *dim;
+ struct type *base_type, *index_type, *range_type;
+
+ /* Define an array type. */
+ /* auxent refers to array, not base type */
+ if (aux->x_sym.x_tagndx.l == 0)
+ cs->c_naux = 0;
+
+ /* shift the indices down */
+ dim = &aux->x_sym.x_fcnary.x_ary.x_dimen[0];
+ i = 1;
+ n = dim[0];
+ for (i = 0; *dim && i < DIMNUM - 1; i++, dim++)
+ *dim = *(dim + 1);
+ *dim = 0;
+
+ base_type = decode_type (cs, new_c_type, aux);
+ index_type = lookup_fundamental_type (current_objfile, FT_INTEGER);
+ range_type =
+ create_range_type ((struct type *) NULL, index_type, 0, n - 1);
+ type =
+ create_array_type ((struct type *) NULL, base_type, range_type);
+ }
+ return type;
+ }
+
+ /* Reference to existing type. This only occurs with the
+ struct, union, and enum types. EPI a29k coff
+ fakes us out by producing aux entries with a nonzero
+ x_tagndx for definitions of structs, unions, and enums, so we
+ have to check the c_sclass field. SCO 3.2v4 cc gets confused
+ with pointers to pointers to defined structs, and generates
+ negative x_tagndx fields. */
+ if (cs->c_naux > 0 && aux->x_sym.x_tagndx.l != 0)
+ {
+ if (cs->c_sclass != C_STRTAG
+ && cs->c_sclass != C_UNTAG
+ && cs->c_sclass != C_ENTAG
+ && aux->x_sym.x_tagndx.l >= 0)
+ {
+ type = coff_alloc_type (aux->x_sym.x_tagndx.l);
+ return type;
+ } else {
+ complain (&tagndx_bad_complaint, cs->c_name);
+ /* And fall through to decode_base_type... */
+ }
+ }
+
+ return decode_base_type (cs, BTYPE (c_type), aux);
+}
+
+/* Decode a coff type specifier for function definition;
+ return the type that the function returns. */
+
+static
+struct type *
+decode_function_type (cs, c_type, aux)
+ register struct coff_symbol *cs;
+ unsigned int c_type;
+ register union internal_auxent *aux;
+{
+ if (aux->x_sym.x_tagndx.l == 0)
+ cs->c_naux = 0; /* auxent refers to function, not base type */
+
+ return decode_type (cs, DECREF (c_type), aux);
+}
+
+/* basic C types */
+
+static
+struct type *
+decode_base_type (cs, c_type, aux)
+ register struct coff_symbol *cs;
+ unsigned int c_type;
+ register union internal_auxent *aux;
+{
+ struct type *type;
+
+ switch (c_type)
+ {
+ case T_NULL:
+ /* shows up with "void (*foo)();" structure members */
+ return lookup_fundamental_type (current_objfile, FT_VOID);
+
+#if 0
+/* DGUX actually defines both T_ARG and T_VOID to the same value. */
+#ifdef T_ARG
+ case T_ARG:
+ /* Shows up in DGUX, I think. Not sure where. */
+ return lookup_fundamental_type (current_objfile, FT_VOID); /* shouldn't show up here */
+#endif
+#endif /* 0 */
+
+#ifdef T_VOID
+ case T_VOID:
+ /* Intel 960 COFF has this symbol and meaning. */
+ return lookup_fundamental_type (current_objfile, FT_VOID);
+#endif
+
+ case T_CHAR:
+ return lookup_fundamental_type (current_objfile, FT_CHAR);
+
+ case T_SHORT:
+ return lookup_fundamental_type (current_objfile, FT_SHORT);
+
+ case T_INT:
+ return lookup_fundamental_type (current_objfile, FT_INTEGER);
+
+ case T_LONG:
+ return lookup_fundamental_type (current_objfile, FT_LONG);
+
+ case T_FLOAT:
+ return lookup_fundamental_type (current_objfile, FT_FLOAT);
+
+ case T_DOUBLE:
+ return lookup_fundamental_type (current_objfile, FT_DBL_PREC_FLOAT);
+
+ case T_STRUCT:
+ if (cs->c_naux != 1)
+ {
+ /* anonymous structure type */
+ type = coff_alloc_type (cs->c_symnum);
+ TYPE_CODE (type) = TYPE_CODE_STRUCT;
+ TYPE_NAME (type) = NULL;
+ /* This used to set the tag to "<opaque>". But I think setting it
+ to NULL is right, and the printing code can print it as
+ "struct {...}". */
+ TYPE_TAG_NAME (type) = NULL;
+ INIT_CPLUS_SPECIFIC(type);
+ TYPE_LENGTH (type) = 0;
+ TYPE_FIELDS (type) = 0;
+ TYPE_NFIELDS (type) = 0;
+ }
+ else
+ {
+ type = coff_read_struct_type (cs->c_symnum,
+ aux->x_sym.x_misc.x_lnsz.x_size,
+ aux->x_sym.x_fcnary.x_fcn.x_endndx.l);
+ }
+ return type;
+
+ case T_UNION:
+ if (cs->c_naux != 1)
+ {
+ /* anonymous union type */
+ type = coff_alloc_type (cs->c_symnum);
+ TYPE_NAME (type) = NULL;
+ /* This used to set the tag to "<opaque>". But I think setting it
+ to NULL is right, and the printing code can print it as
+ "union {...}". */
+ TYPE_TAG_NAME (type) = NULL;
+ INIT_CPLUS_SPECIFIC(type);
+ TYPE_LENGTH (type) = 0;
+ TYPE_FIELDS (type) = 0;
+ TYPE_NFIELDS (type) = 0;
+ }
+ else
+ {
+ type = coff_read_struct_type (cs->c_symnum,
+ aux->x_sym.x_misc.x_lnsz.x_size,
+ aux->x_sym.x_fcnary.x_fcn.x_endndx.l);
+ }
+ TYPE_CODE (type) = TYPE_CODE_UNION;
+ return type;
+
+ case T_ENUM:
+ if (cs->c_naux != 1)
+ {
+ /* anonymous enum type */
+ type = coff_alloc_type (cs->c_symnum);
+ TYPE_CODE (type) = TYPE_CODE_ENUM;
+ TYPE_NAME (type) = NULL;
+ /* This used to set the tag to "<opaque>". But I think setting it
+ to NULL is right, and the printing code can print it as
+ "enum {...}". */
+ TYPE_TAG_NAME (type) = NULL;
+ TYPE_LENGTH (type) = 0;
+ TYPE_FIELDS (type) = 0;
+ TYPE_NFIELDS(type) = 0;
+ }
+ else
+ {
+ type = coff_read_enum_type (cs->c_symnum,
+ aux->x_sym.x_misc.x_lnsz.x_size,
+ aux->x_sym.x_fcnary.x_fcn.x_endndx.l);
+ }
+ return type;
+
+ case T_MOE:
+ /* shouldn't show up here */
+ break;
+
+ case T_UCHAR:
+ return lookup_fundamental_type (current_objfile, FT_UNSIGNED_CHAR);
+
+ case T_USHORT:
+ return lookup_fundamental_type (current_objfile, FT_UNSIGNED_SHORT);
+
+ case T_UINT:
+ return lookup_fundamental_type (current_objfile, FT_UNSIGNED_INTEGER);
+
+ case T_ULONG:
+ return lookup_fundamental_type (current_objfile, FT_UNSIGNED_LONG);
+ }
+ complain (&unexpected_type_complaint, cs->c_name);
+ return lookup_fundamental_type (current_objfile, FT_VOID);
+}
+
+/* This page contains subroutines of read_type. */
+
+/* Read the description of a structure (or union type)
+ and return an object describing the type. */
+
+static struct type *
+coff_read_struct_type (index, length, lastsym)
+ int index;
+ int length;
+ int lastsym;
+{
+ struct nextfield
+ {
+ struct nextfield *next;
+ struct field field;
+ };
+
+ register struct type *type;
+ register struct nextfield *list = 0;
+ struct nextfield *new;
+ int nfields = 0;
+ register int n;
+ char *name;
+ struct coff_symbol member_sym;
+ register struct coff_symbol *ms = &member_sym;
+ struct internal_syment sub_sym;
+ union internal_auxent sub_aux;
+ int done = 0;
+
+ type = coff_alloc_type (index);
+ TYPE_CODE (type) = TYPE_CODE_STRUCT;
+ INIT_CPLUS_SPECIFIC(type);
+ TYPE_LENGTH (type) = length;
+
+ while (!done && symnum < lastsym && symnum < nlist_nsyms_global)
+ {
+ read_one_sym (ms, &sub_sym, &sub_aux);
+ name = ms->c_name;
+ name = EXTERNAL_NAME (name, current_objfile->obfd);
+
+ switch (ms->c_sclass)
+ {
+ case C_MOS:
+ case C_MOU:
+
+ /* Get space to record the next field's data. */
+ new = (struct nextfield *) alloca (sizeof (struct nextfield));
+ new->next = list;
+ list = new;
+
+ /* Save the data. */
+ list->field.name = savestring (name, strlen (name));
+ list->field.type = decode_type (ms, ms->c_type, &sub_aux);
+ list->field.bitpos = 8 * ms->c_value;
+ list->field.bitsize = 0;
+ nfields++;
+ break;
+
+ case C_FIELD:
+
+ /* Get space to record the next field's data. */
+ new = (struct nextfield *) alloca (sizeof (struct nextfield));
+ new->next = list;
+ list = new;
+
+ /* Save the data. */
+ list->field.name = savestring (name, strlen (name));
+ list->field.type = decode_type (ms, ms->c_type, &sub_aux);
+ list->field.bitpos = ms->c_value;
+ list->field.bitsize = sub_aux.x_sym.x_misc.x_lnsz.x_size;
+ nfields++;
+ break;
+
+ case C_EOS:
+ done = 1;
+ break;
+ }
+ }
+ /* Now create the vector of fields, and record how big it is. */
+
+ TYPE_NFIELDS (type) = nfields;
+ TYPE_FIELDS (type) = (struct field *)
+ TYPE_ALLOC (type, sizeof (struct field) * nfields);
+
+ /* Copy the saved-up fields into the field vector. */
+
+ for (n = nfields; list; list = list->next)
+ TYPE_FIELD (type, --n) = list->field;
+
+ return type;
+}
+
+/* Read a definition of an enumeration type,
+ and create and return a suitable type object.
+ Also defines the symbols that represent the values of the type. */
+
+/* ARGSUSED */
+static struct type *
+coff_read_enum_type (index, length, lastsym)
+ int index;
+ int length;
+ int lastsym;
+{
+ register struct symbol *sym;
+ register struct type *type;
+ int nsyms = 0;
+ int done = 0;
+ struct pending **symlist;
+ struct coff_symbol member_sym;
+ register struct coff_symbol *ms = &member_sym;
+ struct internal_syment sub_sym;
+ union internal_auxent sub_aux;
+ struct pending *osyms, *syms;
+ int o_nsyms;
+ register int n;
+ char *name;
+
+ type = coff_alloc_type (index);
+ if (within_function)
+ symlist = &local_symbols;
+ else
+ symlist = &file_symbols;
+ osyms = *symlist;
+ o_nsyms = osyms ? osyms->nsyms : 0;
+
+ while (!done && symnum < lastsym && symnum < nlist_nsyms_global)
+ {
+ read_one_sym (ms, &sub_sym, &sub_aux);
+ name = ms->c_name;
+ name = EXTERNAL_NAME (name, current_objfile->obfd);
+
+ switch (ms->c_sclass)
+ {
+ case C_MOE:
+ sym = (struct symbol *) xmalloc (sizeof (struct symbol));
+ memset (sym, 0, sizeof (struct symbol));
+
+ SYMBOL_NAME (sym) = savestring (name, strlen (name));
+ SYMBOL_CLASS (sym) = LOC_CONST;
+ SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE;
+ SYMBOL_VALUE (sym) = ms->c_value;
+ add_symbol_to_list (sym, symlist);
+ nsyms++;
+ break;
+
+ case C_EOS:
+ /* Sometimes the linker (on 386/ix 2.0.2 at least) screws
+ up the count of how many symbols to read. So stop
+ on .eos. */
+ done = 1;
+ break;
+ }
+ }
+
+ /* Now fill in the fields of the type-structure. */
+
+ if (length > 0)
+ TYPE_LENGTH (type) = length;
+ else
+ TYPE_LENGTH (type) = TARGET_INT_BIT / TARGET_CHAR_BIT; /* Assume ints */
+ TYPE_CODE (type) = TYPE_CODE_ENUM;
+ TYPE_NFIELDS (type) = nsyms;
+ TYPE_FIELDS (type) = (struct field *)
+ TYPE_ALLOC (type, sizeof (struct field) * nsyms);
+
+ /* Find the symbols for the values and put them into the type.
+ The symbols can be found in the symlist that we put them on
+ to cause them to be defined. osyms contains the old value
+ of that symlist; everything up to there was defined by us. */
+ /* Note that we preserve the order of the enum constants, so
+ that in something like "enum {FOO, LAST_THING=FOO}" we print
+ FOO, not LAST_THING. */
+
+ for (syms = *symlist, n = 0; syms; syms = syms->next)
+ {
+ int j = 0;
+ if (syms == osyms)
+ j = o_nsyms;
+ for (; j < syms->nsyms; j++,n++)
+ {
+ struct symbol *xsym = syms->symbol[j];
+ SYMBOL_TYPE (xsym) = type;
+ TYPE_FIELD_NAME (type, n) = SYMBOL_NAME (xsym);
+ TYPE_FIELD_VALUE (type, n) = 0;
+ TYPE_FIELD_BITPOS (type, n) = SYMBOL_VALUE (xsym);
+ TYPE_FIELD_BITSIZE (type, n) = 0;
+ }
+ if (syms == osyms)
+ break;
+ }
+
+ return type;
+}
+
+struct section_offsets *
+coff_symfile_offsets (objfile, addr)
+ struct objfile *objfile;
+ CORE_ADDR addr;
+{
+ struct section_offsets *section_offsets;
+ int i;
+
+ objfile->num_sections = SECT_OFF_MAX;
+ section_offsets = (struct section_offsets *)
+ obstack_alloc (&objfile -> psymbol_obstack,
+ sizeof (struct section_offsets)
+ + sizeof (section_offsets->offsets) * (SECT_OFF_MAX-1));
+
+ for (i = 0; i < SECT_OFF_MAX; i++)
+ ANOFFSET (section_offsets, i) = addr;
+
+ return section_offsets;
+}
+
+/* Register our ability to parse symbols for coff BFD files */
+
+static struct sym_fns coff_sym_fns =
+{
+ bfd_target_coff_flavour,
+ coff_new_init, /* sym_new_init: init anything gbl to entire symtab */
+ coff_symfile_init, /* sym_init: read initial info, setup for sym_read() */
+ coff_symfile_read, /* sym_read: read a symbol file into symtab */
+ coff_symfile_finish, /* sym_finish: finished with file, cleanup */
+ coff_symfile_offsets, /* sym_offsets: xlate external to internal form */
+ NULL /* next: pointer to next struct sym_fns */
+};
+
+void
+_initialize_coffread ()
+{
+ add_symtab_fns(&coff_sym_fns);
+}
diff --git a/gnu/usr.bin/gdb/gdb/command.c b/gnu/usr.bin/gdb/gdb/command.c
new file mode 100644
index 0000000..5d42886
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/command.c
@@ -0,0 +1,1331 @@
+/* Handle lists of commands, their decoding and documentation, for GDB.
+ Copyright 1986, 1989, 1990, 1991 Free Software Foundation, Inc.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "defs.h"
+#include "gdbcmd.h"
+#include "symtab.h"
+#include "value.h"
+#include <ctype.h>
+#include <string.h>
+
+/* Prototypes for local functions */
+
+static void
+undef_cmd_error PARAMS ((char *, char *));
+
+static void
+show_user PARAMS ((char *, int));
+
+static void
+show_user_1 PARAMS ((struct cmd_list_element *, GDB_FILE *));
+
+static void
+make_command PARAMS ((char *, int));
+
+static void
+shell_escape PARAMS ((char *, int));
+
+static int
+parse_binary_operation PARAMS ((char *));
+
+static void
+print_doc_line PARAMS ((GDB_FILE *, char *));
+
+/* Add element named NAME.
+ CLASS is the top level category into which commands are broken down
+ for "help" purposes.
+ FUN should be the function to execute the command;
+ it will get a character string as argument, with leading
+ and trailing blanks already eliminated.
+
+ DOC is a documentation string for the command.
+ Its first line should be a complete sentence.
+ It should start with ? for a command that is an abbreviation
+ or with * for a command that most users don't need to know about.
+
+ Add this command to command list *LIST. */
+
+struct cmd_list_element *
+add_cmd (name, class, fun, doc, list)
+ char *name;
+ enum command_class class;
+ void (*fun) PARAMS ((char *, int));
+ char *doc;
+ struct cmd_list_element **list;
+{
+ register struct cmd_list_element *c
+ = (struct cmd_list_element *) xmalloc (sizeof (struct cmd_list_element));
+
+ delete_cmd (name, list);
+ c->next = *list;
+ c->name = name;
+ c->class = class;
+ c->function.cfunc = fun;
+ c->doc = doc;
+ c->prefixlist = 0;
+ c->prefixname = (char *)NULL;
+ c->allow_unknown = 0;
+ c->hook = 0;
+ c->hookee = 0;
+ c->cmd_pointer = 0;
+ c->abbrev_flag = 0;
+ c->type = not_set_cmd;
+ c->completer = make_symbol_completion_list;
+ c->var = 0;
+ c->var_type = var_boolean;
+ c->user_commands = 0;
+ *list = c;
+ return c;
+}
+
+/* Same as above, except that the abbrev_flag is set. */
+
+#if 0 /* Currently unused */
+
+struct cmd_list_element *
+add_abbrev_cmd (name, class, fun, doc, list)
+ char *name;
+ enum command_class class;
+ void (*fun) PARAMS ((char *, int));
+ char *doc;
+ struct cmd_list_element **list;
+{
+ register struct cmd_list_element *c
+ = add_cmd (name, class, fun, doc, list);
+
+ c->abbrev_flag = 1;
+ return c;
+}
+
+#endif
+
+struct cmd_list_element *
+add_alias_cmd (name, oldname, class, abbrev_flag, list)
+ char *name;
+ char *oldname;
+ enum command_class class;
+ int abbrev_flag;
+ struct cmd_list_element **list;
+{
+ /* Must do this since lookup_cmd tries to side-effect its first arg */
+ char *copied_name;
+ register struct cmd_list_element *old;
+ register struct cmd_list_element *c;
+ copied_name = (char *) alloca (strlen (oldname) + 1);
+ strcpy (copied_name, oldname);
+ old = lookup_cmd (&copied_name, *list, "", 1, 1);
+
+ if (old == 0)
+ {
+ delete_cmd (name, list);
+ return 0;
+ }
+
+ c = add_cmd (name, class, old->function.cfunc, old->doc, list);
+ c->prefixlist = old->prefixlist;
+ c->prefixname = old->prefixname;
+ c->allow_unknown = old->allow_unknown;
+ c->abbrev_flag = abbrev_flag;
+ c->cmd_pointer = old;
+ return c;
+}
+
+/* Like add_cmd but adds an element for a command prefix:
+ a name that should be followed by a subcommand to be looked up
+ in another command list. PREFIXLIST should be the address
+ of the variable containing that list. */
+
+struct cmd_list_element *
+add_prefix_cmd (name, class, fun, doc, prefixlist, prefixname,
+ allow_unknown, list)
+ char *name;
+ enum command_class class;
+ void (*fun) PARAMS ((char *, int));
+ char *doc;
+ struct cmd_list_element **prefixlist;
+ char *prefixname;
+ int allow_unknown;
+ struct cmd_list_element **list;
+{
+ register struct cmd_list_element *c = add_cmd (name, class, fun, doc, list);
+ c->prefixlist = prefixlist;
+ c->prefixname = prefixname;
+ c->allow_unknown = allow_unknown;
+ return c;
+}
+
+/* Like add_prefix_cmd but sets the abbrev_flag on the new command. */
+
+struct cmd_list_element *
+add_abbrev_prefix_cmd (name, class, fun, doc, prefixlist, prefixname,
+ allow_unknown, list)
+ char *name;
+ enum command_class class;
+ void (*fun) PARAMS ((char *, int));
+ char *doc;
+ struct cmd_list_element **prefixlist;
+ char *prefixname;
+ int allow_unknown;
+ struct cmd_list_element **list;
+{
+ register struct cmd_list_element *c = add_cmd (name, class, fun, doc, list);
+ c->prefixlist = prefixlist;
+ c->prefixname = prefixname;
+ c->allow_unknown = allow_unknown;
+ c->abbrev_flag = 1;
+ return c;
+}
+
+/* This is an empty "cfunc". */
+void
+not_just_help_class_command (args, from_tty)
+ char *args;
+ int from_tty;
+{
+}
+
+/* This is an empty "sfunc". */
+static void empty_sfunc PARAMS ((char *, int, struct cmd_list_element *));
+
+static void
+empty_sfunc (args, from_tty, c)
+ char *args;
+ int from_tty;
+ struct cmd_list_element *c;
+{
+}
+
+/* Add element named NAME to command list LIST (the list for set
+ or some sublist thereof).
+ CLASS is as in add_cmd.
+ VAR_TYPE is the kind of thing we are setting.
+ VAR is address of the variable being controlled by this command.
+ DOC is the documentation string. */
+
+struct cmd_list_element *
+add_set_cmd (name, class, var_type, var, doc, list)
+ char *name;
+ enum command_class class;
+ var_types var_type;
+ char *var;
+ char *doc;
+ struct cmd_list_element **list;
+{
+ struct cmd_list_element *c
+ = add_cmd (name, class, NO_FUNCTION, doc, list);
+
+ c->type = set_cmd;
+ c->var_type = var_type;
+ c->var = var;
+ /* This needs to be something besides NO_FUNCTION so that this isn't
+ treated as a help class. */
+ c->function.sfunc = empty_sfunc;
+ return c;
+}
+
+/* Where SETCMD has already been added, add the corresponding show
+ command to LIST and return a pointer to it. */
+struct cmd_list_element *
+add_show_from_set (setcmd, list)
+ struct cmd_list_element *setcmd;
+ struct cmd_list_element **list;
+{
+ struct cmd_list_element *showcmd =
+ (struct cmd_list_element *) xmalloc (sizeof (struct cmd_list_element));
+
+ memcpy (showcmd, setcmd, sizeof (struct cmd_list_element));
+ delete_cmd (showcmd->name, list);
+ showcmd->type = show_cmd;
+
+ /* Replace "set " at start of docstring with "show ". */
+ if (setcmd->doc[0] == 'S' && setcmd->doc[1] == 'e'
+ && setcmd->doc[2] == 't' && setcmd->doc[3] == ' ')
+ showcmd->doc = concat ("Show ", setcmd->doc + 4, NULL);
+ else
+ fprintf_unfiltered (gdb_stderr, "GDB internal error: Bad docstring for set command\n");
+
+ showcmd->next = *list;
+ *list = showcmd;
+ return showcmd;
+}
+
+/* Remove the command named NAME from the command list. */
+
+void
+delete_cmd (name, list)
+ char *name;
+ struct cmd_list_element **list;
+{
+ register struct cmd_list_element *c;
+ struct cmd_list_element *p;
+
+ while (*list && STREQ ((*list)->name, name))
+ {
+ if ((*list)->hookee)
+ (*list)->hookee->hook = 0; /* Hook slips out of its mouth */
+ p = (*list)->next;
+ free ((PTR)*list);
+ *list = p;
+ }
+
+ if (*list)
+ for (c = *list; c->next;)
+ {
+ if (STREQ (c->next->name, name))
+ {
+ if (c->next->hookee)
+ c->next->hookee->hook = 0; /* hooked cmd gets away. */
+ p = c->next->next;
+ free ((PTR)c->next);
+ c->next = p;
+ }
+ else
+ c = c->next;
+ }
+}
+
+/* This command really has to deal with two things:
+ * 1) I want documentation on *this string* (usually called by
+ * "help commandname").
+ * 2) I want documentation on *this list* (usually called by
+ * giving a command that requires subcommands. Also called by saying
+ * just "help".)
+ *
+ * I am going to split this into two seperate comamnds, help_cmd and
+ * help_list.
+ */
+
+void
+help_cmd (command, stream)
+ char *command;
+ GDB_FILE *stream;
+{
+ struct cmd_list_element *c;
+ extern struct cmd_list_element *cmdlist;
+
+ if (!command)
+ {
+ help_list (cmdlist, "", all_classes, stream);
+ return;
+ }
+
+ c = lookup_cmd (&command, cmdlist, "", 0, 0);
+
+ if (c == 0)
+ return;
+
+ /* There are three cases here.
+ If c->prefixlist is nonzero, we have a prefix command.
+ Print its documentation, then list its subcommands.
+
+ If c->function is nonzero, we really have a command.
+ Print its documentation and return.
+
+ If c->function is zero, we have a class name.
+ Print its documentation (as if it were a command)
+ and then set class to the number of this class
+ so that the commands in the class will be listed. */
+
+ fputs_filtered (c->doc, stream);
+ fputs_filtered ("\n", stream);
+
+ if (c->prefixlist == 0 && c->function.cfunc != NULL)
+ return;
+ fprintf_filtered (stream, "\n");
+
+ /* If this is a prefix command, print it's subcommands */
+ if (c->prefixlist)
+ help_list (*c->prefixlist, c->prefixname, all_commands, stream);
+
+ /* If this is a class name, print all of the commands in the class */
+ if (c->function.cfunc == NULL)
+ help_list (cmdlist, "", c->class, stream);
+
+ if (c->hook)
+ fprintf_filtered (stream, "\nThis command has a hook defined: %s\n",
+ c->hook->name);
+}
+
+/*
+ * Get a specific kind of help on a command list.
+ *
+ * LIST is the list.
+ * CMDTYPE is the prefix to use in the title string.
+ * CLASS is the class with which to list the nodes of this list (see
+ * documentation for help_cmd_list below), As usual, ALL_COMMANDS for
+ * everything, ALL_CLASSES for just classes, and non-negative for only things
+ * in a specific class.
+ * and STREAM is the output stream on which to print things.
+ * If you call this routine with a class >= 0, it recurses.
+ */
+void
+help_list (list, cmdtype, class, stream)
+ struct cmd_list_element *list;
+ char *cmdtype;
+ enum command_class class;
+ GDB_FILE *stream;
+{
+ int len;
+ char *cmdtype1, *cmdtype2;
+
+ /* If CMDTYPE is "foo ", CMDTYPE1 gets " foo" and CMDTYPE2 gets "foo sub" */
+ len = strlen (cmdtype);
+ cmdtype1 = (char *) alloca (len + 1);
+ cmdtype1[0] = 0;
+ cmdtype2 = (char *) alloca (len + 4);
+ cmdtype2[0] = 0;
+ if (len)
+ {
+ cmdtype1[0] = ' ';
+ strncpy (cmdtype1 + 1, cmdtype, len - 1);
+ cmdtype1[len] = 0;
+ strncpy (cmdtype2, cmdtype, len - 1);
+ strcpy (cmdtype2 + len - 1, " sub");
+ }
+
+ if (class == all_classes)
+ fprintf_filtered (stream, "List of classes of %scommands:\n\n", cmdtype2);
+ else
+ fprintf_filtered (stream, "List of %scommands:\n\n", cmdtype2);
+
+ help_cmd_list (list, class, cmdtype, (int)class >= 0, stream);
+
+ if (class == all_classes)
+ fprintf_filtered (stream, "\n\
+Type \"help%s\" followed by a class name for a list of commands in that class.",
+ cmdtype1);
+
+ fprintf_filtered (stream, "\n\
+Type \"help%s\" followed by %scommand name for full documentation.\n\
+Command name abbreviations are allowed if unambiguous.\n",
+ cmdtype1, cmdtype2);
+}
+
+/* Print only the first line of STR on STREAM. */
+static void
+print_doc_line (stream, str)
+ GDB_FILE *stream;
+ char *str;
+{
+ static char *line_buffer = 0;
+ static int line_size;
+ register char *p;
+
+ if (!line_buffer)
+ {
+ line_size = 80;
+ line_buffer = (char *) xmalloc (line_size);
+ }
+
+ p = str;
+ while (*p && *p != '\n' && *p != '.' && *p != ',')
+ p++;
+ if (p - str > line_size - 1)
+ {
+ line_size = p - str + 1;
+ free ((PTR)line_buffer);
+ line_buffer = (char *) xmalloc (line_size);
+ }
+ strncpy (line_buffer, str, p - str);
+ line_buffer[p - str] = '\0';
+ if (islower (line_buffer[0]))
+ line_buffer[0] = toupper (line_buffer[0]);
+ fputs_filtered (line_buffer, stream);
+}
+
+/*
+ * Implement a help command on command list LIST.
+ * RECURSE should be non-zero if this should be done recursively on
+ * all sublists of LIST.
+ * PREFIX is the prefix to print before each command name.
+ * STREAM is the stream upon which the output should be written.
+ * CLASS should be:
+ * A non-negative class number to list only commands in that
+ * class.
+ * ALL_COMMANDS to list all commands in list.
+ * ALL_CLASSES to list all classes in list.
+ *
+ * Note that RECURSE will be active on *all* sublists, not just the
+ * ones selected by the criteria above (ie. the selection mechanism
+ * is at the low level, not the high-level).
+ */
+void
+help_cmd_list (list, class, prefix, recurse, stream)
+ struct cmd_list_element *list;
+ enum command_class class;
+ char *prefix;
+ int recurse;
+ GDB_FILE *stream;
+{
+ register struct cmd_list_element *c;
+
+ for (c = list; c; c = c->next)
+ {
+ if (c->abbrev_flag == 0 &&
+ (class == all_commands
+ || (class == all_classes && c->function.cfunc == NULL)
+ || (class == c->class && c->function.cfunc != NULL)))
+ {
+ fprintf_filtered (stream, "%s%s -- ", prefix, c->name);
+ print_doc_line (stream, c->doc);
+ fputs_filtered ("\n", stream);
+ }
+ if (recurse
+ && c->prefixlist != 0
+ && c->abbrev_flag == 0)
+ help_cmd_list (*c->prefixlist, class, c->prefixname, 1, stream);
+ }
+}
+
+/* This routine takes a line of TEXT and a CLIST in which to start the
+ lookup. When it returns it will have incremented the text pointer past
+ the section of text it matched, set *RESULT_LIST to point to the list in
+ which the last word was matched, and will return a pointer to the cmd
+ list element which the text matches. It will return NULL if no match at
+ all was possible. It will return -1 (cast appropriately, ick) if ambigous
+ matches are possible; in this case *RESULT_LIST will be set to point to
+ the list in which there are ambiguous choices (and *TEXT will be set to
+ the ambiguous text string).
+
+ If the located command was an abbreviation, this routine returns the base
+ command of the abbreviation.
+
+ It does no error reporting whatsoever; control will always return
+ to the superior routine.
+
+ In the case of an ambiguous return (-1), *RESULT_LIST will be set to point
+ at the prefix_command (ie. the best match) *or* (special case) will be NULL
+ if no prefix command was ever found. For example, in the case of "info a",
+ "info" matches without ambiguity, but "a" could be "args" or "address", so
+ *RESULT_LIST is set to the cmd_list_element for "info". So in this case
+ RESULT_LIST should not be interpeted as a pointer to the beginning of a
+ list; it simply points to a specific command. In the case of an ambiguous
+ return *TEXT is advanced past the last non-ambiguous prefix (e.g.
+ "info t" can be "info types" or "info target"; upon return *TEXT has been
+ advanced past "info ").
+
+ If RESULT_LIST is NULL, don't set *RESULT_LIST (but don't otherwise
+ affect the operation).
+
+ This routine does *not* modify the text pointed to by TEXT.
+
+ If IGNORE_HELP_CLASSES is nonzero, ignore any command list elements which
+ are actually help classes rather than commands (i.e. the function field of
+ the struct cmd_list_element is NULL). */
+
+struct cmd_list_element *
+lookup_cmd_1 (text, clist, result_list, ignore_help_classes)
+ char **text;
+ struct cmd_list_element *clist, **result_list;
+ int ignore_help_classes;
+{
+ char *p, *command;
+ int len, tmp, nfound;
+ struct cmd_list_element *found, *c;
+
+ while (**text == ' ' || **text == '\t')
+ (*text)++;
+
+ /* Treating underscores as part of command words is important
+ so that "set args_foo()" doesn't get interpreted as
+ "set args _foo()". */
+ for (p = *text;
+ *p && (isalnum(*p) || *p == '-' || *p == '_');
+ p++)
+ ;
+
+ /* If nothing but whitespace, return 0. */
+ if (p == *text)
+ return 0;
+
+ len = p - *text;
+
+ /* *text and p now bracket the first command word to lookup (and
+ it's length is len). We copy this into a local temporary,
+ converting to lower case as we go. */
+
+ command = (char *) alloca (len + 1);
+ for (tmp = 0; tmp < len; tmp++)
+ {
+ char x = (*text)[tmp];
+ command[tmp] = isupper(x) ? tolower(x) : x;
+ }
+ command[len] = '\0';
+
+ /* Look it up. */
+ found = 0;
+ nfound = 0;
+ for (c = clist; c; c = c->next)
+ if (!strncmp (command, c->name, len)
+ && (!ignore_help_classes || c->function.cfunc))
+ {
+ found = c;
+ nfound++;
+ if (c->name[len] == '\0')
+ {
+ nfound = 1;
+ break;
+ }
+ }
+
+ /* If nothing matches, we have a simple failure. */
+ if (nfound == 0)
+ return 0;
+
+ if (nfound > 1)
+ {
+ if (result_list != NULL)
+ /* Will be modified in calling routine
+ if we know what the prefix command is. */
+ *result_list = 0;
+ return (struct cmd_list_element *) -1; /* Ambiguous. */
+ }
+
+ /* We've matched something on this list. Move text pointer forward. */
+
+ *text = p;
+
+ /* If this was an abbreviation, use the base command instead. */
+
+ if (found->cmd_pointer)
+ found = found->cmd_pointer;
+
+ /* If we found a prefix command, keep looking. */
+
+ if (found->prefixlist)
+ {
+ c = lookup_cmd_1 (text, *found->prefixlist, result_list,
+ ignore_help_classes);
+ if (!c)
+ {
+ /* Didn't find anything; this is as far as we got. */
+ if (result_list != NULL)
+ *result_list = clist;
+ return found;
+ }
+ else if (c == (struct cmd_list_element *) -1)
+ {
+ /* We've gotten this far properley, but the next step
+ is ambiguous. We need to set the result list to the best
+ we've found (if an inferior hasn't already set it). */
+ if (result_list != NULL)
+ if (!*result_list)
+ /* This used to say *result_list = *found->prefixlist
+ If that was correct, need to modify the documentation
+ at the top of this function to clarify what is supposed
+ to be going on. */
+ *result_list = found;
+ return c;
+ }
+ else
+ {
+ /* We matched! */
+ return c;
+ }
+ }
+ else
+ {
+ if (result_list != NULL)
+ *result_list = clist;
+ return found;
+ }
+}
+
+/* All this hair to move the space to the front of cmdtype */
+
+static void
+undef_cmd_error (cmdtype, q)
+ char *cmdtype, *q;
+{
+ error ("Undefined %scommand: \"%s\". Try \"help%s%.*s\".",
+ cmdtype,
+ q,
+ *cmdtype? " ": "",
+ strlen(cmdtype)-1,
+ cmdtype);
+}
+
+/* Look up the contents of *LINE as a command in the command list LIST.
+ LIST is a chain of struct cmd_list_element's.
+ If it is found, return the struct cmd_list_element for that command
+ and update *LINE to point after the command name, at the first argument.
+ If not found, call error if ALLOW_UNKNOWN is zero
+ otherwise (or if error returns) return zero.
+ Call error if specified command is ambiguous,
+ unless ALLOW_UNKNOWN is negative.
+ CMDTYPE precedes the word "command" in the error message.
+
+ If INGNORE_HELP_CLASSES is nonzero, ignore any command list
+ elements which are actually help classes rather than commands (i.e.
+ the function field of the struct cmd_list_element is 0). */
+
+struct cmd_list_element *
+lookup_cmd (line, list, cmdtype, allow_unknown, ignore_help_classes)
+ char **line;
+ struct cmd_list_element *list;
+ char *cmdtype;
+ int allow_unknown;
+ int ignore_help_classes;
+{
+ struct cmd_list_element *last_list = 0;
+ struct cmd_list_element *c =
+ lookup_cmd_1 (line, list, &last_list, ignore_help_classes);
+#if 0
+ /* This is wrong for complete_command. */
+ char *ptr = (*line) + strlen (*line) - 1;
+
+ /* Clear off trailing whitespace. */
+ while (ptr >= *line && (*ptr == ' ' || *ptr == '\t'))
+ ptr--;
+ *(ptr + 1) = '\0';
+#endif
+
+ if (!c)
+ {
+ if (!allow_unknown)
+ {
+ if (!*line)
+ error ("Lack of needed %scommand", cmdtype);
+ else
+ {
+ char *p = *line, *q;
+
+ while (isalnum(*p) || *p == '-')
+ p++;
+
+ q = (char *) alloca (p - *line + 1);
+ strncpy (q, *line, p - *line);
+ q[p-*line] = '\0';
+ undef_cmd_error (cmdtype, q);
+ }
+ }
+ else
+ return 0;
+ }
+ else if (c == (struct cmd_list_element *) -1)
+ {
+ /* Ambigous. Local values should be off prefixlist or called
+ values. */
+ int local_allow_unknown = (last_list ? last_list->allow_unknown :
+ allow_unknown);
+ char *local_cmdtype = last_list ? last_list->prefixname : cmdtype;
+ struct cmd_list_element *local_list =
+ (last_list ? *(last_list->prefixlist) : list);
+
+ if (local_allow_unknown < 0)
+ {
+ if (last_list)
+ return last_list; /* Found something. */
+ else
+ return 0; /* Found nothing. */
+ }
+ else
+ {
+ /* Report as error. */
+ int amb_len;
+ char ambbuf[100];
+
+ for (amb_len = 0;
+ ((*line)[amb_len] && (*line)[amb_len] != ' '
+ && (*line)[amb_len] != '\t');
+ amb_len++)
+ ;
+
+ ambbuf[0] = 0;
+ for (c = local_list; c; c = c->next)
+ if (!strncmp (*line, c->name, amb_len))
+ {
+ if (strlen (ambbuf) + strlen (c->name) + 6 < (int)sizeof ambbuf)
+ {
+ if (strlen (ambbuf))
+ strcat (ambbuf, ", ");
+ strcat (ambbuf, c->name);
+ }
+ else
+ {
+ strcat (ambbuf, "..");
+ break;
+ }
+ }
+ error ("Ambiguous %scommand \"%s\": %s.", local_cmdtype,
+ *line, ambbuf);
+ return 0; /* lint */
+ }
+ }
+ else
+ {
+ /* We've got something. It may still not be what the caller
+ wants (if this command *needs* a subcommand). */
+ while (**line == ' ' || **line == '\t')
+ (*line)++;
+
+ if (c->prefixlist && **line && !c->allow_unknown)
+ undef_cmd_error (c->prefixname, *line);
+
+ /* Seems to be what he wants. Return it. */
+ return c;
+ }
+ return 0;
+}
+
+#if 0
+/* Look up the contents of *LINE as a command in the command list LIST.
+ LIST is a chain of struct cmd_list_element's.
+ If it is found, return the struct cmd_list_element for that command
+ and update *LINE to point after the command name, at the first argument.
+ If not found, call error if ALLOW_UNKNOWN is zero
+ otherwise (or if error returns) return zero.
+ Call error if specified command is ambiguous,
+ unless ALLOW_UNKNOWN is negative.
+ CMDTYPE precedes the word "command" in the error message. */
+
+struct cmd_list_element *
+lookup_cmd (line, list, cmdtype, allow_unknown)
+ char **line;
+ struct cmd_list_element *list;
+ char *cmdtype;
+ int allow_unknown;
+{
+ register char *p;
+ register struct cmd_list_element *c, *found;
+ int nfound;
+ char ambbuf[100];
+ char *processed_cmd;
+ int i, cmd_len;
+
+ /* Skip leading whitespace. */
+
+ while (**line == ' ' || **line == '\t')
+ (*line)++;
+
+ /* Clear out trailing whitespace. */
+
+ p = *line + strlen (*line);
+ while (p != *line && (p[-1] == ' ' || p[-1] == '\t'))
+ p--;
+ *p = 0;
+
+ /* Find end of command name. */
+
+ p = *line;
+ while (*p == '-' || isalnum(*p))
+ p++;
+
+ /* Look up the command name.
+ If exact match, keep that.
+ Otherwise, take command abbreviated, if unique. Note that (in my
+ opinion) a null string does *not* indicate ambiguity; simply the
+ end of the argument. */
+
+ if (p == *line)
+ {
+ if (!allow_unknown)
+ error ("Lack of needed %scommand", cmdtype);
+ return 0;
+ }
+
+ /* Copy over to a local buffer, converting to lowercase on the way.
+ This is in case the command being parsed is a subcommand which
+ doesn't match anything, and that's ok. We want the original
+ untouched for the routine of the original command. */
+
+ processed_cmd = (char *) alloca (p - *line + 1);
+ for (cmd_len = 0; cmd_len < p - *line; cmd_len++)
+ {
+ char x = (*line)[cmd_len];
+ if (isupper(x))
+ processed_cmd[cmd_len] = tolower(x);
+ else
+ processed_cmd[cmd_len] = x;
+ }
+ processed_cmd[cmd_len] = '\0';
+
+ /* Check all possibilities in the current command list. */
+ found = 0;
+ nfound = 0;
+ for (c = list; c; c = c->next)
+ {
+ if (!strncmp (processed_cmd, c->name, cmd_len))
+ {
+ found = c;
+ nfound++;
+ if (c->name[cmd_len] == 0)
+ {
+ nfound = 1;
+ break;
+ }
+ }
+ }
+
+ /* Report error for undefined command name. */
+
+ if (nfound != 1)
+ {
+ if (nfound > 1 && allow_unknown >= 0)
+ {
+ ambbuf[0] = 0;
+ for (c = list; c; c = c->next)
+ if (!strncmp (processed_cmd, c->name, cmd_len))
+ {
+ if (strlen (ambbuf) + strlen (c->name) + 6 < sizeof ambbuf)
+ {
+ if (strlen (ambbuf))
+ strcat (ambbuf, ", ");
+ strcat (ambbuf, c->name);
+ }
+ else
+ {
+ strcat (ambbuf, "..");
+ break;
+ }
+ }
+ error ("Ambiguous %scommand \"%s\": %s.", cmdtype,
+ processed_cmd, ambbuf);
+ }
+ else if (!allow_unknown)
+ error ("Undefined %scommand: \"%s\".", cmdtype, processed_cmd);
+ return 0;
+ }
+
+ /* Skip whitespace before the argument. */
+
+ while (*p == ' ' || *p == '\t') p++;
+ *line = p;
+
+ if (found->prefixlist && *p)
+ {
+ c = lookup_cmd (line, *found->prefixlist, found->prefixname,
+ found->allow_unknown);
+ if (c)
+ return c;
+ }
+
+ return found;
+}
+#endif
+
+/* Helper function for SYMBOL_COMPLETION_FUNCTION. */
+
+/* Return a vector of char pointers which point to the different
+ possible completions in LIST of TEXT.
+
+ WORD points in the same buffer as TEXT, and completions should be
+ returned relative to this position. For example, suppose TEXT is "foo"
+ and we want to complete to "foobar". If WORD is "oo", return
+ "oobar"; if WORD is "baz/foo", return "baz/foobar". */
+
+char **
+complete_on_cmdlist (list, text, word)
+ struct cmd_list_element *list;
+ char *text;
+ char *word;
+{
+ struct cmd_list_element *ptr;
+ char **matchlist;
+ int sizeof_matchlist;
+ int matches;
+ int textlen = strlen (text);
+
+ sizeof_matchlist = 10;
+ matchlist = (char **) xmalloc (sizeof_matchlist * sizeof (char *));
+ matches = 0;
+
+ for (ptr = list; ptr; ptr = ptr->next)
+ if (!strncmp (ptr->name, text, textlen)
+ && !ptr->abbrev_flag
+ && (ptr->function.cfunc
+ || ptr->prefixlist))
+ {
+ if (matches == sizeof_matchlist)
+ {
+ sizeof_matchlist *= 2;
+ matchlist = (char **) xrealloc ((char *)matchlist,
+ (sizeof_matchlist
+ * sizeof (char *)));
+ }
+
+ matchlist[matches] = (char *)
+ xmalloc (strlen (word) + strlen (ptr->name) + 1);
+ if (word == text)
+ strcpy (matchlist[matches], ptr->name);
+ else if (word > text)
+ {
+ /* Return some portion of ptr->name. */
+ strcpy (matchlist[matches], ptr->name + (word - text));
+ }
+ else
+ {
+ /* Return some of text plus ptr->name. */
+ strncpy (matchlist[matches], word, text - word);
+ matchlist[matches][text - word] = '\0';
+ strcat (matchlist[matches], ptr->name);
+ }
+ ++matches;
+ }
+
+ if (matches == 0)
+ {
+ free ((PTR)matchlist);
+ matchlist = 0;
+ }
+ else
+ {
+ matchlist = (char **) xrealloc ((char *)matchlist, ((matches + 1)
+ * sizeof (char *)));
+ matchlist[matches] = (char *) 0;
+ }
+
+ return matchlist;
+}
+
+static int
+parse_binary_operation (arg)
+ char *arg;
+{
+ int length;
+
+ if (!arg || !*arg)
+ return 1;
+
+ length = strlen (arg);
+
+ while (arg[length - 1] == ' ' || arg[length - 1] == '\t')
+ length--;
+
+ if (!strncmp (arg, "on", length)
+ || !strncmp (arg, "1", length)
+ || !strncmp (arg, "yes", length))
+ return 1;
+ else
+ if (!strncmp (arg, "off", length)
+ || !strncmp (arg, "0", length)
+ || !strncmp (arg, "no", length))
+ return 0;
+ else
+ {
+ error ("\"on\" or \"off\" expected.");
+ return 0;
+ }
+}
+
+/* Do a "set" or "show" command. ARG is NULL if no argument, or the text
+ of the argument, and FROM_TTY is nonzero if this command is being entered
+ directly by the user (i.e. these are just like any other
+ command). C is the command list element for the command. */
+void
+do_setshow_command (arg, from_tty, c)
+ char *arg;
+ int from_tty;
+ struct cmd_list_element *c;
+{
+ if (c->type == set_cmd)
+ {
+ switch (c->var_type)
+ {
+ case var_string:
+ {
+ char *new;
+ char *p;
+ char *q;
+ int ch;
+
+ if (arg == NULL)
+ arg = "";
+ new = (char *) xmalloc (strlen (arg) + 2);
+ p = arg; q = new;
+ while ((ch = *p++) != '\000')
+ {
+ if (ch == '\\')
+ {
+ /* \ at end of argument is used after spaces
+ so they won't be lost. */
+ /* This is obsolete now that we no longer strip
+ trailing whitespace and actually, the backslash
+ didn't get here in my test, readline or
+ something did something funky with a backslash
+ right before a newline. */
+ if (*p == 0)
+ break;
+ ch = parse_escape (&p);
+ if (ch == 0)
+ break; /* C loses */
+ else if (ch > 0)
+ *q++ = ch;
+ }
+ else
+ *q++ = ch;
+ }
+#if 0
+ if (*(p - 1) != '\\')
+ *q++ = ' ';
+#endif
+ *q++ = '\0';
+ new = (char *) xrealloc (new, q - new);
+ if (*(char **)c->var != NULL)
+ free (*(char **)c->var);
+ *(char **) c->var = new;
+ }
+ break;
+ case var_string_noescape:
+ if (arg == NULL)
+ arg = "";
+ if (*(char **)c->var != NULL)
+ free (*(char **)c->var);
+ *(char **) c->var = savestring (arg, strlen (arg));
+ break;
+ case var_filename:
+ if (arg == NULL)
+ error_no_arg ("filename to set it to.");
+ if (*(char **)c->var != NULL)
+ free (*(char **)c->var);
+ *(char **)c->var = tilde_expand (arg);
+ break;
+ case var_boolean:
+ *(int *) c->var = parse_binary_operation (arg);
+ break;
+ case var_uinteger:
+ if (arg == NULL)
+ error_no_arg ("integer to set it to.");
+ *(unsigned int *) c->var = parse_and_eval_address (arg);
+ if (*(unsigned int *) c->var == 0)
+ *(unsigned int *) c->var = UINT_MAX;
+ break;
+ case var_integer:
+ {
+ unsigned int val;
+ if (arg == NULL)
+ error_no_arg ("integer to set it to.");
+ val = parse_and_eval_address (arg);
+ if (val == 0)
+ *(int *) c->var = INT_MAX;
+ else if (val >= INT_MAX)
+ error ("integer %u out of range", val);
+ else
+ *(int *) c->var = val;
+ break;
+ }
+ case var_zinteger:
+ if (arg == NULL)
+ error_no_arg ("integer to set it to.");
+ *(int *) c->var = parse_and_eval_address (arg);
+ break;
+ default:
+ error ("gdb internal error: bad var_type in do_setshow_command");
+ }
+ }
+ else if (c->type == show_cmd)
+ {
+ /* Print doc minus "show" at start. */
+ print_doc_line (gdb_stdout, c->doc + 5);
+
+ fputs_filtered (" is ", gdb_stdout);
+ wrap_here (" ");
+ switch (c->var_type)
+ {
+ case var_string:
+ {
+ unsigned char *p;
+ fputs_filtered ("\"", gdb_stdout);
+ for (p = *(unsigned char **) c->var; *p != '\0'; p++)
+ gdb_printchar (*p, gdb_stdout, '"');
+ fputs_filtered ("\"", gdb_stdout);
+ }
+ break;
+ case var_string_noescape:
+ case var_filename:
+ fputs_filtered ("\"", gdb_stdout);
+ fputs_filtered (*(char **) c->var, gdb_stdout);
+ fputs_filtered ("\"", gdb_stdout);
+ break;
+ case var_boolean:
+ fputs_filtered (*(int *) c->var ? "on" : "off", gdb_stdout);
+ break;
+ case var_uinteger:
+ if (*(unsigned int *) c->var == UINT_MAX) {
+ fputs_filtered ("unlimited", gdb_stdout);
+ break;
+ }
+ /* else fall through */
+ case var_zinteger:
+ fprintf_filtered (gdb_stdout, "%u", *(unsigned int *) c->var);
+ break;
+ case var_integer:
+ if (*(int *) c->var == INT_MAX)
+ {
+ fputs_filtered ("unlimited", gdb_stdout);
+ }
+ else
+ fprintf_filtered (gdb_stdout, "%d", *(int *) c->var);
+ break;
+
+ default:
+ error ("gdb internal error: bad var_type in do_setshow_command");
+ }
+ fputs_filtered (".\n", gdb_stdout);
+ }
+ else
+ error ("gdb internal error: bad cmd_type in do_setshow_command");
+ (*c->function.sfunc) (NULL, from_tty, c);
+}
+
+/* Show all the settings in a list of show commands. */
+
+void
+cmd_show_list (list, from_tty, prefix)
+ struct cmd_list_element *list;
+ int from_tty;
+ char *prefix;
+{
+ for (; list != NULL; list = list->next) {
+ /* If we find a prefix, run its list, prefixing our output by its
+ prefix (with "show " skipped). */
+ if (list->prefixlist && !list->abbrev_flag)
+ cmd_show_list (*list->prefixlist, from_tty, list->prefixname + 5);
+ if (list->type == show_cmd)
+ {
+ fputs_filtered (prefix, gdb_stdout);
+ fputs_filtered (list->name, gdb_stdout);
+ fputs_filtered (": ", gdb_stdout);
+ do_setshow_command ((char *)NULL, from_tty, list);
+ }
+ }
+}
+
+/* ARGSUSED */
+static void
+shell_escape (arg, from_tty)
+ char *arg;
+ int from_tty;
+{
+#ifdef CANT_FORK
+ /* FIXME: what about errors (I don't know how GO32 system() handles
+ them)? */
+ system (arg);
+#else /* Can fork. */
+ int rc, status, pid;
+ char *p, *user_shell;
+
+ if ((user_shell = (char *) getenv ("SHELL")) == NULL)
+ user_shell = "/bin/sh";
+
+ /* Get the name of the shell for arg0 */
+ if ((p = strrchr (user_shell, '/')) == NULL)
+ p = user_shell;
+ else
+ p++; /* Get past '/' */
+
+ if ((pid = fork()) == 0)
+ {
+ if (!arg)
+ execl (user_shell, p, 0);
+ else
+ execl (user_shell, p, "-c", arg, 0);
+
+ fprintf_unfiltered (gdb_stderr, "Cannot execute %s: %s\n", user_shell,
+ safe_strerror (errno));
+ gdb_flush (gdb_stderr);
+ _exit (0177);
+ }
+
+ if (pid != -1)
+ while ((rc = wait (&status)) != pid && rc != -1)
+ ;
+ else
+ error ("Fork failed");
+#endif /* Can fork. */
+}
+
+static void
+make_command (arg, from_tty)
+ char *arg;
+ int from_tty;
+{
+ char *p;
+
+ if (arg == 0)
+ p = "make";
+ else
+ {
+ p = xmalloc (sizeof("make ") + strlen(arg));
+ strcpy (p, "make ");
+ strcpy (p + sizeof("make ")-1, arg);
+ }
+
+ shell_escape (p, from_tty);
+}
+
+static void
+show_user_1 (c, stream)
+ struct cmd_list_element *c;
+ GDB_FILE *stream;
+{
+ register struct command_line *cmdlines;
+
+ cmdlines = c->user_commands;
+ if (!cmdlines)
+ return;
+ fputs_filtered ("User command ", stream);
+ fputs_filtered (c->name, stream);
+ fputs_filtered (":\n", stream);
+ while (cmdlines)
+ {
+ fputs_filtered (cmdlines->line, stream);
+ fputs_filtered ("\n", stream);
+ cmdlines = cmdlines->next;
+ }
+ fputs_filtered ("\n", stream);
+}
+
+/* ARGSUSED */
+static void
+show_user (args, from_tty)
+ char *args;
+ int from_tty;
+{
+ struct cmd_list_element *c;
+ extern struct cmd_list_element *cmdlist;
+
+ if (args)
+ {
+ c = lookup_cmd (&args, cmdlist, "", 0, 1);
+ if (c->class != class_user)
+ error ("Not a user command.");
+ show_user_1 (c, gdb_stdout);
+ }
+ else
+ {
+ for (c = cmdlist; c; c = c->next)
+ {
+ if (c->class == class_user)
+ show_user_1 (c, gdb_stdout);
+ }
+ }
+}
+
+void
+_initialize_command ()
+{
+ add_com ("shell", class_support, shell_escape,
+ "Execute the rest of the line as a shell command. \n\
+With no arguments, run an inferior shell.");
+ add_com ("make", class_support, make_command,
+ "Run the ``make'' program using the rest of the line as arguments.");
+ add_cmd ("user", no_class, show_user,
+ "Show definitions of user defined commands.\n\
+Argument is the name of the user defined command.\n\
+With no argument, show definitions of all user defined commands.", &showlist);
+}
diff --git a/gnu/usr.bin/gdb/gdb/command.h b/gnu/usr.bin/gdb/gdb/command.h
new file mode 100644
index 0000000..360d78a
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/command.h
@@ -0,0 +1,246 @@
+/* Header file for command-reading library command.c.
+ Copyright (C) 1986, 1989, 1990 Free Software Foundation, Inc.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#if !defined (COMMAND_H)
+#define COMMAND_H 1
+
+/* Not a set/show command. Note that some commands which begin with
+ "set" or "show" might be in this category, if their syntax does
+ not fall into one of the following categories. */
+typedef enum cmd_types {
+ not_set_cmd,
+ set_cmd,
+ show_cmd
+} cmd_types;
+
+/* Types of "set" or "show" command. */
+typedef enum var_types {
+ /* "on" or "off". *VAR is an integer which is nonzero for on,
+ zero for off. */
+ var_boolean,
+ /* Unsigned Integer. *VAR is an unsigned int. The user can type 0
+ to mean "unlimited", which is stored in *VAR as UINT_MAX. */
+ var_uinteger,
+
+ /* Like var_uinteger but signed. *VAR is an int. The user can type 0
+ to mean "unlimited", which is stored in *VAR as INT_MAX. */
+ var_integer,
+
+ /* String which the user enters with escapes (e.g. the user types \n and
+ it is a real newline in the stored string).
+ *VAR is a malloc'd string, or NULL if the string is empty. */
+ var_string,
+ /* String which stores what the user types verbatim.
+ *VAR is a malloc'd string, or NULL if the string is empty. */
+ var_string_noescape,
+ /* String which stores a filename.
+ *VAR is a malloc'd string, or NULL if the string is empty. */
+ var_filename,
+ /* ZeroableInteger. *VAR is an int. Like Unsigned Integer except
+ that zero really means zero. */
+ var_zinteger
+} var_types;
+
+/* This structure records one command'd definition. */
+
+struct cmd_list_element
+ {
+ /* Points to next command in this list. */
+ struct cmd_list_element *next;
+
+ /* Name of this command. */
+ char *name;
+
+ /* Command class; class values are chosen by application program. */
+ enum command_class class;
+
+ /* Function definition of this command.
+ NO_FUNCTION for command class names and for help topics that
+ are not really commands. */
+ union
+ {
+ /* If type is not_set_cmd, call it like this: */
+ void (*cfunc) PARAMS ((char *args, int from_tty));
+
+ /* If type is cmd_set or show_cmd, first set the variables, and
+ then call this. */
+ void (*sfunc) PARAMS ((char *args, int from_tty,
+ struct cmd_list_element *c));
+ } function;
+# define NO_FUNCTION ((void (*) PARAMS((char *args, int from_tty))) 0)
+
+ /* Documentation of this command (or help topic).
+ First line is brief documentation; remaining lines form, with it,
+ the full documentation. First line should end with a period.
+ Entire string should also end with a period, not a newline. */
+ char *doc;
+
+ /* Hook for another command to be executed before this command. */
+ struct cmd_list_element *hook;
+
+ /* Nonzero identifies a prefix command. For them, the address
+ of the variable containing the list of subcommands. */
+ struct cmd_list_element **prefixlist;
+
+ /* For prefix commands only:
+ String containing prefix commands to get here: this one
+ plus any others needed to get to it. Should end in a space.
+ It is used before the word "command" in describing the
+ commands reached through this prefix. */
+ char *prefixname;
+
+ /* For prefix commands only:
+ nonzero means do not get an error if subcommand is not
+ recognized; call the prefix's own function in that case. */
+ char allow_unknown;
+
+ /* Nonzero says this is an abbreviation, and should not
+ be mentioned in lists of commands.
+ This allows "br<tab>" to complete to "break", which it
+ otherwise wouldn't. */
+ char abbrev_flag;
+
+ /* Completion routine for this command. TEXT is the text beyond
+ what was matched for the command itself (leading whitespace is
+ skipped). It stops where we are supposed to stop completing
+ (rl_point) and is '\0' terminated.
+
+ Return value is a malloc'd vector of pointers to possible completions
+ terminated with NULL. If there are no completions, returning a pointer
+ to a NULL would work but returning NULL itself is also valid.
+ WORD points in the same buffer as TEXT, and completions should be
+ returned relative to this position. For example, suppose TEXT is "foo"
+ and we want to complete to "foobar". If WORD is "oo", return
+ "oobar"; if WORD is "baz/foo", return "baz/foobar". */
+ char ** (*completer) PARAMS ((char *text, char *word));
+
+ /* Type of "set" or "show" command (or SET_NOT_SET if not "set"
+ or "show"). */
+ cmd_types type;
+
+ /* Pointer to variable affected by "set" and "show". Doesn't matter
+ if type is not_set. */
+ char *var;
+
+ /* What kind of variable is *VAR? */
+ var_types var_type;
+
+ /* Pointer to command strings of user-defined commands */
+ struct command_line *user_commands;
+
+ /* Pointer to command that is hooked by this one,
+ so the hook can be removed when this one is deleted. */
+ struct cmd_list_element *hookee;
+
+ /* Pointer to command that is aliased by this one, so the
+ aliased command can be located in case it has been hooked. */
+ struct cmd_list_element *cmd_pointer;
+ };
+
+/* Forward-declarations of the entry-points of command.c. */
+
+extern struct cmd_list_element *
+add_cmd PARAMS ((char *, enum command_class, void (*fun) (char *, int),
+ char *, struct cmd_list_element **));
+
+extern struct cmd_list_element *
+add_alias_cmd PARAMS ((char *, char *, enum command_class, int,
+ struct cmd_list_element **));
+
+extern struct cmd_list_element *
+add_prefix_cmd PARAMS ((char *, enum command_class, void (*fun) (char *, int),
+ char *, struct cmd_list_element **, char *, int,
+ struct cmd_list_element **));
+
+extern struct cmd_list_element *
+add_abbrev_prefix_cmd PARAMS ((char *, enum command_class,
+ void (*fun) (char *, int), char *,
+ struct cmd_list_element **, char *, int,
+ struct cmd_list_element **));
+
+extern struct cmd_list_element *
+lookup_cmd PARAMS ((char **, struct cmd_list_element *, char *, int, int));
+
+extern struct cmd_list_element *
+lookup_cmd_1 PARAMS ((char **, struct cmd_list_element *,
+ struct cmd_list_element **, int));
+
+extern void
+add_com PARAMS ((char *, enum command_class, void (*fun)(char *, int),
+ char *));
+
+extern void
+add_com_alias PARAMS ((char *, char *, enum command_class, int));
+
+extern void
+add_info PARAMS ((char *, void (*fun) (char *, int), char *));
+
+extern void
+add_info_alias PARAMS ((char *, char *, int));
+
+extern char **complete_on_cmdlist PARAMS ((struct cmd_list_element *,
+ char *, char *));
+
+extern void
+delete_cmd PARAMS ((char *, struct cmd_list_element **));
+
+extern void
+help_cmd PARAMS ((char *, GDB_FILE *));
+
+extern void
+help_list PARAMS ((struct cmd_list_element *, char *, enum command_class,
+ GDB_FILE *));
+
+extern void
+help_cmd_list PARAMS ((struct cmd_list_element *, enum command_class, char *,
+ int, GDB_FILE *));
+
+extern struct cmd_list_element *
+add_set_cmd PARAMS ((char *, enum command_class, var_types, char *, char *,
+ struct cmd_list_element **));
+
+extern struct cmd_list_element *
+add_show_from_set PARAMS ((struct cmd_list_element *,
+ struct cmd_list_element **));
+
+/* Do a "set" or "show" command. ARG is NULL if no argument, or the text
+ of the argument, and FROM_TTY is nonzero if this command is being entered
+ directly by the user (i.e. these are just like any other
+ command). C is the command list element for the command. */
+
+extern void
+do_setshow_command PARAMS ((char *, int, struct cmd_list_element *));
+
+/* Do a "show" command for each thing on a command list. */
+
+extern void
+cmd_show_list PARAMS ((struct cmd_list_element *, int, char *));
+
+extern void
+error_no_arg PARAMS ((char *));
+
+extern void
+dont_repeat PARAMS ((void));
+
+/* Used to mark commands that don't do anything. If we just leave the
+ function field NULL, the command is interpreted as a help topic, or
+ as a class of commands. */
+
+extern void
+not_just_help_class_command PARAMS ((char *, int));
+
+#endif /* !defined (COMMAND_H) */
diff --git a/gnu/usr.bin/gdb/gdb/compat_que.c b/gnu/usr.bin/gdb/gdb/compat_que.c
new file mode 100644
index 0000000..df185a2
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/compat_que.c
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 1987, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)compat_que.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+
+/*
+ * insque/remque -- vax insque instruction
+ *
+ * NOTE: this implementation is non-atomic!!
+ */
+
+struct vaxque { /* queue format expected by VAX queue instructions */
+ struct vaxque *vq_next;
+ struct vaxque *vq_prev;
+};
+
+insque(e, prev)
+ register struct vaxque *e, *prev;
+{
+ e->vq_prev = prev;
+ e->vq_next = prev->vq_next;
+ prev->vq_next->vq_prev = e;
+ prev->vq_next = e;
+}
+
+remque(e)
+ register struct vaxque *e;
+{
+ e->vq_prev->vq_next = e->vq_next;
+ e->vq_next->vq_prev = e->vq_prev;
+}
diff --git a/gnu/usr.bin/gdb/gdb/complaints.c b/gnu/usr.bin/gdb/gdb/complaints.c
new file mode 100644
index 0000000..7ba7b18
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/complaints.c
@@ -0,0 +1,158 @@
+/* Support for complaint handling during symbol reading in GDB.
+ Copyright (C) 1990, 1991, 1992 Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "defs.h"
+#include "complaints.h"
+#include "gdbcmd.h"
+#include <varargs.h>
+
+/* Structure to manage complaints about symbol file contents. */
+
+struct complaint complaint_root[1] = {
+ {
+ (char *) NULL, /* Complaint message */
+ 0, /* Complaint counter */
+ complaint_root /* Next complaint. */
+ }
+};
+
+/* How many complaints about a particular thing should be printed before
+ we stop whining about it? Default is no whining at all, since so many
+ systems have ill-constructed symbol files. */
+
+static unsigned int stop_whining = 0;
+
+/* Should each complaint be self explanatory, or should we assume that
+ a series of complaints is being produced?
+ case 0: self explanatory message.
+ case 1: First message of a series that must start off with explanation.
+ case 2: Subsequent message, when user already knows we are reading
+ symbols and we can just state our piece. */
+
+static int complaint_series = 0;
+
+/* External variables and functions referenced. */
+
+extern int info_verbose;
+
+
+/* Functions to handle complaints during symbol reading. */
+
+/* Print a complaint about the input symbols, and link the complaint block
+ into a chain for later handling. */
+
+/* VARARGS */
+void
+complain (va_alist)
+ va_dcl
+{
+ va_list args;
+ struct complaint *complaint;
+
+ va_start (args);
+ complaint = va_arg (args, struct complaint *);
+ complaint -> counter++;
+ if (complaint -> next == NULL)
+ {
+ complaint -> next = complaint_root -> next;
+ complaint_root -> next = complaint;
+ }
+ if (complaint -> counter > stop_whining)
+ {
+ return;
+ }
+ wrap_here ("");
+
+ switch (complaint_series + (info_verbose << 1))
+ {
+
+ /* Isolated messages, must be self-explanatory. */
+ case 0:
+ begin_line ();
+ puts_filtered ("During symbol reading, ");
+ wrap_here ("");
+ vprintf_filtered (complaint -> message, args);
+ puts_filtered (".\n");
+ break;
+
+ /* First of a series, without `set verbose'. */
+ case 1:
+ begin_line ();
+ puts_filtered ("During symbol reading...");
+ vprintf_filtered (complaint -> message, args);
+ puts_filtered ("...");
+ wrap_here ("");
+ complaint_series++;
+ break;
+
+ /* Subsequent messages of a series, or messages under `set verbose'.
+ (We'll already have produced a "Reading in symbols for XXX..."
+ message and will clean up at the end with a newline.) */
+ default:
+ vprintf_filtered (complaint -> message, args);
+ puts_filtered ("...");
+ wrap_here ("");
+ }
+ /* If GDB dumps core, we'd like to see the complaints first. Presumably
+ GDB will not be sending so many complaints that this becomes a
+ performance hog. */
+ gdb_flush (gdb_stdout);
+ va_end (args);
+}
+
+/* Clear out all complaint counters that have ever been incremented.
+ If sym_reading is 1, be less verbose about successive complaints,
+ since the messages are appearing all together during a command that
+ reads symbols (rather than scattered around as psymtabs get fleshed
+ out into symtabs at random times). If noisy is 1, we are in a
+ noisy symbol reading command, and our caller will print enough
+ context for the user to figure it out. */
+
+void
+clear_complaints (sym_reading, noisy)
+ int sym_reading;
+ int noisy;
+{
+ struct complaint *p;
+
+ for (p = complaint_root -> next; p != complaint_root; p = p -> next)
+ {
+ p -> counter = 0;
+ }
+
+ if (!sym_reading && !noisy && complaint_series > 1)
+ {
+ /* Terminate previous series, since caller won't. */
+ puts_filtered ("\n");
+ }
+
+ complaint_series = sym_reading ? 1 + noisy : 0;
+}
+
+void
+_initialize_complaints ()
+{
+ add_show_from_set
+ (add_set_cmd ("complaints", class_support, var_zinteger,
+ (char *) &stop_whining,
+ "Set max number of complaints about incorrect symbols.",
+ &setlist),
+ &showlist);
+
+}
diff --git a/gnu/usr.bin/gdb/gdb/complaints.h b/gnu/usr.bin/gdb/gdb/complaints.h
new file mode 100644
index 0000000..ea10cab
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/complaints.h
@@ -0,0 +1,46 @@
+/* Definitions for complaint handling during symbol reading in GDB.
+ Copyright (C) 1990, 1991, 1992 Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+
+/* Support for complaining about things in the symbol file that aren't
+ catastrophic.
+
+ Each such thing gets a counter. The first time we have the problem,
+ during a symbol read, we report it. At the end of symbol reading,
+ if verbose, we report how many of each problem we had. */
+
+struct complaint
+{
+ char *message;
+ unsigned counter;
+ struct complaint *next;
+};
+
+/* Root of the chain of complaints that have at some point been issued.
+ This is used to reset the counters, and/or report the total counts. */
+
+extern struct complaint complaint_root[1];
+
+/* Functions that handle complaints. (in complaints.c) */
+
+extern void
+complain ();
+
+extern void
+clear_complaints PARAMS ((int, int));
diff --git a/gnu/usr.bin/gdb/gdb/copying.c b/gnu/usr.bin/gdb/gdb/copying.c
new file mode 100644
index 0000000..ffc884a
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/copying.c
@@ -0,0 +1,327 @@
+/* ==> Do not modify this file!! It is created automatically
+ by copying.awk. Modify copying.awk instead. <== */
+
+#include "defs.h"
+#include "command.h"
+#include "gdbcmd.h"
+
+static void
+show_copying_command PARAMS ((char *, int));
+
+static void
+show_warranty_command PARAMS ((char *, int));
+
+extern int immediate_quit;
+static void
+show_copying_command (ignore, from_tty)
+ char *ignore;
+ int from_tty;
+{
+ immediate_quit++;
+ printf_filtered (" GNU GENERAL PUBLIC LICENSE\n");
+ printf_filtered (" Version 2, June 1991\n");
+ printf_filtered ("\n");
+ printf_filtered (" Copyright (C) 1989, 1991 Free Software Foundation, Inc.\n");
+ printf_filtered (" 675 Mass Ave, Cambridge, MA 02139, USA\n");
+ printf_filtered (" Everyone is permitted to copy and distribute verbatim copies\n");
+ printf_filtered (" of this license document, but changing it is not allowed.\n");
+ printf_filtered ("\n");
+ printf_filtered (" Preamble\n");
+ printf_filtered ("\n");
+ printf_filtered (" The licenses for most software are designed to take away your\n");
+ printf_filtered ("freedom to share and change it. By contrast, the GNU General Public\n");
+ printf_filtered ("License is intended to guarantee your freedom to share and change free\n");
+ printf_filtered ("software--to make sure the software is free for all its users. This\n");
+ printf_filtered ("General Public License applies to most of the Free Software\n");
+ printf_filtered ("Foundation's software and to any other program whose authors commit to\n");
+ printf_filtered ("using it. (Some other Free Software Foundation software is covered by\n");
+ printf_filtered ("the GNU Library General Public License instead.) You can apply it to\n");
+ printf_filtered ("your programs, too.\n");
+ printf_filtered ("\n");
+ printf_filtered (" When we speak of free software, we are referring to freedom, not\n");
+ printf_filtered ("price. Our General Public Licenses are designed to make sure that you\n");
+ printf_filtered ("have the freedom to distribute copies of free software (and charge for\n");
+ printf_filtered ("this service if you wish), that you receive source code or can get it\n");
+ printf_filtered ("if you want it, that you can change the software or use pieces of it\n");
+ printf_filtered ("in new free programs; and that you know you can do these things.\n");
+ printf_filtered ("\n");
+ printf_filtered (" To protect your rights, we need to make restrictions that forbid\n");
+ printf_filtered ("anyone to deny you these rights or to ask you to surrender the rights.\n");
+ printf_filtered ("These restrictions translate to certain responsibilities for you if you\n");
+ printf_filtered ("distribute copies of the software, or if you modify it.\n");
+ printf_filtered ("\n");
+ printf_filtered (" For example, if you distribute copies of such a program, whether\n");
+ printf_filtered ("gratis or for a fee, you must give the recipients all the rights that\n");
+ printf_filtered ("you have. You must make sure that they, too, receive or can get the\n");
+ printf_filtered ("source code. And you must show them these terms so they know their\n");
+ printf_filtered ("rights.\n");
+ printf_filtered ("\n");
+ printf_filtered (" We protect your rights with two steps: (1) copyright the software, and\n");
+ printf_filtered ("(2) offer you this license which gives you legal permission to copy,\n");
+ printf_filtered ("distribute and/or modify the software.\n");
+ printf_filtered ("\n");
+ printf_filtered (" Also, for each author's protection and ours, we want to make certain\n");
+ printf_filtered ("that everyone understands that there is no warranty for this free\n");
+ printf_filtered ("software. If the software is modified by someone else and passed on, we\n");
+ printf_filtered ("want its recipients to know that what they have is not the original, so\n");
+ printf_filtered ("that any problems introduced by others will not reflect on the original\n");
+ printf_filtered ("authors' reputations.\n");
+ printf_filtered ("\n");
+ printf_filtered (" Finally, any free program is threatened constantly by software\n");
+ printf_filtered ("patents. We wish to avoid the danger that redistributors of a free\n");
+ printf_filtered ("program will individually obtain patent licenses, in effect making the\n");
+ printf_filtered ("program proprietary. To prevent this, we have made it clear that any\n");
+ printf_filtered ("patent must be licensed for everyone's free use or not licensed at all.\n");
+ printf_filtered ("\n");
+ printf_filtered (" The precise terms and conditions for copying, distribution and\n");
+ printf_filtered ("modification follow.\n");
+ printf_filtered ("\n");
+ printf_filtered (" GNU GENERAL PUBLIC LICENSE\n");
+ printf_filtered (" TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION\n");
+ printf_filtered ("\n");
+ printf_filtered (" 0. This License applies to any program or other work which contains\n");
+ printf_filtered ("a notice placed by the copyright holder saying it may be distributed\n");
+ printf_filtered ("under the terms of this General Public License. The \"Program\", below,\n");
+ printf_filtered ("refers to any such program or work, and a \"work based on the Program\"\n");
+ printf_filtered ("means either the Program or any derivative work under copyright law:\n");
+ printf_filtered ("that is to say, a work containing the Program or a portion of it,\n");
+ printf_filtered ("either verbatim or with modifications and/or translated into another\n");
+ printf_filtered ("language. (Hereinafter, translation is included without limitation in\n");
+ printf_filtered ("the term \"modification\".) Each licensee is addressed as \"you\".\n");
+ printf_filtered ("\n");
+ printf_filtered ("Activities other than copying, distribution and modification are not\n");
+ printf_filtered ("covered by this License; they are outside its scope. The act of\n");
+ printf_filtered ("running the Program is not restricted, and the output from the Program\n");
+ printf_filtered ("is covered only if its contents constitute a work based on the\n");
+ printf_filtered ("Program (independent of having been made by running the Program).\n");
+ printf_filtered ("Whether that is true depends on what the Program does.\n");
+ printf_filtered ("\n");
+ printf_filtered (" 1. You may copy and distribute verbatim copies of the Program's\n");
+ printf_filtered ("source code as you receive it, in any medium, provided that you\n");
+ printf_filtered ("conspicuously and appropriately publish on each copy an appropriate\n");
+ printf_filtered ("copyright notice and disclaimer of warranty; keep intact all the\n");
+ printf_filtered ("notices that refer to this License and to the absence of any warranty;\n");
+ printf_filtered ("and give any other recipients of the Program a copy of this License\n");
+ printf_filtered ("along with the Program.\n");
+ printf_filtered ("\n");
+ printf_filtered ("You may charge a fee for the physical act of transferring a copy, and\n");
+ printf_filtered ("you may at your option offer warranty protection in exchange for a fee.\n");
+ printf_filtered ("\n");
+ printf_filtered (" 2. You may modify your copy or copies of the Program or any portion\n");
+ printf_filtered ("of it, thus forming a work based on the Program, and copy and\n");
+ printf_filtered ("distribute such modifications or work under the terms of Section 1\n");
+ printf_filtered ("above, provided that you also meet all of these conditions:\n");
+ printf_filtered ("\n");
+ printf_filtered (" a) You must cause the modified files to carry prominent notices\n");
+ printf_filtered (" stating that you changed the files and the date of any change.\n");
+ printf_filtered ("\n");
+ printf_filtered (" b) You must cause any work that you distribute or publish, that in\n");
+ printf_filtered (" whole or in part contains or is derived from the Program or any\n");
+ printf_filtered (" part thereof, to be licensed as a whole at no charge to all third\n");
+ printf_filtered (" parties under the terms of this License.\n");
+ printf_filtered ("\n");
+ printf_filtered (" c) If the modified program normally reads commands interactively\n");
+ printf_filtered (" when run, you must cause it, when started running for such\n");
+ printf_filtered (" interactive use in the most ordinary way, to print or display an\n");
+ printf_filtered (" announcement including an appropriate copyright notice and a\n");
+ printf_filtered (" notice that there is no warranty (or else, saying that you provide\n");
+ printf_filtered (" a warranty) and that users may redistribute the program under\n");
+ printf_filtered (" these conditions, and telling the user how to view a copy of this\n");
+ printf_filtered (" License. (Exception: if the Program itself is interactive but\n");
+ printf_filtered (" does not normally print such an announcement, your work based on\n");
+ printf_filtered (" the Program is not required to print an announcement.)\n");
+ printf_filtered ("\n");
+ printf_filtered ("These requirements apply to the modified work as a whole. If\n");
+ printf_filtered ("identifiable sections of that work are not derived from the Program,\n");
+ printf_filtered ("and can be reasonably considered independent and separate works in\n");
+ printf_filtered ("themselves, then this License, and its terms, do not apply to those\n");
+ printf_filtered ("sections when you distribute them as separate works. But when you\n");
+ printf_filtered ("distribute the same sections as part of a whole which is a work based\n");
+ printf_filtered ("on the Program, the distribution of the whole must be on the terms of\n");
+ printf_filtered ("this License, whose permissions for other licensees extend to the\n");
+ printf_filtered ("entire whole, and thus to each and every part regardless of who wrote it.\n");
+ printf_filtered ("\n");
+ printf_filtered ("Thus, it is not the intent of this section to claim rights or contest\n");
+ printf_filtered ("your rights to work written entirely by you; rather, the intent is to\n");
+ printf_filtered ("exercise the right to control the distribution of derivative or\n");
+ printf_filtered ("collective works based on the Program.\n");
+ printf_filtered ("\n");
+ printf_filtered ("In addition, mere aggregation of another work not based on the Program\n");
+ printf_filtered ("with the Program (or with a work based on the Program) on a volume of\n");
+ printf_filtered ("a storage or distribution medium does not bring the other work under\n");
+ printf_filtered ("the scope of this License.\n");
+ printf_filtered ("\n");
+ printf_filtered (" 3. You may copy and distribute the Program (or a work based on it,\n");
+ printf_filtered ("under Section 2) in object code or executable form under the terms of\n");
+ printf_filtered ("Sections 1 and 2 above provided that you also do one of the following:\n");
+ printf_filtered ("\n");
+ printf_filtered (" a) Accompany it with the complete corresponding machine-readable\n");
+ printf_filtered (" source code, which must be distributed under the terms of Sections\n");
+ printf_filtered (" 1 and 2 above on a medium customarily used for software interchange; or,\n");
+ printf_filtered ("\n");
+ printf_filtered (" b) Accompany it with a written offer, valid for at least three\n");
+ printf_filtered (" years, to give any third party, for a charge no more than your\n");
+ printf_filtered (" cost of physically performing source distribution, a complete\n");
+ printf_filtered (" machine-readable copy of the corresponding source code, to be\n");
+ printf_filtered (" distributed under the terms of Sections 1 and 2 above on a medium\n");
+ printf_filtered (" customarily used for software interchange; or,\n");
+ printf_filtered ("\n");
+ printf_filtered (" c) Accompany it with the information you received as to the offer\n");
+ printf_filtered (" to distribute corresponding source code. (This alternative is\n");
+ printf_filtered (" allowed only for noncommercial distribution and only if you\n");
+ printf_filtered (" received the program in object code or executable form with such\n");
+ printf_filtered (" an offer, in accord with Subsection b above.)\n");
+ printf_filtered ("\n");
+ printf_filtered ("The source code for a work means the preferred form of the work for\n");
+ printf_filtered ("making modifications to it. For an executable work, complete source\n");
+ printf_filtered ("code means all the source code for all modules it contains, plus any\n");
+ printf_filtered ("associated interface definition files, plus the scripts used to\n");
+ printf_filtered ("control compilation and installation of the executable. However, as a\n");
+ printf_filtered ("special exception, the source code distributed need not include\n");
+ printf_filtered ("anything that is normally distributed (in either source or binary\n");
+ printf_filtered ("form) with the major components (compiler, kernel, and so on) of the\n");
+ printf_filtered ("operating system on which the executable runs, unless that component\n");
+ printf_filtered ("itself accompanies the executable.\n");
+ printf_filtered ("\n");
+ printf_filtered ("If distribution of executable or object code is made by offering\n");
+ printf_filtered ("access to copy from a designated place, then offering equivalent\n");
+ printf_filtered ("access to copy the source code from the same place counts as\n");
+ printf_filtered ("distribution of the source code, even though third parties are not\n");
+ printf_filtered ("compelled to copy the source along with the object code.\n");
+ printf_filtered ("\n");
+ printf_filtered (" 4. You may not copy, modify, sublicense, or distribute the Program\n");
+ printf_filtered ("except as expressly provided under this License. Any attempt\n");
+ printf_filtered ("otherwise to copy, modify, sublicense or distribute the Program is\n");
+ printf_filtered ("void, and will automatically terminate your rights under this License.\n");
+ printf_filtered ("However, parties who have received copies, or rights, from you under\n");
+ printf_filtered ("this License will not have their licenses terminated so long as such\n");
+ printf_filtered ("parties remain in full compliance.\n");
+ printf_filtered ("\n");
+ printf_filtered (" 5. You are not required to accept this License, since you have not\n");
+ printf_filtered ("signed it. However, nothing else grants you permission to modify or\n");
+ printf_filtered ("distribute the Program or its derivative works. These actions are\n");
+ printf_filtered ("prohibited by law if you do not accept this License. Therefore, by\n");
+ printf_filtered ("modifying or distributing the Program (or any work based on the\n");
+ printf_filtered ("Program), you indicate your acceptance of this License to do so, and\n");
+ printf_filtered ("all its terms and conditions for copying, distributing or modifying\n");
+ printf_filtered ("the Program or works based on it.\n");
+ printf_filtered ("\n");
+ printf_filtered (" 6. Each time you redistribute the Program (or any work based on the\n");
+ printf_filtered ("Program), the recipient automatically receives a license from the\n");
+ printf_filtered ("original licensor to copy, distribute or modify the Program subject to\n");
+ printf_filtered ("these terms and conditions. You may not impose any further\n");
+ printf_filtered ("restrictions on the recipients' exercise of the rights granted herein.\n");
+ printf_filtered ("You are not responsible for enforcing compliance by third parties to\n");
+ printf_filtered ("this License.\n");
+ printf_filtered ("\n");
+ printf_filtered (" 7. If, as a consequence of a court judgment or allegation of patent\n");
+ printf_filtered ("infringement or for any other reason (not limited to patent issues),\n");
+ printf_filtered ("conditions are imposed on you (whether by court order, agreement or\n");
+ printf_filtered ("otherwise) that contradict the conditions of this License, they do not\n");
+ printf_filtered ("excuse you from the conditions of this License. If you cannot\n");
+ printf_filtered ("distribute so as to satisfy simultaneously your obligations under this\n");
+ printf_filtered ("License and any other pertinent obligations, then as a consequence you\n");
+ printf_filtered ("may not distribute the Program at all. For example, if a patent\n");
+ printf_filtered ("license would not permit royalty-free redistribution of the Program by\n");
+ printf_filtered ("all those who receive copies directly or indirectly through you, then\n");
+ printf_filtered ("the only way you could satisfy both it and this License would be to\n");
+ printf_filtered ("refrain entirely from distribution of the Program.\n");
+ printf_filtered ("\n");
+ printf_filtered ("If any portion of this section is held invalid or unenforceable under\n");
+ printf_filtered ("any particular circumstance, the balance of the section is intended to\n");
+ printf_filtered ("apply and the section as a whole is intended to apply in other\n");
+ printf_filtered ("circumstances.\n");
+ printf_filtered ("\n");
+ printf_filtered ("It is not the purpose of this section to induce you to infringe any\n");
+ printf_filtered ("patents or other property right claims or to contest validity of any\n");
+ printf_filtered ("such claims; this section has the sole purpose of protecting the\n");
+ printf_filtered ("integrity of the free software distribution system, which is\n");
+ printf_filtered ("implemented by public license practices. Many people have made\n");
+ printf_filtered ("generous contributions to the wide range of software distributed\n");
+ printf_filtered ("through that system in reliance on consistent application of that\n");
+ printf_filtered ("system; it is up to the author/donor to decide if he or she is willing\n");
+ printf_filtered ("to distribute software through any other system and a licensee cannot\n");
+ printf_filtered ("impose that choice.\n");
+ printf_filtered ("\n");
+ printf_filtered ("This section is intended to make thoroughly clear what is believed to\n");
+ printf_filtered ("be a consequence of the rest of this License.\n");
+ printf_filtered ("\n");
+ printf_filtered (" 8. If the distribution and/or use of the Program is restricted in\n");
+ printf_filtered ("certain countries either by patents or by copyrighted interfaces, the\n");
+ printf_filtered ("original copyright holder who places the Program under this License\n");
+ printf_filtered ("may add an explicit geographical distribution limitation excluding\n");
+ printf_filtered ("those countries, so that distribution is permitted only in or among\n");
+ printf_filtered ("countries not thus excluded. In such case, this License incorporates\n");
+ printf_filtered ("the limitation as if written in the body of this License.\n");
+ printf_filtered ("\n");
+ printf_filtered (" 9. The Free Software Foundation may publish revised and/or new versions\n");
+ printf_filtered ("of the General Public License from time to time. Such new versions will\n");
+ printf_filtered ("be similar in spirit to the present version, but may differ in detail to\n");
+ printf_filtered ("address new problems or concerns.\n");
+ printf_filtered ("\n");
+ printf_filtered ("Each version is given a distinguishing version number. If the Program\n");
+ printf_filtered ("specifies a version number of this License which applies to it and \"any\n");
+ printf_filtered ("later version\", you have the option of following the terms and conditions\n");
+ printf_filtered ("either of that version or of any later version published by the Free\n");
+ printf_filtered ("Software Foundation. If the Program does not specify a version number of\n");
+ printf_filtered ("this License, you may choose any version ever published by the Free Software\n");
+ printf_filtered ("Foundation.\n");
+ printf_filtered ("\n");
+ printf_filtered (" 10. If you wish to incorporate parts of the Program into other free\n");
+ printf_filtered ("programs whose distribution conditions are different, write to the author\n");
+ printf_filtered ("to ask for permission. For software which is copyrighted by the Free\n");
+ printf_filtered ("Software Foundation, write to the Free Software Foundation; we sometimes\n");
+ printf_filtered ("make exceptions for this. Our decision will be guided by the two goals\n");
+ printf_filtered ("of preserving the free status of all derivatives of our free software and\n");
+ printf_filtered ("of promoting the sharing and reuse of software generally.\n");
+ printf_filtered ("\n");
+ immediate_quit--;
+}
+
+static void
+show_warranty_command (ignore, from_tty)
+ char *ignore;
+ int from_tty;
+{
+ immediate_quit++;
+ printf_filtered (" NO WARRANTY\n");
+ printf_filtered ("\n");
+ printf_filtered (" 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY\n");
+ printf_filtered ("FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN\n");
+ printf_filtered ("OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES\n");
+ printf_filtered ("PROVIDE THE PROGRAM \"AS IS\" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED\n");
+ printf_filtered ("OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\n");
+ printf_filtered ("MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS\n");
+ printf_filtered ("TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE\n");
+ printf_filtered ("PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,\n");
+ printf_filtered ("REPAIR OR CORRECTION.\n");
+ printf_filtered ("\n");
+ printf_filtered (" 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING\n");
+ printf_filtered ("WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR\n");
+ printf_filtered ("REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,\n");
+ printf_filtered ("INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING\n");
+ printf_filtered ("OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED\n");
+ printf_filtered ("TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY\n");
+ printf_filtered ("YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER\n");
+ printf_filtered ("PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE\n");
+ printf_filtered ("POSSIBILITY OF SUCH DAMAGES.\n");
+ printf_filtered ("\n");
+ immediate_quit--;
+}
+
+void
+_initialize_copying ()
+{
+ add_cmd ("copying", no_class, show_copying_command,
+ "Conditions for redistributing copies of GDB.",
+ &showlist);
+ add_cmd ("warranty", no_class, show_warranty_command,
+ "Various kinds of warranty you do not have.",
+ &showlist);
+
+ /* For old-timers, allow "info copying", etc. */
+ add_info ("copying", show_copying_command,
+ "Conditions for redistributing copies of GDB.");
+ add_info ("warranty", show_warranty_command,
+ "Various kinds of warranty you do not have.");
+}
diff --git a/gnu/usr.bin/gdb/gdb/core.c b/gnu/usr.bin/gdb/gdb/core.c
new file mode 100644
index 0000000..974e55c
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/core.c
@@ -0,0 +1,339 @@
+/* Core dump and executable file functions above target vector, for GDB.
+ Copyright 1986, 1987, 1989, 1991, 1992, 1993, 1994
+ Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "defs.h"
+#include <string.h>
+#include <errno.h>
+#include <signal.h>
+#include <fcntl.h>
+#include "frame.h" /* required by inferior.h */
+#include "inferior.h"
+#include "symtab.h"
+#include "command.h"
+#include "gdbcmd.h"
+#include "bfd.h"
+#include "target.h"
+#include "gdbcore.h"
+#include "dis-asm.h"
+#include "language.h"
+
+extern char registers[];
+
+/* Hook for `exec_file_command' command to call. */
+
+void (*exec_file_display_hook) PARAMS ((char *)) = NULL;
+
+/* Binary file diddling handle for the core file. */
+
+bfd *core_bfd = NULL;
+
+
+/* Backward compatability with old way of specifying core files. */
+
+void
+core_file_command (filename, from_tty)
+ char *filename;
+ int from_tty;
+{
+ struct target_ops *t;
+
+ dont_repeat (); /* Either way, seems bogus. */
+
+ t = find_core_target ();
+ if (t != NULL)
+ if (!filename)
+ (t->to_detach) (filename, from_tty);
+ else
+ (t->to_open) (filename, from_tty);
+ else
+ error ("GDB can't read core files on this machine.");
+}
+
+
+/* Call this to specify the hook for exec_file_command to call back.
+ This is called from the x-window display code. */
+
+void
+specify_exec_file_hook (hook)
+ void (*hook) PARAMS ((char *));
+{
+ exec_file_display_hook = hook;
+}
+
+/* The exec file must be closed before running an inferior.
+ If it is needed again after the inferior dies, it must
+ be reopened. */
+
+void
+close_exec_file ()
+{
+#ifdef FIXME
+ if (exec_bfd)
+ bfd_tempclose (exec_bfd);
+#endif
+}
+
+void
+reopen_exec_file ()
+{
+#ifdef FIXME
+ if (exec_bfd)
+ bfd_reopen (exec_bfd);
+#endif
+}
+
+/* If we have both a core file and an exec file,
+ print a warning if they don't go together. */
+
+void
+validate_files ()
+{
+ if (exec_bfd && core_bfd)
+ {
+ if (!core_file_matches_executable_p (core_bfd, exec_bfd))
+ warning ("core file may not match specified executable file.");
+ else if (bfd_get_mtime(exec_bfd) > bfd_get_mtime(core_bfd))
+ warning ("exec file is newer than core file.");
+ }
+}
+
+/* Return the name of the executable file as a string.
+ ERR nonzero means get error if there is none specified;
+ otherwise return 0 in that case. */
+
+char *
+get_exec_file (err)
+ int err;
+{
+ if (exec_bfd) return bfd_get_filename(exec_bfd);
+ if (!err) return NULL;
+
+ error ("No executable file specified.\n\
+Use the \"file\" or \"exec-file\" command.");
+ return NULL;
+}
+
+
+/* Report a memory error with error(). */
+
+void
+memory_error (status, memaddr)
+ int status;
+ CORE_ADDR memaddr;
+{
+ if (status == EIO)
+ {
+ /* Actually, address between memaddr and memaddr + len
+ was out of bounds. */
+ error_begin ();
+ printf_filtered ("Cannot access memory at address ");
+ print_address_numeric (memaddr, 1, gdb_stdout);
+ printf_filtered (".\n");
+ return_to_top_level (RETURN_ERROR);
+ }
+ else
+ {
+ error_begin ();
+ printf_filtered ("Error accessing memory address ");
+ print_address_numeric (memaddr, 1, gdb_stdout);
+ printf_filtered (": %s.\n",
+ safe_strerror (status));
+ return_to_top_level (RETURN_ERROR);
+ }
+}
+
+/* Same as target_read_memory, but report an error if can't read. */
+void
+read_memory (memaddr, myaddr, len)
+ CORE_ADDR memaddr;
+ char *myaddr;
+ int len;
+{
+ int status;
+ status = target_read_memory (memaddr, myaddr, len);
+ if (status != 0)
+ memory_error (status, memaddr);
+}
+
+/* Like target_read_memory, but slightly different parameters. */
+
+int
+dis_asm_read_memory (memaddr, myaddr, len, info)
+ bfd_vma memaddr;
+ bfd_byte *myaddr;
+ int len;
+ disassemble_info *info;
+{
+ return target_read_memory (memaddr, (char *) myaddr, len);
+}
+
+/* Like memory_error with slightly different parameters. */
+void
+dis_asm_memory_error (status, memaddr, info)
+ int status;
+ bfd_vma memaddr;
+ disassemble_info *info;
+{
+ memory_error (status, memaddr);
+}
+
+/* Like print_address with slightly different parameters. */
+void
+dis_asm_print_address (addr, info)
+ bfd_vma addr;
+ struct disassemble_info *info;
+{
+ print_address (addr, info->stream);
+}
+
+/* Same as target_write_memory, but report an error if can't write. */
+void
+write_memory (memaddr, myaddr, len)
+ CORE_ADDR memaddr;
+ char *myaddr;
+ int len;
+{
+ int status;
+
+ status = target_write_memory (memaddr, myaddr, len);
+ if (status != 0)
+ memory_error (status, memaddr);
+}
+
+/* Read an integer from debugged memory, given address and number of bytes. */
+
+LONGEST
+read_memory_integer (memaddr, len)
+ CORE_ADDR memaddr;
+ int len;
+{
+ char buf[sizeof (LONGEST)];
+
+ read_memory (memaddr, buf, len);
+ return extract_signed_integer (buf, len);
+}
+
+unsigned LONGEST
+read_memory_unsigned_integer (memaddr, len)
+ CORE_ADDR memaddr;
+ int len;
+{
+ char buf[sizeof (unsigned LONGEST)];
+
+ read_memory (memaddr, buf, len);
+ return extract_unsigned_integer (buf, len);
+}
+
+#if 0
+/* Enable after 4.12. It is not tested. */
+
+/* Search code. Targets can just make this their search function, or
+ if the protocol has a less general search function, they can call this
+ in the cases it can't handle. */
+void
+generic_search (len, data, mask, startaddr, increment, lorange, hirange
+ addr_found, data_found)
+ int len;
+ char *data;
+ char *mask;
+ CORE_ADDR startaddr;
+ int increment;
+ CORE_ADDR lorange;
+ CORE_ADDR hirange;
+ CORE_ADDR *addr_found;
+ char *data_found;
+{
+ int i;
+ CORE_ADDR curaddr = startaddr;
+
+ while (curaddr >= lorange && curaddr < hirange)
+ {
+ read_memory (curaddr, data_found, len);
+ for (i = 0; i < len; ++i)
+ if ((data_found[i] & mask[i]) != data[i])
+ goto try_again;
+ /* It matches. */
+ *addr_found = curaddr;
+ return;
+
+ try_again:
+ curaddr += increment;
+ }
+ *addr_found = (CORE_ADDR)0;
+ return;
+}
+#endif /* 0 */
+
+/* The current default bfd target. Points to storage allocated for
+ gnutarget_string. */
+char *gnutarget;
+
+/* Same thing, except it is "auto" not NULL for the default case. */
+static char *gnutarget_string;
+
+static void set_gnutarget_command
+ PARAMS ((char *, int, struct cmd_list_element *));
+
+static void
+set_gnutarget_command (ignore, from_tty, c)
+ char *ignore;
+ int from_tty;
+ struct cmd_list_element *c;
+{
+ if (STREQ (gnutarget_string, "auto"))
+ gnutarget = NULL;
+ else
+ gnutarget = gnutarget_string;
+}
+
+/* Set the gnutarget. */
+void
+set_gnutarget (newtarget)
+ char *newtarget;
+{
+ if (gnutarget_string != NULL)
+ free (gnutarget_string);
+ gnutarget_string = savestring (newtarget, strlen (newtarget));
+ set_gnutarget_command (NULL, 0, NULL);
+}
+
+void
+_initialize_core()
+{
+ struct cmd_list_element *c;
+ c = add_cmd ("core-file", class_files, core_file_command,
+ "Use FILE as core dump for examining memory and registers.\n\
+No arg means have no core file. This command has been superseded by the\n\
+`target core' and `detach' commands.", &cmdlist);
+ c->completer = filename_completer;
+
+ c = add_set_cmd ("gnutarget", class_files, var_string_noescape,
+ (char *) &gnutarget_string,
+ "Set the current BFD target.\n\
+Use `set gnutarget auto' to specify automatic detection.",
+ &setlist);
+ c->function.sfunc = set_gnutarget_command;
+ add_show_from_set (c, &showlist);
+
+ if (getenv ("GNUTARGET"))
+ set_gnutarget (getenv ("GNUTARGET"));
+ else
+ set_gnutarget ("auto");
+}
diff --git a/gnu/usr.bin/gdb/gdb/coredep.c b/gnu/usr.bin/gdb/gdb/coredep.c
new file mode 100644
index 0000000..e27d2e4
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/coredep.c
@@ -0,0 +1,125 @@
+/* Extract registers from a "standard" core file, for GDB.
+ Copyright (C) 1988-1991 Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* core.c is supposed to be the more machine-independent aspects of this;
+ this file is more machine-specific. */
+
+#include "defs.h"
+#include <sys/types.h>
+#include <sys/param.h>
+#include "gdbcore.h"
+#include "value.h" /* For supply_register. */
+#include "inferior.h"
+
+/* These are needed on various systems to expand REGISTER_U_ADDR. */
+#ifndef USG
+#include <sys/dir.h>
+#include <sys/file.h>
+#include <sys/stat.h>
+#include <sys/user.h>
+#ifndef NO_PTRACE_H
+# ifdef PTRACE_IN_WRONG_PLACE
+# include <ptrace.h>
+# else /* !PTRACE_IN_WRONG_PLACE */
+# include <sys/ptrace.h>
+# endif /* !PTRACE_IN_WRONG_PLACE */
+#endif /* NO_PTRACE_H */
+#endif
+
+#ifndef CORE_REGISTER_ADDR
+#define CORE_REGISTER_ADDR(regno, regptr) register_addr(regno, regptr)
+#endif /* CORE_REGISTER_ADDR */
+
+#ifdef NEED_SYS_CORE_H
+#include <sys/core.h>
+#endif
+
+/* Extract the register values out of the core file and store
+ them where `read_register' will find them.
+
+ CORE_REG_SECT points to the register values themselves, read into memory.
+ CORE_REG_SIZE is the size of that area.
+ WHICH says which set of registers we are handling (0 = int, 2 = float
+ on machines where they are discontiguous).
+ REG_ADDR is the offset from u.u_ar0 to the register values relative to
+ core_reg_sect. This is used with old-fashioned core files to
+ locate the registers in a large upage-plus-stack ".reg" section.
+ Original upage address X is at location core_reg_sect+x+reg_addr.
+ */
+
+void
+fetch_core_registers (core_reg_sect, core_reg_size, which, reg_addr)
+ char *core_reg_sect;
+ unsigned core_reg_size;
+ int which;
+ unsigned reg_addr;
+{
+ register int regno;
+ register unsigned int addr;
+ int bad_reg = -1;
+ register reg_ptr = -reg_addr; /* Original u.u_ar0 is -reg_addr. */
+ int numregs = ARCH_NUM_REGS;
+
+ /* If u.u_ar0 was an absolute address in the core file, relativize it now,
+ so we can use it as an offset into core_reg_sect. When we're done,
+ "register 0" will be at core_reg_sect+reg_ptr, and we can use
+ CORE_REGISTER_ADDR to offset to the other registers. If this is a modern
+ core file without a upage, reg_ptr will be zero and this is all a big
+ NOP. */
+ if (reg_ptr > core_reg_size)
+ reg_ptr -= KERNEL_U_ADDR;
+
+ for (regno = 0; regno < numregs; regno++)
+ {
+ addr = CORE_REGISTER_ADDR (regno, reg_ptr);
+ if (addr >= core_reg_size) {
+ if (bad_reg < 0)
+ bad_reg = regno;
+ } else {
+ supply_register (regno, core_reg_sect + addr);
+ }
+ }
+ if (bad_reg >= 0)
+ {
+ error ("Register %s not found in core file.", reg_names[bad_reg]);
+ }
+}
+
+
+#ifdef REGISTER_U_ADDR
+
+/* Return the address in the core dump or inferior of register REGNO.
+ BLOCKEND is the address of the end of the user structure. */
+
+unsigned int
+register_addr (regno, blockend)
+ int regno;
+ int blockend;
+{
+ int addr;
+
+ if (regno < 0 || regno >= ARCH_NUM_REGS)
+ error ("Invalid register number %d.", regno);
+
+ REGISTER_U_ADDR (addr, blockend, regno);
+
+ return addr;
+}
+
+#endif /* REGISTER_U_ADDR */
diff --git a/gnu/usr.bin/gdb/gdb/corelow.c b/gnu/usr.bin/gdb/gdb/corelow.c
new file mode 100644
index 0000000..2729742
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/corelow.c
@@ -0,0 +1,333 @@
+/* Core dump and executable file functions below target vector, for GDB.
+ Copyright 1986, 1987, 1989, 1991, 1992, 1993, 1994
+ Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "defs.h"
+#include <string.h>
+#include <errno.h>
+#include <signal.h>
+#include <fcntl.h>
+#include "frame.h" /* required by inferior.h */
+#include "inferior.h"
+#include "symtab.h"
+#include "command.h"
+#include "bfd.h"
+#include "target.h"
+#include "gdbcore.h"
+#include "thread.h"
+
+static void
+core_files_info PARAMS ((struct target_ops *));
+
+#ifdef SOLIB_ADD
+static int
+solib_add_stub PARAMS ((char *));
+#endif
+
+static void
+core_close PARAMS ((int));
+
+static void
+get_core_registers PARAMS ((int));
+
+/* Discard all vestiges of any previous core file
+ and mark data and stack spaces as empty. */
+
+/* ARGSUSED */
+static void
+core_close (quitting)
+ int quitting;
+{
+ inferior_pid = 0; /* Avoid confusion from thread stuff */
+
+ if (core_bfd) {
+ free (bfd_get_filename (core_bfd));
+ bfd_close (core_bfd);
+ core_bfd = NULL;
+#ifdef CLEAR_SOLIB
+ CLEAR_SOLIB ();
+#endif
+ if (core_ops.to_sections) {
+ free ((PTR)core_ops.to_sections);
+ core_ops.to_sections = NULL;
+ core_ops.to_sections_end = NULL;
+ }
+ }
+}
+
+#ifdef SOLIB_ADD
+/* Stub function for catch_errors around shared library hacking. FROM_TTYP
+ is really an int * which points to from_tty. */
+
+static int
+solib_add_stub (from_ttyp)
+ char *from_ttyp;
+{
+ SOLIB_ADD (NULL, *(int *)from_ttyp, &core_ops);
+ return 0;
+}
+#endif /* SOLIB_ADD */
+
+/* Look for sections whose names start with `.reg/' so that we can extract the
+ list of threads in a core file. */
+
+static void
+add_to_thread_list (abfd, asect, reg_sect_arg)
+ bfd *abfd;
+ asection *asect;
+ PTR reg_sect_arg;
+{
+ int thread_id;
+ asection *reg_sect = (asection *) reg_sect_arg;
+
+ if (strncmp (bfd_section_name (abfd, asect), ".reg/", 5) != 0)
+ return;
+
+ thread_id = atoi (bfd_section_name (abfd, asect) + 5);
+
+ add_thread (thread_id);
+
+/* Warning, Will Robinson, looking at BFD private data! */
+
+ if (asect->filepos == reg_sect->filepos) /* Did we find .reg? */
+ inferior_pid = thread_id; /* Yes, make it current */
+}
+
+/* This routine opens and sets up the core file bfd */
+
+void
+core_open (filename, from_tty)
+ char *filename;
+ int from_tty;
+{
+ const char *p;
+ int siggy;
+ struct cleanup *old_chain;
+ char *temp;
+ bfd *temp_bfd;
+ int ontop;
+ int scratch_chan;
+
+ target_preopen (from_tty);
+ if (!filename)
+ {
+ error (core_bfd?
+ "No core file specified. (Use `detach' to stop debugging a core file.)"
+ : "No core file specified.");
+ }
+
+ filename = tilde_expand (filename);
+ if (filename[0] != '/') {
+ temp = concat (current_directory, "/", filename, NULL);
+ free (filename);
+ filename = temp;
+ }
+
+ old_chain = make_cleanup (free, filename);
+
+ scratch_chan = open (filename, write_files? O_RDWR: O_RDONLY, 0);
+ if (scratch_chan < 0)
+ perror_with_name (filename);
+
+ temp_bfd = bfd_fdopenr (filename, gnutarget, scratch_chan);
+ if (temp_bfd == NULL)
+ {
+ perror_with_name (filename);
+ }
+
+ if (!bfd_check_format (temp_bfd, bfd_core))
+ {
+ /* Do it after the err msg */
+ make_cleanup (bfd_close, temp_bfd);
+ error ("\"%s\" is not a core dump: %s", filename, bfd_errmsg(bfd_get_error ()));
+ }
+
+ /* Looks semi-reasonable. Toss the old core file and work on the new. */
+
+ discard_cleanups (old_chain); /* Don't free filename any more */
+ unpush_target (&core_ops);
+ core_bfd = temp_bfd;
+ old_chain = make_cleanup (core_close, core_bfd);
+
+ validate_files ();
+
+ /* Find the data section */
+ if (build_section_table (core_bfd, &core_ops.to_sections,
+ &core_ops.to_sections_end))
+ error ("Can't find sections in `%s': %s", bfd_get_filename(core_bfd),
+ bfd_errmsg (bfd_get_error ()));
+
+ ontop = !push_target (&core_ops);
+ discard_cleanups (old_chain);
+
+ p = bfd_core_file_failing_command (core_bfd);
+ if (p)
+ printf_filtered ("Core was generated by `%s'.\n", p);
+
+ siggy = bfd_core_file_failing_signal (core_bfd);
+ if (siggy > 0)
+ printf_filtered ("Program terminated with signal %d, %s.\n", siggy,
+ safe_strsignal (siggy));
+
+ /* Build up thread list from BFD sections. */
+
+ init_thread_list ();
+ bfd_map_over_sections (core_bfd, add_to_thread_list,
+ bfd_get_section_by_name (core_bfd, ".reg"));
+
+ if (ontop) {
+ /* Fetch all registers from core file */
+ target_fetch_registers (-1);
+
+ /* Add symbols and section mappings for any shared libraries */
+#ifdef SOLIB_ADD
+ catch_errors (solib_add_stub, &from_tty, (char *)0,
+ RETURN_MASK_ALL);
+#endif
+
+ /* Now, set up the frame cache, and print the top of stack */
+ set_current_frame (create_new_frame (read_fp (),
+ read_pc ()));
+ select_frame (get_current_frame (), 0);
+ print_stack_frame (selected_frame, selected_frame_level, 1);
+ } else {
+ warning (
+"you won't be able to access this core file until you terminate\n\
+your %s; do ``info files''", current_target->to_longname);
+ }
+}
+
+void
+core_detach (args, from_tty)
+ char *args;
+ int from_tty;
+{
+ if (args)
+ error ("Too many arguments");
+ unpush_target (&core_ops);
+ reinit_frame_cache ();
+ if (from_tty)
+ printf_filtered ("No core file now.\n");
+}
+
+/* Get the registers out of a core file. This is the machine-
+ independent part. Fetch_core_registers is the machine-dependent
+ part, typically implemented in the xm-file for each architecture. */
+
+/* We just get all the registers, so we don't use regno. */
+/* ARGSUSED */
+static void
+get_core_registers (regno)
+ int regno;
+{
+ sec_ptr reg_sec;
+ unsigned size;
+ char *the_regs;
+ char secname[10];
+
+ /* Thread support. If inferior_pid is non-zero, then we have found a core
+ file with threads (or multiple processes). In that case, we need to
+ use the appropriate register section, else we just use `.reg'. */
+
+ /* XXX - same thing needs to be done for floating-point (.reg2) sections. */
+
+ if (inferior_pid)
+ sprintf (secname, ".reg/%d", inferior_pid);
+ else
+ strcpy (secname, ".reg");
+
+ reg_sec = bfd_get_section_by_name (core_bfd, secname);
+ if (!reg_sec) goto cant;
+ size = bfd_section_size (core_bfd, reg_sec);
+ the_regs = alloca (size);
+ if (bfd_get_section_contents (core_bfd, reg_sec, the_regs, (file_ptr)0, size))
+ {
+ fetch_core_registers (the_regs, size, 0,
+ (unsigned) bfd_section_vma (abfd,reg_sec));
+ }
+ else
+ {
+cant:
+ fprintf_filtered (gdb_stderr, "Couldn't fetch registers from core file: %s\n",
+ bfd_errmsg (bfd_get_error ()));
+ }
+
+ /* Now do it again for the float registers, if they exist. */
+ reg_sec = bfd_get_section_by_name (core_bfd, ".reg2");
+ if (reg_sec) {
+ size = bfd_section_size (core_bfd, reg_sec);
+ the_regs = alloca (size);
+ if (bfd_get_section_contents (core_bfd, reg_sec, the_regs, (file_ptr)0,
+ size))
+ {
+ fetch_core_registers (the_regs, size, 2,
+ (unsigned) bfd_section_vma (abfd,reg_sec));
+ }
+ else
+ {
+ fprintf_filtered (gdb_stderr, "Couldn't fetch register set 2 from core file: %s\n",
+ bfd_errmsg (bfd_get_error ()));
+ }
+ }
+ registers_fetched();
+}
+
+static void
+core_files_info (t)
+ struct target_ops *t;
+{
+ print_section_info (t, core_bfd);
+}
+
+/* If mourn is being called in all the right places, this could be say
+ `gdb internal error' (since generic_mourn calls breakpoint_init_inferior). */
+
+static int
+ignore (addr, contents)
+ CORE_ADDR addr;
+ char *contents;
+{
+ return 0;
+}
+
+struct target_ops core_ops = {
+ "core", "Local core dump file",
+ "Use a core file as a target. Specify the filename of the core file.",
+ core_open, core_close,
+ find_default_attach, core_detach, 0, 0, /* resume, wait */
+ get_core_registers,
+ 0, 0, /* store_regs, prepare_to_store */
+ xfer_memory, core_files_info,
+ ignore, ignore, /* core_insert_breakpoint, core_remove_breakpoint, */
+ 0, 0, 0, 0, 0, /* terminal stuff */
+ 0, 0, 0, /* kill, load, lookup sym */
+ find_default_create_inferior, 0, /* mourn_inferior */
+ 0, /* can_run */
+ 0, /* notice_signals */
+ core_stratum, 0, /* next */
+ 0, 1, 1, 1, 0, /* all mem, mem, stack, regs, exec */
+ 0, 0, /* section pointers */
+ OPS_MAGIC, /* Always the last thing */
+};
+
+void
+_initialize_corelow()
+{
+ add_target (&core_ops);
+}
diff --git a/gnu/usr.bin/gdb/gdb/cp-valprint.c b/gnu/usr.bin/gdb/gdb/cp-valprint.c
new file mode 100644
index 0000000..de60814
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/cp-valprint.c
@@ -0,0 +1,512 @@
+/* Support for printing C++ values for GDB, the GNU debugger.
+ Copyright 1986, 1988, 1989, 1991 Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "defs.h"
+#include "obstack.h"
+#include "symtab.h"
+#include "gdbtypes.h"
+#include "expression.h"
+#include "value.h"
+#include "command.h"
+#include "gdbcmd.h"
+#include "demangle.h"
+#include "annotate.h"
+
+int vtblprint; /* Controls printing of vtbl's */
+int objectprint; /* Controls looking up an object's derived type
+ using what we find in its vtables. */
+struct obstack dont_print_obstack;
+
+static void
+cplus_print_value PARAMS ((struct type *, char *, GDB_FILE *, int, int,
+ enum val_prettyprint, struct type **));
+
+/* BEGIN-FIXME: Hooks into typeprint.c, find a better home for prototypes. */
+
+extern void
+c_type_print_base PARAMS ((struct type *, GDB_FILE *, int, int));
+
+extern void
+c_type_print_varspec_prefix PARAMS ((struct type *, GDB_FILE *, int, int));
+
+extern void
+cp_type_print_method_args PARAMS ((struct type **, char *, char *, int,
+ GDB_FILE *));
+
+extern struct obstack dont_print_obstack;
+
+/* END-FIXME */
+
+void
+cp_print_class_method (valaddr, type, stream)
+ char *valaddr;
+ struct type *type;
+ GDB_FILE *stream;
+{
+ struct type *domain;
+ struct fn_field *f = NULL;
+ int j = 0;
+ int len2;
+ int offset;
+ char *kind = "";
+ CORE_ADDR addr;
+ struct symbol *sym;
+ unsigned len;
+ unsigned int i;
+
+ check_stub_type (TYPE_TARGET_TYPE (type));
+ domain = TYPE_DOMAIN_TYPE (TYPE_TARGET_TYPE (type));
+ if (domain == (struct type *)NULL)
+ {
+ fprintf_filtered (stream, "<unknown>");
+ return;
+ }
+ addr = unpack_pointer (lookup_pointer_type (builtin_type_void), valaddr);
+ if (METHOD_PTR_IS_VIRTUAL (addr))
+ {
+ offset = METHOD_PTR_TO_VOFFSET (addr);
+ len = TYPE_NFN_FIELDS (domain);
+ for (i = 0; i < len; i++)
+ {
+ f = TYPE_FN_FIELDLIST1 (domain, i);
+ len2 = TYPE_FN_FIELDLIST_LENGTH (domain, i);
+
+ for (j = 0; j < len2; j++)
+ {
+ QUIT;
+ if (TYPE_FN_FIELD_VOFFSET (f, j) == offset)
+ {
+ kind = "virtual ";
+ goto common;
+ }
+ }
+ }
+ }
+ else
+ {
+ sym = find_pc_function (addr);
+ if (sym == 0)
+ {
+ error ("invalid pointer to member function");
+ }
+ len = TYPE_NFN_FIELDS (domain);
+ for (i = 0; i < len; i++)
+ {
+ f = TYPE_FN_FIELDLIST1 (domain, i);
+ len2 = TYPE_FN_FIELDLIST_LENGTH (domain, i);
+
+ for (j = 0; j < len2; j++)
+ {
+ QUIT;
+ if (TYPE_FN_FIELD_STUB (f, j))
+ check_stub_method (domain, i, j);
+ if (STREQ (SYMBOL_NAME (sym), TYPE_FN_FIELD_PHYSNAME (f, j)))
+ {
+ goto common;
+ }
+ }
+ }
+ }
+ common:
+ if (i < len)
+ {
+ fprintf_filtered (stream, "&");
+ c_type_print_varspec_prefix (TYPE_FN_FIELD_TYPE (f, j), stream, 0, 0);
+ fprintf_unfiltered (stream, kind);
+ if (TYPE_FN_FIELD_PHYSNAME (f, j)[0] == '_'
+ && TYPE_FN_FIELD_PHYSNAME (f, j)[1] == CPLUS_MARKER)
+ {
+ cp_type_print_method_args (TYPE_FN_FIELD_ARGS (f, j) + 1, "~",
+ TYPE_FN_FIELDLIST_NAME (domain, i),
+ 0, stream);
+ }
+ else
+ {
+ cp_type_print_method_args (TYPE_FN_FIELD_ARGS (f, j), "",
+ TYPE_FN_FIELDLIST_NAME (domain, i),
+ 0, stream);
+ }
+ }
+ else
+ {
+ fprintf_filtered (stream, "(");
+ type_print (type, "", stream, -1);
+ fprintf_filtered (stream, ") %d", (int) addr >> 3);
+ }
+}
+
+/* This was what it was for gcc 2.4.5 and earlier. */
+static const char vtbl_ptr_name_old[] =
+ { CPLUS_MARKER,'v','t','b','l','_','p','t','r','_','t','y','p','e', 0 };
+/* It was changed to this after 2.4.5. */
+const char vtbl_ptr_name[] =
+ { '_','_','v','t','b','l','_','p','t','r','_','t','y','p','e', 0 };
+
+/* Return truth value for assertion that TYPE is of the type
+ "pointer to virtual function". */
+
+int
+cp_is_vtbl_ptr_type(type)
+ struct type *type;
+{
+ char *typename = type_name_no_tag (type);
+
+ return (typename != NULL
+ && (STREQ (typename, vtbl_ptr_name)
+ || STREQ (typename, vtbl_ptr_name_old)));
+}
+
+/* Return truth value for the assertion that TYPE is of the type
+ "pointer to virtual function table". */
+
+int
+cp_is_vtbl_member(type)
+ struct type *type;
+{
+ if (TYPE_CODE (type) == TYPE_CODE_PTR)
+ {
+ type = TYPE_TARGET_TYPE (type);
+ if (TYPE_CODE (type) == TYPE_CODE_ARRAY)
+ {
+ type = TYPE_TARGET_TYPE (type);
+ if (TYPE_CODE (type) == TYPE_CODE_STRUCT /* if not using thunks */
+ || TYPE_CODE (type) == TYPE_CODE_PTR) /* if using thunks */
+ {
+ /* Virtual functions tables are full of pointers
+ to virtual functions. */
+ return cp_is_vtbl_ptr_type (type);
+ }
+ }
+ }
+ return 0;
+}
+
+/* Mutually recursive subroutines of cplus_print_value and c_val_print to
+ print out a structure's fields: cp_print_value_fields and cplus_print_value.
+
+ TYPE, VALADDR, STREAM, RECURSE, and PRETTY have the
+ same meanings as in cplus_print_value and c_val_print.
+
+ DONT_PRINT is an array of baseclass types that we
+ should not print, or zero if called from top level. */
+
+void
+cp_print_value_fields (type, valaddr, stream, format, recurse, pretty,
+ dont_print)
+ struct type *type;
+ char *valaddr;
+ GDB_FILE *stream;
+ int format;
+ int recurse;
+ enum val_prettyprint pretty;
+ struct type **dont_print;
+{
+ int i, len, n_baseclasses;
+
+ check_stub_type (type);
+
+ fprintf_filtered (stream, "{");
+ len = TYPE_NFIELDS (type);
+ n_baseclasses = TYPE_N_BASECLASSES (type);
+
+ /* Print out baseclasses such that we don't print
+ duplicates of virtual baseclasses. */
+ if (n_baseclasses > 0)
+ cplus_print_value (type, valaddr, stream, format, recurse+1, pretty,
+ dont_print);
+
+ if (!len && n_baseclasses == 1)
+ fprintf_filtered (stream, "<No data fields>");
+ else
+ {
+ extern int inspect_it;
+ int fields_seen = 0;
+
+ for (i = n_baseclasses; i < len; i++)
+ {
+ /* Check if static field */
+ if (TYPE_FIELD_STATIC (type, i))
+ continue;
+ if (fields_seen)
+ fprintf_filtered (stream, ", ");
+ else if (n_baseclasses > 0)
+ {
+ if (pretty)
+ {
+ fprintf_filtered (stream, "\n");
+ print_spaces_filtered (2 + 2 * recurse, stream);
+ fputs_filtered ("members of ", stream);
+ fputs_filtered (type_name_no_tag (type), stream);
+ fputs_filtered (": ", stream);
+ }
+ }
+ fields_seen = 1;
+
+ if (pretty)
+ {
+ fprintf_filtered (stream, "\n");
+ print_spaces_filtered (2 + 2 * recurse, stream);
+ }
+ else
+ {
+ wrap_here (n_spaces (2 + 2 * recurse));
+ }
+ if (inspect_it)
+ {
+ if (TYPE_CODE (TYPE_FIELD_TYPE (type, i)) == TYPE_CODE_PTR)
+ fputs_filtered ("\"( ptr \"", stream);
+ else
+ fputs_filtered ("\"( nodef \"", stream);
+ fprintf_symbol_filtered (stream, TYPE_FIELD_NAME (type, i),
+ language_cplus,
+ DMGL_PARAMS | DMGL_ANSI);
+ fputs_filtered ("\" \"", stream);
+ fprintf_symbol_filtered (stream, TYPE_FIELD_NAME (type, i),
+ language_cplus,
+ DMGL_PARAMS | DMGL_ANSI);
+ fputs_filtered ("\") \"", stream);
+ }
+ else
+ {
+ annotate_field_begin (TYPE_FIELD_TYPE (type, i));
+
+ fprintf_symbol_filtered (stream, TYPE_FIELD_NAME (type, i),
+ language_cplus,
+ DMGL_PARAMS | DMGL_ANSI);
+ annotate_field_name_end ();
+ fputs_filtered (" = ", stream);
+ annotate_field_value ();
+ }
+
+ if (TYPE_FIELD_PACKED (type, i))
+ {
+ value_ptr v;
+
+ /* Bitfields require special handling, especially due to byte
+ order problems. */
+ if (TYPE_FIELD_IGNORE (type, i))
+ {
+ fputs_filtered ("<optimized out or zero length>", stream);
+ }
+ else
+ {
+ v = value_from_longest (TYPE_FIELD_TYPE (type, i),
+ unpack_field_as_long (type, valaddr, i));
+
+ val_print (TYPE_FIELD_TYPE(type, i), VALUE_CONTENTS (v), 0,
+ stream, format, 0, recurse + 1, pretty);
+ }
+ }
+ else
+ {
+ if (TYPE_FIELD_IGNORE (type, i))
+ {
+ fputs_filtered ("<optimized out or zero length>", stream);
+ }
+ else
+ {
+ val_print (TYPE_FIELD_TYPE (type, i),
+ valaddr + TYPE_FIELD_BITPOS (type, i) / 8,
+ 0, stream, format, 0, recurse + 1, pretty);
+ }
+ }
+ annotate_field_end ();
+ }
+
+ if (pretty)
+ {
+ fprintf_filtered (stream, "\n");
+ print_spaces_filtered (2 * recurse, stream);
+ }
+ }
+ fprintf_filtered (stream, "}");
+}
+
+/* Special val_print routine to avoid printing multiple copies of virtual
+ baseclasses. */
+
+static void
+cplus_print_value (type, valaddr, stream, format, recurse, pretty, dont_print)
+ struct type *type;
+ char *valaddr;
+ GDB_FILE *stream;
+ int format;
+ int recurse;
+ enum val_prettyprint pretty;
+ struct type **dont_print;
+{
+ struct obstack tmp_obstack;
+ struct type **last_dont_print
+ = (struct type **)obstack_next_free (&dont_print_obstack);
+ int i, n_baseclasses = TYPE_N_BASECLASSES (type);
+
+ if (dont_print == 0)
+ {
+ /* If we're at top level, carve out a completely fresh
+ chunk of the obstack and use that until this particular
+ invocation returns. */
+ tmp_obstack = dont_print_obstack;
+ /* Bump up the high-water mark. Now alpha is omega. */
+ obstack_finish (&dont_print_obstack);
+ }
+
+ for (i = 0; i < n_baseclasses; i++)
+ {
+ /* FIXME-32x64--assumes that a target pointer can fit in a char *.
+ Fix it by nuking baseclass_addr. */
+ char *baddr;
+ int err;
+ char *basename;
+
+ check_stub_type (TYPE_BASECLASS (type, i));
+ basename = TYPE_NAME (TYPE_BASECLASS (type, i));
+
+ if (BASETYPE_VIA_VIRTUAL (type, i))
+ {
+ struct type **first_dont_print
+ = (struct type **)obstack_base (&dont_print_obstack);
+
+ int j = (struct type **)obstack_next_free (&dont_print_obstack)
+ - first_dont_print;
+
+ while (--j >= 0)
+ if (TYPE_BASECLASS (type, i) == first_dont_print[j])
+ goto flush_it;
+
+ obstack_ptr_grow (&dont_print_obstack, TYPE_BASECLASS (type, i));
+ }
+
+ /* Fix to use baseclass_offset instead. FIXME */
+ baddr = baseclass_addr (type, i, valaddr, 0, &err);
+ if (err == 0 && baddr == 0)
+ error ("could not find virtual baseclass %s\n",
+ basename ? basename : "");
+
+ if (pretty)
+ {
+ fprintf_filtered (stream, "\n");
+ print_spaces_filtered (2 * recurse, stream);
+ }
+ fputs_filtered ("<", stream);
+ /* Not sure what the best notation is in the case where there is no
+ baseclass name. */
+ fputs_filtered (basename ? basename : "", stream);
+ fputs_filtered ("> = ", stream);
+ if (err != 0)
+ {
+ fprintf_filtered (stream, "<invalid address ");
+ print_address_numeric ((CORE_ADDR) baddr, 1, stream);
+ fprintf_filtered (stream, ">");
+ }
+ else
+ cp_print_value_fields (TYPE_BASECLASS (type, i), baddr, stream, format,
+ recurse, pretty,
+ (struct type **) obstack_base (&dont_print_obstack));
+ fputs_filtered (", ", stream);
+
+ flush_it:
+ ;
+ }
+
+ if (dont_print == 0)
+ {
+ /* Free the space used to deal with the printing
+ of this type from top level. */
+ obstack_free (&dont_print_obstack, last_dont_print);
+ /* Reset watermark so that we can continue protecting
+ ourselves from whatever we were protecting ourselves. */
+ dont_print_obstack = tmp_obstack;
+ }
+}
+
+void
+cp_print_class_member (valaddr, domain, stream, prefix)
+ char *valaddr;
+ struct type *domain;
+ GDB_FILE *stream;
+ char *prefix;
+{
+
+ /* VAL is a byte offset into the structure type DOMAIN.
+ Find the name of the field for that offset and
+ print it. */
+ int extra = 0;
+ int bits = 0;
+ register unsigned int i;
+ unsigned len = TYPE_NFIELDS (domain);
+ /* @@ Make VAL into bit offset */
+ LONGEST val = unpack_long (builtin_type_int, valaddr) << 3;
+ for (i = TYPE_N_BASECLASSES (domain); i < len; i++)
+ {
+ int bitpos = TYPE_FIELD_BITPOS (domain, i);
+ QUIT;
+ if (val == bitpos)
+ break;
+ if (val < bitpos && i != 0)
+ {
+ /* Somehow pointing into a field. */
+ i -= 1;
+ extra = (val - TYPE_FIELD_BITPOS (domain, i));
+ if (extra & 0x7)
+ bits = 1;
+ else
+ extra >>= 3;
+ break;
+ }
+ }
+ if (i < len)
+ {
+ char *name;
+ fprintf_filtered (stream, prefix);
+ name = type_name_no_tag (domain);
+ if (name)
+ fputs_filtered (name, stream);
+ else
+ c_type_print_base (domain, stream, 0, 0);
+ fprintf_filtered (stream, "::");
+ fputs_filtered (TYPE_FIELD_NAME (domain, i), stream);
+ if (extra)
+ fprintf_filtered (stream, " + %d bytes", extra);
+ if (bits)
+ fprintf_filtered (stream, " (offset in bits)");
+ }
+ else
+ fprintf_filtered (stream, "%d", val >> 3);
+}
+
+void
+_initialize_cp_valprint ()
+{
+ add_show_from_set
+ (add_set_cmd ("vtbl", class_support, var_boolean, (char *)&vtblprint,
+ "Set printing of C++ virtual function tables.",
+ &setprintlist),
+ &showprintlist);
+
+ add_show_from_set
+ (add_set_cmd ("object", class_support, var_boolean, (char *)&objectprint,
+ "Set printing of object's derived type based on vtable info.",
+ &setprintlist),
+ &showprintlist);
+
+ /* Give people the defaults which they are used to. */
+ objectprint = 0;
+ vtblprint = 0;
+ obstack_begin (&dont_print_obstack, 32 * sizeof (struct type *));
+}
diff --git a/gnu/usr.bin/gdb/gdb/dbxread.c b/gnu/usr.bin/gdb/gdb/dbxread.c
new file mode 100644
index 0000000..f6f4cc3
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/dbxread.c
@@ -0,0 +1,2462 @@
+/* Read dbx symbol tables and convert to internal format, for GDB.
+ Copyright 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994
+ Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* This module provides three functions: dbx_symfile_init,
+ which initializes to read a symbol file; dbx_new_init, which
+ discards existing cached information when all symbols are being
+ discarded; and dbx_symfile_read, which reads a symbol table
+ from a file.
+
+ dbx_symfile_read only does the minimum work necessary for letting the
+ user "name" things symbolically; it does not read the entire symtab.
+ Instead, it reads the external and static symbols and puts them in partial
+ symbol tables. When more extensive information is requested of a
+ file, the corresponding partial symbol table is mutated into a full
+ fledged symbol table by going back and reading the symbols
+ for real. dbx_psymtab_to_symtab() is the function that does this */
+
+#include "defs.h"
+#include <string.h>
+
+#if defined(USG) || defined(__CYGNUSCLIB__)
+#include <sys/types.h>
+#include <fcntl.h>
+#endif
+
+#include <obstack.h>
+#include <sys/param.h>
+#ifndef NO_SYS_FILE
+#include <sys/file.h>
+#endif
+#include <sys/stat.h>
+#include <ctype.h>
+#include "symtab.h"
+#include "breakpoint.h"
+#include "command.h"
+#include "target.h"
+#include "gdbcore.h" /* for bfd stuff */
+#include "libaout.h" /* FIXME Secret internal BFD stuff for a.out */
+#include "symfile.h"
+#include "objfiles.h"
+#include "buildsym.h"
+#include "stabsread.h"
+#include "gdb-stabs.h"
+#include "demangle.h"
+#include "language.h" /* Needed inside partial-stab.h */
+#include "complaints.h"
+
+#include "aout/aout64.h"
+#include "aout/stab_gnu.h" /* We always use GNU stabs, not native, now */
+
+#if !defined (SEEK_SET)
+#define SEEK_SET 0
+#define SEEK_CUR 1
+#endif
+
+/* Each partial symbol table entry contains a pointer to private data for the
+ read_symtab() function to use when expanding a partial symbol table entry
+ to a full symbol table entry.
+
+ For dbxread this structure contains the offset within the file symbol table
+ of first local symbol for this file, and length (in bytes) of the section
+ of the symbol table devoted to this file's symbols (actually, the section
+ bracketed may contain more than just this file's symbols). It also contains
+ further information needed to locate the symbols if they are in an ELF file.
+
+ If ldsymlen is 0, the only reason for this thing's existence is the
+ dependency list. Nothing else will happen when it is read in. */
+
+#define LDSYMOFF(p) (((struct symloc *)((p)->read_symtab_private))->ldsymoff)
+#define LDSYMLEN(p) (((struct symloc *)((p)->read_symtab_private))->ldsymlen)
+#define SYMLOC(p) ((struct symloc *)((p)->read_symtab_private))
+#define SYMBOL_SIZE(p) (SYMLOC(p)->symbol_size)
+#define SYMBOL_OFFSET(p) (SYMLOC(p)->symbol_offset)
+#define STRING_OFFSET(p) (SYMLOC(p)->string_offset)
+#define FILE_STRING_OFFSET(p) (SYMLOC(p)->file_string_offset)
+
+struct symloc {
+ int ldsymoff;
+ int ldsymlen;
+ int symbol_size;
+ int symbol_offset;
+ int string_offset;
+ int file_string_offset;
+};
+
+/* Macro to determine which symbols to ignore when reading the first symbol
+ of a file. Some machines override this definition. */
+#ifndef IGNORE_SYMBOL
+/* This code is used on Ultrix systems. Ignore it */
+#define IGNORE_SYMBOL(type) (type == (int)N_NSYMS)
+#endif
+
+/* Remember what we deduced to be the source language of this psymtab. */
+
+static enum language psymtab_language = language_unknown;
+
+/* Nonzero means give verbose info on gdb action. From main.c. */
+extern int info_verbose;
+
+/* The BFD for this file -- implicit parameter to next_symbol_text. */
+
+static bfd *symfile_bfd;
+
+/* The size of each symbol in the symbol file (in external form).
+ This is set by dbx_symfile_read when building psymtabs, and by
+ dbx_psymtab_to_symtab when building symtabs. */
+
+static unsigned symbol_size;
+
+/* This is the offset of the symbol table in the executable file */
+static unsigned symbol_table_offset;
+
+/* This is the offset of the string table in the executable file */
+static unsigned string_table_offset;
+
+/* For elf+stab executables, the n_strx field is not a simple index
+ into the string table. Instead, each .o file has a base offset
+ in the string table, and the associated symbols contain offsets
+ from this base. The following two variables contain the base
+ offset for the current and next .o files. */
+static unsigned int file_string_table_offset;
+static unsigned int next_file_string_table_offset;
+
+/* .o and NLM files contain unrelocated addresses which are based at 0. When
+ non-zero, this flag disables some of the special cases for Solaris elf+stab
+ text addresses at location 0. */
+
+static int symfile_relocatable = 0;
+
+ /* If this is nonzero, N_LBRAC, N_RBRAC, and N_SLINE entries are relative
+ to the function start address. */
+
+static int block_address_function_relative = 0;
+
+/* This is the lowest text address we have yet encountered. */
+static CORE_ADDR lowest_text_address;
+
+/* Complaints about the symbols we have encountered. */
+
+struct complaint lbrac_complaint =
+ {"bad block start address patched", 0, 0};
+
+struct complaint string_table_offset_complaint =
+ {"bad string table offset in symbol %d", 0, 0};
+
+struct complaint unknown_symtype_complaint =
+ {"unknown symbol type %s", 0, 0};
+
+struct complaint unknown_symchar_complaint =
+ {"unknown symbol descriptor `%c'", 0, 0};
+
+struct complaint lbrac_rbrac_complaint =
+ {"block start larger than block end", 0, 0};
+
+struct complaint lbrac_unmatched_complaint =
+ {"unmatched N_LBRAC before symtab pos %d", 0, 0};
+
+struct complaint lbrac_mismatch_complaint =
+ {"N_LBRAC/N_RBRAC symbol mismatch at symtab pos %d", 0, 0};
+
+struct complaint repeated_header_complaint =
+ {"\"repeated\" header file not previously seen, at symtab pos %d", 0, 0};
+
+struct complaint repeated_header_name_complaint =
+ {"\"repeated\" header file not previously seen, named %s", 0, 0};
+
+/* During initial symbol readin, we need to have a structure to keep
+ track of which psymtabs have which bincls in them. This structure
+ is used during readin to setup the list of dependencies within each
+ partial symbol table. */
+
+struct header_file_location
+{
+ char *name; /* Name of header file */
+ int instance; /* See above */
+ struct partial_symtab *pst; /* Partial symtab that has the
+ BINCL/EINCL defs for this file */
+};
+
+/* The actual list and controling variables */
+static struct header_file_location *bincl_list, *next_bincl;
+static int bincls_allocated;
+
+/* Local function prototypes */
+
+static void
+free_header_files PARAMS ((void));
+
+static void
+init_header_files PARAMS ((void));
+
+static void
+read_ofile_symtab PARAMS ((struct partial_symtab *));
+
+static void
+dbx_psymtab_to_symtab PARAMS ((struct partial_symtab *));
+
+static void
+dbx_psymtab_to_symtab_1 PARAMS ((struct partial_symtab *));
+
+static void
+read_dbx_dynamic_symtab PARAMS ((struct section_offsets *,
+ struct objfile *objfile));
+
+static void
+read_dbx_symtab PARAMS ((struct section_offsets *, struct objfile *,
+ CORE_ADDR, int));
+
+static void
+free_bincl_list PARAMS ((struct objfile *));
+
+static struct partial_symtab *
+find_corresponding_bincl_psymtab PARAMS ((char *, int));
+
+static void
+add_bincl_to_list PARAMS ((struct partial_symtab *, char *, int));
+
+static void
+init_bincl_list PARAMS ((int, struct objfile *));
+
+static void
+init_psymbol_list PARAMS ((struct objfile *));
+
+static char *
+dbx_next_symbol_text PARAMS ((void));
+
+static void
+fill_symbuf PARAMS ((bfd *));
+
+static void
+dbx_symfile_init PARAMS ((struct objfile *));
+
+static void
+dbx_new_init PARAMS ((struct objfile *));
+
+static void
+dbx_symfile_read PARAMS ((struct objfile *, struct section_offsets *, int));
+
+static void
+dbx_symfile_finish PARAMS ((struct objfile *));
+
+static void
+record_minimal_symbol PARAMS ((char *, CORE_ADDR, int, struct objfile *));
+
+static void
+add_new_header_file PARAMS ((char *, int));
+
+static void
+add_old_header_file PARAMS ((char *, int));
+
+static void
+add_this_object_header_file PARAMS ((int));
+
+/* Free up old header file tables */
+
+static void
+free_header_files ()
+{
+ register int i;
+
+ if (header_files != NULL)
+ {
+ for (i = 0; i < n_header_files; i++)
+ {
+ free (header_files[i].name);
+ }
+ free ((PTR)header_files);
+ header_files = NULL;
+ n_header_files = 0;
+ }
+ if (this_object_header_files)
+ {
+ free ((PTR)this_object_header_files);
+ this_object_header_files = NULL;
+ }
+ n_allocated_header_files = 0;
+ n_allocated_this_object_header_files = 0;
+}
+
+/* Allocate new header file tables */
+
+static void
+init_header_files ()
+{
+ n_header_files = 0;
+ n_allocated_header_files = 10;
+ header_files = (struct header_file *)
+ xmalloc (10 * sizeof (struct header_file));
+
+ n_allocated_this_object_header_files = 10;
+ this_object_header_files = (int *) xmalloc (10 * sizeof (int));
+}
+
+/* Add header file number I for this object file
+ at the next successive FILENUM. */
+
+static void
+add_this_object_header_file (i)
+ int i;
+{
+ if (n_this_object_header_files == n_allocated_this_object_header_files)
+ {
+ n_allocated_this_object_header_files *= 2;
+ this_object_header_files
+ = (int *) xrealloc ((char *) this_object_header_files,
+ n_allocated_this_object_header_files * sizeof (int));
+ }
+
+ this_object_header_files[n_this_object_header_files++] = i;
+}
+
+/* Add to this file an "old" header file, one already seen in
+ a previous object file. NAME is the header file's name.
+ INSTANCE is its instance code, to select among multiple
+ symbol tables for the same header file. */
+
+static void
+add_old_header_file (name, instance)
+ char *name;
+ int instance;
+{
+ register struct header_file *p = header_files;
+ register int i;
+
+ for (i = 0; i < n_header_files; i++)
+ if (STREQ (p[i].name, name) && instance == p[i].instance)
+ {
+ add_this_object_header_file (i);
+ return;
+ }
+ complain (&repeated_header_complaint, symnum);
+ complain (&repeated_header_name_complaint, name);
+}
+
+/* Add to this file a "new" header file: definitions for its types follow.
+ NAME is the header file's name.
+ Most often this happens only once for each distinct header file,
+ but not necessarily. If it happens more than once, INSTANCE has
+ a different value each time, and references to the header file
+ use INSTANCE values to select among them.
+
+ dbx output contains "begin" and "end" markers for each new header file,
+ but at this level we just need to know which files there have been;
+ so we record the file when its "begin" is seen and ignore the "end". */
+
+static void
+add_new_header_file (name, instance)
+ char *name;
+ int instance;
+{
+ register int i;
+
+ /* Make sure there is room for one more header file. */
+
+ if (n_header_files == n_allocated_header_files)
+ {
+ n_allocated_header_files *= 2;
+ header_files = (struct header_file *)
+ xrealloc ((char *) header_files,
+ (n_allocated_header_files * sizeof (struct header_file)));
+ }
+
+ /* Create an entry for this header file. */
+
+ i = n_header_files++;
+ header_files[i].name = savestring (name, strlen(name));
+ header_files[i].instance = instance;
+ header_files[i].length = 10;
+ header_files[i].vector
+ = (struct type **) xmalloc (10 * sizeof (struct type *));
+ memset (header_files[i].vector, 0, 10 * sizeof (struct type *));
+
+ add_this_object_header_file (i);
+}
+
+#if 0
+static struct type **
+explicit_lookup_type (real_filenum, index)
+ int real_filenum, index;
+{
+ register struct header_file *f = &header_files[real_filenum];
+
+ if (index >= f->length)
+ {
+ f->length *= 2;
+ f->vector = (struct type **)
+ xrealloc (f->vector, f->length * sizeof (struct type *));
+ memset (&f->vector[f->length / 2],
+ '\0', f->length * sizeof (struct type *) / 2);
+ }
+ return &f->vector[index];
+}
+#endif
+
+static void
+record_minimal_symbol (name, address, type, objfile)
+ char *name;
+ CORE_ADDR address;
+ int type;
+ struct objfile *objfile;
+{
+ enum minimal_symbol_type ms_type;
+ int section;
+
+ switch (type)
+ {
+ case N_TEXT | N_EXT:
+ ms_type = mst_text;
+ section = SECT_OFF_TEXT;
+ break;
+ case N_DATA | N_EXT:
+ ms_type = mst_data;
+ section = SECT_OFF_DATA;
+ break;
+ case N_BSS | N_EXT:
+ ms_type = mst_bss;
+ section = SECT_OFF_BSS;
+ break;
+ case N_ABS | N_EXT:
+ ms_type = mst_abs;
+ section = -1;
+ break;
+#ifdef N_SETV
+ case N_SETV | N_EXT:
+ ms_type = mst_data;
+ section = SECT_OFF_DATA;
+ break;
+ case N_SETV:
+ /* I don't think this type actually exists; since a N_SETV is the result
+ of going over many .o files, it doesn't make sense to have one
+ file local. */
+ ms_type = mst_file_data;
+ section = SECT_OFF_DATA;
+ break;
+#endif
+ case N_TEXT:
+ case N_NBTEXT:
+ case N_FN:
+ case N_FN_SEQ:
+ ms_type = mst_file_text;
+ section = SECT_OFF_TEXT;
+ break;
+ case N_DATA:
+ ms_type = mst_file_data;
+
+ /* Check for __DYNAMIC, which is used by Sun shared libraries.
+ Record it as global even if it's local, not global, so
+ lookup_minimal_symbol can find it. We don't check symbol_leading_char
+ because for SunOS4 it always is '_'. */
+ if (name[8] == 'C' && STREQ ("__DYNAMIC", name))
+ ms_type = mst_data;
+
+ /* Same with virtual function tables, both global and static. */
+ {
+ char *tempstring = name;
+ if (tempstring[0] == bfd_get_symbol_leading_char (objfile->obfd))
+ ++tempstring;
+ if (VTBL_PREFIX_P ((tempstring)))
+ ms_type = mst_data;
+ }
+ section = SECT_OFF_DATA;
+ break;
+ case N_BSS:
+ ms_type = mst_file_bss;
+ section = SECT_OFF_BSS;
+ break;
+ default:
+ ms_type = mst_unknown;
+ section = -1;
+ break;
+ }
+
+ if ((ms_type == mst_file_text || ms_type == mst_text)
+ && address < lowest_text_address)
+ lowest_text_address = address;
+
+ prim_record_minimal_symbol_and_info
+ (obsavestring (name, strlen (name), &objfile -> symbol_obstack),
+ address,
+ ms_type,
+ NULL,
+ section,
+ objfile);
+}
+
+/* Scan and build partial symbols for a symbol file.
+ We have been initialized by a call to dbx_symfile_init, which
+ put all the relevant info into a "struct dbx_symfile_info",
+ hung off the objfile structure.
+
+ SECTION_OFFSETS contains offsets relative to which the symbols in the
+ various sections are (depending where the sections were actually loaded).
+ MAINLINE is true if we are reading the main symbol
+ table (as opposed to a shared lib or dynamically loaded file). */
+
+static void
+dbx_symfile_read (objfile, section_offsets, mainline)
+ struct objfile *objfile;
+ struct section_offsets *section_offsets;
+ int mainline; /* FIXME comments above */
+{
+ bfd *sym_bfd;
+ int val;
+ struct cleanup *back_to;
+
+ val = strlen (objfile->name);
+
+ /* .o and .nlm files are relocatables with text, data and bss segs based at
+ 0. This flag disables special (Solaris stabs-in-elf only) fixups for
+ symbols with a value of 0. XXX - This is a Krock. Solaris stabs-in-elf
+ should be fixed to determine pst->textlow without using this text seg of
+ 0 fixup crap. */
+
+ if (strcmp (&objfile->name[val-2], ".o") == 0
+ || strcmp (&objfile->name[val-4], ".nlm") == 0)
+ symfile_relocatable = 1;
+
+ /* This is true for Solaris (and all other systems which put stabs
+ in sections, hopefully, since it would be silly to do things
+ differently from Solaris), and false for SunOS4 and other a.out
+ file formats. */
+ block_address_function_relative =
+ ((0 == strncmp (bfd_get_target (objfile->obfd), "elf", 3))
+ || (0 == strncmp (bfd_get_target (objfile->obfd), "som", 3))
+ || (0 == strncmp (bfd_get_target (objfile->obfd), "coff", 4))
+ || (0 == strncmp (bfd_get_target (objfile->obfd), "nlm", 3)));
+
+ sym_bfd = objfile->obfd;
+ val = bfd_seek (objfile->obfd, DBX_SYMTAB_OFFSET (objfile), SEEK_SET);
+ if (val < 0)
+ perror_with_name (objfile->name);
+
+ /* If we are reinitializing, or if we have never loaded syms yet, init */
+ if (mainline || objfile->global_psymbols.size == 0 || objfile->static_psymbols.size == 0)
+ init_psymbol_list (objfile);
+
+ symbol_size = DBX_SYMBOL_SIZE (objfile);
+ symbol_table_offset = DBX_SYMTAB_OFFSET (objfile);
+
+ pending_blocks = 0;
+ back_to = make_cleanup (really_free_pendings, 0);
+
+ init_minimal_symbol_collection ();
+ make_cleanup (discard_minimal_symbols, 0);
+
+ /* Now that the symbol table data of the executable file are all in core,
+ process them and define symbols accordingly. */
+
+ read_dbx_symtab (section_offsets, objfile,
+ bfd_section_vma (sym_bfd, DBX_TEXT_SECT (objfile)),
+ bfd_section_size (sym_bfd, DBX_TEXT_SECT (objfile)));
+
+ /* Add the dynamic symbols. */
+
+ read_dbx_dynamic_symtab (section_offsets, objfile);
+
+ /* Install any minimal symbols that have been collected as the current
+ minimal symbols for this objfile. */
+
+ install_minimal_symbols (objfile);
+
+ do_cleanups (back_to);
+}
+
+/* Initialize anything that needs initializing when a completely new
+ symbol file is specified (not just adding some symbols from another
+ file, e.g. a shared library). */
+
+static void
+dbx_new_init (ignore)
+ struct objfile *ignore;
+{
+ stabsread_new_init ();
+ buildsym_new_init ();
+ init_header_files ();
+}
+
+
+/* dbx_symfile_init ()
+ is the dbx-specific initialization routine for reading symbols.
+ It is passed a struct objfile which contains, among other things,
+ the BFD for the file whose symbols are being read, and a slot for a pointer
+ to "private data" which we fill with goodies.
+
+ We read the string table into malloc'd space and stash a pointer to it.
+
+ Since BFD doesn't know how to read debug symbols in a format-independent
+ way (and may never do so...), we have to do it ourselves. We will never
+ be called unless this is an a.out (or very similar) file.
+ FIXME, there should be a cleaner peephole into the BFD environment here. */
+
+#define DBX_STRINGTAB_SIZE_SIZE sizeof(long) /* FIXME */
+
+static void
+dbx_symfile_init (objfile)
+ struct objfile *objfile;
+{
+ int val;
+ bfd *sym_bfd = objfile->obfd;
+ char *name = bfd_get_filename (sym_bfd);
+ unsigned char size_temp[DBX_STRINGTAB_SIZE_SIZE];
+
+ /* Allocate struct to keep track of the symfile */
+ objfile->sym_stab_info = (PTR)
+ xmmalloc (objfile -> md, sizeof (struct dbx_symfile_info));
+
+ /* FIXME POKING INSIDE BFD DATA STRUCTURES */
+#define STRING_TABLE_OFFSET (sym_bfd->origin + obj_str_filepos (sym_bfd))
+#define SYMBOL_TABLE_OFFSET (sym_bfd->origin + obj_sym_filepos (sym_bfd))
+
+ /* FIXME POKING INSIDE BFD DATA STRUCTURES */
+
+ DBX_SYMFILE_INFO (objfile)->stab_section_info = NULL;
+ DBX_TEXT_SECT (objfile) = bfd_get_section_by_name (sym_bfd, ".text");
+ if (!DBX_TEXT_SECT (objfile))
+ error ("Can't find .text section in symbol file");
+
+ DBX_SYMBOL_SIZE (objfile) = obj_symbol_entry_size (sym_bfd);
+ DBX_SYMCOUNT (objfile) = bfd_get_symcount (sym_bfd);
+ DBX_SYMTAB_OFFSET (objfile) = SYMBOL_TABLE_OFFSET;
+
+ /* Read the string table and stash it away in the psymbol_obstack. It is
+ only needed as long as we need to expand psymbols into full symbols,
+ so when we blow away the psymbol the string table goes away as well.
+ Note that gdb used to use the results of attempting to malloc the
+ string table, based on the size it read, as a form of sanity check
+ for botched byte swapping, on the theory that a byte swapped string
+ table size would be so totally bogus that the malloc would fail. Now
+ that we put in on the psymbol_obstack, we can't do this since gdb gets
+ a fatal error (out of virtual memory) if the size is bogus. We can
+ however at least check to see if the size is less than the size of
+ the size field itself, or larger than the size of the entire file.
+ Note that all valid string tables have a size greater than zero, since
+ the bytes used to hold the size are included in the count. */
+
+ if (STRING_TABLE_OFFSET == 0)
+ {
+ /* It appears that with the existing bfd code, STRING_TABLE_OFFSET
+ will never be zero, even when there is no string table. This
+ would appear to be a bug in bfd. */
+ DBX_STRINGTAB_SIZE (objfile) = 0;
+ DBX_STRINGTAB (objfile) = NULL;
+ }
+ else
+ {
+ val = bfd_seek (sym_bfd, STRING_TABLE_OFFSET, SEEK_SET);
+ if (val < 0)
+ perror_with_name (name);
+
+ memset ((PTR) size_temp, 0, sizeof (size_temp));
+ val = bfd_read ((PTR) size_temp, sizeof (size_temp), 1, sym_bfd);
+ if (val < 0)
+ {
+ perror_with_name (name);
+ }
+ else if (val == 0)
+ {
+ /* With the existing bfd code, STRING_TABLE_OFFSET will be set to
+ EOF if there is no string table, and attempting to read the size
+ from EOF will read zero bytes. */
+ DBX_STRINGTAB_SIZE (objfile) = 0;
+ DBX_STRINGTAB (objfile) = NULL;
+ }
+ else
+ {
+ /* Read some data that would appear to be the string table size.
+ If there really is a string table, then it is probably the right
+ size. Byteswap if necessary and validate the size. Note that
+ the minimum is DBX_STRINGTAB_SIZE_SIZE. If we just read some
+ random data that happened to be at STRING_TABLE_OFFSET, because
+ bfd can't tell us there is no string table, the sanity checks may
+ or may not catch this. */
+ DBX_STRINGTAB_SIZE (objfile) = bfd_h_get_32 (sym_bfd, size_temp);
+
+ if (DBX_STRINGTAB_SIZE (objfile) < sizeof (size_temp)
+ || DBX_STRINGTAB_SIZE (objfile) > bfd_get_size (sym_bfd))
+ error ("ridiculous string table size (%d bytes).",
+ DBX_STRINGTAB_SIZE (objfile));
+
+ DBX_STRINGTAB (objfile) =
+ (char *) obstack_alloc (&objfile -> psymbol_obstack,
+ DBX_STRINGTAB_SIZE (objfile));
+
+ /* Now read in the string table in one big gulp. */
+
+ val = bfd_seek (sym_bfd, STRING_TABLE_OFFSET, SEEK_SET);
+ if (val < 0)
+ perror_with_name (name);
+ val = bfd_read (DBX_STRINGTAB (objfile), DBX_STRINGTAB_SIZE (objfile), 1,
+ sym_bfd);
+ if (val != DBX_STRINGTAB_SIZE (objfile))
+ perror_with_name (name);
+ }
+ }
+}
+
+/* Perform any local cleanups required when we are done with a particular
+ objfile. I.E, we are in the process of discarding all symbol information
+ for an objfile, freeing up all memory held for it, and unlinking the
+ objfile struct from the global list of known objfiles. */
+
+static void
+dbx_symfile_finish (objfile)
+ struct objfile *objfile;
+{
+ if (objfile->sym_stab_info != NULL)
+ {
+ mfree (objfile -> md, objfile->sym_stab_info);
+ }
+ free_header_files ();
+}
+
+
+/* Buffer for reading the symbol table entries. */
+static struct internal_nlist symbuf[4096];
+static int symbuf_idx;
+static int symbuf_end;
+
+/* Name of last function encountered. Used in Solaris to approximate
+ object file boundaries. */
+static char *last_function_name;
+
+/* The address in memory of the string table of the object file we are
+ reading (which might not be the "main" object file, but might be a
+ shared library or some other dynamically loaded thing). This is set
+ by read_dbx_symtab when building psymtabs, and by read_ofile_symtab
+ when building symtabs, and is used only by next_symbol_text. */
+static char *stringtab_global;
+
+/* Refill the symbol table input buffer
+ and set the variables that control fetching entries from it.
+ Reports an error if no data available.
+ This function can read past the end of the symbol table
+ (into the string table) but this does no harm. */
+
+static void
+fill_symbuf (sym_bfd)
+ bfd *sym_bfd;
+{
+ int nbytes = bfd_read ((PTR)symbuf, sizeof (symbuf), 1, sym_bfd);
+ if (nbytes < 0)
+ perror_with_name (bfd_get_filename (sym_bfd));
+ else if (nbytes == 0)
+ error ("Premature end of file reading symbol table");
+ symbuf_end = nbytes / symbol_size;
+ symbuf_idx = 0;
+}
+
+#define SWAP_SYMBOL(symp, abfd) \
+ { \
+ (symp)->n_strx = bfd_h_get_32(abfd, \
+ (unsigned char *)&(symp)->n_strx); \
+ (symp)->n_desc = bfd_h_get_16 (abfd, \
+ (unsigned char *)&(symp)->n_desc); \
+ (symp)->n_value = bfd_h_get_32 (abfd, \
+ (unsigned char *)&(symp)->n_value); \
+ }
+
+/* Invariant: The symbol pointed to by symbuf_idx is the first one
+ that hasn't been swapped. Swap the symbol at the same time
+ that symbuf_idx is incremented. */
+
+/* dbx allows the text of a symbol name to be continued into the
+ next symbol name! When such a continuation is encountered
+ (a \ at the end of the text of a name)
+ call this function to get the continuation. */
+
+static char *
+dbx_next_symbol_text ()
+{
+ if (symbuf_idx == symbuf_end)
+ fill_symbuf (symfile_bfd);
+ symnum++;
+ SWAP_SYMBOL(&symbuf[symbuf_idx], symfile_bfd);
+ return symbuf[symbuf_idx++].n_strx + stringtab_global
+ + file_string_table_offset;
+}
+
+/* Initializes storage for all of the partial symbols that will be
+ created by read_dbx_symtab and subsidiaries. */
+
+static void
+init_psymbol_list (objfile)
+ struct objfile *objfile;
+{
+ /* Free any previously allocated psymbol lists. */
+ if (objfile -> global_psymbols.list)
+ mfree (objfile -> md, (PTR)objfile -> global_psymbols.list);
+ if (objfile -> static_psymbols.list)
+ mfree (objfile -> md, (PTR)objfile -> static_psymbols.list);
+
+ /* Current best guess is that there are approximately a twentieth
+ of the total symbols (in a debugging file) are global or static
+ oriented symbols */
+ objfile -> global_psymbols.size = DBX_SYMCOUNT (objfile) / 10;
+ objfile -> static_psymbols.size = DBX_SYMCOUNT (objfile) / 10;
+ objfile -> global_psymbols.next = objfile -> global_psymbols.list = (struct partial_symbol *)
+ xmmalloc (objfile -> md, objfile -> global_psymbols.size * sizeof (struct partial_symbol));
+ objfile -> static_psymbols.next = objfile -> static_psymbols.list = (struct partial_symbol *)
+ xmmalloc (objfile -> md, objfile -> static_psymbols.size * sizeof (struct partial_symbol));
+}
+
+/* Initialize the list of bincls to contain none and have some
+ allocated. */
+
+static void
+init_bincl_list (number, objfile)
+ int number;
+ struct objfile *objfile;
+{
+ bincls_allocated = number;
+ next_bincl = bincl_list = (struct header_file_location *)
+ xmmalloc (objfile -> md, bincls_allocated * sizeof(struct header_file_location));
+}
+
+/* Add a bincl to the list. */
+
+static void
+add_bincl_to_list (pst, name, instance)
+ struct partial_symtab *pst;
+ char *name;
+ int instance;
+{
+ if (next_bincl >= bincl_list + bincls_allocated)
+ {
+ int offset = next_bincl - bincl_list;
+ bincls_allocated *= 2;
+ bincl_list = (struct header_file_location *)
+ xmrealloc (pst->objfile->md, (char *)bincl_list,
+ bincls_allocated * sizeof (struct header_file_location));
+ next_bincl = bincl_list + offset;
+ }
+ next_bincl->pst = pst;
+ next_bincl->instance = instance;
+ next_bincl++->name = name;
+}
+
+/* Given a name, value pair, find the corresponding
+ bincl in the list. Return the partial symtab associated
+ with that header_file_location. */
+
+static struct partial_symtab *
+find_corresponding_bincl_psymtab (name, instance)
+ char *name;
+ int instance;
+{
+ struct header_file_location *bincl;
+
+ for (bincl = bincl_list; bincl < next_bincl; bincl++)
+ if (bincl->instance == instance
+ && STREQ (name, bincl->name))
+ return bincl->pst;
+
+ return (struct partial_symtab *) 0;
+}
+
+/* Free the storage allocated for the bincl list. */
+
+static void
+free_bincl_list (objfile)
+ struct objfile *objfile;
+{
+ mfree (objfile -> md, (PTR)bincl_list);
+ bincls_allocated = 0;
+}
+
+/* Scan a SunOs dynamic symbol table for symbols of interest and
+ add them to the minimal symbol table. */
+
+static void
+read_dbx_dynamic_symtab (section_offsets, objfile)
+ struct section_offsets *section_offsets;
+ struct objfile *objfile;
+{
+ bfd *abfd = objfile->obfd;
+ struct cleanup *back_to;
+ int counter;
+ long dynsym_size;
+ long dynsym_count;
+ asymbol **dynsyms;
+ asymbol **symptr;
+ arelent **relptr;
+ long dynrel_size;
+ long dynrel_count;
+ arelent **dynrels;
+ CORE_ADDR sym_value;
+
+ /* Check that the symbol file has dynamic symbols that we know about.
+ bfd_arch_unknown can happen if we are reading a sun3 symbol file
+ on a sun4 host (and vice versa) and bfd is not configured
+ --with-target=all. This would trigger an assertion in bfd/sunos.c,
+ so we ignore the dynamic symbols in this case. */
+ if (bfd_get_flavour (abfd) != bfd_target_aout_flavour
+ || (bfd_get_file_flags (abfd) & DYNAMIC) == 0
+ || bfd_get_arch (abfd) == bfd_arch_unknown)
+ return;
+
+ dynsym_size = bfd_get_dynamic_symtab_upper_bound (abfd);
+ if (dynsym_size < 0)
+ return;
+
+ dynsyms = (asymbol **) xmalloc (dynsym_size);
+ back_to = make_cleanup (free, dynsyms);
+
+ dynsym_count = bfd_canonicalize_dynamic_symtab (abfd, dynsyms);
+ if (dynsym_count < 0)
+ {
+ do_cleanups (back_to);
+ return;
+ }
+
+ /* Enter dynamic symbols into the minimal symbol table
+ if this is a stripped executable. */
+ if (bfd_get_symcount (abfd) <= 0)
+ {
+ symptr = dynsyms;
+ for (counter = 0; counter < dynsym_count; counter++, symptr++)
+ {
+ asymbol *sym = *symptr;
+ asection *sec;
+ int type;
+
+ sec = bfd_get_section (sym);
+
+ /* BFD symbols are section relative. */
+ sym_value = sym->value + sec->vma;
+
+ if (bfd_get_section_flags (abfd, sec) & SEC_CODE)
+ {
+ sym_value += ANOFFSET (section_offsets, SECT_OFF_TEXT);
+ type = N_TEXT;
+ }
+ else if (bfd_get_section_flags (abfd, sec) & SEC_DATA)
+ {
+ sym_value += ANOFFSET (section_offsets, SECT_OFF_DATA);
+ type = N_DATA;
+ }
+ else if (bfd_get_section_flags (abfd, sec) & SEC_ALLOC)
+ {
+ sym_value += ANOFFSET (section_offsets, SECT_OFF_BSS);
+ type = N_BSS;
+ }
+ else
+ continue;
+
+ if (sym->flags & BSF_GLOBAL)
+ type |= N_EXT;
+
+ record_minimal_symbol ((char *) bfd_asymbol_name (sym), sym_value,
+ type, objfile);
+ }
+ }
+
+ /* Symbols from shared libraries have a dynamic relocation entry
+ that points to the associated slot in the procedure linkage table.
+ We make a mininal symbol table entry with type mst_solib_trampoline
+ at the address in the procedure linkage table. */
+ dynrel_size = bfd_get_dynamic_reloc_upper_bound (abfd);
+ if (dynrel_size < 0)
+ {
+ do_cleanups (back_to);
+ return;
+ }
+
+ dynrels = (arelent **) xmalloc (dynrel_size);
+ make_cleanup (free, dynrels);
+
+ dynrel_count = bfd_canonicalize_dynamic_reloc (abfd, dynrels, dynsyms);
+ if (dynrel_count < 0)
+ {
+ do_cleanups (back_to);
+ return;
+ }
+
+ for (counter = 0, relptr = dynrels;
+ counter < dynrel_count;
+ counter++, relptr++)
+ {
+ arelent *rel = *relptr;
+ CORE_ADDR address =
+ rel->address + ANOFFSET (section_offsets, SECT_OFF_DATA);
+
+ switch (bfd_get_arch (abfd))
+ {
+ case bfd_arch_sparc:
+ if (rel->howto->type != RELOC_JMP_SLOT)
+ continue;
+ break;
+ case bfd_arch_m68k:
+ /* `16' is the type BFD produces for a jump table relocation. */
+ if (rel->howto->type != 16)
+ continue;
+
+ /* Adjust address in the jump table to point to
+ the start of the bsr instruction. */
+ address -= 2;
+ break;
+ default:
+ continue;
+ }
+
+ prim_record_minimal_symbol (bfd_asymbol_name (*rel->sym_ptr_ptr),
+ address,
+ mst_solib_trampoline,
+ objfile);
+ }
+
+ do_cleanups (back_to);
+}
+
+/* Given pointers to an a.out symbol table in core containing dbx
+ style data, setup partial_symtab's describing each source file for
+ which debugging information is available.
+ SYMFILE_NAME is the name of the file we are reading from
+ and SECTION_OFFSETS is the set of offsets for the various sections
+ of the file (a set of zeros if the mainline program). */
+
+static void
+read_dbx_symtab (section_offsets, objfile, text_addr, text_size)
+ struct section_offsets *section_offsets;
+ struct objfile *objfile;
+ CORE_ADDR text_addr;
+ int text_size;
+{
+ register struct internal_nlist *bufp = 0; /* =0 avoids gcc -Wall glitch */
+ register char *namestring;
+ int nsl;
+ int past_first_source_file = 0;
+ CORE_ADDR last_o_file_start = 0;
+ struct cleanup *back_to;
+ bfd *abfd;
+
+ /* Current partial symtab */
+ struct partial_symtab *pst;
+
+ /* List of current psymtab's include files */
+ char **psymtab_include_list;
+ int includes_allocated;
+ int includes_used;
+
+ /* Index within current psymtab dependency list */
+ struct partial_symtab **dependency_list;
+ int dependencies_used, dependencies_allocated;
+
+ /* FIXME. We probably want to change stringtab_global rather than add this
+ while processing every symbol entry. FIXME. */
+ file_string_table_offset = 0;
+ next_file_string_table_offset = 0;
+
+ stringtab_global = DBX_STRINGTAB (objfile);
+
+ pst = (struct partial_symtab *) 0;
+
+ includes_allocated = 30;
+ includes_used = 0;
+ psymtab_include_list = (char **) alloca (includes_allocated *
+ sizeof (char *));
+
+ dependencies_allocated = 30;
+ dependencies_used = 0;
+ dependency_list =
+ (struct partial_symtab **) alloca (dependencies_allocated *
+ sizeof (struct partial_symtab *));
+
+ /* Init bincl list */
+ init_bincl_list (20, objfile);
+ back_to = make_cleanup (free_bincl_list, objfile);
+
+ last_source_file = NULL;
+
+ lowest_text_address = (CORE_ADDR)-1;
+
+ symfile_bfd = objfile->obfd; /* For next_text_symbol */
+ abfd = objfile->obfd;
+ symbuf_end = symbuf_idx = 0;
+ next_symbol_text_func = dbx_next_symbol_text;
+
+ for (symnum = 0; symnum < DBX_SYMCOUNT (objfile); symnum++)
+ {
+ /* Get the symbol for this run and pull out some info */
+ QUIT; /* allow this to be interruptable */
+ if (symbuf_idx == symbuf_end)
+ fill_symbuf (abfd);
+ bufp = &symbuf[symbuf_idx++];
+
+ /*
+ * Special case to speed up readin.
+ */
+ if (bufp->n_type == (unsigned char)N_SLINE) continue;
+
+ SWAP_SYMBOL (bufp, abfd);
+
+ /* Ok. There is a lot of code duplicated in the rest of this
+ switch statement (for efficiency reasons). Since I don't
+ like duplicating code, I will do my penance here, and
+ describe the code which is duplicated:
+
+ *) The assignment to namestring.
+ *) The call to strchr.
+ *) The addition of a partial symbol the the two partial
+ symbol lists. This last is a large section of code, so
+ I've imbedded it in the following macro.
+ */
+
+/* Set namestring based on bufp. If the string table index is invalid,
+ give a fake name, and print a single error message per symbol file read,
+ rather than abort the symbol reading or flood the user with messages. */
+
+/*FIXME: Too many adds and indirections in here for the inner loop. */
+#define SET_NAMESTRING()\
+ if (((unsigned)bufp->n_strx + file_string_table_offset) >= \
+ DBX_STRINGTAB_SIZE (objfile)) { \
+ complain (&string_table_offset_complaint, symnum); \
+ namestring = "<bad string table offset>"; \
+ } else \
+ namestring = bufp->n_strx + file_string_table_offset + \
+ DBX_STRINGTAB (objfile)
+
+#define CUR_SYMBOL_TYPE bufp->n_type
+#define CUR_SYMBOL_VALUE bufp->n_value
+#define DBXREAD_ONLY
+#define START_PSYMTAB(ofile,secoff,fname,low,symoff,global_syms,static_syms)\
+ start_psymtab(ofile, secoff, fname, low, symoff, global_syms, static_syms)
+#define END_PSYMTAB(pst,ilist,ninc,c_off,c_text,dep_list,n_deps)\
+ end_psymtab(pst,ilist,ninc,c_off,c_text,dep_list,n_deps)
+
+#include "partial-stab.h"
+ }
+
+ /* If there's stuff to be cleaned up, clean it up. */
+ if (DBX_SYMCOUNT (objfile) > 0 /* We have some syms */
+/*FIXME, does this have a bug at start address 0? */
+ && last_o_file_start
+ && objfile -> ei.entry_point < bufp->n_value
+ && objfile -> ei.entry_point >= last_o_file_start)
+ {
+ objfile -> ei.entry_file_lowpc = last_o_file_start;
+ objfile -> ei.entry_file_highpc = bufp->n_value;
+ }
+
+ if (pst)
+ {
+ end_psymtab (pst, psymtab_include_list, includes_used,
+ symnum * symbol_size,
+ (lowest_text_address == (CORE_ADDR)-1
+ ? (text_addr + section_offsets->offsets[SECT_OFF_TEXT])
+ : lowest_text_address)
+ + text_size,
+ dependency_list, dependencies_used);
+ }
+
+ do_cleanups (back_to);
+}
+
+/* Allocate and partially fill a partial symtab. It will be
+ completely filled at the end of the symbol list.
+
+ SYMFILE_NAME is the name of the symbol-file we are reading from, and ADDR
+ is the address relative to which its symbols are (incremental) or 0
+ (normal). */
+
+
+struct partial_symtab *
+start_psymtab (objfile, section_offsets,
+ filename, textlow, ldsymoff, global_syms, static_syms)
+ struct objfile *objfile;
+ struct section_offsets *section_offsets;
+ char *filename;
+ CORE_ADDR textlow;
+ int ldsymoff;
+ struct partial_symbol *global_syms;
+ struct partial_symbol *static_syms;
+{
+ struct partial_symtab *result =
+ start_psymtab_common(objfile, section_offsets,
+ filename, textlow, global_syms, static_syms);
+
+ result->read_symtab_private = (char *)
+ obstack_alloc (&objfile -> psymbol_obstack, sizeof (struct symloc));
+ LDSYMOFF(result) = ldsymoff;
+ result->read_symtab = dbx_psymtab_to_symtab;
+ SYMBOL_SIZE(result) = symbol_size;
+ SYMBOL_OFFSET(result) = symbol_table_offset;
+ STRING_OFFSET(result) = string_table_offset;
+ FILE_STRING_OFFSET(result) = file_string_table_offset;
+
+ /* If we're handling an ELF file, drag some section-relocation info
+ for this source file out of the ELF symbol table, to compensate for
+ Sun brain death. This replaces the section_offsets in this psymtab,
+ if successful. */
+ elfstab_offset_sections (objfile, result);
+
+ /* Deduce the source language from the filename for this psymtab. */
+ psymtab_language = deduce_language_from_filename (filename);
+
+ return result;
+}
+
+/* Close off the current usage of PST.
+ Returns PST or NULL if the partial symtab was empty and thrown away.
+
+ FIXME: List variables and peculiarities of same. */
+
+struct partial_symtab *
+end_psymtab (pst, include_list, num_includes, capping_symbol_offset,
+ capping_text, dependency_list, number_dependencies)
+ struct partial_symtab *pst;
+ char **include_list;
+ int num_includes;
+ int capping_symbol_offset;
+ CORE_ADDR capping_text;
+ struct partial_symtab **dependency_list;
+ int number_dependencies;
+{
+ int i;
+ struct objfile *objfile = pst -> objfile;
+
+ if (capping_symbol_offset != -1)
+ LDSYMLEN(pst) = capping_symbol_offset - LDSYMOFF(pst);
+ pst->texthigh = capping_text;
+
+#ifdef N_SO_ADDRESS_MAYBE_MISSING
+ /* Under Solaris, the N_SO symbols always have a value of 0,
+ instead of the usual address of the .o file. Therefore,
+ we have to do some tricks to fill in texthigh and textlow.
+ The first trick is in partial-stab.h: if we see a static
+ or global function, and the textlow for the current pst
+ is still 0, then we use that function's address for
+ the textlow of the pst.
+
+ Now, to fill in texthigh, we remember the last function seen
+ in the .o file (also in partial-stab.h). Also, there's a hack in
+ bfd/elf.c and gdb/elfread.c to pass the ELF st_size field
+ to here via the misc_info field. Therefore, we can fill in
+ a reliable texthigh by taking the address plus size of the
+ last function in the file.
+
+ Unfortunately, that does not cover the case where the last function
+ in the file is static. See the paragraph below for more comments
+ on this situation.
+
+ Finally, if we have a valid textlow for the current file, we run
+ down the partial_symtab_list filling in previous texthighs that
+ are still unknown. */
+
+ if (pst->texthigh == 0 && last_function_name) {
+ char *p;
+ int n;
+ struct minimal_symbol *minsym;
+
+ p = strchr (last_function_name, ':');
+ if (p == NULL)
+ p = last_function_name;
+ n = p - last_function_name;
+ p = alloca (n + 1);
+ strncpy (p, last_function_name, n);
+ p[n] = 0;
+
+ minsym = lookup_minimal_symbol (p, objfile);
+
+ if (minsym) {
+ pst->texthigh = SYMBOL_VALUE_ADDRESS (minsym) +
+ (long) MSYMBOL_INFO (minsym);
+ } else {
+ /* This file ends with a static function, and it's
+ difficult to imagine how hard it would be to track down
+ the elf symbol. Luckily, most of the time no one will notice,
+ since the next file will likely be compiled with -g, so
+ the code below will copy the first fuction's start address
+ back to our texthigh variable. (Also, if this file is the
+ last one in a dynamically linked program, texthigh already
+ has the right value.) If the next file isn't compiled
+ with -g, then the last function in this file winds up owning
+ all of the text space up to the next -g file, or the end (minus
+ shared libraries). This only matters for single stepping,
+ and even then it will still work, except that it will single
+ step through all of the covered functions, instead of setting
+ breakpoints around them as it usualy does. This makes it
+ pretty slow, but at least it doesn't fail.
+
+ We can fix this with a fairly big change to bfd, but we need
+ to coordinate better with Cygnus if we want to do that. FIXME. */
+ }
+ last_function_name = NULL;
+ }
+
+ /* this test will be true if the last .o file is only data */
+ if (pst->textlow == 0)
+ /* This loses if the text section really starts at address zero
+ (generally true when we are debugging a .o file, for example).
+ That is why this whole thing is inside N_SO_ADDRESS_MAYBE_MISSING. */
+ pst->textlow = pst->texthigh;
+
+ /* If we know our own starting text address, then walk through all other
+ psymtabs for this objfile, and if any didn't know their ending text
+ address, set it to our starting address. Take care to not set our
+ own ending address to our starting address, nor to set addresses on
+ `dependency' files that have both textlow and texthigh zero. */
+ if (pst->textlow) {
+ struct partial_symtab *p1;
+
+ ALL_OBJFILE_PSYMTABS (objfile, p1) {
+ if (p1->texthigh == 0 && p1->textlow != 0 && p1 != pst) {
+ p1->texthigh = pst->textlow;
+ /* if this file has only data, then make textlow match texthigh */
+ if (p1->textlow == 0)
+ p1->textlow = p1->texthigh;
+ }
+ }
+ }
+
+ /* End of kludge for patching Solaris textlow and texthigh. */
+#endif /* N_SO_ADDRESS_MAYBE_MISSING. */
+
+ pst->n_global_syms =
+ objfile->global_psymbols.next - (objfile->global_psymbols.list + pst->globals_offset);
+ pst->n_static_syms =
+ objfile->static_psymbols.next - (objfile->static_psymbols.list + pst->statics_offset);
+
+ pst->number_of_dependencies = number_dependencies;
+ if (number_dependencies)
+ {
+ pst->dependencies = (struct partial_symtab **)
+ obstack_alloc (&objfile->psymbol_obstack,
+ number_dependencies * sizeof (struct partial_symtab *));
+ memcpy (pst->dependencies, dependency_list,
+ number_dependencies * sizeof (struct partial_symtab *));
+ }
+ else
+ pst->dependencies = 0;
+
+ for (i = 0; i < num_includes; i++)
+ {
+ struct partial_symtab *subpst =
+ allocate_psymtab (include_list[i], objfile);
+
+ subpst->section_offsets = pst->section_offsets;
+ subpst->read_symtab_private =
+ (char *) obstack_alloc (&objfile->psymbol_obstack,
+ sizeof (struct symloc));
+ LDSYMOFF(subpst) =
+ LDSYMLEN(subpst) =
+ subpst->textlow =
+ subpst->texthigh = 0;
+
+ /* We could save slight bits of space by only making one of these,
+ shared by the entire set of include files. FIXME-someday. */
+ subpst->dependencies = (struct partial_symtab **)
+ obstack_alloc (&objfile->psymbol_obstack,
+ sizeof (struct partial_symtab *));
+ subpst->dependencies[0] = pst;
+ subpst->number_of_dependencies = 1;
+
+ subpst->globals_offset =
+ subpst->n_global_syms =
+ subpst->statics_offset =
+ subpst->n_static_syms = 0;
+
+ subpst->readin = 0;
+ subpst->symtab = 0;
+ subpst->read_symtab = pst->read_symtab;
+ }
+
+ sort_pst_symbols (pst);
+
+ /* If there is already a psymtab or symtab for a file of this name, remove it.
+ (If there is a symtab, more drastic things also happen.)
+ This happens in VxWorks. */
+ free_named_symtabs (pst->filename);
+
+ if (num_includes == 0
+ && number_dependencies == 0
+ && pst->n_global_syms == 0
+ && pst->n_static_syms == 0)
+ {
+ /* Throw away this psymtab, it's empty. We can't deallocate it, since
+ it is on the obstack, but we can forget to chain it on the list. */
+ /* Empty psymtabs happen as a result of header files which don't have
+ any symbols in them. There can be a lot of them. But this check
+ is wrong, in that a psymtab with N_SLINE entries but nothing else
+ is not empty, but we don't realize that. Fixing that without slowing
+ things down might be tricky. */
+ struct partial_symtab *prev_pst;
+
+ /* First, snip it out of the psymtab chain */
+
+ if (pst->objfile->psymtabs == pst)
+ pst->objfile->psymtabs = pst->next;
+ else
+ for (prev_pst = pst->objfile->psymtabs; prev_pst; prev_pst = pst->next)
+ if (prev_pst->next == pst)
+ prev_pst->next = pst->next;
+
+ /* Next, put it on a free list for recycling */
+
+ pst->next = pst->objfile->free_psymtabs;
+ pst->objfile->free_psymtabs = pst;
+
+ /* Indicate that psymtab was thrown away. */
+ pst = (struct partial_symtab *)NULL;
+ }
+ return pst;
+}
+
+static void
+dbx_psymtab_to_symtab_1 (pst)
+ struct partial_symtab *pst;
+{
+ struct cleanup *old_chain;
+ int i;
+
+ if (!pst)
+ return;
+
+ if (pst->readin)
+ {
+ fprintf_unfiltered (gdb_stderr, "Psymtab for %s already read in. Shouldn't happen.\n",
+ pst->filename);
+ return;
+ }
+
+ /* Read in all partial symtabs on which this one is dependent */
+ for (i = 0; i < pst->number_of_dependencies; i++)
+ if (!pst->dependencies[i]->readin)
+ {
+ /* Inform about additional files that need to be read in. */
+ if (info_verbose)
+ {
+ fputs_filtered (" ", gdb_stdout);
+ wrap_here ("");
+ fputs_filtered ("and ", gdb_stdout);
+ wrap_here ("");
+ printf_filtered ("%s...", pst->dependencies[i]->filename);
+ wrap_here (""); /* Flush output */
+ gdb_flush (gdb_stdout);
+ }
+ dbx_psymtab_to_symtab_1 (pst->dependencies[i]);
+ }
+
+ if (LDSYMLEN(pst)) /* Otherwise it's a dummy */
+ {
+ /* Init stuff necessary for reading in symbols */
+ stabsread_init ();
+ buildsym_init ();
+ old_chain = make_cleanup (really_free_pendings, 0);
+ file_string_table_offset = FILE_STRING_OFFSET (pst);
+ symbol_size = SYMBOL_SIZE (pst);
+
+ /* Read in this file's symbols */
+ bfd_seek (pst->objfile->obfd, SYMBOL_OFFSET (pst), SEEK_SET);
+ read_ofile_symtab (pst);
+ sort_symtab_syms (pst->symtab);
+
+ do_cleanups (old_chain);
+ }
+
+ pst->readin = 1;
+}
+
+/* Read in all of the symbols for a given psymtab for real.
+ Be verbose about it if the user wants that. */
+
+static void
+dbx_psymtab_to_symtab (pst)
+ struct partial_symtab *pst;
+{
+ bfd *sym_bfd;
+
+ if (!pst)
+ return;
+
+ if (pst->readin)
+ {
+ fprintf_unfiltered (gdb_stderr, "Psymtab for %s already read in. Shouldn't happen.\n",
+ pst->filename);
+ return;
+ }
+
+ if (LDSYMLEN(pst) || pst->number_of_dependencies)
+ {
+ /* Print the message now, before reading the string table,
+ to avoid disconcerting pauses. */
+ if (info_verbose)
+ {
+ printf_filtered ("Reading in symbols for %s...", pst->filename);
+ gdb_flush (gdb_stdout);
+ }
+
+ sym_bfd = pst->objfile->obfd;
+
+ next_symbol_text_func = dbx_next_symbol_text;
+
+ dbx_psymtab_to_symtab_1 (pst);
+
+ /* Match with global symbols. This only needs to be done once,
+ after all of the symtabs and dependencies have been read in. */
+ scan_file_globals (pst->objfile);
+
+ /* Finish up the debug error message. */
+ if (info_verbose)
+ printf_filtered ("done.\n");
+ }
+}
+
+/* Read in a defined section of a specific object file's symbols. */
+
+static void
+read_ofile_symtab (pst)
+ struct partial_symtab *pst;
+{
+ register char *namestring;
+ register struct internal_nlist *bufp;
+ unsigned char type;
+ unsigned max_symnum;
+ register bfd *abfd;
+ struct objfile *objfile;
+ int sym_offset; /* Offset to start of symbols to read */
+ int sym_size; /* Size of symbols to read */
+ CORE_ADDR text_offset; /* Start of text segment for symbols */
+ int text_size; /* Size of text segment for symbols */
+ struct section_offsets *section_offsets;
+
+ objfile = pst->objfile;
+ sym_offset = LDSYMOFF(pst);
+ sym_size = LDSYMLEN(pst);
+ text_offset = pst->textlow;
+ text_size = pst->texthigh - pst->textlow;
+ section_offsets = pst->section_offsets;
+
+ current_objfile = objfile;
+ subfile_stack = NULL;
+
+ stringtab_global = DBX_STRINGTAB (objfile);
+ last_source_file = NULL;
+
+ abfd = objfile->obfd;
+ symfile_bfd = objfile->obfd; /* Implicit param to next_text_symbol */
+ symbuf_end = symbuf_idx = 0;
+
+ /* It is necessary to actually read one symbol *before* the start
+ of this symtab's symbols, because the GCC_COMPILED_FLAG_SYMBOL
+ occurs before the N_SO symbol.
+
+ Detecting this in read_dbx_symtab
+ would slow down initial readin, so we look for it here instead. */
+ if (!processing_acc_compilation && sym_offset >= (int)symbol_size)
+ {
+ bfd_seek (symfile_bfd, sym_offset - symbol_size, SEEK_CUR);
+ fill_symbuf (abfd);
+ bufp = &symbuf[symbuf_idx++];
+ SWAP_SYMBOL (bufp, abfd);
+
+ SET_NAMESTRING ();
+
+ processing_gcc_compilation = 0;
+ if (bufp->n_type == N_TEXT)
+ {
+ const char *tempstring = namestring;
+
+ if (STREQ (namestring, GCC_COMPILED_FLAG_SYMBOL))
+ processing_gcc_compilation = 1;
+ else if (STREQ (namestring, GCC2_COMPILED_FLAG_SYMBOL))
+ processing_gcc_compilation = 2;
+ if (tempstring[0] == bfd_get_symbol_leading_char (symfile_bfd))
+ ++tempstring;
+ if (STREQN (tempstring, "__gnu_compiled", 14))
+ processing_gcc_compilation = 2;
+ }
+
+ /* Try to select a C++ demangling based on the compilation unit
+ producer. */
+
+ if (processing_gcc_compilation)
+ {
+ if (AUTO_DEMANGLING)
+ {
+ set_demangling_style (GNU_DEMANGLING_STYLE_STRING);
+ }
+ }
+ }
+ else
+ {
+ /* The N_SO starting this symtab is the first symbol, so we
+ better not check the symbol before it. I'm not this can
+ happen, but it doesn't hurt to check for it. */
+ bfd_seek (symfile_bfd, sym_offset, SEEK_CUR);
+ processing_gcc_compilation = 0;
+ }
+
+ if (symbuf_idx == symbuf_end)
+ fill_symbuf (abfd);
+ bufp = &symbuf[symbuf_idx];
+ if (bufp->n_type != (unsigned char)N_SO)
+ error("First symbol in segment of executable not a source symbol");
+
+ max_symnum = sym_size / symbol_size;
+
+ for (symnum = 0;
+ symnum < max_symnum;
+ symnum++)
+ {
+ QUIT; /* Allow this to be interruptable */
+ if (symbuf_idx == symbuf_end)
+ fill_symbuf(abfd);
+ bufp = &symbuf[symbuf_idx++];
+ SWAP_SYMBOL (bufp, abfd);
+
+ type = bufp->n_type;
+
+ SET_NAMESTRING ();
+
+ if (type & N_STAB) {
+ process_one_symbol (type, bufp->n_desc, bufp->n_value,
+ namestring, section_offsets, objfile);
+ }
+ /* We skip checking for a new .o or -l file; that should never
+ happen in this routine. */
+ else if (type == N_TEXT)
+ {
+ /* I don't think this code will ever be executed, because
+ the GCC_COMPILED_FLAG_SYMBOL usually is right before
+ the N_SO symbol which starts this source file.
+ However, there is no reason not to accept
+ the GCC_COMPILED_FLAG_SYMBOL anywhere. */
+
+ if (STREQ (namestring, GCC_COMPILED_FLAG_SYMBOL))
+ processing_gcc_compilation = 1;
+ else if (STREQ (namestring, GCC2_COMPILED_FLAG_SYMBOL))
+ processing_gcc_compilation = 2;
+
+ if (AUTO_DEMANGLING)
+ {
+ set_demangling_style (GNU_DEMANGLING_STYLE_STRING);
+ }
+ }
+ else if (type & N_EXT || type == (unsigned char)N_TEXT
+ || type == (unsigned char)N_NBTEXT
+ ) {
+ /* Global symbol: see if we came across a dbx defintion for
+ a corresponding symbol. If so, store the value. Remove
+ syms from the chain when their values are stored, but
+ search the whole chain, as there may be several syms from
+ different files with the same name. */
+ /* This is probably not true. Since the files will be read
+ in one at a time, each reference to a global symbol will
+ be satisfied in each file as it appears. So we skip this
+ section. */
+ ;
+ }
+ }
+
+ current_objfile = NULL;
+
+ /* In a Solaris elf file, this variable, which comes from the
+ value of the N_SO symbol, will still be 0. Luckily, text_offset,
+ which comes from pst->textlow is correct. */
+ if (last_source_start_addr == 0)
+ last_source_start_addr = text_offset;
+
+ pst->symtab = end_symtab (text_offset + text_size, 0, 0, objfile,
+ SECT_OFF_TEXT);
+ end_stabs ();
+}
+
+
+/* This handles a single symbol from the symbol-file, building symbols
+ into a GDB symtab. It takes these arguments and an implicit argument.
+
+ TYPE is the type field of the ".stab" symbol entry.
+ DESC is the desc field of the ".stab" entry.
+ VALU is the value field of the ".stab" entry.
+ NAME is the symbol name, in our address space.
+ SECTION_OFFSETS is a set of amounts by which the sections of this object
+ file were relocated when it was loaded into memory.
+ All symbols that refer
+ to memory locations need to be offset by these amounts.
+ OBJFILE is the object file from which we are reading symbols.
+ It is used in end_symtab. */
+
+void
+process_one_symbol (type, desc, valu, name, section_offsets, objfile)
+ int type, desc;
+ CORE_ADDR valu;
+ char *name;
+ struct section_offsets *section_offsets;
+ struct objfile *objfile;
+{
+#ifdef SUN_FIXED_LBRAC_BUG
+ /* If SUN_FIXED_LBRAC_BUG is defined, then it tells us whether we need
+ to correct the address of N_LBRAC's. If it is not defined, then
+ we never need to correct the addresses. */
+
+ /* This records the last pc address we've seen. We depend on there being
+ an SLINE or FUN or SO before the first LBRAC, since the variable does
+ not get reset in between reads of different symbol files. */
+ static CORE_ADDR last_pc_address;
+#endif
+
+ register struct context_stack *new;
+ /* This remembers the address of the start of a function. It is used
+ because in Solaris 2, N_LBRAC, N_RBRAC, and N_SLINE entries are
+ relative to the current function's start address. On systems
+ other than Solaris 2, this just holds the SECT_OFF_TEXT value, and is
+ used to relocate these symbol types rather than SECTION_OFFSETS. */
+ static CORE_ADDR function_start_offset;
+
+ /* If this is nonzero, we've seen a non-gcc N_OPT symbol for this source
+ file. Used to detect the SunPRO solaris compiler. */
+ static int n_opt_found;
+
+ /* The stab type used for the definition of the last function.
+ N_STSYM or N_GSYM for SunOS4 acc; N_FUN for other compilers. */
+ static int function_stab_type = 0;
+
+ if (!block_address_function_relative)
+ /* N_LBRAC, N_RBRAC and N_SLINE entries are not relative to the
+ function start address, so just use the text offset. */
+ function_start_offset = ANOFFSET (section_offsets, SECT_OFF_TEXT);
+
+ /* Something is wrong if we see real data before
+ seeing a source file name. */
+
+ if (last_source_file == NULL && type != (unsigned char)N_SO)
+ {
+ /* Ignore any symbols which appear before an N_SO symbol. Currently
+ no one puts symbols there, but we should deal gracefully with the
+ case. A complain()t might be in order (if !IGNORE_SYMBOL (type)),
+ but this should not be an error (). */
+ return;
+ }
+
+ switch (type)
+ {
+ case N_FUN:
+ case N_FNAME:
+ /* Relocate for dynamic loading */
+ valu += ANOFFSET (section_offsets, SECT_OFF_TEXT);
+ goto define_a_symbol;
+
+ case N_LBRAC:
+ /* This "symbol" just indicates the start of an inner lexical
+ context within a function. */
+
+#if defined(BLOCK_ADDRESS_ABSOLUTE)
+ /* Relocate for dynamic loading (?). */
+ valu += function_start_offset;
+#else
+ if (block_address_function_relative)
+ /* Relocate for Sun ELF acc fn-relative syms. */
+ valu += function_start_offset;
+ else
+ /* On most machines, the block addresses are relative to the
+ N_SO, the linker did not relocate them (sigh). */
+ valu += last_source_start_addr;
+#endif
+
+#ifdef SUN_FIXED_LBRAC_BUG
+ if (!SUN_FIXED_LBRAC_BUG && valu < last_pc_address) {
+ /* Patch current LBRAC pc value to match last handy pc value */
+ complain (&lbrac_complaint);
+ valu = last_pc_address;
+ }
+#endif
+ new = push_context (desc, valu);
+ break;
+
+ case N_RBRAC:
+ /* This "symbol" just indicates the end of an inner lexical
+ context that was started with N_LBRAC. */
+
+#if defined(BLOCK_ADDRESS_ABSOLUTE)
+ /* Relocate for dynamic loading (?). */
+ valu += function_start_offset;
+#else
+ if (block_address_function_relative)
+ /* Relocate for Sun ELF acc fn-relative syms. */
+ valu += function_start_offset;
+ else
+ /* On most machines, the block addresses are relative to the
+ N_SO, the linker did not relocate them (sigh). */
+ valu += last_source_start_addr;
+#endif
+
+ new = pop_context();
+ if (desc != new->depth)
+ complain (&lbrac_mismatch_complaint, symnum);
+
+ /* Some compilers put the variable decls inside of an
+ LBRAC/RBRAC block. This macro should be nonzero if this
+ is true. DESC is N_DESC from the N_RBRAC symbol.
+ GCC_P is true if we've detected the GCC_COMPILED_SYMBOL
+ or the GCC2_COMPILED_SYMBOL. */
+#if !defined (VARIABLES_INSIDE_BLOCK)
+#define VARIABLES_INSIDE_BLOCK(desc, gcc_p) 0
+#endif
+
+ /* Can only use new->locals as local symbols here if we're in
+ gcc or on a machine that puts them before the lbrack. */
+ if (!VARIABLES_INSIDE_BLOCK(desc, processing_gcc_compilation))
+ local_symbols = new->locals;
+
+ if (context_stack_depth
+ > !VARIABLES_INSIDE_BLOCK(desc, processing_gcc_compilation))
+ {
+ /* This is not the outermost LBRAC...RBRAC pair in the function,
+ its local symbols preceded it, and are the ones just recovered
+ from the context stack. Define the block for them (but don't
+ bother if the block contains no symbols. Should we complain
+ on blocks without symbols? I can't think of any useful purpose
+ for them). */
+ if (local_symbols != NULL)
+ {
+ /* Muzzle a compiler bug that makes end < start. (which
+ compilers? Is this ever harmful?). */
+ if (new->start_addr > valu)
+ {
+ complain (&lbrac_rbrac_complaint);
+ new->start_addr = valu;
+ }
+ /* Make a block for the local symbols within. */
+ finish_block (0, &local_symbols, new->old_blocks,
+ new->start_addr, valu, objfile);
+ }
+ }
+ else
+ {
+ /* This is the outermost LBRAC...RBRAC pair. There is no
+ need to do anything; leave the symbols that preceded it
+ to be attached to the function's own block. We need to
+ indicate that we just moved outside of the function. */
+ within_function = 0;
+ }
+
+ if (VARIABLES_INSIDE_BLOCK(desc, processing_gcc_compilation))
+ /* Now pop locals of block just finished. */
+ local_symbols = new->locals;
+ break;
+
+ case N_FN:
+ case N_FN_SEQ:
+ /* This kind of symbol indicates the start of an object file. */
+ /* Relocate for dynamic loading */
+ valu += ANOFFSET (section_offsets, SECT_OFF_TEXT);
+ break;
+
+ case N_SO:
+ /* This type of symbol indicates the start of data
+ for one source file.
+ Finish the symbol table of the previous source file
+ (if any) and start accumulating a new symbol table. */
+ /* Relocate for dynamic loading */
+ valu += ANOFFSET (section_offsets, SECT_OFF_TEXT);
+
+ n_opt_found = 0;
+
+#ifdef SUN_FIXED_LBRAC_BUG
+ last_pc_address = valu; /* Save for SunOS bug circumcision */
+#endif
+
+#ifdef PCC_SOL_BROKEN
+ /* pcc bug, occasionally puts out SO for SOL. */
+ if (context_stack_depth > 0)
+ {
+ start_subfile (name, NULL);
+ break;
+ }
+#endif
+ if (last_source_file)
+ {
+ /* Check if previous symbol was also an N_SO (with some
+ sanity checks). If so, that one was actually the directory
+ name, and the current one is the real file name.
+ Patch things up. */
+ if (previous_stab_code == (unsigned char) N_SO)
+ {
+ patch_subfile_names (current_subfile, name);
+ break; /* Ignore repeated SOs */
+ }
+ end_symtab (valu, 0, 0, objfile, SECT_OFF_TEXT);
+ end_stabs ();
+ }
+
+ /* Null name means this just marks the end of text for this .o file.
+ Don't start a new symtab in this case. */
+ if (*name == '\000')
+ break;
+
+ start_stabs ();
+ start_symtab (name, NULL, valu);
+ break;
+
+ case N_SOL:
+ /* This type of symbol indicates the start of data for
+ a sub-source-file, one whose contents were copied or
+ included in the compilation of the main source file
+ (whose name was given in the N_SO symbol.) */
+ /* Relocate for dynamic loading */
+ valu += ANOFFSET (section_offsets, SECT_OFF_TEXT);
+ start_subfile (name, current_subfile->dirname);
+ break;
+
+ case N_BINCL:
+ push_subfile ();
+ add_new_header_file (name, valu);
+ start_subfile (name, current_subfile->dirname);
+ break;
+
+ case N_EINCL:
+ start_subfile (pop_subfile (), current_subfile->dirname);
+ break;
+
+ case N_EXCL:
+ add_old_header_file (name, valu);
+ break;
+
+ case N_SLINE:
+ /* This type of "symbol" really just records
+ one line-number -- core-address correspondence.
+ Enter it in the line list for this symbol table. */
+ /* Relocate for dynamic loading and for ELF acc fn-relative syms. */
+ valu += function_start_offset;
+#ifdef SUN_FIXED_LBRAC_BUG
+ last_pc_address = valu; /* Save for SunOS bug circumcision */
+#endif
+ record_line (current_subfile, desc, valu);
+ break;
+
+ case N_BCOMM:
+ common_block_start (name, objfile);
+ break;
+
+ case N_ECOMM:
+ common_block_end (objfile);
+ break;
+
+ /* The following symbol types need to have the appropriate offset added
+ to their value; then we process symbol definitions in the name. */
+
+ case N_STSYM: /* Static symbol in data seg */
+ case N_LCSYM: /* Static symbol in BSS seg */
+ case N_ROSYM: /* Static symbol in Read-only data seg */
+ /* HORRID HACK DEPT. However, it's Sun's furgin' fault.
+ Solaris2's stabs-in-elf makes *most* symbols relative
+ but leaves a few absolute (at least for Solaris 2.1 and version
+ 2.0.1 of the SunPRO compiler). N_STSYM and friends sit on the fence.
+ .stab "foo:S...",N_STSYM is absolute (ld relocates it)
+ .stab "foo:V...",N_STSYM is relative (section base subtracted).
+ This leaves us no choice but to search for the 'S' or 'V'...
+ (or pass the whole section_offsets stuff down ONE MORE function
+ call level, which we really don't want to do). */
+ {
+ char *p;
+
+ /* .o files and NLMs have non-zero text seg offsets, but don't need
+ their static syms offset in this fashion. XXX - This is really a
+ crock that should be fixed in the solib handling code so that I
+ don't have to work around it here. */
+
+ if (!symfile_relocatable)
+ {
+ p = strchr (name, ':');
+ if (p != 0 && p[1] == 'S')
+ {
+ /* The linker relocated it. We don't want to add an
+ elfstab_offset_sections-type offset, but we *do* want
+ to add whatever solib.c passed to symbol_file_add as
+ addr (this is known to affect SunOS4, and I suspect ELF
+ too). Since elfstab_offset_sections currently does not
+ muck with the text offset (there is no Ttext.text
+ symbol), we can get addr from the text offset. If
+ elfstab_offset_sections ever starts dealing with the
+ text offset, and we still need to do this, we need to
+ invent a SECT_OFF_ADDR_KLUDGE or something. */
+ valu += ANOFFSET (section_offsets, SECT_OFF_TEXT);
+ goto define_a_symbol;
+ }
+ }
+ /* Since it's not the kludge case, re-dispatch to the right handler. */
+ switch (type) {
+ case N_STSYM: goto case_N_STSYM;
+ case N_LCSYM: goto case_N_LCSYM;
+ case N_ROSYM: goto case_N_ROSYM;
+ default: abort();
+ }
+ }
+
+ case_N_STSYM: /* Static symbol in data seg */
+ case N_DSLINE: /* Source line number, data seg */
+ valu += ANOFFSET (section_offsets, SECT_OFF_DATA);
+ goto define_a_symbol;
+
+ case_N_LCSYM: /* Static symbol in BSS seg */
+ case N_BSLINE: /* Source line number, bss seg */
+ /* N_BROWS: overlaps with N_BSLINE */
+ valu += ANOFFSET (section_offsets, SECT_OFF_BSS);
+ goto define_a_symbol;
+
+ case_N_ROSYM: /* Static symbol in Read-only data seg */
+ valu += ANOFFSET (section_offsets, SECT_OFF_RODATA);
+ goto define_a_symbol;
+
+ case N_ENTRY: /* Alternate entry point */
+ /* Relocate for dynamic loading */
+ valu += ANOFFSET (section_offsets, SECT_OFF_TEXT);
+ goto define_a_symbol;
+
+ /* The following symbol types we don't know how to process. Handle
+ them in a "default" way, but complain to people who care. */
+ default:
+ case N_CATCH: /* Exception handler catcher */
+ case N_EHDECL: /* Exception handler name */
+ case N_PC: /* Global symbol in Pascal */
+ case N_M2C: /* Modula-2 compilation unit */
+ /* N_MOD2: overlaps with N_EHDECL */
+ case N_SCOPE: /* Modula-2 scope information */
+ case N_ECOML: /* End common (local name) */
+ case N_NBTEXT: /* Gould Non-Base-Register symbols??? */
+ case N_NBDATA:
+ case N_NBBSS:
+ case N_NBSTS:
+ case N_NBLCS:
+ complain (&unknown_symtype_complaint, local_hex_string (type));
+ /* FALLTHROUGH */
+
+ /* The following symbol types don't need the address field relocated,
+ since it is either unused, or is absolute. */
+ define_a_symbol:
+ case N_GSYM: /* Global variable */
+ case N_NSYMS: /* Number of symbols (ultrix) */
+ case N_NOMAP: /* No map? (ultrix) */
+ case N_RSYM: /* Register variable */
+ case N_DEFD: /* Modula-2 GNU module dependency */
+ case N_SSYM: /* Struct or union element */
+ case N_LSYM: /* Local symbol in stack */
+ case N_PSYM: /* Parameter variable */
+ case N_LENG: /* Length of preceding symbol type */
+ if (name)
+ {
+ int deftype;
+ char *colon_pos = strchr (name, ':');
+ if (colon_pos == NULL)
+ deftype = '\0';
+ else
+ deftype = colon_pos[1];
+
+ switch (deftype)
+ {
+ case 'f':
+ case 'F':
+ function_stab_type = type;
+
+#ifdef SUN_FIXED_LBRAC_BUG
+ /* The Sun acc compiler, under SunOS4, puts out
+ functions with N_GSYM or N_STSYM. The problem is
+ that the address of the symbol is no good (for N_GSYM
+ it doesn't even attept an address; for N_STSYM it
+ puts out an address but then it gets relocated
+ relative to the data segment, not the text segment).
+ Currently we can't fix this up later as we do for
+ some types of symbol in scan_file_globals.
+ Fortunately we do have a way of finding the address -
+ we know that the value in last_pc_address is either
+ the one we want (if we're dealing with the first
+ function in an object file), or somewhere in the
+ previous function. This means that we can use the
+ minimal symbol table to get the address. */
+
+ /* On solaris up to 2.2, the N_FUN stab gets relocated.
+ On Solaris 2.3, ld no longer relocates stabs (which
+ is good), and the N_FUN's value is now always zero.
+ The following code can't deal with this, because
+ last_pc_address depends on getting the address from a
+ N_SLINE or some such and in Solaris those are function
+ relative. Best fix is probably to create a Ttext.text symbol
+ and handle this like Ddata.data and so on. */
+
+ if (type == N_GSYM || type == N_STSYM)
+ {
+ struct minimal_symbol *m;
+ int l = colon_pos - name;
+
+ m = lookup_minimal_symbol_by_pc (last_pc_address);
+ if (m && STREQN (SYMBOL_NAME (m), name, l))
+ /* last_pc_address was in this function */
+ valu = SYMBOL_VALUE (m);
+ else if (m && STREQN (SYMBOL_NAME (m+1), name, l))
+ /* last_pc_address was in last function */
+ valu = SYMBOL_VALUE (m+1);
+ else
+ /* Not found - use last_pc_address (for finish_block) */
+ valu = last_pc_address;
+ }
+
+ last_pc_address = valu; /* Save for SunOS bug circumcision */
+#endif
+
+ if (block_address_function_relative)
+ /* For Solaris 2.0 compilers, the block addresses and
+ N_SLINE's are relative to the start of the
+ function. On normal systems, and when using gcc on
+ Solaris 2.0, these addresses are just absolute, or
+ relative to the N_SO, depending on
+ BLOCK_ADDRESS_ABSOLUTE. */
+ function_start_offset = valu;
+
+ within_function = 1;
+ if (context_stack_depth > 0)
+ {
+ new = pop_context ();
+ /* Make a block for the local symbols within. */
+ finish_block (new->name, &local_symbols, new->old_blocks,
+ new->start_addr, valu, objfile);
+ }
+ /* Stack must be empty now. */
+ if (context_stack_depth != 0)
+ complain (&lbrac_unmatched_complaint, symnum);
+
+ new = push_context (0, valu);
+ new->name = define_symbol (valu, name, desc, type, objfile);
+ break;
+
+ default:
+ define_symbol (valu, name, desc, type, objfile);
+ break;
+ }
+ }
+ break;
+
+ /* We use N_OPT to carry the gcc2_compiled flag. Sun uses it
+ for a bunch of other flags, too. Someday we may parse their
+ flags; for now we ignore theirs and hope they'll ignore ours. */
+ case N_OPT: /* Solaris 2: Compiler options */
+ if (name)
+ {
+ if (STREQ (name, GCC2_COMPILED_FLAG_SYMBOL))
+ {
+ processing_gcc_compilation = 2;
+#if 1 /* Works, but is experimental. -fnf */
+ if (AUTO_DEMANGLING)
+ {
+ set_demangling_style (GNU_DEMANGLING_STYLE_STRING);
+ }
+#endif
+ }
+ else
+ n_opt_found = 1;
+ }
+ break;
+
+ /* The following symbol types can be ignored. */
+ case N_OBJ: /* Solaris 2: Object file dir and name */
+ /* N_UNDF: Solaris 2: file separator mark */
+ /* N_UNDF: -- we will never encounter it, since we only process one
+ file's symbols at once. */
+ case N_ENDM: /* Solaris 2: End of module */
+ case N_MAIN: /* Name of main routine. */
+ break;
+ }
+
+ previous_stab_code = type;
+}
+
+/* FIXME: The only difference between this and elfstab_build_psymtabs is
+ the call to install_minimal_symbols for elf. If the differences are
+ really that small, the code should be shared. */
+
+/* Scan and build partial symbols for an coff symbol file.
+ The coff file has already been processed to get its minimal symbols.
+
+ This routine is the equivalent of dbx_symfile_init and dbx_symfile_read
+ rolled into one.
+
+ OBJFILE is the object file we are reading symbols from.
+ ADDR is the address relative to which the symbols are (e.g.
+ the base address of the text segment).
+ MAINLINE is true if we are reading the main symbol
+ table (as opposed to a shared lib or dynamically loaded file).
+ STABOFFSET and STABSIZE define the location in OBJFILE where the .stab
+ section exists.
+ STABSTROFFSET and STABSTRSIZE define the location in OBJFILE where the
+ .stabstr section exists.
+
+ This routine is mostly copied from dbx_symfile_init and dbx_symfile_read,
+ adjusted for coff details. */
+
+void
+coffstab_build_psymtabs (objfile, section_offsets, mainline,
+ staboffset, stabsize,
+ stabstroffset, stabstrsize)
+ struct objfile *objfile;
+ struct section_offsets *section_offsets;
+ int mainline;
+ file_ptr staboffset;
+ unsigned int stabsize;
+ file_ptr stabstroffset;
+ unsigned int stabstrsize;
+{
+ int val;
+ bfd *sym_bfd = objfile->obfd;
+ char *name = bfd_get_filename (sym_bfd);
+ struct dbx_symfile_info *info;
+
+ /* There is already a dbx_symfile_info allocated by our caller.
+ It might even contain some info from the coff symtab to help us. */
+ info = (struct dbx_symfile_info *) objfile->sym_stab_info;
+
+ DBX_TEXT_SECT (objfile) = bfd_get_section_by_name (sym_bfd, ".text");
+ if (!DBX_TEXT_SECT (objfile))
+ error ("Can't find .text section in symbol file");
+
+#define COFF_STABS_SYMBOL_SIZE 12 /* XXX FIXME XXX */
+ DBX_SYMBOL_SIZE (objfile) = COFF_STABS_SYMBOL_SIZE;
+ DBX_SYMCOUNT (objfile) = stabsize / DBX_SYMBOL_SIZE (objfile);
+ DBX_STRINGTAB_SIZE (objfile) = stabstrsize;
+ DBX_SYMTAB_OFFSET (objfile) = staboffset;
+
+ if (stabstrsize > bfd_get_size (sym_bfd))
+ error ("ridiculous string table size: %d bytes", stabstrsize);
+ DBX_STRINGTAB (objfile) = (char *)
+ obstack_alloc (&objfile->psymbol_obstack, stabstrsize+1);
+
+ /* Now read in the string table in one big gulp. */
+
+ val = bfd_seek (sym_bfd, stabstroffset, SEEK_SET);
+ if (val < 0)
+ perror_with_name (name);
+ val = bfd_read (DBX_STRINGTAB (objfile), stabstrsize, 1, sym_bfd);
+ if (val != stabstrsize)
+ perror_with_name (name);
+
+ stabsread_new_init ();
+ buildsym_new_init ();
+ free_header_files ();
+ init_header_files ();
+
+ processing_acc_compilation = 1;
+
+ /* In a coff file, we've already installed the minimal symbols that came
+ from the coff (non-stab) symbol table, so always act like an
+ incremental load here. */
+ dbx_symfile_read (objfile, section_offsets, 0);
+}
+
+/* Scan and build partial symbols for an ELF symbol file.
+ This ELF file has already been processed to get its minimal symbols,
+ and any DWARF symbols that were in it.
+
+ This routine is the equivalent of dbx_symfile_init and dbx_symfile_read
+ rolled into one.
+
+ OBJFILE is the object file we are reading symbols from.
+ ADDR is the address relative to which the symbols are (e.g.
+ the base address of the text segment).
+ MAINLINE is true if we are reading the main symbol
+ table (as opposed to a shared lib or dynamically loaded file).
+ STABOFFSET and STABSIZE define the location in OBJFILE where the .stab
+ section exists.
+ STABSTROFFSET and STABSTRSIZE define the location in OBJFILE where the
+ .stabstr section exists.
+
+ This routine is mostly copied from dbx_symfile_init and dbx_symfile_read,
+ adjusted for elf details. */
+
+void
+elfstab_build_psymtabs (objfile, section_offsets, mainline,
+ staboffset, stabsize,
+ stabstroffset, stabstrsize)
+ struct objfile *objfile;
+ struct section_offsets *section_offsets;
+ int mainline;
+ file_ptr staboffset;
+ unsigned int stabsize;
+ file_ptr stabstroffset;
+ unsigned int stabstrsize;
+{
+ int val;
+ bfd *sym_bfd = objfile->obfd;
+ char *name = bfd_get_filename (sym_bfd);
+ struct dbx_symfile_info *info;
+
+ /* There is already a dbx_symfile_info allocated by our caller.
+ It might even contain some info from the ELF symtab to help us. */
+ info = (struct dbx_symfile_info *) objfile->sym_stab_info;
+
+ DBX_TEXT_SECT (objfile) = bfd_get_section_by_name (sym_bfd, ".text");
+ if (!DBX_TEXT_SECT (objfile))
+ error ("Can't find .text section in symbol file");
+
+#define ELF_STABS_SYMBOL_SIZE 12 /* XXX FIXME XXX */
+ DBX_SYMBOL_SIZE (objfile) = ELF_STABS_SYMBOL_SIZE;
+ DBX_SYMCOUNT (objfile) = stabsize / DBX_SYMBOL_SIZE (objfile);
+ DBX_STRINGTAB_SIZE (objfile) = stabstrsize;
+ DBX_SYMTAB_OFFSET (objfile) = staboffset;
+
+ if (stabstrsize > bfd_get_size (sym_bfd))
+ error ("ridiculous string table size: %d bytes", stabstrsize);
+ DBX_STRINGTAB (objfile) = (char *)
+ obstack_alloc (&objfile->psymbol_obstack, stabstrsize+1);
+
+ /* Now read in the string table in one big gulp. */
+
+ val = bfd_seek (sym_bfd, stabstroffset, SEEK_SET);
+ if (val < 0)
+ perror_with_name (name);
+ val = bfd_read (DBX_STRINGTAB (objfile), stabstrsize, 1, sym_bfd);
+ if (val != stabstrsize)
+ perror_with_name (name);
+
+ stabsread_new_init ();
+ buildsym_new_init ();
+ free_header_files ();
+ init_header_files ();
+ install_minimal_symbols (objfile);
+
+ processing_acc_compilation = 1;
+
+ /* In an elf file, we've already installed the minimal symbols that came
+ from the elf (non-stab) symbol table, so always act like an
+ incremental load here. */
+ dbx_symfile_read (objfile, section_offsets, 0);
+}
+
+/* Scan and build partial symbols for a file with special sections for stabs
+ and stabstrings. The file has already been processed to get its minimal
+ symbols, and any other symbols that might be necessary to resolve GSYMs.
+
+ This routine is the equivalent of dbx_symfile_init and dbx_symfile_read
+ rolled into one.
+
+ OBJFILE is the object file we are reading symbols from.
+ ADDR is the address relative to which the symbols are (e.g. the base address
+ of the text segment).
+ MAINLINE is true if we are reading the main symbol table (as opposed to a
+ shared lib or dynamically loaded file).
+ STAB_NAME is the name of the section that contains the stabs.
+ STABSTR_NAME is the name of the section that contains the stab strings.
+
+ This routine is mostly copied from dbx_symfile_init and dbx_symfile_read. */
+
+void
+stabsect_build_psymtabs (objfile, section_offsets, mainline, stab_name,
+ stabstr_name, text_name)
+ struct objfile *objfile;
+ struct section_offsets *section_offsets;
+ int mainline;
+ char *stab_name;
+ char *stabstr_name;
+ char *text_name;
+{
+ int val;
+ bfd *sym_bfd = objfile->obfd;
+ char *name = bfd_get_filename (sym_bfd);
+ asection *stabsect;
+ asection *stabstrsect;
+
+ stabsect = bfd_get_section_by_name (sym_bfd, stab_name);
+ stabstrsect = bfd_get_section_by_name (sym_bfd, stabstr_name);
+
+ if (!stabsect)
+ return;
+
+ if (!stabstrsect)
+ error ("stabsect_build_psymtabs: Found stabs (%s), but not string section (%s)",
+ stab_name, stabstr_name);
+
+ objfile->sym_stab_info = (PTR) xmalloc (sizeof (struct dbx_symfile_info));
+ memset (DBX_SYMFILE_INFO (objfile), 0, sizeof (struct dbx_symfile_info));
+
+ DBX_TEXT_SECT (objfile) = bfd_get_section_by_name (sym_bfd, text_name);
+ if (!DBX_TEXT_SECT (objfile))
+ error ("Can't find %s section in symbol file", text_name);
+
+ DBX_SYMBOL_SIZE (objfile) = sizeof (struct external_nlist);
+ DBX_SYMCOUNT (objfile) = bfd_section_size (sym_bfd, stabsect)
+ / DBX_SYMBOL_SIZE (objfile);
+ DBX_STRINGTAB_SIZE (objfile) = bfd_section_size (sym_bfd, stabstrsect);
+ DBX_SYMTAB_OFFSET (objfile) = stabsect->filepos; /* XXX - FIXME: POKING INSIDE BFD DATA STRUCTURES */
+
+ if (DBX_STRINGTAB_SIZE (objfile) > bfd_get_size (sym_bfd))
+ error ("ridiculous string table size: %d bytes", DBX_STRINGTAB_SIZE (objfile));
+ DBX_STRINGTAB (objfile) = (char *)
+ obstack_alloc (&objfile->psymbol_obstack, DBX_STRINGTAB_SIZE (objfile) + 1);
+
+ /* Now read in the string table in one big gulp. */
+
+ val = bfd_get_section_contents (sym_bfd, /* bfd */
+ stabstrsect, /* bfd section */
+ DBX_STRINGTAB (objfile), /* input buffer */
+ 0, /* offset into section */
+ DBX_STRINGTAB_SIZE (objfile)); /* amount to read */
+
+ if (!val)
+ perror_with_name (name);
+
+ stabsread_new_init ();
+ buildsym_new_init ();
+ free_header_files ();
+ init_header_files ();
+ install_minimal_symbols (objfile);
+
+ /* Now, do an incremental load */
+
+ processing_acc_compilation = 1;
+ dbx_symfile_read (objfile, section_offsets, 0);
+}
+
+/* Parse the user's idea of an offset for dynamic linking, into our idea
+ of how to represent it for fast symbol reading. */
+
+static struct section_offsets *
+dbx_symfile_offsets (objfile, addr)
+ struct objfile *objfile;
+ CORE_ADDR addr;
+{
+ struct section_offsets *section_offsets;
+ int i;
+
+ objfile->num_sections = SECT_OFF_MAX;
+ section_offsets = (struct section_offsets *)
+ obstack_alloc (&objfile -> psymbol_obstack,
+ sizeof (struct section_offsets)
+ + sizeof (section_offsets->offsets) * (SECT_OFF_MAX-1));
+
+ for (i = 0; i < SECT_OFF_MAX; i++)
+ ANOFFSET (section_offsets, i) = addr;
+
+ return section_offsets;
+}
+
+static struct sym_fns aout_sym_fns =
+{
+ bfd_target_aout_flavour,
+ dbx_new_init, /* sym_new_init: init anything gbl to entire symtab */
+ dbx_symfile_init, /* sym_init: read initial info, setup for sym_read() */
+ dbx_symfile_read, /* sym_read: read a symbol file into symtab */
+ dbx_symfile_finish, /* sym_finish: finished with file, cleanup */
+ dbx_symfile_offsets, /* sym_offsets: parse user's offsets to internal form */
+ NULL /* next: pointer to next struct sym_fns */
+};
+
+void
+_initialize_dbxread ()
+{
+ add_symtab_fns(&aout_sym_fns);
+}
diff --git a/gnu/usr.bin/gdb/gdb/dcache.c b/gnu/usr.bin/gdb/gdb/dcache.c
new file mode 100644
index 0000000..a957abe
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/dcache.c
@@ -0,0 +1,236 @@
+/* Caching code. Typically used by remote back ends for
+ caching remote memory.
+
+ Copyright 1992, 1993 Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "defs.h"
+#include "dcache.h"
+#include "gdbcmd.h"
+
+extern int insque();
+extern int remque();
+
+int remote_dcache = 0;
+
+/* The data cache records all the data read from the remote machine
+ since the last time it stopped.
+
+ Each cache block holds LINE_SIZE bytes of data
+ starting at a multiple-of-LINE_SIZE address. */
+
+#define LINE_SIZE_MASK ((LINE_SIZE - 1)) /* eg 7*2+1= 111*/
+#define XFORM(x) (((x) & LINE_SIZE_MASK) >> 2)
+
+/* Free all the data cache blocks, thus discarding all cached data. */
+void
+dcache_flush (dcache)
+ DCACHE *dcache;
+{
+ register struct dcache_block *db;
+
+ if (remote_dcache > 0)
+ while ((db = dcache->dcache_valid.next) != &dcache->dcache_valid)
+ {
+ remque (db);
+ insque (db, &dcache->dcache_free);
+ }
+
+ return;
+}
+
+/*
+ * If addr is present in the dcache, return the address of the block
+ * containing it.
+ */
+static
+struct dcache_block *
+dcache_hit (dcache, addr)
+ DCACHE *dcache;
+ unsigned int addr;
+{
+ register struct dcache_block *db;
+
+ if (addr & 3
+ || remote_dcache == 0)
+ abort ();
+
+ /* Search all cache blocks for one that is at this address. */
+ db = dcache->dcache_valid.next;
+ while (db != &dcache->dcache_valid)
+ {
+ if ((addr & ~LINE_SIZE_MASK) == db->addr)
+ return db;
+ db = db->next;
+ }
+
+ return NULL;
+}
+
+/* Return the int data at address ADDR in dcache block DC. */
+static
+int
+dcache_value (db, addr)
+ struct dcache_block *db;
+ unsigned int addr;
+{
+ if (addr & 3
+ || remote_dcache == 0)
+ abort ();
+ return (db->data[XFORM (addr)]);
+}
+
+/* Get a free cache block, put or keep it on the valid list,
+ and return its address. The caller should store into the block
+ the address and data that it describes, then remque it from the
+ free list and insert it into the valid list. This procedure
+ prevents errors from creeping in if a memory retrieval is
+ interrupted (which used to put garbage blocks in the valid
+ list...). */
+static
+struct dcache_block *
+dcache_alloc (dcache)
+ DCACHE *dcache;
+{
+ register struct dcache_block *db;
+
+ if (remote_dcache == 0)
+ abort();
+
+ if ((db = dcache->dcache_free.next) == &dcache->dcache_free)
+ {
+ /* If we can't get one from the free list, take last valid and put
+ it on the free list. */
+ db = dcache->dcache_valid.last;
+ remque (db);
+ insque (db, &dcache->dcache_free);
+ }
+
+ remque (db);
+ insque (db, &dcache->dcache_valid);
+ return (db);
+}
+
+/* Using the data cache DCACHE return the contents of the word at
+ address ADDR in the remote machine. */
+int
+dcache_fetch (dcache, addr)
+ DCACHE *dcache;
+ CORE_ADDR addr;
+{
+ register struct dcache_block *db;
+
+ if (remote_dcache == 0)
+ {
+ int i;
+
+ (*dcache->read_memory) (addr, (unsigned char *) &i, 4);
+ return(i);
+ }
+
+ db = dcache_hit (dcache, addr);
+ if (db == 0)
+ {
+ db = dcache_alloc (dcache);
+ immediate_quit++;
+ (*dcache->read_memory) (addr & ~LINE_SIZE_MASK, (unsigned char *) db->data, LINE_SIZE);
+ immediate_quit--;
+ db->addr = addr & ~LINE_SIZE_MASK;
+ remque (db); /* Off the free list */
+ insque (db, &dcache->dcache_valid); /* On the valid list */
+ }
+ return (dcache_value (db, addr));
+}
+
+/* Write the word at ADDR both in the data cache and in the remote machine. */
+void
+dcache_poke (dcache, addr, data)
+ DCACHE *dcache;
+ CORE_ADDR addr;
+ int data;
+{
+ register struct dcache_block *db;
+
+ if (remote_dcache == 0)
+ {
+ (*dcache->write_memory) (addr, (unsigned char *) &data, 4);
+ return;
+ }
+
+ /* First make sure the word is IN the cache. DB is its cache block. */
+ db = dcache_hit (dcache, addr);
+ if (db == 0)
+ {
+ db = dcache_alloc (dcache);
+ immediate_quit++;
+ (*dcache->write_memory) (addr & ~LINE_SIZE_MASK, (unsigned char *) db->data, LINE_SIZE);
+ immediate_quit--;
+ db->addr = addr & ~LINE_SIZE_MASK;
+ remque (db); /* Off the free list */
+ insque (db, &dcache->dcache_valid); /* On the valid list */
+ }
+
+ /* Modify the word in the cache. */
+ db->data[XFORM (addr)] = data;
+
+ /* Send the changed word. */
+ immediate_quit++;
+ (*dcache->write_memory) (addr, (unsigned char *) &data, 4);
+ immediate_quit--;
+}
+
+/* Initialize the data cache. */
+DCACHE *
+dcache_init (reading, writing)
+ memxferfunc reading;
+ memxferfunc writing;
+{
+ register i;
+ register struct dcache_block *db;
+ DCACHE *dcache;
+
+ dcache = (DCACHE *) xmalloc (sizeof (*dcache));
+ dcache->read_memory = reading;
+ dcache->write_memory = writing;
+ dcache->the_cache = (struct dcache_block *)
+ xmalloc (sizeof (*dcache->the_cache) * DCACHE_SIZE);
+
+ dcache->dcache_free.next = dcache->dcache_free.last = &dcache->dcache_free;
+ dcache->dcache_valid.next = dcache->dcache_valid.last = &dcache->dcache_valid;
+ for (db = dcache->the_cache, i = 0; i < DCACHE_SIZE; i++, db++)
+ insque (db, &dcache->dcache_free);
+
+ return(dcache);
+}
+
+void
+_initialitize_dcache ()
+{
+ add_show_from_set
+ (add_set_cmd ("remotecache", class_support, var_boolean,
+ (char *) &remote_dcache,
+ "\
+Set cache use for remote targets.\n\
+When on, use data caching for remote targets. For many remote targets\n\
+this option can offer better throughput for reading target memory.\n\
+Unfortunately, gdb does not currently know anything about volatile\n\
+registers and thus data caching will produce incorrect results with\n\
+volatile registers are in use. By default, this option is off.",
+ &setlist),
+ &showlist);
+}
diff --git a/gnu/usr.bin/gdb/gdb/dcache.h b/gnu/usr.bin/gdb/gdb/dcache.h
new file mode 100644
index 0000000..bfc0dd7
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/dcache.h
@@ -0,0 +1,83 @@
+/* Declarations for caching. Typically used by remote back ends for
+ caching remote memory.
+
+ Copyright 1992, 1993 Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#ifndef DCACHE_H
+#define DCACHE_H
+
+/* The data cache leads to incorrect results because it doesn't know about
+ volatile variables, thus making it impossible to debug functions which
+ use hardware registers. Therefore it is #if 0'd out. Effect on
+ performance is some, for backtraces of functions with a few
+ arguments each. For functions with many arguments, the stack
+ frames don't fit in the cache blocks, which makes the cache less
+ helpful. Disabling the cache is a big performance win for fetching
+ large structures, because the cache code fetched data in 16-byte
+ chunks. */
+
+#define LINE_SIZE_POWER (4)
+/* eg 1<<3 == 8 */
+#define LINE_SIZE (1 << LINE_SIZE_POWER)
+/* Number of cache blocks */
+#define DCACHE_SIZE (64)
+
+struct dcache_block
+{
+ struct dcache_block *next, *last;
+ unsigned int addr; /* Address for which data is recorded. */
+ int data[LINE_SIZE / sizeof (int)];
+};
+
+typedef int (*memxferfunc) PARAMS((CORE_ADDR memaddr,
+ unsigned char *myaddr,
+ int len));
+
+typedef struct {
+ /* Function to actually read the target memory. */
+ memxferfunc read_memory;
+
+ /* Function to actually write the target memory */
+ memxferfunc write_memory;
+
+ /* free list */
+ struct dcache_block dcache_free;
+
+ /* in use list */
+ struct dcache_block dcache_valid;
+
+ /* The cache itself. */
+ struct dcache_block *the_cache;
+
+} DCACHE;
+
+/* Using the data cache DCACHE return the contents of the word at
+ address ADDR in the remote machine. */
+int dcache_fetch PARAMS((DCACHE *dcache, CORE_ADDR addr));
+
+/* Flush DCACHE. */
+void dcache_flush PARAMS((DCACHE *dcache));
+
+/* Initialize DCACHE. */
+DCACHE *dcache_init PARAMS((memxferfunc reading, memxferfunc writing));
+
+/* Write the word at ADDR both in the data cache and in the remote machine. */
+void dcache_poke PARAMS((DCACHE *dcache, CORE_ADDR addr, int data));
+
+#endif /* DCACHE_H */
diff --git a/gnu/usr.bin/gdb/gdb/defs.h b/gnu/usr.bin/gdb/gdb/defs.h
new file mode 100644
index 0000000..cb95cae
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/defs.h
@@ -0,0 +1,947 @@
+/* Basic, host-specific, and target-specific definitions for GDB.
+ Copyright (C) 1986, 1989, 1991 Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#if !defined (DEFS_H)
+#define DEFS_H 1
+
+#include <stdio.h>
+
+/* First include ansidecl.h so we can use the various macro definitions
+ here and in all subsequent file inclusions. */
+
+#include "ansidecl.h"
+
+/* For BFD64 and bfd_vma. */
+#include "bfd.h"
+
+/* An address in the program being debugged. Host byte order. Rather
+ than duplicate all the logic in BFD which figures out what type
+ this is (long, long long, etc.) and whether it needs to be 64
+ bits (the host/target interactions are subtle), we just use
+ bfd_vma. */
+
+typedef bfd_vma CORE_ADDR;
+
+#define min(a, b) ((a) < (b) ? (a) : (b))
+#define max(a, b) ((a) > (b) ? (a) : (b))
+
+/* Gdb does *lots* of string compares. Use macros to speed them up by
+ avoiding function calls if the first characters are not the same. */
+
+#define STRCMP(a,b) (*(a) == *(b) ? strcmp ((a), (b)) : (int)*(a) - (int)*(b))
+#define STREQ(a,b) (*(a) == *(b) ? !strcmp ((a), (b)) : 0)
+#define STREQN(a,b,c) (*(a) == *(b) ? !strncmp ((a), (b), (c)) : 0)
+
+/* The character GNU C++ uses to build identifiers that must be unique from
+ the program's identifiers (such as $this and $$vptr). */
+#define CPLUS_MARKER '$' /* May be overridden to '.' for SysV */
+
+#include <errno.h> /* System call error return status */
+
+extern int quit_flag;
+extern int immediate_quit;
+extern int sevenbit_strings;
+
+extern void
+quit PARAMS ((void));
+
+#define QUIT { if (quit_flag) quit (); }
+
+/* Command classes are top-level categories into which commands are broken
+ down for "help" purposes.
+ Notes on classes: class_alias is for alias commands which are not
+ abbreviations of the original command. class-pseudo is for commands
+ which are not really commands nor help topics ("stop"). */
+
+enum command_class
+{
+ /* Special args to help_list */
+ all_classes = -2, all_commands = -1,
+ /* Classes of commands */
+ no_class = -1, class_run = 0, class_vars, class_stack,
+ class_files, class_support, class_info, class_breakpoint,
+ class_alias, class_obscure, class_user, class_maintenance,
+ class_pseudo
+};
+
+/* Languages represented in the symbol table and elsewhere.
+ This should probably be in language.h, but since enum's can't
+ be forward declared to satisfy opaque references before their
+ actual definition, needs to be here. */
+
+enum language
+{
+ language_unknown, /* Language not known */
+ language_auto, /* Placeholder for automatic setting */
+ language_c, /* C */
+ language_cplus, /* C++ */
+ language_chill, /* Chill */
+ language_m2, /* Modula-2 */
+ language_asm /* Assembly language */
+};
+
+/* the cleanup list records things that have to be undone
+ if an error happens (descriptors to be closed, memory to be freed, etc.)
+ Each link in the chain records a function to call and an
+ argument to give it.
+
+ Use make_cleanup to add an element to the cleanup chain.
+ Use do_cleanups to do all cleanup actions back to a given
+ point in the chain. Use discard_cleanups to remove cleanups
+ from the chain back to a given point, not doing them. */
+
+struct cleanup
+{
+ struct cleanup *next;
+ void (*function) PARAMS ((PTR));
+ PTR arg;
+};
+
+/* From blockframe.c */
+
+extern int
+inside_entry_func PARAMS ((CORE_ADDR));
+
+extern int
+inside_entry_file PARAMS ((CORE_ADDR addr));
+
+extern int
+inside_main_func PARAMS ((CORE_ADDR pc));
+
+/* From ch-lang.c, for the moment. (FIXME) */
+
+extern char *
+chill_demangle PARAMS ((const char *));
+
+/* From libiberty.a */
+
+extern char *
+cplus_demangle PARAMS ((const char *, int));
+
+extern char *
+cplus_mangle_opname PARAMS ((char *, int));
+
+/* From libmmalloc.a (memory mapped malloc library) */
+
+extern PTR
+mmalloc_attach PARAMS ((int, PTR));
+
+extern PTR
+mmalloc_detach PARAMS ((PTR));
+
+extern PTR
+mmalloc PARAMS ((PTR, long));
+
+extern PTR
+mrealloc PARAMS ((PTR, PTR, long));
+
+extern void
+mfree PARAMS ((PTR, PTR));
+
+extern int
+mmalloc_setkey PARAMS ((PTR, int, PTR));
+
+extern PTR
+mmalloc_getkey PARAMS ((PTR, int));
+
+/* From utils.c */
+
+extern int
+strcmp_iw PARAMS ((const char *, const char *));
+
+extern char *
+safe_strerror PARAMS ((int));
+
+extern char *
+safe_strsignal PARAMS ((int));
+
+extern void
+init_malloc PARAMS ((void *));
+
+extern void
+request_quit PARAMS ((int));
+
+extern void
+do_cleanups PARAMS ((struct cleanup *));
+
+extern void
+discard_cleanups PARAMS ((struct cleanup *));
+
+/* The bare make_cleanup function is one of those rare beasts that
+ takes almost any type of function as the first arg and anything that
+ will fit in a "void *" as the second arg.
+
+ Should be, once all calls and called-functions are cleaned up:
+extern struct cleanup *
+make_cleanup PARAMS ((void (*function) (void *), void *));
+
+ Until then, lint and/or various type-checking compiler options will
+ complain about make_cleanup calls. It'd be wrong to just cast things,
+ since the type actually passed when the function is called would be
+ wrong. */
+
+extern struct cleanup *
+make_cleanup ();
+
+extern struct cleanup *
+save_cleanups PARAMS ((void));
+
+extern void
+restore_cleanups PARAMS ((struct cleanup *));
+
+extern void
+free_current_contents PARAMS ((char **));
+
+extern void
+null_cleanup PARAMS ((char **));
+
+extern int
+myread PARAMS ((int, char *, int));
+
+extern int
+query ();
+
+/* Annotation stuff. */
+
+extern int annotation_level; /* in stack.c */
+
+extern void
+begin_line PARAMS ((void));
+
+extern void
+wrap_here PARAMS ((char *));
+
+extern void
+reinitialize_more_filter PARAMS ((void));
+
+typedef FILE GDB_FILE;
+#define gdb_stdout stdout
+#define gdb_stderr stderr
+
+extern int
+print_insn PARAMS ((CORE_ADDR, GDB_FILE *));
+
+extern void
+gdb_flush PARAMS ((GDB_FILE *));
+
+extern GDB_FILE *
+gdb_fopen PARAMS ((char * name, char * mode));
+
+extern void
+fputs_filtered PARAMS ((const char *, GDB_FILE *));
+
+extern void
+fputs_unfiltered PARAMS ((const char *, GDB_FILE *));
+
+extern void
+fputc_unfiltered PARAMS ((int, GDB_FILE *));
+
+extern void
+putc_unfiltered PARAMS ((int));
+
+#define putchar_unfiltered(C) putc_unfiltered(C)
+
+extern void
+puts_filtered PARAMS ((char *));
+
+extern void
+puts_unfiltered PARAMS ((char *));
+
+extern void
+vprintf_filtered ();
+
+extern void
+vfprintf_filtered ();
+
+extern void
+fprintf_filtered ();
+
+extern void
+fprintfi_filtered ();
+
+extern void
+printf_filtered ();
+
+extern void
+printfi_filtered ();
+
+extern void
+vprintf_unfiltered ();
+
+extern void
+vfprintf_unfiltered ();
+
+extern void
+fprintf_unfiltered ();
+
+extern void
+printf_unfiltered ();
+
+extern void
+print_spaces PARAMS ((int, GDB_FILE *));
+
+extern void
+print_spaces_filtered PARAMS ((int, GDB_FILE *));
+
+extern char *
+n_spaces PARAMS ((int));
+
+extern void
+gdb_printchar PARAMS ((int, GDB_FILE *, int));
+
+/* Print a host address. */
+extern void gdb_print_address PARAMS ((void *, GDB_FILE *));
+
+extern void
+fprintf_symbol_filtered PARAMS ((GDB_FILE *, char *, enum language, int));
+
+extern void
+perror_with_name PARAMS ((char *));
+
+extern void
+print_sys_errmsg PARAMS ((char *, int));
+
+/* From regex.c or libc. BSD 4.4 declares this with the argument type as
+ "const char *" in unistd.h, so we can't declare the argument
+ as "char *". */
+
+extern char *
+re_comp PARAMS ((const char *));
+
+/* From symfile.c */
+
+extern void
+symbol_file_command PARAMS ((char *, int));
+
+/* From main.c */
+
+extern char *
+skip_quoted PARAMS ((char *));
+
+extern char *
+gdb_readline PARAMS ((char *));
+
+extern char *
+command_line_input PARAMS ((char *, int, char *));
+
+extern void
+print_prompt PARAMS ((void));
+
+extern int
+input_from_terminal_p PARAMS ((void));
+
+/* From printcmd.c */
+
+extern void
+set_next_address PARAMS ((CORE_ADDR));
+
+extern void
+print_address_symbolic PARAMS ((CORE_ADDR, GDB_FILE *, int, char *));
+
+extern void
+print_address_numeric PARAMS ((CORE_ADDR, int, GDB_FILE *));
+
+extern void
+print_address PARAMS ((CORE_ADDR, GDB_FILE *));
+
+/* From source.c */
+
+extern int
+openp PARAMS ((char *, int, char *, int, int, char **));
+
+extern void
+mod_path PARAMS ((char *, char **));
+
+extern void
+directory_command PARAMS ((char *, int));
+
+extern void
+init_source_path PARAMS ((void));
+
+/* From findvar.c */
+
+extern int
+read_relative_register_raw_bytes PARAMS ((int, char *));
+
+/* From readline (but not in any readline .h files). */
+
+extern char *
+tilde_expand PARAMS ((char *));
+
+/* Structure for saved commands lines
+ (for breakpoints, defined commands, etc). */
+
+struct command_line
+{
+ struct command_line *next;
+ char *line;
+};
+
+extern struct command_line *
+read_command_lines PARAMS ((void));
+
+extern void
+free_command_lines PARAMS ((struct command_line **));
+
+/* String containing the current directory (what getwd would return). */
+
+extern char *current_directory;
+
+/* Default radixes for input and output. Only some values supported. */
+extern unsigned input_radix;
+extern unsigned output_radix;
+
+/* Possibilities for prettyprint parameters to routines which print
+ things. Like enum language, this should be in value.h, but needs
+ to be here for the same reason. FIXME: If we can eliminate this
+ as an arg to LA_VAL_PRINT, then we can probably move it back to
+ value.h. */
+
+enum val_prettyprint
+{
+ Val_no_prettyprint = 0,
+ Val_prettyprint,
+ /* Use the default setting which the user has specified. */
+ Val_pretty_default
+};
+
+
+/* Host machine definition. This will be a symlink to one of the
+ xm-*.h files, built by the `configure' script. */
+
+#include "xm.h"
+
+/* Native machine support. This will be a symlink to one of the
+ nm-*.h files, built by the `configure' script. */
+
+#include "nm.h"
+
+#ifdef KERNEL_DEBUG
+extern int kernel_debugging;
+extern int kernel_writablecore;
+#endif
+
+/* If the xm.h file did not define the mode string used to open the
+ files, assume that binary files are opened the same way as text
+ files */
+#ifndef FOPEN_RB
+#include "fopen-same.h"
+#endif
+
+/*
+ * Allow things in gdb to be declared "const". If compiling ANSI, it
+ * just works. If compiling with gcc but non-ansi, redefine to __const__.
+ * If non-ansi, non-gcc, then eliminate "const" entirely, making those
+ * objects be read-write rather than read-only.
+ */
+
+#ifndef const
+#ifndef __STDC__
+# ifdef __GNUC__
+# define const __const__
+# else
+# define const /*nothing*/
+# endif /* GNUC */
+#endif /* STDC */
+#endif /* const */
+
+#ifndef volatile
+#ifndef __STDC__
+# ifdef __GNUC__
+# define volatile __volatile__
+# else
+# define volatile /*nothing*/
+# endif /* GNUC */
+#endif /* STDC */
+#endif /* volatile */
+
+#if 1
+#define NORETURN /*nothing*/
+#else /* not 1 */
+/* FIXME: This is bogus. Having "volatile void" mean a function doesn't
+ return is a gcc extension and should be based on #ifdef __GNUC__.
+ Also, as of Sep 93 I'm told gcc is changing the syntax for ansi
+ reasons (so declaring exit here as "volatile void" and as "void" in
+ a system header loses). Using the new "__attributes__ ((noreturn));"
+ syntax would lose for old versions of gcc; using
+ typedef void exit_fn_type PARAMS ((int));
+ volatile exit_fn_type exit;
+ would win. */
+/* Some compilers (many AT&T SVR4 compilers for instance), do not accept
+ declarations of functions that never return (exit for instance) as
+ "volatile void". For such compilers "NORETURN" can be defined away
+ to keep them happy */
+
+#ifndef NORETURN
+# ifdef __lucid
+# define NORETURN /*nothing*/
+# else
+# define NORETURN volatile
+# endif
+#endif
+#endif /* not 1 */
+
+/* Defaults for system-wide constants (if not defined by xm.h, we fake it). */
+
+#if !defined (UINT_MAX)
+#define UINT_MAX ((unsigned int)(~0)) /* 0xFFFFFFFF for 32-bits */
+#endif
+
+#if !defined (INT_MAX)
+#define INT_MAX ((int)(UINT_MAX >> 1)) /* 0x7FFFFFFF for 32-bits */
+#endif
+
+#if !defined (INT_MIN)
+#define INT_MIN (-INT_MAX - 1) /* 0x80000000 for 32-bits */
+#endif
+
+#if !defined (ULONG_MAX)
+#define ULONG_MAX ((unsigned long)(~0L)) /* 0xFFFFFFFF for 32-bits */
+#endif
+
+#if !defined (LONG_MAX)
+#define LONG_MAX ((long)(ULONG_MAX >> 1)) /* 0x7FFFFFFF for 32-bits */
+#endif
+
+#ifdef BFD64
+
+/* This is to make sure that LONGEST is at least as big as CORE_ADDR. */
+
+#define LONGEST BFD_HOST_64_BIT
+
+#else /* No BFD64 */
+
+/* If all compilers for this host support "long long" and we want to
+ use it for LONGEST (the performance hit is about 10% on a testsuite
+ run based on one DECstation test), then the xm.h file can define
+ CC_HAS_LONG_LONG.
+
+ Using GCC 1.39 on BSDI with long long causes about 700 new
+ testsuite failures. Using long long for LONGEST on the DECstation
+ causes 3 new FAILs in the testsuite and many heuristic fencepost
+ warnings. These are not investigated, but a first guess would be
+ that the BSDI problems are GCC bugs in long long support and the
+ latter are GDB bugs. */
+
+#ifndef CC_HAS_LONG_LONG
+# if defined (__GNUC__) && defined (FORCE_LONG_LONG)
+# define CC_HAS_LONG_LONG 1
+# endif
+#endif
+
+/* LONGEST should not be a typedef, because "unsigned LONGEST" needs to work.
+ CC_HAS_LONG_LONG is defined if the host compiler supports "long long"
+ variables and we wish to make use of that support. */
+
+#ifndef LONGEST
+# ifdef CC_HAS_LONG_LONG
+# define LONGEST long long
+# else
+# define LONGEST long
+# endif
+#endif
+
+#endif /* No BFD64 */
+
+/* Convert a LONGEST to an int. This is used in contexts (e.g. number of
+ arguments to a function, number in a value history, register number, etc.)
+ where the value must not be larger than can fit in an int. */
+
+extern int longest_to_int PARAMS ((LONGEST));
+
+/* Assorted functions we can declare, now that const and volatile are
+ defined. */
+
+extern char *
+savestring PARAMS ((const char *, int));
+
+extern char *
+msavestring PARAMS ((void *, const char *, int));
+
+extern char *
+strsave PARAMS ((const char *));
+
+extern char *
+mstrsave PARAMS ((void *, const char *));
+
+extern char *
+concat PARAMS ((char *, ...));
+
+extern PTR
+xmalloc PARAMS ((long));
+
+extern PTR
+xrealloc PARAMS ((PTR, long));
+
+extern PTR
+xmmalloc PARAMS ((PTR, long));
+
+extern PTR
+xmrealloc PARAMS ((PTR, PTR, long));
+
+extern PTR
+mmalloc PARAMS ((PTR, long));
+
+extern PTR
+mrealloc PARAMS ((PTR, PTR, long));
+
+extern void
+mfree PARAMS ((PTR, PTR));
+
+extern int
+mmcheck PARAMS ((PTR, void (*) (void)));
+
+extern int
+mmtrace PARAMS ((void));
+
+extern int
+parse_escape PARAMS ((char **));
+
+extern const char * const reg_names[];
+
+/* Message to be printed before the error message, when an error occurs. */
+
+extern char *error_pre_print;
+
+/* Message to be printed before the warning message, when a warning occurs. */
+
+extern char *warning_pre_print;
+
+extern NORETURN void /* Does not return to the caller. */
+error ();
+
+extern void error_begin PARAMS ((void));
+
+extern NORETURN void /* Does not return to the caller. */
+fatal ();
+
+extern NORETURN void /* Not specified as volatile in ... */
+exit PARAMS ((int)); /* 4.10.4.3 */
+
+extern NORETURN void /* Does not return to the caller. */
+nomem PARAMS ((long));
+
+/* Reasons for calling return_to_top_level. */
+enum return_reason {
+ /* User interrupt. */
+ RETURN_QUIT,
+
+ /* Any other error. */
+ RETURN_ERROR
+};
+
+#define RETURN_MASK_QUIT (1 << (int)RETURN_QUIT)
+#define RETURN_MASK_ERROR (1 << (int)RETURN_ERROR)
+#define RETURN_MASK_ALL (RETURN_MASK_QUIT | RETURN_MASK_ERROR)
+typedef int return_mask;
+
+extern NORETURN void /* Does not return to the caller. */
+return_to_top_level PARAMS ((enum return_reason));
+
+extern int catch_errors PARAMS ((int (*) (char *), void *, char *,
+ return_mask));
+
+extern void
+warning_setup PARAMS ((void));
+
+extern void
+warning ();
+
+/* Global functions from other, non-gdb GNU thingies (libiberty for
+ instance) */
+
+extern char *
+basename PARAMS ((char *));
+
+extern char *
+getenv PARAMS ((const char *));
+
+extern char **
+buildargv PARAMS ((char *));
+
+extern void
+freeargv PARAMS ((char **));
+
+extern char *
+strerrno PARAMS ((int));
+
+extern char *
+strsigno PARAMS ((int));
+
+extern int
+errno_max PARAMS ((void));
+
+extern int
+signo_max PARAMS ((void));
+
+extern int
+strtoerrno PARAMS ((char *));
+
+extern int
+strtosigno PARAMS ((char *));
+
+extern char *
+strsignal PARAMS ((int));
+
+/* From other system libraries */
+
+#ifndef PSIGNAL_IN_SIGNAL_H
+extern void
+psignal PARAMS ((unsigned, const char *));
+#endif
+
+/* For now, we can't include <stdlib.h> because it conflicts with
+ "../include/getopt.h". (FIXME)
+
+ However, if a function is defined in the ANSI C standard and a prototype
+ for that function is defined and visible in any header file in an ANSI
+ conforming environment, then that prototype must match the definition in
+ the ANSI standard. So we can just duplicate them here without conflict,
+ since they must be the same in all conforming ANSI environments. If
+ these cause problems, then the environment is not ANSI conformant. */
+
+#ifdef __STDC__
+#include <stddef.h>
+#endif
+
+extern int
+fclose PARAMS ((GDB_FILE *stream)); /* 4.9.5.1 */
+
+extern void
+perror PARAMS ((const char *)); /* 4.9.10.4 */
+
+extern double
+atof PARAMS ((const char *nptr)); /* 4.10.1.1 */
+
+extern int
+atoi PARAMS ((const char *)); /* 4.10.1.2 */
+
+#ifndef MALLOC_INCOMPATIBLE
+
+extern PTR
+malloc PARAMS ((size_t size)); /* 4.10.3.3 */
+
+extern PTR
+realloc PARAMS ((void *ptr, size_t size)); /* 4.10.3.4 */
+
+extern void
+free PARAMS ((void *)); /* 4.10.3.2 */
+
+#endif /* MALLOC_INCOMPATIBLE */
+
+extern void
+qsort PARAMS ((void *base, size_t nmemb, /* 4.10.5.2 */
+ size_t size,
+ int (*compar)(const void *, const void *)));
+
+#ifndef MEM_FNS_DECLARED /* Some non-ANSI use void *, not char *. */
+extern PTR
+memcpy PARAMS ((void *, const void *, size_t)); /* 4.11.2.1 */
+
+extern int
+memcmp PARAMS ((const void *, const void *, size_t)); /* 4.11.4.1 */
+#endif
+
+extern char *
+strchr PARAMS ((const char *, int)); /* 4.11.5.2 */
+
+extern char *
+strrchr PARAMS ((const char *, int)); /* 4.11.5.5 */
+
+extern char *
+strstr PARAMS ((const char *, const char *)); /* 4.11.5.7 */
+
+extern char *
+strtok PARAMS ((char *, const char *)); /* 4.11.5.8 */
+
+#ifndef MEM_FNS_DECLARED /* Some non-ANSI use void *, not char *. */
+extern PTR
+memset PARAMS ((void *, int, size_t)); /* 4.11.6.1 */
+#endif
+
+extern char *
+strerror PARAMS ((int)); /* 4.11.6.2 */
+
+/* Various possibilities for alloca. */
+#ifndef alloca
+# ifdef __GNUC__
+# define alloca __builtin_alloca
+# else /* Not GNU C */
+# ifdef sparc
+# include <alloca.h> /* NOTE: Doesn't declare alloca() */
+# endif
+
+/* We need to be careful not to declare this in a way which conflicts with
+ bison. Bison never declares it as char *, but under various circumstances
+ (like __hpux) we need to use void *. */
+# if defined (__STDC__) || defined (__hpux)
+ extern void *alloca ();
+# else /* Don't use void *. */
+ extern char *alloca ();
+# endif /* Don't use void *. */
+# endif /* Not GNU C */
+#endif /* alloca not defined */
+
+/* TARGET_BYTE_ORDER and HOST_BYTE_ORDER must be defined to one of these. */
+
+#if !defined (BIG_ENDIAN)
+#define BIG_ENDIAN 4321
+#endif
+
+#if !defined (LITTLE_ENDIAN)
+#define LITTLE_ENDIAN 1234
+#endif
+
+/* Target-system-dependent parameters for GDB. */
+
+/* Target machine definition. This will be a symlink to one of the
+ tm-*.h files, built by the `configure' script. */
+
+#include "tm.h"
+
+/* Number of bits in a char or unsigned char for the target machine.
+ Just like CHAR_BIT in <limits.h> but describes the target machine. */
+#if !defined (TARGET_CHAR_BIT)
+#define TARGET_CHAR_BIT 8
+#endif
+
+/* Number of bits in a short or unsigned short for the target machine. */
+#if !defined (TARGET_SHORT_BIT)
+#define TARGET_SHORT_BIT (2 * TARGET_CHAR_BIT)
+#endif
+
+/* Number of bits in an int or unsigned int for the target machine. */
+#if !defined (TARGET_INT_BIT)
+#define TARGET_INT_BIT (4 * TARGET_CHAR_BIT)
+#endif
+
+/* Number of bits in a long or unsigned long for the target machine. */
+#if !defined (TARGET_LONG_BIT)
+#define TARGET_LONG_BIT (4 * TARGET_CHAR_BIT)
+#endif
+
+/* Number of bits in a long long or unsigned long long for the target machine. */
+#if !defined (TARGET_LONG_LONG_BIT)
+#define TARGET_LONG_LONG_BIT (2 * TARGET_LONG_BIT)
+#endif
+
+/* Number of bits in a float for the target machine. */
+#if !defined (TARGET_FLOAT_BIT)
+#define TARGET_FLOAT_BIT (4 * TARGET_CHAR_BIT)
+#endif
+
+/* Number of bits in a double for the target machine. */
+#if !defined (TARGET_DOUBLE_BIT)
+#define TARGET_DOUBLE_BIT (8 * TARGET_CHAR_BIT)
+#endif
+
+/* Number of bits in a long double for the target machine. */
+#if !defined (TARGET_LONG_DOUBLE_BIT)
+#define TARGET_LONG_DOUBLE_BIT (2 * TARGET_DOUBLE_BIT)
+#endif
+
+/* Number of bits in a "complex" for the target machine. */
+#if !defined (TARGET_COMPLEX_BIT)
+#define TARGET_COMPLEX_BIT (2 * TARGET_FLOAT_BIT)
+#endif
+
+/* Number of bits in a "double complex" for the target machine. */
+#if !defined (TARGET_DOUBLE_COMPLEX_BIT)
+#define TARGET_DOUBLE_COMPLEX_BIT (2 * TARGET_DOUBLE_BIT)
+#endif
+
+/* Number of bits in a pointer for the target machine */
+#if !defined (TARGET_PTR_BIT)
+#define TARGET_PTR_BIT TARGET_INT_BIT
+#endif
+
+/* If we picked up a copy of CHAR_BIT from a configuration file
+ (which may get it by including <limits.h>) then use it to set
+ the number of bits in a host char. If not, use the same size
+ as the target. */
+
+#if defined (CHAR_BIT)
+#define HOST_CHAR_BIT CHAR_BIT
+#else
+#define HOST_CHAR_BIT TARGET_CHAR_BIT
+#endif
+
+/* The bit byte-order has to do just with numbering of bits in
+ debugging symbols and such. Conceptually, it's quite separate
+ from byte/word byte order. */
+
+#if !defined (BITS_BIG_ENDIAN)
+#if TARGET_BYTE_ORDER == BIG_ENDIAN
+#define BITS_BIG_ENDIAN 1
+#endif /* Big endian. */
+
+#if TARGET_BYTE_ORDER == LITTLE_ENDIAN
+#define BITS_BIG_ENDIAN 0
+#endif /* Little endian. */
+#endif /* BITS_BIG_ENDIAN not defined. */
+
+/* In findvar.c. */
+LONGEST extract_signed_integer PARAMS ((void *, int));
+unsigned LONGEST extract_unsigned_integer PARAMS ((void *, int));
+CORE_ADDR extract_address PARAMS ((void *, int));
+
+void store_signed_integer PARAMS ((void *, int, LONGEST));
+void store_unsigned_integer PARAMS ((void *, int, unsigned LONGEST));
+void store_address PARAMS ((void *, int, CORE_ADDR));
+
+double extract_floating PARAMS ((void *, int));
+void store_floating PARAMS ((void *, int, double));
+
+/* On some machines there are bits in addresses which are not really
+ part of the address, but are used by the kernel, the hardware, etc.
+ for special purposes. ADDR_BITS_REMOVE takes out any such bits
+ so we get a "real" address such as one would find in a symbol
+ table. This is used only for addresses of instructions, and even then
+ I'm not sure it's used in all contexts. It exists to deal with there
+ being a few stray bits in the PC which would mislead us, not as some sort
+ of generic thing to handle alignment or segmentation (it's possible it
+ should be in TARGET_READ_PC instead). */
+#if !defined (ADDR_BITS_REMOVE)
+#define ADDR_BITS_REMOVE(addr) (addr)
+#endif /* No ADDR_BITS_REMOVE. */
+
+/* From valops.c */
+
+extern CORE_ADDR
+push_bytes PARAMS ((CORE_ADDR, char *, int));
+
+extern CORE_ADDR
+push_word PARAMS ((CORE_ADDR, unsigned LONGEST));
+
+/* Some parts of gdb might be considered optional, in the sense that they
+ are not essential for being able to build a working, usable debugger
+ for a specific environment. For example, the maintenance commands
+ are there for the benefit of gdb maintainers. As another example,
+ some environments really don't need gdb's that are able to read N
+ different object file formats. In order to make it possible (but
+ not necessarily recommended) to build "stripped down" versions of
+ gdb, the following defines control selective compilation of those
+ parts of gdb which can be safely left out when necessary. Note that
+ the default is to include everything. */
+
+#ifndef MAINTENANCE_CMDS
+#define MAINTENANCE_CMDS 1
+#endif
+
+#endif /* !defined (DEFS_H) */
diff --git a/gnu/usr.bin/gdb/gdb/demangle.c b/gnu/usr.bin/gdb/gdb/demangle.c
new file mode 100644
index 0000000..e4cc996
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/demangle.c
@@ -0,0 +1,181 @@
+/* Basic C++ demangling support for GDB.
+ Copyright 1991, 1992 Free Software Foundation, Inc.
+ Written by Fred Fish at Cygnus Support.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+
+/* This file contains support code for C++ demangling that is common
+ to a styles of demangling, and GDB specific. */
+
+#include "defs.h"
+#include "command.h"
+#include "gdbcmd.h"
+#include "demangle.h"
+#include <string.h>
+
+/* Select the default C++ demangling style to use. The default is "auto",
+ which allows gdb to attempt to pick an appropriate demangling style for
+ the executable it has loaded. It can be set to a specific style ("gnu",
+ "lucid", "arm", etc.) in which case gdb will never attempt to do auto
+ selection of the style unless you do an explicit "set demangle auto".
+ To select one of these as the default, set DEFAULT_DEMANGLING_STYLE in
+ the appropriate target configuration file. */
+
+#ifndef DEFAULT_DEMANGLING_STYLE
+# define DEFAULT_DEMANGLING_STYLE AUTO_DEMANGLING_STYLE_STRING
+#endif
+
+/* String name for the current demangling style. Set by the "set demangling"
+ command, printed as part of the output by the "show demangling" command. */
+
+static char *current_demangling_style_string;
+
+/* List of supported demangling styles. Contains the name of the style as
+ seen by the user, and the enum value that corresponds to that style. */
+
+static const struct demangler
+{
+ char *demangling_style_name;
+ enum demangling_styles demangling_style;
+ char *demangling_style_doc;
+} demanglers [] =
+{
+ {AUTO_DEMANGLING_STYLE_STRING,
+ auto_demangling,
+ "Automatic selection based on executable"},
+ {GNU_DEMANGLING_STYLE_STRING,
+ gnu_demangling,
+ "GNU (g++) style demangling"},
+ {LUCID_DEMANGLING_STYLE_STRING,
+ lucid_demangling,
+ "Lucid (lcc) style demangling"},
+ {ARM_DEMANGLING_STYLE_STRING,
+ arm_demangling,
+ "ARM style demangling"},
+ {NULL, unknown_demangling, NULL}
+};
+
+/* set current demangling style. called by the "set demangling" command
+ after it has updated the current_demangling_style_string to match
+ what the user has entered.
+
+ if the user has entered a string that matches a known demangling style
+ name in the demanglers[] array then just leave the string alone and update
+ the current_demangling_style enum value to match.
+
+ if the user has entered a string that doesn't match, including an empty
+ string, then print a list of the currently known styles and restore
+ the current_demangling_style_string to match the current_demangling_style
+ enum value.
+
+ Note: Assumes that current_demangling_style_string always points to
+ a malloc'd string, even if it is a null-string. */
+
+static void
+set_demangling_command (ignore, from_tty, c)
+ char *ignore;
+ int from_tty;
+ struct cmd_list_element *c;
+{
+ const struct demangler *dem;
+
+ /* First just try to match whatever style name the user supplied with
+ one of the known ones. Don't bother special casing for an empty
+ name, we just treat it as any other style name that doesn't match.
+ If we match, update the current demangling style enum. */
+
+ for (dem = demanglers; dem -> demangling_style_name != NULL; dem++)
+ {
+ if (STREQ (current_demangling_style_string,
+ dem -> demangling_style_name))
+ {
+ current_demangling_style = dem -> demangling_style;
+ break;
+ }
+ }
+
+ /* Check to see if we found a match. If not, gripe about any non-empty
+ style name and supply a list of valid ones. FIXME: This should
+ probably be done with some sort of completion and with help. */
+
+ if (dem -> demangling_style_name == NULL)
+ {
+ if (*current_demangling_style_string != '\0')
+ {
+ printf_unfiltered ("Unknown demangling style `%s'.\n",
+ current_demangling_style_string);
+ }
+ printf_unfiltered ("The currently understood settings are:\n\n");
+ for (dem = demanglers; dem -> demangling_style_name != NULL; dem++)
+ {
+ printf_unfiltered ("%-10s %s\n", dem -> demangling_style_name,
+ dem -> demangling_style_doc);
+ if (dem -> demangling_style == current_demangling_style)
+ {
+ free (current_demangling_style_string);
+ current_demangling_style_string =
+ savestring (dem -> demangling_style_name,
+ strlen (dem -> demangling_style_name));
+ }
+ }
+ if (current_demangling_style == unknown_demangling)
+ {
+ /* This can happen during initialization if gdb is compiled with
+ a DEMANGLING_STYLE value that is unknown, so pick the first
+ one as the default. */
+ current_demangling_style = demanglers[0].demangling_style;
+ current_demangling_style_string =
+ savestring (demanglers[0].demangling_style_name,
+ strlen (demanglers[0].demangling_style_name));
+ warning ("`%s' style demangling chosen as the default.\n",
+ current_demangling_style_string);
+ }
+ }
+}
+
+/* Fake a "set demangling" command. */
+
+void
+set_demangling_style (style)
+ char *style;
+{
+ if (current_demangling_style_string != NULL)
+ {
+ free (current_demangling_style_string);
+ }
+ current_demangling_style_string = savestring (style, strlen (style));
+ set_demangling_command ((char *) NULL, 0);
+}
+
+void
+_initialize_demangler ()
+{
+ struct cmd_list_element *set, *show;
+
+ set = add_set_cmd ("demangle-style", class_support, var_string_noescape,
+ (char *) &current_demangling_style_string,
+ "Set the current C++ demangling style.\n\
+Use `set demangle-style' without arguments for a list of demangling styles.",
+ &setlist);
+ show = add_show_from_set (set, &showlist);
+ set -> function.sfunc = set_demangling_command;
+
+ /* Set the default demangling style chosen at compilation time. */
+ set_demangling_style (DEFAULT_DEMANGLING_STYLE);
+ set_cplus_marker_for_demangling (CPLUS_MARKER);
+}
diff --git a/gnu/usr.bin/gdb/gdb/demangle.h b/gnu/usr.bin/gdb/gdb/demangle.h
new file mode 100644
index 0000000..7fee623
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/demangle.h
@@ -0,0 +1,80 @@
+/* Defs for interface to demanglers.
+ Copyright 1992 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+
+#if !defined (DEMANGLE_H)
+#define DEMANGLE_H
+
+#include <ansidecl.h>
+
+/* Options passed to cplus_demangle (in 2nd parameter). */
+
+#define DMGL_NO_OPTS 0 /* For readability... */
+#define DMGL_PARAMS (1 << 0) /* Include function args */
+#define DMGL_ANSI (1 << 1) /* Include const, volatile, etc */
+
+#define DMGL_AUTO (1 << 8)
+#define DMGL_GNU (1 << 9)
+#define DMGL_LUCID (1 << 10)
+#define DMGL_ARM (1 << 11)
+/* If none of these are set, use 'current_demangling_style' as the default. */
+#define DMGL_STYLE_MASK (DMGL_AUTO|DMGL_GNU|DMGL_LUCID|DMGL_ARM)
+
+/* Enumeration of possible demangling styles.
+
+ Lucid and ARM styles are still kept logically distinct, even though
+ they now both behave identically. The resulting style is actual the
+ union of both. I.E. either style recognizes both "__pt__" and "__rf__"
+ for operator "->", even though the first is lucid style and the second
+ is ARM style. (FIXME?) */
+
+extern enum demangling_styles
+{
+ unknown_demangling = 0,
+ auto_demangling = DMGL_AUTO,
+ gnu_demangling = DMGL_GNU,
+ lucid_demangling = DMGL_LUCID,
+ arm_demangling = DMGL_ARM
+} current_demangling_style;
+
+/* Define string names for the various demangling styles. */
+
+#define AUTO_DEMANGLING_STYLE_STRING "auto"
+#define GNU_DEMANGLING_STYLE_STRING "gnu"
+#define LUCID_DEMANGLING_STYLE_STRING "lucid"
+#define ARM_DEMANGLING_STYLE_STRING "arm"
+
+/* Some macros to test what demangling style is active. */
+
+#define CURRENT_DEMANGLING_STYLE current_demangling_style
+#define AUTO_DEMANGLING (((int) CURRENT_DEMANGLING_STYLE) & DMGL_AUTO)
+#define GNU_DEMANGLING (((int) CURRENT_DEMANGLING_STYLE) & DMGL_GNU)
+#define LUCID_DEMANGLING (((int) CURRENT_DEMANGLING_STYLE) & DMGL_LUCID)
+#define ARM_DEMANGLING (CURRENT_DEMANGLING_STYLE & DMGL_ARM)
+
+extern char *
+cplus_demangle PARAMS ((CONST char *mangled, int options));
+
+extern int
+cplus_demangle_opname PARAMS ((char *opname, char *result, int options));
+
+/* Note: This sets global state. FIXME if you care about multi-threading. */
+
+extern void
+set_cplus_marker_for_demangling PARAMS ((int ch));
+
+#endif /* DEMANGLE_H */
diff --git a/gnu/usr.bin/gdb/gdb/dis-asm.h b/gnu/usr.bin/gdb/gdb/dis-asm.h
new file mode 100644
index 0000000..fde2059
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/dis-asm.h
@@ -0,0 +1,179 @@
+/* Interface between the opcode library and its callers.
+ Written by Cygnus Support, 1993.
+
+ The opcode library (libopcodes.a) provides instruction decoders for
+ a large variety of instruction sets, callable with an identical
+ interface, for making instruction-processing programs more independent
+ of the instruction set being processed. */
+
+#include <stdio.h>
+#include "bfd.h"
+
+typedef int (*fprintf_ftype) PARAMS((FILE*, const char*, ...));
+
+enum dis_insn_type {
+ dis_noninsn, /* Not a valid instruction */
+ dis_nonbranch, /* Not a branch instruction */
+ dis_branch, /* Unconditional branch */
+ dis_condbranch, /* Conditional branch */
+ dis_jsr, /* Jump to subroutine */
+ dis_condjsr, /* Conditional jump to subroutine */
+ dis_dref, /* Data reference instruction */
+ dis_dref2 /* Two data references in instruction */
+};
+
+/* This struct is passed into the instruction decoding routine,
+ and is passed back out into each callback. The various fields are used
+ for conveying information from your main routine into your callbacks,
+ for passing information into the instruction decoders (such as the
+ addresses of the callback functions), or for passing information
+ back from the instruction decoders to their callers.
+
+ It must be initialized before it is first passed; this can be done
+ by hand, or using one of the initialization macros below. */
+
+typedef struct disassemble_info {
+ fprintf_ftype fprintf_func;
+ FILE *stream;
+ PTR application_data;
+
+ /* For use by the disassembler. */
+ int flags;
+ PTR private_data;
+
+ /* Function used to get bytes to disassemble. MEMADDR is the
+ address of the stuff to be disassembled, MYADDR is the address to
+ put the bytes in, and LENGTH is the number of bytes to read.
+ INFO is a pointer to this struct.
+ Returns an errno value or 0 for success. */
+ int (*read_memory_func)
+ PARAMS ((bfd_vma memaddr, bfd_byte *myaddr, int length,
+ struct disassemble_info *info));
+
+ /* Function which should be called if we get an error that we can't
+ recover from. STATUS is the errno value from read_memory_func and
+ MEMADDR is the address that we were trying to read. INFO is a
+ pointer to this struct. */
+ void (*memory_error_func)
+ PARAMS ((int status, bfd_vma memaddr, struct disassemble_info *info));
+
+ /* Function called to print ADDR. */
+ void (*print_address_func)
+ PARAMS ((bfd_vma addr, struct disassemble_info *info));
+
+ /* These are for buffer_read_memory. */
+ bfd_byte *buffer;
+ bfd_vma buffer_vma;
+ int buffer_length;
+
+ /* Results from instruction decoders. Not all decoders yet support
+ this information. This info is set each time an instruction is
+ decoded, and is only valid for the last such instruction.
+
+ To determine whether this decoder supports this information, set
+ insn_info_valid to 0, decode an instruction, then check it. */
+
+ char insn_info_valid; /* Branch info has been set. */
+ char branch_delay_insns; /* How many sequential insn's will run before
+ a branch takes effect. (0 = normal) */
+ char data_size; /* Size of data reference in insn, in bytes */
+ enum dis_insn_type insn_type; /* Type of instruction */
+ bfd_vma target; /* Target address of branch or dref, if known;
+ zero if unknown. */
+ bfd_vma target2; /* Second target address for dref2 */
+
+} disassemble_info;
+
+
+
+
+
+
+/* Standard disassemblers. Disassemble one instruction at the given
+ target address. Return number of bytes processed. */
+typedef int (*disassembler_ftype)
+ PARAMS((bfd_vma, disassemble_info *));
+
+extern int print_insn_big_mips PARAMS ((bfd_vma, disassemble_info*));
+extern int print_insn_little_mips PARAMS ((bfd_vma, disassemble_info*));
+extern int print_insn_i386 PARAMS ((bfd_vma, disassemble_info*));
+extern int print_insn_m68k PARAMS ((bfd_vma, disassemble_info*));
+extern int print_insn_z8001 PARAMS ((bfd_vma, disassemble_info*));
+extern int print_insn_z8002 PARAMS ((bfd_vma, disassemble_info*));
+extern int print_insn_h8300 PARAMS ((bfd_vma, disassemble_info*));
+extern int print_insn_h8300h PARAMS ((bfd_vma, disassemble_info*));
+extern int print_insn_h8500 PARAMS ((bfd_vma, disassemble_info*));
+extern int print_insn_alpha PARAMS ((bfd_vma, disassemble_info*));
+extern int print_insn_sparc PARAMS ((bfd_vma, disassemble_info*));
+extern int print_insn_big_a29k PARAMS ((bfd_vma, disassemble_info*));
+extern int print_insn_little_a29k PARAMS ((bfd_vma, disassemble_info*));
+extern int print_insn_i960 PARAMS ((bfd_vma, disassemble_info*));
+extern int print_insn_sh PARAMS ((bfd_vma, disassemble_info*));
+extern int print_insn_hppa PARAMS ((bfd_vma, disassemble_info*));
+extern int print_insn_m88k PARAMS ((bfd_vma, disassemble_info*));
+extern int print_insn_ns32k PARAMS ((bfd_vma, disassemble_info*));
+extern int print_insn_big_powerpc PARAMS ((bfd_vma, disassemble_info*));
+extern int print_insn_little_powerpc PARAMS ((bfd_vma, disassemble_info*));
+extern int print_insn_rs6000 PARAMS ((bfd_vma, disassemble_info*));
+
+/* Fetch the disassembler for a given BFD, if that support is available. */
+extern disassembler_ftype disassembler PARAMS ((bfd *));
+
+
+/* This block of definitions is for particular callers who read instructions
+ into a buffer before calling the instruction decoder. */
+
+/* Here is a function which callers may wish to use for read_memory_func.
+ It gets bytes from a buffer. */
+extern int buffer_read_memory
+ PARAMS ((bfd_vma, bfd_byte *, int, struct disassemble_info *));
+
+/* This function goes with buffer_read_memory.
+ It prints a message using info->fprintf_func and info->stream. */
+extern void perror_memory PARAMS ((int, bfd_vma, struct disassemble_info *));
+
+
+/* Just print the address is hex. This is included for completeness even
+ though both GDB and objdump provide their own (to print symbolic
+ addresses). */
+extern void generic_print_address
+ PARAMS ((bfd_vma, struct disassemble_info *));
+
+#define INIT_DISASSEMBLE_INFO(INFO, STREAM) \
+ (INFO).fprintf_func = (fprintf_ftype)fprintf, \
+ (INFO).stream = (STREAM), \
+ (INFO).buffer = NULL, \
+ (INFO).buffer_vma = 0, \
+ (INFO).buffer_length = 0, \
+ (INFO).read_memory_func = buffer_read_memory, \
+ (INFO).memory_error_func = perror_memory, \
+ (INFO).print_address_func = generic_print_address, \
+ (INFO).insn_info_valid = 0
+
+
+
+
+/* This block of definitions is for calling the instruction decoders
+ from GDB. */
+
+/* GDB--Like target_read_memory, but slightly different parameters. */
+extern int
+dis_asm_read_memory PARAMS ((bfd_vma memaddr, bfd_byte *myaddr, int len,
+ disassemble_info *info));
+
+/* GDB--Like memory_error with slightly different parameters. */
+extern void
+dis_asm_memory_error
+ PARAMS ((int status, bfd_vma memaddr, disassemble_info *info));
+
+/* GDB--Like print_address with slightly different parameters. */
+extern void
+dis_asm_print_address PARAMS ((bfd_vma addr, disassemble_info *info));
+
+#define GDB_INIT_DISASSEMBLE_INFO(INFO, STREAM) \
+ (INFO).fprintf_func = (fprintf_ftype)fprintf_filtered, \
+ (INFO).stream = (STREAM), \
+ (INFO).read_memory_func = dis_asm_read_memory, \
+ (INFO).memory_error_func = dis_asm_memory_error, \
+ (INFO).print_address_func = dis_asm_print_address, \
+ (INFO).insn_info_valid = 0
diff --git a/gnu/usr.bin/gdb/gdb/dis-buf.c b/gnu/usr.bin/gdb/gdb/dis-buf.c
new file mode 100644
index 0000000..d184b28
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/dis-buf.c
@@ -0,0 +1,70 @@
+/* Disassemble from a buffer, for GNU.
+ Copyright (C) 1993, 1994 Free Software Foundation, Inc.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "dis-asm.h"
+#include "sysdep.h"
+#include <errno.h>
+
+/* Get LENGTH bytes from info's buffer, at target address memaddr.
+ Transfer them to myaddr. */
+int
+buffer_read_memory (memaddr, myaddr, length, info)
+ bfd_vma memaddr;
+ bfd_byte *myaddr;
+ int length;
+ struct disassemble_info *info;
+{
+ if (memaddr < info->buffer_vma
+ || memaddr + length > info->buffer_vma + info->buffer_length)
+ /* Out of bounds. Use EIO because GDB uses it. */
+ return EIO;
+ memcpy (myaddr, info->buffer + (memaddr - info->buffer_vma), length);
+ return 0;
+}
+
+/* Print an error message. We can assume that this is in response to
+ an error return from buffer_read_memory. */
+void
+perror_memory (status, memaddr, info)
+ int status;
+ bfd_vma memaddr;
+ struct disassemble_info *info;
+{
+ if (status != EIO)
+ /* Can't happen. */
+ (*info->fprintf_func) (info->stream, "Unknown error %d\n", status);
+ else
+ /* Actually, address between memaddr and memaddr + len was
+ out of bounds. */
+ (*info->fprintf_func) (info->stream,
+ "Address 0x%x is out of bounds.\n", memaddr);
+}
+
+/* This could be in a separate file, to save miniscule amounts of space
+ in statically linked executables. */
+
+/* Just print the address is hex. This is included for completeness even
+ though both GDB and objdump provide their own (to print symbolic
+ addresses). */
+
+void
+generic_print_address (addr, info)
+ bfd_vma addr;
+ struct disassemble_info *info;
+{
+ (*info->fprintf_func) (info->stream, "0x%x", addr);
+}
diff --git a/gnu/usr.bin/gdb/gdb/disassemble.c b/gnu/usr.bin/gdb/gdb/disassemble.c
new file mode 100644
index 0000000..fe66107
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/disassemble.c
@@ -0,0 +1,148 @@
+/* Select disassembly routine for specified architecture.
+ Copyright 1994 Free Software Foundation, Inc.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "ansidecl.h"
+#include "dis-asm.h"
+
+#ifdef ARCH_all
+#define ARCH_a29k
+#define ARCH_alpha
+#define ARCH_h8300
+#define ARCH_h8500
+#define ARCH_hppa
+#define ARCH_i386
+#define ARCH_i960
+#define ARCH_m68k
+#define ARCH_m88k
+#define ARCH_mips
+#define ARCH_ns32k
+#define ARCH_powerpc
+#define ARCH_rs6000
+#define ARCH_sh
+#define ARCH_sparc
+#define ARCH_z8k
+#endif
+
+disassembler_ftype
+disassembler (abfd)
+ bfd *abfd;
+{
+ enum bfd_architecture a = bfd_get_arch (abfd);
+ disassembler_ftype disassemble;
+
+ switch (a)
+ {
+ /* If you add a case to this table, also add it to the
+ ARCH_all definition right above this function. */
+#ifdef ARCH_a29k
+ case bfd_arch_a29k:
+ /* As far as I know we only handle big-endian 29k objects. */
+ disassemble = print_insn_big_a29k;
+ break;
+#endif
+#ifdef ARCH_alpha
+ case bfd_arch_alpha:
+ disassemble = print_insn_alpha;
+ break;
+#endif
+#ifdef ARCH_h8300
+ case bfd_arch_h8300:
+ if (bfd_get_mach(abfd) == bfd_mach_h8300h)
+ disassemble = print_insn_h8300h;
+ else
+ disassemble = print_insn_h8300;
+ break;
+#endif
+#ifdef ARCH_h8500
+ case bfd_arch_h8500:
+ disassemble = print_insn_h8500;
+ break;
+#endif
+#ifdef ARCH_hppa
+ case bfd_arch_hppa:
+ disassemble = print_insn_hppa;
+ break;
+#endif
+#ifdef ARCH_i386
+ case bfd_arch_i386:
+ disassemble = print_insn_i386;
+ break;
+#endif
+#ifdef ARCH_i960
+ case bfd_arch_i960:
+ disassemble = print_insn_i960;
+ break;
+#endif
+#ifdef ARCH_m68k
+ case bfd_arch_m68k:
+ disassemble = print_insn_m68k;
+ break;
+#endif
+#ifdef ARCH_m88k
+ case bfd_arch_m88k:
+ disassemble = print_insn_m88k;
+ break;
+#endif
+#ifdef ARCH_ns32k
+ case bfd_arch_ns32k:
+ disassemble = print_insn_ns32k;
+ break;
+#endif
+#ifdef ARCH_mips
+ case bfd_arch_mips:
+ if (abfd->xvec->byteorder_big_p)
+ disassemble = print_insn_big_mips;
+ else
+ disassemble = print_insn_little_mips;
+ break;
+#endif
+#ifdef ARCH_powerpc
+ case bfd_arch_powerpc:
+ if (abfd->xvec->byteorder_big_p)
+ disassemble = print_insn_big_powerpc;
+ else
+ disassemble = print_insn_little_powerpc;
+ break;
+#endif
+#ifdef ARCH_rs6000
+ case bfd_arch_rs6000:
+ disassemble = print_insn_rs6000;
+ break;
+#endif
+#ifdef ARCH_sh
+ case bfd_arch_sh:
+ disassemble = print_insn_sh;
+ break;
+#endif
+#ifdef ARCH_sparc
+ case bfd_arch_sparc:
+ disassemble = print_insn_sparc;
+ break;
+#endif
+#ifdef ARCH_z8k
+ case bfd_arch_z8k:
+ if (bfd_get_mach(abfd) == bfd_mach_z8001)
+ disassemble = print_insn_z8001;
+ else
+ disassemble = print_insn_z8002;
+ break;
+#endif
+ default:
+ return 0;
+ }
+ return disassemble;
+}
diff --git a/gnu/usr.bin/gdb/gdb/dwarfread.c b/gnu/usr.bin/gdb/gdb/dwarfread.c
new file mode 100644
index 0000000..a373e4e
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/dwarfread.c
@@ -0,0 +1,3876 @@
+/* DWARF debugging format support for GDB.
+ Copyright (C) 1991, 1992, 1993, 1994 Free Software Foundation, Inc.
+ Written by Fred Fish at Cygnus Support. Portions based on dbxread.c,
+ mipsread.c, coffread.c, and dwarfread.c from a Data General SVR4 gdb port.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/*
+
+FIXME: Do we need to generate dependencies in partial symtabs?
+(Perhaps we don't need to).
+
+FIXME: Resolve minor differences between what information we put in the
+partial symbol table and what dbxread puts in. For example, we don't yet
+put enum constants there. And dbxread seems to invent a lot of typedefs
+we never see. Use the new printpsym command to see the partial symbol table
+contents.
+
+FIXME: Figure out a better way to tell gdb about the name of the function
+contain the user's entry point (I.E. main())
+
+FIXME: See other FIXME's and "ifdef 0" scattered throughout the code for
+other things to work on, if you get bored. :-)
+
+*/
+
+#include "defs.h"
+#include "bfd.h"
+#include "symtab.h"
+#include "gdbtypes.h"
+#include "symfile.h"
+#include "objfiles.h"
+#include "elf/dwarf.h"
+#include "buildsym.h"
+#include "demangle.h"
+#include "expression.h" /* Needed for enum exp_opcode in language.h, sigh... */
+#include "language.h"
+#include "complaints.h"
+
+#include <fcntl.h>
+#include <string.h>
+
+#ifndef NO_SYS_FILE
+#include <sys/file.h>
+#endif
+
+/* FIXME -- convert this to SEEK_SET a la POSIX, move to config files. */
+#ifndef L_SET
+#define L_SET 0
+#endif
+
+/* Some macros to provide DIE info for complaints. */
+
+#define DIE_ID (curdie!=NULL ? curdie->die_ref : 0)
+#define DIE_NAME (curdie!=NULL && curdie->at_name!=NULL) ? curdie->at_name : ""
+
+/* Complaints that can be issued during DWARF debug info reading. */
+
+struct complaint no_bfd_get_N =
+{
+ "DIE @ 0x%x \"%s\", no bfd support for %d byte data object", 0, 0
+};
+
+struct complaint malformed_die =
+{
+ "DIE @ 0x%x \"%s\", malformed DIE, bad length (%d bytes)", 0, 0
+};
+
+struct complaint bad_die_ref =
+{
+ "DIE @ 0x%x \"%s\", reference to DIE (0x%x) outside compilation unit", 0, 0
+};
+
+struct complaint unknown_attribute_form =
+{
+ "DIE @ 0x%x \"%s\", unknown attribute form (0x%x)", 0, 0
+};
+
+struct complaint unknown_attribute_length =
+{
+ "DIE @ 0x%x \"%s\", unknown attribute length, skipped remaining attributes", 0, 0
+};
+
+struct complaint unexpected_fund_type =
+{
+ "DIE @ 0x%x \"%s\", unexpected fundamental type 0x%x", 0, 0
+};
+
+struct complaint unknown_type_modifier =
+{
+ "DIE @ 0x%x \"%s\", unknown type modifier %u", 0, 0
+};
+
+struct complaint volatile_ignored =
+{
+ "DIE @ 0x%x \"%s\", type modifier 'volatile' ignored", 0, 0
+};
+
+struct complaint const_ignored =
+{
+ "DIE @ 0x%x \"%s\", type modifier 'const' ignored", 0, 0
+};
+
+struct complaint botched_modified_type =
+{
+ "DIE @ 0x%x \"%s\", botched modified type decoding (mtype 0x%x)", 0, 0
+};
+
+struct complaint op_deref2 =
+{
+ "DIE @ 0x%x \"%s\", OP_DEREF2 address 0x%x not handled", 0, 0
+};
+
+struct complaint op_deref4 =
+{
+ "DIE @ 0x%x \"%s\", OP_DEREF4 address 0x%x not handled", 0, 0
+};
+
+struct complaint basereg_not_handled =
+{
+ "DIE @ 0x%x \"%s\", BASEREG %d not handled", 0, 0
+};
+
+struct complaint dup_user_type_allocation =
+{
+ "DIE @ 0x%x \"%s\", internal error: duplicate user type allocation", 0, 0
+};
+
+struct complaint dup_user_type_definition =
+{
+ "DIE @ 0x%x \"%s\", internal error: duplicate user type definition", 0, 0
+};
+
+struct complaint missing_tag =
+{
+ "DIE @ 0x%x \"%s\", missing class, structure, or union tag", 0, 0
+};
+
+struct complaint bad_array_element_type =
+{
+ "DIE @ 0x%x \"%s\", bad array element type attribute 0x%x", 0, 0
+};
+
+struct complaint subscript_data_items =
+{
+ "DIE @ 0x%x \"%s\", can't decode subscript data items", 0, 0
+};
+
+struct complaint unhandled_array_subscript_format =
+{
+ "DIE @ 0x%x \"%s\", array subscript format 0x%x not handled yet", 0, 0
+};
+
+struct complaint unknown_array_subscript_format =
+{
+ "DIE @ 0x%x \"%s\", unknown array subscript format %x", 0, 0
+};
+
+struct complaint not_row_major =
+{
+ "DIE @ 0x%x \"%s\", array not row major; not handled correctly", 0, 0
+};
+
+typedef unsigned int DIE_REF; /* Reference to a DIE */
+
+#ifndef GCC_PRODUCER
+#define GCC_PRODUCER "GNU C "
+#endif
+
+#ifndef GPLUS_PRODUCER
+#define GPLUS_PRODUCER "GNU C++ "
+#endif
+
+#ifndef LCC_PRODUCER
+#define LCC_PRODUCER "NCR C/C++"
+#endif
+
+#ifndef CHILL_PRODUCER
+#define CHILL_PRODUCER "GNU Chill "
+#endif
+
+/* Flags to target_to_host() that tell whether or not the data object is
+ expected to be signed. Used, for example, when fetching a signed
+ integer in the target environment which is used as a signed integer
+ in the host environment, and the two environments have different sized
+ ints. In this case, *somebody* has to sign extend the smaller sized
+ int. */
+
+#define GET_UNSIGNED 0 /* No sign extension required */
+#define GET_SIGNED 1 /* Sign extension required */
+
+/* Defines for things which are specified in the document "DWARF Debugging
+ Information Format" published by UNIX International, Programming Languages
+ SIG. These defines are based on revision 1.0.0, Jan 20, 1992. */
+
+#define SIZEOF_DIE_LENGTH 4
+#define SIZEOF_DIE_TAG 2
+#define SIZEOF_ATTRIBUTE 2
+#define SIZEOF_FORMAT_SPECIFIER 1
+#define SIZEOF_FMT_FT 2
+#define SIZEOF_LINETBL_LENGTH 4
+#define SIZEOF_LINETBL_LINENO 4
+#define SIZEOF_LINETBL_STMT 2
+#define SIZEOF_LINETBL_DELTA 4
+#define SIZEOF_LOC_ATOM_CODE 1
+
+#define FORM_FROM_ATTR(attr) ((attr) & 0xF) /* Implicitly specified */
+
+/* Macros that return the sizes of various types of data in the target
+ environment.
+
+ FIXME: Currently these are just compile time constants (as they are in
+ other parts of gdb as well). They need to be able to get the right size
+ either from the bfd or possibly from the DWARF info. It would be nice if
+ the DWARF producer inserted DIES that describe the fundamental types in
+ the target environment into the DWARF info, similar to the way dbx stabs
+ producers produce information about their fundamental types. */
+
+#define TARGET_FT_POINTER_SIZE(objfile) (TARGET_PTR_BIT / TARGET_CHAR_BIT)
+#define TARGET_FT_LONG_SIZE(objfile) (TARGET_LONG_BIT / TARGET_CHAR_BIT)
+
+/* The Amiga SVR4 header file <dwarf.h> defines AT_element_list as a
+ FORM_BLOCK2, and this is the value emitted by the AT&T compiler.
+ However, the Issue 2 DWARF specification from AT&T defines it as
+ a FORM_BLOCK4, as does the latest specification from UI/PLSIG.
+ For backwards compatibility with the AT&T compiler produced executables
+ we define AT_short_element_list for this variant. */
+
+#define AT_short_element_list (0x00f0|FORM_BLOCK2)
+
+/* External variables referenced. */
+
+extern int info_verbose; /* From main.c; nonzero => verbose */
+extern char *warning_pre_print; /* From utils.c */
+
+/* The DWARF debugging information consists of two major pieces,
+ one is a block of DWARF Information Entries (DIE's) and the other
+ is a line number table. The "struct dieinfo" structure contains
+ the information for a single DIE, the one currently being processed.
+
+ In order to make it easier to randomly access the attribute fields
+ of the current DIE, which are specifically unordered within the DIE,
+ each DIE is scanned and an instance of the "struct dieinfo"
+ structure is initialized.
+
+ Initialization is done in two levels. The first, done by basicdieinfo(),
+ just initializes those fields that are vital to deciding whether or not
+ to use this DIE, how to skip past it, etc. The second, done by the
+ function completedieinfo(), fills in the rest of the information.
+
+ Attributes which have block forms are not interpreted at the time
+ the DIE is scanned, instead we just save pointers to the start
+ of their value fields.
+
+ Some fields have a flag <name>_p that is set when the value of the
+ field is valid (I.E. we found a matching attribute in the DIE). Since
+ we may want to test for the presence of some attributes in the DIE,
+ such as AT_low_pc, without restricting the values of the field,
+ we need someway to note that we found such an attribute.
+
+ */
+
+typedef char BLOCK;
+
+struct dieinfo {
+ char * die; /* Pointer to the raw DIE data */
+ unsigned long die_length; /* Length of the raw DIE data */
+ DIE_REF die_ref; /* Offset of this DIE */
+ unsigned short die_tag; /* Tag for this DIE */
+ unsigned long at_padding;
+ unsigned long at_sibling;
+ BLOCK * at_location;
+ char * at_name;
+ unsigned short at_fund_type;
+ BLOCK * at_mod_fund_type;
+ unsigned long at_user_def_type;
+ BLOCK * at_mod_u_d_type;
+ unsigned short at_ordering;
+ BLOCK * at_subscr_data;
+ unsigned long at_byte_size;
+ unsigned short at_bit_offset;
+ unsigned long at_bit_size;
+ BLOCK * at_element_list;
+ unsigned long at_stmt_list;
+ unsigned long at_low_pc;
+ unsigned long at_high_pc;
+ unsigned long at_language;
+ unsigned long at_member;
+ unsigned long at_discr;
+ BLOCK * at_discr_value;
+ BLOCK * at_string_length;
+ char * at_comp_dir;
+ char * at_producer;
+ unsigned long at_start_scope;
+ unsigned long at_stride_size;
+ unsigned long at_src_info;
+ char * at_prototyped;
+ unsigned int has_at_low_pc:1;
+ unsigned int has_at_stmt_list:1;
+ unsigned int has_at_byte_size:1;
+ unsigned int short_element_list:1;
+};
+
+static int diecount; /* Approximate count of dies for compilation unit */
+static struct dieinfo *curdie; /* For warnings and such */
+
+static char *dbbase; /* Base pointer to dwarf info */
+static int dbsize; /* Size of dwarf info in bytes */
+static int dbroff; /* Relative offset from start of .debug section */
+static char *lnbase; /* Base pointer to line section */
+static int isreg; /* Kludge to identify register variables */
+/* Kludge to identify basereg references. Nonzero if we have an offset
+ relative to a basereg. */
+static int offreg;
+/* Which base register is it relative to? */
+static int basereg;
+
+/* This value is added to each symbol value. FIXME: Generalize to
+ the section_offsets structure used by dbxread (once this is done,
+ pass the appropriate section number to end_symtab). */
+static CORE_ADDR baseaddr; /* Add to each symbol value */
+
+/* The section offsets used in the current psymtab or symtab. FIXME,
+ only used to pass one value (baseaddr) at the moment. */
+static struct section_offsets *base_section_offsets;
+
+/* Each partial symbol table entry contains a pointer to private data for the
+ read_symtab() function to use when expanding a partial symbol table entry
+ to a full symbol table entry. For DWARF debugging info, this data is
+ contained in the following structure and macros are provided for easy
+ access to the members given a pointer to a partial symbol table entry.
+
+ dbfoff Always the absolute file offset to the start of the ".debug"
+ section for the file containing the DIE's being accessed.
+
+ dbroff Relative offset from the start of the ".debug" access to the
+ first DIE to be accessed. When building the partial symbol
+ table, this value will be zero since we are accessing the
+ entire ".debug" section. When expanding a partial symbol
+ table entry, this value will be the offset to the first
+ DIE for the compilation unit containing the symbol that
+ triggers the expansion.
+
+ dblength The size of the chunk of DIE's being examined, in bytes.
+
+ lnfoff The absolute file offset to the line table fragment. Ignored
+ when building partial symbol tables, but used when expanding
+ them, and contains the absolute file offset to the fragment
+ of the ".line" section containing the line numbers for the
+ current compilation unit.
+ */
+
+struct dwfinfo {
+ file_ptr dbfoff; /* Absolute file offset to start of .debug section */
+ int dbroff; /* Relative offset from start of .debug section */
+ int dblength; /* Size of the chunk of DIE's being examined */
+ file_ptr lnfoff; /* Absolute file offset to line table fragment */
+};
+
+#define DBFOFF(p) (((struct dwfinfo *)((p)->read_symtab_private))->dbfoff)
+#define DBROFF(p) (((struct dwfinfo *)((p)->read_symtab_private))->dbroff)
+#define DBLENGTH(p) (((struct dwfinfo *)((p)->read_symtab_private))->dblength)
+#define LNFOFF(p) (((struct dwfinfo *)((p)->read_symtab_private))->lnfoff)
+
+/* The generic symbol table building routines have separate lists for
+ file scope symbols and all all other scopes (local scopes). So
+ we need to select the right one to pass to add_symbol_to_list().
+ We do it by keeping a pointer to the correct list in list_in_scope.
+
+ FIXME: The original dwarf code just treated the file scope as the first
+ local scope, and all other local scopes as nested local scopes, and worked
+ fine. Check to see if we really need to distinguish these in buildsym.c */
+
+struct pending **list_in_scope = &file_symbols;
+
+/* DIES which have user defined types or modified user defined types refer to
+ other DIES for the type information. Thus we need to associate the offset
+ of a DIE for a user defined type with a pointer to the type information.
+
+ Originally this was done using a simple but expensive algorithm, with an
+ array of unsorted structures, each containing an offset/type-pointer pair.
+ This array was scanned linearly each time a lookup was done. The result
+ was that gdb was spending over half it's startup time munging through this
+ array of pointers looking for a structure that had the right offset member.
+
+ The second attempt used the same array of structures, but the array was
+ sorted using qsort each time a new offset/type was recorded, and a binary
+ search was used to find the type pointer for a given DIE offset. This was
+ even slower, due to the overhead of sorting the array each time a new
+ offset/type pair was entered.
+
+ The third attempt uses a fixed size array of type pointers, indexed by a
+ value derived from the DIE offset. Since the minimum DIE size is 4 bytes,
+ we can divide any DIE offset by 4 to obtain a unique index into this fixed
+ size array. Since each element is a 4 byte pointer, it takes exactly as
+ much memory to hold this array as to hold the DWARF info for a given
+ compilation unit. But it gets freed as soon as we are done with it.
+ This has worked well in practice, as a reasonable tradeoff between memory
+ consumption and speed, without having to resort to much more complicated
+ algorithms. */
+
+static struct type **utypes; /* Pointer to array of user type pointers */
+static int numutypes; /* Max number of user type pointers */
+
+/* Maintain an array of referenced fundamental types for the current
+ compilation unit being read. For DWARF version 1, we have to construct
+ the fundamental types on the fly, since no information about the
+ fundamental types is supplied. Each such fundamental type is created by
+ calling a language dependent routine to create the type, and then a
+ pointer to that type is then placed in the array at the index specified
+ by it's FT_<TYPENAME> value. The array has a fixed size set by the
+ FT_NUM_MEMBERS compile time constant, which is the number of predefined
+ fundamental types gdb knows how to construct. */
+
+static struct type *ftypes[FT_NUM_MEMBERS]; /* Fundamental types */
+
+/* Record the language for the compilation unit which is currently being
+ processed. We know it once we have seen the TAG_compile_unit DIE,
+ and we need it while processing the DIE's for that compilation unit.
+ It is eventually saved in the symtab structure, but we don't finalize
+ the symtab struct until we have processed all the DIE's for the
+ compilation unit. We also need to get and save a pointer to the
+ language struct for this language, so we can call the language
+ dependent routines for doing things such as creating fundamental
+ types. */
+
+static enum language cu_language;
+static const struct language_defn *cu_language_defn;
+
+/* Forward declarations of static functions so we don't have to worry
+ about ordering within this file. */
+
+static int
+attribute_size PARAMS ((unsigned int));
+
+static unsigned long
+target_to_host PARAMS ((char *, int, int, struct objfile *));
+
+static void
+add_enum_psymbol PARAMS ((struct dieinfo *, struct objfile *));
+
+static void
+handle_producer PARAMS ((char *));
+
+static void
+read_file_scope PARAMS ((struct dieinfo *, char *, char *, struct objfile *));
+
+static void
+read_func_scope PARAMS ((struct dieinfo *, char *, char *, struct objfile *));
+
+static void
+read_lexical_block_scope PARAMS ((struct dieinfo *, char *, char *,
+ struct objfile *));
+
+static void
+scan_partial_symbols PARAMS ((char *, char *, struct objfile *));
+
+static void
+scan_compilation_units PARAMS ((char *, char *, file_ptr,
+ file_ptr, struct objfile *));
+
+static void
+add_partial_symbol PARAMS ((struct dieinfo *, struct objfile *));
+
+static void
+init_psymbol_list PARAMS ((struct objfile *, int));
+
+static void
+basicdieinfo PARAMS ((struct dieinfo *, char *, struct objfile *));
+
+static void
+completedieinfo PARAMS ((struct dieinfo *, struct objfile *));
+
+static void
+dwarf_psymtab_to_symtab PARAMS ((struct partial_symtab *));
+
+static void
+psymtab_to_symtab_1 PARAMS ((struct partial_symtab *));
+
+static void
+read_ofile_symtab PARAMS ((struct partial_symtab *));
+
+static void
+process_dies PARAMS ((char *, char *, struct objfile *));
+
+static void
+read_structure_scope PARAMS ((struct dieinfo *, char *, char *,
+ struct objfile *));
+
+static struct type *
+decode_array_element_type PARAMS ((char *));
+
+static struct type *
+decode_subscript_data_item PARAMS ((char *, char *));
+
+static void
+dwarf_read_array_type PARAMS ((struct dieinfo *));
+
+static void
+read_tag_pointer_type PARAMS ((struct dieinfo *dip));
+
+static void
+read_tag_string_type PARAMS ((struct dieinfo *dip));
+
+static void
+read_subroutine_type PARAMS ((struct dieinfo *, char *, char *));
+
+static void
+read_enumeration PARAMS ((struct dieinfo *, char *, char *, struct objfile *));
+
+static struct type *
+struct_type PARAMS ((struct dieinfo *, char *, char *, struct objfile *));
+
+static struct type *
+enum_type PARAMS ((struct dieinfo *, struct objfile *));
+
+static void
+decode_line_numbers PARAMS ((char *));
+
+static struct type *
+decode_die_type PARAMS ((struct dieinfo *));
+
+static struct type *
+decode_mod_fund_type PARAMS ((char *));
+
+static struct type *
+decode_mod_u_d_type PARAMS ((char *));
+
+static struct type *
+decode_modified_type PARAMS ((char *, unsigned int, int));
+
+static struct type *
+decode_fund_type PARAMS ((unsigned int));
+
+static char *
+create_name PARAMS ((char *, struct obstack *));
+
+static struct type *
+lookup_utype PARAMS ((DIE_REF));
+
+static struct type *
+alloc_utype PARAMS ((DIE_REF, struct type *));
+
+static struct symbol *
+new_symbol PARAMS ((struct dieinfo *, struct objfile *));
+
+static void
+synthesize_typedef PARAMS ((struct dieinfo *, struct objfile *,
+ struct type *));
+
+static int
+locval PARAMS ((char *));
+
+static void
+set_cu_language PARAMS ((struct dieinfo *));
+
+static struct type *
+dwarf_fundamental_type PARAMS ((struct objfile *, int));
+
+
+/*
+
+LOCAL FUNCTION
+
+ dwarf_fundamental_type -- lookup or create a fundamental type
+
+SYNOPSIS
+
+ struct type *
+ dwarf_fundamental_type (struct objfile *objfile, int typeid)
+
+DESCRIPTION
+
+ DWARF version 1 doesn't supply any fundamental type information,
+ so gdb has to construct such types. It has a fixed number of
+ fundamental types that it knows how to construct, which is the
+ union of all types that it knows how to construct for all languages
+ that it knows about. These are enumerated in gdbtypes.h.
+
+ As an example, assume we find a DIE that references a DWARF
+ fundamental type of FT_integer. We first look in the ftypes
+ array to see if we already have such a type, indexed by the
+ gdb internal value of FT_INTEGER. If so, we simply return a
+ pointer to that type. If not, then we ask an appropriate
+ language dependent routine to create a type FT_INTEGER, using
+ defaults reasonable for the current target machine, and install
+ that type in ftypes for future reference.
+
+RETURNS
+
+ Pointer to a fundamental type.
+
+*/
+
+static struct type *
+dwarf_fundamental_type (objfile, typeid)
+ struct objfile *objfile;
+ int typeid;
+{
+ if (typeid < 0 || typeid >= FT_NUM_MEMBERS)
+ {
+ error ("internal error - invalid fundamental type id %d", typeid);
+ }
+
+ /* Look for this particular type in the fundamental type vector. If one is
+ not found, create and install one appropriate for the current language
+ and the current target machine. */
+
+ if (ftypes[typeid] == NULL)
+ {
+ ftypes[typeid] = cu_language_defn -> la_fund_type(objfile, typeid);
+ }
+
+ return (ftypes[typeid]);
+}
+
+/*
+
+LOCAL FUNCTION
+
+ set_cu_language -- set local copy of language for compilation unit
+
+SYNOPSIS
+
+ void
+ set_cu_language (struct dieinfo *dip)
+
+DESCRIPTION
+
+ Decode the language attribute for a compilation unit DIE and
+ remember what the language was. We use this at various times
+ when processing DIE's for a given compilation unit.
+
+RETURNS
+
+ No return value.
+
+ */
+
+static void
+set_cu_language (dip)
+ struct dieinfo *dip;
+{
+ switch (dip -> at_language)
+ {
+ case LANG_C89:
+ case LANG_C:
+ cu_language = language_c;
+ break;
+ case LANG_C_PLUS_PLUS:
+ cu_language = language_cplus;
+ break;
+ case LANG_CHILL:
+ cu_language = language_chill;
+ break;
+ case LANG_MODULA2:
+ cu_language = language_m2;
+ break;
+ case LANG_ADA83:
+ case LANG_COBOL74:
+ case LANG_COBOL85:
+ case LANG_FORTRAN77:
+ case LANG_FORTRAN90:
+ case LANG_PASCAL83:
+ /* We don't know anything special about these yet. */
+ cu_language = language_unknown;
+ break;
+ default:
+ /* If no at_language, try to deduce one from the filename */
+ cu_language = deduce_language_from_filename (dip -> at_name);
+ break;
+ }
+ cu_language_defn = language_def (cu_language);
+}
+
+/*
+
+GLOBAL FUNCTION
+
+ dwarf_build_psymtabs -- build partial symtabs from DWARF debug info
+
+SYNOPSIS
+
+ void dwarf_build_psymtabs (struct objfile *objfile,
+ struct section_offsets *section_offsets,
+ int mainline, file_ptr dbfoff, unsigned int dbfsize,
+ file_ptr lnoffset, unsigned int lnsize)
+
+DESCRIPTION
+
+ This function is called upon to build partial symtabs from files
+ containing DIE's (Dwarf Information Entries) and DWARF line numbers.
+
+ It is passed a bfd* containing the DIES
+ and line number information, the corresponding filename for that
+ file, a base address for relocating the symbols, a flag indicating
+ whether or not this debugging information is from a "main symbol
+ table" rather than a shared library or dynamically linked file,
+ and file offset/size pairs for the DIE information and line number
+ information.
+
+RETURNS
+
+ No return value.
+
+ */
+
+void
+dwarf_build_psymtabs (objfile, section_offsets, mainline, dbfoff, dbfsize,
+ lnoffset, lnsize)
+ struct objfile *objfile;
+ struct section_offsets *section_offsets;
+ int mainline;
+ file_ptr dbfoff;
+ unsigned int dbfsize;
+ file_ptr lnoffset;
+ unsigned int lnsize;
+{
+ bfd *abfd = objfile->obfd;
+ struct cleanup *back_to;
+
+ current_objfile = objfile;
+ dbsize = dbfsize;
+ dbbase = xmalloc (dbsize);
+ dbroff = 0;
+ if ((bfd_seek (abfd, dbfoff, L_SET) != 0) ||
+ (bfd_read (dbbase, dbsize, 1, abfd) != dbsize))
+ {
+ free (dbbase);
+ error ("can't read DWARF data from '%s'", bfd_get_filename (abfd));
+ }
+ back_to = make_cleanup (free, dbbase);
+
+ /* If we are reinitializing, or if we have never loaded syms yet, init.
+ Since we have no idea how many DIES we are looking at, we just guess
+ some arbitrary value. */
+
+ if (mainline || objfile -> global_psymbols.size == 0 ||
+ objfile -> static_psymbols.size == 0)
+ {
+ init_psymbol_list (objfile, 1024);
+ }
+
+ /* Save the relocation factor where everybody can see it. */
+
+ base_section_offsets = section_offsets;
+ baseaddr = ANOFFSET (section_offsets, 0);
+
+ /* Follow the compilation unit sibling chain, building a partial symbol
+ table entry for each one. Save enough information about each compilation
+ unit to locate the full DWARF information later. */
+
+ scan_compilation_units (dbbase, dbbase + dbsize, dbfoff, lnoffset, objfile);
+
+ do_cleanups (back_to);
+ current_objfile = NULL;
+}
+
+/*
+
+LOCAL FUNCTION
+
+ read_lexical_block_scope -- process all dies in a lexical block
+
+SYNOPSIS
+
+ static void read_lexical_block_scope (struct dieinfo *dip,
+ char *thisdie, char *enddie)
+
+DESCRIPTION
+
+ Process all the DIES contained within a lexical block scope.
+ Start a new scope, process the dies, and then close the scope.
+
+ */
+
+static void
+read_lexical_block_scope (dip, thisdie, enddie, objfile)
+ struct dieinfo *dip;
+ char *thisdie;
+ char *enddie;
+ struct objfile *objfile;
+{
+ register struct context_stack *new;
+
+ push_context (0, dip -> at_low_pc);
+ process_dies (thisdie + dip -> die_length, enddie, objfile);
+ new = pop_context ();
+ if (local_symbols != NULL)
+ {
+ finish_block (0, &local_symbols, new -> old_blocks, new -> start_addr,
+ dip -> at_high_pc, objfile);
+ }
+ local_symbols = new -> locals;
+}
+
+/*
+
+LOCAL FUNCTION
+
+ lookup_utype -- look up a user defined type from die reference
+
+SYNOPSIS
+
+ static type *lookup_utype (DIE_REF die_ref)
+
+DESCRIPTION
+
+ Given a DIE reference, lookup the user defined type associated with
+ that DIE, if it has been registered already. If not registered, then
+ return NULL. Alloc_utype() can be called to register an empty
+ type for this reference, which will be filled in later when the
+ actual referenced DIE is processed.
+ */
+
+static struct type *
+lookup_utype (die_ref)
+ DIE_REF die_ref;
+{
+ struct type *type = NULL;
+ int utypeidx;
+
+ utypeidx = (die_ref - dbroff) / 4;
+ if ((utypeidx < 0) || (utypeidx >= numutypes))
+ {
+ complain (&bad_die_ref, DIE_ID, DIE_NAME);
+ }
+ else
+ {
+ type = *(utypes + utypeidx);
+ }
+ return (type);
+}
+
+
+/*
+
+LOCAL FUNCTION
+
+ alloc_utype -- add a user defined type for die reference
+
+SYNOPSIS
+
+ static type *alloc_utype (DIE_REF die_ref, struct type *utypep)
+
+DESCRIPTION
+
+ Given a die reference DIE_REF, and a possible pointer to a user
+ defined type UTYPEP, register that this reference has a user
+ defined type and either use the specified type in UTYPEP or
+ make a new empty type that will be filled in later.
+
+ We should only be called after calling lookup_utype() to verify that
+ there is not currently a type registered for DIE_REF.
+ */
+
+static struct type *
+alloc_utype (die_ref, utypep)
+ DIE_REF die_ref;
+ struct type *utypep;
+{
+ struct type **typep;
+ int utypeidx;
+
+ utypeidx = (die_ref - dbroff) / 4;
+ typep = utypes + utypeidx;
+ if ((utypeidx < 0) || (utypeidx >= numutypes))
+ {
+ utypep = dwarf_fundamental_type (current_objfile, FT_INTEGER);
+ complain (&bad_die_ref, DIE_ID, DIE_NAME);
+ }
+ else if (*typep != NULL)
+ {
+ utypep = *typep;
+ complain (&dup_user_type_allocation, DIE_ID, DIE_NAME);
+ }
+ else
+ {
+ if (utypep == NULL)
+ {
+ utypep = alloc_type (current_objfile);
+ }
+ *typep = utypep;
+ }
+ return (utypep);
+}
+
+/*
+
+LOCAL FUNCTION
+
+ decode_die_type -- return a type for a specified die
+
+SYNOPSIS
+
+ static struct type *decode_die_type (struct dieinfo *dip)
+
+DESCRIPTION
+
+ Given a pointer to a die information structure DIP, decode the
+ type of the die and return a pointer to the decoded type. All
+ dies without specific types default to type int.
+ */
+
+static struct type *
+decode_die_type (dip)
+ struct dieinfo *dip;
+{
+ struct type *type = NULL;
+
+ if (dip -> at_fund_type != 0)
+ {
+ type = decode_fund_type (dip -> at_fund_type);
+ }
+ else if (dip -> at_mod_fund_type != NULL)
+ {
+ type = decode_mod_fund_type (dip -> at_mod_fund_type);
+ }
+ else if (dip -> at_user_def_type)
+ {
+ if ((type = lookup_utype (dip -> at_user_def_type)) == NULL)
+ {
+ type = alloc_utype (dip -> at_user_def_type, NULL);
+ }
+ }
+ else if (dip -> at_mod_u_d_type)
+ {
+ type = decode_mod_u_d_type (dip -> at_mod_u_d_type);
+ }
+ else
+ {
+ type = dwarf_fundamental_type (current_objfile, FT_INTEGER);
+ }
+ return (type);
+}
+
+/*
+
+LOCAL FUNCTION
+
+ struct_type -- compute and return the type for a struct or union
+
+SYNOPSIS
+
+ static struct type *struct_type (struct dieinfo *dip, char *thisdie,
+ char *enddie, struct objfile *objfile)
+
+DESCRIPTION
+
+ Given pointer to a die information structure for a die which
+ defines a union or structure (and MUST define one or the other),
+ and pointers to the raw die data that define the range of dies which
+ define the members, compute and return the user defined type for the
+ structure or union.
+ */
+
+static struct type *
+struct_type (dip, thisdie, enddie, objfile)
+ struct dieinfo *dip;
+ char *thisdie;
+ char *enddie;
+ struct objfile *objfile;
+{
+ struct type *type;
+ struct nextfield {
+ struct nextfield *next;
+ struct field field;
+ };
+ struct nextfield *list = NULL;
+ struct nextfield *new;
+ int nfields = 0;
+ int n;
+ struct dieinfo mbr;
+ char *nextdie;
+#if !BITS_BIG_ENDIAN
+ int anonymous_size;
+#endif
+
+ if ((type = lookup_utype (dip -> die_ref)) == NULL)
+ {
+ /* No forward references created an empty type, so install one now */
+ type = alloc_utype (dip -> die_ref, NULL);
+ }
+ INIT_CPLUS_SPECIFIC(type);
+ switch (dip -> die_tag)
+ {
+ case TAG_class_type:
+ TYPE_CODE (type) = TYPE_CODE_CLASS;
+ break;
+ case TAG_structure_type:
+ TYPE_CODE (type) = TYPE_CODE_STRUCT;
+ break;
+ case TAG_union_type:
+ TYPE_CODE (type) = TYPE_CODE_UNION;
+ break;
+ default:
+ /* Should never happen */
+ TYPE_CODE (type) = TYPE_CODE_UNDEF;
+ complain (&missing_tag, DIE_ID, DIE_NAME);
+ break;
+ }
+ /* Some compilers try to be helpful by inventing "fake" names for
+ anonymous enums, structures, and unions, like "~0fake" or ".0fake".
+ Thanks, but no thanks... */
+ if (dip -> at_name != NULL
+ && *dip -> at_name != '~'
+ && *dip -> at_name != '.')
+ {
+ TYPE_TAG_NAME (type) = obconcat (&objfile -> type_obstack,
+ "", "", dip -> at_name);
+ }
+ /* Use whatever size is known. Zero is a valid size. We might however
+ wish to check has_at_byte_size to make sure that some byte size was
+ given explicitly, but DWARF doesn't specify that explicit sizes of
+ zero have to present, so complaining about missing sizes should
+ probably not be the default. */
+ TYPE_LENGTH (type) = dip -> at_byte_size;
+ thisdie += dip -> die_length;
+ while (thisdie < enddie)
+ {
+ basicdieinfo (&mbr, thisdie, objfile);
+ completedieinfo (&mbr, objfile);
+ if (mbr.die_length <= SIZEOF_DIE_LENGTH)
+ {
+ break;
+ }
+ else if (mbr.at_sibling != 0)
+ {
+ nextdie = dbbase + mbr.at_sibling - dbroff;
+ }
+ else
+ {
+ nextdie = thisdie + mbr.die_length;
+ }
+ switch (mbr.die_tag)
+ {
+ case TAG_member:
+ /* Get space to record the next field's data. */
+ new = (struct nextfield *) alloca (sizeof (struct nextfield));
+ new -> next = list;
+ list = new;
+ /* Save the data. */
+ list -> field.name =
+ obsavestring (mbr.at_name, strlen (mbr.at_name),
+ &objfile -> type_obstack);
+ list -> field.type = decode_die_type (&mbr);
+ list -> field.bitpos = 8 * locval (mbr.at_location);
+ /* Handle bit fields. */
+ list -> field.bitsize = mbr.at_bit_size;
+#if BITS_BIG_ENDIAN
+ /* For big endian bits, the at_bit_offset gives the additional
+ bit offset from the MSB of the containing anonymous object to
+ the MSB of the field. We don't have to do anything special
+ since we don't need to know the size of the anonymous object. */
+ list -> field.bitpos += mbr.at_bit_offset;
+#else
+ /* For little endian bits, we need to have a non-zero at_bit_size,
+ so that we know we are in fact dealing with a bitfield. Compute
+ the bit offset to the MSB of the anonymous object, subtract off
+ the number of bits from the MSB of the field to the MSB of the
+ object, and then subtract off the number of bits of the field
+ itself. The result is the bit offset of the LSB of the field. */
+ if (mbr.at_bit_size > 0)
+ {
+ if (mbr.has_at_byte_size)
+ {
+ /* The size of the anonymous object containing the bit field
+ is explicit, so use the indicated size (in bytes). */
+ anonymous_size = mbr.at_byte_size;
+ }
+ else
+ {
+ /* The size of the anonymous object containing the bit field
+ matches the size of an object of the bit field's type.
+ DWARF allows at_byte_size to be left out in such cases,
+ as a debug information size optimization. */
+ anonymous_size = TYPE_LENGTH (list -> field.type);
+ }
+ list -> field.bitpos +=
+ anonymous_size * 8 - mbr.at_bit_offset - mbr.at_bit_size;
+ }
+#endif
+ nfields++;
+ break;
+ default:
+ process_dies (thisdie, nextdie, objfile);
+ break;
+ }
+ thisdie = nextdie;
+ }
+ /* Now create the vector of fields, and record how big it is. We may
+ not even have any fields, if this DIE was generated due to a reference
+ to an anonymous structure or union. In this case, TYPE_FLAG_STUB is
+ set, which clues gdb in to the fact that it needs to search elsewhere
+ for the full structure definition. */
+ if (nfields == 0)
+ {
+ TYPE_FLAGS (type) |= TYPE_FLAG_STUB;
+ }
+ else
+ {
+ TYPE_NFIELDS (type) = nfields;
+ TYPE_FIELDS (type) = (struct field *)
+ TYPE_ALLOC (type, sizeof (struct field) * nfields);
+ /* Copy the saved-up fields into the field vector. */
+ for (n = nfields; list; list = list -> next)
+ {
+ TYPE_FIELD (type, --n) = list -> field;
+ }
+ }
+ return (type);
+}
+
+/*
+
+LOCAL FUNCTION
+
+ read_structure_scope -- process all dies within struct or union
+
+SYNOPSIS
+
+ static void read_structure_scope (struct dieinfo *dip,
+ char *thisdie, char *enddie, struct objfile *objfile)
+
+DESCRIPTION
+
+ Called when we find the DIE that starts a structure or union
+ scope (definition) to process all dies that define the members
+ of the structure or union. DIP is a pointer to the die info
+ struct for the DIE that names the structure or union.
+
+NOTES
+
+ Note that we need to call struct_type regardless of whether or not
+ the DIE has an at_name attribute, since it might be an anonymous
+ structure or union. This gets the type entered into our set of
+ user defined types.
+
+ However, if the structure is incomplete (an opaque struct/union)
+ then suppress creating a symbol table entry for it since gdb only
+ wants to find the one with the complete definition. Note that if
+ it is complete, we just call new_symbol, which does it's own
+ checking about whether the struct/union is anonymous or not (and
+ suppresses creating a symbol table entry itself).
+
+ */
+
+static void
+read_structure_scope (dip, thisdie, enddie, objfile)
+ struct dieinfo *dip;
+ char *thisdie;
+ char *enddie;
+ struct objfile *objfile;
+{
+ struct type *type;
+ struct symbol *sym;
+
+ type = struct_type (dip, thisdie, enddie, objfile);
+ if (!(TYPE_FLAGS (type) & TYPE_FLAG_STUB))
+ {
+ sym = new_symbol (dip, objfile);
+ if (sym != NULL)
+ {
+ SYMBOL_TYPE (sym) = type;
+ if (cu_language == language_cplus)
+ {
+ synthesize_typedef (dip, objfile, type);
+ }
+ }
+ }
+}
+
+/*
+
+LOCAL FUNCTION
+
+ decode_array_element_type -- decode type of the array elements
+
+SYNOPSIS
+
+ static struct type *decode_array_element_type (char *scan, char *end)
+
+DESCRIPTION
+
+ As the last step in decoding the array subscript information for an
+ array DIE, we need to decode the type of the array elements. We are
+ passed a pointer to this last part of the subscript information and
+ must return the appropriate type. If the type attribute is not
+ recognized, just warn about the problem and return type int.
+ */
+
+static struct type *
+decode_array_element_type (scan)
+ char *scan;
+{
+ struct type *typep;
+ DIE_REF die_ref;
+ unsigned short attribute;
+ unsigned short fundtype;
+ int nbytes;
+
+ attribute = target_to_host (scan, SIZEOF_ATTRIBUTE, GET_UNSIGNED,
+ current_objfile);
+ scan += SIZEOF_ATTRIBUTE;
+ if ((nbytes = attribute_size (attribute)) == -1)
+ {
+ complain (&bad_array_element_type, DIE_ID, DIE_NAME, attribute);
+ typep = dwarf_fundamental_type (current_objfile, FT_INTEGER);
+ }
+ else
+ {
+ switch (attribute)
+ {
+ case AT_fund_type:
+ fundtype = target_to_host (scan, nbytes, GET_UNSIGNED,
+ current_objfile);
+ typep = decode_fund_type (fundtype);
+ break;
+ case AT_mod_fund_type:
+ typep = decode_mod_fund_type (scan);
+ break;
+ case AT_user_def_type:
+ die_ref = target_to_host (scan, nbytes, GET_UNSIGNED,
+ current_objfile);
+ if ((typep = lookup_utype (die_ref)) == NULL)
+ {
+ typep = alloc_utype (die_ref, NULL);
+ }
+ break;
+ case AT_mod_u_d_type:
+ typep = decode_mod_u_d_type (scan);
+ break;
+ default:
+ complain (&bad_array_element_type, DIE_ID, DIE_NAME, attribute);
+ typep = dwarf_fundamental_type (current_objfile, FT_INTEGER);
+ break;
+ }
+ }
+ return (typep);
+}
+
+/*
+
+LOCAL FUNCTION
+
+ decode_subscript_data_item -- decode array subscript item
+
+SYNOPSIS
+
+ static struct type *
+ decode_subscript_data_item (char *scan, char *end)
+
+DESCRIPTION
+
+ The array subscripts and the data type of the elements of an
+ array are described by a list of data items, stored as a block
+ of contiguous bytes. There is a data item describing each array
+ dimension, and a final data item describing the element type.
+ The data items are ordered the same as their appearance in the
+ source (I.E. leftmost dimension first, next to leftmost second,
+ etc).
+
+ The data items describing each array dimension consist of four
+ parts: (1) a format specifier, (2) type type of the subscript
+ index, (3) a description of the low bound of the array dimension,
+ and (4) a description of the high bound of the array dimension.
+
+ The last data item is the description of the type of each of
+ the array elements.
+
+ We are passed a pointer to the start of the block of bytes
+ containing the remaining data items, and a pointer to the first
+ byte past the data. This function recursively decodes the
+ remaining data items and returns a type.
+
+ If we somehow fail to decode some data, we complain about it
+ and return a type "array of int".
+
+BUGS
+ FIXME: This code only implements the forms currently used
+ by the AT&T and GNU C compilers.
+
+ The end pointer is supplied for error checking, maybe we should
+ use it for that...
+ */
+
+static struct type *
+decode_subscript_data_item (scan, end)
+ char *scan;
+ char *end;
+{
+ struct type *typep = NULL; /* Array type we are building */
+ struct type *nexttype; /* Type of each element (may be array) */
+ struct type *indextype; /* Type of this index */
+ struct type *rangetype;
+ unsigned int format;
+ unsigned short fundtype;
+ unsigned long lowbound;
+ unsigned long highbound;
+ int nbytes;
+
+ format = target_to_host (scan, SIZEOF_FORMAT_SPECIFIER, GET_UNSIGNED,
+ current_objfile);
+ scan += SIZEOF_FORMAT_SPECIFIER;
+ switch (format)
+ {
+ case FMT_ET:
+ typep = decode_array_element_type (scan);
+ break;
+ case FMT_FT_C_C:
+ fundtype = target_to_host (scan, SIZEOF_FMT_FT, GET_UNSIGNED,
+ current_objfile);
+ indextype = decode_fund_type (fundtype);
+ scan += SIZEOF_FMT_FT;
+ nbytes = TARGET_FT_LONG_SIZE (current_objfile);
+ lowbound = target_to_host (scan, nbytes, GET_UNSIGNED, current_objfile);
+ scan += nbytes;
+ highbound = target_to_host (scan, nbytes, GET_UNSIGNED, current_objfile);
+ scan += nbytes;
+ nexttype = decode_subscript_data_item (scan, end);
+ if (nexttype == NULL)
+ {
+ /* Munged subscript data or other problem, fake it. */
+ complain (&subscript_data_items, DIE_ID, DIE_NAME);
+ nexttype = dwarf_fundamental_type (current_objfile, FT_INTEGER);
+ }
+ rangetype = create_range_type ((struct type *) NULL, indextype,
+ lowbound, highbound);
+ typep = create_array_type ((struct type *) NULL, nexttype, rangetype);
+ break;
+ case FMT_FT_C_X:
+ case FMT_FT_X_C:
+ case FMT_FT_X_X:
+ case FMT_UT_C_C:
+ case FMT_UT_C_X:
+ case FMT_UT_X_C:
+ case FMT_UT_X_X:
+ complain (&unhandled_array_subscript_format, DIE_ID, DIE_NAME, format);
+ nexttype = dwarf_fundamental_type (current_objfile, FT_INTEGER);
+ rangetype = create_range_type ((struct type *) NULL, nexttype, 0, 0);
+ typep = create_array_type ((struct type *) NULL, nexttype, rangetype);
+ break;
+ default:
+ complain (&unknown_array_subscript_format, DIE_ID, DIE_NAME, format);
+ nexttype = dwarf_fundamental_type (current_objfile, FT_INTEGER);
+ rangetype = create_range_type ((struct type *) NULL, nexttype, 0, 0);
+ typep = create_array_type ((struct type *) NULL, nexttype, rangetype);
+ break;
+ }
+ return (typep);
+}
+
+/*
+
+LOCAL FUNCTION
+
+ dwarf_read_array_type -- read TAG_array_type DIE
+
+SYNOPSIS
+
+ static void dwarf_read_array_type (struct dieinfo *dip)
+
+DESCRIPTION
+
+ Extract all information from a TAG_array_type DIE and add to
+ the user defined type vector.
+ */
+
+static void
+dwarf_read_array_type (dip)
+ struct dieinfo *dip;
+{
+ struct type *type;
+ struct type *utype;
+ char *sub;
+ char *subend;
+ unsigned short blocksz;
+ int nbytes;
+
+ if (dip -> at_ordering != ORD_row_major)
+ {
+ /* FIXME: Can gdb even handle column major arrays? */
+ complain (&not_row_major, DIE_ID, DIE_NAME);
+ }
+ if ((sub = dip -> at_subscr_data) != NULL)
+ {
+ nbytes = attribute_size (AT_subscr_data);
+ blocksz = target_to_host (sub, nbytes, GET_UNSIGNED, current_objfile);
+ subend = sub + nbytes + blocksz;
+ sub += nbytes;
+ type = decode_subscript_data_item (sub, subend);
+ if ((utype = lookup_utype (dip -> die_ref)) == NULL)
+ {
+ /* Install user defined type that has not been referenced yet. */
+ alloc_utype (dip -> die_ref, type);
+ }
+ else if (TYPE_CODE (utype) == TYPE_CODE_UNDEF)
+ {
+ /* Ick! A forward ref has already generated a blank type in our
+ slot, and this type probably already has things pointing to it
+ (which is what caused it to be created in the first place).
+ If it's just a place holder we can plop our fully defined type
+ on top of it. We can't recover the space allocated for our
+ new type since it might be on an obstack, but we could reuse
+ it if we kept a list of them, but it might not be worth it
+ (FIXME). */
+ *utype = *type;
+ }
+ else
+ {
+ /* Double ick! Not only is a type already in our slot, but
+ someone has decorated it. Complain and leave it alone. */
+ complain (&dup_user_type_definition, DIE_ID, DIE_NAME);
+ }
+ }
+}
+
+/*
+
+LOCAL FUNCTION
+
+ read_tag_pointer_type -- read TAG_pointer_type DIE
+
+SYNOPSIS
+
+ static void read_tag_pointer_type (struct dieinfo *dip)
+
+DESCRIPTION
+
+ Extract all information from a TAG_pointer_type DIE and add to
+ the user defined type vector.
+ */
+
+static void
+read_tag_pointer_type (dip)
+ struct dieinfo *dip;
+{
+ struct type *type;
+ struct type *utype;
+
+ type = decode_die_type (dip);
+ if ((utype = lookup_utype (dip -> die_ref)) == NULL)
+ {
+ utype = lookup_pointer_type (type);
+ alloc_utype (dip -> die_ref, utype);
+ }
+ else
+ {
+ TYPE_TARGET_TYPE (utype) = type;
+ TYPE_POINTER_TYPE (type) = utype;
+
+ /* We assume the machine has only one representation for pointers! */
+ /* FIXME: This confuses host<->target data representations, and is a
+ poor assumption besides. */
+
+ TYPE_LENGTH (utype) = sizeof (char *);
+ TYPE_CODE (utype) = TYPE_CODE_PTR;
+ }
+}
+
+/*
+
+LOCAL FUNCTION
+
+ read_tag_string_type -- read TAG_string_type DIE
+
+SYNOPSIS
+
+ static void read_tag_string_type (struct dieinfo *dip)
+
+DESCRIPTION
+
+ Extract all information from a TAG_string_type DIE and add to
+ the user defined type vector. It isn't really a user defined
+ type, but it behaves like one, with other DIE's using an
+ AT_user_def_type attribute to reference it.
+ */
+
+static void
+read_tag_string_type (dip)
+ struct dieinfo *dip;
+{
+ struct type *utype;
+ struct type *indextype;
+ struct type *rangetype;
+ unsigned long lowbound = 0;
+ unsigned long highbound;
+
+ if (dip -> has_at_byte_size)
+ {
+ /* A fixed bounds string */
+ highbound = dip -> at_byte_size - 1;
+ }
+ else
+ {
+ /* A varying length string. Stub for now. (FIXME) */
+ highbound = 1;
+ }
+ indextype = dwarf_fundamental_type (current_objfile, FT_INTEGER);
+ rangetype = create_range_type ((struct type *) NULL, indextype, lowbound,
+ highbound);
+
+ utype = lookup_utype (dip -> die_ref);
+ if (utype == NULL)
+ {
+ /* No type defined, go ahead and create a blank one to use. */
+ utype = alloc_utype (dip -> die_ref, (struct type *) NULL);
+ }
+ else
+ {
+ /* Already a type in our slot due to a forward reference. Make sure it
+ is a blank one. If not, complain and leave it alone. */
+ if (TYPE_CODE (utype) != TYPE_CODE_UNDEF)
+ {
+ complain (&dup_user_type_definition, DIE_ID, DIE_NAME);
+ return;
+ }
+ }
+
+ /* Create the string type using the blank type we either found or created. */
+ utype = create_string_type (utype, rangetype);
+}
+
+/*
+
+LOCAL FUNCTION
+
+ read_subroutine_type -- process TAG_subroutine_type dies
+
+SYNOPSIS
+
+ static void read_subroutine_type (struct dieinfo *dip, char thisdie,
+ char *enddie)
+
+DESCRIPTION
+
+ Handle DIES due to C code like:
+
+ struct foo {
+ int (*funcp)(int a, long l); (Generates TAG_subroutine_type DIE)
+ int b;
+ };
+
+NOTES
+
+ The parameter DIES are currently ignored. See if gdb has a way to
+ include this info in it's type system, and decode them if so. Is
+ this what the type structure's "arg_types" field is for? (FIXME)
+ */
+
+static void
+read_subroutine_type (dip, thisdie, enddie)
+ struct dieinfo *dip;
+ char *thisdie;
+ char *enddie;
+{
+ struct type *type; /* Type that this function returns */
+ struct type *ftype; /* Function that returns above type */
+
+ /* Decode the type that this subroutine returns */
+
+ type = decode_die_type (dip);
+
+ /* Check to see if we already have a partially constructed user
+ defined type for this DIE, from a forward reference. */
+
+ if ((ftype = lookup_utype (dip -> die_ref)) == NULL)
+ {
+ /* This is the first reference to one of these types. Make
+ a new one and place it in the user defined types. */
+ ftype = lookup_function_type (type);
+ alloc_utype (dip -> die_ref, ftype);
+ }
+ else if (TYPE_CODE (ftype) == TYPE_CODE_UNDEF)
+ {
+ /* We have an existing partially constructed type, so bash it
+ into the correct type. */
+ TYPE_TARGET_TYPE (ftype) = type;
+ TYPE_FUNCTION_TYPE (type) = ftype;
+ TYPE_LENGTH (ftype) = 1;
+ TYPE_CODE (ftype) = TYPE_CODE_FUNC;
+ }
+ else
+ {
+ complain (&dup_user_type_definition, DIE_ID, DIE_NAME);
+ }
+}
+
+/*
+
+LOCAL FUNCTION
+
+ read_enumeration -- process dies which define an enumeration
+
+SYNOPSIS
+
+ static void read_enumeration (struct dieinfo *dip, char *thisdie,
+ char *enddie, struct objfile *objfile)
+
+DESCRIPTION
+
+ Given a pointer to a die which begins an enumeration, process all
+ the dies that define the members of the enumeration.
+
+NOTES
+
+ Note that we need to call enum_type regardless of whether or not we
+ have a symbol, since we might have an enum without a tag name (thus
+ no symbol for the tagname).
+ */
+
+static void
+read_enumeration (dip, thisdie, enddie, objfile)
+ struct dieinfo *dip;
+ char *thisdie;
+ char *enddie;
+ struct objfile *objfile;
+{
+ struct type *type;
+ struct symbol *sym;
+
+ type = enum_type (dip, objfile);
+ sym = new_symbol (dip, objfile);
+ if (sym != NULL)
+ {
+ SYMBOL_TYPE (sym) = type;
+ if (cu_language == language_cplus)
+ {
+ synthesize_typedef (dip, objfile, type);
+ }
+ }
+}
+
+/*
+
+LOCAL FUNCTION
+
+ enum_type -- decode and return a type for an enumeration
+
+SYNOPSIS
+
+ static type *enum_type (struct dieinfo *dip, struct objfile *objfile)
+
+DESCRIPTION
+
+ Given a pointer to a die information structure for the die which
+ starts an enumeration, process all the dies that define the members
+ of the enumeration and return a type pointer for the enumeration.
+
+ At the same time, for each member of the enumeration, create a
+ symbol for it with namespace VAR_NAMESPACE and class LOC_CONST,
+ and give it the type of the enumeration itself.
+
+NOTES
+
+ Note that the DWARF specification explicitly mandates that enum
+ constants occur in reverse order from the source program order,
+ for "consistency" and because this ordering is easier for many
+ compilers to generate. (Draft 6, sec 3.8.5, Enumeration type
+ Entries). Because gdb wants to see the enum members in program
+ source order, we have to ensure that the order gets reversed while
+ we are processing them.
+ */
+
+static struct type *
+enum_type (dip, objfile)
+ struct dieinfo *dip;
+ struct objfile *objfile;
+{
+ struct type *type;
+ struct nextfield {
+ struct nextfield *next;
+ struct field field;
+ };
+ struct nextfield *list = NULL;
+ struct nextfield *new;
+ int nfields = 0;
+ int n;
+ char *scan;
+ char *listend;
+ unsigned short blocksz;
+ struct symbol *sym;
+ int nbytes;
+
+ if ((type = lookup_utype (dip -> die_ref)) == NULL)
+ {
+ /* No forward references created an empty type, so install one now */
+ type = alloc_utype (dip -> die_ref, NULL);
+ }
+ TYPE_CODE (type) = TYPE_CODE_ENUM;
+ /* Some compilers try to be helpful by inventing "fake" names for
+ anonymous enums, structures, and unions, like "~0fake" or ".0fake".
+ Thanks, but no thanks... */
+ if (dip -> at_name != NULL
+ && *dip -> at_name != '~'
+ && *dip -> at_name != '.')
+ {
+ TYPE_TAG_NAME (type) = obconcat (&objfile -> type_obstack,
+ "", "", dip -> at_name);
+ }
+ if (dip -> at_byte_size != 0)
+ {
+ TYPE_LENGTH (type) = dip -> at_byte_size;
+ }
+ if ((scan = dip -> at_element_list) != NULL)
+ {
+ if (dip -> short_element_list)
+ {
+ nbytes = attribute_size (AT_short_element_list);
+ }
+ else
+ {
+ nbytes = attribute_size (AT_element_list);
+ }
+ blocksz = target_to_host (scan, nbytes, GET_UNSIGNED, objfile);
+ listend = scan + nbytes + blocksz;
+ scan += nbytes;
+ while (scan < listend)
+ {
+ new = (struct nextfield *) alloca (sizeof (struct nextfield));
+ new -> next = list;
+ list = new;
+ list -> field.type = NULL;
+ list -> field.bitsize = 0;
+ list -> field.bitpos =
+ target_to_host (scan, TARGET_FT_LONG_SIZE (objfile), GET_SIGNED,
+ objfile);
+ scan += TARGET_FT_LONG_SIZE (objfile);
+ list -> field.name = obsavestring (scan, strlen (scan),
+ &objfile -> type_obstack);
+ scan += strlen (scan) + 1;
+ nfields++;
+ /* Handcraft a new symbol for this enum member. */
+ sym = (struct symbol *) obstack_alloc (&objfile->symbol_obstack,
+ sizeof (struct symbol));
+ memset (sym, 0, sizeof (struct symbol));
+ SYMBOL_NAME (sym) = create_name (list -> field.name,
+ &objfile->symbol_obstack);
+ SYMBOL_INIT_LANGUAGE_SPECIFIC (sym, cu_language);
+ SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE;
+ SYMBOL_CLASS (sym) = LOC_CONST;
+ SYMBOL_TYPE (sym) = type;
+ SYMBOL_VALUE (sym) = list -> field.bitpos;
+ add_symbol_to_list (sym, list_in_scope);
+ }
+ /* Now create the vector of fields, and record how big it is. This is
+ where we reverse the order, by pulling the members off the list in
+ reverse order from how they were inserted. If we have no fields
+ (this is apparently possible in C++) then skip building a field
+ vector. */
+ if (nfields > 0)
+ {
+ TYPE_NFIELDS (type) = nfields;
+ TYPE_FIELDS (type) = (struct field *)
+ obstack_alloc (&objfile->symbol_obstack, sizeof (struct field) * nfields);
+ /* Copy the saved-up fields into the field vector. */
+ for (n = 0; (n < nfields) && (list != NULL); list = list -> next)
+ {
+ TYPE_FIELD (type, n++) = list -> field;
+ }
+ }
+ }
+ return (type);
+}
+
+/*
+
+LOCAL FUNCTION
+
+ read_func_scope -- process all dies within a function scope
+
+DESCRIPTION
+
+ Process all dies within a given function scope. We are passed
+ a die information structure pointer DIP for the die which
+ starts the function scope, and pointers into the raw die data
+ that define the dies within the function scope.
+
+ For now, we ignore lexical block scopes within the function.
+ The problem is that AT&T cc does not define a DWARF lexical
+ block scope for the function itself, while gcc defines a
+ lexical block scope for the function. We need to think about
+ how to handle this difference, or if it is even a problem.
+ (FIXME)
+ */
+
+static void
+read_func_scope (dip, thisdie, enddie, objfile)
+ struct dieinfo *dip;
+ char *thisdie;
+ char *enddie;
+ struct objfile *objfile;
+{
+ register struct context_stack *new;
+
+ if (objfile -> ei.entry_point >= dip -> at_low_pc &&
+ objfile -> ei.entry_point < dip -> at_high_pc)
+ {
+ objfile -> ei.entry_func_lowpc = dip -> at_low_pc;
+ objfile -> ei.entry_func_highpc = dip -> at_high_pc;
+ }
+ if (STREQ (dip -> at_name, "main")) /* FIXME: hardwired name */
+ {
+ objfile -> ei.main_func_lowpc = dip -> at_low_pc;
+ objfile -> ei.main_func_highpc = dip -> at_high_pc;
+ }
+ new = push_context (0, dip -> at_low_pc);
+ new -> name = new_symbol (dip, objfile);
+ list_in_scope = &local_symbols;
+ process_dies (thisdie + dip -> die_length, enddie, objfile);
+ new = pop_context ();
+ /* Make a block for the local symbols within. */
+ finish_block (new -> name, &local_symbols, new -> old_blocks,
+ new -> start_addr, dip -> at_high_pc, objfile);
+ list_in_scope = &file_symbols;
+}
+
+
+/*
+
+LOCAL FUNCTION
+
+ handle_producer -- process the AT_producer attribute
+
+DESCRIPTION
+
+ Perform any operations that depend on finding a particular
+ AT_producer attribute.
+
+ */
+
+static void
+handle_producer (producer)
+ char *producer;
+{
+
+ /* If this compilation unit was compiled with g++ or gcc, then set the
+ processing_gcc_compilation flag. */
+
+ processing_gcc_compilation =
+ STREQN (producer, GPLUS_PRODUCER, strlen (GPLUS_PRODUCER))
+ || STREQN (producer, CHILL_PRODUCER, strlen (CHILL_PRODUCER))
+ || STREQN (producer, GCC_PRODUCER, strlen (GCC_PRODUCER));
+
+ /* Select a demangling style if we can identify the producer and if
+ the current style is auto. We leave the current style alone if it
+ is not auto. We also leave the demangling style alone if we find a
+ gcc (cc1) producer, as opposed to a g++ (cc1plus) producer. */
+
+ if (AUTO_DEMANGLING)
+ {
+ if (STREQN (producer, GPLUS_PRODUCER, strlen (GPLUS_PRODUCER)))
+ {
+ set_demangling_style (GNU_DEMANGLING_STYLE_STRING);
+ }
+ else if (STREQN (producer, LCC_PRODUCER, strlen (LCC_PRODUCER)))
+ {
+ set_demangling_style (LUCID_DEMANGLING_STYLE_STRING);
+ }
+ }
+}
+
+
+/*
+
+LOCAL FUNCTION
+
+ read_file_scope -- process all dies within a file scope
+
+DESCRIPTION
+
+ Process all dies within a given file scope. We are passed a
+ pointer to the die information structure for the die which
+ starts the file scope, and pointers into the raw die data which
+ mark the range of dies within the file scope.
+
+ When the partial symbol table is built, the file offset for the line
+ number table for each compilation unit is saved in the partial symbol
+ table entry for that compilation unit. As the symbols for each
+ compilation unit are read, the line number table is read into memory
+ and the variable lnbase is set to point to it. Thus all we have to
+ do is use lnbase to access the line number table for the current
+ compilation unit.
+ */
+
+static void
+read_file_scope (dip, thisdie, enddie, objfile)
+ struct dieinfo *dip;
+ char *thisdie;
+ char *enddie;
+ struct objfile *objfile;
+{
+ struct cleanup *back_to;
+ struct symtab *symtab;
+
+ if (objfile -> ei.entry_point >= dip -> at_low_pc &&
+ objfile -> ei.entry_point < dip -> at_high_pc)
+ {
+ objfile -> ei.entry_file_lowpc = dip -> at_low_pc;
+ objfile -> ei.entry_file_highpc = dip -> at_high_pc;
+ }
+ set_cu_language (dip);
+ if (dip -> at_producer != NULL)
+ {
+ handle_producer (dip -> at_producer);
+ }
+ numutypes = (enddie - thisdie) / 4;
+ utypes = (struct type **) xmalloc (numutypes * sizeof (struct type *));
+ back_to = make_cleanup (free, utypes);
+ memset (utypes, 0, numutypes * sizeof (struct type *));
+ memset (ftypes, 0, FT_NUM_MEMBERS * sizeof (struct type *));
+ start_symtab (dip -> at_name, dip -> at_comp_dir, dip -> at_low_pc);
+ decode_line_numbers (lnbase);
+ process_dies (thisdie + dip -> die_length, enddie, objfile);
+
+ symtab = end_symtab (dip -> at_high_pc, 0, 0, objfile, 0);
+ if (symtab != NULL)
+ {
+ symtab -> language = cu_language;
+ }
+ do_cleanups (back_to);
+ utypes = NULL;
+ numutypes = 0;
+}
+
+/*
+
+LOCAL FUNCTION
+
+ process_dies -- process a range of DWARF Information Entries
+
+SYNOPSIS
+
+ static void process_dies (char *thisdie, char *enddie,
+ struct objfile *objfile)
+
+DESCRIPTION
+
+ Process all DIE's in a specified range. May be (and almost
+ certainly will be) called recursively.
+ */
+
+static void
+process_dies (thisdie, enddie, objfile)
+ char *thisdie;
+ char *enddie;
+ struct objfile *objfile;
+{
+ char *nextdie;
+ struct dieinfo di;
+
+ while (thisdie < enddie)
+ {
+ basicdieinfo (&di, thisdie, objfile);
+ if (di.die_length < SIZEOF_DIE_LENGTH)
+ {
+ break;
+ }
+ else if (di.die_tag == TAG_padding)
+ {
+ nextdie = thisdie + di.die_length;
+ }
+ else
+ {
+ completedieinfo (&di, objfile);
+ if (di.at_sibling != 0)
+ {
+ nextdie = dbbase + di.at_sibling - dbroff;
+ }
+ else
+ {
+ nextdie = thisdie + di.die_length;
+ }
+#ifdef SMASH_TEXT_ADDRESS
+ /* I think that these are always text, not data, addresses. */
+ SMASH_TEXT_ADDRESS (di.at_low_pc);
+ SMASH_TEXT_ADDRESS (di.at_high_pc);
+#endif
+ switch (di.die_tag)
+ {
+ case TAG_compile_unit:
+ /* Skip Tag_compile_unit if we are already inside a compilation
+ unit, we are unable to handle nested compilation units
+ properly (FIXME). */
+ if (current_subfile == NULL)
+ read_file_scope (&di, thisdie, nextdie, objfile);
+ else
+ nextdie = thisdie + di.die_length;
+ break;
+ case TAG_global_subroutine:
+ case TAG_subroutine:
+ if (di.has_at_low_pc)
+ {
+ read_func_scope (&di, thisdie, nextdie, objfile);
+ }
+ break;
+ case TAG_lexical_block:
+ read_lexical_block_scope (&di, thisdie, nextdie, objfile);
+ break;
+ case TAG_class_type:
+ case TAG_structure_type:
+ case TAG_union_type:
+ read_structure_scope (&di, thisdie, nextdie, objfile);
+ break;
+ case TAG_enumeration_type:
+ read_enumeration (&di, thisdie, nextdie, objfile);
+ break;
+ case TAG_subroutine_type:
+ read_subroutine_type (&di, thisdie, nextdie);
+ break;
+ case TAG_array_type:
+ dwarf_read_array_type (&di);
+ break;
+ case TAG_pointer_type:
+ read_tag_pointer_type (&di);
+ break;
+ case TAG_string_type:
+ read_tag_string_type (&di);
+ break;
+ default:
+ new_symbol (&di, objfile);
+ break;
+ }
+ }
+ thisdie = nextdie;
+ }
+}
+
+/*
+
+LOCAL FUNCTION
+
+ decode_line_numbers -- decode a line number table fragment
+
+SYNOPSIS
+
+ static void decode_line_numbers (char *tblscan, char *tblend,
+ long length, long base, long line, long pc)
+
+DESCRIPTION
+
+ Translate the DWARF line number information to gdb form.
+
+ The ".line" section contains one or more line number tables, one for
+ each ".line" section from the objects that were linked.
+
+ The AT_stmt_list attribute for each TAG_source_file entry in the
+ ".debug" section contains the offset into the ".line" section for the
+ start of the table for that file.
+
+ The table itself has the following structure:
+
+ <table length><base address><source statement entry>
+ 4 bytes 4 bytes 10 bytes
+
+ The table length is the total size of the table, including the 4 bytes
+ for the length information.
+
+ The base address is the address of the first instruction generated
+ for the source file.
+
+ Each source statement entry has the following structure:
+
+ <line number><statement position><address delta>
+ 4 bytes 2 bytes 4 bytes
+
+ The line number is relative to the start of the file, starting with
+ line 1.
+
+ The statement position either -1 (0xFFFF) or the number of characters
+ from the beginning of the line to the beginning of the statement.
+
+ The address delta is the difference between the base address and
+ the address of the first instruction for the statement.
+
+ Note that we must copy the bytes from the packed table to our local
+ variables before attempting to use them, to avoid alignment problems
+ on some machines, particularly RISC processors.
+
+BUGS
+
+ Does gdb expect the line numbers to be sorted? They are now by
+ chance/luck, but are not required to be. (FIXME)
+
+ The line with number 0 is unused, gdb apparently can discover the
+ span of the last line some other way. How? (FIXME)
+ */
+
+static void
+decode_line_numbers (linetable)
+ char *linetable;
+{
+ char *tblscan;
+ char *tblend;
+ unsigned long length;
+ unsigned long base;
+ unsigned long line;
+ unsigned long pc;
+
+ if (linetable != NULL)
+ {
+ tblscan = tblend = linetable;
+ length = target_to_host (tblscan, SIZEOF_LINETBL_LENGTH, GET_UNSIGNED,
+ current_objfile);
+ tblscan += SIZEOF_LINETBL_LENGTH;
+ tblend += length;
+ base = target_to_host (tblscan, TARGET_FT_POINTER_SIZE (objfile),
+ GET_UNSIGNED, current_objfile);
+ tblscan += TARGET_FT_POINTER_SIZE (objfile);
+ base += baseaddr;
+ while (tblscan < tblend)
+ {
+ line = target_to_host (tblscan, SIZEOF_LINETBL_LINENO, GET_UNSIGNED,
+ current_objfile);
+ tblscan += SIZEOF_LINETBL_LINENO + SIZEOF_LINETBL_STMT;
+ pc = target_to_host (tblscan, SIZEOF_LINETBL_DELTA, GET_UNSIGNED,
+ current_objfile);
+ tblscan += SIZEOF_LINETBL_DELTA;
+ pc += base;
+ if (line != 0)
+ {
+ record_line (current_subfile, line, pc);
+ }
+ }
+ }
+}
+
+/*
+
+LOCAL FUNCTION
+
+ locval -- compute the value of a location attribute
+
+SYNOPSIS
+
+ static int locval (char *loc)
+
+DESCRIPTION
+
+ Given pointer to a string of bytes that define a location, compute
+ the location and return the value.
+
+ When computing values involving the current value of the frame pointer,
+ the value zero is used, which results in a value relative to the frame
+ pointer, rather than the absolute value. This is what GDB wants
+ anyway.
+
+ When the result is a register number, the global isreg flag is set,
+ otherwise it is cleared. This is a kludge until we figure out a better
+ way to handle the problem. Gdb's design does not mesh well with the
+ DWARF notion of a location computing interpreter, which is a shame
+ because the flexibility goes unused.
+
+NOTES
+
+ Note that stack[0] is unused except as a default error return.
+ Note that stack overflow is not yet handled.
+ */
+
+static int
+locval (loc)
+ char *loc;
+{
+ unsigned short nbytes;
+ unsigned short locsize;
+ auto long stack[64];
+ int stacki;
+ char *end;
+ int loc_atom_code;
+ int loc_value_size;
+
+ nbytes = attribute_size (AT_location);
+ locsize = target_to_host (loc, nbytes, GET_UNSIGNED, current_objfile);
+ loc += nbytes;
+ end = loc + locsize;
+ stacki = 0;
+ stack[stacki] = 0;
+ isreg = 0;
+ offreg = 0;
+ loc_value_size = TARGET_FT_LONG_SIZE (current_objfile);
+ while (loc < end)
+ {
+ loc_atom_code = target_to_host (loc, SIZEOF_LOC_ATOM_CODE, GET_UNSIGNED,
+ current_objfile);
+ loc += SIZEOF_LOC_ATOM_CODE;
+ switch (loc_atom_code)
+ {
+ case 0:
+ /* error */
+ loc = end;
+ break;
+ case OP_REG:
+ /* push register (number) */
+ stack[++stacki] = target_to_host (loc, loc_value_size,
+ GET_UNSIGNED, current_objfile);
+ loc += loc_value_size;
+ isreg = 1;
+ break;
+ case OP_BASEREG:
+ /* push value of register (number) */
+ /* Actually, we compute the value as if register has 0, so the
+ value ends up being the offset from that register. */
+ offreg = 1;
+ basereg = target_to_host (loc, loc_value_size, GET_UNSIGNED,
+ current_objfile);
+ loc += loc_value_size;
+ stack[++stacki] = 0;
+ break;
+ case OP_ADDR:
+ /* push address (relocated address) */
+ stack[++stacki] = target_to_host (loc, loc_value_size,
+ GET_UNSIGNED, current_objfile);
+ loc += loc_value_size;
+ break;
+ case OP_CONST:
+ /* push constant (number) FIXME: signed or unsigned! */
+ stack[++stacki] = target_to_host (loc, loc_value_size,
+ GET_SIGNED, current_objfile);
+ loc += loc_value_size;
+ break;
+ case OP_DEREF2:
+ /* pop, deref and push 2 bytes (as a long) */
+ complain (&op_deref2, DIE_ID, DIE_NAME, stack[stacki]);
+ break;
+ case OP_DEREF4: /* pop, deref and push 4 bytes (as a long) */
+ complain (&op_deref4, DIE_ID, DIE_NAME, stack[stacki]);
+ break;
+ case OP_ADD: /* pop top 2 items, add, push result */
+ stack[stacki - 1] += stack[stacki];
+ stacki--;
+ break;
+ }
+ }
+ return (stack[stacki]);
+}
+
+/*
+
+LOCAL FUNCTION
+
+ read_ofile_symtab -- build a full symtab entry from chunk of DIE's
+
+SYNOPSIS
+
+ static void read_ofile_symtab (struct partial_symtab *pst)
+
+DESCRIPTION
+
+ When expanding a partial symbol table entry to a full symbol table
+ entry, this is the function that gets called to read in the symbols
+ for the compilation unit. A pointer to the newly constructed symtab,
+ which is now the new first one on the objfile's symtab list, is
+ stashed in the partial symbol table entry.
+ */
+
+static void
+read_ofile_symtab (pst)
+ struct partial_symtab *pst;
+{
+ struct cleanup *back_to;
+ unsigned long lnsize;
+ file_ptr foffset;
+ bfd *abfd;
+ char lnsizedata[SIZEOF_LINETBL_LENGTH];
+
+ abfd = pst -> objfile -> obfd;
+ current_objfile = pst -> objfile;
+
+ /* Allocate a buffer for the entire chunk of DIE's for this compilation
+ unit, seek to the location in the file, and read in all the DIE's. */
+
+ diecount = 0;
+ dbsize = DBLENGTH (pst);
+ dbbase = xmalloc (dbsize);
+ dbroff = DBROFF(pst);
+ foffset = DBFOFF(pst) + dbroff;
+ base_section_offsets = pst->section_offsets;
+ baseaddr = ANOFFSET (pst->section_offsets, 0);
+ if (bfd_seek (abfd, foffset, L_SET) ||
+ (bfd_read (dbbase, dbsize, 1, abfd) != dbsize))
+ {
+ free (dbbase);
+ error ("can't read DWARF data");
+ }
+ back_to = make_cleanup (free, dbbase);
+
+ /* If there is a line number table associated with this compilation unit
+ then read the size of this fragment in bytes, from the fragment itself.
+ Allocate a buffer for the fragment and read it in for future
+ processing. */
+
+ lnbase = NULL;
+ if (LNFOFF (pst))
+ {
+ if (bfd_seek (abfd, LNFOFF (pst), L_SET) ||
+ (bfd_read ((PTR) lnsizedata, sizeof (lnsizedata), 1, abfd) !=
+ sizeof (lnsizedata)))
+ {
+ error ("can't read DWARF line number table size");
+ }
+ lnsize = target_to_host (lnsizedata, SIZEOF_LINETBL_LENGTH,
+ GET_UNSIGNED, pst -> objfile);
+ lnbase = xmalloc (lnsize);
+ if (bfd_seek (abfd, LNFOFF (pst), L_SET) ||
+ (bfd_read (lnbase, lnsize, 1, abfd) != lnsize))
+ {
+ free (lnbase);
+ error ("can't read DWARF line numbers");
+ }
+ make_cleanup (free, lnbase);
+ }
+
+ process_dies (dbbase, dbbase + dbsize, pst -> objfile);
+ do_cleanups (back_to);
+ current_objfile = NULL;
+ pst -> symtab = pst -> objfile -> symtabs;
+}
+
+/*
+
+LOCAL FUNCTION
+
+ psymtab_to_symtab_1 -- do grunt work for building a full symtab entry
+
+SYNOPSIS
+
+ static void psymtab_to_symtab_1 (struct partial_symtab *pst)
+
+DESCRIPTION
+
+ Called once for each partial symbol table entry that needs to be
+ expanded into a full symbol table entry.
+
+*/
+
+static void
+psymtab_to_symtab_1 (pst)
+ struct partial_symtab *pst;
+{
+ int i;
+ struct cleanup *old_chain;
+
+ if (pst != NULL)
+ {
+ if (pst->readin)
+ {
+ warning ("psymtab for %s already read in. Shouldn't happen.",
+ pst -> filename);
+ }
+ else
+ {
+ /* Read in all partial symtabs on which this one is dependent */
+ for (i = 0; i < pst -> number_of_dependencies; i++)
+ {
+ if (!pst -> dependencies[i] -> readin)
+ {
+ /* Inform about additional files that need to be read in. */
+ if (info_verbose)
+ {
+ fputs_filtered (" ", gdb_stdout);
+ wrap_here ("");
+ fputs_filtered ("and ", gdb_stdout);
+ wrap_here ("");
+ printf_filtered ("%s...",
+ pst -> dependencies[i] -> filename);
+ wrap_here ("");
+ gdb_flush (gdb_stdout); /* Flush output */
+ }
+ psymtab_to_symtab_1 (pst -> dependencies[i]);
+ }
+ }
+ if (DBLENGTH (pst)) /* Otherwise it's a dummy */
+ {
+ buildsym_init ();
+ old_chain = make_cleanup (really_free_pendings, 0);
+ read_ofile_symtab (pst);
+ if (info_verbose)
+ {
+ printf_filtered ("%d DIE's, sorting...", diecount);
+ wrap_here ("");
+ gdb_flush (gdb_stdout);
+ }
+ sort_symtab_syms (pst -> symtab);
+ do_cleanups (old_chain);
+ }
+ pst -> readin = 1;
+ }
+ }
+}
+
+/*
+
+LOCAL FUNCTION
+
+ dwarf_psymtab_to_symtab -- build a full symtab entry from partial one
+
+SYNOPSIS
+
+ static void dwarf_psymtab_to_symtab (struct partial_symtab *pst)
+
+DESCRIPTION
+
+ This is the DWARF support entry point for building a full symbol
+ table entry from a partial symbol table entry. We are passed a
+ pointer to the partial symbol table entry that needs to be expanded.
+
+*/
+
+static void
+dwarf_psymtab_to_symtab (pst)
+ struct partial_symtab *pst;
+{
+
+ if (pst != NULL)
+ {
+ if (pst -> readin)
+ {
+ warning ("psymtab for %s already read in. Shouldn't happen.",
+ pst -> filename);
+ }
+ else
+ {
+ if (DBLENGTH (pst) || pst -> number_of_dependencies)
+ {
+ /* Print the message now, before starting serious work, to avoid
+ disconcerting pauses. */
+ if (info_verbose)
+ {
+ printf_filtered ("Reading in symbols for %s...",
+ pst -> filename);
+ gdb_flush (gdb_stdout);
+ }
+
+ psymtab_to_symtab_1 (pst);
+
+#if 0 /* FIXME: Check to see what dbxread is doing here and see if
+ we need to do an equivalent or is this something peculiar to
+ stabs/a.out format.
+ Match with global symbols. This only needs to be done once,
+ after all of the symtabs and dependencies have been read in.
+ */
+ scan_file_globals (pst -> objfile);
+#endif
+
+ /* Finish up the verbose info message. */
+ if (info_verbose)
+ {
+ printf_filtered ("done.\n");
+ gdb_flush (gdb_stdout);
+ }
+ }
+ }
+ }
+}
+
+/*
+
+LOCAL FUNCTION
+
+ init_psymbol_list -- initialize storage for partial symbols
+
+SYNOPSIS
+
+ static void init_psymbol_list (struct objfile *objfile, int total_symbols)
+
+DESCRIPTION
+
+ Initializes storage for all of the partial symbols that will be
+ created by dwarf_build_psymtabs and subsidiaries.
+ */
+
+static void
+init_psymbol_list (objfile, total_symbols)
+ struct objfile *objfile;
+ int total_symbols;
+{
+ /* Free any previously allocated psymbol lists. */
+
+ if (objfile -> global_psymbols.list)
+ {
+ mfree (objfile -> md, (PTR)objfile -> global_psymbols.list);
+ }
+ if (objfile -> static_psymbols.list)
+ {
+ mfree (objfile -> md, (PTR)objfile -> static_psymbols.list);
+ }
+
+ /* Current best guess is that there are approximately a twentieth
+ of the total symbols (in a debugging file) are global or static
+ oriented symbols */
+
+ objfile -> global_psymbols.size = total_symbols / 10;
+ objfile -> static_psymbols.size = total_symbols / 10;
+ objfile -> global_psymbols.next =
+ objfile -> global_psymbols.list = (struct partial_symbol *)
+ xmmalloc (objfile -> md, objfile -> global_psymbols.size
+ * sizeof (struct partial_symbol));
+ objfile -> static_psymbols.next =
+ objfile -> static_psymbols.list = (struct partial_symbol *)
+ xmmalloc (objfile -> md, objfile -> static_psymbols.size
+ * sizeof (struct partial_symbol));
+}
+
+/*
+
+LOCAL FUNCTION
+
+ add_enum_psymbol -- add enumeration members to partial symbol table
+
+DESCRIPTION
+
+ Given pointer to a DIE that is known to be for an enumeration,
+ extract the symbolic names of the enumeration members and add
+ partial symbols for them.
+*/
+
+static void
+add_enum_psymbol (dip, objfile)
+ struct dieinfo *dip;
+ struct objfile *objfile;
+{
+ char *scan;
+ char *listend;
+ unsigned short blocksz;
+ int nbytes;
+
+ if ((scan = dip -> at_element_list) != NULL)
+ {
+ if (dip -> short_element_list)
+ {
+ nbytes = attribute_size (AT_short_element_list);
+ }
+ else
+ {
+ nbytes = attribute_size (AT_element_list);
+ }
+ blocksz = target_to_host (scan, nbytes, GET_UNSIGNED, objfile);
+ scan += nbytes;
+ listend = scan + blocksz;
+ while (scan < listend)
+ {
+ scan += TARGET_FT_LONG_SIZE (objfile);
+ ADD_PSYMBOL_TO_LIST (scan, strlen (scan), VAR_NAMESPACE, LOC_CONST,
+ objfile -> static_psymbols, 0, cu_language,
+ objfile);
+ scan += strlen (scan) + 1;
+ }
+ }
+}
+
+/*
+
+LOCAL FUNCTION
+
+ add_partial_symbol -- add symbol to partial symbol table
+
+DESCRIPTION
+
+ Given a DIE, if it is one of the types that we want to
+ add to a partial symbol table, finish filling in the die info
+ and then add a partial symbol table entry for it.
+
+NOTES
+
+ The caller must ensure that the DIE has a valid name attribute.
+*/
+
+static void
+add_partial_symbol (dip, objfile)
+ struct dieinfo *dip;
+ struct objfile *objfile;
+{
+ switch (dip -> die_tag)
+ {
+ case TAG_global_subroutine:
+ ADD_PSYMBOL_TO_LIST (dip -> at_name, strlen (dip -> at_name),
+ VAR_NAMESPACE, LOC_BLOCK,
+ objfile -> global_psymbols,
+ dip -> at_low_pc, cu_language, objfile);
+ break;
+ case TAG_global_variable:
+ ADD_PSYMBOL_TO_LIST (dip -> at_name, strlen (dip -> at_name),
+ VAR_NAMESPACE, LOC_STATIC,
+ objfile -> global_psymbols,
+ 0, cu_language, objfile);
+ break;
+ case TAG_subroutine:
+ ADD_PSYMBOL_TO_LIST (dip -> at_name, strlen (dip -> at_name),
+ VAR_NAMESPACE, LOC_BLOCK,
+ objfile -> static_psymbols,
+ dip -> at_low_pc, cu_language, objfile);
+ break;
+ case TAG_local_variable:
+ ADD_PSYMBOL_TO_LIST (dip -> at_name, strlen (dip -> at_name),
+ VAR_NAMESPACE, LOC_STATIC,
+ objfile -> static_psymbols,
+ 0, cu_language, objfile);
+ break;
+ case TAG_typedef:
+ ADD_PSYMBOL_TO_LIST (dip -> at_name, strlen (dip -> at_name),
+ VAR_NAMESPACE, LOC_TYPEDEF,
+ objfile -> static_psymbols,
+ 0, cu_language, objfile);
+ break;
+ case TAG_class_type:
+ case TAG_structure_type:
+ case TAG_union_type:
+ case TAG_enumeration_type:
+ /* Do not add opaque aggregate definitions to the psymtab. */
+ if (!dip -> has_at_byte_size)
+ break;
+ ADD_PSYMBOL_TO_LIST (dip -> at_name, strlen (dip -> at_name),
+ STRUCT_NAMESPACE, LOC_TYPEDEF,
+ objfile -> static_psymbols,
+ 0, cu_language, objfile);
+ if (cu_language == language_cplus)
+ {
+ /* For C++, these implicitly act as typedefs as well. */
+ ADD_PSYMBOL_TO_LIST (dip -> at_name, strlen (dip -> at_name),
+ VAR_NAMESPACE, LOC_TYPEDEF,
+ objfile -> static_psymbols,
+ 0, cu_language, objfile);
+ }
+ break;
+ }
+}
+
+/*
+
+LOCAL FUNCTION
+
+ scan_partial_symbols -- scan DIE's within a single compilation unit
+
+DESCRIPTION
+
+ Process the DIE's within a single compilation unit, looking for
+ interesting DIE's that contribute to the partial symbol table entry
+ for this compilation unit.
+
+NOTES
+
+ There are some DIE's that may appear both at file scope and within
+ the scope of a function. We are only interested in the ones at file
+ scope, and the only way to tell them apart is to keep track of the
+ scope. For example, consider the test case:
+
+ static int i;
+ main () { int j; }
+
+ for which the relevant DWARF segment has the structure:
+
+ 0x51:
+ 0x23 global subrtn sibling 0x9b
+ name main
+ fund_type FT_integer
+ low_pc 0x800004cc
+ high_pc 0x800004d4
+
+ 0x74:
+ 0x23 local var sibling 0x97
+ name j
+ fund_type FT_integer
+ location OP_BASEREG 0xe
+ OP_CONST 0xfffffffc
+ OP_ADD
+ 0x97:
+ 0x4
+
+ 0x9b:
+ 0x1d local var sibling 0xb8
+ name i
+ fund_type FT_integer
+ location OP_ADDR 0x800025dc
+
+ 0xb8:
+ 0x4
+
+ We want to include the symbol 'i' in the partial symbol table, but
+ not the symbol 'j'. In essence, we want to skip all the dies within
+ the scope of a TAG_global_subroutine DIE.
+
+ Don't attempt to add anonymous structures or unions since they have
+ no name. Anonymous enumerations however are processed, because we
+ want to extract their member names (the check for a tag name is
+ done later).
+
+ Also, for variables and subroutines, check that this is the place
+ where the actual definition occurs, rather than just a reference
+ to an external.
+ */
+
+static void
+scan_partial_symbols (thisdie, enddie, objfile)
+ char *thisdie;
+ char *enddie;
+ struct objfile *objfile;
+{
+ char *nextdie;
+ char *temp;
+ struct dieinfo di;
+
+ while (thisdie < enddie)
+ {
+ basicdieinfo (&di, thisdie, objfile);
+ if (di.die_length < SIZEOF_DIE_LENGTH)
+ {
+ break;
+ }
+ else
+ {
+ nextdie = thisdie + di.die_length;
+ /* To avoid getting complete die information for every die, we
+ only do it (below) for the cases we are interested in. */
+ switch (di.die_tag)
+ {
+ case TAG_global_subroutine:
+ case TAG_subroutine:
+ completedieinfo (&di, objfile);
+ if (di.at_name && (di.has_at_low_pc || di.at_location))
+ {
+ add_partial_symbol (&di, objfile);
+ /* If there is a sibling attribute, adjust the nextdie
+ pointer to skip the entire scope of the subroutine.
+ Apply some sanity checking to make sure we don't
+ overrun or underrun the range of remaining DIE's */
+ if (di.at_sibling != 0)
+ {
+ temp = dbbase + di.at_sibling - dbroff;
+ if ((temp < thisdie) || (temp >= enddie))
+ {
+ complain (&bad_die_ref, DIE_ID, DIE_NAME,
+ di.at_sibling);
+ }
+ else
+ {
+ nextdie = temp;
+ }
+ }
+ }
+ break;
+ case TAG_global_variable:
+ case TAG_local_variable:
+ completedieinfo (&di, objfile);
+ if (di.at_name && (di.has_at_low_pc || di.at_location))
+ {
+ add_partial_symbol (&di, objfile);
+ }
+ break;
+ case TAG_typedef:
+ case TAG_class_type:
+ case TAG_structure_type:
+ case TAG_union_type:
+ completedieinfo (&di, objfile);
+ if (di.at_name)
+ {
+ add_partial_symbol (&di, objfile);
+ }
+ break;
+ case TAG_enumeration_type:
+ completedieinfo (&di, objfile);
+ if (di.at_name)
+ {
+ add_partial_symbol (&di, objfile);
+ }
+ add_enum_psymbol (&di, objfile);
+ break;
+ }
+ }
+ thisdie = nextdie;
+ }
+}
+
+/*
+
+LOCAL FUNCTION
+
+ scan_compilation_units -- build a psymtab entry for each compilation
+
+DESCRIPTION
+
+ This is the top level dwarf parsing routine for building partial
+ symbol tables.
+
+ It scans from the beginning of the DWARF table looking for the first
+ TAG_compile_unit DIE, and then follows the sibling chain to locate
+ each additional TAG_compile_unit DIE.
+
+ For each TAG_compile_unit DIE it creates a partial symtab structure,
+ calls a subordinate routine to collect all the compilation unit's
+ global DIE's, file scope DIEs, typedef DIEs, etc, and then links the
+ new partial symtab structure into the partial symbol table. It also
+ records the appropriate information in the partial symbol table entry
+ to allow the chunk of DIE's and line number table for this compilation
+ unit to be located and re-read later, to generate a complete symbol
+ table entry for the compilation unit.
+
+ Thus it effectively partitions up a chunk of DIE's for multiple
+ compilation units into smaller DIE chunks and line number tables,
+ and associates them with a partial symbol table entry.
+
+NOTES
+
+ If any compilation unit has no line number table associated with
+ it for some reason (a missing at_stmt_list attribute, rather than
+ just one with a value of zero, which is valid) then we ensure that
+ the recorded file offset is zero so that the routine which later
+ reads line number table fragments knows that there is no fragment
+ to read.
+
+RETURNS
+
+ Returns no value.
+
+ */
+
+static void
+scan_compilation_units (thisdie, enddie, dbfoff, lnoffset, objfile)
+ char *thisdie;
+ char *enddie;
+ file_ptr dbfoff;
+ file_ptr lnoffset;
+ struct objfile *objfile;
+{
+ char *nextdie;
+ struct dieinfo di;
+ struct partial_symtab *pst;
+ int culength;
+ int curoff;
+ file_ptr curlnoffset;
+
+ while (thisdie < enddie)
+ {
+ basicdieinfo (&di, thisdie, objfile);
+ if (di.die_length < SIZEOF_DIE_LENGTH)
+ {
+ break;
+ }
+ else if (di.die_tag != TAG_compile_unit)
+ {
+ nextdie = thisdie + di.die_length;
+ }
+ else
+ {
+ completedieinfo (&di, objfile);
+ set_cu_language (&di);
+ if (di.at_sibling != 0)
+ {
+ nextdie = dbbase + di.at_sibling - dbroff;
+ }
+ else
+ {
+ nextdie = thisdie + di.die_length;
+ }
+ curoff = thisdie - dbbase;
+ culength = nextdie - thisdie;
+ curlnoffset = di.has_at_stmt_list ? lnoffset + di.at_stmt_list : 0;
+
+ /* First allocate a new partial symbol table structure */
+
+ pst = start_psymtab_common (objfile, base_section_offsets,
+ di.at_name, di.at_low_pc,
+ objfile -> global_psymbols.next,
+ objfile -> static_psymbols.next);
+
+ pst -> texthigh = di.at_high_pc;
+ pst -> read_symtab_private = (char *)
+ obstack_alloc (&objfile -> psymbol_obstack,
+ sizeof (struct dwfinfo));
+ DBFOFF (pst) = dbfoff;
+ DBROFF (pst) = curoff;
+ DBLENGTH (pst) = culength;
+ LNFOFF (pst) = curlnoffset;
+ pst -> read_symtab = dwarf_psymtab_to_symtab;
+
+ /* Now look for partial symbols */
+
+ scan_partial_symbols (thisdie + di.die_length, nextdie, objfile);
+
+ pst -> n_global_syms = objfile -> global_psymbols.next -
+ (objfile -> global_psymbols.list + pst -> globals_offset);
+ pst -> n_static_syms = objfile -> static_psymbols.next -
+ (objfile -> static_psymbols.list + pst -> statics_offset);
+ sort_pst_symbols (pst);
+ /* If there is already a psymtab or symtab for a file of this name,
+ remove it. (If there is a symtab, more drastic things also
+ happen.) This happens in VxWorks. */
+ free_named_symtabs (pst -> filename);
+ }
+ thisdie = nextdie;
+ }
+}
+
+/*
+
+LOCAL FUNCTION
+
+ new_symbol -- make a symbol table entry for a new symbol
+
+SYNOPSIS
+
+ static struct symbol *new_symbol (struct dieinfo *dip,
+ struct objfile *objfile)
+
+DESCRIPTION
+
+ Given a pointer to a DWARF information entry, figure out if we need
+ to make a symbol table entry for it, and if so, create a new entry
+ and return a pointer to it.
+ */
+
+static struct symbol *
+new_symbol (dip, objfile)
+ struct dieinfo *dip;
+ struct objfile *objfile;
+{
+ struct symbol *sym = NULL;
+
+ if (dip -> at_name != NULL)
+ {
+ sym = (struct symbol *) obstack_alloc (&objfile -> symbol_obstack,
+ sizeof (struct symbol));
+ memset (sym, 0, sizeof (struct symbol));
+ SYMBOL_NAME (sym) = create_name (dip -> at_name,
+ &objfile->symbol_obstack);
+ /* default assumptions */
+ SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE;
+ SYMBOL_CLASS (sym) = LOC_STATIC;
+ SYMBOL_TYPE (sym) = decode_die_type (dip);
+
+ /* If this symbol is from a C++ compilation, then attempt to cache the
+ demangled form for future reference. This is a typical time versus
+ space tradeoff, that was decided in favor of time because it sped up
+ C++ symbol lookups by a factor of about 20. */
+
+ SYMBOL_LANGUAGE (sym) = cu_language;
+ SYMBOL_INIT_DEMANGLED_NAME (sym, &objfile -> symbol_obstack);
+ switch (dip -> die_tag)
+ {
+ case TAG_label:
+ SYMBOL_VALUE (sym) = dip -> at_low_pc;
+ SYMBOL_CLASS (sym) = LOC_LABEL;
+ break;
+ case TAG_global_subroutine:
+ case TAG_subroutine:
+ SYMBOL_VALUE (sym) = dip -> at_low_pc;
+ SYMBOL_TYPE (sym) = lookup_function_type (SYMBOL_TYPE (sym));
+ SYMBOL_CLASS (sym) = LOC_BLOCK;
+ if (dip -> die_tag == TAG_global_subroutine)
+ {
+ add_symbol_to_list (sym, &global_symbols);
+ }
+ else
+ {
+ add_symbol_to_list (sym, list_in_scope);
+ }
+ break;
+ case TAG_global_variable:
+ if (dip -> at_location != NULL)
+ {
+ SYMBOL_VALUE (sym) = locval (dip -> at_location);
+ add_symbol_to_list (sym, &global_symbols);
+ SYMBOL_CLASS (sym) = LOC_STATIC;
+ SYMBOL_VALUE (sym) += baseaddr;
+ }
+ break;
+ case TAG_local_variable:
+ if (dip -> at_location != NULL)
+ {
+ SYMBOL_VALUE (sym) = locval (dip -> at_location);
+ add_symbol_to_list (sym, list_in_scope);
+ if (isreg)
+ {
+ SYMBOL_CLASS (sym) = LOC_REGISTER;
+ }
+ else if (offreg)
+ {
+ SYMBOL_CLASS (sym) = LOC_BASEREG;
+ SYMBOL_BASEREG (sym) = basereg;
+ }
+ else
+ {
+ SYMBOL_CLASS (sym) = LOC_STATIC;
+ SYMBOL_VALUE (sym) += baseaddr;
+ }
+ }
+ break;
+ case TAG_formal_parameter:
+ if (dip -> at_location != NULL)
+ {
+ SYMBOL_VALUE (sym) = locval (dip -> at_location);
+ }
+ add_symbol_to_list (sym, list_in_scope);
+ if (isreg)
+ {
+ SYMBOL_CLASS (sym) = LOC_REGPARM;
+ }
+ else if (offreg)
+ {
+ SYMBOL_CLASS (sym) = LOC_BASEREG_ARG;
+ SYMBOL_BASEREG (sym) = basereg;
+ }
+ else
+ {
+ SYMBOL_CLASS (sym) = LOC_ARG;
+ }
+ break;
+ case TAG_unspecified_parameters:
+ /* From varargs functions; gdb doesn't seem to have any interest in
+ this information, so just ignore it for now. (FIXME?) */
+ break;
+ case TAG_class_type:
+ case TAG_structure_type:
+ case TAG_union_type:
+ case TAG_enumeration_type:
+ SYMBOL_CLASS (sym) = LOC_TYPEDEF;
+ SYMBOL_NAMESPACE (sym) = STRUCT_NAMESPACE;
+ add_symbol_to_list (sym, list_in_scope);
+ break;
+ case TAG_typedef:
+ SYMBOL_CLASS (sym) = LOC_TYPEDEF;
+ SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE;
+ add_symbol_to_list (sym, list_in_scope);
+ break;
+ default:
+ /* Not a tag we recognize. Hopefully we aren't processing trash
+ data, but since we must specifically ignore things we don't
+ recognize, there is nothing else we should do at this point. */
+ break;
+ }
+ }
+ return (sym);
+}
+
+/*
+
+LOCAL FUNCTION
+
+ synthesize_typedef -- make a symbol table entry for a "fake" typedef
+
+SYNOPSIS
+
+ static void synthesize_typedef (struct dieinfo *dip,
+ struct objfile *objfile,
+ struct type *type);
+
+DESCRIPTION
+
+ Given a pointer to a DWARF information entry, synthesize a typedef
+ for the name in the DIE, using the specified type.
+
+ This is used for C++ class, structs, unions, and enumerations to
+ set up the tag name as a type.
+
+ */
+
+static void
+synthesize_typedef (dip, objfile, type)
+ struct dieinfo *dip;
+ struct objfile *objfile;
+ struct type *type;
+{
+ struct symbol *sym = NULL;
+
+ if (dip -> at_name != NULL)
+ {
+ sym = (struct symbol *)
+ obstack_alloc (&objfile -> symbol_obstack, sizeof (struct symbol));
+ memset (sym, 0, sizeof (struct symbol));
+ SYMBOL_NAME (sym) = create_name (dip -> at_name,
+ &objfile->symbol_obstack);
+ SYMBOL_INIT_LANGUAGE_SPECIFIC (sym, cu_language);
+ SYMBOL_TYPE (sym) = type;
+ SYMBOL_CLASS (sym) = LOC_TYPEDEF;
+ SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE;
+ add_symbol_to_list (sym, list_in_scope);
+ }
+}
+
+/*
+
+LOCAL FUNCTION
+
+ decode_mod_fund_type -- decode a modified fundamental type
+
+SYNOPSIS
+
+ static struct type *decode_mod_fund_type (char *typedata)
+
+DESCRIPTION
+
+ Decode a block of data containing a modified fundamental
+ type specification. TYPEDATA is a pointer to the block,
+ which starts with a length containing the size of the rest
+ of the block. At the end of the block is a fundmental type
+ code value that gives the fundamental type. Everything
+ in between are type modifiers.
+
+ We simply compute the number of modifiers and call the general
+ function decode_modified_type to do the actual work.
+*/
+
+static struct type *
+decode_mod_fund_type (typedata)
+ char *typedata;
+{
+ struct type *typep = NULL;
+ unsigned short modcount;
+ int nbytes;
+
+ /* Get the total size of the block, exclusive of the size itself */
+
+ nbytes = attribute_size (AT_mod_fund_type);
+ modcount = target_to_host (typedata, nbytes, GET_UNSIGNED, current_objfile);
+ typedata += nbytes;
+
+ /* Deduct the size of the fundamental type bytes at the end of the block. */
+
+ modcount -= attribute_size (AT_fund_type);
+
+ /* Now do the actual decoding */
+
+ typep = decode_modified_type (typedata, modcount, AT_mod_fund_type);
+ return (typep);
+}
+
+/*
+
+LOCAL FUNCTION
+
+ decode_mod_u_d_type -- decode a modified user defined type
+
+SYNOPSIS
+
+ static struct type *decode_mod_u_d_type (char *typedata)
+
+DESCRIPTION
+
+ Decode a block of data containing a modified user defined
+ type specification. TYPEDATA is a pointer to the block,
+ which consists of a two byte length, containing the size
+ of the rest of the block. At the end of the block is a
+ four byte value that gives a reference to a user defined type.
+ Everything in between are type modifiers.
+
+ We simply compute the number of modifiers and call the general
+ function decode_modified_type to do the actual work.
+*/
+
+static struct type *
+decode_mod_u_d_type (typedata)
+ char *typedata;
+{
+ struct type *typep = NULL;
+ unsigned short modcount;
+ int nbytes;
+
+ /* Get the total size of the block, exclusive of the size itself */
+
+ nbytes = attribute_size (AT_mod_u_d_type);
+ modcount = target_to_host (typedata, nbytes, GET_UNSIGNED, current_objfile);
+ typedata += nbytes;
+
+ /* Deduct the size of the reference type bytes at the end of the block. */
+
+ modcount -= attribute_size (AT_user_def_type);
+
+ /* Now do the actual decoding */
+
+ typep = decode_modified_type (typedata, modcount, AT_mod_u_d_type);
+ return (typep);
+}
+
+/*
+
+LOCAL FUNCTION
+
+ decode_modified_type -- decode modified user or fundamental type
+
+SYNOPSIS
+
+ static struct type *decode_modified_type (char *modifiers,
+ unsigned short modcount, int mtype)
+
+DESCRIPTION
+
+ Decode a modified type, either a modified fundamental type or
+ a modified user defined type. MODIFIERS is a pointer to the
+ block of bytes that define MODCOUNT modifiers. Immediately
+ following the last modifier is a short containing the fundamental
+ type or a long containing the reference to the user defined
+ type. Which one is determined by MTYPE, which is either
+ AT_mod_fund_type or AT_mod_u_d_type to indicate what modified
+ type we are generating.
+
+ We call ourself recursively to generate each modified type,`
+ until MODCOUNT reaches zero, at which point we have consumed
+ all the modifiers and generate either the fundamental type or
+ user defined type. When the recursion unwinds, each modifier
+ is applied in turn to generate the full modified type.
+
+NOTES
+
+ If we find a modifier that we don't recognize, and it is not one
+ of those reserved for application specific use, then we issue a
+ warning and simply ignore the modifier.
+
+BUGS
+
+ We currently ignore MOD_const and MOD_volatile. (FIXME)
+
+ */
+
+static struct type *
+decode_modified_type (modifiers, modcount, mtype)
+ char *modifiers;
+ unsigned int modcount;
+ int mtype;
+{
+ struct type *typep = NULL;
+ unsigned short fundtype;
+ DIE_REF die_ref;
+ char modifier;
+ int nbytes;
+
+ if (modcount == 0)
+ {
+ switch (mtype)
+ {
+ case AT_mod_fund_type:
+ nbytes = attribute_size (AT_fund_type);
+ fundtype = target_to_host (modifiers, nbytes, GET_UNSIGNED,
+ current_objfile);
+ typep = decode_fund_type (fundtype);
+ break;
+ case AT_mod_u_d_type:
+ nbytes = attribute_size (AT_user_def_type);
+ die_ref = target_to_host (modifiers, nbytes, GET_UNSIGNED,
+ current_objfile);
+ if ((typep = lookup_utype (die_ref)) == NULL)
+ {
+ typep = alloc_utype (die_ref, NULL);
+ }
+ break;
+ default:
+ complain (&botched_modified_type, DIE_ID, DIE_NAME, mtype);
+ typep = dwarf_fundamental_type (current_objfile, FT_INTEGER);
+ break;
+ }
+ }
+ else
+ {
+ modifier = *modifiers++;
+ typep = decode_modified_type (modifiers, --modcount, mtype);
+ switch (modifier)
+ {
+ case MOD_pointer_to:
+ typep = lookup_pointer_type (typep);
+ break;
+ case MOD_reference_to:
+ typep = lookup_reference_type (typep);
+ break;
+ case MOD_const:
+ complain (&const_ignored, DIE_ID, DIE_NAME); /* FIXME */
+ break;
+ case MOD_volatile:
+ complain (&volatile_ignored, DIE_ID, DIE_NAME); /* FIXME */
+ break;
+ default:
+ if (!(MOD_lo_user <= (unsigned char) modifier
+ && (unsigned char) modifier <= MOD_hi_user))
+ {
+ complain (&unknown_type_modifier, DIE_ID, DIE_NAME, modifier);
+ }
+ break;
+ }
+ }
+ return (typep);
+}
+
+/*
+
+LOCAL FUNCTION
+
+ decode_fund_type -- translate basic DWARF type to gdb base type
+
+DESCRIPTION
+
+ Given an integer that is one of the fundamental DWARF types,
+ translate it to one of the basic internal gdb types and return
+ a pointer to the appropriate gdb type (a "struct type *").
+
+NOTES
+
+ For robustness, if we are asked to translate a fundamental
+ type that we are unprepared to deal with, we return int so
+ callers can always depend upon a valid type being returned,
+ and so gdb may at least do something reasonable by default.
+ If the type is not in the range of those types defined as
+ application specific types, we also issue a warning.
+*/
+
+static struct type *
+decode_fund_type (fundtype)
+ unsigned int fundtype;
+{
+ struct type *typep = NULL;
+
+ switch (fundtype)
+ {
+
+ case FT_void:
+ typep = dwarf_fundamental_type (current_objfile, FT_VOID);
+ break;
+
+ case FT_boolean: /* Was FT_set in AT&T version */
+ typep = dwarf_fundamental_type (current_objfile, FT_BOOLEAN);
+ break;
+
+ case FT_pointer: /* (void *) */
+ typep = dwarf_fundamental_type (current_objfile, FT_VOID);
+ typep = lookup_pointer_type (typep);
+ break;
+
+ case FT_char:
+ typep = dwarf_fundamental_type (current_objfile, FT_CHAR);
+ break;
+
+ case FT_signed_char:
+ typep = dwarf_fundamental_type (current_objfile, FT_SIGNED_CHAR);
+ break;
+
+ case FT_unsigned_char:
+ typep = dwarf_fundamental_type (current_objfile, FT_UNSIGNED_CHAR);
+ break;
+
+ case FT_short:
+ typep = dwarf_fundamental_type (current_objfile, FT_SHORT);
+ break;
+
+ case FT_signed_short:
+ typep = dwarf_fundamental_type (current_objfile, FT_SIGNED_SHORT);
+ break;
+
+ case FT_unsigned_short:
+ typep = dwarf_fundamental_type (current_objfile, FT_UNSIGNED_SHORT);
+ break;
+
+ case FT_integer:
+ typep = dwarf_fundamental_type (current_objfile, FT_INTEGER);
+ break;
+
+ case FT_signed_integer:
+ typep = dwarf_fundamental_type (current_objfile, FT_SIGNED_INTEGER);
+ break;
+
+ case FT_unsigned_integer:
+ typep = dwarf_fundamental_type (current_objfile, FT_UNSIGNED_INTEGER);
+ break;
+
+ case FT_long:
+ typep = dwarf_fundamental_type (current_objfile, FT_LONG);
+ break;
+
+ case FT_signed_long:
+ typep = dwarf_fundamental_type (current_objfile, FT_SIGNED_LONG);
+ break;
+
+ case FT_unsigned_long:
+ typep = dwarf_fundamental_type (current_objfile, FT_UNSIGNED_LONG);
+ break;
+
+ case FT_long_long:
+ typep = dwarf_fundamental_type (current_objfile, FT_LONG_LONG);
+ break;
+
+ case FT_signed_long_long:
+ typep = dwarf_fundamental_type (current_objfile, FT_SIGNED_LONG_LONG);
+ break;
+
+ case FT_unsigned_long_long:
+ typep = dwarf_fundamental_type (current_objfile, FT_UNSIGNED_LONG_LONG);
+ break;
+
+ case FT_float:
+ typep = dwarf_fundamental_type (current_objfile, FT_FLOAT);
+ break;
+
+ case FT_dbl_prec_float:
+ typep = dwarf_fundamental_type (current_objfile, FT_DBL_PREC_FLOAT);
+ break;
+
+ case FT_ext_prec_float:
+ typep = dwarf_fundamental_type (current_objfile, FT_EXT_PREC_FLOAT);
+ break;
+
+ case FT_complex:
+ typep = dwarf_fundamental_type (current_objfile, FT_COMPLEX);
+ break;
+
+ case FT_dbl_prec_complex:
+ typep = dwarf_fundamental_type (current_objfile, FT_DBL_PREC_COMPLEX);
+ break;
+
+ case FT_ext_prec_complex:
+ typep = dwarf_fundamental_type (current_objfile, FT_EXT_PREC_COMPLEX);
+ break;
+
+ }
+
+ if (typep == NULL)
+ {
+ typep = dwarf_fundamental_type (current_objfile, FT_INTEGER);
+ if (!(FT_lo_user <= fundtype && fundtype <= FT_hi_user))
+ {
+ complain (&unexpected_fund_type, DIE_ID, DIE_NAME, fundtype);
+ }
+ }
+
+ return (typep);
+}
+
+/*
+
+LOCAL FUNCTION
+
+ create_name -- allocate a fresh copy of a string on an obstack
+
+DESCRIPTION
+
+ Given a pointer to a string and a pointer to an obstack, allocates
+ a fresh copy of the string on the specified obstack.
+
+*/
+
+static char *
+create_name (name, obstackp)
+ char *name;
+ struct obstack *obstackp;
+{
+ int length;
+ char *newname;
+
+ length = strlen (name) + 1;
+ newname = (char *) obstack_alloc (obstackp, length);
+ strcpy (newname, name);
+ return (newname);
+}
+
+/*
+
+LOCAL FUNCTION
+
+ basicdieinfo -- extract the minimal die info from raw die data
+
+SYNOPSIS
+
+ void basicdieinfo (char *diep, struct dieinfo *dip,
+ struct objfile *objfile)
+
+DESCRIPTION
+
+ Given a pointer to raw DIE data, and a pointer to an instance of a
+ die info structure, this function extracts the basic information
+ from the DIE data required to continue processing this DIE, along
+ with some bookkeeping information about the DIE.
+
+ The information we absolutely must have includes the DIE tag,
+ and the DIE length. If we need the sibling reference, then we
+ will have to call completedieinfo() to process all the remaining
+ DIE information.
+
+ Note that since there is no guarantee that the data is properly
+ aligned in memory for the type of access required (indirection
+ through anything other than a char pointer), and there is no
+ guarantee that it is in the same byte order as the gdb host,
+ we call a function which deals with both alignment and byte
+ swapping issues. Possibly inefficient, but quite portable.
+
+ We also take care of some other basic things at this point, such
+ as ensuring that the instance of the die info structure starts
+ out completely zero'd and that curdie is initialized for use
+ in error reporting if we have a problem with the current die.
+
+NOTES
+
+ All DIE's must have at least a valid length, thus the minimum
+ DIE size is SIZEOF_DIE_LENGTH. In order to have a valid tag, the
+ DIE size must be at least SIZEOF_DIE_TAG larger, otherwise they
+ are forced to be TAG_padding DIES.
+
+ Padding DIES must be at least SIZEOF_DIE_LENGTH in length, implying
+ that if a padding DIE is used for alignment and the amount needed is
+ less than SIZEOF_DIE_LENGTH, then the padding DIE has to be big
+ enough to align to the next alignment boundry.
+
+ We do some basic sanity checking here, such as verifying that the
+ length of the die would not cause it to overrun the recorded end of
+ the buffer holding the DIE info. If we find a DIE that is either
+ too small or too large, we force it's length to zero which should
+ cause the caller to take appropriate action.
+ */
+
+static void
+basicdieinfo (dip, diep, objfile)
+ struct dieinfo *dip;
+ char *diep;
+ struct objfile *objfile;
+{
+ curdie = dip;
+ memset (dip, 0, sizeof (struct dieinfo));
+ dip -> die = diep;
+ dip -> die_ref = dbroff + (diep - dbbase);
+ dip -> die_length = target_to_host (diep, SIZEOF_DIE_LENGTH, GET_UNSIGNED,
+ objfile);
+ if ((dip -> die_length < SIZEOF_DIE_LENGTH) ||
+ ((diep + dip -> die_length) > (dbbase + dbsize)))
+ {
+ complain (&malformed_die, DIE_ID, DIE_NAME, dip -> die_length);
+ dip -> die_length = 0;
+ }
+ else if (dip -> die_length < (SIZEOF_DIE_LENGTH + SIZEOF_DIE_TAG))
+ {
+ dip -> die_tag = TAG_padding;
+ }
+ else
+ {
+ diep += SIZEOF_DIE_LENGTH;
+ dip -> die_tag = target_to_host (diep, SIZEOF_DIE_TAG, GET_UNSIGNED,
+ objfile);
+ }
+}
+
+/*
+
+LOCAL FUNCTION
+
+ completedieinfo -- finish reading the information for a given DIE
+
+SYNOPSIS
+
+ void completedieinfo (struct dieinfo *dip, struct objfile *objfile)
+
+DESCRIPTION
+
+ Given a pointer to an already partially initialized die info structure,
+ scan the raw DIE data and finish filling in the die info structure
+ from the various attributes found.
+
+ Note that since there is no guarantee that the data is properly
+ aligned in memory for the type of access required (indirection
+ through anything other than a char pointer), and there is no
+ guarantee that it is in the same byte order as the gdb host,
+ we call a function which deals with both alignment and byte
+ swapping issues. Possibly inefficient, but quite portable.
+
+NOTES
+
+ Each time we are called, we increment the diecount variable, which
+ keeps an approximate count of the number of dies processed for
+ each compilation unit. This information is presented to the user
+ if the info_verbose flag is set.
+
+ */
+
+static void
+completedieinfo (dip, objfile)
+ struct dieinfo *dip;
+ struct objfile *objfile;
+{
+ char *diep; /* Current pointer into raw DIE data */
+ char *end; /* Terminate DIE scan here */
+ unsigned short attr; /* Current attribute being scanned */
+ unsigned short form; /* Form of the attribute */
+ int nbytes; /* Size of next field to read */
+
+ diecount++;
+ diep = dip -> die;
+ end = diep + dip -> die_length;
+ diep += SIZEOF_DIE_LENGTH + SIZEOF_DIE_TAG;
+ while (diep < end)
+ {
+ attr = target_to_host (diep, SIZEOF_ATTRIBUTE, GET_UNSIGNED, objfile);
+ diep += SIZEOF_ATTRIBUTE;
+ if ((nbytes = attribute_size (attr)) == -1)
+ {
+ complain (&unknown_attribute_length, DIE_ID, DIE_NAME);
+ diep = end;
+ continue;
+ }
+ switch (attr)
+ {
+ case AT_fund_type:
+ dip -> at_fund_type = target_to_host (diep, nbytes, GET_UNSIGNED,
+ objfile);
+ break;
+ case AT_ordering:
+ dip -> at_ordering = target_to_host (diep, nbytes, GET_UNSIGNED,
+ objfile);
+ break;
+ case AT_bit_offset:
+ dip -> at_bit_offset = target_to_host (diep, nbytes, GET_UNSIGNED,
+ objfile);
+ break;
+ case AT_sibling:
+ dip -> at_sibling = target_to_host (diep, nbytes, GET_UNSIGNED,
+ objfile);
+ break;
+ case AT_stmt_list:
+ dip -> at_stmt_list = target_to_host (diep, nbytes, GET_UNSIGNED,
+ objfile);
+ dip -> has_at_stmt_list = 1;
+ break;
+ case AT_low_pc:
+ dip -> at_low_pc = target_to_host (diep, nbytes, GET_UNSIGNED,
+ objfile);
+ dip -> at_low_pc += baseaddr;
+ dip -> has_at_low_pc = 1;
+ break;
+ case AT_high_pc:
+ dip -> at_high_pc = target_to_host (diep, nbytes, GET_UNSIGNED,
+ objfile);
+ dip -> at_high_pc += baseaddr;
+ break;
+ case AT_language:
+ dip -> at_language = target_to_host (diep, nbytes, GET_UNSIGNED,
+ objfile);
+ break;
+ case AT_user_def_type:
+ dip -> at_user_def_type = target_to_host (diep, nbytes,
+ GET_UNSIGNED, objfile);
+ break;
+ case AT_byte_size:
+ dip -> at_byte_size = target_to_host (diep, nbytes, GET_UNSIGNED,
+ objfile);
+ dip -> has_at_byte_size = 1;
+ break;
+ case AT_bit_size:
+ dip -> at_bit_size = target_to_host (diep, nbytes, GET_UNSIGNED,
+ objfile);
+ break;
+ case AT_member:
+ dip -> at_member = target_to_host (diep, nbytes, GET_UNSIGNED,
+ objfile);
+ break;
+ case AT_discr:
+ dip -> at_discr = target_to_host (diep, nbytes, GET_UNSIGNED,
+ objfile);
+ break;
+ case AT_location:
+ dip -> at_location = diep;
+ break;
+ case AT_mod_fund_type:
+ dip -> at_mod_fund_type = diep;
+ break;
+ case AT_subscr_data:
+ dip -> at_subscr_data = diep;
+ break;
+ case AT_mod_u_d_type:
+ dip -> at_mod_u_d_type = diep;
+ break;
+ case AT_element_list:
+ dip -> at_element_list = diep;
+ dip -> short_element_list = 0;
+ break;
+ case AT_short_element_list:
+ dip -> at_element_list = diep;
+ dip -> short_element_list = 1;
+ break;
+ case AT_discr_value:
+ dip -> at_discr_value = diep;
+ break;
+ case AT_string_length:
+ dip -> at_string_length = diep;
+ break;
+ case AT_name:
+ dip -> at_name = diep;
+ break;
+ case AT_comp_dir:
+ /* For now, ignore any "hostname:" portion, since gdb doesn't
+ know how to deal with it. (FIXME). */
+ dip -> at_comp_dir = strrchr (diep, ':');
+ if (dip -> at_comp_dir != NULL)
+ {
+ dip -> at_comp_dir++;
+ }
+ else
+ {
+ dip -> at_comp_dir = diep;
+ }
+ break;
+ case AT_producer:
+ dip -> at_producer = diep;
+ break;
+ case AT_start_scope:
+ dip -> at_start_scope = target_to_host (diep, nbytes, GET_UNSIGNED,
+ objfile);
+ break;
+ case AT_stride_size:
+ dip -> at_stride_size = target_to_host (diep, nbytes, GET_UNSIGNED,
+ objfile);
+ break;
+ case AT_src_info:
+ dip -> at_src_info = target_to_host (diep, nbytes, GET_UNSIGNED,
+ objfile);
+ break;
+ case AT_prototyped:
+ dip -> at_prototyped = diep;
+ break;
+ default:
+ /* Found an attribute that we are unprepared to handle. However
+ it is specifically one of the design goals of DWARF that
+ consumers should ignore unknown attributes. As long as the
+ form is one that we recognize (so we know how to skip it),
+ we can just ignore the unknown attribute. */
+ break;
+ }
+ form = FORM_FROM_ATTR (attr);
+ switch (form)
+ {
+ case FORM_DATA2:
+ diep += 2;
+ break;
+ case FORM_DATA4:
+ case FORM_REF:
+ diep += 4;
+ break;
+ case FORM_DATA8:
+ diep += 8;
+ break;
+ case FORM_ADDR:
+ diep += TARGET_FT_POINTER_SIZE (objfile);
+ break;
+ case FORM_BLOCK2:
+ diep += 2 + target_to_host (diep, nbytes, GET_UNSIGNED, objfile);
+ break;
+ case FORM_BLOCK4:
+ diep += 4 + target_to_host (diep, nbytes, GET_UNSIGNED, objfile);
+ break;
+ case FORM_STRING:
+ diep += strlen (diep) + 1;
+ break;
+ default:
+ complain (&unknown_attribute_form, DIE_ID, DIE_NAME, form);
+ diep = end;
+ break;
+ }
+ }
+}
+
+/*
+
+LOCAL FUNCTION
+
+ target_to_host -- swap in target data to host
+
+SYNOPSIS
+
+ target_to_host (char *from, int nbytes, int signextend,
+ struct objfile *objfile)
+
+DESCRIPTION
+
+ Given pointer to data in target format in FROM, a byte count for
+ the size of the data in NBYTES, a flag indicating whether or not
+ the data is signed in SIGNEXTEND, and a pointer to the current
+ objfile in OBJFILE, convert the data to host format and return
+ the converted value.
+
+NOTES
+
+ FIXME: If we read data that is known to be signed, and expect to
+ use it as signed data, then we need to explicitly sign extend the
+ result until the bfd library is able to do this for us.
+
+ */
+
+static unsigned long
+target_to_host (from, nbytes, signextend, objfile)
+ char *from;
+ int nbytes;
+ int signextend; /* FIXME: Unused */
+ struct objfile *objfile;
+{
+ unsigned long rtnval;
+
+ switch (nbytes)
+ {
+ case 8:
+ rtnval = bfd_get_64 (objfile -> obfd, (bfd_byte *) from);
+ break;
+ case 4:
+ rtnval = bfd_get_32 (objfile -> obfd, (bfd_byte *) from);
+ break;
+ case 2:
+ rtnval = bfd_get_16 (objfile -> obfd, (bfd_byte *) from);
+ break;
+ case 1:
+ rtnval = bfd_get_8 (objfile -> obfd, (bfd_byte *) from);
+ break;
+ default:
+ complain (&no_bfd_get_N, DIE_ID, DIE_NAME, nbytes);
+ rtnval = 0;
+ break;
+ }
+ return (rtnval);
+}
+
+/*
+
+LOCAL FUNCTION
+
+ attribute_size -- compute size of data for a DWARF attribute
+
+SYNOPSIS
+
+ static int attribute_size (unsigned int attr)
+
+DESCRIPTION
+
+ Given a DWARF attribute in ATTR, compute the size of the first
+ piece of data associated with this attribute and return that
+ size.
+
+ Returns -1 for unrecognized attributes.
+
+ */
+
+static int
+attribute_size (attr)
+ unsigned int attr;
+{
+ int nbytes; /* Size of next data for this attribute */
+ unsigned short form; /* Form of the attribute */
+
+ form = FORM_FROM_ATTR (attr);
+ switch (form)
+ {
+ case FORM_STRING: /* A variable length field is next */
+ nbytes = 0;
+ break;
+ case FORM_DATA2: /* Next 2 byte field is the data itself */
+ case FORM_BLOCK2: /* Next 2 byte field is a block length */
+ nbytes = 2;
+ break;
+ case FORM_DATA4: /* Next 4 byte field is the data itself */
+ case FORM_BLOCK4: /* Next 4 byte field is a block length */
+ case FORM_REF: /* Next 4 byte field is a DIE offset */
+ nbytes = 4;
+ break;
+ case FORM_DATA8: /* Next 8 byte field is the data itself */
+ nbytes = 8;
+ break;
+ case FORM_ADDR: /* Next field size is target sizeof(void *) */
+ nbytes = TARGET_FT_POINTER_SIZE (objfile);
+ break;
+ default:
+ complain (&unknown_attribute_form, DIE_ID, DIE_NAME, form);
+ nbytes = -1;
+ break;
+ }
+ return (nbytes);
+}
diff --git a/gnu/usr.bin/gdb/gdb/elf/common.h b/gnu/usr.bin/gdb/gdb/elf/common.h
new file mode 100644
index 0000000..58c5117
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/elf/common.h
@@ -0,0 +1,227 @@
+/* ELF support for BFD.
+ Copyright (C) 1991, 1992, 1993, 1994 Free Software Foundation, Inc.
+
+ Written by Fred Fish @ Cygnus Support, from information published
+ in "UNIX System V Release 4, Programmers Guide: ANSI C and
+ Programming Support Tools".
+
+This file is part of BFD, the Binary File Descriptor library.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+
+/* This file is part of ELF support for BFD, and contains the portions
+ that are common to both the internal and external representations.
+ For example, ELFMAG0 is the byte 0x7F in both the internal (in-memory)
+ and external (in-file) representations. */
+
+
+/* Fields in e_ident[] */
+
+#define EI_MAG0 0 /* File identification byte 0 index */
+#define ELFMAG0 0x7F /* Magic number byte 0 */
+
+#define EI_MAG1 1 /* File identification byte 1 index */
+#define ELFMAG1 'E' /* Magic number byte 1 */
+
+#define EI_MAG2 2 /* File identification byte 2 index */
+#define ELFMAG2 'L' /* Magic number byte 2 */
+
+#define EI_MAG3 3 /* File identification byte 3 index */
+#define ELFMAG3 'F' /* Magic number byte 3 */
+
+#define EI_CLASS 4 /* File class */
+#define ELFCLASSNONE 0 /* Invalid class */
+#define ELFCLASS32 1 /* 32-bit objects */
+#define ELFCLASS64 2 /* 64-bit objects */
+
+#define EI_DATA 5 /* Data encoding */
+#define ELFDATANONE 0 /* Invalid data encoding */
+#define ELFDATA2LSB 1 /* 2's complement, little endian */
+#define ELFDATA2MSB 2 /* 2's complement, big endian */
+
+#define EI_VERSION 6 /* File version */
+
+#define EI_PAD 7 /* Start of padding bytes */
+
+
+/* Values for e_type, which identifies the object file type */
+
+#define ET_NONE 0 /* No file type */
+#define ET_REL 1 /* Relocatable file */
+#define ET_EXEC 2 /* Executable file */
+#define ET_DYN 3 /* Shared object file */
+#define ET_CORE 4 /* Core file */
+#define ET_LOPROC 0xFF00 /* Processor-specific */
+#define ET_HIPROC 0xFFFF /* Processor-specific */
+
+/* Values for e_machine, which identifies the architecture */
+
+#define EM_NONE 0 /* No machine */
+#define EM_M32 1 /* AT&T WE 32100 */
+#define EM_SPARC 2 /* SUN SPARC */
+#define EM_386 3 /* Intel 80386 */
+#define EM_68K 4 /* Motorola m68k family */
+#define EM_88K 5 /* Motorola m88k family */
+#define EM_860 7 /* Intel 80860 */
+#define EM_MIPS 8 /* MIPS R3000 (officially, big-endian only) */
+
+#define EM_MIPS_RS4_BE 10 /* MIPS R4000 big-endian */
+
+#define EM_SPARC64 11 /* SPARC v9 (not official) 64-bit */
+
+#define EM_PARISC 15 /* HPPA */
+
+/* If it is necessary to assign new unofficial EM_* values, please pick large
+ random numbers (0x8523, 0xa7f2, etc.) to minimize the chances of collision
+ with official or non-GNU unofficial values. */
+
+/* Cygnus PowerPC ELF backend. Written in the absence of an ABI. */
+#define EM_CYGNUS_POWERPC 0x9025
+
+/* Values for e_version */
+
+#define EV_NONE 0 /* Invalid ELF version */
+#define EV_CURRENT 1 /* Current version */
+
+/* Values for program header, p_type field */
+
+#define PT_NULL 0 /* Program header table entry unused */
+#define PT_LOAD 1 /* Loadable program segment */
+#define PT_DYNAMIC 2 /* Dynamic linking information */
+#define PT_INTERP 3 /* Program interpreter */
+#define PT_NOTE 4 /* Auxiliary information */
+#define PT_SHLIB 5 /* Reserved, unspecified semantics */
+#define PT_PHDR 6 /* Entry for header table itself */
+#define PT_LOPROC 0x70000000 /* Processor-specific */
+#define PT_HIPROC 0x7FFFFFFF /* Processor-specific */
+
+/* Program segment permissions, in program header p_flags field */
+
+#define PF_X (1 << 0) /* Segment is executable */
+#define PF_W (1 << 1) /* Segment is writable */
+#define PF_R (1 << 2) /* Segment is readable */
+#define PF_MASKPROC 0xF0000000 /* Processor-specific reserved bits */
+
+/* Values for section header, sh_type field */
+
+#define SHT_NULL 0 /* Section header table entry unused */
+#define SHT_PROGBITS 1 /* Program specific (private) data */
+#define SHT_SYMTAB 2 /* Link editing symbol table */
+#define SHT_STRTAB 3 /* A string table */
+#define SHT_RELA 4 /* Relocation entries with addends */
+#define SHT_HASH 5 /* A symbol hash table */
+#define SHT_DYNAMIC 6 /* Information for dynamic linking */
+#define SHT_NOTE 7 /* Information that marks file */
+#define SHT_NOBITS 8 /* Section occupies no space in file */
+#define SHT_REL 9 /* Relocation entries, no addends */
+#define SHT_SHLIB 10 /* Reserved, unspecified semantics */
+#define SHT_DYNSYM 11 /* Dynamic linking symbol table */
+#define SHT_LOPROC 0x70000000 /* Processor-specific semantics, lo */
+#define SHT_HIPROC 0x7FFFFFFF /* Processor-specific semantics, hi */
+#define SHT_LOUSER 0x80000000 /* Application-specific semantics */
+#define SHT_HIUSER 0x8FFFFFFF /* Application-specific semantics */
+
+/* Values for section header, sh_flags field */
+
+#define SHF_WRITE (1 << 0) /* Writable data during execution */
+#define SHF_ALLOC (1 << 1) /* Occupies memory during execution */
+#define SHF_EXECINSTR (1 << 2) /* Executable machine instructions */
+#define SHF_MASKPROC 0xF0000000 /* Processor-specific semantics */
+
+/* Values of note segment descriptor types for core files. */
+
+#define NT_PRSTATUS 1 /* Contains copy of prstatus struct */
+#define NT_FPREGSET 2 /* Contains copy of fpregset struct */
+#define NT_PRPSINFO 3 /* Contains copy of prpsinfo struct */
+
+/* Values of note segment descriptor types for object files. */
+/* (Only for hppa right now. Should this be moved elsewhere?) */
+
+#define NT_VERSION 1 /* Contains a version string. */
+
+/* These three macros disassemble and assemble a symbol table st_info field,
+ which contains the symbol binding and symbol type. The STB_ and STT_
+ defines identify the binding and type. */
+
+#define ELF_ST_BIND(val) (((unsigned int)(val)) >> 4)
+#define ELF_ST_TYPE(val) ((val) & 0xF)
+#define ELF_ST_INFO(bind,type) (((bind) << 4) + ((type) & 0xF))
+
+#define STN_UNDEF 0 /* undefined symbol index */
+
+#define STB_LOCAL 0 /* Symbol not visible outside obj */
+#define STB_GLOBAL 1 /* Symbol visible outside obj */
+#define STB_WEAK 2 /* Like globals, lower precedence */
+#define STB_LOPROC 13 /* Application-specific semantics */
+#define STB_HIPROC 15 /* Application-specific semantics */
+
+#define STT_NOTYPE 0 /* Symbol type is unspecified */
+#define STT_OBJECT 1 /* Symbol is a data object */
+#define STT_FUNC 2 /* Symbol is a code object */
+#define STT_SECTION 3 /* Symbol associated with a section */
+#define STT_FILE 4 /* Symbol gives a file name */
+#define STT_LOPROC 13 /* Application-specific semantics */
+#define STT_HIPROC 15 /* Application-specific semantics */
+
+/* Special section indices, which may show up in st_shndx fields, among
+ other places. */
+
+#define SHN_UNDEF 0 /* Undefined section reference */
+#define SHN_LORESERVE 0xFF00 /* Begin range of reserved indices */
+#define SHN_LOPROC 0xFF00 /* Begin range of appl-specific */
+#define SHN_HIPROC 0xFF1F /* End range of appl-specific */
+#define SHN_ABS 0xFFF1 /* Associated symbol is absolute */
+#define SHN_COMMON 0xFFF2 /* Associated symbol is in common */
+#define SHN_HIRESERVE 0xFFFF /* End range of reserved indices */
+
+/* relocation info handling macros */
+
+#define ELF32_R_SYM(i) ((i) >> 8)
+#define ELF32_R_TYPE(i) ((i) & 0xff)
+#define ELF32_R_INFO(s,t) (((s) << 8) + ((t) & 0xff))
+
+#define ELF64_R_SYM(i) ((i) >> 32)
+#define ELF64_R_TYPE(i) ((i) & 0xffffffff)
+#define ELF64_R_INFO(s,t) (((bfd_vma) (s) << 32) + (bfd_vma) (t))
+
+/* Dynamic section tags */
+
+#define DT_NULL 0
+#define DT_NEEDED 1
+#define DT_PLTRELSZ 2
+#define DT_PLTGOT 3
+#define DT_HASH 4
+#define DT_STRTAB 5
+#define DT_SYMTAB 6
+#define DT_RELA 7
+#define DT_RELASZ 8
+#define DT_RELAENT 9
+#define DT_STRSZ 10
+#define DT_SYMENT 11
+#define DT_INIT 12
+#define DT_FINI 13
+#define DT_SONAME 14
+#define DT_RPATH 15
+#define DT_SYMBOLIC 16
+#define DT_REL 17
+#define DT_RELSZ 18
+#define DT_RELENT 19
+#define DT_PLTREL 20
+#define DT_DEBUG 21
+#define DT_TEXTREL 22
+#define DT_JMPREL 23
+#define DT_LOPROC 0x70000000
+#define DT_HIPROC 0x7fffffff
diff --git a/gnu/usr.bin/gdb/gdb/elf/dwarf.h b/gnu/usr.bin/gdb/gdb/elf/dwarf.h
new file mode 100644
index 0000000..3590576
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/elf/dwarf.h
@@ -0,0 +1,314 @@
+/* Declarations and definitions of codes relating to the DWARF symbolic
+ debugging information format.
+
+ Written by Ron Guilmette (rfg@ncd.com)
+
+Copyright (C) 1992 Free Software Foundation, Inc.
+
+This file is part of GNU CC.
+
+GNU CC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU CC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* This file is derived from the DWARF specification (a public document)
+ Revision 1.0.1 (April 8, 1992) developed by the UNIX International
+ Programming Languages Special Interest Group (UI/PLSIG) and distributed
+ by UNIX International. Copies of this specification are available from
+ UNIX International, 20 Waterview Boulevard, Parsippany, NJ, 07054.
+*/
+
+/* Tag names and codes. */
+
+enum dwarf_tag {
+ TAG_padding = 0x0000,
+ TAG_array_type = 0x0001,
+ TAG_class_type = 0x0002,
+ TAG_entry_point = 0x0003,
+ TAG_enumeration_type = 0x0004,
+ TAG_formal_parameter = 0x0005,
+ TAG_global_subroutine = 0x0006,
+ TAG_global_variable = 0x0007,
+ /* 0x0008 -- reserved */
+ /* 0x0009 -- reserved */
+ TAG_label = 0x000a,
+ TAG_lexical_block = 0x000b,
+ TAG_local_variable = 0x000c,
+ TAG_member = 0x000d,
+ /* 0x000e -- reserved */
+ TAG_pointer_type = 0x000f,
+ TAG_reference_type = 0x0010,
+ TAG_compile_unit = 0x0011,
+ TAG_string_type = 0x0012,
+ TAG_structure_type = 0x0013,
+ TAG_subroutine = 0x0014,
+ TAG_subroutine_type = 0x0015,
+ TAG_typedef = 0x0016,
+ TAG_union_type = 0x0017,
+ TAG_unspecified_parameters = 0x0018,
+ TAG_variant = 0x0019,
+ TAG_common_block = 0x001a,
+ TAG_common_inclusion = 0x001b,
+ TAG_inheritance = 0x001c,
+ TAG_inlined_subroutine = 0x001d,
+ TAG_module = 0x001e,
+ TAG_ptr_to_member_type = 0x001f,
+ TAG_set_type = 0x0020,
+ TAG_subrange_type = 0x0021,
+ TAG_with_stmt = 0x0022,
+
+ /* GNU extensions */
+
+ TAG_format_label = 0x8000, /* for FORTRAN 77 and Fortran 90 */
+ TAG_namelist = 0x8001, /* For Fortran 90 */
+ TAG_function_template = 0x8002, /* for C++ */
+ TAG_class_template = 0x8003 /* for C++ */
+};
+
+#define TAG_lo_user 0x8000 /* implementation-defined range start */
+#define TAG_hi_user 0xffff /* implementation-defined range end */
+#define TAG_source_file TAG_compile_unit /* for backward compatibility */
+
+/* Form names and codes. */
+
+enum dwarf_form {
+ FORM_ADDR = 0x1,
+ FORM_REF = 0x2,
+ FORM_BLOCK2 = 0x3,
+ FORM_BLOCK4 = 0x4,
+ FORM_DATA2 = 0x5,
+ FORM_DATA4 = 0x6,
+ FORM_DATA8 = 0x7,
+ FORM_STRING = 0x8
+};
+
+/* Attribute names and codes. */
+
+enum dwarf_attribute {
+ AT_sibling = (0x0010|FORM_REF),
+ AT_location = (0x0020|FORM_BLOCK2),
+ AT_name = (0x0030|FORM_STRING),
+ AT_fund_type = (0x0050|FORM_DATA2),
+ AT_mod_fund_type = (0x0060|FORM_BLOCK2),
+ AT_user_def_type = (0x0070|FORM_REF),
+ AT_mod_u_d_type = (0x0080|FORM_BLOCK2),
+ AT_ordering = (0x0090|FORM_DATA2),
+ AT_subscr_data = (0x00a0|FORM_BLOCK2),
+ AT_byte_size = (0x00b0|FORM_DATA4),
+ AT_bit_offset = (0x00c0|FORM_DATA2),
+ AT_bit_size = (0x00d0|FORM_DATA4),
+ /* (0x00e0|FORM_xxxx) -- reserved */
+ AT_element_list = (0x00f0|FORM_BLOCK4),
+ AT_stmt_list = (0x0100|FORM_DATA4),
+ AT_low_pc = (0x0110|FORM_ADDR),
+ AT_high_pc = (0x0120|FORM_ADDR),
+ AT_language = (0x0130|FORM_DATA4),
+ AT_member = (0x0140|FORM_REF),
+ AT_discr = (0x0150|FORM_REF),
+ AT_discr_value = (0x0160|FORM_BLOCK2),
+ /* (0x0170|FORM_xxxx) -- reserved */
+ /* (0x0180|FORM_xxxx) -- reserved */
+ AT_string_length = (0x0190|FORM_BLOCK2),
+ AT_common_reference = (0x01a0|FORM_REF),
+ AT_comp_dir = (0x01b0|FORM_STRING),
+ AT_const_value_string = (0x01c0|FORM_STRING),
+ AT_const_value_data2 = (0x01c0|FORM_DATA2),
+ AT_const_value_data4 = (0x01c0|FORM_DATA4),
+ AT_const_value_data8 = (0x01c0|FORM_DATA8),
+ AT_const_value_block2 = (0x01c0|FORM_BLOCK2),
+ AT_const_value_block4 = (0x01c0|FORM_BLOCK4),
+ AT_containing_type = (0x01d0|FORM_REF),
+ AT_default_value_addr = (0x01e0|FORM_ADDR),
+ AT_default_value_data2 = (0x01e0|FORM_DATA2),
+ AT_default_value_data4 = (0x01e0|FORM_DATA4),
+ AT_default_value_data8 = (0x01e0|FORM_DATA8),
+ AT_default_value_string = (0x01e0|FORM_STRING),
+ AT_friends = (0x01f0|FORM_BLOCK2),
+ AT_inline = (0x0200|FORM_STRING),
+ AT_is_optional = (0x0210|FORM_STRING),
+ AT_lower_bound_ref = (0x0220|FORM_REF),
+ AT_lower_bound_data2 = (0x0220|FORM_DATA2),
+ AT_lower_bound_data4 = (0x0220|FORM_DATA4),
+ AT_lower_bound_data8 = (0x0220|FORM_DATA8),
+ AT_private = (0x0240|FORM_STRING),
+ AT_producer = (0x0250|FORM_STRING),
+ AT_program = (0x0230|FORM_STRING),
+ AT_protected = (0x0260|FORM_STRING),
+ AT_prototyped = (0x0270|FORM_STRING),
+ AT_public = (0x0280|FORM_STRING),
+ AT_pure_virtual = (0x0290|FORM_STRING),
+ AT_return_addr = (0x02a0|FORM_BLOCK2),
+ AT_abstract_origin = (0x02b0|FORM_REF),
+ AT_start_scope = (0x02c0|FORM_DATA4),
+ AT_stride_size = (0x02e0|FORM_DATA4),
+ AT_upper_bound_ref = (0x02f0|FORM_REF),
+ AT_upper_bound_data2 = (0x02f0|FORM_DATA2),
+ AT_upper_bound_data4 = (0x02f0|FORM_DATA4),
+ AT_upper_bound_data8 = (0x02f0|FORM_DATA8),
+ AT_virtual = (0x0300|FORM_STRING),
+
+ /* GNU extensions. */
+
+ AT_sf_names = (0x8000|FORM_DATA4),
+ AT_src_info = (0x8010|FORM_DATA4),
+ AT_mac_info = (0x8020|FORM_DATA4),
+ AT_src_coords = (0x8030|FORM_DATA4),
+ AT_body_begin = (0x8040|FORM_ADDR),
+ AT_body_end = (0x8050|FORM_ADDR)
+};
+
+#define AT_lo_user 0x8000 /* implementation-defined range start */
+#define AT_hi_user 0xffff /* implementation-defined range end */
+
+/* Location atom names and codes. */
+
+enum dwarf_location_atom {
+ OP_REG = 0x01,
+ OP_BASEREG = 0x02,
+ OP_ADDR = 0x03,
+ OP_CONST = 0x04,
+ OP_DEREF2 = 0x05,
+ OP_DEREF4 = 0x06,
+ OP_ADD = 0x07
+};
+
+#define OP_LO_USER 0x80 /* implementation-defined range start */
+#define OP_HI_USER 0xff /* implementation-defined range end */
+
+/* Fundamental type names and codes. */
+
+enum dwarf_fundamental_type {
+ FT_char = 0x0001,
+ FT_signed_char = 0x0002,
+ FT_unsigned_char = 0x0003,
+ FT_short = 0x0004,
+ FT_signed_short = 0x0005,
+ FT_unsigned_short = 0x0006,
+ FT_integer = 0x0007,
+ FT_signed_integer = 0x0008,
+ FT_unsigned_integer = 0x0009,
+ FT_long = 0x000a,
+ FT_signed_long = 0x000b,
+ FT_unsigned_long = 0x000c,
+ FT_pointer = 0x000d, /* an alias for (void *) */
+ FT_float = 0x000e,
+ FT_dbl_prec_float = 0x000f,
+ FT_ext_prec_float = 0x0010, /* breaks "classic" svr4 SDB */
+ FT_complex = 0x0011, /* breaks "classic" svr4 SDB */
+ FT_dbl_prec_complex = 0x0012, /* breaks "classic" svr4 SDB */
+ /* 0x0013 -- reserved */
+ FT_void = 0x0014,
+ FT_boolean = 0x0015, /* breaks "classic" svr4 SDB */
+ FT_ext_prec_complex = 0x0016, /* breaks "classic" svr4 SDB */
+ FT_label = 0x0017,
+
+ /* GNU extensions
+ The low order byte must indicate the size (in bytes) for the type.
+ All of these types will probably break "classic" svr4 SDB */
+
+ FT_long_long = 0x8008,
+ FT_signed_long_long = 0x8108,
+ FT_unsigned_long_long = 0x8208,
+
+ FT_int8 = 0x9001,
+ FT_signed_int8 = 0x9101,
+ FT_unsigned_int8 = 0x9201,
+ FT_int16 = 0x9302,
+ FT_signed_int16 = 0x9402,
+ FT_unsigned_int16 = 0x9502,
+ FT_int32 = 0x9604,
+ FT_signed_int32 = 0x9704,
+ FT_unsigned_int32 = 0x9804,
+ FT_int64 = 0x9908,
+ FT_signed_int64 = 0x9a08,
+ FT_unsigned_int64 = 0x9b08,
+
+ FT_real32 = 0xa004,
+ FT_real64 = 0xa108,
+ FT_real96 = 0xa20c,
+ FT_real128 = 0xa310
+};
+
+#define FT_lo_user 0x8000 /* implementation-defined range start */
+#define FT_hi_user 0xffff /* implementation defined range end */
+
+/* Type modifier names and codes. */
+
+enum dwarf_type_modifier {
+ MOD_pointer_to = 0x01,
+ MOD_reference_to = 0x02,
+ MOD_const = 0x03,
+ MOD_volatile = 0x04
+};
+
+#define MOD_lo_user 0x80 /* implementation-defined range start */
+#define MOD_hi_user 0xff /* implementation-defined range end */
+
+/* Array ordering names and codes. */
+
+enum dwarf_array_dim_ordering {
+ ORD_row_major = 0,
+ ORD_col_major = 1
+};
+
+/* Array subscript format names and codes. */
+
+enum dwarf_subscr_data_formats {
+ FMT_FT_C_C = 0x0,
+ FMT_FT_C_X = 0x1,
+ FMT_FT_X_C = 0x2,
+ FMT_FT_X_X = 0x3,
+ FMT_UT_C_C = 0x4,
+ FMT_UT_C_X = 0x5,
+ FMT_UT_X_C = 0x6,
+ FMT_UT_X_X = 0x7,
+ FMT_ET = 0x8
+};
+
+/* Derived from above for ease of use. */
+
+#define FMT_CODE(_FUNDAMENTAL_TYPE_P, _UB_CONST_P, _LB_CONST_P) \
+ (((_FUNDAMENTAL_TYPE_P) ? 0 : 4) \
+ | ((_UB_CONST_P) ? 0 : 2) \
+ | ((_LB_CONST_P) ? 0 : 1))
+
+/* Source language names and codes. */
+
+enum dwarf_source_language {
+ LANG_C89 = 0x00000001,
+ LANG_C = 0x00000002,
+ LANG_ADA83 = 0x00000003,
+ LANG_C_PLUS_PLUS = 0x00000004,
+ LANG_COBOL74 = 0x00000005,
+ LANG_COBOL85 = 0x00000006,
+ LANG_FORTRAN77 = 0x00000007,
+ LANG_FORTRAN90 = 0x00000008,
+ LANG_PASCAL83 = 0x00000009,
+ LANG_MODULA2 = 0x0000000a,
+
+ /* GNU extensions */
+
+ LANG_CHILL = 0x00009af3 /* random value for GNU Chill */
+};
+
+#define LANG_lo_user 0x00008000 /* implementation-defined range start */
+#define LANG_hi_user 0x0000ffff /* implementation-defined range end */
+
+/* Names and codes for GNU "macinfo" extension. */
+
+enum dwarf_macinfo_record_type {
+ MACINFO_start = 's',
+ MACINFO_resume = 'r',
+ MACINFO_define = 'd',
+ MACINFO_undef = 'u'
+};
diff --git a/gnu/usr.bin/gdb/gdb/elf/external.h b/gnu/usr.bin/gdb/gdb/elf/external.h
new file mode 100644
index 0000000..3e9e53c
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/elf/external.h
@@ -0,0 +1,190 @@
+/* ELF support for BFD.
+ Copyright (C) 1991, 1992 Free Software Foundation, Inc.
+
+ Written by Fred Fish @ Cygnus Support, from information published
+ in "UNIX System V Release 4, Programmers Guide: ANSI C and
+ Programming Support Tools".
+
+This file is part of BFD, the Binary File Descriptor library.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+
+/* This file is part of ELF support for BFD, and contains the portions
+ that describe how ELF is represented externally by the BFD library.
+ I.E. it describes the in-file representation of ELF. It requires
+ the elf-common.h file which contains the portions that are common to
+ both the internal and external representations. */
+
+/* The 64-bit stuff is kind of random. Perhaps someone will publish a
+ spec someday. */
+
+/* ELF Header (32-bit implementations) */
+
+typedef struct {
+ unsigned char e_ident[16]; /* ELF "magic number" */
+ unsigned char e_type[2]; /* Identifies object file type */
+ unsigned char e_machine[2]; /* Specifies required architecture */
+ unsigned char e_version[4]; /* Identifies object file version */
+ unsigned char e_entry[4]; /* Entry point virtual address */
+ unsigned char e_phoff[4]; /* Program header table file offset */
+ unsigned char e_shoff[4]; /* Section header table file offset */
+ unsigned char e_flags[4]; /* Processor-specific flags */
+ unsigned char e_ehsize[2]; /* ELF header size in bytes */
+ unsigned char e_phentsize[2]; /* Program header table entry size */
+ unsigned char e_phnum[2]; /* Program header table entry count */
+ unsigned char e_shentsize[2]; /* Section header table entry size */
+ unsigned char e_shnum[2]; /* Section header table entry count */
+ unsigned char e_shstrndx[2]; /* Section header string table index */
+} Elf32_External_Ehdr;
+
+typedef struct {
+ unsigned char e_ident[16]; /* ELF "magic number" */
+ unsigned char e_type[2]; /* Identifies object file type */
+ unsigned char e_machine[2]; /* Specifies required architecture */
+ unsigned char e_version[4]; /* Identifies object file version */
+ unsigned char e_entry[8]; /* Entry point virtual address */
+ unsigned char e_phoff[8]; /* Program header table file offset */
+ unsigned char e_shoff[8]; /* Section header table file offset */
+ unsigned char e_flags[4]; /* Processor-specific flags */
+ unsigned char e_ehsize[2]; /* ELF header size in bytes */
+ unsigned char e_phentsize[2]; /* Program header table entry size */
+ unsigned char e_phnum[2]; /* Program header table entry count */
+ unsigned char e_shentsize[2]; /* Section header table entry size */
+ unsigned char e_shnum[2]; /* Section header table entry count */
+ unsigned char e_shstrndx[2]; /* Section header string table index */
+} Elf64_External_Ehdr;
+
+/* Program header */
+
+typedef struct {
+ unsigned char p_type[4]; /* Identifies program segment type */
+ unsigned char p_offset[4]; /* Segment file offset */
+ unsigned char p_vaddr[4]; /* Segment virtual address */
+ unsigned char p_paddr[4]; /* Segment physical address */
+ unsigned char p_filesz[4]; /* Segment size in file */
+ unsigned char p_memsz[4]; /* Segment size in memory */
+ unsigned char p_flags[4]; /* Segment flags */
+ unsigned char p_align[4]; /* Segment alignment, file & memory */
+} Elf32_External_Phdr;
+
+typedef struct {
+ unsigned char p_type[4]; /* Identifies program segment type */
+ unsigned char p_flags[4]; /* Segment flags */
+ unsigned char p_offset[8]; /* Segment file offset */
+ unsigned char p_vaddr[8]; /* Segment virtual address */
+ unsigned char p_paddr[8]; /* Segment physical address */
+ unsigned char p_filesz[8]; /* Segment size in file */
+ unsigned char p_memsz[8]; /* Segment size in memory */
+ unsigned char p_align[8]; /* Segment alignment, file & memory */
+} Elf64_External_Phdr;
+
+/* Section header */
+
+typedef struct {
+ unsigned char sh_name[4]; /* Section name, index in string tbl */
+ unsigned char sh_type[4]; /* Type of section */
+ unsigned char sh_flags[4]; /* Miscellaneous section attributes */
+ unsigned char sh_addr[4]; /* Section virtual addr at execution */
+ unsigned char sh_offset[4]; /* Section file offset */
+ unsigned char sh_size[4]; /* Size of section in bytes */
+ unsigned char sh_link[4]; /* Index of another section */
+ unsigned char sh_info[4]; /* Additional section information */
+ unsigned char sh_addralign[4]; /* Section alignment */
+ unsigned char sh_entsize[4]; /* Entry size if section holds table */
+} Elf32_External_Shdr;
+
+typedef struct {
+ unsigned char sh_name[4]; /* Section name, index in string tbl */
+ unsigned char sh_type[4]; /* Type of section */
+ unsigned char sh_flags[8]; /* Miscellaneous section attributes */
+ unsigned char sh_addr[8]; /* Section virtual addr at execution */
+ unsigned char sh_offset[8]; /* Section file offset */
+ unsigned char sh_size[8]; /* Size of section in bytes */
+ unsigned char sh_link[4]; /* Index of another section */
+ unsigned char sh_info[4]; /* Additional section information */
+ unsigned char sh_addralign[8]; /* Section alignment */
+ unsigned char sh_entsize[8]; /* Entry size if section holds table */
+} Elf64_External_Shdr;
+
+/* Symbol table entry */
+
+typedef struct {
+ unsigned char st_name[4]; /* Symbol name, index in string tbl */
+ unsigned char st_value[4]; /* Value of the symbol */
+ unsigned char st_size[4]; /* Associated symbol size */
+ unsigned char st_info[1]; /* Type and binding attributes */
+ unsigned char st_other[1]; /* No defined meaning, 0 */
+ unsigned char st_shndx[2]; /* Associated section index */
+} Elf32_External_Sym;
+
+typedef struct {
+ unsigned char st_name[4]; /* Symbol name, index in string tbl */
+ unsigned char st_info[1]; /* Type and binding attributes */
+ unsigned char st_other[1]; /* No defined meaning, 0 */
+ unsigned char st_shndx[2]; /* Associated section index */
+ unsigned char st_value[8]; /* Value of the symbol */
+ unsigned char st_size[8]; /* Associated symbol size */
+} Elf64_External_Sym;
+
+/* Note segments */
+
+typedef struct {
+ unsigned char namesz[4]; /* Size of entry's owner string */
+ unsigned char descsz[4]; /* Size of the note descriptor */
+ unsigned char type[4]; /* Interpretation of the descriptor */
+ char name[1]; /* Start of the name+desc data */
+} Elf_External_Note;
+
+/* Relocation Entries */
+typedef struct {
+ unsigned char r_offset[4]; /* Location at which to apply the action */
+ unsigned char r_info[4]; /* index and type of relocation */
+} Elf32_External_Rel;
+
+typedef struct {
+ unsigned char r_offset[4]; /* Location at which to apply the action */
+ unsigned char r_info[4]; /* index and type of relocation */
+ unsigned char r_addend[4]; /* Constant addend used to compute value */
+} Elf32_External_Rela;
+
+typedef struct {
+ unsigned char r_offset[8]; /* Location at which to apply the action */
+ unsigned char r_info[8]; /* index and type of relocation */
+} Elf64_External_Rel;
+
+typedef struct {
+ unsigned char r_offset[8]; /* Location at which to apply the action */
+ unsigned char r_info[8]; /* index and type of relocation */
+ unsigned char r_addend[8]; /* Constant addend used to compute value */
+} Elf64_External_Rela;
+
+/* dynamic section structure */
+
+typedef struct {
+ unsigned char d_tag[4]; /* entry tag value */
+ union {
+ unsigned char d_val[4];
+ unsigned char d_ptr[4];
+ } d_un;
+} Elf32_External_Dyn;
+
+typedef struct {
+ unsigned char d_tag[8]; /* entry tag value */
+ union {
+ unsigned char d_val[8];
+ unsigned char d_ptr[8];
+ } d_un;
+} Elf64_External_Dyn;
diff --git a/gnu/usr.bin/gdb/gdb/elf/internal.h b/gnu/usr.bin/gdb/gdb/elf/internal.h
new file mode 100644
index 0000000..da12bdb
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/elf/internal.h
@@ -0,0 +1,174 @@
+/* ELF support for BFD.
+ Copyright (C) 1991, 1992, 1993, 1994 Free Software Foundation, Inc.
+
+ Written by Fred Fish @ Cygnus Support, from information published
+ in "UNIX System V Release 4, Programmers Guide: ANSI C and
+ Programming Support Tools".
+
+This file is part of BFD, the Binary File Descriptor library.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+
+/* This file is part of ELF support for BFD, and contains the portions
+ that describe how ELF is represented internally in the BFD library.
+ I.E. it describes the in-memory representation of ELF. It requires
+ the elf-common.h file which contains the portions that are common to
+ both the internal and external representations. */
+
+
+/* NOTE that these structures are not kept in the same order as they appear
+ in the object file. In some cases they've been reordered for more optimal
+ packing under various circumstances. */
+
+/* ELF Header */
+
+#define EI_NIDENT 16 /* Size of e_ident[] */
+
+typedef struct elf_internal_ehdr {
+ unsigned char e_ident[EI_NIDENT]; /* ELF "magic number" */
+ bfd_vma e_entry; /* Entry point virtual address */
+ bfd_signed_vma e_phoff; /* Program header table file offset */
+ bfd_signed_vma e_shoff; /* Section header table file offset */
+ unsigned long e_version; /* Identifies object file version */
+ unsigned long e_flags; /* Processor-specific flags */
+ unsigned short e_type; /* Identifies object file type */
+ unsigned short e_machine; /* Specifies required architecture */
+ unsigned short e_ehsize; /* ELF header size in bytes */
+ unsigned short e_phentsize; /* Program header table entry size */
+ unsigned short e_phnum; /* Program header table entry count */
+ unsigned short e_shentsize; /* Section header table entry size */
+ unsigned short e_shnum; /* Section header table entry count */
+ unsigned short e_shstrndx; /* Section header string table index */
+} Elf_Internal_Ehdr;
+
+#define elf32_internal_ehdr elf_internal_ehdr
+#define Elf32_Internal_Ehdr Elf_Internal_Ehdr
+#define elf64_internal_ehdr elf_internal_ehdr
+#define Elf64_Internal_Ehdr Elf_Internal_Ehdr
+
+/* Program header */
+
+struct elf_internal_phdr {
+ unsigned long p_type; /* Identifies program segment type */
+ unsigned long p_flags; /* Segment flags */
+ bfd_vma p_offset; /* Segment file offset */
+ bfd_vma p_vaddr; /* Segment virtual address */
+ bfd_vma p_paddr; /* Segment physical address */
+ bfd_vma p_filesz; /* Segment size in file */
+ bfd_vma p_memsz; /* Segment size in memory */
+ bfd_vma p_align; /* Segment alignment, file & memory */
+};
+
+typedef struct elf_internal_phdr Elf_Internal_Phdr;
+#define elf32_internal_phdr elf_internal_phdr
+#define Elf32_Internal_Phdr Elf_Internal_Phdr
+#define elf64_internal_phdr elf_internal_phdr
+#define Elf64_Internal_Phdr Elf_Internal_Phdr
+
+/* Section header */
+
+typedef struct elf_internal_shdr {
+ unsigned int sh_name; /* Section name, index in string tbl */
+ unsigned int sh_type; /* Type of section */
+ bfd_vma sh_flags; /* Miscellaneous section attributes */
+ bfd_vma sh_addr; /* Section virtual addr at execution */
+ bfd_size_type sh_size; /* Size of section in bytes */
+ bfd_size_type sh_entsize; /* Entry size if section holds table */
+ unsigned long sh_link; /* Index of another section */
+ unsigned long sh_info; /* Additional section information */
+ file_ptr sh_offset; /* Section file offset */
+ unsigned int sh_addralign; /* Section alignment */
+
+ /* The internal rep also has some cached info associated with it. */
+ PTR rawdata; /* null if unused... */
+ PTR contents; /* null if unused... */
+ bfd_vma size; /* size of contents (0 if unused) */
+} Elf_Internal_Shdr;
+
+#define elf32_internal_shdr elf_internal_shdr
+#define Elf32_Internal_Shdr Elf_Internal_Shdr
+#define elf64_internal_shdr elf_internal_shdr
+#define Elf64_Internal_Shdr Elf_Internal_Shdr
+
+/* Symbol table entry */
+
+struct elf_internal_sym {
+ bfd_vma st_value; /* Value of the symbol */
+ bfd_vma st_size; /* Associated symbol size */
+ unsigned long st_name; /* Symbol name, index in string tbl */
+ unsigned char st_info; /* Type and binding attributes */
+ unsigned char st_other; /* No defined meaning, 0 */
+ unsigned short st_shndx; /* Associated section index */
+};
+
+typedef struct elf_internal_sym Elf_Internal_Sym;
+
+#define elf32_internal_sym elf_internal_sym
+#define elf64_internal_sym elf_internal_sym
+#define Elf32_Internal_Sym Elf_Internal_Sym
+#define Elf64_Internal_Sym Elf_Internal_Sym
+
+/* Note segments */
+
+typedef struct elf_internal_note {
+ unsigned long namesz; /* Size of entry's owner string */
+ unsigned long descsz; /* Size of the note descriptor */
+ unsigned long type; /* Interpretation of the descriptor */
+ char name[1]; /* Start of the name+desc data */
+} Elf_Internal_Note;
+#define Elf32_Internal_Note Elf_Internal_Note
+#define elf32_internal_note elf_internal_note
+
+/* Relocation Entries */
+
+typedef struct elf_internal_rel {
+ bfd_vma r_offset; /* Location at which to apply the action */
+ /* This needs to support 64-bit values in elf64. */
+ bfd_vma r_info; /* index and type of relocation */
+} Elf_Internal_Rel;
+
+#define elf32_internal_rel elf_internal_rel
+#define Elf32_Internal_Rel Elf_Internal_Rel
+#define elf64_internal_rel elf_internal_rel
+#define Elf64_Internal_Rel Elf_Internal_Rel
+
+typedef struct elf_internal_rela {
+ bfd_vma r_offset; /* Location at which to apply the action */
+ bfd_vma r_info; /* Index and Type of relocation */
+ bfd_signed_vma r_addend; /* Constant addend used to compute value */
+} Elf_Internal_Rela;
+
+#define elf32_internal_rela elf_internal_rela
+#define elf64_internal_rela elf_internal_rela
+#define Elf32_Internal_Rela Elf_Internal_Rela
+#define Elf64_Internal_Rela Elf_Internal_Rela
+
+/* dynamic section structure */
+
+typedef struct elf_internal_dyn {
+ /* This needs to support 64-bit values in elf64. */
+ bfd_vma d_tag; /* entry tag value */
+ union {
+ /* This needs to support 64-bit values in elf64. */
+ bfd_vma d_val;
+ bfd_vma d_ptr;
+ } d_un;
+} Elf_Internal_Dyn;
+
+#define elf32_internal_dyn elf_internal_dyn
+#define elf64_internal_dyn elf_internal_dyn
+#define Elf32_Internal_Dyn Elf_Internal_Dyn
+#define Elf64_Internal_Dyn Elf_Internal_Dyn
diff --git a/gnu/usr.bin/gdb/gdb/elfread.c b/gnu/usr.bin/gdb/gdb/elfread.c
new file mode 100644
index 0000000..47a3de1
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/elfread.c
@@ -0,0 +1,805 @@
+/* Read ELF (Executable and Linking Format) object files for GDB.
+ Copyright 1991, 1992, 1993, 1994 Free Software Foundation, Inc.
+ Written by Fred Fish at Cygnus Support.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "defs.h"
+#include "bfd.h"
+#include <string.h>
+#include "libelf.h"
+/*#include "elf/mips.h"*/
+#include "symtab.h"
+#include "symfile.h"
+#include "objfiles.h"
+#include "buildsym.h"
+#include "stabsread.h"
+#include "gdb-stabs.h"
+#include "complaints.h"
+#include "demangle.h"
+
+/* The struct elfinfo is available only during ELF symbol table and
+ psymtab reading. It is destroyed at the complation of psymtab-reading.
+ It's local to elf_symfile_read. */
+
+struct elfinfo {
+ file_ptr dboffset; /* Offset to dwarf debug section */
+ unsigned int dbsize; /* Size of dwarf debug section */
+ file_ptr lnoffset; /* Offset to dwarf line number section */
+ unsigned int lnsize; /* Size of dwarf line number section */
+ asection *stabsect; /* Section pointer for .stab section */
+ asection *stabindexsect; /* Section pointer for .stab.index section */
+ asection *mdebugsect; /* Section pointer for .mdebug section */
+};
+
+/* Various things we might complain about... */
+
+struct complaint section_info_complaint =
+ {"elf/stab section information %s without a preceding file symbol", 0, 0};
+
+struct complaint section_info_dup_complaint =
+ {"duplicated elf/stab section information for %s", 0, 0};
+
+struct complaint stab_info_mismatch_complaint =
+ {"elf/stab section information missing for %s", 0, 0};
+
+struct complaint stab_info_questionable_complaint =
+ {"elf/stab section information questionable for %s", 0, 0};
+
+static void
+elf_symfile_init PARAMS ((struct objfile *));
+
+static void
+elf_new_init PARAMS ((struct objfile *));
+
+static void
+elf_symfile_read PARAMS ((struct objfile *, struct section_offsets *, int));
+
+static void
+elf_symfile_finish PARAMS ((struct objfile *));
+
+static void
+elf_symtab_read PARAMS ((bfd *, CORE_ADDR, struct objfile *, int));
+
+static void
+free_elfinfo PARAMS ((void *));
+
+static struct section_offsets *
+elf_symfile_offsets PARAMS ((struct objfile *, CORE_ADDR));
+
+static void
+record_minimal_symbol_and_info PARAMS ((char *, CORE_ADDR,
+ enum minimal_symbol_type, char *,
+ struct objfile *));
+
+static void
+elf_locate_sections PARAMS ((bfd *, asection *, void *));
+
+/* We are called once per section from elf_symfile_read. We
+ need to examine each section we are passed, check to see
+ if it is something we are interested in processing, and
+ if so, stash away some access information for the section.
+
+ For now we recognize the dwarf debug information sections and
+ line number sections from matching their section names. The
+ ELF definition is no real help here since it has no direct
+ knowledge of DWARF (by design, so any debugging format can be
+ used).
+
+ We also recognize the ".stab" sections used by the Sun compilers
+ released with Solaris 2.
+
+ FIXME: The section names should not be hardwired strings (what
+ should they be? I don't think most object file formats have enough
+ section flags to specify what kind of debug section it is
+ -kingdon). */
+
+static void
+elf_locate_sections (ignore_abfd, sectp, eip)
+ bfd *ignore_abfd;
+ asection *sectp;
+ PTR eip;
+{
+ register struct elfinfo *ei;
+
+ ei = (struct elfinfo *) eip;
+ if (STREQ (sectp -> name, ".debug"))
+ {
+ ei -> dboffset = sectp -> filepos;
+ ei -> dbsize = bfd_get_section_size_before_reloc (sectp);
+ }
+ else if (STREQ (sectp -> name, ".line"))
+ {
+ ei -> lnoffset = sectp -> filepos;
+ ei -> lnsize = bfd_get_section_size_before_reloc (sectp);
+ }
+ else if (STREQ (sectp -> name, ".stab"))
+ {
+ ei -> stabsect = sectp;
+ }
+ else if (STREQ (sectp -> name, ".stab.index"))
+ {
+ ei -> stabindexsect = sectp;
+ }
+ else if (STREQ (sectp -> name, ".mdebug"))
+ {
+ ei -> mdebugsect = sectp;
+ }
+}
+
+#if 0 /* Currently unused */
+
+char *
+elf_interpreter (abfd)
+ bfd *abfd;
+{
+ sec_ptr interp_sec;
+ unsigned size;
+ char *interp = NULL;
+
+ interp_sec = bfd_get_section_by_name (abfd, ".interp");
+ if (interp_sec)
+ {
+ size = bfd_section_size (abfd, interp_sec);
+ interp = alloca (size);
+ if (bfd_get_section_contents (abfd, interp_sec, interp, (file_ptr)0,
+ size))
+ {
+ interp = savestring (interp, size - 1);
+ }
+ else
+ {
+ interp = NULL;
+ }
+ }
+ return (interp);
+}
+
+#endif
+
+static void
+record_minimal_symbol_and_info (name, address, ms_type, info, objfile)
+ char *name;
+ CORE_ADDR address;
+ enum minimal_symbol_type ms_type;
+ char *info; /* FIXME, is this really char *? */
+ struct objfile *objfile;
+{
+ int section;
+
+ /* Guess the section from the type. This is likely to be wrong in
+ some cases. */
+ switch (ms_type)
+ {
+ case mst_text:
+ case mst_file_text:
+ section = SECT_OFF_TEXT;
+#ifdef SMASH_TEXT_ADDRESS
+ SMASH_TEXT_ADDRESS (address);
+#endif
+ break;
+ case mst_data:
+ case mst_file_data:
+ section = SECT_OFF_DATA;
+ break;
+ case mst_bss:
+ case mst_file_bss:
+ section = SECT_OFF_BSS;
+ break;
+ default:
+ section = -1;
+ break;
+ }
+
+ name = obsavestring (name, strlen (name), &objfile -> symbol_obstack);
+ prim_record_minimal_symbol_and_info (name, address, ms_type, info, section,
+ objfile);
+}
+
+/*
+
+LOCAL FUNCTION
+
+ elf_symtab_read -- read the symbol table of an ELF file
+
+SYNOPSIS
+
+ void elf_symtab_read (bfd *abfd, CORE_ADDR addr,
+ struct objfile *objfile)
+
+DESCRIPTION
+
+ Given an open bfd, a base address to relocate symbols to, and a
+ flag that specifies whether or not this bfd is for an executable
+ or not (may be shared library for example), add all the global
+ function and data symbols to the minimal symbol table.
+
+ In stabs-in-ELF, as implemented by Sun, there are some local symbols
+ defined in the ELF symbol table, which can be used to locate
+ the beginnings of sections from each ".o" file that was linked to
+ form the executable objfile. We gather any such info and record it
+ in data structures hung off the objfile's private data.
+
+*/
+
+static void
+elf_symtab_read (abfd, addr, objfile, dynamic)
+ bfd *abfd;
+ CORE_ADDR addr;
+ struct objfile *objfile;
+ int dynamic;
+{
+ long storage_needed;
+ asymbol *sym;
+ asymbol **symbol_table;
+ long number_of_symbols;
+ long i;
+ int index;
+ struct cleanup *back_to;
+ CORE_ADDR symaddr;
+ enum minimal_symbol_type ms_type;
+ /* If sectinfo is nonNULL, it contains section info that should end up
+ filed in the objfile. */
+ struct stab_section_info *sectinfo = NULL;
+ /* If filesym is nonzero, it points to a file symbol, but we haven't
+ seen any section info for it yet. */
+ asymbol *filesym = 0;
+ struct dbx_symfile_info *dbx = (struct dbx_symfile_info *)
+ objfile->sym_stab_info;
+ unsigned long size;
+ int stripped = (bfd_get_symcount (abfd) == 0);
+
+ if (dynamic)
+ {
+ storage_needed = bfd_get_dynamic_symtab_upper_bound (abfd);
+
+ /* Nothing to be done if there is no dynamic symtab. */
+ if (storage_needed < 0)
+ return;
+ }
+ else
+ {
+ storage_needed = bfd_get_symtab_upper_bound (abfd);
+ if (storage_needed < 0)
+ error ("Can't read symbols from %s: %s", bfd_get_filename (abfd),
+ bfd_errmsg (bfd_get_error ()));
+ }
+ if (storage_needed > 0)
+ {
+ symbol_table = (asymbol **) xmalloc (storage_needed);
+ back_to = make_cleanup (free, symbol_table);
+ if (dynamic)
+ number_of_symbols = bfd_canonicalize_dynamic_symtab (abfd,
+ symbol_table);
+ else
+ number_of_symbols = bfd_canonicalize_symtab (abfd, symbol_table);
+ if (number_of_symbols < 0)
+ error ("Can't read symbols from %s: %s", bfd_get_filename (abfd),
+ bfd_errmsg (bfd_get_error ()));
+ for (i = 0; i < number_of_symbols; i++)
+ {
+ sym = symbol_table[i];
+ if (sym -> name == NULL || *sym -> name == '\0')
+ {
+ /* Skip names that don't exist (shouldn't happen), or names
+ that are null strings (may happen). */
+ continue;
+ }
+
+ /* If it is a nonstripped executable, do not enter dynamic
+ symbols, as the dynamic symbol table is usually a subset
+ of the main symbol table.
+ On Irix 5 however, the symbols for the procedure linkage
+ table entries have meaningful values only in the dynamic
+ symbol table, so we always examine undefined symbols. */
+ if (dynamic && !stripped && sym -> section != &bfd_und_section)
+ continue;
+ if (sym -> flags & BSF_FILE)
+ {
+ /* STT_FILE debugging symbol that helps stabs-in-elf debugging.
+ Chain any old one onto the objfile; remember new sym. */
+ if (sectinfo != NULL)
+ {
+ sectinfo -> next = dbx -> stab_section_info;
+ dbx -> stab_section_info = sectinfo;
+ sectinfo = NULL;
+ }
+ filesym = sym;
+ }
+ else if (sym -> flags & (BSF_GLOBAL | BSF_LOCAL | BSF_WEAK))
+ {
+ /* Select global/local/weak symbols. Note that bfd puts abs
+ symbols in their own section, so all symbols we are
+ interested in will have a section. */
+ /* Bfd symbols are section relative. */
+ symaddr = sym -> value + sym -> section -> vma;
+ /* Relocate all non-absolute symbols by base address. */
+ if (sym -> section != &bfd_abs_section)
+ {
+ symaddr += addr;
+ }
+ /* For non-absolute symbols, use the type of the section
+ they are relative to, to intuit text/data. Bfd provides
+ no way of figuring this out for absolute symbols. */
+ if (sym -> section == &bfd_und_section
+ && (sym -> flags & BSF_GLOBAL)
+ && (sym -> flags & BSF_FUNCTION))
+ {
+ /* Symbol is a reference to a function defined in
+ a shared library.
+ If its value is non zero then it is usually the
+ absolute address of the corresponding entry in
+ the procedure linkage table.
+ If its value is zero then the dynamic linker has to
+ resolve the symbol. We are unable to find any
+ meaningful address for this symbol in the
+ executable file, so we skip it.
+ Irix 5 has a zero value for all shared library functions
+ in the main symbol table, but the dynamic symbol table
+ provides the right values. */
+ ms_type = mst_solib_trampoline;
+ symaddr = sym -> value;
+ if (symaddr == 0)
+ continue;
+ symaddr += addr;
+ }
+ else if (sym -> section == &bfd_abs_section)
+ {
+ /* This is a hack to get the minimal symbol type
+ right for Irix 5, which has absolute adresses
+ with special section indices for dynamic symbols. */
+ unsigned short shndx =
+ ((elf_symbol_type *) sym)->internal_elf_sym.st_shndx;
+
+ switch (shndx)
+ {
+#if 0
+ case SHN_MIPS_TEXT:
+ ms_type = mst_text;
+ break;
+ case SHN_MIPS_DATA:
+ ms_type = mst_data;
+ break;
+ case SHN_MIPS_ACOMMON:
+ ms_type = mst_bss;
+ break;
+#endif
+ default:
+ ms_type = mst_abs;
+ }
+ }
+ else if (sym -> section -> flags & SEC_CODE)
+ {
+ if (sym -> flags & BSF_GLOBAL)
+ {
+ ms_type = mst_text;
+ }
+ else if ((sym->name[0] == '.' && sym->name[1] == 'L')
+ || ((sym -> flags & BSF_LOCAL)
+ && sym->name[0] == 'L'
+ && sym->name[1] == 'L'))
+ /* Looks like a compiler-generated label. Skip it.
+ The assembler should be skipping these (to keep
+ executables small), but apparently with gcc on the
+ delta m88k SVR4, it loses. So to have us check too
+ should be harmless (but I encourage people to fix this
+ in the assembler instead of adding checks here). */
+ continue;
+ else
+ {
+ ms_type = mst_file_text;
+ }
+ }
+ else if (sym -> section -> flags & SEC_ALLOC)
+ {
+ if (sym -> flags & BSF_GLOBAL)
+ {
+ if (sym -> section -> flags & SEC_LOAD)
+ {
+ ms_type = mst_data;
+ }
+ else
+ {
+ ms_type = mst_bss;
+ }
+ }
+ else if (sym -> flags & BSF_LOCAL)
+ {
+ /* Named Local variable in a Data section. Check its
+ name for stabs-in-elf. The STREQ macro checks the
+ first character inline, so we only actually do a
+ strcmp function call on names that start with 'B'
+ or 'D' */
+ index = SECT_OFF_MAX;
+ if (STREQ ("Bbss.bss", sym -> name))
+ {
+ index = SECT_OFF_BSS;
+ }
+ else if (STREQ ("Ddata.data", sym -> name))
+ {
+ index = SECT_OFF_DATA;
+ }
+ else if (STREQ ("Drodata.rodata", sym -> name))
+ {
+ index = SECT_OFF_RODATA;
+ }
+ if (index != SECT_OFF_MAX)
+ {
+ /* Found a special local symbol. Allocate a
+ sectinfo, if needed, and fill it in. */
+ if (sectinfo == NULL)
+ {
+ sectinfo = (struct stab_section_info *)
+ xmmalloc (objfile -> md, sizeof (*sectinfo));
+ memset ((PTR) sectinfo, 0, sizeof (*sectinfo));
+ if (filesym == NULL)
+ {
+ complain (&section_info_complaint,
+ sym -> name);
+ }
+ else
+ {
+ sectinfo -> filename =
+ (char *) filesym -> name;
+ }
+ }
+ if (sectinfo -> sections[index] != 0)
+ {
+ complain (&section_info_dup_complaint,
+ sectinfo -> filename);
+ }
+ /* Bfd symbols are section relative. */
+ symaddr = sym -> value + sym -> section -> vma;
+ /* Relocate non-absolute symbols by base address. */
+ if (sym -> section != &bfd_abs_section)
+ {
+ symaddr += addr;
+ }
+ sectinfo -> sections[index] = symaddr;
+ /* The special local symbols don't go in the
+ minimal symbol table, so ignore this one. */
+ continue;
+ }
+ /* Not a special stabs-in-elf symbol, do regular
+ symbol processing. */
+ if (sym -> section -> flags & SEC_LOAD)
+ {
+ ms_type = mst_file_data;
+ }
+ else
+ {
+ ms_type = mst_file_bss;
+ }
+ }
+ else
+ {
+ ms_type = mst_unknown;
+ }
+ }
+ else
+ {
+ /* FIXME: Solaris2 shared libraries include lots of
+ odd "absolute" and "undefined" symbols, that play
+ hob with actions like finding what function the PC
+ is in. Ignore them if they aren't text, data, or bss. */
+ /* ms_type = mst_unknown; */
+ continue; /* Skip this symbol. */
+ }
+ /* Pass symbol size field in via BFD. FIXME!!! */
+ size = ((elf_symbol_type *) sym) -> internal_elf_sym.st_size;
+ record_minimal_symbol_and_info ((char *) sym -> name, symaddr,
+ ms_type, (PTR) size, objfile);
+ }
+ }
+ do_cleanups (back_to);
+ }
+}
+
+/* Scan and build partial symbols for a symbol file.
+ We have been initialized by a call to elf_symfile_init, which
+ currently does nothing.
+
+ SECTION_OFFSETS is a set of offsets to apply to relocate the symbols
+ in each section. We simplify it down to a single offset for all
+ symbols. FIXME.
+
+ MAINLINE is true if we are reading the main symbol
+ table (as opposed to a shared lib or dynamically loaded file).
+
+ This function only does the minimum work necessary for letting the
+ user "name" things symbolically; it does not read the entire symtab.
+ Instead, it reads the external and static symbols and puts them in partial
+ symbol tables. When more extensive information is requested of a
+ file, the corresponding partial symbol table is mutated into a full
+ fledged symbol table by going back and reading the symbols
+ for real.
+
+ We look for sections with specific names, to tell us what debug
+ format to look for: FIXME!!!
+
+ dwarf_build_psymtabs() builds psymtabs for DWARF symbols;
+ elfstab_build_psymtabs() handles STABS symbols;
+ mdebug_build_psymtabs() handles ECOFF debugging information.
+
+ Note that ELF files have a "minimal" symbol table, which looks a lot
+ like a COFF symbol table, but has only the minimal information necessary
+ for linking. We process this also, and use the information to
+ build gdb's minimal symbol table. This gives us some minimal debugging
+ capability even for files compiled without -g. */
+
+static void
+elf_symfile_read (objfile, section_offsets, mainline)
+ struct objfile *objfile;
+ struct section_offsets *section_offsets;
+ int mainline;
+{
+ bfd *abfd = objfile->obfd;
+ struct elfinfo ei;
+ struct cleanup *back_to;
+ CORE_ADDR offset;
+
+ init_minimal_symbol_collection ();
+ back_to = make_cleanup (discard_minimal_symbols, 0);
+
+ memset ((char *) &ei, 0, sizeof (ei));
+
+ /* Allocate struct to keep track of the symfile */
+ objfile->sym_stab_info = (PTR)
+ xmmalloc (objfile -> md, sizeof (struct dbx_symfile_info));
+ memset ((char *) objfile->sym_stab_info, 0, sizeof (struct dbx_symfile_info));
+ make_cleanup (free_elfinfo, (PTR) objfile);
+
+ /* Process the normal ELF symbol table first. This may write some
+ chain of info into the dbx_symfile_info in objfile->sym_stab_info,
+ which can later be used by elfstab_offset_sections. */
+
+ /* FIXME, should take a section_offsets param, not just an offset. */
+ offset = ANOFFSET (section_offsets, 0);
+ elf_symtab_read (abfd, offset, objfile, 0);
+
+ /* Add the dynamic symbols. */
+
+ elf_symtab_read (abfd, offset, objfile, 1);
+
+ /* Now process debugging information, which is contained in
+ special ELF sections. We first have to find them... */
+
+ bfd_map_over_sections (abfd, elf_locate_sections, (PTR) &ei);
+ if (ei.dboffset && ei.lnoffset)
+ {
+ /* DWARF sections */
+ dwarf_build_psymtabs (objfile,
+ section_offsets, mainline,
+ ei.dboffset, ei.dbsize,
+ ei.lnoffset, ei.lnsize);
+ }
+ if (ei.stabsect)
+ {
+ asection *str_sect;
+
+ /* Stab sections have an associated string table that looks like
+ a separate section. */
+ str_sect = bfd_get_section_by_name (abfd, ".stabstr");
+
+ /* FIXME should probably warn about a stab section without a stabstr. */
+ if (str_sect)
+ elfstab_build_psymtabs (objfile,
+ section_offsets,
+ mainline,
+ ei.stabsect->filepos,
+ bfd_section_size (abfd, ei.stabsect),
+ str_sect->filepos,
+ bfd_section_size (abfd, str_sect));
+ }
+ if (ei.mdebugsect)
+ {
+ const struct ecoff_debug_swap *swap;
+
+ /* .mdebug section, presumably holding ECOFF debugging
+ information. */
+ swap = get_elf_backend_data (abfd)->elf_backend_ecoff_debug_swap;
+ if (swap)
+ elfmdebug_build_psymtabs (objfile, swap, ei.mdebugsect,
+ section_offsets);
+ }
+
+ /* Install any minimal symbols that have been collected as the current
+ minimal symbols for this objfile. */
+
+ install_minimal_symbols (objfile);
+
+ do_cleanups (back_to);
+}
+
+/* This cleans up the objfile's sym_stab_info pointer, and the chain of
+ stab_section_info's, that might be dangling from it. */
+
+static void
+free_elfinfo (objp)
+ PTR objp;
+{
+ struct objfile *objfile = (struct objfile *)objp;
+ struct dbx_symfile_info *dbxinfo = (struct dbx_symfile_info *)
+ objfile->sym_stab_info;
+ struct stab_section_info *ssi, *nssi;
+
+ ssi = dbxinfo->stab_section_info;
+ while (ssi)
+ {
+ nssi = ssi->next;
+ mfree (objfile->md, ssi);
+ ssi = nssi;
+ }
+
+ dbxinfo->stab_section_info = 0; /* Just say No mo info about this. */
+}
+
+
+/* Initialize anything that needs initializing when a completely new symbol
+ file is specified (not just adding some symbols from another file, e.g. a
+ shared library).
+
+ We reinitialize buildsym, since we may be reading stabs from an ELF file. */
+
+static void
+elf_new_init (ignore)
+ struct objfile *ignore;
+{
+ stabsread_new_init ();
+ buildsym_new_init ();
+}
+
+/* Perform any local cleanups required when we are done with a particular
+ objfile. I.E, we are in the process of discarding all symbol information
+ for an objfile, freeing up all memory held for it, and unlinking the
+ objfile struct from the global list of known objfiles. */
+
+static void
+elf_symfile_finish (objfile)
+ struct objfile *objfile;
+{
+ if (objfile -> sym_stab_info != NULL)
+ {
+ mfree (objfile -> md, objfile -> sym_stab_info);
+ }
+}
+
+/* ELF specific initialization routine for reading symbols.
+
+ It is passed a pointer to a struct sym_fns which contains, among other
+ things, the BFD for the file whose symbols are being read, and a slot for
+ a pointer to "private data" which we can fill with goodies.
+
+ For now at least, we have nothing in particular to do, so this function is
+ just a stub. */
+
+static void
+elf_symfile_init (ignore)
+ struct objfile *ignore;
+{
+}
+
+/* ELF specific parsing routine for section offsets.
+
+ Plain and simple for now. */
+
+static
+struct section_offsets *
+elf_symfile_offsets (objfile, addr)
+ struct objfile *objfile;
+ CORE_ADDR addr;
+{
+ struct section_offsets *section_offsets;
+ int i;
+
+ objfile->num_sections = SECT_OFF_MAX;
+ section_offsets = (struct section_offsets *)
+ obstack_alloc (&objfile -> psymbol_obstack,
+ sizeof (struct section_offsets)
+ + sizeof (section_offsets->offsets) * (SECT_OFF_MAX-1));
+
+ for (i = 0; i < SECT_OFF_MAX; i++)
+ ANOFFSET (section_offsets, i) = addr;
+
+ return section_offsets;
+}
+
+/* When handling an ELF file that contains Sun STABS debug info,
+ some of the debug info is relative to the particular chunk of the
+ section that was generated in its individual .o file. E.g.
+ offsets to static variables are relative to the start of the data
+ segment *for that module before linking*. This information is
+ painfully squirreled away in the ELF symbol table as local symbols
+ with wierd names. Go get 'em when needed. */
+
+void
+elfstab_offset_sections (objfile, pst)
+ struct objfile *objfile;
+ struct partial_symtab *pst;
+{
+ char *filename = pst->filename;
+ struct dbx_symfile_info *dbx = (struct dbx_symfile_info *)
+ objfile->sym_stab_info;
+ struct stab_section_info *maybe = dbx->stab_section_info;
+ struct stab_section_info *questionable = 0;
+ int i;
+ char *p;
+
+ /* The ELF symbol info doesn't include path names, so strip the path
+ (if any) from the psymtab filename. */
+ while (0 != (p = strchr (filename, '/')))
+ filename = p+1;
+
+ /* FIXME: This linear search could speed up significantly
+ if it was chained in the right order to match how we search it,
+ and if we unchained when we found a match. */
+ for (; maybe; maybe = maybe->next)
+ {
+ if (filename[0] == maybe->filename[0]
+ && STREQ (filename, maybe->filename))
+ {
+ /* We found a match. But there might be several source files
+ (from different directories) with the same name. */
+ if (0 == maybe->found)
+ break;
+ questionable = maybe; /* Might use it later. */
+ }
+ }
+
+ if (maybe == 0 && questionable != 0)
+ {
+ complain (&stab_info_questionable_complaint, filename);
+ maybe = questionable;
+ }
+
+ if (maybe)
+ {
+ /* Found it! Allocate a new psymtab struct, and fill it in. */
+ maybe->found++;
+ pst->section_offsets = (struct section_offsets *)
+ obstack_alloc (&objfile -> psymbol_obstack,
+ sizeof (struct section_offsets) +
+ sizeof (pst->section_offsets->offsets) * (SECT_OFF_MAX-1));
+
+ for (i = 0; i < SECT_OFF_MAX; i++)
+ ANOFFSET (pst->section_offsets, i) = maybe->sections[i];
+ return;
+ }
+
+ /* We were unable to find any offsets for this file. Complain. */
+ if (dbx->stab_section_info) /* If there *is* any info, */
+ complain (&stab_info_mismatch_complaint, filename);
+}
+
+/* Register that we are able to handle ELF object file formats. */
+
+static struct sym_fns elf_sym_fns =
+{
+ bfd_target_elf_flavour,
+ elf_new_init, /* sym_new_init: init anything gbl to entire symtab */
+ elf_symfile_init, /* sym_init: read initial info, setup for sym_read() */
+ elf_symfile_read, /* sym_read: read a symbol file into symtab */
+ elf_symfile_finish, /* sym_finish: finished with file, cleanup */
+ elf_symfile_offsets, /* sym_offsets: Translate ext. to int. relocation */
+ NULL /* next: pointer to next struct sym_fns */
+};
+
+void
+_initialize_elfread ()
+{
+ add_symtab_fns (&elf_sym_fns);
+}
diff --git a/gnu/usr.bin/gdb/gdb/environ.c b/gnu/usr.bin/gdb/gdb/environ.c
new file mode 100644
index 0000000..5d7a640
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/environ.c
@@ -0,0 +1,194 @@
+/* environ.c -- library for manipulating environments for GNU.
+ Copyright (C) 1986, 1989 Free Software Foundation, Inc.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#define min(a, b) ((a) < (b) ? (a) : (b))
+#define max(a, b) ((a) > (b) ? (a) : (b))
+
+#include "defs.h"
+#include "environ.h"
+#include <string.h>
+#include "gdbcore.h"
+
+
+/* Return a new environment object. */
+
+struct environ *
+make_environ ()
+{
+ register struct environ *e;
+
+ e = (struct environ *) xmalloc (sizeof (struct environ));
+
+ e->allocated = 10;
+ e->vector = (char **) xmalloc ((e->allocated + 1) * sizeof (char *));
+ e->vector[0] = 0;
+ return e;
+}
+
+/* Free an environment and all the strings in it. */
+
+void
+free_environ (e)
+ register struct environ *e;
+{
+ register char **vector = e->vector;
+
+ while (*vector)
+ free (*vector++);
+
+ free (e);
+}
+
+/* Copy the environment given to this process into E.
+ Also copies all the strings in it, so we can be sure
+ that all strings in these environments are safe to free. */
+
+void
+init_environ (e)
+ register struct environ *e;
+{
+ extern char **environ;
+ register int i;
+
+ if (environ == NULL)
+ return;
+
+ for (i = 0; environ[i]; i++) /*EMPTY*/;
+
+ if (e->allocated < i)
+ {
+ e->allocated = max (i, e->allocated + 10);
+ e->vector = (char **) xrealloc ((char *)e->vector,
+ (e->allocated + 1) * sizeof (char *));
+ }
+
+ memcpy (e->vector, environ, (i + 1) * sizeof (char *));
+
+ while (--i >= 0)
+ {
+ register int len = strlen (e->vector[i]);
+ register char *new = (char *) xmalloc (len + 1);
+ memcpy (new, e->vector[i], len + 1);
+ e->vector[i] = new;
+ }
+}
+
+/* Return the vector of environment E.
+ This is used to get something to pass to execve. */
+
+char **
+environ_vector (e)
+ struct environ *e;
+{
+ return e->vector;
+}
+
+/* Return the value in environment E of variable VAR. */
+
+char *
+get_in_environ (e, var)
+ const struct environ *e;
+ const char *var;
+{
+ register int len = strlen (var);
+ register char **vector = e->vector;
+ register char *s;
+
+ for (; (s = *vector) != NULL; vector++)
+ if (STREQN (s, var, len) && s[len] == '=')
+ return &s[len + 1];
+
+ return 0;
+}
+
+/* Store the value in E of VAR as VALUE. */
+
+void
+set_in_environ (e, var, value)
+ struct environ *e;
+ const char *var;
+ const char *value;
+{
+ register int i;
+ register int len = strlen (var);
+ register char **vector = e->vector;
+ register char *s;
+
+ for (i = 0; (s = vector[i]) != NULL; i++)
+ if (STREQN (s, var, len) && s[len] == '=')
+ break;
+
+ if (s == 0)
+ {
+ if (i == e->allocated)
+ {
+ e->allocated += 10;
+ vector = (char **) xrealloc ((char *)vector,
+ (e->allocated + 1) * sizeof (char *));
+ e->vector = vector;
+ }
+ vector[i + 1] = 0;
+ }
+ else
+ free (s);
+
+ s = (char *) xmalloc (len + strlen (value) + 2);
+ strcpy (s, var);
+ strcat (s, "=");
+ strcat (s, value);
+ vector[i] = s;
+
+ /* This used to handle setting the PATH and GNUTARGET variables
+ specially. The latter has been replaced by "set gnutarget"
+ (which has worked since GDB 4.11). The former affects searching
+ the PATH to find SHELL, and searching the PATH to find the
+ argument of "symbol-file" or "exec-file". Maybe we should have
+ some kind of "set exec-path" for that. But in any event, having
+ "set env" affect anything besides the inferior is a bad idea.
+ What if we want to change the environment we pass to the program
+ without afecting GDB's behavior? */
+
+ return;
+}
+
+/* Remove the setting for variable VAR from environment E. */
+
+void
+unset_in_environ (e, var)
+ struct environ *e;
+ char *var;
+{
+ register int len = strlen (var);
+ register char **vector = e->vector;
+ register char *s;
+
+ for (; (s = *vector) != NULL; vector++)
+ {
+ if (STREQN (s, var, len) && s[len] == '=')
+ {
+ free (s);
+ /* Walk through the vector, shuffling args down by one, including
+ the NULL terminator. Can't use memcpy() here since the regions
+ overlap, and memmove() might not be available. */
+ while ((vector[0] = vector[1]) != NULL)
+ {
+ vector++;
+ }
+ break;
+ }
+ }
+}
diff --git a/gnu/usr.bin/gdb/gdb/environ.h b/gnu/usr.bin/gdb/gdb/environ.h
new file mode 100644
index 0000000..6c9fd03
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/environ.h
@@ -0,0 +1,58 @@
+/* Header for environment manipulation library.
+ Copyright 1989, 1992 Free Software Foundation.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#if !defined (ENVIRON_H)
+#define ENVIRON_H 1
+
+/* We manipulate environments represented as these structures. */
+
+struct environ
+{
+ /* Number of usable slots allocated in VECTOR.
+ VECTOR always has one slot not counted here,
+ to hold the terminating zero. */
+ int allocated;
+ /* A vector of slots, ALLOCATED + 1 of them.
+ The first few slots contain strings "VAR=VALUE"
+ and the next one contains zero.
+ Then come some unused slots. */
+ char **vector;
+};
+
+extern struct environ *
+make_environ PARAMS ((void));
+
+extern void
+free_environ PARAMS ((struct environ *));
+
+extern void
+init_environ PARAMS ((struct environ *));
+
+extern char *
+get_in_environ PARAMS ((const struct environ *, const char *));
+
+extern void
+set_in_environ PARAMS ((struct environ *, const char *,
+ const char *));
+
+extern void
+unset_in_environ PARAMS ((struct environ *, char *));
+
+extern char **
+environ_vector PARAMS ((struct environ *));
+
+#endif /* defined (ENVIRON_H) */
diff --git a/gnu/usr.bin/gdb/gdb/eval.c b/gnu/usr.bin/gdb/gdb/eval.c
new file mode 100644
index 0000000..cb956ac
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/eval.c
@@ -0,0 +1,1226 @@
+/* Evaluate expressions for GDB.
+ Copyright 1986, 1987, 1989, 1991, 1992, 1993, 1994
+ Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "defs.h"
+#include <string.h>
+#include "symtab.h"
+#include "gdbtypes.h"
+#include "value.h"
+#include "expression.h"
+#include "target.h"
+#include "frame.h"
+#include "demangle.h"
+#include "language.h" /* For CAST_IS_CONVERSION */
+
+/* Values of NOSIDE argument to eval_subexp. */
+enum noside
+{ EVAL_NORMAL,
+ EVAL_SKIP, /* Only effect is to increment pos. */
+ EVAL_AVOID_SIDE_EFFECTS /* Don't modify any variables or
+ call any functions. The value
+ returned will have the correct
+ type, and will have an
+ approximately correct lvalue
+ type (inaccuracy: anything that is
+ listed as being in a register in
+ the function in which it was
+ declared will be lval_register). */
+};
+
+/* Prototypes for local functions. */
+
+static value_ptr
+evaluate_subexp_for_sizeof PARAMS ((struct expression *, int *));
+
+static value_ptr
+evaluate_subexp_with_coercion PARAMS ((struct expression *, int *,
+ enum noside));
+
+static value_ptr
+evaluate_subexp_for_address PARAMS ((struct expression *, int *,
+ enum noside));
+
+static value_ptr
+evaluate_subexp PARAMS ((struct type *, struct expression *, int *,
+ enum noside));
+
+
+/* Parse the string EXP as a C expression, evaluate it,
+ and return the result as a number. */
+
+CORE_ADDR
+parse_and_eval_address (exp)
+ char *exp;
+{
+ struct expression *expr = parse_expression (exp);
+ register CORE_ADDR addr;
+ register struct cleanup *old_chain =
+ make_cleanup (free_current_contents, &expr);
+
+ addr = value_as_pointer (evaluate_expression (expr));
+ do_cleanups (old_chain);
+ return addr;
+}
+
+/* Like parse_and_eval_address but takes a pointer to a char * variable
+ and advanced that variable across the characters parsed. */
+
+CORE_ADDR
+parse_and_eval_address_1 (expptr)
+ char **expptr;
+{
+ struct expression *expr = parse_exp_1 (expptr, (struct block *)0, 0);
+ register CORE_ADDR addr;
+ register struct cleanup *old_chain =
+ make_cleanup (free_current_contents, &expr);
+
+ addr = value_as_pointer (evaluate_expression (expr));
+ do_cleanups (old_chain);
+ return addr;
+}
+
+value_ptr
+parse_and_eval (exp)
+ char *exp;
+{
+ struct expression *expr = parse_expression (exp);
+ register value_ptr val;
+ register struct cleanup *old_chain
+ = make_cleanup (free_current_contents, &expr);
+
+ val = evaluate_expression (expr);
+ do_cleanups (old_chain);
+ return val;
+}
+
+/* Parse up to a comma (or to a closeparen)
+ in the string EXPP as an expression, evaluate it, and return the value.
+ EXPP is advanced to point to the comma. */
+
+value_ptr
+parse_to_comma_and_eval (expp)
+ char **expp;
+{
+ struct expression *expr = parse_exp_1 (expp, (struct block *) 0, 1);
+ register value_ptr val;
+ register struct cleanup *old_chain
+ = make_cleanup (free_current_contents, &expr);
+
+ val = evaluate_expression (expr);
+ do_cleanups (old_chain);
+ return val;
+}
+
+/* Evaluate an expression in internal prefix form
+ such as is constructed by parse.y.
+
+ See expression.h for info on the format of an expression. */
+
+value_ptr
+evaluate_expression (exp)
+ struct expression *exp;
+{
+ int pc = 0;
+ return evaluate_subexp (NULL_TYPE, exp, &pc, EVAL_NORMAL);
+}
+
+/* Evaluate an expression, avoiding all memory references
+ and getting a value whose type alone is correct. */
+
+value_ptr
+evaluate_type (exp)
+ struct expression *exp;
+{
+ int pc = 0;
+ return evaluate_subexp (NULL_TYPE, exp, &pc, EVAL_AVOID_SIDE_EFFECTS);
+}
+
+static value_ptr
+evaluate_subexp (expect_type, exp, pos, noside)
+ struct type *expect_type;
+ register struct expression *exp;
+ register int *pos;
+ enum noside noside;
+{
+ enum exp_opcode op;
+ int tem, tem2, tem3;
+ register int pc, pc2 = 0, oldpos;
+ register value_ptr arg1 = NULL, arg2 = NULL, arg3;
+ struct type *type;
+ int nargs;
+ value_ptr *argvec;
+
+ pc = (*pos)++;
+ op = exp->elts[pc].opcode;
+
+ switch (op)
+ {
+ case OP_SCOPE:
+ tem = longest_to_int (exp->elts[pc + 2].longconst);
+ (*pos) += 4 + BYTES_TO_EXP_ELEM (tem + 1);
+ arg1 = value_struct_elt_for_reference (exp->elts[pc + 1].type,
+ 0,
+ exp->elts[pc + 1].type,
+ &exp->elts[pc + 3].string,
+ expect_type);
+ if (arg1 == NULL)
+ error ("There is no field named %s", &exp->elts[pc + 3].string);
+ return arg1;
+
+ case OP_LONG:
+ (*pos) += 3;
+ return value_from_longest (exp->elts[pc + 1].type,
+ exp->elts[pc + 2].longconst);
+
+ case OP_DOUBLE:
+ (*pos) += 3;
+ return value_from_double (exp->elts[pc + 1].type,
+ exp->elts[pc + 2].doubleconst);
+
+ case OP_VAR_VALUE:
+ (*pos) += 3;
+ if (noside == EVAL_SKIP)
+ goto nosideret;
+ if (noside == EVAL_AVOID_SIDE_EFFECTS)
+ {
+ struct symbol * sym = exp->elts[pc + 2].symbol;
+ enum lval_type lv;
+
+ switch (SYMBOL_CLASS (sym))
+ {
+ case LOC_CONST:
+ case LOC_LABEL:
+ case LOC_CONST_BYTES:
+ lv = not_lval;
+ break;
+
+ case LOC_REGISTER:
+ case LOC_REGPARM:
+ lv = lval_register;
+ break;
+
+ default:
+ lv = lval_memory;
+ break;
+ }
+
+ return value_zero (SYMBOL_TYPE (sym), lv);
+ }
+ else
+ return value_of_variable (exp->elts[pc + 2].symbol,
+ exp->elts[pc + 1].block);
+
+ case OP_LAST:
+ (*pos) += 2;
+ return
+ access_value_history (longest_to_int (exp->elts[pc + 1].longconst));
+
+ case OP_REGISTER:
+ (*pos) += 2;
+ return value_of_register (longest_to_int (exp->elts[pc + 1].longconst));
+
+ case OP_BOOL:
+ (*pos) += 2;
+ return value_from_longest (builtin_type_chill_bool,
+ exp->elts[pc + 1].longconst);
+
+ case OP_INTERNALVAR:
+ (*pos) += 2;
+ return value_of_internalvar (exp->elts[pc + 1].internalvar);
+
+ case OP_STRING:
+ tem = longest_to_int (exp->elts[pc + 1].longconst);
+ (*pos) += 3 + BYTES_TO_EXP_ELEM (tem + 1);
+ if (noside == EVAL_SKIP)
+ goto nosideret;
+ return value_string (&exp->elts[pc + 2].string, tem);
+
+ case OP_BITSTRING:
+ error ("support for OP_BITSTRING unimplemented");
+ break;
+
+ case OP_ARRAY:
+ (*pos) += 3;
+ tem2 = longest_to_int (exp->elts[pc + 1].longconst);
+ tem3 = longest_to_int (exp->elts[pc + 2].longconst);
+ nargs = tem3 - tem2 + 1;
+ argvec = (value_ptr *) alloca (sizeof (value_ptr) * nargs);
+ for (tem = 0; tem < nargs; tem++)
+ {
+ /* Ensure that array expressions are coerced into pointer objects. */
+ argvec[tem] = evaluate_subexp_with_coercion (exp, pos, noside);
+ }
+ if (noside == EVAL_SKIP)
+ goto nosideret;
+ return (value_array (tem2, tem3, argvec));
+ break;
+
+ case TERNOP_COND:
+ /* Skip third and second args to evaluate the first one. */
+ arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside);
+ if (value_logical_not (arg1))
+ {
+ evaluate_subexp (NULL_TYPE, exp, pos, EVAL_SKIP);
+ return evaluate_subexp (NULL_TYPE, exp, pos, noside);
+ }
+ else
+ {
+ arg2 = evaluate_subexp (NULL_TYPE, exp, pos, noside);
+ evaluate_subexp (NULL_TYPE, exp, pos, EVAL_SKIP);
+ return arg2;
+ }
+
+ case OP_FUNCALL:
+ (*pos) += 2;
+ op = exp->elts[*pos].opcode;
+ if (op == STRUCTOP_MEMBER || op == STRUCTOP_MPTR)
+ {
+ int fnptr;
+
+ nargs = longest_to_int (exp->elts[pc + 1].longconst) + 1;
+ /* First, evaluate the structure into arg2 */
+ pc2 = (*pos)++;
+
+ if (noside == EVAL_SKIP)
+ goto nosideret;
+
+ if (op == STRUCTOP_MEMBER)
+ {
+ arg2 = evaluate_subexp_for_address (exp, pos, noside);
+ }
+ else
+ {
+ arg2 = evaluate_subexp (NULL_TYPE, exp, pos, noside);
+ }
+
+ /* If the function is a virtual function, then the
+ aggregate value (providing the structure) plays
+ its part by providing the vtable. Otherwise,
+ it is just along for the ride: call the function
+ directly. */
+
+ arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside);
+
+ fnptr = longest_to_int (value_as_long (arg1));
+
+ if (METHOD_PTR_IS_VIRTUAL(fnptr))
+ {
+ int fnoffset = METHOD_PTR_TO_VOFFSET(fnptr);
+ struct type *basetype;
+ struct type *domain_type =
+ TYPE_DOMAIN_TYPE (TYPE_TARGET_TYPE (VALUE_TYPE (arg1)));
+ int i, j;
+ basetype = TYPE_TARGET_TYPE (VALUE_TYPE (arg2));
+ if (domain_type != basetype)
+ arg2 = value_cast(lookup_pointer_type (domain_type), arg2);
+ basetype = TYPE_VPTR_BASETYPE (domain_type);
+ for (i = TYPE_NFN_FIELDS (basetype) - 1; i >= 0; i--)
+ {
+ struct fn_field *f = TYPE_FN_FIELDLIST1 (basetype, i);
+ /* If one is virtual, then all are virtual. */
+ if (TYPE_FN_FIELD_VIRTUAL_P (f, 0))
+ for (j = TYPE_FN_FIELDLIST_LENGTH (basetype, i) - 1; j >= 0; --j)
+ if (TYPE_FN_FIELD_VOFFSET (f, j) == fnoffset)
+ {
+ value_ptr temp = value_ind (arg2);
+ arg1 = value_virtual_fn_field (&temp, f, j, domain_type, 0);
+ arg2 = value_addr (temp);
+ goto got_it;
+ }
+ }
+ if (i < 0)
+ error ("virtual function at index %d not found", fnoffset);
+ }
+ else
+ {
+ VALUE_TYPE (arg1) = lookup_pointer_type (TYPE_TARGET_TYPE (VALUE_TYPE (arg1)));
+ }
+ got_it:
+
+ /* Now, say which argument to start evaluating from */
+ tem = 2;
+ }
+ else if (op == STRUCTOP_STRUCT || op == STRUCTOP_PTR)
+ {
+ /* Hair for method invocations */
+ int tem2;
+
+ nargs = longest_to_int (exp->elts[pc + 1].longconst) + 1;
+ /* First, evaluate the structure into arg2 */
+ pc2 = (*pos)++;
+ tem2 = longest_to_int (exp->elts[pc2 + 1].longconst);
+ *pos += 3 + BYTES_TO_EXP_ELEM (tem2 + 1);
+ if (noside == EVAL_SKIP)
+ goto nosideret;
+
+ if (op == STRUCTOP_STRUCT)
+ {
+ /* If v is a variable in a register, and the user types
+ v.method (), this will produce an error, because v has
+ no address.
+
+ A possible way around this would be to allocate a
+ copy of the variable on the stack, copy in the
+ contents, call the function, and copy out the
+ contents. I.e. convert this from call by reference
+ to call by copy-return (or whatever it's called).
+ However, this does not work because it is not the
+ same: the method being called could stash a copy of
+ the address, and then future uses through that address
+ (after the method returns) would be expected to
+ use the variable itself, not some copy of it. */
+ arg2 = evaluate_subexp_for_address (exp, pos, noside);
+ }
+ else
+ {
+ arg2 = evaluate_subexp (NULL_TYPE, exp, pos, noside);
+ }
+ /* Now, say which argument to start evaluating from */
+ tem = 2;
+ }
+ else
+ {
+ nargs = longest_to_int (exp->elts[pc + 1].longconst);
+ tem = 0;
+ }
+ /* Allocate arg vector, including space for the function to be
+ called in argvec[0] and a terminating NULL */
+ argvec = (value_ptr *) alloca (sizeof (value_ptr) * (nargs + 2));
+ for (; tem <= nargs; tem++)
+ /* Ensure that array expressions are coerced into pointer objects. */
+ argvec[tem] = evaluate_subexp_with_coercion (exp, pos, noside);
+
+ /* signal end of arglist */
+ argvec[tem] = 0;
+
+ if (op == STRUCTOP_STRUCT || op == STRUCTOP_PTR)
+ {
+ int static_memfuncp;
+ value_ptr temp = arg2;
+ char tstr[64];
+
+ argvec[1] = arg2;
+ argvec[0] = 0;
+ strcpy(tstr, &exp->elts[pc2+2].string);
+ if (!argvec[0])
+ {
+ temp = arg2;
+ argvec[0] =
+ value_struct_elt (&temp, argvec+1, tstr,
+ &static_memfuncp,
+ op == STRUCTOP_STRUCT
+ ? "structure" : "structure pointer");
+ }
+ arg2 = value_from_longest (lookup_pointer_type(VALUE_TYPE (temp)),
+ VALUE_ADDRESS (temp)+VALUE_OFFSET (temp));
+ argvec[1] = arg2;
+
+ if (static_memfuncp)
+ {
+ argvec[1] = argvec[0];
+ nargs--;
+ argvec++;
+ }
+ }
+ else if (op == STRUCTOP_MEMBER || op == STRUCTOP_MPTR)
+ {
+ argvec[1] = arg2;
+ argvec[0] = arg1;
+ }
+
+ if (noside == EVAL_SKIP)
+ goto nosideret;
+ if (noside == EVAL_AVOID_SIDE_EFFECTS)
+ {
+ /* If the return type doesn't look like a function type, call an
+ error. This can happen if somebody tries to turn a variable into
+ a function call. This is here because people often want to
+ call, eg, strcmp, which gdb doesn't know is a function. If
+ gdb isn't asked for it's opinion (ie. through "whatis"),
+ it won't offer it. */
+
+ struct type *ftype =
+ TYPE_TARGET_TYPE (VALUE_TYPE (argvec[0]));
+
+ if (ftype)
+ return allocate_value (TYPE_TARGET_TYPE (VALUE_TYPE (argvec[0])));
+ else
+ error ("Expression of type other than \"Function returning ...\" used as function");
+ }
+ return call_function_by_hand (argvec[0], nargs, argvec + 1);
+
+ case STRUCTOP_STRUCT:
+ tem = longest_to_int (exp->elts[pc + 1].longconst);
+ (*pos) += 3 + BYTES_TO_EXP_ELEM (tem + 1);
+ arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside);
+ if (noside == EVAL_SKIP)
+ goto nosideret;
+ if (noside == EVAL_AVOID_SIDE_EFFECTS)
+ return value_zero (lookup_struct_elt_type (VALUE_TYPE (arg1),
+ &exp->elts[pc + 2].string,
+ 0),
+ lval_memory);
+ else
+ {
+ value_ptr temp = arg1;
+ return value_struct_elt (&temp, NULL, &exp->elts[pc + 2].string,
+ NULL, "structure");
+ }
+
+ case STRUCTOP_PTR:
+ tem = longest_to_int (exp->elts[pc + 1].longconst);
+ (*pos) += 3 + BYTES_TO_EXP_ELEM (tem + 1);
+ arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside);
+ if (noside == EVAL_SKIP)
+ goto nosideret;
+ if (noside == EVAL_AVOID_SIDE_EFFECTS)
+ return value_zero (lookup_struct_elt_type (VALUE_TYPE (arg1),
+ &exp->elts[pc + 2].string,
+ 0),
+ lval_memory);
+ else
+ {
+ value_ptr temp = arg1;
+ return value_struct_elt (&temp, NULL, &exp->elts[pc + 2].string,
+ NULL, "structure pointer");
+ }
+
+ case STRUCTOP_MEMBER:
+ arg1 = evaluate_subexp_for_address (exp, pos, noside);
+ goto handle_pointer_to_member;
+ case STRUCTOP_MPTR:
+ arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside);
+ handle_pointer_to_member:
+ arg2 = evaluate_subexp (NULL_TYPE, exp, pos, noside);
+ if (noside == EVAL_SKIP)
+ goto nosideret;
+ if (TYPE_CODE (VALUE_TYPE (arg2)) != TYPE_CODE_PTR)
+ goto bad_pointer_to_member;
+ type = TYPE_TARGET_TYPE (VALUE_TYPE (arg2));
+ if (TYPE_CODE (type) == TYPE_CODE_METHOD)
+ error ("not implemented: pointer-to-method in pointer-to-member construct");
+ if (TYPE_CODE (type) != TYPE_CODE_MEMBER)
+ goto bad_pointer_to_member;
+ /* Now, convert these values to an address. */
+ arg1 = value_cast (lookup_pointer_type (TYPE_DOMAIN_TYPE (type)),
+ arg1);
+ arg3 = value_from_longest (lookup_pointer_type (TYPE_TARGET_TYPE (type)),
+ value_as_long (arg1) + value_as_long (arg2));
+ return value_ind (arg3);
+ bad_pointer_to_member:
+ error("non-pointer-to-member value used in pointer-to-member construct");
+
+ case BINOP_CONCAT:
+ arg1 = evaluate_subexp_with_coercion (exp, pos, noside);
+ arg2 = evaluate_subexp_with_coercion (exp, pos, noside);
+ if (noside == EVAL_SKIP)
+ goto nosideret;
+ if (binop_user_defined_p (op, arg1, arg2))
+ return value_x_binop (arg1, arg2, op, OP_NULL);
+ else
+ return value_concat (arg1, arg2);
+
+ case BINOP_ASSIGN:
+ arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside);
+ arg2 = evaluate_subexp (VALUE_TYPE (arg1), exp, pos, noside);
+ if (noside == EVAL_SKIP || noside == EVAL_AVOID_SIDE_EFFECTS)
+ return arg1;
+ if (binop_user_defined_p (op, arg1, arg2))
+ return value_x_binop (arg1, arg2, op, OP_NULL);
+ else
+ return value_assign (arg1, arg2);
+
+ case BINOP_ASSIGN_MODIFY:
+ (*pos) += 2;
+ arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside);
+ arg2 = evaluate_subexp (VALUE_TYPE (arg1), exp, pos, noside);
+ if (noside == EVAL_SKIP || noside == EVAL_AVOID_SIDE_EFFECTS)
+ return arg1;
+ op = exp->elts[pc + 1].opcode;
+ if (binop_user_defined_p (op, arg1, arg2))
+ return value_x_binop (arg1, arg2, BINOP_ASSIGN_MODIFY, op);
+ else if (op == BINOP_ADD)
+ arg2 = value_add (arg1, arg2);
+ else if (op == BINOP_SUB)
+ arg2 = value_sub (arg1, arg2);
+ else
+ arg2 = value_binop (arg1, arg2, op);
+ return value_assign (arg1, arg2);
+
+ case BINOP_ADD:
+ arg1 = evaluate_subexp_with_coercion (exp, pos, noside);
+ arg2 = evaluate_subexp_with_coercion (exp, pos, noside);
+ if (noside == EVAL_SKIP)
+ goto nosideret;
+ if (binop_user_defined_p (op, arg1, arg2))
+ return value_x_binop (arg1, arg2, op, OP_NULL);
+ else
+ return value_add (arg1, arg2);
+
+ case BINOP_SUB:
+ arg1 = evaluate_subexp_with_coercion (exp, pos, noside);
+ arg2 = evaluate_subexp_with_coercion (exp, pos, noside);
+ if (noside == EVAL_SKIP)
+ goto nosideret;
+ if (binop_user_defined_p (op, arg1, arg2))
+ return value_x_binop (arg1, arg2, op, OP_NULL);
+ else
+ return value_sub (arg1, arg2);
+
+ case BINOP_MUL:
+ case BINOP_DIV:
+ case BINOP_REM:
+ case BINOP_MOD:
+ case BINOP_LSH:
+ case BINOP_RSH:
+ case BINOP_BITWISE_AND:
+ case BINOP_BITWISE_IOR:
+ case BINOP_BITWISE_XOR:
+ arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside);
+ arg2 = evaluate_subexp (NULL_TYPE, exp, pos, noside);
+ if (noside == EVAL_SKIP)
+ goto nosideret;
+ if (binop_user_defined_p (op, arg1, arg2))
+ return value_x_binop (arg1, arg2, op, OP_NULL);
+ else
+ if (noside == EVAL_AVOID_SIDE_EFFECTS
+ && (op == BINOP_DIV || op == BINOP_REM || op == BINOP_MOD))
+ return value_zero (VALUE_TYPE (arg1), not_lval);
+ else
+ return value_binop (arg1, arg2, op);
+
+ case BINOP_SUBSCRIPT:
+ arg1 = evaluate_subexp_with_coercion (exp, pos, noside);
+ arg2 = evaluate_subexp_with_coercion (exp, pos, noside);
+ if (noside == EVAL_SKIP)
+ goto nosideret;
+ if (noside == EVAL_AVOID_SIDE_EFFECTS)
+ {
+ /* If the user attempts to subscript something that has no target
+ type (like a plain int variable for example), then report this
+ as an error. */
+
+ type = TYPE_TARGET_TYPE (VALUE_TYPE (arg1));
+ if (type)
+ return value_zero (type, VALUE_LVAL (arg1));
+ else
+ error ("cannot subscript something of type `%s'",
+ TYPE_NAME (VALUE_TYPE (arg1)));
+ }
+
+ if (binop_user_defined_p (op, arg1, arg2))
+ return value_x_binop (arg1, arg2, op, OP_NULL);
+ else
+ return value_subscript (arg1, arg2);
+
+ case BINOP_IN:
+ arg1 = evaluate_subexp_with_coercion (exp, pos, noside);
+ arg2 = evaluate_subexp_with_coercion (exp, pos, noside);
+ if (noside == EVAL_SKIP)
+ goto nosideret;
+ return value_in (arg1, arg2);
+
+ case MULTI_SUBSCRIPT:
+ (*pos) += 2;
+ nargs = longest_to_int (exp->elts[pc + 1].longconst);
+ arg1 = evaluate_subexp_with_coercion (exp, pos, noside);
+ while (nargs-- > 0)
+ {
+ arg2 = evaluate_subexp_with_coercion (exp, pos, noside);
+ /* FIXME: EVAL_SKIP handling may not be correct. */
+ if (noside == EVAL_SKIP)
+ {
+ if (nargs > 0)
+ {
+ continue;
+ }
+ else
+ {
+ goto nosideret;
+ }
+ }
+ /* FIXME: EVAL_AVOID_SIDE_EFFECTS handling may not be correct. */
+ if (noside == EVAL_AVOID_SIDE_EFFECTS)
+ {
+ /* If the user attempts to subscript something that has no target
+ type (like a plain int variable for example), then report this
+ as an error. */
+
+ type = TYPE_TARGET_TYPE (VALUE_TYPE (arg1));
+ if (type != NULL)
+ {
+ arg1 = value_zero (type, VALUE_LVAL (arg1));
+ noside = EVAL_SKIP;
+ continue;
+ }
+ else
+ {
+ error ("cannot subscript something of type `%s'",
+ TYPE_NAME (VALUE_TYPE (arg1)));
+ }
+ }
+
+ if (binop_user_defined_p (op, arg1, arg2))
+ {
+ arg1 = value_x_binop (arg1, arg2, op, OP_NULL);
+ }
+ else
+ {
+ arg1 = value_subscript (arg1, arg2);
+ }
+ }
+ return (arg1);
+
+ case BINOP_LOGICAL_AND:
+ arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside);
+ if (noside == EVAL_SKIP)
+ {
+ arg2 = evaluate_subexp (NULL_TYPE, exp, pos, noside);
+ goto nosideret;
+ }
+
+ oldpos = *pos;
+ arg2 = evaluate_subexp (NULL_TYPE, exp, pos, EVAL_AVOID_SIDE_EFFECTS);
+ *pos = oldpos;
+
+ if (binop_user_defined_p (op, arg1, arg2))
+ {
+ arg2 = evaluate_subexp (NULL_TYPE, exp, pos, noside);
+ return value_x_binop (arg1, arg2, op, OP_NULL);
+ }
+ else
+ {
+ tem = value_logical_not (arg1);
+ arg2 = evaluate_subexp (NULL_TYPE, exp, pos,
+ (tem ? EVAL_SKIP : noside));
+ return value_from_longest (builtin_type_int,
+ (LONGEST) (!tem && !value_logical_not (arg2)));
+ }
+
+ case BINOP_LOGICAL_OR:
+ arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside);
+ if (noside == EVAL_SKIP)
+ {
+ arg2 = evaluate_subexp (NULL_TYPE, exp, pos, noside);
+ goto nosideret;
+ }
+
+ oldpos = *pos;
+ arg2 = evaluate_subexp (NULL_TYPE, exp, pos, EVAL_AVOID_SIDE_EFFECTS);
+ *pos = oldpos;
+
+ if (binop_user_defined_p (op, arg1, arg2))
+ {
+ arg2 = evaluate_subexp (NULL_TYPE, exp, pos, noside);
+ return value_x_binop (arg1, arg2, op, OP_NULL);
+ }
+ else
+ {
+ tem = value_logical_not (arg1);
+ arg2 = evaluate_subexp (NULL_TYPE, exp, pos,
+ (!tem ? EVAL_SKIP : noside));
+ return value_from_longest (builtin_type_int,
+ (LONGEST) (!tem || !value_logical_not (arg2)));
+ }
+
+ case BINOP_EQUAL:
+ arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside);
+ arg2 = evaluate_subexp (VALUE_TYPE (arg1), exp, pos, noside);
+ if (noside == EVAL_SKIP)
+ goto nosideret;
+ if (binop_user_defined_p (op, arg1, arg2))
+ {
+ return value_x_binop (arg1, arg2, op, OP_NULL);
+ }
+ else
+ {
+ tem = value_equal (arg1, arg2);
+ return value_from_longest (builtin_type_int, (LONGEST) tem);
+ }
+
+ case BINOP_NOTEQUAL:
+ arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside);
+ arg2 = evaluate_subexp (VALUE_TYPE (arg1), exp, pos, noside);
+ if (noside == EVAL_SKIP)
+ goto nosideret;
+ if (binop_user_defined_p (op, arg1, arg2))
+ {
+ return value_x_binop (arg1, arg2, op, OP_NULL);
+ }
+ else
+ {
+ tem = value_equal (arg1, arg2);
+ return value_from_longest (builtin_type_int, (LONGEST) ! tem);
+ }
+
+ case BINOP_LESS:
+ arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside);
+ arg2 = evaluate_subexp (VALUE_TYPE (arg1), exp, pos, noside);
+ if (noside == EVAL_SKIP)
+ goto nosideret;
+ if (binop_user_defined_p (op, arg1, arg2))
+ {
+ return value_x_binop (arg1, arg2, op, OP_NULL);
+ }
+ else
+ {
+ tem = value_less (arg1, arg2);
+ return value_from_longest (builtin_type_int, (LONGEST) tem);
+ }
+
+ case BINOP_GTR:
+ arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside);
+ arg2 = evaluate_subexp (VALUE_TYPE (arg1), exp, pos, noside);
+ if (noside == EVAL_SKIP)
+ goto nosideret;
+ if (binop_user_defined_p (op, arg1, arg2))
+ {
+ return value_x_binop (arg1, arg2, op, OP_NULL);
+ }
+ else
+ {
+ tem = value_less (arg2, arg1);
+ return value_from_longest (builtin_type_int, (LONGEST) tem);
+ }
+
+ case BINOP_GEQ:
+ arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside);
+ arg2 = evaluate_subexp (VALUE_TYPE (arg1), exp, pos, noside);
+ if (noside == EVAL_SKIP)
+ goto nosideret;
+ if (binop_user_defined_p (op, arg1, arg2))
+ {
+ return value_x_binop (arg1, arg2, op, OP_NULL);
+ }
+ else
+ {
+ tem = value_less (arg2, arg1) || value_equal (arg1, arg2);
+ return value_from_longest (builtin_type_int, (LONGEST) tem);
+ }
+
+ case BINOP_LEQ:
+ arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside);
+ arg2 = evaluate_subexp (VALUE_TYPE (arg1), exp, pos, noside);
+ if (noside == EVAL_SKIP)
+ goto nosideret;
+ if (binop_user_defined_p (op, arg1, arg2))
+ {
+ return value_x_binop (arg1, arg2, op, OP_NULL);
+ }
+ else
+ {
+ tem = value_less (arg1, arg2) || value_equal (arg1, arg2);
+ return value_from_longest (builtin_type_int, (LONGEST) tem);
+ }
+
+ case BINOP_REPEAT:
+ arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside);
+ arg2 = evaluate_subexp (NULL_TYPE, exp, pos, noside);
+ if (noside == EVAL_SKIP)
+ goto nosideret;
+ if (TYPE_CODE (VALUE_TYPE (arg2)) != TYPE_CODE_INT)
+ error ("Non-integral right operand for \"@\" operator.");
+ if (noside == EVAL_AVOID_SIDE_EFFECTS)
+ return allocate_repeat_value (VALUE_TYPE (arg1),
+ longest_to_int (value_as_long (arg2)));
+ else
+ return value_repeat (arg1, longest_to_int (value_as_long (arg2)));
+
+ case BINOP_COMMA:
+ evaluate_subexp (NULL_TYPE, exp, pos, noside);
+ return evaluate_subexp (NULL_TYPE, exp, pos, noside);
+
+ case UNOP_NEG:
+ arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside);
+ if (noside == EVAL_SKIP)
+ goto nosideret;
+ if (unop_user_defined_p (op, arg1))
+ return value_x_unop (arg1, op);
+ else
+ return value_neg (arg1);
+
+ case UNOP_COMPLEMENT:
+ /* C++: check for and handle destructor names. */
+ op = exp->elts[*pos].opcode;
+
+ arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside);
+ if (noside == EVAL_SKIP)
+ goto nosideret;
+ if (unop_user_defined_p (UNOP_COMPLEMENT, arg1))
+ return value_x_unop (arg1, UNOP_COMPLEMENT);
+ else
+ return value_complement (arg1);
+
+ case UNOP_LOGICAL_NOT:
+ arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside);
+ if (noside == EVAL_SKIP)
+ goto nosideret;
+ if (unop_user_defined_p (op, arg1))
+ return value_x_unop (arg1, op);
+ else
+ return value_from_longest (builtin_type_int,
+ (LONGEST) value_logical_not (arg1));
+
+ case UNOP_IND:
+ if (expect_type && TYPE_CODE (expect_type) == TYPE_CODE_PTR)
+ expect_type = TYPE_TARGET_TYPE (expect_type);
+ arg1 = evaluate_subexp (expect_type, exp, pos, noside);
+ if (noside == EVAL_SKIP)
+ goto nosideret;
+ if (noside == EVAL_AVOID_SIDE_EFFECTS)
+ {
+ if (TYPE_CODE (VALUE_TYPE (arg1)) == TYPE_CODE_PTR
+ || TYPE_CODE (VALUE_TYPE (arg1)) == TYPE_CODE_REF
+ /* In C you can dereference an array to get the 1st elt. */
+ || TYPE_CODE (VALUE_TYPE (arg1)) == TYPE_CODE_ARRAY
+ )
+ return value_zero (TYPE_TARGET_TYPE (VALUE_TYPE (arg1)),
+ lval_memory);
+ else if (TYPE_CODE (VALUE_TYPE (arg1)) == TYPE_CODE_INT)
+ /* GDB allows dereferencing an int. */
+ return value_zero (builtin_type_int, lval_memory);
+ else
+ error ("Attempt to take contents of a non-pointer value.");
+ }
+ return value_ind (arg1);
+
+ case UNOP_ADDR:
+ /* C++: check for and handle pointer to members. */
+
+ op = exp->elts[*pos].opcode;
+
+ if (noside == EVAL_SKIP)
+ {
+ if (op == OP_SCOPE)
+ {
+ int temm = longest_to_int (exp->elts[pc+3].longconst);
+ (*pos) += 3 + BYTES_TO_EXP_ELEM (temm + 1);
+ }
+ else
+ evaluate_subexp (expect_type, exp, pos, EVAL_SKIP);
+ goto nosideret;
+ }
+
+ return evaluate_subexp_for_address (exp, pos, noside);
+
+ case UNOP_SIZEOF:
+ if (noside == EVAL_SKIP)
+ {
+ evaluate_subexp (NULL_TYPE, exp, pos, EVAL_SKIP);
+ goto nosideret;
+ }
+ return evaluate_subexp_for_sizeof (exp, pos);
+
+ case UNOP_CAST:
+ (*pos) += 2;
+ arg1 = evaluate_subexp (expect_type, exp, pos, noside);
+ if (noside == EVAL_SKIP)
+ goto nosideret;
+ return value_cast (exp->elts[pc + 1].type, arg1);
+
+ case UNOP_MEMVAL:
+ (*pos) += 2;
+ arg1 = evaluate_subexp (expect_type, exp, pos, noside);
+ if (noside == EVAL_SKIP)
+ goto nosideret;
+ if (noside == EVAL_AVOID_SIDE_EFFECTS)
+ return value_zero (exp->elts[pc + 1].type, lval_memory);
+ else
+ return value_at_lazy (exp->elts[pc + 1].type,
+ value_as_pointer (arg1));
+
+ case UNOP_PREINCREMENT:
+ arg1 = evaluate_subexp (expect_type, exp, pos, noside);
+ if (noside == EVAL_SKIP || noside == EVAL_AVOID_SIDE_EFFECTS)
+ return arg1;
+ else if (unop_user_defined_p (op, arg1))
+ {
+ return value_x_unop (arg1, op);
+ }
+ else
+ {
+ arg2 = value_add (arg1, value_from_longest (builtin_type_char,
+ (LONGEST) 1));
+ return value_assign (arg1, arg2);
+ }
+
+ case UNOP_PREDECREMENT:
+ arg1 = evaluate_subexp (expect_type, exp, pos, noside);
+ if (noside == EVAL_SKIP || noside == EVAL_AVOID_SIDE_EFFECTS)
+ return arg1;
+ else if (unop_user_defined_p (op, arg1))
+ {
+ return value_x_unop (arg1, op);
+ }
+ else
+ {
+ arg2 = value_sub (arg1, value_from_longest (builtin_type_char,
+ (LONGEST) 1));
+ return value_assign (arg1, arg2);
+ }
+
+ case UNOP_POSTINCREMENT:
+ arg1 = evaluate_subexp (expect_type, exp, pos, noside);
+ if (noside == EVAL_SKIP || noside == EVAL_AVOID_SIDE_EFFECTS)
+ return arg1;
+ else if (unop_user_defined_p (op, arg1))
+ {
+ return value_x_unop (arg1, op);
+ }
+ else
+ {
+ arg2 = value_add (arg1, value_from_longest (builtin_type_char,
+ (LONGEST) 1));
+ value_assign (arg1, arg2);
+ return arg1;
+ }
+
+ case UNOP_POSTDECREMENT:
+ arg1 = evaluate_subexp (expect_type, exp, pos, noside);
+ if (noside == EVAL_SKIP || noside == EVAL_AVOID_SIDE_EFFECTS)
+ return arg1;
+ else if (unop_user_defined_p (op, arg1))
+ {
+ return value_x_unop (arg1, op);
+ }
+ else
+ {
+ arg2 = value_sub (arg1, value_from_longest (builtin_type_char,
+ (LONGEST) 1));
+ value_assign (arg1, arg2);
+ return arg1;
+ }
+
+ case OP_THIS:
+ (*pos) += 1;
+ return value_of_this (1);
+
+ case OP_TYPE:
+ error ("Attempt to use a type name as an expression");
+
+ default:
+ /* Removing this case and compiling with gcc -Wall reveals that
+ a lot of cases are hitting this case. Some of these should
+ probably be removed from expression.h (e.g. do we need a BINOP_SCOPE
+ and an OP_SCOPE?); others are legitimate expressions which are
+ (apparently) not fully implemented.
+
+ If there are any cases landing here which mean a user error,
+ then they should be separate cases, with more descriptive
+ error messages. */
+
+ error ("\
+GDB does not (yet) know how to evaluated that kind of expression");
+ }
+
+ nosideret:
+ return value_from_longest (builtin_type_long, (LONGEST) 1);
+}
+
+/* Evaluate a subexpression of EXP, at index *POS,
+ and return the address of that subexpression.
+ Advance *POS over the subexpression.
+ If the subexpression isn't an lvalue, get an error.
+ NOSIDE may be EVAL_AVOID_SIDE_EFFECTS;
+ then only the type of the result need be correct. */
+
+static value_ptr
+evaluate_subexp_for_address (exp, pos, noside)
+ register struct expression *exp;
+ register int *pos;
+ enum noside noside;
+{
+ enum exp_opcode op;
+ register int pc;
+ struct symbol *var;
+
+ pc = (*pos);
+ op = exp->elts[pc].opcode;
+
+ switch (op)
+ {
+ case UNOP_IND:
+ (*pos)++;
+ return evaluate_subexp (NULL_TYPE, exp, pos, noside);
+
+ case UNOP_MEMVAL:
+ (*pos) += 3;
+ return value_cast (lookup_pointer_type (exp->elts[pc + 1].type),
+ evaluate_subexp (NULL_TYPE, exp, pos, noside));
+
+ case OP_VAR_VALUE:
+ var = exp->elts[pc + 2].symbol;
+
+ /* C++: The "address" of a reference should yield the address
+ * of the object pointed to. Let value_addr() deal with it. */
+ if (TYPE_CODE (SYMBOL_TYPE (var)) == TYPE_CODE_REF)
+ goto default_case;
+
+ (*pos) += 4;
+ if (noside == EVAL_AVOID_SIDE_EFFECTS)
+ {
+ struct type *type =
+ lookup_pointer_type (SYMBOL_TYPE (var));
+ enum address_class sym_class = SYMBOL_CLASS (var);
+
+ if (sym_class == LOC_CONST
+ || sym_class == LOC_CONST_BYTES
+ || sym_class == LOC_REGISTER
+ || sym_class == LOC_REGPARM)
+ error ("Attempt to take address of register or constant.");
+
+ return
+ value_zero (type, not_lval);
+ }
+ else
+ return
+ locate_var_value
+ (var,
+ block_innermost_frame (exp->elts[pc + 1].block));
+
+ default:
+ default_case:
+ if (noside == EVAL_AVOID_SIDE_EFFECTS)
+ {
+ value_ptr x = evaluate_subexp (NULL_TYPE, exp, pos, noside);
+ if (VALUE_LVAL (x) == lval_memory)
+ return value_zero (lookup_pointer_type (VALUE_TYPE (x)),
+ not_lval);
+ else
+ error ("Attempt to take address of non-lval");
+ }
+ return value_addr (evaluate_subexp (NULL_TYPE, exp, pos, noside));
+ }
+}
+
+/* Evaluate like `evaluate_subexp' except coercing arrays to pointers.
+ When used in contexts where arrays will be coerced anyway, this is
+ equivalent to `evaluate_subexp' but much faster because it avoids
+ actually fetching array contents (perhaps obsolete now that we have
+ VALUE_LAZY).
+
+ Note that we currently only do the coercion for C expressions, where
+ arrays are zero based and the coercion is correct. For other languages,
+ with nonzero based arrays, coercion loses. Use CAST_IS_CONVERSION
+ to decide if coercion is appropriate.
+
+ */
+
+static value_ptr
+evaluate_subexp_with_coercion (exp, pos, noside)
+ register struct expression *exp;
+ register int *pos;
+ enum noside noside;
+{
+ register enum exp_opcode op;
+ register int pc;
+ register value_ptr val;
+ struct symbol *var;
+
+ pc = (*pos);
+ op = exp->elts[pc].opcode;
+
+ switch (op)
+ {
+ case OP_VAR_VALUE:
+ var = exp->elts[pc + 2].symbol;
+ if (TYPE_CODE (SYMBOL_TYPE (var)) == TYPE_CODE_ARRAY
+ && CAST_IS_CONVERSION)
+ {
+ (*pos) += 4;
+ val =
+ locate_var_value
+ (var, block_innermost_frame (exp->elts[pc + 1].block));
+ return value_cast (lookup_pointer_type (TYPE_TARGET_TYPE (SYMBOL_TYPE (var))),
+ val);
+ }
+ /* FALLTHROUGH */
+
+ default:
+ return evaluate_subexp (NULL_TYPE, exp, pos, noside);
+ }
+}
+
+/* Evaluate a subexpression of EXP, at index *POS,
+ and return a value for the size of that subexpression.
+ Advance *POS over the subexpression. */
+
+static value_ptr
+evaluate_subexp_for_sizeof (exp, pos)
+ register struct expression *exp;
+ register int *pos;
+{
+ enum exp_opcode op;
+ register int pc;
+ value_ptr val;
+
+ pc = (*pos);
+ op = exp->elts[pc].opcode;
+
+ switch (op)
+ {
+ /* This case is handled specially
+ so that we avoid creating a value for the result type.
+ If the result type is very big, it's desirable not to
+ create a value unnecessarily. */
+ case UNOP_IND:
+ (*pos)++;
+ val = evaluate_subexp (NULL_TYPE, exp, pos, EVAL_AVOID_SIDE_EFFECTS);
+ return value_from_longest (builtin_type_int, (LONGEST)
+ TYPE_LENGTH (TYPE_TARGET_TYPE (VALUE_TYPE (val))));
+
+ case UNOP_MEMVAL:
+ (*pos) += 3;
+ return value_from_longest (builtin_type_int,
+ (LONGEST) TYPE_LENGTH (exp->elts[pc + 1].type));
+
+ case OP_VAR_VALUE:
+ (*pos) += 4;
+ return
+ value_from_longest
+ (builtin_type_int,
+ (LONGEST) TYPE_LENGTH (SYMBOL_TYPE (exp->elts[pc + 2].symbol)));
+
+ default:
+ val = evaluate_subexp (NULL_TYPE, exp, pos, EVAL_AVOID_SIDE_EFFECTS);
+ return value_from_longest (builtin_type_int,
+ (LONGEST) TYPE_LENGTH (VALUE_TYPE (val)));
+ }
+}
+
+/* Parse a type expression in the string [P..P+LENGTH). */
+
+struct type *
+parse_and_eval_type (p, length)
+ char *p;
+ int length;
+{
+ char *tmp = (char *)alloca (length + 4);
+ struct expression *expr;
+ tmp[0] = '(';
+ memcpy (tmp+1, p, length);
+ tmp[length+1] = ')';
+ tmp[length+2] = '0';
+ tmp[length+3] = '\0';
+ expr = parse_expression (tmp);
+ if (expr->elts[0].opcode != UNOP_CAST)
+ error ("Internal error in eval_type.");
+ return expr->elts[1].type;
+}
diff --git a/gnu/usr.bin/gdb/gdb/exec.c b/gnu/usr.bin/gdb/gdb/exec.c
new file mode 100644
index 0000000..4da0a48
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/exec.c
@@ -0,0 +1,506 @@
+/* Work with executable files, for GDB.
+ Copyright 1988, 1989, 1991, 1992, 1993, 1994 Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "defs.h"
+#include "frame.h"
+#include "inferior.h"
+#include "target.h"
+#include "gdbcmd.h"
+#include "language.h"
+
+#ifdef USG
+#include <sys/types.h>
+#endif
+
+#include <sys/param.h>
+#include <fcntl.h>
+#include <string.h>
+
+#include "gdbcore.h"
+
+#include <ctype.h>
+#include <sys/stat.h>
+#ifndef O_BINARY
+#define O_BINARY 0
+#endif
+
+/* Prototypes for local functions */
+
+static void
+add_to_section_table PARAMS ((bfd *, sec_ptr, PTR));
+
+static void
+exec_close PARAMS ((int));
+
+static void
+file_command PARAMS ((char *, int));
+
+static void
+set_section_command PARAMS ((char *, int));
+
+static void
+exec_files_info PARAMS ((struct target_ops *));
+
+extern int info_verbose;
+
+/* The Binary File Descriptor handle for the executable file. */
+
+bfd *exec_bfd = NULL;
+
+/* Whether to open exec and core files read-only or read-write. */
+
+int write_files = 0;
+
+/* Text start and end addresses (KLUDGE) if needed */
+
+#ifdef NEED_TEXT_START_END
+CORE_ADDR text_start = 0;
+CORE_ADDR text_end = 0;
+#endif
+
+/* Forward decl */
+
+extern struct target_ops exec_ops;
+
+/* ARGSUSED */
+static void
+exec_close (quitting)
+ int quitting;
+{
+ if (exec_bfd) {
+ char *name = bfd_get_filename (exec_bfd);
+ bfd_close (exec_bfd);
+ free (name);
+ exec_bfd = NULL;
+ }
+ if (exec_ops.to_sections) {
+ free ((PTR)exec_ops.to_sections);
+ exec_ops.to_sections = NULL;
+ exec_ops.to_sections_end = NULL;
+ }
+}
+
+/* Process the first arg in ARGS as the new exec file.
+
+ Note that we have to explicitly ignore additional args, since we can
+ be called from file_command(), which also calls symbol_file_command()
+ which can take multiple args. */
+
+void
+exec_file_command (args, from_tty)
+ char *args;
+ int from_tty;
+{
+ char **argv;
+ char *filename;
+
+ target_preopen (from_tty);
+
+ /* Remove any previous exec file. */
+ unpush_target (&exec_ops);
+
+ /* Now open and digest the file the user requested, if any. */
+
+ if (args)
+ {
+ char *scratch_pathname;
+ int scratch_chan;
+
+ /* Scan through the args and pick up the first non option arg
+ as the filename. */
+
+ if ((argv = buildargv (args)) == NULL)
+ {
+ nomem (0);
+ }
+ make_cleanup (freeargv, (char *) argv);
+
+ for (; (*argv != NULL) && (**argv == '-'); argv++) {;}
+ if (*argv == NULL)
+ {
+ error ("no exec file name was specified");
+ }
+
+ filename = tilde_expand (*argv);
+ make_cleanup (free, filename);
+
+ scratch_chan = openp (getenv ("PATH"), 1, filename,
+ write_files? O_RDWR|O_BINARY: O_RDONLY|O_BINARY, 0,
+ &scratch_pathname);
+ if (scratch_chan < 0)
+ perror_with_name (filename);
+
+ exec_bfd = bfd_fdopenr (scratch_pathname, gnutarget, scratch_chan);
+ if (!exec_bfd)
+ error ("Could not open `%s' as an executable file: %s",
+ scratch_pathname, bfd_errmsg (bfd_get_error ()));
+ if (!bfd_check_format (exec_bfd, bfd_object))
+ {
+ /* Make sure to close exec_bfd, or else "run" might try to use
+ it. */
+ exec_close (0);
+ error ("\"%s\": not in executable format: %s.",
+ scratch_pathname, bfd_errmsg (bfd_get_error ()));
+ }
+
+ if (build_section_table (exec_bfd, &exec_ops.to_sections,
+ &exec_ops.to_sections_end))
+ {
+ /* Make sure to close exec_bfd, or else "run" might try to use
+ it. */
+ exec_close (0);
+ error ("Can't find the file sections in `%s': %s",
+ exec_bfd->filename, bfd_errmsg (bfd_get_error ()));
+ }
+
+#ifdef NEED_TEXT_START_END
+
+ /* text_end is sometimes used for where to put call dummies. A
+ few ports use these for other purposes too. */
+
+ {
+ struct section_table *p;
+
+ /* Set text_start to the lowest address of the start of any
+ readonly code section and set text_end to the highest
+ address of the end of any readonly code section. */
+
+ text_start = ~(CORE_ADDR)0;
+ text_end = (CORE_ADDR)0;
+ for (p = exec_ops.to_sections; p < exec_ops.to_sections_end; p++)
+ if (bfd_get_section_flags (p->bfd, p->the_bfd_section)
+ & (SEC_CODE | SEC_READONLY))
+ {
+ if (text_start > p->addr)
+ text_start = p->addr;
+ if (text_end < p->endaddr)
+ text_end = p->endaddr;
+ }
+ }
+#endif
+
+ validate_files ();
+
+ push_target (&exec_ops);
+
+ /* Tell display code (if any) about the changed file name. */
+ if (exec_file_display_hook)
+ (*exec_file_display_hook) (filename);
+ }
+ else if (from_tty)
+ printf_unfiltered ("No exec file now.\n");
+}
+
+/* Set both the exec file and the symbol file, in one command.
+ What a novelty. Why did GDB go through four major releases before this
+ command was added? */
+
+static void
+file_command (arg, from_tty)
+ char *arg;
+ int from_tty;
+{
+ /* FIXME, if we lose on reading the symbol file, we should revert
+ the exec file, but that's rough. */
+ exec_file_command (arg, from_tty);
+ symbol_file_command (arg, from_tty);
+}
+
+
+/* Locate all mappable sections of a BFD file.
+ table_pp_char is a char * to get it through bfd_map_over_sections;
+ we cast it back to its proper type. */
+
+static void
+add_to_section_table (abfd, asect, table_pp_char)
+ bfd *abfd;
+ sec_ptr asect;
+ PTR table_pp_char;
+{
+ struct section_table **table_pp = (struct section_table **)table_pp_char;
+ flagword aflag;
+
+ aflag = bfd_get_section_flags (abfd, asect);
+ if (!(aflag & SEC_ALLOC))
+ return;
+ if (0 == bfd_section_size (abfd, asect))
+ return;
+ (*table_pp)->bfd = abfd;
+ (*table_pp)->the_bfd_section = asect;
+ (*table_pp)->addr = bfd_section_vma (abfd, asect);
+ (*table_pp)->endaddr = (*table_pp)->addr + bfd_section_size (abfd, asect);
+ (*table_pp)++;
+}
+
+/* Builds a section table, given args BFD, SECTABLE_PTR, SECEND_PTR.
+ Returns 0 if OK, 1 on error. */
+
+int
+build_section_table (some_bfd, start, end)
+ bfd *some_bfd;
+ struct section_table **start, **end;
+{
+ unsigned count;
+
+ count = bfd_count_sections (some_bfd);
+ if (*start)
+ free ((PTR)*start);
+ *start = (struct section_table *) xmalloc (count * sizeof (**start));
+ *end = *start;
+ bfd_map_over_sections (some_bfd, add_to_section_table, (char *)end);
+ if (*end > *start + count)
+ abort();
+ /* We could realloc the table, but it probably loses for most files. */
+ return 0;
+}
+
+/* Read or write the exec file.
+
+ Args are address within a BFD file, address within gdb address-space,
+ length, and a flag indicating whether to read or write.
+
+ Result is a length:
+
+ 0: We cannot handle this address and length.
+ > 0: We have handled N bytes starting at this address.
+ (If N == length, we did it all.) We might be able
+ to handle more bytes beyond this length, but no
+ promises.
+ < 0: We cannot handle this address, but if somebody
+ else handles (-N) bytes, we can start from there.
+
+ The same routine is used to handle both core and exec files;
+ we just tail-call it with more arguments to select between them. */
+
+int
+xfer_memory (memaddr, myaddr, len, write, target)
+ CORE_ADDR memaddr;
+ char *myaddr;
+ int len;
+ int write;
+ struct target_ops *target;
+{
+ boolean res;
+ struct section_table *p;
+ CORE_ADDR nextsectaddr, memend;
+ boolean (*xfer_fn) PARAMS ((bfd *, sec_ptr, PTR, file_ptr, bfd_size_type));
+
+ if (len <= 0)
+ abort();
+
+ memend = memaddr + len;
+ xfer_fn = write? bfd_set_section_contents: bfd_get_section_contents;
+ nextsectaddr = memend;
+
+ for (p = target->to_sections; p < target->to_sections_end; p++)
+ {
+ if (p->addr <= memaddr)
+ if (p->endaddr >= memend)
+ {
+ /* Entire transfer is within this section. */
+ res = xfer_fn (p->bfd, p->the_bfd_section, myaddr, memaddr - p->addr, len);
+ return (res != 0) ? len : 0;
+ }
+ else if (p->endaddr <= memaddr)
+ {
+ /* This section ends before the transfer starts. */
+ continue;
+ }
+ else
+ {
+ /* This section overlaps the transfer. Just do half. */
+ len = p->endaddr - memaddr;
+ res = xfer_fn (p->bfd, p->the_bfd_section, myaddr, memaddr - p->addr, len);
+ return (res != 0) ? len : 0;
+ }
+ else if (p->addr < nextsectaddr)
+ nextsectaddr = p->addr;
+ }
+
+ if (nextsectaddr >= memend)
+ return 0; /* We can't help */
+ else
+ return - (nextsectaddr - memaddr); /* Next boundary where we can help */
+}
+
+#ifdef FIXME
+#ifdef REG_STACK_SEGMENT
+/* MOVE TO BFD... */
+ /* Pyramids and AM29000s have an extra segment in the virtual address space
+ for the (control) stack of register-window frames. The AM29000 folk
+ call it the "register stack" rather than the "memory stack". */
+ else if (memaddr >= reg_stack_start && memaddr < reg_stack_end)
+ {
+ i = min (len, reg_stack_end - memaddr);
+ fileptr = memaddr - reg_stack_start + reg_stack_offset;
+ wanna_xfer = coredata;
+ }
+#endif /* REG_STACK_SEGMENT */
+#endif /* FIXME */
+
+void
+print_section_info (t, abfd)
+ struct target_ops *t;
+ bfd *abfd;
+{
+ struct section_table *p;
+
+ printf_filtered ("\t`%s', ", bfd_get_filename(abfd));
+ wrap_here (" ");
+ printf_filtered ("file type %s.\n", bfd_get_target(abfd));
+ if (abfd == exec_bfd)
+ {
+ printf_filtered ("\tEntry point: ");
+ print_address_numeric (bfd_get_start_address (abfd), 1, gdb_stdout);
+ printf_filtered ("\n");
+ }
+ for (p = t->to_sections; p < t->to_sections_end; p++)
+ {
+ /* FIXME-32x64 need a print_address_numeric with field width */
+ printf_filtered ("\t%s", local_hex_string_custom ((unsigned long) p->addr, "08l"));
+ printf_filtered (" - %s", local_hex_string_custom ((unsigned long) p->endaddr, "08l"));
+ if (info_verbose)
+ printf_filtered (" @ %s",
+ local_hex_string_custom ((unsigned long) p->the_bfd_section->filepos, "08l"));
+ printf_filtered (" is %s", bfd_section_name (p->bfd, p->the_bfd_section));
+ if (p->bfd != abfd)
+ {
+ printf_filtered (" in %s", bfd_get_filename (p->bfd));
+ }
+ printf_filtered ("\n");
+ }
+}
+
+static void
+exec_files_info (t)
+ struct target_ops *t;
+{
+ print_section_info (t, exec_bfd);
+}
+
+static void
+set_section_command (args, from_tty)
+ char *args;
+ int from_tty;
+{
+ struct section_table *p;
+ char *secname;
+ unsigned seclen;
+ unsigned long secaddr;
+ char secprint[100];
+ long offset;
+
+ if (args == 0)
+ error ("Must specify section name and its virtual address");
+
+ /* Parse out section name */
+ for (secname = args; !isspace(*args); args++) ;
+ seclen = args - secname;
+
+ /* Parse out new virtual address */
+ secaddr = parse_and_eval_address (args);
+
+ for (p = exec_ops.to_sections; p < exec_ops.to_sections_end; p++) {
+ if (!strncmp (secname, bfd_section_name (exec_bfd, p->the_bfd_section), seclen)
+ && bfd_section_name (exec_bfd, p->the_bfd_section)[seclen] == '\0') {
+ offset = secaddr - p->addr;
+ p->addr += offset;
+ p->endaddr += offset;
+ if (from_tty)
+ exec_files_info(&exec_ops);
+ return;
+ }
+ }
+ if (seclen >= sizeof (secprint))
+ seclen = sizeof (secprint) - 1;
+ strncpy (secprint, secname, seclen);
+ secprint[seclen] = '\0';
+ error ("Section %s not found", secprint);
+}
+
+/* If mourn is being called in all the right places, this could be say
+ `gdb internal error' (since generic_mourn calls breakpoint_init_inferior). */
+
+static int
+ignore (addr, contents)
+ CORE_ADDR addr;
+ char *contents;
+{
+ return 0;
+}
+
+struct target_ops exec_ops = {
+ "exec", "Local exec file",
+ "Use an executable file as a target.\n\
+Specify the filename of the executable file.",
+ exec_file_command, exec_close, /* open, close */
+ find_default_attach, 0, 0, 0, /* attach, detach, resume, wait, */
+ 0, 0, /* fetch_registers, store_registers, */
+ 0, /* prepare_to_store, */
+ xfer_memory, exec_files_info,
+ ignore, ignore, /* insert_breakpoint, remove_breakpoint, */
+ 0, 0, 0, 0, 0, /* terminal stuff */
+ 0, 0, /* kill, load */
+ 0, /* lookup sym */
+ find_default_create_inferior,
+ 0, /* mourn_inferior */
+ 0, /* can_run */
+ 0, /* notice_signals */
+ file_stratum, 0, /* next */
+ 0, 1, 0, 0, 0, /* all mem, mem, stack, regs, exec */
+ 0, 0, /* section pointers */
+ OPS_MAGIC, /* Always the last thing */
+};
+
+void
+_initialize_exec()
+{
+ struct cmd_list_element *c;
+
+ c = add_cmd ("file", class_files, file_command,
+ "Use FILE as program to be debugged.\n\
+It is read for its symbols, for getting the contents of pure memory,\n\
+and it is the program executed when you use the `run' command.\n\
+If FILE cannot be found as specified, your execution directory path\n\
+($PATH) is searched for a command of that name.\n\
+No arg means to have no executable file and no symbols.", &cmdlist);
+ c->completer = filename_completer;
+
+ c = add_cmd ("exec-file", class_files, exec_file_command,
+ "Use FILE as program for getting contents of pure memory.\n\
+If FILE cannot be found as specified, your execution directory path\n\
+is searched for a command of that name.\n\
+No arg means have no executable file.", &cmdlist);
+ c->completer = filename_completer;
+
+ add_com ("section", class_files, set_section_command,
+ "Change the base address of section SECTION of the exec file to ADDR.\n\
+This can be used if the exec file does not contain section addresses,\n\
+(such as in the a.out format), or when the addresses specified in the\n\
+file itself are wrong. Each section must be changed separately. The\n\
+``info files'' command lists all the sections and their addresses.");
+
+ add_show_from_set
+ (add_set_cmd ("write", class_support, var_boolean, (char *)&write_files,
+ "Set writing into executable and core files.",
+ &setlist),
+ &showlist);
+
+ add_target (&exec_ops);
+}
diff --git a/gnu/usr.bin/gdb/gdb/expprint.c b/gnu/usr.bin/gdb/gdb/expprint.c
new file mode 100644
index 0000000..14e2a40
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/expprint.c
@@ -0,0 +1,624 @@
+/* Print in infix form a struct expression.
+ Copyright (C) 1986, 1989, 1991 Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "defs.h"
+#include "symtab.h"
+#include "gdbtypes.h"
+#include "expression.h"
+#include "value.h"
+#include "language.h"
+#include "parser-defs.h"
+
+/* Prototypes for local functions */
+
+static void
+print_subexp PARAMS ((struct expression *, int *, GDB_FILE *, enum precedence));
+
+static void
+print_simple_m2_func PARAMS ((char *, struct expression *, int *, GDB_FILE *));
+
+void
+print_expression (exp, stream)
+ struct expression *exp;
+ GDB_FILE *stream;
+{
+ int pc = 0;
+ print_subexp (exp, &pc, stream, PREC_NULL);
+}
+
+/* Print the subexpression of EXP that starts in position POS, on STREAM.
+ PREC is the precedence of the surrounding operator;
+ if the precedence of the main operator of this subexpression is less,
+ parentheses are needed here. */
+
+static void
+print_subexp (exp, pos, stream, prec)
+ register struct expression *exp;
+ register int *pos;
+ GDB_FILE *stream;
+ enum precedence prec;
+{
+ register unsigned tem;
+ register const struct op_print *op_print_tab;
+ register int pc;
+ unsigned nargs;
+ register char *op_str;
+ int assign_modify = 0;
+ enum exp_opcode opcode;
+ enum precedence myprec = PREC_NULL;
+ /* Set to 1 for a right-associative operator. */
+ int assoc = 0;
+ value_ptr val;
+ char *tempstr = NULL;
+
+ op_print_tab = exp->language_defn->la_op_print_tab;
+ pc = (*pos)++;
+ opcode = exp->elts[pc].opcode;
+ switch (opcode)
+ {
+ /* Common ops */
+
+ case OP_SCOPE:
+ myprec = PREC_PREFIX;
+ assoc = 0;
+ fputs_filtered (type_name_no_tag (exp->elts[pc + 1].type), stream);
+ fputs_filtered ("::", stream);
+ nargs = longest_to_int (exp->elts[pc + 2].longconst);
+ (*pos) += 4 + BYTES_TO_EXP_ELEM (nargs + 1);
+ fputs_filtered (&exp->elts[pc + 3].string, stream);
+ return;
+
+ case OP_LONG:
+ (*pos) += 3;
+ value_print (value_from_longest (exp->elts[pc + 1].type,
+ exp->elts[pc + 2].longconst),
+ stream, 0, Val_no_prettyprint);
+ return;
+
+ case OP_DOUBLE:
+ (*pos) += 3;
+ value_print (value_from_double (exp->elts[pc + 1].type,
+ exp->elts[pc + 2].doubleconst),
+ stream, 0, Val_no_prettyprint);
+ return;
+
+ case OP_VAR_VALUE:
+ {
+ struct block *b;
+ (*pos) += 3;
+ b = exp->elts[pc + 1].block;
+ if (b != NULL
+ && BLOCK_FUNCTION (b) != NULL
+ && SYMBOL_SOURCE_NAME (BLOCK_FUNCTION (b)) != NULL)
+ {
+ fputs_filtered (SYMBOL_SOURCE_NAME (BLOCK_FUNCTION (b)), stream);
+ fputs_filtered ("::", stream);
+ }
+ fputs_filtered (SYMBOL_SOURCE_NAME (exp->elts[pc + 2].symbol), stream);
+ }
+ return;
+
+ case OP_LAST:
+ (*pos) += 2;
+ fprintf_filtered (stream, "$%d",
+ longest_to_int (exp->elts[pc + 1].longconst));
+ return;
+
+ case OP_REGISTER:
+ (*pos) += 2;
+ fprintf_filtered (stream, "$%s",
+ reg_names[longest_to_int (exp->elts[pc + 1].longconst)]);
+ return;
+
+ case OP_BOOL:
+ (*pos) += 2;
+ fprintf_filtered (stream, "%s",
+ longest_to_int (exp->elts[pc + 1].longconst)
+ ? "TRUE" : "FALSE");
+ return;
+
+ case OP_INTERNALVAR:
+ (*pos) += 2;
+ fprintf_filtered (stream, "$%s",
+ internalvar_name (exp->elts[pc + 1].internalvar));
+ return;
+
+ case OP_FUNCALL:
+ (*pos) += 2;
+ nargs = longest_to_int (exp->elts[pc + 1].longconst);
+ print_subexp (exp, pos, stream, PREC_SUFFIX);
+ fputs_filtered (" (", stream);
+ for (tem = 0; tem < nargs; tem++)
+ {
+ if (tem != 0)
+ fputs_filtered (", ", stream);
+ print_subexp (exp, pos, stream, PREC_ABOVE_COMMA);
+ }
+ fputs_filtered (")", stream);
+ return;
+
+ case OP_STRING:
+ nargs = longest_to_int (exp -> elts[pc + 1].longconst);
+ (*pos) += 3 + BYTES_TO_EXP_ELEM (nargs + 1);
+ /* LA_PRINT_STRING will print using the current repeat count threshold.
+ If necessary, we can temporarily set it to zero, or pass it as an
+ additional parameter to LA_PRINT_STRING. -fnf */
+ LA_PRINT_STRING (stream, &exp->elts[pc + 2].string, nargs, 0);
+ return;
+
+ case OP_BITSTRING:
+ error ("support for OP_BITSTRING unimplemented");
+ break;
+
+ case OP_ARRAY:
+ (*pos) += 3;
+ nargs = longest_to_int (exp->elts[pc + 2].longconst);
+ nargs -= longest_to_int (exp->elts[pc + 1].longconst);
+ nargs++;
+ tem = 0;
+ if (exp->elts[pc + 4].opcode == OP_LONG
+ && exp->elts[pc + 5].type == builtin_type_char
+ && exp->language_defn->la_language == language_c)
+ {
+ /* Attempt to print C character arrays using string syntax.
+ Walk through the args, picking up one character from each
+ of the OP_LONG expression elements. If any array element
+ does not match our expection of what we should find for
+ a simple string, revert back to array printing. Note that
+ the last expression element is an explicit null terminator
+ byte, which doesn't get printed. */
+ tempstr = alloca (nargs);
+ pc += 4;
+ while (tem < nargs)
+ {
+ if (exp->elts[pc].opcode != OP_LONG
+ || exp->elts[pc + 1].type != builtin_type_char)
+ {
+ /* Not a simple array of char, use regular array printing. */
+ tem = 0;
+ break;
+ }
+ else
+ {
+ tempstr[tem++] =
+ longest_to_int (exp->elts[pc + 2].longconst);
+ pc += 4;
+ }
+ }
+ }
+ if (tem > 0)
+ {
+ LA_PRINT_STRING (stream, tempstr, nargs - 1, 0);
+ (*pos) = pc;
+ }
+ else
+ {
+ fputs_filtered (" {", stream);
+ for (tem = 0; tem < nargs; tem++)
+ {
+ if (tem != 0)
+ {
+ fputs_filtered (", ", stream);
+ }
+ print_subexp (exp, pos, stream, PREC_ABOVE_COMMA);
+ }
+ fputs_filtered ("}", stream);
+ }
+ return;
+
+ case TERNOP_COND:
+ if ((int) prec > (int) PREC_COMMA)
+ fputs_filtered ("(", stream);
+ /* Print the subexpressions, forcing parentheses
+ around any binary operations within them.
+ This is more parentheses than are strictly necessary,
+ but it looks clearer. */
+ print_subexp (exp, pos, stream, PREC_HYPER);
+ fputs_filtered (" ? ", stream);
+ print_subexp (exp, pos, stream, PREC_HYPER);
+ fputs_filtered (" : ", stream);
+ print_subexp (exp, pos, stream, PREC_HYPER);
+ if ((int) prec > (int) PREC_COMMA)
+ fputs_filtered (")", stream);
+ return;
+
+ case STRUCTOP_STRUCT:
+ tem = longest_to_int (exp->elts[pc + 1].longconst);
+ (*pos) += 3 + BYTES_TO_EXP_ELEM (tem + 1);
+ print_subexp (exp, pos, stream, PREC_SUFFIX);
+ fputs_filtered (".", stream);
+ fputs_filtered (&exp->elts[pc + 2].string, stream);
+ return;
+
+ /* Will not occur for Modula-2 */
+ case STRUCTOP_PTR:
+ tem = longest_to_int (exp->elts[pc + 1].longconst);
+ (*pos) += 3 + BYTES_TO_EXP_ELEM (tem + 1);
+ print_subexp (exp, pos, stream, PREC_SUFFIX);
+ fputs_filtered ("->", stream);
+ fputs_filtered (&exp->elts[pc + 2].string, stream);
+ return;
+
+ case BINOP_SUBSCRIPT:
+ print_subexp (exp, pos, stream, PREC_SUFFIX);
+ fputs_filtered ("[", stream);
+ print_subexp (exp, pos, stream, PREC_ABOVE_COMMA);
+ fputs_filtered ("]", stream);
+ return;
+
+ case UNOP_POSTINCREMENT:
+ print_subexp (exp, pos, stream, PREC_SUFFIX);
+ fputs_filtered ("++", stream);
+ return;
+
+ case UNOP_POSTDECREMENT:
+ print_subexp (exp, pos, stream, PREC_SUFFIX);
+ fputs_filtered ("--", stream);
+ return;
+
+ case UNOP_CAST:
+ (*pos) += 2;
+ if ((int) prec > (int) PREC_PREFIX)
+ fputs_filtered ("(", stream);
+ fputs_filtered ("(", stream);
+ type_print (exp->elts[pc + 1].type, "", stream, 0);
+ fputs_filtered (") ", stream);
+ print_subexp (exp, pos, stream, PREC_PREFIX);
+ if ((int) prec > (int) PREC_PREFIX)
+ fputs_filtered (")", stream);
+ return;
+
+ case UNOP_MEMVAL:
+ (*pos) += 2;
+ if ((int) prec > (int) PREC_PREFIX)
+ fputs_filtered ("(", stream);
+ if (exp->elts[pc + 1].type->code == TYPE_CODE_FUNC &&
+ exp->elts[pc + 3].opcode == OP_LONG) {
+ /* We have a minimal symbol fn, probably. It's encoded
+ as a UNOP_MEMVAL (function-type) of an OP_LONG (int, address).
+ Swallow the OP_LONG (including both its opcodes); ignore
+ its type; print the value in the type of the MEMVAL. */
+ (*pos) += 4;
+ val = value_at_lazy (exp->elts[pc + 1].type,
+ (CORE_ADDR) exp->elts[pc + 5].longconst);
+ value_print (val, stream, 0, Val_no_prettyprint);
+ } else {
+ fputs_filtered ("{", stream);
+ type_print (exp->elts[pc + 1].type, "", stream, 0);
+ fputs_filtered ("} ", stream);
+ print_subexp (exp, pos, stream, PREC_PREFIX);
+ }
+ if ((int) prec > (int) PREC_PREFIX)
+ fputs_filtered (")", stream);
+ return;
+
+ case BINOP_ASSIGN_MODIFY:
+ opcode = exp->elts[pc + 1].opcode;
+ (*pos) += 2;
+ myprec = PREC_ASSIGN;
+ assoc = 1;
+ assign_modify = 1;
+ op_str = "???";
+ for (tem = 0; op_print_tab[tem].opcode != OP_NULL; tem++)
+ if (op_print_tab[tem].opcode == opcode)
+ {
+ op_str = op_print_tab[tem].string;
+ break;
+ }
+ if (op_print_tab[tem].opcode != opcode)
+ /* Not found; don't try to keep going because we don't know how
+ to interpret further elements. */
+ error ("Invalid expression");
+ break;
+
+ /* C++ ops */
+
+ case OP_THIS:
+ ++(*pos);
+ fputs_filtered ("this", stream);
+ return;
+
+ /* Modula-2 ops */
+
+ case MULTI_SUBSCRIPT:
+ (*pos) += 2;
+ nargs = longest_to_int (exp->elts[pc + 1].longconst);
+ print_subexp (exp, pos, stream, PREC_SUFFIX);
+ fprintf_unfiltered (stream, " [");
+ for (tem = 0; tem < nargs; tem++)
+ {
+ if (tem != 0)
+ fprintf_unfiltered (stream, ", ");
+ print_subexp (exp, pos, stream, PREC_ABOVE_COMMA);
+ }
+ fprintf_unfiltered (stream, "]");
+ return;
+
+ case BINOP_VAL:
+ (*pos)+=2;
+ fprintf_unfiltered(stream,"VAL(");
+ type_print(exp->elts[pc+1].type,"",stream,0);
+ fprintf_unfiltered(stream,",");
+ print_subexp(exp,pos,stream,PREC_PREFIX);
+ fprintf_unfiltered(stream,")");
+ return;
+
+ case UNOP_CAP:
+ print_simple_m2_func("CAP",exp,pos,stream);
+ return;
+
+ case UNOP_CHR:
+ print_simple_m2_func("CHR",exp,pos,stream);
+ return;
+
+ case UNOP_ORD:
+ print_simple_m2_func("ORD",exp,pos,stream);
+ return;
+
+ case UNOP_ABS:
+ print_simple_m2_func("ABS",exp,pos,stream);
+ return;
+
+ case UNOP_FLOAT:
+ print_simple_m2_func("FLOAT",exp,pos,stream);
+ return;
+
+ case UNOP_HIGH:
+ print_simple_m2_func("HIGH",exp,pos,stream);
+ return;
+
+ case UNOP_MAX:
+ print_simple_m2_func("MAX",exp,pos,stream);
+ return;
+
+ case UNOP_MIN:
+ print_simple_m2_func("MIN",exp,pos,stream);
+ return;
+
+ case UNOP_ODD:
+ print_simple_m2_func("ODD",exp,pos,stream);
+ return;
+
+ case UNOP_TRUNC:
+ print_simple_m2_func("TRUNC",exp,pos,stream);
+ return;
+
+ case BINOP_INCL:
+ case BINOP_EXCL:
+ error("print_subexp: Not implemented.");
+
+ /* Default ops */
+
+ default:
+ op_str = "???";
+ for (tem = 0; op_print_tab[tem].opcode != OP_NULL; tem++)
+ if (op_print_tab[tem].opcode == opcode)
+ {
+ op_str = op_print_tab[tem].string;
+ myprec = op_print_tab[tem].precedence;
+ assoc = op_print_tab[tem].right_assoc;
+ break;
+ }
+ if (op_print_tab[tem].opcode != opcode)
+ /* Not found; don't try to keep going because we don't know how
+ to interpret further elements. For example, this happens
+ if opcode is OP_TYPE. */
+ error ("Invalid expression");
+ }
+
+ if ((int) myprec < (int) prec)
+ fputs_filtered ("(", stream);
+ if ((int) opcode > (int) BINOP_END)
+ {
+ /* Unary prefix operator. */
+ fputs_filtered (op_str, stream);
+ print_subexp (exp, pos, stream, PREC_PREFIX);
+ }
+ else
+ {
+ /* Binary operator. */
+ /* Print left operand.
+ If operator is right-associative,
+ increment precedence for this operand. */
+ print_subexp (exp, pos, stream,
+ (enum precedence) ((int) myprec + assoc));
+ /* Print the operator itself. */
+ if (assign_modify)
+ fprintf_filtered (stream, " %s= ", op_str);
+ else if (op_str[0] == ',')
+ fprintf_filtered (stream, "%s ", op_str);
+ else
+ fprintf_filtered (stream, " %s ", op_str);
+ /* Print right operand.
+ If operator is left-associative,
+ increment precedence for this operand. */
+ print_subexp (exp, pos, stream,
+ (enum precedence) ((int) myprec + !assoc));
+ }
+
+ if ((int) myprec < (int) prec)
+ fputs_filtered (")", stream);
+}
+
+/* Print out something of the form <s>(<arg>).
+ This is used to print out some builtin Modula-2
+ functions.
+ FIXME: There is probably some way to get the precedence
+ rules to do this (print a unary operand with parens around it). */
+static void
+print_simple_m2_func(s,exp,pos,stream)
+ char *s;
+ register struct expression *exp;
+ register int *pos;
+ GDB_FILE *stream;
+{
+ fprintf_unfiltered(stream,"%s(",s);
+ print_subexp(exp,pos,stream,PREC_PREFIX);
+ fprintf_unfiltered(stream,")");
+}
+
+/* Return the operator corresponding to opcode OP as
+ a string. NULL indicates that the opcode was not found in the
+ current language table. */
+char *
+op_string(op)
+ enum exp_opcode op;
+{
+ int tem;
+ register const struct op_print *op_print_tab;
+
+ op_print_tab = current_language->la_op_print_tab;
+ for (tem = 0; op_print_tab[tem].opcode != OP_NULL; tem++)
+ if (op_print_tab[tem].opcode == op)
+ return op_print_tab[tem].string;
+ return NULL;
+}
+
+#ifdef DEBUG_EXPRESSIONS
+
+/* Support for dumping the raw data from expressions in a human readable
+ form. */
+
+void
+dump_expression (exp, stream, note)
+ struct expression *exp;
+ GDB_FILE *stream;
+ char *note;
+{
+ int elt;
+ char *opcode_name;
+ char *eltscan;
+ int eltsize;
+
+ fprintf_filtered (stream, "Dump of expression @ ");
+ gdb_print_address (exp, stream);
+ fprintf_filtered (stream, ", %s:\n", note);
+ fprintf_filtered (stream, "\tLanguage %s, %d elements, %d bytes each.\n",
+ exp->language_defn->la_name, exp -> nelts,
+ sizeof (union exp_element));
+ fprintf_filtered (stream, "\t%5s %20s %16s %s\n", "Index", "Opcode",
+ "Hex Value", "String Value");
+ for (elt = 0; elt < exp -> nelts; elt++)
+ {
+ fprintf_filtered (stream, "\t%5d ", elt);
+ switch (exp -> elts[elt].opcode)
+ {
+ default: opcode_name = "<unknown>"; break;
+ case OP_NULL: opcode_name = "OP_NULL"; break;
+ case BINOP_ADD: opcode_name = "BINOP_ADD"; break;
+ case BINOP_SUB: opcode_name = "BINOP_SUB"; break;
+ case BINOP_MUL: opcode_name = "BINOP_MUL"; break;
+ case BINOP_DIV: opcode_name = "BINOP_DIV"; break;
+ case BINOP_REM: opcode_name = "BINOP_REM"; break;
+ case BINOP_MOD: opcode_name = "BINOP_MOD"; break;
+ case BINOP_LSH: opcode_name = "BINOP_LSH"; break;
+ case BINOP_RSH: opcode_name = "BINOP_RSH"; break;
+ case BINOP_LOGICAL_AND: opcode_name = "BINOP_LOGICAL_AND"; break;
+ case BINOP_LOGICAL_OR: opcode_name = "BINOP_LOGICAL_OR"; break;
+ case BINOP_BITWISE_AND: opcode_name = "BINOP_BITWISE_AND"; break;
+ case BINOP_BITWISE_IOR: opcode_name = "BINOP_BITWISE_IOR"; break;
+ case BINOP_BITWISE_XOR: opcode_name = "BINOP_BITWISE_XOR"; break;
+ case BINOP_EQUAL: opcode_name = "BINOP_EQUAL"; break;
+ case BINOP_NOTEQUAL: opcode_name = "BINOP_NOTEQUAL"; break;
+ case BINOP_LESS: opcode_name = "BINOP_LESS"; break;
+ case BINOP_GTR: opcode_name = "BINOP_GTR"; break;
+ case BINOP_LEQ: opcode_name = "BINOP_LEQ"; break;
+ case BINOP_GEQ: opcode_name = "BINOP_GEQ"; break;
+ case BINOP_REPEAT: opcode_name = "BINOP_REPEAT"; break;
+ case BINOP_ASSIGN: opcode_name = "BINOP_ASSIGN"; break;
+ case BINOP_COMMA: opcode_name = "BINOP_COMMA"; break;
+ case BINOP_SUBSCRIPT: opcode_name = "BINOP_SUBSCRIPT"; break;
+ case MULTI_SUBSCRIPT: opcode_name = "MULTI_SUBSCRIPT"; break;
+ case BINOP_EXP: opcode_name = "BINOP_EXP"; break;
+ case BINOP_MIN: opcode_name = "BINOP_MIN"; break;
+ case BINOP_MAX: opcode_name = "BINOP_MAX"; break;
+ case BINOP_SCOPE: opcode_name = "BINOP_SCOPE"; break;
+ case STRUCTOP_MEMBER: opcode_name = "STRUCTOP_MEMBER"; break;
+ case STRUCTOP_MPTR: opcode_name = "STRUCTOP_MPTR"; break;
+ case BINOP_INTDIV: opcode_name = "BINOP_INTDIV"; break;
+ case BINOP_ASSIGN_MODIFY: opcode_name = "BINOP_ASSIGN_MODIFY"; break;
+ case BINOP_VAL: opcode_name = "BINOP_VAL"; break;
+ case BINOP_INCL: opcode_name = "BINOP_INCL"; break;
+ case BINOP_EXCL: opcode_name = "BINOP_EXCL"; break;
+ case BINOP_CONCAT: opcode_name = "BINOP_CONCAT"; break;
+ case BINOP_END: opcode_name = "BINOP_END"; break;
+ case TERNOP_COND: opcode_name = "TERNOP_COND"; break;
+ case OP_LONG: opcode_name = "OP_LONG"; break;
+ case OP_DOUBLE: opcode_name = "OP_DOUBLE"; break;
+ case OP_VAR_VALUE: opcode_name = "OP_VAR_VALUE"; break;
+ case OP_LAST: opcode_name = "OP_LAST"; break;
+ case OP_REGISTER: opcode_name = "OP_REGISTER"; break;
+ case OP_INTERNALVAR: opcode_name = "OP_INTERNALVAR"; break;
+ case OP_FUNCALL: opcode_name = "OP_FUNCALL"; break;
+ case OP_STRING: opcode_name = "OP_STRING"; break;
+ case OP_BITSTRING: opcode_name = "OP_BITSTRING"; break;
+ case OP_ARRAY: opcode_name = "OP_ARRAY"; break;
+ case UNOP_CAST: opcode_name = "UNOP_CAST"; break;
+ case UNOP_MEMVAL: opcode_name = "UNOP_MEMVAL"; break;
+ case UNOP_NEG: opcode_name = "UNOP_NEG"; break;
+ case UNOP_LOGICAL_NOT: opcode_name = "UNOP_LOGICAL_NOT"; break;
+ case UNOP_COMPLEMENT: opcode_name = "UNOP_COMPLEMENT"; break;
+ case UNOP_IND: opcode_name = "UNOP_IND"; break;
+ case UNOP_ADDR: opcode_name = "UNOP_ADDR"; break;
+ case UNOP_PREINCREMENT: opcode_name = "UNOP_PREINCREMENT"; break;
+ case UNOP_POSTINCREMENT: opcode_name = "UNOP_POSTINCREMENT"; break;
+ case UNOP_PREDECREMENT: opcode_name = "UNOP_PREDECREMENT"; break;
+ case UNOP_POSTDECREMENT: opcode_name = "UNOP_POSTDECREMENT"; break;
+ case UNOP_SIZEOF: opcode_name = "UNOP_SIZEOF"; break;
+ case UNOP_PLUS: opcode_name = "UNOP_PLUS"; break;
+ case UNOP_CAP: opcode_name = "UNOP_CAP"; break;
+ case UNOP_CHR: opcode_name = "UNOP_CHR"; break;
+ case UNOP_ORD: opcode_name = "UNOP_ORD"; break;
+ case UNOP_ABS: opcode_name = "UNOP_ABS"; break;
+ case UNOP_FLOAT: opcode_name = "UNOP_FLOAT"; break;
+ case UNOP_HIGH: opcode_name = "UNOP_HIGH"; break;
+ case UNOP_MAX: opcode_name = "UNOP_MAX"; break;
+ case UNOP_MIN: opcode_name = "UNOP_MIN"; break;
+ case UNOP_ODD: opcode_name = "UNOP_ODD"; break;
+ case UNOP_TRUNC: opcode_name = "UNOP_TRUNC"; break;
+ case OP_BOOL: opcode_name = "OP_BOOL"; break;
+ case OP_M2_STRING: opcode_name = "OP_M2_STRING"; break;
+ case STRUCTOP_STRUCT: opcode_name = "STRUCTOP_STRUCT"; break;
+ case STRUCTOP_PTR: opcode_name = "STRUCTOP_PTR"; break;
+ case OP_THIS: opcode_name = "OP_THIS"; break;
+ case OP_SCOPE: opcode_name = "OP_SCOPE"; break;
+ case OP_TYPE: opcode_name = "OP_TYPE"; break;
+ }
+ fprintf_filtered (stream, "%20s ", opcode_name);
+ fprintf_filtered (stream,
+#if defined (PRINTF_HAS_LONG_LONG)
+ "%ll16x ",
+#else
+ "%l16x ",
+#endif
+ exp -> elts[elt].longconst);
+
+ for (eltscan = (char *) &exp->elts[elt],
+ eltsize = sizeof (union exp_element) ;
+ eltsize-- > 0;
+ eltscan++)
+ {
+ fprintf_filtered (stream, "%c",
+ isprint (*eltscan) ? (*eltscan & 0xFF) : '.');
+ }
+ fprintf_filtered (stream, "\n");
+ }
+}
+
+#endif /* DEBUG_EXPRESSIONS */
diff --git a/gnu/usr.bin/gdb/gdb/expression.h b/gnu/usr.bin/gdb/gdb/expression.h
new file mode 100644
index 0000000..1f85a3f
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/expression.h
@@ -0,0 +1,316 @@
+/* Definitions for expressions stored in reversed prefix form, for GDB.
+ Copyright 1986, 1989, 1992 Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#if !defined (EXPRESSION_H)
+#define EXPRESSION_H 1
+
+#ifdef __STDC__
+struct block; /* Forward declaration for prototypes */
+#endif
+
+/* Definitions for saved C expressions. */
+
+/* An expression is represented as a vector of union exp_element's.
+ Each exp_element is an opcode, except that some opcodes cause
+ the following exp_element to be treated as a long or double constant
+ or as a variable. The opcodes are obeyed, using a stack for temporaries.
+ The value is left on the temporary stack at the end. */
+
+/* When it is necessary to include a string,
+ it can occupy as many exp_elements as it needs.
+ We find the length of the string using strlen,
+ divide to find out how many exp_elements are used up,
+ and skip that many. Strings, like numbers, are indicated
+ by the preceding opcode. */
+
+enum exp_opcode
+{
+ /* Used when it's necessary to pass an opcode which will be ignored,
+ or to catch uninitialized values. */
+ OP_NULL,
+
+/* BINOP_... operate on two values computed by following subexpressions,
+ replacing them by one result value. They take no immediate arguments. */
+ BINOP_ADD, /* + */
+ BINOP_SUB, /* - */
+ BINOP_MUL, /* * */
+ BINOP_DIV, /* / */
+ BINOP_REM, /* % */
+ BINOP_MOD, /* mod (Knuth 1.2.4) */
+ BINOP_LSH, /* << */
+ BINOP_RSH, /* >> */
+ BINOP_LOGICAL_AND, /* && */
+ BINOP_LOGICAL_OR, /* || */
+ BINOP_BITWISE_AND, /* & */
+ BINOP_BITWISE_IOR, /* | */
+ BINOP_BITWISE_XOR, /* ^ */
+ BINOP_EQUAL, /* == */
+ BINOP_NOTEQUAL, /* != */
+ BINOP_LESS, /* < */
+ BINOP_GTR, /* > */
+ BINOP_LEQ, /* <= */
+ BINOP_GEQ, /* >= */
+ BINOP_REPEAT, /* @ */
+ BINOP_ASSIGN, /* = */
+ BINOP_COMMA, /* , */
+ BINOP_SUBSCRIPT, /* x[y] */
+ BINOP_EXP, /* Exponentiation */
+
+/* C++. */
+ BINOP_MIN, /* <? */
+ BINOP_MAX, /* >? */
+ BINOP_SCOPE, /* :: */
+
+ /* STRUCTOP_MEMBER is used for pointer-to-member constructs.
+ X . * Y translates into X STRUCTOP_MEMBER Y. */
+ STRUCTOP_MEMBER,
+ /* STRUCTOP_MPTR is used for pointer-to-member constructs
+ when X is a pointer instead of an aggregate. */
+ STRUCTOP_MPTR,
+/* end of C++. */
+
+ /* For Modula-2 integer division DIV */
+ BINOP_INTDIV,
+
+ BINOP_ASSIGN_MODIFY, /* +=, -=, *=, and so on.
+ The following exp_element is another opcode,
+ a BINOP_, saying how to modify.
+ Then comes another BINOP_ASSIGN_MODIFY,
+ making three exp_elements in total. */
+
+ /* Modula-2 standard (binary) procedures*/
+ BINOP_VAL,
+ BINOP_INCL,
+ BINOP_EXCL,
+
+ /* Concatenate two operands, such as character strings or bitstrings.
+ If the first operand is a integer expression, then it means concatenate
+ the second operand with itself that many times. */
+ BINOP_CONCAT,
+
+ /* For Chill and Pascal. */
+ BINOP_IN, /* Returns 1 iff ARG1 IN ARG2. */
+
+ /* This must be the highest BINOP_ value, for expprint.c. */
+ BINOP_END,
+
+/* Operates on three values computed by following subexpressions. */
+ TERNOP_COND, /* ?: */
+
+/* Multidimensional subscript operator, such as Modula-2 x[a,b,...].
+ The dimensionality is encoded in the operator, like the number of
+ function arguments in OP_FUNCALL, I.E. <OP><dimension><OP>.
+ The value of the first following subexpression is subscripted
+ by each of the next following subexpressions, one per dimension. */
+
+ MULTI_SUBSCRIPT,
+
+/* The OP_... series take immediate following arguments.
+ After the arguments come another OP_... (the same one)
+ so that the grouping can be recognized from the end. */
+
+/* OP_LONG is followed by a type pointer in the next exp_element
+ and the long constant value in the following exp_element.
+ Then comes another OP_LONG.
+ Thus, the operation occupies four exp_elements. */
+
+ OP_LONG,
+/* OP_DOUBLE is similar but takes a double constant instead of a long one. */
+ OP_DOUBLE,
+
+ /* OP_VAR_VALUE takes one struct block * in the following element,
+ and one struct symbol * in the following exp_element, followed by
+ another OP_VAR_VALUE, making four exp_elements. If the block is
+ non-NULL, evaluate the symbol relative to the innermost frame
+ executing in that block; if the block is NULL use the selected frame. */
+
+ OP_VAR_VALUE,
+
+/* OP_LAST is followed by an integer in the next exp_element.
+ The integer is zero for the last value printed,
+ or it is the absolute number of a history element.
+ With another OP_LAST at the end, this makes three exp_elements. */
+ OP_LAST,
+/* OP_REGISTER is followed by an integer in the next exp_element.
+ This is the number of a register to fetch (as an int).
+ With another OP_REGISTER at the end, this makes three exp_elements. */
+ OP_REGISTER,
+/* OP_INTERNALVAR is followed by an internalvar ptr in the next exp_element.
+ With another OP_INTERNALVAR at the end, this makes three exp_elements. */
+ OP_INTERNALVAR,
+/* OP_FUNCALL is followed by an integer in the next exp_element.
+ The integer is the number of args to the function call.
+ That many plus one values from following subexpressions
+ are used, the first one being the function.
+ The integer is followed by a repeat of OP_FUNCALL,
+ making three exp_elements. */
+ OP_FUNCALL,
+/* OP_STRING represents a string constant.
+ Its format is the same as that of a STRUCTOP, but the string
+ data is just made into a string constant when the operation
+ is executed. */
+ OP_STRING,
+/* OP_BITSTRING represents a packed bitstring constant.
+ Its format is the same as that of a STRUCTOP, but the bitstring
+ data is just made into a bitstring constant when the operation
+ is executed. */
+ OP_BITSTRING,
+/* OP_ARRAY creates an array constant out of the following subexpressions.
+ It is followed by two exp_elements, the first containing an integer
+ that is the lower bound of the array and the second containing another
+ integer that is the upper bound of the array. The second integer is
+ followed by a repeat of OP_ARRAY, making four exp_elements total.
+ The bounds are used to compute the number of following subexpressions
+ to consume, as well as setting the bounds in the created array constant.
+ The type of the elements is taken from the type of the first subexp,
+ and they must all match. */
+ OP_ARRAY,
+
+/* UNOP_CAST is followed by a type pointer in the next exp_element.
+ With another UNOP_CAST at the end, this makes three exp_elements.
+ It casts the value of the following subexpression. */
+ UNOP_CAST,
+/* UNOP_MEMVAL is followed by a type pointer in the next exp_element
+ With another UNOP_MEMVAL at the end, this makes three exp_elements.
+ It casts the contents of the word addressed by the value of the
+ following subexpression. */
+ UNOP_MEMVAL,
+/* UNOP_... operate on one value from a following subexpression
+ and replace it with a result. They take no immediate arguments. */
+ UNOP_NEG, /* Unary - */
+ UNOP_LOGICAL_NOT, /* Unary ! */
+ UNOP_COMPLEMENT, /* Unary ~ */
+ UNOP_IND, /* Unary * */
+ UNOP_ADDR, /* Unary & */
+ UNOP_PREINCREMENT, /* ++ before an expression */
+ UNOP_POSTINCREMENT, /* ++ after an expression */
+ UNOP_PREDECREMENT, /* -- before an expression */
+ UNOP_POSTDECREMENT, /* -- after an expression */
+ UNOP_SIZEOF, /* Unary sizeof (followed by expression) */
+
+ UNOP_PLUS, /* Unary plus */
+
+ UNOP_CAP, /* Modula-2 standard (unary) procedures */
+ UNOP_CHR,
+ UNOP_ORD,
+ UNOP_ABS,
+ UNOP_FLOAT,
+ UNOP_HIGH,
+ UNOP_MAX,
+ UNOP_MIN,
+ UNOP_ODD,
+ UNOP_TRUNC,
+
+ OP_BOOL, /* Modula-2 builtin BOOLEAN type */
+ OP_M2_STRING, /* Modula-2 string constants */
+
+/* STRUCTOP_... operate on a value from a following subexpression
+ by extracting a structure component specified by a string
+ that appears in the following exp_elements (as many as needed).
+ STRUCTOP_STRUCT is used for "." and STRUCTOP_PTR for "->".
+ They differ only in the error message given in case the value is
+ not suitable or the structure component specified is not found.
+
+ The length of the string follows the opcode, followed by
+ BYTES_TO_EXP_ELEM(length) elements containing the data of the
+ string, followed by the length again and the opcode again. */
+
+ STRUCTOP_STRUCT,
+ STRUCTOP_PTR,
+
+/* C++ */
+ /* OP_THIS is just a placeholder for the class instance variable.
+ It just comes in a tight (OP_THIS, OP_THIS) pair. */
+ OP_THIS,
+
+ /* OP_SCOPE surrounds a type name and a field name. The type
+ name is encoded as one element, but the field name stays as
+ a string, which, of course, is variable length. */
+ OP_SCOPE,
+
+ /* OP_TYPE is for parsing types, and used with the "ptype" command
+ so we can look up types that are qualified by scope, either with
+ the GDB "::" operator, or the Modula-2 '.' operator. */
+ OP_TYPE
+};
+
+union exp_element
+{
+ enum exp_opcode opcode;
+ struct symbol *symbol;
+ LONGEST longconst;
+ double doubleconst;
+ /* Really sizeof (union exp_element) characters (or less for the last
+ element of a string). */
+ char string;
+ struct type *type;
+ struct internalvar *internalvar;
+ struct block *block;
+};
+
+struct expression
+{
+ const struct language_defn *language_defn; /* language it was entered in */
+ int nelts;
+ union exp_element elts[1];
+};
+
+/* Macros for converting between number of expression elements and bytes
+ to store that many expression elements. */
+
+#define EXP_ELEM_TO_BYTES(elements) \
+ ((elements) * sizeof (union exp_element))
+#define BYTES_TO_EXP_ELEM(bytes) \
+ (((bytes) + sizeof (union exp_element) - 1) / sizeof (union exp_element))
+
+/* From parse.c */
+
+extern struct expression *
+parse_expression PARAMS ((char *));
+
+extern struct expression *
+parse_exp_1 PARAMS ((char **, struct block *, int));
+
+/* The innermost context required by the stack and register variables
+ we've encountered so far. To use this, set it to NULL, then call
+ parse_<whatever>, then look at it. */
+extern struct block *innermost_block;
+
+/* From expprint.c */
+
+extern void
+print_expression PARAMS ((struct expression *, GDB_FILE *));
+
+extern char *
+op_string PARAMS ((enum exp_opcode));
+
+/* To enable dumping of all parsed expressions in a human readable
+ form, define DEBUG_EXPRESSIONS. This is a compile time constant
+ at the moment, since it's not clear that this feature is important
+ enough to include by default. */
+
+#ifdef DEBUG_EXPRESSIONS
+extern void
+dump_expression PARAMS ((struct expression *, GDB_FILE *, char *));
+#define DUMP_EXPRESSION(exp,file,note) dump_expression ((exp), (file), (note))
+#else
+#define DUMP_EXPRESSION(exp,file,note) /* Null expansion */
+#endif /* DEBUG_EXPRESSIONS */
+
+#endif /* !defined (EXPRESSION_H) */
diff --git a/gnu/usr.bin/gdb/gdb/findvar.c b/gnu/usr.bin/gdb/gdb/findvar.c
new file mode 100644
index 0000000..59c813c
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/findvar.c
@@ -0,0 +1,1242 @@
+/* Find a variable's value in memory, for GDB, the GNU debugger.
+ Copyright 1986, 1987, 1989, 1991 Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "defs.h"
+#include "symtab.h"
+#include "gdbtypes.h"
+#include "frame.h"
+#include "value.h"
+#include "gdbcore.h"
+#include "inferior.h"
+#include "target.h"
+
+/* Basic byte-swapping routines. GDB has needed these for a long time...
+ All extract a target-format integer at ADDR which is LEN bytes long. */
+
+#if TARGET_CHAR_BIT != 8 || HOST_CHAR_BIT != 8
+ /* 8 bit characters are a pretty safe assumption these days, so we
+ assume it throughout all these swapping routines. If we had to deal with
+ 9 bit characters, we would need to make len be in bits and would have
+ to re-write these routines... */
+ you lose
+#endif
+
+LONGEST
+extract_signed_integer (addr, len)
+ PTR addr;
+ int len;
+{
+ LONGEST retval;
+ unsigned char *p;
+ unsigned char *startaddr = (unsigned char *)addr;
+ unsigned char *endaddr = startaddr + len;
+
+ if (len > sizeof (LONGEST))
+ error ("\
+That operation is not available on integers of more than %d bytes.",
+ sizeof (LONGEST));
+
+ /* Start at the most significant end of the integer, and work towards
+ the least significant. */
+#if TARGET_BYTE_ORDER == BIG_ENDIAN
+ p = startaddr;
+#else
+ p = endaddr - 1;
+#endif
+ /* Do the sign extension once at the start. */
+ retval = ((LONGEST)*p ^ 0x80) - 0x80;
+#if TARGET_BYTE_ORDER == BIG_ENDIAN
+ for (++p; p < endaddr; ++p)
+#else
+ for (--p; p >= startaddr; --p)
+#endif
+ {
+ retval = (retval << 8) | *p;
+ }
+ return retval;
+}
+
+unsigned LONGEST
+extract_unsigned_integer (addr, len)
+ PTR addr;
+ int len;
+{
+ unsigned LONGEST retval;
+ unsigned char *p;
+ unsigned char *startaddr = (unsigned char *)addr;
+ unsigned char *endaddr = startaddr + len;
+
+ if (len > sizeof (unsigned LONGEST))
+ error ("\
+That operation is not available on integers of more than %d bytes.",
+ sizeof (unsigned LONGEST));
+
+ /* Start at the most significant end of the integer, and work towards
+ the least significant. */
+ retval = 0;
+#if TARGET_BYTE_ORDER == BIG_ENDIAN
+ for (p = startaddr; p < endaddr; ++p)
+#else
+ for (p = endaddr - 1; p >= startaddr; --p)
+#endif
+ {
+ retval = (retval << 8) | *p;
+ }
+ return retval;
+}
+
+CORE_ADDR
+extract_address (addr, len)
+ PTR addr;
+ int len;
+{
+ /* Assume a CORE_ADDR can fit in a LONGEST (for now). Not sure
+ whether we want this to be true eventually. */
+ return extract_unsigned_integer (addr, len);
+}
+
+void
+store_signed_integer (addr, len, val)
+ PTR addr;
+ int len;
+ LONGEST val;
+{
+ unsigned char *p;
+ unsigned char *startaddr = (unsigned char *)addr;
+ unsigned char *endaddr = startaddr + len;
+
+ /* Start at the least significant end of the integer, and work towards
+ the most significant. */
+#if TARGET_BYTE_ORDER == BIG_ENDIAN
+ for (p = endaddr - 1; p >= startaddr; --p)
+#else
+ for (p = startaddr; p < endaddr; ++p)
+#endif
+ {
+ *p = val & 0xff;
+ val >>= 8;
+ }
+}
+
+void
+store_unsigned_integer (addr, len, val)
+ PTR addr;
+ int len;
+ unsigned LONGEST val;
+{
+ unsigned char *p;
+ unsigned char *startaddr = (unsigned char *)addr;
+ unsigned char *endaddr = startaddr + len;
+
+ /* Start at the least significant end of the integer, and work towards
+ the most significant. */
+#if TARGET_BYTE_ORDER == BIG_ENDIAN
+ for (p = endaddr - 1; p >= startaddr; --p)
+#else
+ for (p = startaddr; p < endaddr; ++p)
+#endif
+ {
+ *p = val & 0xff;
+ val >>= 8;
+ }
+}
+
+void
+store_address (addr, len, val)
+ PTR addr;
+ int len;
+ CORE_ADDR val;
+{
+ /* Assume a CORE_ADDR can fit in a LONGEST (for now). Not sure
+ whether we want this to be true eventually. */
+ store_unsigned_integer (addr, len, (LONGEST)val);
+}
+
+/* Swap LEN bytes at BUFFER between target and host byte-order. This is
+ the wrong way to do byte-swapping because it assumes that you have a way
+ to have a host variable of exactly the right size. Once extract_floating
+ and store_floating have been fixed, this can go away. */
+#if TARGET_BYTE_ORDER == HOST_BYTE_ORDER
+#define SWAP_TARGET_AND_HOST(buffer,len)
+#else /* Target and host byte order differ. */
+#define SWAP_TARGET_AND_HOST(buffer,len) \
+ { \
+ char tmp; \
+ char *p = (char *)(buffer); \
+ char *q = ((char *)(buffer)) + len - 1; \
+ for (; p < q; p++, q--) \
+ { \
+ tmp = *q; \
+ *q = *p; \
+ *p = tmp; \
+ } \
+ }
+#endif /* Target and host byte order differ. */
+
+/* There are many problems with floating point cross-debugging.
+
+ 1. These routines only handle byte-swapping, not conversion of
+ formats. So if host is IEEE floating and target is VAX floating,
+ or vice-versa, it loses. This means that we can't (yet) use these
+ routines for extendeds. Extendeds are handled by
+ REGISTER_CONVERTIBLE. What we want is to use floatformat.h, but that
+ doesn't yet handle VAX floating at all.
+
+ 2. We can't deal with it if there is more than one floating point
+ format in use. This has to be fixed at the unpack_double level.
+
+ 3. We probably should have a LONGEST_DOUBLE or DOUBLEST or whatever
+ we want to call it which is long double where available. */
+
+double
+extract_floating (addr, len)
+ PTR addr;
+ int len;
+{
+ if (len == sizeof (float))
+ {
+ float retval;
+ memcpy (&retval, addr, sizeof (retval));
+ SWAP_TARGET_AND_HOST (&retval, sizeof (retval));
+ return retval;
+ }
+ else if (len == sizeof (double))
+ {
+ double retval;
+ memcpy (&retval, addr, sizeof (retval));
+ SWAP_TARGET_AND_HOST (&retval, sizeof (retval));
+ return retval;
+ }
+ else
+ {
+ error ("Can't deal with a floating point number of %d bytes.", len);
+ }
+}
+
+void
+store_floating (addr, len, val)
+ PTR addr;
+ int len;
+ double val;
+{
+ if (len == sizeof (float))
+ {
+ float floatval = val;
+ SWAP_TARGET_AND_HOST (&floatval, sizeof (floatval));
+ memcpy (addr, &floatval, sizeof (floatval));
+ }
+ else if (len == sizeof (double))
+ {
+ SWAP_TARGET_AND_HOST (&val, sizeof (val));
+ memcpy (addr, &val, sizeof (val));
+ }
+ else
+ {
+ error ("Can't deal with a floating point number of %d bytes.", len);
+ }
+}
+
+#if !defined (GET_SAVED_REGISTER)
+
+/* Return the address in which frame FRAME's value of register REGNUM
+ has been saved in memory. Or return zero if it has not been saved.
+ If REGNUM specifies the SP, the value we return is actually
+ the SP value, not an address where it was saved. */
+
+CORE_ADDR
+find_saved_register (frame, regnum)
+ FRAME frame;
+ int regnum;
+{
+ struct frame_info *fi;
+ struct frame_saved_regs saved_regs;
+
+ register FRAME frame1 = 0;
+ register CORE_ADDR addr = 0;
+
+ if (frame == 0) /* No regs saved if want current frame */
+ return 0;
+
+#ifdef HAVE_REGISTER_WINDOWS
+ /* We assume that a register in a register window will only be saved
+ in one place (since the name changes and/or disappears as you go
+ towards inner frames), so we only call get_frame_saved_regs on
+ the current frame. This is directly in contradiction to the
+ usage below, which assumes that registers used in a frame must be
+ saved in a lower (more interior) frame. This change is a result
+ of working on a register window machine; get_frame_saved_regs
+ always returns the registers saved within a frame, within the
+ context (register namespace) of that frame. */
+
+ /* However, note that we don't want this to return anything if
+ nothing is saved (if there's a frame inside of this one). Also,
+ callers to this routine asking for the stack pointer want the
+ stack pointer saved for *this* frame; this is returned from the
+ next frame. */
+
+
+ if (REGISTER_IN_WINDOW_P(regnum))
+ {
+ frame1 = get_next_frame (frame);
+ if (!frame1) return 0; /* Registers of this frame are
+ active. */
+
+ /* Get the SP from the next frame in; it will be this
+ current frame. */
+ if (regnum != SP_REGNUM)
+ frame1 = frame;
+
+ fi = get_frame_info (frame1);
+ get_frame_saved_regs (fi, &saved_regs);
+ return saved_regs.regs[regnum]; /* ... which might be zero */
+ }
+#endif /* HAVE_REGISTER_WINDOWS */
+
+ /* Note that this next routine assumes that registers used in
+ frame x will be saved only in the frame that x calls and
+ frames interior to it. This is not true on the sparc, but the
+ above macro takes care of it, so we should be all right. */
+ while (1)
+ {
+ QUIT;
+ frame1 = get_prev_frame (frame1);
+ if (frame1 == 0 || frame1 == frame)
+ break;
+ fi = get_frame_info (frame1);
+ get_frame_saved_regs (fi, &saved_regs);
+ if (saved_regs.regs[regnum])
+ addr = saved_regs.regs[regnum];
+ }
+
+ return addr;
+}
+
+/* Find register number REGNUM relative to FRAME and put its (raw,
+ target format) contents in *RAW_BUFFER. Set *OPTIMIZED if the
+ variable was optimized out (and thus can't be fetched). Set *LVAL
+ to lval_memory, lval_register, or not_lval, depending on whether
+ the value was fetched from memory, from a register, or in a strange
+ and non-modifiable way (e.g. a frame pointer which was calculated
+ rather than fetched). Set *ADDRP to the address, either in memory
+ on as a REGISTER_BYTE offset into the registers array.
+
+ Note that this implementation never sets *LVAL to not_lval. But
+ it can be replaced by defining GET_SAVED_REGISTER and supplying
+ your own.
+
+ The argument RAW_BUFFER must point to aligned memory. */
+
+void
+get_saved_register (raw_buffer, optimized, addrp, frame, regnum, lval)
+ char *raw_buffer;
+ int *optimized;
+ CORE_ADDR *addrp;
+ FRAME frame;
+ int regnum;
+ enum lval_type *lval;
+{
+ CORE_ADDR addr;
+ /* Normal systems don't optimize out things with register numbers. */
+ if (optimized != NULL)
+ *optimized = 0;
+ addr = find_saved_register (frame, regnum);
+ if (addr != 0)
+ {
+ if (lval != NULL)
+ *lval = lval_memory;
+ if (regnum == SP_REGNUM)
+ {
+ if (raw_buffer != NULL)
+ {
+ /* Put it back in target format. */
+ store_address (raw_buffer, REGISTER_RAW_SIZE (regnum), addr);
+ }
+ if (addrp != NULL)
+ *addrp = 0;
+ return;
+ }
+ if (raw_buffer != NULL)
+ read_memory (addr, raw_buffer, REGISTER_RAW_SIZE (regnum));
+ }
+ else
+ {
+ if (lval != NULL)
+ *lval = lval_register;
+ addr = REGISTER_BYTE (regnum);
+ if (raw_buffer != NULL)
+ read_register_gen (regnum, raw_buffer);
+ }
+ if (addrp != NULL)
+ *addrp = addr;
+}
+#endif /* GET_SAVED_REGISTER. */
+
+/* Copy the bytes of register REGNUM, relative to the current stack frame,
+ into our memory at MYADDR, in target byte order.
+ The number of bytes copied is REGISTER_RAW_SIZE (REGNUM).
+
+ Returns 1 if could not be read, 0 if could. */
+
+int
+read_relative_register_raw_bytes (regnum, myaddr)
+ int regnum;
+ char *myaddr;
+{
+ int optim;
+ if (regnum == FP_REGNUM && selected_frame)
+ {
+ /* Put it back in target format. */
+ store_address (myaddr, REGISTER_RAW_SIZE(FP_REGNUM),
+ FRAME_FP(selected_frame));
+ return 0;
+ }
+
+ get_saved_register (myaddr, &optim, (CORE_ADDR *) NULL, selected_frame,
+ regnum, (enum lval_type *)NULL);
+ return optim;
+}
+
+/* Return a `value' with the contents of register REGNUM
+ in its virtual format, with the type specified by
+ REGISTER_VIRTUAL_TYPE. */
+
+value_ptr
+value_of_register (regnum)
+ int regnum;
+{
+ CORE_ADDR addr;
+ int optim;
+ register value_ptr reg_val;
+ char raw_buffer[MAX_REGISTER_RAW_SIZE];
+ enum lval_type lval;
+
+ get_saved_register (raw_buffer, &optim, &addr,
+ selected_frame, regnum, &lval);
+
+ reg_val = allocate_value (REGISTER_VIRTUAL_TYPE (regnum));
+
+ /* Convert raw data to virtual format if necessary. */
+
+#ifdef REGISTER_CONVERTIBLE
+ if (REGISTER_CONVERTIBLE (regnum))
+ {
+ REGISTER_CONVERT_TO_VIRTUAL (regnum, REGISTER_VIRTUAL_TYPE (regnum),
+ raw_buffer, VALUE_CONTENTS_RAW (reg_val));
+ }
+ else
+#endif
+ memcpy (VALUE_CONTENTS_RAW (reg_val), raw_buffer,
+ REGISTER_RAW_SIZE (regnum));
+ VALUE_LVAL (reg_val) = lval;
+ VALUE_ADDRESS (reg_val) = addr;
+ VALUE_REGNO (reg_val) = regnum;
+ VALUE_OPTIMIZED_OUT (reg_val) = optim;
+ return reg_val;
+}
+
+/* Low level examining and depositing of registers.
+
+ The caller is responsible for making
+ sure that the inferior is stopped before calling the fetching routines,
+ or it will get garbage. (a change from GDB version 3, in which
+ the caller got the value from the last stop). */
+
+/* Contents of the registers in target byte order.
+ We allocate some extra slop since we do a lot of memcpy's around `registers',
+ and failing-soft is better than failing hard. */
+char registers[REGISTER_BYTES + /* SLOP */ 256];
+
+/* Nonzero if that register has been fetched. */
+char register_valid[NUM_REGS];
+
+/* The thread/process associated with the current set of registers. For now,
+ -1 is special, and means `no current process'. */
+int registers_pid = -1;
+
+/* Indicate that registers may have changed, so invalidate the cache. */
+
+void
+registers_changed ()
+{
+ int i;
+ int numregs = ARCH_NUM_REGS;
+
+ registers_pid = -1;
+
+ for (i = 0; i < numregs; i++)
+ register_valid[i] = 0;
+}
+
+/* Indicate that all registers have been fetched, so mark them all valid. */
+void
+registers_fetched ()
+{
+ int i;
+ int numregs = ARCH_NUM_REGS;
+ for (i = 0; i < numregs; i++)
+ register_valid[i] = 1;
+}
+
+/* Copy LEN bytes of consecutive data from registers
+ starting with the REGBYTE'th byte of register data
+ into memory at MYADDR. */
+
+void
+read_register_bytes (regbyte, myaddr, len)
+ int regbyte;
+ char *myaddr;
+ int len;
+{
+ /* Fetch all registers. */
+ int i, numregs;
+
+ if (registers_pid != inferior_pid)
+ {
+ registers_changed ();
+ registers_pid = inferior_pid;
+ }
+
+ numregs = ARCH_NUM_REGS;
+ for (i = 0; i < numregs; i++)
+ if (!register_valid[i])
+ {
+ target_fetch_registers (-1);
+ break;
+ }
+ if (myaddr != NULL)
+ memcpy (myaddr, &registers[regbyte], len);
+}
+
+/* Read register REGNO into memory at MYADDR, which must be large enough
+ for REGISTER_RAW_BYTES (REGNO). Target byte-order.
+ If the register is known to be the size of a CORE_ADDR or smaller,
+ read_register can be used instead. */
+void
+read_register_gen (regno, myaddr)
+ int regno;
+ char *myaddr;
+{
+ if (registers_pid != inferior_pid)
+ {
+ registers_changed ();
+ registers_pid = inferior_pid;
+ }
+
+ if (!register_valid[regno])
+ target_fetch_registers (regno);
+ memcpy (myaddr, &registers[REGISTER_BYTE (regno)],
+ REGISTER_RAW_SIZE (regno));
+}
+
+/* Copy LEN bytes of consecutive data from memory at MYADDR
+ into registers starting with the REGBYTE'th byte of register data. */
+
+void
+write_register_bytes (regbyte, myaddr, len)
+ int regbyte;
+ char *myaddr;
+ int len;
+{
+ if (registers_pid != inferior_pid)
+ {
+ registers_changed ();
+ registers_pid = inferior_pid;
+ }
+
+ /* Make sure the entire registers array is valid. */
+ read_register_bytes (0, (char *)NULL, REGISTER_BYTES);
+ memcpy (&registers[regbyte], myaddr, len);
+ target_store_registers (-1);
+}
+
+/* Return the raw contents of register REGNO, regarding it as an integer. */
+/* This probably should be returning LONGEST rather than CORE_ADDR. */
+
+CORE_ADDR
+read_register (regno)
+ int regno;
+{
+ if (registers_pid != inferior_pid)
+ {
+ registers_changed ();
+ registers_pid = inferior_pid;
+ }
+
+ if (!register_valid[regno])
+ target_fetch_registers (regno);
+
+ return extract_address (&registers[REGISTER_BYTE (regno)],
+ REGISTER_RAW_SIZE(regno));
+}
+
+CORE_ADDR
+read_register_pid (regno, pid)
+ int regno, pid;
+{
+ int save_pid;
+ CORE_ADDR retval;
+
+ if (pid == inferior_pid)
+ return read_register (regno);
+
+ save_pid = inferior_pid;
+
+ inferior_pid = pid;
+
+ retval = read_register (regno);
+
+ inferior_pid = save_pid;
+
+ return retval;
+}
+
+/* Registers we shouldn't try to store. */
+#if !defined (CANNOT_STORE_REGISTER)
+#define CANNOT_STORE_REGISTER(regno) 0
+#endif
+
+/* Store VALUE, into the raw contents of register number REGNO. */
+/* FIXME: The val arg should probably be a LONGEST. */
+
+void
+write_register (regno, val)
+ int regno;
+ LONGEST val;
+{
+ PTR buf;
+ int size;
+
+ /* On the sparc, writing %g0 is a no-op, so we don't even want to change
+ the registers array if something writes to this register. */
+ if (CANNOT_STORE_REGISTER (regno))
+ return;
+
+ if (registers_pid != inferior_pid)
+ {
+ registers_changed ();
+ registers_pid = inferior_pid;
+ }
+
+ size = REGISTER_RAW_SIZE(regno);
+ buf = alloca (size);
+ store_signed_integer (buf, size, (LONGEST) val);
+
+ /* If we have a valid copy of the register, and new value == old value,
+ then don't bother doing the actual store. */
+
+ if (register_valid [regno]
+ && memcmp (&registers[REGISTER_BYTE (regno)], buf, size) == 0)
+ return;
+
+ target_prepare_to_store ();
+
+ memcpy (&registers[REGISTER_BYTE (regno)], buf, size);
+
+ register_valid [regno] = 1;
+
+ target_store_registers (regno);
+}
+
+void
+write_register_pid (regno, val, pid)
+ int regno;
+ LONGEST val;
+ int pid;
+{
+ int save_pid;
+
+ if (pid == inferior_pid)
+ {
+ write_register (regno, val);
+ return;
+ }
+
+ save_pid = inferior_pid;
+
+ inferior_pid = pid;
+
+ write_register (regno, val);
+
+ inferior_pid = save_pid;
+}
+
+/* Record that register REGNO contains VAL.
+ This is used when the value is obtained from the inferior or core dump,
+ so there is no need to store the value there. */
+
+void
+supply_register (regno, val)
+ int regno;
+ char *val;
+{
+ if (registers_pid != inferior_pid)
+ {
+ registers_changed ();
+ registers_pid = inferior_pid;
+ }
+
+ register_valid[regno] = 1;
+ memcpy (&registers[REGISTER_BYTE (regno)], val, REGISTER_RAW_SIZE (regno));
+
+ /* On some architectures, e.g. HPPA, there are a few stray bits in some
+ registers, that the rest of the code would like to ignore. */
+#ifdef CLEAN_UP_REGISTER_VALUE
+ CLEAN_UP_REGISTER_VALUE(regno, &registers[REGISTER_BYTE(regno)]);
+#endif
+}
+
+
+/* This routine is getting awfully cluttered with #if's. It's probably
+ time to turn this into READ_PC and define it in the tm.h file.
+ Ditto for write_pc. */
+
+CORE_ADDR
+read_pc ()
+{
+#ifdef TARGET_READ_PC
+ return TARGET_READ_PC (inferior_pid);
+#else
+ return ADDR_BITS_REMOVE ((CORE_ADDR) read_register_pid (PC_REGNUM, inferior_pid));
+#endif
+}
+
+CORE_ADDR
+read_pc_pid (pid)
+ int pid;
+{
+#ifdef TARGET_READ_PC
+ return TARGET_READ_PC (pid);
+#else
+ return ADDR_BITS_REMOVE ((CORE_ADDR) read_register_pid (PC_REGNUM, pid));
+#endif
+}
+
+void
+write_pc (val)
+ CORE_ADDR val;
+{
+#ifdef TARGET_WRITE_PC
+ TARGET_WRITE_PC (val, inferior_pid);
+#else
+ write_register_pid (PC_REGNUM, (long) val, inferior_pid);
+#ifdef NPC_REGNUM
+ write_register_pid (NPC_REGNUM, (long) val + 4, inferior_pid);
+#ifdef NNPC_REGNUM
+ write_register_pid (NNPC_REGNUM, (long) val + 8, inferior_pid);
+#endif
+#endif
+#endif
+}
+
+void
+write_pc_pid (val, pid)
+ CORE_ADDR val;
+ int pid;
+{
+#ifdef TARGET_WRITE_PC
+ TARGET_WRITE_PC (val, pid);
+#else
+ write_register_pid (PC_REGNUM, (long) val, pid);
+#ifdef NPC_REGNUM
+ write_register_pid (NPC_REGNUM, (long) val + 4, pid);
+#ifdef NNPC_REGNUM
+ write_register_pid (NNPC_REGNUM, (long) val + 8, pid);
+#endif
+#endif
+#endif
+}
+
+/* Cope with strage ways of getting to the stack and frame pointers */
+
+CORE_ADDR
+read_sp ()
+{
+#ifdef TARGET_READ_SP
+ return TARGET_READ_SP ();
+#else
+ return read_register (SP_REGNUM);
+#endif
+}
+
+void
+write_sp (val)
+ CORE_ADDR val;
+{
+#ifdef TARGET_WRITE_SP
+ TARGET_WRITE_SP (val);
+#else
+ write_register (SP_REGNUM, val);
+#endif
+}
+
+CORE_ADDR
+read_fp ()
+{
+#ifdef TARGET_READ_FP
+ return TARGET_READ_FP ();
+#else
+ return read_register (FP_REGNUM);
+#endif
+}
+
+void
+write_fp (val)
+ CORE_ADDR val;
+{
+#ifdef TARGET_WRITE_FP
+ TARGET_WRITE_FP (val);
+#else
+ write_register (FP_REGNUM, val);
+#endif
+}
+
+/* Will calling read_var_value or locate_var_value on SYM end
+ up caring what frame it is being evaluated relative to? SYM must
+ be non-NULL. */
+int
+symbol_read_needs_frame (sym)
+ struct symbol *sym;
+{
+ switch (SYMBOL_CLASS (sym))
+ {
+ /* All cases listed explicitly so that gcc -Wall will detect it if
+ we failed to consider one. */
+ case LOC_REGISTER:
+ case LOC_ARG:
+ case LOC_REF_ARG:
+ case LOC_REGPARM:
+ case LOC_REGPARM_ADDR:
+ case LOC_LOCAL:
+ case LOC_LOCAL_ARG:
+ case LOC_BASEREG:
+ case LOC_BASEREG_ARG:
+ return 1;
+
+ case LOC_UNDEF:
+ case LOC_CONST:
+ case LOC_STATIC:
+ case LOC_TYPEDEF:
+
+ case LOC_LABEL:
+ /* Getting the address of a label can be done independently of the block,
+ even if some *uses* of that address wouldn't work so well without
+ the right frame. */
+
+ case LOC_BLOCK:
+ case LOC_CONST_BYTES:
+ case LOC_OPTIMIZED_OUT:
+ return 0;
+ }
+ return 1;
+}
+
+/* Given a struct symbol for a variable,
+ and a stack frame id, read the value of the variable
+ and return a (pointer to a) struct value containing the value.
+ If the variable cannot be found, return a zero pointer.
+ If FRAME is NULL, use the selected_frame. */
+
+value_ptr
+read_var_value (var, frame)
+ register struct symbol *var;
+ FRAME frame;
+{
+ register value_ptr v;
+ struct frame_info *fi;
+ struct type *type = SYMBOL_TYPE (var);
+ CORE_ADDR addr;
+ register int len;
+
+ v = allocate_value (type);
+ VALUE_LVAL (v) = lval_memory; /* The most likely possibility. */
+ len = TYPE_LENGTH (type);
+
+ if (frame == 0) frame = selected_frame;
+
+ switch (SYMBOL_CLASS (var))
+ {
+ case LOC_CONST:
+ /* Put the constant back in target format. */
+ store_signed_integer (VALUE_CONTENTS_RAW (v), len,
+ (LONGEST) SYMBOL_VALUE (var));
+ VALUE_LVAL (v) = not_lval;
+ return v;
+
+ case LOC_LABEL:
+ /* Put the constant back in target format. */
+ store_address (VALUE_CONTENTS_RAW (v), len, SYMBOL_VALUE_ADDRESS (var));
+ VALUE_LVAL (v) = not_lval;
+ return v;
+
+ case LOC_CONST_BYTES:
+ {
+ char *bytes_addr;
+ bytes_addr = SYMBOL_VALUE_BYTES (var);
+ memcpy (VALUE_CONTENTS_RAW (v), bytes_addr, len);
+ VALUE_LVAL (v) = not_lval;
+ return v;
+ }
+
+ case LOC_STATIC:
+ addr = SYMBOL_VALUE_ADDRESS (var);
+ break;
+
+ case LOC_ARG:
+ fi = get_frame_info (frame);
+ if (fi == NULL)
+ return 0;
+ addr = FRAME_ARGS_ADDRESS (fi);
+ if (!addr)
+ {
+ return 0;
+ }
+ addr += SYMBOL_VALUE (var);
+ break;
+
+ case LOC_REF_ARG:
+ fi = get_frame_info (frame);
+ if (fi == NULL)
+ return 0;
+ addr = FRAME_ARGS_ADDRESS (fi);
+ if (!addr)
+ {
+ return 0;
+ }
+ addr += SYMBOL_VALUE (var);
+ addr = read_memory_unsigned_integer
+ (addr, TARGET_PTR_BIT / TARGET_CHAR_BIT);
+ break;
+
+ case LOC_LOCAL:
+ case LOC_LOCAL_ARG:
+ fi = get_frame_info (frame);
+ if (fi == NULL)
+ return 0;
+ addr = FRAME_LOCALS_ADDRESS (fi);
+ addr += SYMBOL_VALUE (var);
+ break;
+
+ case LOC_BASEREG:
+ case LOC_BASEREG_ARG:
+ {
+ char buf[MAX_REGISTER_RAW_SIZE];
+ get_saved_register (buf, NULL, NULL, frame, SYMBOL_BASEREG (var),
+ NULL);
+ addr = extract_address (buf, REGISTER_RAW_SIZE (SYMBOL_BASEREG (var)));
+ addr += SYMBOL_VALUE (var);
+ break;
+ }
+
+ case LOC_TYPEDEF:
+ error ("Cannot look up value of a typedef");
+ break;
+
+ case LOC_BLOCK:
+ VALUE_ADDRESS (v) = BLOCK_START (SYMBOL_BLOCK_VALUE (var));
+ return v;
+
+ case LOC_REGISTER:
+ case LOC_REGPARM:
+ case LOC_REGPARM_ADDR:
+ {
+ struct block *b;
+
+ if (frame == NULL)
+ return 0;
+ b = get_frame_block (frame);
+
+
+ if (SYMBOL_CLASS (var) == LOC_REGPARM_ADDR)
+ {
+ addr =
+ value_as_pointer (value_from_register (lookup_pointer_type (type),
+ SYMBOL_VALUE (var),
+ frame));
+ VALUE_LVAL (v) = lval_memory;
+ }
+ else
+ return value_from_register (type, SYMBOL_VALUE (var), frame);
+ }
+ break;
+
+ case LOC_OPTIMIZED_OUT:
+ VALUE_LVAL (v) = not_lval;
+ VALUE_OPTIMIZED_OUT (v) = 1;
+ return v;
+
+ default:
+ error ("Cannot look up value of a botched symbol.");
+ break;
+ }
+
+ VALUE_ADDRESS (v) = addr;
+ VALUE_LAZY (v) = 1;
+ return v;
+}
+
+/* Return a value of type TYPE, stored in register REGNUM, in frame
+ FRAME. */
+
+value_ptr
+value_from_register (type, regnum, frame)
+ struct type *type;
+ int regnum;
+ FRAME frame;
+{
+ char raw_buffer [MAX_REGISTER_RAW_SIZE];
+ CORE_ADDR addr;
+ int optim;
+ value_ptr v = allocate_value (type);
+ int len = TYPE_LENGTH (type);
+ char *value_bytes = 0;
+ int value_bytes_copied = 0;
+ int num_storage_locs;
+ enum lval_type lval;
+
+ VALUE_REGNO (v) = regnum;
+
+ num_storage_locs = (len > REGISTER_VIRTUAL_SIZE (regnum) ?
+ ((len - 1) / REGISTER_RAW_SIZE (regnum)) + 1 :
+ 1);
+
+ if (num_storage_locs > 1
+#ifdef GDB_TARGET_IS_H8500
+ || TYPE_CODE (type) == TYPE_CODE_PTR
+#endif
+ )
+ {
+ /* Value spread across multiple storage locations. */
+
+ int local_regnum;
+ int mem_stor = 0, reg_stor = 0;
+ int mem_tracking = 1;
+ CORE_ADDR last_addr = 0;
+ CORE_ADDR first_addr = 0;
+
+ value_bytes = (char *) alloca (len + MAX_REGISTER_RAW_SIZE);
+
+ /* Copy all of the data out, whereever it may be. */
+
+#ifdef GDB_TARGET_IS_H8500
+/* This piece of hideosity is required because the H8500 treats registers
+ differently depending upon whether they are used as pointers or not. As a
+ pointer, a register needs to have a page register tacked onto the front.
+ An alternate way to do this would be to have gcc output different register
+ numbers for the pointer & non-pointer form of the register. But, it
+ doesn't, so we're stuck with this. */
+
+ if (TYPE_CODE (type) == TYPE_CODE_PTR
+ && len > 2)
+ {
+ int page_regnum;
+
+ switch (regnum)
+ {
+ case R0_REGNUM: case R1_REGNUM: case R2_REGNUM: case R3_REGNUM:
+ page_regnum = SEG_D_REGNUM;
+ break;
+ case R4_REGNUM: case R5_REGNUM:
+ page_regnum = SEG_E_REGNUM;
+ break;
+ case R6_REGNUM: case R7_REGNUM:
+ page_regnum = SEG_T_REGNUM;
+ break;
+ }
+
+ value_bytes[0] = 0;
+ get_saved_register (value_bytes + 1,
+ &optim,
+ &addr,
+ frame,
+ page_regnum,
+ &lval);
+
+ if (lval == lval_register)
+ reg_stor++;
+ else
+ mem_stor++;
+ first_addr = addr;
+ last_addr = addr;
+
+ get_saved_register (value_bytes + 2,
+ &optim,
+ &addr,
+ frame,
+ regnum,
+ &lval);
+
+ if (lval == lval_register)
+ reg_stor++;
+ else
+ {
+ mem_stor++;
+ mem_tracking = mem_tracking && (addr == last_addr);
+ }
+ last_addr = addr;
+ }
+ else
+#endif /* GDB_TARGET_IS_H8500 */
+ for (local_regnum = regnum;
+ value_bytes_copied < len;
+ (value_bytes_copied += REGISTER_RAW_SIZE (local_regnum),
+ ++local_regnum))
+ {
+ get_saved_register (value_bytes + value_bytes_copied,
+ &optim,
+ &addr,
+ frame,
+ local_regnum,
+ &lval);
+
+ if (regnum == local_regnum)
+ first_addr = addr;
+ if (lval == lval_register)
+ reg_stor++;
+ else
+ {
+ mem_stor++;
+
+ mem_tracking =
+ (mem_tracking
+ && (regnum == local_regnum
+ || addr == last_addr));
+ }
+ last_addr = addr;
+ }
+
+ if ((reg_stor && mem_stor)
+ || (mem_stor && !mem_tracking))
+ /* Mixed storage; all of the hassle we just went through was
+ for some good purpose. */
+ {
+ VALUE_LVAL (v) = lval_reg_frame_relative;
+ VALUE_FRAME (v) = FRAME_FP (frame);
+ VALUE_FRAME_REGNUM (v) = regnum;
+ }
+ else if (mem_stor)
+ {
+ VALUE_LVAL (v) = lval_memory;
+ VALUE_ADDRESS (v) = first_addr;
+ }
+ else if (reg_stor)
+ {
+ VALUE_LVAL (v) = lval_register;
+ VALUE_ADDRESS (v) = first_addr;
+ }
+ else
+ fatal ("value_from_register: Value not stored anywhere!");
+
+ VALUE_OPTIMIZED_OUT (v) = optim;
+
+ /* Any structure stored in more than one register will always be
+ an integral number of registers. Otherwise, you'd need to do
+ some fiddling with the last register copied here for little
+ endian machines. */
+
+ /* Copy into the contents section of the value. */
+ memcpy (VALUE_CONTENTS_RAW (v), value_bytes, len);
+
+ /* Finally do any conversion necessary when extracting this
+ type from more than one register. */
+#ifdef REGISTER_CONVERT_TO_TYPE
+ REGISTER_CONVERT_TO_TYPE(regnum, type, VALUE_CONTENTS_RAW(v));
+#endif
+ return v;
+ }
+
+ /* Data is completely contained within a single register. Locate the
+ register's contents in a real register or in core;
+ read the data in raw format. */
+
+ get_saved_register (raw_buffer, &optim, &addr, frame, regnum, &lval);
+ VALUE_OPTIMIZED_OUT (v) = optim;
+ VALUE_LVAL (v) = lval;
+ VALUE_ADDRESS (v) = addr;
+
+ /* Convert raw data to virtual format if necessary. */
+
+#ifdef REGISTER_CONVERTIBLE
+ if (REGISTER_CONVERTIBLE (regnum))
+ {
+ REGISTER_CONVERT_TO_VIRTUAL (regnum, type,
+ raw_buffer, VALUE_CONTENTS_RAW (v));
+ }
+ else
+#endif
+ {
+ /* Raw and virtual formats are the same for this register. */
+
+#if TARGET_BYTE_ORDER == BIG_ENDIAN
+ if (len < REGISTER_RAW_SIZE (regnum))
+ {
+ /* Big-endian, and we want less than full size. */
+ VALUE_OFFSET (v) = REGISTER_RAW_SIZE (regnum) - len;
+ }
+#endif
+
+ memcpy (VALUE_CONTENTS_RAW (v), raw_buffer + VALUE_OFFSET (v), len);
+ }
+
+ return v;
+}
+
+/* Given a struct symbol for a variable or function,
+ and a stack frame id,
+ return a (pointer to a) struct value containing the properly typed
+ address. */
+
+value_ptr
+locate_var_value (var, frame)
+ register struct symbol *var;
+ FRAME frame;
+{
+ CORE_ADDR addr = 0;
+ struct type *type = SYMBOL_TYPE (var);
+ value_ptr lazy_value;
+
+ /* Evaluate it first; if the result is a memory address, we're fine.
+ Lazy evaluation pays off here. */
+
+ lazy_value = read_var_value (var, frame);
+ if (lazy_value == 0)
+ error ("Address of \"%s\" is unknown.", SYMBOL_SOURCE_NAME (var));
+
+ if (VALUE_LAZY (lazy_value)
+ || TYPE_CODE (type) == TYPE_CODE_FUNC)
+ {
+ addr = VALUE_ADDRESS (lazy_value);
+ return value_from_longest (lookup_pointer_type (type), (LONGEST) addr);
+ }
+
+ /* Not a memory address; check what the problem was. */
+ switch (VALUE_LVAL (lazy_value))
+ {
+ case lval_register:
+ case lval_reg_frame_relative:
+ error ("Address requested for identifier \"%s\" which is in a register.",
+ SYMBOL_SOURCE_NAME (var));
+ break;
+
+ default:
+ error ("Can't take address of \"%s\" which isn't an lvalue.",
+ SYMBOL_SOURCE_NAME (var));
+ break;
+ }
+ return 0; /* For lint -- never reached */
+}
diff --git a/gnu/usr.bin/gdb/gdb/floatformat.h b/gnu/usr.bin/gdb/gdb/floatformat.h
new file mode 100644
index 0000000..a0a53dc
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/floatformat.h
@@ -0,0 +1,87 @@
+/* IEEE floating point support declarations, for GDB, the GNU Debugger.
+ Copyright (C) 1991 Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#if !defined (FLOATFORMAT_H)
+#define FLOATFORMAT_H 1
+
+#include "ansidecl.h"
+
+/* A floatformat consists of a sign bit, an exponent and a mantissa. Once the
+ bytes are concatenated according to the byteorder flag, then each of those
+ fields is contiguous. We number the bits with 0 being the most significant
+ (i.e. BITS_BIG_ENDIAN type numbering), and specify which bits each field
+ contains with the *_start and *_len fields. */
+
+enum floatformat_byteorders { floatformat_little, floatformat_big };
+
+enum floatformat_intbit { floatformat_intbit_yes, floatformat_intbit_no };
+
+struct floatformat
+{
+ enum floatformat_byteorders byteorder;
+ unsigned int totalsize; /* Total size of number in bits */
+
+ /* Sign bit is always one bit long. 1 means negative, 0 means positive. */
+ unsigned int sign_start;
+
+ unsigned int exp_start;
+ unsigned int exp_len;
+ /* Amount added to "true" exponent. 0x3fff for many IEEE extendeds. */
+ unsigned int exp_bias;
+ /* Exponent value which indicates NaN. This is the actual value stored in
+ the float, not adjusted by the exp_bias. This usually consists of all
+ one bits. */
+ unsigned int exp_nan;
+
+ unsigned int man_start;
+ unsigned int man_len;
+
+ /* Is the integer bit explicit or implicit? */
+ enum floatformat_intbit intbit;
+};
+
+/* floatformats for IEEE single and double, big and little endian. */
+
+extern const struct floatformat floatformat_ieee_single_big;
+extern const struct floatformat floatformat_ieee_single_little;
+extern const struct floatformat floatformat_ieee_double_big;
+extern const struct floatformat floatformat_ieee_double_little;
+
+/* floatformats for various extendeds. */
+
+extern const struct floatformat floatformat_i387_ext;
+extern const struct floatformat floatformat_m68881_ext;
+extern const struct floatformat floatformat_i960_ext;
+extern const struct floatformat floatformat_m88110_ext;
+
+/* Convert from FMT to a double.
+ FROM is the address of the extended float.
+ Store the double in *TO. */
+
+extern void
+floatformat_to_double PARAMS ((const struct floatformat *, char *, double *));
+
+/* The converse: convert the double *FROM to FMT
+ and store where TO points. */
+
+extern void
+floatformat_from_double PARAMS ((const struct floatformat *,
+ double *, char *));
+
+#endif /* defined (FLOATFORMAT_H) */
diff --git a/gnu/usr.bin/gdb/gdb/fopen-bin.h b/gnu/usr.bin/gdb/gdb/fopen-bin.h
new file mode 100644
index 0000000..2b8a8e2
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/fopen-bin.h
@@ -0,0 +1,27 @@
+/* Macros for the 'type' part of an fopen, freopen or fdopen.
+
+ <Read|Write>[Update]<Binary file|text file>
+
+ This version is for "binary" systems, where text and binary files are
+ different. An example is Mess-Dose. Many Unix systems could also
+ cope with a "b" in the string, indicating binary files, but some reject this
+ (and thereby don't conform to ANSI C, but what else is new?).
+
+ This file is designed for inclusion by host-dependent .h files. No
+ user application should include it directly, since that would make
+ the application unable to be configured for both "same" and "binary"
+ variant systems. */
+
+#define FOPEN_RB "rb"
+#define FOPEN_WB "wb"
+#define FOPEN_AB "ab"
+#define FOPEN_RUB "r+b"
+#define FOPEN_WUB "w+b"
+#define FOPEN_AUB "a+b"
+
+#define FOPEN_RT "r"
+#define FOPEN_WT "w"
+#define FOPEN_AT "a"
+#define FOPEN_RUT "r+"
+#define FOPEN_WUT "w+"
+#define FOPEN_AUT "a+"
diff --git a/gnu/usr.bin/gdb/gdb/fopen-same.h b/gnu/usr.bin/gdb/gdb/fopen-same.h
new file mode 100644
index 0000000..c296678
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/fopen-same.h
@@ -0,0 +1,27 @@
+/* Macros for the 'type' part of an fopen, freopen or fdopen.
+
+ <Read|Write>[Update]<Binary file|text file>
+
+ This version is for "same" systems, where text and binary files are
+ the same. An example is Unix. Many Unix systems could also add a
+ "b" to the string, indicating binary files, but some reject this
+ (and thereby don't conform to ANSI C, but what else is new?).
+
+ This file is designed for inclusion by host-dependent .h files. No
+ user application should include it directly, since that would make
+ the application unable to be configured for both "same" and "binary"
+ variant systems. */
+
+#define FOPEN_RB "r"
+#define FOPEN_WB "w"
+#define FOPEN_AB "a"
+#define FOPEN_RUB "r+"
+#define FOPEN_WUB "w+"
+#define FOPEN_AUB "a+"
+
+#define FOPEN_RT "r"
+#define FOPEN_WT "w"
+#define FOPEN_AT "a"
+#define FOPEN_RUT "r+"
+#define FOPEN_WUT "w+"
+#define FOPEN_AUT "a+"
diff --git a/gnu/usr.bin/gdb/gdb/fork-child.c b/gnu/usr.bin/gdb/gdb/fork-child.c
new file mode 100644
index 0000000..bca1841
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/fork-child.c
@@ -0,0 +1,300 @@
+/* Fork a Unix child process, and set up to debug it, for GDB.
+ Copyright 1990, 1991, 1992, 1993, 1994 Free Software Foundation, Inc.
+ Contributed by Cygnus Support.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "defs.h"
+#include <string.h>
+#include "frame.h" /* required by inferior.h */
+#include "inferior.h"
+#include "target.h"
+#include "wait.h"
+#include "gdbcore.h"
+#include "terminal.h"
+#include "thread.h"
+
+#include <signal.h>
+
+extern char **environ;
+
+#ifndef SHELL_FILE
+#define SHELL_FILE "/bin/sh"
+#endif
+
+/* Start an inferior Unix child process and sets inferior_pid to its pid.
+ EXEC_FILE is the file to run.
+ ALLARGS is a string containing the arguments to the program.
+ ENV is the environment vector to pass. SHELL_FILE is the shell file,
+ or NULL if we should pick one. Errors reported with error(). */
+
+void
+fork_inferior (exec_file, allargs, env, traceme_fun, init_trace_fun,
+ shell_file)
+ char *exec_file;
+ char *allargs;
+ char **env;
+ void (*traceme_fun) PARAMS ((void));
+ void (*init_trace_fun) PARAMS ((int));
+ char *shell_file;
+{
+ int pid;
+ char *shell_command;
+ static char default_shell_file[] = SHELL_FILE;
+ int len;
+ /* Set debug_fork then attach to the child while it sleeps, to debug. */
+ static int debug_fork = 0;
+ /* This is set to the result of setpgrp, which if vforked, will be visible
+ to you in the parent process. It's only used by humans for debugging. */
+ static int debug_setpgrp = 657473;
+ char **save_our_env;
+
+ /* If no exec file handed to us, get it from the exec-file command -- with
+ a good, common error message if none is specified. */
+ if (exec_file == 0)
+ exec_file = get_exec_file(1);
+
+ /* The user might want tilde-expansion, and in general probably wants
+ the program to behave the same way as if run from
+ his/her favorite shell. So we let the shell run it for us.
+ FIXME-maybe, we might want a "set shell" command so the user can change
+ the shell from within GDB (if so, change callers which pass in a non-NULL
+ shell_file too). */
+ if (shell_file == NULL)
+ shell_file = getenv ("SHELL");
+ if (shell_file == NULL)
+ shell_file = default_shell_file;
+
+ /* Multiplying the length of exec_file by 4 is to account for the fact
+ that it may expand when quoted; it is a worst-case number based on
+ every character being '. */
+ len = 5 + 4 * strlen (exec_file) + 1 + strlen (allargs) + 1 + /*slop*/ 12;
+ /* If desired, concat something onto the front of ALLARGS.
+ SHELL_COMMAND is the result. */
+#ifdef SHELL_COMMAND_CONCAT
+ shell_command = (char *) alloca (strlen (SHELL_COMMAND_CONCAT) + len);
+ strcpy (shell_command, SHELL_COMMAND_CONCAT);
+#else
+ shell_command = (char *) alloca (len);
+ shell_command[0] = '\0';
+#endif
+ strcat (shell_command, "exec ");
+
+ /* Now add exec_file, quoting as necessary. */
+ {
+ char *p;
+ int need_to_quote;
+
+ /* Quoting in this style is said to work with all shells. But csh
+ on IRIX 4.0.1 can't deal with it. So we only quote it if we need
+ to. */
+ p = exec_file;
+ while (1)
+ {
+ switch (*p)
+ {
+ case '\'':
+ case '"':
+ case '(':
+ case ')':
+ case '$':
+ case '&':
+ case ';':
+ case '<':
+ case '>':
+ case ' ':
+ case '\n':
+ case '\t':
+ need_to_quote = 1;
+ goto end_scan;
+
+ case '\0':
+ need_to_quote = 0;
+ goto end_scan;
+
+ default:
+ break;
+ }
+ ++p;
+ }
+ end_scan:
+ if (need_to_quote)
+ {
+ strcat (shell_command, "'");
+ for (p = exec_file; *p != '\0'; ++p)
+ {
+ if (*p == '\'')
+ strcat (shell_command, "'\\''");
+ else
+ strncat (shell_command, p, 1);
+ }
+ strcat (shell_command, "'");
+ }
+ else
+ strcat (shell_command, exec_file);
+ }
+
+ strcat (shell_command, " ");
+ strcat (shell_command, allargs);
+
+ /* exec is said to fail if the executable is open. */
+ close_exec_file ();
+
+ /* Retain a copy of our environment variables, since the child will
+ replace the value of environ and if we're vforked, we have to
+ restore it. */
+ save_our_env = environ;
+
+ /* Tell the terminal handling subsystem what tty we plan to run on;
+ it will just record the information for later. */
+
+ new_tty_prefork (inferior_io_terminal);
+
+ /* It is generally good practice to flush any possible pending stdio
+ output prior to doing a fork, to avoid the possibility of both the
+ parent and child flushing the same data after the fork. */
+
+ gdb_flush (gdb_stdout);
+ gdb_flush (gdb_stderr);
+
+#if defined(USG) && !defined(HAVE_VFORK)
+ pid = fork ();
+#else
+ if (debug_fork)
+ pid = fork ();
+ else
+ pid = vfork ();
+#endif
+
+ if (pid < 0)
+ perror_with_name ("vfork");
+
+ if (pid == 0)
+ {
+ if (debug_fork)
+ sleep (debug_fork);
+
+ /* Run inferior in a separate process group. */
+ debug_setpgrp = gdb_setpgid ();
+ if (debug_setpgrp == -1)
+ perror("setpgrp failed in child");
+
+ /* Ask the tty subsystem to switch to the one we specified earlier
+ (or to share the current terminal, if none was specified). */
+
+ new_tty ();
+
+ /* Changing the signal handlers for the inferior after
+ a vfork can also change them for the superior, so we don't mess
+ with signals here. See comments in
+ initialize_signals for how we get the right signal handlers
+ for the inferior. */
+
+ /* "Trace me, Dr. Memory!" */
+ (*traceme_fun) ();
+
+ /* There is no execlpe call, so we have to set the environment
+ for our child in the global variable. If we've vforked, this
+ clobbers the parent, but environ is restored a few lines down
+ in the parent. By the way, yes we do need to look down the
+ path to find $SHELL. Rich Pixley says so, and I agree. */
+ environ = env;
+ execlp (shell_file, shell_file, "-c", shell_command, (char *)0);
+
+ fprintf_unfiltered (gdb_stderr, "Cannot exec %s: %s.\n", shell_file,
+ safe_strerror (errno));
+ gdb_flush (gdb_stderr);
+ _exit (0177);
+ }
+
+ /* Restore our environment in case a vforked child clob'd it. */
+ environ = save_our_env;
+
+ init_thread_list();
+
+ inferior_pid = pid; /* Needed for wait_for_inferior stuff below */
+
+ /* Now that we have a child process, make it our target, and
+ initialize anything target-vector-specific that needs initializing. */
+ (*init_trace_fun)(pid);
+
+ /* We are now in the child process of interest, having exec'd the
+ correct program, and are poised at the first instruction of the
+ new program. */
+#ifdef SOLIB_CREATE_INFERIOR_HOOK
+ SOLIB_CREATE_INFERIOR_HOOK (pid);
+#endif
+}
+
+/* Accept NTRAPS traps from the inferior. */
+
+void
+startup_inferior (ntraps)
+ int ntraps;
+{
+ int pending_execs = ntraps;
+ int terminal_initted;
+
+ /* The process was started by the fork that created it,
+ but it will have stopped one instruction after execing the shell.
+ Here we must get it up to actual execution of the real program. */
+
+ clear_proceed_status ();
+
+ init_wait_for_inferior ();
+
+ terminal_initted = 0;
+
+#ifdef STARTUP_INFERIOR
+ STARTUP_INFERIOR (pending_execs);
+#else
+ while (1)
+ {
+ stop_soon_quietly = 1; /* Make wait_for_inferior be quiet */
+ wait_for_inferior ();
+ if (stop_signal != TARGET_SIGNAL_TRAP)
+ {
+ /* Let shell child handle its own signals in its own way */
+ /* FIXME, what if child has exit()ed? Must exit loop somehow */
+ resume (0, stop_signal);
+ }
+ else
+ {
+ /* We handle SIGTRAP, however; it means child did an exec. */
+ if (!terminal_initted)
+ {
+ /* Now that the child has exec'd we know it has already set its
+ process group. On POSIX systems, tcsetpgrp will fail with
+ EPERM if we try it before the child's setpgid. */
+
+ /* Set up the "saved terminal modes" of the inferior
+ based on what modes we are starting it with. */
+ target_terminal_init ();
+
+ /* Install inferior's terminal modes. */
+ target_terminal_inferior ();
+
+ terminal_initted = 1;
+ }
+ if (0 == --pending_execs)
+ break;
+ resume (0, TARGET_SIGNAL_0); /* Just make it go on */
+ }
+ }
+#endif /* STARTUP_INFERIOR */
+ stop_soon_quietly = 0;
+}
diff --git a/gnu/usr.bin/gdb/gdb/frame.h b/gnu/usr.bin/gdb/gdb/frame.h
new file mode 100644
index 0000000..a46ed17
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/frame.h
@@ -0,0 +1,240 @@
+/* Definitions for dealing with stack frames, for GDB, the GNU debugger.
+ Copyright 1986, 1989, 1991, 1992 Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#if !defined (FRAME_H)
+#define FRAME_H 1
+
+/* A FRAME identifies a specific stack frame. It is not constant over
+ calls to the inferior (frame addresses are, see below).
+
+ This is implemented as a "struct frame_info *". This file and
+ blockframe.c are the only places which are allowed to use the
+ equivalence between FRAME and struct frame_info *. Exception:
+ Prototypes in other files use "struct frame_info *" because this
+ file might not be included.
+
+ The distinction between a FRAME and a "struct frame_info *" is made
+ with the idea of maybe someday changing a FRAME to be something else,
+ but seems to me that a "struct frame_info *" is fully general (since
+ any necessarily fields can be added; changing the meaning of existing
+ fields is not helped by the FRAME distinction), and this distinction
+ merely creates unnecessary hair. -kingdon, 18 May 93. */
+typedef struct frame_info *FRAME;
+
+/* Convert from a "struct frame_info *" into a FRAME. */
+#define FRAME_INFO_ID(f) (f)
+
+/* Convert from a FRAME into a "struct frame_info *". */
+extern struct frame_info *
+get_frame_info PARAMS ((FRAME));
+
+/* Type of the address of a frame. It is widely assumed (at least in
+ prototypes in headers which might not include this header) that
+ this is the same as CORE_ADDR, and no one can think of a case in
+ which it wouldn't be, so it might be best to remove this typedef. */
+typedef CORE_ADDR FRAME_ADDR;
+
+/* Convert from a FRAME into a frame address. Except in the
+ machine-dependent *FRAME* macros, a frame address has no defined
+ meaning other than as a magic cookie which identifies a frame over
+ calls to the inferior. The only known exception is inferior.h
+ (PC_IN_CALL_DUMMY) [ON_STACK]; see comments there. You cannot
+ assume that a frame address contains enough information to
+ reconstruct the frame; if you want more than just to identify the
+ frame (e.g. be able to fetch variables relative to that frame),
+ then save the whole struct frame_info (and the next struct
+ frame_info, since the latter is used for fetching variables on some
+ machines). */
+
+#define FRAME_FP(fr) ((fr)->frame)
+
+/* We keep a cache of stack frames, each of which is a "struct
+ frame_info". The innermost one gets allocated (in
+ wait_for_inferior) each time the inferior stops; current_frame
+ points to it. Additional frames get allocated (in
+ get_prev_frame_info) as needed, and are chained through the next
+ and prev fields. Any time that the frame cache becomes invalid
+ (most notably when we execute something, but also if we change how
+ we interpret the frames (e.g. "set heuristic-fence-post" in
+ mips-tdep.c, or anything which reads new symbols)), we should call
+ reinit_frame_cache. */
+
+struct frame_info
+ {
+ /* Nominal address of the frame described. See comments at FRAME_FP
+ about what this means outside the *FRAME* macros; in the *FRAME*
+ macros, it can mean whatever makes most sense for this machine. */
+ FRAME_ADDR frame;
+
+ /* Address at which execution is occurring in this frame.
+ For the innermost frame, it's the current pc.
+ For other frames, it is a pc saved in the next frame. */
+ CORE_ADDR pc;
+
+ /* Nonzero if this is a frame associated with calling a signal handler.
+
+ Set by machine-dependent code. On some machines, if
+ the machine-dependent code fails to check for this, the backtrace
+ will look relatively normal. For example, on the i386
+ #3 0x158728 in sighold ()
+ On other machines (e.g. rs6000), the machine-dependent code better
+ set this to prevent us from trying to print it like a normal frame. */
+ int signal_handler_caller;
+
+ /* Anything extra for this structure that may have been defined
+ in the machine dependent files. */
+#ifdef EXTRA_FRAME_INFO
+ EXTRA_FRAME_INFO
+#endif
+
+ /* We should probably also store a "struct frame_saved_regs" here.
+ This is already done by some machines (e.g. config/m88k/tm-m88k.h)
+ but there is no reason it couldn't be general. */
+
+ /* Pointers to the next and previous frame_info's in the frame cache. */
+ FRAME next, prev;
+ };
+
+/* Describe the saved registers of a frame. */
+
+struct frame_saved_regs
+ {
+
+ /* For each register, address of where it was saved on entry to
+ the frame, or zero if it was not saved on entry to this frame.
+ This includes special registers such as pc and fp saved in
+ special ways in the stack frame. The SP_REGNUM is even more
+ special, the address here is the sp for the next frame, not the
+ address where the sp was saved. */
+
+ CORE_ADDR regs[NUM_REGS];
+ };
+
+/* Define a default FRAME_CHAIN_VALID, in the form that is suitable for most
+ targets. If FRAME_CHAIN_VALID returns zero it means that the given frame
+ is the outermost one and has no caller.
+
+ If a particular target needs a different definition, then it can override
+ the definition here by providing one in the tm file. */
+
+#if !defined (FRAME_CHAIN_VALID)
+
+#if defined (FRAME_CHAIN_VALID_ALTERNATE)
+
+/* Use the alternate method of avoiding running up off the end of the frame
+ chain or following frames back into the startup code. See the comments
+ in objfiles.h. */
+
+#define FRAME_CHAIN_VALID(chain, thisframe) \
+ ((chain) != 0 \
+ && !inside_main_func ((thisframe) -> pc) \
+ && !inside_entry_func ((thisframe) -> pc))
+
+#else
+
+#define FRAME_CHAIN_VALID(chain, thisframe) \
+ ((chain) != 0 \
+ && !inside_entry_file (FRAME_SAVED_PC (thisframe)))
+
+#endif /* FRAME_CHAIN_VALID_ALTERNATE */
+
+#endif /* FRAME_CHAIN_VALID */
+
+/* The stack frame that the user has specified for commands to act on.
+ Note that one cannot assume this is the address of valid data. */
+
+extern FRAME selected_frame;
+
+/* Level of the selected frame:
+ 0 for innermost, 1 for its caller, ...
+ or -1 for frame specified by address with no defined level. */
+
+extern int selected_frame_level;
+
+extern struct frame_info *
+get_prev_frame_info PARAMS ((FRAME));
+
+extern FRAME
+create_new_frame PARAMS ((FRAME_ADDR, CORE_ADDR));
+
+extern void
+flush_cached_frames PARAMS ((void));
+
+extern void
+reinit_frame_cache PARAMS ((void));
+
+extern void
+get_frame_saved_regs PARAMS ((struct frame_info *, struct frame_saved_regs *));
+
+extern void
+set_current_frame PARAMS ((FRAME));
+
+extern FRAME
+get_prev_frame PARAMS ((FRAME));
+
+extern FRAME
+get_current_frame PARAMS ((void));
+
+extern FRAME
+get_next_frame PARAMS ((FRAME));
+
+extern struct block *
+get_frame_block PARAMS ((FRAME));
+
+extern struct block *
+get_current_block PARAMS ((void));
+
+extern struct block *
+get_selected_block PARAMS ((void));
+
+extern struct symbol *
+get_frame_function PARAMS ((FRAME));
+
+extern CORE_ADDR
+get_frame_pc PARAMS ((FRAME));
+
+extern CORE_ADDR
+get_pc_function_start PARAMS ((CORE_ADDR));
+
+extern struct block * block_for_pc PARAMS ((CORE_ADDR));
+
+extern int frameless_look_for_prologue PARAMS ((FRAME));
+
+extern void print_frame_args PARAMS ((struct symbol *, struct frame_info *,
+ int, GDB_FILE *));
+
+extern FRAME find_relative_frame PARAMS ((FRAME, int*));
+
+extern void print_stack_frame PARAMS ((FRAME, int, int));
+
+extern void select_frame PARAMS ((FRAME, int));
+
+extern void record_selected_frame PARAMS ((FRAME_ADDR *, int *));
+
+extern void print_frame_info PARAMS ((struct frame_info *, int, int, int));
+
+extern CORE_ADDR find_saved_register PARAMS ((FRAME, int));
+
+extern FRAME block_innermost_frame PARAMS ((struct block *));
+
+extern FRAME find_frame_addr_in_frame_chain PARAMS ((FRAME_ADDR));
+
+extern CORE_ADDR sigtramp_saved_pc PARAMS ((FRAME));
+
+#endif /* !defined (FRAME_H) */
diff --git a/gnu/usr.bin/gdb/gdb/freebsd-nat.c b/gnu/usr.bin/gdb/gdb/freebsd-nat.c
new file mode 100644
index 0000000..90b3236
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/freebsd-nat.c
@@ -0,0 +1,619 @@
+/* Native-dependent code for BSD Unix running on i386's, for GDB.
+ Copyright 1988, 1989, 1991, 1992 Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ $Id: freebsd-nat.c,v 1.6 1995/05/09 13:59:22 rgrimes Exp $
+*/
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <signal.h>
+#include <sys/user.h>
+#include <machine/reg.h>
+#include <machine/frame.h>
+#include <sys/ptrace.h>
+
+#include "defs.h"
+
+/* this table must line up with REGISTER_NAMES in tm-i386v.h */
+/* symbols like 'tEAX' come from <machine/reg.h> */
+static int tregmap[] =
+{
+ tEAX, tECX, tEDX, tEBX,
+ tESP, tEBP, tESI, tEDI,
+ tEIP, tEFLAGS, tCS, tSS,
+ tDS, tES, tSS, tSS, /* lies: no fs or gs */
+};
+
+/* blockend is the value of u.u_ar0, and points to the
+ place where ES is stored. */
+
+int
+i386_register_u_addr (blockend, regnum)
+ int blockend;
+ int regnum;
+{
+ return (blockend + 4 * tregmap[regnum]);
+}
+
+
+#define fpstate save87
+#define U_FPSTATE(u) u.u_pcb.pcb_savefpu
+
+static void
+i387_to_double (from, to)
+ char *from;
+ char *to;
+{
+ long *lp;
+ /* push extended mode on 387 stack, then pop in double mode
+ *
+ * first, set exception masks so no error is generated -
+ * number will be rounded to inf or 0, if necessary
+ */
+ asm ("pushl %eax"); /* grab a stack slot */
+ asm ("fstcw (%esp)"); /* get 387 control word */
+ asm ("movl (%esp),%eax"); /* save old value */
+ asm ("orl $0x3f,%eax"); /* mask all exceptions */
+ asm ("pushl %eax");
+ asm ("fldcw (%esp)"); /* load new value into 387 */
+
+ asm ("movl 8(%ebp),%eax");
+ asm ("fldt (%eax)"); /* push extended number on 387 stack */
+ asm ("fwait");
+ asm ("movl 12(%ebp),%eax");
+ asm ("fstpl (%eax)"); /* pop double */
+ asm ("fwait");
+
+ asm ("popl %eax"); /* flush modified control word */
+ asm ("fnclex"); /* clear exceptions */
+ asm ("fldcw (%esp)"); /* restore original control word */
+ asm ("popl %eax"); /* flush saved copy */
+}
+
+#if 0
+static void
+double_to_i387 (from, to)
+ char *from;
+ char *to;
+{
+ /* push double mode on 387 stack, then pop in extended mode
+ * no errors are possible because every 64-bit pattern
+ * can be converted to an extended
+ */
+ asm ("movl 8(%ebp),%eax");
+ asm ("fldl (%eax)");
+ asm ("fwait");
+ asm ("movl 12(%ebp),%eax");
+ asm ("fstpt (%eax)");
+ asm ("fwait");
+}
+#endif
+
+struct env387
+{
+ unsigned short control;
+ unsigned short r0;
+ unsigned short status;
+ unsigned short r1;
+ unsigned short tag;
+ unsigned short r2;
+ unsigned long eip;
+ unsigned short code_seg;
+ unsigned short opcode;
+ unsigned long operand;
+ unsigned short operand_seg;
+ unsigned short r3;
+ unsigned char regs[8][10];
+};
+
+/* static */ void
+print_387_control_word (control)
+unsigned int control;
+{
+ printf ("control 0x%04x: ", control);
+ printf ("compute to ");
+ switch ((control >> 8) & 3)
+ {
+ case 0: printf ("24 bits; "); break;
+ case 1: printf ("(bad); "); break;
+ case 2: printf ("53 bits; "); break;
+ case 3: printf ("64 bits; "); break;
+ }
+ printf ("round ");
+ switch ((control >> 10) & 3)
+ {
+ case 0: printf ("NEAREST; "); break;
+ case 1: printf ("DOWN; "); break;
+ case 2: printf ("UP; "); break;
+ case 3: printf ("CHOP; "); break;
+ }
+ if (control & 0x3f)
+ {
+ printf ("mask:");
+ if (control & 0x0001) printf (" INVALID");
+ if (control & 0x0002) printf (" DENORM");
+ if (control & 0x0004) printf (" DIVZ");
+ if (control & 0x0008) printf (" OVERF");
+ if (control & 0x0010) printf (" UNDERF");
+ if (control & 0x0020) printf (" LOS");
+ printf (";");
+ }
+ printf ("\n");
+ if (control & 0xe080) printf ("warning: reserved bits on 0x%x\n",
+ control & 0xe080);
+}
+
+/* static */ void
+print_387_status_word (status)
+ unsigned int status;
+{
+ printf ("status 0x%04x: ", status);
+ if (status & 0xff)
+ {
+ printf ("exceptions:");
+ if (status & 0x0001) printf (" INVALID");
+ if (status & 0x0002) printf (" DENORM");
+ if (status & 0x0004) printf (" DIVZ");
+ if (status & 0x0008) printf (" OVERF");
+ if (status & 0x0010) printf (" UNDERF");
+ if (status & 0x0020) printf (" LOS");
+ if (status & 0x0040) printf (" FPSTACK");
+ printf ("; ");
+ }
+ printf ("flags: %d%d%d%d; ",
+ (status & 0x4000) != 0,
+ (status & 0x0400) != 0,
+ (status & 0x0200) != 0,
+ (status & 0x0100) != 0);
+
+ printf ("top %d\n", (status >> 11) & 7);
+}
+
+static void
+print_387_status (status, ep)
+ unsigned short status;
+ struct env387 *ep;
+{
+ int i;
+ int bothstatus;
+ int top;
+ int fpreg;
+ unsigned char *p;
+
+ bothstatus = ((status != 0) && (ep->status != 0));
+ if (status != 0)
+ {
+ if (bothstatus)
+ printf ("u: ");
+ print_387_status_word ((unsigned int)status);
+ }
+
+ if (ep->status != 0)
+ {
+ if (bothstatus)
+ printf ("e: ");
+ print_387_status_word ((unsigned int)ep->status);
+ }
+
+ print_387_control_word ((unsigned int)ep->control);
+ printf ("opcode 0x%x; ", ep->opcode);
+ printf ("pc 0x%x:0x%x; ", ep->code_seg, ep->eip);
+ printf ("operand 0x%x:0x%x\n", ep->operand_seg, ep->operand);
+
+ top = (ep->status >> 11) & 7;
+
+ printf (" regno tag msb lsb value\n");
+ for (fpreg = 7; fpreg >= 0; fpreg--)
+ {
+ int st_regno;
+ double val;
+
+ /* The physical regno `fpreg' is only relevant as an index into the
+ * tag word. Logical `%st' numbers are required for indexing ep->regs.
+ */
+ st_regno = (fpreg + 8 - top) & 7;
+
+ printf ("%%st(%d) %s ", st_regno, fpreg == top ? "=>" : " ");
+
+ switch ((ep->tag >> (fpreg * 2)) & 3)
+ {
+ case 0: printf ("valid "); break;
+ case 1: printf ("zero "); break;
+ case 2: printf ("trap "); break;
+ case 3: printf ("empty "); break;
+ }
+ for (i = 9; i >= 0; i--)
+ printf ("%02x", ep->regs[st_regno][i]);
+
+ i387_to_double (ep->regs[st_regno], (char *)&val);
+ printf (" %g\n", val);
+ }
+}
+
+void
+i386_float_info ()
+{
+ struct user u; /* just for address computations */
+ int i;
+ /* fpstate defined in <sys/user.h> */
+ struct fpstate *fpstatep;
+ char buf[sizeof (struct fpstate) + 2 * sizeof (int)];
+ unsigned int uaddr;
+ char fpvalid;
+ unsigned int rounded_addr;
+ unsigned int rounded_size;
+ /*extern int corechan;*/
+ int skip;
+ extern int inferior_pid;
+
+ uaddr = (char *)&U_FPSTATE(u) - (char *)&u;
+ if (inferior_pid)
+ {
+ int *ip;
+
+ rounded_addr = uaddr & -sizeof (int);
+ rounded_size = (((uaddr + sizeof (struct fpstate)) - uaddr) +
+ sizeof (int) - 1) / sizeof (int);
+ skip = uaddr - rounded_addr;
+
+ ip = (int *)buf;
+ for (i = 0; i < rounded_size; i++)
+ {
+ *ip++ = ptrace (PT_READ_U, inferior_pid, (caddr_t)rounded_addr, 0);
+ rounded_addr += sizeof (int);
+ }
+ }
+ else
+ {
+#if 1
+ printf("float info: can't do a core file (yet)\n");
+ return;
+#else
+ if (lseek (corechan, uaddr, 0) < 0)
+ perror_with_name ("seek on core file");
+ if (myread (corechan, buf, sizeof (struct fpstate)) < 0)
+ perror_with_name ("read from core file");
+ skip = 0;
+#endif
+ }
+
+ fpstatep = (struct fpstate *)(buf + skip);
+ print_387_status (fpstatep->sv_ex_sw, (struct env387 *)fpstatep);
+}
+
+#ifdef SETUP_ARBITRARY_FRAME
+FRAME
+setup_arbitrary_frame (numargs, args)
+int numargs;
+unsigned int *args;
+{
+ if (numargs > 2)
+ error ("Too many args in frame specification");
+ return create_new_frame ((CORE_ADDR)args[0], (CORE_ADDR)args[1]);
+}
+#endif
+
+#ifdef KERNEL_DEBUG
+#include <sys/proc.h>
+#include <sys/stat.h>
+#include <sys/fcntl.h>
+#include <unistd.h>
+
+#include <vm/vm.h>
+#include <vm/vm_param.h>
+
+#include <machine/vmparam.h>
+#include <machine/pcb.h>
+
+#define KERNOFF ((unsigned)KERNBASE)
+#define INKERNEL(x) ((x) >= KERNOFF)
+
+static CORE_ADDR sbr;
+static CORE_ADDR curpcb;
+static CORE_ADDR kstack;
+static int found_pcb;
+static int devmem;
+static int kfd;
+static struct pcb pcb;
+int read_pcb (int, CORE_ADDR);
+static CORE_ADDR kvtophys (int, CORE_ADDR);
+static physrd(int, u_int, char*, int);
+
+extern CORE_ADDR ksym_lookup(const char *);
+
+/* substitutes for the stuff in libkvm which doesn't work */
+/* most of this was taken from the old kgdb */
+
+/* we don't need all this stuff, but the call should look the same */
+kvm_open (efile, cfile, sfile, perm, errout)
+char *efile;
+char *cfile;
+char *sfile; /* makes this kvm_open more compatible to the one in libkvm */
+int perm;
+char *errout; /* makes this kvm_open more compatible to the one in libkvm */
+{
+ struct stat stb;
+ CORE_ADDR addr;
+ int cfd;
+
+ if ((cfd = open(cfile, perm, 0)) < 0)
+ return (cfd);
+
+ fstat(cfd, &stb);
+ if ((stb.st_mode & S_IFMT) == S_IFCHR && stb.st_rdev == makedev(2, 0)) {
+ devmem = 1;
+ kfd = open ("/dev/kmem", perm, 0);
+ }
+
+ physrd(cfd, ksym_lookup("IdlePTD") - KERNOFF, (char*)&sbr, sizeof sbr);
+ printf("IdlePTD %x\n", sbr);
+ curpcb = ksym_lookup("curpcb") - KERNOFF;
+ physrd(cfd, curpcb, (char*)&curpcb, sizeof curpcb);
+ kstack = ksym_lookup("kstack");
+
+ found_pcb = 1; /* for vtophys */
+ if (!devmem)
+ read_pcb(cfd, ksym_lookup("dumppcb") - KERNOFF);
+ else
+ read_pcb(cfd, kvtophys(cfd, kstack));
+
+ return (cfd);
+}
+
+kvm_close (fd)
+{
+ return (close (fd));
+}
+
+kvm_write(core_kd, memaddr, myaddr, len)
+CORE_ADDR memaddr;
+char *myaddr;
+{
+ int cc;
+
+ if (devmem) {
+ if (kfd > 0) {
+ /*
+ * Just like kvm_read, only we write.
+ */
+ errno = 0;
+ if (lseek(kfd, (off_t)memaddr, 0) < 0 && errno != 0) {
+ error("kvm_write:invalid address (%x)", memaddr);
+ return (0);
+ }
+ cc = write(kfd, myaddr, len);
+ if (cc < 0) {
+ error("kvm_write:write failed");
+ return (0);
+ } else if (cc < len)
+ error("kvm_write:short write");
+ return (cc);
+ } else
+ return (0);
+ } else {
+ printf("kvm_write not implemented for dead kernels\n");
+ return (0);
+ }
+ /* NOTREACHED */
+}
+
+kvm_read(core_kd, memaddr, myaddr, len)
+CORE_ADDR memaddr;
+char *myaddr;
+{
+ return (kernel_core_file_hook (core_kd, memaddr, myaddr, len));
+}
+
+kvm_uread(core_kd, p, memaddr, myaddr, len)
+register struct proc *p;
+CORE_ADDR memaddr;
+char *myaddr;
+{
+ register char *cp;
+ char procfile[MAXPATHLEN];
+ ssize_t amount;
+ int fd;
+
+ if (devmem) {
+ cp = myaddr;
+
+ sprintf(procfile, "/proc/%d/mem", p->p_pid);
+ fd = open(procfile, O_RDONLY, 0);
+
+ if (fd < 0) {
+ error("cannot open %s", procfile);
+ close(fd);
+ return (0);
+ }
+
+ while (len > 0) {
+ if (lseek(fd, memaddr, 0) == -1 && errno != 0) {
+ error("invalid address (%x) in %s",
+ memaddr, procfile);
+ break;
+ }
+ amount = read(fd, cp, len);
+ if (amount < 0) {
+ error("error reading %s", procfile);
+ break;
+ }
+ cp += amount;
+ memaddr += amount;
+ len -= amount;
+ }
+
+ close(fd);
+ return (ssize_t)(cp - myaddr);
+ } else {
+ return (kernel_core_file_hook (core_kd, memaddr, myaddr, len));
+ }
+}
+
+static
+physrd(cfd, addr, dat, len)
+u_int addr;
+char *dat;
+{
+ if (lseek(cfd, (off_t)addr, L_SET) == -1)
+ return (-1);
+ return (read(cfd, dat, len));
+}
+
+static CORE_ADDR
+kvtophys (fd, addr)
+CORE_ADDR addr;
+{
+ CORE_ADDR v;
+ struct pte pte;
+ static CORE_ADDR PTD = -1;
+ CORE_ADDR current_ptd;
+
+ /*
+ * If we're looking at the kernel stack,
+ * munge the address to refer to the user space mapping instead;
+ * that way we get the requested process's kstack, not the running one.
+ */
+ if (addr >= kstack && addr < kstack + ctob(UPAGES))
+ addr = (addr - kstack) + curpcb;
+
+ /*
+ * We may no longer have a linear system page table...
+ *
+ * Here's the scoop. IdlePTD contains the physical address
+ * of a page table directory that always maps the kernel.
+ * IdlePTD is in memory that is mapped 1-to-1, so we can
+ * find it easily given its 'virtual' address from ksym_lookup().
+ * For hysterical reasons, the value of IdlePTD is stored in sbr.
+ *
+ * To look up a kernel address, we first convert it to a 1st-level
+ * address and look it up in IdlePTD. This gives us the physical
+ * address of a page table page; we extract the 2nd-level part of
+ * VA and read the 2nd-level pte. Finally, we add the offset part
+ * of the VA into the physical address from the pte and return it.
+ *
+ * User addresses are a little more complicated. If we don't have
+ * a current PCB from read_pcb(), we use PTD, which is the (fixed)
+ * virtual address of the current ptd. Since it's NOT in 1-to-1
+ * kernel space, we must look it up using IdlePTD. If we do have
+ * a pcb, we get the ptd from pcb_ptd.
+ */
+
+ if (INKERNEL(addr))
+ current_ptd = sbr;
+ else if (found_pcb == 0) {
+ if (PTD == -1)
+ PTD = kvtophys(fd, ksym_lookup("PTD"));
+ current_ptd = PTD;
+ } else
+ current_ptd = pcb.pcb_ptd;
+
+ /*
+ * Read the first-level page table (ptd).
+ */
+ v = current_ptd + ((unsigned)addr >> PD_SHIFT) * sizeof pte;
+ if (physrd(fd, v, (char *)&pte, sizeof pte) < 0 || pte.pg_v == 0)
+ return (~0);
+
+ /*
+ * Read the second-level page table.
+ */
+ v = i386_ptob(pte.pg_pfnum) + ((addr&PT_MASK) >> PG_SHIFT) * sizeof pte;
+ if (physrd(fd, v, (char *) &pte, sizeof(pte)) < 0 || pte.pg_v == 0)
+ return (~0);
+
+ addr = i386_ptob(pte.pg_pfnum) + (addr & PGOFSET);
+#if 0
+ printf("vtophys(%x) -> %x\n", oldaddr, addr);
+#endif
+ return (addr);
+}
+
+read_pcb (fd, uaddr)
+CORE_ADDR uaddr;
+{
+ int i;
+ int *pcb_regs = (int *)&pcb;
+ int eip;
+
+ if (physrd(fd, uaddr, (char *)&pcb, sizeof pcb) < 0) {
+ error("cannot read pcb at %x\n", uaddr);
+ return (-1);
+ }
+ printf("current pcb at %x\n", uaddr);
+
+ /*
+ * get the register values out of the sys pcb and
+ * store them where `read_register' will find them.
+ */
+ for (i = 0; i < 8; ++i)
+ supply_register(i, &pcb_regs[i+10]);
+ supply_register(8, &pcb_regs[8]); /* eip */
+ supply_register(9, &pcb_regs[9]); /* eflags */
+ for (i = 10; i < 13; ++i) /* cs, ss, ds */
+ supply_register(i, &pcb_regs[i+9]);
+ supply_register(13, &pcb_regs[18]); /* es */
+ for (i = 14; i < 16; ++i) /* fs, gs */
+ supply_register(i, &pcb_regs[i+8]);
+
+#if 0 /* doesn't work ??? */
+ /* Hmm... */
+ if (target_read_memory(pcb_regs[5+10]+4, &eip, sizeof eip, 0))
+ error("Cannot read PC.");
+ supply_register(8, &eip); /* eip */
+#endif
+
+ /* XXX 80387 registers? */
+}
+
+/*
+ * read len bytes from kernel virtual address 'addr' into local
+ * buffer 'buf'. Return numbert of bytes if read ok, 0 otherwise. On read
+ * errors, portion of buffer not read is zeroed.
+ */
+kernel_core_file_hook(fd, addr, buf, len)
+ CORE_ADDR addr;
+ char *buf;
+ int len;
+{
+ int i;
+ CORE_ADDR paddr;
+ register char *cp;
+ int cc;
+
+ cp = buf;
+
+ while (len > 0) {
+ paddr = kvtophys(fd, addr);
+ if (paddr == ~0) {
+ bzero(buf, len);
+ break;
+ }
+ /* we can't read across a page boundary */
+ i = min(len, NBPG - (addr & PGOFSET));
+ if ((cc = physrd(fd, paddr, cp, i)) <= 0) {
+ bzero(cp, len);
+ return (cp - buf);
+ }
+ cp += cc;
+ addr += cc;
+ len -= cc;
+ }
+ return (cp - buf);
+}
+#endif /* KERNEL_DEBUG */
diff --git a/gnu/usr.bin/gdb/gdb/gdb-stabs.h b/gnu/usr.bin/gdb/gdb/gdb-stabs.h
new file mode 100644
index 0000000..6c2a5f0
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/gdb-stabs.h
@@ -0,0 +1,76 @@
+/* Definitions for symbol-reading containing "stabs", for GDB.
+ Copyright 1992 Free Software Foundation, Inc.
+ Contributed by Cygnus Support. Written by John Gilmore.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* This file exists to hold the common definitions required of most of
+ the symbol-readers that end up using stabs. The common use of
+ these `symbol-type-specific' customizations of the generic data
+ structures makes the stabs-oriented symbol readers able to call
+ each others' functions as required. */
+
+#if !defined (GDBSTABS_H)
+#define GDBSTABS_H
+
+/* Offsets in the psymtab's section_offsets array for various kinds of
+ stabs symbols. Every psymtab built from stabs will have these offsets
+ filled in by these guidelines, so that when actually reading symbols, the
+ proper offset can simply be selected and added to the symbol value. */
+
+#define SECT_OFF_TEXT 0
+#define SECT_OFF_DATA 1
+#define SECT_OFF_BSS 2
+#define SECT_OFF_RODATA 3
+#define SECT_OFF_MAX 4 /* Count of possible values */
+
+/* The stab_section_info chain remembers info from the ELF symbol table,
+ while psymtabs are being built for the other symbol tables in the
+ objfile. It is destroyed at the complation of psymtab-reading.
+ Any info that was used from it has been copied into psymtabs. */
+
+struct stab_section_info {
+ char *filename;
+ CORE_ADDR sections[SECT_OFF_MAX];
+ struct stab_section_info *next;
+ int found; /* Count of times it's found in searching */
+};
+
+/* Information is passed among various dbxread routines for accessing
+ symbol files. A pointer to this structure is kept in the sym_stab_info
+ field of the objfile struct. */
+
+struct dbx_symfile_info {
+ asection *text_sect; /* Text section accessor */
+ int symcount; /* How many symbols are there in the file */
+ char *stringtab; /* The actual string table */
+ int stringtab_size; /* Its size */
+ file_ptr symtab_offset; /* Offset in file to symbol table */
+ int symbol_size; /* Bytes in a single symbol */
+ struct stab_section_info *stab_section_info; /* section starting points
+ of the original .o files before linking. */
+};
+
+#define DBX_SYMFILE_INFO(o) ((struct dbx_symfile_info *)((o)->sym_stab_info))
+#define DBX_TEXT_SECT(o) (DBX_SYMFILE_INFO(o)->text_sect)
+#define DBX_SYMCOUNT(o) (DBX_SYMFILE_INFO(o)->symcount)
+#define DBX_STRINGTAB(o) (DBX_SYMFILE_INFO(o)->stringtab)
+#define DBX_STRINGTAB_SIZE(o) (DBX_SYMFILE_INFO(o)->stringtab_size)
+#define DBX_SYMTAB_OFFSET(o) (DBX_SYMFILE_INFO(o)->symtab_offset)
+#define DBX_SYMBOL_SIZE(o) (DBX_SYMFILE_INFO(o)->symbol_size)
+
+#endif /* GDBSTABS_H */
diff --git a/gnu/usr.bin/gdb/gdb/gdb.1 b/gnu/usr.bin/gdb/gdb/gdb.1
new file mode 100644
index 0000000..0245ec8
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/gdb.1
@@ -0,0 +1,390 @@
+.\" Copyright (c) 1991 Free Software Foundation
+.\" See section COPYING for conditions for redistribution
+.\" $Id: gdb.1,v 1.2 1994/12/30 23:25:45 jkh Exp $
+.TH gdb 1 "4nov1991" "GNU Tools" "GNU Tools"
+.SH NAME
+gdb \- The GNU Debugger
+.SH SYNOPSIS
+.na
+.TP
+.B gdb
+.RB "[\|" \-help "\|]"
+.RB "[\|" \-nx "\|]"
+.RB "[\|" \-q "\|]"
+.RB "[\|" \-k "\|]"
+.RB "[\|" \-w "\|]"
+.RB "[\|" \-batch "\|]"
+.RB "[\|" \-cd=\c
+.I dir\c
+\|]
+.RB "[\|" \-f "\|]"
+.RB "[\|" "\-b\ "\c
+.IR bps "\|]"
+.RB "[\|" "\-tty="\c
+.IR dev "\|]"
+.RB "[\|" "\-s "\c
+.I symfile\c
+\&\|]
+.RB "[\|" "\-e "\c
+.I prog\c
+\&\|]
+.RB "[\|" "\-se "\c
+.I prog\c
+\&\|]
+.RB "[\|" "\-c "\c
+.I core\c
+\&\|]
+.RB "[\|" "\-x "\c
+.I cmds\c
+\&\|]
+.RB "[\|" "\-d "\c
+.I dir\c
+\&\|]
+.RB "[\|" \c
+.I prog\c
+.RB "[\|" \c
+.IR core \||\| procID\c
+\&\|]\&\|]
+.ad b
+.SH DESCRIPTION
+The purpose of a debugger such as GDB is to allow you to see what is
+going on ``inside'' another program while it executes\(em\&or what another
+program was doing at the moment it crashed.
+
+GDB can do four main kinds of things (plus other things in support of
+these) to help you catch bugs in the act:
+
+.TP
+\ \ \ \(bu
+Start your program, specifying anything that might affect its behavior.
+
+.TP
+\ \ \ \(bu
+Make your program stop on specified conditions.
+
+.TP
+\ \ \ \(bu
+Examine what has happened, when your program has stopped.
+
+.TP
+\ \ \ \(bu
+Change things in your program, so you can experiment with correcting the
+effects of one bug and go on to learn about another.
+.PP
+
+You can use GDB to debug programs written in C, C++, and Modula-2.
+Fortran support will be added when a GNU Fortran compiler is ready.
+
+GDB is invoked with the shell command \c
+.B gdb\c
+\&. Once started, it reads
+commands from the terminal until you tell it to exit with the GDB
+command \c
+.B quit\c
+\&. You can get online help from \c
+.B gdb\c
+\& itself
+by using the command \c
+.B help\c
+\&.
+
+You can run \c
+.B gdb\c
+\& with no arguments or options; but the most
+usual way to start GDB is with one argument or two, specifying an
+executable program as the argument:
+.sp
+.br
+gdb\ program
+.br
+.sp
+
+You can also start with both an executable program and a core file specified:
+.sp
+.br
+gdb\ program\ core
+.br
+.sp
+
+You can, instead, specify a process ID as a second argument, if you want
+to debug a running process:
+.sp
+.br
+gdb\ program\ 1234
+.br
+.sp
+
+would attach GDB to process \c
+.B 1234\c
+\& (unless you also have a file
+named `\|\c
+.B 1234\c
+\&\|'; GDB does check for a core file first).
+
+Here are some of the most frequently needed GDB commands:
+.TP
+.B break \fR[\|\fIfile\fB:\fR\|]\fIfunction
+\&
+Set a breakpoint at \c
+.I function\c
+\& (in \c
+.I file\c
+\&).
+.TP
+.B run \fR[\|\fIarglist\fR\|]
+Start your program (with \c
+.I arglist\c
+\&, if specified).
+.TP
+.B bt
+Backtrace: display the program stack.
+.TP
+.BI print " expr"\c
+\&
+Display the value of an expression.
+.TP
+.B c
+Continue running your program (after stopping, e.g. at a breakpoint).
+.TP
+.B next
+Execute next program line (after stopping); step \c
+.I over\c
+\& any
+function calls in the line.
+.TP
+.B step
+Execute next program line (after stopping); step \c
+.I into\c
+\& any
+function calls in the line.
+.TP
+.B help \fR[\|\fIname\fR\|]
+Show information about GDB command \c
+.I name\c
+\&, or general information
+about using GDB.
+.TP
+.B quit
+Exit from GDB.
+.PP
+For full details on GDB, see \c
+.I
+Using GDB: A Guide to the GNU Source-Level Debugger\c
+\&, by Richard M. Stallman and Roland H. Pesch. The same text is available online
+as the \c
+.B gdb\c
+\& entry in the \c
+.B info\c
+\& program.
+.SH OPTIONS
+Any arguments other than options specify an executable
+file and core file (or process ID); that is, the first argument
+encountered with no
+associated option flag is equivalent to a `\|\c
+.B \-se\c
+\&\|' option, and the
+second, if any, is equivalent to a `\|\c
+.B \-c\c
+\&\|' option if it's the name of a file. Many options have
+both long and short forms; both are shown here. The long forms are also
+recognized if you truncate them, so long as enough of the option is
+present to be unambiguous. (If you prefer, you can flag option
+arguments with `\|\c
+.B +\c
+\&\|' rather than `\|\c
+.B \-\c
+\&\|', though we illustrate the
+more usual convention.)
+
+All the options and command line arguments you give are processed
+in sequential order. The order makes a difference when the
+`\|\c
+.B \-x\c
+\&\|' option is used.
+
+.TP
+.B \-help
+.TP
+.B \-h
+List all options, with brief explanations.
+
+.TP
+.BI "\-symbols=" "file"\c
+.TP
+.BI "\-s " "file"\c
+\&
+Read symbol table from file \c
+.I file\c
+\&.
+
+.TP
+.BI "\-exec=" "file"\c
+.TP
+.BI "\-e " "file"\c
+\&
+Use file \c
+.I file\c
+\& as the executable file to execute when
+appropriate, and for examining pure data in conjunction with a core
+dump.
+
+.TP
+.BI "\-se=" "file"\c
+\&
+Read symbol table from file \c
+.I file\c
+\& and use it as the executable
+file.
+
+.TP
+.BI "\-core=" "file"\c
+.TP
+.BI "\-c " "file"\c
+\&
+Use file \c
+.I file\c
+\& as a core dump to examine.
+
+.TP
+.BI "\-command=" "file"\c
+.TP
+.BI "\-x " "file"\c
+\&
+Execute GDB commands from file \c
+.I file\c
+\&.
+
+.TP
+.BI "\-directory=" "directory"\c
+.TP
+.BI "\-d " "directory"\c
+\&
+Add \c
+.I directory\c
+\& to the path to search for source files.
+.PP
+
+.TP
+.B \-nx
+.TP
+.B \-n
+Do not execute commands from any `\|\c
+.B .gdbinit\c
+\&\|' initialization files.
+Normally, the commands in these files are executed after all the
+command options and arguments have been processed.
+
+
+.TP
+.B \-quiet
+.TP
+.B \-q
+``Quiet''. Do not print the introductory and copyright messages. These
+messages are also suppressed in batch mode.
+
+.TP
+.B \-kernel
+.TP
+.B \-k
+Puts GDB into kernel debugging mode. If no executable file is specified then
+/kernel is used. If no core file is specified then /dev/mem is
+used. Crash dumps can be examined by specifying both an executable and
+a core file.
+
+.TP
+.B \-wcore
+.TP
+.B \-w
+This flag is only effective when debugging a "live" kernel. It makes the
+core file (/dev/mem) writable so that kernel variables can be changed
+during a debugging session. Use this with caution !
+
+.TP
+.B \-batch
+Run in batch mode. Exit with status \c
+.B 0\c
+\& after processing all the command
+files specified with `\|\c
+.B \-x\c
+\&\|' (and `\|\c
+.B .gdbinit\c
+\&\|', if not inhibited).
+Exit with nonzero status if an error occurs in executing the GDB
+commands in the command files.
+
+Batch mode may be useful for running GDB as a filter, for example to
+download and run a program on another computer; in order to make this
+more useful, the message
+.sp
+.br
+Program\ exited\ normally.
+.br
+.sp
+
+(which is ordinarily issued whenever a program running under GDB control
+terminates) is not issued when running in batch mode.
+
+.TP
+.BI "\-cd=" "directory"\c
+\&
+Run GDB using \c
+.I directory\c
+\& as its working directory,
+instead of the current directory.
+
+.TP
+.B \-fullname
+.TP
+.B \-f
+Emacs sets this option when it runs GDB as a subprocess. It tells GDB
+to output the full file name and line number in a standard,
+recognizable fashion each time a stack frame is displayed (which
+includes each time the program stops). This recognizable format looks
+like two `\|\c
+.B \032\c
+\&\|' characters, followed by the file name, line number
+and character position separated by colons, and a newline. The
+Emacs-to-GDB interface program uses the two `\|\c
+.B \032\c
+\&\|' characters as
+a signal to display the source code for the frame.
+
+.TP
+.BI "\-b " "bps"\c
+\&
+Set the line speed (baud rate or bits per second) of any serial
+interface used by GDB for remote debugging.
+
+.TP
+.BI "\-tty=" "device"\c
+\&
+Run using \c
+.I device\c
+\& for your program's standard input and output.
+.PP
+
+.SH "SEE ALSO"
+.RB "`\|" gdb "\|'"
+entry in
+.B info\c
+\&;
+.I
+Using GDB: A Guide to the GNU Source-Level Debugger\c
+, Richard M. Stallman and Roland H. Pesch, July 1991.
+.SH COPYING
+Copyright (c) 1991 Free Software Foundation, Inc.
+.PP
+Permission is granted to make and distribute verbatim copies of
+this manual provided the copyright notice and this permission notice
+are preserved on all copies.
+.PP
+Permission is granted to copy and distribute modified versions of this
+manual under the conditions for verbatim copying, provided that the
+entire resulting derived work is distributed under the terms of a
+permission notice identical to this one.
+.PP
+Permission is granted to copy and distribute translations of this
+manual into another language, under the above conditions for modified
+versions, except that this permission notice may be included in
+translations approved by the Free Software Foundation instead of in
+the original English.
diff --git a/gnu/usr.bin/gdb/gdb/gdbcmd.h b/gnu/usr.bin/gdb/gdb/gdbcmd.h
new file mode 100644
index 0000000..88f323c
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/gdbcmd.h
@@ -0,0 +1,101 @@
+/* Header file for GDB-specific command-line stuff.
+ Copyright 1986, 1989, 1990, 1992 Free Software Foundation, Inc.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#if !defined (GDBCMD_H)
+#define GDBCMD_H 1
+
+#include "command.h"
+
+/* Chain containing all defined commands. */
+
+extern struct cmd_list_element *cmdlist;
+
+/* Chain containing all defined info subcommands. */
+
+extern struct cmd_list_element *infolist;
+
+/* Chain containing all defined enable subcommands. */
+
+extern struct cmd_list_element *enablelist;
+
+/* Chain containing all defined disable subcommands. */
+
+extern struct cmd_list_element *disablelist;
+
+/* Chain containing all defined delete subcommands. */
+
+extern struct cmd_list_element *deletelist;
+
+/* Chain containing all defined "enable breakpoint" subcommands. */
+
+extern struct cmd_list_element *enablebreaklist;
+
+/* Chain containing all defined set subcommands */
+
+extern struct cmd_list_element *setlist;
+
+/* Chain containing all defined unset subcommands */
+
+extern struct cmd_list_element *unsetlist;
+
+/* Chain containing all defined show subcommands. */
+
+extern struct cmd_list_element *showlist;
+
+/* Chain containing all defined \"set history\". */
+
+extern struct cmd_list_element *sethistlist;
+
+/* Chain containing all defined \"show history\". */
+
+extern struct cmd_list_element *showhistlist;
+
+/* Chain containing all defined \"unset history\". */
+
+extern struct cmd_list_element *unsethistlist;
+
+/* Chain containing all defined maintenance subcommands. */
+
+extern struct cmd_list_element *maintenancelist;
+
+/* Chain containing all defined "maintenance info" subcommands. */
+
+extern struct cmd_list_element *maintenanceinfolist;
+
+/* Chain containing all defined "maintenance print" subcommands. */
+
+extern struct cmd_list_element *maintenanceprintlist;
+
+extern struct cmd_list_element *setprintlist;
+
+extern struct cmd_list_element *showprintlist;
+
+extern struct cmd_list_element *setchecklist;
+
+extern struct cmd_list_element *showchecklist;
+
+extern void
+execute_user_command PARAMS ((struct cmd_list_element *, char *));
+
+extern void
+execute_command PARAMS ((char *, int));
+
+extern char **noop_completer PARAMS ((char *, char *));
+
+extern char **filename_completer PARAMS ((char *, char *));
+
+#endif /* !defined (GDBCMD_H) */
diff --git a/gnu/usr.bin/gdb/gdb/gdbcore.h b/gnu/usr.bin/gdb/gdb/gdbcore.h
new file mode 100644
index 0000000..595e20c
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/gdbcore.h
@@ -0,0 +1,139 @@
+/* Machine independent variables that describe the core file under GDB.
+ Copyright 1986, 1987, 1989, 1990, 1992 Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* Interface routines for core, executable, etc. */
+
+#if !defined (GDBCORE_H)
+#define GDBCORE_H 1
+
+#include "bfd.h" /* Binary File Description */
+
+/* Return the name of the executable file as a string.
+ ERR nonzero means get error if there is none specified;
+ otherwise return 0 in that case. */
+
+extern char *
+get_exec_file PARAMS ((int err));
+
+/* Nonzero if there is a core file. */
+
+extern int
+have_core_file_p PARAMS ((void));
+
+/* Read "memory data" from whatever target or inferior we have.
+ Returns zero if successful, errno value if not. EIO is used
+ for address out of bounds. If breakpoints are inserted, returns
+ shadow contents, not the breakpoints themselves. From breakpoint.c. */
+
+extern int
+read_memory_nobpt PARAMS ((CORE_ADDR memaddr, char *myaddr, unsigned len));
+
+/* Report a memory error with error(). */
+
+extern void
+memory_error PARAMS ((int status, CORE_ADDR memaddr));
+
+/* Like target_read_memory, but report an error if can't read. */
+
+extern void
+read_memory PARAMS ((CORE_ADDR memaddr, char *myaddr, int len));
+
+/* Read an integer from debugged memory, given address and number of bytes. */
+
+extern LONGEST
+read_memory_integer PARAMS ((CORE_ADDR memaddr, int len));
+
+/* Read an unsigned integer from debugged memory, given address and number of bytes. */
+
+extern unsigned LONGEST
+read_memory_unsigned_integer PARAMS ((CORE_ADDR memaddr, int len));
+
+/* This takes a char *, not void *. This is probably right, because
+ passing in an int * or whatever is wrong with respect to
+ byteswapping, alignment, different sizes for host vs. target types,
+ etc. */
+
+extern void write_memory PARAMS ((CORE_ADDR memaddr, char *myaddr, int len));
+
+extern void generic_search PARAMS ((int len, char *data, char *mask,
+ CORE_ADDR startaddr, int increment,
+ CORE_ADDR lorange, CORE_ADDR hirange,
+ CORE_ADDR *addr_found, char *data_found));
+
+/* Hook for `exec_file_command' command to call. */
+
+extern void (*exec_file_display_hook) PARAMS ((char *filename));
+
+extern void
+specify_exec_file_hook PARAMS ((void (*hook) (char *filename)));
+
+/* Binary File Diddlers for the exec and core files */
+extern bfd *core_bfd;
+extern bfd *exec_bfd;
+
+/* Whether to open exec and core files read-only or read-write. */
+
+extern int write_files;
+
+extern void
+core_file_command PARAMS ((char *filename, int from_tty));
+
+extern void
+exec_file_command PARAMS ((char *filename, int from_tty));
+
+extern void
+validate_files PARAMS ((void));
+
+extern unsigned int
+register_addr PARAMS ((int regno, int blockend));
+
+extern int
+xfer_core_file PARAMS ((CORE_ADDR memaddr, char *myaddr, int len));
+
+extern void
+fetch_core_registers PARAMS ((char *core_reg_sect, unsigned core_reg_size,
+ int which, unsigned int reg_addr));
+
+extern void
+registers_fetched PARAMS ((void));
+
+#if !defined (KERNEL_U_ADDR)
+extern CORE_ADDR kernel_u_addr;
+#define KERNEL_U_ADDR kernel_u_addr
+#endif
+
+/* The target vector for core files */
+extern struct target_ops core_ops;
+#ifdef KERNEL_DEBUG
+extern struct target_ops kcore_ops;
+#endif
+
+ /* target vector functions called directly from elsewhere */
+void
+core_open PARAMS ((char *, int));
+
+void
+core_detach PARAMS ((char *, int));
+
+/* The current default bfd target. */
+extern char *gnutarget;
+
+extern void set_gnutarget PARAMS ((char *));
+
+#endif /* !defined (GDBCORE_H) */
diff --git a/gnu/usr.bin/gdb/gdb/gdbm.h b/gnu/usr.bin/gdb/gdb/gdbm.h
new file mode 100644
index 0000000..5d244a3
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/gdbm.h
@@ -0,0 +1,91 @@
+/* GNU DBM - DataBase Manager include file
+ Copyright 1989, 1991 Free Software Foundation, Inc.
+ Written by Philip A. Nelson.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* You may contact the author by:
+ e-mail: phil@wwu.edu
+ us-mail: Philip A. Nelson
+ Computer Science Department
+ Western Washington University
+ Bellingham, WA 98226
+ phone: (206) 676-3035
+
+*************************************************************************/
+
+/* Parameters to gdbm_open for READERS, WRITERS, and WRITERS who
+ can create the database. */
+#define GDBM_READER 0
+#define GDBM_WRITER 1
+#define GDBM_WRCREAT 2
+#define GDBM_NEWDB 3
+
+/* Parameters to gdbm_store for simple insertion or replacement. */
+#define GDBM_INSERT 0
+#define GDBM_REPLACE 1
+
+
+/* The data and key structure. This structure is defined for compatibility. */
+typedef struct {
+ char *dptr;
+ int dsize;
+ } datum;
+
+
+/* The file information header. This is good enough for most applications. */
+typedef struct {int dummy[10];} *GDBM_FILE;
+
+
+/* These are the routines! */
+
+extern GDBM_FILE gdbm_open ();
+
+extern void gdbm_close ();
+
+extern datum gdbm_fetch ();
+
+extern int gdbm_store ();
+
+extern int gdbm_delete ();
+
+extern datum gdbm_firstkey ();
+
+extern datum gdbm_nextkey ();
+
+extern int gdbm_reorganize ();
+
+
+/* gdbm sends back the following error codes in the variable gdbm_errno. */
+typedef enum { NO_ERROR,
+ MALLOC_ERROR,
+ BLOCK_SIZE_ERROR,
+ FILE_OPEN_ERROR,
+ FILE_WRITE_ERROR,
+ FILE_SEEK_ERROR,
+ FILE_READ_ERROR,
+ BAD_MAGIC_NUMBER,
+ EMPTY_DATABASE,
+ CANT_BE_READER,
+ CANT_BE_WRITER,
+ READER_CANT_RECOVER,
+ READER_CANT_DELETE,
+ READER_CANT_STORE,
+ READER_CANT_REORGANIZE,
+ UNKNOWN_UPDATE,
+ ITEM_NOT_FOUND,
+ REORGANIZE_FAILED,
+ CANNOT_REPLACE}
+ gdbm_error;
diff --git a/gnu/usr.bin/gdb/gdb/gdbtypes.c b/gnu/usr.bin/gdb/gdb/gdbtypes.c
new file mode 100644
index 0000000..36857be
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/gdbtypes.c
@@ -0,0 +1,1581 @@
+/* Support routines for manipulating internal types for GDB.
+ Copyright (C) 1992 Free Software Foundation, Inc.
+ Contributed by Cygnus Support, using pieces from other GDB modules.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "defs.h"
+#include <string.h>
+#include "bfd.h"
+#include "symtab.h"
+#include "symfile.h"
+#include "objfiles.h"
+#include "gdbtypes.h"
+#include "expression.h"
+#include "language.h"
+#include "target.h"
+#include "value.h"
+#include "demangle.h"
+#include "complaints.h"
+
+/* These variables point to the objects
+ representing the predefined C data types. */
+
+struct type *builtin_type_void;
+struct type *builtin_type_char;
+struct type *builtin_type_short;
+struct type *builtin_type_int;
+struct type *builtin_type_long;
+struct type *builtin_type_long_long;
+struct type *builtin_type_signed_char;
+struct type *builtin_type_unsigned_char;
+struct type *builtin_type_unsigned_short;
+struct type *builtin_type_unsigned_int;
+struct type *builtin_type_unsigned_long;
+struct type *builtin_type_unsigned_long_long;
+struct type *builtin_type_float;
+struct type *builtin_type_double;
+struct type *builtin_type_long_double;
+struct type *builtin_type_complex;
+struct type *builtin_type_double_complex;
+struct type *builtin_type_string;
+
+/* Alloc a new type structure and fill it with some defaults. If
+ OBJFILE is non-NULL, then allocate the space for the type structure
+ in that objfile's type_obstack. */
+
+struct type *
+alloc_type (objfile)
+ struct objfile *objfile;
+{
+ register struct type *type;
+
+ /* Alloc the structure and start off with all fields zeroed. */
+
+ if (objfile == NULL)
+ {
+ type = (struct type *) xmalloc (sizeof (struct type));
+ }
+ else
+ {
+ type = (struct type *) obstack_alloc (&objfile -> type_obstack,
+ sizeof (struct type));
+ }
+ memset ((char *) type, 0, sizeof (struct type));
+
+ /* Initialize the fields that might not be zero. */
+
+ TYPE_CODE (type) = TYPE_CODE_UNDEF;
+ TYPE_OBJFILE (type) = objfile;
+ TYPE_VPTR_FIELDNO (type) = -1;
+
+ return (type);
+}
+
+/* Lookup a pointer to a type TYPE. TYPEPTR, if nonzero, points
+ to a pointer to memory where the pointer type should be stored.
+ If *TYPEPTR is zero, update it to point to the pointer type we return.
+ We allocate new memory if needed. */
+
+struct type *
+make_pointer_type (type, typeptr)
+ struct type *type;
+ struct type **typeptr;
+{
+ register struct type *ntype; /* New type */
+ struct objfile *objfile;
+
+ ntype = TYPE_POINTER_TYPE (type);
+
+ if (ntype)
+ if (typeptr == 0)
+ return ntype; /* Don't care about alloc, and have new type. */
+ else if (*typeptr == 0)
+ {
+ *typeptr = ntype; /* Tracking alloc, and we have new type. */
+ return ntype;
+ }
+
+ if (typeptr == 0 || *typeptr == 0) /* We'll need to allocate one. */
+ {
+ ntype = alloc_type (TYPE_OBJFILE (type));
+ if (typeptr)
+ *typeptr = ntype;
+ }
+ else /* We have storage, but need to reset it. */
+ {
+ ntype = *typeptr;
+ objfile = TYPE_OBJFILE (ntype);
+ memset ((char *) ntype, 0, sizeof (struct type));
+ TYPE_OBJFILE (ntype) = objfile;
+ }
+
+ TYPE_TARGET_TYPE (ntype) = type;
+ TYPE_POINTER_TYPE (type) = ntype;
+
+ /* FIXME! Assume the machine has only one representation for pointers! */
+
+ TYPE_LENGTH (ntype) = TARGET_PTR_BIT / TARGET_CHAR_BIT;
+ TYPE_CODE (ntype) = TYPE_CODE_PTR;
+
+ /* pointers are unsigned */
+ TYPE_FLAGS (ntype) |= TYPE_FLAG_UNSIGNED;
+
+ if (!TYPE_POINTER_TYPE (type)) /* Remember it, if don't have one. */
+ TYPE_POINTER_TYPE (type) = ntype;
+
+ return ntype;
+}
+
+/* Given a type TYPE, return a type of pointers to that type.
+ May need to construct such a type if this is the first use. */
+
+struct type *
+lookup_pointer_type (type)
+ struct type *type;
+{
+ return make_pointer_type (type, (struct type **)0);
+}
+
+/* Lookup a C++ `reference' to a type TYPE. TYPEPTR, if nonzero, points
+ to a pointer to memory where the reference type should be stored.
+ If *TYPEPTR is zero, update it to point to the reference type we return.
+ We allocate new memory if needed. */
+
+struct type *
+make_reference_type (type, typeptr)
+ struct type *type;
+ struct type **typeptr;
+{
+ register struct type *ntype; /* New type */
+ struct objfile *objfile;
+
+ ntype = TYPE_REFERENCE_TYPE (type);
+
+ if (ntype)
+ if (typeptr == 0)
+ return ntype; /* Don't care about alloc, and have new type. */
+ else if (*typeptr == 0)
+ {
+ *typeptr = ntype; /* Tracking alloc, and we have new type. */
+ return ntype;
+ }
+
+ if (typeptr == 0 || *typeptr == 0) /* We'll need to allocate one. */
+ {
+ ntype = alloc_type (TYPE_OBJFILE (type));
+ if (typeptr)
+ *typeptr = ntype;
+ }
+ else /* We have storage, but need to reset it. */
+ {
+ ntype = *typeptr;
+ objfile = TYPE_OBJFILE (ntype);
+ memset ((char *) ntype, 0, sizeof (struct type));
+ TYPE_OBJFILE (ntype) = objfile;
+ }
+
+ TYPE_TARGET_TYPE (ntype) = type;
+ TYPE_REFERENCE_TYPE (type) = ntype;
+
+ /* FIXME! Assume the machine has only one representation for references,
+ and that it matches the (only) representation for pointers! */
+
+ TYPE_LENGTH (ntype) = TARGET_PTR_BIT / TARGET_CHAR_BIT;
+ TYPE_CODE (ntype) = TYPE_CODE_REF;
+
+ if (!TYPE_REFERENCE_TYPE (type)) /* Remember it, if don't have one. */
+ TYPE_REFERENCE_TYPE (type) = ntype;
+
+ return ntype;
+}
+
+/* Same as above, but caller doesn't care about memory allocation details. */
+
+struct type *
+lookup_reference_type (type)
+ struct type *type;
+{
+ return make_reference_type (type, (struct type **)0);
+}
+
+/* Lookup a function type that returns type TYPE. TYPEPTR, if nonzero, points
+ to a pointer to memory where the function type should be stored.
+ If *TYPEPTR is zero, update it to point to the function type we return.
+ We allocate new memory if needed. */
+
+struct type *
+make_function_type (type, typeptr)
+ struct type *type;
+ struct type **typeptr;
+{
+ register struct type *ntype; /* New type */
+ struct objfile *objfile;
+
+ ntype = TYPE_FUNCTION_TYPE (type);
+
+ if (ntype)
+ if (typeptr == 0)
+ return ntype; /* Don't care about alloc, and have new type. */
+ else if (*typeptr == 0)
+ {
+ *typeptr = ntype; /* Tracking alloc, and we have new type. */
+ return ntype;
+ }
+
+ if (typeptr == 0 || *typeptr == 0) /* We'll need to allocate one. */
+ {
+ ntype = alloc_type (TYPE_OBJFILE (type));
+ if (typeptr)
+ *typeptr = ntype;
+ }
+ else /* We have storage, but need to reset it. */
+ {
+ ntype = *typeptr;
+ objfile = TYPE_OBJFILE (ntype);
+ memset ((char *) ntype, 0, sizeof (struct type));
+ TYPE_OBJFILE (ntype) = objfile;
+ }
+
+ TYPE_TARGET_TYPE (ntype) = type;
+ TYPE_FUNCTION_TYPE (type) = ntype;
+
+ TYPE_LENGTH (ntype) = 1;
+ TYPE_CODE (ntype) = TYPE_CODE_FUNC;
+
+ if (!TYPE_FUNCTION_TYPE (type)) /* Remember it, if don't have one. */
+ TYPE_FUNCTION_TYPE (type) = ntype;
+
+ return ntype;
+}
+
+
+/* Given a type TYPE, return a type of functions that return that type.
+ May need to construct such a type if this is the first use. */
+
+struct type *
+lookup_function_type (type)
+ struct type *type;
+{
+ return make_function_type (type, (struct type **)0);
+}
+
+/* Implement direct support for MEMBER_TYPE in GNU C++.
+ May need to construct such a type if this is the first use.
+ The TYPE is the type of the member. The DOMAIN is the type
+ of the aggregate that the member belongs to. */
+
+struct type *
+lookup_member_type (type, domain)
+ struct type *type;
+ struct type *domain;
+{
+ register struct type *mtype;
+
+ mtype = alloc_type (TYPE_OBJFILE (type));
+ smash_to_member_type (mtype, domain, type);
+ return (mtype);
+}
+
+/* Allocate a stub method whose return type is TYPE.
+ This apparently happens for speed of symbol reading, since parsing
+ out the arguments to the method is cpu-intensive, the way we are doing
+ it. So, we will fill in arguments later.
+ This always returns a fresh type. */
+
+struct type *
+allocate_stub_method (type)
+ struct type *type;
+{
+ struct type *mtype;
+
+ mtype = alloc_type (TYPE_OBJFILE (type));
+ TYPE_TARGET_TYPE (mtype) = type;
+ /* _DOMAIN_TYPE (mtype) = unknown yet */
+ /* _ARG_TYPES (mtype) = unknown yet */
+ TYPE_FLAGS (mtype) = TYPE_FLAG_STUB;
+ TYPE_CODE (mtype) = TYPE_CODE_METHOD;
+ TYPE_LENGTH (mtype) = 1;
+ return (mtype);
+}
+
+/* Create a range type using either a blank type supplied in RESULT_TYPE,
+ or creating a new type, inheriting the objfile from INDEX_TYPE.
+
+ Indices will be of type INDEX_TYPE, and will range from LOW_BOUND to
+ HIGH_BOUND, inclusive.
+
+ FIXME: Maybe we should check the TYPE_CODE of RESULT_TYPE to make
+ sure it is TYPE_CODE_UNDEF before we bash it into a range type? */
+
+struct type *
+create_range_type (result_type, index_type, low_bound, high_bound)
+ struct type *result_type;
+ struct type *index_type;
+ int low_bound;
+ int high_bound;
+{
+ if (result_type == NULL)
+ {
+ result_type = alloc_type (TYPE_OBJFILE (index_type));
+ }
+ TYPE_CODE (result_type) = TYPE_CODE_RANGE;
+ TYPE_TARGET_TYPE (result_type) = index_type;
+ TYPE_LENGTH (result_type) = TYPE_LENGTH (index_type);
+ TYPE_NFIELDS (result_type) = 2;
+ TYPE_FIELDS (result_type) = (struct field *)
+ TYPE_ALLOC (result_type, 2 * sizeof (struct field));
+ memset (TYPE_FIELDS (result_type), 0, 2 * sizeof (struct field));
+ TYPE_FIELD_BITPOS (result_type, 0) = low_bound;
+ TYPE_FIELD_BITPOS (result_type, 1) = high_bound;
+ TYPE_FIELD_TYPE (result_type, 0) = builtin_type_int; /* FIXME */
+ TYPE_FIELD_TYPE (result_type, 1) = builtin_type_int; /* FIXME */
+
+ return (result_type);
+}
+
+/* A lot of code assumes that the "index type" of an array/string/
+ set/bitstring is specifically a range type, though in some languages
+ it can be any discrete type. */
+
+struct type *
+force_to_range_type (type)
+ struct type *type;
+{
+ switch (TYPE_CODE (type))
+ {
+ case TYPE_CODE_RANGE:
+ return type;
+
+ case TYPE_CODE_ENUM:
+ {
+ int low_bound = TYPE_FIELD_BITPOS (type, 0);
+ int high_bound = TYPE_FIELD_BITPOS (type, TYPE_NFIELDS (type) - 1);
+ struct type *range_type =
+ create_range_type (NULL, type, low_bound, high_bound);
+ TYPE_NAME (range_type) = TYPE_NAME (range_type);
+ TYPE_DUMMY_RANGE (range_type) = 1;
+ return range_type;
+ }
+ case TYPE_CODE_BOOL:
+ {
+ struct type *range_type = create_range_type (NULL, type, 0, 1);
+ TYPE_NAME (range_type) = TYPE_NAME (range_type);
+ TYPE_DUMMY_RANGE (range_type) = 1;
+ return range_type;
+ }
+ case TYPE_CODE_CHAR:
+ {
+ struct type *range_type = create_range_type (NULL, type, 0, 255);
+ TYPE_NAME (range_type) = TYPE_NAME (range_type);
+ TYPE_DUMMY_RANGE (range_type) = 1;
+ return range_type;
+ }
+ default:
+ {
+ static struct complaint msg =
+ { "array index type must be a discrete type", 0, 0};
+ complain (&msg);
+
+ return create_range_type (NULL, builtin_type_int, 0, 0);
+ }
+ }
+}
+
+/* Create an array type using either a blank type supplied in RESULT_TYPE,
+ or creating a new type, inheriting the objfile from RANGE_TYPE.
+
+ Elements will be of type ELEMENT_TYPE, the indices will be of type
+ RANGE_TYPE.
+
+ FIXME: Maybe we should check the TYPE_CODE of RESULT_TYPE to make
+ sure it is TYPE_CODE_UNDEF before we bash it into an array type? */
+
+struct type *
+create_array_type (result_type, element_type, range_type)
+ struct type *result_type;
+ struct type *element_type;
+ struct type *range_type;
+{
+ int low_bound;
+ int high_bound;
+
+ range_type = force_to_range_type (range_type);
+ if (result_type == NULL)
+ {
+ result_type = alloc_type (TYPE_OBJFILE (range_type));
+ }
+ TYPE_CODE (result_type) = TYPE_CODE_ARRAY;
+ TYPE_TARGET_TYPE (result_type) = element_type;
+ low_bound = TYPE_LOW_BOUND (range_type);
+ high_bound = TYPE_HIGH_BOUND (range_type);
+ TYPE_LENGTH (result_type) =
+ TYPE_LENGTH (element_type) * (high_bound - low_bound + 1);
+ TYPE_NFIELDS (result_type) = 1;
+ TYPE_FIELDS (result_type) =
+ (struct field *) TYPE_ALLOC (result_type, sizeof (struct field));
+ memset (TYPE_FIELDS (result_type), 0, sizeof (struct field));
+ TYPE_FIELD_TYPE (result_type, 0) = range_type;
+ TYPE_VPTR_FIELDNO (result_type) = -1;
+
+ return (result_type);
+}
+
+/* Create a string type using either a blank type supplied in RESULT_TYPE,
+ or creating a new type. String types are similar enough to array of
+ char types that we can use create_array_type to build the basic type
+ and then bash it into a string type.
+
+ For fixed length strings, the range type contains 0 as the lower
+ bound and the length of the string minus one as the upper bound.
+
+ FIXME: Maybe we should check the TYPE_CODE of RESULT_TYPE to make
+ sure it is TYPE_CODE_UNDEF before we bash it into a string type? */
+
+struct type *
+create_string_type (result_type, range_type)
+ struct type *result_type;
+ struct type *range_type;
+{
+ result_type = create_array_type (result_type, builtin_type_char, range_type);
+ TYPE_CODE (result_type) = TYPE_CODE_STRING;
+ return (result_type);
+}
+
+struct type *
+create_set_type (result_type, domain_type)
+ struct type *result_type;
+ struct type *domain_type;
+{
+ int low_bound, high_bound, bit_length;
+ if (result_type == NULL)
+ {
+ result_type = alloc_type (TYPE_OBJFILE (domain_type));
+ }
+ domain_type = force_to_range_type (domain_type);
+ TYPE_CODE (result_type) = TYPE_CODE_SET;
+ TYPE_NFIELDS (result_type) = 1;
+ TYPE_FIELDS (result_type) = (struct field *)
+ TYPE_ALLOC (result_type, 1 * sizeof (struct field));
+ memset (TYPE_FIELDS (result_type), 0, sizeof (struct field));
+ TYPE_FIELD_TYPE (result_type, 0) = domain_type;
+ low_bound = TYPE_LOW_BOUND (domain_type);
+ high_bound = TYPE_HIGH_BOUND (domain_type);
+ bit_length = high_bound - low_bound + 1;
+ if (bit_length <= TARGET_CHAR_BIT)
+ TYPE_LENGTH (result_type) = 1;
+ else if (bit_length <= TARGET_SHORT_BIT)
+ TYPE_LENGTH (result_type) = TARGET_SHORT_BIT / TARGET_CHAR_BIT;
+ else
+ TYPE_LENGTH (result_type)
+ = ((bit_length + TARGET_INT_BIT - 1) / TARGET_INT_BIT)
+ * TARGET_CHAR_BIT;
+ return (result_type);
+}
+
+/* Smash TYPE to be a type of members of DOMAIN with type TO_TYPE.
+ A MEMBER is a wierd thing -- it amounts to a typed offset into
+ a struct, e.g. "an int at offset 8". A MEMBER TYPE doesn't
+ include the offset (that's the value of the MEMBER itself), but does
+ include the structure type into which it points (for some reason).
+
+ When "smashing" the type, we preserve the objfile that the
+ old type pointed to, since we aren't changing where the type is actually
+ allocated. */
+
+void
+smash_to_member_type (type, domain, to_type)
+ struct type *type;
+ struct type *domain;
+ struct type *to_type;
+{
+ struct objfile *objfile;
+
+ objfile = TYPE_OBJFILE (type);
+
+ memset ((char *) type, 0, sizeof (struct type));
+ TYPE_OBJFILE (type) = objfile;
+ TYPE_TARGET_TYPE (type) = to_type;
+ TYPE_DOMAIN_TYPE (type) = domain;
+ TYPE_LENGTH (type) = 1; /* In practice, this is never needed. */
+ TYPE_CODE (type) = TYPE_CODE_MEMBER;
+}
+
+/* Smash TYPE to be a type of method of DOMAIN with type TO_TYPE.
+ METHOD just means `function that gets an extra "this" argument'.
+
+ When "smashing" the type, we preserve the objfile that the
+ old type pointed to, since we aren't changing where the type is actually
+ allocated. */
+
+void
+smash_to_method_type (type, domain, to_type, args)
+ struct type *type;
+ struct type *domain;
+ struct type *to_type;
+ struct type **args;
+{
+ struct objfile *objfile;
+
+ objfile = TYPE_OBJFILE (type);
+
+ memset ((char *) type, 0, sizeof (struct type));
+ TYPE_OBJFILE (type) = objfile;
+ TYPE_TARGET_TYPE (type) = to_type;
+ TYPE_DOMAIN_TYPE (type) = domain;
+ TYPE_ARG_TYPES (type) = args;
+ TYPE_LENGTH (type) = 1; /* In practice, this is never needed. */
+ TYPE_CODE (type) = TYPE_CODE_METHOD;
+}
+
+/* Return a typename for a struct/union/enum type without "struct ",
+ "union ", or "enum ". If the type has a NULL name, return NULL. */
+
+char *
+type_name_no_tag (type)
+ register const struct type *type;
+{
+ if (TYPE_TAG_NAME (type) != NULL)
+ return TYPE_TAG_NAME (type);
+
+ /* Is there code which expects this to return the name if there is no
+ tag name? My guess is that this is mainly used for C++ in cases where
+ the two will always be the same. */
+ return TYPE_NAME (type);
+}
+
+/* Lookup a primitive type named NAME.
+ Return zero if NAME is not a primitive type.*/
+
+struct type *
+lookup_primitive_typename (name)
+ char *name;
+{
+ struct type ** const *p;
+
+ for (p = current_language -> la_builtin_type_vector; *p != NULL; p++)
+ {
+ if (STREQ ((**p) -> name, name))
+ {
+ return (**p);
+ }
+ }
+ return (NULL);
+}
+
+/* Lookup a typedef or primitive type named NAME,
+ visible in lexical block BLOCK.
+ If NOERR is nonzero, return zero if NAME is not suitably defined. */
+
+struct type *
+lookup_typename (name, block, noerr)
+ char *name;
+ struct block *block;
+ int noerr;
+{
+ register struct symbol *sym;
+ register struct type *tmp;
+
+ sym = lookup_symbol (name, block, VAR_NAMESPACE, 0, (struct symtab **) NULL);
+ if (sym == NULL || SYMBOL_CLASS (sym) != LOC_TYPEDEF)
+ {
+ tmp = lookup_primitive_typename (name);
+ if (tmp)
+ {
+ return (tmp);
+ }
+ else if (!tmp && noerr)
+ {
+ return (NULL);
+ }
+ else
+ {
+ error ("No type named %s.", name);
+ }
+ }
+ return (SYMBOL_TYPE (sym));
+}
+
+struct type *
+lookup_unsigned_typename (name)
+ char *name;
+{
+ char *uns = alloca (strlen (name) + 10);
+
+ strcpy (uns, "unsigned ");
+ strcpy (uns + 9, name);
+ return (lookup_typename (uns, (struct block *) NULL, 0));
+}
+
+struct type *
+lookup_signed_typename (name)
+ char *name;
+{
+ struct type *t;
+ char *uns = alloca (strlen (name) + 8);
+
+ strcpy (uns, "signed ");
+ strcpy (uns + 7, name);
+ t = lookup_typename (uns, (struct block *) NULL, 1);
+ /* If we don't find "signed FOO" just try again with plain "FOO". */
+ if (t != NULL)
+ return t;
+ return lookup_typename (name, (struct block *) NULL, 0);
+}
+
+/* Lookup a structure type named "struct NAME",
+ visible in lexical block BLOCK. */
+
+struct type *
+lookup_struct (name, block)
+ char *name;
+ struct block *block;
+{
+ register struct symbol *sym;
+
+ sym = lookup_symbol (name, block, STRUCT_NAMESPACE, 0,
+ (struct symtab **) NULL);
+
+ if (sym == NULL)
+ {
+ error ("No struct type named %s.", name);
+ }
+ if (TYPE_CODE (SYMBOL_TYPE (sym)) != TYPE_CODE_STRUCT)
+ {
+ error ("This context has class, union or enum %s, not a struct.", name);
+ }
+ return (SYMBOL_TYPE (sym));
+}
+
+/* Lookup a union type named "union NAME",
+ visible in lexical block BLOCK. */
+
+struct type *
+lookup_union (name, block)
+ char *name;
+ struct block *block;
+{
+ register struct symbol *sym;
+
+ sym = lookup_symbol (name, block, STRUCT_NAMESPACE, 0,
+ (struct symtab **) NULL);
+
+ if (sym == NULL)
+ {
+ error ("No union type named %s.", name);
+ }
+ if (TYPE_CODE (SYMBOL_TYPE (sym)) != TYPE_CODE_UNION)
+ {
+ error ("This context has class, struct or enum %s, not a union.", name);
+ }
+ return (SYMBOL_TYPE (sym));
+}
+
+/* Lookup an enum type named "enum NAME",
+ visible in lexical block BLOCK. */
+
+struct type *
+lookup_enum (name, block)
+ char *name;
+ struct block *block;
+{
+ register struct symbol *sym;
+
+ sym = lookup_symbol (name, block, STRUCT_NAMESPACE, 0,
+ (struct symtab **) NULL);
+ if (sym == NULL)
+ {
+ error ("No enum type named %s.", name);
+ }
+ if (TYPE_CODE (SYMBOL_TYPE (sym)) != TYPE_CODE_ENUM)
+ {
+ error ("This context has class, struct or union %s, not an enum.", name);
+ }
+ return (SYMBOL_TYPE (sym));
+}
+
+/* Lookup a template type named "template NAME<TYPE>",
+ visible in lexical block BLOCK. */
+
+struct type *
+lookup_template_type (name, type, block)
+ char *name;
+ struct type *type;
+ struct block *block;
+{
+ struct symbol *sym;
+ char *nam = (char*) alloca(strlen(name) + strlen(type->name) + 4);
+ strcpy (nam, name);
+ strcat (nam, "<");
+ strcat (nam, type->name);
+ strcat (nam, " >"); /* FIXME, extra space still introduced in gcc? */
+
+ sym = lookup_symbol (nam, block, VAR_NAMESPACE, 0, (struct symtab **)NULL);
+
+ if (sym == NULL)
+ {
+ error ("No template type named %s.", name);
+ }
+ if (TYPE_CODE (SYMBOL_TYPE (sym)) != TYPE_CODE_STRUCT)
+ {
+ error ("This context has class, union or enum %s, not a struct.", name);
+ }
+ return (SYMBOL_TYPE (sym));
+}
+
+/* Given a type TYPE, lookup the type of the component of type named NAME.
+
+ TYPE can be either a struct or union, or a pointer or reference to a struct or
+ union. If it is a pointer or reference, its target type is automatically used.
+ Thus '.' and '->' are interchangable, as specified for the definitions of the
+ expression element types STRUCTOP_STRUCT and STRUCTOP_PTR.
+
+ If NOERR is nonzero, return zero if NAME is not suitably defined.
+ If NAME is the name of a baseclass type, return that type. */
+
+struct type *
+lookup_struct_elt_type (type, name, noerr)
+ struct type *type;
+ char *name;
+ int noerr;
+{
+ int i;
+
+ while (TYPE_CODE (type) == TYPE_CODE_PTR ||
+ TYPE_CODE (type) == TYPE_CODE_REF)
+ type = TYPE_TARGET_TYPE (type);
+
+ if (TYPE_CODE (type) != TYPE_CODE_STRUCT &&
+ TYPE_CODE (type) != TYPE_CODE_UNION)
+ {
+ target_terminal_ours ();
+ gdb_flush (gdb_stdout);
+ fprintf_unfiltered (gdb_stderr, "Type ");
+ type_print (type, "", gdb_stderr, -1);
+ error (" is not a structure or union type.");
+ }
+
+ check_stub_type (type);
+
+#if 0
+ /* FIXME: This change put in by Michael seems incorrect for the case where
+ the structure tag name is the same as the member name. I.E. when doing
+ "ptype bell->bar" for "struct foo { int bar; int foo; } bell;"
+ Disabled by fnf. */
+ {
+ char *typename;
+
+ typename = type_name_no_tag (type);
+ if (typename != NULL && STREQ (typename, name))
+ return type;
+ }
+#endif
+
+ for (i = TYPE_NFIELDS (type) - 1; i >= TYPE_N_BASECLASSES (type); i--)
+ {
+ char *t_field_name = TYPE_FIELD_NAME (type, i);
+
+ if (t_field_name && STREQ (t_field_name, name))
+ {
+ return TYPE_FIELD_TYPE (type, i);
+ }
+ }
+
+ /* OK, it's not in this class. Recursively check the baseclasses. */
+ for (i = TYPE_N_BASECLASSES (type) - 1; i >= 0; i--)
+ {
+ struct type *t;
+
+ t = lookup_struct_elt_type (TYPE_BASECLASS (type, i), name, noerr);
+ if (t != NULL)
+ {
+ return t;
+ }
+ }
+
+ if (noerr)
+ {
+ return NULL;
+ }
+
+ target_terminal_ours ();
+ gdb_flush (gdb_stdout);
+ fprintf_unfiltered (gdb_stderr, "Type ");
+ type_print (type, "", gdb_stderr, -1);
+ fprintf_unfiltered (gdb_stderr, " has no component named ");
+ fputs_filtered (name, gdb_stderr);
+ error (".");
+ return (struct type *)-1; /* For lint */
+}
+
+/* If possible, make the vptr_fieldno and vptr_basetype fields of TYPE
+ valid. Callers should be aware that in some cases (for example,
+ the type or one of its baseclasses is a stub type and we are
+ debugging a .o file), this function will not be able to find the virtual
+ function table pointer, and vptr_fieldno will remain -1 and vptr_basetype
+ will remain NULL. */
+
+void
+fill_in_vptr_fieldno (type)
+ struct type *type;
+{
+ check_stub_type (type);
+
+ if (TYPE_VPTR_FIELDNO (type) < 0)
+ {
+ int i;
+
+ /* We must start at zero in case the first (and only) baseclass is
+ virtual (and hence we cannot share the table pointer). */
+ for (i = 0; i < TYPE_N_BASECLASSES (type); i++)
+ {
+ fill_in_vptr_fieldno (TYPE_BASECLASS (type, i));
+ if (TYPE_VPTR_FIELDNO (TYPE_BASECLASS (type, i)) >= 0)
+ {
+ TYPE_VPTR_FIELDNO (type)
+ = TYPE_VPTR_FIELDNO (TYPE_BASECLASS (type, i));
+ TYPE_VPTR_BASETYPE (type)
+ = TYPE_VPTR_BASETYPE (TYPE_BASECLASS (type, i));
+ break;
+ }
+ }
+ }
+}
+
+/* Added by Bryan Boreham, Kewill, Sun Sep 17 18:07:17 1989.
+
+ If this is a stubbed struct (i.e. declared as struct foo *), see if
+ we can find a full definition in some other file. If so, copy this
+ definition, so we can use it in future. There used to be a comment (but
+ not any code) that if we don't find a full definition, we'd set a flag
+ so we don't spend time in the future checking the same type. That would
+ be a mistake, though--we might load in more symbols which contain a
+ full definition for the type.
+
+ This used to be coded as a macro, but I don't think it is called
+ often enough to merit such treatment. */
+
+struct complaint stub_noname_complaint =
+ {"stub type has NULL name", 0, 0};
+
+void
+check_stub_type (type)
+ struct type *type;
+{
+ if (TYPE_FLAGS(type) & TYPE_FLAG_STUB)
+ {
+ char* name = type_name_no_tag (type);
+ /* FIXME: shouldn't we separately check the TYPE_NAME and the
+ TYPE_TAG_NAME, and look in STRUCT_NAMESPACE and/or VAR_NAMESPACE
+ as appropriate? (this code was written before TYPE_NAME and
+ TYPE_TAG_NAME were separate). */
+ struct symbol *sym;
+ if (name == NULL)
+ {
+ complain (&stub_noname_complaint);
+ return;
+ }
+ sym = lookup_symbol (name, 0, STRUCT_NAMESPACE, 0,
+ (struct symtab **) NULL);
+ if (sym)
+ {
+ memcpy ((char *)type,
+ (char *)SYMBOL_TYPE(sym),
+ sizeof (struct type));
+ }
+ }
+
+ if (TYPE_FLAGS (type) & TYPE_FLAG_TARGET_STUB)
+ {
+ struct type *range_type;
+
+ check_stub_type (TYPE_TARGET_TYPE (type));
+ if (!(TYPE_FLAGS (TYPE_TARGET_TYPE (type)) & TYPE_FLAG_STUB)
+ && TYPE_CODE (type) == TYPE_CODE_ARRAY
+ && TYPE_NFIELDS (type) == 1
+ && (TYPE_CODE (range_type = TYPE_FIELD_TYPE (type, 0))
+ == TYPE_CODE_RANGE))
+ {
+ /* Now recompute the length of the array type, based on its
+ number of elements and the target type's length. */
+ TYPE_LENGTH (type) =
+ ((TYPE_FIELD_BITPOS (range_type, 1)
+ - TYPE_FIELD_BITPOS (range_type, 0)
+ + 1)
+ * TYPE_LENGTH (TYPE_TARGET_TYPE (type)));
+ TYPE_FLAGS (type) &= ~TYPE_FLAG_TARGET_STUB;
+ }
+ }
+}
+
+/* Ugly hack to convert method stubs into method types.
+
+ He ain't kiddin'. This demangles the name of the method into a string
+ including argument types, parses out each argument type, generates
+ a string casting a zero to that type, evaluates the string, and stuffs
+ the resulting type into an argtype vector!!! Then it knows the type
+ of the whole function (including argument types for overloading),
+ which info used to be in the stab's but was removed to hack back
+ the space required for them. */
+
+void
+check_stub_method (type, i, j)
+ struct type *type;
+ int i;
+ int j;
+{
+ struct fn_field *f;
+ char *mangled_name = gdb_mangle_name (type, i, j);
+ char *demangled_name = cplus_demangle (mangled_name,
+ DMGL_PARAMS | DMGL_ANSI);
+ char *argtypetext, *p;
+ int depth = 0, argcount = 1;
+ struct type **argtypes;
+ struct type *mtype;
+
+ if (demangled_name == NULL)
+ {
+ error ("Internal: Cannot demangle mangled name `%s'.", mangled_name);
+ }
+
+ /* Now, read in the parameters that define this type. */
+ argtypetext = strchr (demangled_name, '(') + 1;
+ p = argtypetext;
+ while (*p)
+ {
+ if (*p == '(')
+ {
+ depth += 1;
+ }
+ else if (*p == ')')
+ {
+ depth -= 1;
+ }
+ else if (*p == ',' && depth == 0)
+ {
+ argcount += 1;
+ }
+
+ p += 1;
+ }
+
+ /* We need two more slots: one for the THIS pointer, and one for the
+ NULL [...] or void [end of arglist]. */
+
+ argtypes = (struct type **)
+ TYPE_ALLOC (type, (argcount + 2) * sizeof (struct type *));
+ p = argtypetext;
+ /* FIXME: This is wrong for static member functions. */
+ argtypes[0] = lookup_pointer_type (type);
+ argcount = 1;
+
+ if (*p != ')') /* () means no args, skip while */
+ {
+ depth = 0;
+ while (*p)
+ {
+ if (depth <= 0 && (*p == ',' || *p == ')'))
+ {
+ /* Avoid parsing of ellipsis, they will be handled below. */
+ if (strncmp (argtypetext, "...", p - argtypetext) != 0)
+ {
+ argtypes[argcount] =
+ parse_and_eval_type (argtypetext, p - argtypetext);
+ argcount += 1;
+ }
+ argtypetext = p + 1;
+ }
+
+ if (*p == '(')
+ {
+ depth += 1;
+ }
+ else if (*p == ')')
+ {
+ depth -= 1;
+ }
+
+ p += 1;
+ }
+ }
+
+ if (p[-2] != '.') /* Not '...' */
+ {
+ argtypes[argcount] = builtin_type_void; /* List terminator */
+ }
+ else
+ {
+ argtypes[argcount] = NULL; /* Ellist terminator */
+ }
+
+ free (demangled_name);
+
+ f = TYPE_FN_FIELDLIST1 (type, i);
+ TYPE_FN_FIELD_PHYSNAME (f, j) = mangled_name;
+
+ /* Now update the old "stub" type into a real type. */
+ mtype = TYPE_FN_FIELD_TYPE (f, j);
+ TYPE_DOMAIN_TYPE (mtype) = type;
+ TYPE_ARG_TYPES (mtype) = argtypes;
+ TYPE_FLAGS (mtype) &= ~TYPE_FLAG_STUB;
+ TYPE_FN_FIELD_STUB (f, j) = 0;
+}
+
+const struct cplus_struct_type cplus_struct_default;
+
+void
+allocate_cplus_struct_type (type)
+ struct type *type;
+{
+ if (!HAVE_CPLUS_STRUCT (type))
+ {
+ TYPE_CPLUS_SPECIFIC (type) = (struct cplus_struct_type *)
+ TYPE_ALLOC (type, sizeof (struct cplus_struct_type));
+ *(TYPE_CPLUS_SPECIFIC(type)) = cplus_struct_default;
+ }
+}
+
+/* Helper function to initialize the standard scalar types.
+
+ If NAME is non-NULL and OBJFILE is non-NULL, then we make a copy
+ of the string pointed to by name in the type_obstack for that objfile,
+ and initialize the type name to that copy. There are places (mipsread.c
+ in particular, where init_type is called with a NULL value for NAME). */
+
+struct type *
+init_type (code, length, flags, name, objfile)
+ enum type_code code;
+ int length;
+ int flags;
+ char *name;
+ struct objfile *objfile;
+{
+ register struct type *type;
+
+ type = alloc_type (objfile);
+ TYPE_CODE (type) = code;
+ TYPE_LENGTH (type) = length;
+ TYPE_FLAGS (type) |= flags;
+ if ((name != NULL) && (objfile != NULL))
+ {
+ TYPE_NAME (type) =
+ obsavestring (name, strlen (name), &objfile -> type_obstack);
+ }
+ else
+ {
+ TYPE_NAME (type) = name;
+ }
+
+ /* C++ fancies. */
+
+ if (code == TYPE_CODE_STRUCT || code == TYPE_CODE_UNION)
+ {
+ INIT_CPLUS_SPECIFIC (type);
+ }
+ return (type);
+}
+
+/* Look up a fundamental type for the specified objfile.
+ May need to construct such a type if this is the first use.
+
+ Some object file formats (ELF, COFF, etc) do not define fundamental
+ types such as "int" or "double". Others (stabs for example), do
+ define fundamental types.
+
+ For the formats which don't provide fundamental types, gdb can create
+ such types, using defaults reasonable for the current language and
+ the current target machine.
+
+ NOTE: This routine is obsolescent. Each debugging format reader
+ should manage it's own fundamental types, either creating them from
+ suitable defaults or reading them from the debugging information,
+ whichever is appropriate. The DWARF reader has already been
+ fixed to do this. Once the other readers are fixed, this routine
+ will go away. Also note that fundamental types should be managed
+ on a compilation unit basis in a multi-language environment, not
+ on a linkage unit basis as is done here. */
+
+
+struct type *
+lookup_fundamental_type (objfile, typeid)
+ struct objfile *objfile;
+ int typeid;
+{
+ register struct type **typep;
+ register int nbytes;
+
+ if (typeid < 0 || typeid >= FT_NUM_MEMBERS)
+ {
+ error ("internal error - invalid fundamental type id %d", typeid);
+ }
+
+ /* If this is the first time we need a fundamental type for this objfile
+ then we need to initialize the vector of type pointers. */
+
+ if (objfile -> fundamental_types == NULL)
+ {
+ nbytes = FT_NUM_MEMBERS * sizeof (struct type *);
+ objfile -> fundamental_types = (struct type **)
+ obstack_alloc (&objfile -> type_obstack, nbytes);
+ memset ((char *) objfile -> fundamental_types, 0, nbytes);
+ }
+
+ /* Look for this particular type in the fundamental type vector. If one is
+ not found, create and install one appropriate for the current language. */
+
+ typep = objfile -> fundamental_types + typeid;
+ if (*typep == NULL)
+ {
+ *typep = create_fundamental_type (objfile, typeid);
+ }
+
+ return (*typep);
+}
+
+int
+can_dereference (t)
+ struct type *t;
+{
+ /* FIXME: Should we return true for references as well as pointers? */
+ return
+ (t != NULL
+ && TYPE_CODE (t) == TYPE_CODE_PTR
+ && TYPE_CODE (TYPE_TARGET_TYPE (t)) != TYPE_CODE_VOID);
+}
+
+#if MAINTENANCE_CMDS
+
+static void
+print_bit_vector (bits, nbits)
+ B_TYPE *bits;
+ int nbits;
+{
+ int bitno;
+
+ for (bitno = 0; bitno < nbits; bitno++)
+ {
+ if ((bitno % 8) == 0)
+ {
+ puts_filtered (" ");
+ }
+ if (B_TST (bits, bitno))
+ {
+ printf_filtered ("1");
+ }
+ else
+ {
+ printf_filtered ("0");
+ }
+ }
+}
+
+/* The args list is a strange beast. It is either terminated by a NULL
+ pointer for varargs functions, or by a pointer to a TYPE_CODE_VOID
+ type for normal fixed argcount functions. (FIXME someday)
+ Also note the first arg should be the "this" pointer, we may not want to
+ include it since we may get into a infinitely recursive situation. */
+
+static void
+print_arg_types (args, spaces)
+ struct type **args;
+ int spaces;
+{
+ if (args != NULL)
+ {
+ while (*args != NULL)
+ {
+ recursive_dump_type (*args, spaces + 2);
+ if ((*args++) -> code == TYPE_CODE_VOID)
+ {
+ break;
+ }
+ }
+ }
+}
+
+static void
+dump_fn_fieldlists (type, spaces)
+ struct type *type;
+ int spaces;
+{
+ int method_idx;
+ int overload_idx;
+ struct fn_field *f;
+
+ printfi_filtered (spaces, "fn_fieldlists ");
+ gdb_print_address (TYPE_FN_FIELDLISTS (type), gdb_stdout);
+ printf_filtered ("\n");
+ for (method_idx = 0; method_idx < TYPE_NFN_FIELDS (type); method_idx++)
+ {
+ f = TYPE_FN_FIELDLIST1 (type, method_idx);
+ printfi_filtered (spaces + 2, "[%d] name '%s' (",
+ method_idx,
+ TYPE_FN_FIELDLIST_NAME (type, method_idx));
+ gdb_print_address (TYPE_FN_FIELDLIST_NAME (type, method_idx),
+ gdb_stdout);
+ printf_filtered (") length %d\n",
+ TYPE_FN_FIELDLIST_LENGTH (type, method_idx));
+ for (overload_idx = 0;
+ overload_idx < TYPE_FN_FIELDLIST_LENGTH (type, method_idx);
+ overload_idx++)
+ {
+ printfi_filtered (spaces + 4, "[%d] physname '%s' (",
+ overload_idx,
+ TYPE_FN_FIELD_PHYSNAME (f, overload_idx));
+ gdb_print_address (TYPE_FN_FIELD_PHYSNAME (f, overload_idx),
+ gdb_stdout);
+ printf_filtered (")\n");
+ printfi_filtered (spaces + 8, "type ");
+ gdb_print_address (TYPE_FN_FIELD_TYPE (f, overload_idx), gdb_stdout);
+ printf_filtered ("\n");
+
+ recursive_dump_type (TYPE_FN_FIELD_TYPE (f, overload_idx),
+ spaces + 8 + 2);
+
+ printfi_filtered (spaces + 8, "args ");
+ gdb_print_address (TYPE_FN_FIELD_ARGS (f, overload_idx), gdb_stdout);
+ printf_filtered ("\n");
+
+ print_arg_types (TYPE_FN_FIELD_ARGS (f, overload_idx), spaces);
+ printfi_filtered (spaces + 8, "fcontext ");
+ gdb_print_address (TYPE_FN_FIELD_FCONTEXT (f, overload_idx),
+ gdb_stdout);
+ printf_filtered ("\n");
+
+ printfi_filtered (spaces + 8, "is_const %d\n",
+ TYPE_FN_FIELD_CONST (f, overload_idx));
+ printfi_filtered (spaces + 8, "is_volatile %d\n",
+ TYPE_FN_FIELD_VOLATILE (f, overload_idx));
+ printfi_filtered (spaces + 8, "is_private %d\n",
+ TYPE_FN_FIELD_PRIVATE (f, overload_idx));
+ printfi_filtered (spaces + 8, "is_protected %d\n",
+ TYPE_FN_FIELD_PROTECTED (f, overload_idx));
+ printfi_filtered (spaces + 8, "is_stub %d\n",
+ TYPE_FN_FIELD_STUB (f, overload_idx));
+ printfi_filtered (spaces + 8, "voffset %u\n",
+ TYPE_FN_FIELD_VOFFSET (f, overload_idx));
+ }
+ }
+}
+
+static void
+print_cplus_stuff (type, spaces)
+ struct type *type;
+ int spaces;
+{
+ printfi_filtered (spaces, "n_baseclasses %d\n",
+ TYPE_N_BASECLASSES (type));
+ printfi_filtered (spaces, "nfn_fields %d\n",
+ TYPE_NFN_FIELDS (type));
+ printfi_filtered (spaces, "nfn_fields_total %d\n",
+ TYPE_NFN_FIELDS_TOTAL (type));
+ if (TYPE_N_BASECLASSES (type) > 0)
+ {
+ printfi_filtered (spaces, "virtual_field_bits (%d bits at *",
+ TYPE_N_BASECLASSES (type));
+ gdb_print_address (TYPE_FIELD_VIRTUAL_BITS (type), gdb_stdout);
+ printf_filtered (")");
+
+ print_bit_vector (TYPE_FIELD_VIRTUAL_BITS (type),
+ TYPE_N_BASECLASSES (type));
+ puts_filtered ("\n");
+ }
+ if (TYPE_NFIELDS (type) > 0)
+ {
+ if (TYPE_FIELD_PRIVATE_BITS (type) != NULL)
+ {
+ printfi_filtered (spaces, "private_field_bits (%d bits at *",
+ TYPE_NFIELDS (type));
+ gdb_print_address (TYPE_FIELD_PRIVATE_BITS (type), gdb_stdout);
+ printf_filtered (")");
+ print_bit_vector (TYPE_FIELD_PRIVATE_BITS (type),
+ TYPE_NFIELDS (type));
+ puts_filtered ("\n");
+ }
+ if (TYPE_FIELD_PROTECTED_BITS (type) != NULL)
+ {
+ printfi_filtered (spaces, "protected_field_bits (%d bits at *",
+ TYPE_NFIELDS (type));
+ gdb_print_address (TYPE_FIELD_PROTECTED_BITS (type), gdb_stdout);
+ printf_filtered (")");
+ print_bit_vector (TYPE_FIELD_PROTECTED_BITS (type),
+ TYPE_NFIELDS (type));
+ puts_filtered ("\n");
+ }
+ }
+ if (TYPE_NFN_FIELDS (type) > 0)
+ {
+ dump_fn_fieldlists (type, spaces);
+ }
+}
+
+void
+recursive_dump_type (type, spaces)
+ struct type *type;
+ int spaces;
+{
+ int idx;
+
+ printfi_filtered (spaces, "type node ");
+ gdb_print_address (type, gdb_stdout);
+ printf_filtered ("\n");
+ printfi_filtered (spaces, "name '%s' (",
+ TYPE_NAME (type) ? TYPE_NAME (type) : "<NULL>");
+ gdb_print_address (TYPE_NAME (type), gdb_stdout);
+ printf_filtered (")\n");
+ if (TYPE_TAG_NAME (type) != NULL)
+ {
+ printfi_filtered (spaces, "tagname '%s' (",
+ TYPE_TAG_NAME (type));
+ gdb_print_address (TYPE_TAG_NAME (type), gdb_stdout);
+ printf_filtered (")\n");
+ }
+ printfi_filtered (spaces, "code 0x%x ", TYPE_CODE (type));
+ switch (TYPE_CODE (type))
+ {
+ case TYPE_CODE_UNDEF:
+ printf_filtered ("(TYPE_CODE_UNDEF)");
+ break;
+ case TYPE_CODE_PTR:
+ printf_filtered ("(TYPE_CODE_PTR)");
+ break;
+ case TYPE_CODE_ARRAY:
+ printf_filtered ("(TYPE_CODE_ARRAY)");
+ break;
+ case TYPE_CODE_STRUCT:
+ printf_filtered ("(TYPE_CODE_STRUCT)");
+ break;
+ case TYPE_CODE_UNION:
+ printf_filtered ("(TYPE_CODE_UNION)");
+ break;
+ case TYPE_CODE_ENUM:
+ printf_filtered ("(TYPE_CODE_ENUM)");
+ break;
+ case TYPE_CODE_FUNC:
+ printf_filtered ("(TYPE_CODE_FUNC)");
+ break;
+ case TYPE_CODE_INT:
+ printf_filtered ("(TYPE_CODE_INT)");
+ break;
+ case TYPE_CODE_FLT:
+ printf_filtered ("(TYPE_CODE_FLT)");
+ break;
+ case TYPE_CODE_VOID:
+ printf_filtered ("(TYPE_CODE_VOID)");
+ break;
+ case TYPE_CODE_SET:
+ printf_filtered ("(TYPE_CODE_SET)");
+ break;
+ case TYPE_CODE_RANGE:
+ printf_filtered ("(TYPE_CODE_RANGE)");
+ break;
+ case TYPE_CODE_STRING:
+ printf_filtered ("(TYPE_CODE_STRING)");
+ break;
+ case TYPE_CODE_ERROR:
+ printf_filtered ("(TYPE_CODE_ERROR)");
+ break;
+ case TYPE_CODE_MEMBER:
+ printf_filtered ("(TYPE_CODE_MEMBER)");
+ break;
+ case TYPE_CODE_METHOD:
+ printf_filtered ("(TYPE_CODE_METHOD)");
+ break;
+ case TYPE_CODE_REF:
+ printf_filtered ("(TYPE_CODE_REF)");
+ break;
+ case TYPE_CODE_CHAR:
+ printf_filtered ("(TYPE_CODE_CHAR)");
+ break;
+ case TYPE_CODE_BOOL:
+ printf_filtered ("(TYPE_CODE_BOOL)");
+ break;
+ default:
+ printf_filtered ("(UNKNOWN TYPE CODE)");
+ break;
+ }
+ puts_filtered ("\n");
+ printfi_filtered (spaces, "length %d\n", TYPE_LENGTH (type));
+ printfi_filtered (spaces, "objfile ");
+ gdb_print_address (TYPE_OBJFILE (type), gdb_stdout);
+ printf_filtered ("\n");
+ printfi_filtered (spaces, "target_type ");
+ gdb_print_address (TYPE_TARGET_TYPE (type), gdb_stdout);
+ printf_filtered ("\n");
+ if (TYPE_TARGET_TYPE (type) != NULL)
+ {
+ recursive_dump_type (TYPE_TARGET_TYPE (type), spaces + 2);
+ }
+ printfi_filtered (spaces, "pointer_type ");
+ gdb_print_address (TYPE_POINTER_TYPE (type), gdb_stdout);
+ printf_filtered ("\n");
+ printfi_filtered (spaces, "reference_type ");
+ gdb_print_address (TYPE_REFERENCE_TYPE (type), gdb_stdout);
+ printf_filtered ("\n");
+ printfi_filtered (spaces, "function_type ");
+ gdb_print_address (TYPE_FUNCTION_TYPE (type), gdb_stdout);
+ printf_filtered ("\n");
+ printfi_filtered (spaces, "flags 0x%x", TYPE_FLAGS (type));
+ if (TYPE_FLAGS (type) & TYPE_FLAG_UNSIGNED)
+ {
+ puts_filtered (" TYPE_FLAG_UNSIGNED");
+ }
+ if (TYPE_FLAGS (type) & TYPE_FLAG_STUB)
+ {
+ puts_filtered (" TYPE_FLAG_STUB");
+ }
+ puts_filtered ("\n");
+ printfi_filtered (spaces, "nfields %d ", TYPE_NFIELDS (type));
+ gdb_print_address (TYPE_FIELDS (type), gdb_stdout);
+ puts_filtered ("\n");
+ for (idx = 0; idx < TYPE_NFIELDS (type); idx++)
+ {
+ printfi_filtered (spaces + 2,
+ "[%d] bitpos %d bitsize %d type ",
+ idx, TYPE_FIELD_BITPOS (type, idx),
+ TYPE_FIELD_BITSIZE (type, idx));
+ gdb_print_address (TYPE_FIELD_TYPE (type, idx), gdb_stdout);
+ printf_filtered (" name '%s' (",
+ TYPE_FIELD_NAME (type, idx) != NULL
+ ? TYPE_FIELD_NAME (type, idx)
+ : "<NULL>");
+ gdb_print_address (TYPE_FIELD_NAME (type, idx), gdb_stdout);
+ printf_filtered (")\n");
+ if (TYPE_FIELD_TYPE (type, idx) != NULL)
+ {
+ recursive_dump_type (TYPE_FIELD_TYPE (type, idx), spaces + 4);
+ }
+ }
+ printfi_filtered (spaces, "vptr_basetype ");
+ gdb_print_address (TYPE_VPTR_BASETYPE (type), gdb_stdout);
+ puts_filtered ("\n");
+ if (TYPE_VPTR_BASETYPE (type) != NULL)
+ {
+ recursive_dump_type (TYPE_VPTR_BASETYPE (type), spaces + 2);
+ }
+ printfi_filtered (spaces, "vptr_fieldno %d\n", TYPE_VPTR_FIELDNO (type));
+ switch (TYPE_CODE (type))
+ {
+ case TYPE_CODE_METHOD:
+ case TYPE_CODE_FUNC:
+ printfi_filtered (spaces, "arg_types ");
+ gdb_print_address (TYPE_ARG_TYPES (type), gdb_stdout);
+ puts_filtered ("\n");
+ print_arg_types (TYPE_ARG_TYPES (type), spaces);
+ break;
+
+ case TYPE_CODE_STRUCT:
+ printfi_filtered (spaces, "cplus_stuff ");
+ gdb_print_address (TYPE_CPLUS_SPECIFIC (type), gdb_stdout);
+ puts_filtered ("\n");
+ print_cplus_stuff (type, spaces);
+ break;
+
+ default:
+ /* We have to pick one of the union types to be able print and test
+ the value. Pick cplus_struct_type, even though we know it isn't
+ any particular one. */
+ printfi_filtered (spaces, "type_specific ");
+ gdb_print_address (TYPE_CPLUS_SPECIFIC (type), gdb_stdout);
+ if (TYPE_CPLUS_SPECIFIC (type) != NULL)
+ {
+ printf_filtered (" (unknown data form)");
+ }
+ printf_filtered ("\n");
+ break;
+
+ }
+}
+
+#endif /* MAINTENANCE_CMDS */
+
+void
+_initialize_gdbtypes ()
+{
+ builtin_type_void =
+ init_type (TYPE_CODE_VOID, 1,
+ 0,
+ "void", (struct objfile *) NULL);
+ builtin_type_char =
+ init_type (TYPE_CODE_INT, TARGET_CHAR_BIT / TARGET_CHAR_BIT,
+ 0,
+ "char", (struct objfile *) NULL);
+ builtin_type_signed_char =
+ init_type (TYPE_CODE_INT, TARGET_CHAR_BIT / TARGET_CHAR_BIT,
+ 0,
+ "signed char", (struct objfile *) NULL);
+ builtin_type_unsigned_char =
+ init_type (TYPE_CODE_INT, TARGET_CHAR_BIT / TARGET_CHAR_BIT,
+ TYPE_FLAG_UNSIGNED,
+ "unsigned char", (struct objfile *) NULL);
+ builtin_type_short =
+ init_type (TYPE_CODE_INT, TARGET_SHORT_BIT / TARGET_CHAR_BIT,
+ 0,
+ "short", (struct objfile *) NULL);
+ builtin_type_unsigned_short =
+ init_type (TYPE_CODE_INT, TARGET_SHORT_BIT / TARGET_CHAR_BIT,
+ TYPE_FLAG_UNSIGNED,
+ "unsigned short", (struct objfile *) NULL);
+ builtin_type_int =
+ init_type (TYPE_CODE_INT, TARGET_INT_BIT / TARGET_CHAR_BIT,
+ 0,
+ "int", (struct objfile *) NULL);
+ builtin_type_unsigned_int =
+ init_type (TYPE_CODE_INT, TARGET_INT_BIT / TARGET_CHAR_BIT,
+ TYPE_FLAG_UNSIGNED,
+ "unsigned int", (struct objfile *) NULL);
+ builtin_type_long =
+ init_type (TYPE_CODE_INT, TARGET_LONG_BIT / TARGET_CHAR_BIT,
+ 0,
+ "long", (struct objfile *) NULL);
+ builtin_type_unsigned_long =
+ init_type (TYPE_CODE_INT, TARGET_LONG_BIT / TARGET_CHAR_BIT,
+ TYPE_FLAG_UNSIGNED,
+ "unsigned long", (struct objfile *) NULL);
+ builtin_type_long_long =
+ init_type (TYPE_CODE_INT, TARGET_LONG_LONG_BIT / TARGET_CHAR_BIT,
+ 0,
+ "long long", (struct objfile *) NULL);
+ builtin_type_unsigned_long_long =
+ init_type (TYPE_CODE_INT, TARGET_LONG_LONG_BIT / TARGET_CHAR_BIT,
+ TYPE_FLAG_UNSIGNED,
+ "unsigned long long", (struct objfile *) NULL);
+ builtin_type_float =
+ init_type (TYPE_CODE_FLT, TARGET_FLOAT_BIT / TARGET_CHAR_BIT,
+ 0,
+ "float", (struct objfile *) NULL);
+ builtin_type_double =
+ init_type (TYPE_CODE_FLT, TARGET_DOUBLE_BIT / TARGET_CHAR_BIT,
+ 0,
+ "double", (struct objfile *) NULL);
+ builtin_type_long_double =
+ init_type (TYPE_CODE_FLT, TARGET_LONG_DOUBLE_BIT / TARGET_CHAR_BIT,
+ 0,
+ "long double", (struct objfile *) NULL);
+ builtin_type_complex =
+ init_type (TYPE_CODE_FLT, TARGET_COMPLEX_BIT / TARGET_CHAR_BIT,
+ 0,
+ "complex", (struct objfile *) NULL);
+ builtin_type_double_complex =
+ init_type (TYPE_CODE_FLT, TARGET_DOUBLE_COMPLEX_BIT / TARGET_CHAR_BIT,
+ 0,
+ "double complex", (struct objfile *) NULL);
+ builtin_type_string =
+ init_type (TYPE_CODE_STRING, TARGET_CHAR_BIT / TARGET_CHAR_BIT,
+ 0,
+ "string", (struct objfile *) NULL);
+}
diff --git a/gnu/usr.bin/gdb/gdb/gdbtypes.h b/gnu/usr.bin/gdb/gdb/gdbtypes.h
new file mode 100644
index 0000000..8ba6bfa
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/gdbtypes.h
@@ -0,0 +1,735 @@
+/* Internal type definitions for GDB.
+ Copyright (C) 1992 Free Software Foundation, Inc.
+ Contributed by Cygnus Support, using pieces from other GDB modules.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#if !defined (GDBTYPES_H)
+#define GDBTYPES_H 1
+
+/* Codes for `fundamental types'. This is a monstrosity based on the
+ bogus notion that there are certain compiler-independent
+ `fundamental types'. None of these is well-defined (how big is
+ FT_SHORT? Does it depend on the language? How does the
+ language-specific code know which type to correlate to FT_SHORT?) */
+
+#define FT_VOID 0
+#define FT_BOOLEAN 1
+#define FT_CHAR 2
+#define FT_SIGNED_CHAR 3
+#define FT_UNSIGNED_CHAR 4
+#define FT_SHORT 5
+#define FT_SIGNED_SHORT 6
+#define FT_UNSIGNED_SHORT 7
+#define FT_INTEGER 8
+#define FT_SIGNED_INTEGER 9
+#define FT_UNSIGNED_INTEGER 10
+#define FT_LONG 11
+#define FT_SIGNED_LONG 12
+#define FT_UNSIGNED_LONG 13
+#define FT_LONG_LONG 14
+#define FT_SIGNED_LONG_LONG 15
+#define FT_UNSIGNED_LONG_LONG 16
+#define FT_FLOAT 17
+#define FT_DBL_PREC_FLOAT 18
+#define FT_EXT_PREC_FLOAT 19
+#define FT_COMPLEX 20
+#define FT_DBL_PREC_COMPLEX 21
+#define FT_EXT_PREC_COMPLEX 22
+#define FT_STRING 23
+#define FT_FIXED_DECIMAL 24
+#define FT_FLOAT_DECIMAL 25
+#define FT_BYTE 26
+#define FT_UNSIGNED_BYTE 27
+
+#define FT_NUM_MEMBERS 28 /* Highest FT_* above, plus one. */
+
+/* Some macros for char-based bitfields. */
+
+#define B_SET(a,x) ((a)[(x)>>3] |= (1 << ((x)&7)))
+#define B_CLR(a,x) ((a)[(x)>>3] &= ~(1 << ((x)&7)))
+#define B_TST(a,x) ((a)[(x)>>3] & (1 << ((x)&7)))
+#define B_TYPE unsigned char
+#define B_BYTES(x) ( 1 + ((x)>>3) )
+#define B_CLRALL(a,x) memset ((a), 0, B_BYTES(x))
+
+/* Different kinds of data types are distinguished by the `code' field. */
+
+enum type_code
+{
+ TYPE_CODE_UNDEF, /* Not used; catches errors */
+ TYPE_CODE_PTR, /* Pointer type */
+ TYPE_CODE_ARRAY, /* Array type with lower & upper bounds. */
+ TYPE_CODE_STRUCT, /* C struct or Pascal record */
+ TYPE_CODE_UNION, /* C union or Pascal variant part */
+ TYPE_CODE_ENUM, /* Enumeration type */
+ TYPE_CODE_FUNC, /* Function type */
+ TYPE_CODE_INT, /* Integer type */
+
+ /* Floating type. This is *NOT* a complex type. Complex types, when
+ we have them, will have their own type code (or TYPE_CODE_ERROR if
+ we can parse a complex type but not manipulate it). There are parts
+ of GDB which bogusly assume that TYPE_CODE_FLT can mean complex. */
+ TYPE_CODE_FLT,
+
+ /* Void type. The length field specifies the length (probably always
+ one) which is used in pointer arithmetic involving pointers to
+ this type, but actually dereferencing such a pointer is invalid;
+ a void type has no length and no actual representation in memory
+ or registers. A pointer to a void type is a generic pointer. */
+ TYPE_CODE_VOID,
+
+ TYPE_CODE_SET, /* Pascal sets */
+ TYPE_CODE_RANGE, /* Range (integers within spec'd bounds) */
+
+ /* A string type which is like an array of character but prints
+ differently (at least for CHILL). It does not contain a length
+ field as Pascal strings (for many Pascals, anyway) do; if we want
+ to deal with such strings, we should use a new type code. */
+ TYPE_CODE_STRING,
+
+ /* String of bits; like TYPE_CODE_SET but prints differently (at least
+ for CHILL). */
+ TYPE_CODE_BITSTRING,
+
+ /* Unknown type. The length field is valid if we were able to
+ deduce that much about the type, or 0 if we don't even know that. */
+ TYPE_CODE_ERROR,
+
+ /* C++ */
+ TYPE_CODE_MEMBER, /* Member type */
+ TYPE_CODE_METHOD, /* Method type */
+ TYPE_CODE_REF, /* C++ Reference types */
+
+ TYPE_CODE_CHAR, /* *real* character type */
+
+ /* Boolean type. 0 is false, 1 is true, and other values are non-boolean
+ (e.g. FORTRAN "logical" used as unsigned int). */
+ TYPE_CODE_BOOL
+};
+
+/* For now allow source to use TYPE_CODE_CLASS for C++ classes, as an
+ alias for TYPE_CODE_STRUCT. This is for DWARF, which has a distinct
+ "class" attribute. Perhaps we should actually have a separate TYPE_CODE
+ so that we can print "class" or "struct" depending on what the debug
+ info said. It's not clear we should bother. */
+
+#define TYPE_CODE_CLASS TYPE_CODE_STRUCT
+
+/* Some bits for the type's flags word. */
+
+/* Unsigned integer type. If this is not set for a TYPE_CODE_INT, the
+ type is signed. */
+
+#define TYPE_FLAG_UNSIGNED (1 << 0)
+
+/* This appears in a type's flags word if it is a stub type (e.g., if
+ someone referenced a type that wasn't defined in a source file
+ via (struct sir_not_appearing_in_this_film *)). */
+
+#define TYPE_FLAG_STUB (1 << 2)
+
+/* The target type of this type is a stub type, and this type needs to
+ be updated if it gets un-stubbed in check_stub_type. Currently only
+ used for arrays, in which TYPE_LENGTH of the array gets set based
+ on the TYPE_LENGTH of the target type. */
+
+#define TYPE_FLAG_TARGET_STUB (1 << 3)
+
+struct type
+{
+
+ /* Code for kind of type */
+
+ enum type_code code;
+
+ /* Name of this type, or NULL if none.
+
+ This is used for printing only, except by poorly designed C++ code.
+ For looking up a name, look for a symbol in the VAR_NAMESPACE. */
+
+ char *name;
+
+ /* Tag name for this type, or NULL if none. This means that the
+ name of the type consists of a keyword followed by the tag name.
+ Which keyword is determined by the type code ("struct" for
+ TYPE_CODE_STRUCT, etc.). As far as I know C/C++ are the only languages
+ with this feature.
+
+ This is used for printing only, except by poorly designed C++ code.
+ For looking up a name, look for a symbol in the STRUCT_NAMESPACE.
+ One more legitimate use is that if TYPE_FLAG_STUB is set, this is
+ the name to use to look for definitions in other files. */
+
+ char *tag_name;
+
+ /* Length, in units of TARGET_CHAR_BIT bits,
+ of storage for a value of this type */
+
+ unsigned length;
+
+ /* Every type is now associated with a particular objfile, and the
+ type is allocated on the type_obstack for that objfile. One problem
+ however, is that there are times when gdb allocates new types while
+ it is not in the process of reading symbols from a particular objfile.
+ Fortunately, these happen when the type being created is a derived
+ type of an existing type, such as in lookup_pointer_type(). So
+ we can just allocate the new type using the same objfile as the
+ existing type, but to do this we need a backpointer to the objfile
+ from the existing type. Yes this is somewhat ugly, but without
+ major overhaul of the internal type system, it can't be avoided
+ for now. */
+
+ struct objfile *objfile;
+
+ /* For a pointer type, describes the type of object pointed to.
+ For an array type, describes the type of the elements.
+ For a function or method type, describes the type of the return value.
+ For a range type, describes the type of the full range.
+ Unused otherwise. */
+
+ struct type *target_type;
+
+ /* Type that is a pointer to this type.
+ NULL if no such pointer-to type is known yet.
+ The debugger may add the address of such a type
+ if it has to construct one later. */
+
+ struct type *pointer_type;
+
+ /* C++: also need a reference type. */
+
+ struct type *reference_type;
+
+ /* Type that is a function returning this type.
+ NULL if no such function type is known here.
+ The debugger may add the address of such a type
+ if it has to construct one later. */
+
+ struct type *function_type;
+
+ /* Flags about this type. */
+
+ short flags;
+
+ /* Number of fields described for this type */
+
+ short nfields;
+
+ /* For structure and union types, a description of each field.
+ For set and pascal array types, there is one "field",
+ whose type is the domain type of the set or array.
+ For range types, there are two "fields",
+ the minimum and maximum values (both inclusive).
+ For enum types, each possible value is described by one "field".
+ For C++ classes, there is one field for each base class (if it is
+ a derived class) plus one field for each class data member. Member
+ functions are recorded elsewhere.
+
+ Using a pointer to a separate array of fields
+ allows all types to have the same size, which is useful
+ because we can allocate the space for a type before
+ we know what to put in it. */
+
+ struct field
+ {
+
+ /* Position of this field, counting in bits from start of
+ containing structure. For a function type, this is the
+ position in the argument list of this argument.
+ For a range bound or enum value, this is the value itself.
+ (FIXME: What about ranges larger than host int size?)
+ For BITS_BIG_ENDIAN=1 targets, it is the bit offset to the MSB.
+ For BITS_BIG_ENDIAN=0 targets, it is the bit offset to the LSB. */
+
+ int bitpos;
+
+ /* Size of this field, in bits, or zero if not packed.
+ For an unpacked field, the field's type's length
+ says how many bytes the field occupies. */
+ /* FIXME: This is abused by TYPE_FIELD_STATIC_PHYSNAME to contain
+ a pointer, so it has to be long. */
+
+ long bitsize;
+
+ /* In a struct or enum type, type of this field.
+ In a function type, type of this argument.
+ In an array type, the domain-type of the array. */
+
+ struct type *type;
+
+ /* Name of field, value or argument.
+ NULL for range bounds and array domains. */
+
+ char *name;
+
+ } *fields;
+
+ /* For types with virtual functions, VPTR_BASETYPE is the base class which
+ defined the virtual function table pointer.
+
+ For types that are pointer to member types, VPTR_BASETYPE
+ is the type that this pointer is a member of.
+
+ Unused otherwise. */
+
+ struct type *vptr_basetype;
+
+ /* Field number of the virtual function table pointer in
+ VPTR_BASETYPE. If -1, we were unable to find the virtual
+ function table pointer in initial symbol reading, and
+ fill_in_vptr_fieldno should be called to find it if possible.
+
+ Unused if this type does not have virtual functions. */
+
+ int vptr_fieldno;
+
+ /* Slot to point to additional language-specific fields of this type. */
+
+ union type_specific
+ {
+
+ /* ARG_TYPES is for TYPE_CODE_METHOD and TYPE_CODE_FUNC. */
+
+ struct type **arg_types;
+
+ /* CPLUS_STUFF is for TYPE_CODE_STRUCT. It is initialized to point to
+ cplus_struct_default, a default static instance of a struct
+ cplus_struct_type. */
+
+ struct cplus_struct_type *cplus_stuff;
+
+ } type_specific;
+};
+
+#define NULL_TYPE ((struct type *) 0)
+
+/* C++ language-specific information for TYPE_CODE_STRUCT and TYPE_CODE_UNION
+ nodes. */
+
+struct cplus_struct_type
+{
+ /* Number of base classes this type derives from. The baseclasses are
+ stored in the first N_BASECLASSES fields (i.e. the `fields' field of
+ the struct type). I think only the `type' field of such a field has
+ any meaning. */
+
+ short n_baseclasses;
+
+ /* Number of methods with unique names. All overloaded methods with
+ the same name count only once. */
+
+ short nfn_fields;
+
+ /* Number of methods described for this type plus all the
+ methods that it derives from. */
+
+ int nfn_fields_total;
+
+ /* For derived classes, the number of base classes is given by n_baseclasses
+ and virtual_field_bits is a bit vector containing one bit per base class.
+ If the base class is virtual, the corresponding bit will be set.
+ I.E, given:
+
+ class A{};
+ class B{};
+ class C : public B, public virtual A {};
+
+ B is a baseclass of C; A is a virtual baseclass for C.
+ This is a C++ 2.0 language feature. */
+
+ B_TYPE *virtual_field_bits;
+
+ /* For classes with private fields, the number of fields is given by
+ nfields and private_field_bits is a bit vector containing one bit
+ per field.
+ If the field is private, the corresponding bit will be set. */
+
+ B_TYPE *private_field_bits;
+
+ /* For classes with protected fields, the number of fields is given by
+ nfields and protected_field_bits is a bit vector containing one bit
+ per field.
+ If the field is private, the corresponding bit will be set. */
+
+ B_TYPE *protected_field_bits;
+
+ /* for classes with fields to be ignored, either this is optimized out
+ or this field has length 0 */
+
+ B_TYPE *ignore_field_bits;
+
+ /* For classes, structures, and unions, a description of each field,
+ which consists of an overloaded name, followed by the types of
+ arguments that the method expects, and then the name after it
+ has been renamed to make it distinct.
+
+ fn_fieldlists points to an array of nfn_fields of these. */
+
+ struct fn_fieldlist
+ {
+
+ /* The overloaded name. */
+
+ char *name;
+
+ /* The number of methods with this name. */
+
+ int length;
+
+ /* The list of methods. */
+
+ struct fn_field
+ {
+
+ /* If is_stub is clear, this is the mangled name which we can
+ look up to find the address of the method (FIXME: it would
+ be cleaner to have a pointer to the struct symbol here
+ instead). */
+
+ /* If is_stub is set, this is the portion of the mangled
+ name which specifies the arguments. For example, "ii",
+ if there are two int arguments, or "" if there are no
+ arguments. See gdb_mangle_name for the conversion from this
+ format to the one used if is_stub is clear. */
+
+ char *physname;
+
+ /* The return value of the method */
+
+ struct type *type;
+
+ /* The argument list. Only valid if is_stub is clear. Contains
+ the type of each argument, including `this', and ending with
+ a NULL pointer after the last argument. Should not contain
+ a `this' pointer for static member functions. */
+
+ struct type **args;
+
+ /* For virtual functions.
+ First baseclass that defines this virtual function. */
+
+ struct type *fcontext;
+
+ /* Attributes. */
+
+ unsigned int is_const : 1;
+ unsigned int is_volatile : 1;
+ unsigned int is_private : 1;
+ unsigned int is_protected : 1;
+
+ /* A stub method only has some fields valid (but they are enough
+ to reconstruct the rest of the fields). */
+ unsigned int is_stub : 1;
+
+ /* Unused. */
+ unsigned int dummy : 3;
+
+ /* Index into that baseclass's virtual function table,
+ minus 2; else if static: VOFFSET_STATIC; else: 0. */
+
+ unsigned int voffset : 24;
+
+# define VOFFSET_STATIC 1
+
+ } *fn_fields;
+
+ } *fn_fieldlists;
+
+};
+
+/* The default value of TYPE_CPLUS_SPECIFIC(T) points to the
+ this shared static structure. */
+
+extern const struct cplus_struct_type cplus_struct_default;
+
+extern void
+allocate_cplus_struct_type PARAMS ((struct type *));
+
+#define INIT_CPLUS_SPECIFIC(type) \
+ (TYPE_CPLUS_SPECIFIC(type)=(struct cplus_struct_type*)&cplus_struct_default)
+#define ALLOCATE_CPLUS_STRUCT_TYPE(type) allocate_cplus_struct_type (type)
+#define HAVE_CPLUS_STRUCT(type) \
+ (TYPE_CPLUS_SPECIFIC(type) != &cplus_struct_default)
+
+#define TYPE_NAME(thistype) (thistype)->name
+#define TYPE_TAG_NAME(type) ((type)->tag_name)
+#define TYPE_TARGET_TYPE(thistype) (thistype)->target_type
+#define TYPE_POINTER_TYPE(thistype) (thistype)->pointer_type
+#define TYPE_REFERENCE_TYPE(thistype) (thistype)->reference_type
+#define TYPE_FUNCTION_TYPE(thistype) (thistype)->function_type
+#define TYPE_LENGTH(thistype) (thistype)->length
+#define TYPE_OBJFILE(thistype) (thistype)->objfile
+#define TYPE_FLAGS(thistype) (thistype)->flags
+#define TYPE_UNSIGNED(thistype) ((thistype)->flags & TYPE_FLAG_UNSIGNED)
+#define TYPE_CODE(thistype) (thistype)->code
+#define TYPE_NFIELDS(thistype) (thistype)->nfields
+#define TYPE_FIELDS(thistype) (thistype)->fields
+
+#define TYPE_LOW_BOUND(range_type) TYPE_FIELD_BITPOS (range_type, 0)
+#define TYPE_HIGH_BOUND(range_type) TYPE_FIELD_BITPOS (range_type, 1)
+/* If TYPE_DUMMY_RANGE is true for a range type, it was allocated
+ by force_to_range_type. */
+#define TYPE_DUMMY_RANGE(type) ((type)->vptr_fieldno)
+
+/* C++ */
+
+#define TYPE_VPTR_BASETYPE(thistype) (thistype)->vptr_basetype
+#define TYPE_DOMAIN_TYPE(thistype) (thistype)->vptr_basetype
+#define TYPE_VPTR_FIELDNO(thistype) (thistype)->vptr_fieldno
+#define TYPE_FN_FIELDS(thistype) TYPE_CPLUS_SPECIFIC(thistype)->fn_fields
+#define TYPE_NFN_FIELDS(thistype) TYPE_CPLUS_SPECIFIC(thistype)->nfn_fields
+#define TYPE_NFN_FIELDS_TOTAL(thistype) TYPE_CPLUS_SPECIFIC(thistype)->nfn_fields_total
+#define TYPE_TYPE_SPECIFIC(thistype) (thistype)->type_specific
+#define TYPE_ARG_TYPES(thistype) (thistype)->type_specific.arg_types
+#define TYPE_CPLUS_SPECIFIC(thistype) (thistype)->type_specific.cplus_stuff
+#define TYPE_BASECLASS(thistype,index) (thistype)->fields[index].type
+#define TYPE_N_BASECLASSES(thistype) TYPE_CPLUS_SPECIFIC(thistype)->n_baseclasses
+#define TYPE_BASECLASS_NAME(thistype,index) (thistype)->fields[index].name
+#define TYPE_BASECLASS_BITPOS(thistype,index) (thistype)->fields[index].bitpos
+#define BASETYPE_VIA_PUBLIC(thistype, index) (!TYPE_FIELD_PRIVATE(thistype, index))
+#define BASETYPE_VIA_VIRTUAL(thistype, index) \
+ B_TST(TYPE_CPLUS_SPECIFIC(thistype)->virtual_field_bits, (index))
+
+#define TYPE_FIELD(thistype, n) (thistype)->fields[n]
+#define TYPE_FIELD_TYPE(thistype, n) (thistype)->fields[n].type
+#define TYPE_FIELD_NAME(thistype, n) (thistype)->fields[n].name
+#define TYPE_FIELD_VALUE(thistype, n) (* (int*) &(thistype)->fields[n].type)
+#define TYPE_FIELD_BITPOS(thistype, n) (thistype)->fields[n].bitpos
+#define TYPE_FIELD_BITSIZE(thistype, n) (thistype)->fields[n].bitsize
+#define TYPE_FIELD_PACKED(thistype, n) (thistype)->fields[n].bitsize
+
+#define TYPE_FIELD_PRIVATE_BITS(thistype) \
+ TYPE_CPLUS_SPECIFIC(thistype)->private_field_bits
+#define TYPE_FIELD_PROTECTED_BITS(thistype) \
+ TYPE_CPLUS_SPECIFIC(thistype)->protected_field_bits
+#define TYPE_FIELD_IGNORE_BITS(thistype) \
+ TYPE_CPLUS_SPECIFIC(thistype)->ignore_field_bits
+#define TYPE_FIELD_VIRTUAL_BITS(thistype) \
+ TYPE_CPLUS_SPECIFIC(thistype)->virtual_field_bits
+#define SET_TYPE_FIELD_PRIVATE(thistype, n) \
+ B_SET (TYPE_CPLUS_SPECIFIC(thistype)->private_field_bits, (n))
+#define SET_TYPE_FIELD_PROTECTED(thistype, n) \
+ B_SET (TYPE_CPLUS_SPECIFIC(thistype)->protected_field_bits, (n))
+#define SET_TYPE_FIELD_IGNORE(thistype, n) \
+ B_SET (TYPE_CPLUS_SPECIFIC(thistype)->ignore_field_bits, (n))
+#define SET_TYPE_FIELD_VIRTUAL(thistype, n) \
+ B_SET (TYPE_CPLUS_SPECIFIC(thistype)->virtual_field_bits, (n))
+#define TYPE_FIELD_PRIVATE(thistype, n) \
+ (TYPE_CPLUS_SPECIFIC(thistype)->private_field_bits == NULL ? 0 \
+ : B_TST(TYPE_CPLUS_SPECIFIC(thistype)->private_field_bits, (n)))
+#define TYPE_FIELD_PROTECTED(thistype, n) \
+ (TYPE_CPLUS_SPECIFIC(thistype)->protected_field_bits == NULL ? 0 \
+ : B_TST(TYPE_CPLUS_SPECIFIC(thistype)->protected_field_bits, (n)))
+#define TYPE_FIELD_IGNORE(thistype, n) \
+ (TYPE_CPLUS_SPECIFIC(thistype)->ignore_field_bits == NULL ? 0 \
+ : B_TST(TYPE_CPLUS_SPECIFIC(thistype)->ignore_field_bits, (n)))
+#define TYPE_FIELD_VIRTUAL(thistype, n) \
+ B_TST(TYPE_CPLUS_SPECIFIC(thistype)->virtual_field_bits, (n))
+
+#define TYPE_FIELD_STATIC(thistype, n) ((thistype)->fields[n].bitpos == -1)
+#define TYPE_FIELD_STATIC_PHYSNAME(thistype, n) ((char *)(thistype)->fields[n].bitsize)
+
+#define TYPE_FN_FIELDLISTS(thistype) TYPE_CPLUS_SPECIFIC(thistype)->fn_fieldlists
+#define TYPE_FN_FIELDLIST(thistype, n) TYPE_CPLUS_SPECIFIC(thistype)->fn_fieldlists[n]
+#define TYPE_FN_FIELDLIST1(thistype, n) TYPE_CPLUS_SPECIFIC(thistype)->fn_fieldlists[n].fn_fields
+#define TYPE_FN_FIELDLIST_NAME(thistype, n) TYPE_CPLUS_SPECIFIC(thistype)->fn_fieldlists[n].name
+#define TYPE_FN_FIELDLIST_LENGTH(thistype, n) TYPE_CPLUS_SPECIFIC(thistype)->fn_fieldlists[n].length
+
+#define TYPE_FN_FIELD(thisfn, n) (thisfn)[n]
+#define TYPE_FN_FIELD_PHYSNAME(thisfn, n) (thisfn)[n].physname
+#define TYPE_FN_FIELD_TYPE(thisfn, n) (thisfn)[n].type
+#define TYPE_FN_FIELD_ARGS(thisfn, n) TYPE_ARG_TYPES ((thisfn)[n].type)
+#define TYPE_FN_FIELD_CONST(thisfn, n) ((thisfn)[n].is_const)
+#define TYPE_FN_FIELD_VOLATILE(thisfn, n) ((thisfn)[n].is_volatile)
+#define TYPE_FN_FIELD_PRIVATE(thisfn, n) ((thisfn)[n].is_private)
+#define TYPE_FN_FIELD_PROTECTED(thisfn, n) ((thisfn)[n].is_protected)
+#define TYPE_FN_FIELD_STUB(thisfn, n) ((thisfn)[n].is_stub)
+#define TYPE_FN_FIELD_FCONTEXT(thisfn, n) ((thisfn)[n].fcontext)
+#define TYPE_FN_FIELD_VOFFSET(thisfn, n) ((thisfn)[n].voffset-2)
+#define TYPE_FN_FIELD_VIRTUAL_P(thisfn, n) ((thisfn)[n].voffset > 1)
+#define TYPE_FN_FIELD_STATIC_P(thisfn, n) ((thisfn)[n].voffset == VOFFSET_STATIC)
+
+extern struct type *builtin_type_void;
+extern struct type *builtin_type_char;
+extern struct type *builtin_type_short;
+extern struct type *builtin_type_int;
+extern struct type *builtin_type_long;
+extern struct type *builtin_type_signed_char;
+extern struct type *builtin_type_unsigned_char;
+extern struct type *builtin_type_unsigned_short;
+extern struct type *builtin_type_unsigned_int;
+extern struct type *builtin_type_unsigned_long;
+extern struct type *builtin_type_float;
+extern struct type *builtin_type_double;
+extern struct type *builtin_type_long_double;
+extern struct type *builtin_type_complex;
+extern struct type *builtin_type_double_complex;
+extern struct type *builtin_type_string;
+
+/* This type represents a type that was unrecognized in symbol
+ read-in. */
+
+extern struct type *builtin_type_error;
+
+extern struct type *builtin_type_long_long;
+extern struct type *builtin_type_unsigned_long_long;
+
+/* Modula-2 types */
+
+extern struct type *builtin_type_m2_char;
+extern struct type *builtin_type_m2_int;
+extern struct type *builtin_type_m2_card;
+extern struct type *builtin_type_m2_real;
+extern struct type *builtin_type_m2_bool;
+
+/* Chill types */
+
+extern struct type *builtin_type_chill_bool;
+extern struct type *builtin_type_chill_char;
+extern struct type *builtin_type_chill_long;
+extern struct type *builtin_type_chill_ulong;
+extern struct type *builtin_type_chill_real;
+
+/* Maximum and minimum values of built-in types */
+
+#define MAX_OF_TYPE(t) \
+ TYPE_UNSIGNED(t) ? UMAX_OF_SIZE(TYPE_LENGTH(t)) \
+ : MAX_OF_SIZE(TYPE_LENGTH(t))
+
+#define MIN_OF_TYPE(t) \
+ TYPE_UNSIGNED(t) ? UMIN_OF_SIZE(TYPE_LENGTH(t)) \
+ : MIN_OF_SIZE(TYPE_LENGTH(t))
+
+/* Allocate space for storing data associated with a particular type.
+ We ensure that the space is allocated using the same mechanism that
+ was used to allocate the space for the type structure itself. I.E.
+ if the type is on an objfile's type_obstack, then the space for data
+ associated with that type will also be allocated on the type_obstack.
+ If the type is not associated with any particular objfile (such as
+ builtin types), then the data space will be allocated with xmalloc,
+ the same as for the type structure. */
+
+#define TYPE_ALLOC(t,size) \
+ (TYPE_OBJFILE (t) != NULL \
+ ? obstack_alloc (&TYPE_OBJFILE (t) -> type_obstack, size) \
+ : xmalloc (size))
+
+extern struct type *
+alloc_type PARAMS ((struct objfile *));
+
+extern struct type *
+init_type PARAMS ((enum type_code, int, int, char *, struct objfile *));
+
+extern struct type *
+lookup_reference_type PARAMS ((struct type *));
+
+extern struct type *
+make_reference_type PARAMS ((struct type *, struct type **));
+
+extern struct type *
+lookup_member_type PARAMS ((struct type *, struct type *));
+
+extern void
+smash_to_method_type PARAMS ((struct type *, struct type *, struct type *,
+ struct type **));
+
+extern void
+smash_to_member_type PARAMS ((struct type *, struct type *, struct type *));
+
+extern struct type *
+allocate_stub_method PARAMS ((struct type *));
+
+extern char *
+type_name_no_tag PARAMS ((const struct type *));
+
+extern struct type *
+lookup_struct_elt_type PARAMS ((struct type *, char *, int));
+
+extern struct type *
+make_pointer_type PARAMS ((struct type *, struct type **));
+
+extern struct type *
+lookup_pointer_type PARAMS ((struct type *));
+
+extern struct type *
+make_function_type PARAMS ((struct type *, struct type **));
+
+extern struct type *
+lookup_function_type PARAMS ((struct type *));
+
+extern struct type *
+create_range_type PARAMS ((struct type *, struct type *, int, int));
+
+extern struct type *
+create_array_type PARAMS ((struct type *, struct type *, struct type *));
+
+extern struct type *
+create_string_type PARAMS ((struct type *, struct type *));
+
+extern struct type *
+create_set_type PARAMS ((struct type *, struct type *));
+
+extern struct type *
+lookup_unsigned_typename PARAMS ((char *));
+
+extern struct type *
+lookup_signed_typename PARAMS ((char *));
+
+extern void
+check_stub_type PARAMS ((struct type *));
+
+extern void
+check_stub_method PARAMS ((struct type *, int, int));
+
+extern struct type *
+lookup_primitive_typename PARAMS ((char *));
+
+extern char *
+gdb_mangle_name PARAMS ((struct type *, int, int));
+
+extern struct type *
+builtin_type PARAMS ((char **));
+
+extern struct type *
+lookup_typename PARAMS ((char *, struct block *, int));
+
+extern struct type *
+lookup_template_type PARAMS ((char *, struct type *, struct block *));
+
+extern struct type *
+lookup_fundamental_type PARAMS ((struct objfile *, int));
+
+extern void
+fill_in_vptr_fieldno PARAMS ((struct type *));
+
+#if MAINTENANCE_CMDS
+extern void recursive_dump_type PARAMS ((struct type *, int));
+#endif
+
+/* printcmd.c */
+
+extern void
+print_scalar_formatted PARAMS ((char *, struct type *, int, int, GDB_FILE *));
+
+extern int can_dereference PARAMS ((struct type *));
+
+#if MAINTENANCE_CMDS
+extern void maintenance_print_type PARAMS ((char *, int));
+#endif
+
+#endif /* GDBTYPES_H */
diff --git a/gnu/usr.bin/gdb/gdb/getopt.h b/gnu/usr.bin/gdb/gdb/getopt.h
new file mode 100644
index 0000000..1b546b2
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/getopt.h
@@ -0,0 +1,129 @@
+/* Declarations for getopt.
+ Copyright (C) 1989, 1990, 1991, 1992, 1993 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License
+ as published by the Free Software Foundation; either version 2, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#ifndef _GETOPT_H
+#define _GETOPT_H 1
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* For communication from `getopt' to the caller.
+ When `getopt' finds an option that takes an argument,
+ the argument value is returned here.
+ Also, when `ordering' is RETURN_IN_ORDER,
+ each non-option ARGV-element is returned here. */
+
+extern char *optarg;
+
+/* Index in ARGV of the next element to be scanned.
+ This is used for communication to and from the caller
+ and for communication between successive calls to `getopt'.
+
+ On entry to `getopt', zero means this is the first call; initialize.
+
+ When `getopt' returns EOF, this is the index of the first of the
+ non-option elements that the caller should itself scan.
+
+ Otherwise, `optind' communicates from one call to the next
+ how much of ARGV has been scanned so far. */
+
+extern int optind;
+
+/* Callers store zero here to inhibit the error message `getopt' prints
+ for unrecognized options. */
+
+extern int opterr;
+
+/* Set to an option character which was unrecognized. */
+
+extern int optopt;
+
+/* Describe the long-named options requested by the application.
+ The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector
+ of `struct option' terminated by an element containing a name which is
+ zero.
+
+ The field `has_arg' is:
+ no_argument (or 0) if the option does not take an argument,
+ required_argument (or 1) if the option requires an argument,
+ optional_argument (or 2) if the option takes an optional argument.
+
+ If the field `flag' is not NULL, it points to a variable that is set
+ to the value given in the field `val' when the option is found, but
+ left unchanged if the option is not found.
+
+ To have a long-named option do something other than set an `int' to
+ a compiled-in constant, such as set a value from `optarg', set the
+ option's `flag' field to zero and its `val' field to a nonzero
+ value (the equivalent single-letter option character, if there is
+ one). For long options that have a zero `flag' field, `getopt'
+ returns the contents of the `val' field. */
+
+struct option
+{
+#if __STDC__
+ const char *name;
+#else
+ char *name;
+#endif
+ /* has_arg can't be an enum because some compilers complain about
+ type mismatches in all the code that assumes it is an int. */
+ int has_arg;
+ int *flag;
+ int val;
+};
+
+/* Names for the values of the `has_arg' field of `struct option'. */
+
+#define no_argument 0
+#define required_argument 1
+#define optional_argument 2
+
+#if __STDC__
+#if defined(__GNU_LIBRARY__)
+/* Many other libraries have conflicting prototypes for getopt, with
+ differences in the consts, in stdlib.h. To avoid compilation
+ errors, only prototype getopt for the GNU C library. */
+extern int getopt (int argc, char *const *argv, const char *shortopts);
+#else /* not __GNU_LIBRARY__ */
+extern int getopt ();
+#endif /* not __GNU_LIBRARY__ */
+extern int getopt_long (int argc, char *const *argv, const char *shortopts,
+ const struct option *longopts, int *longind);
+extern int getopt_long_only (int argc, char *const *argv,
+ const char *shortopts,
+ const struct option *longopts, int *longind);
+
+/* Internal only. Users should not call this directly. */
+extern int _getopt_internal (int argc, char *const *argv,
+ const char *shortopts,
+ const struct option *longopts, int *longind,
+ int long_only);
+#else /* not __STDC__ */
+extern int getopt ();
+extern int getopt_long ();
+extern int getopt_long_only ();
+
+extern int _getopt_internal ();
+#endif /* not __STDC__ */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _GETOPT_H */
diff --git a/gnu/usr.bin/gdb/gdb/i386-dis.c b/gnu/usr.bin/gdb/gdb/i386-dis.c
new file mode 100644
index 0000000..ff94b3d8
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/i386-dis.c
@@ -0,0 +1,1959 @@
+/* Print i386 instructions for GDB, the GNU debugger.
+ Copyright (C) 1988, 1989, 1991, 1993, 1994 Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/*
+ * 80386 instruction printer by Pace Willisson (pace@prep.ai.mit.edu)
+ * July 1988
+ * modified by John Hassey (hassey@dg-rtp.dg.com)
+ */
+
+/*
+ * The main tables describing the instructions is essentially a copy
+ * of the "Opcode Map" chapter (Appendix A) of the Intel 80386
+ * Programmers Manual. Usually, there is a capital letter, followed
+ * by a small letter. The capital letter tell the addressing mode,
+ * and the small letter tells about the operand size. Refer to
+ * the Intel manual for details.
+ */
+
+#include "dis-asm.h"
+#include "sysdep.h"
+
+#define MAXLEN 20
+
+#include <setjmp.h>
+
+struct dis_private
+{
+ /* Points to first byte not fetched. */
+ bfd_byte *max_fetched;
+ bfd_byte the_buffer[MAXLEN];
+ bfd_vma insn_start;
+ jmp_buf bailout;
+};
+
+/* Make sure that bytes from INFO->PRIVATE_DATA->BUFFER (inclusive)
+ to ADDR (exclusive) are valid. Returns 1 for success, longjmps
+ on error. */
+#define FETCH_DATA(info, addr) \
+ ((addr) <= ((struct dis_private *)(info->private_data))->max_fetched \
+ ? 1 : fetch_data ((info), (addr)))
+
+static int
+fetch_data (info, addr)
+ struct disassemble_info *info;
+ bfd_byte *addr;
+{
+ int status;
+ struct dis_private *priv = (struct dis_private *)info->private_data;
+ bfd_vma start = priv->insn_start + (priv->max_fetched - priv->the_buffer);
+
+ status = (*info->read_memory_func) (start,
+ priv->max_fetched,
+ addr - priv->max_fetched,
+ info);
+ if (status != 0)
+ {
+ (*info->memory_error_func) (status, start, info);
+ longjmp (priv->bailout, 1);
+ }
+ else
+ priv->max_fetched = addr;
+ return 1;
+}
+
+#define Eb OP_E, b_mode
+#define indirEb OP_indirE, b_mode
+#define Gb OP_G, b_mode
+#define Ev OP_E, v_mode
+#define indirEv OP_indirE, v_mode
+#define Ew OP_E, w_mode
+#define Ma OP_E, v_mode
+#define M OP_E, 0
+#define Mp OP_E, 0 /* ? */
+#define Gv OP_G, v_mode
+#define Gw OP_G, w_mode
+#define Rw OP_rm, w_mode
+#define Rd OP_rm, d_mode
+#define Ib OP_I, b_mode
+#define sIb OP_sI, b_mode /* sign extened byte */
+#define Iv OP_I, v_mode
+#define Iw OP_I, w_mode
+#define Jb OP_J, b_mode
+#define Jv OP_J, v_mode
+#define ONE OP_ONE, 0
+#define Cd OP_C, d_mode
+#define Dd OP_D, d_mode
+#define Td OP_T, d_mode
+
+#define eAX OP_REG, eAX_reg
+#define eBX OP_REG, eBX_reg
+#define eCX OP_REG, eCX_reg
+#define eDX OP_REG, eDX_reg
+#define eSP OP_REG, eSP_reg
+#define eBP OP_REG, eBP_reg
+#define eSI OP_REG, eSI_reg
+#define eDI OP_REG, eDI_reg
+#define AL OP_REG, al_reg
+#define CL OP_REG, cl_reg
+#define DL OP_REG, dl_reg
+#define BL OP_REG, bl_reg
+#define AH OP_REG, ah_reg
+#define CH OP_REG, ch_reg
+#define DH OP_REG, dh_reg
+#define BH OP_REG, bh_reg
+#define AX OP_REG, ax_reg
+#define DX OP_REG, dx_reg
+#define indirDX OP_REG, indir_dx_reg
+
+#define Sw OP_SEG, w_mode
+#define Ap OP_DIR, lptr
+#define Av OP_DIR, v_mode
+#define Ob OP_OFF, b_mode
+#define Ov OP_OFF, v_mode
+#define Xb OP_DSSI, b_mode
+#define Xv OP_DSSI, v_mode
+#define Yb OP_ESDI, b_mode
+#define Yv OP_ESDI, v_mode
+
+#define es OP_REG, es_reg
+#define ss OP_REG, ss_reg
+#define cs OP_REG, cs_reg
+#define ds OP_REG, ds_reg
+#define fs OP_REG, fs_reg
+#define gs OP_REG, gs_reg
+
+int OP_E(), OP_indirE(), OP_G(), OP_I(), OP_sI(), OP_REG();
+int OP_J(), OP_SEG();
+int OP_DIR(), OP_OFF(), OP_DSSI(), OP_ESDI(), OP_ONE(), OP_C();
+int OP_D(), OP_T(), OP_rm();
+
+static void dofloat (), putop (), append_prefix (), set_op ();
+static int get16 (), get32 ();
+
+#define b_mode 1
+#define v_mode 2
+#define w_mode 3
+#define d_mode 4
+
+#define es_reg 100
+#define cs_reg 101
+#define ss_reg 102
+#define ds_reg 103
+#define fs_reg 104
+#define gs_reg 105
+#define eAX_reg 107
+#define eCX_reg 108
+#define eDX_reg 109
+#define eBX_reg 110
+#define eSP_reg 111
+#define eBP_reg 112
+#define eSI_reg 113
+#define eDI_reg 114
+
+#define lptr 115
+
+#define al_reg 116
+#define cl_reg 117
+#define dl_reg 118
+#define bl_reg 119
+#define ah_reg 120
+#define ch_reg 121
+#define dh_reg 122
+#define bh_reg 123
+
+#define ax_reg 124
+#define cx_reg 125
+#define dx_reg 126
+#define bx_reg 127
+#define sp_reg 128
+#define bp_reg 129
+#define si_reg 130
+#define di_reg 131
+
+#define indir_dx_reg 150
+
+#define GRP1b NULL, NULL, 0
+#define GRP1S NULL, NULL, 1
+#define GRP1Ss NULL, NULL, 2
+#define GRP2b NULL, NULL, 3
+#define GRP2S NULL, NULL, 4
+#define GRP2b_one NULL, NULL, 5
+#define GRP2S_one NULL, NULL, 6
+#define GRP2b_cl NULL, NULL, 7
+#define GRP2S_cl NULL, NULL, 8
+#define GRP3b NULL, NULL, 9
+#define GRP3S NULL, NULL, 10
+#define GRP4 NULL, NULL, 11
+#define GRP5 NULL, NULL, 12
+#define GRP6 NULL, NULL, 13
+#define GRP7 NULL, NULL, 14
+#define GRP8 NULL, NULL, 15
+
+#define FLOATCODE 50
+#define FLOAT NULL, NULL, FLOATCODE
+
+struct dis386 {
+ char *name;
+ int (*op1)();
+ int bytemode1;
+ int (*op2)();
+ int bytemode2;
+ int (*op3)();
+ int bytemode3;
+};
+
+struct dis386 dis386[] = {
+ /* 00 */
+ { "addb", Eb, Gb },
+ { "addS", Ev, Gv },
+ { "addb", Gb, Eb },
+ { "addS", Gv, Ev },
+ { "addb", AL, Ib },
+ { "addS", eAX, Iv },
+ { "pushl", es },
+ { "popl", es },
+ /* 08 */
+ { "orb", Eb, Gb },
+ { "orS", Ev, Gv },
+ { "orb", Gb, Eb },
+ { "orS", Gv, Ev },
+ { "orb", AL, Ib },
+ { "orS", eAX, Iv },
+ { "pushl", cs },
+ { "(bad)" }, /* 0x0f extended opcode escape */
+ /* 10 */
+ { "adcb", Eb, Gb },
+ { "adcS", Ev, Gv },
+ { "adcb", Gb, Eb },
+ { "adcS", Gv, Ev },
+ { "adcb", AL, Ib },
+ { "adcS", eAX, Iv },
+ { "pushl", ss },
+ { "popl", ss },
+ /* 18 */
+ { "sbbb", Eb, Gb },
+ { "sbbS", Ev, Gv },
+ { "sbbb", Gb, Eb },
+ { "sbbS", Gv, Ev },
+ { "sbbb", AL, Ib },
+ { "sbbS", eAX, Iv },
+ { "pushl", ds },
+ { "popl", ds },
+ /* 20 */
+ { "andb", Eb, Gb },
+ { "andS", Ev, Gv },
+ { "andb", Gb, Eb },
+ { "andS", Gv, Ev },
+ { "andb", AL, Ib },
+ { "andS", eAX, Iv },
+ { "(bad)" }, /* SEG ES prefix */
+ { "daa" },
+ /* 28 */
+ { "subb", Eb, Gb },
+ { "subS", Ev, Gv },
+ { "subb", Gb, Eb },
+ { "subS", Gv, Ev },
+ { "subb", AL, Ib },
+ { "subS", eAX, Iv },
+ { "(bad)" }, /* SEG CS prefix */
+ { "das" },
+ /* 30 */
+ { "xorb", Eb, Gb },
+ { "xorS", Ev, Gv },
+ { "xorb", Gb, Eb },
+ { "xorS", Gv, Ev },
+ { "xorb", AL, Ib },
+ { "xorS", eAX, Iv },
+ { "(bad)" }, /* SEG SS prefix */
+ { "aaa" },
+ /* 38 */
+ { "cmpb", Eb, Gb },
+ { "cmpS", Ev, Gv },
+ { "cmpb", Gb, Eb },
+ { "cmpS", Gv, Ev },
+ { "cmpb", AL, Ib },
+ { "cmpS", eAX, Iv },
+ { "(bad)" }, /* SEG DS prefix */
+ { "aas" },
+ /* 40 */
+ { "incS", eAX },
+ { "incS", eCX },
+ { "incS", eDX },
+ { "incS", eBX },
+ { "incS", eSP },
+ { "incS", eBP },
+ { "incS", eSI },
+ { "incS", eDI },
+ /* 48 */
+ { "decS", eAX },
+ { "decS", eCX },
+ { "decS", eDX },
+ { "decS", eBX },
+ { "decS", eSP },
+ { "decS", eBP },
+ { "decS", eSI },
+ { "decS", eDI },
+ /* 50 */
+ { "pushS", eAX },
+ { "pushS", eCX },
+ { "pushS", eDX },
+ { "pushS", eBX },
+ { "pushS", eSP },
+ { "pushS", eBP },
+ { "pushS", eSI },
+ { "pushS", eDI },
+ /* 58 */
+ { "popS", eAX },
+ { "popS", eCX },
+ { "popS", eDX },
+ { "popS", eBX },
+ { "popS", eSP },
+ { "popS", eBP },
+ { "popS", eSI },
+ { "popS", eDI },
+ /* 60 */
+ { "pusha" },
+ { "popa" },
+ { "boundS", Gv, Ma },
+ { "arpl", Ew, Gw },
+ { "(bad)" }, /* seg fs */
+ { "(bad)" }, /* seg gs */
+ { "(bad)" }, /* op size prefix */
+ { "(bad)" }, /* adr size prefix */
+ /* 68 */
+ { "pushS", Iv }, /* 386 book wrong */
+ { "imulS", Gv, Ev, Iv },
+ { "pushl", sIb }, /* push of byte really pushes 4 bytes */
+ { "imulS", Gv, Ev, Ib },
+ { "insb", Yb, indirDX },
+ { "insS", Yv, indirDX },
+ { "outsb", indirDX, Xb },
+ { "outsS", indirDX, Xv },
+ /* 70 */
+ { "jo", Jb },
+ { "jno", Jb },
+ { "jb", Jb },
+ { "jae", Jb },
+ { "je", Jb },
+ { "jne", Jb },
+ { "jbe", Jb },
+ { "ja", Jb },
+ /* 78 */
+ { "js", Jb },
+ { "jns", Jb },
+ { "jp", Jb },
+ { "jnp", Jb },
+ { "jl", Jb },
+ { "jnl", Jb },
+ { "jle", Jb },
+ { "jg", Jb },
+ /* 80 */
+ { GRP1b },
+ { GRP1S },
+ { "(bad)" },
+ { GRP1Ss },
+ { "testb", Eb, Gb },
+ { "testS", Ev, Gv },
+ { "xchgb", Eb, Gb },
+ { "xchgS", Ev, Gv },
+ /* 88 */
+ { "movb", Eb, Gb },
+ { "movS", Ev, Gv },
+ { "movb", Gb, Eb },
+ { "movS", Gv, Ev },
+ { "movw", Ew, Sw },
+ { "leaS", Gv, M },
+ { "movw", Sw, Ew },
+ { "popS", Ev },
+ /* 90 */
+ { "nop" },
+ { "xchgS", eCX, eAX },
+ { "xchgS", eDX, eAX },
+ { "xchgS", eBX, eAX },
+ { "xchgS", eSP, eAX },
+ { "xchgS", eBP, eAX },
+ { "xchgS", eSI, eAX },
+ { "xchgS", eDI, eAX },
+ /* 98 */
+ { "cwtl" },
+ { "cltd" },
+ { "lcall", Ap },
+ { "(bad)" }, /* fwait */
+ { "pushf" },
+ { "popf" },
+ { "sahf" },
+ { "lahf" },
+ /* a0 */
+ { "movb", AL, Ob },
+ { "movS", eAX, Ov },
+ { "movb", Ob, AL },
+ { "movS", Ov, eAX },
+ { "movsb", Yb, Xb },
+ { "movsS", Yv, Xv },
+ { "cmpsb", Yb, Xb },
+ { "cmpsS", Yv, Xv },
+ /* a8 */
+ { "testb", AL, Ib },
+ { "testS", eAX, Iv },
+ { "stosb", Yb, AL },
+ { "stosS", Yv, eAX },
+ { "lodsb", AL, Xb },
+ { "lodsS", eAX, Xv },
+ { "scasb", AL, Yb },
+ { "scasS", eAX, Yv },
+ /* b0 */
+ { "movb", AL, Ib },
+ { "movb", CL, Ib },
+ { "movb", DL, Ib },
+ { "movb", BL, Ib },
+ { "movb", AH, Ib },
+ { "movb", CH, Ib },
+ { "movb", DH, Ib },
+ { "movb", BH, Ib },
+ /* b8 */
+ { "movS", eAX, Iv },
+ { "movS", eCX, Iv },
+ { "movS", eDX, Iv },
+ { "movS", eBX, Iv },
+ { "movS", eSP, Iv },
+ { "movS", eBP, Iv },
+ { "movS", eSI, Iv },
+ { "movS", eDI, Iv },
+ /* c0 */
+ { GRP2b },
+ { GRP2S },
+ { "ret", Iw },
+ { "ret" },
+ { "lesS", Gv, Mp },
+ { "ldsS", Gv, Mp },
+ { "movb", Eb, Ib },
+ { "movS", Ev, Iv },
+ /* c8 */
+ { "enter", Iw, Ib },
+ { "leave" },
+ { "lret", Iw },
+ { "lret" },
+ { "int3" },
+ { "int", Ib },
+ { "into" },
+ { "iret" },
+ /* d0 */
+ { GRP2b_one },
+ { GRP2S_one },
+ { GRP2b_cl },
+ { GRP2S_cl },
+ { "aam", Ib },
+ { "aad", Ib },
+ { "(bad)" },
+ { "xlat" },
+ /* d8 */
+ { FLOAT },
+ { FLOAT },
+ { FLOAT },
+ { FLOAT },
+ { FLOAT },
+ { FLOAT },
+ { FLOAT },
+ { FLOAT },
+ /* e0 */
+ { "loopne", Jb },
+ { "loope", Jb },
+ { "loop", Jb },
+ { "jCcxz", Jb },
+ { "inb", AL, Ib },
+ { "inS", eAX, Ib },
+ { "outb", Ib, AL },
+ { "outS", Ib, eAX },
+ /* e8 */
+ { "call", Av },
+ { "jmp", Jv },
+ { "ljmp", Ap },
+ { "jmp", Jb },
+ { "inb", AL, indirDX },
+ { "inS", eAX, indirDX },
+ { "outb", indirDX, AL },
+ { "outS", indirDX, eAX },
+ /* f0 */
+ { "(bad)" }, /* lock prefix */
+ { "(bad)" },
+ { "(bad)" }, /* repne */
+ { "(bad)" }, /* repz */
+ { "hlt" },
+ { "cmc" },
+ { GRP3b },
+ { GRP3S },
+ /* f8 */
+ { "clc" },
+ { "stc" },
+ { "cli" },
+ { "sti" },
+ { "cld" },
+ { "std" },
+ { GRP4 },
+ { GRP5 },
+};
+
+struct dis386 dis386_twobyte[] = {
+ /* 00 */
+ { GRP6 },
+ { GRP7 },
+ { "larS", Gv, Ew },
+ { "lslS", Gv, Ew },
+ { "(bad)" },
+ { "(bad)" },
+ { "clts" },
+ { "(bad)" },
+ /* 08 */
+ { "invd" },
+ { "wbinvd" },
+ { "(bad)" }, { "(bad)" },
+ { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" },
+ /* 10 */
+ { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" },
+ { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" },
+ /* 18 */
+ { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" },
+ { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" },
+ /* 20 */
+ /* these are all backward in appendix A of the intel book */
+ { "movl", Rd, Cd },
+ { "movl", Rd, Dd },
+ { "movl", Cd, Rd },
+ { "movl", Dd, Rd },
+ { "movl", Rd, Td },
+ { "(bad)" },
+ { "movl", Td, Rd },
+ { "(bad)" },
+ /* 28 */
+ { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" },
+ { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" },
+ /* 30 */
+ { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" },
+ { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" },
+ /* 38 */
+ { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" },
+ { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" },
+ /* 40 */
+ { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" },
+ { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" },
+ /* 48 */
+ { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" },
+ { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" },
+ /* 50 */
+ { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" },
+ { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" },
+ /* 58 */
+ { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" },
+ { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" },
+ /* 60 */
+ { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" },
+ { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" },
+ /* 68 */
+ { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" },
+ { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" },
+ /* 70 */
+ { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" },
+ { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" },
+ /* 78 */
+ { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" },
+ { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" },
+ /* 80 */
+ { "jo", Jv },
+ { "jno", Jv },
+ { "jb", Jv },
+ { "jae", Jv },
+ { "je", Jv },
+ { "jne", Jv },
+ { "jbe", Jv },
+ { "ja", Jv },
+ /* 88 */
+ { "js", Jv },
+ { "jns", Jv },
+ { "jp", Jv },
+ { "jnp", Jv },
+ { "jl", Jv },
+ { "jge", Jv },
+ { "jle", Jv },
+ { "jg", Jv },
+ /* 90 */
+ { "seto", Eb },
+ { "setno", Eb },
+ { "setb", Eb },
+ { "setae", Eb },
+ { "sete", Eb },
+ { "setne", Eb },
+ { "setbe", Eb },
+ { "seta", Eb },
+ /* 98 */
+ { "sets", Eb },
+ { "setns", Eb },
+ { "setp", Eb },
+ { "setnp", Eb },
+ { "setl", Eb },
+ { "setge", Eb },
+ { "setle", Eb },
+ { "setg", Eb },
+ /* a0 */
+ { "pushl", fs },
+ { "popl", fs },
+ { "(bad)" },
+ { "btS", Ev, Gv },
+ { "shldS", Ev, Gv, Ib },
+ { "shldS", Ev, Gv, CL },
+ { "(bad)" },
+ { "(bad)" },
+ /* a8 */
+ { "pushl", gs },
+ { "popl", gs },
+ { "(bad)" },
+ { "btsS", Ev, Gv },
+ { "shrdS", Ev, Gv, Ib },
+ { "shrdS", Ev, Gv, CL },
+ { "(bad)" },
+ { "imulS", Gv, Ev },
+ /* b0 */
+ { "cmpxchgb", Eb, Gb },
+ { "cmpxchgS", Ev, Gv },
+ { "lssS", Gv, Mp }, /* 386 lists only Mp */
+ { "btrS", Ev, Gv },
+ { "lfsS", Gv, Mp }, /* 386 lists only Mp */
+ { "lgsS", Gv, Mp }, /* 386 lists only Mp */
+ { "movzbS", Gv, Eb },
+ { "movzwS", Gv, Ew },
+ /* b8 */
+ { "(bad)" },
+ { "(bad)" },
+ { GRP8 },
+ { "btcS", Ev, Gv },
+ { "bsfS", Gv, Ev },
+ { "bsrS", Gv, Ev },
+ { "movsbS", Gv, Eb },
+ { "movswS", Gv, Ew },
+ /* c0 */
+ { "xaddb", Eb, Gb },
+ { "xaddS", Ev, Gv },
+ { "(bad)" }, { "(bad)" },
+ { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" },
+ /* c8 */
+ { "bswap", eAX },
+ { "bswap", eCX },
+ { "bswap", eDX },
+ { "bswap", eBX },
+ { "bswap", eSP },
+ { "bswap", eBP },
+ { "bswap", eSI },
+ { "bswap", eDI },
+ /* d0 */
+ { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" },
+ { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" },
+ /* d8 */
+ { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" },
+ { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" },
+ /* e0 */
+ { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" },
+ { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" },
+ /* e8 */
+ { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" },
+ { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" },
+ /* f0 */
+ { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" },
+ { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" },
+ /* f8 */
+ { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" },
+ { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" },
+};
+
+static char obuf[100];
+static char *obufp;
+static char scratchbuf[100];
+static unsigned char *start_codep;
+static unsigned char *codep;
+static disassemble_info *the_info;
+static int mod;
+static int rm;
+static int reg;
+static void oappend ();
+
+static char *names32[]={
+ "%eax","%ecx","%edx","%ebx", "%esp","%ebp","%esi","%edi",
+};
+static char *names16[] = {
+ "%ax","%cx","%dx","%bx","%sp","%bp","%si","%di",
+};
+static char *names8[] = {
+ "%al","%cl","%dl","%bl","%ah","%ch","%dh","%bh",
+};
+static char *names_seg[] = {
+ "%es","%cs","%ss","%ds","%fs","%gs","%?","%?",
+};
+
+struct dis386 grps[][8] = {
+ /* GRP1b */
+ {
+ { "addb", Eb, Ib },
+ { "orb", Eb, Ib },
+ { "adcb", Eb, Ib },
+ { "sbbb", Eb, Ib },
+ { "andb", Eb, Ib },
+ { "subb", Eb, Ib },
+ { "xorb", Eb, Ib },
+ { "cmpb", Eb, Ib }
+ },
+ /* GRP1S */
+ {
+ { "addS", Ev, Iv },
+ { "orS", Ev, Iv },
+ { "adcS", Ev, Iv },
+ { "sbbS", Ev, Iv },
+ { "andS", Ev, Iv },
+ { "subS", Ev, Iv },
+ { "xorS", Ev, Iv },
+ { "cmpS", Ev, Iv }
+ },
+ /* GRP1Ss */
+ {
+ { "addS", Ev, sIb },
+ { "orS", Ev, sIb },
+ { "adcS", Ev, sIb },
+ { "sbbS", Ev, sIb },
+ { "andS", Ev, sIb },
+ { "subS", Ev, sIb },
+ { "xorS", Ev, sIb },
+ { "cmpS", Ev, sIb }
+ },
+ /* GRP2b */
+ {
+ { "rolb", Eb, Ib },
+ { "rorb", Eb, Ib },
+ { "rclb", Eb, Ib },
+ { "rcrb", Eb, Ib },
+ { "shlb", Eb, Ib },
+ { "shrb", Eb, Ib },
+ { "(bad)" },
+ { "sarb", Eb, Ib },
+ },
+ /* GRP2S */
+ {
+ { "rolS", Ev, Ib },
+ { "rorS", Ev, Ib },
+ { "rclS", Ev, Ib },
+ { "rcrS", Ev, Ib },
+ { "shlS", Ev, Ib },
+ { "shrS", Ev, Ib },
+ { "(bad)" },
+ { "sarS", Ev, Ib },
+ },
+ /* GRP2b_one */
+ {
+ { "rolb", Eb },
+ { "rorb", Eb },
+ { "rclb", Eb },
+ { "rcrb", Eb },
+ { "shlb", Eb },
+ { "shrb", Eb },
+ { "(bad)" },
+ { "sarb", Eb },
+ },
+ /* GRP2S_one */
+ {
+ { "rolS", Ev },
+ { "rorS", Ev },
+ { "rclS", Ev },
+ { "rcrS", Ev },
+ { "shlS", Ev },
+ { "shrS", Ev },
+ { "(bad)" },
+ { "sarS", Ev },
+ },
+ /* GRP2b_cl */
+ {
+ { "rolb", Eb, CL },
+ { "rorb", Eb, CL },
+ { "rclb", Eb, CL },
+ { "rcrb", Eb, CL },
+ { "shlb", Eb, CL },
+ { "shrb", Eb, CL },
+ { "(bad)" },
+ { "sarb", Eb, CL },
+ },
+ /* GRP2S_cl */
+ {
+ { "rolS", Ev, CL },
+ { "rorS", Ev, CL },
+ { "rclS", Ev, CL },
+ { "rcrS", Ev, CL },
+ { "shlS", Ev, CL },
+ { "shrS", Ev, CL },
+ { "(bad)" },
+ { "sarS", Ev, CL }
+ },
+ /* GRP3b */
+ {
+ { "testb", Eb, Ib },
+ { "(bad)", Eb },
+ { "notb", Eb },
+ { "negb", Eb },
+ { "mulb", AL, Eb },
+ { "imulb", AL, Eb },
+ { "divb", AL, Eb },
+ { "idivb", AL, Eb }
+ },
+ /* GRP3S */
+ {
+ { "testS", Ev, Iv },
+ { "(bad)" },
+ { "notS", Ev },
+ { "negS", Ev },
+ { "mulS", eAX, Ev },
+ { "imulS", eAX, Ev },
+ { "divS", eAX, Ev },
+ { "idivS", eAX, Ev },
+ },
+ /* GRP4 */
+ {
+ { "incb", Eb },
+ { "decb", Eb },
+ { "(bad)" },
+ { "(bad)" },
+ { "(bad)" },
+ { "(bad)" },
+ { "(bad)" },
+ { "(bad)" },
+ },
+ /* GRP5 */
+ {
+ { "incS", Ev },
+ { "decS", Ev },
+ { "call", indirEv },
+ { "lcall", indirEv },
+ { "jmp", indirEv },
+ { "ljmp", indirEv },
+ { "pushS", Ev },
+ { "(bad)" },
+ },
+ /* GRP6 */
+ {
+ { "sldt", Ew },
+ { "str", Ew },
+ { "lldt", Ew },
+ { "ltr", Ew },
+ { "verr", Ew },
+ { "verw", Ew },
+ { "(bad)" },
+ { "(bad)" }
+ },
+ /* GRP7 */
+ {
+ { "sgdt", Ew },
+ { "sidt", Ew },
+ { "lgdt", Ew },
+ { "lidt", Ew },
+ { "smsw", Ew },
+ { "(bad)" },
+ { "lmsw", Ew },
+ { "invlpg", Ew },
+ },
+ /* GRP8 */
+ {
+ { "(bad)" },
+ { "(bad)" },
+ { "(bad)" },
+ { "(bad)" },
+ { "btS", Ev, Ib },
+ { "btsS", Ev, Ib },
+ { "btrS", Ev, Ib },
+ { "btcS", Ev, Ib },
+ }
+};
+
+#define PREFIX_REPZ 1
+#define PREFIX_REPNZ 2
+#define PREFIX_LOCK 4
+#define PREFIX_CS 8
+#define PREFIX_SS 0x10
+#define PREFIX_DS 0x20
+#define PREFIX_ES 0x40
+#define PREFIX_FS 0x80
+#define PREFIX_GS 0x100
+#define PREFIX_DATA 0x200
+#define PREFIX_ADR 0x400
+#define PREFIX_FWAIT 0x800
+
+static int prefixes;
+
+static void
+ckprefix ()
+{
+ prefixes = 0;
+ while (1)
+ {
+ FETCH_DATA (the_info, codep + 1);
+ switch (*codep)
+ {
+ case 0xf3:
+ prefixes |= PREFIX_REPZ;
+ break;
+ case 0xf2:
+ prefixes |= PREFIX_REPNZ;
+ break;
+ case 0xf0:
+ prefixes |= PREFIX_LOCK;
+ break;
+ case 0x2e:
+ prefixes |= PREFIX_CS;
+ break;
+ case 0x36:
+ prefixes |= PREFIX_SS;
+ break;
+ case 0x3e:
+ prefixes |= PREFIX_DS;
+ break;
+ case 0x26:
+ prefixes |= PREFIX_ES;
+ break;
+ case 0x64:
+ prefixes |= PREFIX_FS;
+ break;
+ case 0x65:
+ prefixes |= PREFIX_GS;
+ break;
+ case 0x66:
+ prefixes |= PREFIX_DATA;
+ break;
+ case 0x67:
+ prefixes |= PREFIX_ADR;
+ break;
+ case 0x9b:
+ prefixes |= PREFIX_FWAIT;
+ break;
+ default:
+ return;
+ }
+ codep++;
+ }
+}
+
+static int dflag;
+static int aflag;
+
+static char op1out[100], op2out[100], op3out[100];
+static int op_address[3], op_ad, op_index[3];
+static int start_pc;
+
+
+/*
+ * On the 386's of 1988, the maximum length of an instruction is 15 bytes.
+ * (see topic "Redundant prefixes" in the "Differences from 8086"
+ * section of the "Virtual 8086 Mode" chapter.)
+ * 'pc' should be the address of this instruction, it will
+ * be used to print the target address if this is a relative jump or call
+ * The function returns the length of this instruction in bytes.
+ */
+
+int
+print_insn_i386 (pc, info)
+ bfd_vma pc;
+ disassemble_info *info;
+{
+ struct dis386 *dp;
+ int i;
+ int enter_instruction;
+ char *first, *second, *third;
+ int needcomma;
+
+ struct dis_private priv;
+ bfd_byte *inbuf = priv.the_buffer;
+
+ info->private_data = (PTR) &priv;
+ priv.max_fetched = priv.the_buffer;
+ priv.insn_start = pc;
+ if (setjmp (priv.bailout) != 0)
+ /* Error return. */
+ return -1;
+
+ obuf[0] = 0;
+ op1out[0] = 0;
+ op2out[0] = 0;
+ op3out[0] = 0;
+
+ op_index[0] = op_index[1] = op_index[2] = -1;
+
+ the_info = info;
+ start_pc = pc;
+ start_codep = inbuf;
+ codep = inbuf;
+
+ ckprefix ();
+
+ FETCH_DATA (info, codep + 1);
+ if (*codep == 0xc8)
+ enter_instruction = 1;
+ else
+ enter_instruction = 0;
+
+ obufp = obuf;
+
+ if (prefixes & PREFIX_REPZ)
+ oappend ("repz ");
+ if (prefixes & PREFIX_REPNZ)
+ oappend ("repnz ");
+ if (prefixes & PREFIX_LOCK)
+ oappend ("lock ");
+
+ if ((prefixes & PREFIX_FWAIT)
+ && ((*codep < 0xd8) || (*codep > 0xdf)))
+ {
+ /* fwait not followed by floating point instruction */
+ (*info->fprintf_func) (info->stream, "fwait");
+ return (1);
+ }
+
+ /* these would be initialized to 0 if disassembling for 8086 or 286 */
+ dflag = 1;
+ aflag = 1;
+
+ if (prefixes & PREFIX_DATA)
+ dflag ^= 1;
+
+ if (prefixes & PREFIX_ADR)
+ {
+ aflag ^= 1;
+ oappend ("addr16 ");
+ }
+
+ if (*codep == 0x0f)
+ {
+ FETCH_DATA (info, codep + 2);
+ dp = &dis386_twobyte[*++codep];
+ }
+ else
+ dp = &dis386[*codep];
+ codep++;
+
+ /* Fetch the mod/reg/rm byte. FIXME: We should be only fetching
+ this if we need it. As it is, this code loses if there is a
+ one-byte instruction (without a mod/reg/rm byte) at the end of
+ the address space. */
+
+ FETCH_DATA (info, codep + 1);
+ mod = (*codep >> 6) & 3;
+ reg = (*codep >> 3) & 7;
+ rm = *codep & 7;
+
+ if (dp->name == NULL && dp->bytemode1 == FLOATCODE)
+ {
+ dofloat ();
+ }
+ else
+ {
+ if (dp->name == NULL)
+ dp = &grps[dp->bytemode1][reg];
+
+ putop (dp->name);
+
+ obufp = op1out;
+ op_ad = 2;
+ if (dp->op1)
+ (*dp->op1)(dp->bytemode1);
+
+ obufp = op2out;
+ op_ad = 1;
+ if (dp->op2)
+ (*dp->op2)(dp->bytemode2);
+
+ obufp = op3out;
+ op_ad = 0;
+ if (dp->op3)
+ (*dp->op3)(dp->bytemode3);
+ }
+
+ obufp = obuf + strlen (obuf);
+ for (i = strlen (obuf); i < 6; i++)
+ oappend (" ");
+ oappend (" ");
+ (*info->fprintf_func) (info->stream, "%s", obuf);
+
+ /* enter instruction is printed with operands in the
+ * same order as the intel book; everything else
+ * is printed in reverse order
+ */
+ if (enter_instruction)
+ {
+ first = op1out;
+ second = op2out;
+ third = op3out;
+ op_ad = op_index[0];
+ op_index[0] = op_index[2];
+ op_index[2] = op_ad;
+ }
+ else
+ {
+ first = op3out;
+ second = op2out;
+ third = op1out;
+ }
+ needcomma = 0;
+ if (*first)
+ {
+ if (op_index[0] != -1)
+ (*info->print_address_func) (op_address[op_index[0]], info);
+ else
+ (*info->fprintf_func) (info->stream, "%s", first);
+ needcomma = 1;
+ }
+ if (*second)
+ {
+ if (needcomma)
+ (*info->fprintf_func) (info->stream, ",");
+ if (op_index[1] != -1)
+ (*info->print_address_func) (op_address[op_index[1]], info);
+ else
+ (*info->fprintf_func) (info->stream, "%s", second);
+ needcomma = 1;
+ }
+ if (*third)
+ {
+ if (needcomma)
+ (*info->fprintf_func) (info->stream, ",");
+ if (op_index[2] != -1)
+ (*info->print_address_func) (op_address[op_index[2]], info);
+ else
+ (*info->fprintf_func) (info->stream, "%s", third);
+ }
+ return (codep - inbuf);
+}
+
+char *float_mem[] = {
+ /* d8 */
+ "fadds",
+ "fmuls",
+ "fcoms",
+ "fcomps",
+ "fsubs",
+ "fsubrs",
+ "fdivs",
+ "fdivrs",
+ /* d9 */
+ "flds",
+ "(bad)",
+ "fsts",
+ "fstps",
+ "fldenv",
+ "fldcw",
+ "fNstenv",
+ "fNstcw",
+ /* da */
+ "fiaddl",
+ "fimull",
+ "ficoml",
+ "ficompl",
+ "fisubl",
+ "fisubrl",
+ "fidivl",
+ "fidivrl",
+ /* db */
+ "fildl",
+ "(bad)",
+ "fistl",
+ "fistpl",
+ "(bad)",
+ "fldt",
+ "(bad)",
+ "fstpt",
+ /* dc */
+ "faddl",
+ "fmull",
+ "fcoml",
+ "fcompl",
+ "fsubl",
+ "fsubrl",
+ "fdivl",
+ "fdivrl",
+ /* dd */
+ "fldl",
+ "(bad)",
+ "fstl",
+ "fstpl",
+ "frstor",
+ "(bad)",
+ "fNsave",
+ "fNstsw",
+ /* de */
+ "fiadd",
+ "fimul",
+ "ficom",
+ "ficomp",
+ "fisub",
+ "fisubr",
+ "fidiv",
+ "fidivr",
+ /* df */
+ "fild",
+ "(bad)",
+ "fist",
+ "fistp",
+ "fbld",
+ "fildll",
+ "fbstp",
+ "fistpll",
+};
+
+#define ST OP_ST, 0
+#define STi OP_STi, 0
+int OP_ST(), OP_STi();
+
+#define FGRPd9_2 NULL, NULL, 0
+#define FGRPd9_4 NULL, NULL, 1
+#define FGRPd9_5 NULL, NULL, 2
+#define FGRPd9_6 NULL, NULL, 3
+#define FGRPd9_7 NULL, NULL, 4
+#define FGRPda_5 NULL, NULL, 5
+#define FGRPdb_4 NULL, NULL, 6
+#define FGRPde_3 NULL, NULL, 7
+#define FGRPdf_4 NULL, NULL, 8
+
+struct dis386 float_reg[][8] = {
+ /* d8 */
+ {
+ { "fadd", ST, STi },
+ { "fmul", ST, STi },
+ { "fcom", STi },
+ { "fcomp", STi },
+ { "fsub", ST, STi },
+ { "fsubr", ST, STi },
+ { "fdiv", ST, STi },
+ { "fdivr", ST, STi },
+ },
+ /* d9 */
+ {
+ { "fld", STi },
+ { "fxch", STi },
+ { FGRPd9_2 },
+ { "(bad)" },
+ { FGRPd9_4 },
+ { FGRPd9_5 },
+ { FGRPd9_6 },
+ { FGRPd9_7 },
+ },
+ /* da */
+ {
+ { "(bad)" },
+ { "(bad)" },
+ { "(bad)" },
+ { "(bad)" },
+ { "(bad)" },
+ { FGRPda_5 },
+ { "(bad)" },
+ { "(bad)" },
+ },
+ /* db */
+ {
+ { "(bad)" },
+ { "(bad)" },
+ { "(bad)" },
+ { "(bad)" },
+ { FGRPdb_4 },
+ { "(bad)" },
+ { "(bad)" },
+ { "(bad)" },
+ },
+ /* dc */
+ {
+ { "fadd", STi, ST },
+ { "fmul", STi, ST },
+ { "(bad)" },
+ { "(bad)" },
+ { "fsub", STi, ST },
+ { "fsubr", STi, ST },
+ { "fdiv", STi, ST },
+ { "fdivr", STi, ST },
+ },
+ /* dd */
+ {
+ { "ffree", STi },
+ { "(bad)" },
+ { "fst", STi },
+ { "fstp", STi },
+ { "fucom", STi },
+ { "fucomp", STi },
+ { "(bad)" },
+ { "(bad)" },
+ },
+ /* de */
+ {
+ { "faddp", STi, ST },
+ { "fmulp", STi, ST },
+ { "(bad)" },
+ { FGRPde_3 },
+ { "fsubp", STi, ST },
+ { "fsubrp", STi, ST },
+ { "fdivp", STi, ST },
+ { "fdivrp", STi, ST },
+ },
+ /* df */
+ {
+ { "(bad)" },
+ { "(bad)" },
+ { "(bad)" },
+ { "(bad)" },
+ { FGRPdf_4 },
+ { "(bad)" },
+ { "(bad)" },
+ { "(bad)" },
+ },
+};
+
+
+char *fgrps[][8] = {
+ /* d9_2 0 */
+ {
+ "fnop","(bad)","(bad)","(bad)","(bad)","(bad)","(bad)","(bad)",
+ },
+
+ /* d9_4 1 */
+ {
+ "fchs","fabs","(bad)","(bad)","ftst","fxam","(bad)","(bad)",
+ },
+
+ /* d9_5 2 */
+ {
+ "fld1","fldl2t","fldl2e","fldpi","fldlg2","fldln2","fldz","(bad)",
+ },
+
+ /* d9_6 3 */
+ {
+ "f2xm1","fyl2x","fptan","fpatan","fxtract","fprem1","fdecstp","fincstp",
+ },
+
+ /* d9_7 4 */
+ {
+ "fprem","fyl2xp1","fsqrt","fsincos","frndint","fscale","fsin","fcos",
+ },
+
+ /* da_5 5 */
+ {
+ "(bad)","fucompp","(bad)","(bad)","(bad)","(bad)","(bad)","(bad)",
+ },
+
+ /* db_4 6 */
+ {
+ "feni(287 only)","fdisi(287 only)","fNclex","fNinit",
+ "fNsetpm(287 only)","(bad)","(bad)","(bad)",
+ },
+
+ /* de_3 7 */
+ {
+ "(bad)","fcompp","(bad)","(bad)","(bad)","(bad)","(bad)","(bad)",
+ },
+
+ /* df_4 8 */
+ {
+ "fNstsw","(bad)","(bad)","(bad)","(bad)","(bad)","(bad)","(bad)",
+ },
+};
+
+static void
+dofloat ()
+{
+ struct dis386 *dp;
+ unsigned char floatop;
+
+ floatop = codep[-1];
+
+ if (mod != 3)
+ {
+ putop (float_mem[(floatop - 0xd8) * 8 + reg]);
+ obufp = op1out;
+ OP_E (v_mode);
+ return;
+ }
+ codep++;
+
+ dp = &float_reg[floatop - 0xd8][reg];
+ if (dp->name == NULL)
+ {
+ putop (fgrps[dp->bytemode1][rm]);
+ /* instruction fnstsw is only one with strange arg */
+ if (floatop == 0xdf
+ && FETCH_DATA (the_info, codep + 1)
+ && *codep == 0xe0)
+ strcpy (op1out, "%eax");
+ }
+ else
+ {
+ putop (dp->name);
+ obufp = op1out;
+ if (dp->op1)
+ (*dp->op1)(dp->bytemode1);
+ obufp = op2out;
+ if (dp->op2)
+ (*dp->op2)(dp->bytemode2);
+ }
+}
+
+/* ARGSUSED */
+int
+OP_ST (ignore)
+ int ignore;
+{
+ oappend ("%st");
+ return (0);
+}
+
+/* ARGSUSED */
+int
+OP_STi (ignore)
+ int ignore;
+{
+ sprintf (scratchbuf, "%%st(%d)", rm);
+ oappend (scratchbuf);
+ return (0);
+}
+
+
+/* capital letters in template are macros */
+static void
+putop (template)
+ char *template;
+{
+ char *p;
+
+ for (p = template; *p; p++)
+ {
+ switch (*p)
+ {
+ default:
+ *obufp++ = *p;
+ break;
+ case 'C': /* For jcxz/jecxz */
+ if (aflag == 0)
+ *obufp++ = 'e';
+ break;
+ case 'N':
+ if ((prefixes & PREFIX_FWAIT) == 0)
+ *obufp++ = 'n';
+ break;
+ case 'S':
+ /* operand size flag */
+ if (dflag)
+ *obufp++ = 'l';
+ else
+ *obufp++ = 'w';
+ break;
+ }
+ }
+ *obufp = 0;
+}
+
+static void
+oappend (s)
+ char *s;
+{
+ strcpy (obufp, s);
+ obufp += strlen (s);
+ *obufp = 0;
+}
+
+static void
+append_prefix ()
+{
+ if (prefixes & PREFIX_CS)
+ oappend ("%cs:");
+ if (prefixes & PREFIX_DS)
+ oappend ("%ds:");
+ if (prefixes & PREFIX_SS)
+ oappend ("%ss:");
+ if (prefixes & PREFIX_ES)
+ oappend ("%es:");
+ if (prefixes & PREFIX_FS)
+ oappend ("%fs:");
+ if (prefixes & PREFIX_GS)
+ oappend ("%gs:");
+}
+
+int
+OP_indirE (bytemode)
+ int bytemode;
+{
+ oappend ("*");
+ OP_E (bytemode);
+ return (0);
+}
+
+int
+OP_E (bytemode)
+ int bytemode;
+{
+ int disp;
+ int havesib;
+ int base;
+ int index;
+ int scale;
+ int havebase;
+
+ /* skip mod/rm byte */
+ codep++;
+
+ havesib = 0;
+ havebase = 0;
+ disp = 0;
+
+ if (mod == 3)
+ {
+ switch (bytemode)
+ {
+ case b_mode:
+ oappend (names8[rm]);
+ break;
+ case w_mode:
+ oappend (names16[rm]);
+ break;
+ case v_mode:
+ if (dflag)
+ oappend (names32[rm]);
+ else
+ oappend (names16[rm]);
+ break;
+ default:
+ oappend ("<bad dis table>");
+ break;
+ }
+ return (0);
+ }
+
+ append_prefix ();
+ if (rm == 4)
+ {
+ havesib = 1;
+ havebase = 1;
+ FETCH_DATA (the_info, codep + 1);
+ scale = (*codep >> 6) & 3;
+ index = (*codep >> 3) & 7;
+ base = *codep & 7;
+ codep++;
+ }
+
+ switch (mod)
+ {
+ case 0:
+ switch (rm)
+ {
+ case 4:
+ /* implies havesib and havebase */
+ if (base == 5) {
+ havebase = 0;
+ disp = get32 ();
+ }
+ break;
+ case 5:
+ disp = get32 ();
+ break;
+ default:
+ havebase = 1;
+ base = rm;
+ break;
+ }
+ break;
+ case 1:
+ FETCH_DATA (the_info, codep + 1);
+ disp = *(char *)codep++;
+ if (rm != 4)
+ {
+ havebase = 1;
+ base = rm;
+ }
+ break;
+ case 2:
+ disp = get32 ();
+ if (rm != 4)
+ {
+ havebase = 1;
+ base = rm;
+ }
+ break;
+ }
+
+ if (mod != 0 || rm == 5 || (havesib && base == 5))
+ {
+ sprintf (scratchbuf, "0x%x", disp);
+ oappend (scratchbuf);
+ }
+
+ if (havebase || havesib)
+ {
+ oappend ("(");
+ if (havebase)
+ oappend (names32[base]);
+ if (havesib)
+ {
+ if (index != 4)
+ {
+ sprintf (scratchbuf, ",%s", names32[index]);
+ oappend (scratchbuf);
+ }
+ sprintf (scratchbuf, ",%d", 1 << scale);
+ oappend (scratchbuf);
+ }
+ oappend (")");
+ }
+ return (0);
+}
+
+int
+OP_G (bytemode)
+ int bytemode;
+{
+ switch (bytemode)
+ {
+ case b_mode:
+ oappend (names8[reg]);
+ break;
+ case w_mode:
+ oappend (names16[reg]);
+ break;
+ case d_mode:
+ oappend (names32[reg]);
+ break;
+ case v_mode:
+ if (dflag)
+ oappend (names32[reg]);
+ else
+ oappend (names16[reg]);
+ break;
+ default:
+ oappend ("<internal disassembler error>");
+ break;
+ }
+ return (0);
+}
+
+static int
+get32 ()
+{
+ int x = 0;
+
+ FETCH_DATA (the_info, codep + 4);
+ x = *codep++ & 0xff;
+ x |= (*codep++ & 0xff) << 8;
+ x |= (*codep++ & 0xff) << 16;
+ x |= (*codep++ & 0xff) << 24;
+ return (x);
+}
+
+static int
+get16 ()
+{
+ int x = 0;
+
+ FETCH_DATA (the_info, codep + 2);
+ x = *codep++ & 0xff;
+ x |= (*codep++ & 0xff) << 8;
+ return (x);
+}
+
+static void
+set_op (op)
+ int op;
+{
+ op_index[op_ad] = op_ad;
+ op_address[op_ad] = op;
+}
+
+int
+OP_REG (code)
+ int code;
+{
+ char *s;
+
+ switch (code)
+ {
+ case indir_dx_reg: s = "(%dx)"; break;
+ case ax_reg: case cx_reg: case dx_reg: case bx_reg:
+ case sp_reg: case bp_reg: case si_reg: case di_reg:
+ s = names16[code - ax_reg];
+ break;
+ case es_reg: case ss_reg: case cs_reg:
+ case ds_reg: case fs_reg: case gs_reg:
+ s = names_seg[code - es_reg];
+ break;
+ case al_reg: case ah_reg: case cl_reg: case ch_reg:
+ case dl_reg: case dh_reg: case bl_reg: case bh_reg:
+ s = names8[code - al_reg];
+ break;
+ case eAX_reg: case eCX_reg: case eDX_reg: case eBX_reg:
+ case eSP_reg: case eBP_reg: case eSI_reg: case eDI_reg:
+ if (dflag)
+ s = names32[code - eAX_reg];
+ else
+ s = names16[code - eAX_reg];
+ break;
+ default:
+ s = "<internal disassembler error>";
+ break;
+ }
+ oappend (s);
+ return (0);
+}
+
+int
+OP_I (bytemode)
+ int bytemode;
+{
+ int op;
+
+ switch (bytemode)
+ {
+ case b_mode:
+ FETCH_DATA (the_info, codep + 1);
+ op = *codep++ & 0xff;
+ break;
+ case v_mode:
+ if (dflag)
+ op = get32 ();
+ else
+ op = get16 ();
+ break;
+ case w_mode:
+ op = get16 ();
+ break;
+ default:
+ oappend ("<internal disassembler error>");
+ return (0);
+ }
+ sprintf (scratchbuf, "$0x%x", op);
+ oappend (scratchbuf);
+ return (0);
+}
+
+int
+OP_sI (bytemode)
+ int bytemode;
+{
+ int op;
+
+ switch (bytemode)
+ {
+ case b_mode:
+ FETCH_DATA (the_info, codep + 1);
+ op = *(char *)codep++;
+ break;
+ case v_mode:
+ if (dflag)
+ op = get32 ();
+ else
+ op = (short)get16();
+ break;
+ case w_mode:
+ op = (short)get16 ();
+ break;
+ default:
+ oappend ("<internal disassembler error>");
+ return (0);
+ }
+ sprintf (scratchbuf, "$0x%x", op);
+ oappend (scratchbuf);
+ return (0);
+}
+
+int
+OP_J (bytemode)
+ int bytemode;
+{
+ int disp;
+ int mask = -1;
+
+ switch (bytemode)
+ {
+ case b_mode:
+ FETCH_DATA (the_info, codep + 1);
+ disp = *(char *)codep++;
+ break;
+ case v_mode:
+ if (dflag)
+ disp = get32 ();
+ else
+ {
+ disp = (short)get16 ();
+ /* for some reason, a data16 prefix on a jump instruction
+ means that the pc is masked to 16 bits after the
+ displacement is added! */
+ mask = 0xffff;
+ }
+ break;
+ default:
+ oappend ("<internal disassembler error>");
+ return (0);
+ }
+ disp = (start_pc + codep - start_codep + disp) & mask;
+ set_op (disp);
+ sprintf (scratchbuf, "0x%x", disp);
+ oappend (scratchbuf);
+ return (0);
+}
+
+/* ARGSUSED */
+int
+OP_SEG (dummy)
+ int dummy;
+{
+ static char *sreg[] = {
+ "%es","%cs","%ss","%ds","%fs","%gs","%?","%?",
+ };
+
+ oappend (sreg[reg]);
+ return (0);
+}
+
+int
+OP_DIR (size)
+ int size;
+{
+ int seg, offset;
+
+ switch (size)
+ {
+ case lptr:
+ if (aflag)
+ {
+ offset = get32 ();
+ seg = get16 ();
+ }
+ else
+ {
+ offset = get16 ();
+ seg = get16 ();
+ }
+ sprintf (scratchbuf, "0x%x,0x%x", seg, offset);
+ oappend (scratchbuf);
+ break;
+ case v_mode:
+ if (aflag)
+ offset = get32 ();
+ else
+ offset = (short)get16 ();
+
+ offset = start_pc + codep - start_codep + offset;
+ set_op (offset);
+ sprintf (scratchbuf, "0x%x", offset);
+ oappend (scratchbuf);
+ break;
+ default:
+ oappend ("<internal disassembler error>");
+ break;
+ }
+ return (0);
+}
+
+/* ARGSUSED */
+int
+OP_OFF (bytemode)
+ int bytemode;
+{
+ int off;
+
+ if (aflag)
+ off = get32 ();
+ else
+ off = get16 ();
+
+ sprintf (scratchbuf, "0x%x", off);
+ oappend (scratchbuf);
+ return (0);
+}
+
+/* ARGSUSED */
+int
+OP_ESDI (dummy)
+ int dummy;
+{
+ oappend ("%es:(");
+ oappend (aflag ? "%edi" : "%di");
+ oappend (")");
+ return (0);
+}
+
+/* ARGSUSED */
+int
+OP_DSSI (dummy)
+ int dummy;
+{
+ oappend ("%ds:(");
+ oappend (aflag ? "%esi" : "%si");
+ oappend (")");
+ return (0);
+}
+
+/* ARGSUSED */
+int
+OP_ONE (dummy)
+ int dummy;
+{
+ oappend ("1");
+ return (0);
+}
+
+/* ARGSUSED */
+int
+OP_C (dummy)
+ int dummy;
+{
+ codep++; /* skip mod/rm */
+ sprintf (scratchbuf, "%%cr%d", reg);
+ oappend (scratchbuf);
+ return (0);
+}
+
+/* ARGSUSED */
+int
+OP_D (dummy)
+ int dummy;
+{
+ codep++; /* skip mod/rm */
+ sprintf (scratchbuf, "%%db%d", reg);
+ oappend (scratchbuf);
+ return (0);
+}
+
+/* ARGSUSED */
+int
+OP_T (dummy)
+ int dummy;
+{
+ codep++; /* skip mod/rm */
+ sprintf (scratchbuf, "%%tr%d", reg);
+ oappend (scratchbuf);
+ return (0);
+}
+
+int
+OP_rm (bytemode)
+ int bytemode;
+{
+ switch (bytemode)
+ {
+ case d_mode:
+ oappend (names32[rm]);
+ break;
+ case w_mode:
+ oappend (names16[rm]);
+ break;
+ }
+ return (0);
+}
diff --git a/gnu/usr.bin/gdb/gdb/i386-pinsn.c b/gnu/usr.bin/gdb/gdb/i386-pinsn.c
new file mode 100644
index 0000000..c11ee49
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/i386-pinsn.c
@@ -0,0 +1,37 @@
+/* Print i386 instructions for GDB, the GNU debugger.
+ Copyright 1986, 1987, 1989, 1991, 1992, 1993 Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "defs.h"
+#include "dis-asm.h"
+
+
+/* Print the instruction at address MEMADDR in debugged memory,
+ on STREAM. Returns length of the instruction, in bytes. */
+
+int
+print_insn (memaddr, stream)
+ CORE_ADDR memaddr;
+ GDB_FILE *stream;
+{
+ disassemble_info info;
+
+ GDB_INIT_DISASSEMBLE_INFO(info, stream);
+
+ return print_insn_i386 (memaddr, &info);
+}
diff --git a/gnu/usr.bin/gdb/gdb/i386-tdep.c b/gnu/usr.bin/gdb/gdb/i386-tdep.c
new file mode 100644
index 0000000..2247dd1
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/i386-tdep.c
@@ -0,0 +1,668 @@
+/* Intel 386 target-dependent stuff.
+ Copyright (C) 1988, 1989, 1991, 1994 Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "defs.h"
+#include "frame.h"
+#include "inferior.h"
+#include "gdbcore.h"
+#include "target.h"
+#include "floatformat.h"
+#include "symtab.h"
+
+static long
+i386_get_frame_setup PARAMS ((int));
+
+static void
+i386_follow_jump PARAMS ((void));
+
+static void
+codestream_read PARAMS ((unsigned char *, int));
+
+static void
+codestream_seek PARAMS ((int));
+
+static unsigned char
+codestream_fill PARAMS ((int));
+
+/* helper functions for tm-i386.h */
+
+/* Stdio style buffering was used to minimize calls to ptrace, but this
+ buffering did not take into account that the code section being accessed
+ may not be an even number of buffers long (even if the buffer is only
+ sizeof(int) long). In cases where the code section size happened to
+ be a non-integral number of buffers long, attempting to read the last
+ buffer would fail. Simply using target_read_memory and ignoring errors,
+ rather than read_memory, is not the correct solution, since legitimate
+ access errors would then be totally ignored. To properly handle this
+ situation and continue to use buffering would require that this code
+ be able to determine the minimum code section size granularity (not the
+ alignment of the section itself, since the actual failing case that
+ pointed out this problem had a section alignment of 4 but was not a
+ multiple of 4 bytes long), on a target by target basis, and then
+ adjust it's buffer size accordingly. This is messy, but potentially
+ feasible. It probably needs the bfd library's help and support. For
+ now, the buffer size is set to 1. (FIXME -fnf) */
+
+#define CODESTREAM_BUFSIZ 1 /* Was sizeof(int), see note above. */
+static CORE_ADDR codestream_next_addr;
+static CORE_ADDR codestream_addr;
+static unsigned char codestream_buf[CODESTREAM_BUFSIZ];
+static int codestream_off;
+static int codestream_cnt;
+
+#define codestream_tell() (codestream_addr + codestream_off)
+#define codestream_peek() (codestream_cnt == 0 ? \
+ codestream_fill(1): codestream_buf[codestream_off])
+#define codestream_get() (codestream_cnt-- == 0 ? \
+ codestream_fill(0) : codestream_buf[codestream_off++])
+
+static unsigned char
+codestream_fill (peek_flag)
+ int peek_flag;
+{
+ codestream_addr = codestream_next_addr;
+ codestream_next_addr += CODESTREAM_BUFSIZ;
+ codestream_off = 0;
+ codestream_cnt = CODESTREAM_BUFSIZ;
+ read_memory (codestream_addr, (char *) codestream_buf, CODESTREAM_BUFSIZ);
+
+ if (peek_flag)
+ return (codestream_peek());
+ else
+ return (codestream_get());
+}
+
+static void
+codestream_seek (place)
+ int place;
+{
+ codestream_next_addr = place / CODESTREAM_BUFSIZ;
+ codestream_next_addr *= CODESTREAM_BUFSIZ;
+ codestream_cnt = 0;
+ codestream_fill (1);
+ while (codestream_tell() != place)
+ codestream_get ();
+}
+
+static void
+codestream_read (buf, count)
+ unsigned char *buf;
+ int count;
+{
+ unsigned char *p;
+ int i;
+ p = buf;
+ for (i = 0; i < count; i++)
+ *p++ = codestream_get ();
+}
+
+/* next instruction is a jump, move to target */
+
+static void
+i386_follow_jump ()
+{
+ unsigned char buf[4];
+ long delta;
+
+ int data16;
+ CORE_ADDR pos;
+
+ pos = codestream_tell ();
+
+ data16 = 0;
+ if (codestream_peek () == 0x66)
+ {
+ codestream_get ();
+ data16 = 1;
+ }
+
+ switch (codestream_get ())
+ {
+ case 0xe9:
+ /* relative jump: if data16 == 0, disp32, else disp16 */
+ if (data16)
+ {
+ codestream_read (buf, 2);
+ delta = extract_signed_integer (buf, 2);
+
+ /* include size of jmp inst (including the 0x66 prefix). */
+ pos += delta + 4;
+ }
+ else
+ {
+ codestream_read (buf, 4);
+ delta = extract_signed_integer (buf, 4);
+
+ pos += delta + 5;
+ }
+ break;
+ case 0xeb:
+ /* relative jump, disp8 (ignore data16) */
+ codestream_read (buf, 1);
+ /* Sign-extend it. */
+ delta = extract_signed_integer (buf, 1);
+
+ pos += delta + 2;
+ break;
+ }
+ codestream_seek (pos);
+}
+
+/*
+ * find & return amound a local space allocated, and advance codestream to
+ * first register push (if any)
+ *
+ * if entry sequence doesn't make sense, return -1, and leave
+ * codestream pointer random
+ */
+
+static long
+i386_get_frame_setup (pc)
+ int pc;
+{
+ unsigned char op;
+
+ codestream_seek (pc);
+
+ i386_follow_jump ();
+
+ op = codestream_get ();
+
+ if (op == 0x58) /* popl %eax */
+ {
+ /*
+ * this function must start with
+ *
+ * popl %eax 0x58
+ * xchgl %eax, (%esp) 0x87 0x04 0x24
+ * or xchgl %eax, 0(%esp) 0x87 0x44 0x24 0x00
+ *
+ * (the system 5 compiler puts out the second xchg
+ * inst, and the assembler doesn't try to optimize it,
+ * so the 'sib' form gets generated)
+ *
+ * this sequence is used to get the address of the return
+ * buffer for a function that returns a structure
+ */
+ int pos;
+ unsigned char buf[4];
+ static unsigned char proto1[3] = { 0x87,0x04,0x24 };
+ static unsigned char proto2[4] = { 0x87,0x44,0x24,0x00 };
+ pos = codestream_tell ();
+ codestream_read (buf, 4);
+ if (memcmp (buf, proto1, 3) == 0)
+ pos += 3;
+ else if (memcmp (buf, proto2, 4) == 0)
+ pos += 4;
+
+ codestream_seek (pos);
+ op = codestream_get (); /* update next opcode */
+ }
+
+ if (op == 0x55) /* pushl %ebp */
+ {
+ /* check for movl %esp, %ebp - can be written two ways */
+ switch (codestream_get ())
+ {
+ case 0x8b:
+ if (codestream_get () != 0xec)
+ return (-1);
+ break;
+ case 0x89:
+ if (codestream_get () != 0xe5)
+ return (-1);
+ break;
+ default:
+ return (-1);
+ }
+ /* check for stack adjustment
+ *
+ * subl $XXX, %esp
+ *
+ * note: you can't subtract a 16 bit immediate
+ * from a 32 bit reg, so we don't have to worry
+ * about a data16 prefix
+ */
+ op = codestream_peek ();
+ if (op == 0x83)
+ {
+ /* subl with 8 bit immed */
+ codestream_get ();
+ if (codestream_get () != 0xec)
+ /* Some instruction starting with 0x83 other than subl. */
+ {
+ codestream_seek (codestream_tell () - 2);
+ return 0;
+ }
+ /* subl with signed byte immediate
+ * (though it wouldn't make sense to be negative)
+ */
+ return (codestream_get());
+ }
+ else if (op == 0x81)
+ {
+ char buf[4];
+ /* Maybe it is subl with 32 bit immedediate. */
+ codestream_get();
+ if (codestream_get () != 0xec)
+ /* Some instruction starting with 0x81 other than subl. */
+ {
+ codestream_seek (codestream_tell () - 2);
+ return 0;
+ }
+ /* It is subl with 32 bit immediate. */
+ codestream_read ((unsigned char *)buf, 4);
+ return extract_signed_integer (buf, 4);
+ }
+ else
+ {
+ return (0);
+ }
+ }
+ else if (op == 0xc8)
+ {
+ char buf[2];
+ /* enter instruction: arg is 16 bit unsigned immed */
+ codestream_read ((unsigned char *)buf, 2);
+ codestream_get (); /* flush final byte of enter instruction */
+ return extract_unsigned_integer (buf, 2);
+ }
+ return (-1);
+}
+
+/* Return number of args passed to a frame.
+ Can return -1, meaning no way to tell. */
+
+int
+i386_frame_num_args (fi)
+ struct frame_info *fi;
+{
+#if 1
+ return -1;
+#else
+ /* This loses because not only might the compiler not be popping the
+ args right after the function call, it might be popping args from both
+ this call and a previous one, and we would say there are more args
+ than there really are. */
+
+ int retpc;
+ unsigned char op;
+ struct frame_info *pfi;
+
+ /* on the 386, the instruction following the call could be:
+ popl %ecx - one arg
+ addl $imm, %esp - imm/4 args; imm may be 8 or 32 bits
+ anything else - zero args */
+
+ int frameless;
+
+ FRAMELESS_FUNCTION_INVOCATION (fi, frameless);
+ if (frameless)
+ /* In the absence of a frame pointer, GDB doesn't get correct values
+ for nameless arguments. Return -1, so it doesn't print any
+ nameless arguments. */
+ return -1;
+
+ pfi = get_prev_frame_info (fi);
+ if (pfi == 0)
+ {
+ /* Note: this can happen if we are looking at the frame for
+ main, because FRAME_CHAIN_VALID won't let us go into
+ start. If we have debugging symbols, that's not really
+ a big deal; it just means it will only show as many arguments
+ to main as are declared. */
+ return -1;
+ }
+ else
+ {
+ retpc = pfi->pc;
+ op = read_memory_integer (retpc, 1);
+ if (op == 0x59)
+ /* pop %ecx */
+ return 1;
+ else if (op == 0x83)
+ {
+ op = read_memory_integer (retpc+1, 1);
+ if (op == 0xc4)
+ /* addl $<signed imm 8 bits>, %esp */
+ return (read_memory_integer (retpc+2,1)&0xff)/4;
+ else
+ return 0;
+ }
+ else if (op == 0x81)
+ { /* add with 32 bit immediate */
+ op = read_memory_integer (retpc+1, 1);
+ if (op == 0xc4)
+ /* addl $<imm 32>, %esp */
+ return read_memory_integer (retpc+2, 4) / 4;
+ else
+ return 0;
+ }
+ else
+ {
+ return 0;
+ }
+ }
+#endif
+}
+
+/*
+ * parse the first few instructions of the function to see
+ * what registers were stored.
+ *
+ * We handle these cases:
+ *
+ * The startup sequence can be at the start of the function,
+ * or the function can start with a branch to startup code at the end.
+ *
+ * %ebp can be set up with either the 'enter' instruction, or
+ * 'pushl %ebp, movl %esp, %ebp' (enter is too slow to be useful,
+ * but was once used in the sys5 compiler)
+ *
+ * Local space is allocated just below the saved %ebp by either the
+ * 'enter' instruction, or by 'subl $<size>, %esp'. 'enter' has
+ * a 16 bit unsigned argument for space to allocate, and the
+ * 'addl' instruction could have either a signed byte, or
+ * 32 bit immediate.
+ *
+ * Next, the registers used by this function are pushed. In
+ * the sys5 compiler they will always be in the order: %edi, %esi, %ebx
+ * (and sometimes a harmless bug causes it to also save but not restore %eax);
+ * however, the code below is willing to see the pushes in any order,
+ * and will handle up to 8 of them.
+ *
+ * If the setup sequence is at the end of the function, then the
+ * next instruction will be a branch back to the start.
+ */
+
+void
+i386_frame_find_saved_regs (fip, fsrp)
+ struct frame_info *fip;
+ struct frame_saved_regs *fsrp;
+{
+ long locals;
+ unsigned char op;
+ CORE_ADDR dummy_bottom;
+ CORE_ADDR adr;
+ int i;
+
+ memset (fsrp, 0, sizeof *fsrp);
+
+ /* if frame is the end of a dummy, compute where the
+ * beginning would be
+ */
+ dummy_bottom = fip->frame - 4 - REGISTER_BYTES - CALL_DUMMY_LENGTH;
+
+ /* check if the PC is in the stack, in a dummy frame */
+ if (dummy_bottom <= fip->pc && fip->pc <= fip->frame)
+ {
+ /* all regs were saved by push_call_dummy () */
+ adr = fip->frame;
+ for (i = 0; i < NUM_REGS; i++)
+ {
+ adr -= REGISTER_RAW_SIZE (i);
+ fsrp->regs[i] = adr;
+ }
+ return;
+ }
+
+ locals = i386_get_frame_setup (get_pc_function_start (fip->pc));
+
+ if (locals >= 0)
+ {
+ adr = fip->frame - 4 - locals;
+ for (i = 0; i < 8; i++)
+ {
+ op = codestream_get ();
+ if (op < 0x50 || op > 0x57)
+ break;
+#ifdef I386_REGNO_TO_SYMMETRY
+ /* Dynix uses different internal numbering. Ick. */
+ fsrp->regs[I386_REGNO_TO_SYMMETRY(op - 0x50)] = adr;
+#else
+ fsrp->regs[op - 0x50] = adr;
+#endif
+ adr -= 4;
+ }
+ }
+
+ fsrp->regs[PC_REGNUM] = fip->frame + 4;
+ fsrp->regs[FP_REGNUM] = fip->frame;
+}
+
+/* return pc of first real instruction */
+
+int
+i386_skip_prologue (pc)
+ int pc;
+{
+ unsigned char op;
+ int i;
+ static unsigned char pic_pat[6] = { 0xe8, 0, 0, 0, 0, /* call 0x0 */
+ 0x5b, /* popl %ebx */
+ };
+ CORE_ADDR pos;
+
+ if (i386_get_frame_setup (pc) < 0)
+ return (pc);
+
+ /* found valid frame setup - codestream now points to
+ * start of push instructions for saving registers
+ */
+
+ /* skip over register saves */
+ for (i = 0; i < 8; i++)
+ {
+ op = codestream_peek ();
+ /* break if not pushl inst */
+ if (op < 0x50 || op > 0x57)
+ break;
+ codestream_get ();
+ }
+
+ /* The native cc on SVR4 in -K PIC mode inserts the following code to get
+ the address of the global offset table (GOT) into register %ebx.
+ call 0x0
+ popl %ebx
+ movl %ebx,x(%ebp) (optional)
+ addl y,%ebx
+ This code is with the rest of the prologue (at the end of the
+ function), so we have to skip it to get to the first real
+ instruction at the start of the function. */
+
+ pos = codestream_tell ();
+ for (i = 0; i < 6; i++)
+ {
+ op = codestream_get ();
+ if (pic_pat [i] != op)
+ break;
+ }
+ if (i == 6)
+ {
+ unsigned char buf[4];
+ long delta = 6;
+
+ op = codestream_get ();
+ if (op == 0x89) /* movl %ebx, x(%ebp) */
+ {
+ op = codestream_get ();
+ if (op == 0x5d) /* one byte offset from %ebp */
+ {
+ delta += 3;
+ codestream_read (buf, 1);
+ }
+ else if (op == 0x9d) /* four byte offset from %ebp */
+ {
+ delta += 6;
+ codestream_read (buf, 4);
+ }
+ else /* unexpected instruction */
+ delta = -1;
+ op = codestream_get ();
+ }
+ /* addl y,%ebx */
+ if (delta > 0 && op == 0x81 && codestream_get () == 0xc3)
+ {
+ pos += delta + 6;
+ }
+ }
+ codestream_seek (pos);
+
+ i386_follow_jump ();
+
+ return (codestream_tell ());
+}
+
+void
+i386_push_dummy_frame ()
+{
+ CORE_ADDR sp = read_register (SP_REGNUM);
+ int regnum;
+ char regbuf[MAX_REGISTER_RAW_SIZE];
+
+ sp = push_word (sp, read_register (PC_REGNUM));
+ sp = push_word (sp, read_register (FP_REGNUM));
+ write_register (FP_REGNUM, sp);
+ for (regnum = 0; regnum < NUM_REGS; regnum++)
+ {
+ read_register_gen (regnum, regbuf);
+ sp = push_bytes (sp, regbuf, REGISTER_RAW_SIZE (regnum));
+ }
+ write_register (SP_REGNUM, sp);
+}
+
+void
+i386_pop_frame ()
+{
+ FRAME frame = get_current_frame ();
+ CORE_ADDR fp;
+ int regnum;
+ struct frame_saved_regs fsr;
+ struct frame_info *fi;
+ char regbuf[MAX_REGISTER_RAW_SIZE];
+
+ fi = get_frame_info (frame);
+ fp = fi->frame;
+ get_frame_saved_regs (fi, &fsr);
+ for (regnum = 0; regnum < NUM_REGS; regnum++)
+ {
+ CORE_ADDR adr;
+ adr = fsr.regs[regnum];
+ if (adr)
+ {
+ read_memory (adr, regbuf, REGISTER_RAW_SIZE (regnum));
+ write_register_bytes (REGISTER_BYTE (regnum), regbuf,
+ REGISTER_RAW_SIZE (regnum));
+ }
+ }
+ write_register (FP_REGNUM, read_memory_integer (fp, 4));
+ write_register (PC_REGNUM, read_memory_integer (fp + 4, 4));
+ write_register (SP_REGNUM, fp + 8);
+ flush_cached_frames ();
+ set_current_frame ( create_new_frame (read_register (FP_REGNUM),
+ read_pc ()));
+}
+
+#ifdef GET_LONGJMP_TARGET
+
+/* Figure out where the longjmp will land. Slurp the args out of the stack.
+ We expect the first arg to be a pointer to the jmp_buf structure from which
+ we extract the pc (JB_PC) that we will land at. The pc is copied into PC.
+ This routine returns true on success. */
+
+int
+get_longjmp_target(pc)
+ CORE_ADDR *pc;
+{
+ char buf[TARGET_PTR_BIT / TARGET_CHAR_BIT];
+ CORE_ADDR sp, jb_addr;
+
+ sp = read_register (SP_REGNUM);
+
+ if (target_read_memory (sp + SP_ARG0, /* Offset of first arg on stack */
+ buf,
+ TARGET_PTR_BIT / TARGET_CHAR_BIT))
+ return 0;
+
+ jb_addr = extract_address (buf, TARGET_PTR_BIT / TARGET_CHAR_BIT);
+
+ if (target_read_memory (jb_addr + JB_PC * JB_ELEMENT_SIZE, buf,
+ TARGET_PTR_BIT / TARGET_CHAR_BIT))
+ return 0;
+
+ *pc = extract_address (buf, TARGET_PTR_BIT / TARGET_CHAR_BIT);
+
+ return 1;
+}
+
+#endif /* GET_LONGJMP_TARGET */
+
+#ifdef I386_AIX_TARGET
+/* On AIX, floating point values are returned in floating point registers. */
+
+void
+i386_extract_return_value(type, regbuf, valbuf)
+ struct type *type;
+ char regbuf[REGISTER_BYTES];
+ char *valbuf;
+{
+ if (TYPE_CODE_FLT == TYPE_CODE(type))
+ {
+ double d;
+ /* 387 %st(0), gcc uses this */
+ floatformat_to_double (&floatformat_i387_ext,
+ &regbuf[REGISTER_BYTE(FP0_REGNUM)],
+ &d);
+ store_floating (valbuf, TYPE_LENGTH (type), d);
+ }
+ else
+ {
+ memcpy (valbuf, regbuf, TYPE_LENGTH (type));
+ }
+}
+#endif /* I386_AIX_TARGET */
+
+#ifdef I386V4_SIGTRAMP_SAVED_PC
+/* Get saved user PC for sigtramp from the pushed ucontext on the stack
+ for all three variants of SVR4 sigtramps. */
+
+CORE_ADDR
+i386v4_sigtramp_saved_pc (frame)
+ FRAME frame;
+{
+ CORE_ADDR saved_pc_offset = 4;
+ char *name = NULL;
+
+ find_pc_partial_function (frame->pc, &name,
+ (CORE_ADDR *)NULL,(CORE_ADDR *)NULL);
+ if (name)
+ {
+ if (STREQ (name, "_sigreturn"))
+ saved_pc_offset = 132 + 14 * 4;
+ else if (STREQ (name, "_sigacthandler"))
+ saved_pc_offset = 80 + 14 * 4;
+ else if (STREQ (name, "sigvechandler"))
+ saved_pc_offset = 120 + 14 * 4;
+ }
+
+ if (frame->next)
+ return read_memory_integer (frame->next->frame + saved_pc_offset, 4);
+ return read_memory_integer (read_register (SP_REGNUM) + saved_pc_offset, 4);
+}
+#endif /* I386V4_SIGTRAMP_SAVED_PC */
diff --git a/gnu/usr.bin/gdb/gdb/ieee.h b/gnu/usr.bin/gdb/gdb/ieee.h
new file mode 100644
index 0000000..22cd140
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/ieee.h
@@ -0,0 +1,132 @@
+/* IEEE Standard 695-1980 "Universal Format for Object Modules" header file
+ Contributed by Cygnus Support. */
+
+#define N_W_VARIABLES 8
+#define Module_Beginning 0xe0
+
+typedef struct ieee_module {
+ char *processor;
+ char *module_name;
+} ieee_module_begin_type;
+
+#define Address_Descriptor 0xec
+typedef struct ieee_address {
+bfd_vma number_of_bits_mau;
+ bfd_vma number_of_maus_in_address;
+
+ unsigned char byte_order;
+#define IEEE_LITTLE 0xcc
+#define IEEE_BIG 0xcd
+} ieee_address_descriptor_type;
+
+typedef union ieee_w_variable {
+ file_ptr offset[N_W_VARIABLES];
+ struct {
+ file_ptr extension_record;
+ file_ptr environmental_record;
+ file_ptr section_part;
+ file_ptr external_part;
+ file_ptr debug_information_part;
+ file_ptr data_part;
+ file_ptr trailer_part;
+ file_ptr me_record;
+ } r;
+} ieee_w_variable_type;
+
+
+
+
+
+typedef enum ieee_record
+{
+ ieee_number_start_enum = 0x00,
+ ieee_number_end_enum=0x7f,
+ ieee_number_repeat_start_enum = 0x80,
+ ieee_number_repeat_end_enum = 0x88,
+ ieee_number_repeat_4_enum = 0x84,
+ ieee_number_repeat_3_enum = 0x83,
+ ieee_number_repeat_2_enum = 0x82,
+ ieee_number_repeat_1_enum = 0x81,
+ ieee_module_beginning_enum = 0xe0,
+ ieee_module_end_enum = 0xe1,
+ ieee_extension_length_1_enum = 0xde,
+ ieee_extension_length_2_enum = 0xdf,
+ ieee_section_type_enum = 0xe6,
+ ieee_section_alignment_enum = 0xe7,
+ ieee_external_symbol_enum = 0xe8,
+ ieee_attribute_record_enum = 0xf1c9,
+ ieee_comma = 0x90,
+ ieee_external_reference_enum = 0xe9,
+ ieee_set_current_section_enum = 0xe5,
+ ieee_address_descriptor_enum = 0xec,
+ ieee_load_constant_bytes_enum = 0xed,
+ ieee_load_with_relocation_enum = 0xe4,
+
+ ieee_variable_A_enum = 0xc1,
+ ieee_variable_B_enum = 0xc2,
+ ieee_variable_C_enum = 0xc3,
+ ieee_variable_D_enum = 0xc4,
+ ieee_variable_E_enum = 0xc5,
+ ieee_variable_F_enum = 0xc6,
+ ieee_variable_G_enum = 0xc7,
+ ieee_variable_H_enum = 0xc8,
+ ieee_variable_I_enum = 0xc9,
+ ieee_variable_J_enum = 0xca,
+ ieee_variable_K_enum = 0xcb,
+ ieee_variable_L_enum = 0xcc,
+ ieee_variable_M_enum = 0xcd,
+ ieee_variable_N_enum = 0xce,
+ ieee_variable_O_enum = 0xcf,
+ ieee_variable_P_enum = 0xd0,
+ ieee_variable_Q_enum = 0xd1,
+ ieee_variable_R_enum = 0xd2,
+ ieee_variable_S_enum = 0xd3,
+ ieee_variable_T_enum = 0xd4,
+ ieee_variable_U_enum = 0xd5,
+ ieee_variable_V_enum = 0xd6,
+ ieee_variable_W_enum = 0xd7,
+ ieee_variable_X_enum = 0xd8,
+ ieee_variable_Y_enum = 0xd9,
+ ieee_variable_Z_enum = 0xda,
+ ieee_function_plus_enum = 0xa5,
+ ieee_function_minus_enum = 0xa6,
+ ieee_function_signed_open_b_enum = 0xba,
+ ieee_function_signed_close_b_enum = 0xbb,
+
+ ieee_function_unsigned_open_b_enum = 0xbc,
+ ieee_function_unsigned_close_b_enum = 0xbd,
+
+ ieee_function_either_open_b_enum = 0xbe,
+ ieee_function_either_close_b_enum = 0xbf,
+ ieee_record_seperator_enum = 0xdb,
+
+ ieee_e2_first_byte_enum = 0xe2,
+ ieee_section_size_enum = 0xe2d3,
+ ieee_physical_region_size_enum = 0xe2c1,
+ ieee_region_base_address_enum = 0xe2c2,
+ ieee_mau_size_enum = 0xe2c6,
+ ieee_m_value_enum = 0xe2cd,
+ ieee_section_base_address_enum = 0xe2cc,
+ ieee_section_offset_enum = 0xe2d2,
+ ieee_value_starting_address_enum = 0xe2c7,
+ ieee_assign_value_to_variable_enum = 0xe2d7,
+ ieee_set_current_pc_enum = 0xe2d0,
+ ieee_value_record_enum = 0xe2c9,
+ieee_nn_record = 0xf0,
+ ieee_weak_external_reference_enum= 0xf4,
+ ieee_repeat_data_enum = 0xf7
+} ieee_record_enum_type;
+
+
+typedef struct ieee_section {
+ unsigned int section_index;
+ unsigned int section_type;
+ char *section_name;
+ unsigned int parent_section_index;
+ unsigned int sibling_section_index;
+ unsigned int context_index;
+} ieee_section_type;
+#define IEEE_REFERENCE_BASE 11
+#define IEEE_PUBLIC_BASE 32
+#define IEEE_SECTION_NUMBER_BASE 1
+
diff --git a/gnu/usr.bin/gdb/gdb/infcmd.c b/gnu/usr.bin/gdb/gdb/infcmd.c
new file mode 100644
index 0000000..d0404e1
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/infcmd.c
@@ -0,0 +1,1384 @@
+/* Memory-access and commands for "inferior" (child) process, for GDB.
+ Copyright 1986, 1987, 1988, 1989, 1991, 1992 Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "defs.h"
+#include <signal.h>
+#include <sys/param.h>
+#include <string.h>
+#include "symtab.h"
+#include "gdbtypes.h"
+#include "frame.h"
+#include "inferior.h"
+#include "environ.h"
+#include "value.h"
+#include "gdbcmd.h"
+#include "gdbcore.h"
+#include "target.h"
+#include "language.h"
+
+static void
+continue_command PARAMS ((char *, int));
+
+static void
+until_next_command PARAMS ((int));
+
+static void
+until_command PARAMS ((char *, int));
+
+static void
+path_info PARAMS ((char *, int));
+
+static void
+path_command PARAMS ((char *, int));
+
+static void
+unset_command PARAMS ((char *, int));
+
+static void
+float_info PARAMS ((char *, int));
+
+static void
+detach_command PARAMS ((char *, int));
+
+static void
+nofp_registers_info PARAMS ((char *, int));
+
+static void
+all_registers_info PARAMS ((char *, int));
+
+static void
+registers_info PARAMS ((char *, int));
+
+static void
+do_registers_info PARAMS ((int, int));
+
+static void
+unset_environment_command PARAMS ((char *, int));
+
+static void
+set_environment_command PARAMS ((char *, int));
+
+static void
+environment_info PARAMS ((char *, int));
+
+static void
+program_info PARAMS ((char *, int));
+
+static void
+finish_command PARAMS ((char *, int));
+
+static void
+signal_command PARAMS ((char *, int));
+
+static void
+jump_command PARAMS ((char *, int));
+
+static void
+step_1 PARAMS ((int, int, char *));
+
+static void
+nexti_command PARAMS ((char *, int));
+
+static void
+stepi_command PARAMS ((char *, int));
+
+static void
+next_command PARAMS ((char *, int));
+
+static void
+step_command PARAMS ((char *, int));
+
+static void
+run_command PARAMS ((char *, int));
+
+#define ERROR_NO_INFERIOR \
+ if (!target_has_execution) error ("The program is not being run.");
+
+/* String containing arguments to give to the program, separated by spaces.
+ Empty string (pointer to '\0') means no args. */
+
+static char *inferior_args;
+
+/* File name for default use for standard in/out in the inferior. */
+
+char *inferior_io_terminal;
+
+/* Pid of our debugged inferior, or 0 if no inferior now.
+ Since various parts of infrun.c test this to see whether there is a program
+ being debugged it should be nonzero (currently 3 is used) for remote
+ debugging. */
+
+int inferior_pid;
+
+/* Last signal that the inferior received (why it stopped). */
+
+enum target_signal stop_signal;
+
+/* Address at which inferior stopped. */
+
+CORE_ADDR stop_pc;
+
+/* Stack frame when program stopped. */
+
+FRAME_ADDR stop_frame_address;
+
+/* Chain containing status of breakpoint(s) that we have stopped at. */
+
+bpstat stop_bpstat;
+
+/* Flag indicating that a command has proceeded the inferior past the
+ current breakpoint. */
+
+int breakpoint_proceeded;
+
+/* Nonzero if stopped due to a step command. */
+
+int stop_step;
+
+/* Nonzero if stopped due to completion of a stack dummy routine. */
+
+int stop_stack_dummy;
+
+/* Nonzero if stopped due to a random (unexpected) signal in inferior
+ process. */
+
+int stopped_by_random_signal;
+
+/* Range to single step within.
+ If this is nonzero, respond to a single-step signal
+ by continuing to step if the pc is in this range. */
+
+CORE_ADDR step_range_start; /* Inclusive */
+CORE_ADDR step_range_end; /* Exclusive */
+
+/* Stack frame address as of when stepping command was issued.
+ This is how we know when we step into a subroutine call,
+ and how to set the frame for the breakpoint used to step out. */
+
+FRAME_ADDR step_frame_address;
+
+/* 1 means step over all subroutine calls.
+ 0 means don't step over calls (used by stepi).
+ -1 means step over calls to undebuggable functions. */
+
+int step_over_calls;
+
+/* If stepping, nonzero means step count is > 1
+ so don't print frame next time inferior stops
+ if it stops due to stepping. */
+
+int step_multi;
+
+/* Environment to use for running inferior,
+ in format described in environ.h. */
+
+struct environ *inferior_environ;
+
+
+/* ARGSUSED */
+void
+tty_command (file, from_tty)
+ char *file;
+ int from_tty;
+{
+ if (file == 0)
+ error_no_arg ("terminal name for running target process");
+
+ inferior_io_terminal = savestring (file, strlen (file));
+}
+
+static void
+run_command (args, from_tty)
+ char *args;
+ int from_tty;
+{
+ char *exec_file;
+
+ dont_repeat ();
+
+ /* Shouldn't this be target_has_execution? FIXME. */
+ if (inferior_pid)
+ {
+ if (
+ !query ("The program being debugged has been started already.\n\
+Start it from the beginning? "))
+ error ("Program not restarted.");
+ target_kill ();
+ }
+
+ clear_breakpoint_hit_counts ();
+
+ exec_file = (char *) get_exec_file (0);
+
+ /* The exec file is re-read every time we do a generic_mourn_inferior, so
+ we just have to worry about the symbol file. */
+ reread_symbols ();
+
+ /* We keep symbols from add-symbol-file, on the grounds that the
+ user might want to add some symbols before running the program
+ (right?). But sometimes (dynamic loading where the user manually
+ introduces the new symbols with add-symbol-file), the code which
+ the symbols describe does not persist between runs. Currently
+ the user has to manually nuke all symbols between runs if they
+ want them to go away (PR 2207). This is probably reasonable. */
+
+ if (args)
+ {
+ char *cmd;
+ cmd = concat ("set args ", args, NULL);
+ make_cleanup (free, cmd);
+ execute_command (cmd, from_tty);
+ }
+
+ if (from_tty)
+ {
+ puts_filtered("Starting program: ");
+ if (exec_file)
+ puts_filtered(exec_file);
+ puts_filtered(" ");
+ puts_filtered(inferior_args);
+ puts_filtered("\n");
+ gdb_flush (gdb_stdout);
+ }
+
+ target_create_inferior (exec_file, inferior_args,
+ environ_vector (inferior_environ));
+}
+
+static void
+continue_command (proc_count_exp, from_tty)
+ char *proc_count_exp;
+ int from_tty;
+{
+ ERROR_NO_INFERIOR;
+
+ /* If have argument, set proceed count of breakpoint we stopped at. */
+
+ if (proc_count_exp != NULL)
+ {
+ bpstat bs = stop_bpstat;
+ int num = bpstat_num (&bs);
+ if (num == 0 && from_tty)
+ {
+ printf_filtered
+ ("Not stopped at any breakpoint; argument ignored.\n");
+ }
+ while (num != 0)
+ {
+ set_ignore_count (num,
+ parse_and_eval_address (proc_count_exp) - 1,
+ from_tty);
+ /* set_ignore_count prints a message ending with a period.
+ So print two spaces before "Continuing.". */
+ if (from_tty)
+ printf_filtered (" ");
+ num = bpstat_num (&bs);
+ }
+ }
+
+ if (from_tty)
+ printf_filtered ("Continuing.\n");
+
+ clear_proceed_status ();
+
+ proceed ((CORE_ADDR) -1, TARGET_SIGNAL_DEFAULT, 0);
+}
+
+/* Step until outside of current statement. */
+
+/* ARGSUSED */
+static void
+step_command (count_string, from_tty)
+ char *count_string;
+ int from_tty;
+{
+ step_1 (0, 0, count_string);
+}
+
+/* Likewise, but skip over subroutine calls as if single instructions. */
+
+/* ARGSUSED */
+static void
+next_command (count_string, from_tty)
+ char *count_string;
+ int from_tty;
+{
+ step_1 (1, 0, count_string);
+}
+
+/* Likewise, but step only one instruction. */
+
+/* ARGSUSED */
+static void
+stepi_command (count_string, from_tty)
+ char *count_string;
+ int from_tty;
+{
+ step_1 (0, 1, count_string);
+}
+
+/* ARGSUSED */
+static void
+nexti_command (count_string, from_tty)
+ char *count_string;
+ int from_tty;
+{
+ step_1 (1, 1, count_string);
+}
+
+static void
+step_1 (skip_subroutines, single_inst, count_string)
+ int skip_subroutines;
+ int single_inst;
+ char *count_string;
+{
+ register int count = 1;
+ FRAME fr;
+ struct cleanup *cleanups = 0;
+
+ ERROR_NO_INFERIOR;
+ count = count_string ? parse_and_eval_address (count_string) : 1;
+
+ if (!single_inst || skip_subroutines) /* leave si command alone */
+ {
+ enable_longjmp_breakpoint();
+ cleanups = make_cleanup(disable_longjmp_breakpoint, 0);
+ }
+
+ for (; count > 0; count--)
+ {
+ clear_proceed_status ();
+
+ fr = get_current_frame ();
+ if (!fr) /* Avoid coredump here. Why tho? */
+ error ("No current frame");
+ step_frame_address = FRAME_FP (fr);
+
+ if (! single_inst)
+ {
+ find_pc_line_pc_range (stop_pc, &step_range_start, &step_range_end);
+ if (step_range_end == 0)
+ {
+ char *name;
+ if (find_pc_partial_function (stop_pc, &name, &step_range_start,
+ &step_range_end) == 0)
+ error ("Cannot find bounds of current function");
+
+ target_terminal_ours ();
+ printf_filtered ("\
+Single stepping until exit from function %s, \n\
+which has no line number information.\n", name);
+ gdb_flush (gdb_stdout);
+ }
+ }
+ else
+ {
+ /* Say we are stepping, but stop after one insn whatever it does. */
+ step_range_start = step_range_end = 1;
+ if (!skip_subroutines)
+ /* It is stepi.
+ Don't step over function calls, not even to functions lacking
+ line numbers. */
+ step_over_calls = 0;
+ }
+
+ if (skip_subroutines)
+ step_over_calls = 1;
+
+ step_multi = (count > 1);
+ proceed ((CORE_ADDR) -1, TARGET_SIGNAL_DEFAULT, 1);
+ if (! stop_step)
+ break;
+
+ /* FIXME: On nexti, this may have already been done (when we hit the
+ step resume break, I think). Probably this should be moved to
+ wait_for_inferior (near the top). */
+#if defined (SHIFT_INST_REGS)
+ SHIFT_INST_REGS();
+#endif
+ }
+
+ if (!single_inst || skip_subroutines)
+ do_cleanups(cleanups);
+}
+
+/* Continue program at specified address. */
+
+static void
+jump_command (arg, from_tty)
+ char *arg;
+ int from_tty;
+{
+ register CORE_ADDR addr;
+ struct symtabs_and_lines sals;
+ struct symtab_and_line sal;
+ struct symbol *fn;
+ struct symbol *sfn;
+
+ ERROR_NO_INFERIOR;
+
+ if (!arg)
+ error_no_arg ("starting address");
+
+ sals = decode_line_spec_1 (arg, 1);
+ if (sals.nelts != 1)
+ {
+ error ("Unreasonable jump request");
+ }
+
+ sal = sals.sals[0];
+ free ((PTR)sals.sals);
+
+ if (sal.symtab == 0 && sal.pc == 0)
+ error ("No source file has been specified.");
+
+ resolve_sal_pc (&sal); /* May error out */
+
+ /* See if we are trying to jump to another function. */
+ fn = get_frame_function (get_current_frame ());
+ sfn = find_pc_function (sal.pc);
+ if (fn != NULL && sfn != fn)
+ {
+ if (!query ("Line %d is not in `%s'. Jump anyway? ", sal.line,
+ SYMBOL_SOURCE_NAME (fn)))
+ {
+ error ("Not confirmed.");
+ /* NOTREACHED */
+ }
+ }
+
+ addr = sal.pc;
+
+ if (from_tty)
+ {
+ printf_filtered ("Continuing at ");
+ print_address_numeric (addr, 1, gdb_stdout);
+ printf_filtered (".\n");
+ }
+
+ clear_proceed_status ();
+ proceed (addr, TARGET_SIGNAL_0, 0);
+}
+
+/* Continue program giving it specified signal. */
+
+static void
+signal_command (signum_exp, from_tty)
+ char *signum_exp;
+ int from_tty;
+{
+ enum target_signal oursig;
+
+ dont_repeat (); /* Too dangerous. */
+ ERROR_NO_INFERIOR;
+
+ if (!signum_exp)
+ error_no_arg ("signal number");
+
+ /* It would be even slicker to make signal names be valid expressions,
+ (the type could be "enum $signal" or some such), then the user could
+ assign them to convenience variables. */
+ oursig = target_signal_from_name (signum_exp);
+
+ if (oursig == TARGET_SIGNAL_UNKNOWN)
+ {
+ /* Not found as a name, try it as an expression. */
+ /* The numeric signal refers to our own internal signal numbering
+ from target.h, not to host/target signal number. This is a
+ feature; users really should be using symbolic names anyway,
+ and the common ones like SIGHUP, SIGINT, SIGALRM, etc. will
+ work right anyway. */
+ int signum = parse_and_eval_address (signum_exp);
+ if (signum < 0
+ || signum >= (int)TARGET_SIGNAL_LAST
+ || signum == (int)TARGET_SIGNAL_UNKNOWN
+ || signum == (int)TARGET_SIGNAL_DEFAULT)
+ error ("Invalid signal number %d.", signum);
+ oursig = signum;
+ }
+
+ if (from_tty)
+ {
+ if (oursig == TARGET_SIGNAL_0)
+ printf_filtered ("Continuing with no signal.\n");
+ else
+ printf_filtered ("Continuing with signal %s.\n",
+ target_signal_to_name (oursig));
+ }
+
+ clear_proceed_status ();
+ proceed (stop_pc, oursig, 0);
+}
+
+/* Call breakpoint_auto_delete on the current contents of the bpstat
+ pointed to by arg (which is really a bpstat *). */
+void
+breakpoint_auto_delete_contents (arg)
+ PTR arg;
+{
+ breakpoint_auto_delete (*(bpstat *)arg);
+}
+
+/* Execute a "stack dummy", a piece of code stored in the stack
+ by the debugger to be executed in the inferior.
+
+ To call: first, do PUSH_DUMMY_FRAME.
+ Then push the contents of the dummy. It should end with a breakpoint insn.
+ Then call here, passing address at which to start the dummy.
+
+ The contents of all registers are saved before the dummy frame is popped
+ and copied into the buffer BUFFER.
+
+ The dummy's frame is automatically popped whenever that break is hit.
+ If that is the first time the program stops, run_stack_dummy
+ returns to its caller with that frame already gone and returns 0.
+ Otherwise, run_stack-dummy returns 1 (the frame will eventually be popped
+ when we do hit that breakpoint). */
+
+/* DEBUG HOOK: 4 => return instead of letting the stack dummy run. */
+
+static int stack_dummy_testing = 0;
+
+int
+run_stack_dummy (addr, buffer)
+ CORE_ADDR addr;
+ char buffer[REGISTER_BYTES];
+{
+ struct cleanup *old_cleanups = make_cleanup (null_cleanup, 0);
+
+ /* Now proceed, having reached the desired place. */
+ clear_proceed_status ();
+ if (stack_dummy_testing & 4)
+ {
+ POP_FRAME;
+ return(0);
+ }
+#ifdef CALL_DUMMY_BREAKPOINT_OFFSET
+ {
+ struct breakpoint *bpt;
+ struct symtab_and_line sal;
+
+#if CALL_DUMMY_LOCATION != AT_ENTRY_POINT
+ sal.pc = addr - CALL_DUMMY_START_OFFSET + CALL_DUMMY_BREAKPOINT_OFFSET;
+#else
+ sal.pc = CALL_DUMMY_ADDRESS ();
+#endif
+ sal.symtab = NULL;
+ sal.line = 0;
+
+ /* Set up a FRAME for the dummy frame so we can pass it to
+ set_momentary_breakpoint. We need to give the breakpoint a
+ frame in case there is only one copy of the dummy (e.g.
+ CALL_DUMMY_LOCATION == AFTER_TEXT_END). */
+ flush_cached_frames ();
+ set_current_frame (create_new_frame (read_fp (), sal.pc));
+
+ /* If defined, CALL_DUMMY_BREAKPOINT_OFFSET is where we need to put
+ a breakpoint instruction. If not, the call dummy already has the
+ breakpoint instruction in it.
+
+ addr is the address of the call dummy plus the CALL_DUMMY_START_OFFSET,
+ so we need to subtract the CALL_DUMMY_START_OFFSET. */
+ bpt = set_momentary_breakpoint (sal,
+ get_current_frame (),
+ bp_call_dummy);
+ bpt->disposition = delete;
+
+ /* If all error()s out of proceed ended up calling normal_stop (and
+ perhaps they should; it already does in the special case of error
+ out of resume()), then we wouldn't need this. */
+ make_cleanup (breakpoint_auto_delete_contents, &stop_bpstat);
+ }
+#endif /* CALL_DUMMY_BREAKPOINT_OFFSET. */
+
+ proceed_to_finish = 1; /* We want stop_registers, please... */
+ proceed (addr, TARGET_SIGNAL_0, 0);
+
+ discard_cleanups (old_cleanups);
+
+ if (!stop_stack_dummy)
+ return 1;
+
+ /* On return, the stack dummy has been popped already. */
+
+ memcpy (buffer, stop_registers, sizeof stop_registers);
+ return 0;
+}
+
+/* Proceed until we reach a different source line with pc greater than
+ our current one or exit the function. We skip calls in both cases.
+
+ Note that eventually this command should probably be changed so
+ that only source lines are printed out when we hit the breakpoint
+ we set. This may involve changes to wait_for_inferior and the
+ proceed status code. */
+
+/* ARGSUSED */
+static void
+until_next_command (from_tty)
+ int from_tty;
+{
+ FRAME frame;
+ CORE_ADDR pc;
+ struct symbol *func;
+ struct symtab_and_line sal;
+
+ clear_proceed_status ();
+
+ frame = get_current_frame ();
+
+ /* Step until either exited from this function or greater
+ than the current line (if in symbolic section) or pc (if
+ not). */
+
+ pc = read_pc ();
+ func = find_pc_function (pc);
+
+ if (!func)
+ {
+ struct minimal_symbol *msymbol = lookup_minimal_symbol_by_pc (pc);
+
+ if (msymbol == NULL)
+ error ("Execution is not within a known function.");
+
+ step_range_start = SYMBOL_VALUE_ADDRESS (msymbol);
+ step_range_end = pc;
+ }
+ else
+ {
+ sal = find_pc_line (pc, 0);
+
+ step_range_start = BLOCK_START (SYMBOL_BLOCK_VALUE (func));
+ step_range_end = sal.end;
+ }
+
+ step_over_calls = 1;
+ step_frame_address = FRAME_FP (frame);
+
+ step_multi = 0; /* Only one call to proceed */
+
+ proceed ((CORE_ADDR) -1, TARGET_SIGNAL_DEFAULT, 1);
+}
+
+static void
+until_command (arg, from_tty)
+ char *arg;
+ int from_tty;
+{
+ if (!target_has_execution)
+ error ("The program is not running.");
+ if (arg)
+ until_break_command (arg, from_tty);
+ else
+ until_next_command (from_tty);
+}
+
+/* "finish": Set a temporary breakpoint at the place
+ the selected frame will return to, then continue. */
+
+static void
+finish_command (arg, from_tty)
+ char *arg;
+ int from_tty;
+{
+ struct symtab_and_line sal;
+ register FRAME frame;
+ struct frame_info *fi;
+ register struct symbol *function;
+ struct breakpoint *breakpoint;
+ struct cleanup *old_chain;
+
+ if (arg)
+ error ("The \"finish\" command does not take any arguments.");
+ if (!target_has_execution)
+ error ("The program is not running.");
+ if (selected_frame == NULL)
+ error ("No selected frame.");
+
+ frame = get_prev_frame (selected_frame);
+ if (frame == 0)
+ error ("\"finish\" not meaningful in the outermost frame.");
+
+ clear_proceed_status ();
+
+ fi = get_frame_info (frame);
+ sal = find_pc_line (fi->pc, 0);
+ sal.pc = fi->pc;
+
+ breakpoint = set_momentary_breakpoint (sal, frame, bp_finish);
+
+ old_chain = make_cleanup(delete_breakpoint, breakpoint);
+
+ /* Find the function we will return from. */
+
+ fi = get_frame_info (selected_frame);
+ function = find_pc_function (fi->pc);
+
+ /* Print info on the selected frame, including level number
+ but not source. */
+ if (from_tty)
+ {
+ printf_filtered ("Run till exit from ");
+ print_stack_frame (selected_frame, selected_frame_level, 0);
+ }
+
+ proceed_to_finish = 1; /* We want stop_registers, please... */
+ proceed ((CORE_ADDR) -1, TARGET_SIGNAL_DEFAULT, 0);
+
+ /* Did we stop at our breakpoint? */
+ if (bpstat_find_breakpoint(stop_bpstat, breakpoint) != NULL
+ && function != 0)
+ {
+ struct type *value_type;
+ register value_ptr val;
+ CORE_ADDR funcaddr;
+
+ value_type = TYPE_TARGET_TYPE (SYMBOL_TYPE (function));
+ if (!value_type)
+ fatal ("internal: finish_command: function has no target type");
+
+ if (TYPE_CODE (value_type) == TYPE_CODE_VOID)
+ return;
+
+ funcaddr = BLOCK_START (SYMBOL_BLOCK_VALUE (function));
+
+ val = value_being_returned (value_type, stop_registers,
+ using_struct_return (value_of_variable (function, NULL),
+ funcaddr,
+ value_type,
+ BLOCK_GCC_COMPILED (SYMBOL_BLOCK_VALUE (function))));
+
+ printf_filtered ("Value returned is $%d = ", record_latest_value (val));
+ value_print (val, gdb_stdout, 0, Val_no_prettyprint);
+ printf_filtered ("\n");
+ }
+ do_cleanups(old_chain);
+}
+
+/* ARGSUSED */
+static void
+program_info (args, from_tty)
+ char *args;
+ int from_tty;
+{
+ bpstat bs = stop_bpstat;
+ int num = bpstat_num (&bs);
+
+ if (!target_has_execution)
+ {
+ printf_filtered ("The program being debugged is not being run.\n");
+ return;
+ }
+
+ target_files_info ();
+ printf_filtered ("Program stopped at %s.\n",
+ local_hex_string((unsigned long) stop_pc));
+ if (stop_step)
+ printf_filtered ("It stopped after being stepped.\n");
+ else if (num != 0)
+ {
+ /* There may be several breakpoints in the same place, so this
+ isn't as strange as it seems. */
+ while (num != 0)
+ {
+ if (num < 0)
+ printf_filtered ("It stopped at a breakpoint that has since been deleted.\n");
+ else
+ printf_filtered ("It stopped at breakpoint %d.\n", num);
+ num = bpstat_num (&bs);
+ }
+ }
+ else if (stop_signal != TARGET_SIGNAL_0)
+ {
+ printf_filtered ("It stopped with signal %s, %s.\n",
+ target_signal_to_name (stop_signal),
+ target_signal_to_string (stop_signal));
+ }
+
+ if (!from_tty)
+ printf_filtered ("Type \"info stack\" or \"info registers\" for more information.\n");
+}
+
+static void
+environment_info (var, from_tty)
+ char *var;
+ int from_tty;
+{
+ if (var)
+ {
+ register char *val = get_in_environ (inferior_environ, var);
+ if (val)
+ {
+ puts_filtered (var);
+ puts_filtered (" = ");
+ puts_filtered (val);
+ puts_filtered ("\n");
+ }
+ else
+ {
+ puts_filtered ("Environment variable \"");
+ puts_filtered (var);
+ puts_filtered ("\" not defined.\n");
+ }
+ }
+ else
+ {
+ register char **vector = environ_vector (inferior_environ);
+ while (*vector)
+ {
+ puts_filtered (*vector++);
+ puts_filtered ("\n");
+ }
+ }
+}
+
+static void
+set_environment_command (arg, from_tty)
+ char *arg;
+ int from_tty;
+{
+ register char *p, *val, *var;
+ int nullset = 0;
+
+ if (arg == 0)
+ error_no_arg ("environment variable and value");
+
+ /* Find seperation between variable name and value */
+ p = (char *) strchr (arg, '=');
+ val = (char *) strchr (arg, ' ');
+
+ if (p != 0 && val != 0)
+ {
+ /* We have both a space and an equals. If the space is before the
+ equals, walk forward over the spaces til we see a nonspace
+ (possibly the equals). */
+ if (p > val)
+ while (*val == ' ')
+ val++;
+
+ /* Now if the = is after the char following the spaces,
+ take the char following the spaces. */
+ if (p > val)
+ p = val - 1;
+ }
+ else if (val != 0 && p == 0)
+ p = val;
+
+ if (p == arg)
+ error_no_arg ("environment variable to set");
+
+ if (p == 0 || p[1] == 0)
+ {
+ nullset = 1;
+ if (p == 0)
+ p = arg + strlen (arg); /* So that savestring below will work */
+ }
+ else
+ {
+ /* Not setting variable value to null */
+ val = p + 1;
+ while (*val == ' ' || *val == '\t')
+ val++;
+ }
+
+ while (p != arg && (p[-1] == ' ' || p[-1] == '\t')) p--;
+
+ var = savestring (arg, p - arg);
+ if (nullset)
+ {
+ printf_filtered ("Setting environment variable \"%s\" to null value.\n", var);
+ set_in_environ (inferior_environ, var, "");
+ }
+ else
+ set_in_environ (inferior_environ, var, val);
+ free (var);
+}
+
+static void
+unset_environment_command (var, from_tty)
+ char *var;
+ int from_tty;
+{
+ if (var == 0)
+ {
+ /* If there is no argument, delete all environment variables.
+ Ask for confirmation if reading from the terminal. */
+ if (!from_tty || query ("Delete all environment variables? "))
+ {
+ free_environ (inferior_environ);
+ inferior_environ = make_environ ();
+ }
+ }
+ else
+ unset_in_environ (inferior_environ, var);
+}
+
+/* Handle the execution path (PATH variable) */
+
+static const char path_var_name[] = "PATH";
+
+/* ARGSUSED */
+static void
+path_info (args, from_tty)
+ char *args;
+ int from_tty;
+{
+ puts_filtered ("Executable and object file path: ");
+ puts_filtered (get_in_environ (inferior_environ, path_var_name));
+ puts_filtered ("\n");
+}
+
+/* Add zero or more directories to the front of the execution path. */
+
+static void
+path_command (dirname, from_tty)
+ char *dirname;
+ int from_tty;
+{
+ char *exec_path;
+
+ dont_repeat ();
+ exec_path = strsave (get_in_environ (inferior_environ, path_var_name));
+ mod_path (dirname, &exec_path);
+ set_in_environ (inferior_environ, path_var_name, exec_path);
+ free (exec_path);
+ if (from_tty)
+ path_info ((char *)NULL, from_tty);
+}
+
+const char * const reg_names[] = REGISTER_NAMES;
+
+/* Print out the machine register regnum. If regnum is -1,
+ print all registers (fpregs == 1) or all non-float registers
+ (fpregs == 0).
+
+ For most machines, having all_registers_info() print the
+ register(s) one per line is good enough. If a different format
+ is required, (eg, for MIPS or Pyramid 90x, which both have
+ lots of regs), or there is an existing convention for showing
+ all the registers, define the macro DO_REGISTERS_INFO(regnum, fp)
+ to provide that format. */
+
+#if !defined (DO_REGISTERS_INFO)
+
+#define DO_REGISTERS_INFO(regnum, fp) do_registers_info(regnum, fp)
+
+static void
+do_registers_info (regnum, fpregs)
+ int regnum;
+ int fpregs;
+{
+ register int i;
+ int numregs = ARCH_NUM_REGS;
+
+ for (i = 0; i < numregs; i++)
+ {
+ char raw_buffer[MAX_REGISTER_RAW_SIZE];
+ char virtual_buffer[MAX_REGISTER_VIRTUAL_SIZE];
+
+ /* Decide between printing all regs, nonfloat regs, or specific reg. */
+ if (regnum == -1) {
+ if (TYPE_CODE (REGISTER_VIRTUAL_TYPE (i)) == TYPE_CODE_FLT && !fpregs)
+ continue;
+ } else {
+ if (i != regnum)
+ continue;
+ }
+
+ fputs_filtered (reg_names[i], gdb_stdout);
+ print_spaces_filtered (15 - strlen (reg_names[i]), gdb_stdout);
+
+ /* Get the data in raw format. */
+ if (read_relative_register_raw_bytes (i, raw_buffer))
+ {
+ printf_filtered ("Invalid register contents\n");
+ continue;
+ }
+
+ /* Convert raw data to virtual format if necessary. */
+#ifdef REGISTER_CONVERTIBLE
+ if (REGISTER_CONVERTIBLE (i))
+ {
+ REGISTER_CONVERT_TO_VIRTUAL (i, REGISTER_VIRTUAL_TYPE (i),
+ raw_buffer, virtual_buffer);
+ }
+ else
+#endif
+ memcpy (virtual_buffer, raw_buffer,
+ REGISTER_VIRTUAL_SIZE (i));
+
+ /* If virtual format is floating, print it that way, and in raw hex. */
+ if (TYPE_CODE (REGISTER_VIRTUAL_TYPE (i)) == TYPE_CODE_FLT
+ && ! INVALID_FLOAT (virtual_buffer, REGISTER_VIRTUAL_SIZE (i)))
+ {
+ register int j;
+
+ val_print (REGISTER_VIRTUAL_TYPE (i), virtual_buffer, 0,
+ gdb_stdout, 0, 1, 0, Val_pretty_default);
+
+ printf_filtered ("\t(raw 0x");
+ for (j = 0; j < REGISTER_RAW_SIZE (i); j++)
+ printf_filtered ("%02x", (unsigned char)raw_buffer[j]);
+ printf_filtered (")");
+ }
+
+/* FIXME! val_print probably can handle all of these cases now... */
+
+ /* Else if virtual format is too long for printf,
+ print in hex a byte at a time. */
+ else if (REGISTER_VIRTUAL_SIZE (i) > sizeof (long))
+ {
+ register int j;
+ printf_filtered ("0x");
+ for (j = 0; j < REGISTER_VIRTUAL_SIZE (i); j++)
+ printf_filtered ("%02x", (unsigned char)virtual_buffer[j]);
+ }
+ /* Else print as integer in hex and in decimal. */
+ else
+ {
+ val_print (REGISTER_VIRTUAL_TYPE (i), raw_buffer, 0,
+ gdb_stdout, 'x', 1, 0, Val_pretty_default);
+ printf_filtered ("\t");
+ val_print (REGISTER_VIRTUAL_TYPE (i), raw_buffer, 0,
+ gdb_stdout, 0, 1, 0, Val_pretty_default);
+ }
+
+ /* The SPARC wants to print even-numbered float regs as doubles
+ in addition to printing them as floats. */
+#ifdef PRINT_REGISTER_HOOK
+ PRINT_REGISTER_HOOK (i);
+#endif
+
+ printf_filtered ("\n");
+ }
+}
+#endif /* no DO_REGISTERS_INFO. */
+
+static void
+registers_info (addr_exp, fpregs)
+ char *addr_exp;
+ int fpregs;
+{
+ int regnum, numregs;
+ register char *end;
+
+ if (!target_has_registers)
+ error ("The program has no registers now.");
+
+ if (!addr_exp)
+ {
+ DO_REGISTERS_INFO(-1, fpregs);
+ return;
+ }
+
+ do
+ {
+ if (addr_exp[0] == '$')
+ addr_exp++;
+ end = addr_exp;
+ while (*end != '\0' && *end != ' ' && *end != '\t')
+ ++end;
+ numregs = ARCH_NUM_REGS;
+ for (regnum = 0; regnum < numregs; regnum++)
+ if (!strncmp (addr_exp, reg_names[regnum], end - addr_exp)
+ && strlen (reg_names[regnum]) == end - addr_exp)
+ goto found;
+ if (*addr_exp >= '0' && *addr_exp <= '9')
+ regnum = atoi (addr_exp); /* Take a number */
+ if (regnum >= numregs) /* Bad name, or bad number */
+ error ("%.*s: invalid register", end - addr_exp, addr_exp);
+
+found:
+ DO_REGISTERS_INFO(regnum, fpregs);
+
+ addr_exp = end;
+ while (*addr_exp == ' ' || *addr_exp == '\t')
+ ++addr_exp;
+ } while (*addr_exp != '\0');
+}
+
+static void
+all_registers_info (addr_exp, from_tty)
+ char *addr_exp;
+ int from_tty;
+{
+ registers_info (addr_exp, 1);
+}
+
+static void
+nofp_registers_info (addr_exp, from_tty)
+ char *addr_exp;
+ int from_tty;
+{
+ registers_info (addr_exp, 0);
+}
+
+/*
+ * TODO:
+ * Should save/restore the tty state since it might be that the
+ * program to be debugged was started on this tty and it wants
+ * the tty in some state other than what we want. If it's running
+ * on another terminal or without a terminal, then saving and
+ * restoring the tty state is a harmless no-op.
+ * This only needs to be done if we are attaching to a process.
+ */
+
+/*
+ attach_command --
+ takes a program started up outside of gdb and ``attaches'' to it.
+ This stops it cold in its tracks and allows us to start debugging it.
+ and wait for the trace-trap that results from attaching. */
+
+void
+attach_command (args, from_tty)
+ char *args;
+ int from_tty;
+{
+ dont_repeat (); /* Not for the faint of heart */
+
+ if (target_has_execution)
+ {
+ if (query ("A program is being debugged already. Kill it? "))
+ target_kill ();
+ else
+ error ("Not killed.");
+ }
+
+ target_attach (args, from_tty);
+
+ /* Set up the "saved terminal modes" of the inferior
+ based on what modes we are starting it with. */
+ target_terminal_init ();
+
+ /* Install inferior's terminal modes. */
+ target_terminal_inferior ();
+
+ /* Set up execution context to know that we should return from
+ wait_for_inferior as soon as the target reports a stop. */
+ init_wait_for_inferior ();
+ clear_proceed_status ();
+ stop_soon_quietly = 1;
+
+#ifndef MACH
+ /* Mach 3 does not generate any traps when attaching to inferior,
+ and to set up frames we can do this. */
+
+ wait_for_inferior ();
+#endif
+
+#ifdef SOLIB_ADD
+ /* Add shared library symbols from the newly attached process, if any. */
+ SOLIB_ADD ((char *)0, from_tty, (struct target_ops *)0);
+#endif
+
+ normal_stop ();
+}
+
+/*
+ * detach_command --
+ * takes a program previously attached to and detaches it.
+ * The program resumes execution and will no longer stop
+ * on signals, etc. We better not have left any breakpoints
+ * in the program or it'll die when it hits one. For this
+ * to work, it may be necessary for the process to have been
+ * previously attached. It *might* work if the program was
+ * started via the normal ptrace (PTRACE_TRACEME).
+ */
+
+static void
+detach_command (args, from_tty)
+ char *args;
+ int from_tty;
+{
+ dont_repeat (); /* Not for the faint of heart */
+ if (remove_breakpoints ())
+ printf("detach_command: couldn't remove all breakpoints!\n");
+ target_detach (args, from_tty);
+}
+
+/* ARGSUSED */
+static void
+float_info (addr_exp, from_tty)
+ char *addr_exp;
+ int from_tty;
+{
+#ifdef FLOAT_INFO
+ FLOAT_INFO;
+#else
+ printf_filtered ("No floating point info available for this processor.\n");
+#endif
+}
+
+/* ARGSUSED */
+static void
+unset_command (args, from_tty)
+ char *args;
+ int from_tty;
+{
+ printf_filtered ("\"unset\" must be followed by the name of an unset subcommand.\n");
+ help_list (unsetlist, "unset ", -1, gdb_stdout);
+}
+
+void
+_initialize_infcmd ()
+{
+ struct cmd_list_element *c;
+
+ add_com ("tty", class_run, tty_command,
+ "Set terminal for future runs of program being debugged.");
+
+ add_show_from_set
+ (add_set_cmd ("args", class_run, var_string_noescape, (char *)&inferior_args,
+
+"Set arguments to give program being debugged when it is started.\n\
+Follow this command with any number of args, to be passed to the program.",
+ &setlist),
+ &showlist);
+
+ c = add_cmd
+ ("environment", no_class, environment_info,
+ "The environment to give the program, or one variable's value.\n\
+With an argument VAR, prints the value of environment variable VAR to\n\
+give the program being debugged. With no arguments, prints the entire\n\
+environment to be given to the program.", &showlist);
+ c->completer = noop_completer;
+
+ add_prefix_cmd ("unset", no_class, unset_command,
+ "Complement to certain \"set\" commands",
+ &unsetlist, "unset ", 0, &cmdlist);
+
+ c = add_cmd ("environment", class_run, unset_environment_command,
+ "Cancel environment variable VAR for the program.\n\
+This does not affect the program until the next \"run\" command.",
+ &unsetlist);
+ c->completer = noop_completer;
+
+ c = add_cmd ("environment", class_run, set_environment_command,
+ "Set environment variable value to give the program.\n\
+Arguments are VAR VALUE where VAR is variable name and VALUE is value.\n\
+VALUES of environment variables are uninterpreted strings.\n\
+This does not affect the program until the next \"run\" command.",
+ &setlist);
+ c->completer = noop_completer;
+
+ add_com ("path", class_files, path_command,
+ "Add directory DIR(s) to beginning of search path for object files.\n\
+$cwd in the path means the current working directory.\n\
+This path is equivalent to the $PATH shell variable. It is a list of\n\
+directories, separated by colons. These directories are searched to find\n\
+fully linked executable files and separately compiled object files as needed.");
+
+ c = add_cmd ("paths", no_class, path_info,
+ "Current search path for finding object files.\n\
+$cwd in the path means the current working directory.\n\
+This path is equivalent to the $PATH shell variable. It is a list of\n\
+directories, separated by colons. These directories are searched to find\n\
+fully linked executable files and separately compiled object files as needed.", &showlist);
+ c->completer = noop_completer;
+
+ add_com ("attach", class_run, attach_command,
+ "Attach to a process or file outside of GDB.\n\
+This command attaches to another target, of the same type as your last\n\
+`target' command (`info files' will show your target stack).\n\
+The command may take as argument a process id or a device file.\n\
+For a process id, you must have permission to send the process a signal,\n\
+and it must have the same effective uid as the debugger.\n\
+When using \"attach\", you should use the \"file\" command to specify\n\
+the program running in the process, and to load its symbol table.");
+
+ add_com ("detach", class_run, detach_command,
+ "Detach a process or file previously attached.\n\
+If a process, it is no longer traced, and it continues its execution. If you\n\
+were debugging a file, the file is closed and gdb no longer accesses it.");
+
+ add_com ("signal", class_run, signal_command,
+ "Continue program giving it signal number SIGNUMBER.");
+
+ add_com ("stepi", class_run, stepi_command,
+ "Step one instruction exactly.\n\
+Argument N means do this N times (or till program stops for another reason).");
+ add_com_alias ("si", "stepi", class_alias, 0);
+
+ add_com ("nexti", class_run, nexti_command,
+ "Step one instruction, but proceed through subroutine calls.\n\
+Argument N means do this N times (or till program stops for another reason).");
+ add_com_alias ("ni", "nexti", class_alias, 0);
+
+ add_com ("finish", class_run, finish_command,
+ "Execute until selected stack frame returns.\n\
+Upon return, the value returned is printed and put in the value history.");
+
+ add_com ("next", class_run, next_command,
+ "Step program, proceeding through subroutine calls.\n\
+Like the \"step\" command as long as subroutine calls do not happen;\n\
+when they do, the call is treated as one instruction.\n\
+Argument N means do this N times (or till program stops for another reason).");
+ add_com_alias ("n", "next", class_run, 1);
+
+ add_com ("step", class_run, step_command,
+ "Step program until it reaches a different source line.\n\
+Argument N means do this N times (or till program stops for another reason).");
+ add_com_alias ("s", "step", class_run, 1);
+
+ add_com ("until", class_run, until_command,
+ "Execute until the program reaches a source line greater than the current\n\
+or a specified line or address or function (same args as break command).\n\
+Execution will also stop upon exit from the current stack frame.");
+ add_com_alias ("u", "until", class_run, 1);
+
+ add_com ("jump", class_run, jump_command,
+ "Continue program being debugged at specified line or address.\n\
+Give as argument either LINENUM or *ADDR, where ADDR is an expression\n\
+for an address to start at.");
+
+ add_com ("continue", class_run, continue_command,
+ "Continue program being debugged, after signal or breakpoint.\n\
+If proceeding from breakpoint, a number N may be used as an argument,\n\
+which means to set the ignore count of that breakpoint to N - 1 (so that\n\
+the breakpoint won't break until the Nth time it is reached).");
+ add_com_alias ("c", "cont", class_run, 1);
+ add_com_alias ("fg", "cont", class_run, 1);
+
+ add_com ("run", class_run, run_command,
+ "Start debugged program. You may specify arguments to give it.\n\
+Args may include \"*\", or \"[...]\"; they are expanded using \"sh\".\n\
+Input and output redirection with \">\", \"<\", or \">>\" are also allowed.\n\n\
+With no arguments, uses arguments last specified (with \"run\" or \"set args\").\n\
+To cancel previous arguments and run with no arguments,\n\
+use \"set args\" without arguments.");
+ add_com_alias ("r", "run", class_run, 1);
+
+ add_info ("registers", nofp_registers_info,
+ "List of integer registers and their contents, for selected stack frame.\n\
+Register name as argument means describe only that register.");
+
+ add_info ("all-registers", all_registers_info,
+"List of all registers and their contents, for selected stack frame.\n\
+Register name as argument means describe only that register.");
+
+ add_info ("program", program_info,
+ "Execution status of the program.");
+
+ add_info ("float", float_info,
+ "Print the status of the floating point unit\n");
+
+ inferior_args = savestring ("", 1); /* Initially no args */
+ inferior_environ = make_environ ();
+ init_environ (inferior_environ);
+}
diff --git a/gnu/usr.bin/gdb/gdb/inferior.h b/gnu/usr.bin/gdb/gdb/inferior.h
new file mode 100644
index 0000000..6fd94a6
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/inferior.h
@@ -0,0 +1,420 @@
+/* Variables that describe the inferior process running under GDB:
+ Where it is, why it stopped, and how to step it.
+ Copyright 1986, 1989, 1992 Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#if !defined (INFERIOR_H)
+#define INFERIOR_H 1
+
+/* For bpstat. */
+#include "breakpoint.h"
+
+/* For FRAME_ADDR. */
+#include "frame.h"
+
+/* For enum target_signal. */
+#include "target.h"
+
+/*
+ * Structure in which to save the status of the inferior. Save
+ * through "save_inferior_status", restore through
+ * "restore_inferior_status".
+ * This pair of routines should be called around any transfer of
+ * control to the inferior which you don't want showing up in your
+ * control variables.
+ */
+struct inferior_status {
+ enum target_signal stop_signal;
+ CORE_ADDR stop_pc;
+ FRAME_ADDR stop_frame_address;
+ bpstat stop_bpstat;
+ int stop_step;
+ int stop_stack_dummy;
+ int stopped_by_random_signal;
+ int trap_expected;
+ CORE_ADDR step_range_start;
+ CORE_ADDR step_range_end;
+ FRAME_ADDR step_frame_address;
+ int step_over_calls;
+ CORE_ADDR step_resume_break_address;
+ int stop_after_trap;
+ int stop_soon_quietly;
+ FRAME_ADDR selected_frame_address;
+ int selected_level;
+ char stop_registers[REGISTER_BYTES];
+
+ /* These are here because if call_function_by_hand has written some
+ registers and then decides to call error(), we better not have changed
+ any registers. */
+ char registers[REGISTER_BYTES];
+
+ int breakpoint_proceeded;
+ int restore_stack_info;
+ int proceed_to_finish;
+};
+
+/* This macro gives the number of registers actually in use by the
+ inferior. This may be less than the total number of registers,
+ perhaps depending on the actual CPU in use or program being run. */
+
+#ifndef ARCH_NUM_REGS
+#define ARCH_NUM_REGS NUM_REGS
+#endif
+
+extern void
+save_inferior_status PARAMS ((struct inferior_status *, int));
+
+extern void
+restore_inferior_status PARAMS ((struct inferior_status *));
+
+extern void set_sigint_trap PARAMS ((void));
+extern void clear_sigint_trap PARAMS ((void));
+
+extern void set_sigio_trap PARAMS ((void));
+extern void clear_sigio_trap PARAMS ((void));
+
+/* File name for default use for standard in/out in the inferior. */
+
+extern char *inferior_io_terminal;
+
+/* Pid of our debugged inferior, or 0 if no inferior now. */
+
+extern int inferior_pid;
+
+/* Character array containing an image of the inferior programs' registers. */
+
+extern char registers[];
+
+/* Array of validity bits (one per register). Nonzero at position XXX_REGNUM
+ means that `registers' contains a valid copy of inferior register XXX. */
+
+extern char register_valid[NUM_REGS];
+
+extern void
+clear_proceed_status PARAMS ((void));
+
+extern void
+proceed PARAMS ((CORE_ADDR, enum target_signal, int));
+
+extern void
+kill_inferior PARAMS ((void));
+
+extern void
+generic_mourn_inferior PARAMS ((void));
+
+extern void
+terminal_ours PARAMS ((void));
+
+extern int run_stack_dummy PARAMS ((CORE_ADDR, char [REGISTER_BYTES]));
+
+extern CORE_ADDR
+read_pc PARAMS ((void));
+
+extern CORE_ADDR
+read_pc_pid PARAMS ((int));
+
+extern void
+write_pc PARAMS ((CORE_ADDR));
+
+extern CORE_ADDR
+read_sp PARAMS ((void));
+
+extern void
+write_sp PARAMS ((CORE_ADDR));
+
+extern CORE_ADDR
+read_fp PARAMS ((void));
+
+extern void
+write_fp PARAMS ((CORE_ADDR));
+
+extern void
+wait_for_inferior PARAMS ((void));
+
+extern void
+init_wait_for_inferior PARAMS ((void));
+
+extern void
+close_exec_file PARAMS ((void));
+
+extern void
+reopen_exec_file PARAMS ((void));
+
+/* The `resume' routine should only be called in special circumstances.
+ Normally, use `proceed', which handles a lot of bookkeeping. */
+extern void
+resume PARAMS ((int, enum target_signal));
+
+/* From misc files */
+
+extern void
+store_inferior_registers PARAMS ((int));
+
+extern void
+fetch_inferior_registers PARAMS ((int));
+
+extern void
+solib_create_inferior_hook PARAMS ((void));
+
+extern void
+child_terminal_info PARAMS ((char *, int));
+
+extern void
+term_info PARAMS ((char *, int));
+
+extern void
+terminal_ours_for_output PARAMS ((void));
+
+extern void
+terminal_inferior PARAMS ((void));
+
+extern void
+terminal_init_inferior PARAMS ((void));
+
+/* From infptrace.c */
+
+extern int
+attach PARAMS ((int));
+
+void
+detach PARAMS ((int));
+
+extern void
+child_resume PARAMS ((int, int, enum target_signal));
+
+#ifndef PTRACE_ARG3_TYPE
+#define PTRACE_ARG3_TYPE int /* Correct definition for most systems. */
+#endif
+
+extern int
+call_ptrace PARAMS ((int, int, PTRACE_ARG3_TYPE, int));
+
+/* From procfs.c */
+
+extern int
+proc_iterate_over_mappings PARAMS ((int (*) (int, CORE_ADDR)));
+
+/* From fork-child.c */
+
+extern void fork_inferior PARAMS ((char *, char *, char **,
+ void (*) (void),
+ void (*) (int), char *));
+
+extern void startup_inferior PARAMS ((int));
+
+/* From inflow.c */
+
+extern void
+new_tty_prefork PARAMS ((char *));
+
+extern int gdb_has_a_terminal PARAMS ((void));
+
+/* From infrun.c */
+
+extern void
+start_remote PARAMS ((void));
+
+extern void
+normal_stop PARAMS ((void));
+
+extern int
+signal_stop_state PARAMS ((int));
+
+extern int
+signal_print_state PARAMS ((int));
+
+extern int
+signal_pass_state PARAMS ((int));
+
+/* From infcmd.c */
+
+extern void
+tty_command PARAMS ((char *, int));
+
+extern void
+attach_command PARAMS ((char *, int));
+
+/* Last signal that the inferior received (why it stopped). */
+
+extern enum target_signal stop_signal;
+
+/* Address at which inferior stopped. */
+
+extern CORE_ADDR stop_pc;
+
+/* Stack frame when program stopped. */
+
+extern FRAME_ADDR stop_frame_address;
+
+/* Chain containing status of breakpoint(s) that we have stopped at. */
+
+extern bpstat stop_bpstat;
+
+/* Flag indicating that a command has proceeded the inferior past the
+ current breakpoint. */
+
+extern int breakpoint_proceeded;
+
+/* Nonzero if stopped due to a step command. */
+
+extern int stop_step;
+
+/* Nonzero if stopped due to completion of a stack dummy routine. */
+
+extern int stop_stack_dummy;
+
+/* Nonzero if program stopped due to a random (unexpected) signal in
+ inferior process. */
+
+extern int stopped_by_random_signal;
+
+/* Range to single step within.
+ If this is nonzero, respond to a single-step signal
+ by continuing to step if the pc is in this range.
+
+ If step_range_start and step_range_end are both 1, it means to step for
+ a single instruction (FIXME: it might clean up wait_for_inferior in a
+ minor way if this were changed to the address of the instruction and
+ that address plus one. But maybe not.). */
+
+extern CORE_ADDR step_range_start; /* Inclusive */
+extern CORE_ADDR step_range_end; /* Exclusive */
+
+/* Stack frame address as of when stepping command was issued.
+ This is how we know when we step into a subroutine call,
+ and how to set the frame for the breakpoint used to step out. */
+
+extern FRAME_ADDR step_frame_address;
+
+/* 1 means step over all subroutine calls.
+ -1 means step over calls to undebuggable functions. */
+
+extern int step_over_calls;
+
+/* If stepping, nonzero means step count is > 1
+ so don't print frame next time inferior stops
+ if it stops due to stepping. */
+
+extern int step_multi;
+
+/* Nonzero means expecting a trap and caller will handle it themselves.
+ It is used after attach, due to attaching to a process;
+ when running in the shell before the child program has been exec'd;
+ and when running some kinds of remote stuff (FIXME?). */
+
+extern int stop_soon_quietly;
+
+/* Nonzero if proceed is being used for a "finish" command or a similar
+ situation when stop_registers should be saved. */
+
+extern int proceed_to_finish;
+
+/* Save register contents here when about to pop a stack dummy frame,
+ if-and-only-if proceed_to_finish is set.
+ Thus this contains the return value from the called function (assuming
+ values are returned in a register). */
+
+extern char stop_registers[REGISTER_BYTES];
+
+/* Nonzero if the child process in inferior_pid was attached rather
+ than forked. */
+
+extern int attach_flag;
+
+/* Sigtramp is a routine that the kernel calls (which then calls the
+ signal handler). On most machines it is a library routine that
+ is linked into the executable.
+
+ This macro, given a program counter value and the name of the
+ function in which that PC resides (which can be null if the
+ name is not known), returns nonzero if the PC and name show
+ that we are in sigtramp.
+
+ On most machines just see if the name is sigtramp (and if we have
+ no name, assume we are not in sigtramp). */
+#if !defined (IN_SIGTRAMP)
+# if defined (SIGTRAMP_START)
+# define IN_SIGTRAMP(pc, name) \
+ ((pc) >= SIGTRAMP_START \
+ && (pc) < SIGTRAMP_END \
+ )
+# else
+# define IN_SIGTRAMP(pc, name) \
+ (name && STREQ ("_sigtramp", name))
+# endif
+#endif
+
+/* Possible values for CALL_DUMMY_LOCATION. */
+#define ON_STACK 1
+#define BEFORE_TEXT_END 2
+#define AFTER_TEXT_END 3
+#define AT_ENTRY_POINT 4
+
+#if !defined (CALL_DUMMY_LOCATION)
+#define CALL_DUMMY_LOCATION ON_STACK
+#endif /* No CALL_DUMMY_LOCATION. */
+
+/* Are we in a call dummy? The code below which allows DECR_PC_AFTER_BREAK
+ below is for infrun.c, which may give the macro a pc without that
+ subtracted out. */
+#if !defined (PC_IN_CALL_DUMMY)
+#if CALL_DUMMY_LOCATION == BEFORE_TEXT_END
+extern CORE_ADDR text_end;
+#define PC_IN_CALL_DUMMY(pc, sp, frame_address) \
+ ((pc) >= text_end - CALL_DUMMY_LENGTH \
+ && (pc) <= text_end + DECR_PC_AFTER_BREAK)
+#endif /* Before text_end. */
+
+#if CALL_DUMMY_LOCATION == AFTER_TEXT_END
+extern CORE_ADDR text_end;
+#define PC_IN_CALL_DUMMY(pc, sp, frame_address) \
+ ((pc) >= text_end \
+ && (pc) <= text_end + CALL_DUMMY_LENGTH + DECR_PC_AFTER_BREAK)
+#endif /* After text_end. */
+
+#if CALL_DUMMY_LOCATION == ON_STACK
+/* Is the PC in a call dummy? SP and FRAME_ADDRESS are the bottom and
+ top of the stack frame which we are checking, where "bottom" and
+ "top" refer to some section of memory which contains the code for
+ the call dummy. Calls to this macro assume that the contents of
+ SP_REGNUM and FP_REGNUM (or the saved values thereof), respectively,
+ are the things to pass.
+
+ This won't work on the 29k, where SP_REGNUM and FP_REGNUM don't
+ have that meaning, but the 29k doesn't use ON_STACK. This could be
+ fixed by generalizing this scheme, perhaps by passing in a frame
+ and adding a few fields, at least on machines which need them for
+ PC_IN_CALL_DUMMY.
+
+ Something simpler, like checking for the stack segment, doesn't work,
+ since various programs (threads implementations, gcc nested function
+ stubs, etc) may either allocate stack frames in another segment, or
+ allocate other kinds of code on the stack. */
+
+#define PC_IN_CALL_DUMMY(pc, sp, frame_address) \
+ ((sp) INNER_THAN (pc) && (frame_address != 0) && (pc) INNER_THAN (frame_address))
+#endif /* On stack. */
+
+#if CALL_DUMMY_LOCATION == AT_ENTRY_POINT
+#define PC_IN_CALL_DUMMY(pc, sp, frame_address) \
+ ((pc) >= CALL_DUMMY_ADDRESS () \
+ && (pc) <= (CALL_DUMMY_ADDRESS () + DECR_PC_AFTER_BREAK))
+#endif /* At entry point. */
+#endif /* No PC_IN_CALL_DUMMY. */
+
+#endif /* !defined (INFERIOR_H) */
diff --git a/gnu/usr.bin/gdb/gdb/inflow.c b/gnu/usr.bin/gdb/gdb/inflow.c
new file mode 100644
index 0000000..fc937da
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/inflow.c
@@ -0,0 +1,711 @@
+/* Low level interface to ptrace, for GDB when running under Unix.
+ Copyright 1986, 1987, 1989, 1991, 1992 Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "defs.h"
+#include "frame.h"
+#include "inferior.h"
+#include "command.h"
+#include "signals.h"
+#include "serial.h"
+#include "terminal.h"
+#include "target.h"
+#include "thread.h"
+
+#include <signal.h>
+#include <fcntl.h>
+
+#if !defined (HAVE_TERMIOS) && !defined (HAVE_TERMIO) && !defined (HAVE_SGTTY) && !defined (__GO32__)
+#define HAVE_SGTTY
+#endif
+
+#if defined (HAVE_TERMIOS)
+#include <termios.h>
+#include <unistd.h>
+#endif
+
+#ifdef HAVE_TERMIOS
+#define PROCESS_GROUP_TYPE pid_t
+#endif
+
+#ifdef HAVE_SGTTY
+#ifdef SHORT_PGRP
+/* This is only used for the ultra. Does it have pid_t? */
+#define PROCESS_GROUP_TYPE short
+#else
+#define PROCESS_GROUP_TYPE int
+#endif
+#endif /* sgtty */
+
+static void
+kill_command PARAMS ((char *, int));
+
+static void
+terminal_ours_1 PARAMS ((int));
+
+/* Record terminal status separately for debugger and inferior. */
+
+static serial_t stdin_serial;
+
+/* TTY state for the inferior. We save it whenever the inferior stops, and
+ restore it when it resumes. */
+static serial_ttystate inferior_ttystate;
+
+/* Our own tty state, which we restore every time we need to deal with the
+ terminal. We only set it once, when GDB first starts. The settings of
+ flags which readline saves and restores and unimportant. */
+static serial_ttystate our_ttystate;
+
+/* fcntl flags for us and the inferior. Saved and restored just like
+ {our,inferior}_ttystate. */
+static int tflags_inferior;
+static int tflags_ours;
+
+#ifdef PROCESS_GROUP_TYPE
+/* Process group for us and the inferior. Saved and restored just like
+ {our,inferior}_ttystate. */
+PROCESS_GROUP_TYPE our_process_group;
+PROCESS_GROUP_TYPE inferior_process_group;
+#endif
+
+/* While the inferior is running, we want SIGINT and SIGQUIT to go to the
+ inferior only. If we have job control, that takes care of it. If not,
+ we save our handlers in these two variables and set SIGINT and SIGQUIT
+ to SIG_IGN. */
+static void (*sigint_ours) ();
+static void (*sigquit_ours) ();
+
+/* The name of the tty (from the `tty' command) that we gave to the inferior
+ when it was last started. */
+
+static char *inferior_thisrun_terminal;
+
+/* Nonzero if our terminal settings are in effect. Zero if the
+ inferior's settings are in effect. Ignored if !gdb_has_a_terminal
+ (). */
+
+static int terminal_is_ours;
+
+enum {yes, no, have_not_checked} gdb_has_a_terminal_flag = have_not_checked;
+
+/* Does GDB have a terminal (on stdin)? */
+int
+gdb_has_a_terminal ()
+{
+ switch (gdb_has_a_terminal_flag)
+ {
+ case yes:
+ return 1;
+ case no:
+ return 0;
+ case have_not_checked:
+ /* Get all the current tty settings (including whether we have a tty at
+ all!). Can't do this in _initialize_inflow because SERIAL_FDOPEN
+ won't work until the serial_ops_list is initialized. */
+
+#ifdef F_GETFL
+ tflags_ours = fcntl (0, F_GETFL, 0);
+#endif
+
+ gdb_has_a_terminal_flag = no;
+ stdin_serial = SERIAL_FDOPEN (0);
+ if (stdin_serial != NULL)
+ {
+ our_ttystate = SERIAL_GET_TTY_STATE (stdin_serial);
+
+ if (our_ttystate != NULL)
+ {
+ gdb_has_a_terminal_flag = yes;
+#ifdef HAVE_TERMIOS
+ our_process_group = tcgetpgrp (0);
+#endif
+#ifdef HAVE_SGTTY
+ ioctl (0, TIOCGPGRP, &our_process_group);
+#endif
+ }
+ }
+
+ return gdb_has_a_terminal_flag == yes;
+ default:
+ /* "Can't happen". */
+ return 0;
+ }
+}
+
+/* Macro for printing errors from ioctl operations */
+
+#define OOPSY(what) \
+ if (result == -1) \
+ fprintf_unfiltered(gdb_stderr, "[%s failed in terminal_inferior: %s]\n", \
+ what, strerror (errno))
+
+static void terminal_ours_1 PARAMS ((int));
+
+/* Initialize the terminal settings we record for the inferior,
+ before we actually run the inferior. */
+
+void
+terminal_init_inferior ()
+{
+ if (gdb_has_a_terminal ())
+ {
+ /* We could just as well copy our_ttystate (if we felt like adding
+ a new function SERIAL_COPY_TTY_STATE). */
+ if (inferior_ttystate)
+ free (inferior_ttystate);
+ inferior_ttystate = SERIAL_GET_TTY_STATE (stdin_serial);
+#ifdef PROCESS_GROUP_TYPE
+#ifdef PIDGET
+ /* This is for Lynx, and should be cleaned up by having Lynx be
+ a separate debugging target with a version of
+ target_terminal_init_inferior which passes in the process
+ group to a generic routine which does all the work (and the
+ non-threaded child_terminal_init_inferior can just pass in
+ inferior_pid to the same routine). */
+ inferior_process_group = PIDGET (inferior_pid);
+#else
+ inferior_process_group = inferior_pid;
+#endif
+#endif
+
+ /* Make sure that next time we call terminal_inferior (which will be
+ before the program runs, as it needs to be), we install the new
+ process group. */
+ terminal_is_ours = 1;
+ }
+}
+
+/* Put the inferior's terminal settings into effect.
+ This is preparation for starting or resuming the inferior. */
+
+void
+terminal_inferior ()
+{
+ if (gdb_has_a_terminal () && terminal_is_ours
+ && inferior_thisrun_terminal == 0)
+ {
+ int result;
+
+#ifdef F_GETFL
+ /* Is there a reason this is being done twice? It happens both
+ places we use F_SETFL, so I'm inclined to think perhaps there
+ is some reason, however perverse. Perhaps not though... */
+ result = fcntl (0, F_SETFL, tflags_inferior);
+ result = fcntl (0, F_SETFL, tflags_inferior);
+ OOPSY ("fcntl F_SETFL");
+#endif
+
+ /* Because we were careful to not change in or out of raw mode in
+ terminal_ours, we will not change in our out of raw mode with
+ this call, so we don't flush any input. */
+ result = SERIAL_SET_TTY_STATE (stdin_serial, inferior_ttystate);
+ OOPSY ("setting tty state");
+
+ if (!job_control)
+ {
+ sigint_ours = (void (*) ()) signal (SIGINT, SIG_IGN);
+ sigquit_ours = (void (*) ()) signal (SIGQUIT, SIG_IGN);
+ }
+
+ /* If attach_flag is set, we don't know whether we are sharing a
+ terminal with the inferior or not. (attaching a process
+ without a terminal is one case where we do not; attaching a
+ process which we ran from the same shell as GDB via `&' is
+ one case where we do, I think (but perhaps this is not
+ `sharing' in the sense that we need to save and restore tty
+ state)). I don't know if there is any way to tell whether we
+ are sharing a terminal. So what we do is to go through all
+ the saving and restoring of the tty state, but ignore errors
+ setting the process group, which will happen if we are not
+ sharing a terminal). */
+
+ if (job_control)
+ {
+#ifdef HAVE_TERMIOS
+ result = tcsetpgrp (0, inferior_process_group);
+ if (!attach_flag)
+ OOPSY ("tcsetpgrp");
+#endif
+
+#ifdef HAVE_SGTTY
+ result = ioctl (0, TIOCSPGRP, &inferior_process_group);
+ if (!attach_flag)
+ OOPSY ("TIOCSPGRP");
+#endif
+ }
+
+ }
+ terminal_is_ours = 0;
+}
+
+/* Put some of our terminal settings into effect,
+ enough to get proper results from our output,
+ but do not change into or out of RAW mode
+ so that no input is discarded.
+
+ After doing this, either terminal_ours or terminal_inferior
+ should be called to get back to a normal state of affairs. */
+
+void
+terminal_ours_for_output ()
+{
+ terminal_ours_1 (1);
+}
+
+/* Put our terminal settings into effect.
+ First record the inferior's terminal settings
+ so they can be restored properly later. */
+
+void
+terminal_ours ()
+{
+ terminal_ours_1 (0);
+}
+
+/* output_only is not used, and should not be used unless we introduce
+ separate terminal_is_ours and terminal_is_ours_for_output
+ flags. */
+
+static void
+terminal_ours_1 (output_only)
+ int output_only;
+{
+ /* Checking inferior_thisrun_terminal is necessary so that
+ if GDB is running in the background, it won't block trying
+ to do the ioctl()'s below. Checking gdb_has_a_terminal
+ avoids attempting all the ioctl's when running in batch. */
+ if (inferior_thisrun_terminal != 0 || gdb_has_a_terminal () == 0)
+ return;
+
+ if (!terminal_is_ours)
+ {
+ /* Ignore this signal since it will happen when we try to set the
+ pgrp. */
+ void (*osigttou) ();
+ int result;
+
+ terminal_is_ours = 1;
+
+#ifdef SIGTTOU
+ if (job_control)
+ osigttou = (void (*) ()) signal (SIGTTOU, SIG_IGN);
+#endif
+
+ if (inferior_ttystate)
+ free (inferior_ttystate);
+ inferior_ttystate = SERIAL_GET_TTY_STATE (stdin_serial);
+#ifdef HAVE_TERMIOS
+ inferior_process_group = tcgetpgrp (0);
+#endif
+#ifdef HAVE_SGTTY
+ ioctl (0, TIOCGPGRP, &inferior_process_group);
+#endif
+
+ /* Here we used to set ICANON in our ttystate, but I believe this
+ was an artifact from before when we used readline. Readline sets
+ the tty state when it needs to.
+ FIXME-maybe: However, query() expects non-raw mode and doesn't
+ use readline. Maybe query should use readline (on the other hand,
+ this only matters for HAVE_SGTTY, not termio or termios, I think). */
+
+ /* Set tty state to our_ttystate. We don't change in our out of raw
+ mode, to avoid flushing input. We need to do the same thing
+ regardless of output_only, because we don't have separate
+ terminal_is_ours and terminal_is_ours_for_output flags. It's OK,
+ though, since readline will deal with raw mode when/if it needs to.
+ */
+
+ SERIAL_NOFLUSH_SET_TTY_STATE (stdin_serial, our_ttystate,
+ inferior_ttystate);
+
+ if (job_control)
+ {
+#ifdef HAVE_TERMIOS
+ result = tcsetpgrp (0, our_process_group);
+#if 0
+ /* This fails on Ultrix with EINVAL if you run the testsuite
+ in the background with nohup, and then log out. GDB never
+ used to check for an error here, so perhaps there are other
+ such situations as well. */
+ if (result == -1)
+ fprintf_unfiltered (gdb_stderr, "[tcsetpgrp failed in terminal_ours: %s]\n",
+ strerror (errno));
+#endif
+#endif /* termios */
+
+#ifdef HAVE_SGTTY
+ result = ioctl (0, TIOCSPGRP, &our_process_group);
+#endif
+ }
+
+#ifdef SIGTTOU
+ if (job_control)
+ signal (SIGTTOU, osigttou);
+#endif
+
+ if (!job_control)
+ {
+ signal (SIGINT, sigint_ours);
+ signal (SIGQUIT, sigquit_ours);
+ }
+
+#ifdef F_GETFL
+ tflags_inferior = fcntl (0, F_GETFL, 0);
+
+ /* Is there a reason this is being done twice? It happens both
+ places we use F_SETFL, so I'm inclined to think perhaps there
+ is some reason, however perverse. Perhaps not though... */
+ result = fcntl (0, F_SETFL, tflags_ours);
+ result = fcntl (0, F_SETFL, tflags_ours);
+#endif
+
+ result = result; /* lint */
+ }
+}
+
+/* ARGSUSED */
+void
+term_info (arg, from_tty)
+ char *arg;
+ int from_tty;
+{
+ target_terminal_info (arg, from_tty);
+}
+
+/* ARGSUSED */
+void
+child_terminal_info (args, from_tty)
+ char *args;
+ int from_tty;
+{
+ if (!gdb_has_a_terminal ())
+ {
+ printf_filtered ("This GDB does not control a terminal.\n");
+ return;
+ }
+
+ printf_filtered ("Inferior's terminal status (currently saved by GDB):\n");
+
+ /* First the fcntl flags. */
+ {
+ int flags;
+
+ flags = tflags_inferior;
+
+ printf_filtered ("File descriptor flags = ");
+
+#ifndef O_ACCMODE
+#define O_ACCMODE (O_RDONLY | O_WRONLY | O_RDWR)
+#endif
+ /* (O_ACCMODE) parens are to avoid Ultrix header file bug */
+ switch (flags & (O_ACCMODE))
+ {
+ case O_RDONLY: printf_filtered ("O_RDONLY"); break;
+ case O_WRONLY: printf_filtered ("O_WRONLY"); break;
+ case O_RDWR: printf_filtered ("O_RDWR"); break;
+ }
+ flags &= ~(O_ACCMODE);
+
+#ifdef O_NONBLOCK
+ if (flags & O_NONBLOCK)
+ printf_filtered (" | O_NONBLOCK");
+ flags &= ~O_NONBLOCK;
+#endif
+
+#if defined (O_NDELAY)
+ /* If O_NDELAY and O_NONBLOCK are defined to the same thing, we will
+ print it as O_NONBLOCK, which is good cause that is what POSIX
+ has, and the flag will already be cleared by the time we get here. */
+ if (flags & O_NDELAY)
+ printf_filtered (" | O_NDELAY");
+ flags &= ~O_NDELAY;
+#endif
+
+ if (flags & O_APPEND)
+ printf_filtered (" | O_APPEND");
+ flags &= ~O_APPEND;
+
+#if defined (O_BINARY)
+ if (flags & O_BINARY)
+ printf_filtered (" | O_BINARY");
+ flags &= ~O_BINARY;
+#endif
+
+ if (flags)
+ printf_filtered (" | 0x%x", flags);
+ printf_filtered ("\n");
+ }
+
+#ifdef PROCESS_GROUP_TYPE
+ printf_filtered ("Process group = %d\n", inferior_process_group);
+#endif
+
+ SERIAL_PRINT_TTY_STATE (stdin_serial, inferior_ttystate);
+}
+
+/* NEW_TTY_PREFORK is called before forking a new child process,
+ so we can record the state of ttys in the child to be formed.
+ TTYNAME is null if we are to share the terminal with gdb;
+ or points to a string containing the name of the desired tty.
+
+ NEW_TTY is called in new child processes under Unix, which will
+ become debugger target processes. This actually switches to
+ the terminal specified in the NEW_TTY_PREFORK call. */
+
+void
+new_tty_prefork (ttyname)
+ char *ttyname;
+{
+ /* Save the name for later, for determining whether we and the child
+ are sharing a tty. */
+ inferior_thisrun_terminal = ttyname;
+}
+
+void
+new_tty ()
+{
+ register int tty;
+
+ if (inferior_thisrun_terminal == 0)
+ return;
+#if !defined(__GO32__)
+#ifdef TIOCNOTTY
+ /* Disconnect the child process from our controlling terminal. On some
+ systems (SVR4 for example), this may cause a SIGTTOU, so temporarily
+ ignore SIGTTOU. */
+ tty = open("/dev/tty", O_RDWR);
+ if (tty > 0)
+ {
+ void (*osigttou) ();
+
+ osigttou = (void (*)()) signal(SIGTTOU, SIG_IGN);
+ ioctl(tty, TIOCNOTTY, 0);
+ close(tty);
+ signal(SIGTTOU, osigttou);
+ }
+#endif
+
+ /* Now open the specified new terminal. */
+
+#ifdef USE_O_NOCTTY
+ tty = open(inferior_thisrun_terminal, O_RDWR | O_NOCTTY);
+#else
+ tty = open(inferior_thisrun_terminal, O_RDWR);
+#endif
+ if (tty == -1)
+ {
+ print_sys_errmsg (inferior_thisrun_terminal, errno);
+ _exit(1);
+ }
+
+ /* Avoid use of dup2; doesn't exist on all systems. */
+ if (tty != 0)
+ { close (0); dup (tty); }
+ if (tty != 1)
+ { close (1); dup (tty); }
+ if (tty != 2)
+ { close (2); dup (tty); }
+ if (tty > 2)
+ close(tty);
+#endif /* !go32 */
+}
+
+/* Kill the inferior process. Make us have no inferior. */
+
+/* ARGSUSED */
+static void
+kill_command (arg, from_tty)
+ char *arg;
+ int from_tty;
+{
+ /* Shouldn't this be target_has_execution? FIXME. */
+ if (inferior_pid == 0)
+ error ("The program is not being run.");
+ if (!query ("Kill the program being debugged? "))
+ error ("Not confirmed.");
+ target_kill ();
+
+ init_thread_list(); /* Destroy thread info */
+
+ /* Killing off the inferior can leave us with a core file. If so,
+ print the state we are left in. */
+ if (target_has_stack) {
+ printf_filtered ("In %s,\n", current_target->to_longname);
+ if (selected_frame == NULL)
+ fputs_filtered ("No selected stack frame.\n", gdb_stdout);
+ else
+ print_stack_frame (selected_frame, selected_frame_level, 1);
+ }
+}
+
+/* Call set_sigint_trap when you need to pass a signal on to an attached
+ process when handling SIGINT */
+
+/* ARGSUSED */
+static void
+pass_signal (signo)
+ int signo;
+{
+ kill (inferior_pid, SIGINT);
+}
+
+static void (*osig)();
+
+void
+set_sigint_trap()
+{
+ osig = (void (*) ()) signal (SIGINT, pass_signal);
+}
+
+void
+clear_sigint_trap()
+{
+ signal (SIGINT, osig);
+}
+
+#if defined (SIGIO) && defined (FASYNC) && defined (FD_SET) && defined (F_SETOWN)
+static void (*old_sigio) ();
+
+static void
+handle_sigio (signo)
+ int signo;
+{
+ int numfds;
+ fd_set readfds;
+
+ signal (SIGIO, handle_sigio);
+
+ FD_ZERO (&readfds);
+ FD_SET (target_activity_fd, &readfds);
+ numfds = select (target_activity_fd + 1, &readfds, NULL, NULL, NULL);
+ if (numfds >= 0 && FD_ISSET (target_activity_fd, &readfds))
+ {
+ if ((*target_activity_function) ())
+ kill (inferior_pid, SIGINT);
+ }
+}
+
+static int old_fcntl_flags;
+
+void
+set_sigio_trap ()
+{
+ if (target_activity_function)
+ {
+ old_sigio = (void (*) ()) signal (SIGIO, handle_sigio);
+ fcntl (target_activity_fd, F_SETOWN, getpid());
+ old_fcntl_flags = fcntl (target_activity_fd, F_GETFL, 0);
+ fcntl (target_activity_fd, F_SETFL, old_fcntl_flags | FASYNC);
+ }
+}
+
+void
+clear_sigio_trap ()
+{
+ if (target_activity_function)
+ {
+ signal (SIGIO, old_sigio);
+ fcntl (target_activity_fd, F_SETFL, old_fcntl_flags);
+ }
+}
+#else /* No SIGIO. */
+void
+set_sigio_trap ()
+{
+ if (target_activity_function)
+ abort ();
+}
+
+void
+clear_sigio_trap ()
+{
+ if (target_activity_function)
+ abort ();
+}
+#endif /* No SIGIO. */
+
+
+/* This is here because this is where we figure out whether we (probably)
+ have job control. Just using job_control only does part of it because
+ setpgid or setpgrp might not exist on a system without job control.
+ It might be considered misplaced (on the other hand, process groups and
+ job control are closely related to ttys).
+
+ For a more clean implementation, in libiberty, put a setpgid which merely
+ calls setpgrp and a setpgrp which does nothing (any system with job control
+ will have one or the other). */
+int
+gdb_setpgid ()
+{
+ int retval = 0;
+
+ if (job_control)
+ {
+#if defined (NEED_POSIX_SETPGID) || defined (HAVE_TERMIOS)
+ /* Do all systems with termios have setpgid? I hope so. */
+ /* setpgid (0, 0) is supposed to work and mean the same thing as
+ this, but on Ultrix 4.2A it fails with EPERM (and
+ setpgid (getpid (), getpid ()) succeeds). */
+ retval = setpgid (getpid (), getpid ());
+#else
+#if defined (TIOCGPGRP)
+#if defined(USG) && !defined(SETPGRP_ARGS)
+ retval = setpgrp ();
+#else
+ retval = setpgrp (getpid (), getpid ());
+#endif /* USG */
+#endif /* TIOCGPGRP. */
+#endif /* NEED_POSIX_SETPGID */
+ }
+ return retval;
+}
+
+void
+_initialize_inflow ()
+{
+ add_info ("terminal", term_info,
+ "Print inferior's saved terminal status.");
+
+ add_com ("kill", class_run, kill_command,
+ "Kill execution of program being debugged.");
+
+ inferior_pid = 0;
+
+ terminal_is_ours = 1;
+
+ /* OK, figure out whether we have job control. If neither termios nor
+ sgtty (i.e. termio or go32), leave job_control 0. */
+
+#if defined (HAVE_TERMIOS)
+ /* Do all systems with termios have the POSIX way of identifying job
+ control? I hope so. */
+#ifdef _POSIX_JOB_CONTROL
+ job_control = 1;
+#else
+ job_control = sysconf (_SC_JOB_CONTROL);
+#endif
+#endif /* termios */
+
+#ifdef HAVE_SGTTY
+#ifdef TIOCGPGRP
+ job_control = 1;
+#else
+ job_control = 0;
+#endif /* TIOCGPGRP */
+#endif /* sgtty */
+}
diff --git a/gnu/usr.bin/gdb/gdb/infptrace.c b/gnu/usr.bin/gdb/gdb/infptrace.c
new file mode 100644
index 0000000..36a4b4c
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/infptrace.c
@@ -0,0 +1,508 @@
+/* Low level Unix child interface to ptrace, for GDB when running under Unix.
+ Copyright 1988, 1989, 1990, 1991, 1992, 1993, 1994
+ Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "defs.h"
+#include "frame.h"
+#include "inferior.h"
+#include "target.h"
+
+#ifdef USG
+#include <sys/types.h>
+#endif
+
+#include <sys/param.h>
+#include <sys/dir.h>
+#include <signal.h>
+#include <sys/ioctl.h>
+
+#ifndef NO_PTRACE_H
+#ifdef PTRACE_IN_WRONG_PLACE
+#include <ptrace.h>
+#else
+#include <sys/ptrace.h>
+#endif
+#endif /* NO_PTRACE_H */
+
+#if !defined (PT_KILL)
+#define PT_KILL 8
+#endif
+
+#if !defined (PT_STEP)
+#define PT_STEP 9
+#define PT_CONTINUE 7
+#define PT_READ_U 3
+#define PT_WRITE_U 6
+#define PT_READ_I 1
+#define PT_READ_D 2
+#define PT_WRITE_I 4
+#define PT_WRITE_D 5
+#endif /* No PT_STEP. */
+
+#ifndef PT_ATTACH
+#define PT_ATTACH PTRACE_ATTACH
+#endif
+#ifndef PT_DETACH
+#define PT_DETACH PTRACE_DETACH
+#endif
+
+#include "gdbcore.h"
+#ifndef NO_SYS_FILE
+#include <sys/file.h>
+#endif
+#if 0
+/* Don't think this is used anymore. On the sequent (not sure whether it's
+ dynix or ptx or both), it is included unconditionally by sys/user.h and
+ not protected against multiple inclusion. */
+#include <sys/stat.h>
+#endif
+
+#if !defined (FETCH_INFERIOR_REGISTERS)
+#include <sys/user.h> /* Probably need to poke the user structure */
+#if defined (KERNEL_U_ADDR_BSD)
+#include <a.out.h> /* For struct nlist */
+#endif /* KERNEL_U_ADDR_BSD. */
+#endif /* !FETCH_INFERIOR_REGISTERS */
+
+
+/* This function simply calls ptrace with the given arguments.
+ It exists so that all calls to ptrace are isolated in this
+ machine-dependent file. */
+int
+call_ptrace (request, pid, addr, data)
+ int request, pid;
+ PTRACE_ARG3_TYPE addr;
+ int data;
+{
+ return ptrace (request, pid, addr, data
+#if defined (FIVE_ARG_PTRACE)
+ /* Deal with HPUX 8.0 braindamage. We never use the
+ calls which require the fifth argument. */
+ , 0
+#endif
+ );
+}
+
+#if defined (DEBUG_PTRACE) || defined (FIVE_ARG_PTRACE)
+/* For the rest of the file, use an extra level of indirection */
+/* This lets us breakpoint usefully on call_ptrace. */
+#define ptrace call_ptrace
+#endif
+
+void
+kill_inferior ()
+{
+ if (inferior_pid == 0)
+ return;
+ /* ptrace PT_KILL only works if process is stopped!!! So stop it with
+ a real signal first, if we can. FIXME: This is bogus. When the inferior
+ is not stopped, GDB should just be waiting for it. Either the following
+ line is unecessary, or there is some problem elsewhere in GDB which
+ causes us to get here when the inferior is not stopped. */
+ kill (inferior_pid, SIGKILL);
+ ptrace (PT_KILL, inferior_pid, (PTRACE_ARG3_TYPE) 0, 0);
+ wait ((int *)0);
+ target_mourn_inferior ();
+}
+
+#ifndef CHILD_RESUME
+
+/* Resume execution of the inferior process.
+ If STEP is nonzero, single-step it.
+ If SIGNAL is nonzero, give it that signal. */
+
+void
+child_resume (pid, step, signal)
+ int pid;
+ int step;
+ enum target_signal signal;
+{
+ errno = 0;
+
+ if (pid == -1)
+ /* Resume all threads. */
+ /* I think this only gets used in the non-threaded case, where "resume
+ all threads" and "resume inferior_pid" are the same. */
+ pid = inferior_pid;
+
+ /* An address of (PTRACE_ARG3_TYPE)1 tells ptrace to continue from where
+ it was. (If GDB wanted it to start some other way, we have already
+ written a new PC value to the child.)
+
+ If this system does not support PT_STEP, a higher level function will
+ have called single_step() to transmute the step request into a
+ continue request (by setting breakpoints on all possible successor
+ instructions), so we don't have to worry about that here. */
+
+ if (step)
+ ptrace (PT_STEP, pid, (PTRACE_ARG3_TYPE) 1,
+ target_signal_to_host (signal));
+ else
+ ptrace (PT_CONTINUE, pid, (PTRACE_ARG3_TYPE) 1,
+ target_signal_to_host (signal));
+
+ if (errno)
+ perror_with_name ("ptrace");
+}
+#endif /* CHILD_RESUME */
+
+
+#ifdef ATTACH_DETACH
+#include <sys/fcntl.h>
+/* Start debugging the process whose number is PID. */
+int
+attach (pid)
+ int pid;
+{
+#if defined(BSD4_4) && BSD >= 199306
+ char procfile[MAXPATHLEN];
+ int fd;
+
+ sprintf(procfile, "/proc/%d/ctl", pid);
+ fd = open(procfile, O_WRONLY, 0);
+
+ if (fd < 0) {
+ perror_with_name ("open");
+ }
+
+ /* send attach message to the process */
+ if (write (fd, "attach", 7) < 0) {
+ close(fd);
+ perror_with_name ("write:attach");
+ }
+ /* wait for the process to stop */
+#if 0
+ if (write (fd, "wait", 5) < 0) {
+ close(fd);
+ perror_with_name ("write:wait");
+ }
+#endif
+ close (fd);
+#else
+ errno = 0;
+ ptrace (PT_ATTACH, pid, (PTRACE_ARG3_TYPE) 0, 0);
+ if (errno)
+ perror_with_name ("ptrace");
+#endif
+ attach_flag = 1;
+ return pid;
+}
+
+/* Stop debugging the process whose number is PID
+ and continue it with signal number SIGNAL.
+ SIGNAL = 0 means just continue it. */
+
+void
+detach (signal)
+ int signal;
+{
+#if defined(BSD4_4) && BSD >= 199306
+ char procfile[MAXPATHLEN];
+ int fd;
+
+ sprintf(procfile, "/proc/%d/ctl", inferior_pid);
+ fd = open(procfile, O_WRONLY, 0);
+
+ if (fd < 0) {
+ perror_with_name ("open");
+ }
+ /* send detach message to the process */
+ if (write (fd, "detach", 7) < 0) {
+ close(fd);
+ perror_with_name ("write:detach");
+ }
+ /* TODO signals */
+ close (fd);
+#else
+ errno = 0;
+ ptrace (PT_DETACH, inferior_pid, (PTRACE_ARG3_TYPE) 1, signal);
+ if (errno)
+ perror_with_name ("ptrace");
+#endif
+ attach_flag = 0;
+}
+#endif /* ATTACH_DETACH */
+
+/* Default the type of the ptrace transfer to int. */
+#ifndef PTRACE_XFER_TYPE
+#define PTRACE_XFER_TYPE int
+#endif
+
+/* KERNEL_U_ADDR is the amount to subtract from u.u_ar0
+ to get the offset in the core file of the register values. */
+#if defined (KERNEL_U_ADDR_BSD) && !defined (FETCH_INFERIOR_REGISTERS)
+/* Get kernel_u_addr using BSD-style nlist(). */
+CORE_ADDR kernel_u_addr;
+#endif /* KERNEL_U_ADDR_BSD. */
+
+void
+_initialize_kernel_u_addr ()
+{
+#if defined (KERNEL_U_ADDR_BSD) && !defined (FETCH_INFERIOR_REGISTERS)
+ struct nlist names[2];
+
+ names[0].n_un.n_name = "_u";
+ names[1].n_un.n_name = NULL;
+ if (nlist ("/vmunix", names) == 0)
+ kernel_u_addr = names[0].n_value;
+ else
+ fatal ("Unable to get kernel u area address.");
+#endif /* KERNEL_U_ADDR_BSD. */
+}
+
+#if !defined (FETCH_INFERIOR_REGISTERS)
+
+#if !defined (offsetof)
+#define offsetof(TYPE, MEMBER) ((unsigned long) &((TYPE *)0)->MEMBER)
+#endif
+
+/* U_REGS_OFFSET is the offset of the registers within the u area. */
+#if !defined (U_REGS_OFFSET)
+#define U_REGS_OFFSET \
+ ptrace (PT_READ_U, inferior_pid, \
+ (PTRACE_ARG3_TYPE) (offsetof (struct user, u_ar0)), 0) \
+ - KERNEL_U_ADDR
+#endif
+
+/* Registers we shouldn't try to fetch. */
+#if !defined (CANNOT_FETCH_REGISTER)
+#define CANNOT_FETCH_REGISTER(regno) 0
+#endif
+
+/* Fetch one register. */
+
+static void
+fetch_register (regno)
+ int regno;
+{
+ /* This isn't really an address. But ptrace thinks of it as one. */
+ CORE_ADDR regaddr;
+ char buf[MAX_REGISTER_RAW_SIZE];
+ char mess[128]; /* For messages */
+ register int i;
+
+ /* Offset of registers within the u area. */
+ unsigned int offset;
+
+ if (CANNOT_FETCH_REGISTER (regno))
+ {
+ memset (buf, '\0', REGISTER_RAW_SIZE (regno)); /* Supply zeroes */
+ supply_register (regno, buf);
+ return;
+ }
+
+ offset = U_REGS_OFFSET;
+
+ regaddr = register_addr (regno, offset);
+ for (i = 0; i < REGISTER_RAW_SIZE (regno); i += sizeof (PTRACE_XFER_TYPE))
+ {
+ errno = 0;
+ *(PTRACE_XFER_TYPE *) &buf[i] = ptrace (PT_READ_U, inferior_pid,
+ (PTRACE_ARG3_TYPE) regaddr, 0);
+ regaddr += sizeof (PTRACE_XFER_TYPE);
+ if (errno != 0)
+ {
+ sprintf (mess, "reading register %s (#%d)", reg_names[regno], regno);
+ perror_with_name (mess);
+ }
+ }
+ supply_register (regno, buf);
+}
+
+
+/* Fetch all registers, or just one, from the child process. */
+
+void
+fetch_inferior_registers (regno)
+ int regno;
+{
+ int numregs;
+
+ if (regno == -1)
+ {
+ numregs = ARCH_NUM_REGS;
+ for (regno = 0; regno < numregs; regno++)
+ fetch_register (regno);
+ }
+ else
+ fetch_register (regno);
+}
+
+/* Registers we shouldn't try to store. */
+#if !defined (CANNOT_STORE_REGISTER)
+#define CANNOT_STORE_REGISTER(regno) 0
+#endif
+
+/* Store our register values back into the inferior.
+ If REGNO is -1, do this for all registers.
+ Otherwise, REGNO specifies which register (so we can save time). */
+
+void
+store_inferior_registers (regno)
+ int regno;
+{
+ /* This isn't really an address. But ptrace thinks of it as one. */
+ CORE_ADDR regaddr;
+ char buf[80];
+ register int i, numregs;
+
+ unsigned int offset = U_REGS_OFFSET;
+
+ if (regno >= 0)
+ {
+ regaddr = register_addr (regno, offset);
+ for (i = 0; i < REGISTER_RAW_SIZE (regno); i += sizeof(PTRACE_XFER_TYPE))
+ {
+ errno = 0;
+ ptrace (PT_WRITE_U, inferior_pid, (PTRACE_ARG3_TYPE) regaddr,
+ *(PTRACE_XFER_TYPE *) &registers[REGISTER_BYTE (regno) + i]);
+ if (errno != 0)
+ {
+ sprintf (buf, "writing register number %d(%d)", regno, i);
+ perror_with_name (buf);
+ }
+ regaddr += sizeof(PTRACE_XFER_TYPE);
+ }
+ }
+ else
+ {
+ numregs = ARCH_NUM_REGS;
+ for (regno = 0; regno < numregs; regno++)
+ {
+ if (CANNOT_STORE_REGISTER (regno))
+ continue;
+ regaddr = register_addr (regno, offset);
+ for (i = 0; i < REGISTER_RAW_SIZE (regno); i += sizeof(PTRACE_XFER_TYPE))
+ {
+ errno = 0;
+ ptrace (PT_WRITE_U, inferior_pid, (PTRACE_ARG3_TYPE) regaddr,
+ *(PTRACE_XFER_TYPE *) &registers[REGISTER_BYTE (regno) + i]);
+ if (errno != 0)
+ {
+ sprintf (buf, "writing register number %d(%d)", regno, i);
+ perror_with_name (buf);
+ }
+ regaddr += sizeof(PTRACE_XFER_TYPE);
+ }
+ }
+ }
+}
+#endif /* !defined (FETCH_INFERIOR_REGISTERS). */
+
+
+#if !defined (CHILD_XFER_MEMORY)
+/* NOTE! I tried using PTRACE_READDATA, etc., to read and write memory
+ in the NEW_SUN_PTRACE case.
+ It ought to be straightforward. But it appears that writing did
+ not write the data that I specified. I cannot understand where
+ it got the data that it actually did write. */
+
+/* Copy LEN bytes to or from inferior's memory starting at MEMADDR
+ to debugger memory starting at MYADDR. Copy to inferior if
+ WRITE is nonzero.
+
+ Returns the length copied, which is either the LEN argument or zero.
+ This xfer function does not do partial moves, since child_ops
+ doesn't allow memory operations to cross below us in the target stack
+ anyway. */
+
+int
+child_xfer_memory (memaddr, myaddr, len, write, target)
+ CORE_ADDR memaddr;
+ char *myaddr;
+ int len;
+ int write;
+ struct target_ops *target; /* ignored */
+{
+ register int i;
+ /* Round starting address down to longword boundary. */
+ register CORE_ADDR addr = memaddr & - sizeof (PTRACE_XFER_TYPE);
+ /* Round ending address up; get number of longwords that makes. */
+ register int count
+ = (((memaddr + len) - addr) + sizeof (PTRACE_XFER_TYPE) - 1)
+ / sizeof (PTRACE_XFER_TYPE);
+ /* Allocate buffer of that many longwords. */
+ register PTRACE_XFER_TYPE *buffer
+ = (PTRACE_XFER_TYPE *) alloca (count * sizeof (PTRACE_XFER_TYPE));
+
+ if (write)
+ {
+ /* Fill start and end extra bytes of buffer with existing memory data. */
+
+ if (addr != memaddr || len < (int) sizeof (PTRACE_XFER_TYPE)) {
+ /* Need part of initial word -- fetch it. */
+ buffer[0] = ptrace (PT_READ_I, inferior_pid, (PTRACE_ARG3_TYPE) addr,
+ 0);
+ }
+
+ if (count > 1) /* FIXME, avoid if even boundary */
+ {
+ buffer[count - 1]
+ = ptrace (PT_READ_I, inferior_pid,
+ ((PTRACE_ARG3_TYPE)
+ (addr + (count - 1) * sizeof (PTRACE_XFER_TYPE))),
+ 0);
+ }
+
+ /* Copy data to be written over corresponding part of buffer */
+
+ memcpy ((char *) buffer + (memaddr & (sizeof (PTRACE_XFER_TYPE) - 1)),
+ myaddr,
+ len);
+
+ /* Write the entire buffer. */
+
+ for (i = 0; i < count; i++, addr += sizeof (PTRACE_XFER_TYPE))
+ {
+ errno = 0;
+ ptrace (PT_WRITE_D, inferior_pid, (PTRACE_ARG3_TYPE) addr,
+ buffer[i]);
+ if (errno)
+ {
+ /* Using the appropriate one (I or D) is necessary for
+ Gould NP1, at least. */
+ errno = 0;
+ ptrace (PT_WRITE_I, inferior_pid, (PTRACE_ARG3_TYPE) addr,
+ buffer[i]);
+ }
+ if (errno)
+ return 0;
+ }
+ }
+ else
+ {
+ /* Read all the longwords */
+ for (i = 0; i < count; i++, addr += sizeof (PTRACE_XFER_TYPE))
+ {
+ errno = 0;
+ buffer[i] = ptrace (PT_READ_I, inferior_pid,
+ (PTRACE_ARG3_TYPE) addr, 0);
+ if (errno)
+ return 0;
+ QUIT;
+ }
+
+ /* Copy appropriate bytes out of the buffer. */
+ memcpy (myaddr,
+ (char *) buffer + (memaddr & (sizeof (PTRACE_XFER_TYPE) - 1)),
+ len);
+ }
+ return len;
+}
+#endif /* !defined (CHILD_XFER_MEMORY). */
diff --git a/gnu/usr.bin/gdb/gdb/infrun.c b/gnu/usr.bin/gdb/gdb/infrun.c
new file mode 100644
index 0000000..b07b1fe
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/infrun.c
@@ -0,0 +1,2037 @@
+/* Target-struct-independent code to start (run) and stop an inferior process.
+ Copyright 1986, 1987, 1988, 1989, 1991, 1992, 1993, 1994
+ Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "defs.h"
+#include <string.h>
+#include <ctype.h>
+#include "symtab.h"
+#include "frame.h"
+#include "inferior.h"
+#include "breakpoint.h"
+#include "wait.h"
+#include "gdbcore.h"
+#include "gdbcmd.h"
+#include "target.h"
+#include "thread.h"
+#include "annotate.h"
+
+#include <signal.h>
+
+/* unistd.h is needed to #define X_OK */
+#ifdef USG
+#include <unistd.h>
+#else
+#include <sys/file.h>
+#endif
+
+/* Prototypes for local functions */
+
+static void
+signals_info PARAMS ((char *, int));
+
+static void
+handle_command PARAMS ((char *, int));
+
+static void sig_print_info PARAMS ((enum target_signal));
+
+static void
+sig_print_header PARAMS ((void));
+
+static void
+resume_cleanups PARAMS ((int));
+
+static int
+hook_stop_stub PARAMS ((char *));
+
+/* GET_LONGJMP_TARGET returns the PC at which longjmp() will resume the
+ program. It needs to examine the jmp_buf argument and extract the PC
+ from it. The return value is non-zero on success, zero otherwise. */
+#ifndef GET_LONGJMP_TARGET
+#define GET_LONGJMP_TARGET(PC_ADDR) 0
+#endif
+
+
+/* Some machines have trampoline code that sits between function callers
+ and the actual functions themselves. If this machine doesn't have
+ such things, disable their processing. */
+#ifndef SKIP_TRAMPOLINE_CODE
+#define SKIP_TRAMPOLINE_CODE(pc) 0
+#endif
+
+/* For SVR4 shared libraries, each call goes through a small piece of
+ trampoline code in the ".plt" section. IN_SOLIB_TRAMPOLINE evaluates
+ to nonzero if we are current stopped in one of these. */
+#ifndef IN_SOLIB_TRAMPOLINE
+#define IN_SOLIB_TRAMPOLINE(pc,name) 0
+#endif
+
+/* On some systems, the PC may be left pointing at an instruction that won't
+ actually be executed. This is usually indicated by a bit in the PSW. If
+ we find ourselves in such a state, then we step the target beyond the
+ nullified instruction before returning control to the user so as to avoid
+ confusion. */
+
+#ifndef INSTRUCTION_NULLIFIED
+#define INSTRUCTION_NULLIFIED 0
+#endif
+
+/* Tables of how to react to signals; the user sets them. */
+
+static unsigned char *signal_stop;
+static unsigned char *signal_print;
+static unsigned char *signal_program;
+
+#define SET_SIGS(nsigs,sigs,flags) \
+ do { \
+ int signum = (nsigs); \
+ while (signum-- > 0) \
+ if ((sigs)[signum]) \
+ (flags)[signum] = 1; \
+ } while (0)
+
+#define UNSET_SIGS(nsigs,sigs,flags) \
+ do { \
+ int signum = (nsigs); \
+ while (signum-- > 0) \
+ if ((sigs)[signum]) \
+ (flags)[signum] = 0; \
+ } while (0)
+
+
+/* Command list pointer for the "stop" placeholder. */
+
+static struct cmd_list_element *stop_command;
+
+/* Nonzero if breakpoints are now inserted in the inferior. */
+
+static int breakpoints_inserted;
+
+/* Function inferior was in as of last step command. */
+
+static struct symbol *step_start_function;
+
+/* Nonzero if we are expecting a trace trap and should proceed from it. */
+
+static int trap_expected;
+
+/* Nonzero if the next time we try to continue the inferior, it will
+ step one instruction and generate a spurious trace trap.
+ This is used to compensate for a bug in HP-UX. */
+
+static int trap_expected_after_continue;
+
+/* Nonzero means expecting a trace trap
+ and should stop the inferior and return silently when it happens. */
+
+int stop_after_trap;
+
+/* Nonzero means expecting a trap and caller will handle it themselves.
+ It is used after attach, due to attaching to a process;
+ when running in the shell before the child program has been exec'd;
+ and when running some kinds of remote stuff (FIXME?). */
+
+int stop_soon_quietly;
+
+/* Nonzero if proceed is being used for a "finish" command or a similar
+ situation when stop_registers should be saved. */
+
+int proceed_to_finish;
+
+/* Save register contents here when about to pop a stack dummy frame,
+ if-and-only-if proceed_to_finish is set.
+ Thus this contains the return value from the called function (assuming
+ values are returned in a register). */
+
+char stop_registers[REGISTER_BYTES];
+
+/* Nonzero if program stopped due to error trying to insert breakpoints. */
+
+static int breakpoints_failed;
+
+/* Nonzero after stop if current stack frame should be printed. */
+
+static int stop_print_frame;
+
+#ifdef NO_SINGLE_STEP
+extern int one_stepped; /* From machine dependent code */
+extern void single_step (); /* Same. */
+#endif /* NO_SINGLE_STEP */
+
+
+/* Things to clean up if we QUIT out of resume (). */
+/* ARGSUSED */
+static void
+resume_cleanups (arg)
+ int arg;
+{
+ normal_stop ();
+}
+
+/* Resume the inferior, but allow a QUIT. This is useful if the user
+ wants to interrupt some lengthy single-stepping operation
+ (for child processes, the SIGINT goes to the inferior, and so
+ we get a SIGINT random_signal, but for remote debugging and perhaps
+ other targets, that's not true).
+
+ STEP nonzero if we should step (zero to continue instead).
+ SIG is the signal to give the inferior (zero for none). */
+void
+resume (step, sig)
+ int step;
+ enum target_signal sig;
+{
+ struct cleanup *old_cleanups = make_cleanup (resume_cleanups, 0);
+ QUIT;
+
+#ifdef CANNOT_STEP_BREAKPOINT
+ /* Most targets can step a breakpoint instruction, thus executing it
+ normally. But if this one cannot, just continue and we will hit
+ it anyway. */
+ if (step && breakpoints_inserted && breakpoint_here_p (read_pc ()))
+ step = 0;
+#endif
+
+#ifdef NO_SINGLE_STEP
+ if (step) {
+ single_step(sig); /* Do it the hard way, w/temp breakpoints */
+ step = 0; /* ...and don't ask hardware to do it. */
+ }
+#endif
+
+ /* Handle any optimized stores to the inferior NOW... */
+#ifdef DO_DEFERRED_STORES
+ DO_DEFERRED_STORES;
+#endif
+
+ /* Install inferior's terminal modes. */
+ target_terminal_inferior ();
+
+ target_resume (-1, step, sig);
+ discard_cleanups (old_cleanups);
+}
+
+
+/* Clear out all variables saying what to do when inferior is continued.
+ First do this, then set the ones you want, then call `proceed'. */
+
+void
+clear_proceed_status ()
+{
+ trap_expected = 0;
+ step_range_start = 0;
+ step_range_end = 0;
+ step_frame_address = 0;
+ step_over_calls = -1;
+ stop_after_trap = 0;
+ stop_soon_quietly = 0;
+ proceed_to_finish = 0;
+ breakpoint_proceeded = 1; /* We're about to proceed... */
+
+ /* Discard any remaining commands or status from previous stop. */
+ bpstat_clear (&stop_bpstat);
+}
+
+/* Basic routine for continuing the program in various fashions.
+
+ ADDR is the address to resume at, or -1 for resume where stopped.
+ SIGGNAL is the signal to give it, or 0 for none,
+ or -1 for act according to how it stopped.
+ STEP is nonzero if should trap after one instruction.
+ -1 means return after that and print nothing.
+ You should probably set various step_... variables
+ before calling here, if you are stepping.
+
+ You should call clear_proceed_status before calling proceed. */
+
+void
+proceed (addr, siggnal, step)
+ CORE_ADDR addr;
+ enum target_signal siggnal;
+ int step;
+{
+ int oneproc = 0;
+
+ if (step > 0)
+ step_start_function = find_pc_function (read_pc ());
+ if (step < 0)
+ stop_after_trap = 1;
+
+ if (addr == (CORE_ADDR)-1)
+ {
+ /* If there is a breakpoint at the address we will resume at,
+ step one instruction before inserting breakpoints
+ so that we do not stop right away. */
+
+ if (breakpoint_here_p (read_pc ()))
+ oneproc = 1;
+
+#ifdef STEP_SKIPS_DELAY
+ /* Check breakpoint_here_p first, because breakpoint_here_p is fast
+ (it just checks internal GDB data structures) and STEP_SKIPS_DELAY
+ is slow (it needs to read memory from the target). */
+ if (breakpoint_here_p (read_pc () + 4)
+ && STEP_SKIPS_DELAY (read_pc ()))
+ oneproc = 1;
+#endif /* STEP_SKIPS_DELAY */
+ }
+ else
+ write_pc (addr);
+
+#ifdef PREPARE_TO_PROCEED
+ /* In a multi-threaded task we may select another thread and then continue.
+
+ In this case the thread that stopped at a breakpoint will immediately
+ cause another stop, if it is not stepped over first. On the other hand,
+ if (ADDR != -1) we only want to single step over the breakpoint if we did
+ switch to another thread.
+
+ If we are single stepping, don't do any of the above.
+ (Note that in the current implementation single stepping another
+ thread after a breakpoint and then continuing will cause the original
+ breakpoint to be hit again, but you can always continue, so it's not
+ a big deal.) */
+
+ if (! step && PREPARE_TO_PROCEED (1) && breakpoint_here_p (read_pc ()))
+ oneproc = 1;
+#endif /* PREPARE_TO_PROCEED */
+
+ if (trap_expected_after_continue)
+ {
+ /* If (step == 0), a trap will be automatically generated after
+ the first instruction is executed. Force step one
+ instruction to clear this condition. This should not occur
+ if step is nonzero, but it is harmless in that case. */
+ oneproc = 1;
+ trap_expected_after_continue = 0;
+ }
+
+ if (oneproc)
+ /* We will get a trace trap after one instruction.
+ Continue it automatically and insert breakpoints then. */
+ trap_expected = 1;
+ else
+ {
+ int temp = insert_breakpoints ();
+ if (temp)
+ {
+ print_sys_errmsg ("ptrace", temp);
+ error ("Cannot insert breakpoints.\n\
+The same program may be running in another process.");
+ }
+ breakpoints_inserted = 1;
+ }
+
+ if (siggnal != TARGET_SIGNAL_DEFAULT)
+ stop_signal = siggnal;
+ /* If this signal should not be seen by program,
+ give it zero. Used for debugging signals. */
+ else if (!signal_program[stop_signal])
+ stop_signal = TARGET_SIGNAL_0;
+
+ annotate_starting ();
+
+ /* Resume inferior. */
+ resume (oneproc || step || bpstat_should_step (), stop_signal);
+
+ /* Wait for it to stop (if not standalone)
+ and in any case decode why it stopped, and act accordingly. */
+
+ wait_for_inferior ();
+ normal_stop ();
+}
+
+/* Record the pc and sp of the program the last time it stopped.
+ These are just used internally by wait_for_inferior, but need
+ to be preserved over calls to it and cleared when the inferior
+ is started. */
+static CORE_ADDR prev_pc;
+static CORE_ADDR prev_sp;
+static CORE_ADDR prev_func_start;
+static char *prev_func_name;
+static CORE_ADDR prev_frame_address;
+
+
+/* Start remote-debugging of a machine over a serial link. */
+
+void
+start_remote ()
+{
+ init_wait_for_inferior ();
+ clear_proceed_status ();
+ stop_soon_quietly = 1;
+ trap_expected = 0;
+ wait_for_inferior ();
+ normal_stop ();
+}
+
+/* Initialize static vars when a new inferior begins. */
+
+void
+init_wait_for_inferior ()
+{
+ /* These are meaningless until the first time through wait_for_inferior. */
+ prev_pc = 0;
+ prev_sp = 0;
+ prev_func_start = 0;
+ prev_func_name = NULL;
+ prev_frame_address = 0;
+
+ trap_expected_after_continue = 0;
+ breakpoints_inserted = 0;
+ breakpoint_init_inferior ();
+
+ /* Don't confuse first call to proceed(). */
+ stop_signal = TARGET_SIGNAL_0;
+}
+
+static void
+delete_breakpoint_current_contents (arg)
+ PTR arg;
+{
+ struct breakpoint **breakpointp = (struct breakpoint **)arg;
+ if (*breakpointp != NULL)
+ delete_breakpoint (*breakpointp);
+}
+
+/* Wait for control to return from inferior to debugger.
+ If inferior gets a signal, we may decide to start it up again
+ instead of returning. That is why there is a loop in this function.
+ When this function actually returns it means the inferior
+ should be left stopped and GDB should read more commands. */
+
+void
+wait_for_inferior ()
+{
+ struct cleanup *old_cleanups;
+ struct target_waitstatus w;
+ int another_trap;
+ int random_signal;
+ CORE_ADDR stop_sp = 0;
+ CORE_ADDR stop_func_start;
+ CORE_ADDR stop_func_end;
+ char *stop_func_name;
+ CORE_ADDR prologue_pc = 0, tmp;
+ struct symtab_and_line sal;
+ int remove_breakpoints_on_following_step = 0;
+ int current_line;
+ struct symtab *current_symtab;
+ int handling_longjmp = 0; /* FIXME */
+ struct breakpoint *step_resume_breakpoint = NULL;
+ struct breakpoint *through_sigtramp_breakpoint = NULL;
+ int pid;
+
+ old_cleanups = make_cleanup (delete_breakpoint_current_contents,
+ &step_resume_breakpoint);
+ make_cleanup (delete_breakpoint_current_contents,
+ &through_sigtramp_breakpoint);
+ sal = find_pc_line(prev_pc, 0);
+ current_line = sal.line;
+ current_symtab = sal.symtab;
+
+ /* Are we stepping? */
+#define CURRENTLY_STEPPING() \
+ ((through_sigtramp_breakpoint == NULL \
+ && !handling_longjmp \
+ && ((step_range_end && step_resume_breakpoint == NULL) \
+ || trap_expected)) \
+ || bpstat_should_step ())
+
+ while (1)
+ {
+ /* We have to invalidate the registers BEFORE calling target_wait because
+ they can be loaded from the target while in target_wait. This makes
+ remote debugging a bit more efficient for those targets that provide
+ critical registers as part of their normal status mechanism. */
+
+ registers_changed ();
+
+ pid = target_wait (-1, &w);
+
+ flush_cached_frames ();
+
+ /* If it's a new process, add it to the thread database */
+
+ if (pid != inferior_pid
+ && !in_thread_list (pid))
+ {
+ fprintf_unfiltered (gdb_stderr, "[New %s]\n", target_pid_to_str (pid));
+ add_thread (pid);
+
+ /* We may want to consider not doing a resume here in order to give
+ the user a chance to play with the new thread. It might be good
+ to make that a user-settable option. */
+
+ /* At this point, all threads are stopped (happens automatically in
+ either the OS or the native code). Therefore we need to continue
+ all threads in order to make progress. */
+
+ target_resume (-1, 0, TARGET_SIGNAL_0);
+ continue;
+ }
+
+ switch (w.kind)
+ {
+ case TARGET_WAITKIND_LOADED:
+ /* Ignore it gracefully. */
+ if (breakpoints_inserted)
+ {
+ mark_breakpoints_out ();
+ insert_breakpoints ();
+ }
+ resume (0, TARGET_SIGNAL_0);
+ continue;
+
+ case TARGET_WAITKIND_SPURIOUS:
+ resume (0, TARGET_SIGNAL_0);
+ continue;
+
+ case TARGET_WAITKIND_EXITED:
+ target_terminal_ours (); /* Must do this before mourn anyway */
+ annotate_exited (w.value.integer);
+ if (w.value.integer)
+ printf_filtered ("\nProgram exited with code 0%o.\n",
+ (unsigned int)w.value.integer);
+ else
+ printf_filtered ("\nProgram exited normally.\n");
+ gdb_flush (gdb_stdout);
+ target_mourn_inferior ();
+#ifdef NO_SINGLE_STEP
+ one_stepped = 0;
+#endif
+ stop_print_frame = 0;
+ goto stop_stepping;
+
+ case TARGET_WAITKIND_SIGNALLED:
+ stop_print_frame = 0;
+ stop_signal = w.value.sig;
+ target_terminal_ours (); /* Must do this before mourn anyway */
+ annotate_signalled ();
+ target_kill (); /* kill mourns as well */
+ printf_filtered ("\nProgram terminated with signal ");
+ annotate_signal_name ();
+ printf_filtered ("%s", target_signal_to_name (stop_signal));
+ annotate_signal_name_end ();
+ printf_filtered (", ");
+ annotate_signal_string ();
+ printf_filtered ("%s", target_signal_to_string (stop_signal));
+ annotate_signal_string_end ();
+ printf_filtered (".\n");
+
+ printf_filtered ("The program no longer exists.\n");
+ gdb_flush (gdb_stdout);
+#ifdef NO_SINGLE_STEP
+ one_stepped = 0;
+#endif
+ goto stop_stepping;
+
+ case TARGET_WAITKIND_STOPPED:
+ /* This is the only case in which we keep going; the above cases
+ end in a continue or goto. */
+ break;
+ }
+
+ stop_signal = w.value.sig;
+
+ stop_pc = read_pc_pid (pid);
+
+ /* See if a thread hit a thread-specific breakpoint that was meant for
+ another thread. If so, then step that thread past the breakpoint,
+ and continue it. */
+
+ if (stop_signal == TARGET_SIGNAL_TRAP
+ && breakpoints_inserted
+ && breakpoint_here_p (stop_pc - DECR_PC_AFTER_BREAK))
+ {
+ random_signal = 0;
+ if (!breakpoint_thread_match (stop_pc - DECR_PC_AFTER_BREAK, pid))
+ {
+ /* Saw a breakpoint, but it was hit by the wrong thread. Just continue. */
+ write_pc (stop_pc - DECR_PC_AFTER_BREAK);
+
+ remove_breakpoints ();
+ target_resume (pid, 1, TARGET_SIGNAL_0); /* Single step */
+ /* FIXME: What if a signal arrives instead of the single-step
+ happening? */
+ target_wait (pid, &w);
+ insert_breakpoints ();
+ target_resume (pid, 0, TARGET_SIGNAL_0);
+ continue;
+ }
+ }
+ else
+ random_signal = 1;
+
+ /* See if something interesting happened to the non-current thread. If
+ so, then switch to that thread, and eventually give control back to
+ the user. */
+
+ if (pid != inferior_pid)
+ {
+ int printed = 0;
+
+ /* If it's a random signal for a non-current thread, notify user
+ if he's expressed an interest. */
+
+ if (random_signal
+ && signal_print[stop_signal])
+ {
+ printed = 1;
+ target_terminal_ours_for_output ();
+ printf_filtered ("\nProgram received signal %s, %s.\n",
+ target_signal_to_name (stop_signal),
+ target_signal_to_string (stop_signal));
+ gdb_flush (gdb_stdout);
+ }
+
+ /* If it's not SIGTRAP and not a signal we want to stop for, then
+ continue the thread. */
+
+ if (stop_signal != TARGET_SIGNAL_TRAP
+ && !signal_stop[stop_signal])
+ {
+ if (printed)
+ target_terminal_inferior ();
+
+ /* Clear the signal if it should not be passed. */
+ if (signal_program[stop_signal] == 0)
+ stop_signal = TARGET_SIGNAL_0;
+
+ target_resume (pid, 0, stop_signal);
+ continue;
+ }
+
+ /* It's a SIGTRAP or a signal we're interested in. Switch threads,
+ and fall into the rest of wait_for_inferior(). */
+
+ inferior_pid = pid;
+ printf_filtered ("[Switching to %s]\n", target_pid_to_str (pid));
+
+ flush_cached_frames ();
+ trap_expected = 0;
+ if (step_resume_breakpoint)
+ {
+ delete_breakpoint (step_resume_breakpoint);
+ step_resume_breakpoint = NULL;
+ }
+
+ /* Not sure whether we need to blow this away too,
+ but probably it is like the step-resume
+ breakpoint. */
+ if (through_sigtramp_breakpoint)
+ {
+ delete_breakpoint (through_sigtramp_breakpoint);
+ through_sigtramp_breakpoint = NULL;
+ }
+ prev_pc = 0;
+ prev_sp = 0;
+ prev_func_name = NULL;
+ step_range_start = 0;
+ step_range_end = 0;
+ step_frame_address = 0;
+ handling_longjmp = 0;
+ another_trap = 0;
+ }
+
+#ifdef NO_SINGLE_STEP
+ if (one_stepped)
+ single_step (0); /* This actually cleans up the ss */
+#endif /* NO_SINGLE_STEP */
+
+ /* If PC is pointing at a nullified instruction, then step beyond
+ it so that the user won't be confused when GDB appears to be ready
+ to execute it. */
+
+ if (INSTRUCTION_NULLIFIED)
+ {
+ resume (1, 0);
+ continue;
+ }
+
+ set_current_frame (create_new_frame (read_fp (), stop_pc));
+ select_frame (get_current_frame (), 0);
+
+#ifdef HAVE_STEPPABLE_WATCHPOINT
+ /* It may not be necessary to disable the watchpoint to stop over
+ it. For example, the PA can (with some kernel cooperation)
+ single step over a watchpoint without disabling the watchpoint. */
+ if (STOPPED_BY_WATCHPOINT (w))
+ {
+ resume (1, 0);
+ continue;
+ }
+#endif
+
+#ifdef HAVE_NONSTEPPABLE_WATCHPOINT
+ /* It is far more common to need to disable a watchpoint
+ to step the inferior over it. FIXME. What else might
+ a debug register or page protection watchpoint scheme need
+ here? */
+ if (STOPPED_BY_WATCHPOINT (w))
+ {
+ remove_breakpoints ();
+ resume (1, 0);
+
+ /* FIXME: This is bogus. You can't interact with the
+ inferior except when it is stopped. It apparently
+ happens to work on Irix4, but it depends on /proc
+ allowing us to muck with the memory of a running process,
+ and the kernel deciding to run one instruction of the
+ inferior before it executes our insert_breakpoints code,
+ which seems like an awfully dubious assumption. */
+ insert_breakpoints ();
+
+ continue;
+ }
+#endif
+
+#ifdef HAVE_CONTINUABLE_WATCHPOINT
+ /* It may be possible to simply continue after a watchpoint. */
+ STOPPED_BY_WATCHPOINT (w);
+#endif
+
+ stop_frame_address = FRAME_FP (get_current_frame ());
+ stop_sp = read_sp ();
+ stop_func_start = 0;
+ stop_func_name = 0;
+ /* Don't care about return value; stop_func_start and stop_func_name
+ will both be 0 if it doesn't work. */
+ find_pc_partial_function (stop_pc, &stop_func_name, &stop_func_start,
+ &stop_func_end);
+ stop_func_start += FUNCTION_START_OFFSET;
+ another_trap = 0;
+ bpstat_clear (&stop_bpstat);
+ stop_step = 0;
+ stop_stack_dummy = 0;
+ stop_print_frame = 1;
+ random_signal = 0;
+ stopped_by_random_signal = 0;
+ breakpoints_failed = 0;
+
+ /* Look at the cause of the stop, and decide what to do.
+ The alternatives are:
+ 1) break; to really stop and return to the debugger,
+ 2) drop through to start up again
+ (set another_trap to 1 to single step once)
+ 3) set random_signal to 1, and the decision between 1 and 2
+ will be made according to the signal handling tables. */
+
+ /* First, distinguish signals caused by the debugger from signals
+ that have to do with the program's own actions.
+ Note that breakpoint insns may cause SIGTRAP or SIGILL
+ or SIGEMT, depending on the operating system version.
+ Here we detect when a SIGILL or SIGEMT is really a breakpoint
+ and change it to SIGTRAP. */
+
+ if (stop_signal == TARGET_SIGNAL_TRAP
+ || (breakpoints_inserted &&
+ (stop_signal == TARGET_SIGNAL_ILL
+ || stop_signal == TARGET_SIGNAL_EMT
+ ))
+ || stop_soon_quietly)
+ {
+ if (stop_signal == TARGET_SIGNAL_TRAP && stop_after_trap)
+ {
+ stop_print_frame = 0;
+ break;
+ }
+ if (stop_soon_quietly)
+ break;
+
+ /* Don't even think about breakpoints
+ if just proceeded over a breakpoint.
+
+ However, if we are trying to proceed over a breakpoint
+ and end up in sigtramp, then through_sigtramp_breakpoint
+ will be set and we should check whether we've hit the
+ step breakpoint. */
+ if (stop_signal == TARGET_SIGNAL_TRAP && trap_expected
+ && through_sigtramp_breakpoint == NULL)
+ bpstat_clear (&stop_bpstat);
+ else
+ {
+ /* See if there is a breakpoint at the current PC. */
+ stop_bpstat = bpstat_stop_status
+ (&stop_pc, stop_frame_address,
+#if DECR_PC_AFTER_BREAK
+ /* Notice the case of stepping through a jump
+ that lands just after a breakpoint.
+ Don't confuse that with hitting the breakpoint.
+ What we check for is that 1) stepping is going on
+ and 2) the pc before the last insn does not match
+ the address of the breakpoint before the current pc. */
+ (prev_pc != stop_pc - DECR_PC_AFTER_BREAK
+ && CURRENTLY_STEPPING ())
+#else /* DECR_PC_AFTER_BREAK zero */
+ 0
+#endif /* DECR_PC_AFTER_BREAK zero */
+ );
+ /* Following in case break condition called a
+ function. */
+ stop_print_frame = 1;
+ }
+
+ if (stop_signal == TARGET_SIGNAL_TRAP)
+ random_signal
+ = !(bpstat_explains_signal (stop_bpstat)
+ || trap_expected
+#ifndef CALL_DUMMY_BREAKPOINT_OFFSET
+ || PC_IN_CALL_DUMMY (stop_pc, stop_sp, stop_frame_address)
+#endif /* No CALL_DUMMY_BREAKPOINT_OFFSET. */
+ || (step_range_end && step_resume_breakpoint == NULL));
+ else
+ {
+ random_signal
+ = !(bpstat_explains_signal (stop_bpstat)
+ /* End of a stack dummy. Some systems (e.g. Sony
+ news) give another signal besides SIGTRAP,
+ so check here as well as above. */
+#ifndef CALL_DUMMY_BREAKPOINT_OFFSET
+ || PC_IN_CALL_DUMMY (stop_pc, stop_sp, stop_frame_address)
+#endif /* No CALL_DUMMY_BREAKPOINT_OFFSET. */
+ );
+ if (!random_signal)
+ stop_signal = TARGET_SIGNAL_TRAP;
+ }
+ }
+ else
+ random_signal = 1;
+
+ /* For the program's own signals, act according to
+ the signal handling tables. */
+
+ if (random_signal)
+ {
+ /* Signal not for debugging purposes. */
+ int printed = 0;
+
+ stopped_by_random_signal = 1;
+
+ if (signal_print[stop_signal])
+ {
+ printed = 1;
+ target_terminal_ours_for_output ();
+ annotate_signal ();
+ printf_filtered ("\nProgram received signal ");
+ annotate_signal_name ();
+ printf_filtered ("%s", target_signal_to_name (stop_signal));
+ annotate_signal_name_end ();
+ printf_filtered (", ");
+ annotate_signal_string ();
+ printf_filtered ("%s", target_signal_to_string (stop_signal));
+ annotate_signal_string_end ();
+ printf_filtered (".\n");
+ gdb_flush (gdb_stdout);
+ }
+ if (signal_stop[stop_signal])
+ break;
+ /* If not going to stop, give terminal back
+ if we took it away. */
+ else if (printed)
+ target_terminal_inferior ();
+
+ /* Clear the signal if it should not be passed. */
+ if (signal_program[stop_signal] == 0)
+ stop_signal = TARGET_SIGNAL_0;
+
+ /* I'm not sure whether this needs to be check_sigtramp2 or
+ whether it could/should be keep_going. */
+ goto check_sigtramp2;
+ }
+
+ /* Handle cases caused by hitting a breakpoint. */
+ {
+ CORE_ADDR jmp_buf_pc;
+ struct bpstat_what what;
+
+ what = bpstat_what (stop_bpstat);
+
+ if (what.call_dummy)
+ {
+ stop_stack_dummy = 1;
+#ifdef HP_OS_BUG
+ trap_expected_after_continue = 1;
+#endif
+ }
+
+ switch (what.main_action)
+ {
+ case BPSTAT_WHAT_SET_LONGJMP_RESUME:
+ /* If we hit the breakpoint at longjmp, disable it for the
+ duration of this command. Then, install a temporary
+ breakpoint at the target of the jmp_buf. */
+ disable_longjmp_breakpoint();
+ remove_breakpoints ();
+ breakpoints_inserted = 0;
+ if (!GET_LONGJMP_TARGET(&jmp_buf_pc)) goto keep_going;
+
+ /* Need to blow away step-resume breakpoint, as it
+ interferes with us */
+ if (step_resume_breakpoint != NULL)
+ {
+ delete_breakpoint (step_resume_breakpoint);
+ step_resume_breakpoint = NULL;
+ }
+ /* Not sure whether we need to blow this away too, but probably
+ it is like the step-resume breakpoint. */
+ if (through_sigtramp_breakpoint != NULL)
+ {
+ delete_breakpoint (through_sigtramp_breakpoint);
+ through_sigtramp_breakpoint = NULL;
+ }
+
+#if 0
+ /* FIXME - Need to implement nested temporary breakpoints */
+ if (step_over_calls > 0)
+ set_longjmp_resume_breakpoint(jmp_buf_pc,
+ get_current_frame());
+ else
+#endif /* 0 */
+ set_longjmp_resume_breakpoint(jmp_buf_pc, NULL);
+ handling_longjmp = 1; /* FIXME */
+ goto keep_going;
+
+ case BPSTAT_WHAT_CLEAR_LONGJMP_RESUME:
+ case BPSTAT_WHAT_CLEAR_LONGJMP_RESUME_SINGLE:
+ remove_breakpoints ();
+ breakpoints_inserted = 0;
+#if 0
+ /* FIXME - Need to implement nested temporary breakpoints */
+ if (step_over_calls
+ && (stop_frame_address
+ INNER_THAN step_frame_address))
+ {
+ another_trap = 1;
+ goto keep_going;
+ }
+#endif /* 0 */
+ disable_longjmp_breakpoint();
+ handling_longjmp = 0; /* FIXME */
+ if (what.main_action == BPSTAT_WHAT_CLEAR_LONGJMP_RESUME)
+ break;
+ /* else fallthrough */
+
+ case BPSTAT_WHAT_SINGLE:
+ if (breakpoints_inserted)
+ remove_breakpoints ();
+ breakpoints_inserted = 0;
+ another_trap = 1;
+ /* Still need to check other stuff, at least the case
+ where we are stepping and step out of the right range. */
+ break;
+
+ case BPSTAT_WHAT_STOP_NOISY:
+ stop_print_frame = 1;
+
+ /* We are about to nuke the step_resume_breakpoint and
+ through_sigtramp_breakpoint via the cleanup chain, so
+ no need to worry about it here. */
+
+ goto stop_stepping;
+
+ case BPSTAT_WHAT_STOP_SILENT:
+ stop_print_frame = 0;
+
+ /* We are about to nuke the step_resume_breakpoint and
+ through_sigtramp_breakpoint via the cleanup chain, so
+ no need to worry about it here. */
+
+ goto stop_stepping;
+
+ case BPSTAT_WHAT_STEP_RESUME:
+ delete_breakpoint (step_resume_breakpoint);
+ step_resume_breakpoint = NULL;
+ break;
+
+ case BPSTAT_WHAT_THROUGH_SIGTRAMP:
+ delete_breakpoint (through_sigtramp_breakpoint);
+ through_sigtramp_breakpoint = NULL;
+
+ /* If were waiting for a trap, hitting the step_resume_break
+ doesn't count as getting it. */
+ if (trap_expected)
+ another_trap = 1;
+ break;
+
+ case BPSTAT_WHAT_LAST:
+ /* Not a real code, but listed here to shut up gcc -Wall. */
+
+ case BPSTAT_WHAT_KEEP_CHECKING:
+ break;
+ }
+ }
+
+ /* We come here if we hit a breakpoint but should not
+ stop for it. Possibly we also were stepping
+ and should stop for that. So fall through and
+ test for stepping. But, if not stepping,
+ do not stop. */
+
+#ifndef CALL_DUMMY_BREAKPOINT_OFFSET
+ /* This is the old way of detecting the end of the stack dummy.
+ An architecture which defines CALL_DUMMY_BREAKPOINT_OFFSET gets
+ handled above. As soon as we can test it on all of them, all
+ architectures should define it. */
+
+ /* If this is the breakpoint at the end of a stack dummy,
+ just stop silently, unless the user was doing an si/ni, in which
+ case she'd better know what she's doing. */
+
+ if (PC_IN_CALL_DUMMY (stop_pc, stop_sp, stop_frame_address)
+ && !step_range_end)
+ {
+ stop_print_frame = 0;
+ stop_stack_dummy = 1;
+#ifdef HP_OS_BUG
+ trap_expected_after_continue = 1;
+#endif
+ break;
+ }
+#endif /* No CALL_DUMMY_BREAKPOINT_OFFSET. */
+
+ if (step_resume_breakpoint)
+ /* Having a step-resume breakpoint overrides anything
+ else having to do with stepping commands until
+ that breakpoint is reached. */
+ /* I'm not sure whether this needs to be check_sigtramp2 or
+ whether it could/should be keep_going. */
+ goto check_sigtramp2;
+
+ if (step_range_end == 0)
+ /* Likewise if we aren't even stepping. */
+ /* I'm not sure whether this needs to be check_sigtramp2 or
+ whether it could/should be keep_going. */
+ goto check_sigtramp2;
+
+ /* If stepping through a line, keep going if still within it. */
+ if (stop_pc >= step_range_start
+ && stop_pc < step_range_end
+ /* The step range might include the start of the
+ function, so if we are at the start of the
+ step range and either the stack or frame pointers
+ just changed, we've stepped outside */
+ && !(stop_pc == step_range_start
+ && stop_frame_address
+ && (stop_sp INNER_THAN prev_sp
+ || stop_frame_address != step_frame_address)))
+ {
+ /* We might be doing a BPSTAT_WHAT_SINGLE and getting a signal.
+ So definately need to check for sigtramp here. */
+ goto check_sigtramp2;
+ }
+
+ /* We stepped out of the stepping range. See if that was due
+ to a subroutine call that we should proceed to the end of. */
+
+ /* Did we just take a signal? */
+ if (IN_SIGTRAMP (stop_pc, stop_func_name)
+ && !IN_SIGTRAMP (prev_pc, prev_func_name))
+ {
+ /* We've just taken a signal; go until we are back to
+ the point where we took it and one more. */
+
+ /* This code is needed at least in the following case:
+ The user types "next" and then a signal arrives (before
+ the "next" is done). */
+
+ /* Note that if we are stopped at a breakpoint, then we need
+ the step_resume breakpoint to override any breakpoints at
+ the same location, so that we will still step over the
+ breakpoint even though the signal happened. */
+
+ {
+ struct symtab_and_line sr_sal;
+
+ sr_sal.pc = prev_pc;
+ sr_sal.symtab = NULL;
+ sr_sal.line = 0;
+ /* We could probably be setting the frame to
+ prev_frame_address; the reason we don't is that it didn't used
+ to exist. */
+ step_resume_breakpoint =
+ set_momentary_breakpoint (sr_sal, NULL, bp_step_resume);
+ if (breakpoints_inserted)
+ insert_breakpoints ();
+ }
+
+ /* If this is stepi or nexti, make sure that the stepping range
+ gets us past that instruction. */
+ if (step_range_end == 1)
+ /* FIXME: Does this run afoul of the code below which, if
+ we step into the middle of a line, resets the stepping
+ range? */
+ step_range_end = (step_range_start = prev_pc) + 1;
+
+ remove_breakpoints_on_following_step = 1;
+ goto keep_going;
+ }
+
+#if 1
+ if (stop_func_start)
+ {
+ struct symtab *s;
+
+ /* Do this after the IN_SIGTRAMP check; it might give
+ an error. */
+ prologue_pc = stop_func_start;
+
+ /* Don't skip the prologue if this is assembly source */
+ s = find_pc_symtab (stop_pc);
+ if (s && s->language != language_asm)
+ SKIP_PROLOGUE (prologue_pc);
+ }
+
+ if ((/* Might be a non-recursive call. If the symbols are missing
+ enough that stop_func_start == prev_func_start even though
+ they are really two functions, we will treat some calls as
+ jumps. */
+ stop_func_start != prev_func_start
+
+ /* Might be a recursive call if either we have a prologue
+ or the call instruction itself saves the PC on the stack. */
+ || prologue_pc != stop_func_start
+ || stop_sp != prev_sp)
+ && (/* PC is completely out of bounds of any known objfiles. Treat
+ like a subroutine call. */
+ ! stop_func_start
+
+ /* If we do a call, we will be at the start of a function... */
+ || stop_pc == stop_func_start
+
+ /* ...except on the Alpha with -O (and also Irix 5 and
+ perhaps others), in which we might call the address
+ after the load of gp. Since prologues don't contain
+ calls, we can't return to within one, and we don't
+ jump back into them, so this check is OK. */
+
+ || stop_pc < prologue_pc
+
+ /* ...and if it is a leaf function, the prologue might
+ consist of gp loading only, so the call transfers to
+ the first instruction after the prologue. */
+ || (stop_pc == prologue_pc
+
+ /* Distinguish this from the case where we jump back
+ to the first instruction after the prologue,
+ within a function. */
+ && stop_func_start != prev_func_start)
+
+ /* If we end up in certain places, it means we did a subroutine
+ call. I'm not completely sure this is necessary now that we
+ have the above checks with stop_func_start (and now that
+ find_pc_partial_function is pickier). */
+ || IN_SOLIB_TRAMPOLINE (stop_pc, stop_func_name)
+
+ /* If none of the above apply, it is a jump within a function,
+ or a return from a subroutine. The other case is longjmp,
+ which can no longer happen here as long as the
+ handling_longjmp stuff is working. */
+ ))
+#else
+/* This is experimental code which greatly simplifies the subroutine call
+ test. I've actually tested on the Alpha, and it works great. -Stu */
+
+ if (in_prologue (stop_pc, NULL)
+ || (prev_func_start != 0
+ && stop_func_start == 0))
+#endif
+ {
+ /* It's a subroutine call. */
+
+ if (step_over_calls == 0)
+ {
+ /* I presume that step_over_calls is only 0 when we're
+ supposed to be stepping at the assembly language level
+ ("stepi"). Just stop. */
+ stop_step = 1;
+ break;
+ }
+
+ if (step_over_calls > 0)
+ /* We're doing a "next". */
+ goto step_over_function;
+
+ /* If we are in a function call trampoline (a stub between
+ the calling routine and the real function), locate the real
+ function. That's what tells us (a) whether we want to step
+ into it at all, and (b) what prologue we want to run to
+ the end of, if we do step into it. */
+ tmp = SKIP_TRAMPOLINE_CODE (stop_pc);
+ if (tmp != 0)
+ stop_func_start = tmp;
+
+ /* If we have line number information for the function we
+ are thinking of stepping into, step into it.
+
+ If there are several symtabs at that PC (e.g. with include
+ files), just want to know whether *any* of them have line
+ numbers. find_pc_line handles this. */
+ {
+ struct symtab_and_line tmp_sal;
+
+ tmp_sal = find_pc_line (stop_func_start, 0);
+ if (tmp_sal.line != 0)
+ goto step_into_function;
+ }
+
+step_over_function:
+ /* A subroutine call has happened. */
+ {
+ /* Set a special breakpoint after the return */
+ struct symtab_and_line sr_sal;
+ sr_sal.pc =
+ ADDR_BITS_REMOVE
+ (SAVED_PC_AFTER_CALL (get_current_frame ()));
+ sr_sal.symtab = NULL;
+ sr_sal.line = 0;
+ step_resume_breakpoint =
+ set_momentary_breakpoint (sr_sal, get_current_frame (),
+ bp_step_resume);
+ step_resume_breakpoint->frame = prev_frame_address;
+ if (breakpoints_inserted)
+ insert_breakpoints ();
+ }
+ goto keep_going;
+
+step_into_function:
+ /* Subroutine call with source code we should not step over.
+ Do step to the first line of code in it. */
+ {
+ struct symtab *s;
+
+ s = find_pc_symtab (stop_pc);
+ if (s && s->language != language_asm)
+ SKIP_PROLOGUE (stop_func_start);
+ }
+ sal = find_pc_line (stop_func_start, 0);
+ /* Use the step_resume_break to step until
+ the end of the prologue, even if that involves jumps
+ (as it seems to on the vax under 4.2). */
+ /* If the prologue ends in the middle of a source line,
+ continue to the end of that source line (if it is still
+ within the function). Otherwise, just go to end of prologue. */
+#ifdef PROLOGUE_FIRSTLINE_OVERLAP
+ /* no, don't either. It skips any code that's
+ legitimately on the first line. */
+#else
+ if (sal.end && sal.pc != stop_func_start && sal.end < stop_func_end)
+ stop_func_start = sal.end;
+#endif
+
+ if (stop_func_start == stop_pc)
+ {
+ /* We are already there: stop now. */
+ stop_step = 1;
+ break;
+ }
+ else
+ /* Put the step-breakpoint there and go until there. */
+ {
+ struct symtab_and_line sr_sal;
+
+ sr_sal.pc = stop_func_start;
+ sr_sal.symtab = NULL;
+ sr_sal.line = 0;
+ /* Do not specify what the fp should be when we stop
+ since on some machines the prologue
+ is where the new fp value is established. */
+ step_resume_breakpoint =
+ set_momentary_breakpoint (sr_sal, NULL, bp_step_resume);
+ if (breakpoints_inserted)
+ insert_breakpoints ();
+
+ /* And make sure stepping stops right away then. */
+ step_range_end = step_range_start;
+ }
+ goto keep_going;
+ }
+
+ /* We've wandered out of the step range. */
+
+ sal = find_pc_line(stop_pc, 0);
+
+ if (step_range_end == 1)
+ {
+ /* It is stepi or nexti. We always want to stop stepping after
+ one instruction. */
+ stop_step = 1;
+ break;
+ }
+
+ if (sal.line == 0)
+ {
+ /* We have no line number information. That means to stop
+ stepping (does this always happen right after one instruction,
+ when we do "s" in a function with no line numbers,
+ or can this happen as a result of a return or longjmp?). */
+ stop_step = 1;
+ break;
+ }
+
+ if (stop_pc == sal.pc
+ && (current_line != sal.line || current_symtab != sal.symtab))
+ {
+ /* We are at the start of a different line. So stop. Note that
+ we don't stop if we step into the middle of a different line.
+ That is said to make things like for (;;) statements work
+ better. */
+ stop_step = 1;
+ break;
+ }
+
+ /* We aren't done stepping.
+
+ Optimize by setting the stepping range to the line.
+ (We might not be in the original line, but if we entered a
+ new line in mid-statement, we continue stepping. This makes
+ things like for(;;) statements work better.) */
+
+ if (stop_func_end && sal.end >= stop_func_end)
+ {
+ /* If this is the last line of the function, don't keep stepping
+ (it would probably step us out of the function).
+ This is particularly necessary for a one-line function,
+ in which after skipping the prologue we better stop even though
+ we will be in mid-line. */
+ stop_step = 1;
+ break;
+ }
+ step_range_start = sal.pc;
+ step_range_end = sal.end;
+ goto keep_going;
+
+ check_sigtramp2:
+ if (trap_expected
+ && IN_SIGTRAMP (stop_pc, stop_func_name)
+ && !IN_SIGTRAMP (prev_pc, prev_func_name))
+ {
+ /* What has happened here is that we have just stepped the inferior
+ with a signal (because it is a signal which shouldn't make
+ us stop), thus stepping into sigtramp.
+
+ So we need to set a step_resume_break_address breakpoint
+ and continue until we hit it, and then step. FIXME: This should
+ be more enduring than a step_resume breakpoint; we should know
+ that we will later need to keep going rather than re-hitting
+ the breakpoint here (see testsuite/gdb.t06/signals.exp where
+ it says "exceedingly difficult"). */
+ struct symtab_and_line sr_sal;
+
+ sr_sal.pc = prev_pc;
+ sr_sal.symtab = NULL;
+ sr_sal.line = 0;
+ /* We perhaps could set the frame if we kept track of what
+ the frame corresponding to prev_pc was. But we don't,
+ so don't. */
+ through_sigtramp_breakpoint =
+ set_momentary_breakpoint (sr_sal, NULL, bp_through_sigtramp);
+ if (breakpoints_inserted)
+ insert_breakpoints ();
+
+ remove_breakpoints_on_following_step = 1;
+ another_trap = 1;
+ }
+
+ keep_going:
+ /* Come to this label when you need to resume the inferior.
+ It's really much cleaner to do a goto than a maze of if-else
+ conditions. */
+
+ /* Save the pc before execution, to compare with pc after stop. */
+ prev_pc = read_pc (); /* Might have been DECR_AFTER_BREAK */
+ prev_func_start = stop_func_start; /* Ok, since if DECR_PC_AFTER
+ BREAK is defined, the
+ original pc would not have
+ been at the start of a
+ function. */
+ prev_func_name = stop_func_name;
+ prev_sp = stop_sp;
+ prev_frame_address = stop_frame_address;
+
+ /* If we did not do break;, it means we should keep
+ running the inferior and not return to debugger. */
+
+ if (trap_expected && stop_signal != TARGET_SIGNAL_TRAP)
+ {
+ /* We took a signal (which we are supposed to pass through to
+ the inferior, else we'd have done a break above) and we
+ haven't yet gotten our trap. Simply continue. */
+ resume (CURRENTLY_STEPPING (), stop_signal);
+ }
+ else
+ {
+ /* Either the trap was not expected, but we are continuing
+ anyway (the user asked that this signal be passed to the
+ child)
+ -- or --
+ The signal was SIGTRAP, e.g. it was our signal, but we
+ decided we should resume from it.
+
+ We're going to run this baby now!
+
+ Insert breakpoints now, unless we are trying
+ to one-proceed past a breakpoint. */
+ /* If we've just finished a special step resume and we don't
+ want to hit a breakpoint, pull em out. */
+ if (step_resume_breakpoint == NULL
+ && through_sigtramp_breakpoint == NULL
+ && remove_breakpoints_on_following_step)
+ {
+ remove_breakpoints_on_following_step = 0;
+ remove_breakpoints ();
+ breakpoints_inserted = 0;
+ }
+ else if (!breakpoints_inserted &&
+ (through_sigtramp_breakpoint != NULL || !another_trap))
+ {
+ breakpoints_failed = insert_breakpoints ();
+ if (breakpoints_failed)
+ break;
+ breakpoints_inserted = 1;
+ }
+
+ trap_expected = another_trap;
+
+ if (stop_signal == TARGET_SIGNAL_TRAP)
+ stop_signal = TARGET_SIGNAL_0;
+
+#ifdef SHIFT_INST_REGS
+ /* I'm not sure when this following segment applies. I do know, now,
+ that we shouldn't rewrite the regs when we were stopped by a
+ random signal from the inferior process. */
+ /* FIXME: Shouldn't this be based on the valid bit of the SXIP?
+ (this is only used on the 88k). */
+
+ if (!bpstat_explains_signal (stop_bpstat)
+ && (stop_signal != TARGET_SIGNAL_CHLD)
+ && !stopped_by_random_signal)
+ SHIFT_INST_REGS();
+#endif /* SHIFT_INST_REGS */
+
+ resume (CURRENTLY_STEPPING (), stop_signal);
+ }
+ }
+
+ stop_stepping:
+ if (target_has_execution)
+ {
+ /* Assuming the inferior still exists, set these up for next
+ time, just like we did above if we didn't break out of the
+ loop. */
+ prev_pc = read_pc ();
+ prev_func_start = stop_func_start;
+ prev_func_name = stop_func_name;
+ prev_sp = stop_sp;
+ prev_frame_address = stop_frame_address;
+ }
+ do_cleanups (old_cleanups);
+}
+
+/* Here to return control to GDB when the inferior stops for real.
+ Print appropriate messages, remove breakpoints, give terminal our modes.
+
+ STOP_PRINT_FRAME nonzero means print the executing frame
+ (pc, function, args, file, line number and line text).
+ BREAKPOINTS_FAILED nonzero means stop was due to error
+ attempting to insert breakpoints. */
+
+void
+normal_stop ()
+{
+ /* Make sure that the current_frame's pc is correct. This
+ is a correction for setting up the frame info before doing
+ DECR_PC_AFTER_BREAK */
+ if (target_has_execution && get_current_frame())
+ (get_current_frame ())->pc = read_pc ();
+
+ if (breakpoints_failed)
+ {
+ target_terminal_ours_for_output ();
+ print_sys_errmsg ("ptrace", breakpoints_failed);
+ printf_filtered ("Stopped; cannot insert breakpoints.\n\
+The same program may be running in another process.\n");
+ }
+
+ if (target_has_execution && breakpoints_inserted)
+ if (remove_breakpoints ())
+ {
+ target_terminal_ours_for_output ();
+ printf_filtered ("Cannot remove breakpoints because program is no longer writable.\n\
+It might be running in another process.\n\
+Further execution is probably impossible.\n");
+ }
+
+ breakpoints_inserted = 0;
+
+ /* Delete the breakpoint we stopped at, if it wants to be deleted.
+ Delete any breakpoint that is to be deleted at the next stop. */
+
+ breakpoint_auto_delete (stop_bpstat);
+
+ /* If an auto-display called a function and that got a signal,
+ delete that auto-display to avoid an infinite recursion. */
+
+ if (stopped_by_random_signal)
+ disable_current_display ();
+
+ if (step_multi && stop_step)
+ goto done;
+
+ target_terminal_ours ();
+
+ /* Look up the hook_stop and run it if it exists. */
+
+ if (stop_command->hook)
+ {
+ catch_errors (hook_stop_stub, (char *)stop_command->hook,
+ "Error while running hook_stop:\n", RETURN_MASK_ALL);
+ }
+
+ if (!target_has_stack)
+ goto done;
+
+ /* Select innermost stack frame except on return from a stack dummy routine,
+ or if the program has exited. Print it without a level number if
+ we have changed functions or hit a breakpoint. Print source line
+ if we have one. */
+ if (!stop_stack_dummy)
+ {
+ if (stop_print_frame)
+ {
+ int source_only;
+
+ source_only = bpstat_print (stop_bpstat);
+ source_only = source_only ||
+ ( stop_step
+ && step_frame_address == stop_frame_address
+ && step_start_function == find_pc_function (stop_pc));
+
+ print_stack_frame (selected_frame, -1, source_only? -1: 1);
+
+ /* Display the auto-display expressions. */
+ do_displays ();
+ }
+ }
+
+ /* Save the function value return registers, if we care.
+ We might be about to restore their previous contents. */
+ if (proceed_to_finish)
+ read_register_bytes (0, stop_registers, REGISTER_BYTES);
+
+ if (stop_stack_dummy)
+ {
+ /* Pop the empty frame that contains the stack dummy.
+ POP_FRAME ends with a setting of the current frame, so we
+ can use that next. */
+ POP_FRAME;
+ /* Set stop_pc to what it was before we called the function. Can't rely
+ on restore_inferior_status because that only gets called if we don't
+ stop in the called function. */
+ stop_pc = read_pc();
+ select_frame (get_current_frame (), 0);
+ }
+ done:
+ annotate_stopped ();
+}
+
+static int
+hook_stop_stub (cmd)
+ char *cmd;
+{
+ execute_user_command ((struct cmd_list_element *)cmd, 0);
+ return (0);
+}
+
+int signal_stop_state (signo)
+ int signo;
+{
+ return signal_stop[signo];
+}
+
+int signal_print_state (signo)
+ int signo;
+{
+ return signal_print[signo];
+}
+
+int signal_pass_state (signo)
+ int signo;
+{
+ return signal_program[signo];
+}
+
+static void
+sig_print_header ()
+{
+ printf_filtered ("\
+Signal Stop\tPrint\tPass to program\tDescription\n");
+}
+
+static void
+sig_print_info (oursig)
+ enum target_signal oursig;
+{
+ char *name = target_signal_to_name (oursig);
+ printf_filtered ("%s", name);
+ printf_filtered ("%*.*s ", 13 - strlen (name), 13 - strlen (name),
+ " ");
+ printf_filtered ("%s\t", signal_stop[oursig] ? "Yes" : "No");
+ printf_filtered ("%s\t", signal_print[oursig] ? "Yes" : "No");
+ printf_filtered ("%s\t\t", signal_program[oursig] ? "Yes" : "No");
+ printf_filtered ("%s\n", target_signal_to_string (oursig));
+}
+
+/* Specify how various signals in the inferior should be handled. */
+
+static void
+handle_command (args, from_tty)
+ char *args;
+ int from_tty;
+{
+ char **argv;
+ int digits, wordlen;
+ int sigfirst, signum, siglast;
+ enum target_signal oursig;
+ int allsigs;
+ int nsigs;
+ unsigned char *sigs;
+ struct cleanup *old_chain;
+
+ if (args == NULL)
+ {
+ error_no_arg ("signal to handle");
+ }
+
+ /* Allocate and zero an array of flags for which signals to handle. */
+
+ nsigs = (int)TARGET_SIGNAL_LAST;
+ sigs = (unsigned char *) alloca (nsigs);
+ memset (sigs, 0, nsigs);
+
+ /* Break the command line up into args. */
+
+ argv = buildargv (args);
+ if (argv == NULL)
+ {
+ nomem (0);
+ }
+ old_chain = make_cleanup (freeargv, (char *) argv);
+
+ /* Walk through the args, looking for signal oursigs, signal names, and
+ actions. Signal numbers and signal names may be interspersed with
+ actions, with the actions being performed for all signals cumulatively
+ specified. Signal ranges can be specified as <LOW>-<HIGH>. */
+
+ while (*argv != NULL)
+ {
+ wordlen = strlen (*argv);
+ for (digits = 0; isdigit ((*argv)[digits]); digits++) {;}
+ allsigs = 0;
+ sigfirst = siglast = -1;
+
+ if (wordlen >= 1 && !strncmp (*argv, "all", wordlen))
+ {
+ /* Apply action to all signals except those used by the
+ debugger. Silently skip those. */
+ allsigs = 1;
+ sigfirst = 0;
+ siglast = nsigs - 1;
+ }
+ else if (wordlen >= 1 && !strncmp (*argv, "stop", wordlen))
+ {
+ SET_SIGS (nsigs, sigs, signal_stop);
+ SET_SIGS (nsigs, sigs, signal_print);
+ }
+ else if (wordlen >= 1 && !strncmp (*argv, "ignore", wordlen))
+ {
+ UNSET_SIGS (nsigs, sigs, signal_program);
+ }
+ else if (wordlen >= 2 && !strncmp (*argv, "print", wordlen))
+ {
+ SET_SIGS (nsigs, sigs, signal_print);
+ }
+ else if (wordlen >= 2 && !strncmp (*argv, "pass", wordlen))
+ {
+ SET_SIGS (nsigs, sigs, signal_program);
+ }
+ else if (wordlen >= 3 && !strncmp (*argv, "nostop", wordlen))
+ {
+ UNSET_SIGS (nsigs, sigs, signal_stop);
+ }
+ else if (wordlen >= 3 && !strncmp (*argv, "noignore", wordlen))
+ {
+ SET_SIGS (nsigs, sigs, signal_program);
+ }
+ else if (wordlen >= 4 && !strncmp (*argv, "noprint", wordlen))
+ {
+ UNSET_SIGS (nsigs, sigs, signal_print);
+ UNSET_SIGS (nsigs, sigs, signal_stop);
+ }
+ else if (wordlen >= 4 && !strncmp (*argv, "nopass", wordlen))
+ {
+ UNSET_SIGS (nsigs, sigs, signal_program);
+ }
+ else if (digits > 0)
+ {
+ /* It is numeric. The numeric signal refers to our own internal
+ signal numbering from target.h, not to host/target signal number.
+ This is a feature; users really should be using symbolic names
+ anyway, and the common ones like SIGHUP, SIGINT, SIGALRM, etc.
+ will work right anyway. */
+
+ sigfirst = siglast = atoi (*argv);
+ if ((*argv)[digits] == '-')
+ {
+ siglast = atoi ((*argv) + digits + 1);
+ }
+ if (sigfirst > siglast)
+ {
+ /* Bet he didn't figure we'd think of this case... */
+ signum = sigfirst;
+ sigfirst = siglast;
+ siglast = signum;
+ }
+ if (sigfirst < 0 || sigfirst >= nsigs)
+ {
+ error ("Signal %d not in range 0-%d", sigfirst, nsigs - 1);
+ }
+ if (siglast < 0 || siglast >= nsigs)
+ {
+ error ("Signal %d not in range 0-%d", siglast, nsigs - 1);
+ }
+ }
+ else
+ {
+ oursig = target_signal_from_name (*argv);
+ if (oursig != TARGET_SIGNAL_UNKNOWN)
+ {
+ sigfirst = siglast = (int)oursig;
+ }
+ else
+ {
+ /* Not a number and not a recognized flag word => complain. */
+ error ("Unrecognized or ambiguous flag word: \"%s\".", *argv);
+ }
+ }
+
+ /* If any signal numbers or symbol names were found, set flags for
+ which signals to apply actions to. */
+
+ for (signum = sigfirst; signum >= 0 && signum <= siglast; signum++)
+ {
+ switch ((enum target_signal)signum)
+ {
+ case TARGET_SIGNAL_TRAP:
+ case TARGET_SIGNAL_INT:
+ if (!allsigs && !sigs[signum])
+ {
+ if (query ("%s is used by the debugger.\n\
+Are you sure you want to change it? ",
+ target_signal_to_name
+ ((enum target_signal)signum)))
+ {
+ sigs[signum] = 1;
+ }
+ else
+ {
+ printf_unfiltered ("Not confirmed, unchanged.\n");
+ gdb_flush (gdb_stdout);
+ }
+ }
+ break;
+ default:
+ sigs[signum] = 1;
+ break;
+ }
+ }
+
+ argv++;
+ }
+
+ target_notice_signals(inferior_pid);
+
+ if (from_tty)
+ {
+ /* Show the results. */
+ sig_print_header ();
+ for (signum = 0; signum < nsigs; signum++)
+ {
+ if (sigs[signum])
+ {
+ sig_print_info (signum);
+ }
+ }
+ }
+
+ do_cleanups (old_chain);
+}
+
+/* Print current contents of the tables set by the handle command.
+ It is possible we should just be printing signals actually used
+ by the current target (but for things to work right when switching
+ targets, all signals should be in the signal tables). */
+
+static void
+signals_info (signum_exp, from_tty)
+ char *signum_exp;
+ int from_tty;
+{
+ enum target_signal oursig;
+ sig_print_header ();
+
+ if (signum_exp)
+ {
+ /* First see if this is a symbol name. */
+ oursig = target_signal_from_name (signum_exp);
+ if (oursig == TARGET_SIGNAL_UNKNOWN)
+ {
+ /* Nope, maybe it's an address which evaluates to a signal
+ number. */
+ /* The numeric signal refers to our own internal
+ signal numbering from target.h, not to host/target signal number.
+ This is a feature; users really should be using symbolic names
+ anyway, and the common ones like SIGHUP, SIGINT, SIGALRM, etc.
+ will work right anyway. */
+ int i = parse_and_eval_address (signum_exp);
+ if (i >= (int)TARGET_SIGNAL_LAST
+ || i < 0
+ || i == (int)TARGET_SIGNAL_UNKNOWN
+ || i == (int)TARGET_SIGNAL_DEFAULT)
+ error ("Signal number out of bounds.");
+ oursig = (enum target_signal)i;
+ }
+ sig_print_info (oursig);
+ return;
+ }
+
+ printf_filtered ("\n");
+ /* These ugly casts brought to you by the native VAX compiler. */
+ for (oursig = TARGET_SIGNAL_FIRST;
+ (int)oursig < (int)TARGET_SIGNAL_LAST;
+ oursig = (enum target_signal)((int)oursig + 1))
+ {
+ QUIT;
+
+ if (oursig != TARGET_SIGNAL_UNKNOWN
+ && oursig != TARGET_SIGNAL_DEFAULT
+ && oursig != TARGET_SIGNAL_0)
+ sig_print_info (oursig);
+ }
+
+ printf_filtered ("\nUse the \"handle\" command to change these tables.\n");
+}
+
+/* Save all of the information associated with the inferior<==>gdb
+ connection. INF_STATUS is a pointer to a "struct inferior_status"
+ (defined in inferior.h). */
+
+void
+save_inferior_status (inf_status, restore_stack_info)
+ struct inferior_status *inf_status;
+ int restore_stack_info;
+{
+ inf_status->stop_signal = stop_signal;
+ inf_status->stop_pc = stop_pc;
+ inf_status->stop_frame_address = stop_frame_address;
+ inf_status->stop_step = stop_step;
+ inf_status->stop_stack_dummy = stop_stack_dummy;
+ inf_status->stopped_by_random_signal = stopped_by_random_signal;
+ inf_status->trap_expected = trap_expected;
+ inf_status->step_range_start = step_range_start;
+ inf_status->step_range_end = step_range_end;
+ inf_status->step_frame_address = step_frame_address;
+ inf_status->step_over_calls = step_over_calls;
+ inf_status->stop_after_trap = stop_after_trap;
+ inf_status->stop_soon_quietly = stop_soon_quietly;
+ /* Save original bpstat chain here; replace it with copy of chain.
+ If caller's caller is walking the chain, they'll be happier if we
+ hand them back the original chain when restore_i_s is called. */
+ inf_status->stop_bpstat = stop_bpstat;
+ stop_bpstat = bpstat_copy (stop_bpstat);
+ inf_status->breakpoint_proceeded = breakpoint_proceeded;
+ inf_status->restore_stack_info = restore_stack_info;
+ inf_status->proceed_to_finish = proceed_to_finish;
+
+ memcpy (inf_status->stop_registers, stop_registers, REGISTER_BYTES);
+
+ read_register_bytes (0, inf_status->registers, REGISTER_BYTES);
+
+ record_selected_frame (&(inf_status->selected_frame_address),
+ &(inf_status->selected_level));
+ return;
+}
+
+struct restore_selected_frame_args {
+ FRAME_ADDR frame_address;
+ int level;
+};
+
+static int restore_selected_frame PARAMS ((char *));
+
+/* Restore the selected frame. args is really a struct
+ restore_selected_frame_args * (declared as char * for catch_errors)
+ telling us what frame to restore. Returns 1 for success, or 0 for
+ failure. An error message will have been printed on error. */
+static int
+restore_selected_frame (args)
+ char *args;
+{
+ struct restore_selected_frame_args *fr =
+ (struct restore_selected_frame_args *) args;
+ FRAME fid;
+ int level = fr->level;
+
+ fid = find_relative_frame (get_current_frame (), &level);
+
+ /* If inf_status->selected_frame_address is NULL, there was no
+ previously selected frame. */
+ if (fid == 0 ||
+ FRAME_FP (fid) != fr->frame_address ||
+ level != 0)
+ {
+ warning ("Unable to restore previously selected frame.\n");
+ return 0;
+ }
+ select_frame (fid, fr->level);
+ return(1);
+}
+
+void
+restore_inferior_status (inf_status)
+ struct inferior_status *inf_status;
+{
+ stop_signal = inf_status->stop_signal;
+ stop_pc = inf_status->stop_pc;
+ stop_frame_address = inf_status->stop_frame_address;
+ stop_step = inf_status->stop_step;
+ stop_stack_dummy = inf_status->stop_stack_dummy;
+ stopped_by_random_signal = inf_status->stopped_by_random_signal;
+ trap_expected = inf_status->trap_expected;
+ step_range_start = inf_status->step_range_start;
+ step_range_end = inf_status->step_range_end;
+ step_frame_address = inf_status->step_frame_address;
+ step_over_calls = inf_status->step_over_calls;
+ stop_after_trap = inf_status->stop_after_trap;
+ stop_soon_quietly = inf_status->stop_soon_quietly;
+ bpstat_clear (&stop_bpstat);
+ stop_bpstat = inf_status->stop_bpstat;
+ breakpoint_proceeded = inf_status->breakpoint_proceeded;
+ proceed_to_finish = inf_status->proceed_to_finish;
+
+ memcpy (stop_registers, inf_status->stop_registers, REGISTER_BYTES);
+
+ /* The inferior can be gone if the user types "print exit(0)"
+ (and perhaps other times). */
+ if (target_has_execution)
+ write_register_bytes (0, inf_status->registers, REGISTER_BYTES);
+
+ /* The inferior can be gone if the user types "print exit(0)"
+ (and perhaps other times). */
+
+ /* FIXME: If we are being called after stopping in a function which
+ is called from gdb, we should not be trying to restore the
+ selected frame; it just prints a spurious error message (The
+ message is useful, however, in detecting bugs in gdb (like if gdb
+ clobbers the stack)). In fact, should we be restoring the
+ inferior status at all in that case? . */
+
+ if (target_has_stack && inf_status->restore_stack_info)
+ {
+ struct restore_selected_frame_args fr;
+ fr.level = inf_status->selected_level;
+ fr.frame_address = inf_status->selected_frame_address;
+ /* The point of catch_errors is that if the stack is clobbered,
+ walking the stack might encounter a garbage pointer and error()
+ trying to dereference it. */
+ if (catch_errors (restore_selected_frame, &fr,
+ "Unable to restore previously selected frame:\n",
+ RETURN_MASK_ERROR) == 0)
+ /* Error in restoring the selected frame. Select the innermost
+ frame. */
+ select_frame (get_current_frame (), 0);
+ }
+}
+
+
+void
+_initialize_infrun ()
+{
+ register int i;
+ register int numsigs;
+
+ add_info ("signals", signals_info,
+ "What debugger does when program gets various signals.\n\
+Specify a signal number as argument to print info on that signal only.");
+ add_info_alias ("handle", "signals", 0);
+
+ add_com ("handle", class_run, handle_command,
+ "Specify how to handle a signal.\n\
+Args are signal numbers and actions to apply to those signals.\n\
+Signal numbers may be numeric (ex. 11) or symbolic (ex. SIGSEGV).\n\
+Numeric ranges may be specified with the form LOW-HIGH (ex. 14-21).\n\
+The special arg \"all\" is recognized to mean all signals except those\n\
+used by the debugger, typically SIGTRAP and SIGINT.\n\
+Recognized actions include \"stop\", \"nostop\", \"print\", \"noprint\",\n\
+\"pass\", \"nopass\", \"ignore\", or \"noignore\".\n\
+Stop means reenter debugger if this signal happens (implies print).\n\
+Print means print a message if this signal happens.\n\
+Pass means let program see this signal; otherwise program doesn't know.\n\
+Ignore is a synonym for nopass and noignore is a synonym for pass.\n\
+Pass and Stop may be combined.");
+
+ stop_command = add_cmd ("stop", class_obscure, not_just_help_class_command,
+ "There is no `stop' command, but you can set a hook on `stop'.\n\
+This allows you to set a list of commands to be run each time execution\n\
+of the program stops.", &cmdlist);
+
+ numsigs = (int)TARGET_SIGNAL_LAST;
+ signal_stop = (unsigned char *)
+ xmalloc (sizeof (signal_stop[0]) * numsigs);
+ signal_print = (unsigned char *)
+ xmalloc (sizeof (signal_print[0]) * numsigs);
+ signal_program = (unsigned char *)
+ xmalloc (sizeof (signal_program[0]) * numsigs);
+ for (i = 0; i < numsigs; i++)
+ {
+ signal_stop[i] = 1;
+ signal_print[i] = 1;
+ signal_program[i] = 1;
+ }
+
+ /* Signals caused by debugger's own actions
+ should not be given to the program afterwards. */
+ signal_program[TARGET_SIGNAL_TRAP] = 0;
+ signal_program[TARGET_SIGNAL_INT] = 0;
+
+ /* Signals that are not errors should not normally enter the debugger. */
+ signal_stop[TARGET_SIGNAL_ALRM] = 0;
+ signal_print[TARGET_SIGNAL_ALRM] = 0;
+ signal_stop[TARGET_SIGNAL_VTALRM] = 0;
+ signal_print[TARGET_SIGNAL_VTALRM] = 0;
+ signal_stop[TARGET_SIGNAL_PROF] = 0;
+ signal_print[TARGET_SIGNAL_PROF] = 0;
+ signal_stop[TARGET_SIGNAL_CHLD] = 0;
+ signal_print[TARGET_SIGNAL_CHLD] = 0;
+ signal_stop[TARGET_SIGNAL_IO] = 0;
+ signal_print[TARGET_SIGNAL_IO] = 0;
+ signal_stop[TARGET_SIGNAL_POLL] = 0;
+ signal_print[TARGET_SIGNAL_POLL] = 0;
+ signal_stop[TARGET_SIGNAL_URG] = 0;
+ signal_print[TARGET_SIGNAL_URG] = 0;
+}
diff --git a/gnu/usr.bin/gdb/gdb/inftarg.c b/gnu/usr.bin/gdb/gdb/inftarg.c
new file mode 100644
index 0000000..6515c26
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/inftarg.c
@@ -0,0 +1,328 @@
+/* Target-vector operations for controlling Unix child processes, for GDB.
+ Copyright 1990, 1991, 1992 Free Software Foundation, Inc.
+ Contributed by Cygnus Support.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "defs.h"
+#include "frame.h" /* required by inferior.h */
+#include "inferior.h"
+#include "target.h"
+#include "wait.h"
+#include "gdbcore.h"
+#include "command.h"
+#include <signal.h>
+
+static void
+child_prepare_to_store PARAMS ((void));
+
+#ifndef CHILD_WAIT
+static int child_wait PARAMS ((int, struct target_waitstatus *));
+#endif /* CHILD_WAIT */
+
+static void child_open PARAMS ((char *, int));
+
+static void
+child_files_info PARAMS ((struct target_ops *));
+
+static void
+child_detach PARAMS ((char *, int));
+
+static void
+child_attach PARAMS ((char *, int));
+
+static void
+ptrace_me PARAMS ((void));
+
+static void
+ptrace_him PARAMS ((int));
+
+static void child_create_inferior PARAMS ((char *, char *, char **));
+
+static void
+child_mourn_inferior PARAMS ((void));
+
+static int
+child_can_run PARAMS ((void));
+
+extern char **environ;
+
+/* Forward declaration */
+extern struct target_ops child_ops;
+
+#ifndef CHILD_WAIT
+
+/* Wait for child to do something. Return pid of child, or -1 in case
+ of error; store status through argument pointer OURSTATUS. */
+
+static int
+child_wait (pid, ourstatus)
+ int pid;
+ struct target_waitstatus *ourstatus;
+{
+ int save_errno;
+ int status;
+
+ do {
+ if (attach_flag)
+ set_sigint_trap(); /* Causes SIGINT to be passed on to the
+ attached process. */
+ set_sigio_trap ();
+
+ pid = proc_wait (inferior_pid, &status);
+ save_errno = errno;
+
+ clear_sigio_trap ();
+
+ if (attach_flag)
+ clear_sigint_trap();
+
+ if (pid == -1)
+ {
+ if (save_errno == EINTR)
+ continue;
+ fprintf_unfiltered (gdb_stderr, "Child process unexpectedly missing: %s.\n",
+ safe_strerror (save_errno));
+ /* Claim it exited with unknown signal. */
+ ourstatus->kind = TARGET_WAITKIND_SIGNALLED;
+ ourstatus->value.sig = TARGET_SIGNAL_UNKNOWN;
+ return -1;
+ }
+ } while (pid != inferior_pid); /* Some other child died or stopped */
+ store_waitstatus (ourstatus, status);
+ return pid;
+}
+#endif /* CHILD_WAIT */
+
+/* Attach to process PID, then initialize for debugging it. */
+
+static void
+child_attach (args, from_tty)
+ char *args;
+ int from_tty;
+{
+ if (!args)
+ error_no_arg ("process-id to attach");
+
+#ifndef ATTACH_DETACH
+ error ("Can't attach to a process on this machine.");
+#else
+ {
+ char *exec_file;
+ int pid;
+
+ pid = atoi (args);
+
+ if (pid == getpid()) /* Trying to masturbate? */
+ error ("I refuse to debug myself!");
+
+ if (from_tty)
+ {
+ exec_file = (char *) get_exec_file (0);
+
+ if (exec_file)
+ printf_unfiltered ("Attaching to program `%s', %s\n", exec_file,
+ target_pid_to_str (pid));
+ else
+ printf_unfiltered ("Attaching to %s\n", target_pid_to_str (pid));
+
+ gdb_flush (gdb_stdout);
+ }
+
+ attach (pid);
+ inferior_pid = pid;
+ push_target (&child_ops);
+ }
+#endif /* ATTACH_DETACH */
+}
+
+
+/* Take a program previously attached to and detaches it.
+ The program resumes execution and will no longer stop
+ on signals, etc. We'd better not have left any breakpoints
+ in the program or it'll die when it hits one. For this
+ to work, it may be necessary for the process to have been
+ previously attached. It *might* work if the program was
+ started via the normal ptrace (PTRACE_TRACEME). */
+
+static void
+child_detach (args, from_tty)
+ char *args;
+ int from_tty;
+{
+#ifdef ATTACH_DETACH
+ {
+ int siggnal = 0;
+
+ if (from_tty)
+ {
+ char *exec_file = get_exec_file (0);
+ if (exec_file == 0)
+ exec_file = "";
+ printf_unfiltered ("Detaching from program: %s %s\n", exec_file,
+ target_pid_to_str (inferior_pid));
+ gdb_flush (gdb_stdout);
+ }
+ if (args)
+ siggnal = atoi (args);
+
+ detach (siggnal);
+ inferior_pid = 0;
+ unpush_target (&child_ops);
+ }
+#else
+ error ("This version of Unix does not support detaching a process.");
+#endif
+}
+
+/* Get ready to modify the registers array. On machines which store
+ individual registers, this doesn't need to do anything. On machines
+ which store all the registers in one fell swoop, this makes sure
+ that registers contains all the registers from the program being
+ debugged. */
+
+static void
+child_prepare_to_store ()
+{
+#ifdef CHILD_PREPARE_TO_STORE
+ CHILD_PREPARE_TO_STORE ();
+#endif
+}
+
+/* Print status information about what we're accessing. */
+
+static void
+child_files_info (ignore)
+ struct target_ops *ignore;
+{
+ printf_unfiltered ("\tUsing the running image of %s %s.\n",
+ attach_flag? "attached": "child", target_pid_to_str (inferior_pid));
+}
+
+/* ARGSUSED */
+static void
+child_open (arg, from_tty)
+ char *arg;
+ int from_tty;
+{
+ error ("Use the \"run\" command to start a Unix child process.");
+}
+
+/* Stub function which causes the inferior that runs it, to be ptrace-able
+ by its parent process. */
+
+static void
+ptrace_me ()
+{
+ /* "Trace me, Dr. Memory!" */
+ call_ptrace (0, 0, (PTRACE_ARG3_TYPE) 0, 0);
+}
+
+/* Stub function which causes the GDB that runs it, to start ptrace-ing
+ the child process. */
+
+static void
+ptrace_him (pid)
+ int pid;
+{
+ push_target (&child_ops);
+
+#ifdef START_INFERIOR_TRAPS_EXPECTED
+ startup_inferior (START_INFERIOR_TRAPS_EXPECTED);
+#else
+ /* One trap to exec the shell, one to exec the program being debugged. */
+ startup_inferior (2);
+#endif
+}
+
+/* Start an inferior Unix child process and sets inferior_pid to its pid.
+ EXEC_FILE is the file to run.
+ ALLARGS is a string containing the arguments to the program.
+ ENV is the environment vector to pass. Errors reported with error(). */
+
+static void
+child_create_inferior (exec_file, allargs, env)
+ char *exec_file;
+ char *allargs;
+ char **env;
+{
+ fork_inferior (exec_file, allargs, env, ptrace_me, ptrace_him, NULL);
+ /* We are at the first instruction we care about. */
+ /* Pedal to the metal... */
+ proceed ((CORE_ADDR) -1, TARGET_SIGNAL_0, 0);
+}
+
+static void
+child_mourn_inferior ()
+{
+ unpush_target (&child_ops);
+ proc_remove_foreign (inferior_pid);
+ generic_mourn_inferior ();
+}
+
+static int
+child_can_run ()
+{
+ return(1);
+}
+
+struct target_ops child_ops = {
+ "child", /* to_shortname */
+ "Unix child process", /* to_longname */
+ "Unix child process (started by the \"run\" command).", /* to_doc */
+ child_open, /* to_open */
+ 0, /* to_close */
+ child_attach, /* to_attach */
+ child_detach, /* to_detach */
+ child_resume, /* to_resume */
+ child_wait, /* to_wait */
+ fetch_inferior_registers, /* to_fetch_registers */
+ store_inferior_registers, /* to_store_registers */
+ child_prepare_to_store, /* to_prepare_to_store */
+ child_xfer_memory, /* to_xfer_memory */
+ child_files_info, /* to_files_info */
+ memory_insert_breakpoint, /* to_insert_breakpoint */
+ memory_remove_breakpoint, /* to_remove_breakpoint */
+ terminal_init_inferior, /* to_terminal_init */
+ terminal_inferior, /* to_terminal_inferior */
+ terminal_ours_for_output, /* to_terminal_ours_for_output */
+ terminal_ours, /* to_terminal_ours */
+ child_terminal_info, /* to_terminal_info */
+ kill_inferior, /* to_kill */
+ 0, /* to_load */
+ 0, /* to_lookup_symbol */
+ child_create_inferior, /* to_create_inferior */
+ child_mourn_inferior, /* to_mourn_inferior */
+ child_can_run, /* to_can_run */
+ 0, /* to_notice_signals */
+ process_stratum, /* to_stratum */
+ 0, /* to_next */
+ 1, /* to_has_all_memory */
+ 1, /* to_has_memory */
+ 1, /* to_has_stack */
+ 1, /* to_has_registers */
+ 1, /* to_has_execution */
+ 0, /* sections */
+ 0, /* sections_end */
+ OPS_MAGIC /* to_magic */
+};
+
+void
+_initialize_inftarg ()
+{
+ add_target (&child_ops);
+}
diff --git a/gnu/usr.bin/gdb/gdb/init.c b/gnu/usr.bin/gdb/gdb/init.c
new file mode 100644
index 0000000..7606e3c
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/init.c
@@ -0,0 +1,54 @@
+#include "defs.h" /* for KERNEL_DEBUG */
+/* Do not modify this file. */
+/* It is created automatically by the Makefile. */
+void initialize_all_files () {
+ {extern void _initialize_blockframe (); _initialize_blockframe ();}
+ {extern void _initialize_breakpoint (); _initialize_breakpoint ();}
+ {extern void _initialize_stack (); _initialize_stack ();}
+ {extern void _initialize_thread (); _initialize_thread ();}
+ {extern void _initialize_source (); _initialize_source ();}
+ {extern void _initialize_values (); _initialize_values ();}
+ {extern void _initialize_valarith (); _initialize_valarith ();}
+ {extern void _initialize_valprint (); _initialize_valprint ();}
+ {extern void _initialize_printcmd (); _initialize_printcmd ();}
+ {extern void _initialize_symtab (); _initialize_symtab ();}
+ {extern void _initialize_symfile (); _initialize_symfile ();}
+ {extern void _initialize_symmisc (); _initialize_symmisc ();}
+ {extern void _initialize_infcmd (); _initialize_infcmd ();}
+ {extern void _initialize_infrun (); _initialize_infrun ();}
+ {extern void _initialize_command (); _initialize_command ();}
+ {extern void _initialize_gdbtypes (); _initialize_gdbtypes ();}
+ {extern void _initialize_copying (); _initialize_copying ();}
+ {extern void _initialize_solib (); _initialize_solib ();}
+ {extern void _initialize_ser_hardwire (); _initialize_ser_hardwire ();}
+ {extern void _initialize_exec (); _initialize_exec ();}
+ {extern void _initialize_kernel_u_addr (); _initialize_kernel_u_addr ();}
+ {extern void _initialize_inftarg (); _initialize_inftarg ();}
+ {extern void _initialize_corelow (); _initialize_corelow ();}
+#ifdef KERNEL_DEBUG
+ {extern void _initialize_kcorelow (); _initialize_kcorelow ();}
+#endif
+ {extern void _initialize_remote (); _initialize_remote ();}
+ {extern void _initialize_sr_support (); _initialize_sr_support ();}
+ {extern void _initialize_targets (); _initialize_targets ();}
+ {extern void _initialize_parse (); _initialize_parse ();}
+ {extern void _initialize_language (); _initialize_language ();}
+ {extern void _initialize_buildsym (); _initialize_buildsym ();}
+ {extern void _initialize_maint_cmds (); _initialize_maint_cmds ();}
+ {extern void _initialize_demangler (); _initialize_demangler ();}
+ {extern void _initialize_dbxread (); _initialize_dbxread ();}
+ {extern void _initialize_coffread (); _initialize_coffread ();}
+ {extern void _initialize_elfread (); _initialize_elfread ();}
+ {extern void _initialize_stabsread (); _initialize_stabsread ();}
+ {extern void _initialize_core (); _initialize_core ();}
+ {extern void _initialize_c_language (); _initialize_c_language ();}
+ {extern void _initialize_chill_language (); _initialize_chill_language ();}
+ {extern void _initialize_m2_language (); _initialize_m2_language ();}
+ {extern void _initialize_complaints (); _initialize_complaints ();}
+ {extern void _initialize_typeprint (); _initialize_typeprint ();}
+ {extern void _initialize_cp_valprint (); _initialize_cp_valprint ();}
+ {extern void _initialize_serial (); _initialize_serial ();}
+ {extern void _initialize_mdebugread (); _initialize_mdebugread ();}
+ {extern void _initialize_utils (); _initialize_utils ();}
+ {extern void _initialize_inflow (); _initialize_inflow ();}
+}
diff --git a/gnu/usr.bin/gdb/gdb/kcorelow.c b/gnu/usr.bin/gdb/gdb/kcorelow.c
new file mode 100644
index 0000000..e08c486
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/kcorelow.c
@@ -0,0 +1,363 @@
+/* Core dump and executable file functions below target vector, for GDB.
+ Copyright 1986, 1987, 1989, 1991, 1992 Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ $Id: kcorelow.c,v 1.3 1995/04/26 01:01:09 jkh Exp $
+*/
+
+#include "defs.h"
+
+#ifdef KERNEL_DEBUG
+
+#include <errno.h>
+#include <signal.h>
+#include <fcntl.h>
+#include <sys/param.h>
+#include <sys/time.h>
+#include <sys/proc.h>
+#include <sys/user.h>
+#include "frame.h" /* required by inferior.h */
+#include "inferior.h"
+#include "symtab.h"
+#include "command.h"
+#include "bfd.h"
+#include "target.h"
+#include "gdbcore.h"
+
+static void
+kcore_files_info PARAMS ((struct target_ops *));
+
+static void
+kcore_close PARAMS ((int));
+
+static void
+get_kcore_registers PARAMS ((int));
+
+static int
+xfer_mem PARAMS ((CORE_ADDR, char *, int, int, struct target_ops *));
+
+static int
+xfer_umem PARAMS ((CORE_ADDR, char *, int, int));
+
+static char *core_file;
+static int core_kd = -1;
+static struct proc *cur_proc;
+static CORE_ADDR kernel_start;
+
+/*
+ * Read the "thing" at kernel address 'addr' into the space pointed to
+ * by point. The length of the "thing" is determined by the type of p.
+ * Result is non-zero if transfer fails.
+ */
+#define kvread(addr, p) \
+ (target_read_memory((CORE_ADDR)(addr), (char *)(p), sizeof(*(p))))
+
+extern read_pcb (int, CORE_ADDR);
+
+CORE_ADDR
+ksym_lookup(name)
+const char *name;
+{
+ struct minimal_symbol *sym;
+
+ sym = lookup_minimal_symbol(name, (struct objfile *)NULL);
+ if (sym == NULL)
+ error("kernel symbol `%s' not found.", name);
+
+ return SYMBOL_VALUE_ADDRESS(sym);
+}
+
+static struct proc *
+curProc()
+{
+ struct proc *p;
+ CORE_ADDR addr = ksym_lookup("curproc");
+
+ if (kvread(addr, &p))
+ error("cannot read proc pointer at %x\n", addr);
+ return p;
+}
+
+/*
+ * Set the process context to that of the proc structure at
+ * system address paddr.
+ */
+static int
+set_proc_context(paddr)
+ CORE_ADDR paddr;
+{
+ struct proc p;
+
+ if (paddr < kernel_start)
+ return (1);
+
+ cur_proc = (struct proc *)paddr;
+#ifdef notyet
+ set_kernel_boundaries(cur_proc);
+#endif
+
+ /* Fetch all registers from core file */
+ target_fetch_registers (-1);
+
+ /* Now, set up the frame cache, and print the top of stack */
+ flush_cached_frames();
+ set_current_frame (create_new_frame (read_fp (), read_pc ()));
+ select_frame (get_current_frame (), 0);
+ return (0);
+}
+
+/* Discard all vestiges of any previous core file
+ and mark data and stack spaces as empty. */
+
+/* ARGSUSED */
+static void
+kcore_close (quitting)
+ int quitting;
+{
+ inferior_pid = 0; /* Avoid confusion from thread stuff */
+
+ if (core_kd) {
+ kvm_close(core_kd);
+ free(core_file);
+ core_file = NULL;
+ core_kd = -1;
+ }
+}
+
+/* This routine opens and sets up the core file bfd */
+
+void
+kcore_open (filename, from_tty)
+ char *filename;
+ int from_tty;
+{
+ const char *p;
+ struct cleanup *old_chain;
+ char buf[256], *cp;
+ int ontop;
+ CORE_ADDR addr;
+ struct pcb pcb;
+
+ target_preopen (from_tty);
+ if (!filename) {
+ /*error (core_kd?*/
+ error ((core_kd >= 0)?
+ "No core file specified. (Use `detach' to stop debugging a core file.)"
+ : "No core file specified.");
+ }
+
+ filename = tilde_expand (filename);
+ if (filename[0] != '/') {
+ cp = concat (current_directory, "/", filename, NULL);
+ free (filename);
+ filename = cp;
+ }
+
+ old_chain = make_cleanup (free, filename);
+
+ /*
+ * gdb doesn't really do anything if the exec-file couldn't
+ * be opened (in that case exec_bfd is NULL). Usually that's
+ * no big deal, but kvm_open needs the exec-file's name,
+ * which results in dereferencing a NULL pointer, a real NO-NO !
+ * So, check here if the open of the exec-file succeeded.
+ */
+ if (exec_bfd == NULL) /* the open failed */
+ error ("kgdb could not open the exec-file, please check the name you used !");
+
+ core_kd = kvm_open (exec_bfd->filename, filename, NULL,
+ kernel_writablecore? O_RDWR: O_RDONLY, "kgdb: ");
+ if (core_kd < 0)
+ perror_with_name (filename);
+
+ /* Looks semi-reasonable. Toss the old core file and work on the new. */
+
+ discard_cleanups (old_chain); /* Don't free filename any more */
+ core_file = filename;
+ unpush_target (&kcore_ops);
+ ontop = !push_target (&kcore_ops);
+
+ kernel_start = bfd_get_start_address (exec_bfd); /* XXX */
+
+ /* print out the panic string if there is one */
+ if (kvread(ksym_lookup("panicstr"), &addr) == 0 &&
+ addr != 0 &&
+ target_read_memory(addr, buf, sizeof(buf)) == 0) {
+
+ for (cp = buf; cp < &buf[sizeof(buf)] && *cp; cp++)
+ if (!isascii(*cp) || (!isprint(*cp) && !isspace(*cp)))
+ *cp = '?';
+ *cp = '\0';
+ if (buf[0] != '\0')
+ printf("panic: %s\n", buf);
+ }
+
+ if (!ontop) {
+ warning (
+"you won't be able to access this core file until you terminate\n\
+your %s; do ``info files''", current_target->to_longname);
+ return;
+ }
+
+ /* we may need this later */
+ cur_proc = (struct proc *)curProc();
+ /* Now, set up the frame cache, and print the top of stack */
+ flush_cached_frames();
+ set_current_frame (create_new_frame (read_fp (), read_pc ()));
+ select_frame (get_current_frame (), 0);
+ print_stack_frame (selected_frame, selected_frame_level, 1);
+}
+
+void
+kcore_detach (args, from_tty)
+ char *args;
+ int from_tty;
+{
+ if (args)
+ error ("Too many arguments");
+ unpush_target (&kcore_ops);
+ reinit_frame_cache ();
+ if (from_tty)
+ printf_filtered ("No kernel core file now.\n");
+}
+
+/* Get the registers out of a core file. This is the machine-
+ independent part. Fetch_core_registers is the machine-dependent
+ part, typically implemented in the xm-file for each architecture. */
+
+/* We just get all the registers, so we don't use regno. */
+/* ARGSUSED */
+static void
+get_kcore_registers (regno)
+ int regno;
+{
+ struct user *uaddr;
+
+ /* find the pcb for the current process */
+ if (kvread(&cur_proc->p_addr, &uaddr))
+ error("cannot read u area ptr for proc at %#x", cur_proc);
+ if (read_pcb (core_kd, (CORE_ADDR)&uaddr->u_pcb) < 0)
+ error("cannot read pcb at %#x", &uaddr->u_pcb);
+}
+
+/* If mourn is being called in all the right places, this could be say
+ `gdb internal error' (since generic_mourn calls breakpoint_init_inferior). */
+
+static int
+ignore (addr, contents)
+ CORE_ADDR addr;
+ char *contents;
+{
+ return 0;
+}
+
+static void
+kcore_files_info (t)
+ struct target_ops *t;
+{
+ printf("\t`%s'\n", core_file);
+}
+
+static int
+xfer_kmem (memaddr, myaddr, len, write, target)
+ CORE_ADDR memaddr;
+ char *myaddr;
+ int len;
+ int write;
+ struct target_ops *target;
+{
+ int n;
+
+ if (!memaddr)
+ return (0);
+
+ if (memaddr < kernel_start)
+ return xfer_umem(memaddr, myaddr, len, write);
+
+ n = write ?
+ kvm_write(core_kd, memaddr, myaddr, len) :
+ kvm_read(core_kd, memaddr, myaddr, len) ;
+
+ if (n < 0)
+ return 0;
+ return n;
+}
+
+static int
+xfer_umem (memaddr, myaddr, len, write)
+ CORE_ADDR memaddr;
+ char *myaddr;
+ int len;
+ int write; /* ignored */
+{
+ int n;
+ struct proc proc;
+
+ if (kvread(cur_proc, &proc))
+ error("cannot read proc at %#x", cur_proc);
+ n = kvm_uread(core_kd, &proc, memaddr, myaddr, len) ;
+
+ if (n < 0)
+ return 0;
+ return n;
+}
+
+static void
+set_proc_cmd(arg)
+ char *arg;
+{
+ CORE_ADDR paddr;
+
+ if (!arg)
+ error_no_arg("proc address for new current process");
+ if (!kernel_debugging)
+ error("not debugging kernel");
+
+ paddr = (CORE_ADDR)parse_and_eval_address(arg);
+ if (set_proc_context(paddr))
+ error("invalid proc address");
+}
+
+struct target_ops kcore_ops = {
+ "kcore", "Kernel core dump file",
+ "Use a core file as a target. Specify the filename of the core file.",
+ kcore_open, kcore_close,
+ find_default_attach, kcore_detach, 0, 0, /* resume, wait */
+ get_kcore_registers,
+ 0, 0, /* store_regs, prepare_to_store */
+ xfer_kmem, kcore_files_info,
+ ignore, ignore, /* core_insert_breakpoint, core_remove_breakpoint, */
+ 0, 0, 0, 0, 0, /* terminal stuff */
+ 0, 0, 0, /* kill, load, lookup sym */
+ find_default_create_inferior, 0, /* mourn_inferior */
+ 0, /* can_run */
+ 0, /* notice_signals */
+ kcore_stratum, 0, /* next */
+ 0, 1, 1, 1, 0, /* all mem, mem, stack, regs, exec */
+ 0, 0, /* section pointers */
+ OPS_MAGIC, /* Always the last thing */
+};
+
+void
+_initialize_kcorelow()
+{
+ add_target (&kcore_ops);
+ add_com ("proc", class_obscure, set_proc_cmd, "Set current process context");
+}
+
+#endif /* KERNEL_DEBUG */
diff --git a/gnu/usr.bin/gdb/gdb/language.c b/gnu/usr.bin/gdb/gdb/language.c
new file mode 100644
index 0000000..6d254fb
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/language.c
@@ -0,0 +1,1311 @@
+/* Multiple source language support for GDB.
+ Copyright 1991, 1992 Free Software Foundation, Inc.
+ Contributed by the Department of Computer Science at the State University
+ of New York at Buffalo.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* This file contains functions that return things that are specific
+ to languages. Each function should examine current_language if necessary,
+ and return the appropriate result. */
+
+/* FIXME: Most of these would be better organized as macros which
+ return data out of a "language-specific" struct pointer that is set
+ whenever the working language changes. That would be a lot faster. */
+
+#include "defs.h"
+#include <string.h>
+#include <varargs.h>
+
+#include "symtab.h"
+#include "gdbtypes.h"
+#include "value.h"
+#include "gdbcmd.h"
+#include "frame.h"
+#include "expression.h"
+#include "language.h"
+#include "target.h"
+#include "parser-defs.h"
+
+static void
+show_language_command PARAMS ((char *, int));
+
+static void
+set_language_command PARAMS ((char *, int));
+
+static void
+show_type_command PARAMS ((char *, int));
+
+static void
+set_type_command PARAMS ((char *, int));
+
+static void
+show_range_command PARAMS ((char *, int));
+
+static void
+set_range_command PARAMS ((char *, int));
+
+static void
+set_range_str PARAMS ((void));
+
+static void
+set_type_str PARAMS ((void));
+
+static void
+set_lang_str PARAMS ((void));
+
+static void
+unk_lang_error PARAMS ((char *));
+
+static int
+unk_lang_parser PARAMS ((void));
+
+static void
+show_check PARAMS ((char *, int));
+
+static void
+set_check PARAMS ((char *, int));
+
+static void
+set_type_range PARAMS ((void));
+
+/* Forward declaration */
+extern const struct language_defn unknown_language_defn;
+extern char *warning_pre_print;
+
+/* The current (default at startup) state of type and range checking.
+ (If the modes are set to "auto", though, these are changed based
+ on the default language at startup, and then again based on the
+ language of the first source file. */
+
+enum range_mode range_mode = range_mode_auto;
+enum range_check range_check = range_check_off;
+enum type_mode type_mode = type_mode_auto;
+enum type_check type_check = type_check_off;
+
+/* The current language and language_mode (see language.h) */
+
+const struct language_defn *current_language = &unknown_language_defn;
+enum language_mode language_mode = language_mode_auto;
+
+/* The language that the user expects to be typing in (the language
+ of main(), or the last language we notified them about, or C). */
+
+const struct language_defn *expected_language;
+
+/* The list of supported languages. The list itself is malloc'd. */
+
+static const struct language_defn **languages;
+static unsigned languages_size;
+static unsigned languages_allocsize;
+#define DEFAULT_ALLOCSIZE 4
+
+/* The "set language/type/range" commands all put stuff in these
+ buffers. This is to make them work as set/show commands. The
+ user's string is copied here, then the set_* commands look at
+ them and update them to something that looks nice when it is
+ printed out. */
+
+static char *language;
+static char *type;
+static char *range;
+
+/* Warning issued when current_language and the language of the current
+ frame do not match. */
+char lang_frame_mismatch_warn[] =
+ "Warning: the current language does not match this frame.";
+
+
+/* This page contains the functions corresponding to GDB commands
+ and their helpers. */
+
+/* Show command. Display a warning if the language set
+ does not match the frame. */
+static void
+show_language_command (ignore, from_tty)
+ char *ignore;
+ int from_tty;
+{
+ enum language flang; /* The language of the current frame */
+
+ flang = get_frame_language();
+ if (flang != language_unknown &&
+ language_mode == language_mode_manual &&
+ current_language->la_language != flang)
+ printf_filtered("%s\n",lang_frame_mismatch_warn);
+}
+
+/* Set command. Change the current working language. */
+static void
+set_language_command (ignore, from_tty)
+ char *ignore;
+ int from_tty;
+{
+ int i;
+ enum language flang;
+ char *err_lang;
+
+ /* FIXME -- do this from the list, with HELP. */
+ if (!language || !language[0]) {
+ printf_unfiltered("The currently understood settings are:\n\n");
+ printf_unfiltered ("local or auto Automatic setting based on source file\n");
+ printf_unfiltered ("c Use the C language\n");
+ printf_unfiltered ("c++ Use the C++ language\n");
+ printf_unfiltered ("chill Use the Chill language\n");
+ printf_unfiltered ("modula-2 Use the Modula-2 language\n");
+ /* Restore the silly string. */
+ set_language(current_language->la_language);
+ return;
+ }
+
+ /* Search the list of languages for a match. */
+ for (i = 0; i < languages_size; i++) {
+ if (STREQ (languages[i]->la_name, language)) {
+ /* Found it! Go into manual mode, and use this language. */
+ if (languages[i]->la_language == language_auto) {
+ /* Enter auto mode. Set to the current frame's language, if known. */
+ language_mode = language_mode_auto;
+ flang = get_frame_language();
+ if (flang!=language_unknown)
+ set_language(flang);
+ expected_language = current_language;
+ return;
+ } else {
+ /* Enter manual mode. Set the specified language. */
+ language_mode = language_mode_manual;
+ current_language = languages[i];
+ set_type_range ();
+ set_lang_str();
+ expected_language = current_language;
+ return;
+ }
+ }
+ }
+
+ /* Reset the language (esp. the global string "language") to the
+ correct values. */
+ err_lang=savestring(language,strlen(language));
+ make_cleanup (free, err_lang); /* Free it after error */
+ set_language(current_language->la_language);
+ error ("Unknown language `%s'.",err_lang);
+}
+
+/* Show command. Display a warning if the type setting does
+ not match the current language. */
+static void
+show_type_command(ignore, from_tty)
+ char *ignore;
+ int from_tty;
+{
+ if (type_check != current_language->la_type_check)
+ printf_unfiltered(
+"Warning: the current type check setting does not match the language.\n");
+}
+
+/* Set command. Change the setting for type checking. */
+static void
+set_type_command(ignore, from_tty)
+ char *ignore;
+ int from_tty;
+{
+ if (STREQ(type,"on"))
+ {
+ type_check = type_check_on;
+ type_mode = type_mode_manual;
+ }
+ else if (STREQ(type,"warn"))
+ {
+ type_check = type_check_warn;
+ type_mode = type_mode_manual;
+ }
+ else if (STREQ(type,"off"))
+ {
+ type_check = type_check_off;
+ type_mode = type_mode_manual;
+ }
+ else if (STREQ(type,"auto"))
+ {
+ type_mode = type_mode_auto;
+ set_type_range();
+ /* Avoid hitting the set_type_str call below. We
+ did it in set_type_range. */
+ return;
+ }
+ set_type_str();
+ show_type_command((char *)NULL, from_tty);
+}
+
+/* Show command. Display a warning if the range setting does
+ not match the current language. */
+static void
+show_range_command(ignore, from_tty)
+ char *ignore;
+ int from_tty;
+{
+
+ if (range_check != current_language->la_range_check)
+ printf_unfiltered(
+"Warning: the current range check setting does not match the language.\n");
+}
+
+/* Set command. Change the setting for range checking. */
+static void
+set_range_command(ignore, from_tty)
+ char *ignore;
+ int from_tty;
+{
+ if (STREQ(range,"on"))
+ {
+ range_check = range_check_on;
+ range_mode = range_mode_manual;
+ }
+ else if (STREQ(range,"warn"))
+ {
+ range_check = range_check_warn;
+ range_mode = range_mode_manual;
+ }
+ else if (STREQ(range,"off"))
+ {
+ range_check = range_check_off;
+ range_mode = range_mode_manual;
+ }
+ else if (STREQ(range,"auto"))
+ {
+ range_mode = range_mode_auto;
+ set_type_range();
+ /* Avoid hitting the set_range_str call below. We
+ did it in set_type_range. */
+ return;
+ }
+ set_range_str();
+ show_range_command((char *)0, from_tty);
+}
+
+/* Set the status of range and type checking based on
+ the current modes and the current language.
+ If SHOW is non-zero, then print out the current language,
+ type and range checking status. */
+static void
+set_type_range()
+{
+
+ if (range_mode == range_mode_auto)
+ range_check = current_language->la_range_check;
+
+ if (type_mode == type_mode_auto)
+ type_check = current_language->la_type_check;
+
+ set_type_str();
+ set_range_str();
+}
+
+/* Set current language to (enum language) LANG. */
+
+void
+set_language(lang)
+ enum language lang;
+{
+ int i;
+
+ for (i = 0; i < languages_size; i++) {
+ if (languages[i]->la_language == lang) {
+ current_language = languages[i];
+ set_type_range ();
+ set_lang_str();
+ break;
+ }
+ }
+}
+
+/* This page contains functions that update the global vars
+ language, type and range. */
+static void
+set_lang_str()
+{
+ char *prefix = "";
+
+ free (language);
+ if (language_mode == language_mode_auto)
+ prefix = "auto; currently ";
+
+ language = concat(prefix, current_language->la_name, NULL);
+}
+
+static void
+set_type_str()
+{
+ char *tmp, *prefix = "";
+
+ free (type);
+ if (type_mode==type_mode_auto)
+ prefix = "auto; currently ";
+
+ switch(type_check)
+ {
+ case type_check_on:
+ tmp = "on";
+ break;
+ case type_check_off:
+ tmp = "off";
+ break;
+ case type_check_warn:
+ tmp = "warn";
+ break;
+ default:
+ error ("Unrecognized type check setting.");
+ }
+
+ type = concat(prefix,tmp,NULL);
+}
+
+static void
+set_range_str()
+{
+ char *tmp, *pref = "";
+
+ free (range);
+ if (range_mode==range_mode_auto)
+ pref = "auto; currently ";
+
+ switch(range_check)
+ {
+ case range_check_on:
+ tmp = "on";
+ break;
+ case range_check_off:
+ tmp = "off";
+ break;
+ case range_check_warn:
+ tmp = "warn";
+ break;
+ default:
+ error ("Unrecognized range check setting.");
+ }
+
+ range = concat(pref,tmp,NULL);
+}
+
+
+/* Print out the current language settings: language, range and
+ type checking. If QUIETLY, print only what has changed. */
+
+void
+language_info (quietly)
+ int quietly;
+{
+ if (quietly && expected_language == current_language)
+ return;
+
+ expected_language = current_language;
+ printf_unfiltered("Current language: %s\n",language);
+ show_language_command((char *)0, 1);
+
+ if (!quietly)
+ {
+ printf_unfiltered("Type checking: %s\n",type);
+ show_type_command((char *)0, 1);
+ printf_unfiltered("Range checking: %s\n",range);
+ show_range_command((char *)0, 1);
+ }
+}
+
+/* Return the result of a binary operation. */
+
+#if 0 /* Currently unused */
+
+struct type *
+binop_result_type (v1, v2)
+ value_ptr v1, v2;
+{
+ int l1,l2,size,uns;
+
+ l1 = TYPE_LENGTH(VALUE_TYPE(v1));
+ l2 = TYPE_LENGTH(VALUE_TYPE(v2));
+
+ switch(current_language->la_language)
+ {
+ case language_c:
+ case language_cplus:
+ if (TYPE_CODE(VALUE_TYPE(v1))==TYPE_CODE_FLT)
+ return TYPE_CODE(VALUE_TYPE(v2)) == TYPE_CODE_FLT && l2 > l1 ?
+ VALUE_TYPE(v2) : VALUE_TYPE(v1);
+ else if (TYPE_CODE(VALUE_TYPE(v2))==TYPE_CODE_FLT)
+ return TYPE_CODE(VALUE_TYPE(v1)) == TYPE_CODE_FLT && l1 > l2 ?
+ VALUE_TYPE(v1) : VALUE_TYPE(v2);
+ else if (TYPE_UNSIGNED(VALUE_TYPE(v1)) && l1 > l2)
+ return VALUE_TYPE(v1);
+ else if (TYPE_UNSIGNED(VALUE_TYPE(v2)) && l2 > l1)
+ return VALUE_TYPE(v2);
+ else /* Both are signed. Result is the longer type */
+ return l1 > l2 ? VALUE_TYPE(v1) : VALUE_TYPE(v2);
+ break;
+ case language_m2:
+ /* If we are doing type-checking, l1 should equal l2, so this is
+ not needed. */
+ return l1 > l2 ? VALUE_TYPE(v1) : VALUE_TYPE(v2);
+ break;
+ case language_chill:
+ error ("Missing Chill support in function binop_result_check.");/*FIXME*/
+ }
+ abort();
+ return (struct type *)0; /* For lint */
+}
+
+#endif /* 0 */
+
+
+/* This page contains functions that return format strings for
+ printf for printing out numbers in different formats */
+
+/* Returns the appropriate printf format for hexadecimal
+ numbers. */
+char *
+local_hex_format_custom(pre)
+ char *pre;
+{
+ static char form[50];
+
+ strcpy (form, local_hex_format_prefix ());
+ strcat (form, "%");
+ strcat (form, pre);
+ strcat (form, local_hex_format_specifier ());
+ strcat (form, local_hex_format_suffix ());
+ return form;
+}
+
+/* Converts a number to hexadecimal and stores it in a static
+ string. Returns a pointer to this string. */
+char *
+local_hex_string (num)
+ unsigned long num;
+{
+ static char res[50];
+
+ sprintf (res, local_hex_format(), num);
+ return res;
+}
+
+/* Converts a number to custom hexadecimal and stores it in a static
+ string. Returns a pointer to this string. */
+char *
+local_hex_string_custom(num,pre)
+ unsigned long num;
+ char *pre;
+{
+ static char res[50];
+
+ sprintf (res, local_hex_format_custom(pre), num);
+ return res;
+}
+
+/* Returns the appropriate printf format for octal
+ numbers. */
+char *
+local_octal_format_custom(pre)
+ char *pre;
+{
+ static char form[50];
+
+ strcpy (form, local_octal_format_prefix ());
+ strcat (form, "%");
+ strcat (form, pre);
+ strcat (form, local_octal_format_specifier ());
+ strcat (form, local_octal_format_suffix ());
+ return form;
+}
+
+/* Returns the appropriate printf format for decimal numbers. */
+char *
+local_decimal_format_custom(pre)
+ char *pre;
+{
+ static char form[50];
+
+ strcpy (form, local_decimal_format_prefix ());
+ strcat (form, "%");
+ strcat (form, pre);
+ strcat (form, local_decimal_format_specifier ());
+ strcat (form, local_decimal_format_suffix ());
+ return form;
+}
+
+/* This page contains functions that are used in type/range checking.
+ They all return zero if the type/range check fails.
+
+ It is hoped that these will make extending GDB to parse different
+ languages a little easier. These are primarily used in eval.c when
+ evaluating expressions and making sure that their types are correct.
+ Instead of having a mess of conjucted/disjuncted expressions in an "if",
+ the ideas of type can be wrapped up in the following functions.
+
+ Note that some of them are not currently dependent upon which language
+ is currently being parsed. For example, floats are the same in
+ C and Modula-2 (ie. the only floating point type has TYPE_CODE of
+ TYPE_CODE_FLT), while booleans are different. */
+
+/* Returns non-zero if its argument is a simple type. This is the same for
+ both Modula-2 and for C. In the C case, TYPE_CODE_CHAR will never occur,
+ and thus will never cause the failure of the test. */
+int
+simple_type(type)
+ struct type *type;
+{
+ switch (TYPE_CODE (type)) {
+ case TYPE_CODE_INT:
+ case TYPE_CODE_CHAR:
+ case TYPE_CODE_ENUM:
+ case TYPE_CODE_FLT:
+ case TYPE_CODE_RANGE:
+ case TYPE_CODE_BOOL:
+ return 1;
+
+ default:
+ return 0;
+ }
+}
+
+/* Returns non-zero if its argument is of an ordered type.
+ An ordered type is one in which the elements can be tested for the
+ properties of "greater than", "less than", etc, or for which the
+ operations "increment" or "decrement" make sense. */
+int
+ordered_type (type)
+ struct type *type;
+{
+ switch (TYPE_CODE (type)) {
+ case TYPE_CODE_INT:
+ case TYPE_CODE_CHAR:
+ case TYPE_CODE_ENUM:
+ case TYPE_CODE_FLT:
+ case TYPE_CODE_RANGE:
+ return 1;
+
+ default:
+ return 0;
+ }
+}
+
+/* Returns non-zero if the two types are the same */
+int
+same_type (arg1, arg2)
+ struct type *arg1, *arg2;
+{
+ if (structured_type(arg1) ? !structured_type(arg2) : structured_type(arg2))
+ /* One is structured and one isn't */
+ return 0;
+ else if (structured_type(arg1) && structured_type(arg2))
+ return arg1 == arg2;
+ else if (numeric_type(arg1) && numeric_type(arg2))
+ return (TYPE_CODE(arg2) == TYPE_CODE(arg1)) &&
+ (TYPE_UNSIGNED(arg1) == TYPE_UNSIGNED(arg2))
+ ? 1 : 0;
+ else
+ return arg1==arg2;
+}
+
+/* Returns non-zero if the type is integral */
+int
+integral_type (type)
+ struct type *type;
+{
+ switch(current_language->la_language)
+ {
+ case language_c:
+ case language_cplus:
+ return (TYPE_CODE(type) != TYPE_CODE_INT) &&
+ (TYPE_CODE(type) != TYPE_CODE_ENUM) ? 0 : 1;
+ case language_m2:
+ return TYPE_CODE(type) != TYPE_CODE_INT ? 0 : 1;
+ case language_chill:
+ error ("Missing Chill support in function integral_type."); /*FIXME*/
+ default:
+ error ("Language not supported.");
+ }
+}
+
+/* Returns non-zero if the value is numeric */
+int
+numeric_type (type)
+ struct type *type;
+{
+ switch (TYPE_CODE (type)) {
+ case TYPE_CODE_INT:
+ case TYPE_CODE_FLT:
+ return 1;
+
+ default:
+ return 0;
+ }
+}
+
+/* Returns non-zero if the value is a character type */
+int
+character_type (type)
+ struct type *type;
+{
+ switch(current_language->la_language)
+ {
+ case language_chill:
+ case language_m2:
+ return TYPE_CODE(type) != TYPE_CODE_CHAR ? 0 : 1;
+
+ case language_c:
+ case language_cplus:
+ return (TYPE_CODE(type) == TYPE_CODE_INT) &&
+ TYPE_LENGTH(type) == sizeof(char)
+ ? 1 : 0;
+ default:
+ return (0);
+ }
+}
+
+/* Returns non-zero if the value is a string type */
+int
+string_type (type)
+ struct type *type;
+{
+ switch(current_language->la_language)
+ {
+ case language_chill:
+ case language_m2:
+ return TYPE_CODE(type) != TYPE_CODE_STRING ? 0 : 1;
+
+ case language_c:
+ case language_cplus:
+ /* C does not have distinct string type. */
+ return (0);
+ default:
+ return (0);
+ }
+}
+
+/* Returns non-zero if the value is a boolean type */
+int
+boolean_type (type)
+ struct type *type;
+{
+ if (TYPE_CODE (type) == TYPE_CODE_BOOL)
+ return 1;
+ switch(current_language->la_language)
+ {
+ case language_c:
+ case language_cplus:
+ /* Might be more cleanly handled by having a TYPE_CODE_INT_NOT_BOOL
+ for CHILL and such languages, or a TYPE_CODE_INT_OR_BOOL for C. */
+ if (TYPE_CODE (type) == TYPE_CODE_INT)
+ return 1;
+ default:
+ break;
+ }
+ return 0;
+}
+
+/* Returns non-zero if the value is a floating-point type */
+int
+float_type (type)
+ struct type *type;
+{
+ return TYPE_CODE(type) == TYPE_CODE_FLT;
+}
+
+/* Returns non-zero if the value is a pointer type */
+int
+pointer_type(type)
+ struct type *type;
+{
+ return TYPE_CODE(type) == TYPE_CODE_PTR ||
+ TYPE_CODE(type) == TYPE_CODE_REF;
+}
+
+/* Returns non-zero if the value is a structured type */
+int
+structured_type(type)
+ struct type *type;
+{
+ switch(current_language->la_language)
+ {
+ case language_c:
+ case language_cplus:
+ return (TYPE_CODE(type) == TYPE_CODE_STRUCT) ||
+ (TYPE_CODE(type) == TYPE_CODE_UNION) ||
+ (TYPE_CODE(type) == TYPE_CODE_ARRAY);
+ case language_m2:
+ return (TYPE_CODE(type) == TYPE_CODE_STRUCT) ||
+ (TYPE_CODE(type) == TYPE_CODE_SET) ||
+ (TYPE_CODE(type) == TYPE_CODE_ARRAY);
+ case language_chill:
+ error ("Missing Chill support in function structured_type."); /*FIXME*/
+ default:
+ return (0);
+ }
+}
+
+/* This page contains functions that return info about
+ (struct value) values used in GDB. */
+
+/* Returns non-zero if the value VAL represents a true value. */
+int
+value_true (val)
+ value_ptr val;
+{
+ /* It is possible that we should have some sort of error if a non-boolean
+ value is used in this context. Possibly dependent on some kind of
+ "boolean-checking" option like range checking. But it should probably
+ not depend on the language except insofar as is necessary to identify
+ a "boolean" value (i.e. in C using a float, pointer, etc., as a boolean
+ should be an error, probably). */
+ return !value_logical_not (val);
+}
+
+/* Returns non-zero if the operator OP is defined on
+ the values ARG1 and ARG2. */
+
+#if 0 /* Currently unused */
+
+void
+binop_type_check(arg1,arg2,op)
+ value_ptr arg1,arg2;
+ int op;
+{
+ struct type *t1, *t2;
+
+ /* If we're not checking types, always return success. */
+ if (!STRICT_TYPE)
+ return;
+
+ t1=VALUE_TYPE(arg1);
+ if (arg2 != NULL)
+ t2=VALUE_TYPE(arg2);
+ else
+ t2=NULL;
+
+ switch(op)
+ {
+ case BINOP_ADD:
+ case BINOP_SUB:
+ if ((numeric_type(t1) && pointer_type(t2)) ||
+ (pointer_type(t1) && numeric_type(t2)))
+ {
+ warning ("combining pointer and integer.\n");
+ break;
+ }
+ case BINOP_MUL:
+ case BINOP_LSH:
+ case BINOP_RSH:
+ if (!numeric_type(t1) || !numeric_type(t2))
+ type_op_error ("Arguments to %s must be numbers.",op);
+ else if (!same_type(t1,t2))
+ type_op_error ("Arguments to %s must be of the same type.",op);
+ break;
+
+ case BINOP_LOGICAL_AND:
+ case BINOP_LOGICAL_OR:
+ if (!boolean_type(t1) || !boolean_type(t2))
+ type_op_error ("Arguments to %s must be of boolean type.",op);
+ break;
+
+ case BINOP_EQUAL:
+ if ((pointer_type(t1) && !(pointer_type(t2) || integral_type(t2))) ||
+ (pointer_type(t2) && !(pointer_type(t1) || integral_type(t1))))
+ type_op_error ("A pointer can only be compared to an integer or pointer.",op);
+ else if ((pointer_type(t1) && integral_type(t2)) ||
+ (integral_type(t1) && pointer_type(t2)))
+ {
+ warning ("combining integer and pointer.\n");
+ break;
+ }
+ else if (!simple_type(t1) || !simple_type(t2))
+ type_op_error ("Arguments to %s must be of simple type.",op);
+ else if (!same_type(t1,t2))
+ type_op_error ("Arguments to %s must be of the same type.",op);
+ break;
+
+ case BINOP_REM:
+ case BINOP_MOD:
+ if (!integral_type(t1) || !integral_type(t2))
+ type_op_error ("Arguments to %s must be of integral type.",op);
+ break;
+
+ case BINOP_LESS:
+ case BINOP_GTR:
+ case BINOP_LEQ:
+ case BINOP_GEQ:
+ if (!ordered_type(t1) || !ordered_type(t2))
+ type_op_error ("Arguments to %s must be of ordered type.",op);
+ else if (!same_type(t1,t2))
+ type_op_error ("Arguments to %s must be of the same type.",op);
+ break;
+
+ case BINOP_ASSIGN:
+ if (pointer_type(t1) && !integral_type(t2))
+ type_op_error ("A pointer can only be assigned an integer.",op);
+ else if (pointer_type(t1) && integral_type(t2))
+ {
+ warning ("combining integer and pointer.");
+ break;
+ }
+ else if (!simple_type(t1) || !simple_type(t2))
+ type_op_error ("Arguments to %s must be of simple type.",op);
+ else if (!same_type(t1,t2))
+ type_op_error ("Arguments to %s must be of the same type.",op);
+ break;
+
+ case BINOP_CONCAT:
+ /* FIXME: Needs to handle bitstrings as well. */
+ if (!(string_type(t1) || character_type(t1) || integral_type(t1))
+ || !(string_type(t2) || character_type(t2) || integral_type(t2)))
+ type_op_error ("Arguments to %s must be strings or characters.", op);
+ break;
+
+ /* Unary checks -- arg2 is null */
+
+ case UNOP_LOGICAL_NOT:
+ if (!boolean_type(t1))
+ type_op_error ("Argument to %s must be of boolean type.",op);
+ break;
+
+ case UNOP_PLUS:
+ case UNOP_NEG:
+ if (!numeric_type(t1))
+ type_op_error ("Argument to %s must be of numeric type.",op);
+ break;
+
+ case UNOP_IND:
+ if (integral_type(t1))
+ {
+ warning ("combining pointer and integer.\n");
+ break;
+ }
+ else if (!pointer_type(t1))
+ type_op_error ("Argument to %s must be a pointer.",op);
+ break;
+
+ case UNOP_PREINCREMENT:
+ case UNOP_POSTINCREMENT:
+ case UNOP_PREDECREMENT:
+ case UNOP_POSTDECREMENT:
+ if (!ordered_type(t1))
+ type_op_error ("Argument to %s must be of an ordered type.",op);
+ break;
+
+ default:
+ /* Ok. The following operators have different meanings in
+ different languages. */
+ switch(current_language->la_language)
+ {
+#ifdef _LANG_c
+ case language_c:
+ case language_cplus:
+ switch(op)
+ {
+ case BINOP_DIV:
+ if (!numeric_type(t1) || !numeric_type(t2))
+ type_op_error ("Arguments to %s must be numbers.",op);
+ break;
+ }
+ break;
+#endif
+
+#ifdef _LANG_m2
+ case language_m2:
+ switch(op)
+ {
+ case BINOP_DIV:
+ if (!float_type(t1) || !float_type(t2))
+ type_op_error ("Arguments to %s must be floating point numbers.",op);
+ break;
+ case BINOP_INTDIV:
+ if (!integral_type(t1) || !integral_type(t2))
+ type_op_error ("Arguments to %s must be of integral type.",op);
+ break;
+ }
+#endif
+
+#ifdef _LANG_chill
+ case language_chill:
+ error ("Missing Chill support in function binop_type_check.");/*FIXME*/
+#endif
+
+ }
+ }
+}
+
+#endif /* 0 */
+
+
+/* This page contains functions for the printing out of
+ error messages that occur during type- and range-
+ checking. */
+
+/* Prints the format string FMT with the operator as a string
+ corresponding to the opcode OP. If FATAL is non-zero, then
+ this is an error and error () is called. Otherwise, it is
+ a warning and printf() is called. */
+void
+op_error (fmt,op,fatal)
+ char *fmt;
+ enum exp_opcode op;
+ int fatal;
+{
+ if (fatal)
+ error (fmt,op_string(op));
+ else
+ {
+ warning (fmt,op_string(op));
+ }
+}
+
+/* These are called when a language fails a type- or range-check.
+ The first argument should be a printf()-style format string, and
+ the rest of the arguments should be its arguments. If
+ [type|range]_check is [type|range]_check_on, then return_to_top_level()
+ is called in the style of error (). Otherwise, the message is prefixed
+ by the value of warning_pre_print and we do not return to the top level. */
+
+void
+type_error (va_alist)
+ va_dcl
+{
+ va_list args;
+ char *string;
+
+ if (type_check == type_check_warn)
+ fprintf_filtered (gdb_stderr, warning_pre_print);
+ else
+ error_begin ();
+
+ va_start (args);
+ string = va_arg (args, char *);
+ vfprintf_filtered (gdb_stderr, string, args);
+ fprintf_filtered (gdb_stderr, "\n");
+ va_end (args);
+ if (type_check == type_check_on)
+ return_to_top_level (RETURN_ERROR);
+}
+
+void
+range_error (va_alist)
+ va_dcl
+{
+ va_list args;
+ char *string;
+
+ if (range_check == range_check_warn)
+ fprintf_filtered (gdb_stderr, warning_pre_print);
+ else
+ error_begin ();
+
+ va_start (args);
+ string = va_arg (args, char *);
+ vfprintf_filtered (gdb_stderr, string, args);
+ fprintf_filtered (gdb_stderr, "\n");
+ va_end (args);
+ if (range_check == range_check_on)
+ return_to_top_level (RETURN_ERROR);
+}
+
+
+/* This page contains miscellaneous functions */
+
+/* Return the language struct for a given language enum. */
+
+const struct language_defn *
+language_def(lang)
+ enum language lang;
+{
+ int i;
+
+ for (i = 0; i < languages_size; i++) {
+ if (languages[i]->la_language == lang) {
+ return languages[i];
+ }
+ }
+ return NULL;
+}
+
+/* Return the language as a string */
+char *
+language_str(lang)
+ enum language lang;
+{
+ int i;
+
+ for (i = 0; i < languages_size; i++) {
+ if (languages[i]->la_language == lang) {
+ return languages[i]->la_name;
+ }
+ }
+ return "Unknown";
+}
+
+static void
+set_check (ignore, from_tty)
+ char *ignore;
+ int from_tty;
+{
+ printf_unfiltered(
+"\"set check\" must be followed by the name of a check subcommand.\n");
+ help_list(setchecklist, "set check ", -1, gdb_stdout);
+}
+
+static void
+show_check (ignore, from_tty)
+ char *ignore;
+ int from_tty;
+{
+ cmd_show_list(showchecklist, from_tty, "");
+}
+
+/* Add a language to the set of known languages. */
+
+void
+add_language (lang)
+ const struct language_defn *lang;
+{
+ if (lang->la_magic != LANG_MAGIC)
+ {
+ fprintf_unfiltered(gdb_stderr, "Magic number of %s language struct wrong\n",
+ lang->la_name);
+ abort();
+ }
+
+ if (!languages)
+ {
+ languages_allocsize = DEFAULT_ALLOCSIZE;
+ languages = (const struct language_defn **) xmalloc
+ (languages_allocsize * sizeof (*languages));
+ }
+ if (languages_size >= languages_allocsize)
+ {
+ languages_allocsize *= 2;
+ languages = (const struct language_defn **) xrealloc ((char *) languages,
+ languages_allocsize * sizeof (*languages));
+ }
+ languages[languages_size++] = lang;
+}
+
+/* Define the language that is no language. */
+
+static int
+unk_lang_parser ()
+{
+ return 1;
+}
+
+static void
+unk_lang_error (msg)
+ char *msg;
+{
+ error ("Attempted to parse an expression with unknown language");
+}
+
+static void
+unk_lang_printchar (c, stream)
+ register int c;
+ GDB_FILE *stream;
+{
+ error ("internal error - unimplemented function unk_lang_printchar called.");
+}
+
+static void
+unk_lang_printstr (stream, string, length, force_ellipses)
+ GDB_FILE *stream;
+ char *string;
+ unsigned int length;
+ int force_ellipses;
+{
+ error ("internal error - unimplemented function unk_lang_printstr called.");
+}
+
+static struct type *
+unk_lang_create_fundamental_type (objfile, typeid)
+ struct objfile *objfile;
+ int typeid;
+{
+ error ("internal error - unimplemented function unk_lang_create_fundamental_type called.");
+}
+
+void
+unk_lang_print_type (type, varstring, stream, show, level)
+ struct type *type;
+ char *varstring;
+ GDB_FILE *stream;
+ int show;
+ int level;
+{
+ error ("internal error - unimplemented function unk_lang_print_type called.");
+}
+
+int
+unk_lang_val_print (type, valaddr, address, stream, format, deref_ref,
+ recurse, pretty)
+ struct type *type;
+ char *valaddr;
+ CORE_ADDR address;
+ GDB_FILE *stream;
+ int format;
+ int deref_ref;
+ int recurse;
+ enum val_prettyprint pretty;
+{
+ error ("internal error - unimplemented function unk_lang_val_print called.");
+}
+
+int
+unk_lang_value_print (val, stream, format, pretty)
+ value_ptr val;
+ GDB_FILE *stream;
+ int format;
+ enum val_prettyprint pretty;
+{
+ error ("internal error - unimplemented function unk_lang_value_print called.");
+}
+
+static struct type ** const (unknown_builtin_types[]) = { 0 };
+static const struct op_print unk_op_print_tab[] = {
+ {NULL, OP_NULL, PREC_NULL, 0}
+};
+
+const struct language_defn unknown_language_defn = {
+ "unknown",
+ language_unknown,
+ &unknown_builtin_types[0],
+ range_check_off,
+ type_check_off,
+ unk_lang_parser,
+ unk_lang_error,
+ unk_lang_printchar, /* Print character constant */
+ unk_lang_printstr,
+ unk_lang_create_fundamental_type,
+ unk_lang_print_type, /* Print a type using appropriate syntax */
+ unk_lang_val_print, /* Print a value using appropriate syntax */
+ unk_lang_value_print, /* Print a top-level value */
+ &builtin_type_error, /* longest floating point type */
+ {"", "", "", ""}, /* Binary format info */
+ {"0%lo", "0", "o", ""}, /* Octal format info */
+ {"%ld", "", "d", ""}, /* Decimal format info */
+ {"0x%lx", "0x", "x", ""}, /* Hex format info */
+ unk_op_print_tab, /* expression operators for printing */
+ LANG_MAGIC
+};
+
+/* These two structs define fake entries for the "local" and "auto" options. */
+const struct language_defn auto_language_defn = {
+ "auto",
+ language_auto,
+ &unknown_builtin_types[0],
+ range_check_off,
+ type_check_off,
+ unk_lang_parser,
+ unk_lang_error,
+ unk_lang_printchar, /* Print character constant */
+ unk_lang_printstr,
+ unk_lang_create_fundamental_type,
+ unk_lang_print_type, /* Print a type using appropriate syntax */
+ unk_lang_val_print, /* Print a value using appropriate syntax */
+ unk_lang_value_print, /* Print a top-level value */
+ &builtin_type_error, /* longest floating point type */
+ {"", "", "", ""}, /* Binary format info */
+ {"0%lo", "0", "o", ""}, /* Octal format info */
+ {"%ld", "", "d", ""}, /* Decimal format info */
+ {"0x%lx", "0x", "x", ""}, /* Hex format info */
+ unk_op_print_tab, /* expression operators for printing */
+ LANG_MAGIC
+};
+
+const struct language_defn local_language_defn = {
+ "local",
+ language_auto,
+ &unknown_builtin_types[0],
+ range_check_off,
+ type_check_off,
+ unk_lang_parser,
+ unk_lang_error,
+ unk_lang_printchar, /* Print character constant */
+ unk_lang_printstr,
+ unk_lang_create_fundamental_type,
+ unk_lang_print_type, /* Print a type using appropriate syntax */
+ unk_lang_val_print, /* Print a value using appropriate syntax */
+ unk_lang_value_print, /* Print a top-level value */
+ &builtin_type_error, /* longest floating point type */
+ {"", "", "", ""}, /* Binary format info */
+ {"0%lo", "0", "o", ""}, /* Octal format info */
+ {"%ld", "", "d", ""}, /* Decimal format info */
+ {"0x%lx", "0x", "x", ""}, /* Hex format info */
+ unk_op_print_tab, /* expression operators for printing */
+ LANG_MAGIC
+};
+
+/* Initialize the language routines */
+
+void
+_initialize_language()
+{
+ struct cmd_list_element *set, *show;
+
+ /* GDB commands for language specific stuff */
+
+ set = add_set_cmd ("language", class_support, var_string_noescape,
+ (char *)&language,
+ "Set the current source language.",
+ &setlist);
+ show = add_show_from_set (set, &showlist);
+ set->function.cfunc = set_language_command;
+ show->function.cfunc = show_language_command;
+
+ add_prefix_cmd ("check", no_class, set_check,
+ "Set the status of the type/range checker",
+ &setchecklist, "set check ", 0, &setlist);
+ add_alias_cmd ("c", "check", no_class, 1, &setlist);
+ add_alias_cmd ("ch", "check", no_class, 1, &setlist);
+
+ add_prefix_cmd ("check", no_class, show_check,
+ "Show the status of the type/range checker",
+ &showchecklist, "show check ", 0, &showlist);
+ add_alias_cmd ("c", "check", no_class, 1, &showlist);
+ add_alias_cmd ("ch", "check", no_class, 1, &showlist);
+
+ set = add_set_cmd ("type", class_support, var_string_noescape,
+ (char *)&type,
+ "Set type checking. (on/warn/off/auto)",
+ &setchecklist);
+ show = add_show_from_set (set, &showchecklist);
+ set->function.cfunc = set_type_command;
+ show->function.cfunc = show_type_command;
+
+ set = add_set_cmd ("range", class_support, var_string_noescape,
+ (char *)&range,
+ "Set range checking. (on/warn/off/auto)",
+ &setchecklist);
+ show = add_show_from_set (set, &showchecklist);
+ set->function.cfunc = set_range_command;
+ show->function.cfunc = show_range_command;
+
+ add_language (&unknown_language_defn);
+ add_language (&local_language_defn);
+ add_language (&auto_language_defn);
+
+ language = savestring ("auto",strlen("auto"));
+ range = savestring ("auto",strlen("auto"));
+ type = savestring ("auto",strlen("auto"));
+
+ /* Have the above take effect */
+
+ set_language_command (language, 0);
+ set_type_command (NULL, 0);
+ set_range_command (NULL, 0);
+}
diff --git a/gnu/usr.bin/gdb/gdb/language.h b/gnu/usr.bin/gdb/gdb/language.h
new file mode 100644
index 0000000..202d606
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/language.h
@@ -0,0 +1,413 @@
+/* Source-language-related definitions for GDB.
+ Copyright 1991, 1992 Free Software Foundation, Inc.
+ Contributed by the Department of Computer Science at the State University
+ of New York at Buffalo.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#if !defined (LANGUAGE_H)
+#define LANGUAGE_H 1
+
+#ifdef __STDC__ /* Forward decls for prototypes */
+struct value;
+struct objfile;
+/* enum exp_opcode; ANSI's `wisdom' didn't include forward enum decls. */
+#endif
+
+/* This used to be included to configure GDB for one or more specific
+ languages. Now it is shortcutted to configure for all of them. FIXME. */
+/* #include "lang_def.h" */
+#define _LANG_c
+#define _LANG_m2
+#define _LANG_chill
+
+/* range_mode ==
+ range_mode_auto: range_check set automatically to default of language.
+ range_mode_manual: range_check set manually by user. */
+
+extern enum range_mode {range_mode_auto, range_mode_manual} range_mode;
+
+/* range_check ==
+ range_check_on: Ranges are checked in GDB expressions, producing errors.
+ range_check_warn: Ranges are checked, producing warnings.
+ range_check_off: Ranges are not checked in GDB expressions. */
+
+extern enum range_check
+ {range_check_off, range_check_warn, range_check_on} range_check;
+
+/* type_mode ==
+ type_mode_auto: type_check set automatically to default of language
+ type_mode_manual: type_check set manually by user. */
+
+extern enum type_mode {type_mode_auto, type_mode_manual} type_mode;
+
+/* type_check ==
+ type_check_on: Types are checked in GDB expressions, producing errors.
+ type_check_warn: Types are checked, producing warnings.
+ type_check_off: Types are not checked in GDB expressions. */
+
+extern enum type_check
+ {type_check_off, type_check_warn, type_check_on} type_check;
+
+/* Information for doing language dependent formatting of printed values. */
+
+struct language_format_info
+{
+ /* The format that can be passed directly to standard C printf functions
+ to generate a completely formatted value in the format appropriate for
+ the language. */
+
+ char *la_format;
+
+ /* The prefix to be used when directly printing a value, or constructing
+ a standard C printf format. This generally is everything up to the
+ conversion specification (the part introduced by the '%' character
+ and terminated by the conversion specifier character). */
+
+ char *la_format_prefix;
+
+ /* The conversion specifier. This is generally everything after the
+ field width and precision, typically only a single character such
+ as 'o' for octal format or 'x' for hexadecimal format. */
+
+ char *la_format_specifier;
+
+ /* The suffix to be used when directly printing a value, or constructing
+ a standard C printf format. This generally is everything after the
+ conversion specification (the part introduced by the '%' character
+ and terminated by the conversion specifier character). */
+
+ char *la_format_suffix; /* Suffix for custom format string */
+};
+
+/* Structure tying together assorted information about a language. */
+
+struct language_defn
+{
+ /* Name of the language */
+
+ char *la_name;
+
+ /* its symtab language-enum (defs.h) */
+
+ enum language la_language;
+
+ /* Its builtin types. This is a vector ended by a NULL pointer. These
+ types can be specified by name in parsing types in expressions,
+ regardless of whether the program being debugged actually defines
+ such a type. */
+
+ struct type ** const *la_builtin_type_vector;
+
+ /* Default range checking */
+
+ enum range_check la_range_check;
+
+ /* Default type checking */
+
+ enum type_check la_type_check;
+
+ /* Parser function. */
+
+ int (*la_parser) PARAMS((void));
+
+ /* Parser error function */
+
+ void (*la_error) PARAMS ((char *));
+
+ void (*la_printchar) PARAMS ((int, GDB_FILE *));
+
+ void (*la_printstr) PARAMS ((GDB_FILE *, char *, unsigned int, int));
+
+ struct type *(*la_fund_type) PARAMS ((struct objfile *, int));
+
+ /* Print a type using syntax appropriate for this language. */
+
+ void (*la_print_type) PARAMS ((struct type *, char *, GDB_FILE *, int, int));
+
+ /* Print a value using syntax appropriate for this language. */
+
+ int (*la_val_print) PARAMS ((struct type *, char *, CORE_ADDR, GDB_FILE *,
+ int, int, int, enum val_prettyprint));
+
+ /* Print a top-level value using syntax appropriate for this language. */
+
+ int (*la_value_print) PARAMS ((struct value *, GDB_FILE *,
+ int, enum val_prettyprint));
+
+ /* Longest floating point type */
+
+ struct type **la_longest_float;
+
+ /* Base 2 (binary) formats. */
+
+ struct language_format_info la_binary_format;
+
+ /* Base 8 (octal) formats. */
+
+ struct language_format_info la_octal_format;
+
+ /* Base 10 (decimal) formats */
+
+ struct language_format_info la_decimal_format;
+
+ /* Base 16 (hexadecimal) formats */
+
+ struct language_format_info la_hex_format;
+
+
+ /* Table for printing expressions */
+
+ const struct op_print *la_op_print_tab;
+
+ /* Add fields above this point, so the magic number is always last. */
+ /* Magic number for compat checking */
+
+ long la_magic;
+
+};
+
+#define LANG_MAGIC 910823L
+
+/* Pointer to the language_defn for our current language. This pointer
+ always points to *some* valid struct; it can be used without checking
+ it for validity.
+
+ The current language affects expression parsing and evaluation
+ (FIXME: it might be cleaner to make the evaluation-related stuff
+ separate exp_opcodes for each different set of semantics. We
+ should at least think this through more clearly with respect to
+ what happens if the language is changed between parsing and
+ evaluation) and printing of things like types and arrays. It does
+ *not* affect symbol-reading-- each source file in a symbol-file has
+ its own language and we should keep track of that regardless of the
+ language when symbols are read. If we want some manual setting for
+ the language of symbol files (e.g. detecting when ".c" files are
+ C++), it should be a seprate setting from the current_language. */
+
+extern const struct language_defn *current_language;
+
+/* Pointer to the language_defn expected by the user, e.g. the language
+ of main(), or the language we last mentioned in a message, or C. */
+
+extern const struct language_defn *expected_language;
+
+/* language_mode ==
+ language_mode_auto: current_language automatically set upon selection
+ of scope (e.g. stack frame)
+ language_mode_manual: current_language set only by user. */
+
+extern enum language_mode
+ {language_mode_auto, language_mode_manual} language_mode;
+
+/* These macros define the behaviour of the expression
+ evaluator. */
+
+/* Should we strictly type check expressions? */
+#define STRICT_TYPE (type_check != type_check_off)
+
+/* Should we range check values against the domain of their type? */
+#define RANGE_CHECK (range_check != range_check_off)
+
+/* "cast" really means conversion */
+/* FIXME -- should be a setting in language_defn */
+#define CAST_IS_CONVERSION (current_language->la_language == language_c || \
+ current_language->la_language == language_cplus)
+
+extern void
+language_info PARAMS ((int));
+
+extern void
+set_language PARAMS ((enum language));
+
+
+/* This page contains functions that return things that are
+ specific to languages. Each of these functions is based on
+ the current setting of working_lang, which the user sets
+ with the "set language" command. */
+
+/* Returns some built-in types */
+#define longest_float() (*current_language->la_longest_float)
+
+#define create_fundamental_type(objfile,typeid) \
+ (current_language->la_fund_type(objfile, typeid))
+
+#define LA_PRINT_TYPE(type,varstring,stream,show,level) \
+ (current_language->la_print_type(type,varstring,stream,show,level))
+
+#define LA_VAL_PRINT(type,valaddr,addr,stream,fmt,deref,recurse,pretty) \
+ (current_language->la_val_print(type,valaddr,addr,stream,fmt,deref, \
+ recurse,pretty))
+#define LA_VALUE_PRINT(val,stream,fmt,pretty) \
+ (current_language->la_value_print(val,stream,fmt,pretty))
+
+/* Return a format string for printf that will print a number in one of
+ the local (language-specific) formats. Result is static and is
+ overwritten by the next call. Takes printf options like "08" or "l"
+ (to produce e.g. %08x or %lx). */
+
+#define local_binary_format() \
+ (current_language->la_binary_format.la_format)
+#define local_binary_format_prefix() \
+ (current_language->la_binary_format.la_format_prefix)
+#define local_binary_format_specifier() \
+ (current_language->la_binary_format.la_format_specifier)
+#define local_binary_format_suffix() \
+ (current_language->la_binary_format.la_format_suffix)
+
+#define local_octal_format() \
+ (current_language->la_octal_format.la_format)
+#define local_octal_format_prefix() \
+ (current_language->la_octal_format.la_format_prefix)
+#define local_octal_format_specifier() \
+ (current_language->la_octal_format.la_format_specifier)
+#define local_octal_format_suffix() \
+ (current_language->la_octal_format.la_format_suffix)
+
+#define local_decimal_format() \
+ (current_language->la_decimal_format.la_format)
+#define local_decimal_format_prefix() \
+ (current_language->la_decimal_format.la_format_prefix)
+#define local_decimal_format_specifier() \
+ (current_language->la_decimal_format.la_format_specifier)
+#define local_decimal_format_suffix() \
+ (current_language->la_decimal_format.la_format_suffix)
+
+#define local_hex_format() \
+ (current_language->la_hex_format.la_format)
+#define local_hex_format_prefix() \
+ (current_language->la_hex_format.la_format_prefix)
+#define local_hex_format_specifier() \
+ (current_language->la_hex_format.la_format_specifier)
+#define local_hex_format_suffix() \
+ (current_language->la_hex_format.la_format_suffix)
+
+#define LA_PRINT_CHAR(ch, stream) \
+ (current_language->la_printchar(ch, stream))
+#define LA_PRINT_STRING(stream, string, length, force_ellipses) \
+ (current_language->la_printstr(stream, string, length, force_ellipses))
+
+/* Test a character to decide whether it can be printed in literal form
+ or needs to be printed in another representation. For example,
+ in C the literal form of the character with octal value 141 is 'a'
+ and the "other representation" is '\141'. The "other representation"
+ is program language dependent. */
+
+#define PRINT_LITERAL_FORM(c) \
+ ((c)>=0x20 && ((c)<0x7F || (c)>=0xA0) && (!sevenbit_strings || (c)<0x80))
+
+/* Return a format string for printf that will print a number in one of
+ the local (language-specific) formats. Result is static and is
+ overwritten by the next call. Takes printf options like "08" or "l"
+ (to produce e.g. %08x or %lx). */
+
+extern char *
+local_decimal_format_custom PARAMS ((char *)); /* language.c */
+
+extern char *
+local_octal_format_custom PARAMS ((char *)); /* language.c */
+
+extern char *
+local_hex_format_custom PARAMS ((char *)); /* language.c */
+
+/* Return a string that contains a number formatted in one of the local
+ (language-specific) formats. Result is static and is overwritten by
+ the next call. Takes printf options like "08" or "l". */
+
+extern char *
+local_hex_string PARAMS ((unsigned long)); /* language.c */
+
+extern char *
+local_hex_string_custom PARAMS ((unsigned long, char *)); /* language.c */
+
+/* Type predicates */
+
+extern int
+simple_type PARAMS ((struct type *));
+
+extern int
+ordered_type PARAMS ((struct type *));
+
+extern int
+same_type PARAMS ((struct type *, struct type *));
+
+extern int
+integral_type PARAMS ((struct type *));
+
+extern int
+numeric_type PARAMS ((struct type *));
+
+extern int
+character_type PARAMS ((struct type *));
+
+extern int
+boolean_type PARAMS ((struct type *));
+
+extern int
+float_type PARAMS ((struct type *));
+
+extern int
+pointer_type PARAMS ((struct type *));
+
+extern int
+structured_type PARAMS ((struct type *));
+
+/* Checks Binary and Unary operations for semantic type correctness */
+/* FIXME: Does not appear to be used */
+#define unop_type_check(v,o) binop_type_check((v),NULL,(o))
+
+extern void
+binop_type_check PARAMS ((struct value *, struct value *, int));
+
+/* Error messages */
+
+extern void
+op_error PARAMS ((char *fmt, enum exp_opcode, int));
+
+#define type_op_error(f,o) \
+ op_error((f),(o),type_check==type_check_on ? 1 : 0)
+#define range_op_error(f,o) \
+ op_error((f),(o),range_check==range_check_on ? 1 : 0)
+
+extern void
+type_error ();
+
+void
+range_error ();
+
+/* Data: Does this value represent "truth" to the current language? */
+
+extern int
+value_true PARAMS ((struct value *));
+
+/* Misc: The string representing a particular enum language. */
+
+extern const struct language_defn *
+language_def PARAMS ((enum language));
+
+extern char *
+language_str PARAMS ((enum language));
+
+/* Add a language to the set known by GDB (at initialization time). */
+
+extern void
+add_language PARAMS ((const struct language_defn *));
+
+extern enum language
+get_frame_language PARAMS ((void)); /* In stack.c */
+
+#endif /* defined (LANGUAGE_H) */
diff --git a/gnu/usr.bin/gdb/gdb/libiberty.h b/gnu/usr.bin/gdb/gdb/libiberty.h
new file mode 100644
index 0000000..9854b4c
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/libiberty.h
@@ -0,0 +1,107 @@
+/* Function declarations for libiberty.
+ Written by Cygnus Support, 1994.
+
+ The libiberty library provides a number of functions which are
+ missing on some operating systems. We do not declare those here,
+ to avoid conflicts with the system header files on operating
+ systems that do support those functions. In this file we only
+ declare those functions which are specific to libiberty. */
+
+#ifndef LIBIBERTY_H
+#define LIBIBERTY_H
+
+#include "ansidecl.h"
+
+/* Build an argument vector from a string. Allocates memory using
+ malloc. Use freeargv to free the vector. */
+
+extern char **buildargv PARAMS ((char *));
+
+/* Free a vector returned by buildargv. */
+
+extern void freeargv PARAMS ((char **));
+
+/* Return the last component of a path name. */
+
+extern char *basename PARAMS ((char *));
+
+/* Concatenate an arbitrary number of strings, up to (char *) NULL.
+ Allocates memory using xmalloc. */
+
+extern char *concat PARAMS ((const char *, ...));
+
+/* Check whether two file descriptors refer to the same file. */
+
+extern int fdmatch PARAMS ((int fd1, int fd2));
+
+/* Get the amount of time the process has run, in microseconds. */
+
+extern long get_run_time PARAMS ((void));
+
+/* Allocate memory filled with spaces. Allocates using malloc. */
+
+extern const char *spaces PARAMS ((int count));
+
+/* Return the maximum error number for which strerror will return a
+ string. */
+
+extern int errno_max PARAMS ((void));
+
+/* Return the name of an errno value (e.g., strerrno (EINVAL) returns
+ "EINVAL"). */
+
+extern const char *strerrno PARAMS ((int));
+
+/* Given the name of an errno value, return the value. */
+
+extern int strtoerrno PARAMS ((const char *));
+
+/* Return the maximum signal number for which strsignal will return a
+ string. */
+
+extern int signo_max PARAMS ((void));
+
+/* Return the name of a signal number (e.g., strsigno (SIGHUP) returns
+ "SIGHUP"). */
+
+extern const char *strsigno PARAMS ((int));
+
+/* Given the name of a signal, return its number. */
+
+extern int strtosigno PARAMS ((const char *));
+
+/* Register a function to be run by xexit. Returns 0 on success. */
+
+extern int xatexit PARAMS ((void (*fn) (void)));
+
+/* Exit, calling all the functions registered with xatexit. */
+
+#ifndef __GNUC__
+extern void xexit PARAMS ((int status));
+#else
+typedef void libiberty_voidfn PARAMS ((int status));
+__volatile__ libiberty_voidfn xexit;
+#endif
+
+/* Set the program name used by xmalloc. */
+
+extern void xmalloc_set_program_name PARAMS ((const char *));
+
+/* Allocate memory without fail. If malloc fails, this will print a
+ message to stderr (using the name set by xmalloc_set_program_name,
+ if any) and then call xexit.
+
+ FIXME: We do not declare the parameter type (size_t) in order to
+ avoid conflicts with other declarations of xmalloc that exist in
+ programs which use libiberty. */
+
+extern PTR xmalloc ();
+
+/* Reallocate memory without fail. This works like xmalloc.
+
+ FIXME: We do not declare the parameter types for the same reason as
+ xmalloc. */
+
+extern PTR xrealloc ();
+
+#endif /* ! defined (LIBIBERTY_H) */
diff --git a/gnu/usr.bin/gdb/gdb/m2-exp.y b/gnu/usr.bin/gdb/gdb/m2-exp.y
new file mode 100644
index 0000000..cc4001f
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/m2-exp.y
@@ -0,0 +1,1169 @@
+/* YACC grammar for Modula-2 expressions, for GDB.
+ Copyright (C) 1986, 1989, 1990, 1991 Free Software Foundation, Inc.
+ Generated from expread.y (now c-exp.y) and contributed by the Department
+ of Computer Science at the State University of New York at Buffalo, 1991.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* Parse a Modula-2 expression from text in a string,
+ and return the result as a struct expression pointer.
+ That structure contains arithmetic operations in reverse polish,
+ with constants represented by operations that are followed by special data.
+ See expression.h for the details of the format.
+ What is important here is that it can be built up sequentially
+ during the process of parsing; the lower levels of the tree always
+ come first in the result.
+
+ Note that malloc's and realloc's in this file are transformed to
+ xmalloc and xrealloc respectively by the same sed command in the
+ makefile that remaps any other malloc/realloc inserted by the parser
+ generator. Doing this with #defines and trying to control the interaction
+ with include files (<malloc.h> and <stdlib.h> for example) just became
+ too messy, particularly when such includes can be inserted at random
+ times by the parser generator. */
+
+%{
+
+#include "defs.h"
+#include "expression.h"
+#include "language.h"
+#include "value.h"
+#include "parser-defs.h"
+#include "m2-lang.h"
+
+/* Remap normal yacc parser interface names (yyparse, yylex, yyerror, etc),
+ as well as gratuitiously global symbol names, so we can have multiple
+ yacc generated parsers in gdb. Note that these are only the variables
+ produced by yacc. If other parser generators (bison, byacc, etc) produce
+ additional global names that conflict at link time, then those parser
+ generators need to be fixed instead of adding those names to this list. */
+
+#define yymaxdepth m2_maxdepth
+#define yyparse m2_parse
+#define yylex m2_lex
+#define yyerror m2_error
+#define yylval m2_lval
+#define yychar m2_char
+#define yydebug m2_debug
+#define yypact m2_pact
+#define yyr1 m2_r1
+#define yyr2 m2_r2
+#define yydef m2_def
+#define yychk m2_chk
+#define yypgo m2_pgo
+#define yyact m2_act
+#define yyexca m2_exca
+#define yyerrflag m2_errflag
+#define yynerrs m2_nerrs
+#define yyps m2_ps
+#define yypv m2_pv
+#define yys m2_s
+#define yy_yys m2_yys
+#define yystate m2_state
+#define yytmp m2_tmp
+#define yyv m2_v
+#define yy_yyv m2_yyv
+#define yyval m2_val
+#define yylloc m2_lloc
+#define yyreds m2_reds /* With YYDEBUG defined */
+#define yytoks m2_toks /* With YYDEBUG defined */
+
+#ifndef YYDEBUG
+#define YYDEBUG 0 /* Default to no yydebug support */
+#endif
+
+int
+yyparse PARAMS ((void));
+
+static int
+yylex PARAMS ((void));
+
+void
+yyerror PARAMS ((char *));
+
+#if 0
+static char *
+make_qualname PARAMS ((char *, char *));
+#endif
+
+static int
+parse_number PARAMS ((int));
+
+/* The sign of the number being parsed. */
+static int number_sign = 1;
+
+/* The block that the module specified by the qualifer on an identifer is
+ contained in, */
+#if 0
+static struct block *modblock=0;
+#endif
+
+%}
+
+/* Although the yacc "value" of an expression is not used,
+ since the result is stored in the structure being created,
+ other node types do have values. */
+
+%union
+ {
+ LONGEST lval;
+ unsigned LONGEST ulval;
+ double dval;
+ struct symbol *sym;
+ struct type *tval;
+ struct stoken sval;
+ int voidval;
+ struct block *bval;
+ enum exp_opcode opcode;
+ struct internalvar *ivar;
+
+ struct type **tvec;
+ int *ivec;
+ }
+
+%type <voidval> exp type_exp start set
+%type <voidval> variable
+%type <tval> type
+%type <bval> block
+%type <sym> fblock
+
+%token <lval> INT HEX ERROR
+%token <ulval> UINT M2_TRUE M2_FALSE CHAR
+%token <dval> FLOAT
+
+/* Both NAME and TYPENAME tokens represent symbols in the input,
+ and both convey their data as strings.
+ But a TYPENAME is a string that happens to be defined as a typedef
+ or builtin type name (such as int or char)
+ and a NAME is any other symbol.
+
+ Contexts where this distinction is not important can use the
+ nonterminal "name", which matches either NAME or TYPENAME. */
+
+%token <sval> STRING
+%token <sval> NAME BLOCKNAME IDENT VARNAME
+%token <sval> TYPENAME
+
+%token SIZE CAP ORD HIGH ABS MIN_FUNC MAX_FUNC FLOAT_FUNC VAL CHR ODD TRUNC
+%token INC DEC INCL EXCL
+
+/* The GDB scope operator */
+%token COLONCOLON
+
+%token <lval> LAST REGNAME
+
+%token <ivar> INTERNAL_VAR
+
+/* M2 tokens */
+%left ','
+%left ABOVE_COMMA
+%nonassoc ASSIGN
+%left '<' '>' LEQ GEQ '=' NOTEQUAL '#' IN
+%left OROR
+%left LOGICAL_AND '&'
+%left '@'
+%left '+' '-'
+%left '*' '/' DIV MOD
+%right UNARY
+%right '^' DOT '[' '('
+%right NOT '~'
+%left COLONCOLON QID
+/* This is not an actual token ; it is used for precedence.
+%right QID
+*/
+
+
+%%
+
+start : exp
+ | type_exp
+ ;
+
+type_exp: type
+ { write_exp_elt_opcode(OP_TYPE);
+ write_exp_elt_type($1);
+ write_exp_elt_opcode(OP_TYPE);
+ }
+ ;
+
+/* Expressions */
+
+exp : exp '^' %prec UNARY
+ { write_exp_elt_opcode (UNOP_IND); }
+
+exp : '-'
+ { number_sign = -1; }
+ exp %prec UNARY
+ { number_sign = 1;
+ write_exp_elt_opcode (UNOP_NEG); }
+ ;
+
+exp : '+' exp %prec UNARY
+ { write_exp_elt_opcode(UNOP_PLUS); }
+ ;
+
+exp : not_exp exp %prec UNARY
+ { write_exp_elt_opcode (UNOP_LOGICAL_NOT); }
+ ;
+
+not_exp : NOT
+ | '~'
+ ;
+
+exp : CAP '(' exp ')'
+ { write_exp_elt_opcode (UNOP_CAP); }
+ ;
+
+exp : ORD '(' exp ')'
+ { write_exp_elt_opcode (UNOP_ORD); }
+ ;
+
+exp : ABS '(' exp ')'
+ { write_exp_elt_opcode (UNOP_ABS); }
+ ;
+
+exp : HIGH '(' exp ')'
+ { write_exp_elt_opcode (UNOP_HIGH); }
+ ;
+
+exp : MIN_FUNC '(' type ')'
+ { write_exp_elt_opcode (UNOP_MIN);
+ write_exp_elt_type ($3);
+ write_exp_elt_opcode (UNOP_MIN); }
+ ;
+
+exp : MAX_FUNC '(' type ')'
+ { write_exp_elt_opcode (UNOP_MAX);
+ write_exp_elt_type ($3);
+ write_exp_elt_opcode (UNOP_MIN); }
+ ;
+
+exp : FLOAT_FUNC '(' exp ')'
+ { write_exp_elt_opcode (UNOP_FLOAT); }
+ ;
+
+exp : VAL '(' type ',' exp ')'
+ { write_exp_elt_opcode (BINOP_VAL);
+ write_exp_elt_type ($3);
+ write_exp_elt_opcode (BINOP_VAL); }
+ ;
+
+exp : CHR '(' exp ')'
+ { write_exp_elt_opcode (UNOP_CHR); }
+ ;
+
+exp : ODD '(' exp ')'
+ { write_exp_elt_opcode (UNOP_ODD); }
+ ;
+
+exp : TRUNC '(' exp ')'
+ { write_exp_elt_opcode (UNOP_TRUNC); }
+ ;
+
+exp : SIZE exp %prec UNARY
+ { write_exp_elt_opcode (UNOP_SIZEOF); }
+ ;
+
+
+exp : INC '(' exp ')'
+ { write_exp_elt_opcode(UNOP_PREINCREMENT); }
+ ;
+
+exp : INC '(' exp ',' exp ')'
+ { write_exp_elt_opcode(BINOP_ASSIGN_MODIFY);
+ write_exp_elt_opcode(BINOP_ADD);
+ write_exp_elt_opcode(BINOP_ASSIGN_MODIFY); }
+ ;
+
+exp : DEC '(' exp ')'
+ { write_exp_elt_opcode(UNOP_PREDECREMENT);}
+ ;
+
+exp : DEC '(' exp ',' exp ')'
+ { write_exp_elt_opcode(BINOP_ASSIGN_MODIFY);
+ write_exp_elt_opcode(BINOP_SUB);
+ write_exp_elt_opcode(BINOP_ASSIGN_MODIFY); }
+ ;
+
+exp : exp DOT NAME
+ { write_exp_elt_opcode (STRUCTOP_STRUCT);
+ write_exp_string ($3);
+ write_exp_elt_opcode (STRUCTOP_STRUCT); }
+ ;
+
+exp : set
+ ;
+
+exp : exp IN set
+ { error("Sets are not implemented.");}
+ ;
+
+exp : INCL '(' exp ',' exp ')'
+ { error("Sets are not implemented.");}
+ ;
+
+exp : EXCL '(' exp ',' exp ')'
+ { error("Sets are not implemented.");}
+
+set : '{' arglist '}'
+ { error("Sets are not implemented.");}
+ | type '{' arglist '}'
+ { error("Sets are not implemented.");}
+ ;
+
+
+/* Modula-2 array subscript notation [a,b,c...] */
+exp : exp '['
+ /* This function just saves the number of arguments
+ that follow in the list. It is *not* specific to
+ function types */
+ { start_arglist(); }
+ non_empty_arglist ']' %prec DOT
+ { write_exp_elt_opcode (MULTI_SUBSCRIPT);
+ write_exp_elt_longcst ((LONGEST) end_arglist());
+ write_exp_elt_opcode (MULTI_SUBSCRIPT); }
+ ;
+
+exp : exp '('
+ /* This is to save the value of arglist_len
+ being accumulated by an outer function call. */
+ { start_arglist (); }
+ arglist ')' %prec DOT
+ { write_exp_elt_opcode (OP_FUNCALL);
+ write_exp_elt_longcst ((LONGEST) end_arglist ());
+ write_exp_elt_opcode (OP_FUNCALL); }
+ ;
+
+arglist :
+ ;
+
+arglist : exp
+ { arglist_len = 1; }
+ ;
+
+arglist : arglist ',' exp %prec ABOVE_COMMA
+ { arglist_len++; }
+ ;
+
+non_empty_arglist
+ : exp
+ { arglist_len = 1; }
+ ;
+
+non_empty_arglist
+ : non_empty_arglist ',' exp %prec ABOVE_COMMA
+ { arglist_len++; }
+ ;
+
+/* GDB construct */
+exp : '{' type '}' exp %prec UNARY
+ { write_exp_elt_opcode (UNOP_MEMVAL);
+ write_exp_elt_type ($2);
+ write_exp_elt_opcode (UNOP_MEMVAL); }
+ ;
+
+exp : type '(' exp ')' %prec UNARY
+ { write_exp_elt_opcode (UNOP_CAST);
+ write_exp_elt_type ($1);
+ write_exp_elt_opcode (UNOP_CAST); }
+ ;
+
+exp : '(' exp ')'
+ { }
+ ;
+
+/* Binary operators in order of decreasing precedence. Note that some
+ of these operators are overloaded! (ie. sets) */
+
+/* GDB construct */
+exp : exp '@' exp
+ { write_exp_elt_opcode (BINOP_REPEAT); }
+ ;
+
+exp : exp '*' exp
+ { write_exp_elt_opcode (BINOP_MUL); }
+ ;
+
+exp : exp '/' exp
+ { write_exp_elt_opcode (BINOP_DIV); }
+ ;
+
+exp : exp DIV exp
+ { write_exp_elt_opcode (BINOP_INTDIV); }
+ ;
+
+exp : exp MOD exp
+ { write_exp_elt_opcode (BINOP_REM); }
+ ;
+
+exp : exp '+' exp
+ { write_exp_elt_opcode (BINOP_ADD); }
+ ;
+
+exp : exp '-' exp
+ { write_exp_elt_opcode (BINOP_SUB); }
+ ;
+
+exp : exp '=' exp
+ { write_exp_elt_opcode (BINOP_EQUAL); }
+ ;
+
+exp : exp NOTEQUAL exp
+ { write_exp_elt_opcode (BINOP_NOTEQUAL); }
+ | exp '#' exp
+ { write_exp_elt_opcode (BINOP_NOTEQUAL); }
+ ;
+
+exp : exp LEQ exp
+ { write_exp_elt_opcode (BINOP_LEQ); }
+ ;
+
+exp : exp GEQ exp
+ { write_exp_elt_opcode (BINOP_GEQ); }
+ ;
+
+exp : exp '<' exp
+ { write_exp_elt_opcode (BINOP_LESS); }
+ ;
+
+exp : exp '>' exp
+ { write_exp_elt_opcode (BINOP_GTR); }
+ ;
+
+exp : exp LOGICAL_AND exp
+ { write_exp_elt_opcode (BINOP_LOGICAL_AND); }
+ ;
+
+exp : exp OROR exp
+ { write_exp_elt_opcode (BINOP_LOGICAL_OR); }
+ ;
+
+exp : exp ASSIGN exp
+ { write_exp_elt_opcode (BINOP_ASSIGN); }
+ ;
+
+
+/* Constants */
+
+exp : M2_TRUE
+ { write_exp_elt_opcode (OP_BOOL);
+ write_exp_elt_longcst ((LONGEST) $1);
+ write_exp_elt_opcode (OP_BOOL); }
+ ;
+
+exp : M2_FALSE
+ { write_exp_elt_opcode (OP_BOOL);
+ write_exp_elt_longcst ((LONGEST) $1);
+ write_exp_elt_opcode (OP_BOOL); }
+ ;
+
+exp : INT
+ { write_exp_elt_opcode (OP_LONG);
+ write_exp_elt_type (builtin_type_m2_int);
+ write_exp_elt_longcst ((LONGEST) $1);
+ write_exp_elt_opcode (OP_LONG); }
+ ;
+
+exp : UINT
+ {
+ write_exp_elt_opcode (OP_LONG);
+ write_exp_elt_type (builtin_type_m2_card);
+ write_exp_elt_longcst ((LONGEST) $1);
+ write_exp_elt_opcode (OP_LONG);
+ }
+ ;
+
+exp : CHAR
+ { write_exp_elt_opcode (OP_LONG);
+ write_exp_elt_type (builtin_type_m2_char);
+ write_exp_elt_longcst ((LONGEST) $1);
+ write_exp_elt_opcode (OP_LONG); }
+ ;
+
+
+exp : FLOAT
+ { write_exp_elt_opcode (OP_DOUBLE);
+ write_exp_elt_type (builtin_type_m2_real);
+ write_exp_elt_dblcst ($1);
+ write_exp_elt_opcode (OP_DOUBLE); }
+ ;
+
+exp : variable
+ ;
+
+/* The GDB internal variable $$, et al. */
+exp : LAST
+ { write_exp_elt_opcode (OP_LAST);
+ write_exp_elt_longcst ((LONGEST) $1);
+ write_exp_elt_opcode (OP_LAST); }
+ ;
+
+exp : REGNAME
+ { write_exp_elt_opcode (OP_REGISTER);
+ write_exp_elt_longcst ((LONGEST) $1);
+ write_exp_elt_opcode (OP_REGISTER); }
+ ;
+
+exp : SIZE '(' type ')' %prec UNARY
+ { write_exp_elt_opcode (OP_LONG);
+ write_exp_elt_type (builtin_type_int);
+ write_exp_elt_longcst ((LONGEST) TYPE_LENGTH ($3));
+ write_exp_elt_opcode (OP_LONG); }
+ ;
+
+exp : STRING
+ { write_exp_elt_opcode (OP_M2_STRING);
+ write_exp_string ($1);
+ write_exp_elt_opcode (OP_M2_STRING); }
+ ;
+
+/* This will be used for extensions later. Like adding modules. */
+block : fblock
+ { $$ = SYMBOL_BLOCK_VALUE($1); }
+ ;
+
+fblock : BLOCKNAME
+ { struct symbol *sym
+ = lookup_symbol (copy_name ($1), expression_context_block,
+ VAR_NAMESPACE, 0, NULL);
+ $$ = sym;}
+ ;
+
+
+/* GDB scope operator */
+fblock : block COLONCOLON BLOCKNAME
+ { struct symbol *tem
+ = lookup_symbol (copy_name ($3), $1,
+ VAR_NAMESPACE, 0, NULL);
+ if (!tem || SYMBOL_CLASS (tem) != LOC_BLOCK)
+ error ("No function \"%s\" in specified context.",
+ copy_name ($3));
+ $$ = tem;
+ }
+ ;
+
+/* Useful for assigning to PROCEDURE variables */
+variable: fblock
+ { write_exp_elt_opcode(OP_VAR_VALUE);
+ write_exp_elt_block (NULL);
+ write_exp_elt_sym ($1);
+ write_exp_elt_opcode (OP_VAR_VALUE); }
+ ;
+
+/* GDB internal ($foo) variable */
+variable: INTERNAL_VAR
+ { write_exp_elt_opcode (OP_INTERNALVAR);
+ write_exp_elt_intern ($1);
+ write_exp_elt_opcode (OP_INTERNALVAR); }
+ ;
+
+/* GDB scope operator */
+variable: block COLONCOLON NAME
+ { struct symbol *sym;
+ sym = lookup_symbol (copy_name ($3), $1,
+ VAR_NAMESPACE, 0, NULL);
+ if (sym == 0)
+ error ("No symbol \"%s\" in specified context.",
+ copy_name ($3));
+
+ write_exp_elt_opcode (OP_VAR_VALUE);
+ /* block_found is set by lookup_symbol. */
+ write_exp_elt_block (block_found);
+ write_exp_elt_sym (sym);
+ write_exp_elt_opcode (OP_VAR_VALUE); }
+ ;
+
+/* Base case for variables. */
+variable: NAME
+ { struct symbol *sym;
+ int is_a_field_of_this;
+
+ sym = lookup_symbol (copy_name ($1),
+ expression_context_block,
+ VAR_NAMESPACE,
+ &is_a_field_of_this,
+ NULL);
+ if (sym)
+ {
+ if (symbol_read_needs_frame (sym))
+ {
+ if (innermost_block == 0 ||
+ contained_in (block_found,
+ innermost_block))
+ innermost_block = block_found;
+ }
+
+ write_exp_elt_opcode (OP_VAR_VALUE);
+ /* We want to use the selected frame, not
+ another more inner frame which happens to
+ be in the same block. */
+ write_exp_elt_block (NULL);
+ write_exp_elt_sym (sym);
+ write_exp_elt_opcode (OP_VAR_VALUE);
+ }
+ else
+ {
+ struct minimal_symbol *msymbol;
+ register char *arg = copy_name ($1);
+
+ msymbol = lookup_minimal_symbol (arg,
+ (struct objfile *) NULL);
+ if (msymbol != NULL)
+ {
+ write_exp_elt_opcode (OP_LONG);
+ write_exp_elt_type (builtin_type_long);
+ write_exp_elt_longcst ((LONGEST) SYMBOL_VALUE_ADDRESS (msymbol));
+ write_exp_elt_opcode (OP_LONG);
+ write_exp_elt_opcode (UNOP_MEMVAL);
+ if (msymbol -> type == mst_data ||
+ msymbol -> type == mst_bss)
+ write_exp_elt_type (builtin_type_int);
+ else if (msymbol -> type == mst_text)
+ write_exp_elt_type (lookup_function_type (builtin_type_int));
+ else
+ write_exp_elt_type (builtin_type_char);
+ write_exp_elt_opcode (UNOP_MEMVAL);
+ }
+ else if (!have_full_symbols () && !have_partial_symbols ())
+ error ("No symbol table is loaded. Use the \"symbol-file\" command.");
+ else
+ error ("No symbol \"%s\" in current context.",
+ copy_name ($1));
+ }
+ }
+ ;
+
+type
+ : TYPENAME
+ { $$ = lookup_typename (copy_name ($1),
+ expression_context_block, 0); }
+
+ ;
+
+%%
+
+#if 0 /* FIXME! */
+int
+overflow(a,b)
+ long a,b;
+{
+ return (MAX_OF_TYPE(builtin_type_m2_int) - b) < a;
+}
+
+int
+uoverflow(a,b)
+ unsigned long a,b;
+{
+ return (MAX_OF_TYPE(builtin_type_m2_card) - b) < a;
+}
+#endif /* FIXME */
+
+/* Take care of parsing a number (anything that starts with a digit).
+ Set yylval and return the token type; update lexptr.
+ LEN is the number of characters in it. */
+
+/*** Needs some error checking for the float case ***/
+
+static int
+parse_number (olen)
+ int olen;
+{
+ register char *p = lexptr;
+ register LONGEST n = 0;
+ register LONGEST prevn = 0;
+ register int c,i,ischar=0;
+ register int base = input_radix;
+ register int len = olen;
+ int unsigned_p = number_sign == 1 ? 1 : 0;
+
+ if(p[len-1] == 'H')
+ {
+ base = 16;
+ len--;
+ }
+ else if(p[len-1] == 'C' || p[len-1] == 'B')
+ {
+ base = 8;
+ ischar = p[len-1] == 'C';
+ len--;
+ }
+
+ /* Scan the number */
+ for (c = 0; c < len; c++)
+ {
+ if (p[c] == '.' && base == 10)
+ {
+ /* It's a float since it contains a point. */
+ yylval.dval = atof (p);
+ lexptr += len;
+ return FLOAT;
+ }
+ if (p[c] == '.' && base != 10)
+ error("Floating point numbers must be base 10.");
+ if (base == 10 && (p[c] < '0' || p[c] > '9'))
+ error("Invalid digit \'%c\' in number.",p[c]);
+ }
+
+ while (len-- > 0)
+ {
+ c = *p++;
+ n *= base;
+ if( base == 8 && (c == '8' || c == '9'))
+ error("Invalid digit \'%c\' in octal number.",c);
+ if (c >= '0' && c <= '9')
+ i = c - '0';
+ else
+ {
+ if (base == 16 && c >= 'A' && c <= 'F')
+ i = c - 'A' + 10;
+ else
+ return ERROR;
+ }
+ n+=i;
+ if(i >= base)
+ return ERROR;
+ if(!unsigned_p && number_sign == 1 && (prevn >= n))
+ unsigned_p=1; /* Try something unsigned */
+ /* Don't do the range check if n==i and i==0, since that special
+ case will give an overflow error. */
+ if(RANGE_CHECK && n!=i && i)
+ {
+ if((unsigned_p && (unsigned)prevn >= (unsigned)n) ||
+ ((!unsigned_p && number_sign==-1) && -prevn <= -n))
+ range_error("Overflow on numeric constant.");
+ }
+ prevn=n;
+ }
+
+ lexptr = p;
+ if(*p == 'B' || *p == 'C' || *p == 'H')
+ lexptr++; /* Advance past B,C or H */
+
+ if (ischar)
+ {
+ yylval.ulval = n;
+ return CHAR;
+ }
+ else if ( unsigned_p && number_sign == 1)
+ {
+ yylval.ulval = n;
+ return UINT;
+ }
+ else if((unsigned_p && (n<0))) {
+ range_error("Overflow on numeric constant -- number too large.");
+ /* But, this can return if range_check == range_warn. */
+ }
+ yylval.lval = n;
+ return INT;
+}
+
+
+/* Some tokens */
+
+static struct
+{
+ char name[2];
+ int token;
+} tokentab2[] =
+{
+ { {'<', '>'}, NOTEQUAL },
+ { {':', '='}, ASSIGN },
+ { {'<', '='}, LEQ },
+ { {'>', '='}, GEQ },
+ { {':', ':'}, COLONCOLON },
+
+};
+
+/* Some specific keywords */
+
+struct keyword {
+ char keyw[10];
+ int token;
+};
+
+static struct keyword keytab[] =
+{
+ {"OR" , OROR },
+ {"IN", IN },/* Note space after IN */
+ {"AND", LOGICAL_AND},
+ {"ABS", ABS },
+ {"CHR", CHR },
+ {"DEC", DEC },
+ {"NOT", NOT },
+ {"DIV", DIV },
+ {"INC", INC },
+ {"MAX", MAX_FUNC },
+ {"MIN", MIN_FUNC },
+ {"MOD", MOD },
+ {"ODD", ODD },
+ {"CAP", CAP },
+ {"ORD", ORD },
+ {"VAL", VAL },
+ {"EXCL", EXCL },
+ {"HIGH", HIGH },
+ {"INCL", INCL },
+ {"SIZE", SIZE },
+ {"FLOAT", FLOAT_FUNC },
+ {"TRUNC", TRUNC },
+};
+
+
+/* Read one token, getting characters through lexptr. */
+
+/* This is where we will check to make sure that the language and the operators used are
+ compatible */
+
+static int
+yylex ()
+{
+ register int c;
+ register int namelen;
+ register int i;
+ register char *tokstart;
+ register char quote;
+
+ retry:
+
+ tokstart = lexptr;
+
+
+ /* See if it is a special token of length 2 */
+ for( i = 0 ; i < sizeof tokentab2 / sizeof tokentab2[0] ; i++)
+ if(STREQN(tokentab2[i].name, tokstart, 2))
+ {
+ lexptr += 2;
+ return tokentab2[i].token;
+ }
+
+ switch (c = *tokstart)
+ {
+ case 0:
+ return 0;
+
+ case ' ':
+ case '\t':
+ case '\n':
+ lexptr++;
+ goto retry;
+
+ case '(':
+ paren_depth++;
+ lexptr++;
+ return c;
+
+ case ')':
+ if (paren_depth == 0)
+ return 0;
+ paren_depth--;
+ lexptr++;
+ return c;
+
+ case ',':
+ if (comma_terminates && paren_depth == 0)
+ return 0;
+ lexptr++;
+ return c;
+
+ case '.':
+ /* Might be a floating point number. */
+ if (lexptr[1] >= '0' && lexptr[1] <= '9')
+ break; /* Falls into number code. */
+ else
+ {
+ lexptr++;
+ return DOT;
+ }
+
+/* These are character tokens that appear as-is in the YACC grammar */
+ case '+':
+ case '-':
+ case '*':
+ case '/':
+ case '^':
+ case '<':
+ case '>':
+ case '[':
+ case ']':
+ case '=':
+ case '{':
+ case '}':
+ case '#':
+ case '@':
+ case '~':
+ case '&':
+ lexptr++;
+ return c;
+
+ case '\'' :
+ case '"':
+ quote = c;
+ for (namelen = 1; (c = tokstart[namelen]) != quote && c != '\0'; namelen++)
+ if (c == '\\')
+ {
+ c = tokstart[++namelen];
+ if (c >= '0' && c <= '9')
+ {
+ c = tokstart[++namelen];
+ if (c >= '0' && c <= '9')
+ c = tokstart[++namelen];
+ }
+ }
+ if(c != quote)
+ error("Unterminated string or character constant.");
+ yylval.sval.ptr = tokstart + 1;
+ yylval.sval.length = namelen - 1;
+ lexptr += namelen + 1;
+
+ if(namelen == 2) /* Single character */
+ {
+ yylval.ulval = tokstart[1];
+ return CHAR;
+ }
+ else
+ return STRING;
+ }
+
+ /* Is it a number? */
+ /* Note: We have already dealt with the case of the token '.'.
+ See case '.' above. */
+ if ((c >= '0' && c <= '9'))
+ {
+ /* It's a number. */
+ int got_dot = 0, got_e = 0;
+ register char *p = tokstart;
+ int toktype;
+
+ for (++p ;; ++p)
+ {
+ if (!got_e && (*p == 'e' || *p == 'E'))
+ got_dot = got_e = 1;
+ else if (!got_dot && *p == '.')
+ got_dot = 1;
+ else if (got_e && (p[-1] == 'e' || p[-1] == 'E')
+ && (*p == '-' || *p == '+'))
+ /* This is the sign of the exponent, not the end of the
+ number. */
+ continue;
+ else if ((*p < '0' || *p > '9') &&
+ (*p < 'A' || *p > 'F') &&
+ (*p != 'H')) /* Modula-2 hexadecimal number */
+ break;
+ }
+ toktype = parse_number (p - tokstart);
+ if (toktype == ERROR)
+ {
+ char *err_copy = (char *) alloca (p - tokstart + 1);
+
+ memcpy (err_copy, tokstart, p - tokstart);
+ err_copy[p - tokstart] = 0;
+ error ("Invalid number \"%s\".", err_copy);
+ }
+ lexptr = p;
+ return toktype;
+ }
+
+ if (!(c == '_' || c == '$'
+ || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')))
+ /* We must have come across a bad character (e.g. ';'). */
+ error ("Invalid character '%c' in expression.", c);
+
+ /* It's a name. See how long it is. */
+ namelen = 0;
+ for (c = tokstart[namelen];
+ (c == '_' || c == '$' || (c >= '0' && c <= '9')
+ || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'));
+ c = tokstart[++namelen])
+ ;
+
+ /* The token "if" terminates the expression and is NOT
+ removed from the input stream. */
+ if (namelen == 2 && tokstart[0] == 'i' && tokstart[1] == 'f')
+ {
+ return 0;
+ }
+
+ lexptr += namelen;
+
+ /* Handle the tokens $digits; also $ (short for $0) and $$ (short for $$1)
+ and $$digits (equivalent to $<-digits> if you could type that).
+ Make token type LAST, and put the number (the digits) in yylval. */
+
+ if (*tokstart == '$')
+ {
+ register int negate = 0;
+ c = 1;
+ /* Double dollar means negate the number and add -1 as well.
+ Thus $$ alone means -1. */
+ if (namelen >= 2 && tokstart[1] == '$')
+ {
+ negate = 1;
+ c = 2;
+ }
+ if (c == namelen)
+ {
+ /* Just dollars (one or two) */
+ yylval.lval = - negate;
+ return LAST;
+ }
+ /* Is the rest of the token digits? */
+ for (; c < namelen; c++)
+ if (!(tokstart[c] >= '0' && tokstart[c] <= '9'))
+ break;
+ if (c == namelen)
+ {
+ yylval.lval = atoi (tokstart + 1 + negate);
+ if (negate)
+ yylval.lval = - yylval.lval;
+ return LAST;
+ }
+ }
+
+ /* Handle tokens that refer to machine registers:
+ $ followed by a register name. */
+
+ if (*tokstart == '$') {
+ for (c = 0; c < NUM_REGS; c++)
+ if (namelen - 1 == strlen (reg_names[c])
+ && STREQN (tokstart + 1, reg_names[c], namelen - 1))
+ {
+ yylval.lval = c;
+ return REGNAME;
+ }
+ for (c = 0; c < num_std_regs; c++)
+ if (namelen - 1 == strlen (std_regs[c].name)
+ && STREQN (tokstart + 1, std_regs[c].name, namelen - 1))
+ {
+ yylval.lval = std_regs[c].regnum;
+ return REGNAME;
+ }
+ }
+
+
+ /* Lookup special keywords */
+ for(i = 0 ; i < sizeof(keytab) / sizeof(keytab[0]) ; i++)
+ if(namelen == strlen(keytab[i].keyw) && STREQN(tokstart,keytab[i].keyw,namelen))
+ return keytab[i].token;
+
+ yylval.sval.ptr = tokstart;
+ yylval.sval.length = namelen;
+
+ /* Any other names starting in $ are debugger internal variables. */
+
+ if (*tokstart == '$')
+ {
+ yylval.ivar = (struct internalvar *) lookup_internalvar (copy_name (yylval.sval) + 1);
+ return INTERNAL_VAR;
+ }
+
+
+ /* Use token-type BLOCKNAME for symbols that happen to be defined as
+ functions. If this is not so, then ...
+ Use token-type TYPENAME for symbols that happen to be defined
+ currently as names of types; NAME for other symbols.
+ The caller is not constrained to care about the distinction. */
+ {
+
+
+ char *tmp = copy_name (yylval.sval);
+ struct symbol *sym;
+
+ if (lookup_partial_symtab (tmp))
+ return BLOCKNAME;
+ sym = lookup_symbol (tmp, expression_context_block,
+ VAR_NAMESPACE, 0, NULL);
+ if (sym && SYMBOL_CLASS (sym) == LOC_BLOCK)
+ return BLOCKNAME;
+ if (lookup_typename (copy_name (yylval.sval), expression_context_block, 1))
+ return TYPENAME;
+
+ if(sym)
+ {
+ switch(sym->class)
+ {
+ case LOC_STATIC:
+ case LOC_REGISTER:
+ case LOC_ARG:
+ case LOC_REF_ARG:
+ case LOC_REGPARM:
+ case LOC_REGPARM_ADDR:
+ case LOC_LOCAL:
+ case LOC_LOCAL_ARG:
+ case LOC_BASEREG:
+ case LOC_BASEREG_ARG:
+ case LOC_CONST:
+ case LOC_CONST_BYTES:
+ case LOC_OPTIMIZED_OUT:
+ return NAME;
+
+ case LOC_TYPEDEF:
+ return TYPENAME;
+
+ case LOC_BLOCK:
+ return BLOCKNAME;
+
+ case LOC_UNDEF:
+ error("internal: Undefined class in m2lex()");
+
+ case LOC_LABEL:
+ error("internal: Unforseen case in m2lex()");
+ }
+ }
+ else
+ {
+ /* Built-in BOOLEAN type. This is sort of a hack. */
+ if(STREQN(tokstart,"TRUE",4))
+ {
+ yylval.ulval = 1;
+ return M2_TRUE;
+ }
+ else if(STREQN(tokstart,"FALSE",5))
+ {
+ yylval.ulval = 0;
+ return M2_FALSE;
+ }
+ }
+
+ /* Must be another type of name... */
+ return NAME;
+ }
+}
+
+#if 0 /* Unused */
+static char *
+make_qualname(mod,ident)
+ char *mod, *ident;
+{
+ char *new = malloc(strlen(mod)+strlen(ident)+2);
+
+ strcpy(new,mod);
+ strcat(new,".");
+ strcat(new,ident);
+ return new;
+}
+#endif /* 0 */
+
+void
+yyerror(msg)
+ char *msg; /* unused */
+{
+ printf("Parsing: %s\n",lexptr);
+ if (yychar < 256)
+ error("Invalid syntax in expression near character '%c'.",yychar);
+ else
+ error("Invalid syntax in expression");
+}
+
diff --git a/gnu/usr.bin/gdb/gdb/m2-lang.c b/gnu/usr.bin/gdb/gdb/m2-lang.c
new file mode 100644
index 0000000..6e15d30
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/m2-lang.c
@@ -0,0 +1,447 @@
+/* Modula 2 language support routines for GDB, the GNU debugger.
+ Copyright 1992 Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "defs.h"
+#include "symtab.h"
+#include "gdbtypes.h"
+#include "expression.h"
+#include "parser-defs.h"
+#include "language.h"
+#include "m2-lang.h"
+#include "c-lang.h"
+
+/* Print the character C on STREAM as part of the contents of a literal
+ string whose delimiter is QUOTER. Note that that format for printing
+ characters and strings is language specific.
+ FIXME: This is a copy of the same function from c-exp.y. It should
+ be replaced with a true Modula version.
+ */
+
+static void
+emit_char (c, stream, quoter)
+ register int c;
+ GDB_FILE *stream;
+ int quoter;
+{
+
+ c &= 0xFF; /* Avoid sign bit follies */
+
+ if (PRINT_LITERAL_FORM (c))
+ {
+ if (c == '\\' || c == quoter)
+ {
+ fputs_filtered ("\\", stream);
+ }
+ fprintf_filtered (stream, "%c", c);
+ }
+ else
+ {
+ switch (c)
+ {
+ case '\n':
+ fputs_filtered ("\\n", stream);
+ break;
+ case '\b':
+ fputs_filtered ("\\b", stream);
+ break;
+ case '\t':
+ fputs_filtered ("\\t", stream);
+ break;
+ case '\f':
+ fputs_filtered ("\\f", stream);
+ break;
+ case '\r':
+ fputs_filtered ("\\r", stream);
+ break;
+ case '\033':
+ fputs_filtered ("\\e", stream);
+ break;
+ case '\007':
+ fputs_filtered ("\\a", stream);
+ break;
+ default:
+ fprintf_filtered (stream, "\\%.3o", (unsigned int) c);
+ break;
+ }
+ }
+}
+
+/* FIXME: This is a copy of the same function from c-exp.y. It should
+ be replaced with a true Modula version. */
+
+static void
+m2_printchar (c, stream)
+ int c;
+ GDB_FILE *stream;
+{
+ fputs_filtered ("'", stream);
+ emit_char (c, stream, '\'');
+ fputs_filtered ("'", stream);
+}
+
+/* Print the character string STRING, printing at most LENGTH characters.
+ Printing stops early if the number hits print_max; repeat counts
+ are printed as appropriate. Print ellipses at the end if we
+ had to stop before printing LENGTH characters, or if FORCE_ELLIPSES.
+ FIXME: This is a copy of the same function from c-exp.y. It should
+ be replaced with a true Modula version. */
+
+static void
+m2_printstr (stream, string, length, force_ellipses)
+ GDB_FILE *stream;
+ char *string;
+ unsigned int length;
+ int force_ellipses;
+{
+ register unsigned int i;
+ unsigned int things_printed = 0;
+ int in_quotes = 0;
+ int need_comma = 0;
+ extern int inspect_it;
+ extern int repeat_count_threshold;
+ extern int print_max;
+
+ if (length == 0)
+ {
+ fputs_filtered ("\"\"", gdb_stdout);
+ return;
+ }
+
+ for (i = 0; i < length && things_printed < print_max; ++i)
+ {
+ /* Position of the character we are examining
+ to see whether it is repeated. */
+ unsigned int rep1;
+ /* Number of repetitions we have detected so far. */
+ unsigned int reps;
+
+ QUIT;
+
+ if (need_comma)
+ {
+ fputs_filtered (", ", stream);
+ need_comma = 0;
+ }
+
+ rep1 = i + 1;
+ reps = 1;
+ while (rep1 < length && string[rep1] == string[i])
+ {
+ ++rep1;
+ ++reps;
+ }
+
+ if (reps > repeat_count_threshold)
+ {
+ if (in_quotes)
+ {
+ if (inspect_it)
+ fputs_filtered ("\\\", ", stream);
+ else
+ fputs_filtered ("\", ", stream);
+ in_quotes = 0;
+ }
+ m2_printchar (string[i], stream);
+ fprintf_filtered (stream, " <repeats %u times>", reps);
+ i = rep1 - 1;
+ things_printed += repeat_count_threshold;
+ need_comma = 1;
+ }
+ else
+ {
+ if (!in_quotes)
+ {
+ if (inspect_it)
+ fputs_filtered ("\\\"", stream);
+ else
+ fputs_filtered ("\"", stream);
+ in_quotes = 1;
+ }
+ emit_char (string[i], stream, '"');
+ ++things_printed;
+ }
+ }
+
+ /* Terminate the quotes if necessary. */
+ if (in_quotes)
+ {
+ if (inspect_it)
+ fputs_filtered ("\\\"", stream);
+ else
+ fputs_filtered ("\"", stream);
+ }
+
+ if (force_ellipses || i < length)
+ fputs_filtered ("...", stream);
+}
+
+/* FIXME: This is a copy of c_create_fundamental_type(), before
+ all the non-C types were stripped from it. Needs to be fixed
+ by an experienced Modula programmer. */
+
+static struct type *
+m2_create_fundamental_type (objfile, typeid)
+ struct objfile *objfile;
+ int typeid;
+{
+ register struct type *type = NULL;
+
+ switch (typeid)
+ {
+ default:
+ /* FIXME: For now, if we are asked to produce a type not in this
+ language, create the equivalent of a C integer type with the
+ name "<?type?>". When all the dust settles from the type
+ reconstruction work, this should probably become an error. */
+ type = init_type (TYPE_CODE_INT,
+ TARGET_INT_BIT / TARGET_CHAR_BIT,
+ 0, "<?type?>", objfile);
+ warning ("internal error: no Modula fundamental type %d", typeid);
+ break;
+ case FT_VOID:
+ type = init_type (TYPE_CODE_VOID,
+ TARGET_CHAR_BIT / TARGET_CHAR_BIT,
+ 0, "void", objfile);
+ break;
+ case FT_BOOLEAN:
+ type = init_type (TYPE_CODE_BOOL,
+ TARGET_CHAR_BIT / TARGET_CHAR_BIT,
+ TYPE_FLAG_UNSIGNED, "boolean", objfile);
+ break;
+ case FT_STRING:
+ type = init_type (TYPE_CODE_STRING,
+ TARGET_CHAR_BIT / TARGET_CHAR_BIT,
+ 0, "string", objfile);
+ break;
+ case FT_CHAR:
+ type = init_type (TYPE_CODE_INT,
+ TARGET_CHAR_BIT / TARGET_CHAR_BIT,
+ 0, "char", objfile);
+ break;
+ case FT_SIGNED_CHAR:
+ type = init_type (TYPE_CODE_INT,
+ TARGET_CHAR_BIT / TARGET_CHAR_BIT,
+ 0, "signed char", objfile);
+ break;
+ case FT_UNSIGNED_CHAR:
+ type = init_type (TYPE_CODE_INT,
+ TARGET_CHAR_BIT / TARGET_CHAR_BIT,
+ TYPE_FLAG_UNSIGNED, "unsigned char", objfile);
+ break;
+ case FT_SHORT:
+ type = init_type (TYPE_CODE_INT,
+ TARGET_SHORT_BIT / TARGET_CHAR_BIT,
+ 0, "short", objfile);
+ break;
+ case FT_SIGNED_SHORT:
+ type = init_type (TYPE_CODE_INT,
+ TARGET_SHORT_BIT / TARGET_CHAR_BIT,
+ 0, "short", objfile); /* FIXME-fnf */
+ break;
+ case FT_UNSIGNED_SHORT:
+ type = init_type (TYPE_CODE_INT,
+ TARGET_SHORT_BIT / TARGET_CHAR_BIT,
+ TYPE_FLAG_UNSIGNED, "unsigned short", objfile);
+ break;
+ case FT_INTEGER:
+ type = init_type (TYPE_CODE_INT,
+ TARGET_INT_BIT / TARGET_CHAR_BIT,
+ 0, "int", objfile);
+ break;
+ case FT_SIGNED_INTEGER:
+ type = init_type (TYPE_CODE_INT,
+ TARGET_INT_BIT / TARGET_CHAR_BIT,
+ 0, "int", objfile); /* FIXME -fnf */
+ break;
+ case FT_UNSIGNED_INTEGER:
+ type = init_type (TYPE_CODE_INT,
+ TARGET_INT_BIT / TARGET_CHAR_BIT,
+ TYPE_FLAG_UNSIGNED, "unsigned int", objfile);
+ break;
+ case FT_FIXED_DECIMAL:
+ type = init_type (TYPE_CODE_INT,
+ TARGET_INT_BIT / TARGET_CHAR_BIT,
+ 0, "fixed decimal", objfile);
+ break;
+ case FT_LONG:
+ type = init_type (TYPE_CODE_INT,
+ TARGET_LONG_BIT / TARGET_CHAR_BIT,
+ 0, "long", objfile);
+ break;
+ case FT_SIGNED_LONG:
+ type = init_type (TYPE_CODE_INT,
+ TARGET_LONG_BIT / TARGET_CHAR_BIT,
+ 0, "long", objfile); /* FIXME -fnf */
+ break;
+ case FT_UNSIGNED_LONG:
+ type = init_type (TYPE_CODE_INT,
+ TARGET_LONG_BIT / TARGET_CHAR_BIT,
+ TYPE_FLAG_UNSIGNED, "unsigned long", objfile);
+ break;
+ case FT_LONG_LONG:
+ type = init_type (TYPE_CODE_INT,
+ TARGET_LONG_LONG_BIT / TARGET_CHAR_BIT,
+ 0, "long long", objfile);
+ break;
+ case FT_SIGNED_LONG_LONG:
+ type = init_type (TYPE_CODE_INT,
+ TARGET_LONG_LONG_BIT / TARGET_CHAR_BIT,
+ 0, "signed long long", objfile);
+ break;
+ case FT_UNSIGNED_LONG_LONG:
+ type = init_type (TYPE_CODE_INT,
+ TARGET_LONG_LONG_BIT / TARGET_CHAR_BIT,
+ TYPE_FLAG_UNSIGNED, "unsigned long long", objfile);
+ break;
+ case FT_FLOAT:
+ type = init_type (TYPE_CODE_FLT,
+ TARGET_FLOAT_BIT / TARGET_CHAR_BIT,
+ 0, "float", objfile);
+ break;
+ case FT_DBL_PREC_FLOAT:
+ type = init_type (TYPE_CODE_FLT,
+ TARGET_DOUBLE_BIT / TARGET_CHAR_BIT,
+ 0, "double", objfile);
+ break;
+ case FT_FLOAT_DECIMAL:
+ type = init_type (TYPE_CODE_FLT,
+ TARGET_DOUBLE_BIT / TARGET_CHAR_BIT,
+ 0, "floating decimal", objfile);
+ break;
+ case FT_EXT_PREC_FLOAT:
+ type = init_type (TYPE_CODE_FLT,
+ TARGET_LONG_DOUBLE_BIT / TARGET_CHAR_BIT,
+ 0, "long double", objfile);
+ break;
+ case FT_COMPLEX:
+ type = init_type (TYPE_CODE_FLT,
+ TARGET_COMPLEX_BIT / TARGET_CHAR_BIT,
+ 0, "complex", objfile);
+ break;
+ case FT_DBL_PREC_COMPLEX:
+ type = init_type (TYPE_CODE_FLT,
+ TARGET_DOUBLE_COMPLEX_BIT / TARGET_CHAR_BIT,
+ 0, "double complex", objfile);
+ break;
+ case FT_EXT_PREC_COMPLEX:
+ type = init_type (TYPE_CODE_FLT,
+ TARGET_DOUBLE_COMPLEX_BIT / TARGET_CHAR_BIT,
+ 0, "long double complex", objfile);
+ break;
+ }
+ return (type);
+}
+
+
+/* Table of operators and their precedences for printing expressions. */
+
+static const struct op_print m2_op_print_tab[] = {
+ {"+", BINOP_ADD, PREC_ADD, 0},
+ {"+", UNOP_PLUS, PREC_PREFIX, 0},
+ {"-", BINOP_SUB, PREC_ADD, 0},
+ {"-", UNOP_NEG, PREC_PREFIX, 0},
+ {"*", BINOP_MUL, PREC_MUL, 0},
+ {"/", BINOP_DIV, PREC_MUL, 0},
+ {"DIV", BINOP_INTDIV, PREC_MUL, 0},
+ {"MOD", BINOP_REM, PREC_MUL, 0},
+ {":=", BINOP_ASSIGN, PREC_ASSIGN, 1},
+ {"OR", BINOP_LOGICAL_OR, PREC_LOGICAL_OR, 0},
+ {"AND", BINOP_LOGICAL_AND, PREC_LOGICAL_AND, 0},
+ {"NOT", UNOP_LOGICAL_NOT, PREC_PREFIX, 0},
+ {"=", BINOP_EQUAL, PREC_EQUAL, 0},
+ {"<>", BINOP_NOTEQUAL, PREC_EQUAL, 0},
+ {"<=", BINOP_LEQ, PREC_ORDER, 0},
+ {">=", BINOP_GEQ, PREC_ORDER, 0},
+ {">", BINOP_GTR, PREC_ORDER, 0},
+ {"<", BINOP_LESS, PREC_ORDER, 0},
+ {"^", UNOP_IND, PREC_PREFIX, 0},
+ {"@", BINOP_REPEAT, PREC_REPEAT, 0},
+ {NULL, 0, 0, 0}
+};
+
+/* The built-in types of Modula-2. */
+
+struct type *builtin_type_m2_char;
+struct type *builtin_type_m2_int;
+struct type *builtin_type_m2_card;
+struct type *builtin_type_m2_real;
+struct type *builtin_type_m2_bool;
+
+struct type ** const (m2_builtin_types[]) =
+{
+ &builtin_type_m2_char,
+ &builtin_type_m2_int,
+ &builtin_type_m2_card,
+ &builtin_type_m2_real,
+ &builtin_type_m2_bool,
+ 0
+};
+
+const struct language_defn m2_language_defn = {
+ "modula-2",
+ language_m2,
+ m2_builtin_types,
+ range_check_on,
+ type_check_on,
+ m2_parse, /* parser */
+ m2_error, /* parser error function */
+ m2_printchar, /* Print character constant */
+ m2_printstr, /* function to print string constant */
+ m2_create_fundamental_type, /* Create fundamental type in this language */
+ m2_print_type, /* Print a type using appropriate syntax */
+ m2_val_print, /* Print a value using appropriate syntax */
+ c_value_print, /* Print a top-level value */
+ &builtin_type_m2_real, /* longest floating point type */
+ {"", "", "", ""}, /* Binary format info */
+ {"%loB", "", "o", "B"}, /* Octal format info */
+ {"%ld", "", "d", ""}, /* Decimal format info */
+ {"0%lXH", "0", "X", "H"}, /* Hex format info */
+ m2_op_print_tab, /* expression operators for printing */
+ LANG_MAGIC
+};
+
+/* Initialization for Modula-2 */
+
+void
+_initialize_m2_language ()
+{
+ /* Modula-2 "pervasive" types. NOTE: these can be redefined!!! */
+ builtin_type_m2_int =
+ init_type (TYPE_CODE_INT, TARGET_INT_BIT / TARGET_CHAR_BIT,
+ 0,
+ "INTEGER", (struct objfile *) NULL);
+ builtin_type_m2_card =
+ init_type (TYPE_CODE_INT, TARGET_INT_BIT / TARGET_CHAR_BIT,
+ TYPE_FLAG_UNSIGNED,
+ "CARDINAL", (struct objfile *) NULL);
+ builtin_type_m2_real =
+ init_type (TYPE_CODE_FLT, TARGET_FLOAT_BIT / TARGET_CHAR_BIT,
+ 0,
+ "REAL", (struct objfile *) NULL);
+ builtin_type_m2_char =
+ init_type (TYPE_CODE_CHAR, TARGET_CHAR_BIT / TARGET_CHAR_BIT,
+ TYPE_FLAG_UNSIGNED,
+ "CHAR", (struct objfile *) NULL);
+ builtin_type_m2_bool =
+ init_type (TYPE_CODE_BOOL, TARGET_INT_BIT / TARGET_CHAR_BIT,
+ TYPE_FLAG_UNSIGNED,
+ "BOOLEAN", (struct objfile *) NULL);
+
+ add_language (&m2_language_defn);
+}
diff --git a/gnu/usr.bin/gdb/gdb/m2-lang.h b/gnu/usr.bin/gdb/gdb/m2-lang.h
new file mode 100644
index 0000000..38f4687
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/m2-lang.h
@@ -0,0 +1,31 @@
+/* Modula 2 language support definitions for GDB, the GNU debugger.
+ Copyright 1992 Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+extern int
+m2_parse PARAMS ((void)); /* Defined in m2-exp.y */
+
+extern void
+m2_error PARAMS ((char *)); /* Defined in m2-exp.y */
+
+extern void /* Defined in m2-typeprint.c */
+m2_print_type PARAMS ((struct type *, char *, GDB_FILE *, int, int));
+
+extern int
+m2_val_print PARAMS ((struct type *, char *, CORE_ADDR, GDB_FILE *, int, int,
+ int, enum val_prettyprint));
diff --git a/gnu/usr.bin/gdb/gdb/m2-typeprint.c b/gnu/usr.bin/gdb/gdb/m2-typeprint.c
new file mode 100644
index 0000000..c9ee800
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/m2-typeprint.c
@@ -0,0 +1,49 @@
+/* Support for printing Modula 2 types for GDB, the GNU debugger.
+ Copyright 1986, 1988, 1989, 1991 Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "defs.h"
+#include "obstack.h"
+#include "bfd.h" /* Binary File Description */
+#include "symtab.h"
+#include "gdbtypes.h"
+#include "expression.h"
+#include "value.h"
+#include "gdbcore.h"
+#include "target.h"
+#include "command.h"
+#include "gdbcmd.h"
+#include "language.h"
+#include "demangle.h"
+#include "m2-lang.h"
+
+#include <string.h>
+#include <errno.h>
+
+void
+m2_print_type (type, varstring, stream, show, level)
+ struct type *type;
+ char *varstring;
+ GDB_FILE *stream;
+ int show;
+ int level;
+{
+ extern void c_print_type PARAMS ((struct type *, char *, GDB_FILE *, int, int));
+
+ c_print_type (type, varstring, stream, show, level); /* FIXME */
+}
diff --git a/gnu/usr.bin/gdb/gdb/m2-valprint.c b/gnu/usr.bin/gdb/gdb/m2-valprint.c
new file mode 100644
index 0000000..4a314b9
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/m2-valprint.c
@@ -0,0 +1,45 @@
+/* Support for printing Modula 2 values for GDB, the GNU debugger.
+ Copyright 1986, 1988, 1989, 1991 Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "defs.h"
+#include "obstack.h"
+#include "symtab.h"
+#include "gdbtypes.h"
+#include "valprint.h"
+
+/* FIXME: For now, just explicitly declare c_val_print and use it instead */
+
+int
+m2_val_print (type, valaddr, address, stream, format, deref_ref, recurse,
+ pretty)
+ struct type *type;
+ char *valaddr;
+ CORE_ADDR address;
+ GDB_FILE *stream;
+ int format;
+ int deref_ref;
+ int recurse;
+ enum val_prettyprint pretty;
+{
+ extern int
+ c_val_print PARAMS ((struct type *, char *, CORE_ADDR, GDB_FILE *, int, int,
+ int, enum val_prettyprint));
+ return (c_val_print (type, valaddr, address, stream, format, deref_ref,
+ recurse, pretty));
+}
diff --git a/gnu/usr.bin/gdb/gdb/main.c b/gnu/usr.bin/gdb/gdb/main.c
new file mode 100644
index 0000000..cd434e5
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/main.c
@@ -0,0 +1,571 @@
+/* Top level stuff for GDB, the GNU debugger.
+ Copyright 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994
+ Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "defs.h"
+#include <setjmp.h>
+#include "top.h"
+#include "target.h"
+#include "inferior.h"
+#include "call-cmds.h"
+
+#include "getopt.h"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <ctype.h>
+
+#include <string.h>
+/* R_OK lives in either unistd.h or sys/file.h. */
+#ifdef USG
+#include <unistd.h>
+#endif
+#ifndef NO_SYS_FILE
+#include <sys/file.h>
+#endif
+
+/* Temporary variable for SET_TOP_LEVEL. */
+static int top_level_val;
+
+/* Do a setjmp on error_return and quit_return. catch_errors is
+ generally a cleaner way to do this, but main() would look pretty
+ ugly if it had to use catch_errors each time. */
+
+#define SET_TOP_LEVEL() \
+ (((top_level_val = setjmp (error_return)) \
+ ? (PTR) 0 : (PTR) memcpy (quit_return, error_return, sizeof (jmp_buf))) \
+ , top_level_val)
+
+extern void gdb_init PARAMS ((void));
+
+int
+main (argc, argv)
+ int argc;
+ char **argv;
+{
+ int count;
+ static int quiet = 0;
+ static int batch = 0;
+
+ /* Pointers to various arguments from command line. */
+ char *symarg = NULL;
+ char *execarg = NULL;
+ char *corearg = NULL;
+ char *cdarg = NULL;
+ char *ttyarg = NULL;
+
+ /* These are static so that we can take their address in an initializer. */
+ static int print_help;
+ static int print_version;
+
+ /* Pointers to all arguments of --command option. */
+ char **cmdarg;
+ /* Allocated size of cmdarg. */
+ int cmdsize;
+ /* Number of elements of cmdarg used. */
+ int ncmd;
+
+ /* Indices of all arguments of --directory option. */
+ char **dirarg;
+ /* Allocated size. */
+ int dirsize;
+ /* Number of elements used. */
+ int ndir;
+
+ struct stat homebuf, cwdbuf;
+ char *homedir, *homeinit;
+
+ register int i;
+
+ /* This needs to happen before the first use of malloc. */
+ init_malloc ((PTR) NULL);
+
+#if defined (ALIGN_STACK_ON_STARTUP)
+ i = (int) &count & 0x3;
+ if (i != 0)
+ alloca (4 - i);
+#endif
+
+ /* If error() is called from initialization code, just exit */
+ if (SET_TOP_LEVEL ()) {
+ exit(1);
+ }
+
+ cmdsize = 1;
+ cmdarg = (char **) xmalloc (cmdsize * sizeof (*cmdarg));
+ ncmd = 0;
+ dirsize = 1;
+ dirarg = (char **) xmalloc (dirsize * sizeof (*dirarg));
+ ndir = 0;
+
+ quit_flag = 0;
+ line = (char *) xmalloc (linesize);
+ line[0] = '\0'; /* Terminate saved (now empty) cmd line */
+ instream = stdin;
+
+ getcwd (gdb_dirbuf, sizeof (gdb_dirbuf));
+ current_directory = gdb_dirbuf;
+
+#ifdef KERNEL_DEBUG
+ if (strstr(argv[0], "kgdb") != NULL)
+ kernel_debugging = 1;
+#endif
+
+ /* Parse arguments and options. */
+ {
+ int c;
+ /* When var field is 0, use flag field to record the equivalent
+ short option (or arbitrary numbers starting at 10 for those
+ with no equivalent). */
+ static struct option long_options[] =
+ {
+ {"readnow", no_argument, &readnow_symbol_files, 1},
+ {"r", no_argument, &readnow_symbol_files, 1},
+ {"mapped", no_argument, &mapped_symbol_files, 1},
+ {"m", no_argument, &mapped_symbol_files, 1},
+ {"quiet", no_argument, &quiet, 1},
+ {"q", no_argument, &quiet, 1},
+ {"silent", no_argument, &quiet, 1},
+ {"nx", no_argument, &inhibit_gdbinit, 1},
+ {"n", no_argument, &inhibit_gdbinit, 1},
+ {"batch", no_argument, &batch, 1},
+ {"epoch", no_argument, &epoch_interface, 1},
+
+ /* This is a synonym for "--annotate=1". --annotate is now preferred,
+ but keep this here for a long time because people will be running
+ emacses which use --fullname. */
+ {"fullname", no_argument, 0, 'f'},
+ {"f", no_argument, 0, 'f'},
+
+ {"annotate", required_argument, 0, 12},
+ {"help", no_argument, &print_help, 1},
+ {"se", required_argument, 0, 10},
+ {"symbols", required_argument, 0, 's'},
+ {"s", required_argument, 0, 's'},
+ {"exec", required_argument, 0, 'e'},
+ {"e", required_argument, 0, 'e'},
+ {"core", required_argument, 0, 'c'},
+ {"c", required_argument, 0, 'c'},
+ {"command", required_argument, 0, 'x'},
+ {"version", no_argument, &print_version, 1},
+ {"x", required_argument, 0, 'x'},
+ {"directory", required_argument, 0, 'd'},
+ {"cd", required_argument, 0, 11},
+ {"tty", required_argument, 0, 't'},
+ {"baud", required_argument, 0, 'b'},
+ {"b", required_argument, 0, 'b'},
+#ifdef KERNEL_DEBUG
+ {"kernel", no_argument, &kernel_debugging, 1},
+ {"k", no_argument, &kernel_debugging, 1},
+ {"wcore", no_argument, &kernel_writablecore, 1},
+ {"w", no_argument, &kernel_writablecore, 1},
+#endif
+/* Allow machine descriptions to add more options... */
+#ifdef ADDITIONAL_OPTIONS
+ ADDITIONAL_OPTIONS
+#endif
+ {0, no_argument, 0, 0},
+ };
+
+ while (1)
+ {
+ int option_index;
+
+ c = getopt_long_only (argc, argv, "",
+ long_options, &option_index);
+ if (c == EOF)
+ break;
+
+ /* Long option that takes an argument. */
+ if (c == 0 && long_options[option_index].flag == 0)
+ c = long_options[option_index].val;
+
+ switch (c)
+ {
+ case 0:
+ /* Long option that just sets a flag. */
+ break;
+ case 10:
+ symarg = optarg;
+ execarg = optarg;
+ break;
+ case 11:
+ cdarg = optarg;
+ break;
+ case 12:
+ /* FIXME: what if the syntax is wrong (e.g. not digits)? */
+ annotation_level = atoi (optarg);
+ break;
+ case 'f':
+ annotation_level = 1;
+ break;
+ case 's':
+ symarg = optarg;
+ break;
+ case 'e':
+ execarg = optarg;
+ break;
+ case 'c':
+ corearg = optarg;
+ break;
+ case 'x':
+ cmdarg[ncmd++] = optarg;
+ if (ncmd >= cmdsize)
+ {
+ cmdsize *= 2;
+ cmdarg = (char **) xrealloc ((char *)cmdarg,
+ cmdsize * sizeof (*cmdarg));
+ }
+ break;
+ case 'd':
+ dirarg[ndir++] = optarg;
+ if (ndir >= dirsize)
+ {
+ dirsize *= 2;
+ dirarg = (char **) xrealloc ((char *)dirarg,
+ dirsize * sizeof (*dirarg));
+ }
+ break;
+ case 't':
+ ttyarg = optarg;
+ break;
+ case 'q':
+ quiet = 1;
+ break;
+ case 'b':
+ {
+ int i;
+ char *p;
+
+ i = strtol (optarg, &p, 0);
+ if (i == 0 && p == optarg)
+
+ /* Don't use *_filtered or warning() (which relies on
+ current_target) until after initialize_all_files(). */
+
+ fprintf_unfiltered
+ (gdb_stderr,
+ "warning: could not set baud rate to `%s'.\n", optarg);
+ else
+ baud_rate = i;
+ }
+ break;
+#ifdef KERNEL_DEBUG
+ case 'k':
+ kernel_debugging = 1;
+ break;
+ case 'w':
+ kernel_writablecore = 1;
+ break;
+#endif
+
+#ifdef ADDITIONAL_OPTION_CASES
+ ADDITIONAL_OPTION_CASES
+#endif
+ case '?':
+ fprintf_unfiltered (gdb_stderr,
+ "Use `%s --help' for a complete list of options.\n",
+ argv[0]);
+ exit (1);
+ }
+ }
+
+ /* OK, that's all the options. The other arguments are filenames. */
+ count = 0;
+ for (; optind < argc; optind++)
+ switch (++count)
+ {
+ case 1:
+ symarg = argv[optind];
+ execarg = argv[optind];
+ break;
+ case 2:
+ corearg = argv[optind];
+ break;
+ case 3:
+ fprintf_unfiltered (gdb_stderr,
+ "Excess command line arguments ignored. (%s%s)\n",
+ argv[optind], (optind == argc - 1) ? "" : " ...");
+ break;
+ }
+ if (batch)
+ quiet = 1;
+ }
+
+ gdb_init ();
+
+ /* Do these (and anything which might call wrap_here or *_filtered)
+ after initialize_all_files. */
+ if (print_version)
+ {
+ print_gdb_version (gdb_stdout);
+ wrap_here ("");
+ printf_filtered ("\n");
+ exit (0);
+ }
+
+ if (print_help)
+ {
+ /* --version is intentionally not documented here, because we
+ are printing the version here, and the help is long enough
+ already. */
+
+ print_gdb_version (gdb_stdout);
+ /* Make sure the output gets printed. */
+ wrap_here ("");
+ printf_filtered ("\n");
+
+ /* But don't use *_filtered here. We don't want to prompt for continue
+ no matter how small the screen or how much we're going to print. */
+ fputs_unfiltered ("\
+This is the GNU debugger. Usage:\n\
+ gdb [options] [executable-file [core-file or process-id]]\n\
+Options:\n\
+ --help Print this message.\n\
+ --quiet Do not print version number on startup.\n\
+ --fullname Output information used by emacs-GDB interface.\n\
+ --epoch Output information used by epoch emacs-GDB interface.\n\
+ --batch Exit after processing options.\n\
+ --nx Do not read .gdbinit file.\n\
+ --tty=TTY Use TTY for input/output by the program being debugged.\n\
+ --cd=DIR Change current directory to DIR.\n\
+ --directory=DIR Search for source files in DIR.\n\
+ --command=FILE Execute GDB commands from FILE.\n\
+ --symbols=SYMFILE Read symbols from SYMFILE.\n\
+ --exec=EXECFILE Use EXECFILE as the executable.\n\
+ --se=FILE Use FILE as symbol file and executable file.\n\
+ --core=COREFILE Analyze the core dump COREFILE.\n\
+ -b BAUDRATE Set serial port baud rate used for remote debugging.\n\
+ --mapped Use mapped symbol files if supported on this system.\n\
+ --readnow Fully read symbol files on first access.\n\
+", gdb_stdout);
+#ifdef KERNEL_DEBUG
+ fputs_unfiltered ("\
+ --kernel Enable kernel debugging.\n\
+ --wcore Make core file writable (only works for /dev/mem).\n\
+ This option only works while debugging a kernel !!\n\
+", gdb_stdout);
+#endif /* KERNEL_DEBUGGING */
+#ifdef ADDITIONAL_OPTION_HELP
+ fputs_unfiltered (ADDITIONAL_OPTION_HELP, gdb_stdout);
+#endif
+ fputs_unfiltered ("\n\
+For more information, type \"help\" from within GDB, or consult the\n\
+GDB manual (available as on-line info or a printed manual).\n", gdb_stdout);
+ exit (0);
+ }
+
+ if (!quiet)
+ {
+ /* Print all the junk at the top, with trailing "..." if we are about
+ to read a symbol file (possibly slowly). */
+ print_gnu_advertisement ();
+ print_gdb_version (gdb_stdout);
+ if (symarg)
+ printf_filtered ("..");
+ wrap_here("");
+ gdb_flush (gdb_stdout); /* Force to screen during slow operations */
+ }
+
+ error_pre_print = "\n\n";
+ /* We may get more than one warning, don't double space all of them... */
+ warning_pre_print = "\nwarning: ";
+
+ /* Read and execute $HOME/.gdbinit file, if it exists. This is done
+ *before* all the command line arguments are processed; it sets
+ global parameters, which are independent of what file you are
+ debugging or what directory you are in. */
+ homedir = getenv ("HOME");
+ if (homedir)
+ {
+ homeinit = (char *) alloca (strlen (getenv ("HOME")) +
+ strlen (gdbinit) + 10);
+ strcpy (homeinit, getenv ("HOME"));
+ strcat (homeinit, "/");
+ strcat (homeinit, gdbinit);
+ if (!inhibit_gdbinit && access (homeinit, R_OK) == 0)
+ {
+ if (!SET_TOP_LEVEL ())
+ source_command (homeinit, 0);
+ }
+ do_cleanups (ALL_CLEANUPS);
+
+ /* Do stats; no need to do them elsewhere since we'll only
+ need them if homedir is set. Make sure that they are
+ zero in case one of them fails (this guarantees that they
+ won't match if either exists). */
+
+ memset (&homebuf, 0, sizeof (struct stat));
+ memset (&cwdbuf, 0, sizeof (struct stat));
+
+ stat (homeinit, &homebuf);
+ stat (gdbinit, &cwdbuf); /* We'll only need this if
+ homedir was set. */
+ }
+
+ /* Now perform all the actions indicated by the arguments. */
+ if (cdarg != NULL)
+ {
+ if (!SET_TOP_LEVEL ())
+ {
+ cd_command (cdarg, 0);
+ }
+ }
+ do_cleanups (ALL_CLEANUPS);
+
+ for (i = 0; i < ndir; i++)
+ if (!SET_TOP_LEVEL ())
+ directory_command (dirarg[i], 0);
+ free ((PTR)dirarg);
+ do_cleanups (ALL_CLEANUPS);
+
+ if (execarg != NULL
+ && symarg != NULL
+ && STREQ (execarg, symarg))
+ {
+ /* The exec file and the symbol-file are the same. If we can't open
+ it, better only print one error message. */
+ if (!SET_TOP_LEVEL ())
+ {
+ exec_file_command (execarg, !batch);
+ symbol_file_command (symarg, 0);
+ }
+ }
+ else
+ {
+ if (execarg != NULL)
+ if (!SET_TOP_LEVEL ())
+ exec_file_command (execarg, !batch);
+ if (symarg != NULL)
+ if (!SET_TOP_LEVEL ())
+ symbol_file_command (symarg, 0);
+ }
+ do_cleanups (ALL_CLEANUPS);
+
+ /* After the symbol file has been read, print a newline to get us
+ beyond the copyright line... But errors should still set off
+ the error message with a (single) blank line. */
+ if (!quiet)
+ printf_filtered ("\n");
+ error_pre_print = "\n";
+ warning_pre_print = "\nwarning: ";
+
+ if (corearg != NULL)
+ if (!SET_TOP_LEVEL ())
+ core_file_command (corearg, !batch);
+ else if (isdigit (corearg[0]) && !SET_TOP_LEVEL ())
+ attach_command (corearg, !batch);
+ do_cleanups (ALL_CLEANUPS);
+
+ if (ttyarg != NULL)
+ if (!SET_TOP_LEVEL ())
+ tty_command (ttyarg, !batch);
+ do_cleanups (ALL_CLEANUPS);
+
+#ifdef ADDITIONAL_OPTION_HANDLER
+ ADDITIONAL_OPTION_HANDLER;
+#endif
+
+ /* Error messages should no longer be distinguished with extra output. */
+ error_pre_print = 0;
+ warning_pre_print = "warning: ";
+
+ /* Read the .gdbinit file in the current directory, *if* it isn't
+ the same as the $HOME/.gdbinit file (it should exist, also). */
+
+ if (!homedir
+ || memcmp ((char *) &homebuf, (char *) &cwdbuf, sizeof (struct stat)))
+ if (!inhibit_gdbinit && access (gdbinit, R_OK) == 0)
+ {
+ if (!SET_TOP_LEVEL ())
+ source_command (gdbinit, 0);
+ }
+ do_cleanups (ALL_CLEANUPS);
+
+ for (i = 0; i < ncmd; i++)
+ {
+ if (!SET_TOP_LEVEL ())
+ {
+ if (cmdarg[i][0] == '-' && cmdarg[i][1] == '\0')
+ read_command_file (stdin);
+ else
+ source_command (cmdarg[i], !batch);
+ do_cleanups (ALL_CLEANUPS);
+ }
+ }
+ free ((PTR)cmdarg);
+
+ /* Read in the old history after all the command files have been read. */
+ init_history();
+
+ if (batch)
+ {
+ /* We have hit the end of the batch file. */
+ exit (0);
+ }
+
+ /* Do any host- or target-specific hacks. This is used for i960 targets
+ to force the user to set a nindy target and spec its parameters. */
+
+#ifdef BEFORE_MAIN_LOOP_HOOK
+ BEFORE_MAIN_LOOP_HOOK;
+#endif
+
+ /* The command loop. */
+
+ while (1)
+ {
+ if (!SET_TOP_LEVEL ())
+ {
+ do_cleanups (ALL_CLEANUPS); /* Do complete cleanup */
+ command_loop ();
+ quit_command ((char *)0, instream == stdin);
+ }
+ }
+ /* No exit -- exit is through quit_command. */
+}
+
+void
+init_proc ()
+{
+}
+
+int
+proc_wait (pid, status)
+ int pid;
+ int *status;
+{
+#ifndef __GO32__
+ return wait (status);
+#endif
+}
+
+void
+proc_remove_foreign (pid)
+ int pid;
+{
+}
+
+void
+fputs_unfiltered (linebuffer, stream)
+ const char *linebuffer;
+ FILE *stream;
+{
+ fputs (linebuffer, stream);
+}
diff --git a/gnu/usr.bin/gdb/gdb/maint.c b/gnu/usr.bin/gdb/gdb/maint.c
new file mode 100644
index 0000000..ce39506
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/maint.c
@@ -0,0 +1,295 @@
+/* Support for GDB maintenance commands.
+ Copyright (C) 1992, 1993, 1994 Free Software Foundation, Inc.
+ Written by Fred Fish at Cygnus Support.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+
+#include "defs.h"
+
+#if MAINTENANCE_CMDS /* Entire file goes away if not including maint cmds */
+
+#include <signal.h>
+#include "command.h"
+#include "gdbcmd.h"
+#include "symtab.h"
+#include "gdbtypes.h"
+#include "demangle.h"
+#include "gdbcore.h"
+#include "expression.h" /* For language.h */
+#include "language.h"
+
+static void
+maintenance_command PARAMS ((char *, int));
+
+static void
+maintenance_dump_me PARAMS ((char *, int));
+
+static void
+maintenance_demangle PARAMS ((char *, int));
+
+/*
+
+LOCAL FUNCTION
+
+ maintenance_command -- access the maintenance subcommands
+
+SYNOPSIS
+
+ void maintenance_command (char *args, int from_tty)
+
+DESCRIPTION
+
+*/
+
+static void
+maintenance_command (args, from_tty)
+ char *args;
+ int from_tty;
+{
+ printf_unfiltered ("\"maintenance\" must be followed by the name of a maintenance command.\n");
+ help_list (maintenancelist, "maintenance ", -1, gdb_stdout);
+}
+
+
+/* ARGSUSED */
+static void
+maintenance_dump_me (args, from_tty)
+ char *args;
+ int from_tty;
+{
+ if (query ("Should GDB dump core? "))
+ {
+ signal (SIGQUIT, SIG_DFL);
+ kill (getpid (), SIGQUIT);
+ }
+}
+
+/* Someday we should allow demangling for things other than just
+ explicit strings. For example, we might want to be able to
+ specify the address of a string in either GDB's process space
+ or the debuggee's process space, and have gdb fetch and demangle
+ that string. If we have a char* pointer "ptr" that points to
+ a string, we might want to be able to given just the name and
+ have GDB demangle and print what it points to, etc. (FIXME) */
+
+static void
+maintenance_demangle (args, from_tty)
+ char *args;
+ int from_tty;
+{
+ char *demangled;
+
+ if (args == NULL || *args == '\0')
+ {
+ printf_unfiltered ("\"maintenance demangle\" takes an argument to demangle.\n");
+ }
+ else
+ {
+ demangled = cplus_demangle (args, DMGL_ANSI | DMGL_PARAMS);
+ if (demangled != NULL)
+ {
+ printf_unfiltered ("%s\n", demangled);
+ free (demangled);
+ }
+ else
+ {
+ printf_unfiltered ("Can't demangle \"%s\"\n", args);
+ }
+ }
+}
+
+/* The "maintenance info" command is defined as a prefix, with allow_unknown 0.
+ Therefore, its own definition is called only for "maintenance info" with
+ no args. */
+
+/* ARGSUSED */
+static void
+maintenance_info_command (arg, from_tty)
+ char *arg;
+ int from_tty;
+{
+ printf_unfiltered ("\"maintenance info\" must be followed by the name of an info command.\n");
+ help_list (maintenanceinfolist, "maintenance info ", -1, gdb_stdout);
+}
+
+static void
+print_section_table (abfd, asect, ignore)
+ bfd *abfd;
+ asection *asect;
+ PTR ignore;
+{
+ flagword flags;
+
+ flags = bfd_get_section_flags (abfd, asect);
+
+ /* FIXME-32x64: Need print_address_numeric with field width. */
+ printf_filtered (" %s",
+ local_hex_string_custom
+ ((unsigned long) bfd_section_vma (abfd, asect), "08l"));
+ printf_filtered ("->%s",
+ local_hex_string_custom
+ ((unsigned long) (bfd_section_vma (abfd, asect)
+ + bfd_section_size (abfd, asect)),
+ "08l"));
+ printf_filtered (" at %s",
+ local_hex_string_custom
+ ((unsigned long) asect->filepos, "08l"));
+ printf_filtered (": %s", bfd_section_name (abfd, asect));
+
+ if (flags & SEC_ALLOC)
+ printf_filtered (" ALLOC");
+ if (flags & SEC_LOAD)
+ printf_filtered (" LOAD");
+ if (flags & SEC_RELOC)
+ printf_filtered (" RELOC");
+ if (flags & SEC_READONLY)
+ printf_filtered (" READONLY");
+ if (flags & SEC_CODE)
+ printf_filtered (" CODE");
+ if (flags & SEC_DATA)
+ printf_filtered (" DATA");
+ if (flags & SEC_ROM)
+ printf_filtered (" ROM");
+ if (flags & SEC_CONSTRUCTOR)
+ printf_filtered (" CONSTRUCTOR");
+ if (flags & SEC_HAS_CONTENTS)
+ printf_filtered (" HAS_CONTENTS");
+ if (flags & SEC_NEVER_LOAD)
+ printf_filtered (" NEVER_LOAD");
+ if (flags & SEC_COFF_SHARED_LIBRARY)
+ printf_filtered (" COFF_SHARED_LIBRARY");
+ if (flags & SEC_IS_COMMON)
+ printf_filtered (" IS_COMMON");
+
+ printf_filtered ("\n");
+}
+
+/* ARGSUSED */
+static void
+maintenance_info_sections (arg, from_tty)
+ char *arg;
+ int from_tty;
+{
+ if (exec_bfd)
+ {
+ printf_filtered ("Exec file:\n");
+ printf_filtered (" `%s', ", bfd_get_filename(exec_bfd));
+ wrap_here (" ");
+ printf_filtered ("file type %s.\n", bfd_get_target(exec_bfd));
+ bfd_map_over_sections(exec_bfd, print_section_table, 0);
+ }
+
+ if (core_bfd)
+ {
+ printf_filtered ("Core file:\n");
+ printf_filtered (" `%s', ", bfd_get_filename(core_bfd));
+ wrap_here (" ");
+ printf_filtered ("file type %s.\n", bfd_get_target(core_bfd));
+ bfd_map_over_sections(core_bfd, print_section_table, 0);
+ }
+}
+
+/* The "maintenance print" command is defined as a prefix, with allow_unknown
+ 0. Therefore, its own definition is called only for "maintenance print"
+ with no args. */
+
+/* ARGSUSED */
+static void
+maintenance_print_command (arg, from_tty)
+ char *arg;
+ int from_tty;
+{
+ printf_unfiltered ("\"maintenance print\" must be followed by the name of a print command.\n");
+ help_list (maintenanceprintlist, "maintenance print ", -1, gdb_stdout);
+}
+
+#endif /* MAINTENANCE_CMDS */
+
+void
+_initialize_maint_cmds ()
+{
+#if MAINTENANCE_CMDS /* Entire file goes away if not including maint cmds */
+ add_prefix_cmd ("maintenance", class_maintenance, maintenance_command,
+ "Commands for use by GDB maintainers.\n\
+Includes commands to dump specific internal GDB structures in\n\
+a human readable form, to cause GDB to deliberately dump core,\n\
+to test internal functions such as the C++ demangler, etc.",
+ &maintenancelist, "maintenance ", 0,
+ &cmdlist);
+
+ add_com_alias ("mt", "maintenance", class_maintenance, 1);
+
+ add_prefix_cmd ("info", class_maintenance, maintenance_info_command,
+ "Commands for showing internal info about the program being debugged.",
+ &maintenanceinfolist, "maintenance info ", 0,
+ &maintenancelist);
+
+ add_cmd ("sections", class_maintenance, maintenance_info_sections,
+ "List the BFD sections of the exec and core files.",
+ &maintenanceinfolist);
+
+ add_prefix_cmd ("print", class_maintenance, maintenance_print_command,
+ "Maintenance command for printing GDB internal state.",
+ &maintenanceprintlist, "maintenance print ", 0,
+ &maintenancelist);
+
+ add_cmd ("dump-me", class_maintenance, maintenance_dump_me,
+ "Get fatal error; make debugger dump its core.\n\
+GDB sets it's handling of SIGQUIT back to SIG_DFL and then sends\n\
+itself a SIGQUIT signal.",
+ &maintenancelist);
+
+ add_cmd ("demangle", class_maintenance, maintenance_demangle,
+ "Demangle a C++ mangled name.\n\
+Call internal GDB demangler routine to demangle a C++ link name\n\
+and prints the result.",
+ &maintenancelist);
+
+ add_cmd ("type", class_maintenance, maintenance_print_type,
+ "Print a type chain for a given symbol.\n\
+For each node in a type chain, print the raw data for each member of\n\
+the type structure, and the interpretation of the data.",
+ &maintenanceprintlist);
+
+ add_cmd ("symbols", class_maintenance, maintenance_print_symbols,
+ "Print dump of current symbol definitions.\n\
+Entries in the full symbol table are dumped to file OUTFILE.\n\
+If a SOURCE file is specified, dump only that file's symbols.",
+ &maintenanceprintlist);
+
+ add_cmd ("msymbols", class_maintenance, maintenance_print_msymbols,
+ "Print dump of current minimal symbol definitions.\n\
+Entries in the minimal symbol table are dumped to file OUTFILE.\n\
+If a SOURCE file is specified, dump only that file's minimal symbols.",
+ &maintenanceprintlist);
+
+ add_cmd ("psymbols", class_maintenance, maintenance_print_psymbols,
+ "Print dump of current partial symbol definitions.\n\
+Entries in the partial symbol table are dumped to file OUTFILE.\n\
+If a SOURCE file is specified, dump only that file's partial symbols.",
+ &maintenanceprintlist);
+
+ add_cmd ("objfiles", class_maintenance, maintenance_print_objfiles,
+ "Print dump of current object file definitions.",
+ &maintenanceprintlist);
+
+ add_cmd ("check-symtabs", class_maintenance, maintenance_check_symtabs,
+ "Check consistency of psymtabs and symtabs.",
+ &maintenancelist);
+#endif /* MAINTENANCE_CMDS */
+}
diff --git a/gnu/usr.bin/gdb/gdb/mdebugread.c b/gnu/usr.bin/gdb/gdb/mdebugread.c
new file mode 100644
index 0000000..9c1309f
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/mdebugread.c
@@ -0,0 +1,4053 @@
+/* Read a symbol table in ECOFF format (Third-Eye).
+ Copyright 1986, 1987, 1989, 1990, 1991, 1992, 1993, 1994
+ Free Software Foundation, Inc.
+ Original version contributed by Alessandro Forin (af@cs.cmu.edu) at
+ CMU. Major work by Per Bothner, John Gilmore and Ian Lance Taylor
+ at Cygnus Support.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* This module provides the function mdebug_build_psymtabs. It reads
+ ECOFF debugging information into partial symbol tables. The
+ debugging information is read from two structures. A struct
+ ecoff_debug_swap includes the sizes of each ECOFF structure and
+ swapping routines; these are fixed for a particular target. A
+ struct ecoff_debug_info points to the debugging information for a
+ particular object file.
+
+ ECOFF symbol tables are mostly written in the byte order of the
+ target machine. However, one section of the table (the auxiliary
+ symbol information) is written in the host byte order. There is a
+ bit in the other symbol info which describes which host byte order
+ was used. ECOFF thereby takes the trophy from Intel `b.out' for
+ the most brain-dead adaptation of a file format to byte order.
+
+ This module can read all four of the known byte-order combinations,
+ on any type of host. */
+
+#include "defs.h"
+#include "symtab.h"
+#include "gdbtypes.h"
+#include "gdbcore.h"
+#include "symfile.h"
+#include "objfiles.h"
+#include "obstack.h"
+#include "buildsym.h"
+#include "stabsread.h"
+#include "complaints.h"
+
+#if !defined (SEEK_SET)
+#define SEEK_SET 0
+#define SEEK_CUR 1
+#endif
+
+/* These are needed if the tm.h file does not contain the necessary
+ mips specific definitions. */
+
+#ifndef MIPS_EFI_SYMBOL_NAME
+#define MIPS_EFI_SYMBOL_NAME "__GDB_EFI_INFO__"
+#include "coff/sym.h"
+#include "coff/symconst.h"
+typedef struct mips_extra_func_info {
+ long numargs;
+ PDR pdr;
+} *mips_extra_func_info_t;
+#ifndef RA_REGNUM
+#define RA_REGNUM 0
+#endif
+#endif
+
+#ifdef USG
+#include <sys/types.h>
+#endif
+
+#include <sys/param.h>
+#include <sys/file.h>
+#include <sys/stat.h>
+#include <string.h>
+
+#include "gdb-stabs.h"
+
+#include "bfd.h"
+
+#include "coff/ecoff.h" /* COFF-like aspects of ecoff files */
+
+#include "libaout.h" /* Private BFD a.out information. */
+#include "aout/aout64.h"
+#include "aout/stab_gnu.h" /* STABS information */
+
+#include "expression.h"
+#include "language.h" /* Needed inside partial-stab.h */
+
+/* Provide a default mapping from a ecoff register number to a gdb REGNUM. */
+#ifndef ECOFF_REG_TO_REGNUM
+#define ECOFF_REG_TO_REGNUM(num) (num)
+#endif
+
+/* Each partial symbol table entry contains a pointer to private data
+ for the read_symtab() function to use when expanding a partial
+ symbol table entry to a full symbol table entry.
+
+ For mdebugread this structure contains the index of the FDR that this
+ psymtab represents and a pointer to the BFD that the psymtab was
+ created from. */
+
+#define PST_PRIVATE(p) ((struct symloc *)(p)->read_symtab_private)
+#define FDR_IDX(p) (PST_PRIVATE(p)->fdr_idx)
+#define CUR_BFD(p) (PST_PRIVATE(p)->cur_bfd)
+#define DEBUG_SWAP(p) (PST_PRIVATE(p)->debug_swap)
+#define DEBUG_INFO(p) (PST_PRIVATE(p)->debug_info)
+#define PENDING_LIST(p) (PST_PRIVATE(p)->pending_list)
+
+struct symloc
+{
+ int fdr_idx;
+ bfd *cur_bfd;
+ const struct ecoff_debug_swap *debug_swap;
+ struct ecoff_debug_info *debug_info;
+ struct mdebug_pending **pending_list;
+ EXTR *extern_tab; /* Pointer to external symbols for this file. */
+ int extern_count; /* Size of extern_tab. */
+ enum language pst_language;
+};
+
+/* Things we import explicitly from other modules */
+
+extern int info_verbose;
+
+/* Various complaints about symbol reading that don't abort the process */
+
+static struct complaint bad_file_number_complaint =
+{"bad file number %d", 0, 0};
+
+static struct complaint index_complaint =
+{"bad aux index at symbol %s", 0, 0};
+
+static struct complaint aux_index_complaint =
+{"bad proc end in aux found from symbol %s", 0, 0};
+
+static struct complaint block_index_complaint =
+{"bad aux index at block symbol %s", 0, 0};
+
+static struct complaint unknown_ext_complaint =
+{"unknown external symbol %s", 0, 0};
+
+static struct complaint unknown_sym_complaint =
+{"unknown local symbol %s", 0, 0};
+
+static struct complaint unknown_st_complaint =
+{"with type %d", 0, 0};
+
+static struct complaint block_overflow_complaint =
+{"block containing %s overfilled", 0, 0};
+
+static struct complaint basic_type_complaint =
+{"cannot map ECOFF basic type 0x%x for %s", 0, 0};
+
+static struct complaint unknown_type_qual_complaint =
+{"unknown type qualifier 0x%x", 0, 0};
+
+static struct complaint array_index_type_complaint =
+{"illegal array index type for %s, assuming int", 0, 0};
+
+static struct complaint bad_tag_guess_complaint =
+{"guessed tag type of %s incorrectly", 0, 0};
+
+static struct complaint block_member_complaint =
+{"declaration block contains unhandled symbol type %d", 0, 0};
+
+static struct complaint stEnd_complaint =
+{"stEnd with storage class %d not handled", 0, 0};
+
+static struct complaint unknown_mdebug_symtype_complaint =
+{"unknown symbol type 0x%x", 0, 0};
+
+static struct complaint stab_unknown_complaint =
+{"unknown stabs symbol %s", 0, 0};
+
+static struct complaint pdr_for_nonsymbol_complaint =
+{"PDR for %s, but no symbol", 0, 0};
+
+static struct complaint pdr_static_symbol_complaint =
+{"can't handle PDR for static proc at 0x%lx", 0, 0};
+
+static struct complaint bad_setjmp_pdr_complaint =
+{"fixing bad setjmp PDR from libc", 0, 0};
+
+static struct complaint bad_fbitfield_complaint =
+{"can't handle TIR fBitfield for %s", 0, 0};
+
+static struct complaint bad_continued_complaint =
+{"illegal TIR continued for %s", 0, 0};
+
+static struct complaint bad_rfd_entry_complaint =
+{"bad rfd entry for %s: file %d, index %d", 0, 0};
+
+static struct complaint unexpected_type_code_complaint =
+{"unexpected type code for %s", 0, 0};
+
+static struct complaint unable_to_cross_ref_complaint =
+{"unable to cross ref btTypedef for %s", 0, 0};
+
+static struct complaint illegal_forward_tq0_complaint =
+{"illegal tq0 in forward typedef for %s", 0, 0};
+
+static struct complaint illegal_forward_bt_complaint =
+{"illegal bt %d in forward typedef for %s", 0, 0};
+
+static struct complaint bad_linetable_guess_complaint =
+{"guessed size of linetable for %s incorrectly", 0, 0};
+
+static struct complaint bad_ext_ifd_complaint =
+{"bad ifd for external symbol: %d (max %d)", 0, 0};
+
+static struct complaint bad_ext_iss_complaint =
+{"bad iss for external symbol: %ld (max %ld)", 0, 0};
+
+/* Macros and extra defs */
+
+/* Puns: hard to find whether -g was used and how */
+
+#define MIN_GLEVEL GLEVEL_0
+#define compare_glevel(a,b) \
+ (((a) == GLEVEL_3) ? ((b) < GLEVEL_3) : \
+ ((b) == GLEVEL_3) ? -1 : (int)((b) - (a)))
+
+/* Things that really are local to this module */
+
+/* Remember what we deduced to be the source language of this psymtab. */
+
+static enum language psymtab_language = language_unknown;
+
+/* Current BFD. */
+
+static bfd *cur_bfd;
+
+/* How to parse debugging information for CUR_BFD. */
+
+static const struct ecoff_debug_swap *debug_swap;
+
+/* Pointers to debugging information for CUR_BFD. */
+
+static struct ecoff_debug_info *debug_info;
+
+/* Pointer to current file decriptor record, and its index */
+
+static FDR *cur_fdr;
+static int cur_fd;
+
+/* Index of current symbol */
+
+static int cur_sdx;
+
+/* Note how much "debuggable" this image is. We would like
+ to see at least one FDR with full symbols */
+
+static max_gdbinfo;
+static max_glevel;
+
+/* When examining .o files, report on undefined symbols */
+
+static int n_undef_symbols, n_undef_labels, n_undef_vars, n_undef_procs;
+
+/* Pseudo symbol to use when putting stabs into the symbol table. */
+
+static char stabs_symbol[] = STABS_SYMBOL;
+
+/* Types corresponding to btComplex, btDComplex, etc. These are here
+ rather than in gdbtypes.c or some such, because the meaning of codes
+ like btComplex is specific to the mdebug debug format. FIXME: We should
+ be using our own types thoughout this file, instead of sometimes using
+ builtin_type_*. */
+
+static struct type *mdebug_type_complex;
+static struct type *mdebug_type_double_complex;
+static struct type *mdebug_type_fixed_dec;
+static struct type *mdebug_type_float_dec;
+static struct type *mdebug_type_string;
+
+/* Forward declarations */
+
+static int
+upgrade_type PARAMS ((int, struct type **, int, union aux_ext *, int, char *));
+
+static void
+parse_partial_symbols PARAMS ((struct objfile *,
+ struct section_offsets *));
+
+static FDR
+*get_rfd PARAMS ((int, int));
+
+static int
+has_opaque_xref PARAMS ((FDR *, SYMR *));
+
+static int
+cross_ref PARAMS ((int, union aux_ext *, struct type **, enum type_code,
+ char **, int, char *));
+
+static struct symbol *
+new_symbol PARAMS ((char *));
+
+static struct type *
+new_type PARAMS ((char *));
+
+static struct block *
+new_block PARAMS ((int));
+
+static struct symtab *
+new_symtab PARAMS ((char *, int, int, struct objfile *));
+
+static struct linetable *
+new_linetable PARAMS ((int));
+
+static struct blockvector *
+new_bvect PARAMS ((int));
+
+static int
+parse_symbol PARAMS ((SYMR *, union aux_ext *, char *, int, struct section_offsets *));
+
+static struct type *
+parse_type PARAMS ((int, union aux_ext *, unsigned int, int *, int, char *));
+
+static struct symbol *
+mylookup_symbol PARAMS ((char *, struct block *, enum namespace,
+ enum address_class));
+
+static struct block *
+shrink_block PARAMS ((struct block *, struct symtab *));
+
+static PTR
+xzalloc PARAMS ((unsigned int));
+
+static void
+sort_blocks PARAMS ((struct symtab *));
+
+static int
+compare_blocks PARAMS ((const void *, const void *));
+
+static struct partial_symtab *
+new_psymtab PARAMS ((char *, struct objfile *, struct section_offsets *));
+
+static void
+psymtab_to_symtab_1 PARAMS ((struct partial_symtab *, char *));
+
+static void
+add_block PARAMS ((struct block *, struct symtab *));
+
+static void
+add_symbol PARAMS ((struct symbol *, struct block *));
+
+static int
+add_line PARAMS ((struct linetable *, int, CORE_ADDR, int));
+
+static struct linetable *
+shrink_linetable PARAMS ((struct linetable *));
+
+static void
+handle_psymbol_enumerators PARAMS ((struct objfile *, FDR *, int));
+
+static char *
+mdebug_next_symbol_text PARAMS ((void));
+
+/* Address bounds for the signal trampoline in inferior, if any */
+
+CORE_ADDR sigtramp_address, sigtramp_end;
+
+/* Allocate zeroed memory */
+
+static PTR
+xzalloc (size)
+ unsigned int size;
+{
+ PTR p = xmalloc (size);
+
+ memset (p, 0, size);
+ return p;
+}
+
+/* Exported procedure: Builds a symtab from the PST partial one.
+ Restores the environment in effect when PST was created, delegates
+ most of the work to an ancillary procedure, and sorts
+ and reorders the symtab list at the end */
+
+static void
+mdebug_psymtab_to_symtab (pst)
+ struct partial_symtab *pst;
+{
+
+ if (!pst)
+ return;
+
+ if (info_verbose)
+ {
+ printf_filtered ("Reading in symbols for %s...", pst->filename);
+ gdb_flush (gdb_stdout);
+ }
+
+ next_symbol_text_func = mdebug_next_symbol_text;
+
+ psymtab_to_symtab_1 (pst, pst->filename);
+
+ /* Match with global symbols. This only needs to be done once,
+ after all of the symtabs and dependencies have been read in. */
+ scan_file_globals (pst->objfile);
+
+ if (info_verbose)
+ printf_filtered ("done.\n");
+}
+
+/* File-level interface functions */
+
+/* Find a file descriptor given its index RF relative to a file CF */
+
+static FDR *
+get_rfd (cf, rf)
+ int cf, rf;
+{
+ FDR *fdrs;
+ register FDR *f;
+ RFDT rfd;
+
+ fdrs = debug_info->fdr;
+ f = fdrs + cf;
+ /* Object files do not have the RFD table, all refs are absolute */
+ if (f->rfdBase == 0)
+ return fdrs + rf;
+ (*debug_swap->swap_rfd_in) (cur_bfd,
+ ((char *) debug_info->external_rfd
+ + ((f->rfdBase + rf)
+ * debug_swap->external_rfd_size)),
+ &rfd);
+ return fdrs + rfd;
+}
+
+/* Return a safer print NAME for a file descriptor */
+
+static char *
+fdr_name (f)
+ FDR *f;
+{
+ if (f->rss == -1)
+ return "<stripped file>";
+ if (f->rss == 0)
+ return "<NFY>";
+ return debug_info->ss + f->issBase + f->rss;
+}
+
+
+/* Read in and parse the symtab of the file OBJFILE. Symbols from
+ different sections are relocated via the SECTION_OFFSETS. */
+
+void
+mdebug_build_psymtabs (objfile, swap, info, section_offsets)
+ struct objfile *objfile;
+ const struct ecoff_debug_swap *swap;
+ struct ecoff_debug_info *info;
+ struct section_offsets *section_offsets;
+{
+ cur_bfd = objfile->obfd;
+ debug_swap = swap;
+ debug_info = info;
+
+ /* Make sure all the FDR information is swapped in. */
+ if (info->fdr == (FDR *) NULL)
+ {
+ char *fdr_src;
+ char *fdr_end;
+ FDR *fdr_ptr;
+
+ info->fdr = (FDR *) obstack_alloc (&objfile->psymbol_obstack,
+ (info->symbolic_header.ifdMax
+ * sizeof (FDR)));
+ fdr_src = info->external_fdr;
+ fdr_end = (fdr_src
+ + info->symbolic_header.ifdMax * swap->external_fdr_size);
+ fdr_ptr = info->fdr;
+ for (; fdr_src < fdr_end; fdr_src += swap->external_fdr_size, fdr_ptr++)
+ (*swap->swap_fdr_in) (objfile->obfd, fdr_src, fdr_ptr);
+ }
+
+ parse_partial_symbols (objfile, section_offsets);
+
+#if 0
+ /* Check to make sure file was compiled with -g. If not, warn the
+ user of this limitation. */
+ if (compare_glevel (max_glevel, GLEVEL_2) < 0)
+ {
+ if (max_gdbinfo == 0)
+ printf_unfiltered ("\n%s not compiled with -g, debugging support is limited.\n",
+ objfile->name);
+ printf_unfiltered ("You should compile with -g2 or -g3 for best debugging support.\n");
+ gdb_flush (gdb_stdout);
+ }
+#endif
+}
+
+/* Local utilities */
+
+/* Map of FDR indexes to partial symtabs */
+
+struct pst_map
+{
+ struct partial_symtab *pst; /* the psymtab proper */
+ long n_globals; /* exported globals (external symbols) */
+ long globals_offset; /* cumulative */
+};
+
+
+/* Utility stack, used to nest procedures and blocks properly.
+ It is a doubly linked list, to avoid too many alloc/free.
+ Since we might need it quite a few times it is NOT deallocated
+ after use. */
+
+static struct parse_stack
+{
+ struct parse_stack *next, *prev;
+ struct symtab *cur_st; /* Current symtab. */
+ struct block *cur_block; /* Block in it. */
+
+ /* What are we parsing. stFile, or stBlock are for files and
+ blocks. stProc or stStaticProc means we have seen the start of a
+ procedure, but not the start of the block within in. When we see
+ the start of that block, we change it to stNil, without pushing a
+ new block, i.e. stNil means both a procedure and a block. */
+
+ int blocktype;
+
+ int maxsyms; /* Max symbols in this block. */
+ struct type *cur_type; /* Type we parse fields for. */
+ int cur_field; /* Field number in cur_type. */
+ CORE_ADDR procadr; /* Start addres of this procedure */
+ int numargs; /* Its argument count */
+}
+
+ *top_stack; /* Top stack ptr */
+
+
+/* Enter a new lexical context */
+
+static void
+push_parse_stack ()
+{
+ struct parse_stack *new;
+
+ /* Reuse frames if possible */
+ if (top_stack && top_stack->prev)
+ new = top_stack->prev;
+ else
+ new = (struct parse_stack *) xzalloc (sizeof (struct parse_stack));
+ /* Initialize new frame with previous content */
+ if (top_stack)
+ {
+ register struct parse_stack *prev = new->prev;
+
+ *new = *top_stack;
+ top_stack->prev = new;
+ new->prev = prev;
+ new->next = top_stack;
+ }
+ top_stack = new;
+}
+
+/* Exit a lexical context */
+
+static void
+pop_parse_stack ()
+{
+ if (!top_stack)
+ return;
+ if (top_stack->next)
+ top_stack = top_stack->next;
+}
+
+
+/* Cross-references might be to things we haven't looked at
+ yet, e.g. type references. To avoid too many type
+ duplications we keep a quick fixup table, an array
+ of lists of references indexed by file descriptor */
+
+struct mdebug_pending
+{
+ struct mdebug_pending *next; /* link */
+ char *s; /* the unswapped symbol */
+ struct type *t; /* its partial type descriptor */
+};
+
+
+/* The pending information is kept for an entire object file, and used
+ to be in the sym_private field. I took it out when I split
+ mdebugread from mipsread, because this might not be the only type
+ of symbols read from an object file. Instead, we allocate the
+ pending information table when we create the partial symbols, and
+ we store a pointer to the single table in each psymtab. */
+
+static struct mdebug_pending **pending_list;
+
+/* Check whether we already saw symbol SH in file FH */
+
+static struct mdebug_pending *
+is_pending_symbol (fh, sh)
+ FDR *fh;
+ char *sh;
+{
+ int f_idx = fh - debug_info->fdr;
+ register struct mdebug_pending *p;
+
+ /* Linear search is ok, list is typically no more than 10 deep */
+ for (p = pending_list[f_idx]; p; p = p->next)
+ if (p->s == sh)
+ break;
+ return p;
+}
+
+/* Add a new symbol SH of type T */
+
+static void
+add_pending (fh, sh, t)
+ FDR *fh;
+ char *sh;
+ struct type *t;
+{
+ int f_idx = fh - debug_info->fdr;
+ struct mdebug_pending *p = is_pending_symbol (fh, sh);
+
+ /* Make sure we do not make duplicates */
+ if (!p)
+ {
+ p = ((struct mdebug_pending *)
+ obstack_alloc (&current_objfile->psymbol_obstack,
+ sizeof (struct mdebug_pending)));
+ p->s = sh;
+ p->t = t;
+ p->next = pending_list[f_idx];
+ pending_list[f_idx] = p;
+ }
+}
+
+
+/* Parsing Routines proper. */
+
+/* Parse a single symbol. Mostly just make up a GDB symbol for it.
+ For blocks, procedures and types we open a new lexical context.
+ This is basically just a big switch on the symbol's type. Argument
+ AX is the base pointer of aux symbols for this file (fh->iauxBase).
+ EXT_SH points to the unswapped symbol, which is needed for struct,
+ union, etc., types; it is NULL for an EXTR. BIGEND says whether
+ aux symbols are big-endian or little-endian. Return count of
+ SYMR's handled (normally one). */
+
+static int
+parse_symbol (sh, ax, ext_sh, bigend, section_offsets)
+ SYMR *sh;
+ union aux_ext *ax;
+ char *ext_sh;
+ int bigend;
+ struct section_offsets *section_offsets;
+{
+ const bfd_size_type external_sym_size = debug_swap->external_sym_size;
+ void (* const swap_sym_in) PARAMS ((bfd *, PTR, SYMR *)) =
+ debug_swap->swap_sym_in;
+ char *name;
+ struct symbol *s;
+ struct block *b;
+ struct mdebug_pending *pend;
+ struct type *t;
+ struct field *f;
+ int count = 1;
+ enum address_class class;
+ TIR tir;
+ long svalue = sh->value;
+ int bitsize;
+
+ if (ext_sh == (char *) NULL)
+ name = debug_info->ssext + sh->iss;
+ else
+ name = debug_info->ss + cur_fdr->issBase + sh->iss;
+
+ switch (sh->sc)
+ {
+ case scText:
+ /* The value of a stEnd symbol is the displacement from the
+ corresponding start symbol value, do not relocate it. */
+ if (sh->st != stEnd)
+ sh->value += ANOFFSET (section_offsets, SECT_OFF_TEXT);
+ break;
+ case scData:
+ case scSData:
+ case scRData:
+ case scPData:
+ case scXData:
+ sh->value += ANOFFSET (section_offsets, SECT_OFF_DATA);
+ break;
+ case scBss:
+ case scSBss:
+ sh->value += ANOFFSET (section_offsets, SECT_OFF_BSS);
+ break;
+ }
+
+ switch (sh->st)
+ {
+ case stNil:
+ break;
+
+ case stGlobal: /* external symbol, goes into global block */
+ class = LOC_STATIC;
+ b = BLOCKVECTOR_BLOCK (BLOCKVECTOR (top_stack->cur_st),
+ GLOBAL_BLOCK);
+ s = new_symbol (name);
+ SYMBOL_VALUE_ADDRESS (s) = (CORE_ADDR) sh->value;
+ goto data;
+
+ case stStatic: /* static data, goes into current block. */
+ class = LOC_STATIC;
+ b = top_stack->cur_block;
+ s = new_symbol (name);
+ if (sh->sc == scCommon)
+ {
+ /* It is a FORTRAN common block. At least for SGI Fortran the
+ address is not in the symbol; we need to fix it later in
+ scan_file_globals. */
+ int bucket = hashname (SYMBOL_NAME (s));
+ SYMBOL_VALUE_CHAIN (s) = global_sym_chain[bucket];
+ global_sym_chain[bucket] = s;
+ }
+ else
+ SYMBOL_VALUE_ADDRESS (s) = (CORE_ADDR) sh->value;
+ goto data;
+
+ case stLocal: /* local variable, goes into current block */
+ if (sh->sc == scRegister)
+ {
+ class = LOC_REGISTER;
+ svalue = ECOFF_REG_TO_REGNUM (svalue);
+ }
+ else
+ class = LOC_LOCAL;
+ b = top_stack->cur_block;
+ s = new_symbol (name);
+ SYMBOL_VALUE (s) = svalue;
+
+ data: /* Common code for symbols describing data */
+ SYMBOL_NAMESPACE (s) = VAR_NAMESPACE;
+ SYMBOL_CLASS (s) = class;
+ add_symbol (s, b);
+
+ /* Type could be missing in a number of cases */
+ if (sh->sc == scUndefined || sh->sc == scNil)
+ SYMBOL_TYPE (s) = builtin_type_int; /* undefined? */
+ else
+ SYMBOL_TYPE (s) = parse_type (cur_fd, ax, sh->index, 0, bigend, name);
+ /* Value of a data symbol is its memory address */
+ break;
+
+ case stParam: /* arg to procedure, goes into current block */
+ max_gdbinfo++;
+ top_stack->numargs++;
+
+ /* Special GNU C++ name. */
+ if (name[0] == CPLUS_MARKER && name[1] == 't' && name[2] == 0)
+ name = "this"; /* FIXME, not alloc'd in obstack */
+ s = new_symbol (name);
+
+ SYMBOL_NAMESPACE (s) = VAR_NAMESPACE;
+ switch (sh->sc)
+ {
+ case scRegister:
+ /* Pass by value in register. */
+ SYMBOL_CLASS(s) = LOC_REGPARM;
+ svalue = ECOFF_REG_TO_REGNUM (svalue);
+ break;
+ case scVar:
+ /* Pass by reference on stack. */
+ SYMBOL_CLASS(s) = LOC_REF_ARG;
+ break;
+ case scVarRegister:
+ /* Pass by reference in register. */
+ SYMBOL_CLASS(s) = LOC_REGPARM_ADDR;
+ svalue = ECOFF_REG_TO_REGNUM (svalue);
+ break;
+ default:
+ /* Pass by value on stack. */
+ SYMBOL_CLASS(s) = LOC_ARG;
+ break;
+ }
+ SYMBOL_VALUE (s) = svalue;
+ SYMBOL_TYPE (s) = parse_type (cur_fd, ax, sh->index, 0, bigend, name);
+ add_symbol (s, top_stack->cur_block);
+#if 0
+ /* FIXME: This has not been tested. See dbxread.c */
+ /* Add the type of this parameter to the function/procedure
+ type of this block. */
+ add_param_to_type (&top_stack->cur_block->function->type, s);
+#endif
+ break;
+
+ case stLabel: /* label, goes into current block */
+ s = new_symbol (name);
+ SYMBOL_NAMESPACE (s) = VAR_NAMESPACE; /* so that it can be used */
+ SYMBOL_CLASS (s) = LOC_LABEL; /* but not misused */
+ SYMBOL_VALUE_ADDRESS (s) = (CORE_ADDR) sh->value;
+ SYMBOL_TYPE (s) = builtin_type_int;
+ add_symbol (s, top_stack->cur_block);
+ break;
+
+ case stProc: /* Procedure, usually goes into global block */
+ case stStaticProc: /* Static procedure, goes into current block */
+ s = new_symbol (name);
+ SYMBOL_NAMESPACE (s) = VAR_NAMESPACE;
+ SYMBOL_CLASS (s) = LOC_BLOCK;
+ /* Type of the return value */
+ if (sh->sc == scUndefined || sh->sc == scNil)
+ t = builtin_type_int;
+ else
+ t = parse_type (cur_fd, ax, sh->index + 1, 0, bigend, name);
+ b = top_stack->cur_block;
+ if (sh->st == stProc)
+ {
+ struct blockvector *bv = BLOCKVECTOR (top_stack->cur_st);
+ /* The next test should normally be true, but provides a
+ hook for nested functions (which we don't want to make
+ global). */
+ if (b == BLOCKVECTOR_BLOCK (bv, STATIC_BLOCK))
+ b = BLOCKVECTOR_BLOCK (bv, GLOBAL_BLOCK);
+ /* Irix 5 sometimes has duplicate names for the same
+ function. We want to add such names up at the global
+ level, not as a nested function. */
+ else if (sh->value == top_stack->procadr)
+ b = BLOCKVECTOR_BLOCK (bv, GLOBAL_BLOCK);
+ }
+ add_symbol (s, b);
+
+ /* Make a type for the procedure itself */
+#if 0
+ /* FIXME: This has not been tested yet! See dbxread.c */
+ /* Generate a template for the type of this function. The
+ types of the arguments will be added as we read the symbol
+ table. */
+ memcpy (lookup_function_type (t), SYMBOL_TYPE (s), sizeof (struct type));
+#else
+ SYMBOL_TYPE (s) = lookup_function_type (t);
+#endif
+
+ /* Create and enter a new lexical context */
+ b = new_block (top_stack->maxsyms);
+ SYMBOL_BLOCK_VALUE (s) = b;
+ BLOCK_FUNCTION (b) = s;
+ BLOCK_START (b) = BLOCK_END (b) = sh->value;
+ BLOCK_SUPERBLOCK (b) = top_stack->cur_block;
+ add_block (b, top_stack->cur_st);
+
+ /* Not if we only have partial info */
+ if (sh->sc == scUndefined || sh->sc == scNil)
+ break;
+
+ push_parse_stack ();
+ top_stack->cur_block = b;
+ top_stack->blocktype = sh->st;
+ top_stack->cur_type = SYMBOL_TYPE (s);
+ top_stack->cur_field = -1;
+ top_stack->procadr = sh->value;
+ top_stack->numargs = 0;
+ break;
+
+ /* Beginning of code for structure, union, and enum definitions.
+ They all share a common set of local variables, defined here. */
+ {
+ enum type_code type_code;
+ char *ext_tsym;
+ int nfields;
+ long max_value;
+ struct field *f;
+
+ case stStruct: /* Start a block defining a struct type */
+ type_code = TYPE_CODE_STRUCT;
+ goto structured_common;
+
+ case stUnion: /* Start a block defining a union type */
+ type_code = TYPE_CODE_UNION;
+ goto structured_common;
+
+ case stEnum: /* Start a block defining an enum type */
+ type_code = TYPE_CODE_ENUM;
+ goto structured_common;
+
+ case stBlock: /* Either a lexical block, or some type */
+ if (sh->sc != scInfo && sh->sc != scCommon)
+ goto case_stBlock_code; /* Lexical block */
+
+ type_code = TYPE_CODE_UNDEF; /* We have a type. */
+
+ /* Common code for handling struct, union, enum, and/or as-yet-
+ unknown-type blocks of info about structured data. `type_code'
+ has been set to the proper TYPE_CODE, if we know it. */
+ structured_common:
+ push_parse_stack ();
+ top_stack->blocktype = stBlock;
+
+ /* First count the number of fields and the highest value. */
+ nfields = 0;
+ max_value = 0;
+ for (ext_tsym = ext_sh + external_sym_size;
+ ;
+ ext_tsym += external_sym_size)
+ {
+ SYMR tsym;
+
+ (*swap_sym_in) (cur_bfd, ext_tsym, &tsym);
+
+ switch (tsym.st)
+ {
+ case stEnd:
+ goto end_of_fields;
+
+ case stMember:
+ if (nfields == 0 && type_code == TYPE_CODE_UNDEF)
+ /* If the type of the member is Nil (or Void),
+ without qualifiers, assume the tag is an
+ enumeration. */
+ if (tsym.index == indexNil)
+ type_code = TYPE_CODE_ENUM;
+ else
+ {
+ (*debug_swap->swap_tir_in) (bigend,
+ &ax[tsym.index].a_ti,
+ &tir);
+ if ((tir.bt == btNil || tir.bt == btVoid)
+ && tir.tq0 == tqNil)
+ type_code = TYPE_CODE_ENUM;
+ }
+ nfields++;
+ if (tsym.value > max_value)
+ max_value = tsym.value;
+ break;
+
+ case stBlock:
+ case stUnion:
+ case stEnum:
+ case stStruct:
+ {
+#if 0
+ /* This is a no-op; is it trying to tell us something
+ we should be checking? */
+ if (tsym.sc == scVariant); /*UNIMPLEMENTED*/
+#endif
+ if (tsym.index != 0)
+ {
+ /* This is something like a struct within a
+ struct. Skip over the fields of the inner
+ struct. The -1 is because the for loop will
+ increment ext_tsym. */
+ ext_tsym = ((char *) debug_info->external_sym
+ + ((cur_fdr->isymBase + tsym.index - 1)
+ * external_sym_size));
+ }
+ }
+ break;
+
+ case stTypedef:
+ /* mips cc puts out a typedef for struct x if it is not yet
+ defined when it encounters
+ struct y { struct x *xp; };
+ Just ignore it. */
+ break;
+
+ case stIndirect:
+ /* Irix5 cc puts out a stIndirect for struct x if it is not
+ yet defined when it encounters
+ struct y { struct x *xp; };
+ Just ignore it. */
+ break;
+
+ default:
+ complain (&block_member_complaint, tsym.st);
+ }
+ }
+ end_of_fields:;
+
+ /* In an stBlock, there is no way to distinguish structs,
+ unions, and enums at this point. This is a bug in the
+ original design (that has been fixed with the recent
+ addition of the stStruct, stUnion, and stEnum symbol
+ types.) The way you can tell is if/when you see a variable
+ or field of that type. In that case the variable's type
+ (in the AUX table) says if the type is struct, union, or
+ enum, and points back to the stBlock here. So you can
+ patch the tag kind up later - but only if there actually is
+ a variable or field of that type.
+
+ So until we know for sure, we will guess at this point.
+ The heuristic is:
+ If the first member has index==indexNil or a void type,
+ assume we have an enumeration.
+ Otherwise, if there is more than one member, and all
+ the members have offset 0, assume we have a union.
+ Otherwise, assume we have a struct.
+
+ The heuristic could guess wrong in the case of of an
+ enumeration with no members or a union with one (or zero)
+ members, or when all except the last field of a struct have
+ width zero. These are uncommon and/or illegal situations,
+ and in any case guessing wrong probably doesn't matter
+ much.
+
+ But if we later do find out we were wrong, we fixup the tag
+ kind. Members of an enumeration must be handled
+ differently from struct/union fields, and that is harder to
+ patch up, but luckily we shouldn't need to. (If there are
+ any enumeration members, we can tell for sure it's an enum
+ here.) */
+
+ if (type_code == TYPE_CODE_UNDEF)
+ if (nfields > 1 && max_value == 0)
+ type_code = TYPE_CODE_UNION;
+ else
+ type_code = TYPE_CODE_STRUCT;
+
+ /* Create a new type or use the pending type. */
+ pend = is_pending_symbol (cur_fdr, ext_sh);
+ if (pend == (struct mdebug_pending *) NULL)
+ {
+ t = new_type (NULL);
+ add_pending (cur_fdr, ext_sh, t);
+ }
+ else
+ t = pend->t;
+
+ /* Do not set the tag name if it is a compiler generated tag name
+ (.Fxx or .xxfake or empty) for unnamed struct/union/enums.
+ Alpha cc puts out an sh->iss of zero for those. */
+ if (sh->iss == 0 || name[0] == '.' || name[0] == '\0')
+ TYPE_TAG_NAME (t) = NULL;
+ else
+ TYPE_TAG_NAME (t) = obconcat (&current_objfile->symbol_obstack,
+ "", "", name);
+
+ TYPE_CODE (t) = type_code;
+ TYPE_LENGTH (t) = sh->value;
+ TYPE_NFIELDS (t) = nfields;
+ TYPE_FIELDS (t) = f = ((struct field *)
+ TYPE_ALLOC (t,
+ nfields * sizeof (struct field)));
+
+ if (type_code == TYPE_CODE_ENUM)
+ {
+ /* This is a non-empty enum. */
+
+ /* DEC c89 has the number of enumerators in the sh.value field,
+ not the type length, so we have to compensate for that
+ incompatibility quirk.
+ This might do the wrong thing for an enum with one or two
+ enumerators and gcc -gcoff -fshort-enums, but these cases
+ are hopefully rare enough. */
+ if (TYPE_LENGTH (t) == TYPE_NFIELDS (t))
+ TYPE_LENGTH (t) = TARGET_INT_BIT / HOST_CHAR_BIT;
+ for (ext_tsym = ext_sh + external_sym_size;
+ ;
+ ext_tsym += external_sym_size)
+ {
+ SYMR tsym;
+ struct symbol *enum_sym;
+
+ (*swap_sym_in) (cur_bfd, ext_tsym, &tsym);
+
+ if (tsym.st != stMember)
+ break;
+
+ f->bitpos = tsym.value;
+ f->type = t;
+ f->name = debug_info->ss + cur_fdr->issBase + tsym.iss;
+ f->bitsize = 0;
+
+ enum_sym = ((struct symbol *)
+ obstack_alloc (&current_objfile->symbol_obstack,
+ sizeof (struct symbol)));
+ memset ((PTR) enum_sym, 0, sizeof (struct symbol));
+ SYMBOL_NAME (enum_sym) = f->name;
+ SYMBOL_CLASS (enum_sym) = LOC_CONST;
+ SYMBOL_TYPE (enum_sym) = t;
+ SYMBOL_NAMESPACE (enum_sym) = VAR_NAMESPACE;
+ SYMBOL_VALUE (enum_sym) = tsym.value;
+ add_symbol (enum_sym, top_stack->cur_block);
+
+ /* Skip the stMembers that we've handled. */
+ count++;
+ f++;
+ }
+ }
+ /* make this the current type */
+ top_stack->cur_type = t;
+ top_stack->cur_field = 0;
+
+ /* Do not create a symbol for alpha cc unnamed structs. */
+ if (sh->iss == 0)
+ break;
+
+ /* gcc puts out an empty struct for an opaque struct definitions,
+ do not create a symbol for it either. */
+ if (TYPE_NFIELDS (t) == 0)
+ {
+ TYPE_FLAGS (t) |= TYPE_FLAG_STUB;
+ break;
+ }
+
+ s = new_symbol (name);
+ SYMBOL_NAMESPACE (s) = STRUCT_NAMESPACE;
+ SYMBOL_CLASS (s) = LOC_TYPEDEF;
+ SYMBOL_VALUE (s) = 0;
+ SYMBOL_TYPE (s) = t;
+ add_symbol (s, top_stack->cur_block);
+ break;
+
+ /* End of local variables shared by struct, union, enum, and
+ block (as yet unknown struct/union/enum) processing. */
+ }
+
+ case_stBlock_code:
+ /* beginnning of (code) block. Value of symbol
+ is the displacement from procedure start */
+ push_parse_stack ();
+
+ /* Do not start a new block if this is the outermost block of a
+ procedure. This allows the LOC_BLOCK symbol to point to the
+ block with the local variables, so funcname::var works. */
+ if (top_stack->blocktype == stProc
+ || top_stack->blocktype == stStaticProc)
+ {
+ top_stack->blocktype = stNil;
+ break;
+ }
+
+ top_stack->blocktype = stBlock;
+ b = new_block (top_stack->maxsyms);
+ BLOCK_START (b) = sh->value + top_stack->procadr;
+ BLOCK_SUPERBLOCK (b) = top_stack->cur_block;
+ top_stack->cur_block = b;
+ add_block (b, top_stack->cur_st);
+ break;
+
+ case stEnd: /* end (of anything) */
+ if (sh->sc == scInfo || sh->sc == scCommon)
+ {
+ /* Finished with type */
+ top_stack->cur_type = 0;
+ }
+ else if (sh->sc == scText &&
+ (top_stack->blocktype == stProc ||
+ top_stack->blocktype == stStaticProc))
+ {
+ /* Finished with procedure */
+ struct blockvector *bv = BLOCKVECTOR (top_stack->cur_st);
+ struct mips_extra_func_info *e;
+ struct block *b;
+ int i;
+
+ BLOCK_END (top_stack->cur_block) += sh->value; /* size */
+
+ /* Make up special symbol to contain procedure specific info */
+ s = new_symbol (MIPS_EFI_SYMBOL_NAME);
+ SYMBOL_NAMESPACE (s) = LABEL_NAMESPACE;
+ SYMBOL_CLASS (s) = LOC_CONST;
+ SYMBOL_TYPE (s) = builtin_type_void;
+ e = ((struct mips_extra_func_info *)
+ obstack_alloc (&current_objfile->symbol_obstack,
+ sizeof (struct mips_extra_func_info)));
+ SYMBOL_VALUE (s) = (long) e;
+ e->numargs = top_stack->numargs;
+ add_symbol (s, top_stack->cur_block);
+
+ /* Reallocate symbols, saving memory */
+ b = shrink_block (top_stack->cur_block, top_stack->cur_st);
+
+ /* f77 emits proc-level with address bounds==[0,0],
+ So look for such child blocks, and patch them. */
+ for (i = 0; i < BLOCKVECTOR_NBLOCKS (bv); i++)
+ {
+ struct block *b_bad = BLOCKVECTOR_BLOCK (bv, i);
+ if (BLOCK_SUPERBLOCK (b_bad) == b
+ && BLOCK_START (b_bad) == top_stack->procadr
+ && BLOCK_END (b_bad) == top_stack->procadr)
+ {
+ BLOCK_START (b_bad) = BLOCK_START (b);
+ BLOCK_END (b_bad) = BLOCK_END (b);
+ }
+ }
+ }
+ else if (sh->sc == scText && top_stack->blocktype == stBlock)
+ {
+ /* End of (code) block. The value of the symbol is the
+ displacement from the procedure`s start address of the
+ end of this block. */
+ BLOCK_END (top_stack->cur_block) = sh->value + top_stack->procadr;
+ shrink_block (top_stack->cur_block, top_stack->cur_st);
+ }
+ else if (sh->sc == scText && top_stack->blocktype == stNil)
+ {
+ /* End of outermost block. Pop parse stack and ignore. The
+ following stEnd of stProc will take care of the block. */
+ ;
+ }
+ else if (sh->sc == scText && top_stack->blocktype == stFile)
+ {
+ /* End of file. Pop parse stack and ignore. Higher
+ level code deals with this. */
+ ;
+ }
+ else
+ complain (&stEnd_complaint, sh->sc);
+
+ pop_parse_stack (); /* restore previous lexical context */
+ break;
+
+ case stMember: /* member of struct or union */
+ f = &TYPE_FIELDS (top_stack->cur_type)[top_stack->cur_field++];
+ f->name = name;
+ f->bitpos = sh->value;
+ bitsize = 0;
+ f->type = parse_type (cur_fd, ax, sh->index, &bitsize, bigend, name);
+ f->bitsize = bitsize;
+ break;
+
+ case stIndirect: /* forward declaration on Irix5 */
+ /* Forward declarations from Irix5 cc are handled by cross_ref,
+ skip them. */
+ break;
+
+ case stTypedef: /* type definition */
+ /* Typedefs for forward declarations and opaque structs from alpha cc
+ are handled by cross_ref, skip them. */
+ if (sh->iss == 0)
+ break;
+
+ /* Parse the type or use the pending type. */
+ pend = is_pending_symbol (cur_fdr, ext_sh);
+ if (pend == (struct mdebug_pending *) NULL)
+ {
+ t = parse_type (cur_fd, ax, sh->index, (int *)NULL, bigend, name);
+ add_pending (cur_fdr, ext_sh, t);
+ }
+ else
+ t = pend->t;
+
+ /* mips cc puts out a typedef with the name of the struct for forward
+ declarations. These should not go into the symbol table and
+ TYPE_NAME should not be set for them.
+ They can't be distinguished from an intentional typedef to
+ the same name however:
+ x.h:
+ struct x { int ix; int jx; };
+ struct xx;
+ x.c:
+ typedef struct x x;
+ struct xx {int ixx; int jxx; };
+ generates a cross referencing stTypedef for x and xx.
+ The user visible effect of this is that the type of a pointer
+ to struct foo sometimes is given as `foo *' instead of `struct foo *'.
+ The problem is fixed with alpha cc and Irix5 cc. */
+
+ /* However if the typedef cross references to an opaque aggregate, it
+ is safe to omit it from the symbol table. */
+
+ if (has_opaque_xref (cur_fdr, sh))
+ break;
+ s = new_symbol (name);
+ SYMBOL_NAMESPACE (s) = VAR_NAMESPACE;
+ SYMBOL_CLASS (s) = LOC_TYPEDEF;
+ SYMBOL_BLOCK_VALUE (s) = top_stack->cur_block;
+ SYMBOL_TYPE (s) = t;
+ add_symbol (s, top_stack->cur_block);
+
+ /* Incomplete definitions of structs should not get a name. */
+ if (TYPE_NAME (SYMBOL_TYPE (s)) == NULL
+ && (TYPE_NFIELDS (SYMBOL_TYPE (s)) != 0
+ || (TYPE_CODE (SYMBOL_TYPE (s)) != TYPE_CODE_STRUCT
+ && TYPE_CODE (SYMBOL_TYPE (s)) != TYPE_CODE_UNION)))
+ {
+ if (TYPE_CODE (SYMBOL_TYPE (s)) == TYPE_CODE_PTR
+ || TYPE_CODE (SYMBOL_TYPE (s)) == TYPE_CODE_FUNC)
+ {
+ /* If we are giving a name to a type such as "pointer to
+ foo" or "function returning foo", we better not set
+ the TYPE_NAME. If the program contains "typedef char
+ *caddr_t;", we don't want all variables of type char
+ * to print as caddr_t. This is not just a
+ consequence of GDB's type management; CC and GCC (at
+ least through version 2.4) both output variables of
+ either type char * or caddr_t with the type
+ refering to the stTypedef symbol for caddr_t. If a future
+ compiler cleans this up it GDB is not ready for it
+ yet, but if it becomes ready we somehow need to
+ disable this check (without breaking the PCC/GCC2.4
+ case).
+
+ Sigh.
+
+ Fortunately, this check seems not to be necessary
+ for anything except pointers or functions. */
+ }
+ else
+ TYPE_NAME (SYMBOL_TYPE (s)) = SYMBOL_NAME (s);
+ }
+ break;
+
+ case stFile: /* file name */
+ push_parse_stack ();
+ top_stack->blocktype = sh->st;
+ break;
+
+ /* I`ve never seen these for C */
+ case stRegReloc:
+ break; /* register relocation */
+ case stForward:
+ break; /* forwarding address */
+ case stConstant:
+ break; /* constant */
+ default:
+ complain (&unknown_mdebug_symtype_complaint, sh->st);
+ break;
+ }
+
+ return count;
+}
+
+/* Parse the type information provided in the raw AX entries for
+ the symbol SH. Return the bitfield size in BS, in case.
+ We must byte-swap the AX entries before we use them; BIGEND says whether
+ they are big-endian or little-endian (from fh->fBigendian). */
+
+static struct type *
+parse_type (fd, ax, aux_index, bs, bigend, sym_name)
+ int fd;
+ union aux_ext *ax;
+ unsigned int aux_index;
+ int *bs;
+ int bigend;
+ char *sym_name;
+{
+ /* Null entries in this map are treated specially */
+ static struct type **map_bt[] =
+ {
+ &builtin_type_void, /* btNil */
+ 0, /* btAdr */
+ &builtin_type_char, /* btChar */
+ &builtin_type_unsigned_char,/* btUChar */
+ &builtin_type_short, /* btShort */
+ &builtin_type_unsigned_short, /* btUShort */
+ &builtin_type_int, /* btInt */
+ &builtin_type_unsigned_int, /* btUInt */
+ &builtin_type_long, /* btLong */
+ &builtin_type_unsigned_long,/* btULong */
+ &builtin_type_float, /* btFloat */
+ &builtin_type_double, /* btDouble */
+ 0, /* btStruct */
+ 0, /* btUnion */
+ 0, /* btEnum */
+ 0, /* btTypedef */
+ 0, /* btRange */
+ 0, /* btSet */
+ &mdebug_type_complex, /* btComplex */
+ &mdebug_type_double_complex, /* btDComplex */
+ 0, /* btIndirect */
+ &mdebug_type_fixed_dec, /* btFixedDec */
+ &mdebug_type_float_dec, /* btFloatDec */
+ &mdebug_type_string, /* btString */
+ 0, /* btBit */
+ 0, /* btPicture */
+ &builtin_type_void, /* btVoid */
+ 0, /* DEC C++: Pointer to member */
+ 0, /* DEC C++: Virtual function table */
+ 0, /* DEC C++: Class (Record) */
+ &builtin_type_long, /* btLong64 */
+ &builtin_type_unsigned_long, /* btULong64 */
+ &builtin_type_long_long, /* btLongLong64 */
+ &builtin_type_unsigned_long_long, /* btULongLong64 */
+ &builtin_type_unsigned_long, /* btAdr64 */
+ &builtin_type_long, /* btInt64 */
+ &builtin_type_unsigned_long, /* btUInt64 */
+ };
+
+ TIR t[1];
+ struct type *tp = 0;
+ enum type_code type_code = TYPE_CODE_UNDEF;
+
+ /* Handle undefined types, they have indexNil. */
+ if (aux_index == indexNil)
+ return builtin_type_int;
+
+ /* Handle corrupt aux indices. */
+ if (aux_index >= (debug_info->fdr + fd)->caux)
+ {
+ complain (&index_complaint, sym_name);
+ return builtin_type_int;
+ }
+ ax += aux_index;
+
+ /* Use aux as a type information record, map its basic type. */
+ (*debug_swap->swap_tir_in) (bigend, &ax->a_ti, t);
+ if (t->bt >= (sizeof (map_bt) / sizeof (*map_bt)))
+ {
+ complain (&basic_type_complaint, t->bt, sym_name);
+ return builtin_type_int;
+ }
+ if (map_bt[t->bt])
+ {
+ tp = *map_bt[t->bt];
+ }
+ else
+ {
+ tp = NULL;
+ /* Cannot use builtin types -- build our own */
+ switch (t->bt)
+ {
+ case btAdr:
+ tp = lookup_pointer_type (builtin_type_void);
+ break;
+ case btStruct:
+ type_code = TYPE_CODE_STRUCT;
+ break;
+ case btUnion:
+ type_code = TYPE_CODE_UNION;
+ break;
+ case btEnum:
+ type_code = TYPE_CODE_ENUM;
+ break;
+ case btRange:
+ type_code = TYPE_CODE_RANGE;
+ break;
+ case btSet:
+ type_code = TYPE_CODE_SET;
+ break;
+ case btTypedef:
+ /* alpha cc uses this for typedefs. The true type will be
+ obtained by crossreferencing below. */
+ type_code = TYPE_CODE_ERROR;
+ break;
+ default:
+ complain (&basic_type_complaint, t->bt, sym_name);
+ return builtin_type_int;
+ }
+ }
+
+ /* Move on to next aux */
+ ax++;
+
+ if (t->fBitfield)
+ {
+ /* Inhibit core dumps with some cfront generated objects that
+ corrupt the TIR. */
+ if (bs == (int *)NULL)
+ {
+ complain (&bad_fbitfield_complaint, sym_name);
+ return builtin_type_int;
+ }
+ *bs = AUX_GET_WIDTH (bigend, ax);
+ ax++;
+ }
+
+ /* All these types really point to some (common) MIPS type
+ definition, and only the type-qualifiers fully identify
+ them. We'll make the same effort at sharing. */
+ if (t->bt == btStruct ||
+ t->bt == btUnion ||
+ t->bt == btEnum ||
+
+ /* btSet (I think) implies that the name is a tag name, not a typedef
+ name. This apparently is a MIPS extension for C sets. */
+ t->bt == btSet)
+ {
+ char *name;
+
+ /* Try to cross reference this type, build new type on failure. */
+ ax += cross_ref (fd, ax, &tp, type_code, &name, bigend, sym_name);
+ if (tp == (struct type *) NULL)
+ tp = init_type (type_code, 0, 0, (char *) NULL, current_objfile);
+
+ /* DEC c89 produces cross references to qualified aggregate types,
+ dereference them. */
+ while (TYPE_CODE (tp) == TYPE_CODE_PTR
+ || TYPE_CODE (tp) == TYPE_CODE_ARRAY)
+ tp = tp->target_type;
+
+ /* Make sure that TYPE_CODE(tp) has an expected type code.
+ Any type may be returned from cross_ref if file indirect entries
+ are corrupted. */
+ if (TYPE_CODE (tp) != TYPE_CODE_STRUCT
+ && TYPE_CODE (tp) != TYPE_CODE_UNION
+ && TYPE_CODE (tp) != TYPE_CODE_ENUM)
+ {
+ complain (&unexpected_type_code_complaint, sym_name);
+ }
+ else
+ {
+
+ /* Usually, TYPE_CODE(tp) is already type_code. The main
+ exception is if we guessed wrong re struct/union/enum.
+ But for struct vs. union a wrong guess is harmless, so
+ don't complain(). */
+ if ((TYPE_CODE (tp) == TYPE_CODE_ENUM
+ && type_code != TYPE_CODE_ENUM)
+ || (TYPE_CODE (tp) != TYPE_CODE_ENUM
+ && type_code == TYPE_CODE_ENUM))
+ {
+ complain (&bad_tag_guess_complaint, sym_name);
+ }
+
+ if (TYPE_CODE (tp) != type_code)
+ {
+ TYPE_CODE (tp) = type_code;
+ }
+
+ /* Do not set the tag name if it is a compiler generated tag name
+ (.Fxx or .xxfake or empty) for unnamed struct/union/enums. */
+ if (name[0] == '.' || name[0] == '\0')
+ TYPE_TAG_NAME (tp) = NULL;
+ else if (TYPE_TAG_NAME (tp) == NULL
+ || !STREQ (TYPE_TAG_NAME (tp), name))
+ TYPE_TAG_NAME (tp) = obsavestring (name, strlen (name),
+ &current_objfile->type_obstack);
+ }
+ }
+
+ /* All these types really point to some (common) MIPS type
+ definition, and only the type-qualifiers fully identify
+ them. We'll make the same effort at sharing.
+ FIXME: btIndirect cannot happen here as it is handled by the
+ switch t->bt above. And we are not doing any guessing on range types. */
+ if (t->bt == btIndirect ||
+ t->bt == btRange)
+ {
+ char *name;
+
+ /* Try to cross reference this type, build new type on failure. */
+ ax += cross_ref (fd, ax, &tp, type_code, &name, bigend, sym_name);
+ if (tp == (struct type *) NULL)
+ tp = init_type (type_code, 0, 0, (char *) NULL, current_objfile);
+
+ /* Make sure that TYPE_CODE(tp) has an expected type code.
+ Any type may be returned from cross_ref if file indirect entries
+ are corrupted. */
+ if (TYPE_CODE (tp) != TYPE_CODE_RANGE)
+ {
+ complain (&unexpected_type_code_complaint, sym_name);
+ }
+ else
+ {
+ /* Usually, TYPE_CODE(tp) is already type_code. The main
+ exception is if we guessed wrong re struct/union/enum. */
+ if (TYPE_CODE (tp) != type_code)
+ {
+ complain (&bad_tag_guess_complaint, sym_name);
+ TYPE_CODE (tp) = type_code;
+ }
+ if (TYPE_NAME (tp) == NULL || !STREQ (TYPE_NAME (tp), name))
+ TYPE_NAME (tp) = obsavestring (name, strlen (name),
+ &current_objfile->type_obstack);
+ }
+ }
+ if (t->bt == btTypedef)
+ {
+ char *name;
+
+ /* Try to cross reference this type, it should succeed. */
+ ax += cross_ref (fd, ax, &tp, type_code, &name, bigend, sym_name);
+ if (tp == (struct type *) NULL)
+ {
+ complain (&unable_to_cross_ref_complaint, sym_name);
+ tp = builtin_type_int;
+ }
+ }
+
+ /* Deal with range types */
+ if (t->bt == btRange)
+ {
+ TYPE_NFIELDS (tp) = 2;
+ TYPE_FIELDS (tp) = ((struct field *)
+ TYPE_ALLOC (tp, 2 * sizeof (struct field)));
+ TYPE_FIELD_NAME (tp, 0) = obsavestring ("Low", strlen ("Low"),
+ &current_objfile->type_obstack);
+ TYPE_FIELD_BITPOS (tp, 0) = AUX_GET_DNLOW (bigend, ax);
+ ax++;
+ TYPE_FIELD_NAME (tp, 1) = obsavestring ("High", strlen ("High"),
+ &current_objfile->type_obstack);
+ TYPE_FIELD_BITPOS (tp, 1) = AUX_GET_DNHIGH (bigend, ax);
+ ax++;
+ }
+
+ /* Parse all the type qualifiers now. If there are more
+ than 6 the game will continue in the next aux */
+
+ while (1)
+ {
+#define PARSE_TQ(tq) \
+ if (t->tq != tqNil) \
+ ax += upgrade_type(fd, &tp, t->tq, ax, bigend, sym_name); \
+ else \
+ break;
+
+ PARSE_TQ (tq0);
+ PARSE_TQ (tq1);
+ PARSE_TQ (tq2);
+ PARSE_TQ (tq3);
+ PARSE_TQ (tq4);
+ PARSE_TQ (tq5);
+#undef PARSE_TQ
+
+ /* mips cc 2.x and gcc never put out continued aux entries. */
+ if (!t->continued)
+ break;
+
+ (*debug_swap->swap_tir_in) (bigend, &ax->a_ti, t);
+ ax++;
+ }
+
+ /* Complain for illegal continuations due to corrupt aux entries. */
+ if (t->continued)
+ complain (&bad_continued_complaint, sym_name);
+
+ return tp;
+}
+
+/* Make up a complex type from a basic one. Type is passed by
+ reference in TPP and side-effected as necessary. The type
+ qualifier TQ says how to handle the aux symbols at AX for
+ the symbol SX we are currently analyzing. BIGEND says whether
+ aux symbols are big-endian or little-endian.
+ Returns the number of aux symbols we parsed. */
+
+static int
+upgrade_type (fd, tpp, tq, ax, bigend, sym_name)
+ int fd;
+ struct type **tpp;
+ int tq;
+ union aux_ext *ax;
+ int bigend;
+ char *sym_name;
+{
+ int off;
+ struct type *t;
+
+ /* Used in array processing */
+ int rf, id;
+ FDR *fh;
+ struct type *range;
+ struct type *indx;
+ int lower, upper;
+ RNDXR rndx;
+
+ switch (tq)
+ {
+ case tqPtr:
+ t = lookup_pointer_type (*tpp);
+ *tpp = t;
+ return 0;
+
+ case tqProc:
+ t = lookup_function_type (*tpp);
+ *tpp = t;
+ return 0;
+
+ case tqArray:
+ off = 0;
+
+ /* Determine and record the domain type (type of index) */
+ (*debug_swap->swap_rndx_in) (bigend, &ax->a_rndx, &rndx);
+ id = rndx.index;
+ rf = rndx.rfd;
+ if (rf == 0xfff)
+ {
+ ax++;
+ rf = AUX_GET_ISYM (bigend, ax);
+ off++;
+ }
+ fh = get_rfd (fd, rf);
+
+ indx = parse_type (fd, debug_info->external_aux + fh->iauxBase,
+ id, (int *) NULL, bigend, sym_name);
+
+ /* The bounds type should be an integer type, but might be anything
+ else due to corrupt aux entries. */
+ if (TYPE_CODE (indx) != TYPE_CODE_INT)
+ {
+ complain (&array_index_type_complaint, sym_name);
+ indx = builtin_type_int;
+ }
+
+ /* Get the bounds, and create the array type. */
+ ax++;
+ lower = AUX_GET_DNLOW (bigend, ax);
+ ax++;
+ upper = AUX_GET_DNHIGH (bigend, ax);
+ ax++;
+ rf = AUX_GET_WIDTH (bigend, ax); /* bit size of array element */
+
+ range = create_range_type ((struct type *) NULL, indx,
+ lower, upper);
+
+ t = create_array_type ((struct type *) NULL, *tpp, range);
+
+ /* We used to fill in the supplied array element bitsize
+ here if the TYPE_LENGTH of the target type was zero.
+ This happens for a `pointer to an array of anonymous structs',
+ but in this case the array element bitsize is also zero,
+ so nothing is gained.
+ And we used to check the TYPE_LENGTH of the target type against
+ the supplied array element bitsize.
+ gcc causes a mismatch for `pointer to array of object',
+ since the sdb directives it uses do not have a way of
+ specifying the bitsize, but it does no harm (the
+ TYPE_LENGTH should be correct) and we should be able to
+ ignore the erroneous bitsize from the auxiliary entry safely.
+ dbx seems to ignore it too. */
+
+ *tpp = t;
+ return 4 + off;
+
+ case tqVol:
+ /* Volatile -- currently ignored */
+ return 0;
+
+ case tqConst:
+ /* Const -- currently ignored */
+ return 0;
+
+ default:
+ complain (&unknown_type_qual_complaint, tq);
+ return 0;
+ }
+}
+
+
+/* Parse a procedure descriptor record PR. Note that the procedure is
+ parsed _after_ the local symbols, now we just insert the extra
+ information we need into a MIPS_EFI_SYMBOL_NAME symbol that has
+ already been placed in the procedure's main block. Note also that
+ images that have been partially stripped (ld -x) have been deprived
+ of local symbols, and we have to cope with them here. FIRST_OFF is
+ the offset of the first procedure for this FDR; we adjust the
+ address by this amount, but I don't know why. SEARCH_SYMTAB is the symtab
+ to look for the function which contains the MIPS_EFI_SYMBOL_NAME symbol
+ in question, or NULL to use top_stack->cur_block. */
+
+static void parse_procedure PARAMS ((PDR *, struct symtab *, unsigned long,
+ struct partial_symtab *));
+
+static void
+parse_procedure (pr, search_symtab, first_off, pst)
+ PDR *pr;
+ struct symtab *search_symtab;
+ unsigned long first_off;
+ struct partial_symtab *pst;
+{
+ struct symbol *s, *i;
+ struct block *b;
+ struct mips_extra_func_info *e;
+ char *sh_name;
+
+ /* Simple rule to find files linked "-x" */
+ if (cur_fdr->rss == -1)
+ {
+ if (pr->isym == -1)
+ {
+ /* Static procedure at address pr->adr. Sigh. */
+ /* FIXME-32x64. assuming pr->adr fits in long. */
+ complain (&pdr_static_symbol_complaint, (unsigned long) pr->adr);
+ return;
+ }
+ else
+ {
+ /* external */
+ EXTR she;
+
+ (*debug_swap->swap_ext_in) (cur_bfd,
+ ((char *) debug_info->external_ext
+ + (pr->isym
+ * debug_swap->external_ext_size)),
+ &she);
+ sh_name = debug_info->ssext + she.asym.iss;
+ }
+ }
+ else
+ {
+ /* Full symbols */
+ SYMR sh;
+
+ (*debug_swap->swap_sym_in) (cur_bfd,
+ ((char *) debug_info->external_sym
+ + ((cur_fdr->isymBase + pr->isym)
+ * debug_swap->external_sym_size)),
+ &sh);
+ sh_name = debug_info->ss + cur_fdr->issBase + sh.iss;
+ }
+
+ if (search_symtab != NULL)
+ {
+#if 0
+ /* This loses both in the case mentioned (want a static, find a global),
+ but also if we are looking up a non-mangled name which happens to
+ match the name of a mangled function. */
+ /* We have to save the cur_fdr across the call to lookup_symbol.
+ If the pdr is for a static function and if a global function with
+ the same name exists, lookup_symbol will eventually read in the symtab
+ for the global function and clobber cur_fdr. */
+ FDR *save_cur_fdr = cur_fdr;
+ s = lookup_symbol (sh_name, NULL, VAR_NAMESPACE, 0, NULL);
+ cur_fdr = save_cur_fdr;
+#else
+ s = mylookup_symbol
+ (sh_name,
+ BLOCKVECTOR_BLOCK (BLOCKVECTOR (search_symtab), STATIC_BLOCK),
+ VAR_NAMESPACE,
+ LOC_BLOCK);
+#endif
+ }
+ else
+ s = mylookup_symbol (sh_name, top_stack->cur_block,
+ VAR_NAMESPACE, LOC_BLOCK);
+
+ if (s != 0)
+ {
+ b = SYMBOL_BLOCK_VALUE (s);
+ }
+ else
+ {
+ complain (&pdr_for_nonsymbol_complaint, sh_name);
+#if 1
+ return;
+#else
+/* FIXME -- delete. We can't do symbol allocation now; it's all done. */
+ s = new_symbol (sh_name);
+ SYMBOL_NAMESPACE (s) = VAR_NAMESPACE;
+ SYMBOL_CLASS (s) = LOC_BLOCK;
+ /* Donno its type, hope int is ok */
+ SYMBOL_TYPE (s) = lookup_function_type (builtin_type_int);
+ add_symbol (s, top_stack->cur_block);
+ /* Wont have symbols for this one */
+ b = new_block (2);
+ SYMBOL_BLOCK_VALUE (s) = b;
+ BLOCK_FUNCTION (b) = s;
+ BLOCK_START (b) = pr->adr;
+ /* BOUND used to be the end of procedure's text, but the
+ argument is no longer passed in. */
+ BLOCK_END (b) = bound;
+ BLOCK_SUPERBLOCK (b) = top_stack->cur_block;
+ add_block (b, top_stack->cur_st);
+#endif
+ }
+
+ i = mylookup_symbol (MIPS_EFI_SYMBOL_NAME, b, LABEL_NAMESPACE, LOC_CONST);
+
+ if (i)
+ {
+ e = (struct mips_extra_func_info *) SYMBOL_VALUE (i);
+ e->pdr = *pr;
+ e->pdr.isym = (long) s;
+ e->pdr.adr += pst->textlow - first_off;
+
+ /* Correct incorrect setjmp procedure descriptor from the library
+ to make backtrace through setjmp work. */
+ if (e->pdr.pcreg == 0 && STREQ (sh_name, "setjmp"))
+ {
+ complain (&bad_setjmp_pdr_complaint, 0);
+ e->pdr.pcreg = RA_REGNUM;
+ e->pdr.regmask = 0x80000000;
+ e->pdr.regoffset = -4;
+ }
+ }
+}
+
+/* Relocate the extra function info pointed to by the symbol table. */
+
+void
+ecoff_relocate_efi (sym, delta)
+ struct symbol *sym;
+ CORE_ADDR delta;
+{
+ struct mips_extra_func_info *e;
+
+ e = (struct mips_extra_func_info *) SYMBOL_VALUE (sym);
+
+ e->pdr.adr += delta;
+}
+
+/* Parse the external symbol ES. Just call parse_symbol() after
+ making sure we know where the aux are for it.
+ BIGEND says whether aux entries are big-endian or little-endian.
+
+ This routine clobbers top_stack->cur_block and ->cur_st. */
+
+static void parse_external PARAMS ((EXTR *, int, struct section_offsets *));
+
+static void
+parse_external (es, bigend, section_offsets)
+ EXTR *es;
+ int bigend;
+ struct section_offsets *section_offsets;
+{
+ union aux_ext *ax;
+
+ if (es->ifd != ifdNil)
+ {
+ cur_fd = es->ifd;
+ cur_fdr = debug_info->fdr + cur_fd;
+ ax = debug_info->external_aux + cur_fdr->iauxBase;
+ }
+ else
+ {
+ cur_fdr = debug_info->fdr;
+ ax = 0;
+ }
+
+ /* Reading .o files */
+ if (es->asym.sc == scUndefined || es->asym.sc == scNil)
+ {
+ char *what;
+ switch (es->asym.st)
+ {
+ case stNil:
+ /* These are generated for static symbols in .o files,
+ ignore them. */
+ return;
+ case stStaticProc:
+ case stProc:
+ what = "procedure";
+ n_undef_procs++;
+ break;
+ case stGlobal:
+ what = "variable";
+ n_undef_vars++;
+ break;
+ case stLabel:
+ what = "label";
+ n_undef_labels++;
+ break;
+ default:
+ what = "symbol";
+ break;
+ }
+ n_undef_symbols++;
+ /* FIXME: Turn this into a complaint? */
+ if (info_verbose)
+ printf_filtered ("Warning: %s `%s' is undefined (in %s)\n",
+ what, debug_info->ssext + es->asym.iss,
+ fdr_name (cur_fdr));
+ return;
+ }
+
+ switch (es->asym.st)
+ {
+ case stProc:
+ case stStaticProc:
+ /* There is no need to parse the external procedure symbols.
+ If they are from objects compiled without -g, their index will
+ be indexNil, and the symbol definition from the minimal symbol
+ is preferrable (yielding a function returning int instead of int).
+ If the index points to a local procedure symbol, the local
+ symbol already provides the correct type.
+ Note that the index of the external procedure symbol points
+ to the local procedure symbol in the local symbol table, and
+ _not_ to the auxiliary symbol info. */
+ break;
+ case stGlobal:
+ case stLabel:
+ /* Note that the case of a symbol with indexNil must be handled
+ anyways by parse_symbol(). */
+ parse_symbol (&es->asym, ax, (char *) NULL, bigend, section_offsets);
+ break;
+ default:
+ break;
+ }
+}
+
+/* Parse the line number info for file descriptor FH into
+ GDB's linetable LT. MIPS' encoding requires a little bit
+ of magic to get things out. Note also that MIPS' line
+ numbers can go back and forth, apparently we can live
+ with that and do not need to reorder our linetables */
+
+static void parse_lines PARAMS ((FDR *, PDR *, struct linetable *, int,
+ struct partial_symtab *));
+
+static void
+parse_lines (fh, pr, lt, maxlines, pst)
+ FDR *fh;
+ PDR *pr;
+ struct linetable *lt;
+ int maxlines;
+ struct partial_symtab *pst;
+{
+ unsigned char *base;
+ int j, k;
+ int delta, count, lineno = 0;
+ unsigned long first_off = pr->adr;
+
+ if (fh->cbLine == 0)
+ return;
+
+ /* Scan by procedure descriptors */
+ k = 0;
+ for (j = 0; j < fh->cpd; j++, pr++)
+ {
+ long l;
+ unsigned long adr;
+ unsigned char *halt;
+
+ /* No code for this one */
+ if (pr->iline == ilineNil ||
+ pr->lnLow == -1 || pr->lnHigh == -1)
+ continue;
+
+ /* Determine start and end address of compressed line bytes for
+ this procedure. */
+ base = debug_info->line + fh->cbLineOffset;
+ if (j != (fh->cpd - 1))
+ halt = base + pr[1].cbLineOffset;
+ else
+ halt = base + fh->cbLine;
+ base += pr->cbLineOffset;
+
+ adr = pst->textlow + pr->adr - first_off;
+
+ l = adr >> 2; /* in words */
+ for (lineno = pr->lnLow; base < halt; )
+ {
+ count = *base & 0x0f;
+ delta = *base++ >> 4;
+ if (delta >= 8)
+ delta -= 16;
+ if (delta == -8)
+ {
+ delta = (base[0] << 8) | base[1];
+ if (delta >= 0x8000)
+ delta -= 0x10000;
+ base += 2;
+ }
+ lineno += delta; /* first delta is 0 */
+
+ /* Complain if the line table overflows. Could happen
+ with corrupt binaries. */
+ if (lt->nitems >= maxlines)
+ {
+ complain (&bad_linetable_guess_complaint, fdr_name (fh));
+ break;
+ }
+ k = add_line (lt, lineno, l, k);
+ l += count + 1;
+ }
+ }
+}
+
+/* Master parsing procedure for first-pass reading of file symbols
+ into a partial_symtab. */
+
+static void
+parse_partial_symbols (objfile, section_offsets)
+ struct objfile *objfile;
+ struct section_offsets *section_offsets;
+{
+ const bfd_size_type external_sym_size = debug_swap->external_sym_size;
+ const bfd_size_type external_rfd_size = debug_swap->external_rfd_size;
+ const bfd_size_type external_ext_size = debug_swap->external_ext_size;
+ void (* const swap_ext_in) PARAMS ((bfd *, PTR, EXTR *))
+ = debug_swap->swap_ext_in;
+ void (* const swap_sym_in) PARAMS ((bfd *, PTR, SYMR *))
+ = debug_swap->swap_sym_in;
+ void (* const swap_rfd_in) PARAMS ((bfd *, PTR, RFDT *))
+ = debug_swap->swap_rfd_in;
+ int f_idx, s_idx;
+ HDRR *hdr = &debug_info->symbolic_header;
+ /* Running pointers */
+ FDR *fh;
+ char *ext_out;
+ char *ext_out_end;
+ EXTR *ext_block;
+ register EXTR *ext_in;
+ EXTR *ext_in_end;
+ SYMR sh;
+ struct partial_symtab *pst;
+
+ int past_first_source_file = 0;
+
+ /* List of current psymtab's include files */
+ char **psymtab_include_list;
+ int includes_allocated;
+ int includes_used;
+ EXTR *extern_tab;
+ struct pst_map *fdr_to_pst;
+ /* Index within current psymtab dependency list */
+ struct partial_symtab **dependency_list;
+ int dependencies_used, dependencies_allocated;
+ struct cleanup *old_chain;
+ char *name;
+ enum language prev_language;
+ asection *text_sect;
+ int relocatable = 0;
+
+ /* Irix 5.2 shared libraries have a fh->adr field of zero, but
+ the shared libraries are prelinked at a high memory address.
+ We have to adjust the start address of the object file for this case,
+ by setting it to the start address of the first procedure in the file.
+ But we should do no adjustments if we are debugging a .o file, where
+ the text section (and fh->adr) really starts at zero. */
+ text_sect = bfd_get_section_by_name (cur_bfd, ".text");
+ if (text_sect != NULL
+ && (bfd_get_section_flags (cur_bfd, text_sect) & SEC_RELOC))
+ relocatable = 1;
+
+ extern_tab = (EXTR *) obstack_alloc (&objfile->psymbol_obstack,
+ sizeof (EXTR) * hdr->iextMax);
+
+ includes_allocated = 30;
+ includes_used = 0;
+ psymtab_include_list = (char **) alloca (includes_allocated *
+ sizeof (char *));
+ next_symbol_text_func = mdebug_next_symbol_text;
+
+ dependencies_allocated = 30;
+ dependencies_used = 0;
+ dependency_list =
+ (struct partial_symtab **) alloca (dependencies_allocated *
+ sizeof (struct partial_symtab *));
+
+ last_source_file = NULL;
+
+ /*
+ * Big plan:
+ *
+ * Only parse the Local and External symbols, and the Relative FDR.
+ * Fixup enough of the loader symtab to be able to use it.
+ * Allocate space only for the file's portions we need to
+ * look at. (XXX)
+ */
+
+ max_gdbinfo = 0;
+ max_glevel = MIN_GLEVEL;
+
+ /* Allocate the map FDR -> PST.
+ Minor hack: -O3 images might claim some global data belongs
+ to FDR -1. We`ll go along with that */
+ fdr_to_pst = (struct pst_map *) xzalloc ((hdr->ifdMax + 1) * sizeof *fdr_to_pst);
+ old_chain = make_cleanup (free, fdr_to_pst);
+ fdr_to_pst++;
+ {
+ struct partial_symtab *pst = new_psymtab ("", objfile, section_offsets);
+ fdr_to_pst[-1].pst = pst;
+ FDR_IDX (pst) = -1;
+ }
+
+ /* Allocate the global pending list. */
+ pending_list =
+ ((struct mdebug_pending **)
+ obstack_alloc (&objfile->psymbol_obstack,
+ hdr->ifdMax * sizeof (struct mdebug_pending *)));
+ memset ((PTR) pending_list, 0,
+ hdr->ifdMax * sizeof (struct mdebug_pending *));
+
+ /* Pass 0 over external syms: swap them in. */
+ ext_block = (EXTR *) xmalloc (hdr->iextMax * sizeof (EXTR));
+ make_cleanup (free, ext_block);
+
+ ext_out = (char *) debug_info->external_ext;
+ ext_out_end = ext_out + hdr->iextMax * external_ext_size;
+ ext_in = ext_block;
+ for (; ext_out < ext_out_end; ext_out += external_ext_size, ext_in++)
+ (*swap_ext_in) (cur_bfd, ext_out, ext_in);
+
+ /* Pass 1 over external syms: Presize and partition the list */
+ ext_in = ext_block;
+ ext_in_end = ext_in + hdr->iextMax;
+ for (; ext_in < ext_in_end; ext_in++)
+ {
+ /* See calls to complain below. */
+ if (ext_in->ifd >= -1
+ && ext_in->ifd < hdr->ifdMax
+ && ext_in->asym.iss >= 0
+ && ext_in->asym.iss < hdr->issExtMax)
+ fdr_to_pst[ext_in->ifd].n_globals++;
+ }
+
+ /* Pass 1.5 over files: partition out global symbol space */
+ s_idx = 0;
+ for (f_idx = -1; f_idx < hdr->ifdMax; f_idx++)
+ {
+ fdr_to_pst[f_idx].globals_offset = s_idx;
+ s_idx += fdr_to_pst[f_idx].n_globals;
+ fdr_to_pst[f_idx].n_globals = 0;
+ }
+
+ /* Pass 2 over external syms: fill in external symbols */
+ ext_in = ext_block;
+ ext_in_end = ext_in + hdr->iextMax;
+ for (; ext_in < ext_in_end; ext_in++)
+ {
+ enum minimal_symbol_type ms_type = mst_text;
+ CORE_ADDR svalue = ext_in->asym.value;
+
+ /* The Irix 5 native tools seem to sometimes generate bogus
+ external symbols. */
+ if (ext_in->ifd < -1 || ext_in->ifd >= hdr->ifdMax)
+ {
+ complain (&bad_ext_ifd_complaint, ext_in->ifd, hdr->ifdMax);
+ continue;
+ }
+ if (ext_in->asym.iss < 0 || ext_in->asym.iss >= hdr->issExtMax)
+ {
+ complain (&bad_ext_iss_complaint, ext_in->asym.iss,
+ hdr->issExtMax);
+ continue;
+ }
+
+ extern_tab[fdr_to_pst[ext_in->ifd].globals_offset
+ + fdr_to_pst[ext_in->ifd].n_globals++] = *ext_in;
+
+ if (ext_in->asym.sc == scUndefined || ext_in->asym.sc == scNil)
+ continue;
+
+ name = debug_info->ssext + ext_in->asym.iss;
+ switch (ext_in->asym.st)
+ {
+ case stProc:
+ svalue += ANOFFSET (section_offsets, SECT_OFF_TEXT);
+ break;
+ case stStaticProc:
+ ms_type = mst_file_text;
+ svalue += ANOFFSET (section_offsets, SECT_OFF_TEXT);
+ break;
+ case stGlobal:
+ if (ext_in->asym.sc == scCommon)
+ {
+ /* The value of a common symbol is its size, not its address.
+ Ignore it. */
+ continue;
+ }
+ else if (ext_in->asym.sc == scData
+ || ext_in->asym.sc == scSData
+ || ext_in->asym.sc == scRData
+ || ext_in->asym.sc == scPData
+ || ext_in->asym.sc == scXData)
+ {
+ ms_type = mst_data;
+ svalue += ANOFFSET (section_offsets, SECT_OFF_DATA);
+ }
+ else
+ {
+ ms_type = mst_bss;
+ svalue += ANOFFSET (section_offsets, SECT_OFF_BSS);
+ }
+ break;
+ case stLabel:
+ if (ext_in->asym.sc == scAbs)
+ ms_type = mst_abs;
+ else if (ext_in->asym.sc == scText
+ || ext_in->asym.sc == scInit
+ || ext_in->asym.sc == scFini)
+ {
+ ms_type = mst_file_text;
+ svalue += ANOFFSET (section_offsets, SECT_OFF_TEXT);
+ }
+ else if (ext_in->asym.sc == scData
+ || ext_in->asym.sc == scSData
+ || ext_in->asym.sc == scRData
+ || ext_in->asym.sc == scPData
+ || ext_in->asym.sc == scXData)
+ {
+ ms_type = mst_file_data;
+ svalue += ANOFFSET (section_offsets, SECT_OFF_DATA);
+ }
+ else
+ {
+ ms_type = mst_file_bss;
+ svalue += ANOFFSET (section_offsets, SECT_OFF_BSS);
+ }
+ break;
+ case stLocal:
+ /* The alpha has the section start addresses in stLocal symbols
+ whose name starts with a `.'. Skip those but complain for all
+ other stLocal symbols. */
+ if (name[0] == '.')
+ continue;
+ /* Fall through. */
+ default:
+ ms_type = mst_unknown;
+ complain (&unknown_ext_complaint, name);
+ }
+ prim_record_minimal_symbol (name, svalue, ms_type, objfile);
+ }
+
+ /* Pass 3 over files, over local syms: fill in static symbols */
+ for (f_idx = 0; f_idx < hdr->ifdMax; f_idx++)
+ {
+ struct partial_symtab *save_pst;
+ EXTR *ext_ptr;
+ CORE_ADDR textlow;
+
+ cur_fdr = fh = debug_info->fdr + f_idx;
+
+ if (fh->csym == 0)
+ {
+ fdr_to_pst[f_idx].pst = NULL;
+ continue;
+ }
+
+ /* Determine the start address for this object file from the
+ file header and relocate it, except for Irix 5.2 zero fh->adr. */
+ if (fh->cpd)
+ {
+ textlow = fh->adr;
+ if (relocatable || textlow != 0)
+ textlow += ANOFFSET (section_offsets, SECT_OFF_TEXT);
+ }
+ else
+ textlow = 0;
+ pst = start_psymtab_common (objfile, section_offsets,
+ fdr_name (fh),
+ textlow,
+ objfile->global_psymbols.next,
+ objfile->static_psymbols.next);
+ pst->read_symtab_private = ((char *)
+ obstack_alloc (&objfile->psymbol_obstack,
+ sizeof (struct symloc)));
+ memset ((PTR) pst->read_symtab_private, 0, sizeof (struct symloc));
+
+ save_pst = pst;
+ FDR_IDX (pst) = f_idx;
+ CUR_BFD (pst) = cur_bfd;
+ DEBUG_SWAP (pst) = debug_swap;
+ DEBUG_INFO (pst) = debug_info;
+ PENDING_LIST (pst) = pending_list;
+
+ /* The way to turn this into a symtab is to call... */
+ pst->read_symtab = mdebug_psymtab_to_symtab;
+
+ /* Set up language for the pst.
+ The language from the FDR is used if it is unambigious (e.g. cfront
+ with native cc and g++ will set the language to C).
+ Otherwise we have to deduce the language from the filename.
+ Native ecoff has every header file in a separate FDR, so
+ deduce_language_from_filename will return language_unknown for
+ a header file, which is not what we want.
+ But the FDRs for the header files are after the FDR for the source
+ file, so we can assign the language of the source file to the
+ following header files. Then we save the language in the private
+ pst data so that we can reuse it when building symtabs. */
+ prev_language = psymtab_language;
+
+ switch (fh->lang)
+ {
+ case langCplusplusV2:
+ psymtab_language = language_cplus;
+ break;
+ default:
+ psymtab_language = deduce_language_from_filename (fdr_name (fh));
+ break;
+ }
+ if (psymtab_language == language_unknown)
+ psymtab_language = prev_language;
+ PST_PRIVATE (pst)->pst_language = psymtab_language;
+
+ pst->texthigh = pst->textlow;
+
+ /* For stabs-in-ecoff files, the second symbol must be @stab.
+ This symbol is emitted by mips-tfile to signal that the
+ current object file uses encapsulated stabs instead of mips
+ ecoff for local symbols. (It is the second symbol because
+ the first symbol is the stFile used to signal the start of a
+ file). */
+ processing_gcc_compilation = 0;
+ if (fh->csym >= 2)
+ {
+ (*swap_sym_in) (cur_bfd,
+ ((char *) debug_info->external_sym
+ + (fh->isymBase + 1) * external_sym_size),
+ &sh);
+ if (STREQ (debug_info->ss + fh->issBase + sh.iss, stabs_symbol))
+ processing_gcc_compilation = 2;
+ }
+
+ if (processing_gcc_compilation != 0)
+ {
+ for (cur_sdx = 2; cur_sdx < fh->csym; cur_sdx++)
+ {
+ int type_code;
+ char *namestring;
+
+ (*swap_sym_in) (cur_bfd,
+ (((char *) debug_info->external_sym)
+ + (fh->isymBase + cur_sdx) * external_sym_size),
+ &sh);
+ type_code = ECOFF_UNMARK_STAB (sh.index);
+ if (!ECOFF_IS_STAB (&sh))
+ {
+ if (sh.st == stProc || sh.st == stStaticProc)
+ {
+ long procaddr;
+ long isym;
+
+ sh.value += ANOFFSET (section_offsets, SECT_OFF_TEXT);
+ if (sh.st == stStaticProc)
+ {
+ namestring = debug_info->ss + fh->issBase + sh.iss;
+ prim_record_minimal_symbol_and_info (namestring,
+ sh.value,
+ mst_file_text,
+ NULL,
+ SECT_OFF_TEXT,
+ objfile);
+ }
+ procaddr = sh.value;
+
+ isym = AUX_GET_ISYM (fh->fBigendian,
+ (debug_info->external_aux
+ + fh->iauxBase
+ + sh.index));
+ (*swap_sym_in) (cur_bfd,
+ ((char *) debug_info->external_sym
+ + ((fh->isymBase + isym - 1)
+ * external_sym_size)),
+ &sh);
+ if (sh.st == stEnd)
+ {
+ long high = procaddr + sh.value;
+
+ /* Kludge for Irix 5.2 zero fh->adr. */
+ if (!relocatable
+ && (pst->textlow == 0 || procaddr < pst->textlow))
+ pst->textlow = procaddr;
+ if (high > pst->texthigh)
+ pst->texthigh = high;
+ }
+ }
+ else if (sh.st == stStatic)
+ {
+ switch (sh.sc)
+ {
+ case scUndefined:
+ case scNil:
+ case scAbs:
+ break;
+
+ case scData:
+ case scSData:
+ case scRData:
+ case scPData:
+ case scXData:
+ namestring = debug_info->ss + fh->issBase + sh.iss;
+ sh.value += ANOFFSET (section_offsets, SECT_OFF_DATA);
+ prim_record_minimal_symbol_and_info (namestring,
+ sh.value,
+ mst_file_data,
+ NULL,
+ SECT_OFF_DATA,
+ objfile);
+ break;
+
+ default:
+ namestring = debug_info->ss + fh->issBase + sh.iss;
+ sh.value += ANOFFSET (section_offsets, SECT_OFF_BSS);
+ prim_record_minimal_symbol_and_info (namestring,
+ sh.value,
+ mst_file_bss,
+ NULL,
+ SECT_OFF_BSS,
+ objfile);
+ break;
+ }
+ }
+ continue;
+ }
+#define SET_NAMESTRING() \
+ namestring = debug_info->ss + fh->issBase + sh.iss
+#define CUR_SYMBOL_TYPE type_code
+#define CUR_SYMBOL_VALUE sh.value
+#define START_PSYMTAB(ofile,secoff,fname,low,symoff,global_syms,static_syms)\
+ pst = save_pst
+#define END_PSYMTAB(pst,ilist,ninc,c_off,c_text,dep_list,n_deps) (void)0
+#define HANDLE_RBRAC(val) \
+ if ((val) > save_pst->texthigh) save_pst->texthigh = (val);
+#include "partial-stab.h"
+ }
+ }
+ else
+ {
+ for (cur_sdx = 0; cur_sdx < fh->csym;)
+ {
+ char *name;
+ enum address_class class;
+
+ (*swap_sym_in) (cur_bfd,
+ ((char *) debug_info->external_sym
+ + ((fh->isymBase + cur_sdx)
+ * external_sym_size)),
+ &sh);
+
+ if (ECOFF_IS_STAB (&sh))
+ {
+ cur_sdx++;
+ continue;
+ }
+
+ /* Non absolute static symbols go into the minimal table. */
+ if (sh.sc == scUndefined || sh.sc == scNil
+ || (sh.index == indexNil
+ && (sh.st != stStatic || sh.sc == scAbs)))
+ {
+ /* FIXME, premature? */
+ cur_sdx++;
+ continue;
+ }
+
+ name = debug_info->ss + fh->issBase + sh.iss;
+
+ switch (sh.sc)
+ {
+ case scText:
+ /* The value of a stEnd symbol is the displacement from the
+ corresponding start symbol value, do not relocate it. */
+ if (sh.st != stEnd)
+ sh.value += ANOFFSET (section_offsets, SECT_OFF_TEXT);
+ break;
+ case scData:
+ case scSData:
+ case scRData:
+ case scPData:
+ case scXData:
+ sh.value += ANOFFSET (section_offsets, SECT_OFF_DATA);
+ break;
+ case scBss:
+ case scSBss:
+ sh.value += ANOFFSET (section_offsets, SECT_OFF_BSS);
+ break;
+ }
+
+ switch (sh.st)
+ {
+ long high;
+ long procaddr;
+ int new_sdx;
+
+ case stStaticProc:
+ prim_record_minimal_symbol_and_info (name, sh.value,
+ mst_file_text, NULL,
+ SECT_OFF_TEXT, objfile);
+
+ /* FALLTHROUGH */
+
+ case stProc:
+ /* Usually there is a local and a global stProc symbol
+ for a function. This means that the function name
+ has already been entered into the mimimal symbol table
+ while processing the global symbols in pass 2 above.
+ One notable exception is the PROGRAM name from
+ f77 compiled executables, it is only put out as
+ local stProc symbol, and a global MAIN__ stProc symbol
+ points to it. It doesn't matter though, as gdb is
+ still able to find the PROGRAM name via the partial
+ symbol table, and the MAIN__ symbol via the minimal
+ symbol table. */
+ if (sh.st == stProc)
+ ADD_PSYMBOL_TO_LIST (name, strlen (name),
+ VAR_NAMESPACE, LOC_BLOCK,
+ objfile->global_psymbols,
+ sh.value, psymtab_language, objfile);
+ else
+ ADD_PSYMBOL_TO_LIST (name, strlen (name),
+ VAR_NAMESPACE, LOC_BLOCK,
+ objfile->static_psymbols,
+ sh.value, psymtab_language, objfile);
+
+ /* Skip over procedure to next one. */
+ if (sh.index >= hdr->iauxMax)
+ {
+ /* Should not happen, but does when cross-compiling
+ with the MIPS compiler. FIXME -- pull later. */
+ complain (&index_complaint, name);
+ new_sdx = cur_sdx + 1; /* Don't skip at all */
+ }
+ else
+ new_sdx = AUX_GET_ISYM (fh->fBigendian,
+ (debug_info->external_aux
+ + fh->iauxBase
+ + sh.index));
+ procaddr = sh.value;
+
+ if (new_sdx <= cur_sdx)
+ {
+ /* This should not happen either... FIXME. */
+ complain (&aux_index_complaint, name);
+ new_sdx = cur_sdx + 1; /* Don't skip backward */
+ }
+
+ cur_sdx = new_sdx;
+ (*swap_sym_in) (cur_bfd,
+ ((char *) debug_info->external_sym
+ + ((fh->isymBase + cur_sdx - 1)
+ * external_sym_size)),
+ &sh);
+ if (sh.st != stEnd)
+ continue;
+
+ /* Kludge for Irix 5.2 zero fh->adr. */
+ if (!relocatable
+ && (pst->textlow == 0 || procaddr < pst->textlow))
+ pst->textlow = procaddr;
+
+ high = procaddr + sh.value;
+ if (high > pst->texthigh)
+ pst->texthigh = high;
+ continue;
+
+ case stStatic: /* Variable */
+ if (sh.sc == scData
+ || sh.sc == scSData
+ || sh.sc == scRData
+ || sh.sc == scPData
+ || sh.sc == scXData)
+ prim_record_minimal_symbol_and_info (name, sh.value,
+ mst_file_data, NULL,
+ SECT_OFF_DATA,
+ objfile);
+ else
+ prim_record_minimal_symbol_and_info (name, sh.value,
+ mst_file_bss, NULL,
+ SECT_OFF_BSS,
+ objfile);
+ class = LOC_STATIC;
+ break;
+
+ case stIndirect:/* Irix5 forward declaration */
+ /* Skip forward declarations from Irix5 cc */
+ goto skip;
+
+ case stTypedef:/* Typedef */
+ /* Skip typedefs for forward declarations and opaque
+ structs from alpha and mips cc. */
+ if (sh.iss == 0 || has_opaque_xref (fh, &sh))
+ goto skip;
+ class = LOC_TYPEDEF;
+ break;
+
+ case stConstant: /* Constant decl */
+ class = LOC_CONST;
+ break;
+
+ case stUnion:
+ case stStruct:
+ case stEnum:
+ case stBlock: /* { }, str, un, enum*/
+ /* Do not create a partial symbol for cc unnamed aggregates
+ and gcc empty aggregates. */
+ if ((sh.sc == scInfo || sh.sc == scCommon)
+ && sh.iss != 0
+ && sh.index != cur_sdx + 2)
+ {
+ ADD_PSYMBOL_TO_LIST (name, strlen (name),
+ STRUCT_NAMESPACE, LOC_TYPEDEF,
+ objfile->static_psymbols,
+ sh.value,
+ psymtab_language, objfile);
+ }
+ handle_psymbol_enumerators (objfile, fh, sh.st);
+
+ /* Skip over the block */
+ new_sdx = sh.index;
+ if (new_sdx <= cur_sdx)
+ {
+ /* This happens with the Ultrix kernel. */
+ complain (&block_index_complaint, name);
+ new_sdx = cur_sdx + 1; /* Don't skip backward */
+ }
+ cur_sdx = new_sdx;
+ continue;
+
+ case stFile: /* File headers */
+ case stLabel: /* Labels */
+ case stEnd: /* Ends of files */
+ goto skip;
+
+ case stLocal: /* Local variables */
+ /* Normally these are skipped because we skip over
+ all blocks we see. However, these can occur
+ as visible symbols in a .h file that contains code. */
+ goto skip;
+
+ default:
+ /* Both complaints are valid: one gives symbol name,
+ the other the offending symbol type. */
+ complain (&unknown_sym_complaint, name);
+ complain (&unknown_st_complaint, sh.st);
+ cur_sdx++;
+ continue;
+ }
+ /* Use this gdb symbol */
+ ADD_PSYMBOL_TO_LIST (name, strlen (name),
+ VAR_NAMESPACE, class,
+ objfile->static_psymbols, sh.value,
+ psymtab_language, objfile);
+ skip:
+ cur_sdx++; /* Go to next file symbol */
+ }
+
+ /* Now do enter the external symbols. */
+ ext_ptr = &extern_tab[fdr_to_pst[f_idx].globals_offset];
+ cur_sdx = fdr_to_pst[f_idx].n_globals;
+ PST_PRIVATE (save_pst)->extern_count = cur_sdx;
+ PST_PRIVATE (save_pst)->extern_tab = ext_ptr;
+ for (; --cur_sdx >= 0; ext_ptr++)
+ {
+ enum address_class class;
+ SYMR *psh;
+ char *name;
+ CORE_ADDR svalue;
+
+ if (ext_ptr->ifd != f_idx)
+ abort ();
+ psh = &ext_ptr->asym;
+
+ /* Do not add undefined symbols to the partial symbol table. */
+ if (psh->sc == scUndefined || psh->sc == scNil)
+ continue;
+
+ svalue = psh->value;
+ switch (psh->sc)
+ {
+ case scText:
+ svalue += ANOFFSET (section_offsets, SECT_OFF_TEXT);
+ break;
+ case scData:
+ case scSData:
+ case scRData:
+ case scPData:
+ case scXData:
+ svalue += ANOFFSET (section_offsets, SECT_OFF_DATA);
+ break;
+ case scBss:
+ case scSBss:
+ svalue += ANOFFSET (section_offsets, SECT_OFF_BSS);
+ break;
+ }
+
+ switch (psh->st)
+ {
+ case stNil:
+ /* These are generated for static symbols in .o files,
+ ignore them. */
+ continue;
+ case stProc:
+ case stStaticProc:
+ /* External procedure symbols have been entered
+ into the minimal symbol table in pass 2 above.
+ Ignore them, as parse_external will ignore them too. */
+ continue;
+ case stLabel:
+ class = LOC_LABEL;
+ break;
+ default:
+ complain (&unknown_ext_complaint,
+ debug_info->ssext + psh->iss);
+ /* Fall through, pretend it's global. */
+ case stGlobal:
+ class = LOC_STATIC;
+ break;
+ }
+ name = debug_info->ssext + psh->iss;
+ ADD_PSYMBOL_ADDR_TO_LIST (name, strlen (name),
+ VAR_NAMESPACE, class,
+ objfile->global_psymbols,
+ svalue,
+ psymtab_language, objfile);
+ }
+ }
+
+ /* Link pst to FDR. end_psymtab returns NULL if the psymtab was
+ empty and put on the free list. */
+ fdr_to_pst[f_idx].pst = end_psymtab (save_pst,
+ psymtab_include_list, includes_used,
+ -1, save_pst->texthigh,
+ dependency_list, dependencies_used);
+ if (objfile->ei.entry_point >= save_pst->textlow &&
+ objfile->ei.entry_point < save_pst->texthigh)
+ {
+ objfile->ei.entry_file_lowpc = save_pst->textlow;
+ objfile->ei.entry_file_highpc = save_pst->texthigh;
+ }
+ }
+
+ /* Now scan the FDRs for dependencies */
+ for (f_idx = 0; f_idx < hdr->ifdMax; f_idx++)
+ {
+ fh = f_idx + debug_info->fdr;
+ pst = fdr_to_pst[f_idx].pst;
+
+ if (pst == (struct partial_symtab *)NULL)
+ continue;
+
+ /* This should catch stabs-in-ecoff. */
+ if (fh->crfd <= 1)
+ continue;
+
+ /* Skip the first file indirect entry as it is a self dependency
+ for source files or a reverse .h -> .c dependency for header files. */
+ pst->number_of_dependencies = 0;
+ pst->dependencies =
+ ((struct partial_symtab **)
+ obstack_alloc (&objfile->psymbol_obstack,
+ ((fh->crfd - 1)
+ * sizeof (struct partial_symtab *))));
+ for (s_idx = 1; s_idx < fh->crfd; s_idx++)
+ {
+ RFDT rh;
+
+ (*swap_rfd_in) (cur_bfd,
+ ((char *) debug_info->external_rfd
+ + (fh->rfdBase + s_idx) * external_rfd_size),
+ &rh);
+ if (rh < 0 || rh >= hdr->ifdMax)
+ {
+ complain (&bad_file_number_complaint, rh);
+ continue;
+ }
+
+ /* Skip self dependencies of header files. */
+ if (rh == f_idx)
+ continue;
+
+ /* Do not add to dependeny list if psymtab was empty. */
+ if (fdr_to_pst[rh].pst == (struct partial_symtab *)NULL)
+ continue;
+ pst->dependencies[pst->number_of_dependencies++] = fdr_to_pst[rh].pst;
+ }
+ }
+
+ /* Remove the dummy psymtab created for -O3 images above, if it is
+ still empty, to enable the detection of stripped executables. */
+ if (objfile->psymtabs->next == NULL
+ && objfile->psymtabs->number_of_dependencies == 0
+ && objfile->psymtabs->n_global_syms == 0
+ && objfile->psymtabs->n_static_syms == 0)
+ objfile->psymtabs = NULL;
+ do_cleanups (old_chain);
+}
+
+/* If the current psymbol has an enumerated type, we need to add
+ all the the enum constants to the partial symbol table. */
+
+static void
+handle_psymbol_enumerators (objfile, fh, stype)
+ struct objfile *objfile;
+ FDR *fh;
+ int stype;
+{
+ const bfd_size_type external_sym_size = debug_swap->external_sym_size;
+ void (* const swap_sym_in) PARAMS ((bfd *, PTR, SYMR *))
+ = debug_swap->swap_sym_in;
+ char *ext_sym = ((char *) debug_info->external_sym
+ + ((fh->isymBase + cur_sdx + 1) * external_sym_size));
+ SYMR sh;
+ TIR tir;
+
+ switch (stype)
+ {
+ case stEnum:
+ break;
+
+ case stBlock:
+ /* It is an enumerated type if the next symbol entry is a stMember
+ and its auxiliary index is indexNil or its auxiliary entry
+ is a plain btNil or btVoid. */
+ (*swap_sym_in) (cur_bfd, ext_sym, &sh);
+ if (sh.st != stMember)
+ return;
+
+ if (sh.index == indexNil)
+ break;
+ (*debug_swap->swap_tir_in) (fh->fBigendian,
+ &(debug_info->external_aux
+ + fh->iauxBase + sh.index)->a_ti,
+ &tir);
+ if ((tir.bt != btNil && tir.bt != btVoid) || tir.tq0 != tqNil)
+ return;
+ break;
+
+ default:
+ return;
+ }
+
+ for (;;)
+ {
+ char *name;
+
+ (*swap_sym_in) (cur_bfd, ext_sym, &sh);
+ if (sh.st != stMember)
+ break;
+ name = debug_info->ss + cur_fdr->issBase + sh.iss;
+
+ /* Note that the value doesn't matter for enum constants
+ in psymtabs, just in symtabs. */
+ ADD_PSYMBOL_TO_LIST (name, strlen (name),
+ VAR_NAMESPACE, LOC_CONST,
+ objfile->static_psymbols, 0,
+ psymtab_language, objfile);
+ ext_sym += external_sym_size;
+ }
+}
+
+static char *
+mdebug_next_symbol_text ()
+{
+ SYMR sh;
+
+ cur_sdx++;
+ (*debug_swap->swap_sym_in) (cur_bfd,
+ ((char *) debug_info->external_sym
+ + ((cur_fdr->isymBase + cur_sdx)
+ * debug_swap->external_sym_size)),
+ &sh);
+ return debug_info->ss + cur_fdr->issBase + sh.iss;
+}
+
+/* Ancillary function to psymtab_to_symtab(). Does all the work
+ for turning the partial symtab PST into a symtab, recurring
+ first on all dependent psymtabs. The argument FILENAME is
+ only passed so we can see in debug stack traces what file
+ is being read.
+
+ This function has a split personality, based on whether the
+ symbol table contains ordinary ecoff symbols, or stabs-in-ecoff.
+ The flow of control and even the memory allocation differs. FIXME. */
+
+static void
+psymtab_to_symtab_1 (pst, filename)
+ struct partial_symtab *pst;
+ char *filename;
+{
+ bfd_size_type external_sym_size;
+ bfd_size_type external_pdr_size;
+ void (*swap_sym_in) PARAMS ((bfd *, PTR, SYMR *));
+ void (*swap_pdr_in) PARAMS ((bfd *, PTR, PDR *));
+ int i;
+ struct symtab *st;
+ FDR *fh;
+ struct linetable *lines;
+
+ if (pst->readin)
+ return;
+ pst->readin = 1;
+
+ /* Read in all partial symbtabs on which this one is dependent.
+ NOTE that we do have circular dependencies, sigh. We solved
+ that by setting pst->readin before this point. */
+
+ for (i = 0; i < pst->number_of_dependencies; i++)
+ if (!pst->dependencies[i]->readin)
+ {
+ /* Inform about additional files to be read in. */
+ if (info_verbose)
+ {
+ fputs_filtered (" ", gdb_stdout);
+ wrap_here ("");
+ fputs_filtered ("and ", gdb_stdout);
+ wrap_here ("");
+ printf_filtered ("%s...",
+ pst->dependencies[i]->filename);
+ wrap_here (""); /* Flush output */
+ gdb_flush (gdb_stdout);
+ }
+ /* We only pass the filename for debug purposes */
+ psymtab_to_symtab_1 (pst->dependencies[i],
+ pst->dependencies[i]->filename);
+ }
+
+ /* Do nothing if this is a dummy psymtab. */
+
+ if (pst->n_global_syms == 0 && pst->n_static_syms == 0
+ && pst->textlow == 0 && pst->texthigh == 0)
+ return;
+
+ /* Now read the symbols for this symtab */
+
+ cur_bfd = CUR_BFD (pst);
+ debug_swap = DEBUG_SWAP (pst);
+ debug_info = DEBUG_INFO (pst);
+ pending_list = PENDING_LIST (pst);
+ external_sym_size = debug_swap->external_sym_size;
+ external_pdr_size = debug_swap->external_pdr_size;
+ swap_sym_in = debug_swap->swap_sym_in;
+ swap_pdr_in = debug_swap->swap_pdr_in;
+ current_objfile = pst->objfile;
+ cur_fd = FDR_IDX (pst);
+ fh = ((cur_fd == -1)
+ ? (FDR *) NULL
+ : debug_info->fdr + cur_fd);
+ cur_fdr = fh;
+
+ /* See comment in parse_partial_symbols about the @stabs sentinel. */
+ processing_gcc_compilation = 0;
+ if (fh != (FDR *) NULL && fh->csym >= 2)
+ {
+ SYMR sh;
+
+ (*swap_sym_in) (cur_bfd,
+ ((char *) debug_info->external_sym
+ + (fh->isymBase + 1) * external_sym_size),
+ &sh);
+ if (STREQ (debug_info->ss + fh->issBase + sh.iss,
+ stabs_symbol))
+ {
+ /* We indicate that this is a GCC compilation so that certain
+ features will be enabled in stabsread/dbxread. */
+ processing_gcc_compilation = 2;
+ }
+ }
+
+ if (processing_gcc_compilation != 0)
+ {
+ char *pdr_ptr;
+ char *pdr_end;
+ int first_pdr;
+ unsigned long first_off = 0;
+
+ /* This symbol table contains stabs-in-ecoff entries. */
+
+ /* Parse local symbols first */
+
+ if (fh->csym <= 2) /* FIXME, this blows psymtab->symtab ptr */
+ {
+ current_objfile = NULL;
+ return;
+ }
+ for (cur_sdx = 2; cur_sdx < fh->csym; cur_sdx++)
+ {
+ SYMR sh;
+ char *name;
+ CORE_ADDR valu;
+
+ (*swap_sym_in) (cur_bfd,
+ (((char *) debug_info->external_sym)
+ + (fh->isymBase + cur_sdx) * external_sym_size),
+ &sh);
+ name = debug_info->ss + fh->issBase + sh.iss;
+ valu = sh.value;
+ if (ECOFF_IS_STAB (&sh))
+ {
+ int type_code = ECOFF_UNMARK_STAB (sh.index);
+
+ /* We should never get non N_STAB symbols here, but they
+ should be harmless, so keep process_one_symbol from
+ complaining about them. */
+ if (type_code & N_STAB)
+ {
+ process_one_symbol (type_code, 0, valu, name,
+ pst->section_offsets, pst->objfile);
+ }
+ if (type_code == N_FUN)
+ {
+ /* Make up special symbol to contain
+ procedure specific info */
+ struct mips_extra_func_info *e =
+ ((struct mips_extra_func_info *)
+ obstack_alloc (&current_objfile->symbol_obstack,
+ sizeof (struct mips_extra_func_info)));
+ struct symbol *s = new_symbol (MIPS_EFI_SYMBOL_NAME);
+ SYMBOL_NAMESPACE (s) = LABEL_NAMESPACE;
+ SYMBOL_CLASS (s) = LOC_CONST;
+ SYMBOL_TYPE (s) = builtin_type_void;
+ SYMBOL_VALUE (s) = (long) e;
+ add_symbol_to_list (s, &local_symbols);
+ }
+ }
+ else if (sh.st == stLabel)
+ {
+ if (sh.index == indexNil)
+ {
+ /* This is what the gcc2_compiled and __gnu_compiled_*
+ show up as. So don't complain. */
+ ;
+ }
+ else
+ /* Handle encoded stab line number. */
+ record_line (current_subfile, sh.index, valu);
+ }
+ else if (sh.st == stProc || sh.st == stStaticProc
+ || sh.st == stStatic || sh.st == stEnd)
+ /* These are generated by gcc-2.x, do not complain */
+ ;
+ else
+ complain (&stab_unknown_complaint, name);
+ }
+ st = end_symtab (pst->texthigh, 0, 0, pst->objfile, SECT_OFF_TEXT);
+ end_stabs ();
+
+ /* Sort the symbol table now, we are done adding symbols to it.
+ We must do this before parse_procedure calls lookup_symbol. */
+ sort_symtab_syms (st);
+
+ /* There used to be a call to sort_blocks here, but this should not
+ be necessary for stabs symtabs. And as sort_blocks modifies the
+ start address of the GLOBAL_BLOCK to the FIRST_LOCAL_BLOCK,
+ it did the wrong thing if the first procedure in a file was
+ generated via asm statements. */
+
+ /* Fill in procedure info next. */
+ first_pdr = 1;
+ pdr_ptr = ((char *) debug_info->external_pdr
+ + fh->ipdFirst * external_pdr_size);
+ pdr_end = pdr_ptr + fh->cpd * external_pdr_size;
+ for (; pdr_ptr < pdr_end; pdr_ptr += external_pdr_size)
+ {
+ PDR pr;
+
+ (*swap_pdr_in) (cur_bfd, pdr_ptr, &pr);
+ if (first_pdr)
+ {
+ first_off = pr.adr;
+ first_pdr = 0;
+ }
+ parse_procedure (&pr, st, first_off, pst);
+ }
+ }
+ else
+ {
+ /* This symbol table contains ordinary ecoff entries. */
+
+ /* FIXME: doesn't use pst->section_offsets. */
+
+ int f_max;
+ int maxlines;
+ EXTR *ext_ptr;
+
+ /* How many symbols will we need */
+ /* FIXME, this does not count enum values. */
+ f_max = pst->n_global_syms + pst->n_static_syms;
+ if (fh == 0)
+ {
+ maxlines = 0;
+ st = new_symtab ("unknown", f_max, 0, pst->objfile);
+ }
+ else
+ {
+ f_max += fh->csym + fh->cpd;
+ maxlines = 2 * fh->cline;
+ st = new_symtab (pst->filename, 2 * f_max, maxlines, pst->objfile);
+
+ /* The proper language was already determined when building
+ the psymtab, use it. */
+ st->language = PST_PRIVATE (pst)->pst_language;
+ }
+
+ psymtab_language = st->language;
+
+ lines = LINETABLE (st);
+
+ /* Get a new lexical context */
+
+ push_parse_stack ();
+ top_stack->cur_st = st;
+ top_stack->cur_block = BLOCKVECTOR_BLOCK (BLOCKVECTOR (st),
+ STATIC_BLOCK);
+ BLOCK_START (top_stack->cur_block) = pst->textlow;
+ BLOCK_END (top_stack->cur_block) = 0;
+ top_stack->blocktype = stFile;
+ top_stack->maxsyms = 2 * f_max;
+ top_stack->cur_type = 0;
+ top_stack->procadr = 0;
+ top_stack->numargs = 0;
+
+ if (fh)
+ {
+ char *sym_ptr;
+ char *sym_end;
+
+ /* Parse local symbols first */
+ sym_ptr = ((char *) debug_info->external_sym
+ + fh->isymBase * external_sym_size);
+ sym_end = sym_ptr + fh->csym * external_sym_size;
+ while (sym_ptr < sym_end)
+ {
+ SYMR sh;
+ int c;
+
+ (*swap_sym_in) (cur_bfd, sym_ptr, &sh);
+ c = parse_symbol (&sh,
+ debug_info->external_aux + fh->iauxBase,
+ sym_ptr, fh->fBigendian, pst->section_offsets);
+ sym_ptr += c * external_sym_size;
+ }
+
+ /* Linenumbers. At the end, check if we can save memory.
+ parse_lines has to look ahead an arbitrary number of PDR
+ structures, so we swap them all first. */
+ if (fh->cpd > 0)
+ {
+ PDR *pr_block;
+ struct cleanup *old_chain;
+ char *pdr_ptr;
+ char *pdr_end;
+ PDR *pdr_in;
+ PDR *pdr_in_end;
+
+ pr_block = (PDR *) xmalloc (fh->cpd * sizeof (PDR));
+
+ old_chain = make_cleanup (free, pr_block);
+
+ pdr_ptr = ((char *) debug_info->external_pdr
+ + fh->ipdFirst * external_pdr_size);
+ pdr_end = pdr_ptr + fh->cpd * external_pdr_size;
+ pdr_in = pr_block;
+ for (;
+ pdr_ptr < pdr_end;
+ pdr_ptr += external_pdr_size, pdr_in++)
+ (*swap_pdr_in) (cur_bfd, pdr_ptr, pdr_in);
+
+ parse_lines (fh, pr_block, lines, maxlines, pst);
+ if (lines->nitems < fh->cline)
+ lines = shrink_linetable (lines);
+
+ /* Fill in procedure info next. */
+ pdr_in = pr_block;
+ pdr_in_end = pdr_in + fh->cpd;
+ for (; pdr_in < pdr_in_end; pdr_in++)
+ parse_procedure (pdr_in, 0, pr_block->adr, pst);
+
+ do_cleanups (old_chain);
+ }
+ }
+
+ LINETABLE (st) = lines;
+
+ /* .. and our share of externals.
+ XXX use the global list to speed up things here. how?
+ FIXME, Maybe quit once we have found the right number of ext's? */
+ top_stack->cur_st = st;
+ top_stack->cur_block = BLOCKVECTOR_BLOCK (BLOCKVECTOR (top_stack->cur_st),
+ GLOBAL_BLOCK);
+ top_stack->blocktype = stFile;
+ top_stack->maxsyms
+ = (debug_info->symbolic_header.isymMax
+ + debug_info->symbolic_header.ipdMax
+ + debug_info->symbolic_header.iextMax);
+
+ ext_ptr = PST_PRIVATE (pst)->extern_tab;
+ for (i = PST_PRIVATE (pst)->extern_count; --i >= 0; ext_ptr++)
+ parse_external (ext_ptr, fh->fBigendian, pst->section_offsets);
+
+ /* If there are undefined symbols, tell the user.
+ The alpha has an undefined symbol for every symbol that is
+ from a shared library, so tell the user only if verbose is on. */
+ if (info_verbose && n_undef_symbols)
+ {
+ printf_filtered ("File %s contains %d unresolved references:",
+ st->filename, n_undef_symbols);
+ printf_filtered ("\n\t%4d variables\n\t%4d procedures\n\t%4d labels\n",
+ n_undef_vars, n_undef_procs, n_undef_labels);
+ n_undef_symbols = n_undef_labels = n_undef_vars = n_undef_procs = 0;
+
+ }
+ pop_parse_stack ();
+
+ st->primary = 1;
+
+ /* Sort the symbol table now, we are done adding symbols to it.*/
+ sort_symtab_syms (st);
+
+ sort_blocks (st);
+ }
+
+ /* Now link the psymtab and the symtab. */
+ pst->symtab = st;
+
+ current_objfile = NULL;
+}
+
+/* Ancillary parsing procedures. */
+
+/* Return 1 if the symbol pointed to by SH has a cross reference
+ to an opaque aggregate type, else 0. */
+
+static int
+has_opaque_xref (fh, sh)
+ FDR *fh;
+ SYMR *sh;
+{
+ TIR tir;
+ union aux_ext *ax;
+ RNDXR rn[1];
+ unsigned int rf;
+
+ if (sh->index == indexNil)
+ return 0;
+
+ ax = debug_info->external_aux + fh->iauxBase + sh->index;
+ (*debug_swap->swap_tir_in) (fh->fBigendian, &ax->a_ti, &tir);
+ if (tir.bt != btStruct && tir.bt != btUnion && tir.bt != btEnum)
+ return 0;
+
+ ax++;
+ (*debug_swap->swap_rndx_in) (fh->fBigendian, &ax->a_rndx, rn);
+ if (rn->rfd == 0xfff)
+ rf = AUX_GET_ISYM (fh->fBigendian, ax + 1);
+ else
+ rf = rn->rfd;
+ if (rf != -1)
+ return 0;
+ return 1;
+}
+
+/* Lookup the type at relative index RN. Return it in TPP
+ if found and in any event come up with its name PNAME.
+ BIGEND says whether aux symbols are big-endian or not (from fh->fBigendian).
+ Return value says how many aux symbols we ate. */
+
+static int
+cross_ref (fd, ax, tpp, type_code, pname, bigend, sym_name)
+ int fd;
+ union aux_ext *ax;
+ struct type **tpp;
+ enum type_code type_code; /* Use to alloc new type if none is found. */
+ char **pname;
+ int bigend;
+ char *sym_name;
+{
+ RNDXR rn[1];
+ unsigned int rf;
+ int result = 1;
+ FDR *fh;
+ char *esh;
+ SYMR sh;
+ int xref_fd;
+ struct mdebug_pending *pend;
+
+ *tpp = (struct type *)NULL;
+
+ (*debug_swap->swap_rndx_in) (bigend, &ax->a_rndx, rn);
+
+ /* Escape index means 'the next one' */
+ if (rn->rfd == 0xfff)
+ {
+ result++;
+ rf = AUX_GET_ISYM (bigend, ax + 1);
+ }
+ else
+ {
+ rf = rn->rfd;
+ }
+
+ /* mips cc uses a rf of -1 for opaque struct definitions.
+ Set TYPE_FLAG_STUB for these types so that check_stub_type will
+ resolve them if the struct gets defined in another compilation unit. */
+ if (rf == -1)
+ {
+ *pname = "<undefined>";
+ *tpp = init_type (type_code, 0, 0, (char *) NULL, current_objfile);
+ TYPE_FLAGS (*tpp) |= TYPE_FLAG_STUB;
+ return result;
+ }
+
+ /* mips cc uses an escaped rn->index of 0 for struct return types
+ of procedures that were compiled without -g. These will always remain
+ undefined. */
+ if (rn->rfd == 0xfff && rn->index == 0)
+ {
+ *pname = "<undefined>";
+ return result;
+ }
+
+ /* Find the relative file descriptor and the symbol in it. */
+ fh = get_rfd (fd, rf);
+ xref_fd = fh - debug_info->fdr;
+
+ if (rn->index >= fh->csym)
+ {
+ /* File indirect entry is corrupt. */
+ *pname = "<illegal>";
+ complain (&bad_rfd_entry_complaint,
+ sym_name, xref_fd, rn->index);
+ return result;
+ }
+
+ /* If we have processed this symbol then we left a forwarding
+ pointer to the type in the pending list. If not, we`ll put
+ it in a list of pending types, to be processed later when
+ the file will be. In any event, we collect the name for the
+ type here. */
+
+ esh = ((char *) debug_info->external_sym
+ + ((fh->isymBase + rn->index)
+ * debug_swap->external_sym_size));
+ (*debug_swap->swap_sym_in) (cur_bfd, esh, &sh);
+
+ /* Make sure that this type of cross reference can be handled. */
+ if ((sh.sc != scInfo
+ || (sh.st != stBlock && sh.st != stTypedef && sh.st != stIndirect
+ && sh.st != stStruct && sh.st != stUnion
+ && sh.st != stEnum))
+ && (sh.sc != scCommon || sh.st != stBlock))
+ {
+ /* File indirect entry is corrupt. */
+ *pname = "<illegal>";
+ complain (&bad_rfd_entry_complaint,
+ sym_name, xref_fd, rn->index);
+ return result;
+ }
+
+ *pname = debug_info->ss + fh->issBase + sh.iss;
+
+ pend = is_pending_symbol (fh, esh);
+ if (pend)
+ *tpp = pend->t;
+ else
+ {
+ /* We have not yet seen this type. */
+
+ if ((sh.iss == 0 && sh.st == stTypedef) || sh.st == stIndirect)
+ {
+ TIR tir;
+
+ /* alpha cc puts out a stTypedef with a sh.iss of zero for
+ two cases:
+ a) forward declarations of structs/unions/enums which are not
+ defined in this compilation unit.
+ For these the type will be void. This is a bad design decision
+ as cross referencing across compilation units is impossible
+ due to the missing name.
+ b) forward declarations of structs/unions/enums which are defined
+ later in this file or in another file in the same compilation
+ unit. Irix5 cc uses a stIndirect symbol for this.
+ Simply cross reference those again to get the true type.
+ The forward references are not entered in the pending list and
+ in the symbol table. */
+
+ (*debug_swap->swap_tir_in) (bigend,
+ &(debug_info->external_aux
+ + fh->iauxBase + sh.index)->a_ti,
+ &tir);
+ if (tir.tq0 != tqNil)
+ complain (&illegal_forward_tq0_complaint, sym_name);
+ switch (tir.bt)
+ {
+ case btVoid:
+ *tpp = init_type (type_code, 0, 0, (char *) NULL,
+ current_objfile);
+ *pname = "<undefined>";
+ break;
+
+ case btStruct:
+ case btUnion:
+ case btEnum:
+ cross_ref (xref_fd,
+ (debug_info->external_aux
+ + fh->iauxBase + sh.index + 1),
+ tpp, type_code, pname,
+ fh->fBigendian, sym_name);
+ break;
+
+ default:
+ complain (&illegal_forward_bt_complaint, tir.bt, sym_name);
+ *tpp = init_type (type_code, 0, 0, (char *) NULL,
+ current_objfile);
+ break;
+ }
+ return result;
+ }
+ else if (sh.st == stTypedef)
+ {
+ /* Parse the type for a normal typedef. This might recursively call
+ cross_ref till we get a non typedef'ed type.
+ FIXME: This is not correct behaviour, but gdb currently
+ cannot handle typedefs without type copying. But type copying is
+ impossible as we might have mutual forward references between
+ two files and the copied type would not get filled in when
+ we later parse its definition. */
+ *tpp = parse_type (xref_fd,
+ debug_info->external_aux + fh->iauxBase,
+ sh.index,
+ (int *)NULL,
+ fh->fBigendian,
+ debug_info->ss + fh->issBase + sh.iss);
+ }
+ else
+ {
+ /* Cross reference to a struct/union/enum which is defined
+ in another file in the same compilation unit but that file
+ has not been parsed yet.
+ Initialize the type only, it will be filled in when
+ it's definition is parsed. */
+ *tpp = init_type (type_code, 0, 0, (char *) NULL, current_objfile);
+ }
+ add_pending (fh, esh, *tpp);
+ }
+
+ /* We used one auxent normally, two if we got a "next one" rf. */
+ return result;
+}
+
+
+/* Quick&dirty lookup procedure, to avoid the MI ones that require
+ keeping the symtab sorted */
+
+static struct symbol *
+mylookup_symbol (name, block, namespace, class)
+ char *name;
+ register struct block *block;
+ enum namespace namespace;
+ enum address_class class;
+{
+ register int bot, top, inc;
+ register struct symbol *sym;
+
+ bot = 0;
+ top = BLOCK_NSYMS (block);
+ inc = name[0];
+ while (bot < top)
+ {
+ sym = BLOCK_SYM (block, bot);
+ if (SYMBOL_NAME (sym)[0] == inc
+ && SYMBOL_NAMESPACE (sym) == namespace
+ && SYMBOL_CLASS (sym) == class
+ && strcmp (SYMBOL_NAME (sym), name) == 0)
+ return sym;
+ bot++;
+ }
+ block = BLOCK_SUPERBLOCK (block);
+ if (block)
+ return mylookup_symbol (name, block, namespace, class);
+ return 0;
+}
+
+
+/* Add a new symbol S to a block B.
+ Infrequently, we will need to reallocate the block to make it bigger.
+ We only detect this case when adding to top_stack->cur_block, since
+ that's the only time we know how big the block is. FIXME. */
+
+static void
+add_symbol (s, b)
+ struct symbol *s;
+ struct block *b;
+{
+ int nsyms = BLOCK_NSYMS (b)++;
+ struct block *origb;
+ struct parse_stack *stackp;
+
+ if (b == top_stack->cur_block &&
+ nsyms >= top_stack->maxsyms)
+ {
+ complain (&block_overflow_complaint, SYMBOL_NAME (s));
+ /* In this case shrink_block is actually grow_block, since
+ BLOCK_NSYMS(b) is larger than its current size. */
+ origb = b;
+ b = shrink_block (top_stack->cur_block, top_stack->cur_st);
+
+ /* Now run through the stack replacing pointers to the
+ original block. shrink_block has already done this
+ for the blockvector and BLOCK_FUNCTION. */
+ for (stackp = top_stack; stackp; stackp = stackp->next)
+ {
+ if (stackp->cur_block == origb)
+ {
+ stackp->cur_block = b;
+ stackp->maxsyms = BLOCK_NSYMS (b);
+ }
+ }
+ }
+ BLOCK_SYM (b, nsyms) = s;
+}
+
+/* Add a new block B to a symtab S */
+
+static void
+add_block (b, s)
+ struct block *b;
+ struct symtab *s;
+{
+ struct blockvector *bv = BLOCKVECTOR (s);
+
+ bv = (struct blockvector *) xrealloc ((PTR) bv,
+ (sizeof (struct blockvector)
+ + BLOCKVECTOR_NBLOCKS (bv)
+ * sizeof (bv->block)));
+ if (bv != BLOCKVECTOR (s))
+ BLOCKVECTOR (s) = bv;
+
+ BLOCKVECTOR_BLOCK (bv, BLOCKVECTOR_NBLOCKS (bv)++) = b;
+}
+
+/* Add a new linenumber entry (LINENO,ADR) to a linevector LT.
+ MIPS' linenumber encoding might need more than one byte
+ to describe it, LAST is used to detect these continuation lines.
+
+ Combining lines with the same line number seems like a bad idea.
+ E.g: There could be a line number entry with the same line number after the
+ prologue and GDB should not ignore it (this is a better way to find
+ a prologue than mips_skip_prologue).
+ But due to the compressed line table format there are line number entries
+ for the same line which are needed to bridge the gap to the next
+ line number entry. These entries have a bogus address info with them
+ and we are unable to tell them from intended duplicate line number
+ entries.
+ This is another reason why -ggdb debugging format is preferable. */
+
+static int
+add_line (lt, lineno, adr, last)
+ struct linetable *lt;
+ int lineno;
+ CORE_ADDR adr;
+ int last;
+{
+ /* DEC c89 sometimes produces zero linenos which confuse gdb.
+ Change them to something sensible. */
+ if (lineno == 0)
+ lineno = 1;
+ if (last == 0)
+ last = -2; /* make sure we record first line */
+
+ if (last == lineno) /* skip continuation lines */
+ return lineno;
+
+ lt->item[lt->nitems].line = lineno;
+ lt->item[lt->nitems++].pc = adr << 2;
+ return lineno;
+}
+
+/* Sorting and reordering procedures */
+
+/* Blocks with a smaller low bound should come first */
+
+static int
+compare_blocks (arg1, arg2)
+ const PTR arg1;
+ const PTR arg2;
+{
+ register int addr_diff;
+ struct block **b1 = (struct block **) arg1;
+ struct block **b2 = (struct block **) arg2;
+
+ addr_diff = (BLOCK_START ((*b1))) - (BLOCK_START ((*b2)));
+ if (addr_diff == 0)
+ return (BLOCK_END ((*b2))) - (BLOCK_END ((*b1)));
+ return addr_diff;
+}
+
+/* Sort the blocks of a symtab S.
+ Reorder the blocks in the blockvector by code-address,
+ as required by some MI search routines */
+
+static void
+sort_blocks (s)
+ struct symtab *s;
+{
+ struct blockvector *bv = BLOCKVECTOR (s);
+
+ if (BLOCKVECTOR_NBLOCKS (bv) <= 2)
+ {
+ /* Cosmetic */
+ if (BLOCK_END (BLOCKVECTOR_BLOCK (bv, GLOBAL_BLOCK)) == 0)
+ BLOCK_START (BLOCKVECTOR_BLOCK (bv, GLOBAL_BLOCK)) = 0;
+ if (BLOCK_END (BLOCKVECTOR_BLOCK (bv, STATIC_BLOCK)) == 0)
+ BLOCK_START (BLOCKVECTOR_BLOCK (bv, STATIC_BLOCK)) = 0;
+ return;
+ }
+ /*
+ * This is very unfortunate: normally all functions are compiled in
+ * the order they are found, but if the file is compiled -O3 things
+ * are very different. It would be nice to find a reliable test
+ * to detect -O3 images in advance.
+ */
+ if (BLOCKVECTOR_NBLOCKS (bv) > 3)
+ qsort (&BLOCKVECTOR_BLOCK (bv, FIRST_LOCAL_BLOCK),
+ BLOCKVECTOR_NBLOCKS (bv) - FIRST_LOCAL_BLOCK,
+ sizeof (struct block *),
+ compare_blocks);
+
+ {
+ register CORE_ADDR high = 0;
+ register int i, j = BLOCKVECTOR_NBLOCKS (bv);
+
+ for (i = FIRST_LOCAL_BLOCK; i < j; i++)
+ if (high < BLOCK_END (BLOCKVECTOR_BLOCK (bv, i)))
+ high = BLOCK_END (BLOCKVECTOR_BLOCK (bv, i));
+ BLOCK_END (BLOCKVECTOR_BLOCK (bv, GLOBAL_BLOCK)) = high;
+ }
+
+ BLOCK_START (BLOCKVECTOR_BLOCK (bv, GLOBAL_BLOCK)) =
+ BLOCK_START (BLOCKVECTOR_BLOCK (bv, FIRST_LOCAL_BLOCK));
+
+ BLOCK_START (BLOCKVECTOR_BLOCK (bv, STATIC_BLOCK)) =
+ BLOCK_START (BLOCKVECTOR_BLOCK (bv, GLOBAL_BLOCK));
+ BLOCK_END (BLOCKVECTOR_BLOCK (bv, STATIC_BLOCK)) =
+ BLOCK_END (BLOCKVECTOR_BLOCK (bv, GLOBAL_BLOCK));
+}
+
+
+/* Constructor/restructor/destructor procedures */
+
+/* Allocate a new symtab for NAME. Needs an estimate of how many symbols
+ MAXSYMS and linenumbers MAXLINES we'll put in it */
+
+static struct symtab *
+new_symtab (name, maxsyms, maxlines, objfile)
+ char *name;
+ int maxsyms;
+ int maxlines;
+ struct objfile *objfile;
+{
+ struct symtab *s = allocate_symtab (name, objfile);
+
+ LINETABLE (s) = new_linetable (maxlines);
+
+ /* All symtabs must have at least two blocks */
+ BLOCKVECTOR (s) = new_bvect (2);
+ BLOCKVECTOR_BLOCK (BLOCKVECTOR (s), GLOBAL_BLOCK) = new_block (maxsyms);
+ BLOCKVECTOR_BLOCK (BLOCKVECTOR (s), STATIC_BLOCK) = new_block (maxsyms);
+ BLOCK_SUPERBLOCK (BLOCKVECTOR_BLOCK (BLOCKVECTOR (s), STATIC_BLOCK)) =
+ BLOCKVECTOR_BLOCK (BLOCKVECTOR (s), GLOBAL_BLOCK);
+
+ s->free_code = free_linetable;
+
+ return (s);
+}
+
+/* Allocate a new partial_symtab NAME */
+
+static struct partial_symtab *
+new_psymtab (name, objfile, section_offsets)
+ char *name;
+ struct objfile *objfile;
+ struct section_offsets *section_offsets;
+{
+ struct partial_symtab *psymtab;
+
+ psymtab = allocate_psymtab (name, objfile);
+ psymtab->section_offsets = section_offsets;
+
+ /* Keep a backpointer to the file's symbols */
+
+ psymtab->read_symtab_private = ((char *)
+ obstack_alloc (&objfile->psymbol_obstack,
+ sizeof (struct symloc)));
+ memset ((PTR) psymtab->read_symtab_private, 0, sizeof (struct symloc));
+ CUR_BFD (psymtab) = cur_bfd;
+ DEBUG_SWAP (psymtab) = debug_swap;
+ DEBUG_INFO (psymtab) = debug_info;
+ PENDING_LIST (psymtab) = pending_list;
+
+ /* The way to turn this into a symtab is to call... */
+ psymtab->read_symtab = mdebug_psymtab_to_symtab;
+ return (psymtab);
+}
+
+
+/* Allocate a linetable array of the given SIZE. Since the struct
+ already includes one item, we subtract one when calculating the
+ proper size to allocate. */
+
+static struct linetable *
+new_linetable (size)
+ int size;
+{
+ struct linetable *l;
+
+ size = (size - 1) * sizeof (l->item) + sizeof (struct linetable);
+ l = (struct linetable *) xmalloc (size);
+ l->nitems = 0;
+ return l;
+}
+
+/* Oops, too big. Shrink it. This was important with the 2.4 linetables,
+ I am not so sure about the 3.4 ones.
+
+ Since the struct linetable already includes one item, we subtract one when
+ calculating the proper size to allocate. */
+
+static struct linetable *
+shrink_linetable (lt)
+ struct linetable *lt;
+{
+
+ return (struct linetable *) xrealloc ((PTR) lt,
+ (sizeof (struct linetable)
+ + ((lt->nitems - 1)
+ * sizeof (lt->item))));
+}
+
+/* Allocate and zero a new blockvector of NBLOCKS blocks. */
+
+static struct blockvector *
+new_bvect (nblocks)
+ int nblocks;
+{
+ struct blockvector *bv;
+ int size;
+
+ size = sizeof (struct blockvector) + nblocks * sizeof (struct block *);
+ bv = (struct blockvector *) xzalloc (size);
+
+ BLOCKVECTOR_NBLOCKS (bv) = nblocks;
+
+ return bv;
+}
+
+/* Allocate and zero a new block of MAXSYMS symbols */
+
+static struct block *
+new_block (maxsyms)
+ int maxsyms;
+{
+ int size = sizeof (struct block) + (maxsyms - 1) * sizeof (struct symbol *);
+
+ return (struct block *) xzalloc (size);
+}
+
+/* Ooops, too big. Shrink block B in symtab S to its minimal size.
+ Shrink_block can also be used by add_symbol to grow a block. */
+
+static struct block *
+shrink_block (b, s)
+ struct block *b;
+ struct symtab *s;
+{
+ struct block *new;
+ struct blockvector *bv = BLOCKVECTOR (s);
+ int i;
+
+ /* Just reallocate it and fix references to the old one */
+
+ new = (struct block *) xrealloc ((PTR) b,
+ (sizeof (struct block)
+ + ((BLOCK_NSYMS (b) - 1)
+ * sizeof (struct symbol *))));
+
+ /* Should chase pointers to old one. Fortunately, that`s just
+ the block`s function and inferior blocks */
+ if (BLOCK_FUNCTION (new) && SYMBOL_BLOCK_VALUE (BLOCK_FUNCTION (new)) == b)
+ SYMBOL_BLOCK_VALUE (BLOCK_FUNCTION (new)) = new;
+ for (i = 0; i < BLOCKVECTOR_NBLOCKS (bv); i++)
+ if (BLOCKVECTOR_BLOCK (bv, i) == b)
+ BLOCKVECTOR_BLOCK (bv, i) = new;
+ else if (BLOCK_SUPERBLOCK (BLOCKVECTOR_BLOCK (bv, i)) == b)
+ BLOCK_SUPERBLOCK (BLOCKVECTOR_BLOCK (bv, i)) = new;
+ return new;
+}
+
+/* Create a new symbol with printname NAME */
+
+static struct symbol *
+new_symbol (name)
+ char *name;
+{
+ struct symbol *s = ((struct symbol *)
+ obstack_alloc (&current_objfile->symbol_obstack,
+ sizeof (struct symbol)));
+
+ memset ((PTR) s, 0, sizeof (*s));
+ SYMBOL_NAME (s) = name;
+ SYMBOL_LANGUAGE (s) = psymtab_language;
+ SYMBOL_INIT_DEMANGLED_NAME (s, &current_objfile->symbol_obstack);
+ return s;
+}
+
+/* Create a new type with printname NAME */
+
+static struct type *
+new_type (name)
+ char *name;
+{
+ struct type *t;
+
+ t = alloc_type (current_objfile);
+ TYPE_NAME (t) = name;
+ TYPE_CPLUS_SPECIFIC (t) = (struct cplus_struct_type *) &cplus_struct_default;
+ return t;
+}
+
+/* Read ECOFF debugging information from a BFD section. This is
+ called from elfread.c. It parses the section into a
+ ecoff_debug_info struct, and then lets the rest of the file handle
+ it as normal. */
+
+void
+elfmdebug_build_psymtabs (objfile, swap, sec, section_offsets)
+ struct objfile *objfile;
+ const struct ecoff_debug_swap *swap;
+ asection *sec;
+ struct section_offsets *section_offsets;
+{
+ bfd *abfd = objfile->obfd;
+ struct ecoff_debug_info *info;
+
+ info = ((struct ecoff_debug_info *)
+ obstack_alloc (&objfile->psymbol_obstack,
+ sizeof (struct ecoff_debug_info)));
+
+ if (!(*swap->read_debug_info) (abfd, sec, info))
+ error ("Error reading ECOFF debugging information: %s",
+ bfd_errmsg (bfd_get_error ()));
+
+ mdebug_build_psymtabs (objfile, swap, info, section_offsets);
+}
+
+
+/* Things used for calling functions in the inferior.
+ These functions are exported to our companion
+ mips-tdep.c file and are here because they play
+ with the symbol-table explicitly. */
+
+/* Sigtramp: make sure we have all the necessary information
+ about the signal trampoline code. Since the official code
+ from MIPS does not do so, we make up that information ourselves.
+ If they fix the library (unlikely) this code will neutralize itself. */
+
+/* FIXME: This function is called only by mips-tdep.c. It needs to be
+ here because it calls functions defined in this file, but perhaps
+ this could be handled in a better way. */
+
+void
+fixup_sigtramp ()
+{
+ struct symbol *s;
+ struct symtab *st;
+ struct block *b, *b0 = NULL;
+
+ sigtramp_address = -1;
+
+ /* We have to handle the following cases here:
+ a) The Mips library has a sigtramp label within sigvec.
+ b) Irix has a _sigtramp which we want to use, but it also has sigvec. */
+ s = lookup_symbol ("sigvec", 0, VAR_NAMESPACE, 0, NULL);
+ if (s != 0)
+ {
+ b0 = SYMBOL_BLOCK_VALUE (s);
+ s = lookup_symbol ("sigtramp", b0, VAR_NAMESPACE, 0, NULL);
+ }
+ if (s == 0)
+ {
+ /* No sigvec or no sigtramp inside sigvec, try _sigtramp. */
+ s = lookup_symbol ("_sigtramp", 0, VAR_NAMESPACE, 0, NULL);
+ }
+
+ /* But maybe this program uses its own version of sigvec */
+ if (s == 0)
+ return;
+
+ /* Did we or MIPSco fix the library ? */
+ if (SYMBOL_CLASS (s) == LOC_BLOCK)
+ {
+ sigtramp_address = BLOCK_START (SYMBOL_BLOCK_VALUE (s));
+ sigtramp_end = BLOCK_END (SYMBOL_BLOCK_VALUE (s));
+ return;
+ }
+
+ sigtramp_address = SYMBOL_VALUE (s);
+ sigtramp_end = sigtramp_address + 0x88; /* black magic */
+
+ /* But what symtab does it live in ? */
+ st = find_pc_symtab (SYMBOL_VALUE (s));
+
+ /*
+ * Ok, there goes the fix: turn it into a procedure, with all the
+ * needed info. Note we make it a nested procedure of sigvec,
+ * which is the way the (assembly) code is actually written.
+ */
+ SYMBOL_NAMESPACE (s) = VAR_NAMESPACE;
+ SYMBOL_CLASS (s) = LOC_BLOCK;
+ SYMBOL_TYPE (s) = init_type (TYPE_CODE_FUNC, 4, 0, (char *) NULL,
+ st->objfile);
+ TYPE_TARGET_TYPE (SYMBOL_TYPE (s)) = builtin_type_void;
+
+ /* Need a block to allocate MIPS_EFI_SYMBOL_NAME in */
+ b = new_block (1);
+ SYMBOL_BLOCK_VALUE (s) = b;
+ BLOCK_START (b) = sigtramp_address;
+ BLOCK_END (b) = sigtramp_end;
+ BLOCK_FUNCTION (b) = s;
+ BLOCK_SUPERBLOCK (b) = BLOCK_SUPERBLOCK (b0);
+ add_block (b, st);
+ sort_blocks (st);
+
+ /* Make a MIPS_EFI_SYMBOL_NAME entry for it */
+ {
+ struct mips_extra_func_info *e =
+ ((struct mips_extra_func_info *)
+ xzalloc (sizeof (struct mips_extra_func_info)));
+
+ e->numargs = 0; /* the kernel thinks otherwise */
+ e->pdr.frameoffset = 32;
+ e->pdr.framereg = SP_REGNUM;
+ /* Note that setting pcreg is no longer strictly necessary as
+ mips_frame_saved_pc is now aware of signal handler frames. */
+ e->pdr.pcreg = PC_REGNUM;
+ e->pdr.regmask = -2;
+ /* Offset to saved r31, in the sigtramp case the saved registers
+ are above the frame in the sigcontext.
+ We have 4 alignment bytes, 12 bytes for onstack, mask and pc,
+ 32 * 4 bytes for the general registers, 12 bytes for mdhi, mdlo, ownedfp
+ and 32 * 4 bytes for the floating point registers. */
+ e->pdr.regoffset = 4 + 12 + 31 * 4;
+ e->pdr.fregmask = -1;
+ /* Offset to saved f30 (first saved *double* register). */
+ e->pdr.fregoffset = 4 + 12 + 32 * 4 + 12 + 30 * 4;
+ e->pdr.isym = (long) s;
+ e->pdr.adr = sigtramp_address;
+
+ current_objfile = st->objfile; /* Keep new_symbol happy */
+ s = new_symbol (MIPS_EFI_SYMBOL_NAME);
+ SYMBOL_VALUE (s) = (long) e;
+ SYMBOL_NAMESPACE (s) = LABEL_NAMESPACE;
+ SYMBOL_CLASS (s) = LOC_CONST;
+ SYMBOL_TYPE (s) = builtin_type_void;
+ current_objfile = NULL;
+ }
+
+ BLOCK_SYM (b, BLOCK_NSYMS (b)++) = s;
+}
+
+void
+_initialize_mdebugread ()
+{
+ /* Missing basic types */
+
+ /* Is a "string" the way btString means it the same as TYPE_CODE_STRING?
+ FIXME. */
+ mdebug_type_string =
+ init_type (TYPE_CODE_STRING,
+ TARGET_CHAR_BIT / TARGET_CHAR_BIT,
+ 0, "string",
+ (struct objfile *) NULL);
+
+ mdebug_type_complex =
+ init_type (TYPE_CODE_ERROR,
+ TARGET_COMPLEX_BIT / TARGET_CHAR_BIT,
+ 0, "complex",
+ (struct objfile *) NULL);
+ mdebug_type_double_complex =
+ init_type (TYPE_CODE_ERROR,
+ TARGET_DOUBLE_COMPLEX_BIT / TARGET_CHAR_BIT,
+ 0, "double complex",
+ (struct objfile *) NULL);
+
+ /* We use TYPE_CODE_INT to print these as integers. Does this do any
+ good? Would we be better off with TYPE_CODE_ERROR? Should
+ TYPE_CODE_ERROR print things in hex if it knows the size? */
+ mdebug_type_fixed_dec =
+ init_type (TYPE_CODE_INT,
+ TARGET_INT_BIT / TARGET_CHAR_BIT,
+ 0, "fixed decimal",
+ (struct objfile *) NULL);
+
+ mdebug_type_float_dec =
+ init_type (TYPE_CODE_ERROR,
+ TARGET_DOUBLE_BIT / TARGET_CHAR_BIT,
+ 0, "floating decimal",
+ (struct objfile *) NULL);
+}
diff --git a/gnu/usr.bin/gdb/gdb/mem-break.c b/gnu/usr.bin/gdb/gdb/mem-break.c
new file mode 100644
index 0000000..2c7ba1f
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/mem-break.c
@@ -0,0 +1,104 @@
+/* Simulate breakpoints by patching locations in the target system, for GDB.
+ Copyright 1990, 1991 Free Software Foundation, Inc.
+ Contributed by Cygnus Support. Written by John Gilmore.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "defs.h"
+
+#ifdef BREAKPOINT
+/* This file is only useful if BREAKPOINT is set. If not, we punt. */
+
+#include "symtab.h"
+#include "breakpoint.h"
+#include "inferior.h"
+#include "target.h"
+
+/* This is the sequence of bytes we insert for a breakpoint. On some
+ machines, breakpoints are handled by the target environment and we
+ don't have to worry about them here. */
+
+static unsigned char break_insn[] = BREAKPOINT;
+
+/* This is only to check that BREAKPOINT fits in BREAKPOINT_MAX bytes. */
+
+static unsigned char check_break_insn_size[BREAKPOINT_MAX] = BREAKPOINT;
+
+/* Insert a breakpoint on targets that don't have any better breakpoint
+ support. We read the contents of the target location and stash it,
+ then overwrite it with a breakpoint instruction. ADDR is the target
+ location in the target machine. CONTENTS_CACHE is a pointer to
+ memory allocated for saving the target contents. It is guaranteed
+ by the caller to be long enough to save sizeof BREAKPOINT bytes (this
+ is accomplished via BREAKPOINT_MAX). */
+
+int
+memory_insert_breakpoint (addr, contents_cache)
+ CORE_ADDR addr;
+ char *contents_cache;
+{
+ int val;
+
+ val = target_read_memory (addr, contents_cache, sizeof break_insn);
+
+ if (val == 0)
+ val = target_write_memory (addr, (char *)break_insn, sizeof break_insn);
+
+ return val;
+}
+
+
+int
+memory_remove_breakpoint (addr, contents_cache)
+ CORE_ADDR addr;
+ char *contents_cache;
+{
+ return target_write_memory (addr, contents_cache, sizeof break_insn);
+}
+
+
+/* FIXME: This is a hack and should depend on the debugging target.
+ See comment in breakpoint.c where this is used. */
+
+int memory_breakpoint_size = sizeof (break_insn);
+
+
+#else /* BREAKPOINT */
+
+char nogo[] = "Breakpoints not implemented for this target.";
+
+int
+memory_insert_breakpoint (addr, contents_cache)
+ CORE_ADDR addr;
+ char *contents_cache;
+{
+ error (nogo);
+ return 0; /* lint */
+}
+
+int
+memory_remove_breakpoint (addr, contents_cache)
+ CORE_ADDR addr;
+ char *contents_cache;
+{
+ error (nogo);
+ return 0; /* lint */
+}
+
+int memory_breakpoint_size = -1;
+
+#endif /* BREAKPOINT */
diff --git a/gnu/usr.bin/gdb/gdb/minsyms.c b/gnu/usr.bin/gdb/gdb/minsyms.c
new file mode 100644
index 0000000..743ba83
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/minsyms.c
@@ -0,0 +1,648 @@
+/* GDB routines for manipulating the minimal symbol tables.
+ Copyright 1992, 1993, 1994 Free Software Foundation, Inc.
+ Contributed by Cygnus Support, using pieces from other GDB modules.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+
+/* This file contains support routines for creating, manipulating, and
+ destroying minimal symbol tables.
+
+ Minimal symbol tables are used to hold some very basic information about
+ all defined global symbols (text, data, bss, abs, etc). The only two
+ required pieces of information are the symbol's name and the address
+ associated with that symbol.
+
+ In many cases, even if a file was compiled with no special options for
+ debugging at all, as long as was not stripped it will contain sufficient
+ information to build useful minimal symbol tables using this structure.
+
+ Even when a file contains enough debugging information to build a full
+ symbol table, these minimal symbols are still useful for quickly mapping
+ between names and addresses, and vice versa. They are also sometimes used
+ to figure out what full symbol table entries need to be read in. */
+
+
+#include "defs.h"
+#include <string.h>
+#include "symtab.h"
+#include "bfd.h"
+#include "symfile.h"
+#include "objfiles.h"
+#include "demangle.h"
+#include "gdb-stabs.h"
+
+/* Accumulate the minimal symbols for each objfile in bunches of BUNCH_SIZE.
+ At the end, copy them all into one newly allocated location on an objfile's
+ symbol obstack. */
+
+#define BUNCH_SIZE 127
+
+struct msym_bunch
+{
+ struct msym_bunch *next;
+ struct minimal_symbol contents[BUNCH_SIZE];
+};
+
+/* Bunch currently being filled up.
+ The next field points to chain of filled bunches. */
+
+static struct msym_bunch *msym_bunch;
+
+/* Number of slots filled in current bunch. */
+
+static int msym_bunch_index;
+
+/* Total number of minimal symbols recorded so far for the objfile. */
+
+static int msym_count;
+
+/* Prototypes for local functions. */
+
+static int
+compare_minimal_symbols PARAMS ((const void *, const void *));
+
+static int
+compact_minimal_symbols PARAMS ((struct minimal_symbol *, int));
+
+/* Look through all the current minimal symbol tables and find the first
+ minimal symbol that matches NAME. If OBJF is non-NULL, it specifies a
+ particular objfile and the search is limited to that objfile. Returns
+ a pointer to the minimal symbol that matches, or NULL if no match is found.
+
+ Note: One instance where there may be duplicate minimal symbols with
+ the same name is when the symbol tables for a shared library and the
+ symbol tables for an executable contain global symbols with the same
+ names (the dynamic linker deals with the duplication). */
+
+struct minimal_symbol *
+lookup_minimal_symbol (name, objf)
+ register const char *name;
+ struct objfile *objf;
+{
+ struct objfile *objfile;
+ struct minimal_symbol *msymbol;
+ struct minimal_symbol *found_symbol = NULL;
+ struct minimal_symbol *found_file_symbol = NULL;
+ struct minimal_symbol *trampoline_symbol = NULL;
+
+ for (objfile = object_files;
+ objfile != NULL && found_symbol == NULL;
+ objfile = objfile -> next)
+ {
+ if (objf == NULL || objf == objfile)
+ {
+ for (msymbol = objfile -> msymbols;
+ msymbol != NULL && SYMBOL_NAME (msymbol) != NULL &&
+ found_symbol == NULL;
+ msymbol++)
+ {
+ if (SYMBOL_MATCHES_NAME (msymbol, name))
+ {
+ switch (MSYMBOL_TYPE (msymbol))
+ {
+ case mst_file_text:
+ case mst_file_data:
+ case mst_file_bss:
+ /* It is file-local. If we find more than one, just
+ return the latest one (the user can't expect
+ useful behavior in that case). */
+ found_file_symbol = msymbol;
+ break;
+
+ case mst_solib_trampoline:
+
+ /* If a trampoline symbol is found, we prefer to
+ keep looking for the *real* symbol. If the
+ actual symbol is not found, then we'll use the
+ trampoline entry. */
+ if (trampoline_symbol == NULL)
+ trampoline_symbol = msymbol;
+ break;
+
+ case mst_unknown:
+ default:
+ found_symbol = msymbol;
+ break;
+ }
+ }
+ }
+ }
+ }
+ /* External symbols are best. */
+ if (found_symbol)
+ return found_symbol;
+
+ /* File-local symbols are next best. */
+ if (found_file_symbol)
+ return found_file_symbol;
+
+ /* Symbols for shared library trampolines are next best. */
+ if (trampoline_symbol)
+ return trampoline_symbol;
+
+ return NULL;
+}
+
+
+/* Search through the minimal symbol table for each objfile and find the
+ symbol whose address is the largest address that is still less than or
+ equal to PC. Returns a pointer to the minimal symbol if such a symbol
+ is found, or NULL if PC is not in a suitable range. Note that we need
+ to look through ALL the minimal symbol tables before deciding on the
+ symbol that comes closest to the specified PC. This is because objfiles
+ can overlap, for example objfile A has .text at 0x100 and .data at 0x40000
+ and objfile B has .text at 0x234 and .data at 0x40048. */
+
+struct minimal_symbol *
+lookup_minimal_symbol_by_pc (pc)
+ register CORE_ADDR pc;
+{
+ register int lo;
+ register int hi;
+ register int new;
+ register struct objfile *objfile;
+ register struct minimal_symbol *msymbol;
+ register struct minimal_symbol *best_symbol = NULL;
+
+ for (objfile = object_files;
+ objfile != NULL;
+ objfile = objfile -> next)
+ {
+ /* If this objfile has a minimal symbol table, go search it using
+ a binary search. Note that a minimal symbol table always consists
+ of at least two symbols, a "real" symbol and the terminating
+ "null symbol". If there are no real symbols, then there is no
+ minimal symbol table at all. */
+
+ if ((msymbol = objfile -> msymbols) != NULL)
+ {
+ lo = 0;
+ hi = objfile -> minimal_symbol_count - 1;
+
+ /* This code assumes that the minimal symbols are sorted by
+ ascending address values. If the pc value is greater than or
+ equal to the first symbol's address, then some symbol in this
+ minimal symbol table is a suitable candidate for being the
+ "best" symbol. This includes the last real symbol, for cases
+ where the pc value is larger than any address in this vector.
+
+ By iterating until the address associated with the current
+ hi index (the endpoint of the test interval) is less than
+ or equal to the desired pc value, we accomplish two things:
+ (1) the case where the pc value is larger than any minimal
+ symbol address is trivially solved, (2) the address associated
+ with the hi index is always the one we want when the interation
+ terminates. In essence, we are iterating the test interval
+ down until the pc value is pushed out of it from the high end.
+
+ Warning: this code is trickier than it would appear at first. */
+
+ /* Should also requires that pc is <= end of objfile. FIXME! */
+ if (pc >= SYMBOL_VALUE_ADDRESS (&msymbol[lo]))
+ {
+ while (SYMBOL_VALUE_ADDRESS (&msymbol[hi]) > pc)
+ {
+ /* pc is still strictly less than highest address */
+ /* Note "new" will always be >= lo */
+ new = (lo + hi) / 2;
+ if ((SYMBOL_VALUE_ADDRESS (&msymbol[new]) >= pc) ||
+ (lo == new))
+ {
+ hi = new;
+ }
+ else
+ {
+ lo = new;
+ }
+ }
+ /* The minimal symbol indexed by hi now is the best one in this
+ objfile's minimal symbol table. See if it is the best one
+ overall. */
+
+ /* Skip any absolute symbols. This is apparently what adb
+ and dbx do, and is needed for the CM-5. There are two
+ known possible problems: (1) on ELF, apparently end, edata,
+ etc. are absolute. Not sure ignoring them here is a big
+ deal, but if we want to use them, the fix would go in
+ elfread.c. (2) I think shared library entry points on the
+ NeXT are absolute. If we want special handling for this
+ it probably should be triggered by a special
+ mst_abs_or_lib or some such. */
+ while (hi >= 0
+ && msymbol[hi].type == mst_abs)
+ --hi;
+
+ if (hi >= 0
+ && ((best_symbol == NULL) ||
+ (SYMBOL_VALUE_ADDRESS (best_symbol) <
+ SYMBOL_VALUE_ADDRESS (&msymbol[hi]))))
+ {
+ best_symbol = &msymbol[hi];
+ }
+ }
+ }
+ }
+ return (best_symbol);
+}
+
+/* Prepare to start collecting minimal symbols. Note that presetting
+ msym_bunch_index to BUNCH_SIZE causes the first call to save a minimal
+ symbol to allocate the memory for the first bunch. */
+
+void
+init_minimal_symbol_collection ()
+{
+ msym_count = 0;
+ msym_bunch = NULL;
+ msym_bunch_index = BUNCH_SIZE;
+}
+
+void
+prim_record_minimal_symbol (name, address, ms_type, objfile)
+ const char *name;
+ CORE_ADDR address;
+ enum minimal_symbol_type ms_type;
+ struct objfile *objfile;
+{
+ int section;
+
+ switch (ms_type)
+ {
+ case mst_text:
+ case mst_file_text:
+ case mst_solib_trampoline:
+ section = SECT_OFF_TEXT;
+ break;
+ case mst_data:
+ case mst_file_data:
+ section = SECT_OFF_DATA;
+ break;
+ case mst_bss:
+ case mst_file_bss:
+ section = SECT_OFF_BSS;
+ break;
+ default:
+ section = -1;
+ }
+
+ prim_record_minimal_symbol_and_info (name, address, ms_type,
+ NULL, section, objfile);
+}
+
+void
+prim_record_minimal_symbol_and_info (name, address, ms_type, info, section,
+ objfile)
+ const char *name;
+ CORE_ADDR address;
+ enum minimal_symbol_type ms_type;
+ char *info;
+ int section;
+ struct objfile *objfile;
+{
+ register struct msym_bunch *new;
+ register struct minimal_symbol *msymbol;
+
+ if (ms_type == mst_file_text)
+ {
+ /* Don't put gcc_compiled, __gnu_compiled_cplus, and friends into
+ the minimal symbols, because if there is also another symbol
+ at the same address (e.g. the first function of the file),
+ lookup_minimal_symbol_by_pc would have no way of getting the
+ right one. */
+ if (name[0] == 'g'
+ && (strcmp (name, GCC_COMPILED_FLAG_SYMBOL) == 0
+ || strcmp (name, GCC2_COMPILED_FLAG_SYMBOL) == 0))
+ return;
+
+ {
+ const char *tempstring = name;
+ if (tempstring[0] == bfd_get_symbol_leading_char (objfile->obfd))
+ ++tempstring;
+ if (STREQN (tempstring, "__gnu_compiled", 14))
+ return;
+ }
+ }
+
+ if (msym_bunch_index == BUNCH_SIZE)
+ {
+ new = (struct msym_bunch *) xmalloc (sizeof (struct msym_bunch));
+ msym_bunch_index = 0;
+ new -> next = msym_bunch;
+ msym_bunch = new;
+ }
+ msymbol = &msym_bunch -> contents[msym_bunch_index];
+ SYMBOL_NAME (msymbol) = (char *) name;
+ SYMBOL_INIT_LANGUAGE_SPECIFIC (msymbol, language_unknown);
+ SYMBOL_VALUE_ADDRESS (msymbol) = address;
+ SYMBOL_SECTION (msymbol) = section;
+
+ MSYMBOL_TYPE (msymbol) = ms_type;
+ /* FIXME: This info, if it remains, needs its own field. */
+ MSYMBOL_INFO (msymbol) = info; /* FIXME! */
+ msym_bunch_index++;
+ msym_count++;
+}
+
+/* Compare two minimal symbols by address and return a signed result based
+ on unsigned comparisons, so that we sort into unsigned numeric order. */
+
+static int
+compare_minimal_symbols (fn1p, fn2p)
+ const PTR fn1p;
+ const PTR fn2p;
+{
+ register const struct minimal_symbol *fn1;
+ register const struct minimal_symbol *fn2;
+
+ fn1 = (const struct minimal_symbol *) fn1p;
+ fn2 = (const struct minimal_symbol *) fn2p;
+
+ if (SYMBOL_VALUE_ADDRESS (fn1) < SYMBOL_VALUE_ADDRESS (fn2))
+ {
+ return (-1);
+ }
+ else if (SYMBOL_VALUE_ADDRESS (fn1) > SYMBOL_VALUE_ADDRESS (fn2))
+ {
+ return (1);
+ }
+ else
+ {
+ return (0);
+ }
+}
+
+/* Discard the currently collected minimal symbols, if any. If we wish
+ to save them for later use, we must have already copied them somewhere
+ else before calling this function.
+
+ FIXME: We could allocate the minimal symbol bunches on their own
+ obstack and then simply blow the obstack away when we are done with
+ it. Is it worth the extra trouble though? */
+
+/* ARGSUSED */
+void
+discard_minimal_symbols (foo)
+ int foo;
+{
+ register struct msym_bunch *next;
+
+ while (msym_bunch != NULL)
+ {
+ next = msym_bunch -> next;
+ free ((PTR)msym_bunch);
+ msym_bunch = next;
+ }
+}
+
+/* Compact duplicate entries out of a minimal symbol table by walking
+ through the table and compacting out entries with duplicate addresses
+ and matching names. Return the number of entries remaining.
+
+ On entry, the table resides between msymbol[0] and msymbol[mcount].
+ On exit, it resides between msymbol[0] and msymbol[result_count].
+
+ When files contain multiple sources of symbol information, it is
+ possible for the minimal symbol table to contain many duplicate entries.
+ As an example, SVR4 systems use ELF formatted object files, which
+ usually contain at least two different types of symbol tables (a
+ standard ELF one and a smaller dynamic linking table), as well as
+ DWARF debugging information for files compiled with -g.
+
+ Without compacting, the minimal symbol table for gdb itself contains
+ over a 1000 duplicates, about a third of the total table size. Aside
+ from the potential trap of not noticing that two successive entries
+ identify the same location, this duplication impacts the time required
+ to linearly scan the table, which is done in a number of places. So we
+ just do one linear scan here and toss out the duplicates.
+
+ Note that we are not concerned here about recovering the space that
+ is potentially freed up, because the strings themselves are allocated
+ on the symbol_obstack, and will get automatically freed when the symbol
+ table is freed. The caller can free up the unused minimal symbols at
+ the end of the compacted region if their allocation strategy allows it.
+
+ Also note we only go up to the next to last entry within the loop
+ and then copy the last entry explicitly after the loop terminates.
+
+ Since the different sources of information for each symbol may
+ have different levels of "completeness", we may have duplicates
+ that have one entry with type "mst_unknown" and the other with a
+ known type. So if the one we are leaving alone has type mst_unknown,
+ overwrite its type with the type from the one we are compacting out. */
+
+static int
+compact_minimal_symbols (msymbol, mcount)
+ struct minimal_symbol *msymbol;
+ int mcount;
+{
+ struct minimal_symbol *copyfrom;
+ struct minimal_symbol *copyto;
+
+ if (mcount > 0)
+ {
+ copyfrom = copyto = msymbol;
+ while (copyfrom < msymbol + mcount - 1)
+ {
+ if (SYMBOL_VALUE_ADDRESS (copyfrom) ==
+ SYMBOL_VALUE_ADDRESS ((copyfrom + 1)) &&
+ (STREQ (SYMBOL_NAME (copyfrom), SYMBOL_NAME ((copyfrom + 1)))))
+ {
+ if (MSYMBOL_TYPE((copyfrom + 1)) == mst_unknown)
+ {
+ MSYMBOL_TYPE ((copyfrom + 1)) = MSYMBOL_TYPE (copyfrom);
+ }
+ copyfrom++;
+ }
+ else
+ {
+ *copyto++ = *copyfrom++;
+ }
+ }
+ *copyto++ = *copyfrom++;
+ mcount = copyto - msymbol;
+ }
+ return (mcount);
+}
+
+/* Add the minimal symbols in the existing bunches to the objfile's official
+ minimal symbol table. In most cases there is no minimal symbol table yet
+ for this objfile, and the existing bunches are used to create one. Once
+ in a while (for shared libraries for example), we add symbols (e.g. common
+ symbols) to an existing objfile.
+
+ Because of the way minimal symbols are collected, we generally have no way
+ of knowing what source language applies to any particular minimal symbol.
+ Specifically, we have no way of knowing if the minimal symbol comes from a
+ C++ compilation unit or not. So for the sake of supporting cached
+ demangled C++ names, we have no choice but to try and demangle each new one
+ that comes in. If the demangling succeeds, then we assume it is a C++
+ symbol and set the symbol's language and demangled name fields
+ appropriately. Note that in order to avoid unnecessary demanglings, and
+ allocating obstack space that subsequently can't be freed for the demangled
+ names, we mark all newly added symbols with language_auto. After
+ compaction of the minimal symbols, we go back and scan the entire minimal
+ symbol table looking for these new symbols. For each new symbol we attempt
+ to demangle it, and if successful, record it as a language_cplus symbol
+ and cache the demangled form on the symbol obstack. Symbols which don't
+ demangle are marked as language_unknown symbols, which inhibits future
+ attempts to demangle them if we later add more minimal symbols. */
+
+void
+install_minimal_symbols (objfile)
+ struct objfile *objfile;
+{
+ register int bindex;
+ register int mcount;
+ register struct msym_bunch *bunch;
+ register struct minimal_symbol *msymbols;
+ int alloc_count;
+ register char leading_char;
+
+ if (msym_count > 0)
+ {
+ /* Allocate enough space in the obstack, into which we will gather the
+ bunches of new and existing minimal symbols, sort them, and then
+ compact out the duplicate entries. Once we have a final table,
+ we will give back the excess space. */
+
+ alloc_count = msym_count + objfile->minimal_symbol_count + 1;
+ obstack_blank (&objfile->symbol_obstack,
+ alloc_count * sizeof (struct minimal_symbol));
+ msymbols = (struct minimal_symbol *)
+ obstack_base (&objfile->symbol_obstack);
+
+ /* Copy in the existing minimal symbols, if there are any. */
+
+ if (objfile->minimal_symbol_count)
+ memcpy ((char *)msymbols, (char *)objfile->msymbols,
+ objfile->minimal_symbol_count * sizeof (struct minimal_symbol));
+
+ /* Walk through the list of minimal symbol bunches, adding each symbol
+ to the new contiguous array of symbols. Note that we start with the
+ current, possibly partially filled bunch (thus we use the current
+ msym_bunch_index for the first bunch we copy over), and thereafter
+ each bunch is full. */
+
+ mcount = objfile->minimal_symbol_count;
+ leading_char = bfd_get_symbol_leading_char (objfile->obfd);
+
+ for (bunch = msym_bunch; bunch != NULL; bunch = bunch -> next)
+ {
+ for (bindex = 0; bindex < msym_bunch_index; bindex++, mcount++)
+ {
+ msymbols[mcount] = bunch -> contents[bindex];
+ SYMBOL_LANGUAGE (&msymbols[mcount]) = language_auto;
+ if (SYMBOL_NAME (&msymbols[mcount])[0] == leading_char)
+ {
+ SYMBOL_NAME(&msymbols[mcount])++;
+ }
+ }
+ msym_bunch_index = BUNCH_SIZE;
+ }
+
+ /* Sort the minimal symbols by address. */
+
+ qsort (msymbols, mcount, sizeof (struct minimal_symbol),
+ compare_minimal_symbols);
+
+ /* Compact out any duplicates, and free up whatever space we are
+ no longer using. */
+
+ mcount = compact_minimal_symbols (msymbols, mcount);
+
+ obstack_blank (&objfile->symbol_obstack,
+ (mcount + 1 - alloc_count) * sizeof (struct minimal_symbol));
+ msymbols = (struct minimal_symbol *)
+ obstack_finish (&objfile->symbol_obstack);
+
+ /* We also terminate the minimal symbol table with a "null symbol",
+ which is *not* included in the size of the table. This makes it
+ easier to find the end of the table when we are handed a pointer
+ to some symbol in the middle of it. Zero out the fields in the
+ "null symbol" allocated at the end of the array. Note that the
+ symbol count does *not* include this null symbol, which is why it
+ is indexed by mcount and not mcount-1. */
+
+ SYMBOL_NAME (&msymbols[mcount]) = NULL;
+ SYMBOL_VALUE_ADDRESS (&msymbols[mcount]) = 0;
+ MSYMBOL_INFO (&msymbols[mcount]) = NULL;
+ MSYMBOL_TYPE (&msymbols[mcount]) = mst_unknown;
+ SYMBOL_INIT_LANGUAGE_SPECIFIC (&msymbols[mcount], language_unknown);
+
+ /* Attach the minimal symbol table to the specified objfile.
+ The strings themselves are also located in the symbol_obstack
+ of this objfile. */
+
+ objfile -> minimal_symbol_count = mcount;
+ objfile -> msymbols = msymbols;
+
+ /* Now walk through all the minimal symbols, selecting the newly added
+ ones and attempting to cache their C++ demangled names. */
+
+ for ( ; mcount-- > 0 ; msymbols++)
+ {
+ SYMBOL_INIT_DEMANGLED_NAME (msymbols, &objfile->symbol_obstack);
+ }
+ }
+}
+
+/* Check if PC is in a shared library trampoline code stub.
+ Return minimal symbol for the trampoline entry or NULL if PC is not
+ in a trampoline code stub. */
+
+struct minimal_symbol *
+lookup_solib_trampoline_symbol_by_pc (pc)
+ CORE_ADDR pc;
+{
+ struct minimal_symbol *msymbol = lookup_minimal_symbol_by_pc (pc);
+
+ if (msymbol != NULL && MSYMBOL_TYPE (msymbol) == mst_solib_trampoline)
+ return msymbol;
+ return NULL;
+}
+
+/* If PC is in a shared library trampoline code stub, return the
+ address of the `real' function belonging to the stub.
+ Return 0 if PC is not in a trampoline code stub or if the real
+ function is not found in the minimal symbol table.
+
+ We may fail to find the right function if a function with the
+ same name is defined in more than one shared library, but this
+ is considered bad programming style. We could return 0 if we find
+ a duplicate function in case this matters someday. */
+
+CORE_ADDR
+find_solib_trampoline_target (pc)
+ CORE_ADDR pc;
+{
+ struct objfile *objfile;
+ struct minimal_symbol *msymbol;
+ struct minimal_symbol *tsymbol = lookup_solib_trampoline_symbol_by_pc (pc);
+
+ if (tsymbol != NULL)
+ {
+ ALL_MSYMBOLS (objfile, msymbol)
+ {
+ if (MSYMBOL_TYPE (msymbol) == mst_text
+ && STREQ (SYMBOL_NAME (msymbol), SYMBOL_NAME (tsymbol)))
+ return SYMBOL_VALUE_ADDRESS (msymbol);
+ }
+ }
+ return 0;
+}
+
diff --git a/gnu/usr.bin/gdb/gdb/mipsread.c b/gnu/usr.bin/gdb/gdb/mipsread.c
new file mode 100644
index 0000000..8c45a94
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/mipsread.c
@@ -0,0 +1,457 @@
+/* Read a symbol table in MIPS' format (Third-Eye).
+ Copyright 1986, 1987, 1989, 1990, 1991, 1992, 1993, 1994
+ Free Software Foundation, Inc.
+ Contributed by Alessandro Forin (af@cs.cmu.edu) at CMU. Major work
+ by Per Bothner, John Gilmore and Ian Lance Taylor at Cygnus Support.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* Read symbols from an ECOFF file. Most of the work is done in
+ mdebugread.c. */
+
+#include "defs.h"
+#include <string.h>
+#include "bfd.h"
+#include "symtab.h"
+#include "symfile.h"
+#include "objfiles.h"
+#include "buildsym.h"
+#include "stabsread.h"
+#include "gdb-stabs.h"
+
+#include "coff/sym.h"
+#include "coff/internal.h"
+#include "coff/ecoff.h"
+#include "libcoff.h" /* Private BFD COFF information. */
+#include "libecoff.h" /* Private BFD ECOFF information. */
+#include "elf/common.h"
+#include "elf/mips.h"
+
+static void
+mipscoff_new_init PARAMS ((struct objfile *));
+
+static void
+mipscoff_symfile_init PARAMS ((struct objfile *));
+
+static void
+mipscoff_symfile_read PARAMS ((struct objfile *, struct section_offsets *,
+ int));
+
+static void
+mipscoff_symfile_finish PARAMS ((struct objfile *));
+
+static struct section_offsets *
+mipscoff_symfile_offsets PARAMS ((struct objfile *, CORE_ADDR));
+
+static void
+read_alphacoff_dynamic_symtab PARAMS ((struct section_offsets *,
+ struct objfile *objfile));
+
+/* Initialize anything that needs initializing when a completely new
+ symbol file is specified (not just adding some symbols from another
+ file, e.g. a shared library). */
+
+extern CORE_ADDR sigtramp_address;
+
+static void
+mipscoff_new_init (ignore)
+ struct objfile *ignore;
+{
+ sigtramp_address = 0;
+ stabsread_new_init ();
+ buildsym_new_init ();
+}
+
+/* Initialize to read a symbol file (nothing to do). */
+
+static void
+mipscoff_symfile_init (objfile)
+ struct objfile *objfile;
+{
+}
+
+/* Read a symbol file from a file. */
+
+static void
+mipscoff_symfile_read (objfile, section_offsets, mainline)
+ struct objfile *objfile;
+ struct section_offsets *section_offsets;
+ int mainline;
+{
+ bfd *abfd = objfile->obfd;
+ struct cleanup * back_to;
+
+ init_minimal_symbol_collection ();
+ back_to = make_cleanup (discard_minimal_symbols, 0);
+
+ /* Now that the executable file is positioned at symbol table,
+ process it and define symbols accordingly. */
+
+ if (!((*ecoff_backend (abfd)->debug_swap.read_debug_info)
+ (abfd, (asection *) NULL, &ecoff_data (abfd)->debug_info)))
+ error ("Error reading symbol table: %s", bfd_errmsg (bfd_get_error ()));
+
+ mdebug_build_psymtabs (objfile, &ecoff_backend (abfd)->debug_swap,
+ &ecoff_data (abfd)->debug_info, section_offsets);
+
+ /* Add the dynamic symbols if we are reading the main symbol table. */
+
+ if (mainline)
+ read_alphacoff_dynamic_symtab (section_offsets, objfile);
+
+ /* Install any minimal symbols that have been collected as the current
+ minimal symbols for this objfile. */
+
+ install_minimal_symbols (objfile);
+
+ do_cleanups (back_to);
+}
+
+/* Perform any local cleanups required when we are done with a
+ particular objfile. */
+
+static void
+mipscoff_symfile_finish (objfile)
+ struct objfile *objfile;
+{
+}
+
+/* Fake up identical offsets for all sections. */
+
+static struct section_offsets *
+mipscoff_symfile_offsets (objfile, addr)
+ struct objfile *objfile;
+ CORE_ADDR addr;
+{
+ struct section_offsets *section_offsets;
+ int i;
+
+ objfile->num_sections = SECT_OFF_MAX;
+ section_offsets = ((struct section_offsets *)
+ obstack_alloc (&objfile->psymbol_obstack,
+ (sizeof (struct section_offsets)
+ + (sizeof (section_offsets->offsets)
+ * (SECT_OFF_MAX - 1)))));
+
+ for (i = 0; i < SECT_OFF_MAX; i++)
+ ANOFFSET (section_offsets, i) = addr;
+
+ return section_offsets;
+}
+
+/* Alpha OSF/1 encapsulates the dynamic symbols in ELF format in a
+ standard coff section. The ELF format for the symbols differs from
+ the format defined in elf/external.h. It seems that a normal ELF 32 bit
+ format is used, and the representation only changes because longs are
+ 64 bit on the alpha. In addition, the handling of text/data section
+ indices for symbols is different from the ELF ABI.
+ As the BFD linker currently does not support dynamic linking on the alpha,
+ there seems to be no reason to pollute BFD with another mixture of object
+ file formats for now. */
+
+/* Format of an alpha external ELF symbol. */
+
+typedef struct {
+ unsigned char st_name[4]; /* Symbol name, index in string tbl */
+ unsigned char st_pad[4]; /* Pad to long word boundary */
+ unsigned char st_value[8]; /* Value of the symbol */
+ unsigned char st_size[4]; /* Associated symbol size */
+ unsigned char st_info[1]; /* Type and binding attributes */
+ unsigned char st_other[1]; /* No defined meaning, 0 */
+ unsigned char st_shndx[2]; /* Associated section index */
+} Elfalpha_External_Sym;
+
+/* Format of an alpha external ELF dynamic info structure. */
+
+typedef struct {
+ unsigned char d_tag[4]; /* Tag */
+ unsigned char d_pad[4]; /* Pad to long word boundary */
+ union {
+ unsigned char d_ptr[8]; /* Pointer value */
+ unsigned char d_val[4]; /* Integer value */
+ } d_un;
+} Elfalpha_External_Dyn;
+
+/* Struct to obtain the section pointers for alpha dynamic symbol info. */
+
+struct alphacoff_dynsecinfo {
+ asection *sym_sect; /* Section pointer for .dynsym section */
+ asection *str_sect; /* Section pointer for .dynstr section */
+ asection *dyninfo_sect; /* Section pointer for .dynamic section */
+ asection *got_sect; /* Section pointer for .got section */
+};
+
+static void
+alphacoff_locate_sections PARAMS ((bfd *, asection *, void *));
+
+/* We are called once per section from read_alphacoff_dynamic_symtab.
+ We need to examine each section we are passed, check to see
+ if it is something we are interested in processing, and
+ if so, stash away some access information for the section. */
+
+static void
+alphacoff_locate_sections (ignore_abfd, sectp, sip)
+ bfd *ignore_abfd;
+ asection *sectp;
+ PTR sip;
+{
+ register struct alphacoff_dynsecinfo *si;
+
+ si = (struct alphacoff_dynsecinfo *) sip;
+
+ if (STREQ (sectp->name, ".dynsym"))
+ {
+ si->sym_sect = sectp;
+ }
+ else if (STREQ (sectp->name, ".dynstr"))
+ {
+ si->str_sect = sectp;
+ }
+ else if (STREQ (sectp->name, ".dynamic"))
+ {
+ si->dyninfo_sect = sectp;
+ }
+ else if (STREQ (sectp->name, ".got"))
+ {
+ si->got_sect = sectp;
+ }
+}
+
+/* Scan an alpha dynamic symbol table for symbols of interest and
+ add them to the minimal symbol table. */
+
+static void
+read_alphacoff_dynamic_symtab (section_offsets, objfile)
+ struct section_offsets *section_offsets;
+ struct objfile *objfile;
+{
+ bfd *abfd = objfile->obfd;
+ struct alphacoff_dynsecinfo si;
+ char *sym_secptr;
+ char *str_secptr;
+ char *dyninfo_secptr;
+ char *got_secptr;
+ bfd_size_type sym_secsize;
+ bfd_size_type str_secsize;
+ bfd_size_type dyninfo_secsize;
+ bfd_size_type got_secsize;
+ int sym_count;
+ int i;
+ int stripped;
+ Elfalpha_External_Sym *x_symp;
+ char *dyninfo_p;
+ char *dyninfo_end;
+ int got_entry_size = 8;
+ int dt_mips_local_gotno = -1;
+ int dt_mips_gotsym = -1;
+
+
+ /* We currently only know how to handle alpha dynamic symbols. */
+ if (bfd_get_arch (abfd) != bfd_arch_alpha)
+ return;
+
+ /* Locate the dynamic symbols sections and read them in. */
+ memset ((char *) &si, 0, sizeof (si));
+ bfd_map_over_sections (abfd, alphacoff_locate_sections, (PTR) &si);
+ if (si.sym_sect == NULL
+ || si.str_sect == NULL
+ || si.dyninfo_sect == NULL
+ || si.got_sect == NULL)
+ return;
+
+ sym_secsize = bfd_get_section_size_before_reloc (si.sym_sect);
+ str_secsize = bfd_get_section_size_before_reloc (si.str_sect);
+ dyninfo_secsize = bfd_get_section_size_before_reloc (si.dyninfo_sect);
+ got_secsize = bfd_get_section_size_before_reloc (si.got_sect);
+ sym_secptr = alloca (sym_secsize);
+ str_secptr = alloca (str_secsize);
+ dyninfo_secptr = alloca (dyninfo_secsize);
+ got_secptr = alloca (got_secsize);
+
+ if (!bfd_get_section_contents (abfd, si.sym_sect, sym_secptr,
+ (file_ptr)0, sym_secsize))
+ return;
+ if (!bfd_get_section_contents (abfd, si.str_sect, str_secptr,
+ (file_ptr)0, str_secsize))
+ return;
+ if (!bfd_get_section_contents (abfd, si.dyninfo_sect, dyninfo_secptr,
+ (file_ptr)0, dyninfo_secsize))
+ return;
+ if (!bfd_get_section_contents (abfd, si.got_sect, got_secptr,
+ (file_ptr)0, got_secsize))
+ return;
+
+ /* Find the number of local GOT entries and the index for the
+ the first dynamic symbol in the GOT. */
+ for (dyninfo_p = dyninfo_secptr, dyninfo_end = dyninfo_p + dyninfo_secsize;
+ dyninfo_p < dyninfo_end;
+ dyninfo_p += sizeof (Elfalpha_External_Dyn))
+ {
+ Elfalpha_External_Dyn *x_dynp = (Elfalpha_External_Dyn *)dyninfo_p;
+ long dyn_tag;
+
+ dyn_tag = bfd_h_get_32 (abfd, (bfd_byte *) x_dynp->d_tag);
+ if (dyn_tag == DT_NULL)
+ break;
+ else if (dyn_tag == DT_MIPS_LOCAL_GOTNO)
+ {
+ dt_mips_local_gotno = bfd_h_get_32 (abfd,
+ (bfd_byte *) x_dynp->d_un.d_val);
+ }
+ else if (dyn_tag == DT_MIPS_GOTSYM)
+ {
+ dt_mips_gotsym = bfd_h_get_32 (abfd, (bfd_byte *) x_dynp->d_un.d_val);
+ }
+ }
+ if (dt_mips_local_gotno < 0 || dt_mips_gotsym < 0)
+ return;
+
+ /* Scan all dynamic symbols and enter them into the minimal symbol table
+ if appropriate. */
+ sym_count = sym_secsize / sizeof (Elfalpha_External_Sym);
+ stripped = (bfd_get_symcount (abfd) == 0);
+
+ /* Skip first symbol, which is a null dummy. */
+ for (i = 1, x_symp = (Elfalpha_External_Sym *) sym_secptr + 1;
+ i < sym_count;
+ i++, x_symp++)
+ {
+ unsigned long strx;
+ char *name;
+ bfd_vma sym_value;
+ unsigned char sym_info;
+ unsigned int sym_shndx;
+ int isglobal;
+ enum minimal_symbol_type ms_type;
+
+ strx = bfd_h_get_32 (abfd, (bfd_byte *) x_symp->st_name);
+ if (strx >= str_secsize)
+ continue;
+ name = str_secptr + strx;
+ if (*name == '\0' || *name == '.')
+ continue;
+
+ sym_value = bfd_h_get_64 (abfd, (bfd_byte *) x_symp->st_value);
+ sym_info = bfd_h_get_8 (abfd, (bfd_byte *) x_symp->st_info);
+ sym_shndx = bfd_h_get_16 (abfd, (bfd_byte *) x_symp->st_shndx);
+ isglobal = (ELF_ST_BIND (sym_info) == STB_GLOBAL);
+
+ if (sym_shndx == SHN_UNDEF)
+ {
+ /* Handle undefined functions which are defined in a shared
+ library. */
+ if (ELF_ST_TYPE (sym_info) != STT_FUNC
+ || ELF_ST_BIND (sym_info) != STB_GLOBAL)
+ continue;
+
+ ms_type = mst_solib_trampoline;
+
+ /* If sym_value is nonzero, it points to the shared library
+ trampoline entry, which is what we are looking for.
+
+ If sym_value is zero, then we have to get the GOT entry
+ for the symbol.
+ If the GOT entry is nonzero, it represents the quickstart
+ address of the function and we use that as the symbol value.
+
+ If the GOT entry is zero, the function address has to be resolved
+ by the runtime loader before the executable is started.
+ We are unable to find any meaningful address for these
+ functions in the executable file, so we skip them. */
+ if (sym_value == 0)
+ {
+ int got_entry_offset =
+ (i - dt_mips_gotsym + dt_mips_local_gotno) * got_entry_size;
+
+ if (got_entry_offset < 0 || got_entry_offset >= got_secsize)
+ continue;
+ sym_value =
+ bfd_h_get_64 (abfd,
+ (bfd_byte *) (got_secptr + got_entry_offset));
+ if (sym_value == 0)
+ continue;
+ }
+ }
+ else
+ {
+ /* Symbols defined in the executable itself. We only care about
+ them if this is a stripped executable, otherwise they have
+ been retrieved from the normal symbol table already. */
+ if (!stripped)
+ continue;
+
+ if (sym_shndx == SHN_MIPS_TEXT)
+ {
+ if (isglobal)
+ ms_type = mst_text;
+ else
+ ms_type = mst_file_text;
+ sym_value += ANOFFSET (section_offsets, SECT_OFF_TEXT);
+ }
+ else if (sym_shndx == SHN_MIPS_DATA)
+ {
+ if (isglobal)
+ ms_type = mst_data;
+ else
+ ms_type = mst_file_data;
+ sym_value += ANOFFSET (section_offsets, SECT_OFF_DATA);
+ }
+ else if (sym_shndx == SHN_MIPS_ACOMMON)
+ {
+ if (isglobal)
+ ms_type = mst_bss;
+ else
+ ms_type = mst_file_bss;
+ sym_value += ANOFFSET (section_offsets, SECT_OFF_BSS);
+ }
+ else if (sym_shndx == SHN_ABS)
+ {
+ ms_type = mst_abs;
+ }
+ else
+ {
+ continue;
+ }
+ }
+
+ prim_record_minimal_symbol (obsavestring (name,
+ strlen (name),
+ &objfile -> symbol_obstack),
+ sym_value,
+ ms_type,
+ objfile);
+ }
+}
+
+/* Initialization */
+
+static struct sym_fns ecoff_sym_fns =
+{
+ bfd_target_ecoff_flavour,
+ mipscoff_new_init, /* sym_new_init: init anything gbl to entire symtab */
+ mipscoff_symfile_init, /* sym_init: read initial info, setup for sym_read() */
+ mipscoff_symfile_read, /* sym_read: read a symbol file into symtab */
+ mipscoff_symfile_finish, /* sym_finish: finished with file, cleanup */
+ mipscoff_symfile_offsets, /* sym_offsets: dummy FIXME til implem sym reloc */
+ NULL /* next: pointer to next struct sym_fns */
+};
+
+void
+_initialize_mipsread ()
+{
+ add_symtab_fns (&ecoff_sym_fns);
+}
diff --git a/gnu/usr.bin/gdb/gdb/nlmread.c b/gnu/usr.bin/gdb/gdb/nlmread.c
new file mode 100644
index 0000000..b2ebbe0
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/nlmread.c
@@ -0,0 +1,308 @@
+/* Read NLM (NetWare Loadable Module) format executable files for GDB.
+ Copyright 1993, 1994 Free Software Foundation, Inc.
+ Written by Fred Fish at Cygnus Support (fnf@cygnus.com).
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "defs.h"
+#include <string.h>
+#include "bfd.h"
+#include "symtab.h"
+#include "symfile.h"
+#include "objfiles.h"
+#include "gdb-stabs.h"
+#include "buildsym.h"
+#include "stabsread.h"
+
+static void
+nlm_new_init PARAMS ((struct objfile *));
+
+static void
+nlm_symfile_init PARAMS ((struct objfile *));
+
+static void
+nlm_symfile_read PARAMS ((struct objfile *, struct section_offsets *, int));
+
+static void
+nlm_symfile_finish PARAMS ((struct objfile *));
+
+static void
+nlm_symtab_read PARAMS ((bfd *, CORE_ADDR, struct objfile *));
+
+static struct section_offsets *
+nlm_symfile_offsets PARAMS ((struct objfile *, CORE_ADDR));
+
+static void
+record_minimal_symbol PARAMS ((char *, CORE_ADDR, enum minimal_symbol_type,
+ struct objfile *));
+
+
+/* Initialize anything that needs initializing when a completely new symbol
+ file is specified (not just adding some symbols from another file, e.g. a
+ shared library).
+
+ We reinitialize buildsym, since gdb will be able to read stabs from an NLM
+ file at some point in the near future. */
+
+static void
+nlm_new_init (ignore)
+ struct objfile *ignore;
+{
+ stabsread_new_init ();
+ buildsym_new_init ();
+}
+
+
+/* NLM specific initialization routine for reading symbols.
+
+ It is passed a pointer to a struct sym_fns which contains, among other
+ things, the BFD for the file whose symbols are being read, and a slot for
+ a pointer to "private data" which we can fill with goodies.
+
+ For now at least, we have nothing in particular to do, so this function is
+ just a stub. */
+
+static void
+nlm_symfile_init (ignore)
+ struct objfile *ignore;
+{
+}
+
+static void
+record_minimal_symbol (name, address, ms_type, objfile)
+ char *name;
+ CORE_ADDR address;
+ enum minimal_symbol_type ms_type;
+ struct objfile *objfile;
+{
+ name = obsavestring (name, strlen (name), &objfile -> symbol_obstack);
+ prim_record_minimal_symbol (name, address, ms_type, objfile);
+}
+
+
+/*
+
+LOCAL FUNCTION
+
+ nlm_symtab_read -- read the symbol table of an NLM file
+
+SYNOPSIS
+
+ void nlm_symtab_read (bfd *abfd, CORE_ADDR addr,
+ struct objfile *objfile)
+
+DESCRIPTION
+
+ Given an open bfd, a base address to relocate symbols to, and a
+ flag that specifies whether or not this bfd is for an executable
+ or not (may be shared library for example), add all the global
+ function and data symbols to the minimal symbol table.
+*/
+
+static void
+nlm_symtab_read (abfd, addr, objfile)
+ bfd *abfd;
+ CORE_ADDR addr;
+ struct objfile *objfile;
+{
+ long storage_needed;
+ asymbol *sym;
+ asymbol **symbol_table;
+ long number_of_symbols;
+ long i;
+ struct cleanup *back_to;
+ CORE_ADDR symaddr;
+ enum minimal_symbol_type ms_type;
+
+ storage_needed = bfd_get_symtab_upper_bound (abfd);
+ if (storage_needed < 0)
+ error ("Can't read symbols from %s: %s", bfd_get_filename (abfd),
+ bfd_errmsg (bfd_get_error ()));
+ if (storage_needed > 0)
+ {
+ symbol_table = (asymbol **) xmalloc (storage_needed);
+ back_to = make_cleanup (free, symbol_table);
+ number_of_symbols = bfd_canonicalize_symtab (abfd, symbol_table);
+ if (number_of_symbols < 0)
+ error ("Can't read symbols from %s: %s", bfd_get_filename (abfd),
+ bfd_errmsg (bfd_get_error ()));
+
+ for (i = 0; i < number_of_symbols; i++)
+ {
+ sym = symbol_table[i];
+ if (/*sym -> flags & BSF_GLOBAL*/ 1)
+ {
+ /* Bfd symbols are section relative. */
+ symaddr = sym -> value + sym -> section -> vma;
+ /* Relocate all non-absolute symbols by base address. */
+ if (sym -> section != &bfd_abs_section)
+ symaddr += addr;
+
+ /* For non-absolute symbols, use the type of the section
+ they are relative to, to intuit text/data. BFD provides
+ no way of figuring this out for absolute symbols. */
+ if (sym -> section -> flags & SEC_CODE)
+ ms_type = mst_text;
+ else if (sym -> section -> flags & SEC_DATA)
+ ms_type = mst_data;
+ else
+ ms_type = mst_unknown;
+
+ record_minimal_symbol ((char *) sym -> name, symaddr, ms_type,
+ objfile);
+ }
+ }
+ do_cleanups (back_to);
+ }
+}
+
+
+/* Scan and build partial symbols for a symbol file.
+ We have been initialized by a call to nlm_symfile_init, which
+ currently does nothing.
+
+ SECTION_OFFSETS is a set of offsets to apply to relocate the symbols
+ in each section. We simplify it down to a single offset for all
+ symbols. FIXME.
+
+ MAINLINE is true if we are reading the main symbol
+ table (as opposed to a shared lib or dynamically loaded file).
+
+ This function only does the minimum work necessary for letting the
+ user "name" things symbolically; it does not read the entire symtab.
+ Instead, it reads the external and static symbols and puts them in partial
+ symbol tables. When more extensive information is requested of a
+ file, the corresponding partial symbol table is mutated into a full
+ fledged symbol table by going back and reading the symbols
+ for real.
+
+ Note that NLM files have two sets of information that is potentially
+ useful for building gdb's minimal symbol table. The first is a list
+ of the publically exported symbols, and is currently used to build
+ bfd's canonical symbol table. The second is an optional native debugging
+ format which contains additional symbols (and possibly duplicates of
+ the publically exported symbols). The optional native debugging format
+ is not currently used. */
+
+static void
+nlm_symfile_read (objfile, section_offsets, mainline)
+ struct objfile *objfile;
+ struct section_offsets *section_offsets;
+ int mainline;
+{
+ bfd *abfd = objfile -> obfd;
+ struct cleanup *back_to;
+ CORE_ADDR offset;
+ struct symbol *mainsym;
+
+ init_minimal_symbol_collection ();
+ back_to = make_cleanup (discard_minimal_symbols, 0);
+
+ /* FIXME, should take a section_offsets param, not just an offset. */
+
+ offset = ANOFFSET (section_offsets, 0);
+
+ /* Process the NLM export records, which become the bfd's canonical symbol
+ table. */
+
+ nlm_symtab_read (abfd, offset, objfile);
+
+ stabsect_build_psymtabs (objfile, section_offsets, mainline, ".stab",
+ ".stabstr", ".text");
+
+ mainsym = lookup_symbol ("main", NULL, VAR_NAMESPACE, NULL, NULL);
+
+ if (mainsym
+ && SYMBOL_CLASS(mainsym) == LOC_BLOCK)
+ {
+ objfile->ei.main_func_lowpc = BLOCK_START (SYMBOL_BLOCK_VALUE (mainsym));
+ objfile->ei.main_func_highpc = BLOCK_END (SYMBOL_BLOCK_VALUE (mainsym));
+ }
+
+ /* FIXME: We could locate and read the optional native debugging format
+ here and add the symbols to the minimal symbol table. */
+
+ /* Install any minimal symbols that have been collected as the current
+ minimal symbols for this objfile. */
+
+ install_minimal_symbols (objfile);
+
+ do_cleanups (back_to);
+}
+
+
+/* Perform any local cleanups required when we are done with a particular
+ objfile. I.E, we are in the process of discarding all symbol information
+ for an objfile, freeing up all memory held for it, and unlinking the
+ objfile struct from the global list of known objfiles. */
+
+static void
+nlm_symfile_finish (objfile)
+ struct objfile *objfile;
+{
+ if (objfile -> sym_private != NULL)
+ {
+ mfree (objfile -> md, objfile -> sym_private);
+ }
+}
+
+/* NLM specific parsing routine for section offsets.
+ FIXME: This may or may not be necessary. All the symbol readers seem
+ to have similar code. See if it can be generalized and moved elsewhere. */
+
+static
+struct section_offsets *
+nlm_symfile_offsets (objfile, addr)
+ struct objfile *objfile;
+ CORE_ADDR addr;
+{
+ struct section_offsets *section_offsets;
+ int i;
+
+ objfile->num_sections = SECT_OFF_MAX;
+ section_offsets = (struct section_offsets *)
+ obstack_alloc (&objfile -> psymbol_obstack,
+ sizeof (struct section_offsets) +
+ sizeof (section_offsets->offsets) * (SECT_OFF_MAX-1));
+
+ for (i = 0; i < SECT_OFF_MAX; i++)
+ {
+ ANOFFSET (section_offsets, i) = addr;
+ }
+
+ return (section_offsets);
+}
+
+
+/* Register that we are able to handle NLM file format. */
+
+static struct sym_fns nlm_sym_fns =
+{
+ bfd_target_nlm_flavour,
+ nlm_new_init, /* sym_new_init: init anything gbl to entire symtab */
+ nlm_symfile_init, /* sym_init: read initial info, setup for sym_read() */
+ nlm_symfile_read, /* sym_read: read a symbol file into symtab */
+ nlm_symfile_finish, /* sym_finish: finished with file, cleanup */
+ nlm_symfile_offsets, /* sym_offsets: Translate ext. to int. relocation */
+ NULL /* next: pointer to next struct sym_fns */
+};
+
+void
+_initialize_nlmread ()
+{
+ add_symtab_fns (&nlm_sym_fns);
+}
diff --git a/gnu/usr.bin/gdb/gdb/nm.h b/gnu/usr.bin/gdb/gdb/nm.h
new file mode 100644
index 0000000..ec85bd8
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/nm.h
@@ -0,0 +1,100 @@
+/* Native-dependent definitions for Intel 386 running BSD Unix, for GDB.
+ Copyright 1986, 1987, 1989, 1992 Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#ifndef NM_FREEBSD_H
+#define NM_FREEBSD_H
+
+/* Be shared lib aware */
+#include "solib.h"
+
+/* This is the amount to subtract from u.u_ar0
+ to get the offset in the core file of the register values. */
+
+#include <machine/vmparam.h>
+#define KERNEL_U_ADDR USRSTACK
+
+/* #undef FLOAT_INFO */ /* No float info yet */
+#define FLOAT_INFO extern void i386_float_info (); \
+ i386_float_info ()
+
+#define REGISTER_U_ADDR(addr, blockend, regno) \
+ (addr) = i386_register_u_addr ((blockend),(regno));
+
+extern int
+i386_register_u_addr PARAMS ((int, int));
+
+#define PTRACE_ARG3_TYPE char*
+#define ATTACH_DETACH
+#define KERNEL_DEBUG
+
+/* make structure definitions match up with those expected in solib.c */
+
+#define link_object sod
+#define lo_name sod_name
+#define lo_library sod_library
+#define lo_unused sod_reserved
+#define lo_major sod_major
+#define lo_minor sod_minor
+#define lo_next sod_next
+
+#define link_map so_map
+#define lm_addr som_addr
+#define lm_name som_path
+#define lm_next som_next
+#define lm_lop som_sod
+#define lm_lob som_sodbase
+#define lm_rwt som_write
+#define lm_ld som_dynamic
+#define lm_lpd som_spd
+
+#define link_dynamic_2 section_dispatch_table
+#define ld_loaded sdt_loaded
+#define ld_need sdt_sods
+#define ld_rules sdt_filler1
+#define ld_got sdt_got
+#define ld_plt sdt_plt
+#define ld_rel sdt_rel
+#define ld_hash sdt_hash
+#define ld_stab sdt_nzlist
+#define ld_stab_hash sdt_filler2
+#define ld_buckets sdt_buckets
+#define ld_symbols sdt_strings
+#define ld_symb_size sdt_str_sz
+#define ld_text sdt_text_sz
+#define ld_plt_sz sdt_plt_sz
+
+#define rtc_symb rt_symbol
+#define rtc_sp rt_sp
+#define rtc_next rt_next
+
+#define ld_debug so_debug
+#define ldd_version dd_version
+#define ldd_in_debugger dd_in_debugger
+#define ldd_sym_loaded dd_sym_loaded
+#define ldd_bp_addr dd_bpt_addr
+#define ldd_bp_inst dd_bpt_shadow
+#define ldd_cp dd_cc
+
+#define link_dynamic _dynamic
+#define ld_version d_version
+#define ldd d_debug
+#define ld_un d_un
+#define ld_2 d_sdt
+
+#endif /* NM_FREEBSD_H */
diff --git a/gnu/usr.bin/gdb/gdb/objfiles.c b/gnu/usr.bin/gdb/gdb/objfiles.c
new file mode 100644
index 0000000..8ec08a2
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/objfiles.c
@@ -0,0 +1,868 @@
+/* GDB routines for manipulating objfiles.
+ Copyright 1992 Free Software Foundation, Inc.
+ Contributed by Cygnus Support, using pieces from other GDB modules.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* This file contains support routines for creating, manipulating, and
+ destroying objfile structures. */
+
+#include "defs.h"
+#include "bfd.h" /* Binary File Description */
+#include "symtab.h"
+#include "symfile.h"
+#include "objfiles.h"
+#include "gdb-stabs.h"
+#include "target.h"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <obstack.h>
+
+/* Prototypes for local functions */
+
+#if !defined(NO_MMALLOC) && defined(HAVE_MMAP)
+
+static int
+open_existing_mapped_file PARAMS ((char *, long, int));
+
+static int
+open_mapped_file PARAMS ((char *filename, long mtime, int mapped));
+
+static CORE_ADDR
+map_to_address PARAMS ((void));
+
+#endif /* !defined(NO_MMALLOC) && defined(HAVE_MMAP) */
+
+/* Message to be printed before the error message, when an error occurs. */
+
+extern char *error_pre_print;
+
+/* Externally visible variables that are owned by this module.
+ See declarations in objfile.h for more info. */
+
+struct objfile *object_files; /* Linked list of all objfiles */
+struct objfile *current_objfile; /* For symbol file being read in */
+struct objfile *symfile_objfile; /* Main symbol table loaded from */
+
+int mapped_symbol_files; /* Try to use mapped symbol files */
+
+/* Locate all mappable sections of a BFD file.
+ objfile_p_char is a char * to get it through
+ bfd_map_over_sections; we cast it back to its proper type. */
+
+static void
+add_to_objfile_sections (abfd, asect, objfile_p_char)
+ bfd *abfd;
+ sec_ptr asect;
+ PTR objfile_p_char;
+{
+ struct objfile *objfile = (struct objfile *) objfile_p_char;
+ struct obj_section section;
+ flagword aflag;
+
+ aflag = bfd_get_section_flags (abfd, asect);
+ if (!(aflag & SEC_ALLOC))
+ return;
+ if (0 == bfd_section_size (abfd, asect))
+ return;
+ section.offset = 0;
+ section.objfile = objfile;
+ section.the_bfd_section = asect;
+ section.addr = bfd_section_vma (abfd, asect);
+ section.endaddr = section.addr + bfd_section_size (abfd, asect);
+ obstack_grow (&objfile->psymbol_obstack, &section, sizeof(section));
+ objfile->sections_end = (struct obj_section *) (((unsigned long) objfile->sections_end) + 1);
+}
+
+/* Builds a section table for OBJFILE.
+ Returns 0 if OK, 1 on error (in which case bfd_error contains the
+ error). */
+
+int
+build_objfile_section_table (objfile)
+ struct objfile *objfile;
+{
+ /* objfile->sections can be already set when reading a mapped symbol
+ file. I believe that we do need to rebuild the section table in
+ this case (we rebuild other things derived from the bfd), but we
+ can't free the old one (it's in the psymbol_obstack). So we just
+ waste some memory. */
+
+ objfile->sections_end = 0;
+ bfd_map_over_sections (objfile->obfd, add_to_objfile_sections, (char *)objfile);
+ objfile->sections = (struct obj_section *)
+ obstack_finish (&objfile->psymbol_obstack);
+ objfile->sections_end = objfile->sections + (unsigned long) objfile->sections_end;
+ return(0);
+}
+
+/* Given a pointer to an initialized bfd (ABFD) and a flag that indicates
+ whether or not an objfile is to be mapped (MAPPED), allocate a new objfile
+ struct, fill it in as best we can, link it into the list of all known
+ objfiles, and return a pointer to the new objfile struct. */
+
+struct objfile *
+allocate_objfile (abfd, mapped)
+ bfd *abfd;
+ int mapped;
+{
+ struct objfile *objfile = NULL;
+
+ mapped |= mapped_symbol_files;
+
+#if !defined(NO_MMALLOC) && defined(HAVE_MMAP)
+ {
+
+ /* If we can support mapped symbol files, try to open/reopen the
+ mapped file that corresponds to the file from which we wish to
+ read symbols. If the objfile is to be mapped, we must malloc
+ the structure itself using the mmap version, and arrange that
+ all memory allocation for the objfile uses the mmap routines.
+ If we are reusing an existing mapped file, from which we get
+ our objfile pointer, we have to make sure that we update the
+ pointers to the alloc/free functions in the obstack, in case
+ these functions have moved within the current gdb. */
+
+ int fd;
+
+ fd = open_mapped_file (bfd_get_filename (abfd), bfd_get_mtime (abfd),
+ mapped);
+ if (fd >= 0)
+ {
+ CORE_ADDR mapto;
+ PTR md;
+
+ if (((mapto = map_to_address ()) == 0) ||
+ ((md = mmalloc_attach (fd, (PTR) mapto)) == NULL))
+ {
+ close (fd);
+ }
+ else if ((objfile = (struct objfile *) mmalloc_getkey (md, 0)) != NULL)
+ {
+ /* Update memory corruption handler function addresses. */
+ init_malloc (md);
+ objfile -> md = md;
+ objfile -> mmfd = fd;
+ /* Update pointers to functions to *our* copies */
+ obstack_chunkfun (&objfile -> psymbol_obstack, xmmalloc);
+ obstack_freefun (&objfile -> psymbol_obstack, mfree);
+ obstack_chunkfun (&objfile -> symbol_obstack, xmmalloc);
+ obstack_freefun (&objfile -> symbol_obstack, mfree);
+ obstack_chunkfun (&objfile -> type_obstack, xmmalloc);
+ obstack_freefun (&objfile -> type_obstack, mfree);
+ /* If already in objfile list, unlink it. */
+ unlink_objfile (objfile);
+ /* Forget things specific to a particular gdb, may have changed. */
+ objfile -> sf = NULL;
+ }
+ else
+ {
+
+ /* Set up to detect internal memory corruption. MUST be
+ done before the first malloc. See comments in
+ init_malloc() and mmcheck(). */
+
+ init_malloc (md);
+
+ objfile = (struct objfile *)
+ xmmalloc (md, sizeof (struct objfile));
+ memset (objfile, 0, sizeof (struct objfile));
+ objfile -> md = md;
+ objfile -> mmfd = fd;
+ objfile -> flags |= OBJF_MAPPED;
+ mmalloc_setkey (objfile -> md, 0, objfile);
+ obstack_specify_allocation_with_arg (&objfile -> psymbol_obstack,
+ 0, 0, xmmalloc, mfree,
+ objfile -> md);
+ obstack_specify_allocation_with_arg (&objfile -> symbol_obstack,
+ 0, 0, xmmalloc, mfree,
+ objfile -> md);
+ obstack_specify_allocation_with_arg (&objfile -> type_obstack,
+ 0, 0, xmmalloc, mfree,
+ objfile -> md);
+ }
+ }
+
+ if (mapped && (objfile == NULL))
+ {
+ warning ("symbol table for '%s' will not be mapped",
+ bfd_get_filename (abfd));
+ }
+ }
+#else /* defined(NO_MMALLOC) || !defined(HAVE_MMAP) */
+
+ if (mapped)
+ {
+ warning ("this version of gdb does not support mapped symbol tables.");
+
+ /* Turn off the global flag so we don't try to do mapped symbol tables
+ any more, which shuts up gdb unless the user specifically gives the
+ "mapped" keyword again. */
+
+ mapped_symbol_files = 0;
+ }
+
+#endif /* !defined(NO_MMALLOC) && defined(HAVE_MMAP) */
+
+ /* If we don't support mapped symbol files, didn't ask for the file to be
+ mapped, or failed to open the mapped file for some reason, then revert
+ back to an unmapped objfile. */
+
+ if (objfile == NULL)
+ {
+ objfile = (struct objfile *) xmalloc (sizeof (struct objfile));
+ memset (objfile, 0, sizeof (struct objfile));
+ objfile -> md = NULL;
+ obstack_specify_allocation (&objfile -> psymbol_obstack, 0, 0, xmalloc,
+ free);
+ obstack_specify_allocation (&objfile -> symbol_obstack, 0, 0, xmalloc,
+ free);
+ obstack_specify_allocation (&objfile -> type_obstack, 0, 0, xmalloc,
+ free);
+ }
+
+ /* Update the per-objfile information that comes from the bfd, ensuring
+ that any data that is reference is saved in the per-objfile data
+ region. */
+
+ objfile -> obfd = abfd;
+ if (objfile -> name != NULL)
+ {
+ mfree (objfile -> md, objfile -> name);
+ }
+ objfile -> name = mstrsave (objfile -> md, bfd_get_filename (abfd));
+ objfile -> mtime = bfd_get_mtime (abfd);
+
+ /* Build section table. */
+
+ if (build_objfile_section_table (objfile))
+ {
+ error ("Can't find the file sections in `%s': %s",
+ objfile -> name, bfd_errmsg (bfd_get_error ()));
+ }
+
+ /* Push this file onto the head of the linked list of other such files. */
+
+ objfile -> next = object_files;
+ object_files = objfile;
+
+ return (objfile);
+}
+
+/* Unlink OBJFILE from the list of known objfiles, if it is found in the
+ list.
+
+ It is not a bug, or error, to call this function if OBJFILE is not known
+ to be in the current list. This is done in the case of mapped objfiles,
+ for example, just to ensure that the mapped objfile doesn't appear twice
+ in the list. Since the list is threaded, linking in a mapped objfile
+ twice would create a circular list.
+
+ If OBJFILE turns out to be in the list, we zap it's NEXT pointer after
+ unlinking it, just to ensure that we have completely severed any linkages
+ between the OBJFILE and the list. */
+
+void
+unlink_objfile (objfile)
+ struct objfile *objfile;
+{
+ struct objfile** objpp;
+
+ for (objpp = &object_files; *objpp != NULL; objpp = &((*objpp) -> next))
+ {
+ if (*objpp == objfile)
+ {
+ *objpp = (*objpp) -> next;
+ objfile -> next = NULL;
+ break;
+ }
+ }
+}
+
+
+/* Destroy an objfile and all the symtabs and psymtabs under it. Note
+ that as much as possible is allocated on the symbol_obstack and
+ psymbol_obstack, so that the memory can be efficiently freed.
+
+ Things which we do NOT free because they are not in malloc'd memory
+ or not in memory specific to the objfile include:
+
+ objfile -> sf
+
+ FIXME: If the objfile is using reusable symbol information (via mmalloc),
+ then we need to take into account the fact that more than one process
+ may be using the symbol information at the same time (when mmalloc is
+ extended to support cooperative locking). When more than one process
+ is using the mapped symbol info, we need to be more careful about when
+ we free objects in the reusable area. */
+
+void
+free_objfile (objfile)
+ struct objfile *objfile;
+{
+ /* First do any symbol file specific actions required when we are
+ finished with a particular symbol file. Note that if the objfile
+ is using reusable symbol information (via mmalloc) then each of
+ these routines is responsible for doing the correct thing, either
+ freeing things which are valid only during this particular gdb
+ execution, or leaving them to be reused during the next one. */
+
+ if (objfile -> sf != NULL)
+ {
+ (*objfile -> sf -> sym_finish) (objfile);
+ }
+
+ /* We always close the bfd. */
+
+ if (objfile -> obfd != NULL)
+ {
+ char *name = bfd_get_filename (objfile->obfd);
+ bfd_close (objfile -> obfd);
+ free (name);
+ }
+
+ /* Remove it from the chain of all objfiles. */
+
+ unlink_objfile (objfile);
+
+ /* Before the symbol table code was redone to make it easier to
+ selectively load and remove information particular to a specific
+ linkage unit, gdb used to do these things whenever the monolithic
+ symbol table was blown away. How much still needs to be done
+ is unknown, but we play it safe for now and keep each action until
+ it is shown to be no longer needed. */
+
+#if defined (CLEAR_SOLIB)
+ CLEAR_SOLIB ();
+ /* CLEAR_SOLIB closes the bfd's for any shared libraries. But
+ the to_sections for a core file might refer to those bfd's. So
+ detach any core file. */
+ {
+ struct target_ops *t = find_core_target ();
+ if (t != NULL)
+ (t->to_detach) (NULL, 0);
+ }
+#endif
+ /* I *think* all our callers call clear_symtab_users. If so, no need
+ to call this here. */
+ clear_pc_function_cache ();
+
+ /* The last thing we do is free the objfile struct itself for the
+ non-reusable case, or detach from the mapped file for the reusable
+ case. Note that the mmalloc_detach or the mfree is the last thing
+ we can do with this objfile. */
+
+#if !defined(NO_MMALLOC) && defined(HAVE_MMAP)
+
+ if (objfile -> flags & OBJF_MAPPED)
+ {
+ /* Remember the fd so we can close it. We can't close it before
+ doing the detach, and after the detach the objfile is gone. */
+ int mmfd;
+
+ mmfd = objfile -> mmfd;
+ mmalloc_detach (objfile -> md);
+ objfile = NULL;
+ close (mmfd);
+ }
+
+#endif /* !defined(NO_MMALLOC) && defined(HAVE_MMAP) */
+
+ /* If we still have an objfile, then either we don't support reusable
+ objfiles or this one was not reusable. So free it normally. */
+
+ if (objfile != NULL)
+ {
+ if (objfile -> name != NULL)
+ {
+ mfree (objfile -> md, objfile -> name);
+ }
+ if (objfile->global_psymbols.list)
+ mfree (objfile->md, objfile->global_psymbols.list);
+ if (objfile->static_psymbols.list)
+ mfree (objfile->md, objfile->static_psymbols.list);
+ /* Free the obstacks for non-reusable objfiles */
+ obstack_free (&objfile -> psymbol_obstack, 0);
+ obstack_free (&objfile -> symbol_obstack, 0);
+ obstack_free (&objfile -> type_obstack, 0);
+ mfree (objfile -> md, objfile);
+ objfile = NULL;
+ }
+}
+
+
+/* Free all the object files at once and clean up their users. */
+
+void
+free_all_objfiles ()
+{
+ struct objfile *objfile, *temp;
+
+ ALL_OBJFILES_SAFE (objfile, temp)
+ {
+ free_objfile (objfile);
+ }
+ clear_symtab_users ();
+}
+
+/* Relocate OBJFILE to NEW_OFFSETS. There should be OBJFILE->NUM_SECTIONS
+ entries in new_offsets. */
+void
+objfile_relocate (objfile, new_offsets)
+ struct objfile *objfile;
+ struct section_offsets *new_offsets;
+{
+ struct section_offsets *delta = (struct section_offsets *) alloca
+ (sizeof (struct section_offsets)
+ + objfile->num_sections * sizeof (delta->offsets));
+
+ {
+ int i;
+ int something_changed = 0;
+ for (i = 0; i < objfile->num_sections; ++i)
+ {
+ ANOFFSET (delta, i) =
+ ANOFFSET (new_offsets, i) - ANOFFSET (objfile->section_offsets, i);
+ if (ANOFFSET (delta, i) != 0)
+ something_changed = 1;
+ }
+ if (!something_changed)
+ return;
+ }
+
+ /* OK, get all the symtabs. */
+ {
+ struct symtab *s;
+
+ ALL_OBJFILE_SYMTABS (objfile, s)
+ {
+ struct linetable *l;
+ struct blockvector *bv;
+ int i;
+
+ /* First the line table. */
+ l = LINETABLE (s);
+ if (l)
+ {
+ for (i = 0; i < l->nitems; ++i)
+ l->item[i].pc += ANOFFSET (delta, s->block_line_section);
+ }
+
+ /* Don't relocate a shared blockvector more than once. */
+ if (!s->primary)
+ continue;
+
+ bv = BLOCKVECTOR (s);
+ for (i = 0; i < BLOCKVECTOR_NBLOCKS (bv); ++i)
+ {
+ struct block *b;
+ int j;
+
+ b = BLOCKVECTOR_BLOCK (bv, i);
+ BLOCK_START (b) += ANOFFSET (delta, s->block_line_section);
+ BLOCK_END (b) += ANOFFSET (delta, s->block_line_section);
+
+ for (j = 0; j < BLOCK_NSYMS (b); ++j)
+ {
+ struct symbol *sym = BLOCK_SYM (b, j);
+ /* The RS6000 code from which this was taken skipped
+ any symbols in STRUCT_NAMESPACE or UNDEF_NAMESPACE.
+ But I'm leaving out that test, on the theory that
+ they can't possibly pass the tests below. */
+ if ((SYMBOL_CLASS (sym) == LOC_LABEL
+ || SYMBOL_CLASS (sym) == LOC_STATIC)
+ && SYMBOL_SECTION (sym) >= 0)
+ {
+ SYMBOL_VALUE_ADDRESS (sym) +=
+ ANOFFSET (delta, SYMBOL_SECTION (sym));
+ }
+#ifdef MIPS_EFI_SYMBOL_NAME
+ /* Relocate Extra Function Info for ecoff. */
+
+ else
+ if (SYMBOL_CLASS (sym) == LOC_CONST
+ && SYMBOL_NAMESPACE (sym) == LABEL_NAMESPACE
+ && STRCMP (SYMBOL_NAME (sym), MIPS_EFI_SYMBOL_NAME) == 0)
+ ecoff_relocate_efi (sym, ANOFFSET (delta, s->block_line_section));
+#endif
+ }
+ }
+ }
+ }
+
+ {
+ struct partial_symtab *p;
+
+ ALL_OBJFILE_PSYMTABS (objfile, p)
+ {
+ /* FIXME: specific to symbol readers which use gdb-stabs.h.
+ We can only get away with it since objfile_relocate is only
+ used on XCOFF, which lacks psymtabs, and for gdb-stabs.h
+ targets. */
+ p->textlow += ANOFFSET (delta, SECT_OFF_TEXT);
+ p->texthigh += ANOFFSET (delta, SECT_OFF_TEXT);
+ }
+ }
+
+ {
+ struct partial_symbol *psym;
+
+ for (psym = objfile->global_psymbols.list;
+ psym < objfile->global_psymbols.next;
+ psym++)
+ if (SYMBOL_SECTION (psym) >= 0)
+ SYMBOL_VALUE_ADDRESS (psym) += ANOFFSET (delta, SYMBOL_SECTION (psym));
+ for (psym = objfile->static_psymbols.list;
+ psym < objfile->static_psymbols.next;
+ psym++)
+ if (SYMBOL_SECTION (psym) >= 0)
+ SYMBOL_VALUE_ADDRESS (psym) += ANOFFSET (delta, SYMBOL_SECTION (psym));
+ }
+
+ {
+ struct minimal_symbol *msym;
+ ALL_OBJFILE_MSYMBOLS (objfile, msym)
+ if (SYMBOL_SECTION (msym) >= 0)
+ SYMBOL_VALUE_ADDRESS (msym) += ANOFFSET (delta, SYMBOL_SECTION (msym));
+ }
+
+ {
+ int i;
+ for (i = 0; i < objfile->num_sections; ++i)
+ ANOFFSET (objfile->section_offsets, i) = ANOFFSET (new_offsets, i);
+ }
+
+ {
+ struct obj_section *s;
+ bfd *abfd;
+
+ abfd = symfile_objfile->obfd;
+
+ for (s = symfile_objfile->sections;
+ s < symfile_objfile->sections_end; ++s)
+ {
+ flagword flags;
+
+ flags = bfd_get_section_flags (abfd, s->the_bfd_section);
+
+ if (flags & SEC_CODE)
+ {
+ s->addr += ANOFFSET (delta, SECT_OFF_TEXT);
+ s->endaddr += ANOFFSET (delta, SECT_OFF_TEXT);
+ }
+ else if (flags & (SEC_DATA | SEC_LOAD))
+ {
+ s->addr += ANOFFSET (delta, SECT_OFF_DATA);
+ s->endaddr += ANOFFSET (delta, SECT_OFF_DATA);
+ }
+ else if (flags & SEC_ALLOC)
+ {
+ s->addr += ANOFFSET (delta, SECT_OFF_BSS);
+ s->endaddr += ANOFFSET (delta, SECT_OFF_BSS);
+ }
+ }
+ }
+
+ if (objfile->ei.entry_point != ~0)
+ objfile->ei.entry_point += ANOFFSET (delta, SECT_OFF_TEXT);
+
+ if (objfile->ei.entry_func_lowpc != INVALID_ENTRY_LOWPC)
+ {
+ objfile->ei.entry_func_lowpc += ANOFFSET (delta, SECT_OFF_TEXT);
+ objfile->ei.entry_func_highpc += ANOFFSET (delta, SECT_OFF_TEXT);
+ }
+
+ if (objfile->ei.entry_file_lowpc != INVALID_ENTRY_LOWPC)
+ {
+ objfile->ei.entry_file_lowpc += ANOFFSET (delta, SECT_OFF_TEXT);
+ objfile->ei.entry_file_highpc += ANOFFSET (delta, SECT_OFF_TEXT);
+ }
+
+ if (objfile->ei.main_func_lowpc != INVALID_ENTRY_LOWPC)
+ {
+ objfile->ei.main_func_lowpc += ANOFFSET (delta, SECT_OFF_TEXT);
+ objfile->ei.main_func_highpc += ANOFFSET (delta, SECT_OFF_TEXT);
+ }
+}
+
+/* Many places in gdb want to test just to see if we have any partial
+ symbols available. This function returns zero if none are currently
+ available, nonzero otherwise. */
+
+int
+have_partial_symbols ()
+{
+ struct objfile *ofp;
+
+ ALL_OBJFILES (ofp)
+ {
+ if (ofp -> psymtabs != NULL)
+ {
+ return 1;
+ }
+ }
+ return 0;
+}
+
+/* Many places in gdb want to test just to see if we have any full
+ symbols available. This function returns zero if none are currently
+ available, nonzero otherwise. */
+
+int
+have_full_symbols ()
+{
+ struct objfile *ofp;
+
+ ALL_OBJFILES (ofp)
+ {
+ if (ofp -> symtabs != NULL)
+ {
+ return 1;
+ }
+ }
+ return 0;
+}
+
+/* Many places in gdb want to test just to see if we have any minimal
+ symbols available. This function returns zero if none are currently
+ available, nonzero otherwise. */
+
+int
+have_minimal_symbols ()
+{
+ struct objfile *ofp;
+
+ ALL_OBJFILES (ofp)
+ {
+ if (ofp -> msymbols != NULL)
+ {
+ return 1;
+ }
+ }
+ return 0;
+}
+
+#if !defined(NO_MMALLOC) && defined(HAVE_MMAP)
+
+/* Given the name of a mapped symbol file in SYMSFILENAME, and the timestamp
+ of the corresponding symbol file in MTIME, try to open an existing file
+ with the name SYMSFILENAME and verify it is more recent than the base
+ file by checking it's timestamp against MTIME.
+
+ If SYMSFILENAME does not exist (or can't be stat'd), simply returns -1.
+
+ If SYMSFILENAME does exist, but is out of date, we check to see if the
+ user has specified creation of a mapped file. If so, we don't issue
+ any warning message because we will be creating a new mapped file anyway,
+ overwriting the old one. If not, then we issue a warning message so that
+ the user will know why we aren't using this existing mapped symbol file.
+ In either case, we return -1.
+
+ If SYMSFILENAME does exist and is not out of date, but can't be opened for
+ some reason, then prints an appropriate system error message and returns -1.
+
+ Otherwise, returns the open file descriptor. */
+
+static int
+open_existing_mapped_file (symsfilename, mtime, mapped)
+ char *symsfilename;
+ long mtime;
+ int mapped;
+{
+ int fd = -1;
+ struct stat sbuf;
+
+ if (stat (symsfilename, &sbuf) == 0)
+ {
+ if (sbuf.st_mtime < mtime)
+ {
+ if (!mapped)
+ {
+ warning ("mapped symbol file `%s' is out of date, ignored it",
+ symsfilename);
+ }
+ }
+ else if ((fd = open (symsfilename, O_RDWR)) < 0)
+ {
+ if (error_pre_print)
+ {
+ printf_unfiltered (error_pre_print);
+ }
+ print_sys_errmsg (symsfilename, errno);
+ }
+ }
+ return (fd);
+}
+
+/* Look for a mapped symbol file that corresponds to FILENAME and is more
+ recent than MTIME. If MAPPED is nonzero, the user has asked that gdb
+ use a mapped symbol file for this file, so create a new one if one does
+ not currently exist.
+
+ If found, then return an open file descriptor for the file, otherwise
+ return -1.
+
+ This routine is responsible for implementing the policy that generates
+ the name of the mapped symbol file from the name of a file containing
+ symbols that gdb would like to read. Currently this policy is to append
+ ".syms" to the name of the file.
+
+ This routine is also responsible for implementing the policy that
+ determines where the mapped symbol file is found (the search path).
+ This policy is that when reading an existing mapped file, a file of
+ the correct name in the current directory takes precedence over a
+ file of the correct name in the same directory as the symbol file.
+ When creating a new mapped file, it is always created in the current
+ directory. This helps to minimize the chances of a user unknowingly
+ creating big mapped files in places like /bin and /usr/local/bin, and
+ allows a local copy to override a manually installed global copy (in
+ /bin for example). */
+
+static int
+open_mapped_file (filename, mtime, mapped)
+ char *filename;
+ long mtime;
+ int mapped;
+{
+ int fd;
+ char *symsfilename;
+
+ /* First try to open an existing file in the current directory, and
+ then try the directory where the symbol file is located. */
+
+ symsfilename = concat ("./", basename (filename), ".syms", (char *) NULL);
+ if ((fd = open_existing_mapped_file (symsfilename, mtime, mapped)) < 0)
+ {
+ free (symsfilename);
+ symsfilename = concat (filename, ".syms", (char *) NULL);
+ fd = open_existing_mapped_file (symsfilename, mtime, mapped);
+ }
+
+ /* If we don't have an open file by now, then either the file does not
+ already exist, or the base file has changed since it was created. In
+ either case, if the user has specified use of a mapped file, then
+ create a new mapped file, truncating any existing one. If we can't
+ create one, print a system error message saying why we can't.
+
+ By default the file is rw for everyone, with the user's umask taking
+ care of turning off the permissions the user wants off. */
+
+ if ((fd < 0) && mapped)
+ {
+ free (symsfilename);
+ symsfilename = concat ("./", basename (filename), ".syms",
+ (char *) NULL);
+ if ((fd = open (symsfilename, O_RDWR | O_CREAT | O_TRUNC, 0666)) < 0)
+ {
+ if (error_pre_print)
+ {
+ printf_unfiltered (error_pre_print);
+ }
+ print_sys_errmsg (symsfilename, errno);
+ }
+ }
+
+ free (symsfilename);
+ return (fd);
+}
+
+/* Return the base address at which we would like the next objfile's
+ mapped data to start.
+
+ For now, we use the kludge that the configuration specifies a base
+ address to which it is safe to map the first mmalloc heap, and an
+ increment to add to this address for each successive heap. There are
+ a lot of issues to deal with here to make this work reasonably, including:
+
+ Avoid memory collisions with existing mapped address spaces
+
+ Reclaim address spaces when their mmalloc heaps are unmapped
+
+ When mmalloc heaps are shared between processes they have to be
+ mapped at the same addresses in each
+
+ Once created, a mmalloc heap that is to be mapped back in must be
+ mapped at the original address. I.E. each objfile will expect to
+ be remapped at it's original address. This becomes a problem if
+ the desired address is already in use.
+
+ etc, etc, etc.
+
+ */
+
+
+static CORE_ADDR
+map_to_address ()
+{
+
+#if defined(MMAP_BASE_ADDRESS) && defined (MMAP_INCREMENT)
+
+ static CORE_ADDR next = MMAP_BASE_ADDRESS;
+ CORE_ADDR mapto = next;
+
+ next += MMAP_INCREMENT;
+ return (mapto);
+
+#else
+
+ return (0);
+
+#endif
+
+}
+
+#endif /* !defined(NO_MMALLOC) && defined(HAVE_MMAP) */
+
+/* Returns a section whose range includes PC or NULL if none found. */
+
+struct obj_section *
+find_pc_section(pc)
+ CORE_ADDR pc;
+{
+ struct obj_section *s;
+ struct objfile *objfile;
+
+ ALL_OBJFILES (objfile)
+ for (s = objfile->sections; s < objfile->sections_end; ++s)
+ if (s->addr <= pc
+ && pc < s->endaddr)
+ return(s);
+
+ return(NULL);
+}
+
+/* In SVR4, we recognize a trampoline by it's section name.
+ That is, if the pc is in a section named ".plt" then we are in
+ a trampoline. */
+
+int
+in_plt_section(pc, name)
+ CORE_ADDR pc;
+ char *name;
+{
+ struct obj_section *s;
+ int retval = 0;
+
+ s = find_pc_section(pc);
+
+ retval = (s != NULL
+ && s->the_bfd_section->name != NULL
+ && STREQ (s->the_bfd_section->name, ".plt"));
+ return(retval);
+}
diff --git a/gnu/usr.bin/gdb/gdb/objfiles.h b/gnu/usr.bin/gdb/gdb/objfiles.h
new file mode 100644
index 0000000..b1aa8c9
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/objfiles.h
@@ -0,0 +1,451 @@
+/* Definitions for symbol file management in GDB.
+ Copyright (C) 1992, 1993, 1994 Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#if !defined (OBJFILES_H)
+#define OBJFILES_H
+
+/* This structure maintains information on a per-objfile basis about the
+ "entry point" of the objfile, and the scope within which the entry point
+ exists. It is possible that gdb will see more than one objfile that is
+ executable, each with its own entry point.
+
+ For example, for dynamically linked executables in SVR4, the dynamic linker
+ code is contained within the shared C library, which is actually executable
+ and is run by the kernel first when an exec is done of a user executable
+ that is dynamically linked. The dynamic linker within the shared C library
+ then maps in the various program segments in the user executable and jumps
+ to the user executable's recorded entry point, as if the call had been made
+ directly by the kernel.
+
+ The traditional gdb method of using this info is to use the recorded entry
+ point to set the variables entry_file_lowpc and entry_file_highpc from
+ the debugging information, where these values are the starting address
+ (inclusive) and ending address (exclusive) of the instruction space in the
+ executable which correspond to the "startup file", I.E. crt0.o in most
+ cases. This file is assumed to be a startup file and frames with pc's
+ inside it are treated as nonexistent. Setting these variables is necessary
+ so that backtraces do not fly off the bottom of the stack.
+
+ Gdb also supports an alternate method to avoid running off the bottom
+ of the stack.
+
+ There are two frames that are "special", the frame for the function
+ containing the process entry point, since it has no predecessor frame,
+ and the frame for the function containing the user code entry point
+ (the main() function), since all the predecessor frames are for the
+ process startup code. Since we have no guarantee that the linked
+ in startup modules have any debugging information that gdb can use,
+ we need to avoid following frame pointers back into frames that might
+ have been built in the startup code, as we might get hopelessly
+ confused. However, we almost always have debugging information
+ available for main().
+
+ These variables are used to save the range of PC values which are valid
+ within the main() function and within the function containing the process
+ entry point. If we always consider the frame for main() as the outermost
+ frame when debugging user code, and the frame for the process entry
+ point function as the outermost frame when debugging startup code, then
+ all we have to do is have FRAME_CHAIN_VALID return false whenever a
+ frame's current PC is within the range specified by these variables.
+ In essence, we set "ceilings" in the frame chain beyond which we will
+ not proceed when following the frame chain back up the stack.
+
+ A nice side effect is that we can still debug startup code without
+ running off the end of the frame chain, assuming that we have usable
+ debugging information in the startup modules, and if we choose to not
+ use the block at main, or can't find it for some reason, everything
+ still works as before. And if we have no startup code debugging
+ information but we do have usable information for main(), backtraces
+ from user code don't go wandering off into the startup code.
+
+ To use this method, define your FRAME_CHAIN_VALID macro like:
+
+ #define FRAME_CHAIN_VALID(chain, thisframe) \
+ (chain != 0 \
+ && !(inside_main_func ((thisframe)->pc)) \
+ && !(inside_entry_func ((thisframe)->pc)))
+
+ and add initializations of the four scope controlling variables inside
+ the object file / debugging information processing modules. */
+
+struct entry_info
+{
+
+ /* The value we should use for this objects entry point.
+ The illegal/unknown value needs to be something other than 0, ~0
+ for instance, which is much less likely than 0. */
+
+ CORE_ADDR entry_point;
+
+#define INVALID_ENTRY_POINT (~0) /* ~0 will not be in any file, we hope. */
+
+ /* Start (inclusive) and end (exclusive) of function containing the
+ entry point. */
+
+ CORE_ADDR entry_func_lowpc;
+ CORE_ADDR entry_func_highpc;
+
+ /* Start (inclusive) and end (exclusive) of object file containing the
+ entry point. */
+
+ CORE_ADDR entry_file_lowpc;
+ CORE_ADDR entry_file_highpc;
+
+ /* Start (inclusive) and end (exclusive) of the user code main() function. */
+
+ CORE_ADDR main_func_lowpc;
+ CORE_ADDR main_func_highpc;
+
+/* Use these values when any of the above ranges is invalid. */
+
+/* We use these values because it guarantees that there is no number that is
+ both >= LOWPC && < HIGHPC. It is also highly unlikely that 3 is a valid
+ module or function start address (as opposed to 0). */
+
+#define INVALID_ENTRY_LOWPC (3)
+#define INVALID_ENTRY_HIGHPC (1)
+
+};
+
+/* Sections in an objfile.
+
+ It is strange that we have both this notion of "sections"
+ and the one used by section_offsets. Section as used
+ here, (currently at least) means a BFD section, and the sections
+ are set up from the BFD sections in allocate_objfile.
+
+ The sections in section_offsets have their meaning determined by
+ the symbol format, and they are set up by the sym_offsets function
+ for that symbol file format.
+
+ I'm not sure this could or should be changed, however. */
+
+struct obj_section {
+ CORE_ADDR addr; /* lowest address in section */
+ CORE_ADDR endaddr; /* 1+highest address in section */
+
+ /* This field is being used for nefarious purposes by syms_from_objfile.
+ It is said to be redundant with section_offsets; it's not really being
+ used that way, however, it's some sort of hack I don't understand
+ and am not going to try to eliminate (yet, anyway). FIXME.
+
+ It was documented as "offset between (end)addr and actual memory
+ addresses", but that's not true; addr & endaddr are actual memory
+ addresses. */
+ CORE_ADDR offset;
+
+ sec_ptr the_bfd_section; /* BFD section pointer */
+
+ /* Objfile this section is part of. */
+ struct objfile *objfile;
+};
+
+/* Master structure for keeping track of each file from which
+ gdb reads symbols. There are several ways these get allocated: 1.
+ The main symbol file, symfile_objfile, set by the symbol-file command,
+ 2. Additional symbol files added by the add-symbol-file command,
+ 3. Shared library objfiles, added by ADD_SOLIB, 4. symbol files
+ for modules that were loaded when GDB attached to a remote system
+ (see remote-vx.c). */
+
+struct objfile
+{
+
+ /* All struct objfile's are chained together by their next pointers.
+ The global variable "object_files" points to the first link in this
+ chain.
+
+ FIXME: There is a problem here if the objfile is reusable, and if
+ multiple users are to be supported. The problem is that the objfile
+ list is linked through a member of the objfile struct itself, which
+ is only valid for one gdb process. The list implementation needs to
+ be changed to something like:
+
+ struct list {struct list *next; struct objfile *objfile};
+
+ where the list structure is completely maintained separately within
+ each gdb process. */
+
+ struct objfile *next;
+
+ /* The object file's name. Malloc'd; free it if you free this struct. */
+
+ char *name;
+
+ /* Some flag bits for this objfile. */
+
+ unsigned short flags;
+
+ /* Each objfile points to a linked list of symtabs derived from this file,
+ one symtab structure for each compilation unit (source file). Each link
+ in the symtab list contains a backpointer to this objfile. */
+
+ struct symtab *symtabs;
+
+ /* Each objfile points to a linked list of partial symtabs derived from
+ this file, one partial symtab structure for each compilation unit
+ (source file). */
+
+ struct partial_symtab *psymtabs;
+
+ /* List of freed partial symtabs, available for re-use */
+
+ struct partial_symtab *free_psymtabs;
+
+ /* The object file's BFD. Can be null, in which case bfd_open (name) and
+ put the result here. */
+
+ bfd *obfd;
+
+ /* The modification timestamp of the object file, as of the last time
+ we read its symbols. */
+
+ long mtime;
+
+ /* Obstacks to hold objects that should be freed when we load a new symbol
+ table from this object file. */
+
+ struct obstack psymbol_obstack; /* Partial symbols */
+ struct obstack symbol_obstack; /* Full symbols */
+ struct obstack type_obstack; /* Types */
+
+ /* Vectors of all partial symbols read in from file. The actual data
+ is stored in the psymbol_obstack. */
+
+ struct psymbol_allocation_list global_psymbols;
+ struct psymbol_allocation_list static_psymbols;
+
+ /* Each file contains a pointer to an array of minimal symbols for all
+ global symbols that are defined within the file. The array is terminated
+ by a "null symbol", one that has a NULL pointer for the name and a zero
+ value for the address. This makes it easy to walk through the array
+ when passed a pointer to somewhere in the middle of it. There is also
+ a count of the number of symbols, which does include the terminating
+ null symbol. The array itself, as well as all the data that it points
+ to, should be allocated on the symbol_obstack for this file. */
+
+ struct minimal_symbol *msymbols;
+ int minimal_symbol_count;
+
+ /* For object file formats which don't specify fundamental types, gdb
+ can create such types. For now, it maintains a vector of pointers
+ to these internally created fundamental types on a per objfile basis,
+ however it really should ultimately keep them on a per-compilation-unit
+ basis, to account for linkage-units that consist of a number of
+ compilation units that may have different fundamental types, such as
+ linking C modules with ADA modules, or linking C modules that are
+ compiled with 32-bit ints with C modules that are compiled with 64-bit
+ ints (not inherently evil with a smarter linker). */
+
+ struct type **fundamental_types;
+
+ /* The mmalloc() malloc-descriptor for this objfile if we are using
+ the memory mapped malloc() package to manage storage for this objfile's
+ data. NULL if we are not. */
+
+ PTR md;
+
+ /* The file descriptor that was used to obtain the mmalloc descriptor
+ for this objfile. If we call mmalloc_detach with the malloc descriptor
+ we should then close this file descriptor. */
+
+ int mmfd;
+
+ /* Structure which keeps track of functions that manipulate objfile's
+ of the same type as this objfile. I.E. the function to read partial
+ symbols for example. Note that this structure is in statically
+ allocated memory, and is shared by all objfiles that use the
+ object module reader of this type. */
+
+ struct sym_fns *sf;
+
+ /* The per-objfile information about the entry point, the scope (file/func)
+ containing the entry point, and the scope of the user's main() func. */
+
+ struct entry_info ei;
+
+ /* Information about stabs. Will be filled in with a dbx_symfile_info
+ struct by those readers that need it. */
+
+ PTR sym_stab_info;
+
+ /* Hook for information for use by the symbol reader (currently used
+ for information shared by sym_init and sym_read). It is
+ typically a pointer to malloc'd memory. The symbol reader's finish
+ function is responsible for freeing the memory thusly allocated. */
+
+ PTR sym_private;
+
+ /* Hook for target-architecture-specific information. This must
+ point to memory allocated on one of the obstacks in this objfile,
+ so that it gets freed automatically when reading a new object
+ file. */
+
+ PTR obj_private;
+
+ /* Set of relocation offsets to apply to each section.
+ Currently on the psymbol_obstack (which makes no sense, but I'm
+ not sure it's harming anything).
+
+ These offsets indicate that all symbols (including partial and
+ minimal symbols) which have been read have been relocated by this
+ much. Symbols which are yet to be read need to be relocated by
+ it. */
+
+ struct section_offsets *section_offsets;
+ int num_sections;
+
+ /* set of section begin and end addresses used to map pc addresses
+ into sections. Currently on the psymbol_obstack (which makes no
+ sense, but I'm not sure it's harming anything). */
+
+ struct obj_section
+ *sections,
+ *sections_end;
+
+ /* two auxiliary fields, used to hold the fp of separate symbol files */
+ FILE *auxf1, *auxf2;
+};
+
+/* Defines for the objfile flag word. */
+
+/* Gdb can arrange to allocate storage for all objects related to a
+ particular objfile in a designated section of its address space,
+ managed at a low level by mmap() and using a special version of
+ malloc that handles malloc/free/realloc on top of the mmap() interface.
+ This allows the "internal gdb state" for a particular objfile to be
+ dumped to a gdb state file and subsequently reloaded at a later time. */
+
+#define OBJF_MAPPED (1 << 0) /* Objfile data is mmap'd */
+
+/* When using mapped/remapped predigested gdb symbol information, we need
+ a flag that indicates that we have previously done an initial symbol
+ table read from this particular objfile. We can't just look for the
+ absence of any of the three symbol tables (msymbols, psymtab, symtab)
+ because if the file has no symbols for example, none of these will
+ exist. */
+
+#define OBJF_SYMS (1 << 1) /* Have tried to read symbols */
+
+/* The object file that the main symbol table was loaded from (e.g. the
+ argument to the "symbol-file" or "file" command). */
+
+extern struct objfile *symfile_objfile;
+
+/* When we need to allocate a new type, we need to know which type_obstack
+ to allocate the type on, since there is one for each objfile. The places
+ where types are allocated are deeply buried in function call hierarchies
+ which know nothing about objfiles, so rather than trying to pass a
+ particular objfile down to them, we just do an end run around them and
+ set current_objfile to be whatever objfile we expect to be using at the
+ time types are being allocated. For instance, when we start reading
+ symbols for a particular objfile, we set current_objfile to point to that
+ objfile, and when we are done, we set it back to NULL, to ensure that we
+ never put a type someplace other than where we are expecting to put it.
+ FIXME: Maybe we should review the entire type handling system and
+ see if there is a better way to avoid this problem. */
+
+extern struct objfile *current_objfile;
+
+/* All known objfiles are kept in a linked list. This points to the
+ root of this list. */
+
+extern struct objfile *object_files;
+
+/* Declarations for functions defined in objfiles.c */
+
+extern struct objfile *
+allocate_objfile PARAMS ((bfd *, int));
+
+extern int
+build_objfile_section_table PARAMS ((struct objfile *));
+
+extern void
+unlink_objfile PARAMS ((struct objfile *));
+
+extern void
+free_objfile PARAMS ((struct objfile *));
+
+extern void
+free_all_objfiles PARAMS ((void));
+
+extern void
+objfile_relocate PARAMS ((struct objfile *, struct section_offsets *));
+
+extern int
+have_partial_symbols PARAMS ((void));
+
+extern int
+have_full_symbols PARAMS ((void));
+
+/* Functions for dealing with the minimal symbol table, really a misc
+ address<->symbol mapping for things we don't have debug symbols for. */
+
+extern int
+have_minimal_symbols PARAMS ((void));
+
+extern struct obj_section *
+find_pc_section PARAMS((CORE_ADDR pc));
+
+/* Traverse all object files. ALL_OBJFILES_SAFE works even if you delete
+ the objfile during the traversal. */
+
+#define ALL_OBJFILES(obj) \
+ for ((obj) = object_files; (obj) != NULL; (obj) = (obj)->next)
+
+#define ALL_OBJFILES_SAFE(obj,nxt) \
+ for ((obj) = object_files; \
+ (obj) != NULL? ((nxt)=(obj)->next,1) :0; \
+ (obj) = (nxt))
+
+/* Traverse all symtabs in one objfile. */
+
+#define ALL_OBJFILE_SYMTABS(objfile, s) \
+ for ((s) = (objfile) -> symtabs; (s) != NULL; (s) = (s) -> next)
+
+/* Traverse all psymtabs in one objfile. */
+
+#define ALL_OBJFILE_PSYMTABS(objfile, p) \
+ for ((p) = (objfile) -> psymtabs; (p) != NULL; (p) = (p) -> next)
+
+/* Traverse all minimal symbols in one objfile. */
+
+#define ALL_OBJFILE_MSYMBOLS(objfile, m) \
+ for ((m) = (objfile) -> msymbols; SYMBOL_NAME(m) != NULL; (m)++)
+
+/* Traverse all symtabs in all objfiles. */
+
+#define ALL_SYMTABS(objfile, s) \
+ ALL_OBJFILES (objfile) \
+ ALL_OBJFILE_SYMTABS (objfile, s)
+
+/* Traverse all psymtabs in all objfiles. */
+
+#define ALL_PSYMTABS(objfile, p) \
+ ALL_OBJFILES (objfile) \
+ ALL_OBJFILE_PSYMTABS (objfile, p)
+
+/* Traverse all minimal symbols in all objfiles. */
+
+#define ALL_MSYMBOLS(objfile, m) \
+ ALL_OBJFILES (objfile) \
+ if ((objfile)->msymbols) \
+ ALL_OBJFILE_MSYMBOLS (objfile, m)
+
+#endif /* !defined (OBJFILES_H) */
diff --git a/gnu/usr.bin/gdb/gdb/obstack.h b/gnu/usr.bin/gdb/gdb/obstack.h
new file mode 100644
index 0000000..59ceace5
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/obstack.h
@@ -0,0 +1,513 @@
+/* obstack.h - object stack macros
+ Copyright (C) 1988, 89, 90, 91, 92, 93, 94 Free Software Foundation, Inc.
+
+This program is free software; you can redistribute it and/or modify it
+under the terms of the GNU Library General Public License as published by the
+Free Software Foundation; either version 2, or (at your option) any
+later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public License
+along with this program; if not, write to the Free Software
+Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* Summary:
+
+All the apparent functions defined here are macros. The idea
+is that you would use these pre-tested macros to solve a
+very specific set of problems, and they would run fast.
+Caution: no side-effects in arguments please!! They may be
+evaluated MANY times!!
+
+These macros operate a stack of objects. Each object starts life
+small, and may grow to maturity. (Consider building a word syllable
+by syllable.) An object can move while it is growing. Once it has
+been "finished" it never changes address again. So the "top of the
+stack" is typically an immature growing object, while the rest of the
+stack is of mature, fixed size and fixed address objects.
+
+These routines grab large chunks of memory, using a function you
+supply, called `obstack_chunk_alloc'. On occasion, they free chunks,
+by calling `obstack_chunk_free'. You must define them and declare
+them before using any obstack macros.
+
+Each independent stack is represented by a `struct obstack'.
+Each of the obstack macros expects a pointer to such a structure
+as the first argument.
+
+One motivation for this package is the problem of growing char strings
+in symbol tables. Unless you are "fascist pig with a read-only mind"
+--Gosper's immortal quote from HAKMEM item 154, out of context--you
+would not like to put any arbitrary upper limit on the length of your
+symbols.
+
+In practice this often means you will build many short symbols and a
+few long symbols. At the time you are reading a symbol you don't know
+how long it is. One traditional method is to read a symbol into a
+buffer, realloc()ating the buffer every time you try to read a symbol
+that is longer than the buffer. This is beaut, but you still will
+want to copy the symbol from the buffer to a more permanent
+symbol-table entry say about half the time.
+
+With obstacks, you can work differently. Use one obstack for all symbol
+names. As you read a symbol, grow the name in the obstack gradually.
+When the name is complete, finalize it. Then, if the symbol exists already,
+free the newly read name.
+
+The way we do this is to take a large chunk, allocating memory from
+low addresses. When you want to build a symbol in the chunk you just
+add chars above the current "high water mark" in the chunk. When you
+have finished adding chars, because you got to the end of the symbol,
+you know how long the chars are, and you can create a new object.
+Mostly the chars will not burst over the highest address of the chunk,
+because you would typically expect a chunk to be (say) 100 times as
+long as an average object.
+
+In case that isn't clear, when we have enough chars to make up
+the object, THEY ARE ALREADY CONTIGUOUS IN THE CHUNK (guaranteed)
+so we just point to it where it lies. No moving of chars is
+needed and this is the second win: potentially long strings need
+never be explicitly shuffled. Once an object is formed, it does not
+change its address during its lifetime.
+
+When the chars burst over a chunk boundary, we allocate a larger
+chunk, and then copy the partly formed object from the end of the old
+chunk to the beginning of the new larger chunk. We then carry on
+accreting characters to the end of the object as we normally would.
+
+A special macro is provided to add a single char at a time to a
+growing object. This allows the use of register variables, which
+break the ordinary 'growth' macro.
+
+Summary:
+ We allocate large chunks.
+ We carve out one object at a time from the current chunk.
+ Once carved, an object never moves.
+ We are free to append data of any size to the currently
+ growing object.
+ Exactly one object is growing in an obstack at any one time.
+ You can run one obstack per control block.
+ You may have as many control blocks as you dare.
+ Because of the way we do it, you can `unwind' an obstack
+ back to a previous state. (You may remove objects much
+ as you would with a stack.)
+*/
+
+
+/* Don't do the contents of this file more than once. */
+
+#ifndef __OBSTACK_H__
+#define __OBSTACK_H__
+
+/* We use subtraction of (char *)0 instead of casting to int
+ because on word-addressable machines a simple cast to int
+ may ignore the byte-within-word field of the pointer. */
+
+#ifndef __PTR_TO_INT
+#define __PTR_TO_INT(P) ((P) - (char *)0)
+#endif
+
+#ifndef __INT_TO_PTR
+#define __INT_TO_PTR(P) ((P) + (char *)0)
+#endif
+
+/* We need the type of the resulting object. In ANSI C it is ptrdiff_t
+ but in traditional C it is usually long. If we are in ANSI C and
+ don't already have ptrdiff_t get it. */
+
+#if defined (__STDC__) && ! defined (offsetof)
+#if defined (__GNUC__) && defined (IN_GCC)
+/* On Next machine, the system's stddef.h screws up if included
+ after we have defined just ptrdiff_t, so include all of stddef.h.
+ Otherwise, define just ptrdiff_t, which is all we need. */
+#ifndef __NeXT__
+#define __need_ptrdiff_t
+#endif
+#endif
+
+#include <stddef.h>
+#endif
+
+#ifdef __STDC__
+#define PTR_INT_TYPE ptrdiff_t
+#else
+#define PTR_INT_TYPE long
+#endif
+
+struct _obstack_chunk /* Lives at front of each chunk. */
+{
+ char *limit; /* 1 past end of this chunk */
+ struct _obstack_chunk *prev; /* address of prior chunk or NULL */
+ char contents[4]; /* objects begin here */
+};
+
+struct obstack /* control current object in current chunk */
+{
+ long chunk_size; /* preferred size to allocate chunks in */
+ struct _obstack_chunk* chunk; /* address of current struct obstack_chunk */
+ char *object_base; /* address of object we are building */
+ char *next_free; /* where to add next char to current object */
+ char *chunk_limit; /* address of char after current chunk */
+ PTR_INT_TYPE temp; /* Temporary for some macros. */
+ int alignment_mask; /* Mask of alignment for each object. */
+ struct _obstack_chunk *(*chunkfun) (); /* User's fcn to allocate a chunk. */
+ void (*freefun) (); /* User's function to free a chunk. */
+ char *extra_arg; /* first arg for chunk alloc/dealloc funcs */
+ unsigned use_extra_arg:1; /* chunk alloc/dealloc funcs take extra arg */
+ unsigned maybe_empty_object:1;/* There is a possibility that the current
+ chunk contains a zero-length object. This
+ prevents freeing the chunk if we allocate
+ a bigger chunk to replace it. */
+ unsigned alloc_failed:1; /* chunk alloc func returned 0 */
+};
+
+/* Declare the external functions we use; they are in obstack.c. */
+
+#ifdef __STDC__
+extern void _obstack_newchunk (struct obstack *, int);
+extern void _obstack_free (struct obstack *, void *);
+extern int _obstack_begin (struct obstack *, int, int,
+ void *(*) (), void (*) ());
+extern int _obstack_begin_1 (struct obstack *, int, int,
+ void *(*) (), void (*) (), void *);
+#else
+extern void _obstack_newchunk ();
+extern void _obstack_free ();
+extern int _obstack_begin ();
+extern int _obstack_begin_1 ();
+#endif
+
+#ifdef __STDC__
+
+/* Do the function-declarations after the structs
+ but before defining the macros. */
+
+void obstack_init (struct obstack *obstack);
+
+void * obstack_alloc (struct obstack *obstack, int size);
+
+void * obstack_copy (struct obstack *obstack, void *address, int size);
+void * obstack_copy0 (struct obstack *obstack, void *address, int size);
+
+void obstack_free (struct obstack *obstack, void *block);
+
+void obstack_blank (struct obstack *obstack, int size);
+
+void obstack_grow (struct obstack *obstack, void *data, int size);
+void obstack_grow0 (struct obstack *obstack, void *data, int size);
+
+void obstack_1grow (struct obstack *obstack, int data_char);
+void obstack_ptr_grow (struct obstack *obstack, void *data);
+void obstack_int_grow (struct obstack *obstack, int data);
+
+void * obstack_finish (struct obstack *obstack);
+
+int obstack_object_size (struct obstack *obstack);
+
+int obstack_room (struct obstack *obstack);
+void obstack_1grow_fast (struct obstack *obstack, int data_char);
+void obstack_ptr_grow_fast (struct obstack *obstack, void *data);
+void obstack_int_grow_fast (struct obstack *obstack, int data);
+void obstack_blank_fast (struct obstack *obstack, int size);
+
+void * obstack_base (struct obstack *obstack);
+void * obstack_next_free (struct obstack *obstack);
+int obstack_alignment_mask (struct obstack *obstack);
+int obstack_chunk_size (struct obstack *obstack);
+
+#endif /* __STDC__ */
+
+/* Non-ANSI C cannot really support alternative functions for these macros,
+ so we do not declare them. */
+
+/* Pointer to beginning of object being allocated or to be allocated next.
+ Note that this might not be the final address of the object
+ because a new chunk might be needed to hold the final size. */
+
+#define obstack_base(h) ((h)->alloc_failed ? 0 : (h)->object_base)
+
+/* Size for allocating ordinary chunks. */
+
+#define obstack_chunk_size(h) ((h)->chunk_size)
+
+/* Pointer to next byte not yet allocated in current chunk. */
+
+#define obstack_next_free(h) ((h)->alloc_failed ? 0 : (h)->next_free)
+
+/* Mask specifying low bits that should be clear in address of an object. */
+
+#define obstack_alignment_mask(h) ((h)->alignment_mask)
+
+#define obstack_init(h) \
+ _obstack_begin ((h), 0, 0, \
+ (void *(*) ()) obstack_chunk_alloc, (void (*) ()) obstack_chunk_free)
+
+#define obstack_begin(h, size) \
+ _obstack_begin ((h), (size), 0, \
+ (void *(*) ()) obstack_chunk_alloc, (void (*) ()) obstack_chunk_free)
+
+#define obstack_specify_allocation(h, size, alignment, chunkfun, freefun) \
+ _obstack_begin ((h), (size), (alignment), \
+ (void *(*) ()) (chunkfun), (void (*) ()) (freefun))
+
+#define obstack_specify_allocation_with_arg(h, size, alignment, chunkfun, freefun, arg) \
+ _obstack_begin_1 ((h), (size), (alignment), \
+ (void *(*) ()) (chunkfun), (void (*) ()) (freefun), (arg))
+
+#define obstack_chunkfun(h, newchunkfun) \
+ ((h) -> chunkfun = (struct _obstack_chunk *(*)()) (newchunkfun))
+
+#define obstack_freefun(h, newfreefun) \
+ ((h) -> freefun = (void (*)()) (newfreefun))
+
+#define obstack_1grow_fast(h,achar) (*((h)->next_free)++ = achar)
+
+#define obstack_blank_fast(h,n) ((h)->next_free += (n))
+
+#if defined (__GNUC__) && defined (__STDC__)
+#if __GNUC__ < 2
+#define __extension__
+#endif
+
+/* For GNU C, if not -traditional,
+ we can define these macros to compute all args only once
+ without using a global variable.
+ Also, we can avoid using the `temp' slot, to make faster code. */
+
+#define obstack_object_size(OBSTACK) \
+ __extension__ \
+ ({ struct obstack *__o = (OBSTACK); \
+ __o->alloc_failed ? 0 : \
+ (unsigned) (__o->next_free - __o->object_base); })
+
+#define obstack_room(OBSTACK) \
+ __extension__ \
+ ({ struct obstack *__o = (OBSTACK); \
+ (unsigned) (__o->chunk_limit - __o->next_free); })
+
+#define obstack_grow(OBSTACK,where,length) \
+__extension__ \
+({ struct obstack *__o = (OBSTACK); \
+ int __len = (length); \
+ if (__o->next_free + __len > __o->chunk_limit) \
+ _obstack_newchunk (__o, __len); \
+ if (!__o->alloc_failed) \
+ { \
+ bcopy (where, __o->next_free, __len); \
+ __o->next_free += __len; \
+ } \
+ (void) 0; })
+
+#define obstack_grow0(OBSTACK,where,length) \
+__extension__ \
+({ struct obstack *__o = (OBSTACK); \
+ int __len = (length); \
+ if (__o->next_free + __len + 1 > __o->chunk_limit) \
+ _obstack_newchunk (__o, __len + 1); \
+ if (!__o->alloc_failed) \
+ { \
+ bcopy (where, __o->next_free, __len); \
+ __o->next_free += __len; \
+ *(__o->next_free)++ = 0; \
+ } \
+ (void) 0; })
+
+#define obstack_1grow(OBSTACK,datum) \
+__extension__ \
+({ struct obstack *__o = (OBSTACK); \
+ if (__o->next_free + 1 > __o->chunk_limit) \
+ _obstack_newchunk (__o, 1); \
+ if (!__o->alloc_failed) \
+ *(__o->next_free)++ = (datum); \
+ (void) 0; })
+
+/* These assume that the obstack alignment is good enough for pointers or ints,
+ and that the data added so far to the current object
+ shares that much alignment. */
+
+#define obstack_ptr_grow(OBSTACK,datum) \
+__extension__ \
+({ struct obstack *__o = (OBSTACK); \
+ if (__o->next_free + sizeof (void *) > __o->chunk_limit) \
+ _obstack_newchunk (__o, sizeof (void *)); \
+ if (!__o->alloc_failed) \
+ *((void **)__o->next_free)++ = ((void *)datum); \
+ (void) 0; })
+
+#define obstack_int_grow(OBSTACK,datum) \
+__extension__ \
+({ struct obstack *__o = (OBSTACK); \
+ if (__o->next_free + sizeof (int) > __o->chunk_limit) \
+ _obstack_newchunk (__o, sizeof (int)); \
+ if (!__o->alloc_failed) \
+ *((int *)__o->next_free)++ = ((int)datum); \
+ (void) 0; })
+
+#define obstack_ptr_grow_fast(h,aptr) (*((void **)(h)->next_free)++ = (void *)aptr)
+#define obstack_int_grow_fast(h,aint) (*((int *)(h)->next_free)++ = (int)aint)
+
+#define obstack_blank(OBSTACK,length) \
+__extension__ \
+({ struct obstack *__o = (OBSTACK); \
+ int __len = (length); \
+ if (__o->chunk_limit - __o->next_free < __len) \
+ _obstack_newchunk (__o, __len); \
+ if (!__o->alloc_failed) \
+ __o->next_free += __len; \
+ (void) 0; })
+
+#define obstack_alloc(OBSTACK,length) \
+__extension__ \
+({ struct obstack *__h = (OBSTACK); \
+ obstack_blank (__h, (length)); \
+ obstack_finish (__h); })
+
+#define obstack_copy(OBSTACK,where,length) \
+__extension__ \
+({ struct obstack *__h = (OBSTACK); \
+ obstack_grow (__h, (where), (length)); \
+ obstack_finish (__h); })
+
+#define obstack_copy0(OBSTACK,where,length) \
+__extension__ \
+({ struct obstack *__h = (OBSTACK); \
+ obstack_grow0 (__h, (where), (length)); \
+ obstack_finish (__h); })
+
+/* The local variable is named __o1 to avoid a name conflict
+ when obstack_blank is called. */
+#define obstack_finish(OBSTACK) \
+__extension__ \
+({ struct obstack *__o1 = (OBSTACK); \
+ void *value; \
+ if (__o1->alloc_failed) \
+ value = 0; \
+ else \
+ { \
+ value = (void *) __o1->object_base; \
+ if (__o1->next_free == value) \
+ __o1->maybe_empty_object = 1; \
+ __o1->next_free \
+ = __INT_TO_PTR ((__PTR_TO_INT (__o1->next_free)+__o1->alignment_mask)\
+ & ~ (__o1->alignment_mask)); \
+ if (__o1->next_free - (char *)__o1->chunk \
+ > __o1->chunk_limit - (char *)__o1->chunk) \
+ __o1->next_free = __o1->chunk_limit; \
+ __o1->object_base = __o1->next_free; \
+ } \
+ value; })
+
+#define obstack_free(OBSTACK, OBJ) \
+__extension__ \
+({ struct obstack *__o = (OBSTACK); \
+ void *__obj = (OBJ); \
+ if (__obj > (void *)__o->chunk && __obj < (void *)__o->chunk_limit) \
+ __o->next_free = __o->object_base = __obj; \
+ else (obstack_free) (__o, __obj); })
+
+#else /* not __GNUC__ or not __STDC__ */
+
+#define obstack_object_size(h) \
+ (unsigned) ((h)->alloc_failed ? 0 : (h)->next_free - (h)->object_base)
+
+#define obstack_room(h) \
+ (unsigned) ((h)->chunk_limit - (h)->next_free)
+
+/* Note that the call to _obstack_newchunk is enclosed in (..., 0)
+ so that we can avoid having void expressions
+ in the arms of the conditional expression.
+ Casting the third operand to void was tried before,
+ but some compilers won't accept it. */
+
+#define obstack_grow(h,where,length) \
+( (h)->temp = (length), \
+ (((h)->next_free + (h)->temp > (h)->chunk_limit) \
+ ? (_obstack_newchunk ((h), (h)->temp), 0) : 0), \
+ ((h)->alloc_failed ? 0 : \
+ (bcopy (where, (h)->next_free, (h)->temp), \
+ (h)->next_free += (h)->temp)))
+
+#define obstack_grow0(h,where,length) \
+( (h)->temp = (length), \
+ (((h)->next_free + (h)->temp + 1 > (h)->chunk_limit) \
+ ? (_obstack_newchunk ((h), (h)->temp + 1), 0) : 0), \
+ ((h)->alloc_failed ? 0 : \
+ (bcopy (where, (h)->next_free, (h)->temp), \
+ (h)->next_free += (h)->temp, \
+ *((h)->next_free)++ = 0)))
+
+#define obstack_1grow(h,datum) \
+( (((h)->next_free + 1 > (h)->chunk_limit) \
+ ? (_obstack_newchunk ((h), 1), 0) : 0), \
+ ((h)->alloc_failed ? 0 : \
+ (*((h)->next_free)++ = (datum))))
+
+#define obstack_ptr_grow(h,datum) \
+( (((h)->next_free + sizeof (char *) > (h)->chunk_limit) \
+ ? (_obstack_newchunk ((h), sizeof (char *)), 0) : 0), \
+ ((h)->alloc_failed ? 0 : \
+ (*((char **)(((h)->next_free+=sizeof(char *))-sizeof(char *))) = ((char *)datum))))
+
+#define obstack_int_grow(h,datum) \
+( (((h)->next_free + sizeof (int) > (h)->chunk_limit) \
+ ? (_obstack_newchunk ((h), sizeof (int)), 0) : 0), \
+ ((h)->alloc_failed ? 0 : \
+ (*((int *)(((h)->next_free+=sizeof(int))-sizeof(int))) = ((int)datum))))
+
+#define obstack_ptr_grow_fast(h,aptr) (*((char **)(h)->next_free)++ = (char *)aptr)
+#define obstack_int_grow_fast(h,aint) (*((int *)(h)->next_free)++ = (int)aint)
+
+#define obstack_blank(h,length) \
+( (h)->temp = (length), \
+ (((h)->chunk_limit - (h)->next_free < (h)->temp) \
+ ? (_obstack_newchunk ((h), (h)->temp), 0) : 0), \
+ ((h)->alloc_failed ? 0 : \
+ ((h)->next_free += (h)->temp)))
+
+#define obstack_alloc(h,length) \
+ (obstack_blank ((h), (length)), obstack_finish ((h)))
+
+#define obstack_copy(h,where,length) \
+ (obstack_grow ((h), (where), (length)), obstack_finish ((h)))
+
+#define obstack_copy0(h,where,length) \
+ (obstack_grow0 ((h), (where), (length)), obstack_finish ((h)))
+
+#define obstack_finish(h) \
+( (h)->alloc_failed ? 0 : \
+ (((h)->next_free == (h)->object_base \
+ ? (((h)->maybe_empty_object = 1), 0) \
+ : 0), \
+ (h)->temp = __PTR_TO_INT ((h)->object_base), \
+ (h)->next_free \
+ = __INT_TO_PTR ((__PTR_TO_INT ((h)->next_free)+(h)->alignment_mask) \
+ & ~ ((h)->alignment_mask)), \
+ (((h)->next_free - (char *)(h)->chunk \
+ > (h)->chunk_limit - (char *)(h)->chunk) \
+ ? ((h)->next_free = (h)->chunk_limit) : 0), \
+ (h)->object_base = (h)->next_free, \
+ __INT_TO_PTR ((h)->temp)))
+
+#ifdef __STDC__
+#define obstack_free(h,obj) \
+( (h)->temp = (char *)(obj) - (char *) (h)->chunk, \
+ (((h)->temp > 0 && (h)->temp < (h)->chunk_limit - (char *) (h)->chunk)\
+ ? (int) ((h)->next_free = (h)->object_base \
+ = (h)->temp + (char *) (h)->chunk) \
+ : (((obstack_free) ((h), (h)->temp + (char *) (h)->chunk), 0), 0)))
+#else
+#define obstack_free(h,obj) \
+( (h)->temp = (char *)(obj) - (char *) (h)->chunk, \
+ (((h)->temp > 0 && (h)->temp < (h)->chunk_limit - (char *) (h)->chunk)\
+ ? (int) ((h)->next_free = (h)->object_base \
+ = (h)->temp + (char *) (h)->chunk) \
+ : (_obstack_free ((h), (h)->temp + (char *) (h)->chunk), 0)))
+#endif
+
+#endif /* not __GNUC__ or not __STDC__ */
+
+#endif /* not __OBSTACK_H__ */
diff --git a/gnu/usr.bin/gdb/gdb/parse.c b/gnu/usr.bin/gdb/gdb/parse.c
new file mode 100644
index 0000000..5fb0683
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/parse.c
@@ -0,0 +1,890 @@
+/* Parse expressions for GDB.
+ Copyright (C) 1986, 1989, 1990, 1991, 1994 Free Software Foundation, Inc.
+ Modified from expread.y by the Department of Computer Science at the
+ State University of New York at Buffalo, 1991.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* Parse an expression from text in a string,
+ and return the result as a struct expression pointer.
+ That structure contains arithmetic operations in reverse polish,
+ with constants represented by operations that are followed by special data.
+ See expression.h for the details of the format.
+ What is important here is that it can be built up sequentially
+ during the process of parsing; the lower levels of the tree always
+ come first in the result. */
+
+#include "defs.h"
+#include <string.h>
+#include "symtab.h"
+#include "gdbtypes.h"
+#include "frame.h"
+#include "expression.h"
+#include "value.h"
+#include "command.h"
+#include "language.h"
+#include "parser-defs.h"
+
+/* Global variables declared in parser-defs.h (and commented there). */
+struct expression *expout;
+int expout_size;
+int expout_ptr;
+struct block *expression_context_block;
+struct block *innermost_block;
+int arglist_len;
+union type_stack_elt *type_stack;
+int type_stack_depth, type_stack_size;
+char *lexptr;
+char *namecopy;
+int paren_depth;
+int comma_terminates;
+
+static void
+free_funcalls PARAMS ((void));
+
+static void
+prefixify_expression PARAMS ((struct expression *));
+
+static int
+length_of_subexp PARAMS ((struct expression *, int));
+
+static void
+prefixify_subexp PARAMS ((struct expression *, struct expression *, int, int));
+
+/* Data structure for saving values of arglist_len for function calls whose
+ arguments contain other function calls. */
+
+struct funcall
+ {
+ struct funcall *next;
+ int arglist_len;
+ };
+
+static struct funcall *funcall_chain;
+
+/* Assign machine-independent names to certain registers
+ (unless overridden by the REGISTER_NAMES table) */
+
+#ifdef NO_STD_REGS
+unsigned num_std_regs = 0;
+struct std_regs std_regs[1];
+#else
+struct std_regs std_regs[] = {
+
+#ifdef PC_REGNUM
+ { "pc", PC_REGNUM },
+#endif
+#ifdef FP_REGNUM
+ { "fp", FP_REGNUM },
+#endif
+#ifdef SP_REGNUM
+ { "sp", SP_REGNUM },
+#endif
+#ifdef PS_REGNUM
+ { "ps", PS_REGNUM },
+#endif
+
+};
+
+unsigned num_std_regs = (sizeof std_regs / sizeof std_regs[0]);
+
+#endif
+
+
+/* Begin counting arguments for a function call,
+ saving the data about any containing call. */
+
+void
+start_arglist ()
+{
+ register struct funcall *new;
+
+ new = (struct funcall *) xmalloc (sizeof (struct funcall));
+ new->next = funcall_chain;
+ new->arglist_len = arglist_len;
+ arglist_len = 0;
+ funcall_chain = new;
+}
+
+/* Return the number of arguments in a function call just terminated,
+ and restore the data for the containing function call. */
+
+int
+end_arglist ()
+{
+ register int val = arglist_len;
+ register struct funcall *call = funcall_chain;
+ funcall_chain = call->next;
+ arglist_len = call->arglist_len;
+ free ((PTR)call);
+ return val;
+}
+
+/* Free everything in the funcall chain.
+ Used when there is an error inside parsing. */
+
+static void
+free_funcalls ()
+{
+ register struct funcall *call, *next;
+
+ for (call = funcall_chain; call; call = next)
+ {
+ next = call->next;
+ free ((PTR)call);
+ }
+}
+
+/* This page contains the functions for adding data to the struct expression
+ being constructed. */
+
+/* Add one element to the end of the expression. */
+
+/* To avoid a bug in the Sun 4 compiler, we pass things that can fit into
+ a register through here */
+
+void
+write_exp_elt (expelt)
+ union exp_element expelt;
+{
+ if (expout_ptr >= expout_size)
+ {
+ expout_size *= 2;
+ expout = (struct expression *)
+ xrealloc ((char *) expout, sizeof (struct expression)
+ + EXP_ELEM_TO_BYTES (expout_size));
+ }
+ expout->elts[expout_ptr++] = expelt;
+}
+
+void
+write_exp_elt_opcode (expelt)
+ enum exp_opcode expelt;
+{
+ union exp_element tmp;
+
+ tmp.opcode = expelt;
+
+ write_exp_elt (tmp);
+}
+
+void
+write_exp_elt_sym (expelt)
+ struct symbol *expelt;
+{
+ union exp_element tmp;
+
+ tmp.symbol = expelt;
+
+ write_exp_elt (tmp);
+}
+
+void
+write_exp_elt_block (b)
+ struct block *b;
+{
+ union exp_element tmp;
+ tmp.block = b;
+ write_exp_elt (tmp);
+}
+
+void
+write_exp_elt_longcst (expelt)
+ LONGEST expelt;
+{
+ union exp_element tmp;
+
+ tmp.longconst = expelt;
+
+ write_exp_elt (tmp);
+}
+
+void
+write_exp_elt_dblcst (expelt)
+ double expelt;
+{
+ union exp_element tmp;
+
+ tmp.doubleconst = expelt;
+
+ write_exp_elt (tmp);
+}
+
+void
+write_exp_elt_type (expelt)
+ struct type *expelt;
+{
+ union exp_element tmp;
+
+ tmp.type = expelt;
+
+ write_exp_elt (tmp);
+}
+
+void
+write_exp_elt_intern (expelt)
+ struct internalvar *expelt;
+{
+ union exp_element tmp;
+
+ tmp.internalvar = expelt;
+
+ write_exp_elt (tmp);
+}
+
+/* Add a string constant to the end of the expression.
+
+ String constants are stored by first writing an expression element
+ that contains the length of the string, then stuffing the string
+ constant itself into however many expression elements are needed
+ to hold it, and then writing another expression element that contains
+ the length of the string. I.E. an expression element at each end of
+ the string records the string length, so you can skip over the
+ expression elements containing the actual string bytes from either
+ end of the string. Note that this also allows gdb to handle
+ strings with embedded null bytes, as is required for some languages.
+
+ Don't be fooled by the fact that the string is null byte terminated,
+ this is strictly for the convenience of debugging gdb itself. Gdb
+ Gdb does not depend up the string being null terminated, since the
+ actual length is recorded in expression elements at each end of the
+ string. The null byte is taken into consideration when computing how
+ many expression elements are required to hold the string constant, of
+ course. */
+
+
+void
+write_exp_string (str)
+ struct stoken str;
+{
+ register int len = str.length;
+ register int lenelt;
+ register char *strdata;
+
+ /* Compute the number of expression elements required to hold the string
+ (including a null byte terminator), along with one expression element
+ at each end to record the actual string length (not including the
+ null byte terminator). */
+
+ lenelt = 2 + BYTES_TO_EXP_ELEM (len + 1);
+
+ /* Ensure that we have enough available expression elements to store
+ everything. */
+
+ if ((expout_ptr + lenelt) >= expout_size)
+ {
+ expout_size = max (expout_size * 2, expout_ptr + lenelt + 10);
+ expout = (struct expression *)
+ xrealloc ((char *) expout, (sizeof (struct expression)
+ + EXP_ELEM_TO_BYTES (expout_size)));
+ }
+
+ /* Write the leading length expression element (which advances the current
+ expression element index), then write the string constant followed by a
+ terminating null byte, and then write the trailing length expression
+ element. */
+
+ write_exp_elt_longcst ((LONGEST) len);
+ strdata = (char *) &expout->elts[expout_ptr];
+ memcpy (strdata, str.ptr, len);
+ *(strdata + len) = '\0';
+ expout_ptr += lenelt - 2;
+ write_exp_elt_longcst ((LONGEST) len);
+}
+
+/* Add a bitstring constant to the end of the expression.
+
+ Bitstring constants are stored by first writing an expression element
+ that contains the length of the bitstring (in bits), then stuffing the
+ bitstring constant itself into however many expression elements are
+ needed to hold it, and then writing another expression element that
+ contains the length of the bitstring. I.E. an expression element at
+ each end of the bitstring records the bitstring length, so you can skip
+ over the expression elements containing the actual bitstring bytes from
+ either end of the bitstring. */
+
+void
+write_exp_bitstring (str)
+ struct stoken str;
+{
+ register int bits = str.length; /* length in bits */
+ register int len = (bits + HOST_CHAR_BIT - 1) / HOST_CHAR_BIT;
+ register int lenelt;
+ register char *strdata;
+
+ /* Compute the number of expression elements required to hold the bitstring,
+ along with one expression element at each end to record the actual
+ bitstring length in bits. */
+
+ lenelt = 2 + BYTES_TO_EXP_ELEM (len);
+
+ /* Ensure that we have enough available expression elements to store
+ everything. */
+
+ if ((expout_ptr + lenelt) >= expout_size)
+ {
+ expout_size = max (expout_size * 2, expout_ptr + lenelt + 10);
+ expout = (struct expression *)
+ xrealloc ((char *) expout, (sizeof (struct expression)
+ + EXP_ELEM_TO_BYTES (expout_size)));
+ }
+
+ /* Write the leading length expression element (which advances the current
+ expression element index), then write the bitstring constant, and then
+ write the trailing length expression element. */
+
+ write_exp_elt_longcst ((LONGEST) bits);
+ strdata = (char *) &expout->elts[expout_ptr];
+ memcpy (strdata, str.ptr, len);
+ expout_ptr += lenelt - 2;
+ write_exp_elt_longcst ((LONGEST) bits);
+}
+
+/* Type that corresponds to the address given in a minimal symbol. */
+
+static struct type *msymbol_addr_type;
+
+/* Add the appropriate elements for a minimal symbol to the end of
+ the expression. */
+
+void
+write_exp_msymbol (msymbol, text_symbol_type, data_symbol_type)
+ struct minimal_symbol *msymbol;
+ struct type *text_symbol_type;
+ struct type *data_symbol_type;
+{
+ write_exp_elt_opcode (OP_LONG);
+ write_exp_elt_type (msymbol_addr_type);
+ write_exp_elt_longcst ((LONGEST) SYMBOL_VALUE_ADDRESS (msymbol));
+ write_exp_elt_opcode (OP_LONG);
+
+ write_exp_elt_opcode (UNOP_MEMVAL);
+ switch (msymbol -> type)
+ {
+ case mst_text:
+ case mst_file_text:
+ case mst_solib_trampoline:
+ write_exp_elt_type (text_symbol_type);
+ break;
+
+ case mst_data:
+ case mst_file_data:
+ case mst_bss:
+ case mst_file_bss:
+ write_exp_elt_type (data_symbol_type);
+ break;
+
+ default:
+ write_exp_elt_type (builtin_type_char);
+ break;
+ }
+ write_exp_elt_opcode (UNOP_MEMVAL);
+}
+
+/* Return a null-terminated temporary copy of the name
+ of a string token. */
+
+char *
+copy_name (token)
+ struct stoken token;
+{
+ memcpy (namecopy, token.ptr, token.length);
+ namecopy[token.length] = 0;
+ return namecopy;
+}
+
+/* Reverse an expression from suffix form (in which it is constructed)
+ to prefix form (in which we can conveniently print or execute it). */
+
+static void
+prefixify_expression (expr)
+ register struct expression *expr;
+{
+ register int len =
+ sizeof (struct expression) + EXP_ELEM_TO_BYTES (expr->nelts);
+ register struct expression *temp;
+ register int inpos = expr->nelts, outpos = 0;
+
+ temp = (struct expression *) alloca (len);
+
+ /* Copy the original expression into temp. */
+ memcpy (temp, expr, len);
+
+ prefixify_subexp (temp, expr, inpos, outpos);
+}
+
+/* Return the number of exp_elements in the subexpression of EXPR
+ whose last exp_element is at index ENDPOS - 1 in EXPR. */
+
+static int
+length_of_subexp (expr, endpos)
+ register struct expression *expr;
+ register int endpos;
+{
+ register int oplen = 1;
+ register int args = 0;
+ register int i;
+
+ if (endpos < 1)
+ error ("?error in length_of_subexp");
+
+ i = (int) expr->elts[endpos - 1].opcode;
+
+ switch (i)
+ {
+ /* C++ */
+ case OP_SCOPE:
+ oplen = longest_to_int (expr->elts[endpos - 2].longconst);
+ oplen = 5 + BYTES_TO_EXP_ELEM (oplen + 1);
+ break;
+
+ case OP_LONG:
+ case OP_DOUBLE:
+ case OP_VAR_VALUE:
+ oplen = 4;
+ break;
+
+ case OP_TYPE:
+ case OP_BOOL:
+ case OP_LAST:
+ case OP_REGISTER:
+ case OP_INTERNALVAR:
+ oplen = 3;
+ break;
+
+ case OP_FUNCALL:
+ oplen = 3;
+ args = 1 + longest_to_int (expr->elts[endpos - 2].longconst);
+ break;
+
+ case UNOP_MAX:
+ case UNOP_MIN:
+ oplen = 3;
+ break;
+
+ case BINOP_VAL:
+ case UNOP_CAST:
+ case UNOP_MEMVAL:
+ oplen = 3;
+ args = 1;
+ break;
+
+ case UNOP_ABS:
+ case UNOP_CAP:
+ case UNOP_CHR:
+ case UNOP_FLOAT:
+ case UNOP_HIGH:
+ case UNOP_ODD:
+ case UNOP_ORD:
+ case UNOP_TRUNC:
+ oplen = 1;
+ args = 1;
+ break;
+
+ case STRUCTOP_STRUCT:
+ case STRUCTOP_PTR:
+ args = 1;
+ /* fall through */
+ case OP_M2_STRING:
+ case OP_STRING:
+ oplen = longest_to_int (expr->elts[endpos - 2].longconst);
+ oplen = 4 + BYTES_TO_EXP_ELEM (oplen + 1);
+ break;
+
+ case OP_BITSTRING:
+ oplen = longest_to_int (expr->elts[endpos - 2].longconst);
+ oplen = (oplen + HOST_CHAR_BIT - 1) / HOST_CHAR_BIT;
+ oplen = 4 + BYTES_TO_EXP_ELEM (oplen);
+ break;
+
+ case OP_ARRAY:
+ oplen = 4;
+ args = longest_to_int (expr->elts[endpos - 2].longconst);
+ args -= longest_to_int (expr->elts[endpos - 3].longconst);
+ args += 1;
+ break;
+
+ case TERNOP_COND:
+ args = 3;
+ break;
+
+ /* Modula-2 */
+ case MULTI_SUBSCRIPT:
+ oplen=3;
+ args = 1 + longest_to_int (expr->elts[endpos- 2].longconst);
+ break;
+
+ case BINOP_ASSIGN_MODIFY:
+ oplen = 3;
+ args = 2;
+ break;
+
+ /* C++ */
+ case OP_THIS:
+ oplen = 2;
+ break;
+
+ default:
+ args = 1 + (i < (int) BINOP_END);
+ }
+
+ while (args > 0)
+ {
+ oplen += length_of_subexp (expr, endpos - oplen);
+ args--;
+ }
+
+ return oplen;
+}
+
+/* Copy the subexpression ending just before index INEND in INEXPR
+ into OUTEXPR, starting at index OUTBEG.
+ In the process, convert it from suffix to prefix form. */
+
+static void
+prefixify_subexp (inexpr, outexpr, inend, outbeg)
+ register struct expression *inexpr;
+ struct expression *outexpr;
+ register int inend;
+ int outbeg;
+{
+ register int oplen = 1;
+ register int args = 0;
+ register int i;
+ int *arglens;
+ enum exp_opcode opcode;
+
+ /* Compute how long the last operation is (in OPLEN),
+ and also how many preceding subexpressions serve as
+ arguments for it (in ARGS). */
+
+ opcode = inexpr->elts[inend - 1].opcode;
+ switch (opcode)
+ {
+ /* C++ */
+ case OP_SCOPE:
+ oplen = longest_to_int (inexpr->elts[inend - 2].longconst);
+ oplen = 5 + BYTES_TO_EXP_ELEM (oplen + 1);
+ break;
+
+ case OP_LONG:
+ case OP_DOUBLE:
+ case OP_VAR_VALUE:
+ oplen = 4;
+ break;
+
+ case OP_TYPE:
+ case OP_BOOL:
+ case OP_LAST:
+ case OP_REGISTER:
+ case OP_INTERNALVAR:
+ oplen = 3;
+ break;
+
+ case OP_FUNCALL:
+ oplen = 3;
+ args = 1 + longest_to_int (inexpr->elts[inend - 2].longconst);
+ break;
+
+ case UNOP_MIN:
+ case UNOP_MAX:
+ oplen = 3;
+ break;
+
+ case UNOP_CAST:
+ case UNOP_MEMVAL:
+ oplen = 3;
+ args = 1;
+ break;
+
+ case UNOP_ABS:
+ case UNOP_CAP:
+ case UNOP_CHR:
+ case UNOP_FLOAT:
+ case UNOP_HIGH:
+ case UNOP_ODD:
+ case UNOP_ORD:
+ case UNOP_TRUNC:
+ oplen=1;
+ args=1;
+ break;
+
+ case STRUCTOP_STRUCT:
+ case STRUCTOP_PTR:
+ args = 1;
+ /* fall through */
+ case OP_M2_STRING:
+ case OP_STRING:
+ oplen = longest_to_int (inexpr->elts[inend - 2].longconst);
+ oplen = 4 + BYTES_TO_EXP_ELEM (oplen + 1);
+ break;
+
+ case OP_BITSTRING:
+ oplen = longest_to_int (inexpr->elts[inend - 2].longconst);
+ oplen = (oplen + HOST_CHAR_BIT - 1) / HOST_CHAR_BIT;
+ oplen = 4 + BYTES_TO_EXP_ELEM (oplen);
+ break;
+
+ case OP_ARRAY:
+ oplen = 4;
+ args = longest_to_int (inexpr->elts[inend - 2].longconst);
+ args -= longest_to_int (inexpr->elts[inend - 3].longconst);
+ args += 1;
+ break;
+
+ case TERNOP_COND:
+ args = 3;
+ break;
+
+ case BINOP_ASSIGN_MODIFY:
+ oplen = 3;
+ args = 2;
+ break;
+
+ /* Modula-2 */
+ case MULTI_SUBSCRIPT:
+ oplen=3;
+ args = 1 + longest_to_int (inexpr->elts[inend - 2].longconst);
+ break;
+
+ /* C++ */
+ case OP_THIS:
+ oplen = 2;
+ break;
+
+ default:
+ args = 1 + ((int) opcode < (int) BINOP_END);
+ }
+
+ /* Copy the final operator itself, from the end of the input
+ to the beginning of the output. */
+ inend -= oplen;
+ memcpy (&outexpr->elts[outbeg], &inexpr->elts[inend],
+ EXP_ELEM_TO_BYTES (oplen));
+ outbeg += oplen;
+
+ /* Find the lengths of the arg subexpressions. */
+ arglens = (int *) alloca (args * sizeof (int));
+ for (i = args - 1; i >= 0; i--)
+ {
+ oplen = length_of_subexp (inexpr, inend);
+ arglens[i] = oplen;
+ inend -= oplen;
+ }
+
+ /* Now copy each subexpression, preserving the order of
+ the subexpressions, but prefixifying each one.
+ In this loop, inend starts at the beginning of
+ the expression this level is working on
+ and marches forward over the arguments.
+ outbeg does similarly in the output. */
+ for (i = 0; i < args; i++)
+ {
+ oplen = arglens[i];
+ inend += oplen;
+ prefixify_subexp (inexpr, outexpr, inend, outbeg);
+ outbeg += oplen;
+ }
+}
+
+/* This page contains the two entry points to this file. */
+
+/* Read an expression from the string *STRINGPTR points to,
+ parse it, and return a pointer to a struct expression that we malloc.
+ Use block BLOCK as the lexical context for variable names;
+ if BLOCK is zero, use the block of the selected stack frame.
+ Meanwhile, advance *STRINGPTR to point after the expression,
+ at the first nonwhite character that is not part of the expression
+ (possibly a null character).
+
+ If COMMA is nonzero, stop if a comma is reached. */
+
+struct expression *
+parse_exp_1 (stringptr, block, comma)
+ char **stringptr;
+ struct block *block;
+ int comma;
+{
+ struct cleanup *old_chain;
+
+ lexptr = *stringptr;
+
+ paren_depth = 0;
+ type_stack_depth = 0;
+
+ comma_terminates = comma;
+
+ if (lexptr == 0 || *lexptr == 0)
+ error_no_arg ("expression to compute");
+
+ old_chain = make_cleanup (free_funcalls, 0);
+ funcall_chain = 0;
+
+ expression_context_block = block ? block : get_selected_block ();
+
+ namecopy = (char *) alloca (strlen (lexptr) + 1);
+ expout_size = 10;
+ expout_ptr = 0;
+ expout = (struct expression *)
+ xmalloc (sizeof (struct expression) + EXP_ELEM_TO_BYTES (expout_size));
+ expout->language_defn = current_language;
+ make_cleanup (free_current_contents, &expout);
+
+ if (current_language->la_parser ())
+ current_language->la_error (NULL);
+
+ discard_cleanups (old_chain);
+
+ /* Record the actual number of expression elements, and then
+ reallocate the expression memory so that we free up any
+ excess elements. */
+
+ expout->nelts = expout_ptr;
+ expout = (struct expression *)
+ xrealloc ((char *) expout,
+ sizeof (struct expression) + EXP_ELEM_TO_BYTES (expout_ptr));;
+
+ /* Convert expression from postfix form as generated by yacc
+ parser, to a prefix form. */
+
+ DUMP_EXPRESSION (expout, gdb_stdout, "before conversion to prefix form");
+ prefixify_expression (expout);
+ DUMP_EXPRESSION (expout, gdb_stdout, "after conversion to prefix form");
+
+ *stringptr = lexptr;
+ return expout;
+}
+
+/* Parse STRING as an expression, and complain if this fails
+ to use up all of the contents of STRING. */
+
+struct expression *
+parse_expression (string)
+ char *string;
+{
+ register struct expression *exp;
+ exp = parse_exp_1 (&string, 0, 0);
+ if (*string)
+ error ("Junk after end of expression.");
+ return exp;
+}
+
+/* Stuff for maintaining a stack of types. Currently just used by C, but
+ probably useful for any language which declares its types "backwards". */
+
+void
+push_type (tp)
+ enum type_pieces tp;
+{
+ if (type_stack_depth == type_stack_size)
+ {
+ type_stack_size *= 2;
+ type_stack = (union type_stack_elt *)
+ xrealloc ((char *) type_stack, type_stack_size * sizeof (*type_stack));
+ }
+ type_stack[type_stack_depth++].piece = tp;
+}
+
+void
+push_type_int (n)
+ int n;
+{
+ if (type_stack_depth == type_stack_size)
+ {
+ type_stack_size *= 2;
+ type_stack = (union type_stack_elt *)
+ xrealloc ((char *) type_stack, type_stack_size * sizeof (*type_stack));
+ }
+ type_stack[type_stack_depth++].int_val = n;
+}
+
+enum type_pieces
+pop_type ()
+{
+ if (type_stack_depth)
+ return type_stack[--type_stack_depth].piece;
+ return tp_end;
+}
+
+int
+pop_type_int ()
+{
+ if (type_stack_depth)
+ return type_stack[--type_stack_depth].int_val;
+ /* "Can't happen". */
+ return 0;
+}
+
+/* Pop the type stack and return the type which corresponds to FOLLOW_TYPE
+ as modified by all the stuff on the stack. */
+struct type *
+follow_types (follow_type)
+ struct type *follow_type;
+{
+ int done = 0;
+ int array_size;
+ struct type *range_type;
+
+ while (!done)
+ switch (pop_type ())
+ {
+ case tp_end:
+ done = 1;
+ break;
+ case tp_pointer:
+ follow_type = lookup_pointer_type (follow_type);
+ break;
+ case tp_reference:
+ follow_type = lookup_reference_type (follow_type);
+ break;
+ case tp_array:
+ array_size = pop_type_int ();
+ if (array_size != -1)
+ {
+ range_type =
+ create_range_type ((struct type *) NULL,
+ builtin_type_int, 0,
+ array_size - 1);
+ follow_type =
+ create_array_type ((struct type *) NULL,
+ follow_type, range_type);
+ }
+ else
+ follow_type = lookup_pointer_type (follow_type);
+ break;
+ case tp_function:
+ follow_type = lookup_function_type (follow_type);
+ break;
+ }
+ return follow_type;
+}
+
+void
+_initialize_parse ()
+{
+ type_stack_size = 80;
+ type_stack_depth = 0;
+ type_stack = (union type_stack_elt *)
+ xmalloc (type_stack_size * sizeof (*type_stack));
+
+ /* We don't worry too much about what the name of this type is
+ because the name should rarely appear in output to the user. */
+
+ msymbol_addr_type =
+ init_type (TYPE_CODE_PTR, TARGET_PTR_BIT / HOST_CHAR_BIT, 0,
+ "void *", NULL);
+}
diff --git a/gnu/usr.bin/gdb/gdb/parser-defs.h b/gnu/usr.bin/gdb/gdb/parser-defs.h
new file mode 100644
index 0000000..67ba0c3
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/parser-defs.h
@@ -0,0 +1,186 @@
+/* Parser definitions for GDB.
+ Copyright (C) 1986, 1989, 1990, 1991 Free Software Foundation, Inc.
+ Modified from expread.y by the Department of Computer Science at the
+ State University of New York at Buffalo.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#if !defined (PARSER_DEFS_H)
+#define PARSER_DEFS_H 1
+
+struct std_regs {
+ char *name;
+ int regnum;
+};
+
+extern struct std_regs std_regs[];
+extern unsigned num_std_regs;
+
+extern struct expression *expout;
+extern int expout_size;
+extern int expout_ptr;
+
+/* If this is nonzero, this block is used as the lexical context
+ for symbol names. */
+
+extern struct block *expression_context_block;
+
+/* The innermost context required by the stack and register variables
+ we've encountered so far. */
+extern struct block *innermost_block;
+
+/* The block in which the most recently discovered symbol was found.
+ FIXME: Should be declared along with lookup_symbol in symtab.h; is not
+ related specifically to parsing. */
+extern struct block *block_found;
+
+/* Number of arguments seen so far in innermost function call. */
+extern int arglist_len;
+
+/* A string token, either a char-string or bit-string. Char-strings are
+ used, for example, for the names of symbols. */
+
+struct stoken
+ {
+ /* Pointer to first byte of char-string or first bit of bit-string */
+ char *ptr;
+ /* Length of string in bytes for char-string or bits for bit-string */
+ int length;
+ };
+
+struct ttype
+ {
+ struct stoken stoken;
+ struct type *type;
+ };
+
+struct symtoken
+ {
+ struct stoken stoken;
+ struct symbol *sym;
+ int is_a_field_of_this;
+ };
+
+/* For parsing of complicated types.
+ An array should be preceded in the list by the size of the array. */
+enum type_pieces
+ {tp_end = -1, tp_pointer, tp_reference, tp_array, tp_function};
+/* The stack can contain either an enum type_pieces or an int. */
+union type_stack_elt {
+ enum type_pieces piece;
+ int int_val;
+};
+extern union type_stack_elt *type_stack;
+extern int type_stack_depth, type_stack_size;
+
+extern void write_exp_elt PARAMS ((union exp_element));
+
+extern void write_exp_elt_opcode PARAMS ((enum exp_opcode));
+
+extern void write_exp_elt_sym PARAMS ((struct symbol *));
+
+extern void write_exp_elt_longcst PARAMS ((LONGEST));
+
+extern void write_exp_elt_dblcst PARAMS ((double));
+
+extern void write_exp_elt_type PARAMS ((struct type *));
+
+extern void write_exp_elt_intern PARAMS ((struct internalvar *));
+
+extern void write_exp_string PARAMS ((struct stoken));
+
+extern void write_exp_bitstring PARAMS ((struct stoken));
+
+extern void write_exp_elt_block PARAMS ((struct block *));
+
+extern void write_exp_msymbol PARAMS ((struct minimal_symbol *,
+ struct type *, struct type *));
+
+extern void
+start_arglist PARAMS ((void));
+
+extern int
+end_arglist PARAMS ((void));
+
+extern char *
+copy_name PARAMS ((struct stoken));
+
+extern void
+push_type PARAMS ((enum type_pieces));
+
+extern void
+push_type_int PARAMS ((int));
+
+extern enum type_pieces
+pop_type PARAMS ((void));
+
+extern int
+pop_type_int PARAMS ((void));
+
+extern struct type *follow_types PARAMS ((struct type *));
+
+/* During parsing of a C expression, the pointer to the next character
+ is in this variable. */
+
+extern char *lexptr;
+
+/* Tokens that refer to names do so with explicit pointer and length,
+ so they can share the storage that lexptr is parsing.
+
+ When it is necessary to pass a name to a function that expects
+ a null-terminated string, the substring is copied out
+ into a block of storage that namecopy points to.
+
+ namecopy is allocated once, guaranteed big enough, for each parsing. */
+
+extern char *namecopy;
+
+/* Current depth in parentheses within the expression. */
+
+extern int paren_depth;
+
+/* Nonzero means stop parsing on first comma (if not within parentheses). */
+
+extern int comma_terminates;
+
+/* These codes indicate operator precedences for expression printing,
+ least tightly binding first. */
+/* Adding 1 to a precedence value is done for binary operators,
+ on the operand which is more tightly bound, so that operators
+ of equal precedence within that operand will get parentheses. */
+/* PREC_HYPER and PREC_ABOVE_COMMA are not the precedence of any operator;
+ they are used as the "surrounding precedence" to force
+ various kinds of things to be parenthesized. */
+enum precedence
+{ PREC_NULL, PREC_COMMA, PREC_ABOVE_COMMA, PREC_ASSIGN, PREC_LOGICAL_OR,
+ PREC_LOGICAL_AND, PREC_BITWISE_IOR, PREC_BITWISE_AND, PREC_BITWISE_XOR,
+ PREC_EQUAL, PREC_ORDER, PREC_SHIFT, PREC_ADD, PREC_MUL, PREC_REPEAT,
+ PREC_HYPER, PREC_PREFIX, PREC_SUFFIX };
+
+/* Table mapping opcodes into strings for printing operators
+ and precedences of the operators. */
+
+struct op_print
+{
+ char *string;
+ enum exp_opcode opcode;
+ /* Precedence of operator. These values are used only by comparisons. */
+ enum precedence precedence;
+ int right_assoc;
+};
+
+#endif /* PARSER_DEFS_H */
diff --git a/gnu/usr.bin/gdb/gdb/partial-stab.h b/gnu/usr.bin/gdb/gdb/partial-stab.h
new file mode 100644
index 0000000..2f15423
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/partial-stab.h
@@ -0,0 +1,679 @@
+/* Shared code to pre-read a stab (dbx-style), when building a psymtab.
+ Copyright 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994
+ Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* The following need to be defined:
+ SET_NAMESTRING() --Set namestring to name of symbol.
+ CUR_SYMBOL_TYPE --Type code of current symbol.
+ CUR_SYMBOL_VALUE --Value field of current symbol. May be adjusted here.
+ */
+
+/* End of macro definitions, now let's handle them symbols! */
+
+ switch (CUR_SYMBOL_TYPE)
+ {
+ char *p;
+ /*
+ * Standard, external, non-debugger, symbols
+ */
+
+ case N_TEXT | N_EXT:
+ case N_NBTEXT | N_EXT:
+ CUR_SYMBOL_VALUE += ANOFFSET (section_offsets, SECT_OFF_TEXT);
+ goto record_it;
+
+ case N_DATA | N_EXT:
+ case N_NBDATA | N_EXT:
+ CUR_SYMBOL_VALUE += ANOFFSET (section_offsets, SECT_OFF_DATA);
+ goto record_it;
+
+ case N_BSS:
+ case N_BSS | N_EXT:
+ case N_NBBSS | N_EXT:
+ case N_SETV | N_EXT: /* FIXME, is this in BSS? */
+ CUR_SYMBOL_VALUE += ANOFFSET (section_offsets, SECT_OFF_BSS);
+ goto record_it;
+
+ case N_ABS | N_EXT:
+ record_it:
+#ifdef DBXREAD_ONLY
+ SET_NAMESTRING();
+
+ bss_ext_symbol:
+ record_minimal_symbol (namestring, CUR_SYMBOL_VALUE,
+ CUR_SYMBOL_TYPE, objfile); /* Always */
+#endif /* DBXREAD_ONLY */
+ continue;
+
+ /* Standard, local, non-debugger, symbols */
+
+ case N_NBTEXT:
+
+ /* We need to be able to deal with both N_FN or N_TEXT,
+ because we have no way of knowing whether the sys-supplied ld
+ or GNU ld was used to make the executable. Sequents throw
+ in another wrinkle -- they renumbered N_FN. */
+
+ case N_FN:
+ case N_FN_SEQ:
+ case N_TEXT:
+#ifdef DBXREAD_ONLY
+ CUR_SYMBOL_VALUE += ANOFFSET (section_offsets, SECT_OFF_TEXT);
+ SET_NAMESTRING();
+ if ((namestring[0] == '-' && namestring[1] == 'l')
+ || (namestring [(nsl = strlen (namestring)) - 1] == 'o'
+ && namestring [nsl - 2] == '.')
+#ifdef GDB_TARGET_IS_HPPA
+ /* some cooperation from gcc to get around ld stupidity */
+ || (namestring[0] == 'e' && STREQ (namestring, "end_file."))
+#endif
+ )
+ {
+#ifndef GDB_TARGET_IS_HPPA
+ if (objfile -> ei.entry_point < CUR_SYMBOL_VALUE &&
+ objfile -> ei.entry_point >= last_o_file_start)
+ {
+ objfile -> ei.entry_file_lowpc = last_o_file_start;
+ objfile -> ei.entry_file_highpc = CUR_SYMBOL_VALUE;
+ }
+#endif
+ if (past_first_source_file && pst
+ /* The gould NP1 uses low values for .o and -l symbols
+ which are not the address. */
+ && CUR_SYMBOL_VALUE >= pst->textlow)
+ {
+ END_PSYMTAB (pst, psymtab_include_list, includes_used,
+ symnum * symbol_size, CUR_SYMBOL_VALUE,
+ dependency_list, dependencies_used);
+ pst = (struct partial_symtab *) 0;
+ includes_used = 0;
+ dependencies_used = 0;
+ }
+ else
+ past_first_source_file = 1;
+ last_o_file_start = CUR_SYMBOL_VALUE;
+ }
+ else
+ goto record_it;
+#endif /* DBXREAD_ONLY */
+ continue;
+
+ case N_DATA:
+ CUR_SYMBOL_VALUE += ANOFFSET (section_offsets, SECT_OFF_DATA);
+ goto record_it;
+
+ case N_UNDF | N_EXT:
+#ifdef DBXREAD_ONLY
+ if (CUR_SYMBOL_VALUE != 0) {
+ /* This is a "Fortran COMMON" symbol. See if the target
+ environment knows where it has been relocated to. */
+
+ CORE_ADDR reladdr;
+
+ SET_NAMESTRING();
+ if (target_lookup_symbol (namestring, &reladdr)) {
+ continue; /* Error in lookup; ignore symbol for now. */
+ }
+ CUR_SYMBOL_TYPE ^= (N_BSS^N_UNDF); /* Define it as a bss-symbol */
+ CUR_SYMBOL_VALUE = reladdr;
+ goto bss_ext_symbol;
+ }
+#endif /* DBXREAD_ONLY */
+ continue; /* Just undefined, not COMMON */
+
+ case N_UNDF:
+#ifdef DBXREAD_ONLY
+ if (processing_acc_compilation && bufp->n_strx == 1) {
+ /* Deal with relative offsets in the string table
+ used in ELF+STAB under Solaris. If we want to use the
+ n_strx field, which contains the name of the file,
+ we must adjust file_string_table_offset *before* calling
+ SET_NAMESTRING(). */
+ past_first_source_file = 1;
+ file_string_table_offset = next_file_string_table_offset;
+ next_file_string_table_offset =
+ file_string_table_offset + bufp->n_value;
+ if (next_file_string_table_offset < file_string_table_offset)
+ error ("string table offset backs up at %d", symnum);
+ /* FIXME -- replace error() with complaint. */
+ continue;
+ }
+#endif /* DBXREAD_ONLY */
+ continue;
+
+ /* Lots of symbol types we can just ignore. */
+
+ case N_ABS:
+ case N_NBDATA:
+ case N_NBBSS:
+ continue;
+
+ /* Keep going . . .*/
+
+ /*
+ * Special symbol types for GNU
+ */
+ case N_INDR:
+ case N_INDR | N_EXT:
+ case N_SETA:
+ case N_SETA | N_EXT:
+ case N_SETT:
+ case N_SETT | N_EXT:
+ case N_SETD:
+ case N_SETD | N_EXT:
+ case N_SETB:
+ case N_SETB | N_EXT:
+ case N_SETV:
+ continue;
+
+ /*
+ * Debugger symbols
+ */
+
+ case N_SO: {
+ unsigned long valu;
+ static int prev_so_symnum = -10;
+ static int first_so_symnum;
+ char *p;
+
+ valu = CUR_SYMBOL_VALUE + ANOFFSET (section_offsets, SECT_OFF_TEXT);
+
+ past_first_source_file = 1;
+
+ if (prev_so_symnum != symnum - 1)
+ { /* Here if prev stab wasn't N_SO */
+ first_so_symnum = symnum;
+
+ if (pst)
+ {
+ END_PSYMTAB (pst, psymtab_include_list, includes_used,
+ symnum * symbol_size, valu,
+ dependency_list, dependencies_used);
+ pst = (struct partial_symtab *) 0;
+ includes_used = 0;
+ dependencies_used = 0;
+ }
+ }
+
+ prev_so_symnum = symnum;
+
+ /* End the current partial symtab and start a new one */
+
+ SET_NAMESTRING();
+
+ /* Some compilers (including gcc) emit a pair of initial N_SOs.
+ The first one is a directory name; the second the file name.
+ If pst exists, is empty, and has a filename ending in '/',
+ we assume the previous N_SO was a directory name. */
+
+ p = strrchr (namestring, '/');
+ if (p && *(p+1) == '\000')
+ continue; /* Simply ignore directory name SOs */
+
+ /* Some other compilers (C++ ones in particular) emit useless
+ SOs for non-existant .c files. We ignore all subsequent SOs that
+ immediately follow the first. */
+
+ if (!pst)
+ pst = START_PSYMTAB (objfile, section_offsets,
+ namestring, valu,
+ first_so_symnum * symbol_size,
+ objfile -> global_psymbols.next,
+ objfile -> static_psymbols.next);
+ continue;
+ }
+
+ case N_BINCL:
+ {
+#ifdef DBXREAD_ONLY
+ enum language tmp_language;
+ /* Add this bincl to the bincl_list for future EXCLs. No
+ need to save the string; it'll be around until
+ read_dbx_symtab function returns */
+
+ SET_NAMESTRING();
+
+ tmp_language = deduce_language_from_filename (namestring);
+
+ /* Only change the psymtab's language if we've learned
+ something useful (eg. tmp_language is not language_unknown).
+ In addition, to match what start_subfile does, never change
+ from C++ to C. */
+ if (tmp_language != language_unknown
+ && (tmp_language != language_c
+ || psymtab_language != language_cplus))
+ psymtab_language = tmp_language;
+
+ add_bincl_to_list (pst, namestring, CUR_SYMBOL_VALUE);
+
+ /* Mark down an include file in the current psymtab */
+
+ goto record_include_file;
+
+#else /* DBXREAD_ONLY */
+ continue;
+#endif
+ }
+
+ case N_SOL:
+ {
+ enum language tmp_language;
+ /* Mark down an include file in the current psymtab */
+
+ SET_NAMESTRING();
+
+ tmp_language = deduce_language_from_filename (namestring);
+
+ /* Only change the psymtab's language if we've learned
+ something useful (eg. tmp_language is not language_unknown).
+ In addition, to match what start_subfile does, never change
+ from C++ to C. */
+ if (tmp_language != language_unknown
+ && (tmp_language != language_c
+ || psymtab_language != language_cplus))
+ psymtab_language = tmp_language;
+
+ /* In C++, one may expect the same filename to come round many
+ times, when code is coming alternately from the main file
+ and from inline functions in other files. So I check to see
+ if this is a file we've seen before -- either the main
+ source file, or a previously included file.
+
+ This seems to be a lot of time to be spending on N_SOL, but
+ things like "break c-exp.y:435" need to work (I
+ suppose the psymtab_include_list could be hashed or put
+ in a binary tree, if profiling shows this is a major hog). */
+ if (pst && STREQ (namestring, pst->filename))
+ continue;
+ {
+ register int i;
+ for (i = 0; i < includes_used; i++)
+ if (STREQ (namestring, psymtab_include_list[i]))
+ {
+ i = -1;
+ break;
+ }
+ if (i == -1)
+ continue;
+ }
+
+#ifdef DBXREAD_ONLY
+ record_include_file:
+#endif
+
+ psymtab_include_list[includes_used++] = namestring;
+ if (includes_used >= includes_allocated)
+ {
+ char **orig = psymtab_include_list;
+
+ psymtab_include_list = (char **)
+ alloca ((includes_allocated *= 2) *
+ sizeof (char *));
+ memcpy ((PTR)psymtab_include_list, (PTR)orig,
+ includes_used * sizeof (char *));
+ }
+ continue;
+ }
+ case N_LSYM: /* Typedef or automatic variable. */
+ case N_STSYM: /* Data seg var -- static */
+ case N_LCSYM: /* BSS " */
+ case N_ROSYM: /* Read-only data seg var -- static. */
+ case N_NBSTS: /* Gould nobase. */
+ case N_NBLCS: /* symbols. */
+ case N_FUN:
+ case N_GSYM: /* Global (extern) variable; can be
+ data or bss (sigh FIXME). */
+
+ /* Following may probably be ignored; I'll leave them here
+ for now (until I do Pascal and Modula 2 extensions). */
+
+ case N_PC: /* I may or may not need this; I
+ suspect not. */
+ case N_M2C: /* I suspect that I can ignore this here. */
+ case N_SCOPE: /* Same. */
+
+ SET_NAMESTRING();
+
+ p = (char *) strchr (namestring, ':');
+ if (!p)
+ continue; /* Not a debugging symbol. */
+
+
+
+ /* Main processing section for debugging symbols which
+ the initial read through the symbol tables needs to worry
+ about. If we reach this point, the symbol which we are
+ considering is definitely one we are interested in.
+ p must also contain the (valid) index into the namestring
+ which indicates the debugging type symbol. */
+
+ switch (p[1])
+ {
+ case 'S':
+ CUR_SYMBOL_VALUE += ANOFFSET (section_offsets, SECT_OFF_DATA);
+ ADD_PSYMBOL_ADDR_TO_LIST (namestring, p - namestring,
+ VAR_NAMESPACE, LOC_STATIC,
+ objfile->static_psymbols,
+ CUR_SYMBOL_VALUE,
+ psymtab_language, objfile);
+ continue;
+ case 'G':
+ CUR_SYMBOL_VALUE += ANOFFSET (section_offsets, SECT_OFF_DATA);
+ /* The addresses in these entries are reported to be
+ wrong. See the code that reads 'G's for symtabs. */
+ ADD_PSYMBOL_ADDR_TO_LIST (namestring, p - namestring,
+ VAR_NAMESPACE, LOC_STATIC,
+ objfile->global_psymbols,
+ CUR_SYMBOL_VALUE,
+ psymtab_language, objfile);
+ continue;
+
+ case 'T':
+ if (p != namestring) /* a name is there, not just :T... */
+ {
+ ADD_PSYMBOL_TO_LIST (namestring, p - namestring,
+ STRUCT_NAMESPACE, LOC_TYPEDEF,
+ objfile->static_psymbols,
+ CUR_SYMBOL_VALUE,
+ psymtab_language, objfile);
+ if (p[2] == 't')
+ {
+ /* Also a typedef with the same name. */
+ ADD_PSYMBOL_TO_LIST (namestring, p - namestring,
+ VAR_NAMESPACE, LOC_TYPEDEF,
+ objfile->static_psymbols,
+ CUR_SYMBOL_VALUE, psymtab_language,
+ objfile);
+ p += 1;
+ }
+ /* The semantics of C++ state that "struct foo { ... }"
+ also defines a typedef for "foo". Unfortuantely, cfront
+ never makes the typedef when translating from C++ to C.
+ We make the typedef here so that "ptype foo" works as
+ expected for cfront translated code. */
+ else if (psymtab_language == language_cplus)
+ {
+ /* Also a typedef with the same name. */
+ ADD_PSYMBOL_TO_LIST (namestring, p - namestring,
+ VAR_NAMESPACE, LOC_TYPEDEF,
+ objfile->static_psymbols,
+ CUR_SYMBOL_VALUE, psymtab_language,
+ objfile);
+ }
+ }
+ goto check_enum;
+ case 't':
+ if (p != namestring) /* a name is there, not just :T... */
+ {
+ ADD_PSYMBOL_TO_LIST (namestring, p - namestring,
+ VAR_NAMESPACE, LOC_TYPEDEF,
+ objfile->static_psymbols,
+ CUR_SYMBOL_VALUE,
+ psymtab_language, objfile);
+ }
+ check_enum:
+ /* If this is an enumerated type, we need to
+ add all the enum constants to the partial symbol
+ table. This does not cover enums without names, e.g.
+ "enum {a, b} c;" in C, but fortunately those are
+ rare. There is no way for GDB to find those from the
+ enum type without spending too much time on it. Thus
+ to solve this problem, the compiler needs to put out the
+ enum in a nameless type. GCC2 does this. */
+
+ /* We are looking for something of the form
+ <name> ":" ("t" | "T") [<number> "="] "e"
+ {<constant> ":" <value> ","} ";". */
+
+ /* Skip over the colon and the 't' or 'T'. */
+ p += 2;
+ /* This type may be given a number. Also, numbers can come
+ in pairs like (0,26). Skip over it. */
+ while ((*p >= '0' && *p <= '9')
+ || *p == '(' || *p == ',' || *p == ')'
+ || *p == '=')
+ p++;
+
+ if (*p++ == 'e')
+ {
+ /* We have found an enumerated type. */
+ /* According to comments in read_enum_type
+ a comma could end it instead of a semicolon.
+ I don't know where that happens.
+ Accept either. */
+ while (*p && *p != ';' && *p != ',')
+ {
+ char *q;
+
+ /* Check for and handle cretinous dbx symbol name
+ continuation! */
+ if (*p == '\\' || (*p == '?' && p[1] == '\0'))
+ p = next_symbol_text ();
+
+ /* Point to the character after the name
+ of the enum constant. */
+ for (q = p; *q && *q != ':'; q++)
+ ;
+ /* Note that the value doesn't matter for
+ enum constants in psymtabs, just in symtabs. */
+ ADD_PSYMBOL_TO_LIST (p, q - p,
+ VAR_NAMESPACE, LOC_CONST,
+ objfile->static_psymbols, 0,
+ psymtab_language, objfile);
+ /* Point past the name. */
+ p = q;
+ /* Skip over the value. */
+ while (*p && *p != ',')
+ p++;
+ /* Advance past the comma. */
+ if (*p)
+ p++;
+ }
+ }
+ continue;
+ case 'c':
+ /* Constant, e.g. from "const" in Pascal. */
+ ADD_PSYMBOL_TO_LIST (namestring, p - namestring,
+ VAR_NAMESPACE, LOC_CONST,
+ objfile->static_psymbols, CUR_SYMBOL_VALUE,
+ psymtab_language, objfile);
+ continue;
+
+ case 'f':
+ CUR_SYMBOL_VALUE += ANOFFSET (section_offsets, SECT_OFF_TEXT);
+#ifdef DBXREAD_ONLY
+ /* Kludges for ELF/STABS with Sun ACC */
+ last_function_name = namestring;
+ /* Do not fix textlow==0 for .o or NLM files, as 0 is a legit
+ value for the bottom of the text seg in those cases. */
+ if (pst && pst->textlow == 0 && !symfile_relocatable)
+ pst->textlow = CUR_SYMBOL_VALUE;
+#if 0
+ if (startup_file_end == 0)
+ startup_file_end = CUR_SYMBOL_VALUE;
+#endif
+ /* End kludge. */
+#endif /* DBXREAD_ONLY */
+ ADD_PSYMBOL_TO_LIST (namestring, p - namestring,
+ VAR_NAMESPACE, LOC_BLOCK,
+ objfile->static_psymbols, CUR_SYMBOL_VALUE,
+ psymtab_language, objfile);
+ continue;
+
+ /* Global functions were ignored here, but now they
+ are put into the global psymtab like one would expect.
+ They're also in the minimal symbol table. */
+ case 'F':
+ CUR_SYMBOL_VALUE += ANOFFSET (section_offsets, SECT_OFF_TEXT);
+#ifdef DBXREAD_ONLY
+ /* Kludges for ELF/STABS with Sun ACC */
+ last_function_name = namestring;
+ /* Do not fix textlow==0 for .o or NLM files, as 0 is a legit
+ value for the bottom of the text seg in those cases. */
+ if (pst && pst->textlow == 0 && !symfile_relocatable)
+ pst->textlow = CUR_SYMBOL_VALUE;
+#if 0
+ if (startup_file_end == 0)
+ startup_file_end = CUR_SYMBOL_VALUE;
+#endif
+ /* End kludge. */
+#endif /* DBXREAD_ONLY */
+ ADD_PSYMBOL_TO_LIST (namestring, p - namestring,
+ VAR_NAMESPACE, LOC_BLOCK,
+ objfile->global_psymbols, CUR_SYMBOL_VALUE,
+ psymtab_language, objfile);
+ continue;
+
+ /* Two things show up here (hopefully); static symbols of
+ local scope (static used inside braces) or extensions
+ of structure symbols. We can ignore both. */
+ case 'V':
+ case '(':
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ continue;
+
+ case ':':
+ /* It is a C++ nested symbol. We don't need to record it
+ (I don't think); if we try to look up foo::bar::baz,
+ then symbols for the symtab containing foo should get
+ read in, I think. */
+ /* Someone says sun cc puts out symbols like
+ /foo/baz/maclib::/usr/local/bin/maclib,
+ which would get here with a symbol type of ':'. */
+ continue;
+
+ default:
+ /* Unexpected symbol descriptor. The second and subsequent stabs
+ of a continued stab can show up here. The question is
+ whether they ever can mimic a normal stab--it would be
+ nice if not, since we certainly don't want to spend the
+ time searching to the end of every string looking for
+ a backslash. */
+
+ complain (&unknown_symchar_complaint, p[1]);
+
+ /* Ignore it; perhaps it is an extension that we don't
+ know about. */
+ continue;
+ }
+
+ case N_EXCL:
+#ifdef DBXREAD_ONLY
+
+ SET_NAMESTRING();
+
+ /* Find the corresponding bincl and mark that psymtab on the
+ psymtab dependency list */
+ {
+ struct partial_symtab *needed_pst =
+ find_corresponding_bincl_psymtab (namestring, CUR_SYMBOL_VALUE);
+
+ /* If this include file was defined earlier in this file,
+ leave it alone. */
+ if (needed_pst == pst) continue;
+
+ if (needed_pst)
+ {
+ int i;
+ int found = 0;
+
+ for (i = 0; i < dependencies_used; i++)
+ if (dependency_list[i] == needed_pst)
+ {
+ found = 1;
+ break;
+ }
+
+ /* If it's already in the list, skip the rest. */
+ if (found) continue;
+
+ dependency_list[dependencies_used++] = needed_pst;
+ if (dependencies_used >= dependencies_allocated)
+ {
+ struct partial_symtab **orig = dependency_list;
+ dependency_list =
+ (struct partial_symtab **)
+ alloca ((dependencies_allocated *= 2)
+ * sizeof (struct partial_symtab *));
+ memcpy ((PTR)dependency_list, (PTR)orig,
+ (dependencies_used
+ * sizeof (struct partial_symtab *)));
+#ifdef DEBUG_INFO
+ fprintf_unfiltered (gdb_stderr, "Had to reallocate dependency list.\n");
+ fprintf_unfiltered (gdb_stderr, "New dependencies allocated: %d\n",
+ dependencies_allocated);
+#endif
+ }
+ }
+ else
+ error ("Invalid symbol data: \"repeated\" header file not previously seen, at symtab pos %d.",
+ symnum);
+ }
+#endif /* DBXREAD_ONLY */
+ continue;
+
+ case N_RBRAC:
+#ifdef HANDLE_RBRAC
+ HANDLE_RBRAC(CUR_SYMBOL_VALUE);
+ continue;
+#endif
+ case N_EINCL:
+ case N_DSLINE:
+ case N_BSLINE:
+ case N_SSYM: /* Claim: Structure or union element.
+ Hopefully, I can ignore this. */
+ case N_ENTRY: /* Alternate entry point; can ignore. */
+ case N_MAIN: /* Can definitely ignore this. */
+ case N_CATCH: /* These are GNU C++ extensions */
+ case N_EHDECL: /* that can safely be ignored here. */
+ case N_LENG:
+ case N_BCOMM:
+ case N_ECOMM:
+ case N_ECOML:
+ case N_FNAME:
+ case N_SLINE:
+ case N_RSYM:
+ case N_PSYM:
+ case N_LBRAC:
+ case N_NSYMS: /* Ultrix 4.0: symbol count */
+ case N_DEFD: /* GNU Modula-2 */
+
+ case N_OBJ: /* useless types from Solaris */
+ case N_OPT:
+ case N_ENDM:
+ /* These symbols aren't interesting; don't worry about them */
+
+ continue;
+
+ default:
+ /* If we haven't found it yet, ignore it. It's probably some
+ new type we don't know about yet. */
+ complain (&unknown_symtype_complaint,
+ local_hex_string (CUR_SYMBOL_TYPE));
+ continue;
+ }
diff --git a/gnu/usr.bin/gdb/gdb/printcmd.c b/gnu/usr.bin/gdb/gdb/printcmd.c
new file mode 100644
index 0000000..1f81bc9
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/printcmd.c
@@ -0,0 +1,2220 @@
+/* Print values for GNU debugger GDB.
+ Copyright 1986, 1987, 1988, 1989, 1990, 1991, 1993, 1994
+ Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "defs.h"
+#include <string.h>
+#include <varargs.h>
+#include "frame.h"
+#include "symtab.h"
+#include "gdbtypes.h"
+#include "value.h"
+#include "language.h"
+#include "expression.h"
+#include "gdbcore.h"
+#include "gdbcmd.h"
+#include "target.h"
+#include "breakpoint.h"
+#include "demangle.h"
+#include "valprint.h"
+#include "annotate.h"
+
+extern int asm_demangle; /* Whether to demangle syms in asm printouts */
+extern int addressprint; /* Whether to print hex addresses in HLL " */
+
+struct format_data
+{
+ int count;
+ char format;
+ char size;
+};
+
+/* Last specified output format. */
+
+static char last_format = 'x';
+
+/* Last specified examination size. 'b', 'h', 'w' or `q'. */
+
+static char last_size = 'w';
+
+/* Default address to examine next. */
+
+static CORE_ADDR next_address;
+
+/* Last address examined. */
+
+static CORE_ADDR last_examine_address;
+
+/* Contents of last address examined.
+ This is not valid past the end of the `x' command! */
+
+static value_ptr last_examine_value;
+
+/* Largest offset between a symbolic value and an address, that will be
+ printed as `0x1234 <symbol+offset>'. */
+
+static unsigned int max_symbolic_offset = UINT_MAX;
+
+/* Append the source filename and linenumber of the symbol when
+ printing a symbolic value as `<symbol at filename:linenum>' if set. */
+static int print_symbol_filename = 0;
+
+/* Number of auto-display expression currently being displayed.
+ So that we can disable it if we get an error or a signal within it.
+ -1 when not doing one. */
+
+int current_display_number;
+
+/* Flag to low-level print routines that this value is being printed
+ in an epoch window. We'd like to pass this as a parameter, but
+ every routine would need to take it. Perhaps we can encapsulate
+ this in the I/O stream once we have GNU stdio. */
+
+int inspect_it = 0;
+
+struct display
+{
+ /* Chain link to next auto-display item. */
+ struct display *next;
+ /* Expression to be evaluated and displayed. */
+ struct expression *exp;
+ /* Item number of this auto-display item. */
+ int number;
+ /* Display format specified. */
+ struct format_data format;
+ /* Innermost block required by this expression when evaluated */
+ struct block *block;
+ /* Status of this display (enabled or disabled) */
+ enum enable status;
+};
+
+/* Chain of expressions whose values should be displayed
+ automatically each time the program stops. */
+
+static struct display *display_chain;
+
+static int display_number;
+
+/* Prototypes for local functions */
+
+static void
+delete_display PARAMS ((int));
+
+static void
+enable_display PARAMS ((char *, int));
+
+static void
+disable_display_command PARAMS ((char *, int));
+
+static void
+disassemble_command PARAMS ((char *, int));
+
+static void
+printf_command PARAMS ((char *, int));
+
+static void
+print_frame_nameless_args PARAMS ((struct frame_info *, long, int, int,
+ GDB_FILE *));
+
+static void
+display_info PARAMS ((char *, int));
+
+static void
+do_one_display PARAMS ((struct display *));
+
+static void
+undisplay_command PARAMS ((char *, int));
+
+static void
+free_display PARAMS ((struct display *));
+
+static void
+display_command PARAMS ((char *, int));
+
+static void
+x_command PARAMS ((char *, int));
+
+static void
+address_info PARAMS ((char *, int));
+
+static void
+set_command PARAMS ((char *, int));
+
+static void
+output_command PARAMS ((char *, int));
+
+static void
+call_command PARAMS ((char *, int));
+
+static void
+inspect_command PARAMS ((char *, int));
+
+static void
+print_command PARAMS ((char *, int));
+
+static void
+print_command_1 PARAMS ((char *, int, int));
+
+static void
+validate_format PARAMS ((struct format_data, char *));
+
+static void
+do_examine PARAMS ((struct format_data, CORE_ADDR));
+
+static void
+print_formatted PARAMS ((value_ptr, int, int));
+
+static struct format_data
+decode_format PARAMS ((char **, int, int));
+
+
+/* Decode a format specification. *STRING_PTR should point to it.
+ OFORMAT and OSIZE are used as defaults for the format and size
+ if none are given in the format specification.
+ If OSIZE is zero, then the size field of the returned value
+ should be set only if a size is explicitly specified by the
+ user.
+ The structure returned describes all the data
+ found in the specification. In addition, *STRING_PTR is advanced
+ past the specification and past all whitespace following it. */
+
+static struct format_data
+decode_format (string_ptr, oformat, osize)
+ char **string_ptr;
+ int oformat;
+ int osize;
+{
+ struct format_data val;
+ register char *p = *string_ptr;
+
+ val.format = '?';
+ val.size = '?';
+ val.count = 1;
+
+ if (*p >= '0' && *p <= '9')
+ val.count = atoi (p);
+ while (*p >= '0' && *p <= '9') p++;
+
+ /* Now process size or format letters that follow. */
+
+ while (1)
+ {
+ if (*p == 'b' || *p == 'h' || *p == 'w' || *p == 'g')
+ val.size = *p++;
+ else if (*p >= 'a' && *p <= 'z')
+ val.format = *p++;
+ else
+ break;
+ }
+
+ while (*p == ' ' || *p == '\t') p++;
+ *string_ptr = p;
+
+ /* Set defaults for format and size if not specified. */
+ if (val.format == '?')
+ {
+ if (val.size == '?')
+ {
+ /* Neither has been specified. */
+ val.format = oformat;
+ val.size = osize;
+ }
+ else
+ /* If a size is specified, any format makes a reasonable
+ default except 'i'. */
+ val.format = oformat == 'i' ? 'x' : oformat;
+ }
+ else if (val.size == '?')
+ switch (val.format)
+ {
+ case 'a':
+ case 's':
+ /* Pick the appropriate size for an address. */
+ if (TARGET_PTR_BIT == 64)
+ val.size = osize ? 'g' : osize;
+ else if (TARGET_PTR_BIT == 32)
+ val.size = osize ? 'w' : osize;
+ else if (TARGET_PTR_BIT == 16)
+ val.size = osize ? 'h' : osize;
+ else
+ /* Bad value for TARGET_PTR_BIT */
+ abort ();
+ break;
+ case 'f':
+ /* Floating point has to be word or giantword. */
+ if (osize == 'w' || osize == 'g')
+ val.size = osize;
+ else
+ /* Default it to giantword if the last used size is not
+ appropriate. */
+ val.size = osize ? 'g' : osize;
+ break;
+ case 'c':
+ /* Characters default to one byte. */
+ val.size = osize ? 'b' : osize;
+ break;
+ default:
+ /* The default is the size most recently specified. */
+ val.size = osize;
+ }
+
+ return val;
+}
+
+/* Print value VAL on gdb_stdout according to FORMAT, a letter or 0.
+ Do not end with a newline.
+ 0 means print VAL according to its own type.
+ SIZE is the letter for the size of datum being printed.
+ This is used to pad hex numbers so they line up. */
+
+static void
+print_formatted (val, format, size)
+ register value_ptr val;
+ register int format;
+ int size;
+{
+ int len = TYPE_LENGTH (VALUE_TYPE (val));
+
+ if (VALUE_LVAL (val) == lval_memory)
+ next_address = VALUE_ADDRESS (val) + len;
+
+ switch (format)
+ {
+ case 's':
+ next_address = VALUE_ADDRESS (val)
+ + value_print (value_addr (val), gdb_stdout, format, Val_pretty_default);
+ break;
+
+ case 'i':
+ /* The old comment says
+ "Force output out, print_insn not using _filtered".
+ I'm not completely sure what that means, I suspect most print_insn
+ now do use _filtered, so I guess it's obsolete. */
+ /* We often wrap here if there are long symbolic names. */
+ wrap_here (" ");
+ next_address = VALUE_ADDRESS (val)
+ + print_insn (VALUE_ADDRESS (val), gdb_stdout);
+ break;
+
+ default:
+ if (format == 0
+ || TYPE_CODE (VALUE_TYPE (val)) == TYPE_CODE_ARRAY
+ || TYPE_CODE (VALUE_TYPE (val)) == TYPE_CODE_STRING
+ || TYPE_CODE (VALUE_TYPE (val)) == TYPE_CODE_STRUCT
+ || TYPE_CODE (VALUE_TYPE (val)) == TYPE_CODE_UNION
+ || VALUE_REPEATED (val))
+ value_print (val, gdb_stdout, format, Val_pretty_default);
+ else
+ print_scalar_formatted (VALUE_CONTENTS (val), VALUE_TYPE (val),
+ format, size, gdb_stdout);
+ }
+}
+
+/* Print a scalar of data of type TYPE, pointed to in GDB by VALADDR,
+ according to letters FORMAT and SIZE on STREAM.
+ FORMAT may not be zero. Formats s and i are not supported at this level.
+
+ This is how the elements of an array or structure are printed
+ with a format. */
+
+void
+print_scalar_formatted (valaddr, type, format, size, stream)
+ char *valaddr;
+ struct type *type;
+ int format;
+ int size;
+ GDB_FILE *stream;
+{
+ LONGEST val_long;
+ int len = TYPE_LENGTH (type);
+
+ if (len > sizeof (LONGEST)
+ && (format == 't'
+ || format == 'c'
+ || format == 'o'
+ || format == 'u'
+ || format == 'd'
+ || format == 'x'))
+ {
+ /* We can't print it normally, but we can print it in hex.
+ Printing it in the wrong radix is more useful than saying
+ "use /x, you dummy". */
+ /* FIXME: we could also do octal or binary if that was the
+ desired format. */
+ /* FIXME: we should be using the size field to give us a minimum
+ field width to print. */
+ val_print_type_code_int (type, valaddr, stream);
+ return;
+ }
+
+ if (format != 'f')
+ val_long = unpack_long (type, valaddr);
+
+ /* If we are printing it as unsigned, truncate it in case it is actually
+ a negative signed value (e.g. "print/u (short)-1" should print 65535
+ (if shorts are 16 bits) instead of 4294967295). */
+ if (format != 'd')
+ {
+ if (len < sizeof (LONGEST))
+ val_long &= ((LONGEST) 1 << HOST_CHAR_BIT * len) - 1;
+ }
+
+ switch (format)
+ {
+ case 'x':
+ if (!size)
+ {
+ /* no size specified, like in print. Print varying # of digits. */
+ print_longest (stream, 'x', 1, val_long);
+ }
+ else
+ switch (size)
+ {
+ case 'b':
+ case 'h':
+ case 'w':
+ case 'g':
+ print_longest (stream, size, 1, val_long);
+ break;
+ default:
+ error ("Undefined output size \"%c\".", size);
+ }
+ break;
+
+ case 'd':
+ print_longest (stream, 'd', 1, val_long);
+ break;
+
+ case 'u':
+ print_longest (stream, 'u', 0, val_long);
+ break;
+
+ case 'o':
+ if (val_long)
+ print_longest (stream, 'o', 1, val_long);
+ else
+ fprintf_filtered (stream, "0");
+ break;
+
+ case 'a':
+ print_address (unpack_pointer (type, valaddr), stream);
+ break;
+
+ case 'c':
+ value_print (value_from_longest (builtin_type_char, val_long), stream, 0,
+ Val_pretty_default);
+ break;
+
+ case 'f':
+ if (len == sizeof (float))
+ type = builtin_type_float;
+ else if (len == sizeof (double))
+ type = builtin_type_double;
+ print_floating (valaddr, type, stream);
+ break;
+
+ case 0:
+ abort ();
+
+ case 't':
+ /* Binary; 't' stands for "two". */
+ {
+ char bits[8*(sizeof val_long) + 1];
+ char *cp = bits;
+ int width;
+
+ if (!size)
+ width = 8*(sizeof val_long);
+ else
+ switch (size)
+ {
+ case 'b':
+ width = 8;
+ break;
+ case 'h':
+ width = 16;
+ break;
+ case 'w':
+ width = 32;
+ break;
+ case 'g':
+ width = 64;
+ break;
+ default:
+ error ("Undefined output size \"%c\".", size);
+ }
+
+ bits[width] = '\0';
+ while (width-- > 0)
+ {
+ bits[width] = (val_long & 1) ? '1' : '0';
+ val_long >>= 1;
+ }
+ if (!size)
+ {
+ while (*cp && *cp == '0')
+ cp++;
+ if (*cp == '\0')
+ cp--;
+ }
+ fprintf_filtered (stream, local_binary_format_prefix());
+ fprintf_filtered (stream, cp);
+ fprintf_filtered (stream, local_binary_format_suffix());
+ }
+ break;
+
+ default:
+ error ("Undefined output format \"%c\".", format);
+ }
+}
+
+/* Specify default address for `x' command.
+ `info lines' uses this. */
+
+void
+set_next_address (addr)
+ CORE_ADDR addr;
+{
+ next_address = addr;
+
+ /* Make address available to the user as $_. */
+ set_internalvar (lookup_internalvar ("_"),
+ value_from_longest (lookup_pointer_type (builtin_type_void),
+ (LONGEST) addr));
+}
+
+/* Optionally print address ADDR symbolically as <SYMBOL+OFFSET> on STREAM,
+ after LEADIN. Print nothing if no symbolic name is found nearby.
+ Optionally also print source file and line number, if available.
+ DO_DEMANGLE controls whether to print a symbol in its native "raw" form,
+ or to interpret it as a possible C++ name and convert it back to source
+ form. However note that DO_DEMANGLE can be overridden by the specific
+ settings of the demangle and asm_demangle variables. */
+
+void
+print_address_symbolic (addr, stream, do_demangle, leadin)
+ CORE_ADDR addr;
+ GDB_FILE *stream;
+ int do_demangle;
+ char *leadin;
+{
+ struct minimal_symbol *msymbol;
+ struct symbol *symbol;
+ struct symtab *symtab = 0;
+ CORE_ADDR name_location = 0;
+ char *name = "";
+
+ /* First try to find the address in the symbol table, then
+ in the minsyms. Take the closest one. */
+
+ /* This is defective in the sense that it only finds text symbols. So
+ really this is kind of pointless--we should make sure that the
+ minimal symbols have everything we need (by changing that we could
+ save some memory, but for many debug format--ELF/DWARF or
+ anything/stabs--it would be inconvenient to eliminate those minimal
+ symbols anyway). */
+ symbol = find_pc_function (addr);
+ if (symbol)
+ name_location = BLOCK_START (SYMBOL_BLOCK_VALUE (symbol));
+
+ if (symbol)
+ {
+ if (do_demangle)
+ name = SYMBOL_SOURCE_NAME (symbol);
+ else
+ name = SYMBOL_LINKAGE_NAME (symbol);
+ }
+
+ msymbol = lookup_minimal_symbol_by_pc (addr);
+ if (msymbol != NULL)
+ {
+ if (SYMBOL_VALUE_ADDRESS (msymbol) > name_location || symbol == NULL)
+ {
+ /* The msymbol is closer to the address than the symbol;
+ use the msymbol instead. */
+ symbol = 0;
+ symtab = 0;
+ name_location = SYMBOL_VALUE_ADDRESS (msymbol);
+ if (do_demangle)
+ name = SYMBOL_SOURCE_NAME (msymbol);
+ else
+ name = SYMBOL_LINKAGE_NAME (msymbol);
+ }
+ }
+ if (symbol == NULL && msymbol == NULL)
+ return;
+
+ /* If the nearest symbol is too far away, don't print anything symbolic. */
+
+ /* For when CORE_ADDR is larger than unsigned int, we do math in
+ CORE_ADDR. But when we detect unsigned wraparound in the
+ CORE_ADDR math, we ignore this test and print the offset,
+ because addr+max_symbolic_offset has wrapped through the end
+ of the address space back to the beginning, giving bogus comparison. */
+ if (addr > name_location + max_symbolic_offset
+ && name_location + max_symbolic_offset > name_location)
+ return;
+
+ fputs_filtered (leadin, stream);
+ fputs_filtered ("<", stream);
+ fputs_filtered (name, stream);
+ if (addr != name_location)
+ fprintf_filtered (stream, "+%u", (unsigned int)(addr - name_location));
+
+ /* Append source filename and line number if desired. Give specific
+ line # of this addr, if we have it; else line # of the nearest symbol. */
+ if (print_symbol_filename)
+ {
+ struct symtab_and_line sal;
+
+ sal = find_pc_line (addr, 0);
+ if (sal.symtab)
+ fprintf_filtered (stream, " at %s:%d", sal.symtab->filename, sal.line);
+ else if (symtab && symbol && symbol->line)
+ fprintf_filtered (stream, " at %s:%d", symtab->filename, symbol->line);
+ else if (symtab)
+ fprintf_filtered (stream, " in %s", symtab->filename);
+ }
+ fputs_filtered (">", stream);
+}
+
+/* Print address ADDR on STREAM. USE_LOCAL means the same thing as for
+ print_longest. */
+void
+print_address_numeric (addr, use_local, stream)
+ CORE_ADDR addr;
+ int use_local;
+ GDB_FILE *stream;
+{
+ /* This assumes a CORE_ADDR can fit in a LONGEST. Probably a safe
+ assumption. We pass use_local but I'm not completely sure whether
+ that is correct. When (if ever) should we *not* use_local? */
+ print_longest (stream, 'x', 1, (unsigned LONGEST) addr);
+}
+
+/* Print address ADDR symbolically on STREAM.
+ First print it as a number. Then perhaps print
+ <SYMBOL + OFFSET> after the number. */
+
+void
+print_address (addr, stream)
+ CORE_ADDR addr;
+ GDB_FILE *stream;
+{
+ print_address_numeric (addr, 1, stream);
+ print_address_symbolic (addr, stream, asm_demangle, " ");
+}
+
+/* Print address ADDR symbolically on STREAM. Parameter DEMANGLE
+ controls whether to print the symbolic name "raw" or demangled.
+ Global setting "addressprint" controls whether to print hex address
+ or not. */
+
+void
+print_address_demangle (addr, stream, do_demangle)
+ CORE_ADDR addr;
+ GDB_FILE *stream;
+ int do_demangle;
+{
+ if (addr == 0)
+ {
+ fprintf_filtered (stream, "0");
+ }
+ else if (addressprint)
+ {
+ print_address_numeric (addr, 1, stream);
+ print_address_symbolic (addr, stream, do_demangle, " ");
+ }
+ else
+ {
+ print_address_symbolic (addr, stream, do_demangle, "");
+ }
+}
+
+
+/* These are the types that $__ will get after an examine command of one
+ of these sizes. */
+
+static struct type *examine_b_type;
+static struct type *examine_h_type;
+static struct type *examine_w_type;
+static struct type *examine_g_type;
+
+/* Examine data at address ADDR in format FMT.
+ Fetch it from memory and print on gdb_stdout. */
+
+static void
+do_examine (fmt, addr)
+ struct format_data fmt;
+ CORE_ADDR addr;
+{
+ register char format = 0;
+ register char size;
+ register int count = 1;
+ struct type *val_type = NULL;
+ register int i;
+ register int maxelts;
+
+ format = fmt.format;
+ size = fmt.size;
+ count = fmt.count;
+ next_address = addr;
+
+ /* String or instruction format implies fetch single bytes
+ regardless of the specified size. */
+ if (format == 's' || format == 'i')
+ size = 'b';
+
+ if (size == 'b')
+ val_type = examine_b_type;
+ else if (size == 'h')
+ val_type = examine_h_type;
+ else if (size == 'w')
+ val_type = examine_w_type;
+ else if (size == 'g')
+ val_type = examine_g_type;
+
+ maxelts = 8;
+ if (size == 'w')
+ maxelts = 4;
+ if (size == 'g')
+ maxelts = 2;
+ if (format == 's' || format == 'i')
+ maxelts = 1;
+
+ /* Print as many objects as specified in COUNT, at most maxelts per line,
+ with the address of the next one at the start of each line. */
+
+ while (count > 0)
+ {
+ print_address (next_address, gdb_stdout);
+ printf_filtered (":");
+ for (i = maxelts;
+ i > 0 && count > 0;
+ i--, count--)
+ {
+ printf_filtered ("\t");
+ /* Note that print_formatted sets next_address for the next
+ object. */
+ last_examine_address = next_address;
+ last_examine_value = value_at (val_type, next_address);
+ print_formatted (last_examine_value, format, size);
+ }
+ printf_filtered ("\n");
+ gdb_flush (gdb_stdout);
+ }
+}
+
+static void
+validate_format (fmt, cmdname)
+ struct format_data fmt;
+ char *cmdname;
+{
+ if (fmt.size != 0)
+ error ("Size letters are meaningless in \"%s\" command.", cmdname);
+ if (fmt.count != 1)
+ error ("Item count other than 1 is meaningless in \"%s\" command.",
+ cmdname);
+ if (fmt.format == 'i' || fmt.format == 's')
+ error ("Format letter \"%c\" is meaningless in \"%s\" command.",
+ fmt.format, cmdname);
+}
+
+/* Evaluate string EXP as an expression in the current language and
+ print the resulting value. EXP may contain a format specifier as the
+ first argument ("/x myvar" for example, to print myvar in hex).
+ */
+
+static void
+print_command_1 (exp, inspect, voidprint)
+ char *exp;
+ int inspect;
+ int voidprint;
+{
+ struct expression *expr;
+ register struct cleanup *old_chain = 0;
+ register char format = 0;
+ register value_ptr val;
+ struct format_data fmt;
+ int cleanup = 0;
+
+ /* Pass inspect flag to the rest of the print routines in a global (sigh). */
+ inspect_it = inspect;
+
+ if (exp && *exp == '/')
+ {
+ exp++;
+ fmt = decode_format (&exp, last_format, 0);
+ validate_format (fmt, "print");
+ last_format = format = fmt.format;
+ }
+ else
+ {
+ fmt.count = 1;
+ fmt.format = 0;
+ fmt.size = 0;
+ }
+
+ if (exp && *exp)
+ {
+ extern int objectprint;
+ struct type *type;
+ expr = parse_expression (exp);
+ old_chain = make_cleanup (free_current_contents, &expr);
+ cleanup = 1;
+ val = evaluate_expression (expr);
+
+ /* C++: figure out what type we actually want to print it as. */
+ type = VALUE_TYPE (val);
+
+ if (objectprint
+ && ( TYPE_CODE (type) == TYPE_CODE_PTR
+ || TYPE_CODE (type) == TYPE_CODE_REF)
+ && ( TYPE_CODE (TYPE_TARGET_TYPE (type)) == TYPE_CODE_STRUCT
+ || TYPE_CODE (TYPE_TARGET_TYPE (type)) == TYPE_CODE_UNION))
+ {
+ value_ptr v;
+
+ v = value_from_vtable_info (val, TYPE_TARGET_TYPE (type));
+ if (v != 0)
+ {
+ val = v;
+ type = VALUE_TYPE (val);
+ }
+ }
+ }
+ else
+ val = access_value_history (0);
+
+ if (voidprint || (val && VALUE_TYPE (val) &&
+ TYPE_CODE (VALUE_TYPE (val)) != TYPE_CODE_VOID))
+ {
+ int histindex = record_latest_value (val);
+
+ if (histindex >= 0)
+ annotate_value_history_begin (histindex, VALUE_TYPE (val));
+ else
+ annotate_value_begin (VALUE_TYPE (val));
+
+ if (inspect)
+ printf_unfiltered ("\031(gdb-makebuffer \"%s\" %d '(\"", exp, histindex);
+ else
+ if (histindex >= 0) printf_filtered ("$%d = ", histindex);
+
+ if (histindex >= 0)
+ annotate_value_history_value ();
+
+ print_formatted (val, format, fmt.size);
+ printf_filtered ("\n");
+
+ if (histindex >= 0)
+ annotate_value_history_end ();
+ else
+ annotate_value_end ();
+
+ if (inspect)
+ printf_unfiltered("\") )\030");
+ }
+
+ if (cleanup)
+ do_cleanups (old_chain);
+ inspect_it = 0; /* Reset print routines to normal */
+}
+
+/* ARGSUSED */
+static void
+print_command (exp, from_tty)
+ char *exp;
+ int from_tty;
+{
+ print_command_1 (exp, 0, 1);
+}
+
+/* Same as print, except in epoch, it gets its own window */
+/* ARGSUSED */
+static void
+inspect_command (exp, from_tty)
+ char *exp;
+ int from_tty;
+{
+ extern int epoch_interface;
+
+ print_command_1 (exp, epoch_interface, 1);
+}
+
+/* Same as print, except it doesn't print void results. */
+/* ARGSUSED */
+static void
+call_command (exp, from_tty)
+ char *exp;
+ int from_tty;
+{
+ print_command_1 (exp, 0, 0);
+}
+
+/* ARGSUSED */
+static void
+output_command (exp, from_tty)
+ char *exp;
+ int from_tty;
+{
+ struct expression *expr;
+ register struct cleanup *old_chain;
+ register char format = 0;
+ register value_ptr val;
+ struct format_data fmt;
+
+ if (exp && *exp == '/')
+ {
+ exp++;
+ fmt = decode_format (&exp, 0, 0);
+ validate_format (fmt, "output");
+ format = fmt.format;
+ }
+
+ expr = parse_expression (exp);
+ old_chain = make_cleanup (free_current_contents, &expr);
+
+ val = evaluate_expression (expr);
+
+ annotate_value_begin (VALUE_TYPE (val));
+
+ print_formatted (val, format, fmt.size);
+
+ annotate_value_end ();
+
+ do_cleanups (old_chain);
+}
+
+/* ARGSUSED */
+static void
+set_command (exp, from_tty)
+ char *exp;
+ int from_tty;
+{
+ struct expression *expr = parse_expression (exp);
+ register struct cleanup *old_chain
+ = make_cleanup (free_current_contents, &expr);
+ evaluate_expression (expr);
+ do_cleanups (old_chain);
+}
+
+/* ARGSUSED */
+static void
+address_info (exp, from_tty)
+ char *exp;
+ int from_tty;
+{
+ register struct symbol *sym;
+ register struct minimal_symbol *msymbol;
+ register long val;
+ register long basereg;
+ int is_a_field_of_this; /* C++: lookup_symbol sets this to nonzero
+ if exp is a field of `this'. */
+
+ if (exp == 0)
+ error ("Argument required.");
+
+ sym = lookup_symbol (exp, get_selected_block (), VAR_NAMESPACE,
+ &is_a_field_of_this, (struct symtab **)NULL);
+ if (sym == NULL)
+ {
+ if (is_a_field_of_this)
+ {
+ printf_filtered ("Symbol \"");
+ fprintf_symbol_filtered (gdb_stdout, exp,
+ current_language->la_language, DMGL_ANSI);
+ printf_filtered ("\" is a field of the local class variable `this'\n");
+ return;
+ }
+
+ msymbol = lookup_minimal_symbol (exp, (struct objfile *) NULL);
+
+ if (msymbol != NULL)
+ {
+ printf_filtered ("Symbol \"");
+ fprintf_symbol_filtered (gdb_stdout, exp,
+ current_language->la_language, DMGL_ANSI);
+ printf_filtered ("\" is at ");
+ print_address_numeric (SYMBOL_VALUE_ADDRESS (msymbol), 1,
+ gdb_stdout);
+ printf_filtered (" in a file compiled without debugging.\n");
+ }
+ else
+ error ("No symbol \"%s\" in current context.", exp);
+ return;
+ }
+
+ printf_filtered ("Symbol \"");
+ fprintf_symbol_filtered (gdb_stdout, SYMBOL_NAME (sym),
+ current_language->la_language, DMGL_ANSI);
+ printf_filtered ("\" is ", SYMBOL_NAME (sym));
+ val = SYMBOL_VALUE (sym);
+ basereg = SYMBOL_BASEREG (sym);
+
+ switch (SYMBOL_CLASS (sym))
+ {
+ case LOC_CONST:
+ case LOC_CONST_BYTES:
+ printf_filtered ("constant");
+ break;
+
+ case LOC_LABEL:
+ printf_filtered ("a label at address ");
+ print_address_numeric (SYMBOL_VALUE_ADDRESS (sym), 1, gdb_stdout);
+ break;
+
+ case LOC_REGISTER:
+ printf_filtered ("a variable in register %s", reg_names[val]);
+ break;
+
+ case LOC_STATIC:
+ printf_filtered ("static storage at address ");
+ print_address_numeric (SYMBOL_VALUE_ADDRESS (sym), 1, gdb_stdout);
+ break;
+
+ case LOC_REGPARM:
+ printf_filtered ("an argument in register %s", reg_names[val]);
+ break;
+
+ case LOC_REGPARM_ADDR:
+ printf_filtered ("address of an argument in register %s", reg_names[val]);
+ break;
+
+ case LOC_ARG:
+ printf_filtered ("an argument at offset %ld", val);
+ break;
+
+ case LOC_LOCAL_ARG:
+ printf_filtered ("an argument at frame offset %ld", val);
+ break;
+
+ case LOC_LOCAL:
+ printf_filtered ("a local variable at frame offset %ld", val);
+ break;
+
+ case LOC_REF_ARG:
+ printf_filtered ("a reference argument at offset %ld", val);
+ break;
+
+ case LOC_BASEREG:
+ printf_filtered ("a variable at offset %ld from register %s",
+ val, reg_names[basereg]);
+ break;
+
+ case LOC_BASEREG_ARG:
+ printf_filtered ("an argument at offset %ld from register %s",
+ val, reg_names[basereg]);
+ break;
+
+ case LOC_TYPEDEF:
+ printf_filtered ("a typedef");
+ break;
+
+ case LOC_BLOCK:
+ printf_filtered ("a function at address ");
+ print_address_numeric (BLOCK_START (SYMBOL_BLOCK_VALUE (sym)), 1,
+ gdb_stdout);
+ break;
+
+ case LOC_OPTIMIZED_OUT:
+ printf_filtered ("optimized out");
+ break;
+
+ default:
+ printf_filtered ("of unknown (botched) type");
+ break;
+ }
+ printf_filtered (".\n");
+}
+
+static void
+x_command (exp, from_tty)
+ char *exp;
+ int from_tty;
+{
+ struct expression *expr;
+ struct format_data fmt;
+ struct cleanup *old_chain;
+ struct value *val;
+
+ fmt.format = last_format;
+ fmt.size = last_size;
+ fmt.count = 1;
+
+ if (exp && *exp == '/')
+ {
+ exp++;
+ fmt = decode_format (&exp, last_format, last_size);
+ }
+
+ /* If we have an expression, evaluate it and use it as the address. */
+
+ if (exp != 0 && *exp != 0)
+ {
+ expr = parse_expression (exp);
+ /* Cause expression not to be there any more
+ if this command is repeated with Newline.
+ But don't clobber a user-defined command's definition. */
+ if (from_tty)
+ *exp = 0;
+ old_chain = make_cleanup (free_current_contents, &expr);
+ val = evaluate_expression (expr);
+ if (TYPE_CODE (VALUE_TYPE (val)) == TYPE_CODE_REF)
+ val = value_ind (val);
+ /* In rvalue contexts, such as this, functions are coerced into
+ pointers to functions. This makes "x/i main" work. */
+ if (/* last_format == 'i'
+ && */ TYPE_CODE (VALUE_TYPE (val)) == TYPE_CODE_FUNC
+ && VALUE_LVAL (val) == lval_memory)
+ next_address = VALUE_ADDRESS (val);
+ else
+ next_address = value_as_pointer (val);
+ do_cleanups (old_chain);
+ }
+
+ do_examine (fmt, next_address);
+
+ /* If the examine succeeds, we remember its size and format for next time. */
+ last_size = fmt.size;
+ last_format = fmt.format;
+
+ /* Set a couple of internal variables if appropriate. */
+ if (last_examine_value)
+ {
+ /* Make last address examined available to the user as $_. Use
+ the correct pointer type. */
+ set_internalvar (lookup_internalvar ("_"),
+ value_from_longest (
+ lookup_pointer_type (VALUE_TYPE (last_examine_value)),
+ (LONGEST) last_examine_address));
+
+ /* Make contents of last address examined available to the user as $__.*/
+ set_internalvar (lookup_internalvar ("__"), last_examine_value);
+ }
+}
+
+
+/* Add an expression to the auto-display chain.
+ Specify the expression. */
+
+static void
+display_command (exp, from_tty)
+ char *exp;
+ int from_tty;
+{
+ struct format_data fmt;
+ register struct expression *expr;
+ register struct display *new;
+
+ if (exp == 0)
+ {
+ do_displays ();
+ return;
+ }
+
+ if (*exp == '/')
+ {
+ exp++;
+ fmt = decode_format (&exp, 0, 0);
+ if (fmt.size && fmt.format == 0)
+ fmt.format = 'x';
+ if (fmt.format == 'i' || fmt.format == 's')
+ fmt.size = 'b';
+ }
+ else
+ {
+ fmt.format = 0;
+ fmt.size = 0;
+ fmt.count = 0;
+ }
+
+ innermost_block = 0;
+ expr = parse_expression (exp);
+
+ new = (struct display *) xmalloc (sizeof (struct display));
+
+ new->exp = expr;
+ new->block = innermost_block;
+ new->next = display_chain;
+ new->number = ++display_number;
+ new->format = fmt;
+ new->status = enabled;
+ display_chain = new;
+
+ if (from_tty && target_has_execution)
+ do_one_display (new);
+
+ dont_repeat ();
+}
+
+static void
+free_display (d)
+ struct display *d;
+{
+ free ((PTR)d->exp);
+ free ((PTR)d);
+}
+
+/* Clear out the display_chain.
+ Done when new symtabs are loaded, since this invalidates
+ the types stored in many expressions. */
+
+void
+clear_displays ()
+{
+ register struct display *d;
+
+ while ((d = display_chain) != NULL)
+ {
+ free ((PTR)d->exp);
+ display_chain = d->next;
+ free ((PTR)d);
+ }
+}
+
+/* Delete the auto-display number NUM. */
+
+static void
+delete_display (num)
+ int num;
+{
+ register struct display *d1, *d;
+
+ if (!display_chain)
+ error ("No display number %d.", num);
+
+ if (display_chain->number == num)
+ {
+ d1 = display_chain;
+ display_chain = d1->next;
+ free_display (d1);
+ }
+ else
+ for (d = display_chain; ; d = d->next)
+ {
+ if (d->next == 0)
+ error ("No display number %d.", num);
+ if (d->next->number == num)
+ {
+ d1 = d->next;
+ d->next = d1->next;
+ free_display (d1);
+ break;
+ }
+ }
+}
+
+/* Delete some values from the auto-display chain.
+ Specify the element numbers. */
+
+static void
+undisplay_command (args, from_tty)
+ char *args;
+ int from_tty;
+{
+ register char *p = args;
+ register char *p1;
+ register int num;
+
+ if (args == 0)
+ {
+ if (query ("Delete all auto-display expressions? "))
+ clear_displays ();
+ dont_repeat ();
+ return;
+ }
+
+ while (*p)
+ {
+ p1 = p;
+ while (*p1 >= '0' && *p1 <= '9') p1++;
+ if (*p1 && *p1 != ' ' && *p1 != '\t')
+ error ("Arguments must be display numbers.");
+
+ num = atoi (p);
+
+ delete_display (num);
+
+ p = p1;
+ while (*p == ' ' || *p == '\t') p++;
+ }
+ dont_repeat ();
+}
+
+/* Display a single auto-display.
+ Do nothing if the display cannot be printed in the current context,
+ or if the display is disabled. */
+
+static void
+do_one_display (d)
+ struct display *d;
+{
+ int within_current_scope;
+
+ if (d->status == disabled)
+ return;
+
+ if (d->block)
+ within_current_scope = contained_in (get_selected_block (), d->block);
+ else
+ within_current_scope = 1;
+ if (!within_current_scope)
+ return;
+
+ current_display_number = d->number;
+
+ annotate_display_begin ();
+ printf_filtered ("%d", d->number);
+ annotate_display_number_end ();
+ printf_filtered (": ");
+ if (d->format.size)
+ {
+ CORE_ADDR addr;
+
+ annotate_display_format ();
+
+ printf_filtered ("x/");
+ if (d->format.count != 1)
+ printf_filtered ("%d", d->format.count);
+ printf_filtered ("%c", d->format.format);
+ if (d->format.format != 'i' && d->format.format != 's')
+ printf_filtered ("%c", d->format.size);
+ printf_filtered (" ");
+
+ annotate_display_expression ();
+
+ print_expression (d->exp, gdb_stdout);
+ annotate_display_expression_end ();
+
+ if (d->format.count != 1)
+ printf_filtered ("\n");
+ else
+ printf_filtered (" ");
+
+ addr = value_as_pointer (evaluate_expression (d->exp));
+ if (d->format.format == 'i')
+ addr = ADDR_BITS_REMOVE (addr);
+
+ annotate_display_value ();
+
+ do_examine (d->format, addr);
+ }
+ else
+ {
+ annotate_display_format ();
+
+ if (d->format.format)
+ printf_filtered ("/%c ", d->format.format);
+
+ annotate_display_expression ();
+
+ print_expression (d->exp, gdb_stdout);
+ annotate_display_expression_end ();
+
+ printf_filtered (" = ");
+
+ annotate_display_expression ();
+
+ print_formatted (evaluate_expression (d->exp),
+ d->format.format, d->format.size);
+ printf_filtered ("\n");
+ }
+
+ annotate_display_end ();
+
+ gdb_flush (gdb_stdout);
+ current_display_number = -1;
+}
+
+/* Display all of the values on the auto-display chain which can be
+ evaluated in the current scope. */
+
+void
+do_displays ()
+{
+ register struct display *d;
+
+ for (d = display_chain; d; d = d->next)
+ do_one_display (d);
+}
+
+/* Delete the auto-display which we were in the process of displaying.
+ This is done when there is an error or a signal. */
+
+void
+disable_display (num)
+ int num;
+{
+ register struct display *d;
+
+ for (d = display_chain; d; d = d->next)
+ if (d->number == num)
+ {
+ d->status = disabled;
+ return;
+ }
+ printf_unfiltered ("No display number %d.\n", num);
+}
+
+void
+disable_current_display ()
+{
+ if (current_display_number >= 0)
+ {
+ disable_display (current_display_number);
+ fprintf_unfiltered (gdb_stderr, "Disabling display %d to avoid infinite recursion.\n",
+ current_display_number);
+ }
+ current_display_number = -1;
+}
+
+static void
+display_info (ignore, from_tty)
+ char *ignore;
+ int from_tty;
+{
+ register struct display *d;
+
+ if (!display_chain)
+ printf_unfiltered ("There are no auto-display expressions now.\n");
+ else
+ printf_filtered ("Auto-display expressions now in effect:\n\
+Num Enb Expression\n");
+
+ for (d = display_chain; d; d = d->next)
+ {
+ printf_filtered ("%d: %c ", d->number, "ny"[(int)d->status]);
+ if (d->format.size)
+ printf_filtered ("/%d%c%c ", d->format.count, d->format.size,
+ d->format.format);
+ else if (d->format.format)
+ printf_filtered ("/%c ", d->format.format);
+ print_expression (d->exp, gdb_stdout);
+ if (d->block && !contained_in (get_selected_block (), d->block))
+ printf_filtered (" (cannot be evaluated in the current context)");
+ printf_filtered ("\n");
+ gdb_flush (gdb_stdout);
+ }
+}
+
+static void
+enable_display (args, from_tty)
+ char *args;
+ int from_tty;
+{
+ register char *p = args;
+ register char *p1;
+ register int num;
+ register struct display *d;
+
+ if (p == 0)
+ {
+ for (d = display_chain; d; d = d->next)
+ d->status = enabled;
+ }
+ else
+ while (*p)
+ {
+ p1 = p;
+ while (*p1 >= '0' && *p1 <= '9')
+ p1++;
+ if (*p1 && *p1 != ' ' && *p1 != '\t')
+ error ("Arguments must be display numbers.");
+
+ num = atoi (p);
+
+ for (d = display_chain; d; d = d->next)
+ if (d->number == num)
+ {
+ d->status = enabled;
+ goto win;
+ }
+ printf_unfiltered ("No display number %d.\n", num);
+ win:
+ p = p1;
+ while (*p == ' ' || *p == '\t')
+ p++;
+ }
+}
+
+/* ARGSUSED */
+static void
+disable_display_command (args, from_tty)
+ char *args;
+ int from_tty;
+{
+ register char *p = args;
+ register char *p1;
+ register struct display *d;
+
+ if (p == 0)
+ {
+ for (d = display_chain; d; d = d->next)
+ d->status = disabled;
+ }
+ else
+ while (*p)
+ {
+ p1 = p;
+ while (*p1 >= '0' && *p1 <= '9')
+ p1++;
+ if (*p1 && *p1 != ' ' && *p1 != '\t')
+ error ("Arguments must be display numbers.");
+
+ disable_display (atoi (p));
+
+ p = p1;
+ while (*p == ' ' || *p == '\t')
+ p++;
+ }
+}
+
+
+/* Print the value in stack frame FRAME of a variable
+ specified by a struct symbol. */
+
+void
+print_variable_value (var, frame, stream)
+ struct symbol *var;
+ FRAME frame;
+ GDB_FILE *stream;
+{
+ value_ptr val = read_var_value (var, frame);
+ value_print (val, stream, 0, Val_pretty_default);
+}
+
+/* Print the arguments of a stack frame, given the function FUNC
+ running in that frame (as a symbol), the info on the frame,
+ and the number of args according to the stack frame (or -1 if unknown). */
+
+/* References here and elsewhere to "number of args according to the
+ stack frame" appear in all cases to refer to "number of ints of args
+ according to the stack frame". At least for VAX, i386, isi. */
+
+void
+print_frame_args (func, fi, num, stream)
+ struct symbol *func;
+ struct frame_info *fi;
+ int num;
+ GDB_FILE *stream;
+{
+ struct block *b = NULL;
+ int nsyms = 0;
+ int first = 1;
+ register int i;
+ register struct symbol *sym;
+ register value_ptr val;
+ /* Offset of next stack argument beyond the one we have seen that is
+ at the highest offset.
+ -1 if we haven't come to a stack argument yet. */
+ long highest_offset = -1;
+ int arg_size;
+ /* Number of ints of arguments that we have printed so far. */
+ int args_printed = 0;
+
+ if (func)
+ {
+ b = SYMBOL_BLOCK_VALUE (func);
+ nsyms = BLOCK_NSYMS (b);
+ }
+
+ for (i = 0; i < nsyms; i++)
+ {
+ QUIT;
+ sym = BLOCK_SYM (b, i);
+
+ /* Keep track of the highest stack argument offset seen, and
+ skip over any kinds of symbols we don't care about. */
+
+ switch (SYMBOL_CLASS (sym)) {
+ case LOC_ARG:
+ case LOC_REF_ARG:
+ {
+ long current_offset = SYMBOL_VALUE (sym);
+
+ arg_size = TYPE_LENGTH (SYMBOL_TYPE (sym));
+
+ /* Compute address of next argument by adding the size of
+ this argument and rounding to an int boundary. */
+ current_offset
+ = ((current_offset + arg_size + sizeof (int) - 1)
+ & ~(sizeof (int) - 1));
+
+ /* If this is the highest offset seen yet, set highest_offset. */
+ if (highest_offset == -1
+ || (current_offset > highest_offset))
+ highest_offset = current_offset;
+
+ /* Add the number of ints we're about to print to args_printed. */
+ args_printed += (arg_size + sizeof (int) - 1) / sizeof (int);
+ }
+
+ /* We care about types of symbols, but don't need to keep track of
+ stack offsets in them. */
+ case LOC_REGPARM:
+ case LOC_REGPARM_ADDR:
+ case LOC_LOCAL_ARG:
+ case LOC_BASEREG_ARG:
+ break;
+
+ /* Other types of symbols we just skip over. */
+ default:
+ continue;
+ }
+
+ /* We have to look up the symbol because arguments can have
+ two entries (one a parameter, one a local) and the one we
+ want is the local, which lookup_symbol will find for us.
+ This includes gcc1 (not gcc2) on the sparc when passing a
+ small structure and gcc2 when the argument type is float
+ and it is passed as a double and converted to float by
+ the prologue (in the latter case the type of the LOC_ARG
+ symbol is double and the type of the LOC_LOCAL symbol is
+ float). */
+ /* But if the parameter name is null, don't try it.
+ Null parameter names occur on the RS/6000, for traceback tables.
+ FIXME, should we even print them? */
+
+ if (*SYMBOL_NAME (sym))
+ {
+ struct symbol *nsym;
+ nsym = lookup_symbol
+ (SYMBOL_NAME (sym),
+ b, VAR_NAMESPACE, (int *)NULL, (struct symtab **)NULL);
+ if (SYMBOL_CLASS (nsym) == LOC_REGISTER)
+ {
+ /* There is a LOC_ARG/LOC_REGISTER pair. This means that
+ it was passed on the stack and loaded into a register,
+ or passed in a register and stored in a stack slot.
+ GDB 3.x used the LOC_ARG; GDB 4.0-4.11 used the LOC_REGISTER.
+
+ Reasons for using the LOC_ARG:
+ (1) because find_saved_registers may be slow for remote
+ debugging,
+ (2) because registers are often re-used and stack slots
+ rarely (never?) are. Therefore using the stack slot is
+ much less likely to print garbage.
+
+ Reasons why we might want to use the LOC_REGISTER:
+ (1) So that the backtrace prints the same value as
+ "print foo". I see no compelling reason why this needs
+ to be the case; having the backtrace print the value which
+ was passed in, and "print foo" print the value as modified
+ within the called function, makes perfect sense to me.
+
+ Additional note: It might be nice if "info args" displayed
+ both values.
+ One more note: There is a case with sparc structure passing
+ where we need to use the LOC_REGISTER, but this is dealt with
+ by creating a single LOC_REGPARM in symbol reading. */
+
+ /* Leave sym (the LOC_ARG) alone. */
+ ;
+ }
+ else
+ sym = nsym;
+ }
+
+ /* Print the current arg. */
+ if (! first)
+ fprintf_filtered (stream, ", ");
+ wrap_here (" ");
+
+ annotate_arg_begin ();
+
+ fprintf_symbol_filtered (stream, SYMBOL_SOURCE_NAME (sym),
+ SYMBOL_LANGUAGE (sym), DMGL_PARAMS | DMGL_ANSI);
+ annotate_arg_name_end ();
+ fputs_filtered ("=", stream);
+
+ /* Avoid value_print because it will deref ref parameters. We just
+ want to print their addresses. Print ??? for args whose address
+ we do not know. We pass 2 as "recurse" to val_print because our
+ standard indentation here is 4 spaces, and val_print indents
+ 2 for each recurse. */
+ val = read_var_value (sym, FRAME_INFO_ID (fi));
+
+ annotate_arg_value (val == NULL ? NULL : VALUE_TYPE (val));
+
+ if (val)
+ val_print (VALUE_TYPE (val), VALUE_CONTENTS (val), VALUE_ADDRESS (val),
+ stream, 0, 0, 2, Val_no_prettyprint);
+ else
+ fputs_filtered ("???", stream);
+
+ annotate_arg_end ();
+
+ first = 0;
+ }
+
+ /* Don't print nameless args in situations where we don't know
+ enough about the stack to find them. */
+ if (num != -1)
+ {
+ long start;
+
+ if (highest_offset == -1)
+ start = FRAME_ARGS_SKIP;
+ else
+ start = highest_offset;
+
+ print_frame_nameless_args (fi, start, num - args_printed,
+ first, stream);
+ }
+}
+
+/* Print nameless args on STREAM.
+ FI is the frameinfo for this frame, START is the offset
+ of the first nameless arg, and NUM is the number of nameless args to
+ print. FIRST is nonzero if this is the first argument (not just
+ the first nameless arg). */
+static void
+print_frame_nameless_args (fi, start, num, first, stream)
+ struct frame_info *fi;
+ long start;
+ int num;
+ int first;
+ GDB_FILE *stream;
+{
+ int i;
+ CORE_ADDR argsaddr;
+ long arg_value;
+
+ for (i = 0; i < num; i++)
+ {
+ QUIT;
+#ifdef NAMELESS_ARG_VALUE
+ NAMELESS_ARG_VALUE (fi, start, &arg_value);
+#else
+ argsaddr = FRAME_ARGS_ADDRESS (fi);
+ if (!argsaddr)
+ return;
+
+ arg_value = read_memory_integer (argsaddr + start, sizeof (int));
+#endif
+
+ if (!first)
+ fprintf_filtered (stream, ", ");
+
+#ifdef PRINT_NAMELESS_INTEGER
+ PRINT_NAMELESS_INTEGER (stream, arg_value);
+#else
+#ifdef PRINT_TYPELESS_INTEGER
+ PRINT_TYPELESS_INTEGER (stream, builtin_type_int, (LONGEST) arg_value);
+#else
+ fprintf_filtered (stream, "%d", arg_value);
+#endif /* PRINT_TYPELESS_INTEGER */
+#endif /* PRINT_NAMELESS_INTEGER */
+ first = 0;
+ start += sizeof (int);
+ }
+}
+
+/* ARGSUSED */
+static void
+printf_command (arg, from_tty)
+ char *arg;
+ int from_tty;
+{
+ register char *f;
+ register char *s = arg;
+ char *string;
+ value_ptr *val_args;
+ char *substrings;
+ char *current_substring;
+ int nargs = 0;
+ int allocated_args = 20;
+ struct cleanup *old_cleanups;
+
+ val_args = (value_ptr *) xmalloc (allocated_args * sizeof (value_ptr));
+ old_cleanups = make_cleanup (free_current_contents, &val_args);
+
+ if (s == 0)
+ error_no_arg ("format-control string and values to print");
+
+ /* Skip white space before format string */
+ while (*s == ' ' || *s == '\t') s++;
+
+ /* A format string should follow, enveloped in double quotes */
+ if (*s++ != '"')
+ error ("Bad format string, missing '\"'.");
+
+ /* Parse the format-control string and copy it into the string STRING,
+ processing some kinds of escape sequence. */
+
+ f = string = (char *) alloca (strlen (s) + 1);
+
+ while (*s != '"')
+ {
+ int c = *s++;
+ switch (c)
+ {
+ case '\0':
+ error ("Bad format string, non-terminated '\"'.");
+
+ case '\\':
+ switch (c = *s++)
+ {
+ case '\\':
+ *f++ = '\\';
+ break;
+ case 'a':
+#ifdef __STDC__
+ *f++ = '\a';
+#else
+ *f++ = '\007'; /* Bell */
+#endif
+ break;
+ case 'b':
+ *f++ = '\b';
+ break;
+ case 'f':
+ *f++ = '\f';
+ break;
+ case 'n':
+ *f++ = '\n';
+ break;
+ case 'r':
+ *f++ = '\r';
+ break;
+ case 't':
+ *f++ = '\t';
+ break;
+ case 'v':
+ *f++ = '\v';
+ break;
+ case '"':
+ *f++ = '"';
+ break;
+ default:
+ /* ??? TODO: handle other escape sequences */
+ error ("Unrecognized escape character \\%c in format string.",
+ c);
+ }
+ break;
+
+ default:
+ *f++ = c;
+ }
+ }
+
+ /* Skip over " and following space and comma. */
+ s++;
+ *f++ = '\0';
+ while (*s == ' ' || *s == '\t') s++;
+
+ if (*s != ',' && *s != 0)
+ error ("Invalid argument syntax");
+
+ if (*s == ',') s++;
+ while (*s == ' ' || *s == '\t') s++;
+
+ /* Need extra space for the '\0's. Doubling the size is sufficient. */
+ substrings = alloca (strlen (string) * 2);
+ current_substring = substrings;
+
+ {
+ /* Now scan the string for %-specs and see what kinds of args they want.
+ argclass[I] classifies the %-specs so we can give printf_filtered
+ something of the right size. */
+
+ enum argclass {no_arg, int_arg, string_arg, double_arg, long_long_arg};
+ enum argclass *argclass;
+ enum argclass this_argclass;
+ char *last_arg;
+ int nargs_wanted;
+ int lcount;
+ int i;
+
+ argclass = (enum argclass *) alloca (strlen (s) * sizeof *argclass);
+ nargs_wanted = 0;
+ f = string;
+ last_arg = string;
+ while (*f)
+ if (*f++ == '%')
+ {
+ lcount = 0;
+ while (strchr ("0123456789.hlL-+ #", *f))
+ {
+ if (*f == 'l' || *f == 'L')
+ lcount++;
+ f++;
+ }
+ switch (*f)
+ {
+ case 's':
+ this_argclass = string_arg;
+ break;
+
+ case 'e':
+ case 'f':
+ case 'g':
+ this_argclass = double_arg;
+ break;
+
+ case '*':
+ error ("`*' not supported for precision or width in printf");
+
+ case 'n':
+ error ("Format specifier `n' not supported in printf");
+
+ case '%':
+ this_argclass = no_arg;
+ break;
+
+ default:
+ if (lcount > 1)
+ this_argclass = long_long_arg;
+ else
+ this_argclass = int_arg;
+ break;
+ }
+ f++;
+ if (this_argclass != no_arg)
+ {
+ strncpy (current_substring, last_arg, f - last_arg);
+ current_substring += f - last_arg;
+ *current_substring++ = '\0';
+ last_arg = f;
+ argclass[nargs_wanted++] = this_argclass;
+ }
+ }
+
+ /* Now, parse all arguments and evaluate them.
+ Store the VALUEs in VAL_ARGS. */
+
+ while (*s != '\0')
+ {
+ char *s1;
+ if (nargs == allocated_args)
+ val_args = (value_ptr *) xrealloc ((char *) val_args,
+ (allocated_args *= 2)
+ * sizeof (value_ptr));
+ s1 = s;
+ val_args[nargs] = parse_to_comma_and_eval (&s1);
+
+ /* If format string wants a float, unchecked-convert the value to
+ floating point of the same size */
+
+ if (argclass[nargs] == double_arg)
+ {
+ if (TYPE_LENGTH (VALUE_TYPE (val_args[nargs])) == sizeof (float))
+ VALUE_TYPE (val_args[nargs]) = builtin_type_float;
+ if (TYPE_LENGTH (VALUE_TYPE (val_args[nargs])) == sizeof (double))
+ VALUE_TYPE (val_args[nargs]) = builtin_type_double;
+ }
+ nargs++;
+ s = s1;
+ if (*s == ',')
+ s++;
+ }
+
+ if (nargs != nargs_wanted)
+ error ("Wrong number of arguments for specified format-string");
+
+ /* Now actually print them. */
+ current_substring = substrings;
+ for (i = 0; i < nargs; i++)
+ {
+ switch (argclass[i])
+ {
+ case string_arg:
+ {
+ char *str;
+ CORE_ADDR tem;
+ int j;
+ tem = value_as_pointer (val_args[i]);
+
+ /* This is a %s argument. Find the length of the string. */
+ for (j = 0; ; j++)
+ {
+ char c;
+ QUIT;
+ read_memory (tem + j, &c, 1);
+ if (c == 0)
+ break;
+ }
+
+ /* Copy the string contents into a string inside GDB. */
+ str = (char *) alloca (j + 1);
+ read_memory (tem, str, j);
+ str[j] = 0;
+
+ printf_filtered (current_substring, str);
+ }
+ break;
+ case double_arg:
+ {
+ double val = value_as_double (val_args[i]);
+ printf_filtered (current_substring, val);
+ break;
+ }
+ case long_long_arg:
+#if defined (CC_HAS_LONG_LONG) && defined (PRINTF_HAS_LONG_LONG)
+ {
+ long long val = value_as_long (val_args[i]);
+ printf_filtered (current_substring, val);
+ break;
+ }
+#else
+ error ("long long not supported in printf");
+#endif
+ case int_arg:
+ {
+ /* FIXME: there should be separate int_arg and long_arg. */
+ long val = value_as_long (val_args[i]);
+ printf_filtered (current_substring, val);
+ break;
+ }
+ default:
+ error ("internal error in printf_command");
+ }
+ /* Skip to the next substring. */
+ current_substring += strlen (current_substring) + 1;
+ }
+ /* Print the portion of the format string after the last argument. */
+ printf_filtered (last_arg);
+ }
+ do_cleanups (old_cleanups);
+}
+
+/* Dump a specified section of assembly code. With no command line
+ arguments, this command will dump the assembly code for the
+ function surrounding the pc value in the selected frame. With one
+ argument, it will dump the assembly code surrounding that pc value.
+ Two arguments are interpeted as bounds within which to dump
+ assembly. */
+
+/* ARGSUSED */
+static void
+disassemble_command (arg, from_tty)
+ char *arg;
+ int from_tty;
+{
+ CORE_ADDR low, high;
+ char *name;
+ CORE_ADDR pc;
+ char *space_index;
+
+ name = NULL;
+ if (!arg)
+ {
+ if (!selected_frame)
+ error ("No frame selected.\n");
+
+ pc = get_frame_pc (selected_frame);
+ if (find_pc_partial_function (pc, &name, &low, &high) == 0)
+ error ("No function contains program counter for selected frame.\n");
+ }
+ else if (!(space_index = (char *) strchr (arg, ' ')))
+ {
+ /* One argument. */
+ pc = parse_and_eval_address (arg);
+ if (find_pc_partial_function (pc, &name, &low, &high) == 0)
+ error ("No function contains specified address.\n");
+ }
+ else
+ {
+ /* Two arguments. */
+ *space_index = '\0';
+ low = parse_and_eval_address (arg);
+ high = parse_and_eval_address (space_index + 1);
+ }
+
+ printf_filtered ("Dump of assembler code ");
+ if (name != NULL)
+ {
+ printf_filtered ("for function %s:\n", name);
+ }
+ else
+ {
+ printf_filtered ("from ");
+ print_address_numeric (low, 1, gdb_stdout);
+ printf_filtered (" to ");
+ print_address_numeric (high, 1, gdb_stdout);
+ printf_filtered (":\n");
+ }
+
+ /* Dump the specified range. */
+ for (pc = low; pc < high; )
+ {
+ QUIT;
+ print_address (pc, gdb_stdout);
+ printf_filtered (":\t");
+ /* We often wrap here if there are long symbolic names. */
+ wrap_here (" ");
+ pc += print_insn (pc, gdb_stdout);
+ printf_filtered ("\n");
+ }
+ printf_filtered ("End of assembler dump.\n");
+ gdb_flush (gdb_stdout);
+}
+
+
+void
+_initialize_printcmd ()
+{
+ current_display_number = -1;
+
+ add_info ("address", address_info,
+ "Describe where variable VAR is stored.");
+
+ add_com ("x", class_vars, x_command,
+ "Examine memory: x/FMT ADDRESS.\n\
+ADDRESS is an expression for the memory address to examine.\n\
+FMT is a repeat count followed by a format letter and a size letter.\n\
+Format letters are o(octal), x(hex), d(decimal), u(unsigned decimal),\n\
+ t(binary), f(float), a(address), i(instruction), c(char) and s(string).\n\
+Size letters are b(byte), h(halfword), w(word), g(giant, 8 bytes).\n\
+The specified number of objects of the specified size are printed\n\
+according to the format.\n\n\
+Defaults for format and size letters are those previously used.\n\
+Default count is 1. Default address is following last thing printed\n\
+with this command or \"print\".");
+
+ add_com ("disassemble", class_vars, disassemble_command,
+ "Disassemble a specified section of memory.\n\
+Default is the function surrounding the pc of the selected frame.\n\
+With a single argument, the function surrounding that address is dumped.\n\
+Two arguments are taken as a range of memory to dump.");
+
+#if 0
+ add_com ("whereis", class_vars, whereis_command,
+ "Print line number and file of definition of variable.");
+#endif
+
+ add_info ("display", display_info,
+ "Expressions to display when program stops, with code numbers.");
+
+ add_cmd ("undisplay", class_vars, undisplay_command,
+ "Cancel some expressions to be displayed when program stops.\n\
+Arguments are the code numbers of the expressions to stop displaying.\n\
+No argument means cancel all automatic-display expressions.\n\
+\"delete display\" has the same effect as this command.\n\
+Do \"info display\" to see current list of code numbers.",
+ &cmdlist);
+
+ add_com ("display", class_vars, display_command,
+ "Print value of expression EXP each time the program stops.\n\
+/FMT may be used before EXP as in the \"print\" command.\n\
+/FMT \"i\" or \"s\" or including a size-letter is allowed,\n\
+as in the \"x\" command, and then EXP is used to get the address to examine\n\
+and examining is done as in the \"x\" command.\n\n\
+With no argument, display all currently requested auto-display expressions.\n\
+Use \"undisplay\" to cancel display requests previously made.");
+
+ add_cmd ("display", class_vars, enable_display,
+ "Enable some expressions to be displayed when program stops.\n\
+Arguments are the code numbers of the expressions to resume displaying.\n\
+No argument means enable all automatic-display expressions.\n\
+Do \"info display\" to see current list of code numbers.", &enablelist);
+
+ add_cmd ("display", class_vars, disable_display_command,
+ "Disable some expressions to be displayed when program stops.\n\
+Arguments are the code numbers of the expressions to stop displaying.\n\
+No argument means disable all automatic-display expressions.\n\
+Do \"info display\" to see current list of code numbers.", &disablelist);
+
+ add_cmd ("display", class_vars, undisplay_command,
+ "Cancel some expressions to be displayed when program stops.\n\
+Arguments are the code numbers of the expressions to stop displaying.\n\
+No argument means cancel all automatic-display expressions.\n\
+Do \"info display\" to see current list of code numbers.", &deletelist);
+
+ add_com ("printf", class_vars, printf_command,
+ "printf \"printf format string\", arg1, arg2, arg3, ..., argn\n\
+This is useful for formatted output in user-defined commands.");
+ add_com ("output", class_vars, output_command,
+ "Like \"print\" but don't put in value history and don't print newline.\n\
+This is useful in user-defined commands.");
+
+ add_prefix_cmd ("set", class_vars, set_command,
+"Evaluate expression EXP and assign result to variable VAR, using assignment\n\
+syntax appropriate for the current language (VAR = EXP or VAR := EXP for\n\
+example). VAR may be a debugger \"convenience\" variable (names starting\n\
+with $), a register (a few standard names starting with $), or an actual\n\
+variable in the program being debugged. EXP is any valid expression.\n\
+Use \"set variable\" for variables with names identical to set subcommands.\n\
+\nWith a subcommand, this command modifies parts of the gdb environment.\n\
+You can see these environment settings with the \"show\" command.",
+ &setlist, "set ", 1, &cmdlist);
+
+ /* "call" is the same as "set", but handy for dbx users to call fns. */
+ add_com ("call", class_vars, call_command,
+ "Call a function in the program.\n\
+The argument is the function name and arguments, in the notation of the\n\
+current working language. The result is printed and saved in the value\n\
+history, if it is not void.");
+
+ add_cmd ("variable", class_vars, set_command,
+"Evaluate expression EXP and assign result to variable VAR, using assignment\n\
+syntax appropriate for the current language (VAR = EXP or VAR := EXP for\n\
+example). VAR may be a debugger \"convenience\" variable (names starting\n\
+with $), a register (a few standard names starting with $), or an actual\n\
+variable in the program being debugged. EXP is any valid expression.\n\
+This may usually be abbreviated to simply \"set\".",
+ &setlist);
+
+ add_com ("print", class_vars, print_command,
+ concat ("Print value of expression EXP.\n\
+Variables accessible are those of the lexical environment of the selected\n\
+stack frame, plus all those whose scope is global or an entire file.\n\
+\n\
+$NUM gets previous value number NUM. $ and $$ are the last two values.\n\
+$$NUM refers to NUM'th value back from the last one.\n\
+Names starting with $ refer to registers (with the values they would have\n\
+if the program were to return to the stack frame now selected, restoring\n\
+all registers saved by frames farther in) or else to debugger\n\
+\"convenience\" variables (any such name not a known register).\n\
+Use assignment expressions to give values to convenience variables.\n",
+ "\n\
+{TYPE}ADREXP refers to a datum of data type TYPE, located at address ADREXP.\n\
+@ is a binary operator for treating consecutive data objects\n\
+anywhere in memory as an array. FOO@NUM gives an array whose first\n\
+element is FOO, whose second element is stored in the space following\n\
+where FOO is stored, etc. FOO must be an expression whose value\n\
+resides in memory.\n",
+ "\n\
+EXP may be preceded with /FMT, where FMT is a format letter\n\
+but no count or size letter (see \"x\" command).", NULL));
+ add_com_alias ("p", "print", class_vars, 1);
+
+ add_com ("inspect", class_vars, inspect_command,
+"Same as \"print\" command, except that if you are running in the epoch\n\
+environment, the value is printed in its own window.");
+
+ add_show_from_set (
+ add_set_cmd ("max-symbolic-offset", no_class, var_uinteger,
+ (char *)&max_symbolic_offset,
+ "Set the largest offset that will be printed in <symbol+1234> form.",
+ &setprintlist),
+ &showprintlist);
+ add_show_from_set (
+ add_set_cmd ("symbol-filename", no_class, var_boolean,
+ (char *)&print_symbol_filename,
+ "Set printing of source filename and line number with <symbol>.",
+ &setprintlist),
+ &showprintlist);
+
+ examine_b_type = init_type (TYPE_CODE_INT, 1, 0, NULL, NULL);
+ examine_h_type = init_type (TYPE_CODE_INT, 2, 0, NULL, NULL);
+ examine_w_type = init_type (TYPE_CODE_INT, 4, 0, NULL, NULL);
+ examine_g_type = init_type (TYPE_CODE_INT, 8, 0, NULL, NULL);
+}
diff --git a/gnu/usr.bin/gdb/gdb/remote-utils.c b/gnu/usr.bin/gdb/gdb/remote-utils.c
new file mode 100644
index 0000000..3f38d3e
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/remote-utils.c
@@ -0,0 +1,704 @@
+/* Generic support for remote debugging interfaces.
+
+ Copyright 1993, 1994 Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* This file actually contains two distinct logical "packages". They
+ are packaged together in this one file because they are typically
+ used together.
+
+ The first package is an addition to the serial package. The
+ addition provides reading and writing with debugging output and
+ timeouts based on user settable variables. These routines are
+ intended to support serial port based remote backends. These
+ functions are prefixed with sr_.
+
+ The second package is a collection of more or less generic
+ functions for use by remote backends. They support user settable
+ variables for debugging, retries, and the like.
+
+ Todo:
+
+ * a pass through mode a la kermit or telnet.
+ * autobaud.
+ * ask remote to change his baud rate.
+ */
+
+#include <ctype.h>
+
+#include "defs.h"
+#include <string.h>
+#include "gdbcmd.h"
+#include "target.h"
+#include "serial.h"
+#include "gdbcore.h" /* for exec_bfd */
+#include "inferior.h" /* for generic_mourn_inferior */
+#include "remote-utils.h"
+
+struct _sr_settings sr_settings = {
+ 4, /* timeout:
+ remote-hms.c had 2
+ remote-bug.c had "with a timeout of 2, we time out waiting for
+ the prompt after an s-record dump."
+
+ remote.c had (2): This was 5 seconds, which is a long time to
+ sit and wait. Unless this is going though some terminal server
+ or multiplexer or other form of hairy serial connection, I
+ would think 2 seconds would be plenty.
+*/
+
+ 10, /* retries */
+ NULL, /* device */
+ NULL, /* descriptor */
+};
+
+struct gr_settings *gr_settings = NULL;
+
+static void
+usage(proto, junk)
+ char *proto;
+ char *junk;
+{
+ if (junk != NULL)
+ fprintf_unfiltered(gdb_stderr, "Unrecognized arguments: `%s'.\n", junk);
+
+ error ("Usage: target %s [DEVICE [SPEED [DEBUG]]]\n\
+where DEVICE is the name of a device or HOST:PORT", proto, proto);
+
+ return;
+}
+
+#define CHECKDONE(p, q) \
+{ \
+ if (q == p) \
+ { \
+ if (*p == '\0') \
+ return; \
+ else \
+ usage(proto, p); \
+ } \
+}
+
+void
+sr_scan_args(proto, args)
+ char *proto;
+ char *args;
+{
+ int n;
+ char *p, *q;
+
+ extern int strtol();
+
+ /* if no args, then nothing to do. */
+ if (args == NULL || *args == '\0')
+ return;
+
+ /* scan off white space. */
+ for (p = args; isspace(*p); ++p) ;;
+
+ /* find end of device name. */
+ for (q = p; *q != '\0' && !isspace(*q); ++q) ;;
+
+ /* check for missing or empty device name. */
+ CHECKDONE(p, q);
+ sr_set_device(savestring(p, q - p));
+
+ /* look for baud rate. */
+ n = strtol(q, &p, 10);
+
+ /* check for missing or empty baud rate. */
+ CHECKDONE(p, q);
+ baud_rate = n;
+
+ /* look for debug value. */
+ n = strtol(p, &q, 10);
+
+ /* check for missing or empty debug value. */
+ CHECKDONE(p, q);
+ sr_set_debug(n);
+
+ /* scan off remaining white space. */
+ for (p = q; isspace(*p); ++p) ;;
+
+ /* if not end of string, then there's unrecognized junk. */
+ if (*p != '\0')
+ usage(proto, p);
+
+ return;
+}
+
+void
+gr_generic_checkin()
+{
+ sr_write_cr("");
+ gr_expect_prompt();
+}
+
+void
+gr_open(args, from_tty, gr)
+ char *args;
+ int from_tty;
+ struct gr_settings *gr;
+{
+ target_preopen(from_tty);
+ sr_scan_args(gr->ops->to_shortname, args);
+ unpush_target(gr->ops);
+
+ gr_settings = gr;
+
+ gr_set_dcache(dcache_init(gr->readfunc, gr->writefunc));
+
+ if (sr_get_desc() != NULL)
+ gr_close (0);
+
+ /* If no args are specified, then we use the device specified by a
+ previous command or "set remotedevice". But if there is no
+ device, better stop now, not dump core. */
+
+ if (sr_get_device () == NULL)
+ usage (gr->ops->to_shortname, NULL);
+
+ sr_set_desc(SERIAL_OPEN (sr_get_device()));
+ if (!sr_get_desc())
+ perror_with_name((char *) sr_get_device());
+
+ if (baud_rate != -1)
+ {
+ if (SERIAL_SETBAUDRATE(sr_get_desc(), baud_rate) != 0)
+ {
+ SERIAL_CLOSE(sr_get_desc());
+ perror_with_name(sr_get_device());
+ }
+ }
+
+ SERIAL_RAW (sr_get_desc());
+
+ /* If there is something sitting in the buffer we might take it as a
+ response to a command, which would be bad. */
+ SERIAL_FLUSH_INPUT (sr_get_desc ());
+
+ /* default retries */
+ if (sr_get_retries() == 0)
+ sr_set_retries(1);
+
+ /* default clear breakpoint function */
+ if (gr_settings->clear_all_breakpoints == NULL)
+ gr_settings->clear_all_breakpoints = remove_breakpoints;
+
+ if (from_tty)
+ {
+ printf_filtered ("Remote debugging using `%s'", sr_get_device ());
+ if (baud_rate != -1)
+ printf_filtered (" at baud rate of %d",
+ baud_rate);
+ printf_filtered ("\n");
+ }
+
+ push_target(gr->ops);
+ gr_checkin();
+ gr_clear_all_breakpoints ();
+ return;
+}
+
+/* Read a character from the remote system masking it down to 7 bits
+ and doing all the fancy timeout stuff. */
+
+int
+sr_readchar ()
+{
+ int buf;
+
+ buf = SERIAL_READCHAR (sr_get_desc(), sr_get_timeout());
+
+ if (buf == SERIAL_TIMEOUT)
+ error ("Timeout reading from remote system.");
+
+ if (sr_get_debug() > 0)
+ printf_unfiltered ("%c", buf);
+
+ return buf & 0x7f;
+}
+
+int
+sr_pollchar()
+{
+ int buf;
+
+ buf = SERIAL_READCHAR (sr_get_desc(), 0);
+ if (buf == SERIAL_TIMEOUT)
+ buf = 0;
+ if (sr_get_debug() > 0)
+ if (buf)
+ printf_unfiltered ("%c", buf);
+ else
+ printf_unfiltered ("<empty character poll>");
+
+ return buf & 0x7f;
+}
+
+/* Keep discarding input from the remote system, until STRING is found.
+ Let the user break out immediately. */
+void
+sr_expect (string)
+ char *string;
+{
+ char *p = string;
+
+ immediate_quit = 1;
+ while (1)
+ {
+ if (sr_readchar () == *p)
+ {
+ p++;
+ if (*p == '\0')
+ {
+ immediate_quit = 0;
+ return;
+ }
+ }
+ else
+ p = string;
+ }
+}
+
+void
+sr_write (a, l)
+ char *a;
+ int l;
+{
+ int i;
+
+ if (SERIAL_WRITE (sr_get_desc(), a, l) != 0)
+ perror_with_name ("sr_write: Error writing to remote");
+
+ if (sr_get_debug() > 0)
+ for (i = 0; i < l; i++)
+ printf_unfiltered ("%c", a[i]);
+
+ return;
+}
+
+void
+sr_write_cr (s)
+ char *s;
+{
+ sr_write (s, strlen (s));
+ sr_write ("\r", 1);
+ return;
+}
+
+int
+sr_timed_read (buf, n)
+ char *buf;
+ int n;
+{
+ int i;
+ char c;
+
+ i = 0;
+ while (i < n)
+ {
+ c = sr_readchar ();
+
+ if (c == 0)
+ return i;
+ buf[i] = c;
+ i++;
+
+ }
+ return i;
+}
+
+/* Get a hex digit from the remote system & return its value. If
+ ignore_space is nonzero, ignore spaces (not newline, tab, etc). */
+
+int
+sr_get_hex_digit (ignore_space)
+ int ignore_space;
+{
+ int ch;
+
+ while (1)
+ {
+ ch = sr_readchar ();
+ if (ch >= '0' && ch <= '9')
+ return ch - '0';
+ else if (ch >= 'A' && ch <= 'F')
+ return ch - 'A' + 10;
+ else if (ch >= 'a' && ch <= 'f')
+ return ch - 'a' + 10;
+ else if (ch != ' ' || !ignore_space)
+ {
+ gr_expect_prompt ();
+ error ("Invalid hex digit from remote system.");
+ }
+ }
+}
+
+/* Get a byte from the remote and put it in *BYT. Accept any number
+ leading spaces. */
+void
+sr_get_hex_byte (byt)
+ char *byt;
+{
+ int val;
+
+ val = sr_get_hex_digit (1) << 4;
+ val |= sr_get_hex_digit (0);
+ *byt = val;
+}
+
+/* Read a 32-bit hex word from the remote, preceded by a space */
+long
+sr_get_hex_word ()
+{
+ long val;
+ int j;
+
+ val = 0;
+ for (j = 0; j < 8; j++)
+ val = (val << 4) + sr_get_hex_digit (j == 0);
+ return val;
+}
+
+/* Put a command string, in args, out to the remote. The remote is assumed to
+ be in raw mode, all writing/reading done through desc.
+ Ouput from the remote is placed on the users terminal until the
+ prompt from the remote is seen.
+ FIXME: Can't handle commands that take input. */
+
+void
+sr_com (args, fromtty)
+ char *args;
+ int fromtty;
+{
+ sr_check_open ();
+
+ if (!args)
+ return;
+
+ /* Clear all input so only command relative output is displayed */
+
+ sr_write_cr (args);
+ sr_write ("\030", 1);
+ gr_expect_prompt ();
+}
+
+void
+gr_close(quitting)
+ int quitting;
+{
+ gr_clear_all_breakpoints();
+
+ if (sr_is_open())
+ {
+ SERIAL_CLOSE (sr_get_desc());
+ sr_set_desc(NULL);
+ }
+
+ return;
+}
+
+/* gr_detach()
+ takes a program previously attached to and detaches it.
+ We better not have left any breakpoints
+ in the program or it'll die when it hits one.
+ Close the open connection to the remote debugger.
+ Use this when you want to detach and do something else
+ with your gdb. */
+
+void
+gr_detach(args, from_tty)
+ char *args;
+ int from_tty;
+{
+ if (args)
+ error ("Argument given to \"detach\" when remotely debugging.");
+
+ if (sr_is_open())
+ gr_clear_all_breakpoints ();
+
+ pop_target ();
+ if (from_tty)
+ puts_filtered ("Ending remote debugging.\n");
+
+ return;
+}
+
+void
+gr_files_info (ops)
+ struct target_ops *ops;
+{
+#ifdef __GO32__
+ printf_filtered ("\tAttached to DOS asynctsr\n");
+#else
+ printf_filtered ("\tAttached to %s", sr_get_device());
+ if (baud_rate != -1)
+ printf_filtered ("at %d baud", baud_rate);
+ printf_filtered ("\n");
+#endif
+
+ if (exec_bfd)
+ {
+ printf_filtered ("\tand running program %s\n",
+ bfd_get_filename (exec_bfd));
+ }
+ printf_filtered ("\tusing the %s protocol.\n", ops->to_shortname);
+}
+
+void
+gr_mourn ()
+{
+ gr_clear_all_breakpoints ();
+ unpush_target (gr_get_ops());
+ generic_mourn_inferior ();
+}
+
+void
+gr_kill ()
+{
+ return;
+}
+
+/* This is called not only when we first attach, but also when the
+ user types "run" after having attached. */
+void
+gr_create_inferior (execfile, args, env)
+ char *execfile;
+ char *args;
+ char **env;
+{
+ int entry_pt;
+
+ if (args && *args)
+ error ("Can't pass arguments to remote process.");
+
+ if (execfile == 0 || exec_bfd == 0)
+ error ("No exec file specified");
+
+ entry_pt = (int) bfd_get_start_address (exec_bfd);
+ sr_check_open ();
+
+ gr_kill ();
+ gr_clear_all_breakpoints ();
+
+ init_wait_for_inferior ();
+ gr_checkin();
+
+ insert_breakpoints (); /* Needed to get correct instruction in cache */
+ proceed (entry_pt, -1, 0);
+}
+
+/* Given a null terminated list of strings LIST, read the input until we find one of
+ them. Return the index of the string found or -1 on error. '?' means match
+ any single character. Note that with the algorithm we use, the initial
+ character of the string cannot recur in the string, or we will not find some
+ cases of the string in the input. If PASSTHROUGH is non-zero, then
+ pass non-matching data on. */
+
+int
+gr_multi_scan (list, passthrough)
+ char *list[];
+ int passthrough;
+{
+ char *swallowed = NULL; /* holding area */
+ char *swallowed_p = swallowed; /* Current position in swallowed. */
+ int ch;
+ int ch_handled;
+ int i;
+ int string_count;
+ int max_length;
+ char **plist;
+
+ /* Look through the strings. Count them. Find the largest one so we can
+ allocate a holding area. */
+
+ for (max_length = string_count = i = 0;
+ list[i] != NULL;
+ ++i, ++string_count)
+ {
+ int length = strlen(list[i]);
+
+ if (length > max_length)
+ max_length = length;
+ }
+
+ /* if we have no strings, then something is wrong. */
+ if (string_count == 0)
+ return(-1);
+
+ /* otherwise, we will need a holding area big enough to hold almost two
+ copies of our largest string. */
+ swallowed_p = swallowed = alloca(max_length << 1);
+
+ /* and a list of pointers to current scan points. */
+ plist = (char **) alloca (string_count * sizeof(*plist));
+
+ /* and initialize */
+ for (i = 0; i < string_count; ++i)
+ plist[i] = list[i];
+
+ for (ch = sr_readchar(); /* loop forever */ ; ch = sr_readchar())
+ {
+ QUIT; /* Let user quit and leave process running */
+ ch_handled = 0;
+
+ for (i = 0; i < string_count; ++i)
+ {
+ if (ch == *plist[i] || *plist[i] == '?')
+ {
+ ++plist[i];
+ if (*plist[i] == '\0')
+ return(i);
+
+ if (!ch_handled)
+ *swallowed_p++ = ch;
+
+ ch_handled = 1;
+ }
+ else
+ plist[i] = list[i];
+ }
+
+ if (!ch_handled)
+ {
+ char *p;
+
+ /* Print out any characters which have been swallowed. */
+ if (passthrough)
+ {
+ for (p = swallowed; p < swallowed_p; ++p)
+ fputc_unfiltered (*p, gdb_stdout);
+
+ fputc_unfiltered (ch, gdb_stdout);
+ }
+
+ swallowed_p = swallowed;
+ }
+ }
+#if 0
+ /* Never reached. */
+ return(-1);
+#endif
+}
+
+/* Get ready to modify the registers array. On machines which store
+ individual registers, this doesn't need to do anything. On machines
+ which store all the registers in one fell swoop, this makes sure
+ that registers contains all the registers from the program being
+ debugged. */
+
+void
+gr_prepare_to_store ()
+{
+ /* Do nothing, since we assume we can store individual regs */
+}
+
+/* Read a word from remote address ADDR and return it.
+ * This goes through the data cache.
+ */
+int
+gr_fetch_word (addr)
+ CORE_ADDR addr;
+{
+ return dcache_fetch (gr_get_dcache(), addr);
+}
+
+/* Write a word WORD into remote address ADDR.
+ This goes through the data cache. */
+
+void
+gr_store_word (addr, word)
+ CORE_ADDR addr;
+ int word;
+{
+ dcache_poke (gr_get_dcache(), addr, word);
+}
+
+/* general purpose load a file specified on the command line
+ into target memory. */
+
+void
+gr_load_image (args, fromtty)
+ char *args;
+ int fromtty;
+{
+ bfd *abfd;
+
+ asection *s;
+ struct cleanup *old_cleanups;
+ int delta = 4096;
+ char *buffer = xmalloc (delta);
+
+ abfd = bfd_openr (args, (char *) 0);
+
+ if (!abfd)
+ perror_with_name (args);
+
+ old_cleanups = make_cleanup (bfd_close, abfd);
+
+ QUIT;
+
+ if (!bfd_check_format (abfd, bfd_object))
+ error ("It doesn't seem to be an object file.\n");
+
+ for (s = abfd->sections; s && !quit_flag; s = s->next)
+ {
+ if (bfd_get_section_flags (abfd, s) & SEC_LOAD)
+ {
+ int i;
+ printf_filtered ("%s\t: 0x%4x .. 0x%4x ",
+ s->name, s->vma, s->vma + s->_raw_size);
+ fflush (stdout);
+ for (i = 0; i < s->_raw_size && !quit_flag; i += delta)
+ {
+ int sub_delta = delta;
+ if (sub_delta > s->_raw_size - i)
+ sub_delta = s->_raw_size - i;
+ QUIT;
+ bfd_get_section_contents (abfd, s, buffer, i, sub_delta);
+ target_write_memory (s->vma + i, buffer, sub_delta);
+ printf_filtered ("*");
+ fflush (stdout);
+ }
+ printf_filtered ("\n");
+ }
+ }
+
+ free (buffer);
+ write_pc (bfd_get_start_address (abfd));
+ bfd_close (abfd);
+ discard_cleanups (old_cleanups);
+}
+
+
+void
+_initialize_sr_support ()
+{
+/* FIXME-now: if target is open... */
+ add_show_from_set (add_set_cmd ("remotedevice", no_class,
+ var_filename, (char *)&sr_settings.device,
+ "Set device for remote serial I/O.\n\
+This device is used as the serial port when debugging using remote\n\
+targets.", &setlist),
+ &showlist);
+
+ add_com ("remote <command>", class_obscure, sr_com,
+ "Send a command to the remote monitor.");
+
+}
diff --git a/gnu/usr.bin/gdb/gdb/remote-utils.h b/gnu/usr.bin/gdb/gdb/remote-utils.h
new file mode 100644
index 0000000..d859330
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/remote-utils.h
@@ -0,0 +1,142 @@
+/* Generic support for remote debugging interfaces.
+
+ Copyright 1993 Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#ifndef REMOTE_UTILS_H
+#define REMOTE_UTILS_H
+
+#include "serial.h"
+#include "target.h"
+#include "dcache.h"
+
+/* Stuff that should be shared (and handled consistently) among the various
+ remote targets. */
+
+struct _sr_settings {
+ unsigned int timeout;
+
+ int retries;
+
+ char *device;
+ serial_t desc;
+
+};
+
+extern struct _sr_settings sr_settings;
+
+/* get and set debug value. */
+#define sr_get_debug() (remote_debug)
+#define sr_set_debug(newval) (remote_debug = (newval))
+
+/* get and set timeout. */
+#define sr_get_timeout() (sr_settings.timeout)
+#define sr_set_timeout(newval) (sr_settings.timeout = (newval))
+
+/* get and set device. */
+#define sr_get_device() (sr_settings.device)
+#define sr_set_device(newval) \
+{ \
+ if (sr_settings.device) free(sr_settings.device); \
+ sr_settings.device = (newval); \
+}
+
+/* get and set descriptor value. */
+#define sr_get_desc() (sr_settings.desc)
+#define sr_set_desc(newval) (sr_settings.desc = (newval))
+
+/* get and set retries. */
+#define sr_get_retries() (sr_settings.retries)
+#define sr_set_retries(newval) (sr_settings.retries = (newval))
+
+#define sr_is_open() (sr_settings.desc != NULL)
+
+#define sr_check_open() { if (!sr_is_open()) \
+ error ("Remote device not open"); }
+
+struct gr_settings {
+ /* This is our data cache. */
+ DCACHE *dcache;
+ char *prompt;
+ struct target_ops *ops;
+ int (*clear_all_breakpoints)PARAMS((void));
+ memxferfunc readfunc;
+ memxferfunc writefunc;
+ void (*checkin)PARAMS((void));
+};
+
+extern struct gr_settings *gr_settings;
+
+/* get and set dcache. */
+#define gr_get_dcache() (gr_settings->dcache)
+#define gr_set_dcache(newval) (gr_settings->dcache = (newval))
+
+/* get and set prompt. */
+#define gr_get_prompt() (gr_settings->prompt)
+#define gr_set_prompt(newval) (gr_settings->prompt = (newval))
+
+/* get and set ops. */
+#define gr_get_ops() (gr_settings->ops)
+#define gr_set_ops(newval) (gr_settings->ops = (newval))
+
+#define gr_clear_all_breakpoints() ((gr_settings->clear_all_breakpoints)())
+#define gr_checkin() ((gr_settings->checkin)())
+
+/* Keep discarding input until we see the prompt.
+
+ The convention for dealing with the prompt is that you
+ o give your command
+ o *then* wait for the prompt.
+
+ Thus the last thing that a procedure does with the serial line
+ will be an gr_expect_prompt(). Exception: resume does not
+ wait for the prompt, because the terminal is being handed over
+ to the inferior. However, the next thing which happens after that
+ is a bug_wait which does wait for the prompt.
+ Note that this includes abnormal exit, e.g. error(). This is
+ necessary to prevent getting into states from which we can't
+ recover. */
+
+#define gr_expect_prompt() sr_expect(gr_get_prompt())
+
+int gr_fetch_word PARAMS((CORE_ADDR addr));
+int gr_multi_scan PARAMS((char *list[], int passthrough));
+int sr_get_hex_digit PARAMS((int ignore_space));
+int sr_pollchar PARAMS((void));
+int sr_readchar PARAMS((void));
+int sr_timed_read PARAMS((char *buf, int n));
+long sr_get_hex_word PARAMS((void));
+void gr_close PARAMS((int quitting));
+void gr_create_inferior PARAMS((char *execfile, char *args, char **env));
+void gr_detach PARAMS((char *args, int from_tty));
+void gr_files_info PARAMS((struct target_ops *ops));
+void gr_generic_checkin PARAMS((void));
+void gr_kill PARAMS((void));
+void gr_mourn PARAMS((void));
+void gr_prepare_to_store PARAMS((void));
+void gr_store_word PARAMS((CORE_ADDR addr, int word));
+void sr_expect PARAMS((char *string));
+void sr_get_hex_byte PARAMS((char *byt));
+void sr_scan_args PARAMS((char *proto, char *args));
+void sr_write PARAMS((char *a, int l));
+void sr_write_cr PARAMS((char *s));
+
+void gr_open PARAMS((char *args, int from_tty,
+ struct gr_settings *gr_settings));
+void gr_load_image PARAMS((char*, int from_tty));
+#endif /* REMOTE_UTILS_H */
diff --git a/gnu/usr.bin/gdb/gdb/remote.c b/gnu/usr.bin/gdb/gdb/remote.c
new file mode 100644
index 0000000..c340ca9
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/remote.c
@@ -0,0 +1,1470 @@
+/* Remote target communications for serial-line targets in custom GDB protocol
+ Copyright 1988, 1991, 1992, 1993, 1994 Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* Remote communication protocol.
+
+ A debug packet whose contents are <data>
+ is encapsulated for transmission in the form:
+
+ $ <data> # CSUM1 CSUM2
+
+ <data> must be ASCII alphanumeric and cannot include characters
+ '$' or '#'. If <data> starts with two characters followed by
+ ':', then the existing stubs interpret this as a sequence number.
+
+ CSUM1 and CSUM2 are ascii hex representation of an 8-bit
+ checksum of <data>, the most significant nibble is sent first.
+ the hex digits 0-9,a-f are used.
+
+ Receiver responds with:
+
+ + - if CSUM is correct and ready for next packet
+ - - if CSUM is incorrect
+
+ <data> is as follows:
+ All values are encoded in ascii hex digits.
+
+ Request Packet
+
+ read registers g
+ reply XX....X Each byte of register data
+ is described by two hex digits.
+ Registers are in the internal order
+ for GDB, and the bytes in a register
+ are in the same order the machine uses.
+ or ENN for an error.
+
+ write regs GXX..XX Each byte of register data
+ is described by two hex digits.
+ reply OK for success
+ ENN for an error
+
+ write reg Pn...=r... Write register n... with value r...,
+ which contains two hex digits for each
+ byte in the register (target byte
+ order).
+ reply OK for success
+ ENN for an error
+ (not supported by all stubs).
+
+ read mem mAA..AA,LLLL AA..AA is address, LLLL is length.
+ reply XX..XX XX..XX is mem contents
+ Can be fewer bytes than requested
+ if able to read only part of the data.
+ or ENN NN is errno
+
+ write mem MAA..AA,LLLL:XX..XX
+ AA..AA is address,
+ LLLL is number of bytes,
+ XX..XX is data
+ reply OK for success
+ ENN for an error (this includes the case
+ where only part of the data was
+ written).
+
+ cont cAA..AA AA..AA is address to resume
+ If AA..AA is omitted,
+ resume at same address.
+
+ step sAA..AA AA..AA is address to resume
+ If AA..AA is omitted,
+ resume at same address.
+
+ last signal ? Reply the current reason for stopping.
+ This is the same reply as is generated
+ for step or cont : SAA where AA is the
+ signal number.
+
+ There is no immediate reply to step or cont.
+ The reply comes when the machine stops.
+ It is SAA AA is the "signal number"
+
+ or... TAAn...:r...;n:r...;n...:r...;
+ AA = signal number
+ n... = register number
+ r... = register contents
+ or... WAA The process exited, and AA is
+ the exit status. This is only
+ applicable for certains sorts of
+ targets.
+ kill request k
+
+ toggle debug d toggle debug flag (see 386 & 68k stubs)
+ reset r reset -- see sparc stub.
+ reserved <other> On other requests, the stub should
+ ignore the request and send an empty
+ response ($#<checksum>). This way
+ we can extend the protocol and GDB
+ can tell whether the stub it is
+ talking to uses the old or the new.
+ search tAA:PP,MM Search backwards starting at address
+ AA for a match with pattern PP and
+ mask MM. PP and MM are 4 bytes.
+ Not supported by all stubs.
+
+ general query qXXXX Request info about XXXX.
+ general set QXXXX=yyyy Set value of XXXX to yyyy.
+ query sect offs qOffsets Get section offsets. Reply is
+ Text=xxx;Data=yyy;Bss=zzz
+ console output Otext Send text to stdout. Only comes from
+ remote target.
+
+ Responses can be run-length encoded to save space. A '*' means that
+ the next two characters are hex digits giving a repeat count which
+ stands for that many repititions of the character preceding the '*'.
+ Note that this means that responses cannot contain '*'. Example:
+ "0*03" means the same as "0000". */
+
+#include "defs.h"
+#include <string.h>
+#include <fcntl.h>
+#include "frame.h"
+#include "inferior.h"
+#include "bfd.h"
+#include "symfile.h"
+#include "target.h"
+#include "wait.h"
+#include "terminal.h"
+#include "gdbcmd.h"
+#include "objfiles.h"
+#include "gdb-stabs.h"
+
+#include "dcache.h"
+
+#if !defined(DONT_USE_REMOTE)
+#ifdef USG
+#include <sys/types.h>
+#endif
+
+#include <signal.h>
+#include "serial.h"
+
+/* Prototypes for local functions */
+
+static int
+remote_write_bytes PARAMS ((CORE_ADDR memaddr, unsigned char *myaddr, int len));
+
+static int
+remote_read_bytes PARAMS ((CORE_ADDR memaddr, unsigned char *myaddr, int len));
+
+static void
+remote_files_info PARAMS ((struct target_ops *ignore));
+
+static int
+remote_xfer_memory PARAMS ((CORE_ADDR memaddr, char *myaddr, int len,
+ int should_write, struct target_ops *target));
+
+static void
+remote_prepare_to_store PARAMS ((void));
+
+static void
+remote_fetch_registers PARAMS ((int regno));
+
+static void
+remote_resume PARAMS ((int pid, int step, enum target_signal siggnal));
+
+static int
+remote_start_remote PARAMS ((char *dummy));
+
+static void
+remote_open PARAMS ((char *name, int from_tty));
+
+static void
+remote_close PARAMS ((int quitting));
+
+static void
+remote_store_registers PARAMS ((int regno));
+
+static void
+getpkt PARAMS ((char *buf, int forever));
+
+static void
+putpkt PARAMS ((char *buf));
+
+static void
+remote_send PARAMS ((char *buf));
+
+static int
+readchar PARAMS ((int timeout));
+
+static int remote_wait PARAMS ((int pid, struct target_waitstatus *status));
+
+static int
+tohex PARAMS ((int nib));
+
+static int
+fromhex PARAMS ((int a));
+
+static void
+remote_detach PARAMS ((char *args, int from_tty));
+
+static void
+remote_interrupt PARAMS ((int signo));
+
+static void
+remote_interrupt_twice PARAMS ((int signo));
+
+static void
+interrupt_query PARAMS ((void));
+
+extern struct target_ops remote_ops; /* Forward decl */
+
+/* This was 5 seconds, which is a long time to sit and wait.
+ Unless this is going though some terminal server or multiplexer or
+ other form of hairy serial connection, I would think 2 seconds would
+ be plenty. */
+static int remote_timeout = 2;
+
+#if 0
+int icache;
+#endif
+
+/* Descriptor for I/O to remote machine. Initialize it to NULL so that
+ remote_open knows that we don't have a file open when the program
+ starts. */
+serial_t remote_desc = NULL;
+
+/* Having this larger than 400 causes us to be incompatible with m68k-stub.c
+ and i386-stub.c. Normally, no one would notice because it only matters
+ for writing large chunks of memory (e.g. in downloads). Also, this needs
+ to be more than 400 if required to hold the registers (see below, where
+ we round it up based on REGISTER_BYTES). */
+#define PBUFSIZ 400
+
+/* Maximum number of bytes to read/write at once. The value here
+ is chosen to fill up a packet (the headers account for the 32). */
+#define MAXBUFBYTES ((PBUFSIZ-32)/2)
+
+/* Round up PBUFSIZ to hold all the registers, at least. */
+/* The blank line after the #if seems to be required to work around a
+ bug in HP's PA compiler. */
+#if REGISTER_BYTES > MAXBUFBYTES
+
+#undef PBUFSIZ
+#define PBUFSIZ (REGISTER_BYTES * 2 + 32)
+#endif
+
+/* Should we try the 'P' request? If this is set to one when the stub
+ doesn't support 'P', the only consequence is some unnecessary traffic. */
+static int stub_supports_P = 1;
+
+
+/* Clean up connection to a remote debugger. */
+
+/* ARGSUSED */
+static void
+remote_close (quitting)
+ int quitting;
+{
+ if (remote_desc)
+ SERIAL_CLOSE (remote_desc);
+ remote_desc = NULL;
+}
+
+/* Query the remote side for the text, data and bss offsets. */
+
+static void
+get_offsets ()
+{
+ unsigned char buf[PBUFSIZ];
+ int nvals;
+ CORE_ADDR text_addr, data_addr, bss_addr;
+ struct section_offsets *offs;
+
+ putpkt ("qOffsets");
+
+ getpkt (buf, 0);
+
+ if (buf[0] == '\000')
+ return; /* Return silently. Stub doesn't support this
+ command. */
+ if (buf[0] == 'E')
+ {
+ warning ("Remote failure reply: %s", buf);
+ return;
+ }
+
+ nvals = sscanf (buf, "Text=%lx;Data=%lx;Bss=%lx", &text_addr, &data_addr,
+ &bss_addr);
+ if (nvals != 3)
+ error ("Malformed response to offset query, %s", buf);
+
+ if (symfile_objfile == NULL)
+ return;
+
+ offs = (struct section_offsets *) alloca (sizeof (struct section_offsets)
+ + symfile_objfile->num_sections
+ * sizeof (offs->offsets));
+ memcpy (offs, symfile_objfile->section_offsets,
+ sizeof (struct section_offsets)
+ + symfile_objfile->num_sections
+ * sizeof (offs->offsets));
+
+ /* FIXME: This code assumes gdb-stabs.h is being used; it's broken
+ for xcoff, dwarf, sdb-coff, etc. But there is no simple
+ canonical representation for this stuff. (Just what does "text"
+ as seen by the stub mean, anyway? I think it means all sections
+ with SEC_CODE set, but we currently have no way to deal with that). */
+
+ ANOFFSET (offs, SECT_OFF_TEXT) = text_addr;
+
+ /* This is a temporary kludge to force data and bss to use the same offsets
+ because that's what nlmconv does now. The real solution requires changes
+ to the stub and remote.c that I don't have time to do right now. */
+
+ ANOFFSET (offs, SECT_OFF_DATA) = data_addr;
+ ANOFFSET (offs, SECT_OFF_BSS) = data_addr;
+
+ objfile_relocate (symfile_objfile, offs);
+}
+
+/* Stub for catch_errors. */
+
+static int
+remote_start_remote (dummy)
+ char *dummy;
+{
+ immediate_quit = 1; /* Allow user to interrupt it */
+
+ /* Ack any packet which the remote side has already sent. */
+
+ SERIAL_WRITE (remote_desc, "+", 1);
+
+ get_offsets (); /* Get text, data & bss offsets */
+
+ putpkt ("?"); /* initiate a query from remote machine */
+ immediate_quit = 0;
+
+ start_remote (); /* Initialize gdb process mechanisms */
+
+ return 1;
+}
+
+/* Open a connection to a remote debugger.
+ NAME is the filename used for communication. */
+
+static DCACHE *remote_dcache;
+
+static void
+remote_open (name, from_tty)
+ char *name;
+ int from_tty;
+{
+ if (name == 0)
+ error (
+"To open a remote debug connection, you need to specify what serial\n\
+device is attached to the remote system (e.g. /dev/ttya).");
+
+ target_preopen (from_tty);
+
+ unpush_target (&remote_ops);
+
+ remote_dcache = dcache_init (remote_read_bytes, remote_write_bytes);
+
+ remote_desc = SERIAL_OPEN (name);
+ if (!remote_desc)
+ perror_with_name (name);
+
+ if (baud_rate != -1)
+ {
+ if (SERIAL_SETBAUDRATE (remote_desc, baud_rate))
+ {
+ SERIAL_CLOSE (remote_desc);
+ perror_with_name (name);
+ }
+ }
+
+ SERIAL_RAW (remote_desc);
+
+ /* If there is something sitting in the buffer we might take it as a
+ response to a command, which would be bad. */
+ SERIAL_FLUSH_INPUT (remote_desc);
+
+ if (from_tty)
+ {
+ puts_filtered ("Remote debugging using ");
+ puts_filtered (name);
+ puts_filtered ("\n");
+ }
+ push_target (&remote_ops); /* Switch to using remote target now */
+
+ /* Start out by trying the 'P' request to set registers. We set this each
+ time that we open a new target so that if the user switches from one
+ stub to another, we can (if the target is closed and reopened) cope. */
+ stub_supports_P = 1;
+
+ /* Start the remote connection; if error (0), discard this target.
+ In particular, if the user quits, be sure to discard it
+ (we'd be in an inconsistent state otherwise). */
+ if (!catch_errors (remote_start_remote, (char *)0,
+ "Couldn't establish connection to remote target\n", RETURN_MASK_ALL))
+ pop_target();
+}
+
+/* remote_detach()
+ takes a program previously attached to and detaches it.
+ We better not have left any breakpoints
+ in the program or it'll die when it hits one.
+ Close the open connection to the remote debugger.
+ Use this when you want to detach and do something else
+ with your gdb. */
+
+static void
+remote_detach (args, from_tty)
+ char *args;
+ int from_tty;
+{
+ if (args)
+ error ("Argument given to \"detach\" when remotely debugging.");
+
+ pop_target ();
+ if (from_tty)
+ puts_filtered ("Ending remote debugging.\n");
+}
+
+/* Convert hex digit A to a number. */
+
+static int
+fromhex (a)
+ int a;
+{
+ if (a >= '0' && a <= '9')
+ return a - '0';
+ else if (a >= 'a' && a <= 'f')
+ return a - 'a' + 10;
+ else
+ error ("Reply contains invalid hex digit");
+}
+
+/* Convert number NIB to a hex digit. */
+
+static int
+tohex (nib)
+ int nib;
+{
+ if (nib < 10)
+ return '0'+nib;
+ else
+ return 'a'+nib-10;
+}
+
+/* Tell the remote machine to resume. */
+
+static void
+remote_resume (pid, step, siggnal)
+ int pid, step;
+ enum target_signal siggnal;
+{
+ char buf[PBUFSIZ];
+
+ if (siggnal)
+ {
+ target_terminal_ours_for_output ();
+ printf_filtered
+ ("Can't send signals to a remote system. %s not sent.\n",
+ target_signal_to_name (siggnal));
+ target_terminal_inferior ();
+ }
+
+ dcache_flush (remote_dcache);
+
+ strcpy (buf, step ? "s": "c");
+
+ putpkt (buf);
+}
+
+/* Send ^C to target to halt it. Target will respond, and send us a
+ packet. */
+
+static void
+remote_interrupt (signo)
+ int signo;
+{
+ /* If this doesn't work, try more severe steps. */
+ signal (signo, remote_interrupt_twice);
+
+ if (remote_debug)
+ printf_unfiltered ("remote_interrupt called\n");
+
+ SERIAL_WRITE (remote_desc, "\003", 1); /* Send a ^C */
+}
+
+static void (*ofunc)();
+
+/* The user typed ^C twice. */
+static void
+remote_interrupt_twice (signo)
+ int signo;
+{
+ signal (signo, ofunc);
+
+ interrupt_query ();
+
+ signal (signo, remote_interrupt);
+}
+
+/* Ask the user what to do when an interrupt is received. */
+
+static void
+interrupt_query ()
+{
+ target_terminal_ours ();
+
+ if (query ("Interrupted while waiting for the program.\n\
+Give up (and stop debugging it)? "))
+ {
+ target_mourn_inferior ();
+ return_to_top_level (RETURN_QUIT);
+ }
+
+ target_terminal_inferior ();
+}
+
+/* Wait until the remote machine stops, then return,
+ storing status in STATUS just as `wait' would.
+ Returns "pid" (though it's not clear what, if anything, that
+ means in the case of this target). */
+
+static int
+remote_wait (pid, status)
+ int pid;
+ struct target_waitstatus *status;
+{
+ unsigned char buf[PBUFSIZ];
+
+ status->kind = TARGET_WAITKIND_EXITED;
+ status->value.integer = 0;
+
+ while (1)
+ {
+ unsigned char *p;
+
+ ofunc = (void (*)()) signal (SIGINT, remote_interrupt);
+ getpkt ((char *) buf, 1);
+ signal (SIGINT, ofunc);
+
+ switch (buf[0])
+ {
+ case 'E': /* Error of some sort */
+ warning ("Remote failure reply: %s", buf);
+ continue;
+ case 'T': /* Status with PC, SP, FP, ... */
+ {
+ int i;
+ long regno;
+ char regs[MAX_REGISTER_RAW_SIZE];
+
+ /* Expedited reply, containing Signal, {regno, reg} repeat */
+ /* format is: 'Tssn...:r...;n...:r...;n...:r...;#cc', where
+ ss = signal number
+ n... = register number
+ r... = register contents
+ */
+
+ p = &buf[3]; /* after Txx */
+
+ while (*p)
+ {
+ unsigned char *p1;
+
+ regno = strtol (p, &p1, 16); /* Read the register number */
+
+ if (p1 == p)
+ warning ("Remote sent badly formed register number: %s\nPacket: '%s'\n",
+ p1, buf);
+
+ p = p1;
+
+ if (*p++ != ':')
+ warning ("Malformed packet (missing colon): %s\nPacket: '%s'\n",
+ p, buf);
+
+ if (regno >= NUM_REGS)
+ warning ("Remote sent bad register number %d: %s\nPacket: '%s'\n",
+ regno, p, buf);
+
+ for (i = 0; i < REGISTER_RAW_SIZE (regno); i++)
+ {
+ if (p[0] == 0 || p[1] == 0)
+ warning ("Remote reply is too short: %s", buf);
+ regs[i] = fromhex (p[0]) * 16 + fromhex (p[1]);
+ p += 2;
+ }
+
+ if (*p++ != ';')
+ warning ("Remote register badly formatted: %s", buf);
+
+ supply_register (regno, regs);
+ }
+ }
+ /* fall through */
+ case 'S': /* Old style status, just signal only */
+ status->kind = TARGET_WAITKIND_STOPPED;
+ status->value.sig = (enum target_signal)
+ (((fromhex (buf[1])) << 4) + (fromhex (buf[2])));
+
+ return 0;
+ case 'W': /* Target exited */
+ {
+ /* The remote process exited. */
+ status->kind = TARGET_WAITKIND_EXITED;
+ status->value.integer = (fromhex (buf[1]) << 4) + fromhex (buf[2]);
+ return 0;
+ }
+ case 'O': /* Console output */
+ fputs_filtered (buf + 1, gdb_stdout);
+ continue;
+ default:
+ warning ("Invalid remote reply: %s", buf);
+ continue;
+ }
+ }
+ return 0;
+}
+
+/* Number of bytes of registers this stub implements. */
+static int register_bytes_found;
+
+/* Read the remote registers into the block REGS. */
+/* Currently we just read all the registers, so we don't use regno. */
+/* ARGSUSED */
+static void
+remote_fetch_registers (regno)
+ int regno;
+{
+ char buf[PBUFSIZ];
+ int i;
+ char *p;
+ char regs[REGISTER_BYTES];
+
+ sprintf (buf, "g");
+ remote_send (buf);
+
+ /* Unimplemented registers read as all bits zero. */
+ memset (regs, 0, REGISTER_BYTES);
+
+ /* We can get out of synch in various cases. If the first character
+ in the buffer is not a hex character, assume that has happened
+ and try to fetch another packet to read. */
+ while ((buf[0] < '0' || buf[0] > '9')
+ && (buf[0] < 'a' || buf[0] > 'f'))
+ {
+ if (remote_debug)
+ printf_unfiltered ("Bad register packet; fetching a new packet\n");
+ getpkt (buf, 0);
+ }
+
+ /* Reply describes registers byte by byte, each byte encoded as two
+ hex characters. Suck them all up, then supply them to the
+ register cacheing/storage mechanism. */
+
+ p = buf;
+ for (i = 0; i < REGISTER_BYTES; i++)
+ {
+ if (p[0] == 0)
+ break;
+ if (p[1] == 0)
+ {
+ warning ("Remote reply is of odd length: %s", buf);
+ /* Don't change register_bytes_found in this case, and don't
+ print a second warning. */
+ goto supply_them;
+ }
+ regs[i] = fromhex (p[0]) * 16 + fromhex (p[1]);
+ p += 2;
+ }
+
+ if (i != register_bytes_found)
+ {
+ register_bytes_found = i;
+#ifdef REGISTER_BYTES_OK
+ if (!REGISTER_BYTES_OK (i))
+ warning ("Remote reply is too short: %s", buf);
+#endif
+ }
+
+ supply_them:
+ for (i = 0; i < NUM_REGS; i++)
+ supply_register (i, &regs[REGISTER_BYTE(i)]);
+}
+
+/* Prepare to store registers. Since we may send them all (using a
+ 'G' request), we have to read out the ones we don't want to change
+ first. */
+
+static void
+remote_prepare_to_store ()
+{
+ /* Make sure the entire registers array is valid. */
+ read_register_bytes (0, (char *)NULL, REGISTER_BYTES);
+}
+
+/* Store register REGNO, or all registers if REGNO == -1, from the contents
+ of REGISTERS. FIXME: ignores errors. */
+
+static void
+remote_store_registers (regno)
+ int regno;
+{
+ char buf[PBUFSIZ];
+ int i;
+ char *p;
+
+ if (regno >= 0 && stub_supports_P)
+ {
+ /* Try storing a single register. */
+ char *regp;
+
+ sprintf (buf, "P%x=", regno);
+ p = buf + strlen (buf);
+ regp = &registers[REGISTER_BYTE (regno)];
+ for (i = 0; i < REGISTER_RAW_SIZE (regno); ++i)
+ {
+ *p++ = tohex ((regp[i] >> 4) & 0xf);
+ *p++ = tohex (regp[i] & 0xf);
+ }
+ *p = '\0';
+ remote_send (buf);
+ if (buf[0] != '\0')
+ {
+ /* The stub understands the 'P' request. We are done. */
+ return;
+ }
+
+ /* The stub does not support the 'P' request. Use 'G' instead,
+ and don't try using 'P' in the future (it will just waste our
+ time). */
+ stub_supports_P = 0;
+ }
+
+ buf[0] = 'G';
+
+ /* Command describes registers byte by byte,
+ each byte encoded as two hex characters. */
+
+ p = buf + 1;
+ /* remote_prepare_to_store insures that register_bytes_found gets set. */
+ for (i = 0; i < register_bytes_found; i++)
+ {
+ *p++ = tohex ((registers[i] >> 4) & 0xf);
+ *p++ = tohex (registers[i] & 0xf);
+ }
+ *p = '\0';
+
+ remote_send (buf);
+}
+
+#if 0
+
+/* Use of the data cache is disabled because it loses for looking at
+ and changing hardware I/O ports and the like. Accepting `volatile'
+ would perhaps be one way to fix it, but a better way which would
+ win for more cases would be to use the executable file for the text
+ segment, like the `icache' code below but done cleanly (in some
+ target-independent place, perhaps in target_xfer_memory, perhaps
+ based on assigning each target a speed or perhaps by some simpler
+ mechanism). */
+
+/* Read a word from remote address ADDR and return it.
+ This goes through the data cache. */
+
+static int
+remote_fetch_word (addr)
+ CORE_ADDR addr;
+{
+#if 0
+ if (icache)
+ {
+ extern CORE_ADDR text_start, text_end;
+
+ if (addr >= text_start && addr < text_end)
+ {
+ int buffer;
+ xfer_core_file (addr, &buffer, sizeof (int));
+ return buffer;
+ }
+ }
+#endif
+ return dcache_fetch (remote_dcache, addr);
+}
+
+/* Write a word WORD into remote address ADDR.
+ This goes through the data cache. */
+
+static void
+remote_store_word (addr, word)
+ CORE_ADDR addr;
+ int word;
+{
+ dcache_poke (remote_dcache, addr, word);
+}
+#endif /* 0 */
+
+/* Write memory data directly to the remote machine.
+ This does not inform the data cache; the data cache uses this.
+ MEMADDR is the address in the remote memory space.
+ MYADDR is the address of the buffer in our space.
+ LEN is the number of bytes.
+
+ Returns number of bytes transferred, or 0 for error. */
+
+static int
+remote_write_bytes (memaddr, myaddr, len)
+ CORE_ADDR memaddr;
+ unsigned char *myaddr;
+ int len;
+{
+ char buf[PBUFSIZ];
+ int i;
+ char *p;
+
+ /* FIXME-32x64: Need a version of print_address_numeric which puts the
+ result in a buffer like sprintf. */
+ sprintf (buf, "M%lx,%x:", (unsigned long) memaddr, len);
+
+ /* We send target system values byte by byte, in increasing byte addresses,
+ each byte encoded as two hex characters. */
+
+ p = buf + strlen (buf);
+ for (i = 0; i < len; i++)
+ {
+ *p++ = tohex ((myaddr[i] >> 4) & 0xf);
+ *p++ = tohex (myaddr[i] & 0xf);
+ }
+ *p = '\0';
+
+ putpkt (buf);
+ getpkt (buf, 0);
+
+ if (buf[0] == 'E')
+ {
+ /* There is no correspondance between what the remote protocol uses
+ for errors and errno codes. We would like a cleaner way of
+ representing errors (big enough to include errno codes, bfd_error
+ codes, and others). But for now just return EIO. */
+ errno = EIO;
+ return 0;
+ }
+ return len;
+}
+
+/* Read memory data directly from the remote machine.
+ This does not use the data cache; the data cache uses this.
+ MEMADDR is the address in the remote memory space.
+ MYADDR is the address of the buffer in our space.
+ LEN is the number of bytes.
+
+ Returns number of bytes transferred, or 0 for error. */
+
+static int
+remote_read_bytes (memaddr, myaddr, len)
+ CORE_ADDR memaddr;
+ unsigned char *myaddr;
+ int len;
+{
+ char buf[PBUFSIZ];
+ int i;
+ char *p;
+
+ if (len > PBUFSIZ / 2 - 1)
+ abort ();
+
+ /* FIXME-32x64: Need a version of print_address_numeric which puts the
+ result in a buffer like sprintf. */
+ sprintf (buf, "m%lx,%x", (unsigned long) memaddr, len);
+ putpkt (buf);
+ getpkt (buf, 0);
+
+ if (buf[0] == 'E')
+ {
+ /* There is no correspondance between what the remote protocol uses
+ for errors and errno codes. We would like a cleaner way of
+ representing errors (big enough to include errno codes, bfd_error
+ codes, and others). But for now just return EIO. */
+ errno = EIO;
+ return 0;
+ }
+
+ /* Reply describes memory byte by byte,
+ each byte encoded as two hex characters. */
+
+ p = buf;
+ for (i = 0; i < len; i++)
+ {
+ if (p[0] == 0 || p[1] == 0)
+ /* Reply is short. This means that we were able to read only part
+ of what we wanted to. */
+ break;
+ myaddr[i] = fromhex (p[0]) * 16 + fromhex (p[1]);
+ p += 2;
+ }
+ return i;
+}
+
+/* Read or write LEN bytes from inferior memory at MEMADDR, transferring
+ to or from debugger address MYADDR. Write to inferior if SHOULD_WRITE is
+ nonzero. Returns length of data written or read; 0 for error. */
+
+/* ARGSUSED */
+static int
+remote_xfer_memory(memaddr, myaddr, len, should_write, target)
+ CORE_ADDR memaddr;
+ char *myaddr;
+ int len;
+ int should_write;
+ struct target_ops *target; /* ignored */
+{
+ int xfersize;
+ int bytes_xferred;
+ int total_xferred = 0;
+
+ while (len > 0)
+ {
+ if (len > MAXBUFBYTES)
+ xfersize = MAXBUFBYTES;
+ else
+ xfersize = len;
+
+ if (should_write)
+ bytes_xferred = remote_write_bytes (memaddr,
+ (unsigned char *)myaddr, xfersize);
+ else
+ bytes_xferred = remote_read_bytes (memaddr,
+ (unsigned char *)myaddr, xfersize);
+
+ /* If we get an error, we are done xferring. */
+ if (bytes_xferred == 0)
+ break;
+
+ memaddr += bytes_xferred;
+ myaddr += bytes_xferred;
+ len -= bytes_xferred;
+ total_xferred += bytes_xferred;
+ }
+ return total_xferred;
+}
+
+#if 0
+/* Enable after 4.12. */
+
+void
+remote_search (len, data, mask, startaddr, increment, lorange, hirange
+ addr_found, data_found)
+ int len;
+ char *data;
+ char *mask;
+ CORE_ADDR startaddr;
+ int increment;
+ CORE_ADDR lorange;
+ CORE_ADDR hirange;
+ CORE_ADDR *addr_found;
+ char *data_found;
+{
+ if (increment == -4 && len == 4)
+ {
+ long mask_long, data_long;
+ long data_found_long;
+ CORE_ADDR addr_we_found;
+ char buf[PBUFSIZ];
+ long returned_long[2];
+ char *p;
+
+ mask_long = extract_unsigned_integer (mask, len);
+ data_long = extract_unsigned_integer (data, len);
+ sprintf (buf, "t%x:%x,%x", startaddr, data_long, mask_long);
+ putpkt (buf);
+ getpkt (buf, 0);
+ if (buf[0] == '\0')
+ {
+ /* The stub doesn't support the 't' request. We might want to
+ remember this fact, but on the other hand the stub could be
+ switched on us. Maybe we should remember it only until
+ the next "target remote". */
+ generic_search (len, data, mask, startaddr, increment, lorange,
+ hirange, addr_found, data_found);
+ return;
+ }
+
+ if (buf[0] == 'E')
+ /* There is no correspondance between what the remote protocol uses
+ for errors and errno codes. We would like a cleaner way of
+ representing errors (big enough to include errno codes, bfd_error
+ codes, and others). But for now just use EIO. */
+ memory_error (EIO, startaddr);
+ p = buf;
+ addr_we_found = 0;
+ while (*p != '\0' && *p != ',')
+ addr_we_found = (addr_we_found << 4) + fromhex (*p++);
+ if (*p == '\0')
+ error ("Protocol error: short return for search");
+
+ data_found_long = 0;
+ while (*p != '\0' && *p != ',')
+ data_found_long = (data_found_long << 4) + fromhex (*p++);
+ /* Ignore anything after this comma, for future extensions. */
+
+ if (addr_we_found < lorange || addr_we_found >= hirange)
+ {
+ *addr_found = 0;
+ return;
+ }
+
+ *addr_found = addr_we_found;
+ *data_found = store_unsigned_integer (data_we_found, len);
+ return;
+ }
+ generic_search (len, data, mask, startaddr, increment, lorange,
+ hirange, addr_found, data_found);
+}
+#endif /* 0 */
+
+static void
+remote_files_info (ignore)
+ struct target_ops *ignore;
+{
+ puts_filtered ("Debugging a target over a serial line.\n");
+}
+
+/* Stuff for dealing with the packets which are part of this protocol.
+ See comment at top of file for details. */
+
+/* Read a single character from the remote end, masking it down to 7 bits. */
+
+static int
+readchar (timeout)
+ int timeout;
+{
+ int ch;
+
+ ch = SERIAL_READCHAR (remote_desc, timeout);
+
+ switch (ch)
+ {
+ case SERIAL_EOF:
+ error ("Remote connection closed");
+ case SERIAL_ERROR:
+ perror_with_name ("Remote communication error");
+ case SERIAL_TIMEOUT:
+ return ch;
+ default:
+ return ch & 0x7f;
+ }
+}
+
+/* Send the command in BUF to the remote machine,
+ and read the reply into BUF.
+ Report an error if we get an error reply. */
+
+static void
+remote_send (buf)
+ char *buf;
+{
+
+ putpkt (buf);
+ getpkt (buf, 0);
+
+ if (buf[0] == 'E')
+ error ("Remote failure reply: %s", buf);
+}
+
+/* Send a packet to the remote machine, with error checking.
+ The data of the packet is in BUF. */
+
+static void
+putpkt (buf)
+ char *buf;
+{
+ int i;
+ unsigned char csum = 0;
+ char buf2[PBUFSIZ];
+ int cnt = strlen (buf);
+ int ch;
+ char *p;
+
+ /* Copy the packet into buffer BUF2, encapsulating it
+ and giving it a checksum. */
+
+ if (cnt > sizeof(buf2) - 5) /* Prosanity check */
+ abort();
+
+ p = buf2;
+ *p++ = '$';
+
+ for (i = 0; i < cnt; i++)
+ {
+ csum += buf[i];
+ *p++ = buf[i];
+ }
+ *p++ = '#';
+ *p++ = tohex ((csum >> 4) & 0xf);
+ *p++ = tohex (csum & 0xf);
+
+ /* Send it over and over until we get a positive ack. */
+
+ while (1)
+ {
+ int started_error_output = 0;
+
+ if (remote_debug)
+ {
+ *p = '\0';
+ printf_unfiltered ("Sending packet: %s...", buf2);
+ gdb_flush(gdb_stdout);
+ }
+ if (SERIAL_WRITE (remote_desc, buf2, p - buf2))
+ perror_with_name ("putpkt: write failed");
+
+ /* read until either a timeout occurs (-2) or '+' is read */
+ while (1)
+ {
+ ch = readchar (remote_timeout);
+
+ if (remote_debug)
+ {
+ switch (ch)
+ {
+ case '+':
+ case SERIAL_TIMEOUT:
+ case '$':
+ if (started_error_output)
+ {
+ putc_unfiltered ('\n');
+ started_error_output = 0;
+ }
+ }
+ }
+
+ switch (ch)
+ {
+ case '+':
+ if (remote_debug)
+ printf_unfiltered("Ack\n");
+ return;
+ case SERIAL_TIMEOUT:
+ break; /* Retransmit buffer */
+ case '$':
+ {
+ unsigned char junkbuf[PBUFSIZ];
+
+ /* It's probably an old response, and we're out of sync. Just
+ gobble up the packet and ignore it. */
+ getpkt (junkbuf, 0);
+ continue; /* Now, go look for + */
+ }
+ default:
+ if (remote_debug)
+ {
+ if (!started_error_output)
+ {
+ started_error_output = 1;
+ printf_unfiltered ("putpkt: Junk: ");
+ }
+ putc_unfiltered (ch & 0177);
+ }
+ continue;
+ }
+ break; /* Here to retransmit */
+ }
+
+#if 0
+ /* This is wrong. If doing a long backtrace, the user should be
+ able to get out next time we call QUIT, without anything as violent
+ as interrupt_query. If we want to provide a way out of here
+ without getting to the next QUIT, it should be based on hitting
+ ^C twice as in remote_wait. */
+ if (quit_flag)
+ {
+ quit_flag = 0;
+ interrupt_query ();
+ }
+#endif
+ }
+}
+
+/* Come here after finding the start of the frame. Collect the rest into BUF,
+ verifying the checksum, length, and handling run-length compression.
+ Returns 0 on any error, 1 on success. */
+
+static int
+read_frame (buf)
+ char *buf;
+{
+ unsigned char csum;
+ char *bp;
+ int c;
+
+ csum = 0;
+ bp = buf;
+
+ while (1)
+ {
+ c = readchar (remote_timeout);
+
+ switch (c)
+ {
+ case SERIAL_TIMEOUT:
+ if (remote_debug)
+ puts_filtered ("Timeout in mid-packet, retrying\n");
+ return 0;
+ case '$':
+ if (remote_debug)
+ puts_filtered ("Saw new packet start in middle of old one\n");
+ return 0; /* Start a new packet, count retries */
+ case '#':
+ {
+ unsigned char pktcsum;
+
+ *bp = '\000';
+
+ pktcsum = fromhex (readchar (remote_timeout)) << 4
+ | fromhex (readchar (remote_timeout));
+
+ if (csum == pktcsum)
+ return 1;
+
+ printf_filtered ("Bad checksum, sentsum=0x%x, csum=0x%x, buf=",
+ pktcsum, csum);
+ puts_filtered (buf);
+ puts_filtered ("\n");
+
+ return 0;
+ }
+ case '*': /* Run length encoding */
+ c = readchar (remote_timeout);
+ csum += c;
+ c = c - ' ' + 3; /* Compute repeat count */
+
+ if (bp + c - 1 < buf + PBUFSIZ - 1)
+ {
+ memset (bp, *(bp - 1), c);
+ bp += c;
+ continue;
+ }
+
+ *bp = '\0';
+ printf_filtered ("Repeat count %d too large for buffer: ", c);
+ puts_filtered (buf);
+ puts_filtered ("\n");
+
+ return 0;
+ default:
+ if (bp < buf + PBUFSIZ - 1)
+ {
+ *bp++ = c;
+ csum += c;
+ continue;
+ }
+
+ *bp = '\0';
+ puts_filtered ("Remote packet too long: ");
+ puts_filtered (buf);
+ puts_filtered ("\n");
+
+ return 0;
+ }
+ }
+}
+
+/* Read a packet from the remote machine, with error checking,
+ and store it in BUF. BUF is expected to be of size PBUFSIZ.
+ If FOREVER, wait forever rather than timing out; this is used
+ while the target is executing user code. */
+
+static void
+getpkt (buf, forever)
+ char *buf;
+ int forever;
+{
+ char *bp;
+ int c;
+ int tries;
+ int timeout;
+ int val;
+
+ if (forever)
+ timeout = -1;
+ else
+ timeout = remote_timeout;
+
+#define MAX_TRIES 10
+
+ for (tries = 1; tries <= MAX_TRIES; tries++)
+ {
+ /* This can loop forever if the remote side sends us characters
+ continuously, but if it pauses, we'll get a zero from readchar
+ because of timeout. Then we'll count that as a retry. */
+
+ /* Note that we will only wait forever prior to the start of a packet.
+ After that, we expect characters to arrive at a brisk pace. They
+ should show up within remote_timeout intervals. */
+
+ do
+ {
+ c = readchar (timeout);
+
+ if (c == SERIAL_TIMEOUT)
+ {
+ if (remote_debug)
+ puts_filtered ("Timed out.\n");
+ goto retry;
+ }
+ }
+ while (c != '$');
+
+ /* We've found the start of a packet, now collect the data. */
+
+ val = read_frame (buf);
+
+ if (val == 1)
+ {
+ if (remote_debug)
+ fprintf_unfiltered (gdb_stderr, "Packet received: %s\n", buf);
+ SERIAL_WRITE (remote_desc, "+", 1);
+ return;
+ }
+
+ /* Try the whole thing again. */
+retry:
+ SERIAL_WRITE (remote_desc, "-", 1);
+ }
+
+ /* We have tried hard enough, and just can't receive the packet. Give up. */
+
+ printf_unfiltered ("Ignoring packet error, continuing...\n");
+ SERIAL_WRITE (remote_desc, "+", 1);
+}
+
+static void
+remote_kill ()
+{
+ putpkt ("k");
+ /* Don't wait for it to die. I'm not really sure it matters whether
+ we do or not. For the existing stubs, kill is a noop. */
+ target_mourn_inferior ();
+}
+
+static void
+remote_mourn ()
+{
+ unpush_target (&remote_ops);
+ generic_mourn_inferior ();
+}
+
+#ifdef REMOTE_BREAKPOINT
+
+/* On some machines, e.g. 68k, we may use a different breakpoint instruction
+ than other targets. */
+static unsigned char break_insn[] = REMOTE_BREAKPOINT;
+
+/* Check that it fits in BREAKPOINT_MAX bytes. */
+static unsigned char check_break_insn_size[BREAKPOINT_MAX] = REMOTE_BREAKPOINT;
+
+#else /* No REMOTE_BREAKPOINT. */
+
+/* Same old breakpoint instruction. This code does nothing different
+ than mem-break.c. */
+static unsigned char break_insn[] = BREAKPOINT;
+
+#endif /* No REMOTE_BREAKPOINT. */
+
+/* Insert a breakpoint on targets that don't have any better breakpoint
+ support. We read the contents of the target location and stash it,
+ then overwrite it with a breakpoint instruction. ADDR is the target
+ location in the target machine. CONTENTS_CACHE is a pointer to
+ memory allocated for saving the target contents. It is guaranteed
+ by the caller to be long enough to save sizeof BREAKPOINT bytes (this
+ is accomplished via BREAKPOINT_MAX). */
+
+static int
+remote_insert_breakpoint (addr, contents_cache)
+ CORE_ADDR addr;
+ char *contents_cache;
+{
+ int val;
+
+ val = target_read_memory (addr, contents_cache, sizeof break_insn);
+
+ if (val == 0)
+ val = target_write_memory (addr, (char *)break_insn, sizeof break_insn);
+
+ return val;
+}
+
+static int
+remote_remove_breakpoint (addr, contents_cache)
+ CORE_ADDR addr;
+ char *contents_cache;
+{
+ return target_write_memory (addr, contents_cache, sizeof break_insn);
+}
+
+/* Define the target subroutine names */
+
+struct target_ops remote_ops = {
+ "remote", /* to_shortname */
+ "Remote serial target in gdb-specific protocol", /* to_longname */
+ "Use a remote computer via a serial line, using a gdb-specific protocol.\n\
+Specify the serial device it is connected to (e.g. /dev/ttya).", /* to_doc */
+ remote_open, /* to_open */
+ remote_close, /* to_close */
+ NULL, /* to_attach */
+ remote_detach, /* to_detach */
+ remote_resume, /* to_resume */
+ remote_wait, /* to_wait */
+ remote_fetch_registers, /* to_fetch_registers */
+ remote_store_registers, /* to_store_registers */
+ remote_prepare_to_store, /* to_prepare_to_store */
+ remote_xfer_memory, /* to_xfer_memory */
+ remote_files_info, /* to_files_info */
+
+ remote_insert_breakpoint, /* to_insert_breakpoint */
+ remote_remove_breakpoint, /* to_remove_breakpoint */
+
+ NULL, /* to_terminal_init */
+ NULL, /* to_terminal_inferior */
+ NULL, /* to_terminal_ours_for_output */
+ NULL, /* to_terminal_ours */
+ NULL, /* to_terminal_info */
+ remote_kill, /* to_kill */
+ generic_load, /* to_load */
+ NULL, /* to_lookup_symbol */
+ NULL, /* to_create_inferior */
+ remote_mourn, /* to_mourn_inferior */
+ 0, /* to_can_run */
+ 0, /* to_notice_signals */
+ process_stratum, /* to_stratum */
+ NULL, /* to_next */
+ 1, /* to_has_all_memory */
+ 1, /* to_has_memory */
+ 1, /* to_has_stack */
+ 1, /* to_has_registers */
+ 1, /* to_has_execution */
+ NULL, /* sections */
+ NULL, /* sections_end */
+ OPS_MAGIC /* to_magic */
+};
+#endif /* Use remote. */
+
+void
+_initialize_remote ()
+{
+#if !defined(DONT_USE_REMOTE)
+ add_target (&remote_ops);
+#endif
+}
diff --git a/gnu/usr.bin/gdb/gdb/ser-unix.c b/gnu/usr.bin/gdb/gdb/ser-unix.c
new file mode 100644
index 0000000..1e5e1a6
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/ser-unix.c
@@ -0,0 +1,684 @@
+/* Serial interface for local (hardwired) serial ports on Un*x like systems
+ Copyright 1992, 1993, 1994 Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "defs.h"
+#include "serial.h"
+#include <fcntl.h>
+#include <sys/types.h>
+
+#if !defined (HAVE_TERMIOS) && !defined (HAVE_TERMIO) && !defined (HAVE_SGTTY)
+#define HAVE_SGTTY
+#endif
+
+#ifdef HAVE_TERMIOS
+#include <termios.h>
+#include <unistd.h>
+
+struct hardwire_ttystate
+{
+ struct termios termios;
+};
+#endif /* termios */
+
+#ifdef HAVE_TERMIO
+#include <termio.h>
+
+/* It is believed that all systems which have added job control to SVR3
+ (e.g. sco) have also added termios. Even if not, trying to figure out
+ all the variations (TIOCGPGRP vs. TCGETPGRP, etc.) would be pretty
+ bewildering. So we don't attempt it. */
+
+struct hardwire_ttystate
+{
+ struct termio termio;
+};
+#endif /* termio */
+
+#ifdef HAVE_SGTTY
+/* Needed for the code which uses select(). We would include <sys/select.h>
+ too if it existed on all systems. */
+#include <sys/time.h>
+
+#include <sgtty.h>
+
+struct hardwire_ttystate
+{
+ struct sgttyb sgttyb;
+ struct tchars tc;
+ struct ltchars ltc;
+ /* Line discipline flags. */
+ int lmode;
+};
+#endif /* sgtty */
+
+static int hardwire_open PARAMS ((serial_t scb, const char *name));
+static void hardwire_raw PARAMS ((serial_t scb));
+static int wait_for PARAMS ((serial_t scb, int timeout));
+static int hardwire_readchar PARAMS ((serial_t scb, int timeout));
+static int rate_to_code PARAMS ((int rate));
+static int hardwire_setbaudrate PARAMS ((serial_t scb, int rate));
+static int hardwire_write PARAMS ((serial_t scb, const char *str, int len));
+/* FIXME: static void hardwire_restore PARAMS ((serial_t scb)); */
+static void hardwire_close PARAMS ((serial_t scb));
+static int get_tty_state PARAMS ((serial_t scb, struct hardwire_ttystate *state));
+static int set_tty_state PARAMS ((serial_t scb, struct hardwire_ttystate *state));
+static serial_ttystate hardwire_get_tty_state PARAMS ((serial_t scb));
+static int hardwire_set_tty_state PARAMS ((serial_t scb, serial_ttystate state));
+
+/* Open up a real live device for serial I/O */
+
+static int
+hardwire_open(scb, name)
+ serial_t scb;
+ const char *name;
+{
+ scb->fd = open (name, O_RDWR);
+ if (scb->fd < 0)
+ return -1;
+
+ return 0;
+}
+
+static int
+get_tty_state(scb, state)
+ serial_t scb;
+ struct hardwire_ttystate *state;
+{
+#ifdef HAVE_TERMIOS
+ extern int errno;
+
+ if (tcgetattr(scb->fd, &state->termios) < 0)
+ return -1;
+
+ return 0;
+#endif
+
+#ifdef HAVE_TERMIO
+ if (ioctl (scb->fd, TCGETA, &state->termio) < 0)
+ return -1;
+ return 0;
+#endif
+
+#ifdef HAVE_SGTTY
+ if (ioctl (scb->fd, TIOCGETP, &state->sgttyb) < 0)
+ return -1;
+ if (ioctl (scb->fd, TIOCGETC, &state->tc) < 0)
+ return -1;
+ if (ioctl (scb->fd, TIOCGLTC, &state->ltc) < 0)
+ return -1;
+ if (ioctl (scb->fd, TIOCLGET, &state->lmode) < 0)
+ return -1;
+
+ return 0;
+#endif
+}
+
+static int
+set_tty_state(scb, state)
+ serial_t scb;
+ struct hardwire_ttystate *state;
+{
+#ifdef HAVE_TERMIOS
+ if (tcsetattr(scb->fd, TCSANOW, &state->termios) < 0)
+ return -1;
+
+ return 0;
+#endif
+
+#ifdef HAVE_TERMIO
+ if (ioctl (scb->fd, TCSETA, &state->termio) < 0)
+ return -1;
+ return 0;
+#endif
+
+#ifdef HAVE_SGTTY
+ if (ioctl (scb->fd, TIOCSETN, &state->sgttyb) < 0)
+ return -1;
+ if (ioctl (scb->fd, TIOCSETC, &state->tc) < 0)
+ return -1;
+ if (ioctl (scb->fd, TIOCSLTC, &state->ltc) < 0)
+ return -1;
+ if (ioctl (scb->fd, TIOCLSET, &state->lmode) < 0)
+ return -1;
+
+ return 0;
+#endif
+}
+
+static serial_ttystate
+hardwire_get_tty_state(scb)
+ serial_t scb;
+{
+ struct hardwire_ttystate *state;
+
+ state = (struct hardwire_ttystate *)xmalloc(sizeof *state);
+
+ if (get_tty_state(scb, state))
+ return NULL;
+
+ return (serial_ttystate)state;
+}
+
+static int
+hardwire_set_tty_state(scb, ttystate)
+ serial_t scb;
+ serial_ttystate ttystate;
+{
+ struct hardwire_ttystate *state;
+
+ state = (struct hardwire_ttystate *)ttystate;
+
+ return set_tty_state(scb, state);
+}
+
+static int
+hardwire_noflush_set_tty_state (scb, new_ttystate, old_ttystate)
+ serial_t scb;
+ serial_ttystate new_ttystate;
+ serial_ttystate old_ttystate;
+{
+ struct hardwire_ttystate new_state;
+ struct hardwire_ttystate *state = (struct hardwire_ttystate *) old_ttystate;
+
+ new_state = *(struct hardwire_ttystate *)new_ttystate;
+
+ /* Don't change in or out of raw mode; we don't want to flush input.
+ termio and termios have no such restriction; for them flushing input
+ is separate from setting the attributes. */
+
+#ifdef HAVE_SGTTY
+ if (state->sgttyb.sg_flags & RAW)
+ new_state.sgttyb.sg_flags |= RAW;
+ else
+ new_state.sgttyb.sg_flags &= ~RAW;
+
+ /* I'm not sure whether this is necessary; the manpage just mentions
+ RAW not CBREAK. */
+ if (state->sgttyb.sg_flags & CBREAK)
+ new_state.sgttyb.sg_flags |= CBREAK;
+ else
+ new_state.sgttyb.sg_flags &= ~CBREAK;
+#endif
+
+ return set_tty_state (scb, &new_state);
+}
+
+static void
+hardwire_print_tty_state (scb, ttystate)
+ serial_t scb;
+ serial_ttystate ttystate;
+{
+ struct hardwire_ttystate *state = (struct hardwire_ttystate *) ttystate;
+ int i;
+
+#ifdef HAVE_TERMIOS
+ printf_filtered ("c_iflag = 0x%x, c_oflag = 0x%x,\n",
+ state->termios.c_iflag, state->termios.c_oflag);
+ printf_filtered ("c_cflag = 0x%x, c_lflag = 0x%x\n",
+ state->termios.c_cflag, state->termios.c_lflag);
+#if 0
+ /* This not in POSIX, and is not really documented by those systems
+ which have it (at least not Sun). */
+ printf_filtered ("c_line = 0x%x.\n", state->termios.c_line);
+#endif
+ printf_filtered ("c_cc: ");
+ for (i = 0; i < NCCS; i += 1)
+ printf_filtered ("0x%x ", state->termios.c_cc[i]);
+ printf_filtered ("\n");
+#endif
+
+#ifdef HAVE_TERMIO
+ printf_filtered ("c_iflag = 0x%x, c_oflag = 0x%x,\n",
+ state->termio.c_iflag, state->termio.c_oflag);
+ printf_filtered ("c_cflag = 0x%x, c_lflag = 0x%x, c_line = 0x%x.\n",
+ state->termio.c_cflag, state->termio.c_lflag,
+ state->termio.c_line);
+ printf_filtered ("c_cc: ");
+ for (i = 0; i < NCC; i += 1)
+ printf_filtered ("0x%x ", state->termio.c_cc[i]);
+ printf_filtered ("\n");
+#endif
+
+#ifdef HAVE_SGTTY
+ printf_filtered ("sgttyb.sg_flags = 0x%x.\n", state->sgttyb.sg_flags);
+
+ printf_filtered ("tchars: ");
+ for (i = 0; i < (int)sizeof (struct tchars); i++)
+ printf_filtered ("0x%x ", ((unsigned char *)&state->tc)[i]);
+ printf_filtered ("\n");
+
+ printf_filtered ("ltchars: ");
+ for (i = 0; i < (int)sizeof (struct ltchars); i++)
+ printf_filtered ("0x%x ", ((unsigned char *)&state->ltc)[i]);
+ printf_filtered ("\n");
+
+ printf_filtered ("lmode: 0x%x\n", state->lmode);
+#endif
+}
+
+static int
+hardwire_flush_output (scb)
+ serial_t scb;
+{
+#ifdef HAVE_TERMIOS
+ return tcflush (scb->fd, TCOFLUSH);
+#endif
+
+#ifdef HAVE_TERMIO
+ return ioctl (scb->fd, TCFLSH, 1);
+#endif
+
+#ifdef HAVE_SGTTY
+ /* This flushes both input and output, but we can't do better. */
+ return ioctl (scb->fd, TIOCFLUSH, 0);
+#endif
+}
+
+static int
+hardwire_flush_input (scb)
+ serial_t scb;
+{
+#ifdef HAVE_TERMIOS
+ return tcflush (scb->fd, TCIFLUSH);
+#endif
+
+#ifdef HAVE_TERMIO
+ return ioctl (scb->fd, TCFLSH, 0);
+#endif
+
+#ifdef HAVE_SGTTY
+ /* This flushes both input and output, but we can't do better. */
+ return ioctl (scb->fd, TIOCFLUSH, 0);
+#endif
+}
+
+static int
+hardwire_send_break (scb)
+ serial_t scb;
+{
+#ifdef HAVE_TERMIOS
+ return tcsendbreak (scb->fd, 0);
+#endif
+
+#ifdef HAVE_TERMIO
+ return ioctl (scb->fd, TCSBRK, 0);
+#endif
+
+#ifdef HAVE_SGTTY
+ {
+ int status;
+ struct timeval timeout;
+
+ status = ioctl (scb->fd, TIOCSBRK, 0);
+
+ /* Can't use usleep; it doesn't exist in BSD 4.2. */
+ /* Note that if this select() is interrupted by a signal it will not wait
+ the full length of time. I think that is OK. */
+ timeout.tv_sec = 0;
+ timeout.tv_usec = 250000;
+ select (0, 0, 0, 0, &timeout);
+ status = ioctl (scb->fd, TIOCCBRK, 0);
+ return status;
+ }
+#endif
+}
+
+static void
+hardwire_raw(scb)
+ serial_t scb;
+{
+ struct hardwire_ttystate state;
+
+ if (get_tty_state(scb, &state))
+ fprintf_unfiltered(gdb_stderr, "get_tty_state failed: %s\n", safe_strerror(errno));
+
+#ifdef HAVE_TERMIOS
+ state.termios.c_iflag = 0;
+ state.termios.c_oflag = 0;
+ state.termios.c_lflag = 0;
+ state.termios.c_cflag &= ~(CSIZE|PARENB);
+ state.termios.c_cflag |= CLOCAL | CS8;
+ state.termios.c_cc[VMIN] = 0;
+ state.termios.c_cc[VTIME] = 0;
+#endif
+
+#ifdef HAVE_TERMIO
+ state.termio.c_iflag = 0;
+ state.termio.c_oflag = 0;
+ state.termio.c_lflag = 0;
+ state.termio.c_cflag &= ~(CSIZE|PARENB);
+ state.termio.c_cflag |= CLOCAL | CS8;
+ state.termio.c_cc[VMIN] = 0;
+ state.termio.c_cc[VTIME] = 0;
+#endif
+
+#ifdef HAVE_SGTTY
+ state.sgttyb.sg_flags |= RAW | ANYP;
+ state.sgttyb.sg_flags &= ~(CBREAK | ECHO);
+#endif
+
+ scb->current_timeout = 0;
+
+ if (set_tty_state (scb, &state))
+ fprintf_unfiltered(gdb_stderr, "set_tty_state failed: %s\n", safe_strerror(errno));
+}
+
+/* Wait for input on scb, with timeout seconds. Returns 0 on success,
+ otherwise SERIAL_TIMEOUT or SERIAL_ERROR.
+
+ For termio{s}, we actually just setup VTIME if necessary, and let the
+ timeout occur in the read() in hardwire_read().
+ */
+
+static int
+wait_for(scb, timeout)
+ serial_t scb;
+ int timeout;
+{
+ scb->timeout_remaining = 0;
+
+#ifdef HAVE_SGTTY
+ {
+ struct timeval tv;
+ fd_set readfds;
+
+ FD_ZERO (&readfds);
+
+ tv.tv_sec = timeout;
+ tv.tv_usec = 0;
+
+ FD_SET(scb->fd, &readfds);
+
+ while (1)
+ {
+ int numfds;
+
+ if (timeout >= 0)
+ numfds = select(scb->fd+1, &readfds, 0, 0, &tv);
+ else
+ numfds = select(scb->fd+1, &readfds, 0, 0, 0);
+
+ if (numfds <= 0)
+ if (numfds == 0)
+ return SERIAL_TIMEOUT;
+ else if (errno == EINTR)
+ continue;
+ else
+ return SERIAL_ERROR; /* Got an error from select or poll */
+
+ return 0;
+ }
+ }
+#endif /* HAVE_SGTTY */
+
+#if defined HAVE_TERMIO || defined HAVE_TERMIOS
+ if (timeout == scb->current_timeout)
+ return 0;
+
+ scb->current_timeout = timeout;
+
+ {
+ struct hardwire_ttystate state;
+
+ if (get_tty_state(scb, &state))
+ fprintf_unfiltered(gdb_stderr, "get_tty_state failed: %s\n", safe_strerror(errno));
+
+#ifdef HAVE_TERMIOS
+ if (timeout < 0)
+ {
+ /* No timeout. */
+ state.termios.c_cc[VTIME] = 0;
+ state.termios.c_cc[VMIN] = 1;
+ }
+ else
+ {
+ state.termios.c_cc[VMIN] = 0;
+ state.termios.c_cc[VTIME] = timeout * 10;
+ if (state.termios.c_cc[VTIME] != timeout * 10)
+ {
+
+ /* If c_cc is an 8-bit signed character, we can't go
+ bigger than this. If it is always unsigned, we could use
+ 25. */
+
+ scb->current_timeout = 12;
+ state.termios.c_cc[VTIME] = scb->current_timeout * 10;
+ scb->timeout_remaining = timeout - scb->current_timeout;
+ }
+ }
+#endif
+
+#ifdef HAVE_TERMIO
+ if (timeout < 0)
+ {
+ /* No timeout. */
+ state.termio.c_cc[VTIME] = 0;
+ state.termio.c_cc[VMIN] = 1;
+ }
+ else
+ {
+ state.termio.c_cc[VMIN] = 0;
+ state.termio.c_cc[VTIME] = timeout * 10;
+ if (state.termio.c_cc[VTIME] != timeout * 10)
+ {
+ /* If c_cc is an 8-bit signed character, we can't go
+ bigger than this. If it is always unsigned, we could use
+ 25. */
+
+ scb->current_timeout = 12;
+ state.termio.c_cc[VTIME] = scb->current_timeout * 10;
+ scb->timeout_remaining = timeout - scb->current_timeout;
+ }
+ }
+#endif
+
+ if (set_tty_state (scb, &state))
+ fprintf_unfiltered(gdb_stderr, "set_tty_state failed: %s\n", safe_strerror(errno));
+
+ return 0;
+ }
+#endif /* HAVE_TERMIO || HAVE_TERMIOS */
+}
+
+/* Read a character with user-specified timeout. TIMEOUT is number of seconds
+ to wait, or -1 to wait forever. Use timeout of 0 to effect a poll. Returns
+ char if successful. Returns SERIAL_TIMEOUT if timeout expired, EOF if line
+ dropped dead, or SERIAL_ERROR for any other error (see errno in that case). */
+
+static int
+hardwire_readchar(scb, timeout)
+ serial_t scb;
+ int timeout;
+{
+ int status;
+
+ if (scb->bufcnt-- > 0)
+ return *scb->bufp++;
+
+ while (1)
+ {
+ status = wait_for (scb, timeout);
+
+ if (status < 0)
+ return status;
+
+ scb->bufcnt = read (scb->fd, scb->buf, BUFSIZ);
+
+ if (scb->bufcnt <= 0)
+ {
+ if (scb->bufcnt == 0)
+ {
+ /* Zero characters means timeout (it could also be EOF, but
+ we don't (yet at least) distinguish). */
+ if (scb->timeout_remaining > 0)
+ {
+ timeout = scb->timeout_remaining;
+ continue;
+ }
+ else
+ return SERIAL_TIMEOUT;
+ }
+ else if (errno == EINTR)
+ continue;
+ else
+ return SERIAL_ERROR; /* Got an error from read */
+ }
+
+ scb->bufcnt--;
+ scb->bufp = scb->buf;
+ return *scb->bufp++;
+ }
+}
+
+#ifndef B19200
+#define B19200 EXTA
+#endif
+
+#ifndef B38400
+#define B38400 EXTB
+#endif
+
+/* Translate baud rates from integers to damn B_codes. Unix should
+ have outgrown this crap years ago, but even POSIX wouldn't buck it. */
+
+static struct
+{
+ int rate;
+ int code;
+}
+baudtab[] =
+{
+ {50, B50},
+ {75, B75},
+ {110, B110},
+ {134, B134},
+ {150, B150},
+ {200, B200},
+ {300, B300},
+ {600, B600},
+ {1200, B1200},
+ {1800, B1800},
+ {2400, B2400},
+ {4800, B4800},
+ {9600, B9600},
+ {19200, B19200},
+ {38400, B38400},
+ {-1, -1},
+};
+
+static int
+rate_to_code(rate)
+ int rate;
+{
+ int i;
+
+ for (i = 0; baudtab[i].rate != -1; i++)
+ if (rate == baudtab[i].rate)
+ return baudtab[i].code;
+
+ return -1;
+}
+
+static int
+hardwire_setbaudrate(scb, rate)
+ serial_t scb;
+ int rate;
+{
+ struct hardwire_ttystate state;
+
+ if (get_tty_state(scb, &state))
+ return -1;
+
+#ifdef HAVE_TERMIOS
+ cfsetospeed (&state.termios, rate_to_code (rate));
+ cfsetispeed (&state.termios, rate_to_code (rate));
+#endif
+
+#ifdef HAVE_TERMIO
+#ifndef CIBAUD
+#define CIBAUD CBAUD
+#endif
+
+ state.termio.c_cflag &= ~(CBAUD | CIBAUD);
+ state.termio.c_cflag |= rate_to_code (rate);
+#endif
+
+#ifdef HAVE_SGTTY
+ state.sgttyb.sg_ispeed = rate_to_code (rate);
+ state.sgttyb.sg_ospeed = rate_to_code (rate);
+#endif
+
+ return set_tty_state (scb, &state);
+}
+
+static int
+hardwire_write(scb, str, len)
+ serial_t scb;
+ const char *str;
+ int len;
+{
+ int cc;
+
+ while (len > 0)
+ {
+ cc = write(scb->fd, str, len);
+
+ if (cc < 0)
+ return 1;
+ len -= cc;
+ str += cc;
+ }
+ return 0;
+}
+
+static void
+hardwire_close(scb)
+ serial_t scb;
+{
+ if (scb->fd < 0)
+ return;
+
+ close(scb->fd);
+ scb->fd = -1;
+}
+
+static struct serial_ops hardwire_ops =
+{
+ "hardwire",
+ 0,
+ hardwire_open,
+ hardwire_close,
+ hardwire_readchar,
+ hardwire_write,
+ hardwire_flush_output,
+ hardwire_flush_input,
+ hardwire_send_break,
+ hardwire_raw,
+ hardwire_get_tty_state,
+ hardwire_set_tty_state,
+ hardwire_print_tty_state,
+ hardwire_noflush_set_tty_state,
+ hardwire_setbaudrate,
+};
+
+void
+_initialize_ser_hardwire ()
+{
+ serial_add_interface (&hardwire_ops);
+}
diff --git a/gnu/usr.bin/gdb/gdb/serial.c b/gnu/usr.bin/gdb/gdb/serial.c
new file mode 100644
index 0000000..e15b0c8
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/serial.c
@@ -0,0 +1,265 @@
+/* Generic serial interface routines
+ Copyright 1992, 1993 Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "defs.h"
+#include "serial.h"
+
+/* Linked list of serial I/O handlers */
+
+static struct serial_ops *serial_ops_list = NULL;
+
+/* This is the last serial stream opened. Used by connect command. */
+
+static serial_t last_serial_opened = NULL;
+
+static struct serial_ops *
+serial_interface_lookup (name)
+ char *name;
+{
+ struct serial_ops *ops;
+
+ for (ops = serial_ops_list; ops; ops = ops->next)
+ if (strcmp (name, ops->name) == 0)
+ return ops;
+
+ return NULL;
+}
+
+void
+serial_add_interface(optable)
+ struct serial_ops *optable;
+{
+ optable->next = serial_ops_list;
+ serial_ops_list = optable;
+}
+
+/* Open up a device or a network socket, depending upon the syntax of NAME. */
+
+serial_t
+serial_open (name)
+ const char *name;
+{
+ serial_t scb;
+ struct serial_ops *ops;
+
+ if (strcmp (name, "pc") == 0)
+ ops = serial_interface_lookup ("pc");
+ else if (strchr (name, ':'))
+ ops = serial_interface_lookup ("tcp");
+ else
+ ops = serial_interface_lookup ("hardwire");
+
+ if (!ops)
+ return NULL;
+
+ scb = (serial_t)xmalloc (sizeof (struct _serial_t));
+
+ scb->ops = ops;
+
+ scb->bufcnt = 0;
+ scb->bufp = scb->buf;
+
+ if (scb->ops->open(scb, name))
+ {
+ free (scb);
+ return NULL;
+ }
+
+ last_serial_opened = scb;
+
+ return scb;
+}
+
+serial_t
+serial_fdopen(fd)
+ const int fd;
+{
+ serial_t scb;
+ struct serial_ops *ops;
+
+ ops = serial_interface_lookup ("hardwire");
+
+ if (!ops)
+ return NULL;
+
+ scb = (serial_t)xmalloc (sizeof (struct _serial_t));
+
+ scb->ops = ops;
+
+ scb->bufcnt = 0;
+ scb->bufp = scb->buf;
+
+ scb->fd = fd;
+
+ last_serial_opened = scb;
+
+ return scb;
+}
+
+void
+serial_close(scb)
+ serial_t scb;
+{
+ last_serial_opened = NULL;
+
+/* This is bogus. It's not our fault if you pass us a bad scb...! Rob, you
+ should fix your code instead. */
+
+ if (!scb)
+ return;
+
+ scb->ops->close(scb);
+ free(scb);
+}
+
+#if 0
+/*
+The connect command is #if 0 because I hadn't thought of an elegant
+way to wait for I/O on two serial_t's simultaneously. Two solutions
+came to mind:
+
+ 1) Fork, and have have one fork handle the to user direction,
+ and have the other hand the to target direction. This
+ obviously won't cut it for MSDOS.
+
+ 2) Use something like select. This assumes that stdin and
+ the target side can both be waited on via the same
+ mechanism. This may not be true for DOS, if GDB is
+ talking to the target via a TCP socket.
+-grossman, 8 Jun 93
+*/
+
+/* Connect the user directly to the remote system. This command acts just like
+ the 'cu' or 'tip' command. Use <CR>~. or <CR>~^D to break out. */
+
+static serial_t tty_desc; /* Controlling terminal */
+
+static void
+cleanup_tty(ttystate)
+ serial_ttystate ttystate;
+{
+ printf_unfiltered ("\r\n[Exiting connect mode]\r\n");
+ SERIAL_SET_TTY_STATE (tty_desc, ttystate);
+ free (ttystate);
+ SERIAL_CLOSE (tty_desc);
+}
+
+static void
+connect_command (args, fromtty)
+ char *args;
+ int fromtty;
+{
+ int c;
+ char cur_esc = 0;
+ serial_ttystate ttystate;
+ serial_t port_desc; /* TTY port */
+
+ dont_repeat();
+
+ if (args)
+ fprintf_unfiltered(gdb_stderr, "This command takes no args. They have been ignored.\n");
+
+ printf_unfiltered("[Entering connect mode. Use ~. or ~^D to escape]\n");
+
+ tty_desc = SERIAL_FDOPEN (0);
+ port_desc = last_serial_opened;
+
+ ttystate = SERIAL_GET_TTY_STATE (tty_desc);
+
+ SERIAL_RAW (tty_desc);
+ SERIAL_RAW (port_desc);
+
+ make_cleanup (cleanup_tty, ttystate);
+
+ while (1)
+ {
+ int mask;
+
+ mask = SERIAL_WAIT_2 (tty_desc, port_desc, -1);
+
+ if (mask & 2)
+ { /* tty input */
+ char cx;
+
+ while (1)
+ {
+ c = SERIAL_READCHAR(tty_desc, 0);
+
+ if (c == SERIAL_TIMEOUT)
+ break;
+
+ if (c < 0)
+ perror_with_name("connect");
+
+ cx = c;
+ SERIAL_WRITE(port_desc, &cx, 1);
+
+ switch (cur_esc)
+ {
+ case 0:
+ if (c == '\r')
+ cur_esc = c;
+ break;
+ case '\r':
+ if (c == '~')
+ cur_esc = c;
+ else
+ cur_esc = 0;
+ break;
+ case '~':
+ if (c == '.' || c == '\004')
+ return;
+ else
+ cur_esc = 0;
+ }
+ }
+ }
+
+ if (mask & 1)
+ { /* Port input */
+ char cx;
+
+ while (1)
+ {
+ c = SERIAL_READCHAR(port_desc, 0);
+
+ if (c == SERIAL_TIMEOUT)
+ break;
+
+ if (c < 0)
+ perror_with_name("connect");
+
+ cx = c;
+
+ SERIAL_WRITE(tty_desc, &cx, 1);
+ }
+ }
+ }
+}
+#endif /* 0 */
+
+void
+_initialize_serial ()
+{
+#if 0
+ add_com ("connect", class_obscure, connect_command,
+ "Connect the terminal directly up to the command monitor.\n\
+Use <CR>~. or <CR>~^D to break out.");
+#endif /* 0 */
+}
diff --git a/gnu/usr.bin/gdb/gdb/serial.h b/gnu/usr.bin/gdb/gdb/serial.h
new file mode 100644
index 0000000..9e669cb
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/serial.h
@@ -0,0 +1,158 @@
+/* Remote serial support interface definitions for GDB, the GNU Debugger.
+ Copyright 1992, 1993 Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#ifndef SERIAL_H
+#define SERIAL_H
+
+/* Terminal state pointer. This is specific to each type of interface. */
+
+typedef PTR serial_ttystate;
+
+struct _serial_t
+{
+ int fd; /* File descriptor */
+ struct serial_ops *ops; /* Function vector */
+ serial_ttystate ttystate; /* Not used (yet) */
+ int bufcnt; /* Amount of data in receive buffer */
+ unsigned char *bufp; /* Current byte */
+ unsigned char buf[BUFSIZ]; /* Da buffer itself */
+ int current_timeout; /* (termio{s} only), last value of VTIME */
+ /* ser-unix.c termio{,s} only, we still need to wait for this many more
+ seconds. */
+ int timeout_remaining;
+};
+
+typedef struct _serial_t *serial_t;
+
+struct serial_ops {
+ char *name;
+ struct serial_ops *next;
+ int (*open) PARAMS ((serial_t, const char *name));
+ void (*close) PARAMS ((serial_t));
+ int (*readchar) PARAMS ((serial_t, int timeout));
+ int (*write) PARAMS ((serial_t, const char *str, int len));
+ int (*flush_output) PARAMS ((serial_t));
+ int (*flush_input) PARAMS ((serial_t));
+ int (*send_break) PARAMS ((serial_t));
+ void (*go_raw) PARAMS ((serial_t));
+ serial_ttystate (*get_tty_state) PARAMS ((serial_t));
+ int (*set_tty_state) PARAMS ((serial_t, serial_ttystate));
+ void (*print_tty_state) PARAMS ((serial_t, serial_ttystate));
+ int (*noflush_set_tty_state)
+ PARAMS ((serial_t, serial_ttystate, serial_ttystate));
+ int (*setbaudrate) PARAMS ((serial_t, int rate));
+};
+
+/* Add a new serial interface to the interface list */
+
+void serial_add_interface PARAMS ((struct serial_ops *optable));
+
+serial_t serial_open PARAMS ((const char *name));
+
+serial_t serial_fdopen PARAMS ((const int fd));
+
+/* For most routines, if a failure is indicated, then errno should be
+ examined. */
+
+/* Try to open NAME. Returns a new serial_t on success, NULL on failure.
+ */
+
+#define SERIAL_OPEN(NAME) serial_open(NAME)
+
+/* Open a new serial stream using a file handle. */
+
+#define SERIAL_FDOPEN(FD) serial_fdopen(FD)
+
+/* Flush pending output. Might also flush input (if this system can't flush
+ only output). */
+
+#define SERIAL_FLUSH_OUTPUT(SERIAL_T) \
+ ((SERIAL_T)->ops->flush_output((SERIAL_T)))
+
+/* Flush pending input. Might also flush output (if this system can't flush
+ only input). */
+
+#define SERIAL_FLUSH_INPUT(SERIAL_T)\
+ ((*(SERIAL_T)->ops->flush_input) ((SERIAL_T)))
+
+/* Send a break between 0.25 and 0.5 seconds long. */
+
+#define SERIAL_SEND_BREAK(SERIAL_T) \
+ ((*(SERIAL_T)->ops->send_break) (SERIAL_T))
+
+/* Turn the port into raw mode. */
+
+#define SERIAL_RAW(SERIAL_T) (SERIAL_T)->ops->go_raw((SERIAL_T))
+
+/* Return a pointer to a newly malloc'd ttystate containing the state
+ of the tty. */
+#define SERIAL_GET_TTY_STATE(SERIAL_T) (SERIAL_T)->ops->get_tty_state((SERIAL_T))
+
+/* Set the state of the tty to TTYSTATE. The change is immediate.
+ When changing to or from raw mode, input might be discarded.
+ Returns 0 for success, negative value for error (in which case errno
+ contains the error). */
+#define SERIAL_SET_TTY_STATE(SERIAL_T, TTYSTATE) (SERIAL_T)->ops->set_tty_state((SERIAL_T), (TTYSTATE))
+
+/* printf_filtered a user-comprehensible description of ttystate. */
+#define SERIAL_PRINT_TTY_STATE(SERIAL_T, TTYSTATE) \
+ ((*((SERIAL_T)->ops->print_tty_state)) ((SERIAL_T), (TTYSTATE)))
+
+/* Set the tty state to NEW_TTYSTATE, where OLD_TTYSTATE is the
+ current state (generally obtained from a recent call to
+ SERIAL_GET_TTY_STATE), but be careful not to discard any input.
+ This means that we never switch in or out of raw mode, even
+ if NEW_TTYSTATE specifies a switch. */
+#define SERIAL_NOFLUSH_SET_TTY_STATE(SERIAL_T, NEW_TTYSTATE, OLD_TTYSTATE) \
+ ((*((SERIAL_T)->ops->noflush_set_tty_state)) \
+ ((SERIAL_T), (NEW_TTYSTATE), (OLD_TTYSTATE)))
+
+/* Read one char from the serial device with TIMEOUT seconds to wait
+ or -1 to wait forever. Use timeout of 0 to effect a poll. Returns
+ char if ok, else one of the following codes. Note that all error
+ codes are guaranteed to be < 0. */
+
+#define SERIAL_ERROR -1 /* General error, see errno for details */
+#define SERIAL_TIMEOUT -2
+#define SERIAL_EOF -3
+
+#define SERIAL_READCHAR(SERIAL_T, TIMEOUT) ((SERIAL_T)->ops->readchar((SERIAL_T), TIMEOUT))
+
+/* Set the baudrate to the decimal value supplied. Returns 0 for success,
+ -1 for failure. */
+
+#define SERIAL_SETBAUDRATE(SERIAL_T, RATE) ((SERIAL_T)->ops->setbaudrate((SERIAL_T), RATE))
+
+/* Write LEN chars from STRING to the port SERIAL_T. Returns 0 for
+ success, non-zero for failure. */
+
+#define SERIAL_WRITE(SERIAL_T, STRING, LEN) ((SERIAL_T)->ops->write((SERIAL_T), STRING, LEN))
+
+/* Push out all buffers, close the device and destroy SERIAL_T. */
+
+void serial_close PARAMS ((serial_t));
+
+#define SERIAL_CLOSE(SERIAL_T) serial_close(SERIAL_T)
+
+/* Destroy SERIAL_T without doing the rest of the stuff that SERIAL_CLOSE
+ does. */
+
+#define SERIAL_UN_FDOPEN(SERIAL_T) (free (SERIAL_T))
+
+#endif /* SERIAL_H */
diff --git a/gnu/usr.bin/gdb/gdb/signals.h b/gnu/usr.bin/gdb/gdb/signals.h
new file mode 100644
index 0000000..08fa606
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/signals.h
@@ -0,0 +1,27 @@
+/* Signal handler definitions for GDB, the GNU Debugger.
+ Copyright (C) 1986, 1989 Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+
+/* This file is almost the same as including <signal.h> except that it
+ eliminates certain signal names when job control is not supported,
+ (or, on some systems, when job control is there but doesn't work
+ the way GDB expects it to work). */
+/* This has been superceded by the job_control variable in serial.h. */
+
+#include <signal.h>
diff --git a/gnu/usr.bin/gdb/gdb/solib.c b/gnu/usr.bin/gdb/gdb/solib.c
new file mode 100644
index 0000000..55eaba7
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/solib.c
@@ -0,0 +1,1549 @@
+/* Handle SunOS and SVR4 shared libraries for GDB, the GNU Debugger.
+ Copyright 1990, 1991, 1992, 1993, 1994 Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+
+#include "defs.h"
+
+#include <sys/types.h>
+#include <signal.h>
+#include <string.h>
+#ifdef __FreeBSD__
+#include <a.out.h>
+#endif
+#include <link.h>
+#include <sys/param.h>
+#include <fcntl.h>
+
+#ifndef SVR4_SHARED_LIBS
+ /* SunOS shared libs need the nlist structure. */
+#include <a.out.h>
+#else
+#include "libelf.h"
+#ifndef DT_MIPS_RLD_MAP
+#include "elf/mips.h"
+#endif
+#endif
+
+#include "symtab.h"
+#include "bfd.h"
+#include "symfile.h"
+#include "objfiles.h"
+#include "gdbcore.h"
+#include "command.h"
+#include "target.h"
+#include "frame.h"
+#include "gnuregex.h"
+#include "inferior.h"
+#include "language.h"
+
+#define MAX_PATH_SIZE 256 /* FIXME: Should be dynamic */
+
+/* On SVR4 systems, for the initial implementation, use some runtime startup
+ symbol as the "startup mapping complete" breakpoint address. The models
+ for SunOS and SVR4 dynamic linking debugger support are different in that
+ SunOS hits one breakpoint when all mapping is complete while using the SVR4
+ debugger support takes two breakpoint hits for each file mapped, and
+ there is no way to know when the "last" one is hit. Both these
+ mechanisms should be tied to a "breakpoint service routine" that
+ gets automatically executed whenever one of the breakpoints indicating
+ a change in mapping is hit. This is a future enhancement. (FIXME) */
+
+#define BKPT_AT_SYMBOL 1
+
+#if defined (BKPT_AT_SYMBOL) && defined (SVR4_SHARED_LIBS)
+static char *bkpt_names[] = {
+#ifdef SOLIB_BKPT_NAME
+ SOLIB_BKPT_NAME, /* Prefer configured name if it exists. */
+#endif
+ "_start",
+ "main",
+ NULL
+};
+#endif
+
+/* Symbols which are used to locate the base of the link map structures. */
+
+#ifndef SVR4_SHARED_LIBS
+static char *debug_base_symbols[] = {
+ "_DYNAMIC",
+ NULL
+};
+#endif
+
+/* local data declarations */
+
+#ifndef SVR4_SHARED_LIBS
+
+#define LM_ADDR(so) ((so) -> lm.lm_addr)
+#define LM_NEXT(so) ((so) -> lm.lm_next)
+#define LM_NAME(so) ((so) -> lm.lm_name)
+/* Test for first link map entry; first entry is a shared library. */
+#define IGNORE_FIRST_LINK_MAP_ENTRY(x) (0)
+static struct link_dynamic dynamic_copy;
+static struct link_dynamic_2 ld_2_copy;
+static struct ld_debug debug_copy;
+static CORE_ADDR debug_addr;
+static CORE_ADDR flag_addr;
+
+#else /* SVR4_SHARED_LIBS */
+
+#define LM_ADDR(so) ((so) -> lm.l_addr)
+#define LM_NEXT(so) ((so) -> lm.l_next)
+#define LM_NAME(so) ((so) -> lm.l_name)
+/* Test for first link map entry; first entry is the exec-file. */
+#define IGNORE_FIRST_LINK_MAP_ENTRY(x) ((x).l_prev == NULL)
+static struct r_debug debug_copy;
+char shadow_contents[BREAKPOINT_MAX]; /* Stash old bkpt addr contents */
+
+#endif /* !SVR4_SHARED_LIBS */
+
+struct so_list {
+ struct so_list *next; /* next structure in linked list */
+ struct link_map lm; /* copy of link map from inferior */
+ struct link_map *lmaddr; /* addr in inferior lm was read from */
+ CORE_ADDR lmend; /* upper addr bound of mapped object */
+ char so_name[MAX_PATH_SIZE]; /* shared object lib name (FIXME) */
+ char symbols_loaded; /* flag: symbols read in yet? */
+ char from_tty; /* flag: print msgs? */
+ struct objfile *objfile; /* objfile for loaded lib */
+ struct section_table *sections;
+ struct section_table *sections_end;
+ struct section_table *textsection;
+ bfd *abfd;
+};
+
+static struct so_list *so_list_head; /* List of known shared objects */
+static CORE_ADDR debug_base; /* Base of dynamic linker structures */
+static CORE_ADDR breakpoint_addr; /* Address where end bkpt is set */
+
+extern int
+fdmatch PARAMS ((int, int)); /* In libiberty */
+
+/* Local function prototypes */
+
+static void
+special_symbol_handling PARAMS ((struct so_list *));
+
+static void
+sharedlibrary_command PARAMS ((char *, int));
+
+static int
+enable_break PARAMS ((void));
+
+static int
+disable_break PARAMS ((void));
+
+static void
+info_sharedlibrary_command PARAMS ((char *, int));
+
+static int
+symbol_add_stub PARAMS ((char *));
+
+static struct so_list *
+find_solib PARAMS ((struct so_list *));
+
+static struct link_map *
+first_link_map_member PARAMS ((void));
+
+static CORE_ADDR
+locate_base PARAMS ((void));
+
+static void
+solib_map_sections PARAMS ((struct so_list *));
+
+#ifdef SVR4_SHARED_LIBS
+
+static CORE_ADDR
+elf_locate_base PARAMS ((void));
+
+#else
+
+static void
+solib_add_common_symbols PARAMS ((struct rtc_symb *, struct objfile *));
+
+#endif
+
+/*
+
+LOCAL FUNCTION
+
+ solib_map_sections -- open bfd and build sections for shared lib
+
+SYNOPSIS
+
+ static void solib_map_sections (struct so_list *so)
+
+DESCRIPTION
+
+ Given a pointer to one of the shared objects in our list
+ of mapped objects, use the recorded name to open a bfd
+ descriptor for the object, build a section table, and then
+ relocate all the section addresses by the base address at
+ which the shared object was mapped.
+
+FIXMES
+
+ In most (all?) cases the shared object file name recorded in the
+ dynamic linkage tables will be a fully qualified pathname. For
+ cases where it isn't, do we really mimic the systems search
+ mechanism correctly in the below code (particularly the tilde
+ expansion stuff?).
+ */
+
+static void
+solib_map_sections (so)
+ struct so_list *so;
+{
+ char *filename;
+ char *scratch_pathname;
+ int scratch_chan;
+ struct section_table *p;
+ struct cleanup *old_chain;
+ bfd *abfd;
+
+ filename = tilde_expand (so -> so_name);
+ old_chain = make_cleanup (free, filename);
+
+ scratch_chan = openp (getenv ("PATH"), 1, filename, O_RDONLY, 0,
+ &scratch_pathname);
+ if (scratch_chan < 0)
+ {
+ scratch_chan = openp (getenv ("LD_LIBRARY_PATH"), 1, filename,
+ O_RDONLY, 0, &scratch_pathname);
+ }
+ if (scratch_chan < 0)
+ {
+ perror_with_name (filename);
+ }
+ /* Leave scratch_pathname allocated. abfd->name will point to it. */
+
+ abfd = bfd_fdopenr (scratch_pathname, gnutarget, scratch_chan);
+ if (!abfd)
+ {
+ close (scratch_chan);
+ error ("Could not open `%s' as an executable file: %s",
+ scratch_pathname, bfd_errmsg (bfd_get_error ()));
+ }
+ /* Leave bfd open, core_xfer_memory and "info files" need it. */
+ so -> abfd = abfd;
+ abfd -> cacheable = true;
+
+ if (!bfd_check_format (abfd, bfd_object))
+ {
+ error ("\"%s\": not in executable format: %s.",
+ scratch_pathname, bfd_errmsg (bfd_get_error ()));
+ }
+ if (build_section_table (abfd, &so -> sections, &so -> sections_end))
+ {
+ error ("Can't find the file sections in `%s': %s",
+ bfd_get_filename (abfd), bfd_errmsg (bfd_get_error ()));
+ }
+
+ for (p = so -> sections; p < so -> sections_end; p++)
+ {
+ /* Relocate the section binding addresses as recorded in the shared
+ object's file by the base address to which the object was actually
+ mapped. */
+ p -> addr += (CORE_ADDR) LM_ADDR (so);
+ p -> endaddr += (CORE_ADDR) LM_ADDR (so);
+ so -> lmend = (CORE_ADDR) max (p -> endaddr, so -> lmend);
+ if (STREQ (p -> the_bfd_section -> name, ".text"))
+ {
+ so -> textsection = p;
+ }
+ }
+
+ /* Free the file names, close the file now. */
+ do_cleanups (old_chain);
+}
+
+/* Read all dynamically loaded common symbol definitions from the inferior
+ and add them to the minimal symbol table for the shared library objfile. */
+
+#ifndef SVR4_SHARED_LIBS
+
+/* In GDB 4.9 this routine was a real performance hog. According to
+ some gprof data which mtranle@paris.IntelliCorp.COM (Minh Tran-Le)
+ sent, almost all the time spend in solib_add (up to 20 minutes with
+ 35 shared libraries) was spent here, with 5/6 in
+ lookup_minimal_symbol and 1/6 in read_memory.
+
+ To fix this, we moved the call to special_symbol_handling out of the
+ loop in solib_add, so this only gets called once, rather than once
+ for every shared library, and also removed the call to lookup_minimal_symbol
+ in this routine. */
+
+static void
+solib_add_common_symbols (rtc_symp, objfile)
+ struct rtc_symb *rtc_symp;
+ struct objfile *objfile;
+{
+ struct rtc_symb inferior_rtc_symb;
+ struct nlist inferior_rtc_nlist;
+ int len;
+ char *name;
+ char *origname;
+
+ init_minimal_symbol_collection ();
+ make_cleanup (discard_minimal_symbols, 0);
+
+ while (rtc_symp)
+ {
+ read_memory ((CORE_ADDR) rtc_symp,
+ (char *) &inferior_rtc_symb,
+ sizeof (inferior_rtc_symb));
+ read_memory ((CORE_ADDR) inferior_rtc_symb.rtc_sp,
+ (char *) &inferior_rtc_nlist,
+ sizeof(inferior_rtc_nlist));
+ if (inferior_rtc_nlist.n_type == N_COMM)
+ {
+ /* FIXME: The length of the symbol name is not available, but in the
+ current implementation the common symbol is allocated immediately
+ behind the name of the symbol. */
+ len = inferior_rtc_nlist.n_value - inferior_rtc_nlist.n_un.n_strx;
+
+ origname = name = xmalloc (len);
+ read_memory ((CORE_ADDR) inferior_rtc_nlist.n_un.n_name, name, len);
+
+ /* Don't enter the symbol twice if the target is re-run. */
+
+ if (name[0] == bfd_get_symbol_leading_char (objfile->obfd))
+ {
+ name++;
+ }
+
+#if 0
+ /* I think this is unnecessary, GDB can probably deal with
+ duplicate minimal symbols, more or less. And the duplication
+ which used to happen because this was called for each shared
+ library is gone now that we are just called once. */
+ /* FIXME: Do we really want to exclude symbols which happen
+ to match symbols for other locations in the inferior's
+ address space, even when they are in different linkage units? */
+ if (lookup_minimal_symbol (name, (struct objfile *) NULL) == NULL)
+#endif
+ {
+ name = obsavestring (name, strlen (name),
+ &objfile -> symbol_obstack);
+ prim_record_minimal_symbol (name, inferior_rtc_nlist.n_value,
+ mst_bss, objfile);
+ }
+ free (origname);
+ }
+ rtc_symp = inferior_rtc_symb.rtc_next;
+ }
+
+ /* Install any minimal symbols that have been collected as the current
+ minimal symbols for this objfile. */
+
+ install_minimal_symbols (objfile);
+}
+
+#endif /* SVR4_SHARED_LIBS */
+
+
+#ifdef SVR4_SHARED_LIBS
+
+#ifdef HANDLE_SVR4_EXEC_EMULATORS
+
+/*
+ Solaris BCP (the part of Solaris which allows it to run SunOS4
+ a.out files) throws in another wrinkle. Solaris does not fill
+ in the usual a.out link map structures when running BCP programs,
+ the only way to get at them is via groping around in the dynamic
+ linker.
+ The dynamic linker and it's structures are located in the shared
+ C library, which gets run as the executable's "interpreter" by
+ the kernel.
+
+ Note that we can assume nothing about the process state at the time
+ we need to find these structures. We may be stopped on the first
+ instruction of the interpreter (C shared library), the first
+ instruction of the executable itself, or somewhere else entirely
+ (if we attached to the process for example).
+*/
+
+static char *debug_base_symbols[] = {
+ "r_debug", /* Solaris 2.3 */
+ "_r_debug", /* Solaris 2.1, 2.2 */
+ NULL
+};
+
+static int
+look_for_base PARAMS ((int, CORE_ADDR));
+
+static CORE_ADDR
+bfd_lookup_symbol PARAMS ((bfd *, char *));
+
+/*
+
+LOCAL FUNCTION
+
+ bfd_lookup_symbol -- lookup the value for a specific symbol
+
+SYNOPSIS
+
+ CORE_ADDR bfd_lookup_symbol (bfd *abfd, char *symname)
+
+DESCRIPTION
+
+ An expensive way to lookup the value of a single symbol for
+ bfd's that are only temporary anyway. This is used by the
+ shared library support to find the address of the debugger
+ interface structures in the shared library.
+
+ Note that 0 is specifically allowed as an error return (no
+ such symbol).
+*/
+
+static CORE_ADDR
+bfd_lookup_symbol (abfd, symname)
+ bfd *abfd;
+ char *symname;
+{
+ unsigned int storage_needed;
+ asymbol *sym;
+ asymbol **symbol_table;
+ unsigned int number_of_symbols;
+ unsigned int i;
+ struct cleanup *back_to;
+ CORE_ADDR symaddr = 0;
+
+ storage_needed = bfd_get_symtab_upper_bound (abfd);
+
+ if (storage_needed > 0)
+ {
+ symbol_table = (asymbol **) xmalloc (storage_needed);
+ back_to = make_cleanup (free, (PTR)symbol_table);
+ number_of_symbols = bfd_canonicalize_symtab (abfd, symbol_table);
+
+ for (i = 0; i < number_of_symbols; i++)
+ {
+ sym = *symbol_table++;
+ if (STREQ (sym -> name, symname))
+ {
+ /* Bfd symbols are section relative. */
+ symaddr = sym -> value + sym -> section -> vma;
+ break;
+ }
+ }
+ do_cleanups (back_to);
+ }
+ return (symaddr);
+}
+
+/*
+
+LOCAL FUNCTION
+
+ look_for_base -- examine file for each mapped address segment
+
+SYNOPSYS
+
+ static int look_for_base (int fd, CORE_ADDR baseaddr)
+
+DESCRIPTION
+
+ This function is passed to proc_iterate_over_mappings, which
+ causes it to get called once for each mapped address space, with
+ an open file descriptor for the file mapped to that space, and the
+ base address of that mapped space.
+
+ Our job is to find the debug base symbol in the file that this
+ fd is open on, if it exists, and if so, initialize the dynamic
+ linker structure base address debug_base.
+
+ Note that this is a computationally expensive proposition, since
+ we basically have to open a bfd on every call, so we specifically
+ avoid opening the exec file.
+ */
+
+static int
+look_for_base (fd, baseaddr)
+ int fd;
+ CORE_ADDR baseaddr;
+{
+ bfd *interp_bfd;
+ CORE_ADDR address = 0;
+ char **symbolp;
+
+ /* If the fd is -1, then there is no file that corresponds to this
+ mapped memory segment, so skip it. Also, if the fd corresponds
+ to the exec file, skip it as well. */
+
+ if (fd == -1
+ || (exec_bfd != NULL
+ && fdmatch (fileno ((GDB_FILE *)(exec_bfd -> iostream)), fd)))
+ {
+ return (0);
+ }
+
+ /* Try to open whatever random file this fd corresponds to. Note that
+ we have no way currently to find the filename. Don't gripe about
+ any problems we might have, just fail. */
+
+ if ((interp_bfd = bfd_fdopenr ("unnamed", gnutarget, fd)) == NULL)
+ {
+ return (0);
+ }
+ if (!bfd_check_format (interp_bfd, bfd_object))
+ {
+ bfd_close (interp_bfd);
+ return (0);
+ }
+
+ /* Now try to find our debug base symbol in this file, which we at
+ least know to be a valid ELF executable or shared library. */
+
+ for (symbolp = debug_base_symbols; *symbolp != NULL; symbolp++)
+ {
+ address = bfd_lookup_symbol (interp_bfd, *symbolp);
+ if (address != 0)
+ {
+ break;
+ }
+ }
+ if (address == 0)
+ {
+ bfd_close (interp_bfd);
+ return (0);
+ }
+
+ /* Eureka! We found the symbol. But now we may need to relocate it
+ by the base address. If the symbol's value is less than the base
+ address of the shared library, then it hasn't yet been relocated
+ by the dynamic linker, and we have to do it ourself. FIXME: Note
+ that we make the assumption that the first segment that corresponds
+ to the shared library has the base address to which the library
+ was relocated. */
+
+ if (address < baseaddr)
+ {
+ address += baseaddr;
+ }
+ debug_base = address;
+ bfd_close (interp_bfd);
+ return (1);
+}
+#endif /* HANDLE_SVR4_EXEC_EMULATORS */
+
+/*
+
+LOCAL FUNCTION
+
+ elf_locate_base -- locate the base address of dynamic linker structs
+ for SVR4 elf targets.
+
+SYNOPSIS
+
+ CORE_ADDR elf_locate_base (void)
+
+DESCRIPTION
+
+ For SVR4 elf targets the address of the dynamic linker's runtime
+ structure is contained within the dynamic info section in the
+ executable file. The dynamic section is also mapped into the
+ inferior address space. Because the runtime loader fills in the
+ real address before starting the inferior, we have to read in the
+ dynamic info section from the inferior address space.
+ If there are any errors while trying to find the address, we
+ silently return 0, otherwise the found address is returned.
+
+ */
+
+static CORE_ADDR
+elf_locate_base ()
+{
+ struct elf_internal_shdr *dyninfo_sect;
+ int dyninfo_sect_size;
+ CORE_ADDR dyninfo_addr;
+ char *buf;
+ char *bufend;
+
+ /* Find the start address of the .dynamic section. */
+ dyninfo_sect = bfd_elf_find_section (exec_bfd, ".dynamic");
+ if (dyninfo_sect == NULL)
+ return 0;
+ dyninfo_addr = dyninfo_sect->sh_addr;
+
+ /* Read in .dynamic section, silently ignore errors. */
+ dyninfo_sect_size = dyninfo_sect->sh_size;
+ buf = alloca (dyninfo_sect_size);
+ if (target_read_memory (dyninfo_addr, buf, dyninfo_sect_size))
+ return 0;
+
+ /* Find the DT_DEBUG entry in the the .dynamic section.
+ For mips elf we look for DT_MIPS_RLD_MAP, mips elf apparently has
+ no DT_DEBUG entries. */
+ /* FIXME: In lack of a 64 bit ELF ABI the following code assumes
+ a 32 bit ELF ABI target. */
+ for (bufend = buf + dyninfo_sect_size;
+ buf < bufend;
+ buf += sizeof (Elf32_External_Dyn))
+ {
+ Elf32_External_Dyn *x_dynp = (Elf32_External_Dyn *)buf;
+ long dyn_tag;
+ CORE_ADDR dyn_ptr;
+
+ dyn_tag = bfd_h_get_32 (exec_bfd, (bfd_byte *) x_dynp->d_tag);
+ if (dyn_tag == DT_NULL)
+ break;
+ else if (dyn_tag == DT_DEBUG)
+ {
+ dyn_ptr = bfd_h_get_32 (exec_bfd, (bfd_byte *) x_dynp->d_un.d_ptr);
+ return dyn_ptr;
+ }
+ else if (dyn_tag == DT_MIPS_RLD_MAP)
+ {
+ char pbuf[TARGET_PTR_BIT / HOST_CHAR_BIT];
+
+ /* DT_MIPS_RLD_MAP contains a pointer to the address
+ of the dynamic link structure. */
+ dyn_ptr = bfd_h_get_32 (exec_bfd, (bfd_byte *) x_dynp->d_un.d_ptr);
+ if (target_read_memory (dyn_ptr, pbuf, sizeof (pbuf)))
+ return 0;
+ return extract_unsigned_integer (pbuf, sizeof (pbuf));
+ }
+ }
+
+ /* DT_DEBUG entry not found. */
+ return 0;
+}
+
+#endif /* SVR4_SHARED_LIBS */
+
+/*
+
+LOCAL FUNCTION
+
+ locate_base -- locate the base address of dynamic linker structs
+
+SYNOPSIS
+
+ CORE_ADDR locate_base (void)
+
+DESCRIPTION
+
+ For both the SunOS and SVR4 shared library implementations, if the
+ inferior executable has been linked dynamically, there is a single
+ address somewhere in the inferior's data space which is the key to
+ locating all of the dynamic linker's runtime structures. This
+ address is the value of the debug base symbol. The job of this
+ function is to find and return that address, or to return 0 if there
+ is no such address (the executable is statically linked for example).
+
+ For SunOS, the job is almost trivial, since the dynamic linker and
+ all of it's structures are statically linked to the executable at
+ link time. Thus the symbol for the address we are looking for has
+ already been added to the minimal symbol table for the executable's
+ objfile at the time the symbol file's symbols were read, and all we
+ have to do is look it up there. Note that we explicitly do NOT want
+ to find the copies in the shared library.
+
+ The SVR4 version is a bit more complicated because the address
+ is contained somewhere in the dynamic info section. We have to go
+ to a lot more work to discover the address of the debug base symbol.
+ Because of this complexity, we cache the value we find and return that
+ value on subsequent invocations. Note there is no copy in the
+ executable symbol tables.
+
+ */
+
+static CORE_ADDR
+locate_base ()
+{
+
+#ifndef SVR4_SHARED_LIBS
+
+ struct minimal_symbol *msymbol;
+ CORE_ADDR address = 0;
+ char **symbolp;
+
+ /* For SunOS, we want to limit the search for the debug base symbol to the
+ executable being debugged, since there is a duplicate named symbol in the
+ shared library. We don't want the shared library versions. */
+
+ for (symbolp = debug_base_symbols; *symbolp != NULL; symbolp++)
+ {
+ msymbol = lookup_minimal_symbol (*symbolp, symfile_objfile);
+ if ((msymbol != NULL) && (SYMBOL_VALUE_ADDRESS (msymbol) != 0))
+ {
+ address = SYMBOL_VALUE_ADDRESS (msymbol);
+ return (address);
+ }
+ }
+ return (0);
+
+#else /* SVR4_SHARED_LIBS */
+
+ /* Check to see if we have a currently valid address, and if so, avoid
+ doing all this work again and just return the cached address. If
+ we have no cached address, try to locate it in the dynamic info
+ section for ELF executables. */
+
+ if (debug_base == 0)
+ {
+ if (exec_bfd != NULL
+ && bfd_get_flavour (exec_bfd) == bfd_target_elf_flavour)
+ debug_base = elf_locate_base ();
+#ifdef HANDLE_SVR4_EXEC_EMULATORS
+ /* Try it the hard way for emulated executables. */
+ else if (inferior_pid != 0)
+ proc_iterate_over_mappings (look_for_base);
+#endif
+ }
+ return (debug_base);
+
+#endif /* !SVR4_SHARED_LIBS */
+
+}
+
+/*
+
+LOCAL FUNCTION
+
+ first_link_map_member -- locate first member in dynamic linker's map
+
+SYNOPSIS
+
+ static struct link_map *first_link_map_member (void)
+
+DESCRIPTION
+
+ Read in a copy of the first member in the inferior's dynamic
+ link map from the inferior's dynamic linker structures, and return
+ a pointer to the copy in our address space.
+*/
+
+static struct link_map *
+first_link_map_member ()
+{
+ struct link_map *lm = NULL;
+
+#ifndef SVR4_SHARED_LIBS
+
+ read_memory (debug_base, (char *) &dynamic_copy, sizeof (dynamic_copy));
+ if (dynamic_copy.ld_version >= 2)
+ {
+ /* It is a version that we can deal with, so read in the secondary
+ structure and find the address of the link map list from it. */
+ read_memory ((CORE_ADDR) dynamic_copy.ld_un.ld_2, (char *) &ld_2_copy,
+ sizeof (struct link_dynamic_2));
+ lm = ld_2_copy.ld_loaded;
+ }
+
+#else /* SVR4_SHARED_LIBS */
+
+ read_memory (debug_base, (char *) &debug_copy, sizeof (struct r_debug));
+ /* FIXME: Perhaps we should validate the info somehow, perhaps by
+ checking r_version for a known version number, or r_state for
+ RT_CONSISTENT. */
+ lm = debug_copy.r_map;
+
+#endif /* !SVR4_SHARED_LIBS */
+
+ return (lm);
+}
+
+/*
+
+LOCAL FUNCTION
+
+ find_solib -- step through list of shared objects
+
+SYNOPSIS
+
+ struct so_list *find_solib (struct so_list *so_list_ptr)
+
+DESCRIPTION
+
+ This module contains the routine which finds the names of any
+ loaded "images" in the current process. The argument in must be
+ NULL on the first call, and then the returned value must be passed
+ in on subsequent calls. This provides the capability to "step" down
+ the list of loaded objects. On the last object, a NULL value is
+ returned.
+
+ The arg and return value are "struct link_map" pointers, as defined
+ in <link.h>.
+ */
+
+static struct so_list *
+find_solib (so_list_ptr)
+ struct so_list *so_list_ptr; /* Last lm or NULL for first one */
+{
+ struct so_list *so_list_next = NULL;
+ struct link_map *lm = NULL;
+ struct so_list *new;
+
+ if (so_list_ptr == NULL)
+ {
+ /* We are setting up for a new scan through the loaded images. */
+ if ((so_list_next = so_list_head) == NULL)
+ {
+ /* We have not already read in the dynamic linking structures
+ from the inferior, lookup the address of the base structure. */
+ debug_base = locate_base ();
+ if (debug_base != 0)
+ {
+ /* Read the base structure in and find the address of the first
+ link map list member. */
+ lm = first_link_map_member ();
+ }
+ }
+ }
+ else
+ {
+ /* We have been called before, and are in the process of walking
+ the shared library list. Advance to the next shared object. */
+ if ((lm = LM_NEXT (so_list_ptr)) == NULL)
+ {
+ /* We have hit the end of the list, so check to see if any were
+ added, but be quiet if we can't read from the target any more. */
+ int status = target_read_memory ((CORE_ADDR) so_list_ptr -> lmaddr,
+ (char *) &(so_list_ptr -> lm),
+ sizeof (struct link_map));
+ if (status == 0)
+ {
+ lm = LM_NEXT (so_list_ptr);
+ }
+ else
+ {
+ lm = NULL;
+ }
+ }
+ so_list_next = so_list_ptr -> next;
+ }
+ if ((so_list_next == NULL) && (lm != NULL))
+ {
+ /* Get next link map structure from inferior image and build a local
+ abbreviated load_map structure */
+ new = (struct so_list *) xmalloc (sizeof (struct so_list));
+ memset ((char *) new, 0, sizeof (struct so_list));
+ new -> lmaddr = lm;
+ /* Add the new node as the next node in the list, or as the root
+ node if this is the first one. */
+ if (so_list_ptr != NULL)
+ {
+ so_list_ptr -> next = new;
+ }
+ else
+ {
+ so_list_head = new;
+ }
+ so_list_next = new;
+ read_memory ((CORE_ADDR) lm, (char *) &(new -> lm),
+ sizeof (struct link_map));
+ /* For SVR4 versions, the first entry in the link map is for the
+ inferior executable, so we must ignore it. For some versions of
+ SVR4, it has no name. For others (Solaris 2.3 for example), it
+ does have a name, so we can no longer use a missing name to
+ decide when to ignore it. */
+ if (!IGNORE_FIRST_LINK_MAP_ENTRY (new -> lm))
+ {
+ int errcode;
+ char *buffer;
+ target_read_string ((CORE_ADDR) LM_NAME (new), &buffer,
+ MAX_PATH_SIZE - 1, &errcode);
+ if (errcode != 0)
+ error ("find_solib: Can't read pathname for load map: %s\n",
+ safe_strerror (errcode));
+ strncpy (new -> so_name, buffer, MAX_PATH_SIZE - 1);
+ new -> so_name[MAX_PATH_SIZE - 1] = '\0';
+ free (buffer);
+ solib_map_sections (new);
+ }
+ }
+ return (so_list_next);
+}
+
+/* A small stub to get us past the arg-passing pinhole of catch_errors. */
+
+static int
+symbol_add_stub (arg)
+ char *arg;
+{
+ register struct so_list *so = (struct so_list *) arg; /* catch_errs bogon */
+
+ so -> objfile =
+ symbol_file_add (so -> so_name, so -> from_tty,
+ (so->textsection == NULL
+ ? 0
+ : (unsigned int) so -> textsection -> addr),
+ 0, 0, 0);
+ return (1);
+}
+
+/*
+
+GLOBAL FUNCTION
+
+ solib_add -- add a shared library file to the symtab and section list
+
+SYNOPSIS
+
+ void solib_add (char *arg_string, int from_tty,
+ struct target_ops *target)
+
+DESCRIPTION
+
+*/
+
+void
+solib_add (arg_string, from_tty, target)
+ char *arg_string;
+ int from_tty;
+ struct target_ops *target;
+{
+ register struct so_list *so = NULL; /* link map state variable */
+
+ /* Last shared library that we read. */
+ struct so_list *so_last = NULL;
+
+ char *re_err;
+ int count;
+ int old;
+
+ if ((re_err = re_comp (arg_string ? arg_string : ".")) != NULL)
+ {
+ error ("Invalid regexp: %s", re_err);
+ }
+
+ /* Add the shared library sections to the section table of the
+ specified target, if any. We have to do this before reading the
+ symbol files as symbol_file_add calls reinit_frame_cache and
+ creating a new frame might access memory in the shared library. */
+ if (target)
+ {
+ /* Count how many new section_table entries there are. */
+ so = NULL;
+ count = 0;
+ while ((so = find_solib (so)) != NULL)
+ {
+ if (so -> so_name[0])
+ {
+ count += so -> sections_end - so -> sections;
+ }
+ }
+
+ if (count)
+ {
+ /* Reallocate the target's section table including the new size. */
+ if (target -> to_sections)
+ {
+ old = target -> to_sections_end - target -> to_sections;
+ target -> to_sections = (struct section_table *)
+ xrealloc ((char *)target -> to_sections,
+ (sizeof (struct section_table)) * (count + old));
+ }
+ else
+ {
+ old = 0;
+ target -> to_sections = (struct section_table *)
+ xmalloc ((sizeof (struct section_table)) * count);
+ }
+ target -> to_sections_end = target -> to_sections + (count + old);
+
+ /* Add these section table entries to the target's table. */
+ while ((so = find_solib (so)) != NULL)
+ {
+ if (so -> so_name[0])
+ {
+ count = so -> sections_end - so -> sections;
+ memcpy ((char *) (target -> to_sections + old),
+ so -> sections,
+ (sizeof (struct section_table)) * count);
+ old += count;
+ }
+ }
+ }
+ }
+
+ /* Now add the symbol files. */
+ while ((so = find_solib (so)) != NULL)
+ {
+ if (so -> so_name[0] && re_exec (so -> so_name))
+ {
+ so -> from_tty = from_tty;
+ if (so -> symbols_loaded)
+ {
+ if (from_tty)
+ {
+ printf_unfiltered ("Symbols already loaded for %s\n", so -> so_name);
+ }
+ }
+ else if (catch_errors
+ (symbol_add_stub, (char *) so,
+ "Error while reading shared library symbols:\n",
+ RETURN_MASK_ALL))
+ {
+ so_last = so;
+ so -> symbols_loaded = 1;
+ }
+ }
+ }
+
+ /* Calling this once at the end means that we put all the minimal
+ symbols for commons into the objfile for the last shared library.
+ Since they are in common, this should not be a problem. If we
+ delete the objfile with the minimal symbols, we can put all the
+ symbols into a new objfile (and will on the next call to solib_add).
+
+ An alternate approach would be to create an objfile just for
+ common minsyms, thus not needing any objfile argument to
+ solib_add_common_symbols. */
+
+ if (so_last)
+ special_symbol_handling (so_last);
+}
+
+/*
+
+LOCAL FUNCTION
+
+ info_sharedlibrary_command -- code for "info sharedlibrary"
+
+SYNOPSIS
+
+ static void info_sharedlibrary_command ()
+
+DESCRIPTION
+
+ Walk through the shared library list and print information
+ about each attached library.
+*/
+
+static void
+info_sharedlibrary_command (ignore, from_tty)
+ char *ignore;
+ int from_tty;
+{
+ register struct so_list *so = NULL; /* link map state variable */
+ int header_done = 0;
+
+ if (exec_bfd == NULL)
+ {
+ printf_unfiltered ("No exec file.\n");
+ return;
+ }
+ while ((so = find_solib (so)) != NULL)
+ {
+ if (so -> so_name[0])
+ {
+ if (!header_done)
+ {
+ printf_unfiltered("%-12s%-12s%-12s%s\n", "From", "To", "Syms Read",
+ "Shared Object Library");
+ header_done++;
+ }
+ /* FIXME-32x64: need print_address_numeric with field width or
+ some such. */
+ printf_unfiltered ("%-12s",
+ local_hex_string_custom ((unsigned long) LM_ADDR (so),
+ "08l"));
+ printf_unfiltered ("%-12s",
+ local_hex_string_custom ((unsigned long) so -> lmend,
+ "08l"));
+ printf_unfiltered ("%-12s", so -> symbols_loaded ? "Yes" : "No");
+ printf_unfiltered ("%s\n", so -> so_name);
+ }
+ }
+ if (so_list_head == NULL)
+ {
+ printf_unfiltered ("No shared libraries loaded at this time.\n");
+ }
+}
+
+/*
+
+GLOBAL FUNCTION
+
+ solib_address -- check to see if an address is in a shared lib
+
+SYNOPSIS
+
+ int solib_address (CORE_ADDR address)
+
+DESCRIPTION
+
+ Provides a hook for other gdb routines to discover whether or
+ not a particular address is within the mapped address space of
+ a shared library. Any address between the base mapping address
+ and the first address beyond the end of the last mapping, is
+ considered to be within the shared library address space, for
+ our purposes.
+
+ For example, this routine is called at one point to disable
+ breakpoints which are in shared libraries that are not currently
+ mapped in.
+ */
+
+int
+solib_address (address)
+ CORE_ADDR address;
+{
+ register struct so_list *so = 0; /* link map state variable */
+
+ while ((so = find_solib (so)) != NULL)
+ {
+ if (so -> so_name[0])
+ {
+ if ((address >= (CORE_ADDR) LM_ADDR (so)) &&
+ (address < (CORE_ADDR) so -> lmend))
+ {
+ return (1);
+ }
+ }
+ }
+ return (0);
+}
+
+/* Called by free_all_symtabs */
+
+void
+clear_solib()
+{
+ struct so_list *next;
+ char *bfd_filename;
+
+ while (so_list_head)
+ {
+ if (so_list_head -> sections)
+ {
+ free ((PTR)so_list_head -> sections);
+ }
+ if (so_list_head -> abfd)
+ {
+ bfd_filename = bfd_get_filename (so_list_head -> abfd);
+ bfd_close (so_list_head -> abfd);
+ }
+ else
+ /* This happens for the executable on SVR4. */
+ bfd_filename = NULL;
+
+ next = so_list_head -> next;
+ if (bfd_filename)
+ free ((PTR)bfd_filename);
+ free ((PTR)so_list_head);
+ so_list_head = next;
+ }
+ debug_base = 0;
+}
+
+/*
+
+LOCAL FUNCTION
+
+ disable_break -- remove the "mapping changed" breakpoint
+
+SYNOPSIS
+
+ static int disable_break ()
+
+DESCRIPTION
+
+ Removes the breakpoint that gets hit when the dynamic linker
+ completes a mapping change.
+
+*/
+
+static int
+disable_break ()
+{
+ int status = 1;
+
+#ifndef SVR4_SHARED_LIBS
+
+ int in_debugger = 0;
+
+ /* Read the debugger structure from the inferior to retrieve the
+ address of the breakpoint and the original contents of the
+ breakpoint address. Remove the breakpoint by writing the original
+ contents back. */
+
+ read_memory (debug_addr, (char *) &debug_copy, sizeof (debug_copy));
+
+ /* Set `in_debugger' to zero now. */
+
+ write_memory (flag_addr, (char *) &in_debugger, sizeof (in_debugger));
+
+ breakpoint_addr = (CORE_ADDR) debug_copy.ldd_bp_addr;
+ write_memory (breakpoint_addr, (char *) &debug_copy.ldd_bp_inst,
+ sizeof (debug_copy.ldd_bp_inst));
+
+#else /* SVR4_SHARED_LIBS */
+
+ /* Note that breakpoint address and original contents are in our address
+ space, so we just need to write the original contents back. */
+
+ if (memory_remove_breakpoint (breakpoint_addr, shadow_contents) != 0)
+ {
+ status = 0;
+ }
+
+#endif /* !SVR4_SHARED_LIBS */
+
+ /* For the SVR4 version, we always know the breakpoint address. For the
+ SunOS version we don't know it until the above code is executed.
+ Grumble if we are stopped anywhere besides the breakpoint address. */
+
+ if (stop_pc != breakpoint_addr)
+ {
+ warning ("stopped at unknown breakpoint while handling shared libraries");
+ }
+
+ return (status);
+}
+
+/*
+
+LOCAL FUNCTION
+
+ enable_break -- arrange for dynamic linker to hit breakpoint
+
+SYNOPSIS
+
+ int enable_break (void)
+
+DESCRIPTION
+
+ Both the SunOS and the SVR4 dynamic linkers have, as part of their
+ debugger interface, support for arranging for the inferior to hit
+ a breakpoint after mapping in the shared libraries. This function
+ enables that breakpoint.
+
+ For SunOS, there is a special flag location (in_debugger) which we
+ set to 1. When the dynamic linker sees this flag set, it will set
+ a breakpoint at a location known only to itself, after saving the
+ original contents of that place and the breakpoint address itself,
+ in it's own internal structures. When we resume the inferior, it
+ will eventually take a SIGTRAP when it runs into the breakpoint.
+ We handle this (in a different place) by restoring the contents of
+ the breakpointed location (which is only known after it stops),
+ chasing around to locate the shared libraries that have been
+ loaded, then resuming.
+
+ For SVR4, the debugger interface structure contains a member (r_brk)
+ which is statically initialized at the time the shared library is
+ built, to the offset of a function (_r_debug_state) which is guaran-
+ teed to be called once before mapping in a library, and again when
+ the mapping is complete. At the time we are examining this member,
+ it contains only the unrelocated offset of the function, so we have
+ to do our own relocation. Later, when the dynamic linker actually
+ runs, it relocates r_brk to be the actual address of _r_debug_state().
+
+ The debugger interface structure also contains an enumeration which
+ is set to either RT_ADD or RT_DELETE prior to changing the mapping,
+ depending upon whether or not the library is being mapped or unmapped,
+ and then set to RT_CONSISTENT after the library is mapped/unmapped.
+*/
+
+static int
+enable_break ()
+{
+ int success = 0;
+
+#ifndef SVR4_SHARED_LIBS
+
+ int j;
+ int in_debugger;
+
+ /* Get link_dynamic structure */
+
+ j = target_read_memory (debug_base, (char *) &dynamic_copy,
+ sizeof (dynamic_copy));
+ if (j)
+ {
+ /* unreadable */
+ return (0);
+ }
+
+ /* Calc address of debugger interface structure */
+
+ debug_addr = (CORE_ADDR) dynamic_copy.ldd;
+
+ /* Calc address of `in_debugger' member of debugger interface structure */
+
+ flag_addr = debug_addr + (CORE_ADDR) ((char *) &debug_copy.ldd_in_debugger -
+ (char *) &debug_copy);
+
+ /* Write a value of 1 to this member. */
+
+ in_debugger = 1;
+ write_memory (flag_addr, (char *) &in_debugger, sizeof (in_debugger));
+ success = 1;
+
+#else /* SVR4_SHARED_LIBS */
+
+#ifdef BKPT_AT_SYMBOL
+
+ struct minimal_symbol *msymbol;
+ char **bkpt_namep;
+ CORE_ADDR bkpt_addr;
+
+ /* Scan through the list of symbols, trying to look up the symbol and
+ set a breakpoint there. Terminate loop when we/if we succeed. */
+
+ breakpoint_addr = 0;
+ for (bkpt_namep = bkpt_names; *bkpt_namep != NULL; bkpt_namep++)
+ {
+ msymbol = lookup_minimal_symbol (*bkpt_namep, symfile_objfile);
+ if ((msymbol != NULL) && (SYMBOL_VALUE_ADDRESS (msymbol) != 0))
+ {
+ bkpt_addr = SYMBOL_VALUE_ADDRESS (msymbol);
+ if (target_insert_breakpoint (bkpt_addr, shadow_contents) == 0)
+ {
+ breakpoint_addr = bkpt_addr;
+ success = 1;
+ break;
+ }
+ }
+ }
+
+#else /* !BKPT_AT_SYMBOL */
+
+ struct symtab_and_line sal;
+
+ /* Read the debugger interface structure directly. */
+
+ read_memory (debug_base, (char *) &debug_copy, sizeof (debug_copy));
+
+ /* Set breakpoint at the debugger interface stub routine that will
+ be called just prior to each mapping change and again after the
+ mapping change is complete. Set up the (nonexistent) handler to
+ deal with hitting these breakpoints. (FIXME). */
+
+ warning ("'%s': line %d: missing SVR4 support code", __FILE__, __LINE__);
+ success = 1;
+
+#endif /* BKPT_AT_SYMBOL */
+
+#endif /* !SVR4_SHARED_LIBS */
+
+ return (success);
+}
+
+/*
+
+GLOBAL FUNCTION
+
+ solib_create_inferior_hook -- shared library startup support
+
+SYNOPSIS
+
+ void solib_create_inferior_hook()
+
+DESCRIPTION
+
+ When gdb starts up the inferior, it nurses it along (through the
+ shell) until it is ready to execute it's first instruction. At this
+ point, this function gets called via expansion of the macro
+ SOLIB_CREATE_INFERIOR_HOOK.
+
+ For SunOS executables, this first instruction is typically the
+ one at "_start", or a similar text label, regardless of whether
+ the executable is statically or dynamically linked. The runtime
+ startup code takes care of dynamically linking in any shared
+ libraries, once gdb allows the inferior to continue.
+
+ For SVR4 executables, this first instruction is either the first
+ instruction in the dynamic linker (for dynamically linked
+ executables) or the instruction at "start" for statically linked
+ executables. For dynamically linked executables, the system
+ first exec's /lib/libc.so.N, which contains the dynamic linker,
+ and starts it running. The dynamic linker maps in any needed
+ shared libraries, maps in the actual user executable, and then
+ jumps to "start" in the user executable.
+
+ For both SunOS shared libraries, and SVR4 shared libraries, we
+ can arrange to cooperate with the dynamic linker to discover the
+ names of shared libraries that are dynamically linked, and the
+ base addresses to which they are linked.
+
+ This function is responsible for discovering those names and
+ addresses, and saving sufficient information about them to allow
+ their symbols to be read at a later time.
+
+FIXME
+
+ Between enable_break() and disable_break(), this code does not
+ properly handle hitting breakpoints which the user might have
+ set in the startup code or in the dynamic linker itself. Proper
+ handling will probably have to wait until the implementation is
+ changed to use the "breakpoint handler function" method.
+
+ Also, what if child has exit()ed? Must exit loop somehow.
+ */
+
+void
+solib_create_inferior_hook()
+{
+ /* If we are using the BKPT_AT_SYMBOL code, then we don't need the base
+ yet. In fact, in the case of a SunOS4 executable being run on
+ Solaris, we can't get it yet. find_solib will get it when it needs
+ it. */
+#if !(defined (SVR4_SHARED_LIBS) && defined (BKPT_AT_SYMBOL))
+ if ((debug_base = locate_base ()) == 0)
+ {
+ /* Can't find the symbol or the executable is statically linked. */
+ return;
+ }
+#endif
+
+ if (!enable_break ())
+ {
+ warning ("shared library handler failed to enable breakpoint");
+ return;
+ }
+
+ /* Now run the target. It will eventually hit the breakpoint, at
+ which point all of the libraries will have been mapped in and we
+ can go groveling around in the dynamic linker structures to find
+ out what we need to know about them. */
+
+ clear_proceed_status ();
+ stop_soon_quietly = 1;
+ stop_signal = TARGET_SIGNAL_0;
+ do
+ {
+ target_resume (-1, 0, stop_signal);
+ wait_for_inferior ();
+ }
+ while (stop_signal != TARGET_SIGNAL_TRAP);
+ stop_soon_quietly = 0;
+
+ /* We are now either at the "mapping complete" breakpoint (or somewhere
+ else, a condition we aren't prepared to deal with anyway), so adjust
+ the PC as necessary after a breakpoint, disable the breakpoint, and
+ add any shared libraries that were mapped in. */
+
+ if (DECR_PC_AFTER_BREAK)
+ {
+ stop_pc -= DECR_PC_AFTER_BREAK;
+ write_register (PC_REGNUM, stop_pc);
+ }
+
+ if (!disable_break ())
+ {
+ warning ("shared library handler failed to disable breakpoint");
+ }
+
+ solib_add ((char *) 0, 0, (struct target_ops *) 0);
+}
+
+/*
+
+LOCAL FUNCTION
+
+ special_symbol_handling -- additional shared library symbol handling
+
+SYNOPSIS
+
+ void special_symbol_handling (struct so_list *so)
+
+DESCRIPTION
+
+ Once the symbols from a shared object have been loaded in the usual
+ way, we are called to do any system specific symbol handling that
+ is needed.
+
+ For Suns, this consists of grunging around in the dynamic linkers
+ structures to find symbol definitions for "common" symbols and
+ adding them to the minimal symbol table for the corresponding
+ objfile.
+
+*/
+
+static void
+special_symbol_handling (so)
+struct so_list *so;
+{
+#ifndef SVR4_SHARED_LIBS
+ int j;
+
+ if (debug_addr == 0)
+ {
+ /* Get link_dynamic structure */
+
+ j = target_read_memory (debug_base, (char *) &dynamic_copy,
+ sizeof (dynamic_copy));
+ if (j)
+ {
+ /* unreadable */
+ return;
+ }
+
+ /* Calc address of debugger interface structure */
+ /* FIXME, this needs work for cross-debugging of core files
+ (byteorder, size, alignment, etc). */
+
+ debug_addr = (CORE_ADDR) dynamic_copy.ldd;
+ }
+
+ /* Read the debugger structure from the inferior, just to make sure
+ we have a current copy. */
+
+ j = target_read_memory (debug_addr, (char *) &debug_copy,
+ sizeof (debug_copy));
+ if (j)
+ return; /* unreadable */
+
+ /* Get common symbol definitions for the loaded object. */
+
+ if (debug_copy.ldd_cp)
+ {
+ solib_add_common_symbols (debug_copy.ldd_cp, so -> objfile);
+ }
+
+#endif /* !SVR4_SHARED_LIBS */
+}
+
+
+/*
+
+LOCAL FUNCTION
+
+ sharedlibrary_command -- handle command to explicitly add library
+
+SYNOPSIS
+
+ static void sharedlibrary_command (char *args, int from_tty)
+
+DESCRIPTION
+
+*/
+
+static void
+sharedlibrary_command (args, from_tty)
+char *args;
+int from_tty;
+{
+ dont_repeat ();
+ solib_add (args, from_tty, (struct target_ops *) 0);
+}
+
+void
+_initialize_solib()
+{
+
+ add_com ("sharedlibrary", class_files, sharedlibrary_command,
+ "Load shared object library symbols for files matching REGEXP.");
+ add_info ("sharedlibrary", info_sharedlibrary_command,
+ "Status of loaded shared object libraries.");
+}
diff --git a/gnu/usr.bin/gdb/gdb/solib.h b/gnu/usr.bin/gdb/gdb/solib.h
new file mode 100644
index 0000000..ddabf74
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/solib.h
@@ -0,0 +1,56 @@
+/* Shared library declarations for GDB, the GNU Debugger.
+ Copyright (C) 1992 Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#ifdef __STDC__ /* Forward decl's for prototypes */
+struct target_ops;
+#endif
+
+/* Called when we free all symtabs, to free the shared library information
+ as well. */
+
+#define CLEAR_SOLIB clear_solib
+
+extern void
+clear_solib PARAMS ((void));
+
+/* Called to add symbols from a shared library to gdb's symbol table. */
+
+#define SOLIB_ADD(filename, from_tty, targ) \
+ solib_add (filename, from_tty, targ)
+
+extern void
+solib_add PARAMS ((char *, int, struct target_ops *));
+
+/* Function to be called when the inferior starts up, to discover the names
+ of shared libraries that are dynamically linked, the base addresses to
+ which they are linked, and sufficient information to read in their symbols
+ at a later time. */
+
+#define SOLIB_CREATE_INFERIOR_HOOK(PID) solib_create_inferior_hook()
+
+extern void
+solib_create_inferior_hook PARAMS((void)); /* solib.c */
+
+/* If we can't set a breakpoint, and it's in a shared library, just
+ disable it. */
+
+#define DISABLE_UNSETTABLE_BREAK(addr) solib_address(addr)
+
+extern int
+solib_address PARAMS ((CORE_ADDR)); /* solib.c */
diff --git a/gnu/usr.bin/gdb/gdb/source.c b/gnu/usr.bin/gdb/gdb/source.c
new file mode 100644
index 0000000..9dc175b
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/source.c
@@ -0,0 +1,1415 @@
+/* List lines of source files for GDB, the GNU debugger.
+ Copyright (C) 1986, 1987, 1988, 1989, 1991 Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "defs.h"
+#include "symtab.h"
+#include "expression.h"
+#include "language.h"
+#include "command.h"
+#include "gdbcmd.h"
+#include "frame.h"
+
+#include <sys/types.h>
+#include <string.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include "gdbcore.h"
+#include "gnuregex.h"
+#include "symfile.h"
+#include "objfiles.h"
+#include "annotate.h"
+
+#ifndef DIRNAME_SEPARATOR
+#define DIRNAME_SEPARATOR ':'
+#endif
+
+/* Prototypes for local functions. */
+
+static int
+open_source_file PARAMS ((struct symtab *));
+
+static int
+get_filename_and_charpos PARAMS ((struct symtab *, char **));
+
+static void
+reverse_search_command PARAMS ((char *, int));
+
+static void
+forward_search_command PARAMS ((char *, int));
+
+static void
+line_info PARAMS ((char *, int));
+
+static void
+list_command PARAMS ((char *, int));
+
+static void
+ambiguous_line_spec PARAMS ((struct symtabs_and_lines *));
+
+static void
+source_info PARAMS ((char *, int));
+
+static void
+show_directories PARAMS ((char *, int));
+
+static void
+find_source_lines PARAMS ((struct symtab *, int));
+
+/* If we use this declaration, it breaks because of fucking ANSI "const" stuff
+ on some systems. We just have to not declare it at all, have it default
+ to int, and possibly botch on a few systems. Thanks, ANSIholes... */
+/* extern char *strstr(); */
+
+/* Path of directories to search for source files.
+ Same format as the PATH environment variable's value. */
+
+char *source_path;
+
+/* Symtab of default file for listing lines of. */
+
+struct symtab *current_source_symtab;
+
+/* Default next line to list. */
+
+int current_source_line;
+
+/* Default number of lines to print with commands like "list".
+ This is based on guessing how many long (i.e. more than chars_per_line
+ characters) lines there will be. To be completely correct, "list"
+ and friends should be rewritten to count characters and see where
+ things are wrapping, but that would be a fair amount of work. */
+
+int lines_to_list = 10;
+
+/* Line number of last line printed. Default for various commands.
+ current_source_line is usually, but not always, the same as this. */
+
+static int last_line_listed;
+
+/* First line number listed by last listing command. */
+
+static int first_line_listed;
+
+
+/* Set the source file default for the "list" command to be S.
+
+ If S is NULL, and we don't have a default, find one. This
+ should only be called when the user actually tries to use the
+ default, since we produce an error if we can't find a reasonable
+ default. Also, since this can cause symbols to be read, doing it
+ before we need to would make things slower than necessary. */
+
+void
+select_source_symtab (s)
+ register struct symtab *s;
+{
+ struct symtabs_and_lines sals;
+ struct symtab_and_line sal;
+ struct partial_symtab *ps;
+ struct partial_symtab *cs_pst = 0;
+ struct objfile *ofp;
+
+ if (s)
+ {
+ current_source_symtab = s;
+ current_source_line = 1;
+ return;
+ }
+
+ if (current_source_symtab)
+ return;
+
+ /* Make the default place to list be the function `main'
+ if one exists. */
+ if (lookup_symbol ("main", 0, VAR_NAMESPACE, 0, NULL))
+ {
+ sals = decode_line_spec ("main", 1);
+ sal = sals.sals[0];
+ free (sals.sals);
+ current_source_symtab = sal.symtab;
+ current_source_line = max (sal.line - (lines_to_list - 1), 1);
+ if (current_source_symtab)
+ return;
+ }
+
+ /* All right; find the last file in the symtab list (ignoring .h's). */
+
+ current_source_line = 1;
+
+ for (ofp = object_files; ofp != NULL; ofp = ofp -> next)
+ {
+ for (s = ofp -> symtabs; s; s = s->next)
+ {
+ char *name = s -> filename;
+ int len = strlen (name);
+ if (! (len > 2 && (STREQ (&name[len - 2], ".h"))))
+ {
+ current_source_symtab = s;
+ }
+ }
+ }
+ if (current_source_symtab)
+ return;
+
+ /* Howabout the partial symbol tables? */
+
+ for (ofp = object_files; ofp != NULL; ofp = ofp -> next)
+ {
+ for (ps = ofp -> psymtabs; ps != NULL; ps = ps -> next)
+ {
+ char *name = ps -> filename;
+ int len = strlen (name);
+ if (! (len > 2 && (STREQ (&name[len - 2], ".h"))))
+ {
+ cs_pst = ps;
+ }
+ }
+ }
+ if (cs_pst)
+ {
+ if (cs_pst -> readin)
+ {
+ fatal ("Internal: select_source_symtab: readin pst found and no symtabs.");
+ }
+ else
+ {
+ current_source_symtab = PSYMTAB_TO_SYMTAB (cs_pst);
+ }
+ }
+
+ error ("Can't find a default source file");
+}
+
+static void
+show_directories (ignore, from_tty)
+ char *ignore;
+ int from_tty;
+{
+ puts_filtered ("Source directories searched: ");
+ puts_filtered (source_path);
+ puts_filtered ("\n");
+}
+
+/* Forget what we learned about line positions in source files,
+ and which directories contain them;
+ must check again now since files may be found in
+ a different directory now. */
+
+void
+forget_cached_source_info ()
+{
+ register struct symtab *s;
+ register struct objfile *objfile;
+
+ for (objfile = object_files; objfile != NULL; objfile = objfile -> next)
+ {
+ for (s = objfile -> symtabs; s != NULL; s = s -> next)
+ {
+ if (s -> line_charpos != NULL)
+ {
+ mfree (objfile -> md, s -> line_charpos);
+ s -> line_charpos = NULL;
+ }
+ if (s -> fullname != NULL)
+ {
+ mfree (objfile -> md, s -> fullname);
+ s -> fullname = NULL;
+ }
+ }
+ }
+}
+
+void
+init_source_path ()
+{
+ char buf[20];
+
+ sprintf (buf, "$cdir%c$cwd", DIRNAME_SEPARATOR);
+ source_path = strsave (buf);
+ forget_cached_source_info ();
+}
+
+/* Add zero or more directories to the front of the source path. */
+
+void
+directory_command (dirname, from_tty)
+ char *dirname;
+ int from_tty;
+{
+ dont_repeat ();
+ /* FIXME, this goes to "delete dir"... */
+ if (dirname == 0)
+ {
+ if (query ("Reinitialize source path to empty? ", ""))
+ {
+ free (source_path);
+ init_source_path ();
+ }
+ }
+ else
+ mod_path (dirname, &source_path);
+ if (from_tty)
+ show_directories ((char *)0, from_tty);
+ forget_cached_source_info ();
+}
+
+/* Add zero or more directories to the front of an arbitrary path. */
+
+void
+mod_path (dirname, which_path)
+ char *dirname;
+ char **which_path;
+{
+ char *old = *which_path;
+ int prefix = 0;
+
+ if (dirname == 0)
+ return;
+
+ dirname = strsave (dirname);
+ make_cleanup (free, dirname);
+
+ do
+ {
+ char *name = dirname;
+ register char *p;
+ struct stat st;
+
+ {
+ char *colon = strchr (name, DIRNAME_SEPARATOR);
+ char *space = strchr (name, ' ');
+ char *tab = strchr (name, '\t');
+ if (colon == 0 && space == 0 && tab == 0)
+ p = dirname = name + strlen (name);
+ else
+ {
+ p = 0;
+ if (colon != 0 && (p == 0 || colon < p))
+ p = colon;
+ if (space != 0 && (p == 0 || space < p))
+ p = space;
+ if (tab != 0 && (p == 0 || tab < p))
+ p = tab;
+ dirname = p + 1;
+ while (*dirname == DIRNAME_SEPARATOR || *dirname == ' ' || *dirname == '\t')
+ ++dirname;
+ }
+ }
+
+ if (p[-1] == '/')
+ /* Sigh. "foo/" => "foo" */
+ --p;
+ *p = '\0';
+
+ while (p[-1] == '.')
+ {
+ if (p - name == 1)
+ {
+ /* "." => getwd (). */
+ name = current_directory;
+ goto append;
+ }
+ else if (p[-2] == '/')
+ {
+ if (p - name == 2)
+ {
+ /* "/." => "/". */
+ *--p = '\0';
+ goto append;
+ }
+ else
+ {
+ /* "...foo/." => "...foo". */
+ p -= 2;
+ *p = '\0';
+ continue;
+ }
+ }
+ else
+ break;
+ }
+
+ if (name[0] == '~')
+ name = tilde_expand (name);
+ else if (name[0] != '/' && name[0] != '$')
+ name = concat (current_directory, "/", name, NULL);
+ else
+ name = savestring (name, p - name);
+ make_cleanup (free, name);
+
+ /* Unless it's a variable, check existence. */
+ if (name[0] != '$') {
+ /* These are warnings, not errors, since we don't want a
+ non-existent directory in a .gdbinit file to stop processing
+ of the .gdbinit file.
+
+ Whether they get added to the path is more debatable. Current
+ answer is yes, in case the user wants to go make the directory
+ or whatever. If the directory continues to not exist/not be
+ a directory/etc, then having them in the path should be
+ harmless. */
+ if (stat (name, &st) < 0)
+ {
+ int save_errno = errno;
+ fprintf_unfiltered (gdb_stderr, "Warning: ");
+ print_sys_errmsg (name, save_errno);
+ }
+ else if ((st.st_mode & S_IFMT) != S_IFDIR)
+ warning ("%s is not a directory.", name);
+ }
+
+ append:
+ {
+ register unsigned int len = strlen (name);
+
+ p = *which_path;
+ while (1)
+ {
+ if (!strncmp (p, name, len)
+ && (p[len] == '\0' || p[len] == DIRNAME_SEPARATOR))
+ {
+ /* Found it in the search path, remove old copy */
+ if (p > *which_path)
+ p--; /* Back over leading colon */
+ if (prefix > p - *which_path)
+ goto skip_dup; /* Same dir twice in one cmd */
+ strcpy (p, &p[len+1]); /* Copy from next \0 or : */
+ }
+ p = strchr (p, DIRNAME_SEPARATOR);
+ if (p != 0)
+ ++p;
+ else
+ break;
+ }
+ if (p == 0)
+ {
+ char tinybuf[2];
+
+ tinybuf[0] = DIRNAME_SEPARATOR;
+ tinybuf[1] = '\0';
+
+ /* If we have already tacked on a name(s) in this command, be sure they stay on the front as we tack on some more. */
+ if (prefix)
+ {
+ char *temp, c;
+
+ c = old[prefix];
+ old[prefix] = '\0';
+ temp = concat (old, tinybuf, name, NULL);
+ old[prefix] = c;
+ *which_path = concat (temp, "", &old[prefix], NULL);
+ prefix = strlen (temp);
+ free (temp);
+ }
+ else
+ {
+ *which_path = concat (name, (old[0] ? tinybuf : old), old, NULL);
+ prefix = strlen (name);
+ }
+ free (old);
+ old = *which_path;
+ }
+ }
+ skip_dup: ;
+ } while (*dirname != '\0');
+}
+
+
+static void
+source_info (ignore, from_tty)
+ char *ignore;
+ int from_tty;
+{
+ register struct symtab *s = current_source_symtab;
+
+ if (!s)
+ {
+ printf_filtered("No current source file.\n");
+ return;
+ }
+ printf_filtered ("Current source file is %s\n", s->filename);
+ if (s->dirname)
+ printf_filtered ("Compilation directory is %s\n", s->dirname);
+ if (s->fullname)
+ printf_filtered ("Located in %s\n", s->fullname);
+ if (s->nlines)
+ printf_filtered ("Contains %d line%s.\n", s->nlines,
+ s->nlines == 1 ? "" : "s");
+
+ printf_filtered("Source language is %s.\n", language_str (s->language));
+}
+
+
+
+/* Open a file named STRING, searching path PATH (dir names sep by some char)
+ using mode MODE and protection bits PROT in the calls to open.
+
+ If TRY_CWD_FIRST, try to open ./STRING before searching PATH.
+ (ie pretend the first element of PATH is "."). This also indicates
+ that a slash in STRING disables searching of the path (this is
+ so that "exec-file ./foo" or "symbol-file ./foo" insures that you
+ get that particular version of foo or an error message).
+
+ If FILENAMED_OPENED is non-null, set it to a newly allocated string naming
+ the actual file opened (this string will always start with a "/". We
+ have to take special pains to avoid doubling the "/" between the directory
+ and the file, sigh! Emacs gets confuzzed by this when we print the
+ source file name!!!
+
+ If a file is found, return the descriptor.
+ Otherwise, return -1, with errno set for the last name we tried to open. */
+
+/* >>>> This should only allow files of certain types,
+ >>>> eg executable, non-directory */
+int
+openp (path, try_cwd_first, string, mode, prot, filename_opened)
+ char *path;
+ int try_cwd_first;
+ char *string;
+ int mode;
+ int prot;
+ char **filename_opened;
+{
+ register int fd;
+ register char *filename;
+ register char *p, *p1;
+ register int len;
+ int alloclen;
+
+ if (!path)
+ path = ".";
+
+ if (try_cwd_first || string[0] == '/')
+ {
+ filename = string;
+ fd = open (filename, mode, prot);
+ if (fd >= 0 || string[0] == '/' || strchr (string, '/'))
+ goto done;
+ }
+
+ /* ./foo => foo */
+ while (string[0] == '.' && string[1] == '/')
+ string += 2;
+
+ alloclen = strlen (path) + strlen (string) + 2;
+ filename = (char *) alloca (alloclen);
+ fd = -1;
+ for (p = path; p; p = p1 ? p1 + 1 : 0)
+ {
+ p1 = (char *) strchr (p, DIRNAME_SEPARATOR);
+ if (p1)
+ len = p1 - p;
+ else
+ len = strlen (p);
+
+ if (len == 4 && p[0] == '$' && p[1] == 'c'
+ && p[2] == 'w' && p[3] == 'd') {
+ /* Name is $cwd -- insert current directory name instead. */
+ int newlen;
+
+ /* First, realloc the filename buffer if too short. */
+ len = strlen (current_directory);
+ newlen = len + strlen (string) + 2;
+ if (newlen > alloclen) {
+ alloclen = newlen;
+ filename = (char *) alloca (alloclen);
+ }
+ strcpy (filename, current_directory);
+ } else {
+ /* Normal file name in path -- just use it. */
+ strncpy (filename, p, len);
+ filename[len] = 0;
+ }
+
+ /* Remove trailing slashes */
+ while (len > 0 && filename[len-1] == '/')
+ filename[--len] = 0;
+
+ strcat (filename+len, "/");
+ strcat (filename, string);
+
+ fd = open (filename, mode);
+ if (fd >= 0) break;
+ }
+
+ done:
+ if (filename_opened)
+ if (fd < 0)
+ *filename_opened = (char *) 0;
+ else if (filename[0] == '/')
+ *filename_opened = savestring (filename, strlen (filename));
+ else
+ {
+ /* Beware the // my son, the Emacs barfs, the botch that catch... */
+
+ *filename_opened = concat (current_directory,
+ '/' == current_directory[strlen(current_directory)-1]? "": "/",
+ filename, NULL);
+ }
+
+ return fd;
+}
+
+/* Open a source file given a symtab S. Returns a file descriptor
+ or negative number for error. */
+
+static int
+open_source_file (s)
+ struct symtab *s;
+{
+ char *path = source_path;
+ char *p;
+ int result;
+ char *fullname;
+
+ /* Quick way out if we already know its full name */
+ if (s->fullname)
+ {
+ result = open (s->fullname, O_RDONLY);
+ if (result >= 0)
+ return result;
+ /* Didn't work -- free old one, try again. */
+ mfree (s->objfile->md, s->fullname);
+ s->fullname = NULL;
+ }
+
+ if (s->dirname != NULL)
+ {
+ /* Replace a path entry of $cdir with the compilation directory name */
+#define cdir_len 5
+ /* We cast strstr's result in case an ANSIhole has made it const,
+ which produces a "required warning" when assigned to a nonconst. */
+ p = (char *)strstr (source_path, "$cdir");
+ if (p && (p == path || p[-1] == DIRNAME_SEPARATOR)
+ && (p[cdir_len] == DIRNAME_SEPARATOR || p[cdir_len] == '\0')) {
+ int len;
+
+ path = (char *)
+ alloca (strlen (source_path) + 1 + strlen (s->dirname) + 1);
+ len = p - source_path;
+ strncpy (path, source_path, len); /* Before $cdir */
+ strcpy (path + len, s->dirname); /* new stuff */
+ strcat (path + len, source_path + len + cdir_len); /* After $cdir */
+ }
+ }
+
+ result = openp (path, 0, s->filename, O_RDONLY, 0, &s->fullname);
+ if (result < 0)
+ {
+ /* Didn't work. Try using just the basename. */
+ p = basename (s->filename);
+ if (p != s->filename)
+ result = openp (path, 0, p, O_RDONLY, 0, &s->fullname);
+ }
+ if (result >= 0)
+ {
+ fullname = s->fullname;
+ s->fullname = mstrsave (s->objfile->md, s->fullname);
+ free (fullname);
+ }
+ return result;
+}
+
+
+/* Create and initialize the table S->line_charpos that records
+ the positions of the lines in the source file, which is assumed
+ to be open on descriptor DESC.
+ All set S->nlines to the number of such lines. */
+
+static void
+find_source_lines (s, desc)
+ struct symtab *s;
+ int desc;
+{
+ struct stat st;
+ register char *data, *p, *end;
+ int nlines = 0;
+ int lines_allocated = 1000;
+ int *line_charpos;
+ long exec_mtime;
+ int size;
+
+ line_charpos = (int *) xmmalloc (s -> objfile -> md,
+ lines_allocated * sizeof (int));
+ if (fstat (desc, &st) < 0)
+ perror_with_name (s->filename);
+
+ if (exec_bfd)
+ {
+ exec_mtime = bfd_get_mtime(exec_bfd);
+ if (exec_mtime && exec_mtime < st.st_mtime)
+ printf_filtered ("Source file is more recent than executable.\n");
+ }
+
+#ifdef LSEEK_NOT_LINEAR
+ {
+ char c;
+
+ /* Have to read it byte by byte to find out where the chars live */
+
+ line_charpos[0] = tell(desc);
+ nlines = 1;
+ while (myread(desc, &c, 1)>0)
+ {
+ if (c == '\n')
+ {
+ if (nlines == lines_allocated)
+ {
+ lines_allocated *= 2;
+ line_charpos =
+ (int *) xmrealloc (s -> objfile -> md, (char *) line_charpos,
+ sizeof (int) * lines_allocated);
+ }
+ line_charpos[nlines++] = tell(desc);
+ }
+ }
+ }
+#else /* lseek linear. */
+ {
+ struct cleanup *old_cleanups;
+
+ /* st_size might be a large type, but we only support source files whose
+ size fits in an int. */
+ size = (int) st.st_size;
+
+ /* Use malloc, not alloca, because this may be pretty large, and we may
+ run into various kinds of limits on stack size. */
+ data = (char *) xmalloc (size);
+ old_cleanups = make_cleanup (free, data);
+
+ if (myread (desc, data, size) < 0)
+ perror_with_name (s->filename);
+ end = data + size;
+ p = data;
+ line_charpos[0] = 0;
+ nlines = 1;
+ while (p != end)
+ {
+ if (*p++ == '\n'
+ /* A newline at the end does not start a new line. */
+ && p != end)
+ {
+ if (nlines == lines_allocated)
+ {
+ lines_allocated *= 2;
+ line_charpos =
+ (int *) xmrealloc (s -> objfile -> md, (char *) line_charpos,
+ sizeof (int) * lines_allocated);
+ }
+ line_charpos[nlines++] = p - data;
+ }
+ }
+ do_cleanups (old_cleanups);
+ }
+#endif /* lseek linear. */
+ s->nlines = nlines;
+ s->line_charpos =
+ (int *) xmrealloc (s -> objfile -> md, (char *) line_charpos,
+ nlines * sizeof (int));
+
+}
+
+/* Return the character position of a line LINE in symtab S.
+ Return 0 if anything is invalid. */
+
+#if 0 /* Currently unused */
+
+int
+source_line_charpos (s, line)
+ struct symtab *s;
+ int line;
+{
+ if (!s) return 0;
+ if (!s->line_charpos || line <= 0) return 0;
+ if (line > s->nlines)
+ line = s->nlines;
+ return s->line_charpos[line - 1];
+}
+
+/* Return the line number of character position POS in symtab S. */
+
+int
+source_charpos_line (s, chr)
+ register struct symtab *s;
+ register int chr;
+{
+ register int line = 0;
+ register int *lnp;
+
+ if (s == 0 || s->line_charpos == 0) return 0;
+ lnp = s->line_charpos;
+ /* Files are usually short, so sequential search is Ok */
+ while (line < s->nlines && *lnp <= chr)
+ {
+ line++;
+ lnp++;
+ }
+ if (line >= s->nlines)
+ line = s->nlines;
+ return line;
+}
+
+#endif /* 0 */
+
+
+/* Get full pathname and line number positions for a symtab.
+ Return nonzero if line numbers may have changed.
+ Set *FULLNAME to actual name of the file as found by `openp',
+ or to 0 if the file is not found. */
+
+static int
+get_filename_and_charpos (s, fullname)
+ struct symtab *s;
+ char **fullname;
+{
+ register int desc, linenums_changed = 0;
+
+ desc = open_source_file (s);
+ if (desc < 0)
+ {
+ if (fullname)
+ *fullname = NULL;
+ return 0;
+ }
+ if (fullname)
+ *fullname = s->fullname;
+ if (s->line_charpos == 0) linenums_changed = 1;
+ if (linenums_changed) find_source_lines (s, desc);
+ close (desc);
+ return linenums_changed;
+}
+
+/* Print text describing the full name of the source file S
+ and the line number LINE and its corresponding character position.
+ The text starts with two Ctrl-z so that the Emacs-GDB interface
+ can easily find it.
+
+ MID_STATEMENT is nonzero if the PC is not at the beginning of that line.
+
+ Return 1 if successful, 0 if could not find the file. */
+
+int
+identify_source_line (s, line, mid_statement, pc)
+ struct symtab *s;
+ int line;
+ int mid_statement;
+ CORE_ADDR pc;
+{
+ if (s->line_charpos == 0)
+ get_filename_and_charpos (s, (char **)NULL);
+ if (s->fullname == 0)
+ return 0;
+ if (line > s->nlines)
+ /* Don't index off the end of the line_charpos array. */
+ return 0;
+ annotate_source (s->fullname, line, s->line_charpos[line - 1],
+ mid_statement, pc);
+
+ current_source_line = line;
+ first_line_listed = line;
+ last_line_listed = line;
+ current_source_symtab = s;
+ return 1;
+}
+
+/* Print source lines from the file of symtab S,
+ starting with line number LINE and stopping before line number STOPLINE. */
+
+void
+print_source_lines (s, line, stopline, noerror)
+ struct symtab *s;
+ int line, stopline;
+ int noerror;
+{
+ register int c;
+ register int desc;
+ register FILE *stream;
+ int nlines = stopline - line;
+
+ /* Regardless of whether we can open the file, set current_source_symtab. */
+ current_source_symtab = s;
+ current_source_line = line;
+ first_line_listed = line;
+
+ desc = open_source_file (s);
+ if (desc < 0)
+ {
+ if (! noerror) {
+ char *name = alloca (strlen (s->filename) + 100);
+ sprintf (name, "%s:%d", s->filename, line);
+ print_sys_errmsg (name, errno);
+ }
+ return;
+ }
+
+ if (s->line_charpos == 0)
+ find_source_lines (s, desc);
+
+ if (line < 1 || line > s->nlines)
+ {
+ close (desc);
+ error ("Line number %d out of range; %s has %d lines.",
+ line, s->filename, s->nlines);
+ }
+
+ if (lseek (desc, s->line_charpos[line - 1], 0) < 0)
+ {
+ close (desc);
+ perror_with_name (s->filename);
+ }
+
+ stream = fdopen (desc, FOPEN_RT);
+ clearerr (stream);
+
+ while (nlines-- > 0)
+ {
+ c = fgetc (stream);
+ if (c == EOF) break;
+ last_line_listed = current_source_line;
+ printf_filtered ("%d\t", current_source_line++);
+ do
+ {
+ if (c < 040 && c != '\t' && c != '\n' && c != '\r')
+ printf_filtered ("^%c", c + 0100);
+ else if (c == 0177)
+ printf_filtered ("^?");
+ else
+ printf_filtered ("%c", c);
+ } while (c != '\n' && (c = fgetc (stream)) >= 0);
+ }
+
+ fclose (stream);
+}
+
+
+
+/*
+ C++
+ Print a list of files and line numbers which a user may choose from
+ in order to list a function which was specified ambiguously
+ (as with `list classname::overloadedfuncname', for example).
+ The vector in SALS provides the filenames and line numbers.
+ */
+static void
+ambiguous_line_spec (sals)
+ struct symtabs_and_lines *sals;
+{
+ int i;
+
+ for (i = 0; i < sals->nelts; ++i)
+ printf_filtered("file: \"%s\", line number: %d\n",
+ sals->sals[i].symtab->filename, sals->sals[i].line);
+}
+
+
+static void
+list_command (arg, from_tty)
+ char *arg;
+ int from_tty;
+{
+ struct symtabs_and_lines sals, sals_end;
+ struct symtab_and_line sal, sal_end;
+ struct symbol *sym;
+ char *arg1;
+ int no_end = 1;
+ int dummy_end = 0;
+ int dummy_beg = 0;
+ int linenum_beg = 0;
+ char *p;
+
+ if (!have_full_symbols () && !have_partial_symbols())
+ error ("No symbol table is loaded. Use the \"file\" command.");
+
+ /* Pull in a current source symtab if necessary */
+ if (current_source_symtab == 0 &&
+ (arg == 0 || arg[0] == '+' || arg[0] == '-'))
+ select_source_symtab (0);
+
+ /* "l" or "l +" lists next ten lines. */
+
+ if (arg == 0 || STREQ (arg, "+"))
+ {
+ if (current_source_symtab == 0)
+ error ("No default source file yet. Do \"help list\".");
+ print_source_lines (current_source_symtab, current_source_line,
+ current_source_line + lines_to_list, 0);
+ return;
+ }
+
+ /* "l -" lists previous ten lines, the ones before the ten just listed. */
+ if (STREQ (arg, "-"))
+ {
+ if (current_source_symtab == 0)
+ error ("No default source file yet. Do \"help list\".");
+ print_source_lines (current_source_symtab,
+ max (first_line_listed - lines_to_list, 1),
+ first_line_listed, 0);
+ return;
+ }
+
+ /* Now if there is only one argument, decode it in SAL
+ and set NO_END.
+ If there are two arguments, decode them in SAL and SAL_END
+ and clear NO_END; however, if one of the arguments is blank,
+ set DUMMY_BEG or DUMMY_END to record that fact. */
+
+ arg1 = arg;
+ if (*arg1 == ',')
+ dummy_beg = 1;
+ else
+ {
+ sals = decode_line_1 (&arg1, 0, 0, 0, 0);
+
+ if (! sals.nelts) return; /* C++ */
+ if (sals.nelts > 1)
+ {
+ ambiguous_line_spec (&sals);
+ free (sals.sals);
+ return;
+ }
+
+ sal = sals.sals[0];
+ free (sals.sals);
+ }
+
+ /* Record whether the BEG arg is all digits. */
+
+ for (p = arg; p != arg1 && *p >= '0' && *p <= '9'; p++);
+ linenum_beg = (p == arg1);
+
+ while (*arg1 == ' ' || *arg1 == '\t')
+ arg1++;
+ if (*arg1 == ',')
+ {
+ no_end = 0;
+ arg1++;
+ while (*arg1 == ' ' || *arg1 == '\t')
+ arg1++;
+ if (*arg1 == 0)
+ dummy_end = 1;
+ else
+ {
+ if (dummy_beg)
+ sals_end = decode_line_1 (&arg1, 0, 0, 0, 0);
+ else
+ sals_end = decode_line_1 (&arg1, 0, sal.symtab, sal.line, 0);
+ if (sals_end.nelts == 0)
+ return;
+ if (sals_end.nelts > 1)
+ {
+ ambiguous_line_spec (&sals_end);
+ free (sals_end.sals);
+ return;
+ }
+ sal_end = sals_end.sals[0];
+ free (sals_end.sals);
+ }
+ }
+
+ if (*arg1)
+ error ("Junk at end of line specification.");
+
+ if (!no_end && !dummy_beg && !dummy_end
+ && sal.symtab != sal_end.symtab)
+ error ("Specified start and end are in different files.");
+ if (dummy_beg && dummy_end)
+ error ("Two empty args do not say what lines to list.");
+
+ /* if line was specified by address,
+ first print exactly which line, and which file.
+ In this case, sal.symtab == 0 means address is outside
+ of all known source files, not that user failed to give a filename. */
+ if (*arg == '*')
+ {
+ if (sal.symtab == 0)
+ /* FIXME-32x64--assumes sal.pc fits in long. */
+ error ("No source file for address %s.",
+ local_hex_string((unsigned long) sal.pc));
+ sym = find_pc_function (sal.pc);
+ if (sym)
+ {
+ print_address_numeric (sal.pc, 1, gdb_stdout);
+ printf_filtered (" is in ");
+ fputs_filtered (SYMBOL_SOURCE_NAME (sym), gdb_stdout);
+ printf_filtered (" (%s:%d).\n", sal.symtab->filename, sal.line);
+ }
+ else
+ {
+ print_address_numeric (sal.pc, 1, gdb_stdout);
+ printf_filtered (" is at %s:%d.\n",
+ sal.symtab->filename, sal.line);
+ }
+ }
+
+ /* If line was not specified by just a line number,
+ and it does not imply a symtab, it must be an undebuggable symbol
+ which means no source code. */
+
+ if (! linenum_beg && sal.symtab == 0)
+ error ("No line number known for %s.", arg);
+
+ /* If this command is repeated with RET,
+ turn it into the no-arg variant. */
+
+ if (from_tty)
+ *arg = 0;
+
+ if (dummy_beg && sal_end.symtab == 0)
+ error ("No default source file yet. Do \"help list\".");
+ if (dummy_beg)
+ print_source_lines (sal_end.symtab,
+ max (sal_end.line - (lines_to_list - 1), 1),
+ sal_end.line + 1, 0);
+ else if (sal.symtab == 0)
+ error ("No default source file yet. Do \"help list\".");
+ else if (no_end)
+ print_source_lines (sal.symtab,
+ max (sal.line - (lines_to_list / 2), 1),
+ sal.line + (lines_to_list / 2), 0);
+ else
+ print_source_lines (sal.symtab, sal.line,
+ (dummy_end
+ ? sal.line + lines_to_list
+ : sal_end.line + 1),
+ 0);
+}
+
+/* Print info on range of pc's in a specified line. */
+
+static void
+line_info (arg, from_tty)
+ char *arg;
+ int from_tty;
+{
+ struct symtabs_and_lines sals;
+ struct symtab_and_line sal;
+ CORE_ADDR start_pc, end_pc;
+ int i;
+
+ if (arg == 0)
+ {
+ sal.symtab = current_source_symtab;
+ sal.line = last_line_listed;
+ sals.nelts = 1;
+ sals.sals = (struct symtab_and_line *)
+ xmalloc (sizeof (struct symtab_and_line));
+ sals.sals[0] = sal;
+ }
+ else
+ {
+ sals = decode_line_spec_1 (arg, 0);
+
+ dont_repeat ();
+ }
+
+ /* C++ More than one line may have been specified, as when the user
+ specifies an overloaded function name. Print info on them all. */
+ for (i = 0; i < sals.nelts; i++)
+ {
+ sal = sals.sals[i];
+
+ if (sal.symtab == 0)
+ {
+ printf_filtered ("No line number information available");
+ if (sal.pc != 0)
+ {
+ /* This is useful for "info line *0x7f34". If we can't tell the
+ user about a source line, at least let them have the symbolic
+ address. */
+ printf_filtered (" for address ");
+ wrap_here (" ");
+ print_address (sal.pc, gdb_stdout);
+ }
+ else
+ printf_filtered (".");
+ printf_filtered ("\n");
+ }
+ else if (sal.line > 0
+ && find_line_pc_range (sal, &start_pc, &end_pc))
+ {
+ if (start_pc == end_pc)
+ {
+ printf_filtered ("Line %d of \"%s\"",
+ sal.line, sal.symtab->filename);
+ wrap_here (" ");
+ printf_filtered (" is at address ");
+ print_address (start_pc, gdb_stdout);
+ wrap_here (" ");
+ printf_filtered (" but contains no code.\n");
+ }
+ else
+ {
+ printf_filtered ("Line %d of \"%s\"",
+ sal.line, sal.symtab->filename);
+ wrap_here (" ");
+ printf_filtered (" starts at address ");
+ print_address (start_pc, gdb_stdout);
+ wrap_here (" ");
+ printf_filtered (" and ends at ");
+ print_address (end_pc, gdb_stdout);
+ printf_filtered (".\n");
+ }
+
+ /* x/i should display this line's code. */
+ set_next_address (start_pc);
+
+ /* Repeating "info line" should do the following line. */
+ last_line_listed = sal.line + 1;
+
+ /* If this is the only line, show the source code. If it could
+ not find the file, don't do anything special. */
+ if (annotation_level && sals.nelts == 1)
+ identify_source_line (sal.symtab, sal.line, 0, start_pc);
+ }
+ else
+ /* Is there any case in which we get here, and have an address
+ which the user would want to see? If we have debugging symbols
+ and no line numbers? */
+ printf_filtered ("Line number %d is out of range for \"%s\".\n",
+ sal.line, sal.symtab->filename);
+ }
+ free (sals.sals);
+}
+
+/* Commands to search the source file for a regexp. */
+
+/* ARGSUSED */
+static void
+forward_search_command (regex, from_tty)
+ char *regex;
+ int from_tty;
+{
+ register int c;
+ register int desc;
+ register FILE *stream;
+ int line = last_line_listed + 1;
+ char *msg;
+
+ msg = (char *) re_comp (regex);
+ if (msg)
+ error (msg);
+
+ if (current_source_symtab == 0)
+ select_source_symtab (0);
+
+ /* Search from last_line_listed+1 in current_source_symtab */
+
+ desc = open_source_file (current_source_symtab);
+ if (desc < 0)
+ perror_with_name (current_source_symtab->filename);
+
+ if (current_source_symtab->line_charpos == 0)
+ find_source_lines (current_source_symtab, desc);
+
+ if (line < 1 || line > current_source_symtab->nlines)
+ {
+ close (desc);
+ error ("Expression not found");
+ }
+
+ if (lseek (desc, current_source_symtab->line_charpos[line - 1], 0) < 0)
+ {
+ close (desc);
+ perror_with_name (current_source_symtab->filename);
+ }
+
+ stream = fdopen (desc, FOPEN_RT);
+ clearerr (stream);
+ while (1) {
+/* FIXME!!! We walk right off the end of buf if we get a long line!!! */
+ char buf[4096]; /* Should be reasonable??? */
+ register char *p = buf;
+
+ c = getc (stream);
+ if (c == EOF)
+ break;
+ do {
+ *p++ = c;
+ } while (c != '\n' && (c = getc (stream)) >= 0);
+
+ /* we now have a source line in buf, null terminate and match */
+ *p = 0;
+ if (re_exec (buf) > 0)
+ {
+ /* Match! */
+ fclose (stream);
+ print_source_lines (current_source_symtab,
+ line, line+1, 0);
+ current_source_line = max (line - lines_to_list / 2, 1);
+ return;
+ }
+ line++;
+ }
+
+ printf_filtered ("Expression not found\n");
+ fclose (stream);
+}
+
+/* ARGSUSED */
+static void
+reverse_search_command (regex, from_tty)
+ char *regex;
+ int from_tty;
+{
+ register int c;
+ register int desc;
+ register FILE *stream;
+ int line = last_line_listed - 1;
+ char *msg;
+
+ msg = (char *) re_comp (regex);
+ if (msg)
+ error (msg);
+
+ if (current_source_symtab == 0)
+ select_source_symtab (0);
+
+ /* Search from last_line_listed-1 in current_source_symtab */
+
+ desc = open_source_file (current_source_symtab);
+ if (desc < 0)
+ perror_with_name (current_source_symtab->filename);
+
+ if (current_source_symtab->line_charpos == 0)
+ find_source_lines (current_source_symtab, desc);
+
+ if (line < 1 || line > current_source_symtab->nlines)
+ {
+ close (desc);
+ error ("Expression not found");
+ }
+
+ if (lseek (desc, current_source_symtab->line_charpos[line - 1], 0) < 0)
+ {
+ close (desc);
+ perror_with_name (current_source_symtab->filename);
+ }
+
+ stream = fdopen (desc, FOPEN_RT);
+ clearerr (stream);
+ while (line > 1)
+ {
+/* FIXME!!! We walk right off the end of buf if we get a long line!!! */
+ char buf[4096]; /* Should be reasonable??? */
+ register char *p = buf;
+
+ c = getc (stream);
+ if (c == EOF)
+ break;
+ do {
+ *p++ = c;
+ } while (c != '\n' && (c = getc (stream)) >= 0);
+
+ /* We now have a source line in buf; null terminate and match. */
+ *p = 0;
+ if (re_exec (buf) > 0)
+ {
+ /* Match! */
+ fclose (stream);
+ print_source_lines (current_source_symtab,
+ line, line+1, 0);
+ current_source_line = max (line - lines_to_list / 2, 1);
+ return;
+ }
+ line--;
+ if (fseek (stream, current_source_symtab->line_charpos[line - 1], 0) < 0)
+ {
+ fclose (stream);
+ perror_with_name (current_source_symtab->filename);
+ }
+ }
+
+ printf_filtered ("Expression not found\n");
+ fclose (stream);
+ return;
+}
+
+void
+_initialize_source ()
+{
+ struct cmd_list_element *c;
+ current_source_symtab = 0;
+ init_source_path ();
+
+ /* The intention is to use POSIX Basic Regular Expressions.
+ Always use the GNU regex routine for consistency across all hosts.
+ Our current GNU regex.c does not have all the POSIX features, so this is
+ just an approximation. */
+ re_set_syntax (RE_SYNTAX_GREP);
+
+ c = add_cmd ("directory", class_files, directory_command,
+ "Add directory DIR to beginning of search path for source files.\n\
+Forget cached info on source file locations and line positions.\n\
+DIR can also be $cwd for the current working directory, or $cdir for the\n\
+directory in which the source file was compiled into object code.\n\
+With no argument, reset the search path to $cdir:$cwd, the default.",
+ &cmdlist);
+ c->completer = filename_completer;
+
+ add_cmd ("directories", no_class, show_directories,
+ "Current search path for finding source files.\n\
+$cwd in the path means the current working directory.\n\
+$cdir in the path means the compilation directory of the source file.",
+ &showlist);
+
+ add_info ("source", source_info,
+ "Information about the current source file.");
+
+ add_info ("line", line_info,
+ "Core addresses of the code for a source line.\n\
+Line can be specified as\n\
+ LINENUM, to list around that line in current file,\n\
+ FILE:LINENUM, to list around that line in that file,\n\
+ FUNCTION, to list around beginning of that function,\n\
+ FILE:FUNCTION, to distinguish among like-named static functions.\n\
+Default is to describe the last source line that was listed.\n\n\
+This sets the default address for \"x\" to the line's first instruction\n\
+so that \"x/i\" suffices to start examining the machine code.\n\
+The address is also stored as the value of \"$_\".");
+
+ add_com ("forward-search", class_files, forward_search_command,
+ "Search for regular expression (see regex(3)) from last line listed.");
+ add_com_alias ("search", "forward-search", class_files, 0);
+
+ add_com ("reverse-search", class_files, reverse_search_command,
+ "Search backward for regular expression (see regex(3)) from last line listed.");
+
+ add_com ("list", class_files, list_command,
+ "List specified function or line.\n\
+With no argument, lists ten more lines after or around previous listing.\n\
+\"list -\" lists the ten lines before a previous ten-line listing.\n\
+One argument specifies a line, and ten lines are listed around that line.\n\
+Two arguments with comma between specify starting and ending lines to list.\n\
+Lines can be specified in these ways:\n\
+ LINENUM, to list around that line in current file,\n\
+ FILE:LINENUM, to list around that line in that file,\n\
+ FUNCTION, to list around beginning of that function,\n\
+ FILE:FUNCTION, to distinguish among like-named static functions.\n\
+ *ADDRESS, to list around the line containing that address.\n\
+With two args if one is empty it stands for ten lines away from the other arg.");
+ add_com_alias ("l", "list", class_files, 1);
+
+ add_show_from_set
+ (add_set_cmd ("listsize", class_support, var_uinteger,
+ (char *)&lines_to_list,
+ "Set number of source lines gdb will list by default.",
+ &setlist),
+ &showlist);
+}
diff --git a/gnu/usr.bin/gdb/gdb/stabsread.c b/gnu/usr.bin/gdb/gdb/stabsread.c
new file mode 100644
index 0000000..7e4d32f
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/stabsread.c
@@ -0,0 +1,3948 @@
+/* Support routines for decoding "stabs" debugging information format.
+ Copyright 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994
+ Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* Support routines for reading and decoding debugging information in
+ the "stabs" format. This format is used with many systems that use
+ the a.out object file format, as well as some systems that use
+ COFF or ELF where the stabs data is placed in a special section.
+ Avoid placing any object file format specific code in this file. */
+
+#include "defs.h"
+#include <string.h>
+#include "bfd.h"
+#include "obstack.h"
+#include "symtab.h"
+#include "gdbtypes.h"
+#include "symfile.h"
+#include "objfiles.h"
+#include "aout/stab_gnu.h" /* We always use GNU stabs, not native */
+#include "libaout.h"
+#include "aout/aout64.h"
+#include "gdb-stabs.h"
+#include "buildsym.h"
+#include "complaints.h"
+#include "demangle.h"
+
+#include <ctype.h>
+
+/* Ask stabsread.h to define the vars it normally declares `extern'. */
+#define EXTERN /**/
+#include "stabsread.h" /* Our own declarations */
+#undef EXTERN
+
+/* The routines that read and process a complete stabs for a C struct or
+ C++ class pass lists of data member fields and lists of member function
+ fields in an instance of a field_info structure, as defined below.
+ This is part of some reorganization of low level C++ support and is
+ expected to eventually go away... (FIXME) */
+
+struct field_info
+{
+ struct nextfield
+ {
+ struct nextfield *next;
+
+ /* This is the raw visibility from the stab. It is not checked
+ for being one of the visibilities we recognize, so code which
+ examines this field better be able to deal. */
+ int visibility;
+
+ struct field field;
+ } *list;
+ struct next_fnfieldlist
+ {
+ struct next_fnfieldlist *next;
+ struct fn_fieldlist fn_fieldlist;
+ } *fnlist;
+};
+
+static struct type *
+dbx_alloc_type PARAMS ((int [2], struct objfile *));
+
+static long read_huge_number PARAMS ((char **, int, int *));
+
+static struct type *error_type PARAMS ((char **));
+
+static void
+patch_block_stabs PARAMS ((struct pending *, struct pending_stabs *,
+ struct objfile *));
+
+static void
+fix_common_block PARAMS ((struct symbol *, int));
+
+static int
+read_type_number PARAMS ((char **, int *));
+
+static struct type *
+read_range_type PARAMS ((char **, int [2], struct objfile *));
+
+static struct type *
+read_sun_builtin_type PARAMS ((char **, int [2], struct objfile *));
+
+static struct type *
+read_sun_floating_type PARAMS ((char **, int [2], struct objfile *));
+
+static struct type *
+read_enum_type PARAMS ((char **, struct type *, struct objfile *));
+
+static struct type *
+rs6000_builtin_type PARAMS ((int));
+
+static int
+read_member_functions PARAMS ((struct field_info *, char **, struct type *,
+ struct objfile *));
+
+static int
+read_struct_fields PARAMS ((struct field_info *, char **, struct type *,
+ struct objfile *));
+
+static int
+read_baseclasses PARAMS ((struct field_info *, char **, struct type *,
+ struct objfile *));
+
+static int
+read_tilde_fields PARAMS ((struct field_info *, char **, struct type *,
+ struct objfile *));
+
+static int
+attach_fn_fields_to_type PARAMS ((struct field_info *, struct type *));
+
+static int
+attach_fields_to_type PARAMS ((struct field_info *, struct type *,
+ struct objfile *));
+
+static struct type *
+read_struct_type PARAMS ((char **, struct type *, struct objfile *));
+
+static struct type *
+read_array_type PARAMS ((char **, struct type *, struct objfile *));
+
+static struct type **
+read_args PARAMS ((char **, int, struct objfile *));
+
+static int
+read_cpp_abbrev PARAMS ((struct field_info *, char **, struct type *,
+ struct objfile *));
+
+static const char vptr_name[] = { '_','v','p','t','r',CPLUS_MARKER,'\0' };
+static const char vb_name[] = { '_','v','b',CPLUS_MARKER,'\0' };
+
+/* Define this as 1 if a pcc declaration of a char or short argument
+ gives the correct address. Otherwise assume pcc gives the
+ address of the corresponding int, which is not the same on a
+ big-endian machine. */
+
+#ifndef BELIEVE_PCC_PROMOTION
+#define BELIEVE_PCC_PROMOTION 0
+#endif
+
+struct complaint invalid_cpp_abbrev_complaint =
+ {"invalid C++ abbreviation `%s'", 0, 0};
+
+struct complaint invalid_cpp_type_complaint =
+ {"C++ abbreviated type name unknown at symtab pos %d", 0, 0};
+
+struct complaint member_fn_complaint =
+ {"member function type missing, got '%c'", 0, 0};
+
+struct complaint const_vol_complaint =
+ {"const/volatile indicator missing, got '%c'", 0, 0};
+
+struct complaint error_type_complaint =
+ {"debug info mismatch between compiler and debugger", 0, 0};
+
+struct complaint invalid_member_complaint =
+ {"invalid (minimal) member type data format at symtab pos %d.", 0, 0};
+
+struct complaint range_type_base_complaint =
+ {"base type %d of range type is not defined", 0, 0};
+
+struct complaint reg_value_complaint =
+ {"register number too large in symbol %s", 0, 0};
+
+struct complaint vtbl_notfound_complaint =
+ {"virtual function table pointer not found when defining class `%s'", 0, 0};
+
+struct complaint unrecognized_cplus_name_complaint =
+ {"Unknown C++ symbol name `%s'", 0, 0};
+
+struct complaint rs6000_builtin_complaint =
+ {"Unknown builtin type %d", 0, 0};
+
+struct complaint stabs_general_complaint =
+ {"%s", 0, 0};
+
+/* Make a list of forward references which haven't been defined. */
+
+static struct type **undef_types;
+static int undef_types_allocated;
+static int undef_types_length;
+
+/* Check for and handle cretinous stabs symbol name continuation! */
+#define STABS_CONTINUE(pp) \
+ do { \
+ if (**(pp) == '\\' || (**(pp) == '?' && (*(pp))[1] == '\0')) \
+ *(pp) = next_symbol_text (); \
+ } while (0)
+
+/* FIXME: These probably should be our own types (like rs6000_builtin_type
+ has its own types) rather than builtin_type_*. */
+static struct type **os9k_type_vector[] = {
+ 0,
+ &builtin_type_int,
+ &builtin_type_char,
+ &builtin_type_long,
+ &builtin_type_short,
+ &builtin_type_unsigned_char,
+ &builtin_type_unsigned_short,
+ &builtin_type_unsigned_long,
+ &builtin_type_unsigned_int,
+ &builtin_type_float,
+ &builtin_type_double,
+ &builtin_type_void,
+ &builtin_type_long_double
+};
+
+static void os9k_init_type_vector PARAMS ((struct type **));
+
+static void
+os9k_init_type_vector(tv)
+ struct type **tv;
+{
+ int i;
+ for (i=0; i<sizeof(os9k_type_vector)/sizeof(struct type **); i++)
+ tv[i] = (os9k_type_vector[i] == 0 ? 0 : *(os9k_type_vector[i]));
+}
+
+/* Look up a dbx type-number pair. Return the address of the slot
+ where the type for that number-pair is stored.
+ The number-pair is in TYPENUMS.
+
+ This can be used for finding the type associated with that pair
+ or for associating a new type with the pair. */
+
+struct type **
+dbx_lookup_type (typenums)
+ int typenums[2];
+{
+ register int filenum = typenums[0];
+ register int index = typenums[1];
+ unsigned old_len;
+ register int real_filenum;
+ register struct header_file *f;
+ int f_orig_length;
+
+ if (filenum == -1) /* -1,-1 is for temporary types. */
+ return 0;
+
+ if (filenum < 0 || filenum >= n_this_object_header_files)
+ {
+ static struct complaint msg = {"\
+Invalid symbol data: type number (%d,%d) out of range at symtab pos %d.",
+ 0, 0};
+ complain (&msg, filenum, index, symnum);
+ goto error_return;
+ }
+
+ if (filenum == 0)
+ {
+ if (index < 0)
+ {
+ /* Caller wants address of address of type. We think
+ that negative (rs6k builtin) types will never appear as
+ "lvalues", (nor should they), so we stuff the real type
+ pointer into a temp, and return its address. If referenced,
+ this will do the right thing. */
+ static struct type *temp_type;
+
+ temp_type = rs6000_builtin_type(index);
+ return &temp_type;
+ }
+
+ /* Type is defined outside of header files.
+ Find it in this object file's type vector. */
+ if (index >= type_vector_length)
+ {
+ old_len = type_vector_length;
+ if (old_len == 0)
+ {
+ type_vector_length = INITIAL_TYPE_VECTOR_LENGTH;
+ type_vector = (struct type **)
+ malloc (type_vector_length * sizeof (struct type *));
+ }
+ while (index >= type_vector_length)
+ {
+ type_vector_length *= 2;
+ }
+ type_vector = (struct type **)
+ xrealloc ((char *) type_vector,
+ (type_vector_length * sizeof (struct type *)));
+ memset (&type_vector[old_len], 0,
+ (type_vector_length - old_len) * sizeof (struct type *));
+
+ if (os9k_stabs)
+ /* Deal with OS9000 fundamental types. */
+ os9k_init_type_vector (type_vector);
+ }
+ return (&type_vector[index]);
+ }
+ else
+ {
+ real_filenum = this_object_header_files[filenum];
+
+ if (real_filenum >= n_header_files)
+ {
+ struct type *temp_type;
+ struct type **temp_type_p;
+
+ warning ("GDB internal error: bad real_filenum");
+
+ error_return:
+ temp_type = init_type (TYPE_CODE_ERROR, 0, 0, NULL, NULL);
+ temp_type_p = (struct type **) xmalloc (sizeof (struct type *));
+ *temp_type_p = temp_type;
+ return temp_type_p;
+ }
+
+ f = &header_files[real_filenum];
+
+ f_orig_length = f->length;
+ if (index >= f_orig_length)
+ {
+ while (index >= f->length)
+ {
+ f->length *= 2;
+ }
+ f->vector = (struct type **)
+ xrealloc ((char *) f->vector, f->length * sizeof (struct type *));
+ memset (&f->vector[f_orig_length], 0,
+ (f->length - f_orig_length) * sizeof (struct type *));
+ }
+ return (&f->vector[index]);
+ }
+}
+
+/* Make sure there is a type allocated for type numbers TYPENUMS
+ and return the type object.
+ This can create an empty (zeroed) type object.
+ TYPENUMS may be (-1, -1) to return a new type object that is not
+ put into the type vector, and so may not be referred to by number. */
+
+static struct type *
+dbx_alloc_type (typenums, objfile)
+ int typenums[2];
+ struct objfile *objfile;
+{
+ register struct type **type_addr;
+
+ if (typenums[0] == -1)
+ {
+ return (alloc_type (objfile));
+ }
+
+ type_addr = dbx_lookup_type (typenums);
+
+ /* If we are referring to a type not known at all yet,
+ allocate an empty type for it.
+ We will fill it in later if we find out how. */
+ if (*type_addr == 0)
+ {
+ *type_addr = alloc_type (objfile);
+ }
+
+ return (*type_addr);
+}
+
+/* for all the stabs in a given stab vector, build appropriate types
+ and fix their symbols in given symbol vector. */
+
+static void
+patch_block_stabs (symbols, stabs, objfile)
+ struct pending *symbols;
+ struct pending_stabs *stabs;
+ struct objfile *objfile;
+{
+ int ii;
+ char *name;
+ char *pp;
+ struct symbol *sym;
+
+ if (stabs)
+ {
+
+ /* for all the stab entries, find their corresponding symbols and
+ patch their types! */
+
+ for (ii = 0; ii < stabs->count; ++ii)
+ {
+ name = stabs->stab[ii];
+ pp = (char*) strchr (name, ':');
+ while (pp[1] == ':')
+ {
+ pp += 2;
+ pp = (char *)strchr(pp, ':');
+ }
+ sym = find_symbol_in_list (symbols, name, pp-name);
+ if (!sym)
+ {
+ /* FIXME-maybe: it would be nice if we noticed whether
+ the variable was defined *anywhere*, not just whether
+ it is defined in this compilation unit. But neither
+ xlc or GCC seem to need such a definition, and until
+ we do psymtabs (so that the minimal symbols from all
+ compilation units are available now), I'm not sure
+ how to get the information. */
+
+ /* On xcoff, if a global is defined and never referenced,
+ ld will remove it from the executable. There is then
+ a N_GSYM stab for it, but no regular (C_EXT) symbol. */
+ sym = (struct symbol *)
+ obstack_alloc (&objfile->symbol_obstack,
+ sizeof (struct symbol));
+
+ memset (sym, 0, sizeof (struct symbol));
+ SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE;
+ SYMBOL_CLASS (sym) = LOC_OPTIMIZED_OUT;
+ SYMBOL_NAME (sym) =
+ obstack_copy0 (&objfile->symbol_obstack, name, pp - name);
+ pp += 2;
+ if (*(pp-1) == 'F' || *(pp-1) == 'f')
+ {
+ /* I don't think the linker does this with functions,
+ so as far as I know this is never executed.
+ But it doesn't hurt to check. */
+ SYMBOL_TYPE (sym) =
+ lookup_function_type (read_type (&pp, objfile));
+ }
+ else
+ {
+ SYMBOL_TYPE (sym) = read_type (&pp, objfile);
+ }
+ add_symbol_to_list (sym, &global_symbols);
+ }
+ else
+ {
+ pp += 2;
+ if (*(pp-1) == 'F' || *(pp-1) == 'f')
+ {
+ SYMBOL_TYPE (sym) =
+ lookup_function_type (read_type (&pp, objfile));
+ }
+ else
+ {
+ SYMBOL_TYPE (sym) = read_type (&pp, objfile);
+ }
+ }
+ }
+ }
+}
+
+
+/* Read a number by which a type is referred to in dbx data,
+ or perhaps read a pair (FILENUM, TYPENUM) in parentheses.
+ Just a single number N is equivalent to (0,N).
+ Return the two numbers by storing them in the vector TYPENUMS.
+ TYPENUMS will then be used as an argument to dbx_lookup_type.
+
+ Returns 0 for success, -1 for error. */
+
+static int
+read_type_number (pp, typenums)
+ register char **pp;
+ register int *typenums;
+{
+ int nbits;
+ if (**pp == '(')
+ {
+ (*pp)++;
+ typenums[0] = read_huge_number (pp, ',', &nbits);
+ if (nbits != 0) return -1;
+ typenums[1] = read_huge_number (pp, ')', &nbits);
+ if (nbits != 0) return -1;
+ }
+ else
+ {
+ typenums[0] = 0;
+ typenums[1] = read_huge_number (pp, 0, &nbits);
+ if (nbits != 0) return -1;
+ }
+ return 0;
+}
+
+
+/* To handle GNU C++ typename abbreviation, we need to be able to
+ fill in a type's name as soon as space for that type is allocated.
+ `type_synonym_name' is the name of the type being allocated.
+ It is cleared as soon as it is used (lest all allocated types
+ get this name). */
+
+static char *type_synonym_name;
+
+#if !defined (REG_STRUCT_HAS_ADDR)
+#define REG_STRUCT_HAS_ADDR(gcc_p,type) 0
+#endif
+
+/* ARGSUSED */
+struct symbol *
+define_symbol (valu, string, desc, type, objfile)
+ CORE_ADDR valu;
+ char *string;
+ int desc;
+ int type;
+ struct objfile *objfile;
+{
+ register struct symbol *sym;
+ char *p = (char *) strchr (string, ':');
+ int deftype;
+ int synonym = 0;
+ register int i;
+
+ /* We would like to eliminate nameless symbols, but keep their types.
+ E.g. stab entry ":t10=*2" should produce a type 10, which is a pointer
+ to type 2, but, should not create a symbol to address that type. Since
+ the symbol will be nameless, there is no way any user can refer to it. */
+
+ int nameless;
+
+ /* Ignore syms with empty names. */
+ if (string[0] == 0)
+ return 0;
+
+ /* Ignore old-style symbols from cc -go */
+ if (p == 0)
+ return 0;
+
+ while (p[1] == ':')
+ {
+ p += 2;
+ p = strchr(p, ':');
+ }
+
+ /* If a nameless stab entry, all we need is the type, not the symbol.
+ e.g. ":t10=*2" or a nameless enum like " :T16=ered:0,green:1,blue:2,;" */
+ nameless = (p == string || ((string[0] == ' ') && (string[1] == ':')));
+
+ sym = (struct symbol *)
+ obstack_alloc (&objfile -> symbol_obstack, sizeof (struct symbol));
+ memset (sym, 0, sizeof (struct symbol));
+
+ switch (type & N_TYPE)
+ {
+ case N_TEXT:
+ SYMBOL_SECTION(sym) = SECT_OFF_TEXT;
+ break;
+ case N_DATA:
+ SYMBOL_SECTION(sym) = SECT_OFF_DATA;
+ break;
+ case N_BSS:
+ SYMBOL_SECTION(sym) = SECT_OFF_BSS;
+ break;
+ }
+
+ if (processing_gcc_compilation)
+ {
+ /* GCC 2.x puts the line number in desc. SunOS apparently puts in the
+ number of bytes occupied by a type or object, which we ignore. */
+ SYMBOL_LINE(sym) = desc;
+ }
+ else
+ {
+ SYMBOL_LINE(sym) = 0; /* unknown */
+ }
+
+ if (string[0] == CPLUS_MARKER)
+ {
+ /* Special GNU C++ names. */
+ switch (string[1])
+ {
+ case 't':
+ SYMBOL_NAME (sym) = obsavestring ("this", strlen ("this"),
+ &objfile -> symbol_obstack);
+ break;
+
+ case 'v': /* $vtbl_ptr_type */
+ /* Was: SYMBOL_NAME (sym) = "vptr"; */
+ goto normal;
+
+ case 'e':
+ SYMBOL_NAME (sym) = obsavestring ("eh_throw", strlen ("eh_throw"),
+ &objfile -> symbol_obstack);
+ break;
+
+ case '_':
+ /* This was an anonymous type that was never fixed up. */
+ goto normal;
+
+ default:
+ complain (&unrecognized_cplus_name_complaint, string);
+ goto normal; /* Do *something* with it */
+ }
+ }
+ else
+ {
+ normal:
+ SYMBOL_LANGUAGE (sym) = current_subfile -> language;
+ SYMBOL_NAME (sym) = (char *)
+ obstack_alloc (&objfile -> symbol_obstack, ((p - string) + 1));
+ /* Open-coded memcpy--saves function call time. */
+ /* FIXME: Does it really? Try replacing with simple strcpy and
+ try it on an executable with a large symbol table. */
+ /* FIXME: considering that gcc can open code memcpy anyway, I
+ doubt it. xoxorich. */
+ {
+ register char *p1 = string;
+ register char *p2 = SYMBOL_NAME (sym);
+ while (p1 != p)
+ {
+ *p2++ = *p1++;
+ }
+ *p2++ = '\0';
+ }
+
+ /* If this symbol is from a C++ compilation, then attempt to cache the
+ demangled form for future reference. This is a typical time versus
+ space tradeoff, that was decided in favor of time because it sped up
+ C++ symbol lookups by a factor of about 20. */
+
+ SYMBOL_INIT_DEMANGLED_NAME (sym, &objfile->symbol_obstack);
+ }
+ p++;
+
+ /* Determine the type of name being defined. */
+#if 0
+ /* Getting GDB to correctly skip the symbol on an undefined symbol
+ descriptor and not ever dump core is a very dodgy proposition if
+ we do things this way. I say the acorn RISC machine can just
+ fix their compiler. */
+ /* The Acorn RISC machine's compiler can put out locals that don't
+ start with "234=" or "(3,4)=", so assume anything other than the
+ deftypes we know how to handle is a local. */
+ if (!strchr ("cfFGpPrStTvVXCR", *p))
+#else
+ if (isdigit (*p) || *p == '(' || *p == '-')
+#endif
+ deftype = 'l';
+ else
+ deftype = *p++;
+
+ switch (deftype)
+ {
+ case 'c':
+ /* c is a special case, not followed by a type-number.
+ SYMBOL:c=iVALUE for an integer constant symbol.
+ SYMBOL:c=rVALUE for a floating constant symbol.
+ SYMBOL:c=eTYPE,INTVALUE for an enum constant symbol.
+ e.g. "b:c=e6,0" for "const b = blob1"
+ (where type 6 is defined by "blobs:t6=eblob1:0,blob2:1,;"). */
+ if (*p != '=')
+ {
+ SYMBOL_CLASS (sym) = LOC_CONST;
+ SYMBOL_TYPE (sym) = error_type (&p);
+ SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE;
+ add_symbol_to_list (sym, &file_symbols);
+ return sym;
+ }
+ ++p;
+ switch (*p++)
+ {
+ case 'r':
+ {
+ double d = atof (p);
+ char *dbl_valu;
+
+ /* FIXME-if-picky-about-floating-accuracy: Should be using
+ target arithmetic to get the value. real.c in GCC
+ probably has the necessary code. */
+
+ /* FIXME: lookup_fundamental_type is a hack. We should be
+ creating a type especially for the type of float constants.
+ Problem is, what type should it be?
+
+ Also, what should the name of this type be? Should we
+ be using 'S' constants (see stabs.texinfo) instead? */
+
+ SYMBOL_TYPE (sym) = lookup_fundamental_type (objfile,
+ FT_DBL_PREC_FLOAT);
+ dbl_valu = (char *)
+ obstack_alloc (&objfile -> symbol_obstack,
+ TYPE_LENGTH (SYMBOL_TYPE (sym)));
+ store_floating (dbl_valu, TYPE_LENGTH (SYMBOL_TYPE (sym)), d);
+ SYMBOL_VALUE_BYTES (sym) = dbl_valu;
+ SYMBOL_CLASS (sym) = LOC_CONST_BYTES;
+ }
+ break;
+ case 'i':
+ {
+ /* Defining integer constants this way is kind of silly,
+ since 'e' constants allows the compiler to give not
+ only the value, but the type as well. C has at least
+ int, long, unsigned int, and long long as constant
+ types; other languages probably should have at least
+ unsigned as well as signed constants. */
+
+ /* We just need one int constant type for all objfiles.
+ It doesn't depend on languages or anything (arguably its
+ name should be a language-specific name for a type of
+ that size, but I'm inclined to say that if the compiler
+ wants a nice name for the type, it can use 'e'). */
+ static struct type *int_const_type;
+
+ /* Yes, this is as long as a *host* int. That is because we
+ use atoi. */
+ if (int_const_type == NULL)
+ int_const_type =
+ init_type (TYPE_CODE_INT,
+ sizeof (int) * HOST_CHAR_BIT / TARGET_CHAR_BIT, 0,
+ "integer constant",
+ (struct objfile *)NULL);
+ SYMBOL_TYPE (sym) = int_const_type;
+ SYMBOL_VALUE (sym) = atoi (p);
+ SYMBOL_CLASS (sym) = LOC_CONST;
+ }
+ break;
+ case 'e':
+ /* SYMBOL:c=eTYPE,INTVALUE for a constant symbol whose value
+ can be represented as integral.
+ e.g. "b:c=e6,0" for "const b = blob1"
+ (where type 6 is defined by "blobs:t6=eblob1:0,blob2:1,;"). */
+ {
+ SYMBOL_CLASS (sym) = LOC_CONST;
+ SYMBOL_TYPE (sym) = read_type (&p, objfile);
+
+ if (*p != ',')
+ {
+ SYMBOL_TYPE (sym) = error_type (&p);
+ break;
+ }
+ ++p;
+
+ /* If the value is too big to fit in an int (perhaps because
+ it is unsigned), or something like that, we silently get
+ a bogus value. The type and everything else about it is
+ correct. Ideally, we should be using whatever we have
+ available for parsing unsigned and long long values,
+ however. */
+ SYMBOL_VALUE (sym) = atoi (p);
+ }
+ break;
+ default:
+ {
+ SYMBOL_CLASS (sym) = LOC_CONST;
+ SYMBOL_TYPE (sym) = error_type (&p);
+ }
+ }
+ SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE;
+ add_symbol_to_list (sym, &file_symbols);
+ return sym;
+
+ case 'C':
+ /* The name of a caught exception. */
+ SYMBOL_TYPE (sym) = read_type (&p, objfile);
+ SYMBOL_CLASS (sym) = LOC_LABEL;
+ SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE;
+ SYMBOL_VALUE_ADDRESS (sym) = valu;
+ add_symbol_to_list (sym, &local_symbols);
+ break;
+
+ case 'f':
+ /* A static function definition. */
+ SYMBOL_TYPE (sym) = read_type (&p, objfile);
+ SYMBOL_CLASS (sym) = LOC_BLOCK;
+ SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE;
+ add_symbol_to_list (sym, &file_symbols);
+ /* fall into process_function_types. */
+
+ process_function_types:
+ /* Function result types are described as the result type in stabs.
+ We need to convert this to the function-returning-type-X type
+ in GDB. E.g. "int" is converted to "function returning int". */
+ if (TYPE_CODE (SYMBOL_TYPE (sym)) != TYPE_CODE_FUNC)
+ {
+#if 0
+ /* This code doesn't work -- it needs to realloc and can't. */
+ /* Attempt to set up to record a function prototype... */
+ struct type *new = alloc_type (objfile);
+
+ /* Generate a template for the type of this function. The
+ types of the arguments will be added as we read the symbol
+ table. */
+ *new = *lookup_function_type (SYMBOL_TYPE(sym));
+ SYMBOL_TYPE(sym) = new;
+ TYPE_OBJFILE (new) = objfile;
+ in_function_type = new;
+#else
+ SYMBOL_TYPE (sym) = lookup_function_type (SYMBOL_TYPE (sym));
+#endif
+ }
+ /* fall into process_prototype_types */
+
+ process_prototype_types:
+ /* Sun acc puts declared types of arguments here. We don't care
+ about their actual types (FIXME -- we should remember the whole
+ function prototype), but the list may define some new types
+ that we have to remember, so we must scan it now. */
+ while (*p == ';') {
+ p++;
+ read_type (&p, objfile);
+ }
+ break;
+
+ case 'F':
+ /* A global function definition. */
+ SYMBOL_TYPE (sym) = read_type (&p, objfile);
+ SYMBOL_CLASS (sym) = LOC_BLOCK;
+ SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE;
+ add_symbol_to_list (sym, &global_symbols);
+ goto process_function_types;
+
+ case 'G':
+ /* For a class G (global) symbol, it appears that the
+ value is not correct. It is necessary to search for the
+ corresponding linker definition to find the value.
+ These definitions appear at the end of the namelist. */
+ SYMBOL_TYPE (sym) = read_type (&p, objfile);
+ i = hashname (SYMBOL_NAME (sym));
+ SYMBOL_VALUE_CHAIN (sym) = global_sym_chain[i];
+ global_sym_chain[i] = sym;
+ SYMBOL_CLASS (sym) = LOC_STATIC;
+ SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE;
+ add_symbol_to_list (sym, &global_symbols);
+ break;
+
+ /* This case is faked by a conditional above,
+ when there is no code letter in the dbx data.
+ Dbx data never actually contains 'l'. */
+ case 's':
+ case 'l':
+ SYMBOL_TYPE (sym) = read_type (&p, objfile);
+ SYMBOL_CLASS (sym) = LOC_LOCAL;
+ SYMBOL_VALUE (sym) = valu;
+ SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE;
+ add_symbol_to_list (sym, &local_symbols);
+ break;
+
+ case 'p':
+ if (*p == 'F')
+ /* pF is a two-letter code that means a function parameter in Fortran.
+ The type-number specifies the type of the return value.
+ Translate it into a pointer-to-function type. */
+ {
+ p++;
+ SYMBOL_TYPE (sym)
+ = lookup_pointer_type
+ (lookup_function_type (read_type (&p, objfile)));
+ }
+ else
+ SYMBOL_TYPE (sym) = read_type (&p, objfile);
+
+ /* Normally this is a parameter, a LOC_ARG. On the i960, it
+ can also be a LOC_LOCAL_ARG depending on symbol type. */
+#ifndef DBX_PARM_SYMBOL_CLASS
+#define DBX_PARM_SYMBOL_CLASS(type) LOC_ARG
+#endif
+
+ SYMBOL_CLASS (sym) = DBX_PARM_SYMBOL_CLASS (type);
+ SYMBOL_VALUE (sym) = valu;
+ SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE;
+#if 0
+ /* This doesn't work yet. */
+ add_param_to_type (&in_function_type, sym);
+#endif
+ add_symbol_to_list (sym, &local_symbols);
+
+#if TARGET_BYTE_ORDER == LITTLE_ENDIAN
+ /* On little-endian machines, this crud is never necessary, and,
+ if the extra bytes contain garbage, is harmful. */
+ break;
+#else /* Big endian. */
+ /* If it's gcc-compiled, if it says `short', believe it. */
+ if (processing_gcc_compilation || BELIEVE_PCC_PROMOTION)
+ break;
+
+#if !BELIEVE_PCC_PROMOTION
+ {
+ /* This is the signed type which arguments get promoted to. */
+ static struct type *pcc_promotion_type;
+ /* This is the unsigned type which arguments get promoted to. */
+ static struct type *pcc_unsigned_promotion_type;
+
+ /* Call it "int" because this is mainly C lossage. */
+ if (pcc_promotion_type == NULL)
+ pcc_promotion_type =
+ init_type (TYPE_CODE_INT, TARGET_INT_BIT / TARGET_CHAR_BIT,
+ 0, "int", NULL);
+
+ if (pcc_unsigned_promotion_type == NULL)
+ pcc_unsigned_promotion_type =
+ init_type (TYPE_CODE_INT, TARGET_INT_BIT / TARGET_CHAR_BIT,
+ TYPE_FLAG_UNSIGNED, "unsigned int", NULL);
+
+#if defined(BELIEVE_PCC_PROMOTION_TYPE)
+ /* This macro is defined on machines (e.g. sparc) where
+ we should believe the type of a PCC 'short' argument,
+ but shouldn't believe the address (the address is
+ the address of the corresponding int).
+
+ My guess is that this correction, as opposed to changing
+ the parameter to an 'int' (as done below, for PCC
+ on most machines), is the right thing to do
+ on all machines, but I don't want to risk breaking
+ something that already works. On most PCC machines,
+ the sparc problem doesn't come up because the calling
+ function has to zero the top bytes (not knowing whether
+ the called function wants an int or a short), so there
+ is little practical difference between an int and a short
+ (except perhaps what happens when the GDB user types
+ "print short_arg = 0x10000;").
+
+ Hacked for SunOS 4.1 by gnu@cygnus.com. In 4.1, the compiler
+ actually produces the correct address (we don't need to fix it
+ up). I made this code adapt so that it will offset the symbol
+ if it was pointing at an int-aligned location and not
+ otherwise. This way you can use the same gdb for 4.0.x and
+ 4.1 systems.
+
+ If the parameter is shorter than an int, and is integral
+ (e.g. char, short, or unsigned equivalent), and is claimed to
+ be passed on an integer boundary, don't believe it! Offset the
+ parameter's address to the tail-end of that integer. */
+
+ if (TYPE_LENGTH (SYMBOL_TYPE (sym)) < TYPE_LENGTH (pcc_promotion_type)
+ && TYPE_CODE (SYMBOL_TYPE (sym)) == TYPE_CODE_INT
+ && 0 == SYMBOL_VALUE (sym) % TYPE_LENGTH (pcc_promotion_type))
+ {
+ SYMBOL_VALUE (sym) += TYPE_LENGTH (pcc_promotion_type)
+ - TYPE_LENGTH (SYMBOL_TYPE (sym));
+ }
+ break;
+
+#else /* no BELIEVE_PCC_PROMOTION_TYPE. */
+
+ /* If PCC says a parameter is a short or a char,
+ it is really an int. */
+ if (TYPE_LENGTH (SYMBOL_TYPE (sym)) < TYPE_LENGTH (pcc_promotion_type)
+ && TYPE_CODE (SYMBOL_TYPE (sym)) == TYPE_CODE_INT)
+ {
+ SYMBOL_TYPE (sym) =
+ TYPE_UNSIGNED (SYMBOL_TYPE (sym))
+ ? pcc_unsigned_promotion_type
+ : pcc_promotion_type;
+ }
+ break;
+
+#endif /* no BELIEVE_PCC_PROMOTION_TYPE. */
+ }
+#endif /* !BELIEVE_PCC_PROMOTION. */
+#endif /* Big endian. */
+
+ case 'P':
+ /* acc seems to use P to delare the prototypes of functions that
+ are referenced by this file. gdb is not prepared to deal
+ with this extra information. FIXME, it ought to. */
+ if (type == N_FUN)
+ {
+ read_type (&p, objfile);
+ goto process_prototype_types;
+ }
+ /*FALLTHROUGH*/
+
+ case 'R':
+ /* Parameter which is in a register. */
+ SYMBOL_TYPE (sym) = read_type (&p, objfile);
+ SYMBOL_CLASS (sym) = LOC_REGPARM;
+ SYMBOL_VALUE (sym) = STAB_REG_TO_REGNUM (valu);
+ if (SYMBOL_VALUE (sym) >= NUM_REGS)
+ {
+ complain (&reg_value_complaint, SYMBOL_SOURCE_NAME (sym));
+ SYMBOL_VALUE (sym) = SP_REGNUM; /* Known safe, though useless */
+ }
+ SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE;
+ add_symbol_to_list (sym, &local_symbols);
+ break;
+
+ case 'r':
+ /* Register variable (either global or local). */
+ SYMBOL_TYPE (sym) = read_type (&p, objfile);
+ SYMBOL_CLASS (sym) = LOC_REGISTER;
+ SYMBOL_VALUE (sym) = STAB_REG_TO_REGNUM (valu);
+ if (SYMBOL_VALUE (sym) >= NUM_REGS)
+ {
+ complain (&reg_value_complaint, SYMBOL_SOURCE_NAME (sym));
+ SYMBOL_VALUE (sym) = SP_REGNUM; /* Known safe, though useless */
+ }
+ SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE;
+ if (within_function)
+ {
+ /* Sun cc uses a pair of symbols, one 'p' and one 'r' with the same
+ name to represent an argument passed in a register.
+ GCC uses 'P' for the same case. So if we find such a symbol pair
+ we combine it into one 'P' symbol. For Sun cc we need to do this
+ regardless of REG_STRUCT_HAS_ADDR, because the compiler puts out
+ the 'p' symbol even if it never saves the argument onto the stack.
+
+ On most machines, we want to preserve both symbols, so that
+ we can still get information about what is going on with the
+ stack (VAX for computing args_printed, using stack slots instead
+ of saved registers in backtraces, etc.).
+
+ Note that this code illegally combines
+ main(argc) struct foo argc; { register struct foo argc; }
+ but this case is considered pathological and causes a warning
+ from a decent compiler. */
+
+ if (local_symbols
+ && local_symbols->nsyms > 0
+#ifndef USE_REGISTER_NOT_ARG
+ && REG_STRUCT_HAS_ADDR (processing_gcc_compilation,
+ SYMBOL_TYPE (sym))
+ && (TYPE_CODE (SYMBOL_TYPE (sym)) == TYPE_CODE_STRUCT
+ || TYPE_CODE (SYMBOL_TYPE (sym)) == TYPE_CODE_UNION)
+#endif
+ )
+ {
+ struct symbol *prev_sym;
+ prev_sym = local_symbols->symbol[local_symbols->nsyms - 1];
+ if ((SYMBOL_CLASS (prev_sym) == LOC_REF_ARG
+ || SYMBOL_CLASS (prev_sym) == LOC_ARG)
+ && STREQ (SYMBOL_NAME (prev_sym), SYMBOL_NAME(sym)))
+ {
+ SYMBOL_CLASS (prev_sym) = LOC_REGPARM;
+ /* Use the type from the LOC_REGISTER; that is the type
+ that is actually in that register. */
+ SYMBOL_TYPE (prev_sym) = SYMBOL_TYPE (sym);
+ SYMBOL_VALUE (prev_sym) = SYMBOL_VALUE (sym);
+ sym = prev_sym;
+ break;
+ }
+ }
+ add_symbol_to_list (sym, &local_symbols);
+ }
+ else
+ add_symbol_to_list (sym, &file_symbols);
+ break;
+
+ case 'S':
+ /* Static symbol at top level of file */
+ SYMBOL_TYPE (sym) = read_type (&p, objfile);
+ SYMBOL_CLASS (sym) = LOC_STATIC;
+ SYMBOL_VALUE_ADDRESS (sym) = valu;
+ SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE;
+ add_symbol_to_list (sym, &file_symbols);
+ break;
+
+ case 't':
+ SYMBOL_TYPE (sym) = read_type (&p, objfile);
+
+ /* For a nameless type, we don't want a create a symbol, thus we
+ did not use `sym'. Return without further processing. */
+ if (nameless) return NULL;
+
+ SYMBOL_CLASS (sym) = LOC_TYPEDEF;
+ SYMBOL_VALUE (sym) = valu;
+ SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE;
+ /* C++ vagaries: we may have a type which is derived from
+ a base type which did not have its name defined when the
+ derived class was output. We fill in the derived class's
+ base part member's name here in that case. */
+ if (TYPE_NAME (SYMBOL_TYPE (sym)) != NULL)
+ if ((TYPE_CODE (SYMBOL_TYPE (sym)) == TYPE_CODE_STRUCT
+ || TYPE_CODE (SYMBOL_TYPE (sym)) == TYPE_CODE_UNION)
+ && TYPE_N_BASECLASSES (SYMBOL_TYPE (sym)))
+ {
+ int j;
+ for (j = TYPE_N_BASECLASSES (SYMBOL_TYPE (sym)) - 1; j >= 0; j--)
+ if (TYPE_BASECLASS_NAME (SYMBOL_TYPE (sym), j) == 0)
+ TYPE_BASECLASS_NAME (SYMBOL_TYPE (sym), j) =
+ type_name_no_tag (TYPE_BASECLASS (SYMBOL_TYPE (sym), j));
+ }
+
+ if (TYPE_NAME (SYMBOL_TYPE (sym)) == NULL)
+ {
+ /* gcc-2.6 or later (when using -fvtable-thunks)
+ emits a unique named type for a vtable entry.
+ Some gdb code depends on that specific name. */
+ extern const char vtbl_ptr_name[];
+
+ if ((TYPE_CODE (SYMBOL_TYPE (sym)) == TYPE_CODE_PTR
+ && strcmp (SYMBOL_NAME (sym), vtbl_ptr_name))
+ || TYPE_CODE (SYMBOL_TYPE (sym)) == TYPE_CODE_FUNC)
+ {
+ /* If we are giving a name to a type such as "pointer to
+ foo" or "function returning foo", we better not set
+ the TYPE_NAME. If the program contains "typedef char
+ *caddr_t;", we don't want all variables of type char
+ * to print as caddr_t. This is not just a
+ consequence of GDB's type management; PCC and GCC (at
+ least through version 2.4) both output variables of
+ either type char * or caddr_t with the type number
+ defined in the 't' symbol for caddr_t. If a future
+ compiler cleans this up it GDB is not ready for it
+ yet, but if it becomes ready we somehow need to
+ disable this check (without breaking the PCC/GCC2.4
+ case).
+
+ Sigh.
+
+ Fortunately, this check seems not to be necessary
+ for anything except pointers or functions. */
+ }
+ else
+ TYPE_NAME (SYMBOL_TYPE (sym)) = SYMBOL_NAME (sym);
+ }
+
+ add_symbol_to_list (sym, &file_symbols);
+ break;
+
+ case 'T':
+ /* Struct, union, or enum tag. For GNU C++, this can be be followed
+ by 't' which means we are typedef'ing it as well. */
+ synonym = *p == 't';
+
+ if (synonym)
+ {
+ p++;
+ type_synonym_name = obsavestring (SYMBOL_NAME (sym),
+ strlen (SYMBOL_NAME (sym)),
+ &objfile -> symbol_obstack);
+ }
+ /* The semantics of C++ state that "struct foo { ... }" also defines
+ a typedef for "foo". Unfortunately, cfront never makes the typedef
+ when translating C++ into C. We make the typedef here so that
+ "ptype foo" works as expected for cfront translated code. */
+ else if (current_subfile->language == language_cplus)
+ {
+ synonym = 1;
+ type_synonym_name = obsavestring (SYMBOL_NAME (sym),
+ strlen (SYMBOL_NAME (sym)),
+ &objfile -> symbol_obstack);
+ }
+
+ SYMBOL_TYPE (sym) = read_type (&p, objfile);
+
+ /* For a nameless type, we don't want a create a symbol, thus we
+ did not use `sym'. Return without further processing. */
+ if (nameless) return NULL;
+
+ SYMBOL_CLASS (sym) = LOC_TYPEDEF;
+ SYMBOL_VALUE (sym) = valu;
+ SYMBOL_NAMESPACE (sym) = STRUCT_NAMESPACE;
+ if (TYPE_TAG_NAME (SYMBOL_TYPE (sym)) == 0)
+ TYPE_TAG_NAME (SYMBOL_TYPE (sym))
+ = obconcat (&objfile -> type_obstack, "", "", SYMBOL_NAME (sym));
+ add_symbol_to_list (sym, &file_symbols);
+
+ if (synonym)
+ {
+ /* Clone the sym and then modify it. */
+ register struct symbol *typedef_sym = (struct symbol *)
+ obstack_alloc (&objfile -> symbol_obstack, sizeof (struct symbol));
+ *typedef_sym = *sym;
+ SYMBOL_CLASS (typedef_sym) = LOC_TYPEDEF;
+ SYMBOL_VALUE (typedef_sym) = valu;
+ SYMBOL_NAMESPACE (typedef_sym) = VAR_NAMESPACE;
+ if (TYPE_NAME (SYMBOL_TYPE (sym)) == 0)
+ TYPE_NAME (SYMBOL_TYPE (sym))
+ = obconcat (&objfile -> type_obstack, "", "", SYMBOL_NAME (sym));
+ add_symbol_to_list (typedef_sym, &file_symbols);
+ }
+ break;
+
+ case 'V':
+ /* Static symbol of local scope */
+ SYMBOL_TYPE (sym) = read_type (&p, objfile);
+ SYMBOL_CLASS (sym) = LOC_STATIC;
+ SYMBOL_VALUE_ADDRESS (sym) = valu;
+ SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE;
+ if (os9k_stabs)
+ add_symbol_to_list (sym, &global_symbols);
+ else
+ add_symbol_to_list (sym, &local_symbols);
+ break;
+
+ case 'v':
+ /* Reference parameter */
+ SYMBOL_TYPE (sym) = read_type (&p, objfile);
+ SYMBOL_CLASS (sym) = LOC_REF_ARG;
+ SYMBOL_VALUE (sym) = valu;
+ SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE;
+ add_symbol_to_list (sym, &local_symbols);
+ break;
+
+ case 'X':
+ /* This is used by Sun FORTRAN for "function result value".
+ Sun claims ("dbx and dbxtool interfaces", 2nd ed)
+ that Pascal uses it too, but when I tried it Pascal used
+ "x:3" (local symbol) instead. */
+ SYMBOL_TYPE (sym) = read_type (&p, objfile);
+ SYMBOL_CLASS (sym) = LOC_LOCAL;
+ SYMBOL_VALUE (sym) = valu;
+ SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE;
+ add_symbol_to_list (sym, &local_symbols);
+ break;
+
+ default:
+ SYMBOL_TYPE (sym) = error_type (&p);
+ SYMBOL_CLASS (sym) = LOC_CONST;
+ SYMBOL_VALUE (sym) = 0;
+ SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE;
+ add_symbol_to_list (sym, &file_symbols);
+ break;
+ }
+
+ /* When passing structures to a function, some systems sometimes pass
+ the address in a register, not the structure itself.
+
+ If REG_STRUCT_HAS_ADDR yields non-zero we have to convert LOC_REGPARM
+ to LOC_REGPARM_ADDR for structures and unions. */
+
+ if (SYMBOL_CLASS (sym) == LOC_REGPARM
+ && REG_STRUCT_HAS_ADDR (processing_gcc_compilation,
+ SYMBOL_TYPE (sym))
+ && ((TYPE_CODE (SYMBOL_TYPE (sym)) == TYPE_CODE_STRUCT)
+ || (TYPE_CODE (SYMBOL_TYPE (sym)) == TYPE_CODE_UNION)))
+ SYMBOL_CLASS (sym) = LOC_REGPARM_ADDR;
+
+ /* Likewise for converting LOC_ARG to LOC_REF_ARG (for the 7th and
+ subsequent arguments on the sparc, for example). */
+ if (SYMBOL_CLASS (sym) == LOC_ARG
+ && REG_STRUCT_HAS_ADDR (processing_gcc_compilation,
+ SYMBOL_TYPE (sym))
+ && ((TYPE_CODE (SYMBOL_TYPE (sym)) == TYPE_CODE_STRUCT)
+ || (TYPE_CODE (SYMBOL_TYPE (sym)) == TYPE_CODE_UNION)))
+ SYMBOL_CLASS (sym) = LOC_REF_ARG;
+
+ return sym;
+}
+
+
+/* Skip rest of this symbol and return an error type.
+
+ General notes on error recovery: error_type always skips to the
+ end of the symbol (modulo cretinous dbx symbol name continuation).
+ Thus code like this:
+
+ if (*(*pp)++ != ';')
+ return error_type (pp);
+
+ is wrong because if *pp starts out pointing at '\0' (typically as the
+ result of an earlier error), it will be incremented to point to the
+ start of the next symbol, which might produce strange results, at least
+ if you run off the end of the string table. Instead use
+
+ if (**pp != ';')
+ return error_type (pp);
+ ++*pp;
+
+ or
+
+ if (**pp != ';')
+ foo = error_type (pp);
+ else
+ ++*pp;
+
+ And in case it isn't obvious, the point of all this hair is so the compiler
+ can define new types and new syntaxes, and old versions of the
+ debugger will be able to read the new symbol tables. */
+
+static struct type *
+error_type (pp)
+ char **pp;
+{
+ complain (&error_type_complaint);
+ while (1)
+ {
+ /* Skip to end of symbol. */
+ while (**pp != '\0')
+ {
+ (*pp)++;
+ }
+
+ /* Check for and handle cretinous dbx symbol name continuation! */
+ if ((*pp)[-1] == '\\' || (*pp)[-1] == '?')
+ {
+ *pp = next_symbol_text ();
+ }
+ else
+ {
+ break;
+ }
+ }
+ return (builtin_type_error);
+}
+
+
+/* Read type information or a type definition; return the type. Even
+ though this routine accepts either type information or a type
+ definition, the distinction is relevant--some parts of stabsread.c
+ assume that type information starts with a digit, '-', or '(' in
+ deciding whether to call read_type. */
+
+struct type *
+read_type (pp, objfile)
+ register char **pp;
+ struct objfile *objfile;
+{
+ register struct type *type = 0;
+ struct type *type1;
+ int typenums[2];
+ int xtypenums[2];
+ char type_descriptor;
+
+ /* Size in bits of type if specified by a type attribute, or -1 if
+ there is no size attribute. */
+ int type_size = -1;
+
+ /* Used to distinguish string and bitstring from char-array and set. */
+ int is_string = 0;
+
+ /* Read type number if present. The type number may be omitted.
+ for instance in a two-dimensional array declared with type
+ "ar1;1;10;ar1;1;10;4". */
+ if ((**pp >= '0' && **pp <= '9')
+ || **pp == '('
+ || **pp == '-')
+ {
+ if (read_type_number (pp, typenums) != 0)
+ return error_type (pp);
+
+ /* Type is not being defined here. Either it already exists,
+ or this is a forward reference to it. dbx_alloc_type handles
+ both cases. */
+ if (**pp != '=')
+ return dbx_alloc_type (typenums, objfile);
+
+ /* Type is being defined here. */
+ /* Skip the '='. */
+ ++(*pp);
+
+ while (**pp == '@')
+ {
+ char *p = *pp + 1;
+ /* It might be a type attribute or a member type. */
+ if (isdigit (*p) || *p == '(' || *p == '-')
+ /* Member type. */
+ break;
+ else
+ {
+ /* Type attributes. */
+ char *attr = p;
+
+ /* Skip to the semicolon. */
+ while (*p != ';' && *p != '\0')
+ ++p;
+ *pp = p;
+ if (*p == '\0')
+ return error_type (pp);
+ else
+ /* Skip the semicolon. */
+ ++*pp;
+
+ switch (*attr)
+ {
+ case 's':
+ type_size = atoi (attr + 1);
+ if (type_size <= 0)
+ type_size = -1;
+ break;
+
+ case 'S':
+ is_string = 1;
+ break;
+
+ default:
+ /* Ignore unrecognized type attributes, so future compilers
+ can invent new ones. */
+ break;
+ }
+ }
+ }
+ /* Skip the type descriptor, we get it below with (*pp)[-1]. */
+ ++(*pp);
+ }
+ else
+ {
+ /* 'typenums=' not present, type is anonymous. Read and return
+ the definition, but don't put it in the type vector. */
+ typenums[0] = typenums[1] = -1;
+ (*pp)++;
+ }
+
+ type_descriptor = (*pp)[-1];
+ switch (type_descriptor)
+ {
+ case 'x':
+ {
+ enum type_code code;
+
+ /* Used to index through file_symbols. */
+ struct pending *ppt;
+ int i;
+
+ /* Name including "struct", etc. */
+ char *type_name;
+
+ {
+ char *from, *to, *p, *q1, *q2;
+
+ /* Set the type code according to the following letter. */
+ switch ((*pp)[0])
+ {
+ case 's':
+ code = TYPE_CODE_STRUCT;
+ break;
+ case 'u':
+ code = TYPE_CODE_UNION;
+ break;
+ case 'e':
+ code = TYPE_CODE_ENUM;
+ break;
+ default:
+ {
+ /* Complain and keep going, so compilers can invent new
+ cross-reference types. */
+ static struct complaint msg =
+ {"Unrecognized cross-reference type `%c'", 0, 0};
+ complain (&msg, (*pp)[0]);
+ code = TYPE_CODE_STRUCT;
+ break;
+ }
+ }
+
+ q1 = strchr(*pp, '<');
+ p = strchr(*pp, ':');
+ if (p == NULL)
+ return error_type (pp);
+ while (q1 && p > q1 && p[1] == ':')
+ {
+ q2 = strchr(q1, '>');
+ if (!q2 || q2 < p)
+ break;
+ p += 2;
+ p = strchr(p, ':');
+ if (p == NULL)
+ return error_type (pp);
+ }
+ to = type_name =
+ (char *)obstack_alloc (&objfile->type_obstack, p - *pp + 1);
+
+ /* Copy the name. */
+ from = *pp + 1;
+ while (from < p)
+ *to++ = *from++;
+ *to = '\0';
+
+ /* Set the pointer ahead of the name which we just read, and
+ the colon. */
+ *pp = from + 1;
+ }
+
+ /* Now check to see whether the type has already been
+ declared. This was written for arrays of cross-referenced
+ types before we had TYPE_CODE_TARGET_STUBBED, so I'm pretty
+ sure it is not necessary anymore. But it might be a good
+ idea, to save a little memory. */
+
+ for (ppt = file_symbols; ppt; ppt = ppt->next)
+ for (i = 0; i < ppt->nsyms; i++)
+ {
+ struct symbol *sym = ppt->symbol[i];
+
+ if (SYMBOL_CLASS (sym) == LOC_TYPEDEF
+ && SYMBOL_NAMESPACE (sym) == STRUCT_NAMESPACE
+ && (TYPE_CODE (SYMBOL_TYPE (sym)) == code)
+ && STREQ (SYMBOL_NAME (sym), type_name))
+ {
+ obstack_free (&objfile -> type_obstack, type_name);
+ type = SYMBOL_TYPE (sym);
+ return type;
+ }
+ }
+
+ /* Didn't find the type to which this refers, so we must
+ be dealing with a forward reference. Allocate a type
+ structure for it, and keep track of it so we can
+ fill in the rest of the fields when we get the full
+ type. */
+ type = dbx_alloc_type (typenums, objfile);
+ TYPE_CODE (type) = code;
+ TYPE_TAG_NAME (type) = type_name;
+ INIT_CPLUS_SPECIFIC(type);
+ TYPE_FLAGS (type) |= TYPE_FLAG_STUB;
+
+ add_undefined_type (type);
+ return type;
+ }
+
+ case '-': /* RS/6000 built-in type */
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ case '(':
+
+ {
+ char *pp_saved;
+
+ (*pp)--;
+ pp_saved = *pp;
+
+ /* Peek ahead at the number to detect void. */
+ if (read_type_number (pp, xtypenums) != 0)
+ return error_type (pp);
+
+ if (typenums[0] == xtypenums[0] && typenums[1] == xtypenums[1])
+ /* It's being defined as itself. That means it is "void". */
+ type = init_type (TYPE_CODE_VOID, 1, 0, NULL, objfile);
+ else
+ {
+ struct type *xtype;
+
+ /* Go back to the number and have read_type get it. This means
+ that we can deal with something like t(1,2)=(3,4)=... which
+ the Lucid compiler uses. */
+ *pp = pp_saved;
+ xtype = read_type (pp, objfile);
+
+ /* The type is being defined to another type. So we copy the type.
+ This loses if we copy a C++ class and so we lose track of how
+ the names are mangled (but g++ doesn't output stabs like this
+ now anyway). */
+
+ type = alloc_type (objfile);
+ memcpy (type, xtype, sizeof (struct type));
+
+ /* The idea behind clearing the names is that the only purpose
+ for defining a type to another type is so that the name of
+ one can be different. So we probably don't need to worry much
+ about the case where the compiler doesn't give a name to the
+ new type. */
+ TYPE_NAME (type) = NULL;
+ TYPE_TAG_NAME (type) = NULL;
+ }
+ if (typenums[0] != -1)
+ *dbx_lookup_type (typenums) = type;
+ break;
+ }
+
+ /* In the following types, we must be sure to overwrite any existing
+ type that the typenums refer to, rather than allocating a new one
+ and making the typenums point to the new one. This is because there
+ may already be pointers to the existing type (if it had been
+ forward-referenced), and we must change it to a pointer, function,
+ reference, or whatever, *in-place*. */
+
+ case '*':
+ type1 = read_type (pp, objfile);
+ type = make_pointer_type (type1, dbx_lookup_type (typenums));
+ break;
+
+ case '&': /* Reference to another type */
+ type1 = read_type (pp, objfile);
+ type = make_reference_type (type1, dbx_lookup_type (typenums));
+ break;
+
+ case 'f': /* Function returning another type */
+ if (os9k_stabs && **pp == '(')
+ {
+ /* Function prototype; parse it.
+ We must conditionalize this on os9k_stabs because otherwise
+ it could be confused with a Sun-style (1,3) typenumber
+ (I think). */
+ struct type *t;
+ ++*pp;
+ while (**pp != ')')
+ {
+ t = read_type(pp, objfile);
+ if (**pp == ',') ++*pp;
+ }
+ }
+ type1 = read_type (pp, objfile);
+ type = make_function_type (type1, dbx_lookup_type (typenums));
+ break;
+
+ case 'k': /* Const qualifier on some type (Sun) */
+ case 'c': /* Const qualifier on some type (OS9000) */
+ /* Because 'c' means other things to AIX and 'k' is perfectly good,
+ only accept 'c' in the os9k_stabs case. */
+ if (type_descriptor == 'c' && !os9k_stabs)
+ return error_type (pp);
+ type = read_type (pp, objfile);
+ /* FIXME! For now, we ignore const and volatile qualifiers. */
+ break;
+
+ case 'B': /* Volatile qual on some type (Sun) */
+ case 'i': /* Volatile qual on some type (OS9000) */
+ /* Because 'i' means other things to AIX and 'B' is perfectly good,
+ only accept 'i' in the os9k_stabs case. */
+ if (type_descriptor == 'i' && !os9k_stabs)
+ return error_type (pp);
+ type = read_type (pp, objfile);
+ /* FIXME! For now, we ignore const and volatile qualifiers. */
+ break;
+
+/* FIXME -- we should be doing smash_to_XXX types here. */
+ case '@': /* Member (class & variable) type */
+ {
+ struct type *domain = read_type (pp, objfile);
+ struct type *memtype;
+
+ if (**pp != ',')
+ /* Invalid member type data format. */
+ return error_type (pp);
+ ++*pp;
+
+ memtype = read_type (pp, objfile);
+ type = dbx_alloc_type (typenums, objfile);
+ smash_to_member_type (type, domain, memtype);
+ }
+ break;
+
+ case '#': /* Method (class & fn) type */
+ if ((*pp)[0] == '#')
+ {
+ /* We'll get the parameter types from the name. */
+ struct type *return_type;
+
+ (*pp)++;
+ return_type = read_type (pp, objfile);
+ if (*(*pp)++ != ';')
+ complain (&invalid_member_complaint, symnum);
+ type = allocate_stub_method (return_type);
+ if (typenums[0] != -1)
+ *dbx_lookup_type (typenums) = type;
+ }
+ else
+ {
+ struct type *domain = read_type (pp, objfile);
+ struct type *return_type;
+ struct type **args;
+
+ if (**pp != ',')
+ /* Invalid member type data format. */
+ return error_type (pp);
+ else
+ ++(*pp);
+
+ return_type = read_type (pp, objfile);
+ args = read_args (pp, ';', objfile);
+ type = dbx_alloc_type (typenums, objfile);
+ smash_to_method_type (type, domain, return_type, args);
+ }
+ break;
+
+ case 'r': /* Range type */
+ type = read_range_type (pp, typenums, objfile);
+ if (typenums[0] != -1)
+ *dbx_lookup_type (typenums) = type;
+ break;
+
+ case 'b':
+ if (os9k_stabs)
+ /* Const and volatile qualified type. */
+ type = read_type (pp, objfile);
+ else
+ {
+ /* Sun ACC builtin int type */
+ type = read_sun_builtin_type (pp, typenums, objfile);
+ if (typenums[0] != -1)
+ *dbx_lookup_type (typenums) = type;
+ }
+ break;
+
+ case 'R': /* Sun ACC builtin float type */
+ type = read_sun_floating_type (pp, typenums, objfile);
+ if (typenums[0] != -1)
+ *dbx_lookup_type (typenums) = type;
+ break;
+
+ case 'e': /* Enumeration type */
+ type = dbx_alloc_type (typenums, objfile);
+ type = read_enum_type (pp, type, objfile);
+ if (typenums[0] != -1)
+ *dbx_lookup_type (typenums) = type;
+ break;
+
+ case 's': /* Struct type */
+ case 'u': /* Union type */
+ type = dbx_alloc_type (typenums, objfile);
+ if (!TYPE_NAME (type))
+ {
+ TYPE_NAME (type) = type_synonym_name;
+ }
+ type_synonym_name = NULL;
+ switch (type_descriptor)
+ {
+ case 's':
+ TYPE_CODE (type) = TYPE_CODE_STRUCT;
+ break;
+ case 'u':
+ TYPE_CODE (type) = TYPE_CODE_UNION;
+ break;
+ }
+ type = read_struct_type (pp, type, objfile);
+ break;
+
+ case 'a': /* Array type */
+ if (**pp != 'r')
+ return error_type (pp);
+ ++*pp;
+
+ type = dbx_alloc_type (typenums, objfile);
+ type = read_array_type (pp, type, objfile);
+ if (is_string)
+ TYPE_CODE (type) = TYPE_CODE_STRING;
+ break;
+
+ case 'S':
+ type1 = read_type (pp, objfile);
+ type = create_set_type ((struct type*) NULL, type1);
+ if (is_string)
+ TYPE_CODE (type) = TYPE_CODE_BITSTRING;
+ if (typenums[0] != -1)
+ *dbx_lookup_type (typenums) = type;
+ break;
+
+ default:
+ --*pp; /* Go back to the symbol in error */
+ /* Particularly important if it was \0! */
+ return error_type (pp);
+ }
+
+ if (type == 0)
+ {
+ warning ("GDB internal error, type is NULL in stabsread.c\n");
+ return error_type (pp);
+ }
+
+ /* Size specified in a type attribute overrides any other size. */
+ if (type_size != -1)
+ TYPE_LENGTH (type) = type_size / TARGET_CHAR_BIT;
+
+ return type;
+}
+
+/* RS/6000 xlc/dbx combination uses a set of builtin types, starting from -1.
+ Return the proper type node for a given builtin type number. */
+
+static struct type *
+rs6000_builtin_type (typenum)
+ int typenum;
+{
+ /* We recognize types numbered from -NUMBER_RECOGNIZED to -1. */
+#define NUMBER_RECOGNIZED 30
+ /* This includes an empty slot for type number -0. */
+ static struct type *negative_types[NUMBER_RECOGNIZED + 1];
+ struct type *rettype = NULL;
+
+ if (typenum >= 0 || typenum < -NUMBER_RECOGNIZED)
+ {
+ complain (&rs6000_builtin_complaint, typenum);
+ return builtin_type_error;
+ }
+ if (negative_types[-typenum] != NULL)
+ return negative_types[-typenum];
+
+#if TARGET_CHAR_BIT != 8
+ #error This code wrong for TARGET_CHAR_BIT not 8
+ /* These definitions all assume that TARGET_CHAR_BIT is 8. I think
+ that if that ever becomes not true, the correct fix will be to
+ make the size in the struct type to be in bits, not in units of
+ TARGET_CHAR_BIT. */
+#endif
+
+ switch (-typenum)
+ {
+ case 1:
+ /* The size of this and all the other types are fixed, defined
+ by the debugging format. If there is a type called "int" which
+ is other than 32 bits, then it should use a new negative type
+ number (or avoid negative type numbers for that case).
+ See stabs.texinfo. */
+ rettype = init_type (TYPE_CODE_INT, 4, 0, "int", NULL);
+ break;
+ case 2:
+ rettype = init_type (TYPE_CODE_INT, 1, 0, "char", NULL);
+ break;
+ case 3:
+ rettype = init_type (TYPE_CODE_INT, 2, 0, "short", NULL);
+ break;
+ case 4:
+ rettype = init_type (TYPE_CODE_INT, 4, 0, "long", NULL);
+ break;
+ case 5:
+ rettype = init_type (TYPE_CODE_INT, 1, TYPE_FLAG_UNSIGNED,
+ "unsigned char", NULL);
+ break;
+ case 6:
+ rettype = init_type (TYPE_CODE_INT, 1, 0, "signed char", NULL);
+ break;
+ case 7:
+ rettype = init_type (TYPE_CODE_INT, 2, TYPE_FLAG_UNSIGNED,
+ "unsigned short", NULL);
+ break;
+ case 8:
+ rettype = init_type (TYPE_CODE_INT, 4, TYPE_FLAG_UNSIGNED,
+ "unsigned int", NULL);
+ break;
+ case 9:
+ rettype = init_type (TYPE_CODE_INT, 4, TYPE_FLAG_UNSIGNED,
+ "unsigned", NULL);
+ case 10:
+ rettype = init_type (TYPE_CODE_INT, 4, TYPE_FLAG_UNSIGNED,
+ "unsigned long", NULL);
+ break;
+ case 11:
+ rettype = init_type (TYPE_CODE_VOID, 1, 0, "void", NULL);
+ break;
+ case 12:
+ /* IEEE single precision (32 bit). */
+ rettype = init_type (TYPE_CODE_FLT, 4, 0, "float", NULL);
+ break;
+ case 13:
+ /* IEEE double precision (64 bit). */
+ rettype = init_type (TYPE_CODE_FLT, 8, 0, "double", NULL);
+ break;
+ case 14:
+ /* This is an IEEE double on the RS/6000, and different machines with
+ different sizes for "long double" should use different negative
+ type numbers. See stabs.texinfo. */
+ rettype = init_type (TYPE_CODE_FLT, 8, 0, "long double", NULL);
+ break;
+ case 15:
+ rettype = init_type (TYPE_CODE_INT, 4, 0, "integer", NULL);
+ break;
+ case 16:
+ rettype = init_type (TYPE_CODE_BOOL, 4, 0, "boolean", NULL);
+ break;
+ case 17:
+ rettype = init_type (TYPE_CODE_FLT, 4, 0, "short real", NULL);
+ break;
+ case 18:
+ rettype = init_type (TYPE_CODE_FLT, 8, 0, "real", NULL);
+ break;
+ case 19:
+ rettype = init_type (TYPE_CODE_ERROR, 0, 0, "stringptr", NULL);
+ break;
+ case 20:
+ rettype = init_type (TYPE_CODE_CHAR, 1, TYPE_FLAG_UNSIGNED,
+ "character", NULL);
+ break;
+ case 21:
+ rettype = init_type (TYPE_CODE_BOOL, 1, TYPE_FLAG_UNSIGNED,
+ "logical*1", NULL);
+ break;
+ case 22:
+ rettype = init_type (TYPE_CODE_BOOL, 2, TYPE_FLAG_UNSIGNED,
+ "logical*2", NULL);
+ break;
+ case 23:
+ rettype = init_type (TYPE_CODE_BOOL, 4, TYPE_FLAG_UNSIGNED,
+ "logical*4", NULL);
+ break;
+ case 24:
+ rettype = init_type (TYPE_CODE_BOOL, 4, TYPE_FLAG_UNSIGNED,
+ "logical", NULL);
+ break;
+ case 25:
+ /* Complex type consisting of two IEEE single precision values. */
+ rettype = init_type (TYPE_CODE_ERROR, 8, 0, "complex", NULL);
+ break;
+ case 26:
+ /* Complex type consisting of two IEEE double precision values. */
+ rettype = init_type (TYPE_CODE_ERROR, 16, 0, "double complex", NULL);
+ break;
+ case 27:
+ rettype = init_type (TYPE_CODE_INT, 1, 0, "integer*1", NULL);
+ break;
+ case 28:
+ rettype = init_type (TYPE_CODE_INT, 2, 0, "integer*2", NULL);
+ break;
+ case 29:
+ rettype = init_type (TYPE_CODE_INT, 4, 0, "integer*4", NULL);
+ break;
+ case 30:
+ rettype = init_type (TYPE_CODE_CHAR, 2, 0, "wchar", NULL);
+ break;
+ }
+ negative_types[-typenum] = rettype;
+ return rettype;
+}
+
+/* This page contains subroutines of read_type. */
+
+#define VISIBILITY_PRIVATE '0' /* Stabs character for private field */
+#define VISIBILITY_PROTECTED '1' /* Stabs character for protected fld */
+#define VISIBILITY_PUBLIC '2' /* Stabs character for public field */
+#define VISIBILITY_IGNORE '9' /* Optimized out or zero length */
+
+/* Read member function stabs info for C++ classes. The form of each member
+ function data is:
+
+ NAME :: TYPENUM[=type definition] ARGS : PHYSNAME ;
+
+ An example with two member functions is:
+
+ afunc1::20=##15;:i;2A.;afunc2::20:i;2A.;
+
+ For the case of overloaded operators, the format is op$::*.funcs, where
+ $ is the CPLUS_MARKER (usually '$'), `*' holds the place for an operator
+ name (such as `+=') and `.' marks the end of the operator name.
+
+ Returns 1 for success, 0 for failure. */
+
+static int
+read_member_functions (fip, pp, type, objfile)
+ struct field_info *fip;
+ char **pp;
+ struct type *type;
+ struct objfile *objfile;
+{
+ int nfn_fields = 0;
+ int length = 0;
+ /* Total number of member functions defined in this class. If the class
+ defines two `f' functions, and one `g' function, then this will have
+ the value 3. */
+ int total_length = 0;
+ int i;
+ struct next_fnfield
+ {
+ struct next_fnfield *next;
+ struct fn_field fn_field;
+ } *sublist;
+ struct type *look_ahead_type;
+ struct next_fnfieldlist *new_fnlist;
+ struct next_fnfield *new_sublist;
+ char *main_fn_name;
+ register char *p;
+
+ /* Process each list until we find something that is not a member function
+ or find the end of the functions. */
+
+ while (**pp != ';')
+ {
+ /* We should be positioned at the start of the function name.
+ Scan forward to find the first ':' and if it is not the
+ first of a "::" delimiter, then this is not a member function. */
+ p = *pp;
+ while (*p != ':')
+ {
+ p++;
+ }
+ if (p[1] != ':')
+ {
+ break;
+ }
+
+ sublist = NULL;
+ look_ahead_type = NULL;
+ length = 0;
+
+ new_fnlist = (struct next_fnfieldlist *)
+ xmalloc (sizeof (struct next_fnfieldlist));
+ make_cleanup (free, new_fnlist);
+ memset (new_fnlist, 0, sizeof (struct next_fnfieldlist));
+
+ if ((*pp)[0] == 'o' && (*pp)[1] == 'p' && (*pp)[2] == CPLUS_MARKER)
+ {
+ /* This is a completely wierd case. In order to stuff in the
+ names that might contain colons (the usual name delimiter),
+ Mike Tiemann defined a different name format which is
+ signalled if the identifier is "op$". In that case, the
+ format is "op$::XXXX." where XXXX is the name. This is
+ used for names like "+" or "=". YUUUUUUUK! FIXME! */
+ /* This lets the user type "break operator+".
+ We could just put in "+" as the name, but that wouldn't
+ work for "*". */
+ static char opname[32] = {'o', 'p', CPLUS_MARKER};
+ char *o = opname + 3;
+
+ /* Skip past '::'. */
+ *pp = p + 2;
+
+ STABS_CONTINUE (pp);
+ p = *pp;
+ while (*p != '.')
+ {
+ *o++ = *p++;
+ }
+ main_fn_name = savestring (opname, o - opname);
+ /* Skip past '.' */
+ *pp = p + 1;
+ }
+ else
+ {
+ main_fn_name = savestring (*pp, p - *pp);
+ /* Skip past '::'. */
+ *pp = p + 2;
+ }
+ new_fnlist -> fn_fieldlist.name = main_fn_name;
+
+ do
+ {
+ new_sublist =
+ (struct next_fnfield *) xmalloc (sizeof (struct next_fnfield));
+ make_cleanup (free, new_sublist);
+ memset (new_sublist, 0, sizeof (struct next_fnfield));
+
+ /* Check for and handle cretinous dbx symbol name continuation! */
+ if (look_ahead_type == NULL)
+ {
+ /* Normal case. */
+ STABS_CONTINUE (pp);
+
+ new_sublist -> fn_field.type = read_type (pp, objfile);
+ if (**pp != ':')
+ {
+ /* Invalid symtab info for member function. */
+ return 0;
+ }
+ }
+ else
+ {
+ /* g++ version 1 kludge */
+ new_sublist -> fn_field.type = look_ahead_type;
+ look_ahead_type = NULL;
+ }
+
+ (*pp)++;
+ p = *pp;
+ while (*p != ';')
+ {
+ p++;
+ }
+
+ /* If this is just a stub, then we don't have the real name here. */
+
+ if (TYPE_FLAGS (new_sublist -> fn_field.type) & TYPE_FLAG_STUB)
+ {
+ if (!TYPE_DOMAIN_TYPE (new_sublist -> fn_field.type))
+ TYPE_DOMAIN_TYPE (new_sublist -> fn_field.type) = type;
+ new_sublist -> fn_field.is_stub = 1;
+ }
+ new_sublist -> fn_field.physname = savestring (*pp, p - *pp);
+ *pp = p + 1;
+
+ /* Set this member function's visibility fields. */
+ switch (*(*pp)++)
+ {
+ case VISIBILITY_PRIVATE:
+ new_sublist -> fn_field.is_private = 1;
+ break;
+ case VISIBILITY_PROTECTED:
+ new_sublist -> fn_field.is_protected = 1;
+ break;
+ }
+
+ STABS_CONTINUE (pp);
+ switch (**pp)
+ {
+ case 'A': /* Normal functions. */
+ new_sublist -> fn_field.is_const = 0;
+ new_sublist -> fn_field.is_volatile = 0;
+ (*pp)++;
+ break;
+ case 'B': /* `const' member functions. */
+ new_sublist -> fn_field.is_const = 1;
+ new_sublist -> fn_field.is_volatile = 0;
+ (*pp)++;
+ break;
+ case 'C': /* `volatile' member function. */
+ new_sublist -> fn_field.is_const = 0;
+ new_sublist -> fn_field.is_volatile = 1;
+ (*pp)++;
+ break;
+ case 'D': /* `const volatile' member function. */
+ new_sublist -> fn_field.is_const = 1;
+ new_sublist -> fn_field.is_volatile = 1;
+ (*pp)++;
+ break;
+ case '*': /* File compiled with g++ version 1 -- no info */
+ case '?':
+ case '.':
+ break;
+ default:
+ complain (&const_vol_complaint, **pp);
+ break;
+ }
+
+ switch (*(*pp)++)
+ {
+ case '*':
+ {
+ int nbits;
+ /* virtual member function, followed by index.
+ The sign bit is set to distinguish pointers-to-methods
+ from virtual function indicies. Since the array is
+ in words, the quantity must be shifted left by 1
+ on 16 bit machine, and by 2 on 32 bit machine, forcing
+ the sign bit out, and usable as a valid index into
+ the array. Remove the sign bit here. */
+ new_sublist -> fn_field.voffset =
+ (0x7fffffff & read_huge_number (pp, ';', &nbits)) + 2;
+ if (nbits != 0)
+ return 0;
+
+ STABS_CONTINUE (pp);
+ if (**pp == ';' || **pp == '\0')
+ {
+ /* Must be g++ version 1. */
+ new_sublist -> fn_field.fcontext = 0;
+ }
+ else
+ {
+ /* Figure out from whence this virtual function came.
+ It may belong to virtual function table of
+ one of its baseclasses. */
+ look_ahead_type = read_type (pp, objfile);
+ if (**pp == ':')
+ {
+ /* g++ version 1 overloaded methods. */
+ }
+ else
+ {
+ new_sublist -> fn_field.fcontext = look_ahead_type;
+ if (**pp != ';')
+ {
+ return 0;
+ }
+ else
+ {
+ ++*pp;
+ }
+ look_ahead_type = NULL;
+ }
+ }
+ break;
+ }
+ case '?':
+ /* static member function. */
+ new_sublist -> fn_field.voffset = VOFFSET_STATIC;
+ if (strncmp (new_sublist -> fn_field.physname,
+ main_fn_name, strlen (main_fn_name)))
+ {
+ new_sublist -> fn_field.is_stub = 1;
+ }
+ break;
+
+ default:
+ /* error */
+ complain (&member_fn_complaint, (*pp)[-1]);
+ /* Fall through into normal member function. */
+
+ case '.':
+ /* normal member function. */
+ new_sublist -> fn_field.voffset = 0;
+ new_sublist -> fn_field.fcontext = 0;
+ break;
+ }
+
+ new_sublist -> next = sublist;
+ sublist = new_sublist;
+ length++;
+ STABS_CONTINUE (pp);
+ }
+ while (**pp != ';' && **pp != '\0');
+
+ (*pp)++;
+
+ new_fnlist -> fn_fieldlist.fn_fields = (struct fn_field *)
+ obstack_alloc (&objfile -> type_obstack,
+ sizeof (struct fn_field) * length);
+ memset (new_fnlist -> fn_fieldlist.fn_fields, 0,
+ sizeof (struct fn_field) * length);
+ for (i = length; (i--, sublist); sublist = sublist -> next)
+ {
+ new_fnlist -> fn_fieldlist.fn_fields[i] = sublist -> fn_field;
+ }
+
+ new_fnlist -> fn_fieldlist.length = length;
+ new_fnlist -> next = fip -> fnlist;
+ fip -> fnlist = new_fnlist;
+ nfn_fields++;
+ total_length += length;
+ STABS_CONTINUE (pp);
+ }
+
+ if (nfn_fields)
+ {
+ ALLOCATE_CPLUS_STRUCT_TYPE (type);
+ TYPE_FN_FIELDLISTS (type) = (struct fn_fieldlist *)
+ TYPE_ALLOC (type, sizeof (struct fn_fieldlist) * nfn_fields);
+ memset (TYPE_FN_FIELDLISTS (type), 0,
+ sizeof (struct fn_fieldlist) * nfn_fields);
+ TYPE_NFN_FIELDS (type) = nfn_fields;
+ TYPE_NFN_FIELDS_TOTAL (type) = total_length;
+ }
+
+ return 1;
+}
+
+/* Special GNU C++ name.
+
+ Returns 1 for success, 0 for failure. "failure" means that we can't
+ keep parsing and it's time for error_type(). */
+
+static int
+read_cpp_abbrev (fip, pp, type, objfile)
+ struct field_info *fip;
+ char **pp;
+ struct type *type;
+ struct objfile *objfile;
+{
+ register char *p;
+ char *name;
+ char cpp_abbrev;
+ struct type *context;
+
+ p = *pp;
+ if (*++p == 'v')
+ {
+ name = NULL;
+ cpp_abbrev = *++p;
+
+ *pp = p + 1;
+
+ /* At this point, *pp points to something like "22:23=*22...",
+ where the type number before the ':' is the "context" and
+ everything after is a regular type definition. Lookup the
+ type, find it's name, and construct the field name. */
+
+ context = read_type (pp, objfile);
+
+ switch (cpp_abbrev)
+ {
+ case 'f': /* $vf -- a virtual function table pointer */
+ fip->list->field.name =
+ obconcat (&objfile->type_obstack, vptr_name, "", "");
+ break;
+
+ case 'b': /* $vb -- a virtual bsomethingorother */
+ name = type_name_no_tag (context);
+ if (name == NULL)
+ {
+ complain (&invalid_cpp_type_complaint, symnum);
+ name = "FOO";
+ }
+ fip->list->field.name =
+ obconcat (&objfile->type_obstack, vb_name, name, "");
+ break;
+
+ default:
+ complain (&invalid_cpp_abbrev_complaint, *pp);
+ fip->list->field.name =
+ obconcat (&objfile->type_obstack,
+ "INVALID_CPLUSPLUS_ABBREV", "", "");
+ break;
+ }
+
+ /* At this point, *pp points to the ':'. Skip it and read the
+ field type. */
+
+ p = ++(*pp);
+ if (p[-1] != ':')
+ {
+ complain (&invalid_cpp_abbrev_complaint, *pp);
+ return 0;
+ }
+ fip->list->field.type = read_type (pp, objfile);
+ if (**pp == ',')
+ (*pp)++; /* Skip the comma. */
+ else
+ return 0;
+
+ {
+ int nbits;
+ fip->list->field.bitpos = read_huge_number (pp, ';', &nbits);
+ if (nbits != 0)
+ return 0;
+ }
+ /* This field is unpacked. */
+ fip->list->field.bitsize = 0;
+ fip->list->visibility = VISIBILITY_PRIVATE;
+ }
+ else
+ {
+ complain (&invalid_cpp_abbrev_complaint, *pp);
+ /* We have no idea what syntax an unrecognized abbrev would have, so
+ better return 0. If we returned 1, we would need to at least advance
+ *pp to avoid an infinite loop. */
+ return 0;
+ }
+ return 1;
+}
+
+static void
+read_one_struct_field (fip, pp, p, type, objfile)
+ struct field_info *fip;
+ char **pp;
+ char *p;
+ struct type *type;
+ struct objfile *objfile;
+{
+ fip -> list -> field.name =
+ obsavestring (*pp, p - *pp, &objfile -> type_obstack);
+ *pp = p + 1;
+
+ /* This means we have a visibility for a field coming. */
+ if (**pp == '/')
+ {
+ (*pp)++;
+ fip -> list -> visibility = *(*pp)++;
+ }
+ else
+ {
+ /* normal dbx-style format, no explicit visibility */
+ fip -> list -> visibility = VISIBILITY_PUBLIC;
+ }
+
+ fip -> list -> field.type = read_type (pp, objfile);
+ if (**pp == ':')
+ {
+ p = ++(*pp);
+#if 0
+ /* Possible future hook for nested types. */
+ if (**pp == '!')
+ {
+ fip -> list -> field.bitpos = (long)-2; /* nested type */
+ p = ++(*pp);
+ }
+ else
+#endif
+ {
+ /* Static class member. */
+ fip -> list -> field.bitpos = (long) -1;
+ }
+ while (*p != ';')
+ {
+ p++;
+ }
+ fip -> list -> field.bitsize = (long) savestring (*pp, p - *pp);
+ *pp = p + 1;
+ return;
+ }
+ else if (**pp != ',')
+ {
+ /* Bad structure-type format. */
+ complain (&stabs_general_complaint, "bad structure-type format");
+ return;
+ }
+
+ (*pp)++; /* Skip the comma. */
+
+ {
+ int nbits;
+ fip -> list -> field.bitpos = read_huge_number (pp, ',', &nbits);
+ if (nbits != 0)
+ {
+ complain (&stabs_general_complaint, "bad structure-type format");
+ return;
+ }
+ fip -> list -> field.bitsize = read_huge_number (pp, ';', &nbits);
+ if (nbits != 0)
+ {
+ complain (&stabs_general_complaint, "bad structure-type format");
+ return;
+ }
+ }
+
+ if (fip -> list -> field.bitpos == 0 && fip -> list -> field.bitsize == 0)
+ {
+ /* This can happen in two cases: (1) at least for gcc 2.4.5 or so,
+ it is a field which has been optimized out. The correct stab for
+ this case is to use VISIBILITY_IGNORE, but that is a recent
+ invention. (2) It is a 0-size array. For example
+ union { int num; char str[0]; } foo. Printing "<no value>" for
+ str in "p foo" is OK, since foo.str (and thus foo.str[3])
+ will continue to work, and a 0-size array as a whole doesn't
+ have any contents to print.
+
+ I suspect this probably could also happen with gcc -gstabs (not
+ -gstabs+) for static fields, and perhaps other C++ extensions.
+ Hopefully few people use -gstabs with gdb, since it is intended
+ for dbx compatibility. */
+
+ /* Ignore this field. */
+ fip -> list-> visibility = VISIBILITY_IGNORE;
+ }
+ else
+ {
+ /* Detect an unpacked field and mark it as such.
+ dbx gives a bit size for all fields.
+ Note that forward refs cannot be packed,
+ and treat enums as if they had the width of ints. */
+
+ if (TYPE_CODE (fip -> list -> field.type) != TYPE_CODE_INT
+ && TYPE_CODE (fip -> list -> field.type) != TYPE_CODE_ENUM)
+ {
+ fip -> list -> field.bitsize = 0;
+ }
+ if ((fip -> list -> field.bitsize
+ == TARGET_CHAR_BIT * TYPE_LENGTH (fip -> list -> field.type)
+ || (TYPE_CODE (fip -> list -> field.type) == TYPE_CODE_ENUM
+ && (fip -> list -> field.bitsize
+ == TARGET_INT_BIT)
+ )
+ )
+ &&
+ fip -> list -> field.bitpos % 8 == 0)
+ {
+ fip -> list -> field.bitsize = 0;
+ }
+ }
+}
+
+
+/* Read struct or class data fields. They have the form:
+
+ NAME : [VISIBILITY] TYPENUM , BITPOS , BITSIZE ;
+
+ At the end, we see a semicolon instead of a field.
+
+ In C++, this may wind up being NAME:?TYPENUM:PHYSNAME; for
+ a static field.
+
+ The optional VISIBILITY is one of:
+
+ '/0' (VISIBILITY_PRIVATE)
+ '/1' (VISIBILITY_PROTECTED)
+ '/2' (VISIBILITY_PUBLIC)
+ '/9' (VISIBILITY_IGNORE)
+
+ or nothing, for C style fields with public visibility.
+
+ Returns 1 for success, 0 for failure. */
+
+static int
+read_struct_fields (fip, pp, type, objfile)
+ struct field_info *fip;
+ char **pp;
+ struct type *type;
+ struct objfile *objfile;
+{
+ register char *p;
+ struct nextfield *new;
+
+ /* We better set p right now, in case there are no fields at all... */
+
+ p = *pp;
+
+ /* Read each data member type until we find the terminating ';' at the end of
+ the data member list, or break for some other reason such as finding the
+ start of the member function list. */
+
+ while (**pp != ';')
+ {
+ if (os9k_stabs && **pp == ',') break;
+ STABS_CONTINUE (pp);
+ /* Get space to record the next field's data. */
+ new = (struct nextfield *) xmalloc (sizeof (struct nextfield));
+ make_cleanup (free, new);
+ memset (new, 0, sizeof (struct nextfield));
+ new -> next = fip -> list;
+ fip -> list = new;
+
+ /* Get the field name. */
+ p = *pp;
+
+ /* If is starts with CPLUS_MARKER it is a special abbreviation,
+ unless the CPLUS_MARKER is followed by an underscore, in
+ which case it is just the name of an anonymous type, which we
+ should handle like any other type name. We accept either '$'
+ or '.', because a field name can never contain one of these
+ characters except as a CPLUS_MARKER (we probably should be
+ doing that in most parts of GDB). */
+
+ if ((*p == '$' || *p == '.') && p[1] != '_')
+ {
+ if (!read_cpp_abbrev (fip, pp, type, objfile))
+ return 0;
+ continue;
+ }
+
+ /* Look for the ':' that separates the field name from the field
+ values. Data members are delimited by a single ':', while member
+ functions are delimited by a pair of ':'s. When we hit the member
+ functions (if any), terminate scan loop and return. */
+
+ while (*p != ':' && *p != '\0')
+ {
+ p++;
+ }
+ if (*p == '\0')
+ return 0;
+
+ /* Check to see if we have hit the member functions yet. */
+ if (p[1] == ':')
+ {
+ break;
+ }
+ read_one_struct_field (fip, pp, p, type, objfile);
+ }
+ if (p[0] == ':' && p[1] == ':')
+ {
+ /* chill the list of fields: the last entry (at the head) is a
+ partially constructed entry which we now scrub. */
+ fip -> list = fip -> list -> next;
+ }
+ return 1;
+}
+
+/* The stabs for C++ derived classes contain baseclass information which
+ is marked by a '!' character after the total size. This function is
+ called when we encounter the baseclass marker, and slurps up all the
+ baseclass information.
+
+ Immediately following the '!' marker is the number of base classes that
+ the class is derived from, followed by information for each base class.
+ For each base class, there are two visibility specifiers, a bit offset
+ to the base class information within the derived class, a reference to
+ the type for the base class, and a terminating semicolon.
+
+ A typical example, with two base classes, would be "!2,020,19;0264,21;".
+ ^^ ^ ^ ^ ^ ^ ^
+ Baseclass information marker __________________|| | | | | | |
+ Number of baseclasses __________________________| | | | | | |
+ Visibility specifiers (2) ________________________| | | | | |
+ Offset in bits from start of class _________________| | | | |
+ Type number for base class ___________________________| | | |
+ Visibility specifiers (2) _______________________________| | |
+ Offset in bits from start of class ________________________| |
+ Type number of base class ____________________________________|
+
+ Return 1 for success, 0 for (error-type-inducing) failure. */
+
+static int
+read_baseclasses (fip, pp, type, objfile)
+ struct field_info *fip;
+ char **pp;
+ struct type *type;
+ struct objfile *objfile;
+{
+ int i;
+ struct nextfield *new;
+
+ if (**pp != '!')
+ {
+ return 1;
+ }
+ else
+ {
+ /* Skip the '!' baseclass information marker. */
+ (*pp)++;
+ }
+
+ ALLOCATE_CPLUS_STRUCT_TYPE (type);
+ {
+ int nbits;
+ TYPE_N_BASECLASSES (type) = read_huge_number (pp, ',', &nbits);
+ if (nbits != 0)
+ return 0;
+ }
+
+#if 0
+ /* Some stupid compilers have trouble with the following, so break
+ it up into simpler expressions. */
+ TYPE_FIELD_VIRTUAL_BITS (type) = (B_TYPE *)
+ TYPE_ALLOC (type, B_BYTES (TYPE_N_BASECLASSES (type)));
+#else
+ {
+ int num_bytes = B_BYTES (TYPE_N_BASECLASSES (type));
+ char *pointer;
+
+ pointer = (char *) TYPE_ALLOC (type, num_bytes);
+ TYPE_FIELD_VIRTUAL_BITS (type) = (B_TYPE *) pointer;
+ }
+#endif /* 0 */
+
+ B_CLRALL (TYPE_FIELD_VIRTUAL_BITS (type), TYPE_N_BASECLASSES (type));
+
+ for (i = 0; i < TYPE_N_BASECLASSES (type); i++)
+ {
+ new = (struct nextfield *) xmalloc (sizeof (struct nextfield));
+ make_cleanup (free, new);
+ memset (new, 0, sizeof (struct nextfield));
+ new -> next = fip -> list;
+ fip -> list = new;
+ new -> field.bitsize = 0; /* this should be an unpacked field! */
+
+ STABS_CONTINUE (pp);
+ switch (**pp)
+ {
+ case '0':
+ /* Nothing to do. */
+ break;
+ case '1':
+ SET_TYPE_FIELD_VIRTUAL (type, i);
+ break;
+ default:
+ /* Unknown character. Complain and treat it as non-virtual. */
+ {
+ static struct complaint msg = {
+ "Unknown virtual character `%c' for baseclass", 0, 0};
+ complain (&msg, **pp);
+ }
+ }
+ ++(*pp);
+
+ new -> visibility = *(*pp)++;
+ switch (new -> visibility)
+ {
+ case VISIBILITY_PRIVATE:
+ case VISIBILITY_PROTECTED:
+ case VISIBILITY_PUBLIC:
+ break;
+ default:
+ /* Bad visibility format. Complain and treat it as
+ public. */
+ {
+ static struct complaint msg = {
+ "Unknown visibility `%c' for baseclass", 0, 0};
+ complain (&msg, new -> visibility);
+ new -> visibility = VISIBILITY_PUBLIC;
+ }
+ }
+
+ {
+ int nbits;
+
+ /* The remaining value is the bit offset of the portion of the object
+ corresponding to this baseclass. Always zero in the absence of
+ multiple inheritance. */
+
+ new -> field.bitpos = read_huge_number (pp, ',', &nbits);
+ if (nbits != 0)
+ return 0;
+ }
+
+ /* The last piece of baseclass information is the type of the
+ base class. Read it, and remember it's type name as this
+ field's name. */
+
+ new -> field.type = read_type (pp, objfile);
+ new -> field.name = type_name_no_tag (new -> field.type);
+
+ /* skip trailing ';' and bump count of number of fields seen */
+ if (**pp == ';')
+ (*pp)++;
+ else
+ return 0;
+ }
+ return 1;
+}
+
+/* The tail end of stabs for C++ classes that contain a virtual function
+ pointer contains a tilde, a %, and a type number.
+ The type number refers to the base class (possibly this class itself) which
+ contains the vtable pointer for the current class.
+
+ This function is called when we have parsed all the method declarations,
+ so we can look for the vptr base class info. */
+
+static int
+read_tilde_fields (fip, pp, type, objfile)
+ struct field_info *fip;
+ char **pp;
+ struct type *type;
+ struct objfile *objfile;
+{
+ register char *p;
+
+ STABS_CONTINUE (pp);
+
+ /* If we are positioned at a ';', then skip it. */
+ if (**pp == ';')
+ {
+ (*pp)++;
+ }
+
+ if (**pp == '~')
+ {
+ (*pp)++;
+
+ if (**pp == '=' || **pp == '+' || **pp == '-')
+ {
+ /* Obsolete flags that used to indicate the presence
+ of constructors and/or destructors. */
+ (*pp)++;
+ }
+
+ /* Read either a '%' or the final ';'. */
+ if (*(*pp)++ == '%')
+ {
+ /* The next number is the type number of the base class
+ (possibly our own class) which supplies the vtable for
+ this class. Parse it out, and search that class to find
+ its vtable pointer, and install those into TYPE_VPTR_BASETYPE
+ and TYPE_VPTR_FIELDNO. */
+
+ struct type *t;
+ int i;
+
+ t = read_type (pp, objfile);
+ p = (*pp)++;
+ while (*p != '\0' && *p != ';')
+ {
+ p++;
+ }
+ if (*p == '\0')
+ {
+ /* Premature end of symbol. */
+ return 0;
+ }
+
+ TYPE_VPTR_BASETYPE (type) = t;
+ if (type == t) /* Our own class provides vtbl ptr */
+ {
+ for (i = TYPE_NFIELDS (t) - 1;
+ i >= TYPE_N_BASECLASSES (t);
+ --i)
+ {
+ if (! strncmp (TYPE_FIELD_NAME (t, i), vptr_name,
+ sizeof (vptr_name) - 1))
+ {
+ TYPE_VPTR_FIELDNO (type) = i;
+ goto gotit;
+ }
+ }
+ /* Virtual function table field not found. */
+ complain (&vtbl_notfound_complaint, TYPE_NAME (type));
+ return 0;
+ }
+ else
+ {
+ TYPE_VPTR_FIELDNO (type) = TYPE_VPTR_FIELDNO (t);
+ }
+
+ gotit:
+ *pp = p + 1;
+ }
+ }
+ return 1;
+}
+
+static int
+attach_fn_fields_to_type (fip, type)
+ struct field_info *fip;
+ register struct type *type;
+{
+ register int n;
+
+ for (n = 0; n < TYPE_N_BASECLASSES (type); n++)
+ {
+ if (TYPE_CODE (TYPE_BASECLASS (type, n)) == TYPE_CODE_UNDEF)
+ {
+ /* @@ Memory leak on objfile -> type_obstack? */
+ return 0;
+ }
+ TYPE_NFN_FIELDS_TOTAL (type) +=
+ TYPE_NFN_FIELDS_TOTAL (TYPE_BASECLASS (type, n));
+ }
+
+ for (n = TYPE_NFN_FIELDS (type);
+ fip -> fnlist != NULL;
+ fip -> fnlist = fip -> fnlist -> next)
+ {
+ --n; /* Circumvent Sun3 compiler bug */
+ TYPE_FN_FIELDLISTS (type)[n] = fip -> fnlist -> fn_fieldlist;
+ }
+ return 1;
+}
+
+/* Create the vector of fields, and record how big it is.
+ We need this info to record proper virtual function table information
+ for this class's virtual functions. */
+
+static int
+attach_fields_to_type (fip, type, objfile)
+ struct field_info *fip;
+ register struct type *type;
+ struct objfile *objfile;
+{
+ register int nfields = 0;
+ register int non_public_fields = 0;
+ register struct nextfield *scan;
+
+ /* Count up the number of fields that we have, as well as taking note of
+ whether or not there are any non-public fields, which requires us to
+ allocate and build the private_field_bits and protected_field_bits
+ bitfields. */
+
+ for (scan = fip -> list; scan != NULL; scan = scan -> next)
+ {
+ nfields++;
+ if (scan -> visibility != VISIBILITY_PUBLIC)
+ {
+ non_public_fields++;
+ }
+ }
+
+ /* Now we know how many fields there are, and whether or not there are any
+ non-public fields. Record the field count, allocate space for the
+ array of fields, and create blank visibility bitfields if necessary. */
+
+ TYPE_NFIELDS (type) = nfields;
+ TYPE_FIELDS (type) = (struct field *)
+ TYPE_ALLOC (type, sizeof (struct field) * nfields);
+ memset (TYPE_FIELDS (type), 0, sizeof (struct field) * nfields);
+
+ if (non_public_fields)
+ {
+ ALLOCATE_CPLUS_STRUCT_TYPE (type);
+
+ TYPE_FIELD_PRIVATE_BITS (type) =
+ (B_TYPE *) TYPE_ALLOC (type, B_BYTES (nfields));
+ B_CLRALL (TYPE_FIELD_PRIVATE_BITS (type), nfields);
+
+ TYPE_FIELD_PROTECTED_BITS (type) =
+ (B_TYPE *) TYPE_ALLOC (type, B_BYTES (nfields));
+ B_CLRALL (TYPE_FIELD_PROTECTED_BITS (type), nfields);
+
+ TYPE_FIELD_IGNORE_BITS (type) =
+ (B_TYPE *) TYPE_ALLOC (type, B_BYTES (nfields));
+ B_CLRALL (TYPE_FIELD_IGNORE_BITS (type), nfields);
+ }
+
+ /* Copy the saved-up fields into the field vector. Start from the head
+ of the list, adding to the tail of the field array, so that they end
+ up in the same order in the array in which they were added to the list. */
+
+ while (nfields-- > 0)
+ {
+ TYPE_FIELD (type, nfields) = fip -> list -> field;
+ switch (fip -> list -> visibility)
+ {
+ case VISIBILITY_PRIVATE:
+ SET_TYPE_FIELD_PRIVATE (type, nfields);
+ break;
+
+ case VISIBILITY_PROTECTED:
+ SET_TYPE_FIELD_PROTECTED (type, nfields);
+ break;
+
+ case VISIBILITY_IGNORE:
+ SET_TYPE_FIELD_IGNORE (type, nfields);
+ break;
+
+ case VISIBILITY_PUBLIC:
+ break;
+
+ default:
+ /* Unknown visibility. Complain and treat it as public. */
+ {
+ static struct complaint msg = {
+ "Unknown visibility `%c' for field", 0, 0};
+ complain (&msg, fip -> list -> visibility);
+ }
+ break;
+ }
+ fip -> list = fip -> list -> next;
+ }
+ return 1;
+}
+
+/* Read the description of a structure (or union type) and return an object
+ describing the type.
+
+ PP points to a character pointer that points to the next unconsumed token
+ in the the stabs string. For example, given stabs "A:T4=s4a:1,0,32;;",
+ *PP will point to "4a:1,0,32;;".
+
+ TYPE points to an incomplete type that needs to be filled in.
+
+ OBJFILE points to the current objfile from which the stabs information is
+ being read. (Note that it is redundant in that TYPE also contains a pointer
+ to this same objfile, so it might be a good idea to eliminate it. FIXME).
+ */
+
+static struct type *
+read_struct_type (pp, type, objfile)
+ char **pp;
+ struct type *type;
+ struct objfile *objfile;
+{
+ struct cleanup *back_to;
+ struct field_info fi;
+
+ fi.list = NULL;
+ fi.fnlist = NULL;
+
+ back_to = make_cleanup (null_cleanup, 0);
+
+ INIT_CPLUS_SPECIFIC (type);
+ TYPE_FLAGS (type) &= ~TYPE_FLAG_STUB;
+
+ /* First comes the total size in bytes. */
+
+ {
+ int nbits;
+ TYPE_LENGTH (type) = read_huge_number (pp, 0, &nbits);
+ if (nbits != 0)
+ return error_type (pp);
+ }
+
+ /* Now read the baseclasses, if any, read the regular C struct or C++
+ class member fields, attach the fields to the type, read the C++
+ member functions, attach them to the type, and then read any tilde
+ field (baseclass specifier for the class holding the main vtable). */
+
+ if (!read_baseclasses (&fi, pp, type, objfile)
+ || !read_struct_fields (&fi, pp, type, objfile)
+ || !attach_fields_to_type (&fi, type, objfile)
+ || !read_member_functions (&fi, pp, type, objfile)
+ || !attach_fn_fields_to_type (&fi, type)
+ || !read_tilde_fields (&fi, pp, type, objfile))
+ {
+ do_cleanups (back_to);
+ return (error_type (pp));
+ }
+
+ do_cleanups (back_to);
+ return (type);
+}
+
+/* Read a definition of an array type,
+ and create and return a suitable type object.
+ Also creates a range type which represents the bounds of that
+ array. */
+
+static struct type *
+read_array_type (pp, type, objfile)
+ register char **pp;
+ register struct type *type;
+ struct objfile *objfile;
+{
+ struct type *index_type, *element_type, *range_type;
+ int lower, upper;
+ int adjustable = 0;
+ int nbits;
+
+ /* Format of an array type:
+ "ar<index type>;lower;upper;<array_contents_type>".
+ OS9000: "arlower,upper;<array_contents_type>".
+
+ Fortran adjustable arrays use Adigits or Tdigits for lower or upper;
+ for these, produce a type like float[][]. */
+
+ if (os9k_stabs)
+ index_type = builtin_type_int;
+ else
+ {
+ index_type = read_type (pp, objfile);
+ if (**pp != ';')
+ /* Improper format of array type decl. */
+ return error_type (pp);
+ ++*pp;
+ }
+
+ if (!(**pp >= '0' && **pp <= '9') && **pp != '-')
+ {
+ (*pp)++;
+ adjustable = 1;
+ }
+ lower = read_huge_number (pp, os9k_stabs ? ',' : ';', &nbits);
+ if (nbits != 0)
+ return error_type (pp);
+
+ if (!(**pp >= '0' && **pp <= '9') && **pp != '-')
+ {
+ (*pp)++;
+ adjustable = 1;
+ }
+ upper = read_huge_number (pp, ';', &nbits);
+ if (nbits != 0)
+ return error_type (pp);
+
+ element_type = read_type (pp, objfile);
+
+ if (adjustable)
+ {
+ lower = 0;
+ upper = -1;
+ }
+
+ range_type =
+ create_range_type ((struct type *) NULL, index_type, lower, upper);
+ type = create_array_type (type, element_type, range_type);
+
+ /* If we have an array whose element type is not yet known, but whose
+ bounds *are* known, record it to be adjusted at the end of the file. */
+ /* FIXME: Why check for zero length rather than TYPE_FLAG_STUB? I think
+ the two have the same effect except that the latter is cleaner and the
+ former would be wrong for types which really are zero-length (if we
+ have any). */
+
+ if (TYPE_LENGTH (element_type) == 0 && !adjustable)
+ {
+ TYPE_FLAGS (type) |= TYPE_FLAG_TARGET_STUB;
+ add_undefined_type (type);
+ }
+
+ return type;
+}
+
+
+/* Read a definition of an enumeration type,
+ and create and return a suitable type object.
+ Also defines the symbols that represent the values of the type. */
+
+static struct type *
+read_enum_type (pp, type, objfile)
+ register char **pp;
+ register struct type *type;
+ struct objfile *objfile;
+{
+ register char *p;
+ char *name;
+ register long n;
+ register struct symbol *sym;
+ int nsyms = 0;
+ struct pending **symlist;
+ struct pending *osyms, *syms;
+ int o_nsyms;
+ int nbits;
+
+#if 0
+ /* FIXME! The stabs produced by Sun CC merrily define things that ought
+ to be file-scope, between N_FN entries, using N_LSYM. What's a mother
+ to do? For now, force all enum values to file scope. */
+ if (within_function)
+ symlist = &local_symbols;
+ else
+#endif
+ symlist = &file_symbols;
+ osyms = *symlist;
+ o_nsyms = osyms ? osyms->nsyms : 0;
+
+ if (os9k_stabs)
+ {
+ /* Size. Perhaps this does not have to be conditionalized on
+ os9k_stabs (assuming the name of an enum constant can't start
+ with a digit). */
+ read_huge_number (pp, 0, &nbits);
+ if (nbits != 0)
+ return error_type (pp);
+ }
+
+ /* Read the value-names and their values.
+ The input syntax is NAME:VALUE,NAME:VALUE, and so on.
+ A semicolon or comma instead of a NAME means the end. */
+ while (**pp && **pp != ';' && **pp != ',')
+ {
+ STABS_CONTINUE (pp);
+ p = *pp;
+ while (*p != ':') p++;
+ name = obsavestring (*pp, p - *pp, &objfile -> symbol_obstack);
+ *pp = p + 1;
+ n = read_huge_number (pp, ',', &nbits);
+ if (nbits != 0)
+ return error_type (pp);
+
+ sym = (struct symbol *)
+ obstack_alloc (&objfile -> symbol_obstack, sizeof (struct symbol));
+ memset (sym, 0, sizeof (struct symbol));
+ SYMBOL_NAME (sym) = name;
+ SYMBOL_LANGUAGE (sym) = current_subfile -> language;
+ SYMBOL_CLASS (sym) = LOC_CONST;
+ SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE;
+ SYMBOL_VALUE (sym) = n;
+ add_symbol_to_list (sym, symlist);
+ nsyms++;
+ }
+
+ if (**pp == ';')
+ (*pp)++; /* Skip the semicolon. */
+
+ /* Now fill in the fields of the type-structure. */
+
+ TYPE_LENGTH (type) = TARGET_INT_BIT / HOST_CHAR_BIT;
+ TYPE_CODE (type) = TYPE_CODE_ENUM;
+ TYPE_FLAGS (type) &= ~TYPE_FLAG_STUB;
+ TYPE_NFIELDS (type) = nsyms;
+ TYPE_FIELDS (type) = (struct field *)
+ TYPE_ALLOC (type, sizeof (struct field) * nsyms);
+ memset (TYPE_FIELDS (type), 0, sizeof (struct field) * nsyms);
+
+ /* Find the symbols for the values and put them into the type.
+ The symbols can be found in the symlist that we put them on
+ to cause them to be defined. osyms contains the old value
+ of that symlist; everything up to there was defined by us. */
+ /* Note that we preserve the order of the enum constants, so
+ that in something like "enum {FOO, LAST_THING=FOO}" we print
+ FOO, not LAST_THING. */
+
+ for (syms = *symlist, n = 0; syms; syms = syms->next)
+ {
+ int j = 0;
+ if (syms == osyms)
+ j = o_nsyms;
+ for (; j < syms->nsyms; j++,n++)
+ {
+ struct symbol *xsym = syms->symbol[j];
+ SYMBOL_TYPE (xsym) = type;
+ TYPE_FIELD_NAME (type, n) = SYMBOL_NAME (xsym);
+ TYPE_FIELD_VALUE (type, n) = 0;
+ TYPE_FIELD_BITPOS (type, n) = SYMBOL_VALUE (xsym);
+ TYPE_FIELD_BITSIZE (type, n) = 0;
+ }
+ if (syms == osyms)
+ break;
+ }
+
+ return type;
+}
+
+/* Sun's ACC uses a somewhat saner method for specifying the builtin
+ typedefs in every file (for int, long, etc):
+
+ type = b <signed> <width>; <offset>; <nbits>
+ signed = u or s. Possible c in addition to u or s (for char?).
+ offset = offset from high order bit to start bit of type.
+ width is # bytes in object of this type, nbits is # bits in type.
+
+ The width/offset stuff appears to be for small objects stored in
+ larger ones (e.g. `shorts' in `int' registers). We ignore it for now,
+ FIXME. */
+
+static struct type *
+read_sun_builtin_type (pp, typenums, objfile)
+ char **pp;
+ int typenums[2];
+ struct objfile *objfile;
+{
+ int type_bits;
+ int nbits;
+ int signed_type;
+
+ switch (**pp)
+ {
+ case 's':
+ signed_type = 1;
+ break;
+ case 'u':
+ signed_type = 0;
+ break;
+ default:
+ return error_type (pp);
+ }
+ (*pp)++;
+
+ /* For some odd reason, all forms of char put a c here. This is strange
+ because no other type has this honor. We can safely ignore this because
+ we actually determine 'char'acterness by the number of bits specified in
+ the descriptor. */
+
+ if (**pp == 'c')
+ (*pp)++;
+
+ /* The first number appears to be the number of bytes occupied
+ by this type, except that unsigned short is 4 instead of 2.
+ Since this information is redundant with the third number,
+ we will ignore it. */
+ read_huge_number (pp, ';', &nbits);
+ if (nbits != 0)
+ return error_type (pp);
+
+ /* The second number is always 0, so ignore it too. */
+ read_huge_number (pp, ';', &nbits);
+ if (nbits != 0)
+ return error_type (pp);
+
+ /* The third number is the number of bits for this type. */
+ type_bits = read_huge_number (pp, 0, &nbits);
+ if (nbits != 0)
+ return error_type (pp);
+ /* The type *should* end with a semicolon. If it are embedded
+ in a larger type the semicolon may be the only way to know where
+ the type ends. If this type is at the end of the stabstring we
+ can deal with the omitted semicolon (but we don't have to like
+ it). Don't bother to complain(), Sun's compiler omits the semicolon
+ for "void". */
+ if (**pp == ';')
+ ++(*pp);
+
+ if (type_bits == 0)
+ return init_type (TYPE_CODE_VOID, 1,
+ signed_type ? 0 : TYPE_FLAG_UNSIGNED, (char *)NULL,
+ objfile);
+ else
+ return init_type (TYPE_CODE_INT,
+ type_bits / TARGET_CHAR_BIT,
+ signed_type ? 0 : TYPE_FLAG_UNSIGNED, (char *)NULL,
+ objfile);
+}
+
+static struct type *
+read_sun_floating_type (pp, typenums, objfile)
+ char **pp;
+ int typenums[2];
+ struct objfile *objfile;
+{
+ int nbits;
+ int details;
+ int nbytes;
+
+ /* The first number has more details about the type, for example
+ FN_COMPLEX. */
+ details = read_huge_number (pp, ';', &nbits);
+ if (nbits != 0)
+ return error_type (pp);
+
+ /* The second number is the number of bytes occupied by this type */
+ nbytes = read_huge_number (pp, ';', &nbits);
+ if (nbits != 0)
+ return error_type (pp);
+
+ if (details == NF_COMPLEX || details == NF_COMPLEX16
+ || details == NF_COMPLEX32)
+ /* This is a type we can't handle, but we do know the size.
+ We also will be able to give it a name. */
+ return init_type (TYPE_CODE_ERROR, nbytes, 0, NULL, objfile);
+
+ return init_type (TYPE_CODE_FLT, nbytes, 0, NULL, objfile);
+}
+
+/* Read a number from the string pointed to by *PP.
+ The value of *PP is advanced over the number.
+ If END is nonzero, the character that ends the
+ number must match END, or an error happens;
+ and that character is skipped if it does match.
+ If END is zero, *PP is left pointing to that character.
+
+ If the number fits in a long, set *BITS to 0 and return the value.
+ If not, set *BITS to be the number of bits in the number and return 0.
+
+ If encounter garbage, set *BITS to -1 and return 0. */
+
+static long
+read_huge_number (pp, end, bits)
+ char **pp;
+ int end;
+ int *bits;
+{
+ char *p = *pp;
+ int sign = 1;
+ long n = 0;
+ int radix = 10;
+ char overflow = 0;
+ int nbits = 0;
+ int c;
+ long upper_limit;
+
+ if (*p == '-')
+ {
+ sign = -1;
+ p++;
+ }
+
+ /* Leading zero means octal. GCC uses this to output values larger
+ than an int (because that would be hard in decimal). */
+ if (*p == '0')
+ {
+ radix = 8;
+ p++;
+ }
+
+ if (os9k_stabs)
+ upper_limit = ULONG_MAX / radix;
+ else
+ upper_limit = LONG_MAX / radix;
+
+ while ((c = *p++) >= '0' && c < ('0' + radix))
+ {
+ if (n <= upper_limit)
+ {
+ n *= radix;
+ n += c - '0'; /* FIXME this overflows anyway */
+ }
+ else
+ overflow = 1;
+
+ /* This depends on large values being output in octal, which is
+ what GCC does. */
+ if (radix == 8)
+ {
+ if (nbits == 0)
+ {
+ if (c == '0')
+ /* Ignore leading zeroes. */
+ ;
+ else if (c == '1')
+ nbits = 1;
+ else if (c == '2' || c == '3')
+ nbits = 2;
+ else
+ nbits = 3;
+ }
+ else
+ nbits += 3;
+ }
+ }
+ if (end)
+ {
+ if (c && c != end)
+ {
+ if (bits != NULL)
+ *bits = -1;
+ return 0;
+ }
+ }
+ else
+ --p;
+
+ *pp = p;
+ if (overflow)
+ {
+ if (nbits == 0)
+ {
+ /* Large decimal constants are an error (because it is hard to
+ count how many bits are in them). */
+ if (bits != NULL)
+ *bits = -1;
+ return 0;
+ }
+
+ /* -0x7f is the same as 0x80. So deal with it by adding one to
+ the number of bits. */
+ if (sign == -1)
+ ++nbits;
+ if (bits)
+ *bits = nbits;
+ }
+ else
+ {
+ if (bits)
+ *bits = 0;
+ return n * sign;
+ }
+ /* It's *BITS which has the interesting information. */
+ return 0;
+}
+
+static struct type *
+read_range_type (pp, typenums, objfile)
+ char **pp;
+ int typenums[2];
+ struct objfile *objfile;
+{
+ int rangenums[2];
+ long n2, n3;
+ int n2bits, n3bits;
+ int self_subrange;
+ struct type *result_type;
+ struct type *index_type;
+
+ /* First comes a type we are a subrange of.
+ In C it is usually 0, 1 or the type being defined. */
+ /* FIXME: according to stabs.texinfo and AIX doc, this can be a type-id
+ not just a type number. */
+ if (read_type_number (pp, rangenums) != 0)
+ return error_type (pp);
+ self_subrange = (rangenums[0] == typenums[0] &&
+ rangenums[1] == typenums[1]);
+
+ /* A semicolon should now follow; skip it. */
+ if (**pp == ';')
+ (*pp)++;
+
+ /* The remaining two operands are usually lower and upper bounds
+ of the range. But in some special cases they mean something else. */
+ n2 = read_huge_number (pp, ';', &n2bits);
+ n3 = read_huge_number (pp, ';', &n3bits);
+
+ if (n2bits == -1 || n3bits == -1)
+ return error_type (pp);
+
+ /* If limits are huge, must be large integral type. */
+ if (n2bits != 0 || n3bits != 0)
+ {
+ char got_signed = 0;
+ char got_unsigned = 0;
+ /* Number of bits in the type. */
+ int nbits = 0;
+
+ /* Range from 0 to <large number> is an unsigned large integral type. */
+ if ((n2bits == 0 && n2 == 0) && n3bits != 0)
+ {
+ got_unsigned = 1;
+ nbits = n3bits;
+ }
+ /* Range from <large number> to <large number>-1 is a large signed
+ integral type. Take care of the case where <large number> doesn't
+ fit in a long but <large number>-1 does. */
+ else if ((n2bits != 0 && n3bits != 0 && n2bits == n3bits + 1)
+ || (n2bits != 0 && n3bits == 0
+ && (n2bits == sizeof (long) * HOST_CHAR_BIT)
+ && n3 == LONG_MAX))
+ {
+ got_signed = 1;
+ nbits = n2bits;
+ }
+
+ if (got_signed || got_unsigned)
+ {
+ return init_type (TYPE_CODE_INT, nbits / TARGET_CHAR_BIT,
+ got_unsigned ? TYPE_FLAG_UNSIGNED : 0, NULL,
+ objfile);
+ }
+ else
+ return error_type (pp);
+ }
+
+ /* A type defined as a subrange of itself, with bounds both 0, is void. */
+ if (self_subrange && n2 == 0 && n3 == 0)
+ return init_type (TYPE_CODE_VOID, 1, 0, NULL, objfile);
+
+ /* If n3 is zero and n2 is not, we want a floating type,
+ and n2 is the width in bytes.
+
+ Fortran programs appear to use this for complex types also,
+ and they give no way to distinguish between double and single-complex!
+
+ GDB does not have complex types.
+
+ Just return the complex as a float of that size. It won't work right
+ for the complex values, but at least it makes the file loadable. */
+
+ if (n3 == 0 && n2 > 0)
+ {
+ return init_type (TYPE_CODE_FLT, n2, 0, NULL, objfile);
+ }
+
+ /* If the upper bound is -1, it must really be an unsigned int. */
+
+ else if (n2 == 0 && n3 == -1)
+ {
+ /* It is unsigned int or unsigned long. */
+ /* GCC 2.3.3 uses this for long long too, but that is just a GDB 3.5
+ compatibility hack. */
+ return init_type (TYPE_CODE_INT, TARGET_INT_BIT / TARGET_CHAR_BIT,
+ TYPE_FLAG_UNSIGNED, NULL, objfile);
+ }
+
+ /* Special case: char is defined (Who knows why) as a subrange of
+ itself with range 0-127. */
+ else if (self_subrange && n2 == 0 && n3 == 127)
+ return init_type (TYPE_CODE_INT, 1, 0, NULL, objfile);
+
+ /* We used to do this only for subrange of self or subrange of int. */
+ else if (n2 == 0)
+ {
+ if (n3 < 0)
+ /* n3 actually gives the size. */
+ return init_type (TYPE_CODE_INT, - n3, TYPE_FLAG_UNSIGNED,
+ NULL, objfile);
+ if (n3 == 0xff)
+ return init_type (TYPE_CODE_INT, 1, TYPE_FLAG_UNSIGNED, NULL, objfile);
+ if (n3 == 0xffff)
+ return init_type (TYPE_CODE_INT, 2, TYPE_FLAG_UNSIGNED, NULL, objfile);
+
+ /* -1 is used for the upper bound of (4 byte) "unsigned int" and
+ "unsigned long", and we already checked for that,
+ so don't need to test for it here. */
+ }
+ /* I think this is for Convex "long long". Since I don't know whether
+ Convex sets self_subrange, I also accept that particular size regardless
+ of self_subrange. */
+ else if (n3 == 0 && n2 < 0
+ && (self_subrange
+ || n2 == - TARGET_LONG_LONG_BIT / TARGET_CHAR_BIT))
+ return init_type (TYPE_CODE_INT, - n2, 0, NULL, objfile);
+ else if (n2 == -n3 -1)
+ {
+ if (n3 == 0x7f)
+ return init_type (TYPE_CODE_INT, 1, 0, NULL, objfile);
+ if (n3 == 0x7fff)
+ return init_type (TYPE_CODE_INT, 2, 0, NULL, objfile);
+ if (n3 == 0x7fffffff)
+ return init_type (TYPE_CODE_INT, 4, 0, NULL, objfile);
+ }
+
+ /* We have a real range type on our hands. Allocate space and
+ return a real pointer. */
+
+ /* At this point I don't have the faintest idea how to deal with
+ a self_subrange type; I'm going to assume that this is used
+ as an idiom, and that all of them are special cases. So . . . */
+ if (self_subrange)
+ return error_type (pp);
+
+ index_type = *dbx_lookup_type (rangenums);
+ if (index_type == NULL)
+ {
+ /* Does this actually ever happen? Is that why we are worrying
+ about dealing with it rather than just calling error_type? */
+
+ static struct type *range_type_index;
+
+ complain (&range_type_base_complaint, rangenums[1]);
+ if (range_type_index == NULL)
+ range_type_index =
+ init_type (TYPE_CODE_INT, TARGET_INT_BIT / TARGET_CHAR_BIT,
+ 0, "range type index type", NULL);
+ index_type = range_type_index;
+ }
+
+ result_type = create_range_type ((struct type *) NULL, index_type, n2, n3);
+ return (result_type);
+}
+
+/* Read in an argument list. This is a list of types, separated by commas
+ and terminated with END. Return the list of types read in, or (struct type
+ **)-1 if there is an error. */
+
+static struct type **
+read_args (pp, end, objfile)
+ char **pp;
+ int end;
+ struct objfile *objfile;
+{
+ /* FIXME! Remove this arbitrary limit! */
+ struct type *types[1024], **rval; /* allow for fns of 1023 parameters */
+ int n = 0;
+
+ while (**pp != end)
+ {
+ if (**pp != ',')
+ /* Invalid argument list: no ','. */
+ return (struct type **)-1;
+ (*pp)++;
+ STABS_CONTINUE (pp);
+ types[n++] = read_type (pp, objfile);
+ }
+ (*pp)++; /* get past `end' (the ':' character) */
+
+ if (n == 1)
+ {
+ rval = (struct type **) xmalloc (2 * sizeof (struct type *));
+ }
+ else if (TYPE_CODE (types[n-1]) != TYPE_CODE_VOID)
+ {
+ rval = (struct type **) xmalloc ((n + 1) * sizeof (struct type *));
+ memset (rval + n, 0, sizeof (struct type *));
+ }
+ else
+ {
+ rval = (struct type **) xmalloc (n * sizeof (struct type *));
+ }
+ memcpy (rval, types, n * sizeof (struct type *));
+ return rval;
+}
+
+/* Common block handling. */
+
+/* List of symbols declared since the last BCOMM. This list is a tail
+ of local_symbols. When ECOMM is seen, the symbols on the list
+ are noted so their proper addresses can be filled in later,
+ using the common block base address gotten from the assembler
+ stabs. */
+
+static struct pending *common_block;
+static int common_block_i;
+
+/* Name of the current common block. We get it from the BCOMM instead of the
+ ECOMM to match IBM documentation (even though IBM puts the name both places
+ like everyone else). */
+static char *common_block_name;
+
+/* Process a N_BCOMM symbol. The storage for NAME is not guaranteed
+ to remain after this function returns. */
+
+void
+common_block_start (name, objfile)
+ char *name;
+ struct objfile *objfile;
+{
+ if (common_block_name != NULL)
+ {
+ static struct complaint msg = {
+ "Invalid symbol data: common block within common block",
+ 0, 0};
+ complain (&msg);
+ }
+ common_block = local_symbols;
+ common_block_i = local_symbols ? local_symbols->nsyms : 0;
+ common_block_name = obsavestring (name, strlen (name),
+ &objfile -> symbol_obstack);
+}
+
+/* Process a N_ECOMM symbol. */
+
+void
+common_block_end (objfile)
+ struct objfile *objfile;
+{
+ /* Symbols declared since the BCOMM are to have the common block
+ start address added in when we know it. common_block and
+ common_block_i point to the first symbol after the BCOMM in
+ the local_symbols list; copy the list and hang it off the
+ symbol for the common block name for later fixup. */
+ int i;
+ struct symbol *sym;
+ struct pending *new = 0;
+ struct pending *next;
+ int j;
+
+ if (common_block_name == NULL)
+ {
+ static struct complaint msg = {"ECOMM symbol unmatched by BCOMM", 0, 0};
+ complain (&msg);
+ return;
+ }
+
+ sym = (struct symbol *)
+ obstack_alloc (&objfile -> symbol_obstack, sizeof (struct symbol));
+ memset (sym, 0, sizeof (struct symbol));
+ SYMBOL_NAME (sym) = common_block_name;
+ SYMBOL_CLASS (sym) = LOC_BLOCK;
+
+ /* Now we copy all the symbols which have been defined since the BCOMM. */
+
+ /* Copy all the struct pendings before common_block. */
+ for (next = local_symbols;
+ next != NULL && next != common_block;
+ next = next->next)
+ {
+ for (j = 0; j < next->nsyms; j++)
+ add_symbol_to_list (next->symbol[j], &new);
+ }
+
+ /* Copy however much of COMMON_BLOCK we need. If COMMON_BLOCK is
+ NULL, it means copy all the local symbols (which we already did
+ above). */
+
+ if (common_block != NULL)
+ for (j = common_block_i; j < common_block->nsyms; j++)
+ add_symbol_to_list (common_block->symbol[j], &new);
+
+ SYMBOL_TYPE (sym) = (struct type *) new;
+
+ /* Should we be putting local_symbols back to what it was?
+ Does it matter? */
+
+ i = hashname (SYMBOL_NAME (sym));
+ SYMBOL_VALUE_CHAIN (sym) = global_sym_chain[i];
+ global_sym_chain[i] = sym;
+ common_block_name = NULL;
+}
+
+/* Add a common block's start address to the offset of each symbol
+ declared to be in it (by being between a BCOMM/ECOMM pair that uses
+ the common block name). */
+
+static void
+fix_common_block (sym, valu)
+ struct symbol *sym;
+ int valu;
+{
+ struct pending *next = (struct pending *) SYMBOL_TYPE (sym);
+ for ( ; next; next = next->next)
+ {
+ register int j;
+ for (j = next->nsyms - 1; j >= 0; j--)
+ SYMBOL_VALUE_ADDRESS (next->symbol[j]) += valu;
+ }
+}
+
+
+
+/* What about types defined as forward references inside of a small lexical
+ scope? */
+/* Add a type to the list of undefined types to be checked through
+ once this file has been read in. */
+
+void
+add_undefined_type (type)
+ struct type *type;
+{
+ if (undef_types_length == undef_types_allocated)
+ {
+ undef_types_allocated *= 2;
+ undef_types = (struct type **)
+ xrealloc ((char *) undef_types,
+ undef_types_allocated * sizeof (struct type *));
+ }
+ undef_types[undef_types_length++] = type;
+}
+
+/* Go through each undefined type, see if it's still undefined, and fix it
+ up if possible. We have two kinds of undefined types:
+
+ TYPE_CODE_ARRAY: Array whose target type wasn't defined yet.
+ Fix: update array length using the element bounds
+ and the target type's length.
+ TYPE_CODE_STRUCT, TYPE_CODE_UNION: Structure whose fields were not
+ yet defined at the time a pointer to it was made.
+ Fix: Do a full lookup on the struct/union tag. */
+void
+cleanup_undefined_types ()
+{
+ struct type **type;
+
+ for (type = undef_types; type < undef_types + undef_types_length; type++)
+ {
+ switch (TYPE_CODE (*type))
+ {
+
+ case TYPE_CODE_STRUCT:
+ case TYPE_CODE_UNION:
+ case TYPE_CODE_ENUM:
+ {
+ /* Check if it has been defined since. Need to do this here
+ as well as in check_stub_type to deal with the (legitimate in
+ C though not C++) case of several types with the same name
+ in different source files. */
+ if (TYPE_FLAGS (*type) & TYPE_FLAG_STUB)
+ {
+ struct pending *ppt;
+ int i;
+ /* Name of the type, without "struct" or "union" */
+ char *typename = TYPE_TAG_NAME (*type);
+
+ if (typename == NULL)
+ {
+ static struct complaint msg = {"need a type name", 0, 0};
+ complain (&msg);
+ break;
+ }
+ for (ppt = file_symbols; ppt; ppt = ppt->next)
+ {
+ for (i = 0; i < ppt->nsyms; i++)
+ {
+ struct symbol *sym = ppt->symbol[i];
+
+ if (SYMBOL_CLASS (sym) == LOC_TYPEDEF
+ && SYMBOL_NAMESPACE (sym) == STRUCT_NAMESPACE
+ && (TYPE_CODE (SYMBOL_TYPE (sym)) ==
+ TYPE_CODE (*type))
+ && STREQ (SYMBOL_NAME (sym), typename))
+ {
+ memcpy (*type, SYMBOL_TYPE (sym),
+ sizeof (struct type));
+ }
+ }
+ }
+ }
+ }
+ break;
+
+ case TYPE_CODE_ARRAY:
+ {
+ /* This is a kludge which is here for historical reasons
+ because I suspect that check_stub_type does not get
+ called everywhere it needs to be called for arrays. Even
+ with this kludge, those places are broken for the case
+ where the stub type is defined in another compilation
+ unit, but this kludge at least deals with it for the case
+ in which it is the same compilation unit.
+
+ Don't try to do this by calling check_stub_type; it might
+ cause symbols to be read in lookup_symbol, and the symbol
+ reader is not reentrant. */
+
+ struct type *range_type;
+ int lower, upper;
+
+ if (TYPE_LENGTH (*type) != 0) /* Better be unknown */
+ goto badtype;
+ if (TYPE_NFIELDS (*type) != 1)
+ goto badtype;
+ range_type = TYPE_FIELD_TYPE (*type, 0);
+ if (TYPE_CODE (range_type) != TYPE_CODE_RANGE)
+ goto badtype;
+
+ /* Now recompute the length of the array type, based on its
+ number of elements and the target type's length. */
+ lower = TYPE_FIELD_BITPOS (range_type, 0);
+ upper = TYPE_FIELD_BITPOS (range_type, 1);
+ TYPE_LENGTH (*type) = (upper - lower + 1)
+ * TYPE_LENGTH (TYPE_TARGET_TYPE (*type));
+
+ /* If the target type is not a stub, we could be clearing
+ TYPE_FLAG_TARGET_STUB for *type. */
+ }
+ break;
+
+ default:
+ badtype:
+ {
+ static struct complaint msg = {"\
+GDB internal error. cleanup_undefined_types with bad type %d.", 0, 0};
+ complain (&msg, TYPE_CODE (*type));
+ }
+ break;
+ }
+ }
+
+ undef_types_length = 0;
+}
+
+/* Scan through all of the global symbols defined in the object file,
+ assigning values to the debugging symbols that need to be assigned
+ to. Get these symbols from the minimal symbol table. */
+
+void
+scan_file_globals (objfile)
+ struct objfile *objfile;
+{
+ int hash;
+ struct minimal_symbol *msymbol;
+ struct symbol *sym, *prev;
+
+ if (objfile->msymbols == 0) /* Beware the null file. */
+ return;
+
+ for (msymbol = objfile -> msymbols; SYMBOL_NAME (msymbol) != NULL; msymbol++)
+ {
+ QUIT;
+
+ prev = NULL;
+
+ /* Get the hash index and check all the symbols
+ under that hash index. */
+
+ hash = hashname (SYMBOL_NAME (msymbol));
+
+ for (sym = global_sym_chain[hash]; sym;)
+ {
+ if (SYMBOL_NAME (msymbol)[0] == SYMBOL_NAME (sym)[0] &&
+ STREQ(SYMBOL_NAME (msymbol) + 1, SYMBOL_NAME (sym) + 1))
+ {
+ /* Splice this symbol out of the hash chain and
+ assign the value we have to it. */
+ if (prev)
+ {
+ SYMBOL_VALUE_CHAIN (prev) = SYMBOL_VALUE_CHAIN (sym);
+ }
+ else
+ {
+ global_sym_chain[hash] = SYMBOL_VALUE_CHAIN (sym);
+ }
+
+ /* Check to see whether we need to fix up a common block. */
+ /* Note: this code might be executed several times for
+ the same symbol if there are multiple references. */
+
+ if (SYMBOL_CLASS (sym) == LOC_BLOCK)
+ {
+ fix_common_block (sym, SYMBOL_VALUE_ADDRESS (msymbol));
+ }
+ else
+ {
+ SYMBOL_VALUE_ADDRESS (sym) = SYMBOL_VALUE_ADDRESS (msymbol);
+ }
+
+ SYMBOL_SECTION (sym) = SYMBOL_SECTION (msymbol);
+
+ if (prev)
+ {
+ sym = SYMBOL_VALUE_CHAIN (prev);
+ }
+ else
+ {
+ sym = global_sym_chain[hash];
+ }
+ }
+ else
+ {
+ prev = sym;
+ sym = SYMBOL_VALUE_CHAIN (sym);
+ }
+ }
+ }
+}
+
+/* Initialize anything that needs initializing when starting to read
+ a fresh piece of a symbol file, e.g. reading in the stuff corresponding
+ to a psymtab. */
+
+void
+stabsread_init ()
+{
+}
+
+/* Initialize anything that needs initializing when a completely new
+ symbol file is specified (not just adding some symbols from another
+ file, e.g. a shared library). */
+
+void
+stabsread_new_init ()
+{
+ /* Empty the hash table of global syms looking for values. */
+ memset (global_sym_chain, 0, sizeof (global_sym_chain));
+}
+
+/* Initialize anything that needs initializing at the same time as
+ start_symtab() is called. */
+
+void start_stabs ()
+{
+ global_stabs = NULL; /* AIX COFF */
+ /* Leave FILENUM of 0 free for builtin types and this file's types. */
+ n_this_object_header_files = 1;
+ type_vector_length = 0;
+ type_vector = (struct type **) 0;
+
+ /* FIXME: If common_block_name is not already NULL, we should complain(). */
+ common_block_name = NULL;
+
+ os9k_stabs = 0;
+}
+
+/* Call after end_symtab() */
+
+void end_stabs ()
+{
+ if (type_vector)
+ {
+ free ((char *) type_vector);
+ }
+ type_vector = 0;
+ type_vector_length = 0;
+ previous_stab_code = 0;
+}
+
+void
+finish_global_stabs (objfile)
+ struct objfile *objfile;
+{
+ if (global_stabs)
+ {
+ patch_block_stabs (global_symbols, global_stabs, objfile);
+ free ((PTR) global_stabs);
+ global_stabs = NULL;
+ }
+}
+
+/* Initializer for this module */
+
+void
+_initialize_stabsread ()
+{
+ undef_types_allocated = 20;
+ undef_types_length = 0;
+ undef_types = (struct type **)
+ xmalloc (undef_types_allocated * sizeof (struct type *));
+}
diff --git a/gnu/usr.bin/gdb/gdb/stabsread.h b/gnu/usr.bin/gdb/gdb/stabsread.h
new file mode 100644
index 0000000..20859d6
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/stabsread.h
@@ -0,0 +1,212 @@
+/* Include file for stabs debugging format support functions.
+ Copyright 1986-1991, 1992, 1993 Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* Definitions, prototypes, etc for stabs debugging format support
+ functions.
+
+ Variables declared in this file can be defined by #define-ing
+ the name EXTERN to null. It is used to declare variables that
+ are normally extern, but which get defined in a single module
+ using this technique. */
+
+#ifndef EXTERN
+#define EXTERN extern
+#endif
+
+/* Convert stab register number (from `r' declaration) to a gdb REGNUM. */
+
+#ifndef STAB_REG_TO_REGNUM
+#define STAB_REG_TO_REGNUM(VALUE) (VALUE)
+#endif
+
+/* Hash table of global symbols whose values are not known yet.
+ They are chained thru the SYMBOL_VALUE_CHAIN, since we don't
+ have the correct data for that slot yet.
+
+ The use of the LOC_BLOCK code in this chain is nonstandard--
+ it refers to a FORTRAN common block rather than the usual meaning, and
+ the such LOC_BLOCK symbols use their fields in nonstandard ways. */
+
+EXTERN struct symbol *global_sym_chain[HASHSIZE];
+
+extern void common_block_start PARAMS ((char *, struct objfile *));
+extern void common_block_end PARAMS ((struct objfile *));
+
+/* Kludge for xcoffread.c */
+
+struct pending_stabs
+{
+ int count;
+ int length;
+ char *stab[1];
+};
+
+EXTERN struct pending_stabs *global_stabs;
+
+/* The type code that process_one_symbol saw on its previous invocation.
+ Used to detect pairs of N_SO symbols. */
+
+EXTERN int previous_stab_code;
+
+/* Support for Sun changes to dbx symbol format */
+
+/* For each identified header file, we have a table of types defined
+ in that header file.
+
+ header_files maps header file names to their type tables.
+ It is a vector of n_header_files elements.
+ Each element describes one header file.
+ It contains a vector of types.
+
+ Sometimes it can happen that the same header file produces
+ different results when included in different places.
+ This can result from conditionals or from different
+ things done before including the file.
+ When this happens, there are multiple entries for the file in this table,
+ one entry for each distinct set of results.
+ The entries are distinguished by the INSTANCE field.
+ The INSTANCE field appears in the N_BINCL and N_EXCL symbol table and is
+ used to match header-file references to their corresponding data. */
+
+struct header_file
+{
+
+ /* Name of header file */
+
+ char *name;
+
+ /* Numeric code distinguishing instances of one header file that produced
+ different results when included. It comes from the N_BINCL or N_EXCL. */
+
+ int instance;
+
+ /* Pointer to vector of types */
+
+ struct type **vector;
+
+ /* Allocated length (# elts) of that vector */
+
+ int length;
+
+};
+
+EXTERN struct header_file *header_files;
+
+EXTERN int n_header_files;
+
+EXTERN int n_allocated_header_files;
+
+/* Within each object file, various header files are assigned numbers.
+ A type is defined or referred to with a pair of numbers
+ (FILENUM,TYPENUM) where FILENUM is the number of the header file
+ and TYPENUM is the number within that header file.
+ TYPENUM is the index within the vector of types for that header file.
+
+ FILENUM == 1 is special; it refers to the main source of the object file,
+ and not to any header file. FILENUM != 1 is interpreted by looking it up
+ in the following table, which contains indices in header_files. */
+
+EXTERN int *this_object_header_files;
+
+EXTERN int n_this_object_header_files;
+
+EXTERN int n_allocated_this_object_header_files;
+
+extern struct complaint unknown_symtype_complaint;
+extern struct complaint unknown_symchar_complaint;
+
+extern struct type *
+read_type PARAMS ((char **, struct objfile *));
+
+extern void
+cleanup_undefined_types PARAMS ((void));
+
+extern struct type **
+dbx_lookup_type PARAMS ((int [2]));
+
+extern long
+read_number PARAMS ((char **, int));
+
+extern void
+add_undefined_type PARAMS ((struct type *));
+
+extern struct symbol *
+define_symbol PARAMS ((CORE_ADDR, char *, int, int, struct objfile *));
+
+extern void
+stabsread_init PARAMS ((void));
+
+extern void
+stabsread_new_init PARAMS ((void));
+
+extern void
+start_stabs PARAMS ((void));
+
+extern void
+end_stabs PARAMS ((void));
+
+extern void
+finish_global_stabs PARAMS ((struct objfile *objfile));
+
+EXTERN int os9k_stabs;
+
+/* Functions exported by dbxread.c. These are not in stabsread.h because
+ they are only used by some stabs readers. */
+
+extern struct partial_symtab *
+start_psymtab PARAMS ((struct objfile *, struct section_offsets *, char *,
+ CORE_ADDR, int, struct partial_symbol *,
+ struct partial_symbol *));
+
+extern struct partial_symtab *
+end_psymtab PARAMS ((struct partial_symtab *, char **, int, int, CORE_ADDR,
+ struct partial_symtab **, int));
+
+extern void
+process_one_symbol PARAMS ((int, int, CORE_ADDR, char *,
+ struct section_offsets *, struct objfile *));
+
+extern void elfstab_build_psymtabs
+ PARAMS ((struct objfile *objfile,
+ struct section_offsets *section_offsets,
+ int mainline,
+ file_ptr staboff, unsigned int stabsize,
+ file_ptr stabstroffset,
+ unsigned int stabstrsize));
+
+extern void coffstab_build_psymtabs
+ PARAMS ((struct objfile *objfile,
+ struct section_offsets *section_offsets,
+ int mainline,
+ file_ptr staboff, unsigned int stabsize,
+ file_ptr stabstroffset,
+ unsigned int stabstrsize));
+
+extern void stabsect_build_psymtabs
+ PARAMS ((struct objfile *objfile,
+ struct section_offsets *section_offsets,
+ int mainline,
+ char *stab_name,
+ char *stabstr_name,
+ char *text_name));
+
+extern void elfstab_offset_sections PARAMS ((struct objfile *,
+ struct partial_symtab *));
+
+#undef EXTERN
diff --git a/gnu/usr.bin/gdb/gdb/stack.c b/gnu/usr.bin/gdb/gdb/stack.c
new file mode 100644
index 0000000..6eb56e4
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/stack.c
@@ -0,0 +1,1482 @@
+/* Print and select stack frames for GDB, the GNU debugger.
+ Copyright 1986, 1987, 1989, 1991, 1992, 1993 Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "defs.h"
+#include "value.h"
+#include "symtab.h"
+#include "gdbtypes.h"
+#include "expression.h"
+#include "language.h"
+#include "frame.h"
+#include "gdbcmd.h"
+#include "gdbcore.h"
+#include "target.h"
+#include "breakpoint.h"
+#include "demangle.h"
+#include "inferior.h"
+#include "annotate.h"
+
+static void
+return_command PARAMS ((char *, int));
+
+static void
+down_command PARAMS ((char *, int));
+
+static void
+down_silently_command PARAMS ((char *, int));
+
+static void
+up_command PARAMS ((char *, int));
+
+static void
+up_silently_command PARAMS ((char *, int));
+
+static void
+frame_command PARAMS ((char *, int));
+
+static void
+select_frame_command PARAMS ((char *, int));
+
+static void
+args_info PARAMS ((char *, int));
+
+static void
+print_frame_arg_vars PARAMS ((FRAME, GDB_FILE *));
+
+static void
+catch_info PARAMS ((char *, int));
+
+static void
+locals_info PARAMS ((char *, int));
+
+static void
+print_frame_label_vars PARAMS ((FRAME, int, GDB_FILE *));
+
+static void
+print_frame_local_vars PARAMS ((FRAME, GDB_FILE *));
+
+static int
+print_block_frame_labels PARAMS ((struct block *, int *, GDB_FILE *));
+
+static int
+print_block_frame_locals PARAMS ((struct block *, FRAME, GDB_FILE *));
+
+static void
+backtrace_command PARAMS ((char *, int));
+
+static FRAME
+parse_frame_specification PARAMS ((char *));
+
+static void
+frame_info PARAMS ((char *, int));
+
+
+extern int addressprint; /* Print addresses, or stay symbolic only? */
+extern int info_verbose; /* Verbosity of symbol reading msgs */
+extern int lines_to_list; /* # of lines "list" command shows by default */
+
+/* The "selected" stack frame is used by default for local and arg access.
+ May be zero, for no selected frame. */
+
+FRAME selected_frame;
+
+/* Level of the selected frame:
+ 0 for innermost, 1 for its caller, ...
+ or -1 for frame specified by address with no defined level. */
+
+int selected_frame_level;
+
+/* Zero means do things normally; we are interacting directly with the
+ user. One means print the full filename and linenumber when a
+ frame is printed, and do so in a format emacs18/emacs19.22 can
+ parse. Two means print similar annotations, but in many more
+ cases and in a slightly different syntax. */
+
+int annotation_level = 0;
+
+
+struct print_stack_frame_args {
+ struct frame_info *fi;
+ int level;
+ int source;
+ int args;
+};
+
+static int print_stack_frame_stub PARAMS ((char *));
+
+/* Pass the args the way catch_errors wants them. */
+static int
+print_stack_frame_stub (args)
+ char *args;
+{
+ struct print_stack_frame_args *p = (struct print_stack_frame_args *)args;
+ print_frame_info (p->fi, p->level, p->source, p->args);
+ return 0;
+}
+
+/* Print a stack frame briefly. FRAME should be the frame id
+ and LEVEL should be its level in the stack (or -1 for level not defined).
+ This prints the level, the function executing, the arguments,
+ and the file name and line number.
+ If the pc is not at the beginning of the source line,
+ the actual pc is printed at the beginning.
+
+ If SOURCE is 1, print the source line as well.
+ If SOURCE is -1, print ONLY the source line. */
+
+void
+print_stack_frame (frame, level, source)
+ FRAME frame;
+ int level;
+ int source;
+{
+ struct print_stack_frame_args args;
+
+ args.fi = get_frame_info (frame);
+ args.level = level;
+ args.source = source;
+ args.args = 1;
+
+ catch_errors (print_stack_frame_stub, (char *)&args, "", RETURN_MASK_ERROR);
+}
+
+struct print_args_args {
+ struct symbol *func;
+ struct frame_info *fi;
+};
+
+static int print_args_stub PARAMS ((char *));
+
+/* Pass the args the way catch_errors wants them. */
+static int
+print_args_stub (args)
+ char *args;
+{
+ int numargs;
+ struct print_args_args *p = (struct print_args_args *)args;
+ FRAME_NUM_ARGS (numargs, (p->fi));
+ print_frame_args (p->func, p->fi, numargs, gdb_stdout);
+ return 0;
+}
+
+/* LEVEL is the level of the frame, or -1 if it is the innermost frame
+ but we don't want to print the level. */
+void
+print_frame_info (fi, level, source, args)
+ struct frame_info *fi;
+ register int level;
+ int source;
+ int args;
+{
+ struct symtab_and_line sal;
+ struct symbol *func;
+ register char *funname = 0;
+ enum language funlang = language_unknown;
+
+#if 0
+ char buf[MAX_REGISTER_RAW_SIZE];
+ CORE_ADDR sp;
+
+ /* On the 68k, this spends too much time in m68k_find_saved_regs. */
+
+ /* Get the value of SP_REGNUM relative to the frame. */
+ get_saved_register (buf, (int *)NULL, (CORE_ADDR *)NULL,
+ FRAME_INFO_ID (fi), SP_REGNUM, (enum lval_type *)NULL);
+ sp = extract_address (buf, REGISTER_RAW_SIZE (SP_REGNUM));
+
+ /* This is not a perfect test, because if a function alloca's some
+ memory, puts some code there, and then jumps into it, then the test
+ will succeed even though there is no call dummy. Probably best is
+ to check for a bp_call_dummy breakpoint. */
+ if (PC_IN_CALL_DUMMY (fi->pc, sp, fi->frame))
+#else
+ if (frame_in_dummy (fi))
+#endif
+ {
+ annotate_frame_begin (level == -1 ? 0 : level, fi->pc);
+
+ /* Do this regardless of SOURCE because we don't have any source
+ to list for this frame. */
+ if (level >= 0)
+ printf_filtered ("#%-2d ", level);
+ annotate_function_call ();
+ printf_filtered ("<function called from gdb>\n");
+ annotate_frame_end ();
+ return;
+ }
+ if (fi->signal_handler_caller)
+ {
+ annotate_frame_begin (level == -1 ? 0 : level, fi->pc);
+
+ /* Do this regardless of SOURCE because we don't have any source
+ to list for this frame. */
+ if (level >= 0)
+ printf_filtered ("#%-2d ", level);
+ annotate_signal_handler_caller ();
+ printf_filtered ("<signal handler called>\n");
+ annotate_frame_end ();
+ return;
+ }
+
+ /* If fi is not the innermost frame, that normally means that fi->pc
+ points to *after* the call instruction, and we want to get the line
+ containing the call, never the next line. But if the next frame is
+ a signal_handler_caller or a dummy frame, then the next frame was
+ not entered as the result of a call, and we want to get the line
+ containing fi->pc. */
+ sal =
+ find_pc_line (fi->pc,
+ fi->next != NULL
+ && !fi->next->signal_handler_caller
+ && !frame_in_dummy (fi->next));
+
+ func = find_pc_function (fi->pc);
+ if (func)
+ {
+ /* In certain pathological cases, the symtabs give the wrong
+ function (when we are in the first function in a file which
+ is compiled without debugging symbols, the previous function
+ is compiled with debugging symbols, and the "foo.o" symbol
+ that is supposed to tell us where the file with debugging symbols
+ ends has been truncated by ar because it is longer than 15
+ characters). This also occurs if the user uses asm() to create
+ a function but not stabs for it (in a file compiled -g).
+
+ So look in the minimal symbol tables as well, and if it comes
+ up with a larger address for the function use that instead.
+ I don't think this can ever cause any problems; there shouldn't
+ be any minimal symbols in the middle of a function; if this is
+ ever changed many parts of GDB will need to be changed (and we'll
+ create a find_pc_minimal_function or some such). */
+
+ struct minimal_symbol *msymbol = lookup_minimal_symbol_by_pc (fi->pc);
+ if (msymbol != NULL
+ && (SYMBOL_VALUE_ADDRESS (msymbol)
+ > BLOCK_START (SYMBOL_BLOCK_VALUE (func))))
+ {
+#if 0
+ /* There is no particular reason to think the line number
+ information is wrong. Someone might have just put in
+ a label with asm() but left the line numbers alone. */
+ /* In this case we have no way of knowing the source file
+ and line number, so don't print them. */
+ sal.symtab = 0;
+#endif
+ /* We also don't know anything about the function besides
+ its address and name. */
+ func = 0;
+ funname = SYMBOL_NAME (msymbol);
+ funlang = SYMBOL_LANGUAGE (msymbol);
+ }
+ else
+ {
+ funname = SYMBOL_NAME (func);
+ funlang = SYMBOL_LANGUAGE (func);
+ }
+ }
+ else
+ {
+ register struct minimal_symbol *msymbol = lookup_minimal_symbol_by_pc (fi->pc);
+ if (msymbol != NULL)
+ {
+ funname = SYMBOL_NAME (msymbol);
+ funlang = SYMBOL_LANGUAGE (msymbol);
+ }
+ }
+
+ if (source >= 0 || !sal.symtab)
+ {
+ annotate_frame_begin (level == -1 ? 0 : level, fi->pc);
+
+ if (level >= 0)
+ printf_filtered ("#%-2d ", level);
+ if (addressprint)
+ if (fi->pc != sal.pc || !sal.symtab)
+ {
+ annotate_frame_address ();
+ print_address_numeric (fi->pc, 1, gdb_stdout);
+ annotate_frame_address_end ();
+ printf_filtered (" in ");
+ }
+ annotate_frame_function_name ();
+ fprintf_symbol_filtered (gdb_stdout, funname ? funname : "??", funlang,
+ DMGL_ANSI);
+ wrap_here (" ");
+ annotate_frame_args ();
+ fputs_filtered (" (", gdb_stdout);
+ if (args)
+ {
+ struct print_args_args args;
+ args.fi = fi;
+ args.func = func;
+ catch_errors (print_args_stub, (char *)&args, "", RETURN_MASK_ERROR);
+ }
+ printf_filtered (")");
+ if (sal.symtab && sal.symtab->filename)
+ {
+ annotate_frame_source_begin ();
+ wrap_here (" ");
+ printf_filtered (" at ");
+ annotate_frame_source_file ();
+ printf_filtered ("%s", sal.symtab->filename);
+ annotate_frame_source_file_end ();
+ printf_filtered (":");
+ annotate_frame_source_line ();
+ printf_filtered ("%d", sal.line);
+ annotate_frame_source_end ();
+ }
+
+#ifdef PC_LOAD_SEGMENT
+ /* If we couldn't print out function name but if can figure out what
+ load segment this pc value is from, at least print out some info
+ about its load segment. */
+ if (!funname)
+ {
+ annotate_frame_where ();
+ wrap_here (" ");
+ printf_filtered (" from %s", PC_LOAD_SEGMENT (fi->pc));
+ }
+#endif
+ printf_filtered ("\n");
+ }
+
+ if ((source != 0) && sal.symtab)
+ {
+ int done = 0;
+ int mid_statement = source < 0 && fi->pc != sal.pc;
+ if (annotation_level)
+ done = identify_source_line (sal.symtab, sal.line, mid_statement,
+ fi->pc);
+ if (!done)
+ {
+ if (addressprint && mid_statement)
+ {
+ print_address_numeric (fi->pc, 1, gdb_stdout);
+ printf_filtered ("\t");
+ }
+ print_source_lines (sal.symtab, sal.line, sal.line + 1, 0);
+ }
+ current_source_line = max (sal.line - lines_to_list/2, 1);
+ }
+ if (source != 0)
+ set_default_breakpoint (1, fi->pc, sal.symtab, sal.line);
+
+ annotate_frame_end ();
+
+ gdb_flush (gdb_stdout);
+}
+
+/*
+ * Read a frame specification in whatever the appropriate format is.
+ * Call error() if the specification is in any way invalid (i.e.
+ * this function never returns NULL).
+ */
+static FRAME
+parse_frame_specification (frame_exp)
+ char *frame_exp;
+{
+ int numargs = 0;
+#define MAXARGS 4
+ CORE_ADDR args[MAXARGS];
+
+ if (frame_exp)
+ {
+ char *addr_string, *p;
+ struct cleanup *tmp_cleanup;
+
+ while (*frame_exp == ' ') frame_exp++;
+
+ while (*frame_exp)
+ {
+ if (numargs > MAXARGS)
+ error ("Too many args in frame specification");
+ /* Parse an argument. */
+ for (p = frame_exp; *p && *p != ' '; p++)
+ ;
+ addr_string = savestring(frame_exp, p - frame_exp);
+
+ {
+ tmp_cleanup = make_cleanup (free, addr_string);
+ args[numargs++] = parse_and_eval_address (addr_string);
+ do_cleanups (tmp_cleanup);
+ }
+
+ /* Skip spaces, move to possible next arg. */
+ while (*p == ' ') p++;
+ frame_exp = p;
+ }
+ }
+
+ switch (numargs)
+ {
+ case 0:
+ if (selected_frame == NULL)
+ error ("No selected frame.");
+ return selected_frame;
+ /* NOTREACHED */
+ case 1:
+ {
+ int level = args[0];
+ FRAME fid = find_relative_frame (get_current_frame (), &level);
+ FRAME tfid;
+
+ if (level == 0)
+ /* find_relative_frame was successful */
+ return fid;
+
+ /* If SETUP_ARBITRARY_FRAME is defined, then frame specifications
+ take at least 2 addresses. It is important to detect this case
+ here so that "frame 100" does not give a confusing error message
+ like "frame specification requires two addresses". This of course
+ does not solve the "frame 100" problem for machines on which
+ a frame specification can be made with one address. To solve
+ that, we need a new syntax for a specifying a frame by address.
+ I think the cleanest syntax is $frame(0x45) ($frame(0x23,0x45) for
+ two args, etc.), but people might think that is too much typing,
+ so I guess *0x23,0x45 would be a possible alternative (commas
+ really should be used instead of spaces to delimit; using spaces
+ normally works in an expression). */
+#ifdef SETUP_ARBITRARY_FRAME
+ error ("No frame %d", args[0]);
+#endif
+
+ /* If (s)he specifies the frame with an address, he deserves what
+ (s)he gets. Still, give the highest one that matches. */
+
+ for (fid = get_current_frame ();
+ fid && FRAME_FP (fid) != args[0];
+ fid = get_prev_frame (fid))
+ ;
+
+ if (fid)
+ while ((tfid = get_prev_frame (fid)) &&
+ (FRAME_FP (tfid) == args[0]))
+ fid = tfid;
+
+ /* We couldn't identify the frame as an existing frame, but
+ perhaps we can create one with a single argument. */
+ }
+
+ default:
+#ifdef SETUP_ARBITRARY_FRAME
+ return SETUP_ARBITRARY_FRAME (numargs, args);
+#else
+ /* Usual case. Do it here rather than have everyone supply
+ a SETUP_ARBITRARY_FRAME that does this. */
+ if (numargs == 1)
+ return create_new_frame (args[0], 0);
+ error ("Too many args in frame specification");
+#endif
+ /* NOTREACHED */
+ }
+ /* NOTREACHED */
+}
+
+/* FRAME_ARGS_ADDRESS_CORRECT is just like FRAME_ARGS_ADDRESS except
+ that if it is unsure about the answer, it returns 0
+ instead of guessing (this happens on the VAX and i960, for example).
+
+ On most machines, we never have to guess about the args address,
+ so FRAME_ARGS_ADDRESS{,_CORRECT} are the same. */
+#if !defined (FRAME_ARGS_ADDRESS_CORRECT)
+#define FRAME_ARGS_ADDRESS_CORRECT FRAME_ARGS_ADDRESS
+#endif
+
+/* Print verbosely the selected frame or the frame at address ADDR.
+ This means absolutely all information in the frame is printed. */
+
+static void
+frame_info (addr_exp, from_tty)
+ char *addr_exp;
+ int from_tty;
+{
+ FRAME frame;
+ struct frame_info *fi;
+ struct frame_saved_regs fsr;
+ struct symtab_and_line sal;
+ struct symbol *func;
+ struct symtab *s;
+ FRAME calling_frame;
+ int i, count, numregs;
+ char *funname = 0;
+ enum language funlang = language_unknown;
+
+ if (!target_has_stack)
+ error ("No stack.");
+
+ frame = parse_frame_specification (addr_exp);
+ if (!frame)
+ error ("Invalid frame specified.");
+
+ fi = get_frame_info (frame);
+ sal = find_pc_line (fi->pc,
+ fi->next != NULL
+ && !fi->next->signal_handler_caller
+ && !frame_in_dummy (fi->next));
+ func = get_frame_function (frame);
+ s = find_pc_symtab(fi->pc);
+ if (func)
+ {
+ funname = SYMBOL_NAME (func);
+ funlang = SYMBOL_LANGUAGE (func);
+ }
+ else
+ {
+ register struct minimal_symbol *msymbol = lookup_minimal_symbol_by_pc (fi->pc);
+ if (msymbol != NULL)
+ {
+ funname = SYMBOL_NAME (msymbol);
+ funlang = SYMBOL_LANGUAGE (msymbol);
+ }
+ }
+ calling_frame = get_prev_frame (frame);
+
+ if (!addr_exp && selected_frame_level >= 0)
+ {
+ printf_filtered ("Stack level %d, frame at ", selected_frame_level);
+ print_address_numeric (FRAME_FP(frame), 1, gdb_stdout);
+ printf_filtered (":\n");
+ }
+ else
+ {
+ printf_filtered ("Stack frame at ");
+ print_address_numeric (FRAME_FP(frame), 1, gdb_stdout);
+ printf_filtered (":\n");
+ }
+ printf_filtered (" %s = ",
+ reg_names[PC_REGNUM]);
+ print_address_numeric (fi->pc, 1, gdb_stdout);
+
+ wrap_here (" ");
+ if (funname)
+ {
+ printf_filtered (" in ");
+ fprintf_symbol_filtered (gdb_stdout, funname, funlang,
+ DMGL_ANSI | DMGL_PARAMS);
+ }
+ wrap_here (" ");
+ if (sal.symtab)
+ printf_filtered (" (%s:%d)", sal.symtab->filename, sal.line);
+ puts_filtered ("; ");
+ wrap_here (" ");
+ printf_filtered ("saved %s ", reg_names[PC_REGNUM]);
+ print_address_numeric (FRAME_SAVED_PC (frame), 1, gdb_stdout);
+ printf_filtered ("\n");
+
+ {
+ int frameless = 0;
+#ifdef FRAMELESS_FUNCTION_INVOCATION
+ FRAMELESS_FUNCTION_INVOCATION (fi, frameless);
+#endif
+ if (frameless)
+ printf_filtered (" (FRAMELESS),");
+ }
+
+ if (calling_frame)
+ {
+ printf_filtered (" called by frame at ");
+ print_address_numeric (FRAME_FP (calling_frame), 1, gdb_stdout);
+ }
+ if (fi->next && calling_frame)
+ puts_filtered (",");
+ wrap_here (" ");
+ if (fi->next)
+ {
+ printf_filtered (" caller of frame at ");
+ print_address_numeric (fi->next->frame, 1, gdb_stdout);
+ }
+ if (fi->next || calling_frame)
+ puts_filtered ("\n");
+ if (s)
+ printf_filtered (" source language %s.\n", language_str (s->language));
+
+#ifdef PRINT_EXTRA_FRAME_INFO
+ PRINT_EXTRA_FRAME_INFO (fi);
+#endif
+
+ {
+ /* Address of the argument list for this frame, or 0. */
+ CORE_ADDR arg_list = FRAME_ARGS_ADDRESS_CORRECT (fi);
+ /* Number of args for this frame, or -1 if unknown. */
+ int numargs;
+
+ if (arg_list == 0)
+ printf_filtered (" Arglist at unknown address.\n");
+ else
+ {
+ printf_filtered (" Arglist at ");
+ print_address_numeric (arg_list, 1, gdb_stdout);
+ printf_filtered (",");
+
+ FRAME_NUM_ARGS (numargs, fi);
+ if (numargs < 0)
+ puts_filtered (" args: ");
+ else if (numargs == 0)
+ puts_filtered (" no args.");
+ else if (numargs == 1)
+ puts_filtered (" 1 arg: ");
+ else
+ printf_filtered (" %d args: ", numargs);
+ print_frame_args (func, fi, numargs, gdb_stdout);
+ puts_filtered ("\n");
+ }
+ }
+ {
+ /* Address of the local variables for this frame, or 0. */
+ CORE_ADDR arg_list = FRAME_LOCALS_ADDRESS (fi);
+
+ if (arg_list == 0)
+ printf_filtered (" Locals at unknown address,");
+ else
+ {
+ printf_filtered (" Locals at ");
+ print_address_numeric (arg_list, 1, gdb_stdout);
+ printf_filtered (",");
+ }
+ }
+
+#if defined (FRAME_FIND_SAVED_REGS)
+ get_frame_saved_regs (fi, &fsr);
+ /* The sp is special; what's returned isn't the save address, but
+ actually the value of the previous frame's sp. */
+ printf_filtered (" Previous frame's sp is ");
+ print_address_numeric (fsr.regs[SP_REGNUM], 1, gdb_stdout);
+ printf_filtered ("\n");
+ count = 0;
+ numregs = ARCH_NUM_REGS;
+ for (i = 0; i < numregs; i++)
+ if (fsr.regs[i] && i != SP_REGNUM)
+ {
+ if (count == 0)
+ puts_filtered (" Saved registers:\n ");
+ else
+ puts_filtered (",");
+ wrap_here (" ");
+ printf_filtered (" %s at ", reg_names[i]);
+ print_address_numeric (fsr.regs[i], 1, gdb_stdout);
+ count++;
+ }
+ if (count)
+ puts_filtered ("\n");
+#else /* Have FRAME_FIND_SAVED_REGS. */
+ puts_filtered ("\n");
+#endif /* Have FRAME_FIND_SAVED_REGS. */
+}
+
+#if 0
+/* Set a limit on the number of frames printed by default in a
+ backtrace. */
+
+static int backtrace_limit;
+
+static void
+set_backtrace_limit_command (count_exp, from_tty)
+ char *count_exp;
+ int from_tty;
+{
+ int count = parse_and_eval_address (count_exp);
+
+ if (count < 0)
+ error ("Negative argument not meaningful as backtrace limit.");
+
+ backtrace_limit = count;
+}
+
+static void
+backtrace_limit_info (arg, from_tty)
+ char *arg;
+ int from_tty;
+{
+ if (arg)
+ error ("\"Info backtrace-limit\" takes no arguments.");
+
+ printf_unfiltered ("Backtrace limit: %d.\n", backtrace_limit);
+}
+#endif
+
+/* Print briefly all stack frames or just the innermost COUNT frames. */
+
+static void
+backtrace_command (count_exp, from_tty)
+ char *count_exp;
+ int from_tty;
+{
+ struct frame_info *fi;
+ register int count;
+ register FRAME frame;
+ register int i;
+ register FRAME trailing;
+ register int trailing_level;
+
+ if (!target_has_stack)
+ error ("No stack.");
+
+ /* The following code must do two things. First, it must
+ set the variable TRAILING to the frame from which we should start
+ printing. Second, it must set the variable count to the number
+ of frames which we should print, or -1 if all of them. */
+ trailing = get_current_frame ();
+ trailing_level = 0;
+ if (count_exp)
+ {
+ count = parse_and_eval_address (count_exp);
+ if (count < 0)
+ {
+ FRAME current;
+
+ count = -count;
+
+ current = trailing;
+ while (current && count--)
+ {
+ QUIT;
+ current = get_prev_frame (current);
+ }
+
+ /* Will stop when CURRENT reaches the top of the stack. TRAILING
+ will be COUNT below it. */
+ while (current)
+ {
+ QUIT;
+ trailing = get_prev_frame (trailing);
+ current = get_prev_frame (current);
+ trailing_level++;
+ }
+
+ count = -1;
+ }
+ }
+ else
+ count = -1;
+
+ if (info_verbose)
+ {
+ struct partial_symtab *ps;
+
+ /* Read in symbols for all of the frames. Need to do this in
+ a separate pass so that "Reading in symbols for xxx" messages
+ don't screw up the appearance of the backtrace. Also
+ if people have strong opinions against reading symbols for
+ backtrace this may have to be an option. */
+ i = count;
+ for (frame = trailing;
+ frame != NULL && i--;
+ frame = get_prev_frame (frame))
+ {
+ QUIT;
+ fi = get_frame_info (frame);
+ ps = find_pc_psymtab (fi->pc);
+ if (ps)
+ PSYMTAB_TO_SYMTAB (ps); /* Force syms to come in */
+ }
+ }
+
+ for (i = 0, frame = trailing;
+ frame && count--;
+ i++, frame = get_prev_frame (frame))
+ {
+ QUIT;
+ fi = get_frame_info (frame);
+
+ /* Don't use print_stack_frame; if an error() occurs it probably
+ means further attempts to backtrace would fail (on the other
+ hand, perhaps the code does or could be fixed to make sure
+ the frame->prev field gets set to NULL in that case). */
+ print_frame_info (fi, trailing_level + i, 0, 1);
+ }
+
+ /* If we've stopped before the end, mention that. */
+ if (frame && from_tty)
+ printf_filtered ("(More stack frames follow...)\n");
+}
+
+/* Print the local variables of a block B active in FRAME.
+ Return 1 if any variables were printed; 0 otherwise. */
+
+static int
+print_block_frame_locals (b, frame, stream)
+ struct block *b;
+ register FRAME frame;
+ register GDB_FILE *stream;
+{
+ int nsyms;
+ register int i;
+ register struct symbol *sym;
+ register int values_printed = 0;
+
+ nsyms = BLOCK_NSYMS (b);
+
+ for (i = 0; i < nsyms; i++)
+ {
+ sym = BLOCK_SYM (b, i);
+ switch (SYMBOL_CLASS (sym))
+ {
+ case LOC_LOCAL:
+ case LOC_REGISTER:
+ case LOC_STATIC:
+ case LOC_BASEREG:
+ values_printed = 1;
+ fputs_filtered (SYMBOL_SOURCE_NAME (sym), stream);
+ fputs_filtered (" = ", stream);
+ print_variable_value (sym, frame, stream);
+ fprintf_filtered (stream, "\n");
+ break;
+
+ default:
+ /* Ignore symbols which are not locals. */
+ break;
+ }
+ }
+ return values_printed;
+}
+
+/* Same, but print labels. */
+
+static int
+print_block_frame_labels (b, have_default, stream)
+ struct block *b;
+ int *have_default;
+ register GDB_FILE *stream;
+{
+ int nsyms;
+ register int i;
+ register struct symbol *sym;
+ register int values_printed = 0;
+
+ nsyms = BLOCK_NSYMS (b);
+
+ for (i = 0; i < nsyms; i++)
+ {
+ sym = BLOCK_SYM (b, i);
+ if (STREQ (SYMBOL_NAME (sym), "default"))
+ {
+ if (*have_default)
+ continue;
+ *have_default = 1;
+ }
+ if (SYMBOL_CLASS (sym) == LOC_LABEL)
+ {
+ struct symtab_and_line sal;
+ sal = find_pc_line (SYMBOL_VALUE_ADDRESS (sym), 0);
+ values_printed = 1;
+ fputs_filtered (SYMBOL_SOURCE_NAME (sym), stream);
+ if (addressprint)
+ {
+ fprintf_filtered (stream, " ");
+ print_address_numeric (SYMBOL_VALUE_ADDRESS (sym), 1, stream);
+ }
+ fprintf_filtered (stream, " in file %s, line %d\n",
+ sal.symtab->filename, sal.line);
+ }
+ }
+ return values_printed;
+}
+
+/* Print on STREAM all the local variables in frame FRAME,
+ including all the blocks active in that frame
+ at its current pc.
+
+ Returns 1 if the job was done,
+ or 0 if nothing was printed because we have no info
+ on the function running in FRAME. */
+
+static void
+print_frame_local_vars (frame, stream)
+ register FRAME frame;
+ register GDB_FILE *stream;
+{
+ register struct block *block = get_frame_block (frame);
+ register int values_printed = 0;
+
+ if (block == 0)
+ {
+ fprintf_filtered (stream, "No symbol table info available.\n");
+ return;
+ }
+
+ while (block != 0)
+ {
+ if (print_block_frame_locals (block, frame, stream))
+ values_printed = 1;
+ /* After handling the function's top-level block, stop.
+ Don't continue to its superblock, the block of
+ per-file symbols. */
+ if (BLOCK_FUNCTION (block))
+ break;
+ block = BLOCK_SUPERBLOCK (block);
+ }
+
+ if (!values_printed)
+ {
+ fprintf_filtered (stream, "No locals.\n");
+ }
+}
+
+/* Same, but print labels. */
+
+static void
+print_frame_label_vars (frame, this_level_only, stream)
+ register FRAME frame;
+ int this_level_only;
+ register GDB_FILE *stream;
+{
+ register struct blockvector *bl;
+ register struct block *block = get_frame_block (frame);
+ register int values_printed = 0;
+ int index, have_default = 0;
+ char *blocks_printed;
+ struct frame_info *fi = get_frame_info (frame);
+ CORE_ADDR pc = fi->pc;
+
+ if (block == 0)
+ {
+ fprintf_filtered (stream, "No symbol table info available.\n");
+ return;
+ }
+
+ bl = blockvector_for_pc (BLOCK_END (block) - 4, &index);
+ blocks_printed = (char *) alloca (BLOCKVECTOR_NBLOCKS (bl) * sizeof (char));
+ memset (blocks_printed, 0, BLOCKVECTOR_NBLOCKS (bl) * sizeof (char));
+
+ while (block != 0)
+ {
+ CORE_ADDR end = BLOCK_END (block) - 4;
+ int last_index;
+
+ if (bl != blockvector_for_pc (end, &index))
+ error ("blockvector blotch");
+ if (BLOCKVECTOR_BLOCK (bl, index) != block)
+ error ("blockvector botch");
+ last_index = BLOCKVECTOR_NBLOCKS (bl);
+ index += 1;
+
+ /* Don't print out blocks that have gone by. */
+ while (index < last_index
+ && BLOCK_END (BLOCKVECTOR_BLOCK (bl, index)) < pc)
+ index++;
+
+ while (index < last_index
+ && BLOCK_END (BLOCKVECTOR_BLOCK (bl, index)) < end)
+ {
+ if (blocks_printed[index] == 0)
+ {
+ if (print_block_frame_labels (BLOCKVECTOR_BLOCK (bl, index), &have_default, stream))
+ values_printed = 1;
+ blocks_printed[index] = 1;
+ }
+ index++;
+ }
+ if (have_default)
+ return;
+ if (values_printed && this_level_only)
+ return;
+
+ /* After handling the function's top-level block, stop.
+ Don't continue to its superblock, the block of
+ per-file symbols. */
+ if (BLOCK_FUNCTION (block))
+ break;
+ block = BLOCK_SUPERBLOCK (block);
+ }
+
+ if (!values_printed && !this_level_only)
+ {
+ fprintf_filtered (stream, "No catches.\n");
+ }
+}
+
+/* ARGSUSED */
+static void
+locals_info (args, from_tty)
+ char *args;
+ int from_tty;
+{
+ if (!selected_frame)
+ error ("No frame selected.");
+ print_frame_local_vars (selected_frame, gdb_stdout);
+}
+
+static void
+catch_info (ignore, from_tty)
+ char *ignore;
+ int from_tty;
+{
+ if (!selected_frame)
+ error ("No frame selected.");
+ print_frame_label_vars (selected_frame, 0, gdb_stdout);
+}
+
+static void
+print_frame_arg_vars (frame, stream)
+ register FRAME frame;
+ register GDB_FILE *stream;
+{
+ struct symbol *func = get_frame_function (frame);
+ register struct block *b;
+ int nsyms;
+ register int i;
+ register struct symbol *sym, *sym2;
+ register int values_printed = 0;
+
+ if (func == 0)
+ {
+ fprintf_filtered (stream, "No symbol table info available.\n");
+ return;
+ }
+
+ b = SYMBOL_BLOCK_VALUE (func);
+ nsyms = BLOCK_NSYMS (b);
+
+ for (i = 0; i < nsyms; i++)
+ {
+ sym = BLOCK_SYM (b, i);
+ switch (SYMBOL_CLASS (sym))
+ {
+ case LOC_ARG:
+ case LOC_LOCAL_ARG:
+ case LOC_REF_ARG:
+ case LOC_REGPARM:
+ case LOC_REGPARM_ADDR:
+ case LOC_BASEREG_ARG:
+ values_printed = 1;
+ fputs_filtered (SYMBOL_SOURCE_NAME (sym), stream);
+ fputs_filtered (" = ", stream);
+
+ /* We have to look up the symbol because arguments can have
+ two entries (one a parameter, one a local) and the one we
+ want is the local, which lookup_symbol will find for us.
+ This includes gcc1 (not gcc2) on the sparc when passing a
+ small structure and gcc2 when the argument type is float
+ and it is passed as a double and converted to float by
+ the prologue (in the latter case the type of the LOC_ARG
+ symbol is double and the type of the LOC_LOCAL symbol is
+ float). There are also LOC_ARG/LOC_REGISTER pairs which
+ are not combined in symbol-reading. */
+
+ sym2 = lookup_symbol (SYMBOL_NAME (sym),
+ b, VAR_NAMESPACE, (int *)NULL, (struct symtab **)NULL);
+ print_variable_value (sym2, frame, stream);
+ fprintf_filtered (stream, "\n");
+ break;
+
+ default:
+ /* Don't worry about things which aren't arguments. */
+ break;
+ }
+ }
+
+ if (!values_printed)
+ {
+ fprintf_filtered (stream, "No arguments.\n");
+ }
+}
+
+static void
+args_info (ignore, from_tty)
+ char *ignore;
+ int from_tty;
+{
+ if (!selected_frame)
+ error ("No frame selected.");
+ print_frame_arg_vars (selected_frame, gdb_stdout);
+}
+
+/* Select frame FRAME, and note that its stack level is LEVEL.
+ LEVEL may be -1 if an actual level number is not known. */
+
+void
+select_frame (frame, level)
+ FRAME frame;
+ int level;
+{
+ register struct symtab *s;
+
+ selected_frame = frame;
+ selected_frame_level = level;
+
+ /* Ensure that symbols for this frame are read in. Also, determine the
+ source language of this frame, and switch to it if desired. */
+ if (frame)
+ {
+ s = find_pc_symtab (get_frame_info (frame)->pc);
+ if (s
+ && s->language != current_language->la_language
+ && s->language != language_unknown
+ && language_mode == language_mode_auto) {
+ set_language(s->language);
+ }
+ }
+}
+
+/* Store the selected frame and its level into *FRAMEP and *LEVELP.
+ If there is no selected frame, *FRAMEP is set to NULL. */
+
+void
+record_selected_frame (frameaddrp, levelp)
+ FRAME_ADDR *frameaddrp;
+ int *levelp;
+{
+ *frameaddrp = selected_frame ? FRAME_FP (selected_frame) : 0;
+ *levelp = selected_frame_level;
+}
+
+/* Return the symbol-block in which the selected frame is executing.
+ Can return zero under various legitimate circumstances. */
+
+struct block *
+get_selected_block ()
+{
+ if (!target_has_stack)
+ return 0;
+
+ if (!selected_frame)
+ return get_current_block ();
+ return get_frame_block (selected_frame);
+}
+
+/* Find a frame a certain number of levels away from FRAME.
+ LEVEL_OFFSET_PTR points to an int containing the number of levels.
+ Positive means go to earlier frames (up); negative, the reverse.
+ The int that contains the number of levels is counted toward
+ zero as the frames for those levels are found.
+ If the top or bottom frame is reached, that frame is returned,
+ but the final value of *LEVEL_OFFSET_PTR is nonzero and indicates
+ how much farther the original request asked to go. */
+
+FRAME
+find_relative_frame (frame, level_offset_ptr)
+ register FRAME frame;
+ register int* level_offset_ptr;
+{
+ register FRAME prev;
+ register FRAME frame1;
+
+ /* Going up is simple: just do get_prev_frame enough times
+ or until initial frame is reached. */
+ while (*level_offset_ptr > 0)
+ {
+ prev = get_prev_frame (frame);
+ if (prev == 0)
+ break;
+ (*level_offset_ptr)--;
+ frame = prev;
+ }
+ /* Going down is just as simple. */
+ if (*level_offset_ptr < 0)
+ {
+ while (*level_offset_ptr < 0) {
+ frame1 = get_next_frame (frame);
+ if (!frame1)
+ break;
+ frame = frame1;
+ (*level_offset_ptr)++;
+ }
+ }
+ return frame;
+}
+
+/* The "select_frame" command. With no arg, NOP.
+ With arg LEVEL_EXP, select the frame at level LEVEL if it is a
+ valid level. Otherwise, treat level_exp as an address expression
+ and select it. See parse_frame_specification for more info on proper
+ frame expressions. */
+
+/* ARGSUSED */
+static void
+select_frame_command (level_exp, from_tty)
+ char *level_exp;
+ int from_tty;
+{
+ register FRAME frame, frame1;
+ unsigned int level = 0;
+
+ if (!target_has_stack)
+ error ("No stack.");
+
+ frame = parse_frame_specification (level_exp);
+
+ /* Try to figure out what level this frame is. But if there is
+ no current stack, don't error out -- let the user set one. */
+ frame1 = 0;
+ if (get_current_frame()) {
+ for (frame1 = get_prev_frame (0);
+ frame1 && frame1 != frame;
+ frame1 = get_prev_frame (frame1))
+ level++;
+ }
+
+ if (!frame1)
+ level = 0;
+
+ select_frame (frame, level);
+}
+
+/* The "frame" command. With no arg, print selected frame briefly.
+ With arg, behaves like select_frame and then prints the selected
+ frame. */
+
+static void
+frame_command (level_exp, from_tty)
+ char *level_exp;
+ int from_tty;
+{
+ select_frame_command (level_exp, from_tty);
+ print_stack_frame (selected_frame, selected_frame_level, 1);
+}
+
+/* Select the frame up one or COUNT stack levels
+ from the previously selected frame, and print it briefly. */
+
+/* ARGSUSED */
+static void
+up_silently_command (count_exp, from_tty)
+ char *count_exp;
+ int from_tty;
+{
+ register FRAME frame;
+ int count = 1, count1;
+ if (count_exp)
+ count = parse_and_eval_address (count_exp);
+ count1 = count;
+
+ if (target_has_stack == 0 || selected_frame == 0)
+ error ("No stack.");
+
+ frame = find_relative_frame (selected_frame, &count1);
+ if (count1 != 0 && count_exp == 0)
+ error ("Initial frame selected; you cannot go up.");
+ select_frame (frame, selected_frame_level + count - count1);
+}
+
+static void
+up_command (count_exp, from_tty)
+ char *count_exp;
+ int from_tty;
+{
+ up_silently_command (count_exp, from_tty);
+ print_stack_frame (selected_frame, selected_frame_level, 1);
+}
+
+/* Select the frame down one or COUNT stack levels
+ from the previously selected frame, and print it briefly. */
+
+/* ARGSUSED */
+static void
+down_silently_command (count_exp, from_tty)
+ char *count_exp;
+ int from_tty;
+{
+ register FRAME frame;
+ int count = -1, count1;
+ if (count_exp)
+ count = - parse_and_eval_address (count_exp);
+ count1 = count;
+
+ if (target_has_stack == 0 || selected_frame == 0)
+ error ("No stack.");
+
+ frame = find_relative_frame (selected_frame, &count1);
+ if (count1 != 0 && count_exp == 0)
+ {
+
+ /* We only do this if count_exp is not specified. That way "down"
+ means to really go down (and let me know if that is
+ impossible), but "down 9999" can be used to mean go all the way
+ down without getting an error. */
+
+ error ("Bottom (i.e., innermost) frame selected; you cannot go down.");
+ }
+
+ select_frame (frame, selected_frame_level + count - count1);
+}
+
+
+static void
+down_command (count_exp, from_tty)
+ char *count_exp;
+ int from_tty;
+{
+ down_silently_command (count_exp, from_tty);
+ print_stack_frame (selected_frame, selected_frame_level, 1);
+}
+
+static void
+return_command (retval_exp, from_tty)
+ char *retval_exp;
+ int from_tty;
+{
+ struct symbol *thisfun;
+ FRAME_ADDR selected_frame_addr;
+ CORE_ADDR selected_frame_pc;
+ FRAME frame;
+ value_ptr return_value = NULL;
+
+ if (selected_frame == NULL)
+ error ("No selected frame.");
+ thisfun = get_frame_function (selected_frame);
+ selected_frame_addr = FRAME_FP (selected_frame);
+ selected_frame_pc = (get_frame_info (selected_frame))->pc;
+
+ /* Compute the return value (if any -- possibly getting errors here). */
+
+ if (retval_exp)
+ {
+ return_value = parse_and_eval (retval_exp);
+
+ /* Make sure we have fully evaluated it, since
+ it might live in the stack frame we're about to pop. */
+ if (VALUE_LAZY (return_value))
+ value_fetch_lazy (return_value);
+ }
+
+ /* If interactive, require confirmation. */
+
+ if (from_tty)
+ {
+ if (thisfun != 0)
+ {
+ if (!query ("Make %s return now? ", SYMBOL_SOURCE_NAME (thisfun)))
+ {
+ error ("Not confirmed.");
+ /* NOTREACHED */
+ }
+ }
+ else
+ if (!query ("Make selected stack frame return now? "))
+ error ("Not confirmed.");
+ }
+
+ /* Do the real work. Pop until the specified frame is current. We
+ use this method because the selected_frame is not valid after
+ a POP_FRAME. The pc comparison makes this work even if the
+ selected frame shares its fp with another frame. */
+
+ while ( selected_frame_addr != FRAME_FP (frame = get_current_frame())
+ || selected_frame_pc != (get_frame_info (frame))->pc )
+ POP_FRAME;
+
+ /* Then pop that frame. */
+
+ POP_FRAME;
+
+ /* Compute the return value (if any) and store in the place
+ for return values. */
+
+ if (retval_exp)
+ set_return_value (return_value);
+
+ /* If interactive, print the frame that is now current. */
+
+ if (from_tty)
+ frame_command ("0", 1);
+}
+
+/* Gets the language of the current frame. */
+enum language
+get_frame_language()
+{
+ register struct symtab *s;
+ FRAME fr;
+ enum language flang; /* The language of the current frame */
+
+ fr = get_frame_info(selected_frame);
+ if(fr)
+ {
+ s = find_pc_symtab(fr->pc);
+ if(s)
+ flang = s->language;
+ else
+ flang = language_unknown;
+ }
+ else
+ flang = language_unknown;
+
+ return flang;
+}
+
+void
+_initialize_stack ()
+{
+#if 0
+ backtrace_limit = 30;
+#endif
+
+ add_com ("return", class_stack, return_command,
+ "Make selected stack frame return to its caller.\n\
+Control remains in the debugger, but when you continue\n\
+execution will resume in the frame above the one now selected.\n\
+If an argument is given, it is an expression for the value to return.");
+
+ add_com ("up", class_stack, up_command,
+ "Select and print stack frame that called this one.\n\
+An argument says how many frames up to go.");
+ add_com ("up-silently", class_support, up_silently_command,
+ "Same as the `up' command, but does not print anything.\n\
+This is useful in command scripts.");
+
+ add_com ("down", class_stack, down_command,
+ "Select and print stack frame called by this one.\n\
+An argument says how many frames down to go.");
+ add_com_alias ("do", "down", class_stack, 1);
+ add_com_alias ("dow", "down", class_stack, 1);
+ add_com ("down-silently", class_support, down_silently_command,
+ "Same as the `down' command, but does not print anything.\n\
+This is useful in command scripts.");
+
+ add_com ("frame", class_stack, frame_command,
+ "Select and print a stack frame.\n\
+With no argument, print the selected stack frame. (See also \"info frame\").\n\
+An argument specifies the frame to select.\n\
+It can be a stack frame number or the address of the frame.\n\
+With argument, nothing is printed if input is coming from\n\
+a command file or a user-defined command.");
+
+ add_com_alias ("f", "frame", class_stack, 1);
+
+ add_com ("select-frame", class_stack, select_frame_command,
+ "Select a stack frame without printing anything.\n\
+An argument specifies the frame to select.\n\
+It can be a stack frame number or the address of the frame.\n");
+
+ add_com ("backtrace", class_stack, backtrace_command,
+ "Print backtrace of all stack frames, or innermost COUNT frames.\n\
+With a negative argument, print outermost -COUNT frames.");
+ add_com_alias ("bt", "backtrace", class_stack, 0);
+ add_com_alias ("where", "backtrace", class_alias, 0);
+ add_info ("stack", backtrace_command,
+ "Backtrace of the stack, or innermost COUNT frames.");
+ add_info_alias ("s", "stack", 1);
+ add_info ("frame", frame_info,
+ "All about selected stack frame, or frame at ADDR.");
+ add_info_alias ("f", "frame", 1);
+ add_info ("locals", locals_info,
+ "Local variables of current stack frame.");
+ add_info ("args", args_info,
+ "Argument variables of current stack frame.");
+ add_info ("catch", catch_info,
+ "Exceptions that can be caught in the current stack frame.");
+
+#if 0
+ add_cmd ("backtrace-limit", class_stack, set_backtrace_limit_command,
+ "Specify maximum number of frames for \"backtrace\" to print by default.",
+ &setlist);
+ add_info ("backtrace-limit", backtrace_limit_info,
+ "The maximum number of frames for \"backtrace\" to print by default.");
+#endif
+}
diff --git a/gnu/usr.bin/gdb/gdb/symfile.c b/gnu/usr.bin/gdb/gdb/symfile.c
new file mode 100644
index 0000000..7857041
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/symfile.c
@@ -0,0 +1,1684 @@
+/* Generic symbol file reading for the GNU debugger, GDB.
+ Copyright 1990, 1991, 1992, 1993, 1994 Free Software Foundation, Inc.
+ Contributed by Cygnus Support, using pieces from other GDB modules.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "defs.h"
+#include "symtab.h"
+#include "gdbtypes.h"
+#include "gdbcore.h"
+#include "frame.h"
+#include "target.h"
+#include "value.h"
+#include "symfile.h"
+#include "objfiles.h"
+#include "gdbcmd.h"
+#include "breakpoint.h"
+#include "language.h"
+#include "complaints.h"
+#include "demangle.h"
+#include "inferior.h" /* for write_pc */
+
+#include <obstack.h>
+#include <assert.h>
+
+#include <sys/types.h>
+#include <fcntl.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <ctype.h>
+
+#ifndef O_BINARY
+#define O_BINARY 0
+#endif
+
+/* Global variables owned by this file */
+int readnow_symbol_files; /* Read full symbols immediately */
+
+struct complaint oldsyms_complaint = {
+ "Replacing old symbols for `%s'", 0, 0
+};
+
+struct complaint empty_symtab_complaint = {
+ "Empty symbol table found for `%s'", 0, 0
+};
+
+/* External variables and functions referenced. */
+
+extern int info_verbose;
+
+/* Functions this file defines */
+
+static void
+set_initial_language PARAMS ((void));
+
+static void
+load_command PARAMS ((char *, int));
+
+static void
+add_symbol_file_command PARAMS ((char *, int));
+
+static void
+add_shared_symbol_files_command PARAMS ((char *, int));
+
+static void
+cashier_psymtab PARAMS ((struct partial_symtab *));
+
+static int
+compare_psymbols PARAMS ((const void *, const void *));
+
+static int
+compare_symbols PARAMS ((const void *, const void *));
+
+static bfd *
+symfile_bfd_open PARAMS ((char *));
+
+static void
+find_sym_fns PARAMS ((struct objfile *));
+
+/* List of all available sym_fns. On gdb startup, each object file reader
+ calls add_symtab_fns() to register information on each format it is
+ prepared to read. */
+
+static struct sym_fns *symtab_fns = NULL;
+
+/* Structures with which to manage partial symbol allocation. */
+
+struct psymbol_allocation_list global_psymbols = {0}, static_psymbols = {0};
+
+/* Flag for whether user will be reloading symbols multiple times.
+ Defaults to ON for VxWorks, otherwise OFF. */
+
+#ifdef SYMBOL_RELOADING_DEFAULT
+int symbol_reloading = SYMBOL_RELOADING_DEFAULT;
+#else
+int symbol_reloading = 0;
+#endif
+
+
+/* Since this function is called from within qsort, in an ANSI environment
+ it must conform to the prototype for qsort, which specifies that the
+ comparison function takes two "void *" pointers. */
+
+static int
+compare_symbols (s1p, s2p)
+ const PTR s1p;
+ const PTR s2p;
+{
+ register struct symbol **s1, **s2;
+
+ s1 = (struct symbol **) s1p;
+ s2 = (struct symbol **) s2p;
+
+ return (STRCMP (SYMBOL_NAME (*s1), SYMBOL_NAME (*s2)));
+}
+
+/*
+
+LOCAL FUNCTION
+
+ compare_psymbols -- compare two partial symbols by name
+
+DESCRIPTION
+
+ Given pointer to two partial symbol table entries, compare
+ them by name and return -N, 0, or +N (ala strcmp). Typically
+ used by sorting routines like qsort().
+
+NOTES
+
+ Does direct compare of first two characters before punting
+ and passing to strcmp for longer compares. Note that the
+ original version had a bug whereby two null strings or two
+ identically named one character strings would return the
+ comparison of memory following the null byte.
+
+ */
+
+static int
+compare_psymbols (s1p, s2p)
+ const PTR s1p;
+ const PTR s2p;
+{
+ register char *st1 = SYMBOL_NAME ((struct partial_symbol *) s1p);
+ register char *st2 = SYMBOL_NAME ((struct partial_symbol *) s2p);
+
+ if ((st1[0] - st2[0]) || !st1[0])
+ {
+ return (st1[0] - st2[0]);
+ }
+ else if ((st1[1] - st2[1]) || !st1[1])
+ {
+ return (st1[1] - st2[1]);
+ }
+ else
+ {
+ return (STRCMP (st1 + 2, st2 + 2));
+ }
+}
+
+void
+sort_pst_symbols (pst)
+ struct partial_symtab *pst;
+{
+ /* Sort the global list; don't sort the static list */
+
+ qsort (pst -> objfile -> global_psymbols.list + pst -> globals_offset,
+ pst -> n_global_syms, sizeof (struct partial_symbol),
+ compare_psymbols);
+}
+
+/* Call sort_block_syms to sort alphabetically the symbols of one block. */
+
+void
+sort_block_syms (b)
+ register struct block *b;
+{
+ qsort (&BLOCK_SYM (b, 0), BLOCK_NSYMS (b),
+ sizeof (struct symbol *), compare_symbols);
+}
+
+/* Call sort_symtab_syms to sort alphabetically
+ the symbols of each block of one symtab. */
+
+void
+sort_symtab_syms (s)
+ register struct symtab *s;
+{
+ register struct blockvector *bv;
+ int nbl;
+ int i;
+ register struct block *b;
+
+ if (s == 0)
+ return;
+ bv = BLOCKVECTOR (s);
+ nbl = BLOCKVECTOR_NBLOCKS (bv);
+ for (i = 0; i < nbl; i++)
+ {
+ b = BLOCKVECTOR_BLOCK (bv, i);
+ if (BLOCK_SHOULD_SORT (b))
+ sort_block_syms (b);
+ }
+}
+
+/* Make a copy of the string at PTR with SIZE characters in the symbol obstack
+ (and add a null character at the end in the copy).
+ Returns the address of the copy. */
+
+char *
+obsavestring (ptr, size, obstackp)
+ char *ptr;
+ int size;
+ struct obstack *obstackp;
+{
+ register char *p = (char *) obstack_alloc (obstackp, size + 1);
+ /* Open-coded memcpy--saves function call time.
+ These strings are usually short. */
+ {
+ register char *p1 = ptr;
+ register char *p2 = p;
+ char *end = ptr + size;
+ while (p1 != end)
+ *p2++ = *p1++;
+ }
+ p[size] = 0;
+ return p;
+}
+
+/* Concatenate strings S1, S2 and S3; return the new string.
+ Space is found in the symbol_obstack. */
+
+char *
+obconcat (obstackp, s1, s2, s3)
+ struct obstack *obstackp;
+ const char *s1, *s2, *s3;
+{
+ register int len = strlen (s1) + strlen (s2) + strlen (s3) + 1;
+ register char *val = (char *) obstack_alloc (obstackp, len);
+ strcpy (val, s1);
+ strcat (val, s2);
+ strcat (val, s3);
+ return val;
+}
+
+/* Get the symbol table that corresponds to a partial_symtab.
+ This is fast after the first time you do it. In fact, there
+ is an even faster macro PSYMTAB_TO_SYMTAB that does the fast
+ case inline. */
+
+struct symtab *
+psymtab_to_symtab (pst)
+ register struct partial_symtab *pst;
+{
+ /* If it's been looked up before, return it. */
+ if (pst->symtab)
+ return pst->symtab;
+
+ /* If it has not yet been read in, read it. */
+ if (!pst->readin)
+ {
+ (*pst->read_symtab) (pst);
+ }
+
+ return pst->symtab;
+}
+
+/* Initialize entry point information for this objfile. */
+
+void
+init_entry_point_info (objfile)
+ struct objfile *objfile;
+{
+ /* Save startup file's range of PC addresses to help blockframe.c
+ decide where the bottom of the stack is. */
+
+ if (bfd_get_file_flags (objfile -> obfd) & EXEC_P)
+ {
+ /* Executable file -- record its entry point so we'll recognize
+ the startup file because it contains the entry point. */
+ objfile -> ei.entry_point = bfd_get_start_address (objfile -> obfd);
+ }
+ else
+ {
+ /* Examination of non-executable.o files. Short-circuit this stuff. */
+ objfile -> ei.entry_point = INVALID_ENTRY_POINT;
+ objfile -> ei.entry_file_lowpc = INVALID_ENTRY_LOWPC;
+ objfile -> ei.entry_file_highpc = INVALID_ENTRY_HIGHPC;
+ }
+}
+
+/* Get current entry point address. */
+
+CORE_ADDR
+entry_point_address()
+{
+ return symfile_objfile ? symfile_objfile->ei.entry_point : 0;
+}
+
+/* Remember the lowest-addressed loadable section we've seen.
+ This function is called via bfd_map_over_sections. */
+
+#if 0 /* Not used yet */
+static void
+find_lowest_section (abfd, sect, obj)
+ bfd *abfd;
+ asection *sect;
+ PTR obj;
+{
+ asection **lowest = (asection **)obj;
+
+ if (0 == (bfd_get_section_flags (abfd, sect) & SEC_LOAD))
+ return;
+ if (!*lowest)
+ *lowest = sect; /* First loadable section */
+ else if (bfd_section_vma (abfd, *lowest) >= bfd_section_vma (abfd, sect))
+ *lowest = sect; /* A lower loadable section */
+}
+#endif
+
+/* Process a symbol file, as either the main file or as a dynamically
+ loaded file.
+
+ NAME is the file name (which will be tilde-expanded and made
+ absolute herein) (but we don't free or modify NAME itself).
+ FROM_TTY says how verbose to be. MAINLINE specifies whether this
+ is the main symbol file, or whether it's an extra symbol file such
+ as dynamically loaded code. If !mainline, ADDR is the address
+ where the text segment was loaded. If VERBO, the caller has printed
+ a verbose message about the symbol reading (and complaints can be
+ more terse about it). */
+
+void
+syms_from_objfile (objfile, addr, mainline, verbo)
+ struct objfile *objfile;
+ CORE_ADDR addr;
+ int mainline;
+ int verbo;
+{
+ struct section_offsets *section_offsets;
+ asection *lowest_sect;
+ struct cleanup *old_chain;
+
+ init_entry_point_info (objfile);
+ find_sym_fns (objfile);
+
+ /* Make sure that partially constructed symbol tables will be cleaned up
+ if an error occurs during symbol reading. */
+ old_chain = make_cleanup (free_objfile, objfile);
+
+ if (mainline)
+ {
+ /* We will modify the main symbol table, make sure that all its users
+ will be cleaned up if an error occurs during symbol reading. */
+ make_cleanup (clear_symtab_users, 0);
+
+ /* Since no error yet, throw away the old symbol table. */
+
+ if (symfile_objfile != NULL)
+ {
+ free_objfile (symfile_objfile);
+ symfile_objfile = NULL;
+ }
+
+ /* Currently we keep symbols from the add-symbol-file command.
+ If the user wants to get rid of them, they should do "symbol-file"
+ without arguments first. Not sure this is the best behavior
+ (PR 2207). */
+
+ (*objfile -> sf -> sym_new_init) (objfile);
+ }
+
+ /* Convert addr into an offset rather than an absolute address.
+ We find the lowest address of a loaded segment in the objfile,
+ and assume that <addr> is where that got loaded. Due to historical
+ precedent, we warn if that doesn't happen to be the ".text"
+ segment. */
+
+ if (mainline)
+ {
+ addr = 0; /* No offset from objfile addresses. */
+ }
+ else
+ {
+ lowest_sect = bfd_get_section_by_name (objfile->obfd, ".text");
+#if 0
+ lowest_sect = 0;
+ bfd_map_over_sections (objfile->obfd, find_lowest_section,
+ (PTR) &lowest_sect);
+#endif
+
+ if (lowest_sect == 0)
+ warning ("no loadable sections found in added symbol-file %s",
+ objfile->name);
+ else if (0 == bfd_get_section_name (objfile->obfd, lowest_sect)
+ || !STREQ (".text",
+ bfd_get_section_name (objfile->obfd, lowest_sect)))
+ /* FIXME-32x64--assumes bfd_vma fits in long. */
+ warning ("Lowest section in %s is %s at 0x%lx",
+ objfile->name,
+ bfd_section_name (objfile->obfd, lowest_sect),
+ (unsigned long) bfd_section_vma (objfile->obfd, lowest_sect));
+
+ if (lowest_sect)
+ addr -= bfd_section_vma (objfile->obfd, lowest_sect);
+ }
+
+ /* Initialize symbol reading routines for this objfile, allow complaints to
+ appear for this new file, and record how verbose to be, then do the
+ initial symbol reading for this file. */
+
+ (*objfile -> sf -> sym_init) (objfile);
+ clear_complaints (1, verbo);
+
+ section_offsets = (*objfile -> sf -> sym_offsets) (objfile, addr);
+ objfile->section_offsets = section_offsets;
+
+#ifndef IBM6000_TARGET
+ /* This is a SVR4/SunOS specific hack, I think. In any event, it
+ screws RS/6000. sym_offsets should be doing this sort of thing,
+ because it knows the mapping between bfd sections and
+ section_offsets. */
+ /* This is a hack. As far as I can tell, section offsets are not
+ target dependent. They are all set to addr with a couple of
+ exceptions. The exceptions are sysvr4 shared libraries, whose
+ offsets are kept in solib structures anyway and rs6000 xcoff
+ which handles shared libraries in a completely unique way.
+
+ Section offsets are built similarly, except that they are built
+ by adding addr in all cases because there is no clear mapping
+ from section_offsets into actual sections. Note that solib.c
+ has a different algorythm for finding section offsets.
+
+ These should probably all be collapsed into some target
+ independent form of shared library support. FIXME. */
+
+ if (addr)
+ {
+ struct obj_section *s;
+
+ for (s = objfile->sections; s < objfile->sections_end; ++s)
+ {
+ s->addr -= s->offset;
+ s->addr += addr;
+ s->endaddr -= s->offset;
+ s->endaddr += addr;
+ s->offset += addr;
+ }
+ }
+#endif /* not IBM6000_TARGET */
+
+ (*objfile -> sf -> sym_read) (objfile, section_offsets, mainline);
+
+ if (!have_partial_symbols () && !have_full_symbols ())
+ {
+ wrap_here ("");
+ printf_filtered ("(no debugging symbols found)...");
+ wrap_here ("");
+ }
+
+ /* Don't allow char * to have a typename (else would get caddr_t).
+ Ditto void *. FIXME: Check whether this is now done by all the
+ symbol readers themselves (many of them now do), and if so remove
+ it from here. */
+
+ TYPE_NAME (lookup_pointer_type (builtin_type_char)) = 0;
+ TYPE_NAME (lookup_pointer_type (builtin_type_void)) = 0;
+
+ /* Mark the objfile has having had initial symbol read attempted. Note
+ that this does not mean we found any symbols... */
+
+ objfile -> flags |= OBJF_SYMS;
+
+ /* Discard cleanups as symbol reading was successful. */
+
+ discard_cleanups (old_chain);
+}
+
+/* Perform required actions after either reading in the initial
+ symbols for a new objfile, or mapping in the symbols from a reusable
+ objfile. */
+
+void
+new_symfile_objfile (objfile, mainline, verbo)
+ struct objfile *objfile;
+ int mainline;
+ int verbo;
+{
+
+ /* If this is the main symbol file we have to clean up all users of the
+ old main symbol file. Otherwise it is sufficient to fixup all the
+ breakpoints that may have been redefined by this symbol file. */
+ if (mainline)
+ {
+ /* OK, make it the "real" symbol file. */
+ symfile_objfile = objfile;
+
+ clear_symtab_users ();
+ }
+ else
+ {
+ breakpoint_re_set ();
+ }
+
+ /* We're done reading the symbol file; finish off complaints. */
+ clear_complaints (0, verbo);
+}
+
+/* Process a symbol file, as either the main file or as a dynamically
+ loaded file.
+
+ NAME is the file name (which will be tilde-expanded and made
+ absolute herein) (but we don't free or modify NAME itself).
+ FROM_TTY says how verbose to be. MAINLINE specifies whether this
+ is the main symbol file, or whether it's an extra symbol file such
+ as dynamically loaded code. If !mainline, ADDR is the address
+ where the text segment was loaded.
+
+ Upon success, returns a pointer to the objfile that was added.
+ Upon failure, jumps back to command level (never returns). */
+
+struct objfile *
+symbol_file_add (name, from_tty, addr, mainline, mapped, readnow)
+ char *name;
+ int from_tty;
+ CORE_ADDR addr;
+ int mainline;
+ int mapped;
+ int readnow;
+{
+ struct objfile *objfile;
+ struct partial_symtab *psymtab;
+ bfd *abfd;
+
+ /* Open a bfd for the file, and give user a chance to burp if we'd be
+ interactively wiping out any existing symbols. */
+
+ abfd = symfile_bfd_open (name);
+
+ if ((have_full_symbols () || have_partial_symbols ())
+ && mainline
+ && from_tty
+ && !query ("Load new symbol table from \"%s\"? ", name))
+ error ("Not confirmed.");
+
+ objfile = allocate_objfile (abfd, mapped);
+
+ /* If the objfile uses a mapped symbol file, and we have a psymtab for
+ it, then skip reading any symbols at this time. */
+
+ if ((objfile -> flags & OBJF_MAPPED) && (objfile -> flags & OBJF_SYMS))
+ {
+ /* We mapped in an existing symbol table file that already has had
+ initial symbol reading performed, so we can skip that part. Notify
+ the user that instead of reading the symbols, they have been mapped.
+ */
+ if (from_tty || info_verbose)
+ {
+ printf_filtered ("Mapped symbols for %s...", name);
+ wrap_here ("");
+ gdb_flush (gdb_stdout);
+ }
+ init_entry_point_info (objfile);
+ find_sym_fns (objfile);
+ }
+ else
+ {
+ /* We either created a new mapped symbol table, mapped an existing
+ symbol table file which has not had initial symbol reading
+ performed, or need to read an unmapped symbol table. */
+ if (from_tty || info_verbose)
+ {
+ printf_filtered ("Reading symbols from %s...", name);
+ wrap_here ("");
+ gdb_flush (gdb_stdout);
+ }
+ syms_from_objfile (objfile, addr, mainline, from_tty);
+ }
+
+ /* We now have at least a partial symbol table. Check to see if the
+ user requested that all symbols be read on initial access via either
+ the gdb startup command line or on a per symbol file basis. Expand
+ all partial symbol tables for this objfile if so. */
+
+ if (readnow || readnow_symbol_files)
+ {
+ if (from_tty || info_verbose)
+ {
+ printf_filtered ("expanding to full symbols...");
+ wrap_here ("");
+ gdb_flush (gdb_stdout);
+ }
+
+ for (psymtab = objfile -> psymtabs;
+ psymtab != NULL;
+ psymtab = psymtab -> next)
+ {
+ psymtab_to_symtab (psymtab);
+ }
+ }
+
+ if (from_tty || info_verbose)
+ {
+ printf_filtered ("done.\n");
+ gdb_flush (gdb_stdout);
+ }
+
+ new_symfile_objfile (objfile, mainline, from_tty);
+
+ /* Getting new symbols may change our opinion about what is
+ frameless. */
+
+ reinit_frame_cache ();
+
+ return (objfile);
+}
+
+/* This is the symbol-file command. Read the file, analyze its
+ symbols, and add a struct symtab to a symtab list. The syntax of
+ the command is rather bizarre--(1) buildargv implements various
+ quoting conventions which are undocumented and have little or
+ nothing in common with the way things are quoted (or not quoted)
+ elsewhere in GDB, (2) options are used, which are not generally
+ used in GDB (perhaps "set mapped on", "set readnow on" would be
+ better), (3) the order of options matters, which is contrary to GNU
+ conventions (because it is confusing and inconvenient). */
+
+void
+symbol_file_command (args, from_tty)
+ char *args;
+ int from_tty;
+{
+ char **argv;
+ char *name = NULL;
+ CORE_ADDR text_relocation = 0; /* text_relocation */
+ struct cleanup *cleanups;
+ int mapped = 0;
+ int readnow = 0;
+
+ dont_repeat ();
+
+ if (args == NULL)
+ {
+ if ((have_full_symbols () || have_partial_symbols ())
+ && from_tty
+ && !query ("Discard symbol table from `%s'? ",
+ symfile_objfile -> name))
+ error ("Not confirmed.");
+ free_all_objfiles ();
+ symfile_objfile = NULL;
+ if (from_tty)
+ {
+ printf_unfiltered ("No symbol file now.\n");
+ }
+ }
+ else
+ {
+ if ((argv = buildargv (args)) == NULL)
+ {
+ nomem (0);
+ }
+ cleanups = make_cleanup (freeargv, (char *) argv);
+ while (*argv != NULL)
+ {
+ if (STREQ (*argv, "-mapped"))
+ {
+ mapped = 1;
+ }
+ else if (STREQ (*argv, "-readnow"))
+ {
+ readnow = 1;
+ }
+ else if (**argv == '-')
+ {
+ error ("unknown option `%s'", *argv);
+ }
+ else
+ {
+ char *p;
+
+ name = *argv;
+
+ /* this is for rombug remote only, to get the text relocation by
+ using link command */
+ p = strrchr(name, '/');
+ if (p != NULL) p++;
+ else p = name;
+
+ target_link(p, &text_relocation);
+
+ if (text_relocation == (CORE_ADDR)0)
+ return;
+ else if (text_relocation == (CORE_ADDR)-1)
+ symbol_file_add (name, from_tty, (CORE_ADDR)0, 1, mapped,
+ readnow);
+ else
+ symbol_file_add (name, from_tty, (CORE_ADDR)text_relocation,
+ 0, mapped, readnow);
+ set_initial_language ();
+ }
+ argv++;
+ }
+
+ if (name == NULL)
+ {
+ error ("no symbol file name was specified");
+ }
+ do_cleanups (cleanups);
+ }
+}
+
+/* Set the initial language.
+
+ A better solution would be to record the language in the psymtab when reading
+ partial symbols, and then use it (if known) to set the language. This would
+ be a win for formats that encode the language in an easily discoverable place,
+ such as DWARF. For stabs, we can jump through hoops looking for specially
+ named symbols or try to intuit the language from the specific type of stabs
+ we find, but we can't do that until later when we read in full symbols.
+ FIXME. */
+
+static void
+set_initial_language ()
+{
+ struct partial_symtab *pst;
+ enum language lang = language_unknown;
+
+ pst = find_main_psymtab ();
+ if (pst != NULL)
+ {
+ if (pst -> filename != NULL)
+ {
+ lang = deduce_language_from_filename (pst -> filename);
+ }
+ if (lang == language_unknown)
+ {
+ /* Make C the default language */
+ lang = language_c;
+ }
+ set_language (lang);
+ expected_language = current_language; /* Don't warn the user */
+ }
+}
+
+/* Open file specified by NAME and hand it off to BFD for preliminary
+ analysis. Result is a newly initialized bfd *, which includes a newly
+ malloc'd` copy of NAME (tilde-expanded and made absolute).
+ In case of trouble, error() is called. */
+
+static bfd *
+symfile_bfd_open (name)
+ char *name;
+{
+ bfd *sym_bfd;
+ int desc;
+ char *absolute_name;
+
+ name = tilde_expand (name); /* Returns 1st new malloc'd copy */
+
+ /* Look down path for it, allocate 2nd new malloc'd copy. */
+ desc = openp (getenv ("PATH"), 1, name, O_RDONLY | O_BINARY, 0, &absolute_name);
+ if (desc < 0)
+ {
+ make_cleanup (free, name);
+ perror_with_name (name);
+ }
+ free (name); /* Free 1st new malloc'd copy */
+ name = absolute_name; /* Keep 2nd malloc'd copy in bfd */
+ /* It'll be freed in free_objfile(). */
+
+ sym_bfd = bfd_fdopenr (name, gnutarget, desc);
+ if (!sym_bfd)
+ {
+ close (desc);
+ make_cleanup (free, name);
+ error ("\"%s\": can't open to read symbols: %s.", name,
+ bfd_errmsg (bfd_get_error ()));
+ }
+ sym_bfd->cacheable = true;
+
+ if (!bfd_check_format (sym_bfd, bfd_object))
+ {
+ bfd_close (sym_bfd); /* This also closes desc */
+ make_cleanup (free, name);
+ error ("\"%s\": can't read symbols: %s.", name,
+ bfd_errmsg (bfd_get_error ()));
+ }
+
+ return (sym_bfd);
+}
+
+/* Link a new symtab_fns into the global symtab_fns list. Called on gdb
+ startup by the _initialize routine in each object file format reader,
+ to register information about each format the the reader is prepared
+ to handle. */
+
+void
+add_symtab_fns (sf)
+ struct sym_fns *sf;
+{
+ sf->next = symtab_fns;
+ symtab_fns = sf;
+}
+
+
+/* Initialize to read symbols from the symbol file sym_bfd. It either
+ returns or calls error(). The result is an initialized struct sym_fns
+ in the objfile structure, that contains cached information about the
+ symbol file. */
+
+static void
+find_sym_fns (objfile)
+ struct objfile *objfile;
+{
+ struct sym_fns *sf;
+ enum bfd_flavour our_flavour = bfd_get_flavour (objfile -> obfd);
+ char *our_target = bfd_get_target (objfile -> obfd);
+
+ /* Special kludge for RS/6000. See xcoffread.c. */
+ if (STREQ (our_target, "aixcoff-rs6000"))
+ our_flavour = (enum bfd_flavour)-1;
+
+ /* Special kludge for apollo. See dstread.c. */
+ if (STREQN (our_target, "apollo", 6))
+ our_flavour = (enum bfd_flavour)-2;
+
+ for (sf = symtab_fns; sf != NULL; sf = sf -> next)
+ {
+ if (our_flavour == sf -> sym_flavour)
+ {
+ objfile -> sf = sf;
+ return;
+ }
+ }
+ error ("I'm sorry, Dave, I can't do that. Symbol format `%s' unknown.",
+ bfd_get_target (objfile -> obfd));
+}
+
+/* This function runs the load command of our current target. */
+
+static void
+load_command (arg, from_tty)
+ char *arg;
+ int from_tty;
+{
+ target_load (arg, from_tty);
+}
+
+/* This version of "load" should be usable for any target. Currently
+ it is just used for remote targets, not inftarg.c or core files,
+ on the theory that only in that case is it useful.
+
+ Avoiding xmodem and the like seems like a win (a) because we don't have
+ to worry about finding it, and (b) On VMS, fork() is very slow and so
+ we don't want to run a subprocess. On the other hand, I'm not sure how
+ performance compares. */
+void
+generic_load (filename, from_tty)
+ char *filename;
+ int from_tty;
+{
+ struct cleanup *old_cleanups;
+ asection *s;
+ bfd *loadfile_bfd;
+
+ if (filename == NULL)
+ filename = get_exec_file (1);
+
+ loadfile_bfd = bfd_openr (filename, gnutarget);
+ if (loadfile_bfd == NULL)
+ {
+ perror_with_name (filename);
+ return;
+ }
+ old_cleanups = make_cleanup (bfd_close, loadfile_bfd);
+
+ if (!bfd_check_format (loadfile_bfd, bfd_object))
+ {
+ error ("\"%s\" is not an object file: %s", filename,
+ bfd_errmsg (bfd_get_error ()));
+ }
+
+ for (s = loadfile_bfd->sections; s; s = s->next)
+ {
+ if (s->flags & SEC_LOAD)
+ {
+ bfd_size_type size;
+
+ size = bfd_get_section_size_before_reloc (s);
+ if (size > 0)
+ {
+ char *buffer;
+ struct cleanup *old_chain;
+ bfd_vma vma;
+
+ buffer = xmalloc (size);
+ old_chain = make_cleanup (free, buffer);
+
+ vma = bfd_get_section_vma (loadfile_bfd, s);
+
+ /* Is this really necessary? I guess it gives the user something
+ to look at during a long download. */
+ printf_filtered ("Loading section %s, size 0x%lx vma ",
+ bfd_get_section_name (loadfile_bfd, s),
+ (unsigned long) size);
+ print_address_numeric (vma, 1, gdb_stdout);
+ printf_filtered ("\n");
+
+ bfd_get_section_contents (loadfile_bfd, s, buffer, 0, size);
+
+ target_write_memory (vma, buffer, size);
+
+ do_cleanups (old_chain);
+ }
+ }
+ }
+
+ /* We were doing this in remote-mips.c, I suspect it is right
+ for other targets too. */
+ write_pc (loadfile_bfd->start_address);
+
+ /* FIXME: are we supposed to call symbol_file_add or not? According to
+ a comment from remote-mips.c (where a call to symbol_file_add was
+ commented out), making the call confuses GDB if more than one file is
+ loaded in. remote-nindy.c had no call to symbol_file_add, but remote-vx.c
+ does. */
+
+ do_cleanups (old_cleanups);
+}
+
+/* This function allows the addition of incrementally linked object files.
+ It does not modify any state in the target, only in the debugger. */
+
+/* ARGSUSED */
+static void
+add_symbol_file_command (args, from_tty)
+ char *args;
+ int from_tty;
+{
+ char *name = NULL;
+ CORE_ADDR text_addr;
+ char *arg;
+ int readnow = 0;
+ int mapped = 0;
+
+ dont_repeat ();
+
+ if (args == NULL)
+ {
+ error ("add-symbol-file takes a file name and an address");
+ }
+
+ /* Make a copy of the string that we can safely write into. */
+
+ args = strdup (args);
+ make_cleanup (free, args);
+
+ /* Pick off any -option args and the file name. */
+
+ while ((*args != '\000') && (name == NULL))
+ {
+ while (isspace (*args)) {args++;}
+ arg = args;
+ while ((*args != '\000') && !isspace (*args)) {args++;}
+ if (*args != '\000')
+ {
+ *args++ = '\000';
+ }
+ if (*arg != '-')
+ {
+ name = arg;
+ }
+ else if (STREQ (arg, "-mapped"))
+ {
+ mapped = 1;
+ }
+ else if (STREQ (arg, "-readnow"))
+ {
+ readnow = 1;
+ }
+ else
+ {
+ error ("unknown option `%s'", arg);
+ }
+ }
+
+ /* After picking off any options and the file name, args should be
+ left pointing at the remainder of the command line, which should
+ be the address expression to evaluate. */
+
+ if (name == NULL)
+ {
+ error ("add-symbol-file takes a file name");
+ }
+ name = tilde_expand (name);
+ make_cleanup (free, name);
+
+ if (*args != '\000')
+ {
+ text_addr = parse_and_eval_address (args);
+ }
+ else
+ {
+ target_link(name, &text_addr);
+ if (text_addr == (CORE_ADDR)-1)
+ error("Don't know how to get text start location for this file");
+ }
+
+ /* FIXME-32x64: Assumes text_addr fits in a long. */
+ if (!query ("add symbol table from file \"%s\" at text_addr = %s?\n",
+ name, local_hex_string ((unsigned long)text_addr)))
+ error ("Not confirmed.");
+
+ symbol_file_add (name, 0, text_addr, 0, mapped, readnow);
+}
+
+static void
+add_shared_symbol_files_command (args, from_tty)
+ char *args;
+ int from_tty;
+{
+#ifdef ADD_SHARED_SYMBOL_FILES
+ ADD_SHARED_SYMBOL_FILES (args, from_tty);
+#else
+ error ("This command is not available in this configuration of GDB.");
+#endif
+}
+
+/* Re-read symbols if a symbol-file has changed. */
+void
+reread_symbols ()
+{
+ struct objfile *objfile;
+ long new_modtime;
+ int reread_one = 0;
+ struct stat new_statbuf;
+ int res;
+
+ /* With the addition of shared libraries, this should be modified,
+ the load time should be saved in the partial symbol tables, since
+ different tables may come from different source files. FIXME.
+ This routine should then walk down each partial symbol table
+ and see if the symbol table that it originates from has been changed */
+
+ for (objfile = object_files; objfile; objfile = objfile->next) {
+ if (objfile->obfd) {
+#ifdef IBM6000_TARGET
+ /* If this object is from a shared library, then you should
+ stat on the library name, not member name. */
+
+ if (objfile->obfd->my_archive)
+ res = stat (objfile->obfd->my_archive->filename, &new_statbuf);
+ else
+#endif
+ res = stat (objfile->name, &new_statbuf);
+ if (res != 0) {
+ /* FIXME, should use print_sys_errmsg but it's not filtered. */
+ printf_filtered ("`%s' has disappeared; keeping its symbols.\n",
+ objfile->name);
+ continue;
+ }
+ new_modtime = new_statbuf.st_mtime;
+ if (new_modtime != objfile->mtime)
+ {
+ struct cleanup *old_cleanups;
+ struct section_offsets *offsets;
+ int num_offsets;
+ int section_offsets_size;
+
+ printf_filtered ("`%s' has changed; re-reading symbols.\n",
+ objfile->name);
+
+ /* There are various functions like symbol_file_add,
+ symfile_bfd_open, syms_from_objfile, etc., which might
+ appear to do what we want. But they have various other
+ effects which we *don't* want. So we just do stuff
+ ourselves. We don't worry about mapped files (for one thing,
+ any mapped file will be out of date). */
+
+ /* If we get an error, blow away this objfile (not sure if
+ that is the correct response for things like shared
+ libraries). */
+ old_cleanups = make_cleanup (free_objfile, objfile);
+ /* We need to do this whenever any symbols go away. */
+ make_cleanup (clear_symtab_users, 0);
+
+ /* Clean up any state BFD has sitting around. We don't need
+ to close the descriptor but BFD lacks a way of closing the
+ BFD without closing the descriptor. */
+ if (!bfd_close (objfile->obfd))
+ error ("Can't close BFD for %s.", objfile->name);
+ objfile->obfd = bfd_openr (objfile->name, gnutarget);
+ if (objfile->obfd == NULL)
+ error ("Can't open %s to read symbols.", objfile->name);
+ /* bfd_openr sets cacheable to true, which is what we want. */
+ if (!bfd_check_format (objfile->obfd, bfd_object))
+ error ("Can't read symbols from %s: %s.", objfile->name,
+ bfd_errmsg (bfd_get_error ()));
+
+ /* Save the offsets, we will nuke them with the rest of the
+ psymbol_obstack. */
+ num_offsets = objfile->num_sections;
+ section_offsets_size =
+ sizeof (struct section_offsets)
+ + sizeof (objfile->section_offsets->offsets) * num_offsets;
+ offsets = (struct section_offsets *) alloca (section_offsets_size);
+ memcpy (offsets, objfile->section_offsets, section_offsets_size);
+
+ /* Nuke all the state that we will re-read. Much of the following
+ code which sets things to NULL really is necessary to tell
+ other parts of GDB that there is nothing currently there. */
+
+ /* FIXME: Do we have to free a whole linked list, or is this
+ enough? */
+ if (objfile->global_psymbols.list)
+ mfree (objfile->md, objfile->global_psymbols.list);
+ objfile->global_psymbols.list = NULL;
+ objfile->global_psymbols.next = NULL;
+ objfile->global_psymbols.size = 0;
+ if (objfile->static_psymbols.list)
+ mfree (objfile->md, objfile->static_psymbols.list);
+ objfile->static_psymbols.list = NULL;
+ objfile->static_psymbols.next = NULL;
+ objfile->static_psymbols.size = 0;
+
+ /* Free the obstacks for non-reusable objfiles */
+ obstack_free (&objfile -> psymbol_obstack, 0);
+ obstack_free (&objfile -> symbol_obstack, 0);
+ obstack_free (&objfile -> type_obstack, 0);
+ objfile->sections = NULL;
+ objfile->symtabs = NULL;
+ objfile->psymtabs = NULL;
+ objfile->free_psymtabs = NULL;
+ objfile->msymbols = NULL;
+ objfile->minimal_symbol_count= 0;
+ objfile->fundamental_types = NULL;
+ if (objfile -> sf != NULL)
+ {
+ (*objfile -> sf -> sym_finish) (objfile);
+ }
+
+ /* We never make this a mapped file. */
+ objfile -> md = NULL;
+ /* obstack_specify_allocation also initializes the obstack so
+ it is empty. */
+ obstack_specify_allocation (&objfile -> psymbol_obstack, 0, 0,
+ xmalloc, free);
+ obstack_specify_allocation (&objfile -> symbol_obstack, 0, 0,
+ xmalloc, free);
+ obstack_specify_allocation (&objfile -> type_obstack, 0, 0,
+ xmalloc, free);
+ if (build_objfile_section_table (objfile))
+ {
+ error ("Can't find the file sections in `%s': %s",
+ objfile -> name, bfd_errmsg (bfd_get_error ()));
+ }
+
+ /* We use the same section offsets as from last time. I'm not
+ sure whether that is always correct for shared libraries. */
+ objfile->section_offsets = (struct section_offsets *)
+ obstack_alloc (&objfile -> psymbol_obstack, section_offsets_size);
+ memcpy (objfile->section_offsets, offsets, section_offsets_size);
+ objfile->num_sections = num_offsets;
+
+ /* What the hell is sym_new_init for, anyway? The concept of
+ distinguishing between the main file and additional files
+ in this way seems rather dubious. */
+ if (objfile == symfile_objfile)
+ (*objfile->sf->sym_new_init) (objfile);
+
+ (*objfile->sf->sym_init) (objfile);
+ clear_complaints (1, 1);
+ /* The "mainline" parameter is a hideous hack; I think leaving it
+ zero is OK since dbxread.c also does what it needs to do if
+ objfile->global_psymbols.size is 0. */
+ (*objfile->sf->sym_read) (objfile, objfile->section_offsets, 0);
+ if (!have_partial_symbols () && !have_full_symbols ())
+ {
+ wrap_here ("");
+ printf_filtered ("(no debugging symbols found)\n");
+ wrap_here ("");
+ }
+ objfile -> flags |= OBJF_SYMS;
+
+ /* We're done reading the symbol file; finish off complaints. */
+ clear_complaints (0, 1);
+
+ /* Getting new symbols may change our opinion about what is
+ frameless. */
+
+ reinit_frame_cache ();
+
+ /* Discard cleanups as symbol reading was successful. */
+ discard_cleanups (old_cleanups);
+
+ /* If the mtime has changed between the time we set new_modtime
+ and now, we *want* this to be out of date, so don't call stat
+ again now. */
+ objfile->mtime = new_modtime;
+ reread_one = 1;
+ }
+ }
+ }
+
+ if (reread_one)
+ clear_symtab_users ();
+}
+
+
+enum language
+deduce_language_from_filename (filename)
+ char *filename;
+{
+ char *c;
+
+ if (0 == filename)
+ ; /* Get default */
+ else if (0 == (c = strrchr (filename, '.')))
+ ; /* Get default. */
+ else if (STREQ(c,".mod"))
+ return language_m2;
+ else if (STREQ(c,".c"))
+ return language_c;
+ else if (STREQ(c,".s"))
+ return language_asm;
+ else if (STREQ (c,".cc") || STREQ (c,".C") || STREQ (c, ".cxx")
+ || STREQ (c, ".cpp"))
+ return language_cplus;
+ else if (STREQ (c,".ch") || STREQ (c,".c186") || STREQ (c,".c286"))
+ return language_chill;
+
+ return language_unknown; /* default */
+}
+
+/* allocate_symtab:
+
+ Allocate and partly initialize a new symbol table. Return a pointer
+ to it. error() if no space.
+
+ Caller must set these fields:
+ LINETABLE(symtab)
+ symtab->blockvector
+ symtab->dirname
+ symtab->free_code
+ symtab->free_ptr
+ initialize any EXTRA_SYMTAB_INFO
+ possibly free_named_symtabs (symtab->filename);
+ */
+
+struct symtab *
+allocate_symtab (filename, objfile)
+ char *filename;
+ struct objfile *objfile;
+{
+ register struct symtab *symtab;
+
+ symtab = (struct symtab *)
+ obstack_alloc (&objfile -> symbol_obstack, sizeof (struct symtab));
+ memset (symtab, 0, sizeof (*symtab));
+ symtab -> filename = obsavestring (filename, strlen (filename),
+ &objfile -> symbol_obstack);
+ symtab -> fullname = NULL;
+ symtab -> language = deduce_language_from_filename (filename);
+
+ /* Hook it to the objfile it comes from */
+
+ symtab -> objfile = objfile;
+ symtab -> next = objfile -> symtabs;
+ objfile -> symtabs = symtab;
+
+#ifdef INIT_EXTRA_SYMTAB_INFO
+ INIT_EXTRA_SYMTAB_INFO (symtab);
+#endif
+
+ return (symtab);
+}
+
+struct partial_symtab *
+allocate_psymtab (filename, objfile)
+ char *filename;
+ struct objfile *objfile;
+{
+ struct partial_symtab *psymtab;
+
+ if (objfile -> free_psymtabs)
+ {
+ psymtab = objfile -> free_psymtabs;
+ objfile -> free_psymtabs = psymtab -> next;
+ }
+ else
+ psymtab = (struct partial_symtab *)
+ obstack_alloc (&objfile -> psymbol_obstack,
+ sizeof (struct partial_symtab));
+
+ memset (psymtab, 0, sizeof (struct partial_symtab));
+ psymtab -> filename = obsavestring (filename, strlen (filename),
+ &objfile -> psymbol_obstack);
+ psymtab -> symtab = NULL;
+
+ /* Hook it to the objfile it comes from */
+
+ psymtab -> objfile = objfile;
+ psymtab -> next = objfile -> psymtabs;
+ objfile -> psymtabs = psymtab;
+
+ return (psymtab);
+}
+
+
+/* Reset all data structures in gdb which may contain references to symbol
+ table date. */
+
+void
+clear_symtab_users ()
+{
+ /* Someday, we should do better than this, by only blowing away
+ the things that really need to be blown. */
+ clear_value_history ();
+ clear_displays ();
+ clear_internalvars ();
+ breakpoint_re_set ();
+ set_default_breakpoint (0, 0, 0, 0);
+ current_source_symtab = 0;
+ current_source_line = 0;
+ clear_pc_function_cache ();
+}
+
+/* clear_symtab_users_once:
+
+ This function is run after symbol reading, or from a cleanup.
+ If an old symbol table was obsoleted, the old symbol table
+ has been blown away, but the other GDB data structures that may
+ reference it have not yet been cleared or re-directed. (The old
+ symtab was zapped, and the cleanup queued, in free_named_symtab()
+ below.)
+
+ This function can be queued N times as a cleanup, or called
+ directly; it will do all the work the first time, and then will be a
+ no-op until the next time it is queued. This works by bumping a
+ counter at queueing time. Much later when the cleanup is run, or at
+ the end of symbol processing (in case the cleanup is discarded), if
+ the queued count is greater than the "done-count", we do the work
+ and set the done-count to the queued count. If the queued count is
+ less than or equal to the done-count, we just ignore the call. This
+ is needed because reading a single .o file will often replace many
+ symtabs (one per .h file, for example), and we don't want to reset
+ the breakpoints N times in the user's face.
+
+ The reason we both queue a cleanup, and call it directly after symbol
+ reading, is because the cleanup protects us in case of errors, but is
+ discarded if symbol reading is successful. */
+
+#if 0
+/* FIXME: As free_named_symtabs is currently a big noop this function
+ is no longer needed. */
+static void
+clear_symtab_users_once PARAMS ((void));
+
+static int clear_symtab_users_queued;
+static int clear_symtab_users_done;
+
+static void
+clear_symtab_users_once ()
+{
+ /* Enforce once-per-`do_cleanups'-semantics */
+ if (clear_symtab_users_queued <= clear_symtab_users_done)
+ return;
+ clear_symtab_users_done = clear_symtab_users_queued;
+
+ clear_symtab_users ();
+}
+#endif
+
+/* Delete the specified psymtab, and any others that reference it. */
+
+static void
+cashier_psymtab (pst)
+ struct partial_symtab *pst;
+{
+ struct partial_symtab *ps, *pprev = NULL;
+ int i;
+
+ /* Find its previous psymtab in the chain */
+ for (ps = pst->objfile->psymtabs; ps; ps = ps->next) {
+ if (ps == pst)
+ break;
+ pprev = ps;
+ }
+
+ if (ps) {
+ /* Unhook it from the chain. */
+ if (ps == pst->objfile->psymtabs)
+ pst->objfile->psymtabs = ps->next;
+ else
+ pprev->next = ps->next;
+
+ /* FIXME, we can't conveniently deallocate the entries in the
+ partial_symbol lists (global_psymbols/static_psymbols) that
+ this psymtab points to. These just take up space until all
+ the psymtabs are reclaimed. Ditto the dependencies list and
+ filename, which are all in the psymbol_obstack. */
+
+ /* We need to cashier any psymtab that has this one as a dependency... */
+again:
+ for (ps = pst->objfile->psymtabs; ps; ps = ps->next) {
+ for (i = 0; i < ps->number_of_dependencies; i++) {
+ if (ps->dependencies[i] == pst) {
+ cashier_psymtab (ps);
+ goto again; /* Must restart, chain has been munged. */
+ }
+ }
+ }
+ }
+}
+
+/* If a symtab or psymtab for filename NAME is found, free it along
+ with any dependent breakpoints, displays, etc.
+ Used when loading new versions of object modules with the "add-file"
+ command. This is only called on the top-level symtab or psymtab's name;
+ it is not called for subsidiary files such as .h files.
+
+ Return value is 1 if we blew away the environment, 0 if not.
+ FIXME. The return valu appears to never be used.
+
+ FIXME. I think this is not the best way to do this. We should
+ work on being gentler to the environment while still cleaning up
+ all stray pointers into the freed symtab. */
+
+int
+free_named_symtabs (name)
+ char *name;
+{
+#if 0
+ /* FIXME: With the new method of each objfile having it's own
+ psymtab list, this function needs serious rethinking. In particular,
+ why was it ever necessary to toss psymtabs with specific compilation
+ unit filenames, as opposed to all psymtabs from a particular symbol
+ file? -- fnf
+ Well, the answer is that some systems permit reloading of particular
+ compilation units. We want to blow away any old info about these
+ compilation units, regardless of which objfiles they arrived in. --gnu. */
+
+ register struct symtab *s;
+ register struct symtab *prev;
+ register struct partial_symtab *ps;
+ struct blockvector *bv;
+ int blewit = 0;
+
+ /* We only wack things if the symbol-reload switch is set. */
+ if (!symbol_reloading)
+ return 0;
+
+ /* Some symbol formats have trouble providing file names... */
+ if (name == 0 || *name == '\0')
+ return 0;
+
+ /* Look for a psymtab with the specified name. */
+
+again2:
+ for (ps = partial_symtab_list; ps; ps = ps->next) {
+ if (STREQ (name, ps->filename)) {
+ cashier_psymtab (ps); /* Blow it away...and its little dog, too. */
+ goto again2; /* Must restart, chain has been munged */
+ }
+ }
+
+ /* Look for a symtab with the specified name. */
+
+ for (s = symtab_list; s; s = s->next)
+ {
+ if (STREQ (name, s->filename))
+ break;
+ prev = s;
+ }
+
+ if (s)
+ {
+ if (s == symtab_list)
+ symtab_list = s->next;
+ else
+ prev->next = s->next;
+
+ /* For now, queue a delete for all breakpoints, displays, etc., whether
+ or not they depend on the symtab being freed. This should be
+ changed so that only those data structures affected are deleted. */
+
+ /* But don't delete anything if the symtab is empty.
+ This test is necessary due to a bug in "dbxread.c" that
+ causes empty symtabs to be created for N_SO symbols that
+ contain the pathname of the object file. (This problem
+ has been fixed in GDB 3.9x). */
+
+ bv = BLOCKVECTOR (s);
+ if (BLOCKVECTOR_NBLOCKS (bv) > 2
+ || BLOCK_NSYMS (BLOCKVECTOR_BLOCK (bv, GLOBAL_BLOCK))
+ || BLOCK_NSYMS (BLOCKVECTOR_BLOCK (bv, STATIC_BLOCK)))
+ {
+ complain (&oldsyms_complaint, name);
+
+ clear_symtab_users_queued++;
+ make_cleanup (clear_symtab_users_once, 0);
+ blewit = 1;
+ } else {
+ complain (&empty_symtab_complaint, name);
+ }
+
+ free_symtab (s);
+ }
+ else
+ {
+ /* It is still possible that some breakpoints will be affected
+ even though no symtab was found, since the file might have
+ been compiled without debugging, and hence not be associated
+ with a symtab. In order to handle this correctly, we would need
+ to keep a list of text address ranges for undebuggable files.
+ For now, we do nothing, since this is a fairly obscure case. */
+ ;
+ }
+
+ /* FIXME, what about the minimal symbol table? */
+ return blewit;
+#else
+ return (0);
+#endif
+}
+
+/* Allocate and partially fill a partial symtab. It will be
+ completely filled at the end of the symbol list.
+
+ SYMFILE_NAME is the name of the symbol-file we are reading from, and ADDR
+ is the address relative to which its symbols are (incremental) or 0
+ (normal). */
+
+
+struct partial_symtab *
+start_psymtab_common (objfile, section_offsets,
+ filename, textlow, global_syms, static_syms)
+ struct objfile *objfile;
+ struct section_offsets *section_offsets;
+ char *filename;
+ CORE_ADDR textlow;
+ struct partial_symbol *global_syms;
+ struct partial_symbol *static_syms;
+{
+ struct partial_symtab *psymtab;
+
+ psymtab = allocate_psymtab (filename, objfile);
+ psymtab -> section_offsets = section_offsets;
+ psymtab -> textlow = textlow;
+ psymtab -> texthigh = psymtab -> textlow; /* default */
+ psymtab -> globals_offset = global_syms - objfile -> global_psymbols.list;
+ psymtab -> statics_offset = static_syms - objfile -> static_psymbols.list;
+ return (psymtab);
+}
+
+/* Debugging versions of functions that are usually inline macros
+ (see symfile.h). */
+
+#if !INLINE_ADD_PSYMBOL
+
+/* Add a symbol with a long value to a psymtab.
+ Since one arg is a struct, we pass in a ptr and deref it (sigh). */
+
+void
+add_psymbol_to_list (name, namelength, namespace, class, list, val, language,
+ objfile)
+ char *name;
+ int namelength;
+ enum namespace namespace;
+ enum address_class class;
+ struct psymbol_allocation_list *list;
+ long val;
+ enum language language;
+ struct objfile *objfile;
+{
+ register struct partial_symbol *psym;
+ register char *demangled_name;
+
+ if (list->next >= list->list + list->size)
+ {
+ extend_psymbol_list (list,objfile);
+ }
+ psym = list->next++;
+
+ SYMBOL_NAME (psym) =
+ (char *) obstack_alloc (&objfile->psymbol_obstack, namelength + 1);
+ memcpy (SYMBOL_NAME (psym), name, namelength);
+ SYMBOL_NAME (psym)[namelength] = '\0';
+ SYMBOL_VALUE (psym) = val;
+ SYMBOL_LANGUAGE (psym) = language;
+ PSYMBOL_NAMESPACE (psym) = namespace;
+ PSYMBOL_CLASS (psym) = class;
+ SYMBOL_INIT_DEMANGLED_NAME (psym, &objfile->psymbol_obstack);
+}
+
+/* Add a symbol with a CORE_ADDR value to a psymtab. */
+
+void
+add_psymbol_addr_to_list (name, namelength, namespace, class, list, val,
+ language, objfile)
+ char *name;
+ int namelength;
+ enum namespace namespace;
+ enum address_class class;
+ struct psymbol_allocation_list *list;
+ CORE_ADDR val;
+ enum language language;
+ struct objfile *objfile;
+{
+ register struct partial_symbol *psym;
+ register char *demangled_name;
+
+ if (list->next >= list->list + list->size)
+ {
+ extend_psymbol_list (list,objfile);
+ }
+ psym = list->next++;
+
+ SYMBOL_NAME (psym) =
+ (char *) obstack_alloc (&objfile->psymbol_obstack, namelength + 1);
+ memcpy (SYMBOL_NAME (psym), name, namelength);
+ SYMBOL_NAME (psym)[namelength] = '\0';
+ SYMBOL_VALUE_ADDRESS (psym) = val;
+ SYMBOL_LANGUAGE (psym) = language;
+ PSYMBOL_NAMESPACE (psym) = namespace;
+ PSYMBOL_CLASS (psym) = class;
+ SYMBOL_INIT_DEMANGLED_NAME (psym, &objfile->psymbol_obstack);
+}
+
+#endif /* !INLINE_ADD_PSYMBOL */
+
+
+void
+_initialize_symfile ()
+{
+ struct cmd_list_element *c;
+
+ c = add_cmd ("symbol-file", class_files, symbol_file_command,
+ "Load symbol table from executable file FILE.\n\
+The `file' command can also load symbol tables, as well as setting the file\n\
+to execute.", &cmdlist);
+ c->completer = filename_completer;
+
+ c = add_cmd ("add-symbol-file", class_files, add_symbol_file_command,
+ "Usage: add-symbol-file FILE ADDR\n\
+Load the symbols from FILE, assuming FILE has been dynamically loaded.\n\
+ADDR is the starting address of the file's text.",
+ &cmdlist);
+ c->completer = filename_completer;
+
+ c = add_cmd ("add-shared-symbol-files", class_files,
+ add_shared_symbol_files_command,
+ "Load the symbols from shared objects in the dynamic linker's link map.",
+ &cmdlist);
+ c = add_alias_cmd ("assf", "add-shared-symbol-files", class_files, 1,
+ &cmdlist);
+
+ c = add_cmd ("load", class_files, load_command,
+ "Dynamically load FILE into the running program, and record its symbols\n\
+for access from GDB.", &cmdlist);
+ c->completer = filename_completer;
+
+ add_show_from_set
+ (add_set_cmd ("symbol-reloading", class_support, var_boolean,
+ (char *)&symbol_reloading,
+ "Set dynamic symbol table reloading multiple times in one run.",
+ &setlist),
+ &showlist);
+
+}
diff --git a/gnu/usr.bin/gdb/gdb/symfile.h b/gnu/usr.bin/gdb/gdb/symfile.h
new file mode 100644
index 0000000..17303bb
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/symfile.h
@@ -0,0 +1,250 @@
+/* Definitions for reading symbol files into GDB.
+ Copyright (C) 1990, 1991, 1992 Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#if !defined (SYMFILE_H)
+#define SYMFILE_H
+
+/* This file requires that you first include "bfd.h". */
+
+struct psymbol_allocation_list {
+ struct partial_symbol *list;
+ struct partial_symbol *next;
+ int size;
+};
+
+/* Structure to keep track of symbol reading functions for various
+ object file types. */
+
+struct sym_fns {
+
+ /* BFD flavour that we handle, or (as a special kludge, see xcoffread.c,
+ (enum bfd_flavour)-1 for xcoff). */
+
+ enum bfd_flavour sym_flavour;
+
+ /* Initializes anything that is global to the entire symbol table. It is
+ called during symbol_file_add, when we begin debugging an entirely new
+ program. */
+
+ void (*sym_new_init) PARAMS ((struct objfile *));
+
+ /* Reads any initial information from a symbol file, and initializes the
+ struct sym_fns SF in preparation for sym_read(). It is called every
+ time we read a symbol file for any reason. */
+
+ void (*sym_init) PARAMS ((struct objfile *));
+
+ /* sym_read (objfile, addr, mainline)
+ Reads a symbol file into a psymtab (or possibly a symtab).
+ OBJFILE is the objfile struct for the file we are reading.
+ SECTION_OFFSETS
+ are the offset between the file's specified section addresses and
+ their true addresses in memory.
+ MAINLINE is 1 if this is the
+ main symbol table being read, and 0 if a secondary
+ symbol file (e.g. shared library or dynamically loaded file)
+ is being read. */
+
+ void (*sym_read) PARAMS ((struct objfile *, struct section_offsets *, int));
+
+ /* Called when we are finished with an objfile. Should do all cleanup
+ that is specific to the object file format for the particular objfile. */
+
+ void (*sym_finish) PARAMS ((struct objfile *));
+
+ /* This function produces a file-dependent section_offsets structure,
+ allocated in the objfile's storage, and based on the parameter.
+ The parameter is currently a CORE_ADDR (FIXME!) for backward compatibility
+ with the higher levels of GDB. It should probably be changed to
+ a string, where NULL means the default, and others are parsed in a file
+ dependent way. The result of this function is handed in to sym_read. */
+
+ struct section_offsets *(*sym_offsets) PARAMS ((struct objfile *, CORE_ADDR));
+
+ /* Finds the next struct sym_fns. They are allocated and initialized
+ in whatever module implements the functions pointed to; an
+ initializer calls add_symtab_fns to add them to the global chain. */
+
+ struct sym_fns *next;
+
+};
+
+extern void
+extend_psymbol_list PARAMS ((struct psymbol_allocation_list *,
+ struct objfile *));
+
+/* Add any kind of symbol to a psymbol_allocation_list. */
+
+#ifndef INLINE_ADD_PSYMBOL
+#define INLINE_ADD_PSYMBOL 1
+#endif
+
+#if !INLINE_ADD_PSYMBOL
+
+/* Since one arg is a struct, we have to pass in a ptr and deref it (sigh) */
+
+#define ADD_PSYMBOL_TO_LIST(name, namelength, namespace, class, list, value, language, objfile) \
+ add_psymbol_to_list (name, namelength, namespace, class, &list, value, language, objfile)
+
+#define ADD_PSYMBOL_ADDR_TO_LIST(name, namelength, namespace, class, list, value, language, objfile) \
+ add_psymbol_addr_to_list (name, namelength, namespace, class, &list, value, language, objfile)
+
+#else /* !INLINE_ADD_PSYMBOL */
+
+#include "demangle.h"
+
+#define ADD_PSYMBOL_VT_TO_LIST(NAME,NAMELENGTH,NAMESPACE,CLASS,LIST,VALUE,VT,LANGUAGE, OBJFILE) \
+ do { \
+ register struct partial_symbol *psym; \
+ if ((LIST).next >= (LIST).list + (LIST).size) \
+ extend_psymbol_list (&(LIST),(OBJFILE)); \
+ psym = (LIST).next++; \
+ SYMBOL_NAME (psym) = \
+ (char *) obstack_alloc (&objfile->psymbol_obstack, \
+ (NAMELENGTH) + 1); \
+ memcpy (SYMBOL_NAME (psym), (NAME), (NAMELENGTH)); \
+ SYMBOL_NAME (psym)[(NAMELENGTH)] = '\0'; \
+ SYMBOL_NAMESPACE (psym) = (NAMESPACE); \
+ PSYMBOL_CLASS (psym) = (CLASS); \
+ VT (psym) = (VALUE); \
+ SYMBOL_LANGUAGE (psym) = (LANGUAGE); \
+ SYMBOL_INIT_DEMANGLED_NAME (psym, &objfile->psymbol_obstack); \
+ } while (0)
+
+/* Add a symbol with an integer value to a psymtab. */
+
+#define ADD_PSYMBOL_TO_LIST(name, namelength, namespace, class, list, value, language, objfile) \
+ ADD_PSYMBOL_VT_TO_LIST (name, namelength, namespace, class, list, value, SYMBOL_VALUE, language, objfile)
+
+/* Add a symbol with a CORE_ADDR value to a psymtab. */
+
+#define ADD_PSYMBOL_ADDR_TO_LIST(name, namelength, namespace, class, list, value, language, objfile)\
+ ADD_PSYMBOL_VT_TO_LIST (name, namelength, namespace, class, list, value, SYMBOL_VALUE_ADDRESS, language, objfile)
+
+#endif /* INLINE_ADD_PSYMBOL */
+
+ /* Functions */
+
+extern void
+sort_pst_symbols PARAMS ((struct partial_symtab *));
+
+extern struct symtab *
+allocate_symtab PARAMS ((char *, struct objfile *));
+
+extern int
+free_named_symtabs PARAMS ((char *));
+
+extern void
+fill_in_vptr_fieldno PARAMS ((struct type *));
+
+extern void
+add_symtab_fns PARAMS ((struct sym_fns *));
+
+extern void
+init_entry_point_info PARAMS ((struct objfile *));
+
+extern void
+syms_from_objfile PARAMS ((struct objfile *, CORE_ADDR, int, int));
+
+extern void
+new_symfile_objfile PARAMS ((struct objfile *, int, int));
+
+extern struct partial_symtab *
+start_psymtab_common PARAMS ((struct objfile *, struct section_offsets *,
+ char *, CORE_ADDR,
+ struct partial_symbol *,
+ struct partial_symbol *));
+
+/* Sorting your symbols for fast lookup or alphabetical printing. */
+
+extern void
+sort_block_syms PARAMS ((struct block *));
+
+extern void
+sort_symtab_syms PARAMS ((struct symtab *));
+
+/* Make a copy of the string at PTR with SIZE characters in the symbol obstack
+ (and add a null character at the end in the copy).
+ Returns the address of the copy. */
+
+extern char *
+obsavestring PARAMS ((char *, int, struct obstack *));
+
+/* Concatenate strings S1, S2 and S3; return the new string.
+ Space is found in the symbol_obstack. */
+
+extern char *
+obconcat PARAMS ((struct obstack *obstackp, const char *, const char *,
+ const char *));
+
+ /* Variables */
+
+/* From symfile.c */
+
+extern struct partial_symtab *
+allocate_psymtab PARAMS ((char *, struct objfile *));
+
+/* Remote targets may wish to use this as their load function. */
+extern void generic_load PARAMS ((char *name, int from_tty));
+
+/* From dwarfread.c */
+
+extern void
+dwarf_build_psymtabs PARAMS ((struct objfile *, struct section_offsets *, int,
+ file_ptr, unsigned int, file_ptr, unsigned int));
+
+/* From mdebugread.c */
+
+/* Hack to force structures to exist before use in parameter list. */
+struct ecoff_debug_hack
+{
+ struct ecoff_debug_swap *a;
+ struct ecoff_debug_info *b;
+};
+extern void
+mdebug_build_psymtabs PARAMS ((struct objfile *,
+ const struct ecoff_debug_swap *,
+ struct ecoff_debug_info *,
+ struct section_offsets *));
+
+extern void
+elfmdebug_build_psymtabs PARAMS ((struct objfile *,
+ const struct ecoff_debug_swap *,
+ asection *,
+ struct section_offsets *));
+
+/* From demangle.c */
+
+extern void
+set_demangling_style PARAMS ((char *));
+
+
+/* Stuff shared between coffread.c and xcoffread.c. Eventually we want
+ to merge coffread.c and xcoffread.c so this part of this header can
+ go away. */
+
+#if 0
+extern char *coff_getfilename PARAMS ((union internal_auxent *));
+#else
+/* Don't declare the arguments; if union internal_auxent has not been
+ declared here, gcc1 will give warnings. */
+extern char *coff_getfilename ();
+#endif
+
+#endif /* !defined(SYMFILE_H) */
diff --git a/gnu/usr.bin/gdb/gdb/symmisc.c b/gnu/usr.bin/gdb/gdb/symmisc.c
new file mode 100644
index 0000000..5b3930f
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/symmisc.c
@@ -0,0 +1,988 @@
+/* Do various things to symbol tables (other than lookup), for GDB.
+ Copyright 1986, 1987, 1989, 1991, 1992, 1993, 1994
+ Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "defs.h"
+#include "symtab.h"
+#include "gdbtypes.h"
+#include "bfd.h"
+#include "symfile.h"
+#include "objfiles.h"
+#include "breakpoint.h"
+#include "command.h"
+#include "obstack.h"
+#include "language.h"
+
+#include <string.h>
+
+#ifndef DEV_TTY
+#define DEV_TTY "/dev/tty"
+#endif
+
+/* Unfortunately for debugging, stderr is usually a macro. This is painful
+ when calling functions that take FILE *'s from the debugger.
+ So we make a variable which has the same value and which is accessible when
+ debugging GDB with itself. Because stdin et al need not be constants,
+ we initialize them in the _initialize_symmisc function at the bottom
+ of the file. */
+FILE *std_in;
+FILE *std_out;
+FILE *std_err;
+
+/* Prototypes for local functions */
+
+static void
+dump_symtab PARAMS ((struct objfile *, struct symtab *, GDB_FILE *));
+
+static void
+dump_psymtab PARAMS ((struct objfile *, struct partial_symtab *, GDB_FILE *));
+
+static void
+dump_msymbols PARAMS ((struct objfile *, GDB_FILE *));
+
+static void
+dump_objfile PARAMS ((struct objfile *));
+
+static int
+block_depth PARAMS ((struct block *));
+
+static void
+print_partial_symbol PARAMS ((struct partial_symbol *, int, char *, GDB_FILE *));
+
+struct print_symbol_args {
+ struct symbol *symbol;
+ int depth;
+ GDB_FILE *outfile;
+};
+
+static int print_symbol PARAMS ((char *));
+
+static void
+free_symtab_block PARAMS ((struct objfile *, struct block *));
+
+
+/* Free a struct block <- B and all the symbols defined in that block. */
+
+static void
+free_symtab_block (objfile, b)
+ struct objfile *objfile;
+ struct block *b;
+{
+ register int i, n;
+ n = BLOCK_NSYMS (b);
+ for (i = 0; i < n; i++)
+ {
+ mfree (objfile -> md, SYMBOL_NAME (BLOCK_SYM (b, i)));
+ mfree (objfile -> md, (PTR) BLOCK_SYM (b, i));
+ }
+ mfree (objfile -> md, (PTR) b);
+}
+
+/* Free all the storage associated with the struct symtab <- S.
+ Note that some symtabs have contents malloc'ed structure by structure,
+ while some have contents that all live inside one big block of memory,
+ and some share the contents of another symbol table and so you should
+ not free the contents on their behalf (except sometimes the linetable,
+ which maybe per symtab even when the rest is not).
+ It is s->free_code that says which alternative to use. */
+
+void
+free_symtab (s)
+ register struct symtab *s;
+{
+ register int i, n;
+ register struct blockvector *bv;
+
+ switch (s->free_code)
+ {
+ case free_nothing:
+ /* All the contents are part of a big block of memory (an obstack),
+ and some other symtab is in charge of freeing that block.
+ Therefore, do nothing. */
+ break;
+
+ case free_contents:
+ /* Here all the contents were malloc'ed structure by structure
+ and must be freed that way. */
+ /* First free the blocks (and their symbols. */
+ bv = BLOCKVECTOR (s);
+ n = BLOCKVECTOR_NBLOCKS (bv);
+ for (i = 0; i < n; i++)
+ free_symtab_block (s -> objfile, BLOCKVECTOR_BLOCK (bv, i));
+ /* Free the blockvector itself. */
+ mfree (s -> objfile -> md, (PTR) bv);
+ /* Also free the linetable. */
+
+ case free_linetable:
+ /* Everything will be freed either by our `free_ptr'
+ or by some other symtab, except for our linetable.
+ Free that now. */
+ if (LINETABLE (s))
+ mfree (s -> objfile -> md, (PTR) LINETABLE (s));
+ break;
+ }
+
+ /* If there is a single block of memory to free, free it. */
+ if (s -> free_ptr != NULL)
+ mfree (s -> objfile -> md, s -> free_ptr);
+
+ /* Free source-related stuff */
+ if (s -> line_charpos != NULL)
+ mfree (s -> objfile -> md, (PTR) s -> line_charpos);
+ if (s -> fullname != NULL)
+ mfree (s -> objfile -> md, s -> fullname);
+ mfree (s -> objfile -> md, (PTR) s);
+}
+
+#if MAINTENANCE_CMDS
+
+static void
+dump_objfile (objfile)
+ struct objfile *objfile;
+{
+ struct symtab *symtab;
+ struct partial_symtab *psymtab;
+
+ printf_filtered ("\nObject file %s: ", objfile -> name);
+ printf_filtered ("Objfile at ");
+ gdb_print_address (objfile, gdb_stdout);
+ printf_filtered (", bfd at ");
+ gdb_print_address (objfile->obfd, gdb_stdout);
+ printf_filtered (", %d minsyms\n\n",
+ objfile->minimal_symbol_count);
+
+ if (objfile -> psymtabs)
+ {
+ printf_filtered ("Psymtabs:\n");
+ for (psymtab = objfile -> psymtabs;
+ psymtab != NULL;
+ psymtab = psymtab -> next)
+ {
+ printf_filtered ("%s at ",
+ psymtab -> filename);
+ gdb_print_address (psymtab, gdb_stdout);
+ printf_filtered (", ");
+ if (psymtab -> objfile != objfile)
+ {
+ printf_filtered ("NOT ON CHAIN! ");
+ }
+ wrap_here (" ");
+ }
+ printf_filtered ("\n\n");
+ }
+
+ if (objfile -> symtabs)
+ {
+ printf_filtered ("Symtabs:\n");
+ for (symtab = objfile -> symtabs;
+ symtab != NULL;
+ symtab = symtab->next)
+ {
+ printf_filtered ("%s at ", symtab -> filename);
+ gdb_print_address (symtab, gdb_stdout);
+ printf_filtered (", ");
+ if (symtab -> objfile != objfile)
+ {
+ printf_filtered ("NOT ON CHAIN! ");
+ }
+ wrap_here (" ");
+ }
+ printf_filtered ("\n\n");
+ }
+}
+
+/* Print minimal symbols from this objfile. */
+
+static void
+dump_msymbols (objfile, outfile)
+ struct objfile *objfile;
+ GDB_FILE *outfile;
+{
+ struct minimal_symbol *msymbol;
+ int index;
+ char ms_type;
+
+ fprintf_filtered (outfile, "\nObject file %s:\n\n", objfile -> name);
+ if (objfile -> minimal_symbol_count == 0)
+ {
+ fprintf_filtered (outfile, "No minimal symbols found.\n");
+ return;
+ }
+ for (index = 0, msymbol = objfile -> msymbols;
+ SYMBOL_NAME (msymbol) != NULL; msymbol++, index++)
+ {
+ switch (msymbol -> type)
+ {
+ case mst_unknown:
+ ms_type = 'u';
+ break;
+ case mst_text:
+ ms_type = 'T';
+ break;
+ case mst_solib_trampoline:
+ ms_type = 'S';
+ break;
+ case mst_data:
+ ms_type = 'D';
+ break;
+ case mst_bss:
+ ms_type = 'B';
+ break;
+ case mst_abs:
+ ms_type = 'A';
+ break;
+ case mst_file_text:
+ ms_type = 't';
+ break;
+ case mst_file_data:
+ ms_type = 'd';
+ break;
+ case mst_file_bss:
+ ms_type = 'b';
+ break;
+ default:
+ ms_type = '?';
+ break;
+ }
+ fprintf_filtered (outfile, "[%2d] %c %#10lx %s", index, ms_type,
+ SYMBOL_VALUE_ADDRESS (msymbol), SYMBOL_NAME (msymbol));
+ if (SYMBOL_DEMANGLED_NAME (msymbol) != NULL)
+ {
+ fprintf_filtered (outfile, " %s", SYMBOL_DEMANGLED_NAME (msymbol));
+ }
+ fputs_filtered ("\n", outfile);
+ }
+ if (objfile -> minimal_symbol_count != index)
+ {
+ warning ("internal error: minimal symbol count %d != %d",
+ objfile -> minimal_symbol_count, index);
+ }
+ fprintf_filtered (outfile, "\n");
+}
+
+static void
+dump_psymtab (objfile, psymtab, outfile)
+ struct objfile *objfile;
+ struct partial_symtab *psymtab;
+ GDB_FILE *outfile;
+{
+ int i;
+
+ fprintf_filtered (outfile, "\nPartial symtab for source file %s ",
+ psymtab -> filename);
+ fprintf_filtered (outfile, "(object ");
+ gdb_print_address (psymtab, outfile);
+ fprintf_filtered (outfile, ")\n\n");
+ fprintf_unfiltered (outfile, " Read from object file %s (",
+ objfile -> name);
+ gdb_print_address (objfile, outfile);
+ fprintf_unfiltered (outfile, ")\n");
+
+ if (psymtab -> readin)
+ {
+ fprintf_filtered (outfile,
+ " Full symtab was read (at ");
+ gdb_print_address (psymtab->symtab, outfile);
+ fprintf_filtered (outfile, " by function at ");
+ gdb_print_address ((PTR)psymtab->read_symtab, outfile);
+ fprintf_filtered (outfile, ")\n");
+ }
+
+ fprintf_filtered (outfile, " Relocate symbols by ");
+ for (i = 0; i < psymtab->objfile->num_sections; ++i)
+ {
+ if (i != 0)
+ fprintf_filtered (outfile, ", ");
+ wrap_here (" ");
+ print_address_numeric (ANOFFSET (psymtab->section_offsets, i),
+ 1,
+ outfile);
+ }
+ fprintf_filtered (outfile, "\n");
+
+ fprintf_filtered (outfile, " Symbols cover text addresses ");
+ print_address_numeric (psymtab->textlow, 1, outfile);
+ fprintf_filtered (outfile, "-");
+ print_address_numeric (psymtab->texthigh, 1, outfile);
+ fprintf_filtered (outfile, "\n");
+ fprintf_filtered (outfile, " Depends on %d other partial symtabs.\n",
+ psymtab -> number_of_dependencies);
+ for (i = 0; i < psymtab -> number_of_dependencies; i++)
+ {
+ fprintf_filtered (outfile, " %d ", i);
+ gdb_print_address (psymtab -> dependencies[i], outfile);
+ fprintf_filtered (outfile, " %s\n",
+ psymtab -> dependencies[i] -> filename);
+ }
+ if (psymtab -> n_global_syms > 0)
+ {
+ print_partial_symbol (objfile -> global_psymbols.list
+ + psymtab -> globals_offset,
+ psymtab -> n_global_syms, "Global", outfile);
+ }
+ if (psymtab -> n_static_syms > 0)
+ {
+ print_partial_symbol (objfile -> static_psymbols.list
+ + psymtab -> statics_offset,
+ psymtab -> n_static_syms, "Static", outfile);
+ }
+ fprintf_filtered (outfile, "\n");
+}
+
+static void
+dump_symtab (objfile, symtab, outfile)
+ struct objfile *objfile;
+ struct symtab *symtab;
+ GDB_FILE *outfile;
+{
+ register int i, j;
+ int len, blen;
+ register struct linetable *l;
+ struct blockvector *bv;
+ register struct block *b;
+ int depth;
+
+ fprintf_filtered (outfile, "\nSymtab for file %s\n", symtab->filename);
+ fprintf_filtered (outfile, "Read from object file %s (", objfile->name);
+ gdb_print_address (objfile, outfile);
+ fprintf_filtered (outfile, ")\n");
+ fprintf_filtered (outfile, "Language: %s\n", language_str (symtab -> language));
+
+ /* First print the line table. */
+ l = LINETABLE (symtab);
+ if (l)
+ {
+ fprintf_filtered (outfile, "\nLine table:\n\n");
+ len = l->nitems;
+ for (i = 0; i < len; i++)
+ {
+ fprintf_filtered (outfile, " line %d at ", l->item[i].line);
+ print_address_numeric (l->item[i].pc, 1, outfile);
+ fprintf_filtered (outfile, "\n");
+ }
+ }
+ /* Now print the block info. */
+ fprintf_filtered (outfile, "\nBlockvector:\n\n");
+ bv = BLOCKVECTOR (symtab);
+ len = BLOCKVECTOR_NBLOCKS (bv);
+ for (i = 0; i < len; i++)
+ {
+ b = BLOCKVECTOR_BLOCK (bv, i);
+ depth = block_depth (b) * 2;
+ print_spaces (depth, outfile);
+ fprintf_filtered (outfile, "block #%03d (object ", i);
+ gdb_print_address (b, outfile);
+ fprintf_filtered (outfile, ") ");
+ fprintf_filtered (outfile, "[");
+ print_address_numeric (BLOCK_START (b), 1, outfile);
+ fprintf_filtered (outfile, "..");
+ print_address_numeric (BLOCK_END (b), 1, outfile);
+ fprintf_filtered (outfile, "]");
+ if (BLOCK_SUPERBLOCK (b))
+ {
+ fprintf_filtered (outfile, " (under ");
+ gdb_print_address (BLOCK_SUPERBLOCK (b), outfile);
+ fprintf_filtered (outfile, ")");
+ }
+ if (BLOCK_FUNCTION (b))
+ {
+ fprintf_filtered (outfile, " %s", SYMBOL_NAME (BLOCK_FUNCTION (b)));
+ if (SYMBOL_DEMANGLED_NAME (BLOCK_FUNCTION (b)) != NULL)
+ {
+ fprintf_filtered (outfile, " %s",
+ SYMBOL_DEMANGLED_NAME (BLOCK_FUNCTION (b)));
+ }
+ }
+ if (BLOCK_GCC_COMPILED(b))
+ fprintf_filtered (outfile, " gcc%d compiled", BLOCK_GCC_COMPILED(b));
+ fprintf_filtered (outfile, "\n");
+ blen = BLOCK_NSYMS (b);
+ for (j = 0; j < blen; j++)
+ {
+ struct print_symbol_args s;
+ s.symbol = BLOCK_SYM (b, j);
+ s.depth = depth + 1;
+ s.outfile = outfile;
+ catch_errors (print_symbol, &s, "Error printing symbol:\n",
+ RETURN_MASK_ERROR);
+ }
+ }
+ fprintf_filtered (outfile, "\n");
+}
+
+void
+maintenance_print_symbols (args, from_tty)
+ char *args;
+ int from_tty;
+{
+ char **argv;
+ GDB_FILE *outfile;
+ struct cleanup *cleanups;
+ char *symname = NULL;
+ char *filename = DEV_TTY;
+ struct objfile *objfile;
+ struct symtab *s;
+
+ dont_repeat ();
+
+ if (args == NULL)
+ {
+ error ("\
+Arguments missing: an output file name and an optional symbol file name");
+ }
+ else if ((argv = buildargv (args)) == NULL)
+ {
+ nomem (0);
+ }
+ cleanups = make_cleanup (freeargv, (char *) argv);
+
+ if (argv[0] != NULL)
+ {
+ filename = argv[0];
+ /* If a second arg is supplied, it is a source file name to match on */
+ if (argv[1] != NULL)
+ {
+ symname = argv[1];
+ }
+ }
+
+ filename = tilde_expand (filename);
+ make_cleanup (free, filename);
+
+ outfile = gdb_fopen (filename, FOPEN_WT);
+ if (outfile == 0)
+ perror_with_name (filename);
+ make_cleanup (fclose, (char *) outfile);
+
+ immediate_quit++;
+ ALL_SYMTABS (objfile, s)
+ if (symname == NULL || (STREQ (symname, s -> filename)))
+ dump_symtab (objfile, s, outfile);
+ immediate_quit--;
+ do_cleanups (cleanups);
+}
+
+/* Print symbol ARGS->SYMBOL on ARGS->OUTFILE. ARGS->DEPTH says how
+ far to indent. ARGS is really a struct print_symbol_args *, but is
+ declared as char * to get it past catch_errors. Returns 0 for error,
+ 1 for success. */
+
+static int
+print_symbol (args)
+ char *args;
+{
+ struct symbol *symbol = ((struct print_symbol_args *)args)->symbol;
+ int depth = ((struct print_symbol_args *)args)->depth;
+ GDB_FILE *outfile = ((struct print_symbol_args *)args)->outfile;
+
+ print_spaces (depth, outfile);
+ if (SYMBOL_NAMESPACE (symbol) == LABEL_NAMESPACE)
+ {
+ fprintf_filtered (outfile, "label %s at ", SYMBOL_SOURCE_NAME (symbol));
+ print_address_numeric (SYMBOL_VALUE_ADDRESS (symbol), 1, outfile);
+ fprintf_filtered (outfile, "\n");
+ return 1;
+ }
+ if (SYMBOL_NAMESPACE (symbol) == STRUCT_NAMESPACE)
+ {
+ if (TYPE_TAG_NAME (SYMBOL_TYPE (symbol)))
+ {
+ LA_PRINT_TYPE (SYMBOL_TYPE (symbol), "", outfile, 1, depth);
+ }
+ else
+ {
+ fprintf_filtered (outfile, "%s %s = ",
+ (TYPE_CODE (SYMBOL_TYPE (symbol)) == TYPE_CODE_ENUM
+ ? "enum"
+ : (TYPE_CODE (SYMBOL_TYPE (symbol)) == TYPE_CODE_STRUCT
+ ? "struct" : "union")),
+ SYMBOL_NAME (symbol));
+ LA_PRINT_TYPE (SYMBOL_TYPE (symbol), "", outfile, 1, depth);
+ }
+ fprintf_filtered (outfile, ";\n");
+ }
+ else
+ {
+ if (SYMBOL_CLASS (symbol) == LOC_TYPEDEF)
+ fprintf_filtered (outfile, "typedef ");
+ if (SYMBOL_TYPE (symbol))
+ {
+ /* Print details of types, except for enums where it's clutter. */
+ LA_PRINT_TYPE (SYMBOL_TYPE (symbol), SYMBOL_SOURCE_NAME (symbol),
+ outfile,
+ TYPE_CODE (SYMBOL_TYPE (symbol)) != TYPE_CODE_ENUM,
+ depth);
+ fprintf_filtered (outfile, "; ");
+ }
+ else
+ fprintf_filtered (outfile, "%s ", SYMBOL_SOURCE_NAME (symbol));
+
+ switch (SYMBOL_CLASS (symbol))
+ {
+ case LOC_CONST:
+ fprintf_filtered (outfile, "const %ld (0x%lx),",
+ SYMBOL_VALUE (symbol),
+ SYMBOL_VALUE (symbol));
+ break;
+
+ case LOC_CONST_BYTES:
+ fprintf_filtered (outfile, "const %u hex bytes:",
+ TYPE_LENGTH (SYMBOL_TYPE (symbol)));
+ {
+ unsigned i;
+ for (i = 0; i < TYPE_LENGTH (SYMBOL_TYPE (symbol)); i++)
+ fprintf_filtered (outfile, " %02x",
+ (unsigned)SYMBOL_VALUE_BYTES (symbol) [i]);
+ fprintf_filtered (outfile, ",");
+ }
+ break;
+
+ case LOC_STATIC:
+ fprintf_filtered (outfile, "static at ");
+ print_address_numeric (SYMBOL_VALUE_ADDRESS (symbol), 1,outfile);
+ fprintf_filtered (outfile, ",");
+ break;
+
+ case LOC_REGISTER:
+ fprintf_filtered (outfile, "register %ld,", SYMBOL_VALUE (symbol));
+ break;
+
+ case LOC_ARG:
+ fprintf_filtered (outfile, "arg at offset 0x%lx,",
+ SYMBOL_VALUE (symbol));
+ break;
+
+ case LOC_LOCAL_ARG:
+ fprintf_filtered (outfile, "arg at offset 0x%lx from fp,",
+ SYMBOL_VALUE (symbol));
+ break;
+
+ case LOC_REF_ARG:
+ fprintf_filtered (outfile, "reference arg at 0x%lx,", SYMBOL_VALUE (symbol));
+ break;
+
+ case LOC_REGPARM:
+ fprintf_filtered (outfile, "parameter register %ld,", SYMBOL_VALUE (symbol));
+ break;
+
+ case LOC_REGPARM_ADDR:
+ fprintf_filtered (outfile, "address parameter register %ld,", SYMBOL_VALUE (symbol));
+ break;
+
+ case LOC_LOCAL:
+ fprintf_filtered (outfile, "local at offset 0x%lx,",
+ SYMBOL_VALUE (symbol));
+ break;
+
+ case LOC_BASEREG:
+ fprintf_filtered (outfile, "local at 0x%lx from register %d",
+ SYMBOL_VALUE (symbol), SYMBOL_BASEREG (symbol));
+ break;
+
+ case LOC_BASEREG_ARG:
+ fprintf_filtered (outfile, "arg at 0x%lx from register %d,",
+ SYMBOL_VALUE (symbol), SYMBOL_BASEREG (symbol));
+ break;
+
+ case LOC_TYPEDEF:
+ break;
+
+ case LOC_LABEL:
+ fprintf_filtered (outfile, "label at ");
+ print_address_numeric (SYMBOL_VALUE_ADDRESS (symbol), 1, outfile);
+ break;
+
+ case LOC_BLOCK:
+ fprintf_filtered (outfile, "block (object ");
+ gdb_print_address (SYMBOL_BLOCK_VALUE (symbol), outfile);
+ fprintf_filtered (outfile, ") starting at ");
+ print_address_numeric (BLOCK_START (SYMBOL_BLOCK_VALUE (symbol)),
+ 1,
+ outfile);
+ fprintf_filtered (outfile, ",");
+ break;
+
+ case LOC_OPTIMIZED_OUT:
+ fprintf_filtered (outfile, "optimized out");
+ break;
+
+ default:
+ fprintf_filtered (outfile, "botched symbol class %x",
+ SYMBOL_CLASS (symbol));
+ break;
+ }
+ }
+ fprintf_filtered (outfile, "\n");
+ return 1;
+}
+
+void
+maintenance_print_psymbols (args, from_tty)
+ char *args;
+ int from_tty;
+{
+ char **argv;
+ GDB_FILE *outfile;
+ struct cleanup *cleanups;
+ char *symname = NULL;
+ char *filename = DEV_TTY;
+ struct objfile *objfile;
+ struct partial_symtab *ps;
+
+ dont_repeat ();
+
+ if (args == NULL)
+ {
+ error ("print-psymbols takes an output file name and optional symbol file name");
+ }
+ else if ((argv = buildargv (args)) == NULL)
+ {
+ nomem (0);
+ }
+ cleanups = make_cleanup (freeargv, (char *) argv);
+
+ if (argv[0] != NULL)
+ {
+ filename = argv[0];
+ /* If a second arg is supplied, it is a source file name to match on */
+ if (argv[1] != NULL)
+ {
+ symname = argv[1];
+ }
+ }
+
+ filename = tilde_expand (filename);
+ make_cleanup (free, filename);
+
+ outfile = gdb_fopen (filename, FOPEN_WT);
+ if (outfile == 0)
+ perror_with_name (filename);
+ make_cleanup (fclose, outfile);
+
+ immediate_quit++;
+ ALL_PSYMTABS (objfile, ps)
+ if (symname == NULL || (STREQ (symname, ps -> filename)))
+ dump_psymtab (objfile, ps, outfile);
+ immediate_quit--;
+ do_cleanups (cleanups);
+}
+
+static void
+print_partial_symbol (p, count, what, outfile)
+ struct partial_symbol *p;
+ int count;
+ char *what;
+ GDB_FILE *outfile;
+{
+
+ fprintf_filtered (outfile, " %s partial symbols:\n", what);
+ while (count-- > 0)
+ {
+ fprintf_filtered (outfile, " `%s'", SYMBOL_NAME(p));
+ if (SYMBOL_DEMANGLED_NAME (p) != NULL)
+ {
+ fprintf_filtered (outfile, " `%s'", SYMBOL_DEMANGLED_NAME (p));
+ }
+ fputs_filtered (", ", outfile);
+ switch (SYMBOL_NAMESPACE (p))
+ {
+ case UNDEF_NAMESPACE:
+ fputs_filtered ("undefined namespace, ", outfile);
+ break;
+ case VAR_NAMESPACE:
+ /* This is the usual thing -- don't print it */
+ break;
+ case STRUCT_NAMESPACE:
+ fputs_filtered ("struct namespace, ", outfile);
+ break;
+ case LABEL_NAMESPACE:
+ fputs_filtered ("label namespace, ", outfile);
+ break;
+ default:
+ fputs_filtered ("<invalid namespace>, ", outfile);
+ break;
+ }
+ switch (SYMBOL_CLASS (p))
+ {
+ case LOC_UNDEF:
+ fputs_filtered ("undefined", outfile);
+ break;
+ case LOC_CONST:
+ fputs_filtered ("constant int", outfile);
+ break;
+ case LOC_STATIC:
+ fputs_filtered ("static", outfile);
+ break;
+ case LOC_REGISTER:
+ fputs_filtered ("register", outfile);
+ break;
+ case LOC_ARG:
+ fputs_filtered ("pass by value", outfile);
+ break;
+ case LOC_REF_ARG:
+ fputs_filtered ("pass by reference", outfile);
+ break;
+ case LOC_REGPARM:
+ fputs_filtered ("register parameter", outfile);
+ break;
+ case LOC_REGPARM_ADDR:
+ fputs_filtered ("register address parameter", outfile);
+ break;
+ case LOC_LOCAL:
+ fputs_filtered ("stack parameter", outfile);
+ break;
+ case LOC_TYPEDEF:
+ fputs_filtered ("type", outfile);
+ break;
+ case LOC_LABEL:
+ fputs_filtered ("label", outfile);
+ break;
+ case LOC_BLOCK:
+ fputs_filtered ("function", outfile);
+ break;
+ case LOC_CONST_BYTES:
+ fputs_filtered ("constant bytes", outfile);
+ break;
+ case LOC_LOCAL_ARG:
+ fputs_filtered ("shuffled arg", outfile);
+ break;
+ case LOC_OPTIMIZED_OUT:
+ fputs_filtered ("optimized out", outfile);
+ break;
+ default:
+ fputs_filtered ("<invalid location>", outfile);
+ break;
+ }
+ fputs_filtered (", ", outfile);
+ /* FIXME-32x64: Need to use SYMBOL_VALUE_ADDRESS, etc.; this
+ could be 32 bits when some of the other fields in the union
+ are 64. */
+ fprintf_filtered (outfile, "0x%lx\n", SYMBOL_VALUE (p));
+ p++;
+ }
+}
+
+void
+maintenance_print_msymbols (args, from_tty)
+ char *args;
+ int from_tty;
+{
+ char **argv;
+ GDB_FILE *outfile;
+ struct cleanup *cleanups;
+ char *filename = DEV_TTY;
+ char *symname = NULL;
+ struct objfile *objfile;
+
+ dont_repeat ();
+
+ if (args == NULL)
+ {
+ error ("print-msymbols takes an output file name and optional symbol file name");
+ }
+ else if ((argv = buildargv (args)) == NULL)
+ {
+ nomem (0);
+ }
+ cleanups = make_cleanup (freeargv, argv);
+
+ if (argv[0] != NULL)
+ {
+ filename = argv[0];
+ /* If a second arg is supplied, it is a source file name to match on */
+ if (argv[1] != NULL)
+ {
+ symname = argv[1];
+ }
+ }
+
+ filename = tilde_expand (filename);
+ make_cleanup (free, filename);
+
+ outfile = gdb_fopen (filename, FOPEN_WT);
+ if (outfile == 0)
+ perror_with_name (filename);
+ make_cleanup (fclose, outfile);
+
+ immediate_quit++;
+ ALL_OBJFILES (objfile)
+ if (symname == NULL || (STREQ (symname, objfile -> name)))
+ dump_msymbols (objfile, outfile);
+ immediate_quit--;
+ fprintf_filtered (outfile, "\n\n");
+ do_cleanups (cleanups);
+}
+
+void
+maintenance_print_objfiles (ignore, from_tty)
+ char *ignore;
+ int from_tty;
+{
+ struct objfile *objfile;
+
+ dont_repeat ();
+
+ immediate_quit++;
+ ALL_OBJFILES (objfile)
+ dump_objfile (objfile);
+ immediate_quit--;
+}
+
+/* Check consistency of psymtabs and symtabs. */
+
+void
+maintenance_check_symtabs (ignore, from_tty)
+ char *ignore;
+ int from_tty;
+{
+ register struct symbol *sym;
+ register struct partial_symbol *psym;
+ register struct symtab *s = NULL;
+ register struct partial_symtab *ps;
+ struct blockvector *bv;
+ register struct objfile *objfile;
+ register struct block *b;
+ int length;
+
+ ALL_PSYMTABS (objfile, ps)
+ {
+ s = PSYMTAB_TO_SYMTAB(ps);
+ if (s == NULL)
+ continue;
+ bv = BLOCKVECTOR (s);
+ b = BLOCKVECTOR_BLOCK (bv, STATIC_BLOCK);
+ psym = ps->objfile->static_psymbols.list + ps->statics_offset;
+ length = ps->n_static_syms;
+ while (length--)
+ {
+ sym = lookup_block_symbol (b, SYMBOL_NAME (psym),
+ SYMBOL_NAMESPACE (psym));
+ if (!sym)
+ {
+ printf_filtered ("Static symbol `");
+ puts_filtered (SYMBOL_NAME (psym));
+ printf_filtered ("' only found in ");
+ puts_filtered (ps->filename);
+ printf_filtered (" psymtab\n");
+ }
+ psym++;
+ }
+ b = BLOCKVECTOR_BLOCK (bv, GLOBAL_BLOCK);
+ psym = ps->objfile->global_psymbols.list + ps->globals_offset;
+ length = ps->n_global_syms;
+ while (length--)
+ {
+ sym = lookup_block_symbol (b, SYMBOL_NAME (psym),
+ SYMBOL_NAMESPACE (psym));
+ if (!sym)
+ {
+ printf_filtered ("Global symbol `");
+ puts_filtered (SYMBOL_NAME (psym));
+ printf_filtered ("' only found in ");
+ puts_filtered (ps->filename);
+ printf_filtered (" psymtab\n");
+ }
+ psym++;
+ }
+ if (ps->texthigh < ps->textlow)
+ {
+ printf_filtered ("Psymtab ");
+ puts_filtered (ps->filename);
+ printf_filtered (" covers bad range ");
+ print_address_numeric (ps->textlow, 1, stdout);
+ printf_filtered (" - ");
+ print_address_numeric (ps->texthigh, 1, stdout);
+ printf_filtered ("\n");
+ continue;
+ }
+ if (ps->texthigh == 0)
+ continue;
+ if (ps->textlow < BLOCK_START (b) || ps->texthigh > BLOCK_END (b))
+ {
+ printf_filtered ("Psymtab ");
+ puts_filtered (ps->filename);
+ printf_filtered (" covers ");
+ print_address_numeric (ps->textlow, 1, stdout);
+ printf_filtered (" - ");
+ print_address_numeric (ps->texthigh, 1, stdout);
+ printf_filtered (" but symtab covers only ");
+ print_address_numeric (BLOCK_START (b), 1, stdout);
+ printf_filtered (" - ");
+ print_address_numeric (BLOCK_END (b), 1, stdout);
+ printf_filtered ("\n");
+ }
+ }
+}
+
+
+/* Return the nexting depth of a block within other blocks in its symtab. */
+
+static int
+block_depth (block)
+ struct block *block;
+{
+ register int i = 0;
+ while ((block = BLOCK_SUPERBLOCK (block)) != NULL)
+ {
+ i++;
+ }
+ return i;
+}
+
+#endif /* MAINTENANCE_CMDS */
+
+
+/* Increase the space allocated for LISTP, which is probably
+ global_psymbol_list or static_psymbol_list. This space will eventually
+ be freed in free_objfile(). */
+
+void
+extend_psymbol_list (listp, objfile)
+ register struct psymbol_allocation_list *listp;
+ struct objfile *objfile;
+{
+ int new_size;
+ if (listp->size == 0)
+ {
+ new_size = 255;
+ listp->list = (struct partial_symbol *)
+ xmmalloc (objfile -> md, new_size * sizeof (struct partial_symbol));
+ }
+ else
+ {
+ new_size = listp->size * 2;
+ listp->list = (struct partial_symbol *)
+ xmrealloc (objfile -> md, (char *) listp->list,
+ new_size * sizeof (struct partial_symbol));
+ }
+ /* Next assumes we only went one over. Should be good if
+ program works correctly */
+ listp->next = listp->list + listp->size;
+ listp->size = new_size;
+}
+
+
+/* Do early runtime initializations. */
+void
+_initialize_symmisc ()
+{
+ std_in = stdin;
+ std_out = stdout;
+ std_err = stderr;
+}
diff --git a/gnu/usr.bin/gdb/gdb/symtab.c b/gnu/usr.bin/gdb/gdb/symtab.c
new file mode 100644
index 0000000..eab46ce
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/symtab.c
@@ -0,0 +1,3251 @@
+/* Symbol table lookup for the GNU debugger, GDB.
+ Copyright 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994
+ Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "defs.h"
+#include "symtab.h"
+#include "gdbtypes.h"
+#include "gdbcore.h"
+#include "frame.h"
+#include "target.h"
+#include "value.h"
+#include "symfile.h"
+#include "objfiles.h"
+#include "gdbcmd.h"
+#include "call-cmds.h"
+#include "gnuregex.h"
+#include "expression.h"
+#include "language.h"
+#include "demangle.h"
+
+#include <obstack.h>
+
+#include <sys/types.h>
+#include <fcntl.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <ctype.h>
+
+/* Prototypes for local functions */
+
+extern int
+find_methods PARAMS ((struct type *, char *, struct symbol **));
+
+static void
+completion_list_add_name PARAMS ((char *, char *, int, char *, char *));
+
+static void
+build_canonical_line_spec PARAMS ((struct symtab_and_line *, char *, char ***));
+
+static struct symtabs_and_lines
+decode_line_2 PARAMS ((struct symbol *[], int, int, char ***));
+
+static void
+rbreak_command PARAMS ((char *, int));
+
+static void
+types_info PARAMS ((char *, int));
+
+static void
+functions_info PARAMS ((char *, int));
+
+static void
+variables_info PARAMS ((char *, int));
+
+static void
+sources_info PARAMS ((char *, int));
+
+static void
+list_symbols PARAMS ((char *, int, int, int));
+
+static void
+output_source_filename PARAMS ((char *, int *));
+
+static char *
+operator_chars PARAMS ((char *, char **));
+
+static int find_line_common PARAMS ((struct linetable *, int, int *));
+
+static struct partial_symbol *
+lookup_partial_symbol PARAMS ((struct partial_symtab *, const char *,
+ int, enum namespace));
+
+static struct symtab *
+lookup_symtab_1 PARAMS ((char *));
+
+/* */
+
+/* The single non-language-specific builtin type */
+struct type *builtin_type_error;
+
+/* Block in which the most recently searched-for symbol was found.
+ Might be better to make this a parameter to lookup_symbol and
+ value_of_this. */
+
+const struct block *block_found;
+
+char no_symtab_msg[] = "No symbol table is loaded. Use the \"file\" command.";
+
+/* While the C++ support is still in flux, issue a possibly helpful hint on
+ using the new command completion feature on single quoted demangled C++
+ symbols. Remove when loose ends are cleaned up. FIXME -fnf */
+
+void
+cplusplus_hint (name)
+ char *name;
+{
+ printf_filtered ("Hint: try '%s<TAB> or '%s<ESC-?>\n", name, name);
+ printf_filtered ("(Note leading single quote.)\n");
+}
+
+/* Check for a symtab of a specific name; first in symtabs, then in
+ psymtabs. *If* there is no '/' in the name, a match after a '/'
+ in the symtab filename will also work. */
+
+static struct symtab *
+lookup_symtab_1 (name)
+ char *name;
+{
+ register struct symtab *s;
+ register struct partial_symtab *ps;
+ register char *slash;
+ register struct objfile *objfile;
+
+ got_symtab:
+
+ /* First, search for an exact match */
+
+ ALL_SYMTABS (objfile, s)
+ if (STREQ (name, s->filename))
+ return s;
+
+ slash = strchr (name, '/');
+
+ /* Now, search for a matching tail (only if name doesn't have any dirs) */
+
+ if (!slash)
+ ALL_SYMTABS (objfile, s)
+ {
+ char *p = s -> filename;
+ char *tail = strrchr (p, '/');
+
+ if (tail)
+ p = tail + 1;
+
+ if (STREQ (p, name))
+ return s;
+ }
+
+ /* Same search rules as above apply here, but now we look thru the
+ psymtabs. */
+
+ ps = lookup_partial_symtab (name);
+ if (!ps)
+ return (NULL);
+
+ if (ps -> readin)
+ error ("Internal: readin %s pst for `%s' found when no symtab found.",
+ ps -> filename, name);
+
+ s = PSYMTAB_TO_SYMTAB (ps);
+
+ if (s)
+ return s;
+
+ /* At this point, we have located the psymtab for this file, but
+ the conversion to a symtab has failed. This usually happens
+ when we are looking up an include file. In this case,
+ PSYMTAB_TO_SYMTAB doesn't return a symtab, even though one has
+ been created. So, we need to run through the symtabs again in
+ order to find the file.
+ XXX - This is a crock, and should be fixed inside of the the
+ symbol parsing routines. */
+ goto got_symtab;
+}
+
+/* Lookup the symbol table of a source file named NAME. Try a couple
+ of variations if the first lookup doesn't work. */
+
+struct symtab *
+lookup_symtab (name)
+ char *name;
+{
+ register struct symtab *s;
+#if 0
+ register char *copy;
+#endif
+
+ s = lookup_symtab_1 (name);
+ if (s) return s;
+
+#if 0
+ /* This screws c-exp.y:yylex if there is both a type "tree" and a symtab
+ "tree.c". */
+
+ /* If name not found as specified, see if adding ".c" helps. */
+ /* Why is this? Is it just a user convenience? (If so, it's pretty
+ questionable in the presence of C++, FORTRAN, etc.). It's not in
+ the GDB manual. */
+
+ copy = (char *) alloca (strlen (name) + 3);
+ strcpy (copy, name);
+ strcat (copy, ".c");
+ s = lookup_symtab_1 (copy);
+ if (s) return s;
+#endif /* 0 */
+
+ /* We didn't find anything; die. */
+ return 0;
+}
+
+/* Lookup the partial symbol table of a source file named NAME.
+ *If* there is no '/' in the name, a match after a '/'
+ in the psymtab filename will also work. */
+
+struct partial_symtab *
+lookup_partial_symtab (name)
+char *name;
+{
+ register struct partial_symtab *pst;
+ register struct objfile *objfile;
+
+ ALL_PSYMTABS (objfile, pst)
+ {
+ if (STREQ (name, pst -> filename))
+ {
+ return (pst);
+ }
+ }
+
+ /* Now, search for a matching tail (only if name doesn't have any dirs) */
+
+ if (!strchr (name, '/'))
+ ALL_PSYMTABS (objfile, pst)
+ {
+ char *p = pst -> filename;
+ char *tail = strrchr (p, '/');
+
+ if (tail)
+ p = tail + 1;
+
+ if (STREQ (p, name))
+ return (pst);
+ }
+
+ return (NULL);
+}
+
+/* Demangle a GDB method stub type.
+ Note that this function is g++ specific. */
+
+char *
+gdb_mangle_name (type, i, j)
+ struct type *type;
+ int i, j;
+{
+ int mangled_name_len;
+ char *mangled_name;
+ struct fn_field *f = TYPE_FN_FIELDLIST1 (type, i);
+ struct fn_field *method = &f[j];
+ char *field_name = TYPE_FN_FIELDLIST_NAME (type, i);
+ char *physname = TYPE_FN_FIELD_PHYSNAME (f, j);
+ char *newname = type_name_no_tag (type);
+
+ /* Does the form of physname indicate that it is the full mangled name
+ of a constructor (not just the args)? */
+ int is_full_physname_constructor;
+
+ int is_constructor;
+ int is_destructor = DESTRUCTOR_PREFIX_P (physname);
+ /* Need a new type prefix. */
+ char *const_prefix = method->is_const ? "C" : "";
+ char *volatile_prefix = method->is_volatile ? "V" : "";
+ char buf[20];
+ int len = (newname == NULL ? 0 : strlen (newname));
+
+ is_full_physname_constructor =
+ ((physname[0]=='_' && physname[1]=='_' &&
+ (isdigit(physname[2]) || physname[2]=='Q' || physname[2]=='t'))
+ || (strncmp(physname, "__ct", 4) == 0));
+
+ is_constructor =
+ is_full_physname_constructor || (newname && STREQ(field_name, newname));
+
+ if (!is_destructor)
+ is_destructor = (strncmp(physname, "__dt", 4) == 0);
+
+#ifndef GCC_MANGLE_BUG
+ if (is_destructor || is_full_physname_constructor)
+ {
+ mangled_name = (char*) xmalloc(strlen(physname)+1);
+ strcpy(mangled_name, physname);
+ return mangled_name;
+ }
+
+ if (len == 0)
+ {
+ sprintf (buf, "__%s%s", const_prefix, volatile_prefix);
+ if (strcmp(buf, "__") == 0)
+ buf[0] = '\0';
+ }
+ else
+ {
+ sprintf (buf, "__%s%s%d", const_prefix, volatile_prefix, len);
+ }
+ mangled_name_len = ((is_constructor ? 0 : strlen (field_name))
+ + strlen (buf) + len
+ + strlen (physname)
+ + 1);
+
+ /* Only needed for GNU-mangled names. ANSI-mangled names
+ work with the normal mechanisms. */
+ if (OPNAME_PREFIX_P (field_name))
+ {
+ char *opname = cplus_mangle_opname (field_name + 3, 0);
+ if (opname == NULL)
+ error ("No mangling for \"%s\"", field_name);
+ mangled_name_len += strlen (opname);
+ mangled_name = (char *)xmalloc (mangled_name_len);
+
+ strncpy (mangled_name, field_name, 3);
+ mangled_name[3] = '\0';
+ strcat (mangled_name, opname);
+ }
+ else
+ {
+ mangled_name = (char *)xmalloc (mangled_name_len);
+ if (is_constructor)
+ mangled_name[0] = '\0';
+ else
+ strcpy (mangled_name, field_name);
+ }
+ strcat (mangled_name, buf);
+ /* If the class doesn't have a name, i.e. newname NULL, then we just
+ mangle it using 0 for the length of the class. Thus it gets mangled
+ as something starting with `::' rather than `classname::'. */
+ if (newname != NULL)
+ strcat (mangled_name, newname);
+
+#else
+
+ if (is_constructor)
+ {
+ buf[0] = '\0';
+ }
+ else
+ {
+ sprintf (buf, "__%s%s", const_prefix, volatile_prefix);
+ }
+
+ mangled_name_len = ((is_constructor ? 0 : strlen (field_name))
+ + strlen (buf) + strlen (physname) + 1);
+
+ /* Only needed for GNU-mangled names. ANSI-mangled names
+ work with the normal mechanisms. */
+ if (OPNAME_PREFIX_P (field_name))
+ {
+ char *opname;
+ opname = cplus_mangle_opname (field_name + 3, 0);
+ if (opname == NULL)
+ {
+ error ("No mangling for \"%s\"", field_name);
+ }
+ mangled_name_len += strlen (opname);
+ mangled_name = (char *) xmalloc (mangled_name_len);
+
+ strncpy (mangled_name, field_name, 3);
+ strcpy (mangled_name + 3, opname);
+ }
+ else
+ {
+ mangled_name = (char *) xmalloc (mangled_name_len);
+ if (is_constructor)
+ {
+ mangled_name[0] = '\0';
+ }
+ else
+ {
+ strcpy (mangled_name, field_name);
+ }
+ }
+ strcat (mangled_name, buf);
+
+#endif
+ strcat (mangled_name, physname);
+ return (mangled_name);
+}
+
+
+/* Find which partial symtab on contains PC. Return 0 if none. */
+
+struct partial_symtab *
+find_pc_psymtab (pc)
+ register CORE_ADDR pc;
+{
+ register struct partial_symtab *pst;
+ register struct objfile *objfile;
+
+ ALL_PSYMTABS (objfile, pst)
+ {
+ if (pc >= pst->textlow && pc < pst->texthigh)
+ return (pst);
+ }
+ return (NULL);
+}
+
+/* Find which partial symbol within a psymtab contains PC. Return 0
+ if none. Check all psymtabs if PSYMTAB is 0. */
+struct partial_symbol *
+find_pc_psymbol (psymtab, pc)
+ struct partial_symtab *psymtab;
+ CORE_ADDR pc;
+{
+ struct partial_symbol *best = NULL, *p;
+ CORE_ADDR best_pc;
+
+ if (!psymtab)
+ psymtab = find_pc_psymtab (pc);
+ if (!psymtab)
+ return 0;
+
+ best_pc = psymtab->textlow - 1;
+
+ /* Search the global symbols as well as the static symbols, so that
+ find_pc_partial_function doesn't use a minimal symbol and thus
+ cache a bad endaddr. */
+ for (p = psymtab->objfile->global_psymbols.list + psymtab->globals_offset;
+ (p - (psymtab->objfile->global_psymbols.list + psymtab->globals_offset)
+ < psymtab->n_global_syms);
+ p++)
+ if (SYMBOL_NAMESPACE (p) == VAR_NAMESPACE
+ && SYMBOL_CLASS (p) == LOC_BLOCK
+ && pc >= SYMBOL_VALUE_ADDRESS (p)
+ && SYMBOL_VALUE_ADDRESS (p) > best_pc)
+ {
+ best_pc = SYMBOL_VALUE_ADDRESS (p);
+ best = p;
+ }
+ for (p = psymtab->objfile->static_psymbols.list + psymtab->statics_offset;
+ (p - (psymtab->objfile->static_psymbols.list + psymtab->statics_offset)
+ < psymtab->n_static_syms);
+ p++)
+ if (SYMBOL_NAMESPACE (p) == VAR_NAMESPACE
+ && SYMBOL_CLASS (p) == LOC_BLOCK
+ && pc >= SYMBOL_VALUE_ADDRESS (p)
+ && SYMBOL_VALUE_ADDRESS (p) > best_pc)
+ {
+ best_pc = SYMBOL_VALUE_ADDRESS (p);
+ best = p;
+ }
+ if (best_pc == psymtab->textlow - 1)
+ return 0;
+ return best;
+}
+
+
+/* Find the definition for a specified symbol name NAME
+ in namespace NAMESPACE, visible from lexical block BLOCK.
+ Returns the struct symbol pointer, or zero if no symbol is found.
+ If SYMTAB is non-NULL, store the symbol table in which the
+ symbol was found there, or NULL if not found.
+ C++: if IS_A_FIELD_OF_THIS is nonzero on entry, check to see if
+ NAME is a field of the current implied argument `this'. If so set
+ *IS_A_FIELD_OF_THIS to 1, otherwise set it to zero.
+ BLOCK_FOUND is set to the block in which NAME is found (in the case of
+ a field of `this', value_of_this sets BLOCK_FOUND to the proper value.) */
+
+/* This function has a bunch of loops in it and it would seem to be
+ attractive to put in some QUIT's (though I'm not really sure
+ whether it can run long enough to be really important). But there
+ are a few calls for which it would appear to be bad news to quit
+ out of here: find_proc_desc in alpha-tdep.c and mips-tdep.c, and
+ nindy_frame_chain_valid in nindy-tdep.c. (Note that there is C++
+ code below which can error(), but that probably doesn't affect
+ these calls since they are looking for a known variable and thus
+ can probably assume it will never hit the C++ code). */
+
+struct symbol *
+lookup_symbol (name, block, namespace, is_a_field_of_this, symtab)
+ const char *name;
+ register const struct block *block;
+ const enum namespace namespace;
+ int *is_a_field_of_this;
+ struct symtab **symtab;
+{
+ register struct symbol *sym;
+ register struct symtab *s = NULL;
+ register struct partial_symtab *ps;
+ struct blockvector *bv;
+ register struct objfile *objfile;
+ register struct block *b;
+ register struct minimal_symbol *msymbol;
+
+ /* Search specified block and its superiors. */
+
+ while (block != 0)
+ {
+ sym = lookup_block_symbol (block, name, namespace);
+ if (sym)
+ {
+ block_found = block;
+ if (symtab != NULL)
+ {
+ /* Search the list of symtabs for one which contains the
+ address of the start of this block. */
+ ALL_SYMTABS (objfile, s)
+ {
+ bv = BLOCKVECTOR (s);
+ b = BLOCKVECTOR_BLOCK (bv, GLOBAL_BLOCK);
+ if (BLOCK_START (b) <= BLOCK_START (block)
+ && BLOCK_END (b) > BLOCK_START (block))
+ goto found;
+ }
+found:
+ *symtab = s;
+ }
+
+ return (sym);
+ }
+ block = BLOCK_SUPERBLOCK (block);
+ }
+
+ /* FIXME: this code is never executed--block is always NULL at this
+ point. What is it trying to do, anyway? We already should have
+ checked the STATIC_BLOCK above (it is the superblock of top-level
+ blocks). Why is VAR_NAMESPACE special-cased? */
+ /* Don't need to mess with the psymtabs; if we have a block,
+ that file is read in. If we don't, then we deal later with
+ all the psymtab stuff that needs checking. */
+ if (namespace == VAR_NAMESPACE && block != NULL)
+ {
+ struct block *b;
+ /* Find the right symtab. */
+ ALL_SYMTABS (objfile, s)
+ {
+ bv = BLOCKVECTOR (s);
+ b = BLOCKVECTOR_BLOCK (bv, STATIC_BLOCK);
+ if (BLOCK_START (b) <= BLOCK_START (block)
+ && BLOCK_END (b) > BLOCK_START (block))
+ {
+ sym = lookup_block_symbol (b, name, VAR_NAMESPACE);
+ if (sym)
+ {
+ block_found = b;
+ if (symtab != NULL)
+ *symtab = s;
+ return sym;
+ }
+ }
+ }
+ }
+
+
+ /* C++: If requested to do so by the caller,
+ check to see if NAME is a field of `this'. */
+ if (is_a_field_of_this)
+ {
+ struct value *v = value_of_this (0);
+
+ *is_a_field_of_this = 0;
+ if (v && check_field (v, name))
+ {
+ *is_a_field_of_this = 1;
+ if (symtab != NULL)
+ *symtab = NULL;
+ return 0;
+ }
+ }
+
+ /* Now search all global blocks. Do the symtab's first, then
+ check the psymtab's */
+
+ ALL_SYMTABS (objfile, s)
+ {
+ bv = BLOCKVECTOR (s);
+ block = BLOCKVECTOR_BLOCK (bv, GLOBAL_BLOCK);
+ sym = lookup_block_symbol (block, name, namespace);
+ if (sym)
+ {
+ block_found = block;
+ if (symtab != NULL)
+ *symtab = s;
+ return sym;
+ }
+ }
+
+ /* Check for the possibility of the symbol being a global function
+ that is stored in one of the minimal symbol tables. Eventually, all
+ global symbols might be resolved in this way. */
+
+ if (namespace == VAR_NAMESPACE)
+ {
+ msymbol = lookup_minimal_symbol (name, (struct objfile *) NULL);
+ if (msymbol != NULL)
+ {
+ s = find_pc_symtab (SYMBOL_VALUE_ADDRESS (msymbol));
+ /* If S is NULL, there are no debug symbols for this file.
+ Skip this stuff and check for matching static symbols below. */
+ if (s != NULL)
+ {
+ bv = BLOCKVECTOR (s);
+ block = BLOCKVECTOR_BLOCK (bv, GLOBAL_BLOCK);
+ sym = lookup_block_symbol (block, SYMBOL_NAME (msymbol),
+ namespace);
+ /* We kept static functions in minimal symbol table as well as
+ in static scope. We want to find them in the symbol table. */
+ if (!sym) {
+ block = BLOCKVECTOR_BLOCK (bv, STATIC_BLOCK);
+ sym = lookup_block_symbol (block, SYMBOL_NAME (msymbol),
+ namespace);
+ }
+
+ /* sym == 0 if symbol was found in the minimal symbol table
+ but not in the symtab.
+ Return 0 to use the msymbol definition of "foo_".
+
+ This happens for Fortran "foo_" symbols,
+ which are "foo" in the symtab.
+
+ This can also happen if "asm" is used to make a
+ regular symbol but not a debugging symbol, e.g.
+ asm(".globl _main");
+ asm("_main:");
+ */
+
+ if (symtab != NULL)
+ *symtab = s;
+ return sym;
+ }
+ }
+ }
+
+ ALL_PSYMTABS (objfile, ps)
+ {
+ if (!ps->readin && lookup_partial_symbol (ps, name, 1, namespace))
+ {
+ s = PSYMTAB_TO_SYMTAB(ps);
+ bv = BLOCKVECTOR (s);
+ block = BLOCKVECTOR_BLOCK (bv, GLOBAL_BLOCK);
+ sym = lookup_block_symbol (block, name, namespace);
+ if (!sym)
+ error ("Internal: global symbol `%s' found in %s psymtab but not in symtab", name, ps->filename);
+ if (symtab != NULL)
+ *symtab = s;
+ return sym;
+ }
+ }
+
+ /* Now search all per-file blocks.
+ Not strictly correct, but more useful than an error.
+ Do the symtabs first, then check the psymtabs */
+
+ ALL_SYMTABS (objfile, s)
+ {
+ bv = BLOCKVECTOR (s);
+ block = BLOCKVECTOR_BLOCK (bv, STATIC_BLOCK);
+ sym = lookup_block_symbol (block, name, namespace);
+ if (sym)
+ {
+ block_found = block;
+ if (symtab != NULL)
+ *symtab = s;
+ return sym;
+ }
+ }
+
+ ALL_PSYMTABS (objfile, ps)
+ {
+ if (!ps->readin && lookup_partial_symbol (ps, name, 0, namespace))
+ {
+ s = PSYMTAB_TO_SYMTAB(ps);
+ bv = BLOCKVECTOR (s);
+ block = BLOCKVECTOR_BLOCK (bv, STATIC_BLOCK);
+ sym = lookup_block_symbol (block, name, namespace);
+ if (!sym)
+ error ("Internal: static symbol `%s' found in %s psymtab but not in symtab", name, ps->filename);
+ if (symtab != NULL)
+ *symtab = s;
+ return sym;
+ }
+ }
+
+ /* Now search all per-file blocks for static mangled symbols.
+ Do the symtabs first, then check the psymtabs. */
+
+ if (namespace == VAR_NAMESPACE)
+ {
+ ALL_SYMTABS (objfile, s)
+ {
+ bv = BLOCKVECTOR (s);
+ block = BLOCKVECTOR_BLOCK (bv, STATIC_BLOCK);
+ sym = lookup_block_symbol (block, name, VAR_NAMESPACE);
+ if (sym)
+ {
+ block_found = block;
+ if (symtab != NULL)
+ *symtab = s;
+ return sym;
+ }
+ }
+
+ ALL_PSYMTABS (objfile, ps)
+ {
+ if (!ps->readin && lookup_partial_symbol (ps, name, 0, VAR_NAMESPACE))
+ {
+ s = PSYMTAB_TO_SYMTAB(ps);
+ bv = BLOCKVECTOR (s);
+ block = BLOCKVECTOR_BLOCK (bv, STATIC_BLOCK);
+ sym = lookup_block_symbol (block, name, VAR_NAMESPACE);
+ if (!sym)
+ error ("Internal: mangled static symbol `%s' found in %s psymtab but not in symtab", name, ps->filename);
+ if (symtab != NULL)
+ *symtab = s;
+ return sym;
+ }
+ }
+ }
+
+ if (symtab != NULL)
+ *symtab = NULL;
+ return 0;
+}
+
+/* Look, in partial_symtab PST, for symbol NAME. Check the global
+ symbols if GLOBAL, the static symbols if not */
+
+static struct partial_symbol *
+lookup_partial_symbol (pst, name, global, namespace)
+ struct partial_symtab *pst;
+ const char *name;
+ int global;
+ enum namespace namespace;
+{
+ struct partial_symbol *start, *psym;
+ struct partial_symbol *top, *bottom, *center;
+ int length = (global ? pst->n_global_syms : pst->n_static_syms);
+ int do_linear_search = 1;
+
+ if (length == 0)
+ {
+ return (NULL);
+ }
+
+ start = (global ?
+ pst->objfile->global_psymbols.list + pst->globals_offset :
+ pst->objfile->static_psymbols.list + pst->statics_offset );
+
+ if (global) /* This means we can use a binary search. */
+ {
+ do_linear_search = 0;
+
+ /* Binary search. This search is guaranteed to end with center
+ pointing at the earliest partial symbol with the correct
+ name. At that point *all* partial symbols with that name
+ will be checked against the correct namespace. */
+
+ bottom = start;
+ top = start + length - 1;
+ while (top > bottom)
+ {
+ center = bottom + (top - bottom) / 2;
+ if (!(center < top))
+ abort ();
+ if (!do_linear_search && SYMBOL_LANGUAGE (center) == language_cplus)
+ {
+ do_linear_search = 1;
+ }
+ if (STRCMP (SYMBOL_NAME (center), name) >= 0)
+ {
+ top = center;
+ }
+ else
+ {
+ bottom = center + 1;
+ }
+ }
+ if (!(top == bottom))
+ abort ();
+ while (STREQ (SYMBOL_NAME (top), name))
+ {
+ if (SYMBOL_NAMESPACE (top) == namespace)
+ {
+ return top;
+ }
+ top ++;
+ }
+ }
+
+ /* Can't use a binary search or else we found during the binary search that
+ we should also do a linear search. */
+
+ if (do_linear_search)
+ {
+ for (psym = start; psym < start + length; psym++)
+ {
+ if (namespace == SYMBOL_NAMESPACE (psym))
+ {
+ if (SYMBOL_MATCHES_NAME (psym, name))
+ {
+ return (psym);
+ }
+ }
+ }
+ }
+
+ return (NULL);
+}
+
+/* Find the psymtab containing main(). */
+/* FIXME: What about languages without main() or specially linked
+ executables that have no main() ? */
+
+struct partial_symtab *
+find_main_psymtab ()
+{
+ register struct partial_symtab *pst;
+ register struct objfile *objfile;
+
+ ALL_PSYMTABS (objfile, pst)
+ {
+ if (lookup_partial_symbol (pst, "main", 1, VAR_NAMESPACE))
+ {
+ return (pst);
+ }
+ }
+ return (NULL);
+}
+
+/* Search BLOCK for symbol NAME in NAMESPACE.
+
+ Note that if NAME is the demangled form of a C++ symbol, we will fail
+ to find a match during the binary search of the non-encoded names, but
+ for now we don't worry about the slight inefficiency of looking for
+ a match we'll never find, since it will go pretty quick. Once the
+ binary search terminates, we drop through and do a straight linear
+ search on the symbols. Each symbol which is marked as being a C++
+ symbol (language_cplus set) has both the encoded and non-encoded names
+ tested for a match. */
+
+struct symbol *
+lookup_block_symbol (block, name, namespace)
+ register const struct block *block;
+ const char *name;
+ const enum namespace namespace;
+{
+ register int bot, top, inc;
+ register struct symbol *sym;
+ register struct symbol *sym_found = NULL;
+ register int do_linear_search = 1;
+
+ /* If the blocks's symbols were sorted, start with a binary search. */
+
+ if (BLOCK_SHOULD_SORT (block))
+ {
+ /* Reset the linear search flag so if the binary search fails, we
+ won't do the linear search once unless we find some reason to
+ do so, such as finding a C++ symbol during the binary search.
+ Note that for C++ modules, ALL the symbols in a block should
+ end up marked as C++ symbols. */
+
+ do_linear_search = 0;
+ top = BLOCK_NSYMS (block);
+ bot = 0;
+
+ /* Advance BOT to not far before the first symbol whose name is NAME. */
+
+ while (1)
+ {
+ inc = (top - bot + 1);
+ /* No need to keep binary searching for the last few bits worth. */
+ if (inc < 4)
+ {
+ break;
+ }
+ inc = (inc >> 1) + bot;
+ sym = BLOCK_SYM (block, inc);
+ if (!do_linear_search && SYMBOL_LANGUAGE (sym) == language_cplus)
+ {
+ do_linear_search = 1;
+ }
+ if (SYMBOL_NAME (sym)[0] < name[0])
+ {
+ bot = inc;
+ }
+ else if (SYMBOL_NAME (sym)[0] > name[0])
+ {
+ top = inc;
+ }
+ else if (STRCMP (SYMBOL_NAME (sym), name) < 0)
+ {
+ bot = inc;
+ }
+ else
+ {
+ top = inc;
+ }
+ }
+
+ /* Now scan forward until we run out of symbols, find one whose
+ name is greater than NAME, or find one we want. If there is
+ more than one symbol with the right name and namespace, we
+ return the first one; I believe it is now impossible for us
+ to encounter two symbols with the same name and namespace
+ here, because blocks containing argument symbols are no
+ longer sorted. */
+
+ top = BLOCK_NSYMS (block);
+ while (bot < top)
+ {
+ sym = BLOCK_SYM (block, bot);
+ inc = SYMBOL_NAME (sym)[0] - name[0];
+ if (inc == 0)
+ {
+ inc = STRCMP (SYMBOL_NAME (sym), name);
+ }
+ if (inc == 0 && SYMBOL_NAMESPACE (sym) == namespace)
+ {
+ return (sym);
+ }
+ if (inc > 0)
+ {
+ break;
+ }
+ bot++;
+ }
+ }
+
+ /* Here if block isn't sorted, or we fail to find a match during the
+ binary search above. If during the binary search above, we find a
+ symbol which is a C++ symbol, then we have re-enabled the linear
+ search flag which was reset when starting the binary search.
+
+ This loop is equivalent to the loop above, but hacked greatly for speed.
+
+ Note that parameter symbols do not always show up last in the
+ list; this loop makes sure to take anything else other than
+ parameter symbols first; it only uses parameter symbols as a
+ last resort. Note that this only takes up extra computation
+ time on a match. */
+
+ if (do_linear_search)
+ {
+ top = BLOCK_NSYMS (block);
+ bot = 0;
+ while (bot < top)
+ {
+ sym = BLOCK_SYM (block, bot);
+ if (SYMBOL_NAMESPACE (sym) == namespace &&
+ SYMBOL_MATCHES_NAME (sym, name))
+ {
+ sym_found = sym;
+ if (SYMBOL_CLASS (sym) != LOC_ARG &&
+ SYMBOL_CLASS (sym) != LOC_LOCAL_ARG &&
+ SYMBOL_CLASS (sym) != LOC_REF_ARG &&
+ SYMBOL_CLASS (sym) != LOC_REGPARM &&
+ SYMBOL_CLASS (sym) != LOC_REGPARM_ADDR &&
+ SYMBOL_CLASS (sym) != LOC_BASEREG_ARG)
+ {
+ break;
+ }
+ }
+ bot++;
+ }
+ }
+ return (sym_found); /* Will be NULL if not found. */
+}
+
+
+/* Return the symbol for the function which contains a specified
+ lexical block, described by a struct block BL. */
+
+struct symbol *
+block_function (bl)
+ struct block *bl;
+{
+ while (BLOCK_FUNCTION (bl) == 0 && BLOCK_SUPERBLOCK (bl) != 0)
+ bl = BLOCK_SUPERBLOCK (bl);
+
+ return BLOCK_FUNCTION (bl);
+}
+
+/* Find the symtab associated with PC. Look through the psymtabs and read in
+ another symtab if necessary. */
+
+struct symtab *
+find_pc_symtab (pc)
+ register CORE_ADDR pc;
+{
+ register struct block *b;
+ struct blockvector *bv;
+ register struct symtab *s = NULL;
+ register struct symtab *best_s = NULL;
+ register struct partial_symtab *ps;
+ register struct objfile *objfile;
+ int distance = 0;
+
+ /* Search all symtabs for the one whose file contains our address, and which
+ is the smallest of all the ones containing the address. This is designed
+ to deal with a case like symtab a is at 0x1000-0x2000 and 0x3000-0x4000
+ and symtab b is at 0x2000-0x3000. So the GLOBAL_BLOCK for a is from
+ 0x1000-0x4000, but for address 0x2345 we want to return symtab b.
+ This is said to happen for the mips; it might be swifter to create
+ several symtabs with the same name like xcoff does (I'm not sure). */
+
+ ALL_SYMTABS (objfile, s)
+ {
+ bv = BLOCKVECTOR (s);
+ b = BLOCKVECTOR_BLOCK (bv, GLOBAL_BLOCK);
+ if (BLOCK_START (b) <= pc
+ && BLOCK_END (b) > pc
+ && (distance == 0
+ || BLOCK_END (b) - BLOCK_START (b) < distance))
+ {
+ distance = BLOCK_END (b) - BLOCK_START (b);
+ best_s = s;
+ }
+ }
+
+ if (best_s != NULL)
+ return(best_s);
+
+ s = NULL;
+ ps = find_pc_psymtab (pc);
+ if (ps)
+ {
+ if (ps->readin)
+ /* Might want to error() here (in case symtab is corrupt and
+ will cause a core dump), but maybe we can successfully
+ continue, so let's not. */
+ /* FIXME-32x64: assumes pc fits in a long */
+ warning ("\
+(Internal error: pc 0x%lx in read in psymtab, but not in symtab.)\n",
+ (unsigned long) pc);
+ s = PSYMTAB_TO_SYMTAB (ps);
+ }
+ return (s);
+}
+
+#if 0
+
+/* Find the closest symbol value (of any sort -- function or variable)
+ for a given address value. Slow but complete. (currently unused,
+ mainly because it is too slow. We could fix it if each symtab and
+ psymtab had contained in it the addresses ranges of each of its
+ sections, which also would be required to make things like "info
+ line *0x2345" cause psymtabs to be converted to symtabs). */
+
+struct symbol *
+find_addr_symbol (addr, symtabp, symaddrp)
+ CORE_ADDR addr;
+ struct symtab **symtabp;
+ CORE_ADDR *symaddrp;
+{
+ struct symtab *symtab, *best_symtab;
+ struct objfile *objfile;
+ register int bot, top;
+ register struct symbol *sym;
+ register CORE_ADDR sym_addr;
+ struct block *block;
+ int blocknum;
+
+ /* Info on best symbol seen so far */
+
+ register CORE_ADDR best_sym_addr = 0;
+ struct symbol *best_sym = 0;
+
+ /* FIXME -- we should pull in all the psymtabs, too! */
+ ALL_SYMTABS (objfile, symtab)
+ {
+ /* Search the global and static blocks in this symtab for
+ the closest symbol-address to the desired address. */
+
+ for (blocknum = GLOBAL_BLOCK; blocknum <= STATIC_BLOCK; blocknum++)
+ {
+ QUIT;
+ block = BLOCKVECTOR_BLOCK (BLOCKVECTOR (symtab), blocknum);
+ top = BLOCK_NSYMS (block);
+ for (bot = 0; bot < top; bot++)
+ {
+ sym = BLOCK_SYM (block, bot);
+ switch (SYMBOL_CLASS (sym))
+ {
+ case LOC_STATIC:
+ case LOC_LABEL:
+ sym_addr = SYMBOL_VALUE_ADDRESS (sym);
+ break;
+
+ case LOC_BLOCK:
+ sym_addr = BLOCK_START (SYMBOL_BLOCK_VALUE (sym));
+ break;
+
+ default:
+ continue;
+ }
+
+ if (sym_addr <= addr)
+ if (sym_addr > best_sym_addr)
+ {
+ /* Quit if we found an exact match. */
+ best_sym = sym;
+ best_sym_addr = sym_addr;
+ best_symtab = symtab;
+ if (sym_addr == addr)
+ goto done;
+ }
+ }
+ }
+ }
+
+ done:
+ if (symtabp)
+ *symtabp = best_symtab;
+ if (symaddrp)
+ *symaddrp = best_sym_addr;
+ return best_sym;
+}
+#endif /* 0 */
+
+/* Find the source file and line number for a given PC value.
+ Return a structure containing a symtab pointer, a line number,
+ and a pc range for the entire source line.
+ The value's .pc field is NOT the specified pc.
+ NOTCURRENT nonzero means, if specified pc is on a line boundary,
+ use the line that ends there. Otherwise, in that case, the line
+ that begins there is used. */
+
+/* The big complication here is that a line may start in one file, and end just
+ before the start of another file. This usually occurs when you #include
+ code in the middle of a subroutine. To properly find the end of a line's PC
+ range, we must search all symtabs associated with this compilation unit, and
+ find the one whose first PC is closer than that of the next line in this
+ symtab. */
+
+/* If it's worth the effort, we could be using a binary search. */
+
+struct symtab_and_line
+find_pc_line (pc, notcurrent)
+ CORE_ADDR pc;
+ int notcurrent;
+{
+ struct symtab *s;
+ register struct linetable *l;
+ register int len;
+ register int i;
+ register struct linetable_entry *item;
+ struct symtab_and_line val;
+ struct blockvector *bv;
+
+ /* Info on best line seen so far, and where it starts, and its file. */
+
+ struct linetable_entry *best = NULL;
+ CORE_ADDR best_end = 0;
+ struct symtab *best_symtab = 0;
+
+ /* Store here the first line number
+ of a file which contains the line at the smallest pc after PC.
+ If we don't find a line whose range contains PC,
+ we will use a line one less than this,
+ with a range from the start of that file to the first line's pc. */
+ struct linetable_entry *alt = NULL;
+ struct symtab *alt_symtab = 0;
+
+ /* Info on best line seen in this file. */
+
+ struct linetable_entry *prev;
+
+ /* If this pc is not from the current frame,
+ it is the address of the end of a call instruction.
+ Quite likely that is the start of the following statement.
+ But what we want is the statement containing the instruction.
+ Fudge the pc to make sure we get that. */
+
+ if (notcurrent) pc -= 1;
+
+ s = find_pc_symtab (pc);
+ if (!s)
+ {
+ val.symtab = 0;
+ val.line = 0;
+ val.pc = pc;
+ val.end = 0;
+ return val;
+ }
+
+ bv = BLOCKVECTOR (s);
+
+ /* Look at all the symtabs that share this blockvector.
+ They all have the same apriori range, that we found was right;
+ but they have different line tables. */
+
+ for (; s && BLOCKVECTOR (s) == bv; s = s->next)
+ {
+ /* Find the best line in this symtab. */
+ l = LINETABLE (s);
+ if (!l)
+ continue;
+ len = l->nitems;
+ if (len <= 0)
+ {
+ /* I think len can be zero if the symtab lacks line numbers
+ (e.g. gcc -g1). (Either that or the LINETABLE is NULL;
+ I'm not sure which, and maybe it depends on the symbol
+ reader). */
+ continue;
+ }
+
+ prev = NULL;
+ item = l->item; /* Get first line info */
+
+ /* Is this file's first line closer than the first lines of other files?
+ If so, record this file, and its first line, as best alternate. */
+ if (item->pc > pc && (!alt || item->pc < alt->pc))
+ {
+ alt = item;
+ alt_symtab = s;
+ }
+
+ for (i = 0; i < len; i++, item++)
+ {
+ /* Return the last line that did not start after PC. */
+ if (item->pc > pc)
+ break;
+
+ prev = item;
+ }
+
+ /* At this point, prev points at the line whose start addr is <= pc, and
+ item points at the next line. If we ran off the end of the linetable
+ (pc >= start of the last line), then prev == item. If pc < start of
+ the first line, prev will not be set. */
+
+ /* Is this file's best line closer than the best in the other files?
+ If so, record this file, and its best line, as best so far. */
+
+ if (prev && (!best || prev->pc > best->pc))
+ {
+ best = prev;
+ best_symtab = s;
+ /* If another line is in the linetable, and its PC is closer
+ than the best_end we currently have, take it as best_end. */
+ if (i < len && (best_end == 0 || best_end > item->pc))
+ best_end = item->pc;
+ }
+ }
+
+ if (!best_symtab)
+ {
+ if (!alt_symtab)
+ { /* If we didn't find any line # info, just
+ return zeros. */
+ val.symtab = 0;
+ val.line = 0;
+ val.pc = pc;
+ val.end = 0;
+ }
+ else
+ {
+ val.symtab = alt_symtab;
+ val.line = alt->line - 1;
+ val.pc = BLOCK_END (BLOCKVECTOR_BLOCK (bv, GLOBAL_BLOCK));
+ val.end = alt->pc;
+ }
+ }
+ else
+ {
+ val.symtab = best_symtab;
+ val.line = best->line;
+ val.pc = best->pc;
+ if (best_end && (!alt || best_end < alt->pc))
+ val.end = best_end;
+ else if (alt)
+ val.end = alt->pc;
+ else
+ val.end = BLOCK_END (BLOCKVECTOR_BLOCK (bv, GLOBAL_BLOCK));
+ }
+ return val;
+}
+
+static int find_line_symtab PARAMS ((struct symtab *, int, struct linetable **,
+ int *, int *));
+
+/* Find line number LINE in any symtab whose name is the same as
+ SYMTAB.
+
+ If found, return 1, set *LINETABLE to the linetable in which it was
+ found, set *INDEX to the index in the linetable of the best entry
+ found, and set *EXACT_MATCH nonzero if the value returned is an
+ exact match.
+
+ If not found, return 0. */
+
+static int
+find_line_symtab (symtab, line, linetable, index, exact_match)
+ struct symtab *symtab;
+ int line;
+ struct linetable **linetable;
+ int *index;
+ int *exact_match;
+{
+ int exact;
+
+ /* BEST_INDEX and BEST_LINETABLE identify the smallest linenumber > LINE
+ so far seen. */
+
+ int best_index;
+ struct linetable *best_linetable;
+
+ /* First try looking it up in the given symtab. */
+ best_linetable = LINETABLE (symtab);
+ best_index = find_line_common (best_linetable, line, &exact);
+ if (best_index < 0 || !exact)
+ {
+ /* Didn't find an exact match. So we better keep looking for
+ another symtab with the same name. In the case of xcoff,
+ multiple csects for one source file (produced by IBM's FORTRAN
+ compiler) produce multiple symtabs (this is unavoidable
+ assuming csects can be at arbitrary places in memory and that
+ the GLOBAL_BLOCK of a symtab has a begin and end address). */
+
+ /* BEST is the smallest linenumber > LINE so far seen,
+ or 0 if none has been seen so far.
+ BEST_INDEX and BEST_LINETABLE identify the item for it. */
+ int best;
+
+ struct objfile *objfile;
+ struct symtab *s;
+
+ if (best_index >= 0)
+ best = best_linetable->item[best_index].line;
+ else
+ best = 0;
+
+ ALL_SYMTABS (objfile, s)
+ {
+ struct linetable *l;
+ int ind;
+
+ if (!STREQ (symtab->filename, s->filename))
+ continue;
+ l = LINETABLE (s);
+ ind = find_line_common (l, line, &exact);
+ if (ind >= 0)
+ {
+ if (exact)
+ {
+ best_index = ind;
+ best_linetable = l;
+ goto done;
+ }
+ if (best == 0 || l->item[ind].line < best)
+ {
+ best = l->item[ind].line;
+ best_index = ind;
+ best_linetable = l;
+ }
+ }
+ }
+ }
+ done:
+ if (best_index < 0)
+ return 0;
+
+ if (index)
+ *index = best_index;
+ if (linetable)
+ *linetable = best_linetable;
+ if (exact_match)
+ *exact_match = exact;
+ return 1;
+}
+
+/* Find the PC value for a given source file and line number.
+ Returns zero for invalid line number.
+ The source file is specified with a struct symtab. */
+
+CORE_ADDR
+find_line_pc (symtab, line)
+ struct symtab *symtab;
+ int line;
+{
+ struct linetable *l;
+ int ind;
+
+ if (symtab == 0)
+ return 0;
+ if (find_line_symtab (symtab, line, &l, &ind, NULL))
+ return l->item[ind].pc;
+ else
+ return 0;
+}
+
+/* Find the range of pc values in a line.
+ Store the starting pc of the line into *STARTPTR
+ and the ending pc (start of next line) into *ENDPTR.
+ Returns 1 to indicate success.
+ Returns 0 if could not find the specified line. */
+
+int
+find_line_pc_range (sal, startptr, endptr)
+ struct symtab_and_line sal;
+ CORE_ADDR *startptr, *endptr;
+{
+ CORE_ADDR startaddr;
+ struct symtab_and_line found_sal;
+
+ startaddr = sal.pc;
+ if (startaddr == 0)
+ {
+ startaddr = find_line_pc (sal.symtab, sal.line);
+ }
+ if (startaddr == 0)
+ return 0;
+
+ /* This whole function is based on address. For example, if line 10 has
+ two parts, one from 0x100 to 0x200 and one from 0x300 to 0x400, then
+ "info line *0x123" should say the line goes from 0x100 to 0x200
+ and "info line *0x355" should say the line goes from 0x300 to 0x400.
+ This also insures that we never give a range like "starts at 0x134
+ and ends at 0x12c". */
+
+ found_sal = find_pc_line (startaddr, 0);
+ if (found_sal.line != sal.line)
+ {
+ /* The specified line (sal) has zero bytes. */
+ *startptr = found_sal.pc;
+ *endptr = found_sal.pc;
+ }
+ else
+ {
+ *startptr = found_sal.pc;
+ *endptr = found_sal.end;
+ }
+ return 1;
+}
+
+/* Given a line table and a line number, return the index into the line
+ table for the pc of the nearest line whose number is >= the specified one.
+ Return -1 if none is found. The value is >= 0 if it is an index.
+
+ Set *EXACT_MATCH nonzero if the value returned is an exact match. */
+
+static int
+find_line_common (l, lineno, exact_match)
+ register struct linetable *l;
+ register int lineno;
+ int *exact_match;
+{
+ register int i;
+ register int len;
+
+ /* BEST is the smallest linenumber > LINENO so far seen,
+ or 0 if none has been seen so far.
+ BEST_INDEX identifies the item for it. */
+
+ int best_index = -1;
+ int best = 0;
+
+ if (lineno <= 0)
+ return -1;
+ if (l == 0)
+ return -1;
+
+ len = l->nitems;
+ for (i = 0; i < len; i++)
+ {
+ register struct linetable_entry *item = &(l->item[i]);
+
+ if (item->line == lineno)
+ {
+ /* Return the first (lowest address) entry which matches. */
+ *exact_match = 1;
+ return i;
+ }
+
+ if (item->line > lineno && (best == 0 || item->line < best))
+ {
+ best = item->line;
+ best_index = i;
+ }
+ }
+
+ /* If we got here, we didn't get an exact match. */
+
+ *exact_match = 0;
+ return best_index;
+}
+
+int
+find_pc_line_pc_range (pc, startptr, endptr)
+ CORE_ADDR pc;
+ CORE_ADDR *startptr, *endptr;
+{
+ struct symtab_and_line sal;
+ sal = find_pc_line (pc, 0);
+ *startptr = sal.pc;
+ *endptr = sal.end;
+ return sal.symtab != 0;
+}
+
+/* Given a function symbol SYM, find the symtab and line for the start
+ of the function.
+ If the argument FUNFIRSTLINE is nonzero, we want the first line
+ of real code inside the function. */
+
+static struct symtab_and_line
+find_function_start_sal PARAMS ((struct symbol *sym, int));
+
+static struct symtab_and_line
+find_function_start_sal (sym, funfirstline)
+ struct symbol *sym;
+ int funfirstline;
+{
+ CORE_ADDR pc;
+ struct symtab_and_line sal;
+
+ pc = BLOCK_START (SYMBOL_BLOCK_VALUE (sym));
+ if (funfirstline)
+ {
+ pc += FUNCTION_START_OFFSET;
+ SKIP_PROLOGUE (pc);
+ }
+ sal = find_pc_line (pc, 0);
+
+#ifdef PROLOGUE_FIRSTLINE_OVERLAP
+ /* Convex: no need to suppress code on first line, if any */
+ sal.pc = pc;
+#else
+ /* Check if SKIP_PROLOGUE left us in mid-line, and the next
+ line is still part of the same function. */
+ if (sal.pc != pc
+ && BLOCK_START (SYMBOL_BLOCK_VALUE (sym)) <= sal.end
+ && sal.end < BLOCK_END (SYMBOL_BLOCK_VALUE (sym)))
+ {
+ /* First pc of next line */
+ pc = sal.end;
+ /* Recalculate the line number (might not be N+1). */
+ sal = find_pc_line (pc, 0);
+ }
+ sal.pc = pc;
+#endif
+
+ return sal;
+}
+
+/* If P is of the form "operator[ \t]+..." where `...' is
+ some legitimate operator text, return a pointer to the
+ beginning of the substring of the operator text.
+ Otherwise, return "". */
+static char *
+operator_chars (p, end)
+ char *p;
+ char **end;
+{
+ *end = "";
+ if (strncmp (p, "operator", 8))
+ return *end;
+ p += 8;
+
+ /* Don't get faked out by `operator' being part of a longer
+ identifier. */
+ if (isalpha(*p) || *p == '_' || *p == '$' || *p == '\0')
+ return *end;
+
+ /* Allow some whitespace between `operator' and the operator symbol. */
+ while (*p == ' ' || *p == '\t')
+ p++;
+
+ /* Recognize 'operator TYPENAME'. */
+
+ if (isalpha(*p) || *p == '_' || *p == '$')
+ {
+ register char *q = p+1;
+ while (isalnum(*q) || *q == '_' || *q == '$')
+ q++;
+ *end = q;
+ return p;
+ }
+
+ switch (*p)
+ {
+ case '!':
+ case '=':
+ case '*':
+ case '/':
+ case '%':
+ case '^':
+ if (p[1] == '=')
+ *end = p+2;
+ else
+ *end = p+1;
+ return p;
+ case '<':
+ case '>':
+ case '+':
+ case '-':
+ case '&':
+ case '|':
+ if (p[1] == '=' || p[1] == p[0])
+ *end = p+2;
+ else
+ *end = p+1;
+ return p;
+ case '~':
+ case ',':
+ *end = p+1;
+ return p;
+ case '(':
+ if (p[1] != ')')
+ error ("`operator ()' must be specified without whitespace in `()'");
+ *end = p+2;
+ return p;
+ case '?':
+ if (p[1] != ':')
+ error ("`operator ?:' must be specified without whitespace in `?:'");
+ *end = p+2;
+ return p;
+ case '[':
+ if (p[1] != ']')
+ error ("`operator []' must be specified without whitespace in `[]'");
+ *end = p+2;
+ return p;
+ default:
+ error ("`operator %s' not supported", p);
+ break;
+ }
+ *end = "";
+ return *end;
+}
+
+/* Recursive helper function for decode_line_1.
+ * Look for methods named NAME in type T.
+ * Return number of matches.
+ * Put matches in SYM_ARR (which better be big enough!).
+ * These allocations seem to define "big enough":
+ * sym_arr = (struct symbol **) alloca(TYPE_NFN_FIELDS_TOTAL (t) * sizeof(struct symbol*));
+ * Note that this function is g++ specific.
+ */
+
+int
+find_methods (t, name, sym_arr)
+ struct type *t;
+ char *name;
+ struct symbol **sym_arr;
+{
+ int i1 = 0;
+ int ibase;
+ struct symbol *sym_class;
+ char *class_name = type_name_no_tag (t);
+ /* Ignore this class if it doesn't have a name. This is ugly, but
+ unless we figure out how to get the physname without the name of
+ the class, then the loop can't do any good. */
+ if (class_name
+ && (sym_class = lookup_symbol (class_name,
+ (struct block *)NULL,
+ STRUCT_NAMESPACE,
+ (int *)NULL,
+ (struct symtab **)NULL)))
+ {
+ int method_counter;
+ /* FIXME: Shouldn't this just be check_stub_type (t)? */
+ t = SYMBOL_TYPE (sym_class);
+ for (method_counter = TYPE_NFN_FIELDS (t) - 1;
+ method_counter >= 0;
+ --method_counter)
+ {
+ int field_counter;
+ struct fn_field *f = TYPE_FN_FIELDLIST1 (t, method_counter);
+ char *method_name = TYPE_FN_FIELDLIST_NAME (t, method_counter);
+ char dem_opname[64];
+
+ if (strncmp(method_name, "__", 2)==0 ||
+ strncmp(method_name, "op", 2)==0 ||
+ strncmp(method_name, "type", 4)==0 )
+ {
+ if (cplus_demangle_opname(method_name, dem_opname, DMGL_ANSI))
+ method_name = dem_opname;
+ else if (cplus_demangle_opname(method_name, dem_opname, 0))
+ method_name = dem_opname;
+ }
+ if (STREQ (name, method_name))
+ /* Find all the fields with that name. */
+ for (field_counter = TYPE_FN_FIELDLIST_LENGTH (t, method_counter) - 1;
+ field_counter >= 0;
+ --field_counter)
+ {
+ char *phys_name;
+ if (TYPE_FN_FIELD_STUB (f, field_counter))
+ check_stub_method (t, method_counter, field_counter);
+ phys_name = TYPE_FN_FIELD_PHYSNAME (f, field_counter);
+ /* Destructor is handled by caller, dont add it to the list */
+ if (DESTRUCTOR_PREFIX_P (phys_name))
+ continue;
+
+ /* FIXME: Why are we looking this up in the
+ SYMBOL_BLOCK_VALUE (sym_class)? It is intended as a hook
+ for nested types? If so, it should probably hook to the
+ type, not the symbol. mipsread.c is the only symbol
+ reader which sets the SYMBOL_BLOCK_VALUE for types, and
+ this is not documented in symtab.h. -26Aug93. */
+
+ sym_arr[i1] = lookup_symbol (phys_name,
+ SYMBOL_BLOCK_VALUE (sym_class),
+ VAR_NAMESPACE,
+ (int *) NULL,
+ (struct symtab **) NULL);
+ if (sym_arr[i1]) i1++;
+ else
+ {
+ fputs_filtered("(Cannot find method ", gdb_stdout);
+ fprintf_symbol_filtered (gdb_stdout, phys_name,
+ language_cplus,
+ DMGL_PARAMS | DMGL_ANSI);
+ fputs_filtered(" - possibly inlined.)\n", gdb_stdout);
+ }
+ }
+ }
+ }
+
+ /* Only search baseclasses if there is no match yet, since names in
+ derived classes override those in baseclasses.
+
+ FIXME: The above is not true; it is only true of member functions
+ if they have the same number of arguments (??? - section 13.1 of the
+ ARM says the function members are not in the same scope but doesn't
+ really spell out the rules in a way I understand. In any case, if
+ the number of arguments differ this is a case in which we can overload
+ rather than hiding without any problem, and gcc 2.4.5 does overload
+ rather than hiding in this case). */
+
+ if (i1)
+ return i1;
+ for (ibase = 0; ibase < TYPE_N_BASECLASSES (t); ibase++)
+ i1 += find_methods(TYPE_BASECLASS(t, ibase), name,
+ sym_arr + i1);
+ return i1;
+}
+
+/* Helper function for decode_line_1.
+ Build a canonical line spec in CANONICAL if it is non-NULL and if
+ the SAL has a symtab.
+ If SYMNAME is non-NULL the canonical line spec is `filename:symname'.
+ If SYMNAME is NULL the line number from SAL is used and the canonical
+ line spec is `filename:linenum'. */
+
+static void
+build_canonical_line_spec (sal, symname, canonical)
+ struct symtab_and_line *sal;
+ char *symname;
+ char ***canonical;
+{
+ char **canonical_arr;
+ char *canonical_name;
+ char *filename;
+ struct symtab *s = sal->symtab;
+
+ if (s == (struct symtab *)NULL
+ || s->filename == (char *)NULL
+ || canonical == (char ***)NULL)
+ return;
+
+ canonical_arr = (char **) xmalloc (sizeof (char *));
+ *canonical = canonical_arr;
+
+ filename = s->filename;
+ if (symname != NULL)
+ {
+ canonical_name = xmalloc (strlen (filename) + strlen (symname) + 2);
+ sprintf (canonical_name, "%s:%s", filename, symname);
+ }
+ else
+ {
+ canonical_name = xmalloc (strlen (filename) + 30);
+ sprintf (canonical_name, "%s:%d", filename, sal->line);
+ }
+ canonical_arr[0] = canonical_name;
+}
+
+/* Parse a string that specifies a line number.
+ Pass the address of a char * variable; that variable will be
+ advanced over the characters actually parsed.
+
+ The string can be:
+
+ LINENUM -- that line number in current file. PC returned is 0.
+ FILE:LINENUM -- that line in that file. PC returned is 0.
+ FUNCTION -- line number of openbrace of that function.
+ PC returned is the start of the function.
+ VARIABLE -- line number of definition of that variable.
+ PC returned is 0.
+ FILE:FUNCTION -- likewise, but prefer functions in that file.
+ *EXPR -- line in which address EXPR appears.
+
+ FUNCTION may be an undebuggable function found in minimal symbol table.
+
+ If the argument FUNFIRSTLINE is nonzero, we want the first line
+ of real code inside a function when a function is specified.
+
+ DEFAULT_SYMTAB specifies the file to use if none is specified.
+ It defaults to current_source_symtab.
+ DEFAULT_LINE specifies the line number to use for relative
+ line numbers (that start with signs). Defaults to current_source_line.
+ If CANONICAL is non-NULL, store an array of strings containing the canonical
+ line specs there if necessary. Currently overloaded member functions and
+ line numbers or static functions without a filename yield a canonical
+ line spec. The array and the line spec strings are allocated on the heap,
+ it is the callers responsibility to free them.
+
+ Note that it is possible to return zero for the symtab
+ if no file is validly specified. Callers must check that.
+ Also, the line number returned may be invalid. */
+
+/* We allow single quotes in various places. This is a hideous
+ kludge, which exists because the completer can't yet deal with the
+ lack of single quotes. FIXME: write a linespec_completer which we
+ can use as appropriate instead of make_symbol_completion_list. */
+
+struct symtabs_and_lines
+decode_line_1 (argptr, funfirstline, default_symtab, default_line, canonical)
+ char **argptr;
+ int funfirstline;
+ struct symtab *default_symtab;
+ int default_line;
+ char ***canonical;
+{
+ struct symtabs_and_lines values;
+#ifdef HPPA_COMPILER_BUG
+ /* FIXME: The native HP 9000/700 compiler has a bug which appears
+ when optimizing this file with target i960-vxworks. I haven't
+ been able to construct a simple test case. The problem is that
+ in the second call to SKIP_PROLOGUE below, the compiler somehow
+ does not realize that the statement val = find_pc_line (...) will
+ change the values of the fields of val. It extracts the elements
+ into registers at the top of the block, and does not update the
+ registers after the call to find_pc_line. You can check this by
+ inserting a printf at the end of find_pc_line to show what values
+ it is returning for val.pc and val.end and another printf after
+ the call to see what values the function actually got (remember,
+ this is compiling with cc -O, with this patch removed). You can
+ also examine the assembly listing: search for the second call to
+ skip_prologue; the LDO statement before the next call to
+ find_pc_line loads the address of the structure which
+ find_pc_line will return; if there is a LDW just before the LDO,
+ which fetches an element of the structure, then the compiler
+ still has the bug.
+
+ Setting val to volatile avoids the problem. We must undef
+ volatile, because the HPPA native compiler does not define
+ __STDC__, although it does understand volatile, and so volatile
+ will have been defined away in defs.h. */
+#undef volatile
+ volatile struct symtab_and_line val;
+#define volatile /*nothing*/
+#else
+ struct symtab_and_line val;
+#endif
+ register char *p, *p1;
+ char *q, *pp;
+#if 0
+ char *q1;
+#endif
+ register struct symtab *s;
+
+ register struct symbol *sym;
+ /* The symtab that SYM was found in. */
+ struct symtab *sym_symtab;
+
+ register CORE_ADDR pc;
+ register struct minimal_symbol *msymbol;
+ char *copy;
+ struct symbol *sym_class;
+ int i1;
+ int is_quoted, has_parens;
+ struct symbol **sym_arr;
+ struct type *t;
+ char *saved_arg = *argptr;
+ extern char *gdb_completer_quote_characters;
+
+ /* Defaults have defaults. */
+
+ if (default_symtab == 0)
+ {
+ default_symtab = current_source_symtab;
+ default_line = current_source_line;
+ }
+
+ /* See if arg is *PC */
+
+ if (**argptr == '*')
+ {
+ if (**argptr == '*')
+ {
+ (*argptr)++;
+ }
+ pc = parse_and_eval_address_1 (argptr);
+ values.sals = (struct symtab_and_line *)
+ xmalloc (sizeof (struct symtab_and_line));
+ values.nelts = 1;
+ values.sals[0] = find_pc_line (pc, 0);
+ values.sals[0].pc = pc;
+ build_canonical_line_spec (values.sals, NULL, canonical);
+ return values;
+ }
+
+ /* Maybe arg is FILE : LINENUM or FILE : FUNCTION */
+
+ s = NULL;
+ is_quoted = (strchr(gdb_completer_quote_characters, **argptr) != NULL);
+ has_parens = (( pp = strchr(*argptr, '(')) != NULL &&
+ (pp = strchr(pp, ')')) != NULL);
+
+ for (p = *argptr; *p; p++)
+ {
+ if (p[0] == '<')
+ {
+ while(++p && *p != '>');
+ if (!p)
+ {
+ error ("non-matching '<' and '>' in command");
+ }
+ }
+ if (p[0] == ':' || p[0] == ' ' || p[0] == '\t')
+ break;
+ }
+ while (p[0] == ' ' || p[0] == '\t') p++;
+
+ if ((p[0] == ':') && !has_parens)
+ {
+
+ /* C++ */
+ if (is_quoted) *argptr = *argptr+1;
+ if (p[1] ==':')
+ {
+ /* Extract the class name. */
+ p1 = p;
+ while (p != *argptr && p[-1] == ' ') --p;
+ copy = (char *) alloca (p - *argptr + 1);
+ memcpy (copy, *argptr, p - *argptr);
+ copy[p - *argptr] = 0;
+
+ /* Discard the class name from the arg. */
+ p = p1 + 2;
+ while (*p == ' ' || *p == '\t') p++;
+ *argptr = p;
+
+ sym_class = lookup_symbol (copy, 0, STRUCT_NAMESPACE, 0,
+ (struct symtab **)NULL);
+
+ if (sym_class &&
+ ( TYPE_CODE (SYMBOL_TYPE (sym_class)) == TYPE_CODE_STRUCT
+ || TYPE_CODE (SYMBOL_TYPE (sym_class)) == TYPE_CODE_UNION))
+ {
+ /* Arg token is not digits => try it as a function name
+ Find the next token(everything up to end or next blank). */
+ if (strchr(gdb_completer_quote_characters, **argptr) != NULL)
+ {
+ p = skip_quoted(*argptr);
+ *argptr = *argptr + 1;
+ }
+ else
+ {
+ p = *argptr;
+ while (*p && *p!=' ' && *p!='\t' && *p!=',' && *p!=':') p++;
+ }
+/*
+ q = operator_chars (*argptr, &q1);
+ if (q1 - q)
+ {
+ char *opname;
+ char *tmp = alloca (q1 - q + 1);
+ memcpy (tmp, q, q1 - q);
+ tmp[q1 - q] = '\0';
+ opname = cplus_mangle_opname (tmp, DMGL_ANSI);
+ if (opname == NULL)
+ {
+ error_begin ();
+ printf_filtered ("no mangling for \"%s\"\n", tmp);
+ cplusplus_hint (saved_arg);
+ return_to_top_level (RETURN_ERROR);
+ }
+ copy = (char*) alloca (3 + strlen(opname));
+ sprintf (copy, "__%s", opname);
+ p = q1;
+ }
+ else
+*/
+ {
+ copy = (char *) alloca (p - *argptr + 1 );
+ memcpy (copy, *argptr, p - *argptr);
+ copy[p - *argptr] = '\0';
+ if (strchr(gdb_completer_quote_characters, copy[p-*argptr-1]) != NULL)
+ copy[p - *argptr -1] = '\0';
+ }
+
+ /* no line number may be specified */
+ while (*p == ' ' || *p == '\t') p++;
+ *argptr = p;
+
+ sym = 0;
+ i1 = 0; /* counter for the symbol array */
+ t = SYMBOL_TYPE (sym_class);
+ sym_arr = (struct symbol **) alloca(TYPE_NFN_FIELDS_TOTAL (t) * sizeof(struct symbol*));
+
+ /* Cfront objects don't have fieldlists. */
+ if (destructor_name_p (copy, t) && TYPE_FN_FIELDLISTS (t) != NULL)
+ {
+ /* destructors are a special case. */
+ struct fn_field *f = TYPE_FN_FIELDLIST1 (t, 0);
+ int len = TYPE_FN_FIELDLIST_LENGTH (t, 0) - 1;
+ /* gcc 1.x puts destructor in last field,
+ gcc 2.x puts destructor in first field. */
+ char *phys_name = TYPE_FN_FIELD_PHYSNAME (f, len);
+ if (!DESTRUCTOR_PREFIX_P (phys_name))
+ {
+ phys_name = TYPE_FN_FIELD_PHYSNAME (f, 0);
+ if (!DESTRUCTOR_PREFIX_P (phys_name))
+ phys_name = "";
+ }
+ sym_arr[i1] =
+ lookup_symbol (phys_name, SYMBOL_BLOCK_VALUE (sym_class),
+ VAR_NAMESPACE, 0, (struct symtab **)NULL);
+ if (sym_arr[i1]) i1++;
+ }
+ else
+ i1 = find_methods (t, copy, sym_arr);
+ if (i1 == 1)
+ {
+ /* There is exactly one field with that name. */
+ sym = sym_arr[0];
+
+ if (sym && SYMBOL_CLASS (sym) == LOC_BLOCK)
+ {
+ values.sals = (struct symtab_and_line *)xmalloc (sizeof (struct symtab_and_line));
+ values.nelts = 1;
+ values.sals[0] = find_function_start_sal (sym,
+ funfirstline);
+ }
+ else
+ {
+ values.nelts = 0;
+ }
+ return values;
+ }
+ if (i1 > 0)
+ {
+ /* There is more than one field with that name
+ (overloaded). Ask the user which one to use. */
+ return decode_line_2 (sym_arr, i1, funfirstline, canonical);
+ }
+ else
+ {
+ char *tmp;
+
+ if (OPNAME_PREFIX_P (copy))
+ {
+ tmp = (char *)alloca (strlen (copy+3) + 9);
+ strcpy (tmp, "operator ");
+ strcat (tmp, copy+3);
+ }
+ else
+ tmp = copy;
+ error_begin ();
+ if (tmp[0] == '~')
+ printf_filtered
+ ("the class `%s' does not have destructor defined\n",
+ SYMBOL_SOURCE_NAME(sym_class));
+ else
+ printf_filtered
+ ("the class %s does not have any method named %s\n",
+ SYMBOL_SOURCE_NAME(sym_class), tmp);
+ cplusplus_hint (saved_arg);
+ return_to_top_level (RETURN_ERROR);
+ }
+ }
+ else
+ {
+ error_begin ();
+ /* The quotes are important if copy is empty. */
+ printf_filtered
+ ("can't find class, struct, or union named \"%s\"\n", copy);
+ cplusplus_hint (saved_arg);
+ return_to_top_level (RETURN_ERROR);
+ }
+ }
+ /* end of C++ */
+
+
+ /* Extract the file name. */
+ p1 = p;
+ while (p != *argptr && p[-1] == ' ') --p;
+ copy = (char *) alloca (p - *argptr + 1);
+ memcpy (copy, *argptr, p - *argptr);
+ copy[p - *argptr] = 0;
+
+ /* Find that file's data. */
+ s = lookup_symtab (copy);
+ if (s == 0)
+ {
+ if (!have_full_symbols () && !have_partial_symbols ())
+ error (no_symtab_msg);
+ error ("No source file named %s.", copy);
+ }
+
+ /* Discard the file name from the arg. */
+ p = p1 + 1;
+ while (*p == ' ' || *p == '\t') p++;
+ *argptr = p;
+ }
+
+ /* S is specified file's symtab, or 0 if no file specified.
+ arg no longer contains the file name. */
+
+ /* Check whether arg is all digits (and sign) */
+
+ q = *argptr;
+ if (*q == '-' || *q == '+') q++;
+ while (*q >= '0' && *q <= '9')
+ q++;
+
+ if (q != *argptr && (*q == 0 || *q == ' ' || *q == '\t' || *q == ','))
+ {
+ /* We found a token consisting of all digits -- at least one digit. */
+ enum sign {none, plus, minus} sign = none;
+
+ /* We might need a canonical line spec if no file was specified. */
+ int need_canonical = (s == 0) ? 1 : 0;
+
+ /* This is where we need to make sure that we have good defaults.
+ We must guarantee that this section of code is never executed
+ when we are called with just a function name, since
+ select_source_symtab calls us with such an argument */
+
+ if (s == 0 && default_symtab == 0)
+ {
+ select_source_symtab (0);
+ default_symtab = current_source_symtab;
+ default_line = current_source_line;
+ }
+
+ if (**argptr == '+')
+ sign = plus, (*argptr)++;
+ else if (**argptr == '-')
+ sign = minus, (*argptr)++;
+ val.line = atoi (*argptr);
+ switch (sign)
+ {
+ case plus:
+ if (q == *argptr)
+ val.line = 5;
+ if (s == 0)
+ val.line = default_line + val.line;
+ break;
+ case minus:
+ if (q == *argptr)
+ val.line = 15;
+ if (s == 0)
+ val.line = default_line - val.line;
+ else
+ val.line = 1;
+ break;
+ case none:
+ break; /* No need to adjust val.line. */
+ }
+
+ while (*q == ' ' || *q == '\t') q++;
+ *argptr = q;
+ if (s == 0)
+ s = default_symtab;
+ val.symtab = s;
+ val.pc = 0;
+ values.sals = (struct symtab_and_line *)xmalloc (sizeof (struct symtab_and_line));
+ values.sals[0] = val;
+ values.nelts = 1;
+ if (need_canonical)
+ build_canonical_line_spec (values.sals, NULL, canonical);
+ return values;
+ }
+
+ /* Arg token is not digits => try it as a variable name
+ Find the next token (everything up to end or next whitespace). */
+
+ if (is_quoted)
+ {
+ p = skip_quoted (*argptr);
+ if (p[-1] != '\'')
+ error ("Unmatched single quote.");
+ }
+ else if (has_parens)
+ {
+ p = pp+1;
+ }
+ else
+ {
+ p = skip_quoted(*argptr);
+ }
+
+ copy = (char *) alloca (p - *argptr + 1);
+ memcpy (copy, *argptr, p - *argptr);
+ copy[p - *argptr] = '\0';
+ if (p != *argptr
+ && (copy[0] == copy [p - *argptr - 1])
+ && strchr (gdb_completer_quote_characters, copy[0]) != NULL)
+ {
+ copy [p - *argptr - 1] = '\0';
+ copy++;
+ }
+ while (*p == ' ' || *p == '\t') p++;
+ *argptr = p;
+
+ /* Look up that token as a variable.
+ If file specified, use that file's per-file block to start with. */
+
+ sym = lookup_symbol (copy,
+ (s ? BLOCKVECTOR_BLOCK (BLOCKVECTOR (s), STATIC_BLOCK)
+ : get_selected_block ()),
+ VAR_NAMESPACE, 0, &sym_symtab);
+
+ if (sym != NULL)
+ {
+ if (SYMBOL_CLASS (sym) == LOC_BLOCK)
+ {
+ /* Arg is the name of a function */
+ values.sals = (struct symtab_and_line *)xmalloc (sizeof (struct symtab_and_line));
+ values.sals[0] = find_function_start_sal (sym, funfirstline);
+ values.nelts = 1;
+
+ /* Don't use the SYMBOL_LINE; if used at all it points to
+ the line containing the parameters or thereabouts, not
+ the first line of code. */
+
+ /* We might need a canonical line spec if it is a static
+ function. */
+ if (s == 0)
+ {
+ struct blockvector *bv = BLOCKVECTOR (sym_symtab);
+ struct block *b = BLOCKVECTOR_BLOCK (bv, STATIC_BLOCK);
+ if (lookup_block_symbol (b, copy, VAR_NAMESPACE) != NULL)
+ build_canonical_line_spec (values.sals, copy, canonical);
+ }
+ return values;
+ }
+ else if (SYMBOL_LINE (sym) != 0)
+ {
+ /* We know its line number. */
+ values.sals = (struct symtab_and_line *)
+ xmalloc (sizeof (struct symtab_and_line));
+ values.nelts = 1;
+ memset (&values.sals[0], 0, sizeof (values.sals[0]));
+ values.sals[0].symtab = sym_symtab;
+ values.sals[0].line = SYMBOL_LINE (sym);
+ return values;
+ }
+ else
+ /* This can happen if it is compiled with a compiler which doesn't
+ put out line numbers for variables. */
+ /* FIXME: Shouldn't we just set .line and .symtab to zero and
+ return? For example, "info line foo" could print the address. */
+ error ("Line number not known for symbol \"%s\"", copy);
+ }
+
+ msymbol = lookup_minimal_symbol (copy, (struct objfile *) NULL);
+ if (msymbol != NULL)
+ {
+ val.symtab = 0;
+ val.line = 0;
+ val.pc = SYMBOL_VALUE_ADDRESS (msymbol);
+ if (funfirstline)
+ {
+ val.pc += FUNCTION_START_OFFSET;
+ SKIP_PROLOGUE (val.pc);
+ }
+ values.sals = (struct symtab_and_line *)xmalloc (sizeof (struct symtab_and_line));
+ values.sals[0] = val;
+ values.nelts = 1;
+ return values;
+ }
+
+ if (!have_full_symbols () &&
+ !have_partial_symbols () && !have_minimal_symbols ())
+ error (no_symtab_msg);
+
+ error ("Function \"%s\" not defined.", copy);
+ return values; /* for lint */
+}
+
+struct symtabs_and_lines
+decode_line_spec (string, funfirstline)
+ char *string;
+ int funfirstline;
+{
+ struct symtabs_and_lines sals;
+ if (string == 0)
+ error ("Empty line specification.");
+ sals = decode_line_1 (&string, funfirstline,
+ current_source_symtab, current_source_line,
+ (char ***)NULL);
+ if (*string)
+ error ("Junk at end of line specification: %s", string);
+ return sals;
+}
+
+/* Given a list of NELTS symbols in SYM_ARR, return a list of lines to
+ operate on (ask user if necessary).
+ If CANONICAL is non-NULL return a corresponding array of mangled names
+ as canonical line specs there. */
+
+static struct symtabs_and_lines
+decode_line_2 (sym_arr, nelts, funfirstline, canonical)
+ struct symbol *sym_arr[];
+ int nelts;
+ int funfirstline;
+ char ***canonical;
+{
+ struct symtabs_and_lines values, return_values;
+ char *args, *arg1;
+ int i;
+ char *prompt;
+ char *symname;
+ struct cleanup *old_chain;
+ char **canonical_arr = (char **)NULL;
+
+ values.sals = (struct symtab_and_line *) alloca (nelts * sizeof(struct symtab_and_line));
+ return_values.sals = (struct symtab_and_line *) xmalloc (nelts * sizeof(struct symtab_and_line));
+ old_chain = make_cleanup (free, return_values.sals);
+
+ if (canonical)
+ {
+ canonical_arr = (char **) xmalloc (nelts * sizeof (char *));
+ make_cleanup (free, canonical_arr);
+ memset (canonical_arr, 0, nelts * sizeof (char *));
+ *canonical = canonical_arr;
+ }
+
+ i = 0;
+ printf_unfiltered("[0] cancel\n[1] all\n");
+ while (i < nelts)
+ {
+ if (sym_arr[i] && SYMBOL_CLASS (sym_arr[i]) == LOC_BLOCK)
+ {
+ values.sals[i] = find_function_start_sal (sym_arr[i], funfirstline);
+ printf_unfiltered ("[%d] %s at %s:%d\n",
+ (i+2),
+ SYMBOL_SOURCE_NAME (sym_arr[i]),
+ values.sals[i].symtab->filename,
+ values.sals[i].line);
+ }
+ else
+ printf_unfiltered ("?HERE\n");
+ i++;
+ }
+
+ if ((prompt = getenv ("PS2")) == NULL)
+ {
+ prompt = ">";
+ }
+ printf_unfiltered("%s ",prompt);
+ gdb_flush(gdb_stdout);
+
+ args = command_line_input ((char *) NULL, 0, "overload-choice");
+
+ if (args == 0 || *args == 0)
+ error_no_arg ("one or more choice numbers");
+
+ i = 0;
+ while (*args)
+ {
+ int num;
+
+ arg1 = args;
+ while (*arg1 >= '0' && *arg1 <= '9') arg1++;
+ if (*arg1 && *arg1 != ' ' && *arg1 != '\t')
+ error ("Arguments must be choice numbers.");
+
+ num = atoi (args);
+
+ if (num == 0)
+ error ("cancelled");
+ else if (num == 1)
+ {
+ if (canonical_arr)
+ {
+ for (i = 0; i < nelts; i++)
+ {
+ if (canonical_arr[i] == NULL)
+ {
+ symname = SYMBOL_NAME (sym_arr[i]);
+ canonical_arr[i] = savestring (symname, strlen (symname));
+ }
+ }
+ }
+ memcpy (return_values.sals, values.sals,
+ (nelts * sizeof(struct symtab_and_line)));
+ return_values.nelts = nelts;
+ discard_cleanups (old_chain);
+ return return_values;
+ }
+
+ if (num > nelts + 2)
+ {
+ printf_unfiltered ("No choice number %d.\n", num);
+ }
+ else
+ {
+ num -= 2;
+ if (values.sals[num].pc)
+ {
+ if (canonical_arr)
+ {
+ symname = SYMBOL_NAME (sym_arr[num]);
+ make_cleanup (free, symname);
+ canonical_arr[i] = savestring (symname, strlen (symname));
+ }
+ return_values.sals[i++] = values.sals[num];
+ values.sals[num].pc = 0;
+ }
+ else
+ {
+ printf_unfiltered ("duplicate request for %d ignored.\n", num);
+ }
+ }
+
+ args = arg1;
+ while (*args == ' ' || *args == '\t') args++;
+ }
+ return_values.nelts = i;
+ discard_cleanups (old_chain);
+ return return_values;
+}
+
+
+/* Slave routine for sources_info. Force line breaks at ,'s.
+ NAME is the name to print and *FIRST is nonzero if this is the first
+ name printed. Set *FIRST to zero. */
+static void
+output_source_filename (name, first)
+ char *name;
+ int *first;
+{
+ /* Table of files printed so far. Since a single source file can
+ result in several partial symbol tables, we need to avoid printing
+ it more than once. Note: if some of the psymtabs are read in and
+ some are not, it gets printed both under "Source files for which
+ symbols have been read" and "Source files for which symbols will
+ be read in on demand". I consider this a reasonable way to deal
+ with the situation. I'm not sure whether this can also happen for
+ symtabs; it doesn't hurt to check. */
+ static char **tab = NULL;
+ /* Allocated size of tab in elements.
+ Start with one 256-byte block (when using GNU malloc.c).
+ 24 is the malloc overhead when range checking is in effect. */
+ static int tab_alloc_size = (256 - 24) / sizeof (char *);
+ /* Current size of tab in elements. */
+ static int tab_cur_size;
+
+ char **p;
+
+ if (*first)
+ {
+ if (tab == NULL)
+ tab = (char **) xmalloc (tab_alloc_size * sizeof (*tab));
+ tab_cur_size = 0;
+ }
+
+ /* Is NAME in tab? */
+ for (p = tab; p < tab + tab_cur_size; p++)
+ if (STREQ (*p, name))
+ /* Yes; don't print it again. */
+ return;
+ /* No; add it to tab. */
+ if (tab_cur_size == tab_alloc_size)
+ {
+ tab_alloc_size *= 2;
+ tab = (char **) xrealloc ((char *) tab, tab_alloc_size * sizeof (*tab));
+ }
+ tab[tab_cur_size++] = name;
+
+ if (*first)
+ {
+ *first = 0;
+ }
+ else
+ {
+ printf_filtered (", ");
+ }
+
+ wrap_here ("");
+ fputs_filtered (name, gdb_stdout);
+}
+
+static void
+sources_info (ignore, from_tty)
+ char *ignore;
+ int from_tty;
+{
+ register struct symtab *s;
+ register struct partial_symtab *ps;
+ register struct objfile *objfile;
+ int first;
+
+ if (!have_full_symbols () && !have_partial_symbols ())
+ {
+ error (no_symtab_msg);
+ }
+
+ printf_filtered ("Source files for which symbols have been read in:\n\n");
+
+ first = 1;
+ ALL_SYMTABS (objfile, s)
+ {
+ output_source_filename (s -> filename, &first);
+ }
+ printf_filtered ("\n\n");
+
+ printf_filtered ("Source files for which symbols will be read in on demand:\n\n");
+
+ first = 1;
+ ALL_PSYMTABS (objfile, ps)
+ {
+ if (!ps->readin)
+ {
+ output_source_filename (ps -> filename, &first);
+ }
+ }
+ printf_filtered ("\n");
+}
+
+/* List all symbols (if REGEXP is NULL) or all symbols matching REGEXP.
+ If CLASS is zero, list all symbols except functions, type names, and
+ constants (enums).
+ If CLASS is 1, list only functions.
+ If CLASS is 2, list only type names.
+ If CLASS is 3, list only method names.
+
+ BPT is non-zero if we should set a breakpoint at the functions
+ we find. */
+
+static void
+list_symbols (regexp, class, bpt, from_tty)
+ char *regexp;
+ int class;
+ int bpt;
+ int from_tty;
+{
+ register struct symtab *s;
+ register struct partial_symtab *ps;
+ register struct blockvector *bv;
+ struct blockvector *prev_bv = 0;
+ register struct block *b;
+ register int i, j;
+ register struct symbol *sym;
+ struct partial_symbol *psym;
+ struct objfile *objfile;
+ struct minimal_symbol *msymbol;
+ char *val;
+ static char *classnames[]
+ = {"variable", "function", "type", "method"};
+ int found_in_file = 0;
+ int found_misc = 0;
+ static enum minimal_symbol_type types[]
+ = {mst_data, mst_text, mst_abs, mst_unknown};
+ static enum minimal_symbol_type types2[]
+ = {mst_bss, mst_file_text, mst_abs, mst_unknown};
+ static enum minimal_symbol_type types3[]
+ = {mst_file_data, mst_solib_trampoline, mst_abs, mst_unknown};
+ static enum minimal_symbol_type types4[]
+ = {mst_file_bss, mst_text, mst_abs, mst_unknown};
+ enum minimal_symbol_type ourtype = types[class];
+ enum minimal_symbol_type ourtype2 = types2[class];
+ enum minimal_symbol_type ourtype3 = types3[class];
+ enum minimal_symbol_type ourtype4 = types4[class];
+
+ if (regexp != NULL)
+ {
+ /* Make sure spacing is right for C++ operators.
+ This is just a courtesy to make the matching less sensitive
+ to how many spaces the user leaves between 'operator'
+ and <TYPENAME> or <OPERATOR>. */
+ char *opend;
+ char *opname = operator_chars (regexp, &opend);
+ if (*opname)
+ {
+ int fix = -1; /* -1 means ok; otherwise number of spaces needed. */
+ if (isalpha(*opname) || *opname == '_' || *opname == '$')
+ {
+ /* There should 1 space between 'operator' and 'TYPENAME'. */
+ if (opname[-1] != ' ' || opname[-2] == ' ')
+ fix = 1;
+ }
+ else
+ {
+ /* There should 0 spaces between 'operator' and 'OPERATOR'. */
+ if (opname[-1] == ' ')
+ fix = 0;
+ }
+ /* If wrong number of spaces, fix it. */
+ if (fix >= 0)
+ {
+ char *tmp = (char*) alloca(opend-opname+10);
+ sprintf(tmp, "operator%.*s%s", fix, " ", opname);
+ regexp = tmp;
+ }
+ }
+
+ if (0 != (val = re_comp (regexp)))
+ error ("Invalid regexp (%s): %s", val, regexp);
+ }
+
+ /* Search through the partial symtabs *first* for all symbols
+ matching the regexp. That way we don't have to reproduce all of
+ the machinery below. */
+
+ ALL_PSYMTABS (objfile, ps)
+ {
+ struct partial_symbol *bound, *gbound, *sbound;
+ int keep_going = 1;
+
+ if (ps->readin) continue;
+
+ gbound = objfile->global_psymbols.list + ps->globals_offset + ps->n_global_syms;
+ sbound = objfile->static_psymbols.list + ps->statics_offset + ps->n_static_syms;
+ bound = gbound;
+
+ /* Go through all of the symbols stored in a partial
+ symtab in one loop. */
+ psym = objfile->global_psymbols.list + ps->globals_offset;
+ while (keep_going)
+ {
+ if (psym >= bound)
+ {
+ if (bound == gbound && ps->n_static_syms != 0)
+ {
+ psym = objfile->static_psymbols.list + ps->statics_offset;
+ bound = sbound;
+ }
+ else
+ keep_going = 0;
+ continue;
+ }
+ else
+ {
+ QUIT;
+
+ /* If it would match (logic taken from loop below)
+ load the file and go on to the next one */
+ if ((regexp == NULL || SYMBOL_MATCHES_REGEXP (psym))
+ && ((class == 0 && SYMBOL_CLASS (psym) != LOC_TYPEDEF
+ && SYMBOL_CLASS (psym) != LOC_BLOCK)
+ || (class == 1 && SYMBOL_CLASS (psym) == LOC_BLOCK)
+ || (class == 2 && SYMBOL_CLASS (psym) == LOC_TYPEDEF)
+ || (class == 3 && SYMBOL_CLASS (psym) == LOC_BLOCK)))
+ {
+ PSYMTAB_TO_SYMTAB(ps);
+ keep_going = 0;
+ }
+ }
+ psym++;
+ }
+ }
+
+ /* Here, we search through the minimal symbol tables for functions that
+ match, and call find_pc_symtab on them to force their symbols to
+ be read. The symbol will then be found during the scan of symtabs
+ below. If find_pc_symtab fails, set found_misc so that we will
+ rescan to print any matching symbols without debug info. */
+
+ if (class == 1)
+ {
+ ALL_MSYMBOLS (objfile, msymbol)
+ {
+ if (MSYMBOL_TYPE (msymbol) == ourtype ||
+ MSYMBOL_TYPE (msymbol) == ourtype2 ||
+ MSYMBOL_TYPE (msymbol) == ourtype3 ||
+ MSYMBOL_TYPE (msymbol) == ourtype4)
+ {
+ if (regexp == NULL || SYMBOL_MATCHES_REGEXP (msymbol))
+ {
+ if (0 == find_pc_symtab (SYMBOL_VALUE_ADDRESS (msymbol)))
+ {
+ found_misc = 1;
+ }
+ }
+ }
+ }
+ }
+
+ /* Printout here so as to get after the "Reading in symbols"
+ messages which will be generated above. */
+ if (!bpt)
+ printf_filtered (regexp
+ ? "All %ss matching regular expression \"%s\":\n"
+ : "All defined %ss:\n",
+ classnames[class],
+ regexp);
+
+ ALL_SYMTABS (objfile, s)
+ {
+ found_in_file = 0;
+ bv = BLOCKVECTOR (s);
+ /* Often many files share a blockvector.
+ Scan each blockvector only once so that
+ we don't get every symbol many times.
+ It happens that the first symtab in the list
+ for any given blockvector is the main file. */
+ if (bv != prev_bv)
+ for (i = GLOBAL_BLOCK; i <= STATIC_BLOCK; i++)
+ {
+ b = BLOCKVECTOR_BLOCK (bv, i);
+ /* Skip the sort if this block is always sorted. */
+ if (!BLOCK_SHOULD_SORT (b))
+ sort_block_syms (b);
+ for (j = 0; j < BLOCK_NSYMS (b); j++)
+ {
+ QUIT;
+ sym = BLOCK_SYM (b, j);
+ if ((regexp == NULL || SYMBOL_MATCHES_REGEXP (sym))
+ && ((class == 0 && SYMBOL_CLASS (sym) != LOC_TYPEDEF
+ && SYMBOL_CLASS (sym) != LOC_BLOCK
+ && SYMBOL_CLASS (sym) != LOC_CONST)
+ || (class == 1 && SYMBOL_CLASS (sym) == LOC_BLOCK)
+ || (class == 2 && SYMBOL_CLASS (sym) == LOC_TYPEDEF)
+ || (class == 3 && SYMBOL_CLASS (sym) == LOC_BLOCK)))
+ {
+ if (bpt)
+ {
+ /* Set a breakpoint here, if it's a function */
+ if (class == 1)
+ {
+ /* There may be more than one function with the
+ same name but in different files. In order to
+ set breakpoints on all of them, we must give
+ both the file name and the function name to
+ break_command.
+ Quoting the symbol name gets rid of problems
+ with mangled symbol names that contain
+ CPLUS_MARKER characters. */
+ char *string =
+ (char *) alloca (strlen (s->filename)
+ + strlen (SYMBOL_NAME(sym))
+ + 4);
+ strcpy (string, s->filename);
+ strcat (string, ":'");
+ strcat (string, SYMBOL_NAME(sym));
+ strcat (string, "'");
+ break_command (string, from_tty);
+ }
+ }
+ else if (!found_in_file)
+ {
+ fputs_filtered ("\nFile ", gdb_stdout);
+ fputs_filtered (s->filename, gdb_stdout);
+ fputs_filtered (":\n", gdb_stdout);
+ }
+ found_in_file = 1;
+
+ if (class != 2 && i == STATIC_BLOCK)
+ printf_filtered ("static ");
+
+ /* Typedef that is not a C++ class */
+ if (class == 2
+ && SYMBOL_NAMESPACE (sym) != STRUCT_NAMESPACE)
+ c_typedef_print (SYMBOL_TYPE(sym), sym, gdb_stdout);
+ /* variable, func, or typedef-that-is-c++-class */
+ else if (class < 2 ||
+ (class == 2 &&
+ SYMBOL_NAMESPACE(sym) == STRUCT_NAMESPACE))
+ {
+ type_print (SYMBOL_TYPE (sym),
+ (SYMBOL_CLASS (sym) == LOC_TYPEDEF
+ ? "" : SYMBOL_SOURCE_NAME (sym)),
+ gdb_stdout, 0);
+
+ printf_filtered (";\n");
+ }
+ else
+ {
+# if 0 /* FIXME, why is this zapped out? */
+ char buf[1024];
+ c_type_print_base (TYPE_FN_FIELD_TYPE(t, i),
+ gdb_stdout, 0, 0);
+ c_type_print_varspec_prefix (TYPE_FN_FIELD_TYPE(t, i),
+ gdb_stdout, 0);
+ sprintf (buf, " %s::", type_name_no_tag (t));
+ cp_type_print_method_args (TYPE_FN_FIELD_ARGS (t, i),
+ buf, name, gdb_stdout);
+# endif
+ }
+ }
+ }
+ }
+ prev_bv = bv;
+ }
+
+ /* If there are no eyes, avoid all contact. I mean, if there are
+ no debug symbols, then print directly from the msymbol_vector. */
+
+ if (found_misc || class != 1)
+ {
+ found_in_file = 0;
+ ALL_MSYMBOLS (objfile, msymbol)
+ {
+ if (MSYMBOL_TYPE (msymbol) == ourtype ||
+ MSYMBOL_TYPE (msymbol) == ourtype2 ||
+ MSYMBOL_TYPE (msymbol) == ourtype3 ||
+ MSYMBOL_TYPE (msymbol) == ourtype4)
+ {
+ if (regexp == NULL || SYMBOL_MATCHES_REGEXP (msymbol))
+ {
+ /* Functions: Look up by address. */
+ if (class != 1 ||
+ (0 == find_pc_symtab (SYMBOL_VALUE_ADDRESS (msymbol))))
+ {
+ /* Variables/Absolutes: Look up by name */
+ if (lookup_symbol (SYMBOL_NAME (msymbol),
+ (struct block *) NULL, VAR_NAMESPACE,
+ 0, (struct symtab **) NULL) == NULL)
+ {
+ if (!found_in_file)
+ {
+ printf_filtered ("\nNon-debugging symbols:\n");
+ found_in_file = 1;
+ }
+ printf_filtered (" %08lx %s\n",
+ (unsigned long) SYMBOL_VALUE_ADDRESS (msymbol),
+ SYMBOL_SOURCE_NAME (msymbol));
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+static void
+variables_info (regexp, from_tty)
+ char *regexp;
+ int from_tty;
+{
+ list_symbols (regexp, 0, 0, from_tty);
+}
+
+static void
+functions_info (regexp, from_tty)
+ char *regexp;
+ int from_tty;
+{
+ list_symbols (regexp, 1, 0, from_tty);
+}
+
+static void
+types_info (regexp, from_tty)
+ char *regexp;
+ int from_tty;
+{
+ list_symbols (regexp, 2, 0, from_tty);
+}
+
+#if 0
+/* Tiemann says: "info methods was never implemented." */
+static void
+methods_info (regexp)
+ char *regexp;
+{
+ list_symbols (regexp, 3, 0, from_tty);
+}
+#endif /* 0 */
+
+/* Breakpoint all functions matching regular expression. */
+static void
+rbreak_command (regexp, from_tty)
+ char *regexp;
+ int from_tty;
+{
+ list_symbols (regexp, 1, 1, from_tty);
+}
+
+
+/* Return Nonzero if block a is lexically nested within block b,
+ or if a and b have the same pc range.
+ Return zero otherwise. */
+int
+contained_in (a, b)
+ struct block *a, *b;
+{
+ if (!a || !b)
+ return 0;
+ return BLOCK_START (a) >= BLOCK_START (b)
+ && BLOCK_END (a) <= BLOCK_END (b);
+}
+
+
+/* Helper routine for make_symbol_completion_list. */
+
+static int return_val_size;
+static int return_val_index;
+static char **return_val;
+
+#define COMPLETION_LIST_ADD_SYMBOL(symbol, sym_text, len, text, word) \
+ do { \
+ if (SYMBOL_DEMANGLED_NAME (symbol) != NULL) \
+ /* Put only the mangled name on the list. */ \
+ /* Advantage: "b foo<TAB>" completes to "b foo(int, int)" */ \
+ /* Disadvantage: "b foo__i<TAB>" doesn't complete. */ \
+ completion_list_add_name \
+ (SYMBOL_DEMANGLED_NAME (symbol), (sym_text), (len), (text), (word)); \
+ else \
+ completion_list_add_name \
+ (SYMBOL_NAME (symbol), (sym_text), (len), (text), (word)); \
+ } while (0)
+
+/* Test to see if the symbol specified by SYMNAME (which is already
+ demangled for C++ symbols) matches SYM_TEXT in the first SYM_TEXT_LEN
+ characters. If so, add it to the current completion list. */
+
+static void
+completion_list_add_name (symname, sym_text, sym_text_len, text, word)
+ char *symname;
+ char *sym_text;
+ int sym_text_len;
+ char *text;
+ char *word;
+{
+ int newsize;
+ int i;
+
+ /* clip symbols that cannot match */
+
+ if (strncmp (symname, sym_text, sym_text_len) != 0)
+ {
+ return;
+ }
+
+ /* Clip any symbol names that we've already considered. (This is a
+ time optimization) */
+
+ for (i = 0; i < return_val_index; ++i)
+ {
+ if (STREQ (symname, return_val[i]))
+ {
+ return;
+ }
+ }
+
+ /* We have a match for a completion, so add SYMNAME to the current list
+ of matches. Note that the name is moved to freshly malloc'd space. */
+
+ {
+ char *new;
+ if (word == sym_text)
+ {
+ new = xmalloc (strlen (symname) + 5);
+ strcpy (new, symname);
+ }
+ else if (word > sym_text)
+ {
+ /* Return some portion of symname. */
+ new = xmalloc (strlen (symname) + 5);
+ strcpy (new, symname + (word - sym_text));
+ }
+ else
+ {
+ /* Return some of SYM_TEXT plus symname. */
+ new = xmalloc (strlen (symname) + (sym_text - word) + 5);
+ strncpy (new, word, sym_text - word);
+ new[sym_text - word] = '\0';
+ strcat (new, symname);
+ }
+
+ if (return_val_index + 3 > return_val_size)
+ {
+ newsize = (return_val_size *= 2) * sizeof (char *);
+ return_val = (char **) xrealloc ((char *) return_val, newsize);
+ }
+ return_val[return_val_index++] = new;
+ return_val[return_val_index] = NULL;
+ }
+}
+
+/* Return a NULL terminated array of all symbols (regardless of class) which
+ begin by matching TEXT. If the answer is no symbols, then the return value
+ is an array which contains only a NULL pointer.
+
+ Problem: All of the symbols have to be copied because readline frees them.
+ I'm not going to worry about this; hopefully there won't be that many. */
+
+char **
+make_symbol_completion_list (text, word)
+ char *text;
+ char *word;
+{
+ register struct symbol *sym;
+ register struct symtab *s;
+ register struct partial_symtab *ps;
+ register struct minimal_symbol *msymbol;
+ register struct objfile *objfile;
+ register struct block *b, *surrounding_static_block = 0;
+ register int i, j;
+ struct partial_symbol *psym;
+ /* The symbol we are completing on. Points in same buffer as text. */
+ char *sym_text;
+ /* Length of sym_text. */
+ int sym_text_len;
+
+ /* Now look for the symbol we are supposed to complete on.
+ FIXME: This should be language-specific. */
+ {
+ char *p;
+ char quote_found;
+ char *quote_pos = NULL;
+
+ /* First see if this is a quoted string. */
+ quote_found = '\0';
+ for (p = text; *p != '\0'; ++p)
+ {
+ if (quote_found != '\0')
+ {
+ if (*p == quote_found)
+ /* Found close quote. */
+ quote_found = '\0';
+ else if (*p == '\\' && p[1] == quote_found)
+ /* A backslash followed by the quote character
+ doesn't end the string. */
+ ++p;
+ }
+ else if (*p == '\'' || *p == '"')
+ {
+ quote_found = *p;
+ quote_pos = p;
+ }
+ }
+ if (quote_found == '\'')
+ /* A string within single quotes can be a symbol, so complete on it. */
+ sym_text = quote_pos + 1;
+ else if (quote_found == '"')
+ /* A double-quoted string is never a symbol, nor does it make sense
+ to complete it any other way. */
+ return NULL;
+ else
+ {
+ /* It is not a quoted string. Break it based on the characters
+ which are in symbols. */
+ while (p > text)
+ {
+ if (isalnum (p[-1]) || p[-1] == '_' || p[-1] == '\0')
+ --p;
+ else
+ break;
+ }
+ sym_text = p;
+ }
+ }
+
+ sym_text_len = strlen (sym_text);
+
+ return_val_size = 100;
+ return_val_index = 0;
+ return_val = (char **) xmalloc ((return_val_size + 1) * sizeof (char *));
+ return_val[0] = NULL;
+
+ /* Look through the partial symtabs for all symbols which begin
+ by matching SYM_TEXT. Add each one that you find to the list. */
+
+ ALL_PSYMTABS (objfile, ps)
+ {
+ /* If the psymtab's been read in we'll get it when we search
+ through the blockvector. */
+ if (ps->readin) continue;
+
+ for (psym = objfile->global_psymbols.list + ps->globals_offset;
+ psym < (objfile->global_psymbols.list + ps->globals_offset
+ + ps->n_global_syms);
+ psym++)
+ {
+ /* If interrupted, then quit. */
+ QUIT;
+ COMPLETION_LIST_ADD_SYMBOL (psym, sym_text, sym_text_len, text, word);
+ }
+
+ for (psym = objfile->static_psymbols.list + ps->statics_offset;
+ psym < (objfile->static_psymbols.list + ps->statics_offset
+ + ps->n_static_syms);
+ psym++)
+ {
+ QUIT;
+ COMPLETION_LIST_ADD_SYMBOL (psym, sym_text, sym_text_len, text, word);
+ }
+ }
+
+ /* At this point scan through the misc symbol vectors and add each
+ symbol you find to the list. Eventually we want to ignore
+ anything that isn't a text symbol (everything else will be
+ handled by the psymtab code above). */
+
+ ALL_MSYMBOLS (objfile, msymbol)
+ {
+ QUIT;
+ COMPLETION_LIST_ADD_SYMBOL (msymbol, sym_text, sym_text_len, text, word);
+ }
+
+ /* Search upwards from currently selected frame (so that we can
+ complete on local vars. */
+
+ for (b = get_selected_block (); b != NULL; b = BLOCK_SUPERBLOCK (b))
+ {
+ if (!BLOCK_SUPERBLOCK (b))
+ {
+ surrounding_static_block = b; /* For elmin of dups */
+ }
+
+ /* Also catch fields of types defined in this places which match our
+ text string. Only complete on types visible from current context. */
+
+ for (i = 0; i < BLOCK_NSYMS (b); i++)
+ {
+ sym = BLOCK_SYM (b, i);
+ COMPLETION_LIST_ADD_SYMBOL (sym, sym_text, sym_text_len, text, word);
+ if (SYMBOL_CLASS (sym) == LOC_TYPEDEF)
+ {
+ struct type *t = SYMBOL_TYPE (sym);
+ enum type_code c = TYPE_CODE (t);
+
+ if (c == TYPE_CODE_UNION || c == TYPE_CODE_STRUCT)
+ {
+ for (j = TYPE_N_BASECLASSES (t); j < TYPE_NFIELDS (t); j++)
+ {
+ if (TYPE_FIELD_NAME (t, j))
+ {
+ completion_list_add_name (TYPE_FIELD_NAME (t, j),
+ sym_text, sym_text_len, text, word);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /* Go through the symtabs and check the externs and statics for
+ symbols which match. */
+
+ ALL_SYMTABS (objfile, s)
+ {
+ QUIT;
+ b = BLOCKVECTOR_BLOCK (BLOCKVECTOR (s), GLOBAL_BLOCK);
+ for (i = 0; i < BLOCK_NSYMS (b); i++)
+ {
+ sym = BLOCK_SYM (b, i);
+ COMPLETION_LIST_ADD_SYMBOL (sym, sym_text, sym_text_len, text, word);
+ }
+ }
+
+ ALL_SYMTABS (objfile, s)
+ {
+ QUIT;
+ b = BLOCKVECTOR_BLOCK (BLOCKVECTOR (s), STATIC_BLOCK);
+ /* Don't do this block twice. */
+ if (b == surrounding_static_block) continue;
+ for (i = 0; i < BLOCK_NSYMS (b); i++)
+ {
+ sym = BLOCK_SYM (b, i);
+ COMPLETION_LIST_ADD_SYMBOL (sym, sym_text, sym_text_len, text, word);
+ }
+ }
+
+ return (return_val);
+}
+
+
+#if 0
+/* Add the type of the symbol sym to the type of the current
+ function whose block we are in (assumed). The type of
+ this current function is contained in *TYPE.
+
+ This basically works as follows: When we find a function
+ symbol (N_FUNC with a 'f' or 'F' in the symbol name), we record
+ a pointer to its type in the global in_function_type. Every
+ time we come across a parameter symbol ('p' in its name), then
+ this procedure adds the name and type of that parameter
+ to the function type pointed to by *TYPE. (Which should correspond
+ to in_function_type if it was called correctly).
+
+ Note that since we are modifying a type, the result of
+ lookup_function_type() should be memcpy()ed before calling
+ this. When not in strict typing mode, the expression
+ evaluator can choose to ignore this.
+
+ Assumption: All of a function's parameter symbols will
+ appear before another function symbol is found. The parameters
+ appear in the same order in the argument list as they do in the
+ symbol table. */
+
+void
+add_param_to_type (type,sym)
+ struct type **type;
+ struct symbol *sym;
+{
+ int num = ++(TYPE_NFIELDS(*type));
+
+ if(TYPE_NFIELDS(*type)-1)
+ TYPE_FIELDS(*type) = (struct field *)
+ (*current_objfile->xrealloc) ((char *)(TYPE_FIELDS(*type)),
+ num*sizeof(struct field));
+ else
+ TYPE_FIELDS(*type) = (struct field *)
+ (*current_objfile->xmalloc) (num*sizeof(struct field));
+
+ TYPE_FIELD_BITPOS(*type,num-1) = num-1;
+ TYPE_FIELD_BITSIZE(*type,num-1) = 0;
+ TYPE_FIELD_TYPE(*type,num-1) = SYMBOL_TYPE(sym);
+ TYPE_FIELD_NAME(*type,num-1) = SYMBOL_NAME(sym);
+}
+#endif
+
+void
+_initialize_symtab ()
+{
+ add_info ("variables", variables_info,
+ "All global and static variable names, or those matching REGEXP.");
+ add_info ("functions", functions_info,
+ "All function names, or those matching REGEXP.");
+
+ /* FIXME: This command has at least the following problems:
+ 1. It prints builtin types (in a very strange and confusing fashion).
+ 2. It doesn't print right, e.g. with
+ typedef struct foo *FOO
+ type_print prints "FOO" when we want to make it (in this situation)
+ print "struct foo *".
+ I also think "ptype" or "whatis" is more likely to be useful (but if
+ there is much disagreement "info types" can be fixed). */
+ add_info ("types", types_info,
+ "All type names, or those matching REGEXP.");
+
+#if 0
+ add_info ("methods", methods_info,
+ "All method names, or those matching REGEXP::REGEXP.\n\
+If the class qualifier is omitted, it is assumed to be the current scope.\n\
+If the first REGEXP is omitted, then all methods matching the second REGEXP\n\
+are listed.");
+#endif
+ add_info ("sources", sources_info,
+ "Source files in the program.");
+
+ add_com ("rbreak", no_class, rbreak_command,
+ "Set a breakpoint for all functions matching REGEXP.");
+
+ /* Initialize the one built-in type that isn't language dependent... */
+ builtin_type_error = init_type (TYPE_CODE_ERROR, 0, 0,
+ "<unknown type>", (struct objfile *) NULL);
+}
diff --git a/gnu/usr.bin/gdb/gdb/symtab.h b/gnu/usr.bin/gdb/gdb/symtab.h
new file mode 100644
index 0000000..5e4fa56
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/symtab.h
@@ -0,0 +1,1176 @@
+/* Symbol table definitions for GDB.
+ Copyright 1986, 1989, 1991, 1992, 1993, 1994 Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#if !defined (SYMTAB_H)
+#define SYMTAB_H 1
+
+/* Some definitions and declarations to go with use of obstacks. */
+
+#include "obstack.h"
+#define obstack_chunk_alloc xmalloc
+#define obstack_chunk_free free
+
+/* Don't do this; it means that if some .o's are compiled with GNU C
+ and some are not (easy to do accidentally the way we configure
+ things; also it is a pain to have to "make clean" every time you
+ want to switch compilers), then GDB dies a horrible death. */
+/* GNU C supports enums that are bitfields. Some compilers don't. */
+#if 0 && defined(__GNUC__) && !defined(BYTE_BITFIELD)
+#define BYTE_BITFIELD :8;
+#else
+#define BYTE_BITFIELD /*nothing*/
+#endif
+
+/* Define a structure for the information that is common to all symbol types,
+ including minimal symbols, partial symbols, and full symbols. In a
+ multilanguage environment, some language specific information may need to
+ be recorded along with each symbol.
+
+ These fields are ordered to encourage good packing, since we frequently
+ have tens or hundreds of thousands of these. */
+
+struct general_symbol_info
+{
+ /* Name of the symbol. This is a required field. Storage for the name is
+ allocated on the psymbol_obstack or symbol_obstack for the associated
+ objfile. */
+
+ char *name;
+
+ /* Value of the symbol. Which member of this union to use, and what
+ it means, depends on what kind of symbol this is and its
+ SYMBOL_CLASS. See comments there for more details. All of these
+ are in host byte order (though what they point to might be in
+ target byte order, e.g. LOC_CONST_BYTES). */
+
+ union
+ {
+ /* The fact that this is a long not a LONGEST mainly limits the
+ range of a LOC_CONST. Since LOC_CONST_BYTES exists, I'm not
+ sure that is a big deal. */
+ long ivalue;
+
+ struct block *block;
+
+ char *bytes;
+
+ CORE_ADDR address;
+
+ /* for opaque typedef struct chain */
+
+ struct symbol *chain;
+ }
+ value;
+
+ /* Since one and only one language can apply, wrap the language specific
+ information inside a union. */
+
+ union
+ {
+ struct cplus_specific /* For C++ */
+ {
+ char *demangled_name;
+ } cplus_specific;
+ struct chill_specific /* For Chill */
+ {
+ char *demangled_name;
+ } chill_specific;
+ } language_specific;
+
+ /* Record the source code language that applies to this symbol.
+ This is used to select one of the fields from the language specific
+ union above. */
+
+ enum language language BYTE_BITFIELD;
+
+ /* Which section is this symbol in? This is an index into
+ section_offsets for this objfile. Negative means that the symbol
+ does not get relocated relative to a section.
+ Disclaimer: currently this is just used for xcoff, so don't
+ expect all symbol-reading code to set it correctly (the ELF code
+ also tries to set it correctly). */
+
+ short section;
+};
+
+#define SYMBOL_NAME(symbol) (symbol)->ginfo.name
+#define SYMBOL_VALUE(symbol) (symbol)->ginfo.value.ivalue
+#define SYMBOL_VALUE_ADDRESS(symbol) (symbol)->ginfo.value.address
+#define SYMBOL_VALUE_BYTES(symbol) (symbol)->ginfo.value.bytes
+#define SYMBOL_BLOCK_VALUE(symbol) (symbol)->ginfo.value.block
+#define SYMBOL_VALUE_CHAIN(symbol) (symbol)->ginfo.value.chain
+#define SYMBOL_LANGUAGE(symbol) (symbol)->ginfo.language
+#define SYMBOL_SECTION(symbol) (symbol)->ginfo.section
+
+#define SYMBOL_CPLUS_DEMANGLED_NAME(symbol) \
+ (symbol)->ginfo.language_specific.cplus_specific.demangled_name
+
+/* Macro that initializes the language dependent portion of a symbol
+ depending upon the language for the symbol. */
+
+#define SYMBOL_INIT_LANGUAGE_SPECIFIC(symbol,language) \
+ do { \
+ SYMBOL_LANGUAGE (symbol) = language; \
+ if (SYMBOL_LANGUAGE (symbol) == language_cplus) \
+ { \
+ SYMBOL_CPLUS_DEMANGLED_NAME (symbol) = NULL; \
+ } \
+ else if (SYMBOL_LANGUAGE (symbol) == language_chill) \
+ { \
+ SYMBOL_CHILL_DEMANGLED_NAME (symbol) = NULL; \
+ } \
+ else \
+ { \
+ memset (&(symbol)->ginfo.language_specific, 0, \
+ sizeof ((symbol)->ginfo.language_specific)); \
+ } \
+ } while (0)
+
+/* Macro that attempts to initialize the demangled name for a symbol,
+ based on the language of that symbol. If the language is set to
+ language_auto, it will attempt to find any demangling algorithm
+ that works and then set the language appropriately. If no demangling
+ of any kind is found, the language is set back to language_unknown,
+ so we can avoid doing this work again the next time we encounter
+ the symbol. Any required space to store the name is obtained from the
+ specified obstack. */
+
+#define SYMBOL_INIT_DEMANGLED_NAME(symbol,obstack) \
+ do { \
+ char *demangled = NULL; \
+ if (SYMBOL_LANGUAGE (symbol) == language_cplus \
+ || SYMBOL_LANGUAGE (symbol) == language_auto) \
+ { \
+ demangled = \
+ cplus_demangle (SYMBOL_NAME (symbol), DMGL_PARAMS | DMGL_ANSI);\
+ if (demangled != NULL) \
+ { \
+ SYMBOL_LANGUAGE (symbol) = language_cplus; \
+ SYMBOL_CPLUS_DEMANGLED_NAME (symbol) = \
+ obsavestring (demangled, strlen (demangled), (obstack)); \
+ free (demangled); \
+ } \
+ else \
+ { \
+ SYMBOL_CPLUS_DEMANGLED_NAME (symbol) = NULL; \
+ } \
+ } \
+ if (demangled == NULL \
+ && (SYMBOL_LANGUAGE (symbol) == language_chill \
+ || SYMBOL_LANGUAGE (symbol) == language_auto)) \
+ { \
+ demangled = \
+ chill_demangle (SYMBOL_NAME (symbol)); \
+ if (demangled != NULL) \
+ { \
+ SYMBOL_LANGUAGE (symbol) = language_chill; \
+ SYMBOL_CHILL_DEMANGLED_NAME (symbol) = \
+ obsavestring (demangled, strlen (demangled), (obstack)); \
+ free (demangled); \
+ } \
+ else \
+ { \
+ SYMBOL_CHILL_DEMANGLED_NAME (symbol) = NULL; \
+ } \
+ } \
+ if (SYMBOL_LANGUAGE (symbol) == language_auto) \
+ { \
+ SYMBOL_LANGUAGE (symbol) = language_unknown; \
+ } \
+ } while (0)
+
+/* Macro that returns the demangled name for a symbol based on the language
+ for that symbol. If no demangled name exists, returns NULL. */
+
+#define SYMBOL_DEMANGLED_NAME(symbol) \
+ (SYMBOL_LANGUAGE (symbol) == language_cplus \
+ ? SYMBOL_CPLUS_DEMANGLED_NAME (symbol) \
+ : (SYMBOL_LANGUAGE (symbol) == language_chill \
+ ? SYMBOL_CHILL_DEMANGLED_NAME (symbol) \
+ : NULL))
+
+#define SYMBOL_CHILL_DEMANGLED_NAME(symbol) \
+ (symbol)->ginfo.language_specific.chill_specific.demangled_name
+
+/* Macro that returns the "natural source name" of a symbol. In C++ this is
+ the "demangled" form of the name if demangle is on and the "mangled" form
+ of the name if demangle is off. In other languages this is just the
+ symbol name. The result should never be NULL. */
+
+#define SYMBOL_SOURCE_NAME(symbol) \
+ (demangle && SYMBOL_DEMANGLED_NAME (symbol) != NULL \
+ ? SYMBOL_DEMANGLED_NAME (symbol) \
+ : SYMBOL_NAME (symbol))
+
+/* Macro that returns the "natural assembly name" of a symbol. In C++ this is
+ the "mangled" form of the name if demangle is off, or if demangle is on and
+ asm_demangle is off. Otherwise if asm_demangle is on it is the "demangled"
+ form. In other languages this is just the symbol name. The result should
+ never be NULL. */
+
+#define SYMBOL_LINKAGE_NAME(symbol) \
+ (demangle && asm_demangle && SYMBOL_DEMANGLED_NAME (symbol) != NULL \
+ ? SYMBOL_DEMANGLED_NAME (symbol) \
+ : SYMBOL_NAME (symbol))
+
+/* Macro that tests a symbol for a match against a specified name string.
+ First test the unencoded name, then looks for and test a C++ encoded
+ name if it exists. Note that whitespace is ignored while attempting to
+ match a C++ encoded name, so that "foo::bar(int,long)" is the same as
+ "foo :: bar (int, long)".
+ Evaluates to zero if the match fails, or nonzero if it succeeds. */
+
+#define SYMBOL_MATCHES_NAME(symbol, name) \
+ (STREQ (SYMBOL_NAME (symbol), (name)) \
+ || (SYMBOL_DEMANGLED_NAME (symbol) != NULL \
+ && strcmp_iw (SYMBOL_DEMANGLED_NAME (symbol), (name)) == 0))
+
+/* Macro that tests a symbol for an re-match against the last compiled regular
+ expression. First test the unencoded name, then look for and test a C++
+ encoded name if it exists.
+ Evaluates to zero if the match fails, or nonzero if it succeeds. */
+
+#define SYMBOL_MATCHES_REGEXP(symbol) \
+ (re_exec (SYMBOL_NAME (symbol)) != 0 \
+ || (SYMBOL_DEMANGLED_NAME (symbol) != NULL \
+ && re_exec (SYMBOL_DEMANGLED_NAME (symbol)) != 0))
+
+/* Define a simple structure used to hold some very basic information about
+ all defined global symbols (text, data, bss, abs, etc). The only required
+ information is the general_symbol_info.
+
+ In many cases, even if a file was compiled with no special options for
+ debugging at all, as long as was not stripped it will contain sufficient
+ information to build a useful minimal symbol table using this structure.
+ Even when a file contains enough debugging information to build a full
+ symbol table, these minimal symbols are still useful for quickly mapping
+ between names and addresses, and vice versa. They are also sometimes
+ used to figure out what full symbol table entries need to be read in. */
+
+struct minimal_symbol
+{
+
+ /* The general symbol info required for all types of symbols.
+
+ The SYMBOL_VALUE_ADDRESS contains the address that this symbol
+ corresponds to. */
+
+ struct general_symbol_info ginfo;
+
+ /* The info field is available for caching machine-specific information that
+ The AMD 29000 tdep.c uses it to remember things it has decoded from the
+ instructions in the function header, so it doesn't have to rederive the
+ info constantly (over a serial line). It is initialized to zero and
+ stays that way until target-dependent code sets it. Storage for any data
+ pointed to by this field should be allocated on the symbol_obstack for
+ the associated objfile. The type would be "void *" except for reasons
+ of compatibility with older compilers. This field is optional. */
+
+ char *info;
+
+ /* Classification types for this symbol. These should be taken as "advisory
+ only", since if gdb can't easily figure out a classification it simply
+ selects mst_unknown. It may also have to guess when it can't figure out
+ which is a better match between two types (mst_data versus mst_bss) for
+ example. Since the minimal symbol info is sometimes derived from the
+ BFD library's view of a file, we need to live with what information bfd
+ supplies. */
+
+ enum minimal_symbol_type
+ {
+ mst_unknown = 0, /* Unknown type, the default */
+ mst_text, /* Generally executable instructions */
+ mst_data, /* Generally initialized data */
+ mst_bss, /* Generally uninitialized data */
+ mst_abs, /* Generally absolute (nonrelocatable) */
+ /* GDB uses mst_solib_trampoline for the start address of a shared
+ library trampoline entry. Breakpoints for shared library functions
+ are put there if the shared library is not yet loaded.
+ After the shared library is loaded, lookup_minimal_symbol will
+ prefer the minimal symbol from the shared library (usually
+ a mst_text symbol) over the mst_solib_trampoline symbol, and the
+ breakpoints will be moved to their true address in the shared
+ library via breakpoint_re_set. */
+ mst_solib_trampoline, /* Shared library trampoline code */
+ /* For the mst_file* types, the names are only guaranteed to be unique
+ within a given .o file. */
+ mst_file_text, /* Static version of mst_text */
+ mst_file_data, /* Static version of mst_data */
+ mst_file_bss /* Static version of mst_bss */
+ } type BYTE_BITFIELD;
+
+};
+
+#define MSYMBOL_INFO(msymbol) (msymbol)->info
+#define MSYMBOL_TYPE(msymbol) (msymbol)->type
+
+
+/* All of the name-scope contours of the program
+ are represented by `struct block' objects.
+ All of these objects are pointed to by the blockvector.
+
+ Each block represents one name scope.
+ Each lexical context has its own block.
+
+ The blockvector begins with some special blocks.
+ The GLOBAL_BLOCK contains all the symbols defined in this compilation
+ whose scope is the entire program linked together.
+ The STATIC_BLOCK contains all the symbols whose scope is the
+ entire compilation excluding other separate compilations.
+ Blocks starting with the FIRST_LOCAL_BLOCK are not special.
+
+ Each block records a range of core addresses for the code that
+ is in the scope of the block. The STATIC_BLOCK and GLOBAL_BLOCK
+ give, for the range of code, the entire range of code produced
+ by the compilation that the symbol segment belongs to.
+
+ The blocks appear in the blockvector
+ in order of increasing starting-address,
+ and, within that, in order of decreasing ending-address.
+
+ This implies that within the body of one function
+ the blocks appear in the order of a depth-first tree walk. */
+
+struct blockvector
+{
+ /* Number of blocks in the list. */
+ int nblocks;
+ /* The blocks themselves. */
+ struct block *block[1];
+};
+
+#define BLOCKVECTOR_NBLOCKS(blocklist) (blocklist)->nblocks
+#define BLOCKVECTOR_BLOCK(blocklist,n) (blocklist)->block[n]
+
+/* Special block numbers */
+
+#define GLOBAL_BLOCK 0
+#define STATIC_BLOCK 1
+#define FIRST_LOCAL_BLOCK 2
+
+struct block
+{
+
+ /* Addresses in the executable code that are in this block. */
+
+ CORE_ADDR startaddr;
+ CORE_ADDR endaddr;
+
+ /* The symbol that names this block, if the block is the body of a
+ function; otherwise, zero. */
+
+ struct symbol *function;
+
+ /* The `struct block' for the containing block, or 0 if none.
+
+ The superblock of a top-level local block (i.e. a function in the
+ case of C) is the STATIC_BLOCK. The superblock of the
+ STATIC_BLOCK is the GLOBAL_BLOCK. */
+
+ struct block *superblock;
+
+ /* Version of GCC used to compile the function corresponding
+ to this block, or 0 if not compiled with GCC. When possible,
+ GCC should be compatible with the native compiler, or if that
+ is not feasible, the differences should be fixed during symbol
+ reading. As of 16 Apr 93, this flag is never used to distinguish
+ between gcc2 and the native compiler.
+
+ If there is no function corresponding to this block, this meaning
+ of this flag is undefined. */
+
+ unsigned char gcc_compile_flag;
+
+ /* Number of local symbols. */
+
+ int nsyms;
+
+ /* The symbols. If some of them are arguments, then they must be
+ in the order in which we would like to print them. */
+
+ struct symbol *sym[1];
+};
+
+#define BLOCK_START(bl) (bl)->startaddr
+#define BLOCK_END(bl) (bl)->endaddr
+#define BLOCK_NSYMS(bl) (bl)->nsyms
+#define BLOCK_SYM(bl, n) (bl)->sym[n]
+#define BLOCK_FUNCTION(bl) (bl)->function
+#define BLOCK_SUPERBLOCK(bl) (bl)->superblock
+#define BLOCK_GCC_COMPILED(bl) (bl)->gcc_compile_flag
+
+/* Nonzero if symbols of block BL should be sorted alphabetically.
+ Don't sort a block which corresponds to a function. If we did the
+ sorting would have to preserve the order of the symbols for the
+ arguments. */
+
+#define BLOCK_SHOULD_SORT(bl) ((bl)->nsyms >= 40 && BLOCK_FUNCTION (bl) == NULL)
+
+
+/* Represent one symbol name; a variable, constant, function or typedef. */
+
+/* Different name spaces for symbols. Looking up a symbol specifies a
+ namespace and ignores symbol definitions in other name spaces. */
+
+enum namespace
+{
+ /* UNDEF_NAMESPACE is used when a namespace has not been discovered or
+ none of the following apply. This usually indicates an error either
+ in the symbol information or in gdb's handling of symbols. */
+
+ UNDEF_NAMESPACE,
+
+ /* VAR_NAMESPACE is the usual namespace. In C, this contains variables,
+ function names, typedef names and enum type values. */
+
+ VAR_NAMESPACE,
+
+ /* STRUCT_NAMESPACE is used in C to hold struct, union and enum type names.
+ Thus, if `struct foo' is used in a C program, it produces a symbol named
+ `foo' in the STRUCT_NAMESPACE. */
+
+ STRUCT_NAMESPACE,
+
+ /* LABEL_NAMESPACE may be used for names of labels (for gotos);
+ currently it is not used and labels are not recorded at all. */
+
+ LABEL_NAMESPACE
+};
+
+/* An address-class says where to find the value of a symbol. */
+
+enum address_class
+{
+ /* Not used; catches errors */
+
+ LOC_UNDEF,
+
+ /* Value is constant int SYMBOL_VALUE, host byteorder */
+
+ LOC_CONST,
+
+ /* Value is at fixed address SYMBOL_VALUE_ADDRESS */
+
+ LOC_STATIC,
+
+ /* Value is in register. SYMBOL_VALUE is the register number. */
+
+ LOC_REGISTER,
+
+ /* It's an argument; the value is at SYMBOL_VALUE offset in arglist. */
+
+ LOC_ARG,
+
+ /* Value address is at SYMBOL_VALUE offset in arglist. */
+
+ LOC_REF_ARG,
+
+ /* Value is in register number SYMBOL_VALUE. Just like LOC_REGISTER
+ except this is an argument. Probably the cleaner way to handle
+ this would be to separate address_class (which would include
+ separate ARG and LOCAL to deal with FRAME_ARGS_ADDRESS versus
+ FRAME_LOCALS_ADDRESS), and an is_argument flag.
+
+ For some symbol formats (stabs, for some compilers at least),
+ the compiler generates two symbols, an argument and a register.
+ In some cases we combine them to a single LOC_REGPARM in symbol
+ reading, but currently not for all cases (e.g. it's passed on the
+ stack and then loaded into a register). */
+
+ LOC_REGPARM,
+
+ /* Value is in specified register. Just like LOC_REGPARM except the
+ register holds the address of the argument instead of the argument
+ itself. This is currently used for the passing of structs and unions
+ on sparc and hppa. It is also used for call by reference where the
+ address is in a register, at least by mipsread.c. */
+
+ LOC_REGPARM_ADDR,
+
+ /* Value is a local variable at SYMBOL_VALUE offset in stack frame. */
+
+ LOC_LOCAL,
+
+ /* Value not used; definition in SYMBOL_TYPE. Symbols in the namespace
+ STRUCT_NAMESPACE all have this class. */
+
+ LOC_TYPEDEF,
+
+ /* Value is address SYMBOL_VALUE_ADDRESS in the code */
+
+ LOC_LABEL,
+
+ /* In a symbol table, value is SYMBOL_BLOCK_VALUE of a `struct block'.
+ In a partial symbol table, SYMBOL_VALUE_ADDRESS is the start address
+ of the block. Function names have this class. */
+
+ LOC_BLOCK,
+
+ /* Value is a constant byte-sequence pointed to by SYMBOL_VALUE_BYTES, in
+ target byte order. */
+
+ LOC_CONST_BYTES,
+
+ /* Value is arg at SYMBOL_VALUE offset in stack frame. Differs from
+ LOC_LOCAL in that symbol is an argument; differs from LOC_ARG in
+ that we find it in the frame (FRAME_LOCALS_ADDRESS), not in the
+ arglist (FRAME_ARGS_ADDRESS). Added for i960, which passes args
+ in regs then copies to frame. */
+
+ LOC_LOCAL_ARG,
+
+ /* Value is at SYMBOL_VALUE offset from the current value of
+ register number SYMBOL_BASEREG. This exists mainly for the same
+ things that LOC_LOCAL and LOC_ARG do; but we need to do this
+ instead because on 88k DWARF gives us the offset from the
+ frame/stack pointer, rather than the offset from the "canonical
+ frame address" used by COFF, stabs, etc., and we don't know how
+ to convert between these until we start examining prologues.
+
+ Note that LOC_BASEREG is much less general than a DWARF expression.
+ We don't need the generality (at least not yet), and storing a general
+ DWARF expression would presumably take up more space than the existing
+ scheme. */
+
+ LOC_BASEREG,
+
+ /* Same as LOC_BASEREG but it is an argument. */
+
+ LOC_BASEREG_ARG,
+
+ /* The variable does not actually exist in the program.
+ The value is ignored. */
+
+ LOC_OPTIMIZED_OUT
+};
+
+struct symbol
+{
+
+ /* The general symbol info required for all types of symbols. */
+
+ struct general_symbol_info ginfo;
+
+ /* Data type of value */
+
+ struct type *type;
+
+ /* Name space code. */
+
+ enum namespace namespace BYTE_BITFIELD;
+
+ /* Address class */
+
+ enum address_class class BYTE_BITFIELD;
+
+ /* Line number of definition. FIXME: Should we really make the assumption
+ that nobody will try to debug files longer than 64K lines? What about
+ machine generated programs? */
+
+ unsigned short line;
+
+ /* Some symbols require an additional value to be recorded on a per-
+ symbol basis. Stash those values here. */
+
+ union
+ {
+ /* Used by LOC_BASEREG and LOC_BASEREG_ARG. */
+ short basereg;
+ }
+ aux_value;
+};
+
+#define SYMBOL_NAMESPACE(symbol) (symbol)->namespace
+#define SYMBOL_CLASS(symbol) (symbol)->class
+#define SYMBOL_TYPE(symbol) (symbol)->type
+#define SYMBOL_LINE(symbol) (symbol)->line
+#define SYMBOL_BASEREG(symbol) (symbol)->aux_value.basereg
+
+/* A partial_symbol records the name, namespace, and address class of
+ symbols whose types we have not parsed yet. For functions, it also
+ contains their memory address, so we can find them from a PC value.
+ Each partial_symbol sits in a partial_symtab, all of which are chained
+ on a partial symtab list and which points to the corresponding
+ normal symtab once the partial_symtab has been referenced. */
+
+struct partial_symbol
+{
+
+ /* The general symbol info required for all types of symbols. */
+
+ struct general_symbol_info ginfo;
+
+ /* Name space code. */
+
+ enum namespace namespace BYTE_BITFIELD;
+
+ /* Address class (for info_symbols) */
+
+ enum address_class class BYTE_BITFIELD;
+
+};
+
+#define PSYMBOL_NAMESPACE(psymbol) (psymbol)->namespace
+#define PSYMBOL_CLASS(psymbol) (psymbol)->class
+
+
+/* Source-file information. This describes the relation between source files,
+ ine numbers and addresses in the program text. */
+
+struct sourcevector
+{
+ int length; /* Number of source files described */
+ struct source *source[1]; /* Descriptions of the files */
+};
+
+/* Each item represents a line-->pc (or the reverse) mapping. This is
+ somewhat more wasteful of space than one might wish, but since only
+ the files which are actually debugged are read in to core, we don't
+ waste much space. */
+
+struct linetable_entry
+{
+ int line;
+ CORE_ADDR pc;
+};
+
+/* The order of entries in the linetable is significant. They should
+ be sorted by increasing values of the pc field. If there is more than
+ one entry for a given pc, then I'm not sure what should happen (and
+ I not sure whether we currently handle it the best way).
+
+ Example: a C for statement generally looks like this
+
+ 10 0x100 - for the init/test part of a for stmt.
+ 20 0x200
+ 30 0x300
+ 10 0x400 - for the increment part of a for stmt.
+
+ */
+
+struct linetable
+{
+ int nitems;
+
+ /* Actually NITEMS elements. If you don't like this use of the
+ `struct hack', you can shove it up your ANSI (seriously, if the
+ committee tells us how to do it, we can probably go along). */
+ struct linetable_entry item[1];
+};
+
+/* All the information on one source file. */
+
+struct source
+{
+ char *name; /* Name of file */
+ struct linetable contents;
+};
+
+/* How to relocate the symbols from each section in a symbol file.
+ Each struct contains an array of offsets.
+ The ordering and meaning of the offsets is file-type-dependent;
+ typically it is indexed by section numbers or symbol types or
+ something like that.
+
+ To give us flexibility in changing the internal representation
+ of these offsets, the ANOFFSET macro must be used to insert and
+ extract offset values in the struct. */
+
+struct section_offsets
+ {
+ CORE_ADDR offsets[1]; /* As many as needed. */
+ };
+
+#define ANOFFSET(secoff, whichone) (secoff->offsets[whichone])
+
+/* Each source file or header is represented by a struct symtab.
+ These objects are chained through the `next' field. */
+
+struct symtab
+ {
+
+ /* Chain of all existing symtabs. */
+
+ struct symtab *next;
+
+ /* List of all symbol scope blocks for this symtab. May be shared
+ between different symtabs (and normally is for all the symtabs
+ in a given compilation unit). */
+
+ struct blockvector *blockvector;
+
+ /* Table mapping core addresses to line numbers for this file.
+ Can be NULL if none. Never shared between different symtabs. */
+
+ struct linetable *linetable;
+
+ /* Section in objfile->section_offsets for the blockvector and
+ the linetable. */
+
+ int block_line_section;
+
+ /* If several symtabs share a blockvector, exactly one of them
+ should be designed the primary, so that the blockvector
+ is relocated exactly once by objfile_relocate. */
+
+ int primary;
+
+ /* Name of this source file. */
+
+ char *filename;
+
+ /* Directory in which it was compiled, or NULL if we don't know. */
+
+ char *dirname;
+
+ /* This component says how to free the data we point to:
+ free_contents => do a tree walk and free each object.
+ free_nothing => do nothing; some other symtab will free
+ the data this one uses.
+ free_linetable => free just the linetable. FIXME: Is this redundant
+ with the primary field? */
+
+ enum free_code
+ {
+ free_nothing, free_contents, free_linetable
+ }
+ free_code;
+
+ /* Pointer to one block of storage to be freed, if nonzero. */
+ /* This is IN ADDITION to the action indicated by free_code. */
+
+ char *free_ptr;
+
+ /* Total number of lines found in source file. */
+
+ int nlines;
+
+ /* line_charpos[N] is the position of the (N-1)th line of the
+ source file. "position" means something we can lseek() to; it
+ is not guaranteed to be useful any other way. */
+
+ int *line_charpos;
+
+ /* Language of this source file. */
+
+ enum language language;
+
+ /* String of version information. May be zero. */
+
+ char *version;
+
+ /* Full name of file as found by searching the source path.
+ NULL if not yet known. */
+
+ char *fullname;
+
+ /* Object file from which this symbol information was read. */
+
+ struct objfile *objfile;
+
+ /* Anything extra for this symtab. This is for target machines
+ with special debugging info of some sort (which cannot just
+ be represented in a normal symtab). */
+
+#if defined (EXTRA_SYMTAB_INFO)
+ EXTRA_SYMTAB_INFO
+#endif
+
+ };
+
+#define BLOCKVECTOR(symtab) (symtab)->blockvector
+#define LINETABLE(symtab) (symtab)->linetable
+
+
+/* Each source file that has not been fully read in is represented by
+ a partial_symtab. This contains the information on where in the
+ executable the debugging symbols for a specific file are, and a
+ list of names of global symbols which are located in this file.
+ They are all chained on partial symtab lists.
+
+ Even after the source file has been read into a symtab, the
+ partial_symtab remains around. They are allocated on an obstack,
+ psymbol_obstack. FIXME, this is bad for dynamic linking or VxWorks-
+ style execution of a bunch of .o's. */
+
+struct partial_symtab
+{
+
+ /* Chain of all existing partial symtabs. */
+
+ struct partial_symtab *next;
+
+ /* Name of the source file which this partial_symtab defines */
+
+ char *filename;
+
+ /* Information about the object file from which symbols should be read. */
+
+ struct objfile *objfile;
+
+ /* Set of relocation offsets to apply to each section. */
+
+ struct section_offsets *section_offsets;
+
+ /* Range of text addresses covered by this file; texthigh is the
+ beginning of the next section. */
+
+ CORE_ADDR textlow;
+ CORE_ADDR texthigh;
+
+ /* Array of pointers to all of the partial_symtab's which this one
+ depends on. Since this array can only be set to previous or
+ the current (?) psymtab, this dependency tree is guaranteed not
+ to have any loops. "depends on" means that symbols must be read
+ for the dependencies before being read for this psymtab; this is
+ for type references in stabs, where if foo.c includes foo.h, declarations
+ in foo.h may use type numbers defined in foo.c. For other debugging
+ formats there may be no need to use dependencies. */
+
+ struct partial_symtab **dependencies;
+
+ int number_of_dependencies;
+
+ /* Global symbol list. This list will be sorted after readin to
+ improve access. Binary search will be the usual method of
+ finding a symbol within it. globals_offset is an integer offset
+ within global_psymbols[]. */
+
+ int globals_offset;
+ int n_global_syms;
+
+ /* Static symbol list. This list will *not* be sorted after readin;
+ to find a symbol in it, exhaustive search must be used. This is
+ reasonable because searches through this list will eventually
+ lead to either the read in of a files symbols for real (assumed
+ to take a *lot* of time; check) or an error (and we don't care
+ how long errors take). This is an offset and size within
+ static_psymbols[]. */
+
+ int statics_offset;
+ int n_static_syms;
+
+ /* Pointer to symtab eventually allocated for this source file, 0 if
+ !readin or if we haven't looked for the symtab after it was readin. */
+
+ struct symtab *symtab;
+
+ /* Pointer to function which will read in the symtab corresponding to
+ this psymtab. */
+
+ void (*read_symtab) PARAMS ((struct partial_symtab *));
+
+ /* Information that lets read_symtab() locate the part of the symbol table
+ that this psymtab corresponds to. This information is private to the
+ format-dependent symbol reading routines. For further detail examine
+ the various symbol reading modules. Should really be (void *) but is
+ (char *) as with other such gdb variables. (FIXME) */
+
+ char *read_symtab_private;
+
+ /* Non-zero if the symtab corresponding to this psymtab has been readin */
+
+ unsigned char readin;
+};
+
+/* A fast way to get from a psymtab to its symtab (after the first time). */
+#define PSYMTAB_TO_SYMTAB(pst) \
+ ((pst) -> symtab != NULL ? (pst) -> symtab : psymtab_to_symtab (pst))
+
+
+/* The virtual function table is now an array of structures which have the
+ form { int16 offset, delta; void *pfn; }.
+
+ In normal virtual function tables, OFFSET is unused.
+ DELTA is the amount which is added to the apparent object's base
+ address in order to point to the actual object to which the
+ virtual function should be applied.
+ PFN is a pointer to the virtual function.
+
+ Note that this macro is g++ specific (FIXME). */
+
+#define VTBL_FNADDR_OFFSET 2
+
+/* Macro that yields non-zero value iff NAME is the prefix for C++ operator
+ names. If you leave out the parenthesis here you will lose!
+ Currently 'o' 'p' CPLUS_MARKER is used for both the symbol in the
+ symbol-file and the names in gdb's symbol table.
+ Note that this macro is g++ specific (FIXME). */
+
+#define OPNAME_PREFIX_P(NAME) \
+ ((NAME)[0] == 'o' && (NAME)[1] == 'p' && (NAME)[2] == CPLUS_MARKER)
+
+/* Macro that yields non-zero value iff NAME is the prefix for C++ vtbl
+ names. Note that this macro is g++ specific (FIXME).
+ '_vt$' is the old cfront-style vtables; '_VT$' is the new
+ style, using thunks (where '$' is really CPLUS_MARKER). */
+
+#define VTBL_PREFIX_P(NAME) \
+ ((NAME)[3] == CPLUS_MARKER && (NAME)[0] == '_' \
+ && (((NAME)[1] == 'V' && (NAME)[2] == 'T') \
+ || ((NAME)[1] == 'v' && (NAME)[2] == 't')))
+
+/* Macro that yields non-zero value iff NAME is the prefix for C++ destructor
+ names. Note that this macro is g++ specific (FIXME). */
+
+#define DESTRUCTOR_PREFIX_P(NAME) \
+ ((NAME)[0] == '_' && (NAME)[1] == CPLUS_MARKER && (NAME)[2] == '_')
+
+
+/* External variables and functions for the objects described above. */
+
+/* This symtab variable specifies the current file for printing source lines */
+
+extern struct symtab *current_source_symtab;
+
+/* This is the next line to print for listing source lines. */
+
+extern int current_source_line;
+
+/* See the comment in symfile.c about how current_objfile is used. */
+
+extern struct objfile *current_objfile;
+
+/* From utils.c. */
+extern int demangle;
+extern int asm_demangle;
+
+extern struct symtab *
+lookup_symtab PARAMS ((char *));
+
+extern struct symbol *
+lookup_symbol PARAMS ((const char *, const struct block *,
+ const enum namespace, int *, struct symtab **));
+
+extern struct symbol *
+lookup_block_symbol PARAMS ((const struct block *, const char *,
+ const enum namespace));
+
+extern struct type *
+lookup_struct PARAMS ((char *, struct block *));
+
+extern struct type *
+lookup_union PARAMS ((char *, struct block *));
+
+extern struct type *
+lookup_enum PARAMS ((char *, struct block *));
+
+extern struct symbol *
+block_function PARAMS ((struct block *));
+
+extern struct symbol *
+find_pc_function PARAMS ((CORE_ADDR));
+
+extern int find_pc_partial_function
+ PARAMS ((CORE_ADDR, char **, CORE_ADDR *, CORE_ADDR *));
+
+extern void
+clear_pc_function_cache PARAMS ((void));
+
+extern struct partial_symtab *
+lookup_partial_symtab PARAMS ((char *));
+
+extern struct partial_symtab *
+find_pc_psymtab PARAMS ((CORE_ADDR));
+
+extern struct symtab *
+find_pc_symtab PARAMS ((CORE_ADDR));
+
+extern struct partial_symbol *
+find_pc_psymbol PARAMS ((struct partial_symtab *, CORE_ADDR));
+
+extern int
+find_pc_line_pc_range PARAMS ((CORE_ADDR, CORE_ADDR *, CORE_ADDR *));
+
+extern int
+contained_in PARAMS ((struct block *, struct block *));
+
+extern void
+reread_symbols PARAMS ((void));
+
+/* Macro for name of symbol to indicate a file compiled with gcc. */
+#ifndef GCC_COMPILED_FLAG_SYMBOL
+#define GCC_COMPILED_FLAG_SYMBOL "gcc_compiled."
+#endif
+
+/* Macro for name of symbol to indicate a file compiled with gcc2. */
+#ifndef GCC2_COMPILED_FLAG_SYMBOL
+#define GCC2_COMPILED_FLAG_SYMBOL "gcc2_compiled."
+#endif
+
+/* Functions for dealing with the minimal symbol table, really a misc
+ address<->symbol mapping for things we don't have debug symbols for. */
+
+extern void prim_record_minimal_symbol PARAMS ((const char *, CORE_ADDR,
+ enum minimal_symbol_type,
+ struct objfile *));
+
+extern void prim_record_minimal_symbol_and_info
+ PARAMS ((const char *, CORE_ADDR,
+ enum minimal_symbol_type,
+ char *info, int section,
+ struct objfile *));
+
+extern struct minimal_symbol *
+lookup_minimal_symbol PARAMS ((const char *, struct objfile *));
+
+extern struct minimal_symbol *
+lookup_minimal_symbol_by_pc PARAMS ((CORE_ADDR));
+
+extern struct minimal_symbol *
+lookup_solib_trampoline_symbol_by_pc PARAMS ((CORE_ADDR));
+
+extern CORE_ADDR
+find_solib_trampoline_target PARAMS ((CORE_ADDR));
+
+extern void
+init_minimal_symbol_collection PARAMS ((void));
+
+extern void
+discard_minimal_symbols PARAMS ((int));
+
+extern void
+install_minimal_symbols PARAMS ((struct objfile *));
+
+struct symtab_and_line
+{
+ struct symtab *symtab;
+
+ /* Line number. Line numbers start at 1 and proceed through symtab->nlines.
+ 0 is never a valid line number; it is used to indicate that line number
+ information is not available. */
+ int line;
+
+ CORE_ADDR pc;
+ CORE_ADDR end;
+};
+
+struct symtabs_and_lines
+{
+ struct symtab_and_line *sals;
+ int nelts;
+};
+
+/* Given a pc value, return line number it is in. Second arg nonzero means
+ if pc is on the boundary use the previous statement's line number. */
+
+extern struct symtab_and_line
+find_pc_line PARAMS ((CORE_ADDR, int));
+
+/* Given an address, return the nearest symbol at or below it in memory.
+ Optionally return the symtab it's from through 2nd arg, and the
+ address in inferior memory of the symbol through 3rd arg. */
+
+extern struct symbol *
+find_addr_symbol PARAMS ((CORE_ADDR, struct symtab **, CORE_ADDR *));
+
+/* Given a symtab and line number, return the pc there. */
+
+extern CORE_ADDR
+find_line_pc PARAMS ((struct symtab *, int));
+
+extern int
+find_line_pc_range PARAMS ((struct symtab_and_line,
+ CORE_ADDR *, CORE_ADDR *));
+
+extern void
+resolve_sal_pc PARAMS ((struct symtab_and_line *));
+
+/* Given a string, return the line specified by it. For commands like "list"
+ and "breakpoint". */
+
+extern struct symtabs_and_lines
+decode_line_spec PARAMS ((char *, int));
+
+extern struct symtabs_and_lines
+decode_line_spec_1 PARAMS ((char *, int));
+
+extern struct symtabs_and_lines
+decode_line_1 PARAMS ((char **, int, struct symtab *, int, char ***));
+
+/* Symmisc.c */
+
+#if MAINTENANCE_CMDS
+
+void
+maintenance_print_symbols PARAMS ((char *, int));
+
+void
+maintenance_print_psymbols PARAMS ((char *, int));
+
+void
+maintenance_print_msymbols PARAMS ((char *, int));
+
+void
+maintenance_print_objfiles PARAMS ((char *, int));
+
+void
+maintenance_check_symtabs PARAMS ((char *, int));
+
+#endif
+
+extern void
+free_symtab PARAMS ((struct symtab *));
+
+/* Symbol-reading stuff in symfile.c and solib.c. */
+
+extern struct symtab *
+psymtab_to_symtab PARAMS ((struct partial_symtab *));
+
+extern void
+clear_solib PARAMS ((void));
+
+extern struct objfile *
+symbol_file_add PARAMS ((char *, int, CORE_ADDR, int, int, int));
+
+/* source.c */
+
+extern int
+identify_source_line PARAMS ((struct symtab *, int, int, CORE_ADDR));
+
+extern void
+print_source_lines PARAMS ((struct symtab *, int, int, int));
+
+extern void
+forget_cached_source_info PARAMS ((void));
+
+extern void
+select_source_symtab PARAMS ((struct symtab *));
+
+extern char **make_symbol_completion_list PARAMS ((char *, char *));
+
+/* symtab.c */
+
+extern struct partial_symtab *
+find_main_psymtab PARAMS ((void));
+
+/* blockframe.c */
+
+extern struct blockvector *
+blockvector_for_pc PARAMS ((CORE_ADDR, int *));
+
+/* symfile.c */
+
+extern void
+clear_symtab_users PARAMS ((void));
+
+extern enum language
+deduce_language_from_filename PARAMS ((char *));
+
+#endif /* !defined(SYMTAB_H) */
diff --git a/gnu/usr.bin/gdb/gdb/target.c b/gnu/usr.bin/gdb/gdb/target.c
new file mode 100644
index 0000000..e3c6b34
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/target.c
@@ -0,0 +1,1316 @@
+/* Select target systems and architectures at runtime for GDB.
+ Copyright 1990, 1992, 1993, 1994 Free Software Foundation, Inc.
+ Contributed by Cygnus Support.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "defs.h"
+#include <errno.h>
+#include <ctype.h>
+#include "target.h"
+#include "gdbcmd.h"
+#include "symtab.h"
+#include "inferior.h"
+#include "bfd.h"
+#include "symfile.h"
+#include "objfiles.h"
+#include "wait.h"
+#include <signal.h>
+
+extern int errno;
+
+static void
+target_info PARAMS ((char *, int));
+
+static void
+cleanup_target PARAMS ((struct target_ops *));
+
+static void
+maybe_kill_then_create_inferior PARAMS ((char *, char *, char **));
+
+static void
+maybe_kill_then_attach PARAMS ((char *, int));
+
+static void
+kill_or_be_killed PARAMS ((int));
+
+static void
+default_terminal_info PARAMS ((char *, int));
+
+static int
+nosymbol PARAMS ((char *, CORE_ADDR *));
+
+static void
+tcomplain PARAMS ((void));
+
+static int
+nomemory PARAMS ((CORE_ADDR, char *, int, int));
+
+static int
+return_zero PARAMS ((void));
+
+static void
+ignore PARAMS ((void));
+
+static void
+target_command PARAMS ((char *, int));
+
+static struct target_ops *
+find_default_run_target PARAMS ((char *));
+
+/* Pointer to array of target architecture structures; the size of the
+ array; the current index into the array; the allocated size of the
+ array. */
+struct target_ops **target_structs;
+unsigned target_struct_size;
+unsigned target_struct_index;
+unsigned target_struct_allocsize;
+#define DEFAULT_ALLOCSIZE 10
+
+/* The initial current target, so that there is always a semi-valid
+ current target. */
+
+struct target_ops dummy_target = {"None", "None", "",
+ 0, 0, /* open, close */
+ find_default_attach, 0, /* attach, detach */
+ 0, 0, /* resume, wait */
+ 0, 0, 0, /* registers */
+ 0, 0, /* memory */
+ 0, 0, /* bkpts */
+ 0, 0, 0, 0, 0, /* terminal */
+ 0, 0, /* kill, load */
+ 0, /* lookup_symbol */
+ find_default_create_inferior, /* create_inferior */
+ 0, /* mourn_inferior */
+ 0, /* can_run */
+ 0, /* notice_signals */
+ dummy_stratum, 0, /* stratum, next */
+ 0, 0, 0, 0, 0, /* all mem, mem, stack, regs, exec */
+ 0, 0, /* section pointers */
+ OPS_MAGIC,
+};
+
+/* The target structure we are currently using to talk to a process
+ or file or whatever "inferior" we have. */
+
+struct target_ops *current_target;
+
+/* The stack of target structures that have been pushed. */
+
+struct target_ops **current_target_stack;
+
+/* Command list for target. */
+
+static struct cmd_list_element *targetlist = NULL;
+
+/* Nonzero if we are debugging an attached outside process
+ rather than an inferior. */
+
+int attach_flag;
+
+/* The user just typed 'target' without the name of a target. */
+
+/* ARGSUSED */
+static void
+target_command (arg, from_tty)
+ char *arg;
+ int from_tty;
+{
+ fputs_filtered ("Argument required (target name). Try `help target'\n",
+ gdb_stdout);
+}
+
+/* Add a possible target architecture to the list. */
+
+void
+add_target (t)
+ struct target_ops *t;
+{
+ if (t->to_magic != OPS_MAGIC)
+ {
+ fprintf_unfiltered(gdb_stderr, "Magic number of %s target struct wrong\n",
+ t->to_shortname);
+ abort();
+ }
+
+ if (!target_structs)
+ {
+ target_struct_allocsize = DEFAULT_ALLOCSIZE;
+ target_structs = (struct target_ops **) xmalloc
+ (target_struct_allocsize * sizeof (*target_structs));
+ }
+ if (target_struct_size >= target_struct_allocsize)
+ {
+ target_struct_allocsize *= 2;
+ target_structs = (struct target_ops **)
+ xrealloc ((char *) target_structs,
+ target_struct_allocsize * sizeof (*target_structs));
+ }
+ target_structs[target_struct_size++] = t;
+ cleanup_target (t);
+
+ if (targetlist == NULL)
+ add_prefix_cmd ("target", class_run, target_command,
+ "Connect to a target machine or process.\n\
+The first argument is the type or protocol of the target machine.\n\
+Remaining arguments are interpreted by the target protocol. For more\n\
+information on the arguments for a particular protocol, type\n\
+`help target ' followed by the protocol name.",
+ &targetlist, "target ", 0, &cmdlist);
+ add_cmd (t->to_shortname, no_class, t->to_open, t->to_doc, &targetlist);
+}
+
+/* Stub functions */
+
+static void
+ignore ()
+{
+}
+
+/* ARGSUSED */
+static int
+nomemory (memaddr, myaddr, len, write)
+ CORE_ADDR memaddr;
+ char *myaddr;
+ int len;
+ int write;
+{
+ errno = EIO; /* Can't read/write this location */
+ return 0; /* No bytes handled */
+}
+
+static void
+tcomplain ()
+{
+ error ("You can't do that when your target is `%s'",
+ current_target->to_shortname);
+}
+
+void
+noprocess ()
+{
+ error ("You can't do that without a process to debug");
+}
+
+/* ARGSUSED */
+static int
+nosymbol (name, addrp)
+ char *name;
+ CORE_ADDR *addrp;
+{
+ return 1; /* Symbol does not exist in target env */
+}
+
+/* ARGSUSED */
+static void
+default_terminal_info (args, from_tty)
+ char *args;
+ int from_tty;
+{
+ printf_unfiltered("No saved terminal information.\n");
+}
+
+#if 0
+/* With strata, this function is no longer needed. FIXME. */
+/* This is the default target_create_inferior function. It looks up
+ the stack for some target that cares to create inferiors, then
+ calls it -- or complains if not found. */
+
+static void
+upstack_create_inferior (exec, args, env)
+ char *exec;
+ char *args;
+ char **env;
+{
+ struct target_ops *t;
+
+ for (t = current_target;
+ t;
+ t = t->to_next)
+ {
+ if (t->to_create_inferior != upstack_create_inferior)
+ {
+ t->to_create_inferior (exec, args, env);
+ return;
+ }
+
+ }
+ tcomplain();
+}
+#endif
+
+/* This is the default target_create_inferior and target_attach function.
+ If the current target is executing, it asks whether to kill it off.
+ If this function returns without calling error(), it has killed off
+ the target, and the operation should be attempted. */
+
+static void
+kill_or_be_killed (from_tty)
+ int from_tty;
+{
+ if (target_has_execution)
+ {
+ printf_unfiltered ("You are already running a program:\n");
+ target_files_info ();
+ if (query ("Kill it? ")) {
+ target_kill ();
+ if (target_has_execution)
+ error ("Killing the program did not help.");
+ return;
+ } else {
+ error ("Program not killed.");
+ }
+ }
+ tcomplain();
+}
+
+static void
+maybe_kill_then_attach (args, from_tty)
+ char *args;
+ int from_tty;
+{
+ kill_or_be_killed (from_tty);
+ target_attach (args, from_tty);
+}
+
+static void
+maybe_kill_then_create_inferior (exec, args, env)
+ char *exec;
+ char *args;
+ char **env;
+{
+ kill_or_be_killed (0);
+ target_create_inferior (exec, args, env);
+}
+
+/* Clean up a target struct so it no longer has any zero pointers in it.
+ We default entries, at least to stubs that print error messages. */
+
+static void
+cleanup_target (t)
+ struct target_ops *t;
+{
+
+ /* Check magic number. If wrong, it probably means someone changed
+ the struct definition, but not all the places that initialize one. */
+ if (t->to_magic != OPS_MAGIC)
+ {
+ fprintf_unfiltered(gdb_stderr, "Magic number of %s target struct wrong\n",
+ t->to_shortname);
+ abort();
+ }
+
+#define de_fault(field, value) \
+ if (!t->field) t->field = value
+
+ /* FIELD DEFAULT VALUE */
+
+ de_fault (to_open, (void (*)())tcomplain);
+ de_fault (to_close, (void (*)())ignore);
+ de_fault (to_attach, maybe_kill_then_attach);
+ de_fault (to_detach, (void (*)())ignore);
+ de_fault (to_resume, (void (*)())noprocess);
+ de_fault (to_wait, (int (*)())noprocess);
+ de_fault (to_fetch_registers, (void (*)())ignore);
+ de_fault (to_store_registers, (void (*)())noprocess);
+ de_fault (to_prepare_to_store, (void (*)())noprocess);
+ de_fault (to_xfer_memory, (int (*)())nomemory);
+ de_fault (to_files_info, (void (*)())ignore);
+ de_fault (to_insert_breakpoint, memory_insert_breakpoint);
+ de_fault (to_remove_breakpoint, memory_remove_breakpoint);
+ de_fault (to_terminal_init, ignore);
+ de_fault (to_terminal_inferior, ignore);
+ de_fault (to_terminal_ours_for_output,ignore);
+ de_fault (to_terminal_ours, ignore);
+ de_fault (to_terminal_info, default_terminal_info);
+ de_fault (to_kill, (void (*)())noprocess);
+ de_fault (to_load, (void (*)())tcomplain);
+ de_fault (to_lookup_symbol, nosymbol);
+ de_fault (to_create_inferior, maybe_kill_then_create_inferior);
+ de_fault (to_mourn_inferior, (void (*)())noprocess);
+ de_fault (to_can_run, return_zero);
+ de_fault (to_notice_signals, (void (*)())ignore);
+ de_fault (to_next, 0);
+ de_fault (to_has_all_memory, 0);
+ de_fault (to_has_memory, 0);
+ de_fault (to_has_stack, 0);
+ de_fault (to_has_registers, 0);
+ de_fault (to_has_execution, 0);
+
+#undef de_fault
+}
+
+/* Push a new target type into the stack of the existing target accessors,
+ possibly superseding some of the existing accessors.
+
+ Result is zero if the pushed target ended up on top of the stack,
+ nonzero if at least one target is on top of it.
+
+ Rather than allow an empty stack, we always have the dummy target at
+ the bottom stratum, so we can call the function vectors without
+ checking them. */
+
+int
+push_target (t)
+ struct target_ops *t;
+{
+ struct target_ops *st, *prev;
+
+ for (prev = 0, st = current_target;
+ st;
+ prev = st, st = st->to_next) {
+ if ((int)(t->to_stratum) >= (int)(st->to_stratum))
+ break;
+ }
+
+ while (t->to_stratum == st->to_stratum) {
+ /* There's already something on this stratum. Close it off. */
+ (st->to_close) (0);
+ if (prev)
+ prev->to_next = st->to_next; /* Unchain old target_ops */
+ else
+ current_target = st->to_next; /* Unchain first on list */
+ st = st->to_next;
+ }
+
+ /* We have removed all targets in our stratum, now add ourself. */
+ t->to_next = st;
+ if (prev)
+ prev->to_next = t;
+ else
+ current_target = t;
+
+ cleanup_target (current_target);
+ return prev != 0;
+}
+
+/* Remove a target_ops vector from the stack, wherever it may be.
+ Return how many times it was removed (0 or 1 unless bug). */
+
+int
+unpush_target (t)
+ struct target_ops *t;
+{
+ struct target_ops *u, *v;
+ int result = 0;
+
+ for (u = current_target, v = 0;
+ u;
+ v = u, u = u->to_next)
+ if (u == t)
+ {
+ if (v == 0)
+ pop_target(); /* unchain top copy */
+ else {
+ (t->to_close)(0); /* Let it clean up */
+ v->to_next = t->to_next; /* unchain middle copy */
+ }
+ result++;
+ }
+ return result;
+}
+
+void
+pop_target ()
+{
+ (current_target->to_close)(0); /* Let it clean up */
+ current_target = current_target->to_next;
+#if 0
+ /* This will dump core if ever called--push_target expects current_target
+ to be non-NULL. But I don't think it's needed; I don't see how the
+ dummy_target could ever be removed from the stack. */
+ if (!current_target) /* At bottom, push dummy. */
+ push_target (&dummy_target);
+#endif
+}
+
+#undef MIN
+#define MIN(A, B) (((A) <= (B)) ? (A) : (B))
+
+/* target_read_string -- read a null terminated string, up to LEN bytes,
+ from MEMADDR in target. Set *ERRNOP to the errno code, or 0 if successful.
+ Set *STRING to a pointer to malloc'd memory containing the data; the caller
+ is responsible for freeing it. Return the number of bytes successfully
+ read. */
+
+int
+target_read_string (memaddr, string, len, errnop)
+ CORE_ADDR memaddr;
+ char **string;
+ int len;
+ int *errnop;
+{
+ int tlen, origlen, offset, i;
+ char buf[4];
+ int errcode = 0;
+ char *buffer;
+ int buffer_allocated;
+ char *bufptr;
+ unsigned int nbytes_read = 0;
+
+ /* Small for testing. */
+ buffer_allocated = 4;
+ buffer = xmalloc (buffer_allocated);
+ bufptr = buffer;
+
+ origlen = len;
+
+ while (len > 0)
+ {
+ tlen = MIN (len, 4 - (memaddr & 3));
+ offset = memaddr & 3;
+
+ errcode = target_xfer_memory (memaddr & ~3, buf, 4, 0);
+ if (errcode != 0)
+ goto done;
+
+ if (bufptr - buffer + tlen > buffer_allocated)
+ {
+ unsigned int bytes;
+ bytes = bufptr - buffer;
+ buffer_allocated *= 2;
+ buffer = xrealloc (buffer, buffer_allocated);
+ bufptr = buffer + bytes;
+ }
+
+ for (i = 0; i < tlen; i++)
+ {
+ *bufptr++ = buf[i + offset];
+ if (buf[i + offset] == '\000')
+ {
+ nbytes_read += i + 1;
+ goto done;
+ }
+ }
+
+ memaddr += tlen;
+ len -= tlen;
+ nbytes_read += tlen;
+ }
+ done:
+ if (errnop != NULL)
+ *errnop = errcode;
+ if (string != NULL)
+ *string = buffer;
+ return nbytes_read;
+}
+
+/* Read LEN bytes of target memory at address MEMADDR, placing the results in
+ GDB's memory at MYADDR. Returns either 0 for success or an errno value
+ if any error occurs.
+
+ If an error occurs, no guarantee is made about the contents of the data at
+ MYADDR. In particular, the caller should not depend upon partial reads
+ filling the buffer with good data. There is no way for the caller to know
+ how much good data might have been transfered anyway. Callers that can
+ deal with partial reads should call target_read_memory_partial. */
+
+int
+target_read_memory (memaddr, myaddr, len)
+ CORE_ADDR memaddr;
+ char *myaddr;
+ int len;
+{
+ return target_xfer_memory (memaddr, myaddr, len, 0);
+}
+
+/* Read LEN bytes of target memory at address MEMADDR, placing the results
+ in GDB's memory at MYADDR. Returns a count of the bytes actually read,
+ and optionally an errno value in the location pointed to by ERRNOPTR
+ if ERRNOPTR is non-null. */
+
+int
+target_read_memory_partial (memaddr, myaddr, len, errnoptr)
+ CORE_ADDR memaddr;
+ char *myaddr;
+ int len;
+ int *errnoptr;
+{
+ int nread; /* Number of bytes actually read. */
+ int errcode; /* Error from last read. */
+
+ /* First try a complete read. */
+ errcode = target_xfer_memory (memaddr, myaddr, len, 0);
+ if (errcode == 0)
+ {
+ /* Got it all. */
+ nread = len;
+ }
+ else
+ {
+ /* Loop, reading one byte at a time until we get as much as we can. */
+ for (errcode = 0, nread = 0; len > 0 && errcode == 0; nread++, len--)
+ {
+ errcode = target_xfer_memory (memaddr++, myaddr++, 1, 0);
+ }
+ /* If an error, the last read was unsuccessful, so adjust count. */
+ if (errcode != 0)
+ {
+ nread--;
+ }
+ }
+ if (errnoptr != NULL)
+ {
+ *errnoptr = errcode;
+ }
+ return (nread);
+}
+
+int
+target_write_memory (memaddr, myaddr, len)
+ CORE_ADDR memaddr;
+ char *myaddr;
+ int len;
+{
+ return target_xfer_memory (memaddr, myaddr, len, 1);
+}
+
+/* Move memory to or from the targets. Iterate until all of it has
+ been moved, if necessary. The top target gets priority; anything
+ it doesn't want, is offered to the next one down, etc. Note the
+ business with curlen: if an early target says "no, but I have a
+ boundary overlapping this xfer" then we shorten what we offer to
+ the subsequent targets so the early guy will get a chance at the
+ tail before the subsequent ones do.
+
+ Result is 0 or errno value. */
+
+int
+target_xfer_memory (memaddr, myaddr, len, write)
+ CORE_ADDR memaddr;
+ char *myaddr;
+ int len;
+ int write;
+{
+ int curlen;
+ int res;
+ struct target_ops *t;
+
+ /* to_xfer_memory is not guaranteed to set errno, even when it returns
+ 0. */
+ errno = 0;
+
+ /* The quick case is that the top target does it all. */
+ res = current_target->to_xfer_memory
+ (memaddr, myaddr, len, write, current_target);
+ if (res == len)
+ return 0;
+
+ if (res > 0)
+ goto bump;
+ /* If res <= 0 then we call it again in the loop. Ah well. */
+
+ for (; len > 0;)
+ {
+ curlen = len; /* Want to do it all */
+ for (t = current_target;
+ t;
+ t = t->to_has_all_memory? 0: t->to_next)
+ {
+ res = t->to_xfer_memory(memaddr, myaddr, curlen, write, t);
+ if (res > 0) break; /* Handled all or part of xfer */
+ if (res == 0) continue; /* Handled none */
+ curlen = -res; /* Could handle once we get past res bytes */
+ }
+ if (res <= 0)
+ {
+ /* If this address is for nonexistent memory,
+ read zeros if reading, or do nothing if writing. Return error. */
+ if (!write)
+ memset (myaddr, 0, len);
+ if (errno == 0)
+ return EIO;
+ else
+ return errno;
+ }
+bump:
+ memaddr += res;
+ myaddr += res;
+ len -= res;
+ }
+ return 0; /* We managed to cover it all somehow. */
+}
+
+
+/* ARGSUSED */
+static void
+target_info (args, from_tty)
+ char *args;
+ int from_tty;
+{
+ struct target_ops *t;
+ int has_all_mem = 0;
+
+ if (symfile_objfile != NULL)
+ printf_unfiltered ("Symbols from \"%s\".\n", symfile_objfile->name);
+
+#ifdef FILES_INFO_HOOK
+ if (FILES_INFO_HOOK ())
+ return;
+#endif
+
+ for (t = current_target;
+ t;
+ t = t->to_next)
+ {
+ if ((int)(t->to_stratum) <= (int)dummy_stratum)
+ continue;
+ if (has_all_mem)
+ printf_unfiltered("\tWhile running this, GDB does not access memory from...\n");
+ printf_unfiltered("%s:\n", t->to_longname);
+ (t->to_files_info)(t);
+ has_all_mem = t->to_has_all_memory;
+ }
+}
+
+/* This is to be called by the open routine before it does
+ anything. */
+
+void
+target_preopen (from_tty)
+ int from_tty;
+{
+ dont_repeat();
+
+ if (target_has_execution)
+ {
+ if (query ("A program is being debugged already. Kill it? "))
+ target_kill ();
+ else
+ error ("Program not killed.");
+ }
+
+ /* Calling target_kill may remove the target from the stack. But if
+ it doesn't (which seems like a win for UDI), remove it now. */
+
+ if (target_has_execution)
+ pop_target ();
+}
+
+/* Detach a target after doing deferred register stores. */
+
+void
+target_detach (args, from_tty)
+ char *args;
+ int from_tty;
+{
+ /* Handle any optimized stores to the inferior. */
+#ifdef DO_DEFERRED_STORES
+ DO_DEFERRED_STORES;
+#endif
+ (current_target->to_detach) (args, from_tty);
+}
+
+void
+target_link (modname, t_reloc)
+ char *modname;
+ CORE_ADDR *t_reloc;
+{
+ if (STREQ(current_target->to_shortname, "rombug"))
+ {
+ (current_target->to_lookup_symbol) (modname, t_reloc);
+ if (*t_reloc == 0)
+ error("Unable to link to %s and get relocation in rombug", modname);
+ }
+ else
+ *t_reloc = (CORE_ADDR)-1;
+}
+
+/* Look through the list of possible targets for a target that can
+ execute a run or attach command without any other data. This is
+ used to locate the default process stratum.
+
+ Result is always valid (error() is called for errors). */
+
+static struct target_ops *
+find_default_run_target (do_mesg)
+ char *do_mesg;
+{
+ struct target_ops **t;
+ struct target_ops *runable = NULL;
+ int count;
+
+ count = 0;
+
+ for (t = target_structs; t < target_structs + target_struct_size;
+ ++t)
+ {
+ if (target_can_run(*t))
+ {
+ runable = *t;
+ ++count;
+ }
+ }
+
+ if (count != 1)
+ error ("Don't know how to %s. Try \"help target\".", do_mesg);
+
+ return runable;
+}
+
+void
+find_default_attach (args, from_tty)
+ char *args;
+ int from_tty;
+{
+ struct target_ops *t;
+
+ t = find_default_run_target("attach");
+ (t->to_attach) (args, from_tty);
+ return;
+}
+
+void
+find_default_create_inferior (exec_file, allargs, env)
+ char *exec_file;
+ char *allargs;
+ char **env;
+{
+ struct target_ops *t;
+
+ t = find_default_run_target("run");
+ (t->to_create_inferior) (exec_file, allargs, env);
+ return;
+}
+
+static int
+return_zero ()
+{
+ return 0;
+}
+
+struct target_ops *
+find_core_target ()
+{
+ struct target_ops **t;
+ struct target_ops *runable = NULL;
+ int count;
+
+ count = 0;
+
+ for (t = target_structs; t < target_structs + target_struct_size;
+ ++t)
+ {
+#ifdef KERNEL_DEBUG
+ if ((*t)->to_stratum == (kernel_debugging ? kcore_stratum : core_stratum))
+#else
+ if ((*t)->to_stratum == core_stratum)
+#endif
+ {
+ runable = *t;
+ ++count;
+ }
+ }
+
+ return(count == 1 ? runable : NULL);
+}
+
+/* The inferior process has died. Long live the inferior! */
+
+void
+generic_mourn_inferior ()
+{
+ extern int show_breakpoint_hit_counts;
+
+ inferior_pid = 0;
+ attach_flag = 0;
+ breakpoint_init_inferior ();
+ registers_changed ();
+
+#ifdef CLEAR_DEFERRED_STORES
+ /* Delete any pending stores to the inferior... */
+ CLEAR_DEFERRED_STORES;
+#endif
+
+ reopen_exec_file ();
+ reinit_frame_cache ();
+
+ /* It is confusing to the user for ignore counts to stick around
+ from previous runs of the inferior. So clear them. */
+ /* However, it is more confusing for the ignore counts to disappear when
+ using hit counts. So don't clear them if we're counting hits. */
+ if (!show_breakpoint_hit_counts)
+ breakpoint_clear_ignore_counts ();
+}
+
+/* This table must match in order and size the signals in enum target_signal
+ in target.h. */
+static struct {
+ char *name;
+ char *string;
+ } signals [] =
+{
+ {"0", "Signal 0"},
+ {"SIGHUP", "Hangup"},
+ {"SIGINT", "Interrupt"},
+ {"SIGQUIT", "Quit"},
+ {"SIGILL", "Illegal instruction"},
+ {"SIGTRAP", "Trace/breakpoint trap"},
+ {"SIGABRT", "Aborted"},
+ {"SIGEMT", "Emulation trap"},
+ {"SIGFPE", "Arithmetic exception"},
+ {"SIGKILL", "Killed"},
+ {"SIGBUS", "Bus error"},
+ {"SIGSEGV", "Segmentation fault"},
+ {"SIGSYS", "Bad system call"},
+ {"SIGPIPE", "Broken pipe"},
+ {"SIGALRM", "Alarm clock"},
+ {"SIGTERM", "Terminated"},
+ {"SIGURG", "Urgent I/O condition"},
+ {"SIGSTOP", "Stopped (signal)"},
+ {"SIGTSTP", "Stopped (user)"},
+ {"SIGCONT", "Continued"},
+ {"SIGCHLD", "Child status changed"},
+ {"SIGTTIN", "Stopped (tty input)"},
+ {"SIGTTOU", "Stopped (tty output)"},
+ {"SIGIO", "I/O possible"},
+ {"SIGXCPU", "CPU time limit exceeded"},
+ {"SIGXFSZ", "File size limit exceeded"},
+ {"SIGVTALRM", "Virtual timer expired"},
+ {"SIGPROF", "Profiling timer expired"},
+ {"SIGWINCH", "Window size changed"},
+ {"SIGLOST", "Resource lost"},
+ {"SIGUSR1", "User defined signal 1"},
+ {"SIGUSR2", "User defined signal 2"},
+ {"SIGPWR", "Power fail/restart"},
+ {"SIGPOLL", "Pollable event occurred"},
+ {"SIGWIND", "SIGWIND"},
+ {"SIGPHONE", "SIGPHONE"},
+ {"SIGWAITING", "Process's LWPs are blocked"},
+ {"SIGLWP", "Signal LWP"},
+ {"SIGDANGER", "Swap space dangerously low"},
+ {"SIGGRANT", "Monitor mode granted"},
+ {"SIGRETRACT", "Need to relinguish monitor mode"},
+ {"SIGMSG", "Monitor mode data available"},
+ {"SIGSOUND", "Sound completed"},
+ {"SIGSAK", "Secure attention"},
+ {NULL, "Unknown signal"},
+ {NULL, "Internal error: printing TARGET_SIGNAL_DEFAULT"},
+
+ /* Last entry, used to check whether the table is the right size. */
+ {NULL, "TARGET_SIGNAL_MAGIC"}
+};
+
+/* Return the string for a signal. */
+char *
+target_signal_to_string (sig)
+ enum target_signal sig;
+{
+ return signals[sig].string;
+}
+
+/* Return the name for a signal. */
+char *
+target_signal_to_name (sig)
+ enum target_signal sig;
+{
+ if (sig == TARGET_SIGNAL_UNKNOWN)
+ /* I think the code which prints this will always print it along with
+ the string, so no need to be verbose. */
+ return "?";
+ return signals[sig].name;
+}
+
+/* Given a name, return its signal. */
+enum target_signal
+target_signal_from_name (name)
+ char *name;
+{
+ enum target_signal sig;
+
+ /* It's possible we also should allow "SIGCLD" as well as "SIGCHLD"
+ for TARGET_SIGNAL_SIGCHLD. SIGIOT, on the other hand, is more
+ questionable; seems like by now people should call it SIGABRT
+ instead. */
+
+ /* This ugly cast brought to you by the native VAX compiler. */
+ for (sig = TARGET_SIGNAL_HUP;
+ signals[sig].name != NULL;
+ sig = (enum target_signal)((int)sig + 1))
+ if (STREQ (name, signals[sig].name))
+ return sig;
+ return TARGET_SIGNAL_UNKNOWN;
+}
+
+/* The following functions are to help certain targets deal
+ with the signal/waitstatus stuff. They could just as well be in
+ a file called native-utils.c or unixwaitstatus-utils.c or whatever. */
+
+/* Convert host signal to our signals. */
+enum target_signal
+target_signal_from_host (hostsig)
+ int hostsig;
+{
+ /* A switch statement would make sense but would require special kludges
+ to deal with the cases where more than one signal has the same number. */
+
+ if (hostsig == 0) return TARGET_SIGNAL_0;
+
+#if defined (SIGHUP)
+ if (hostsig == SIGHUP) return TARGET_SIGNAL_HUP;
+#endif
+#if defined (SIGINT)
+ if (hostsig == SIGINT) return TARGET_SIGNAL_INT;
+#endif
+#if defined (SIGQUIT)
+ if (hostsig == SIGQUIT) return TARGET_SIGNAL_QUIT;
+#endif
+#if defined (SIGILL)
+ if (hostsig == SIGILL) return TARGET_SIGNAL_ILL;
+#endif
+#if defined (SIGTRAP)
+ if (hostsig == SIGTRAP) return TARGET_SIGNAL_TRAP;
+#endif
+#if defined (SIGABRT)
+ if (hostsig == SIGABRT) return TARGET_SIGNAL_ABRT;
+#endif
+#if defined (SIGEMT)
+ if (hostsig == SIGEMT) return TARGET_SIGNAL_EMT;
+#endif
+#if defined (SIGFPE)
+ if (hostsig == SIGFPE) return TARGET_SIGNAL_FPE;
+#endif
+#if defined (SIGKILL)
+ if (hostsig == SIGKILL) return TARGET_SIGNAL_KILL;
+#endif
+#if defined (SIGBUS)
+ if (hostsig == SIGBUS) return TARGET_SIGNAL_BUS;
+#endif
+#if defined (SIGSEGV)
+ if (hostsig == SIGSEGV) return TARGET_SIGNAL_SEGV;
+#endif
+#if defined (SIGSYS)
+ if (hostsig == SIGSYS) return TARGET_SIGNAL_SYS;
+#endif
+#if defined (SIGPIPE)
+ if (hostsig == SIGPIPE) return TARGET_SIGNAL_PIPE;
+#endif
+#if defined (SIGALRM)
+ if (hostsig == SIGALRM) return TARGET_SIGNAL_ALRM;
+#endif
+#if defined (SIGTERM)
+ if (hostsig == SIGTERM) return TARGET_SIGNAL_TERM;
+#endif
+#if defined (SIGUSR1)
+ if (hostsig == SIGUSR1) return TARGET_SIGNAL_USR1;
+#endif
+#if defined (SIGUSR2)
+ if (hostsig == SIGUSR2) return TARGET_SIGNAL_USR2;
+#endif
+#if defined (SIGCLD)
+ if (hostsig == SIGCLD) return TARGET_SIGNAL_CHLD;
+#endif
+#if defined (SIGCHLD)
+ if (hostsig == SIGCHLD) return TARGET_SIGNAL_CHLD;
+#endif
+#if defined (SIGPWR)
+ if (hostsig == SIGPWR) return TARGET_SIGNAL_PWR;
+#endif
+#if defined (SIGWINCH)
+ if (hostsig == SIGWINCH) return TARGET_SIGNAL_WINCH;
+#endif
+#if defined (SIGURG)
+ if (hostsig == SIGURG) return TARGET_SIGNAL_URG;
+#endif
+#if defined (SIGIO)
+ if (hostsig == SIGIO) return TARGET_SIGNAL_IO;
+#endif
+#if defined (SIGPOLL)
+ if (hostsig == SIGPOLL) return TARGET_SIGNAL_POLL;
+#endif
+#if defined (SIGSTOP)
+ if (hostsig == SIGSTOP) return TARGET_SIGNAL_STOP;
+#endif
+#if defined (SIGTSTP)
+ if (hostsig == SIGTSTP) return TARGET_SIGNAL_TSTP;
+#endif
+#if defined (SIGCONT)
+ if (hostsig == SIGCONT) return TARGET_SIGNAL_CONT;
+#endif
+#if defined (SIGTTIN)
+ if (hostsig == SIGTTIN) return TARGET_SIGNAL_TTIN;
+#endif
+#if defined (SIGTTOU)
+ if (hostsig == SIGTTOU) return TARGET_SIGNAL_TTOU;
+#endif
+#if defined (SIGVTALRM)
+ if (hostsig == SIGVTALRM) return TARGET_SIGNAL_VTALRM;
+#endif
+#if defined (SIGPROF)
+ if (hostsig == SIGPROF) return TARGET_SIGNAL_PROF;
+#endif
+#if defined (SIGXCPU)
+ if (hostsig == SIGXCPU) return TARGET_SIGNAL_XCPU;
+#endif
+#if defined (SIGXFSZ)
+ if (hostsig == SIGXFSZ) return TARGET_SIGNAL_XFSZ;
+#endif
+#if defined (SIGWIND)
+ if (hostsig == SIGWIND) return TARGET_SIGNAL_WIND;
+#endif
+#if defined (SIGPHONE)
+ if (hostsig == SIGPHONE) return TARGET_SIGNAL_PHONE;
+#endif
+#if defined (SIGLOST)
+ if (hostsig == SIGLOST) return TARGET_SIGNAL_LOST;
+#endif
+#if defined (SIGWAITING)
+ if (hostsig == SIGWAITING) return TARGET_SIGNAL_WAITING;
+#endif
+#if defined (SIGLWP)
+ if (hostsig == SIGLWP) return TARGET_SIGNAL_LWP;
+#endif
+#if defined (SIGDANGER)
+ if (hostsig == SIGDANGER) return TARGET_SIGNAL_DANGER;
+#endif
+#if defined (SIGGRANT)
+ if (hostsig == SIGGRANT) return TARGET_SIGNAL_GRANT;
+#endif
+#if defined (SIGRETRACT)
+ if (hostsig == SIGRETRACT) return TARGET_SIGNAL_RETRACT;
+#endif
+#if defined (SIGMSG)
+ if (hostsig == SIGMSG) return TARGET_SIGNAL_MSG;
+#endif
+#if defined (SIGSOUND)
+ if (hostsig == SIGSOUND) return TARGET_SIGNAL_SOUND;
+#endif
+#if defined (SIGSAK)
+ if (hostsig == SIGSAK) return TARGET_SIGNAL_SAK;
+#endif
+ return TARGET_SIGNAL_UNKNOWN;
+}
+
+int
+target_signal_to_host (oursig)
+ enum target_signal oursig;
+{
+ switch (oursig)
+ {
+ case TARGET_SIGNAL_0: return 0;
+
+#if defined (SIGHUP)
+ case TARGET_SIGNAL_HUP: return SIGHUP;
+#endif
+#if defined (SIGINT)
+ case TARGET_SIGNAL_INT: return SIGINT;
+#endif
+#if defined (SIGQUIT)
+ case TARGET_SIGNAL_QUIT: return SIGQUIT;
+#endif
+#if defined (SIGILL)
+ case TARGET_SIGNAL_ILL: return SIGILL;
+#endif
+#if defined (SIGTRAP)
+ case TARGET_SIGNAL_TRAP: return SIGTRAP;
+#endif
+#if defined (SIGABRT)
+ case TARGET_SIGNAL_ABRT: return SIGABRT;
+#endif
+#if defined (SIGEMT)
+ case TARGET_SIGNAL_EMT: return SIGEMT;
+#endif
+#if defined (SIGFPE)
+ case TARGET_SIGNAL_FPE: return SIGFPE;
+#endif
+#if defined (SIGKILL)
+ case TARGET_SIGNAL_KILL: return SIGKILL;
+#endif
+#if defined (SIGBUS)
+ case TARGET_SIGNAL_BUS: return SIGBUS;
+#endif
+#if defined (SIGSEGV)
+ case TARGET_SIGNAL_SEGV: return SIGSEGV;
+#endif
+#if defined (SIGSYS)
+ case TARGET_SIGNAL_SYS: return SIGSYS;
+#endif
+#if defined (SIGPIPE)
+ case TARGET_SIGNAL_PIPE: return SIGPIPE;
+#endif
+#if defined (SIGALRM)
+ case TARGET_SIGNAL_ALRM: return SIGALRM;
+#endif
+#if defined (SIGTERM)
+ case TARGET_SIGNAL_TERM: return SIGTERM;
+#endif
+#if defined (SIGUSR1)
+ case TARGET_SIGNAL_USR1: return SIGUSR1;
+#endif
+#if defined (SIGUSR2)
+ case TARGET_SIGNAL_USR2: return SIGUSR2;
+#endif
+#if defined (SIGCHLD) || defined (SIGCLD)
+ case TARGET_SIGNAL_CHLD:
+#if defined (SIGCHLD)
+ return SIGCHLD;
+#else
+ return SIGCLD;
+#endif
+#endif /* SIGCLD or SIGCHLD */
+#if defined (SIGPWR)
+ case TARGET_SIGNAL_PWR: return SIGPWR;
+#endif
+#if defined (SIGWINCH)
+ case TARGET_SIGNAL_WINCH: return SIGWINCH;
+#endif
+#if defined (SIGURG)
+ case TARGET_SIGNAL_URG: return SIGURG;
+#endif
+#if defined (SIGIO)
+ case TARGET_SIGNAL_IO: return SIGIO;
+#endif
+#if defined (SIGPOLL)
+ case TARGET_SIGNAL_POLL: return SIGPOLL;
+#endif
+#if defined (SIGSTOP)
+ case TARGET_SIGNAL_STOP: return SIGSTOP;
+#endif
+#if defined (SIGTSTP)
+ case TARGET_SIGNAL_TSTP: return SIGTSTP;
+#endif
+#if defined (SIGCONT)
+ case TARGET_SIGNAL_CONT: return SIGCONT;
+#endif
+#if defined (SIGTTIN)
+ case TARGET_SIGNAL_TTIN: return SIGTTIN;
+#endif
+#if defined (SIGTTOU)
+ case TARGET_SIGNAL_TTOU: return SIGTTOU;
+#endif
+#if defined (SIGVTALRM)
+ case TARGET_SIGNAL_VTALRM: return SIGVTALRM;
+#endif
+#if defined (SIGPROF)
+ case TARGET_SIGNAL_PROF: return SIGPROF;
+#endif
+#if defined (SIGXCPU)
+ case TARGET_SIGNAL_XCPU: return SIGXCPU;
+#endif
+#if defined (SIGXFSZ)
+ case TARGET_SIGNAL_XFSZ: return SIGXFSZ;
+#endif
+#if defined (SIGWIND)
+ case TARGET_SIGNAL_WIND: return SIGWIND;
+#endif
+#if defined (SIGPHONE)
+ case TARGET_SIGNAL_PHONE: return SIGPHONE;
+#endif
+#if defined (SIGLOST)
+ case TARGET_SIGNAL_LOST: return SIGLOST;
+#endif
+#if defined (SIGWAITING)
+ case TARGET_SIGNAL_WAITING: return SIGWAITING;
+#endif
+#if defined (SIGLWP)
+ case TARGET_SIGNAL_LWP: return SIGLWP;
+#endif
+#if defined (SIGDANGER)
+ case TARGET_SIGNAL_DANGER: return SIGDANGER;
+#endif
+#if defined (SIGGRANT)
+ case TARGET_SIGNAL_GRANT: return SIGGRANT;
+#endif
+#if defined (SIGRETRACT)
+ case TARGET_SIGNAL_RETRACT: return SIGRETRACT;
+#endif
+#if defined (SIGMSG)
+ case TARGET_SIGNAL_MSG: return SIGMSG;
+#endif
+#if defined (SIGSOUND)
+ case TARGET_SIGNAL_SOUND: return SIGSOUND;
+#endif
+#if defined (SIGSAK)
+ case TARGET_SIGNAL_SAK: return SIGSAK;
+#endif
+ default:
+ /* The user might be trying to do "signal SIGSAK" where this system
+ doesn't have SIGSAK. */
+ warning ("Signal %s does not exist on this system.\n",
+ target_signal_to_name (oursig));
+ return 0;
+ }
+}
+
+/* Helper function for child_wait and the Lynx derivatives of child_wait.
+ HOSTSTATUS is the waitstatus from wait() or the equivalent; store our
+ translation of that in OURSTATUS. */
+void
+store_waitstatus (ourstatus, hoststatus)
+ struct target_waitstatus *ourstatus;
+ int hoststatus;
+{
+#ifdef CHILD_SPECIAL_WAITSTATUS
+ /* CHILD_SPECIAL_WAITSTATUS should return nonzero and set *OURSTATUS
+ if it wants to deal with hoststatus. */
+ if (CHILD_SPECIAL_WAITSTATUS (ourstatus, hoststatus))
+ return;
+#endif
+
+ if (WIFEXITED (hoststatus))
+ {
+ ourstatus->kind = TARGET_WAITKIND_EXITED;
+ ourstatus->value.integer = WEXITSTATUS (hoststatus);
+ }
+ else if (!WIFSTOPPED (hoststatus))
+ {
+ ourstatus->kind = TARGET_WAITKIND_SIGNALLED;
+ ourstatus->value.sig = target_signal_from_host (WTERMSIG (hoststatus));
+ }
+ else
+ {
+ ourstatus->kind = TARGET_WAITKIND_STOPPED;
+ ourstatus->value.sig = target_signal_from_host (WSTOPSIG (hoststatus));
+ }
+}
+
+
+/* Returns zero to leave the inferior alone, one to interrupt it. */
+int (*target_activity_function) PARAMS ((void));
+int target_activity_fd;
+
+/* Convert a normal process ID to a string. Returns the string in a static
+ buffer. */
+
+char *
+normal_pid_to_str (pid)
+ int pid;
+{
+ static char buf[30];
+
+ sprintf (buf, "process %d", pid);
+
+ return buf;
+}
+
+static char targ_desc[] =
+ "Names of targets and files being debugged.\n\
+Shows the entire stack of targets currently in use (including the exec-file,\n\
+core-file, and process, if any), as well as the symbol file name.";
+
+void
+_initialize_targets ()
+{
+ current_target = &dummy_target;
+ cleanup_target (current_target);
+
+ add_info ("target", target_info, targ_desc);
+ add_info ("files", target_info, targ_desc);
+
+ if (!STREQ (signals[TARGET_SIGNAL_LAST].string, "TARGET_SIGNAL_MAGIC"))
+ abort ();
+}
diff --git a/gnu/usr.bin/gdb/gdb/target.h b/gnu/usr.bin/gdb/gdb/target.h
new file mode 100644
index 0000000..750be84
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/target.h
@@ -0,0 +1,649 @@
+/* Interface between GDB and target environments, including files and processes
+ Copyright 1990, 1991, 1992, 1993, 1994 Free Software Foundation, Inc.
+ Contributed by Cygnus Support. Written by John Gilmore.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#if !defined (TARGET_H)
+#define TARGET_H
+
+/* This include file defines the interface between the main part
+ of the debugger, and the part which is target-specific, or
+ specific to the communications interface between us and the
+ target.
+
+ A TARGET is an interface between the debugger and a particular
+ kind of file or process. Targets can be STACKED in STRATA,
+ so that more than one target can potentially respond to a request.
+ In particular, memory accesses will walk down the stack of targets
+ until they find a target that is interested in handling that particular
+ address. STRATA are artificial boundaries on the stack, within
+ which particular kinds of targets live. Strata exist so that
+ people don't get confused by pushing e.g. a process target and then
+ a file target, and wondering why they can't see the current values
+ of variables any more (the file target is handling them and they
+ never get to the process target). So when you push a file target,
+ it goes into the file stratum, which is always below the process
+ stratum. */
+
+#include "bfd.h"
+
+enum strata {
+ dummy_stratum, /* The lowest of the low */
+ file_stratum, /* Executable files, etc */
+ core_stratum, /* Core dump files */
+#ifdef KERNEL_DEBUG
+ kcore_stratum, /* Kernel core files */
+#endif
+ process_stratum /* Executing processes */
+};
+
+/* Stuff for target_wait. */
+
+/* Generally, what has the program done? */
+enum target_waitkind {
+ /* The program has exited. The exit status is in value.integer. */
+ TARGET_WAITKIND_EXITED,
+
+ /* The program has stopped with a signal. Which signal is in value.sig. */
+ TARGET_WAITKIND_STOPPED,
+
+ /* The program has terminated with a signal. Which signal is in
+ value.sig. */
+ TARGET_WAITKIND_SIGNALLED,
+
+ /* The program is letting us know that it dynamically loaded something
+ (e.g. it called load(2) on AIX). */
+ TARGET_WAITKIND_LOADED,
+
+ /* Nothing happened, but we stopped anyway. This perhaps should be handled
+ within target_wait, but I'm not sure target_wait should be resuming the
+ inferior. */
+ TARGET_WAITKIND_SPURIOUS
+ };
+
+/* The numbering of these signals is chosen to match traditional unix
+ signals (insofar as various unices use the same numbers, anyway).
+ It is also the numbering of the GDB remote protocol. Other remote
+ protocols, if they use a different numbering, should make sure to
+ translate appropriately. */
+
+/* This is based strongly on Unix/POSIX signals for several reasons:
+ (1) This set of signals represents a widely-accepted attempt to
+ represent events of this sort in a portable fashion, (2) we want a
+ signal to make it from wait to child_wait to the user intact, (3) many
+ remote protocols use a similar encoding. However, it is
+ recognized that this set of signals has limitations (such as not
+ distinguishing between various kinds of SIGSEGV, or not
+ distinguishing hitting a breakpoint from finishing a single step).
+ So in the future we may get around this either by adding additional
+ signals for breakpoint, single-step, etc., or by adding signal
+ codes; the latter seems more in the spirit of what BSD, System V,
+ etc. are doing to address these issues. */
+
+/* For an explanation of what each signal means, see
+ target_signal_to_string. */
+
+enum target_signal {
+ /* Used some places (e.g. stop_signal) to record the concept that
+ there is no signal. */
+ TARGET_SIGNAL_0 = 0,
+ TARGET_SIGNAL_FIRST = 0,
+ TARGET_SIGNAL_HUP = 1,
+ TARGET_SIGNAL_INT = 2,
+ TARGET_SIGNAL_QUIT = 3,
+ TARGET_SIGNAL_ILL = 4,
+ TARGET_SIGNAL_TRAP = 5,
+ TARGET_SIGNAL_ABRT = 6,
+ TARGET_SIGNAL_EMT = 7,
+ TARGET_SIGNAL_FPE = 8,
+ TARGET_SIGNAL_KILL = 9,
+ TARGET_SIGNAL_BUS = 10,
+ TARGET_SIGNAL_SEGV = 11,
+ TARGET_SIGNAL_SYS = 12,
+ TARGET_SIGNAL_PIPE = 13,
+ TARGET_SIGNAL_ALRM = 14,
+ TARGET_SIGNAL_TERM = 15,
+ TARGET_SIGNAL_URG = 16,
+ TARGET_SIGNAL_STOP = 17,
+ TARGET_SIGNAL_TSTP = 18,
+ TARGET_SIGNAL_CONT = 19,
+ TARGET_SIGNAL_CHLD = 20,
+ TARGET_SIGNAL_TTIN = 21,
+ TARGET_SIGNAL_TTOU = 22,
+ TARGET_SIGNAL_IO = 23,
+ TARGET_SIGNAL_XCPU = 24,
+ TARGET_SIGNAL_XFSZ = 25,
+ TARGET_SIGNAL_VTALRM = 26,
+ TARGET_SIGNAL_PROF = 27,
+ TARGET_SIGNAL_WINCH = 28,
+ TARGET_SIGNAL_LOST = 29,
+ TARGET_SIGNAL_USR1 = 30,
+ TARGET_SIGNAL_USR2 = 31,
+ TARGET_SIGNAL_PWR = 32,
+ /* Similar to SIGIO. Perhaps they should have the same number. */
+ TARGET_SIGNAL_POLL = 33,
+ TARGET_SIGNAL_WIND = 34,
+ TARGET_SIGNAL_PHONE = 35,
+ TARGET_SIGNAL_WAITING = 36,
+ TARGET_SIGNAL_LWP = 37,
+ TARGET_SIGNAL_DANGER = 38,
+ TARGET_SIGNAL_GRANT = 39,
+ TARGET_SIGNAL_RETRACT = 40,
+ TARGET_SIGNAL_MSG = 41,
+ TARGET_SIGNAL_SOUND = 42,
+ TARGET_SIGNAL_SAK = 43,
+
+ /* Some signal we don't know about. */
+ TARGET_SIGNAL_UNKNOWN,
+
+ /* Use whatever signal we use when one is not specifically specified
+ (for passing to proceed and so on). */
+ TARGET_SIGNAL_DEFAULT,
+
+ /* Last and unused enum value, for sizing arrays, etc. */
+ TARGET_SIGNAL_LAST
+};
+
+struct target_waitstatus {
+ enum target_waitkind kind;
+
+ /* Exit status or signal number. */
+ union {
+ int integer;
+ enum target_signal sig;
+ } value;
+};
+
+/* Return the string for a signal. */
+extern char *target_signal_to_string PARAMS ((enum target_signal));
+
+/* Return the name (SIGHUP, etc.) for a signal. */
+extern char *target_signal_to_name PARAMS ((enum target_signal));
+
+/* Given a name (SIGHUP, etc.), return its signal. */
+enum target_signal target_signal_from_name PARAMS ((char *));
+
+/* If certain kinds of activity happen, target_wait should perform
+ callbacks. */
+/* Right now we just call (*TARGET_ACTIVITY_FUNCTION) if I/O is possible
+ on TARGET_ACTIVITY_FD. */
+extern int target_activity_fd;
+/* Returns zero to leave the inferior alone, one to interrupt it. */
+extern int (*target_activity_function) PARAMS ((void));
+
+struct target_ops
+{
+ char *to_shortname; /* Name this target type */
+ char *to_longname; /* Name for printing */
+ char *to_doc; /* Documentation. Does not include trailing
+ newline, and starts with a one-line descrip-
+ tion (probably similar to to_longname). */
+ void (*to_open) PARAMS ((char *, int));
+ void (*to_close) PARAMS ((int));
+ void (*to_attach) PARAMS ((char *, int));
+ void (*to_detach) PARAMS ((char *, int));
+ void (*to_resume) PARAMS ((int, int, enum target_signal));
+ int (*to_wait) PARAMS ((int, struct target_waitstatus *));
+ void (*to_fetch_registers) PARAMS ((int));
+ void (*to_store_registers) PARAMS ((int));
+ void (*to_prepare_to_store) PARAMS ((void));
+
+ /* Transfer LEN bytes of memory between GDB address MYADDR and
+ target address MEMADDR. If WRITE, transfer them to the target, else
+ transfer them from the target. TARGET is the target from which we
+ get this function.
+
+ Return value, N, is one of the following:
+
+ 0 means that we can't handle this. If errno has been set, it is the
+ error which prevented us from doing it (FIXME: What about bfd_error?).
+
+ positive (call it N) means that we have transferred N bytes
+ starting at MEMADDR. We might be able to handle more bytes
+ beyond this length, but no promises.
+
+ negative (call its absolute value N) means that we cannot
+ transfer right at MEMADDR, but we could transfer at least
+ something at MEMADDR + N. */
+
+ int (*to_xfer_memory) PARAMS ((CORE_ADDR memaddr, char *myaddr,
+ int len, int write,
+ struct target_ops * target));
+
+#if 0
+ /* Enable this after 4.12. */
+
+ /* Search target memory. Start at STARTADDR and take LEN bytes of
+ target memory, and them with MASK, and compare to DATA. If they
+ match, set *ADDR_FOUND to the address we found it at, store the data
+ we found at LEN bytes starting at DATA_FOUND, and return. If
+ not, add INCREMENT to the search address and keep trying until
+ the search address is outside of the range [LORANGE,HIRANGE).
+
+ If we don't find anything, set *ADDR_FOUND to (CORE_ADDR)0 and return. */
+ void (*to_search) PARAMS ((int len, char *data, char *mask,
+ CORE_ADDR startaddr, int increment,
+ CORE_ADDR lorange, CORE_ADDR hirange,
+ CORE_ADDR *addr_found, char *data_found));
+
+#define target_search(len, data, mask, startaddr, increment, lorange, hirange, addr_found, data_found) \
+ (*current_target->to_search) (len, data, mask, startaddr, increment, \
+ lorange, hirange, addr_found, data_found)
+#endif /* 0 */
+
+ void (*to_files_info) PARAMS ((struct target_ops *));
+ int (*to_insert_breakpoint) PARAMS ((CORE_ADDR, char *));
+ int (*to_remove_breakpoint) PARAMS ((CORE_ADDR, char *));
+ void (*to_terminal_init) PARAMS ((void));
+ void (*to_terminal_inferior) PARAMS ((void));
+ void (*to_terminal_ours_for_output) PARAMS ((void));
+ void (*to_terminal_ours) PARAMS ((void));
+ void (*to_terminal_info) PARAMS ((char *, int));
+ void (*to_kill) PARAMS ((void));
+ void (*to_load) PARAMS ((char *, int));
+ int (*to_lookup_symbol) PARAMS ((char *, CORE_ADDR *));
+ void (*to_create_inferior) PARAMS ((char *, char *, char **));
+ void (*to_mourn_inferior) PARAMS ((void));
+ int (*to_can_run) PARAMS ((void));
+ void (*to_notice_signals) PARAMS ((int pid));
+ enum strata to_stratum;
+ struct target_ops
+ *to_next;
+ int to_has_all_memory;
+ int to_has_memory;
+ int to_has_stack;
+ int to_has_registers;
+ int to_has_execution;
+ struct section_table
+ *to_sections;
+ struct section_table
+ *to_sections_end;
+ int to_magic;
+ /* Need sub-structure for target machine related rather than comm related? */
+};
+
+/* Magic number for checking ops size. If a struct doesn't end with this
+ number, somebody changed the declaration but didn't change all the
+ places that initialize one. */
+
+#define OPS_MAGIC 3840
+
+/* The ops structure for our "current" target process. This should
+ never be NULL. If there is no target, it points to the dummy_target. */
+
+extern struct target_ops *current_target;
+
+/* Define easy words for doing these operations on our current target. */
+
+#define target_shortname (current_target->to_shortname)
+#define target_longname (current_target->to_longname)
+
+/* The open routine takes the rest of the parameters from the command,
+ and (if successful) pushes a new target onto the stack.
+ Targets should supply this routine, if only to provide an error message. */
+#define target_open(name, from_tty) \
+ (*current_target->to_open) (name, from_tty)
+
+/* Does whatever cleanup is required for a target that we are no longer
+ going to be calling. Argument says whether we are quitting gdb and
+ should not get hung in case of errors, or whether we want a clean
+ termination even if it takes a while. This routine is automatically
+ always called just before a routine is popped off the target stack.
+ Closing file descriptors and freeing memory are typical things it should
+ do. */
+
+#define target_close(quitting) \
+ (*current_target->to_close) (quitting)
+
+/* Attaches to a process on the target side. Arguments are as passed
+ to the `attach' command by the user. This routine can be called
+ when the target is not on the target-stack, if the target_can_run
+ routine returns 1; in that case, it must push itself onto the stack.
+ Upon exit, the target should be ready for normal operations, and
+ should be ready to deliver the status of the process immediately
+ (without waiting) to an upcoming target_wait call. */
+
+#define target_attach(args, from_tty) \
+ (*current_target->to_attach) (args, from_tty)
+
+/* Takes a program previously attached to and detaches it.
+ The program may resume execution (some targets do, some don't) and will
+ no longer stop on signals, etc. We better not have left any breakpoints
+ in the program or it'll die when it hits one. ARGS is arguments
+ typed by the user (e.g. a signal to send the process). FROM_TTY
+ says whether to be verbose or not. */
+
+extern void
+target_detach PARAMS ((char *, int));
+
+/* Resume execution of the target process PID. STEP says whether to
+ single-step or to run free; SIGGNAL is the signal to be given to
+ the target, or TARGET_SIGNAL_0 for no signal. The caller may not
+ pass TARGET_SIGNAL_DEFAULT. */
+
+#define target_resume(pid, step, siggnal) \
+ (*current_target->to_resume) (pid, step, siggnal)
+
+/* Wait for process pid to do something. Pid = -1 to wait for any pid
+ to do something. Return pid of child, or -1 in case of error;
+ store status through argument pointer STATUS. Note that it is
+ *not* OK to return_to_top_level out of target_wait without popping
+ the debugging target from the stack; GDB isn't prepared to get back
+ to the prompt with a debugging target but without the frame cache,
+ stop_pc, etc., set up. */
+
+#define target_wait(pid, status) \
+ (*current_target->to_wait) (pid, status)
+
+/* Fetch register REGNO, or all regs if regno == -1. No result. */
+
+#define target_fetch_registers(regno) \
+ (*current_target->to_fetch_registers) (regno)
+
+/* Store at least register REGNO, or all regs if REGNO == -1.
+ It can store as many registers as it wants to, so target_prepare_to_store
+ must have been previously called. Calls error() if there are problems. */
+
+#define target_store_registers(regs) \
+ (*current_target->to_store_registers) (regs)
+
+/* Get ready to modify the registers array. On machines which store
+ individual registers, this doesn't need to do anything. On machines
+ which store all the registers in one fell swoop, this makes sure
+ that REGISTERS contains all the registers from the program being
+ debugged. */
+
+#define target_prepare_to_store() \
+ (*current_target->to_prepare_to_store) ()
+
+extern int target_read_string PARAMS ((CORE_ADDR, char **, int, int *));
+
+extern int
+target_read_memory PARAMS ((CORE_ADDR, char *, int));
+
+extern int
+target_read_memory_partial PARAMS ((CORE_ADDR, char *, int, int *));
+
+extern int
+target_write_memory PARAMS ((CORE_ADDR, char *, int));
+
+extern int
+xfer_memory PARAMS ((CORE_ADDR, char *, int, int, struct target_ops *));
+
+extern int
+child_xfer_memory PARAMS ((CORE_ADDR, char *, int, int, struct target_ops *));
+
+/* Transfer LEN bytes between target address MEMADDR and GDB address MYADDR.
+ Returns 0 for success, errno code for failure (which includes partial
+ transfers--if you want a more useful response to partial transfers, try
+ target_read_memory_partial). */
+
+extern int target_xfer_memory PARAMS ((CORE_ADDR memaddr, char *myaddr,
+ int len, int write));
+
+/* From exec.c */
+
+extern void
+print_section_info PARAMS ((struct target_ops *, bfd *));
+
+/* Print a line about the current target. */
+
+#define target_files_info() \
+ (*current_target->to_files_info) (current_target)
+
+/* Insert a breakpoint at address ADDR in the target machine.
+ SAVE is a pointer to memory allocated for saving the
+ target contents. It is guaranteed by the caller to be long enough
+ to save "sizeof BREAKPOINT" bytes. Result is 0 for success, or
+ an errno value. */
+
+#define target_insert_breakpoint(addr, save) \
+ (*current_target->to_insert_breakpoint) (addr, save)
+
+/* Remove a breakpoint at address ADDR in the target machine.
+ SAVE is a pointer to the same save area
+ that was previously passed to target_insert_breakpoint.
+ Result is 0 for success, or an errno value. */
+
+#define target_remove_breakpoint(addr, save) \
+ (*current_target->to_remove_breakpoint) (addr, save)
+
+/* Initialize the terminal settings we record for the inferior,
+ before we actually run the inferior. */
+
+#define target_terminal_init() \
+ (*current_target->to_terminal_init) ()
+
+/* Put the inferior's terminal settings into effect.
+ This is preparation for starting or resuming the inferior. */
+
+#define target_terminal_inferior() \
+ (*current_target->to_terminal_inferior) ()
+
+/* Put some of our terminal settings into effect,
+ enough to get proper results from our output,
+ but do not change into or out of RAW mode
+ so that no input is discarded.
+
+ After doing this, either terminal_ours or terminal_inferior
+ should be called to get back to a normal state of affairs. */
+
+#define target_terminal_ours_for_output() \
+ (*current_target->to_terminal_ours_for_output) ()
+
+/* Put our terminal settings into effect.
+ First record the inferior's terminal settings
+ so they can be restored properly later. */
+
+#define target_terminal_ours() \
+ (*current_target->to_terminal_ours) ()
+
+/* Print useful information about our terminal status, if such a thing
+ exists. */
+
+#define target_terminal_info(arg, from_tty) \
+ (*current_target->to_terminal_info) (arg, from_tty)
+
+/* Kill the inferior process. Make it go away. */
+
+#define target_kill() \
+ (*current_target->to_kill) ()
+
+/* Load an executable file into the target process. This is expected to
+ not only bring new code into the target process, but also to update
+ GDB's symbol tables to match. */
+
+#define target_load(arg, from_tty) \
+ (*current_target->to_load) (arg, from_tty)
+
+/* Look up a symbol in the target's symbol table. NAME is the symbol
+ name. ADDRP is a CORE_ADDR * pointing to where the value of the symbol
+ should be returned. The result is 0 if successful, nonzero if the
+ symbol does not exist in the target environment. This function should
+ not call error() if communication with the target is interrupted, since
+ it is called from symbol reading, but should return nonzero, possibly
+ doing a complain(). */
+
+#define target_lookup_symbol(name, addrp) \
+ (*current_target->to_lookup_symbol) (name, addrp)
+
+/* Start an inferior process and set inferior_pid to its pid.
+ EXEC_FILE is the file to run.
+ ALLARGS is a string containing the arguments to the program.
+ ENV is the environment vector to pass. Errors reported with error().
+ On VxWorks and various standalone systems, we ignore exec_file. */
+
+#define target_create_inferior(exec_file, args, env) \
+ (*current_target->to_create_inferior) (exec_file, args, env)
+
+/* The inferior process has died. Do what is right. */
+
+#define target_mourn_inferior() \
+ (*current_target->to_mourn_inferior) ()
+
+/* Does target have enough data to do a run or attach command? */
+
+#define target_can_run(t) \
+ ((t)->to_can_run) ()
+
+/* post process changes to signal handling in the inferior. */
+
+#define target_notice_signals(pid) \
+ (*current_target->to_notice_signals) (pid)
+
+/* Pointer to next target in the chain, e.g. a core file and an exec file. */
+
+#define target_next \
+ (current_target->to_next)
+
+/* Does the target include all of memory, or only part of it? This
+ determines whether we look up the target chain for other parts of
+ memory if this target can't satisfy a request. */
+
+#define target_has_all_memory \
+ (current_target->to_has_all_memory)
+
+/* Does the target include memory? (Dummy targets don't.) */
+
+#define target_has_memory \
+ (current_target->to_has_memory)
+
+/* Does the target have a stack? (Exec files don't, VxWorks doesn't, until
+ we start a process.) */
+
+#define target_has_stack \
+ (current_target->to_has_stack)
+
+/* Does the target have registers? (Exec files don't.) */
+
+#define target_has_registers \
+ (current_target->to_has_registers)
+
+/* Does the target have execution? Can we make it jump (through
+ hoops), or pop its stack a few times? FIXME: If this is to work that
+ way, it needs to check whether an inferior actually exists.
+ remote-udi.c and probably other targets can be the current target
+ when the inferior doesn't actually exist at the moment. Right now
+ this just tells us whether this target is *capable* of execution. */
+
+#define target_has_execution \
+ (current_target->to_has_execution)
+
+extern void target_link PARAMS ((char *, CORE_ADDR *));
+
+/* Converts a process id to a string. Usually, the string just contains
+ `process xyz', but on some systems it may contain
+ `process xyz thread abc'. */
+
+#ifndef target_pid_to_str
+#define target_pid_to_str(PID) \
+ normal_pid_to_str (PID)
+extern char *normal_pid_to_str PARAMS ((int pid));
+#endif
+
+/* Routines for maintenance of the target structures...
+
+ add_target: Add a target to the list of all possible targets.
+
+ push_target: Make this target the top of the stack of currently used
+ targets, within its particular stratum of the stack. Result
+ is 0 if now atop the stack, nonzero if not on top (maybe
+ should warn user).
+
+ unpush_target: Remove this from the stack of currently used targets,
+ no matter where it is on the list. Returns 0 if no
+ change, 1 if removed from stack.
+
+ pop_target: Remove the top thing on the stack of current targets. */
+
+extern void
+add_target PARAMS ((struct target_ops *));
+
+extern int
+push_target PARAMS ((struct target_ops *));
+
+extern int
+unpush_target PARAMS ((struct target_ops *));
+
+extern void
+target_preopen PARAMS ((int));
+
+extern void
+pop_target PARAMS ((void));
+
+/* Struct section_table maps address ranges to file sections. It is
+ mostly used with BFD files, but can be used without (e.g. for handling
+ raw disks, or files not in formats handled by BFD). */
+
+struct section_table {
+ CORE_ADDR addr; /* Lowest address in section */
+ CORE_ADDR endaddr; /* 1+highest address in section */
+
+ sec_ptr the_bfd_section;
+
+ bfd *bfd; /* BFD file pointer */
+};
+
+/* Builds a section table, given args BFD, SECTABLE_PTR, SECEND_PTR.
+ Returns 0 if OK, 1 on error. */
+
+extern int
+build_section_table PARAMS ((bfd *, struct section_table **,
+ struct section_table **));
+
+/* From mem-break.c */
+
+extern int
+memory_remove_breakpoint PARAMS ((CORE_ADDR, char *));
+
+extern int
+memory_insert_breakpoint PARAMS ((CORE_ADDR, char *));
+
+/* From target.c */
+
+void
+noprocess PARAMS ((void));
+
+void
+find_default_attach PARAMS ((char *, int));
+
+void
+find_default_create_inferior PARAMS ((char *, char *, char **));
+
+struct target_ops *
+find_core_target PARAMS ((void));
+
+/* Stuff that should be shared among the various remote targets. */
+
+/* Debugging level. 0 is off, and non-zero values mean to print some debug
+ information (higher values, more information). */
+extern int remote_debug;
+
+/* Speed in bits per second, or -1 which means don't mess with the speed. */
+extern int baud_rate;
+
+/* Functions for helping to write a native target. */
+
+/* This is for native targets which use a unix/POSIX-style waitstatus. */
+extern void store_waitstatus PARAMS ((struct target_waitstatus *, int));
+
+/* Convert between host signal numbers and enum target_signal's. */
+extern enum target_signal target_signal_from_host PARAMS ((int));
+extern int target_signal_to_host PARAMS ((enum target_signal));
+
+#endif /* !defined (TARGET_H) */
diff --git a/gnu/usr.bin/gdb/gdb/terminal.h b/gnu/usr.bin/gdb/gdb/terminal.h
new file mode 100644
index 0000000..f76fa90
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/terminal.h
@@ -0,0 +1,62 @@
+/* Terminal interface definitions for GDB, the GNU Debugger.
+ Copyright 1986, 1989, 1991, 1992 Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#if !defined (TERMINAL_H)
+#define TERMINAL_H 1
+
+#if !defined(__GO32__) && !defined (HAVE_TERMIOS)
+
+/* Define a common set of macros -- BSD based -- and redefine whatever
+ the system offers to make it look like that. FIXME: serial.h and
+ ser-*.c deal with this in a much cleaner fashion; as soon as stuff
+ is converted to use them, can get rid of this crap. */
+
+#ifdef HAVE_TERMIO
+
+#include <termio.h>
+
+#undef TIOCGETP
+#define TIOCGETP TCGETA
+#undef TIOCSETN
+#define TIOCSETN TCSETA
+#undef TIOCSETP
+#define TIOCSETP TCSETAF
+#define TERMINAL struct termio
+
+#else /* sgtty */
+
+#include <fcntl.h>
+#include <sgtty.h>
+#include <sys/ioctl.h>
+#define TERMINAL struct sgttyb
+
+#endif /* sgtty */
+#endif /* termio or sgtty */
+
+extern void new_tty PARAMS ((void));
+
+/* Do we have job control? Can be assumed to always be the same within
+ a given run of GDB. In inflow.c. */
+extern int job_control;
+
+/* Set the process group of the caller to its own pid, or do nothing if
+ we lack job control. */
+extern int gdb_setpgid PARAMS ((void));
+
+#endif /* !defined (TERMINAL_H) */
diff --git a/gnu/usr.bin/gdb/gdb/thread.c b/gnu/usr.bin/gdb/gdb/thread.c
new file mode 100644
index 0000000..c3d52c3
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/thread.c
@@ -0,0 +1,371 @@
+/* Multi-process/thread control for GDB, the GNU debugger.
+ Copyright 1986, 1987, 1988, 1993
+
+ Contributed by Lynx Real-Time Systems, Inc. Los Gatos, CA.
+ Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "defs.h"
+#include "symtab.h"
+#include "frame.h"
+#include "inferior.h"
+#include "environ.h"
+#include "value.h"
+#include "target.h"
+#include "thread.h"
+#include "command.h"
+#include "gdbcmd.h"
+
+#include <ctype.h>
+#include <sys/types.h>
+#include <signal.h>
+
+/*#include "lynxos-core.h"*/
+
+struct thread_info
+{
+ struct thread_info *next;
+ int pid; /* Actual process id */
+ int num; /* Convenient handle */
+};
+
+static struct thread_info *thread_list = NULL;
+static int highest_thread_num;
+
+static void thread_command PARAMS ((char * tidstr, int from_tty));
+
+static void prune_threads PARAMS ((void));
+
+static void thread_switch PARAMS ((int pid));
+
+static struct thread_info * find_thread_id PARAMS ((int num));
+
+void
+init_thread_list ()
+{
+ struct thread_info *tp, *tpnext;
+
+ if (!thread_list)
+ return;
+
+ for (tp = thread_list; tp; tp = tpnext)
+ {
+ tpnext = tp->next;
+ free (tp);
+ }
+
+ thread_list = NULL;
+ highest_thread_num = 0;
+}
+
+void
+add_thread (pid)
+ int pid;
+{
+ struct thread_info *tp;
+
+ tp = (struct thread_info *) xmalloc (sizeof (struct thread_info));
+
+ tp->pid = pid;
+ tp->num = ++highest_thread_num;
+ tp->next = thread_list;
+ thread_list = tp;
+}
+
+static struct thread_info *
+find_thread_id (num)
+ int num;
+{
+ struct thread_info *tp;
+
+ for (tp = thread_list; tp; tp = tp->next)
+ if (tp->num == num)
+ return tp;
+
+ return NULL;
+}
+
+int
+valid_thread_id (num)
+ int num;
+{
+ struct thread_info *tp;
+
+ for (tp = thread_list; tp; tp = tp->next)
+ if (tp->num == num)
+ return 1;
+
+ return 0;
+}
+
+int
+pid_to_thread_id (pid)
+ int pid;
+{
+ struct thread_info *tp;
+
+ for (tp = thread_list; tp; tp = tp->next)
+ if (tp->pid == pid)
+ return tp->num;
+
+ return 0;
+}
+
+int
+in_thread_list (pid)
+ int pid;
+{
+ struct thread_info *tp;
+
+ for (tp = thread_list; tp; tp = tp->next)
+ if (tp->pid == pid)
+ return 1;
+
+ return 0; /* Never heard of 'im */
+}
+
+static void
+prune_threads ()
+{
+ struct thread_info *tp, *tpprev;
+
+ tpprev = 0;
+
+ for (tp = thread_list; tp; tp = tp->next)
+ if (tp->pid == -1)
+ {
+ if (tpprev)
+ tpprev->next = tp->next;
+ else
+ thread_list = NULL;
+
+ free (tp);
+ }
+ else
+ tpprev = tp;
+}
+
+/* Print information about currently known threads */
+
+static void
+info_threads_command (arg, from_tty)
+ char *arg;
+ int from_tty;
+{
+ struct thread_info *tp;
+ int current_pid = inferior_pid;
+
+ for (tp = thread_list; tp; tp = tp->next)
+ {
+ if (target_has_execution
+ && kill (tp->pid, 0) == -1)
+ {
+ tp->pid = -1; /* Mark it as dead */
+ continue;
+ }
+
+ if (tp->pid == current_pid)
+ printf_filtered ("* ");
+ else
+ printf_filtered (" ");
+
+ printf_filtered ("%d %s ", tp->num, target_pid_to_str (tp->pid));
+
+ thread_switch (tp->pid);
+ print_stack_frame (selected_frame, -1, 0);
+ }
+
+ thread_switch (current_pid);
+ prune_threads ();
+}
+
+/* Switch from one thread to another. */
+
+static void
+thread_switch (pid)
+ int pid;
+{
+ if (pid == inferior_pid)
+ return;
+
+ inferior_pid = pid;
+ flush_cached_frames ();
+ registers_changed ();
+ stop_pc = read_pc();
+ set_current_frame (create_new_frame (read_fp (), stop_pc));
+ stop_frame_address = FRAME_FP (get_current_frame ());
+ select_frame (get_current_frame (), 0);
+}
+
+static void
+restore_current_thread (pid)
+ int pid;
+{
+ if (pid != inferior_pid)
+ thread_switch (pid);
+}
+
+/* Apply a GDB command to a list of threads. List syntax is a whitespace
+ seperated list of numbers, or ranges, or the keyword `all'. Ranges consist
+ of two numbers seperated by a hyphen. Examples:
+
+ thread apply 1 2 7 4 backtrace Apply backtrace cmd to threads 1,2,7,4
+ thread apply 2-7 9 p foo(1) Apply p foo(1) cmd to threads 2->7 & 9
+ thread apply all p x/i $pc Apply x/i $pc cmd to all threads
+*/
+
+static void
+thread_apply_all_command (cmd, from_tty)
+ char *cmd;
+ int from_tty;
+{
+ struct thread_info *tp;
+ struct cleanup *old_chain;
+
+ if (cmd == NULL || *cmd == '\000')
+ error ("Please specify a command following the thread ID list");
+
+ old_chain = make_cleanup (restore_current_thread, inferior_pid);
+
+ for (tp = thread_list; tp; tp = tp->next)
+ {
+ thread_switch (tp->pid);
+ printf_filtered ("\nThread %d (%s):\n", tp->num,
+ target_pid_to_str (inferior_pid));
+ execute_command (cmd, from_tty);
+ }
+}
+
+static void
+thread_apply_command (tidlist, from_tty)
+ char *tidlist;
+ int from_tty;
+{
+ char *cmd;
+ char *p;
+ struct cleanup *old_chain;
+
+ if (tidlist == NULL || *tidlist == '\000')
+ error ("Please specify a thread ID list");
+
+ for (cmd = tidlist; *cmd != '\000' && !isalpha(*cmd); cmd++);
+
+ if (*cmd == '\000')
+ error ("Please specify a command following the thread ID list");
+
+ old_chain = make_cleanup (restore_current_thread, inferior_pid);
+
+ while (tidlist < cmd)
+ {
+ struct thread_info *tp;
+ int start, end;
+
+ start = strtol (tidlist, &p, 10);
+ if (p == tidlist)
+ error ("Error parsing %s", tidlist);
+ tidlist = p;
+
+ while (*tidlist == ' ' || *tidlist == '\t')
+ tidlist++;
+
+ if (*tidlist == '-') /* Got a range of IDs? */
+ {
+ tidlist++; /* Skip the - */
+ end = strtol (tidlist, &p, 10);
+ if (p == tidlist)
+ error ("Error parsing %s", tidlist);
+ tidlist = p;
+
+ while (*tidlist == ' ' || *tidlist == '\t')
+ tidlist++;
+ }
+ else
+ end = start;
+
+ for (; start <= end; start++)
+ {
+ tp = find_thread_id (start);
+
+ if (!tp)
+ {
+ warning ("Unknown thread %d.", start);
+ continue;
+ }
+
+ thread_switch (tp->pid);
+ printf_filtered ("\nThread %d (%s):\n", tp->num,
+ target_pid_to_str (inferior_pid));
+ execute_command (cmd, from_tty);
+ }
+ }
+}
+
+/* Switch to the specified thread. Will dispatch off to thread_apply_command
+ if prefix of arg is `apply'. */
+
+static void
+thread_command (tidstr, from_tty)
+ char *tidstr;
+ int from_tty;
+{
+ int num;
+ struct thread_info *tp;
+
+ if (!tidstr)
+ error ("Please specify a thread ID. Use the \"info threads\" command to\n\
+see the IDs of currently known threads.");
+
+ num = atoi (tidstr);
+
+ tp = find_thread_id (num);
+
+ if (!tp)
+ error ("Thread ID %d not known. Use the \"info threads\" command to\n\
+see the IDs of currently known threads.", num);
+
+ thread_switch (tp->pid);
+
+ printf_filtered ("[Switching to %s]\n", target_pid_to_str (inferior_pid));
+ print_stack_frame (selected_frame, selected_frame_level, 1);
+}
+
+void
+_initialize_thread ()
+{
+ static struct cmd_list_element *thread_cmd_list = NULL;
+ static struct cmd_list_element *thread_apply_list = NULL;
+ extern struct cmd_list_element *cmdlist;
+
+ add_info ("threads", info_threads_command,
+ "IDs of currently known threads.");
+
+ add_prefix_cmd ("thread", class_run, thread_command,
+ "Use this command to switch between threads.\n\
+The new thread ID must be currently known.", &thread_cmd_list, "thread ", 1,
+ &cmdlist);
+
+ add_prefix_cmd ("apply", class_run, thread_apply_command,
+ "Apply a command to a list of threads.",
+ &thread_apply_list, "apply ", 1, &thread_cmd_list);
+
+ add_cmd ("all", class_run, thread_apply_all_command,
+ "Apply a command to all threads.",
+ &thread_apply_list);
+
+ add_com_alias ("t", "thread", class_run, 1);
+}
diff --git a/gnu/usr.bin/gdb/gdb/thread.h b/gnu/usr.bin/gdb/gdb/thread.h
new file mode 100644
index 0000000..2ec94fc
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/thread.h
@@ -0,0 +1,36 @@
+/* Multi-process/thread control defs for GDB, the GNU debugger.
+ Copyright 1987, 1988, 1989, 1990, 1991, 1992, 1993
+
+ Contributed by Lynx Real-Time Systems, Inc. Los Gatos, CA.
+ Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#ifndef THREAD_H
+#define THREAD_H
+
+extern void init_thread_list PARAMS ((void));
+
+extern void add_thread PARAMS ((int pid));
+
+extern int in_thread_list PARAMS ((int pid));
+
+extern int pid_to_thread_id PARAMS ((int pid));
+
+extern int valid_thread_id PARAMS ((int thread));
+
+#endif /* THREAD_H */
diff --git a/gnu/usr.bin/gdb/gdb/tm-i386v.h b/gnu/usr.bin/gdb/gdb/tm-i386v.h
new file mode 100644
index 0000000..1584b82
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/tm-i386v.h
@@ -0,0 +1,296 @@
+/* Macro definitions for i386, Unix System V.
+ Copyright 1986, 1987, 1989, 1991, 1992, 1993 Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#if !defined (TM_I386V_H)
+#define TM_I386V_H 1
+
+/*
+ * Changes for 80386 by Pace Willisson (pace@prep.ai.mit.edu)
+ * July 1988
+ */
+
+#define TARGET_BYTE_ORDER LITTLE_ENDIAN
+
+/* turn this on when rest of gdb is ready */
+#define IEEE_FLOAT
+
+/* number of traps that happen between exec'ing the shell
+ * to run an inferior, and when we finally get to
+ * the inferior code. This is 2 on most implementations.
+ */
+#ifndef START_INFERIOR_TRAPS_EXPECTED
+#define START_INFERIOR_TRAPS_EXPECTED 4
+#endif
+
+/* Offset from address of function to start of its code.
+ Zero on most machines. */
+
+#define FUNCTION_START_OFFSET 0
+
+/* Advance PC across any function entry prologue instructions
+ to reach some "real" code. */
+
+#define SKIP_PROLOGUE(frompc) {(frompc) = i386_skip_prologue((frompc));}
+
+extern int
+i386_skip_prologue PARAMS ((int));
+
+/* Immediately after a function call, return the saved pc.
+ Can't always go through the frames for this because on some machines
+ the new frame is not set up until the new function executes
+ some instructions. */
+
+#define SAVED_PC_AFTER_CALL(frame) \
+ (read_memory_integer (read_register (SP_REGNUM), 4))
+
+/* Stack grows downward. */
+
+#define INNER_THAN <
+
+/* Sequence of bytes for breakpoint instruction. */
+
+#define BREAKPOINT {0xcc}
+
+/* Amount PC must be decremented by after a breakpoint.
+ This is often the number of bytes in BREAKPOINT
+ but not always. */
+
+#ifndef DECR_PC_AFTER_BREAK
+#define DECR_PC_AFTER_BREAK 1
+#endif
+
+/* Nonzero if instruction at PC is a return instruction. */
+
+#define ABOUT_TO_RETURN(pc) (read_memory_integer (pc, 1) == 0xc3)
+
+/* Return 1 if P points to an invalid floating point value.
+ LEN is the length in bytes -- not relevant on the 386. */
+
+#define INVALID_FLOAT(p, len) (0)
+
+/* Say how long (ordinary) registers are. This is a piece of bogosity
+ used in push_word and a few other places; REGISTER_RAW_SIZE is the
+ real way to know how big a register is. */
+
+#define REGISTER_SIZE 4
+
+/* Number of machine registers */
+
+#define NUM_REGS 16
+
+/* Initializer for an array of names of registers.
+ There should be NUM_REGS strings in this initializer. */
+
+/* the order of the first 8 registers must match the compiler's
+ * numbering scheme (which is the same as the 386 scheme)
+ * also, this table must match regmap in i386-pinsn.c.
+ */
+#define REGISTER_NAMES { "eax", "ecx", "edx", "ebx", \
+ "esp", "ebp", "esi", "edi", \
+ "eip", "ps", "cs", "ss", \
+ "ds", "es", "fs", "gs", \
+ }
+
+/* Register numbers of various important registers.
+ Note that some of these values are "real" register numbers,
+ and correspond to the general registers of the machine,
+ and some are "phony" register numbers which are too large
+ to be actual register numbers as far as the user is concerned
+ but do serve to get the desired values when passed to read_register. */
+
+#define FP_REGNUM 5 /* Contains address of executing stack frame */
+#define SP_REGNUM 4 /* Contains address of top of stack */
+
+#define PC_REGNUM 8
+#define PS_REGNUM 9
+
+/* Total amount of space needed to store our copies of the machine's
+ register state, the array `registers'. */
+#define REGISTER_BYTES (NUM_REGS * 4)
+
+/* Index within `registers' of the first byte of the space for
+ register N. */
+
+#define REGISTER_BYTE(N) ((N)*4)
+
+/* Number of bytes of storage in the actual machine representation
+ for register N. */
+
+#define REGISTER_RAW_SIZE(N) (4)
+
+/* Number of bytes of storage in the program's representation
+ for register N. */
+
+#define REGISTER_VIRTUAL_SIZE(N) (4)
+
+/* Largest value REGISTER_RAW_SIZE can have. */
+
+#define MAX_REGISTER_RAW_SIZE 4
+
+/* Largest value REGISTER_VIRTUAL_SIZE can have. */
+
+#define MAX_REGISTER_VIRTUAL_SIZE 4
+
+/* Return the GDB type object for the "standard" data type
+ of data in register N. */
+/* Perhaps si and di should go here, but potentially they could be
+ used for things other than address. */
+#define REGISTER_VIRTUAL_TYPE(N) \
+ ((N) == PC_REGNUM || (N) == FP_REGNUM || (N) == SP_REGNUM ? \
+ lookup_pointer_type (builtin_type_void) : builtin_type_int)
+
+/* Store the address of the place in which to copy the structure the
+ subroutine will return. This is called from call_function. */
+
+#define STORE_STRUCT_RETURN(ADDR, SP) \
+ { (SP) -= sizeof (ADDR); \
+ write_memory ((SP), (char *) &(ADDR), sizeof (ADDR)); }
+
+/* Extract from an array REGBUF containing the (raw) register state
+ a function return value of type TYPE, and copy that, in virtual format,
+ into VALBUF. */
+
+#define EXTRACT_RETURN_VALUE(TYPE,REGBUF,VALBUF) \
+ memcpy ((VALBUF), (REGBUF), TYPE_LENGTH (TYPE))
+
+/* Write into appropriate registers a function return value
+ of type TYPE, given in virtual format. */
+
+#define STORE_RETURN_VALUE(TYPE,VALBUF) \
+ write_register_bytes (0, VALBUF, TYPE_LENGTH (TYPE))
+
+/* Extract from an array REGBUF containing the (raw) register state
+ the address in which a function should return its structure value,
+ as a CORE_ADDR (or an expression that can be used as one). */
+
+#define EXTRACT_STRUCT_VALUE_ADDRESS(REGBUF) (*(int *)(REGBUF))
+
+
+/* Describe the pointer in each stack frame to the previous stack frame
+ (its caller). */
+
+/* FRAME_CHAIN takes a frame's nominal address
+ and produces the frame's chain-pointer. */
+
+#define FRAME_CHAIN(thisframe) \
+ (!inside_entry_file ((thisframe)->pc) ? \
+ read_memory_integer ((thisframe)->frame, 4) :\
+ 0)
+
+/* Define other aspects of the stack frame. */
+
+/* A macro that tells us whether the function invocation represented
+ by FI does not have a frame on the stack associated with it. If it
+ does not, FRAMELESS is set to 1, else 0. */
+#define FRAMELESS_FUNCTION_INVOCATION(FI, FRAMELESS) \
+ (FRAMELESS) = frameless_look_for_prologue(FI)
+
+#define FRAME_SAVED_PC(FRAME) (read_memory_integer ((FRAME)->frame + 4, 4))
+
+#define FRAME_ARGS_ADDRESS(fi) ((fi)->frame)
+
+#define FRAME_LOCALS_ADDRESS(fi) ((fi)->frame)
+
+/* Return number of args passed to a frame.
+ Can return -1, meaning no way to tell. */
+
+#define FRAME_NUM_ARGS(numargs, fi) (numargs) = -1
+
+#ifdef __STDC__ /* Forward decl's for prototypes */
+struct frame_info;
+struct frame_saved_regs;
+#endif
+
+extern int
+i386_frame_num_args PARAMS ((struct frame_info *));
+
+/* Return number of bytes at start of arglist that are not really args. */
+
+#define FRAME_ARGS_SKIP 8
+
+/* Put here the code to store, into a struct frame_saved_regs,
+ the addresses of the saved registers of frame described by FRAME_INFO.
+ This includes special registers such as pc and fp saved in special
+ ways in the stack frame. sp is even more special:
+ the address we return for it IS the sp for the next frame. */
+
+#define FRAME_FIND_SAVED_REGS(frame_info, frame_saved_regs) \
+{ i386_frame_find_saved_regs ((frame_info), &(frame_saved_regs)); }
+
+extern void
+i386_frame_find_saved_regs PARAMS ((struct frame_info *,
+ struct frame_saved_regs *));
+
+
+/* Things needed for making the inferior call functions. */
+
+/* Push an empty stack frame, to record the current PC, etc. */
+
+#define PUSH_DUMMY_FRAME { i386_push_dummy_frame (); }
+
+extern void
+i386_push_dummy_frame PARAMS ((void));
+
+/* Discard from the stack the innermost frame, restoring all registers. */
+
+#define POP_FRAME { i386_pop_frame (); }
+
+extern void
+i386_pop_frame PARAMS ((void));
+
+/* this is
+ * call 11223344 (32 bit relative)
+ * int3
+ */
+
+#define CALL_DUMMY { 0x223344e8, 0xcc11 }
+
+#define CALL_DUMMY_LENGTH 8
+
+#define CALL_DUMMY_START_OFFSET 0 /* Start execution at beginning of dummy */
+
+#define CALL_DUMMY_BREAKPOINT_OFFSET 5
+
+/* Insert the specified number of args and function address
+ into a call sequence of the above form stored at DUMMYNAME. */
+
+#define FIX_CALL_DUMMY(dummyname, pc, fun, nargs, args, type, gcc_p) \
+{ \
+ int from, to, delta, loc; \
+ loc = (int)(read_register (SP_REGNUM) - CALL_DUMMY_LENGTH); \
+ from = loc + 5; \
+ to = (int)(fun); \
+ delta = to - from; \
+ *((char *)(dummyname) + 1) = (delta & 0xff); \
+ *((char *)(dummyname) + 2) = ((delta >> 8) & 0xff); \
+ *((char *)(dummyname) + 3) = ((delta >> 16) & 0xff); \
+ *((char *)(dummyname) + 4) = ((delta >> 24) & 0xff); \
+}
+
+extern void
+print_387_control_word PARAMS ((unsigned int));
+
+extern void
+print_387_status_word PARAMS ((unsigned int));
+
+/* Offset from SP to first arg on stack at first instruction of a function */
+
+#define SP_ARG0 (1 * 4)
+
+#endif /* !defined (TM_I386V_H) */
diff --git a/gnu/usr.bin/gdb/gdb/tm.h b/gnu/usr.bin/gdb/gdb/tm.h
new file mode 100644
index 0000000..1c90483
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/tm.h
@@ -0,0 +1,90 @@
+/* Macro definitions for i386 running under BSD Unix.
+ Copyright 1986, 1987, 1989, 1991, 1992, 1993 Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#ifndef _FREEBSD_TM_H_
+#define _FREEBSD_TM_H_
+/* Override number of expected traps from sysv. */
+#define START_INFERIOR_TRAPS_EXPECTED 2
+
+/* Most definitions from sysv could be used. */
+#include "tm-i386v.h"
+
+/* 386BSD cannot handle the segment registers. */
+/* BSDI can't handle them either. */
+/* FreeBSD cannot handle %fs or %gs. */
+#undef NUM_REGS
+#ifdef __FreeBSD__
+#define NUM_REGS 14
+#else
+#define NUM_REGS 10
+#endif
+
+/* On 386 bsd, sigtramp is above the user stack and immediately below
+ the user area. Using constants here allows for cross debugging.
+ These are tested for BSDI but should work on 386BSD. */
+#define SIGTRAMP_START 0xfdbfdfc0
+#define SIGTRAMP_END 0xfdbfe000
+
+/* The following redefines make backtracing through sigtramp work.
+ They manufacture a fake sigtramp frame and obtain the saved pc in sigtramp
+ from the sigcontext structure which is pushed by the kernel on the
+ user stack, along with a pointer to it. */
+
+/* FRAME_CHAIN takes a frame's nominal address and produces the frame's
+ chain-pointer.
+ In the case of the i386, the frame's nominal address
+ is the address of a 4-byte word containing the calling frame's address. */
+#undef FRAME_CHAIN
+#define FRAME_CHAIN(thisframe) \
+ (thisframe->signal_handler_caller \
+ ? thisframe->frame \
+ : (!inside_entry_file ((thisframe)->pc) \
+ ? read_memory_integer ((thisframe)->frame, 4) \
+ : 0))
+
+/* A macro that tells us whether the function invocation represented
+ by FI does not have a frame on the stack associated with it. If it
+ does not, FRAMELESS is set to 1, else 0. */
+#undef FRAMELESS_FUNCTION_INVOCATION
+#define FRAMELESS_FUNCTION_INVOCATION(FI, FRAMELESS) \
+ do { \
+ if ((FI)->signal_handler_caller) \
+ (FRAMELESS) = 0; \
+ else \
+ (FRAMELESS) = frameless_look_for_prologue(FI); \
+ } while (0)
+
+/* Saved Pc. Get it from sigcontext if within sigtramp. */
+
+/* Offset to saved PC in sigcontext, from <sys/signal.h>. */
+#define SIGCONTEXT_PC_OFFSET 20
+
+#undef FRAME_SAVED_PC
+#define FRAME_SAVED_PC(FRAME) \
+ (((FRAME)->signal_handler_caller \
+ ? sigtramp_saved_pc (FRAME) \
+ : read_memory_integer ((FRAME)->frame + 4, 4)) \
+ )
+
+#undef SETUP_ARBITRARY_FRAME
+#include "frame.h"
+extern FRAME setup_arbitrary_frame ();
+#define SETUP_ARBITRARY_FRAME setup_arbitrary_frame
+
+#endif /* _FREEBSD_TM_H_ */
diff --git a/gnu/usr.bin/gdb/gdb/top.c b/gnu/usr.bin/gdb/gdb/top.c
new file mode 100644
index 0000000..f90f141
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/top.c
@@ -0,0 +1,2494 @@
+/* Top level stuff for GDB, the GNU debugger.
+ Copyright 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994
+ Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "defs.h"
+#include "gdbcmd.h"
+#include "call-cmds.h"
+#include "symtab.h"
+#include "inferior.h"
+#include "signals.h"
+#include "target.h"
+#include "breakpoint.h"
+#include "gdbtypes.h"
+#include "expression.h"
+#include "language.h"
+#include "terminal.h" /* For job_control. */
+#include "annotate.h"
+#include <setjmp.h>
+#include "top.h"
+
+/* readline include files */
+#include "readline.h"
+#include "history.h"
+
+/* readline defines this. */
+#undef savestring
+
+#include <sys/types.h>
+#ifdef USG
+/* What is this for? X_OK? */
+#include <unistd.h>
+#endif
+
+#include <string.h>
+#ifndef NO_SYS_FILE
+#include <sys/file.h>
+#endif
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <ctype.h>
+
+/* Prototypes for local functions */
+
+static char *
+symbol_completion_function PARAMS ((char *, int));
+
+static void
+command_loop_marker PARAMS ((int));
+
+static void
+init_main PARAMS ((void));
+
+static void
+init_cmd_lists PARAMS ((void));
+
+static void
+float_handler PARAMS ((int));
+
+static void
+init_signals PARAMS ((void));
+
+static void
+set_verbose PARAMS ((char *, int, struct cmd_list_element *));
+
+static void
+show_history PARAMS ((char *, int));
+
+static void
+set_history PARAMS ((char *, int));
+
+static void
+set_history_size_command PARAMS ((char *, int, struct cmd_list_element *));
+
+static void
+show_commands PARAMS ((char *, int));
+
+static void
+echo_command PARAMS ((char *, int));
+
+static void
+pwd_command PARAMS ((char *, int));
+
+static void
+show_version PARAMS ((char *, int));
+
+static void
+document_command PARAMS ((char *, int));
+
+static void
+define_command PARAMS ((char *, int));
+
+static void
+validate_comname PARAMS ((char *));
+
+static void
+help_command PARAMS ((char *, int));
+
+static void
+show_command PARAMS ((char *, int));
+
+static void
+info_command PARAMS ((char *, int));
+
+static void
+complete_command PARAMS ((char *, int));
+
+static void
+do_nothing PARAMS ((int));
+
+static int
+quit_cover PARAMS ((char *));
+
+static void
+disconnect PARAMS ((int));
+
+static void
+source_cleanup PARAMS ((FILE *));
+
+/* If this definition isn't overridden by the header files, assume
+ that isatty and fileno exist on this system. */
+#ifndef ISATTY
+#define ISATTY(FP) (isatty (fileno (FP)))
+#endif
+
+/* Initialization file name for gdb. This is overridden in some configs. */
+
+#ifndef GDBINIT_FILENAME
+#define GDBINIT_FILENAME ".gdbinit"
+#endif
+char gdbinit[] = GDBINIT_FILENAME;
+int inhibit_gdbinit = 0;
+
+/* Version number of GDB, as a string. */
+
+extern char *version;
+
+/* Canonical host name as a string. */
+
+extern char *host_name;
+
+/* Canonical target name as a string. */
+
+extern char *target_name;
+
+extern char lang_frame_mismatch_warn[]; /* language.c */
+
+/* Flag for whether we want all the "from_tty" gubbish printed. */
+
+int caution = 1; /* Default is yes, sigh. */
+
+/*
+ * Define all cmd_list_element's
+ */
+
+/* Chain containing all defined commands. */
+
+struct cmd_list_element *cmdlist;
+
+/* Chain containing all defined info subcommands. */
+
+struct cmd_list_element *infolist;
+
+/* Chain containing all defined enable subcommands. */
+
+struct cmd_list_element *enablelist;
+
+/* Chain containing all defined disable subcommands. */
+
+struct cmd_list_element *disablelist;
+
+/* Chain containing all defined delete subcommands. */
+
+struct cmd_list_element *deletelist;
+
+/* Chain containing all defined "enable breakpoint" subcommands. */
+
+struct cmd_list_element *enablebreaklist;
+
+/* Chain containing all defined set subcommands */
+
+struct cmd_list_element *setlist;
+
+/* Chain containing all defined unset subcommands */
+
+struct cmd_list_element *unsetlist;
+
+/* Chain containing all defined show subcommands. */
+
+struct cmd_list_element *showlist;
+
+/* Chain containing all defined \"set history\". */
+
+struct cmd_list_element *sethistlist;
+
+/* Chain containing all defined \"show history\". */
+
+struct cmd_list_element *showhistlist;
+
+/* Chain containing all defined \"unset history\". */
+
+struct cmd_list_element *unsethistlist;
+
+/* Chain containing all defined maintenance subcommands. */
+
+#if MAINTENANCE_CMDS
+struct cmd_list_element *maintenancelist;
+#endif
+
+/* Chain containing all defined "maintenance info" subcommands. */
+
+#if MAINTENANCE_CMDS
+struct cmd_list_element *maintenanceinfolist;
+#endif
+
+/* Chain containing all defined "maintenance print" subcommands. */
+
+#if MAINTENANCE_CMDS
+struct cmd_list_element *maintenanceprintlist;
+#endif
+
+struct cmd_list_element *setprintlist;
+
+struct cmd_list_element *showprintlist;
+
+struct cmd_list_element *setchecklist;
+
+struct cmd_list_element *showchecklist;
+
+/* stdio stream that command input is being read from. Set to stdin normally.
+ Set by source_command to the file we are sourcing. Set to NULL if we are
+ executing a user-defined command. */
+
+FILE *instream;
+
+/* Current working directory. */
+
+char *current_directory;
+
+/* The directory name is actually stored here (usually). */
+char gdb_dirbuf[1024];
+
+/* Function to call before reading a command, if nonzero.
+ The function receives two args: an input stream,
+ and a prompt string. */
+
+void (*window_hook) PARAMS ((FILE *, char *));
+
+int epoch_interface;
+int xgdb_verbose;
+
+/* gdb prints this when reading a command interactively */
+static char *prompt;
+
+/* Buffer used for reading command lines, and the size
+ allocated for it so far. */
+
+char *line;
+int linesize = 100;
+
+/* Nonzero if the current command is modified by "server ". This
+ affects things like recording into the command history, comamnds
+ repeating on RETURN, etc. This is so a user interface (emacs, GUI,
+ whatever) can issue its own commands and also send along commands
+ from the user, and have the user not notice that the user interface
+ is issuing commands too. */
+int server_command;
+
+/* Baud rate specified for talking to serial target systems. Default
+ is left as -1, so targets can choose their own defaults. */
+/* FIXME: This means that "show remotebaud" and gr_files_info can print -1
+ or (unsigned int)-1. This is a Bad User Interface. */
+
+int baud_rate = -1;
+
+/* Non-zero tells remote* modules to output debugging info. */
+
+int remote_debug = 0;
+
+/* Signal to catch ^Z typed while reading a command: SIGTSTP or SIGCONT. */
+
+#ifndef STOP_SIGNAL
+#ifdef SIGTSTP
+#define STOP_SIGNAL SIGTSTP
+static void stop_sig PARAMS ((int));
+#endif
+#endif
+
+/* Some System V have job control but not sigsetmask(). */
+#if !defined (HAVE_SIGSETMASK)
+#if !defined (USG)
+#define HAVE_SIGSETMASK 1
+#else
+#define HAVE_SIGSETMASK 0
+#endif
+#endif
+
+#if 0 == (HAVE_SIGSETMASK)
+#define sigsetmask(n)
+#endif
+
+/* Where to go for return_to_top_level (RETURN_ERROR). */
+jmp_buf error_return;
+/* Where to go for return_to_top_level (RETURN_QUIT). */
+jmp_buf quit_return;
+
+#ifdef KERNEL_DEBUG
+/* Non-zero means we are debugging a kernel core file */
+int kernel_debugging = 0;
+int kernel_writablecore = 0;
+#endif
+
+/* Return for reason REASON. This generally gets back to the command
+ loop, but can be caught via catch_errors. */
+
+NORETURN void
+return_to_top_level (reason)
+ enum return_reason reason;
+{
+ quit_flag = 0;
+ immediate_quit = 0;
+
+ /* Perhaps it would be cleaner to do this via the cleanup chain (not sure
+ I can think of a reason why that is vital, though). */
+ bpstat_clear_actions(stop_bpstat); /* Clear queued breakpoint commands */
+
+ disable_current_display ();
+ do_cleanups (ALL_CLEANUPS);
+
+ if (annotation_level > 1)
+ switch (reason)
+ {
+ case RETURN_QUIT:
+ annotate_quit ();
+ break;
+ case RETURN_ERROR:
+ annotate_error ();
+ break;
+ }
+
+ (NORETURN void) longjmp
+ (reason == RETURN_ERROR ? error_return : quit_return, 1);
+}
+
+/* Call FUNC with arg ARGS, catching any errors. If there is no
+ error, return the value returned by FUNC. If there is an error,
+ print ERRSTRING, print the specific error message, then return
+ zero.
+
+ Must not be called with immediate_quit in effect (bad things might
+ happen, say we got a signal in the middle of a memcpy to quit_return).
+ This is an OK restriction; with very few exceptions immediate_quit can
+ be replaced by judicious use of QUIT.
+
+ MASK specifies what to catch; it is normally set to
+ RETURN_MASK_ALL, if for no other reason than that the code which
+ calls catch_errors might not be set up to deal with a quit which
+ isn't caught. But if the code can deal with it, it generally
+ should be RETURN_MASK_ERROR, unless for some reason it is more
+ useful to abort only the portion of the operation inside the
+ catch_errors. Note that quit should return to the command line
+ fairly quickly, even if some further processing is being done. */
+
+int
+catch_errors (func, args, errstring, mask)
+ int (*func) PARAMS ((char *));
+ PTR args;
+ char *errstring;
+ return_mask mask;
+{
+ jmp_buf saved_error;
+ jmp_buf saved_quit;
+ jmp_buf tmp_jmp;
+ int val;
+ struct cleanup *saved_cleanup_chain;
+ char *saved_error_pre_print;
+
+ saved_cleanup_chain = save_cleanups ();
+ saved_error_pre_print = error_pre_print;
+
+ if (mask & RETURN_MASK_ERROR)
+ memcpy ((char *)saved_error, (char *)error_return, sizeof (jmp_buf));
+ if (mask & RETURN_MASK_QUIT)
+ memcpy (saved_quit, quit_return, sizeof (jmp_buf));
+ error_pre_print = errstring;
+
+ if (setjmp (tmp_jmp) == 0)
+ {
+ if (mask & RETURN_MASK_ERROR)
+ memcpy (error_return, tmp_jmp, sizeof (jmp_buf));
+ if (mask & RETURN_MASK_QUIT)
+ memcpy (quit_return, tmp_jmp, sizeof (jmp_buf));
+ val = (*func) (args);
+ }
+ else
+ val = 0;
+
+ restore_cleanups (saved_cleanup_chain);
+
+ error_pre_print = saved_error_pre_print;
+ if (mask & RETURN_MASK_ERROR)
+ memcpy (error_return, saved_error, sizeof (jmp_buf));
+ if (mask & RETURN_MASK_QUIT)
+ memcpy (quit_return, saved_quit, sizeof (jmp_buf));
+ return val;
+}
+
+/* Handler for SIGHUP. */
+
+static void
+disconnect (signo)
+int signo;
+{
+ catch_errors (quit_cover, NULL,
+ "Could not kill the program being debugged", RETURN_MASK_ALL);
+ signal (SIGHUP, SIG_DFL);
+ kill (getpid (), SIGHUP);
+}
+
+/* Just a little helper function for disconnect(). */
+
+static int
+quit_cover (s)
+char *s;
+{
+ caution = 0; /* Throw caution to the wind -- we're exiting.
+ This prevents asking the user dumb questions. */
+ quit_command((char *)0, 0);
+ return 0;
+}
+
+/* Line number we are currently in in a file which is being sourced. */
+static int source_line_number;
+
+/* Name of the file we are sourcing. */
+static char *source_file_name;
+
+/* Buffer containing the error_pre_print used by the source stuff.
+ Malloc'd. */
+static char *source_error;
+static int source_error_allocated;
+
+/* Something to glom on to the start of error_pre_print if source_file_name
+ is set. */
+static char *source_pre_error;
+
+/* Clean up on error during a "source" command (or execution of a
+ user-defined command). */
+
+static void
+source_cleanup (stream)
+ FILE *stream;
+{
+ /* Restore the previous input stream. */
+ instream = stream;
+}
+
+/* Read commands from STREAM. */
+void
+read_command_file (stream)
+ FILE *stream;
+{
+ struct cleanup *cleanups;
+
+ cleanups = make_cleanup (source_cleanup, instream);
+ instream = stream;
+ command_loop ();
+ do_cleanups (cleanups);
+}
+
+extern void init_proc ();
+
+void
+gdb_init ()
+{
+ /* Run the init function of each source file */
+
+ getcwd (gdb_dirbuf, sizeof (gdb_dirbuf));
+ current_directory = gdb_dirbuf;
+
+ init_cmd_lists (); /* This needs to be done first */
+ initialize_all_files ();
+ init_main (); /* But that omits this file! Do it now */
+ init_signals ();
+
+ init_proc ();
+
+ /* We need a default language for parsing expressions, so simple things like
+ "set width 0" won't fail if no language is explicitly set in a config file
+ or implicitly set by reading an executable during startup. */
+ set_language (language_c);
+ expected_language = current_language; /* don't warn about the change. */
+}
+
+void
+execute_user_command (c, args)
+ struct cmd_list_element *c;
+ char *args;
+{
+ register struct command_line *cmdlines;
+ struct cleanup *old_chain;
+
+ if (args)
+ error ("User-defined commands cannot take arguments.");
+
+ cmdlines = c->user_commands;
+ if (cmdlines == 0)
+ /* Null command */
+ return;
+
+ /* Set the instream to 0, indicating execution of a
+ user-defined function. */
+ old_chain = make_cleanup (source_cleanup, instream);
+ instream = (FILE *) 0;
+ while (cmdlines)
+ {
+ execute_command (cmdlines->line, 0);
+ cmdlines = cmdlines->next;
+ }
+ do_cleanups (old_chain);
+}
+
+/* Execute the line P as a command.
+ Pass FROM_TTY as second argument to the defining function. */
+
+void
+execute_command (p, from_tty)
+ char *p;
+ int from_tty;
+{
+ register struct cmd_list_element *c;
+ register enum language flang;
+ static int warned = 0;
+
+ free_all_values ();
+
+ /* This can happen when command_line_input hits end of file. */
+ if (p == NULL)
+ return;
+
+ while (*p == ' ' || *p == '\t') p++;
+ if (*p)
+ {
+ char *arg;
+
+ c = lookup_cmd (&p, cmdlist, "", 0, 1);
+ /* Pass null arg rather than an empty one. */
+ arg = *p ? p : 0;
+
+ /* If this command has been hooked, run the hook first. */
+ if (c->hook)
+ execute_user_command (c->hook, (char *)0);
+
+ if (c->class == class_user)
+ execute_user_command (c, arg);
+ else if (c->type == set_cmd || c->type == show_cmd)
+ do_setshow_command (arg, from_tty & caution, c);
+ else if (c->function.cfunc == NO_FUNCTION)
+ error ("That is not a command, just a help topic.");
+ else
+ (*c->function.cfunc) (arg, from_tty & caution);
+ }
+
+ /* Tell the user if the language has changed (except first time). */
+ if (current_language != expected_language)
+ {
+ if (language_mode == language_mode_auto) {
+ language_info (1); /* Print what changed. */
+ }
+ warned = 0;
+ }
+
+ /* Warn the user if the working language does not match the
+ language of the current frame. Only warn the user if we are
+ actually running the program, i.e. there is a stack. */
+ /* FIXME: This should be cacheing the frame and only running when
+ the frame changes. */
+ if (target_has_stack)
+ {
+ flang = get_frame_language ();
+ if (!warned
+ && flang != language_unknown
+ && flang != current_language->la_language)
+ {
+ printf_filtered ("%s\n", lang_frame_mismatch_warn);
+ warned = 1;
+ }
+ }
+}
+
+/* ARGSUSED */
+static void
+command_loop_marker (foo)
+ int foo;
+{
+}
+
+/* Read commands from `instream' and execute them
+ until end of file or error reading instream. */
+void
+command_loop ()
+{
+ struct cleanup *old_chain;
+ char *command;
+ int stdin_is_tty = ISATTY (stdin);
+
+ while (!feof (instream))
+ {
+ if (window_hook && instream == stdin)
+ (*window_hook) (instream, prompt);
+
+ quit_flag = 0;
+ if (instream == stdin && stdin_is_tty)
+ reinitialize_more_filter ();
+ old_chain = make_cleanup (command_loop_marker, 0);
+ command = command_line_input (instream == stdin ? prompt : (char *) NULL,
+ instream == stdin, "prompt");
+ if (command == 0)
+ return;
+ execute_command (command, instream == stdin);
+ /* Do any commands attached to breakpoint we stopped at. */
+ bpstat_do_actions (&stop_bpstat);
+ do_cleanups (old_chain);
+ }
+}
+
+/* Commands call this if they do not want to be repeated by null lines. */
+
+void
+dont_repeat ()
+{
+ if (server_command)
+ return;
+
+ /* If we aren't reading from standard input, we are saving the last
+ thing read from stdin in line and don't want to delete it. Null lines
+ won't repeat here in any case. */
+ if (instream == stdin)
+ *line = 0;
+}
+
+/* Read a line from the stream "instream" without command line editing.
+
+ It prints PRROMPT once at the start.
+ Action is compatible with "readline", e.g. space for the result is
+ malloc'd and should be freed by the caller.
+
+ A NULL return means end of file. */
+char *
+gdb_readline (prrompt)
+ char *prrompt;
+{
+ int c;
+ char *result;
+ int input_index = 0;
+ int result_size = 80;
+
+ if (prrompt)
+ {
+ /* Don't use a _filtered function here. It causes the assumed
+ character position to be off, since the newline we read from
+ the user is not accounted for. */
+ fputs_unfiltered (prrompt, gdb_stdout);
+ gdb_flush (gdb_stdout);
+ }
+
+ result = (char *) xmalloc (result_size);
+
+ while (1)
+ {
+ /* Read from stdin if we are executing a user defined command.
+ This is the right thing for prompt_for_continue, at least. */
+ c = fgetc (instream ? instream : stdin);
+
+ if (c == EOF)
+ {
+ if (input_index > 0)
+ /* The last line does not end with a newline. Return it, and
+ if we are called again fgetc will still return EOF and
+ we'll return NULL then. */
+ break;
+ free (result);
+ return NULL;
+ }
+
+ if (c == '\n')
+ break;
+
+ result[input_index++] = c;
+ while (input_index >= result_size)
+ {
+ result_size *= 2;
+ result = (char *) xrealloc (result, result_size);
+ }
+ }
+
+ result[input_index++] = '\0';
+ return result;
+}
+
+/* Variables which control command line editing and history
+ substitution. These variables are given default values at the end
+ of this file. */
+static int command_editing_p;
+static int history_expansion_p;
+static int write_history_p;
+static int history_size;
+static char *history_filename;
+
+/* readline uses the word breaks for two things:
+ (1) In figuring out where to point the TEXT parameter to the
+ rl_completion_entry_function. Since we don't use TEXT for much,
+ it doesn't matter a lot what the word breaks are for this purpose, but
+ it does affect how much stuff M-? lists.
+ (2) If one of the matches contains a word break character, readline
+ will quote it. That's why we switch between
+ gdb_completer_word_break_characters and
+ gdb_completer_command_word_break_characters. I'm not sure when
+ we need this behavior (perhaps for funky characters in C++ symbols?). */
+
+/* Variables which are necessary for fancy command line editing. */
+char *gdb_completer_word_break_characters =
+ " \t\n!@#$%^&*()+=|~`}{[]\"';:?/>.<,-";
+
+/* When completing on command names, we remove '-' from the list of
+ word break characters, since we use it in command names. If the
+ readline library sees one in any of the current completion strings,
+ it thinks that the string needs to be quoted and automatically supplies
+ a leading quote. */
+char *gdb_completer_command_word_break_characters =
+ " \t\n!@#$%^&*()+=|~`}{[]\"';:?/>.<,";
+
+/* Characters that can be used to quote completion strings. Note that we
+ can't include '"' because the gdb C parser treats such quoted sequences
+ as strings. */
+char *gdb_completer_quote_characters =
+ "'";
+
+/* Functions that are used as part of the fancy command line editing. */
+
+/* This can be used for functions which don't want to complete on symbols
+ but don't want to complete on anything else either. */
+/* ARGSUSED */
+char **
+noop_completer (text, prefix)
+ char *text;
+ char *prefix;
+{
+ return NULL;
+}
+
+/* Complete on filenames. */
+char **
+filename_completer (text, word)
+ char *text;
+ char *word;
+{
+ /* From readline. */
+ extern char *filename_completion_function ();
+ int subsequent_name;
+ char **return_val;
+ int return_val_used;
+ int return_val_alloced;
+
+ return_val_used = 0;
+ /* Small for testing. */
+ return_val_alloced = 1;
+ return_val = (char **) xmalloc (return_val_alloced * sizeof (char *));
+
+ subsequent_name = 0;
+ while (1)
+ {
+ char *p;
+ p = filename_completion_function (text, subsequent_name);
+ if (return_val_used >= return_val_alloced)
+ {
+ return_val_alloced *= 2;
+ return_val =
+ (char **) xrealloc (return_val,
+ return_val_alloced * sizeof (char *));
+ }
+ if (p == NULL)
+ {
+ return_val[return_val_used++] = p;
+ break;
+ }
+ /* Like emacs, don't complete on old versions. Especially useful
+ in the "source" command. */
+ if (p[strlen (p) - 1] == '~')
+ continue;
+
+ {
+ char *q;
+ if (word == text)
+ /* Return exactly p. */
+ return_val[return_val_used++] = p;
+ else if (word > text)
+ {
+ /* Return some portion of p. */
+ q = xmalloc (strlen (p) + 5);
+ strcpy (q, p + (word - text));
+ return_val[return_val_used++] = q;
+ free (p);
+ }
+ else
+ {
+ /* Return some of TEXT plus p. */
+ q = xmalloc (strlen (p) + (text - word) + 5);
+ strncpy (q, word, text - word);
+ q[text - word] = '\0';
+ strcat (q, p);
+ return_val[return_val_used++] = q;
+ free (p);
+ }
+ }
+ subsequent_name = 1;
+ }
+#if 0
+ /* There is no way to do this just long enough to affect quote inserting
+ without also affecting the next completion. This should be fixed in
+ readline. FIXME. */
+ /* Insure that readline does the right thing
+ with respect to inserting quotes. */
+ rl_completer_word_break_characters = "";
+#endif
+ return return_val;
+}
+
+/* Here are some useful test cases for completion. FIXME: These should
+ be put in the test suite. They should be tested with both M-? and TAB.
+
+ "show output-" "radix"
+ "show output" "-radix"
+ "p" ambiguous (commands starting with p--path, print, printf, etc.)
+ "p " ambiguous (all symbols)
+ "info t foo" no completions
+ "info t " no completions
+ "info t" ambiguous ("info target", "info terminal", etc.)
+ "info ajksdlfk" no completions
+ "info ajksdlfk " no completions
+ "info" " "
+ "info " ambiguous (all info commands)
+ "p \"a" no completions (string constant)
+ "p 'a" ambiguous (all symbols starting with a)
+ "p b-a" ambiguous (all symbols starting with a)
+ "p b-" ambiguous (all symbols)
+ "file Make" "file" (word break hard to screw up here)
+ "file ../gdb.stabs/we" "ird" (needs to not break word at slash)
+ */
+
+/* Generate completions one by one for the completer. Each time we are
+ called return another potential completion to the caller. The function
+ is misnamed; it just completes on commands or passes the buck to the
+ command's completer function; the stuff specific to symbol completion
+ is in make_symbol_completion_list.
+
+ TEXT is readline's idea of the "word" we are looking at; we don't really
+ like readline's ideas about word breaking so we ignore it.
+
+ MATCHES is the number of matches that have currently been collected from
+ calling this completion function. When zero, then we need to initialize,
+ otherwise the initialization has already taken place and we can just
+ return the next potential completion string.
+
+ Returns NULL if there are no more completions, else a pointer to a string
+ which is a possible completion.
+
+ RL_LINE_BUFFER is available to be looked at; it contains the entire text
+ of the line. RL_POINT is the offset in that line of the cursor. You
+ should pretend that the line ends at RL_POINT. */
+
+static char *
+symbol_completion_function (text, matches)
+ char *text;
+ int matches;
+{
+ static char **list = (char **)NULL; /* Cache of completions */
+ static int index; /* Next cached completion */
+ char *output = NULL;
+ char *tmp_command, *p;
+ /* Pointer within tmp_command which corresponds to text. */
+ char *word;
+ struct cmd_list_element *c, *result_list;
+
+ if (matches == 0)
+ {
+ /* The caller is beginning to accumulate a new set of completions, so
+ we need to find all of them now, and cache them for returning one at
+ a time on future calls. */
+
+ if (list)
+ {
+ /* Free the storage used by LIST, but not by the strings inside.
+ This is because rl_complete_internal () frees the strings. */
+ free ((PTR)list);
+ }
+ list = 0;
+ index = 0;
+
+ /* Choose the default set of word break characters to break completions.
+ If we later find out that we are doing completions on command strings
+ (as opposed to strings supplied by the individual command completer
+ functions, which can be any string) then we will switch to the
+ special word break set for command strings, which leaves out the
+ '-' character used in some commands. */
+
+ rl_completer_word_break_characters =
+ gdb_completer_word_break_characters;
+
+ /* Decide whether to complete on a list of gdb commands or on symbols. */
+ tmp_command = (char *) alloca (rl_point + 1);
+ p = tmp_command;
+
+ strncpy (tmp_command, rl_line_buffer, rl_point);
+ tmp_command[rl_point] = '\0';
+ /* Since text always contains some number of characters leading up
+ to rl_point, we can find the equivalent position in tmp_command
+ by subtracting that many characters from the end of tmp_command. */
+ word = tmp_command + rl_point - strlen (text);
+
+ if (rl_point == 0)
+ {
+ /* An empty line we want to consider ambiguous; that is, it
+ could be any command. */
+ c = (struct cmd_list_element *) -1;
+ result_list = 0;
+ }
+ else
+ {
+ c = lookup_cmd_1 (&p, cmdlist, &result_list, 1);
+ }
+
+ /* Move p up to the next interesting thing. */
+ while (*p == ' ' || *p == '\t')
+ {
+ p++;
+ }
+
+ if (!c)
+ {
+ /* It is an unrecognized command. So there are no
+ possible completions. */
+ list = NULL;
+ }
+ else if (c == (struct cmd_list_element *) -1)
+ {
+ char *q;
+
+ /* lookup_cmd_1 advances p up to the first ambiguous thing, but
+ doesn't advance over that thing itself. Do so now. */
+ q = p;
+ while (*q && (isalnum (*q) || *q == '-' || *q == '_'))
+ ++q;
+ if (q != tmp_command + rl_point)
+ {
+ /* There is something beyond the ambiguous
+ command, so there are no possible completions. For
+ example, "info t " or "info t foo" does not complete
+ to anything, because "info t" can be "info target" or
+ "info terminal". */
+ list = NULL;
+ }
+ else
+ {
+ /* We're trying to complete on the command which was ambiguous.
+ This we can deal with. */
+ if (result_list)
+ {
+ list = complete_on_cmdlist (*result_list->prefixlist, p,
+ word);
+ }
+ else
+ {
+ list = complete_on_cmdlist (cmdlist, p, word);
+ }
+ /* Insure that readline does the right thing with respect to
+ inserting quotes. */
+ rl_completer_word_break_characters =
+ gdb_completer_command_word_break_characters;
+ }
+ }
+ else
+ {
+ /* We've recognized a full command. */
+
+ if (p == tmp_command + rl_point)
+ {
+ /* There is no non-whitespace in the line beyond the command. */
+
+ if (p[-1] == ' ' || p[-1] == '\t')
+ {
+ /* The command is followed by whitespace; we need to complete
+ on whatever comes after command. */
+ if (c->prefixlist)
+ {
+ /* It is a prefix command; what comes after it is
+ a subcommand (e.g. "info "). */
+ list = complete_on_cmdlist (*c->prefixlist, p, word);
+
+ /* Insure that readline does the right thing
+ with respect to inserting quotes. */
+ rl_completer_word_break_characters =
+ gdb_completer_command_word_break_characters;
+ }
+ else
+ {
+ /* It is a normal command; what comes after it is
+ completed by the command's completer function. */
+ list = (*c->completer) (p, word);
+ }
+ }
+ else
+ {
+ /* The command is not followed by whitespace; we need to
+ complete on the command itself. e.g. "p" which is a
+ command itself but also can complete to "print", "ptype"
+ etc. */
+ char *q;
+
+ /* Find the command we are completing on. */
+ q = p;
+ while (q > tmp_command)
+ {
+ if (isalnum (q[-1]) || q[-1] == '-' || q[-1] == '_')
+ --q;
+ else
+ break;
+ }
+
+ list = complete_on_cmdlist (result_list, q, word);
+
+ /* Insure that readline does the right thing
+ with respect to inserting quotes. */
+ rl_completer_word_break_characters =
+ gdb_completer_command_word_break_characters;
+ }
+ }
+ else
+ {
+ /* There is non-whitespace beyond the command. */
+
+ if (c->prefixlist && !c->allow_unknown)
+ {
+ /* It is an unrecognized subcommand of a prefix command,
+ e.g. "info adsfkdj". */
+ list = NULL;
+ }
+ else
+ {
+ /* It is a normal command. */
+ list = (*c->completer) (p, word);
+ }
+ }
+ }
+ }
+
+ /* If we found a list of potential completions during initialization then
+ dole them out one at a time. The vector of completions is NULL
+ terminated, so after returning the last one, return NULL (and continue
+ to do so) each time we are called after that, until a new list is
+ available. */
+
+ if (list)
+ {
+ output = list[index];
+ if (output)
+ {
+ index++;
+ }
+ }
+
+#if 0
+ /* Can't do this because readline hasn't yet checked the word breaks
+ for figuring out whether to insert a quote. */
+ if (output == NULL)
+ /* Make sure the word break characters are set back to normal for the
+ next time that readline tries to complete something. */
+ rl_completer_word_break_characters =
+ gdb_completer_word_break_characters;
+#endif
+
+ return (output);
+}
+
+/* Skip over a possibly quoted word (as defined by the quote characters
+ and word break characters the completer uses). Returns pointer to the
+ location after the "word". */
+
+char *
+skip_quoted (str)
+ char *str;
+{
+ char quote_char = '\0';
+ char *scan;
+
+ for (scan = str; *scan != '\0'; scan++)
+ {
+ if (quote_char != '\0')
+ {
+ /* Ignore everything until the matching close quote char */
+ if (*scan == quote_char)
+ {
+ /* Found matching close quote. */
+ scan++;
+ break;
+ }
+ }
+ else if (strchr (gdb_completer_quote_characters, *scan))
+ {
+ /* Found start of a quoted string. */
+ quote_char = *scan;
+ }
+ else if (strchr (gdb_completer_word_break_characters, *scan))
+ {
+ break;
+ }
+ }
+ return (scan);
+}
+
+
+#ifdef STOP_SIGNAL
+static void
+stop_sig (signo)
+int signo;
+{
+#if STOP_SIGNAL == SIGTSTP
+ signal (SIGTSTP, SIG_DFL);
+ sigsetmask (0);
+ kill (getpid (), SIGTSTP);
+ signal (SIGTSTP, stop_sig);
+#else
+ signal (STOP_SIGNAL, stop_sig);
+#endif
+ printf_unfiltered ("%s", prompt);
+ gdb_flush (gdb_stdout);
+
+ /* Forget about any previous command -- null line now will do nothing. */
+ dont_repeat ();
+}
+#endif /* STOP_SIGNAL */
+
+/* Initialize signal handlers. */
+static void
+do_nothing (signo)
+int signo;
+{
+}
+
+static void
+init_signals ()
+{
+ signal (SIGINT, request_quit);
+
+ /* If we initialize SIGQUIT to SIG_IGN, then the SIG_IGN will get
+ passed to the inferior, which we don't want. It would be
+ possible to do a "signal (SIGQUIT, SIG_DFL)" after we fork, but
+ on BSD4.3 systems using vfork, that can affect the
+ GDB process as well as the inferior (the signal handling tables
+ might be in memory, shared between the two). Since we establish
+ a handler for SIGQUIT, when we call exec it will set the signal
+ to SIG_DFL for us. */
+ signal (SIGQUIT, do_nothing);
+ if (signal (SIGHUP, do_nothing) != SIG_IGN)
+ signal (SIGHUP, disconnect);
+ signal (SIGFPE, float_handler);
+
+#if defined(SIGWINCH) && defined(SIGWINCH_HANDLER)
+ signal (SIGWINCH, SIGWINCH_HANDLER);
+#endif
+}
+
+/* Read one line from the command input stream `instream'
+ into the local static buffer `linebuffer' (whose current length
+ is `linelength').
+ The buffer is made bigger as necessary.
+ Returns the address of the start of the line.
+
+ NULL is returned for end of file.
+
+ *If* the instream == stdin & stdin is a terminal, the line read
+ is copied into the file line saver (global var char *line,
+ length linesize) so that it can be duplicated.
+
+ This routine either uses fancy command line editing or
+ simple input as the user has requested. */
+
+char *
+command_line_input (prrompt, repeat, annotation_suffix)
+ char *prrompt;
+ int repeat;
+ char *annotation_suffix;
+{
+ static char *linebuffer = 0;
+ static unsigned linelength = 0;
+ register char *p;
+ char *p1;
+ char *rl;
+ char *local_prompt = prrompt;
+ register int c;
+ char *nline;
+ char got_eof = 0;
+
+ if (annotation_level > 1 && instream == stdin)
+ {
+ local_prompt = alloca ((prrompt == NULL ? 0 : strlen (prrompt))
+ + strlen (annotation_suffix) + 40);
+ if (prrompt == NULL)
+ local_prompt[0] = '\0';
+ else
+ strcpy (local_prompt, prrompt);
+ strcat (local_prompt, "\n\032\032");
+ strcat (local_prompt, annotation_suffix);
+ strcat (local_prompt, "\n");
+ }
+
+ if (linebuffer == 0)
+ {
+ linelength = 80;
+ linebuffer = (char *) xmalloc (linelength);
+ }
+
+ p = linebuffer;
+
+ /* Control-C quits instantly if typed while in this loop
+ since it should not wait until the user types a newline. */
+ immediate_quit++;
+#ifdef STOP_SIGNAL
+ if (job_control)
+ signal (STOP_SIGNAL, stop_sig);
+#endif
+
+ while (1)
+ {
+ /* Make sure that all output has been output. Some machines may let
+ you get away with leaving out some of the gdb_flush, but not all. */
+ wrap_here ("");
+ gdb_flush (gdb_stdout);
+ gdb_flush (gdb_stderr);
+
+ if (source_file_name != NULL)
+ {
+ ++source_line_number;
+ sprintf (source_error,
+ "%s%s:%d: Error in sourced command file:\n",
+ source_pre_error,
+ source_file_name,
+ source_line_number);
+ error_pre_print = source_error;
+ }
+
+ if (annotation_level > 1 && instream == stdin)
+ {
+ printf_unfiltered ("\n\032\032pre-");
+ printf_unfiltered (annotation_suffix);
+ printf_unfiltered ("\n");
+ }
+
+ /* Don't use fancy stuff if not talking to stdin. */
+ if (command_editing_p && instream == stdin
+ && ISATTY (instream))
+ rl = readline (local_prompt);
+ else
+ rl = gdb_readline (local_prompt);
+
+ if (annotation_level > 1 && instream == stdin)
+ {
+ printf_unfiltered ("\n\032\032post-");
+ printf_unfiltered (annotation_suffix);
+ printf_unfiltered ("\n");
+ }
+
+ if (!rl || rl == (char *) EOF)
+ {
+ got_eof = 1;
+ break;
+ }
+ if (strlen(rl) + 1 + (p - linebuffer) > linelength)
+ {
+ linelength = strlen(rl) + 1 + (p - linebuffer);
+ nline = (char *) xrealloc (linebuffer, linelength);
+ p += nline - linebuffer;
+ linebuffer = nline;
+ }
+ p1 = rl;
+ /* Copy line. Don't copy null at end. (Leaves line alone
+ if this was just a newline) */
+ while (*p1)
+ *p++ = *p1++;
+
+ free (rl); /* Allocated in readline. */
+
+ if (p == linebuffer || *(p - 1) != '\\')
+ break;
+
+ p--; /* Put on top of '\'. */
+ local_prompt = (char *) 0;
+ }
+
+#ifdef STOP_SIGNAL
+ if (job_control)
+ signal (STOP_SIGNAL, SIG_DFL);
+#endif
+ immediate_quit--;
+
+ if (got_eof)
+ return NULL;
+
+#define SERVER_COMMAND_LENGTH 7
+ server_command =
+ (p - linebuffer > SERVER_COMMAND_LENGTH)
+ && STREQN (linebuffer, "server ", SERVER_COMMAND_LENGTH);
+ if (server_command)
+ {
+ /* Note that we don't set `line'. Between this and the check in
+ dont_repeat, this insures that repeating will still do the
+ right thing. */
+ *p = '\0';
+ return linebuffer + SERVER_COMMAND_LENGTH;
+ }
+
+ /* Do history expansion if that is wished. */
+ if (history_expansion_p && instream == stdin
+ && ISATTY (instream))
+ {
+ char *history_value;
+ int expanded;
+
+ *p = '\0'; /* Insert null now. */
+ expanded = history_expand (linebuffer, &history_value);
+ if (expanded)
+ {
+ /* Print the changes. */
+ printf_unfiltered ("%s\n", history_value);
+
+ /* If there was an error, call this function again. */
+ if (expanded < 0)
+ {
+ free (history_value);
+ return command_line_input (prrompt, repeat, annotation_suffix);
+ }
+ if (strlen (history_value) > linelength)
+ {
+ linelength = strlen (history_value) + 1;
+ linebuffer = (char *) xrealloc (linebuffer, linelength);
+ }
+ strcpy (linebuffer, history_value);
+ p = linebuffer + strlen(linebuffer);
+ free (history_value);
+ }
+ }
+
+ /* If we just got an empty line, and that is supposed
+ to repeat the previous command, return the value in the
+ global buffer. */
+ if (repeat)
+ {
+ if (p == linebuffer)
+ return line;
+ p1 = linebuffer;
+ while (*p1 == ' ' || *p1 == '\t')
+ p1++;
+ if (!*p1)
+ return line;
+ }
+
+ *p = 0;
+
+ /* Add line to history if appropriate. */
+ if (instream == stdin
+ && ISATTY (stdin) && *linebuffer)
+ add_history (linebuffer);
+
+ /* Note: lines consisting solely of comments are added to the command
+ history. This is useful when you type a command, and then
+ realize you don't want to execute it quite yet. You can comment
+ out the command and then later fetch it from the value history
+ and remove the '#'. The kill ring is probably better, but some
+ people are in the habit of commenting things out. */
+ p1 = linebuffer;
+ while ((c = *p1++) != '\0')
+ {
+ if (c == '"')
+ while ((c = *p1++) != '"')
+ {
+ /* Make sure an escaped '"' doesn't make us think the string
+ is ended. */
+ if (c == '\\')
+ parse_escape (&p1);
+ if (c == '\0')
+ break;
+ }
+ else if (c == '\'')
+ while ((c = *p1++) != '\'')
+ {
+ /* Make sure an escaped '\'' doesn't make us think the string
+ is ended. */
+ if (c == '\\')
+ parse_escape (&p1);
+ if (c == '\0')
+ break;
+ }
+ else if (c == '#')
+ {
+ /* Found a comment. */
+ p1[-1] = '\0';
+ break;
+ }
+ }
+
+ /* Save into global buffer if appropriate. */
+ if (repeat)
+ {
+ if (linelength > linesize)
+ {
+ line = xrealloc (line, linelength);
+ linesize = linelength;
+ }
+ strcpy (line, linebuffer);
+ return line;
+ }
+
+ return linebuffer;
+}
+
+/* Read lines from the input stream
+ and accumulate them in a chain of struct command_line's
+ which is then returned. */
+
+struct command_line *
+read_command_lines ()
+{
+ struct command_line *first = 0;
+ register struct command_line *next, *tail = 0;
+ register char *p, *p1;
+ struct cleanup *old_chain = 0;
+
+ while (1)
+ {
+ dont_repeat ();
+ p = command_line_input ((char *) NULL, instream == stdin, "commands");
+ if (p == NULL)
+ /* Treat end of file like "end". */
+ break;
+
+ /* Remove leading and trailing blanks. */
+ while (*p == ' ' || *p == '\t') p++;
+ p1 = p + strlen (p);
+ while (p1 != p && (p1[-1] == ' ' || p1[-1] == '\t')) p1--;
+
+ /* Is this "end"? */
+ if (p1 - p == 3 && !strncmp (p, "end", 3))
+ break;
+
+ /* No => add this line to the chain of command lines. */
+ next = (struct command_line *) xmalloc (sizeof (struct command_line));
+ next->line = savestring (p, p1 - p);
+ next->next = 0;
+ if (tail)
+ {
+ tail->next = next;
+ }
+ else
+ {
+ /* We just read the first line.
+ From now on, arrange to throw away the lines we have
+ if we quit or get an error while inside this function. */
+ first = next;
+ old_chain = make_cleanup (free_command_lines, &first);
+ }
+ tail = next;
+ }
+
+ dont_repeat ();
+
+ /* Now we are about to return the chain to our caller,
+ so freeing it becomes his responsibility. */
+ if (first)
+ discard_cleanups (old_chain);
+ return first;
+}
+
+/* Free a chain of struct command_line's. */
+
+void
+free_command_lines (lptr)
+ struct command_line **lptr;
+{
+ register struct command_line *l = *lptr;
+ register struct command_line *next;
+
+ while (l)
+ {
+ next = l->next;
+ free (l->line);
+ free ((PTR)l);
+ l = next;
+ }
+}
+
+/* Add an element to the list of info subcommands. */
+
+void
+add_info (name, fun, doc)
+ char *name;
+ void (*fun) PARAMS ((char *, int));
+ char *doc;
+{
+ add_cmd (name, no_class, fun, doc, &infolist);
+}
+
+/* Add an alias to the list of info subcommands. */
+
+void
+add_info_alias (name, oldname, abbrev_flag)
+ char *name;
+ char *oldname;
+ int abbrev_flag;
+{
+ add_alias_cmd (name, oldname, 0, abbrev_flag, &infolist);
+}
+
+/* The "info" command is defined as a prefix, with allow_unknown = 0.
+ Therefore, its own definition is called only for "info" with no args. */
+
+/* ARGSUSED */
+static void
+info_command (arg, from_tty)
+ char *arg;
+ int from_tty;
+{
+ printf_unfiltered ("\"info\" must be followed by the name of an info command.\n");
+ help_list (infolist, "info ", -1, gdb_stdout);
+}
+
+/* The "complete" command is used by Emacs to implement completion. */
+
+/* ARGSUSED */
+static void
+complete_command (arg, from_tty)
+ char *arg;
+ int from_tty;
+{
+ int i;
+ char *completion;
+
+ dont_repeat ();
+
+ if (arg == NULL)
+ {
+ rl_line_buffer[0] = '\0';
+ rl_point = 0;
+ }
+ else
+ {
+ strcpy (rl_line_buffer, arg);
+ rl_point = strlen (arg);
+ }
+
+ for (completion = symbol_completion_function (rl_line_buffer, i = 0);
+ completion;
+ completion = symbol_completion_function (rl_line_buffer, ++i))
+ printf_unfiltered ("%s\n", completion);
+}
+
+/* The "show" command with no arguments shows all the settings. */
+
+/* ARGSUSED */
+static void
+show_command (arg, from_tty)
+ char *arg;
+ int from_tty;
+{
+ cmd_show_list (showlist, from_tty, "");
+}
+
+/* Add an element to the list of commands. */
+
+void
+add_com (name, class, fun, doc)
+ char *name;
+ enum command_class class;
+ void (*fun) PARAMS ((char *, int));
+ char *doc;
+{
+ add_cmd (name, class, fun, doc, &cmdlist);
+}
+
+/* Add an alias or abbreviation command to the list of commands. */
+
+void
+add_com_alias (name, oldname, class, abbrev_flag)
+ char *name;
+ char *oldname;
+ enum command_class class;
+ int abbrev_flag;
+{
+ add_alias_cmd (name, oldname, class, abbrev_flag, &cmdlist);
+}
+
+void
+error_no_arg (why)
+ char *why;
+{
+ error ("Argument required (%s).", why);
+}
+
+/* ARGSUSED */
+static void
+help_command (command, from_tty)
+ char *command;
+ int from_tty; /* Ignored */
+{
+ help_cmd (command, gdb_stdout);
+}
+
+static void
+validate_comname (comname)
+ char *comname;
+{
+ register char *p;
+
+ if (comname == 0)
+ error_no_arg ("name of command to define");
+
+ p = comname;
+ while (*p)
+ {
+ if (!isalnum(*p) && *p != '-')
+ error ("Junk in argument list: \"%s\"", p);
+ p++;
+ }
+}
+
+/* This is just a placeholder in the command data structures. */
+static void
+user_defined_command (ignore, from_tty)
+ char *ignore;
+ int from_tty;
+{
+}
+
+static void
+define_command (comname, from_tty)
+ char *comname;
+ int from_tty;
+{
+ register struct command_line *cmds;
+ register struct cmd_list_element *c, *newc, *hookc = 0;
+ char *tem = comname;
+#define HOOK_STRING "hook-"
+#define HOOK_LEN 5
+
+ validate_comname (comname);
+
+ /* Look it up, and verify that we got an exact match. */
+ c = lookup_cmd (&tem, cmdlist, "", -1, 1);
+ if (c && !STREQ (comname, c->name))
+ c = 0;
+
+ if (c)
+ {
+ if (c->class == class_user || c->class == class_alias)
+ tem = "Redefine command \"%s\"? ";
+ else
+ tem = "Really redefine built-in command \"%s\"? ";
+ if (!query (tem, c->name))
+ error ("Command \"%s\" not redefined.", c->name);
+ }
+
+ /* If this new command is a hook, then mark the command which it
+ is hooking. Note that we allow hooking `help' commands, so that
+ we can hook the `stop' pseudo-command. */
+
+ if (!strncmp (comname, HOOK_STRING, HOOK_LEN))
+ {
+ /* Look up cmd it hooks, and verify that we got an exact match. */
+ tem = comname+HOOK_LEN;
+ hookc = lookup_cmd (&tem, cmdlist, "", -1, 0);
+ if (hookc && !STREQ (comname+HOOK_LEN, hookc->name))
+ hookc = 0;
+ if (!hookc)
+ {
+ warning ("Your new `%s' command does not hook any existing command.",
+ comname);
+ if (!query ("Proceed? ", (char *)0))
+ error ("Not confirmed.");
+ }
+ }
+
+ comname = savestring (comname, strlen (comname));
+
+ /* If the rest of the commands will be case insensitive, this one
+ should behave in the same manner. */
+ for (tem = comname; *tem; tem++)
+ if (isupper(*tem)) *tem = tolower(*tem);
+
+ if (from_tty)
+ {
+ printf_unfiltered ("Type commands for definition of \"%s\".\n\
+End with a line saying just \"end\".\n", comname);
+ gdb_flush (gdb_stdout);
+ }
+
+ cmds = read_command_lines ();
+
+ if (c && c->class == class_user)
+ free_command_lines (&c->user_commands);
+
+ newc = add_cmd (comname, class_user, user_defined_command,
+ (c && c->class == class_user)
+ ? c->doc : savestring ("User-defined.", 13), &cmdlist);
+ newc->user_commands = cmds;
+
+ /* If this new command is a hook, then mark both commands as being
+ tied. */
+ if (hookc)
+ {
+ hookc->hook = newc; /* Target gets hooked. */
+ newc->hookee = hookc; /* We are marked as hooking target cmd. */
+ }
+}
+
+static void
+document_command (comname, from_tty)
+ char *comname;
+ int from_tty;
+{
+ struct command_line *doclines;
+ register struct cmd_list_element *c;
+ char *tem = comname;
+
+ validate_comname (comname);
+
+ c = lookup_cmd (&tem, cmdlist, "", 0, 1);
+
+ if (c->class != class_user)
+ error ("Command \"%s\" is built-in.", comname);
+
+ if (from_tty)
+ printf_unfiltered ("Type documentation for \"%s\".\n\
+End with a line saying just \"end\".\n", comname);
+
+ doclines = read_command_lines ();
+
+ if (c->doc) free (c->doc);
+
+ {
+ register struct command_line *cl1;
+ register int len = 0;
+
+ for (cl1 = doclines; cl1; cl1 = cl1->next)
+ len += strlen (cl1->line) + 1;
+
+ c->doc = (char *) xmalloc (len + 1);
+ *c->doc = 0;
+
+ for (cl1 = doclines; cl1; cl1 = cl1->next)
+ {
+ strcat (c->doc, cl1->line);
+ if (cl1->next)
+ strcat (c->doc, "\n");
+ }
+ }
+
+ free_command_lines (&doclines);
+}
+
+void
+print_gnu_advertisement ()
+{
+ printf_unfiltered ("\
+GDB is free software and you are welcome to distribute copies of it\n\
+ under certain conditions; type \"show copying\" to see the conditions.\n\
+There is absolutely no warranty for GDB; type \"show warranty\" for details.\n\
+");
+}
+
+void
+print_gdb_version (stream)
+ GDB_FILE *stream;
+{
+ fprintf_filtered (stream, "\
+GDB %s (%s", version, host_name);
+
+ if (!STREQ (host_name, target_name))
+ fprintf_filtered (stream, " --target %s", target_name);
+
+ fprintf_filtered (stream, "), ");
+ wrap_here("");
+ fprintf_filtered (stream, "Copyright 1994 Free Software Foundation, Inc.");
+}
+
+/* ARGSUSED */
+static void
+show_version (args, from_tty)
+ char *args;
+ int from_tty;
+{
+ immediate_quit++;
+ print_gnu_advertisement ();
+ print_gdb_version (gdb_stdout);
+ printf_filtered ("\n");
+ immediate_quit--;
+}
+
+/* xgdb calls this to reprint the usual GDB prompt. Obsolete now that xgdb
+ is obsolete. */
+
+void
+print_prompt ()
+{
+ printf_unfiltered ("%s", prompt);
+ gdb_flush (gdb_stdout);
+}
+
+void
+quit_command (args, from_tty)
+ char *args;
+ int from_tty;
+{
+ if (inferior_pid != 0 && target_has_execution)
+ {
+ if (attach_flag)
+ {
+ if (query ("The program is running. Quit anyway (and detach it)? "))
+ target_detach (args, from_tty);
+ else
+ error ("Not confirmed.");
+ }
+ else
+ {
+ if (query ("The program is running. Quit anyway (and kill it)? "))
+ target_kill ();
+ else
+ error ("Not confirmed.");
+ }
+ }
+ /* UDI wants this, to kill the TIP. */
+ target_close (1);
+
+ /* Save the history information if it is appropriate to do so. */
+ if (write_history_p && history_filename)
+ write_history (history_filename);
+
+ exit (0);
+}
+
+/* Returns whether GDB is running on a terminal and whether the user
+ desires that questions be asked of them on that terminal. */
+
+int
+input_from_terminal_p ()
+{
+ return gdb_has_a_terminal () && (instream == stdin) & caution;
+}
+
+/* ARGSUSED */
+static void
+pwd_command (args, from_tty)
+ char *args;
+ int from_tty;
+{
+ if (args) error ("The \"pwd\" command does not take an argument: %s", args);
+ getcwd (gdb_dirbuf, sizeof (gdb_dirbuf));
+
+ if (!STREQ (gdb_dirbuf, current_directory))
+ printf_unfiltered ("Working directory %s\n (canonically %s).\n",
+ current_directory, gdb_dirbuf);
+ else
+ printf_unfiltered ("Working directory %s.\n", current_directory);
+}
+
+void
+cd_command (dir, from_tty)
+ char *dir;
+ int from_tty;
+{
+ int len;
+ /* Found something other than leading repetitions of "/..". */
+ int found_real_path;
+ char *p;
+
+ /* If the new directory is absolute, repeat is a no-op; if relative,
+ repeat might be useful but is more likely to be a mistake. */
+ dont_repeat ();
+
+ if (dir == 0)
+ error_no_arg ("new working directory");
+
+ dir = tilde_expand (dir);
+ make_cleanup (free, dir);
+
+ if (chdir (dir) < 0)
+ perror_with_name (dir);
+
+ len = strlen (dir);
+ dir = savestring (dir, len - (len > 1 && dir[len-1] == '/'));
+ if (dir[0] == '/')
+ current_directory = dir;
+ else
+ {
+ if (current_directory[0] == '/' && current_directory[1] == '\0')
+ current_directory = concat (current_directory, dir, NULL);
+ else
+ current_directory = concat (current_directory, "/", dir, NULL);
+ free (dir);
+ }
+
+ /* Now simplify any occurrences of `.' and `..' in the pathname. */
+
+ found_real_path = 0;
+ for (p = current_directory; *p;)
+ {
+ if (p[0] == '/' && p[1] == '.' && (p[2] == 0 || p[2] == '/'))
+ strcpy (p, p + 2);
+ else if (p[0] == '/' && p[1] == '.' && p[2] == '.'
+ && (p[3] == 0 || p[3] == '/'))
+ {
+ if (found_real_path)
+ {
+ /* Search backwards for the directory just before the "/.."
+ and obliterate it and the "/..". */
+ char *q = p;
+ while (q != current_directory && q[-1] != '/')
+ --q;
+
+ if (q == current_directory)
+ /* current_directory is
+ a relative pathname ("can't happen"--leave it alone). */
+ ++p;
+ else
+ {
+ strcpy (q - 1, p + 3);
+ p = q - 1;
+ }
+ }
+ else
+ /* We are dealing with leading repetitions of "/..", for example
+ "/../..", which is the Mach super-root. */
+ p += 3;
+ }
+ else
+ {
+ found_real_path = 1;
+ ++p;
+ }
+ }
+
+ forget_cached_source_info ();
+
+ if (from_tty)
+ pwd_command ((char *) 0, 1);
+}
+
+struct source_cleanup_lines_args {
+ int old_line;
+ char *old_file;
+ char *old_pre_error;
+ char *old_error_pre_print;
+};
+
+static void
+source_cleanup_lines (args)
+ PTR args;
+{
+ struct source_cleanup_lines_args *p =
+ (struct source_cleanup_lines_args *)args;
+ source_line_number = p->old_line;
+ source_file_name = p->old_file;
+ source_pre_error = p->old_pre_error;
+ error_pre_print = p->old_error_pre_print;
+}
+
+/* ARGSUSED */
+void
+source_command (args, from_tty)
+ char *args;
+ int from_tty;
+{
+ FILE *stream;
+ struct cleanup *old_cleanups;
+ char *file = args;
+ struct source_cleanup_lines_args old_lines;
+ int needed_length;
+
+ if (file == NULL)
+ {
+ error ("source command requires pathname of file to source.");
+ }
+
+ file = tilde_expand (file);
+ old_cleanups = make_cleanup (free, file);
+
+ stream = fopen (file, FOPEN_RT);
+ if (stream == 0)
+ perror_with_name (file);
+
+ make_cleanup (fclose, stream);
+
+ old_lines.old_line = source_line_number;
+ old_lines.old_file = source_file_name;
+ old_lines.old_pre_error = source_pre_error;
+ old_lines.old_error_pre_print = error_pre_print;
+ make_cleanup (source_cleanup_lines, &old_lines);
+ source_line_number = 0;
+ source_file_name = file;
+ source_pre_error = error_pre_print == NULL ? "" : error_pre_print;
+ source_pre_error = savestring (source_pre_error, strlen (source_pre_error));
+ make_cleanup (free, source_pre_error);
+ /* This will get set every time we read a line. So it won't stay "" for
+ long. */
+ error_pre_print = "";
+
+ needed_length = strlen (source_file_name) + strlen (source_pre_error) + 80;
+ if (source_error_allocated < needed_length)
+ {
+ source_error_allocated *= 2;
+ if (source_error_allocated < needed_length)
+ source_error_allocated = needed_length;
+ if (source_error == NULL)
+ source_error = xmalloc (source_error_allocated);
+ else
+ source_error = xrealloc (source_error, source_error_allocated);
+ }
+
+ read_command_file (stream);
+
+ do_cleanups (old_cleanups);
+}
+
+/* ARGSUSED */
+static void
+echo_command (text, from_tty)
+ char *text;
+ int from_tty;
+{
+ char *p = text;
+ register int c;
+
+ if (text)
+ while ((c = *p++) != '\0')
+ {
+ if (c == '\\')
+ {
+ /* \ at end of argument is used after spaces
+ so they won't be lost. */
+ if (*p == 0)
+ return;
+
+ c = parse_escape (&p);
+ if (c >= 0)
+ printf_filtered ("%c", c);
+ }
+ else
+ printf_filtered ("%c", c);
+ }
+
+ /* Force this output to appear now. */
+ wrap_here ("");
+ gdb_flush (gdb_stdout);
+}
+
+
+/* Functions to manipulate command line editing control variables. */
+
+/* Number of commands to print in each call to show_commands. */
+#define Hist_print 10
+static void
+show_commands (args, from_tty)
+ char *args;
+ int from_tty;
+{
+ /* Index for history commands. Relative to history_base. */
+ int offset;
+
+ /* Number of the history entry which we are planning to display next.
+ Relative to history_base. */
+ static int num = 0;
+
+ /* The first command in the history which doesn't exist (i.e. one more
+ than the number of the last command). Relative to history_base. */
+ int hist_len;
+
+ extern HIST_ENTRY *history_get PARAMS ((int));
+
+ /* Print out some of the commands from the command history. */
+ /* First determine the length of the history list. */
+ hist_len = history_size;
+ for (offset = 0; offset < history_size; offset++)
+ {
+ if (!history_get (history_base + offset))
+ {
+ hist_len = offset;
+ break;
+ }
+ }
+
+ if (args)
+ {
+ if (args[0] == '+' && args[1] == '\0')
+ /* "info editing +" should print from the stored position. */
+ ;
+ else
+ /* "info editing <exp>" should print around command number <exp>. */
+ num = (parse_and_eval_address (args) - history_base) - Hist_print / 2;
+ }
+ /* "show commands" means print the last Hist_print commands. */
+ else
+ {
+ num = hist_len - Hist_print;
+ }
+
+ if (num < 0)
+ num = 0;
+
+ /* If there are at least Hist_print commands, we want to display the last
+ Hist_print rather than, say, the last 6. */
+ if (hist_len - num < Hist_print)
+ {
+ num = hist_len - Hist_print;
+ if (num < 0)
+ num = 0;
+ }
+
+ for (offset = num; offset < num + Hist_print && offset < hist_len; offset++)
+ {
+ printf_filtered ("%5d %s\n", history_base + offset,
+ (history_get (history_base + offset))->line);
+ }
+
+ /* The next command we want to display is the next one that we haven't
+ displayed yet. */
+ num += Hist_print;
+
+ /* If the user repeats this command with return, it should do what
+ "show commands +" does. This is unnecessary if arg is null,
+ because "show commands +" is not useful after "show commands". */
+ if (from_tty && args)
+ {
+ args[0] = '+';
+ args[1] = '\0';
+ }
+}
+
+/* Called by do_setshow_command. */
+/* ARGSUSED */
+static void
+set_history_size_command (args, from_tty, c)
+ char *args;
+ int from_tty;
+ struct cmd_list_element *c;
+{
+ if (history_size == INT_MAX)
+ unstifle_history ();
+ else if (history_size >= 0)
+ stifle_history (history_size);
+ else
+ {
+ history_size = INT_MAX;
+ error ("History size must be non-negative");
+ }
+}
+
+/* ARGSUSED */
+static void
+set_history (args, from_tty)
+ char *args;
+ int from_tty;
+{
+ printf_unfiltered ("\"set history\" must be followed by the name of a history subcommand.\n");
+ help_list (sethistlist, "set history ", -1, gdb_stdout);
+}
+
+/* ARGSUSED */
+static void
+show_history (args, from_tty)
+ char *args;
+ int from_tty;
+{
+ cmd_show_list (showhistlist, from_tty, "");
+}
+
+int info_verbose = 0; /* Default verbose msgs off */
+
+/* Called by do_setshow_command. An elaborate joke. */
+/* ARGSUSED */
+static void
+set_verbose (args, from_tty, c)
+ char *args;
+ int from_tty;
+ struct cmd_list_element *c;
+{
+ char *cmdname = "verbose";
+ struct cmd_list_element *showcmd;
+
+ showcmd = lookup_cmd_1 (&cmdname, showlist, NULL, 1);
+
+ if (info_verbose)
+ {
+ c->doc = "Set verbose printing of informational messages.";
+ showcmd->doc = "Show verbose printing of informational messages.";
+ }
+ else
+ {
+ c->doc = "Set verbosity.";
+ showcmd->doc = "Show verbosity.";
+ }
+}
+
+static void
+float_handler (signo)
+int signo;
+{
+ /* This message is based on ANSI C, section 4.7. Note that integer
+ divide by zero causes this, so "float" is a misnomer. */
+ signal (SIGFPE, float_handler);
+ error ("Erroneous arithmetic operation.");
+}
+
+
+static void
+init_cmd_lists ()
+{
+ cmdlist = NULL;
+ infolist = NULL;
+ enablelist = NULL;
+ disablelist = NULL;
+ deletelist = NULL;
+ enablebreaklist = NULL;
+ setlist = NULL;
+ unsetlist = NULL;
+ showlist = NULL;
+ sethistlist = NULL;
+ showhistlist = NULL;
+ unsethistlist = NULL;
+#if MAINTENANCE_CMDS
+ maintenancelist = NULL;
+ maintenanceinfolist = NULL;
+ maintenanceprintlist = NULL;
+#endif
+ setprintlist = NULL;
+ showprintlist = NULL;
+ setchecklist = NULL;
+ showchecklist = NULL;
+}
+
+/* Init the history buffer. Note that we are called after the init file(s)
+ * have been read so that the user can change the history file via his
+ * .gdbinit file (for instance). The GDBHISTFILE environment variable
+ * overrides all of this.
+ */
+
+void
+init_history()
+{
+ char *tmpenv;
+
+ tmpenv = getenv ("HISTSIZE");
+ if (tmpenv)
+ history_size = atoi (tmpenv);
+ else if (!history_size)
+ history_size = 256;
+
+ stifle_history (history_size);
+
+ tmpenv = getenv ("GDBHISTFILE");
+ if (tmpenv)
+ history_filename = savestring (tmpenv, strlen(tmpenv));
+ else if (!history_filename) {
+ /* We include the current directory so that if the user changes
+ directories the file written will be the same as the one
+ that was read. */
+ history_filename = concat (current_directory, "/.gdb_history", NULL);
+ }
+ read_history (history_filename);
+}
+
+static void
+init_main ()
+{
+ struct cmd_list_element *c;
+
+#ifdef DEFAULT_PROMPT
+ prompt = savestring (DEFAULT_PROMPT, strlen(DEFAULT_PROMPT));
+#else
+ prompt = savestring ("(gdb) ", 6);
+#endif
+#ifdef KERNEL_DEBUG
+ if (kernel_debugging)
+ prompt = savestring ("(kgdb) ", 7);
+#endif
+
+ /* Set the important stuff up for command editing. */
+ command_editing_p = 1;
+ history_expansion_p = 0;
+ write_history_p = 0;
+
+ /* Setup important stuff for command line editing. */
+ rl_completion_entry_function = (int (*)()) symbol_completion_function;
+ rl_completer_word_break_characters = gdb_completer_word_break_characters;
+ rl_completer_quote_characters = gdb_completer_quote_characters;
+ rl_readline_name = "gdb";
+
+ /* Define the classes of commands.
+ They will appear in the help list in the reverse of this order. */
+
+ add_cmd ("internals", class_maintenance, NO_FUNCTION,
+ "Maintenance commands.\n\
+Some gdb commands are provided just for use by gdb maintainers.\n\
+These commands are subject to frequent change, and may not be as\n\
+well documented as user commands.",
+ &cmdlist);
+ add_cmd ("obscure", class_obscure, NO_FUNCTION, "Obscure features.", &cmdlist);
+ add_cmd ("aliases", class_alias, NO_FUNCTION, "Aliases of other commands.", &cmdlist);
+ add_cmd ("user-defined", class_user, NO_FUNCTION, "User-defined commands.\n\
+The commands in this class are those defined by the user.\n\
+Use the \"define\" command to define a command.", &cmdlist);
+ add_cmd ("support", class_support, NO_FUNCTION, "Support facilities.", &cmdlist);
+ add_cmd ("status", class_info, NO_FUNCTION, "Status inquiries.", &cmdlist);
+ add_cmd ("files", class_files, NO_FUNCTION, "Specifying and examining files.", &cmdlist);
+ add_cmd ("breakpoints", class_breakpoint, NO_FUNCTION, "Making program stop at certain points.", &cmdlist);
+ add_cmd ("data", class_vars, NO_FUNCTION, "Examining data.", &cmdlist);
+ add_cmd ("stack", class_stack, NO_FUNCTION, "Examining the stack.\n\
+The stack is made up of stack frames. Gdb assigns numbers to stack frames\n\
+counting from zero for the innermost (currently executing) frame.\n\n\
+At any time gdb identifies one frame as the \"selected\" frame.\n\
+Variable lookups are done with respect to the selected frame.\n\
+When the program being debugged stops, gdb selects the innermost frame.\n\
+The commands below can be used to select other frames by number or address.",
+ &cmdlist);
+ add_cmd ("running", class_run, NO_FUNCTION, "Running the program.", &cmdlist);
+
+ add_com ("pwd", class_files, pwd_command,
+ "Print working directory. This is used for your program as well.");
+ c = add_cmd ("cd", class_files, cd_command,
+ "Set working directory to DIR for debugger and program being debugged.\n\
+The change does not take effect for the program being debugged\n\
+until the next time it is started.", &cmdlist);
+ c->completer = filename_completer;
+
+ add_show_from_set
+ (add_set_cmd ("prompt", class_support, var_string, (char *)&prompt,
+ "Set gdb's prompt",
+ &setlist),
+ &showlist);
+
+ add_com ("echo", class_support, echo_command,
+ "Print a constant string. Give string as argument.\n\
+C escape sequences may be used in the argument.\n\
+No newline is added at the end of the argument;\n\
+use \"\\n\" if you want a newline to be printed.\n\
+Since leading and trailing whitespace are ignored in command arguments,\n\
+if you want to print some you must use \"\\\" before leading whitespace\n\
+to be printed or after trailing whitespace.");
+ add_com ("document", class_support, document_command,
+ "Document a user-defined command.\n\
+Give command name as argument. Give documentation on following lines.\n\
+End with a line of just \"end\".");
+ add_com ("define", class_support, define_command,
+ "Define a new command name. Command name is argument.\n\
+Definition appears on following lines, one command per line.\n\
+End with a line of just \"end\".\n\
+Use the \"document\" command to give documentation for the new command.\n\
+Commands defined in this way do not take arguments.");
+
+#ifdef __STDC__
+ c = add_cmd ("source", class_support, source_command,
+ "Read commands from a file named FILE.\n\
+Note that the file \"" GDBINIT_FILENAME "\" is read automatically in this way\n\
+when gdb is started.", &cmdlist);
+#else
+ /* Punt file name, we can't help it easily. */
+ c = add_cmd ("source", class_support, source_command,
+ "Read commands from a file named FILE.\n\
+Note that the file \".gdbinit\" is read automatically in this way\n\
+when gdb is started.", &cmdlist);
+#endif
+ c->completer = filename_completer;
+
+ add_com ("quit", class_support, quit_command, "Exit gdb.");
+ add_com ("help", class_support, help_command, "Print list of commands.");
+ add_com_alias ("q", "quit", class_support, 1);
+ add_com_alias ("h", "help", class_support, 1);
+
+
+ c = add_set_cmd ("verbose", class_support, var_boolean, (char *)&info_verbose,
+ "Set ",
+ &setlist),
+ add_show_from_set (c, &showlist);
+ c->function.sfunc = set_verbose;
+ set_verbose (NULL, 0, c);
+
+ add_show_from_set
+ (add_set_cmd ("editing", class_support, var_boolean, (char *)&command_editing_p,
+ "Set editing of command lines as they are typed.\n\
+Use \"on\" to enable to enable the editing, and \"off\" to disable it.\n\
+Without an argument, command line editing is enabled. To edit, use\n\
+EMACS-like or VI-like commands like control-P or ESC.", &setlist),
+ &showlist);
+
+ add_prefix_cmd ("history", class_support, set_history,
+ "Generic command for setting command history parameters.",
+ &sethistlist, "set history ", 0, &setlist);
+ add_prefix_cmd ("history", class_support, show_history,
+ "Generic command for showing command history parameters.",
+ &showhistlist, "show history ", 0, &showlist);
+
+ add_show_from_set
+ (add_set_cmd ("expansion", no_class, var_boolean, (char *)&history_expansion_p,
+ "Set history expansion on command input.\n\
+Without an argument, history expansion is enabled.", &sethistlist),
+ &showhistlist);
+
+ add_show_from_set
+ (add_set_cmd ("save", no_class, var_boolean, (char *)&write_history_p,
+ "Set saving of the history record on exit.\n\
+Use \"on\" to enable to enable the saving, and \"off\" to disable it.\n\
+Without an argument, saving is enabled.", &sethistlist),
+ &showhistlist);
+
+ c = add_set_cmd ("size", no_class, var_integer, (char *)&history_size,
+ "Set the size of the command history, \n\
+ie. the number of previous commands to keep a record of.", &sethistlist);
+ add_show_from_set (c, &showhistlist);
+ c->function.sfunc = set_history_size_command;
+
+ add_show_from_set
+ (add_set_cmd ("filename", no_class, var_filename, (char *)&history_filename,
+ "Set the filename in which to record the command history\n\
+ (the list of previous commands of which a record is kept).", &sethistlist),
+ &showhistlist);
+
+ add_show_from_set
+ (add_set_cmd ("confirm", class_support, var_boolean,
+ (char *)&caution,
+ "Set whether to confirm potentially dangerous operations.",
+ &setlist),
+ &showlist);
+
+ add_prefix_cmd ("info", class_info, info_command,
+ "Generic command for showing things about the program being debugged.",
+ &infolist, "info ", 0, &cmdlist);
+ add_com_alias ("i", "info", class_info, 1);
+
+ add_com ("complete", class_obscure, complete_command,
+ "List the completions for the rest of the line as a command.");
+
+ add_prefix_cmd ("show", class_info, show_command,
+ "Generic command for showing things about the debugger.",
+ &showlist, "show ", 0, &cmdlist);
+ /* Another way to get at the same thing. */
+ add_info ("set", show_command, "Show all GDB settings.");
+
+ add_cmd ("commands", no_class, show_commands,
+ "Show the the history of commands you typed.\n\
+You can supply a command number to start with, or a `+' to start after\n\
+the previous command number shown.",
+ &showlist);
+
+ add_cmd ("version", no_class, show_version,
+ "Show what version of GDB this is.", &showlist);
+
+ /* If target is open when baud changes, it doesn't take effect until the
+ next open (I think, not sure). */
+ add_show_from_set (add_set_cmd ("remotebaud", no_class,
+ var_zinteger, (char *)&baud_rate,
+ "Set baud rate for remote serial I/O.\n\
+This value is used to set the speed of the serial port when debugging\n\
+using remote targets.", &setlist),
+ &showlist);
+
+ add_show_from_set (
+ add_set_cmd ("remotedebug", no_class, var_zinteger, (char *)&remote_debug,
+ "Set debugging of remote protocol.\n\
+When enabled, each packet sent or received with the remote target\n\
+is displayed.", &setlist),
+ &showlist);
+}
diff --git a/gnu/usr.bin/gdb/gdb/top.h b/gnu/usr.bin/gdb/gdb/top.h
new file mode 100644
index 0000000..6ae28a2
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/top.h
@@ -0,0 +1,48 @@
+/* Top level stuff for GDB, the GNU debugger.
+ Copyright 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994
+ Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* From top.c. */
+extern char *line;
+extern int linesize;
+extern FILE *instream;
+extern char gdb_dirbuf[1024];
+extern int inhibit_gdbinit;
+extern int epoch_interface;
+extern char gdbinit[];
+
+/* Generally one should use catch_errors rather than manipulating these
+ directly. The exception is main(). */
+extern jmp_buf error_return;
+extern jmp_buf quit_return;
+
+extern void print_gdb_version PARAMS ((GDB_FILE *));
+extern void print_gnu_advertisement PARAMS ((void));
+
+extern void source_command PARAMS ((char *, int));
+extern void cd_command PARAMS ((char *, int));
+extern void read_command_file PARAMS ((FILE *));
+extern void init_history PARAMS ((void));
+extern void command_loop PARAMS ((void));
+extern void quit_command PARAMS ((char *, int));
+
+/* From random places. */
+extern int mapped_symbol_files;
+extern int readnow_symbol_files;
+#define ALL_CLEANUPS ((struct cleanup *)0)
diff --git a/gnu/usr.bin/gdb/gdb/typeprint.c b/gnu/usr.bin/gdb/gdb/typeprint.c
new file mode 100644
index 0000000..785ec61
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/typeprint.c
@@ -0,0 +1,297 @@
+/* Language independent support for printing types for GDB, the GNU debugger.
+ Copyright 1986, 1988, 1989, 1991, 1992, 1993 Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "defs.h"
+#include "obstack.h"
+#include "bfd.h" /* Binary File Description */
+#include "symtab.h"
+#include "gdbtypes.h"
+#include "expression.h"
+#include "value.h"
+#include "gdbcore.h"
+#include "command.h"
+#include "gdbcmd.h"
+#include "target.h"
+#include "language.h"
+#include "demangle.h"
+
+#include <string.h>
+#include <errno.h>
+
+static void
+ptype_command PARAMS ((char *, int));
+
+static struct type *
+ptype_eval PARAMS ((struct expression *));
+
+static void
+whatis_command PARAMS ((char *, int));
+
+static void
+whatis_exp PARAMS ((char *, int));
+
+/* Print a description of a type TYPE in the form of a declaration of a
+ variable named VARSTRING. (VARSTRING is demangled if necessary.)
+ Output goes to STREAM (via stdio).
+ If SHOW is positive, we show the contents of the outermost level
+ of structure even if there is a type name that could be used instead.
+ If SHOW is negative, we never show the details of elements' types. */
+
+void
+type_print (type, varstring, stream, show)
+ struct type *type;
+ char *varstring;
+ GDB_FILE *stream;
+ int show;
+{
+ LA_PRINT_TYPE (type, varstring, stream, show, 0);
+}
+
+/* Print type of EXP, or last thing in value history if EXP == NULL.
+ show is passed to type_print. */
+
+static void
+whatis_exp (exp, show)
+ char *exp;
+ int show;
+{
+ struct expression *expr;
+ register value_ptr val;
+ register struct cleanup *old_chain = NULL;
+
+ if (exp)
+ {
+ expr = parse_expression (exp);
+ old_chain = make_cleanup (free_current_contents, &expr);
+ val = evaluate_type (expr);
+ }
+ else
+ val = access_value_history (0);
+
+ printf_filtered ("type = ");
+ type_print (VALUE_TYPE (val), "", gdb_stdout, show);
+ printf_filtered ("\n");
+
+ if (exp)
+ do_cleanups (old_chain);
+}
+
+/* ARGSUSED */
+static void
+whatis_command (exp, from_tty)
+ char *exp;
+ int from_tty;
+{
+ /* Most of the time users do not want to see all the fields
+ in a structure. If they do they can use the "ptype" command.
+ Hence the "-1" below. */
+ whatis_exp (exp, -1);
+}
+
+/* Simple subroutine for ptype_command. */
+
+static struct type *
+ptype_eval (exp)
+ struct expression *exp;
+{
+ if (exp->elts[0].opcode == OP_TYPE)
+ {
+ return (exp->elts[1].type);
+ }
+ else
+ {
+ return (NULL);
+ }
+}
+
+/* TYPENAME is either the name of a type, or an expression. */
+
+/* ARGSUSED */
+static void
+ptype_command (typename, from_tty)
+ char *typename;
+ int from_tty;
+{
+ register struct type *type;
+ struct expression *expr;
+ register struct cleanup *old_chain;
+
+ if (typename == NULL)
+ {
+ /* Print type of last thing in value history. */
+ whatis_exp (typename, 1);
+ }
+ else
+ {
+ expr = parse_expression (typename);
+ old_chain = make_cleanup (free_current_contents, &expr);
+ type = ptype_eval (expr);
+ if (type != NULL)
+ {
+ /* User did "ptype <typename>" */
+ printf_filtered ("type = ");
+ type_print (type, "", gdb_stdout, 1);
+ printf_filtered ("\n");
+ do_cleanups (old_chain);
+ }
+ else
+ {
+ /* User did "ptype <symbolname>" */
+ do_cleanups (old_chain);
+ whatis_exp (typename, 1);
+ }
+ }
+}
+
+/* Print integral scalar data VAL, of type TYPE, onto stdio stream STREAM.
+ Used to print data from type structures in a specified type. For example,
+ array bounds may be characters or booleans in some languages, and this
+ allows the ranges to be printed in their "natural" form rather than as
+ decimal integer values.
+
+ FIXME: This is here simply because only the type printing routines
+ currently use it, and it wasn't clear if it really belonged somewhere
+ else (like printcmd.c). There are a lot of other gdb routines that do
+ something similar, but they are generally concerned with printing values
+ that come from the inferior in target byte order and target size. */
+
+void
+print_type_scalar (type, val, stream)
+ struct type *type;
+ LONGEST val;
+ GDB_FILE *stream;
+{
+ unsigned int i;
+ unsigned len;
+
+ switch (TYPE_CODE (type))
+ {
+
+ case TYPE_CODE_ENUM:
+ len = TYPE_NFIELDS (type);
+ for (i = 0; i < len; i++)
+ {
+ if (TYPE_FIELD_BITPOS (type, i) == val)
+ {
+ break;
+ }
+ }
+ if (i < len)
+ {
+ fputs_filtered (TYPE_FIELD_NAME (type, i), stream);
+ }
+ else
+ {
+ print_longest (stream, 'd', 0, val);
+ }
+ break;
+
+ case TYPE_CODE_INT:
+ print_longest (stream, TYPE_UNSIGNED (type) ? 'u' : 'd', 0, val);
+ break;
+
+ case TYPE_CODE_CHAR:
+ LA_PRINT_CHAR ((unsigned char) val, stream);
+ break;
+
+ case TYPE_CODE_BOOL:
+ fprintf_filtered (stream, val ? "TRUE" : "FALSE");
+ break;
+
+ case TYPE_CODE_UNDEF:
+ case TYPE_CODE_PTR:
+ case TYPE_CODE_ARRAY:
+ case TYPE_CODE_STRUCT:
+ case TYPE_CODE_UNION:
+ case TYPE_CODE_FUNC:
+ case TYPE_CODE_FLT:
+ case TYPE_CODE_VOID:
+ case TYPE_CODE_SET:
+ case TYPE_CODE_RANGE:
+ case TYPE_CODE_STRING:
+ case TYPE_CODE_ERROR:
+ case TYPE_CODE_MEMBER:
+ case TYPE_CODE_METHOD:
+ case TYPE_CODE_REF:
+ error ("internal error: unhandled type in print_type_scalar");
+ break;
+
+ default:
+ error ("Invalid type code in symbol table.");
+ }
+ gdb_flush (stream);
+}
+
+#if MAINTENANCE_CMDS
+
+/* Dump details of a type specified either directly or indirectly.
+ Uses the same sort of type lookup mechanism as ptype_command()
+ and whatis_command(). */
+
+void
+maintenance_print_type (typename, from_tty)
+ char *typename;
+ int from_tty;
+{
+ register value_ptr val;
+ register struct type *type;
+ register struct cleanup *old_chain;
+ struct expression *expr;
+
+ if (typename != NULL)
+ {
+ expr = parse_expression (typename);
+ old_chain = make_cleanup (free_current_contents, &expr);
+ if (expr -> elts[0].opcode == OP_TYPE)
+ {
+ /* The user expression names a type directly, just use that type. */
+ type = expr -> elts[1].type;
+ }
+ else
+ {
+ /* The user expression may name a type indirectly by naming an
+ object of that type. Find that indirectly named type. */
+ val = evaluate_type (expr);
+ type = VALUE_TYPE (val);
+ }
+ if (type != NULL)
+ {
+ recursive_dump_type (type, 0);
+ }
+ do_cleanups (old_chain);
+ }
+}
+
+#endif /* MAINTENANCE_CMDS */
+
+
+void
+_initialize_typeprint ()
+{
+
+ add_com ("ptype", class_vars, ptype_command,
+ "Print definition of type TYPE.\n\
+Argument may be a type name defined by typedef, or \"struct STRUCT-TAG\"\n\
+or \"class CLASS-NAME\" or \"union UNION-TAG\" or \"enum ENUM-TAG\".\n\
+The selected stack frame's lexical context is used to look up the name.");
+
+ add_com ("whatis", class_vars, whatis_command,
+ "Print data type of expression EXP.");
+
+}
diff --git a/gnu/usr.bin/gdb/gdb/typeprint.h b/gnu/usr.bin/gdb/gdb/typeprint.h
new file mode 100644
index 0000000..eead5f6
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/typeprint.h
@@ -0,0 +1,21 @@
+/* Language independent support for printing types for GDB, the GNU debugger.
+ Copyright 1986, 1988, 1989, 1991, 1992, 1993 Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+void
+print_type_scalar PARAMS ((struct type *type, LONGEST, GDB_FILE *));
diff --git a/gnu/usr.bin/gdb/gdb/utils.c b/gnu/usr.bin/gdb/gdb/utils.c
new file mode 100644
index 0000000..5749013
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/utils.c
@@ -0,0 +1,1790 @@
+/* General utility routines for GDB, the GNU debugger.
+ Copyright 1986, 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "defs.h"
+#if !defined(__GO32__)
+#include <sys/ioctl.h>
+#include <sys/param.h>
+#include <pwd.h>
+#endif
+#include <varargs.h>
+#include <ctype.h>
+#include <string.h>
+
+#include "signals.h"
+#include "gdbcmd.h"
+#include "serial.h"
+#include "bfd.h"
+#include "target.h"
+#include "demangle.h"
+#include "expression.h"
+#include "language.h"
+#include "annotate.h"
+
+#include "readline.h"
+
+/* readline defines this. */
+#undef savestring
+
+/* Prototypes for local functions */
+
+#if defined (NO_MMALLOC) || defined (NO_MMALLOC_CHECK)
+#else
+
+static void
+malloc_botch PARAMS ((void));
+
+#endif /* NO_MMALLOC, etc */
+
+static void
+fatal_dump_core (); /* Can't prototype with <varargs.h> usage... */
+
+static void
+prompt_for_continue PARAMS ((void));
+
+static void
+set_width_command PARAMS ((char *, int, struct cmd_list_element *));
+
+/* If this definition isn't overridden by the header files, assume
+ that isatty and fileno exist on this system. */
+#ifndef ISATTY
+#define ISATTY(FP) (isatty (fileno (FP)))
+#endif
+
+/* Chain of cleanup actions established with make_cleanup,
+ to be executed if an error happens. */
+
+static struct cleanup *cleanup_chain;
+
+/* Nonzero if we have job control. */
+
+int job_control;
+
+/* Nonzero means a quit has been requested. */
+
+int quit_flag;
+
+/* Nonzero means quit immediately if Control-C is typed now, rather
+ than waiting until QUIT is executed. Be careful in setting this;
+ code which executes with immediate_quit set has to be very careful
+ about being able to deal with being interrupted at any time. It is
+ almost always better to use QUIT; the only exception I can think of
+ is being able to quit out of a system call (using EINTR loses if
+ the SIGINT happens between the previous QUIT and the system call).
+ To immediately quit in the case in which a SIGINT happens between
+ the previous QUIT and setting immediate_quit (desirable anytime we
+ expect to block), call QUIT after setting immediate_quit. */
+
+int immediate_quit;
+
+/* Nonzero means that encoded C++ names should be printed out in their
+ C++ form rather than raw. */
+
+int demangle = 1;
+
+/* Nonzero means that encoded C++ names should be printed out in their
+ C++ form even in assembler language displays. If this is set, but
+ DEMANGLE is zero, names are printed raw, i.e. DEMANGLE controls. */
+
+int asm_demangle = 0;
+
+/* Nonzero means that strings with character values >0x7F should be printed
+ as octal escapes. Zero means just print the value (e.g. it's an
+ international character, and the terminal or window can cope.) */
+
+int sevenbit_strings = 0;
+
+/* String to be printed before error messages, if any. */
+
+char *error_pre_print;
+char *warning_pre_print = "\nwarning: ";
+
+/* Add a new cleanup to the cleanup_chain,
+ and return the previous chain pointer
+ to be passed later to do_cleanups or discard_cleanups.
+ Args are FUNCTION to clean up with, and ARG to pass to it. */
+
+struct cleanup *
+make_cleanup (function, arg)
+ void (*function) PARAMS ((PTR));
+ PTR arg;
+{
+ register struct cleanup *new
+ = (struct cleanup *) xmalloc (sizeof (struct cleanup));
+ register struct cleanup *old_chain = cleanup_chain;
+
+ new->next = cleanup_chain;
+ new->function = function;
+ new->arg = arg;
+ cleanup_chain = new;
+
+ return old_chain;
+}
+
+/* Discard cleanups and do the actions they describe
+ until we get back to the point OLD_CHAIN in the cleanup_chain. */
+
+void
+do_cleanups (old_chain)
+ register struct cleanup *old_chain;
+{
+ register struct cleanup *ptr;
+ while ((ptr = cleanup_chain) != old_chain)
+ {
+ cleanup_chain = ptr->next; /* Do this first incase recursion */
+ (*ptr->function) (ptr->arg);
+ free (ptr);
+ }
+}
+
+/* Discard cleanups, not doing the actions they describe,
+ until we get back to the point OLD_CHAIN in the cleanup_chain. */
+
+void
+discard_cleanups (old_chain)
+ register struct cleanup *old_chain;
+{
+ register struct cleanup *ptr;
+ while ((ptr = cleanup_chain) != old_chain)
+ {
+ cleanup_chain = ptr->next;
+ free ((PTR)ptr);
+ }
+}
+
+/* Set the cleanup_chain to 0, and return the old cleanup chain. */
+struct cleanup *
+save_cleanups ()
+{
+ struct cleanup *old_chain = cleanup_chain;
+
+ cleanup_chain = 0;
+ return old_chain;
+}
+
+/* Restore the cleanup chain from a previously saved chain. */
+void
+restore_cleanups (chain)
+ struct cleanup *chain;
+{
+ cleanup_chain = chain;
+}
+
+/* This function is useful for cleanups.
+ Do
+
+ foo = xmalloc (...);
+ old_chain = make_cleanup (free_current_contents, &foo);
+
+ to arrange to free the object thus allocated. */
+
+void
+free_current_contents (location)
+ char **location;
+{
+ free (*location);
+}
+
+/* Provide a known function that does nothing, to use as a base for
+ for a possibly long chain of cleanups. This is useful where we
+ use the cleanup chain for handling normal cleanups as well as dealing
+ with cleanups that need to be done as a result of a call to error().
+ In such cases, we may not be certain where the first cleanup is, unless
+ we have a do-nothing one to always use as the base. */
+
+/* ARGSUSED */
+void
+null_cleanup (arg)
+ char **arg;
+{
+}
+
+
+/* Provide a hook for modules wishing to print their own warning messages
+ to set up the terminal state in a compatible way, without them having
+ to import all the target_<...> macros. */
+
+void
+warning_setup ()
+{
+ target_terminal_ours ();
+ wrap_here(""); /* Force out any buffered output */
+ gdb_flush (gdb_stdout);
+}
+
+/* Print a warning message.
+ The first argument STRING is the warning message, used as a fprintf string,
+ and the remaining args are passed as arguments to it.
+ The primary difference between warnings and errors is that a warning
+ does not force the return to command level. */
+
+/* VARARGS */
+void
+warning (va_alist)
+ va_dcl
+{
+ va_list args;
+ char *string;
+
+ va_start (args);
+ target_terminal_ours ();
+ wrap_here(""); /* Force out any buffered output */
+ gdb_flush (gdb_stdout);
+ if (warning_pre_print)
+ fprintf_unfiltered (gdb_stderr, warning_pre_print);
+ string = va_arg (args, char *);
+ vfprintf_unfiltered (gdb_stderr, string, args);
+ fprintf_unfiltered (gdb_stderr, "\n");
+ va_end (args);
+}
+
+/* Start the printing of an error message. Way to use this is to call
+ this, output the error message (use filtered output), and then call
+ return_to_top_level (RETURN_ERROR). error() provides a convenient way to
+ do this for the special case that the error message can be formatted with
+ a single printf call, but this is more general. */
+void
+error_begin ()
+{
+ target_terminal_ours ();
+ wrap_here (""); /* Force out any buffered output */
+ gdb_flush (gdb_stdout);
+
+ annotate_error_begin ();
+
+ if (error_pre_print)
+ fprintf_filtered (gdb_stderr, error_pre_print);
+}
+
+/* Print an error message and return to command level.
+ The first argument STRING is the error message, used as a fprintf string,
+ and the remaining args are passed as arguments to it. */
+
+/* VARARGS */
+NORETURN void
+error (va_alist)
+ va_dcl
+{
+ va_list args;
+ char *string;
+
+ error_begin ();
+ va_start (args);
+ string = va_arg (args, char *);
+ vfprintf_filtered (gdb_stderr, string, args);
+ fprintf_filtered (gdb_stderr, "\n");
+ va_end (args);
+ return_to_top_level (RETURN_ERROR);
+}
+
+/* Print an error message and exit reporting failure.
+ This is for a error that we cannot continue from.
+ The arguments are printed a la printf.
+
+ This function cannot be declared volatile (NORETURN) in an
+ ANSI environment because exit() is not declared volatile. */
+
+/* VARARGS */
+NORETURN void
+fatal (va_alist)
+ va_dcl
+{
+ va_list args;
+ char *string;
+
+ va_start (args);
+ string = va_arg (args, char *);
+ fprintf_unfiltered (gdb_stderr, "\ngdb: ");
+ vfprintf_unfiltered (gdb_stderr, string, args);
+ fprintf_unfiltered (gdb_stderr, "\n");
+ va_end (args);
+ exit (1);
+}
+
+/* Print an error message and exit, dumping core.
+ The arguments are printed a la printf (). */
+
+/* VARARGS */
+static void
+fatal_dump_core (va_alist)
+ va_dcl
+{
+ va_list args;
+ char *string;
+
+ va_start (args);
+ string = va_arg (args, char *);
+ /* "internal error" is always correct, since GDB should never dump
+ core, no matter what the input. */
+ fprintf_unfiltered (gdb_stderr, "\ngdb internal error: ");
+ vfprintf_unfiltered (gdb_stderr, string, args);
+ fprintf_unfiltered (gdb_stderr, "\n");
+ va_end (args);
+
+ signal (SIGQUIT, SIG_DFL);
+ kill (getpid (), SIGQUIT);
+ /* We should never get here, but just in case... */
+ exit (1);
+}
+
+/* The strerror() function can return NULL for errno values that are
+ out of range. Provide a "safe" version that always returns a
+ printable string. */
+
+char *
+safe_strerror (errnum)
+ int errnum;
+{
+ char *msg;
+ static char buf[32];
+
+ if ((msg = strerror (errnum)) == NULL)
+ {
+ sprintf (buf, "(undocumented errno %d)", errnum);
+ msg = buf;
+ }
+ return (msg);
+}
+
+/* The strsignal() function can return NULL for signal values that are
+ out of range. Provide a "safe" version that always returns a
+ printable string. */
+
+char *
+safe_strsignal (signo)
+ int signo;
+{
+ char *msg;
+ static char buf[32];
+
+ if ((msg = strsignal (signo)) == NULL)
+ {
+ sprintf (buf, "(undocumented signal %d)", signo);
+ msg = buf;
+ }
+ return (msg);
+}
+
+
+/* Print the system error message for errno, and also mention STRING
+ as the file name for which the error was encountered.
+ Then return to command level. */
+
+void
+perror_with_name (string)
+ char *string;
+{
+ char *err;
+ char *combined;
+
+ err = safe_strerror (errno);
+ combined = (char *) alloca (strlen (err) + strlen (string) + 3);
+ strcpy (combined, string);
+ strcat (combined, ": ");
+ strcat (combined, err);
+
+ /* I understand setting these is a matter of taste. Still, some people
+ may clear errno but not know about bfd_error. Doing this here is not
+ unreasonable. */
+ bfd_set_error (bfd_error_no_error);
+ errno = 0;
+
+ error ("%s.", combined);
+}
+
+/* Print the system error message for ERRCODE, and also mention STRING
+ as the file name for which the error was encountered. */
+
+void
+print_sys_errmsg (string, errcode)
+ char *string;
+ int errcode;
+{
+ char *err;
+ char *combined;
+
+ err = safe_strerror (errcode);
+ combined = (char *) alloca (strlen (err) + strlen (string) + 3);
+ strcpy (combined, string);
+ strcat (combined, ": ");
+ strcat (combined, err);
+
+ /* We want anything which was printed on stdout to come out first, before
+ this message. */
+ gdb_flush (gdb_stdout);
+ fprintf_unfiltered (gdb_stderr, "%s.\n", combined);
+}
+
+/* Control C eventually causes this to be called, at a convenient time. */
+
+void
+quit ()
+{
+ serial_t gdb_stdout_serial = serial_fdopen (1);
+
+ target_terminal_ours ();
+
+ /* We want all output to appear now, before we print "Quit". We
+ have 3 levels of buffering we have to flush (it's possible that
+ some of these should be changed to flush the lower-level ones
+ too): */
+
+ /* 1. The _filtered buffer. */
+ wrap_here ((char *)0);
+
+ /* 2. The stdio buffer. */
+ gdb_flush (gdb_stdout);
+ gdb_flush (gdb_stderr);
+
+ /* 3. The system-level buffer. */
+ SERIAL_FLUSH_OUTPUT (gdb_stdout_serial);
+ SERIAL_UN_FDOPEN (gdb_stdout_serial);
+
+ annotate_error_begin ();
+
+ /* Don't use *_filtered; we don't want to prompt the user to continue. */
+ if (error_pre_print)
+ fprintf_unfiltered (gdb_stderr, error_pre_print);
+
+ if (job_control
+ /* If there is no terminal switching for this target, then we can't
+ possibly get screwed by the lack of job control. */
+ || current_target->to_terminal_ours == NULL)
+ fprintf_unfiltered (gdb_stderr, "Quit\n");
+ else
+ fprintf_unfiltered (gdb_stderr,
+ "Quit (expect signal SIGINT when the program is resumed)\n");
+ return_to_top_level (RETURN_QUIT);
+}
+
+
+#ifdef __GO32__
+
+/* In the absence of signals, poll keyboard for a quit.
+ Called from #define QUIT pollquit() in xm-go32.h. */
+
+void
+pollquit()
+{
+ if (kbhit ())
+ {
+ int k = getkey ();
+ if (k == 1) {
+ quit_flag = 1;
+ quit();
+ }
+ else if (k == 2) {
+ immediate_quit = 1;
+ quit ();
+ }
+ else
+ {
+ /* We just ignore it */
+ fprintf_unfiltered (gdb_stderr, "CTRL-A to quit, CTRL-B to quit harder\n");
+ }
+ }
+}
+
+
+#endif
+#ifdef __GO32__
+void notice_quit()
+{
+ if (kbhit ())
+ {
+ int k = getkey ();
+ if (k == 1) {
+ quit_flag = 1;
+ }
+ else if (k == 2)
+ {
+ immediate_quit = 1;
+ }
+ else
+ {
+ fprintf_unfiltered (gdb_stderr, "CTRL-A to quit, CTRL-B to quit harder\n");
+ }
+ }
+}
+#else
+void notice_quit()
+{
+ /* Done by signals */
+}
+#endif
+/* Control C comes here */
+
+void
+request_quit (signo)
+ int signo;
+{
+ quit_flag = 1;
+
+ /* Restore the signal handler. Harmless with BSD-style signals, needed
+ for System V-style signals. So just always do it, rather than worrying
+ about USG defines and stuff like that. */
+ signal (signo, request_quit);
+
+#ifdef REQUEST_QUIT
+ REQUEST_QUIT;
+#else
+ if (immediate_quit)
+ quit ();
+#endif
+}
+
+
+/* Memory management stuff (malloc friends). */
+
+#if defined (NO_MMALLOC)
+
+PTR
+mmalloc (md, size)
+ PTR md;
+ long size;
+{
+ return (malloc (size));
+}
+
+PTR
+mrealloc (md, ptr, size)
+ PTR md;
+ PTR ptr;
+ long size;
+{
+ if (ptr == 0) /* Guard against old realloc's */
+ return malloc (size);
+ else
+ return realloc (ptr, size);
+}
+
+void
+mfree (md, ptr)
+ PTR md;
+ PTR ptr;
+{
+ free (ptr);
+}
+
+#endif /* NO_MMALLOC */
+
+#if defined (NO_MMALLOC) || defined (NO_MMALLOC_CHECK)
+
+void
+init_malloc (md)
+ PTR md;
+{
+}
+
+#else /* have mmalloc and want corruption checking */
+
+static void
+malloc_botch ()
+{
+ fatal_dump_core ("Memory corruption");
+}
+
+/* Attempt to install hooks in mmalloc/mrealloc/mfree for the heap specified
+ by MD, to detect memory corruption. Note that MD may be NULL to specify
+ the default heap that grows via sbrk.
+
+ Note that for freshly created regions, we must call mmcheck prior to any
+ mallocs in the region. Otherwise, any region which was allocated prior to
+ installing the checking hooks, which is later reallocated or freed, will
+ fail the checks! The mmcheck function only allows initial hooks to be
+ installed before the first mmalloc. However, anytime after we have called
+ mmcheck the first time to install the checking hooks, we can call it again
+ to update the function pointer to the memory corruption handler.
+
+ Returns zero on failure, non-zero on success. */
+
+void
+init_malloc (md)
+ PTR md;
+{
+ if (!mmcheck (md, malloc_botch))
+ {
+ warning ("internal error: failed to install memory consistency checks");
+ }
+
+ mmtrace ();
+}
+
+#endif /* Have mmalloc and want corruption checking */
+
+/* Called when a memory allocation fails, with the number of bytes of
+ memory requested in SIZE. */
+
+NORETURN void
+nomem (size)
+ long size;
+{
+ if (size > 0)
+ {
+ fatal ("virtual memory exhausted: can't allocate %ld bytes.", size);
+ }
+ else
+ {
+ fatal ("virtual memory exhausted.");
+ }
+}
+
+/* Like mmalloc but get error if no storage available, and protect against
+ the caller wanting to allocate zero bytes. Whether to return NULL for
+ a zero byte request, or translate the request into a request for one
+ byte of zero'd storage, is a religious issue. */
+
+PTR
+xmmalloc (md, size)
+ PTR md;
+ long size;
+{
+ register PTR val;
+
+ if (size == 0)
+ {
+ val = NULL;
+ }
+ else if ((val = mmalloc (md, size)) == NULL)
+ {
+ nomem (size);
+ }
+ return (val);
+}
+
+/* Like mrealloc but get error if no storage available. */
+
+PTR
+xmrealloc (md, ptr, size)
+ PTR md;
+ PTR ptr;
+ long size;
+{
+ register PTR val;
+
+ if (ptr != NULL)
+ {
+ val = mrealloc (md, ptr, size);
+ }
+ else
+ {
+ val = mmalloc (md, size);
+ }
+ if (val == NULL)
+ {
+ nomem (size);
+ }
+ return (val);
+}
+
+/* Like malloc but get error if no storage available, and protect against
+ the caller wanting to allocate zero bytes. */
+
+PTR
+xmalloc (size)
+ long size;
+{
+ return (xmmalloc ((PTR) NULL, size));
+}
+
+/* Like mrealloc but get error if no storage available. */
+
+PTR
+xrealloc (ptr, size)
+ PTR ptr;
+ long size;
+{
+ return (xmrealloc ((PTR) NULL, ptr, size));
+}
+
+
+/* My replacement for the read system call.
+ Used like `read' but keeps going if `read' returns too soon. */
+
+int
+myread (desc, addr, len)
+ int desc;
+ char *addr;
+ int len;
+{
+ register int val;
+ int orglen = len;
+
+ while (len > 0)
+ {
+ val = read (desc, addr, len);
+ if (val < 0)
+ return val;
+ if (val == 0)
+ return orglen - len;
+ len -= val;
+ addr += val;
+ }
+ return orglen;
+}
+
+/* Make a copy of the string at PTR with SIZE characters
+ (and add a null character at the end in the copy).
+ Uses malloc to get the space. Returns the address of the copy. */
+
+char *
+savestring (ptr, size)
+ const char *ptr;
+ int size;
+{
+ register char *p = (char *) xmalloc (size + 1);
+ memcpy (p, ptr, size);
+ p[size] = 0;
+ return p;
+}
+
+char *
+msavestring (md, ptr, size)
+ PTR md;
+ const char *ptr;
+ int size;
+{
+ register char *p = (char *) xmmalloc (md, size + 1);
+ memcpy (p, ptr, size);
+ p[size] = 0;
+ return p;
+}
+
+/* The "const" is so it compiles under DGUX (which prototypes strsave
+ in <string.h>. FIXME: This should be named "xstrsave", shouldn't it?
+ Doesn't real strsave return NULL if out of memory? */
+char *
+strsave (ptr)
+ const char *ptr;
+{
+ return savestring (ptr, strlen (ptr));
+}
+
+char *
+mstrsave (md, ptr)
+ PTR md;
+ const char *ptr;
+{
+ return (msavestring (md, ptr, strlen (ptr)));
+}
+
+void
+print_spaces (n, file)
+ register int n;
+ register FILE *file;
+{
+ while (n-- > 0)
+ fputc (' ', file);
+}
+
+/* Print a host address. */
+
+void
+gdb_print_address (addr, stream)
+ PTR addr;
+ GDB_FILE *stream;
+{
+
+ /* We could use the %p conversion specifier to fprintf if we had any
+ way of knowing whether this host supports it. But the following
+ should work on the Alpha and on 32 bit machines. */
+
+ fprintf_filtered (stream, "0x%lx", (unsigned long)addr);
+}
+
+/* Ask user a y-or-n question and return 1 iff answer is yes.
+ Takes three args which are given to printf to print the question.
+ The first, a control string, should end in "? ".
+ It should not say how to answer, because we do that. */
+
+/* VARARGS */
+int
+query (va_alist)
+ va_dcl
+{
+ va_list args;
+ char *ctlstr;
+ register int answer;
+ register int ans2;
+ int retval;
+
+ /* Automatically answer "yes" if input is not from a terminal. */
+ if (!input_from_terminal_p ())
+ return 1;
+
+ while (1)
+ {
+ wrap_here (""); /* Flush any buffered output */
+ gdb_flush (gdb_stdout);
+
+ if (annotation_level > 1)
+ printf_filtered ("\n\032\032pre-query\n");
+
+ va_start (args);
+ ctlstr = va_arg (args, char *);
+ vfprintf_filtered (gdb_stdout, ctlstr, args);
+ va_end (args);
+ printf_filtered ("(y or n) ");
+
+ if (annotation_level > 1)
+ printf_filtered ("\n\032\032query\n");
+
+ gdb_flush (gdb_stdout);
+ answer = fgetc (stdin);
+ clearerr (stdin); /* in case of C-d */
+ if (answer == EOF) /* C-d */
+ {
+ retval = 1;
+ break;
+ }
+ if (answer != '\n') /* Eat rest of input line, to EOF or newline */
+ do
+ {
+ ans2 = fgetc (stdin);
+ clearerr (stdin);
+ }
+ while (ans2 != EOF && ans2 != '\n');
+ if (answer >= 'a')
+ answer -= 040;
+ if (answer == 'Y')
+ {
+ retval = 1;
+ break;
+ }
+ if (answer == 'N')
+ {
+ retval = 0;
+ break;
+ }
+ printf_filtered ("Please answer y or n.\n");
+ }
+
+ if (annotation_level > 1)
+ printf_filtered ("\n\032\032post-query\n");
+ return retval;
+}
+
+
+/* Parse a C escape sequence. STRING_PTR points to a variable
+ containing a pointer to the string to parse. That pointer
+ should point to the character after the \. That pointer
+ is updated past the characters we use. The value of the
+ escape sequence is returned.
+
+ A negative value means the sequence \ newline was seen,
+ which is supposed to be equivalent to nothing at all.
+
+ If \ is followed by a null character, we return a negative
+ value and leave the string pointer pointing at the null character.
+
+ If \ is followed by 000, we return 0 and leave the string pointer
+ after the zeros. A value of 0 does not mean end of string. */
+
+int
+parse_escape (string_ptr)
+ char **string_ptr;
+{
+ register int c = *(*string_ptr)++;
+ switch (c)
+ {
+ case 'a':
+ return 007; /* Bell (alert) char */
+ case 'b':
+ return '\b';
+ case 'e': /* Escape character */
+ return 033;
+ case 'f':
+ return '\f';
+ case 'n':
+ return '\n';
+ case 'r':
+ return '\r';
+ case 't':
+ return '\t';
+ case 'v':
+ return '\v';
+ case '\n':
+ return -2;
+ case 0:
+ (*string_ptr)--;
+ return 0;
+ case '^':
+ c = *(*string_ptr)++;
+ if (c == '\\')
+ c = parse_escape (string_ptr);
+ if (c == '?')
+ return 0177;
+ return (c & 0200) | (c & 037);
+
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ {
+ register int i = c - '0';
+ register int count = 0;
+ while (++count < 3)
+ {
+ if ((c = *(*string_ptr)++) >= '0' && c <= '7')
+ {
+ i *= 8;
+ i += c - '0';
+ }
+ else
+ {
+ (*string_ptr)--;
+ break;
+ }
+ }
+ return i;
+ }
+ default:
+ return c;
+ }
+}
+
+/* Print the character C on STREAM as part of the contents of a literal
+ string whose delimiter is QUOTER. Note that this routine should only
+ be call for printing things which are independent of the language
+ of the program being debugged. */
+
+void
+gdb_printchar (c, stream, quoter)
+ register int c;
+ FILE *stream;
+ int quoter;
+{
+
+ c &= 0xFF; /* Avoid sign bit follies */
+
+ if ( c < 0x20 || /* Low control chars */
+ (c >= 0x7F && c < 0xA0) || /* DEL, High controls */
+ (sevenbit_strings && c >= 0x80)) { /* high order bit set */
+ switch (c)
+ {
+ case '\n':
+ fputs_filtered ("\\n", stream);
+ break;
+ case '\b':
+ fputs_filtered ("\\b", stream);
+ break;
+ case '\t':
+ fputs_filtered ("\\t", stream);
+ break;
+ case '\f':
+ fputs_filtered ("\\f", stream);
+ break;
+ case '\r':
+ fputs_filtered ("\\r", stream);
+ break;
+ case '\033':
+ fputs_filtered ("\\e", stream);
+ break;
+ case '\007':
+ fputs_filtered ("\\a", stream);
+ break;
+ default:
+ fprintf_filtered (stream, "\\%.3o", (unsigned int) c);
+ break;
+ }
+ } else {
+ if (c == '\\' || c == quoter)
+ fputs_filtered ("\\", stream);
+ fprintf_filtered (stream, "%c", c);
+ }
+}
+
+/* Number of lines per page or UINT_MAX if paging is disabled. */
+static unsigned int lines_per_page;
+/* Number of chars per line or UNIT_MAX is line folding is disabled. */
+static unsigned int chars_per_line;
+/* Current count of lines printed on this page, chars on this line. */
+static unsigned int lines_printed, chars_printed;
+
+/* Buffer and start column of buffered text, for doing smarter word-
+ wrapping. When someone calls wrap_here(), we start buffering output
+ that comes through fputs_filtered(). If we see a newline, we just
+ spit it out and forget about the wrap_here(). If we see another
+ wrap_here(), we spit it out and remember the newer one. If we see
+ the end of the line, we spit out a newline, the indent, and then
+ the buffered output. */
+
+/* Malloc'd buffer with chars_per_line+2 bytes. Contains characters which
+ are waiting to be output (they have already been counted in chars_printed).
+ When wrap_buffer[0] is null, the buffer is empty. */
+static char *wrap_buffer;
+
+/* Pointer in wrap_buffer to the next character to fill. */
+static char *wrap_pointer;
+
+/* String to indent by if the wrap occurs. Must not be NULL if wrap_column
+ is non-zero. */
+static char *wrap_indent;
+
+/* Column number on the screen where wrap_buffer begins, or 0 if wrapping
+ is not in effect. */
+static int wrap_column;
+
+/* ARGSUSED */
+static void
+set_width_command (args, from_tty, c)
+ char *args;
+ int from_tty;
+ struct cmd_list_element *c;
+{
+ if (!wrap_buffer)
+ {
+ wrap_buffer = (char *) xmalloc (chars_per_line + 2);
+ wrap_buffer[0] = '\0';
+ }
+ else
+ wrap_buffer = (char *) xrealloc (wrap_buffer, chars_per_line + 2);
+ wrap_pointer = wrap_buffer; /* Start it at the beginning */
+}
+
+/* Wait, so the user can read what's on the screen. Prompt the user
+ to continue by pressing RETURN. */
+
+static void
+prompt_for_continue ()
+{
+ char *ignore;
+ char cont_prompt[120];
+
+ if (annotation_level > 1)
+ printf_unfiltered ("\n\032\032pre-prompt-for-continue\n");
+
+ strcpy (cont_prompt,
+ "---Type <return> to continue, or q <return> to quit---");
+ if (annotation_level > 1)
+ strcat (cont_prompt, "\n\032\032prompt-for-continue\n");
+
+ /* We must do this *before* we call gdb_readline, else it will eventually
+ call us -- thinking that we're trying to print beyond the end of the
+ screen. */
+ reinitialize_more_filter ();
+
+ immediate_quit++;
+ /* On a real operating system, the user can quit with SIGINT.
+ But not on GO32.
+
+ 'q' is provided on all systems so users don't have to change habits
+ from system to system, and because telling them what to do in
+ the prompt is more user-friendly than expecting them to think of
+ SIGINT. */
+ /* Call readline, not gdb_readline, because GO32 readline handles control-C
+ whereas control-C to gdb_readline will cause the user to get dumped
+ out to DOS. */
+ ignore = readline (cont_prompt);
+
+ if (annotation_level > 1)
+ printf_unfiltered ("\n\032\032post-prompt-for-continue\n");
+
+ if (ignore)
+ {
+ char *p = ignore;
+ while (*p == ' ' || *p == '\t')
+ ++p;
+ if (p[0] == 'q')
+ request_quit (SIGINT);
+ free (ignore);
+ }
+ immediate_quit--;
+
+ /* Now we have to do this again, so that GDB will know that it doesn't
+ need to save the ---Type <return>--- line at the top of the screen. */
+ reinitialize_more_filter ();
+
+ dont_repeat (); /* Forget prev cmd -- CR won't repeat it. */
+}
+
+/* Reinitialize filter; ie. tell it to reset to original values. */
+
+void
+reinitialize_more_filter ()
+{
+ lines_printed = 0;
+ chars_printed = 0;
+}
+
+/* Indicate that if the next sequence of characters overflows the line,
+ a newline should be inserted here rather than when it hits the end.
+ If INDENT is non-null, it is a string to be printed to indent the
+ wrapped part on the next line. INDENT must remain accessible until
+ the next call to wrap_here() or until a newline is printed through
+ fputs_filtered().
+
+ If the line is already overfull, we immediately print a newline and
+ the indentation, and disable further wrapping.
+
+ If we don't know the width of lines, but we know the page height,
+ we must not wrap words, but should still keep track of newlines
+ that were explicitly printed.
+
+ INDENT should not contain tabs, as that will mess up the char count
+ on the next line. FIXME.
+
+ This routine is guaranteed to force out any output which has been
+ squirreled away in the wrap_buffer, so wrap_here ((char *)0) can be
+ used to force out output from the wrap_buffer. */
+
+void
+wrap_here(indent)
+ char *indent;
+{
+ /* This should have been allocated, but be paranoid anyway. */
+ if (!wrap_buffer)
+ abort ();
+
+ if (wrap_buffer[0])
+ {
+ *wrap_pointer = '\0';
+ fputs_unfiltered (wrap_buffer, gdb_stdout);
+ }
+ wrap_pointer = wrap_buffer;
+ wrap_buffer[0] = '\0';
+ if (chars_per_line == UINT_MAX) /* No line overflow checking */
+ {
+ wrap_column = 0;
+ }
+ else if (chars_printed >= chars_per_line)
+ {
+ puts_filtered ("\n");
+ if (indent != NULL)
+ puts_filtered (indent);
+ wrap_column = 0;
+ }
+ else
+ {
+ wrap_column = chars_printed;
+ if (indent == NULL)
+ wrap_indent = "";
+ else
+ wrap_indent = indent;
+ }
+}
+
+/* Ensure that whatever gets printed next, using the filtered output
+ commands, starts at the beginning of the line. I.E. if there is
+ any pending output for the current line, flush it and start a new
+ line. Otherwise do nothing. */
+
+void
+begin_line ()
+{
+ if (chars_printed > 0)
+ {
+ puts_filtered ("\n");
+ }
+}
+
+
+GDB_FILE *
+gdb_fopen (name, mode)
+ char * name;
+ char * mode;
+{
+ return fopen (name, mode);
+}
+
+void
+gdb_flush (stream)
+ FILE *stream;
+{
+ fflush (stream);
+}
+
+/* Like fputs but if FILTER is true, pause after every screenful.
+
+ Regardless of FILTER can wrap at points other than the final
+ character of a line.
+
+ Unlike fputs, fputs_maybe_filtered does not return a value.
+ It is OK for LINEBUFFER to be NULL, in which case just don't print
+ anything.
+
+ Note that a longjmp to top level may occur in this routine (only if
+ FILTER is true) (since prompt_for_continue may do so) so this
+ routine should not be called when cleanups are not in place. */
+
+static void
+fputs_maybe_filtered (linebuffer, stream, filter)
+ const char *linebuffer;
+ FILE *stream;
+ int filter;
+{
+ const char *lineptr;
+
+ if (linebuffer == 0)
+ return;
+
+ /* Don't do any filtering if it is disabled. */
+ if (stream != gdb_stdout
+ || (lines_per_page == UINT_MAX && chars_per_line == UINT_MAX))
+ {
+ fputs_unfiltered (linebuffer, stream);
+ return;
+ }
+
+ /* Go through and output each character. Show line extension
+ when this is necessary; prompt user for new page when this is
+ necessary. */
+
+ lineptr = linebuffer;
+ while (*lineptr)
+ {
+ /* Possible new page. */
+ if (filter &&
+ (lines_printed >= lines_per_page - 1))
+ prompt_for_continue ();
+
+ while (*lineptr && *lineptr != '\n')
+ {
+ /* Print a single line. */
+ if (*lineptr == '\t')
+ {
+ if (wrap_column)
+ *wrap_pointer++ = '\t';
+ else
+ fputc_unfiltered ('\t', stream);
+ /* Shifting right by 3 produces the number of tab stops
+ we have already passed, and then adding one and
+ shifting left 3 advances to the next tab stop. */
+ chars_printed = ((chars_printed >> 3) + 1) << 3;
+ lineptr++;
+ }
+ else
+ {
+ if (wrap_column)
+ *wrap_pointer++ = *lineptr;
+ else
+ fputc_unfiltered (*lineptr, stream);
+ chars_printed++;
+ lineptr++;
+ }
+
+ if (chars_printed >= chars_per_line)
+ {
+ unsigned int save_chars = chars_printed;
+
+ chars_printed = 0;
+ lines_printed++;
+ /* If we aren't actually wrapping, don't output newline --
+ if chars_per_line is right, we probably just overflowed
+ anyway; if it's wrong, let us keep going. */
+ if (wrap_column)
+ fputc_unfiltered ('\n', stream);
+
+ /* Possible new page. */
+ if (lines_printed >= lines_per_page - 1)
+ prompt_for_continue ();
+
+ /* Now output indentation and wrapped string */
+ if (wrap_column)
+ {
+ fputs_unfiltered (wrap_indent, stream);
+ *wrap_pointer = '\0'; /* Null-terminate saved stuff */
+ fputs_unfiltered (wrap_buffer, stream); /* and eject it */
+ /* FIXME, this strlen is what prevents wrap_indent from
+ containing tabs. However, if we recurse to print it
+ and count its chars, we risk trouble if wrap_indent is
+ longer than (the user settable) chars_per_line.
+ Note also that this can set chars_printed > chars_per_line
+ if we are printing a long string. */
+ chars_printed = strlen (wrap_indent)
+ + (save_chars - wrap_column);
+ wrap_pointer = wrap_buffer; /* Reset buffer */
+ wrap_buffer[0] = '\0';
+ wrap_column = 0; /* And disable fancy wrap */
+ }
+ }
+ }
+
+ if (*lineptr == '\n')
+ {
+ chars_printed = 0;
+ wrap_here ((char *)0); /* Spit out chars, cancel further wraps */
+ lines_printed++;
+ fputc_unfiltered ('\n', stream);
+ lineptr++;
+ }
+ }
+}
+
+void
+fputs_filtered (linebuffer, stream)
+ const char *linebuffer;
+ FILE *stream;
+{
+ fputs_maybe_filtered (linebuffer, stream, 1);
+}
+
+void
+putc_unfiltered (c)
+ int c;
+{
+ char buf[2];
+ buf[0] = c;
+ buf[1] = 0;
+ fputs_unfiltered (buf, gdb_stdout);
+}
+
+void
+fputc_unfiltered (c, stream)
+ int c;
+ FILE * stream;
+{
+ char buf[2];
+ buf[0] = c;
+ buf[1] = 0;
+ fputs_unfiltered (buf, stream);
+}
+
+
+/* Print a variable number of ARGS using format FORMAT. If this
+ information is going to put the amount written (since the last call
+ to REINITIALIZE_MORE_FILTER or the last page break) over the page size,
+ call prompt_for_continue to get the users permision to continue.
+
+ Unlike fprintf, this function does not return a value.
+
+ We implement three variants, vfprintf (takes a vararg list and stream),
+ fprintf (takes a stream to write on), and printf (the usual).
+
+ Note also that a longjmp to top level may occur in this routine
+ (since prompt_for_continue may do so) so this routine should not be
+ called when cleanups are not in place. */
+
+static void
+vfprintf_maybe_filtered (stream, format, args, filter)
+ FILE *stream;
+ char *format;
+ va_list args;
+ int filter;
+{
+ char *linebuffer;
+ struct cleanup *old_cleanups;
+
+ vasprintf (&linebuffer, format, args);
+ if (linebuffer == NULL)
+ {
+ fputs_unfiltered ("\ngdb: virtual memory exhausted.\n", gdb_stderr);
+ exit (1);
+ }
+ old_cleanups = make_cleanup (free, linebuffer);
+ fputs_maybe_filtered (linebuffer, stream, filter);
+ do_cleanups (old_cleanups);
+}
+
+
+void
+vfprintf_filtered (stream, format, args)
+ FILE *stream;
+ char *format;
+ va_list args;
+{
+ vfprintf_maybe_filtered (stream, format, args, 1);
+}
+
+void
+vfprintf_unfiltered (stream, format, args)
+ FILE *stream;
+ char *format;
+ va_list args;
+{
+ char *linebuffer;
+ struct cleanup *old_cleanups;
+
+ vasprintf (&linebuffer, format, args);
+ if (linebuffer == NULL)
+ {
+ fputs_unfiltered ("\ngdb: virtual memory exhausted.\n", gdb_stderr);
+ exit (1);
+ }
+ old_cleanups = make_cleanup (free, linebuffer);
+ fputs_unfiltered (linebuffer, stream);
+ do_cleanups (old_cleanups);
+}
+
+void
+vprintf_filtered (format, args)
+ char *format;
+ va_list args;
+{
+ vfprintf_maybe_filtered (gdb_stdout, format, args, 1);
+}
+
+void
+vprintf_unfiltered (format, args)
+ char *format;
+ va_list args;
+{
+ vfprintf_unfiltered (gdb_stdout, format, args);
+}
+
+/* VARARGS */
+void
+fprintf_filtered (va_alist)
+ va_dcl
+{
+ va_list args;
+ FILE *stream;
+ char *format;
+
+ va_start (args);
+ stream = va_arg (args, FILE *);
+ format = va_arg (args, char *);
+
+ vfprintf_filtered (stream, format, args);
+ va_end (args);
+}
+
+/* VARARGS */
+void
+fprintf_unfiltered (va_alist)
+ va_dcl
+{
+ va_list args;
+ FILE *stream;
+ char *format;
+
+ va_start (args);
+ stream = va_arg (args, FILE *);
+ format = va_arg (args, char *);
+
+ vfprintf_unfiltered (stream, format, args);
+ va_end (args);
+}
+
+/* Like fprintf_filtered, but prints its result indented.
+ Called as fprintfi_filtered (spaces, stream, format, ...); */
+
+/* VARARGS */
+void
+fprintfi_filtered (va_alist)
+ va_dcl
+{
+ va_list args;
+ int spaces;
+ FILE *stream;
+ char *format;
+
+ va_start (args);
+ spaces = va_arg (args, int);
+ stream = va_arg (args, FILE *);
+ format = va_arg (args, char *);
+ print_spaces_filtered (spaces, stream);
+
+ vfprintf_filtered (stream, format, args);
+ va_end (args);
+}
+
+
+/* VARARGS */
+void
+printf_filtered (va_alist)
+ va_dcl
+{
+ va_list args;
+ char *format;
+
+ va_start (args);
+ format = va_arg (args, char *);
+
+ vfprintf_filtered (gdb_stdout, format, args);
+ va_end (args);
+}
+
+
+/* VARARGS */
+void
+printf_unfiltered (va_alist)
+ va_dcl
+{
+ va_list args;
+ char *format;
+
+ va_start (args);
+ format = va_arg (args, char *);
+
+ vfprintf_unfiltered (gdb_stdout, format, args);
+ va_end (args);
+}
+
+/* Like printf_filtered, but prints it's result indented.
+ Called as printfi_filtered (spaces, format, ...); */
+
+/* VARARGS */
+void
+printfi_filtered (va_alist)
+ va_dcl
+{
+ va_list args;
+ int spaces;
+ char *format;
+
+ va_start (args);
+ spaces = va_arg (args, int);
+ format = va_arg (args, char *);
+ print_spaces_filtered (spaces, gdb_stdout);
+ vfprintf_filtered (gdb_stdout, format, args);
+ va_end (args);
+}
+
+/* Easy -- but watch out!
+
+ This routine is *not* a replacement for puts()! puts() appends a newline.
+ This one doesn't, and had better not! */
+
+void
+puts_filtered (string)
+ char *string;
+{
+ fputs_filtered (string, gdb_stdout);
+}
+
+void
+puts_unfiltered (string)
+ char *string;
+{
+ fputs_unfiltered (string, gdb_stdout);
+}
+
+/* Return a pointer to N spaces and a null. The pointer is good
+ until the next call to here. */
+char *
+n_spaces (n)
+ int n;
+{
+ register char *t;
+ static char *spaces;
+ static int max_spaces;
+
+ if (n > max_spaces)
+ {
+ if (spaces)
+ free (spaces);
+ spaces = (char *) xmalloc (n+1);
+ for (t = spaces+n; t != spaces;)
+ *--t = ' ';
+ spaces[n] = '\0';
+ max_spaces = n;
+ }
+
+ return spaces + max_spaces - n;
+}
+
+/* Print N spaces. */
+void
+print_spaces_filtered (n, stream)
+ int n;
+ FILE *stream;
+{
+ fputs_filtered (n_spaces (n), stream);
+}
+
+/* C++ demangler stuff. */
+
+/* fprintf_symbol_filtered attempts to demangle NAME, a symbol in language
+ LANG, using demangling args ARG_MODE, and print it filtered to STREAM.
+ If the name is not mangled, or the language for the name is unknown, or
+ demangling is off, the name is printed in its "raw" form. */
+
+void
+fprintf_symbol_filtered (stream, name, lang, arg_mode)
+ FILE *stream;
+ char *name;
+ enum language lang;
+ int arg_mode;
+{
+ char *demangled;
+
+ if (name != NULL)
+ {
+ /* If user wants to see raw output, no problem. */
+ if (!demangle)
+ {
+ fputs_filtered (name, stream);
+ }
+ else
+ {
+ switch (lang)
+ {
+ case language_cplus:
+ demangled = cplus_demangle (name, arg_mode);
+ break;
+ case language_chill:
+ demangled = chill_demangle (name);
+ break;
+ default:
+ demangled = NULL;
+ break;
+ }
+ fputs_filtered (demangled ? demangled : name, stream);
+ if (demangled != NULL)
+ {
+ free (demangled);
+ }
+ }
+ }
+}
+
+/* Do a strcmp() type operation on STRING1 and STRING2, ignoring any
+ differences in whitespace. Returns 0 if they match, non-zero if they
+ don't (slightly different than strcmp()'s range of return values).
+
+ As an extra hack, string1=="FOO(ARGS)" matches string2=="FOO".
+ This "feature" is useful when searching for matching C++ function names
+ (such as if the user types 'break FOO', where FOO is a mangled C++
+ function). */
+
+int
+strcmp_iw (string1, string2)
+ const char *string1;
+ const char *string2;
+{
+ while ((*string1 != '\0') && (*string2 != '\0'))
+ {
+ while (isspace (*string1))
+ {
+ string1++;
+ }
+ while (isspace (*string2))
+ {
+ string2++;
+ }
+ if (*string1 != *string2)
+ {
+ break;
+ }
+ if (*string1 != '\0')
+ {
+ string1++;
+ string2++;
+ }
+ }
+ return (*string1 != '\0' && *string1 != '(') || (*string2 != '\0');
+}
+
+
+void
+_initialize_utils ()
+{
+ struct cmd_list_element *c;
+
+ c = add_set_cmd ("width", class_support, var_uinteger,
+ (char *)&chars_per_line,
+ "Set number of characters gdb thinks are in a line.",
+ &setlist);
+ add_show_from_set (c, &showlist);
+ c->function.sfunc = set_width_command;
+
+ add_show_from_set
+ (add_set_cmd ("height", class_support,
+ var_uinteger, (char *)&lines_per_page,
+ "Set number of lines gdb thinks are in a page.", &setlist),
+ &showlist);
+
+ /* These defaults will be used if we are unable to get the correct
+ values from termcap. */
+#if defined(__GO32__)
+ lines_per_page = ScreenRows();
+ chars_per_line = ScreenCols();
+#else
+ lines_per_page = 24;
+ chars_per_line = 80;
+ /* Initialize the screen height and width from termcap. */
+ {
+ char *termtype = getenv ("TERM");
+
+ /* Positive means success, nonpositive means failure. */
+ int status;
+
+ /* 2048 is large enough for all known terminals, according to the
+ GNU termcap manual. */
+ char term_buffer[2048];
+
+ if (termtype)
+ {
+ status = tgetent (term_buffer, termtype);
+ if (status > 0)
+ {
+ int val;
+
+ val = tgetnum ("li");
+ if (val >= 0)
+ lines_per_page = val;
+ else
+ /* The number of lines per page is not mentioned
+ in the terminal description. This probably means
+ that paging is not useful (e.g. emacs shell window),
+ so disable paging. */
+ lines_per_page = UINT_MAX;
+
+ val = tgetnum ("co");
+ if (val >= 0)
+ chars_per_line = val;
+ }
+ }
+ }
+
+#if defined(SIGWINCH) && defined(SIGWINCH_HANDLER)
+
+ /* If there is a better way to determine the window size, use it. */
+ SIGWINCH_HANDLER ();
+#endif
+#endif
+ /* If the output is not a terminal, don't paginate it. */
+ if (!ISATTY (gdb_stdout))
+ lines_per_page = UINT_MAX;
+
+ set_width_command ((char *)NULL, 0, c);
+
+ add_show_from_set
+ (add_set_cmd ("demangle", class_support, var_boolean,
+ (char *)&demangle,
+ "Set demangling of encoded C++ names when displaying symbols.",
+ &setprintlist),
+ &showprintlist);
+
+ add_show_from_set
+ (add_set_cmd ("sevenbit-strings", class_support, var_boolean,
+ (char *)&sevenbit_strings,
+ "Set printing of 8-bit characters in strings as \\nnn.",
+ &setprintlist),
+ &showprintlist);
+
+ add_show_from_set
+ (add_set_cmd ("asm-demangle", class_support, var_boolean,
+ (char *)&asm_demangle,
+ "Set demangling of C++ names in disassembly listings.",
+ &setprintlist),
+ &showprintlist);
+}
+
+/* Machine specific function to handle SIGWINCH signal. */
+
+#ifdef SIGWINCH_HANDLER_BODY
+ SIGWINCH_HANDLER_BODY
+#endif
+
diff --git a/gnu/usr.bin/gdb/gdb/valarith.c b/gnu/usr.bin/gdb/gdb/valarith.c
new file mode 100644
index 0000000..8a01b46
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/valarith.c
@@ -0,0 +1,1068 @@
+/* Perform arithmetic and other operations on values, for GDB.
+ Copyright 1986, 1989, 1991, 1992 Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "defs.h"
+#include "value.h"
+#include "symtab.h"
+#include "gdbtypes.h"
+#include "expression.h"
+#include "target.h"
+#include "language.h"
+#include "demangle.h"
+#include <string.h>
+
+/* Define whether or not the C operator '/' truncates towards zero for
+ differently signed operands (truncation direction is undefined in C). */
+
+#ifndef TRUNCATION_TOWARDS_ZERO
+#define TRUNCATION_TOWARDS_ZERO ((-5 / 2) == -2)
+#endif
+
+static value_ptr value_subscripted_rvalue PARAMS ((value_ptr, value_ptr));
+
+
+value_ptr
+value_add (arg1, arg2)
+ value_ptr arg1, arg2;
+{
+ register value_ptr valint, valptr;
+ register int len;
+
+ COERCE_ARRAY (arg1);
+ COERCE_ARRAY (arg2);
+
+ if ((TYPE_CODE (VALUE_TYPE (arg1)) == TYPE_CODE_PTR
+ || TYPE_CODE (VALUE_TYPE (arg2)) == TYPE_CODE_PTR)
+ &&
+ (TYPE_CODE (VALUE_TYPE (arg1)) == TYPE_CODE_INT
+ || TYPE_CODE (VALUE_TYPE (arg2)) == TYPE_CODE_INT))
+ /* Exactly one argument is a pointer, and one is an integer. */
+ {
+ if (TYPE_CODE (VALUE_TYPE (arg1)) == TYPE_CODE_PTR)
+ {
+ valptr = arg1;
+ valint = arg2;
+ }
+ else
+ {
+ valptr = arg2;
+ valint = arg1;
+ }
+ len = TYPE_LENGTH (TYPE_TARGET_TYPE (VALUE_TYPE (valptr)));
+ if (len == 0) len = 1; /* For (void *) */
+ return value_from_longest (VALUE_TYPE (valptr),
+ value_as_long (valptr)
+ + (len * value_as_long (valint)));
+ }
+
+ return value_binop (arg1, arg2, BINOP_ADD);
+}
+
+value_ptr
+value_sub (arg1, arg2)
+ value_ptr arg1, arg2;
+{
+
+ COERCE_ARRAY (arg1);
+ COERCE_ARRAY (arg2);
+
+ if (TYPE_CODE (VALUE_TYPE (arg1)) == TYPE_CODE_PTR)
+ {
+ if (TYPE_CODE (VALUE_TYPE (arg2)) == TYPE_CODE_INT)
+ {
+ /* pointer - integer. */
+ return value_from_longest
+ (VALUE_TYPE (arg1),
+ value_as_long (arg1)
+ - (TYPE_LENGTH (TYPE_TARGET_TYPE (VALUE_TYPE (arg1)))
+ * value_as_long (arg2)));
+ }
+ else if (VALUE_TYPE (arg1) == VALUE_TYPE (arg2))
+ {
+ /* pointer to <type x> - pointer to <type x>. */
+ return value_from_longest
+ (builtin_type_long, /* FIXME -- should be ptrdiff_t */
+ (value_as_long (arg1) - value_as_long (arg2))
+ / TYPE_LENGTH (TYPE_TARGET_TYPE (VALUE_TYPE (arg1))));
+ }
+ else
+ {
+ error ("\
+First argument of `-' is a pointer and second argument is neither\n\
+an integer nor a pointer of the same type.");
+ }
+ }
+
+ return value_binop (arg1, arg2, BINOP_SUB);
+}
+
+/* Return the value of ARRAY[IDX].
+ See comments in value_coerce_array() for rationale for reason for
+ doing lower bounds adjustment here rather than there.
+ FIXME: Perhaps we should validate that the index is valid and if
+ verbosity is set, warn about invalid indices (but still use them). */
+
+value_ptr
+value_subscript (array, idx)
+ value_ptr array, idx;
+{
+ int lowerbound;
+ value_ptr bound;
+ struct type *range_type;
+
+ COERCE_REF (array);
+
+ if (TYPE_CODE (VALUE_TYPE (array)) == TYPE_CODE_ARRAY
+ || TYPE_CODE (VALUE_TYPE (array)) == TYPE_CODE_STRING)
+ {
+ range_type = TYPE_FIELD_TYPE (VALUE_TYPE (array), 0);
+ lowerbound = TYPE_FIELD_BITPOS (range_type, 0);
+ if (lowerbound != 0)
+ {
+ bound = value_from_longest (builtin_type_int, (LONGEST) lowerbound);
+ idx = value_sub (idx, bound);
+ }
+ if (VALUE_LVAL (array) != lval_memory)
+ {
+ return value_subscripted_rvalue (array, idx);
+ }
+ array = value_coerce_array (array);
+ }
+ return value_ind (value_add (array, idx));
+}
+
+/* Return the value of EXPR[IDX], expr an aggregate rvalue
+ (eg, a vector register). This routine used to promote floats
+ to doubles, but no longer does. */
+
+static value_ptr
+value_subscripted_rvalue (array, idx)
+ value_ptr array, idx;
+{
+ struct type *elt_type = TYPE_TARGET_TYPE (VALUE_TYPE (array));
+ int elt_size = TYPE_LENGTH (elt_type);
+ int elt_offs = elt_size * longest_to_int (value_as_long (idx));
+ value_ptr v;
+
+ if (elt_offs >= TYPE_LENGTH (VALUE_TYPE (array)))
+ error ("no such vector element");
+
+ v = allocate_value (elt_type);
+ memcpy (VALUE_CONTENTS (v), VALUE_CONTENTS (array) + elt_offs, elt_size);
+
+ if (VALUE_LVAL (array) == lval_internalvar)
+ VALUE_LVAL (v) = lval_internalvar_component;
+ else
+ VALUE_LVAL (v) = not_lval;
+ VALUE_ADDRESS (v) = VALUE_ADDRESS (array);
+ VALUE_OFFSET (v) = VALUE_OFFSET (array) + elt_offs;
+ VALUE_BITSIZE (v) = elt_size * 8;
+ return v;
+}
+
+/* Check to see if either argument is a structure. This is called so
+ we know whether to go ahead with the normal binop or look for a
+ user defined function instead.
+
+ For now, we do not overload the `=' operator. */
+
+int
+binop_user_defined_p (op, arg1, arg2)
+ enum exp_opcode op;
+ value_ptr arg1, arg2;
+{
+ if (op == BINOP_ASSIGN)
+ return 0;
+ return (TYPE_CODE (VALUE_TYPE (arg1)) == TYPE_CODE_STRUCT
+ || TYPE_CODE (VALUE_TYPE (arg2)) == TYPE_CODE_STRUCT
+ || (TYPE_CODE (VALUE_TYPE (arg1)) == TYPE_CODE_REF
+ && TYPE_CODE (TYPE_TARGET_TYPE (VALUE_TYPE (arg1))) == TYPE_CODE_STRUCT)
+ || (TYPE_CODE (VALUE_TYPE (arg2)) == TYPE_CODE_REF
+ && TYPE_CODE (TYPE_TARGET_TYPE (VALUE_TYPE (arg2))) == TYPE_CODE_STRUCT));
+}
+
+/* Check to see if argument is a structure. This is called so
+ we know whether to go ahead with the normal unop or look for a
+ user defined function instead.
+
+ For now, we do not overload the `&' operator. */
+
+int unop_user_defined_p (op, arg1)
+ enum exp_opcode op;
+ value_ptr arg1;
+{
+ if (op == UNOP_ADDR)
+ return 0;
+ return (TYPE_CODE (VALUE_TYPE (arg1)) == TYPE_CODE_STRUCT
+ || (TYPE_CODE (VALUE_TYPE (arg1)) == TYPE_CODE_REF
+ && TYPE_CODE (TYPE_TARGET_TYPE (VALUE_TYPE (arg1))) == TYPE_CODE_STRUCT));
+}
+
+/* We know either arg1 or arg2 is a structure, so try to find the right
+ user defined function. Create an argument vector that calls
+ arg1.operator @ (arg1,arg2) and return that value (where '@' is any
+ binary operator which is legal for GNU C++).
+
+ OP is the operatore, and if it is BINOP_ASSIGN_MODIFY, then OTHEROP
+ is the opcode saying how to modify it. Otherwise, OTHEROP is
+ unused. */
+
+value_ptr
+value_x_binop (arg1, arg2, op, otherop)
+ value_ptr arg1, arg2;
+ enum exp_opcode op, otherop;
+{
+ value_ptr * argvec;
+ char *ptr;
+ char tstr[13];
+ int static_memfuncp;
+
+ COERCE_REF (arg1);
+ COERCE_REF (arg2);
+ COERCE_ENUM (arg1);
+ COERCE_ENUM (arg2);
+
+ /* now we know that what we have to do is construct our
+ arg vector and find the right function to call it with. */
+
+ if (TYPE_CODE (VALUE_TYPE (arg1)) != TYPE_CODE_STRUCT)
+ error ("Can't do that binary op on that type"); /* FIXME be explicit */
+
+ argvec = (value_ptr *) alloca (sizeof (value_ptr) * 4);
+ argvec[1] = value_addr (arg1);
+ argvec[2] = arg2;
+ argvec[3] = 0;
+
+ /* make the right function name up */
+ strcpy(tstr, "operator__");
+ ptr = tstr+8;
+ switch (op)
+ {
+ case BINOP_ADD: strcpy(ptr,"+"); break;
+ case BINOP_SUB: strcpy(ptr,"-"); break;
+ case BINOP_MUL: strcpy(ptr,"*"); break;
+ case BINOP_DIV: strcpy(ptr,"/"); break;
+ case BINOP_REM: strcpy(ptr,"%"); break;
+ case BINOP_LSH: strcpy(ptr,"<<"); break;
+ case BINOP_RSH: strcpy(ptr,">>"); break;
+ case BINOP_BITWISE_AND: strcpy(ptr,"&"); break;
+ case BINOP_BITWISE_IOR: strcpy(ptr,"|"); break;
+ case BINOP_BITWISE_XOR: strcpy(ptr,"^"); break;
+ case BINOP_LOGICAL_AND: strcpy(ptr,"&&"); break;
+ case BINOP_LOGICAL_OR: strcpy(ptr,"||"); break;
+ case BINOP_MIN: strcpy(ptr,"<?"); break;
+ case BINOP_MAX: strcpy(ptr,">?"); break;
+ case BINOP_ASSIGN: strcpy(ptr,"="); break;
+ case BINOP_ASSIGN_MODIFY:
+ switch (otherop)
+ {
+ case BINOP_ADD: strcpy(ptr,"+="); break;
+ case BINOP_SUB: strcpy(ptr,"-="); break;
+ case BINOP_MUL: strcpy(ptr,"*="); break;
+ case BINOP_DIV: strcpy(ptr,"/="); break;
+ case BINOP_REM: strcpy(ptr,"%="); break;
+ case BINOP_BITWISE_AND: strcpy(ptr,"&="); break;
+ case BINOP_BITWISE_IOR: strcpy(ptr,"|="); break;
+ case BINOP_BITWISE_XOR: strcpy(ptr,"^="); break;
+ case BINOP_MOD: /* invalid */
+ default:
+ error ("Invalid binary operation specified.");
+ }
+ break;
+ case BINOP_SUBSCRIPT: strcpy(ptr,"[]"); break;
+ case BINOP_EQUAL: strcpy(ptr,"=="); break;
+ case BINOP_NOTEQUAL: strcpy(ptr,"!="); break;
+ case BINOP_LESS: strcpy(ptr,"<"); break;
+ case BINOP_GTR: strcpy(ptr,">"); break;
+ case BINOP_GEQ: strcpy(ptr,">="); break;
+ case BINOP_LEQ: strcpy(ptr,"<="); break;
+ case BINOP_MOD: /* invalid */
+ default:
+ error ("Invalid binary operation specified.");
+ }
+
+ argvec[0] = value_struct_elt (&arg1, argvec+1, tstr, &static_memfuncp, "structure");
+
+ if (argvec[0])
+ {
+ if (static_memfuncp)
+ {
+ argvec[1] = argvec[0];
+ argvec++;
+ }
+ return call_function_by_hand (argvec[0], 2 - static_memfuncp, argvec + 1);
+ }
+ error ("member function %s not found", tstr);
+#ifdef lint
+ return call_function_by_hand (argvec[0], 2 - static_memfuncp, argvec + 1);
+#endif
+}
+
+/* We know that arg1 is a structure, so try to find a unary user
+ defined operator that matches the operator in question.
+ Create an argument vector that calls arg1.operator @ (arg1)
+ and return that value (where '@' is (almost) any unary operator which
+ is legal for GNU C++). */
+
+value_ptr
+value_x_unop (arg1, op)
+ value_ptr arg1;
+ enum exp_opcode op;
+{
+ value_ptr * argvec;
+ char *ptr, *mangle_ptr;
+ char tstr[13], mangle_tstr[13];
+ int static_memfuncp;
+
+ COERCE_ENUM (arg1);
+
+ /* now we know that what we have to do is construct our
+ arg vector and find the right function to call it with. */
+
+ if (TYPE_CODE (VALUE_TYPE (arg1)) != TYPE_CODE_STRUCT)
+ error ("Can't do that unary op on that type"); /* FIXME be explicit */
+
+ argvec = (value_ptr *) alloca (sizeof (value_ptr) * 3);
+ argvec[1] = value_addr (arg1);
+ argvec[2] = 0;
+
+ /* make the right function name up */
+ strcpy(tstr,"operator__");
+ ptr = tstr+8;
+ strcpy(mangle_tstr, "__");
+ mangle_ptr = mangle_tstr+2;
+ switch (op)
+ {
+ case UNOP_PREINCREMENT: strcpy(ptr,"++"); break;
+ case UNOP_PREDECREMENT: strcpy(ptr,"++"); break;
+ case UNOP_POSTINCREMENT: strcpy(ptr,"++"); break;
+ case UNOP_POSTDECREMENT: strcpy(ptr,"++"); break;
+ case UNOP_LOGICAL_NOT: strcpy(ptr,"!"); break;
+ case UNOP_COMPLEMENT: strcpy(ptr,"~"); break;
+ case UNOP_NEG: strcpy(ptr,"-"); break;
+ default:
+ error ("Invalid binary operation specified.");
+ }
+
+ argvec[0] = value_struct_elt (&arg1, argvec+1, tstr, &static_memfuncp, "structure");
+
+ if (argvec[0])
+ {
+ if (static_memfuncp)
+ {
+ argvec[1] = argvec[0];
+ argvec++;
+ }
+ return call_function_by_hand (argvec[0], 1 - static_memfuncp, argvec + 1);
+ }
+ error ("member function %s not found", tstr);
+ return 0; /* For lint -- never reached */
+}
+
+
+/* Concatenate two values with the following conditions:
+
+ (1) Both values must be either bitstring values or character string
+ values and the resulting value consists of the concatenation of
+ ARG1 followed by ARG2.
+
+ or
+
+ One value must be an integer value and the other value must be
+ either a bitstring value or character string value, which is
+ to be repeated by the number of times specified by the integer
+ value.
+
+
+ (2) Boolean values are also allowed and are treated as bit string
+ values of length 1.
+
+ (3) Character values are also allowed and are treated as character
+ string values of length 1.
+*/
+
+value_ptr
+value_concat (arg1, arg2)
+ value_ptr arg1, arg2;
+{
+ register value_ptr inval1, inval2, outval;
+ int inval1len, inval2len;
+ int count, idx;
+ char *ptr;
+ char inchar;
+
+ /* First figure out if we are dealing with two values to be concatenated
+ or a repeat count and a value to be repeated. INVAL1 is set to the
+ first of two concatenated values, or the repeat count. INVAL2 is set
+ to the second of the two concatenated values or the value to be
+ repeated. */
+
+ if (TYPE_CODE (VALUE_TYPE (arg2)) == TYPE_CODE_INT)
+ {
+ inval1 = arg2;
+ inval2 = arg1;
+ }
+ else
+ {
+ inval1 = arg1;
+ inval2 = arg2;
+ }
+
+ /* Now process the input values. */
+
+ if (TYPE_CODE (VALUE_TYPE (inval1)) == TYPE_CODE_INT)
+ {
+ /* We have a repeat count. Validate the second value and then
+ construct a value repeated that many times. */
+ if (TYPE_CODE (VALUE_TYPE (inval2)) == TYPE_CODE_STRING
+ || TYPE_CODE (VALUE_TYPE (inval2)) == TYPE_CODE_CHAR)
+ {
+ count = longest_to_int (value_as_long (inval1));
+ inval2len = TYPE_LENGTH (VALUE_TYPE (inval2));
+ ptr = (char *) alloca (count * inval2len);
+ if (TYPE_CODE (VALUE_TYPE (inval2)) == TYPE_CODE_CHAR)
+ {
+ inchar = (char) unpack_long (VALUE_TYPE (inval2),
+ VALUE_CONTENTS (inval2));
+ for (idx = 0; idx < count; idx++)
+ {
+ *(ptr + idx) = inchar;
+ }
+ }
+ else
+ {
+ for (idx = 0; idx < count; idx++)
+ {
+ memcpy (ptr + (idx * inval2len), VALUE_CONTENTS (inval2),
+ inval2len);
+ }
+ }
+ outval = value_string (ptr, count * inval2len);
+ }
+ else if (TYPE_CODE (VALUE_TYPE (inval2)) == TYPE_CODE_BITSTRING
+ || TYPE_CODE (VALUE_TYPE (inval2)) == TYPE_CODE_BOOL)
+ {
+ error ("unimplemented support for bitstring/boolean repeats");
+ }
+ else
+ {
+ error ("can't repeat values of that type");
+ }
+ }
+ else if (TYPE_CODE (VALUE_TYPE (inval1)) == TYPE_CODE_STRING
+ || TYPE_CODE (VALUE_TYPE (inval1)) == TYPE_CODE_CHAR)
+ {
+ /* We have two character strings to concatenate. */
+ if (TYPE_CODE (VALUE_TYPE (inval2)) != TYPE_CODE_STRING
+ && TYPE_CODE (VALUE_TYPE (inval2)) != TYPE_CODE_CHAR)
+ {
+ error ("Strings can only be concatenated with other strings.");
+ }
+ inval1len = TYPE_LENGTH (VALUE_TYPE (inval1));
+ inval2len = TYPE_LENGTH (VALUE_TYPE (inval2));
+ ptr = (char *) alloca (inval1len + inval2len);
+ if (TYPE_CODE (VALUE_TYPE (inval1)) == TYPE_CODE_CHAR)
+ {
+ *ptr = (char) unpack_long (VALUE_TYPE (inval1), VALUE_CONTENTS (inval1));
+ }
+ else
+ {
+ memcpy (ptr, VALUE_CONTENTS (inval1), inval1len);
+ }
+ if (TYPE_CODE (VALUE_TYPE (inval2)) == TYPE_CODE_CHAR)
+ {
+ *(ptr + inval1len) =
+ (char) unpack_long (VALUE_TYPE (inval2), VALUE_CONTENTS (inval2));
+ }
+ else
+ {
+ memcpy (ptr + inval1len, VALUE_CONTENTS (inval2), inval2len);
+ }
+ outval = value_string (ptr, inval1len + inval2len);
+ }
+ else if (TYPE_CODE (VALUE_TYPE (inval1)) == TYPE_CODE_BITSTRING
+ || TYPE_CODE (VALUE_TYPE (inval1)) == TYPE_CODE_BOOL)
+ {
+ /* We have two bitstrings to concatenate. */
+ if (TYPE_CODE (VALUE_TYPE (inval2)) != TYPE_CODE_BITSTRING
+ && TYPE_CODE (VALUE_TYPE (inval2)) != TYPE_CODE_BOOL)
+ {
+ error ("Bitstrings or booleans can only be concatenated with other bitstrings or booleans.");
+ }
+ error ("unimplemented support for bitstring/boolean concatenation.");
+ }
+ else
+ {
+ /* We don't know how to concatenate these operands. */
+ error ("illegal operands for concatenation.");
+ }
+ return (outval);
+}
+
+
+
+/* Perform a binary operation on two operands which have reasonable
+ representations as integers or floats. This includes booleans,
+ characters, integers, or floats.
+ Does not support addition and subtraction on pointers;
+ use value_add or value_sub if you want to handle those possibilities. */
+
+value_ptr
+value_binop (arg1, arg2, op)
+ value_ptr arg1, arg2;
+ enum exp_opcode op;
+{
+ register value_ptr val;
+
+ COERCE_ENUM (arg1);
+ COERCE_ENUM (arg2);
+
+ if ((TYPE_CODE (VALUE_TYPE (arg1)) != TYPE_CODE_FLT
+ && TYPE_CODE (VALUE_TYPE (arg1)) != TYPE_CODE_CHAR
+ && TYPE_CODE (VALUE_TYPE (arg1)) != TYPE_CODE_INT
+ && TYPE_CODE (VALUE_TYPE (arg1)) != TYPE_CODE_BOOL
+ && TYPE_CODE (VALUE_TYPE (arg1)) != TYPE_CODE_RANGE)
+ ||
+ (TYPE_CODE (VALUE_TYPE (arg2)) != TYPE_CODE_FLT
+ && TYPE_CODE (VALUE_TYPE (arg2)) != TYPE_CODE_CHAR
+ && TYPE_CODE (VALUE_TYPE (arg2)) != TYPE_CODE_INT
+ && TYPE_CODE (VALUE_TYPE (arg2)) != TYPE_CODE_BOOL
+ && TYPE_CODE (VALUE_TYPE (arg2)) != TYPE_CODE_RANGE))
+ error ("Argument to arithmetic operation not a number or boolean.");
+
+ if (TYPE_CODE (VALUE_TYPE (arg1)) == TYPE_CODE_FLT
+ ||
+ TYPE_CODE (VALUE_TYPE (arg2)) == TYPE_CODE_FLT)
+ {
+ /* FIXME-if-picky-about-floating-accuracy: Should be doing this
+ in target format. real.c in GCC probably has the necessary
+ code. */
+ double v1, v2, v;
+ v1 = value_as_double (arg1);
+ v2 = value_as_double (arg2);
+ switch (op)
+ {
+ case BINOP_ADD:
+ v = v1 + v2;
+ break;
+
+ case BINOP_SUB:
+ v = v1 - v2;
+ break;
+
+ case BINOP_MUL:
+ v = v1 * v2;
+ break;
+
+ case BINOP_DIV:
+ v = v1 / v2;
+ break;
+
+ default:
+ error ("Integer-only operation on floating point number.");
+ }
+
+ val = allocate_value (builtin_type_double);
+ store_floating (VALUE_CONTENTS_RAW (val), TYPE_LENGTH (VALUE_TYPE (val)),
+ v);
+ }
+ else if (TYPE_CODE (VALUE_TYPE (arg1)) == TYPE_CODE_BOOL
+ &&
+ TYPE_CODE (VALUE_TYPE (arg2)) == TYPE_CODE_BOOL)
+ {
+ LONGEST v1, v2, v;
+ v1 = value_as_long (arg1);
+ v2 = value_as_long (arg2);
+
+ switch (op)
+ {
+ case BINOP_BITWISE_AND:
+ v = v1 & v2;
+ break;
+
+ case BINOP_BITWISE_IOR:
+ v = v1 | v2;
+ break;
+
+ case BINOP_BITWISE_XOR:
+ v = v1 ^ v2;
+ break;
+
+ default:
+ error ("Invalid operation on booleans.");
+ }
+
+ val = allocate_value (builtin_type_chill_bool);
+ store_signed_integer (VALUE_CONTENTS_RAW (val),
+ TYPE_LENGTH (VALUE_TYPE (val)),
+ v);
+ }
+ else
+ /* Integral operations here. */
+ /* FIXME: Also mixed integral/booleans, with result an integer. */
+ {
+ /* Should we promote to unsigned longest? */
+ if ((TYPE_UNSIGNED (VALUE_TYPE (arg1))
+ || TYPE_UNSIGNED (VALUE_TYPE (arg2)))
+ && (TYPE_LENGTH (VALUE_TYPE (arg1)) >= sizeof (unsigned LONGEST)
+ || TYPE_LENGTH (VALUE_TYPE (arg2)) >= sizeof (unsigned LONGEST)))
+ {
+ unsigned LONGEST v1, v2, v;
+ v1 = (unsigned LONGEST) value_as_long (arg1);
+ v2 = (unsigned LONGEST) value_as_long (arg2);
+
+ switch (op)
+ {
+ case BINOP_ADD:
+ v = v1 + v2;
+ break;
+
+ case BINOP_SUB:
+ v = v1 - v2;
+ break;
+
+ case BINOP_MUL:
+ v = v1 * v2;
+ break;
+
+ case BINOP_DIV:
+ v = v1 / v2;
+ break;
+
+ case BINOP_REM:
+ v = v1 % v2;
+ break;
+
+ case BINOP_MOD:
+ /* Knuth 1.2.4, integer only. Note that unlike the C '%' op,
+ v1 mod 0 has a defined value, v1. */
+ /* Chill specifies that v2 must be > 0, so check for that. */
+ if (current_language -> la_language == language_chill
+ && value_as_long (arg2) <= 0)
+ {
+ error ("Second operand of MOD must be greater than zero.");
+ }
+ if (v2 == 0)
+ {
+ v = v1;
+ }
+ else
+ {
+ v = v1/v2;
+ /* Note floor(v1/v2) == v1/v2 for unsigned. */
+ v = v1 - (v2 * v);
+ }
+ break;
+
+ case BINOP_LSH:
+ v = v1 << v2;
+ break;
+
+ case BINOP_RSH:
+ v = v1 >> v2;
+ break;
+
+ case BINOP_BITWISE_AND:
+ v = v1 & v2;
+ break;
+
+ case BINOP_BITWISE_IOR:
+ v = v1 | v2;
+ break;
+
+ case BINOP_BITWISE_XOR:
+ v = v1 ^ v2;
+ break;
+
+ case BINOP_LOGICAL_AND:
+ v = v1 && v2;
+ break;
+
+ case BINOP_LOGICAL_OR:
+ v = v1 || v2;
+ break;
+
+ case BINOP_MIN:
+ v = v1 < v2 ? v1 : v2;
+ break;
+
+ case BINOP_MAX:
+ v = v1 > v2 ? v1 : v2;
+ break;
+
+ default:
+ error ("Invalid binary operation on numbers.");
+ }
+
+ /* This is a kludge to get around the fact that we don't
+ know how to determine the result type from the types of
+ the operands. (I'm not really sure how much we feel the
+ need to duplicate the exact rules of the current
+ language. They can get really hairy. But not to do so
+ makes it hard to document just what we *do* do). */
+
+ /* Can't just call init_type because we wouldn't know what
+ name to give the type. */
+ val = allocate_value
+ (sizeof (LONGEST) > TARGET_LONG_BIT / HOST_CHAR_BIT
+ ? builtin_type_unsigned_long_long
+ : builtin_type_unsigned_long);
+ store_unsigned_integer (VALUE_CONTENTS_RAW (val),
+ TYPE_LENGTH (VALUE_TYPE (val)),
+ v);
+ }
+ else
+ {
+ LONGEST v1, v2, v;
+ v1 = value_as_long (arg1);
+ v2 = value_as_long (arg2);
+
+ switch (op)
+ {
+ case BINOP_ADD:
+ v = v1 + v2;
+ break;
+
+ case BINOP_SUB:
+ v = v1 - v2;
+ break;
+
+ case BINOP_MUL:
+ v = v1 * v2;
+ break;
+
+ case BINOP_DIV:
+ v = v1 / v2;
+ break;
+
+ case BINOP_REM:
+ v = v1 % v2;
+ break;
+
+ case BINOP_MOD:
+ /* Knuth 1.2.4, integer only. Note that unlike the C '%' op,
+ X mod 0 has a defined value, X. */
+ /* Chill specifies that v2 must be > 0, so check for that. */
+ if (current_language -> la_language == language_chill
+ && v2 <= 0)
+ {
+ error ("Second operand of MOD must be greater than zero.");
+ }
+ if (v2 == 0)
+ {
+ v = v1;
+ }
+ else
+ {
+ v = v1/v2;
+ /* Compute floor. */
+ if (TRUNCATION_TOWARDS_ZERO && (v < 0) && ((v1 % v2) != 0))
+ {
+ v--;
+ }
+ v = v1 - (v2 * v);
+ }
+ break;
+
+ case BINOP_LSH:
+ v = v1 << v2;
+ break;
+
+ case BINOP_RSH:
+ v = v1 >> v2;
+ break;
+
+ case BINOP_BITWISE_AND:
+ v = v1 & v2;
+ break;
+
+ case BINOP_BITWISE_IOR:
+ v = v1 | v2;
+ break;
+
+ case BINOP_BITWISE_XOR:
+ v = v1 ^ v2;
+ break;
+
+ case BINOP_LOGICAL_AND:
+ v = v1 && v2;
+ break;
+
+ case BINOP_LOGICAL_OR:
+ v = v1 || v2;
+ break;
+
+ case BINOP_MIN:
+ v = v1 < v2 ? v1 : v2;
+ break;
+
+ case BINOP_MAX:
+ v = v1 > v2 ? v1 : v2;
+ break;
+
+ default:
+ error ("Invalid binary operation on numbers.");
+ }
+
+ /* This is a kludge to get around the fact that we don't
+ know how to determine the result type from the types of
+ the operands. (I'm not really sure how much we feel the
+ need to duplicate the exact rules of the current
+ language. They can get really hairy. But not to do so
+ makes it hard to document just what we *do* do). */
+
+ /* Can't just call init_type because we wouldn't know what
+ name to give the type. */
+ val = allocate_value
+ (sizeof (LONGEST) > TARGET_LONG_BIT / HOST_CHAR_BIT
+ ? builtin_type_long_long
+ : builtin_type_long);
+ store_signed_integer (VALUE_CONTENTS_RAW (val),
+ TYPE_LENGTH (VALUE_TYPE (val)),
+ v);
+ }
+ }
+
+ return val;
+}
+
+/* Simulate the C operator ! -- return 1 if ARG1 contains zero. */
+
+int
+value_logical_not (arg1)
+ value_ptr arg1;
+{
+ register int len;
+ register char *p;
+
+ COERCE_ARRAY (arg1);
+
+ if (TYPE_CODE (VALUE_TYPE (arg1)) == TYPE_CODE_FLT)
+ return 0 == value_as_double (arg1);
+
+ len = TYPE_LENGTH (VALUE_TYPE (arg1));
+ p = VALUE_CONTENTS (arg1);
+
+ while (--len >= 0)
+ {
+ if (*p++)
+ break;
+ }
+
+ return len < 0;
+}
+
+/* Simulate the C operator == by returning a 1
+ iff ARG1 and ARG2 have equal contents. */
+
+int
+value_equal (arg1, arg2)
+ register value_ptr arg1, arg2;
+
+{
+ register int len;
+ register char *p1, *p2;
+ enum type_code code1;
+ enum type_code code2;
+
+ COERCE_ARRAY (arg1);
+ COERCE_ARRAY (arg2);
+
+ code1 = TYPE_CODE (VALUE_TYPE (arg1));
+ code2 = TYPE_CODE (VALUE_TYPE (arg2));
+
+ if (code1 == TYPE_CODE_INT && code2 == TYPE_CODE_INT)
+ return value_as_long (arg1) == value_as_long (arg2);
+ else if ((code1 == TYPE_CODE_FLT || code1 == TYPE_CODE_INT)
+ && (code2 == TYPE_CODE_FLT || code2 == TYPE_CODE_INT))
+ return value_as_double (arg1) == value_as_double (arg2);
+
+ /* FIXME: Need to promote to either CORE_ADDR or LONGEST, whichever
+ is bigger. */
+ else if (code1 == TYPE_CODE_PTR && code2 == TYPE_CODE_INT)
+ return value_as_pointer (arg1) == (CORE_ADDR) value_as_long (arg2);
+ else if (code2 == TYPE_CODE_PTR && code1 == TYPE_CODE_INT)
+ return (CORE_ADDR) value_as_long (arg1) == value_as_pointer (arg2);
+
+ else if (code1 == code2
+ && ((len = TYPE_LENGTH (VALUE_TYPE (arg1)))
+ == TYPE_LENGTH (VALUE_TYPE (arg2))))
+ {
+ p1 = VALUE_CONTENTS (arg1);
+ p2 = VALUE_CONTENTS (arg2);
+ while (--len >= 0)
+ {
+ if (*p1++ != *p2++)
+ break;
+ }
+ return len < 0;
+ }
+ else
+ {
+ error ("Invalid type combination in equality test.");
+ return 0; /* For lint -- never reached */
+ }
+}
+
+/* Simulate the C operator < by returning 1
+ iff ARG1's contents are less than ARG2's. */
+
+int
+value_less (arg1, arg2)
+ register value_ptr arg1, arg2;
+{
+ register enum type_code code1;
+ register enum type_code code2;
+
+ COERCE_ARRAY (arg1);
+ COERCE_ARRAY (arg2);
+
+ code1 = TYPE_CODE (VALUE_TYPE (arg1));
+ code2 = TYPE_CODE (VALUE_TYPE (arg2));
+
+ if (code1 == TYPE_CODE_INT && code2 == TYPE_CODE_INT)
+ {
+ if (TYPE_UNSIGNED (VALUE_TYPE (arg1))
+ || TYPE_UNSIGNED (VALUE_TYPE (arg2)))
+ return ((unsigned LONGEST) value_as_long (arg1)
+ < (unsigned LONGEST) value_as_long (arg2));
+ else
+ return value_as_long (arg1) < value_as_long (arg2);
+ }
+ else if ((code1 == TYPE_CODE_FLT || code1 == TYPE_CODE_INT)
+ && (code2 == TYPE_CODE_FLT || code2 == TYPE_CODE_INT))
+ return value_as_double (arg1) < value_as_double (arg2);
+ else if (code1 == TYPE_CODE_PTR && code2 == TYPE_CODE_PTR)
+ return value_as_pointer (arg1) < value_as_pointer (arg2);
+
+ /* FIXME: Need to promote to either CORE_ADDR or LONGEST, whichever
+ is bigger. */
+ else if (code1 == TYPE_CODE_PTR && code2 == TYPE_CODE_INT)
+ return value_as_pointer (arg1) < (CORE_ADDR) value_as_long (arg2);
+ else if (code2 == TYPE_CODE_PTR && code1 == TYPE_CODE_INT)
+ return (CORE_ADDR) value_as_long (arg1) < value_as_pointer (arg2);
+
+ else
+ {
+ error ("Invalid type combination in ordering comparison.");
+ return 0;
+ }
+}
+
+/* The unary operators - and ~. Both free the argument ARG1. */
+
+value_ptr
+value_neg (arg1)
+ register value_ptr arg1;
+{
+ register struct type *type;
+
+ COERCE_ENUM (arg1);
+
+ type = VALUE_TYPE (arg1);
+
+ if (TYPE_CODE (type) == TYPE_CODE_FLT)
+ return value_from_double (type, - value_as_double (arg1));
+ else if (TYPE_CODE (type) == TYPE_CODE_INT)
+ return value_from_longest (type, - value_as_long (arg1));
+ else {
+ error ("Argument to negate operation not a number.");
+ return 0; /* For lint -- never reached */
+ }
+}
+
+value_ptr
+value_complement (arg1)
+ register value_ptr arg1;
+{
+ COERCE_ENUM (arg1);
+
+ if (TYPE_CODE (VALUE_TYPE (arg1)) != TYPE_CODE_INT)
+ error ("Argument to complement operation not an integer.");
+
+ return value_from_longest (VALUE_TYPE (arg1), ~ value_as_long (arg1));
+}
+
+/* The INDEX'th bit of SET value whose VALUE_TYPE is TYPE,
+ and whose VALUE_CONTENTS is valaddr.
+ Return -1 if out of range, -2 other error. */
+
+int
+value_bit_index (type, valaddr, index)
+ struct type *type;
+ char *valaddr;
+ int index;
+{
+ struct type *range;
+ int low_bound, high_bound, bit_length;
+ LONGEST word;
+ range = TYPE_FIELD_TYPE (type, 0);
+ if (TYPE_CODE (range) != TYPE_CODE_RANGE)
+ return -2;
+ low_bound = TYPE_LOW_BOUND (range);
+ high_bound = TYPE_HIGH_BOUND (range);
+ if (index < low_bound || index > high_bound)
+ return -1;
+ bit_length = high_bound - low_bound + 1;
+ index -= low_bound;
+ if (bit_length <= TARGET_CHAR_BIT)
+ word = unpack_long (builtin_type_unsigned_char, valaddr);
+ else if (bit_length <= TARGET_SHORT_BIT)
+ word = unpack_long (builtin_type_unsigned_short, valaddr);
+ else
+ {
+ int word_start_index = (index / TARGET_INT_BIT) * TARGET_INT_BIT;
+ index -= word_start_index;
+ word = unpack_long (builtin_type_unsigned_int,
+ valaddr + (word_start_index / HOST_CHAR_BIT));
+ }
+#if BITS_BIG_ENDIAN
+ if (bit_length <= TARGET_CHAR_BIT)
+ index = TARGET_CHAR_BIT - 1 - index;
+ else if (bit_length <= TARGET_SHORT_BIT)
+ index = TARGET_SHORT_BIT - 1 - index;
+ else
+ index = TARGET_INT_BIT - 1 - index;
+#endif
+ return (word >> index) & 1;
+}
+
+value_ptr
+value_in (element, set)
+ value_ptr element, set;
+{
+ int member;
+ if (TYPE_CODE (VALUE_TYPE (set)) != TYPE_CODE_SET)
+ error ("Second argument of 'IN' has wrong type");
+ if (TYPE_CODE (VALUE_TYPE (element)) != TYPE_CODE_INT
+ && TYPE_CODE (VALUE_TYPE (element)) != TYPE_CODE_CHAR
+ && TYPE_CODE (VALUE_TYPE (element)) != TYPE_CODE_ENUM
+ && TYPE_CODE (VALUE_TYPE (element)) != TYPE_CODE_BOOL)
+ error ("First argument of 'IN' has wrong type");
+ member = value_bit_index (VALUE_TYPE (set), VALUE_CONTENTS (set),
+ value_as_long (element));
+ if (member < 0)
+ error ("First argument of 'IN' not in range");
+ return value_from_longest (builtin_type_int, member);
+}
+
+void
+_initialize_valarith ()
+{
+}
diff --git a/gnu/usr.bin/gdb/gdb/valops.c b/gnu/usr.bin/gdb/gdb/valops.c
new file mode 100644
index 0000000..f84db12
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/valops.c
@@ -0,0 +1,1898 @@
+/* Perform non-arithmetic operations on values, for GDB.
+ Copyright 1986, 1987, 1989, 1991, 1992, 1993, 1994
+ Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "defs.h"
+#include "symtab.h"
+#include "gdbtypes.h"
+#include "value.h"
+#include "frame.h"
+#include "inferior.h"
+#include "gdbcore.h"
+#include "target.h"
+#include "demangle.h"
+#include "language.h"
+
+#include <errno.h>
+
+/* Local functions. */
+
+static int typecmp PARAMS ((int staticp, struct type *t1[], value_ptr t2[]));
+
+static CORE_ADDR find_function_addr PARAMS ((value_ptr, struct type **));
+
+static CORE_ADDR value_push PARAMS ((CORE_ADDR, value_ptr));
+
+static CORE_ADDR value_arg_push PARAMS ((CORE_ADDR, value_ptr));
+
+static value_ptr search_struct_field PARAMS ((char *, value_ptr, int,
+ struct type *, int));
+
+static value_ptr search_struct_method PARAMS ((char *, value_ptr *,
+ value_ptr *,
+ int, int *, struct type *));
+
+static int
+check_field_in PARAMS ((struct type *, const char *));
+
+static CORE_ADDR
+allocate_space_in_inferior PARAMS ((int));
+
+
+/* Allocate NBYTES of space in the inferior using the inferior's malloc
+ and return a value that is a pointer to the allocated space. */
+
+static CORE_ADDR
+allocate_space_in_inferior (len)
+ int len;
+{
+ register value_ptr val;
+ register struct symbol *sym;
+ struct minimal_symbol *msymbol;
+ struct type *type;
+ value_ptr blocklen;
+ LONGEST maddr;
+
+ /* Find the address of malloc in the inferior. */
+
+ sym = lookup_symbol ("malloc", 0, VAR_NAMESPACE, 0, NULL);
+ if (sym != NULL)
+ {
+ if (SYMBOL_CLASS (sym) != LOC_BLOCK)
+ {
+ error ("\"malloc\" exists in this program but is not a function.");
+ }
+ val = value_of_variable (sym, NULL);
+ }
+ else
+ {
+ msymbol = lookup_minimal_symbol ("malloc", (struct objfile *) NULL);
+ if (msymbol != NULL)
+ {
+ type = lookup_pointer_type (builtin_type_char);
+ type = lookup_function_type (type);
+ type = lookup_pointer_type (type);
+ maddr = (LONGEST) SYMBOL_VALUE_ADDRESS (msymbol);
+ val = value_from_longest (type, maddr);
+ }
+ else
+ {
+ error ("evaluation of this expression requires the program to have a function \"malloc\".");
+ }
+ }
+
+ blocklen = value_from_longest (builtin_type_int, (LONGEST) len);
+ val = call_function_by_hand (val, 1, &blocklen);
+ if (value_logical_not (val))
+ {
+ error ("No memory available to program.");
+ }
+ return (value_as_long (val));
+}
+
+/* Cast value ARG2 to type TYPE and return as a value.
+ More general than a C cast: accepts any two types of the same length,
+ and if ARG2 is an lvalue it can be cast into anything at all. */
+/* In C++, casts may change pointer or object representations. */
+
+value_ptr
+value_cast (type, arg2)
+ struct type *type;
+ register value_ptr arg2;
+{
+ register enum type_code code1;
+ register enum type_code code2;
+ register int scalar;
+
+ /* Coerce arrays but not enums. Enums will work as-is
+ and coercing them would cause an infinite recursion. */
+ if (TYPE_CODE (VALUE_TYPE (arg2)) != TYPE_CODE_ENUM)
+ COERCE_ARRAY (arg2);
+
+ code1 = TYPE_CODE (type);
+ code2 = TYPE_CODE (VALUE_TYPE (arg2));
+ scalar = (code2 == TYPE_CODE_INT || code2 == TYPE_CODE_FLT
+ || code2 == TYPE_CODE_ENUM);
+
+ if ( code1 == TYPE_CODE_STRUCT
+ && code2 == TYPE_CODE_STRUCT
+ && TYPE_NAME (type) != 0)
+ {
+ /* Look in the type of the source to see if it contains the
+ type of the target as a superclass. If so, we'll need to
+ offset the object in addition to changing its type. */
+ value_ptr v = search_struct_field (type_name_no_tag (type),
+ arg2, 0, VALUE_TYPE (arg2), 1);
+ if (v)
+ {
+ VALUE_TYPE (v) = type;
+ return v;
+ }
+ }
+ if (code1 == TYPE_CODE_FLT && scalar)
+ return value_from_double (type, value_as_double (arg2));
+ else if ((code1 == TYPE_CODE_INT || code1 == TYPE_CODE_ENUM)
+ && (scalar || code2 == TYPE_CODE_PTR))
+ return value_from_longest (type, value_as_long (arg2));
+ else if (TYPE_LENGTH (type) == TYPE_LENGTH (VALUE_TYPE (arg2)))
+ {
+ if (code1 == TYPE_CODE_PTR && code2 == TYPE_CODE_PTR)
+ {
+ /* Look in the type of the source to see if it contains the
+ type of the target as a superclass. If so, we'll need to
+ offset the pointer rather than just change its type. */
+ struct type *t1 = TYPE_TARGET_TYPE (type);
+ struct type *t2 = TYPE_TARGET_TYPE (VALUE_TYPE (arg2));
+ if ( TYPE_CODE (t1) == TYPE_CODE_STRUCT
+ && TYPE_CODE (t2) == TYPE_CODE_STRUCT
+ && TYPE_NAME (t1) != 0) /* if name unknown, can't have supercl */
+ {
+ value_ptr v = search_struct_field (type_name_no_tag (t1),
+ value_ind (arg2), 0, t2, 1);
+ if (v)
+ {
+ v = value_addr (v);
+ VALUE_TYPE (v) = type;
+ return v;
+ }
+ }
+ /* No superclass found, just fall through to change ptr type. */
+ }
+ VALUE_TYPE (arg2) = type;
+ return arg2;
+ }
+ else if (VALUE_LVAL (arg2) == lval_memory)
+ {
+ return value_at_lazy (type, VALUE_ADDRESS (arg2) + VALUE_OFFSET (arg2));
+ }
+ else if (code1 == TYPE_CODE_VOID)
+ {
+ return value_zero (builtin_type_void, not_lval);
+ }
+ else
+ {
+ error ("Invalid cast.");
+ return 0;
+ }
+}
+
+/* Create a value of type TYPE that is zero, and return it. */
+
+value_ptr
+value_zero (type, lv)
+ struct type *type;
+ enum lval_type lv;
+{
+ register value_ptr val = allocate_value (type);
+
+ memset (VALUE_CONTENTS (val), 0, TYPE_LENGTH (type));
+ VALUE_LVAL (val) = lv;
+
+ return val;
+}
+
+/* Return a value with type TYPE located at ADDR.
+
+ Call value_at only if the data needs to be fetched immediately;
+ if we can be 'lazy' and defer the fetch, perhaps indefinately, call
+ value_at_lazy instead. value_at_lazy simply records the address of
+ the data and sets the lazy-evaluation-required flag. The lazy flag
+ is tested in the VALUE_CONTENTS macro, which is used if and when
+ the contents are actually required. */
+
+value_ptr
+value_at (type, addr)
+ struct type *type;
+ CORE_ADDR addr;
+{
+ register value_ptr val;
+
+ if (TYPE_CODE (type) == TYPE_CODE_VOID)
+ error ("Attempt to dereference a generic pointer.");
+
+ val = allocate_value (type);
+
+ read_memory (addr, VALUE_CONTENTS_RAW (val), TYPE_LENGTH (type));
+
+ VALUE_LVAL (val) = lval_memory;
+ VALUE_ADDRESS (val) = addr;
+
+ return val;
+}
+
+/* Return a lazy value with type TYPE located at ADDR (cf. value_at). */
+
+value_ptr
+value_at_lazy (type, addr)
+ struct type *type;
+ CORE_ADDR addr;
+{
+ register value_ptr val;
+
+ if (TYPE_CODE (type) == TYPE_CODE_VOID)
+ error ("Attempt to dereference a generic pointer.");
+
+ val = allocate_value (type);
+
+ VALUE_LVAL (val) = lval_memory;
+ VALUE_ADDRESS (val) = addr;
+ VALUE_LAZY (val) = 1;
+
+ return val;
+}
+
+/* Called only from the VALUE_CONTENTS macro, if the current data for
+ a variable needs to be loaded into VALUE_CONTENTS(VAL). Fetches the
+ data from the user's process, and clears the lazy flag to indicate
+ that the data in the buffer is valid.
+
+ If the value is zero-length, we avoid calling read_memory, which would
+ abort. We mark the value as fetched anyway -- all 0 bytes of it.
+
+ This function returns a value because it is used in the VALUE_CONTENTS
+ macro as part of an expression, where a void would not work. The
+ value is ignored. */
+
+int
+value_fetch_lazy (val)
+ register value_ptr val;
+{
+ CORE_ADDR addr = VALUE_ADDRESS (val) + VALUE_OFFSET (val);
+
+ if (TYPE_LENGTH (VALUE_TYPE (val)))
+ read_memory (addr, VALUE_CONTENTS_RAW (val),
+ TYPE_LENGTH (VALUE_TYPE (val)));
+ VALUE_LAZY (val) = 0;
+ return 0;
+}
+
+
+/* Store the contents of FROMVAL into the location of TOVAL.
+ Return a new value with the location of TOVAL and contents of FROMVAL. */
+
+value_ptr
+value_assign (toval, fromval)
+ register value_ptr toval, fromval;
+{
+ register struct type *type;
+ register value_ptr val;
+ char raw_buffer[MAX_REGISTER_RAW_SIZE];
+ int use_buffer = 0;
+
+ if (!toval->modifiable)
+ error ("Left operand of assignment is not a modifiable lvalue.");
+
+ COERCE_ARRAY (fromval);
+ COERCE_REF (toval);
+
+ type = VALUE_TYPE (toval);
+ if (VALUE_LVAL (toval) != lval_internalvar)
+ fromval = value_cast (type, fromval);
+
+ /* If TOVAL is a special machine register requiring conversion
+ of program values to a special raw format,
+ convert FROMVAL's contents now, with result in `raw_buffer',
+ and set USE_BUFFER to the number of bytes to write. */
+
+#ifdef REGISTER_CONVERTIBLE
+ if (VALUE_REGNO (toval) >= 0
+ && REGISTER_CONVERTIBLE (VALUE_REGNO (toval)))
+ {
+ int regno = VALUE_REGNO (toval);
+ if (REGISTER_CONVERTIBLE (regno))
+ {
+ REGISTER_CONVERT_TO_RAW (VALUE_TYPE (fromval), regno,
+ VALUE_CONTENTS (fromval), raw_buffer);
+ use_buffer = REGISTER_RAW_SIZE (regno);
+ }
+ }
+#endif
+
+ switch (VALUE_LVAL (toval))
+ {
+ case lval_internalvar:
+ set_internalvar (VALUE_INTERNALVAR (toval), fromval);
+ break;
+
+ case lval_internalvar_component:
+ set_internalvar_component (VALUE_INTERNALVAR (toval),
+ VALUE_OFFSET (toval),
+ VALUE_BITPOS (toval),
+ VALUE_BITSIZE (toval),
+ fromval);
+ break;
+
+ case lval_memory:
+ if (VALUE_BITSIZE (toval))
+ {
+ char buffer[sizeof (LONGEST)];
+ /* We assume that the argument to read_memory is in units of
+ host chars. FIXME: Is that correct? */
+ int len = (VALUE_BITPOS (toval)
+ + VALUE_BITSIZE (toval)
+ + HOST_CHAR_BIT - 1)
+ / HOST_CHAR_BIT;
+
+ if (len > sizeof (LONGEST))
+ error ("Can't handle bitfields which don't fit in a %d bit word.",
+ sizeof (LONGEST) * HOST_CHAR_BIT);
+
+ read_memory (VALUE_ADDRESS (toval) + VALUE_OFFSET (toval),
+ buffer, len);
+ modify_field (buffer, value_as_long (fromval),
+ VALUE_BITPOS (toval), VALUE_BITSIZE (toval));
+ write_memory (VALUE_ADDRESS (toval) + VALUE_OFFSET (toval),
+ buffer, len);
+ }
+ else if (use_buffer)
+ write_memory (VALUE_ADDRESS (toval) + VALUE_OFFSET (toval),
+ raw_buffer, use_buffer);
+ else
+ write_memory (VALUE_ADDRESS (toval) + VALUE_OFFSET (toval),
+ VALUE_CONTENTS (fromval), TYPE_LENGTH (type));
+ break;
+
+ case lval_register:
+ if (VALUE_BITSIZE (toval))
+ {
+ char buffer[sizeof (LONGEST)];
+ int len = REGISTER_RAW_SIZE (VALUE_REGNO (toval));
+
+ if (len > sizeof (LONGEST))
+ error ("Can't handle bitfields in registers larger than %d bits.",
+ sizeof (LONGEST) * HOST_CHAR_BIT);
+
+ if (VALUE_BITPOS (toval) + VALUE_BITSIZE (toval)
+ > len * HOST_CHAR_BIT)
+ /* Getting this right would involve being very careful about
+ byte order. */
+ error ("\
+Can't handle bitfield which doesn't fit in a single register.");
+
+ read_register_bytes (VALUE_ADDRESS (toval) + VALUE_OFFSET (toval),
+ buffer, len);
+ modify_field (buffer, value_as_long (fromval),
+ VALUE_BITPOS (toval), VALUE_BITSIZE (toval));
+ write_register_bytes (VALUE_ADDRESS (toval) + VALUE_OFFSET (toval),
+ buffer, len);
+ }
+ else if (use_buffer)
+ write_register_bytes (VALUE_ADDRESS (toval) + VALUE_OFFSET (toval),
+ raw_buffer, use_buffer);
+ else
+ {
+ /* Do any conversion necessary when storing this type to more
+ than one register. */
+#ifdef REGISTER_CONVERT_FROM_TYPE
+ memcpy (raw_buffer, VALUE_CONTENTS (fromval), TYPE_LENGTH (type));
+ REGISTER_CONVERT_FROM_TYPE(VALUE_REGNO (toval), type, raw_buffer);
+ write_register_bytes (VALUE_ADDRESS (toval) + VALUE_OFFSET (toval),
+ raw_buffer, TYPE_LENGTH (type));
+#else
+ write_register_bytes (VALUE_ADDRESS (toval) + VALUE_OFFSET (toval),
+ VALUE_CONTENTS (fromval), TYPE_LENGTH (type));
+#endif
+ }
+ /* Assigning to the stack pointer, frame pointer, and other
+ (architecture and calling convention specific) registers may
+ cause the frame cache to be out of date. We just do this
+ on all assignments to registers for simplicity; I doubt the slowdown
+ matters. */
+ reinit_frame_cache ();
+ break;
+
+ case lval_reg_frame_relative:
+ {
+ /* value is stored in a series of registers in the frame
+ specified by the structure. Copy that value out, modify
+ it, and copy it back in. */
+ int amount_to_copy = (VALUE_BITSIZE (toval) ? 1 : TYPE_LENGTH (type));
+ int reg_size = REGISTER_RAW_SIZE (VALUE_FRAME_REGNUM (toval));
+ int byte_offset = VALUE_OFFSET (toval) % reg_size;
+ int reg_offset = VALUE_OFFSET (toval) / reg_size;
+ int amount_copied;
+
+ /* Make the buffer large enough in all cases. */
+ char *buffer = (char *) alloca (amount_to_copy
+ + sizeof (LONGEST)
+ + MAX_REGISTER_RAW_SIZE);
+
+ int regno;
+ FRAME frame;
+
+ /* Figure out which frame this is in currently. */
+ for (frame = get_current_frame ();
+ frame && FRAME_FP (frame) != VALUE_FRAME (toval);
+ frame = get_prev_frame (frame))
+ ;
+
+ if (!frame)
+ error ("Value being assigned to is no longer active.");
+
+ amount_to_copy += (reg_size - amount_to_copy % reg_size);
+
+ /* Copy it out. */
+ for ((regno = VALUE_FRAME_REGNUM (toval) + reg_offset,
+ amount_copied = 0);
+ amount_copied < amount_to_copy;
+ amount_copied += reg_size, regno++)
+ {
+ get_saved_register (buffer + amount_copied,
+ (int *)NULL, (CORE_ADDR *)NULL,
+ frame, regno, (enum lval_type *)NULL);
+ }
+
+ /* Modify what needs to be modified. */
+ if (VALUE_BITSIZE (toval))
+ modify_field (buffer + byte_offset,
+ value_as_long (fromval),
+ VALUE_BITPOS (toval), VALUE_BITSIZE (toval));
+ else if (use_buffer)
+ memcpy (buffer + byte_offset, raw_buffer, use_buffer);
+ else
+ memcpy (buffer + byte_offset, VALUE_CONTENTS (fromval),
+ TYPE_LENGTH (type));
+
+ /* Copy it back. */
+ for ((regno = VALUE_FRAME_REGNUM (toval) + reg_offset,
+ amount_copied = 0);
+ amount_copied < amount_to_copy;
+ amount_copied += reg_size, regno++)
+ {
+ enum lval_type lval;
+ CORE_ADDR addr;
+ int optim;
+
+ /* Just find out where to put it. */
+ get_saved_register ((char *)NULL,
+ &optim, &addr, frame, regno, &lval);
+
+ if (optim)
+ error ("Attempt to assign to a value that was optimized out.");
+ if (lval == lval_memory)
+ write_memory (addr, buffer + amount_copied, reg_size);
+ else if (lval == lval_register)
+ write_register_bytes (addr, buffer + amount_copied, reg_size);
+ else
+ error ("Attempt to assign to an unmodifiable value.");
+ }
+ }
+ break;
+
+
+ default:
+ error ("Left operand of assignment is not an lvalue.");
+ }
+
+ /* Return a value just like TOVAL except with the contents of FROMVAL
+ (except in the case of the type if TOVAL is an internalvar). */
+
+ if (VALUE_LVAL (toval) == lval_internalvar
+ || VALUE_LVAL (toval) == lval_internalvar_component)
+ {
+ type = VALUE_TYPE (fromval);
+ }
+
+ val = allocate_value (type);
+ memcpy (val, toval, VALUE_CONTENTS_RAW (val) - (char *) val);
+ memcpy (VALUE_CONTENTS_RAW (val), VALUE_CONTENTS (fromval),
+ TYPE_LENGTH (type));
+ VALUE_TYPE (val) = type;
+
+ return val;
+}
+
+/* Extend a value VAL to COUNT repetitions of its type. */
+
+value_ptr
+value_repeat (arg1, count)
+ value_ptr arg1;
+ int count;
+{
+ register value_ptr val;
+
+ if (VALUE_LVAL (arg1) != lval_memory)
+ error ("Only values in memory can be extended with '@'.");
+ if (count < 1)
+ error ("Invalid number %d of repetitions.", count);
+
+ val = allocate_repeat_value (VALUE_TYPE (arg1), count);
+
+ read_memory (VALUE_ADDRESS (arg1) + VALUE_OFFSET (arg1),
+ VALUE_CONTENTS_RAW (val),
+ TYPE_LENGTH (VALUE_TYPE (val)) * count);
+ VALUE_LVAL (val) = lval_memory;
+ VALUE_ADDRESS (val) = VALUE_ADDRESS (arg1) + VALUE_OFFSET (arg1);
+
+ return val;
+}
+
+value_ptr
+value_of_variable (var, b)
+ struct symbol *var;
+ struct block *b;
+{
+ value_ptr val;
+ FRAME fr;
+
+ if (b == NULL)
+ /* Use selected frame. */
+ fr = NULL;
+ else
+ {
+ fr = block_innermost_frame (b);
+ if (fr == NULL && symbol_read_needs_frame (var))
+ {
+ if (BLOCK_FUNCTION (b) != NULL
+ && SYMBOL_NAME (BLOCK_FUNCTION (b)) != NULL)
+ error ("No frame is currently executing in block %s.",
+ SYMBOL_NAME (BLOCK_FUNCTION (b)));
+ else
+ error ("No frame is currently executing in specified block");
+ }
+ }
+ val = read_var_value (var, fr);
+ if (val == 0)
+ error ("Address of symbol \"%s\" is unknown.", SYMBOL_SOURCE_NAME (var));
+ return val;
+}
+
+/* Given a value which is an array, return a value which is a pointer to its
+ first element, regardless of whether or not the array has a nonzero lower
+ bound.
+
+ FIXME: A previous comment here indicated that this routine should be
+ substracting the array's lower bound. It's not clear to me that this
+ is correct. Given an array subscripting operation, it would certainly
+ work to do the adjustment here, essentially computing:
+
+ (&array[0] - (lowerbound * sizeof array[0])) + (index * sizeof array[0])
+
+ However I believe a more appropriate and logical place to account for
+ the lower bound is to do so in value_subscript, essentially computing:
+
+ (&array[0] + ((index - lowerbound) * sizeof array[0]))
+
+ As further evidence consider what would happen with operations other
+ than array subscripting, where the caller would get back a value that
+ had an address somewhere before the actual first element of the array,
+ and the information about the lower bound would be lost because of
+ the coercion to pointer type.
+ */
+
+value_ptr
+value_coerce_array (arg1)
+ value_ptr arg1;
+{
+ register struct type *type;
+
+ if (VALUE_LVAL (arg1) != lval_memory)
+ error ("Attempt to take address of value not located in memory.");
+
+ /* Get type of elements. */
+ if (TYPE_CODE (VALUE_TYPE (arg1)) == TYPE_CODE_ARRAY
+ || TYPE_CODE (VALUE_TYPE (arg1)) == TYPE_CODE_STRING)
+ type = TYPE_TARGET_TYPE (VALUE_TYPE (arg1));
+ else
+ /* A phony array made by value_repeat.
+ Its type is the type of the elements, not an array type. */
+ type = VALUE_TYPE (arg1);
+
+ return value_from_longest (lookup_pointer_type (type),
+ (LONGEST) (VALUE_ADDRESS (arg1) + VALUE_OFFSET (arg1)));
+}
+
+/* Given a value which is a function, return a value which is a pointer
+ to it. */
+
+value_ptr
+value_coerce_function (arg1)
+ value_ptr arg1;
+{
+
+ if (VALUE_LVAL (arg1) != lval_memory)
+ error ("Attempt to take address of value not located in memory.");
+
+ return value_from_longest (lookup_pointer_type (VALUE_TYPE (arg1)),
+ (LONGEST) (VALUE_ADDRESS (arg1) + VALUE_OFFSET (arg1)));
+}
+
+/* Return a pointer value for the object for which ARG1 is the contents. */
+
+value_ptr
+value_addr (arg1)
+ value_ptr arg1;
+{
+ struct type *type = VALUE_TYPE (arg1);
+ if (TYPE_CODE (type) == TYPE_CODE_REF)
+ {
+ /* Copy the value, but change the type from (T&) to (T*).
+ We keep the same location information, which is efficient,
+ and allows &(&X) to get the location containing the reference. */
+ value_ptr arg2 = value_copy (arg1);
+ VALUE_TYPE (arg2) = lookup_pointer_type (TYPE_TARGET_TYPE (type));
+ return arg2;
+ }
+ if (VALUE_REPEATED (arg1)
+ || TYPE_CODE (type) == TYPE_CODE_ARRAY)
+ return value_coerce_array (arg1);
+ if (TYPE_CODE (type) == TYPE_CODE_FUNC)
+ return value_coerce_function (arg1);
+
+ if (VALUE_LVAL (arg1) != lval_memory)
+ error ("Attempt to take address of value not located in memory.");
+
+ return value_from_longest (lookup_pointer_type (type),
+ (LONGEST) (VALUE_ADDRESS (arg1) + VALUE_OFFSET (arg1)));
+}
+
+/* Given a value of a pointer type, apply the C unary * operator to it. */
+
+value_ptr
+value_ind (arg1)
+ value_ptr arg1;
+{
+ COERCE_ARRAY (arg1);
+
+ if (TYPE_CODE (VALUE_TYPE (arg1)) == TYPE_CODE_MEMBER)
+ error ("not implemented: member types in value_ind");
+
+ /* Allow * on an integer so we can cast it to whatever we want.
+ This returns an int, which seems like the most C-like thing
+ to do. "long long" variables are rare enough that
+ BUILTIN_TYPE_LONGEST would seem to be a mistake. */
+ if (TYPE_CODE (VALUE_TYPE (arg1)) == TYPE_CODE_INT)
+ return value_at (builtin_type_int,
+ (CORE_ADDR) value_as_long (arg1));
+ else if (TYPE_CODE (VALUE_TYPE (arg1)) == TYPE_CODE_PTR)
+ return value_at_lazy (TYPE_TARGET_TYPE (VALUE_TYPE (arg1)),
+ value_as_pointer (arg1));
+ error ("Attempt to take contents of a non-pointer value.");
+ return 0; /* For lint -- never reached */
+}
+
+/* Pushing small parts of stack frames. */
+
+/* Push one word (the size of object that a register holds). */
+
+CORE_ADDR
+push_word (sp, word)
+ CORE_ADDR sp;
+ unsigned LONGEST word;
+{
+ register int len = REGISTER_SIZE;
+ char buffer[MAX_REGISTER_RAW_SIZE];
+
+ store_unsigned_integer (buffer, len, word);
+#if 1 INNER_THAN 2
+ sp -= len;
+ write_memory (sp, buffer, len);
+#else /* stack grows upward */
+ write_memory (sp, buffer, len);
+ sp += len;
+#endif /* stack grows upward */
+
+ return sp;
+}
+
+/* Push LEN bytes with data at BUFFER. */
+
+CORE_ADDR
+push_bytes (sp, buffer, len)
+ CORE_ADDR sp;
+ char *buffer;
+ int len;
+{
+#if 1 INNER_THAN 2
+ sp -= len;
+ write_memory (sp, buffer, len);
+#else /* stack grows upward */
+ write_memory (sp, buffer, len);
+ sp += len;
+#endif /* stack grows upward */
+
+ return sp;
+}
+
+/* Push onto the stack the specified value VALUE. */
+
+static CORE_ADDR
+value_push (sp, arg)
+ register CORE_ADDR sp;
+ value_ptr arg;
+{
+ register int len = TYPE_LENGTH (VALUE_TYPE (arg));
+
+#if 1 INNER_THAN 2
+ sp -= len;
+ write_memory (sp, VALUE_CONTENTS (arg), len);
+#else /* stack grows upward */
+ write_memory (sp, VALUE_CONTENTS (arg), len);
+ sp += len;
+#endif /* stack grows upward */
+
+ return sp;
+}
+
+/* Perform the standard coercions that are specified
+ for arguments to be passed to C functions. */
+
+value_ptr
+value_arg_coerce (arg)
+ value_ptr arg;
+{
+ register struct type *type;
+
+ /* FIXME: We should coerce this according to the prototype (if we have
+ one). Right now we do a little bit of this in typecmp(), but that
+ doesn't always get called. For example, if passing a ref to a function
+ without a prototype, we probably should de-reference it. Currently
+ we don't. */
+
+ if (TYPE_CODE (VALUE_TYPE (arg)) == TYPE_CODE_ENUM)
+ arg = value_cast (builtin_type_unsigned_int, arg);
+
+#if 1 /* FIXME: This is only a temporary patch. -fnf */
+ if (VALUE_REPEATED (arg)
+ || TYPE_CODE (VALUE_TYPE (arg)) == TYPE_CODE_ARRAY)
+ arg = value_coerce_array (arg);
+ if (TYPE_CODE (VALUE_TYPE (arg)) == TYPE_CODE_FUNC)
+ arg = value_coerce_function (arg);
+#endif
+
+ type = VALUE_TYPE (arg);
+
+ if (TYPE_CODE (type) == TYPE_CODE_INT
+ && TYPE_LENGTH (type) < TYPE_LENGTH (builtin_type_int))
+ return value_cast (builtin_type_int, arg);
+
+ if (TYPE_CODE (type) == TYPE_CODE_FLT
+ && TYPE_LENGTH (type) < TYPE_LENGTH (builtin_type_double))
+ return value_cast (builtin_type_double, arg);
+
+ return arg;
+}
+
+/* Push the value ARG, first coercing it as an argument
+ to a C function. */
+
+static CORE_ADDR
+value_arg_push (sp, arg)
+ register CORE_ADDR sp;
+ value_ptr arg;
+{
+ return value_push (sp, value_arg_coerce (arg));
+}
+
+/* Determine a function's address and its return type from its value.
+ Calls error() if the function is not valid for calling. */
+
+static CORE_ADDR
+find_function_addr (function, retval_type)
+ value_ptr function;
+ struct type **retval_type;
+{
+ register struct type *ftype = VALUE_TYPE (function);
+ register enum type_code code = TYPE_CODE (ftype);
+ struct type *value_type;
+ CORE_ADDR funaddr;
+
+ /* If it's a member function, just look at the function
+ part of it. */
+
+ /* Determine address to call. */
+ if (code == TYPE_CODE_FUNC || code == TYPE_CODE_METHOD)
+ {
+ funaddr = VALUE_ADDRESS (function);
+ value_type = TYPE_TARGET_TYPE (ftype);
+ }
+ else if (code == TYPE_CODE_PTR)
+ {
+ funaddr = value_as_pointer (function);
+ if (TYPE_CODE (TYPE_TARGET_TYPE (ftype)) == TYPE_CODE_FUNC
+ || TYPE_CODE (TYPE_TARGET_TYPE (ftype)) == TYPE_CODE_METHOD)
+ value_type = TYPE_TARGET_TYPE (TYPE_TARGET_TYPE (ftype));
+ else
+ value_type = builtin_type_int;
+ }
+ else if (code == TYPE_CODE_INT)
+ {
+ /* Handle the case of functions lacking debugging info.
+ Their values are characters since their addresses are char */
+ if (TYPE_LENGTH (ftype) == 1)
+ funaddr = value_as_pointer (value_addr (function));
+ else
+ /* Handle integer used as address of a function. */
+ funaddr = (CORE_ADDR) value_as_long (function);
+
+ value_type = builtin_type_int;
+ }
+ else
+ error ("Invalid data type for function to be called.");
+
+ *retval_type = value_type;
+ return funaddr;
+}
+
+#if defined (CALL_DUMMY)
+/* All this stuff with a dummy frame may seem unnecessarily complicated
+ (why not just save registers in GDB?). The purpose of pushing a dummy
+ frame which looks just like a real frame is so that if you call a
+ function and then hit a breakpoint (get a signal, etc), "backtrace"
+ will look right. Whether the backtrace needs to actually show the
+ stack at the time the inferior function was called is debatable, but
+ it certainly needs to not display garbage. So if you are contemplating
+ making dummy frames be different from normal frames, consider that. */
+
+/* Perform a function call in the inferior.
+ ARGS is a vector of values of arguments (NARGS of them).
+ FUNCTION is a value, the function to be called.
+ Returns a value representing what the function returned.
+ May fail to return, if a breakpoint or signal is hit
+ during the execution of the function. */
+
+value_ptr
+call_function_by_hand (function, nargs, args)
+ value_ptr function;
+ int nargs;
+ value_ptr *args;
+{
+ register CORE_ADDR sp;
+ register int i;
+ CORE_ADDR start_sp;
+ /* CALL_DUMMY is an array of words (REGISTER_SIZE), but each word
+ is in host byte order. Before calling FIX_CALL_DUMMY, we byteswap it
+ and remove any extra bytes which might exist because unsigned LONGEST is
+ bigger than REGISTER_SIZE. */
+ static unsigned LONGEST dummy[] = CALL_DUMMY;
+ char dummy1[REGISTER_SIZE * sizeof dummy / sizeof (unsigned LONGEST)];
+ CORE_ADDR old_sp;
+ struct type *value_type;
+ unsigned char struct_return;
+ CORE_ADDR struct_addr;
+ struct inferior_status inf_status;
+ struct cleanup *old_chain;
+ CORE_ADDR funaddr;
+ int using_gcc;
+ CORE_ADDR real_pc;
+
+ if (!target_has_execution)
+ noprocess();
+
+ save_inferior_status (&inf_status, 1);
+ old_chain = make_cleanup (restore_inferior_status, &inf_status);
+
+ /* PUSH_DUMMY_FRAME is responsible for saving the inferior registers
+ (and POP_FRAME for restoring them). (At least on most machines)
+ they are saved on the stack in the inferior. */
+ PUSH_DUMMY_FRAME;
+
+ old_sp = sp = read_sp ();
+
+#if 1 INNER_THAN 2 /* Stack grows down */
+ sp -= sizeof dummy;
+ start_sp = sp;
+#else /* Stack grows up */
+ start_sp = sp;
+ sp += sizeof dummy;
+#endif
+
+ funaddr = find_function_addr (function, &value_type);
+
+ {
+ struct block *b = block_for_pc (funaddr);
+ /* If compiled without -g, assume GCC. */
+ using_gcc = b == NULL || BLOCK_GCC_COMPILED (b);
+ }
+
+ /* Are we returning a value using a structure return or a normal
+ value return? */
+
+ struct_return = using_struct_return (function, funaddr, value_type,
+ using_gcc);
+
+ /* Create a call sequence customized for this function
+ and the number of arguments for it. */
+ for (i = 0; i < sizeof dummy / sizeof (dummy[0]); i++)
+ store_unsigned_integer (&dummy1[i * REGISTER_SIZE],
+ REGISTER_SIZE,
+ (unsigned LONGEST)dummy[i]);
+
+#ifdef GDB_TARGET_IS_HPPA
+ real_pc = FIX_CALL_DUMMY (dummy1, start_sp, funaddr, nargs, args,
+ value_type, using_gcc);
+#else
+ FIX_CALL_DUMMY (dummy1, start_sp, funaddr, nargs, args,
+ value_type, using_gcc);
+ real_pc = start_sp;
+#endif
+
+#if CALL_DUMMY_LOCATION == ON_STACK
+ write_memory (start_sp, (char *)dummy1, sizeof dummy);
+#endif /* On stack. */
+
+#if CALL_DUMMY_LOCATION == BEFORE_TEXT_END
+ /* Convex Unix prohibits executing in the stack segment. */
+ /* Hope there is empty room at the top of the text segment. */
+ {
+ extern CORE_ADDR text_end;
+ static checked = 0;
+ if (!checked)
+ for (start_sp = text_end - sizeof dummy; start_sp < text_end; ++start_sp)
+ if (read_memory_integer (start_sp, 1) != 0)
+ error ("text segment full -- no place to put call");
+ checked = 1;
+ sp = old_sp;
+ real_pc = text_end - sizeof dummy;
+ write_memory (real_pc, (char *)dummy1, sizeof dummy);
+ }
+#endif /* Before text_end. */
+
+#if CALL_DUMMY_LOCATION == AFTER_TEXT_END
+ {
+ extern CORE_ADDR text_end;
+ int errcode;
+ sp = old_sp;
+ real_pc = text_end;
+ errcode = target_write_memory (real_pc, (char *)dummy1, sizeof dummy);
+ if (errcode != 0)
+ error ("Cannot write text segment -- call_function failed");
+ }
+#endif /* After text_end. */
+
+#if CALL_DUMMY_LOCATION == AT_ENTRY_POINT
+ real_pc = funaddr;
+#endif /* At entry point. */
+
+#ifdef lint
+ sp = old_sp; /* It really is used, for some ifdef's... */
+#endif
+
+#ifdef STACK_ALIGN
+ /* If stack grows down, we must leave a hole at the top. */
+ {
+ int len = 0;
+
+ /* Reserve space for the return structure to be written on the
+ stack, if necessary */
+
+ if (struct_return)
+ len += TYPE_LENGTH (value_type);
+
+ for (i = nargs - 1; i >= 0; i--)
+ len += TYPE_LENGTH (VALUE_TYPE (value_arg_coerce (args[i])));
+#ifdef CALL_DUMMY_STACK_ADJUST
+ len += CALL_DUMMY_STACK_ADJUST;
+#endif
+#if 1 INNER_THAN 2
+ sp -= STACK_ALIGN (len) - len;
+#else
+ sp += STACK_ALIGN (len) - len;
+#endif
+ }
+#endif /* STACK_ALIGN */
+
+ /* Reserve space for the return structure to be written on the
+ stack, if necessary */
+
+ if (struct_return)
+ {
+#if 1 INNER_THAN 2
+ sp -= TYPE_LENGTH (value_type);
+ struct_addr = sp;
+#else
+ struct_addr = sp;
+ sp += TYPE_LENGTH (value_type);
+#endif
+ }
+
+#if defined (REG_STRUCT_HAS_ADDR)
+ {
+ /* This is a machine like the sparc, where we may need to pass a pointer
+ to the structure, not the structure itself. */
+ for (i = nargs - 1; i >= 0; i--)
+ if (TYPE_CODE (VALUE_TYPE (args[i])) == TYPE_CODE_STRUCT
+ && REG_STRUCT_HAS_ADDR (using_gcc, VALUE_TYPE (args[i])))
+ {
+ CORE_ADDR addr;
+#if !(1 INNER_THAN 2)
+ /* The stack grows up, so the address of the thing we push
+ is the stack pointer before we push it. */
+ addr = sp;
+#endif
+ /* Push the structure. */
+ sp = value_push (sp, args[i]);
+#if 1 INNER_THAN 2
+ /* The stack grows down, so the address of the thing we push
+ is the stack pointer after we push it. */
+ addr = sp;
+#endif
+ /* The value we're going to pass is the address of the thing
+ we just pushed. */
+ args[i] = value_from_longest (lookup_pointer_type (value_type),
+ (LONGEST) addr);
+ }
+ }
+#endif /* REG_STRUCT_HAS_ADDR. */
+
+#ifdef PUSH_ARGUMENTS
+ PUSH_ARGUMENTS(nargs, args, sp, struct_return, struct_addr);
+#else /* !PUSH_ARGUMENTS */
+ for (i = nargs - 1; i >= 0; i--)
+ sp = value_arg_push (sp, args[i]);
+#endif /* !PUSH_ARGUMENTS */
+
+#ifdef CALL_DUMMY_STACK_ADJUST
+#if 1 INNER_THAN 2
+ sp -= CALL_DUMMY_STACK_ADJUST;
+#else
+ sp += CALL_DUMMY_STACK_ADJUST;
+#endif
+#endif /* CALL_DUMMY_STACK_ADJUST */
+
+ /* Store the address at which the structure is supposed to be
+ written. Note that this (and the code which reserved the space
+ above) assumes that gcc was used to compile this function. Since
+ it doesn't cost us anything but space and if the function is pcc
+ it will ignore this value, we will make that assumption.
+
+ Also note that on some machines (like the sparc) pcc uses a
+ convention like gcc's. */
+
+ if (struct_return)
+ STORE_STRUCT_RETURN (struct_addr, sp);
+
+ /* Write the stack pointer. This is here because the statements above
+ might fool with it. On SPARC, this write also stores the register
+ window into the right place in the new stack frame, which otherwise
+ wouldn't happen. (See store_inferior_registers in sparc-nat.c.) */
+ write_sp (sp);
+
+ {
+ char retbuf[REGISTER_BYTES];
+ char *name;
+ struct symbol *symbol;
+
+ name = NULL;
+ symbol = find_pc_function (funaddr);
+ if (symbol)
+ {
+ name = SYMBOL_SOURCE_NAME (symbol);
+ }
+ else
+ {
+ /* Try the minimal symbols. */
+ struct minimal_symbol *msymbol = lookup_minimal_symbol_by_pc (funaddr);
+
+ if (msymbol)
+ {
+ name = SYMBOL_SOURCE_NAME (msymbol);
+ }
+ }
+ if (name == NULL)
+ {
+ char format[80];
+ sprintf (format, "at %s", local_hex_format ());
+ name = alloca (80);
+ /* FIXME-32x64: assumes funaddr fits in a long. */
+ sprintf (name, format, (unsigned long) funaddr);
+ }
+
+ /* Execute the stack dummy routine, calling FUNCTION.
+ When it is done, discard the empty frame
+ after storing the contents of all regs into retbuf. */
+ if (run_stack_dummy (real_pc + CALL_DUMMY_START_OFFSET, retbuf))
+ {
+ /* We stopped somewhere besides the call dummy. */
+
+ /* If we did the cleanups, we would print a spurious error message
+ (Unable to restore previously selected frame), would write the
+ registers from the inf_status (which is wrong), and would do other
+ wrong things (like set stop_bpstat to the wrong thing). */
+ discard_cleanups (old_chain);
+ /* Prevent memory leak. */
+ bpstat_clear (&inf_status.stop_bpstat);
+
+ /* The following error message used to say "The expression
+ which contained the function call has been discarded." It
+ is a hard concept to explain in a few words. Ideally, GDB
+ would be able to resume evaluation of the expression when
+ the function finally is done executing. Perhaps someday
+ this will be implemented (it would not be easy). */
+
+ /* FIXME: Insert a bunch of wrap_here; name can be very long if it's
+ a C++ name with arguments and stuff. */
+ error ("\
+The program being debugged stopped while in a function called from GDB.\n\
+When the function (%s) is done executing, GDB will silently\n\
+stop (instead of continuing to evaluate the expression containing\n\
+the function call).", name);
+ }
+
+ do_cleanups (old_chain);
+
+ /* Figure out the value returned by the function. */
+ return value_being_returned (value_type, retbuf, struct_return);
+ }
+}
+#else /* no CALL_DUMMY. */
+value_ptr
+call_function_by_hand (function, nargs, args)
+ value_ptr function;
+ int nargs;
+ value_ptr *args;
+{
+ error ("Cannot invoke functions on this machine.");
+}
+#endif /* no CALL_DUMMY. */
+
+
+/* Create a value for an array by allocating space in the inferior, copying
+ the data into that space, and then setting up an array value.
+
+ The array bounds are set from LOWBOUND and HIGHBOUND, and the array is
+ populated from the values passed in ELEMVEC.
+
+ The element type of the array is inherited from the type of the
+ first element, and all elements must have the same size (though we
+ don't currently enforce any restriction on their types). */
+
+value_ptr
+value_array (lowbound, highbound, elemvec)
+ int lowbound;
+ int highbound;
+ value_ptr *elemvec;
+{
+ int nelem;
+ int idx;
+ int typelength;
+ value_ptr val;
+ struct type *rangetype;
+ struct type *arraytype;
+ CORE_ADDR addr;
+
+ /* Validate that the bounds are reasonable and that each of the elements
+ have the same size. */
+
+ nelem = highbound - lowbound + 1;
+ if (nelem <= 0)
+ {
+ error ("bad array bounds (%d, %d)", lowbound, highbound);
+ }
+ typelength = TYPE_LENGTH (VALUE_TYPE (elemvec[0]));
+ for (idx = 0; idx < nelem; idx++)
+ {
+ if (TYPE_LENGTH (VALUE_TYPE (elemvec[idx])) != typelength)
+ {
+ error ("array elements must all be the same size");
+ }
+ }
+
+ /* Allocate space to store the array in the inferior, and then initialize
+ it by copying in each element. FIXME: Is it worth it to create a
+ local buffer in which to collect each value and then write all the
+ bytes in one operation? */
+
+ addr = allocate_space_in_inferior (nelem * typelength);
+ for (idx = 0; idx < nelem; idx++)
+ {
+ write_memory (addr + (idx * typelength), VALUE_CONTENTS (elemvec[idx]),
+ typelength);
+ }
+
+ /* Create the array type and set up an array value to be evaluated lazily. */
+
+ rangetype = create_range_type ((struct type *) NULL, builtin_type_int,
+ lowbound, highbound);
+ arraytype = create_array_type ((struct type *) NULL,
+ VALUE_TYPE (elemvec[0]), rangetype);
+ val = value_at_lazy (arraytype, addr);
+ return (val);
+}
+
+/* Create a value for a string constant by allocating space in the inferior,
+ copying the data into that space, and returning the address with type
+ TYPE_CODE_STRING. PTR points to the string constant data; LEN is number
+ of characters.
+ Note that string types are like array of char types with a lower bound of
+ zero and an upper bound of LEN - 1. Also note that the string may contain
+ embedded null bytes. */
+
+value_ptr
+value_string (ptr, len)
+ char *ptr;
+ int len;
+{
+ value_ptr val;
+ struct type *rangetype;
+ struct type *stringtype;
+ CORE_ADDR addr;
+
+ /* Allocate space to store the string in the inferior, and then
+ copy LEN bytes from PTR in gdb to that address in the inferior. */
+
+ addr = allocate_space_in_inferior (len);
+ write_memory (addr, ptr, len);
+
+ /* Create the string type and set up a string value to be evaluated
+ lazily. */
+
+ rangetype = create_range_type ((struct type *) NULL, builtin_type_int,
+ 0, len - 1);
+ stringtype = create_string_type ((struct type *) NULL, rangetype);
+ val = value_at_lazy (stringtype, addr);
+ return (val);
+}
+
+/* See if we can pass arguments in T2 to a function which takes arguments
+ of types T1. Both t1 and t2 are NULL-terminated vectors. If some
+ arguments need coercion of some sort, then the coerced values are written
+ into T2. Return value is 0 if the arguments could be matched, or the
+ position at which they differ if not.
+
+ STATICP is nonzero if the T1 argument list came from a
+ static member function.
+
+ For non-static member functions, we ignore the first argument,
+ which is the type of the instance variable. This is because we want
+ to handle calls with objects from derived classes. This is not
+ entirely correct: we should actually check to make sure that a
+ requested operation is type secure, shouldn't we? FIXME. */
+
+static int
+typecmp (staticp, t1, t2)
+ int staticp;
+ struct type *t1[];
+ value_ptr t2[];
+{
+ int i;
+
+ if (t2 == 0)
+ return 1;
+ if (staticp && t1 == 0)
+ return t2[1] != 0;
+ if (t1 == 0)
+ return 1;
+ if (TYPE_CODE (t1[0]) == TYPE_CODE_VOID) return 0;
+ if (t1[!staticp] == 0) return 0;
+ for (i = !staticp; t1[i] && TYPE_CODE (t1[i]) != TYPE_CODE_VOID; i++)
+ {
+ struct type *tt1, *tt2;
+ if (! t2[i])
+ return i+1;
+ tt1 = t1[i];
+ tt2 = VALUE_TYPE(t2[i]);
+ if (TYPE_CODE (tt1) == TYPE_CODE_REF
+ /* We should be doing hairy argument matching, as below. */
+ && (TYPE_CODE (TYPE_TARGET_TYPE (tt1)) == TYPE_CODE (tt2)))
+ {
+ t2[i] = value_addr (t2[i]);
+ continue;
+ }
+
+ while (TYPE_CODE (tt1) == TYPE_CODE_PTR
+ && (TYPE_CODE(tt2)==TYPE_CODE_ARRAY || TYPE_CODE(tt2)==TYPE_CODE_PTR))
+ {
+ tt1 = TYPE_TARGET_TYPE(tt1);
+ tt2 = TYPE_TARGET_TYPE(tt2);
+ }
+ if (TYPE_CODE(tt1) == TYPE_CODE(tt2)) continue;
+ /* Array to pointer is a `trivial conversion' according to the ARM. */
+
+ /* We should be doing much hairier argument matching (see section 13.2
+ of the ARM), but as a quick kludge, just check for the same type
+ code. */
+ if (TYPE_CODE (t1[i]) != TYPE_CODE (VALUE_TYPE (t2[i])))
+ return i+1;
+ }
+ if (!t1[i]) return 0;
+ return t2[i] ? i+1 : 0;
+}
+
+/* Helper function used by value_struct_elt to recurse through baseclasses.
+ Look for a field NAME in ARG1. Adjust the address of ARG1 by OFFSET bytes,
+ and search in it assuming it has (class) type TYPE.
+ If found, return value, else return NULL.
+
+ If LOOKING_FOR_BASECLASS, then instead of looking for struct fields,
+ look for a baseclass named NAME. */
+
+static value_ptr
+search_struct_field (name, arg1, offset, type, looking_for_baseclass)
+ char *name;
+ register value_ptr arg1;
+ int offset;
+ register struct type *type;
+ int looking_for_baseclass;
+{
+ int i;
+
+ check_stub_type (type);
+
+ if (! looking_for_baseclass)
+ for (i = TYPE_NFIELDS (type) - 1; i >= TYPE_N_BASECLASSES (type); i--)
+ {
+ char *t_field_name = TYPE_FIELD_NAME (type, i);
+
+ if (t_field_name && STREQ (t_field_name, name))
+ {
+ value_ptr v;
+ if (TYPE_FIELD_STATIC (type, i))
+ {
+ char *phys_name = TYPE_FIELD_STATIC_PHYSNAME (type, i);
+ struct symbol *sym =
+ lookup_symbol (phys_name, 0, VAR_NAMESPACE, 0, NULL);
+ if (sym == NULL)
+ error ("Internal error: could not find physical static variable named %s",
+ phys_name);
+ v = value_at (TYPE_FIELD_TYPE (type, i),
+ (CORE_ADDR)SYMBOL_BLOCK_VALUE (sym));
+ }
+ else
+ v = value_primitive_field (arg1, offset, i, type);
+ if (v == 0)
+ error("there is no field named %s", name);
+ return v;
+ }
+ }
+
+ for (i = TYPE_N_BASECLASSES (type) - 1; i >= 0; i--)
+ {
+ value_ptr v;
+ /* If we are looking for baseclasses, this is what we get when we
+ hit them. But it could happen that the base part's member name
+ is not yet filled in. */
+ int found_baseclass = (looking_for_baseclass
+ && TYPE_BASECLASS_NAME (type, i) != NULL
+ && STREQ (name, TYPE_BASECLASS_NAME (type, i)));
+
+ if (BASETYPE_VIA_VIRTUAL (type, i))
+ {
+ value_ptr v2;
+ /* Fix to use baseclass_offset instead. FIXME */
+ baseclass_addr (type, i, VALUE_CONTENTS (arg1) + offset,
+ &v2, (int *)NULL);
+ if (v2 == 0)
+ error ("virtual baseclass botch");
+ if (found_baseclass)
+ return v2;
+ v = search_struct_field (name, v2, 0, TYPE_BASECLASS (type, i),
+ looking_for_baseclass);
+ }
+ else if (found_baseclass)
+ v = value_primitive_field (arg1, offset, i, type);
+ else
+ v = search_struct_field (name, arg1,
+ offset + TYPE_BASECLASS_BITPOS (type, i) / 8,
+ TYPE_BASECLASS (type, i),
+ looking_for_baseclass);
+ if (v) return v;
+ }
+ return NULL;
+}
+
+/* Helper function used by value_struct_elt to recurse through baseclasses.
+ Look for a field NAME in ARG1. Adjust the address of ARG1 by OFFSET bytes,
+ and search in it assuming it has (class) type TYPE.
+ If found, return value, else if name matched and args not return (value)-1,
+ else return NULL. */
+
+static value_ptr
+search_struct_method (name, arg1p, args, offset, static_memfuncp, type)
+ char *name;
+ register value_ptr *arg1p, *args;
+ int offset, *static_memfuncp;
+ register struct type *type;
+{
+ int i;
+ value_ptr v;
+ int name_matched = 0;
+ char dem_opname[64];
+
+ check_stub_type (type);
+ for (i = TYPE_NFN_FIELDS (type) - 1; i >= 0; i--)
+ {
+ char *t_field_name = TYPE_FN_FIELDLIST_NAME (type, i);
+ if (strncmp(t_field_name, "__", 2)==0 ||
+ strncmp(t_field_name, "op", 2)==0 ||
+ strncmp(t_field_name, "type", 4)==0 )
+ {
+ if (cplus_demangle_opname(t_field_name, dem_opname, DMGL_ANSI))
+ t_field_name = dem_opname;
+ else if (cplus_demangle_opname(t_field_name, dem_opname, 0))
+ t_field_name = dem_opname;
+ }
+ if (t_field_name && STREQ (t_field_name, name))
+ {
+ int j = TYPE_FN_FIELDLIST_LENGTH (type, i) - 1;
+ struct fn_field *f = TYPE_FN_FIELDLIST1 (type, i);
+ name_matched = 1;
+
+ if (j > 0 && args == 0)
+ error ("cannot resolve overloaded method `%s'", name);
+ while (j >= 0)
+ {
+ if (TYPE_FN_FIELD_STUB (f, j))
+ check_stub_method (type, i, j);
+ if (!typecmp (TYPE_FN_FIELD_STATIC_P (f, j),
+ TYPE_FN_FIELD_ARGS (f, j), args))
+ {
+ if (TYPE_FN_FIELD_VIRTUAL_P (f, j))
+ return value_virtual_fn_field (arg1p, f, j, type, offset);
+ if (TYPE_FN_FIELD_STATIC_P (f, j) && static_memfuncp)
+ *static_memfuncp = 1;
+ v = value_fn_field (arg1p, f, j, type, offset);
+ if (v != NULL) return v;
+ }
+ j--;
+ }
+ }
+ }
+
+ for (i = TYPE_N_BASECLASSES (type) - 1; i >= 0; i--)
+ {
+ int base_offset;
+
+ if (BASETYPE_VIA_VIRTUAL (type, i))
+ {
+ base_offset = baseclass_offset (type, i, *arg1p, offset);
+ if (base_offset == -1)
+ error ("virtual baseclass botch");
+ }
+ else
+ {
+ base_offset = TYPE_BASECLASS_BITPOS (type, i) / 8;
+ }
+ v = search_struct_method (name, arg1p, args, base_offset + offset,
+ static_memfuncp, TYPE_BASECLASS (type, i));
+ if (v == (value_ptr) -1)
+ {
+ name_matched = 1;
+ }
+ else if (v)
+ {
+/* FIXME-bothner: Why is this commented out? Why is it here? */
+/* *arg1p = arg1_tmp;*/
+ return v;
+ }
+ }
+ if (name_matched) return (value_ptr) -1;
+ else return NULL;
+}
+
+/* Given *ARGP, a value of type (pointer to a)* structure/union,
+ extract the component named NAME from the ultimate target structure/union
+ and return it as a value with its appropriate type.
+ ERR is used in the error message if *ARGP's type is wrong.
+
+ C++: ARGS is a list of argument types to aid in the selection of
+ an appropriate method. Also, handle derived types.
+
+ STATIC_MEMFUNCP, if non-NULL, points to a caller-supplied location
+ where the truthvalue of whether the function that was resolved was
+ a static member function or not is stored.
+
+ ERR is an error message to be printed in case the field is not found. */
+
+value_ptr
+value_struct_elt (argp, args, name, static_memfuncp, err)
+ register value_ptr *argp, *args;
+ char *name;
+ int *static_memfuncp;
+ char *err;
+{
+ register struct type *t;
+ value_ptr v;
+
+ COERCE_ARRAY (*argp);
+
+ t = VALUE_TYPE (*argp);
+
+ /* Follow pointers until we get to a non-pointer. */
+
+ while (TYPE_CODE (t) == TYPE_CODE_PTR || TYPE_CODE (t) == TYPE_CODE_REF)
+ {
+ *argp = value_ind (*argp);
+ /* Don't coerce fn pointer to fn and then back again! */
+ if (TYPE_CODE (VALUE_TYPE (*argp)) != TYPE_CODE_FUNC)
+ COERCE_ARRAY (*argp);
+ t = VALUE_TYPE (*argp);
+ }
+
+ if (TYPE_CODE (t) == TYPE_CODE_MEMBER)
+ error ("not implemented: member type in value_struct_elt");
+
+ if ( TYPE_CODE (t) != TYPE_CODE_STRUCT
+ && TYPE_CODE (t) != TYPE_CODE_UNION)
+ error ("Attempt to extract a component of a value that is not a %s.", err);
+
+ /* Assume it's not, unless we see that it is. */
+ if (static_memfuncp)
+ *static_memfuncp =0;
+
+ if (!args)
+ {
+ /* if there are no arguments ...do this... */
+
+ /* Try as a field first, because if we succeed, there
+ is less work to be done. */
+ v = search_struct_field (name, *argp, 0, t, 0);
+ if (v)
+ return v;
+
+ /* C++: If it was not found as a data field, then try to
+ return it as a pointer to a method. */
+
+ if (destructor_name_p (name, t))
+ error ("Cannot get value of destructor");
+
+ v = search_struct_method (name, argp, args, 0, static_memfuncp, t);
+
+ if (v == (value_ptr) -1)
+ error ("Cannot take address of a method");
+ else if (v == 0)
+ {
+ if (TYPE_NFN_FIELDS (t))
+ error ("There is no member or method named %s.", name);
+ else
+ error ("There is no member named %s.", name);
+ }
+ return v;
+ }
+
+ if (destructor_name_p (name, t))
+ {
+ if (!args[1])
+ {
+ /* destructors are a special case. */
+ v = value_fn_field (NULL, TYPE_FN_FIELDLIST1 (t, 0),
+ TYPE_FN_FIELDLIST_LENGTH (t, 0), 0, 0);
+ if (!v) error("could not find destructor function named %s.", name);
+ else return v;
+ }
+ else
+ {
+ error ("destructor should not have any argument");
+ }
+ }
+ else
+ v = search_struct_method (name, argp, args, 0, static_memfuncp, t);
+
+ if (v == (value_ptr) -1)
+ {
+ error("Argument list of %s mismatch with component in the structure.", name);
+ }
+ else if (v == 0)
+ {
+ /* See if user tried to invoke data as function. If so,
+ hand it back. If it's not callable (i.e., a pointer to function),
+ gdb should give an error. */
+ v = search_struct_field (name, *argp, 0, t, 0);
+ }
+
+ if (!v)
+ error ("Structure has no component named %s.", name);
+ return v;
+}
+
+/* C++: return 1 is NAME is a legitimate name for the destructor
+ of type TYPE. If TYPE does not have a destructor, or
+ if NAME is inappropriate for TYPE, an error is signaled. */
+int
+destructor_name_p (name, type)
+ const char *name;
+ const struct type *type;
+{
+ /* destructors are a special case. */
+
+ if (name[0] == '~')
+ {
+ char *dname = type_name_no_tag (type);
+ if (!STREQ (dname, name+1))
+ error ("name of destructor must equal name of class");
+ else
+ return 1;
+ }
+ return 0;
+}
+
+/* Helper function for check_field: Given TYPE, a structure/union,
+ return 1 if the component named NAME from the ultimate
+ target structure/union is defined, otherwise, return 0. */
+
+static int
+check_field_in (type, name)
+ register struct type *type;
+ const char *name;
+{
+ register int i;
+
+ for (i = TYPE_NFIELDS (type) - 1; i >= TYPE_N_BASECLASSES (type); i--)
+ {
+ char *t_field_name = TYPE_FIELD_NAME (type, i);
+ if (t_field_name && STREQ (t_field_name, name))
+ return 1;
+ }
+
+ /* C++: If it was not found as a data field, then try to
+ return it as a pointer to a method. */
+
+ /* Destructors are a special case. */
+ if (destructor_name_p (name, type))
+ return 1;
+
+ for (i = TYPE_NFN_FIELDS (type) - 1; i >= 0; --i)
+ {
+ if (STREQ (TYPE_FN_FIELDLIST_NAME (type, i), name))
+ return 1;
+ }
+
+ for (i = TYPE_N_BASECLASSES (type) - 1; i >= 0; i--)
+ if (check_field_in (TYPE_BASECLASS (type, i), name))
+ return 1;
+
+ return 0;
+}
+
+
+/* C++: Given ARG1, a value of type (pointer to a)* structure/union,
+ return 1 if the component named NAME from the ultimate
+ target structure/union is defined, otherwise, return 0. */
+
+int
+check_field (arg1, name)
+ register value_ptr arg1;
+ const char *name;
+{
+ register struct type *t;
+
+ COERCE_ARRAY (arg1);
+
+ t = VALUE_TYPE (arg1);
+
+ /* Follow pointers until we get to a non-pointer. */
+
+ while (TYPE_CODE (t) == TYPE_CODE_PTR || TYPE_CODE (t) == TYPE_CODE_REF)
+ t = TYPE_TARGET_TYPE (t);
+
+ if (TYPE_CODE (t) == TYPE_CODE_MEMBER)
+ error ("not implemented: member type in check_field");
+
+ if ( TYPE_CODE (t) != TYPE_CODE_STRUCT
+ && TYPE_CODE (t) != TYPE_CODE_UNION)
+ error ("Internal error: `this' is not an aggregate");
+
+ return check_field_in (t, name);
+}
+
+/* C++: Given an aggregate type CURTYPE, and a member name NAME,
+ return the address of this member as a "pointer to member"
+ type. If INTYPE is non-null, then it will be the type
+ of the member we are looking for. This will help us resolve
+ "pointers to member functions". This function is used
+ to resolve user expressions of the form "DOMAIN::NAME". */
+
+value_ptr
+value_struct_elt_for_reference (domain, offset, curtype, name, intype)
+ struct type *domain, *curtype, *intype;
+ int offset;
+ char *name;
+{
+ register struct type *t = curtype;
+ register int i;
+ value_ptr v;
+
+ if ( TYPE_CODE (t) != TYPE_CODE_STRUCT
+ && TYPE_CODE (t) != TYPE_CODE_UNION)
+ error ("Internal error: non-aggregate type to value_struct_elt_for_reference");
+
+ for (i = TYPE_NFIELDS (t) - 1; i >= TYPE_N_BASECLASSES (t); i--)
+ {
+ char *t_field_name = TYPE_FIELD_NAME (t, i);
+
+ if (t_field_name && STREQ (t_field_name, name))
+ {
+ if (TYPE_FIELD_STATIC (t, i))
+ {
+ char *phys_name = TYPE_FIELD_STATIC_PHYSNAME (t, i);
+ struct symbol *sym =
+ lookup_symbol (phys_name, 0, VAR_NAMESPACE, 0, NULL);
+ if (sym == NULL)
+ error ("Internal error: could not find physical static variable named %s",
+ phys_name);
+ return value_at (SYMBOL_TYPE (sym),
+ (CORE_ADDR)SYMBOL_BLOCK_VALUE (sym));
+ }
+ if (TYPE_FIELD_PACKED (t, i))
+ error ("pointers to bitfield members not allowed");
+
+ return value_from_longest
+ (lookup_reference_type (lookup_member_type (TYPE_FIELD_TYPE (t, i),
+ domain)),
+ offset + (LONGEST) (TYPE_FIELD_BITPOS (t, i) >> 3));
+ }
+ }
+
+ /* C++: If it was not found as a data field, then try to
+ return it as a pointer to a method. */
+
+ /* Destructors are a special case. */
+ if (destructor_name_p (name, t))
+ {
+ error ("member pointers to destructors not implemented yet");
+ }
+
+ /* Perform all necessary dereferencing. */
+ while (intype && TYPE_CODE (intype) == TYPE_CODE_PTR)
+ intype = TYPE_TARGET_TYPE (intype);
+
+ for (i = TYPE_NFN_FIELDS (t) - 1; i >= 0; --i)
+ {
+ char *t_field_name = TYPE_FN_FIELDLIST_NAME (t, i);
+ char dem_opname[64];
+
+ if (strncmp(t_field_name, "__", 2)==0 ||
+ strncmp(t_field_name, "op", 2)==0 ||
+ strncmp(t_field_name, "type", 4)==0 )
+ {
+ if (cplus_demangle_opname(t_field_name, dem_opname, DMGL_ANSI))
+ t_field_name = dem_opname;
+ else if (cplus_demangle_opname(t_field_name, dem_opname, 0))
+ t_field_name = dem_opname;
+ }
+ if (t_field_name && STREQ (t_field_name, name))
+ {
+ int j = TYPE_FN_FIELDLIST_LENGTH (t, i);
+ struct fn_field *f = TYPE_FN_FIELDLIST1 (t, i);
+
+ if (intype == 0 && j > 1)
+ error ("non-unique member `%s' requires type instantiation", name);
+ if (intype)
+ {
+ while (j--)
+ if (TYPE_FN_FIELD_TYPE (f, j) == intype)
+ break;
+ if (j < 0)
+ error ("no member function matches that type instantiation");
+ }
+ else
+ j = 0;
+
+ if (TYPE_FN_FIELD_STUB (f, j))
+ check_stub_method (t, i, j);
+ if (TYPE_FN_FIELD_VIRTUAL_P (f, j))
+ {
+ return value_from_longest
+ (lookup_reference_type
+ (lookup_member_type (TYPE_FN_FIELD_TYPE (f, j),
+ domain)),
+ (LONGEST) METHOD_PTR_FROM_VOFFSET
+ (TYPE_FN_FIELD_VOFFSET (f, j)));
+ }
+ else
+ {
+ struct symbol *s = lookup_symbol (TYPE_FN_FIELD_PHYSNAME (f, j),
+ 0, VAR_NAMESPACE, 0, NULL);
+ if (s == NULL)
+ {
+ v = 0;
+ }
+ else
+ {
+ v = read_var_value (s, 0);
+#if 0
+ VALUE_TYPE (v) = lookup_reference_type
+ (lookup_member_type (TYPE_FN_FIELD_TYPE (f, j),
+ domain));
+#endif
+ }
+ return v;
+ }
+ }
+ }
+ for (i = TYPE_N_BASECLASSES (t) - 1; i >= 0; i--)
+ {
+ value_ptr v;
+ int base_offset;
+
+ if (BASETYPE_VIA_VIRTUAL (t, i))
+ base_offset = 0;
+ else
+ base_offset = TYPE_BASECLASS_BITPOS (t, i) / 8;
+ v = value_struct_elt_for_reference (domain,
+ offset + base_offset,
+ TYPE_BASECLASS (t, i),
+ name,
+ intype);
+ if (v)
+ return v;
+ }
+ return 0;
+}
+
+/* C++: return the value of the class instance variable, if one exists.
+ Flag COMPLAIN signals an error if the request is made in an
+ inappropriate context. */
+value_ptr
+value_of_this (complain)
+ int complain;
+{
+ extern FRAME selected_frame;
+ struct symbol *func, *sym;
+ struct block *b;
+ int i;
+ static const char funny_this[] = "this";
+ value_ptr this;
+
+ if (selected_frame == 0)
+ if (complain)
+ error ("no frame selected");
+ else return 0;
+
+ func = get_frame_function (selected_frame);
+ if (!func)
+ {
+ if (complain)
+ error ("no `this' in nameless context");
+ else return 0;
+ }
+
+ b = SYMBOL_BLOCK_VALUE (func);
+ i = BLOCK_NSYMS (b);
+ if (i <= 0)
+ if (complain)
+ error ("no args, no `this'");
+ else return 0;
+
+ /* Calling lookup_block_symbol is necessary to get the LOC_REGISTER
+ symbol instead of the LOC_ARG one (if both exist). */
+ sym = lookup_block_symbol (b, funny_this, VAR_NAMESPACE);
+ if (sym == NULL)
+ {
+ if (complain)
+ error ("current stack frame not in method");
+ else
+ return NULL;
+ }
+
+ this = read_var_value (sym, selected_frame);
+ if (this == 0 && complain)
+ error ("`this' argument at unknown address");
+ return this;
+}
diff --git a/gnu/usr.bin/gdb/gdb/valprint.c b/gnu/usr.bin/gdb/gdb/valprint.c
new file mode 100644
index 0000000..823a8c4
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/valprint.c
@@ -0,0 +1,1087 @@
+/* Print values for GDB, the GNU debugger.
+ Copyright 1986, 1988, 1989, 1991, 1992, 1993, 1994
+ Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "defs.h"
+#include <string.h>
+#include "symtab.h"
+#include "gdbtypes.h"
+#include "value.h"
+#include "gdbcore.h"
+#include "gdbcmd.h"
+#include "target.h"
+#include "obstack.h"
+#include "language.h"
+#include "demangle.h"
+#include "annotate.h"
+
+#include <errno.h>
+
+/* Prototypes for local functions */
+
+static void
+print_hex_chars PARAMS ((GDB_FILE *, unsigned char *, unsigned int));
+
+static void
+show_print PARAMS ((char *, int));
+
+static void
+set_print PARAMS ((char *, int));
+
+static void
+set_radix PARAMS ((char *, int));
+
+static void
+show_radix PARAMS ((char *, int));
+
+static void
+set_input_radix PARAMS ((char *, int, struct cmd_list_element *));
+
+static void
+set_input_radix_1 PARAMS ((int, unsigned));
+
+static void
+set_output_radix PARAMS ((char *, int, struct cmd_list_element *));
+
+static void
+set_output_radix_1 PARAMS ((int, unsigned));
+
+/* Maximum number of chars to print for a string pointer value or vector
+ contents, or UINT_MAX for no limit. Note that "set print elements 0"
+ stores UINT_MAX in print_max, which displays in a show command as
+ "unlimited". */
+
+unsigned int print_max;
+#define PRINT_MAX_DEFAULT 200 /* Start print_max off at this value. */
+
+/* Default input and output radixes, and output format letter. */
+
+unsigned input_radix = 10;
+unsigned output_radix = 10;
+int output_format = 0;
+
+/* Print repeat counts if there are more than this many repetitions of an
+ element in an array. Referenced by the low level language dependent
+ print routines. */
+
+unsigned int repeat_count_threshold = 10;
+
+/* If nonzero, stops printing of char arrays at first null. */
+
+int stop_print_at_null;
+
+/* Controls pretty printing of structures. */
+
+int prettyprint_structs;
+
+/* Controls pretty printing of arrays. */
+
+int prettyprint_arrays;
+
+/* If nonzero, causes unions inside structures or other unions to be
+ printed. */
+
+int unionprint; /* Controls printing of nested unions. */
+
+/* If nonzero, causes machine addresses to be printed in certain contexts. */
+
+int addressprint; /* Controls printing of machine addresses */
+
+
+/* Print data of type TYPE located at VALADDR (within GDB), which came from
+ the inferior at address ADDRESS, onto stdio stream STREAM according to
+ FORMAT (a letter, or 0 for natural format using TYPE).
+
+ If DEREF_REF is nonzero, then dereference references, otherwise just print
+ them like pointers.
+
+ The PRETTY parameter controls prettyprinting.
+
+ If the data are a string pointer, returns the number of string characters
+ printed.
+
+ FIXME: The data at VALADDR is in target byte order. If gdb is ever
+ enhanced to be able to debug more than the single target it was compiled
+ for (specific CPU type and thus specific target byte ordering), then
+ either the print routines are going to have to take this into account,
+ or the data is going to have to be passed into here already converted
+ to the host byte ordering, whichever is more convenient. */
+
+
+int
+val_print (type, valaddr, address, stream, format, deref_ref, recurse, pretty)
+ struct type *type;
+ char *valaddr;
+ CORE_ADDR address;
+ GDB_FILE *stream;
+ int format;
+ int deref_ref;
+ int recurse;
+ enum val_prettyprint pretty;
+{
+ if (pretty == Val_pretty_default)
+ {
+ pretty = prettyprint_structs ? Val_prettyprint : Val_no_prettyprint;
+ }
+
+ QUIT;
+
+ /* Ensure that the type is complete and not just a stub. If the type is
+ only a stub and we can't find and substitute its complete type, then
+ print appropriate string and return. */
+
+ check_stub_type (type);
+ if (TYPE_FLAGS (type) & TYPE_FLAG_STUB)
+ {
+ fprintf_filtered (stream, "<incomplete type>");
+ gdb_flush (stream);
+ return (0);
+ }
+
+ return (LA_VAL_PRINT (type, valaddr, address, stream, format, deref_ref,
+ recurse, pretty));
+}
+
+/* Print the value VAL in C-ish syntax on stream STREAM.
+ FORMAT is a format-letter, or 0 for print in natural format of data type.
+ If the object printed is a string pointer, returns
+ the number of string bytes printed. */
+
+int
+value_print (val, stream, format, pretty)
+ value_ptr val;
+ GDB_FILE *stream;
+ int format;
+ enum val_prettyprint pretty;
+{
+ if (val == 0)
+ {
+ printf_filtered ("<address of value unknown>");
+ return 0;
+ }
+ if (VALUE_OPTIMIZED_OUT (val))
+ {
+ printf_filtered ("<value optimized out>");
+ return 0;
+ }
+ return LA_VALUE_PRINT (val, stream, format, pretty);
+}
+
+/* Called by various <lang>_val_print routines to print TYPE_CODE_INT's */
+
+void
+val_print_type_code_int (type, valaddr, stream)
+ struct type *type;
+ char *valaddr;
+ GDB_FILE *stream;
+{
+ char *p;
+ /* Pointer to first (i.e. lowest address) nonzero character. */
+ char *first_addr;
+ unsigned int len;
+
+ if (TYPE_LENGTH (type) > sizeof (LONGEST))
+ {
+ if (TYPE_UNSIGNED (type))
+ {
+ /* First figure out whether the number in fact has zeros
+ in all its bytes more significant than least significant
+ sizeof (LONGEST) ones. */
+ len = TYPE_LENGTH (type);
+
+#if TARGET_BYTE_ORDER == BIG_ENDIAN
+ for (p = valaddr;
+ len > sizeof (LONGEST) && p < valaddr + TYPE_LENGTH (type);
+ p++)
+#else /* Little endian. */
+ first_addr = valaddr;
+ for (p = valaddr + TYPE_LENGTH (type) - 1;
+ len > sizeof (LONGEST) && p >= valaddr;
+ p--)
+#endif /* Little endian. */
+ {
+ if (*p == 0)
+ {
+ len--;
+ }
+ else
+ {
+ break;
+ }
+ }
+#if TARGET_BYTE_ORDER == BIG_ENDIAN
+ first_addr = p;
+#endif
+ if (len <= sizeof (LONGEST))
+ {
+ /* The most significant bytes are zero, so we can just get
+ the least significant sizeof (LONGEST) bytes and print it
+ in decimal. */
+ print_longest (stream, 'u', 0,
+ extract_unsigned_integer (first_addr,
+ sizeof (LONGEST)));
+ }
+ else
+ {
+ /* It is big, so print it in hex. */
+ print_hex_chars (stream, (unsigned char *) first_addr, len);
+ }
+ }
+ else
+ {
+ /* Signed. One could assume two's complement (a reasonable
+ assumption, I think) and do better than this. */
+ print_hex_chars (stream, (unsigned char *) valaddr,
+ TYPE_LENGTH (type));
+ }
+ }
+ else
+ {
+#ifdef PRINT_TYPELESS_INTEGER
+ PRINT_TYPELESS_INTEGER (stream, type, unpack_long (type, valaddr));
+#else
+ print_longest (stream, TYPE_UNSIGNED (type) ? 'u' : 'd', 0,
+ unpack_long (type, valaddr));
+#endif
+ }
+}
+
+/* Print a number according to FORMAT which is one of d,u,x,o,b,h,w,g.
+ The raison d'etre of this function is to consolidate printing of LONG_LONG's
+ into this one function. Some platforms have long longs but don't have a
+ printf() that supports "ll" in the format string. We handle these by seeing
+ if the number is actually a long, and if not we just bail out and print the
+ number in hex. The format chars b,h,w,g are from
+ print_scalar_formatted(). If USE_LOCAL, format it according to the current
+ language (this should be used for most integers which GDB prints, the
+ exception is things like protocols where the format of the integer is
+ a protocol thing, not a user-visible thing). */
+
+void
+print_longest (stream, format, use_local, val_long)
+ GDB_FILE *stream;
+ int format;
+ int use_local;
+ LONGEST val_long;
+{
+#if defined (CC_HAS_LONG_LONG) && !defined (PRINTF_HAS_LONG_LONG)
+ long vtop, vbot;
+
+ vtop = val_long >> (sizeof (long) * HOST_CHAR_BIT);
+ vbot = (long) val_long;
+
+ if ((format == 'd' && (val_long < INT_MIN || val_long > INT_MAX))
+ || ((format == 'u' || format == 'x') && (unsigned long long)val_long > UINT_MAX))
+ {
+ fprintf_filtered (stream, "0x%lx%08lx", vtop, vbot);
+ return;
+ }
+#endif
+
+#ifdef PRINTF_HAS_LONG_LONG
+ switch (format)
+ {
+ case 'd':
+ fprintf_filtered (stream,
+ use_local ? local_decimal_format_custom ("ll")
+ : "%lld",
+ val_long);
+ break;
+ case 'u':
+ fprintf_filtered (stream, "%llu", val_long);
+ break;
+ case 'x':
+ fprintf_filtered (stream,
+ use_local ? local_hex_format_custom ("ll")
+ : "%llx",
+ val_long);
+ break;
+ case 'o':
+ fprintf_filtered (stream,
+ use_local ? local_octal_format_custom ("ll")
+ : "%llo",
+ break;
+ case 'b':
+ fprintf_filtered (stream, local_hex_format_custom ("02ll"), val_long);
+ break;
+ case 'h':
+ fprintf_filtered (stream, local_hex_format_custom ("04ll"), val_long);
+ break;
+ case 'w':
+ fprintf_filtered (stream, local_hex_format_custom ("08ll"), val_long);
+ break;
+ case 'g':
+ fprintf_filtered (stream, local_hex_format_custom ("016ll"), val_long);
+ break;
+ default:
+ abort ();
+ }
+#else /* !PRINTF_HAS_LONG_LONG */
+ /* In the following it is important to coerce (val_long) to a long. It does
+ nothing if !LONG_LONG, but it will chop off the top half (which we know
+ we can ignore) if the host supports long longs. */
+
+ switch (format)
+ {
+ case 'd':
+ fprintf_filtered (stream,
+ use_local ? local_decimal_format_custom ("l")
+ : "%ld",
+ (long) val_long);
+ break;
+ case 'u':
+ fprintf_filtered (stream, "%lu", (unsigned long) val_long);
+ break;
+ case 'x':
+ fprintf_filtered (stream,
+ use_local ? local_hex_format_custom ("l")
+ : "%lx",
+ (long) val_long);
+ break;
+ case 'o':
+ fprintf_filtered (stream,
+ use_local ? local_octal_format_custom ("l")
+ : "%lo",
+ (long) val_long);
+ break;
+ case 'b':
+ fprintf_filtered (stream, local_hex_format_custom ("02l"),
+ (long) val_long);
+ break;
+ case 'h':
+ fprintf_filtered (stream, local_hex_format_custom ("04l"),
+ (long) val_long);
+ break;
+ case 'w':
+ fprintf_filtered (stream, local_hex_format_custom ("08l"),
+ (long) val_long);
+ break;
+ case 'g':
+ fprintf_filtered (stream, local_hex_format_custom ("016l"),
+ (long) val_long);
+ break;
+ default:
+ abort ();
+ }
+#endif /* !PRINTF_HAS_LONG_LONG */
+}
+
+/* This used to be a macro, but I don't think it is called often enough
+ to merit such treatment. */
+/* Convert a LONGEST to an int. This is used in contexts (e.g. number of
+ arguments to a function, number in a value history, register number, etc.)
+ where the value must not be larger than can fit in an int. */
+
+int
+longest_to_int (arg)
+ LONGEST arg;
+{
+
+ /* This check is in case a system header has botched the
+ definition of INT_MIN, like on BSDI. */
+ if (sizeof (LONGEST) <= sizeof (int))
+ return arg;
+
+ if (arg > INT_MAX || arg < INT_MIN)
+ error ("Value out of range.");
+
+ return arg;
+}
+
+/* Print a floating point value of type TYPE, pointed to in GDB by VALADDR,
+ on STREAM. */
+
+void
+print_floating (valaddr, type, stream)
+ char *valaddr;
+ struct type *type;
+ GDB_FILE *stream;
+{
+ double doub;
+ int inv;
+ unsigned len = TYPE_LENGTH (type);
+
+#if defined (IEEE_FLOAT)
+
+ /* Check for NaN's. Note that this code does not depend on us being
+ on an IEEE conforming system. It only depends on the target
+ machine using IEEE representation. This means (a)
+ cross-debugging works right, and (2) IEEE_FLOAT can (and should)
+ be defined for systems like the 68881, which uses IEEE
+ representation, but is not IEEE conforming. */
+
+ {
+ unsigned long low, high;
+ /* Is the sign bit 0? */
+ int nonnegative;
+ /* Is it is a NaN (i.e. the exponent is all ones and
+ the fraction is nonzero)? */
+ int is_nan;
+
+ if (len == 4)
+ {
+ /* It's single precision. */
+ /* Assume that floating point byte order is the same as
+ integer byte order. */
+ low = extract_unsigned_integer (valaddr, 4);
+ nonnegative = ((low & 0x80000000) == 0);
+ is_nan = ((((low >> 23) & 0xFF) == 0xFF)
+ && 0 != (low & 0x7FFFFF));
+ low &= 0x7fffff;
+ high = 0;
+ }
+ else if (len == 8)
+ {
+ /* It's double precision. Get the high and low words. */
+
+ /* Assume that floating point byte order is the same as
+ integer byte order. */
+#if TARGET_BYTE_ORDER == BIG_ENDIAN
+ low = extract_unsigned_integer (valaddr + 4, 4);
+ high = extract_unsigned_integer (valaddr, 4);
+#else
+ low = extract_unsigned_integer (valaddr, 4);
+ high = extract_unsigned_integer (valaddr + 4, 4);
+#endif
+ nonnegative = ((high & 0x80000000) == 0);
+ is_nan = (((high >> 20) & 0x7ff) == 0x7ff
+ && ! ((((high & 0xfffff) == 0)) && (low == 0)));
+ high &= 0xfffff;
+ }
+ else
+ /* Extended. We can't detect NaNs for extendeds yet. Also note
+ that currently extendeds get nuked to double in
+ REGISTER_CONVERTIBLE. */
+ is_nan = 0;
+
+ if (is_nan)
+ {
+ /* The meaning of the sign and fraction is not defined by IEEE.
+ But the user might know what they mean. For example, they
+ (in an implementation-defined manner) distinguish between
+ signaling and quiet NaN's. */
+ if (high)
+ fprintf_filtered (stream, "-NaN(0x%lx%.8lx)" + nonnegative,
+ high, low);
+ else
+ fprintf_filtered (stream, "-NaN(0x%lx)" + nonnegative, low);
+ return;
+ }
+ }
+#endif /* IEEE_FLOAT. */
+
+ doub = unpack_double (type, valaddr, &inv);
+ if (inv)
+ fprintf_filtered (stream, "<invalid float value>");
+ else
+ fprintf_filtered (stream, len <= sizeof(float) ? "%.9g" : "%.17g", doub);
+}
+
+/* VALADDR points to an integer of LEN bytes. Print it in hex on stream. */
+
+static void
+print_hex_chars (stream, valaddr, len)
+ GDB_FILE *stream;
+ unsigned char *valaddr;
+ unsigned len;
+{
+ unsigned char *p;
+
+ /* FIXME: We should be not printing leading zeroes in most cases. */
+
+ fprintf_filtered (stream, local_hex_format_prefix ());
+#if TARGET_BYTE_ORDER == BIG_ENDIAN
+ for (p = valaddr;
+ p < valaddr + len;
+ p++)
+#else /* Little endian. */
+ for (p = valaddr + len - 1;
+ p >= valaddr;
+ p--)
+#endif
+ {
+ fprintf_filtered (stream, "%02x", *p);
+ }
+ fprintf_filtered (stream, local_hex_format_suffix ());
+}
+
+/* Called by various <lang>_val_print routines to print elements of an
+ array in the form "<elem1>, <elem2>, <elem3>, ...".
+
+ (FIXME?) Assumes array element separator is a comma, which is correct
+ for all languages currently handled.
+ (FIXME?) Some languages have a notation for repeated array elements,
+ perhaps we should try to use that notation when appropriate.
+ */
+
+void
+val_print_array_elements (type, valaddr, address, stream, format, deref_ref,
+ recurse, pretty, i)
+ struct type *type;
+ char *valaddr;
+ CORE_ADDR address;
+ GDB_FILE *stream;
+ int format;
+ int deref_ref;
+ int recurse;
+ enum val_prettyprint pretty;
+ unsigned int i;
+{
+ unsigned int things_printed = 0;
+ unsigned len;
+ struct type *elttype;
+ unsigned eltlen;
+ /* Position of the array element we are examining to see
+ whether it is repeated. */
+ unsigned int rep1;
+ /* Number of repetitions we have detected so far. */
+ unsigned int reps;
+
+ elttype = TYPE_TARGET_TYPE (type);
+ eltlen = TYPE_LENGTH (elttype);
+ len = TYPE_LENGTH (type) / eltlen;
+
+ annotate_array_section_begin (i, elttype);
+
+ for (; i < len && things_printed < print_max; i++)
+ {
+ if (i != 0)
+ {
+ if (prettyprint_arrays)
+ {
+ fprintf_filtered (stream, ",\n");
+ print_spaces_filtered (2 + 2 * recurse, stream);
+ }
+ else
+ {
+ fprintf_filtered (stream, ", ");
+ }
+ }
+ wrap_here (n_spaces (2 + 2 * recurse));
+
+ rep1 = i + 1;
+ reps = 1;
+ while ((rep1 < len) &&
+ !memcmp (valaddr + i * eltlen, valaddr + rep1 * eltlen, eltlen))
+ {
+ ++reps;
+ ++rep1;
+ }
+
+ if (reps > repeat_count_threshold)
+ {
+ val_print (elttype, valaddr + i * eltlen, 0, stream, format,
+ deref_ref, recurse + 1, pretty);
+ annotate_elt_rep (reps);
+ fprintf_filtered (stream, " <repeats %u times>", reps);
+ annotate_elt_rep_end ();
+
+ i = rep1 - 1;
+ things_printed += repeat_count_threshold;
+ }
+ else
+ {
+ val_print (elttype, valaddr + i * eltlen, 0, stream, format,
+ deref_ref, recurse + 1, pretty);
+ annotate_elt ();
+ things_printed++;
+ }
+ }
+ annotate_array_section_end ();
+ if (i < len)
+ {
+ fprintf_filtered (stream, "...");
+ }
+}
+
+void
+value_print_array_elements (val, stream, format, pretty)
+ value_ptr val;
+ GDB_FILE *stream;
+ int format;
+ enum val_prettyprint pretty;
+{
+ unsigned int things_printed = 0;
+ register unsigned int i, n, typelen;
+ /* Position of the array elem we are examining to see if it is repeated. */
+ unsigned int rep1;
+ /* Number of repetitions we have detected so far. */
+ unsigned int reps;
+
+ n = VALUE_REPETITIONS (val);
+ typelen = TYPE_LENGTH (VALUE_TYPE (val));
+ for (i = 0; i < n && things_printed < print_max; i++)
+ {
+ if (i != 0)
+ {
+ fprintf_filtered (stream, ", ");
+ }
+ wrap_here ("");
+
+ rep1 = i + 1;
+ reps = 1;
+ while (rep1 < n && !memcmp (VALUE_CONTENTS (val) + typelen * i,
+ VALUE_CONTENTS (val) + typelen * rep1,
+ typelen))
+ {
+ ++reps;
+ ++rep1;
+ }
+
+ if (reps > repeat_count_threshold)
+ {
+ val_print (VALUE_TYPE (val), VALUE_CONTENTS (val) + typelen * i,
+ VALUE_ADDRESS (val) + typelen * i, stream, format, 1,
+ 0, pretty);
+ fprintf_unfiltered (stream, " <repeats %u times>", reps);
+ i = rep1 - 1;
+ things_printed += repeat_count_threshold;
+ }
+ else
+ {
+ val_print (VALUE_TYPE (val), VALUE_CONTENTS (val) + typelen * i,
+ VALUE_ADDRESS (val) + typelen * i, stream, format, 1,
+ 0, pretty);
+ things_printed++;
+ }
+ }
+ if (i < n)
+ {
+ fprintf_filtered (stream, "...");
+ }
+}
+
+/* Print a string from the inferior, starting at ADDR and printing up to LEN
+ characters, to STREAM. If LEN is zero, printing stops at the first null
+ byte, otherwise printing proceeds (including null bytes) until either
+ print_max or LEN characters have been printed, whichever is smaller. */
+
+/* FIXME: All callers supply LEN of zero. Supplying a non-zero LEN is
+ pointless, this routine just then becomes a convoluted version of
+ target_read_memory_partial. Removing all the LEN stuff would simplify
+ this routine enormously.
+
+ FIXME: Use target_read_string. */
+
+int
+val_print_string (addr, len, stream)
+ CORE_ADDR addr;
+ unsigned int len;
+ GDB_FILE *stream;
+{
+ int force_ellipsis = 0; /* Force ellipsis to be printed if nonzero. */
+ int errcode; /* Errno returned from bad reads. */
+ unsigned int fetchlimit; /* Maximum number of bytes to fetch. */
+ unsigned int nfetch; /* Bytes to fetch / bytes fetched. */
+ unsigned int chunksize; /* Size of each fetch, in bytes. */
+ int bufsize; /* Size of current fetch buffer. */
+ char *buffer = NULL; /* Dynamically growable fetch buffer. */
+ char *bufptr; /* Pointer to next available byte in buffer. */
+ char *limit; /* First location past end of fetch buffer. */
+ struct cleanup *old_chain = NULL; /* Top of the old cleanup chain. */
+ char peekchar; /* Place into which we can read one char. */
+
+ /* First we need to figure out the limit on the number of characters we are
+ going to attempt to fetch and print. This is actually pretty simple. If
+ LEN is nonzero, then the limit is the minimum of LEN and print_max. If
+ LEN is zero, then the limit is print_max. This is true regardless of
+ whether print_max is zero, UINT_MAX (unlimited), or something in between,
+ because finding the null byte (or available memory) is what actually
+ limits the fetch. */
+
+ fetchlimit = (len == 0 ? print_max : min (len, print_max));
+
+ /* Now decide how large of chunks to try to read in one operation. This
+ is also pretty simple. If LEN is nonzero, then we want fetchlimit bytes,
+ so we might as well read them all in one operation. If LEN is zero, we
+ are looking for a null terminator to end the fetching, so we might as
+ well read in blocks that are large enough to be efficient, but not so
+ large as to be slow if fetchlimit happens to be large. So we choose the
+ minimum of 8 and fetchlimit. We used to use 200 instead of 8 but
+ 200 is way too big for remote debugging over a serial line. */
+
+ chunksize = (len == 0 ? min (8, fetchlimit) : fetchlimit);
+
+ /* Loop until we either have all the characters to print, or we encounter
+ some error, such as bumping into the end of the address space. */
+
+ bufsize = 0;
+ do {
+ QUIT;
+ /* Figure out how much to fetch this time, and grow the buffer to fit. */
+ nfetch = min (chunksize, fetchlimit - bufsize);
+ bufsize += nfetch;
+ if (buffer == NULL)
+ {
+ buffer = (char *) xmalloc (bufsize);
+ bufptr = buffer;
+ }
+ else
+ {
+ discard_cleanups (old_chain);
+ buffer = (char *) xrealloc (buffer, bufsize);
+ bufptr = buffer + bufsize - nfetch;
+ }
+ old_chain = make_cleanup (free, buffer);
+
+ /* Read as much as we can. */
+ nfetch = target_read_memory_partial (addr, bufptr, nfetch, &errcode);
+ if (len != 0)
+ {
+ addr += nfetch;
+ bufptr += nfetch;
+ }
+ else
+ {
+ /* Scan this chunk for the null byte that terminates the string
+ to print. If found, we don't need to fetch any more. Note
+ that bufptr is explicitly left pointing at the next character
+ after the null byte, or at the next character after the end of
+ the buffer. */
+ limit = bufptr + nfetch;
+ while (bufptr < limit)
+ {
+ ++addr;
+ ++bufptr;
+ if (bufptr[-1] == '\0')
+ {
+ /* We don't care about any error which happened after
+ the NULL terminator. */
+ errcode = 0;
+ break;
+ }
+ }
+ }
+ } while (errcode == 0 /* no error */
+ && bufsize < fetchlimit /* no overrun */
+ && !(len == 0 && *(bufptr - 1) == '\0')); /* no null term */
+
+ /* bufptr and addr now point immediately beyond the last byte which we
+ consider part of the string (including a '\0' which ends the string). */
+
+ /* We now have either successfully filled the buffer to fetchlimit, or
+ terminated early due to an error or finding a null byte when LEN is
+ zero. */
+
+ if (len == 0 && bufptr > buffer && *(bufptr - 1) != '\0')
+ {
+ /* We didn't find a null terminator we were looking for. Attempt
+ to peek at the next character. If not successful, or it is not
+ a null byte, then force ellipsis to be printed. */
+ if (target_read_memory (addr, &peekchar, 1) != 0 || peekchar != '\0')
+ {
+ force_ellipsis = 1;
+ }
+ }
+ else if ((len != 0 && errcode != 0) || (len > bufptr - buffer))
+ {
+ /* Getting an error when we have a requested length, or fetching less
+ than the number of characters actually requested, always make us
+ print ellipsis. */
+ force_ellipsis = 1;
+ }
+
+ QUIT;
+
+ /* If we get an error before fetching anything, don't print a string.
+ But if we fetch something and then get an error, print the string
+ and then the error message. */
+ if (errcode == 0 || bufptr > buffer)
+ {
+ if (addressprint)
+ {
+ fputs_filtered (" ", stream);
+ }
+ LA_PRINT_STRING (stream, buffer, bufptr - buffer, force_ellipsis);
+ }
+
+ if (errcode != 0)
+ {
+ if (errcode == EIO)
+ {
+ fprintf_filtered (stream, " <Address ");
+ print_address_numeric (addr, 1, stream);
+ fprintf_filtered (stream, " out of bounds>");
+ }
+ else
+ {
+ fprintf_filtered (stream, " <Error reading address ");
+ print_address_numeric (addr, 1, stream);
+ fprintf_filtered (stream, ": %s>", safe_strerror (errcode));
+ }
+ }
+ gdb_flush (stream);
+ do_cleanups (old_chain);
+ return (bufptr - buffer);
+}
+
+
+/* Validate an input or output radix setting, and make sure the user
+ knows what they really did here. Radix setting is confusing, e.g.
+ setting the input radix to "10" never changes it! */
+
+/* ARGSUSED */
+static void
+set_input_radix (args, from_tty, c)
+ char *args;
+ int from_tty;
+ struct cmd_list_element *c;
+{
+ set_input_radix_1 (from_tty, *(unsigned *)c->var);
+}
+
+/* ARGSUSED */
+static void
+set_input_radix_1 (from_tty, radix)
+ int from_tty;
+ unsigned radix;
+{
+ /* We don't currently disallow any input radix except 0 or 1, which don't
+ make any mathematical sense. In theory, we can deal with any input
+ radix greater than 1, even if we don't have unique digits for every
+ value from 0 to radix-1, but in practice we lose on large radix values.
+ We should either fix the lossage or restrict the radix range more.
+ (FIXME). */
+
+ if (radix < 2)
+ {
+ error ("Nonsense input radix ``decimal %u''; input radix unchanged.",
+ radix);
+ }
+ input_radix = radix;
+ if (from_tty)
+ {
+ printf_filtered ("Input radix now set to decimal %u, hex %x, octal %o.\n",
+ radix, radix, radix);
+ }
+}
+
+/* ARGSUSED */
+static void
+set_output_radix (args, from_tty, c)
+ char *args;
+ int from_tty;
+ struct cmd_list_element *c;
+{
+ set_output_radix_1 (from_tty, *(unsigned *)c->var);
+}
+
+static void
+set_output_radix_1 (from_tty, radix)
+ int from_tty;
+ unsigned radix;
+{
+ /* Validate the radix and disallow ones that we aren't prepared to
+ handle correctly, leaving the radix unchanged. */
+ switch (radix)
+ {
+ case 16:
+ output_format = 'x'; /* hex */
+ break;
+ case 10:
+ output_format = 0; /* decimal */
+ break;
+ case 8:
+ output_format = 'o'; /* octal */
+ break;
+ default:
+ error ("Unsupported output radix ``decimal %u''; output radix unchanged.",
+ radix);
+ }
+ output_radix = radix;
+ if (from_tty)
+ {
+ printf_filtered ("Output radix now set to decimal %u, hex %x, octal %o.\n",
+ radix, radix, radix);
+ }
+}
+
+/* Set both the input and output radix at once. Try to set the output radix
+ first, since it has the most restrictive range. An radix that is valid as
+ an output radix is also valid as an input radix.
+
+ It may be useful to have an unusual input radix. If the user wishes to
+ set an input radix that is not valid as an output radix, he needs to use
+ the 'set input-radix' command. */
+
+static void
+set_radix (arg, from_tty)
+ char *arg;
+ int from_tty;
+{
+ unsigned radix;
+
+ radix = (arg == NULL) ? 10 : parse_and_eval_address (arg);
+ set_output_radix_1 (0, radix);
+ set_input_radix_1 (0, radix);
+ if (from_tty)
+ {
+ printf_filtered ("Input and output radices now set to decimal %u, hex %x, octal %o.\n",
+ radix, radix, radix);
+ }
+}
+
+/* Show both the input and output radices. */
+
+/*ARGSUSED*/
+static void
+show_radix (arg, from_tty)
+ char *arg;
+ int from_tty;
+{
+ if (from_tty)
+ {
+ if (input_radix == output_radix)
+ {
+ printf_filtered ("Input and output radices set to decimal %u, hex %x, octal %o.\n",
+ input_radix, input_radix, input_radix);
+ }
+ else
+ {
+ printf_filtered ("Input radix set to decimal %u, hex %x, octal %o.\n",
+ input_radix, input_radix, input_radix);
+ printf_filtered ("Output radix set to decimal %u, hex %x, octal %o.\n",
+ output_radix, output_radix, output_radix);
+ }
+ }
+}
+
+
+/*ARGSUSED*/
+static void
+set_print (arg, from_tty)
+ char *arg;
+ int from_tty;
+{
+ printf_unfiltered (
+"\"set print\" must be followed by the name of a print subcommand.\n");
+ help_list (setprintlist, "set print ", -1, gdb_stdout);
+}
+
+/*ARGSUSED*/
+static void
+show_print (args, from_tty)
+ char *args;
+ int from_tty;
+{
+ cmd_show_list (showprintlist, from_tty, "");
+}
+
+void
+_initialize_valprint ()
+{
+ struct cmd_list_element *c;
+
+ add_prefix_cmd ("print", no_class, set_print,
+ "Generic command for setting how things print.",
+ &setprintlist, "set print ", 0, &setlist);
+ add_alias_cmd ("p", "print", no_class, 1, &setlist);
+ /* prefer set print to set prompt */
+ add_alias_cmd ("pr", "print", no_class, 1, &setlist);
+
+ add_prefix_cmd ("print", no_class, show_print,
+ "Generic command for showing print settings.",
+ &showprintlist, "show print ", 0, &showlist);
+ add_alias_cmd ("p", "print", no_class, 1, &showlist);
+ add_alias_cmd ("pr", "print", no_class, 1, &showlist);
+
+ add_show_from_set
+ (add_set_cmd ("elements", no_class, var_uinteger, (char *)&print_max,
+ "Set limit on string chars or array elements to print.\n\
+\"set print elements 0\" causes there to be no limit.",
+ &setprintlist),
+ &showprintlist);
+
+ add_show_from_set
+ (add_set_cmd ("null-stop", no_class, var_boolean,
+ (char *)&stop_print_at_null,
+ "Set printing of char arrays to stop at first null char.",
+ &setprintlist),
+ &showprintlist);
+
+ add_show_from_set
+ (add_set_cmd ("repeats", no_class, var_uinteger,
+ (char *)&repeat_count_threshold,
+ "Set threshold for repeated print elements.\n\
+\"set print repeats 0\" causes all elements to be individually printed.",
+ &setprintlist),
+ &showprintlist);
+
+ add_show_from_set
+ (add_set_cmd ("pretty", class_support, var_boolean,
+ (char *)&prettyprint_structs,
+ "Set prettyprinting of structures.",
+ &setprintlist),
+ &showprintlist);
+
+ add_show_from_set
+ (add_set_cmd ("union", class_support, var_boolean, (char *)&unionprint,
+ "Set printing of unions interior to structures.",
+ &setprintlist),
+ &showprintlist);
+
+ add_show_from_set
+ (add_set_cmd ("array", class_support, var_boolean,
+ (char *)&prettyprint_arrays,
+ "Set prettyprinting of arrays.",
+ &setprintlist),
+ &showprintlist);
+
+ add_show_from_set
+ (add_set_cmd ("address", class_support, var_boolean, (char *)&addressprint,
+ "Set printing of addresses.",
+ &setprintlist),
+ &showprintlist);
+
+ c = add_set_cmd ("input-radix", class_support, var_uinteger,
+ (char *)&input_radix,
+ "Set default input radix for entering numbers.",
+ &setlist);
+ add_show_from_set (c, &showlist);
+ c->function.sfunc = set_input_radix;
+
+ c = add_set_cmd ("output-radix", class_support, var_uinteger,
+ (char *)&output_radix,
+ "Set default output radix for printing of values.",
+ &setlist);
+ add_show_from_set (c, &showlist);
+ c->function.sfunc = set_output_radix;
+
+ /* The "set radix" and "show radix" commands are special in that they are
+ like normal set and show commands but allow two normally independent
+ variables to be either set or shown with a single command. So the
+ usual add_set_cmd() and add_show_from_set() commands aren't really
+ appropriate. */
+ add_cmd ("radix", class_support, set_radix,
+ "Set default input and output number radices.\n\
+Use 'set input-radix' or 'set output-radix' to independently set each.\n\
+Without an argument, sets both radices back to the default value of 10.",
+ &setlist);
+ add_cmd ("radix", class_support, show_radix,
+ "Show the default input and output number radices.\n\
+Use 'show input-radix' or 'show output-radix' to independently show each.",
+ &showlist);
+
+ /* Give people the defaults which they are used to. */
+ prettyprint_structs = 0;
+ prettyprint_arrays = 0;
+ unionprint = 1;
+ addressprint = 1;
+ print_max = PRINT_MAX_DEFAULT;
+}
diff --git a/gnu/usr.bin/gdb/gdb/valprint.h b/gnu/usr.bin/gdb/gdb/valprint.h
new file mode 100644
index 0000000..e45f48d
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/valprint.h
@@ -0,0 +1,44 @@
+/* Declarations for value printing routines for GDB, the GNU debugger.
+ Copyright 1986, 1988, 1989, 1991, 1992, 1993, 1994
+ Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+
+extern int prettyprint_arrays; /* Controls pretty printing of arrays. */
+extern int prettyprint_structs; /* Controls pretty printing of structures */
+extern int prettyprint_arrays; /* Controls pretty printing of arrays. */
+
+extern int vtblprint; /* Controls printing of vtbl's */
+extern int unionprint; /* Controls printing of nested unions. */
+extern int addressprint; /* Controls pretty printing of addresses. */
+extern int objectprint; /* Controls looking up an object's derived type
+ using what we find in its vtables. */
+
+extern unsigned int print_max; /* Max # of chars for strings/vectors */
+
+extern int output_format;
+
+extern int stop_print_at_null; /* Stop printing at null char? */
+
+extern void
+val_print_array_elements PARAMS ((struct type *, char *, CORE_ADDR, GDB_FILE *,
+ int, int, int, enum val_prettyprint, int));
+
+extern void
+val_print_type_code_int PARAMS ((struct type *, char *, GDB_FILE *));
+
diff --git a/gnu/usr.bin/gdb/gdb/value.h b/gnu/usr.bin/gdb/gdb/value.h
new file mode 100644
index 0000000..31d3585
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/value.h
@@ -0,0 +1,482 @@
+/* Definitions for values of C expressions, for GDB.
+ Copyright 1986, 1987, 1989, 1992, 1993, 1994 Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#if !defined (VALUE_H)
+#define VALUE_H 1
+
+/*
+ * The structure which defines the type of a value. It should never
+ * be possible for a program lval value to survive over a call to the inferior
+ * (ie to be put into the history list or an internal variable).
+ */
+enum lval_type {
+ /* Not an lval. */
+ not_lval,
+ /* In memory. Could be a saved register. */
+ lval_memory,
+ /* In a register. */
+ lval_register,
+ /* In a gdb internal variable. */
+ lval_internalvar,
+ /* Part of a gdb internal variable (structure field). */
+ lval_internalvar_component,
+ /* In a register series in a frame not the current one, which may have been
+ partially saved or saved in different places (otherwise would be
+ lval_register or lval_memory). */
+ lval_reg_frame_relative
+};
+
+struct value
+ {
+ /* Type of value; either not an lval, or one of the various
+ different possible kinds of lval. */
+ enum lval_type lval;
+ /* Is it modifiable? Only relevant if lval != not_lval. */
+ int modifiable;
+ /* Location of value (if lval). */
+ union
+ {
+ /* Address in inferior or byte of registers structure. */
+ CORE_ADDR address;
+ /* Pointer to internal variable. */
+ struct internalvar *internalvar;
+ /* Number of register. Only used with
+ lval_reg_frame_relative. */
+ int regnum;
+ } location;
+ /* Describes offset of a value within lval a structure in bytes. */
+ int offset;
+ /* Only used for bitfields; number of bits contained in them. */
+ int bitsize;
+ /* Only used for bitfields; position of start of field.
+ For BITS_BIG_ENDIAN=0 targets, it is the position of the LSB.
+ For BITS_BIG_ENDIAN=1 targets, it is the position of the MSB. */
+ int bitpos;
+ /* Frame value is relative to. In practice, this address is only
+ used if the value is stored in several registers in other than
+ the current frame, and these registers have not all been saved
+ at the same place in memory. This will be described in the
+ lval enum above as "lval_reg_frame_relative". */
+ CORE_ADDR frame_addr;
+ /* Type of the value. */
+ struct type *type;
+ /* Values are stored in a chain, so that they can be deleted
+ easily over calls to the inferior. Values assigned to internal
+ variables or put into the value history are taken off this
+ list. */
+ struct value *next;
+ /* If an lval is forced to repeat, a new value is created with
+ these fields set. The new value is not an lval. */
+ short repeated;
+ short repetitions;
+ /* Register number if the value is from a register. Is not kept
+ if you take a field of a structure that is stored in a
+ register. Shouldn't it be? */
+ short regno;
+ /* If zero, contents of this value are in the contents field.
+ If nonzero, contents are in inferior memory at address
+ in the location.address field plus the offset field
+ (and the lval field should be lval_memory). */
+ char lazy;
+ /* If nonzero, this is the value of a variable which does not
+ actually exist in the program. */
+ char optimized_out;
+ /* Actual contents of the value. For use of this value; setting
+ it uses the stuff above. Not valid if lazy is nonzero.
+ Target byte-order. We force it to be aligned properly for any
+ possible value. */
+ union {
+ long contents[1];
+ double force_double_align;
+ LONGEST force_longlong_align;
+ } aligner;
+
+ };
+
+typedef struct value *value_ptr;
+
+#define VALUE_TYPE(val) (val)->type
+#define VALUE_LAZY(val) (val)->lazy
+/* VALUE_CONTENTS and VALUE_CONTENTS_RAW both return the address of
+ the gdb buffer used to hold a copy of the contents of the lval.
+ VALUE_CONTENTS is used when the contents of the buffer are needed --
+ it uses value_fetch_lazy() to load the buffer from the process being
+ debugged if it hasn't already been loaded. VALUE_CONTENTS_RAW is
+ used when data is being stored into the buffer, or when it is
+ certain that the contents of the buffer are valid. */
+#define VALUE_CONTENTS_RAW(val) ((char *) (val)->aligner.contents)
+#define VALUE_CONTENTS(val) ((void)(VALUE_LAZY(val) && value_fetch_lazy(val)),\
+ VALUE_CONTENTS_RAW(val))
+extern int value_fetch_lazy PARAMS ((value_ptr val));
+
+#define VALUE_LVAL(val) (val)->lval
+#define VALUE_ADDRESS(val) (val)->location.address
+#define VALUE_INTERNALVAR(val) (val)->location.internalvar
+#define VALUE_FRAME_REGNUM(val) ((val)->location.regnum)
+#define VALUE_FRAME(val) ((val)->frame_addr)
+#define VALUE_OFFSET(val) (val)->offset
+#define VALUE_BITSIZE(val) (val)->bitsize
+#define VALUE_BITPOS(val) (val)->bitpos
+#define VALUE_NEXT(val) (val)->next
+#define VALUE_REPEATED(val) (val)->repeated
+#define VALUE_REPETITIONS(val) (val)->repetitions
+#define VALUE_REGNO(val) (val)->regno
+#define VALUE_OPTIMIZED_OUT(val) ((val)->optimized_out)
+
+/* Convert a REF to the object referenced. */
+
+#define COERCE_REF(arg) \
+{ if (TYPE_CODE (VALUE_TYPE (arg)) == TYPE_CODE_REF) \
+ arg = value_at_lazy (TYPE_TARGET_TYPE (VALUE_TYPE (arg)), \
+ unpack_long (VALUE_TYPE (arg), \
+ VALUE_CONTENTS (arg)));}
+
+/* If ARG is an array, convert it to a pointer.
+ If ARG is an enum, convert it to an integer.
+ If ARG is a function, convert it to a function pointer.
+
+ References are dereferenced. */
+
+#define COERCE_ARRAY(arg) \
+{ COERCE_REF(arg); \
+ if (VALUE_REPEATED (arg) \
+ || TYPE_CODE (VALUE_TYPE (arg)) == TYPE_CODE_ARRAY) \
+ arg = value_coerce_array (arg); \
+ if (TYPE_CODE (VALUE_TYPE (arg)) == TYPE_CODE_FUNC) \
+ arg = value_coerce_function (arg); \
+ if (TYPE_CODE (VALUE_TYPE (arg)) == TYPE_CODE_ENUM) \
+ arg = value_cast (builtin_type_unsigned_int, arg); \
+}
+
+/* If ARG is an enum, convert it to an integer. */
+
+#define COERCE_ENUM(arg) \
+{ COERCE_REF (arg); \
+ if (TYPE_CODE (VALUE_TYPE (arg)) == TYPE_CODE_ENUM) \
+ arg = value_cast (builtin_type_unsigned_int, arg); \
+}
+
+/* Internal variables (variables for convenience of use of debugger)
+ are recorded as a chain of these structures. */
+
+struct internalvar
+{
+ struct internalvar *next;
+ char *name;
+ value_ptr value;
+};
+
+/* Pointer to member function. Depends on compiler implementation. */
+
+#define METHOD_PTR_IS_VIRTUAL(ADDR) ((ADDR) & 0x80000000)
+#define METHOD_PTR_FROM_VOFFSET(OFFSET) (0x80000000 + (OFFSET))
+#define METHOD_PTR_TO_VOFFSET(ADDR) (~0x80000000 & (ADDR))
+
+
+#include "symtab.h"
+#include "gdbtypes.h"
+#include "expression.h"
+
+#ifdef __STDC__
+struct frame_info;
+struct fn_field;
+#endif
+
+extern void
+print_address_demangle PARAMS ((CORE_ADDR, GDB_FILE *, int));
+
+extern LONGEST value_as_long PARAMS ((value_ptr val));
+
+extern double value_as_double PARAMS ((value_ptr val));
+
+extern CORE_ADDR value_as_pointer PARAMS ((value_ptr val));
+
+extern LONGEST unpack_long PARAMS ((struct type *type, char *valaddr));
+
+extern double unpack_double PARAMS ((struct type *type, char *valaddr,
+ int *invp));
+
+extern CORE_ADDR unpack_pointer PARAMS ((struct type *type, char *valaddr));
+
+extern LONGEST unpack_field_as_long PARAMS ((struct type *type, char *valaddr,
+ int fieldno));
+
+extern value_ptr value_from_longest PARAMS ((struct type *type, LONGEST num));
+
+extern value_ptr value_from_double PARAMS ((struct type *type, double num));
+
+extern value_ptr value_at PARAMS ((struct type *type, CORE_ADDR addr));
+
+extern value_ptr value_at_lazy PARAMS ((struct type *type, CORE_ADDR addr));
+
+/* FIXME: Assumes equivalence of "struct frame_info *" and "FRAME" */
+extern value_ptr value_from_register PARAMS ((struct type *type, int regnum,
+ struct frame_info * frame));
+
+extern value_ptr value_of_variable PARAMS ((struct symbol *var,
+ struct block *b));
+
+extern value_ptr value_of_register PARAMS ((int regnum));
+
+extern int symbol_read_needs_frame PARAMS ((struct symbol *));
+
+/* FIXME: Assumes equivalence of "struct frame_info *" and "FRAME" */
+extern value_ptr read_var_value PARAMS ((struct symbol *var,
+ struct frame_info *frame));
+
+/* FIXME: Assumes equivalence of "struct frame_info *" and "FRAME" */
+extern value_ptr locate_var_value PARAMS ((struct symbol *var,
+ struct frame_info *frame));
+
+extern value_ptr allocate_value PARAMS ((struct type *type));
+
+extern value_ptr allocate_repeat_value PARAMS ((struct type *type, int count));
+
+extern value_ptr value_mark PARAMS ((void));
+
+extern void value_free_to_mark PARAMS ((value_ptr mark));
+
+extern value_ptr value_string PARAMS ((char *ptr, int len));
+
+extern value_ptr value_array PARAMS ((int lowbound, int highbound,
+ value_ptr *elemvec));
+
+extern value_ptr value_concat PARAMS ((value_ptr arg1, value_ptr arg2));
+
+extern value_ptr value_binop PARAMS ((value_ptr arg1, value_ptr arg2,
+ enum exp_opcode op));
+
+extern value_ptr value_add PARAMS ((value_ptr arg1, value_ptr arg2));
+
+extern value_ptr value_sub PARAMS ((value_ptr arg1, value_ptr arg2));
+
+extern value_ptr value_coerce_array PARAMS ((value_ptr arg1));
+
+extern value_ptr value_coerce_function PARAMS ((value_ptr arg1));
+
+extern value_ptr value_ind PARAMS ((value_ptr arg1));
+
+extern value_ptr value_addr PARAMS ((value_ptr arg1));
+
+extern value_ptr value_assign PARAMS ((value_ptr toval, value_ptr fromval));
+
+extern value_ptr value_neg PARAMS ((value_ptr arg1));
+
+extern value_ptr value_complement PARAMS ((value_ptr arg1));
+
+extern value_ptr value_struct_elt PARAMS ((value_ptr *argp, value_ptr *args,
+ char *name,
+ int *static_memfuncp, char *err));
+
+extern value_ptr value_struct_elt_for_reference PARAMS ((struct type *domain,
+ int offset,
+ struct type *curtype,
+ char *name,
+ struct type *intype));
+
+extern value_ptr value_field PARAMS ((value_ptr arg1, int fieldno));
+
+extern value_ptr value_primitive_field PARAMS ((value_ptr arg1, int offset,
+ int fieldno,
+ struct type *arg_type));
+
+extern value_ptr value_cast PARAMS ((struct type *type, value_ptr arg2));
+
+extern value_ptr value_zero PARAMS ((struct type *type, enum lval_type lv));
+
+extern value_ptr value_repeat PARAMS ((value_ptr arg1, int count));
+
+extern value_ptr value_subscript PARAMS ((value_ptr array, value_ptr idx));
+
+extern value_ptr value_from_vtable_info PARAMS ((value_ptr arg,
+ struct type *type));
+
+extern value_ptr value_being_returned PARAMS ((struct type *valtype,
+ char retbuf[REGISTER_BYTES],
+ int struct_return));
+
+extern value_ptr value_in PARAMS ((value_ptr element, value_ptr set));
+
+extern int value_bit_index PARAMS ((struct type *type, char *addr, int index));
+
+extern int using_struct_return PARAMS ((value_ptr function, CORE_ADDR funcaddr,
+ struct type *value_type, int gcc_p));
+
+extern void set_return_value PARAMS ((value_ptr val));
+
+extern value_ptr evaluate_expression PARAMS ((struct expression *exp));
+
+extern value_ptr evaluate_type PARAMS ((struct expression *exp));
+
+extern value_ptr parse_and_eval PARAMS ((char *exp));
+
+extern value_ptr parse_to_comma_and_eval PARAMS ((char **expp));
+
+extern struct type *parse_and_eval_type PARAMS ((char *p, int length));
+
+extern CORE_ADDR parse_and_eval_address PARAMS ((char *exp));
+
+extern CORE_ADDR parse_and_eval_address_1 PARAMS ((char **expptr));
+
+extern value_ptr access_value_history PARAMS ((int num));
+
+extern value_ptr value_of_internalvar PARAMS ((struct internalvar *var));
+
+extern void set_internalvar PARAMS ((struct internalvar *var, value_ptr val));
+
+extern void set_internalvar_component PARAMS ((struct internalvar *var,
+ int offset,
+ int bitpos, int bitsize,
+ value_ptr newvalue));
+
+extern struct internalvar *lookup_internalvar PARAMS ((char *name));
+
+extern int value_equal PARAMS ((value_ptr arg1, value_ptr arg2));
+
+extern int value_less PARAMS ((value_ptr arg1, value_ptr arg2));
+
+extern int value_logical_not PARAMS ((value_ptr arg1));
+
+/* C++ */
+
+extern value_ptr value_of_this PARAMS ((int complain));
+
+extern value_ptr value_x_binop PARAMS ((value_ptr arg1, value_ptr arg2,
+ enum exp_opcode op,
+ enum exp_opcode otherop));
+
+extern value_ptr value_x_unop PARAMS ((value_ptr arg1, enum exp_opcode op));
+
+extern value_ptr value_fn_field PARAMS ((value_ptr *arg1p, struct fn_field *f,
+ int j,
+ struct type* type, int offset));
+
+extern value_ptr value_virtual_fn_field PARAMS ((value_ptr *arg1p,
+ struct fn_field *f, int j,
+ struct type *type,
+ int offset));
+
+extern int binop_user_defined_p PARAMS ((enum exp_opcode op,
+ value_ptr arg1, value_ptr arg2));
+
+extern int unop_user_defined_p PARAMS ((enum exp_opcode op, value_ptr arg1));
+
+extern int destructor_name_p PARAMS ((const char *name,
+ const struct type *type));
+
+#define value_free(val) free ((PTR)val)
+
+extern void free_all_values PARAMS ((void));
+
+extern void release_value PARAMS ((value_ptr val));
+
+extern int record_latest_value PARAMS ((value_ptr val));
+
+extern void registers_changed PARAMS ((void));
+
+extern void read_register_bytes PARAMS ((int regbyte, char *myaddr, int len));
+
+extern void write_register_bytes PARAMS ((int regbyte, char *myaddr, int len));
+
+extern void
+read_register_gen PARAMS ((int regno, char *myaddr));
+
+extern CORE_ADDR
+read_register PARAMS ((int regno));
+
+extern void
+write_register PARAMS ((int regno, LONGEST val));
+
+extern void
+supply_register PARAMS ((int regno, char *val));
+
+/* FIXME: Assumes equivalence of "struct frame_info *" and "FRAME" */
+extern void
+get_saved_register PARAMS ((char *raw_buffer, int *optimized,
+ CORE_ADDR *addrp, struct frame_info *frame,
+ int regnum, enum lval_type *lval));
+
+extern void
+modify_field PARAMS ((char *addr, LONGEST fieldval, int bitpos, int bitsize));
+
+extern void
+type_print PARAMS ((struct type *type, char *varstring, GDB_FILE *stream,
+ int show));
+
+extern char *baseclass_addr PARAMS ((struct type *type, int index,
+ char *valaddr,
+ value_ptr *valuep, int *errp));
+
+extern void
+print_longest PARAMS ((GDB_FILE *stream, int format, int use_local,
+ LONGEST val));
+
+extern void
+print_floating PARAMS ((char *valaddr, struct type *type, GDB_FILE *stream));
+
+extern int value_print PARAMS ((value_ptr val, GDB_FILE *stream, int format,
+ enum val_prettyprint pretty));
+
+extern void
+value_print_array_elements PARAMS ((value_ptr val, GDB_FILE* stream,
+ int format, enum val_prettyprint pretty));
+
+extern value_ptr
+value_release_to_mark PARAMS ((value_ptr mark));
+
+extern int
+val_print PARAMS ((struct type *type, char *valaddr, CORE_ADDR address,
+ GDB_FILE *stream, int format, int deref_ref,
+ int recurse, enum val_prettyprint pretty));
+
+extern int
+val_print_string PARAMS ((CORE_ADDR addr, unsigned int len, GDB_FILE *stream));
+
+/* FIXME: Assumes equivalence of "struct frame_info *" and "FRAME" */
+extern void
+print_variable_value PARAMS ((struct symbol *var, struct frame_info *frame,
+ GDB_FILE *stream));
+
+extern value_ptr value_arg_coerce PARAMS ((value_ptr));
+
+extern int check_field PARAMS ((value_ptr, const char *));
+
+extern void
+c_typedef_print PARAMS ((struct type *type, struct symbol *new, GDB_FILE *stream));
+
+extern char *
+internalvar_name PARAMS ((struct internalvar *var));
+
+extern void
+clear_value_history PARAMS ((void));
+
+extern void
+clear_internalvars PARAMS ((void));
+
+/* From values.c */
+
+extern value_ptr value_copy PARAMS ((value_ptr));
+
+extern int baseclass_offset PARAMS ((struct type *, int, value_ptr, int));
+
+/* From valops.c */
+
+extern value_ptr call_function_by_hand PARAMS ((value_ptr, int, value_ptr *));
+
+#endif /* !defined (VALUE_H) */
diff --git a/gnu/usr.bin/gdb/gdb/values.c b/gnu/usr.bin/gdb/gdb/values.c
new file mode 100644
index 0000000..3a2dd43
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/values.c
@@ -0,0 +1,1508 @@
+/* Low level packing and unpacking of values for GDB, the GNU Debugger.
+ Copyright 1986, 1987, 1989, 1991 Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "defs.h"
+#include <string.h>
+#include "symtab.h"
+#include "gdbtypes.h"
+#include "value.h"
+#include "gdbcore.h"
+#include "frame.h"
+#include "command.h"
+#include "gdbcmd.h"
+#include "target.h"
+#include "demangle.h"
+
+/* Local function prototypes. */
+
+static value_ptr value_headof PARAMS ((value_ptr, struct type *,
+ struct type *));
+
+static void show_values PARAMS ((char *, int));
+
+static void show_convenience PARAMS ((char *, int));
+
+/* The value-history records all the values printed
+ by print commands during this session. Each chunk
+ records 60 consecutive values. The first chunk on
+ the chain records the most recent values.
+ The total number of values is in value_history_count. */
+
+#define VALUE_HISTORY_CHUNK 60
+
+struct value_history_chunk
+{
+ struct value_history_chunk *next;
+ value_ptr values[VALUE_HISTORY_CHUNK];
+};
+
+/* Chain of chunks now in use. */
+
+static struct value_history_chunk *value_history_chain;
+
+static int value_history_count; /* Abs number of last entry stored */
+
+/* List of all value objects currently allocated
+ (except for those released by calls to release_value)
+ This is so they can be freed after each command. */
+
+static value_ptr all_values;
+
+/* Allocate a value that has the correct length for type TYPE. */
+
+value_ptr
+allocate_value (type)
+ struct type *type;
+{
+ register value_ptr val;
+
+ check_stub_type (type);
+
+ val = (struct value *) xmalloc (sizeof (struct value) + TYPE_LENGTH (type));
+ VALUE_NEXT (val) = all_values;
+ all_values = val;
+ VALUE_TYPE (val) = type;
+ VALUE_LVAL (val) = not_lval;
+ VALUE_ADDRESS (val) = 0;
+ VALUE_FRAME (val) = 0;
+ VALUE_OFFSET (val) = 0;
+ VALUE_BITPOS (val) = 0;
+ VALUE_BITSIZE (val) = 0;
+ VALUE_REPEATED (val) = 0;
+ VALUE_REPETITIONS (val) = 0;
+ VALUE_REGNO (val) = -1;
+ VALUE_LAZY (val) = 0;
+ VALUE_OPTIMIZED_OUT (val) = 0;
+ val->modifiable = 1;
+ return val;
+}
+
+/* Allocate a value that has the correct length
+ for COUNT repetitions type TYPE. */
+
+value_ptr
+allocate_repeat_value (type, count)
+ struct type *type;
+ int count;
+{
+ register value_ptr val;
+
+ val =
+ (value_ptr) xmalloc (sizeof (struct value) + TYPE_LENGTH (type) * count);
+ VALUE_NEXT (val) = all_values;
+ all_values = val;
+ VALUE_TYPE (val) = type;
+ VALUE_LVAL (val) = not_lval;
+ VALUE_ADDRESS (val) = 0;
+ VALUE_FRAME (val) = 0;
+ VALUE_OFFSET (val) = 0;
+ VALUE_BITPOS (val) = 0;
+ VALUE_BITSIZE (val) = 0;
+ VALUE_REPEATED (val) = 1;
+ VALUE_REPETITIONS (val) = count;
+ VALUE_REGNO (val) = -1;
+ VALUE_LAZY (val) = 0;
+ VALUE_OPTIMIZED_OUT (val) = 0;
+ return val;
+}
+
+/* Return a mark in the value chain. All values allocated after the
+ mark is obtained (except for those released) are subject to being freed
+ if a subsequent value_free_to_mark is passed the mark. */
+value_ptr
+value_mark ()
+{
+ return all_values;
+}
+
+/* Free all values allocated since MARK was obtained by value_mark
+ (except for those released). */
+void
+value_free_to_mark (mark)
+ value_ptr mark;
+{
+ value_ptr val, next;
+
+ for (val = all_values; val && val != mark; val = next)
+ {
+ next = VALUE_NEXT (val);
+ value_free (val);
+ }
+ all_values = val;
+}
+
+/* Free all the values that have been allocated (except for those released).
+ Called after each command, successful or not. */
+
+void
+free_all_values ()
+{
+ register value_ptr val, next;
+
+ for (val = all_values; val; val = next)
+ {
+ next = VALUE_NEXT (val);
+ value_free (val);
+ }
+
+ all_values = 0;
+}
+
+/* Remove VAL from the chain all_values
+ so it will not be freed automatically. */
+
+void
+release_value (val)
+ register value_ptr val;
+{
+ register value_ptr v;
+
+ if (all_values == val)
+ {
+ all_values = val->next;
+ return;
+ }
+
+ for (v = all_values; v; v = v->next)
+ {
+ if (v->next == val)
+ {
+ v->next = val->next;
+ break;
+ }
+ }
+}
+
+/* Release all values up to mark */
+value_ptr
+value_release_to_mark (mark)
+ value_ptr mark;
+{
+ value_ptr val, next;
+
+ for (val = next = all_values; next; next = VALUE_NEXT (next))
+ if (VALUE_NEXT (next) == mark)
+ {
+ all_values = VALUE_NEXT (next);
+ VALUE_NEXT (next) = 0;
+ return val;
+ }
+ all_values = 0;
+ return val;
+}
+
+/* Return a copy of the value ARG.
+ It contains the same contents, for same memory address,
+ but it's a different block of storage. */
+
+value_ptr
+value_copy (arg)
+ value_ptr arg;
+{
+ register value_ptr val;
+ register struct type *type = VALUE_TYPE (arg);
+ if (VALUE_REPEATED (arg))
+ val = allocate_repeat_value (type, VALUE_REPETITIONS (arg));
+ else
+ val = allocate_value (type);
+ VALUE_LVAL (val) = VALUE_LVAL (arg);
+ VALUE_ADDRESS (val) = VALUE_ADDRESS (arg);
+ VALUE_OFFSET (val) = VALUE_OFFSET (arg);
+ VALUE_BITPOS (val) = VALUE_BITPOS (arg);
+ VALUE_BITSIZE (val) = VALUE_BITSIZE (arg);
+ VALUE_REGNO (val) = VALUE_REGNO (arg);
+ VALUE_LAZY (val) = VALUE_LAZY (arg);
+ val->modifiable = arg->modifiable;
+ if (!VALUE_LAZY (val))
+ {
+ memcpy (VALUE_CONTENTS_RAW (val), VALUE_CONTENTS_RAW (arg),
+ TYPE_LENGTH (VALUE_TYPE (arg))
+ * (VALUE_REPEATED (arg) ? VALUE_REPETITIONS (arg) : 1));
+ }
+ return val;
+}
+
+/* Access to the value history. */
+
+/* Record a new value in the value history.
+ Returns the absolute history index of the entry.
+ Result of -1 indicates the value was not saved; otherwise it is the
+ value history index of this new item. */
+
+int
+record_latest_value (val)
+ value_ptr val;
+{
+ int i;
+
+ /* Check error now if about to store an invalid float. We return -1
+ to the caller, but allow them to continue, e.g. to print it as "Nan". */
+ if (TYPE_CODE (VALUE_TYPE (val)) == TYPE_CODE_FLT)
+ {
+ unpack_double (VALUE_TYPE (val), VALUE_CONTENTS (val), &i);
+ if (i) return -1; /* Indicate value not saved in history */
+ }
+
+ /* Here we treat value_history_count as origin-zero
+ and applying to the value being stored now. */
+
+ i = value_history_count % VALUE_HISTORY_CHUNK;
+ if (i == 0)
+ {
+ register struct value_history_chunk *new
+ = (struct value_history_chunk *)
+ xmalloc (sizeof (struct value_history_chunk));
+ memset (new->values, 0, sizeof new->values);
+ new->next = value_history_chain;
+ value_history_chain = new;
+ }
+
+ value_history_chain->values[i] = val;
+
+ /* We don't want this value to have anything to do with the inferior anymore.
+ In particular, "set $1 = 50" should not affect the variable from which
+ the value was taken, and fast watchpoints should be able to assume that
+ a value on the value history never changes. */
+ if (VALUE_LAZY (val))
+ value_fetch_lazy (val);
+ /* We preserve VALUE_LVAL so that the user can find out where it was fetched
+ from. This is a bit dubious, because then *&$1 does not just return $1
+ but the current contents of that location. c'est la vie... */
+ val->modifiable = 0;
+ release_value (val);
+
+ /* Now we regard value_history_count as origin-one
+ and applying to the value just stored. */
+
+ return ++value_history_count;
+}
+
+/* Return a copy of the value in the history with sequence number NUM. */
+
+value_ptr
+access_value_history (num)
+ int num;
+{
+ register struct value_history_chunk *chunk;
+ register int i;
+ register int absnum = num;
+
+ if (absnum <= 0)
+ absnum += value_history_count;
+
+ if (absnum <= 0)
+ {
+ if (num == 0)
+ error ("The history is empty.");
+ else if (num == 1)
+ error ("There is only one value in the history.");
+ else
+ error ("History does not go back to $$%d.", -num);
+ }
+ if (absnum > value_history_count)
+ error ("History has not yet reached $%d.", absnum);
+
+ absnum--;
+
+ /* Now absnum is always absolute and origin zero. */
+
+ chunk = value_history_chain;
+ for (i = (value_history_count - 1) / VALUE_HISTORY_CHUNK - absnum / VALUE_HISTORY_CHUNK;
+ i > 0; i--)
+ chunk = chunk->next;
+
+ return value_copy (chunk->values[absnum % VALUE_HISTORY_CHUNK]);
+}
+
+/* Clear the value history entirely.
+ Must be done when new symbol tables are loaded,
+ because the type pointers become invalid. */
+
+void
+clear_value_history ()
+{
+ register struct value_history_chunk *next;
+ register int i;
+ register value_ptr val;
+
+ while (value_history_chain)
+ {
+ for (i = 0; i < VALUE_HISTORY_CHUNK; i++)
+ if ((val = value_history_chain->values[i]) != NULL)
+ free ((PTR)val);
+ next = value_history_chain->next;
+ free ((PTR)value_history_chain);
+ value_history_chain = next;
+ }
+ value_history_count = 0;
+}
+
+static void
+show_values (num_exp, from_tty)
+ char *num_exp;
+ int from_tty;
+{
+ register int i;
+ register value_ptr val;
+ static int num = 1;
+
+ if (num_exp)
+ {
+ /* "info history +" should print from the stored position.
+ "info history <exp>" should print around value number <exp>. */
+ if (num_exp[0] != '+' || num_exp[1] != '\0')
+ num = parse_and_eval_address (num_exp) - 5;
+ }
+ else
+ {
+ /* "info history" means print the last 10 values. */
+ num = value_history_count - 9;
+ }
+
+ if (num <= 0)
+ num = 1;
+
+ for (i = num; i < num + 10 && i <= value_history_count; i++)
+ {
+ val = access_value_history (i);
+ printf_filtered ("$%d = ", i);
+ value_print (val, gdb_stdout, 0, Val_pretty_default);
+ printf_filtered ("\n");
+ }
+
+ /* The next "info history +" should start after what we just printed. */
+ num += 10;
+
+ /* Hitting just return after this command should do the same thing as
+ "info history +". If num_exp is null, this is unnecessary, since
+ "info history +" is not useful after "info history". */
+ if (from_tty && num_exp)
+ {
+ num_exp[0] = '+';
+ num_exp[1] = '\0';
+ }
+}
+
+/* Internal variables. These are variables within the debugger
+ that hold values assigned by debugger commands.
+ The user refers to them with a '$' prefix
+ that does not appear in the variable names stored internally. */
+
+static struct internalvar *internalvars;
+
+/* Look up an internal variable with name NAME. NAME should not
+ normally include a dollar sign.
+
+ If the specified internal variable does not exist,
+ one is created, with a void value. */
+
+struct internalvar *
+lookup_internalvar (name)
+ char *name;
+{
+ register struct internalvar *var;
+
+ for (var = internalvars; var; var = var->next)
+ if (STREQ (var->name, name))
+ return var;
+
+ var = (struct internalvar *) xmalloc (sizeof (struct internalvar));
+ var->name = concat (name, NULL);
+ var->value = allocate_value (builtin_type_void);
+ release_value (var->value);
+ var->next = internalvars;
+ internalvars = var;
+ return var;
+}
+
+value_ptr
+value_of_internalvar (var)
+ struct internalvar *var;
+{
+ register value_ptr val;
+
+#ifdef IS_TRAPPED_INTERNALVAR
+ if (IS_TRAPPED_INTERNALVAR (var->name))
+ return VALUE_OF_TRAPPED_INTERNALVAR (var);
+#endif
+
+ val = value_copy (var->value);
+ if (VALUE_LAZY (val))
+ value_fetch_lazy (val);
+ VALUE_LVAL (val) = lval_internalvar;
+ VALUE_INTERNALVAR (val) = var;
+ return val;
+}
+
+void
+set_internalvar_component (var, offset, bitpos, bitsize, newval)
+ struct internalvar *var;
+ int offset, bitpos, bitsize;
+ value_ptr newval;
+{
+ register char *addr = VALUE_CONTENTS (var->value) + offset;
+
+#ifdef IS_TRAPPED_INTERNALVAR
+ if (IS_TRAPPED_INTERNALVAR (var->name))
+ SET_TRAPPED_INTERNALVAR (var, newval, bitpos, bitsize, offset);
+#endif
+
+ if (bitsize)
+ modify_field (addr, value_as_long (newval),
+ bitpos, bitsize);
+ else
+ memcpy (addr, VALUE_CONTENTS (newval), TYPE_LENGTH (VALUE_TYPE (newval)));
+}
+
+void
+set_internalvar (var, val)
+ struct internalvar *var;
+ value_ptr val;
+{
+ value_ptr newval;
+
+#ifdef IS_TRAPPED_INTERNALVAR
+ if (IS_TRAPPED_INTERNALVAR (var->name))
+ SET_TRAPPED_INTERNALVAR (var, val, 0, 0, 0);
+#endif
+
+ newval = value_copy (val);
+
+ /* Force the value to be fetched from the target now, to avoid problems
+ later when this internalvar is referenced and the target is gone or
+ has changed. */
+ if (VALUE_LAZY (newval))
+ value_fetch_lazy (newval);
+
+ /* Begin code which must not call error(). If var->value points to
+ something free'd, an error() obviously leaves a dangling pointer.
+ But we also get a danling pointer if var->value points to
+ something in the value chain (i.e., before release_value is
+ called), because after the error free_all_values will get called before
+ long. */
+ free ((PTR)var->value);
+ var->value = newval;
+ release_value (newval);
+ /* End code which must not call error(). */
+}
+
+char *
+internalvar_name (var)
+ struct internalvar *var;
+{
+ return var->name;
+}
+
+/* Free all internalvars. Done when new symtabs are loaded,
+ because that makes the values invalid. */
+
+void
+clear_internalvars ()
+{
+ register struct internalvar *var;
+
+ while (internalvars)
+ {
+ var = internalvars;
+ internalvars = var->next;
+ free ((PTR)var->name);
+ free ((PTR)var->value);
+ free ((PTR)var);
+ }
+}
+
+static void
+show_convenience (ignore, from_tty)
+ char *ignore;
+ int from_tty;
+{
+ register struct internalvar *var;
+ int varseen = 0;
+
+ for (var = internalvars; var; var = var->next)
+ {
+#ifdef IS_TRAPPED_INTERNALVAR
+ if (IS_TRAPPED_INTERNALVAR (var->name))
+ continue;
+#endif
+ if (!varseen)
+ {
+ varseen = 1;
+ }
+ printf_filtered ("$%s = ", var->name);
+ value_print (var->value, gdb_stdout, 0, Val_pretty_default);
+ printf_filtered ("\n");
+ }
+ if (!varseen)
+ printf_unfiltered ("No debugger convenience variables now defined.\n\
+Convenience variables have names starting with \"$\";\n\
+use \"set\" as in \"set $foo = 5\" to define them.\n");
+}
+
+/* Extract a value as a C number (either long or double).
+ Knows how to convert fixed values to double, or
+ floating values to long.
+ Does not deallocate the value. */
+
+LONGEST
+value_as_long (val)
+ register value_ptr val;
+{
+ /* This coerces arrays and functions, which is necessary (e.g.
+ in disassemble_command). It also dereferences references, which
+ I suspect is the most logical thing to do. */
+ if (TYPE_CODE (VALUE_TYPE (val)) != TYPE_CODE_ENUM)
+ COERCE_ARRAY (val);
+ return unpack_long (VALUE_TYPE (val), VALUE_CONTENTS (val));
+}
+
+double
+value_as_double (val)
+ register value_ptr val;
+{
+ double foo;
+ int inv;
+
+ foo = unpack_double (VALUE_TYPE (val), VALUE_CONTENTS (val), &inv);
+ if (inv)
+ error ("Invalid floating value found in program.");
+ return foo;
+}
+/* Extract a value as a C pointer.
+ Does not deallocate the value. */
+CORE_ADDR
+value_as_pointer (val)
+ value_ptr val;
+{
+ /* Assume a CORE_ADDR can fit in a LONGEST (for now). Not sure
+ whether we want this to be true eventually. */
+#if 0
+ /* ADDR_BITS_REMOVE is wrong if we are being called for a
+ non-address (e.g. argument to "signal", "info break", etc.), or
+ for pointers to char, in which the low bits *are* significant. */
+ return ADDR_BITS_REMOVE(value_as_long (val));
+#else
+ return value_as_long (val);
+#endif
+}
+
+/* Unpack raw data (copied from debugee, target byte order) at VALADDR
+ as a long, or as a double, assuming the raw data is described
+ by type TYPE. Knows how to convert different sizes of values
+ and can convert between fixed and floating point. We don't assume
+ any alignment for the raw data. Return value is in host byte order.
+
+ If you want functions and arrays to be coerced to pointers, and
+ references to be dereferenced, call value_as_long() instead.
+
+ C++: It is assumed that the front-end has taken care of
+ all matters concerning pointers to members. A pointer
+ to member which reaches here is considered to be equivalent
+ to an INT (or some size). After all, it is only an offset. */
+
+LONGEST
+unpack_long (type, valaddr)
+ struct type *type;
+ char *valaddr;
+{
+ register enum type_code code = TYPE_CODE (type);
+ register int len = TYPE_LENGTH (type);
+ register int nosign = TYPE_UNSIGNED (type);
+
+ switch (code)
+ {
+ case TYPE_CODE_ENUM:
+ case TYPE_CODE_BOOL:
+ case TYPE_CODE_INT:
+ case TYPE_CODE_CHAR:
+ case TYPE_CODE_RANGE:
+ if (nosign)
+ return extract_unsigned_integer (valaddr, len);
+ else
+ return extract_signed_integer (valaddr, len);
+
+ case TYPE_CODE_FLT:
+ return extract_floating (valaddr, len);
+
+ case TYPE_CODE_PTR:
+ case TYPE_CODE_REF:
+ /* Assume a CORE_ADDR can fit in a LONGEST (for now). Not sure
+ whether we want this to be true eventually. */
+ return extract_address (valaddr, len);
+
+ case TYPE_CODE_MEMBER:
+ error ("not implemented: member types in unpack_long");
+
+ default:
+ error ("Value can't be converted to integer.");
+ }
+ return 0; /* Placate lint. */
+}
+
+/* Return a double value from the specified type and address.
+ INVP points to an int which is set to 0 for valid value,
+ 1 for invalid value (bad float format). In either case,
+ the returned double is OK to use. Argument is in target
+ format, result is in host format. */
+
+double
+unpack_double (type, valaddr, invp)
+ struct type *type;
+ char *valaddr;
+ int *invp;
+{
+ register enum type_code code = TYPE_CODE (type);
+ register int len = TYPE_LENGTH (type);
+ register int nosign = TYPE_UNSIGNED (type);
+
+ *invp = 0; /* Assume valid. */
+ if (code == TYPE_CODE_FLT)
+ {
+ if (INVALID_FLOAT (valaddr, len))
+ {
+ *invp = 1;
+ return 1.234567891011121314;
+ }
+ return extract_floating (valaddr, len);
+ }
+ else if (nosign)
+ {
+ /* Unsigned -- be sure we compensate for signed LONGEST. */
+ return (unsigned LONGEST) unpack_long (type, valaddr);
+ }
+ else
+ {
+ /* Signed -- we are OK with unpack_long. */
+ return unpack_long (type, valaddr);
+ }
+}
+
+/* Unpack raw data (copied from debugee, target byte order) at VALADDR
+ as a CORE_ADDR, assuming the raw data is described by type TYPE.
+ We don't assume any alignment for the raw data. Return value is in
+ host byte order.
+
+ If you want functions and arrays to be coerced to pointers, and
+ references to be dereferenced, call value_as_pointer() instead.
+
+ C++: It is assumed that the front-end has taken care of
+ all matters concerning pointers to members. A pointer
+ to member which reaches here is considered to be equivalent
+ to an INT (or some size). After all, it is only an offset. */
+
+CORE_ADDR
+unpack_pointer (type, valaddr)
+ struct type *type;
+ char *valaddr;
+{
+ /* Assume a CORE_ADDR can fit in a LONGEST (for now). Not sure
+ whether we want this to be true eventually. */
+ return unpack_long (type, valaddr);
+}
+
+/* Given a value ARG1 (offset by OFFSET bytes)
+ of a struct or union type ARG_TYPE,
+ extract and return the value of one of its fields.
+ FIELDNO says which field.
+
+ For C++, must also be able to return values from static fields */
+
+value_ptr
+value_primitive_field (arg1, offset, fieldno, arg_type)
+ register value_ptr arg1;
+ int offset;
+ register int fieldno;
+ register struct type *arg_type;
+{
+ register value_ptr v;
+ register struct type *type;
+
+ check_stub_type (arg_type);
+ type = TYPE_FIELD_TYPE (arg_type, fieldno);
+
+ /* Handle packed fields */
+
+ offset += TYPE_FIELD_BITPOS (arg_type, fieldno) / 8;
+ if (TYPE_FIELD_BITSIZE (arg_type, fieldno))
+ {
+ v = value_from_longest (type,
+ unpack_field_as_long (arg_type,
+ VALUE_CONTENTS (arg1),
+ fieldno));
+ VALUE_BITPOS (v) = TYPE_FIELD_BITPOS (arg_type, fieldno) % 8;
+ VALUE_BITSIZE (v) = TYPE_FIELD_BITSIZE (arg_type, fieldno);
+ }
+ else
+ {
+ v = allocate_value (type);
+ if (VALUE_LAZY (arg1))
+ VALUE_LAZY (v) = 1;
+ else
+ memcpy (VALUE_CONTENTS_RAW (v), VALUE_CONTENTS_RAW (arg1) + offset,
+ TYPE_LENGTH (type));
+ }
+ VALUE_LVAL (v) = VALUE_LVAL (arg1);
+ if (VALUE_LVAL (arg1) == lval_internalvar)
+ VALUE_LVAL (v) = lval_internalvar_component;
+ VALUE_ADDRESS (v) = VALUE_ADDRESS (arg1);
+ VALUE_OFFSET (v) = offset + VALUE_OFFSET (arg1);
+ return v;
+}
+
+/* Given a value ARG1 of a struct or union type,
+ extract and return the value of one of its fields.
+ FIELDNO says which field.
+
+ For C++, must also be able to return values from static fields */
+
+value_ptr
+value_field (arg1, fieldno)
+ register value_ptr arg1;
+ register int fieldno;
+{
+ return value_primitive_field (arg1, 0, fieldno, VALUE_TYPE (arg1));
+}
+
+/* Return a non-virtual function as a value.
+ F is the list of member functions which contains the desired method.
+ J is an index into F which provides the desired method. */
+
+value_ptr
+value_fn_field (arg1p, f, j, type, offset)
+ value_ptr *arg1p;
+ struct fn_field *f;
+ int j;
+ struct type *type;
+ int offset;
+{
+ register value_ptr v;
+ register struct type *ftype = TYPE_FN_FIELD_TYPE (f, j);
+ struct symbol *sym;
+
+ sym = lookup_symbol (TYPE_FN_FIELD_PHYSNAME (f, j),
+ 0, VAR_NAMESPACE, 0, NULL);
+ if (! sym)
+ return NULL;
+/*
+ error ("Internal error: could not find physical method named %s",
+ TYPE_FN_FIELD_PHYSNAME (f, j));
+*/
+
+ v = allocate_value (ftype);
+ VALUE_ADDRESS (v) = BLOCK_START (SYMBOL_BLOCK_VALUE (sym));
+ VALUE_TYPE (v) = ftype;
+
+ if (arg1p)
+ {
+ if (type != VALUE_TYPE (*arg1p))
+ *arg1p = value_ind (value_cast (lookup_pointer_type (type),
+ value_addr (*arg1p)));
+
+ /* Move the `this' pointer according to the offset.
+ VALUE_OFFSET (*arg1p) += offset;
+ */
+ }
+
+ return v;
+}
+
+/* Return a virtual function as a value.
+ ARG1 is the object which provides the virtual function
+ table pointer. *ARG1P is side-effected in calling this function.
+ F is the list of member functions which contains the desired virtual
+ function.
+ J is an index into F which provides the desired virtual function.
+
+ TYPE is the type in which F is located. */
+value_ptr
+value_virtual_fn_field (arg1p, f, j, type, offset)
+ value_ptr *arg1p;
+ struct fn_field *f;
+ int j;
+ struct type *type;
+ int offset;
+{
+ value_ptr arg1 = *arg1p;
+ /* First, get the virtual function table pointer. That comes
+ with a strange type, so cast it to type `pointer to long' (which
+ should serve just fine as a function type). Then, index into
+ the table, and convert final value to appropriate function type. */
+ value_ptr entry, vfn, vtbl;
+ value_ptr vi = value_from_longest (builtin_type_int,
+ (LONGEST) TYPE_FN_FIELD_VOFFSET (f, j));
+ struct type *fcontext = TYPE_FN_FIELD_FCONTEXT (f, j);
+ struct type *context;
+ if (fcontext == NULL)
+ /* We don't have an fcontext (e.g. the program was compiled with
+ g++ version 1). Try to get the vtbl from the TYPE_VPTR_BASETYPE.
+ This won't work right for multiple inheritance, but at least we
+ should do as well as GDB 3.x did. */
+ fcontext = TYPE_VPTR_BASETYPE (type);
+ context = lookup_pointer_type (fcontext);
+ /* Now context is a pointer to the basetype containing the vtbl. */
+ if (TYPE_TARGET_TYPE (context) != VALUE_TYPE (arg1))
+ arg1 = value_ind (value_cast (context, value_addr (arg1)));
+
+ context = VALUE_TYPE (arg1);
+ /* Now context is the basetype containing the vtbl. */
+
+ /* This type may have been defined before its virtual function table
+ was. If so, fill in the virtual function table entry for the
+ type now. */
+ if (TYPE_VPTR_FIELDNO (context) < 0)
+ fill_in_vptr_fieldno (context);
+
+ /* The virtual function table is now an array of structures
+ which have the form { int16 offset, delta; void *pfn; }. */
+ vtbl = value_ind (value_primitive_field (arg1, 0,
+ TYPE_VPTR_FIELDNO (context),
+ TYPE_VPTR_BASETYPE (context)));
+
+ /* Index into the virtual function table. This is hard-coded because
+ looking up a field is not cheap, and it may be important to save
+ time, e.g. if the user has set a conditional breakpoint calling
+ a virtual function. */
+ entry = value_subscript (vtbl, vi);
+
+ if (TYPE_CODE (VALUE_TYPE (entry)) == TYPE_CODE_STRUCT)
+ {
+ /* Move the `this' pointer according to the virtual function table. */
+ VALUE_OFFSET (arg1) += value_as_long (value_field (entry, 0));
+
+ if (! VALUE_LAZY (arg1))
+ {
+ VALUE_LAZY (arg1) = 1;
+ value_fetch_lazy (arg1);
+ }
+
+ vfn = value_field (entry, 2);
+ }
+ else if (TYPE_CODE (VALUE_TYPE (entry)) == TYPE_CODE_PTR)
+ vfn = entry;
+ else
+ error ("I'm confused: virtual function table has bad type");
+ /* Reinstantiate the function pointer with the correct type. */
+ VALUE_TYPE (vfn) = lookup_pointer_type (TYPE_FN_FIELD_TYPE (f, j));
+
+ *arg1p = arg1;
+ return vfn;
+}
+
+/* ARG is a pointer to an object we know to be at least
+ a DTYPE. BTYPE is the most derived basetype that has
+ already been searched (and need not be searched again).
+ After looking at the vtables between BTYPE and DTYPE,
+ return the most derived type we find. The caller must
+ be satisfied when the return value == DTYPE.
+
+ FIXME-tiemann: should work with dossier entries as well. */
+
+static value_ptr
+value_headof (in_arg, btype, dtype)
+ value_ptr in_arg;
+ struct type *btype, *dtype;
+{
+ /* First collect the vtables we must look at for this object. */
+ /* FIXME-tiemann: right now, just look at top-most vtable. */
+ value_ptr arg, vtbl, entry, best_entry = 0;
+ int i, nelems;
+ int offset, best_offset = 0;
+ struct symbol *sym;
+ CORE_ADDR pc_for_sym;
+ char *demangled_name;
+ struct minimal_symbol *msymbol;
+
+ btype = TYPE_VPTR_BASETYPE (dtype);
+ check_stub_type (btype);
+ arg = in_arg;
+ if (btype != dtype)
+ arg = value_cast (lookup_pointer_type (btype), arg);
+ vtbl = value_ind (value_field (value_ind (arg), TYPE_VPTR_FIELDNO (btype)));
+
+ /* Check that VTBL looks like it points to a virtual function table. */
+ msymbol = lookup_minimal_symbol_by_pc (VALUE_ADDRESS (vtbl));
+ if (msymbol == NULL
+ || (demangled_name = SYMBOL_NAME (msymbol)) == NULL
+ || !VTBL_PREFIX_P (demangled_name))
+ {
+ /* If we expected to find a vtable, but did not, let the user
+ know that we aren't happy, but don't throw an error.
+ FIXME: there has to be a better way to do this. */
+ struct type *error_type = (struct type *)xmalloc (sizeof (struct type));
+ memcpy (error_type, VALUE_TYPE (in_arg), sizeof (struct type));
+ TYPE_NAME (error_type) = savestring ("suspicious *", sizeof ("suspicious *"));
+ VALUE_TYPE (in_arg) = error_type;
+ return in_arg;
+ }
+
+ /* Now search through the virtual function table. */
+ entry = value_ind (vtbl);
+ nelems = longest_to_int (value_as_long (value_field (entry, 2)));
+ for (i = 1; i <= nelems; i++)
+ {
+ entry = value_subscript (vtbl, value_from_longest (builtin_type_int,
+ (LONGEST) i));
+ /* This won't work if we're using thunks. */
+ if (TYPE_CODE (VALUE_TYPE (entry)) != TYPE_CODE_STRUCT)
+ break;
+ offset = longest_to_int (value_as_long (value_field (entry, 0)));
+ /* If we use '<=' we can handle single inheritance
+ * where all offsets are zero - just use the first entry found. */
+ if (offset <= best_offset)
+ {
+ best_offset = offset;
+ best_entry = entry;
+ }
+ }
+ /* Move the pointer according to BEST_ENTRY's offset, and figure
+ out what type we should return as the new pointer. */
+ if (best_entry == 0)
+ {
+ /* An alternative method (which should no longer be necessary).
+ * But we leave it in for future use, when we will hopefully
+ * have optimizes the vtable to use thunks instead of offsets. */
+ /* Use the name of vtable itself to extract a base type. */
+ demangled_name += 4; /* Skip _vt$ prefix. */
+ }
+ else
+ {
+ pc_for_sym = value_as_pointer (value_field (best_entry, 2));
+ sym = find_pc_function (pc_for_sym);
+ demangled_name = cplus_demangle (SYMBOL_NAME (sym), DMGL_ANSI);
+ *(strchr (demangled_name, ':')) = '\0';
+ }
+ sym = lookup_symbol (demangled_name, 0, VAR_NAMESPACE, 0, 0);
+ if (sym == NULL)
+ error ("could not find type declaration for `%s'", demangled_name);
+ if (best_entry)
+ {
+ free (demangled_name);
+ arg = value_add (value_cast (builtin_type_int, arg),
+ value_field (best_entry, 0));
+ }
+ else arg = in_arg;
+ VALUE_TYPE (arg) = lookup_pointer_type (SYMBOL_TYPE (sym));
+ return arg;
+}
+
+/* ARG is a pointer object of type TYPE. If TYPE has virtual
+ function tables, probe ARG's tables (including the vtables
+ of its baseclasses) to figure out the most derived type that ARG
+ could actually be a pointer to. */
+
+value_ptr
+value_from_vtable_info (arg, type)
+ value_ptr arg;
+ struct type *type;
+{
+ /* Take care of preliminaries. */
+ if (TYPE_VPTR_FIELDNO (type) < 0)
+ fill_in_vptr_fieldno (type);
+ if (TYPE_VPTR_FIELDNO (type) < 0 || VALUE_REPEATED (arg))
+ return 0;
+
+ return value_headof (arg, 0, type);
+}
+
+/* Return true if the INDEXth field of TYPE is a virtual baseclass
+ pointer which is for the base class whose type is BASECLASS. */
+
+static int
+vb_match (type, index, basetype)
+ struct type *type;
+ int index;
+ struct type *basetype;
+{
+ struct type *fieldtype;
+ char *name = TYPE_FIELD_NAME (type, index);
+ char *field_class_name = NULL;
+
+ if (*name != '_')
+ return 0;
+ /* gcc 2.4 uses _vb$. */
+ if (name[1] == 'v' && name[2] == 'b' && name[3] == CPLUS_MARKER)
+ field_class_name = name + 4;
+ /* gcc 2.5 will use __vb_. */
+ if (name[1] == '_' && name[2] == 'v' && name[3] == 'b' && name[4] == '_')
+ field_class_name = name + 5;
+
+ if (field_class_name == NULL)
+ /* This field is not a virtual base class pointer. */
+ return 0;
+
+ /* It's a virtual baseclass pointer, now we just need to find out whether
+ it is for this baseclass. */
+ fieldtype = TYPE_FIELD_TYPE (type, index);
+ if (fieldtype == NULL
+ || TYPE_CODE (fieldtype) != TYPE_CODE_PTR)
+ /* "Can't happen". */
+ return 0;
+
+ /* What we check for is that either the types are equal (needed for
+ nameless types) or have the same name. This is ugly, and a more
+ elegant solution should be devised (which would probably just push
+ the ugliness into symbol reading unless we change the stabs format). */
+ if (TYPE_TARGET_TYPE (fieldtype) == basetype)
+ return 1;
+
+ if (TYPE_NAME (basetype) != NULL
+ && TYPE_NAME (TYPE_TARGET_TYPE (fieldtype)) != NULL
+ && STREQ (TYPE_NAME (basetype),
+ TYPE_NAME (TYPE_TARGET_TYPE (fieldtype))))
+ return 1;
+ return 0;
+}
+
+/* Compute the offset of the baseclass which is
+ the INDEXth baseclass of class TYPE, for a value ARG,
+ wih extra offset of OFFSET.
+ The result is the offste of the baseclass value relative
+ to (the address of)(ARG) + OFFSET.
+
+ -1 is returned on error. */
+
+int
+baseclass_offset (type, index, arg, offset)
+ struct type *type;
+ int index;
+ value_ptr arg;
+ int offset;
+{
+ struct type *basetype = TYPE_BASECLASS (type, index);
+
+ if (BASETYPE_VIA_VIRTUAL (type, index))
+ {
+ /* Must hunt for the pointer to this virtual baseclass. */
+ register int i, len = TYPE_NFIELDS (type);
+ register int n_baseclasses = TYPE_N_BASECLASSES (type);
+
+ /* First look for the virtual baseclass pointer
+ in the fields. */
+ for (i = n_baseclasses; i < len; i++)
+ {
+ if (vb_match (type, i, basetype))
+ {
+ CORE_ADDR addr
+ = unpack_pointer (TYPE_FIELD_TYPE (type, i),
+ VALUE_CONTENTS (arg) + VALUE_OFFSET (arg)
+ + offset
+ + (TYPE_FIELD_BITPOS (type, i) / 8));
+
+ if (VALUE_LVAL (arg) != lval_memory)
+ return -1;
+
+ return addr -
+ (LONGEST) (VALUE_ADDRESS (arg) + VALUE_OFFSET (arg) + offset);
+ }
+ }
+ /* Not in the fields, so try looking through the baseclasses. */
+ for (i = index+1; i < n_baseclasses; i++)
+ {
+ int boffset =
+ baseclass_offset (type, i, arg, offset);
+ if (boffset)
+ return boffset;
+ }
+ /* Not found. */
+ return -1;
+ }
+
+ /* Baseclass is easily computed. */
+ return TYPE_BASECLASS_BITPOS (type, index) / 8;
+}
+
+/* Compute the address of the baseclass which is
+ the INDEXth baseclass of class TYPE. The TYPE base
+ of the object is at VALADDR.
+
+ If ERRP is non-NULL, set *ERRP to be the errno code of any error,
+ or 0 if no error. In that case the return value is not the address
+ of the baseclasss, but the address which could not be read
+ successfully. */
+
+/* FIXME Fix remaining uses of baseclass_addr to use baseclass_offset */
+
+char *
+baseclass_addr (type, index, valaddr, valuep, errp)
+ struct type *type;
+ int index;
+ char *valaddr;
+ value_ptr *valuep;
+ int *errp;
+{
+ struct type *basetype = TYPE_BASECLASS (type, index);
+
+ if (errp)
+ *errp = 0;
+
+ if (BASETYPE_VIA_VIRTUAL (type, index))
+ {
+ /* Must hunt for the pointer to this virtual baseclass. */
+ register int i, len = TYPE_NFIELDS (type);
+ register int n_baseclasses = TYPE_N_BASECLASSES (type);
+
+ /* First look for the virtual baseclass pointer
+ in the fields. */
+ for (i = n_baseclasses; i < len; i++)
+ {
+ if (vb_match (type, i, basetype))
+ {
+ value_ptr val = allocate_value (basetype);
+ CORE_ADDR addr;
+ int status;
+
+ addr
+ = unpack_pointer (TYPE_FIELD_TYPE (type, i),
+ valaddr + (TYPE_FIELD_BITPOS (type, i) / 8));
+
+ status = target_read_memory (addr,
+ VALUE_CONTENTS_RAW (val),
+ TYPE_LENGTH (basetype));
+ VALUE_LVAL (val) = lval_memory;
+ VALUE_ADDRESS (val) = addr;
+
+ if (status != 0)
+ {
+ if (valuep)
+ *valuep = NULL;
+ release_value (val);
+ value_free (val);
+ if (errp)
+ *errp = status;
+ return (char *)addr;
+ }
+ else
+ {
+ if (valuep)
+ *valuep = val;
+ return (char *) VALUE_CONTENTS (val);
+ }
+ }
+ }
+ /* Not in the fields, so try looking through the baseclasses. */
+ for (i = index+1; i < n_baseclasses; i++)
+ {
+ char *baddr;
+
+ baddr = baseclass_addr (type, i, valaddr, valuep, errp);
+ if (baddr)
+ return baddr;
+ }
+ /* Not found. */
+ if (valuep)
+ *valuep = 0;
+ return 0;
+ }
+
+ /* Baseclass is easily computed. */
+ if (valuep)
+ *valuep = 0;
+ return valaddr + TYPE_BASECLASS_BITPOS (type, index) / 8;
+}
+
+/* Unpack a field FIELDNO of the specified TYPE, from the anonymous object at
+ VALADDR.
+
+ Extracting bits depends on endianness of the machine. Compute the
+ number of least significant bits to discard. For big endian machines,
+ we compute the total number of bits in the anonymous object, subtract
+ off the bit count from the MSB of the object to the MSB of the
+ bitfield, then the size of the bitfield, which leaves the LSB discard
+ count. For little endian machines, the discard count is simply the
+ number of bits from the LSB of the anonymous object to the LSB of the
+ bitfield.
+
+ If the field is signed, we also do sign extension. */
+
+LONGEST
+unpack_field_as_long (type, valaddr, fieldno)
+ struct type *type;
+ char *valaddr;
+ int fieldno;
+{
+ unsigned LONGEST val;
+ unsigned LONGEST valmask;
+ int bitpos = TYPE_FIELD_BITPOS (type, fieldno);
+ int bitsize = TYPE_FIELD_BITSIZE (type, fieldno);
+ int lsbcount;
+
+ val = extract_unsigned_integer (valaddr + bitpos / 8, sizeof (val));
+
+ /* Extract bits. See comment above. */
+
+#if BITS_BIG_ENDIAN
+ lsbcount = (sizeof val * 8 - bitpos % 8 - bitsize);
+#else
+ lsbcount = (bitpos % 8);
+#endif
+ val >>= lsbcount;
+
+ /* If the field does not entirely fill a LONGEST, then zero the sign bits.
+ If the field is signed, and is negative, then sign extend. */
+
+ if ((bitsize > 0) && (bitsize < 8 * sizeof (val)))
+ {
+ valmask = (((unsigned LONGEST) 1) << bitsize) - 1;
+ val &= valmask;
+ if (!TYPE_UNSIGNED (TYPE_FIELD_TYPE (type, fieldno)))
+ {
+ if (val & (valmask ^ (valmask >> 1)))
+ {
+ val |= ~valmask;
+ }
+ }
+ }
+ return (val);
+}
+
+/* Modify the value of a bitfield. ADDR points to a block of memory in
+ target byte order; the bitfield starts in the byte pointed to. FIELDVAL
+ is the desired value of the field, in host byte order. BITPOS and BITSIZE
+ indicate which bits (in target bit order) comprise the bitfield. */
+
+void
+modify_field (addr, fieldval, bitpos, bitsize)
+ char *addr;
+ LONGEST fieldval;
+ int bitpos, bitsize;
+{
+ LONGEST oword;
+
+ /* Reject values too big to fit in the field in question,
+ otherwise adjoining fields may be corrupted. */
+ if (bitsize < (8 * sizeof (fieldval))
+ && 0 != (fieldval & ~((1<<bitsize)-1)))
+ {
+ /* FIXME: would like to include fieldval in the message, but
+ we don't have a sprintf_longest. */
+ error ("Value does not fit in %d bits.", bitsize);
+ }
+
+ oword = extract_signed_integer (addr, sizeof oword);
+
+ /* Shifting for bit field depends on endianness of the target machine. */
+#if BITS_BIG_ENDIAN
+ bitpos = sizeof (oword) * 8 - bitpos - bitsize;
+#endif
+
+ /* Mask out old value, while avoiding shifts >= size of oword */
+ if (bitsize < 8 * sizeof (oword))
+ oword &= ~(((((unsigned LONGEST)1) << bitsize) - 1) << bitpos);
+ else
+ oword &= ~((~(unsigned LONGEST)0) << bitpos);
+ oword |= fieldval << bitpos;
+
+ store_signed_integer (addr, sizeof oword, oword);
+}
+
+/* Convert C numbers into newly allocated values */
+
+value_ptr
+value_from_longest (type, num)
+ struct type *type;
+ register LONGEST num;
+{
+ register value_ptr val = allocate_value (type);
+ register enum type_code code = TYPE_CODE (type);
+ register int len = TYPE_LENGTH (type);
+
+ switch (code)
+ {
+ case TYPE_CODE_INT:
+ case TYPE_CODE_CHAR:
+ case TYPE_CODE_ENUM:
+ case TYPE_CODE_BOOL:
+ case TYPE_CODE_RANGE:
+ store_signed_integer (VALUE_CONTENTS_RAW (val), len, num);
+ break;
+
+ case TYPE_CODE_REF:
+ case TYPE_CODE_PTR:
+ /* This assumes that all pointers of a given length
+ have the same form. */
+ store_address (VALUE_CONTENTS_RAW (val), len, (CORE_ADDR) num);
+ break;
+
+ default:
+ error ("Unexpected type encountered for integer constant.");
+ }
+ return val;
+}
+
+value_ptr
+value_from_double (type, num)
+ struct type *type;
+ double num;
+{
+ register value_ptr val = allocate_value (type);
+ register enum type_code code = TYPE_CODE (type);
+ register int len = TYPE_LENGTH (type);
+
+ if (code == TYPE_CODE_FLT)
+ {
+ store_floating (VALUE_CONTENTS_RAW (val), len, num);
+ }
+ else
+ error ("Unexpected type encountered for floating constant.");
+
+ return val;
+}
+
+/* Deal with the value that is "about to be returned". */
+
+/* Return the value that a function returning now
+ would be returning to its caller, assuming its type is VALTYPE.
+ RETBUF is where we look for what ought to be the contents
+ of the registers (in raw form). This is because it is often
+ desirable to restore old values to those registers
+ after saving the contents of interest, and then call
+ this function using the saved values.
+ struct_return is non-zero when the function in question is
+ using the structure return conventions on the machine in question;
+ 0 when it is using the value returning conventions (this often
+ means returning pointer to where structure is vs. returning value). */
+
+value_ptr
+value_being_returned (valtype, retbuf, struct_return)
+ register struct type *valtype;
+ char retbuf[REGISTER_BYTES];
+ int struct_return;
+ /*ARGSUSED*/
+{
+ register value_ptr val;
+ CORE_ADDR addr;
+
+#if defined (EXTRACT_STRUCT_VALUE_ADDRESS)
+ /* If this is not defined, just use EXTRACT_RETURN_VALUE instead. */
+ if (struct_return) {
+ addr = EXTRACT_STRUCT_VALUE_ADDRESS (retbuf);
+ if (!addr)
+ error ("Function return value unknown");
+ return value_at (valtype, addr);
+ }
+#endif
+
+ val = allocate_value (valtype);
+ EXTRACT_RETURN_VALUE (valtype, retbuf, VALUE_CONTENTS_RAW (val));
+
+ return val;
+}
+
+/* Should we use EXTRACT_STRUCT_VALUE_ADDRESS instead of
+ EXTRACT_RETURN_VALUE? GCC_P is true if compiled with gcc
+ and TYPE is the type (which is known to be struct, union or array).
+
+ On most machines, the struct convention is used unless we are
+ using gcc and the type is of a special size. */
+/* As of about 31 Mar 93, GCC was changed to be compatible with the
+ native compiler. GCC 2.3.3 was the last release that did it the
+ old way. Since gcc2_compiled was not changed, we have no
+ way to correctly win in all cases, so we just do the right thing
+ for gcc1 and for gcc2 after this change. Thus it loses for gcc
+ 2.0-2.3.3. This is somewhat unfortunate, but changing gcc2_compiled
+ would cause more chaos than dealing with some struct returns being
+ handled wrong. */
+#if !defined (USE_STRUCT_CONVENTION)
+#define USE_STRUCT_CONVENTION(gcc_p, type)\
+ (!((gcc_p == 1) && (TYPE_LENGTH (value_type) == 1 \
+ || TYPE_LENGTH (value_type) == 2 \
+ || TYPE_LENGTH (value_type) == 4 \
+ || TYPE_LENGTH (value_type) == 8 \
+ ) \
+ ))
+#endif
+
+/* Return true if the function specified is using the structure returning
+ convention on this machine to return arguments, or 0 if it is using
+ the value returning convention. FUNCTION is the value representing
+ the function, FUNCADDR is the address of the function, and VALUE_TYPE
+ is the type returned by the function. GCC_P is nonzero if compiled
+ with GCC. */
+
+int
+using_struct_return (function, funcaddr, value_type, gcc_p)
+ value_ptr function;
+ CORE_ADDR funcaddr;
+ struct type *value_type;
+ int gcc_p;
+ /*ARGSUSED*/
+{
+ register enum type_code code = TYPE_CODE (value_type);
+
+ if (code == TYPE_CODE_ERROR)
+ error ("Function return type unknown.");
+
+ if (code == TYPE_CODE_STRUCT ||
+ code == TYPE_CODE_UNION ||
+ code == TYPE_CODE_ARRAY)
+ return USE_STRUCT_CONVENTION (gcc_p, value_type);
+
+ return 0;
+}
+
+/* Store VAL so it will be returned if a function returns now.
+ Does not verify that VAL's type matches what the current
+ function wants to return. */
+
+void
+set_return_value (val)
+ value_ptr val;
+{
+ register enum type_code code = TYPE_CODE (VALUE_TYPE (val));
+ double dbuf;
+ LONGEST lbuf;
+
+ if (code == TYPE_CODE_ERROR)
+ error ("Function return type unknown.");
+
+ if ( code == TYPE_CODE_STRUCT
+ || code == TYPE_CODE_UNION) /* FIXME, implement struct return. */
+ error ("GDB does not support specifying a struct or union return value.");
+
+ /* FIXME, this is bogus. We don't know what the return conventions
+ are, or how values should be promoted.... */
+ if (code == TYPE_CODE_FLT)
+ {
+ dbuf = value_as_double (val);
+
+ STORE_RETURN_VALUE (VALUE_TYPE (val), (char *)&dbuf);
+ }
+ else
+ {
+ lbuf = value_as_long (val);
+ STORE_RETURN_VALUE (VALUE_TYPE (val), (char *)&lbuf);
+ }
+}
+
+void
+_initialize_values ()
+{
+ add_cmd ("convenience", no_class, show_convenience,
+ "Debugger convenience (\"$foo\") variables.\n\
+These variables are created when you assign them values;\n\
+thus, \"print $foo=1\" gives \"$foo\" the value 1. Values may be any type.\n\n\
+A few convenience variables are given values automatically:\n\
+\"$_\"holds the last address examined with \"x\" or \"info lines\",\n\
+\"$__\" holds the contents of the last address examined with \"x\".",
+ &showlist);
+
+ add_cmd ("values", no_class, show_values,
+ "Elements of value history around item number IDX (or last ten).",
+ &showlist);
+}
diff --git a/gnu/usr.bin/gdb/gdb/version.c b/gnu/usr.bin/gdb/gdb/version.c
new file mode 100644
index 0000000..43f63d2
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/version.c
@@ -0,0 +1,3 @@
+char *version = "4.13";
+char *host_name = "i386-unknown-freebsd";
+char *target_name = "i386-unknown-freebsd";
diff --git a/gnu/usr.bin/gdb/gdb/wait.h b/gnu/usr.bin/gdb/gdb/wait.h
new file mode 100644
index 0000000..10a5eb0
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/wait.h
@@ -0,0 +1,38 @@
+/* Define how to access the int that the wait system call stores.
+ This has been compatible in all Unix systems since time immemorial,
+ but various well-meaning people have defined various different
+ words for the same old bits in the same old int (sometimes claimed
+ to be a struct). We just know it's an int and we use these macros
+ to access the bits. */
+
+/* The following macros are defined equivalently to their definitions
+ in POSIX.1. We fail to define WNOHANG and WUNTRACED, which POSIX.1
+ <sys/wait.h> defines, since our code does not use waitpid(). We
+ also fail to declare wait() and waitpid(). */
+
+#define WIFEXITED(w) (((w)&0377) == 0)
+#define WIFSIGNALED(w) (((w)&0377) != 0177 && ((w)&~0377) == 0)
+#ifdef IBM6000
+
+/* Unfortunately, the above comment (about being compatible in all Unix
+ systems) is not quite correct for AIX, sigh. And AIX 3.2 can generate
+ status words like 0x57c (sigtrap received after load), and gdb would
+ choke on it. */
+
+#define WIFSTOPPED(w) ((w)&0x40)
+
+#else
+#define WIFSTOPPED(w) (((w)&0377) == 0177)
+#endif
+
+#define WEXITSTATUS(w) (((w) >> 8) & 0377) /* same as WRETCODE */
+#define WTERMSIG(w) ((w) & 0177)
+#define WSTOPSIG WEXITSTATUS
+
+/* These are not defined in POSIX, but are used by our programs. */
+
+#define WAITTYPE int
+
+#define WCOREDUMP(w) (((w)&0200) != 0)
+#define WSETEXIT(w,status) ((w) = (0 | ((status) << 8)))
+#define WSETSTOP(w,sig) ((w) = (0177 | ((sig) << 8)))
diff --git a/gnu/usr.bin/gdb/gdb/xm.h b/gnu/usr.bin/gdb/gdb/xm.h
new file mode 100644
index 0000000..6a71227
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/xm.h
@@ -0,0 +1,29 @@
+/* Host-dependent definitions for Intel 386 running BSD Unix, for GDB.
+ Copyright 1986, 1987, 1989, 1992 Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#define HOST_BYTE_ORDER LITTLE_ENDIAN
+
+#include <machine/limits.h> /* for INT_MIN, to avoid "INT_MIN
+ redefined" warnings from defs.h */
+
+/* psignal() is in <signal.h>. */
+
+#define PSIGNAL_IN_SIGNAL_H
+
+#define HAVE_TERMIOS
diff --git a/gnu/usr.bin/gdb/libiberty/COPYING.LIB b/gnu/usr.bin/gdb/libiberty/COPYING.LIB
new file mode 100644
index 0000000..eb685a5
--- /dev/null
+++ b/gnu/usr.bin/gdb/libiberty/COPYING.LIB
@@ -0,0 +1,481 @@
+ GNU LIBRARY GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1991 Free Software Foundation, Inc.
+ 675 Mass Ave, Cambridge, MA 02139, USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the library GPL. It is
+ numbered 2 because it goes with version 2 of the ordinary GPL.]
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+ This license, the Library General Public License, applies to some
+specially designated Free Software Foundation software, and to any
+other libraries whose authors decide to use it. You can use it for
+your libraries, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if
+you distribute copies of the library, or if you modify it.
+
+ For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you. You must make sure that they, too, receive or can get the source
+code. If you link a program with the library, you must provide
+complete object files to the recipients so that they can relink them
+with the library, after making changes to the library and recompiling
+it. And you must show them these terms so they know their rights.
+
+ Our method of protecting your rights has two steps: (1) copyright
+the library, and (2) offer you this license which gives you legal
+permission to copy, distribute and/or modify the library.
+
+ Also, for each distributor's protection, we want to make certain
+that everyone understands that there is no warranty for this free
+library. If the library is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original
+version, so that any problems introduced by others will not reflect on
+the original authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that companies distributing free
+software will individually obtain patent licenses, thus in effect
+transforming the program into proprietary software. To prevent this,
+we have made it clear that any patent must be licensed for everyone's
+free use or not licensed at all.
+
+ Most GNU software, including some libraries, is covered by the ordinary
+GNU General Public License, which was designed for utility programs. This
+license, the GNU Library General Public License, applies to certain
+designated libraries. This license is quite different from the ordinary
+one; be sure to read it in full, and don't assume that anything in it is
+the same as in the ordinary license.
+
+ The reason we have a separate public license for some libraries is that
+they blur the distinction we usually make between modifying or adding to a
+program and simply using it. Linking a program with a library, without
+changing the library, is in some sense simply using the library, and is
+analogous to running a utility program or application program. However, in
+a textual and legal sense, the linked executable is a combined work, a
+derivative of the original library, and the ordinary General Public License
+treats it as such.
+
+ Because of this blurred distinction, using the ordinary General
+Public License for libraries did not effectively promote software
+sharing, because most developers did not use the libraries. We
+concluded that weaker conditions might promote sharing better.
+
+ However, unrestricted linking of non-free programs would deprive the
+users of those programs of all benefit from the free status of the
+libraries themselves. This Library General Public License is intended to
+permit developers of non-free programs to use free libraries, while
+preserving your freedom as a user of such programs to change the free
+libraries that are incorporated in them. (We have not seen how to achieve
+this as regards changes in header files, but we have achieved it as regards
+changes in the actual functions of the Library.) The hope is that this
+will lead to faster development of free libraries.
+
+ The precise terms and conditions for copying, distribution and
+modification follow. Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library". The
+former contains code derived from the library, while the latter only
+works together with the library.
+
+ Note that it is possible for a library to be covered by the ordinary
+General Public License rather than by this special one.
+
+ GNU LIBRARY GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License Agreement applies to any software library which
+contains a notice placed by the copyright holder or other authorized
+party saying it may be distributed under the terms of this Library
+General Public License (also called "this License"). Each licensee is
+addressed as "you".
+
+ A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+ The "Library", below, refers to any such software library or work
+which has been distributed under these terms. A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language. (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+ "Source code" for a work means the preferred form of the work for
+making modifications to it. For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+ Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it). Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+
+ 1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+ You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+
+ 2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) The modified work must itself be a software library.
+
+ b) You must cause the files modified to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ c) You must cause the whole of the work to be licensed at no
+ charge to all third parties under the terms of this License.
+
+ d) If a facility in the modified Library refers to a function or a
+ table of data to be supplied by an application program that uses
+ the facility, other than as an argument passed when the facility
+ is invoked, then you must make a good faith effort to ensure that,
+ in the event an application does not supply such function or
+ table, the facility still operates, and performs whatever part of
+ its purpose remains meaningful.
+
+ (For example, a function in a library to compute square roots has
+ a purpose that is entirely well-defined independent of the
+ application. Therefore, Subsection 2d requires that any
+ application-supplied function or table used by this function must
+ be optional: if the application does not supply it, the square
+ root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library. To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License. (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.) Do not make any other change in
+these notices.
+
+ Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+ This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+ 4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+ If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library". Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+ However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library". The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+ When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library. The
+threshold for this to be true is not precisely defined by law.
+
+ If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work. (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+ Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+
+ 6. As an exception to the Sections above, you may also compile or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+ You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License. You must supply a copy of this License. If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License. Also, you must do one
+of these things:
+
+ a) Accompany the work with the complete corresponding
+ machine-readable source code for the Library including whatever
+ changes were used in the work (which must be distributed under
+ Sections 1 and 2 above); and, if the work is an executable linked
+ with the Library, with the complete machine-readable "work that
+ uses the Library", as object code and/or source code, so that the
+ user can modify the Library and then relink to produce a modified
+ executable containing the modified Library. (It is understood
+ that the user who changes the contents of definitions files in the
+ Library will not necessarily be able to recompile the application
+ to use the modified definitions.)
+
+ b) Accompany the work with a written offer, valid for at
+ least three years, to give the same user the materials
+ specified in Subsection 6a, above, for a charge no more
+ than the cost of performing this distribution.
+
+ c) If distribution of the work is made by offering access to copy
+ from a designated place, offer equivalent access to copy the above
+ specified materials from the same place.
+
+ d) Verify that the user has already received a copy of these
+ materials or that you have already sent this user a copy.
+
+ For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it. However, as a special exception,
+the source code distributed need not include anything that is normally
+distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+ It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system. Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+
+ 7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+ a) Accompany the combined library with a copy of the same work
+ based on the Library, uncombined with any other library
+ facilities. This must be distributed under the terms of the
+ Sections above.
+
+ b) Give prominent notice with the combined library of the fact
+ that part of it is a work based on the Library, and explaining
+ where to find the accompanying uncombined form of the same work.
+
+ 8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License. Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License. However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+ 9. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Library or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+ 10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all. For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded. In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+ 13. The Free Software Foundation may publish revised and/or new
+versions of the Library General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation. If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+
+ 14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission. For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this. Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+ NO WARRANTY
+
+ 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ Appendix: How to Apply These Terms to Your New Libraries
+
+ If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change. You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+ To apply these terms, attach the following notices to the library. It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the library's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the
+ library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+ <signature of Ty Coon>, 1 April 1990
+ Ty Coon, President of Vice
+
+That's all there is to it!
diff --git a/gnu/usr.bin/gdb/libiberty/Makefile b/gnu/usr.bin/gdb/libiberty/Makefile
new file mode 100644
index 0000000..2bc6abf
--- /dev/null
+++ b/gnu/usr.bin/gdb/libiberty/Makefile
@@ -0,0 +1,13 @@
+LIB= iberty
+SRCS= argv.c basename.c concat.c cplus-dem.c fdmatch.c getopt.c \
+ getopt1.c ieee-float.c obstack.c spaces.c strerror.c strsignal.c \
+ vasprintf.c xmalloc.c
+
+CFLAGS+= -I$(.CURDIR)/../gdb/.
+NOPROFILE=no
+NOPIC=no
+
+install:
+ @echo -n
+
+.include <bsd.lib.mk>
diff --git a/gnu/usr.bin/gdb/libiberty/README.FreeBSD b/gnu/usr.bin/gdb/libiberty/README.FreeBSD
new file mode 100644
index 0000000..0964280
--- /dev/null
+++ b/gnu/usr.bin/gdb/libiberty/README.FreeBSD
@@ -0,0 +1,4 @@
+This is a greatly pared down libiberty directory. Only what's required to build
+gdb-4.13 on FreeBSD 2.0 was kept.
+
+gj@freebsd.org
diff --git a/gnu/usr.bin/gdb/libiberty/alloca-conf.h b/gnu/usr.bin/gdb/libiberty/alloca-conf.h
new file mode 100644
index 0000000..e1d9177
--- /dev/null
+++ b/gnu/usr.bin/gdb/libiberty/alloca-conf.h
@@ -0,0 +1,11 @@
+/* "Normal" configuration for alloca. */
+
+#ifdef __GNUC__
+#define alloca __builtin_alloca
+#else /* not __GNUC__ */
+#ifdef sparc
+#include <alloca.h>
+#else
+char *alloca ();
+#endif /* sparc */
+#endif /* not __GNUC__ */
diff --git a/gnu/usr.bin/gdb/libiberty/argv.c b/gnu/usr.bin/gdb/libiberty/argv.c
new file mode 100644
index 0000000..f344255
--- /dev/null
+++ b/gnu/usr.bin/gdb/libiberty/argv.c
@@ -0,0 +1,344 @@
+/* Create and destroy argument vectors (argv's)
+ Copyright (C) 1992 Free Software Foundation, Inc.
+ Written by Fred Fish @ Cygnus Support
+
+This file is part of the libiberty library.
+Libiberty is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public
+License as published by the Free Software Foundation; either
+version 2 of the License, or (at your option) any later version.
+
+Libiberty is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with libiberty; see the file COPYING.LIB. If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA. */
+
+
+/* Create and destroy argument vectors. An argument vector is simply an
+ array of string pointers, terminated by a NULL pointer. */
+
+/* AIX requires this to be the first thing in the file. */
+#ifdef __GNUC__
+#define alloca __builtin_alloca
+#else /* not __GNUC__ */
+#ifdef sparc
+#include <alloca.h>
+extern char *__builtin_alloca(); /* Stupid include file doesn't declare it */
+#else
+#ifdef _AIX
+ #pragma alloca
+#else
+char *alloca ();
+#endif
+#endif /* sparc */
+#endif /* not __GNUC__ */
+
+#define isspace(ch) ((ch) == ' ' || (ch) == '\t')
+
+#include "alloca-conf.h"
+
+#include "ansidecl.h"
+#include "libiberty.h"
+
+/* Routines imported from standard C runtime libraries. */
+
+#ifdef __STDC__
+
+#include <stddef.h>
+extern void *memcpy (void *s1, const void *s2, size_t n); /* 4.11.2.1 */
+extern size_t strlen (const char *s); /* 4.11.6.3 */
+extern void *malloc (size_t size); /* 4.10.3.3 */
+extern void *realloc (void *ptr, size_t size); /* 4.10.3.4 */
+extern void free (void *ptr); /* 4.10.3.2 */
+extern char *strdup (const char *s); /* Non-ANSI */
+
+#else /* !__STDC__ */
+
+extern char *memcpy (); /* Copy memory region */
+extern int strlen (); /* Count length of string */
+extern char *malloc (); /* Standard memory allocater */
+extern char *realloc (); /* Standard memory reallocator */
+extern void free (); /* Free malloc'd memory */
+extern char *strdup (); /* Duplicate a string */
+
+#endif /* __STDC__ */
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+#ifndef EOS
+#define EOS '\0'
+#endif
+
+#define INITIAL_MAXARGC 8 /* Number of args + NULL in initial argv */
+
+
+/*
+
+NAME
+
+ freeargv -- free an argument vector
+
+SYNOPSIS
+
+ void freeargv (vector)
+ char **vector;
+
+DESCRIPTION
+
+ Free an argument vector that was built using buildargv. Simply scans
+ through the vector, freeing the memory for each argument until the
+ terminating NULL is found, and then frees the vector itself.
+
+RETURNS
+
+ No value.
+
+*/
+
+void freeargv (vector)
+char **vector;
+{
+ register char **scan;
+
+ if (vector != NULL)
+ {
+ for (scan = vector; *scan != NULL; scan++)
+ {
+ free (*scan);
+ }
+ free (vector);
+ }
+}
+
+/*
+
+NAME
+
+ buildargv -- build an argument vector from a string
+
+SYNOPSIS
+
+ char **buildargv (sp)
+ char *sp;
+
+DESCRIPTION
+
+ Given a pointer to a string, parse the string extracting fields
+ separated by whitespace and optionally enclosed within either single
+ or double quotes (which are stripped off), and build a vector of
+ pointers to copies of the string for each field. The input string
+ remains unchanged.
+
+ All of the memory for the pointer array and copies of the string
+ is obtained from malloc. All of the memory can be returned to the
+ system with the single function call freeargv, which takes the
+ returned result of buildargv, as it's argument.
+
+ The memory for the argv array is dynamically expanded as necessary.
+
+RETURNS
+
+ Returns a pointer to the argument vector if successful. Returns NULL
+ if the input string pointer is NULL or if there is insufficient
+ memory to complete building the argument vector.
+
+NOTES
+
+ In order to provide a working buffer for extracting arguments into,
+ with appropriate stripping of quotes and translation of backslash
+ sequences, we allocate a working buffer at least as long as the input
+ string. This ensures that we always have enough space in which to
+ work, since the extracted arg is never larger than the input string.
+
+ If the input is a null string (as opposed to a NULL pointer), then
+ buildarg returns an argv that has one arg, a null string.
+
+ Argv is always kept terminated with a NULL arg pointer, so it can
+ be passed to freeargv at any time, or returned, as appropriate.
+*/
+
+char **buildargv (input)
+char *input;
+{
+ char *arg;
+ char *copybuf;
+ int squote = 0;
+ int dquote = 0;
+ int bsquote = 0;
+ int argc = 0;
+ int maxargc = 0;
+ char **argv = NULL;
+ char **nargv;
+
+ if (input != NULL)
+ {
+ copybuf = alloca (strlen (input) + 1);
+ /* Is a do{}while to always execute the loop once. Always return an
+ argv, even for null strings. See NOTES above, test case below. */
+ do
+ {
+ /* Pick off argv[argc] */
+ while (isspace (*input))
+ {
+ input++;
+ }
+ if ((maxargc == 0) || (argc >= (maxargc - 1)))
+ {
+ /* argv needs initialization, or expansion */
+ if (argv == NULL)
+ {
+ maxargc = INITIAL_MAXARGC;
+ nargv = (char **) malloc (maxargc * sizeof (char *));
+ }
+ else
+ {
+ maxargc *= 2;
+ nargv = (char **) realloc (argv, maxargc * sizeof (char *));
+ }
+ if (nargv == NULL)
+ {
+ if (argv != NULL)
+ {
+ freeargv (argv);
+ argv = NULL;
+ }
+ break;
+ }
+ argv = nargv;
+ argv[argc] = NULL;
+ }
+ /* Begin scanning arg */
+ arg = copybuf;
+ while (*input != EOS)
+ {
+ if (isspace (*input) && !squote && !dquote && !bsquote)
+ {
+ break;
+ }
+ else
+ {
+ if (bsquote)
+ {
+ bsquote = 0;
+ *arg++ = *input;
+ }
+ else if (*input == '\\')
+ {
+ bsquote = 1;
+ }
+ else if (squote)
+ {
+ if (*input == '\'')
+ {
+ squote = 0;
+ }
+ else
+ {
+ *arg++ = *input;
+ }
+ }
+ else if (dquote)
+ {
+ if (*input == '"')
+ {
+ dquote = 0;
+ }
+ else
+ {
+ *arg++ = *input;
+ }
+ }
+ else
+ {
+ if (*input == '\'')
+ {
+ squote = 1;
+ }
+ else if (*input == '"')
+ {
+ dquote = 1;
+ }
+ else
+ {
+ *arg++ = *input;
+ }
+ }
+ input++;
+ }
+ }
+ *arg = EOS;
+ argv[argc] = strdup (copybuf);
+ if (argv[argc] == NULL)
+ {
+ freeargv (argv);
+ argv = NULL;
+ break;
+ }
+ argc++;
+ argv[argc] = NULL;
+
+ while (isspace (*input))
+ {
+ input++;
+ }
+ }
+ while (*input != EOS);
+ }
+ return (argv);
+}
+
+#ifdef MAIN
+
+/* Simple little test driver. */
+
+static char *tests[] =
+{
+ "a simple command line",
+ "arg 'foo' is single quoted",
+ "arg \"bar\" is double quoted",
+ "arg \"foo bar\" has embedded whitespace",
+ "arg 'Jack said \\'hi\\'' has single quotes",
+ "arg 'Jack said \\\"hi\\\"' has double quotes",
+ "a b c d e f g h i j k l m n o p q r s t u v w x y z 1 2 3 4 5 6 7 8 9",
+
+ /* This should be expanded into only one argument. */
+ "trailing-whitespace ",
+
+ "",
+ NULL
+};
+
+main ()
+{
+ char **argv;
+ char **test;
+ char **targs;
+
+ for (test = tests; *test != NULL; test++)
+ {
+ printf ("buildargv(\"%s\")\n", *test);
+ if ((argv = buildargv (*test)) == NULL)
+ {
+ printf ("failed!\n\n");
+ }
+ else
+ {
+ for (targs = argv; *targs != NULL; targs++)
+ {
+ printf ("\t\"%s\"\n", *targs);
+ }
+ printf ("\n");
+ }
+ freeargv (argv);
+ }
+
+}
+
+#endif /* MAIN */
diff --git a/gnu/usr.bin/gdb/libiberty/basename.c b/gnu/usr.bin/gdb/libiberty/basename.c
new file mode 100644
index 0000000..db1bb6c
--- /dev/null
+++ b/gnu/usr.bin/gdb/libiberty/basename.c
@@ -0,0 +1,59 @@
+/* Return the basename of a pathname.
+ Copyright (C) 1991 Free Software Foundation, Inc.
+
+This file is part of the libiberty library.
+Libiberty is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public
+License as published by the Free Software Foundation; either
+version 2 of the License, or (at your option) any later version.
+
+Libiberty is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with libiberty; see the file COPYING.LIB. If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA. */
+
+/*
+
+NAME
+
+ basename -- return pointer to last component of a pathname
+
+SYNOPSIS
+
+ char *basename (char *name)
+
+DESCRIPTION
+
+ Given a pointer to a string containing a typical pathname
+ (/usr/src/cmd/ls/ls.c for example), returns a pointer to the
+ last component of the pathname ("ls.c" in this case).
+
+BUGS
+
+ Presumes a UNIX style path with UNIX style separators.
+*/
+
+
+#include "ansidecl.h"
+#include "libiberty.h"
+
+char *
+basename (name)
+ char *name;
+{
+ char *base = name;
+
+ while (*name)
+ {
+ if (*name++ == '/')
+ {
+ base = name;
+ }
+ }
+ return (base);
+}
diff --git a/gnu/usr.bin/gdb/libiberty/concat.c b/gnu/usr.bin/gdb/libiberty/concat.c
new file mode 100644
index 0000000..fd720d1
--- /dev/null
+++ b/gnu/usr.bin/gdb/libiberty/concat.c
@@ -0,0 +1,167 @@
+/* Concatenate variable number of strings.
+ Copyright (C) 1991, 1994 Free Software Foundation, Inc.
+ Written by Fred Fish @ Cygnus Support
+
+This file is part of the libiberty library.
+Libiberty is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public
+License as published by the Free Software Foundation; either
+version 2 of the License, or (at your option) any later version.
+
+Libiberty is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with libiberty; see the file COPYING.LIB. If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA. */
+
+
+/*
+
+NAME
+
+ concat -- concatenate a variable number of strings
+
+SYNOPSIS
+
+ #include <varargs.h>
+
+ char *concat (s1, s2, s3, ..., NULL)
+
+DESCRIPTION
+
+ Concatenate a variable number of strings and return the result
+ in freshly malloc'd memory.
+
+ Returns NULL if insufficient memory is available. The argument
+ list is terminated by the first NULL pointer encountered. Pointers
+ to empty strings are ignored.
+
+NOTES
+
+ This function uses xmalloc() which is expected to be a front end
+ function to malloc() that deals with low memory situations. In
+ typical use, if malloc() returns NULL then xmalloc() diverts to an
+ error handler routine which never returns, and thus xmalloc will
+ never return a NULL pointer. If the client application wishes to
+ deal with low memory situations itself, it should supply an xmalloc
+ that just directly invokes malloc and blindly returns whatever
+ malloc returns.
+*/
+
+
+#include "ansidecl.h"
+#include "libiberty.h"
+
+#ifdef ANSI_PROTOTYPES
+#include <stdarg.h>
+#else
+#include <varargs.h>
+#endif
+
+#ifdef __STDC__
+#include <stddef.h>
+extern size_t strlen (const char *s);
+#else
+extern int strlen ();
+#endif
+
+#define NULLP (char *)0
+
+/* VARARGS */
+#ifdef ANSI_PROTOTYPES
+char *
+concat (const char *first, ...)
+#else
+char *
+concat (va_alist)
+ va_dcl
+#endif
+{
+ register int length;
+ register char *newstr;
+ register char *end;
+ register const char *arg;
+ va_list args;
+#ifndef ANSI_PROTOTYPES
+ const char *first;
+#endif
+
+ /* First compute the size of the result and get sufficient memory. */
+
+#ifdef ANSI_PROTOTYPES
+ va_start (args, first);
+#else
+ va_start (args);
+ first = va_arg (args, const char *);
+#endif
+
+ if (first == NULLP)
+ length = 0;
+ else
+ {
+ length = strlen (first);
+ while ((arg = va_arg (args, const char *)) != NULLP)
+ {
+ length += strlen (arg);
+ }
+ }
+ newstr = (char *) xmalloc (length + 1);
+ va_end (args);
+
+ /* Now copy the individual pieces to the result string. */
+
+ if (newstr != NULLP)
+ {
+#ifdef ANSI_PROTOTYPES
+ va_start (args, first);
+#else
+ va_start (args);
+ first = va_arg (args, const char *);
+#endif
+ end = newstr;
+ if (first != NULLP)
+ {
+ arg = first;
+ while (*arg)
+ {
+ *end++ = *arg++;
+ }
+ while ((arg = va_arg (args, const char *)) != NULLP)
+ {
+ while (*arg)
+ {
+ *end++ = *arg++;
+ }
+ }
+ }
+ *end = '\000';
+ va_end (args);
+ }
+
+ return (newstr);
+}
+
+#ifdef MAIN
+
+/* Simple little test driver. */
+
+#include <stdio.h>
+
+int
+main ()
+{
+ printf ("\"\" = \"%s\"\n", concat (NULLP));
+ printf ("\"a\" = \"%s\"\n", concat ("a", NULLP));
+ printf ("\"ab\" = \"%s\"\n", concat ("a", "b", NULLP));
+ printf ("\"abc\" = \"%s\"\n", concat ("a", "b", "c", NULLP));
+ printf ("\"abcd\" = \"%s\"\n", concat ("ab", "cd", NULLP));
+ printf ("\"abcde\" = \"%s\"\n", concat ("ab", "c", "de", NULLP));
+ printf ("\"abcdef\" = \"%s\"\n", concat ("", "a", "", "bcd", "ef", NULLP));
+ return 0;
+}
+
+#endif
diff --git a/gnu/usr.bin/gdb/libiberty/config.h b/gnu/usr.bin/gdb/libiberty/config.h
new file mode 100644
index 0000000..b37ee84
--- /dev/null
+++ b/gnu/usr.bin/gdb/libiberty/config.h
@@ -0,0 +1 @@
+/* !Automatically generated from ./functions.def - DO NOT EDIT! */
diff --git a/gnu/usr.bin/gdb/libiberty/cplus-dem.c b/gnu/usr.bin/gdb/libiberty/cplus-dem.c
new file mode 100644
index 0000000..cc9edf0
--- /dev/null
+++ b/gnu/usr.bin/gdb/libiberty/cplus-dem.c
@@ -0,0 +1,2876 @@
+/* Demangler for GNU C++
+ Copyright 1989, 1991 Free Software Foundation, Inc.
+ Written by James Clark (jjc@jclark.uucp)
+ Rewritten by Fred Fish (fnf@cygnus.com) for ARM and Lucid demangling
+
+This file is part of the libiberty library.
+Libiberty is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public
+License as published by the Free Software Foundation; either
+version 2 of the License, or (at your option) any later version.
+
+Libiberty is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with libiberty; see the file COPYING.LIB. If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA. */
+
+/* This file exports two functions; cplus_mangle_opname and cplus_demangle.
+
+ This file imports xmalloc and xrealloc, which are like malloc and
+ realloc except that they generate a fatal error if there is no
+ available memory. */
+
+#include <demangle.h>
+#undef CURRENT_DEMANGLING_STYLE
+#define CURRENT_DEMANGLING_STYLE work->options
+#include <ctype.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "libiberty.h"
+
+extern char *strstr ();
+
+/* In order to allow a single demangler executable to demangle strings
+ using various common values of CPLUS_MARKER, as well as any specific
+ one set at compile time, we maintain a string containing all the
+ commonly used ones, and check to see if the marker we are looking for
+ is in that string. CPLUS_MARKER is usually '$' on systems where the
+ assembler can deal with that. Where the assembler can't, it's usually
+ '.' (but on many systems '.' is used for other things). We put the
+ current defined CPLUS_MARKER first (which defaults to '$'), followed
+ by the next most common value, followed by an explicit '$' in case
+ the value of CPLUS_MARKER is not '$'.
+
+ We could avoid this if we could just get g++ to tell us what the actual
+ cplus marker character is as part of the debug information, perhaps by
+ ensuring that it is the character that terminates the gcc<n>_compiled
+ marker symbol (FIXME). */
+
+#if !defined (CPLUS_MARKER)
+#define CPLUS_MARKER '$'
+#endif
+
+enum demangling_styles current_demangling_style = gnu_demangling;
+
+static char cplus_markers[] = { CPLUS_MARKER, '.', '$', '\0' };
+
+void
+set_cplus_marker_for_demangling (ch)
+ int ch;
+{
+ cplus_markers[0] = ch;
+}
+
+/* Stuff that is shared between sub-routines.
+ * Using a shared structure allows cplus_demangle to be reentrant. */
+
+struct work_stuff
+{
+ int options;
+ char **typevec;
+ int ntypes;
+ int typevec_size;
+ int constructor;
+ int destructor;
+ int static_type; /* A static member function */
+ int const_type; /* A const member function */
+};
+
+#define PRINT_ANSI_QUALIFIERS (work -> options & DMGL_ANSI)
+#define PRINT_ARG_TYPES (work -> options & DMGL_PARAMS)
+
+static CONST struct optable
+{
+ CONST char *in;
+ CONST char *out;
+ int flags;
+} optable[] = {
+ {"nw", " new", DMGL_ANSI}, /* new (1.92, ansi) */
+ {"dl", " delete", DMGL_ANSI}, /* new (1.92, ansi) */
+ {"new", " new", 0}, /* old (1.91, and 1.x) */
+ {"delete", " delete", 0}, /* old (1.91, and 1.x) */
+ {"vn", " new []", DMGL_ANSI}, /* GNU, pending ansi */
+ {"vd", " delete []", DMGL_ANSI}, /* GNU, pending ansi */
+ {"as", "=", DMGL_ANSI}, /* ansi */
+ {"ne", "!=", DMGL_ANSI}, /* old, ansi */
+ {"eq", "==", DMGL_ANSI}, /* old, ansi */
+ {"ge", ">=", DMGL_ANSI}, /* old, ansi */
+ {"gt", ">", DMGL_ANSI}, /* old, ansi */
+ {"le", "<=", DMGL_ANSI}, /* old, ansi */
+ {"lt", "<", DMGL_ANSI}, /* old, ansi */
+ {"plus", "+", 0}, /* old */
+ {"pl", "+", DMGL_ANSI}, /* ansi */
+ {"apl", "+=", DMGL_ANSI}, /* ansi */
+ {"minus", "-", 0}, /* old */
+ {"mi", "-", DMGL_ANSI}, /* ansi */
+ {"ami", "-=", DMGL_ANSI}, /* ansi */
+ {"mult", "*", 0}, /* old */
+ {"ml", "*", DMGL_ANSI}, /* ansi */
+ {"amu", "*=", DMGL_ANSI}, /* ansi (ARM/Lucid) */
+ {"aml", "*=", DMGL_ANSI}, /* ansi (GNU/g++) */
+ {"convert", "+", 0}, /* old (unary +) */
+ {"negate", "-", 0}, /* old (unary -) */
+ {"trunc_mod", "%", 0}, /* old */
+ {"md", "%", DMGL_ANSI}, /* ansi */
+ {"amd", "%=", DMGL_ANSI}, /* ansi */
+ {"trunc_div", "/", 0}, /* old */
+ {"dv", "/", DMGL_ANSI}, /* ansi */
+ {"adv", "/=", DMGL_ANSI}, /* ansi */
+ {"truth_andif", "&&", 0}, /* old */
+ {"aa", "&&", DMGL_ANSI}, /* ansi */
+ {"truth_orif", "||", 0}, /* old */
+ {"oo", "||", DMGL_ANSI}, /* ansi */
+ {"truth_not", "!", 0}, /* old */
+ {"nt", "!", DMGL_ANSI}, /* ansi */
+ {"postincrement","++", 0}, /* old */
+ {"pp", "++", DMGL_ANSI}, /* ansi */
+ {"postdecrement","--", 0}, /* old */
+ {"mm", "--", DMGL_ANSI}, /* ansi */
+ {"bit_ior", "|", 0}, /* old */
+ {"or", "|", DMGL_ANSI}, /* ansi */
+ {"aor", "|=", DMGL_ANSI}, /* ansi */
+ {"bit_xor", "^", 0}, /* old */
+ {"er", "^", DMGL_ANSI}, /* ansi */
+ {"aer", "^=", DMGL_ANSI}, /* ansi */
+ {"bit_and", "&", 0}, /* old */
+ {"ad", "&", DMGL_ANSI}, /* ansi */
+ {"aad", "&=", DMGL_ANSI}, /* ansi */
+ {"bit_not", "~", 0}, /* old */
+ {"co", "~", DMGL_ANSI}, /* ansi */
+ {"call", "()", 0}, /* old */
+ {"cl", "()", DMGL_ANSI}, /* ansi */
+ {"alshift", "<<", 0}, /* old */
+ {"ls", "<<", DMGL_ANSI}, /* ansi */
+ {"als", "<<=", DMGL_ANSI}, /* ansi */
+ {"arshift", ">>", 0}, /* old */
+ {"rs", ">>", DMGL_ANSI}, /* ansi */
+ {"ars", ">>=", DMGL_ANSI}, /* ansi */
+ {"component", "->", 0}, /* old */
+ {"pt", "->", DMGL_ANSI}, /* ansi; Lucid C++ form */
+ {"rf", "->", DMGL_ANSI}, /* ansi; ARM/GNU form */
+ {"indirect", "*", 0}, /* old */
+ {"method_call", "->()", 0}, /* old */
+ {"addr", "&", 0}, /* old (unary &) */
+ {"array", "[]", 0}, /* old */
+ {"vc", "[]", DMGL_ANSI}, /* ansi */
+ {"compound", ", ", 0}, /* old */
+ {"cm", ", ", DMGL_ANSI}, /* ansi */
+ {"cond", "?:", 0}, /* old */
+ {"cn", "?:", DMGL_ANSI}, /* psuedo-ansi */
+ {"max", ">?", 0}, /* old */
+ {"mx", ">?", DMGL_ANSI}, /* psuedo-ansi */
+ {"min", "<?", 0}, /* old */
+ {"mn", "<?", DMGL_ANSI}, /* psuedo-ansi */
+ {"nop", "", 0}, /* old (for operator=) */
+ {"rm", "->*", DMGL_ANSI} /* ansi */
+};
+
+
+typedef struct string /* Beware: these aren't required to be */
+{ /* '\0' terminated. */
+ char *b; /* pointer to start of string */
+ char *p; /* pointer after last character */
+ char *e; /* pointer after end of allocated space */
+} string;
+
+#define STRING_EMPTY(str) ((str) -> b == (str) -> p)
+#define PREPEND_BLANK(str) {if (!STRING_EMPTY(str)) \
+ string_prepend(str, " ");}
+#define APPEND_BLANK(str) {if (!STRING_EMPTY(str)) \
+ string_append(str, " ");}
+
+#define ARM_VTABLE_STRING "__vtbl__" /* Lucid/ARM virtual table prefix */
+#define ARM_VTABLE_STRLEN 8 /* strlen (ARM_VTABLE_STRING) */
+
+/* Prototypes for local functions */
+
+static char *
+mop_up PARAMS ((struct work_stuff *, string *, int));
+
+#if 0
+static int
+demangle_method_args PARAMS ((struct work_stuff *work, CONST char **, string *));
+#endif
+
+static int
+demangle_template PARAMS ((struct work_stuff *work, CONST char **, string *,
+ string *));
+
+static int
+demangle_qualified PARAMS ((struct work_stuff *, CONST char **, string *,
+ int, int));
+
+static int
+demangle_class PARAMS ((struct work_stuff *, CONST char **, string *));
+
+static int
+demangle_fund_type PARAMS ((struct work_stuff *, CONST char **, string *));
+
+static int
+demangle_signature PARAMS ((struct work_stuff *, CONST char **, string *));
+
+static int
+demangle_prefix PARAMS ((struct work_stuff *, CONST char **, string *));
+
+static int
+gnu_special PARAMS ((struct work_stuff *, CONST char **, string *));
+
+static int
+arm_special PARAMS ((struct work_stuff *, CONST char **, string *));
+
+static void
+string_need PARAMS ((string *, int));
+
+static void
+string_delete PARAMS ((string *));
+
+static void
+string_init PARAMS ((string *));
+
+static void
+string_clear PARAMS ((string *));
+
+#if 0
+static int
+string_empty PARAMS ((string *));
+#endif
+
+static void
+string_append PARAMS ((string *, CONST char *));
+
+static void
+string_appends PARAMS ((string *, string *));
+
+static void
+string_appendn PARAMS ((string *, CONST char *, int));
+
+static void
+string_prepend PARAMS ((string *, CONST char *));
+
+static void
+string_prependn PARAMS ((string *, CONST char *, int));
+
+static int
+get_count PARAMS ((CONST char **, int *));
+
+static int
+consume_count PARAMS ((CONST char **));
+
+static int
+demangle_args PARAMS ((struct work_stuff *, CONST char **, string *));
+
+static int
+do_type PARAMS ((struct work_stuff *, CONST char **, string *));
+
+static int
+do_arg PARAMS ((struct work_stuff *, CONST char **, string *));
+
+static void
+demangle_function_name PARAMS ((struct work_stuff *, CONST char **, string *,
+ CONST char *));
+
+static void
+remember_type PARAMS ((struct work_stuff *, CONST char *, int));
+
+static void
+forget_types PARAMS ((struct work_stuff *));
+
+static void
+string_prepends PARAMS ((string *, string *));
+
+/* Translate count to integer, consuming tokens in the process.
+ Conversion terminates on the first non-digit character.
+ Trying to consume something that isn't a count results in
+ no consumption of input and a return of 0. */
+
+static int
+consume_count (type)
+ CONST char **type;
+{
+ int count = 0;
+
+ while (isdigit (**type))
+ {
+ count *= 10;
+ count += **type - '0';
+ (*type)++;
+ }
+ return (count);
+}
+
+int
+cplus_demangle_opname (opname, result, options)
+ char *opname;
+ char *result;
+ int options;
+{
+ int len, i, len1, ret;
+ string type;
+ struct work_stuff work[1];
+ CONST char *tem;
+
+ len = strlen(opname);
+ result[0] = '\0';
+ ret = 0;
+ work->options = options;
+
+ if (opname[0] == '_' && opname[1] == '_'
+ && opname[2] == 'o' && opname[3] == 'p')
+ {
+ /* ANSI. */
+ /* type conversion operator. */
+ tem = opname + 4;
+ if (do_type (work, &tem, &type))
+ {
+ strcat (result, "operator ");
+ strncat (result, type.b, type.p - type.b);
+ string_delete (&type);
+ ret = 1;
+ }
+ }
+ else if (opname[0] == '_' && opname[1] == '_'
+ && opname[2] >= 'a' && opname[2] <= 'z'
+ && opname[3] >= 'a' && opname[3] <= 'z')
+ {
+ if (opname[4] == '\0')
+ {
+ /* Operator. */
+ for (i = 0; i < sizeof (optable) / sizeof (optable[0]); i++)
+ {
+ if (strlen (optable[i].in) == 2
+ && memcmp (optable[i].in, opname + 2, 2) == 0)
+ {
+ strcat (result, "operator");
+ strcat (result, optable[i].out);
+ ret = 1;
+ break;
+ }
+ }
+ }
+ else
+ {
+ if (opname[2] == 'a' && opname[5] == '\0')
+ {
+ /* Assignment. */
+ for (i = 0; i < sizeof (optable) / sizeof (optable[0]); i++)
+ {
+ if (strlen (optable[i].in) == 3
+ && memcmp (optable[i].in, opname + 2, 3) == 0)
+ {
+ strcat (result, "operator");
+ strcat (result, optable[i].out);
+ ret = 1;
+ break;
+ }
+ }
+ }
+ }
+ }
+ else if (len >= 3
+ && opname[0] == 'o'
+ && opname[1] == 'p'
+ && strchr (cplus_markers, opname[2]) != NULL)
+ {
+ /* see if it's an assignment expression */
+ if (len >= 10 /* op$assign_ */
+ && memcmp (opname + 3, "assign_", 7) == 0)
+ {
+ for (i = 0; i < sizeof (optable) / sizeof (optable[0]); i++)
+ {
+ len1 = len - 10;
+ if (strlen (optable[i].in) == len1
+ && memcmp (optable[i].in, opname + 10, len1) == 0)
+ {
+ strcat (result, "operator");
+ strcat (result, optable[i].out);
+ strcat (result, "=");
+ ret = 1;
+ break;
+ }
+ }
+ }
+ else
+ {
+ for (i = 0; i < sizeof (optable) / sizeof (optable[0]); i++)
+ {
+ len1 = len - 3;
+ if (strlen (optable[i].in) == len1
+ && memcmp (optable[i].in, opname + 3, len1) == 0)
+ {
+ strcat (result, "operator");
+ strcat (result, optable[i].out);
+ ret = 1;
+ break;
+ }
+ }
+ }
+ }
+ else if (len >= 5 && memcmp (opname, "type", 4) == 0
+ && strchr (cplus_markers, opname[4]) != NULL)
+ {
+ /* type conversion operator */
+ tem = opname + 5;
+ if (do_type (work, &tem, &type))
+ {
+ strcat (result, "operator ");
+ strncat (result, type.b, type.p - type.b);
+ string_delete (&type);
+ ret = 1;
+ }
+ }
+ return ret;
+
+}
+/* Takes operator name as e.g. "++" and returns mangled
+ operator name (e.g. "postincrement_expr"), or NULL if not found.
+
+ If OPTIONS & DMGL_ANSI == 1, return the ANSI name;
+ if OPTIONS & DMGL_ANSI == 0, return the old GNU name. */
+
+char *
+cplus_mangle_opname (opname, options)
+ char *opname;
+ int options;
+{
+ int i;
+ int len;
+
+ len = strlen (opname);
+ for (i = 0; i < sizeof (optable) / sizeof (optable[0]); i++)
+ {
+ if (strlen (optable[i].out) == len
+ && (options & DMGL_ANSI) == (optable[i].flags & DMGL_ANSI)
+ && memcmp (optable[i].out, opname, len) == 0)
+ return ((char *)optable[i].in);
+ }
+ return (0);
+}
+
+/* check to see whether MANGLED can match TEXT in the first TEXT_LEN
+ characters. */
+
+int cplus_match (mangled, text, text_len)
+ CONST char *mangled;
+ char *text;
+ int text_len;
+{
+ if (strncmp (mangled, text, text_len) != 0) {
+ return(0); /* cannot match either */
+ } else {
+ return(1); /* matches mangled, may match demangled */
+ }
+}
+
+/* char *cplus_demangle (const char *mangled, int options)
+
+ If MANGLED is a mangled function name produced by GNU C++, then
+ a pointer to a malloced string giving a C++ representation
+ of the name will be returned; otherwise NULL will be returned.
+ It is the caller's responsibility to free the string which
+ is returned.
+
+ The OPTIONS arg may contain one or more of the following bits:
+
+ DMGL_ANSI ANSI qualifiers such as `const' and `void' are
+ included.
+ DMGL_PARAMS Function parameters are included.
+
+ For example,
+
+ cplus_demangle ("foo__1Ai", DMGL_PARAMS) => "A::foo(int)"
+ cplus_demangle ("foo__1Ai", DMGL_PARAMS | DMGL_ANSI) => "A::foo(int)"
+ cplus_demangle ("foo__1Ai", 0) => "A::foo"
+
+ cplus_demangle ("foo__1Afe", DMGL_PARAMS) => "A::foo(float,...)"
+ cplus_demangle ("foo__1Afe", DMGL_PARAMS | DMGL_ANSI)=> "A::foo(float,...)"
+ cplus_demangle ("foo__1Afe", 0) => "A::foo"
+
+ Note that any leading underscores, or other such characters prepended by
+ the compilation system, are presumed to have already been stripped from
+ MANGLED. */
+
+char *
+cplus_demangle (mangled, options)
+ CONST char *mangled;
+ int options;
+{
+ string decl;
+ int success = 0;
+ struct work_stuff work[1];
+ char *demangled = NULL;
+
+ if ((mangled != NULL) && (*mangled != '\0'))
+ {
+ memset ((char *) work, 0, sizeof (work));
+ work -> options = options;
+ if ((work->options & DMGL_STYLE_MASK) == 0)
+ work->options |= (int)current_demangling_style & DMGL_STYLE_MASK;
+
+ string_init (&decl);
+
+ /* First check to see if gnu style demangling is active and if the
+ string to be demangled contains a CPLUS_MARKER. If so, attempt to
+ recognize one of the gnu special forms rather than looking for a
+ standard prefix. In particular, don't worry about whether there
+ is a "__" string in the mangled string. Consider "_$_5__foo" for
+ example. */
+
+ if ((AUTO_DEMANGLING || GNU_DEMANGLING))
+ {
+ success = gnu_special (work, &mangled, &decl);
+ }
+ if (!success)
+ {
+ success = demangle_prefix (work, &mangled, &decl);
+ }
+ if (success && (*mangled != '\0'))
+ {
+ success = demangle_signature (work, &mangled, &decl);
+ }
+ if (work->constructor == 2)
+ {
+ string_prepend(&decl, "global constructors keyed to ");
+ work->constructor = 0;
+ }
+ else if (work->destructor == 2)
+ {
+ string_prepend(&decl, "global destructors keyed to ");
+ work->destructor = 0;
+ }
+ demangled = mop_up (work, &decl, success);
+ }
+ return (demangled);
+}
+
+static char *
+mop_up (work, declp, success)
+ struct work_stuff *work;
+ string *declp;
+ int success;
+{
+ char *demangled = NULL;
+
+ /* Discard the remembered types, if any. */
+
+ forget_types (work);
+ if (work -> typevec != NULL)
+ {
+ free ((char *) work -> typevec);
+ }
+
+ /* If demangling was successful, ensure that the demangled string is null
+ terminated and return it. Otherwise, free the demangling decl. */
+
+ if (!success)
+ {
+ string_delete (declp);
+ }
+ else
+ {
+ string_appendn (declp, "", 1);
+ demangled = declp -> b;
+ }
+ return (demangled);
+}
+
+/*
+
+LOCAL FUNCTION
+
+ demangle_signature -- demangle the signature part of a mangled name
+
+SYNOPSIS
+
+ static int
+ demangle_signature (struct work_stuff *work, const char **mangled,
+ string *declp);
+
+DESCRIPTION
+
+ Consume and demangle the signature portion of the mangled name.
+
+ DECLP is the string where demangled output is being built. At
+ entry it contains the demangled root name from the mangled name
+ prefix. I.E. either a demangled operator name or the root function
+ name. In some special cases, it may contain nothing.
+
+ *MANGLED points to the current unconsumed location in the mangled
+ name. As tokens are consumed and demangling is performed, the
+ pointer is updated to continuously point at the next token to
+ be consumed.
+
+ Demangling GNU style mangled names is nasty because there is no
+ explicit token that marks the start of the outermost function
+ argument list.
+*/
+
+static int
+demangle_signature (work, mangled, declp)
+ struct work_stuff *work;
+ CONST char **mangled;
+ string *declp;
+{
+ int success = 1;
+ int func_done = 0;
+ int expect_func = 0;
+ CONST char *oldmangled = NULL;
+ string trawname;
+ string tname;
+
+ while (success && (**mangled != '\0'))
+ {
+ switch (**mangled)
+ {
+ case 'Q':
+ oldmangled = *mangled;
+ success = demangle_qualified (work, mangled, declp, 1, 0);
+ if (success)
+ {
+ remember_type (work, oldmangled, *mangled - oldmangled);
+ }
+ if (AUTO_DEMANGLING || GNU_DEMANGLING)
+ {
+ expect_func = 1;
+ }
+ oldmangled = NULL;
+ break;
+
+ case 'S':
+ /* Static member function */
+ if (oldmangled == NULL)
+ {
+ oldmangled = *mangled;
+ }
+ (*mangled)++;
+ work -> static_type = 1;
+ break;
+
+ case 'C':
+ /* a const member function */
+ if (oldmangled == NULL)
+ {
+ oldmangled = *mangled;
+ }
+ (*mangled)++;
+ work -> const_type = 1;
+ break;
+
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ if (oldmangled == NULL)
+ {
+ oldmangled = *mangled;
+ }
+ success = demangle_class (work, mangled, declp);
+ if (success)
+ {
+ remember_type (work, oldmangled, *mangled - oldmangled);
+ }
+ if (AUTO_DEMANGLING || GNU_DEMANGLING)
+ {
+ expect_func = 1;
+ }
+ oldmangled = NULL;
+ break;
+
+ case 'F':
+ /* Function */
+ /* ARM style demangling includes a specific 'F' character after
+ the class name. For GNU style, it is just implied. So we can
+ safely just consume any 'F' at this point and be compatible
+ with either style. */
+
+ oldmangled = NULL;
+ func_done = 1;
+ (*mangled)++;
+
+ /* For lucid/ARM style we have to forget any types we might
+ have remembered up to this point, since they were not argument
+ types. GNU style considers all types seen as available for
+ back references. See comment in demangle_args() */
+
+ if (LUCID_DEMANGLING || ARM_DEMANGLING)
+ {
+ forget_types (work);
+ }
+ success = demangle_args (work, mangled, declp);
+ break;
+
+ case 't':
+ /* G++ Template */
+ string_init(&trawname);
+ string_init(&tname);
+ if (oldmangled == NULL)
+ {
+ oldmangled = *mangled;
+ }
+ success = demangle_template (work, mangled, &tname, &trawname);
+ if (success)
+ {
+ remember_type (work, oldmangled, *mangled - oldmangled);
+ }
+ string_append(&tname, "::");
+ string_prepends(declp, &tname);
+ if (work -> destructor & 1)
+ {
+ string_prepend (&trawname, "~");
+ string_appends (declp, &trawname);
+ work->destructor -= 1;
+ }
+ if ((work->constructor & 1) || (work->destructor & 1))
+ {
+ string_appends (declp, &trawname);
+ work->constructor -= 1;
+ }
+ string_delete(&trawname);
+ string_delete(&tname);
+ oldmangled = NULL;
+ expect_func = 1;
+ break;
+
+ case '_':
+ /* At the outermost level, we cannot have a return type specified,
+ so if we run into another '_' at this point we are dealing with
+ a mangled name that is either bogus, or has been mangled by
+ some algorithm we don't know how to deal with. So just
+ reject the entire demangling. */
+ success = 0;
+ break;
+
+ default:
+ if (AUTO_DEMANGLING || GNU_DEMANGLING)
+ {
+ /* Assume we have stumbled onto the first outermost function
+ argument token, and start processing args. */
+ func_done = 1;
+ success = demangle_args (work, mangled, declp);
+ }
+ else
+ {
+ /* Non-GNU demanglers use a specific token to mark the start
+ of the outermost function argument tokens. Typically 'F',
+ for ARM-demangling, for example. So if we find something
+ we are not prepared for, it must be an error. */
+ success = 0;
+ }
+ break;
+ }
+/*
+ if (AUTO_DEMANGLING || GNU_DEMANGLING)
+*/
+ {
+ if (success && expect_func)
+ {
+ func_done = 1;
+ success = demangle_args (work, mangled, declp);
+ }
+ }
+ }
+ if (success && !func_done)
+ {
+ if (AUTO_DEMANGLING || GNU_DEMANGLING)
+ {
+ /* With GNU style demangling, bar__3foo is 'foo::bar(void)', and
+ bar__3fooi is 'foo::bar(int)'. We get here when we find the
+ first case, and need to ensure that the '(void)' gets added to
+ the current declp. Note that with ARM, the first case
+ represents the name of a static data member 'foo::bar',
+ which is in the current declp, so we leave it alone. */
+ success = demangle_args (work, mangled, declp);
+ }
+ }
+ if (success && work -> static_type && PRINT_ARG_TYPES)
+ {
+ string_append (declp, " static");
+ }
+ if (success && work -> const_type && PRINT_ARG_TYPES)
+ {
+ string_append (declp, " const");
+ }
+ return (success);
+}
+
+#if 0
+
+static int
+demangle_method_args (work, mangled, declp)
+ struct work_stuff *work;
+ CONST char **mangled;
+ string *declp;
+{
+ int success = 0;
+
+ if (work -> static_type)
+ {
+ string_append (declp, *mangled + 1);
+ *mangled += strlen (*mangled);
+ success = 1;
+ }
+ else
+ {
+ success = demangle_args (work, mangled, declp);
+ }
+ return (success);
+}
+
+#endif
+
+static int
+demangle_template (work, mangled, tname, trawname)
+ struct work_stuff *work;
+ CONST char **mangled;
+ string *tname;
+ string *trawname;
+{
+ int i;
+ int is_pointer;
+ int is_real;
+ int is_integral;
+ int r;
+ int need_comma = 0;
+ int success = 0;
+ int done;
+ CONST char *old_p;
+ CONST char *start;
+ int symbol_len;
+ string temp;
+
+ (*mangled)++;
+ start = *mangled;
+ /* get template name */
+ if ((r = consume_count (mangled)) == 0 || strlen (*mangled) < r)
+ {
+ return (0);
+ }
+ if (trawname)
+ string_appendn (trawname, *mangled, r);
+ string_appendn (tname, *mangled, r);
+ *mangled += r;
+ string_append (tname, "<");
+ /* get size of template parameter list */
+ if (!get_count (mangled, &r))
+ {
+ return (0);
+ }
+ for (i = 0; i < r; i++)
+ {
+ if (need_comma)
+ {
+ string_append (tname, ", ");
+ }
+ /* Z for type parameters */
+ if (**mangled == 'Z')
+ {
+ (*mangled)++;
+ /* temp is initialized in do_type */
+ success = do_type (work, mangled, &temp);
+ if (success)
+ {
+ string_appends (tname, &temp);
+ }
+ string_delete(&temp);
+ if (!success)
+ {
+ break;
+ }
+ }
+ else
+ {
+ /* otherwise, value parameter */
+ old_p = *mangled;
+ is_pointer = 0;
+ is_real = 0;
+ is_integral = 0;
+ done = 0;
+ /* temp is initialized in do_type */
+ success = do_type (work, mangled, &temp);
+ if (success)
+ {
+ string_appends (tname, &temp);
+ }
+ string_delete(&temp);
+ if (!success)
+ {
+ break;
+ }
+ string_append (tname, "=");
+ while (*old_p && !done)
+ {
+ switch (*old_p)
+ {
+ case 'P':
+ case 'p':
+ case 'R':
+ done = is_pointer = 1;
+ break;
+ case 'C': /* const */
+ case 'S': /* explicitly signed [char] */
+ case 'U': /* unsigned */
+ case 'V': /* volatile */
+ case 'F': /* function */
+ case 'M': /* member function */
+ case 'O': /* ??? */
+ old_p++;
+ continue;
+ case 'Q': /* qualified name */
+ done = is_integral = 1;
+ break;
+ case 'T': /* remembered type */
+ abort ();
+ break;
+ case 'v': /* void */
+ abort ();
+ break;
+ case 'x': /* long long */
+ case 'l': /* long */
+ case 'i': /* int */
+ case 's': /* short */
+ case 'c': /* char */
+ case 'w': /* wchar_t */
+ done = is_integral = 1;
+ break;
+ case 'r': /* long double */
+ case 'd': /* double */
+ case 'f': /* float */
+ done = is_real = 1;
+ break;
+ default:
+ /* it's probably user defined type, let's assume
+ it's integeral, it seems hard to figure out
+ what it really is */
+ done = is_integral = 1;
+ }
+ }
+ if (is_integral)
+ {
+ if (**mangled == 'm')
+ {
+ string_appendn (tname, "-", 1);
+ (*mangled)++;
+ }
+ while (isdigit (**mangled))
+ {
+ string_appendn (tname, *mangled, 1);
+ (*mangled)++;
+ }
+ }
+ else if (is_real)
+ {
+ if (**mangled == 'm')
+ {
+ string_appendn (tname, "-", 1);
+ (*mangled)++;
+ }
+ while (isdigit (**mangled))
+ {
+ string_appendn (tname, *mangled, 1);
+ (*mangled)++;
+ }
+ if (**mangled == '.') /* fraction */
+ {
+ string_appendn (tname, ".", 1);
+ (*mangled)++;
+ while (isdigit (**mangled))
+ {
+ string_appendn (tname, *mangled, 1);
+ (*mangled)++;
+ }
+ }
+ if (**mangled == 'e') /* exponent */
+ {
+ string_appendn (tname, "e", 1);
+ (*mangled)++;
+ while (isdigit (**mangled))
+ {
+ string_appendn (tname, *mangled, 1);
+ (*mangled)++;
+ }
+ }
+ }
+ else if (is_pointer)
+ {
+ if (!get_count (mangled, &symbol_len))
+ {
+ success = 0;
+ break;
+ }
+ string_appendn (tname, *mangled, symbol_len);
+ *mangled += symbol_len;
+ }
+ }
+ need_comma = 1;
+ }
+ if (tname->p[-1] == '>')
+ string_append (tname, " ");
+ string_append (tname, ">");
+
+/*
+ if (work -> static_type)
+ {
+ string_append (declp, *mangled + 1);
+ *mangled += strlen (*mangled);
+ success = 1;
+ }
+ else
+ {
+ success = demangle_args (work, mangled, declp);
+ }
+ }
+*/
+ return (success);
+}
+
+static int
+arm_pt (work, mangled, n, anchor, args)
+ struct work_stuff *work;
+ CONST char *mangled;
+ int n;
+ CONST char **anchor, **args;
+{
+ /* ARM template? */
+ if (ARM_DEMANGLING && (*anchor = strstr(mangled, "__pt__")))
+ {
+ int len;
+ *args = *anchor + 6;
+ len = consume_count (args);
+ if (*args + len == mangled + n && **args == '_')
+ {
+ ++*args;
+ return 1;
+ }
+ }
+ return 0;
+}
+
+static void
+demangle_arm_pt (work, mangled, n, declp)
+ struct work_stuff *work;
+ CONST char **mangled;
+ int n;
+ string *declp;
+{
+ CONST char *p;
+ CONST char *args;
+ CONST char *e = *mangled + n;
+
+ /* ARM template? */
+ if (arm_pt (work, *mangled, n, &p, &args))
+ {
+ string arg;
+ string_init (&arg);
+ string_appendn (declp, *mangled, p - *mangled);
+ string_append (declp, "<");
+ /* should do error checking here */
+ while (args < e) {
+ string_clear (&arg);
+ do_type (work, &args, &arg);
+ string_appends (declp, &arg);
+ string_append (declp, ",");
+ }
+ string_delete (&arg);
+ --declp->p;
+ string_append (declp, ">");
+ }
+ else
+ {
+ string_appendn (declp, *mangled, n);
+ }
+ *mangled += n;
+}
+
+static int
+demangle_class_name (work, mangled, declp)
+ struct work_stuff *work;
+ CONST char **mangled;
+ string *declp;
+{
+ int n;
+ int success = 0;
+
+ n = consume_count (mangled);
+ if (strlen (*mangled) >= n)
+ {
+ demangle_arm_pt (work, mangled, n, declp);
+ success = 1;
+ }
+
+ return (success);
+}
+
+/*
+
+LOCAL FUNCTION
+
+ demangle_class -- demangle a mangled class sequence
+
+SYNOPSIS
+
+ static int
+ demangle_class (struct work_stuff *work, const char **mangled,
+ strint *declp)
+
+DESCRIPTION
+
+ DECLP points to the buffer into which demangling is being done.
+
+ *MANGLED points to the current token to be demangled. On input,
+ it points to a mangled class (I.E. "3foo", "13verylongclass", etc.)
+ On exit, it points to the next token after the mangled class on
+ success, or the first unconsumed token on failure.
+
+ If the CONSTRUCTOR or DESTRUCTOR flags are set in WORK, then
+ we are demangling a constructor or destructor. In this case
+ we prepend "class::class" or "class::~class" to DECLP.
+
+ Otherwise, we prepend "class::" to the current DECLP.
+
+ Reset the constructor/destructor flags once they have been
+ "consumed". This allows demangle_class to be called later during
+ the same demangling, to do normal class demangling.
+
+ Returns 1 if demangling is successful, 0 otherwise.
+
+*/
+
+static int
+demangle_class (work, mangled, declp)
+ struct work_stuff *work;
+ CONST char **mangled;
+ string *declp;
+{
+ int success = 0;
+ string class_name;
+
+ string_init (&class_name);
+ if (demangle_class_name (work, mangled, &class_name))
+ {
+ if ((work->constructor & 1) || (work->destructor & 1))
+ {
+ string_prepends (declp, &class_name);
+ if (work -> destructor & 1)
+ {
+ string_prepend (declp, "~");
+ work -> destructor -= 1;
+ }
+ else
+ {
+ work -> constructor -= 1;
+ }
+ }
+ string_prepend (declp, "::");
+ string_prepends (declp, &class_name);
+ success = 1;
+ }
+ string_delete (&class_name);
+ return (success);
+}
+
+/*
+
+LOCAL FUNCTION
+
+ demangle_prefix -- consume the mangled name prefix and find signature
+
+SYNOPSIS
+
+ static int
+ demangle_prefix (struct work_stuff *work, const char **mangled,
+ string *declp);
+
+DESCRIPTION
+
+ Consume and demangle the prefix of the mangled name.
+
+ DECLP points to the string buffer into which demangled output is
+ placed. On entry, the buffer is empty. On exit it contains
+ the root function name, the demangled operator name, or in some
+ special cases either nothing or the completely demangled result.
+
+ MANGLED points to the current pointer into the mangled name. As each
+ token of the mangled name is consumed, it is updated. Upon entry
+ the current mangled name pointer points to the first character of
+ the mangled name. Upon exit, it should point to the first character
+ of the signature if demangling was successful, or to the first
+ unconsumed character if demangling of the prefix was unsuccessful.
+
+ Returns 1 on success, 0 otherwise.
+ */
+
+static int
+demangle_prefix (work, mangled, declp)
+ struct work_stuff *work;
+ CONST char **mangled;
+ string *declp;
+{
+ int success = 1;
+ CONST char *scan;
+ int i;
+
+ if (strlen(*mangled) >= 11 && strncmp(*mangled, "_GLOBAL_", 8) == 0)
+ {
+ char *marker = strchr (cplus_markers, (*mangled)[8]);
+ if (marker != NULL && *marker == (*mangled)[10])
+ {
+ if ((*mangled)[9] == 'D')
+ {
+ /* it's a GNU global destructor to be executed at program exit */
+ (*mangled) += 11;
+ work->destructor = 2;
+ }
+ else if ((*mangled)[9] == 'I')
+ {
+ /* it's a GNU global constructor to be executed at program init */
+ (*mangled) += 11;
+ work->constructor = 2;
+ }
+ }
+ }
+ else if (ARM_DEMANGLING && strncmp(*mangled, "__std__", 7) == 0)
+ {
+ /* it's a ARM global destructor to be executed at program exit */
+ (*mangled) += 7;
+ work->destructor = 2;
+ }
+ else if (ARM_DEMANGLING && strncmp(*mangled, "__sti__", 7) == 0)
+ {
+ /* it's a ARM global constructor to be executed at program initial */
+ (*mangled) += 7;
+ work->constructor = 2;
+ }
+
+/* This block of code is a reduction in strength time optimization
+ of:
+ scan = strstr (*mangled, "__"); */
+
+ {
+ scan = *mangled;
+
+ do {
+ scan = strchr (scan, '_');
+ } while (scan != NULL && *++scan != '_');
+
+ if (scan != NULL) --scan;
+ }
+
+ if (scan != NULL)
+ {
+ /* We found a sequence of two or more '_', ensure that we start at
+ the last pair in the sequence. */
+ i = strspn (scan, "_");
+ if (i > 2)
+ {
+ scan += (i - 2);
+ }
+ }
+
+ if (scan == NULL)
+ {
+ success = 0;
+ }
+ else if (work -> static_type)
+ {
+ if (!isdigit (scan[0]) && (scan[0] != 't'))
+ {
+ success = 0;
+ }
+ }
+ else if ((scan == *mangled) &&
+ (isdigit (scan[2]) || (scan[2] == 'Q') || (scan[2] == 't')))
+ {
+ /* The ARM says nothing about the mangling of local variables.
+ But cfront mangles local variables by prepending __<nesting_level>
+ to them. As an extension to ARM demangling we handle this case. */
+ if ((LUCID_DEMANGLING || ARM_DEMANGLING) && isdigit (scan[2]))
+ {
+ *mangled = scan + 2;
+ consume_count (mangled);
+ string_append (declp, *mangled);
+ *mangled += strlen (*mangled);
+ success = 1;
+ }
+ else
+ {
+ /* A GNU style constructor starts with __[0-9Qt]. But cfront uses
+ names like __Q2_3foo3bar for nested type names. So don't accept
+ this style of constructor for cfront demangling. */
+ if (!(LUCID_DEMANGLING || ARM_DEMANGLING))
+ work -> constructor += 1;
+ *mangled = scan + 2;
+ }
+ }
+ else if ((scan == *mangled) && !isdigit (scan[2]) && (scan[2] != 't'))
+ {
+ /* Mangled name starts with "__". Skip over any leading '_' characters,
+ then find the next "__" that separates the prefix from the signature.
+ */
+ if (!(ARM_DEMANGLING || LUCID_DEMANGLING)
+ || (arm_special (work, mangled, declp) == 0))
+ {
+ while (*scan == '_')
+ {
+ scan++;
+ }
+ if ((scan = strstr (scan, "__")) == NULL || (*(scan + 2) == '\0'))
+ {
+ /* No separator (I.E. "__not_mangled"), or empty signature
+ (I.E. "__not_mangled_either__") */
+ success = 0;
+ }
+ else
+ {
+ demangle_function_name (work, mangled, declp, scan);
+ }
+ }
+ }
+ else if (ARM_DEMANGLING && scan[2] == 'p' && scan[3] == 't')
+ {
+ /* Cfront-style parameterized type. Handled later as a signature. */
+ success = 1;
+
+ /* ARM template? */
+ demangle_arm_pt (work, mangled, strlen (*mangled), declp);
+ }
+ else if (*(scan + 2) != '\0')
+ {
+ /* Mangled name does not start with "__" but does have one somewhere
+ in there with non empty stuff after it. Looks like a global
+ function name. */
+ demangle_function_name (work, mangled, declp, scan);
+ }
+ else
+ {
+ /* Doesn't look like a mangled name */
+ success = 0;
+ }
+
+ if (!success && (work->constructor == 2 || work->destructor == 2))
+ {
+ string_append (declp, *mangled);
+ *mangled += strlen (*mangled);
+ success = 1;
+ }
+ return (success);
+}
+
+/*
+
+LOCAL FUNCTION
+
+ gnu_special -- special handling of gnu mangled strings
+
+SYNOPSIS
+
+ static int
+ gnu_special (struct work_stuff *work, const char **mangled,
+ string *declp);
+
+
+DESCRIPTION
+
+ Process some special GNU style mangling forms that don't fit
+ the normal pattern. For example:
+
+ _$_3foo (destructor for class foo)
+ _vt$foo (foo virtual table)
+ _vt$foo$bar (foo::bar virtual table)
+ __vt_foo (foo virtual table, new style with thunks)
+ _3foo$varname (static data member)
+ _Q22rs2tu$vw (static data member)
+ __t6vector1Zii (constructor with template)
+ __thunk_4__$_7ostream (virtual function thunk)
+ */
+
+static int
+gnu_special (work, mangled, declp)
+ struct work_stuff *work;
+ CONST char **mangled;
+ string *declp;
+{
+ int n;
+ int success = 1;
+ CONST char *p;
+
+ if ((*mangled)[0] == '_'
+ && strchr (cplus_markers, (*mangled)[1]) != NULL
+ && (*mangled)[2] == '_')
+ {
+ /* Found a GNU style destructor, get past "_<CPLUS_MARKER>_" */
+ (*mangled) += 3;
+ work -> destructor += 1;
+ }
+ else if ((*mangled)[0] == '_'
+ && (((*mangled)[1] == '_'
+ && (*mangled)[2] == 'v'
+ && (*mangled)[3] == 't'
+ && (*mangled)[4] == '_')
+ || ((*mangled)[1] == 'v'
+ && (*mangled)[2] == 't'
+ && strchr (cplus_markers, (*mangled)[3]) != NULL)))
+ {
+ /* Found a GNU style virtual table, get past "_vt<CPLUS_MARKER>"
+ and create the decl. Note that we consume the entire mangled
+ input string, which means that demangle_signature has no work
+ to do. */
+ if ((*mangled)[2] == 'v')
+ (*mangled) += 5; /* New style, with thunks: "__vt_" */
+ else
+ (*mangled) += 4; /* Old style, no thunks: "_vt<CPLUS_MARKER>" */
+ while (**mangled != '\0')
+ {
+ p = strpbrk (*mangled, cplus_markers);
+ switch (**mangled)
+ {
+ case 'Q':
+ success = demangle_qualified (work, mangled, declp, 0, 1);
+ break;
+ case 't':
+ success = demangle_template (work, mangled, declp, 0);
+ break;
+ default:
+ if (isdigit(*mangled[0]))
+ {
+ n = consume_count(mangled);
+ }
+ else
+ {
+ n = strcspn (*mangled, cplus_markers);
+ }
+ string_appendn (declp, *mangled, n);
+ (*mangled) += n;
+ }
+
+ if (success && ((p == NULL) || (p == *mangled)))
+ {
+ if (p != NULL)
+ {
+ string_append (declp, "::");
+ (*mangled)++;
+ }
+ }
+ else
+ {
+ success = 0;
+ break;
+ }
+ }
+ if (success)
+ string_append (declp, " virtual table");
+ }
+ else if ((*mangled)[0] == '_'
+ && (strchr("0123456789Qt", (*mangled)[1]) != NULL)
+ && (p = strpbrk (*mangled, cplus_markers)) != NULL)
+ {
+ /* static data member, "_3foo$varname" for example */
+ (*mangled)++;
+ switch (**mangled)
+ {
+ case 'Q':
+ success = demangle_qualified (work, mangled, declp, 0, 1);
+ break;
+ case 't':
+ success = demangle_template (work, mangled, declp, 0);
+ break;
+ default:
+ n = consume_count (mangled);
+ string_appendn (declp, *mangled, n);
+ (*mangled) += n;
+ }
+ if (success && (p == *mangled))
+ {
+ /* Consumed everything up to the cplus_marker, append the
+ variable name. */
+ (*mangled)++;
+ string_append (declp, "::");
+ n = strlen (*mangled);
+ string_appendn (declp, *mangled, n);
+ (*mangled) += n;
+ }
+ else
+ {
+ success = 0;
+ }
+ }
+ else if (strncmp (*mangled, "__thunk_", 8) == 0)
+ {
+ int delta = ((*mangled) += 8, consume_count (mangled));
+ char *method = cplus_demangle (++*mangled, work->options);
+ if (method)
+ {
+ char buf[50];
+ sprintf (buf, "virtual function thunk (delta:%d) for ", -delta);
+ string_append (declp, buf);
+ string_append (declp, method);
+ free (method);
+ n = strlen (*mangled);
+ (*mangled) += n;
+ }
+ else
+ {
+ success = 0;
+ }
+ }
+ else
+ {
+ success = 0;
+ }
+ return (success);
+}
+
+/*
+
+LOCAL FUNCTION
+
+ arm_special -- special handling of ARM/lucid mangled strings
+
+SYNOPSIS
+
+ static int
+ arm_special (struct work_stuff *work, const char **mangled,
+ string *declp);
+
+
+DESCRIPTION
+
+ Process some special ARM style mangling forms that don't fit
+ the normal pattern. For example:
+
+ __vtbl__3foo (foo virtual table)
+ __vtbl__3foo__3bar (bar::foo virtual table)
+
+ */
+
+static int
+arm_special (work, mangled, declp)
+ struct work_stuff *work;
+ CONST char **mangled;
+ string *declp;
+{
+ int n;
+ int success = 1;
+ CONST char *scan;
+
+ if (strncmp (*mangled, ARM_VTABLE_STRING, ARM_VTABLE_STRLEN) == 0)
+ {
+ /* Found a ARM style virtual table, get past ARM_VTABLE_STRING
+ and create the decl. Note that we consume the entire mangled
+ input string, which means that demangle_signature has no work
+ to do. */
+ scan = *mangled + ARM_VTABLE_STRLEN;
+ while (*scan != '\0') /* first check it can be demangled */
+ {
+ n = consume_count (&scan);
+ if (n==0)
+ {
+ return (0); /* no good */
+ }
+ scan += n;
+ if (scan[0] == '_' && scan[1] == '_')
+ {
+ scan += 2;
+ }
+ }
+ (*mangled) += ARM_VTABLE_STRLEN;
+ while (**mangled != '\0')
+ {
+ n = consume_count (mangled);
+ string_prependn (declp, *mangled, n);
+ (*mangled) += n;
+ if ((*mangled)[0] == '_' && (*mangled)[1] == '_')
+ {
+ string_prepend (declp, "::");
+ (*mangled) += 2;
+ }
+ }
+ string_append (declp, " virtual table");
+ }
+ else
+ {
+ success = 0;
+ }
+ return (success);
+}
+
+/*
+
+LOCAL FUNCTION
+
+ demangle_qualified -- demangle 'Q' qualified name strings
+
+SYNOPSIS
+
+ static int
+ demangle_qualified (struct work_stuff *, const char *mangled,
+ string *result, int isfuncname, int append);
+
+DESCRIPTION
+
+ Demangle a qualified name, such as "Q25Outer5Inner" which is
+ the mangled form of "Outer::Inner". The demangled output is
+ prepended or appended to the result string according to the
+ state of the append flag.
+
+ If isfuncname is nonzero, then the qualified name we are building
+ is going to be used as a member function name, so if it is a
+ constructor or destructor function, append an appropriate
+ constructor or destructor name. I.E. for the above example,
+ the result for use as a constructor is "Outer::Inner::Inner"
+ and the result for use as a destructor is "Outer::Inner::~Inner".
+
+BUGS
+
+ Numeric conversion is ASCII dependent (FIXME).
+
+ */
+
+static int
+demangle_qualified (work, mangled, result, isfuncname, append)
+ struct work_stuff *work;
+ CONST char **mangled;
+ string *result;
+ int isfuncname;
+ int append;
+{
+ int qualifiers;
+ int namelength;
+ int success = 1;
+ CONST char *p;
+ char num[2];
+ string temp;
+
+ string_init (&temp);
+ switch ((*mangled)[1])
+ {
+ case '_':
+ /* GNU mangled name with more than 9 classes. The count is preceded
+ by an underscore (to distinguish it from the <= 9 case) and followed
+ by an underscore. */
+ p = *mangled + 2;
+ qualifiers = atoi (p);
+ if (!isdigit (*p) || *p == '0')
+ success = 0;
+
+ /* Skip the digits. */
+ while (isdigit (*p))
+ ++p;
+
+ if (*p != '_')
+ success = 0;
+
+ *mangled = p + 1;
+ break;
+
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ /* The count is in a single digit. */
+ num[0] = (*mangled)[1];
+ num[1] = '\0';
+ qualifiers = atoi (num);
+
+ /* If there is an underscore after the digit, skip it. This is
+ said to be for ARM-qualified names, but the ARM makes no
+ mention of such an underscore. Perhaps cfront uses one. */
+ if ((*mangled)[2] == '_')
+ {
+ (*mangled)++;
+ }
+ (*mangled) += 2;
+ break;
+
+ case '0':
+ default:
+ success = 0;
+ }
+
+ if (!success)
+ return success;
+
+ /* Pick off the names and collect them in the temp buffer in the order
+ in which they are found, separated by '::'. */
+
+ while (qualifiers-- > 0)
+ {
+ if (*mangled[0] == 't')
+ {
+ success = demangle_template(work, mangled, &temp, 0);
+ if (!success) break;
+ }
+ else
+ {
+ namelength = consume_count (mangled);
+ if (strlen (*mangled) < namelength)
+ {
+ /* Simple sanity check failed */
+ success = 0;
+ break;
+ }
+ string_appendn (&temp, *mangled, namelength);
+ *mangled += namelength;
+ }
+ if (qualifiers > 0)
+ {
+ string_appendn (&temp, "::", 2);
+ }
+ }
+
+ /* If we are using the result as a function name, we need to append
+ the appropriate '::' separated constructor or destructor name.
+ We do this here because this is the most convenient place, where
+ we already have a pointer to the name and the length of the name. */
+
+ if (isfuncname && (work->constructor & 1 || work->destructor & 1))
+ {
+ string_appendn (&temp, "::", 2);
+ if (work -> destructor & 1)
+ {
+ string_append (&temp, "~");
+ }
+ string_appendn (&temp, (*mangled) - namelength, namelength);
+ }
+
+ /* Now either prepend the temp buffer to the result, or append it,
+ depending upon the state of the append flag. */
+
+ if (append)
+ {
+ string_appends (result, &temp);
+ }
+ else
+ {
+ if (!STRING_EMPTY (result))
+ {
+ string_appendn (&temp, "::", 2);
+ }
+ string_prepends (result, &temp);
+ }
+
+ string_delete (&temp);
+ return (success);
+}
+
+/*
+
+LOCAL FUNCTION
+
+ get_count -- convert an ascii count to integer, consuming tokens
+
+SYNOPSIS
+
+ static int
+ get_count (const char **type, int *count)
+
+DESCRIPTION
+
+ Return 0 if no conversion is performed, 1 if a string is converted.
+*/
+
+static int
+get_count (type, count)
+ CONST char **type;
+ int *count;
+{
+ CONST char *p;
+ int n;
+
+ if (!isdigit (**type))
+ {
+ return (0);
+ }
+ else
+ {
+ *count = **type - '0';
+ (*type)++;
+ if (isdigit (**type))
+ {
+ p = *type;
+ n = *count;
+ do
+ {
+ n *= 10;
+ n += *p - '0';
+ p++;
+ }
+ while (isdigit (*p));
+ if (*p == '_')
+ {
+ *type = p + 1;
+ *count = n;
+ }
+ }
+ }
+ return (1);
+}
+
+/* result will be initialised here; it will be freed on failure */
+
+static int
+do_type (work, mangled, result)
+ struct work_stuff *work;
+ CONST char **mangled;
+ string *result;
+{
+ int n;
+ int done;
+ int success;
+ string decl;
+ CONST char *remembered_type;
+ int constp;
+ int volatilep;
+
+ string_init (&decl);
+ string_init (result);
+
+ done = 0;
+ success = 1;
+ while (success && !done)
+ {
+ int member;
+ switch (**mangled)
+ {
+
+ /* A pointer type */
+ case 'P':
+ case 'p':
+ (*mangled)++;
+ string_prepend (&decl, "*");
+ break;
+
+ /* A reference type */
+ case 'R':
+ (*mangled)++;
+ string_prepend (&decl, "&");
+ break;
+
+ /* An array */
+ case 'A':
+ {
+ CONST char *p = ++(*mangled);
+
+ string_prepend (&decl, "(");
+ string_append (&decl, ")[");
+ /* Copy anything up until the next underscore (the size of the
+ array). */
+ while (**mangled && **mangled != '_')
+ ++(*mangled);
+ if (**mangled == '_')
+ {
+ string_appendn (&decl, p, *mangled - p);
+ string_append (&decl, "]");
+ *mangled += 1;
+ }
+ else
+ success = 0;
+ break;
+ }
+
+ /* A back reference to a previously seen type */
+ case 'T':
+ (*mangled)++;
+ if (!get_count (mangled, &n) || n >= work -> ntypes)
+ {
+ success = 0;
+ }
+ else
+ {
+ remembered_type = work -> typevec[n];
+ mangled = &remembered_type;
+ }
+ break;
+
+ /* A function */
+ case 'F':
+ (*mangled)++;
+ if (!STRING_EMPTY (&decl) && decl.b[0] == '*')
+ {
+ string_prepend (&decl, "(");
+ string_append (&decl, ")");
+ }
+ /* After picking off the function args, we expect to either find the
+ function return type (preceded by an '_') or the end of the
+ string. */
+ if (!demangle_args (work, mangled, &decl)
+ || (**mangled != '_' && **mangled != '\0'))
+ {
+ success = 0;
+ }
+ if (success && (**mangled == '_'))
+ {
+ (*mangled)++;
+ }
+ break;
+
+ case 'M':
+ case 'O':
+ {
+ constp = 0;
+ volatilep = 0;
+
+ member = **mangled == 'M';
+ (*mangled)++;
+ if (!isdigit (**mangled))
+ {
+ success = 0;
+ break;
+ }
+ n = consume_count (mangled);
+ if (strlen (*mangled) < n)
+ {
+ success = 0;
+ break;
+ }
+ string_append (&decl, ")");
+ string_prepend (&decl, "::");
+ string_prependn (&decl, *mangled, n);
+ string_prepend (&decl, "(");
+ *mangled += n;
+ if (member)
+ {
+ if (**mangled == 'C')
+ {
+ (*mangled)++;
+ constp = 1;
+ }
+ if (**mangled == 'V')
+ {
+ (*mangled)++;
+ volatilep = 1;
+ }
+ if (*(*mangled)++ != 'F')
+ {
+ success = 0;
+ break;
+ }
+ }
+ if ((member && !demangle_args (work, mangled, &decl))
+ || **mangled != '_')
+ {
+ success = 0;
+ break;
+ }
+ (*mangled)++;
+ if (! PRINT_ANSI_QUALIFIERS)
+ {
+ break;
+ }
+ if (constp)
+ {
+ APPEND_BLANK (&decl);
+ string_append (&decl, "const");
+ }
+ if (volatilep)
+ {
+ APPEND_BLANK (&decl);
+ string_append (&decl, "volatile");
+ }
+ break;
+ }
+ case 'G':
+ (*mangled)++;
+ break;
+
+ case 'C':
+ (*mangled)++;
+/*
+ if ((*mangled)[1] == 'P')
+ {
+*/
+ if (PRINT_ANSI_QUALIFIERS)
+ {
+ if (!STRING_EMPTY (&decl))
+ {
+ string_prepend (&decl, " ");
+ }
+ string_prepend (&decl, "const");
+ }
+ break;
+/*
+ }
+*/
+
+ /* fall through */
+ default:
+ done = 1;
+ break;
+ }
+ }
+
+ switch (**mangled)
+ {
+ /* A qualified name, such as "Outer::Inner". */
+ case 'Q':
+ success = demangle_qualified (work, mangled, result, 0, 1);
+ break;
+
+ default:
+ success = demangle_fund_type (work, mangled, result);
+ break;
+ }
+
+ if (success)
+ {
+ if (!STRING_EMPTY (&decl))
+ {
+ string_append (result, " ");
+ string_appends (result, &decl);
+ }
+ }
+ else
+ {
+ string_delete (result);
+ }
+ string_delete (&decl);
+ return (success);
+}
+
+/* Given a pointer to a type string that represents a fundamental type
+ argument (int, long, unsigned int, etc) in TYPE, a pointer to the
+ string in which the demangled output is being built in RESULT, and
+ the WORK structure, decode the types and add them to the result.
+
+ For example:
+
+ "Ci" => "const int"
+ "Sl" => "signed long"
+ "CUs" => "const unsigned short"
+
+ */
+
+static int
+demangle_fund_type (work, mangled, result)
+ struct work_stuff *work;
+ CONST char **mangled;
+ string *result;
+{
+ int done = 0;
+ int success = 1;
+
+ /* First pick off any type qualifiers. There can be more than one. */
+
+ while (!done)
+ {
+ switch (**mangled)
+ {
+ case 'C':
+ (*mangled)++;
+ if (PRINT_ANSI_QUALIFIERS)
+ {
+ APPEND_BLANK (result);
+ string_append (result, "const");
+ }
+ break;
+ case 'U':
+ (*mangled)++;
+ APPEND_BLANK (result);
+ string_append (result, "unsigned");
+ break;
+ case 'S': /* signed char only */
+ (*mangled)++;
+ APPEND_BLANK (result);
+ string_append (result, "signed");
+ break;
+ case 'V':
+ (*mangled)++;
+ if (PRINT_ANSI_QUALIFIERS)
+ {
+ APPEND_BLANK (result);
+ string_append (result, "volatile");
+ }
+ break;
+ default:
+ done = 1;
+ break;
+ }
+ }
+
+ /* Now pick off the fundamental type. There can be only one. */
+
+ switch (**mangled)
+ {
+ case '\0':
+ case '_':
+ break;
+ case 'v':
+ (*mangled)++;
+ APPEND_BLANK (result);
+ string_append (result, "void");
+ break;
+ case 'x':
+ (*mangled)++;
+ APPEND_BLANK (result);
+ string_append (result, "long long");
+ break;
+ case 'l':
+ (*mangled)++;
+ APPEND_BLANK (result);
+ string_append (result, "long");
+ break;
+ case 'i':
+ (*mangled)++;
+ APPEND_BLANK (result);
+ string_append (result, "int");
+ break;
+ case 's':
+ (*mangled)++;
+ APPEND_BLANK (result);
+ string_append (result, "short");
+ break;
+ case 'b':
+ (*mangled)++;
+ APPEND_BLANK (result);
+ string_append (result, "bool");
+ break;
+ case 'c':
+ (*mangled)++;
+ APPEND_BLANK (result);
+ string_append (result, "char");
+ break;
+ case 'w':
+ (*mangled)++;
+ APPEND_BLANK (result);
+ string_append (result, "wchar_t");
+ break;
+ case 'r':
+ (*mangled)++;
+ APPEND_BLANK (result);
+ string_append (result, "long double");
+ break;
+ case 'd':
+ (*mangled)++;
+ APPEND_BLANK (result);
+ string_append (result, "double");
+ break;
+ case 'f':
+ (*mangled)++;
+ APPEND_BLANK (result);
+ string_append (result, "float");
+ break;
+ case 'G':
+ (*mangled)++;
+ if (!isdigit (**mangled))
+ {
+ success = 0;
+ break;
+ }
+ /* fall through */
+ /* An explicit type, such as "6mytype" or "7integer" */
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ APPEND_BLANK (result);
+ if (!demangle_class_name (work, mangled, result)) {
+ --result->p;
+ success = 0;
+ }
+ break;
+ case 't':
+ success = demangle_template(work,mangled, result, 0);
+ break;
+ default:
+ success = 0;
+ break;
+ }
+
+ return (success);
+}
+
+/* `result' will be initialized in do_type; it will be freed on failure */
+
+static int
+do_arg (work, mangled, result)
+ struct work_stuff *work;
+ CONST char **mangled;
+ string *result;
+{
+ CONST char *start = *mangled;
+
+ if (!do_type (work, mangled, result))
+ {
+ return (0);
+ }
+ else
+ {
+ remember_type (work, start, *mangled - start);
+ return (1);
+ }
+}
+
+static void
+remember_type (work, start, len)
+ struct work_stuff *work;
+ CONST char *start;
+ int len;
+{
+ char *tem;
+
+ if (work -> ntypes >= work -> typevec_size)
+ {
+ if (work -> typevec_size == 0)
+ {
+ work -> typevec_size = 3;
+ work -> typevec =
+ (char **) xmalloc (sizeof (char *) * work -> typevec_size);
+ }
+ else
+ {
+ work -> typevec_size *= 2;
+ work -> typevec =
+ (char **) xrealloc ((char *)work -> typevec,
+ sizeof (char *) * work -> typevec_size);
+ }
+ }
+ tem = xmalloc (len + 1);
+ memcpy (tem, start, len);
+ tem[len] = '\0';
+ work -> typevec[work -> ntypes++] = tem;
+}
+
+/* Forget the remembered types, but not the type vector itself. */
+
+static void
+forget_types (work)
+ struct work_stuff *work;
+{
+ int i;
+
+ while (work -> ntypes > 0)
+ {
+ i = --(work -> ntypes);
+ if (work -> typevec[i] != NULL)
+ {
+ free (work -> typevec[i]);
+ work -> typevec[i] = NULL;
+ }
+ }
+}
+
+/* Process the argument list part of the signature, after any class spec
+ has been consumed, as well as the first 'F' character (if any). For
+ example:
+
+ "__als__3fooRT0" => process "RT0"
+ "complexfunc5__FPFPc_PFl_i" => process "PFPc_PFl_i"
+
+ DECLP must be already initialised, usually non-empty. It won't be freed
+ on failure.
+
+ Note that g++ differs significantly from ARM and lucid style mangling
+ with regards to references to previously seen types. For example, given
+ the source fragment:
+
+ class foo {
+ public:
+ foo::foo (int, foo &ia, int, foo &ib, int, foo &ic);
+ };
+
+ foo::foo (int, foo &ia, int, foo &ib, int, foo &ic) { ia = ib = ic; }
+ void foo (int, foo &ia, int, foo &ib, int, foo &ic) { ia = ib = ic; }
+
+ g++ produces the names:
+
+ __3fooiRT0iT2iT2
+ foo__FiR3fooiT1iT1
+
+ while lcc (and presumably other ARM style compilers as well) produces:
+
+ foo__FiR3fooT1T2T1T2
+ __ct__3fooFiR3fooT1T2T1T2
+
+ Note that g++ bases it's type numbers starting at zero and counts all
+ previously seen types, while lucid/ARM bases it's type numbers starting
+ at one and only considers types after it has seen the 'F' character
+ indicating the start of the function args. For lucid/ARM style, we
+ account for this difference by discarding any previously seen types when
+ we see the 'F' character, and subtracting one from the type number
+ reference.
+
+ */
+
+static int
+demangle_args (work, mangled, declp)
+ struct work_stuff *work;
+ CONST char **mangled;
+ string *declp;
+{
+ string arg;
+ int need_comma = 0;
+ int r;
+ int t;
+ CONST char *tem;
+ char temptype;
+
+ if (PRINT_ARG_TYPES)
+ {
+ string_append (declp, "(");
+ if (**mangled == '\0')
+ {
+ string_append (declp, "void");
+ }
+ }
+
+ while (**mangled != '_' && **mangled != '\0' && **mangled != 'e')
+ {
+ if ((**mangled == 'N') || (**mangled == 'T'))
+ {
+ temptype = *(*mangled)++;
+
+ if (temptype == 'N')
+ {
+ if (!get_count (mangled, &r))
+ {
+ return (0);
+ }
+ }
+ else
+ {
+ r = 1;
+ }
+ if (!get_count (mangled, &t))
+ {
+ return (0);
+ }
+ if (LUCID_DEMANGLING || ARM_DEMANGLING)
+ {
+ t--;
+ }
+ /* Validate the type index. Protect against illegal indices from
+ malformed type strings. */
+ if ((t < 0) || (t >= work -> ntypes))
+ {
+ return (0);
+ }
+ while (--r >= 0)
+ {
+ tem = work -> typevec[t];
+ if (need_comma && PRINT_ARG_TYPES)
+ {
+ string_append (declp, ", ");
+ }
+ if (!do_arg (work, &tem, &arg))
+ {
+ return (0);
+ }
+ if (PRINT_ARG_TYPES)
+ {
+ string_appends (declp, &arg);
+ }
+ string_delete (&arg);
+ need_comma = 1;
+ }
+ }
+ else
+ {
+ if (need_comma & PRINT_ARG_TYPES)
+ {
+ string_append (declp, ", ");
+ }
+ if (!do_arg (work, mangled, &arg))
+ {
+ return (0);
+ }
+ if (PRINT_ARG_TYPES)
+ {
+ string_appends (declp, &arg);
+ }
+ string_delete (&arg);
+ need_comma = 1;
+ }
+ }
+
+ if (**mangled == 'e')
+ {
+ (*mangled)++;
+ if (PRINT_ARG_TYPES)
+ {
+ if (need_comma)
+ {
+ string_append (declp, ",");
+ }
+ string_append (declp, "...");
+ }
+ }
+
+ if (PRINT_ARG_TYPES)
+ {
+ string_append (declp, ")");
+ }
+ return (1);
+}
+
+static void
+demangle_function_name (work, mangled, declp, scan)
+ struct work_stuff *work;
+ CONST char **mangled;
+ string *declp;
+ CONST char *scan;
+{
+ int i;
+ int len;
+ string type;
+ CONST char *tem;
+
+ string_appendn (declp, (*mangled), scan - (*mangled));
+ string_need (declp, 1);
+ *(declp -> p) = '\0';
+
+ /* Consume the function name, including the "__" separating the name
+ from the signature. We are guaranteed that SCAN points to the
+ separator. */
+
+ (*mangled) = scan + 2;
+
+ if (LUCID_DEMANGLING || ARM_DEMANGLING)
+ {
+
+ /* See if we have an ARM style constructor or destructor operator.
+ If so, then just record it, clear the decl, and return.
+ We can't build the actual constructor/destructor decl until later,
+ when we recover the class name from the signature. */
+
+ if (strcmp (declp -> b, "__ct") == 0)
+ {
+ work -> constructor += 1;
+ string_clear (declp);
+ return;
+ }
+ else if (strcmp (declp -> b, "__dt") == 0)
+ {
+ work -> destructor += 1;
+ string_clear (declp);
+ return;
+ }
+ }
+
+ if (declp->p - declp->b >= 3
+ && declp->b[0] == 'o'
+ && declp->b[1] == 'p'
+ && strchr (cplus_markers, declp->b[2]) != NULL)
+ {
+ /* see if it's an assignment expression */
+ if (declp->p - declp->b >= 10 /* op$assign_ */
+ && memcmp (declp->b + 3, "assign_", 7) == 0)
+ {
+ for (i = 0; i < sizeof (optable) / sizeof (optable[0]); i++)
+ {
+ len = declp->p - declp->b - 10;
+ if (strlen (optable[i].in) == len
+ && memcmp (optable[i].in, declp->b + 10, len) == 0)
+ {
+ string_clear (declp);
+ string_append (declp, "operator");
+ string_append (declp, optable[i].out);
+ string_append (declp, "=");
+ break;
+ }
+ }
+ }
+ else
+ {
+ for (i = 0; i < sizeof (optable) / sizeof (optable[0]); i++)
+ {
+ int len = declp->p - declp->b - 3;
+ if (strlen (optable[i].in) == len
+ && memcmp (optable[i].in, declp->b + 3, len) == 0)
+ {
+ string_clear (declp);
+ string_append (declp, "operator");
+ string_append (declp, optable[i].out);
+ break;
+ }
+ }
+ }
+ }
+ else if (declp->p - declp->b >= 5 && memcmp (declp->b, "type", 4) == 0
+ && strchr (cplus_markers, declp->b[4]) != NULL)
+ {
+ /* type conversion operator */
+ tem = declp->b + 5;
+ if (do_type (work, &tem, &type))
+ {
+ string_clear (declp);
+ string_append (declp, "operator ");
+ string_appends (declp, &type);
+ string_delete (&type);
+ }
+ }
+ else if (declp->b[0] == '_' && declp->b[1] == '_'
+ && declp->b[2] == 'o' && declp->b[3] == 'p')
+ {
+ /* ANSI. */
+ /* type conversion operator. */
+ tem = declp->b + 4;
+ if (do_type (work, &tem, &type))
+ {
+ string_clear (declp);
+ string_append (declp, "operator ");
+ string_appends (declp, &type);
+ string_delete (&type);
+ }
+ }
+ else if (declp->b[0] == '_' && declp->b[1] == '_'
+ && declp->b[2] >= 'a' && declp->b[2] <= 'z'
+ && declp->b[3] >= 'a' && declp->b[3] <= 'z')
+ {
+ if (declp->b[4] == '\0')
+ {
+ /* Operator. */
+ for (i = 0; i < sizeof (optable) / sizeof (optable[0]); i++)
+ {
+ if (strlen (optable[i].in) == 2
+ && memcmp (optable[i].in, declp->b + 2, 2) == 0)
+ {
+ string_clear (declp);
+ string_append (declp, "operator");
+ string_append (declp, optable[i].out);
+ break;
+ }
+ }
+ }
+ else
+ {
+ if (declp->b[2] == 'a' && declp->b[5] == '\0')
+ {
+ /* Assignment. */
+ for (i = 0; i < sizeof (optable) / sizeof (optable[0]); i++)
+ {
+ if (strlen (optable[i].in) == 3
+ && memcmp (optable[i].in, declp->b + 2, 3) == 0)
+ {
+ string_clear (declp);
+ string_append (declp, "operator");
+ string_append (declp, optable[i].out);
+ break;
+ }
+ }
+ }
+ }
+ }
+}
+
+/* a mini string-handling package */
+
+static void
+string_need (s, n)
+ string *s;
+ int n;
+{
+ int tem;
+
+ if (s->b == NULL)
+ {
+ if (n < 32)
+ {
+ n = 32;
+ }
+ s->p = s->b = xmalloc (n);
+ s->e = s->b + n;
+ }
+ else if (s->e - s->p < n)
+ {
+ tem = s->p - s->b;
+ n += tem;
+ n *= 2;
+ s->b = xrealloc (s->b, n);
+ s->p = s->b + tem;
+ s->e = s->b + n;
+ }
+}
+
+static void
+string_delete (s)
+ string *s;
+{
+ if (s->b != NULL)
+ {
+ free (s->b);
+ s->b = s->e = s->p = NULL;
+ }
+}
+
+static void
+string_init (s)
+ string *s;
+{
+ s->b = s->p = s->e = NULL;
+}
+
+static void
+string_clear (s)
+ string *s;
+{
+ s->p = s->b;
+}
+
+#if 0
+
+static int
+string_empty (s)
+ string *s;
+{
+ return (s->b == s->p);
+}
+
+#endif
+
+static void
+string_append (p, s)
+ string *p;
+ CONST char *s;
+{
+ int n;
+ if (s == NULL || *s == '\0')
+ return;
+ n = strlen (s);
+ string_need (p, n);
+ memcpy (p->p, s, n);
+ p->p += n;
+}
+
+static void
+string_appends (p, s)
+ string *p, *s;
+{
+ int n;
+
+ if (s->b != s->p)
+ {
+ n = s->p - s->b;
+ string_need (p, n);
+ memcpy (p->p, s->b, n);
+ p->p += n;
+ }
+}
+
+static void
+string_appendn (p, s, n)
+ string *p;
+ CONST char *s;
+ int n;
+{
+ if (n != 0)
+ {
+ string_need (p, n);
+ memcpy (p->p, s, n);
+ p->p += n;
+ }
+}
+
+static void
+string_prepend (p, s)
+ string *p;
+ CONST char *s;
+{
+ if (s != NULL && *s != '\0')
+ {
+ string_prependn (p, s, strlen (s));
+ }
+}
+
+static void
+string_prepends (p, s)
+ string *p, *s;
+{
+ if (s->b != s->p)
+ {
+ string_prependn (p, s->b, s->p - s->b);
+ }
+}
+
+static void
+string_prependn (p, s, n)
+ string *p;
+ CONST char *s;
+ int n;
+{
+ char *q;
+
+ if (n != 0)
+ {
+ string_need (p, n);
+ for (q = p->p - 1; q >= p->b; q--)
+ {
+ q[n] = q[0];
+ }
+ memcpy (p->b, s, n);
+ p->p += n;
+ }
+}
+
+/* To generate a standalone demangler program for testing purposes,
+ just compile and link this file with -DMAIN and libiberty.a. When
+ run, it demangles each command line arg, or each stdin string, and
+ prints the result on stdout. */
+
+#ifdef MAIN
+
+static void
+demangle_it (mangled_name)
+ char *mangled_name;
+{
+ char *result;
+
+ result = cplus_demangle (mangled_name, DMGL_PARAMS | DMGL_ANSI);
+ if (result == NULL)
+ {
+ printf ("%s\n", mangled_name);
+ }
+ else
+ {
+ printf ("%s\n", result);
+ free (result);
+ }
+}
+
+#include "getopt.h"
+
+static char *program_name;
+extern char *program_version;
+
+static void
+usage (stream, status)
+ FILE *stream;
+ int status;
+{
+ fprintf (stream, "\
+Usage: %s [-_] [-n] [-s {gnu,lucid,arm}] [--strip-underscores]\n\
+ [--no-strip-underscores] [--format={gnu,lucid,arm}]\n\
+ [--help] [--version] [arg...]\n",
+ program_name);
+ exit (status);
+}
+
+#define MBUF_SIZE 512
+char mbuffer[MBUF_SIZE];
+
+/* Defined in the automatically-generated ../binutils/underscore.c. */
+extern int prepends_underscore;
+
+int strip_underscore = 0;
+
+static struct option long_options[] = {
+ {"strip-underscores", no_argument, 0, '_'},
+ {"format", required_argument, 0, 's'},
+ {"help", no_argument, 0, 'h'},
+ {"no-strip-underscores", no_argument, 0, 'n'},
+ {"version", no_argument, 0, 'v'},
+ {0, no_argument, 0, 0}
+};
+
+int
+main (argc, argv)
+ int argc;
+ char **argv;
+{
+ char *result;
+ int c;
+
+ program_name = argv[0];
+ xmalloc_set_program_name (program_name);
+
+ strip_underscore = prepends_underscore;
+
+ while ((c = getopt_long (argc, argv, "_ns:", long_options, (int *) 0)) != EOF)
+ {
+ switch (c)
+ {
+ case '?':
+ usage (stderr, 1);
+ break;
+ case 'h':
+ usage (stdout, 0);
+ case 'n':
+ strip_underscore = 0;
+ break;
+ case 'v':
+ printf ("GNU %s version %s\n", program_name, program_version);
+ exit (0);
+ case '_':
+ strip_underscore = 1;
+ break;
+ case 's':
+ if (strcmp (optarg, "gnu") == 0)
+ {
+ current_demangling_style = gnu_demangling;
+ }
+ else if (strcmp (optarg, "lucid") == 0)
+ {
+ current_demangling_style = lucid_demangling;
+ }
+ else if (strcmp (optarg, "arm") == 0)
+ {
+ current_demangling_style = arm_demangling;
+ }
+ else
+ {
+ fprintf (stderr, "%s: unknown demangling style `%s'\n",
+ program_name, optarg);
+ exit (1);
+ }
+ break;
+ }
+ }
+
+ if (optind < argc)
+ {
+ for ( ; optind < argc; optind++)
+ {
+ demangle_it (argv[optind]);
+ }
+ }
+ else
+ {
+ for (;;)
+ {
+ int i = 0;
+ c = getchar ();
+ /* Try to read a label. */
+ while (c != EOF && (isalnum(c) || c == '_' || c == '$' || c == '.'))
+ {
+ if (i >= MBUF_SIZE-1)
+ break;
+ mbuffer[i++] = c;
+ c = getchar ();
+ }
+ if (i > 0)
+ {
+ int skip_first = strip_underscore && i > 1 && mbuffer[0] == '_';
+ mbuffer[i] = 0;
+
+ result = cplus_demangle (mbuffer+skip_first,
+ DMGL_PARAMS | DMGL_ANSI);
+ if (result)
+ {
+ fputs (result, stdout);
+ free (result);
+ }
+ else
+ fputs (mbuffer + skip_first, stdout);
+ }
+ if (c == EOF)
+ break;
+ putchar (c);
+ }
+ }
+
+ exit (0);
+}
+
+#endif /* main */
diff --git a/gnu/usr.bin/gdb/libiberty/fdmatch.c b/gnu/usr.bin/gdb/libiberty/fdmatch.c
new file mode 100644
index 0000000..3a0218a
--- /dev/null
+++ b/gnu/usr.bin/gdb/libiberty/fdmatch.c
@@ -0,0 +1,73 @@
+/* Compare two open file descriptors to see if they refer to the same file.
+ Copyright (C) 1991 Free Software Foundation, Inc.
+
+This file is part of the libiberty library.
+Libiberty is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public
+License as published by the Free Software Foundation; either
+version 2 of the License, or (at your option) any later version.
+
+Libiberty is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with libiberty; see the file COPYING.LIB. If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA. */
+
+
+/*
+
+NAME
+
+ fdmatch -- see if two file descriptors refer to same file
+
+SYNOPSIS
+
+ int fdmatch (int fd1, int fd2)
+
+DESCRIPTION
+
+ Check to see if two open file descriptors refer to the same file.
+ This is useful, for example, when we have an open file descriptor
+ for an unnamed file, and the name of a file that we believe to
+ correspond to that fd. This can happen when we are exec'd with
+ an already open file (stdout for example) or from the SVR4 /proc
+ calls that return open file descriptors for mapped address spaces.
+ All we have to do is open the file by name and check the two file
+ descriptors for a match, which is done by comparing major&minor
+ device numbers and inode numbers.
+
+BUGS
+
+ (FIXME: does this work for networks?)
+ It works for NFS, which assigns a device number to each mount.
+
+*/
+
+#include "ansidecl.h"
+#include "libiberty.h"
+#include <sys/types.h>
+#include <sys/stat.h>
+
+int fdmatch (fd1, fd2)
+ int fd1;
+ int fd2;
+{
+ struct stat sbuf1;
+ struct stat sbuf2;
+
+ if ((fstat (fd1, &sbuf1) == 0) &&
+ (fstat (fd2, &sbuf2) == 0) &&
+ (sbuf1.st_dev == sbuf2.st_dev) &&
+ (sbuf1.st_ino == sbuf2.st_ino))
+ {
+ return (1);
+ }
+ else
+ {
+ return (0);
+ }
+}
diff --git a/gnu/usr.bin/gdb/libiberty/getopt.c b/gnu/usr.bin/gdb/libiberty/getopt.c
new file mode 100644
index 0000000..671553d
--- /dev/null
+++ b/gnu/usr.bin/gdb/libiberty/getopt.c
@@ -0,0 +1,747 @@
+/* Getopt for GNU.
+ NOTE: getopt is now part of the C library, so if you don't know what
+ "Keep this file name-space clean" means, talk to roland@gnu.ai.mit.edu
+ before changing it!
+
+ Copyright (C) 1987, 88, 89, 90, 91, 92, 93, 94
+ Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License
+ as published by the Free Software Foundation; either version 2, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* This tells Alpha OSF/1 not to define a getopt prototype in <stdio.h>.
+ Ditto for AIX 3.2 and <stdlib.h>. */
+#ifndef _NO_PROTO
+#define _NO_PROTO
+#endif
+
+#ifdef HAVE_CONFIG_H
+#if defined (emacs) || defined (CONFIG_BROKETS)
+/* We use <config.h> instead of "config.h" so that a compilation
+ using -I. -I$srcdir will use ./config.h rather than $srcdir/config.h
+ (which it would do because it found this file in $srcdir). */
+#include <config.h>
+#else
+#include "config.h"
+#endif
+#endif
+
+#ifndef __STDC__
+/* This is a separate conditional since some stdc systems
+ reject `defined (const)'. */
+#ifndef const
+#define const
+#endif
+#endif
+
+#include <stdio.h>
+
+/* Comment out all this code if we are using the GNU C Library, and are not
+ actually compiling the library itself. This code is part of the GNU C
+ Library, but also included in many other GNU distributions. Compiling
+ and linking in this code is a waste when using the GNU C library
+ (especially if it is a shared library). Rather than having every GNU
+ program understand `configure --with-gnu-libc' and omit the object files,
+ it is simpler to just do this in the source for each such file. */
+
+#if defined (_LIBC) || !defined (__GNU_LIBRARY__)
+
+
+/* This needs to come after some library #include
+ to get __GNU_LIBRARY__ defined. */
+#ifdef __GNU_LIBRARY__
+/* Don't include stdlib.h for non-GNU C libraries because some of them
+ contain conflicting prototypes for getopt. */
+#include <stdlib.h>
+#endif /* GNU C library. */
+
+/* This version of `getopt' appears to the caller like standard Unix `getopt'
+ but it behaves differently for the user, since it allows the user
+ to intersperse the options with the other arguments.
+
+ As `getopt' works, it permutes the elements of ARGV so that,
+ when it is done, all the options precede everything else. Thus
+ all application programs are extended to handle flexible argument order.
+
+ Setting the environment variable POSIXLY_CORRECT disables permutation.
+ Then the behavior is completely standard.
+
+ GNU application programs can use a third alternative mode in which
+ they can distinguish the relative order of options and other arguments. */
+
+#include "getopt.h"
+
+/* For communication from `getopt' to the caller.
+ When `getopt' finds an option that takes an argument,
+ the argument value is returned here.
+ Also, when `ordering' is RETURN_IN_ORDER,
+ each non-option ARGV-element is returned here. */
+
+char *optarg = NULL;
+
+/* Index in ARGV of the next element to be scanned.
+ This is used for communication to and from the caller
+ and for communication between successive calls to `getopt'.
+
+ On entry to `getopt', zero means this is the first call; initialize.
+
+ When `getopt' returns EOF, this is the index of the first of the
+ non-option elements that the caller should itself scan.
+
+ Otherwise, `optind' communicates from one call to the next
+ how much of ARGV has been scanned so far. */
+
+/* XXX 1003.2 says this must be 1 before any call. */
+int optind = 0;
+
+/* The next char to be scanned in the option-element
+ in which the last option character we returned was found.
+ This allows us to pick up the scan where we left off.
+
+ If this is zero, or a null string, it means resume the scan
+ by advancing to the next ARGV-element. */
+
+static char *nextchar;
+
+/* Callers store zero here to inhibit the error message
+ for unrecognized options. */
+
+int opterr = 1;
+
+/* Set to an option character which was unrecognized.
+ This must be initialized on some systems to avoid linking in the
+ system's own getopt implementation. */
+
+int optopt = '?';
+
+/* Describe how to deal with options that follow non-option ARGV-elements.
+
+ If the caller did not specify anything,
+ the default is REQUIRE_ORDER if the environment variable
+ POSIXLY_CORRECT is defined, PERMUTE otherwise.
+
+ REQUIRE_ORDER means don't recognize them as options;
+ stop option processing when the first non-option is seen.
+ This is what Unix does.
+ This mode of operation is selected by either setting the environment
+ variable POSIXLY_CORRECT, or using `+' as the first character
+ of the list of option characters.
+
+ PERMUTE is the default. We permute the contents of ARGV as we scan,
+ so that eventually all the non-options are at the end. This allows options
+ to be given in any order, even with programs that were not written to
+ expect this.
+
+ RETURN_IN_ORDER is an option available to programs that were written
+ to expect options and other ARGV-elements in any order and that care about
+ the ordering of the two. We describe each non-option ARGV-element
+ as if it were the argument of an option with character code 1.
+ Using `-' as the first character of the list of option characters
+ selects this mode of operation.
+
+ The special argument `--' forces an end of option-scanning regardless
+ of the value of `ordering'. In the case of RETURN_IN_ORDER, only
+ `--' can cause `getopt' to return EOF with `optind' != ARGC. */
+
+static enum
+{
+ REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER
+} ordering;
+
+#ifdef __GNU_LIBRARY__
+/* We want to avoid inclusion of string.h with non-GNU libraries
+ because there are many ways it can cause trouble.
+ On some systems, it contains special magic macros that don't work
+ in GCC. */
+#include <string.h>
+#define my_index strchr
+#else
+
+/* Avoid depending on library functions or files
+ whose names are inconsistent. */
+
+char *getenv ();
+
+static char *
+my_index (str, chr)
+ const char *str;
+ int chr;
+{
+ while (*str)
+ {
+ if (*str == chr)
+ return (char *) str;
+ str++;
+ }
+ return 0;
+}
+
+/* If using GCC, we can safely declare strlen this way.
+ If not using GCC, it is ok not to declare it. */
+#ifdef __GNUC__
+/* Note that Motorola Delta 68k R3V7 comes with GCC but not stddef.h.
+ That was relevant to code that was here before. */
+#ifndef __STDC__
+/* gcc with -traditional declares the built-in strlen to return int,
+ and has done so at least since version 2.4.5. -- rms. */
+extern int strlen (const char *);
+#endif /* not __STDC__ */
+#endif /* __GNUC__ */
+
+#endif /* not __GNU_LIBRARY__ */
+
+/* Handle permutation of arguments. */
+
+/* Describe the part of ARGV that contains non-options that have
+ been skipped. `first_nonopt' is the index in ARGV of the first of them;
+ `last_nonopt' is the index after the last of them. */
+
+static int first_nonopt;
+static int last_nonopt;
+
+/* Exchange two adjacent subsequences of ARGV.
+ One subsequence is elements [first_nonopt,last_nonopt)
+ which contains all the non-options that have been skipped so far.
+ The other is elements [last_nonopt,optind), which contains all
+ the options processed since those non-options were skipped.
+
+ `first_nonopt' and `last_nonopt' are relocated so that they describe
+ the new indices of the non-options in ARGV after they are moved. */
+
+static void
+exchange (argv)
+ char **argv;
+{
+ int bottom = first_nonopt;
+ int middle = last_nonopt;
+ int top = optind;
+ char *tem;
+
+ /* Exchange the shorter segment with the far end of the longer segment.
+ That puts the shorter segment into the right place.
+ It leaves the longer segment in the right place overall,
+ but it consists of two parts that need to be swapped next. */
+
+ while (top > middle && middle > bottom)
+ {
+ if (top - middle > middle - bottom)
+ {
+ /* Bottom segment is the short one. */
+ int len = middle - bottom;
+ register int i;
+
+ /* Swap it with the top part of the top segment. */
+ for (i = 0; i < len; i++)
+ {
+ tem = argv[bottom + i];
+ argv[bottom + i] = argv[top - (middle - bottom) + i];
+ argv[top - (middle - bottom) + i] = tem;
+ }
+ /* Exclude the moved bottom segment from further swapping. */
+ top -= len;
+ }
+ else
+ {
+ /* Top segment is the short one. */
+ int len = top - middle;
+ register int i;
+
+ /* Swap it with the bottom part of the bottom segment. */
+ for (i = 0; i < len; i++)
+ {
+ tem = argv[bottom + i];
+ argv[bottom + i] = argv[middle + i];
+ argv[middle + i] = tem;
+ }
+ /* Exclude the moved top segment from further swapping. */
+ bottom += len;
+ }
+ }
+
+ /* Update records for the slots the non-options now occupy. */
+
+ first_nonopt += (optind - last_nonopt);
+ last_nonopt = optind;
+}
+
+/* Initialize the internal data when the first call is made. */
+
+static const char *
+_getopt_initialize (optstring)
+ const char *optstring;
+{
+ /* Start processing options with ARGV-element 1 (since ARGV-element 0
+ is the program name); the sequence of previously skipped
+ non-option ARGV-elements is empty. */
+
+ first_nonopt = last_nonopt = optind = 1;
+
+ nextchar = NULL;
+
+ /* Determine how to handle the ordering of options and nonoptions. */
+
+ if (optstring[0] == '-')
+ {
+ ordering = RETURN_IN_ORDER;
+ ++optstring;
+ }
+ else if (optstring[0] == '+')
+ {
+ ordering = REQUIRE_ORDER;
+ ++optstring;
+ }
+ else if (getenv ("POSIXLY_CORRECT") != NULL)
+ ordering = REQUIRE_ORDER;
+ else
+ ordering = PERMUTE;
+
+ return optstring;
+}
+
+/* Scan elements of ARGV (whose length is ARGC) for option characters
+ given in OPTSTRING.
+
+ If an element of ARGV starts with '-', and is not exactly "-" or "--",
+ then it is an option element. The characters of this element
+ (aside from the initial '-') are option characters. If `getopt'
+ is called repeatedly, it returns successively each of the option characters
+ from each of the option elements.
+
+ If `getopt' finds another option character, it returns that character,
+ updating `optind' and `nextchar' so that the next call to `getopt' can
+ resume the scan with the following option character or ARGV-element.
+
+ If there are no more option characters, `getopt' returns `EOF'.
+ Then `optind' is the index in ARGV of the first ARGV-element
+ that is not an option. (The ARGV-elements have been permuted
+ so that those that are not options now come last.)
+
+ OPTSTRING is a string containing the legitimate option characters.
+ If an option character is seen that is not listed in OPTSTRING,
+ return '?' after printing an error message. If you set `opterr' to
+ zero, the error message is suppressed but we still return '?'.
+
+ If a char in OPTSTRING is followed by a colon, that means it wants an arg,
+ so the following text in the same ARGV-element, or the text of the following
+ ARGV-element, is returned in `optarg'. Two colons mean an option that
+ wants an optional arg; if there is text in the current ARGV-element,
+ it is returned in `optarg', otherwise `optarg' is set to zero.
+
+ If OPTSTRING starts with `-' or `+', it requests different methods of
+ handling the non-option ARGV-elements.
+ See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above.
+
+ Long-named options begin with `--' instead of `-'.
+ Their names may be abbreviated as long as the abbreviation is unique
+ or is an exact match for some defined option. If they have an
+ argument, it follows the option name in the same ARGV-element, separated
+ from the option name by a `=', or else the in next ARGV-element.
+ When `getopt' finds a long-named option, it returns 0 if that option's
+ `flag' field is nonzero, the value of the option's `val' field
+ if the `flag' field is zero.
+
+ The elements of ARGV aren't really const, because we permute them.
+ But we pretend they're const in the prototype to be compatible
+ with other systems.
+
+ LONGOPTS is a vector of `struct option' terminated by an
+ element containing a name which is zero.
+
+ LONGIND returns the index in LONGOPT of the long-named option found.
+ It is only valid when a long-named option has been found by the most
+ recent call.
+
+ If LONG_ONLY is nonzero, '-' as well as '--' can introduce
+ long-named options. */
+
+int
+_getopt_internal (argc, argv, optstring, longopts, longind, long_only)
+ int argc;
+ char *const *argv;
+ const char *optstring;
+ const struct option *longopts;
+ int *longind;
+ int long_only;
+{
+ optarg = NULL;
+
+ if (optind == 0)
+ optstring = _getopt_initialize (optstring);
+
+ if (nextchar == NULL || *nextchar == '\0')
+ {
+ /* Advance to the next ARGV-element. */
+
+ if (ordering == PERMUTE)
+ {
+ /* If we have just processed some options following some non-options,
+ exchange them so that the options come first. */
+
+ if (first_nonopt != last_nonopt && last_nonopt != optind)
+ exchange ((char **) argv);
+ else if (last_nonopt != optind)
+ first_nonopt = optind;
+
+ /* Skip any additional non-options
+ and extend the range of non-options previously skipped. */
+
+ while (optind < argc
+ && (argv[optind][0] != '-' || argv[optind][1] == '\0'))
+ optind++;
+ last_nonopt = optind;
+ }
+
+ /* The special ARGV-element `--' means premature end of options.
+ Skip it like a null option,
+ then exchange with previous non-options as if it were an option,
+ then skip everything else like a non-option. */
+
+ if (optind != argc && !strcmp (argv[optind], "--"))
+ {
+ optind++;
+
+ if (first_nonopt != last_nonopt && last_nonopt != optind)
+ exchange ((char **) argv);
+ else if (first_nonopt == last_nonopt)
+ first_nonopt = optind;
+ last_nonopt = argc;
+
+ optind = argc;
+ }
+
+ /* If we have done all the ARGV-elements, stop the scan
+ and back over any non-options that we skipped and permuted. */
+
+ if (optind == argc)
+ {
+ /* Set the next-arg-index to point at the non-options
+ that we previously skipped, so the caller will digest them. */
+ if (first_nonopt != last_nonopt)
+ optind = first_nonopt;
+ return EOF;
+ }
+
+ /* If we have come to a non-option and did not permute it,
+ either stop the scan or describe it to the caller and pass it by. */
+
+ if ((argv[optind][0] != '-' || argv[optind][1] == '\0'))
+ {
+ if (ordering == REQUIRE_ORDER)
+ return EOF;
+ optarg = argv[optind++];
+ return 1;
+ }
+
+ /* We have found another option-ARGV-element.
+ Skip the initial punctuation. */
+
+ nextchar = (argv[optind] + 1
+ + (longopts != NULL && argv[optind][1] == '-'));
+ }
+
+ /* Decode the current option-ARGV-element. */
+
+ /* Check whether the ARGV-element is a long option.
+
+ If long_only and the ARGV-element has the form "-f", where f is
+ a valid short option, don't consider it an abbreviated form of
+ a long option that starts with f. Otherwise there would be no
+ way to give the -f short option.
+
+ On the other hand, if there's a long option "fubar" and
+ the ARGV-element is "-fu", do consider that an abbreviation of
+ the long option, just like "--fu", and not "-f" with arg "u".
+
+ This distinction seems to be the most useful approach. */
+
+ if (longopts != NULL
+ && (argv[optind][1] == '-'
+ || (long_only && (argv[optind][2] || !my_index (optstring, argv[optind][1])))))
+ {
+ char *nameend;
+ const struct option *p;
+ const struct option *pfound = NULL;
+ int exact = 0;
+ int ambig = 0;
+ int indfound;
+ int option_index;
+
+ for (nameend = nextchar; *nameend && *nameend != '='; nameend++)
+ /* Do nothing. */ ;
+
+ /* Test all long options for either exact match
+ or abbreviated matches. */
+ for (p = longopts, option_index = 0; p->name; p++, option_index++)
+ if (!strncmp (p->name, nextchar, nameend - nextchar))
+ {
+ if (nameend - nextchar == strlen (p->name))
+ {
+ /* Exact match found. */
+ pfound = p;
+ indfound = option_index;
+ exact = 1;
+ break;
+ }
+ else if (pfound == NULL)
+ {
+ /* First nonexact match found. */
+ pfound = p;
+ indfound = option_index;
+ }
+ else
+ /* Second or later nonexact match found. */
+ ambig = 1;
+ }
+
+ if (ambig && !exact)
+ {
+ if (opterr)
+ fprintf (stderr, "%s: option `%s' is ambiguous\n",
+ argv[0], argv[optind]);
+ nextchar += strlen (nextchar);
+ optind++;
+ return '?';
+ }
+
+ if (pfound != NULL)
+ {
+ option_index = indfound;
+ optind++;
+ if (*nameend)
+ {
+ /* Don't test has_arg with >, because some C compilers don't
+ allow it to be used on enums. */
+ if (pfound->has_arg)
+ optarg = nameend + 1;
+ else
+ {
+ if (opterr)
+ {
+ if (argv[optind - 1][1] == '-')
+ /* --option */
+ fprintf (stderr,
+ "%s: option `--%s' doesn't allow an argument\n",
+ argv[0], pfound->name);
+ else
+ /* +option or -option */
+ fprintf (stderr,
+ "%s: option `%c%s' doesn't allow an argument\n",
+ argv[0], argv[optind - 1][0], pfound->name);
+ }
+ nextchar += strlen (nextchar);
+ return '?';
+ }
+ }
+ else if (pfound->has_arg == 1)
+ {
+ if (optind < argc)
+ optarg = argv[optind++];
+ else
+ {
+ if (opterr)
+ fprintf (stderr, "%s: option `%s' requires an argument\n",
+ argv[0], argv[optind - 1]);
+ nextchar += strlen (nextchar);
+ return optstring[0] == ':' ? ':' : '?';
+ }
+ }
+ nextchar += strlen (nextchar);
+ if (longind != NULL)
+ *longind = option_index;
+ if (pfound->flag)
+ {
+ *(pfound->flag) = pfound->val;
+ return 0;
+ }
+ return pfound->val;
+ }
+
+ /* Can't find it as a long option. If this is not getopt_long_only,
+ or the option starts with '--' or is not a valid short
+ option, then it's an error.
+ Otherwise interpret it as a short option. */
+ if (!long_only || argv[optind][1] == '-'
+ || my_index (optstring, *nextchar) == NULL)
+ {
+ if (opterr)
+ {
+ if (argv[optind][1] == '-')
+ /* --option */
+ fprintf (stderr, "%s: unrecognized option `--%s'\n",
+ argv[0], nextchar);
+ else
+ /* +option or -option */
+ fprintf (stderr, "%s: unrecognized option `%c%s'\n",
+ argv[0], argv[optind][0], nextchar);
+ }
+ nextchar = (char *) "";
+ optind++;
+ return '?';
+ }
+ }
+
+ /* Look at and handle the next short option-character. */
+
+ {
+ char c = *nextchar++;
+ char *temp = my_index (optstring, c);
+
+ /* Increment `optind' when we start to process its last character. */
+ if (*nextchar == '\0')
+ ++optind;
+
+ if (temp == NULL || c == ':')
+ {
+ if (opterr)
+ {
+ /* 1003.2 specifies the format of this message. */
+ fprintf (stderr, "%s: illegal option -- %c\n", argv[0], c);
+ }
+ optopt = c;
+ return '?';
+ }
+ if (temp[1] == ':')
+ {
+ if (temp[2] == ':')
+ {
+ /* This is an option that accepts an argument optionally. */
+ if (*nextchar != '\0')
+ {
+ optarg = nextchar;
+ optind++;
+ }
+ else
+ optarg = NULL;
+ nextchar = NULL;
+ }
+ else
+ {
+ /* This is an option that requires an argument. */
+ if (*nextchar != '\0')
+ {
+ optarg = nextchar;
+ /* If we end this ARGV-element by taking the rest as an arg,
+ we must advance to the next element now. */
+ optind++;
+ }
+ else if (optind == argc)
+ {
+ if (opterr)
+ {
+ /* 1003.2 specifies the format of this message. */
+ fprintf (stderr, "%s: option requires an argument -- %c\n",
+ argv[0], c);
+ }
+ optopt = c;
+ if (optstring[0] == ':')
+ c = ':';
+ else
+ c = '?';
+ }
+ else
+ /* We already incremented `optind' once;
+ increment it again when taking next ARGV-elt as argument. */
+ optarg = argv[optind++];
+ nextchar = NULL;
+ }
+ }
+ return c;
+ }
+}
+
+int
+getopt (argc, argv, optstring)
+ int argc;
+ char *const *argv;
+ const char *optstring;
+{
+ return _getopt_internal (argc, argv, optstring,
+ (const struct option *) 0,
+ (int *) 0,
+ 0);
+}
+
+#endif /* _LIBC or not __GNU_LIBRARY__. */
+
+#ifdef TEST
+
+/* Compile with -DTEST to make an executable for use in testing
+ the above definition of `getopt'. */
+
+int
+main (argc, argv)
+ int argc;
+ char **argv;
+{
+ int c;
+ int digit_optind = 0;
+
+ while (1)
+ {
+ int this_option_optind = optind ? optind : 1;
+
+ c = getopt (argc, argv, "abc:d:0123456789");
+ if (c == EOF)
+ break;
+
+ switch (c)
+ {
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ if (digit_optind != 0 && digit_optind != this_option_optind)
+ printf ("digits occur in two different argv-elements.\n");
+ digit_optind = this_option_optind;
+ printf ("option %c\n", c);
+ break;
+
+ case 'a':
+ printf ("option a\n");
+ break;
+
+ case 'b':
+ printf ("option b\n");
+ break;
+
+ case 'c':
+ printf ("option c with value `%s'\n", optarg);
+ break;
+
+ case '?':
+ break;
+
+ default:
+ printf ("?? getopt returned character code 0%o ??\n", c);
+ }
+ }
+
+ if (optind < argc)
+ {
+ printf ("non-option ARGV-elements: ");
+ while (optind < argc)
+ printf ("%s ", argv[optind++]);
+ printf ("\n");
+ }
+
+ exit (0);
+}
+
+#endif /* TEST */
diff --git a/gnu/usr.bin/gdb/libiberty/getopt1.c b/gnu/usr.bin/gdb/libiberty/getopt1.c
new file mode 100644
index 0000000..90dc12a
--- /dev/null
+++ b/gnu/usr.bin/gdb/libiberty/getopt1.c
@@ -0,0 +1,187 @@
+/* getopt_long and getopt_long_only entry points for GNU getopt.
+ Copyright (C) 1987, 88, 89, 90, 91, 92, 1993
+ Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License
+ as published by the Free Software Foundation; either version 2, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#ifdef HAVE_CONFIG_H
+#if defined (emacs) || defined (CONFIG_BROKETS)
+/* We use <config.h> instead of "config.h" so that a compilation
+ using -I. -I$srcdir will use ./config.h rather than $srcdir/config.h
+ (which it would do because it found this file in $srcdir). */
+#include <config.h>
+#else
+#include "config.h"
+#endif
+#endif
+
+#include "getopt.h"
+
+#ifndef __STDC__
+/* This is a separate conditional since some stdc systems
+ reject `defined (const)'. */
+#ifndef const
+#define const
+#endif
+#endif
+
+#include <stdio.h>
+
+/* Comment out all this code if we are using the GNU C Library, and are not
+ actually compiling the library itself. This code is part of the GNU C
+ Library, but also included in many other GNU distributions. Compiling
+ and linking in this code is a waste when using the GNU C library
+ (especially if it is a shared library). Rather than having every GNU
+ program understand `configure --with-gnu-libc' and omit the object files,
+ it is simpler to just do this in the source for each such file. */
+
+#if defined (_LIBC) || !defined (__GNU_LIBRARY__)
+
+
+/* This needs to come after some library #include
+ to get __GNU_LIBRARY__ defined. */
+#ifdef __GNU_LIBRARY__
+#include <stdlib.h>
+#else
+char *getenv ();
+#endif
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+int
+getopt_long (argc, argv, options, long_options, opt_index)
+ int argc;
+ char *const *argv;
+ const char *options;
+ const struct option *long_options;
+ int *opt_index;
+{
+ return _getopt_internal (argc, argv, options, long_options, opt_index, 0);
+}
+
+/* Like getopt_long, but '-' as well as '--' can indicate a long option.
+ If an option that starts with '-' (not '--') doesn't match a long option,
+ but does match a short option, it is parsed as a short option
+ instead. */
+
+int
+getopt_long_only (argc, argv, options, long_options, opt_index)
+ int argc;
+ char *const *argv;
+ const char *options;
+ const struct option *long_options;
+ int *opt_index;
+{
+ return _getopt_internal (argc, argv, options, long_options, opt_index, 1);
+}
+
+
+#endif /* _LIBC or not __GNU_LIBRARY__. */
+
+#ifdef TEST
+
+#include <stdio.h>
+
+int
+main (argc, argv)
+ int argc;
+ char **argv;
+{
+ int c;
+ int digit_optind = 0;
+
+ while (1)
+ {
+ int this_option_optind = optind ? optind : 1;
+ int option_index = 0;
+ static struct option long_options[] =
+ {
+ {"add", 1, 0, 0},
+ {"append", 0, 0, 0},
+ {"delete", 1, 0, 0},
+ {"verbose", 0, 0, 0},
+ {"create", 0, 0, 0},
+ {"file", 1, 0, 0},
+ {0, 0, 0, 0}
+ };
+
+ c = getopt_long (argc, argv, "abc:d:0123456789",
+ long_options, &option_index);
+ if (c == EOF)
+ break;
+
+ switch (c)
+ {
+ case 0:
+ printf ("option %s", long_options[option_index].name);
+ if (optarg)
+ printf (" with arg %s", optarg);
+ printf ("\n");
+ break;
+
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ if (digit_optind != 0 && digit_optind != this_option_optind)
+ printf ("digits occur in two different argv-elements.\n");
+ digit_optind = this_option_optind;
+ printf ("option %c\n", c);
+ break;
+
+ case 'a':
+ printf ("option a\n");
+ break;
+
+ case 'b':
+ printf ("option b\n");
+ break;
+
+ case 'c':
+ printf ("option c with value `%s'\n", optarg);
+ break;
+
+ case 'd':
+ printf ("option d with value `%s'\n", optarg);
+ break;
+
+ case '?':
+ break;
+
+ default:
+ printf ("?? getopt returned character code 0%o ??\n", c);
+ }
+ }
+
+ if (optind < argc)
+ {
+ printf ("non-option ARGV-elements: ");
+ while (optind < argc)
+ printf ("%s ", argv[optind++]);
+ printf ("\n");
+ }
+
+ exit (0);
+}
+
+#endif /* TEST */
diff --git a/gnu/usr.bin/gdb/libiberty/ieee-float.c b/gnu/usr.bin/gdb/libiberty/ieee-float.c
new file mode 100644
index 0000000..040f783
--- /dev/null
+++ b/gnu/usr.bin/gdb/libiberty/ieee-float.c
@@ -0,0 +1,150 @@
+/* IEEE floating point support routines, for GDB, the GNU Debugger.
+ Copyright (C) 1991 Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "ieee-float.h"
+#include <math.h> /* ldexp */
+
+/* Convert an IEEE extended float to a double.
+ FROM is the address of the extended float.
+ Store the double in *TO. */
+
+void
+ieee_extended_to_double (ext_format, from, to)
+ CONST struct ext_format *ext_format;
+ char *from;
+ double *to;
+{
+ unsigned char *ufrom = (unsigned char *)from;
+ double dto;
+ unsigned long mant0, mant1, exponent;
+
+ memcpy (&mant0, &from[MANBYTE_H], 4);
+ memcpy (&mant1, &from[MANBYTE_L], 4);
+ exponent = ((ufrom[EXPBYTE_H] & (unsigned char)~SIGNMASK) << 8) | ufrom[EXPBYTE_L];
+
+#if 0
+ /* We can't do anything useful with a NaN anyway, so ignore its
+ difference. It will end up as Infinity or something close. */
+ if (exponent == EXT_EXP_NAN) {
+ /* We have a NaN source. */
+ dto = 0.123456789; /* Not much else useful to do -- we don't know if
+ the host system even *has* NaNs, nor how to
+ generate an innocuous one if it does. */
+ } else
+#endif
+ if (exponent == 0 && mant0 == 0 && mant1 == 0) {
+ dto = 0;
+ } else {
+ /* Build the result algebraically. Might go infinite, underflow, etc;
+ who cares. */
+ mant0 |= 0x80000000;
+ dto = ldexp ((double)mant0, exponent - EXT_EXP_BIAS - 31);
+ dto += ldexp ((double)mant1, exponent - EXT_EXP_BIAS - 31 - 32);
+ if (ufrom[EXPBYTE_H] & SIGNMASK) /* If negative... */
+ dto = -dto; /* ...negate. */
+ }
+ memcpy (to, &dto, sizeof (dto));
+}
+
+/* The converse: convert the double *FROM to an extended float
+ and store where TO points. Neither FROM nor TO have any alignment
+ restrictions. */
+
+void
+double_to_ieee_extended (ext_format, from, to)
+ CONST struct ext_format *ext_format;
+ double *from;
+ char *to;
+{
+ double dfrom;
+ unsigned long twolongs[2];
+ unsigned long mant0, mant1, exponent;
+ unsigned char tobytes[8];
+
+ memcpy (&dfrom, from, sizeof (dfrom));
+ memset (to, 0, TOTALSIZE);
+ if (dfrom == 0)
+ return; /* Result is zero */
+ if (dfrom != dfrom) {
+ /* From is NaN */
+ to[EXPBYTE_H] = (unsigned char)(EXT_EXP_NAN >> 8);
+ to[EXPBYTE_L] = (unsigned char)EXT_EXP_NAN;
+ to[MANBYTE_H] = 1; /* Be sure it's not infinity, but NaN value is irrel */
+ return; /* Result is NaN */
+ }
+ if (dfrom < 0)
+ to[SIGNBYTE] |= SIGNMASK; /* Set negative sign */
+ /* How to tell an infinity from an ordinary number? FIXME-someday */
+
+ /* The following code assumes that the host has IEEE doubles. FIXME-someday.
+ It also assumes longs are 32 bits! FIXME-someday. */
+ memcpy (twolongs, from, 8);
+ memcpy (tobytes, from, 8);
+#if HOST_BYTE_ORDER == BIG_ENDIAN
+ exponent = ((tobytes[1] & 0xF0) >> 4) | (tobytes[0] & 0x7F) << 4;
+ mant0 = (twolongs[0] << 11) | twolongs[1] >> 21;
+ mant1 = (twolongs[1] << 11);
+#else
+ exponent = ((tobytes[6] & 0xF0) >> 4) | (tobytes[7] & 0x7F) << 4;
+ mant0 = (twolongs[1] << 11) | twolongs[0] >> 21;
+ mant1 = (twolongs[0] << 11);
+#endif
+
+ /* Fiddle with leading 1-bit, implied in double, explicit in extended. */
+ if (exponent == 0)
+ mant0 &= 0x7FFFFFFF;
+ else
+ mant0 |= 0x80000000;
+
+ exponent -= DBL_EXP_BIAS; /* Get integer exp */
+ exponent += EXT_EXP_BIAS; /* Offset for extended */
+
+ /* OK, now store it in extended format. */
+ to[EXPBYTE_H] |= (unsigned char)(exponent >> 8); /* Retain sign */
+ to[EXPBYTE_L] = (unsigned char) exponent;
+
+ memcpy (&to[MANBYTE_H], &mant0, 4);
+ memcpy (&to[MANBYTE_L], &mant1, 4);
+}
+
+
+#ifdef IEEE_DEBUG
+
+/* Test some numbers to see that extended/double conversion works for them. */
+
+ieee_test (n)
+ int n;
+{
+ union { double d; int i[2]; } di;
+ double result;
+ int i;
+ char exten[16];
+ extern struct ext_format ext_format_68881;
+
+ for (i = 0; i < n; i++) {
+ di.i[0] = (random() << 16) | (random() & 0xffff);
+ di.i[1] = (random() << 16) | (random() & 0xffff);
+ double_to_ieee_extended (&ext_format_68881, &di.d, exten);
+ ieee_extended_to_double (&ext_format_68881, exten, &result);
+ if (di.d != result)
+ printf ("Differ: %x %x %g => %x %x %g\n", di.d, di.d, result, result);
+ }
+}
+
+#endif
diff --git a/gnu/usr.bin/gdb/libiberty/ieee-float.h b/gnu/usr.bin/gdb/libiberty/ieee-float.h
new file mode 100644
index 0000000..68ef23b
--- /dev/null
+++ b/gnu/usr.bin/gdb/libiberty/ieee-float.h
@@ -0,0 +1,65 @@
+/* IEEE floating point support declarations, for GDB, the GNU Debugger.
+ Copyright (C) 1991 Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#if !defined (IEEE_FLOAT_H)
+#define IEEE_FLOAT_H 1
+
+#include "ansidecl.h"
+
+/* Parameters for extended float format: */
+
+struct ext_format {
+ unsigned totalsize; /* Total size of extended number */
+ unsigned signbyte; /* Byte number of sign bit */
+ unsigned char signmask; /* Mask for sign bit */
+ unsigned expbyte_h; /* High byte of exponent */
+ unsigned expbyte_l; /* Low byte of exponent */
+ unsigned manbyte_h; /* High byte of mantissa */
+ unsigned manbyte_l; /* Low byte of mantissa */
+};
+
+#define TOTALSIZE ext_format->totalsize
+#define SIGNBYTE ext_format->signbyte
+#define SIGNMASK ext_format->signmask
+#define EXPBYTE_H ext_format->expbyte_h
+#define EXPBYTE_L ext_format->expbyte_l
+#define MANBYTE_H ext_format->manbyte_h
+#define MANBYTE_L ext_format->manbyte_l
+
+/* Actual ext_format structs for various machines are in the *-tdep.c file
+ for each machine. */
+
+#define EXT_EXP_NAN 0x7FFF /* Exponent value that indicates NaN */
+#define EXT_EXP_BIAS 0x3FFF /* Amount added to "true" exponent for ext */
+#define DBL_EXP_BIAS 0x3FF /* Ditto, for doubles */
+
+/* Convert an IEEE extended float to a double.
+ FROM is the address of the extended float.
+ Store the double in *TO. */
+
+extern void
+ieee_extended_to_double PARAMS ((const struct ext_format *, char *, double *));
+
+/* The converse: convert the double *FROM to an extended float
+ and store where TO points. */
+
+extern void
+double_to_ieee_extended PARAMS ((const struct ext_format *, double *, char *));
+
+#endif /* defined (IEEE_FLOAT_H) */
diff --git a/gnu/usr.bin/gdb/libiberty/obstack.c b/gnu/usr.bin/gdb/libiberty/obstack.c
new file mode 100644
index 0000000..f3f39fc
--- /dev/null
+++ b/gnu/usr.bin/gdb/libiberty/obstack.c
@@ -0,0 +1,493 @@
+/* obstack.c - subroutines used implicitly by object stack macros
+ Copyright (C) 1988, 89, 90, 91, 92, 93, 94 Free Software Foundation, Inc.
+
+This program is free software; you can redistribute it and/or modify it
+under the terms of the GNU Library General Public License as published by the
+Free Software Foundation; either version 2, or (at your option) any
+later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public License
+along with this program; if not, write to the Free Software
+Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "obstack.h"
+
+/* This is just to get __GNU_LIBRARY__ defined. */
+#include <stdio.h>
+
+/* Comment out all this code if we are using the GNU C Library, and are not
+ actually compiling the library itself. This code is part of the GNU C
+ Library, but also included in many other GNU distributions. Compiling
+ and linking in this code is a waste when using the GNU C library
+ (especially if it is a shared library). Rather than having every GNU
+ program understand `configure --with-gnu-libc' and omit the object files,
+ it is simpler to just do this in the source for each such file. */
+
+/* CYGNUS LOCAL. No, don't comment the code out. We will be using
+ ../include/obstack.h, which was changed relatively recently in a
+ way that is not binary compatible. Until we feel confident that
+ nobody is using the old obstack.c code, force the use of this code.
+ This issue will arise anytime a change is made which is not binary
+ compatible.
+#if defined (_LIBC) || !defined (__GNU_LIBRARY__)
+*/
+#if 1
+
+
+#ifdef __STDC__
+#define POINTER void *
+#else
+#define POINTER char *
+#endif
+
+/* Determine default alignment. */
+struct fooalign {char x; double d;};
+#define DEFAULT_ALIGNMENT \
+ ((PTR_INT_TYPE) ((char *)&((struct fooalign *) 0)->d - (char *)0))
+/* If malloc were really smart, it would round addresses to DEFAULT_ALIGNMENT.
+ But in fact it might be less smart and round addresses to as much as
+ DEFAULT_ROUNDING. So we prepare for it to do that. */
+union fooround {long x; double d;};
+#define DEFAULT_ROUNDING (sizeof (union fooround))
+
+/* When we copy a long block of data, this is the unit to do it with.
+ On some machines, copying successive ints does not work;
+ in such a case, redefine COPYING_UNIT to `long' (if that works)
+ or `char' as a last resort. */
+#ifndef COPYING_UNIT
+#define COPYING_UNIT int
+#endif
+
+/* The non-GNU-C macros copy the obstack into this global variable
+ to avoid multiple evaluation. */
+
+struct obstack *_obstack;
+
+/* Define a macro that either calls functions with the traditional malloc/free
+ calling interface, or calls functions with the mmalloc/mfree interface
+ (that adds an extra first argument), based on the state of use_extra_arg.
+ For free, do not use ?:, since some compilers, like the MIPS compilers,
+ do not allow (expr) ? void : void. */
+
+#define CALL_CHUNKFUN(h, size) \
+ (((h) -> use_extra_arg) \
+ ? (*(h)->chunkfun) ((h)->extra_arg, (size)) \
+ : (*(h)->chunkfun) ((size)))
+
+#define CALL_FREEFUN(h, old_chunk) \
+ do { \
+ if ((h) -> use_extra_arg) \
+ (*(h)->freefun) ((h)->extra_arg, (old_chunk)); \
+ else \
+ (*(h)->freefun) ((old_chunk)); \
+ } while (0)
+
+
+/* Initialize an obstack H for use. Specify chunk size SIZE (0 means default).
+ Objects start on multiples of ALIGNMENT (0 means use default).
+ CHUNKFUN is the function to use to allocate chunks,
+ and FREEFUN the function to free them.
+
+ Return nonzero if successful, zero if out of memory.
+ To recover from an out of memory error,
+ free up some memory, then call this again. */
+
+int
+_obstack_begin (h, size, alignment, chunkfun, freefun)
+ struct obstack *h;
+ int size;
+ int alignment;
+ POINTER (*chunkfun) ();
+ void (*freefun) ();
+{
+ register struct _obstack_chunk* chunk; /* points to new chunk */
+
+ if (alignment == 0)
+ alignment = DEFAULT_ALIGNMENT;
+ if (size == 0)
+ /* Default size is what GNU malloc can fit in a 4096-byte block. */
+ {
+ /* 12 is sizeof (mhead) and 4 is EXTRA from GNU malloc.
+ Use the values for range checking, because if range checking is off,
+ the extra bytes won't be missed terribly, but if range checking is on
+ and we used a larger request, a whole extra 4096 bytes would be
+ allocated.
+
+ These number are irrelevant to the new GNU malloc. I suspect it is
+ less sensitive to the size of the request. */
+ int extra = ((((12 + DEFAULT_ROUNDING - 1) & ~(DEFAULT_ROUNDING - 1))
+ + 4 + DEFAULT_ROUNDING - 1)
+ & ~(DEFAULT_ROUNDING - 1));
+ size = 4096 - extra;
+ }
+
+ h->chunkfun = (struct _obstack_chunk * (*)()) chunkfun;
+ h->freefun = freefun;
+ h->chunk_size = size;
+ h->alignment_mask = alignment - 1;
+ h->use_extra_arg = 0;
+
+ chunk = h->chunk = CALL_CHUNKFUN (h, h -> chunk_size);
+ if (!chunk)
+ {
+ h->alloc_failed = 1;
+ return 0;
+ }
+ h->alloc_failed = 0;
+ h->next_free = h->object_base = chunk->contents;
+ h->chunk_limit = chunk->limit
+ = (char *) chunk + h->chunk_size;
+ chunk->prev = 0;
+ /* The initial chunk now contains no empty object. */
+ h->maybe_empty_object = 0;
+ return 1;
+}
+
+int
+_obstack_begin_1 (h, size, alignment, chunkfun, freefun, arg)
+ struct obstack *h;
+ int size;
+ int alignment;
+ POINTER (*chunkfun) ();
+ void (*freefun) ();
+ POINTER arg;
+{
+ register struct _obstack_chunk* chunk; /* points to new chunk */
+
+ if (alignment == 0)
+ alignment = DEFAULT_ALIGNMENT;
+ if (size == 0)
+ /* Default size is what GNU malloc can fit in a 4096-byte block. */
+ {
+ /* 12 is sizeof (mhead) and 4 is EXTRA from GNU malloc.
+ Use the values for range checking, because if range checking is off,
+ the extra bytes won't be missed terribly, but if range checking is on
+ and we used a larger request, a whole extra 4096 bytes would be
+ allocated.
+
+ These number are irrelevant to the new GNU malloc. I suspect it is
+ less sensitive to the size of the request. */
+ int extra = ((((12 + DEFAULT_ROUNDING - 1) & ~(DEFAULT_ROUNDING - 1))
+ + 4 + DEFAULT_ROUNDING - 1)
+ & ~(DEFAULT_ROUNDING - 1));
+ size = 4096 - extra;
+ }
+
+ h->chunkfun = (struct _obstack_chunk * (*)()) chunkfun;
+ h->freefun = freefun;
+ h->chunk_size = size;
+ h->alignment_mask = alignment - 1;
+ h->extra_arg = arg;
+ h->use_extra_arg = 1;
+
+ chunk = h->chunk = CALL_CHUNKFUN (h, h -> chunk_size);
+ if (!chunk)
+ {
+ h->alloc_failed = 1;
+ return 0;
+ }
+ h->alloc_failed = 0;
+ h->next_free = h->object_base = chunk->contents;
+ h->chunk_limit = chunk->limit
+ = (char *) chunk + h->chunk_size;
+ chunk->prev = 0;
+ /* The initial chunk now contains no empty object. */
+ h->maybe_empty_object = 0;
+ return 1;
+}
+
+/* Allocate a new current chunk for the obstack *H
+ on the assumption that LENGTH bytes need to be added
+ to the current object, or a new object of length LENGTH allocated.
+ Copies any partial object from the end of the old chunk
+ to the beginning of the new one. */
+
+void
+_obstack_newchunk (h, length)
+ struct obstack *h;
+ int length;
+{
+ register struct _obstack_chunk* old_chunk = h->chunk;
+ register struct _obstack_chunk* new_chunk;
+ register long new_size;
+ register int obj_size = h->next_free - h->object_base;
+ register int i;
+ int already;
+
+ /* Compute size for new chunk. */
+ new_size = (obj_size + length) + (obj_size >> 3) + 100;
+ if (new_size < h->chunk_size)
+ new_size = h->chunk_size;
+
+ /* Allocate and initialize the new chunk. */
+ new_chunk = CALL_CHUNKFUN (h, new_size);
+ if (!new_chunk)
+ {
+ h->alloc_failed = 1;
+ return;
+ }
+ h->alloc_failed = 0;
+ h->chunk = new_chunk;
+ new_chunk->prev = old_chunk;
+ new_chunk->limit = h->chunk_limit = (char *) new_chunk + new_size;
+
+ /* Move the existing object to the new chunk.
+ Word at a time is fast and is safe if the object
+ is sufficiently aligned. */
+ if (h->alignment_mask + 1 >= DEFAULT_ALIGNMENT)
+ {
+ for (i = obj_size / sizeof (COPYING_UNIT) - 1;
+ i >= 0; i--)
+ ((COPYING_UNIT *)new_chunk->contents)[i]
+ = ((COPYING_UNIT *)h->object_base)[i];
+ /* We used to copy the odd few remaining bytes as one extra COPYING_UNIT,
+ but that can cross a page boundary on a machine
+ which does not do strict alignment for COPYING_UNITS. */
+ already = obj_size / sizeof (COPYING_UNIT) * sizeof (COPYING_UNIT);
+ }
+ else
+ already = 0;
+ /* Copy remaining bytes one by one. */
+ for (i = already; i < obj_size; i++)
+ new_chunk->contents[i] = h->object_base[i];
+
+ /* If the object just copied was the only data in OLD_CHUNK,
+ free that chunk and remove it from the chain.
+ But not if that chunk might contain an empty object. */
+ if (h->object_base == old_chunk->contents && ! h->maybe_empty_object)
+ {
+ new_chunk->prev = old_chunk->prev;
+ CALL_FREEFUN (h, old_chunk);
+ }
+
+ h->object_base = new_chunk->contents;
+ h->next_free = h->object_base + obj_size;
+ /* The new chunk certainly contains no empty object yet. */
+ h->maybe_empty_object = 0;
+}
+
+/* Return nonzero if object OBJ has been allocated from obstack H.
+ This is here for debugging.
+ If you use it in a program, you are probably losing. */
+
+#ifdef __STDC__
+/* Suppress -Wmissing-prototypes warning. We don't want to declare this in
+ obstack.h because it is just for debugging. */
+int _obstack_allocated_p (struct obstack *h, POINTER obj);
+#endif
+
+int
+_obstack_allocated_p (h, obj)
+ struct obstack *h;
+ POINTER obj;
+{
+ register struct _obstack_chunk* lp; /* below addr of any objects in this chunk */
+ register struct _obstack_chunk* plp; /* point to previous chunk if any */
+
+ lp = (h)->chunk;
+ /* We use >= rather than > since the object cannot be exactly at
+ the beginning of the chunk but might be an empty object exactly
+ at the end of an adjacent chunk. */
+ while (lp != 0 && ((POINTER)lp >= obj || (POINTER)(lp)->limit < obj))
+ {
+ plp = lp->prev;
+ lp = plp;
+ }
+ return lp != 0;
+}
+
+/* Free objects in obstack H, including OBJ and everything allocate
+ more recently than OBJ. If OBJ is zero, free everything in H. */
+
+#undef obstack_free
+
+/* This function has two names with identical definitions.
+ This is the first one, called from non-ANSI code. */
+
+void
+_obstack_free (h, obj)
+ struct obstack *h;
+ POINTER obj;
+{
+ register struct _obstack_chunk* lp; /* below addr of any objects in this chunk */
+ register struct _obstack_chunk* plp; /* point to previous chunk if any */
+
+ lp = h->chunk;
+ /* We use >= because there cannot be an object at the beginning of a chunk.
+ But there can be an empty object at that address
+ at the end of another chunk. */
+ while (lp != 0 && ((POINTER)lp >= obj || (POINTER)(lp)->limit < obj))
+ {
+ plp = lp->prev;
+ CALL_FREEFUN (h, lp);
+ lp = plp;
+ /* If we switch chunks, we can't tell whether the new current
+ chunk contains an empty object, so assume that it may. */
+ h->maybe_empty_object = 1;
+ }
+ if (lp)
+ {
+ h->object_base = h->next_free = (char *)(obj);
+ h->chunk_limit = lp->limit;
+ h->chunk = lp;
+ }
+ else if (obj != 0)
+ /* obj is not in any of the chunks! */
+ abort ();
+}
+
+/* This function is used from ANSI code. */
+
+void
+obstack_free (h, obj)
+ struct obstack *h;
+ POINTER obj;
+{
+ register struct _obstack_chunk* lp; /* below addr of any objects in this chunk */
+ register struct _obstack_chunk* plp; /* point to previous chunk if any */
+
+ lp = h->chunk;
+ /* We use >= because there cannot be an object at the beginning of a chunk.
+ But there can be an empty object at that address
+ at the end of another chunk. */
+ while (lp != 0 && ((POINTER)lp >= obj || (POINTER)(lp)->limit < obj))
+ {
+ plp = lp->prev;
+ CALL_FREEFUN (h, lp);
+ lp = plp;
+ /* If we switch chunks, we can't tell whether the new current
+ chunk contains an empty object, so assume that it may. */
+ h->maybe_empty_object = 1;
+ }
+ if (lp)
+ {
+ h->object_base = h->next_free = (char *)(obj);
+ h->chunk_limit = lp->limit;
+ h->chunk = lp;
+ }
+ else if (obj != 0)
+ /* obj is not in any of the chunks! */
+ abort ();
+}
+
+#if 0
+/* These are now turned off because the applications do not use it
+ and it uses bcopy via obstack_grow, which causes trouble on sysV. */
+
+/* Now define the functional versions of the obstack macros.
+ Define them to simply use the corresponding macros to do the job. */
+
+#ifdef __STDC__
+/* These function definitions do not work with non-ANSI preprocessors;
+ they won't pass through the macro names in parentheses. */
+
+/* The function names appear in parentheses in order to prevent
+ the macro-definitions of the names from being expanded there. */
+
+POINTER (obstack_base) (obstack)
+ struct obstack *obstack;
+{
+ return obstack_base (obstack);
+}
+
+POINTER (obstack_next_free) (obstack)
+ struct obstack *obstack;
+{
+ return obstack_next_free (obstack);
+}
+
+int (obstack_object_size) (obstack)
+ struct obstack *obstack;
+{
+ return obstack_object_size (obstack);
+}
+
+int (obstack_room) (obstack)
+ struct obstack *obstack;
+{
+ return obstack_room (obstack);
+}
+
+void (obstack_grow) (obstack, pointer, length)
+ struct obstack *obstack;
+ POINTER pointer;
+ int length;
+{
+ obstack_grow (obstack, pointer, length);
+}
+
+void (obstack_grow0) (obstack, pointer, length)
+ struct obstack *obstack;
+ POINTER pointer;
+ int length;
+{
+ obstack_grow0 (obstack, pointer, length);
+}
+
+void (obstack_1grow) (obstack, character)
+ struct obstack *obstack;
+ int character;
+{
+ obstack_1grow (obstack, character);
+}
+
+void (obstack_blank) (obstack, length)
+ struct obstack *obstack;
+ int length;
+{
+ obstack_blank (obstack, length);
+}
+
+void (obstack_1grow_fast) (obstack, character)
+ struct obstack *obstack;
+ int character;
+{
+ obstack_1grow_fast (obstack, character);
+}
+
+void (obstack_blank_fast) (obstack, length)
+ struct obstack *obstack;
+ int length;
+{
+ obstack_blank_fast (obstack, length);
+}
+
+POINTER (obstack_finish) (obstack)
+ struct obstack *obstack;
+{
+ return obstack_finish (obstack);
+}
+
+POINTER (obstack_alloc) (obstack, length)
+ struct obstack *obstack;
+ int length;
+{
+ return obstack_alloc (obstack, length);
+}
+
+POINTER (obstack_copy) (obstack, pointer, length)
+ struct obstack *obstack;
+ POINTER pointer;
+ int length;
+{
+ return obstack_copy (obstack, pointer, length);
+}
+
+POINTER (obstack_copy0) (obstack, pointer, length)
+ struct obstack *obstack;
+ POINTER pointer;
+ int length;
+{
+ return obstack_copy0 (obstack, pointer, length);
+}
+
+#endif /* __STDC__ */
+
+#endif /* 0 */
+
+#endif /* _LIBC or not __GNU_LIBRARY__. */
diff --git a/gnu/usr.bin/gdb/libiberty/sigsetmask.c b/gnu/usr.bin/gdb/libiberty/sigsetmask.c
new file mode 100644
index 0000000..5c9e8fa
--- /dev/null
+++ b/gnu/usr.bin/gdb/libiberty/sigsetmask.c
@@ -0,0 +1,44 @@
+/* Version of sigsetmask.c
+ Copyright 1991, 1992 Free Software Foundation, Inc.
+ Written by Steve Chamberlain (sac@cygnus.com).
+ Contributed by Cygnus Support.
+
+This file is part of the libiberty library.
+Libiberty is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public
+License as published by the Free Software Foundation; either
+version 2 of the License, or (at your option) any later version.
+
+Libiberty is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with libiberty; see the file COPYING.LIB. If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA. */
+
+/* Set the current signal mask to the set provided, and return the
+ previous value */
+
+#define _POSIX_SOURCE
+#include <ansidecl.h>
+#include <signal.h>
+
+#ifdef SIG_SETMASK
+int
+DEFUN(sigsetmask,(set),
+ int set)
+{
+ sigset_t new;
+ sigset_t old;
+
+ sigemptyset (&new);
+ if (set != 0) {
+ abort(); /* FIXME, we don't know how to translate old mask to new */
+ }
+ sigprocmask(SIG_SETMASK, &new, &old);
+ return 1; /* FIXME, we always return 1 as old value. */
+}
+#endif
diff --git a/gnu/usr.bin/gdb/libiberty/spaces.c b/gnu/usr.bin/gdb/libiberty/spaces.c
new file mode 100644
index 0000000..884c960
--- /dev/null
+++ b/gnu/usr.bin/gdb/libiberty/spaces.c
@@ -0,0 +1,71 @@
+/* Allocate memory region filled with spaces.
+ Copyright (C) 1991 Free Software Foundation, Inc.
+
+This file is part of the libiberty library.
+Libiberty is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public
+License as published by the Free Software Foundation; either
+version 2 of the License, or (at your option) any later version.
+
+Libiberty is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with libiberty; see the file COPYING.LIB. If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA. */
+
+/*
+
+NAME
+
+ spaces -- return a pointer to a buffer full of spaces
+
+SYNOPSIS
+
+ char *spaces (int count)
+
+DESCRIPTION
+
+ Returns a pointer to a memory region filled with the specified
+ number of spaces and null terminated. The returned pointer is
+ valid until at least the next call.
+
+BUGS
+
+*/
+
+#include "ansidecl.h"
+#include "libiberty.h"
+
+const char *
+spaces (count)
+ int count;
+{
+ register char *t;
+ static char *buf;
+ static int maxsize;
+ extern char *malloc ();
+ extern void free ();
+
+ if (count > maxsize)
+ {
+ if (buf)
+ {
+ free (buf);
+ }
+ buf = malloc (count + 1);
+ if (buf == (char *) 0)
+ return 0;
+ for (t = buf + count ; t != buf ; )
+ {
+ *--t = ' ';
+ }
+ maxsize = count;
+ buf[count] = '\0';
+ }
+ return (const char *) (buf + maxsize - count);
+}
+
diff --git a/gnu/usr.bin/gdb/libiberty/strerror.c b/gnu/usr.bin/gdb/libiberty/strerror.c
new file mode 100644
index 0000000..29a4e4a
--- /dev/null
+++ b/gnu/usr.bin/gdb/libiberty/strerror.c
@@ -0,0 +1,823 @@
+/* Extended support for using errno values.
+ Copyright (C) 1992 Free Software Foundation, Inc.
+ Written by Fred Fish. fnf@cygnus.com
+
+This file is part of the libiberty library.
+Libiberty is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public
+License as published by the Free Software Foundation; either
+version 2 of the License, or (at your option) any later version.
+
+Libiberty is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with libiberty; see the file COPYING.LIB. If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA. */
+
+#include "ansidecl.h"
+#include "libiberty.h"
+
+#include "config.h"
+
+#ifndef NEED_sys_errlist
+/* Note that errno.h (not sure what OS) or stdio.h (BSD 4.4, at least)
+ might declare sys_errlist in a way that the compiler might consider
+ incompatible with our later declaration, perhaps by using const
+ attributes. So we hide the declaration in errno.h (if any) using a
+ macro. */
+#define sys_errlist sys_errlist__
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+
+#ifndef NEED_sys_errlist
+#undef sys_errlist
+#endif
+
+/* Routines imported from standard C runtime libraries. */
+
+#ifdef __STDC__
+#include <stddef.h>
+extern void *malloc (size_t size); /* 4.10.3.3 */
+extern void *memset (void *s, int c, size_t n); /* 4.11.6.1 */
+#else /* !__STDC__ */
+extern char *malloc (); /* Standard memory allocater */
+extern char *memset ();
+#endif /* __STDC__ */
+
+#ifndef MAX
+# define MAX(a,b) ((a) > (b) ? (a) : (b))
+#endif
+
+/* Translation table for errno values. See intro(2) in most UNIX systems
+ Programmers Reference Manuals.
+
+ Note that this table is generally only accessed when it is used at runtime
+ to initialize errno name and message tables that are indexed by errno
+ value.
+
+ Not all of these errnos will exist on all systems. This table is the only
+ thing that should have to be updated as new error numbers are introduced.
+ It's sort of ugly, but at least its portable. */
+
+struct error_info
+{
+ int value; /* The numeric value from <errno.h> */
+ const char *name; /* The equivalent symbolic value */
+#ifdef NEED_sys_errlist
+ const char *msg; /* Short message about this value */
+#endif
+};
+
+#ifdef NEED_sys_errlist
+# define ENTRY(value, name, msg) {value, name, msg}
+#else
+# define ENTRY(value, name, msg) {value, name}
+#endif
+
+static const struct error_info error_table[] =
+{
+#if defined (EPERM)
+ ENTRY(EPERM, "EPERM", "Not owner"),
+#endif
+#if defined (ENOENT)
+ ENTRY(ENOENT, "ENOENT", "No such file or directory"),
+#endif
+#if defined (ESRCH)
+ ENTRY(ESRCH, "ESRCH", "No such process"),
+#endif
+#if defined (EINTR)
+ ENTRY(EINTR, "EINTR", "Interrupted system call"),
+#endif
+#if defined (EIO)
+ ENTRY(EIO, "EIO", "I/O error"),
+#endif
+#if defined (ENXIO)
+ ENTRY(ENXIO, "ENXIO", "No such device or address"),
+#endif
+#if defined (E2BIG)
+ ENTRY(E2BIG, "E2BIG", "Arg list too long"),
+#endif
+#if defined (ENOEXEC)
+ ENTRY(ENOEXEC, "ENOEXEC", "Exec format error"),
+#endif
+#if defined (EBADF)
+ ENTRY(EBADF, "EBADF", "Bad file number"),
+#endif
+#if defined (ECHILD)
+ ENTRY(ECHILD, "ECHILD", "No child processes"),
+#endif
+#if defined (EWOULDBLOCK) /* Put before EAGAIN, sometimes aliased */
+ ENTRY(EWOULDBLOCK, "EWOULDBLOCK", "Operation would block"),
+#endif
+#if defined (EAGAIN)
+ ENTRY(EAGAIN, "EAGAIN", "No more processes"),
+#endif
+#if defined (ENOMEM)
+ ENTRY(ENOMEM, "ENOMEM", "Not enough space"),
+#endif
+#if defined (EACCES)
+ ENTRY(EACCES, "EACCES", "Permission denied"),
+#endif
+#if defined (EFAULT)
+ ENTRY(EFAULT, "EFAULT", "Bad address"),
+#endif
+#if defined (ENOTBLK)
+ ENTRY(ENOTBLK, "ENOTBLK", "Block device required"),
+#endif
+#if defined (EBUSY)
+ ENTRY(EBUSY, "EBUSY", "Device busy"),
+#endif
+#if defined (EEXIST)
+ ENTRY(EEXIST, "EEXIST", "File exists"),
+#endif
+#if defined (EXDEV)
+ ENTRY(EXDEV, "EXDEV", "Cross-device link"),
+#endif
+#if defined (ENODEV)
+ ENTRY(ENODEV, "ENODEV", "No such device"),
+#endif
+#if defined (ENOTDIR)
+ ENTRY(ENOTDIR, "ENOTDIR", "Not a directory"),
+#endif
+#if defined (EISDIR)
+ ENTRY(EISDIR, "EISDIR", "Is a directory"),
+#endif
+#if defined (EINVAL)
+ ENTRY(EINVAL, "EINVAL", "Invalid argument"),
+#endif
+#if defined (ENFILE)
+ ENTRY(ENFILE, "ENFILE", "File table overflow"),
+#endif
+#if defined (EMFILE)
+ ENTRY(EMFILE, "EMFILE", "Too many open files"),
+#endif
+#if defined (ENOTTY)
+ ENTRY(ENOTTY, "ENOTTY", "Not a typewriter"),
+#endif
+#if defined (ETXTBSY)
+ ENTRY(ETXTBSY, "ETXTBSY", "Text file busy"),
+#endif
+#if defined (EFBIG)
+ ENTRY(EFBIG, "EFBIG", "File too large"),
+#endif
+#if defined (ENOSPC)
+ ENTRY(ENOSPC, "ENOSPC", "No space left on device"),
+#endif
+#if defined (ESPIPE)
+ ENTRY(ESPIPE, "ESPIPE", "Illegal seek"),
+#endif
+#if defined (EROFS)
+ ENTRY(EROFS, "EROFS", "Read-only file system"),
+#endif
+#if defined (EMLINK)
+ ENTRY(EMLINK, "EMLINK", "Too many links"),
+#endif
+#if defined (EPIPE)
+ ENTRY(EPIPE, "EPIPE", "Broken pipe"),
+#endif
+#if defined (EDOM)
+ ENTRY(EDOM, "EDOM", "Math argument out of domain of func"),
+#endif
+#if defined (ERANGE)
+ ENTRY(ERANGE, "ERANGE", "Math result not representable"),
+#endif
+#if defined (ENOMSG)
+ ENTRY(ENOMSG, "ENOMSG", "No message of desired type"),
+#endif
+#if defined (EIDRM)
+ ENTRY(EIDRM, "EIDRM", "Identifier removed"),
+#endif
+#if defined (ECHRNG)
+ ENTRY(ECHRNG, "ECHRNG", "Channel number out of range"),
+#endif
+#if defined (EL2NSYNC)
+ ENTRY(EL2NSYNC, "EL2NSYNC", "Level 2 not synchronized"),
+#endif
+#if defined (EL3HLT)
+ ENTRY(EL3HLT, "EL3HLT", "Level 3 halted"),
+#endif
+#if defined (EL3RST)
+ ENTRY(EL3RST, "EL3RST", "Level 3 reset"),
+#endif
+#if defined (ELNRNG)
+ ENTRY(ELNRNG, "ELNRNG", "Link number out of range"),
+#endif
+#if defined (EUNATCH)
+ ENTRY(EUNATCH, "EUNATCH", "Protocol driver not attached"),
+#endif
+#if defined (ENOCSI)
+ ENTRY(ENOCSI, "ENOCSI", "No CSI structure available"),
+#endif
+#if defined (EL2HLT)
+ ENTRY(EL2HLT, "EL2HLT", "Level 2 halted"),
+#endif
+#if defined (EDEADLK)
+ ENTRY(EDEADLK, "EDEADLK", "Deadlock condition"),
+#endif
+#if defined (ENOLCK)
+ ENTRY(ENOLCK, "ENOLCK", "No record locks available"),
+#endif
+#if defined (EBADE)
+ ENTRY(EBADE, "EBADE", "Invalid exchange"),
+#endif
+#if defined (EBADR)
+ ENTRY(EBADR, "EBADR", "Invalid request descriptor"),
+#endif
+#if defined (EXFULL)
+ ENTRY(EXFULL, "EXFULL", "Exchange full"),
+#endif
+#if defined (ENOANO)
+ ENTRY(ENOANO, "ENOANO", "No anode"),
+#endif
+#if defined (EBADRQC)
+ ENTRY(EBADRQC, "EBADRQC", "Invalid request code"),
+#endif
+#if defined (EBADSLT)
+ ENTRY(EBADSLT, "EBADSLT", "Invalid slot"),
+#endif
+#if defined (EDEADLOCK)
+ ENTRY(EDEADLOCK, "EDEADLOCK", "File locking deadlock error"),
+#endif
+#if defined (EBFONT)
+ ENTRY(EBFONT, "EBFONT", "Bad font file format"),
+#endif
+#if defined (ENOSTR)
+ ENTRY(ENOSTR, "ENOSTR", "Device not a stream"),
+#endif
+#if defined (ENODATA)
+ ENTRY(ENODATA, "ENODATA", "No data available"),
+#endif
+#if defined (ETIME)
+ ENTRY(ETIME, "ETIME", "Timer expired"),
+#endif
+#if defined (ENOSR)
+ ENTRY(ENOSR, "ENOSR", "Out of streams resources"),
+#endif
+#if defined (ENONET)
+ ENTRY(ENONET, "ENONET", "Machine is not on the network"),
+#endif
+#if defined (ENOPKG)
+ ENTRY(ENOPKG, "ENOPKG", "Package not installed"),
+#endif
+#if defined (EREMOTE)
+ ENTRY(EREMOTE, "EREMOTE", "Object is remote"),
+#endif
+#if defined (ENOLINK)
+ ENTRY(ENOLINK, "ENOLINK", "Link has been severed"),
+#endif
+#if defined (EADV)
+ ENTRY(EADV, "EADV", "Advertise error"),
+#endif
+#if defined (ESRMNT)
+ ENTRY(ESRMNT, "ESRMNT", "Srmount error"),
+#endif
+#if defined (ECOMM)
+ ENTRY(ECOMM, "ECOMM", "Communication error on send"),
+#endif
+#if defined (EPROTO)
+ ENTRY(EPROTO, "EPROTO", "Protocol error"),
+#endif
+#if defined (EMULTIHOP)
+ ENTRY(EMULTIHOP, "EMULTIHOP", "Multihop attempted"),
+#endif
+#if defined (EDOTDOT)
+ ENTRY(EDOTDOT, "EDOTDOT", "RFS specific error"),
+#endif
+#if defined (EBADMSG)
+ ENTRY(EBADMSG, "EBADMSG", "Not a data message"),
+#endif
+#if defined (ENAMETOOLONG)
+ ENTRY(ENAMETOOLONG, "ENAMETOOLONG", "File name too long"),
+#endif
+#if defined (EOVERFLOW)
+ ENTRY(EOVERFLOW, "EOVERFLOW", "Value too large for defined data type"),
+#endif
+#if defined (ENOTUNIQ)
+ ENTRY(ENOTUNIQ, "ENOTUNIQ", "Name not unique on network"),
+#endif
+#if defined (EBADFD)
+ ENTRY(EBADFD, "EBADFD", "File descriptor in bad state"),
+#endif
+#if defined (EREMCHG)
+ ENTRY(EREMCHG, "EREMCHG", "Remote address changed"),
+#endif
+#if defined (ELIBACC)
+ ENTRY(ELIBACC, "ELIBACC", "Can not access a needed shared library"),
+#endif
+#if defined (ELIBBAD)
+ ENTRY(ELIBBAD, "ELIBBAD", "Accessing a corrupted shared library"),
+#endif
+#if defined (ELIBSCN)
+ ENTRY(ELIBSCN, "ELIBSCN", ".lib section in a.out corrupted"),
+#endif
+#if defined (ELIBMAX)
+ ENTRY(ELIBMAX, "ELIBMAX", "Attempting to link in too many shared libraries"),
+#endif
+#if defined (ELIBEXEC)
+ ENTRY(ELIBEXEC, "ELIBEXEC", "Cannot exec a shared library directly"),
+#endif
+#if defined (EILSEQ)
+ ENTRY(EILSEQ, "EILSEQ", "Illegal byte sequence"),
+#endif
+#if defined (ENOSYS)
+ ENTRY(ENOSYS, "ENOSYS", "Operation not applicable"),
+#endif
+#if defined (ELOOP)
+ ENTRY(ELOOP, "ELOOP", "Too many symbolic links encountered"),
+#endif
+#if defined (ERESTART)
+ ENTRY(ERESTART, "ERESTART", "Interrupted system call should be restarted"),
+#endif
+#if defined (ESTRPIPE)
+ ENTRY(ESTRPIPE, "ESTRPIPE", "Streams pipe error"),
+#endif
+#if defined (ENOTEMPTY)
+ ENTRY(ENOTEMPTY, "ENOTEMPTY", "Directory not empty"),
+#endif
+#if defined (EUSERS)
+ ENTRY(EUSERS, "EUSERS", "Too many users"),
+#endif
+#if defined (ENOTSOCK)
+ ENTRY(ENOTSOCK, "ENOTSOCK", "Socket operation on non-socket"),
+#endif
+#if defined (EDESTADDRREQ)
+ ENTRY(EDESTADDRREQ, "EDESTADDRREQ", "Destination address required"),
+#endif
+#if defined (EMSGSIZE)
+ ENTRY(EMSGSIZE, "EMSGSIZE", "Message too long"),
+#endif
+#if defined (EPROTOTYPE)
+ ENTRY(EPROTOTYPE, "EPROTOTYPE", "Protocol wrong type for socket"),
+#endif
+#if defined (ENOPROTOOPT)
+ ENTRY(ENOPROTOOPT, "ENOPROTOOPT", "Protocol not available"),
+#endif
+#if defined (EPROTONOSUPPORT)
+ ENTRY(EPROTONOSUPPORT, "EPROTONOSUPPORT", "Protocol not supported"),
+#endif
+#if defined (ESOCKTNOSUPPORT)
+ ENTRY(ESOCKTNOSUPPORT, "ESOCKTNOSUPPORT", "Socket type not supported"),
+#endif
+#if defined (EOPNOTSUPP)
+ ENTRY(EOPNOTSUPP, "EOPNOTSUPP", "Operation not supported on transport endpoint"),
+#endif
+#if defined (EPFNOSUPPORT)
+ ENTRY(EPFNOSUPPORT, "EPFNOSUPPORT", "Protocol family not supported"),
+#endif
+#if defined (EAFNOSUPPORT)
+ ENTRY(EAFNOSUPPORT, "EAFNOSUPPORT", "Address family not supported by protocol"),
+#endif
+#if defined (EADDRINUSE)
+ ENTRY(EADDRINUSE, "EADDRINUSE", "Address already in use"),
+#endif
+#if defined (EADDRNOTAVAIL)
+ ENTRY(EADDRNOTAVAIL, "EADDRNOTAVAIL","Cannot assign requested address"),
+#endif
+#if defined (ENETDOWN)
+ ENTRY(ENETDOWN, "ENETDOWN", "Network is down"),
+#endif
+#if defined (ENETUNREACH)
+ ENTRY(ENETUNREACH, "ENETUNREACH", "Network is unreachable"),
+#endif
+#if defined (ENETRESET)
+ ENTRY(ENETRESET, "ENETRESET", "Network dropped connection because of reset"),
+#endif
+#if defined (ECONNABORTED)
+ ENTRY(ECONNABORTED, "ECONNABORTED", "Software caused connection abort"),
+#endif
+#if defined (ECONNRESET)
+ ENTRY(ECONNRESET, "ECONNRESET", "Connection reset by peer"),
+#endif
+#if defined (ENOBUFS)
+ ENTRY(ENOBUFS, "ENOBUFS", "No buffer space available"),
+#endif
+#if defined (EISCONN)
+ ENTRY(EISCONN, "EISCONN", "Transport endpoint is already connected"),
+#endif
+#if defined (ENOTCONN)
+ ENTRY(ENOTCONN, "ENOTCONN", "Transport endpoint is not connected"),
+#endif
+#if defined (ESHUTDOWN)
+ ENTRY(ESHUTDOWN, "ESHUTDOWN", "Cannot send after transport endpoint shutdown"),
+#endif
+#if defined (ETOOMANYREFS)
+ ENTRY(ETOOMANYREFS, "ETOOMANYREFS", "Too many references: cannot splice"),
+#endif
+#if defined (ETIMEDOUT)
+ ENTRY(ETIMEDOUT, "ETIMEDOUT", "Connection timed out"),
+#endif
+#if defined (ECONNREFUSED)
+ ENTRY(ECONNREFUSED, "ECONNREFUSED", "Connection refused"),
+#endif
+#if defined (EHOSTDOWN)
+ ENTRY(EHOSTDOWN, "EHOSTDOWN", "Host is down"),
+#endif
+#if defined (EHOSTUNREACH)
+ ENTRY(EHOSTUNREACH, "EHOSTUNREACH", "No route to host"),
+#endif
+#if defined (EALREADY)
+ ENTRY(EALREADY, "EALREADY", "Operation already in progress"),
+#endif
+#if defined (EINPROGRESS)
+ ENTRY(EINPROGRESS, "EINPROGRESS", "Operation now in progress"),
+#endif
+#if defined (ESTALE)
+ ENTRY(ESTALE, "ESTALE", "Stale NFS file handle"),
+#endif
+#if defined (EUCLEAN)
+ ENTRY(EUCLEAN, "EUCLEAN", "Structure needs cleaning"),
+#endif
+#if defined (ENOTNAM)
+ ENTRY(ENOTNAM, "ENOTNAM", "Not a XENIX named type file"),
+#endif
+#if defined (ENAVAIL)
+ ENTRY(ENAVAIL, "ENAVAIL", "No XENIX semaphores available"),
+#endif
+#if defined (EISNAM)
+ ENTRY(EISNAM, "EISNAM", "Is a named type file"),
+#endif
+#if defined (EREMOTEIO)
+ ENTRY(EREMOTEIO, "EREMOTEIO", "Remote I/O error"),
+#endif
+ ENTRY(0, NULL, NULL)
+};
+
+/* Translation table allocated and initialized at runtime. Indexed by the
+ errno value to find the equivalent symbolic value. */
+
+static const char **error_names;
+static int num_error_names = 0;
+
+/* Translation table allocated and initialized at runtime, if it does not
+ already exist in the host environment. Indexed by the errno value to find
+ the descriptive string.
+
+ We don't export it for use in other modules because even though it has the
+ same name, it differs from other implementations in that it is dynamically
+ initialized rather than statically initialized. */
+
+#ifdef NEED_sys_errlist
+
+static int sys_nerr;
+static const char **sys_errlist;
+
+#else
+
+extern int sys_nerr;
+extern char *sys_errlist[];
+
+#endif
+
+
+/*
+
+NAME
+
+ init_error_tables -- initialize the name and message tables
+
+SYNOPSIS
+
+ static void init_error_tables ();
+
+DESCRIPTION
+
+ Using the error_table, which is initialized at compile time, generate
+ the error_names and the sys_errlist (if needed) tables, which are
+ indexed at runtime by a specific errno value.
+
+BUGS
+
+ The initialization of the tables may fail under low memory conditions,
+ in which case we don't do anything particularly useful, but we don't
+ bomb either. Who knows, it might succeed at a later point if we free
+ some memory in the meantime. In any case, the other routines know
+ how to deal with lack of a table after trying to initialize it. This
+ may or may not be considered to be a bug, that we don't specifically
+ warn about this particular failure mode.
+
+*/
+
+static void
+init_error_tables ()
+{
+ const struct error_info *eip;
+ int nbytes;
+
+ /* If we haven't already scanned the error_table once to find the maximum
+ errno value, then go find it now. */
+
+ if (num_error_names == 0)
+ {
+ for (eip = error_table; eip -> name != NULL; eip++)
+ {
+ if (eip -> value >= num_error_names)
+ {
+ num_error_names = eip -> value + 1;
+ }
+ }
+ }
+
+ /* Now attempt to allocate the error_names table, zero it out, and then
+ initialize it from the statically initialized error_table. */
+
+ if (error_names == NULL)
+ {
+ nbytes = num_error_names * sizeof (char *);
+ if ((error_names = (const char **) malloc (nbytes)) != NULL)
+ {
+ memset (error_names, 0, nbytes);
+ for (eip = error_table; eip -> name != NULL; eip++)
+ {
+ error_names[eip -> value] = eip -> name;
+ }
+ }
+ }
+
+#ifdef NEED_sys_errlist
+
+ /* Now attempt to allocate the sys_errlist table, zero it out, and then
+ initialize it from the statically initialized error_table. */
+
+ if (sys_errlist == NULL)
+ {
+ nbytes = num_error_names * sizeof (char *);
+ if ((sys_errlist = (const char **) malloc (nbytes)) != NULL)
+ {
+ memset (sys_errlist, 0, nbytes);
+ sys_nerr = num_error_names;
+ for (eip = error_table; eip -> name != NULL; eip++)
+ {
+ sys_errlist[eip -> value] = eip -> msg;
+ }
+ }
+ }
+
+#endif
+
+}
+
+/*
+
+NAME
+
+ errno_max -- return the max errno value
+
+SYNOPSIS
+
+ int errno_max ();
+
+DESCRIPTION
+
+ Returns the maximum errno value for which a corresponding symbolic
+ name or message is available. Note that in the case where
+ we use the sys_errlist supplied by the system, it is possible for
+ there to be more symbolic names than messages, or vice versa.
+ In fact, the manual page for perror(3C) explicitly warns that one
+ should check the size of the table (sys_nerr) before indexing it,
+ since new error codes may be added to the system before they are
+ added to the table. Thus sys_nerr might be smaller than value
+ implied by the largest errno value defined in <errno.h>.
+
+ We return the maximum value that can be used to obtain a meaningful
+ symbolic name or message.
+
+*/
+
+int
+errno_max ()
+{
+ int maxsize;
+
+ if (error_names == NULL)
+ {
+ init_error_tables ();
+ }
+ maxsize = MAX (sys_nerr, num_error_names);
+ return (maxsize - 1);
+}
+
+#ifdef NEED_strerror
+
+/*
+
+NAME
+
+ strerror -- map an error number to an error message string
+
+SYNOPSIS
+
+ char *strerror (int errnoval)
+
+DESCRIPTION
+
+ Maps an errno number to an error message string, the contents of
+ which are implementation defined. On systems which have the external
+ variables sys_nerr and sys_errlist, these strings will be the same
+ as the ones used by perror().
+
+ If the supplied error number is within the valid range of indices
+ for the sys_errlist, but no message is available for the particular
+ error number, then returns the string "Error NUM", where NUM is the
+ error number.
+
+ If the supplied error number is not a valid index into sys_errlist,
+ returns NULL.
+
+ The returned string is only guaranteed to be valid only until the
+ next call to strerror.
+
+*/
+
+char *
+strerror (errnoval)
+ int errnoval;
+{
+ char *msg;
+ static char buf[32];
+
+#ifdef NEED_sys_errlist
+
+ if (error_names == NULL)
+ {
+ init_error_tables ();
+ }
+
+#endif
+
+ if ((errnoval < 0) || (errnoval >= sys_nerr))
+ {
+ /* Out of range, just return NULL */
+ msg = NULL;
+ }
+ else if ((sys_errlist == NULL) || (sys_errlist[errnoval] == NULL))
+ {
+ /* In range, but no sys_errlist or no entry at this index. */
+ sprintf (buf, "Error %d", errnoval);
+ msg = buf;
+ }
+ else
+ {
+ /* In range, and a valid message. Just return the message. */
+ msg = (char *) sys_errlist[errnoval];
+ }
+
+ return (msg);
+}
+
+#endif /* NEED_strerror */
+
+
+/*
+
+NAME
+
+ strerrno -- map an error number to a symbolic name string
+
+SYNOPSIS
+
+ const char *strerrno (int errnoval)
+
+DESCRIPTION
+
+ Given an error number returned from a system call (typically
+ returned in errno), returns a pointer to a string containing the
+ symbolic name of that error number, as found in <errno.h>.
+
+ If the supplied error number is within the valid range of indices
+ for symbolic names, but no name is available for the particular
+ error number, then returns the string "Error NUM", where NUM is
+ the error number.
+
+ If the supplied error number is not within the range of valid
+ indices, then returns NULL.
+
+BUGS
+
+ The contents of the location pointed to are only guaranteed to be
+ valid until the next call to strerrno.
+
+*/
+
+const char *
+strerrno (errnoval)
+ int errnoval;
+{
+ const char *name;
+ static char buf[32];
+
+ if (error_names == NULL)
+ {
+ init_error_tables ();
+ }
+
+ if ((errnoval < 0) || (errnoval >= num_error_names))
+ {
+ /* Out of range, just return NULL */
+ name = NULL;
+ }
+ else if ((error_names == NULL) || (error_names[errnoval] == NULL))
+ {
+ /* In range, but no error_names or no entry at this index. */
+ sprintf (buf, "Error %d", errnoval);
+ name = (const char *) buf;
+ }
+ else
+ {
+ /* In range, and a valid name. Just return the name. */
+ name = error_names[errnoval];
+ }
+
+ return (name);
+}
+
+/*
+
+NAME
+
+ strtoerrno -- map a symbolic errno name to a numeric value
+
+SYNOPSIS
+
+ int strtoerrno (char *name)
+
+DESCRIPTION
+
+ Given the symbolic name of a error number, map it to an errno value.
+ If no translation is found, returns 0.
+
+*/
+
+int
+strtoerrno (name)
+ const char *name;
+{
+ int errnoval = 0;
+
+ if (name != NULL)
+ {
+ if (error_names == NULL)
+ {
+ init_error_tables ();
+ }
+ for (errnoval = 0; errnoval < num_error_names; errnoval++)
+ {
+ if ((error_names[errnoval] != NULL) &&
+ (strcmp (name, error_names[errnoval]) == 0))
+ {
+ break;
+ }
+ }
+ if (errnoval == num_error_names)
+ {
+ errnoval = 0;
+ }
+ }
+ return (errnoval);
+}
+
+
+/* A simple little main that does nothing but print all the errno translations
+ if MAIN is defined and this file is compiled and linked. */
+
+#ifdef MAIN
+
+#include <stdio.h>
+
+int
+main ()
+{
+ int errn;
+ int errnmax;
+ const char *name;
+ char *msg;
+ char *strerror ();
+
+ errnmax = errno_max ();
+ printf ("%d entries in names table.\n", num_error_names);
+ printf ("%d entries in messages table.\n", sys_nerr);
+ printf ("%d is max useful index.\n", errnmax);
+
+ /* Keep printing values until we get to the end of *both* tables, not
+ *either* table. Note that knowing the maximum useful index does *not*
+ relieve us of the responsibility of testing the return pointer for
+ NULL. */
+
+ for (errn = 0; errn <= errnmax; errn++)
+ {
+ name = strerrno (errn);
+ name = (name == NULL) ? "<NULL>" : name;
+ msg = strerror (errn);
+ msg = (msg == NULL) ? "<NULL>" : msg;
+ printf ("%-4d%-18s%s\n", errn, name, msg);
+ }
+
+ return 0;
+}
+
+#endif
diff --git a/gnu/usr.bin/gdb/libiberty/strsignal.c b/gnu/usr.bin/gdb/libiberty/strsignal.c
new file mode 100644
index 0000000..815af83
--- /dev/null
+++ b/gnu/usr.bin/gdb/libiberty/strsignal.c
@@ -0,0 +1,643 @@
+/* Extended support for using signal values.
+ Copyright (C) 1992 Free Software Foundation, Inc.
+ Written by Fred Fish. fnf@cygnus.com
+
+This file is part of the libiberty library.
+Libiberty is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public
+License as published by the Free Software Foundation; either
+version 2 of the License, or (at your option) any later version.
+
+Libiberty is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with libiberty; see the file COPYING.LIB. If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA. */
+
+#include "ansidecl.h"
+#include "libiberty.h"
+
+#include "config.h"
+
+#ifdef LOSING_SYS_SIGLIST
+#define sys_siglist no_such_symbol
+#endif
+
+#include <stdio.h>
+#include <signal.h>
+
+/* Routines imported from standard C runtime libraries. */
+
+#ifdef __STDC__
+#include <stddef.h>
+extern void *malloc (size_t size); /* 4.10.3.3 */
+extern void *memset (void *s, int c, size_t n); /* 4.11.6.1 */
+#else /* !__STDC__ */
+extern char *malloc (); /* Standard memory allocater */
+extern char *memset ();
+#endif /* __STDC__ */
+
+#ifdef LOSING_SYS_SIGLIST
+#undef sys_siglist
+#endif
+
+
+#ifndef NULL
+# ifdef __STDC__
+# define NULL (void *) 0
+# else
+# define NULL 0
+# endif
+#endif
+
+#ifndef MAX
+# define MAX(a,b) ((a) > (b) ? (a) : (b))
+#endif
+
+/* Translation table for signal values.
+
+ Note that this table is generally only accessed when it is used at runtime
+ to initialize signal name and message tables that are indexed by signal
+ value.
+
+ Not all of these signals will exist on all systems. This table is the only
+ thing that should have to be updated as new signal numbers are introduced.
+ It's sort of ugly, but at least its portable. */
+
+struct signal_info
+{
+ int value; /* The numeric value from <signal.h> */
+ const char *name; /* The equivalent symbolic value */
+#ifdef NEED_sys_siglist
+ const char *msg; /* Short message about this value */
+#endif
+};
+
+#ifdef NEED_sys_siglist
+# define ENTRY(value, name, msg) {value, name, msg}
+#else
+# define ENTRY(value, name, msg) {value, name}
+#endif
+
+static const struct signal_info signal_table[] =
+{
+#if defined (SIGHUP)
+ ENTRY(SIGHUP, "SIGHUP", "Hangup"),
+#endif
+#if defined (SIGINT)
+ ENTRY(SIGINT, "SIGINT", "Interrupt"),
+#endif
+#if defined (SIGQUIT)
+ ENTRY(SIGQUIT, "SIGQUIT", "Quit"),
+#endif
+#if defined (SIGILL)
+ ENTRY(SIGILL, "SIGILL", "Illegal instruction"),
+#endif
+#if defined (SIGTRAP)
+ ENTRY(SIGTRAP, "SIGTRAP", "Trace/breakpoint trap"),
+#endif
+/* Put SIGIOT before SIGABRT, so that if SIGIOT==SIGABRT then SIGABRT
+ overrides SIGIOT. SIGABRT is in ANSI and POSIX.1, and SIGIOT isn't. */
+#if defined (SIGIOT)
+ ENTRY(SIGIOT, "SIGIOT", "IOT trap"),
+#endif
+#if defined (SIGABRT)
+ ENTRY(SIGABRT, "SIGABRT", "Aborted"),
+#endif
+#if defined (SIGEMT)
+ ENTRY(SIGEMT, "SIGEMT", "Emulation trap"),
+#endif
+#if defined (SIGFPE)
+ ENTRY(SIGFPE, "SIGFPE", "Arithmetic exception"),
+#endif
+#if defined (SIGKILL)
+ ENTRY(SIGKILL, "SIGKILL", "Killed"),
+#endif
+#if defined (SIGBUS)
+ ENTRY(SIGBUS, "SIGBUS", "Bus error"),
+#endif
+#if defined (SIGSEGV)
+ ENTRY(SIGSEGV, "SIGSEGV", "Segmentation fault"),
+#endif
+#if defined (SIGSYS)
+ ENTRY(SIGSYS, "SIGSYS", "Bad system call"),
+#endif
+#if defined (SIGPIPE)
+ ENTRY(SIGPIPE, "SIGPIPE", "Broken pipe"),
+#endif
+#if defined (SIGALRM)
+ ENTRY(SIGALRM, "SIGALRM", "Alarm clock"),
+#endif
+#if defined (SIGTERM)
+ ENTRY(SIGTERM, "SIGTERM", "Terminated"),
+#endif
+#if defined (SIGUSR1)
+ ENTRY(SIGUSR1, "SIGUSR1", "User defined signal 1"),
+#endif
+#if defined (SIGUSR2)
+ ENTRY(SIGUSR2, "SIGUSR2", "User defined signal 2"),
+#endif
+/* Put SIGCLD before SIGCHLD, so that if SIGCLD==SIGCHLD then SIGCHLD
+ overrides SIGCLD. SIGCHLD is in POXIX.1 */
+#if defined (SIGCLD)
+ ENTRY(SIGCLD, "SIGCLD", "Child status changed"),
+#endif
+#if defined (SIGCHLD)
+ ENTRY(SIGCHLD, "SIGCHLD", "Child status changed"),
+#endif
+#if defined (SIGPWR)
+ ENTRY(SIGPWR, "SIGPWR", "Power fail/restart"),
+#endif
+#if defined (SIGWINCH)
+ ENTRY(SIGWINCH, "SIGWINCH", "Window size changed"),
+#endif
+#if defined (SIGURG)
+ ENTRY(SIGURG, "SIGURG", "Urgent I/O condition"),
+#endif
+#if defined (SIGIO)
+ /* "I/O pending" has also been suggested, but is misleading since the
+ signal only happens when the process has asked for it, not everytime
+ I/O is pending. */
+ ENTRY(SIGIO, "SIGIO", "I/O possible"),
+#endif
+#if defined (SIGPOLL)
+ ENTRY(SIGPOLL, "SIGPOLL", "Pollable event occurred"),
+#endif
+#if defined (SIGSTOP)
+ ENTRY(SIGSTOP, "SIGSTOP", "Stopped (signal)"),
+#endif
+#if defined (SIGTSTP)
+ ENTRY(SIGTSTP, "SIGTSTP", "Stopped (user)"),
+#endif
+#if defined (SIGCONT)
+ ENTRY(SIGCONT, "SIGCONT", "Continued"),
+#endif
+#if defined (SIGTTIN)
+ ENTRY(SIGTTIN, "SIGTTIN", "Stopped (tty input)"),
+#endif
+#if defined (SIGTTOU)
+ ENTRY(SIGTTOU, "SIGTTOU", "Stopped (tty output)"),
+#endif
+#if defined (SIGVTALRM)
+ ENTRY(SIGVTALRM, "SIGVTALRM", "Virtual timer expired"),
+#endif
+#if defined (SIGPROF)
+ ENTRY(SIGPROF, "SIGPROF", "Profiling timer expired"),
+#endif
+#if defined (SIGXCPU)
+ ENTRY(SIGXCPU, "SIGXCPU", "CPU time limit exceeded"),
+#endif
+#if defined (SIGXFSZ)
+ ENTRY(SIGXFSZ, "SIGXFSZ", "File size limit exceeded"),
+#endif
+#if defined (SIGWIND)
+ ENTRY(SIGWIND, "SIGWIND", "SIGWIND"),
+#endif
+#if defined (SIGPHONE)
+ ENTRY(SIGPHONE, "SIGPHONE", "SIGPHONE"),
+#endif
+#if defined (SIGLOST)
+ ENTRY(SIGLOST, "SIGLOST", "Resource lost"),
+#endif
+#if defined (SIGWAITING)
+ ENTRY(SIGWAITING, "SIGWAITING", "Process's LWPs are blocked"),
+#endif
+#if defined (SIGLWP)
+ ENTRY(SIGLWP, "SIGLWP", "Signal LWP"),
+#endif
+#if defined (SIGDANGER)
+ ENTRY(SIGDANGER, "SIGDANGER", "Swap space dangerously low"),
+#endif
+#if defined (SIGGRANT)
+ ENTRY(SIGGRANT, "SIGGRANT", "Monitor mode granted"),
+#endif
+#if defined (SIGRETRACT)
+ ENTRY(SIGRETRACT, "SIGRETRACT", "Need to relinguish monitor mode"),
+#endif
+#if defined (SIGMSG)
+ ENTRY(SIGMSG, "SIGMSG", "Monitor mode data available"),
+#endif
+#if defined (SIGSOUND)
+ ENTRY(SIGSOUND, "SIGSOUND", "Sound completed"),
+#endif
+#if defined (SIGSAK)
+ ENTRY(SIGSAK, "SIGSAK", "Secure attention"),
+#endif
+ ENTRY(0, NULL, NULL)
+};
+
+/* Translation table allocated and initialized at runtime. Indexed by the
+ signal value to find the equivalent symbolic value. */
+
+static const char **signal_names;
+static int num_signal_names = 0;
+
+/* Translation table allocated and initialized at runtime, if it does not
+ already exist in the host environment. Indexed by the signal value to find
+ the descriptive string.
+
+ We don't export it for use in other modules because even though it has the
+ same name, it differs from other implementations in that it is dynamically
+ initialized rather than statically initialized. */
+
+#ifdef NEED_sys_siglist
+
+static int sys_nsig;
+static const char **sys_siglist;
+
+#else
+
+static int sys_nsig = NSIG;
+extern const char * const sys_siglist[];
+
+#endif
+
+
+/*
+
+NAME
+
+ init_signal_tables -- initialize the name and message tables
+
+SYNOPSIS
+
+ static void init_signal_tables ();
+
+DESCRIPTION
+
+ Using the signal_table, which is initialized at compile time, generate
+ the signal_names and the sys_siglist (if needed) tables, which are
+ indexed at runtime by a specific signal value.
+
+BUGS
+
+ The initialization of the tables may fail under low memory conditions,
+ in which case we don't do anything particularly useful, but we don't
+ bomb either. Who knows, it might succeed at a later point if we free
+ some memory in the meantime. In any case, the other routines know
+ how to deal with lack of a table after trying to initialize it. This
+ may or may not be considered to be a bug, that we don't specifically
+ warn about this particular failure mode.
+
+*/
+
+static void
+init_signal_tables ()
+{
+ const struct signal_info *eip;
+ int nbytes;
+
+ /* If we haven't already scanned the signal_table once to find the maximum
+ signal value, then go find it now. */
+
+ if (num_signal_names == 0)
+ {
+ for (eip = signal_table; eip -> name != NULL; eip++)
+ {
+ if (eip -> value >= num_signal_names)
+ {
+ num_signal_names = eip -> value + 1;
+ }
+ }
+ }
+
+ /* Now attempt to allocate the signal_names table, zero it out, and then
+ initialize it from the statically initialized signal_table. */
+
+ if (signal_names == NULL)
+ {
+ nbytes = num_signal_names * sizeof (char *);
+ if ((signal_names = (const char **) malloc (nbytes)) != NULL)
+ {
+ memset (signal_names, 0, nbytes);
+ for (eip = signal_table; eip -> name != NULL; eip++)
+ {
+ signal_names[eip -> value] = eip -> name;
+ }
+ }
+ }
+
+#ifdef NEED_sys_siglist
+
+ /* Now attempt to allocate the sys_siglist table, zero it out, and then
+ initialize it from the statically initialized signal_table. */
+
+ if (sys_siglist == NULL)
+ {
+ nbytes = num_signal_names * sizeof (char *);
+ if ((sys_siglist = (const char **) malloc (nbytes)) != NULL)
+ {
+ memset (sys_siglist, 0, nbytes);
+ sys_nsig = num_signal_names;
+ for (eip = signal_table; eip -> name != NULL; eip++)
+ {
+ sys_siglist[eip -> value] = eip -> msg;
+ }
+ }
+ }
+
+#endif
+
+}
+
+
+/*
+
+NAME
+
+ signo_max -- return the max signo value
+
+SYNOPSIS
+
+ int signo_max ();
+
+DESCRIPTION
+
+ Returns the maximum signo value for which a corresponding symbolic
+ name or message is available. Note that in the case where
+ we use the sys_siglist supplied by the system, it is possible for
+ there to be more symbolic names than messages, or vice versa.
+ In fact, the manual page for psignal(3b) explicitly warns that one
+ should check the size of the table (NSIG) before indexing it,
+ since new signal codes may be added to the system before they are
+ added to the table. Thus NSIG might be smaller than value
+ implied by the largest signo value defined in <signal.h>.
+
+ We return the maximum value that can be used to obtain a meaningful
+ symbolic name or message.
+
+*/
+
+int
+signo_max ()
+{
+ int maxsize;
+
+ if (signal_names == NULL)
+ {
+ init_signal_tables ();
+ }
+ maxsize = MAX (sys_nsig, num_signal_names);
+ return (maxsize - 1);
+}
+
+
+/*
+
+NAME
+
+ strsignal -- map a signal number to a signal message string
+
+SYNOPSIS
+
+ const char *strsignal (int signo)
+
+DESCRIPTION
+
+ Maps an signal number to an signal message string, the contents of
+ which are implementation defined. On systems which have the external
+ variable sys_siglist, these strings will be the same as the ones used
+ by psignal().
+
+ If the supplied signal number is within the valid range of indices
+ for the sys_siglist, but no message is available for the particular
+ signal number, then returns the string "Signal NUM", where NUM is the
+ signal number.
+
+ If the supplied signal number is not a valid index into sys_siglist,
+ returns NULL.
+
+ The returned string is only guaranteed to be valid only until the
+ next call to strsignal.
+
+*/
+
+const char *
+strsignal (signo)
+ int signo;
+{
+ const char *msg;
+ static char buf[32];
+
+#ifdef NEED_sys_siglist
+
+ if (signal_names == NULL)
+ {
+ init_signal_tables ();
+ }
+
+#endif
+
+ if ((signo < 0) || (signo >= sys_nsig))
+ {
+ /* Out of range, just return NULL */
+ msg = NULL;
+ }
+ else if ((sys_siglist == NULL) || (sys_siglist[signo] == NULL))
+ {
+ /* In range, but no sys_siglist or no entry at this index. */
+ sprintf (buf, "Signal %d", signo);
+ msg = (const char *) buf;
+ }
+ else
+ {
+ /* In range, and a valid message. Just return the message. */
+ msg = (const char *) sys_siglist[signo];
+ }
+
+ return (msg);
+}
+
+
+/*
+
+NAME
+
+ strsigno -- map an signal number to a symbolic name string
+
+SYNOPSIS
+
+ const char *strsigno (int signo)
+
+DESCRIPTION
+
+ Given an signal number, returns a pointer to a string containing
+ the symbolic name of that signal number, as found in <signal.h>.
+
+ If the supplied signal number is within the valid range of indices
+ for symbolic names, but no name is available for the particular
+ signal number, then returns the string "Signal NUM", where NUM is
+ the signal number.
+
+ If the supplied signal number is not within the range of valid
+ indices, then returns NULL.
+
+BUGS
+
+ The contents of the location pointed to are only guaranteed to be
+ valid until the next call to strsigno.
+
+*/
+
+const char *
+strsigno (signo)
+ int signo;
+{
+ const char *name;
+ static char buf[32];
+
+ if (signal_names == NULL)
+ {
+ init_signal_tables ();
+ }
+
+ if ((signo < 0) || (signo >= num_signal_names))
+ {
+ /* Out of range, just return NULL */
+ name = NULL;
+ }
+ else if ((signal_names == NULL) || (signal_names[signo] == NULL))
+ {
+ /* In range, but no signal_names or no entry at this index. */
+ sprintf (buf, "Signal %d", signo);
+ name = (const char *) buf;
+ }
+ else
+ {
+ /* In range, and a valid name. Just return the name. */
+ name = signal_names[signo];
+ }
+
+ return (name);
+}
+
+
+/*
+
+NAME
+
+ strtosigno -- map a symbolic signal name to a numeric value
+
+SYNOPSIS
+
+ int strtosigno (char *name)
+
+DESCRIPTION
+
+ Given the symbolic name of a signal, map it to a signal number.
+ If no translation is found, returns 0.
+
+*/
+
+int
+strtosigno (name)
+ const char *name;
+{
+ int signo = 0;
+
+ if (name != NULL)
+ {
+ if (signal_names == NULL)
+ {
+ init_signal_tables ();
+ }
+ for (signo = 0; signo < num_signal_names; signo++)
+ {
+ if ((signal_names[signo] != NULL) &&
+ (strcmp (name, signal_names[signo]) == 0))
+ {
+ break;
+ }
+ }
+ if (signo == num_signal_names)
+ {
+ signo = 0;
+ }
+ }
+ return (signo);
+}
+
+
+/*
+
+NAME
+
+ psignal -- print message about signal to stderr
+
+SYNOPSIS
+
+ void psignal (unsigned signo, char *message);
+
+DESCRIPTION
+
+ Print to the standard error the message, followed by a colon,
+ followed by the description of the signal specified by signo,
+ followed by a newline.
+*/
+
+#ifdef NEED_psignal
+
+void
+psignal (signo, message)
+ unsigned signo;
+ char *message;
+{
+ if (signal_names == NULL)
+ {
+ init_signal_tables ();
+ }
+ if ((signo <= 0) || (signo >= sys_nsig))
+ {
+ fprintf (stderr, "%s: unknown signal\n", message);
+ }
+ else
+ {
+ fprintf (stderr, "%s: %s\n", message, sys_siglist[signo]);
+ }
+}
+
+#endif /* NEED_psignal */
+
+
+/* A simple little main that does nothing but print all the signal translations
+ if MAIN is defined and this file is compiled and linked. */
+
+#ifdef MAIN
+
+#include <stdio.h>
+
+int
+main ()
+{
+ int signo;
+ int maxsigno;
+ const char *name;
+ const char *msg;
+
+ maxsigno = signo_max ();
+ printf ("%d entries in names table.\n", num_signal_names);
+ printf ("%d entries in messages table.\n", sys_nsig);
+ printf ("%d is max useful index.\n", maxsigno);
+
+ /* Keep printing values until we get to the end of *both* tables, not
+ *either* table. Note that knowing the maximum useful index does *not*
+ relieve us of the responsibility of testing the return pointer for
+ NULL. */
+
+ for (signo = 0; signo <= maxsigno; signo++)
+ {
+ name = strsigno (signo);
+ name = (name == NULL) ? "<NULL>" : name;
+ msg = strsignal (signo);
+ msg = (msg == NULL) ? "<NULL>" : msg;
+ printf ("%-4d%-18s%s\n", signo, name, msg);
+ }
+
+ return 0;
+}
+
+#endif
diff --git a/gnu/usr.bin/gdb/libiberty/vasprintf.c b/gnu/usr.bin/gdb/libiberty/vasprintf.c
new file mode 100644
index 0000000..b3ba0ca
--- /dev/null
+++ b/gnu/usr.bin/gdb/libiberty/vasprintf.c
@@ -0,0 +1,139 @@
+/* Like vsprintf but provides a pointer to malloc'd storage, which must
+ be freed by the caller.
+ Copyright (C) 1994 Free Software Foundation, Inc.
+
+This file is part of the libiberty library.
+Libiberty is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public
+License as published by the Free Software Foundation; either
+version 2 of the License, or (at your option) any later version.
+
+Libiberty is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with libiberty; see the file COPYING.LIB. If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA. */
+
+#include <stdio.h>
+#include <varargs.h>
+
+#ifdef TEST
+int global_total_width;
+#endif
+
+unsigned long strtoul ();
+char *malloc ();
+
+int
+vasprintf (result, format, args)
+ char **result;
+ char *format;
+ va_list args;
+{
+ char *p = format;
+ /* Add one to make sure that it is never zero, which might cause malloc
+ to return NULL. */
+ int total_width = strlen (format) + 1;
+ va_list ap = args;
+
+ while (*p != '\0')
+ {
+ if (*p++ == '%')
+ {
+ while (strchr ("-+ #0", *p))
+ ++p;
+ if (*p == '*')
+ {
+ ++p;
+ total_width += abs (va_arg (ap, int));
+ }
+ else
+ total_width += strtoul (p, &p, 10);
+ if (*p == '.')
+ {
+ ++p;
+ if (*p == '*')
+ {
+ ++p;
+ total_width += abs (va_arg (ap, int));
+ }
+ else
+ total_width += strtoul (p, &p, 10);
+ }
+ while (strchr ("hlL", *p))
+ ++p;
+ /* Should be big enough for any format specifier except %s. */
+ total_width += 30;
+ switch (*p)
+ {
+ case 'd':
+ case 'i':
+ case 'o':
+ case 'u':
+ case 'x':
+ case 'X':
+ case 'c':
+ va_arg (ap, int);
+ break;
+ case 'f':
+ case 'e':
+ case 'E':
+ case 'g':
+ case 'G':
+ va_arg (ap, double);
+ break;
+ case 's':
+ total_width += strlen (va_arg (ap, char *));
+ break;
+ case 'p':
+ case 'n':
+ va_arg (ap, char *);
+ break;
+ }
+ }
+ }
+#ifdef TEST
+ global_total_width = total_width;
+#endif
+ *result = malloc (total_width);
+ if (*result != NULL)
+ return vsprintf (*result, format, args);
+ else
+ return 0;
+}
+
+#ifdef TEST
+void
+checkit (va_alist)
+ va_dcl
+{
+ va_list args;
+ char *format;
+ char *result;
+
+ va_start (args);
+ format = va_arg (args, char *);
+ vasprintf (&result, format, args);
+ if (strlen (result) < global_total_width)
+ printf ("PASS: ");
+ else
+ printf ("FAIL: ");
+ printf ("%d %s\n", global_total_width, result);
+}
+
+int
+main ()
+{
+ checkit ("%d", 0x12345678);
+ checkit ("%200d", 5);
+ checkit ("%.300d", 6);
+ checkit ("%100.150d", 7);
+ checkit ("%s", "jjjjjjjjjiiiiiiiiiiiiiiioooooooooooooooooppppppppppppaa\n\
+777777777777777777333333333333366666666666622222222222777777777777733333");
+ checkit ("%f%s%d%s", 1.0, "foo", 77, "asdjffffffffffffffiiiiiiiiiiixxxxx");
+}
+#endif /* TEST */
diff --git a/gnu/usr.bin/gdb/libiberty/xmalloc.c b/gnu/usr.bin/gdb/libiberty/xmalloc.c
new file mode 100644
index 0000000..a750339
--- /dev/null
+++ b/gnu/usr.bin/gdb/libiberty/xmalloc.c
@@ -0,0 +1,85 @@
+/* memory allocation routines with error checking.
+ Copyright 1989, 90, 91, 92, 93, 94 Free Software Foundation, Inc.
+
+This file is part of the libiberty library.
+Libiberty is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public
+License as published by the Free Software Foundation; either
+version 2 of the License, or (at your option) any later version.
+
+Libiberty is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with libiberty; see the file COPYING.LIB. If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA. */
+
+#include "ansidecl.h"
+#include "libiberty.h"
+
+#include <stdio.h>
+
+#ifdef __STDC__
+#include <stddef.h>
+#else
+#define size_t unsigned long
+#endif
+
+/* For systems with larger pointers than ints, these must be declared. */
+PTR malloc PARAMS ((size_t));
+PTR realloc PARAMS ((PTR, size_t));
+
+/* The program name if set. */
+static const char *name = "";
+
+void
+xmalloc_set_program_name (s)
+ const char *s;
+{
+ name = s;
+}
+
+PTR
+xmalloc (size)
+ size_t size;
+{
+ PTR newmem;
+
+ if (size == 0)
+ size = 1;
+ newmem = malloc (size);
+ if (!newmem)
+ {
+ fprintf (stderr, "\n%s%sCan not allocate %lu bytes\n",
+ name, *name ? ": " : "",
+ (unsigned long) size);
+ xexit (1);
+ }
+ return (newmem);
+}
+
+PTR
+xrealloc (oldmem, size)
+ PTR oldmem;
+ size_t size;
+{
+ PTR newmem;
+
+ if (size == 0)
+ size = 1;
+ if (!oldmem)
+ newmem = malloc (size);
+ else
+ newmem = realloc (oldmem, size);
+ if (!newmem)
+ {
+ fprintf (stderr, "\n%s%sCan not reallocate %lu bytes\n",
+ name, *name ? ": " : "",
+ (unsigned long) size);
+ xexit (1);
+ }
+ return (newmem);
+}
diff --git a/gnu/usr.bin/gdb/mmalloc/COPYING.LIB b/gnu/usr.bin/gdb/mmalloc/COPYING.LIB
new file mode 100644
index 0000000..eb685a5
--- /dev/null
+++ b/gnu/usr.bin/gdb/mmalloc/COPYING.LIB
@@ -0,0 +1,481 @@
+ GNU LIBRARY GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1991 Free Software Foundation, Inc.
+ 675 Mass Ave, Cambridge, MA 02139, USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the library GPL. It is
+ numbered 2 because it goes with version 2 of the ordinary GPL.]
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+ This license, the Library General Public License, applies to some
+specially designated Free Software Foundation software, and to any
+other libraries whose authors decide to use it. You can use it for
+your libraries, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if
+you distribute copies of the library, or if you modify it.
+
+ For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you. You must make sure that they, too, receive or can get the source
+code. If you link a program with the library, you must provide
+complete object files to the recipients so that they can relink them
+with the library, after making changes to the library and recompiling
+it. And you must show them these terms so they know their rights.
+
+ Our method of protecting your rights has two steps: (1) copyright
+the library, and (2) offer you this license which gives you legal
+permission to copy, distribute and/or modify the library.
+
+ Also, for each distributor's protection, we want to make certain
+that everyone understands that there is no warranty for this free
+library. If the library is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original
+version, so that any problems introduced by others will not reflect on
+the original authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that companies distributing free
+software will individually obtain patent licenses, thus in effect
+transforming the program into proprietary software. To prevent this,
+we have made it clear that any patent must be licensed for everyone's
+free use or not licensed at all.
+
+ Most GNU software, including some libraries, is covered by the ordinary
+GNU General Public License, which was designed for utility programs. This
+license, the GNU Library General Public License, applies to certain
+designated libraries. This license is quite different from the ordinary
+one; be sure to read it in full, and don't assume that anything in it is
+the same as in the ordinary license.
+
+ The reason we have a separate public license for some libraries is that
+they blur the distinction we usually make between modifying or adding to a
+program and simply using it. Linking a program with a library, without
+changing the library, is in some sense simply using the library, and is
+analogous to running a utility program or application program. However, in
+a textual and legal sense, the linked executable is a combined work, a
+derivative of the original library, and the ordinary General Public License
+treats it as such.
+
+ Because of this blurred distinction, using the ordinary General
+Public License for libraries did not effectively promote software
+sharing, because most developers did not use the libraries. We
+concluded that weaker conditions might promote sharing better.
+
+ However, unrestricted linking of non-free programs would deprive the
+users of those programs of all benefit from the free status of the
+libraries themselves. This Library General Public License is intended to
+permit developers of non-free programs to use free libraries, while
+preserving your freedom as a user of such programs to change the free
+libraries that are incorporated in them. (We have not seen how to achieve
+this as regards changes in header files, but we have achieved it as regards
+changes in the actual functions of the Library.) The hope is that this
+will lead to faster development of free libraries.
+
+ The precise terms and conditions for copying, distribution and
+modification follow. Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library". The
+former contains code derived from the library, while the latter only
+works together with the library.
+
+ Note that it is possible for a library to be covered by the ordinary
+General Public License rather than by this special one.
+
+ GNU LIBRARY GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License Agreement applies to any software library which
+contains a notice placed by the copyright holder or other authorized
+party saying it may be distributed under the terms of this Library
+General Public License (also called "this License"). Each licensee is
+addressed as "you".
+
+ A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+ The "Library", below, refers to any such software library or work
+which has been distributed under these terms. A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language. (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+ "Source code" for a work means the preferred form of the work for
+making modifications to it. For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+ Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it). Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+
+ 1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+ You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+
+ 2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) The modified work must itself be a software library.
+
+ b) You must cause the files modified to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ c) You must cause the whole of the work to be licensed at no
+ charge to all third parties under the terms of this License.
+
+ d) If a facility in the modified Library refers to a function or a
+ table of data to be supplied by an application program that uses
+ the facility, other than as an argument passed when the facility
+ is invoked, then you must make a good faith effort to ensure that,
+ in the event an application does not supply such function or
+ table, the facility still operates, and performs whatever part of
+ its purpose remains meaningful.
+
+ (For example, a function in a library to compute square roots has
+ a purpose that is entirely well-defined independent of the
+ application. Therefore, Subsection 2d requires that any
+ application-supplied function or table used by this function must
+ be optional: if the application does not supply it, the square
+ root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library. To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License. (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.) Do not make any other change in
+these notices.
+
+ Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+ This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+ 4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+ If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library". Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+ However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library". The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+ When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library. The
+threshold for this to be true is not precisely defined by law.
+
+ If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work. (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+ Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+
+ 6. As an exception to the Sections above, you may also compile or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+ You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License. You must supply a copy of this License. If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License. Also, you must do one
+of these things:
+
+ a) Accompany the work with the complete corresponding
+ machine-readable source code for the Library including whatever
+ changes were used in the work (which must be distributed under
+ Sections 1 and 2 above); and, if the work is an executable linked
+ with the Library, with the complete machine-readable "work that
+ uses the Library", as object code and/or source code, so that the
+ user can modify the Library and then relink to produce a modified
+ executable containing the modified Library. (It is understood
+ that the user who changes the contents of definitions files in the
+ Library will not necessarily be able to recompile the application
+ to use the modified definitions.)
+
+ b) Accompany the work with a written offer, valid for at
+ least three years, to give the same user the materials
+ specified in Subsection 6a, above, for a charge no more
+ than the cost of performing this distribution.
+
+ c) If distribution of the work is made by offering access to copy
+ from a designated place, offer equivalent access to copy the above
+ specified materials from the same place.
+
+ d) Verify that the user has already received a copy of these
+ materials or that you have already sent this user a copy.
+
+ For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it. However, as a special exception,
+the source code distributed need not include anything that is normally
+distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+ It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system. Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+
+ 7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+ a) Accompany the combined library with a copy of the same work
+ based on the Library, uncombined with any other library
+ facilities. This must be distributed under the terms of the
+ Sections above.
+
+ b) Give prominent notice with the combined library of the fact
+ that part of it is a work based on the Library, and explaining
+ where to find the accompanying uncombined form of the same work.
+
+ 8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License. Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License. However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+ 9. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Library or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+ 10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all. For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded. In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+ 13. The Free Software Foundation may publish revised and/or new
+versions of the Library General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation. If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+
+ 14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission. For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this. Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+ NO WARRANTY
+
+ 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ Appendix: How to Apply These Terms to Your New Libraries
+
+ If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change. You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+ To apply these terms, attach the following notices to the library. It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the library's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the
+ library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+ <signature of Ty Coon>, 1 April 1990
+ Ty Coon, President of Vice
+
+That's all there is to it!
diff --git a/gnu/usr.bin/gdb/mmalloc/Makefile b/gnu/usr.bin/gdb/mmalloc/Makefile
new file mode 100644
index 0000000..1ef0d1d
--- /dev/null
+++ b/gnu/usr.bin/gdb/mmalloc/Makefile
@@ -0,0 +1,10 @@
+LIB= mmalloc
+SRCS= mcalloc.c mfree.c mmalloc.c mmcheck.c mmemalign.c mmstats.c \
+ mmtrace.c mrealloc.c mvalloc.c mmap-sup.c attach.c detach.c keys.c \
+ sbrk-sup.c
+
+NOPROFILE=no
+NOPIC=no
+install:
+ @echo -n
+.include <bsd.lib.mk>
diff --git a/gnu/usr.bin/gdb/mmalloc/README.FreeBSD b/gnu/usr.bin/gdb/mmalloc/README.FreeBSD
new file mode 100644
index 0000000..544755a
--- /dev/null
+++ b/gnu/usr.bin/gdb/mmalloc/README.FreeBSD
@@ -0,0 +1,4 @@
+This is a greatly pared down libmmalloc directory. Only what's required to build
+gdb-4.13 on FreeBSD 2.0 was kept.
+
+gj@freebsd.org
diff --git a/gnu/usr.bin/gdb/mmalloc/attach.c b/gnu/usr.bin/gdb/mmalloc/attach.c
new file mode 100644
index 0000000..a1b6686
--- /dev/null
+++ b/gnu/usr.bin/gdb/mmalloc/attach.c
@@ -0,0 +1,218 @@
+/* Initialization for access to a mmap'd malloc managed region.
+ Copyright 1992 Free Software Foundation, Inc.
+
+ Contributed by Fred Fish at Cygnus Support. fnf@cygnus.com
+
+This file is part of the GNU C Library.
+
+The GNU C Library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public License as
+published by the Free Software Foundation; either version 2 of the
+License, or (at your option) any later version.
+
+The GNU C Library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with the GNU C Library; see the file COPYING.LIB. If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA. */
+
+#include <sys/types.h>
+#include <fcntl.h> /* After sys/types.h, at least for dpx/2. */
+#include <sys/stat.h>
+#include <string.h>
+#include "mmalloc.h"
+
+#ifndef SEEK_SET
+#define SEEK_SET 0
+#endif
+
+
+#if defined(HAVE_MMAP)
+
+/* Forward declarations/prototypes for local functions */
+
+static struct mdesc *reuse PARAMS ((int));
+
+/* Initialize access to a mmalloc managed region.
+
+ If FD is a valid file descriptor for an open file then data for the
+ mmalloc managed region is mapped to that file, otherwise "/dev/zero"
+ is used and the data will not exist in any filesystem object.
+
+ If the open file corresponding to FD is from a previous use of
+ mmalloc and passes some basic sanity checks to ensure that it is
+ compatible with the current mmalloc package, then it's data is
+ mapped in and is immediately accessible at the same addresses in
+ the current process as the process that created the file.
+
+ If BASEADDR is not NULL, the mapping is established starting at the
+ specified address in the process address space. If BASEADDR is NULL,
+ the mmalloc package chooses a suitable address at which to start the
+ mapped region, which will be the value of the previous mapping if
+ opening an existing file which was previously built by mmalloc, or
+ for new files will be a value chosen by mmap.
+
+ Specifying BASEADDR provides more control over where the regions
+ start and how big they can be before bumping into existing mapped
+ regions or future mapped regions.
+
+ On success, returns a "malloc descriptor" which is used in subsequent
+ calls to other mmalloc package functions. It is explicitly "void *"
+ ("char *" for systems that don't fully support void) so that users
+ of the package don't have to worry about the actual implementation
+ details.
+
+ On failure returns NULL. */
+
+PTR
+mmalloc_attach (fd, baseaddr)
+ int fd;
+ PTR baseaddr;
+{
+ struct mdesc mtemp;
+ struct mdesc *mdp;
+ PTR mbase;
+ struct stat sbuf;
+
+ /* First check to see if FD is a valid file descriptor, and if so, see
+ if the file has any current contents (size > 0). If it does, then
+ attempt to reuse the file. If we can't reuse the file, either
+ because it isn't a valid mmalloc produced file, was produced by an
+ obsolete version, or any other reason, then we fail to attach to
+ this file. */
+
+ if (fd >= 0)
+ {
+ if (fstat (fd, &sbuf) < 0)
+ {
+ return (NULL);
+ }
+ else if (sbuf.st_size > 0)
+ {
+ return ((PTR) reuse (fd));
+ }
+ }
+
+ /* We start off with the malloc descriptor allocated on the stack, until
+ we build it up enough to call _mmalloc_mmap_morecore() to allocate the
+ first page of the region and copy it there. Ensure that it is zero'd and
+ then initialize the fields that we know values for. */
+
+ mdp = &mtemp;
+ memset ((char *) mdp, 0, sizeof (mtemp));
+ strncpy (mdp -> magic, MMALLOC_MAGIC, MMALLOC_MAGIC_SIZE);
+ mdp -> headersize = sizeof (mtemp);
+ mdp -> version = MMALLOC_VERSION;
+ mdp -> morecore = __mmalloc_mmap_morecore;
+ mdp -> fd = fd;
+ mdp -> base = mdp -> breakval = mdp -> top = baseaddr;
+
+ /* If we have not been passed a valid open file descriptor for the file
+ to map to, then open /dev/zero and use that to map to. */
+
+ if (mdp -> fd < 0)
+ {
+ if ((mdp -> fd = open ("/dev/zero", O_RDWR)) < 0)
+ {
+ return (NULL);
+ }
+ else
+ {
+ mdp -> flags |= MMALLOC_DEVZERO;
+ }
+ }
+
+ /* Now try to map in the first page, copy the malloc descriptor structure
+ there, and arrange to return a pointer to this new copy. If the mapping
+ fails, then close the file descriptor if it was opened by us, and arrange
+ to return a NULL. */
+
+ if ((mbase = mdp -> morecore (mdp, sizeof (mtemp))) != NULL)
+ {
+ memcpy (mbase, mdp, sizeof (mtemp));
+ mdp = (struct mdesc *) mbase;
+ }
+ else
+ {
+ if (mdp -> flags & MMALLOC_DEVZERO)
+ {
+ close (mdp -> fd);
+ }
+ mdp = NULL;
+ }
+
+ return ((PTR) mdp);
+}
+
+/* Given an valid file descriptor on an open file, test to see if that file
+ is a valid mmalloc produced file, and if so, attempt to remap it into the
+ current process at the same address to which it was previously mapped.
+
+ Note that we have to update the file descriptor number in the malloc-
+ descriptor read from the file to match the current valid one, before
+ trying to map the file in, and again after a successful mapping and
+ after we've switched over to using the mapped in malloc descriptor
+ rather than the temporary one on the stack.
+
+ Once we've switched over to using the mapped in malloc descriptor, we
+ have to update the pointer to the morecore function, since it almost
+ certainly will be at a different address if the process reusing the
+ mapped region is from a different executable.
+
+ Also note that if the heap being remapped previously used the mmcheck()
+ routines, we need to update the hooks since their target functions
+ will have certainly moved if the executable has changed in any way.
+ We do this by calling mmcheck() internally.
+
+ Returns a pointer to the malloc descriptor if successful, or NULL if
+ unsuccessful for some reason. */
+
+static struct mdesc *
+reuse (fd)
+ int fd;
+{
+ struct mdesc mtemp;
+ struct mdesc *mdp = NULL;
+
+ if ((lseek (fd, 0L, SEEK_SET) == 0) &&
+ (read (fd, (char *) &mtemp, sizeof (mtemp)) == sizeof (mtemp)) &&
+ (mtemp.headersize == sizeof (mtemp)) &&
+ (strcmp (mtemp.magic, MMALLOC_MAGIC) == 0) &&
+ (mtemp.version <= MMALLOC_VERSION))
+ {
+ mtemp.fd = fd;
+ if (__mmalloc_remap_core (&mtemp) == mtemp.base)
+ {
+ mdp = (struct mdesc *) mtemp.base;
+ mdp -> fd = fd;
+ mdp -> morecore = __mmalloc_mmap_morecore;
+ if (mdp -> mfree_hook != NULL)
+ {
+ mmcheck ((PTR) mdp, (void (*) PARAMS ((void))) NULL);
+ }
+ }
+ }
+ return (mdp);
+}
+
+#else /* !defined (HAVE_MMAP) */
+
+/* For systems without mmap, the library still supplies an entry point
+ to link to, but trying to initialize access to an mmap'd managed region
+ always fails. */
+
+/* ARGSUSED */
+PTR
+mmalloc_attach (fd, baseaddr)
+ int fd;
+ PTR baseaddr;
+{
+ return (NULL);
+}
+
+#endif /* defined (HAVE_MMAP) */
+
diff --git a/gnu/usr.bin/gdb/mmalloc/detach.c b/gnu/usr.bin/gdb/mmalloc/detach.c
new file mode 100644
index 0000000..7f7f685
--- /dev/null
+++ b/gnu/usr.bin/gdb/mmalloc/detach.c
@@ -0,0 +1,71 @@
+/* Finish access to a mmap'd malloc managed region.
+ Copyright 1992 Free Software Foundation, Inc.
+
+ Contributed by Fred Fish at Cygnus Support. fnf@cygnus.com
+
+This file is part of the GNU C Library.
+
+The GNU C Library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public License as
+published by the Free Software Foundation; either version 2 of the
+License, or (at your option) any later version.
+
+The GNU C Library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with the GNU C Library; see the file COPYING.LIB. If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA. */
+
+#include <sys/types.h>
+#include <fcntl.h> /* After sys/types.h, at least for dpx/2. */
+#include "mmalloc.h"
+
+/* Terminate access to a mmalloc managed region by unmapping all memory pages
+ associated with the region, and closing the file descriptor if it is one
+ that we opened.
+
+ Returns NULL on success.
+
+ Returns the malloc descriptor on failure, which can subsequently be used
+ for further action, such as obtaining more information about the nature of
+ the failure by examining the preserved errno value.
+
+ Note that the malloc descriptor that we are using is currently located in
+ region we are about to unmap, so we first make a local copy of it on the
+ stack and use the copy. */
+
+PTR
+mmalloc_detach (md)
+ PTR md;
+{
+ struct mdesc mtemp;
+
+ if (md != NULL)
+ {
+
+ mtemp = *(struct mdesc *) md;
+
+ /* Now unmap all the pages associated with this region by asking for a
+ negative increment equal to the current size of the region. */
+
+ if ((mtemp.morecore (&mtemp, mtemp.base - mtemp.top)) == NULL)
+ {
+ /* Update the original malloc descriptor with any changes */
+ *(struct mdesc *) md = mtemp;
+ }
+ else
+ {
+ if (mtemp.flags & MMALLOC_DEVZERO)
+ {
+ close (mtemp.fd);
+ }
+ md = NULL;
+ }
+ }
+
+ return (md);
+}
diff --git a/gnu/usr.bin/gdb/mmalloc/keys.c b/gnu/usr.bin/gdb/mmalloc/keys.c
new file mode 100644
index 0000000..c9ef0e6
--- /dev/null
+++ b/gnu/usr.bin/gdb/mmalloc/keys.c
@@ -0,0 +1,66 @@
+/* Access for application keys in mmap'd malloc managed region.
+ Copyright 1992 Free Software Foundation, Inc.
+
+ Contributed by Fred Fish at Cygnus Support. fnf@cygnus.com
+
+This file is part of the GNU C Library.
+
+The GNU C Library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public License as
+published by the Free Software Foundation; either version 2 of the
+License, or (at your option) any later version.
+
+The GNU C Library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with the GNU C Library; see the file COPYING.LIB. If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA. */
+
+/* This module provides access to some keys that the application can use to
+ provide persistent access to locations in the mapped memory section.
+ The intent is that these keys are to be used sparingly as sort of
+ persistent global variables which the application can use to reinitialize
+ access to data in the mapped region.
+
+ For the moment, these keys are simply stored in the malloc descriptor
+ itself, in an array of fixed length. This should be fixed so that there
+ can be an unlimited number of keys, possibly using a multilevel access
+ scheme of some sort. */
+
+#include "mmalloc.h"
+
+int
+mmalloc_setkey (md, keynum, key)
+ PTR md;
+ int keynum;
+ PTR key;
+{
+ struct mdesc *mdp = (struct mdesc *) md;
+ int result = 0;
+
+ if ((mdp != NULL) && (keynum >= 0) && (keynum < MMALLOC_KEYS))
+ {
+ mdp -> keys [keynum] = key;
+ result++;
+ }
+ return (result);
+}
+
+PTR
+mmalloc_getkey (md, keynum)
+ PTR md;
+ int keynum;
+{
+ struct mdesc *mdp = (struct mdesc *) md;
+ PTR keyval = NULL;
+
+ if ((mdp != NULL) && (keynum >= 0) && (keynum < MMALLOC_KEYS))
+ {
+ keyval = mdp -> keys [keynum];
+ }
+ return (keyval);
+}
diff --git a/gnu/usr.bin/gdb/mmalloc/mcalloc.c b/gnu/usr.bin/gdb/mmalloc/mcalloc.c
new file mode 100644
index 0000000..08f07bf
--- /dev/null
+++ b/gnu/usr.bin/gdb/mmalloc/mcalloc.c
@@ -0,0 +1,53 @@
+/* Copyright (C) 1991, 1992 Free Software Foundation, Inc.
+This file is part of the GNU C Library.
+
+The GNU C Library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public License as
+published by the Free Software Foundation; either version 2 of the
+License, or (at your option) any later version.
+
+The GNU C Library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with the GNU C Library; see the file COPYING.LIB. If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA. */
+
+#include <string.h> /* Prototypes for memcpy, memmove, memset, etc */
+
+#include "mmalloc.h"
+
+/* Allocate an array of NMEMB elements each SIZE bytes long.
+ The entire array is initialized to zeros. */
+
+PTR
+mcalloc (md, nmemb, size)
+ PTR md;
+ register size_t nmemb;
+ register size_t size;
+{
+ register PTR result;
+
+ if ((result = mmalloc (md, nmemb * size)) != NULL)
+ {
+ memset (result, 0, nmemb * size);
+ }
+ return (result);
+}
+
+/* When using this package, provide a version of malloc/realloc/free built
+ on top of it, so that if we use the default sbrk() region we will not
+ collide with another malloc package trying to do the same thing, if
+ the application contains any "hidden" calls to malloc/realloc/free (such
+ as inside a system library). */
+
+PTR
+calloc (nmemb, size)
+ size_t nmemb;
+ size_t size;
+{
+ return (mcalloc ((PTR) NULL, nmemb, size));
+}
diff --git a/gnu/usr.bin/gdb/mmalloc/mfree.c b/gnu/usr.bin/gdb/mmalloc/mfree.c
new file mode 100644
index 0000000..16328be
--- /dev/null
+++ b/gnu/usr.bin/gdb/mmalloc/mfree.c
@@ -0,0 +1,247 @@
+/* Free a block of memory allocated by `mmalloc'.
+ Copyright 1990, 1991, 1992 Free Software Foundation
+
+ Written May 1989 by Mike Haertel.
+ Heavily modified Mar 1992 by Fred Fish. (fnf@cygnus.com)
+
+The GNU C Library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public License as
+published by the Free Software Foundation; either version 2 of the
+License, or (at your option) any later version.
+
+The GNU C Library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with the GNU C Library; see the file COPYING.LIB. If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA.
+
+ The author may be reached (Email) at the address mike@ai.mit.edu,
+ or (US mail) as Mike Haertel c/o Free Software Foundation. */
+
+#include "mmalloc.h"
+
+/* Return memory to the heap.
+ Like `mfree' but don't call a mfree_hook if there is one. */
+
+void
+__mmalloc_free (mdp, ptr)
+ struct mdesc *mdp;
+ PTR ptr;
+{
+ int type;
+ size_t block, blocks;
+ register size_t i;
+ struct list *prev, *next;
+
+ block = BLOCK (ptr);
+
+ type = mdp -> heapinfo[block].busy.type;
+ switch (type)
+ {
+ case 0:
+ /* Get as many statistics as early as we can. */
+ mdp -> heapstats.chunks_used--;
+ mdp -> heapstats.bytes_used -=
+ mdp -> heapinfo[block].busy.info.size * BLOCKSIZE;
+ mdp -> heapstats.bytes_free +=
+ mdp -> heapinfo[block].busy.info.size * BLOCKSIZE;
+
+ /* Find the free cluster previous to this one in the free list.
+ Start searching at the last block referenced; this may benefit
+ programs with locality of allocation. */
+ i = mdp -> heapindex;
+ if (i > block)
+ {
+ while (i > block)
+ {
+ i = mdp -> heapinfo[i].free.prev;
+ }
+ }
+ else
+ {
+ do
+ {
+ i = mdp -> heapinfo[i].free.next;
+ }
+ while ((i != 0) && (i < block));
+ i = mdp -> heapinfo[i].free.prev;
+ }
+
+ /* Determine how to link this block into the free list. */
+ if (block == i + mdp -> heapinfo[i].free.size)
+ {
+ /* Coalesce this block with its predecessor. */
+ mdp -> heapinfo[i].free.size +=
+ mdp -> heapinfo[block].busy.info.size;
+ block = i;
+ }
+ else
+ {
+ /* Really link this block back into the free list. */
+ mdp -> heapinfo[block].free.size =
+ mdp -> heapinfo[block].busy.info.size;
+ mdp -> heapinfo[block].free.next = mdp -> heapinfo[i].free.next;
+ mdp -> heapinfo[block].free.prev = i;
+ mdp -> heapinfo[i].free.next = block;
+ mdp -> heapinfo[mdp -> heapinfo[block].free.next].free.prev = block;
+ mdp -> heapstats.chunks_free++;
+ }
+
+ /* Now that the block is linked in, see if we can coalesce it
+ with its successor (by deleting its successor from the list
+ and adding in its size). */
+ if (block + mdp -> heapinfo[block].free.size ==
+ mdp -> heapinfo[block].free.next)
+ {
+ mdp -> heapinfo[block].free.size
+ += mdp -> heapinfo[mdp -> heapinfo[block].free.next].free.size;
+ mdp -> heapinfo[block].free.next
+ = mdp -> heapinfo[mdp -> heapinfo[block].free.next].free.next;
+ mdp -> heapinfo[mdp -> heapinfo[block].free.next].free.prev = block;
+ mdp -> heapstats.chunks_free--;
+ }
+
+ /* Now see if we can return stuff to the system. */
+ blocks = mdp -> heapinfo[block].free.size;
+ if (blocks >= FINAL_FREE_BLOCKS && block + blocks == mdp -> heaplimit
+ && mdp -> morecore (mdp, 0) == ADDRESS (block + blocks))
+ {
+ register size_t bytes = blocks * BLOCKSIZE;
+ mdp -> heaplimit -= blocks;
+ mdp -> morecore (mdp, -bytes);
+ mdp -> heapinfo[mdp -> heapinfo[block].free.prev].free.next
+ = mdp -> heapinfo[block].free.next;
+ mdp -> heapinfo[mdp -> heapinfo[block].free.next].free.prev
+ = mdp -> heapinfo[block].free.prev;
+ block = mdp -> heapinfo[block].free.prev;
+ mdp -> heapstats.chunks_free--;
+ mdp -> heapstats.bytes_free -= bytes;
+ }
+
+ /* Set the next search to begin at this block. */
+ mdp -> heapindex = block;
+ break;
+
+ default:
+ /* Do some of the statistics. */
+ mdp -> heapstats.chunks_used--;
+ mdp -> heapstats.bytes_used -= 1 << type;
+ mdp -> heapstats.chunks_free++;
+ mdp -> heapstats.bytes_free += 1 << type;
+
+ /* Get the address of the first free fragment in this block. */
+ prev = (struct list *)
+ ((char *) ADDRESS(block) +
+ (mdp -> heapinfo[block].busy.info.frag.first << type));
+
+ if (mdp -> heapinfo[block].busy.info.frag.nfree ==
+ (BLOCKSIZE >> type) - 1)
+ {
+ /* If all fragments of this block are free, remove them
+ from the fragment list and free the whole block. */
+ next = prev;
+ for (i = 1; i < (size_t) (BLOCKSIZE >> type); ++i)
+ {
+ next = next -> next;
+ }
+ prev -> prev -> next = next;
+ if (next != NULL)
+ {
+ next -> prev = prev -> prev;
+ }
+ mdp -> heapinfo[block].busy.type = 0;
+ mdp -> heapinfo[block].busy.info.size = 1;
+
+ /* Keep the statistics accurate. */
+ mdp -> heapstats.chunks_used++;
+ mdp -> heapstats.bytes_used += BLOCKSIZE;
+ mdp -> heapstats.chunks_free -= BLOCKSIZE >> type;
+ mdp -> heapstats.bytes_free -= BLOCKSIZE;
+
+ mfree ((PTR) mdp, (PTR) ADDRESS(block));
+ }
+ else if (mdp -> heapinfo[block].busy.info.frag.nfree != 0)
+ {
+ /* If some fragments of this block are free, link this
+ fragment into the fragment list after the first free
+ fragment of this block. */
+ next = (struct list *) ptr;
+ next -> next = prev -> next;
+ next -> prev = prev;
+ prev -> next = next;
+ if (next -> next != NULL)
+ {
+ next -> next -> prev = next;
+ }
+ ++mdp -> heapinfo[block].busy.info.frag.nfree;
+ }
+ else
+ {
+ /* No fragments of this block are free, so link this
+ fragment into the fragment list and announce that
+ it is the first free fragment of this block. */
+ prev = (struct list *) ptr;
+ mdp -> heapinfo[block].busy.info.frag.nfree = 1;
+ mdp -> heapinfo[block].busy.info.frag.first =
+ RESIDUAL (ptr, BLOCKSIZE) >> type;
+ prev -> next = mdp -> fraghead[type].next;
+ prev -> prev = &mdp -> fraghead[type];
+ prev -> prev -> next = prev;
+ if (prev -> next != NULL)
+ {
+ prev -> next -> prev = prev;
+ }
+ }
+ break;
+ }
+}
+
+/* Return memory to the heap. */
+
+void
+mfree (md, ptr)
+ PTR md;
+ PTR ptr;
+{
+ struct mdesc *mdp;
+ register struct alignlist *l;
+
+ if (ptr != NULL)
+ {
+ mdp = MD_TO_MDP (md);
+ for (l = mdp -> aligned_blocks; l != NULL; l = l -> next)
+ {
+ if (l -> aligned == ptr)
+ {
+ l -> aligned = NULL; /* Mark the slot in the list as free. */
+ ptr = l -> exact;
+ break;
+ }
+ }
+ if (mdp -> mfree_hook != NULL)
+ {
+ (*mdp -> mfree_hook) (md, ptr);
+ }
+ else
+ {
+ __mmalloc_free (mdp, ptr);
+ }
+ }
+}
+
+/* When using this package, provide a version of malloc/realloc/free built
+ on top of it, so that if we use the default sbrk() region we will not
+ collide with another malloc package trying to do the same thing, if
+ the application contains any "hidden" calls to malloc/realloc/free (such
+ as inside a system library). */
+
+void
+free (ptr)
+ PTR ptr;
+{
+ mfree ((PTR) NULL, ptr);
+}
diff --git a/gnu/usr.bin/gdb/mmalloc/mmalloc.c b/gnu/usr.bin/gdb/mmalloc/mmalloc.c
new file mode 100644
index 0000000..491aa16
--- /dev/null
+++ b/gnu/usr.bin/gdb/mmalloc/mmalloc.c
@@ -0,0 +1,334 @@
+/* Memory allocator `malloc'.
+ Copyright 1990, 1991, 1992 Free Software Foundation
+
+ Written May 1989 by Mike Haertel.
+ Heavily modified Mar 1992 by Fred Fish for mmap'd version.
+
+The GNU C Library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public License as
+published by the Free Software Foundation; either version 2 of the
+License, or (at your option) any later version.
+
+The GNU C Library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with the GNU C Library; see the file COPYING.LIB. If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA.
+
+ The author may be reached (Email) at the address mike@ai.mit.edu,
+ or (US mail) as Mike Haertel c/o Free Software Foundation. */
+
+#include <string.h> /* Prototypes for memcpy, memmove, memset, etc */
+
+#include "mmalloc.h"
+
+/* Prototypes for local functions */
+
+static int initialize PARAMS ((struct mdesc *));
+static PTR morecore PARAMS ((struct mdesc *, size_t));
+static PTR align PARAMS ((struct mdesc *, size_t));
+
+/* Aligned allocation. */
+
+static PTR
+align (mdp, size)
+ struct mdesc *mdp;
+ size_t size;
+{
+ PTR result;
+ unsigned long int adj;
+
+ result = mdp -> morecore (mdp, size);
+ adj = RESIDUAL (result, BLOCKSIZE);
+ if (adj != 0)
+ {
+ adj = BLOCKSIZE - adj;
+ mdp -> morecore (mdp, adj);
+ result = (char *) result + adj;
+ }
+ return (result);
+}
+
+/* Set everything up and remember that we have. */
+
+static int
+initialize (mdp)
+ struct mdesc *mdp;
+{
+ mdp -> heapsize = HEAP / BLOCKSIZE;
+ mdp -> heapinfo = (malloc_info *)
+ align (mdp, mdp -> heapsize * sizeof (malloc_info));
+ if (mdp -> heapinfo == NULL)
+ {
+ return (0);
+ }
+ memset ((PTR)mdp -> heapinfo, 0, mdp -> heapsize * sizeof (malloc_info));
+ mdp -> heapinfo[0].free.size = 0;
+ mdp -> heapinfo[0].free.next = mdp -> heapinfo[0].free.prev = 0;
+ mdp -> heapindex = 0;
+ mdp -> heapbase = (char *) mdp -> heapinfo;
+ mdp -> flags |= MMALLOC_INITIALIZED;
+ return (1);
+}
+
+/* Get neatly aligned memory, initializing or
+ growing the heap info table as necessary. */
+
+static PTR
+morecore (mdp, size)
+ struct mdesc *mdp;
+ size_t size;
+{
+ PTR result;
+ malloc_info *newinfo, *oldinfo;
+ size_t newsize;
+
+ result = align (mdp, size);
+ if (result == NULL)
+ {
+ return (NULL);
+ }
+
+ /* Check if we need to grow the info table. */
+ if ((size_t) BLOCK ((char *) result + size) > mdp -> heapsize)
+ {
+ newsize = mdp -> heapsize;
+ while ((size_t) BLOCK ((char *) result + size) > newsize)
+ {
+ newsize *= 2;
+ }
+ newinfo = (malloc_info *) align (mdp, newsize * sizeof (malloc_info));
+ if (newinfo == NULL)
+ {
+ mdp -> morecore (mdp, -size);
+ return (NULL);
+ }
+ memset ((PTR) newinfo, 0, newsize * sizeof (malloc_info));
+ memcpy ((PTR) newinfo, (PTR) mdp -> heapinfo,
+ mdp -> heapsize * sizeof (malloc_info));
+ oldinfo = mdp -> heapinfo;
+ newinfo[BLOCK (oldinfo)].busy.type = 0;
+ newinfo[BLOCK (oldinfo)].busy.info.size
+ = BLOCKIFY (mdp -> heapsize * sizeof (malloc_info));
+ mdp -> heapinfo = newinfo;
+ __mmalloc_free (mdp, (PTR)oldinfo);
+ mdp -> heapsize = newsize;
+ }
+
+ mdp -> heaplimit = BLOCK ((char *) result + size);
+ return (result);
+}
+
+/* Allocate memory from the heap. */
+
+PTR
+mmalloc (md, size)
+ PTR md;
+ size_t size;
+{
+ struct mdesc *mdp;
+ PTR result;
+ size_t block, blocks, lastblocks, start;
+ register size_t i;
+ struct list *next;
+ register size_t log;
+
+ if (size == 0)
+ {
+ return (NULL);
+ }
+
+ mdp = MD_TO_MDP (md);
+
+ if (mdp -> mmalloc_hook != NULL)
+ {
+ return ((*mdp -> mmalloc_hook) (md, size));
+ }
+
+ if (!(mdp -> flags & MMALLOC_INITIALIZED))
+ {
+ if (!initialize (mdp))
+ {
+ return (NULL);
+ }
+ }
+
+ if (size < sizeof (struct list))
+ {
+ size = sizeof (struct list);
+ }
+
+ /* Determine the allocation policy based on the request size. */
+ if (size <= BLOCKSIZE / 2)
+ {
+ /* Small allocation to receive a fragment of a block.
+ Determine the logarithm to base two of the fragment size. */
+ log = 1;
+ --size;
+ while ((size /= 2) != 0)
+ {
+ ++log;
+ }
+
+ /* Look in the fragment lists for a
+ free fragment of the desired size. */
+ next = mdp -> fraghead[log].next;
+ if (next != NULL)
+ {
+ /* There are free fragments of this size.
+ Pop a fragment out of the fragment list and return it.
+ Update the block's nfree and first counters. */
+ result = (PTR) next;
+ next -> prev -> next = next -> next;
+ if (next -> next != NULL)
+ {
+ next -> next -> prev = next -> prev;
+ }
+ block = BLOCK (result);
+ if (--mdp -> heapinfo[block].busy.info.frag.nfree != 0)
+ {
+ mdp -> heapinfo[block].busy.info.frag.first =
+ RESIDUAL (next -> next, BLOCKSIZE) >> log;
+ }
+
+ /* Update the statistics. */
+ mdp -> heapstats.chunks_used++;
+ mdp -> heapstats.bytes_used += 1 << log;
+ mdp -> heapstats.chunks_free--;
+ mdp -> heapstats.bytes_free -= 1 << log;
+ }
+ else
+ {
+ /* No free fragments of the desired size, so get a new block
+ and break it into fragments, returning the first. */
+ result = mmalloc (md, BLOCKSIZE);
+ if (result == NULL)
+ {
+ return (NULL);
+ }
+
+ /* Link all fragments but the first into the free list. */
+ for (i = 1; i < (size_t) (BLOCKSIZE >> log); ++i)
+ {
+ next = (struct list *) ((char *) result + (i << log));
+ next -> next = mdp -> fraghead[log].next;
+ next -> prev = &mdp -> fraghead[log];
+ next -> prev -> next = next;
+ if (next -> next != NULL)
+ {
+ next -> next -> prev = next;
+ }
+ }
+
+ /* Initialize the nfree and first counters for this block. */
+ block = BLOCK (result);
+ mdp -> heapinfo[block].busy.type = log;
+ mdp -> heapinfo[block].busy.info.frag.nfree = i - 1;
+ mdp -> heapinfo[block].busy.info.frag.first = i - 1;
+
+ mdp -> heapstats.chunks_free += (BLOCKSIZE >> log) - 1;
+ mdp -> heapstats.bytes_free += BLOCKSIZE - (1 << log);
+ mdp -> heapstats.bytes_used -= BLOCKSIZE - (1 << log);
+ }
+ }
+ else
+ {
+ /* Large allocation to receive one or more blocks.
+ Search the free list in a circle starting at the last place visited.
+ If we loop completely around without finding a large enough
+ space we will have to get more memory from the system. */
+ blocks = BLOCKIFY(size);
+ start = block = MALLOC_SEARCH_START;
+ while (mdp -> heapinfo[block].free.size < blocks)
+ {
+ block = mdp -> heapinfo[block].free.next;
+ if (block == start)
+ {
+ /* Need to get more from the system. Check to see if
+ the new core will be contiguous with the final free
+ block; if so we don't need to get as much. */
+ block = mdp -> heapinfo[0].free.prev;
+ lastblocks = mdp -> heapinfo[block].free.size;
+ if (mdp -> heaplimit != 0 &&
+ block + lastblocks == mdp -> heaplimit &&
+ mdp -> morecore (mdp, 0) == ADDRESS(block + lastblocks) &&
+ (morecore (mdp, (blocks - lastblocks) * BLOCKSIZE)) != NULL)
+ {
+ /* Which block we are extending (the `final free
+ block' referred to above) might have changed, if
+ it got combined with a freed info table. */
+ block = mdp -> heapinfo[0].free.prev;
+
+ mdp -> heapinfo[block].free.size += (blocks - lastblocks);
+ mdp -> heapstats.bytes_free +=
+ (blocks - lastblocks) * BLOCKSIZE;
+ continue;
+ }
+ result = morecore(mdp, blocks * BLOCKSIZE);
+ if (result == NULL)
+ {
+ return (NULL);
+ }
+ block = BLOCK (result);
+ mdp -> heapinfo[block].busy.type = 0;
+ mdp -> heapinfo[block].busy.info.size = blocks;
+ mdp -> heapstats.chunks_used++;
+ mdp -> heapstats.bytes_used += blocks * BLOCKSIZE;
+ return (result);
+ }
+ }
+
+ /* At this point we have found a suitable free list entry.
+ Figure out how to remove what we need from the list. */
+ result = ADDRESS(block);
+ if (mdp -> heapinfo[block].free.size > blocks)
+ {
+ /* The block we found has a bit left over,
+ so relink the tail end back into the free list. */
+ mdp -> heapinfo[block + blocks].free.size
+ = mdp -> heapinfo[block].free.size - blocks;
+ mdp -> heapinfo[block + blocks].free.next
+ = mdp -> heapinfo[block].free.next;
+ mdp -> heapinfo[block + blocks].free.prev
+ = mdp -> heapinfo[block].free.prev;
+ mdp -> heapinfo[mdp -> heapinfo[block].free.prev].free.next
+ = mdp -> heapinfo[mdp -> heapinfo[block].free.next].free.prev
+ = mdp -> heapindex = block + blocks;
+ }
+ else
+ {
+ /* The block exactly matches our requirements,
+ so just remove it from the list. */
+ mdp -> heapinfo[mdp -> heapinfo[block].free.next].free.prev
+ = mdp -> heapinfo[block].free.prev;
+ mdp -> heapinfo[mdp -> heapinfo[block].free.prev].free.next
+ = mdp -> heapindex = mdp -> heapinfo[block].free.next;
+ mdp -> heapstats.chunks_free--;
+ }
+
+ mdp -> heapinfo[block].busy.type = 0;
+ mdp -> heapinfo[block].busy.info.size = blocks;
+ mdp -> heapstats.chunks_used++;
+ mdp -> heapstats.bytes_used += blocks * BLOCKSIZE;
+ mdp -> heapstats.bytes_free -= blocks * BLOCKSIZE;
+ }
+
+ return (result);
+}
+
+/* When using this package, provide a version of malloc/realloc/free built
+ on top of it, so that if we use the default sbrk() region we will not
+ collide with another malloc package trying to do the same thing, if
+ the application contains any "hidden" calls to malloc/realloc/free (such
+ as inside a system library). */
+
+PTR
+malloc (size)
+ size_t size;
+{
+ return (mmalloc ((PTR) NULL, size));
+}
diff --git a/gnu/usr.bin/gdb/mmalloc/mmalloc.h b/gnu/usr.bin/gdb/mmalloc/mmalloc.h
new file mode 100644
index 0000000..34ba775
--- /dev/null
+++ b/gnu/usr.bin/gdb/mmalloc/mmalloc.h
@@ -0,0 +1,390 @@
+/* Declarations for `mmalloc' and friends.
+ Copyright 1990, 1991, 1992 Free Software Foundation
+
+ Written May 1989 by Mike Haertel.
+ Heavily modified Mar 1992 by Fred Fish. (fnf@cygnus.com)
+
+The GNU C Library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public License as
+published by the Free Software Foundation; either version 2 of the
+License, or (at your option) any later version.
+
+The GNU C Library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with the GNU C Library; see the file COPYING.LIB. If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA.
+
+ The author may be reached (Email) at the address mike@ai.mit.edu,
+ or (US mail) as Mike Haertel c/o Free Software Foundation. */
+
+
+#ifndef __MMALLOC_H
+#define __MMALLOC_H 1
+
+#ifdef __STDC__
+# include <stddef.h>
+# define PTR void *
+# define CONST const
+# define PARAMS(paramlist) paramlist
+# include <limits.h>
+# ifndef NULL
+# define NULL (void *) 0
+# endif
+#else
+# define PTR char *
+# define CONST /* nothing */
+# define PARAMS(paramlist) ()
+# ifndef size_t
+# define size_t unsigned int
+# endif
+# ifndef CHAR_BIT
+# define CHAR_BIT 8
+# endif
+# ifndef NULL
+# define NULL 0
+# endif
+#endif
+
+#ifndef MIN
+# define MIN(A, B) ((A) < (B) ? (A) : (B))
+#endif
+
+#define MMALLOC_MAGIC "mmalloc" /* Mapped file magic number */
+#define MMALLOC_MAGIC_SIZE 8 /* Size of magic number buf */
+#define MMALLOC_VERSION 1 /* Current mmalloc version */
+#define MMALLOC_KEYS 16 /* Keys for application use */
+
+/* The allocator divides the heap into blocks of fixed size; large
+ requests receive one or more whole blocks, and small requests
+ receive a fragment of a block. Fragment sizes are powers of two,
+ and all fragments of a block are the same size. When all the
+ fragments in a block have been freed, the block itself is freed. */
+
+#define INT_BIT (CHAR_BIT * sizeof(int))
+#define BLOCKLOG (INT_BIT > 16 ? 12 : 9)
+#define BLOCKSIZE ((unsigned int) 1 << BLOCKLOG)
+#define BLOCKIFY(SIZE) (((SIZE) + BLOCKSIZE - 1) / BLOCKSIZE)
+
+/* The difference between two pointers is a signed int. On machines where
+ the data addresses have the high bit set, we need to ensure that the
+ difference becomes an unsigned int when we are using the address as an
+ integral value. In addition, when using with the '%' operator, the
+ sign of the result is machine dependent for negative values, so force
+ it to be treated as an unsigned int. */
+
+#define ADDR2UINT(addr) ((unsigned int) ((char *) (addr) - (char *) NULL))
+#define RESIDUAL(addr,bsize) ((unsigned int) (ADDR2UINT (addr) % (bsize)))
+
+/* Determine the amount of memory spanned by the initial heap table
+ (not an absolute limit). */
+
+#define HEAP (INT_BIT > 16 ? 4194304 : 65536)
+
+/* Number of contiguous free blocks allowed to build up at the end of
+ memory before they will be returned to the system. */
+
+#define FINAL_FREE_BLOCKS 8
+
+/* Where to start searching the free list when looking for new memory.
+ The two possible values are 0 and heapindex. Starting at 0 seems
+ to reduce total memory usage, while starting at heapindex seems to
+ run faster. */
+
+#define MALLOC_SEARCH_START mdp -> heapindex
+
+/* Address to block number and vice versa. */
+
+#define BLOCK(A) (((char *) (A) - mdp -> heapbase) / BLOCKSIZE + 1)
+
+#define ADDRESS(B) ((PTR) (((B) - 1) * BLOCKSIZE + mdp -> heapbase))
+
+/* Data structure giving per-block information. */
+
+typedef union
+ {
+ /* Heap information for a busy block. */
+ struct
+ {
+ /* Zero for a large block, or positive giving the
+ logarithm to the base two of the fragment size. */
+ int type;
+ union
+ {
+ struct
+ {
+ size_t nfree; /* Free fragments in a fragmented block. */
+ size_t first; /* First free fragment of the block. */
+ } frag;
+ /* Size (in blocks) of a large cluster. */
+ size_t size;
+ } info;
+ } busy;
+ /* Heap information for a free block (that may be the first of
+ a free cluster). */
+ struct
+ {
+ size_t size; /* Size (in blocks) of a free cluster. */
+ size_t next; /* Index of next free cluster. */
+ size_t prev; /* Index of previous free cluster. */
+ } free;
+ } malloc_info;
+
+/* List of blocks allocated with `mmemalign' (or `mvalloc'). */
+
+struct alignlist
+ {
+ struct alignlist *next;
+ PTR aligned; /* The address that mmemaligned returned. */
+ PTR exact; /* The address that malloc returned. */
+ };
+
+/* Doubly linked lists of free fragments. */
+
+struct list
+ {
+ struct list *next;
+ struct list *prev;
+ };
+
+/* Statistics available to the user.
+ FIXME: By design, the internals of the malloc package are no longer
+ exported to the user via an include file, so access to this data needs
+ to be via some other mechanism, such as mmstat_<something> where the
+ return value is the <something> the user is interested in. */
+
+struct mstats
+ {
+ size_t bytes_total; /* Total size of the heap. */
+ size_t chunks_used; /* Chunks allocated by the user. */
+ size_t bytes_used; /* Byte total of user-allocated chunks. */
+ size_t chunks_free; /* Chunks in the free list. */
+ size_t bytes_free; /* Byte total of chunks in the free list. */
+ };
+
+/* Internal structure that defines the format of the malloc-descriptor.
+ This gets written to the base address of the region that mmalloc is
+ managing, and thus also becomes the file header for the mapped file,
+ if such a file exists. */
+
+struct mdesc
+{
+ /* The "magic number" for an mmalloc file. */
+
+ char magic[MMALLOC_MAGIC_SIZE];
+
+ /* The size in bytes of this structure, used as a sanity check when reusing
+ a previously created mapped file. */
+
+ unsigned int headersize;
+
+ /* The version number of the mmalloc package that created this file. */
+
+ unsigned char version;
+
+ /* Some flag bits to keep track of various internal things. */
+
+ unsigned int flags;
+
+ /* If a system call made by the mmalloc package fails, the errno is
+ preserved for future examination. */
+
+ int saved_errno;
+
+ /* Pointer to the function that is used to get more core, or return core
+ to the system, for requests using this malloc descriptor. For memory
+ mapped regions, this is the mmap() based routine. There may also be
+ a single malloc descriptor that points to an sbrk() based routine
+ for systems without mmap() or for applications that call the mmalloc()
+ package with a NULL malloc descriptor.
+
+ FIXME: For mapped regions shared by more than one process, this
+ needs to be maintained on a per-process basis. */
+
+ PTR (*morecore) PARAMS ((struct mdesc *, int));
+
+ /* Pointer to the function that causes an abort when the memory checking
+ features are activated. By default this is set to abort(), but can
+ be set to another function by the application using mmalloc().
+
+ FIXME: For mapped regions shared by more than one process, this
+ needs to be maintained on a per-process basis. */
+
+ void (*abortfunc) PARAMS ((void));
+
+ /* Debugging hook for free.
+
+ FIXME: For mapped regions shared by more than one process, this
+ needs to be maintained on a per-process basis. */
+
+ void (*mfree_hook) PARAMS ((PTR, PTR));
+
+ /* Debugging hook for `malloc'.
+
+ FIXME: For mapped regions shared by more than one process, this
+ needs to be maintained on a per-process basis. */
+
+ PTR (*mmalloc_hook) PARAMS ((PTR, size_t));
+
+ /* Debugging hook for realloc.
+
+ FIXME: For mapped regions shared by more than one process, this
+ needs to be maintained on a per-process basis. */
+
+ PTR (*mrealloc_hook) PARAMS ((PTR, PTR, size_t));
+
+ /* Number of info entries. */
+
+ size_t heapsize;
+
+ /* Pointer to first block of the heap (base of the first block). */
+
+ char *heapbase;
+
+ /* Current search index for the heap table. */
+ /* Search index in the info table. */
+
+ size_t heapindex;
+
+ /* Limit of valid info table indices. */
+
+ size_t heaplimit;
+
+ /* Block information table.
+ Allocated with malign/__mmalloc_free (not mmalloc/mfree). */
+ /* Table indexed by block number giving per-block information. */
+
+ malloc_info *heapinfo;
+
+ /* Instrumentation. */
+
+ struct mstats heapstats;
+
+ /* Free list headers for each fragment size. */
+ /* Free lists for each fragment size. */
+
+ struct list fraghead[BLOCKLOG];
+
+ /* List of blocks allocated by memalign. */
+
+ struct alignlist *aligned_blocks;
+
+ /* The base address of the memory region for this malloc heap. This
+ is the location where the bookkeeping data for mmap and for malloc
+ begins. */
+
+ char *base;
+
+ /* The current location in the memory region for this malloc heap which
+ represents the end of memory in use. */
+
+ char *breakval;
+
+ /* The end of the current memory region for this malloc heap. This is
+ the first location past the end of mapped memory. */
+
+ char *top;
+
+ /* Open file descriptor for the file to which this malloc heap is mapped.
+ This will always be a valid file descriptor, since /dev/zero is used
+ by default if no open file is supplied by the client. Also note that
+ it may change each time the region is mapped and unmapped. */
+
+ int fd;
+
+ /* An array of keys to data within the mapped region, for use by the
+ application. */
+
+ PTR keys[MMALLOC_KEYS];
+
+};
+
+/* Bits to look at in the malloc descriptor flags word */
+
+#define MMALLOC_DEVZERO (1 << 0) /* Have mapped to /dev/zero */
+#define MMALLOC_INITIALIZED (1 << 1) /* Initialized mmalloc */
+#define MMALLOC_MMCHECK_USED (1 << 2) /* mmcheck() called already */
+
+/* Allocate SIZE bytes of memory. */
+
+extern PTR mmalloc PARAMS ((PTR, size_t));
+
+/* Re-allocate the previously allocated block in PTR, making the new block
+ SIZE bytes long. */
+
+extern PTR mrealloc PARAMS ((PTR, PTR, size_t));
+
+/* Allocate NMEMB elements of SIZE bytes each, all initialized to 0. */
+
+extern PTR mcalloc PARAMS ((PTR, size_t, size_t));
+
+/* Free a block allocated by `mmalloc', `mrealloc' or `mcalloc'. */
+
+extern void mfree PARAMS ((PTR, PTR));
+
+/* Allocate SIZE bytes allocated to ALIGNMENT bytes. */
+
+extern PTR mmemalign PARAMS ((PTR, size_t, size_t));
+
+/* Allocate SIZE bytes on a page boundary. */
+
+extern PTR mvalloc PARAMS ((PTR, size_t));
+
+/* Activate a standard collection of debugging hooks. */
+
+extern int mmcheck PARAMS ((PTR, void (*) (void)));
+
+/* Pick up the current statistics. (see FIXME elsewhere) */
+
+extern struct mstats mmstats PARAMS ((PTR));
+
+/* Internal version of `mfree' used in `morecore'. */
+
+extern void __mmalloc_free PARAMS ((struct mdesc *, PTR));
+
+/* Hooks for debugging versions. */
+
+extern void (*__mfree_hook) PARAMS ((PTR, PTR));
+extern PTR (*__mmalloc_hook) PARAMS ((PTR, size_t));
+extern PTR (*__mrealloc_hook) PARAMS ((PTR, PTR, size_t));
+
+/* A default malloc descriptor for the single sbrk() managed region. */
+
+extern struct mdesc *__mmalloc_default_mdp;
+
+/* Initialize the first use of the default malloc descriptor, which uses
+ an sbrk() region. */
+
+extern struct mdesc *__mmalloc_sbrk_init PARAMS ((void));
+
+/* Grow or shrink a contiguous mapped region using mmap().
+ Works much like sbrk() */
+
+#if defined(HAVE_MMAP)
+
+extern PTR __mmalloc_mmap_morecore PARAMS ((struct mdesc *, int));
+
+#endif
+
+/* Remap a mmalloc region that was previously mapped. */
+
+extern PTR __mmalloc_remap_core PARAMS ((struct mdesc *));
+
+/* Macro to convert from a user supplied malloc descriptor to pointer to the
+ internal malloc descriptor. If the user supplied descriptor is NULL, then
+ use the default internal version, initializing it if necessary. Otherwise
+ just cast the user supplied version (which is void *) to the proper type
+ (struct mdesc *). */
+
+#define MD_TO_MDP(md) \
+ ((md) == NULL \
+ ? (__mmalloc_default_mdp == NULL \
+ ? __mmalloc_sbrk_init () \
+ : __mmalloc_default_mdp) \
+ : (struct mdesc *) (md))
+
+#endif /* __MMALLOC_H */
diff --git a/gnu/usr.bin/gdb/mmalloc/mmalloc.texi b/gnu/usr.bin/gdb/mmalloc/mmalloc.texi
new file mode 100644
index 0000000..5e28398
--- /dev/null
+++ b/gnu/usr.bin/gdb/mmalloc/mmalloc.texi
@@ -0,0 +1,258 @@
+\input texinfo @c -*- Texinfo -*-
+@setfilename mmalloc.info
+
+@ifinfo
+@format
+START-INFO-DIR-ENTRY
+* Mmalloc: (mmalloc). The GNU mapped-malloc package.
+END-INFO-DIR-ENTRY
+@end format
+
+This file documents the GNU mmalloc (mapped-malloc) package, written by
+fnf@@cygnus.com, based on GNU malloc written by mike@@ai.mit.edu.
+
+Copyright (C) 1992 Free Software Foundation, Inc.
+
+Permission is granted to make and distribute verbatim copies of
+this manual provided the copyright notice and this permission notice
+are preserved on all copies.
+
+@ignore
+Permission is granted to process this file through Tex and print the
+results, provided the printed document carries copying permission
+notice identical to this one except for the removal of this paragraph
+(this paragraph not being relevant to the printed manual).
+
+@end ignore
+Permission is granted to copy and distribute modified versions of this
+manual under the conditions for verbatim copying, provided also that the
+entire resulting derived work is distributed under the terms of a
+permission notice identical to this one.
+
+Permission is granted to copy and distribute translations of this manual
+into another language, under the above conditions for modified versions.
+@end ifinfo
+@iftex
+@c @finalout
+@setchapternewpage odd
+@settitle MMALLOC, the GNU memory-mapped malloc package
+@titlepage
+@title mmalloc
+@subtitle The GNU memory-mapped malloc package
+@author Fred Fish
+@author Cygnus Support
+@author Mike Haertel
+@author Free Software Foundation
+@page
+
+@tex
+\def\$#1${{#1}} % Kluge: collect RCS revision info without $...$
+\xdef\manvers{\$Revision: 1.1.1.1 $} % For use in headers, footers too
+{\parskip=0pt
+\hfill Cygnus Support\par
+\hfill fnf\@cygnus.com\par
+\hfill {\it MMALLOC, the GNU memory-mapped malloc package}, \manvers\par
+\hfill \TeX{}info \texinfoversion\par
+}
+@end tex
+
+@vskip 0pt plus 1filll
+Copyright @copyright{} 1992 Free Software Foundation, Inc.
+
+Permission is granted to make and distribute verbatim copies of
+this manual provided the copyright notice and this permission notice
+are preserved on all copies.
+
+Permission is granted to copy and distribute modified versions of this
+manual under the conditions for verbatim copying, provided also that
+the entire resulting derived work is distributed under the terms of a
+permission notice identical to this one.
+
+Permission is granted to copy and distribute translations of this manual
+into another language, under the above conditions for modified versions.
+@end titlepage
+@end iftex
+
+@ifinfo
+@node Top, Overview, (dir), (dir)
+@top mmalloc
+This file documents the GNU memory-mapped malloc package mmalloc.
+
+@menu
+* Overview:: Overall Description
+* Implementation:: Implementation
+
+ --- The Detailed Node Listing ---
+
+Implementation
+
+* Compatibility:: Backwards Compatibility
+* Functions:: Function Descriptions
+@end menu
+
+@end ifinfo
+
+@node Overview, Implementation, Top, Top
+@chapter Overall Description
+
+This is a heavily modified version of GNU @code{malloc}. It uses
+@code{mmap} as the basic mechanism for for obtaining memory from the
+system, rather than @code{sbrk}. This gives it several advantages over the
+more traditional malloc:
+
+@itemize @bullet
+@item
+Several different heaps can be used, each of them growing
+or shinking under control of @code{mmap}, with the @code{mmalloc} functions
+using a specific heap on a call by call basis.
+
+@item
+By using @code{mmap}, it is easy to create heaps which are intended to
+be persistent and exist as a filesystem object after the creating
+process has gone away.
+
+@item
+Because multiple heaps can be managed, data used for a
+specific purpose can be allocated into its own heap, making
+it easier to allow applications to ``dump'' and ``restore'' initialized
+malloc-managed memory regions. For example, the ``unexec'' hack popularized
+by GNU Emacs could potentially go away.
+@end itemize
+
+@node Implementation, , Overview, Top
+@chapter Implementation
+
+The @code{mmalloc} functions contain no internal static state. All
+@code{mmalloc} internal data is allocated in the mapped in region, along
+with the user data that it manages. This allows it to manage multiple
+such regions and to ``pick up where it left off'' when such regions are
+later dynamically mapped back in.
+
+In some sense, malloc has been ``purified'' to contain no internal state
+information and generalized to use multiple memory regions rather than a
+single region managed by @code{sbrk}. However the new routines now need an
+extra parameter which informs @code{mmalloc} which memory region it is dealing
+with (along with other information). This parameter is called the
+@dfn{malloc descriptor}.
+
+The functions initially provided by @code{mmalloc} are:
+
+@example
+void *mmalloc_attach (int fd, void *baseaddr);
+void *mmalloc_detach (void *md);
+int mmalloc_errno (void *md);
+int mmalloc_setkey (void *md, int keynum, void *key);
+void *mmalloc_getkey (void *md, int keynum);
+
+void *mmalloc (void *md, size_t size);
+void *mrealloc (void *md, void *ptr, size_t size);
+void *mvalloc (void *md, size_t size);
+void mfree (void *md, void *ptr);
+@end example
+
+@menu
+* Compatibility:: Backwards Compatibility
+* Functions:: Function Descriptions
+@end menu
+
+@node Compatibility, Functions, Implementation, Implementation
+@section Backwards Compatibility
+
+To allow a single malloc package to be used in a given application,
+provision is made for the traditional @code{malloc}, @code{realloc}, and
+@code{free} functions to be implemented as special cases of the
+@code{mmalloc} functions. In particular, if any of the functions that
+expect malloc descriptors are called with a @code{NULL} pointer rather than a
+valid malloc descriptor, then they default to using an @code{sbrk} managed
+region.
+The @code{mmalloc} package provides compatible @code{malloc}, @code{realloc},
+and @code{free} functions using this mechanism internally.
+Applications can avoid this extra interface layer by simply including the
+following defines:
+
+@example
+#define malloc(size) mmalloc ((void *)0, (size))
+#define realloc(ptr,size) mrealloc ((void *)0, (ptr), (size));
+#define free(ptr) mfree ((void *)0, (ptr))
+@end example
+
+@noindent
+or replace the existing @code{malloc}, @code{realloc}, and @code{free}
+calls with the above patterns if using @code{#define} causes problems.
+
+@node Functions, , Compatibility, Implementation
+@section Function Descriptions
+
+These are the details on the functions that make up the @code{mmalloc}
+package.
+
+@table @code
+@item void *mmalloc_attach (int @var{fd}, void *@var{baseaddr});
+Initialize access to a @code{mmalloc} managed region.
+
+If @var{fd} is a valid file descriptor for an open file, then data for the
+@code{mmalloc} managed region is mapped to that file. Otherwise
+@file{/dev/zero} is used and the data will not exist in any filesystem object.
+
+If the open file corresponding to @var{fd} is from a previous use of
+@code{mmalloc} and passes some basic sanity checks to ensure that it is
+compatible with the current @code{mmalloc} package, then its data is
+mapped in and is immediately accessible at the same addresses in
+the current process as the process that created the file.
+
+If @var{baseaddr} is not @code{NULL}, the mapping is established
+starting at the specified address in the process address space. If
+@var{baseaddr} is @code{NULL}, the @code{mmalloc} package chooses a
+suitable address at which to start the mapped region, which will be the
+value of the previous mapping if opening an existing file which was
+previously built by @code{mmalloc}, or for new files will be a value
+chosen by @code{mmap}.
+
+Specifying @var{baseaddr} provides more control over where the regions
+start and how big they can be before bumping into existing mapped
+regions or future mapped regions.
+
+On success, returns a malloc descriptor which is used in subsequent
+calls to other @code{mmalloc} package functions. It is explicitly
+@samp{void *} (@samp{char *} for systems that don't fully support
+@code{void}) so that users of the package don't have to worry about the
+actual implementation details.
+
+On failure returns @code{NULL}.
+
+@item void *mmalloc_detach (void *@var{md});
+Terminate access to a @code{mmalloc} managed region identified by the
+descriptor @var{md}, by closing the base file and unmapping all memory
+pages associated with the region.
+
+Returns @code{NULL} on success.
+
+Returns the malloc descriptor on failure, which can subsequently
+be used for further action (such as obtaining more information about
+the nature of the failure).
+
+@item void *mmalloc (void *@var{md}, size_t @var{size});
+Given an @code{mmalloc} descriptor @var{md}, allocate additional memory of
+@var{size} bytes in the associated mapped region.
+
+@item *mrealloc (void *@var{md}, void *@var{ptr}, size_t @var{size});
+Given an @code{mmalloc} descriptor @var{md} and a pointer to memory
+previously allocated by @code{mmalloc} in @var{ptr}, reallocate the
+memory to be @var{size} bytes long, possibly moving the existing
+contents of memory if necessary.
+
+@item void *mvalloc (void *@var{md}, size_t @var{size});
+Like @code{mmalloc} but the resulting memory is aligned on a page boundary.
+
+@item void mfree (void *@var{md}, void *@var{ptr});
+Given an @code{mmalloc} descriptor @var{md} and a pointer to memory previously
+allocated by @code{mmalloc} in @var{ptr}, free the previously allocated memory.
+
+@item int mmalloc_errno (void *@var{md});
+Given a @code{mmalloc} descriptor, if the last @code{mmalloc} operation
+failed for some reason due to a system call failure, then
+returns the associated @code{errno}. Returns 0 otherwise.
+(This function is not yet implemented).
+@end table
+
+@bye
diff --git a/gnu/usr.bin/gdb/mmalloc/mmap-sup.c b/gnu/usr.bin/gdb/mmalloc/mmap-sup.c
new file mode 100644
index 0000000..37b3079
--- /dev/null
+++ b/gnu/usr.bin/gdb/mmalloc/mmap-sup.c
@@ -0,0 +1,144 @@
+/* Support for an sbrk-like function that uses mmap.
+ Copyright 1992 Free Software Foundation, Inc.
+
+ Contributed by Fred Fish at Cygnus Support. fnf@cygnus.com
+
+This file is part of the GNU C Library.
+
+The GNU C Library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public License as
+published by the Free Software Foundation; either version 2 of the
+License, or (at your option) any later version.
+
+The GNU C Library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with the GNU C Library; see the file COPYING.LIB. If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA. */
+
+#if defined(HAVE_MMAP)
+
+#include <stdio.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+
+#ifndef SEEK_SET
+#define SEEK_SET 0
+#endif
+
+#include "mmalloc.h"
+
+extern int munmap PARAMS ((caddr_t, size_t)); /* Not in any header file */
+
+/* Cache the pagesize for the current host machine. Note that if the host
+ does not readily provide a getpagesize() function, we need to emulate it
+ elsewhere, not clutter up this file with lots of kluges to try to figure
+ it out. */
+
+static size_t pagesize;
+extern int getpagesize PARAMS ((void));
+
+#define PAGE_ALIGN(addr) (caddr_t) (((long)(addr) + pagesize - 1) & \
+ ~(pagesize - 1))
+
+/* Get core for the memory region specified by MDP, using SIZE as the
+ amount to either add to or subtract from the existing region. Works
+ like sbrk(), but using mmap(). */
+
+PTR
+__mmalloc_mmap_morecore (mdp, size)
+ struct mdesc *mdp;
+ int size;
+{
+ PTR result = NULL;
+ off_t foffset; /* File offset at which new mapping will start */
+ size_t mapbytes; /* Number of bytes to map */
+ caddr_t moveto; /* Address where we wish to move "break value" to */
+ caddr_t mapto; /* Address we actually mapped to */
+ char buf = 0; /* Single byte to write to extend mapped file */
+
+ if (pagesize == 0)
+ {
+ pagesize = getpagesize ();
+ }
+ if (size == 0)
+ {
+ /* Just return the current "break" value. */
+ result = mdp -> breakval;
+ }
+ else if (size < 0)
+ {
+ /* We are deallocating memory. If the amount requested would cause
+ us to try to deallocate back past the base of the mmap'd region
+ then do nothing, and return NULL. Otherwise, deallocate the
+ memory and return the old break value. */
+ if (mdp -> breakval + size >= mdp -> base)
+ {
+ result = (PTR) mdp -> breakval;
+ mdp -> breakval += size;
+ moveto = PAGE_ALIGN (mdp -> breakval);
+ munmap (moveto, (size_t) (mdp -> top - moveto));
+ mdp -> top = moveto;
+ }
+ }
+ else
+ {
+ /* We are allocating memory. Make sure we have an open file
+ descriptor and then go on to get the memory. */
+ if (mdp -> fd < 0)
+ {
+ result = NULL;
+ }
+ else if (mdp -> breakval + size > mdp -> top)
+ {
+ /* The request would move us past the end of the currently
+ mapped memory, so map in enough more memory to satisfy
+ the request. This means we also have to grow the mapped-to
+ file by an appropriate amount, since mmap cannot be used
+ to extend a file. */
+ moveto = PAGE_ALIGN (mdp -> breakval + size);
+ mapbytes = moveto - mdp -> top;
+ foffset = mdp -> top - mdp -> base;
+ /* FIXME: Test results of lseek() and write() */
+ lseek (mdp -> fd, foffset + mapbytes - 1, SEEK_SET);
+ write (mdp -> fd, &buf, 1);
+ mapto = mmap (mdp -> top, mapbytes, PROT_READ | PROT_WRITE,
+ MAP_SHARED | MAP_FIXED, mdp -> fd, foffset);
+ if (mapto == mdp -> top)
+ {
+ mdp -> top = moveto;
+ result = (PTR) mdp -> breakval;
+ mdp -> breakval += size;
+ }
+ }
+ else
+ {
+ result = (PTR) mdp -> breakval;
+ mdp -> breakval += size;
+ }
+ }
+ return (result);
+}
+
+PTR
+__mmalloc_remap_core (mdp)
+ struct mdesc *mdp;
+{
+ caddr_t base;
+
+ /* FIXME: Quick hack, needs error checking and other attention. */
+
+ base = mmap (mdp -> base, mdp -> top - mdp -> base,
+ PROT_READ | PROT_WRITE, MAP_SHARED | MAP_FIXED,
+ mdp -> fd, 0);
+ return ((PTR) base);
+}
+
+#else /* defined(HAVE_MMAP) */
+/* Prevent "empty translation unit" warnings from the idiots at X3J11. */
+static char ansi_c_idiots = 69;
+#endif /* defined(HAVE_MMAP) */
diff --git a/gnu/usr.bin/gdb/mmalloc/mmcheck.c b/gnu/usr.bin/gdb/mmalloc/mmcheck.c
new file mode 100644
index 0000000..c3e29d3
--- /dev/null
+++ b/gnu/usr.bin/gdb/mmalloc/mmcheck.c
@@ -0,0 +1,196 @@
+/* Standard debugging hooks for `mmalloc'.
+ Copyright 1990, 1991, 1992 Free Software Foundation
+
+ Written May 1989 by Mike Haertel.
+ Heavily modified Mar 1992 by Fred Fish (fnf@cygnus.com)
+
+The GNU C Library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public License as
+published by the Free Software Foundation; either version 2 of the
+License, or (at your option) any later version.
+
+The GNU C Library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with the GNU C Library; see the file COPYING.LIB. If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA.
+
+ The author may be reached (Email) at the address mike@ai.mit.edu,
+ or (US mail) as Mike Haertel c/o Free Software Foundation. */
+
+#include "mmalloc.h"
+
+/* Default function to call when something awful happens. The application
+ can specify an alternate function to be called instead (and probably will
+ want to). */
+
+extern void abort PARAMS ((void));
+
+/* Arbitrary magical numbers. */
+
+#define MAGICWORD (unsigned int) 0xfedabeeb /* Active chunk */
+#define MAGICWORDFREE (unsigned int) 0xdeadbeef /* Inactive chunk */
+#define MAGICBYTE ((char) 0xd7)
+
+/* Each memory allocation is bounded by a header structure and a trailer
+ byte. I.E.
+
+ <size><magicword><user's allocation><magicbyte>
+
+ The pointer returned to the user points to the first byte in the
+ user's allocation area. The magic word can be tested to detect
+ buffer underruns and the magic byte can be tested to detect overruns. */
+
+struct hdr
+ {
+ size_t size; /* Exact size requested by user. */
+ unsigned long int magic; /* Magic number to check header integrity. */
+ };
+
+/* Check the magicword and magicbyte, and if either is corrupted then
+ call the emergency abort function specified for the heap in use. */
+
+static void
+checkhdr (mdp, hdr)
+ struct mdesc *mdp;
+ CONST struct hdr *hdr;
+{
+ if (hdr -> magic != MAGICWORD ||
+ ((char *) &hdr[1])[hdr -> size] != MAGICBYTE)
+ {
+ (*mdp -> abortfunc)();
+ }
+}
+
+static void
+mfree_check (md, ptr)
+ PTR md;
+ PTR ptr;
+{
+ struct hdr *hdr = ((struct hdr *) ptr) - 1;
+ struct mdesc *mdp;
+
+ mdp = MD_TO_MDP (md);
+ checkhdr (mdp, hdr);
+ hdr -> magic = MAGICWORDFREE;
+ mdp -> mfree_hook = NULL;
+ mfree (md, (PTR)hdr);
+ mdp -> mfree_hook = mfree_check;
+}
+
+static PTR
+mmalloc_check (md, size)
+ PTR md;
+ size_t size;
+{
+ struct hdr *hdr;
+ struct mdesc *mdp;
+ size_t nbytes;
+
+ mdp = MD_TO_MDP (md);
+ mdp -> mmalloc_hook = NULL;
+ nbytes = sizeof (struct hdr) + size + 1;
+ hdr = (struct hdr *) mmalloc (md, nbytes);
+ mdp -> mmalloc_hook = mmalloc_check;
+ if (hdr != NULL)
+ {
+ hdr -> size = size;
+ hdr -> magic = MAGICWORD;
+ hdr++;
+ *((char *) hdr + size) = MAGICBYTE;
+ }
+ return ((PTR) hdr);
+}
+
+static PTR
+mrealloc_check (md, ptr, size)
+ PTR md;
+ PTR ptr;
+ size_t size;
+{
+ struct hdr *hdr = ((struct hdr *) ptr) - 1;
+ struct mdesc *mdp;
+ size_t nbytes;
+
+ mdp = MD_TO_MDP (md);
+ checkhdr (mdp, hdr);
+ mdp -> mfree_hook = NULL;
+ mdp -> mmalloc_hook = NULL;
+ mdp -> mrealloc_hook = NULL;
+ nbytes = sizeof (struct hdr) + size + 1;
+ hdr = (struct hdr *) mrealloc (md, (PTR) hdr, nbytes);
+ mdp -> mfree_hook = mfree_check;
+ mdp -> mmalloc_hook = mmalloc_check;
+ mdp -> mrealloc_hook = mrealloc_check;
+ if (hdr != NULL)
+ {
+ hdr -> size = size;
+ hdr++;
+ *((char *) hdr + size) = MAGICBYTE;
+ }
+ return ((PTR) hdr);
+}
+
+/* Turn on default checking for mmalloc/mrealloc/mfree, for the heap specified
+ by MD. If FUNC is non-NULL, it is a pointer to the function to call
+ to abort whenever memory corruption is detected. By default, this is the
+ standard library function abort().
+
+ Note that we disallow installation of initial checking hooks if mmalloc
+ has been called at any time for this particular heap, since if any region
+ that is allocated prior to installation of the hooks is subsequently
+ reallocated or freed after installation of the hooks, it is guaranteed
+ to trigger a memory corruption error. We do this by checking the state
+ of the MMALLOC_INITIALIZED flag.
+
+ However, we can call this function at any time after the initial call,
+ to update the function pointers to the checking routines and to the
+ user defined corruption handler routine, as long as these function pointers
+ have been previously extablished by the initial call. Note that we
+ do this automatically when remapping an previously used heap, to ensure
+ that the hooks get updated to the correct values, although the corruption
+ handler pointer gets set back to the default. The application can then
+ call mmcheck to use a different corruption handler if desired.
+
+ Returns non-zero if checking is successfully enabled, zero otherwise. */
+
+int
+mmcheck (md, func)
+ PTR md;
+ void (*func) PARAMS ((void));
+{
+ struct mdesc *mdp;
+ int rtnval;
+
+ mdp = MD_TO_MDP (md);
+
+ /* We can safely set or update the abort function at any time, regardless
+ of whether or not we successfully do anything else. */
+
+ mdp -> abortfunc = (func != NULL ? func : abort);
+
+ /* If we haven't yet called mmalloc the first time for this heap, or if we
+ have hooks that were previously installed, then allow the hooks to be
+ initialized or updated. */
+
+ if (1 /* FIXME: Always allow installation for now. */ ||
+ !(mdp -> flags & MMALLOC_INITIALIZED) ||
+ (mdp -> mfree_hook != NULL))
+ {
+ mdp -> mfree_hook = mfree_check;
+ mdp -> mmalloc_hook = mmalloc_check;
+ mdp -> mrealloc_hook = mrealloc_check;
+ mdp -> flags |= MMALLOC_MMCHECK_USED;
+ rtnval = 1;
+ }
+ else
+ {
+ rtnval = 0;
+ }
+
+ return (rtnval);
+}
diff --git a/gnu/usr.bin/gdb/mmalloc/mmemalign.c b/gnu/usr.bin/gdb/mmalloc/mmemalign.c
new file mode 100644
index 0000000..63350a2
--- /dev/null
+++ b/gnu/usr.bin/gdb/mmalloc/mmemalign.c
@@ -0,0 +1,64 @@
+/* Copyright (C) 1991, 1992 Free Software Foundation, Inc.
+This file is part of the GNU C Library.
+
+The GNU C Library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public License as
+published by the Free Software Foundation; either version 2 of the
+License, or (at your option) any later version.
+
+The GNU C Library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with the GNU C Library; see the file COPYING.LIB. If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA. */
+
+#include "mmalloc.h"
+
+PTR
+mmemalign (md, alignment, size)
+ PTR md;
+ size_t alignment;
+ size_t size;
+{
+ PTR result;
+ unsigned long int adj;
+ struct alignlist *l;
+ struct mdesc *mdp;
+
+ size = ((size + alignment - 1) / alignment) * alignment;
+
+ if ((result = mmalloc (md, size)) != NULL)
+ {
+ adj = RESIDUAL (result, alignment);
+ if (adj != 0)
+ {
+ mdp = MD_TO_MDP (md);
+ for (l = mdp -> aligned_blocks; l != NULL; l = l -> next)
+ {
+ if (l -> aligned == NULL)
+ {
+ /* This slot is free. Use it. */
+ break;
+ }
+ }
+ if (l == NULL)
+ {
+ l = (struct alignlist *) mmalloc (md, sizeof (struct alignlist));
+ if (l == NULL)
+ {
+ mfree (md, result);
+ return (NULL);
+ }
+ }
+ l -> exact = result;
+ result = l -> aligned = (char *) result + alignment - adj;
+ l -> next = mdp -> aligned_blocks;
+ mdp -> aligned_blocks = l;
+ }
+ }
+ return (result);
+}
diff --git a/gnu/usr.bin/gdb/mmalloc/mmstats.c b/gnu/usr.bin/gdb/mmalloc/mmstats.c
new file mode 100644
index 0000000..d3846eb
--- /dev/null
+++ b/gnu/usr.bin/gdb/mmalloc/mmstats.c
@@ -0,0 +1,46 @@
+/* Access the statistics maintained by `mmalloc'.
+ Copyright 1990, 1991, 1992 Free Software Foundation
+
+ Written May 1989 by Mike Haertel.
+ Modified Mar 1992 by Fred Fish. (fnf@cygnus.com)
+
+The GNU C Library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public License as
+published by the Free Software Foundation; either version 2 of the
+License, or (at your option) any later version.
+
+The GNU C Library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with the GNU C Library; see the file COPYING.LIB. If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA.
+
+ The author may be reached (Email) at the address mike@ai.mit.edu,
+ or (US mail) as Mike Haertel c/o Free Software Foundation. */
+
+#include "mmalloc.h"
+
+/* FIXME: See the comment in mmalloc.h where struct mstats is defined.
+ None of the internal mmalloc structures should be externally visible
+ outside the library. */
+
+struct mstats
+mmstats (md)
+ PTR md;
+{
+ struct mstats result;
+ struct mdesc *mdp;
+
+ mdp = MD_TO_MDP (md);
+ result.bytes_total =
+ (char *) mdp -> morecore (mdp, 0) - mdp -> heapbase;
+ result.chunks_used = mdp -> heapstats.chunks_used;
+ result.bytes_used = mdp -> heapstats.bytes_used;
+ result.chunks_free = mdp -> heapstats.chunks_free;
+ result.bytes_free = mdp -> heapstats.bytes_free;
+ return (result);
+}
diff --git a/gnu/usr.bin/gdb/mmalloc/mmtrace.c b/gnu/usr.bin/gdb/mmalloc/mmtrace.c
new file mode 100644
index 0000000..aca3508
--- /dev/null
+++ b/gnu/usr.bin/gdb/mmalloc/mmtrace.c
@@ -0,0 +1,166 @@
+/* More debugging hooks for `mmalloc'.
+ Copyright 1991, 1992, 1994 Free Software Foundation
+
+ Written April 2, 1991 by John Gilmore of Cygnus Support
+ Based on mcheck.c by Mike Haertel.
+ Modified Mar 1992 by Fred Fish. (fnf@cygnus.com)
+
+This file is part of the GNU C Library.
+
+The GNU C Library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public License as
+published by the Free Software Foundation; either version 2 of the
+License, or (at your option) any later version.
+
+The GNU C Library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with the GNU C Library; see the file COPYING.LIB. If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA. */
+
+#include <stdio.h>
+#include "mmalloc.h"
+
+#ifndef __GNU_LIBRARY__
+extern char *getenv ();
+#endif
+
+static FILE *mallstream;
+
+#if 0 /* FIXME: Disabled for now. */
+static char mallenv[] = "MALLOC_TRACE";
+static char mallbuf[BUFSIZ]; /* Buffer for the output. */
+#endif
+
+/* Address to breakpoint on accesses to... */
+static PTR mallwatch;
+
+/* Old hook values. */
+
+static void (*old_mfree_hook) PARAMS ((PTR, PTR));
+static PTR (*old_mmalloc_hook) PARAMS ((PTR, size_t));
+static PTR (*old_mrealloc_hook) PARAMS ((PTR, PTR, size_t));
+
+/* This function is called when the block being alloc'd, realloc'd, or
+ freed has an address matching the variable "mallwatch". In a debugger,
+ set "mallwatch" to the address of interest, then put a breakpoint on
+ tr_break. */
+
+static void
+tr_break ()
+{
+}
+
+static void
+tr_freehook (md, ptr)
+ PTR md;
+ PTR ptr;
+{
+ struct mdesc *mdp;
+
+ mdp = MD_TO_MDP (md);
+ /* Be sure to print it first. */
+ fprintf (mallstream, "- %08lx\n", (unsigned long) ptr);
+ if (ptr == mallwatch)
+ tr_break ();
+ mdp -> mfree_hook = old_mfree_hook;
+ mfree (md, ptr);
+ mdp -> mfree_hook = tr_freehook;
+}
+
+static PTR
+tr_mallochook (md, size)
+ PTR md;
+ size_t size;
+{
+ PTR hdr;
+ struct mdesc *mdp;
+
+ mdp = MD_TO_MDP (md);
+ mdp -> mmalloc_hook = old_mmalloc_hook;
+ hdr = (PTR) mmalloc (md, size);
+ mdp -> mmalloc_hook = tr_mallochook;
+
+ /* We could be printing a NULL here; that's OK. */
+ fprintf (mallstream, "+ %08lx %x\n", (unsigned long) hdr, size);
+
+ if (hdr == mallwatch)
+ tr_break ();
+
+ return (hdr);
+}
+
+static PTR
+tr_reallochook (md, ptr, size)
+ PTR md;
+ PTR ptr;
+ size_t size;
+{
+ PTR hdr;
+ struct mdesc *mdp;
+
+ mdp = MD_TO_MDP (md);
+
+ if (ptr == mallwatch)
+ tr_break ();
+
+ mdp -> mfree_hook = old_mfree_hook;
+ mdp -> mmalloc_hook = old_mmalloc_hook;
+ mdp -> mrealloc_hook = old_mrealloc_hook;
+ hdr = (PTR) mrealloc (md, ptr, size);
+ mdp -> mfree_hook = tr_freehook;
+ mdp -> mmalloc_hook = tr_mallochook;
+ mdp -> mrealloc_hook = tr_reallochook;
+ if (hdr == NULL)
+ /* Failed realloc. */
+ fprintf (mallstream, "! %08lx %x\n", (unsigned long) ptr, size);
+ else
+ fprintf (mallstream, "< %08lx\n> %08lx %x\n", (unsigned long) ptr,
+ (unsigned long) hdr, size);
+
+ if (hdr == mallwatch)
+ tr_break ();
+
+ return hdr;
+}
+
+/* We enable tracing if either the environment variable MALLOC_TRACE
+ is set, or if the variable mallwatch has been patched to an address
+ that the debugging user wants us to stop on. When patching mallwatch,
+ don't forget to set a breakpoint on tr_break! */
+
+int
+mmtrace ()
+{
+#if 0 /* FIXME! This is disabled for now until we figure out how to
+ maintain a stack of hooks per heap, since we might have other
+ hooks (such as set by mmcheck) active also. */
+ char *mallfile;
+
+ mallfile = getenv (mallenv);
+ if (mallfile != NULL || mallwatch != NULL)
+ {
+ mallstream = fopen (mallfile != NULL ? mallfile : "/dev/null", "w");
+ if (mallstream != NULL)
+ {
+ /* Be sure it doesn't mmalloc its buffer! */
+ setbuf (mallstream, mallbuf);
+ fprintf (mallstream, "= Start\n");
+ old_mfree_hook = mdp -> mfree_hook;
+ mdp -> mfree_hook = tr_freehook;
+ old_mmalloc_hook = mdp -> mmalloc_hook;
+ mdp -> mmalloc_hook = tr_mallochook;
+ old_mrealloc_hook = mdp -> mrealloc_hook;
+ mdp -> mrealloc_hook = tr_reallochook;
+ }
+ }
+
+#endif /* 0 */
+
+ return (1);
+}
+
diff --git a/gnu/usr.bin/gdb/mmalloc/mrealloc.c b/gnu/usr.bin/gdb/mmalloc/mrealloc.c
new file mode 100644
index 0000000..85bec56
--- /dev/null
+++ b/gnu/usr.bin/gdb/mmalloc/mrealloc.c
@@ -0,0 +1,160 @@
+/* Change the size of a block allocated by `mmalloc'.
+ Copyright 1990, 1991 Free Software Foundation
+ Written May 1989 by Mike Haertel.
+
+The GNU C Library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public License as
+published by the Free Software Foundation; either version 2 of the
+License, or (at your option) any later version.
+
+The GNU C Library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with the GNU C Library; see the file COPYING.LIB. If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA.
+
+ The author may be reached (Email) at the address mike@ai.mit.edu,
+ or (US mail) as Mike Haertel c/o Free Software Foundation. */
+
+#include <string.h> /* Prototypes for memcpy, memmove, memset, etc */
+
+#include "mmalloc.h"
+
+/* Resize the given region to the new size, returning a pointer
+ to the (possibly moved) region. This is optimized for speed;
+ some benchmarks seem to indicate that greater compactness is
+ achieved by unconditionally allocating and copying to a
+ new region. This module has incestuous knowledge of the
+ internals of both mfree and mmalloc. */
+
+PTR
+mrealloc (md, ptr, size)
+ PTR md;
+ PTR ptr;
+ size_t size;
+{
+ struct mdesc *mdp;
+ PTR result;
+ int type;
+ size_t block, blocks, oldlimit;
+
+ if (size == 0)
+ {
+ mfree (md, ptr);
+ return (mmalloc (md, 0));
+ }
+ else if (ptr == NULL)
+ {
+ return (mmalloc (md, size));
+ }
+
+ mdp = MD_TO_MDP (md);
+
+ if (mdp -> mrealloc_hook != NULL)
+ {
+ return ((*mdp -> mrealloc_hook) (md, ptr, size));
+ }
+
+ block = BLOCK (ptr);
+
+ type = mdp -> heapinfo[block].busy.type;
+ switch (type)
+ {
+ case 0:
+ /* Maybe reallocate a large block to a small fragment. */
+ if (size <= BLOCKSIZE / 2)
+ {
+ result = mmalloc (md, size);
+ if (result != NULL)
+ {
+ memcpy (result, ptr, size);
+ mfree (md, ptr);
+ return (result);
+ }
+ }
+
+ /* The new size is a large allocation as well;
+ see if we can hold it in place. */
+ blocks = BLOCKIFY (size);
+ if (blocks < mdp -> heapinfo[block].busy.info.size)
+ {
+ /* The new size is smaller; return excess memory to the free list. */
+ mdp -> heapinfo[block + blocks].busy.type = 0;
+ mdp -> heapinfo[block + blocks].busy.info.size
+ = mdp -> heapinfo[block].busy.info.size - blocks;
+ mdp -> heapinfo[block].busy.info.size = blocks;
+ mfree (md, ADDRESS (block + blocks));
+ result = ptr;
+ }
+ else if (blocks == mdp -> heapinfo[block].busy.info.size)
+ {
+ /* No size change necessary. */
+ result = ptr;
+ }
+ else
+ {
+ /* Won't fit, so allocate a new region that will.
+ Free the old region first in case there is sufficient
+ adjacent free space to grow without moving. */
+ blocks = mdp -> heapinfo[block].busy.info.size;
+ /* Prevent free from actually returning memory to the system. */
+ oldlimit = mdp -> heaplimit;
+ mdp -> heaplimit = 0;
+ mfree (md, ptr);
+ mdp -> heaplimit = oldlimit;
+ result = mmalloc (md, size);
+ if (result == NULL)
+ {
+ mmalloc (md, blocks * BLOCKSIZE);
+ return (NULL);
+ }
+ if (ptr != result)
+ {
+ memmove (result, ptr, blocks * BLOCKSIZE);
+ }
+ }
+ break;
+
+ default:
+ /* Old size is a fragment; type is logarithm
+ to base two of the fragment size. */
+ if (size > (size_t) (1 << (type - 1)) && size <= (size_t) (1 << type))
+ {
+ /* The new size is the same kind of fragment. */
+ result = ptr;
+ }
+ else
+ {
+ /* The new size is different; allocate a new space,
+ and copy the lesser of the new size and the old. */
+ result = mmalloc (md, size);
+ if (result == NULL)
+ {
+ return (NULL);
+ }
+ memcpy (result, ptr, MIN (size, (size_t) 1 << type));
+ mfree (md, ptr);
+ }
+ break;
+ }
+
+ return (result);
+}
+
+/* When using this package, provide a version of malloc/realloc/free built
+ on top of it, so that if we use the default sbrk() region we will not
+ collide with another malloc package trying to do the same thing, if
+ the application contains any "hidden" calls to malloc/realloc/free (such
+ as inside a system library). */
+
+PTR
+realloc (ptr, size)
+ PTR ptr;
+ size_t size;
+{
+ return (mrealloc ((PTR) NULL, ptr, size));
+}
diff --git a/gnu/usr.bin/gdb/mmalloc/mvalloc.c b/gnu/usr.bin/gdb/mmalloc/mvalloc.c
new file mode 100644
index 0000000..1ffba78
--- /dev/null
+++ b/gnu/usr.bin/gdb/mmalloc/mvalloc.c
@@ -0,0 +1,40 @@
+/* Allocate memory on a page boundary.
+ Copyright (C) 1991 Free Software Foundation, Inc.
+
+The GNU C Library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public License as
+published by the Free Software Foundation; either version 2 of the
+License, or (at your option) any later version.
+
+The GNU C Library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with the GNU C Library; see the file COPYING.LIB. If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA. */
+
+#include "mmalloc.h"
+
+/* Cache the pagesize for the current host machine. Note that if the host
+ does not readily provide a getpagesize() function, we need to emulate it
+ elsewhere, not clutter up this file with lots of kluges to try to figure
+ it out. */
+
+static size_t pagesize;
+extern int getpagesize PARAMS ((void));
+
+PTR
+mvalloc (md, size)
+ PTR md;
+ size_t size;
+{
+ if (pagesize == 0)
+ {
+ pagesize = getpagesize ();
+ }
+
+ return (mmemalign (md, pagesize, size));
+}
diff --git a/gnu/usr.bin/gdb/mmalloc/sbrk-sup.c b/gnu/usr.bin/gdb/mmalloc/sbrk-sup.c
new file mode 100644
index 0000000..e6a57d6
--- /dev/null
+++ b/gnu/usr.bin/gdb/mmalloc/sbrk-sup.c
@@ -0,0 +1,96 @@
+/* Support for sbrk() regions.
+ Copyright 1992 Free Software Foundation, Inc.
+ Contributed by Fred Fish at Cygnus Support. fnf@cygnus.com
+
+This file is part of the GNU C Library.
+
+The GNU C Library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public License as
+published by the Free Software Foundation; either version 2 of the
+License, or (at your option) any later version.
+
+The GNU C Library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with the GNU C Library; see the file COPYING.LIB. If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA. */
+
+#include <string.h> /* Prototypes for memcpy, memmove, memset, etc */
+
+#include "mmalloc.h"
+
+extern PTR sbrk ();
+
+/* The mmalloc() package can use a single implicit malloc descriptor
+ for mmalloc/mrealloc/mfree operations which do not supply an explicit
+ descriptor. For these operations, sbrk() is used to obtain more core
+ from the system, or return core. This allows mmalloc() to provide
+ backwards compatibility with the non-mmap'd version. */
+
+struct mdesc *__mmalloc_default_mdp;
+
+/* Use sbrk() to get more core. */
+
+static PTR
+sbrk_morecore (mdp, size)
+ struct mdesc *mdp;
+ int size;
+{
+ PTR result;
+
+ if ((result = sbrk (size)) == (PTR) -1)
+ {
+ result = NULL;
+ }
+ else
+ {
+ mdp -> breakval += size;
+ mdp -> top += size;
+ }
+ return (result);
+}
+
+/* Initialize the default malloc descriptor if this is the first time
+ a request has been made to use the default sbrk'd region.
+
+ Since no alignment guarantees are made about the initial value returned
+ by sbrk, test the initial value and (if necessary) sbrk enough additional
+ memory to start off with alignment to BLOCKSIZE. We actually only need
+ it aligned to an alignment suitable for any object, so this is overkill.
+ But at most it wastes just part of one BLOCKSIZE chunk of memory and
+ minimizes portability problems by avoiding us having to figure out
+ what the actual minimal alignment is. The rest of the malloc code
+ avoids this as well, by always aligning to the minimum of the requested
+ size rounded up to a power of two, or to BLOCKSIZE.
+
+ Note that we are going to use some memory starting at this initial sbrk
+ address for the sbrk region malloc descriptor, which is a struct, so the
+ base address must be suitably aligned. */
+
+struct mdesc *
+__mmalloc_sbrk_init ()
+{
+ PTR base;
+ unsigned int adj;
+
+ base = sbrk (0);
+ adj = RESIDUAL (base, BLOCKSIZE);
+ if (adj != 0)
+ {
+ sbrk (BLOCKSIZE - adj);
+ base = sbrk (0);
+ }
+ __mmalloc_default_mdp = (struct mdesc *) sbrk (sizeof (struct mdesc));
+ memset ((char *) __mmalloc_default_mdp, 0, sizeof (struct mdesc));
+ __mmalloc_default_mdp -> morecore = sbrk_morecore;
+ __mmalloc_default_mdp -> base = base;
+ __mmalloc_default_mdp -> breakval = __mmalloc_default_mdp -> top = sbrk (0);
+ __mmalloc_default_mdp -> fd = -1;
+ return (__mmalloc_default_mdp);
+}
+
+
diff --git a/gnu/usr.bin/grep/AUTHORS b/gnu/usr.bin/grep/AUTHORS
new file mode 100644
index 0000000..e3e033b
--- /dev/null
+++ b/gnu/usr.bin/grep/AUTHORS
@@ -0,0 +1,29 @@
+Mike Haertel wrote the main program and the dfa and kwset matchers.
+
+Arthur David Olson contributed the heuristics for finding fixed substrings
+at the end of dfa.c.
+
+Richard Stallman and Karl Berry wrote the regex backtracking matcher.
+
+Henry Spencer wrote the original test suite from which grep's was derived.
+
+Scott Anderson invented the Khadafy test.
+
+David MacKenzie wrote the automatic configuration software use to
+produce the configure script.
+
+Authors of the replacements for standard library routines are identified
+in the corresponding source files.
+
+The idea of using Boyer-Moore type algorithms to quickly filter out
+non-matching text before calling the regexp matcher was originally due
+to James Woods. He also contributed some code to early versions of
+GNU grep.
+
+Finally, I would like to thank Andrew Hume for many fascinating discussions
+of string searching issues over the years. Hume & Sunday's excellent
+paper on fast string searching (AT&T Bell Laboratories CSTR #156)
+describes some of the history of the subject, as well as providing
+exhaustive performance analysis of various implementation alternatives.
+The inner loop of GNU grep is similar to Hume & Sunday's recommended
+"Tuned Boyer Moore" inner loop.
diff --git a/gnu/usr.bin/grep/COPYING b/gnu/usr.bin/grep/COPYING
new file mode 100644
index 0000000..a43ea21
--- /dev/null
+++ b/gnu/usr.bin/grep/COPYING
@@ -0,0 +1,339 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 675 Mass Ave, Cambridge, MA 02139, USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ Appendix: How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) 19yy <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) 19yy name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/gnu/usr.bin/grep/Makefile b/gnu/usr.bin/grep/Makefile
new file mode 100644
index 0000000..0cfcf6b
--- /dev/null
+++ b/gnu/usr.bin/grep/Makefile
@@ -0,0 +1,17 @@
+PROG= grep
+SRCS= dfa.c grep.c getopt.c kwset.c obstack.c search.c
+CFLAGS+=-DGREP -DHAVE_STRING_H=1 -DHAVE_SYS_PARAM_H=1 -DHAVE_UNISTD_H=1 \
+ -DHAVE_GETPAGESIZE=1 -DHAVE_MEMCHR=1 -DHAVE_STRERROR=1 \
+ -DHAVE_VALLOC=1 -DHAVE_MMAP=1 -DHAVE_FTS=1
+
+LINKS+= ${BINDIR}/grep ${BINDIR}/egrep \
+ ${BINDIR}/grep ${BINDIR}/fgrep
+MLINKS= grep.1 egrep.1 grep.1 fgrep.1
+
+DPADD+= ${LIBGNUREGEX}
+LDADD+= -lgnuregex
+
+check: all
+ sh ${.CURDIR}/tests/check.sh ${.CURDIR}/tests
+
+.include <bsd.prog.mk>
diff --git a/gnu/usr.bin/grep/NEWS b/gnu/usr.bin/grep/NEWS
new file mode 100644
index 0000000..eb0b513
--- /dev/null
+++ b/gnu/usr.bin/grep/NEWS
@@ -0,0 +1,35 @@
+Version 2.0:
+
+The most important user visible change is that egrep and fgrep have
+disappeared as separate programs into the single grep program mandated
+by POSIX 1003.2. New options -G, -E, and -F have been added,
+selecting grep, egrep, and fgrep behavior respectively. For
+compatibility with historical practice, hard links named egrep and
+fgrep are also provided. See the manual page for details.
+
+In addition, the regular expression facilities described in Posix
+draft 11.2 are now supported, except for internationalization features
+related to locale-dependent collating sequence information.
+
+There is a new option, -L, which is like -l except it lists
+files which don't contain matches. The reason this option was
+added is because '-l -v' doesn't do what you expect.
+
+Performance has been improved; the amount of improvement is platform
+dependent, but (for example) grep 2.0 typically runs at least 30% faster
+than grep 1.6 on a DECstation using the MIPS compiler. Where possible,
+grep now uses mmap() for file input; on a Sun 4 running SunOS 4.1 this
+may cut system time by as much as half, for a total reduction in running
+time by nearly 50%. On machines that don't use mmap(), the buffering
+code has been rewritten to choose more favorable alignments and buffer
+sizes for read().
+
+Portability has been substantially cleaned up, and an automatic
+configure script is now provided.
+
+The internals have changed in ways too numerous to mention.
+People brave enough to reuse the DFA matcher in other programs
+will now have their bravery amply "rewarded", for the interface
+to that file has been completely changed. Some changes were
+necessary to track the evolution of the regex package, and since
+I was changing it anyway I decided to do a general cleanup.
diff --git a/gnu/usr.bin/grep/PROJECTS b/gnu/usr.bin/grep/PROJECTS
new file mode 100644
index 0000000..67e9a2a
--- /dev/null
+++ b/gnu/usr.bin/grep/PROJECTS
@@ -0,0 +1,15 @@
+Write Texinfo documentation for grep. The manual page would be a good
+place to start, but Info documents are also supposed to contain a
+tutorial and examples.
+
+Fix the DFA matcher to never use exponential space. (Fortunately, these
+cases are rare.)
+
+Improve the performance of the regex backtracking matcher. This matcher
+is agonizingly slow, and is responsible for grep sometimes being slower
+than Unix grep when backreferences are used.
+
+Provide support for the Posix [= =] and [. .] constructs. This is
+difficult because it requires locale-dependent details of the character
+set and collating sequence, but Posix does not standardize any method
+for accessing this information!
diff --git a/gnu/usr.bin/grep/README b/gnu/usr.bin/grep/README
new file mode 100644
index 0000000..bc34a85
--- /dev/null
+++ b/gnu/usr.bin/grep/README
@@ -0,0 +1,28 @@
+This is GNU grep 2.0, the "fastest grep in the west" (we hope). All
+bugs reported in previous releases have been fixed. Many exciting new
+bugs have probably been introduced in this major revision.
+
+GNU grep is provided "as is" with no warranty. The exact terms
+under which you may use and (re)distribute this program are detailed
+in the GNU General Public License, in the file COPYING.
+
+GNU grep is based on a fast lazy-state deterministic matcher (about
+twice as fast as stock Unix egrep) hybridized with a Boyer-Moore-Gosper
+search for a fixed string that eliminates impossible text from being
+considered by the full regexp matcher without necessarily having to
+look at every character. The result is typically many times faster
+than Unix grep or egrep. (Regular expressions containing backreferencing
+will run more slowly, however.)
+
+See the file AUTHORS for a list of authors and other contributors.
+
+See the file INSTALL for compilation and installation instructions.
+
+See the file MANIFEST for a list of files in this distribution.
+
+See the file NEWS for a description of major changes in this release.
+
+See the file PROJECTS if you want to be mentioned in AUTHORS.
+
+Send bug reports to bug-gnu-utils@prep.ai.mit.edu. Be sure to
+include the word "grep" in your Subject: header field.
diff --git a/gnu/usr.bin/grep/dfa.c b/gnu/usr.bin/grep/dfa.c
new file mode 100644
index 0000000..0409b1e
--- /dev/null
+++ b/gnu/usr.bin/grep/dfa.c
@@ -0,0 +1,2511 @@
+/* dfa.c - deterministic extended regexp routines for GNU
+ Copyright (C) 1988 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* Written June, 1988 by Mike Haertel
+ Modified July, 1988 by Arthur David Olson to assist BMG speedups */
+
+#include <assert.h>
+#include <ctype.h>
+#include <stdio.h>
+
+#ifdef STDC_HEADERS
+#include <stdlib.h>
+#else
+#include <sys/types.h>
+extern char *calloc(), *malloc(), *realloc();
+extern void free();
+#endif
+
+#if defined(HAVE_STRING_H) || defined(STDC_HEADERS)
+#include <string.h>
+#undef index
+#define index strchr
+#else
+#include <strings.h>
+#endif
+
+#ifndef isgraph
+#define isgraph(C) (isprint(C) && !isspace(C))
+#endif
+
+#define ISALPHA(C) isalpha(C)
+#define ISUPPER(C) isupper(C)
+#define ISLOWER(C) islower(C)
+#define ISDIGIT(C) isdigit(C)
+#define ISXDIGIT(C) isxdigit(C)
+#define ISSPACE(C) isspace(C)
+#define ISPUNCT(C) ispunct(C)
+#define ISALNUM(C) isalnum(C)
+#define ISPRINT(C) isprint(C)
+#define ISGRAPH(C) isgraph(C)
+#define ISCNTRL(C) iscntrl(C)
+
+#include "dfa.h"
+#include "gnuregex.h"
+
+#if __STDC__
+typedef void *ptr_t;
+#else
+typedef char *ptr_t;
+#endif
+
+static void dfamust();
+
+static ptr_t
+xcalloc(n, s)
+ int n;
+ size_t s;
+{
+ ptr_t r = calloc(n, s);
+
+ if (!r)
+ dfaerror("Memory exhausted");
+ return r;
+}
+
+static ptr_t
+xmalloc(n)
+ size_t n;
+{
+ ptr_t r = malloc(n);
+
+ assert(n != 0);
+ if (!r)
+ dfaerror("Memory exhausted");
+ return r;
+}
+
+static ptr_t
+xrealloc(p, n)
+ ptr_t p;
+ size_t n;
+{
+ ptr_t r = realloc(p, n);
+
+ assert(n != 0);
+ if (!r)
+ dfaerror("Memory exhausted");
+ return r;
+}
+
+#define CALLOC(p, t, n) ((p) = (t *) xcalloc((n), sizeof (t)))
+#define MALLOC(p, t, n) ((p) = (t *) xmalloc((n) * sizeof (t)))
+#define REALLOC(p, t, n) ((p) = (t *) xrealloc((ptr_t) (p), (n) * sizeof (t)))
+
+/* Reallocate an array of type t if nalloc is too small for index. */
+#define REALLOC_IF_NECESSARY(p, t, nalloc, index) \
+ if ((index) >= (nalloc)) \
+ { \
+ while ((index) >= (nalloc)) \
+ (nalloc) *= 2; \
+ REALLOC(p, t, nalloc); \
+ }
+
+#ifdef DEBUG
+
+static void
+prtok(t)
+ token t;
+{
+ char *s;
+
+ if (t < 0)
+ fprintf(stderr, "END");
+ else if (t < NOTCHAR)
+ fprintf(stderr, "%c", t);
+ else
+ {
+ switch (t)
+ {
+ case EMPTY: s = "EMPTY"; break;
+ case BACKREF: s = "BACKREF"; break;
+ case BEGLINE: s = "BEGLINE"; break;
+ case ENDLINE: s = "ENDLINE"; break;
+ case BEGWORD: s = "BEGWORD"; break;
+ case ENDWORD: s = "ENDWORD"; break;
+ case LIMWORD: s = "LIMWORD"; break;
+ case NOTLIMWORD: s = "NOTLIMWORD"; break;
+ case QMARK: s = "QMARK"; break;
+ case STAR: s = "STAR"; break;
+ case PLUS: s = "PLUS"; break;
+ case CAT: s = "CAT"; break;
+ case OR: s = "OR"; break;
+ case ORTOP: s = "ORTOP"; break;
+ case LPAREN: s = "LPAREN"; break;
+ case RPAREN: s = "RPAREN"; break;
+ default: s = "CSET"; break;
+ }
+ fprintf(stderr, "%s", s);
+ }
+}
+#endif /* DEBUG */
+
+/* Stuff pertaining to charclasses. */
+
+static int
+tstbit(b, c)
+ int b;
+ charclass c;
+{
+ return c[b / INTBITS] & 1 << b % INTBITS;
+}
+
+static void
+setbit(b, c)
+ int b;
+ charclass c;
+{
+ c[b / INTBITS] |= 1 << b % INTBITS;
+}
+
+static void
+clrbit(b, c)
+ int b;
+ charclass c;
+{
+ c[b / INTBITS] &= ~(1 << b % INTBITS);
+}
+
+static void
+copyset(src, dst)
+ charclass src;
+ charclass dst;
+{
+ int i;
+
+ for (i = 0; i < CHARCLASS_INTS; ++i)
+ dst[i] = src[i];
+}
+
+static void
+zeroset(s)
+ charclass s;
+{
+ int i;
+
+ for (i = 0; i < CHARCLASS_INTS; ++i)
+ s[i] = 0;
+}
+
+static void
+notset(s)
+ charclass s;
+{
+ int i;
+
+ for (i = 0; i < CHARCLASS_INTS; ++i)
+ s[i] = ~s[i];
+}
+
+static int
+equal(s1, s2)
+ charclass s1;
+ charclass s2;
+{
+ int i;
+
+ for (i = 0; i < CHARCLASS_INTS; ++i)
+ if (s1[i] != s2[i])
+ return 0;
+ return 1;
+}
+
+/* A pointer to the current dfa is kept here during parsing. */
+static struct dfa *dfa;
+
+/* Find the index of charclass s in dfa->charclasses, or allocate a new charclass. */
+static int
+charclass_index(s)
+ charclass s;
+{
+ int i;
+
+ for (i = 0; i < dfa->cindex; ++i)
+ if (equal(s, dfa->charclasses[i]))
+ return i;
+ REALLOC_IF_NECESSARY(dfa->charclasses, charclass, dfa->calloc, dfa->cindex);
+ ++dfa->cindex;
+ copyset(s, dfa->charclasses[i]);
+ return i;
+}
+
+/* Syntax bits controlling the behavior of the lexical analyzer. */
+static int syntax_bits, syntax_bits_set;
+
+/* Flag for case-folding letters into sets. */
+static int case_fold;
+
+/* Entry point to set syntax options. */
+void
+dfasyntax(bits, fold)
+ int bits;
+ int fold;
+{
+ syntax_bits_set = 1;
+ syntax_bits = bits;
+ case_fold = fold;
+}
+
+/* Lexical analyzer. All the dross that deals with the obnoxious
+ GNU Regex syntax bits is located here. The poor, suffering
+ reader is referred to the GNU Regex documentation for the
+ meaning of the @#%!@#%^!@ syntax bits. */
+
+static char *lexstart; /* Pointer to beginning of input string. */
+static char *lexptr; /* Pointer to next input character. */
+static lexleft; /* Number of characters remaining. */
+static token lasttok; /* Previous token returned; initially END. */
+static int laststart; /* True if we're separated from beginning or (, |
+ only by zero-width characters. */
+static int parens; /* Count of outstanding left parens. */
+static int minrep, maxrep; /* Repeat counts for {m,n}. */
+
+/* Note that characters become unsigned here. */
+#define FETCH(c, eoferr) \
+ { \
+ if (! lexleft) \
+ if (eoferr != 0) \
+ dfaerror(eoferr); \
+ else \
+ return END; \
+ (c) = (unsigned char) *lexptr++; \
+ --lexleft; \
+ }
+
+#define FUNC(F, P) static int F(c) int c; { return P(c); }
+
+FUNC(is_alpha, ISALPHA)
+FUNC(is_upper, ISUPPER)
+FUNC(is_lower, ISLOWER)
+FUNC(is_digit, ISDIGIT)
+FUNC(is_xdigit, ISXDIGIT)
+FUNC(is_space, ISSPACE)
+FUNC(is_punct, ISPUNCT)
+FUNC(is_alnum, ISALNUM)
+FUNC(is_print, ISPRINT)
+FUNC(is_graph, ISGRAPH)
+FUNC(is_cntrl, ISCNTRL)
+
+/* The following list maps the names of the Posix named character classes
+ to predicate functions that determine whether a given character is in
+ the class. The leading [ has already been eaten by the lexical analyzer. */
+static struct {
+ char *name;
+ int (*pred)();
+} prednames[] = {
+ ":alpha:]", is_alpha,
+ ":upper:]", is_upper,
+ ":lower:]", is_lower,
+ ":digit:]", is_digit,
+ ":xdigit:]", is_xdigit,
+ ":space:]", is_space,
+ ":punct:]", is_punct,
+ ":alnum:]", is_alnum,
+ ":print:]", is_print,
+ ":graph:]", is_graph,
+ ":cntrl:]", is_cntrl,
+ 0
+};
+
+static int
+looking_at(s)
+ char *s;
+{
+ int len;
+
+ len = strlen(s);
+ if (lexleft < len)
+ return 0;
+ return strncmp(s, lexptr, len) == 0;
+}
+
+static token
+lex()
+{
+ token c, c1, c2;
+ int backslash = 0, invert;
+ charclass ccl;
+ int i;
+
+ /* Basic plan: We fetch a character. If it's a backslash,
+ we set the backslash flag and go through the loop again.
+ On the plus side, this avoids having a duplicate of the
+ main switch inside the backslash case. On the minus side,
+ it means that just about every case begins with
+ "if (backslash) ...". */
+ for (i = 0; i < 2; ++i)
+ {
+ FETCH(c, 0);
+ switch (c)
+ {
+ case '\\':
+ if (backslash)
+ goto normal_char;
+ if (lexleft == 0)
+ dfaerror("Unfinished \\ escape");
+ backslash = 1;
+ break;
+
+ case '^':
+ if (backslash)
+ goto normal_char;
+ if (syntax_bits & RE_CONTEXT_INDEP_ANCHORS
+ || lasttok == END
+ || lasttok == LPAREN
+ || lasttok == OR)
+ return lasttok = BEGLINE;
+ goto normal_char;
+
+ case '$':
+ if (backslash)
+ goto normal_char;
+ if (syntax_bits & RE_CONTEXT_INDEP_ANCHORS
+ || lexleft == 0
+ || (syntax_bits & RE_NO_BK_PARENS
+ ? lexleft > 0 && *lexptr == ')'
+ : lexleft > 1 && lexptr[0] == '\\' && lexptr[1] == ')')
+ || (syntax_bits & RE_NO_BK_VBAR
+ ? lexleft > 0 && *lexptr == '|'
+ : lexleft > 1 && lexptr[0] == '\\' && lexptr[1] == '|')
+ || ((syntax_bits & RE_NEWLINE_ALT)
+ && lexleft > 0 && *lexptr == '\n'))
+ return lasttok = ENDLINE;
+ goto normal_char;
+
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ if (backslash && !(syntax_bits & RE_NO_BK_REFS))
+ {
+ laststart = 0;
+ return lasttok = BACKREF;
+ }
+ goto normal_char;
+
+ case '<':
+ if (backslash)
+ return lasttok = BEGWORD;
+ goto normal_char;
+
+ case '>':
+ if (backslash)
+ return lasttok = ENDWORD;
+ goto normal_char;
+
+ case 'b':
+ if (backslash)
+ return lasttok = LIMWORD;
+ goto normal_char;
+
+ case 'B':
+ if (backslash)
+ return lasttok = NOTLIMWORD;
+ goto normal_char;
+
+ case '?':
+ if (syntax_bits & RE_LIMITED_OPS)
+ goto normal_char;
+ if (backslash != ((syntax_bits & RE_BK_PLUS_QM) != 0))
+ goto normal_char;
+ if (!(syntax_bits & RE_CONTEXT_INDEP_OPS) && laststart)
+ goto normal_char;
+ return lasttok = QMARK;
+
+ case '*':
+ if (backslash)
+ goto normal_char;
+ if (!(syntax_bits & RE_CONTEXT_INDEP_OPS) && laststart)
+ goto normal_char;
+ return lasttok = STAR;
+
+ case '+':
+ if (syntax_bits & RE_LIMITED_OPS)
+ goto normal_char;
+ if (backslash != ((syntax_bits & RE_BK_PLUS_QM) != 0))
+ goto normal_char;
+ if (!(syntax_bits & RE_CONTEXT_INDEP_OPS) && laststart)
+ goto normal_char;
+ return lasttok = PLUS;
+
+ case '{':
+ if (!(syntax_bits & RE_INTERVALS))
+ goto normal_char;
+ if (backslash != ((syntax_bits & RE_NO_BK_BRACES) == 0))
+ goto normal_char;
+ minrep = maxrep = 0;
+ /* Cases:
+ {M} - exact count
+ {M,} - minimum count, maximum is infinity
+ {,M} - 0 through M
+ {M,N} - M through N */
+ FETCH(c, "unfinished repeat count");
+ if (ISDIGIT(c))
+ {
+ minrep = c - '0';
+ for (;;)
+ {
+ FETCH(c, "unfinished repeat count");
+ if (!ISDIGIT(c))
+ break;
+ minrep = 10 * minrep + c - '0';
+ }
+ }
+ else if (c != ',')
+ dfaerror("malformed repeat count");
+ if (c == ',')
+ for (;;)
+ {
+ FETCH(c, "unfinished repeat count");
+ if (!ISDIGIT(c))
+ break;
+ maxrep = 10 * maxrep + c - '0';
+ }
+ else
+ maxrep = minrep;
+ if (!(syntax_bits & RE_NO_BK_BRACES))
+ {
+ if (c != '\\')
+ dfaerror("malformed repeat count");
+ FETCH(c, "unfinished repeat count");
+ }
+ if (c != '}')
+ dfaerror("malformed repeat count");
+ laststart = 0;
+ return lasttok = REPMN;
+
+ case '|':
+ if (syntax_bits & RE_LIMITED_OPS)
+ goto normal_char;
+ if (backslash != ((syntax_bits & RE_NO_BK_VBAR) == 0))
+ goto normal_char;
+ laststart = 1;
+ return lasttok = OR;
+
+ case '\n':
+ if (syntax_bits & RE_LIMITED_OPS
+ || backslash
+ || !(syntax_bits & RE_NEWLINE_ALT))
+ goto normal_char;
+ laststart = 1;
+ return lasttok = OR;
+
+ case '(':
+ if (backslash != ((syntax_bits & RE_NO_BK_PARENS) == 0))
+ goto normal_char;
+ ++parens;
+ laststart = 1;
+ return lasttok = LPAREN;
+
+ case ')':
+ if (backslash != ((syntax_bits & RE_NO_BK_PARENS) == 0))
+ goto normal_char;
+ if (parens == 0 && syntax_bits & RE_UNMATCHED_RIGHT_PAREN_ORD)
+ goto normal_char;
+ --parens;
+ laststart = 0;
+ return lasttok = RPAREN;
+
+ case '.':
+ if (backslash)
+ goto normal_char;
+ zeroset(ccl);
+ notset(ccl);
+ if (!(syntax_bits & RE_DOT_NEWLINE))
+ clrbit('\n', ccl);
+ if (syntax_bits & RE_DOT_NOT_NULL)
+ clrbit('\0', ccl);
+ laststart = 0;
+ return lasttok = CSET + charclass_index(ccl);
+
+ case 'w':
+ case 'W':
+ if (!backslash)
+ goto normal_char;
+ zeroset(ccl);
+ for (c2 = 0; c2 < NOTCHAR; ++c2)
+ if (ISALNUM(c2))
+ setbit(c2, ccl);
+ if (c == 'W')
+ notset(ccl);
+ laststart = 0;
+ return lasttok = CSET + charclass_index(ccl);
+
+ case '[':
+ if (backslash)
+ goto normal_char;
+ zeroset(ccl);
+ FETCH(c, "Unbalanced [");
+ if (c == '^')
+ {
+ FETCH(c, "Unbalanced [");
+ invert = 1;
+ }
+ else
+ invert = 0;
+ do
+ {
+ /* Nobody ever said this had to be fast. :-)
+ Note that if we're looking at some other [:...:]
+ construct, we just treat it as a bunch of ordinary
+ characters. We can do this because we assume
+ regex has checked for syntax errors before
+ dfa is ever called. */
+ if (c == '[' && (syntax_bits & RE_CHAR_CLASSES))
+ for (c1 = 0; prednames[c1].name; ++c1)
+ if (looking_at(prednames[c1].name))
+ {
+ for (c2 = 0; c2 < NOTCHAR; ++c2)
+ if ((*prednames[c1].pred)(c2))
+ setbit(c2, ccl);
+ lexptr += strlen(prednames[c1].name);
+ lexleft -= strlen(prednames[c1].name);
+ FETCH(c1, "Unbalanced [");
+ goto skip;
+ }
+ if (c == '\\' && (syntax_bits & RE_BACKSLASH_ESCAPE_IN_LISTS))
+ FETCH(c, "Unbalanced [");
+ FETCH(c1, "Unbalanced [");
+ if (c1 == '-')
+ {
+ FETCH(c2, "Unbalanced [");
+ if (c2 == ']')
+ {
+ /* In the case [x-], the - is an ordinary hyphen,
+ which is left in c1, the lookahead character. */
+ --lexptr;
+ ++lexleft;
+ c2 = c;
+ }
+ else
+ {
+ if (c2 == '\\'
+ && (syntax_bits & RE_BACKSLASH_ESCAPE_IN_LISTS))
+ FETCH(c2, "Unbalanced [");
+ FETCH(c1, "Unbalanced [");
+ }
+ }
+ else
+ c2 = c;
+ while (c <= c2)
+ {
+ setbit(c, ccl);
+ if (case_fold)
+ if (ISUPPER(c))
+ setbit(tolower(c), ccl);
+ else if (ISLOWER(c))
+ setbit(toupper(c), ccl);
+ ++c;
+ }
+ skip:
+ ;
+ }
+ while ((c = c1) != ']');
+ if (invert)
+ {
+ notset(ccl);
+ if (syntax_bits & RE_HAT_LISTS_NOT_NEWLINE)
+ clrbit('\n', ccl);
+ }
+ laststart = 0;
+ return lasttok = CSET + charclass_index(ccl);
+
+ default:
+ normal_char:
+ laststart = 0;
+ if (case_fold && ISALPHA(c))
+ {
+ zeroset(ccl);
+ setbit(c, ccl);
+ if (isupper(c))
+ setbit(tolower(c), ccl);
+ else
+ setbit(toupper(c), ccl);
+ return lasttok = CSET + charclass_index(ccl);
+ }
+ return c;
+ }
+ }
+
+ /* The above loop should consume at most a backslash
+ and some other character. */
+ abort();
+}
+
+/* Recursive descent parser for regular expressions. */
+
+static token tok; /* Lookahead token. */
+static depth; /* Current depth of a hypothetical stack
+ holding deferred productions. This is
+ used to determine the depth that will be
+ required of the real stack later on in
+ dfaanalyze(). */
+
+/* Add the given token to the parse tree, maintaining the depth count and
+ updating the maximum depth if necessary. */
+static void
+addtok(t)
+ token t;
+{
+ REALLOC_IF_NECESSARY(dfa->tokens, token, dfa->talloc, dfa->tindex);
+ dfa->tokens[dfa->tindex++] = t;
+
+ switch (t)
+ {
+ case QMARK:
+ case STAR:
+ case PLUS:
+ break;
+
+ case CAT:
+ case OR:
+ case ORTOP:
+ --depth;
+ break;
+
+ default:
+ ++dfa->nleaves;
+ case EMPTY:
+ ++depth;
+ break;
+ }
+ if (depth > dfa->depth)
+ dfa->depth = depth;
+}
+
+/* The grammar understood by the parser is as follows.
+
+ regexp:
+ regexp OR branch
+ branch
+
+ branch:
+ branch closure
+ closure
+
+ closure:
+ closure QMARK
+ closure STAR
+ closure PLUS
+ atom
+
+ atom:
+ <normal character>
+ CSET
+ BACKREF
+ BEGLINE
+ ENDLINE
+ BEGWORD
+ ENDWORD
+ LIMWORD
+ NOTLIMWORD
+ <empty>
+
+ The parser builds a parse tree in postfix form in an array of tokens. */
+
+#if __STDC__
+static void regexp(int);
+#else
+static void regexp();
+#endif
+
+static void
+atom()
+{
+ if ((tok >= 0 && tok < NOTCHAR) || tok >= CSET || tok == BACKREF
+ || tok == BEGLINE || tok == ENDLINE || tok == BEGWORD
+ || tok == ENDWORD || tok == LIMWORD || tok == NOTLIMWORD)
+ {
+ addtok(tok);
+ tok = lex();
+ }
+ else if (tok == LPAREN)
+ {
+ tok = lex();
+ regexp(0);
+ if (tok != RPAREN)
+ dfaerror("Unbalanced (");
+ tok = lex();
+ }
+ else
+ addtok(EMPTY);
+}
+
+/* Return the number of tokens in the given subexpression. */
+static int
+nsubtoks(tindex)
+{
+ int ntoks1;
+
+ switch (dfa->tokens[tindex - 1])
+ {
+ default:
+ return 1;
+ case QMARK:
+ case STAR:
+ case PLUS:
+ return 1 + nsubtoks(tindex - 1);
+ case CAT:
+ case OR:
+ case ORTOP:
+ ntoks1 = nsubtoks(tindex - 1);
+ return 1 + ntoks1 + nsubtoks(tindex - 1 - ntoks1);
+ }
+}
+
+/* Copy the given subexpression to the top of the tree. */
+static void
+copytoks(tindex, ntokens)
+ int tindex, ntokens;
+{
+ int i;
+
+ for (i = 0; i < ntokens; ++i)
+ addtok(dfa->tokens[tindex + i]);
+}
+
+static void
+closure()
+{
+ int tindex, ntokens, i;
+
+ atom();
+ while (tok == QMARK || tok == STAR || tok == PLUS || tok == REPMN)
+ if (tok == REPMN)
+ {
+ ntokens = nsubtoks(dfa->tindex);
+ tindex = dfa->tindex - ntokens;
+ if (maxrep == 0)
+ addtok(PLUS);
+ if (minrep == 0)
+ addtok(QMARK);
+ for (i = 1; i < minrep; ++i)
+ {
+ copytoks(tindex, ntokens);
+ addtok(CAT);
+ }
+ for (; i < maxrep; ++i)
+ {
+ copytoks(tindex, ntokens);
+ addtok(QMARK);
+ addtok(CAT);
+ }
+ tok = lex();
+ }
+ else
+ {
+ addtok(tok);
+ tok = lex();
+ }
+}
+
+static void
+branch()
+{
+ closure();
+ while (tok != RPAREN && tok != OR && tok >= 0)
+ {
+ closure();
+ addtok(CAT);
+ }
+}
+
+static void
+regexp(toplevel)
+ int toplevel;
+{
+ branch();
+ while (tok == OR)
+ {
+ tok = lex();
+ branch();
+ if (toplevel)
+ addtok(ORTOP);
+ else
+ addtok(OR);
+ }
+}
+
+/* Main entry point for the parser. S is a string to be parsed, len is the
+ length of the string, so s can include NUL characters. D is a pointer to
+ the struct dfa to parse into. */
+void
+dfaparse(s, len, d)
+ char *s;
+ size_t len;
+ struct dfa *d;
+
+{
+ dfa = d;
+ lexstart = lexptr = s;
+ lexleft = len;
+ lasttok = END;
+ laststart = 1;
+ parens = 0;
+
+ if (! syntax_bits_set)
+ dfaerror("No syntax specified");
+
+ tok = lex();
+ depth = d->depth;
+
+ regexp(1);
+
+ if (tok != END)
+ dfaerror("Unbalanced )");
+
+ addtok(END - d->nregexps);
+ addtok(CAT);
+
+ if (d->nregexps)
+ addtok(ORTOP);
+
+ ++d->nregexps;
+}
+
+/* Some primitives for operating on sets of positions. */
+
+/* Copy one set to another; the destination must be large enough. */
+static void
+copy(src, dst)
+ position_set *src;
+ position_set *dst;
+{
+ int i;
+
+ for (i = 0; i < src->nelem; ++i)
+ dst->elems[i] = src->elems[i];
+ dst->nelem = src->nelem;
+}
+
+/* Insert a position in a set. Position sets are maintained in sorted
+ order according to index. If position already exists in the set with
+ the same index then their constraints are logically or'd together.
+ S->elems must point to an array large enough to hold the resulting set. */
+static void
+insert(p, s)
+ position p;
+ position_set *s;
+{
+ int i;
+ position t1, t2;
+
+ for (i = 0; i < s->nelem && p.index < s->elems[i].index; ++i)
+ ;
+ if (i < s->nelem && p.index == s->elems[i].index)
+ s->elems[i].constraint |= p.constraint;
+ else
+ {
+ t1 = p;
+ ++s->nelem;
+ while (i < s->nelem)
+ {
+ t2 = s->elems[i];
+ s->elems[i++] = t1;
+ t1 = t2;
+ }
+ }
+}
+
+/* Merge two sets of positions into a third. The result is exactly as if
+ the positions of both sets were inserted into an initially empty set. */
+static void
+merge(s1, s2, m)
+ position_set *s1;
+ position_set *s2;
+ position_set *m;
+{
+ int i = 0, j = 0;
+
+ m->nelem = 0;
+ while (i < s1->nelem && j < s2->nelem)
+ if (s1->elems[i].index > s2->elems[j].index)
+ m->elems[m->nelem++] = s1->elems[i++];
+ else if (s1->elems[i].index < s2->elems[j].index)
+ m->elems[m->nelem++] = s2->elems[j++];
+ else
+ {
+ m->elems[m->nelem] = s1->elems[i++];
+ m->elems[m->nelem++].constraint |= s2->elems[j++].constraint;
+ }
+ while (i < s1->nelem)
+ m->elems[m->nelem++] = s1->elems[i++];
+ while (j < s2->nelem)
+ m->elems[m->nelem++] = s2->elems[j++];
+}
+
+/* Delete a position from a set. */
+static void
+delete(p, s)
+ position p;
+ position_set *s;
+{
+ int i;
+
+ for (i = 0; i < s->nelem; ++i)
+ if (p.index == s->elems[i].index)
+ break;
+ if (i < s->nelem)
+ for (--s->nelem; i < s->nelem; ++i)
+ s->elems[i] = s->elems[i + 1];
+}
+
+/* Find the index of the state corresponding to the given position set with
+ the given preceding context, or create a new state if there is no such
+ state. Newline and letter tell whether we got here on a newline or
+ letter, respectively. */
+static int
+state_index(d, s, newline, letter)
+ struct dfa *d;
+ position_set *s;
+ int newline;
+ int letter;
+{
+ int hash = 0;
+ int constraint;
+ int i, j;
+
+ newline = newline ? 1 : 0;
+ letter = letter ? 1 : 0;
+
+ for (i = 0; i < s->nelem; ++i)
+ hash ^= s->elems[i].index + s->elems[i].constraint;
+
+ /* Try to find a state that exactly matches the proposed one. */
+ for (i = 0; i < d->sindex; ++i)
+ {
+ if (hash != d->states[i].hash || s->nelem != d->states[i].elems.nelem
+ || newline != d->states[i].newline || letter != d->states[i].letter)
+ continue;
+ for (j = 0; j < s->nelem; ++j)
+ if (s->elems[j].constraint
+ != d->states[i].elems.elems[j].constraint
+ || s->elems[j].index != d->states[i].elems.elems[j].index)
+ break;
+ if (j == s->nelem)
+ return i;
+ }
+
+ /* We'll have to create a new state. */
+ REALLOC_IF_NECESSARY(d->states, dfa_state, d->salloc, d->sindex);
+ d->states[i].hash = hash;
+ MALLOC(d->states[i].elems.elems, position, s->nelem);
+ copy(s, &d->states[i].elems);
+ d->states[i].newline = newline;
+ d->states[i].letter = letter;
+ d->states[i].backref = 0;
+ d->states[i].constraint = 0;
+ d->states[i].first_end = 0;
+ for (j = 0; j < s->nelem; ++j)
+ if (d->tokens[s->elems[j].index] < 0)
+ {
+ constraint = s->elems[j].constraint;
+ if (SUCCEEDS_IN_CONTEXT(constraint, newline, 0, letter, 0)
+ || SUCCEEDS_IN_CONTEXT(constraint, newline, 0, letter, 1)
+ || SUCCEEDS_IN_CONTEXT(constraint, newline, 1, letter, 0)
+ || SUCCEEDS_IN_CONTEXT(constraint, newline, 1, letter, 1))
+ d->states[i].constraint |= constraint;
+ if (! d->states[i].first_end)
+ d->states[i].first_end = d->tokens[s->elems[j].index];
+ }
+ else if (d->tokens[s->elems[j].index] == BACKREF)
+ {
+ d->states[i].constraint = NO_CONSTRAINT;
+ d->states[i].backref = 1;
+ }
+
+ ++d->sindex;
+
+ return i;
+}
+
+/* Find the epsilon closure of a set of positions. If any position of the set
+ contains a symbol that matches the empty string in some context, replace
+ that position with the elements of its follow labeled with an appropriate
+ constraint. Repeat exhaustively until no funny positions are left.
+ S->elems must be large enough to hold the result. */
+void
+epsclosure(s, d)
+ position_set *s;
+ struct dfa *d;
+{
+ int i, j;
+ int *visited;
+ position p, old;
+
+ MALLOC(visited, int, d->tindex);
+ for (i = 0; i < d->tindex; ++i)
+ visited[i] = 0;
+
+ for (i = 0; i < s->nelem; ++i)
+ if (d->tokens[s->elems[i].index] >= NOTCHAR
+ && d->tokens[s->elems[i].index] != BACKREF
+ && d->tokens[s->elems[i].index] < CSET)
+ {
+ old = s->elems[i];
+ p.constraint = old.constraint;
+ delete(s->elems[i], s);
+ if (visited[old.index])
+ {
+ --i;
+ continue;
+ }
+ visited[old.index] = 1;
+ switch (d->tokens[old.index])
+ {
+ case BEGLINE:
+ p.constraint &= BEGLINE_CONSTRAINT;
+ break;
+ case ENDLINE:
+ p.constraint &= ENDLINE_CONSTRAINT;
+ break;
+ case BEGWORD:
+ p.constraint &= BEGWORD_CONSTRAINT;
+ break;
+ case ENDWORD:
+ p.constraint &= ENDWORD_CONSTRAINT;
+ break;
+ case LIMWORD:
+ p.constraint &= LIMWORD_CONSTRAINT;
+ break;
+ case NOTLIMWORD:
+ p.constraint &= NOTLIMWORD_CONSTRAINT;
+ break;
+ default:
+ break;
+ }
+ for (j = 0; j < d->follows[old.index].nelem; ++j)
+ {
+ p.index = d->follows[old.index].elems[j].index;
+ insert(p, s);
+ }
+ /* Force rescan to start at the beginning. */
+ i = -1;
+ }
+
+ free(visited);
+}
+
+/* Perform bottom-up analysis on the parse tree, computing various functions.
+ Note that at this point, we're pretending constructs like \< are real
+ characters rather than constraints on what can follow them.
+
+ Nullable: A node is nullable if it is at the root of a regexp that can
+ match the empty string.
+ * EMPTY leaves are nullable.
+ * No other leaf is nullable.
+ * A QMARK or STAR node is nullable.
+ * A PLUS node is nullable if its argument is nullable.
+ * A CAT node is nullable if both its arguments are nullable.
+ * An OR node is nullable if either argument is nullable.
+
+ Firstpos: The firstpos of a node is the set of positions (nonempty leaves)
+ that could correspond to the first character of a string matching the
+ regexp rooted at the given node.
+ * EMPTY leaves have empty firstpos.
+ * The firstpos of a nonempty leaf is that leaf itself.
+ * The firstpos of a QMARK, STAR, or PLUS node is the firstpos of its
+ argument.
+ * The firstpos of a CAT node is the firstpos of the left argument, union
+ the firstpos of the right if the left argument is nullable.
+ * The firstpos of an OR node is the union of firstpos of each argument.
+
+ Lastpos: The lastpos of a node is the set of positions that could
+ correspond to the last character of a string matching the regexp at
+ the given node.
+ * EMPTY leaves have empty lastpos.
+ * The lastpos of a nonempty leaf is that leaf itself.
+ * The lastpos of a QMARK, STAR, or PLUS node is the lastpos of its
+ argument.
+ * The lastpos of a CAT node is the lastpos of its right argument, union
+ the lastpos of the left if the right argument is nullable.
+ * The lastpos of an OR node is the union of the lastpos of each argument.
+
+ Follow: The follow of a position is the set of positions that could
+ correspond to the character following a character matching the node in
+ a string matching the regexp. At this point we consider special symbols
+ that match the empty string in some context to be just normal characters.
+ Later, if we find that a special symbol is in a follow set, we will
+ replace it with the elements of its follow, labeled with an appropriate
+ constraint.
+ * Every node in the firstpos of the argument of a STAR or PLUS node is in
+ the follow of every node in the lastpos.
+ * Every node in the firstpos of the second argument of a CAT node is in
+ the follow of every node in the lastpos of the first argument.
+
+ Because of the postfix representation of the parse tree, the depth-first
+ analysis is conveniently done by a linear scan with the aid of a stack.
+ Sets are stored as arrays of the elements, obeying a stack-like allocation
+ scheme; the number of elements in each set deeper in the stack can be
+ used to determine the address of a particular set's array. */
+void
+dfaanalyze(d, searchflag)
+ struct dfa *d;
+ int searchflag;
+{
+ int *nullable; /* Nullable stack. */
+ int *nfirstpos; /* Element count stack for firstpos sets. */
+ position *firstpos; /* Array where firstpos elements are stored. */
+ int *nlastpos; /* Element count stack for lastpos sets. */
+ position *lastpos; /* Array where lastpos elements are stored. */
+ int *nalloc; /* Sizes of arrays allocated to follow sets. */
+ position_set tmp; /* Temporary set for merging sets. */
+ position_set merged; /* Result of merging sets. */
+ int wants_newline; /* True if some position wants newline info. */
+ int *o_nullable;
+ int *o_nfirst, *o_nlast;
+ position *o_firstpos, *o_lastpos;
+ int i, j;
+ position *pos;
+
+#ifdef DEBUG
+ fprintf(stderr, "dfaanalyze:\n");
+ for (i = 0; i < d->tindex; ++i)
+ {
+ fprintf(stderr, " %d:", i);
+ prtok(d->tokens[i]);
+ }
+ putc('\n', stderr);
+#endif
+
+ d->searchflag = searchflag;
+
+ MALLOC(nullable, int, d->depth);
+ o_nullable = nullable;
+ MALLOC(nfirstpos, int, d->depth);
+ o_nfirst = nfirstpos;
+ MALLOC(firstpos, position, d->nleaves);
+ o_firstpos = firstpos, firstpos += d->nleaves;
+ MALLOC(nlastpos, int, d->depth);
+ o_nlast = nlastpos;
+ MALLOC(lastpos, position, d->nleaves);
+ o_lastpos = lastpos, lastpos += d->nleaves;
+ MALLOC(nalloc, int, d->tindex);
+ for (i = 0; i < d->tindex; ++i)
+ nalloc[i] = 0;
+ MALLOC(merged.elems, position, d->nleaves);
+
+ CALLOC(d->follows, position_set, d->tindex);
+
+ for (i = 0; i < d->tindex; ++i)
+#ifdef DEBUG
+ { /* Nonsyntactic #ifdef goo... */
+#endif
+ switch (d->tokens[i])
+ {
+ case EMPTY:
+ /* The empty set is nullable. */
+ *nullable++ = 1;
+
+ /* The firstpos and lastpos of the empty leaf are both empty. */
+ *nfirstpos++ = *nlastpos++ = 0;
+ break;
+
+ case STAR:
+ case PLUS:
+ /* Every element in the firstpos of the argument is in the follow
+ of every element in the lastpos. */
+ tmp.nelem = nfirstpos[-1];
+ tmp.elems = firstpos;
+ pos = lastpos;
+ for (j = 0; j < nlastpos[-1]; ++j)
+ {
+ merge(&tmp, &d->follows[pos[j].index], &merged);
+ REALLOC_IF_NECESSARY(d->follows[pos[j].index].elems, position,
+ nalloc[pos[j].index], merged.nelem - 1);
+ copy(&merged, &d->follows[pos[j].index]);
+ }
+
+ case QMARK:
+ /* A QMARK or STAR node is automatically nullable. */
+ if (d->tokens[i] != PLUS)
+ nullable[-1] = 1;
+ break;
+
+ case CAT:
+ /* Every element in the firstpos of the second argument is in the
+ follow of every element in the lastpos of the first argument. */
+ tmp.nelem = nfirstpos[-1];
+ tmp.elems = firstpos;
+ pos = lastpos + nlastpos[-1];
+ for (j = 0; j < nlastpos[-2]; ++j)
+ {
+ merge(&tmp, &d->follows[pos[j].index], &merged);
+ REALLOC_IF_NECESSARY(d->follows[pos[j].index].elems, position,
+ nalloc[pos[j].index], merged.nelem - 1);
+ copy(&merged, &d->follows[pos[j].index]);
+ }
+
+ /* The firstpos of a CAT node is the firstpos of the first argument,
+ union that of the second argument if the first is nullable. */
+ if (nullable[-2])
+ nfirstpos[-2] += nfirstpos[-1];
+ else
+ firstpos += nfirstpos[-1];
+ --nfirstpos;
+
+ /* The lastpos of a CAT node is the lastpos of the second argument,
+ union that of the first argument if the second is nullable. */
+ if (nullable[-1])
+ nlastpos[-2] += nlastpos[-1];
+ else
+ {
+ pos = lastpos + nlastpos[-2];
+ for (j = nlastpos[-1] - 1; j >= 0; --j)
+ pos[j] = lastpos[j];
+ lastpos += nlastpos[-2];
+ nlastpos[-2] = nlastpos[-1];
+ }
+ --nlastpos;
+
+ /* A CAT node is nullable if both arguments are nullable. */
+ nullable[-2] = nullable[-1] && nullable[-2];
+ --nullable;
+ break;
+
+ case OR:
+ case ORTOP:
+ /* The firstpos is the union of the firstpos of each argument. */
+ nfirstpos[-2] += nfirstpos[-1];
+ --nfirstpos;
+
+ /* The lastpos is the union of the lastpos of each argument. */
+ nlastpos[-2] += nlastpos[-1];
+ --nlastpos;
+
+ /* An OR node is nullable if either argument is nullable. */
+ nullable[-2] = nullable[-1] || nullable[-2];
+ --nullable;
+ break;
+
+ default:
+ /* Anything else is a nonempty position. (Note that special
+ constructs like \< are treated as nonempty strings here;
+ an "epsilon closure" effectively makes them nullable later.
+ Backreferences have to get a real position so we can detect
+ transitions on them later. But they are nullable. */
+ *nullable++ = d->tokens[i] == BACKREF;
+
+ /* This position is in its own firstpos and lastpos. */
+ *nfirstpos++ = *nlastpos++ = 1;
+ --firstpos, --lastpos;
+ firstpos->index = lastpos->index = i;
+ firstpos->constraint = lastpos->constraint = NO_CONSTRAINT;
+
+ /* Allocate the follow set for this position. */
+ nalloc[i] = 1;
+ MALLOC(d->follows[i].elems, position, nalloc[i]);
+ break;
+ }
+#ifdef DEBUG
+ /* ... balance the above nonsyntactic #ifdef goo... */
+ fprintf(stderr, "node %d:", i);
+ prtok(d->tokens[i]);
+ putc('\n', stderr);
+ fprintf(stderr, nullable[-1] ? " nullable: yes\n" : " nullable: no\n");
+ fprintf(stderr, " firstpos:");
+ for (j = nfirstpos[-1] - 1; j >= 0; --j)
+ {
+ fprintf(stderr, " %d:", firstpos[j].index);
+ prtok(d->tokens[firstpos[j].index]);
+ }
+ fprintf(stderr, "\n lastpos:");
+ for (j = nlastpos[-1] - 1; j >= 0; --j)
+ {
+ fprintf(stderr, " %d:", lastpos[j].index);
+ prtok(d->tokens[lastpos[j].index]);
+ }
+ putc('\n', stderr);
+ }
+#endif
+
+ /* For each follow set that is the follow set of a real position, replace
+ it with its epsilon closure. */
+ for (i = 0; i < d->tindex; ++i)
+ if (d->tokens[i] < NOTCHAR || d->tokens[i] == BACKREF
+ || d->tokens[i] >= CSET)
+ {
+#ifdef DEBUG
+ fprintf(stderr, "follows(%d:", i);
+ prtok(d->tokens[i]);
+ fprintf(stderr, "):");
+ for (j = d->follows[i].nelem - 1; j >= 0; --j)
+ {
+ fprintf(stderr, " %d:", d->follows[i].elems[j].index);
+ prtok(d->tokens[d->follows[i].elems[j].index]);
+ }
+ putc('\n', stderr);
+#endif
+ copy(&d->follows[i], &merged);
+ epsclosure(&merged, d);
+ if (d->follows[i].nelem < merged.nelem)
+ REALLOC(d->follows[i].elems, position, merged.nelem);
+ copy(&merged, &d->follows[i]);
+ }
+
+ /* Get the epsilon closure of the firstpos of the regexp. The result will
+ be the set of positions of state 0. */
+ merged.nelem = 0;
+ for (i = 0; i < nfirstpos[-1]; ++i)
+ insert(firstpos[i], &merged);
+ epsclosure(&merged, d);
+
+ /* Check if any of the positions of state 0 will want newline context. */
+ wants_newline = 0;
+ for (i = 0; i < merged.nelem; ++i)
+ if (PREV_NEWLINE_DEPENDENT(merged.elems[i].constraint))
+ wants_newline = 1;
+
+ /* Build the initial state. */
+ d->salloc = 1;
+ d->sindex = 0;
+ MALLOC(d->states, dfa_state, d->salloc);
+ state_index(d, &merged, wants_newline, 0);
+
+ free(o_nullable);
+ free(o_nfirst);
+ free(o_firstpos);
+ free(o_nlast);
+ free(o_lastpos);
+ free(nalloc);
+ free(merged.elems);
+}
+
+/* Find, for each character, the transition out of state s of d, and store
+ it in the appropriate slot of trans.
+
+ We divide the positions of s into groups (positions can appear in more
+ than one group). Each group is labeled with a set of characters that
+ every position in the group matches (taking into account, if necessary,
+ preceding context information of s). For each group, find the union
+ of the its elements' follows. This set is the set of positions of the
+ new state. For each character in the group's label, set the transition
+ on this character to be to a state corresponding to the set's positions,
+ and its associated backward context information, if necessary.
+
+ If we are building a searching matcher, we include the positions of state
+ 0 in every state.
+
+ The collection of groups is constructed by building an equivalence-class
+ partition of the positions of s.
+
+ For each position, find the set of characters C that it matches. Eliminate
+ any characters from C that fail on grounds of backward context.
+
+ Search through the groups, looking for a group whose label L has nonempty
+ intersection with C. If L - C is nonempty, create a new group labeled
+ L - C and having the same positions as the current group, and set L to
+ the intersection of L and C. Insert the position in this group, set
+ C = C - L, and resume scanning.
+
+ If after comparing with every group there are characters remaining in C,
+ create a new group labeled with the characters of C and insert this
+ position in that group. */
+void
+dfastate(s, d, trans)
+ int s;
+ struct dfa *d;
+ int trans[];
+{
+ position_set grps[NOTCHAR]; /* As many as will ever be needed. */
+ charclass labels[NOTCHAR]; /* Labels corresponding to the groups. */
+ int ngrps = 0; /* Number of groups actually used. */
+ position pos; /* Current position being considered. */
+ charclass matches; /* Set of matching characters. */
+ int matchesf; /* True if matches is nonempty. */
+ charclass intersect; /* Intersection with some label set. */
+ int intersectf; /* True if intersect is nonempty. */
+ charclass leftovers; /* Stuff in the label that didn't match. */
+ int leftoversf; /* True if leftovers is nonempty. */
+ static charclass letters; /* Set of characters considered letters. */
+ static charclass newline; /* Set of characters that aren't newline. */
+ position_set follows; /* Union of the follows of some group. */
+ position_set tmp; /* Temporary space for merging sets. */
+ int state; /* New state. */
+ int wants_newline; /* New state wants to know newline context. */
+ int state_newline; /* New state on a newline transition. */
+ int wants_letter; /* New state wants to know letter context. */
+ int state_letter; /* New state on a letter transition. */
+ static initialized; /* Flag for static initialization. */
+ int i, j, k;
+
+ /* Initialize the set of letters, if necessary. */
+ if (! initialized)
+ {
+ initialized = 1;
+ for (i = 0; i < NOTCHAR; ++i)
+ if (ISALNUM(i))
+ setbit(i, letters);
+ setbit('\n', newline);
+ }
+
+ zeroset(matches);
+
+ for (i = 0; i < d->states[s].elems.nelem; ++i)
+ {
+ pos = d->states[s].elems.elems[i];
+ if (d->tokens[pos.index] >= 0 && d->tokens[pos.index] < NOTCHAR)
+ setbit(d->tokens[pos.index], matches);
+ else if (d->tokens[pos.index] >= CSET)
+ copyset(d->charclasses[d->tokens[pos.index] - CSET], matches);
+ else
+ continue;
+
+ /* Some characters may need to be eliminated from matches because
+ they fail in the current context. */
+ if (pos.constraint != 0xFF)
+ {
+ if (! MATCHES_NEWLINE_CONTEXT(pos.constraint,
+ d->states[s].newline, 1))
+ clrbit('\n', matches);
+ if (! MATCHES_NEWLINE_CONTEXT(pos.constraint,
+ d->states[s].newline, 0))
+ for (j = 0; j < CHARCLASS_INTS; ++j)
+ matches[j] &= newline[j];
+ if (! MATCHES_LETTER_CONTEXT(pos.constraint,
+ d->states[s].letter, 1))
+ for (j = 0; j < CHARCLASS_INTS; ++j)
+ matches[j] &= ~letters[j];
+ if (! MATCHES_LETTER_CONTEXT(pos.constraint,
+ d->states[s].letter, 0))
+ for (j = 0; j < CHARCLASS_INTS; ++j)
+ matches[j] &= letters[j];
+
+ /* If there are no characters left, there's no point in going on. */
+ for (j = 0; j < CHARCLASS_INTS && !matches[j]; ++j)
+ ;
+ if (j == CHARCLASS_INTS)
+ continue;
+ }
+
+ for (j = 0; j < ngrps; ++j)
+ {
+ /* If matches contains a single character only, and the current
+ group's label doesn't contain that character, go on to the
+ next group. */
+ if (d->tokens[pos.index] >= 0 && d->tokens[pos.index] < NOTCHAR
+ && !tstbit(d->tokens[pos.index], labels[j]))
+ continue;
+
+ /* Check if this group's label has a nonempty intersection with
+ matches. */
+ intersectf = 0;
+ for (k = 0; k < CHARCLASS_INTS; ++k)
+ (intersect[k] = matches[k] & labels[j][k]) ? intersectf = 1 : 0;
+ if (! intersectf)
+ continue;
+
+ /* It does; now find the set differences both ways. */
+ leftoversf = matchesf = 0;
+ for (k = 0; k < CHARCLASS_INTS; ++k)
+ {
+ /* Even an optimizing compiler can't know this for sure. */
+ int match = matches[k], label = labels[j][k];
+
+ (leftovers[k] = ~match & label) ? leftoversf = 1 : 0;
+ (matches[k] = match & ~label) ? matchesf = 1 : 0;
+ }
+
+ /* If there were leftovers, create a new group labeled with them. */
+ if (leftoversf)
+ {
+ copyset(leftovers, labels[ngrps]);
+ copyset(intersect, labels[j]);
+ MALLOC(grps[ngrps].elems, position, d->nleaves);
+ copy(&grps[j], &grps[ngrps]);
+ ++ngrps;
+ }
+
+ /* Put the position in the current group. Note that there is no
+ reason to call insert() here. */
+ grps[j].elems[grps[j].nelem++] = pos;
+
+ /* If every character matching the current position has been
+ accounted for, we're done. */
+ if (! matchesf)
+ break;
+ }
+
+ /* If we've passed the last group, and there are still characters
+ unaccounted for, then we'll have to create a new group. */
+ if (j == ngrps)
+ {
+ copyset(matches, labels[ngrps]);
+ zeroset(matches);
+ MALLOC(grps[ngrps].elems, position, d->nleaves);
+ grps[ngrps].nelem = 1;
+ grps[ngrps].elems[0] = pos;
+ ++ngrps;
+ }
+ }
+
+ MALLOC(follows.elems, position, d->nleaves);
+ MALLOC(tmp.elems, position, d->nleaves);
+
+ /* If we are a searching matcher, the default transition is to a state
+ containing the positions of state 0, otherwise the default transition
+ is to fail miserably. */
+ if (d->searchflag)
+ {
+ wants_newline = 0;
+ wants_letter = 0;
+ for (i = 0; i < d->states[0].elems.nelem; ++i)
+ {
+ if (PREV_NEWLINE_DEPENDENT(d->states[0].elems.elems[i].constraint))
+ wants_newline = 1;
+ if (PREV_LETTER_DEPENDENT(d->states[0].elems.elems[i].constraint))
+ wants_letter = 1;
+ }
+ copy(&d->states[0].elems, &follows);
+ state = state_index(d, &follows, 0, 0);
+ if (wants_newline)
+ state_newline = state_index(d, &follows, 1, 0);
+ else
+ state_newline = state;
+ if (wants_letter)
+ state_letter = state_index(d, &follows, 0, 1);
+ else
+ state_letter = state;
+ for (i = 0; i < NOTCHAR; ++i)
+ if (i == '\n')
+ trans[i] = state_newline;
+ else if (ISALNUM(i))
+ trans[i] = state_letter;
+ else
+ trans[i] = state;
+ }
+ else
+ for (i = 0; i < NOTCHAR; ++i)
+ trans[i] = -1;
+
+ for (i = 0; i < ngrps; ++i)
+ {
+ follows.nelem = 0;
+
+ /* Find the union of the follows of the positions of the group.
+ This is a hideously inefficient loop. Fix it someday. */
+ for (j = 0; j < grps[i].nelem; ++j)
+ for (k = 0; k < d->follows[grps[i].elems[j].index].nelem; ++k)
+ insert(d->follows[grps[i].elems[j].index].elems[k], &follows);
+
+ /* If we are building a searching matcher, throw in the positions
+ of state 0 as well. */
+ if (d->searchflag)
+ for (j = 0; j < d->states[0].elems.nelem; ++j)
+ insert(d->states[0].elems.elems[j], &follows);
+
+ /* Find out if the new state will want any context information. */
+ wants_newline = 0;
+ if (tstbit('\n', labels[i]))
+ for (j = 0; j < follows.nelem; ++j)
+ if (PREV_NEWLINE_DEPENDENT(follows.elems[j].constraint))
+ wants_newline = 1;
+
+ wants_letter = 0;
+ for (j = 0; j < CHARCLASS_INTS; ++j)
+ if (labels[i][j] & letters[j])
+ break;
+ if (j < CHARCLASS_INTS)
+ for (j = 0; j < follows.nelem; ++j)
+ if (PREV_LETTER_DEPENDENT(follows.elems[j].constraint))
+ wants_letter = 1;
+
+ /* Find the state(s) corresponding to the union of the follows. */
+ state = state_index(d, &follows, 0, 0);
+ if (wants_newline)
+ state_newline = state_index(d, &follows, 1, 0);
+ else
+ state_newline = state;
+ if (wants_letter)
+ state_letter = state_index(d, &follows, 0, 1);
+ else
+ state_letter = state;
+
+ /* Set the transitions for each character in the current label. */
+ for (j = 0; j < CHARCLASS_INTS; ++j)
+ for (k = 0; k < INTBITS; ++k)
+ if (labels[i][j] & 1 << k)
+ {
+ int c = j * INTBITS + k;
+
+ if (c == '\n')
+ trans[c] = state_newline;
+ else if (ISALNUM(c))
+ trans[c] = state_letter;
+ else if (c < NOTCHAR)
+ trans[c] = state;
+ }
+ }
+
+ for (i = 0; i < ngrps; ++i)
+ free(grps[i].elems);
+ free(follows.elems);
+ free(tmp.elems);
+}
+
+/* Some routines for manipulating a compiled dfa's transition tables.
+ Each state may or may not have a transition table; if it does, and it
+ is a non-accepting state, then d->trans[state] points to its table.
+ If it is an accepting state then d->fails[state] points to its table.
+ If it has no table at all, then d->trans[state] is NULL.
+ TODO: Improve this comment, get rid of the unnecessary redundancy. */
+
+static void
+build_state(s, d)
+ int s;
+ struct dfa *d;
+{
+ int *trans; /* The new transition table. */
+ int i;
+
+ /* Set an upper limit on the number of transition tables that will ever
+ exist at once. 1024 is arbitrary. The idea is that the frequently
+ used transition tables will be quickly rebuilt, whereas the ones that
+ were only needed once or twice will be cleared away. */
+ if (d->trcount >= 1024)
+ {
+ for (i = 0; i < d->tralloc; ++i)
+ if (d->trans[i])
+ {
+ free((ptr_t) d->trans[i]);
+ d->trans[i] = NULL;
+ }
+ else if (d->fails[i])
+ {
+ free((ptr_t) d->fails[i]);
+ d->fails[i] = NULL;
+ }
+ d->trcount = 0;
+ }
+
+ ++d->trcount;
+
+ /* Set up the success bits for this state. */
+ d->success[s] = 0;
+ if (ACCEPTS_IN_CONTEXT(d->states[s].newline, 1, d->states[s].letter, 0,
+ s, *d))
+ d->success[s] |= 4;
+ if (ACCEPTS_IN_CONTEXT(d->states[s].newline, 0, d->states[s].letter, 1,
+ s, *d))
+ d->success[s] |= 2;
+ if (ACCEPTS_IN_CONTEXT(d->states[s].newline, 0, d->states[s].letter, 0,
+ s, *d))
+ d->success[s] |= 1;
+
+ MALLOC(trans, int, NOTCHAR);
+ dfastate(s, d, trans);
+
+ /* Now go through the new transition table, and make sure that the trans
+ and fail arrays are allocated large enough to hold a pointer for the
+ largest state mentioned in the table. */
+ for (i = 0; i < NOTCHAR; ++i)
+ if (trans[i] >= d->tralloc)
+ {
+ int oldalloc = d->tralloc;
+
+ while (trans[i] >= d->tralloc)
+ d->tralloc *= 2;
+ REALLOC(d->realtrans, int *, d->tralloc + 1);
+ d->trans = d->realtrans + 1;
+ REALLOC(d->fails, int *, d->tralloc);
+ REALLOC(d->success, int, d->tralloc);
+ REALLOC(d->newlines, int, d->tralloc);
+ while (oldalloc < d->tralloc)
+ {
+ d->trans[oldalloc] = NULL;
+ d->fails[oldalloc++] = NULL;
+ }
+ }
+
+ /* Keep the newline transition in a special place so we can use it as
+ a sentinel. */
+ d->newlines[s] = trans['\n'];
+ trans['\n'] = -1;
+
+ if (ACCEPTING(s, *d))
+ d->fails[s] = trans;
+ else
+ d->trans[s] = trans;
+}
+
+static void
+build_state_zero(d)
+ struct dfa *d;
+{
+ d->tralloc = 1;
+ d->trcount = 0;
+ CALLOC(d->realtrans, int *, d->tralloc + 1);
+ d->trans = d->realtrans + 1;
+ CALLOC(d->fails, int *, d->tralloc);
+ MALLOC(d->success, int, d->tralloc);
+ MALLOC(d->newlines, int, d->tralloc);
+ build_state(0, d);
+}
+
+/* Search through a buffer looking for a match to the given struct dfa.
+ Find the first occurrence of a string matching the regexp in the buffer,
+ and the shortest possible version thereof. Return a pointer to the first
+ character after the match, or NULL if none is found. Begin points to
+ the beginning of the buffer, and end points to the first character after
+ its end. We store a newline in *end to act as a sentinel, so end had
+ better point somewhere valid. Newline is a flag indicating whether to
+ allow newlines to be in the matching string. If count is non-
+ NULL it points to a place we're supposed to increment every time we
+ see a newline. Finally, if backref is non-NULL it points to a place
+ where we're supposed to store a 1 if backreferencing happened and the
+ match needs to be verified by a backtracking matcher. Otherwise
+ we store a 0 in *backref. */
+char *
+dfaexec(d, begin, end, newline, count, backref)
+ struct dfa *d;
+ char *begin;
+ char *end;
+ int newline;
+ int *count;
+ int *backref;
+{
+ register s, s1, tmp; /* Current state. */
+ register unsigned char *p; /* Current input character. */
+ register **trans, *t; /* Copy of d->trans so it can be optimized
+ into a register. */
+ static sbit[NOTCHAR]; /* Table for anding with d->success. */
+ static sbit_init;
+
+ if (! sbit_init)
+ {
+ int i;
+
+ sbit_init = 1;
+ for (i = 0; i < NOTCHAR; ++i)
+ if (i == '\n')
+ sbit[i] = 4;
+ else if (ISALNUM(i))
+ sbit[i] = 2;
+ else
+ sbit[i] = 1;
+ }
+
+ if (! d->tralloc)
+ build_state_zero(d);
+
+ s = s1 = 0;
+ p = (unsigned char *) begin;
+ trans = d->trans;
+ *end = '\n';
+
+ for (;;)
+ {
+ /* The dreaded inner loop. */
+ if ((t = trans[s]) != 0)
+ do
+ {
+ s1 = t[*p++];
+ if (! (t = trans[s1]))
+ goto last_was_s;
+ s = t[*p++];
+ }
+ while ((t = trans[s]) != 0);
+ goto last_was_s1;
+ last_was_s:
+ tmp = s, s = s1, s1 = tmp;
+ last_was_s1:
+
+ if (s >= 0 && p <= (unsigned char *) end && d->fails[s])
+ {
+ if (d->success[s] & sbit[*p])
+ {
+ if (backref)
+ if (d->states[s].backref)
+ *backref = 1;
+ else
+ *backref = 0;
+ return (char *) p;
+ }
+
+ s1 = s;
+ s = d->fails[s][*p++];
+ continue;
+ }
+
+ /* If the previous character was a newline, count it. */
+ if (count && (char *) p <= end && p[-1] == '\n')
+ ++*count;
+
+ /* Check if we've run off the end of the buffer. */
+ if ((char *) p > end)
+ return NULL;
+
+ if (s >= 0)
+ {
+ build_state(s, d);
+ trans = d->trans;
+ continue;
+ }
+
+ if (p[-1] == '\n' && newline)
+ {
+ s = d->newlines[s1];
+ continue;
+ }
+
+ s = 0;
+ }
+}
+
+/* Initialize the components of a dfa that the other routines don't
+ initialize for themselves. */
+void
+dfainit(d)
+ struct dfa *d;
+{
+ d->calloc = 1;
+ MALLOC(d->charclasses, charclass, d->calloc);
+ d->cindex = 0;
+
+ d->talloc = 1;
+ MALLOC(d->tokens, token, d->talloc);
+ d->tindex = d->depth = d->nleaves = d->nregexps = 0;
+
+ d->searchflag = 0;
+ d->tralloc = 0;
+
+ d->musts = 0;
+}
+
+/* Parse and analyze a single string of the given length. */
+void
+dfacomp(s, len, d, searchflag)
+ char *s;
+ size_t len;
+ struct dfa *d;
+ int searchflag;
+{
+ if (case_fold) /* dummy folding in service of dfamust() */
+ {
+ char *copy;
+ int i;
+
+ copy = malloc(len);
+ if (!copy)
+ dfaerror("out of memory");
+
+ /* This is a kludge. */
+ case_fold = 0;
+ for (i = 0; i < len; ++i)
+ if (ISUPPER(s[i]))
+ copy[i] = tolower(s[i]);
+ else
+ copy[i] = s[i];
+
+ dfainit(d);
+ dfaparse(copy, len, d);
+ free(copy);
+ dfamust(d);
+ d->cindex = d->tindex = d->depth = d->nleaves = d->nregexps = 0;
+ case_fold = 1;
+ dfaparse(s, len, d);
+ dfaanalyze(d, searchflag);
+ }
+ else
+ {
+ dfainit(d);
+ dfaparse(s, len, d);
+ dfamust(d);
+ dfaanalyze(d, searchflag);
+ }
+}
+
+/* Free the storage held by the components of a dfa. */
+void
+dfafree(d)
+ struct dfa *d;
+{
+ int i;
+ struct dfamust *dm, *ndm;
+
+ free((ptr_t) d->charclasses);
+ free((ptr_t) d->tokens);
+ for (i = 0; i < d->sindex; ++i)
+ free((ptr_t) d->states[i].elems.elems);
+ free((ptr_t) d->states);
+ for (i = 0; i < d->tindex; ++i)
+ if (d->follows[i].elems)
+ free((ptr_t) d->follows[i].elems);
+ free((ptr_t) d->follows);
+ for (i = 0; i < d->tralloc; ++i)
+ if (d->trans[i])
+ free((ptr_t) d->trans[i]);
+ else if (d->fails[i])
+ free((ptr_t) d->fails[i]);
+ free((ptr_t) d->realtrans);
+ free((ptr_t) d->fails);
+ free((ptr_t) d->newlines);
+ for (dm = d->musts; dm; dm = ndm)
+ {
+ ndm = dm->next;
+ free(dm->must);
+ free((ptr_t) dm);
+ }
+}
+
+/* Having found the postfix representation of the regular expression,
+ try to find a long sequence of characters that must appear in any line
+ containing the r.e.
+ Finding a "longest" sequence is beyond the scope here;
+ we take an easy way out and hope for the best.
+ (Take "(ab|a)b"--please.)
+
+ We do a bottom-up calculation of sequences of characters that must appear
+ in matches of r.e.'s represented by trees rooted at the nodes of the postfix
+ representation:
+ sequences that must appear at the left of the match ("left")
+ sequences that must appear at the right of the match ("right")
+ lists of sequences that must appear somewhere in the match ("in")
+ sequences that must constitute the match ("is")
+
+ When we get to the root of the tree, we use one of the longest of its
+ calculated "in" sequences as our answer. The sequence we find is returned in
+ d->must (where "d" is the single argument passed to "dfamust");
+ the length of the sequence is returned in d->mustn.
+
+ The sequences calculated for the various types of node (in pseudo ANSI c)
+ are shown below. "p" is the operand of unary operators (and the left-hand
+ operand of binary operators); "q" is the right-hand operand of binary
+ operators.
+
+ "ZERO" means "a zero-length sequence" below.
+
+ Type left right is in
+ ---- ---- ----- -- --
+ char c # c # c # c # c
+
+ CSET ZERO ZERO ZERO ZERO
+
+ STAR ZERO ZERO ZERO ZERO
+
+ QMARK ZERO ZERO ZERO ZERO
+
+ PLUS p->left p->right ZERO p->in
+
+ CAT (p->is==ZERO)? (q->is==ZERO)? (p->is!=ZERO && p->in plus
+ p->left : q->right : q->is!=ZERO) ? q->in plus
+ p->is##q->left p->right##q->is p->is##q->is : p->right##q->left
+ ZERO
+
+ OR longest common longest common (do p->is and substrings common to
+ leading trailing q->is have same p->in and q->in
+ (sub)sequence (sub)sequence length and
+ of p->left of p->right content) ?
+ and q->left and q->right p->is : NULL
+
+ If there's anything else we recognize in the tree, all four sequences get set
+ to zero-length sequences. If there's something we don't recognize in the tree,
+ we just return a zero-length sequence.
+
+ Break ties in favor of infrequent letters (choosing 'zzz' in preference to
+ 'aaa')?
+
+ And. . .is it here or someplace that we might ponder "optimizations" such as
+ egrep 'psi|epsilon' -> egrep 'psi'
+ egrep 'pepsi|epsilon' -> egrep 'epsi'
+ (Yes, we now find "epsi" as a "string
+ that must occur", but we might also
+ simplify the *entire* r.e. being sought)
+ grep '[c]' -> grep 'c'
+ grep '(ab|a)b' -> grep 'ab'
+ grep 'ab*' -> grep 'a'
+ grep 'a*b' -> grep 'b'
+
+ There are several issues:
+
+ Is optimization easy (enough)?
+
+ Does optimization actually accomplish anything,
+ or is the automaton you get from "psi|epsilon" (for example)
+ the same as the one you get from "psi" (for example)?
+
+ Are optimizable r.e.'s likely to be used in real-life situations
+ (something like 'ab*' is probably unlikely; something like is
+ 'psi|epsilon' is likelier)? */
+
+static char *
+icatalloc(old, new)
+ char *old;
+ char *new;
+{
+ char *result;
+ int oldsize, newsize;
+
+ newsize = (new == NULL) ? 0 : strlen(new);
+ if (old == NULL)
+ oldsize = 0;
+ else if (newsize == 0)
+ return old;
+ else oldsize = strlen(old);
+ if (old == NULL)
+ result = (char *) malloc(newsize + 1);
+ else
+ result = (char *) realloc((void *) old, oldsize + newsize + 1);
+ if (result != NULL && new != NULL)
+ (void) strcpy(result + oldsize, new);
+ return result;
+}
+
+static char *
+icpyalloc(string)
+ char *string;
+{
+ return icatalloc((char *) NULL, string);
+}
+
+static char *
+istrstr(lookin, lookfor)
+ char *lookin;
+ char *lookfor;
+{
+ char *cp;
+ int len;
+
+ len = strlen(lookfor);
+ for (cp = lookin; *cp != '\0'; ++cp)
+ if (strncmp(cp, lookfor, len) == 0)
+ return cp;
+ return NULL;
+}
+
+static void
+ifree(cp)
+ char *cp;
+{
+ if (cp != NULL)
+ free(cp);
+}
+
+static void
+freelist(cpp)
+ char **cpp;
+{
+ int i;
+
+ if (cpp == NULL)
+ return;
+ for (i = 0; cpp[i] != NULL; ++i)
+ {
+ free(cpp[i]);
+ cpp[i] = NULL;
+ }
+}
+
+static char **
+enlist(cpp, new, len)
+ char **cpp;
+ char *new;
+ int len;
+{
+ int i, j;
+
+ if (cpp == NULL)
+ return NULL;
+ if ((new = icpyalloc(new)) == NULL)
+ {
+ freelist(cpp);
+ return NULL;
+ }
+ new[len] = '\0';
+ /* Is there already something in the list that's new (or longer)? */
+ for (i = 0; cpp[i] != NULL; ++i)
+ if (istrstr(cpp[i], new) != NULL)
+ {
+ free(new);
+ return cpp;
+ }
+ /* Eliminate any obsoleted strings. */
+ j = 0;
+ while (cpp[j] != NULL)
+ if (istrstr(new, cpp[j]) == NULL)
+ ++j;
+ else
+ {
+ free(cpp[j]);
+ if (--i == j)
+ break;
+ cpp[j] = cpp[i];
+ cpp[i] = NULL;
+ }
+ /* Add the new string. */
+ cpp = (char **) realloc((char *) cpp, (i + 2) * sizeof *cpp);
+ if (cpp == NULL)
+ return NULL;
+ cpp[i] = new;
+ cpp[i + 1] = NULL;
+ return cpp;
+}
+
+/* Given pointers to two strings, return a pointer to an allocated
+ list of their distinct common substrings. Return NULL if something
+ seems wild. */
+static char **
+comsubs(left, right)
+ char *left;
+ char *right;
+{
+ char **cpp;
+ char *lcp;
+ char *rcp;
+ int i, len;
+
+ if (left == NULL || right == NULL)
+ return NULL;
+ cpp = (char **) malloc(sizeof *cpp);
+ if (cpp == NULL)
+ return NULL;
+ cpp[0] = NULL;
+ for (lcp = left; *lcp != '\0'; ++lcp)
+ {
+ len = 0;
+ rcp = index(right, *lcp);
+ while (rcp != NULL)
+ {
+ for (i = 1; lcp[i] != '\0' && lcp[i] == rcp[i]; ++i)
+ ;
+ if (i > len)
+ len = i;
+ rcp = index(rcp + 1, *lcp);
+ }
+ if (len == 0)
+ continue;
+ if ((cpp = enlist(cpp, lcp, len)) == NULL)
+ break;
+ }
+ return cpp;
+}
+
+static char **
+addlists(old, new)
+char **old;
+char **new;
+{
+ int i;
+
+ if (old == NULL || new == NULL)
+ return NULL;
+ for (i = 0; new[i] != NULL; ++i)
+ {
+ old = enlist(old, new[i], strlen(new[i]));
+ if (old == NULL)
+ break;
+ }
+ return old;
+}
+
+/* Given two lists of substrings, return a new list giving substrings
+ common to both. */
+static char **
+inboth(left, right)
+ char **left;
+ char **right;
+{
+ char **both;
+ char **temp;
+ int lnum, rnum;
+
+ if (left == NULL || right == NULL)
+ return NULL;
+ both = (char **) malloc(sizeof *both);
+ if (both == NULL)
+ return NULL;
+ both[0] = NULL;
+ for (lnum = 0; left[lnum] != NULL; ++lnum)
+ {
+ for (rnum = 0; right[rnum] != NULL; ++rnum)
+ {
+ temp = comsubs(left[lnum], right[rnum]);
+ if (temp == NULL)
+ {
+ freelist(both);
+ return NULL;
+ }
+ both = addlists(both, temp);
+ freelist(temp);
+ if (both == NULL)
+ return NULL;
+ }
+ }
+ return both;
+}
+
+typedef struct
+{
+ char **in;
+ char *left;
+ char *right;
+ char *is;
+} must;
+
+static void
+resetmust(mp)
+must *mp;
+{
+ mp->left[0] = mp->right[0] = mp->is[0] = '\0';
+ freelist(mp->in);
+}
+
+static void
+dfamust(dfa)
+struct dfa *dfa;
+{
+ must *musts;
+ must *mp;
+ char *result;
+ int ri;
+ int i;
+ int exact;
+ token t;
+ static must must0;
+ struct dfamust *dm;
+
+ result = "";
+ exact = 0;
+ musts = (must *) malloc((dfa->tindex + 1) * sizeof *musts);
+ if (musts == NULL)
+ return;
+ mp = musts;
+ for (i = 0; i <= dfa->tindex; ++i)
+ mp[i] = must0;
+ for (i = 0; i <= dfa->tindex; ++i)
+ {
+ mp[i].in = (char **) malloc(sizeof *mp[i].in);
+ mp[i].left = malloc(2);
+ mp[i].right = malloc(2);
+ mp[i].is = malloc(2);
+ if (mp[i].in == NULL || mp[i].left == NULL ||
+ mp[i].right == NULL || mp[i].is == NULL)
+ goto done;
+ mp[i].left[0] = mp[i].right[0] = mp[i].is[0] = '\0';
+ mp[i].in[0] = NULL;
+ }
+#ifdef DEBUG
+ fprintf(stderr, "dfamust:\n");
+ for (i = 0; i < dfa->tindex; ++i)
+ {
+ fprintf(stderr, " %d:", i);
+ prtok(dfa->tokens[i]);
+ }
+ putc('\n', stderr);
+#endif
+ for (ri = 0; ri < dfa->tindex; ++ri)
+ {
+ switch (t = dfa->tokens[ri])
+ {
+ case LPAREN:
+ case RPAREN:
+ goto done; /* "cannot happen" */
+ case EMPTY:
+ case BEGLINE:
+ case ENDLINE:
+ case BEGWORD:
+ case ENDWORD:
+ case LIMWORD:
+ case NOTLIMWORD:
+ case BACKREF:
+ resetmust(mp);
+ break;
+ case STAR:
+ case QMARK:
+ if (mp <= musts)
+ goto done; /* "cannot happen" */
+ --mp;
+ resetmust(mp);
+ break;
+ case OR:
+ case ORTOP:
+ if (mp < &musts[2])
+ goto done; /* "cannot happen" */
+ {
+ char **new;
+ must *lmp;
+ must *rmp;
+ int j, ln, rn, n;
+
+ rmp = --mp;
+ lmp = --mp;
+ /* Guaranteed to be. Unlikely, but. . . */
+ if (strcmp(lmp->is, rmp->is) != 0)
+ lmp->is[0] = '\0';
+ /* Left side--easy */
+ i = 0;
+ while (lmp->left[i] != '\0' && lmp->left[i] == rmp->left[i])
+ ++i;
+ lmp->left[i] = '\0';
+ /* Right side */
+ ln = strlen(lmp->right);
+ rn = strlen(rmp->right);
+ n = ln;
+ if (n > rn)
+ n = rn;
+ for (i = 0; i < n; ++i)
+ if (lmp->right[ln - i - 1] != rmp->right[rn - i - 1])
+ break;
+ for (j = 0; j < i; ++j)
+ lmp->right[j] = lmp->right[(ln - i) + j];
+ lmp->right[j] = '\0';
+ new = inboth(lmp->in, rmp->in);
+ if (new == NULL)
+ goto done;
+ freelist(lmp->in);
+ free((char *) lmp->in);
+ lmp->in = new;
+ }
+ break;
+ case PLUS:
+ if (mp <= musts)
+ goto done; /* "cannot happen" */
+ --mp;
+ mp->is[0] = '\0';
+ break;
+ case END:
+ if (mp != &musts[1])
+ goto done; /* "cannot happen" */
+ for (i = 0; musts[0].in[i] != NULL; ++i)
+ if (strlen(musts[0].in[i]) > strlen(result))
+ result = musts[0].in[i];
+ if (strcmp(result, musts[0].is) == 0)
+ exact = 1;
+ goto done;
+ case CAT:
+ if (mp < &musts[2])
+ goto done; /* "cannot happen" */
+ {
+ must *lmp;
+ must *rmp;
+
+ rmp = --mp;
+ lmp = --mp;
+ /* In. Everything in left, plus everything in
+ right, plus catenation of
+ left's right and right's left. */
+ lmp->in = addlists(lmp->in, rmp->in);
+ if (lmp->in == NULL)
+ goto done;
+ if (lmp->right[0] != '\0' &&
+ rmp->left[0] != '\0')
+ {
+ char *tp;
+
+ tp = icpyalloc(lmp->right);
+ if (tp == NULL)
+ goto done;
+ tp = icatalloc(tp, rmp->left);
+ if (tp == NULL)
+ goto done;
+ lmp->in = enlist(lmp->in, tp,
+ strlen(tp));
+ free(tp);
+ if (lmp->in == NULL)
+ goto done;
+ }
+ /* Left-hand */
+ if (lmp->is[0] != '\0')
+ {
+ lmp->left = icatalloc(lmp->left,
+ rmp->left);
+ if (lmp->left == NULL)
+ goto done;
+ }
+ /* Right-hand */
+ if (rmp->is[0] == '\0')
+ lmp->right[0] = '\0';
+ lmp->right = icatalloc(lmp->right, rmp->right);
+ if (lmp->right == NULL)
+ goto done;
+ /* Guaranteed to be */
+ if (lmp->is[0] != '\0' && rmp->is[0] != '\0')
+ {
+ lmp->is = icatalloc(lmp->is, rmp->is);
+ if (lmp->is == NULL)
+ goto done;
+ }
+ else
+ lmp->is[0] = '\0';
+ }
+ break;
+ default:
+ if (t < END)
+ {
+ /* "cannot happen" */
+ goto done;
+ }
+ else if (t == '\0')
+ {
+ /* not on *my* shift */
+ goto done;
+ }
+ else if (t >= CSET)
+ {
+ /* easy enough */
+ resetmust(mp);
+ }
+ else
+ {
+ /* plain character */
+ resetmust(mp);
+ mp->is[0] = mp->left[0] = mp->right[0] = t;
+ mp->is[1] = mp->left[1] = mp->right[1] = '\0';
+ mp->in = enlist(mp->in, mp->is, 1);
+ if (mp->in == NULL)
+ goto done;
+ }
+ break;
+ }
+#ifdef DEBUG
+ fprintf(stderr, " node: %d:", ri);
+ prtok(dfa->tokens[ri]);
+ fprintf(stderr, "\n in:");
+ for (i = 0; mp->in[i]; ++i)
+ fprintf(stderr, " \"%s\"", mp->in[i]);
+ fprintf(stderr, "\n is: \"%s\"\n", mp->is);
+ fprintf(stderr, " left: \"%s\"\n", mp->left);
+ fprintf(stderr, " right: \"%s\"\n", mp->right);
+#endif
+ ++mp;
+ }
+ done:
+ if (strlen(result))
+ {
+ dm = (struct dfamust *) malloc(sizeof (struct dfamust));
+ dm->exact = exact;
+ dm->must = malloc(strlen(result) + 1);
+ strcpy(dm->must, result);
+ dm->next = dfa->musts;
+ dfa->musts = dm;
+ }
+ mp = musts;
+ for (i = 0; i <= dfa->tindex; ++i)
+ {
+ freelist(mp[i].in);
+ ifree((char *) mp[i].in);
+ ifree(mp[i].left);
+ ifree(mp[i].right);
+ ifree(mp[i].is);
+ }
+ free((char *) mp);
+}
diff --git a/gnu/usr.bin/grep/dfa.h b/gnu/usr.bin/grep/dfa.h
new file mode 100644
index 0000000..32e05fc
--- /dev/null
+++ b/gnu/usr.bin/grep/dfa.h
@@ -0,0 +1,360 @@
+/* dfa.h - declarations for GNU deterministic regexp compiler
+ Copyright (C) 1988 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* Written June, 1988 by Mike Haertel */
+
+/* FIXME:
+ 2. We should not export so much of the DFA internals.
+ In addition to clobbering modularity, we eat up valuable
+ name space. */
+
+/* Number of bits in an unsigned char. */
+#define CHARBITS 8
+
+/* First integer value that is greater than any character code. */
+#define NOTCHAR (1 << CHARBITS)
+
+/* INTBITS need not be exact, just a lower bound. */
+#define INTBITS (CHARBITS * sizeof (int))
+
+/* Number of ints required to hold a bit for every character. */
+#define CHARCLASS_INTS ((NOTCHAR + INTBITS - 1) / INTBITS)
+
+/* Sets of unsigned characters are stored as bit vectors in arrays of ints. */
+typedef int charclass[CHARCLASS_INTS];
+
+/* The regexp is parsed into an array of tokens in postfix form. Some tokens
+ are operators and others are terminal symbols. Most (but not all) of these
+ codes are returned by the lexical analyzer. */
+
+typedef enum
+{
+ END = -1, /* END is a terminal symbol that matches the
+ end of input; any value of END or less in
+ the parse tree is such a symbol. Accepting
+ states of the DFA are those that would have
+ a transition on END. */
+
+ /* Ordinary character values are terminal symbols that match themselves. */
+
+ EMPTY = NOTCHAR, /* EMPTY is a terminal symbol that matches
+ the empty string. */
+
+ BACKREF, /* BACKREF is generated by \<digit>; it
+ it not completely handled. If the scanner
+ detects a transition on backref, it returns
+ a kind of "semi-success" indicating that
+ the match will have to be verified with
+ a backtracking matcher. */
+
+ BEGLINE, /* BEGLINE is a terminal symbol that matches
+ the empty string if it is at the beginning
+ of a line. */
+
+ ENDLINE, /* ENDLINE is a terminal symbol that matches
+ the empty string if it is at the end of
+ a line. */
+
+ BEGWORD, /* BEGWORD is a terminal symbol that matches
+ the empty string if it is at the beginning
+ of a word. */
+
+ ENDWORD, /* ENDWORD is a terminal symbol that matches
+ the empty string if it is at the end of
+ a word. */
+
+ LIMWORD, /* LIMWORD is a terminal symbol that matches
+ the empty string if it is at the beginning
+ or the end of a word. */
+
+ NOTLIMWORD, /* NOTLIMWORD is a terminal symbol that
+ matches the empty string if it is not at
+ the beginning or end of a word. */
+
+ QMARK, /* QMARK is an operator of one argument that
+ matches zero or one occurences of its
+ argument. */
+
+ STAR, /* STAR is an operator of one argument that
+ matches the Kleene closure (zero or more
+ occurrences) of its argument. */
+
+ PLUS, /* PLUS is an operator of one argument that
+ matches the positive closure (one or more
+ occurrences) of its argument. */
+
+ REPMN, /* REPMN is a lexical token corresponding
+ to the {m,n} construct. REPMN never
+ appears in the compiled token vector. */
+
+ CAT, /* CAT is an operator of two arguments that
+ matches the concatenation of its
+ arguments. CAT is never returned by the
+ lexical analyzer. */
+
+ OR, /* OR is an operator of two arguments that
+ matches either of its arguments. */
+
+ ORTOP, /* OR at the toplevel in the parse tree.
+ This is used for a boyer-moore heuristic. */
+
+ LPAREN, /* LPAREN never appears in the parse tree,
+ it is only a lexeme. */
+
+ RPAREN, /* RPAREN never appears in the parse tree. */
+
+ CSET /* CSET and (and any value greater) is a
+ terminal symbol that matches any of a
+ class of characters. */
+} token;
+
+/* Sets are stored in an array in the compiled dfa; the index of the
+ array corresponding to a given set token is given by SET_INDEX(t). */
+#define SET_INDEX(t) ((t) - CSET)
+
+/* Sometimes characters can only be matched depending on the surrounding
+ context. Such context decisions depend on what the previous character
+ was, and the value of the current (lookahead) character. Context
+ dependent constraints are encoded as 8 bit integers. Each bit that
+ is set indicates that the constraint succeeds in the corresponding
+ context.
+
+ bit 7 - previous and current are newlines
+ bit 6 - previous was newline, current isn't
+ bit 5 - previous wasn't newline, current is
+ bit 4 - neither previous nor current is a newline
+ bit 3 - previous and current are word-constituents
+ bit 2 - previous was word-constituent, current isn't
+ bit 1 - previous wasn't word-constituent, current is
+ bit 0 - neither previous nor current is word-constituent
+
+ Word-constituent characters are those that satisfy isalnum().
+
+ The macro SUCCEEDS_IN_CONTEXT determines whether a a given constraint
+ succeeds in a particular context. Prevn is true if the previous character
+ was a newline, currn is true if the lookahead character is a newline.
+ Prevl and currl similarly depend upon whether the previous and current
+ characters are word-constituent letters. */
+#define MATCHES_NEWLINE_CONTEXT(constraint, prevn, currn) \
+ ((constraint) & 1 << (((prevn) ? 2 : 0) + ((currn) ? 1 : 0) + 4))
+#define MATCHES_LETTER_CONTEXT(constraint, prevl, currl) \
+ ((constraint) & 1 << (((prevl) ? 2 : 0) + ((currl) ? 1 : 0)))
+#define SUCCEEDS_IN_CONTEXT(constraint, prevn, currn, prevl, currl) \
+ (MATCHES_NEWLINE_CONTEXT(constraint, prevn, currn) \
+ && MATCHES_LETTER_CONTEXT(constraint, prevl, currl))
+
+/* The following macros give information about what a constraint depends on. */
+#define PREV_NEWLINE_DEPENDENT(constraint) \
+ (((constraint) & 0xc0) >> 2 != ((constraint) & 0x30))
+#define PREV_LETTER_DEPENDENT(constraint) \
+ (((constraint) & 0x0c) >> 2 != ((constraint) & 0x03))
+
+/* Tokens that match the empty string subject to some constraint actually
+ work by applying that constraint to determine what may follow them,
+ taking into account what has gone before. The following values are
+ the constraints corresponding to the special tokens previously defined. */
+#define NO_CONSTRAINT 0xff
+#define BEGLINE_CONSTRAINT 0xcf
+#define ENDLINE_CONSTRAINT 0xaf
+#define BEGWORD_CONSTRAINT 0xf2
+#define ENDWORD_CONSTRAINT 0xf4
+#define LIMWORD_CONSTRAINT 0xf6
+#define NOTLIMWORD_CONSTRAINT 0xf9
+
+/* States of the recognizer correspond to sets of positions in the parse
+ tree, together with the constraints under which they may be matched.
+ So a position is encoded as an index into the parse tree together with
+ a constraint. */
+typedef struct
+{
+ unsigned index; /* Index into the parse array. */
+ unsigned constraint; /* Constraint for matching this position. */
+} position;
+
+/* Sets of positions are stored as arrays. */
+typedef struct
+{
+ position *elems; /* Elements of this position set. */
+ int nelem; /* Number of elements in this set. */
+} position_set;
+
+/* A state of the dfa consists of a set of positions, some flags,
+ and the token value of the lowest-numbered position of the state that
+ contains an END token. */
+typedef struct
+{
+ int hash; /* Hash of the positions of this state. */
+ position_set elems; /* Positions this state could match. */
+ char newline; /* True if previous state matched newline. */
+ char letter; /* True if previous state matched a letter. */
+ char backref; /* True if this state matches a \<digit>. */
+ unsigned char constraint; /* Constraint for this state to accept. */
+ int first_end; /* Token value of the first END in elems. */
+} dfa_state;
+
+/* Element of a list of strings, at least one of which is known to
+ appear in any R.E. matching the DFA. */
+struct dfamust
+{
+ int exact;
+ char *must;
+ struct dfamust *next;
+};
+
+/* A compiled regular expression. */
+struct dfa
+{
+ /* Stuff built by the scanner. */
+ charclass *charclasses; /* Array of character sets for CSET tokens. */
+ int cindex; /* Index for adding new charclasses. */
+ int calloc; /* Number of charclasses currently allocated. */
+
+ /* Stuff built by the parser. */
+ token *tokens; /* Postfix parse array. */
+ int tindex; /* Index for adding new tokens. */
+ int talloc; /* Number of tokens currently allocated. */
+ int depth; /* Depth required of an evaluation stack
+ used for depth-first traversal of the
+ parse tree. */
+ int nleaves; /* Number of leaves on the parse tree. */
+ int nregexps; /* Count of parallel regexps being built
+ with dfaparse(). */
+
+ /* Stuff owned by the state builder. */
+ dfa_state *states; /* States of the dfa. */
+ int sindex; /* Index for adding new states. */
+ int salloc; /* Number of states currently allocated. */
+
+ /* Stuff built by the structure analyzer. */
+ position_set *follows; /* Array of follow sets, indexed by position
+ index. The follow of a position is the set
+ of positions containing characters that
+ could conceivably follow a character
+ matching the given position in a string
+ matching the regexp. Allocated to the
+ maximum possible position index. */
+ int searchflag; /* True if we are supposed to build a searching
+ as opposed to an exact matcher. A searching
+ matcher finds the first and shortest string
+ matching a regexp anywhere in the buffer,
+ whereas an exact matcher finds the longest
+ string matching, but anchored to the
+ beginning of the buffer. */
+
+ /* Stuff owned by the executor. */
+ int tralloc; /* Number of transition tables that have
+ slots so far. */
+ int trcount; /* Number of transition tables that have
+ actually been built. */
+ int **trans; /* Transition tables for states that can
+ never accept. If the transitions for a
+ state have not yet been computed, or the
+ state could possibly accept, its entry in
+ this table is NULL. */
+ int **realtrans; /* Trans always points to realtrans + 1; this
+ is so trans[-1] can contain NULL. */
+ int **fails; /* Transition tables after failing to accept
+ on a state that potentially could do so. */
+ int *success; /* Table of acceptance conditions used in
+ dfaexec and computed in build_state. */
+ int *newlines; /* Transitions on newlines. The entry for a
+ newline in any transition table is always
+ -1 so we can count lines without wasting
+ too many cycles. The transition for a
+ newline is stored separately and handled
+ as a special case. Newline is also used
+ as a sentinel at the end of the buffer. */
+ struct dfamust *musts; /* List of strings, at least one of which
+ is known to appear in any r.e. matching
+ the dfa. */
+};
+
+/* Some macros for user access to dfa internals. */
+
+/* ACCEPTING returns true if s could possibly be an accepting state of r. */
+#define ACCEPTING(s, r) ((r).states[s].constraint)
+
+/* ACCEPTS_IN_CONTEXT returns true if the given state accepts in the
+ specified context. */
+#define ACCEPTS_IN_CONTEXT(prevn, currn, prevl, currl, state, dfa) \
+ SUCCEEDS_IN_CONTEXT((dfa).states[state].constraint, \
+ prevn, currn, prevl, currl)
+
+/* FIRST_MATCHING_REGEXP returns the index number of the first of parallel
+ regexps that a given state could accept. Parallel regexps are numbered
+ starting at 1. */
+#define FIRST_MATCHING_REGEXP(state, dfa) (-(dfa).states[state].first_end)
+
+/* Entry points. */
+
+#if __STDC__
+
+/* dfasyntax() takes two arguments; the first sets the syntax bits described
+ earlier in this file, and the second sets the case-folding flag. */
+extern void dfasyntax(int, int);
+
+/* Compile the given string of the given length into the given struct dfa.
+ Final argument is a flag specifying whether to build a searching or an
+ exact matcher. */
+extern void dfacomp(char *, size_t, struct dfa *, int);
+
+/* Execute the given struct dfa on the buffer of characters. The
+ first char * points to the beginning, and the second points to the
+ first character after the end of the buffer, which must be a writable
+ place so a sentinel end-of-buffer marker can be stored there. The
+ second-to-last argument is a flag telling whether to allow newlines to
+ be part of a string matching the regexp. The next-to-last argument,
+ if non-NULL, points to a place to increment every time we see a
+ newline. The final argument, if non-NULL, points to a flag that will
+ be set if further examination by a backtracking matcher is needed in
+ order to verify backreferencing; otherwise the flag will be cleared.
+ Returns NULL if no match is found, or a pointer to the first
+ character after the first & shortest matching string in the buffer. */
+extern char *dfaexec(struct dfa *, char *, char *, int, int *, int *);
+
+/* Free the storage held by the components of a struct dfa. */
+extern void dfafree(struct dfa *);
+
+/* Entry points for people who know what they're doing. */
+
+/* Initialize the components of a struct dfa. */
+extern void dfainit(struct dfa *);
+
+/* Incrementally parse a string of given length into a struct dfa. */
+extern void dfaparse(char *, size_t, struct dfa *);
+
+/* Analyze a parsed regexp; second argument tells whether to build a searching
+ or an exact matcher. */
+extern void dfaanalyze(struct dfa *, int);
+
+/* Compute, for each possible character, the transitions out of a given
+ state, storing them in an array of integers. */
+extern void dfastate(int, struct dfa *, int []);
+
+/* Error handling. */
+
+/* dfaerror() is called by the regexp routines whenever an error occurs. It
+ takes a single argument, a NUL-terminated string describing the error.
+ The default dfaerror() prints the error message to stderr and exits.
+ The user can provide a different dfafree() if so desired. */
+extern void dfaerror(char *);
+
+#else /* ! __STDC__ */
+extern void dfasyntax(), dfacomp(), dfafree(), dfainit(), dfaparse();
+extern void dfaanalyze(), dfastate(), dfaerror();
+extern char *dfaexec();
+#endif /* ! __STDC__ */
diff --git a/gnu/usr.bin/grep/getopt.c b/gnu/usr.bin/grep/getopt.c
new file mode 100644
index 0000000..a59a013
--- /dev/null
+++ b/gnu/usr.bin/grep/getopt.c
@@ -0,0 +1,731 @@
+/* Getopt for GNU.
+ NOTE: getopt is now part of the C library, so if you don't know what
+ "Keep this file name-space clean" means, talk to roland@gnu.ai.mit.edu
+ before changing it!
+
+ Copyright (C) 1987, 88, 89, 90, 91, 92, 1993
+ Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any
+ later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* NOTE!!! AIX requires this to be the first thing in the file.
+ Do not put ANYTHING before it! */
+#if !defined (__GNUC__) && defined (_AIX)
+ #pragma alloca
+#endif
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef __GNUC__
+#define alloca __builtin_alloca
+#else /* not __GNUC__ */
+#if defined (HAVE_ALLOCA_H) || (defined(sparc) && (defined(sun) || (!defined(USG) && !defined(SVR4) && !defined(__svr4__))))
+#include <alloca.h>
+#else
+#ifndef _AIX
+char *alloca ();
+#endif
+#endif /* alloca.h */
+#endif /* not __GNUC__ */
+
+#if !__STDC__ && !defined(const) && IN_GCC
+#define const
+#endif
+
+/* This tells Alpha OSF/1 not to define a getopt prototype in <stdio.h>. */
+#ifndef _NO_PROTO
+#define _NO_PROTO
+#endif
+
+#include <stdio.h>
+
+/* Comment out all this code if we are using the GNU C Library, and are not
+ actually compiling the library itself. This code is part of the GNU C
+ Library, but also included in many other GNU distributions. Compiling
+ and linking in this code is a waste when using the GNU C library
+ (especially if it is a shared library). Rather than having every GNU
+ program understand `configure --with-gnu-libc' and omit the object files,
+ it is simpler to just do this in the source for each such file. */
+
+#if defined (_LIBC) || !defined (__GNU_LIBRARY__)
+
+
+/* This needs to come after some library #include
+ to get __GNU_LIBRARY__ defined. */
+#ifdef __GNU_LIBRARY__
+#undef alloca
+/* Don't include stdlib.h for non-GNU C libraries because some of them
+ contain conflicting prototypes for getopt. */
+#include <stdlib.h>
+#else /* Not GNU C library. */
+#define __alloca alloca
+#endif /* GNU C library. */
+
+/* If GETOPT_COMPAT is defined, `+' as well as `--' can introduce a
+ long-named option. Because this is not POSIX.2 compliant, it is
+ being phased out. */
+/* #define GETOPT_COMPAT */
+
+/* This version of `getopt' appears to the caller like standard Unix `getopt'
+ but it behaves differently for the user, since it allows the user
+ to intersperse the options with the other arguments.
+
+ As `getopt' works, it permutes the elements of ARGV so that,
+ when it is done, all the options precede everything else. Thus
+ all application programs are extended to handle flexible argument order.
+
+ Setting the environment variable POSIXLY_CORRECT disables permutation.
+ Then the behavior is completely standard.
+
+ GNU application programs can use a third alternative mode in which
+ they can distinguish the relative order of options and other arguments. */
+
+#include "getopt.h"
+
+/* For communication from `getopt' to the caller.
+ When `getopt' finds an option that takes an argument,
+ the argument value is returned here.
+ Also, when `ordering' is RETURN_IN_ORDER,
+ each non-option ARGV-element is returned here. */
+
+char *optarg = 0;
+
+/* Index in ARGV of the next element to be scanned.
+ This is used for communication to and from the caller
+ and for communication between successive calls to `getopt'.
+
+ On entry to `getopt', zero means this is the first call; initialize.
+
+ When `getopt' returns EOF, this is the index of the first of the
+ non-option elements that the caller should itself scan.
+
+ Otherwise, `optind' communicates from one call to the next
+ how much of ARGV has been scanned so far. */
+
+/* XXX 1003.2 says this must be 1 before any call. */
+int optind = 0;
+
+/* The next char to be scanned in the option-element
+ in which the last option character we returned was found.
+ This allows us to pick up the scan where we left off.
+
+ If this is zero, or a null string, it means resume the scan
+ by advancing to the next ARGV-element. */
+
+static char *nextchar;
+
+/* Callers store zero here to inhibit the error message
+ for unrecognized options. */
+
+int opterr = 1;
+
+/* Set to an option character which was unrecognized.
+ This must be initialized on some systems to avoid linking in the
+ system's own getopt implementation. */
+
+int optopt = '?';
+
+/* Describe how to deal with options that follow non-option ARGV-elements.
+
+ If the caller did not specify anything,
+ the default is REQUIRE_ORDER if the environment variable
+ POSIXLY_CORRECT is defined, PERMUTE otherwise.
+
+ REQUIRE_ORDER means don't recognize them as options;
+ stop option processing when the first non-option is seen.
+ This is what Unix does.
+ This mode of operation is selected by either setting the environment
+ variable POSIXLY_CORRECT, or using `+' as the first character
+ of the list of option characters.
+
+ PERMUTE is the default. We permute the contents of ARGV as we scan,
+ so that eventually all the non-options are at the end. This allows options
+ to be given in any order, even with programs that were not written to
+ expect this.
+
+ RETURN_IN_ORDER is an option available to programs that were written
+ to expect options and other ARGV-elements in any order and that care about
+ the ordering of the two. We describe each non-option ARGV-element
+ as if it were the argument of an option with character code 1.
+ Using `-' as the first character of the list of option characters
+ selects this mode of operation.
+
+ The special argument `--' forces an end of option-scanning regardless
+ of the value of `ordering'. In the case of RETURN_IN_ORDER, only
+ `--' can cause `getopt' to return EOF with `optind' != ARGC. */
+
+static enum
+{
+ REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER
+} ordering;
+
+#ifdef __GNU_LIBRARY__
+/* We want to avoid inclusion of string.h with non-GNU libraries
+ because there are many ways it can cause trouble.
+ On some systems, it contains special magic macros that don't work
+ in GCC. */
+#include <string.h>
+#define my_index strchr
+#define my_bcopy(src, dst, n) memcpy ((dst), (src), (n))
+#else
+
+/* Avoid depending on library functions or files
+ whose names are inconsistent. */
+
+char *getenv ();
+
+static char *
+my_index (str, chr)
+ const char *str;
+ int chr;
+{
+ while (*str)
+ {
+ if (*str == chr)
+ return (char *) str;
+ str++;
+ }
+ return 0;
+}
+
+static void
+my_bcopy (from, to, size)
+ const char *from;
+ char *to;
+ int size;
+{
+ int i;
+ for (i = 0; i < size; i++)
+ to[i] = from[i];
+}
+#endif /* GNU C library. */
+
+/* Handle permutation of arguments. */
+
+/* Describe the part of ARGV that contains non-options that have
+ been skipped. `first_nonopt' is the index in ARGV of the first of them;
+ `last_nonopt' is the index after the last of them. */
+
+static int first_nonopt;
+static int last_nonopt;
+
+/* Exchange two adjacent subsequences of ARGV.
+ One subsequence is elements [first_nonopt,last_nonopt)
+ which contains all the non-options that have been skipped so far.
+ The other is elements [last_nonopt,optind), which contains all
+ the options processed since those non-options were skipped.
+
+ `first_nonopt' and `last_nonopt' are relocated so that they describe
+ the new indices of the non-options in ARGV after they are moved. */
+
+static void
+exchange (argv)
+ char **argv;
+{
+ int nonopts_size = (last_nonopt - first_nonopt) * sizeof (char *);
+ char **temp = (char **) __alloca (nonopts_size);
+
+ /* Interchange the two blocks of data in ARGV. */
+
+ my_bcopy ((char *) &argv[first_nonopt], (char *) temp, nonopts_size);
+ my_bcopy ((char *) &argv[last_nonopt], (char *) &argv[first_nonopt],
+ (optind - last_nonopt) * sizeof (char *));
+ my_bcopy ((char *) temp,
+ (char *) &argv[first_nonopt + optind - last_nonopt],
+ nonopts_size);
+
+ /* Update records for the slots the non-options now occupy. */
+
+ first_nonopt += (optind - last_nonopt);
+ last_nonopt = optind;
+}
+
+/* Scan elements of ARGV (whose length is ARGC) for option characters
+ given in OPTSTRING.
+
+ If an element of ARGV starts with '-', and is not exactly "-" or "--",
+ then it is an option element. The characters of this element
+ (aside from the initial '-') are option characters. If `getopt'
+ is called repeatedly, it returns successively each of the option characters
+ from each of the option elements.
+
+ If `getopt' finds another option character, it returns that character,
+ updating `optind' and `nextchar' so that the next call to `getopt' can
+ resume the scan with the following option character or ARGV-element.
+
+ If there are no more option characters, `getopt' returns `EOF'.
+ Then `optind' is the index in ARGV of the first ARGV-element
+ that is not an option. (The ARGV-elements have been permuted
+ so that those that are not options now come last.)
+
+ OPTSTRING is a string containing the legitimate option characters.
+ If an option character is seen that is not listed in OPTSTRING,
+ return '?' after printing an error message. If you set `opterr' to
+ zero, the error message is suppressed but we still return '?'.
+
+ If a char in OPTSTRING is followed by a colon, that means it wants an arg,
+ so the following text in the same ARGV-element, or the text of the following
+ ARGV-element, is returned in `optarg'. Two colons mean an option that
+ wants an optional arg; if there is text in the current ARGV-element,
+ it is returned in `optarg', otherwise `optarg' is set to zero.
+
+ If OPTSTRING starts with `-' or `+', it requests different methods of
+ handling the non-option ARGV-elements.
+ See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above.
+
+ Long-named options begin with `--' instead of `-'.
+ Their names may be abbreviated as long as the abbreviation is unique
+ or is an exact match for some defined option. If they have an
+ argument, it follows the option name in the same ARGV-element, separated
+ from the option name by a `=', or else the in next ARGV-element.
+ When `getopt' finds a long-named option, it returns 0 if that option's
+ `flag' field is nonzero, the value of the option's `val' field
+ if the `flag' field is zero.
+
+ The elements of ARGV aren't really const, because we permute them.
+ But we pretend they're const in the prototype to be compatible
+ with other systems.
+
+ LONGOPTS is a vector of `struct option' terminated by an
+ element containing a name which is zero.
+
+ LONGIND returns the index in LONGOPT of the long-named option found.
+ It is only valid when a long-named option has been found by the most
+ recent call.
+
+ If LONG_ONLY is nonzero, '-' as well as '--' can introduce
+ long-named options. */
+
+int
+_getopt_internal (argc, argv, optstring, longopts, longind, long_only)
+ int argc;
+ char *const *argv;
+ const char *optstring;
+ const struct option *longopts;
+ int *longind;
+ int long_only;
+{
+ int option_index;
+
+ optarg = 0;
+
+ /* Initialize the internal data when the first call is made.
+ Start processing options with ARGV-element 1 (since ARGV-element 0
+ is the program name); the sequence of previously skipped
+ non-option ARGV-elements is empty. */
+
+ if (optind == 0)
+ {
+ first_nonopt = last_nonopt = optind = 1;
+
+ nextchar = NULL;
+
+ /* Determine how to handle the ordering of options and nonoptions. */
+
+ if (optstring[0] == '-')
+ {
+ ordering = RETURN_IN_ORDER;
+ ++optstring;
+ }
+ else if (optstring[0] == '+')
+ {
+ ordering = REQUIRE_ORDER;
+ ++optstring;
+ }
+ else if (getenv ("POSIXLY_CORRECT") != NULL)
+ ordering = REQUIRE_ORDER;
+ else
+ ordering = PERMUTE;
+ }
+
+ if (nextchar == NULL || *nextchar == '\0')
+ {
+ if (ordering == PERMUTE)
+ {
+ /* If we have just processed some options following some non-options,
+ exchange them so that the options come first. */
+
+ if (first_nonopt != last_nonopt && last_nonopt != optind)
+ exchange ((char **) argv);
+ else if (last_nonopt != optind)
+ first_nonopt = optind;
+
+ /* Now skip any additional non-options
+ and extend the range of non-options previously skipped. */
+
+ while (optind < argc
+ && (argv[optind][0] != '-' || argv[optind][1] == '\0')
+#ifdef GETOPT_COMPAT
+ && (longopts == NULL
+ || argv[optind][0] != '+' || argv[optind][1] == '\0')
+#endif /* GETOPT_COMPAT */
+ )
+ optind++;
+ last_nonopt = optind;
+ }
+
+ /* Special ARGV-element `--' means premature end of options.
+ Skip it like a null option,
+ then exchange with previous non-options as if it were an option,
+ then skip everything else like a non-option. */
+
+ if (optind != argc && !strcmp (argv[optind], "--"))
+ {
+ optind++;
+
+ if (first_nonopt != last_nonopt && last_nonopt != optind)
+ exchange ((char **) argv);
+ else if (first_nonopt == last_nonopt)
+ first_nonopt = optind;
+ last_nonopt = argc;
+
+ optind = argc;
+ }
+
+ /* If we have done all the ARGV-elements, stop the scan
+ and back over any non-options that we skipped and permuted. */
+
+ if (optind == argc)
+ {
+ /* Set the next-arg-index to point at the non-options
+ that we previously skipped, so the caller will digest them. */
+ if (first_nonopt != last_nonopt)
+ optind = first_nonopt;
+ return EOF;
+ }
+
+ /* If we have come to a non-option and did not permute it,
+ either stop the scan or describe it to the caller and pass it by. */
+
+ if ((argv[optind][0] != '-' || argv[optind][1] == '\0')
+#ifdef GETOPT_COMPAT
+ && (longopts == NULL
+ || argv[optind][0] != '+' || argv[optind][1] == '\0')
+#endif /* GETOPT_COMPAT */
+ )
+ {
+ if (ordering == REQUIRE_ORDER)
+ return EOF;
+ optarg = argv[optind++];
+ return 1;
+ }
+
+ /* We have found another option-ARGV-element.
+ Start decoding its characters. */
+
+ nextchar = (argv[optind] + 1
+ + (longopts != NULL && argv[optind][1] == '-'));
+ }
+
+ if (longopts != NULL
+ && ((argv[optind][0] == '-'
+ && (argv[optind][1] == '-' || long_only))
+#ifdef GETOPT_COMPAT
+ || argv[optind][0] == '+'
+#endif /* GETOPT_COMPAT */
+ ))
+ {
+ const struct option *p;
+ char *s = nextchar;
+ int exact = 0;
+ int ambig = 0;
+ const struct option *pfound = NULL;
+ int indfound;
+
+ while (*s && *s != '=')
+ s++;
+
+ /* Test all options for either exact match or abbreviated matches. */
+ for (p = longopts, option_index = 0; p->name;
+ p++, option_index++)
+ if (!strncmp (p->name, nextchar, s - nextchar))
+ {
+ if (s - nextchar == strlen (p->name))
+ {
+ /* Exact match found. */
+ pfound = p;
+ indfound = option_index;
+ exact = 1;
+ break;
+ }
+ else if (pfound == NULL)
+ {
+ /* First nonexact match found. */
+ pfound = p;
+ indfound = option_index;
+ }
+ else
+ /* Second nonexact match found. */
+ ambig = 1;
+ }
+
+ if (ambig && !exact)
+ {
+ if (opterr)
+ fprintf (stderr, "%s: option `%s' is ambiguous\n",
+ argv[0], argv[optind]);
+ nextchar += strlen (nextchar);
+ optind++;
+ return '?';
+ }
+
+ if (pfound != NULL)
+ {
+ option_index = indfound;
+ optind++;
+ if (*s)
+ {
+ /* Don't test has_arg with >, because some C compilers don't
+ allow it to be used on enums. */
+ if (pfound->has_arg)
+ optarg = s + 1;
+ else
+ {
+ if (opterr)
+ {
+ if (argv[optind - 1][1] == '-')
+ /* --option */
+ fprintf (stderr,
+ "%s: option `--%s' doesn't allow an argument\n",
+ argv[0], pfound->name);
+ else
+ /* +option or -option */
+ fprintf (stderr,
+ "%s: option `%c%s' doesn't allow an argument\n",
+ argv[0], argv[optind - 1][0], pfound->name);
+ }
+ nextchar += strlen (nextchar);
+ return '?';
+ }
+ }
+ else if (pfound->has_arg == 1)
+ {
+ if (optind < argc)
+ optarg = argv[optind++];
+ else
+ {
+ if (opterr)
+ fprintf (stderr, "%s: option `%s' requires an argument\n",
+ argv[0], argv[optind - 1]);
+ nextchar += strlen (nextchar);
+ return optstring[0] == ':' ? ':' : '?';
+ }
+ }
+ nextchar += strlen (nextchar);
+ if (longind != NULL)
+ *longind = option_index;
+ if (pfound->flag)
+ {
+ *(pfound->flag) = pfound->val;
+ return 0;
+ }
+ return pfound->val;
+ }
+ /* Can't find it as a long option. If this is not getopt_long_only,
+ or the option starts with '--' or is not a valid short
+ option, then it's an error.
+ Otherwise interpret it as a short option. */
+ if (!long_only || argv[optind][1] == '-'
+#ifdef GETOPT_COMPAT
+ || argv[optind][0] == '+'
+#endif /* GETOPT_COMPAT */
+ || my_index (optstring, *nextchar) == NULL)
+ {
+ if (opterr)
+ {
+ if (argv[optind][1] == '-')
+ /* --option */
+ fprintf (stderr, "%s: unrecognized option `--%s'\n",
+ argv[0], nextchar);
+ else
+ /* +option or -option */
+ fprintf (stderr, "%s: unrecognized option `%c%s'\n",
+ argv[0], argv[optind][0], nextchar);
+ }
+ nextchar = (char *) "";
+ optind++;
+ return '?';
+ }
+ }
+
+ /* Look at and handle the next option-character. */
+
+ {
+ char c = *nextchar++;
+ char *temp = my_index (optstring, c);
+
+ /* Increment `optind' when we start to process its last character. */
+ if (*nextchar == '\0')
+ ++optind;
+
+ if (temp == NULL || c == ':')
+ {
+ if (opterr)
+ {
+#if 0
+ if (c < 040 || c >= 0177)
+ fprintf (stderr, "%s: unrecognized option, character code 0%o\n",
+ argv[0], c);
+ else
+ fprintf (stderr, "%s: unrecognized option `-%c'\n", argv[0], c);
+#else
+ /* 1003.2 specifies the format of this message. */
+ fprintf (stderr, "%s: illegal option -- %c\n", argv[0], c);
+#endif
+ }
+ optopt = c;
+ return '?';
+ }
+ if (temp[1] == ':')
+ {
+ if (temp[2] == ':')
+ {
+ /* This is an option that accepts an argument optionally. */
+ if (*nextchar != '\0')
+ {
+ optarg = nextchar;
+ optind++;
+ }
+ else
+ optarg = 0;
+ nextchar = NULL;
+ }
+ else
+ {
+ /* This is an option that requires an argument. */
+ if (*nextchar != '\0')
+ {
+ optarg = nextchar;
+ /* If we end this ARGV-element by taking the rest as an arg,
+ we must advance to the next element now. */
+ optind++;
+ }
+ else if (optind == argc)
+ {
+ if (opterr)
+ {
+#if 0
+ fprintf (stderr, "%s: option `-%c' requires an argument\n",
+ argv[0], c);
+#else
+ /* 1003.2 specifies the format of this message. */
+ fprintf (stderr, "%s: option requires an argument -- %c\n",
+ argv[0], c);
+#endif
+ }
+ optopt = c;
+ if (optstring[0] == ':')
+ c = ':';
+ else
+ c = '?';
+ }
+ else
+ /* We already incremented `optind' once;
+ increment it again when taking next ARGV-elt as argument. */
+ optarg = argv[optind++];
+ nextchar = NULL;
+ }
+ }
+ return c;
+ }
+}
+
+int
+getopt (argc, argv, optstring)
+ int argc;
+ char *const *argv;
+ const char *optstring;
+{
+ return _getopt_internal (argc, argv, optstring,
+ (const struct option *) 0,
+ (int *) 0,
+ 0);
+}
+
+#endif /* _LIBC or not __GNU_LIBRARY__. */
+
+#ifdef TEST
+
+/* Compile with -DTEST to make an executable for use in testing
+ the above definition of `getopt'. */
+
+int
+main (argc, argv)
+ int argc;
+ char **argv;
+{
+ int c;
+ int digit_optind = 0;
+
+ while (1)
+ {
+ int this_option_optind = optind ? optind : 1;
+
+ c = getopt (argc, argv, "abc:d:0123456789");
+ if (c == EOF)
+ break;
+
+ switch (c)
+ {
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ if (digit_optind != 0 && digit_optind != this_option_optind)
+ printf ("digits occur in two different argv-elements.\n");
+ digit_optind = this_option_optind;
+ printf ("option %c\n", c);
+ break;
+
+ case 'a':
+ printf ("option a\n");
+ break;
+
+ case 'b':
+ printf ("option b\n");
+ break;
+
+ case 'c':
+ printf ("option c with value `%s'\n", optarg);
+ break;
+
+ case '?':
+ break;
+
+ default:
+ printf ("?? getopt returned character code 0%o ??\n", c);
+ }
+ }
+
+ if (optind < argc)
+ {
+ printf ("non-option ARGV-elements: ");
+ while (optind < argc)
+ printf ("%s ", argv[optind++]);
+ printf ("\n");
+ }
+
+ exit (0);
+}
+
+#endif /* TEST */
diff --git a/gnu/usr.bin/grep/getopt.h b/gnu/usr.bin/grep/getopt.h
new file mode 100644
index 0000000..45541f5
--- /dev/null
+++ b/gnu/usr.bin/grep/getopt.h
@@ -0,0 +1,129 @@
+/* Declarations for getopt.
+ Copyright (C) 1989, 1990, 1991, 1992, 1993 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any
+ later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#ifndef _GETOPT_H
+#define _GETOPT_H 1
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* For communication from `getopt' to the caller.
+ When `getopt' finds an option that takes an argument,
+ the argument value is returned here.
+ Also, when `ordering' is RETURN_IN_ORDER,
+ each non-option ARGV-element is returned here. */
+
+extern char *optarg;
+
+/* Index in ARGV of the next element to be scanned.
+ This is used for communication to and from the caller
+ and for communication between successive calls to `getopt'.
+
+ On entry to `getopt', zero means this is the first call; initialize.
+
+ When `getopt' returns EOF, this is the index of the first of the
+ non-option elements that the caller should itself scan.
+
+ Otherwise, `optind' communicates from one call to the next
+ how much of ARGV has been scanned so far. */
+
+extern int optind;
+
+/* Callers store zero here to inhibit the error message `getopt' prints
+ for unrecognized options. */
+
+extern int opterr;
+
+/* Set to an option character which was unrecognized. */
+
+extern int optopt;
+
+/* Describe the long-named options requested by the application.
+ The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector
+ of `struct option' terminated by an element containing a name which is
+ zero.
+
+ The field `has_arg' is:
+ no_argument (or 0) if the option does not take an argument,
+ required_argument (or 1) if the option requires an argument,
+ optional_argument (or 2) if the option takes an optional argument.
+
+ If the field `flag' is not NULL, it points to a variable that is set
+ to the value given in the field `val' when the option is found, but
+ left unchanged if the option is not found.
+
+ To have a long-named option do something other than set an `int' to
+ a compiled-in constant, such as set a value from `optarg', set the
+ option's `flag' field to zero and its `val' field to a nonzero
+ value (the equivalent single-letter option character, if there is
+ one). For long options that have a zero `flag' field, `getopt'
+ returns the contents of the `val' field. */
+
+struct option
+{
+#if __STDC__
+ const char *name;
+#else
+ char *name;
+#endif
+ /* has_arg can't be an enum because some compilers complain about
+ type mismatches in all the code that assumes it is an int. */
+ int has_arg;
+ int *flag;
+ int val;
+};
+
+/* Names for the values of the `has_arg' field of `struct option'. */
+
+#define no_argument 0
+#define required_argument 1
+#define optional_argument 2
+
+#if __STDC__
+#if defined(__GNU_LIBRARY__)
+/* Many other libraries have conflicting prototypes for getopt, with
+ differences in the consts, in stdlib.h. To avoid compilation
+ errors, only prototype getopt for the GNU C library. */
+extern int getopt (int argc, char *const *argv, const char *shortopts);
+#else /* not __GNU_LIBRARY__ */
+extern int getopt ();
+#endif /* not __GNU_LIBRARY__ */
+extern int getopt_long (int argc, char *const *argv, const char *shortopts,
+ const struct option *longopts, int *longind);
+extern int getopt_long_only (int argc, char *const *argv,
+ const char *shortopts,
+ const struct option *longopts, int *longind);
+
+/* Internal only. Users should not call this directly. */
+extern int _getopt_internal (int argc, char *const *argv,
+ const char *shortopts,
+ const struct option *longopts, int *longind,
+ int long_only);
+#else /* not __STDC__ */
+extern int getopt ();
+extern int getopt_long ();
+extern int getopt_long_only ();
+
+extern int _getopt_internal ();
+#endif /* not __STDC__ */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _GETOPT_H */
diff --git a/gnu/usr.bin/grep/getpagesize.h b/gnu/usr.bin/grep/getpagesize.h
new file mode 100644
index 0000000..e6bd561
--- /dev/null
+++ b/gnu/usr.bin/grep/getpagesize.h
@@ -0,0 +1,42 @@
+#ifdef BSD
+#ifndef BSD4_1
+#define HAVE_GETPAGESIZE
+#endif
+#endif
+
+#ifndef HAVE_GETPAGESIZE
+
+#ifdef VMS
+#define getpagesize() 512
+#endif
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#ifdef _SC_PAGESIZE
+#define getpagesize() sysconf(_SC_PAGESIZE)
+#else
+
+#ifdef HAVE_SYS_PARAM_H
+#include <sys/param.h>
+
+#ifdef EXEC_PAGESIZE
+#define getpagesize() EXEC_PAGESIZE
+#else
+#ifdef NBPG
+#define getpagesize() NBPG * CLSIZE
+#ifndef CLSIZE
+#define CLSIZE 1
+#endif /* no CLSIZE */
+#else /* no NBPG */
+#define getpagesize() NBPC
+#endif /* no NBPG */
+#endif /* no EXEC_PAGESIZE */
+#else /* !HAVE_SYS_PARAM_H */
+#define getpagesize() 8192 /* punt totally */
+#endif /* !HAVE_SYS_PARAM_H */
+#endif /* no _SC_PAGESIZE */
+
+#endif /* not HAVE_GETPAGESIZE */
+
diff --git a/gnu/usr.bin/grep/grep.1 b/gnu/usr.bin/grep/grep.1
new file mode 100644
index 0000000..22e96e8
--- /dev/null
+++ b/gnu/usr.bin/grep/grep.1
@@ -0,0 +1,399 @@
+.TH GREP 1 "1992 September 10" "GNU Project"
+.SH NAME
+grep, egrep, fgrep \- print lines matching a pattern
+.SH SYNOPOSIS
+.B grep
+[\-[AB] num]
+[\-HRPS]
+[\-CEFGLVabchilnqsvwx]
+[\-e expr]
+[\-f file]
+files...
+
+.SH DESCRIPTION
+.PP
+.B Grep
+searches the named input
+.I files
+(or standard input if no files are named, or
+the file name
+.B \-
+is given)
+for lines containing a match to the given
+.IR pattern .
+By default,
+.B grep
+prints the matching lines.
+.PP
+There are three major variants of
+.BR grep ,
+controlled by the following options.
+.PD 0
+.TP
+.B \-G
+Interpret
+.I pattern
+as a basic regular expression (see below). This is the default.
+.TP
+.B \-E
+Interpret
+.I pattern
+as an extended regular expression (see below).
+.TP
+.B \-F
+Interpret
+.I pattern
+as a list of fixed strings, separated by newlines,
+any of which is to be matched.
+.LP
+In addition, two variant programs
+.B egrep
+and
+.B fgrep
+are available.
+.B Egrep
+is similiar (but not identical) to
+.BR "grep\ \-E" ,
+and is compatible with the historical Unix
+.BR egrep .
+.B Fgrep
+is the same as
+.BR "grep\ \-F" .
+.PD
+.LP
+All variants of
+.B grep
+understand the following options:
+.PD 0
+.TP
+.BI \- num
+Matches will be printed with
+.I num
+lines of leading and trailing context. However,
+.B grep
+will never print any given line more than once.
+.TP
+.BI \-A " num"
+Print
+.I num
+lines of trailing context after matching lines.
+.TP
+.BI \-B " num"
+Print
+.I num
+lines of leading context before matching lines.
+.TP
+.B \-C
+Equivalent to
+.BR \-2 .
+.TP
+.B \-V
+Print the version number of
+.B grep
+to standard error. This version number should
+be included in all bug reports (see below).
+.TP
+.B \-a
+Don't search in binary files.
+.TP
+.B \-b
+Print the byte offset within the input file before
+each line of output.
+.TP
+.B \-c
+Suppress normal output; instead print a count of
+matching lines for each input file.
+With the
+.B \-v
+option (see below), count non-matching lines.
+.TP
+.BI \-e " pattern"
+Use
+.I pattern
+as the pattern; useful to protect patterns beginning with
+.BR \- .
+.TP
+.BI \-f " file"
+Obtain the pattern from
+.IR file .
+.TP
+.B \-h
+Suppress the prefixing of filenames on output
+when multiple files are searched.
+.TP
+.B \-i
+Ignore case distinctions in both the
+.I pattern
+and the input files.
+.TP
+.B \-L
+Suppress normal output; instead print the name
+of each input file from which no output would
+normally have been printed.
+.TP
+.B \-l
+Suppress normal output; instead print
+the name of each input file from which output
+would normally have been printed.
+.TP
+.B \-n
+Prefix each line of output with the line number
+within its input file.
+.TP
+.B \-q
+Quiet; suppress normal output.
+.TP
+.B \-s
+Suppress error messages about nonexistent or unreadable files.
+.TP
+.B \-v
+Invert the sense of matching, to select non-matching lines.
+.TP
+.B \-w
+Select only those lines containing matches that form whole words.
+The test is that the matching substring must either be at the
+beginning of the line, or preceded by a non-word constituent
+character. Similarly, it must be either at the end of the line
+or followed by a non-word constituent character. Word-constituent
+characters are letters, digits, and the underscore.
+.TP
+.B \-x
+Select only those matches that exactly match the whole line.
+
+.PP
+Following options only avaible if compiled with FTS library:
+.PD 0
+.TP
+.BI \-H
+If the
+.I \-R
+option is specified, symbolic links on the command line
+are followed. (Symbolic links encountered in the tree traversal
+are not followed.)
+.TP
+
+.BI \-L
+If the
+.I \-R
+option is specified, all symbolic links are followed.
+.TP
+
+.BI \-P
+If the
+.I \-R
+option is specified, no symbolic links are followed.
+.TP
+
+.BI \-R
+Search in the file hierarchies
+rooted in the files instead of just the files themselves.
+.TP
+
+.PD
+.SH "REGULAR EXPRESSIONS"
+.PP
+A regular expression is a pattern that describes a set of strings.
+Regular expressions are constructed analagously to arithmetic
+expressions, by using various operators to combine smaller expressions.
+.PP
+.B Grep
+understands two different versions of regular expression syntax:
+``basic'' and ``extended.'' In
+.RB "GNU\ " grep ,
+there is no difference in available functionality using either syntax.
+In other implementations, basic regular expressions are less powerful.
+The following description applies to extended regular expressions;
+differences for basic regular expressions are summarized afterwards.
+.PP
+The fundamental building blocks are the regular expressions that match
+a single character. Most characters, including all letters and digits,
+are regular expressions that match themselves. Any metacharacter with
+special meaning may be quoted by preceding it with a backslash.
+.PP
+A list of characters enclosed by
+.B [
+and
+.B ]
+matches any single
+character in that list; if the first character of the list
+is the caret
+.B ^
+then it matches any character
+.I not
+in the list.
+For example, the regular expression
+.B [0123456789]
+matches any single digit. A range of ASCII characters
+may be specified by giving the first and last characters, separated
+by a hyphen.
+Finally, certain named classes of characters are predefined.
+Their names are self explanatory, and they are
+.BR [:alnum:] ,
+.BR [:alpha:] ,
+.BR [:cntrl:] ,
+.BR [:digit:] ,
+.BR [:graph:] ,
+.BR [:lower:] ,
+.BR [:print:] ,
+.BR [:punct:] ,
+.BR [:space:] ,
+.BR [:upper:] ,
+and
+.BR [:xdigit:].
+For example,
+.B [[:alnum:]]
+means
+.BR [0-9A-Za-z] ,
+except the latter form is dependent upon the ASCII character encoding,
+whereas the former is portable.
+(Note that the brackets in these class names are part of the symbolic
+names, and must be included in addition to the brackets delimiting
+the bracket list.) Most metacharacters lose their special meaning
+inside lists. To include a literal
+.B ]
+place it first in the list. Similarly, to include a literal
+.B ^
+place it anywhere but first. Finally, to include a literal
+.B \-
+place it last.
+.PP
+The period
+.B .
+matches any single character.
+The symbol
+.B \ew
+is a synonym for
+.B [[:alnum:]]
+and
+.B \eW
+is a synonym for
+.BR [^[:alnum]] .
+.PP
+The caret
+.B ^
+and the dollar sign
+.B $
+are metacharacters that respectively match the empty string at the
+beginning and end of a line.
+The symbols
+.B \e<
+and
+.B \e>
+respectively match the empty string at the beginning and end of a word.
+The symbol
+.B \eb
+matches the empty string at the edge of a word,
+and
+.B \eB
+matches the empty string provided it's
+.I not
+at the edge of a word.
+.PP
+A regular expression matching a single character may be followed
+by one of several repetition operators:
+.PD 0
+.TP
+.B ?
+The preceding item is optional and matched at most once.
+.TP
+.B *
+The preceding item will be matched zero or more times.
+.TP
+.B +
+The preceding item will be matched one or more times.
+.TP
+.BI { n }
+The preceding item is matched exactly
+.I n
+times.
+.TP
+.BI { n ,}
+The preceding item is matched
+.I n
+or more times.
+.TP
+.BI {, m }
+The preceding item is optional and is matched at most
+.I m
+times.
+.TP
+.BI { n , m }
+The preceding item is matched at least
+.I n
+times, but not more than
+.I m
+times.
+.PD
+.PP
+Two regular expressions may be concatenated; the resulting
+regular expression matches any string formed by concatenating
+two substrings that respectively match the concatenated
+subexpressions.
+.PP
+Two regular expressions may be joined by the infix operator
+.BR | ;
+the resulting regular expression matches any string matching
+either subexpression.
+.PP
+Repetition takes precedence over concatenation, which in turn
+takes precedence over alternation. A whole subexpression may be
+enclosed in parentheses to override these precedence rules.
+.PP
+The backreference
+.BI \e n\c
+\&, where
+.I n
+is a single digit, matches the substring
+previously matched by the
+.IR n th
+parenthesized subexpression of the regular expression.
+.PP
+In basic regular expressions the metacharacters
+.BR ? ,
+.BR + ,
+.BR { ,
+.BR | ,
+.BR ( ,
+and
+.BR )
+lose their special meaning; instead use the backslashed
+versions
+.BR \e? ,
+.BR \e+ ,
+.BR \e{ ,
+.BR \e| ,
+.BR \e( ,
+and
+.BR \e) .
+.PP
+In
+.B egrep
+the metacharacter
+.B {
+loses its special meaning; instead use
+.BR \e{ .
+.SH DIAGNOSTICS
+.PP
+Normally, exit status is 0 if matches were found,
+and 1 if no matches were found. (The
+.B \-v
+option inverts the sense of the exit status.)
+Exit status is 2 if there were syntax errors
+in the pattern, inaccessible input files, or
+other system errors.
+.SH BUGS
+.PP
+Email bug reports to
+.BR bug-gnu-utils@prep.ai.mit.edu .
+Be sure to include the word ``grep'' somewhere in the ``Subject:'' field.
+.PP
+Large repetition counts in the
+.BI { m , n }
+construct may cause grep to use lots of memory.
+In addition,
+certain other obscure regular expressions require exponential time
+and space, and may cause
+.B grep
+to run out of memory.
+.PP
+Backreferences are very slow, and may require exponential time.
diff --git a/gnu/usr.bin/grep/grep.c b/gnu/usr.bin/grep/grep.c
new file mode 100644
index 0000000..2576e3d
--- /dev/null
+++ b/gnu/usr.bin/grep/grep.c
@@ -0,0 +1,1049 @@
+/* grep.c - main driver file for grep.
+ Copyright (C) 1992 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ Written July 1992 by Mike Haertel. */
+
+#include <errno.h>
+#include <stdio.h>
+#ifdef __FreeBSD__
+#include <locale.h>
+#endif
+
+#ifndef errno
+extern int errno;
+#endif
+
+#ifdef STDC_HEADERS
+#include <stdlib.h>
+#else
+#include <sys/types.h>
+extern char *malloc(), *realloc();
+extern void free();
+#endif
+
+#if defined(STDC_HEADERS) || defined(HAVE_STRING_H)
+#include <string.h>
+#ifdef NEED_MEMORY_H
+#include <memory.h>
+#endif
+#else
+#include <strings.h>
+#ifdef __STDC__
+extern void *memchr();
+#else
+extern char *memchr();
+#endif
+#define strrchr rindex
+#endif
+
+#ifdef HAVE_UNISTD_H
+#include <sys/types.h>
+#include <fcntl.h>
+#include <unistd.h>
+#else
+#define O_RDONLY 0
+#define STDIN_FILENO 0
+extern int open(), read(), close();
+#endif
+
+#include "getpagesize.h"
+#include "grep.h"
+
+#undef MAX
+#define MAX(A,B) ((A) > (B) ? (A) : (B))
+
+/* Provide missing ANSI features if necessary. */
+
+#ifndef HAVE_STRERROR
+extern int sys_nerr;
+extern char *sys_errlist[];
+#define strerror(E) ((E) < sys_nerr ? sys_errlist[(E)] : "bogus error number")
+#endif
+
+#ifndef HAVE_MEMCHR
+#ifdef __STDC__
+#define VOID void
+#else
+#define VOID char
+#endif
+VOID *
+memchr(vp, c, n)
+ VOID *vp;
+ int c;
+ size_t n;
+{
+ unsigned char *p;
+
+ for (p = (unsigned char *) vp; n--; ++p)
+ if (*p == c)
+ return (VOID *) p;
+ return 0;
+}
+#endif
+
+/* traverse a file hierarchy library */
+#ifdef HAVE_FTS
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fts.h>
+#endif
+
+/* don't search in binary files */
+int aflag;
+
+/* Define flags declared in grep.h. */
+char *matcher;
+int match_icase;
+int match_words;
+int match_lines;
+
+/* Functions we'll use to search. */
+static void (*compile)();
+static char *(*execute)();
+
+/* For error messages. */
+static char *prog;
+static char *filename;
+static int errseen;
+
+/* Print a message and possibly an error string. Remember
+ that something awful happened. */
+static void
+error(mesg, errnum)
+#ifdef __STDC__
+ const
+#endif
+ char *mesg;
+ int errnum;
+{
+ if (errnum)
+ fprintf(stderr, "%s: %s: %s\n", prog, mesg, strerror(errnum));
+ else
+ fprintf(stderr, "%s: %s\n", prog, mesg);
+ errseen = 1;
+}
+
+/* Like error(), but die horribly after printing. */
+void
+fatal(mesg, errnum)
+#ifdef __STDC__
+ const
+#endif
+ char *mesg;
+ int errnum;
+{
+ error(mesg, errnum);
+ exit(2);
+}
+
+/* Interface to handle errors and fix library lossage. */
+char *
+xmalloc(size)
+ size_t size;
+{
+ char *result;
+
+ result = malloc(size);
+ if (size && !result)
+ fatal("memory exhausted", 0);
+ return result;
+}
+
+/* Interface to handle errors and fix some library lossage. */
+char *
+xrealloc(ptr, size)
+ char *ptr;
+ size_t size;
+{
+ char *result;
+
+ if (ptr)
+ result = realloc(ptr, size);
+ else
+ result = malloc(size);
+ if (size && !result)
+ fatal("memory exhausted", 0);
+ return result;
+}
+
+#if !defined(HAVE_VALLOC)
+#define valloc malloc
+#else
+#ifdef __STDC__
+extern void *valloc(size_t);
+#else
+extern char *valloc();
+#endif
+#endif
+
+/* Hairy buffering mechanism for grep. The intent is to keep
+ all reads aligned on a page boundary and multiples of the
+ page size. */
+
+static char *buffer; /* Base of buffer. */
+static size_t bufsalloc; /* Allocated size of buffer save region. */
+static size_t bufalloc; /* Total buffer size. */
+static int bufdesc; /* File descriptor. */
+static char *bufbeg; /* Beginning of user-visible stuff. */
+static char *buflim; /* Limit of user-visible stuff. */
+
+#if defined(HAVE_WORKING_MMAP)
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+
+static int bufmapped; /* True for ordinary files. */
+static struct stat bufstat; /* From fstat(). */
+static off_t bufoffset; /* What read() normally remembers. */
+#endif
+
+/* Reset the buffer for a new file. Initialize
+ on the first time through. */
+void
+reset(fd)
+ int fd;
+{
+ static int initialized;
+
+ if (!initialized)
+ {
+ initialized = 1;
+#ifndef BUFSALLOC
+ bufsalloc = MAX(8192, getpagesize());
+#else
+ bufsalloc = BUFSALLOC;
+#endif
+ bufalloc = 5 * bufsalloc;
+ /* The 1 byte of overflow is a kludge for dfaexec(), which
+ inserts a sentinel newline at the end of the buffer
+ being searched. There's gotta be a better way... */
+ buffer = valloc(bufalloc + 1);
+ if (!buffer)
+ fatal("memory exhausted", 0);
+ bufbeg = buffer;
+ buflim = buffer;
+ }
+ bufdesc = fd;
+#if defined(HAVE_WORKING_MMAP)
+ if (fstat(fd, &bufstat) < 0 || !S_ISREG(bufstat.st_mode))
+ bufmapped = 0;
+ else
+ {
+ bufmapped = 1;
+ bufoffset = lseek(fd, 0, 1);
+ }
+#endif
+}
+
+/* Read new stuff into the buffer, saving the specified
+ amount of old stuff. When we're done, 'bufbeg' points
+ to the beginning of the buffer contents, and 'buflim'
+ points just after the end. Return count of new stuff. */
+static int
+fillbuf(save)
+ size_t save;
+{
+ char *nbuffer, *dp, *sp;
+ int cc;
+#if defined(HAVE_WORKING_MMAP)
+ caddr_t maddr;
+#endif
+ static int pagesize;
+
+ if (pagesize == 0 && (pagesize = getpagesize()) == 0)
+ abort();
+
+ if (save > bufsalloc)
+ {
+ while (save > bufsalloc)
+ bufsalloc *= 2;
+ bufalloc = 5 * bufsalloc;
+ nbuffer = valloc(bufalloc + 1);
+ if (!nbuffer)
+ fatal("memory exhausted", 0);
+ }
+ else
+ nbuffer = buffer;
+
+ sp = buflim - save;
+ dp = nbuffer + bufsalloc - save;
+ bufbeg = dp;
+ while (save--)
+ *dp++ = *sp++;
+
+ /* We may have allocated a new, larger buffer. Since
+ there is no portable vfree(), we just have to forget
+ about the old one. Sorry. */
+ buffer = nbuffer;
+
+#if defined(HAVE_WORKING_MMAP)
+ if (bufmapped && bufoffset % pagesize == 0
+ && bufstat.st_size - bufoffset >= bufalloc - bufsalloc)
+ {
+ maddr = buffer + bufsalloc;
+ maddr = mmap(maddr, bufalloc - bufsalloc, PROT_READ | PROT_WRITE,
+ MAP_PRIVATE | MAP_FIXED, bufdesc, bufoffset);
+ if (maddr == (caddr_t) -1)
+ {
+ fprintf(stderr, "%s: warning: %s: %s\n", filename,
+ strerror(errno));
+ goto tryread;
+ }
+#if 0
+ /* You might thing this (or MADV_WILLNEED) would help,
+ but it doesn't, at least not on a Sun running 4.1.
+ In fact, it actually slows us down about 30%! */
+ madvise(maddr, bufalloc - bufsalloc, MADV_SEQUENTIAL);
+#endif
+ cc = bufalloc - bufsalloc;
+ bufoffset += cc;
+ }
+ else
+ {
+ tryread:
+ /* We come here when we're not going to use mmap() any more.
+ Note that we need to synchronize the file offset the
+ first time through. */
+ if (bufmapped)
+ {
+ bufmapped = 0;
+ lseek(bufdesc, bufoffset, 0);
+ }
+ cc = read(bufdesc, buffer + bufsalloc, bufalloc - bufsalloc);
+ }
+#else
+ cc = read(bufdesc, buffer + bufsalloc, bufalloc - bufsalloc);
+#endif
+ if (cc > 0)
+ buflim = buffer + bufsalloc + cc;
+ else
+ buflim = buffer + bufsalloc;
+ return cc;
+}
+
+/* Flags controlling the style of output. */
+static int out_quiet; /* Suppress all normal output. */
+static int out_invert; /* Print nonmatching stuff. */
+static int out_file; /* Print filenames. */
+static int out_line; /* Print line numbers. */
+static int out_byte; /* Print byte offsets. */
+static int out_before; /* Lines of leading context. */
+static int out_after; /* Lines of trailing context. */
+
+/* Internal variables to keep track of byte count, context, etc. */
+static size_t totalcc; /* Total character count before bufbeg. */
+static char *lastnl; /* Pointer after last newline counted. */
+static char *lastout; /* Pointer after last character output;
+ NULL if no character has been output
+ or if it's conceptually before bufbeg. */
+static size_t totalnl; /* Total newline count before lastnl. */
+static int pending; /* Pending lines of output. */
+
+static void
+nlscan(lim)
+ char *lim;
+{
+ char *beg;
+
+ for (beg = lastnl; beg < lim; ++beg)
+ if (*beg == '\n')
+ ++totalnl;
+ lastnl = beg;
+}
+
+static void
+prline(beg, lim, sep)
+ char *beg;
+ char *lim;
+ char sep;
+{
+ if (out_file)
+ printf("%s%c", filename, sep);
+ if (out_line)
+ {
+ nlscan(beg);
+ printf("%d%c", ++totalnl, sep);
+ lastnl = lim;
+ }
+ if (out_byte)
+ printf("%lu%c", totalcc + (beg - bufbeg), sep);
+ fwrite(beg, 1, lim - beg, stdout);
+ if (ferror(stdout))
+ error("writing output", errno);
+ lastout = lim;
+}
+
+/* Print pending lines of trailing context prior to LIM. */
+static void
+prpending(lim)
+ char *lim;
+{
+ char *nl;
+
+ if (!lastout)
+ lastout = bufbeg;
+ while (pending > 0 && lastout < lim)
+ {
+ --pending;
+ if ((nl = memchr(lastout, '\n', lim - lastout)) != 0)
+ ++nl;
+ else
+ nl = lim;
+ prline(lastout, nl, '-');
+ }
+}
+
+/* Print the lines between BEG and LIM. Deal with context crap.
+ If NLINESP is non-null, store a count of lines between BEG and LIM. */
+static void
+prtext(beg, lim, nlinesp)
+ char *beg;
+ char *lim;
+ int *nlinesp;
+{
+ static int used; /* avoid printing "--" before any output */
+ char *bp, *p, *nl;
+ int i, n;
+
+ if (!out_quiet && pending > 0)
+ prpending(beg);
+
+ p = beg;
+
+ if (!out_quiet)
+ {
+ /* Deal with leading context crap. */
+
+ bp = lastout ? lastout : bufbeg;
+ for (i = 0; i < out_before; ++i)
+ if (p > bp)
+ do
+ --p;
+ while (p > bp && p[-1] != '\n');
+
+ /* We only print the "--" separator if our output is
+ discontiguous from the last output in the file. */
+ if ((out_before || out_after) && used && p != lastout)
+ puts("--");
+
+ while (p < beg)
+ {
+ nl = memchr(p, '\n', beg - p);
+ prline(p, nl + 1, '-');
+ p = nl + 1;
+ }
+ }
+
+ if (nlinesp)
+ {
+ /* Caller wants a line count. */
+ for (n = 0; p < lim; ++n)
+ {
+ if ((nl = memchr(p, '\n', lim - p)) != 0)
+ ++nl;
+ else
+ nl = lim;
+ if (!out_quiet)
+ prline(p, nl, ':');
+ p = nl;
+ }
+ *nlinesp = n;
+ }
+ else
+ if (!out_quiet)
+ prline(beg, lim, ':');
+
+ pending = out_after;
+ used = 1;
+}
+
+/* Scan the specified portion of the buffer, matching lines (or
+ between matching lines if OUT_INVERT is true). Return a count of
+ lines printed. */
+static int
+grepbuf(beg, lim)
+ char *beg;
+ char *lim;
+{
+ int nlines, n;
+ register char *p, *b;
+ char *endp;
+
+ nlines = 0;
+ p = beg;
+ while ((b = (*execute)(p, lim - p, &endp)) != 0)
+ {
+ /* Avoid matching the empty line at the end of the buffer. */
+ if (b == lim && ((b > beg && b[-1] == '\n') || b == beg))
+ break;
+ if (!out_invert)
+ {
+ prtext(b, endp, (int *) 0);
+ nlines += 1;
+ }
+ else if (p < b)
+ {
+ prtext(p, b, &n);
+ nlines += n;
+ }
+ p = endp;
+ }
+ if (out_invert && p < lim)
+ {
+ prtext(p, lim, &n);
+ nlines += n;
+ }
+ return nlines;
+}
+
+
+/*
+ * try to guess if fd belong to a binary file
+ */
+
+int isBinaryFile(fd)
+ int fd;
+{
+#define BINARY_BUF_LEN 32
+ static unsigned char buf[BINARY_BUF_LEN];
+ int i, n;
+
+ /* pipe, socket, fifo */
+ if (lseek(fd, (off_t)0, SEEK_SET) == (off_t)-1)
+ return(0);
+
+ if ((n =(int) read(fd, buf, (size_t)BINARY_BUF_LEN)) == -1)
+ return(0);
+
+ /* look for non-printable chars */
+ for(i = 0; i < n; i++)
+ if (!isprint(buf[i]) && !isspace(buf[i]))
+ return(1);
+
+ /* reset fd to begin of file */
+ if (lseek(fd, (off_t)0, SEEK_SET) == (off_t)-1)
+ return(0);
+
+
+ return(0);
+}
+
+
+
+/* Search a given file. Return a count of lines printed. */
+static int
+grep(fd)
+ int fd;
+{
+ int nlines, i;
+ size_t residue, save;
+ char *beg, *lim;
+
+ /* skip binary files */
+ if (aflag && isBinaryFile(fd))
+ return(0);
+
+ reset(fd);
+
+ totalcc = 0;
+ lastout = 0;
+ totalnl = 0;
+ pending = 0;
+
+ nlines = 0;
+ residue = 0;
+ save = 0;
+
+ for (;;)
+ {
+ if (fillbuf(save) < 0)
+ {
+ error(filename, errno);
+ return nlines;
+ }
+ lastnl = bufbeg;
+ if (lastout)
+ lastout = bufbeg;
+ if (buflim - bufbeg == save)
+ break;
+ beg = bufbeg + save - residue;
+ for (lim = buflim; lim > beg && lim[-1] != '\n'; --lim)
+ ;
+ residue = buflim - lim;
+ if (beg < lim)
+ {
+ nlines += grepbuf(beg, lim);
+ if (pending)
+ prpending(lim);
+ }
+ i = 0;
+ beg = lim;
+ while (i < out_before && beg > bufbeg && beg != lastout)
+ {
+ ++i;
+ do
+ --beg;
+ while (beg > bufbeg && beg[-1] != '\n');
+ }
+ if (beg != lastout)
+ lastout = 0;
+ save = residue + lim - beg;
+ totalcc += buflim - bufbeg - save;
+ if (out_line)
+ nlscan(beg);
+ }
+ if (residue)
+ {
+ nlines += grepbuf(bufbeg + save - residue, buflim);
+ if (pending)
+ prpending(buflim);
+ }
+ return nlines;
+}
+
+static char version[] = "GNU grep version 2.0";
+
+#ifdef HAVE_FTS
+#define USAGE \
+"usage: %s [-[AB] <num>] [-HRPS] [-CEFGLVabchilnqsvwx]\n\
+ [-e <expr>] [-f file] [files ...]\n"
+#else
+#define USAGE \
+"usage: %s [-[AB] <num>] [-CEFGLVabchilnqsvwx]\n\
+ [-e <expr>] [-f file] [files ...]\n"
+#endif
+
+static void
+usage()
+{
+ fprintf(stderr, USAGE, prog);
+ exit(2);
+}
+
+/* Go through the matchers vector and look for the specified matcher.
+ If we find it, install it in compile and execute, and return 1. */
+int
+setmatcher(name)
+ char *name;
+{
+ int i;
+
+ for (i = 0; matchers[i].name; ++i)
+ if (strcmp(name, matchers[i].name) == 0)
+ {
+ compile = matchers[i].compile;
+ execute = matchers[i].execute;
+ return 1;
+ }
+ return 0;
+}
+
+int
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ char *keys;
+ size_t keycc, oldcc, keyalloc;
+ int keyfound, count_matches, no_filenames, list_files, suppress_errors;
+ int opt, cc, desc, count, status;
+ FILE *fp;
+ extern char *optarg;
+ extern int optind;
+#ifdef HAVE_FTS
+ int Rflag, Hflag, Pflag, Lflag;
+ FTS *ftsp;
+ FTSENT *ftsent;
+ int fts_options;
+#endif
+
+#ifdef __FreeBSD__
+ (void) setlocale(LC_CTYPE, "");
+#endif
+ prog = argv[0];
+ if (prog && strrchr(prog, '/'))
+ prog = strrchr(prog, '/') + 1;
+
+ keys = NULL;
+ keycc = 0;
+ keyfound = 0;
+ count_matches = 0;
+ no_filenames = 0;
+ list_files = 0;
+ suppress_errors = 0;
+ matcher = NULL;
+ aflag = 0;
+#ifdef HAVE_FTS
+ Rflag = Hflag = Pflag = Lflag = 0;
+#endif
+
+ while ((opt = getopt(argc, argv,
+
+#ifndef HAVE_FTS
+"0123456789A:B:CEFGVX:abce:f:hiLlnqsvwxy"
+#else
+"0123456789A:B:CEFGHLPRSVX:abce:f:hiLlnqsvwxy?"
+#endif
+
+)) != EOF)
+ switch (opt)
+ {
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ out_before = 10 * out_before + opt - '0';
+ out_after = 10 * out_after + opt - '0';
+ break;
+ case 'A':
+ out_after = atoi(optarg);
+ if (out_after < 0)
+ usage();
+ break;
+ case 'B':
+ out_before = atoi(optarg);
+ if (out_before < 0)
+ usage();
+ break;
+ case 'C':
+ out_before = out_after = 2;
+ break;
+ case 'E':
+ if (matcher && strcmp(matcher, "egrep") != 0)
+ fatal("you may specify only one of -E, -F, or -G", 0);
+ matcher = "posix-egrep";
+ break;
+ case 'F':
+ if (matcher && strcmp(matcher, "fgrep") != 0)
+ fatal("you may specify only one of -E, -F, or -G", 0);;
+ matcher = "fgrep";
+ break;
+ case 'G':
+ if (matcher && strcmp(matcher, "grep") != 0)
+ fatal("you may specify only one of -E, -F, or -G", 0);
+ matcher = "grep";
+ break;
+ case 'V':
+ fprintf(stderr, "%s\n", version);
+ break;
+ case 'X':
+ if (matcher)
+ fatal("matcher already specified", 0);
+ matcher = optarg;
+ break;
+
+#ifdef HAVE_FTS
+ /* symbolic links on the command line are followed */
+ case 'H':
+ Hflag = 1;
+ Lflag = Pflag = 0;
+ break;
+
+ /* no symbolic links are followed */
+ case 'P':
+ Pflag = 1;
+ Hflag = Lflag = 0;
+ break;
+
+ /* traverse file hierarchies */
+ case 'R':
+ Rflag = 1;
+ break;
+
+ /* all symbolic links are followed */
+ case 'S':
+ Lflag = 1;
+ Hflag = Pflag = 0;
+ break;
+#endif
+ case 'a':
+ aflag = 1;
+ break;
+ case 'b':
+ out_byte = 1;
+ break;
+ case 'c':
+ out_quiet = 1;
+ count_matches = 1;
+ break;
+ case 'e':
+ cc = strlen(optarg);
+ keys = xrealloc(keys, keycc + cc + 1);
+ if (keyfound)
+ keys[keycc++] = '\n';
+ strcpy(&keys[keycc], optarg);
+ keycc += cc;
+ keyfound = 1;
+ break;
+ case 'f':
+ fp = strcmp(optarg, "-") != 0 ? fopen(optarg, "r") : stdin;
+ if (!fp)
+ fatal(optarg, errno);
+ for (keyalloc = 1; keyalloc <= keycc; keyalloc *= 2)
+ ;
+ keys = xrealloc(keys, keyalloc);
+ oldcc = keycc;
+ if (keyfound)
+ keys[keycc++] = '\n';
+ while (!feof(fp)
+ && (cc = fread(keys + keycc, 1, keyalloc - keycc, fp)) > 0)
+ {
+ keycc += cc;
+ if (keycc == keyalloc)
+ keys = xrealloc(keys, keyalloc *= 2);
+ }
+ if (fp != stdin)
+ fclose(fp);
+ /* Nuke the final newline to avoid matching a null string. */
+ if (keycc - oldcc > 0 && keys[keycc - 1] == '\n')
+ --keycc;
+ keyfound = 1;
+ break;
+ case 'h':
+ no_filenames = 1;
+ break;
+ case 'i':
+ case 'y': /* For old-timers . . . */
+ match_icase = 1;
+ break;
+ case 'L':
+ /* Like -l, except list files that don't contain matches.
+ Inspired by the same option in Hume's gre. */
+ out_quiet = 1;
+ list_files = -1;
+ break;
+ case 'l':
+ out_quiet = 1;
+ list_files = 1;
+ break;
+ case 'n':
+ out_line = 1;
+ break;
+ case 'q':
+ out_quiet = 1;
+ break;
+ case 's':
+ suppress_errors = 1;
+ break;
+ case 'v':
+ out_invert = 1;
+ break;
+ case 'w':
+ match_words = 1;
+ break;
+ case 'x':
+ match_lines = 1;
+ break;
+ default:
+ usage();
+ break;
+ }
+
+ if (!keyfound)
+ if (optind < argc)
+ {
+ keys = argv[optind++];
+ keycc = strlen(keys);
+ }
+ else
+ usage();
+
+ if (!matcher)
+ matcher = prog;
+
+ if (!setmatcher(matcher) && !setmatcher("default"))
+ abort();
+
+ (*compile)(keys, keycc);
+
+#ifndef HAVE_FTS
+ if (argc - optind > 1 && !no_filenames)
+#else
+ if ((argc - optind > 1 || Rflag) && !no_filenames)
+#endif
+ out_file = 1;
+
+ status = 1;
+
+#if HAVE_FTS
+ if (Rflag) {
+ fts_options = FTS_PHYSICAL | FTS_NOCHDIR;
+
+ if (Hflag)
+ fts_options |= FTS_COMFOLLOW;
+
+ if (Lflag) {
+ fts_options |= FTS_LOGICAL;
+ fts_options &= ~FTS_PHYSICAL;
+ }
+
+ if (Pflag) {
+ fts_options &= ~FTS_LOGICAL & ~FTS_COMFOLLOW;
+ fts_options |= FTS_PHYSICAL;
+ }
+ }
+
+ if (Rflag && optind < argc) {
+ int i;
+
+ /* replace "-" with "/dev/stdin" */
+ for (i = optind; i < argc; i++)
+ if (strcmp(argv[i], "-") == 0)
+ *(argv + i) = "/dev/stdin";
+
+ if ((ftsp = fts_open(argv + optind, fts_options,
+ (int(*)())NULL)) == NULL) {
+ if (!suppress_errors)
+ error("", errno);
+ } else {
+
+ while((ftsent = fts_read(ftsp)) != NULL) {
+ filename = ftsent->fts_accpath;
+
+ switch(ftsent->fts_info) {
+
+ /* regular file */
+ case FTS_F:
+ break;
+
+ /* directory */
+ case FTS_D:
+ case FTS_DC:
+ case FTS_DP:
+ continue; break;
+
+ /* errors */
+ case FTS_DNR:
+ error(filename, errno);
+ continue; break;
+
+ case FTS_ERR:
+ case FTS_NS:
+ error(filename, ftsent->fts_errno);
+ continue; break;
+
+ /* dead symlink */
+ case FTS_SLNONE:
+ continue; break;
+
+ /* symlink, don't skip */
+ case FTS_SL:
+ break;
+
+ default:
+ /*
+ if (!suppress_errors)
+ fprintf(stderr, "%s: ignored\n", filename);
+ continue; break;
+ */
+
+ }
+
+ if ((desc = open(filename, O_RDONLY)) == -1) {
+ error(filename, errno);
+ continue;
+ }
+
+ count = grep(desc);
+ if (count_matches)
+ {
+ if (out_file)
+ printf("%s:", filename);
+ printf("%d\n", count);
+ }
+ if (count)
+ {
+ status = 0;
+ if (list_files == 1)
+ printf("%s\n", filename);
+ }
+ else if (list_files == -1)
+ printf("%s\n", filename);
+
+ if (desc != STDIN_FILENO)
+ close(desc);
+ }
+
+ if (fts_close(ftsp) == -1)
+ error("fts_close", errno);
+ }
+
+ /* ! Rflag */
+ } else
+
+#endif /* HAVE_FTS */
+
+ /* search in file names from arguments, not from stdin */
+ if (optind < argc)
+
+ while (optind < argc)
+ {
+ desc = strcmp(argv[optind], "-") ? open(argv[optind], O_RDONLY) : 0;
+ if (desc < 0)
+ {
+ if (!suppress_errors)
+ error(argv[optind], errno);
+ }
+ else
+ {
+ filename = desc == 0 ? "(standard input)" : argv[optind];
+ count = grep(desc);
+ if (count_matches)
+ {
+ if (out_file)
+ printf("%s:", filename);
+ printf("%d\n", count);
+ }
+ if (count)
+ {
+ status = 0;
+ if (list_files == 1)
+ printf("%s\n", filename);
+ }
+ else if (list_files == -1)
+ printf("%s\n", filename);
+ }
+ if (desc != 0)
+ close(desc);
+ ++optind;
+ }
+
+ /* read input from stdin */
+ else
+ {
+ filename = "(standard input)";
+ count = grep(0);
+ if (count_matches)
+ printf("%d\n", count);
+ if (count)
+ {
+ status = 0;
+ if (list_files == 1)
+ printf("(standard input)\n");
+ }
+ else if (list_files == -1)
+ printf("(standard input)\n");
+ }
+
+ exit(errseen ? 2 : status);
+}
diff --git a/gnu/usr.bin/grep/grep.h b/gnu/usr.bin/grep/grep.h
new file mode 100644
index 0000000..a3316c5
--- /dev/null
+++ b/gnu/usr.bin/grep/grep.h
@@ -0,0 +1,53 @@
+/* grep.h - interface to grep driver for searching subroutines.
+ Copyright (C) 1992 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#if __STDC__
+
+extern void fatal(const char *, int);
+
+/* Grep.c expects the matchers vector to be terminated
+ by an entry with a NULL name, and to contain at least
+ an entry named "default". */
+
+extern struct matcher
+{
+ char *name;
+ void (*compile)(char *, size_t);
+ char *(*execute)(char *, size_t, char **);
+} matchers[];
+
+#else
+
+extern void fatal();
+
+extern struct matcher
+{
+ char *name;
+ void (*compile)();
+ char *(*execute)();
+} matchers[];
+
+#endif
+
+/* Exported from grep.c. */
+extern char *matcher;
+
+/* The following flags are exported from grep for the matchers
+ to look at. */
+extern int match_icase; /* -i */
+extern int match_words; /* -w */
+extern int match_lines; /* -x */
diff --git a/gnu/usr.bin/grep/kwset.c b/gnu/usr.bin/grep/kwset.c
new file mode 100644
index 0000000..afbeb64
--- /dev/null
+++ b/gnu/usr.bin/grep/kwset.c
@@ -0,0 +1,805 @@
+/* kwset.c - search for any of a set of keywords.
+ Copyright 1989 Free Software Foundation
+ Written August 1989 by Mike Haertel.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 1, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ The author may be reached (Email) at the address mike@ai.mit.edu,
+ or (US mail) as Mike Haertel c/o Free Software Foundation. */
+
+/* The algorithm implemented by these routines bears a startling resemblence
+ to one discovered by Beate Commentz-Walter, although it is not identical.
+ See "A String Matching Algorithm Fast on the Average," Technical Report,
+ IBM-Germany, Scientific Center Heidelberg, Tiergartenstrasse 15, D-6900
+ Heidelberg, Germany. See also Aho, A.V., and M. Corasick, "Efficient
+ String Matching: An Aid to Bibliographic Search," CACM June 1975,
+ Vol. 18, No. 6, which describes the failure function used below. */
+
+
+#ifdef STDC_HEADERS
+#include <limits.h>
+#include <stdlib.h>
+#else
+#define INT_MAX 2147483647
+#define UCHAR_MAX 255
+#ifdef __STDC__
+#include <stddef.h>
+#else
+#include <sys/types.h>
+#endif
+extern char *malloc();
+extern void free();
+#endif
+
+#ifdef HAVE_MEMCHR
+#include <string.h>
+#ifdef NEED_MEMORY_H
+#include <memory.h>
+#endif
+#else
+#ifdef __STDC__
+extern void *memchr();
+#else
+extern char *memchr();
+#endif
+#endif
+
+#ifdef GREP
+extern char *xmalloc();
+#define malloc xmalloc
+#endif
+
+#include "kwset.h"
+#include "obstack.h"
+
+#define NCHAR (UCHAR_MAX + 1)
+#define obstack_chunk_alloc malloc
+#define obstack_chunk_free free
+
+/* Balanced tree of edges and labels leaving a given trie node. */
+struct tree
+{
+ struct tree *llink; /* Left link; MUST be first field. */
+ struct tree *rlink; /* Right link (to larger labels). */
+ struct trie *trie; /* Trie node pointed to by this edge. */
+ unsigned char label; /* Label on this edge. */
+ char balance; /* Difference in depths of subtrees. */
+};
+
+/* Node of a trie representing a set of reversed keywords. */
+struct trie
+{
+ unsigned int accepting; /* Word index of accepted word, or zero. */
+ struct tree *links; /* Tree of edges leaving this node. */
+ struct trie *parent; /* Parent of this node. */
+ struct trie *next; /* List of all trie nodes in level order. */
+ struct trie *fail; /* Aho-Corasick failure function. */
+ int depth; /* Depth of this node from the root. */
+ int shift; /* Shift function for search failures. */
+ int maxshift; /* Max shift of self and descendents. */
+};
+
+/* Structure returned opaquely to the caller, containing everything. */
+struct kwset
+{
+ struct obstack obstack; /* Obstack for node allocation. */
+ int words; /* Number of words in the trie. */
+ struct trie *trie; /* The trie itself. */
+ int mind; /* Minimum depth of an accepting node. */
+ int maxd; /* Maximum depth of any node. */
+ unsigned char delta[NCHAR]; /* Delta table for rapid search. */
+ struct trie *next[NCHAR]; /* Table of children of the root. */
+ char *target; /* Target string if there's only one. */
+ int mind2; /* Used in Boyer-Moore search for one string. */
+ char *trans; /* Character translation table. */
+};
+
+/* Allocate and initialize a keyword set object, returning an opaque
+ pointer to it. Return NULL if memory is not available. */
+kwset_t
+kwsalloc(trans)
+ char *trans;
+{
+ struct kwset *kwset;
+
+ kwset = (struct kwset *) malloc(sizeof (struct kwset));
+ if (!kwset)
+ return 0;
+
+ obstack_init(&kwset->obstack);
+ kwset->words = 0;
+ kwset->trie
+ = (struct trie *) obstack_alloc(&kwset->obstack, sizeof (struct trie));
+ if (!kwset->trie)
+ {
+ kwsfree((kwset_t) kwset);
+ return 0;
+ }
+ kwset->trie->accepting = 0;
+ kwset->trie->links = 0;
+ kwset->trie->parent = 0;
+ kwset->trie->next = 0;
+ kwset->trie->fail = 0;
+ kwset->trie->depth = 0;
+ kwset->trie->shift = 0;
+ kwset->mind = INT_MAX;
+ kwset->maxd = -1;
+ kwset->target = 0;
+ kwset->trans = trans;
+
+ return (kwset_t) kwset;
+}
+
+/* Add the given string to the contents of the keyword set. Return NULL
+ for success, an error message otherwise. */
+char *
+kwsincr(kws, text, len)
+ kwset_t kws;
+ char *text;
+ size_t len;
+{
+ struct kwset *kwset;
+ register struct trie *trie;
+ register unsigned char label;
+ register struct tree *link;
+ register int depth;
+ struct tree *links[12];
+ enum { L, R } dirs[12];
+ struct tree *t, *r, *l, *rl, *lr;
+
+ kwset = (struct kwset *) kws;
+ trie = kwset->trie;
+ text += len;
+
+ /* Descend the trie (built of reversed keywords) character-by-character,
+ installing new nodes when necessary. */
+ while (len--)
+ {
+ label = kwset->trans ? kwset->trans[(unsigned char) *--text] : *--text;
+
+ /* Descend the tree of outgoing links for this trie node,
+ looking for the current character and keeping track
+ of the path followed. */
+ link = trie->links;
+ links[0] = (struct tree *) &trie->links;
+ dirs[0] = L;
+ depth = 1;
+
+ while (link && label != link->label)
+ {
+ links[depth] = link;
+ if (label < link->label)
+ dirs[depth++] = L, link = link->llink;
+ else
+ dirs[depth++] = R, link = link->rlink;
+ }
+
+ /* The current character doesn't have an outgoing link at
+ this trie node, so build a new trie node and install
+ a link in the current trie node's tree. */
+ if (!link)
+ {
+ link = (struct tree *) obstack_alloc(&kwset->obstack,
+ sizeof (struct tree));
+ if (!link)
+ return "memory exhausted";
+ link->llink = 0;
+ link->rlink = 0;
+ link->trie = (struct trie *) obstack_alloc(&kwset->obstack,
+ sizeof (struct trie));
+ if (!link->trie)
+ return "memory exhausted";
+ link->trie->accepting = 0;
+ link->trie->links = 0;
+ link->trie->parent = trie;
+ link->trie->next = 0;
+ link->trie->fail = 0;
+ link->trie->depth = trie->depth + 1;
+ link->trie->shift = 0;
+ link->label = label;
+ link->balance = 0;
+
+ /* Install the new tree node in its parent. */
+ if (dirs[--depth] == L)
+ links[depth]->llink = link;
+ else
+ links[depth]->rlink = link;
+
+ /* Back up the tree fixing the balance flags. */
+ while (depth && !links[depth]->balance)
+ {
+ if (dirs[depth] == L)
+ --links[depth]->balance;
+ else
+ ++links[depth]->balance;
+ --depth;
+ }
+
+ /* Rebalance the tree by pointer rotations if necessary. */
+ if (depth && ((dirs[depth] == L && --links[depth]->balance)
+ || (dirs[depth] == R && ++links[depth]->balance)))
+ {
+ switch (links[depth]->balance)
+ {
+ case (char) -2:
+ switch (dirs[depth + 1])
+ {
+ case L:
+ r = links[depth], t = r->llink, rl = t->rlink;
+ t->rlink = r, r->llink = rl;
+ t->balance = r->balance = 0;
+ break;
+ case R:
+ r = links[depth], l = r->llink, t = l->rlink;
+ rl = t->rlink, lr = t->llink;
+ t->llink = l, l->rlink = lr, t->rlink = r, r->llink = rl;
+ l->balance = t->balance != 1 ? 0 : -1;
+ r->balance = t->balance != (char) -1 ? 0 : 1;
+ t->balance = 0;
+ break;
+ }
+ break;
+ case 2:
+ switch (dirs[depth + 1])
+ {
+ case R:
+ l = links[depth], t = l->rlink, lr = t->llink;
+ t->llink = l, l->rlink = lr;
+ t->balance = l->balance = 0;
+ break;
+ case L:
+ l = links[depth], r = l->rlink, t = r->llink;
+ lr = t->llink, rl = t->rlink;
+ t->llink = l, l->rlink = lr, t->rlink = r, r->llink = rl;
+ l->balance = t->balance != 1 ? 0 : -1;
+ r->balance = t->balance != (char) -1 ? 0 : 1;
+ t->balance = 0;
+ break;
+ }
+ break;
+ }
+
+ if (dirs[depth - 1] == L)
+ links[depth - 1]->llink = t;
+ else
+ links[depth - 1]->rlink = t;
+ }
+ }
+
+ trie = link->trie;
+ }
+
+ /* Mark the node we finally reached as accepting, encoding the
+ index number of this word in the keyword set so far. */
+ if (!trie->accepting)
+ trie->accepting = 1 + 2 * kwset->words;
+ ++kwset->words;
+
+ /* Keep track of the longest and shortest string of the keyword set. */
+ if (trie->depth < kwset->mind)
+ kwset->mind = trie->depth;
+ if (trie->depth > kwset->maxd)
+ kwset->maxd = trie->depth;
+
+ return 0;
+}
+
+/* Enqueue the trie nodes referenced from the given tree in the
+ given queue. */
+static void
+enqueue(tree, last)
+ struct tree *tree;
+ struct trie **last;
+{
+ if (!tree)
+ return;
+ enqueue(tree->llink, last);
+ enqueue(tree->rlink, last);
+ (*last) = (*last)->next = tree->trie;
+}
+
+/* Compute the Aho-Corasick failure function for the trie nodes referenced
+ from the given tree, given the failure function for their parent as
+ well as a last resort failure node. */
+static void
+treefails(tree, fail, recourse)
+ register struct tree *tree;
+ struct trie *fail;
+ struct trie *recourse;
+{
+ register struct tree *link;
+
+ if (!tree)
+ return;
+
+ treefails(tree->llink, fail, recourse);
+ treefails(tree->rlink, fail, recourse);
+
+ /* Find, in the chain of fails going back to the root, the first
+ node that has a descendent on the current label. */
+ while (fail)
+ {
+ link = fail->links;
+ while (link && tree->label != link->label)
+ if (tree->label < link->label)
+ link = link->llink;
+ else
+ link = link->rlink;
+ if (link)
+ {
+ tree->trie->fail = link->trie;
+ return;
+ }
+ fail = fail->fail;
+ }
+
+ tree->trie->fail = recourse;
+}
+
+/* Set delta entries for the links of the given tree such that
+ the preexisting delta value is larger than the current depth. */
+static void
+treedelta(tree, depth, delta)
+ register struct tree *tree;
+ register unsigned int depth;
+ unsigned char delta[];
+{
+ if (!tree)
+ return;
+ treedelta(tree->llink, depth, delta);
+ treedelta(tree->rlink, depth, delta);
+ if (depth < delta[tree->label])
+ delta[tree->label] = depth;
+}
+
+/* Return true if A has every label in B. */
+static int
+hasevery(a, b)
+ register struct tree *a;
+ register struct tree *b;
+{
+ if (!b)
+ return 1;
+ if (!hasevery(a, b->llink))
+ return 0;
+ if (!hasevery(a, b->rlink))
+ return 0;
+ while (a && b->label != a->label)
+ if (b->label < a->label)
+ a = a->llink;
+ else
+ a = a->rlink;
+ return !!a;
+}
+
+/* Compute a vector, indexed by character code, of the trie nodes
+ referenced from the given tree. */
+static void
+treenext(tree, next)
+ struct tree *tree;
+ struct trie *next[];
+{
+ if (!tree)
+ return;
+ treenext(tree->llink, next);
+ treenext(tree->rlink, next);
+ next[tree->label] = tree->trie;
+}
+
+/* Compute the shift for each trie node, as well as the delta
+ table and next cache for the given keyword set. */
+char *
+kwsprep(kws)
+ kwset_t kws;
+{
+ register struct kwset *kwset;
+ register int i;
+ register struct trie *curr, *fail;
+ register char *trans;
+ unsigned char delta[NCHAR];
+ struct trie *last, *next[NCHAR];
+
+ kwset = (struct kwset *) kws;
+
+ /* Initial values for the delta table; will be changed later. The
+ delta entry for a given character is the smallest depth of any
+ node at which an outgoing edge is labeled by that character. */
+ if (kwset->mind < 256)
+ for (i = 0; i < NCHAR; ++i)
+ delta[i] = kwset->mind;
+ else
+ for (i = 0; i < NCHAR; ++i)
+ delta[i] = 255;
+
+ /* Check if we can use the simple boyer-moore algorithm, instead
+ of the hairy commentz-walter algorithm. */
+ if (kwset->words == 1 && kwset->trans == 0)
+ {
+ /* Looking for just one string. Extract it from the trie. */
+ kwset->target = obstack_alloc(&kwset->obstack, kwset->mind);
+ for (i = kwset->mind - 1, curr = kwset->trie; i >= 0; --i)
+ {
+ kwset->target[i] = curr->links->label;
+ curr = curr->links->trie;
+ }
+ /* Build the Boyer Moore delta. Boy that's easy compared to CW. */
+ for (i = 0; i < kwset->mind; ++i)
+ delta[(unsigned char) kwset->target[i]] = kwset->mind - (i + 1);
+ kwset->mind2 = kwset->mind;
+ /* Find the minimal delta2 shift that we might make after
+ a backwards match has failed. */
+ for (i = 0; i < kwset->mind - 1; ++i)
+ if (kwset->target[i] == kwset->target[kwset->mind - 1])
+ kwset->mind2 = kwset->mind - (i + 1);
+ }
+ else
+ {
+ /* Traverse the nodes of the trie in level order, simultaneously
+ computing the delta table, failure function, and shift function. */
+ for (curr = last = kwset->trie; curr; curr = curr->next)
+ {
+ /* Enqueue the immediate descendents in the level order queue. */
+ enqueue(curr->links, &last);
+
+ curr->shift = kwset->mind;
+ curr->maxshift = kwset->mind;
+
+ /* Update the delta table for the descendents of this node. */
+ treedelta(curr->links, curr->depth, delta);
+
+ /* Compute the failure function for the decendents of this node. */
+ treefails(curr->links, curr->fail, kwset->trie);
+
+ /* Update the shifts at each node in the current node's chain
+ of fails back to the root. */
+ for (fail = curr->fail; fail; fail = fail->fail)
+ {
+ /* If the current node has some outgoing edge that the fail
+ doesn't, then the shift at the fail should be no larger
+ than the difference of their depths. */
+ if (!hasevery(fail->links, curr->links))
+ if (curr->depth - fail->depth < fail->shift)
+ fail->shift = curr->depth - fail->depth;
+
+ /* If the current node is accepting then the shift at the
+ fail and its descendents should be no larger than the
+ difference of their depths. */
+ if (curr->accepting && fail->maxshift > curr->depth - fail->depth)
+ fail->maxshift = curr->depth - fail->depth;
+ }
+ }
+
+ /* Traverse the trie in level order again, fixing up all nodes whose
+ shift exceeds their inherited maxshift. */
+ for (curr = kwset->trie->next; curr; curr = curr->next)
+ {
+ if (curr->maxshift > curr->parent->maxshift)
+ curr->maxshift = curr->parent->maxshift;
+ if (curr->shift > curr->maxshift)
+ curr->shift = curr->maxshift;
+ }
+
+ /* Create a vector, indexed by character code, of the outgoing links
+ from the root node. */
+ for (i = 0; i < NCHAR; ++i)
+ next[i] = 0;
+ treenext(kwset->trie->links, next);
+
+ if ((trans = kwset->trans) != 0)
+ for (i = 0; i < NCHAR; ++i)
+ kwset->next[i] = next[(unsigned char) trans[i]];
+ else
+ for (i = 0; i < NCHAR; ++i)
+ kwset->next[i] = next[i];
+ }
+
+ /* Fix things up for any translation table. */
+ if ((trans = kwset->trans) != 0)
+ for (i = 0; i < NCHAR; ++i)
+ kwset->delta[i] = delta[(unsigned char) trans[i]];
+ else
+ for (i = 0; i < NCHAR; ++i)
+ kwset->delta[i] = delta[i];
+
+ return 0;
+}
+
+#define U(C) ((unsigned char) (C))
+
+/* Fast boyer-moore search. */
+static char *
+bmexec(kws, text, size)
+ kwset_t kws;
+ char *text;
+ size_t size;
+{
+ struct kwset *kwset;
+ register unsigned char *d1;
+ register char *ep, *sp, *tp;
+ register int d, gc, i, len, md2;
+
+ kwset = (struct kwset *) kws;
+ len = kwset->mind;
+
+ if (len == 0)
+ return text;
+ if (len > size)
+ return 0;
+ if (len == 1)
+ return memchr(text, kwset->target[0], size);
+
+ d1 = kwset->delta;
+ sp = kwset->target + len;
+ gc = U(sp[-2]);
+ md2 = kwset->mind2;
+ tp = text + len;
+
+ /* Significance of 12: 1 (initial offset) + 10 (skip loop) + 1 (md2). */
+ if (size > 12 * len)
+ /* 11 is not a bug, the initial offset happens only once. */
+ for (ep = text + size - 11 * len;;)
+ {
+ while (tp <= ep)
+ {
+ d = d1[U(tp[-1])], tp += d;
+ d = d1[U(tp[-1])], tp += d;
+ if (d == 0)
+ goto found;
+ d = d1[U(tp[-1])], tp += d;
+ d = d1[U(tp[-1])], tp += d;
+ d = d1[U(tp[-1])], tp += d;
+ if (d == 0)
+ goto found;
+ d = d1[U(tp[-1])], tp += d;
+ d = d1[U(tp[-1])], tp += d;
+ d = d1[U(tp[-1])], tp += d;
+ if (d == 0)
+ goto found;
+ d = d1[U(tp[-1])], tp += d;
+ d = d1[U(tp[-1])], tp += d;
+ }
+ break;
+ found:
+ if (U(tp[-2]) == gc)
+ {
+ for (i = 3; i <= len && U(tp[-i]) == U(sp[-i]); ++i)
+ ;
+ if (i > len)
+ return tp - len;
+ }
+ tp += md2;
+ }
+
+ /* Now we have only a few characters left to search. We
+ carefully avoid ever producing an out-of-bounds pointer. */
+ ep = text + size;
+ d = d1[U(tp[-1])];
+ while (d <= ep - tp)
+ {
+ d = d1[U((tp += d)[-1])];
+ if (d != 0)
+ continue;
+ if (tp[-2] == gc)
+ {
+ for (i = 3; i <= len && U(tp[-i]) == U(sp[-i]); ++i)
+ ;
+ if (i > len)
+ return tp - len;
+ }
+ d = md2;
+ }
+
+ return 0;
+}
+
+/* Hairy multiple string search. */
+static char *
+cwexec(kws, text, len, kwsmatch)
+ kwset_t kws;
+ char *text;
+ size_t len;
+ struct kwsmatch *kwsmatch;
+{
+ struct kwset *kwset;
+ struct trie **next, *trie, *accept;
+ char *beg, *lim, *mch, *lmch;
+ register unsigned char c, *delta;
+ register int d;
+ register char *end, *qlim;
+ register struct tree *tree;
+ register char *trans;
+
+ /* Initialize register copies and look for easy ways out. */
+ kwset = (struct kwset *) kws;
+ if (len < kwset->mind)
+ return 0;
+ next = kwset->next;
+ delta = kwset->delta;
+ trans = kwset->trans;
+ lim = text + len;
+ end = text;
+ if ((d = kwset->mind) != 0)
+ mch = 0;
+ else
+ {
+ mch = text, accept = kwset->trie;
+ goto match;
+ }
+
+ if (len >= 4 * kwset->mind)
+ qlim = lim - 4 * kwset->mind;
+ else
+ qlim = 0;
+
+ while (lim - end >= d)
+ {
+ if (qlim && end <= qlim)
+ {
+ end += d - 1;
+ while ((d = delta[c = *end]) && end < qlim)
+ {
+ end += d;
+ end += delta[(unsigned char) *end];
+ end += delta[(unsigned char) *end];
+ }
+ ++end;
+ }
+ else
+ d = delta[c = (end += d)[-1]];
+ if (d)
+ continue;
+ beg = end - 1;
+ trie = next[c];
+ if (trie->accepting)
+ {
+ mch = beg;
+ accept = trie;
+ }
+ d = trie->shift;
+ while (beg > text)
+ {
+ c = trans ? trans[(unsigned char) *--beg] : *--beg;
+ tree = trie->links;
+ while (tree && c != tree->label)
+ if (c < tree->label)
+ tree = tree->llink;
+ else
+ tree = tree->rlink;
+ if (tree)
+ {
+ trie = tree->trie;
+ if (trie->accepting)
+ {
+ mch = beg;
+ accept = trie;
+ }
+ }
+ else
+ break;
+ d = trie->shift;
+ }
+ if (mch)
+ goto match;
+ }
+ return 0;
+
+ match:
+ /* Given a known match, find the longest possible match anchored
+ at or before its starting point. This is nearly a verbatim
+ copy of the preceding main search loops. */
+ if (lim - mch > kwset->maxd)
+ lim = mch + kwset->maxd;
+ lmch = 0;
+ d = 1;
+ while (lim - end >= d)
+ {
+ if ((d = delta[c = (end += d)[-1]]) != 0)
+ continue;
+ beg = end - 1;
+ if (!(trie = next[c]))
+ {
+ d = 1;
+ continue;
+ }
+ if (trie->accepting && beg <= mch)
+ {
+ lmch = beg;
+ accept = trie;
+ }
+ d = trie->shift;
+ while (beg > text)
+ {
+ c = trans ? trans[(unsigned char) *--beg] : *--beg;
+ tree = trie->links;
+ while (tree && c != tree->label)
+ if (c < tree->label)
+ tree = tree->llink;
+ else
+ tree = tree->rlink;
+ if (tree)
+ {
+ trie = tree->trie;
+ if (trie->accepting && beg <= mch)
+ {
+ lmch = beg;
+ accept = trie;
+ }
+ }
+ else
+ break;
+ d = trie->shift;
+ }
+ if (lmch)
+ {
+ mch = lmch;
+ goto match;
+ }
+ if (!d)
+ d = 1;
+ }
+
+ if (kwsmatch)
+ {
+ kwsmatch->index = accept->accepting / 2;
+ kwsmatch->beg[0] = mch;
+ kwsmatch->size[0] = accept->depth;
+ }
+ return mch;
+}
+
+/* Search through the given text for a match of any member of the
+ given keyword set. Return a pointer to the first character of
+ the matching substring, or NULL if no match is found. If FOUNDLEN
+ is non-NULL store in the referenced location the length of the
+ matching substring. Similarly, if FOUNDIDX is non-NULL, store
+ in the referenced location the index number of the particular
+ keyword matched. */
+char *
+kwsexec(kws, text, size, kwsmatch)
+ kwset_t kws;
+ char *text;
+ size_t size;
+ struct kwsmatch *kwsmatch;
+{
+ struct kwset *kwset;
+ char *ret;
+
+ kwset = (struct kwset *) kws;
+ if (kwset->words == 1 && kwset->trans == 0)
+ {
+ ret = bmexec(kws, text, size);
+ if (kwsmatch != 0 && ret != 0)
+ {
+ kwsmatch->index = 0;
+ kwsmatch->beg[0] = ret;
+ kwsmatch->size[0] = kwset->mind;
+ }
+ return ret;
+ }
+ else
+ return cwexec(kws, text, size, kwsmatch);
+}
+
+/* Free the components of the given keyword set. */
+void
+kwsfree(kws)
+ kwset_t kws;
+{
+ struct kwset *kwset;
+
+ kwset = (struct kwset *) kws;
+ obstack_free(&kwset->obstack, 0);
+ free(kws);
+}
diff --git a/gnu/usr.bin/grep/kwset.h b/gnu/usr.bin/grep/kwset.h
new file mode 100644
index 0000000..95f62e7
--- /dev/null
+++ b/gnu/usr.bin/grep/kwset.h
@@ -0,0 +1,69 @@
+/* kwset.h - header declaring the keyword set library.
+ Copyright 1989 Free Software Foundation
+ Written August 1989 by Mike Haertel.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 1, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ The author may be reached (Email) at the address mike@ai.mit.edu,
+ or (US mail) as Mike Haertel c/o Free Software Foundation. */
+
+struct kwsmatch
+{
+ int index; /* Index number of matching keyword. */
+ char *beg[1]; /* Begin pointer for each submatch. */
+ size_t size[1]; /* Length of each submatch. */
+};
+
+#if __STDC__
+
+typedef void *kwset_t;
+
+/* Return an opaque pointer to a newly allocated keyword set, or NULL
+ if enough memory cannot be obtained. The argument if non-NULL
+ specifies a table of character translations to be applied to all
+ pattern and search text. */
+extern kwset_t kwsalloc(char *);
+
+/* Incrementally extend the keyword set to include the given string.
+ Return NULL for success, or an error message. Remember an index
+ number for each keyword included in the set. */
+extern char *kwsincr(kwset_t, char *, size_t);
+
+/* When the keyword set has been completely built, prepare it for
+ use. Return NULL for success, or an error message. */
+extern char *kwsprep(kwset_t);
+
+/* Search through the given buffer for a member of the keyword set.
+ Return a pointer to the leftmost longest match found, or NULL if
+ no match is found. If foundlen is non-NULL, store the length of
+ the matching substring in the integer it points to. Similarly,
+ if foundindex is non-NULL, store the index of the particular
+ keyword found therein. */
+extern char *kwsexec(kwset_t, char *, size_t, struct kwsmatch *);
+
+/* Deallocate the given keyword set and all its associated storage. */
+extern void kwsfree(kwset_t);
+
+#else
+
+typedef char *kwset_t;
+
+extern kwset_t kwsalloc();
+extern char *kwsincr();
+extern char *kwsprep();
+extern char *kwsexec();
+extern void kwsfree();
+
+#endif
diff --git a/gnu/usr.bin/grep/obstack.c b/gnu/usr.bin/grep/obstack.c
new file mode 100644
index 0000000..7b9d3b9
--- /dev/null
+++ b/gnu/usr.bin/grep/obstack.c
@@ -0,0 +1,454 @@
+/* obstack.c - subroutines used implicitly by object stack macros
+ Copyright (C) 1988, 1993 Free Software Foundation, Inc.
+
+This program is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 2, or (at your option) any
+later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "obstack.h"
+
+/* This is just to get __GNU_LIBRARY__ defined. */
+#include <stdio.h>
+
+/* Comment out all this code if we are using the GNU C Library, and are not
+ actually compiling the library itself. This code is part of the GNU C
+ Library, but also included in many other GNU distributions. Compiling
+ and linking in this code is a waste when using the GNU C library
+ (especially if it is a shared library). Rather than having every GNU
+ program understand `configure --with-gnu-libc' and omit the object files,
+ it is simpler to just do this in the source for each such file. */
+
+#if defined (_LIBC) || !defined (__GNU_LIBRARY__)
+
+
+#ifdef __STDC__
+#define POINTER void *
+#else
+#define POINTER char *
+#endif
+
+/* Determine default alignment. */
+struct fooalign {char x; double d;};
+#define DEFAULT_ALIGNMENT \
+ ((PTR_INT_TYPE) ((char *)&((struct fooalign *) 0)->d - (char *)0))
+/* If malloc were really smart, it would round addresses to DEFAULT_ALIGNMENT.
+ But in fact it might be less smart and round addresses to as much as
+ DEFAULT_ROUNDING. So we prepare for it to do that. */
+union fooround {long x; double d;};
+#define DEFAULT_ROUNDING (sizeof (union fooround))
+
+/* When we copy a long block of data, this is the unit to do it with.
+ On some machines, copying successive ints does not work;
+ in such a case, redefine COPYING_UNIT to `long' (if that works)
+ or `char' as a last resort. */
+#ifndef COPYING_UNIT
+#define COPYING_UNIT int
+#endif
+
+/* The non-GNU-C macros copy the obstack into this global variable
+ to avoid multiple evaluation. */
+
+struct obstack *_obstack;
+
+/* Define a macro that either calls functions with the traditional malloc/free
+ calling interface, or calls functions with the mmalloc/mfree interface
+ (that adds an extra first argument), based on the state of use_extra_arg.
+ For free, do not use ?:, since some compilers, like the MIPS compilers,
+ do not allow (expr) ? void : void. */
+
+#define CALL_CHUNKFUN(h, size) \
+ (((h) -> use_extra_arg) \
+ ? (*(h)->chunkfun) ((h)->extra_arg, (size)) \
+ : (*(h)->chunkfun) ((size)))
+
+#define CALL_FREEFUN(h, old_chunk) \
+ do { \
+ if ((h) -> use_extra_arg) \
+ (*(h)->freefun) ((h)->extra_arg, (old_chunk)); \
+ else \
+ (*(h)->freefun) ((old_chunk)); \
+ } while (0)
+
+
+/* Initialize an obstack H for use. Specify chunk size SIZE (0 means default).
+ Objects start on multiples of ALIGNMENT (0 means use default).
+ CHUNKFUN is the function to use to allocate chunks,
+ and FREEFUN the function to free them. */
+
+void
+_obstack_begin (h, size, alignment, chunkfun, freefun)
+ struct obstack *h;
+ int size;
+ int alignment;
+ POINTER (*chunkfun) ();
+ void (*freefun) ();
+{
+ register struct _obstack_chunk* chunk; /* points to new chunk */
+
+ if (alignment == 0)
+ alignment = DEFAULT_ALIGNMENT;
+ if (size == 0)
+ /* Default size is what GNU malloc can fit in a 4096-byte block. */
+ {
+ /* 12 is sizeof (mhead) and 4 is EXTRA from GNU malloc.
+ Use the values for range checking, because if range checking is off,
+ the extra bytes won't be missed terribly, but if range checking is on
+ and we used a larger request, a whole extra 4096 bytes would be
+ allocated.
+
+ These number are irrelevant to the new GNU malloc. I suspect it is
+ less sensitive to the size of the request. */
+ int extra = ((((12 + DEFAULT_ROUNDING - 1) & ~(DEFAULT_ROUNDING - 1))
+ + 4 + DEFAULT_ROUNDING - 1)
+ & ~(DEFAULT_ROUNDING - 1));
+ size = 4096 - extra;
+ }
+
+ h->chunkfun = (struct _obstack_chunk * (*)()) chunkfun;
+ h->freefun = freefun;
+ h->chunk_size = size;
+ h->alignment_mask = alignment - 1;
+ h->use_extra_arg = 0;
+
+ chunk = h->chunk = CALL_CHUNKFUN (h, h -> chunk_size);
+ h->next_free = h->object_base = chunk->contents;
+ h->chunk_limit = chunk->limit
+ = (char *) chunk + h->chunk_size;
+ chunk->prev = 0;
+ /* The initial chunk now contains no empty object. */
+ h->maybe_empty_object = 0;
+}
+
+void
+_obstack_begin_1 (h, size, alignment, chunkfun, freefun, arg)
+ struct obstack *h;
+ int size;
+ int alignment;
+ POINTER (*chunkfun) ();
+ void (*freefun) ();
+ POINTER arg;
+{
+ register struct _obstack_chunk* chunk; /* points to new chunk */
+
+ if (alignment == 0)
+ alignment = DEFAULT_ALIGNMENT;
+ if (size == 0)
+ /* Default size is what GNU malloc can fit in a 4096-byte block. */
+ {
+ /* 12 is sizeof (mhead) and 4 is EXTRA from GNU malloc.
+ Use the values for range checking, because if range checking is off,
+ the extra bytes won't be missed terribly, but if range checking is on
+ and we used a larger request, a whole extra 4096 bytes would be
+ allocated.
+
+ These number are irrelevant to the new GNU malloc. I suspect it is
+ less sensitive to the size of the request. */
+ int extra = ((((12 + DEFAULT_ROUNDING - 1) & ~(DEFAULT_ROUNDING - 1))
+ + 4 + DEFAULT_ROUNDING - 1)
+ & ~(DEFAULT_ROUNDING - 1));
+ size = 4096 - extra;
+ }
+
+ h->chunkfun = (struct _obstack_chunk * (*)()) chunkfun;
+ h->freefun = freefun;
+ h->chunk_size = size;
+ h->alignment_mask = alignment - 1;
+ h->extra_arg = arg;
+ h->use_extra_arg = 1;
+
+ chunk = h->chunk = CALL_CHUNKFUN (h, h -> chunk_size);
+ h->next_free = h->object_base = chunk->contents;
+ h->chunk_limit = chunk->limit
+ = (char *) chunk + h->chunk_size;
+ chunk->prev = 0;
+ /* The initial chunk now contains no empty object. */
+ h->maybe_empty_object = 0;
+}
+
+/* Allocate a new current chunk for the obstack *H
+ on the assumption that LENGTH bytes need to be added
+ to the current object, or a new object of length LENGTH allocated.
+ Copies any partial object from the end of the old chunk
+ to the beginning of the new one. */
+
+void
+_obstack_newchunk (h, length)
+ struct obstack *h;
+ int length;
+{
+ register struct _obstack_chunk* old_chunk = h->chunk;
+ register struct _obstack_chunk* new_chunk;
+ register long new_size;
+ register int obj_size = h->next_free - h->object_base;
+ register int i;
+ int already;
+
+ /* Compute size for new chunk. */
+ new_size = (obj_size + length) + (obj_size >> 3) + 100;
+ if (new_size < h->chunk_size)
+ new_size = h->chunk_size;
+
+ /* Allocate and initialize the new chunk. */
+ new_chunk = h->chunk = CALL_CHUNKFUN (h, new_size);
+ new_chunk->prev = old_chunk;
+ new_chunk->limit = h->chunk_limit = (char *) new_chunk + new_size;
+
+ /* Move the existing object to the new chunk.
+ Word at a time is fast and is safe if the object
+ is sufficiently aligned. */
+ if (h->alignment_mask + 1 >= DEFAULT_ALIGNMENT)
+ {
+ for (i = obj_size / sizeof (COPYING_UNIT) - 1;
+ i >= 0; i--)
+ ((COPYING_UNIT *)new_chunk->contents)[i]
+ = ((COPYING_UNIT *)h->object_base)[i];
+ /* We used to copy the odd few remaining bytes as one extra COPYING_UNIT,
+ but that can cross a page boundary on a machine
+ which does not do strict alignment for COPYING_UNITS. */
+ already = obj_size / sizeof (COPYING_UNIT) * sizeof (COPYING_UNIT);
+ }
+ else
+ already = 0;
+ /* Copy remaining bytes one by one. */
+ for (i = already; i < obj_size; i++)
+ new_chunk->contents[i] = h->object_base[i];
+
+ /* If the object just copied was the only data in OLD_CHUNK,
+ free that chunk and remove it from the chain.
+ But not if that chunk might contain an empty object. */
+ if (h->object_base == old_chunk->contents && ! h->maybe_empty_object)
+ {
+ new_chunk->prev = old_chunk->prev;
+ CALL_FREEFUN (h, old_chunk);
+ }
+
+ h->object_base = new_chunk->contents;
+ h->next_free = h->object_base + obj_size;
+ /* The new chunk certainly contains no empty object yet. */
+ h->maybe_empty_object = 0;
+}
+
+/* Return nonzero if object OBJ has been allocated from obstack H.
+ This is here for debugging.
+ If you use it in a program, you are probably losing. */
+
+int
+_obstack_allocated_p (h, obj)
+ struct obstack *h;
+ POINTER obj;
+{
+ register struct _obstack_chunk* lp; /* below addr of any objects in this chunk */
+ register struct _obstack_chunk* plp; /* point to previous chunk if any */
+
+ lp = (h)->chunk;
+ /* We use >= rather than > since the object cannot be exactly at
+ the beginning of the chunk but might be an empty object exactly
+ at the end of an adjacent chunk. */
+ while (lp != 0 && ((POINTER)lp >= obj || (POINTER)(lp)->limit < obj))
+ {
+ plp = lp->prev;
+ lp = plp;
+ }
+ return lp != 0;
+}
+
+/* Free objects in obstack H, including OBJ and everything allocate
+ more recently than OBJ. If OBJ is zero, free everything in H. */
+
+#undef obstack_free
+
+/* This function has two names with identical definitions.
+ This is the first one, called from non-ANSI code. */
+
+void
+_obstack_free (h, obj)
+ struct obstack *h;
+ POINTER obj;
+{
+ register struct _obstack_chunk* lp; /* below addr of any objects in this chunk */
+ register struct _obstack_chunk* plp; /* point to previous chunk if any */
+
+ lp = h->chunk;
+ /* We use >= because there cannot be an object at the beginning of a chunk.
+ But there can be an empty object at that address
+ at the end of another chunk. */
+ while (lp != 0 && ((POINTER)lp >= obj || (POINTER)(lp)->limit < obj))
+ {
+ plp = lp->prev;
+ CALL_FREEFUN (h, lp);
+ lp = plp;
+ /* If we switch chunks, we can't tell whether the new current
+ chunk contains an empty object, so assume that it may. */
+ h->maybe_empty_object = 1;
+ }
+ if (lp)
+ {
+ h->object_base = h->next_free = (char *)(obj);
+ h->chunk_limit = lp->limit;
+ h->chunk = lp;
+ }
+ else if (obj != 0)
+ /* obj is not in any of the chunks! */
+ abort ();
+}
+
+/* This function is used from ANSI code. */
+
+void
+obstack_free (h, obj)
+ struct obstack *h;
+ POINTER obj;
+{
+ register struct _obstack_chunk* lp; /* below addr of any objects in this chunk */
+ register struct _obstack_chunk* plp; /* point to previous chunk if any */
+
+ lp = h->chunk;
+ /* We use >= because there cannot be an object at the beginning of a chunk.
+ But there can be an empty object at that address
+ at the end of another chunk. */
+ while (lp != 0 && ((POINTER)lp >= obj || (POINTER)(lp)->limit < obj))
+ {
+ plp = lp->prev;
+ CALL_FREEFUN (h, lp);
+ lp = plp;
+ /* If we switch chunks, we can't tell whether the new current
+ chunk contains an empty object, so assume that it may. */
+ h->maybe_empty_object = 1;
+ }
+ if (lp)
+ {
+ h->object_base = h->next_free = (char *)(obj);
+ h->chunk_limit = lp->limit;
+ h->chunk = lp;
+ }
+ else if (obj != 0)
+ /* obj is not in any of the chunks! */
+ abort ();
+}
+
+#if 0
+/* These are now turned off because the applications do not use it
+ and it uses bcopy via obstack_grow, which causes trouble on sysV. */
+
+/* Now define the functional versions of the obstack macros.
+ Define them to simply use the corresponding macros to do the job. */
+
+#ifdef __STDC__
+/* These function definitions do not work with non-ANSI preprocessors;
+ they won't pass through the macro names in parentheses. */
+
+/* The function names appear in parentheses in order to prevent
+ the macro-definitions of the names from being expanded there. */
+
+POINTER (obstack_base) (obstack)
+ struct obstack *obstack;
+{
+ return obstack_base (obstack);
+}
+
+POINTER (obstack_next_free) (obstack)
+ struct obstack *obstack;
+{
+ return obstack_next_free (obstack);
+}
+
+int (obstack_object_size) (obstack)
+ struct obstack *obstack;
+{
+ return obstack_object_size (obstack);
+}
+
+int (obstack_room) (obstack)
+ struct obstack *obstack;
+{
+ return obstack_room (obstack);
+}
+
+void (obstack_grow) (obstack, pointer, length)
+ struct obstack *obstack;
+ POINTER pointer;
+ int length;
+{
+ obstack_grow (obstack, pointer, length);
+}
+
+void (obstack_grow0) (obstack, pointer, length)
+ struct obstack *obstack;
+ POINTER pointer;
+ int length;
+{
+ obstack_grow0 (obstack, pointer, length);
+}
+
+void (obstack_1grow) (obstack, character)
+ struct obstack *obstack;
+ int character;
+{
+ obstack_1grow (obstack, character);
+}
+
+void (obstack_blank) (obstack, length)
+ struct obstack *obstack;
+ int length;
+{
+ obstack_blank (obstack, length);
+}
+
+void (obstack_1grow_fast) (obstack, character)
+ struct obstack *obstack;
+ int character;
+{
+ obstack_1grow_fast (obstack, character);
+}
+
+void (obstack_blank_fast) (obstack, length)
+ struct obstack *obstack;
+ int length;
+{
+ obstack_blank_fast (obstack, length);
+}
+
+POINTER (obstack_finish) (obstack)
+ struct obstack *obstack;
+{
+ return obstack_finish (obstack);
+}
+
+POINTER (obstack_alloc) (obstack, length)
+ struct obstack *obstack;
+ int length;
+{
+ return obstack_alloc (obstack, length);
+}
+
+POINTER (obstack_copy) (obstack, pointer, length)
+ struct obstack *obstack;
+ POINTER pointer;
+ int length;
+{
+ return obstack_copy (obstack, pointer, length);
+}
+
+POINTER (obstack_copy0) (obstack, pointer, length)
+ struct obstack *obstack;
+ POINTER pointer;
+ int length;
+{
+ return obstack_copy0 (obstack, pointer, length);
+}
+
+#endif /* __STDC__ */
+
+#endif /* 0 */
+
+#endif /* _LIBC or not __GNU_LIBRARY__. */
diff --git a/gnu/usr.bin/grep/obstack.h b/gnu/usr.bin/grep/obstack.h
new file mode 100644
index 0000000..09d2c32
--- /dev/null
+++ b/gnu/usr.bin/grep/obstack.h
@@ -0,0 +1,484 @@
+/* obstack.h - object stack macros
+ Copyright (C) 1988, 1992 Free Software Foundation, Inc.
+
+This program is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 2, or (at your option) any
+later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* Summary:
+
+All the apparent functions defined here are macros. The idea
+is that you would use these pre-tested macros to solve a
+very specific set of problems, and they would run fast.
+Caution: no side-effects in arguments please!! They may be
+evaluated MANY times!!
+
+These macros operate a stack of objects. Each object starts life
+small, and may grow to maturity. (Consider building a word syllable
+by syllable.) An object can move while it is growing. Once it has
+been "finished" it never changes address again. So the "top of the
+stack" is typically an immature growing object, while the rest of the
+stack is of mature, fixed size and fixed address objects.
+
+These routines grab large chunks of memory, using a function you
+supply, called `obstack_chunk_alloc'. On occasion, they free chunks,
+by calling `obstack_chunk_free'. You must define them and declare
+them before using any obstack macros.
+
+Each independent stack is represented by a `struct obstack'.
+Each of the obstack macros expects a pointer to such a structure
+as the first argument.
+
+One motivation for this package is the problem of growing char strings
+in symbol tables. Unless you are "fascist pig with a read-only mind"
+--Gosper's immortal quote from HAKMEM item 154, out of context--you
+would not like to put any arbitrary upper limit on the length of your
+symbols.
+
+In practice this often means you will build many short symbols and a
+few long symbols. At the time you are reading a symbol you don't know
+how long it is. One traditional method is to read a symbol into a
+buffer, realloc()ating the buffer every time you try to read a symbol
+that is longer than the buffer. This is beaut, but you still will
+want to copy the symbol from the buffer to a more permanent
+symbol-table entry say about half the time.
+
+With obstacks, you can work differently. Use one obstack for all symbol
+names. As you read a symbol, grow the name in the obstack gradually.
+When the name is complete, finalize it. Then, if the symbol exists already,
+free the newly read name.
+
+The way we do this is to take a large chunk, allocating memory from
+low addresses. When you want to build a symbol in the chunk you just
+add chars above the current "high water mark" in the chunk. When you
+have finished adding chars, because you got to the end of the symbol,
+you know how long the chars are, and you can create a new object.
+Mostly the chars will not burst over the highest address of the chunk,
+because you would typically expect a chunk to be (say) 100 times as
+long as an average object.
+
+In case that isn't clear, when we have enough chars to make up
+the object, THEY ARE ALREADY CONTIGUOUS IN THE CHUNK (guaranteed)
+so we just point to it where it lies. No moving of chars is
+needed and this is the second win: potentially long strings need
+never be explicitly shuffled. Once an object is formed, it does not
+change its address during its lifetime.
+
+When the chars burst over a chunk boundary, we allocate a larger
+chunk, and then copy the partly formed object from the end of the old
+chunk to the beginning of the new larger chunk. We then carry on
+accreting characters to the end of the object as we normally would.
+
+A special macro is provided to add a single char at a time to a
+growing object. This allows the use of register variables, which
+break the ordinary 'growth' macro.
+
+Summary:
+ We allocate large chunks.
+ We carve out one object at a time from the current chunk.
+ Once carved, an object never moves.
+ We are free to append data of any size to the currently
+ growing object.
+ Exactly one object is growing in an obstack at any one time.
+ You can run one obstack per control block.
+ You may have as many control blocks as you dare.
+ Because of the way we do it, you can `unwind' an obstack
+ back to a previous state. (You may remove objects much
+ as you would with a stack.)
+*/
+
+
+/* Don't do the contents of this file more than once. */
+
+#ifndef __OBSTACKS__
+#define __OBSTACKS__
+
+/* We use subtraction of (char *)0 instead of casting to int
+ because on word-addressable machines a simple cast to int
+ may ignore the byte-within-word field of the pointer. */
+
+#ifndef __PTR_TO_INT
+#define __PTR_TO_INT(P) ((P) - (char *)0)
+#endif
+
+#ifndef __INT_TO_PTR
+#define __INT_TO_PTR(P) ((P) + (char *)0)
+#endif
+
+/* We need the type of the resulting object. In ANSI C it is ptrdiff_t
+ but in traditional C it is usually long. If we are in ANSI C and
+ don't already have ptrdiff_t get it. */
+
+#if defined (__STDC__) && ! defined (offsetof)
+#if defined (__GNUC__) && defined (IN_GCC)
+/* On Next machine, the system's stddef.h screws up if included
+ after we have defined just ptrdiff_t, so include all of gstddef.h.
+ Otherwise, define just ptrdiff_t, which is all we need. */
+#ifndef __NeXT__
+#define __need_ptrdiff_t
+#endif
+
+/* While building GCC, the stddef.h that goes with GCC has this name. */
+#include "gstddef.h"
+#else
+#include <stddef.h>
+#endif
+#endif
+
+#ifdef __STDC__
+#define PTR_INT_TYPE ptrdiff_t
+#else
+#define PTR_INT_TYPE long
+#endif
+
+struct _obstack_chunk /* Lives at front of each chunk. */
+{
+ char *limit; /* 1 past end of this chunk */
+ struct _obstack_chunk *prev; /* address of prior chunk or NULL */
+ char contents[4]; /* objects begin here */
+};
+
+struct obstack /* control current object in current chunk */
+{
+ long chunk_size; /* preferred size to allocate chunks in */
+ struct _obstack_chunk* chunk; /* address of current struct obstack_chunk */
+ char *object_base; /* address of object we are building */
+ char *next_free; /* where to add next char to current object */
+ char *chunk_limit; /* address of char after current chunk */
+ PTR_INT_TYPE temp; /* Temporary for some macros. */
+ int alignment_mask; /* Mask of alignment for each object. */
+ struct _obstack_chunk *(*chunkfun) (); /* User's fcn to allocate a chunk. */
+ void (*freefun) (); /* User's function to free a chunk. */
+ char *extra_arg; /* first arg for chunk alloc/dealloc funcs */
+ unsigned use_extra_arg:1; /* chunk alloc/dealloc funcs take extra arg */
+ unsigned maybe_empty_object:1;/* There is a possibility that the current
+ chunk contains a zero-length object. This
+ prevents freeing the chunk if we allocate
+ a bigger chunk to replace it. */
+};
+
+/* Declare the external functions we use; they are in obstack.c. */
+
+#ifdef __STDC__
+extern void _obstack_newchunk (struct obstack *, int);
+extern void _obstack_free (struct obstack *, void *);
+extern void _obstack_begin (struct obstack *, int, int,
+ void *(*) (), void (*) ());
+extern void _obstack_begin_1 (struct obstack *, int, int,
+ void *(*) (), void (*) (), void *);
+#else
+extern void _obstack_newchunk ();
+extern void _obstack_free ();
+extern void _obstack_begin ();
+extern void _obstack_begin_1 ();
+#endif
+
+#ifdef __STDC__
+
+/* Do the function-declarations after the structs
+ but before defining the macros. */
+
+void obstack_init (struct obstack *obstack);
+
+void * obstack_alloc (struct obstack *obstack, int size);
+
+void * obstack_copy (struct obstack *obstack, void *address, int size);
+void * obstack_copy0 (struct obstack *obstack, void *address, int size);
+
+void obstack_free (struct obstack *obstack, void *block);
+
+void obstack_blank (struct obstack *obstack, int size);
+
+void obstack_grow (struct obstack *obstack, void *data, int size);
+void obstack_grow0 (struct obstack *obstack, void *data, int size);
+
+void obstack_1grow (struct obstack *obstack, int data_char);
+void obstack_ptr_grow (struct obstack *obstack, void *data);
+void obstack_int_grow (struct obstack *obstack, int data);
+
+void * obstack_finish (struct obstack *obstack);
+
+int obstack_object_size (struct obstack *obstack);
+
+int obstack_room (struct obstack *obstack);
+void obstack_1grow_fast (struct obstack *obstack, int data_char);
+void obstack_ptr_grow_fast (struct obstack *obstack, void *data);
+void obstack_int_grow_fast (struct obstack *obstack, int data);
+void obstack_blank_fast (struct obstack *obstack, int size);
+
+void * obstack_base (struct obstack *obstack);
+void * obstack_next_free (struct obstack *obstack);
+int obstack_alignment_mask (struct obstack *obstack);
+int obstack_chunk_size (struct obstack *obstack);
+
+#endif /* __STDC__ */
+
+/* Non-ANSI C cannot really support alternative functions for these macros,
+ so we do not declare them. */
+
+/* Pointer to beginning of object being allocated or to be allocated next.
+ Note that this might not be the final address of the object
+ because a new chunk might be needed to hold the final size. */
+
+#define obstack_base(h) ((h)->object_base)
+
+/* Size for allocating ordinary chunks. */
+
+#define obstack_chunk_size(h) ((h)->chunk_size)
+
+/* Pointer to next byte not yet allocated in current chunk. */
+
+#define obstack_next_free(h) ((h)->next_free)
+
+/* Mask specifying low bits that should be clear in address of an object. */
+
+#define obstack_alignment_mask(h) ((h)->alignment_mask)
+
+#define obstack_init(h) \
+ _obstack_begin ((h), 0, 0, \
+ (void *(*) ()) obstack_chunk_alloc, (void (*) ()) obstack_chunk_free)
+
+#define obstack_begin(h, size) \
+ _obstack_begin ((h), (size), 0, \
+ (void *(*) ()) obstack_chunk_alloc, (void (*) ()) obstack_chunk_free)
+
+#define obstack_specify_allocation(h, size, alignment, chunkfun, freefun) \
+ _obstack_begin ((h), (size), (alignment), \
+ (void *(*) ()) (chunkfun), (void (*) ()) (freefun))
+
+#define obstack_specify_allocation_with_arg(h, size, alignment, chunkfun, freefun, arg) \
+ _obstack_begin_1 ((h), (size), (alignment), \
+ (void *(*) ()) (chunkfun), (void (*) ()) (freefun), (arg))
+
+#define obstack_1grow_fast(h,achar) (*((h)->next_free)++ = achar)
+
+#define obstack_blank_fast(h,n) ((h)->next_free += (n))
+
+#if defined (__GNUC__) && defined (__STDC__)
+#if __GNUC__ < 2 || defined(NeXT)
+#define __extension__
+#endif
+
+/* For GNU C, if not -traditional,
+ we can define these macros to compute all args only once
+ without using a global variable.
+ Also, we can avoid using the `temp' slot, to make faster code. */
+
+#define obstack_object_size(OBSTACK) \
+ __extension__ \
+ ({ struct obstack *__o = (OBSTACK); \
+ (unsigned) (__o->next_free - __o->object_base); })
+
+#define obstack_room(OBSTACK) \
+ __extension__ \
+ ({ struct obstack *__o = (OBSTACK); \
+ (unsigned) (__o->chunk_limit - __o->next_free); })
+
+/* Note that the call to _obstack_newchunk is enclosed in (..., 0)
+ so that we can avoid having void expressions
+ in the arms of the conditional expression.
+ Casting the third operand to void was tried before,
+ but some compilers won't accept it. */
+#define obstack_grow(OBSTACK,where,length) \
+__extension__ \
+({ struct obstack *__o = (OBSTACK); \
+ int __len = (length); \
+ ((__o->next_free + __len > __o->chunk_limit) \
+ ? (_obstack_newchunk (__o, __len), 0) : 0); \
+ bcopy (where, __o->next_free, __len); \
+ __o->next_free += __len; \
+ (void) 0; })
+
+#define obstack_grow0(OBSTACK,where,length) \
+__extension__ \
+({ struct obstack *__o = (OBSTACK); \
+ int __len = (length); \
+ ((__o->next_free + __len + 1 > __o->chunk_limit) \
+ ? (_obstack_newchunk (__o, __len + 1), 0) : 0), \
+ bcopy (where, __o->next_free, __len), \
+ __o->next_free += __len, \
+ *(__o->next_free)++ = 0; \
+ (void) 0; })
+
+#define obstack_1grow(OBSTACK,datum) \
+__extension__ \
+({ struct obstack *__o = (OBSTACK); \
+ ((__o->next_free + 1 > __o->chunk_limit) \
+ ? (_obstack_newchunk (__o, 1), 0) : 0), \
+ *(__o->next_free)++ = (datum); \
+ (void) 0; })
+
+/* These assume that the obstack alignment is good enough for pointers or ints,
+ and that the data added so far to the current object
+ shares that much alignment. */
+
+#define obstack_ptr_grow(OBSTACK,datum) \
+__extension__ \
+({ struct obstack *__o = (OBSTACK); \
+ ((__o->next_free + sizeof (void *) > __o->chunk_limit) \
+ ? (_obstack_newchunk (__o, sizeof (void *)), 0) : 0), \
+ *((void **)__o->next_free)++ = ((void *)datum); \
+ (void) 0; })
+
+#define obstack_int_grow(OBSTACK,datum) \
+__extension__ \
+({ struct obstack *__o = (OBSTACK); \
+ ((__o->next_free + sizeof (int) > __o->chunk_limit) \
+ ? (_obstack_newchunk (__o, sizeof (int)), 0) : 0), \
+ *((int *)__o->next_free)++ = ((int)datum); \
+ (void) 0; })
+
+#define obstack_ptr_grow_fast(h,aptr) (*((void **)(h)->next_free)++ = (void *)aptr)
+#define obstack_int_grow_fast(h,aint) (*((int *)(h)->next_free)++ = (int)aint)
+
+#define obstack_blank(OBSTACK,length) \
+__extension__ \
+({ struct obstack *__o = (OBSTACK); \
+ int __len = (length); \
+ ((__o->chunk_limit - __o->next_free < __len) \
+ ? (_obstack_newchunk (__o, __len), 0) : 0); \
+ __o->next_free += __len; \
+ (void) 0; })
+
+#define obstack_alloc(OBSTACK,length) \
+__extension__ \
+({ struct obstack *__h = (OBSTACK); \
+ obstack_blank (__h, (length)); \
+ obstack_finish (__h); })
+
+#define obstack_copy(OBSTACK,where,length) \
+__extension__ \
+({ struct obstack *__h = (OBSTACK); \
+ obstack_grow (__h, (where), (length)); \
+ obstack_finish (__h); })
+
+#define obstack_copy0(OBSTACK,where,length) \
+__extension__ \
+({ struct obstack *__h = (OBSTACK); \
+ obstack_grow0 (__h, (where), (length)); \
+ obstack_finish (__h); })
+
+/* The local variable is named __o1 to avoid a name conflict
+ when obstack_blank is called. */
+#define obstack_finish(OBSTACK) \
+__extension__ \
+({ struct obstack *__o1 = (OBSTACK); \
+ void *value = (void *) __o1->object_base; \
+ if (__o1->next_free == value) \
+ __o1->maybe_empty_object = 1; \
+ __o1->next_free \
+ = __INT_TO_PTR ((__PTR_TO_INT (__o1->next_free)+__o1->alignment_mask)\
+ & ~ (__o1->alignment_mask)); \
+ ((__o1->next_free - (char *)__o1->chunk \
+ > __o1->chunk_limit - (char *)__o1->chunk) \
+ ? (__o1->next_free = __o1->chunk_limit) : 0); \
+ __o1->object_base = __o1->next_free; \
+ value; })
+
+#define obstack_free(OBSTACK, OBJ) \
+__extension__ \
+({ struct obstack *__o = (OBSTACK); \
+ void *__obj = (OBJ); \
+ if (__obj > (void *)__o->chunk && __obj < (void *)__o->chunk_limit) \
+ __o->next_free = __o->object_base = __obj; \
+ else (obstack_free) (__o, __obj); })
+
+#else /* not __GNUC__ or not __STDC__ */
+
+#define obstack_object_size(h) \
+ (unsigned) ((h)->next_free - (h)->object_base)
+
+#define obstack_room(h) \
+ (unsigned) ((h)->chunk_limit - (h)->next_free)
+
+#define obstack_grow(h,where,length) \
+( (h)->temp = (length), \
+ (((h)->next_free + (h)->temp > (h)->chunk_limit) \
+ ? (_obstack_newchunk ((h), (h)->temp), 0) : 0), \
+ bcopy (where, (h)->next_free, (h)->temp), \
+ (h)->next_free += (h)->temp)
+
+#define obstack_grow0(h,where,length) \
+( (h)->temp = (length), \
+ (((h)->next_free + (h)->temp + 1 > (h)->chunk_limit) \
+ ? (_obstack_newchunk ((h), (h)->temp + 1), 0) : 0), \
+ bcopy (where, (h)->next_free, (h)->temp), \
+ (h)->next_free += (h)->temp, \
+ *((h)->next_free)++ = 0)
+
+#define obstack_1grow(h,datum) \
+( (((h)->next_free + 1 > (h)->chunk_limit) \
+ ? (_obstack_newchunk ((h), 1), 0) : 0), \
+ *((h)->next_free)++ = (datum))
+
+#define obstack_ptr_grow(h,datum) \
+( (((h)->next_free + sizeof (char *) > (h)->chunk_limit) \
+ ? (_obstack_newchunk ((h), sizeof (char *)), 0) : 0), \
+ *((char **)(((h)->next_free+=sizeof(char *))-sizeof(char *))) = ((char *)datum))
+
+#define obstack_int_grow(h,datum) \
+( (((h)->next_free + sizeof (int) > (h)->chunk_limit) \
+ ? (_obstack_newchunk ((h), sizeof (int)), 0) : 0), \
+ *((int *)(((h)->next_free+=sizeof(int))-sizeof(int))) = ((int)datum))
+
+#define obstack_ptr_grow_fast(h,aptr) (*((char **)(h)->next_free)++ = (char *)aptr)
+#define obstack_int_grow_fast(h,aint) (*((int *)(h)->next_free)++ = (int)aint)
+
+#define obstack_blank(h,length) \
+( (h)->temp = (length), \
+ (((h)->chunk_limit - (h)->next_free < (h)->temp) \
+ ? (_obstack_newchunk ((h), (h)->temp), 0) : 0), \
+ (h)->next_free += (h)->temp)
+
+#define obstack_alloc(h,length) \
+ (obstack_blank ((h), (length)), obstack_finish ((h)))
+
+#define obstack_copy(h,where,length) \
+ (obstack_grow ((h), (where), (length)), obstack_finish ((h)))
+
+#define obstack_copy0(h,where,length) \
+ (obstack_grow0 ((h), (where), (length)), obstack_finish ((h)))
+
+#define obstack_finish(h) \
+( ((h)->next_free == (h)->object_base \
+ ? (((h)->maybe_empty_object = 1), 0) \
+ : 0), \
+ (h)->temp = __PTR_TO_INT ((h)->object_base), \
+ (h)->next_free \
+ = __INT_TO_PTR ((__PTR_TO_INT ((h)->next_free)+(h)->alignment_mask) \
+ & ~ ((h)->alignment_mask)), \
+ (((h)->next_free - (char *)(h)->chunk \
+ > (h)->chunk_limit - (char *)(h)->chunk) \
+ ? ((h)->next_free = (h)->chunk_limit) : 0), \
+ (h)->object_base = (h)->next_free, \
+ __INT_TO_PTR ((h)->temp))
+
+#ifdef __STDC__
+#define obstack_free(h,obj) \
+( (h)->temp = (char *)(obj) - (char *) (h)->chunk, \
+ (((h)->temp > 0 && (h)->temp < (h)->chunk_limit - (char *) (h)->chunk)\
+ ? (int) ((h)->next_free = (h)->object_base \
+ = (h)->temp + (char *) (h)->chunk) \
+ : (((obstack_free) ((h), (h)->temp + (char *) (h)->chunk), 0), 0)))
+#else
+#define obstack_free(h,obj) \
+( (h)->temp = (char *)(obj) - (char *) (h)->chunk, \
+ (((h)->temp > 0 && (h)->temp < (h)->chunk_limit - (char *) (h)->chunk)\
+ ? (int) ((h)->next_free = (h)->object_base \
+ = (h)->temp + (char *) (h)->chunk) \
+ : (_obstack_free ((h), (h)->temp + (char *) (h)->chunk), 0)))
+#endif
+
+#endif /* not __GNUC__ or not __STDC__ */
+
+#endif /* not __OBSTACKS__ */
diff --git a/gnu/usr.bin/grep/search.c b/gnu/usr.bin/grep/search.c
new file mode 100644
index 0000000..5e17d03
--- /dev/null
+++ b/gnu/usr.bin/grep/search.c
@@ -0,0 +1,481 @@
+/* search.c - searching subroutines using dfa, kwset and regex for grep.
+ Copyright (C) 1992 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ Written August 1992 by Mike Haertel. */
+
+#include <ctype.h>
+
+#ifdef STDC_HEADERS
+#include <limits.h>
+#include <stdlib.h>
+#else
+#define UCHAR_MAX 255
+#include <sys/types.h>
+extern char *malloc();
+#endif
+
+#ifdef HAVE_MEMCHR
+#include <string.h>
+#ifdef NEED_MEMORY_H
+#include <memory.h>
+#endif
+#else
+#ifdef __STDC__
+extern void *memchr();
+#else
+extern char *memchr();
+#endif
+#endif
+
+#if defined(HAVE_STRING_H) || defined(STDC_HEADERS)
+#undef bcopy
+#define bcopy(s, d, n) memcpy((d), (s), (n))
+#endif
+
+#if defined(isascii) && !defined(__FreeBSD__)
+#define ISALNUM(C) (isascii(C) && isalnum(C))
+#define ISUPPER(C) (isascii(C) && isupper(C))
+#else
+#define ISALNUM(C) isalnum(C)
+#define ISUPPER(C) isupper(C)
+#endif
+
+#define TOLOWER(C) (ISUPPER(C) ? tolower(C) : (C))
+
+#include "grep.h"
+#include "dfa.h"
+#include "kwset.h"
+#include "gnuregex.h"
+
+#define NCHAR (UCHAR_MAX + 1)
+
+#if __STDC__
+static void Gcompile(char *, size_t);
+static void Ecompile(char *, size_t);
+static char *EGexecute(char *, size_t, char **);
+static void Fcompile(char *, size_t);
+static char *Fexecute(char *, size_t, char **);
+#else
+static void Gcompile();
+static void Ecompile();
+static char *EGexecute();
+static void Fcompile();
+static char *Fexecute();
+#endif
+
+/* Here is the matchers vector for the main program. */
+struct matcher matchers[] = {
+ { "default", Gcompile, EGexecute },
+ { "grep", Gcompile, EGexecute },
+ { "ggrep", Gcompile, EGexecute },
+ { "egrep", Ecompile, EGexecute },
+ { "posix-egrep", Ecompile, EGexecute },
+ { "gegrep", Ecompile, EGexecute },
+ { "fgrep", Fcompile, Fexecute },
+ { "gfgrep", Fcompile, Fexecute },
+ { 0, 0, 0 },
+};
+
+/* For -w, we also consider _ to be word constituent. */
+#define WCHAR(C) (ISALNUM(C) || (C) == '_')
+
+/* DFA compiled regexp. */
+static struct dfa dfa;
+
+/* Regex compiled regexp. */
+static struct re_pattern_buffer regex;
+
+/* KWset compiled pattern. For Ecompile and Gcompile, we compile
+ a list of strings, at least one of which is known to occur in
+ any string matching the regexp. */
+static kwset_t kwset;
+
+/* Last compiled fixed string known to exactly match the regexp.
+ If kwsexec() returns < lastexact, then we don't need to
+ call the regexp matcher at all. */
+static int lastexact;
+
+void
+dfaerror(mesg)
+ char *mesg;
+{
+ fatal(mesg, 0);
+}
+
+static void
+kwsinit()
+{
+ static char trans[NCHAR];
+ int i;
+
+ if (match_icase)
+ for (i = 0; i < NCHAR; ++i)
+ trans[i] = TOLOWER(i);
+
+ if (!(kwset = kwsalloc(match_icase ? trans : (char *) 0)))
+ fatal("memory exhausted", 0);
+}
+
+/* If the DFA turns out to have some set of fixed strings one of
+ which must occur in the match, then we build a kwset matcher
+ to find those strings, and thus quickly filter out impossible
+ matches. */
+static void
+kwsmusts()
+{
+ struct dfamust *dm;
+ char *err;
+
+ if (dfa.musts)
+ {
+ kwsinit();
+ /* First, we compile in the substrings known to be exact
+ matches. The kwset matcher will return the index
+ of the matching string that it chooses. */
+ for (dm = dfa.musts; dm; dm = dm->next)
+ {
+ if (!dm->exact)
+ continue;
+ ++lastexact;
+ if ((err = kwsincr(kwset, dm->must, strlen(dm->must))) != 0)
+ fatal(err, 0);
+ }
+ /* Now, we compile the substrings that will require
+ the use of the regexp matcher. */
+ for (dm = dfa.musts; dm; dm = dm->next)
+ {
+ if (dm->exact)
+ continue;
+ if ((err = kwsincr(kwset, dm->must, strlen(dm->must))) != 0)
+ fatal(err, 0);
+ }
+ if ((err = kwsprep(kwset)) != 0)
+ fatal(err, 0);
+ }
+}
+
+static void
+Gcompile(pattern, size)
+ char *pattern;
+ size_t size;
+{
+#ifdef __STDC__
+ const
+#endif
+ char *err;
+
+ re_set_syntax(RE_SYNTAX_GREP | RE_HAT_LISTS_NOT_NEWLINE);
+ dfasyntax(RE_SYNTAX_GREP | RE_HAT_LISTS_NOT_NEWLINE, match_icase);
+
+ if ((err = re_compile_pattern(pattern, size, &regex)) != 0)
+ fatal(err, 0);
+
+ dfainit(&dfa);
+
+ /* In the match_words and match_lines cases, we use a different pattern
+ for the DFA matcher that will quickly throw out cases that won't work.
+ Then if DFA succeeds we do some hairy stuff using the regex matcher
+ to decide whether the match should really count. */
+ if (match_words || match_lines)
+ {
+ /* In the whole-word case, we use the pattern:
+ (^|[^A-Za-z_])(userpattern)([^A-Za-z_]|$).
+ In the whole-line case, we use the pattern:
+ ^(userpattern)$.
+ BUG: Using [A-Za-z_] is locale-dependent! */
+
+ char *n = malloc(size + 50);
+ int i = 0;
+
+ strcpy(n, "");
+
+ if (match_lines)
+ strcpy(n, "^\\(");
+ if (match_words)
+ strcpy(n, "\\(^\\|[^0-9A-Za-z_]\\)\\(");
+
+ i = strlen(n);
+ bcopy(pattern, n + i, size);
+ i += size;
+
+ if (match_words)
+ strcpy(n + i, "\\)\\([^0-9A-Za-z_]\\|$\\)");
+ if (match_lines)
+ strcpy(n + i, "\\)$");
+
+ i += strlen(n + i);
+ dfacomp(n, i, &dfa, 1);
+ }
+ else
+ dfacomp(pattern, size, &dfa, 1);
+
+ kwsmusts();
+}
+
+static void
+Ecompile(pattern, size)
+ char *pattern;
+ size_t size;
+{
+#ifdef __STDC__
+ const
+#endif
+ char *err;
+
+ if (strcmp(matcher, "posix-egrep") == 0)
+ {
+ re_set_syntax(RE_SYNTAX_POSIX_EGREP);
+ dfasyntax(RE_SYNTAX_POSIX_EGREP, match_icase);
+ }
+ else
+ {
+ re_set_syntax(RE_SYNTAX_EGREP);
+ dfasyntax(RE_SYNTAX_EGREP, match_icase);
+ }
+
+ if ((err = re_compile_pattern(pattern, size, &regex)) != 0)
+ fatal(err, 0);
+
+ dfainit(&dfa);
+
+ /* In the match_words and match_lines cases, we use a different pattern
+ for the DFA matcher that will quickly throw out cases that won't work.
+ Then if DFA succeeds we do some hairy stuff using the regex matcher
+ to decide whether the match should really count. */
+ if (match_words || match_lines)
+ {
+ /* In the whole-word case, we use the pattern:
+ (^|[^A-Za-z_])(userpattern)([^A-Za-z_]|$).
+ In the whole-line case, we use the pattern:
+ ^(userpattern)$.
+ BUG: Using [A-Za-z_] is locale-dependent! */
+
+ char *n = malloc(size + 50);
+ int i = 0;
+
+ strcpy(n, "");
+
+ if (match_lines)
+ strcpy(n, "^(");
+ if (match_words)
+ strcpy(n, "(^|[^0-9A-Za-z_])(");
+
+ i = strlen(n);
+ bcopy(pattern, n + i, size);
+ i += size;
+
+ if (match_words)
+ strcpy(n + i, ")([^0-9A-Za-z_]|$)");
+ if (match_lines)
+ strcpy(n + i, ")$");
+
+ i += strlen(n + i);
+ dfacomp(n, i, &dfa, 1);
+ }
+ else
+ dfacomp(pattern, size, &dfa, 1);
+
+ kwsmusts();
+}
+
+static char *
+EGexecute(buf, size, endp)
+ char *buf;
+ size_t size;
+ char **endp;
+{
+ register char *buflim, *beg, *end, save;
+ int backref, start, len;
+ struct kwsmatch kwsm;
+ static struct re_registers regs; /* This is static on account of a BRAIN-DEAD
+ Q@#%!# library interface in regex.c. */
+
+ buflim = buf + size;
+
+ for (beg = end = buf; end < buflim; beg = end + 1)
+ {
+ if (kwset)
+ {
+ /* Find a possible match using the KWset matcher. */
+ beg = kwsexec(kwset, beg, buflim - beg, &kwsm);
+ if (!beg)
+ goto failure;
+ /* Narrow down to the line containing the candidate, and
+ run it through DFA. */
+ end = memchr(beg, '\n', buflim - beg);
+ if (!end)
+ end = buflim;
+ while (beg > buf && beg[-1] != '\n')
+ --beg;
+ save = *end;
+ if (kwsm.index < lastexact)
+ goto success;
+ if (!dfaexec(&dfa, beg, end, 0, (int *) 0, &backref))
+ {
+ *end = save;
+ continue;
+ }
+ *end = save;
+ /* Successful, no backreferences encountered. */
+ if (!backref)
+ goto success;
+ }
+ else
+ {
+ /* No good fixed strings; start with DFA. */
+ save = *buflim;
+ beg = dfaexec(&dfa, beg, buflim, 0, (int *) 0, &backref);
+ *buflim = save;
+ if (!beg)
+ goto failure;
+ /* Narrow down to the line we've found. */
+ end = memchr(beg, '\n', buflim - beg);
+ if (!end)
+ end = buflim;
+ while (beg > buf && beg[-1] != '\n')
+ --beg;
+ /* Successful, no backreferences encountered! */
+ if (!backref)
+ goto success;
+ }
+ /* If we've made it to this point, this means DFA has seen
+ a probable match, and we need to run it through Regex. */
+ regex.not_eol = 0;
+ if ((start = re_search(&regex, beg, end - beg, 0, end - beg, &regs)) >= 0)
+ {
+ len = regs.end[0] - start;
+ if (!match_lines && !match_words || match_lines && len == end - beg)
+ goto success;
+ /* If -w, check if the match aligns with word boundaries.
+ We do this iteratively because:
+ (a) the line may contain more than one occurence of the pattern, and
+ (b) Several alternatives in the pattern might be valid at a given
+ point, and we may need to consider a shorter one to find a word
+ boundary. */
+ if (match_words)
+ while (start >= 0)
+ {
+ if ((start == 0 || !WCHAR(beg[start - 1]))
+ && (len == end - beg || !WCHAR(beg[start + len])))
+ goto success;
+ if (len > 0)
+ {
+ /* Try a shorter length anchored at the same place. */
+ --len;
+ regex.not_eol = 1;
+ len = re_match(&regex, beg, start + len, start, &regs);
+ }
+ if (len <= 0)
+ {
+ /* Try looking further on. */
+ if (start == end - beg)
+ break;
+ ++start;
+ regex.not_eol = 0;
+ start = re_search(&regex, beg, end - beg,
+ start, end - beg - start, &regs);
+ len = regs.end[0] - start;
+ }
+ }
+ }
+ }
+
+ failure:
+ return 0;
+
+ success:
+ *endp = end < buflim ? end + 1 : end;
+ return beg;
+}
+
+static void
+Fcompile(pattern, size)
+ char *pattern;
+ size_t size;
+{
+ char *beg, *lim, *err;
+
+ kwsinit();
+ beg = pattern;
+ do
+ {
+ for (lim = beg; lim < pattern + size && *lim != '\n'; ++lim)
+ ;
+ if ((err = kwsincr(kwset, beg, lim - beg)) != 0)
+ fatal(err, 0);
+ if (lim < pattern + size)
+ ++lim;
+ beg = lim;
+ }
+ while (beg < pattern + size);
+
+ if ((err = kwsprep(kwset)) != 0)
+ fatal(err, 0);
+}
+
+static char *
+Fexecute(buf, size, endp)
+ char *buf;
+ size_t size;
+ char **endp;
+{
+ register char *beg, *try, *end;
+ register size_t len;
+ struct kwsmatch kwsmatch;
+
+ for (beg = buf; beg <= buf + size; ++beg)
+ {
+ if (!(beg = kwsexec(kwset, beg, buf + size - beg, &kwsmatch)))
+ return 0;
+ len = kwsmatch.size[0];
+ if (match_lines)
+ {
+ if (beg > buf && beg[-1] != '\n')
+ continue;
+ if (beg + len < buf + size && beg[len] != '\n')
+ continue;
+ goto success;
+ }
+ else if (match_words)
+ for (try = beg; len && try;)
+ {
+ if (try > buf && WCHAR((unsigned char) try[-1]))
+ break;
+ if (try + len < buf + size && WCHAR((unsigned char) try[len]))
+ {
+ try = kwsexec(kwset, beg, --len, &kwsmatch);
+ len = kwsmatch.size[0];
+ }
+ else
+ goto success;
+ }
+ else
+ goto success;
+ }
+
+ return 0;
+
+ success:
+ if ((end = memchr(beg + len, '\n', (buf + size) - (beg + len))) != 0)
+ ++end;
+ else
+ end = buf + size;
+ *endp = end;
+ while (beg > buf && beg[-1] != '\n')
+ --beg;
+ return beg;
+}
diff --git a/gnu/usr.bin/grep/tests/check.sh b/gnu/usr.bin/grep/tests/check.sh
new file mode 100644
index 0000000..d2c8fdb
--- /dev/null
+++ b/gnu/usr.bin/grep/tests/check.sh
@@ -0,0 +1,24 @@
+#! /bin/sh
+# Regression test for GNU grep.
+# Usage: regress.sh [testdir]
+
+testdir=${1-tests}
+
+failures=0
+
+# The Khadafy test is brought to you by Scott Anderson . . .
+./grep -E -f $testdir/khadafy.regexp $testdir/khadafy.lines > khadafy.out
+if cmp $testdir/khadafy.lines khadafy.out
+then
+ :
+else
+ echo Khadafy test failed -- output left on khadafy.out
+ failures=1
+fi
+
+# . . . and the following by Henry Spencer.
+
+${AWK-awk} -F: -f $testdir/scriptgen.awk $testdir/spencer.tests > tmp.script
+
+sh tmp.script && exit $failures
+exit 1
diff --git a/gnu/usr.bin/grep/tests/khadafy.lines b/gnu/usr.bin/grep/tests/khadafy.lines
new file mode 100644
index 0000000..57e21a1
--- /dev/null
+++ b/gnu/usr.bin/grep/tests/khadafy.lines
@@ -0,0 +1,32 @@
+1) Muammar Qaddafi
+2) Mo'ammar Gadhafi
+3) Muammar Kaddafi
+4) Muammar Qadhafi
+5) Moammar El Kadhafi
+6) Muammar Gadafi
+7) Mu'ammar al-Qadafi
+8) Moamer El Kazzafi
+9) Moamar al-Gaddafi
+10) Mu'ammar Al Qathafi
+11) Muammar Al Qathafi
+12) Mo'ammar el-Gadhafi
+13) Moamar El Kadhafi
+14) Muammar al-Qadhafi
+15) Mu'ammar al-Qadhdhafi
+16) Mu'ammar Qadafi
+17) Moamar Gaddafi
+18) Mu'ammar Qadhdhafi
+19) Muammar Khaddafi
+20) Muammar al-Khaddafi
+21) Mu'amar al-Kadafi
+22) Muammar Ghaddafy
+23) Muammar Ghadafi
+24) Muammar Ghaddafi
+25) Muamar Kaddafi
+26) Muammar Quathafi
+27) Muammar Gheddafi
+28) Muamar Al-Kaddafi
+29) Moammar Khadafy
+30) Moammar Qudhafi
+31) Mu'ammar al-Qaddafi
+32) Mulazim Awwal Mu'ammar Muhammad Abu Minyar al-Qadhafi
diff --git a/gnu/usr.bin/grep/tests/khadafy.regexp b/gnu/usr.bin/grep/tests/khadafy.regexp
new file mode 100644
index 0000000..46fe8dd
--- /dev/null
+++ b/gnu/usr.bin/grep/tests/khadafy.regexp
@@ -0,0 +1 @@
+M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy]
diff --git a/gnu/usr.bin/grep/tests/scriptgen.awk b/gnu/usr.bin/grep/tests/scriptgen.awk
new file mode 100644
index 0000000..44ef4df
--- /dev/null
+++ b/gnu/usr.bin/grep/tests/scriptgen.awk
@@ -0,0 +1,10 @@
+BEGIN { print "failures=0"; }
+$0 !~ /^#/ && NF == 3 {
+ print "echo '" $3 "' | ./grep -E -e '" $2 "' > /dev/null 2>&1";
+ print "if [ $? != " $1 " ]"
+ print "then"
+ printf "\techo Spencer test \\#%d failed\n", ++n
+ print "\tfailures=1"
+ print "fi"
+}
+END { print "exit $failures"; }
diff --git a/gnu/usr.bin/grep/tests/spencer.tests b/gnu/usr.bin/grep/tests/spencer.tests
new file mode 100644
index 0000000..913f198
--- /dev/null
+++ b/gnu/usr.bin/grep/tests/spencer.tests
@@ -0,0 +1,122 @@
+0:abc:abc
+1:abc:xbc
+1:abc:axc
+1:abc:abx
+0:abc:xabcy
+0:abc:ababc
+0:ab*c:abc
+0:ab*bc:abc
+0:ab*bc:abbc
+0:ab*bc:abbbbc
+0:ab+bc:abbc
+1:ab+bc:abc
+1:ab+bc:abq
+0:ab+bc:abbbbc
+0:ab?bc:abbc
+0:ab?bc:abc
+1:ab?bc:abbbbc
+0:ab?c:abc
+0:^abc$:abc
+1:^abc$:abcc
+0:^abc:abcc
+1:^abc$:aabc
+0:abc$:aabc
+0:^:abc
+0:$:abc
+0:a.c:abc
+0:a.c:axc
+0:a.*c:axyzc
+1:a.*c:axyzd
+1:a[bc]d:abc
+0:a[bc]d:abd
+1:a[b-d]e:abd
+0:a[b-d]e:ace
+0:a[b-d]:aac
+0:a[-b]:a-
+0:a[b-]:a-
+1:a[b-a]:-
+2:a[]b:-
+2:a[:-
+0:a]:a]
+0:a[]]b:a]b
+0:a[^bc]d:aed
+1:a[^bc]d:abd
+0:a[^-b]c:adc
+1:a[^-b]c:a-c
+1:a[^]b]c:a]c
+0:a[^]b]c:adc
+0:ab|cd:abc
+0:ab|cd:abcd
+0:()ef:def
+0:()*:-
+1:*a:-
+0:^*:-
+0:$*:-
+1:(*)b:-
+1:$b:b
+2:a\:-
+0:a\(b:a(b
+0:a\(*b:ab
+0:a\(*b:a((b
+1:a\x:a\x
+2:abc):-
+2:(abc:-
+0:((a)):abc
+0:(a)b(c):abc
+0:a+b+c:aabbabc
+0:a**:-
+0:a*?:-
+0:(a*)*:-
+0:(a*)+:-
+0:(a|)*:-
+0:(a*|b)*:-
+0:(a+|b)*:ab
+0:(a+|b)+:ab
+0:(a+|b)?:ab
+0:[^ab]*:cde
+0:(^)*:-
+0:(ab|)*:-
+2:)(:-
+1:abc:
+1:abc:
+0:a*:
+0:([abc])*d:abbbcd
+0:([abc])*bcd:abcd
+0:a|b|c|d|e:e
+0:(a|b|c|d|e)f:ef
+0:((a*|b))*:-
+0:abcd*efg:abcdefg
+0:ab*:xabyabbbz
+0:ab*:xayabbbz
+0:(ab|cd)e:abcde
+0:[abhgefdc]ij:hij
+1:^(ab|cd)e:abcde
+0:(abc|)ef:abcdef
+0:(a|b)c*d:abcd
+0:(ab|ab*)bc:abc
+0:a([bc]*)c*:abc
+0:a([bc]*)(c*d):abcd
+0:a([bc]+)(c*d):abcd
+0:a([bc]*)(c+d):abcd
+0:a[bcd]*dcdcde:adcdcde
+1:a[bcd]+dcdcde:adcdcde
+0:(ab|a)b*c:abc
+0:((a)(b)c)(d):abcd
+0:[A-Za-z_][A-Za-z0-9_]*:alpha
+0:^a(bc+|b[eh])g|.h$:abh
+0:(bc+d$|ef*g.|h?i(j|k)):effgz
+0:(bc+d$|ef*g.|h?i(j|k)):ij
+1:(bc+d$|ef*g.|h?i(j|k)):effg
+1:(bc+d$|ef*g.|h?i(j|k)):bcdd
+0:(bc+d$|ef*g.|h?i(j|k)):reffgz
+1:((((((((((a)))))))))):-
+0:(((((((((a))))))))):a
+1:multiple words of text:uh-uh
+0:multiple words:multiple words, yeah
+0:(.*)c(.*):abcde
+1:\((.*),:(.*)\)
+1:[k]:ab
+0:abcd:abcd
+0:a(bc)d:abcd
+0:a[-]?c:ac
+0:(....).*\1:beriberi
diff --git a/gnu/usr.bin/groff/BUG-REPORT b/gnu/usr.bin/groff/BUG-REPORT
new file mode 100644
index 0000000..d3c9b02
--- /dev/null
+++ b/gnu/usr.bin/groff/BUG-REPORT
@@ -0,0 +1,57 @@
+ Groff Bug Report
+
+Please read the PROBLEMS file before sending in a bug report.
+
+Please fill in all fields, even if you think they are not relevant.
+
+Please delete the text in brackets before sending it in.
+
+Please report separate bugs separately.
+
+Send the completed form either to bug-groff@prep.ai.mit.edu or
+directly to me (jjc@jclark.com). Messages sent to bug-groff can
+sometimes take several days to reach me.
+
+GROFF VERSION:
+[The version of groff you are using. For example, `1.05']
+
+MACHINE:
+[The machine you are using. For example, `Sun SPARCstation 2']
+
+OS:
+[The operating system you are using. For example, `SunOS 4.1.1']
+
+COMPILER:
+[The compiler you are used to compile groff. For example, `g++ 1.40.3']
+
+INPUT FILES:
+[Include all the files necessary to reproduce the problem that are not
+part of the standard groff distribution. This includes font
+description files, DESC files and macro files (with the exception of
+the -ms and -mm macros: I have them). Send them as as a shell archive
+or as a uuencoded, compressed tar file.
+
+It's easier for me if you can provide an example that doesn't depend
+on any macro package, but obviously if you're reporting a problem with
+a macro package that won't be possible. Also a short example is more
+convenient than a long one, but don't worry if you can't find a short
+example. Don't say something like ``any file that X'': always send a
+definite example.]
+
+COMMAND LINE:
+[The command line that I should run in order to observe the bug. For
+example, `gtroff -Tps bug.tr'. If the command line uses -ms or -mm,
+say whether these refer to the groff versions or the Unix versions of
+the macros.]
+
+DESCRIPTION OF INCORRECT BEHAVIOUR:
+[What goes wrong when that command line is run? For example, `gtroff
+gets a segmentation fault', or `The output looks bad because the bar
+over the x is too long and is too far over to the left.' If you get
+an error message, include it here without modification: don't edit it
+to make it more readable.]
+
+SUGGESTED FIX [optional]:
+[If you can suggest a fix for the problem, include a context diff
+here. But don't delay sending in a bug report in the hope of finding
+a fix. Guesses about the cause of the bug are not usually helpful.]
diff --git a/gnu/usr.bin/groff/COPYING b/gnu/usr.bin/groff/COPYING
new file mode 100644
index 0000000..c712f50
--- /dev/null
+++ b/gnu/usr.bin/groff/COPYING
@@ -0,0 +1,339 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
+ 675 Mass Ave, Cambridge, MA 02139, USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ Appendix: How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) 19yy <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) 19yy name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/gnu/usr.bin/groff/ChangeLog b/gnu/usr.bin/groff/ChangeLog
new file mode 100644
index 0000000..9db9bd7
--- /dev/null
+++ b/gnu/usr.bin/groff/ChangeLog
@@ -0,0 +1,5351 @@
+Sat Feb 19 13:07:16 1994 James Clark (jjc@jclark.com)
+
+ * Version 1.09 released.
+
+Wed Feb 16 16:53:49 1994 James Clark (jjc@jclark.com)
+
+ * tmac/doc-ditroff (hK): Don't reset page number if \nC is > 0.
+
+Mon Feb 14 08:26:40 1994 James Clark (jjc@jclark.com)
+
+ * libgroff/font.cc (font::load_desc): Fix typo in error message.
+
+Sun Feb 13 09:37:38 1994 James Clark (jjc@jclark.com)
+
+ * libgroff/new.cc (operator new): Rewrite so as to avoid warning
+ about returning without a value.
+
+ * troff/charinfo.h (charinfo::get_special_translation): Cast
+ TRANSLATE_NONE to int.
+
+ * refer/token.cc (lookup_token, store_token): Remove bogus loop
+ test. Fix test so that it works with n unsigned.
+
+ * pic/pic.y (defaults_table): Fully bracket initializer.
+ * pic/lex.cc (lookup_keyword): Likewise.
+ * eqn/lex.cc (token_table, def_table): Likewise.
+ * eqn/box.cc (param_table): Likewise.
+ * troff/input.cc (warning_table): Likewise.
+ * libgroff/font.cc (table): Likewise.
+ * grops/ps.cc (ps_printer::special): Likewise.
+ * grops/psrm.cc (resource_manager::process_file): Likewise.
+ * tfmtodit/tfmtodit.cc (lig_chars, lig_table): Likewise.
+ * refer/command.cc (command_table): Likewise.
+ * addftinfo/addftinfo.cc (param_table): Likewise.
+
+ * troff/symbol.cc (symbol::symbol): Prevent compiler warnings
+ about temp's being unused.
+ (unused): New function.
+
+ * groff/pipeline.cc: Declare c_fatal.
+
+ * libbib/linear.cc (bmpattern::search): Cast patterrn[--j] to
+ uchar.
+
+ * libbib/index.cc (index_search_item::load): Prevent compiler
+ warnings about fd_closer's being unused.
+ (unused): New function.
+
+Sat Feb 12 10:31:59 1994 James Clark (jjc@jclark.com)
+
+ * troff/input.cc (copy_mode_error): Make `prefix' static.
+ Fix typo.
+
+ * include/posix.h: Include <osfcn.h> is HAVE_CC_OSFCN_H is
+ defined.
+ * acgroff.m4, configure.in, Makefile: Rename HAVE_CC_UNISTD_H to
+ HAVE_CC_OSFCN_H and modify accordingly.
+
+ * troff/input.cc (init_charset_table): radicalex overlaps
+ horizontally.
+
+ * groff/acgroff.m4 (GROFF_ISC_SYSV3): New macro (from
+ udodo!hans@relay.NL.net).
+ * groff/configure.in: Call it.
+
+ * groff/acgroff.m4 (GROFF_PCLOSE): New macro.
+ * groff/configure.in: Call it.
+ * include/lib.h: Conditionalize declaration of pclose.
+
+ * troff/div.cc (last_page_number): New global variable.
+ (top_level_diversion::begin_page): Exit if we just printed the
+ last page.
+ * troff/div.h (last_page_number): Declare it.
+ * troff/input.cc (parse_output_page_list): Set last_page_number.
+
+ * eqn/sqrt.cc: Rename \(rn to \[radicalex].
+ * devps/S, devps/textmap, tmac/tmac.ps, tmac/tmac.dvi,
+ tmac/tmac.X: Likewise.
+ * tmac/tmac.ps, tmac/tmac.X, tmac.dvi: Add definitions of \(rn.
+ * tmac.dvi: Make \(ru and \(ul extend beyond their width by .04m.
+
+Fri Feb 11 11:45:40 1994 James Clark (jjc@jclark.com)
+
+ * tmac/doc-ditroff (hK): Remove groff specific code which
+ prevented page-breaks between separate manual entries. If this is
+ the first page, don't set the page number to 1.
+
+ * acgroff.m4 (GROFF_POSIX): New macro.
+ * configure.in: Use it.
+
+ * troff/node.cc (class real_output_file,
+ real_output_file::real_output_file,
+ real_output_file::~real_output_file): Conditionalize use of
+ popen/pclose on POPEN_MISSING.
+ * troff/node.h: Conditionalize pipe_command on POPEN_MISSING.
+ * troff/input.cc (pipe_command): Give an error if POPEN_MISSING.
+ (pipe_source): Similarily.
+
+ * acgroff.m4 (GROFF_PROG_CCC): Update message about libg++.
+
+ * acgroff.m4 (GROFF_GETOPT, GROFF_PUTENV, GROFF_POPEN): Detect
+ presence of declarations by trying to compile example with
+ conflicting declarations. (gcc only gives a warning for missing
+ declarations.)
+
+Wed Feb 9 09:12:23 1994 James Clark (jjc@jclark.com)
+
+ * tmac/tmac.pspic (PSPIC): Allow options to specify alignment
+ (from Ulrich Lauther).
+
+Tue Feb 8 03:56:40 1994 James Clark (jjc@jclark.com)
+
+ * libbib/linear.cc (file_buffer::load): Use S_ISREG macro.
+
+Thu Feb 3 09:34:35 1994 James Clark (jjc@jclark.com)
+
+ * indxbib/indxbib.cc (write_hash_table): Add code for case where
+ pointers and ints have different sizes.
+
+Sun Jan 9 16:17:51 1994 James Clark (jjc@jclark.com)
+
+ * tmac/tmac.s (par*env-init): Call par@reset.
+
+Fri Jan 7 10:24:27 1994 James Clark (jjc@jclark.com)
+
+ * tmac/tmac.s (@IP): Switch to a new environment when diverting
+ tag.
+ (par*push-tag-env, par*pop-tag-env): New macros.
+
+Wed Jan 5 21:18:34 1994 James Clark (jjc@jclark.com)
+
+ * grops/ps.cc (ps_printer::ps_printer): Use MAX_LINE_LENGTH for
+ initializing `out'. Reduce MAX_LINE_LENGTH from 79 to 72.
+
+ * grops/ps.cc (ps_printer::~ps_printer): Output %%CreationDate
+ comment. Include <time.h>.
+
+Wed Dec 15 14:14:00 1993 James Clark (jjc@jclark.com)
+
+ * grops/ps.cc (is_small_h, is_small_v): Deleted.
+ (ps_printer::flush_sbuf): Use absolute motion only at beginning of
+ lines.
+
+Tue Dec 14 10:06:34 1993 James Clark (jjc@jclark.com)
+
+ * troff/input.cc (read_request): Only print a prompt if reading
+ from the terminal. Also clearerr on EOF if reading from the
+ terminal. Declare isatty.
+
+Mon Nov 29 08:38:15 1993 James Clark (jjc@jclark.com)
+
+ * refer/label.y: Rename map_t to map_func and extractor_t to
+ extractor_func.
+
+Sat Oct 30 06:38:12 1993 James Clark (jjc@jclark.com)
+
+ * include/assert.h: Don't use volatile.
+ * libgroff/assert.cc: Likewise.
+
+Fri Oct 29 15:00:23 1993 James Clark (jjc@jclark.com)
+
+ * troff/input.cc (abort_request): Look at character in tok before
+ calling get_copy().
+
+Thu Oct 28 14:09:48 1993 James Clark (jjc@jclark.com)
+
+ * troff/troff.h (NO_RETURN): Deleted.
+ * troff/div.cc (cleanup_and_exit): Don't declare aas NO_RETURN.
+ * troff/input.cc (exit_troff): Likewise
+
+ * Makefile.in: Remove `Making ...' messages since GNU make now
+ gives these.
+
+ * configure.in: Use AC_HAVE_HEADERS(unistd.h) instead of AC_UNISTD_H.
+
+Wed Oct 27 11:12:51 1993 James Clark (jjc@jclark.com)
+
+ * tmac/tmac.s (@init): Initialize PO to \n(.o here, rather than
+ to constant 1 inch.
+
+Sat Oct 23 10:03:52 1993 James Clark (jjc@jclark.com)
+
+ * tmac/tmac.e (hl): Use \n[.in] rather than \n(.i.
+
+Thu Oct 14 12:09:45 1993 James Clark (jjc@jclark.com)
+
+ * eqn/delim.cc (delim_box::compute_metrics): Don't increase
+ MARK_REG if there was no left delimiter.
+
+Sat Oct 2 19:54:47 1993 James Clark (jjc@jclark.com)
+
+ * pic/troff.cc (troff_output::text): Set line thickness to
+ relative before outputting text.
+
+ * tmac/tmac.e (@k): Don't zero ?T.
+ ((z): Likewise.
+
+Sat Sep 25 11:08:43 1993 James Clark (jjc@jclark.com)
+
+ * tmac/tmac.e ($p): Handle possibility that $3 is empty.
+
+Wed Aug 18 08:51:41 1993 James Clark (jjc@jclark.com)
+
+ * troff/input.cc (decode_args): Warn about unquoted tabs (from
+ Paul Eggert).
+
+Tue Aug 10 08:38:32 1993 James Clark (jjc@jclark.com)
+
+ * troff/input.cc (ignoring): New variable.
+ (ignore): Set ignoring during call to do_define_macro.
+ (do_define_macro): Clear ignoring before interpolating terminating
+ macro.
+ (copy_mode_error): New function.
+ (get_char_for_escape_name, read_long_escape_name,
+ interpolate_arg): Use copy_mode_error.
+ (warning_table): Add WARN_IG.
+ * troff/troff.h (WARN_IG): Declare.
+ (WARN_TOTAL): Change accordingly.
+
+ * groff/pipeline.c (strsignal): Rename to xstrsignal.
+ * groff/groff.cc (strsignal): Delete declaration.
+
+Fri Jul 16 01:43:12 1993 James Clark (jjc@jclark.com)
+
+ * troff/div.cc (page_offset): Use 'm' as default scaling.
+
+Sat Jul 3 09:11:38 1993 James Clark (jjc@jclark.com)
+
+ * nroff/nroff.sh: Ignore -u.
+
+Wed Jun 9 12:17:27 1993 James Clark (jjc@jclark.com)
+
+ * Makefile.in (MDEFINES): Pass down MAKEOVERRIDES.
+
+Fri Jun 4 17:35:47 1993 James Clark (jjc@jclark.com)
+
+ * tmac/tmac.s (par*box-draw): Set adjustment mode to l while
+ drawing box.
+ (B2): With -Tascii, leave additional vertical space before
+ and after. Ensure that the left and right indent is restored to
+ what it was even if the point size changes. Don't call
+ par@finish. Change the indent, line length and title length
+ directly. With -Tascii, make the width of the box 1n less.
+ (B1): Remember 1n at the current point size. Don't call
+ par@reset. Change the indent, line length and title length
+ directly. Ensure that the temporary indent is preserved.
+ (par*box-mark-top): Turn off no spacing mode.
+
+Thu Jun 3 17:47:14 1993 James Clark (jjc@jclark.com)
+
+ * Makefile.in (dist): Use .gz suffix.
+
+Thu May 27 20:04:59 1993 James Clark (jjc@jclark.com)
+
+ * troff/input.cc (main): Add return 0.
+ * pic/main.cc (main): Use return instead of exit.
+ * tbl/main.cc (main): Likewise.
+ * eqn/main.cc (main): Likewise.
+ * grops/ps.cc (main): Likewise.
+ * grotty/tty.cc (main): Likewise.
+ * groff/groff.cc (main): Likewise.
+ * grodvi/dvi.cc (main): Likewise.
+ * refer/refer.cc (main): Likewise.
+ * indxbib/indxbib.cc (main): Likewise.
+ * lkbib/lkbib.cc (main): Likewise.
+ * soelim/soelim.cc (main): Likewise.
+ * addftinfo/addftinfo.cc (main): Likewise.
+ * acgroff.m4 (GROFF_PROG_CCC, GROFF_CC_COMPILE_CHECK,
+ GROFF_COOKIE_BUG, GROFF_CC_ANSI_BUG): Likewise.
+
+ * troff/token.h (process_input_stack): Don't declare as static.
+ * troff/input.cc: Likewise.
+
+ * troff/node.c (invalidate_fontno): Make it a static member of
+ class font_family. Change callers.
+ * troff/node.c: Change declaration.
+
+ * tbl/main.cc (struct input_entry_format): Add explicit public
+ specifier.
+ * tbl/table.cc (struct text_stuff, struct single_hline_stuff,
+ struct double_hline_stuff): Likewise.
+ * tbl/table.h (struct entry_format): Likewise.
+ * pic/object.h (struct saved_state): Likewise.
+
+ * include/stringclass.h: Add forward declarations of friend
+ functions that are later declared as inline. Don't include inline
+ specifier in friend declaration.
+
+ * libgroff/lib.h: Declare popen and pclose.
+ * acgroff.m4 (GROFF_POPEN): New macro.
+ * configure.in: Call it.
+
+ * include/lib.h (PI): New constant. Undef first if necessary.
+ * tfmtodit/tfmtodit.cc (main): Use PI rather than M_PI.
+ * grops/ps.cc (degrees, radians): Likewise.
+ * libgroff/font.cc (font::get_skew): Likewise.
+
+ * grops/ps.cc (is_ascii): New function.
+ (ps_output::put_string): Use is_ascii. Use csprint rather than
+ isprint.
+ (ps_printer::define_encoding): Use csspace.
+ * libgroff/strtol.c (ISASCII): New macro.
+ (strtol): Cast arguments to is*() and tolower() to unsigned char.
+ Use ISASCII rather than isascii.
+ * libgroff/cmap.cc: Use isascii() only if <ctype.h> defines it.
+ * libgroff/cset.cc: Likewise.
+ * libdriver/input.cc: Include cset.h.
+ (do_file, get_integer, possibly_get_integer): Use csdigit() rather
+ than isdigit().
+
+ * refer/refer.cc (main): Use %ld rather than %d for longs.
+
+ * libbib/index.cc (index_search_item_iterator::get_tag): Use
+ S_ISREG macro.
+
+ * addftinfo/addftinfo.cc (param_t): Add explicit `int'.
+
+Mon May 24 08:51:37 1993 James Clark (jjc@jclark.com)
+
+ * troff/input.cc (hyphenation_code): Skip white space between
+ char/code pairs.
+
+Sun May 16 08:15:52 1993 James Clark (jjc at jclark.com)
+
+ * tbl/table.h (table::entry_list_tailp): New member.
+ (table::table): Initialize it.
+ (table::add_entry): Use entry_list_tailp to avoid O(n^2)
+ behaviour.
+
+Sat May 15 17:26:00 1993 James Clark (jjc at jclark.com)
+
+ * grotty/tty.cc (tty_printer::add_char): Don't discard characters
+ with negative horizontal positions. Remove casts of glyph::hpos to
+ int.
+ (USHRT_MAX): Delete definition.
+ (SHRT_MAX, SHRT_MIN): New definitions.
+ (glyph::hpos): Change type to short.
+ (tty_printer::end_page): Output multiple backspaces if necessary.
+ Remove casts of glyph::hpos to int.
+
+Fri May 7 12:14:37 1993 James Clark (jjc at jclark.com)
+
+ * tmac/tmac.s (@RT): New definition.
+
+Thu May 6 21:36:54 1993 James Clark (jjc at jclark.com)
+
+ * refer/refer.cc (do_file): Make sure current_filename is set when
+ filename is "-".
+
+ * pic/common.cc (common_output::dot_line): Handle zero length
+ lines.
+
+Sun May 2 19:54:16 1993 James Clark (jjc at jclark.com)
+
+ * tmac/tmac.s (par@reset): Get value for .hy for \n[HY].
+ (par@init): Initialize \n[HY].
+
+Mon Apr 26 11:43:16 1993 James Clark (jjc at jclark.com)
+
+ * troff/dictionary.cc (dictionary::remove): Continue when
+ r < j < i.
+
+Sun Apr 25 11:03:00 1993 James Clark (jjc at jclark.com)
+
+ * Makefile.com (.y.cc): Avoid ending up with two versions of
+ $(YTABH).
+
+Thu Apr 22 21:03:45 1993 James Clark (jjc at jclark.com)
+
+ * tmac/tmac.dvi (\(,c): Define only if it does not exist.
+ (\(,C): Likewise. Also fix typo.
+
+Wed Apr 21 08:47:32 1993 James Clark (jjc at jclark.com)
+
+ * lib.h: Delete extraneous semi-colon.
+
+ * Add pso request: `so' from a pipe.
+ * troff/input.c (file_iterator::file_iterator): Add 3rd argument.
+ (file_iterator::close): New function.
+ (file_iterator::~file_iterator, file_iterator::next_file): Use
+ file_iterator::close.
+ (file_iterator::backtrace): Say `process' rather than `file' when
+ the stream is popened.
+ (pipe_source): New function.
+ (init_input_requests): Bind ".pso" to pipe_source.
+
+Tue Apr 20 00:02:26 1993 James Clark (jjc at jclark.com)
+
+ * afmtodit/afmtodit.pl: Avoid single quotes in comments.
+
+ * pfbtops/pfbtops.c: Output 64 characters per line. Output hex
+ digits in lower case.
+
+Mon Apr 19 09:55:57 1993 James Clark (jjc at jclark)
+
+ * Version 1.08 released.
+
+ * Makefile.in (dist): Insert || true after ln -s commands that
+ might fail.
+
+ * mm: Update to mm 1.16.
+
+ * acgroff.m4 (GROFF_CSH_HACK): New macro.
+ * configure.in: Call GROFF_CSH_HACK. Substitute for
+ SH_SCRIPT_SED_CMD.
+ * Makefile.in (SH_SCRIPT_SED_CMD): New variable. Include in
+ MDEFINES.
+ * nroff/Makefile.sub (nroff): New target.
+ (install_data): Install nroff.
+ * eqn/Makefile.sub (neqn): Sed with SH_SCRIPT_SED_CMD.
+ * grog/Makefile.sub (grog): Sed grog.sh with SH_SCRIPT_SED_CMD.
+
+Sat Apr 17 08:24:28 1993 James Clark (jjc at jclark)
+
+ * eqn/Makefile.sub (neqn): Add chmod +x.
+
+ * grog/Makefile.sub (grog): Remove spurious semi-colon.
+
+Fri Apr 16 22:41:57 1993 James Clark (jjc at jclark)
+
+ * troff/input.cc (string_iterator::string_iterator()): Initialize
+ lineno and count.
+
+Tue Apr 13 10:22:28 1993 James Clark (jjc at jclark)
+
+ * troff/div.cc (macro_diversion::space,
+ top_level_diversion::space): Don't set high_water_mark.
+ (macro_diversion::output, top_level_diversion::output): Don't
+ include post line space in high water mark.
+
+Wed Apr 7 12:48:18 1993 James Clark (jjc at jclark)
+
+ * eqn/eqn.y: Don't define YYDEBUG.
+ * pic/pic.y: Likewise.
+
+Mon Apr 5 10:15:15 1993 James Clark (jjc at jclark)
+
+ * tmac/tmac.e ([3): Add space after comma following editors.
+ Change double spaces to single spaces.
+ ([4): Change double spaces to single spaces.
+
+ * grops/ps.h (USE_PS_ADOBE_2_0): New flag for broken_flags.
+ * grops/ps.cc (ps_printer::~ps_printer): If the USE_PS_ADOBE_2_0
+ bit is set in broken_flags, use 2.0 rather than 3.0 as the version
+ after %!PS-Adobe- (for Newsprint).
+
+ * troff/div.cc (top_level_diversion::begin_page): When
+ before_first_page is 1, set page_number to 1.
+
+Sun Apr 4 14:28:53 1993 James Clark (jjc at jclark)
+
+ * eqn/box.cc (box::top_level): Protect equation with \&.
+
+Sat Apr 3 23:27:25 1993 James Clark (jjc at jclark)
+
+ * groff/groff.cc (possible_command::set_name): Delete old name.
+
+ * groff/groff.cc (possible_command::~possible_command): Use
+ a_delete.
+
+ * troff/node.cc (troff_output_file::begun_page): New member.
+ (troff_output_file::troff_output_file): Initialize it.
+ (troff_output_file::really_begin_page): Only output V command if a
+ page has been begun.
+
+ * pic/pic.y (placeless_element): Delete argument to PRINT after
+ use.
+
+Fri Apr 2 11:31:02 1993 James Clark (jjc at jclark)
+
+ * Make wrapman work.
+ * troff/div.h (class top_level_diversion): Replace
+ first_page_begun by before_first_page (with opposite sense).
+ * Change first_page_begun to before_first_page inverting sense.
+ * troff/div.cc (class nl_reg): New class.
+ (init_div_requests): Use class nl_reg for \n(nl.
+ (top_level_diversion::begin_page): Don't call
+ output_file::begin_page if before_first_page is 2;
+ reset before_first_page afterwards. If have_next_page_number is
+ false, then always increment page_number.
+ * tmac/tmac.an: Set traps within TH rather than at the top-level.
+ Restore compatibility mode after loading, and then disable
+ compatibility mode in TH.
+
+Thu Apr 1 11:09:34 1993 James Clark (jjc at jclark)
+
+ * grotty/tty.cc (tty_printer::end_page): Don't discard characters
+ past last line.
+ * troff/node.h (output_file::trailer): Declare.
+ * troff/div.cc (cleanup_and_exit): Call output_file::trailer().
+ * troff/node.cc (output_file::trailer): New function.
+ (troff_output_file::~troff_output_file): Move most code into...
+ (troff_output_file::trailer): New function.
+ (class troff_output_file): Delete page_length member. Declare
+ trailer().
+ (troff_output_file::really_begin_page): Use current page length
+ for final V command.
+
+ * tbl/main.cc (struct options): New decimal_point_char member.
+ (options::options): Initialize this.
+ (process_options): Implement decimalpoint option.
+ (process_data): Pass decimal_point_char option to table::table.
+ * tbl/table.h (class table): New decimal_point_char member.
+ (table::table): Add additional argument.
+ * tbl/table.cc (find_dot): Rename to find_decimal_point. Add
+ second argument specifying decimal point character. Use this
+ instead of '.'.
+ (table::table): Initialize decimal_point_char.
+ (table::add_entry): Change call to find_dot.
+
+ * troff/input.cc (get_copy, token::next): Implement \V.
+ (interpolate_environment_variable): New function.
+
+Tue Mar 30 14:41:39 1993 James Clark (jjc at jclark)
+
+ * pic/lex.cc (lookup_keyword): Rename MIN to K_MIN, MAX to K_MAX.
+ * pic/pic.y: Likewise.
+
+ * grotty/tty.cc (tty_printer::add_char, tty_printer::end_page):
+ Add casts to int.
+ * refer/ref.cc (reference::insert_field, reference::delete_field):
+ Likewise.
+ * troff/number.cc (parse_term): Likewise.
+
+ * acgroff.m4 (GROFF_PROG_YACC): New macro.
+ * configure.in: Use GROFF_PROG_YACC.
+
+ * acgroff.m4 (GROFF_PROG_CCC): Don't add -O automatically for gcc
+ and g++.
+ * Makefile.in (OPTIMIZE): New define.
+ (DEBUG): Empty by default.
+ (CCFLAGS, CFLAGS): Include $(OPTIMIZE).
+
+ * acgroff.m4 (GROFF_SYS_SIGLIST): Don't quote program.
+ (GROFF_ARRAY_DELETE): Likewise.
+ (GROFF_CC_COMPILE_CHECK): Quote use of $2 and $3.
+
+ * troff/env.cc (trie::~trie): Make virtual to shut up g++.
+
+ * devps/psstrip.sed: Use different delimiter on last line (so that
+ it works with BSD 4.4 sed.)
+
+Mon Mar 29 17:07:14 1993 James Clark (jjc at jclark)
+
+ * devps/psstrip.sed: Delete comments.
+
+ * acgroff.m4 (AC_GETOPT): Don't test whether <unistd.h> declares
+ optind, opterr, optarg.
+ * lib.h: When UNISTD_H_DECLARES_GETOPT is defined, declare optind,
+ opterr, optarg.
+
+Sun Mar 28 17:44:25 1993 James Clark (jjc at jclark)
+
+ * Makefile.in (check): Dummy target.
+
+Wed Mar 3 04:53:38 1993 James Clark (jjc at jclark)
+
+ * Version 1.07 released.
+
+ * Integrate mm 1.11.
+
+ * tbl/table.cc (alphabetic_block_entry::print): start_row was used
+ where start_col was meant.
+
+Thu Feb 25 07:55:36 1993 James Clark (jjc at jclark)
+
+ * grog/grog.sh, grog/grog.pl: Recognize PH and SA as -mm macros.
+
+Wed Feb 24 10:15:34 1993 James Clark (jjc at jclark)
+
+ * troff/input.cc (token::next): Make \z\o'...' and similar things
+ work.
+
+ * env.h (MARGIN_CHARACTER_ON, MARGIN_CHARACTER_NEXT): New
+ constants.
+ (environment): Add margin_character_flags member.
+ * env.cc (environment::environment(symbol),
+ environment::environment(const environment *): Initialize
+ margin_character_flags.
+ (margin_character): Rewrite.
+ (environment::output_line): Add a margin character if
+ margin_character_flags is non-zero. Turn off the
+ MARGIN_CHARACTER_NEXT bit. If that makes margin_character_flags
+ zero, use margin_character_node without copying and then set
+ margin_character_node to 0.
+
+ * devps/DESC.in: Change minimum size to 1000.
+
+Tue Feb 23 14:57:49 1993 James Clark (jjc at jclark)
+
+ * troff/symbol.h (symbol::hash): Change return type to unsigned
+ long.
+ * troff/dictionary.cc (dictionary::lookup, dictionary::remove):
+ Add casts to int.
+
+ * test-groff: Use -r rather than -x.
+
+ * grops/psfig.diff: Include in distribution again.
+
+Mon Feb 22 09:10:44 1993 James Clark (jjc at jclark)
+
+ * Makefile.in (dist): Use gzip.
+
+Sun Feb 21 11:12:53 1993 James Clark (jjc at jclark)
+
+ * acgroff.m4 (GROFF_GETOPT): Check for declaration of getopt() in
+ unistd.h as well as in stdlib.h.
+ * include/lib.h: Include <stdlib.h> is STDLIB_H_DECLARES_GETOPT is
+ defined; otherwise include <sys/types.h> and <unistd.h> if
+ UNISTD_H_DECLARES_GETOPT is defined.
+
+ * configure.in: use builtin(include, ... rather than include(...
+ * configure: Regenerate with autoconf 1.3.
+
+ * libdriver/print.cc (printer::adjust_arc_center): Use new
+ algorithm suggested by Andy Fyfe.
+
+ * libdriver/printer.cc (printer::adjust_arc_center): New function.
+ * include/printer.h: Declare this.
+ * grops/ps.cc (ps_printer::draw): Use it.
+ * grodvi/dvi.cc (dvi_printer::draw): Use it.
+
+Fri Feb 19 23:13:51 1993 James Clark (jjc at jclark)
+
+ * Makefile.comm (.man.n): Replace macrodir by tmacdir.
+
+Thu Feb 11 16:46:59 1993 James Clark (jjc at jclark)
+
+ * eqn/main.cc (main): Handle "eqn -".
+
+Mon Jan 4 20:29:56 1993 James Clark (jjc at jclark)
+
+ * tmac/tmac.e (++): Install fix from comp.bugs.4sd.
+
+ * mm: Integrate version 1.08.
+
+ * pic/troff.cc (troff_output::finish_picture): Set
+ EQN_NO_EXTRA_SPACE reg to 0 rather than removing it.
+ * eqn/box.cc (box::extra_space): Set EQN_NO_EXTRA_SPACE_REG to 0
+ if it's not defined. Check whether the register is non-zero rather
+ than whether it's not defined.
+ * tmac.e ({, <): Make argument to \x zero if \n(0x is non-zero.
+
+ * indxbib/indxbib.cc: Move all signal handling into...
+ * indxbib/signal.c: New file.
+ * configure.in: Call AC_RETSIGTYPE.
+
+ * acgroff.m4 (GROFF_STRUCT_EXCEPTION): New macro.
+ * configure.in: Call GROFF_STRUCT_EXCEPTION.
+ * libgroff/matherr.c: Protect with ifdef HAVE_STRUCT_EXCEPTION.
+
+ * troff/input.cc (token::token, token::operator=): Work round SGI
+ C++ bug.
+ * pic/object.cc (position::position): Likewise.
+
+Mon Dec 28 21:50:21 1992 James Clark (jjc at jclark)
+
+ * pic/pic.h: Move declaration of hypot().
+
+Wed Dec 16 12:28:29 1992 James Clark (jjc at jclark)
+
+ * pic/pic.h: Declare hypot().
+
+ * pic/pic.h: Define M_PI if necessary.
+
+Thu Dec 10 12:03:29 1992 James Clark (jjc at jclark)
+
+ * tmac/tmac.e (re): Add alternative version that doesn't use groff
+ `.ta T' feature.
+
+ * devps/prologue.ps (RE): Handle the possibility that the old font
+ doesn't have a FontName entry.
+
+Wed Dec 2 10:25:29 1992 James Clark (jjc at jclark)
+
+ * tmac/tmac.e (fam): Redefine to set family in environment 2.
+ (@C): Use @fam not fam.
+
+Thu Nov 26 16:01:25 1992 James Clark (jjc at jclark)
+
+ * lookbib/lookbib.cc (main): Change type of start to const char *.
+ * lkbib/lkbib.cc (main): Likewise.
+
+ * eqn/lex.cc (definition::definition): Don't use member
+ initializer syntax for members of anonymous unions.
+
+ * troff/input.cc (input_stack::backtrace): Change type of to const
+ char *.
+
+Wed Nov 25 13:43:09 1992 James Clark (jjc at jclark)
+
+ * include/stringclass.h (class string): Declare inline friend
+ functions as inline in class declaration.
+ * troff/hvunits.h (class hunits, class vunits): Likewise.
+ * include/refid.h (class reference_id): Likewise
+ * troff/troff.h (points_to_units(units), scale(units, double)):
+ Delete declarations.
+ * libdriver/input.cc (get_char): Delete declaration.
+ * include/lib.h: Change 2nd argument of getopt from const char **
+ to char **.
+ * troff/symbol.cc (symbol::symbol): Cast `new char *[n]' to `const
+ char **' before assigning to a `const char **'.
+ * tbl/table.cc: Delete extra declarations of prints().
+
+Tue Nov 24 14:33:13 1992 James Clark (jjc at jclark)
+
+ * libgroff/font.cc (font::load_desc): Cast `new char *[n]' to `const
+ char **' before assigning to a `const char **'.
+
+ * libgroff/errarg.cc (errarg::errarg): Don't use member
+ initializer syntax for members of anonymous unions.
+
+Sat Nov 21 05:02:23 1992 James Clark (jjc at jclark)
+
+ * mm: Integrate version 1.07.
+
+Tue Nov 17 16:44:27 1992 James Clark (jjc at jclark)
+
+ * troff/input.c (translate2): Rename to
+ (translate_no_transparent).
+ (init_input_requests): Rename tr2 to trnt.
+
+Mon Nov 16 09:49:32 1992 James Clark (jjc at jclark)
+
+ * troff/charinfo.h (class charinfo): Add transparent_translate field.
+ (charinfo::set_translation, charinfo::set_special_translation):
+ Add second argument that specifies value for
+ transparent_translate.
+ (charinfo::get_translation, charinfo::get_special_translation):
+ Add optional second argument that specifies whether translation is
+ being used for transparent throughput.
+ * troff/input.cc (charinfo::set_translation,
+ charinfo::set_special_translation): Handle second argument.
+ (charinfo::charinfo): Initialize transparent_translate.
+ (translate): Split main part off into
+ (do_translate): New function. Pass argument saying whether
+ translation applies to transparent throughput.
+ (translate2): New request.
+ (init_input_requests): Bind translate2 to `tr2'.
+
+Wed Nov 11 11:43:20 1992 James Clark (jjc at jclark)
+
+ * tbl/table.h (class table): Add `nokeep' flag.
+ * tbl/main.cc (process_options): Handle `nokeep' option.
+ * tbl/table.cc (table::init_output, table::do_row, table::do_top,
+ table::do_bottom): Don't output keep/release macro definitions or
+ calls when `nokeep' option has been specified.
+
+Sat Nov 7 01:28:33 1992 James Clark (jjc at jclark)
+
+ * tmac/tmac.Xps (Xps-char): Use " as delimiter for \Z.
+
+Wed Nov 4 16:29:04 1992 James Clark (jjc at jclark)
+
+ * tbl/table.cc (table_entry::divert, block_entry::do_divert,
+ block_entry::divert, alphabetic_block_entry::divert): Add extra
+ argument giving column separation.
+ (table::compute_widths): Pass column separation to
+ table_entry::divert().
+ (block_entry::do_divert): If an entry spans multiple columns and a
+ minimumum width has been specified for each column, then set the
+ line length to the sum of the widths (plus possibly the column
+ separations).
+
+ * troff/input.cc (set_escape_char): Don't set the escape_char
+ until after calling has_arg().
+
+Tue Nov 3 11:23:27 1992 James Clark (jjc at jclark)
+
+ * tbl/table.cc (table::do_top): Add missing \s0 for double box
+ case.
+
+ * tbl/table.cc (table::print_double_hline): Avoid extra new line
+ in case where r > nrows - 1.
+
+ * tbl/table.cc (BODY_HEIGHT): Deleted.
+ (LINE_SEP): New definition.
+ (table::print_single_hline, table::print_double_hline,
+ table::compute_vrule_top_adjust, table::compute_vrule_bot_adjust,
+ table::do_row, table::do_top): Use LINE_SEP space before a line
+ instead of \n[.v]-BODY_HEIGHT-BODY_DEPTH.
+
+ * tbl/table.cc (text_entry::print_contents): New function.
+ (text_string_name, right_text_string_name): Deleted.
+ (TEXT_STRING, RIGHT_TEXT_STRING): Deleted.
+ (simple_text_entry::do_width, numeric_text_entry::do_width,
+ alphabetic_text_entry::do_width): Don't store the contents of the
+ entry in a string.
+ (left_text_entry::simple_print, right_text_entry::simple_print,
+ center_text_entry::simple_print,
+ alphabetic_text_entry::simple_print,
+ numeric_text_entry::simple_print): Print the entry directly
+ instead of using the stored string.
+
+Fri Oct 30 10:39:32 1992 James Clark (jjc at jclark)
+
+ * devps/Makefile: Strip PostScript files.
+ * devps/prologue: Rename to...
+ * devps/prologue.ps.
+ * devps/psstrip.sed: New file.
+ * devps/download: Use .pfa rather than .ps for installed versions
+ of fonts.
+
+Thu Oct 29 09:14:43 1992 James Clark (jjc at jclark)
+
+ * troff/env.cc (input_trap): Give a warning if the argument is out
+ of range.
+
+ * troff/env.cc (adjust): Treat negative argument as missing. Round
+ argument > 5 down to 5.
+
+ * troff/env.cc (center, right_justify): Make negative argument zero.
+
+ * troff/div.cc (page_offset, vertical_position_traps): Treat
+ invalid argument as missing.
+ * troff/env.cc (line_spacing, line_length, title_length, indent,
+ underline, hyphen_line_max_request, control_char,
+ no_break_control_char, widow_control_request, adjust, input_trap,
+ point_size): Likewise.
+ * troff/node.cc (ligature, kern_request, bold_font, track_kern,
+ constant_space): Likewise.
+ * troff/input.cc (compatible, shift, warn_request,
+ set_escape_char): Likewise.
+
+ * tbl/main.cc (format::format): Avoid doing `new int[0]'.
+ * tbl/table.cc (table::table): Likewise.
+
+ * Makefile.dev (install_dev): depends on $(DEVFILES).
+
+Wed Oct 28 08:30:57 1992 James Clark (jjc at jclark)
+
+ * devX75, devX75-12, devX100, devX100-12: New directories.
+ * Makefile.in: Add these to DEVDIRS.
+
+ * troff/Makefile.sub, eqn/Makefile.sub, indxbib/Makefile.sub,
+ afmtodit/Makefile.sub, tmac/Makefile.sub, nroff/Makefile.sub,
+ grog/Makefile.sub, mm/Makefile.sub (uninstall_sub): New target.
+ * Makefile.in (uninstall, uninstall_sub, uninstall_dirs): New
+ targets.
+ * Makefile.ccpg, Makefile.cpg, Makefile.dev, Makefile.man
+ (uninstall): New target.
+ * Makefile.comm (uninstall, uninstall_sub, uninstall_man,
+ uninstall_prog, uninstall_dev): New targets.
+
+ * troff/div.cc (return_request): Treat an invalid argument as
+ missing.
+
+Mon Oct 26 11:33:47 1992 James Clark (jjc at jclark)
+
+ * tmac/tmac.e ((f): Set up the environment even when there's a
+ current diversion. Transperently throughput a call to @N.
+ (@N): New macro.
+
+Thu Oct 22 05:05:59 1992 James Clark (jjc at jclark)
+
+ * tbl/table.cc (table::compute_vrule_top_adjust): Round adjustment
+ up to vertical resolution.
+
+ * tbl/table.cc (table::do_row): Change row number after printing
+ stuff list.
+
+ * pic/lex.cc (get_token_after_dot): Make .left and .right work.
+
+Wed Oct 21 14:46:45 1992 James Clark (jjc at jclark)
+
+ * Rename CHANGES to NEWS.
+
+Tue Oct 20 23:25:21 1992 James Clark (jjc at jclark)
+
+ * libgroff/new.cc (operator new): Avoid calling malloc(0).
+
+Mon Oct 19 09:10:13 1992 James Clark (jjc at jclark)
+
+ * man.ultrix: Removed.
+
+Sun Oct 18 06:35:15 1992 James Clark (jjc at jclark)
+
+ * Makefile.comm (extraclean): Delete files whose names begin with
+ `='.
+
+ * pic/troff.cc (troff_output::text): Fix typo in implementation of
+ aligned text.
+
+Sat Oct 10 09:32:29 1992 James Clark (jjc at jclark)
+
+ * troff/env.cc (hyphenate_request, vertical_spacing, no_number):
+ * troff/div.cc (page_length, need_space, space_request): Treat
+ invalid optional argument as missing.
+ * troff/env.cc (number_lines): If the first argument is present
+ but not a number, turn on line numbering, don't change the next
+ line number and parse the remaining arguments.
+
+ * tmac/tmac.e (@q): Do the `ne' before changing to environment 2.
+
+Thu Oct 8 10:24:40 1992 James Clark (jjc at jclark)
+
+ * eqn/box.h: Change declaration accordingly.
+ * eqn/box.cc (set_gsize): Change return type to int. Return 0 if
+ the specified size was bad but don't give an error. Check for
+ overflow.
+ * eqn/main.cc (main): Change caller. Leave validation to set_gsize.
+ * eqn/lex (do_size): Likewise.
+
+Wed Oct 7 09:48:59 1992 James Clark (jjc at jclark)
+
+ * acgroff.m4 (GROFF_PROG_CCC): Use fopen when checking for C++
+ compatible headers.
+
+Sun Oct 4 18:24:02 1992 James Clark (jjc at jclark)
+
+ * tbl/table.cc (table::init_output): Improve error message when
+ table won't fit on one page.
+
+Fri Oct 2 10:41:40 1992 James Clark (jjc at jclark)
+
+ * pic/troff.cc (troff_output::start_picture): Generate line
+ containing a horizontal motion equal to the width of the picture.
+
+ * groff/groff.cc (main): Allow PROG_PREFIX to be set at runtime
+ using GROFF_COMMAND_PREFIX environment variable.
+
+Fri Sep 25 11:40:40 1992 James Clark (jjc at jclark)
+
+ * mdate.sh: Use $NF rather than $(NF).
+
+Tue Sep 22 09:47:24 1992 James Clark (jjc at jclark)
+
+ * pic/main.cc (main): Use %1 not %c in argument to warning.
+
+ * eqn/main.cc (main): Output code to check that geqn was given the
+ correct -T option.
+
+Mon Sep 21 10:59:16 1992 James Clark (jjc at jclark)
+
+ * Makefile.in (dist): Instead of doing `make -f ../Makefile', do
+ `ln -s ../Makefile .; make; rm -f Makefile'.
+
+ * troff/hyphen: Rename to...
+ * troff/hyphen.us:
+ * troff/input.cc (main): Delete -H option. Don't call
+ read_hyphen_file().
+ * troff/env.cc: Include searchpath.h and macropath.h.
+ (exception_dictionary): Deleted.
+ (ht): Deleted.
+ (read_hyphen_file): Deleted.
+ (hyphenation_language): New struct.
+ (class trie, class hyphen_trie): Move declarations up.
+ (trie_node::~trie_node): Deleted.
+ (trie::delete_trie_node): New function.
+ (trie::do_delete): New pure virtual function.
+ (hyphen_trie::do_delete): New function.
+ (trie::~trie): New function.
+ (hyphen_trie::~hyphen_trie): New function.
+ (trie::clear): No need to chcek that tp is not 0.
+ (current_language, language_dictionary): New variables.
+ (hyphen_word): Give an error if no current language. Use
+ exceptions dictionary in current language.
+ (hyphen_trie::read_patterns_file): Find file using macro_path.
+ Allow comments (starting with %) in patterns file. Don't make it
+ a fatal error if the file can't be found.
+ (hyphenate): Return if no current language. Get the exceptions
+ dictionary and the hyphenation patterns from the current language.
+ (set_hyphenation_language): New variable.
+ (hyphenation_patterns_file): New function.
+ (hyphenation_language_reg): New class.
+ (hyphenation_language_reg::get_string): New function.
+ (init_hyphen_requests): Bind "hla" to set_hyphenation_language and
+ "hpf" to hyphenation_patterns_file. Initialize `.hla' number
+ register.
+ * groff/groff.cc (main, help, synopsis): Delete -H option.
+ * include/Makefile.sub: Don't define HYPHENFILE.
+ * Makefile.in: Delete hyphenfile variable and remove from MDEFINES.
+ * Makefile.comm (.man.n): Don't substitute for HYPHENFILE.
+ * tmac/troffrc: Set hyphenation language to `us'. Load `hyphen.us'
+ hyphenation patterns.
+
+Sun Sep 20 09:33:02 1992 James Clark (jjc at jclark)
+
+ * eqn/neqn.sh: New file.
+ * eqn/Makefile.sub: Handle neqn.sh.
+
+ * eqn/eqn.h: Declare `nroff' variable.
+ * eqn/box.cc (param_table): Add `nroff' param.
+ (nroff): Define it.
+ * eqn/lex.cc (yylex): Handle TDEFINE and NDEFINE using `nroff'
+ variable.
+ * tmac/eqnrc: Set `nroff' to 1 for -Tascii or -Tlatin1.
+
+ * troff/troff.h (WARN_FONT): New warning.
+ (WARN_TOTAL): Change accordingly.
+ * troff/input.cc (DEFAULT_WARNING_MASK): Include WARN_FONT.
+ (warning_table): Add WARN_FONT.
+ * troff/node.cc (mount_font_no_translate): Pass argument to
+ font::load_font. If this is non-zero, give a warning.
+ Don't give an error message when accessing a font that has already
+ been found to be invalid.
+ * include/font.h (font::load, font::load_font): Add additional
+ optional argument which suppresses error message if the font is
+ not found.
+ * libgroff/font.cc (font::load_font): Handle additional argument.
+ (font::load): Add additional argument. If this is non-null, set it
+ to 1 and don't give error message.
+
+ * include/printer.h (printer::end_page): Add argument giving
+ length of page.
+ * libdriver/input.cc (do_file): Pass this.
+ * grops/ps.cc (ps_printer::end_page): Add argument.
+ * grodvi/dvi.cc (dvi_printer::end_page,
+ draw_dvi_printer::end_page): Add argument.
+ * grotty/tty.cc (class tty_printer): Remove lines_per_page and
+ columns_per_page members. New member nlines.
+ (DEFAULT_LINES_PER_PAGE): Deleted.
+ (tty_printer::tty_printer): Don't compute lines_per_page from
+ font::paperlength. Don't compute columns_per_page from
+ font::paperwidth.
+ (tty_printer::add_char): Don't check horizontal position against
+ columns_per_page. Grow glyphs vector if neccessary.
+ (tty_printer::end_page): Add argument giving page_length in units.
+ Discard lines past end of page.
+
+Wed Sep 16 06:29:52 1992 James Clark (jjc at jclark)
+
+ * tmac/tmac.tty-char: Fix definition of \(/l.
+
+ * tmac/tmac.X: Define \(en.
+
+Tue Sep 15 10:37:13 1992 James Clark (jjc at jclark)
+
+ * acgroff.m4 (GROFF_PRINT): If a system has lpr and lp but not
+ lpq, then use lp rather than lpr.
+
+ * tmac/tmac.s (par@reset): Don't call `ad'.
+ (par*env-init): Call `ad'.
+
+Sun Sep 13 18:48:20 1992 James Clark (jjc at jclark)
+
+ * mdate.sh: Use $(NF) instead of $6 to extract year from output of
+ date.
+
+ * troff/symbol.cc: #undef BLOCK_SIZE if it's defined.
+ * indxbib/indxbib.cc: Likewise.
+
+Sun Sep 6 09:44:46 1992 James Clark (jjc at jclark)
+
+ * libgroff/putenv.c: New file.
+ * libgroff/Makefile.sub: Add putenv.c to CSRCS.
+ * Makefile.in: Say that putenv.o can be one of LIBOBJS.
+ * configure.in: Test for putenv with AC_REPLACE_FUNCS. Test for
+ stdlib.h with AC_HAVE_HEADERS.
+
+Sat Sep 5 18:11:52 1992 James Clark (jjc at jclark)
+
+ * indxbib/dirnamemax.c: Include <sys/dir.h> only if <dirent.h>
+ does not exist.
+
+Fri Sep 4 09:43:26 1992 James Clark (jjc at jclark)
+
+ * eqn/box.cc (gsize): Make it an int.
+ (set_gsize): Parse argument handling increment or decrement.
+ (box::top_level): Convert gsize to a string.
+
+ * troff/input.cc (exit_troff): Make buf unsigned char [].
+ Call to make_temp_iterator casts buf to char*.
+
+ * Makefile.in ($(TARGETS), dot): Pass $(MDEFINES) to recursive makes.
+
+ * Makefile.ccpg (depend.temp): Depends on $(YTABC).
+ * Makefile.cpg (depend.temp): Likewise.
+
+ * Makefile.dep: Remove Makefile.dep from $(REALCLEANFILES).
+
+ * Makefile.comm: Add y.output to MOSTLYCLEANFILES.
+
+Thu Sep 3 08:01:55 1992 James Clark (jjc at jclark)
+
+ * tmac/tmac.s (B, I, BI, CW): Rewrite avoiding aliases.
+
+Tue Sep 1 18:24:53 1992 James Clark (jjc at jclark)
+
+ * Version 1.06 released.
+
+ * Integrate mm 1.04.
+
+Fri Aug 28 11:28:19 1992 James Clark (jjc at jclark)
+
+ * Makefile.comm, Makefile.ccpg, Makefile.cpg: Fix TAGS target.
+
+Thu Aug 27 11:03:33 1992 James Clark (jjc at jclark)
+
+ * afmtodit/afmtodit.pl: Add -n option that disables generation of
+ ligatures command.
+ * devps/generate/Makefile (CR, CB, CI, CBI): Pass -n flag to
+ afmtodit. Regenerate.
+
+ * tmac/tmac.e ()z): Adjust _b if necessary so as to avoid moving
+ @f back past the current position.
+
+ * tmac/tmac.e: Change calls to @R so that comments are not part of
+ arguments.
+
+Tue Aug 25 10:42:07 1992 James Clark (jjc at jclark)
+
+ * configure.in: Check for mkstemp with AC_HAVE_FUNCS.
+
+ * acgroff.m4 (GROFF_PROG_CCC): Don't check for <osfcn.h>. Instead
+ check that we can link a call to a function declared in <stdio.h>.
+ (GROFF_UNISTD_H): New macro.
+ * configure.in: Call it.
+ * Makefile.in: Document it.
+ * include/posix.h: New file.
+ * troff/troff.h: Don't include <osfcn.h>
+ * troff/input.cc: Include posix.h.
+ * libgroff/new.cc, libgroff/tmpfile.cc: Include posix.h rather than
+ osfcn.h.
+ * indxbib/indxbib.cc, libbib/{search.cc,linear.cc,index.cc}:
+ Include posix.h rather <sys/types.h>, <sys/stat.h>, <osfcn.h>,
+ <fcntl.h>.
+ * indxbib/indxbib.cc (S_IRUSR, S_IRGRP, S_IROTH): Delete definitions.
+ * libbib/index.cc (S_ISREG, O_RDONLY): Delete definitions.
+ * libbib/search.cc (O_RDONLY): Delete definition.
+ * refer/refer.cc, include/driver.h, pic/pic.h, groff/groff.cc:
+ Don't include <osfcn.h>.
+
+ * acgroff.m4 (GROFF_TIME_T): New macro.
+ * configure.in: Call it.
+ * Makefile.in: Document it.
+
+ * acgroff.m4 (GROFF_TRADITIONAL_CPP): New macro.
+ * configure.in: Call it.
+ * Makefile.in: Document -DTRADITIONAL_CPP.
+ * include/ptable.h: Don't include generic.h.
+ (name2): Define it.
+
+ * tmac/tmac.s (][): Make [T1 and [T2 aliases for [T.
+ Afterwards remove [T1 and [T2.
+ (ref*spec!0, ref*spec!2): Use T1 rather than T.
+ (ref*spec!1, ref*spec!4, ref*spec!4): Use T2 rather than T.
+ (ref*add-T2): Renamed from ref*add-T.
+ (ref*add-T1): New macro.
+
+Mon Aug 24 11:11:11 1992 James Clark (jjc at jclark)
+
+ * acgroff.m4 (AC_PROG_CCC): Use GROFF_EXIT rather than exit 1.
+
+ * libbib/index.cc: Include <fcntl.h>.
+ (O_RDONLY): Define if necessary.
+ (make_index_search_item, index_search_item_iterator::get_tag,
+ index_search_item::check_files): Use O_RDONLY.
+ * libbib/seach.cc: Include <fcntl.h>, <sys/types.h>, <sys/stat.h>.
+ (O_RDONLY): Define if necessary.
+ (search_list::add_file): Use O_RDONLY.
+ * indxbib/indxbib.cc: Include <fcntl.h>, <sys/types.h>,
+ <sys/stat.h>.
+ (S_IRUSR, S_IRGRP, S_IROTH): Define if necessary.
+ (main): Use these.
+
+ * libbib/index.cc (S_ISREG): Define it if necessary.
+ (index_search_item::load): Use S_ISREG.
+
+ * include/driver.h: Include <errno.h>.
+
+Sun Aug 23 11:32:18 1992 James Clark (jjc at jclark)
+
+ * eqn/box.cc (body_height): Increase default value to 85.
+ (body_depth): Increase default value to 35.
+
+Fri Aug 21 05:34:42 1992 James Clark (jjc at jclark)
+
+ * eqn/pbox.h (SAVE_FONT_STRING): Define it.
+ * eqn/box.cc (box::top_level): Hide use of \R in a string that is
+ protected from expansion with \E.
+
+ * acgroff.m4 (GROFF_PAGE): Use `case' to test domain.
+
+ * Makefile (Makefile): New target.
+
+ * Makefile.sub (configure, distfiles): New targets.
+
+ * acgroff.m4 (GROFF_BROKEN_SPOOLER_FLAGS): Avoid using ${var:-val}
+ construct.
+
+Thu Aug 20 12:27:26 1992 James Clark (jjc at jclark)
+
+ * eqn/box.cc (param_table): Add body_height and body_depth.
+
+ * eqn/lex.cc (def_table): Make circumflex in hat_def roman.
+
+Tue Aug 18 16:24:25 1992 James Clark (jjc at jclark)
+
+ * psbb/Makefile.sub: Don't link with libgroff.a.
+
+ * acgroff.m4 (GROFF_PUTENV): New macro.
+ * configure.in: Call GROFF_PUTENV.
+ * Makefile.in: Document STDLIB_H_DECLARES_PUTENV.
+ * groff/groff.cc: Don't declare putenv if STDLIB_H_DECLARES_PUTENV
+ is defined.
+
+ * troff/env.cc (distribute_space): Rename force_forward argument
+ to force_reverse. Reverse the list if force_reverse is true.
+
+Mon Aug 17 17:49:05 1992 James Clark (jjc at jclark)
+
+ * tmac/tmac.an: Don't define a string `T'. Just define Tm.
+
+ * eqn/pile.cc (matrix_box::compute_metrics): Don't allow computed
+ height or depth to be negative. Guard against SUP_RAISE quantity
+ being negative.
+
+Sat Aug 15 08:18:54 1992 James Clark (jjc at jclark)
+
+ * devps/generate/textmap: Add `an' (arrowhorizex).
+ * tmac/tmac.ps: \(an overlaps horizontally.
+ * tmac/tmac.dvi, tmac/tmac.tty: Add `an'.
+
+ * devps/symbolchars: Add arrowverttp, arrowvertbt.
+ * devps/textmap: Add arrowvertex.
+ * eqn/delim.cc (delim_table): Add uparrow, downarrow and
+ updownarrow delimiters.
+ * tmac/tmac.ps, tmac/tmac.X: Add definition of \(va.
+
+ * tbl/table.cc (simple_entry::position_vertically,
+ block_entry::position_vertically): For a centered entry, perform
+ the motion in two stages.
+
+ * refer/refer.cc (split_punct): Don't call lookup_token if there
+ is no token.
+
+Fri Aug 14 11:14:58 1992 James Clark (jjc at jclark)
+
+ * troff/input.cc (token::next): Delete token_node after copying
+ token.
+
+ * grodvi/grodvi.cc (dvi_printer::dvi_printer): Initialize
+ cur_point_size.
+
+ * libdriver/printer.cc (printer::load_font): Delete old_font_table.
+
+ * grops/ps.cc (ps_printer::define_encoding): Delete elements of vec.
+
+Tue Aug 11 13:50:38 1992 James Clark (jjc at jclark)
+
+ * grops/ps.cc (usage): -b option takes an argument.
+
+ * devps/prologue (PLG): New procedure.
+ * grops/ps.cc (main, usage): New -g option.
+ (ps_printer::~ps_printer): If guess_flag is set, guess the paper
+ length using PLG.
+
+Mon Aug 10 11:17:53 1992 James Clark (jjc at jclark)
+
+ * include/cset.h: Include <limits.h> if we have it.
+
+ * libgroff/illegal.cc: New file.
+ * include/lib.h (illegal_input_char): Use table.
+ * troff/input.cc (ESCAPE_RIGHT_PARENTHESIS): Renumber to 0206.
+ * pic/lex.cc (ARG1): Renumber to 14.
+ * eqn/lex.cc (ARG1: Likewise.
+
+ * troff/Makefile.sub (majorminor.cc): Handle 3 part versions
+ (eg 1.05.90) correctly.
+
+Sun Aug 9 13:35:43 1992 James Clark (jjc at jclark)
+
+ * tmac/tmac.e (sr): Deleted. Set $r and $R directly.
+ Rename $r and $R registers to $v and $V.
+ ($r, $R): Initialize to 0.
+ (@v, @V): New macros.
+ (sz): Call @v.
+ (@M): Call @V.
+
+ * troff/input.cc (main, usage): Add -R option that says not to
+ load troffrc.
+ * eqn/main.cc (main, usage): Rename -n to -R.
+
+Sat Aug 8 00:16:00 1992 James Clark (jjc at jclark)
+
+ * devps/DESC.in: Leave font positions 5-9 blank.
+ * devdvi/DESC.in: Likewise.
+
+ * grog/grog.pl: Handle `.PS <file' correctly.
+
+ * troff/input.cc (input_stack::push): Improve error message when
+ input stack limit exceeded.
+
+Fri Aug 7 13:08:16 1992 James Clark (jjc at jclark)
+
+ * refer/refer.cc (main): Fix typo in handling of `a' option.
+
+ * refer/refer.cc (do_bib): In state START after a newline remain
+ in state START.
+
+ * groff/groff.sh: Deleted.
+ * groff/Makefile.sub: Delete handling of groff.sh.
+
+ * pic/troff.cc (troff_output::text): Test \n(0p rather than \*(.T
+ to determine whether to use \X'ps:...'.
+ * tmac/troffrc: Set 0p register to 0.
+ * tmac/tmac.ps: Set 0p register to 1.
+
+ * groff/groff.cc: Support -X option. Give warning for -TXps and
+ transform to -X -Tps. Pass troff a -r.X=1 option if -X is used.
+ * tmac/troffrc: Support -r.X=1.
+
+ * pic/troff.cc (troff_output::dot): Don't test
+ zero_length_line_flag.
+
+Thu Aug 6 13:32:08 1992 James Clark (jjc at jclark)
+
+ * include/lib.h: Declare getopt() and friends unless
+ STDLIB_H_DECLARES_GETOPT is defined.
+
+ * doc/chars.tr: Delete.
+ * man/groff_char.man: New file.
+
+Wed Aug 5 00:38:58 1992 James Clark (jjc at jclark)
+
+ * tmac/tmac.e (np, bu): Test \n($p with string expression in case
+ user has changed register format.
+
+Mon Aug 3 11:22:18 1992 James Clark (jjc at jclark)
+
+ * groff/groff.cc: Get rid of device_table. Get postprocessor from
+ `postpro' command in DESC file. Get spooler command from `print'
+ command in DESC file. Execute spooler command with /bin/sh.
+
+ * groff/groff.cc: Split Unix-specific parts into...
+ * groff/pipeline.c: New file.
+
+ * LICENSE: Delete.
+ * COPYING: New file.
+ * all files: Update copyright notices.
+
+ * Rearrange files. Redo Makefiles. Use autoconf.
+
+Sat Aug 1 09:36:50 1992 James Clark (jjc at jclark)
+
+ * troff/input.c (charinfo_to_node_list): Interpret character
+ definition with escape_char of `\'.
+
+Tue Jul 28 12:20:12 1992 James Clark (jjc at jclark)
+
+ * lib/strerror.c, lib/iftoa.c, lib/itoa.c: Don't include lib.h.
+ Define INT_DIGITS as big enough for 64-bit integer.
+ * lib/strtol.c: Don't include lib.h.
+ * lib/lib.h: Delete ifdef __cplusplus stuff.
+
+Mon Jul 27 11:08:50 1992 James Clark (jjc at jclark)
+
+ * ps/devps/Makefile: Add DESC to DEVICEFILES. Separate out rule
+ for making DESC. Make $(FONTS) depend on DESC. afmtodit should
+ get DESC from current directory.
+
+Sun Jul 26 15:38:26 1992 James Clark (jjc at jclark)
+
+ * tbl/main.c (main): Always reset the line number when reading
+ from stdin.
+
+ * tbl/table.c (table::print_single_hline, table::print_double_hline,
+ table::define_bottom_macro, table::do_row, table::do_top): Round
+ vertical spacing up to vertical resolution.
+
+Fri Jul 24 14:32:07 1992 James Clark (jjc at jclark)
+
+ * ps/ps.h (enum resource_type): Avoid comma at end of
+ enumerator-list.
+ * dvi/dvi.c (class dvi_printer): Likewise.
+ * dvi/tfmtodit.c (gf::load): Likewise.
+ * refer/label.y (struct expression): Likewise.
+ * refer/refer.c (class label_processing_state): Likewise.
+ * refer/indxbib.c (do_file): Likewise.
+ * troff/troff.c (enum warning_type): Likewise.
+ * tbl/main.c (process_data): Likewise.
+ * troff/charinfo.h (class charinfo):
+
+Wed Jul 22 09:17:58 1992 James Clark (jjc at jclark)
+
+ * dvi/devdvi/textt.map: Add entry for `-'. Regenerate fonts.
+
+Tue Jul 21 11:39:26 1992 James Clark (jjc at jclark)
+
+ * groff.c: Move to new groff subdirectory.
+ * groff/Makefile: New file.
+ * Makefile: Remove handling of groff.c. Add groff to SUBDIRS.
+
+ * man/mdate.sh: Use ls -L if supported.
+
+ * Consolidate all header files produced by gendef into lib/defs.h.
+ * lib/macropath.c, lib/fontfile.c, lib/device.c: Include defs.h.
+ Don't include path.h.
+ * lib/Makefile (path.h): Don't generate.
+ * troff/input.c: Include defs.h. Don't include config.h.
+ * troff/Makefile (config.h): Don't generate.
+ * refer/index.h: Don't include suffix.h.
+ * refer/index.c: Include defs.h.
+ * refer/indxbib.c: Include defs.h.
+ * refer/refer.h, refer/lkbib.h: Don't include path.h. Include
+ defs.h.
+ * refer/Makefile (suffix.h, path.h): Don't generate.
+ * groff.c: Don't include config.h. Include defs.h.
+ * Makefile (config.h): Don't generate.
+ (lib/defs.h): Generate.
+ (topclean): Remove lib/defs.h.
+
+Mon Jul 20 10:12:57 1992 James Clark (jjc at jclark)
+
+ * lib/malloc.c, lib/getpagesize.h: Deleted.
+ * Makefile: Add COOKIE_BUG configuration option. Delete malloc
+ related stuff.
+ * lib/Makefile: Delete malloc-related stuff.
+ * lib/new.c: Workaround COOKIE_BUG if necessary.
+
+ * refer/lkbib.c, refer/indxbib.c: Don't include refer.h. Include
+ needed header files directly.
+ * refer/refer.h: Omit definition of DEFAULT_INDEX.
+ * Makefile: Include definition of DEFAULT_INDEX in path.h.
+
+Sun Jul 19 10:19:22 1992 James Clark (jjc at jclark)
+
+ * lib/font.c (FONT_COMMAND_HANDLER): Pass command name and single
+ argument.
+ * lib/font (font::load_desc, font::load): Don't split argument of
+ unknown command.
+ (font::handle_unknown_font_command): Change type.
+ * ps/ps.c (ps_font::handle_unknown_font_command,
+ handle_unknown_desc_command): Change type.
+ * dvi/dvi.c (dvi_font::handle_unknown_font_command): Change type.
+
+Fri Jul 17 11:12:49 1992 James Clark (jjc at jclark)
+
+ * lib/font.h (font::handle_unknown_font_command): Add file and
+ line arguments.
+ * lib/font.c (font::handle_unknown_font_command):
+ * ps/ps.c (ps_font::handle_unknown_font_command):
+ * dvi/dvi.c (dvi_font::handle_unknown_font_command): Add file and
+ lineno arguments. Use _with_file_and_line functions for error
+ reporting.
+
+ * lib/fontfile.c (font::unknown_desc_command_handler): New static
+ data member.
+ * lib/font.c (font::set_unknown_desc_command_handler): New
+ function.
+ (font::load_desc): For unknown commands, call
+ unknown_desc_command_handler if not null.
+ * lib/font.h (class font): Declare them.
+ (FONT_COMMAND_HANDLER): New typedef.
+ * ps/ps.c (handle_unknown_desc_command): New function.
+ (main): Set bflag if we had a -b option. Call
+ font::set_unknown_desc_command_handler.
+ (broken.h): Don't include.
+ * ps/Makefile: No need for broken.h. Pass BROKEN_SPOOLER_FLAGS to
+ submake
+ * ps/devps/Makefile: Add `broken' command to DESC file using
+ BROKEN_SPOOLER_FLAGS.
+
+ * macros/tmac.e ([, ]): Add as synonyms for { and }.
+
+ * macros/tmac.e ($p): Only exdent if \$3 > 0.
+
+ * macros/tmac.e (@R, @S): New macros.
+ Declare @, po, $0, $i, $p, df, so, fu, bt, *, ?a, ?b, ?C, ?e, ?H,
+ ?I, ?n, ?o, ?R, ?s, ?T, ?W, ?w registers with @R.
+ Declare $H, $[0-9], .. macros with @S.
+ Declare |0, |1, |2, |3 strings with @S.
+
+ * macros/tmac.e (@S): Rename to @U.
+
+ * macros/tmac.e (@z): Define @b and bp as empty instead of
+ deleting them,
+
+ * macros/tmac.e (@m): Deleted.
+ (@h): Don't call @m.
+ (@z): Don't set @m trap.
+
+ * macros/tmac.e ($h, $f): Define |z as empty string.
+
+ * macros/tmac.e (@D): Rework to avoid unbalanced .el requests.
+ (@q): Likewise.
+
+ * macros/tmac.e (@h): Set ?H, ?C , ?s registers to 0 rather than
+ removing them.
+ ()f): Likewise for * register.
+
+ * macros/tmac.e (sr): Don't ever scale the arguments. If the third
+ argument is missing, don't change $R. Call sr with three
+ arguments when initializing.
+
+Thu Jul 16 12:17:12 1992 James Clark (jjc at jclark)
+
+ * macros/tmac.e (sr): New macro.
+ Initialize $r and $R using sr.
+
+ * macros/tmac.e (,): Delete \*(#[.
+
+ * troff/env.c (set_tabs): Read the tab type even if the position
+ is bad. Allow the position of the first tab stop to be negative.
+
+Wed Jul 15 13:14:37 1992 James Clark (jjc at jclark)
+
+ * refer/dirnamemax.c: Use pathconf() if <unistd.h> defines
+ _POSIX_VERSION.
+ * refer/Makefile: Compile dirnamemax.c using -DHAVE_UNISTD_H
+ rather than -DPATHCONF_MISSING.
+ * Makefile: Get rid of PATHCONF_MISSING.
+
+ * refer/map.c: New file.
+ * refer/index.c: Interface to mmap through map.c. Rename map_size
+ to map_len.
+ * refer/Makefile: Handle map.c.
+ * Makefile: Include -DHAVE_MMAP in OLDCFLAGS rather than CFLAGS.
+
+Tue Jul 14 14:15:20 1992 James Clark (jjc at jclark)
+
+ * Makefile: RANLIB should be `true' if there is no ranlib.
+ * lib/Makefile (libgroff.a): Simplify.
+ * driver/Makefile (libdriver.a): Simplify.
+
+ * Makefile: Change -DWAIT_COREDUMP_0200 to -DWCOREFLAG=0200.
+ * groff.c (WCOREDUMP): Use WCOREFLAG. Define only if not already
+ defined.
+
+Sat Jul 11 09:19:17 1992 James Clark (jjc at jclark)
+
+ * troff/env.c (compare_ranges): Declare as extern "C".
+
+ * troff/input.c (init_registers): Use `struct tm' instead of `tm'.
+
+ * macros/tmac.s, macros/tmac.e: Change .nx /dev/null to .nx.
+
+Wed Jul 8 11:52:27 1992 James Clark (jjc at jclark)
+
+ * pic/troff.c (troff_output::text): Merge in grops_output::text,
+ but conditionalize use of \X based on \*(.T.
+ (grops_output::*): Deleted.
+ * pic/output.h: Delete declaration of make_grops_output.
+ * pic/main.c (main): Ignore -p and -x. driver_extension_flag is 1
+ by default. -n sets it to 0.
+ (usage): Corresponding changes.
+ * groff.c (main): Don't pass -x or -p to pic.
+ * groff.sh: Likewise.
+
+ * ps/ps.c (ps_printer::do_exec, ps_printer::do_file): Force ndefs
+ to be non-zero.
+
+ * ps/devps/afmtodit: Change calculation of asc_boundary and
+ desc_boundary. Make these bounds inclusive.
+ * ps/devps: Regenerate font files.
+
+Tue Jul 7 13:14:15 1992 James Clark (jjc at jclark)
+
+ * macros/tmac.latin1: New file.
+ * macros/tmac.tty-char: Use tmac.latin1.
+ (tmac.tty-tr): Deleted.
+ * macros/Makefile: Install tmac.latin1.
+ * macros/tmac.dvi: Use tmac.latin1.
+ * macros/troffrc: Translate \[char160] onto no-break space here.
+ * macros/{tmac.dvi,tmac.ps,tmac.tty,tmac.X75}: Don't do it here.
+
+Mon Jul 6 11:06:52 1992 James Clark (jjc at jclark)
+
+ * macros/tmac.Xps: Use `do' request.
+
+ * macros/tmac.ps: Use `do' request.
+
+ * macros/tmac.e (@C): Use `do' request.
+
+ * macros/tmac.X, macros/tmac.Xps: Moved from xditview.
+ * macros/Makefile: Install tmac.X*.
+
+ * tty/tmac.tty, tty/tmac.tty-char: Move to macros.
+ * tty/Makefile: Don't install tmac.tty*.
+ * macros/Makefile: Install tmac.tty*.
+
+ * dvi/tmac.dvi: Move to macros.
+ * dvi/Makefile: Don't install tmac.dvi.
+ * macros/Makefile: Install tmac.dvi.
+
+ * ps/tmac.ps*: Move to macros.
+ * ps/Makefile: Don't install tmac.ps*.
+ * macros/Makefile: Install tmac.ps*.
+
+ * eqn/box.c: Provide draw_lines parameter corresponding to -D
+ option.
+ * macros/eqnrc: Set draw_lines parameter based on device.
+ * groff.c: Don't pass -D flag to eqn.
+ * groff.sh: Likewise.
+ * eqn/main.c: Warn about use of -D.
+
+ * troff/input.c (process_startup_file): New function.
+ (main): Call process_startup_file().
+ * macros/troffrc: New file.
+ * macros/Makefile: Install troffrc.
+ * groff.c (main): Don't pass extra -m option to troff. For a
+ pseudo device pass the name of the pseudo device to troff using
+ -d.
+ * groff.sh: Likewise.
+ * groff.c (possible_command::prepend_arg): Deleted.
+
+ * troff/input.c (do_request): New function.
+ (init_input_requests): Bind "do" to do_request.
+
+ * eqn/main.c (main): Instead of loading eqnchar from device directory,
+ load eqnrc from macro directory.
+ * macros/eqnrc: New file.
+ * macros/Makefile: Install eqnrc.
+ * ps/devps/eqnchar: Deleted.
+ * ps/devps/Makefile: Don't install eqnchar.
+ * dvi/devdvi/eqnchar: Deleted.
+ * dvi/devdvi/Makefile: Don't install eqnchar.
+ * groff.c (main): Pass -M to eqn. Don't pass -F to eqn. New
+ variable optM.
+
+ * lib/device.[ch]: New files.
+ * lib/font.h (font::set_device_name, font::get_device_name):
+ Deleted.
+ * lib/fontfile.c: Use device.h.
+ * lib/Makefile: Handle device.[ch]. Make paths.h define DEVICE.
+ * troff/input.c: Delete definition of `device'.
+ (main): Don't initialize device.
+ * troff/troff.h: Include device.h rather than declaring device.
+ * troff/Makefile: No need to handle DEVICE.
+ * driver/input.c: Include device.h. Don't use
+ font::{set,get}_device_name.
+ * groff.c, Makefile: Rename device.h to config.h.
+ * groff.c: Use library device variable.
+ * eqn/main.c: Use library device variable.
+ * eqn/Makefile: No need to handle DEVICE.
+
+ * lib/searchpath.[ch]: New files.
+ * lib/Makefile: Handle searchpath.[ch].
+ * troff/input.c (open_file, init_dirs): Deleted.
+ (macro_dirs): Deleted.
+ (open_mac_file, macro_source): Use class search_path.
+ (add_string, struct string_list): Move definition.
+ (main): Change -M option to use macro_path. Delete call to
+ init_dirs().
+ * lib/fontfile.c (font::command_line_font_dir, font::open_file):
+ Rewrite to use class search_path.
+ * lib/font.h, lib/fontfile.c (font::cl_font_dirs): Deleted.
+ * lib/Makefile: fontfile.c depends on searchpath.h.
+ * lib/Makefile: Rename fontpath.h to paths.h. Make paths.h define
+ MACROPATH.
+ * lib/macropath.[ch]: New files.
+ * troff/Makefile: No need to handle MACROPATH.
+
+ * troff/input.c: Delete DUMP code.
+ * lib/fontfile.c, lib/font.h: Delete
+ font::forget_command_line_font_dirs.
+
+ * troff/input.c (push_token): New function.
+ (handle_first_page_transition): Use push_token().
+ (process_input_stack): Change handling of a space at the beginning
+ of the line.
+
+Sun Jul 5 17:11:09 1992 James Clark (jjc at jclark)
+
+ * troff/input.c (font_dirs): Delete unused variable.
+
+ * eqn/lex.c (do_set): Correct error messages.
+
+Sat Jul 4 10:20:55 1992 James Clark (jjc at jclark)
+
+ * troff/input.c (do_define_string): Allow the string name to be
+ followed immediately by a tab.
+ (define_character): Likewise.
+
+Thu Jul 2 10:59:15 1992 James Clark (jjc at jclark)
+
+ * ps/ps.c (ps_printer::draw): When drawing an arc, don't allow k to
+ be negative.
+
+ * troff/input.c (input_iterator::is_file): New virtual function.
+ (file_iterator::is_file): New function.
+ (input_stack::end_file): New function.
+ (input_stack::next_file): Handle the situation where there is no
+ file on the input stack correctly. Avoid making two passes over
+ the input stack.
+ (next_file): Make the filename optional; in this case call
+ input_stack::end_file().
+
+Wed Jul 1 10:17:25 1992 James Clark (jjc at jclark)
+
+ * dvi/tmac.dvi: Change the definitions of \(ul and _ so that they
+ produce a real _ charater when the current font is CW and _
+ otherwise.
+
+ * lib/errarg.c (errarg::errarg(const char *)): Invert conditional
+ expression to work around gcc 2.2 bug.
+
+Wed Jun 24 08:12:24 1992 James Clark (jjc at jclark)
+
+ * eqn/main.c (main): Don't give an error if we can't find eqnchar.
+
+ * troff/env.c (environment::add_padding): New function.
+ (environment::add_char): Use add_padding().
+ (environment::space): Likewise.
+ (environment::wrap_up_field): Add some padding if there is none
+ and there's no current tab.
+ * troff/env.h: Declare environment::add_padding.
+
+Mon Jun 22 08:37:45 1992 James Clark (jjc@jclark)
+
+ * pic/pic.y: undef fmod and rand before declaring them.
+
+Sun Jun 14 11:40:18 1992 James Clark (jjc@jclark)
+
+ * troff/input.c (main): If the DESC file specifies a font name of
+ 0, then leave the corresponding font position empty.
+
+ * nroff.sh: New file.
+ * Makefile (install.nobin): Install nroff.sh.
+
+ * tty/devlatin1/R.proto: Add ao as synonym for de.
+ * tty/tmac.tty-char: Define ao as o.
+
+ * tty/dev{ascii,latin1}/R.proto: Add aq.
+ * tty/tmac.tty-char: Delete definition of aq.
+
+Mon Jun 8 11:43:20 1992 James Clark (jjc@jclark)
+
+ * troff/input.c (init_charset_table): Don't translate 0240.
+ * ps/tmac.ps: Translate char160 to space.
+ * dvi/tmac.dvi: Likewise.
+ * tty/tmac.tty: Likewise.
+
+Sun Jun 7 10:52:35 1992 James Clark (jjc@jclark)
+
+ * dvi/tmac.dvi: Add support for all Latin-1 characters.
+
+ * macros/tmac.s: Delete definitions of \(rg, \(ah, \(ad, \(a-,
+ \(ao, \(ac, \(ho, \(-D, \(Sd, \(TP, \(Tp, \(ss, \(AE, \(ae, \(OE,
+ \(oe, \(r?, \(r!.
+
+ * tty/tmac.tty-char: Add \(ah.
+
+ * dvi/tmac.dvi: Add definitions of Tp, TP, Sd, -D, ho.
+ No need to define \(FM and \(!/. Conditionalize all character
+ definitions.
+
+ * ps/devps/lgreekmap: Add +h, +f, +p.
+
+ * ps/tmac.psnew: New file.
+ * ps/Makefile: Install tmac.psnew.
+
+ * troff/input.c (charinfo_to_node_list): Don't ever interpret
+ character definitions in compatible mode.
+
+ * troff/input.c (remove_character): New function.
+ (init_input_requests): Bind remove_character to "rchar".
+
+ * ps/tmac.psold: New file.
+ * ps/Makefile: Install tmac.psold.
+ * ps/tmac.ps: Load tmac.psold. Move definitions of ISO Latin-1
+ characters into tmac.psold. Make these definitions unconditional.
+
+ * tty/tmac.tty-char: Define \n(_C only if it is not already defined.
+
+ * ps/tmac.ps: Don't define \('c and \('C.
+
+ * ps/devps/textmap: Move Greek characters to...
+ * ps/devps/symbolchars:
+
+Sat Jun 6 16:41:17 1992 James Clark (jjc@jclark)
+
+ * ps/devps/text.enc: Add quotesingle.
+ * ps/devps/textmap: Add +h, +f, +p, Fn, Bq, bq, aq, lz.
+ * tty/tmac.tty-char: Likewise.
+ * dvi/devdvi/texmi.map: Add +h, +f, +p.
+ * dvi/devdvi/texi.map: Add Fn.
+ * dvi/devdvi/msam.map: Add lz.
+ * dvi/tmac.dvi: Handle Bq, bq, aq.
+
+ * pic/lex.c (get_token): Recognize 'th.
+ * pic/map.y: Allow `expr'th in contexts where ORDINAL was allowed.
+
+Fri Jun 5 11:20:46 1992 James Clark (jjc@jclark)
+
+ * ps/devps/textmap: Move di, mu, +- to...
+ * ps/devps/symbolchars:
+
+ * macros/tmac.s (@XS): Don't call par@reset or fi.
+ (XA): Call LP. Turn off adjustment. Reduce line length.
+
+ * macros/tmac.s: Initially alias XS to LP.
+ (XS): Rename to @XS.
+ (cov*ab-init): Alias XS to @XS.
+
+Thu Jun 4 09:12:05 1992 James Clark (jjc@jclark)
+
+ * troff/token.h: Delete TOKEN_CHAR_HEIGHT, TOKEN_CHAR_SLANT,
+ TOKEN_FONT_NAME, TOKEN_FONT_POSITION, TOKEN_SIZE tokens.
+ (token::is_size, token::changes_env): Deleted.
+ * troff/number.c (parse_term): No need to process \s explicitly.
+ Call tok.next() only after scale indicator has been processed.
+ * troff/input.c (do_overstrike, do_bracket): No need to process \s,
+ \f etc explicitly.
+ (token::next): Handle \s, \f, \S, \H immediately rather than
+ returning them as tokens.
+ (token::operator==, token::description, token::add_to_node_list,
+ token::process): Remove handling of deleted tokens.
+
+ * troff/env.c (environment::add_char): When adding padding
+ indicator character, call start_line() if necessary.
+
+Wed Jun 3 09:55:50 1992 James Clark (jjc@jclark)
+
+ * ps/devps/afmtodit: Don't output 0 kerns.
+
+ * ps/devps/afmtodit: Remove directory from name of encoding in
+ font description file.
+
+ * ps/devps/afmtodit: Improve error messages.
+
+ * ps/devps/afmtodit: Allow DESC file to be specified with -d.
+
+ * ps/devps/Makefile: Incorporate FontMakefile. Rework.
+ * ps/devps/FontMakefile: Deleted.
+ * ps/devps/afmname: New file.
+
+ * ps/devps/symbol.sed: New file.
+ * ps/devps/symbol.diff: Deleted.
+ * ps/devps/FontMakefile: Generate symbol.afm using symbol.sed.
+ Generate zapfdr.afm from zapfd.afm.
+
+ * tty/tmac.tty (tty-char): Prefix definition with ".
+
+ * macros/tmac.an (TP): Don't start a diversion if one has already
+ been started.
+
+ * tty/tmac.tty-char: Add Latin-1 characters.
+
+ * tty/tmac.tty-char: Incorporate suggestions from Paul Eggert.
+
+Tue Jun 2 00:54:34 1992 James Clark (jjc@jclark)
+
+ * tbl/table.c (table::allocate): Delete old_vline, old_entry.
+ Move declaration of struct horizontal_span.
+
+ * tbl/table.c (table::table): Initialize span_list.
+ (table::~table): Delete span_list.
+
+ * lib/ptable.h (PTABLE(T)::~PTABLE(T)): Delete v.
+
+ * ps/devps/Makefile: Avoid dependency on GNU make.
+
+ * ps/tmac.ps: Check that character does not already exist before
+ defining it.
+
+ * tty/tmac.tty: Add definitions of \(ff, \(!=, \(==, \(~=, \(sq,
+ \(OE, \(oe, \(AE, \(ae, \(lh, \(rh. Delete definitions of \(en,
+ \(ru, \(ul, \(br, \(bv, \(sl which are in the font description
+ files.
+
+ * tty/tmac.tty-char: New file.
+ * tty/Makefile: Install tmac.tty-char.
+ * tty/tmac.tty: Move definitions of \(ua, \(da, \(uA, \(dA into
+ tmac.tty-char.
+
+ * tty/tmac.tty: Fix definition of \(34.
+
+ * tty/dev{ascii,latin1}/R.proto: Add ha and ti. Map
+ bracket-drawing characters onto |. Add *o.
+
+ * troff/env.c (environment::wrap_up_tab): Increment field_spaces
+ only if current_field.
+
+ * troff/dictionary.c (dictionary::lookup): Free old_table after
+ rehashing.
+
+Mon Jun 1 10:15:22 1992 James Clark (jjc@jclark)
+
+ * tty/dev{ascii,latin1}/R.proto: Add uppercase Greek characters
+ whose glyphs are identical to glyphs of some Roman character.
+
+ * tty/devlatin1/R.proto (bu): Deleted.
+ * tty/devascii/R.proto (bu): Deleted.
+ * tty/tmac.tty: Add definition of \(bu.
+
+ * eqn/main.c (do_file): Pass FILE as argument.
+ (main): Automatically load eqnchar. New options -F and -n.
+ Pass do_file an opened FILE.
+ * groff.c: Don't pass eqnchar to eqn. Pass -F options onto eqn.
+ No need to include font.h.
+ * groff.sh: Likewise. Don't need to use - for standard input.
+ Prefix files with -- if first file starts with -.
+
+ * macros/tmac.e: Conditionalize use of \$* on \n(.g.
+
+ * troff/env.c (environment::possibly_break_line): Don't set line
+ to 0 across call to output_line(). Don't call output_line() until
+ after discarding nodes after break.
+
+Sun May 31 10:45:29 1992 James Clark (jjc@jclark)
+
+ * request.h (macro::empty): Declare it.
+ * input.c (macro::empty): New method.
+ (interpolate_macro): Don't give a WARN_SPACE if the two-character
+ macro is empty.
+
+Sat May 30 10:27:15 1992 James Clark (jjc@jclark)
+
+ * troff/env.c (environment::start_field): Decrement space_total
+ when a space is frozen.
+
+Fri May 22 14:34:38 1992 James Clark (jjc@jclark)
+
+ * macros/tmac.an (R): Delete macro.
+
+ * troff/input.c (get_copy, token::next): Support \# (like \" but
+ newline is ignored).
+
+ * troff/input.c (token::next): Fix error message in 'Y' case.
+
+Thu May 21 09:26:24 1992 James Clark (jjc@jclark)
+
+ * eqn/delim.c (define_extensible_string): Recognize any prefix of
+ a delimiter name.
+
+Fri May 15 10:20:41 1992 James Clark (jjc at jclark)
+
+ * c++test.c: Include <osfcn.h>.
+
+ * lib/strtol.c, lib/getcwd.c, ps/psbb.c: Declare errno in case
+ <errno.h> doesn't.
+
+Fri May 8 09:37:19 1992 James Clark (jjc at jclark)
+
+ * tbl/table.c (table::divide_span): Don't count column separation
+ if expand was specified.
+
+ * tbl/main.c (process_format): Don't ignore width specs in
+ continued format. Give warning for changing equal widths or
+ column separation in continued format.
+ (process_data): Set column separation, minimum width, equal
+ columns at end of table.
+
+Thu May 7 08:50:40 1992 James Clark (jjc at jclark)
+
+ * troff/node.c (kern_pair_node::add_discretionary_hyphen,
+ node::add_discretionary_hyphen): Use soft_hyphen_char.
+ (set_soft_hyphen_char): New function.
+ (init_node_requests): Bind to shc. Initialize soft_hyphen_char.
+
+ * Makefile (c++tested): Give more helpful message if test fails.
+
+Tue May 5 10:58:39 1992 James Clark (jjc at jclark)
+
+ * troff/input.c (init_charset_table): Translate 0240 to
+ an unbreakable space.
+
+ * troff/token.h (token::hyphen_indicator): New function.
+ * troff/charinfo.h (TRANSLATE_HYPHEN_INDICATOR): New special
+ translation.
+ * troff/input.c (translate): Allow translation to \%.
+ * troff/node.c (node::add_char): Handle
+ TRANSLATE_HYPHEN_INDICATOR.
+ (make_node): Don't allow TRANSLATE_HYPHEN_INDICATOR here.
+
+ * troff/input.c (init_charset_table): Don't set BREAK_AFTER flag
+ for \(hy.
+
+ * tty/devlatin1/R.proto: \(hy and - should print as 055.
+
+Tue Apr 21 09:24:42 1992 James Clark (jjc at jclark)
+
+ * groff.c (run_commands): If the last command gets a SIGPIPE send
+ a SIGPIPE to all children than haven't yet terminated. When
+ command terminates, set pid field to -1.
+
+Fri Apr 17 11:20:48 1992 James Clark (jjc at jclark)
+
+ * groff.c (main): Pass an appropriate -filename option to gxditview.
+
+Thu Apr 16 15:11:40 1992 James Clark (jjc at jclark)
+
+ * Makefile.bd (install): Remove existing program before copying.
+
+ * Makefile, */Makefile, Makefile.bd, groff.sh, groff.c: Allow
+ programs which have Unix counterparts to be installed with
+ user-specified prefix.
+
+ * troff/input.c (exit_troff): Don't check if exit_started.
+ (exit_request): Don't call exit_troff if exit_started.
+
+ * Makefile.bd (install.mm): Rename to install.dwbmm.
+
+Tue Apr 14 10:05:10 1992 James Clark (jjc at jclark)
+
+ * driver/input.c (do_file): Add missing break for '#' case.
+
+Mon Apr 13 10:11:02 1992 James Clark (jjc at jclark)
+
+ * troff/input.c (input_stack::clear): Clear past any boundaries and
+ then add the boundaries back.
+
+ * troff/input.c (exit_troff): Return immediately if already
+ exiting.
+
+ * macros/tmac.s (pg@end-text): New macro. Use pg@end-text for the
+ end macro.
+ (pg*end-page): If the text has ended and there are no more
+ footnotes or keeps, exit.
+
+ * macros/doc-ditroff (Lq, Rq): Define as \(lq and \(rq.
+
+ * troff/input.c (init_charset_table): Make \(rq transparent by
+ default.
+
+ * macros/tmac.an: Define lq and rq strings.
+
+ * macros/tmac.s (Q, U): Define as \(lq and \(rq.
+
+Sun Apr 12 12:54:37 1992 James Clark (jjc at jclark)
+
+ * troff/env.c (environment::final_break): New function.
+ (environment::newline): Set prev_line_interrupted to 2 if
+ exit_started.
+ * troff/env.h: Declare environment::final_break.
+ * troff/input.c (exit_troff): Call environment::final_break()
+ instead of environment::do_break().
+
+ * macros/Makefile: Install man.local if $(MACRODIR)/man.local
+ doesn't already exist.
+ * macros/man.local: New file.
+ * macros/tmac.an: Load man.local.
+ * macros/man.ultrix: New file.
+
+Sat Apr 11 17:32:04 1992 James Clark (jjc at jclark)
+
+ * troff/input.c (exit_groff): Rename to...
+ (exit_troff): New function.
+
+ * troff/div.c (exit_started, done_end_macro,
+ seen_last_page_ejector): New global variables.
+ (began_page_in_end_macro): New static variable.
+ (exit_flag): Deleted.
+ (top_level_diversion::top_level_diversion): Initialize
+ last_page_count.
+ (top_level_diversion): More elaborate test for whether
+ cleanup_and_exit() should be called.
+ Set began_page_in_end_macro if the end macro isn't yet finished.
+ * troff/div.h (top_level_diversion::last_page_count): New data
+ member.
+ (top_level_diversion::set_last_page): New function.
+ (exit_started, done_end_macro, seen_last_page_ejector): Declare.
+ * troff/env.c (do_break): Zero prev_line_interrupted.
+ * troff/input.c (exit_flag): Delete declaration.
+ (LAST_PAGE_EJECTOR): New magic cookie.
+ (token::next): Handle LAST_PAGE_EJECTOR.
+ (exit_groff): Set exit_started and done_end_macro instead of
+ exit_flag. Call top_level_diversion::set_last_page. Push a
+ LAST_PAGE_EJECTOR instead of calling push_page_ejector(). Do
+ another ejection after setting seen_last_page_ejector.
+
+Thu Apr 9 04:37:11 1992 James Clark (jjc at jclark)
+
+ * etc/grog.sh, etc/grog.sh: Recognize -me sh macro.
+
+ * macros/tmac.e (TH): Make sure there's room for the initial
+ header.
+
+ * macros/tmac.s (par@init): Make PD and DD at least \n(.V.
+ Set FVS in points rather than units.
+
+Mon Apr 6 11:21:32 1992 James Clark (jjc at jclark)
+
+ * troff/div.c (top_level_diversion::add_trap): Don't consider the
+ position of empty slots.
+
+Fri Apr 3 10:46:45 1992 James Clark (jjc at jclark)
+
+ * ps/devps/S: Fix height and depth of parenrightex.
+ * ps/devps/symbol.diff: Regenerate.
+
+Sat Mar 28 21:17:52 1992 James Clark (jjc at jclark)
+
+ * tmac.e (u): Do underlining as in -mgs.
+
+Fri Mar 27 09:23:44 1992 James Clark (jjc at jclark)
+
+ * tty/tty.c (tty_printer::end_page): If overstriking is
+ suppressed, still turn overstruck horizontal and vertical lines
+ into +.
+
+ * lib/new.c: Back out Feb 24 change; no longer needed with gcc
+ 2.1.
+
+ * refer/label.y (format_expr::evaluate): Avoid use of %0*d.
+
+Wed Mar 18 09:29:10 1992 James Clark (jjc at jclark)
+
+ * Version 1.05 released.
+
+Tue Mar 17 16:50:45 1992 James Clark (jjc at jclark)
+
+ * tty/tty.c: Instead of keeping an array of glyphs and then
+ sorting it, keep a ordered linked list of glyphs for each line.
+
+ * driver/driver.h: Include stddef.h.
+
+ * tty/tty.c (compare_glyph):
+ * refer/refer.c (rcompare):
+ * troff/env.c (compare_ranges): Arguments of qsort comparison
+ function should be const void *.
+
+ * troff/number.c (parse_term):
+ * dvi/dvi.c (draw_dvi_printer::draw): Avoid initialization in
+ switch statement.
+
+ * refer/label.y (consider_authors): Don't access variables
+ constructed under a condition outside that condition: put braces
+ round for statement containing declaration; redeclare use of same
+ variable later.
+
+ * pic/pic.y (text_expr): Delete production that allows
+ parenthesised text_expr.
+ (expr): Allow a conditional_expr to appear in parentheses.
+ (conditional_expr): Rename to any_expr.
+
+ * mm: Install new version 1.01 from jh.
+
+ * lib/font.c (font::get_width): Cache scaled widths.
+ (font::font): Initialize widths_cache.
+ (font::~font): Destroy widths_cache.
+ * lib/font.h: Add font::widths_cache. Declare font_widths_cache.
+
+Mon Mar 16 10:16:10 1992 James Clark (jjc at jclark)
+
+ * c++test.c, c++test.ref: New files.
+ * Makefile: Check that the C++ compiler works.
+
+ * ps/tmac.pspic (PSPIC): Do a break.
+
+ * ps/tmac.ps: Move definition of PSPIC into...
+ * ps/tmac.pspic: New file.
+ (PSPIC): Draw box around picture, but make it invisible to grops.
+ * ps/tmac.ps: Load tmac.pspic.
+ * ps/Makefile: Install tmac.pspic.
+
+Sun Mar 15 14:18:08 1992 James Clark (jjc at jclark)
+
+ * lib/font.c (scale_round): If n is negative,
+ subtract .5 before truncating floating point result.
+
+ * lib/fontfile.c: Include <errno.h>.
+
+Tue Mar 10 14:17:03 1992 James Clark (jjc at jclark)
+
+ * driver/input.c (get_char): Inline. Don't update current_lineno.
+ Change callers to up date current_lineno if necessary.
+ Use get_char() instead of getc(current_file).
+
+Sun Mar 8 18:05:28 1992 James Clark (jjc at jclark)
+
+ * ps/tmac.ps: Fix up spacing of \(mo and \(nm.
+
+Fri Mar 6 19:38:58 1992 James Clark (jjc at jclark)
+
+ * tty/tty.c (tmac.tty): Define \(rg as (R).
+
+Tue Mar 3 10:11:25 1992 James Clark (jjc at jclark)
+
+ * lib/lib.h: New define a_delete.
+ * Use a_delete instead of delete when deleting an array of objects
+ without destructors.
+
+ * lib/lib.h: Rename adelete to ad_delete.
+ * Change uses of adelete.
+
+Mon Mar 2 12:41:05 1992 James Clark (jjc at jclark)
+
+ * eqn/eqn.y: Include lib.h.
+
+ * troff/node.c (grow_font_table): Delete old_font_table.
+
+ * mm: Install new version from jh.
+
+Fri Feb 28 10:42:23 1992 James Clark (jjc at jclark)
+
+ * tbl/table.h (format_type): Make global instead of local to class
+ entry_format. Prefix enumerators with FORMAT_.
+ * tbl/table.c, tbl/main.c: Corresponding changes.
+ * refer/token.h (token_type): Make global. Prefix enumerators
+ with TOKEN_.
+ * refer/token.[ch]: Corresponding changes.
+ * Makefile: Get rid of -DNO_NESTED_TYPES configuration option.
+
+ * troff/div.c (node::set_vertical_size): Don't name argument.
+
+Thu Feb 27 10:29:19 1992 James Clark (jjc at jclark)
+
+ * Makefile: New configuration option ARRAY_DELETE_NEEDS_SIZE.
+ * lib/lib.h: Define adelete accordingly.
+ * pic/object.c (graphic_object::graphic_object):
+ * tbl/main.c (format::~format):
+ * tbl/table.c (table::~table):
+ * refer/ref.c (reference::~reference, reference::merge,
+ reference::insert_field, reference::delete_field): Use adelete.
+
+ * Makefile: Change NESTED_TYPES to NO_NESTED_TYPES.
+ * refer/token.h:
+ * tbl/table.h: Corresponding changes.
+
+ * common.c (common_output::dashed_arc, common_output::dotted_arc):
+ Ensure total_angle is positive.
+
+Wed Feb 26 08:49:26 1992 James Clark (jjc at jclark)
+
+ * refer/ref.c (reference::merge, reference::insert_field,
+ reference::delete_field): Avoid delete[0].
+
+ * refer/token.c (init_special_chars): Move calls to cmupper
+ outside calls to init_two_char_letter to work around bug in gcc
+ 2.0.
+
+Mon Feb 24 14:20:00 1992 James Clark (jjc at jclark)
+
+ * lib/new.c (operator new): Use __builtin_new for g++.
+
+ * pic/object.c (graphic_object::~graphic_object): Don't use
+ delete [] on 0.
+
+ * pic/object.c (output::compute_scale): Initialize max_width and
+ max_height.
+
+Sat Feb 15 09:55:20 1992 James Clark (jjc at jclark)
+
+ * troff/input.c (write_request): Call fflush.
+
+ * troff/node.h (class composite_node): Move declaration to node.c
+ * troff/input.c (charinfo_to_node): Rename to ...
+ (charinfo_to_node_list): Return node list rather than composite
+ node.
+ * troff/node.c (make_composite_node): New function.
+ (make_node, add_char): Call make_composite_node instead of
+ charinfo_to_node.
+ (class composite_node): Add a tfont * member. Delete font_size
+ member.
+ (composite_node::composite_node, composite_node::copy,
+ composite_node::size): Corresponding changes.
+ (composite_node::tprint): Provide constant spacing, emboldening
+ and track kerning as specified in tfont.
+ (composite_node::width): Change width calculation accordingly.
+ * troff/env.h (environment::composite): New member.
+ (environment::is_composite, environment::set_composite): New
+ functions.
+ * troff/env.c (environment::environment): Initialize composite.
+ * troff/input.c (charinfo_to_node): Call
+ environment::set_composite.
+ * troff/node.c (make_composite_node, make_glyph_node): Use the
+ plain version of the tfont if the environment is composite.
+
+ * troff/node.c (font_info::get_space_width): Additional argument
+ giving space_size. Handle constant space correctly. Scale by
+ space_size unless constant spaced.
+ (env_sentence_space_width): New function.
+ * troff/node.h: Declare it.
+ * troff/env.h (environment::get_space_size,
+ environment::get_sentence_space_size,
+ environment::get_narrow_space_width,
+ environment::get_half_narrow_space_width): Make inline.
+ (environment::get_space_width): Make inline. Just call
+ env_space_width.
+ * troff/env.c: Delete definitions for funtions made inline.
+ (environment::space_newline, environment::space): Use
+ env_sentence_space_width(). Don't scale by space_size.
+ * troff/node.h: Move declarations of env*space_width() functions
+ into env.h.
+
+Sat Feb 8 09:30:22 1992 James Clark (jjc at jclark)
+
+ * macros/tmac.s (PS): Don't try to set negative indent.
+
+Thu Feb 6 09:00:35 1992 James Clark (jjc at jclark)
+
+ * pic/pic.y: Fix min function.
+
+Tue Jan 28 07:52:29 1992 James Clark (jjc at jclark)
+
+ * man/mdate.sh: Clear LANGUAGE.
+
+Sun Jan 19 13:02:41 1992 James Clark (jjc at jclark)
+
+ * pic/pic.y, pic/lex.c: Rename COMMAND token to COMMAND_LINE.
+ * pic/lex.c: New COMMAND keyword.
+ * pic/pic.y (print_args, print_arg): New rules.
+ (placeless_element): Use print_args for PRINT.
+ New COMMAND element.
+
+Tue Jan 7 13:14:31 1992 James Clark (jjc at jclark)
+
+ * troff/input.c (terminal): Handle missing argument correctly.
+
+ * pic/pic.y (text_expr): New rule.
+
+ * pic/pic.y: Implement := operator.
+
+Sun Jan 5 10:23:02 1992 James Clark (jjc at jclark)
+
+ * etc/grog.pl, etc/grog.sh: Distinguish old and new versions of
+ mdoc.
+
+Sat Jan 4 14:42:26 1992 James Clark (jjc at jclark)
+
+ * ps/devps/dingbatsrmap: Include this in the distribution.
+
+ * macros/tmac.doc: Replace with new version from 2nd Networking
+ Release. Fix loading of doc-* files.
+ * macros/{doc-common,doc-ditroff,doc-nroff,doc-syms}: New files.
+ * macros/tmac.doc.old: New file. Apply fixes that had been
+ applied to old tmac.doc.
+ * macros/tmac.andoc: Check that we're running under groff.
+ * macros/Makefile: Rework.
+
+Fri Jan 3 13:27:51 1992 James Clark (jjc at jclark)
+
+ * tbl/table.h (format_type):
+ * refer/token.h (token_type): If NESTED_TYPES is defined, use
+ typedef to make these types visible at file scope.
+ * Makefile: Add NESTED_TYPES configuration option.
+
+ * troff/div.c (mark): At the top level use the value of
+ nl_reg_contents rather than the current vertical position.
+
+Thu Jan 2 10:34:51 1992 James Clark (jjc at jclark)
+
+ * tty/tty.c: Implement \D for horizontal or vertical lines.
+ (tty_printer::set_char): Use vec_used+2 as serial number.
+ Don't allow size of vector to exceed USHRT_MAX-2.
+ Split off part into...
+ (tty_printer::add_char): New function.
+ (tty_printer::draw): New function.
+ (compare_glyph): Handle equal serial numbers.
+ (tty_printer::end_page): Handle overstruck characters from \D.
+ (main, usage): Implement -d option.
+
+Mon Dec 23 10:37:51 1991 James Clark (jjc at jclark)
+
+ * tbl/main.c (process_format):
+ * eqn/text.c (split_text):
+ * troff/input.c (token::next): Use inner block for declarations
+ with initializers in switch statement.
+
+Mon Dec 16 20:52:03 1991 James Clark (jjc at jclark)
+
+ * pic/common.c (common_output::dash_line): Cope with zero-length
+ lines.
+
+Sun Nov 17 12:04:08 1991 James Clark (jjc at jclark)
+
+ * Version 1.04 released.
+
+Wed Nov 13 05:27:21 1991 James Clark (jjc at jclark)
+
+ * macros/tmac.an (TH): Define a macro an-init to define variables
+ based on command line arguments.
+ (an-header): Call it.
+
+Sun Nov 3 12:07:34 1991 James Clark (jjc at jclark)
+
+ * Makefile (install.mm): Rename to install.dwbmm.
+
+ * Makefile: Integrate mm.
+ * mm: New directory.
+
+Wed Oct 30 10:11:34 1991 James Clark (jjc at jclark)
+
+ * refer/dirnamemax.c: If PATHCONF_MISSING is defined, include
+ <sys/types.h>.
+
+ * pic/troff.c (troff_output::simple_spline,
+ troff_output::simple_polygon): Rename variable `v' to `d' to avoid
+ shadowing parameter.
+
+ * lib/tmpfile.c (xtmpfile): Declare dir as const char *.
+
+ * lib/ptable.h: Add explicit casts when converting from unsigned
+ long to unsigned.
+
+ * dvi/devdvi/{SA,SB,msam.map,msbm.map}: New files.
+ * dvi/devdvi/Makefile: Install SA, SB.
+
+ * refer/indxbib.c: Add declaration of mktemp.
+
+ * refer/lookbib.c: Add declaration of isatty.
+
+Fri Oct 25 09:00:17 1991 James Clark (jjc at jclark)
+
+ * pic/lex.c (interpolate_macro_with_args): While collecting
+ arguments, keep track of whether we're in a string.
+
+Wed Oct 23 08:42:48 1991 James Clark (jjc at jclark)
+
+ * ps/tmac.ps (PSPIC): Do the .sp after the \X, and move the \X
+ down with \v, so as to avoid problems with top of page trap
+ setting no space mode.
+
+Tue Oct 22 17:38:49 1991 James Clark (jjc at jclark)
+
+ * eqn/lex.c (get_delimited_text): Allow tab before macro body.
+
+Tue Oct 15 17:24:53 1991 James Clark (jjc at jclark)
+
+ * ps/psrm.c (ps_get_line): Fix bug when lines longer than 255.
+ Improve error message.
+
+Fri Oct 11 11:09:38 1991 James Clark (jjc at jclark)
+
+ * ps/psrm.c (print_ps_string): Don't pass negative numbers to
+ printf("%03o");
+
+Wed Oct 9 17:50:14 1991 James Clark (jjc at jclark)
+
+ * groff.c (possible_command::execp): Always use _exit() after a
+ failed exec.
+
+ * Makefile: Add HAVE_UNION_WAIT, HAVE_PID_T, WAIT_COREDUMP_0200,
+ NO_SYS_WAIT_H configuration options.
+ * groff.c: Use these options. Use POSIX-style macros to extract
+ fields from the status returned by wait().
+
+Fri Oct 4 12:12:27 1991 James Clark (jjc at jclark)
+
+ * tbl/table.c (table::compute_separation_factor): Allow the
+ separation factor to drop to 0.
+
+Tue Oct 1 18:12:38 1991 James Clark (jjc at jclark)
+
+ * refer/search.c: Include <errno.h>.
+
+Sun Sep 29 08:40:57 1991 James Clark (jjc at jclark)
+
+ * pic/pic.y (YYDEBUG): Don't define for Borland C++.
+
+ * lib/lib.h: #ifdef out declarations of itoa and iftoa for Borland
+ C++.
+
+ * pic/lex.c (input_stack::bol): Move definition out of class body.
+
+ * pic/main.c: On MSDOS munge argv[0].
+
+ * lib/ptable.h: Define name2 as _Paste2 for Borland C++.
+
+ * lib/ptable.c (hash_string): Use unsigned long rather than
+ unsigned.
+ (next_ptable_size): Use unsigned rather than int. Give an error
+ message if we've hit the largest table size.
+ * lib/ptable.c: Corresponding changes. Also use unsigneds for the
+ table size.
+
+ * pic/object.h (object_spec): Make flags unsigned long. Declare
+ flags as const unisgned long rather than as enums.
+
+ * pic/output.c: Deleted.
+
+ * pic/troff.c (troff_output::simple_ellipse): Remove spurious %.
+
+ * tbl/table.c (simple_entry::note_double_vrule_on_{left,right}):
+ Add additional argument.
+ (line_entry::note_double_vrule_on_{left,right}): Set value of
+ douvle_vrule_on_{right,left} flag according to argument.
+ (simple_line_entry::simple_print,
+ simple_line_entry::double_line_print): If adjacent to double vrule
+ on a corner extend rather than shorten the rule by half the double
+ vrule sep.
+
+ * troff/number.c (parse_term): In checking for overflow, handle the
+ case where the current horizontal position is negative.
+
+Thu Sep 12 08:26:09 1991 James Clark (jjc at jclark)
+
+ * pic/object.c (draw_arrow): Check for object having zero length.
+
+Wed Sep 11 10:32:38 1991 James Clark (jjc at jclark)
+
+ * eqn/main.c (do_file): Split off inline equation handling into...
+ (inline_equation): New function. Search for starting delimiter
+ using...
+ (delim_search): New function. Don't recognize a delimiter that
+ occurs in the name of an escape sequence, number register, string
+ etc.
+
+Tue Sep 10 04:01:11 1991 James Clark (jjc at jclark)
+
+ * eqn/delim.c (delim_box::compute_metrics): Don't call
+ define_extensible_string if left is 0.
+ (delim_box::output): Don't print the left delimiter if left is 0.
+ (delim_box::debug_print): Check for left == 0 before calling printf.
+
+Fri Aug 23 13:02:30 1991 James Clark (jjc at jclark)
+
+ * troff/Makefile (majorminor.c): Include only digits in
+ minor_version.
+
+Thu Aug 22 09:35:37 1991 James Clark (jjc at jclark)
+
+ * refer/dirnamemax.c: new file.
+ * refer/genlimits.c: Deleted.
+ * refer/indxbib.c (main): Use dir_name_max() instead of NAME_MAX.
+ Don't check path length.
+ * refer/Makefile: Add dir_name_max.o; delete genlimits.
+ * Makefile: Add PATHCONF_MISSING option.
+
+ * refer/indxbib.c (get_cwd): New function.
+ (main): Use get_cwd().
+ * lib/getcwd.c: New file.
+ * Makefile: Delete -DHAVE_GETWD. Include GETCWD variable. Pass
+ GETCWD in SUBFLAGS.
+ * lib/Makefile: Compile getcwd.o.
+
+ * ps/tmac.psatk (psatk-defs): Define showpage after pushing
+ userdict.
+
+ * refer/indxbib.c (main): Check success of mktemp.
+
+ * lib/tmpfile.c: New file.
+ * lib/Makefile: Add tmpfile.c.
+ * lib/lib.h: Declare xtmpfile(); include <stdio.h>.
+ * ps/ps.h: Delete declaration of mktemp().
+ * ps/ps.c (ps_printer::ps_printer): Use xtmpfile().
+ * refer/refer.c (divert_to_temporary_file): Use xtmpfile().
+ * driver/driver.h: No need now to include errno.h.
+
+ * everywhere: Set errno to 0 before calling fopen().
+
+ * eqn/eqn.h, etc/soelim.c, driver/driver.h, etc/addftinfo.c,
+ dvi/tfmtodit.c, groff.c, refer/index.c, refer/linear.c,
+ refer/lookbib.c, refer/refer.h, ps/psbb.c: Include <errno.h>.
+
+Mon Aug 19 10:52:18 1991 James Clark (jjc at jclark)
+
+ * troff/env.h (translate_space_to_dummy): Declare it.
+ * troff/env.c (environment::space_newline, environment::space):
+ If translate_space_to_dummy is set then make the width of spaces 0.
+ * troff/input.c (translate): If the second character of a
+ translation is a space, translate to unbreakable space. If the
+ first character is a space, set or clear translate_space_to_dummy
+ according to whether the second character is \&. Weird!
+
+Tue Jul 30 10:03:56 1991 James Clark (jjc at jclark)
+
+ * groff.c (run_commands): Don't use non-zero exit code because a
+ command gets SIGPIPE.
+
+ * groff.c, groff.sh: Use -mXps with -TXps.
+
+ * ps/ps.c (ps_printer::special): Move call to flush_sbuf() into...
+ (ps_printer::do_exec, ps_printer::do_file, ps_printer::do_def,
+ ps_printer::do_mdef, ps_printer::do_import): Call flush_sbuf().
+ (ps_printer::special): New specials invis and endinvis.
+ (ps_printer::do_invis, ps_printer::do_endinvis): New functions.
+ (ps_printer::set_char, ps_printer::draw): Return if invis_count>0.
+ (ps_printer::end_page): Check that invis_count == 0.
+ (ps_printer::invis_count): New member.
+ (ps_printer::ps_printer): Initialize invis_count to 0.
+
+ * troff/env.c (environment::hyphenate_line): Hyphenation
+ indicator at beginning of word inhibits splitting after -, \(em
+ etc.
+
+ * pic/pic.y (element): Allow another element to follow } without
+ any intervening separator.
+
+Mon Jul 22 12:27:37 1991 James Clark (jjc at jclark)
+
+ * pic/lex.c (get_delimited): Allow tabs before delimiter.
+
+Wed Jul 17 10:59:08 1991 James Clark (jjc at jclark)
+
+ * groff.c: Get rid of HAVE_UNION_WAIT stuff. Instead suppress
+ declaration of wait() in header files.
+ * Makefile: Get rid of -DHAVE_UNION_WAIT.
+
+ * tbl/table.c (alphabetic_text_entry::add_tab): New function.
+
+ * lib/lib.h: Declare return type of strerror as char *.
+
+ * man/Makefile: Add g flag to sed substitutions.
+ * Makefile (shgroff, bindist): Likewise.
+
+Sun Jul 14 11:57:02 1991 James Clark (jjc at jclark)
+
+ * ps/ps.c (ps_printer::do_import): Move push of userdict into...
+ * ps/devps/prologue (PBEGIN): Define showpage after pushing
+ userdict.
+
+Sat Jul 13 20:53:04 1991 James Clark (jjc at jclark)
+
+ * ps/devps/prologue (PBEGIN): Zap any definition of showpage in
+ userdict.
+
+Fri Jul 12 07:10:09 1991 James Clark (jjc at jclark)
+
+ * man/mdate.sh: Handle the fact that BSD ls -l does not print the
+ group.
+
+Sun Jul 7 08:00:23 1991 James Clark (jjc at jclark)
+
+ * troff/input.c (define_number_reg): If currently undefined,
+ don't define it if the argument is an invalid expression.
+
+ * Makefile: Ignore return value of `if' commands without `else'
+ parts.
+
+ * Makefile: Split up CPPDEFINES into a series of separate
+ configuration options.
+
+ * troff/input.c (init_registers): Use time_t instead of long
+ unless LONG_FOR_TIME_T is defined. Use returned result rather
+ than passing pointer.
+ * Makefile: Document LONG_FOR_TIME_T as a CPPDEFINE.
+
+ * lib/Makefile (fontpath.h): Use gendef.
+
+Thu Jul 4 09:48:05 1991 James Clark (jjc at jclark)
+
+ * troff/input.c (input_iterator::shift): Delete argument name.
+ * troff/node.c (suppress_output_file::really_begin_page,
+ suppress_output_file::really_transparent_char, node::ascii_print,
+ node::tprint): Delete names of unused arguments.
+
+Wed Jul 3 17:34:57 1991 James Clark (jjc at jclark)
+
+ * refer/label.y (string): Pass $4 to command_error.
+
+Tue Jul 2 15:06:01 1991 James Clark (jjc at jclark)
+
+ * Version 1.03 released.
+
+Sat Jun 29 08:14:01 1991 James Clark (jjc at jclark)
+
+ * Makefile: Pass definition of SHELL in SUBFLAGS.
+
+ * gendef: New file.
+ * Makefile, eqn/Makefile, refer/Makefile, troff/Makefile,
+ ps/Makefile: Use gendef to construct header files that are
+ constructed from the Makefile.
+
+ * macros/Makefile: make all should build stripped version of tmac.e.
+
+ * refer/Makefile (clean): Remove y.output.
+
+Fri Jun 28 09:44:36 1991 James Clark (jjc at jclark)
+
+ * ps/pfbtops.c (main): Add -v option which prints out a version
+ number.
+ * ps/Makefile (pfbtops): Link with libgroff.a.
+
+Fri Jun 21 07:43:23 1991 James Clark (jjc at jclark)
+
+ * refer/search.h (linear_searcher::get_nkeys): Delete declaration.
+ * refer/linear.c (linear_searcher::get_nkeys): Delete definition.
+
+ * refer/lkbib.c (main): Always terminate reference with blank
+ line.
+ * refer/lookbib.c (main): Likewise.
+
+ * refer/linear.c (file_buffer::load): Check that the file is not a
+ binary file.
+
+ * refer/Makefile (genlimits): Possibly add -DHAVE_SYS_DIR_H.
+ (genlimits.c): Include <sys/dir.h> if HAVE_SYS_DIR_H is defined.
+ Delete second inclusion of <sys/param.h>.
+
+Tue Jun 18 01:32:26 1991 James Clark (jjc at jclark)
+
+ * troff/token.h (token::special): Deleted.
+
+ * tbl/main.c (process_format): Rework so that opt->tab_char is
+ recognized only when appropriate.
+
+ * ps/Makefile (clean): Remove pfbtops.
+
+Sun Jun 16 09:37:19 1991 James Clark (jjc at jclark)
+
+ * lib/font.c (text_file::next): Don't return if we have got a
+ blank line.
+
+Fri Jun 14 09:52:26 1991 James Clark (jjc at jclark)
+
+ * refer/refer.c (store_reference): Get hash code from old_table[i]
+ when rehashing the table.
+
+Thu Jun 13 01:26:43 1991 James Clark (jjc at jclark)
+
+ * eqn/box.c (box::top_level): Save size and prev size using \R and
+ restore it afterwards. Set the size to the size at the beginning
+ of the line.
+ * eqn/pbox.h: Declare SAVED_INLINE_PREV_SIZE_REG,
+ SAVED_INLINE_SIZE_REG, and SAVED_SIZE_REG.
+
+ * refer/Makefile (limits.h): Use ./genlimits.
+
+Wed Jun 12 16:05:34 1991 James Clark (jjc at jclark)
+
+ * refer/index.c: Delete declarations of stat() and fstat().
+
+Tue Jun 11 14:52:49 1991 James Clark (jjc at jclark)
+
+ * tty/tmac.tty: Add character definitions for \(>= and \(<=.
+
+Mon Jun 10 22:49:48 1991 James Clark (jjc at jclark)
+
+ * etc/grog.sh, etc/grog.pl: Change regex for .PS.
+
+Fri Jun 7 09:13:06 1991 James Clark (jjc at jclark)
+
+ * troff/input.c (token::get_char): Handle \e.
+
+ * refer/linear.c: Delete declarations of fstat() and stat().
+
+Wed Jun 5 09:11:59 1991 James Clark (jjc at jclark)
+
+ * troff/node.c, troff/env.c, troff/input.c, Makefile: Remove
+ OP_DELETE_BROKEN stuff, since we now have a fix for g++.
+
+Mon Jun 3 13:41:32 1991 James Clark (jjc at jclark)
+
+ * troff/input.c (do_define_macro): Improve error handling for end
+ of file while defining macro.
+
+Sun Jun 2 10:20:24 1991 James Clark (jjc at jclark)
+
+ * eqn/box.h: Fix declaration of set_gsize.
+ * eqn/box.c (set_gsize): Make argument const char *.
+ (gsize): Declare as char *.
+ * eqn/main.c (main): Don't convert gsize to int.
+ * eqn/lex.c (do_gsize): Pass char * to set_gsize.
+
+ * Version 1.02 released.
+
+Sat Jun 1 12:19:46 1991 James Clark (jjc at jclark)
+
+ * macros/tmac.andoc: New file.
+ * macros/Makefile: Install tmac.andoc.
+
+ * troff/node.c, troff/env.c, troff/input.c: Conditionalize use of
+ operator new and delete on OP_DELETE_BROKEN not being defined.
+ * Makefile: Mention OP_DELETE_BROKEN.
+
+Mon May 27 13:49:07 1991 James Clark (jjc at jclark)
+
+ * Makefile (bindist): Pass SUBFLAGS.
+
+Sun May 26 14:13:22 1991 James Clark (jjc at jclark)
+
+ * Makefile, groff.c: Pass definitions to groff.c via device.h.
+
+ * tty/tty.c (tty_font::load_tty_font): Avoid shadowing
+ parameter.
+
+ * ps/Makefile, ps.c: Pass BROKEN_SPOOLER_FLAGS via broken.h.
+
+ * ps/ps.h, ps/psrm.c: Make comment_table and
+ header_comment_table local to resource_manager::process_file.
+
+ * groff.sh: With -TXps pass -printCommand option to gxditview.
+
+ * groff.c (possible_command::print): Implement using
+ append_arg_to_string.
+
+ * xditview: Merge in new implementation with own ChangeLog.
+
+Sat May 25 18:33:20 1991 James Clark (jjc at jclark)
+
+ * groff.c (main): Implement PRINT_OPTION.
+ (append_arg_to_string): New command.
+ (device_table): Set PRINT_OPTION flag for Xps.
+
+Fri May 24 09:48:58 1991 James Clark (jjc at jclark)
+
+ * troff/groff.h: Rename to troff.h.
+
+ * pic/lex.c (lookup_keyword, docmp): New functions.
+ (get_token): Use new lookup_keyword.
+ Don't include key.h.
+ * pic/key.[ch], pic/pic.gperf: Deleted.
+ * pic/Makefile: Remove gperf stuff.
+
+ * pic/Makefile, pic/output.h: Move definition of TEX_SUPPORT
+ into output.h.
+ * pic/tex.c: Move include of pic.h before test of TEX_SUPPORT.
+
+ * troff/Makefile, troff/node.c: Move definition of
+ STORE_WIDTH into node.c.
+
+ * etc/grog.pl, etc/grog.sh: Support -mdoc.
+
+Thu May 23 12:30:49 1991 James Clark (jjc at jclark)
+
+ * dvi/devdvi/texr.map, dvi.devdvi/texi.map,
+ dvi/devdvi/texb.map: Add lq and rq.
+ dvi/devdvi: Regenerate fonts.
+ * ps/devps/textmap: Add lq and rq.
+ * ps/devps: Regenerate fonts.
+ * tty/devascii/R.proto, tty/devlatin1/R.proto: Add lq and rq.
+ * macros/tmac.e: Define \*(lq and \*(rq to be \(lq and \(rq.
+
+ * pic/object.c (position_rectangle): When checking radius
+ cope with possiblity that width or height is negative.
+ (box_object::box_object): Have separate xrad and yrad with
+ signs matching signs of dim components.
+ (box_object::{north,south}_{east,west}): Use xrad and yrad.
+ (box_object::print): With rounded boxes use absolute values
+ for dim and rad arguments.
+
+ * lib/Makefile, lib/fontfile.o: Pass definition of FONTPATH
+ in fontpath.h.
+
+ * eqn/Makefile, eqn/main.c: Pass definition of DEVICE in device.h.
+
+ * various files: Add explicit destructors to keep Saber CC +d
+ happy.
+
+Wed May 22 11:37:11 1991 James Clark (jjc at jclark)
+
+ * eqn/box.c (box::top_level): Restore fonts correctly after
+ font changes in line containing inline equation. Also
+ restore previous font as well as current font.
+ * eqn/pbox.h: Define necessary string and register names.
+
+ * troff/input.c (token::next): Case 'R' calls do_register.
+ (do_register): New function.
+
+Tue May 21 11:28:23 1991 James Clark (jjc at jclark)
+
+ * groff.c, groff.sh: Support Xps device. Allow each device
+ to have a pseudo_name and a real_name.
+
+ * groff.c (run_commands): Don't print `Broken pipe' messages.
+
+ * ps/pfbtops.c: New file.
+ * ps/Makefile: Add pfbtops.
+
+ * troff/number.c (parse_term): Improved error message.
+
+Mon May 20 11:22:14 1991 James Clark (jjc at jclark)
+
+ * groff.c, groff.sh, etc/grog.sh, etc/grog.pl: Support grefer.
+
+ * Makefile: Integrate refer.
+ * refer: New directory.
+ * man/grefer.man, man/glookbib.man, man/gindxbib.man,
+ man/lkbib.man: New files.
+ * man/Makefile: Support refer man pages.
+
+ * lib/lib.h: Declare is_prime.
+ * lib/prime.c: New file.
+
+ * troff/input.c (macro_source): New function.
+ (init_input_requests): Bind "mso" to macro_source.
+
+ * troff/env.c (environment::possibly_break_line): Maintain
+ pointer to pointer to node to be split in ndp so as to avoid
+ using address of freed node.
+
+ * troff/env.c (environment::hyphenate_line): Maintain pointer to
+ pointer to first node to be hyphenated in startp so as to
+ avoid using address of freed node.
+
+ * troff/env.c (class trie, class hyphen_trie): Make the
+ elements of the trie be of type char not unsigned char.
+ Declare arguments to be const char* instead of unsigned char *.
+
+ * troff/env.c (hyphenate): Initialize hbuf[0].
+
+ * troff/input.c (set_string): Declare p to be char * and cast
+ *p to unsigned char when necessary.
+
+ * troff/input.c (do_define_macro): Declare s to be const
+ char*. Cast element to unisgned char when necessary, Declare
+ d to be an int. Handle EOF better.
+
+ * troff/Makefile, troff/input.c: Different scheme for passing
+ definitions of MACROPATH, HYPHENFILE and DEVICE.
+
+Tue May 14 13:41:36 1991 James Clark (jjc at jclark)
+
+ * tty/devascii/R.proto: Delete entry for em.
+ * tty/devlatin1/R.proto: Likewise.
+
+Sat May 11 11:13:28 1991 James Clark (jjc at jclark)
+
+ * troff/input.c (translate): Stop when we get a space. Treat eof
+ like newline.
+
+ * macros/tmac.an (IP): Only pass quoted argument to TP when \n(.$>1.
+
+Wed Apr 24 19:24:33 1991 James Clark (jjc at jclark)
+
+ * tbl/main.c (process_format): A font name following a `f'
+ modifier that starts with a digit can be only one character long.
+ Also deal with EOF on the second character of the font name.
+
+Wed Apr 17 11:23:43 1991 James Clark (jjc at jclark)
+
+ * troff/input.c (token::next): Turn \~ into an
+ unbreakable_space_node.
+ * troff/node.c (unbreakable_space_node): New class.
+ * troff/node.h: Declare it.
+
+Tue Apr 16 10:47:12 1991 James Clark (jjc at jclark)
+
+ * dvi/dvi.c (dvi_printer::set_char): Make code an int. Check that
+ it's >= 0, before outputting it as a single byte.
+
+Mon Apr 15 11:20:23 1991 James Clark (jjc at jclark)
+
+ * lib/font.c: Make font_char_metric::code an int.
+ (font::get_code): Change return type to int.
+ (font::load): Allow code to be arbitrary integer.
+ * lib/font.h (font::get_code): Change return type to int.
+ (font::number_to_index): Change argument type to int.
+ * troff/input.c (token::next): In case 'N', allow any value.
+ Store value in token::val.
+ (token::operator==): For TOKEN_NUMBERED_CHAR test equality of val.
+ (token::get_char, token::add_to_node_list, token::process): Get
+ number from val.
+ (charinfo::set_number): Change argument to int.
+ (charinfo::get_number): Require that NUMBERED flag be set.
+ (get_charinfo_by_number): Store numbered characters not between 0
+ and 255 in a dictionary.
+ * troff/charinfo.h (get_charinfo_by_number): Change argument type
+ to int.
+ (charinfo::number): Change type to int.
+ (charinfo::set_number): Change type of set_number to int.
+ * troff/node.c (troff_output_file::put_char_width,
+ troff_output_file::put_char): Test whether character is numbered
+ using charinfo::numbered().
+ * driver/printer.c (printer::set_numbered_char): Allow arbitrary
+ values of num.
+ * lib/nametoindex.c: New implementation to cope with arbitrary
+ number characters.
+
+ * troff/input.c (token::operator==): Test val for
+ TOKEN_CHAR_HEIGHT, TOKEN_CHAR_SLANT, TOKEN_FONT_POSITION, and
+ TOKEN_SIZE.
+
+ * man/Makefile: Add definiton of BROKEN_SPOOLER_FLAGS.
+ (.man.n): sed out @BROKEN_SPOOLER_FLAGS@.
+
+Sun Apr 14 12:57:00 1991 James Clark (jjc at jclark)
+
+ * ps/devps/zapfdr.ps: Don't copy UniqueID. Avoid use of newdict
+ variable.
+
+ * all Makefiles: rm targets of cp and >.
+
+ * xditview/xtotroff.c (MapFont): Unlink troff_name before opening
+ it.
+
+ * eqn/lex.c (def_table): Add dollar.
+
+Sat Apr 13 13:02:44 1991 James Clark (jjc at jclark)
+
+ * troff/input.c (do_width): Push back newline before closing delim
+ like do_bracket.
+
+Fri Apr 12 15:16:03 1991 James Clark (jjc at jclark)
+
+ * groff.c (possible_command::prepend_arg): New function.
+ (main): Prepend device -m option.
+ * groff.sh: Put device -m options before command-line options.
+
+Tue Apr 9 10:24:43 1991 James Clark (jjc at jclark)
+
+ * macros/tmac.an (IP): Quote argument to TP.
+
+ * ps/ps.c (main): New option -b, which sets...
+ (broken_flags): New variable.
+ (ps_printer::~ps_printer): Incorporate the setup section in the
+ prolog if (broken_flags & NO_SETUP_SECTION).
+ (ps_printer::begin_page): Generate {Begin,End}PageSetup comments.
+ (ps_printer::merge_download_fonts, ps_printer::merge_import_fonts,
+ ps_printer::merge_ps_fonts, ps_printer::print_font_comment,
+ ps_printer::print_needed_font_comment,
+ ps_printer::print_supplied_font_comment,
+ ps_printer::print_include_font_comments,
+ ps_printer::lookup_doc_font, ps_printer::download_fonts,
+ ps_printer::read_download_file, read_document_fonts, add_font,
+ skip_line, parse_fonts_arg, document_font::document_font,
+ document_font::~document_font, document_font::download,
+ ps_output::include_file): Deleted.
+ (ps_printer::~ps_printer): Generate %%EOF. Generate %!PS-Adobe-3.0
+ rather than %!PS-Adobe-2.0. Make calls to
+ resource_manager::need_font for each font that we used. Replace
+ calls to merge_ps_fonts, merge_download_fonts, print_font_comment,
+ print_supplied_font_comment, print_needed_font_comment by call to
+ resource_manager::print_header_comments. Output %%Orientation
+ comment. Output %%Requirements: numcopies comment if ncopies > 1.
+ Don't output the prolog directly. Instead call
+ resource_manager::output_prolog. Only define #copies when ncopies
+ > 1. Delete calls to print_include_font_comments and
+ download_fonts. Add call to resource_manager::document_setup.
+ (ps_printer::do_file): Call resource_manager::import_file instead
+ of including it ourselves.
+ (ps_printer::do_import): Likewise. Also don't call
+ merge_import_fonts. Push userdict on the dictionary stack before
+ and pop it afterwards.
+ Move declaration of ps_output into ps.h.
+ * ps/psrm.c: New file implementing resource_manager class.
+ * ps/ps.h: New file declaring ps_output and resource_manager
+ classes.
+ * ps/devps/zapfdr.ps:
+ * ps/devps/symbolsl.ps:
+ * ps/devps/prologue: Use 3.0 conventions.
+ * ps/Makefile: Pass definition of BROKEN_SPOOLER_FLAGS in DEFINES.
+ Add default definition of BROKEN_SPOOLER_FLAGS.
+ * Makefile: New variable BROKEN_SPOOLER_FLAGS. Add
+ BROKEN_SPOOLER_FLAGS to SUBFLAGS.
+
+Mon Apr 8 09:26:54 1991 James Clark (jjc at jclark)
+
+ * etc/grog.pl: New file.
+ * Makefile (GROG): New variable.
+ Add GROG to SUBFLAGS.
+ * etc/Makefile (GROG): New variable.
+ (install.nobin): Install $(GROG) rather than grog.sh.
+
+Thu Apr 4 11:36:45 1991 James Clark (jjc at jclark)
+
+ * eqn/special.c (special_box::compute_metrics): Make the input and
+ output strings the same. Get the new height and depth from the
+ predefined height and depth registers. Also make subscript kern
+ and skew available.
+ (special_box::compute_subscript_kern, special_box::compute_skew):
+ New functions.
+
+ * eqn/box.c (pointer_box::compute_skew,
+ simple_box::compute_metrics, box::top_level)
+ * eqn/text.c (prime_box::compute_metrics,
+ prime_box::comput_subscript_kern)
+ * eqn/limit.c (limit_box::compute_metrics):
+ * eqn/delim.c (build_extensible, delim_box::compute_metrics):
+ * eqn/sqrt.c (sqrt_box::compute_metrics): Protect possibly
+ negative numbers in `nr' requests with a leading 0.
+
+Wed Apr 3 15:58:23 1991 James Clark (jjc at jclark)
+
+ * eqn/special.c: New file.
+ * eqn/eqn.y: Declare token SPECIAL. Make it right associative.
+ Add new rule for simple.
+ * eqn/lex.c (token_table): Add SPECIAL.
+ * eqn/box.h: Declare make_special_box.
+ * eqn/Makefile: Add special.[co].
+
+Sat Mar 30 10:57:53 1991 James Clark (jjc at jclark)
+
+ * ps/devps/prologue: Possibly set packing to true while defining.
+ Create grops dictionary here. Initialize local variables before
+ defining procedures.
+ (PICTURE): Rename to PBEGIN. Also do save, noop showpage, count
+ the dictionary stack. Set strokeadjust and overprint to false if
+ the relevant operators are defined.
+ (PEND): New procedure.
+ * ps/ps.c (ps_printer::~ps_printer): In the prolog just include
+ prologue. Do everything else in the setup section.
+ (ps_printer::do_import): Just call PBEGIN and PEND around the
+ picture. Also push userdict before, and pop it afterwards.
+
+Wed Mar 27 07:59:50 1991 James Clark (jjc at jclark)
+
+ * troff/node.c (bracket_node::tprint): Brackets were being printed
+ 1m too low.
+
+ * macros/tmac.an (SH, SS): Set fill mode.
+
+Tue Mar 26 07:46:31 1991 James Clark (jjc at jclark)
+
+ * troff/div.c (top_level_diversion::begin_page): Set
+ high_water_mark to 0.
+
+Fri Mar 22 09:19:46 1991 James Clark (jjc at jclark)
+
+ * man/mdate.sh: New file.
+ * man/mdate.c: Deleted.
+ * man/Makefile: Use mdate.sh instead of mdate.
+ (mdate): Deleted.
+
+ * eqn/lex.c (do_gsize): Supply missing argument to error message.
+
+Tue Mar 19 11:06:50 1991 James Clark (jjc at jclark)
+
+ * man/mdate.c: New file.
+ * man/*.man: Replace modification date by @MDATE@.
+ * man/Makefile (.man.n): Replace @MDATE@ by `mdate $<`.
+ (mdate): New target.
+
+ * lib/font.c (text_file::next): Deal with arbitrarily long lines.
+ Remove illegal input characters.
+
+Mon Mar 18 08:32:25 1991 James Clark (jjc at jclark)
+
+ * macros/tmac.s (pg*start-col): Do .ns *after* running the hooks.
+
+Sat Mar 16 03:52:25 1991 James Clark (jjc at jclark)
+
+ * troff/div.c (begin_page): Change behaviour when
+ !first_page_begun and !break_flag.
+
+ * troff/input.c (do_name_test): Return 0 if argument is empty.
+
+ * troff/input.c (read_long_escape_name): Require closing ] to be
+ at same input level as opening [.
+
+ * troff/input.c (read_increment_and_escape_name): New function.
+ (get_copy, process_input_stack): Use this for \n.
+
+Fri Mar 15 00:31:48 1991 James Clark (jjc at jclark)
+
+ * troff/div.c (top_level_diversion::begin_page): Ignore the
+ current value of page_number if !first_page_begun.
+
+ * groff.c (main): Fix declaration of buf.
+
+ * troff/input.c (do_name_test): New function.
+ (token::next): Implement \A.
+ (token::next): Implement \e by turning it into a TOKEN_ESCAPE.
+ (token::description, token::add_to_node_list, token::process):
+ Handle TOKEN_ESCAPE.
+ * troff/token.h: New token TOKEN_ESCAPE.
+
+Thu Mar 14 10:22:26 1991 James Clark (jjc at jclark)
+
+ * pic/main.c (do_picture): Allow space before and after filename
+ following `<'. Check that the filename is not empty.
+
+Wed Mar 13 12:49:40 1991 James Clark (jjc at jclark)
+
+ * Version 1.01 released.
+
+ * dvi/devdvi/CompileFonts: Add cm*ss10 fonts.
+
+ * dvi/tmac.dvi: ftr HR to H.
+
+ * macros/tmac.e: Round up computation of $r.
+
+ * xditview/tmac.X: Don't give up completely in compatibility mode.
+ Use \n(.s instead of \n[.s].
+
+ * dvi/tmac.dvi: Don't give up completely in compatibility mode.
+ Use \(ci instead of \[ci]. Use \n(.s instead of \n[.s].
+ Add u to factors inside \s[...]. Rename frac to dvi-frac.
+ Translate \(FM onto \[prime] and \(!/ onto \[slashnot]; use these
+ short names in the char definitions.
+
+ * ps/tmac.ps: Don't give up completely in compatibility mode.
+ Fix the fraction definitions to use \n(.s and \(f/. Add an extra
+ quote in front of \n(.s. Add u to factors inside \s[...].
+
+Mon Mar 11 12:01:20 1991 James Clark (jjc at jclark)
+
+ * tty/tmac.tty: Call the nroff request.
+
+ * macros/tmac.e ((x, )x): Better definitions that work properly
+ in a diversion.
+ (@0, @1): Helper macros for (x.
+
+ * macros/tmac.e ($s, hl): Use \l rather than \D.
+
+ * tty/tmac.tty: Make it work better in compatibility mode.
+ (pchar): Rename to tty-char.
+
+ * macros/tmac.e (@E): New macro.
+ (r, i, b, rb, bi): Use @E.
+
+ * macros/tmac.e (@F): Don't use (;...) syntax.
+
+ * macros/tmac.e: Remove mention of \*(||/revisions. Mention that
+ it was modified for groff.
+
+ * macros/tmac.e: Make sure \n(ps and \n(es are >= \n(.V.
+
+ * macros/tmac.e (<., .>): Removed.
+ ([., .]): If \n(.V>=1v, use [] instead of superscripting.
+
+ * macros/tmac.e: Remove check that groff is being used.
+
+ * macros/tmac.e (@C): Change families only if using groff; turn
+ compatibility mode off while changing familes. Save compatibility
+ mode before changing families and restore it afterwards.
+
+ * macros/tmac.e (@h): Remove test for offset + line length.
+
+ * macros/tmac.e (sorry): Rename to @S. Use \$1 instead of \$0
+ (lo, th, ac): Define to call @S instead of using als.
+
+ * macros/tmac.e: Make $r and $R now contain \n(.v*100/\n(.sp, ie
+ the ratio of the vertical spacing to the point size in units
+ expressed as a percentage. Use these instead of $10r and $10R,
+ Delete $10r and $10R.
+
+ * lib/font.c (font::load): In default computation of space_width,
+ divide by sizescale. Use scale_round.
+
+ * macros/tmac.an (TP): Don't call `nf'.
+ (an-do-tag): Don't call `fi'.
+
+Sun Mar 10 09:52:35 1991 James Clark (jjc at jclark)
+
+ * troff/input.c (process_input_stack): Handle the case where
+ spaces at the beginning of an input line are followed by a
+ newline.
+
+Thu Mar 7 20:18:07 1991 James Clark (jjc at jclark)
+
+ * groff.c (device_table): Add PIC_X_OPTION for dvi device.
+ * groff.sh: Use pic -x with the dvi device.
+
+ * dvi/devdvi/FontMakefile (H): Don't use -s.
+
+ * dvi/devdvi/HI, dvi/devdvi/HB: New files.
+ * dvi/devdvi/Makefile: Add HI and HB to FONTS.
+ * dvi/devdvi/FontMakefile: Add rules for HI and HB. Include these
+ in FONTS.
+
+Mon Mar 4 13:20:14 1991 James Clark (jjc at jclark)
+
+ * ps/psfig.diff: New file.
+ * ps/tmac.psfig: New file.
+
+Sat Mar 2 00:15:09 1991 James Clark (jjc at jclark)
+
+ * macros/tmac.s (]=, ref*do-tl, ref*bib-print): Deleted.
+ (]-): Don't call ref*do-tl.
+
+ * macros/tmac.s (ref*end-print): Use XP if [F not defined.
+
+ * macros/tmac.s (ref*normal-print): Call FS rather than fn@do-FS.
+ (fn@do-FS): Rename to fn*do-FS.
+
+ * troff/input.c (transparent_translate): New function.
+ (process_input_stack): Apply transparent_translate before calling
+ diversion::transparent_output(unsigned char).
+
+Wed Feb 27 00:13:25 1991 James Clark (jjc at jclark)
+
+ * troff/input.c (do_define_macro): Define the macro before calling
+ skip_line.
+
+ * xditview/Makefile: Add DEVICES variable. Change install target
+ to use this.
+
+Tue Feb 26 10:46:22 1991 James Clark (jjc at jclark)
+
+ * groff.c (run_commands): Handle the possibility that there are
+ child processes other than those forked by us.
+
+Sun Feb 24 21:32:30 1991 James Clark (jjc at jclark)
+
+ * lib/string.c (string::append): New function.
+ * lib/stringclass.h: Declare it.
+
+Thu Feb 21 11:49:26 1991 James Clark (jjc at jclark)
+
+ * eqn/main.c (main): New option -N which sets
+ no_newline_in_delim_flag.
+ (do_file): If no_newline_in_delim_flag is set don't allow newlines
+ in delimiters.
+ * groff.c (main): Pass -N on to eqn.
+ (help, synopsis): Mention -N.
+ * groff.sh: Implement -N.
+
+Wed Feb 20 15:16:10 1991 James Clark (jjc at jclark)
+
+ * macros/tmac.s (]=, ref*bib-print, ref*do-tl): New macros.
+ (]-): Call ref*do-tl if ref*need-tl is non-zero.
+ (XP): Allow as initializer.
+
+Tue Feb 19 14:09:06 1991 James Clark (jjc at jclark)
+
+ * troff/env.c (environment::wrap_up_field): If field_spaces are
+ non-zero and we have a current_tab, subtract padding from
+ tab_distance. If this makes tab_distance <= 0, use the next tab
+ stop instead. If there isn't any next tab or it's a left tab,
+ wrap up the current tab.
+ (environment::start_field): Initialize tab_precedes_field.
+ (environment::wrap_up_tab): If there's a current field, update
+ pre_field_width, field_distance and tab_precedes_field.
+ * troff/env.h (environment::tab_precedes_field): New member.
+
+Fri Feb 15 01:24:00 1991 James Clark (jjc at jclark)
+
+ * ps/ps.c (ps_printer::do_file): New function.
+ (ps_printer::special): Bind to `file' special.
+ (ps_printer::do_exec): Set ndefined_styles to 0.
+
+Sat Feb 9 03:03:04 1991 James Clark (jjc at jclark)
+
+ * eqn/text.c (split_text): Grok \* and similar escapes sequences.
+ Avoid stripping first character from the start of unrecognized
+ escapes. Use lex_error instead of error to report errors.
+ * eqn/lex.c (get_token): Rework handling of escapes.
+ (lex_error): Move declaration into...
+ * eqn/eqn.h.
+
+ * xditview/xditview.c (main): Make -page option work.
+
+ * Makefile: Correct comment about -DBROKEN_SPOOLER and pageview.
+
+Wed Feb 6 12:28:43 1991 James Clark (jjc at jclark)
+
+ * macros/tmac.s (B2): Correct size of box.
+
+Tue Feb 5 00:37:35 1991 James Clark (jjc at jclark)
+
+ * macros/tmac.s (B2): Postpone drawing the box until in the
+ top-level diversion.
+
+ * tty/tmac.tty: Add font translations for C, CR, CW.
+
+ * groff.c (synopsis, help): Document -i.
+ * groff.sh: Implement -i.
+
+ * macros/tmac.s (@NH): Put a `.' after multi-part numbers.
+ Simplify the construction of SN.
+
+ * troff/number.c (parse_term): Give `|' a higher precedence.
+ * tbl/table.c (numeric_text_entry::simple_print): Parenthesise
+ accordingly.
+
+ * macros/tmac.s (B2): Use par@finish instead of par@reset.
+
+Mon Feb 4 12:36:09 1991 James Clark (jjc at jclark)
+
+ * lib/string.c (string::move): New function.
+ * lib/stringclass.h: Declare it.
+
+Sat Feb 2 16:02:16 1991 James Clark (jjc at jclark)
+
+ * troff/env.c (distribute_space): Add optional argument
+ `force_forward'.
+ (environment::wrap_up_field): Call distribute_space with
+ `force_forward' argument of 1.
+
+Fri Feb 1 19:36:33 1991 James Clark (jjc at jclark)
+
+ * lib/string.c, lib/stringclass.h (string::operator+=(char)):
+ Inline it. Move reallocation into...
+ (string::grow1): New function.
+ * pic/Makefile, tbl/Makefile, eqn/Makefile, ps/Makefile: Redo
+ dependencies to include library header files.
+ * lib/Makefile: Make string.c and lf.c depend on stringclass.h.
+
+Thu Jan 31 15:02:27 1991 James Clark (jjc at jclark)
+
+ * macros/tmac.s (@NH): Use the same number registers than -ms does
+ for the heading level counters. Use the same string that -ms does
+ for the number for this heading.
+
+Wed Jan 30 14:25:40 1991 James Clark (jjc at jclark)
+
+ * lib/new.c (operator new): Cast result of malloc to char *.
+
+ * troff/input.c (spring_trap, lookup_request): Add assert that nm
+ is not null.
+
+Tue Jan 29 18:08:05 1991 James Clark (jjc at jclark)
+
+ * groff.c (main): Support -i.
+
+Sun Jan 27 13:23:17 1991 James Clark (jjc at jclark)
+
+ * pic/pic.h: Include <osfcn.h>.
+
+ * ps/ps.c: Add declaration of mktemp.
+
+ * Makefile: Add -DHAVE_UNION_WAIT option for CPPDEFINES.
+ * groff.c: If HAVE_UNION_WAIT is defined, declare wait()'s
+ argument as union wait *.
+ (run_commands): If HAVE_UNION_WAIT is defined cast wait()'s
+ argument to union wait *.
+
+Sat Jan 26 12:04:52 1991 James Clark (jjc at jclark)
+
+ * tty/tmac.tty: Add definition of \(co.
+
+ * pic/object.c (make_arc): Only increase radius when radius
+ strictly less than d.
+ (arc_object::update_bounding_box): May need to add 4.0 to end_quad
+ more than once.
+
+ * troff/env.c (environment::environment(symbol),
+ environment::environment(const environment *)): Initialize
+ input_trap_count.
+
+Sat Jan 19 08:18:35 1991 James Clark (jjc at jclark)
+
+ * tbl/main.c (main): Add exit(0).
+
+ * ps/ps.c (ps_printer::~ps_printer): Use fseek instead of rewind.
+
+ * pic/main.c (main):
+ * eqn/main.c (main):
+ * tbl/main.c (main):
+ * etc/soelim.c (main):
+ * driver/printer.c (printer::~printer):
+ * troff/node.c (real_output_file::~real_output_file,
+ real_output_file::flush): Check for errors on stdout.
+
+ * most files: Add 1991 to copyright notice.
+
+ * macros/tmac.s: Don't test \n(.x and \n(.y.
+
+ * troff/input.c (token::next): Rename `escape_char' label to
+ `handle_escape_char' and `normal_char' label to
+ `handle_normal_char'.
+
+Thu Jan 17 15:46:35 1991 James Clark (jjc at jclark)
+
+ * groff.c (main, synopsis, help): Support -a option.
+ * groff.sh: Likewise. Also eliminate Zflag variable by adding -z
+ to trflags while parsing options.
+
+Tue Jan 15 13:07:27 1991 James Clark (jjc at jclark)
+
+ * troff/number.c (parse_term): With `m', `M' and `n' scale
+ indicators, convert scale factor to hunits before scaling.
+
+Mon Jan 14 12:39:12 1991 James Clark (jjc at jclark)
+
+ * lib/font.c (scale_round): Better test for overflow when n is
+ negative.
+
+Thu Jan 10 11:10:56 1991 James Clark (jjc at jclark)
+
+ * tbl/main.c (process_format): Add second argument of type
+ options*. Change callers. Allow opt->tab_char as well as '\t'
+ between format items.
+
+Mon Jan 7 12:30:18 1991 James Clark (jjc at jclark)
+
+ * macros/tmac.an (PD): With no arguments, make sure register PD is
+ at least \n[.V].
+ (TH): Call PD with no argument, instead of setting register PD
+ directly.
+
+Sun Jan 6 11:18:39 1991 James Clark (jjc at jclark)
+
+ * Version 1.00 released.
+
+Sat Jan 5 08:44:30 1991 James Clark (jjc at jclark)
+
+ * ps/tmac.ps, xditview/tmac.X: Add font translation of C to CR.
+
+ * dvi/devdvi/DESC: Mount CW instead of CR.
+
+ * dvi/tmac.dvi: Add definition of \(tm.
+
+ * dvi/devdvi/texsy.map: Add lh, and rh.
+ * dvi/devdvi/texex.map: Add lt, rt, lb, rb, lk, rk.
+ * dvi/devdvi/texmi.map: Add *o. Regenerate fonts.
+
+ * dvi/devdvi/FontMakefile: Generate H from cmss10.
+ * dvi/devdvi/Makefile: Install H.
+ * dvi/devdvi/H: New file.
+
+Fri Jan 4 15:04:57 1991 James Clark (jjc at jclark)
+
+ * troff/env.c (vertical_spacing): Don't allow vertical spacing to
+ be 0.
+
+Thu Jan 3 13:41:19 1991 James Clark (jjc at jclark)
+
+ * macros/tmac.s (@EN): Add \n(.V to the argument to ds@need.
+
+ * macros/tmac.pic (PS): Avoid attempting to set negative indent.
+
+ * macros/tmac.s (@EN): Handle the case where the equation is empty
+ but the label is not.
+
+Wed Jan 2 10:31:44 1991 James Clark (jjc at jclark)
+
+ * troff/groff.h: New warning category WARN_SPACE.
+ * troff/input.c: Add WARN_SPACE to DEFAULT_WARNING_MASK. Add
+ WARN_SPACE to warning_table.
+ (interpolate_macro): Give a warning of type WARN_SPACE if the name
+ is longer than two characters and is not defined, but the first
+ two characters do make a defined name.
+
+ * PROBLEMS: New file.
+
+ * CHANGES: New file.
+ * README-0.6, README-1.00: Deleted.
+
+ * groff.c, groff.sh: Add X75-12 and X100-12 devices.
+ * xditview/devX75/Makefile: Make devX75-12.
+ * xditview/devX100/Makefile: Make devX100-12.
+
+ * xditview/devX100/eqnchar, xditview/devX75/eqnchar,
+ dvi/devdvi/eqnchar, ps/devps/eqnchar: Remove use of \R.
+
+Tue Jan 1 19:24:01 1991 James Clark (jjc at jclark)
+
+ * README-0.7: Rename to README-1.00.
+
+ * macros/tmac.pic: New file.
+ * macros/Makefile (install.nobin): Install tmac.pic.
+
+Mon Dec 31 10:40:53 1990 James Clark (jjc at jclark)
+
+ * troff/env.c (hyphen_word): Correct the test for whether the
+ token is a hyphen. Reset npos to 0.
+
+ * macros/tmac.s (par@sup-start, par@sup-end): New implementations.
+
+Sun Dec 30 15:53:13 1990 James Clark (jjc at jclark)
+
+ * macros/tmac.s (ds*common-end): Call par*reset.
+ (PE): Likewise.
+ (par@reset-indent): Deleted.
+
+ * macros/tmac.s (@IP): Divert the label.
+
+Sat Dec 29 14:33:32 1990 James Clark (jjc at jclark)
+
+ * xditview/draw.c (setGC): Use a line width of .1m rather than
+ .04m by default; round rather than truncate value.
+
+ * tbl/table.c (class empty_entry): New class.
+ (empty_entry::empty_entry, empty_entry::line_type): New functions.
+ (table::add_entry): Represent empty entries by objects of type
+ empty_entry.
+ (table_entry::line_type): Return -1.
+ (table::determine_row_type): Ignore entries with line_type 0.
+ Treat type -1 as non-lines.
+
+Fri Dec 28 15:04:41 1990 James Clark (jjc at jclark)
+
+ * ps/devps/textmap, xditview/libXdvi/DviChar.c, tty/devlatin1/R.proto,
+ macros/tmac.s: Rename \(-d to \(Sd.
+
+Thu Dec 27 12:35:47 1990 James Clark (jjc at jclark)
+
+ * ps/devps/textmap: Add `sd', `/_' and `3d' characters.
+ * xditview/libXdvi/DviChar.c: Likewise.
+ * dvi/devdvi/texsy.map: Add `<<', `>>'.
+
+Wed Dec 26 13:33:23 1990 James Clark (jjc at jclark)
+
+ * troff/div.c (top_level_diversion::begin_page): Call
+ init_output() if the_output is 0.
+
+Sat Dec 22 12:35:29 1990 James Clark (jjc at jclark)
+
+ * troff/input.c: Replace ESCAPE_E by ESCAPE_e and ESCAPE_C by
+ ESCAPE_c.
+ (get_copy): Turn \E into ESCAPE_E.
+ (token::process, asciify): Handle ESCAPE_E.
+
+ * macros/tmac.s (ds*common-end, par@reset): Add `.rj 0'.
+ (RD): New macro.
+ (DS): Implement `.DS R'.
+
+Fri Dec 21 11:41:53 1990 James Clark (jjc at jclark)
+
+ * macros/tmac.s (FS): New macro.
+
+ * macros/tmac.s (fn@do-FS): Use @LP instead of LP.
+
+ * macros/tmac.s (cov*tl-init): Remove after first execution
+ instead of aliasing to @nop. Call top of page macro explicitly
+ instead of setting trap; call @init first. Set pg@top as top of
+ page macro.
+ (cov*auto-init): Deleted. Set cov*tl-init instead of
+ cov*auto-init as top of page trap.
+ (TL, LP): Do a break instead of calling cov*tl-init.
+ (cov*print): With RP format but no TL, alias FS and FE to @FS and
+ @FE; in this case also give a warning and always start another
+ page. No need to set pg@top here.
+ (cov*tl-init): Rename to cov*first-page-init.
+
+ * macros/tmac.s (RP): Do `.pn 0'.
+ (cov*tl-init): With RP format don't do `.pn 0'.
+
+ * macros/tmac.s (pg@cs-top): Set no space mode.
+
+ * macros/tmac.s (par@TL, par@AU, par@AI): New macros.
+ (cov*ab-init): Alias TL, AU and AI to these.
+
+Thu Dec 20 10:10:50 1990 James Clark (jjc at jclark)
+
+ * macros/tmac.s (@EQ): Move the space before the equation into @EN
+ (@EN): Do nothing unless \n[dl] is > 0.
+
+Tue Dec 18 12:20:47 1990 James Clark (jjc at jclark)
+
+ * pic/object.c (ellipse_object::radius): New function.
+
+ * VERSION: Change version to 0.7.
+
+ * tbl/table.c (block_entry::do_divert): Declare return type as
+ void.
+ (block_entry::divert, alphabetic_block_entry::divert): Return 1.
+
+Mon Dec 17 12:30:34 1990 James Clark (jjc at jclark)
+
+ * troff/column.c: New file.
+ * troff/Makefile: Corresponding changes.
+
+ * troff/hvunits.c (scale(vunits, vunits, vunits)): New function.
+ Friend of vunits.
+
+ * troff/div.c (top_level_diversion::space): If the space causes
+ the first-page transition and springs a trap, truncate the space
+ to 0.
+
+Fri Dec 14 12:30:02 1990 James Clark (jjc at jclark)
+
+ * ps/ps.c (ps_printer::do_import): Add a `clear' after including
+ the document.
+
+ * pic/troff.c (troff_output::line_thickness,
+ troff_output::set_fill): Do a horizontal motion to compensate for
+ the width of the \D escape sequence.
+
+Thu Dec 13 10:17:14 1990 James Clark (jjc at jclark)
+
+ * xditview/tmac.X: Reinstate definition of \(rn, but only for X100
+ (not X75).
+
+ * eqn/sqrt.c (sqrt_box::compute_metrics): Supply missing argument
+ to printf.
+
+ * tbl/table.c (simple_entry::simply_print): Don't declare as pure.
+ Supply empty definition.
+ (text_entry::simple_print, simple_text_entry::simple_print):
+ Delete declarations.
+ (table::add_entry): Represent empty entries by objects of type
+ `simple_entry'.
+
+Wed Dec 12 08:50:48 1990 James Clark (jjc at jclark)
+
+ * troff/Makefile: Remove -DHYPHEN_CONTROL from DEFINES.
+
+ * tbl/table.c (left_text_entry::add_tab): New function.
+
+ * macros/tmac.s: Make @RT an alias for par@reset. Make RT
+ initialize like LP.
+
+Mon Dec 10 11:19:55 1990 James Clark (jjc at jclark)
+
+ * troff/env.c (environment::start_field): Give an error message if
+ there is no next tab.
+
+Sun Dec 9 11:46:40 1990 James Clark (jjc at jclark)
+
+ * troff/env.c (hyphenate): Skip initial elements with zero
+ hyphenation code.
+
+ * macros/tmac.s (par@init): Keep VS in points rather than units.
+
+Sat Dec 8 23:00:27 1990 James Clark (jjc at jclark)
+
+ * pic/main.c (main): Implement `-c' option.
+ * pic/output.h: Declare make_tpic_output().
+ * pic/tex.c (tex_output::set_pen_size): Make it virtual and
+ protected.
+ (tpic_output): New class.
+ (tpic_output::tpic_output, tpic_output::set_pen_size,
+ tpic_output::command, make_tpic_output): New functions.
+
+Fri Dec 7 11:57:41 1990 James Clark (jjc at jclark)
+
+ * tbl/main.c (main): Call `.ab' if \n(.g is false. Define TS/TE
+ if they're not already defined.
+ * tbl/table.c (init_output): Don't test \n(.g.
+
+ * troff/input.c (do_if_request): Delete `g' condition. Recognize
+ `d', `r' and `c' conditions even in compatibility mode.
+
+Tue Dec 4 09:13:47 1990 James Clark (jjc at jclark)
+
+ * ps/tmac.ps (ps-bb): Protect against negative numbers in bounding
+ box.
+
+Mon Dec 3 07:18:26 1990 James Clark (jjc at jclark)
+
+ * troff/env.h (environment::prev_line_interrupted): New member.
+ (environment::get_prev_line_interrupted): New function.
+ * troff/env.c (environment::newline): Set prev_line_interrupted.
+ (environment::environment(const environment *),
+ environment::environment(symbol)): Initialize
+ prev_line_interrupted.
+ * troff/input.c (process_input_stack): Don't give special
+ treatment to space and newline at the beginning of the line if the
+ previous line was interrupted.
+
+Sat Dec 1 15:48:37 1990 James Clark (jjc at jclark)
+
+ * eqn/eqn.y: Disallow PRIME by itself.
+ * eqn/lex.c (token_table): Bind `opprime' instead of `prime' to
+ PRIME.
+ (def_table): Remove definition of '. Define prime to be `.
+
+ * eqn/eqn.y: Split off part of rule `script' into a new rule
+ `nonsup'.
+
+Fri Nov 30 10:23:44 1990 James Clark (jjc at jclark)
+
+ * macros/tmac.s ({, }): New string aliases.
+
+Thu Nov 29 11:34:40 1990 James Clark (jjc at jclark)
+
+ * README-0.7: New file.
+
+Wed Nov 28 10:09:57 1990 James Clark (jjc at jclark)
+
+ * macros/tmac.s: New file.
+ * man/groff_ms.man: New file.
+ * Makefile: Add definition of TMAC_S. Pass TMAC_S in SUBFLAGS.
+ * Makefile.bd: Similarily.
+ * man/Makefile: Add groff_ms.n to MAN7PAGES. Replace @TMAC_S@. Add
+ definition of TMAC_S.
+ * macros/Makefile: Add definition of TMAC_S. Install tmac.s.
+ * macros/TODO: New file.
+
+Sat Nov 24 20:04:54 1990 James Clark (jjc at jclark)
+
+ * troff/env.c (right_justify): New function.
+ (init_env_requests): Bind this to request "rj".
+ (center_lines): Set right_justify_lines to 0. If we get a bad
+ integer, center 1 line.
+ (environment::environment(symbol), environment::environment(const
+ environment *)): Initialize right_justify_lines.
+ (environment::get_right_justify_lines): New function.
+ (init_env_requests): Bind this to number_register ".rj".
+
+ * troff/env.c (environment::choose_breakpoint): Implement
+ hyphenation_margin and hyphenation_space.
+ (environment::get_hyphenation_space,
+ environment::get_hyphenation_margin): New functions.
+ (init_env_requests): Bind these to .hys and .hym.
+ (hyphenation_space_request, hyphenation_margin_request): New
+ functions
+ (init_env_requests): Bind these to hys and hym.
+ (environment::environment(symbol), environment::environment(const
+ environment *)): Initialize hyphenation_margin and
+ hyphenation_space.
+ * troff/env.h: Corresponding changes to class environment.
+
+Fri Nov 23 09:08:16 1990 James Clark (jjc at jclark)
+
+ * troff/div.c (blank_line): Always do a break.
+
+ * eqn/box.c (do_text): Turn off escapes while appending text to
+ string.
+
+Thu Nov 22 10:58:59 1990 James Clark (jjc at jclark)
+
+ * troff/input.c (while_break_request, while_continue_request): New
+ functions.
+ (init_input_requests): Bind these to "break" and "continue".
+ (while_depth, while_break_flag): New variables.
+ (while_request): Update while_depth. Break out of loop if
+ while_break_flag is set.
+
+Wed Nov 21 10:54:40 1990 James Clark (jjc at jclark)
+
+ * tbl/table.c (init_span_reg): Initialize span_width_reg to \n(.H
+ rather than 0.
+
+Mon Nov 19 00:45:03 1990 James Clark (jjc at jclark)
+
+ * Makefile: Include -DBROKEN_SPOOLER by default. Expand comment.
+
+ * stringify: New file.
+ * Makefile (groff.o): Use stringify.
+
+ * xditview/tmac.X: Remove definition of \(rn.
+ * xditview/libXdvi/DviChar.c: Remove radicalex from
+ Adobe_symbol_map.
+
+Sat Nov 17 10:44:58 1990 James Clark (jjc at jclark)
+
+ * tbl/table.c (table::add_entry): Allow alphabetic text blocks.
+ (alphabetic_block_entry::alphabetic_block_entry,
+ alphabetic_block_entry::divert, alphabetic_block_entry::print):
+ New functions.
+ (block_entry::divert): Split off body into ...
+ (block_entry::do_divert): If the block is alphabetic, subtract 2n
+ from the line length; also update the span width to dl+2n, and the
+ alphabetic span width to dl.
+
+ * driver/input.c (do_file): While reading argument to D command,
+ when expanding buffer, multiply szp by sizeof(int) rather than 2
+ in the argument to memcpy.
+
+ * tbl/table.c (compute_span_width): Add 2n rather than 1n to the
+ width of alphabetic columns.
+
+Fri Nov 16 06:34:27 1990 James Clark (jjc at jclark)
+
+ * troff/node.c (lookup_family): Supply second argument to lookup.
+
+ * troff/dictionary.c (dictionary::lookup): After an unsuccesful
+ search, return immediately if v is 0.
+
+ * pic/troff.c: Define EQN_NO_EXTRA_SPACE_REG.
+ (troff_output::start_picture): Set this reg.
+ (troff_output::end_picture): Remove this reg
+ * eqn/box.c (box::extra_space): Don't produce `\x's if
+ EQN_NO_EXTRA_SPACE_REG is defined.
+
+ * eqn/eqn.y: Allow just a PRIME to be a `simple'.
+ * eqn/text.c (split_text): Map ' to \(fm when it's the first
+ character.
+
+Thu Nov 15 10:35:06 1990 James Clark (jjc at jclark)
+
+ * macros/tmac.e: Use font 3 instead of B in $c. Remove `bd'
+ requests.
+
+ * troff/div.c (top_level_diversion::top_level_diversion):
+ Initialize page_number to 0.
+
+Wed Nov 14 21:41:58 1990 James Clark (jjc at jclark)
+
+ * groff/troff (environment::environment(const environment *)):
+ Initialize name to e->name, rather than "anonymous".
+
+Sat Nov 10 01:59:37 1990 James Clark (jjc at jclark)
+
+ * xditview/libXdvi/Dvi.c (ShowDvi): If eof is encountered, reset
+ requested_page. Split middle part into ...
+ (FindPage): New function.
+ (SetValues): If we don't yet know the last page, and the requested
+ page is greater than the current page, call FindPage.
+ Update the font_map_string before doing this.
+
+ * xditview/tmac.X: Add definitions of \(sq, \(ga, \(dg and \(dd.
+ Translate \(lh and \(rh into left and right double arrows.
+
+ * troff/node.c (class hyphen_inhibitor_node): New class.
+ (hyphen_inhibitor_node::hyphen_inhibitor_node,
+ hyphen_inhibitor_node::copy, hyphen_inhibitor_node::same,
+ hyphen_inhibitor_node::type,
+ hyphen_inhibitor_node::get_hyphenation_type): New functions.
+ (node::add_discretionary_hyphen): Use hyphen_inhibitor_node rather
+ than dbreak_node(0, 0) to represent a `\%' at the beginning of a
+ word.
+
+Fri Nov 9 16:05:38 1990 James Clark (jjc at jclark)
+
+ * troff/node.h (dummy_node::get_hyphenation_type,
+ transparent_dummy_node::get_hyphenation_type): Declare them.
+ * troff/node.c: (dummy_node::get_hyphenation_type,
+ transparent_dummy_node::get_hyphenation_type): New functions.
+
+Wed Nov 7 10:09:06 1990 James Clark (jjc at jclark)
+
+ * xditview/libXdvi/draw.c: If M_PI not defined after including
+ math.h, then define it.
+
+ * xditview/Makefile: Add definition of AR. Pass it to the submake
+ in libXdvi.
+ * xditview/libXdvi/Makefile: Add definitions of AR and RANLIB.
+
+Tue Nov 6 10:14:27 1990 James Clark (jjc at jclark)
+
+ * troff/dictionary.h (object_dictionary::alias): Declare return
+ value as int.
+ * troff/dictionary.c (object_dictionary::alias): Return non-zero
+ if the old name was defined.
+ * troff/input.c (alias_macro): Give a warning if the old name was
+ not defined.
+ * troff/reg.c (alias_reg): Likewise.
+
+Mon Nov 5 00:31:39 1990 James Clark (jjc at jclark)
+
+ * troff/input.c (token::next): Delete implementation of \R.
+
+ * macros/Makefile: Strip comments from tmac.e while installing it.
+
+ * troff/input.c: New variable `nroff_mode'.
+ (troff_request, nroff_request): New functions.
+ (init_input_requests): Bind `troff' and `nroff' to troff_request
+ and nroff_request.
+ (do_if_request): Compute results of t and n conditions from
+ nroff_mode.
+
+ * text/text.c (split_text): Fix typo in >=.
+
+ * eqn/lex.c: Add definition of `==' to def_table.
+
+Fri Nov 2 02:49:09 1990 James Clark (jjc at jclark)
+
+ * pic/tex.c (tex_output::start_picture): Change the definitions of
+ \graph and \graphtemp so that they work properly with Plain TeX.
+
+ * pic/tex.c (tex_output::solid_arc): Ensure that the second angle
+ argument to `ar' is not less than the first.
+
+ * pic/pic.y: Allow a comma between elements of the variable list
+ in the argument to `reset'.
+
+ * pic/object.c (arc_object::arc_object): Fix computation of
+ radius.
+
+ * eqn/main.c (main): Add exit(0).
+
+Thu Nov 1 02:03:50 1990 James Clark (jjc at jclark)
+
+ * troff/div.c (begin_page): Test no_space_mode after doing the
+ break, but still push the page ejector cookie before doing the
+ break. Also set the next page number after doing the break.
+
+ * xditview/xditview.c (NewFile): Don't set the title and icon name
+ if this is the first file and its name is `-'.
+ * groff/groff.c: Define a new device flag XT_OPTION. Set it for
+ the X75 and X100 devices.
+ (main): If a device has the XT_OPTION flag set and there's exactly
+ one file argument, pass the driver -xrm and -title options to set
+ the icon name and window title to the name of the file.
+
+ * troff/env.c (environment_switch): If there was an argument but
+ it wasn't a valid number or name, then pop an environment but
+ don't give an error message on underflow.
+
+ * troff/number.c (start_number): Correct spelling in error message.
+
+ * troff/input.c (token::delimiter): Don't print an error message
+ if err is false.
+
+ * xditview/libXdvi/parse.c (ParseInput): In case 'D', only call
+ ParseDrawFunction if dw->display_enable is true.
+
+Wed Oct 31 05:49:50 1990 James Clark (jjc at jclark)
+
+ * pic/pic.y: Parse text positioning like normal attributes, so as
+ to allow `"text" at 0,0 ljust'. Don't allow `center' as a
+ positioning attribute.
+
+Mon Oct 29 22:50:38 1990 James Clark (jjc at jclark)
+
+ * tbl/main.c (process_data): When in state START while reading a
+ text block, don't change to state MIDDLE if c is a newline.
+
+Sun Oct 28 21:59:56 1990 James Clark (jjc at jclark)
+
+ * dvi/dvi.c (dvi_printer::begin_page): Rename `i' variable to `j'
+ so as to avoid shadowing parameter.
+
+Wed Oct 24 18:35:39 1990 James Clark (jjc at jclark)
+
+ * tbl/table.c (trim_space): Deleted.
+ (table::add_entry): Don't call trim_space.
+
+Mon Oct 22 03:48:39 1990 James Clark (jjc at jclark)
+
+ * VERSION: Change version to 0.6.
+
+ * troff/number.c (parse_expr): Make == work.
+
+Sat Oct 20 11:28:17 1990 James Clark (jjc at jclark)
+
+ * man/grog.man: New file.
+ * man/Makefile: Add grog.n to MAN1PAGES.
+ * etc/grog.sh: New file.
+ * etc/Makefile: Install grog.sh as grog.
+
+Fri Oct 19 11:17:15 1990 James Clark (jjc at jclark)
+
+ * troff/input.c (token::next): Implement \E.
+
+Thu Oct 18 11:56:24 1990 James Clark (jjc at jclark)
+
+ * xditview/tmac.X: Change font translations to match tmac.ps.
+
+ * troff/input.c (non_empty_name_warning): Don't give a warning if
+ `\{' terminates the name.
+
+Tue Oct 16 10:04:23 1990 James Clark (jjc at jclark)
+
+ * ps/devps/symbol.diff: New file.
+ * ps/devps/FontMakefile: Mention symbol.diff.
+
+Sun Oct 14 11:46:46 1990 James Clark (jjc at jclark)
+
+ * troff/node.c (font_position): Use get_long_name to read the
+ external_name.
+
+ * troff/env.c (environment_switch): If we get a number that's < 0
+ or >= NENVIRONMENTS, treat it like a name.
+ Change NENVIRONMENTS to 10.
+
+ * troff/groff.h: Remove definition of FONTS_MAX.
+ * troff/node.h (class font_family): Make map a pointer instead of
+ an array. Add a map_size member. Make it a class. Make nm const
+ and public. Make invalidate_fontno a friend.
+ * troff/node.c: Define font_table_size. Make font_info a pointer
+ rather than an array.
+ (class troff_output_file): Allocate font_position dynamically. Add
+ nfont_positions member.
+ (troff_output_file::set_font): Grow font_position if necessary.
+ (troff_output_file::~troff_output_file): Delete font_position.
+ (troff_output_file::troff_output_file): Allocate font_position.
+ (grow_font_table): New function.
+ (troff_output_file::really_begin_page,
+ troff_output_file:really_copy_page): Use nfont_positions rather
+ than FONTS_MAX.
+ (mount_font_no_translate, mount_style): Call grow_font_table if
+ necessary.
+ (font_family::font_family): Allocate map.
+ (font_family::make_definite): Grow map if necessary. Use
+ font_table_size instead of FONTS_MAX.
+ (font_family::~font_family): New function.
+ (invalidate_fontno): Use font_family::map_size.
+ (get_fontno, env_space_width, env_half_narrow_space_width,
+ env_narrow_space_width, symbol_fotno, is_good_fontno,
+ get_bold_fontno, make_glyph_node): Use font_table_size rather than
+ FONTS_MAX.
+ (next_available_font_position): Never return 0.
+
+Fri Oct 12 10:17:52 1990 James Clark (jjc at jclark)
+
+ * ps/tmac.ps: Add font translations for compatibility with dpost.
+
+Thu Oct 11 12:09:03 1990 James Clark (jjc at jclark)
+
+ * eqn/pile.c: Rename default_baseline_sep to baseline_sep.
+ Move BASELINE_SEP_FORMAT and COLUMN_WIDTH_FORMAT into pbox.h.
+ Move definitions baseline_sep, shift_down, column_sep,
+ matrix_side_sep into...
+ * eqn/box.c: Add them to param_table.
+ * eqn/pbox.h: Add declarations to pbox.h.
+
+ * troff/input.c (set_string): Cast value to unsigned char *.
+
+ * troff/token.h (process_input_stack): Declare it static before
+ declaring it a friend.
+
+Wed Oct 10 09:59:13 1990 James Clark (jjc at jclark)
+
+ * dvi/devdvi/texex.map: Fix positions of extensible brace middle
+ and bottom.
+ * dvi/devdvi/EX: Regenerate.
+
+ * troff/input.c (init_charset_table): Make ", ', ), ], *, \(dg
+ transparent.
+
+Tue Oct 9 08:34:02 1990 James Clark (jjc at jclark)
+
+ * eqn/lex.c: In defaults_table, make definition of `dot' call
+ `dot_def'. Don't explicitly make it roman. Similarily for other
+ accents.
+
+ * pic/lex.c (for_input::for_input): Add by_is_multiplicative
+ argument.
+ (for_input::get, for_input::peek): Use this.
+ (do_for): Add by_is_multiplicative argument.
+ * pic/pic.y: Change optional_by clause to allow '*' after `by'.
+ Change semantic value of optional_by to be a double plus a flag
+ saying whethet the by clause is multiplicative.
+
+ * eqn/lex.c (get_delimited_text): Remember location of start of
+ definition. Improve error handling when EOF is encountered.
+
+ * lib/font.h: Rename handle_x_command to
+ handle_unknown_font_command.
+ * lib/font.c (font::load): Call handle_unknown_font_command for
+ any unknown command in the font description file. Don't call
+ handle_x_command. Include the name of the command in the argv.
+ Improve message for unknown command after kernpairs or charset
+ command.
+ * ps/ps.c (ps_font::handle_x_command): Rename to
+ handle_unknown_font_command. Remove message about `x download'
+ command. Give error message for wrong number of arguments.
+ * ps/devps/afmtodit: Generate `encoding' instead of `x encoding'.
+ * dvi/dvi.c (dvi_font::handle_x_command): Rename to
+ handle_unknown_font_command. Give an error message for wrong
+ number of arguments. Rename design_size to designsize.
+ * dvi/tfmtodit.c (main): Generate `checksum' instead of `x
+ checksum', `designsize' instead of `design_size'.
+
+Mon Oct 8 00:38:55 1990 James Clark (jjc at jclark)
+
+ * eqn/*.[chy]: Change underaccent to uaccent.
+
+ * eqn/eqn.y: Add rule for underaccent. Declare UNDERACCENT token;
+ give it the same precedence as ACCENT.
+ * eqn/other.c (make_underaccent_box): New function.
+ * eqn/box.h: Declare it.
+ * eqn/lex.c: Add UNDERACCENT to token_table. Add utilde to
+ def_table.
+
+Sun Oct 7 11:25:16 1990 James Clark (jjc at jclark)
+
+ * pic/pic.y (reset_all): New function. Called in rule for RESET.
+ (parse_init): Call reset_all.
+ (define_variable): When defining scale reset only those
+ pre-defined variables that are scaled.
+ (defaults_table): Add `scale' as non-scaled value.
+
+ * pic/pic.y: Redo parsing of text adjustments: parse adjustments
+ together with the text; allow any number of positioning words;
+ allow center as a positioning word.
+
+ * pic/object.c (output::compute_scale): Get picture maximum height
+ and width from variables called maxpswid and maxpsht.
+ * pic/pic.y: Add maxpswid and maxpsht to defaults_table.
+
+Sat Oct 6 10:16:56 1990 James Clark (jjc at jclark)
+
+ * pic/object.c (object_spec::make_text): Multiply textht by number
+ of text items.
+
+ * pic/pic.y: Allow `sprintf("string", expr,...)' wherever text can
+ occur.
+ (do_sprintf): New function.
+ (pic.gperf): Add sprintf token.
+ (text, sprintf): New rules.
+
+ * pic/pic.y: `rand()' with no arguments returns a random number
+ in the range [0,1).
+
+ * pic/pic.y: Allow a bare expression to be an attribute: change
+ precedences to support this. Change optional_ordinal rule to
+ optional_ordinal_last to avoid reduce/reduce conflict.
+ * pic/object.c (object_spec::object_spec): Initialize direction.
+
+ * pic/pic.y: Implement ^ operator meaning exponentiation.
+
+ * troff/node.h: Add default argument to mount_font.
+ * troff/node.c (font_position): Read an optional third argument
+ giving the external_name.
+ (mount_font): Add optional argument giving the external_name.
+ (mount_font_not_translate): Have additional argument giving
+ external name. Use this name to load the font. Pass both names
+ to font_info::font_info.
+ (font_info::font_info): Have additional argument giving
+ external_name.
+ (class tfont): New member external_name.
+ (font_info::get_tfont): Use external name to construct tfont_spec.
+
+Fri Oct 5 04:03:13 1990 James Clark (jjc at jclark)
+
+ * eqn/lex.c (init_table): Add argument giving device. Define
+ name of device to be "1".
+ (do_ifdef): Counts as true if the argument has been defined with
+ `define'.
+ * eqn/main.c (main): Call init_table with device argument. Make
+ device local to main.
+ * eqn/eqn.h: Change declaration of init_table. Remove declaration
+ of device.
+
+ * pic/lex.c (get_delimited): Allow text to be delimited by
+ matching {}s. Don't recognize ending delimiter within a string.
+
+ * troff/input.c (get_delim_name): New function.
+ (token::next): Implement \C.
+
+ * lib/font.c (font::load): Grok ---. Add an alias for each
+ character based on its code.
+ (font::get_code_width): Deleted.
+ * lib/font.h (class font): Declare font::number_to_index().
+ Remove declaration of font::get_code_width.
+ * lib/nametoindex.c (font::name_to_index): Add 512 rather than 256
+ to indices of named characters.
+ (font::number_to_index): New function.
+ * troff/input.c (font::number_to_index): New function.
+ (get_charinfo_by_number, charinfo::get_number,
+ charinfo::set_number): New functions.
+ (token::next): Turn \N into a TOKEN_NUMBERED_CHAR.
+ (token::process, token::description, token::get_char,
+ token::add_to_node_list, token::operator==): Handle
+ TOKEN_NUMBERED_CHAR.
+ * troff/charinfo.h: Declare get_charinfo_by_number,
+ charinfo::get_number, charinfo::set_number. Add NUMBERED flag to
+ charinfo class.
+ (charinfo::numbered): New function.
+ * troff/token.h: Add TOKEN_NUMBERED_CHAR.
+ * troff/env.h (class environment): Remove declaration of ...
+ * troff/env.c (environment::make_numbered_char_node): Deleted.
+ * troff/node.c (make_numbered_node): Deleted.
+ (class numbered_glyph_node): Remove.
+ (troff_output_file::put_char_width, troff_output_file::put_char):
+ Handle numbered chars.
+ (troff_output_file::numbered_char): Removed.
+ (tfont::get_code_width): Removed.
+ (make_glyph_node): Don't search special fonts for numbered
+ characters.
+ * troff/node.h: Remove declaration of make_numbered_node.
+ * driver/input.c (do_file): Handle N command.
+ * driver/printer.h: Add declaration of ...
+ * driver/printer.c (printer::set_numbered_char): New function.
+ * dvi/tfmtodit.c (main): Generate unnamed entries.
+ * ps/devps/afmtodit: Likewise.
+ * xditview/xtotroff.c (MapFont): Likewise.
+ * xditview/libXdvi/parse.c (ParseInput): Grok N command.
+
+ * tbl/main.c (process_format): If multiple widths are specified
+ for a column but all the widths are the same, don't give an error
+ message.
+
+ * tbl/table.c (table::do_row): If the current row is all lines and
+ the stuff doesn't contains a line, mark the top of the row after
+ printing stuff before the row. If the current row is not all
+ lines and the stuff doesn't contain a line, don't unnecessarily
+ mark the top of the row before printing the stuff.
+
+Mon Oct 1 11:42:00 1990 James Clark (jjc at jclark)
+
+ * troff/groff.h: Remove MAX_PATH.
+ * troff/input.c (open_file): Dynamically allocate space for the
+ path.
+ (open_mac_file, process_macro_file): Corresponding changes.
+
+Sun Sep 23 18:56:26 1990 James Clark (jjc at jclark)
+
+ * troff/node.h (class output_file): Make copy_file pure. Add
+ vspace method ifdef COLUMN. Add is_printing method.
+ * troff/node.c: Add class printing_reg. Add class
+ real_output_file. Derive other output_file classes from
+ real_output_file; in these classes rename begin_page to
+ really_begin_page, print_line to really_print_line, copy_file to
+ really_copy_file, transparent_char to really_transparent_char.
+ Move output_file::flush to real_output_file. Add printing member
+ to class output_file.
+ * troff/div.h: Remove printing member from top_level_diversion.
+ Add vspace member function to class diversion ifdef COLUMN. Add
+ some declarations ifdef COLUMN.
+ * troff/div.c (top_level_diversion::copy_file,
+ top_level_diversion::transparent_output,
+ top_level_diversion::output): Don't test printing member before
+ output.
+ * troff/input.c: Handle initial variable_space_request ifdef
+ COLUMN.
+ * troff/Makefile: Add column.c but comment it out. Add -DCOLUMN
+ but comment it out.
+
+Sat Sep 22 11:32:22 1990 James Clark (jjc at jclark)
+
+ * troff/div.c (diversion::need): Make any space forced. If we
+ sprung a trap, set truncated_space to minus the distance to the
+ trap and set needed_space to the amount that was needed.
+ (top_level_diversion::space): A forced space turns no_space_mode
+ off.
+ (class constant_vunits_reg): New class.
+ (init_div_requests): Implement number registers .trunc and .ne
+ using constant_vunits_reg.
+ (class truncated_space_reg): Deleted.
+
+ * troff/div.h: Don't have a no_space_mode member in diversion.
+ Instead have it in top_level_diversion.
+ * troff/div.c (diversion::diversion): Don't initialize
+ no_space_mode.
+ (top_level_diversion::top_level_diversion): Initialize
+ no_space_mode.
+ (no_space, restore_spacing): Do nothing if curdiv != topdiv.
+ (macro_diversion::output): Don't clear no_space_mode.
+
+ * troff/input.c (diverted_space_node::reread): Don't call
+ environment::do_break. In fill mode, act like a blank line.
+ (diverted_copy_file_node::reread): Don't call
+ environment::do_break.
+
+ * troff/div.c (blank_line): New function.
+ * troff/div.h: Declare it.
+ * troff/input.c (process_input_stack): Call it.
+
+ * troff/div.c (truncated_space_reg::get_string): New function.
+ (init_div_requests): Bind to .trunc.
+ (space_request, top_level_diversion::space,
+ top_level_diversion::output, macro_diversion::space,
+ macro_diversion::output): Update truncated_space.
+ (macro_diversion::output): Redo calculations when trap sprung.
+ (macro_diversion::output, macro_diversion::space): No need for
+ trap_flag.
+
+ * troff/div.c (top_level_diversion::output): Set nl_reg_contents
+ after truncating post line spacing.
+
+Fri Sep 21 11:27:25 1990 James Clark (jjc at jclark)
+
+ * ps/devps/prologue (MF, SF): Make them work even if setfont is
+ defined as a procedure rather than as an operator.
+
+Thu Sep 20 12:55:05 1990 James Clark (jjc at jclark)
+
+ * troff/div.c (macro_diversion::space): Ignore no_space_mode.
+
+Wed Sep 19 10:54:37 1990 James Clark (jjc at jclark)
+
+ * troff/div.c (top_level_diversion::output): Merge
+ output_file::print_line and output_file::end_of_line member
+ functions.
+ * troff/div.h (class output_file):
+ * troff/node.c (troff_output_file::print_line,
+ troff_output_file::end_of_line, output_file::end_of_line,
+ ascii_output_file::print_line, suppress_output_file::print_line):
+ Corresponding changes.
+
+Tue Sep 18 11:31:47 1990 James Clark (jjc at jclark)
+
+ * troff/input.c (token::next): Don't give a warning for `\.'.
+
+ * troff/env.c (environment::get_center_lines): New function.
+ (init_env_requests): Bind number register .ce to it.
+ * troff/env.h: Declare it.
+ * tbl/table.c (table::init_output): Define reset macro to restore
+ .ce. If center option not given, store .ce in SAVED_CENTER_REG.
+ Then do .ce 0.
+ (table::print): If center option not given, then imply center
+ option if SAVED_CENTER_REG > 0.
+
+Mon Sep 17 09:19:19 1990 James Clark (jjc at jclark)
+
+ * ps/devps/Makefile: Remove T from FONTS. Remove TSymbol.ps and
+ Troff.ps from DOWNLOAD.
+
+ * troff/Makefile: Change comment in DEFINES to avoid confusing
+ System V make.
+
+ * ps/ps.c (ps_printer::do_exec): Allow newlines within PostScript
+ code. Don't try to catch errors with stopped.
+ (check_line_lengths): New function.
+ * ps/devps/prologue (EXEC): Deleted.
+ (EBEGIN, EEND): New procedures.
+
+Sun Sep 16 14:51:15 1990 James Clark (jjc at jclark)
+
+ * troff/input.c: Include request.h before node.h.
+ * troff/node.c: Likewise.
+ * troff/env.c: Likewise.
+ * troff/div.c: Likewise.
+ * troff/node.h (class special_node): Store argument as a macro
+ rather than a char *.
+ * troff/node.c (special_node::special_node, special_node::copy):
+ Grok this.
+ (special_node::~special_node): Deleted.
+ (special_node::tprint): Deleted.
+ (special_node::tprint_start, special_node::tprint_end,
+ special_node::tprint_char): New functions.
+ (troff_output_file::special): Deleted.
+ (troff_output_file::start_special, troff_output_file::end_special,
+ troff_output_file::special_char): New functions.
+ * troff/input.c (special_node::tprint): New function.
+ (do_special): Use macro not char *.
+ (do_transparent_macro): Deleted.
+ (token::next): Don't call do_transparent_macro.
+
+ * troff/input.c (token::next): Add 'Y' case.
+ (do_transparent_macro): New function.
+ * troff/node.c (troff_output_file::special): Handle newlines with
+ argument using new continuation convention.
+ * driver/input.c (get_string): Cope with continuation convention.
+ (do_file): Don't call skip_line after calling get_string(1).
+ * ps/ps.c (ps_printer::special, ps_printer::do_import,
+ ps_printer::do_def, ps_printer::do_exec): Cope with newlines in
+ arg.
+ * xditview/libXdvi/parse.c (ParseInput): Ignore lines starting
+ with +.
+
+Sat Sep 15 19:00:10 1990 James Clark (jjc at jclark)
+
+ * troff/input.c (asciify): By default, illegal input characters
+ should return empty string.
+
+ * troff/input.c (copy_file): Handle first page transition like title.
+ (token::next, process_input_stack): Grok COPY_FILE_REQUEST.
+
+ * troff/input.c (token::next): Improve error message for EOF after
+ escape character.
+ (input_char_description): New function.
+ (get_char_for_escape_name): Use input_char_description.
+ (token::next): Warn about unrecognized escape sequences.
+ (warning_table): Add WARN_ESCAPE.
+ * troff/groff.h: Declare WARN_ESCAPE. Change WARN_TOTAL
+ accordingly.
+
+ * troff/token.h: Remove declaration of process_input_stack.
+
+ * troff/input.c: Remove declaration of init_hyphen_requests.
+ * troff/request.h: Correct spelling in declaration of same.
+
+ * troff/input.c (token::next): Check whether escape_char is 0.
+
+Fri Sep 14 12:09:25 1990 James Clark (jjc at jclark)
+
+ * groff.c (main, usage, help): Implement -P and -L options.
+ * groff.sh: Likewise.
+
+ * troff/input.c (token::next): Use some gotos to avoid code
+ duplication.
+
+ * troff/input.c (get_long_name, get_name, read_long_ecsape_name):
+ Avoid calling symbol::symbol if name empty.
+
+Thu Sep 13 06:21:45 1990 James Clark (jjc at jclark)
+
+ * troff/input.c (init_input_requests): Make \n(.x return the major
+ version number and \n(.y return the minor version number.
+ * troff/Makefile: Construct file majorminor.c defining
+ major_version and minor_version automatically from ../VERSION.
+
+ * troff/node.c (class glyph_node): Make operator new and operator
+ delete public.
+ (class ligature_node): Similarily.
+
+ * troff/input.c (operator==(const macro &, const macro &)): New
+ function.
+ (non_interpreted_node::same): Use this.
+ (string_iterator::string_iterator): Make macro& argument const.
+
+ * troff/input.c (input_iterator::get): New function. Don't make
+ asciify_macro or class non_interpreted_node friends of class
+ input_iterator.
+ (non_interpreted_node::interpret): Use input_iterator::get.
+ (asciify_macro): Likewise.
+
+ * troff/input.c (~token_node, ~string_iterator, ~arg_list,
+ ~non_interpreted_node): Deleted.
+ * troff/node.c: (~suppress_output_file, ~ascii_output_file):
+ Deleted.
+
+ * troff/symbol.h: Make all symbol member functions const.
+
+ * lib/strtol.c: New file.
+ * lib/Makefile: Add strtol.c.
+ * Makefile: Define STRTOL as strtol.o to include strtol in
+ libgroff.a.
+
+Wed Sep 12 10:00:49 1990 James Clark (jjc at jclark)
+
+ * pic/troff.c (troff_output::simple_circle): Divide by scale.
+
+Tue Sep 11 14:17:16 1990 James Clark (jjc at jclark)
+
+ * troff/input.c (do_special): Use input_level.
+
+ * troff/token.h (TOKEN_BACKSPACE): New token.
+ (token::backspace): New function.
+ * troff/input.c (token::description, token::next, token::process):
+ Grok TOKEN_BACKSPACE.
+ (do_special): Turn TOKEN_BACKSPACE back into \b.
+
+ * troff/token.h (token::leader): New function.
+ * troff/input.c (do_special): Turn TOKEN_LEADER back into \001.
+
+ * troff/input.c (do_special): Turn TOKEN_TAB back into \t.
+
+ * troff/input.c (do_special): Use token::description in error
+ message.
+
+Mon Sep 10 11:06:27 1990 James Clark (jjc at jclark)
+
+ * troff/input.c (decode_args): Combine quoted and
+ quote_input_level variables. Make it a for (;;) loop.
+
+ * troff/input.c (get_char_for_escape_name): Check for \001 and \b.
+
+ * troff/input.c (read_long_escape_name): The test for whether to
+ expand buffer was off by 1.
+ (read_string): Similarily.
+
+Fri Sep 7 11:45:50 1990 James Clark (jjc at jclark)
+
+ * troff/input.c: Use `const int' rather than `static const int'.
+
+ * troff/div.h (diversion::copy_file): Declare as pure virtual.
+ (macro_diversion::copy_file): New function.
+ * troff/node.h: New class diverted_copy_file_node.
+ * troff/node.c: Implement it.
+ * troff/input.c (copy_file): Use diversion::copy_file. Handle
+ first page transition by pushing a diverted_copy_file_node.
+ * troff/input.c (token::next, process_input_stack): Don't handle
+ COPY_FILE_REQUEST.
+
+Thu Sep 6 13:29:10 1990 James Clark (jjc at jclark)
+
+ * ps/ps.c (flush_sbuf): Remember to add sbuf_kern when checking
+ whether space widths need adjusting.
+
+ * troff/charinfo.h: Generalize translated_to_space to
+ special_translation so as to allow translation to \&.
+ * troff/input.c (translate): Allow translation to \&.
+ (charinfo::*): Corresponding changes.
+ * troff/node.c (make_node, node::add_char): Corresponding changes.
+ * troff/node.h (dummy_node::dummy_node): Allow optional first
+ argument.
+
+ * lib/lib.h: Make codes 0200 to 0237 illegal input characters.
+ * troff/token.h: Remove TOKEN_TITLE. Remove token::title. Add
+ TOKEN_REQUEST.
+ * troff/input.c (token::next): Turn a TITLE_REQUEST into a
+ TOKEN_REQUEST with an argument of TITLE_REQUEST.
+ (token::process): Grok that.
+ * troff/input.c (copy_file): Handle first page transition like
+ title by pushing a COPY_FILE_REQUEST cookie.
+ (token::next, process_input_stack): Grok that.
+ * troff/node.h (output_file::copy_file): Add x and y arguments.
+ Make it non-pure.
+ * troff/div.c (top_level_diversion::copy_file): Supply them.
+ * troff/node.c (troff_output_file::copy_file): Add x and y
+ arguments; moveto specified position. Invalidate font_position
+ array after copying file.
+ (output_file::copy_file): New function.
+ (suppressed_output_file::copy_file, ascii_output::copy_file):
+ Removed.
+ * troff/input.c (transparent_file): New function.
+ (init_input_requests): Bind to "trf".
+ (token::next): Handle TRANSPARENT_FILE_REQUEST cookie.
+ (process_input_stack): Likewise.
+
+ * troff/Makefile: Add ../lib/lib.h to GROFF_H.
+
+ * troff/node.c (init_node_requests): New number registers .kern
+ pointing to global_kern_mode, and .lg pointing to
+ global_ligature_mode.
+
+ * troff/node.c (ligature): Don't change it if we get a bad
+ integer.
+
+ * troff/input.c (do_define_string): Don't strip tabs.
+
+ * troff/input.c (asciify_macro): Make the string_iterator auto.
+
+ * troff/node.c (init_font_requests): Rename to...
+ (init_node_requests):
+ * troff/node.h: Change declaration.
+ * troff/input.c (main): Change call.
+
+ * troff/input.c (node::reread, diverted_space_node::reread): New
+ methods.
+ (process_input_stack): Call reread rather than
+ get_diverted_space_node.
+ * troff/node.c (node::get_diverted_space_node,
+ diverted_space_node::get_diverted_space_node): Removed.
+ * troff/node.h: Declare reread methods instead of
+ get_diverted_space_node methods. Make `n' member private.
+ * troff/input.c: (token::diverted_space): Removed.
+ * troff/token.h: Removed declaration.
+
+
+Tue Sep 4 00:48:04 1990 James Clark (jjc at jclark)
+
+ * eqn/script.c (script_box::compute_metrics): Don't let
+ SUP_RAISE_FORMAT become negative.
+
+ * tbl/table.c (table::do_row): Entries that don't end in the
+ this row shouldn't make the row non-blank.
+
+ * tbl/table.c (table::make_columns_equal): Only set the width of
+ columns which are marked as equal.
+
+ * tbl/main.c (process_data): Before issuing excess data error,
+ if last character was a newline unget it; then get it again after
+ the error. Also include the contents of the entry in the message.
+
+ * groff.c: New file.
+ * Makefile: Build groff from groff.c. Make it possible to use
+ either groff.sh or groff.c as groff.
+ * Makefile.bd: Similarily.
+
+Mon Sep 3 09:39:49 1990 James Clark (jjc at jclark)
+
+ * groff.sh: Don't delay expansion of $@ in assignment to files.
+ Remove occurrences of \".
+
+Sun Sep 2 09:56:59 1990 James Clark (jjc at jclark)
+
+ * all Makefiles: Simplify and rearrange.
+
+ * Makefile: Handle fmod like malloc.
+ * lib/Makefile: Similarily.
+ * lib/fmod.c: Remove #ifdef NEED_FMOD.
+
+ * Makefile: Rename OPTIMISE to OPTIMIZE.
+
+ * groff.sh: Remove assignment to PATH.
+ * Makefile: Remove SHPATH variable.
+ * Makefile.bd: Similarily.
+
+ * groff.sh: Add -V option to print the pipeline instead of
+ executing it.
+
+Fri Aug 31 00:56:46 1990 James Clark (jjc at jclark)
+
+ * lib/font.c: Split off file searching into ...
+ * lib/fontfile.c: New file.
+
+ * lib/strerror.c (strerror): Use `Error %d' for unknown errors.
+
+Thu Aug 30 13:13:55 1990 James Clark (jjc at jclark)
+
+ * tbl/table.c (table::do_hspan): Delete assertion that e != 0.
+ Also change misleading comment.
+ (table::do_vspan): Change similarily misleading comment.
+ * tbl/main.c (process_data): A format row with an explicit `s'
+ uses up a data line, even if all the other columns are `_' or `='.
+
+ * troff/input.c (token::description): Fix description of
+ TOKEN_DUMMY and TOKEN_EMPTY.
+
+Wed Aug 29 04:12:08 1990 James Clark (jjc at jclark)
+
+ * groff.sh: Fix description of -Z in help message.
+
+Tue Aug 28 07:28:33 1990 James Clark (jjc at jclark)
+
+ * pic/object.c (object_spec::make_object): Allow negative and zero
+ line thicknesses.
+ * pic/pic.y: Give linethick default value of -1.0.
+ * pic/troff.c (troff_output::troff_output): Initialize
+ last_line_thickness to BAD_THICKNESS.
+ (troff_output::finish_picture): Set thickness to BAD_THICKNESS.
+ (troff_output::line_thickness): Canonicalize negative thicknesses
+ to RELATIVE_THICKNESS.
+ * pic/tex.c (tex_output::set_pen_size): Silently map negative line
+ thicknesses to DEFAULT_PEN_SIZE. Canonicalize negative pen sizes
+ to -1.0.
+ (tex_output::start_picture): Set pen_size to -2.0.
+
+ * ps/ps.c (ps_printer::set_line_thickness): If line_thickness is
+ 0, then use 0 linewidth.
+ (ps_printer::ps_printer): Initialize line_thickness to -1.
+
+ * pic/troff.c (troff_output::simple_ellipse): Divide by scale.
+
+ * ps/devps/symbolchars: Remove `or'.
+ * ps/tmac.ps: Implement \(or with .char.
+
+ * ps/devps/symbolchars: Move most characters into textmap.
+ * ps/devps/textmap: Add names for troff bracket characters. Remove
+ ul, ru, br, bv.
+
+ * ps/devps/TSymbol.ps: Removed.
+ * ps/devps/FontMakefile: Make S from Symbol not TSymbol.
+ * ps/tmac.ps: Do with .char what TSymbol did.
+ * ps/devps/download: Remove TSymbol.
+
+ * ps/devps/T: Removed.
+ * ps/devps/Troff.ps: Removed.
+ * ps/devps/Troff.afm: Removed.
+ * ps/tmac.ps: Implement \(ru, \(ul, and \(br with .char.
+ * ps/devps/download: Remove Troff.
+ * ps/devps/FontMakefile: Remove T target.
+ * ps/devps/DESC-A4: Remove T from font list.
+ * ps/devps/DESC-letter: Likewise.
+
+ * troff/input.c (macro_to_node): Rename to ...
+ (charinfo_to_node): Don't pass mac argument. Temporarily remove the
+ character's definition while processing it.
+ * troff/node.c (node::add_char, make_node): Change calls to
+ macro_to_node accordingly.
+
+ * troff/input.c (token::next): Translate \_ to \(ul.
+
+ * tty/devascii/R.proto: Add `|'.
+ * tty/devlatin1/R.proto: Likewise.
+
+Mon Aug 27 11:25:41 1990 James Clark (jjc at jclark)
+
+ * man: Put the version number in all the man pages.
+
+Sun Aug 26 11:40:05 1990 James Clark (jjc at jclark)
+
+ * Makefile.bd: New file.
+ * README.bd: New file.
+
+ * VERSION: New file.
+ * lib/version.c: Removed.
+ * lib/Makefile: Create version.c from ../VERSION. Remove version.c
+ in clean target.
+
+ * troff/input.c (main): Get hyphen_file from GROFF_HYPHEN
+ environment variable.
+
+ * all Makefiles: Split install target into install.bin for
+ binaries, and install.nobin for everything else.
+ * Makefile: Add bindist target.
+
+ * man/afmtodit.man: New file.
+ * man/Makefile: Add afmtodit.n to MAN1PAGES.
+ * ps/devps/Makefile: Add textmap to DEVICEFILES. Install afmtodit
+ in BINDIR.
+ * ps/Makefile: Pass BINDIR to make install in devps.
+
+ * ps/ps.c (ps_printer::set_char): Do nothing if the character is
+ the space character.
+
+ * ps/devps/FontMakefile: Rename symbol.afm to tsymbol.afm.
+
+Sat Aug 25 15:39:03 1990 James Clark (jjc at jclark)
+
+ * ps/ps.c: Redo font downloading.
+ * ps/devps/download: New file.
+ * ps/devps/Makefile: Add download to DEVICEFILES.
+ * ps/devps/afmtodit: Remove -d option.
+ * ps/devps/FontMakefile: Don't use -d option with afmtodit.
+ * ps/devps/symbosl.ps: Add %%DocumentFonts comment.
+ * ps/devps/zapfdr.ps: Likewise.
+ * ps/devps/TSymbol.ps: Likewise.
+
+Fri Aug 24 20:10:30 1990 James Clark (jjc at jclark)
+
+ * groff.sh: Initialize dev to ${GROFF_TYPESETTER:-@DEVICE@}.
+
+Thu Aug 23 10:03:47 1990 James Clark (jjc at yquem)
+
+ * ps/ps.c (ps_output::include_file): If BROKEN_SPOOLER is defined,
+ then strip the first line if it starts with %.
+ * Makefile: Add a comment about this.
+
+ * man/tfmtodit.man: New file.
+ * man/Makefile: Add tfmtodit.n to MAN1PAGES.
+ * dvi/Makefile: Install tfmtodit in BINDIR.
+
+ * dvi/tfmtodit.c (usage): Mention -v option.
+
+Wed Aug 22 09:56:36 1990 James Clark (jjc at yquem)
+
+ * troff/node.c (troff_output_file::end_of_line): Call do_motion.
+ * troff/node.c (troff_output_file::transparent_char): Don't call
+ flush_tbuf.
+
+ * eqn: Add check_tabs method to most box classes.
+ * eqn/box.c (box::top_level): Call check_tabs.
+
+ * eqn/script.c (script_box::output): Use \Z.
+ * eqn/limit.c (limit_box::output): Use \Z.
+
+ * eqn/box.c (box::top_level): Use itoa.
+
+Tue Aug 21 09:29:28 1990 James Clark (jjc at yquem)
+
+ * dvi/tmac.dvi: Add font translations for CR, C, TT.
+ * dvi/devdvi/Makefile: Don't make links to CW.
+
+ * ps/tmac.ps: Add font translations for C, CW, CO, CX, CD, H, HO,
+ HX, HD.
+ * xditview/tmac.X: Likewise.
+
+ * troff/node.c: Add font translation feature.
+ (get_font_translation): New function.
+ (symbol_fontno): Translate the font name.
+ (mount_font_no_translate): Rename to mount_font to this.
+ (mount_font): New function.
+ (font_family::make_definite): Call mount_font_no_translate instead
+ of mount_font.
+ (mount_style): Translate the font name.
+ (font_translate): New function.
+ (init_font_requests): Bind "ftr" to font_translate.
+
+ * ps/devps/prologue (SN): New procedure that rounds a position to
+ the nearest (pixel + (.25,.25)).
+ (DL): Use SN to round endpoints.
+
+ * lib/version.c: Changed version to 0.5.
+
+Sat Aug 18 04:43:21 1990 James Clark (jjc at yquem)
+
+ * Makefile: Move definition of PAGE to the very beginning, so that
+ people are less likely to miss it.
+
+Fri Aug 17 02:15:11 1990 James Clark (jjc at yquem)
+
+ * man/Makefile: Don't need to sed out @UPCASE_PROG_PREFIX@.
+
+ * troff/env.c (environment::choose_breakpoint): Make `can't find
+ breakpoint' error a warning of type WARN_BREAK. Change message to
+ `can't break line'.
+ * troff/groff.h: Declare WARN_BREAK with code 4; change WARN_INPUT to
+ code 040000.
+ * troff/input.c: Add WARN_BREAK to warning_table. Include
+ WARN_BREAK in DEFAULT_WARNING_MASK.
+
+ * tty/tmac.tty: Add definition of \(+-.
+
+ * groff.sh: Remove `--' option to set command.
+
+ * dvi/devdvi/texsy.map: Remove duplicate md entry.
+
+ * ps/devps/eqnchar: Better definition of cdot using md.
+ * dvi/devdvi/eqnchar: Likewise.
+ * xditview/devX100/eqnchar: Likewise.
+ * xditview/devX75/eqnchar: Likewise.
+ * eqn/lex.c: Add definition of cdot.
+
+Thu Aug 16 09:33:57 1990 James Clark (jjc at yquem)
+
+ * troff/input.c (get_optional_char): New function.
+ * troff/input.c (set_page_character): Use get_optional_char(),
+ rather than has_arg() and tok.get_char(1).
+ * troff/env.c (tab_character, leader_character, hyphen_char,
+ field_characters): Likewise.
+ (margin_character): Likewise. Also always delete the
+ margin_character_node.
+
+ * troff/input.c (token::get_char): Use token::description.
+
+ * troff/input.c (has_arg): Don't skip over tab and \}.
+ * troff/number.c (start_number): Give a warning if the number
+ starts with \} (WARN_RIGHT_BRACE) or tab (WARN_TAB).
+
+Wed Aug 15 10:04:37 1990 James Clark (jjc at yquem)
+
+ * troff/input.c (empty_name_warning, non_empty_name_warning): New
+ functions.
+ (get_name, get_long_name): Use these. Rename `warn' argument to
+ `required'.
+
+ * troff/node.c (get_fontno): Test that the symbol is not null.
+
+ * troff/input.c (token::description): New function.
+ * troff/number.c (parse_term): Use token::description in `numeric
+ expression expected' message.
+ * troff/groff.h: Add WARN_MISSING.
+ * troff/number.c (start_number): New function.
+ * troff/number.c (get_vunits, get_hunits, get_number, get_integer,
+ get_incr_number): Use start_number().
+ * troff/input.c (DEFAULT_WARNING_MASK): Enable WARN_NUMBER by
+ default.
+ * troff/input.c (get_name, get_long_name): Use WARN_MISSING.
+ * troff/reg.c (alter_format): Use WARN_MISSING. Also use
+ token::descripion.
+ * troff/input.c (token::get_char): Use WARN_MISSING.
+ * troff/input.c (token::delimiter): Use token::description.
+ * troff/env.c (environment_switch): Back out Aug 3 change.
+ * troff/input.c (has_arg): Skip over \}s and tabs but give a
+ warning.
+ * troff/token.h (token::tab): New function.
+ * troff/node.c (get_fontno): Use tok.skip() rather than has_arg().
+ * troff/reg.c (alter_format): Likewise.
+ * troff/node.c (bold_font): Use has_arg() rather than tok.skip().
+
+Tue Aug 14 10:11:21 1990 James Clark (jjc at yquem)
+
+ * troff (most files): Redo warnings. Divide warnings into various
+ categories; warning() has an additional first argument indicating
+ the category it falls into.
+ * troff/input.c (main): -w now takes an argument. New option -W.
+ (enable_warning, disable_warning): New functions.
+
+ * ps/devps/afmtodit: Add -a option to lie about the italic angle.
+ * ps/devps/FontMakefile: Pretend TI has an angle of 7.
+
+Mon Aug 13 10:11:16 1990 James Clark (jjc at yquem)
+
+ * ps/devps/eqnchar: Better definitions of dotdot, vec, dyad, inf.
+ * xditview/devX100/eqnchar: Likewise. Remove definition of dot.
+ * xditview/devX75/eqnchar: Likewise.
+ * dvi/devdvi/eqnchar: Better definitions of vec, dyad, dotdot.
+
+ * eqn/other.c: When bar or over applies to a single character
+ don't produce an overline_box or an underline_box. Instead produce
+ an accent_box or an underaccent_box, with the accent a line
+ whose width is accent_width. New classes underaccent_box,
+ overline_char_box and underline_char_box.
+ * eqn/box.h: Move overline_box, underline_box, accent_box class
+ declarations into eqn/other.c. Add declarations of
+ make_underline_box, make_overline_box, make_accent_box.
+ * eqn/eqn.y: Call make_overline_box, make_underline_box
+ make_accent_box instead of constructors.
+ * eqn/pbox.h, eqn/box.c: Add accent_width parameter.
+
+ * eqn/other.c: Add accent_box::~accent_box.
+ * eqn/box.h: Declare it.
+
+ * groff.sh: With -Tps, use eqn -D.
+
+ * eqn/other.c (overline_box::output): Use \Z. If draw_flag use \D
+ rather than \l.
+ (underline_box::output): Similarily.
+ (accent_box::output): Use \Z.
+
+ * xditview/tmac.X: Add definitions of ~ and ^ (so that they are a
+ bit smaller.)
+
+Sun Aug 12 09:41:15 1990 James Clark (jjc at yquem)
+
+ * troff/div.c (top_level_diversion::transparent_output(unsigned
+ char)): Use asciify.
+ * troff/input.c (asciify): Don't make it static.
+ * troff/token.h (asciify): Declare it.
+
+ * troff/input.c (get_name, get_long_name, token::get_char,
+ token::delimiter): Add an extra default argument which says
+ whether a warning should be printed.
+ * troff: Pass a non-zero argument to one of these rather than
+ printing a warning directly.
+
+Sat Aug 11 09:02:21 1990 James Clark (jjc at yquem)
+
+ * troff: Consistently use symbol::is_null.
+
+ * troff/dictionary.h: Move some inline functions into
+ dictionary.c.
+
+ * troff/request.h: Move inline functions into input.c.
+ (request_or_macro::invoke): Make it pure.
+
+ * troff/input.c, troff/reg.h: New class `constant_int_reg'.
+ * troff/input.c (init_input_requests): Use class constant_int_reg.
+ (class compatible_reg): Deleted.
+ * troff/div.c (init_div_requests): Use class constant_int_reg.
+ (class last_post_line_extra_space_reg): Deleted.
+
+ * troff/env.c (tab_character): Don't change the tab character if
+ we get an invalid argument.
+ (hyphen_char): Similarily.
+
+ * troff/reg.c (alter_format): Check that nm is not null.
+
+ * Makefile, groff.sh: Make it possible to customize the commands
+ used for printing PostScript and dvi files. Also make it possible
+ to customize the path used by groff.sh.
+
+ * eqn/eqn.y: Make `left' right associative.
+
+Fri Aug 10 18:20:39 1990 James Clark (jjc at yquem)
+
+ * pic/pic.h: Added definition of M_SQRT2 for those systems that
+ don't have it.
+
+ * pic/pic.h: Removed definition of INT_MAX.
+
+ * troff/node.c (italic_corrected_node::vertical_extent): Omit
+ `return'.
+
+ * troff/input.c (token::next): Handle \R like \n.
+
+Tue Aug 7 09:46:33 1990 James Clark (jjc at yquem)
+
+ * ps/tmac.pc (PSPIC): Simplify.
+
+ * troff/env.c (tab_stops::to_string):
+ * pic/pic.y (object_type_name):
+ * pic/troff.c (simple_output::line):
+ * pic/tex.c (tex_output::spline):
+ * pic/object.c (object_spec::make_object):
+ * tbl/main.c (process_data): Add cases to switch statements to
+ avoid cfront warnings. (Some of these are spurious, since the
+ switch already has a default case.)
+
+ * ps/tmac.ps (PSPIC): Reformatted. Prefix all local names with
+ `ps-'. Don't test systat; instead check number of arguments to
+ ps-bb.
+
+Mon Aug 6 00:13:07 1990 James Clark (jjc at yquem)
+
+ * macros/tmac.e: Do not decrease the page offset by 0.5i.
+
+ * ps/ps.c (ps_printer::ps_printer): Use mktemp instead of tempnam.
+ Unlink the file as soon as we have opened it, so that we don't
+ have to bother with signal handlers.
+ (handler): Deleted.
+ (fatal_error_exit): Deleted.
+ (main): Don't call signal.
+
+ * dvi/tfmtodit.c: Add -k option so that kerns with the skewchar
+ can be ignored.
+ * dvi/devdvi/Makefile: Use the -k option with S and MI.
+
+ * pic/pic.y: If there is a label, or an nth construction before
+ the first `.' in the argument to `with', ignore it and generate a
+ warning.
+ * pic/lex.c (lex_warning): New function.
+
+ * tbl/table.c (table::init_output): In section keep and release
+ macro, use 0 indent when diverting and the correct indent when
+ rereading.
+
+ * troff/input.c (interpolate_number_format): Do not interpolate
+ anything if the number register is not defined.
+
+ * tbl/main.c (process_data): Don't add entry when col >= ncolumns.
+
+Sat Aug 4 08:12:05 1990 James Clark (jjc at yquem)
+
+ * ps/devps/prologue (PICTURE): Set components of graphics state to
+ their default values.
+
+ * ps/devps/text.enc: Add trademark
+ * ps/devps/textmap: Add names for club, spade, heart, diamond,
+ carriagereturn, suchthat. Use Upsilon1 rather than Upsilon.
+ * ps/devps/symbolchars: Add names for summation and product.
+
+ * dvi/devdvi/texsy.map: Add names for club, spade, heart, diamond,
+ suchthat. Add pp. Add upper-case letters.
+
+ * xditview/libXdvi/DviChar.c: Add names for club, spade, heart,
+ diamond, carriagereturn, suchthat. Use Upsilon1 rather than
+ Upsilon.
+
+ * dvi/devdvi/texsy.map: Rename lA (left angle bracket) to la, and
+ rA (right angle bracket) to ra. Introduce names for double-headed
+ arrows and double-barred arrows: <>, va, lA, rA, hA, uA, dA, vA.
+ * ps/devps/textmap: Likewise for ps device.
+ * xditview/libXdvi/DviChar.c: Likewise for X100 and X75 devices.
+ * tty/devascii/R.proto: Rename lA to la and rA to ra.
+ * tty/devascii/R.proto: Likewise.
+ * tty/tmac.tty: Provide definitions for \(<>, \(lA, \(rA, \(hA,
+ \(uA, \(dA.
+ * eqn/delim.c: In delim_table, rename \(lA to \(la and \(rA to \(ra.
+
+ * xditview/tmac.X: Add definitions for \(fi \(fl \(ff \(Fi \(Fl.
+
+ * eqn/lex.c: Added definitions of `approx', `grad' and `del' to
+ def_table.
+
+Fri Aug 3 09:59:27 1990 James Clark (jjc at yquem)
+
+ * troff/div.c (when_request): Use symbol::is_null rather than
+ has_arg to determine whether we have an argument.
+ (change_trap): Remove the trap if we get an invalid number. Give
+ an error if we don't get at least the macro name.
+ (diversion_trap): Remove trap if we get an invalid name or number.
+
+ * troff/env.c (environment_switch): Pop if we get an invalid
+ symbol or numeric expression.
+
+ * troff/input.c (do_define_macro): If EOF is encoutered while
+ defining the macro, do tok.next() before returning.
+
+ * troff/token.h (has_arg): Move definition from here, to ...
+ * troff/input.c (has_arg): ... here
+
+ * troff/env.c (space_size): Do nothing if we get an invalid argument.
+ * troff/input.c (shift): Likewise.
+
+ * pic/lex.c (get_token_after_dot): Accept `.center' as a synonym
+ for `.c'.
+
+ * pic/troff.c (troff_output::start_picture): Comment out calls to
+ `..'.
+
+ * eqn/main.c (do_file): Subtract 1 from current_lineno if
+ interpret_lf_args succeeds.
+
+ * eqn/main.c (do_file): Don't recognize delimiter if preceded by
+ \\. This avoids problems with \$N.
+
+ * groff.sh: Pass -C to preprocessors.
+
+ * lib/lf.c (interpret_lf_args): Be more flexible.
+
+ * tbl/main.c (main): Add -C option.
+ (table_input::get): Do not recognize TE if followed by character
+ other than a space or newline unless -C option given.
+ (process_input_file): Likewise for lf, TS.
+ (process_data): Likewise for lf in text blocks.
+
+ * eqn/main.c (main): Add -C option.
+ (do_file): Don't recognize EQ, EN or lf if followed by character
+ other than space or newline unless -C option given.
+ * eqn/lex.c (file_input::read_line): Similarily.
+ * eqn/eqn.h: Declare compatible_flag.
+
+ * etc/soelim.c (main): Add -C option.
+ (interpret_lf_args): Use version in libgroff.
+ (do_file):
+
+ * pic/main.c (main): Add -C option, which sets compatible_flag.
+ (top_input::get), (top_input::peek): If -C option not given,
+ do not recognize .PS/.PE/.PF/.lf if followed by a character
+ other than space or newline.
+ * pic/lex.c (file_input::read_line): Similarily.
+ * pic/pic.h: Add declaration of compatible_flag.
+
+Thu Aug 2 11:11:27 1990 James Clark (jjc at yquem)
+
+ * ps/tmac.ps (PSPIC): Avoid use of `echo -n'.
+
+ * troff/node.c, troff/node.h: Add `asciify' methods to classes
+ derived from node. New class space_char_hmotion_node.
+ * troff/input.c (asciify_macro): New function.
+ * troff/input.c (init_input_requests): New request `asciify' bound
+ to asciify_macro.
+ * macros/mm.diff: New file.
+ * Makefile: In install.mm target use `patch' to apply
+ macros/mm.diff.
+
+ * troff/input.c (macro::print_size): Just print the size in bytes.
+
+ * troff/div.c (return_request): Correct the argument
+ interpretation.
+
+Wed Aug 1 12:38:36 1990 James Clark (jjc at yquem)
+
+ * troff/node.h (class composite_node): Add sz member.
+ * troff/node.c (composite_node::size): Return sz.
+ * troff/input.c (macro_to_node): Use the initial size in the
+ environment as the size of the composite_node.
+
+ * troff/node.c (node::zero_width_tprint): Provide a reasonable
+ default.
+
+Tue Jul 31 10:07:10 1990 James Clark (jjc at yquem)
+
+ * troff/div.c (change_trap): If we get a bad number expression,
+ do nothing.
+
+Mon Jul 30 10:30:49 1990 James Clark (jjc at yquem)
+
+ * lib/matherr.c (matherr): Define this only if math.h defines
+ TLOSS.
+
+Sun Jul 29 10:34:27 1990 James Clark (jjc at yquem)
+
+ * troff/div.c (macro_diversion::distance_to_next_trap): If there
+ no diversion trap return vunits(INT_MAX - vresolution).
+
+Sat Jul 28 14:28:14 1990 James Clark (jjc at yquem)
+
+ * troff/input.c (do_zero_width): New implementation that doesn't
+ use a temporary environment. Use instead:
+ (token::add_to_node_list): New function.
+ * troff/env.c (environment::get_prev_char_height),
+ (environment::get_prev_char_height),
+ (environment::get_prev_char_skew): New functions.
+ (environment::get_prev_char): New function.
+ (environment::get_prev_char_width): Change to use get_prev_char.
+ (init_env_request): Implement new registers .cht, .cdp, .csk.
+ * eqn/sqrt.c (sqrt_box::output): Don't rely upon the argument to
+ \Z being processed in a separate environment.
+
+Fri Jul 27 10:21:25 1990 James Clark (jjc at yquem)
+
+ * tbl/table.c: Removed TABLE_BOTTOM_REG.
+
+ * tbl/table.c (table::init_output): In the section release macro,
+ give a warning message if the section won't fit on one page.
+
+ * tbl/table.c (table::do_top): Emit table keep only if table is
+ boxed.
+ (table::do_bottom): Likewise for table release.
+ (table::table), (table::add_vertical_rule): Remove reference to
+ keep member.
+ * tbl/table.h: Remove keep member.
+
+ * tbl/table.c: New register SUPPRESS_BOTTOM_REG. In
+ SECTION_RELEASE_MACRO, if there's not enough space before the next
+ trap to output the diversion, call T# ourselves, set
+ SUPPRESS_BOTTOM_REG to 1, spring the trap, then set
+ SUPPRESS_BOTTOM_REG back to 0. In T#, do nothing if
+ SUPPRESS_BOTTOM_REG is non-zero. In T#, always mark the current
+ vertical position and return to it before turning traps on again.
+
+Thu Jul 26 02:54:32 1990 James Clark (jjc at yquem)
+
+ * troff/node.c, troff/node.h: In classes derived from node,
+ replace prev_char_width method by last_char_node method.
+ * troff/env.c (environment::get_prev_char_width): Use
+ node::last_char_node rather than node::get_prev_char_width.
+
+ * Makefile: Added comment about -fno-inline on 68030-based
+ Apollos.
+
+ * troff/reg.c (number_format_to_ascii), eqn/delim.c (DELIM_TABLE_SIZE),
+ tty/tty.c (tty_font::load_tty_font), dvi/tfmtodit.c (main): Cast
+ expressions using sizeof to int.
+ * dvi/dvi.c (dvi_font::handle_x_command): Avoid long->int warnings.
+
+ * macros/tmac.e (TS): Don't move @f back past the current
+ position.
+
+Wed Jul 25 09:11:08 1990 James Clark (jjc at yquem)
+
+ * ps/ps.c (main): Buffer stderr.
+ * dvi/dvi.c (main): Likewise.
+ * tty/tty.c (main): Likewise.
+
+ * ps/ps.c (ps_printer::do_import): Improve error handling.
+
+ * troff/input.c (abort_request): Use asciify.
+
+ * driver/printer.h (printer::draw), driver/printer.c (printer::draw),
+ ps/ps.c (ps_printer::draw), dvi/dvi.c (dvi_printer::draw): Make
+ type of first argument int rather than char. This works around a
+ bug on the 68030 based Apollo using g++ 1.37.1.
+
+ * tbl/table.h (class table): Add `keep' member.
+ * tbl/table.c (table::table): Initialize `keep'.
+ (table::add_vertical_rule): Set `keep' to 1.
+ (table::do_top): Only emit table keep macro is `keep' is non-zero.
+ (table::do_bottom): Likewise for table release macro.
+ (table::do_row): Emit section keep macro even if the row is 0.
+
+Tue Jul 24 08:35:07 1990 James Clark (jjc at yquem)
+
+ * macros/tmac.e (@C): Preserve the font family across the change
+ in environments.
+
+Mon Jul 23 10:15:23 1990 James Clark (jjc at yquem)
+
+ * lib/font.c: Initialize font::hor and font::vert to 1.
+ (font::load_desc): Check the values of font::hor and font::vert.
+
+ * lib/lib.h: Added definition of INT_DIGITS. Fix it so that it can
+ be included in a C compilation.
+ (iftoa): Use INT_DIGITS. Include lib.h.
+ (itoa): Likewise.
+ (as_string): Likewise.
+ * tbl/table.c: Removed definition of INT_DIGITS.
+ * eqn/box.c (box::top_level): Use INT_DIGITS + 1 instead of 12.
+ * troff/input.c (input_input_requests): Likewise.
+ * ps/ps.c (make_encoding_name): Likewise.
+ (ps_printer::set_style): Likewise.
+ (ps_output::put_number): Use 1 + INT_DIGITS + 1 instead of 12.
+
+ * tty/devascii/R.proto: Map fm onto '.
+ * tty/devlatin1/R.proto: Likewise.
+
+Sat Jul 21 12:45:07 1990 James Clark (jjc at yquem)
+
+ * tbl/table.c: Use ' instead of DELIMITER_CHAR in places where the
+ argument to \w is at a different input level.
+
+ * tbl/table.c (table::init_output): Define a new macro
+ REPEATED_VPT_MACRO, like vpt but if in a diversion also
+ transparently outputs itself.
+ (table::define_bottom_macro): Use REPEATED_VPT_MACRO instead of
+ vpt.
+ (table::do_row): Likewise.
+
+ * tbl/table.c (vertical_rule::print): Prefix the .sp -1 line with
+ TRANSPARENT_STRING_NAME.
+
+ * tbl/table.c (table::init_output): In the table release macro
+ print an error message and don't produce any output if after
+ issuing the need request the table still will not fit. Also
+ remove the diversion after bringing it back.
+
+ * tbl/table.c (table::init_output): Define a new macro
+ REPEATED_MARK_MACRO, like mk but if in a diversion also
+ transparently outputs itself.
+ (table::do_row): Mark row_top_reg using REPEATED_MARK_MACRO. This
+ is necessary because .TH might not call .T#.
+ (table::do_top): Likewise TOP_REG.
+ (table::define_bottom_macro): If TOP_REG is no longer valid, use
+ #T - DOUBLE_LINE_SEP rather than #T. This is necessary because the
+ table header might contain just the two top rules.
+
+Fri Jul 20 10:51:42 1990 James Clark (jjc at yquem)
+
+ * troff/div.c: Implement new request `ptr' to print all traps.
+
+ * troff/env.c (init_env_requests): Implement `.tabs' reg with
+ init_string_env_reg.
+ * troff/env.c (class tab_reg): Deleted.
+
+Thu Jul 19 12:07:16 1990 James Clark (jjc at yquem)
+
+ * troff/div.c: New number register .pn returns the number of the
+ next page as set by the pn request.
+
+ * macros/tmac.an: Redid headers and footers. Number each manual
+ entry starting from 1 unless \nC is > 0, like Sun. Added an
+ optional 5th argument to .TH which specifies the manual name and
+ appears in the center of the header. Understand the X, P and D
+ registers like Sun.
+
+Wed Jul 18 10:23:31 1990 James Clark (jjc at yquem)
+
+ * troff/env.c (init_env_requests): New number register `.lt' to
+ return the title length.
+
+ * troff/node.h (class transparent_dummy_node): New class.
+ * troff/node.c (class transparent_dummy_node): Provide member
+ functions.
+ * troff/env.c (interrupt): Add a transparent_dummy_node, rather
+ than a dummy_node.
+
+ * troff/input.c (token::next): New escape sequence \).
+ * troff/input.c (get_copy): Recognize \) in copy mode.
+
+ * troff/input.c (input_stack::clear): New function.
+ * troff/input.c (exit_request): Use input_stack::clear.
+
+ * troff/token.h: Removed TOKEN_NO_PRINT_CHAR.
+ * troff/input.c (token::process): Removed case TOKEN_NO_PRINT_CHAR.
+
+ * troff/env.c: Move set_page_character to input.c. Move
+ page_character to input.c also.
+ * troff/env.c (title): Split off the reading of the parts of the
+ title into read_title_parts.
+ * troff/input.c (read_title_parts): New function. Check the
+ input_level when testing whether a token matches the delimiter.
+
+ * troff/input.c (exit_request): New function.
+ * troff/input.c (init_input_requests): Bind ex request to
+ exit_request rather than exit_groff.
+
+ * troff/input.c (exit_groff): Call tok.next() before
+ process_input_stack().
+
+Mon Jul 16 09:47:23 1990 James Clark (jjc at yquem)
+
+ * troff/env.c: ifdef widow control support on WIDOW_CONTROL.
+ * troff/env.h: ditto.
+ * troff/input.c: ditto.
+
+ * troff/env.c (environment::is_empty): Test pending_lines.
+
+ * troff/env.c (environment::have_pending_lines): Removed.
+
+ * troff/input.c: Add request to flush pending lines from the
+ environment.
+
+ * troff/env.c, troff/env.h: Add automatic widow control feature.
+
+ * troff/input.c (exit_groff): Do process_input_stack() after
+ do_break() but before setting exit_flag to 2.
+
+ * troff/input.c: Remove FLUSH_PENDING_LINES and
+ TOKEN_FLUSH_PENDING_LINES. Instead, flush pending lines from
+ environment after END_TRAP token seen, but only if there aren't
+ any more traps still unfinished.
+ * troff/token.h: Remove TOKEN_FLUSH_PENDING_LINES.
+
+Sun Jul 15 10:50:08 1990 James Clark (jjc at yquem)
+
+ * troff/env.c: Rename the `retain_size' member of class
+ pending_output_line to `no_fill'.
+
+ * troff/env.c (title): When the line is output, make the
+ retain_size argument !fill.
+
+ * troff/node.h: Add `hyphenated' member to struct breakpoint.
+ * troff/node.c (space_node::get_breakpoints),
+ (dbreak_node::get_breakpoints): Fill this in.
+ * troff/env.c: Allow specification of maximum number of
+ consecutive hyphenated lines.
+
+ * troff/env.c (environment::is_empty): Add test for !current_tab.
+
+Sat Jul 14 11:23:01 1990 James Clark (jjc at yquem)
+
+ * troff/env.c (environment::hyphenate_line): Don't completely give
+ up if the word is not to be hyphenated; continue so that breaks
+ can be made at break_char_node's.
+
+ * lib/lib.h: Only define INT_MAX if it's not already defined;
+ undef INT_MIN if it's already defined.
+
+ * Makefile: Make it easy to define CFRONT_ANSI_BUG.
+
+ * lib/lib.h: If CFRONT_ANSI_BUG is defined, cast INT_MIN to long.
+ This works around a bug in AT&T C++ 2.0 used with an ANSI C
+ compiler.
+
+ * macros/tmac.an (an-header): Set no-space mode.
+
+ * macros/tmac.an (TH): Start a new page if necessary.
+
+ * Started using ChangeLog at version 0.4.
+
+Local Variables:
+version-control: never
+End:
diff --git a/gnu/usr.bin/groff/INSTALL b/gnu/usr.bin/groff/INSTALL
new file mode 100644
index 0000000..3e10726b
--- /dev/null
+++ b/gnu/usr.bin/groff/INSTALL
@@ -0,0 +1,122 @@
+1. Get a C++ compiler. The C++ source files use a suffix of `.cc', so
+your C++ compiler must be able to handle this. If you don't already
+have a C++ compiler, I suggest gcc 2.5.8 or later (gcc version 2
+includes GNU C++ as well as GNU C). From gcc 2.5, it is no longer
+necessary to install libg++: the C++ header files needed by groff are
+created by the gcc installation process.
+
+2. In the directory that this file is in, type `./configure'. If
+you're using `csh' on an old version of System V, you might need to
+type `sh configure' instead to prevent `csh' from trying to execute
+`configure' itself.
+
+The `configure' shell script attempts to guess correct values for
+various system-dependent variables used during compilation, and
+creates the Makefile. It also creates a file `config.status' that you
+can run in the future to recreate the current configuration.
+
+Running `configure' takes a minute or two. While it is running, it
+prints some messages that tell what it is doing. It also performs
+some checks on your C++ compiler. If these checks fail, it will print
+a message and exit. In this case, you should correct the problems
+with your C++ compiler and then rerun configure.
+
+To compile the package in a different directory from the one
+containing the source code, you must use GNU make (or a version of
+make that supports VPATH in the same way as GNU make). `cd' to the
+directory where you want the object files and executables to go and
+run `configure'. `configure' automatically checks for the source code
+in the directory that `configure' is in and in `..'. If for some
+reason `configure' is not in the source code directory that you are
+configuring, then it will report that it can't find the source code.
+In that case, run `configure' with the option `--srcdir=DIR', where
+DIR is the directory that contains the source code.
+
+By default, `make install' will install the package's files in
+/usr/local/bin, /usr/local/lib/groff, and /usr/local/man. You can
+specify an installation prefix other than /usr/local by giving
+`configure' the option `--prefix=PATH'. Alternately, you can do so by
+changing the `prefix' variable in the Makefile that `configure'
+creates.
+
+You can specify separate installation prefixes for
+architecture-specific files and architecture-independent files. If
+you give `configure' the option `--exec_prefix=PATH', the package will
+use PATH as the prefix for installing programs and libraries. Data
+files and documentation will still use the regular prefix. Normally,
+all files are installed using the regular prefix.
+
+You can tell `configure' to figure out the configuration for your
+system, and record it in `config.status', without actually configuring
+the package (creating `Makefile's and perhaps a configuration header
+file). To do this, give `configure' the `--no-create' option. Later,
+you can run `./config.status' to actually configure the package. This
+option is useful mainly in `Makefile' rules for updating `config.status'
+and `Makefile'. You can also give `config.status' the `--recheck'
+option, which makes it re-run `configure' with the same arguments you
+used before. This is useful if you change `configure'.
+
+`configure' ignores any other arguments that you give it.
+
+If your system requires unusual options for compilation or linking
+that `configure' doesn't know about, you can give `configure' initial
+values for some variables by setting them in the environment. In
+Bourne-compatible shells, you can do that on the command line like
+this:
+ CC='gcc -traditional' DEFS=-D_POSIX_SOURCE ./configure
+
+The `make' variables that you might want to override with environment
+variables when running `configure' are:
+
+(For these variables, any value given in the environment overrides the
+value that `configure' would choose:)
+CC C compiler program.
+ Default is `cc', or `gcc' if `gcc' is in your PATH.
+CCC C++ compiler program (for .cc files).
+ By default, configure will look for gcc version 2, g++,
+ and then CC.
+INSTALL Program to use to install files.
+ Default is `install' if you have it, `cp' otherwise.
+PAGE This should be `A4' if your PostScript printer uses
+ A4 paper and `letter' if your printer uses 8.5x11in
+ paper.
+
+(For these variables, any value given in the environment is added to
+the value that `configure' chooses:)
+DEFS Configuration options, in the form `-Dfoo -Dbar ...'
+LIBS Libraries to link with, in the form `-lfoo -lbar ...'
+CCLIBS Libraries to link C++ programs with, in the same form.
+
+If you have a library that provides a faster malloc than your system's
+usual malloc, it is good idea to include it in LIBS. For example,
+using the malloc that comes with GNU Emacs version 18 can give a
+worthwhile (and sometimes spectacular) performance improvement.
+
+If you need to do unusual things to compile the package, we encourage
+you to figure out how `configure' could check whether to do them, and
+mail diffs or instructions to the address given in the README so we
+can include them in the next release.
+
+3. Have a look at the generated Makefile. The options you are most
+likely to want to change are near the beginning. Make sure that the
+definition of PAGE is correct.
+
+4. Type `make'.
+
+5. Use the test-groff script to try groff out on one of the man pages.
+(Use the .n files not the .man files.) The test-groff script sets up
+environment variables to allow groff to run without being installed.
+The current directory must be the build directory when the script is
+run. For example, you could do
+
+ ./test-groff -man -Tascii groff/groff.n | less
+
+6. If you want to install gxditview (an X11 previewer), follow the
+instructions in the INSTALL file in the xditview directory.
+
+7. Type `make install' to install groff.
+
+8. Try the installed version of groff on one of the man pages.
+
+If you have problems, read the PROBLEMS file. If this doesn't help
+send a bug report using the form in the file BUG-REPORT.
diff --git a/gnu/usr.bin/groff/Makefile b/gnu/usr.bin/groff/Makefile
new file mode 100644
index 0000000..5cb5306
--- /dev/null
+++ b/gnu/usr.bin/groff/Makefile
@@ -0,0 +1,13 @@
+# Makefile for groff
+
+SUBDIR= libgroff libdriver libbib\
+ groff troff nroff tbl pic eqn grops grotty grodvi\
+ refer lookbib indxbib lkbib \
+ tfmtodit addftinfo pfbtops psbb \
+ devX100 devX100-12 devX75 devX75-12 devascii devdvi devlatin1 \
+ devkoi8-r devps tmac mm man xditview
+
+# BSD already provides soelim
+MISC= soelim
+
+.include <bsd.subdir.mk>
diff --git a/gnu/usr.bin/groff/Makefile.ccpg b/gnu/usr.bin/groff/Makefile.ccpg
new file mode 100644
index 0000000..20e888ad
--- /dev/null
+++ b/gnu/usr.bin/groff/Makefile.ccpg
@@ -0,0 +1,26 @@
+# Makefile.ccpg
+MAKEFILEPARTS=$(srcdir)/../Makefile.comm ../Makefile.cfg \
+ $(srcdir)/Makefile.sub $(srcdir)/../Makefile.ccpg $(srcdir)/Makefile.dep
+
+all: $(PROG) $(MANPAGES)
+
+$(PROG): $(OBJS) $(XLIBS)
+ $(LINK.cc) -o $@ $(OBJS) $(XLIBS) $(CCLIBS) $(LIBS) $(MLIB)
+
+install_bin: install_prog
+install_prog: $(PROG)
+install_data: install_man
+install_man: $(MANPAGES)
+uninstall_sub: uninstall_prog uninstall_man
+depend: depend_src
+depend.temp: $(GENSRCS) $(YTABC)
+distfiles: $(YTABC)
+TAGS: TAGS_src
+TAGS_src: $(CCSRCS) $(CSRCS) $(GRAM) $(HDRS)
+Makefile: $(MAKEFILEPARTS)
+
+pure: $(PROG).pure
+
+$(PROG).pure: $(OBJS) $(XLIBS)
+ $(PURIFY) $(PURIFYCCFLAGS) \
+ $(LINK.cc) -o $@ $(OBJS) $(XLIBS) $(CCLIBS) $(LIBS) $(MLIB)
diff --git a/gnu/usr.bin/groff/Makefile.cfg b/gnu/usr.bin/groff/Makefile.cfg
new file mode 100644
index 0000000..406e24e
--- /dev/null
+++ b/gnu/usr.bin/groff/Makefile.cfg
@@ -0,0 +1,131 @@
+BINDIR?= /usr/bin
+SHAREDIR?= /usr/share
+SHELL= /bin/sh
+
+# Define `page' to be letter if your PostScript printer uses 8.5x11
+# paper (USA) and define it to be A4, if it uses A4 paper (rest of the
+# world).
+PAGE=letter
+
+# Normally the Postscript driver, grops, produces output that conforms
+# to version 3.0 of the Adobe Document Structuring Conventions.
+# Unfortunately some spoolers and previewers can't handle such output.
+# The BROKEN_SPOOLER_FLAGS variable tells grops what it should do to
+# make its output acceptable to such programs. This variable controls
+# only the default behaviour of grops; the behaviour can be changed at
+# runtime by the grops -b option (and so by groff -P-b).
+# Use a value of 0 if your spoolers and previewers are able to handle
+# conforming PostScript correctly.
+# Add 1 if no %%{Begin,End}DocumentSetup comments should be generated;
+# this is needed for early versions of TranScript that get confused by
+# anything between the %%EndProlog line and the first %%Page: comment.
+# Add 2 if lines in included files beginning with %! should be
+# stripped out; this is needed for the OpenWindows 2.0 pageview previewer.
+# Add 4 if %%Page, %%Trailer and %%EndProlog comments should be
+# stripped out of included files; this is needed for spoolers that
+# don't understand the %%{Begin,End}Document comments. I suspect this
+# includes early versions of TranScript.
+# Add 8 if the first line of the PostScript output should be %!PS-Adobe-2.0
+# rather than %!PS-Adobe-3.0; this is needed when using Sun's Newsprint
+# with a printer that requires page reversal.
+BROKEN_SPOOLER_FLAGS=7
+
+# PSPRINT is the command to use for printing a PostScript file,
+# for example `lpr'.
+PSPRINT=lpr
+
+# DVIPRINT is the command to use for printing a TeX dvi file,
+# for example `lpr -d'.
+DVIPRINT=lpr -d
+########################################################################
+# Don't touch...
+
+g=
+tmac_s=s
+tmac_m=m
+device=ps
+fontdir=/usr/share/groff_font
+fontpath=$(fontdir)
+tmacdir=/usr/share/tmac
+tmacpath=$(tmacdir)
+indexext=.i
+common_words_file=/usr/share/dict/eign
+indexdir=/usr/share/dict/papers
+indexname=Ind
+
+########################################################################
+# Libraries
+
+# Bad assumption, if one exists they all exist
+.if exists(${.CURDIR}/../libgroff/obj)
+LIBGROFF= $(.CURDIR)/../libgroff/obj/libgroff.a
+LIBDRIVER= $(.CURDIR)/../libdriver/obj/libdriver.a
+LIBBIB= $(.CURDIR)/../libbib/obj/libbib.a
+.else
+LIBGROFF= $(.CURDIR)/../libgroff/libgroff.a
+LIBDRIVER= $(.CURDIR)/../libdriver/libdriver.a
+LIBBIB= $(.CURDIR)/../libbib/libbib.a
+.endif
+
+DEFINES= -DHAVE_UNISTD_H=1\
+ -DHAVE_DIRENT_H=1\
+ -DHAVE_LIMITS_H=1\
+ -DHAVE_STDLIB_H=1\
+ -DHAVE_SYS_DIR_H=1\
+ -DHAVE_CC_LIMITS_H=1\
+ -DHAVE_CC_UNISTD_H=1\
+ -DSTDLIB_H_DECLARES_GETOPT=1\
+ -DUNISTD_H_DECLARES_GETOPT=1\
+ -DSTDLIB_H_DECLARES_PUTENV=1\
+ -DSTDIO_H_DECLARES_POPEN=1\
+ -DSTDIO_H_DECLARE_PCLOSE=1\
+ -DRETSIGTYPE=void\
+ -DHAVE_MMAP=1\
+ -DHAVE_RENAME=1\
+ -DHAVE_MKSTEMP=1\
+ -DHAVE_SYS_SIGLIST=1
+
+CFLAGS+=$(DEFINES)
+
+.y.o:
+ $(YACC) $(YFLAGS) $(.IMPSRC)
+ mv y.tab.c $(.PREFIX).cc
+ mv y.tab.h $(.PREFIX).tab.h
+ ${CXX} ${CXXFLAGS} -c $(.PREFIX).cc -o ${.TARGET}
+.y.cc:
+ $(YACC) $(YFLAGS) $(.IMPSRC)
+ mv y.tab.c $(.PREFIX).cc
+ mv y.tab.h $(.PREFIX).tab.h
+
+.SUFFIXES: .man .1 .2 .3 .4 .5 .6 .7 .8
+
+#.8.man .7.man .6.man .5.man .4.man .3.man .2.man .1.man:
+
+.man.8 .man.7 .man.6 .man.5 .man.4 .man.3 .man.2 .man.1:
+ @${ECHO} Making $@ from $<
+ @-rm -f $@
+ @sed -e "s;@FONTDIR@;$(fontdir);g" \
+ -e "s;@FONTPATH@;$(fontpath);g" \
+ -e "s;@MACRODIR@;$(tmacdir);g" \
+ -e "s;@MACROPATH@;$(tmacpath);g" \
+ -e "s;@DEVICE@;$(device);g" \
+ -e "s;@DEFAULT_INDEX@;$(indexdir)/$(indexname);g" \
+ -e "s;@DEFAULT_INDEX_NAME@;$(indexname);g" \
+ -e "s;@INDEX_SUFFIX@;$(indexext);g" \
+ -e "s;@COMMON_WORDS_FILE@;$(common_words_file);g" \
+ -e "s;@MAN1EXT@;1;g" \
+ -e "s;@MAN5EXT@;5;g" \
+ -e "s;@MAN7EXT@;7;g" \
+ -e "s;@TMAC_S@;$(tmac_s);g" \
+ -e "s;@TMAC_M@;$(tmac_m);g" \
+ -e "s;@TMAC_MDIR@;$(tmacdir)/mm;g" \
+ -e "s;@BROKEN_SPOOLER_FLAGS@;$(BROKEN_SPOOLER_FLAGS);g" \
+ -e "s;@VERSION@;`cat ${.CURDIR}/../VERSION`;g" \
+ -e "s;@MDATE@;`$(SHELL) ${.CURDIR}/../mdate.sh $<`;g" \
+ -e "s;@g@;$(g);g" \
+ -e "s;@G@;`echo $(g) | tr [a-z] [A-Z]`;g" \
+ $< >$@
+
+.if exists(${.CURDIR}/obj)
+MANSRC=${.CURDIR}/obj
+.endif
diff --git a/gnu/usr.bin/groff/Makefile.comm b/gnu/usr.bin/groff/Makefile.comm
new file mode 100644
index 0000000..b3d24af
--- /dev/null
+++ b/gnu/usr.bin/groff/Makefile.comm
@@ -0,0 +1,247 @@
+# Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
+# Written by James Clark (jjc@jclark.com)
+#
+# This file is part of groff.
+#
+# groff is free software; you can redistribute it and/or modify it under
+# the terms of the GNU General Public License as published by the Free
+# Software Foundation; either version 2, or (at your option) any later
+# version.
+#
+# groff is distributed in the hope that it will be useful, but WITHOUT ANY
+# WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with groff; see the file COPYING. If not, write to the Free Software
+# Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+# Makefile.comm
+#
+SHELL=/bin/sh
+INCLUDES=-I. -I$(srcdir) -I../include -I$(srcdir)/../include
+ALL_CCFLAGS=$(INCLUDES) $(CCDEFINES) $(CCFLAGS) $(CPPFLAGS)
+COMPILE.cc=$(CCC) $(ALL_CCFLAGS) -c
+ALL_CFLAGS=$(CDEFINES) $(CFLAGS) $(CPPFLAGS)
+COMPILE.c=$(CC) $(ALL_CFLAGS) -c
+LINK.cc=$(CCC) $(CCFLAGS) $(LDFLAGS)
+LINK.c=$(CC) $(CFLAGS) $(LDFLAGS)
+TOP=..
+LIBGROFF=$(TOP)/libgroff/libgroff.a
+LIBBIB=$(TOP)/libbib/libbib.a
+LIBDRIVER=$(TOP)/libdriver/libdriver.a
+LIBM=-lm
+MLIB=
+XLIBS=
+YTABH=
+YTABC=
+GRAM=
+LIBCLEAN=
+CLEANADD=
+MOSTLYCLEANFILES=$(MANCLEAN) $(PROG) $(OBJS) $(GENSRCS) $(GENHDRS) \
+ depend.temp core y.output $(CLEANADD)
+CLEANFILES=$(LIBCLEAN)
+DISTCLEANFILES=TAGS Makefile
+REALCLEANFILES=$(YTABC) $(YTABH)
+NAMEPREFIX=
+HDRS=
+MANPAGES=$(MAN1) $(MAN5) $(MAN7)
+MANCLEAN=$(MANPAGES)
+fontsubdir=$(fontdir)/dev$(DEV)
+
+all install install_bin install_data TAGS depend distfiles uninstall_sub:
+
+install: install_bin install_data
+uninstall: uninstall_sub
+pure:
+
+.PHONY: all clean distclean mostlyclean realclean extraclean depend distfiles
+.PHONY: install install_bin install_data
+.PHONY: uninstall uninstall_sub
+.PHONY: pure
+
+mostlyclean:
+ -rm -f $(MOSTLYCLEANFILES)
+
+clean:
+ -rm -f $(CLEANFILES) $(MOSTLYCLEANFILES)
+
+distclean:
+ -rm -f $(DISTCLEANFILES) $(CLEANFILES) $(MOSTLYCLEANFILES)
+
+realclean:
+ -rm -f $(REALCLEANFILES) $(DISTCLEANFILES) $(CLEANFILES) \
+ $(MOSTLYCLEANFILES)
+
+extraclean:
+ -rm -f $(DISTCLEANFILES) $(CLEANFILES) $(MOSTLYCLEANFILES) \
+ \#* *~ =* core junk grot old temp tmp tem
+
+.SUFFIXES:
+.SUFFIXES: .o .cc .c .y .man .n
+
+.cc.o:
+ $(COMPILE.cc) $<
+
+.c.o:
+ $(COMPILE.c) $<
+
+.y.cc:
+ if test -n "$(YTABH)"; then \
+ $(YACC) $(YACCFLAGS) -d $<; \
+ else \
+ $(YACC) $(YACCFLAGS) $<; \
+ fi
+ mv y.tab.c $@
+# Avoid ending up with two versions of $(YTABH).
+ if test -n "$(YTABH)"; then \
+ if test -f $(srcdir)/$(YTABH); then \
+ rm -f $(YTABH); \
+ mv y.tab.h $(srcdir)/$(YTABH); \
+ else \
+ mv y.tab.h $(YTABH); \
+ fi; \
+ fi
+
+.man.n:
+ @echo Making $@ from $<
+ @-rm -f $@
+ @sed -e "s;@FONTDIR@;$(fontdir);g" \
+ -e "s;@FONTPATH@;$(fontpath);g" \
+ -e "s;@MACRODIR@;$(tmacdir);g" \
+ -e "s;@MACROPATH@;$(tmacpath);g" \
+ -e "s;@DEVICE@;$(DEVICE);g" \
+ -e "s;@DEFAULT_INDEX@;$(indexdir)/$(indexname);g" \
+ -e "s;@DEFAULT_INDEX_NAME@;$(indexname);g" \
+ -e "s;@INDEX_SUFFIX@;$(indexext);g" \
+ -e "s;@COMMON_WORDS_FILE@;$(common_words_file);g" \
+ -e "s;@MAN1EXT@;$(man1ext);g" \
+ -e "s;@MAN5EXT@;$(man5ext);g" \
+ -e "s;@MAN7EXT@;$(man7ext);g" \
+ -e "s;@TMAC_S@;$(tmac_s);g" \
+ -e "s;@TMAC_M@;$(tmac_m);g" \
+ -e "s;@TMAC_MDIR@;$(tmacdir)/mm;g" \
+ -e "s;@BROKEN_SPOOLER_FLAGS@;$(BROKEN_SPOOLER_FLAGS);g" \
+ -e "s;@VERSION@;`cat $(srcdir)/../VERSION`;g" \
+ -e "s;@MDATE@;`$(SHELL) $(srcdir)/../mdate.sh $<`;g" \
+ -e "s;@g@;$(g);g" \
+ -e "s;@G@;`echo $(g) | tr [a-z] [A-Z]`;g" \
+ $< >$@
+
+.PHONY: install_man
+install_man:
+ -test -d $(manroot) || mkdir $(manroot)
+ -test -d $(man1dir) || mkdir $(man1dir)
+ @-pages="$(MAN1)"; \
+ for p in $$pages; do \
+ prog=`basename $$p .n`; \
+ target=$(man1dir)/$(NAMEPREFIX)$$prog.$(man1ext); \
+ rm -f $$target; \
+ echo $(INSTALL_DATA) $$p $$target; \
+ $(INSTALL_DATA) $$p $$target; \
+ done
+ -test -d $(man5dir) || mkdir $(man5dir)
+ @-pages="$(MAN5)"; \
+ for p in $$pages; do \
+ target=$(man5dir)/`basename $$p .n`.$(man5ext); \
+ rm -f $$target; \
+ echo $(INSTALL_DATA) $$p $$target; \
+ $(INSTALL_DATA) $$p $$target; \
+ done
+ -test -d $(man7dir) || mkdir $(man7dir)
+ @-pages="$(MAN7)"; \
+ for p in $$pages; do \
+ target=$(man7dir)/`basename $$p .n`.$(man7ext); \
+ rm -f $$target; \
+ echo $(INSTALL_DATA) $$p $$target; \
+ $(INSTALL_DATA) $$p $$target; \
+ done
+
+.PHONY: uninstall_man
+uninstall_man:
+ @-pages="$(MAN1)"; \
+ for p in $$pages; do \
+ target=$(man1dir)/$(NAMEPREFIX)`basename $$p .n`.$(man1ext); \
+ echo rm -f $$target; \
+ rm -f $$target; \
+ done
+ @-pages="$(MAN5)"; \
+ for p in $$pages; do \
+ target=$(man5dir)/`basename $$p .n`.$(man5ext); \
+ echo rm -f $$target; \
+ rm -f $$target; \
+ done
+ @-pages="$(MAN7)"; \
+ for p in $$pages; do \
+ target=$(man7dir)/`basename $$p .n`.$(man7ext); \
+ echo rm -f $$target; \
+ rm -f $$target; \
+ done
+
+.PHONY: install_prog
+install_prog:
+ -test -d $(bindir) || mkdir $(bindir)
+ rm -f $(bindir)/$(NAMEPREFIX)$(PROG)
+ $(INSTALL_PROGRAM) $(PROG) $(bindir)/$(NAMEPREFIX)$(PROG)
+
+.PHONY: uninstall_prog
+uninstall_prog:
+ -rm -f $(bindir)/$(NAMEPREFIX)$(PROG)
+
+.PHONY: install_dev
+install_dev:
+ -test -d $(datadir) || mkdir $(datadir)
+ -test -d $(datasubdir) || mkdir $(datasubdir)
+ -test -d $(fontdir) || mkdir $(fontdir)
+ -test -d $(fontsubdir) || mkdir $(fontsubdir)
+ -if test -d $(srcdir)/generate; then \
+ test -d $(fontsubdir)/generate || mkdir $(fontsubdir)/generate; \
+ fi
+ -for f in $(DEVFILES); do \
+ rm -f $(fontsubdir)/$$f; \
+ if test -f $$f; then \
+ $(INSTALL_DATA) $$f $(fontsubdir)/$$f; \
+ else \
+ $(INSTALL_DATA) $(srcdir)/$$f $(fontsubdir)/$$f; \
+ fi; \
+ done
+
+.PHONY: uninstall_dev
+uninstall_dev:
+ -for f in $(DEVFILES); do rm -f $(fontsubdir)/$$f; done
+ -if test -d $(fontsubdir)/generate; then \
+ rmdir $(fontsubdir)/generate; \
+ fi
+ -rmdir $(fontsubdir)
+
+.PHONY: depend_src
+depend_src: depend.temp
+ mv depend.temp Makefile.dep
+
+depend.temp: FORCE
+ > depend.temp;
+ test -z "$(CCSRCS)$(YTABC)" \
+ || $(CCC) $(ALL_CCFLAGS) -MM $(CCSRCS) $(YTABC) >>depend.temp
+ test -z "$(CSRCS)" \
+ || $(CC) $(ALL_CFLAGS) -MM $(CSRCS) >>depend.temp
+ if test -n "$(YTABH)"; then \
+ sed -e 's|$(YTABH)|$(YTABC)|g' depend.temp >depend.temp1; \
+ mv depend.temp1 depend.temp; \
+ fi
+
+.PHONY: TAGS_src
+TAGS_src:
+ $(ETAGS) $(ETAGSFLAGS) $(CCSRCS) $(CSRCS)
+ test -z "$(GRAM)$(HDRS)" \
+ || $(ETAGS) $(ETAGSFLAGS) -a $(ETAGSCCFLAG) $(GRAM) $(HDRS)
+
+Makefile:
+ -rm -f Makefile
+ echo srcdir=$(srcdir) >>Makefile
+ echo VPATH=$(VPATH) >>Makefile
+ cat $(MAKEFILEPARTS) /dev/null >>Makefile
+
+FORCE:
+
+.NOEXPORT:
diff --git a/gnu/usr.bin/groff/Makefile.cpg b/gnu/usr.bin/groff/Makefile.cpg
new file mode 100644
index 0000000..1b9f66f
--- /dev/null
+++ b/gnu/usr.bin/groff/Makefile.cpg
@@ -0,0 +1,20 @@
+# Makefile.cpg
+MAKEFILEPARTS=$(srcdir)/../Makefile.comm ../Makefile.cfg \
+ $(srcdir)/Makefile.sub $(srcdir)/../Makefile.cpg $(srcdir)/Makefile.dep
+
+all: $(PROG) $(MANPAGES)
+
+$(PROG): $(OBJS) $(XLIBS)
+ $(LINK.c) -o $@ $(OBJS) $(XLIBS) $(LIBS) $(MLIB)
+
+install_bin: install_prog
+install_prog: $(PROG)
+install_data: install_man
+install_man: $(MANPAGES)
+uninstall_sub: uninstall_prog uninstall_man
+depend: depend_src
+depend.temp: $(GENSRCS) $(YTABC)
+distfiles: $(YTABC)
+TAGS: TAGS_src
+TAGS_src: $(CCSRCS) $(CSRCS) $(GRAM) $(HDRS)
+Makefile: $(MAKEFILEPARTS)
diff --git a/gnu/usr.bin/groff/Makefile.dev b/gnu/usr.bin/groff/Makefile.dev
new file mode 100644
index 0000000..2aa71f8
--- /dev/null
+++ b/gnu/usr.bin/groff/Makefile.dev
@@ -0,0 +1,27 @@
+# @(#)Makefile.dev 6.2 (Berkeley) 3/16/91
+
+# Client Makefiles define DEVICE and FONTFILES and provide rules for
+# individual font files
+
+.include "../Makefile.cfg"
+
+FONTDIR?= /usr/share/groff_font
+DEVICEDIR?= $(FONTDIR)/dev$(DEVICE)
+FONTOWN?= bin
+FONTGRP?= bin
+FONTMODE?= 444
+
+all: $(FONTFILES)
+
+.for f in $(FONTFILES)
+.if exists($f)
+beforeinstall: $f
+.else
+beforeinstall: $(.CURDIR)/$f
+.endif
+.endfor
+beforeinstall:
+ $(INSTALL) -c -o $(FONTOWN) -g $(FONTGRP) -m $(FONTMODE) \
+ ${.ALLSRC} $(DESTDIR)$(DEVICEDIR)
+
+.include <bsd.prog.mk>
diff --git a/gnu/usr.bin/groff/Makefile.in b/gnu/usr.bin/groff/Makefile.in
new file mode 100644
index 0000000..321fc2e
--- /dev/null
+++ b/gnu/usr.bin/groff/Makefile.in
@@ -0,0 +1,387 @@
+# Copyright (C) 1989, 1990, 1991, 1992, 1993 Free Software Foundation, Inc.
+# Written by James Clark (jjc@jclark.com)
+#
+# This file is part of groff.
+#
+# groff is free software; you can redistribute it and/or modify it under
+# the terms of the GNU General Public License as published by the Free
+# Software Foundation; either version 2, or (at your option) any later
+# version.
+#
+# groff is distributed in the hope that it will be useful, but WITHOUT ANY
+# WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with groff; see the file COPYING. If not, write to the Free Software
+# Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+# Define `page' to be letter if your PostScript printer uses 8.5x11
+# paper (USA) and define it to be A4, if it uses A4 paper (rest of the
+# world).
+PAGE=@PAGE@
+
+# Normally the Postscript driver, grops, produces output that conforms
+# to version 3.0 of the Adobe Document Structuring Conventions.
+# Unfortunately some spoolers and previewers can't handle such output.
+# The BROKEN_SPOOLER_FLAGS variable tells grops what it should do to
+# make its output acceptable to such programs. This variable controls
+# only the default behaviour of grops; the behaviour can be changed at
+# runtime by the grops -b option (and so by groff -P-b).
+# Use a value of 0 if your spoolers and previewers are able to handle
+# conforming PostScript correctly.
+# Add 1 if no %%{Begin,End}DocumentSetup comments should be generated;
+# this is needed for early versions of TranScript that get confused by
+# anything between the %%EndProlog line and the first %%Page: comment.
+# Add 2 if lines in included files beginning with %! should be
+# stripped out; this is needed for the OpenWindows 2.0 pageview previewer.
+# Add 4 if %%Page, %%Trailer and %%EndProlog comments should be
+# stripped out of included files; this is needed for spoolers that
+# don't understand the %%{Begin,End}Document comments. I suspect this
+# includes early versions of TranScript.
+# Add 8 if the first line of the PostScript output should be %!PS-Adobe-2.0
+# rather than %!PS-Adobe-3.0; this is needed when using Sun's Newsprint
+# with a printer that requires page reversal.
+BROKEN_SPOOLER_FLAGS=@BROKEN_SPOOLER_FLAGS@
+
+# DEVICE is the default device.
+DEVICE=ps
+
+# PSPRINT is the command to use for printing a PostScript file,
+# for example `lpr'.
+PSPRINT=@PSPRINT@
+
+# DVIPRINT is the command to use for printing a TeX dvi file,
+# for example `lpr -d'.
+DVIPRINT=@DVIPRINT@
+
+# Prefix for names of programs that have Unix counterparts.
+# For example, if `g' is `g' then troff will be installed as
+# gtroff. This doesn't affect programs like grops or groff that have
+# no Unix counterparts. Note that the groff versions of eqn and tbl
+# will not work with Unix troff. This is also use in the definitions
+# of tmac_s and tmac_m.
+g=g
+
+# The groff ms macros will be available as -m$(tmac_s).
+# If you use `tmac_s=s', you can use the Unix ms macros by using
+# groff -ms -M/usr/lib/tmac.
+tmac_s=$(g)s
+
+# Similarly, the groff mm macros will be available as -m$(tmac_m).
+tmac_m=$(g)m
+
+# Common prefix for installation directories.
+# Used in definitions of exec_prefix, datasubdir, fontpath, manroot.
+# This must already exist when you do make install.
+prefix=/usr/local
+
+exec_prefix=$(prefix)
+
+# bindir says where to install executables.
+bindir=$(exec_prefix)/bin
+
+# datasubdir says where to install data files
+datadir=$(prefix)/lib
+datasubdir=$(datadir)/groff
+
+# fontdir says where to install dev*/*.
+fontdir=$(datasubdir)/font
+
+# fontpath says where to look for dev*/*.
+fontpath=.:$(fontdir):$(prefix)/lib/font:/usr/lib/font
+
+# tmacdir says where to install macros.
+tmacdir=$(datasubdir)/tmac
+
+# tmacpath says where to look for macro files.
+tmacpath=.:$(tmacdir):/usr/lib/tmac
+
+# Extension to be used for refer index files. Index files are not
+# sharable between different architectures, so you might want to use
+# different suffixes for different architectures. Choose an extension
+# that doesn't conflict with refer or any other indexing program.
+indexext=.i
+
+# Directory containing the default index for refer.
+indexdir=/usr/dict/papers
+
+# The filename (without suffix) of the default index for refer.
+indexname=Ind
+
+# common_words_file is a file containing a list of common words.
+# If your system provides /usr/lib/eign it will be copied onto this,
+# otherwise the supplied eign file will be used.
+common_words_file=$(datasubdir)/eign
+
+# manroot is the root of the man page directory tree.
+manroot=$(prefix)/man
+
+# man1ext is the man section for user commands.
+man1ext=1
+man1dir=$(manroot)/man$(man1ext)
+
+# man5ext is the man section for file formats.
+man5ext=5
+man5dir=$(manroot)/man$(man5ext)
+
+# man7ext is the man section for macros.
+man7ext=7
+man7dir=$(manroot)/man$(man7ext)
+
+# DEFINES should include the following:
+# -DHAVE_MMAP if you have mmap() and <sys/mman.h>
+# -DCFRONT_ANSI_BUG if you're using cfront 2.0 (or later?) with
+# an ANSI C compiler
+# -DCOOKIE_BUG if you're using gcc/g++ 2.[012] (you should
+# upgrade to 2.3).
+# -DARRAY_DELETE_NEEDS_SIZE if your C++ doesn't understand `delete []'
+# -DHAVE_SYS_SIGLIST if you have sys_siglist[]
+# -DWCOREFLAG=0200 if the 0200 bit of the status returned by
+# wait() indicates whether a core image was
+# produced for a process that was terminated
+# by a signal
+# -DHAVE_UNISTD_H if you have <unistd.h>
+# -DHAVE_CC_OSFCN_H if you have a C++ <osfcn.h>
+# -DHAVE_DIRENT_H if you have <dirent.h>
+# -DHAVE_LIMITS_H if you have <limits.h>
+# -DHAVE_CC_LIMITS_H if you have a C++ <limits.h>
+# -DHAVE_SYS_DIR_H if you have <sys/dir.h>
+# -DHAVE_STDLIB_H if you have <stdlib.h>
+# -DHAVE_VFORK_H if you have <vfork.h>
+# -Dvfork=fork if you don't have a working vfork()
+# -DHAVE_RENAME if you have rename()
+# -DHAVE_MKSTEMP if you have mkstemp()
+# -DSTDLIB_H_DECLARES_GETOPT if your C++ <stdlib.h> declares getopt()
+# -DUNISTD_H_DECLARES_GETOPT if your C++ <unistd.h> declares getopt()
+# -DSTDLIB_H_DECLARES_PUTENV if your C++ <stdlib.h> declares putenv()
+# -DSTDIO_H_DECLARES_POPEN if your C++ <stdio.h> declares popen()
+# -DTRADITIONAL_CPP if your C++ compiler uses a traditional
+# (Reiser) preprocessor.
+# -DLONG_FOR_TIME_T if localtime() takes a long * not a time_t *
+# -DHAVE_STRUCT_EXCEPTION if <math.h> defines struct exception
+# -DRETSIGTYPE=int if signal handlers return int not void
+DEFINES=@DEFS@
+
+# Include fmod.o, strtol.o, getcwd.o, strerror.o, putenv.o in LIBOBJS if
+# your C library is missing the corresponding function.
+LIBOBJS=@LIBOBJS@
+
+# CCC is the compiler for C++ (.cc) files.
+CCC=@CCC@
+CC=@CC@
+# CCDEFINES are definitions for C++ compilations.
+CCDEFINES=$(DEFINES)
+# CDEFINES are definitions for C compilations.
+CDEFINES=$(DEFINES)
+
+DEBUG=
+OPTIMIZE=-O
+CCFLAGS=$(DEBUG) $(OPTIMIZE)
+CFLAGS=$(DEBUG) $(OPTIMIZE)
+YACC=@YACC@
+YACCFLAGS=-v
+
+LIBS=@LIBS@
+CCLIBS=@CCLIBS@
+RANLIB=@RANLIB@
+INSTALL=@INSTALL@
+INSTALL_PROGRAM=@INSTALL_PROGRAM@
+INSTALL_DATA=@INSTALL_DATA@
+LN_S=@LN_S@
+AR=ar
+ETAGS=etags
+ETAGSFLAGS=
+# Flag that tells etags to assume C++.
+ETAGSCCFLAG=@ETAGSCCFLAG@
+# Full path to perl.
+PERLPATH=@PERLPATH@
+# Sed command with which to edit sh scripts.
+SH_SCRIPT_SED_CMD=@SH_SCRIPT_SED_CMD@
+srcdir = @srcdir@
+VPATH = @srcdir@
+
+PURIFY=purify
+PURIFYCCFLAGS=
+#PURIFYCCFLAGS=-g++=yes \
+# -collector=`dirname \`$(CCC) -print-libgcc-file-name\``/ld
+
+# Passing down MAKEOVERRIDES prevents $(MAKE) from containing a second
+# copy of $(MDEFINES) when making individual directories; this could
+# cause the argument list to become too long on some systems.
+MDEFINES="MAKEOVERRIDES=$(MAKEOVERRIDES)" \
+ "PAGE=$(PAGE)" "BROKEN_SPOOLER_FLAGS=$(BROKEN_SPOOLER_FLAGS)" \
+ "DEVICE=$(DEVICE)" "PSPRINT=$(PSPRINT)" "DVIPRINT=$(DVIPRINT)" \
+ "prefix=$(prefix)" "exec_prefix=$(exec_prefix)" "bindir=$(bindir)" \
+ "g=$(g)" "datadir=$(datadir)" "datasubdir=$(datasubdir)" \
+ "fontdir=$(fontdir)" "fontpath=$(fontpath)" \
+ "tmacdir=$(tmacdir)" "tmacpath=$(tmacpath)" \
+ "indexext=$(indexext)" "indexdir=$(indexdir)" \
+ "indexname=$(indexname)" "common_words_file=$(common_words_file)" \
+ "manroot=$(manroot)" "man1ext=$(man1ext)" "man1dir=$(man1dir)" \
+ "man5ext=$(man5ext)" "man5dir=$(man5dir)" \
+ "man7ext=$(man7ext)" "man7dir=$(man7dir)" \
+ "tmac_s=$(tmac_s)" "tmac_m=$(tmac_m)" \
+ "CCC=$(CCC)" "CC=$(CC)" "CCDEFINES=$(CCDEFINES)" "CDEFINES=$(CDEFINES)" \
+ "CCFLAGS=$(CCFLAGS)" "CFLAGS=$(CFLAGS)" \
+ "YACC=$(YACC)" "YACCFLAGS=$(YACCFLAGS)" \
+ "LIBS=$(LIBS)" "CCLIBS=$(CCLIBS)" "LIBOBJS=$(LIBOBJS)" \
+ "RANLIB=$(RANLIB)" "AR=$(AR)" \
+ "INSTALL_PROGRAM=$(INSTALL_PROGRAM)" "INSTALL_DATA=$(INSTALL_DATA)" \
+ "ETAGS=$(ETAGS)" "ETAGSFLAGS=$(ETAGSFLAGS)" "ETAGSCCFLAG=$(ETAGSCCFLAG)" \
+ "PERLPATH=$(PERLPATH)" "SH_SCRIPT_SED_CMD=$(SH_SCRIPT_SED_CMD)" \
+ "PURIFY=$(PURIFY)" "PURIFYCCFLAGS=$(PURIFYCCFLAGS)"
+
+SHELL=/bin/sh
+INCDIRS=include
+LIBDIRS=libgroff libdriver libbib
+CCPROGDIRS=groff troff tbl pic eqn grops grotty grodvi tfmtodit \
+ refer lookbib indxbib lkbib soelim addftinfo
+CPROGDIRS=pfbtops psbb
+PROGDIRS=$(CCPROGDIRS) $(CPROGDIRS)
+DEVDIRS=devps devdvi devascii devlatin1 devX75 devX75-12 devX100 devX100-12
+OTHERDIRS=man tmac afmtodit grog nroff mm
+ALLDIRS=$(INCDIRS) $(LIBDIRS) $(PROGDIRS) $(DEVDIRS) $(OTHERDIRS)
+EXTRADIRS=devps/generate devdvi/generate xditview doc
+DISTDIRS=$(ALLDIRS) $(EXTRADIRS)
+TARGETS=all install install_bin install_data clean distclean mostlyclean \
+ realclean extraclean distfiles TAGS depend uninstall_sub
+
+do=all
+dodirs=$(ALLDIRS) dot
+# Default target for subdir_Makefile
+subdir=troff
+
+
+$(TARGETS):
+ @$(MAKE) $(MDEFINES) do=$@ $(dodirs)
+
+dot: FORCE
+ @$(MAKE) $(MDEFINES) srcdir=$(srcdir) VPATH=$(srcdir) \
+ -f $(srcdir)/Makefile.comm -f $(srcdir)/Makefile.sub $(do)
+
+$(LIBDIRS): FORCE
+ @if test $(srcdir) = .; \
+ then srcdir=.; \
+ else srcdir=`cd $(srcdir); pwd`/$@; \
+ fi; \
+ test -d $@ || mkdir $@; \
+ cd $@; \
+ $(MAKE) $(MDEFINES) srcdir=$$srcdir VPATH=$$srcdir \
+ -f $$srcdir/../Makefile.comm -f $$srcdir/Makefile.sub \
+ -f $$srcdir/../Makefile.lib -f $$srcdir/Makefile.dep $(do)
+
+$(CPROGDIRS): FORCE
+ @if test $(srcdir) = .; \
+ then srcdir=.; \
+ else srcdir=`cd $(srcdir); pwd`/$@; \
+ fi; \
+ test -d $@ || mkdir $@; \
+ cd $@; \
+ $(MAKE) $(MDEFINES) srcdir=$$srcdir VPATH=$$srcdir \
+ -f $$srcdir/../Makefile.comm -f $$srcdir/Makefile.sub \
+ -f $$srcdir/../Makefile.cpg -f $$srcdir/Makefile.dep $(do)
+
+$(CCPROGDIRS): FORCE
+ @if test $(srcdir) = .; \
+ then srcdir=.; \
+ else srcdir=`cd $(srcdir); pwd`/$@; \
+ fi; \
+ test -d $@ || mkdir $@; \
+ cd $@; \
+ $(MAKE) $(MDEFINES) srcdir=$$srcdir VPATH=$$srcdir \
+ -f $$srcdir/../Makefile.comm -f $$srcdir/Makefile.sub \
+ -f $$srcdir/../Makefile.ccpg -f $$srcdir/Makefile.dep $(do)
+
+$(DEVDIRS): FORCE
+ @if test $(srcdir) = .; \
+ then srcdir=.; \
+ else srcdir=`cd $(srcdir); pwd`/$@; \
+ fi; \
+ test -d $@ || mkdir $@; \
+ cd $@; \
+ $(MAKE) $(MDEFINES) srcdir=$$srcdir VPATH=$$srcdir \
+ -f $$srcdir/../Makefile.comm -f $$srcdir/Makefile.sub \
+ -f $$srcdir/../Makefile.dev $(do)
+
+$(INCDIRS) $(OTHERDIRS): FORCE
+ @if test $(srcdir) = .; \
+ then srcdir=.; \
+ else srcdir=`cd $(srcdir); pwd`/$@; \
+ fi; \
+ test -d $@ || mkdir $@; \
+ cd $@; \
+ $(MAKE) $(MDEFINES) srcdir=$$srcdir VPATH=$$srcdir \
+ -f $$srcdir/../Makefile.comm -f $$srcdir/Makefile.sub \
+ -f $$srcdir/../Makefile.man $(do)
+
+version=`cat $(srcdir)/VERSION`
+
+.PHONY: dist
+dist:
+ -rm -fr tmp
+ mkdir tmp
+ for d in $(DISTDIRS); do \
+ mkdir tmp/$$d; \
+ done
+ srcdir=`cd $(srcdir); pwd`; \
+ cd tmp; \
+ $(LN_S) ../Makefile .; \
+ $(LN_S) $$srcdir/* . 2>/dev/null || true; \
+ for d in $(DISTDIRS); do \
+ (cd $$d; $(LN_S) $$srcdir/$$d/* . 2>/dev/null || true); \
+ done; \
+ $(MAKE) srcdir=$$srcdir VPATH=$$srcdir extraclean; \
+ for d in $(EXTRADIRS); do \
+ (cd $$d; $(MAKE) extraclean); \
+ done; \
+ rm -f Makefile; \
+ $(LN_S) $$srcdir/Makefile.init Makefile
+ mv tmp groff-$(version)
+ tar cfh - groff-$(version) | gzip -c >groff-$(version).tar.gz
+ rm -fr groff-$(version)
+
+# $(PROGDIRS): libgroff
+# grops grotty grodvi: libdriver
+# refer lookbib indxbib lkbib: libbib
+# $(LIBDIRS) $(PROGDIRS): include
+
+.PHONY: $(ALLDIRS) dot $(TARGETS) FORCE
+
+subdir_Makefile: Makefile.cfg
+ $(MAKE) do=Makefile $(subdir)
+
+Makefile.cfg: Makefile
+ >Makefile.cfg
+ for var in $(MDEFINES); do \
+ echo "$$var" >>Makefile.cfg; \
+ done
+
+depend: srcdir_must_be_dot
+
+.PHONY: srcdir_must_be_dot
+srcdir_must_be_dot:
+ @test "X$(srcdir)" = "X." \
+ || (echo This target can only be made in the source directory; \
+ exit 1)
+
+Makefile: Makefile.in
+ $(SHELL) config.status
+
+.PHONY: uninstall
+uninstall: uninstall_sub uninstall_dirs
+
+.PHONY: uninstall_dirs
+uninstall_dirs:
+# Use rmdir here so that the directories are only removed if they're empty
+ -rmdir $(man1dir) $(man5dir) $(man7dir) $(manroot) \
+ $(tmacdir) $(fontdir) $(bindir) $(datasubdir) $(datadir)
+
+
+.PHONY: check
+check:
+
+FORCE:
+
+.NOEXPORT:
diff --git a/gnu/usr.bin/groff/Makefile.init b/gnu/usr.bin/groff/Makefile.init
new file mode 100644
index 0000000..dfcf0dd
--- /dev/null
+++ b/gnu/usr.bin/groff/Makefile.init
@@ -0,0 +1,25 @@
+# Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
+# Written by James Clark (jjc@jclark.com)
+#
+# This file is part of groff.
+#
+# groff is free software; you can redistribute it and/or modify it under
+# the terms of the GNU General Public License as published by the Free
+# Software Foundation; either version 2, or (at your option) any later
+# version.
+#
+# groff is distributed in the hope that it will be useful, but WITHOUT ANY
+# WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with groff; see the file COPYING. If not, write to the Free Software
+# Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+SHELL=/bin/sh
+
+.PHONY: all
+all:
+ $(SHELL) configure
+ $(MAKE) all
diff --git a/gnu/usr.bin/groff/Makefile.lib b/gnu/usr.bin/groff/Makefile.lib
new file mode 100644
index 0000000..019ba6a
--- /dev/null
+++ b/gnu/usr.bin/groff/Makefile.lib
@@ -0,0 +1,14 @@
+LIBCLEAN=lib$(LIB).a
+MAKEFILEPARTS=$(srcdir)/../Makefile.comm ../Makefile.cfg \
+ $(srcdir)/Makefile.sub $(srcdir)/../Makefile.lib $(srcdir)/Makefile.dep
+
+all: lib$(LIB).a
+
+lib$(LIB).a: $(OBJS)
+ $(AR) r $@ $?
+ $(RANLIB) $@
+
+depend: depend_src
+depend.temp: $(GENSRCS)
+TAGS: $(CCSRCS) $(CSRCS)
+Makefile: $(MAKEFILEPARTS)
diff --git a/gnu/usr.bin/groff/Makefile.man b/gnu/usr.bin/groff/Makefile.man
new file mode 100644
index 0000000..59378de
--- /dev/null
+++ b/gnu/usr.bin/groff/Makefile.man
@@ -0,0 +1,4 @@
+all: $(MANPAGES)
+install_data: install_man
+install_man: $(MANPAGES)
+uninstall_sub: uninstall_man
diff --git a/gnu/usr.bin/groff/Makefile.sub b/gnu/usr.bin/groff/Makefile.sub
new file mode 100644
index 0000000..f0d09a3
--- /dev/null
+++ b/gnu/usr.bin/groff/Makefile.sub
@@ -0,0 +1,7 @@
+DISTCLEANFILES=config.status Makefile
+CLEANADD=Makefile.cfg conftest*
+
+distfiles: configure
+
+configure: configure.in acgroff.m4
+ cd $(srcdir); autoconf
diff --git a/gnu/usr.bin/groff/Makefile.tty b/gnu/usr.bin/groff/Makefile.tty
new file mode 100644
index 0000000..95cd6ca
--- /dev/null
+++ b/gnu/usr.bin/groff/Makefile.tty
@@ -0,0 +1,53 @@
+# @(#)Makefile.tty 6.1 (Berkeley) 3/3/91
+#
+# Modified for Berkeley Unix by Donn Seeley, donn@okeeffe.berkeley.edu
+#
+#Copyright (C) 1989, 1990 Free Software Foundation, Inc.
+# Written by James Clark (jjc@jclark.uucp)
+#
+#This file is part of groff.
+#
+#groff is free software; you can redistribute it and/or modify it under
+#the terms of the GNU General Public License as published by the Free
+#Software Foundation; either version 1, or (at your option) any later
+#version.
+#
+#groff is distributed in the hope that it will be useful, but WITHOUT ANY
+#WARRANTY; without even the implied warranty of MERCHANTABILITY or
+#FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+#for more details.
+#
+#You should have received a copy of the GNU General Public License along
+#with groff; see the file LICENSE. If not, write to the Free Software
+#Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+.MAIN: all
+
+RES=240
+CPI=10
+LPI=6
+FONTS=R I B BI S L
+
+FONTFILES=$(FONTS) DESC
+CLEANFILES=$(FONTFILES)
+
+$(FONTS): R.proto
+ @${ECHO} Making $@
+ @(charwidth=`echo $(RES) / $(CPI) | bc` ; \
+ sed -e "s/^name [A-Z]*$$/name $@/" \
+ -e "s/^\\([^ ]*\\) [0-9]+ /\\1 $$charwidth /" \
+ -e "s/^spacewidth [0-9]+$$/spacewidth $$charwidth/" \
+ -e "s/^internalname .*$$/internalname $@/" \
+ -e "/^internalname/s/BI/3/" \
+ -e "/^internalname/s/B/2/" \
+ -e "/^internalname/s/I/1/" \
+ -e "/^internalname .*[^ 0-9]/d" \
+ $(.CURDIR)/R.proto >$@)
+
+DESC: DESC.proto
+ @${ECHO} Making $@
+ @sed -e "s/^res .*$$/res $(RES)/" \
+ -e "s/^hor .*$$/hor `echo $(RES) / $(CPI) | bc`/" \
+ -e "s/^vert .*$$/vert `echo $(RES) / $(LPI) | bc`/" \
+ -e "s/^fonts .*$$/fonts `set $(FONTS); echo $$#` $(FONTS)/" \
+ $(.CURDIR)/DESC.proto >$@
diff --git a/gnu/usr.bin/groff/NEWS b/gnu/usr.bin/groff/NEWS
new file mode 100644
index 0000000..f92f475
--- /dev/null
+++ b/gnu/usr.bin/groff/NEWS
@@ -0,0 +1,683 @@
+This file describes recent user-visible changes in groff. Bug fixes
+are not described. There are more details in the man pages.
+
+VERSION 1.09
+============
+
+\(rn will now produce a character that has the traditional metrics,
+and will form corners with \(ul and \(br. This means that it will not
+align properly with \(sr. Instead there's a new character
+\[radicalex] which aligns with \(sr; this is used by eqn for doing
+square roots.
+
+Troff
+-----
+
+The `pso' request allows you to read from the standard output of a
+command.
+
+Grops
+-----
+
+The PSPIC macro has options to allow the horizontal alignment of the
+graphic to be specified.
+
+VERSION 1.08
+============
+
+Troff
+-----
+
+The escape sequence \V[xxx] will interpolate the value of the
+environment variable xxx.
+
+Tbl
+---
+
+The decimalpoint option can be used to specify the character to be
+recognized as the decimal point character in place of the default
+period.
+
+VERSION 1.07
+============
+
+Groff
+-----
+
+The environment variable GROFF_COMMAND_PREFIX can be used to control
+whether groff looks for `gtroff' or `troff' (similarily for the
+preprocessors.)
+
+Troff
+-----
+
+Multilingual hyphenation is supported by new `hpf' and `hla' requests,
+and by a `\n[.hla]' number register. The -H option has been removed.
+Files of hyphenation patterns can have comments.
+
+When a font cannot be found, troff gives a warning (of type `font',
+enabled by default) instead of an error.
+
+There's a new request `trnt' that's like `tr' except that it doesn't
+apply to text transparently throughput into a diversion with \!.
+
+Tbl
+---
+
+There is a `nokeep' option which tells tbl not to use diversions to
+try to keep the table on one page.
+
+Eqn
+---
+
+Setting the parameter `nroff' to a non-zero value causes `ndefine' to
+behave like `define' and `tdefine' to be ignored. This is done by
+eqnrc when the current device is ascii or latin1. There's a `neqn'
+script that just does `eqn -Tascii'.
+
+Grotty
+------
+
+grotty uses whatever page length was specified using the `pl' request
+rather than using the paperlength command in the DESC file. The
+paperwidth command in the DESC file is also ignored.
+
+VERSION 1.06
+============
+
+The programs in groff that have Unix counterparts can now be installed
+without a leading `g' prefix. See the `g' variable in the Makefile.
+
+The g?nroff script simulates the nroff command using groff.
+
+New special characters \(+h, \(+f, \(+p, \(Fn, \(Bq, \(bq, \(aq, \(lz,
+\(an. See groff_char(7).
+
+^L is now a legal input character.
+
+Groff
+-----
+
+The Xps pseudo-device has disappeared. Instead there is a new -X
+option that tells groff to use gxditview instead of the usual
+postprocessor. (So instead of -TXps, use -XTps or just -X if your
+default device is ps.)
+
+The postprocessor to be used for a particular device is now specified
+by a `postpro' command in the DESC file rather than being compiled
+into groff. Similarly the command to be used for printing (with the
+-l option) is now specified by a `print' command in the DESC file.
+
+The groff command no longer specifies eqnchar as an input file for
+eqn. Instead eqn automatically loads a file `eqnrc'. The groff
+command no longer passes the -D option to eqn. Instead eqnrc sets the
+draw_lines parameter.
+
+The groff command no longer tells troff to load a device-specific
+macro file. This is handled instead by the `troffrc' file, which is
+always loaded by troff.
+
+The shell script version of groff has been removed.
+
+Troff
+-----
+
+The `rchar' request removes a character definition established with `char'.
+
+Compatibility mode is disabled and the escape character is set to `\'
+while a character definition is being processed.
+
+The `\#' escape sequence is like `\%' except that the terminating
+newline is ignored.
+
+The `shc' request tells troff which character to insert (instead of
+the default \(hy) when a word is hyphenated at a line break.
+
+A font name of 0 (zero) in the DESC file will cause no font to be
+mounted on the corresponding font position. This is useful for
+arranging that special fonts are mounted on positions on which users
+are not likely explicitly to mount fonts. All groff devices now avoid
+initially mounting fonts on positions 5-9.
+
+The `do' request allows a single request or macro to be interpreted
+with compatibility mode disabled.
+
+troff automatically loads a file `troffrc' before any other input file.
+This can be prevented with the -R option. This file is responsible
+for loading the device-specific macros.
+
+Pic
+---
+
+The -x option has been removed and a -n option has been added. By
+default, pic now assumes that the postprocessor supports groff
+extensions. The -n option tells pic to generate output that works
+with ditroff drivers. The -z option now applies only to TeX mode.
+
+The -p option has been removed. Instead if the -n option is not
+specified, pic generates output that uses \X'ps: ...' if the \n(0p
+register is non-zero and tmac.ps sets this register to 1.
+
+In places where you could 1st or 5th you can now say `i'th or `i+1'th
+(the quotes are required).
+
+Eqn
+---
+
+Eqn now automatically reads a file `eqnrc' from the macro directory.
+This performs the same role that the eqnchar files used to. This can
+be prevented by the -R option.
+
+Setting the draw_lines parameter to a non-zero value causes lines to
+be drawn using \D rather than \l. The -D option is now obsolete.
+
+`uparrow', `downarrow' and `updownarrow' can be used with `left' and
+`right'.
+
+The amount of extra space added before and after lines containing
+equations can be controlled using the `body_height' and `body_depth'
+parameters.
+
+Grops
+-----
+
+Font description files have been regenerated from newer AFM files.
+You can get access to the additional characters present in the text
+fonts in newer PostScript printers by using -mpsnew.
+
+The default value of the -b option is specified by a `broken' command
+in the DESC file.
+
+With the -g option, grops will generate PostScript code that guesses
+the page height. This allows documents to be printed on both letter
+(8.5x11) and A4 paper without change.
+
+Grodvi
+------
+
+ISO Latin-1 characters are available with -Tdvi. Format groff_char(7)
+with groff -Tdvi for more information.
+
+Grotty
+------
+
+The -mtty-char macros contain additional character definitions for
+use with grotty.
+
+Macros
+------
+
+In previous releases the groff -me macros treated the $r and $R number
+registers in a way that was incompatible with the BSD -me macros. The
+reason for this was that the approach used by the BSD -me macros does
+not work with low resolution devices such as -TX75 and -TX100.
+However, this caused problems with existing -me documents. In this
+release, the vertical spacing is controlled by the $v and $V registers
+which have the same meaning as $r and $R in earlier groff releases.
+In addition, if the $r or $R register is set to a value that would be
+correct for for the BSD -me macros and a low resolution device is not
+being used, then an appropriate value for the $v or $V register will
+be derived from the $r or $R register.
+
+The groff -me macros work with -C and (I think) with Unix troff.
+
+For backward compatibility with BSD -me, the \*{ and \*} strings are
+also available as \*[ and \*]. Of course, \*[ will only be usable
+with -C.
+
+The \*T string has been deleted. Use \*(Tm instead.
+
+Xditview
+--------
+
+The `n', Space and Return keys are bound to the Next Page action. The
+`p', BackSpace and Delete keys are bound to the Previous Page action.
+The `q' key is bound to the Quit action.
+
+The `r' key is bound to a rerasterize action that reruns groff, and
+redisplays the current page.
+
+VERSION 1.05
+============
+
+Pic
+---
+
+There is a alternative assignment operator `:=' which interacts
+differently with blocks.
+
+There is a new command `command', which allows the values of variables
+to be passed through to troff or TeX.
+
+The `print' command now accepts multiple arguments.
+
+String comparison expressions (using `==' or `!=') are allowed in more
+contexts.
+
+Grotty
+------
+
+Horizontal and vertical lines drawn with \D'l ...' will be rendered
+using -, | and + characters. This is intended to give reasonable
+results with boxed tables. It won't work well with pic.
+
+Macros
+------
+
+The -mdoc macros have been upgraded to the version in the second
+Berkeley networking release. This version is not completely
+compatible with earlier versions; the old version is still available
+as -mdoc.old. The grog script has been enhanced so that it can
+usually determine whether a document requires the old or new versions.
+
+With -TX75, -TX100 and -TXps, the PSPIC macro will produce a box
+around where the picture would appear with -Tps.
+
+VERSION 1.04
+============
+
+An implementation of the -mm macros is included.
+
+The directory in which temporary files are created can be controlled
+by setting the GROFF_TMPDIR or TMPDIR environment variables.
+
+Pic
+---
+
+Some MS-DOS support (see pic/make-dos-dist).
+
+Grops
+-----
+
+There are two new \X commands (\X'ps: invis' and \X'ps: endinvis')
+which make it possible to have substitute characters that are
+displayed when previewing with -TXps but ignored when printing with
+grops.
+
+Xditview
+--------
+
+Support for scalable fonts.
+
+VERSION 1.03
+============
+
+No changes other than bug fixes.
+
+VERSION 1.02
+============
+
+There is an implementation of refer and associated programs. groff -R
+preprocesses with grefer; no mechanism is provided for passing
+arguments to grefer because most grefer options have equivalent
+commands which can be included in the file. grog also supports refer.
+
+There is an alternative perl implementation of the grog script.
+
+The code field in lines in the charset section of font description
+files is now allowed to contain an arbitrary integer (previously it
+was required to lie between 0 and 255). Currently grops and grodvi
+use only the low order 8 bits of the value. Grodvi will use the
+complete value; however, this is unlikely to be useful with
+traditional TeX tools (.tfm files only allow 8 bit character codes.)
+
+Left and right double quotes can be obtained with \(lq and \(rq
+respectively.
+
+There is a new program called pfbtops which translates PostScript
+fonts in pfb format to ASCII.
+
+A slightly modified version of the Berkeley tmac.doc is included.
+
+Troff
+-----
+
+In long escape names the closing ] is now required to be at the same
+input level as the opening [.
+
+The \A'S' escape sequence returns 1 or 0 according as S is or is not
+suitable for use as a name.
+
+\~ produces an unbreakable space that can be stretched when the line
+is adjusted.
+
+The `mso' request is like the `so' request except that it searches for
+the file in the same directories in which tmac.X is searched for when
+the -mX option is given.
+
+The escape sequence `\R' is similar to the `nr' request.
+
+Eqn
+---
+
+A new `special' primitive allows you to add new types of unary
+constructs by writing a troff macro.
+
+Pic
+---
+
+The implementation no longer uses gperf.
+
+Grops
+-----
+
+The compile-time -DBROKEN_SPOOLER option has been replaced by a
+BROKEN_SPOOLER_FLAGS option. This allows more precise control over
+how grops should workaround broken spoolers and previewers. There is
+a new -b option that can change this at run-time.
+
+Grops now generates PostScript that complies with version 3.0 of the
+Document Structuring Convention.
+
+The resource management component of grops (the part that deals with
+imported documents and downloadable fonts) has been rewritten and now
+supports version 3.0 of the Document Structuring Conventions. The
+%%DocumentFonts comment is no longer supported; you must use the
+%%Document{Needed,Supplied}{Fonts,Resources} comments instead
+(or as well.)
+
+tmac.psatk contains some macros that support the mechanism used by the
+Andrew Toolkit for including PostScript graphics in troff documents.
+
+Xditview
+--------
+
+Parts of xditview have been rewritten so that it can be used with the
+output of gtroff -Tps. groff -TXps will run gtroff -Tps with
+gxditview.
+
+There is a new menu entry `Print' which brings up a dialog box for
+specifying a command with which the file being previewed should be
+printed.
+
+Xditview now uses imake.
+
+VERSION 1.01
+============
+
+The groff command now understands the gtroff `-a' and `-i' options.
+
+With the `m' and `n' scale indicators, the scale factor is rounded
+horizontally before being applied. This makes (almost) no difference
+for devices with `hor' equal to 1, but it makes groff with -Tascii or
+-Tlatin1 behave more like nroff in its treatment of these scale
+indicators. Accordingly tmac.tty now calls the `nroff' request so
+that the `n' condition will be true.
+
+The device-specific macros (tmac.ps, tmac.dvi, tmac.tty and tmac.X)
+have been made to work at least somewhat with -C. In particular the
+special characters defined by these macros now work with -C.
+
+groff -Tdvi -p will now pass pic the -x flag; this will enable filling
+of arrowheads and boxes, provided that your dvi driver supports the
+latest version of the tpic specials.
+
+Eqn
+---
+
+There is a new `-N' option that tells eqn not to allow newlines in
+delimiters. This allows eqn to recover better from missing closing
+delimiters. The groff command will pass on a `-N' option to eqn.
+
+Grops
+-----
+
+You can now use psfig with grops. See the file ps/psfig.diff. I do
+not recommend using psfig for new documents.
+
+The command \X'ps: file F' is similar to \X'ps: exec ...' except that
+the PostScript code is read from the file F instead of being contained
+within the \X command. This was added to support psfig.
+
+Grodvi
+------
+
+There are font files HB and HI corresponding to cmsssbx10 and cmssi10.
+
+Macros
+------
+
+The groff -me macros now work with the -C option. As a result, they
+may also work with Unix nroff/troff.
+
+In -me, the $r and $R number registers now contain the line spacing as
+a percentage of the pointsize expressed in units (normally about 120).
+The previous definition was useless with low resolution devices such
+as X75 and X100.
+
+VERSION 1.00
+============
+
+A -ms-like macro-package is now included.
+
+The name for the Icelandic lowercase eth character has been changed
+from \(-d to \(Sd.
+
+Troff
+-----
+
+There is a new request `nroff', which makes the `n' built-in condition
+true and the `t' built-in condition false; also a new request `troff'
+which undoes the effect of the `nroff' request. This is intended only
+for backward compatibility: it is usually better to test \n(.H or
+\n(.V or to use the `c' built-in condition.
+
+The \R escape sequence has been deleted. Use \E instead.
+
+There are `break' and `continue' requests for use with the `while'
+request.
+
+There is a request `hym' that can ensure that when the current
+adjustment mode is not `b' a line will not be hyphenated if it is no
+more than a given amount short, and a request `hys' that can ensure
+that when the current adjustment mode is `b' a line will not be
+hyphenated if it can be justified by adding no more than a given
+amount of extra space to each word space.
+
+There is a request `rj' similar to `ce' that right justifies lines.
+
+A warning of type `space' will be given when a call is made to an
+undefined request or macro with a name longer than two characters, and
+the first two characters of the name make a name that is defined.
+This is intended to find places where a space has been omitted been a
+request or macro and its argument. This type of warning is enabled by
+default.
+
+Pic
+---
+
+A comma is permitted between the arguments to the `reset' command.
+
+For use with TeX, there is a new `-c' option that makes gpic treat
+lines beginning with `.' in a way that is more compatible with tpic
+(but ugly).
+
+Eqn
+---
+
+It is no longer necessary to add `space 0' at the beginning of
+complicated equations inside pictures.
+
+`prime' is now treated as an ordinary character, as in Unix eqn. The
+previous behaviour of `prime' as an operator can now be obtained using
+`opprime'.
+
+Xditview
+--------
+
+There are two new devices X75-12 and X100-12 which are the same as X75
+and X100 except that they are optimized for documents that use mostly
+12 point text.
+
+VERSION 0.6
+===========
+
+The installation process has been refined to make it easy for you to
+share groff with someone who has the same type of machine as you but
+does not have a C++ compiler. See the end of the INSTALL file for
+details.
+
+There is a man page for the tfmtodit program which explains how to use
+your own fonts with groff -Tdvi.
+
+There is a man page for afmtodit which explains how to use your own
+PostScript fonts with groff -Tps.
+
+The \N escape sequence is now fully supported. It can now be used to
+access any character in a font by its output code, even if it doesn't
+have a groff name. This is made possible by a convention in the font
+files that a character name of `---' refers to an unnamed character.
+The drivers now all support the `N' command required for this. The font
+description files have been updated to include unnamed characters.
+
+The `x' command in font description files has been removed: instead
+any unknown commands are automatically made available to the drivers.
+If you constructed your own font files with an earlier version of
+tfmtodit or afmtodit, you must construct them again using the current
+version.
+
+Characters between 0200 and 0237 octal are no longer legal input
+characters. Note that these are not used in ISO 8859.
+
+A command called `grog' has been added, similar to the `doctype'
+command described in Kernighan and Pike.
+
+Groff
+-----
+
+The groff command has some new options: -V prints the pipeline
+instead of executing it; -P passes an argument to the postprocessor,
+-L passes an argument to the spooler.
+
+There is a C++ implementation of the groff command. This handles some
+things slightly better than the shell script. In particular, it can
+correctly handle arguments containing characters that have a special
+meaning to the shell; it can give an error message when child
+processes other than the last in the pipeline terminate abnormally;
+its exit status can take account of the exit statuses of all its child
+processes; it is a little more efficient; when geqn is used, it
+searches for the eqnchar file in the same way that font metric files
+are searched for, rather than expecting to find it in one particular
+directory.
+
+Gtroff
+------
+
+There is font translation feature: For example, you can tell gtroff to
+use font `HR' whenever font `H' is requested with the line
+ .ftr H HR
+This would be useful for a document that uses `H' to refer to
+Helvetica.
+
+There are some new number registers: `.kern' contains the current kern
+mode, `.lg' the current ligature mode, `.x' the major version number,
+`.y' the minor version number, `.ce' the number of lines to be
+centered in the current environment, `.trunc' the amount of vertical
+space truncated by the most recently sprung vertical position trap,
+`.ne' the amount of vertical space needed in the last `ne' request
+that caused a vertical position trap to be sprung.
+
+The `cf' request now behaves sensibly in a diversion. If used in a
+diversion, it will now arrange for the file to be copied to the output
+when the diversion is reread.
+
+There is a new request `trf' (transparent file) similar to `cf', but
+more like `\!'.
+
+There is a new escape sequence `\Y[xxx]', roughly equivalent to
+`\X'\*[xxx]'', except that the contents of string or macro xxx are not
+interpreted, and xxx may contain newlines. This requires an output
+format extension; the drivers have been modified to understand this.
+Grops has also been modified to cope with newlines in the arguments to
+\X commands; grops has a new \X command mdef, which is like def except
+that it has a first argument giving the number of definitions.
+
+There is a new warning category `escape' which warns about unknown
+escape sequences.
+
+The `fp' request now takes an optional third argument giving the external
+name of the font.
+
+The `\_' character is now automatically translated to `\(ul' as in troff.
+
+The environment variable `GROFF_HYPHEN' gives the name of the file
+containing the hyphenation patterns.
+
+There is a `\C'xxx'' escape sequence equivalent to `\[xxx]'.
+
+Characters ", ', ), ], *, \(dg are now initially transparent for the purposes
+of end of sentence recognition.
+
+There is an anti-recursion feature in the `char' request, so you can
+say `.char \(bu \s+2\(bu\s-2'.
+
+The limit on the number of font positions has been removed.
+Accordingly `\n[.fp]' never returns 0.
+
+The restriction on the number of numbered environments has been removed.
+
+There is a new escape sequence `\E' that makes it possible to
+guarantee that an escape sequence won't get interpreted in copy-mode.
+The `\R' escape sequence is accordingly now deprecated.
+
+Gpic
+----
+
+Arguments of the form `X anything X' (in the `copy thru', `sh', `for',
+`if' and `define' constructs) can now be of the form `{ anything }'.
+
+If the `linethick' variable is negative (as it now is initially),
+lines will be drawn with a thickness proportional to the current point
+size.
+
+The `rand' function now takes no arguments and returns a number between
+0 and 1. The old syntax is still supported.
+
+`^' can be used in expressions to indicate exponentiation.
+
+In the `for' construct the argument to the by clause can be prefixed
+by `*' to indicate that the increment is multiplicative.
+
+A bare expression may be used as an attribute. If the current
+direction is `dir', then an attribute `expr' is equivalent to
+`dir expr'
+
+There is a `sprintf' construct that allows numbers to be formatted and used
+wherever a quoted string can be used.
+
+The height of a text object without an explicit height attribute is
+the number of text strings associated with the object times the value
+of the `textht' variable.
+
+The maximum height and width of a picture is controlled by the
+`maxpswid' and `maxpsht' variables.
+
+Gtbl
+----
+
+Gtbl can now handle gracefully the situation where the `ce' request
+has been applied to a table.
+
+Geqn
+----
+
+The `ifdef' primitive has been generalized.
+
+A tilde accent can be put underneath a box using `utilde'. This
+defined using a general `uaccent' primitive.
+
+Grops
+-----
+
+There is a new PostScript font downloading scheme which handles font
+downloading for imported illustrations. Previously, the name of the
+file containing the font was given in the `x download' line in the
+groff font metric file. Now, there is a `download' file which says
+for each PostScript font name which file contains that font. Grops
+can also now handle inter-font dependencies, where one downloadable
+font depends on some other (possibly downloadable) font.
+
+The `T' font has been removed. The characters it used to provide are
+now provided by `char' definitions in tmac.ps. TSymbol.ps has also
+been removed, and the tweaks it provided are now provided by `char'
+definitions.
diff --git a/gnu/usr.bin/groff/PROBLEMS b/gnu/usr.bin/groff/PROBLEMS
new file mode 100644
index 0000000..feb2f88
--- /dev/null
+++ b/gnu/usr.bin/groff/PROBLEMS
@@ -0,0 +1,544 @@
+This file describes various problems that have been encountered in
+compiling, installing and running groff. Suggestions for additions or
+other improvements to this file are welcome.
+
+* I get lots of `numeric overflow' error messages whenever I run
+groff; I compiled groff with AT&T C++ 2.0 with an ANSI C compiler.
+
+Make sure -DCFRONT_ANSI_BUG is included in DEFINES in the top-level
+Makefile. If that doesn't solve the problem, define INT_MIN as
+-INT_MAX in libgroff/lib.h.
+
+* I get errors when I try to compile groff with Sun C++.
+
+Groff requires header files that are moderately compatible with AT&T
+C++ and ANSI C. With some versions of Sun C++, the supplied header
+files need some of the following changes to meet this requirement:
+<string.h> must declare the mem* functions, (just add `#include
+<memory.h>' to <string.h>); the first argument to fopen and freopen
+should be declared as `const char *'; the first argument to fread
+should be declared as `void *'; the first argument to fwrite should be
+declared as `const void *'; malloc should be declared to return `void
+*'; in <alloca.h>, the declaration `extern "C" { void
+*__builtin_alloca(int); }' should be added; declarations of getopt(),
+optarg, optind and opterr should be added to <stdlib.h>; in
+<sys/signal.h> the return type and the second argument type of
+signal() should be changed to be `void (*)(int)'.
+
+You can either change them in place, or copy them to some other
+directory and include that directory with a -I option.
+
+* I get errors when I try to compile groff with DEC C++.
+
+Fix the declaration of write() in <unistd.h> so that the second
+argument is a const char *. Fix the declaration of open() in
+<sys/file.h> so that the first argument is a const char *.
+
+* On Ultrix, the make stops with the message
+
+ *** Error code 1
+
+ Stop.
+
+for no apparent reason.
+
+Use GNU make.
+
+* I'm having problems compiling groff on 386BSD 0.1.
+
+If you're using ash as /bin/sh, you'll need the following patch.
+
+*** gendef.sh.org Sun Jun 30 13:30:36 1991
+--- gendef.sh Sun Feb 28 10:23:49 1993
+***************
+*** 3,9 ****
+ file=$1
+ shift
+
+! defs="#define $1"
+ shift
+ for def
+ do
+--- 3,10 ----
+ file=$1
+ shift
+
+! x=$1
+! defs="#define $x"
+ shift
+ for def
+ do
+
+You'll also need to change dirnamemax.c so that it doesn't use
+pathconf().
+
+* While compiling on Xenix, ranlib libgroff.a fails.
+
+The system ranlib can't handle externals longer than 40 characters.
+Use the ranlib included in demon.co.uk:/pub/xenix/g++-1.40.3a.v1
+instead.
+
+* Groff can't handle my troff document. It works fine with AT&T troff.
+
+Read the section on incompatibilities in gtroff(1). Try using the -C
+option. Alternatively there's the sed script in tmac/fixmacros.sed
+which will attempt to edit a file of macros so that it can be used
+with groff without the -C flag.
+
+* groff -Tdvi produces dvi files that use fonts at weird magnifications.
+
+Yes, it does. You may need to compile fonts with Metafont at these
+magnifications. The CompileFonts script in the devdvi/generate
+directory may help you to do this. (It will take a *long* time.)
+
+* pic output is not centered horizontally; pictures sometimes run off
+the bottom of the page.
+
+The macro package you are using is not supplying appropriate definitions
+of PS and PE. Give groff a -mpic option.
+
+* I'm having problems including PostScript illustrations using the PSPIC
+macro.
+
+A PostScript document must meet three requirements in order to be
+included with the PSPIC macro: it must comply with the Adobe Document
+Structuring Conventions; it must contain a BoundingBox line; it must
+be ``well-behaved''. The BoundingBox line should be of the form:
+
+ %%BoundingBox: llx lly urx ury
+
+where llx, lly, urx, ury are the coordinates of the lower left x,
+lower left y, upper right x, upper right y of the bounding box of
+marks on the page expressed as integers in the default PostScript
+coordinate system (72 units per inch, origin at bottom left corner).
+A useful tactic is to print out the illustration by itself (you may
+need to add a `showpage' at the end), and physically measure the
+bounding box. For more detail on these requirements, read the
+specification of Encapsulated PostScript format. (This is available
+from the Adobe file server; send a message with a body of `help' to
+ps-file-server@adobe.com.)
+
+* I've configured groff for A4 paper, but gtroff still seems to think
+that the length of a page (as returned by \n(.p) is 11 inches.
+
+This is intentional. The PAGE option is used only by grops. For
+compatibility with ditroff, the default page length in gtroff is
+always 11 inches. The page length can be changed with the `pl'
+request.
+
+* Groff doesn't use the font names I'm used to.
+
+Use the `ftr' request. See gtroff(1).
+
+* I get errors using the Unix -ms macros with groff -e -C.
+
+Apply this change:
+
+*** /usr/lib/ms/ms.eqn Tue Apr 25 02:14:28 1989
+--- ms.eqn Sun Nov 11 10:33:59 1990
+***************
+*** 22,29 ****
+ ..
+ . \" EN - end of a displayed equation
+ .de EN
+! .if !\\*(10 .br
+ .di
+ .rm EZ
+ .nr ZN \\n(dn
+ .if \\n(ZN>0 .if \\n(YE=0 .LP
+--- 22,30 ----
+ ..
+ . \" EN - end of a displayed equation
+ .de EN
+! .if \\n(.k>0 .br
+ .di
++ .ds 10 \\*(EZ\\
+ .rm EZ
+ .nr ZN \\n(dn
+ .if \\n(ZN>0 .if \\n(YE=0 .LP
+
+
+* gpic doesn't accept the syntax `chop N M' for chopping both ends of a
+line.
+
+The correct syntax is `chop N chop M'.
+
+* With gpic -t, when I print `line ->; box' using a dvi to ps
+program, the arrow head sticks through into the inside of the box.
+
+The dvi to ps program should be modified to set the line cap and
+line join parameters to 1 while printing tpic specials.
+
+* When I print the output groff -Tps, the output is always shifted up
+by about 0.7 inches; I'm using 8.5x11 inch paper.
+
+Make sure that PAGE is defined to be `letter' in the top-level
+Makefile.
+
+* When I try to print the output of groff -Tps, I get no output at all
+from the printer, and the log file shows the error
+%%[ error: undefined; offendingcommand: BP ]%%
+I using TranScript spooling software.
+
+This is a bug in the page reversal filter in early versions of
+TranScript. Change the `broken' parameter in
+/usr/local/lib/groff/font/devps/DESC to 7.
+
+* When I preview groff -Tps output using the Sun OpenWindows 2.0 pageview
+program, all the pages are displayed on top of each other.
+
+This is a defect in pageview. Change the `broken' parameter in
+/usr/local/lib/groff/font/devps/DESC to 2.
+
+* With groff -TX75, -TX100or -X, I can only view the first page.
+
+The left mouse button brings up a menu that allows you to view other
+pages.
+
+* When I print the output of groff -Tdvi, I just get a black dot in
+upper left corner.
+
+Some dvi drivers (notably early versions of xtex) do not correctly
+handle dvi files that use a resolution different from that used by dvi
+files produced by TeX. Try getting a more up to date driver.
+
+* I get lots of errors when I use groff with the AT&T -mm macros.
+
+The AT&T -mm macros need a few changes to work with groff; `make
+install.dwbmm' will copy your -mm macros to groff's macro directory
+and make the necessary changes. You may need to edit the commands for
+the install.mm target in the Makefile. Alternatively use the groff
+-mm macros.
+
+* gtroff doesn't understand lines like `.ce99' with no space between
+the name of the request or macro and the arguments.
+
+Gtroff requires a space between macro or request and its arguments
+because it allows the use of long names for macros and requests. You
+can use the -C option or the `cp' request to put gtroff into a
+compatibility mode in which it is not possible to use long names for
+macros but in which no space is required between macros and their
+arguments. The use of compatibility mode is strongly discouraged.
+
+* gtroff gives warnings about lines like
+ .ev \" a comment
+(with a tab after the .ev).
+
+A tab character cannot be used as a substitute for a space character
+(except in one case: between a control character at the beginning of a
+line and the name of a macro or request). For example, in Unix troff
+ .ps \" restore the previous point size
+(with a tab after the .ps) will NOT restore the previous point-size;
+instead it will be silently ignored. Since this is very likely to be
+an error, gtroff can give a warning about it. If you want to align
+comments, you can do it like this:
+ .ev\" \" a comment
+
+* I don't like the page headers and footers produced by groff -man.
+
+There seem to be many different styles of page header and footer
+produced by different versions of the -man macros. You will need to
+modify macros/tmac.an to suit your personal taste. For example, if
+you want the center of the page header to say
+ UNIX Programmer's Manual
+you will need to change the line
+ .el .ds an-extra3 \"UNIX Programmer's Manual
+to
+ .el .ds an-extra3 UNIX Programmer's Manual
+
+* While formatting a manual page, groff complains about not being able to
+break lines. The problem seems to be caused by a line like:
+ .TP \w'label'+2
+
+The -man documentation says that the default scale indicator for TP
+macro is `n'. The groff -man macros implement this correctly, so that
+the argument will be evaluated as if it were
+ \w'label'n+2n
+The Unix -man macros don't implement this correctly (probably because
+it's hard to do in Unix troff); they just append `n' to the entire
+argument, so that it will be evaluated as if it were
+ \w'label'u+2n
+The solution is to fix the manual page:
+ .TP \w'label'u+2
+
+* I'm having problems formatting Ultrix man pages with groff -man.
+
+The Ultrix man pages use a number of non-standard extensions to the
+Unix man macros. One solution is to use the Ultrix -man macros with
+groff. Rename /usr/local/lib/groff/tmac/tmac.an to
+/usr/local/lib/groff/tmac/tmac.an.gnu, copy /usr/lib/tmac/tmac.an to
+/usr/local/lib/groff/tmac/tmac.an and apply the following patch (from
+Frank Wortner):
+
+*** /usr/local/lib/groff/tmac/tmac.an Wed Sep 9 12:29:28 1992
+--- /usr/lib/tmac/tmac.an Fri Jul 24 19:58:19 1992
+***************
+*** 489,495 ****
+ . \" make special case of shift out of italic
+ .de }S
+ .ds ]F
+! .if \\$12 .if !\\$5 .ds ]F \^
+ .ie !\\$4 .}S \\$2 \\$1 "\\$3\f\\$1\\$4\\*(]F" "\\$5" "\\$6" "\\$7" "\\$8" "\\$9"
+ .el \\$3
+ .}f
+--- 489,495 ----
+ . \" make special case of shift out of italic
+ .de }S
+ .ds ]F
+! .if \\$12 .if !\\$5 .ds ]F\^
+ .ie !\\$4 .}S \\$2 \\$1 "\\$3\f\\$1\\$4\\*(]F" "\\$5" "\\$6" "\\$7" "\\$8" "\\$9"
+ .el \\$3
+ .}f
+
+Another possible solution is to install tmac/man.ultrix as
+/usr/local/lib/groff/tmac/man.local.
+
+* I'm having problems formatting HP-UX 9.0 man pages with groff -man.
+
+Rename /usr/local/lib/groff/tmac/tmac.an to (for example)
+/usr/local/lib/groff/tmac/tmac.gan, copy HP's tmac.an into
+/usr/local/lib/groff/tmac/tmac.an, and either put `.cp 1' at the
+beginning or filter it (and any files it .so's) through
+tmac/fixmacros.sed.
+
+* I'm having problems formatting man pages produced by the perl
+wrapman script.
+
+Some versions of wrapman have a superfluous blank line before the .TH
+line. This must be deleted. Then either use groff -C, or apply the
+following patch:
+
+*** wrapman.~2~ Sun Jan 19 12:10:24 1992
+--- wrapman Fri Apr 2 12:12:57 1993
+***************
+*** 35,41 ****
+ $line1 .= <IN> if $line1 =~ /eval/;
+ $line1 .= <IN> if $line1 =~ /argv/;
+ $line2 = <IN>;
+! next if $line2 eq "'di';\n";
+
+ # Pull the old switcheroo.
+
+--- 35,41 ----
+ $line1 .= <IN> if $line1 =~ /eval/;
+ $line1 .= <IN> if $line1 =~ /argv/;
+ $line2 = <IN>;
+! next if $line2 eq "'di ';\n";
+
+ # Pull the old switcheroo.
+
+***************
+*** 49,56 ****
+
+ print OUT $line1;
+ print OUT <<EOF;
+! 'di';
+! 'ig00';
+ #
+ # $header
+ #
+--- 49,57 ----
+
+ print OUT $line1;
+ print OUT <<EOF;
+! 'di ';
+! 'ds 00 \\"';
+! 'ig 00 ';
+ #
+ # $header
+ #
+***************
+*** 72,85 ****
+
+ # These next few lines are legal in both Perl and nroff.
+
+! $null.00; # finish .ig
+
+ 'di \\" finish diversion--previous line must be blank
+ .nr nl 0-1 \\" fake up transition to first page again
+ .nr % 0 \\" start at page 1
+! '; __END__ ##### From here on it's a standard manual page #####
+ .TH $PROG 1 "$month $mday, 19$year"
+- .AT 3
+ .SH NAME
+ $prog \\- whatever
+ .SH SYNOPSIS
+--- 73,85 ----
+
+ # These next few lines are legal in both Perl and nroff.
+
+! $null.00 ; # finish .ig
+
+ 'di \\" finish diversion--previous line must be blank
+ .nr nl 0-1 \\" fake up transition to first page again
+ .nr % 0 \\" start at page 1
+! .\\"'; __END__ ##### From here on it's a standard manual page #####
+ .TH $PROG 1 "$month $mday, 19$year"
+ .SH NAME
+ $prog \\- whatever
+ .SH SYNOPSIS
+
+
+* When I preview documents using -TX75 or -TX100, the layout is not the same
+as when I print the document with -Tps: the line and page breaks come
+in different places.
+
+Use groff -X -Tps.
+
+* When I try to run gxditview, I get the error:
+Error: Widget viewport has zero width and/or height
+
+This error means you haven't correctly installed the application
+defaults file, GXditview.ad; ``make install'' does this for you
+automatically, so either you didn't do ``make install'', or you don't
+have imake configured correctly.
+
+* groff uses up an enormous amount of memory processing large files.
+I'm using 386BSD 0.1.
+
+386BSD includes an old version of g++, 1.39, which has a bug that
+causes a major memory leak in gtroff. Apply the following fix to g++
+and recompile groff:
+
+*** cplus-decl.c.~1~ Mon Aug 6 05:28:59 1990
+--- cplus-decl.c Wed Jun 5 08:55:04 1991
+***************
+*** 7951,7961 ****
+
+ /* At the end, call delete if that's what's requested. */
+ if (TREE_GETS_DELETE (current_class_type))
+ exprstmt = build_method_call (build1 (NOP_EXPR, TYPE_POINTER_TO (current_class_type), error_mark_node),
+ get_identifier (OPERATOR_DELETE_FORMAT),
+! build_tree_list (NULL_TREE, integer_zero_node),
+ NULL_TREE, LOOKUP_NORMAL);
+ else if (TYPE_USES_VIRTUAL_BASECLASSES (current_class_type))
+ exprstmt = build_x_delete (ptr_type_node, current_class_decl, 0);
+ else
+ exprstmt = 0;
+--- 7951,7961 ----
+
+ /* At the end, call delete if that's what's requested. */
+ if (TREE_GETS_DELETE (current_class_type))
+ exprstmt = build_method_call (build1 (NOP_EXPR, TYPE_POINTER_TO (current_class_type), error_mark_node),
+ get_identifier (OPERATOR_DELETE_FORMAT),
+! build_tree_list (NULL_TREE, current_class_decl),
+ NULL_TREE, LOOKUP_NORMAL);
+ else if (TYPE_USES_VIRTUAL_BASECLASSES (current_class_type))
+ exprstmt = build_x_delete (ptr_type_node, current_class_decl, 0);
+ else
+ exprstmt = 0;
+
+* Where can I get grap?
+
+Grap is not freely available, but there is a nawk script implementing
+an extended subset of grap available for ftp as
+ftp.informatik.uni-rostock.de:/pub/local/software/prag-1.0.shar.gz.
+
+* How can I use groff with a Laserjet printer?
+
+You have at least 3 options:
+
+- use groff -Tps with GNU Ghostscript;
+
+- use groff -Tdvi with a TeX .dvi to Laserjet driver;
+
+- use groff with the Laserjet driver in Chris Lewis' psroff package
+(available for ftp from:
+ftp.uunet.ca:/distrib/chris_lewis/psroff3.0pl17).
+
+* Groff seems to generate level 3 Postscript, but my printer is only a
+level 1 or 2 PostScript printer.
+
+In fact groff generates only level 1 PostScript. The `%!PS-Adobe-3.0'
+comment at the beginning of PostScript output generated by groff
+indicates that the file conforms to version 3.0 of the Adobe Document
+Structuring Conventions. The output generated by groff should be
+printable on any PostScript printer. Problems with groff output's not
+printing are most often caused by the spooling system.
+
+* The \n(st and \n(sb registers don't seem to work. I thought \w set
+them to the height and depth of its argument, but the registers always
+seem to be 0.
+
+\n(st and \n(sb aren't supposed to give the height and depth of the
+string rather they give the minimum and maximum vertical displacement
+of the baseline. For example for \v'2u'\v'-3u', \n(st will be 1 and
+\n(sb will be -2. The height and depth of the string is available in
+the \n[rst] and \n[rsb] registers: these are groff extensions.
+
+* On an SGI system, how can I make the man command use groff?
+
+From David Hinds <dhinds@allegro.stanford.edu> (some of these steps
+are unnecessary if you install with the `g' Makefile variable defined
+as empty):
+
+Create a script called 'eqn':
+
+ > #!/bin/sh
+ > if [ ${1:-""} = /usr/pub/eqnchar ] ; then shift ; fi
+ > geqn $*
+
+and a script called 'neqn':
+
+ > #!/bin/sh
+ > if [ ${1:-""} = /usr/pub/eqnchar ] ; then shift ; fi
+ > geqn -Tascii $*
+
+and do:
+
+ > ln -s gnroff nroff
+
+and edit the end of the gnroff script to be:
+
+ > rest=`echo ${1+"$@"} | sed -e 's+/usr/lib/tmac+/usr/local/lib/groff/tmac+'`
+ > exec groff -Wall -mtty-char $T $opts $rest
+
+To get PostScript output from 'man -t', you also need to create a
+'psroff' script similar to 'nroff'. Here are the context diffs:
+
+*** /usr/local/bin/nroff Sat Feb 13 15:51:09 1993
+--- /usr/local/bin/psroff Sat Feb 13 17:45:46 1993
+***************
+*** 1,8 ****
+ #!/bin/sh
+! # Emulate nroff with groff.
+
+ prog="$0"
+! T=-Tascii
+ opts=
+
+ for i
+--- 1,8 ----
+ #!/bin/sh
+! # Emulate psroff with groff.
+
+ prog="$0"
+! T=-Tps
+ opts=
+
+ for i
+***************
+*** 25,30 ****
+--- 25,33 ----
+ -Tascii|-Tlatin1)
+ T=$1
+ ;;
++ -t)
++ # ignore -- default is send to stdout
++ ;;
+ -T*)
+ # ignore other devices
+ ;;
+***************
+*** 49,53 ****
+ rest=`echo ${1+"$@"} | sed -e 's+/usr/lib/tmac+/usr/local/lib/groff/tmac+'`
+
+ # This shell script is intended for use with man, so warnings are
+ # probably not wanted. Also load nroff-style character definitions.
+! exec groff -Wall -mtty-char $T $opts $rest
+--- 52,56 ----
+ rest=`echo ${1+"$@"} | sed -e 's+/usr/lib/tmac+/usr/local/lib/groff/tmac+'`
+
+ # This shell script is intended for use with man, so warnings are
+! # probably not wanted.
+! exec groff -Wall $T $opts $rest
diff --git a/gnu/usr.bin/groff/PROJECTS b/gnu/usr.bin/groff/PROJECTS
new file mode 100644
index 0000000..6ba76e2
--- /dev/null
+++ b/gnu/usr.bin/groff/PROJECTS
@@ -0,0 +1,19 @@
+Here are some things that would be useful additions to groff:
+
+ a driver for the HP Laserjet 2 and 3
+
+ grap
+
+ -mv macros (for typesetting viewgraphs and slides)
+
+ a deroff that understands long names
+
+ a page-makeup postprocessor and associated macro package
+ (like pm and -mpm)
+
+ a complete, self-contained manual (trent@cs.pdx.edu is working on this)
+
+If you want to work on one of these, I suggest you contact me first.
+
+James Clark
+jjc@jclark.com
diff --git a/gnu/usr.bin/groff/README b/gnu/usr.bin/groff/README
new file mode 100644
index 0000000..a8982c2
--- /dev/null
+++ b/gnu/usr.bin/groff/README
@@ -0,0 +1,38 @@
+This is the GNU groff document formatting system. The version number
+is given in the file VERSION.
+
+Included in this release are implementations of troff, pic, eqn, tbl,
+refer, the -man macros and the -ms macros, and drivers for PostScript,
+TeX dvi format, and typewriter-like devices. Also included is a
+modified version of the Berkeley -me macros, an enhanced version of
+the X11 xditview previewer, and an implementation of the -mm macros
+contributed by Joergen Haegg (jh@efd.lth.se).
+
+See the file INSTALL for installation instructions. You will require
+a C++ compiler.
+
+The file NEWS describes recent user-visible changes to groff.
+
+Groff is free software. See the file COPYING for copying permission.
+
+The file PROBLEMS describes various problems that have been
+encountered in compiling, installing, and running groff.
+
+For the moment, the documentation assumes that you are already
+familiar with the Unix versions of troff, -man, -ms and the
+preprocessors.
+
+The most recent released version of groff is always available by
+anonymous ftp from prep.ai.mit.edu in the directory pub/gnu.
+
+Please report bugs using the form in the file BUG-REPORT; the idea of
+this is to make sure that I have all the information I need to fix the
+bug. At the very least, read the BUG-REPORT form and make sure that
+you supply all the information that it asks for. Even if you are not
+sure that something is a bug, report it using BUG-REPORT: this will
+enable me to determine whether it really is a bug or not. As well as
+bug reports, I welcome suggestions for improvements to groff (no
+matter how small).
+
+James Clark
+jjc@jclark.com
diff --git a/gnu/usr.bin/groff/TODO b/gnu/usr.bin/groff/TODO
new file mode 100644
index 0000000..7a7d379
--- /dev/null
+++ b/gnu/usr.bin/groff/TODO
@@ -0,0 +1,26 @@
+Provide man.sun implementing .TX.
+
+Improve GROFF_PRINT macro in acgroff.m4.
+
+Guess value for `g' variable.
+
+Guess appropriate value for tmac_m and tmac_s
+(if /usr/lib/tmac/tmac.s or /usr/local/lib/groff/tmac/tmac.s exists
+and is not the groff -ms macros then install as -mgs else install as -ms).
+
+Put all dev* files in a separate subdirectory `font'.
+
+Provide a `check' target.
+
+Provide a `bindist' target.
+
+Implement tmac.bib in terms of tmac.s.
+
+Support long options using GNU getopt.
+
+Catch the following error in -me:
+.(z
+.(l C
+.)z
+
+Arrows for next/previous page from R5 xditview.
diff --git a/gnu/usr.bin/groff/VERSION b/gnu/usr.bin/groff/VERSION
new file mode 100644
index 0000000..799001d
--- /dev/null
+++ b/gnu/usr.bin/groff/VERSION
@@ -0,0 +1 @@
+1.09
diff --git a/gnu/usr.bin/groff/acgroff.m4 b/gnu/usr.bin/groff/acgroff.m4
new file mode 100644
index 0000000..f1a7cd1
--- /dev/null
+++ b/gnu/usr.bin/groff/acgroff.m4
@@ -0,0 +1,403 @@
+dnl Autoconf macros for groff.
+dnl Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
+dnl
+dnl This file is part of groff.
+dnl
+dnl groff is free software; you can redistribute it and/or modify it under
+dnl the terms of the GNU General Public License as published by the Free
+dnl Software Foundation; either version 2, or (at your option) any later
+dnl version.
+dnl
+dnl groff is distributed in the hope that it will be useful, but WITHOUT ANY
+dnl WARRANTY; without even the implied warranty of MERCHANTABILITY or
+dnl FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+dnl for more details.
+dnl
+dnl You should have received a copy of the GNU General Public License along
+dnl with groff; see the file COPYING. If not, write to the Free Software
+dnl Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+dnl
+define(GROFF_EXIT,[rm -f conftest* core; exit 1])dnl
+define(GROFF_PREFIX,[AC_PROVIDE([$0])AC_PREFIX(grops)AC_PREFIX(gcc)])dnl
+define(GROFF_PROG_CCC,
+[AC_PROVIDE([$0])AC_REQUIRE([AC_PROG_CC])dnl
+cc_compile='$CCC conftest.cc -o conftest $CCLIBS $LIBS >/dev/null 2>&1'
+AC_SUBST(CCLIBS)
+if test -z "$CCC"; then
+# See whether the C compiler is also a C++ compiler.
+echo checking if C compiler is also a C++ compiler
+cat <<EOF > conftest.cc
+#ifdef __cplusplus
+ yes
+#endif
+EOF
+$CC -E conftest.cc >conftest.out 2>&1
+if egrep yes conftest.out >/dev/null 2>&1; then
+ CCC="$CC"
+fi
+fi
+AC_PROGRAM_CHECK(CCC,g++,g++,)
+AC_PROGRAM_CHECK(CCC,CC,CC,)
+AC_PROGRAM_CHECK(CCC,cc++,cc++,)
+if test -z "$CCC"; then
+cat <<EOM
+This package requires a C++ compiler, but I couldn't find one.
+Set the environment variable CCC to the name of your C++ compiler.
+EOM
+GROFF_EXIT
+fi
+echo checking that C++ compiler can compile very simple C++ program
+GROFF_CC_TEST_PROGRAM([
+int main() { return 0; }
+],,
+cat <<EOM
+$CCC was unable successfully to compile a very simple C++ program
+(the C++ program was in a file with a suffix of .cc)
+EOM
+GROFF_EXIT
+,)
+echo checking that C++ static constructors and destructors are called
+GROFF_CC_TEST_PROGRAM([
+extern "C" {
+ void _exit(int);
+}
+int i;
+struct A {
+ char dummy;
+ A() { i = 1; }
+ ~A() { if (i == 1) _exit(0); }
+};
+A a;
+int main() { return 1; }
+],,
+cat <<EOM
+$CCC is not installed correctly: static constructors and destructors do not work
+EOM
+GROFF_EXIT
+,)
+GROFF_CC_COMPILE_CHECK([C++ header files],[#include <stdio.h>],
+[fopen(0, 0);],,
+[cat <<\EOF
+Your header files do not appear to support C++.
+I was unable to compile and link a simple C++ program that used a function
+declared in <stdio.h>.
+If you're using a version of gcc/g++ earlier than 2.5,
+you should install libg++.
+EOF
+GROFF_EXIT])])dnl
+define(GROFF_CC_COMPILE_CHECK,
+[AC_PROVIDE([$0])AC_REQUIRE([GROFF_PROG_CCC])echo checking for $1
+cat <<EOF >conftest.cc
+[$2]
+int main() { return 0; } void t() { [$3] }
+EOF
+dnl Don't try to run the program, which would prevent cross-configuring.
+if eval $cc_compile; then
+ ifelse([$4], , :, [$4])
+ifelse([$5], , , [else
+ $5
+])dnl
+fi
+rm -f conftest*])dnl
+dnl
+define(GROFF_CC_TEST_PROGRAM,
+[AC_PROVIDE([$0])AC_REQUIRE([GROFF_PROG_CCC])ifelse([$4], , ,
+[AC_REQUIRE([AC_CROSS_CHECK])if $cross_compiling
+then
+ $4
+else
+])dnl
+cat <<EOF > conftest.cc
+[$1]
+EOF
+rm -f conftest
+eval $cc_compile
+if test -s conftest && (./conftest) 2>/dev/null; then
+ ifelse([$2], , :, [$2])
+ifelse([$3], , , [else
+ $3
+])dnl
+fi
+ifelse([$4], , , fi
+)dnl
+rm -f conftest*])dnl
+dnl
+define(GROFF_PAGE,
+[AC_REQUIRE([GROFF_PREFIX])
+if test -z "$PAGE" && test -r $prefix/lib/groff/font/devps/DESC
+then
+ if grep "^paperlength 841890" \
+ $prefix/lib/groff/font/devps/DESC >/dev/null 2>&1
+ then
+ PAGE=A4
+ else
+ PAGE=letter
+ fi
+fi
+if test -z "$PAGE"
+then
+ dom=`awk '([$]1 == "dom" || [$]1 == "search") { print [$]2; exit}' \
+ /etc/resolv.conf 2>/dev/null`
+
+ if test -z "$dom"
+ then
+ dom=`(domainname) 2>/dev/null | tr -d '+'`
+ if test -z "$dom"
+ then
+ dom=`(hostname) 2>/dev/null | grep '\.'`
+ fi
+ fi
+
+changequote(,)dnl
+ # If the top-level domain is two letters and it's not `us' or `ca'
+ # then they probably use A4 paper.
+ case "$dom" in
+ *.[Uu][Ss]|*.[Cc][Aa]) ;;
+ *.[A-Za-z][A-Za-z]) PAGE=A4 ;;
+ esac
+changequote([,])dnl
+fi
+test -n "$PAGE" || PAGE=letter
+echo guessing $PAGE size paper
+AC_SUBST(PAGE)])dnl
+dnl
+define(GROFF_PERL_PATH,
+[echo checking for perl
+PERLPATH=
+saveifs="$IFS"; IFS="${IFS}:"
+for dir in $PATH; do
+ test -z "$dir" && dir=.
+ if test -f $dir/perl; then
+ PERLPATH="$dir/perl"
+ break
+ fi
+done
+IFS="$saveifs"
+AC_SUBST(PERLPATH)])dnl
+dnl
+define(GROFF_WCOREFLAG,
+[echo checking for w_coredump
+AC_TEST_PROGRAM([
+#include <sys/types.h>
+#include <sys/wait.h>
+main()
+{
+#ifdef WCOREFLAG
+ exit(1);
+#else
+ int i = 0;
+ ((union wait *)&i)->w_coredump = 1;
+ exit(i != 0200);
+#endif
+}
+],AC_DEFINE(WCOREFLAG,0200),,)])dnl
+dnl
+define(GROFF_MMAP,
+[AC_COMPILE_CHECK([mmap],[#include <sys/types.h>
+#include <sys/mman.h>],
+[char *p = mmap(0, 0, PROT_READ, MAP_PRIVATE, 0, 0); munmap(p, 0);],
+AC_DEFINE(HAVE_MMAP))])dnl
+dnl;
+define(GROFF_SYS_SIGLIST,
+[AC_COMPILE_CHECK([sys_siglist],,changequote(,)dnl
+extern char *sys_siglist[]; sys_siglist[0] = 0;,changequote([,])dnl
+AC_DEFINE(HAVE_SYS_SIGLIST))])dnl
+dnl
+define(GROFF_STRUCT_EXCEPTION,
+[AC_COMPILE_CHECK([struct exception],[#include <math.h>],
+[struct exception e;],
+AC_DEFINE(HAVE_STRUCT_EXCEPTION))])dnl
+define(GROFF_COOKIE_BUG,
+[echo checking for gcc/g++ delete bug
+GROFF_CC_TEST_PROGRAM([
+#include <stdlib.h>
+#include <stddef.h>
+
+int testit = 0;
+
+int main()
+{
+ testit = 1;
+ int *p = new int;
+ delete p;
+ testit = 0;
+ return 1;
+}
+
+static unsigned dummy[3];
+
+void *operator new(size_t n)
+{
+ if (testit) {
+ dummy[1] = -(unsigned)(dummy + 2);
+ return dummy + 2;
+ }
+ else
+ return (void *)malloc(n);
+}
+
+void operator delete(void *p)
+{
+ if (testit) {
+ if (p == dummy)
+ exit(0);
+ }
+ else
+ free(p);
+}
+],AC_DEFINE(COOKIE_BUG),,)])dnl
+dnl
+define(GROFF_CFRONT_ANSI_BUG,
+[AC_REQUIRE([GROFF_LIMITS_H])echo checking for cfront ANSI C INT_MIN bug
+GROFF_CC_TEST_PROGRAM([#include <stdlib.h>
+#ifdef HAVE_CC_LIMITS_H
+#include <limits.h>
+#else
+#define INT_MAX 2147483647
+#endif
+
+#undef INT_MIN
+#define INT_MIN (-INT_MAX-1)
+
+int main()
+{
+ int z = 0;
+ return INT_MIN < z;
+}
+],AC_DEFINE(CFRONT_ANSI_BUG),,)])dnl
+dnl
+define(GROFF_ARRAY_DELETE,
+[GROFF_CC_COMPILE_CHECK(new array delete syntax,,
+changequote(,)dnl
+char *p = new char[5]; delete [] p;changequote([,]),
+,AC_DEFINE(ARRAY_DELETE_NEEDS_SIZE))])dnl
+dnl
+define(GROFF_BROKEN_SPOOLER_FLAGS,
+[test -n "${BROKEN_SPOOLER_FLAGS}" || BROKEN_SPOOLER_FLAGS=7
+echo using default value of ${BROKEN_SPOOLER_FLAGS} for grops -b option
+AC_SUBST(BROKEN_SPOOLER_FLAGS)])dnl
+dnl
+define(GROFF_PRINT,
+[if test -z "$PSPRINT"
+then
+ AC_PROGRAMS_CHECK(LPR,lpr)
+ AC_PROGRAMS_CHECK(LP,lp)
+ if test -n "$LPR" && test -n "$LP"
+ then
+ # HP-UX provides an lpr command that emulates lpr using lp,
+ # but it doesn't have lpq; in this case we want to use lp
+ # rather than lpr.
+ AC_PROGRAMS_CHECK(LPQ,lpq)
+ test -n "$LPQ" || LPR=
+ fi
+ if test -n "$LPR"
+ then
+ PSPRINT="$LPR"
+ elif test -n "$LP"
+ then
+ PSPRINT="$LP"
+ fi
+fi
+AC_SUBST(PSPRINT)
+# Figure out DVIPRINT from PSPRINT.
+if test -n "$PSPRINT" && test -z "$DVIPRINT"
+then
+ if test "X$PSPRINT" = "Xlpr"
+ then
+ DVIPRINT="lpr -d"
+ else
+ DVIPRINT="$PSPRINT"
+ fi
+fi
+AC_SUBST(DVIPRINT)])dnl
+define(GROFF_GETOPT,
+[GROFF_CC_COMPILE_CHECK([declaration of getopt in stdlib.h],
+[#include <stdlib.h>
+extern "C" { void getopt(int); }],,,
+AC_DEFINE(STDLIB_H_DECLARES_GETOPT))
+GROFF_CC_COMPILE_CHECK([declaration of getopt in unistd.h],
+[#include <sys/types.h>
+#include <unistd.h>
+extern "C" { void getopt(int); }],,,
+AC_DEFINE(UNISTD_H_DECLARES_GETOPT))
+])dnl
+define(GROFF_PUTENV,
+[GROFF_CC_COMPILE_CHECK([declaration of putenv],
+[#include <stdlib.h>
+extern "C" { void putenv(int); }],,,
+AC_DEFINE(STDLIB_H_DECLARES_PUTENV))])dnl
+define(GROFF_POPEN,
+[GROFF_CC_COMPILE_CHECK([declaration of popen],
+[#include <stdio.h>
+extern "C" { void popen(int); }],,,
+AC_DEFINE(STDIO_H_DECLARES_POPEN))])dnl
+define(GROFF_PCLOSE,
+[GROFF_CC_COMPILE_CHECK([declaration of pclose],
+[#include <stdio.h>
+extern "C" { void pclose(int); }],,,
+AC_DEFINE(STDIO_H_DECLARES_PCLOSE))])dnl
+define(GROFF_ETAGSCCFLAG,
+[echo checking for etags C++ option
+for flag in p C
+do
+ test -z "$ETAGSCCFLAG" || break
+ >conftest.c
+ (etags -$flag -o /dev/null conftest.c >/dev/null 2>&1) 2>/dev/null &&
+ ETAGSCCFLAG="-$flag"
+ rm -f conftest.c
+done
+AC_SUBST(ETAGSCCFLAG)])dnl
+define(GROFF_LIMITS_H,
+[AC_PROVIDE([$0])GROFF_CC_COMPILE_CHECK(['C++ <limits.h>'],
+[#include <limits.h>],
+[int x = INT_MIN; int y = INT_MAX; int z = UCHAR_MAX;],
+AC_DEFINE(HAVE_CC_LIMITS_H))])dnl
+define(GROFF_TRADITIONAL_CPP,
+[GROFF_CC_COMPILE_CHECK([traditional preprocessor],
+[#define name2(a,b) a/**/b],[int name2(foo,bar);],
+AC_DEFINE(TRADITIONAL_CPP))])dnl
+define(GROFF_TIME_T,
+[GROFF_CC_COMPILE_CHECK([time_t],[#include <time.h>],
+[time_t t = time(0); struct tm *p = localtime(&t);],,
+AC_DEFINE(LONG_FOR_TIME_T))])dnl
+define(GROFF_OSFCN_H,
+[GROFF_CC_COMPILE_CHECK(['C++ <osfcn.h>'],[#include <osfcn.h>],
+[read(0, 0, 0); open(0, 0);],AC_DEFINE(HAVE_CC_OSFCN_H))])dnl
+dnl Bison generated parsers have problems with C++ compilers other than g++.
+dnl So byacc is preferred over bison.
+define(GROFF_PROG_YACC,
+[AC_PROGRAM_CHECK(YACC, byacc, byacc, )
+AC_PROGRAM_CHECK(YACC, bison, bison -y, yacc)
+])dnl
+dnl GROFF_CSH_HACK(if hack present, if not present)
+define(GROFF_CSH_HACK,
+[echo 'checking for csh # hack'
+cat <<EOF >conftest.sh
+#!/bin/sh
+true || exit 0
+export PATH || exit 0
+exit 1
+EOF
+chmod +x conftest.sh
+if echo ./conftest.sh | (csh >/dev/null 2>&1) >/dev/null 2>&1
+then
+ :; $1
+else
+ :; $2
+fi
+rm -f conftest.sh
+])dnl
+define(GROFF_POSIX,
+[GROFF_CC_COMPILE_CHECK(whether -D_POSIX_SOURCE is necessary,
+[#include <stdio.h>],
+[(void)fileno(stdin);],,
+AC_DEFINE(_POSIX_SOURCE))])dnl
+dnl From udodo!hans@relay.NL.net (Hans Zuidam)
+define(GROFF_ISC_SYSV3,
+[echo 'checking for ISC 3.x or 4.x'
+changequote(,)dnl
+if grep '[34]\.' /usr/options/cb.name >/dev/null 2>&1
+changequote([,])dnl
+then
+ AC_DEFINE(_SYSV3)
+fi])dnl
diff --git a/gnu/usr.bin/groff/addftinfo/Makefile b/gnu/usr.bin/groff/addftinfo/Makefile
new file mode 100644
index 0000000..db79f7c
--- /dev/null
+++ b/gnu/usr.bin/groff/addftinfo/Makefile
@@ -0,0 +1,13 @@
+# Makefile for addftinfo
+
+PROG= addftinfo
+SRCS= addftinfo.cc guess.cc
+CFLAGS+= -I${.CURDIR}/../include
+LDADD+= ${LIBGROFF}
+DPADD+= ${LIBGROFF}
+
+MANDEPEND= addftinfo.1
+CLEANFILES+= ${MANDEPEND}
+
+.include "../Makefile.cfg"
+.include <bsd.prog.mk>
diff --git a/gnu/usr.bin/groff/addftinfo/Makefile.dep b/gnu/usr.bin/groff/addftinfo/Makefile.dep
new file mode 100644
index 0000000..4583de2
--- /dev/null
+++ b/gnu/usr.bin/groff/addftinfo/Makefile.dep
@@ -0,0 +1,3 @@
+addftinfo.o : addftinfo.cc ../include/lib.h ../include/errarg.h \
+ ../include/error.h ../include/stringclass.h ../include/cset.h guess.h
+guess.o : guess.cc guess.h
diff --git a/gnu/usr.bin/groff/addftinfo/Makefile.sub b/gnu/usr.bin/groff/addftinfo/Makefile.sub
new file mode 100644
index 0000000..95a8f5b
--- /dev/null
+++ b/gnu/usr.bin/groff/addftinfo/Makefile.sub
@@ -0,0 +1,6 @@
+PROG=addftinfo
+MAN1=addftinfo.n
+XLIBS=$(LIBGROFF)
+OBJS=addftinfo.o guess.o
+CCSRCS=addftinfo.cc guess.cc
+HDRS=guess.h
diff --git a/gnu/usr.bin/groff/addftinfo/addftinfo.cc b/gnu/usr.bin/groff/addftinfo/addftinfo.cc
new file mode 100644
index 0000000..253a08a
--- /dev/null
+++ b/gnu/usr.bin/groff/addftinfo/addftinfo.cc
@@ -0,0 +1,194 @@
+// -*- C++ -*-
+/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
+ Written by James Clark (jjc@jclark.com)
+
+This file is part of groff.
+
+groff is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
+
+groff is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License along
+with groff; see the file COPYING. If not, write to the Free Software
+Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+#include <assert.h>
+#include <stdlib.h>
+#include <errno.h>
+#include "lib.h"
+#include "errarg.h"
+#include "error.h"
+#include "stringclass.h"
+#include "cset.h"
+#include "guess.h"
+
+static void usage();
+static void convert_font(const font_params &, FILE *, FILE *);
+
+typedef int font_params::*param_t;
+
+static struct {
+ const char *name;
+ param_t par;
+} param_table[] = {
+ { "x-height", &font_params::x_height },
+ { "fig-height", &font_params::fig_height },
+ { "asc-height", &font_params::asc_height },
+ { "body-height", &font_params::body_height },
+ { "cap-height", &font_params::cap_height },
+ { "comma-depth", &font_params::comma_depth },
+ { "desc-depth", &font_params::desc_depth },
+ { "body-depth", &font_params::body_depth },
+};
+
+// These are all in thousandths of an em.
+// These values are correct for PostScript Times Roman.
+
+#define DEFAULT_X_HEIGHT 448
+#define DEFAULT_FIG_HEIGHT 676
+#define DEFAULT_ASC_HEIGHT 682
+#define DEFAULT_BODY_HEIGHT 676
+#define DEFAULT_CAP_HEIGHT 662
+#define DEFAULT_COMMA_DEPTH 143
+#define DEFAULT_DESC_DEPTH 217
+#define DEFAULT_BODY_DEPTH 177
+
+int main(int argc, char **argv)
+{
+ program_name = argv[0];
+ if (argc < 4)
+ usage();
+ int resolution;
+ if (sscanf(argv[argc-3], "%d", &resolution) != 1)
+ usage();
+ if (resolution <= 0)
+ fatal("resolution must be > 0");
+ int unitwidth;
+ if (sscanf(argv[argc-2], "%d", &unitwidth) != 1)
+ usage();
+ if (unitwidth <= 0)
+ fatal("unitwidth must be > 0");
+ font_params param;
+ const char *font = argv[argc-1];
+ param.italic = (font[0] != '\0' && strchr(font, '\0')[-1] == 'I');
+ param.em = (resolution*unitwidth)/72;
+ param.x_height = DEFAULT_X_HEIGHT;
+ param.fig_height = DEFAULT_FIG_HEIGHT;
+ param.asc_height = DEFAULT_ASC_HEIGHT;
+ param.body_height = DEFAULT_BODY_HEIGHT;
+ param.cap_height = DEFAULT_CAP_HEIGHT;
+ param.comma_depth = DEFAULT_COMMA_DEPTH;
+ param.desc_depth = DEFAULT_DESC_DEPTH;
+ param.body_depth = DEFAULT_BODY_DEPTH;
+ for (int i = 1; i < argc && argv[i][0] == '-'; i++) {
+ if (argv[i][1] == '-' && argv[i][2] == '\0') {
+ i++;
+ break;
+ }
+ if (i + 1 >= argc)
+ usage();
+ for (int j = 0;; j++) {
+ if (j >= sizeof(param_table)/sizeof(param_table[0]))
+ fatal("parameter `%1' not recognized", argv[i] + 1);
+ if (strcmp(param_table[j].name, argv[i] + 1) == 0)
+ break;
+ }
+ if (sscanf(argv[i+1], "%d", &(param.*(param_table[j].par))) != 1)
+ fatal("invalid argument `%1'", argv[i+1]);
+ i++;
+ }
+ if (argc - i != 3)
+ usage();
+ errno = 0;
+ FILE *infp = fopen(font, "r");
+ if (infp == 0)
+ fatal("can't open `%1': %2", font, strerror(errno));
+ convert_font(param, infp, stdout);
+ return 0;
+}
+
+static void usage()
+{
+ fprintf(stderr, "usage: %s [-param value] ... resolution unitwidth font\n",
+ program_name);
+ exit(1);
+}
+
+static int get_line(FILE *fp, string *p)
+{
+ int c;
+ p->clear();
+ while ((c = getc(fp)) != EOF) {
+ *p += char(c);
+ if (c == '\n')
+ break;
+ }
+ return p->length() > 0;
+}
+
+static void convert_font(const font_params &param, FILE *infp, FILE *outfp)
+{
+ string s;
+ while (get_line(infp, &s)) {
+ put_string(s, outfp);
+ if (s.length() >= 8
+ && strncmp(&s[0], "charset", 7))
+ break;
+ }
+ while (get_line(infp, &s)) {
+ s += '\0';
+ string name;
+ const char *p = s.contents();
+ while (csspace(*p))
+ p++;
+ while (*p != '\0' && !csspace(*p))
+ name += *p++;
+ while (csspace(*p))
+ p++;
+ for (const char *q = s.contents(); q < p; q++)
+ putc(*q, outfp);
+ char *next;
+ char_metric metric;
+ metric.width = (int)strtol(p, &next, 10);
+ if (next != p) {
+ printf("%d", metric.width);
+ p = next;
+ metric.type = (int)strtol(p, &next, 10);
+ if (next != p) {
+ name += '\0';
+ guess(name.contents(), param, &metric);
+ if (metric.sk == 0) {
+ if (metric.left_ic == 0) {
+ if (metric.ic == 0) {
+ if (metric.depth == 0) {
+ if (metric.height != 0)
+ printf(",%d", metric.height);
+ }
+ else
+ printf(",%d,%d", metric.height, metric.depth);
+ }
+ else
+ printf(",%d,%d,%d", metric.height, metric.depth, metric.ic);
+ }
+ else
+ printf(",%d,%d,%d,%d", metric.height, metric.depth, metric.ic,
+ metric.left_ic);
+ }
+ else
+ printf(",%d,%d,%d,%d,%d", metric.height, metric.depth, metric.ic,
+ metric.left_ic, metric.sk);
+ }
+ }
+ fputs(p, outfp);
+ }
+}
+
diff --git a/gnu/usr.bin/groff/addftinfo/addftinfo.man b/gnu/usr.bin/groff/addftinfo/addftinfo.man
new file mode 100644
index 0000000..0b6b796
--- /dev/null
+++ b/gnu/usr.bin/groff/addftinfo/addftinfo.man
@@ -0,0 +1,84 @@
+.\" -*- nroff -*-
+.TH ADDFTINFO @MAN1EXT@ "@MDATE@" "Groff Version @VERSION@"
+.SH NAME
+addftinfo \- add information to troff font files for use with groff
+.SH SYNOPSIS
+.B addftinfo
+[
+.BI \- param\ value\fR.\|.\|.
+]
+.I res
+.I unitwidth
+.I font
+.SH DESCRIPTION
+.B addftinfo
+reads a troff font file
+and adds some additional font-metric information
+that is used by the groff system.
+The font file with the information added is written on the
+standard output.
+The information added is guessed using
+some parametric information about the font
+and assumptions
+about the traditional troff names for characters.
+The main information added is the heights and depths of characters.
+The
+.I res
+and
+.I unitwidth
+arguments should be the same as the corresponding parameters
+in the DESC file;
+.I font
+is the name of the file describing the font;
+if
+.I font
+ends with
+.B I
+the font will be assumed to be italic.
+.SH OPTIONS
+Each of the options changes one of the parameters that is used
+to derive the heights and depths.
+Like the existing quantities in the font
+file, each
+.I value
+is in
+.RI inches/ res
+for a font whose point size is
+.IR unitwidth .
+.I param
+must be one of:
+.TP
+.B x-height
+The height of lowercase letters without ascenders such as x.
+.TP
+.B fig-height
+The height of figures (digits).
+.TP
+.B asc-height
+The height of characters with ascenders, such as b, d or l.
+.TP
+.B body-height
+The height of characters such as parentheses.
+.TP
+.B cap-height
+The height of uppercase letters such as A.
+.TP
+.B comma-depth
+The depth of a comma.
+.TP
+.B desc-depth
+The depth of characters with descenders, such as p,q, or y.
+.TP
+.B body-depth
+The depth of characters such as parentheses.
+.LP
+.B addftinfo
+makes no attempt to use the specified parameters to guess
+the unspecified parameters.
+If a parameter is not specified the default will be used.
+The defaults are chosen to have the reasonable values for
+a Times font.
+.SH "SEE ALSO"
+.BR groff_font (@MAN5EXT@),
+.BR groff (@MAN1EXT@),
+.BR groff_char (@MAN7EXT@)
diff --git a/gnu/usr.bin/groff/addftinfo/guess.cc b/gnu/usr.bin/groff/addftinfo/guess.cc
new file mode 100644
index 0000000..44b5f91
--- /dev/null
+++ b/gnu/usr.bin/groff/addftinfo/guess.cc
@@ -0,0 +1,490 @@
+// -*- C++ -*-
+/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
+ Written by James Clark (jjc@jclark.com)
+
+This file is part of groff.
+
+groff is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
+
+groff is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License along
+with groff; see the file COPYING. If not, write to the Free Software
+Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "guess.h"
+
+void guess(const char *s, const font_params &param, char_metric *metric)
+{
+ int &height = metric->height;
+ int &depth = metric->depth;
+
+ metric->ic = 0;
+ metric->left_ic = 0;
+ metric->sk = 0;
+ height = 0;
+ depth = 0;
+ if (s[0] == '\0' || (s[1] != '\0' && s[2] != '\0'))
+ goto do_default;
+#define HASH(c1, c2) (((unsigned char)(c1) << 8) | (unsigned char)(c2))
+ switch (HASH(s[0], s[1])) {
+ default:
+ do_default:
+ if (metric->type & 01)
+ depth = param.desc_depth;
+ if (metric->type & 02)
+ height = param.asc_height;
+ else
+ height = param.x_height;
+ break;
+ case HASH('\\', '|'):
+ case HASH('\\', '^'):
+ case HASH('\\', '&'):
+ // these have zero height and depth
+ break;
+ case HASH('f', 0):
+ height = param.asc_height;
+ if (param.italic)
+ depth = param.desc_depth;
+ break;
+ case HASH('a', 0):
+ case HASH('c', 0):
+ case HASH('e', 0):
+ case HASH('m', 0):
+ case HASH('n', 0):
+ case HASH('o', 0):
+ case HASH('r', 0):
+ case HASH('s', 0):
+ case HASH('u', 0):
+ case HASH('v', 0):
+ case HASH('w', 0):
+ case HASH('x', 0):
+ case HASH('z', 0):
+ height = param.x_height;
+ break;
+ case HASH('i', 0):
+ height = param.x_height;
+ break;
+ case HASH('b', 0):
+ case HASH('d', 0):
+ case HASH('h', 0):
+ case HASH('k', 0):
+ case HASH('l', 0):
+ case HASH('F', 'i'):
+ case HASH('F', 'l'):
+ case HASH('f', 'f'):
+ case HASH('f', 'i'):
+ case HASH('f', 'l'):
+ height = param.asc_height;
+ break;
+ case HASH('t', 0):
+ height = param.asc_height;
+ break;
+ case HASH('g', 0):
+ case HASH('p', 0):
+ case HASH('q', 0):
+ case HASH('y', 0):
+ height = param.x_height;
+ depth = param.desc_depth;
+ break;
+ case HASH('j', 0):
+ height = param.x_height;
+ depth = param.desc_depth;
+ break;
+ case HASH('A', 0):
+ case HASH('B', 0):
+ case HASH('C', 0):
+ case HASH('D', 0):
+ case HASH('E', 0):
+ case HASH('F', 0):
+ case HASH('G', 0):
+ case HASH('H', 0):
+ case HASH('I', 0):
+ case HASH('J', 0):
+ case HASH('K', 0):
+ case HASH('L', 0):
+ case HASH('M', 0):
+ case HASH('N', 0):
+ case HASH('O', 0):
+ case HASH('P', 0):
+ case HASH('Q', 0):
+ case HASH('R', 0):
+ case HASH('S', 0):
+ case HASH('T', 0):
+ case HASH('U', 0):
+ case HASH('V', 0):
+ case HASH('W', 0):
+ case HASH('X', 0):
+ case HASH('Y', 0):
+ case HASH('Z', 0):
+ height = param.cap_height;
+ break;
+ case HASH('*', 'A'):
+ case HASH('*', 'B'):
+ case HASH('*', 'C'):
+ case HASH('*', 'D'):
+ case HASH('*', 'E'):
+ case HASH('*', 'F'):
+ case HASH('*', 'G'):
+ case HASH('*', 'H'):
+ case HASH('*', 'I'):
+ case HASH('*', 'K'):
+ case HASH('*', 'L'):
+ case HASH('*', 'M'):
+ case HASH('*', 'N'):
+ case HASH('*', 'O'):
+ case HASH('*', 'P'):
+ case HASH('*', 'Q'):
+ case HASH('*', 'R'):
+ case HASH('*', 'S'):
+ case HASH('*', 'T'):
+ case HASH('*', 'U'):
+ case HASH('*', 'W'):
+ case HASH('*', 'X'):
+ case HASH('*', 'Y'):
+ case HASH('*', 'Z'):
+ height = param.cap_height;
+ break;
+ case HASH('0', 0):
+ case HASH('1', 0):
+ case HASH('2', 0):
+ case HASH('3', 0):
+ case HASH('4', 0):
+ case HASH('5', 0):
+ case HASH('6', 0):
+ case HASH('7', 0):
+ case HASH('8', 0):
+ case HASH('9', 0):
+ case HASH('1', '2'):
+ case HASH('1', '4'):
+ case HASH('3', '4'):
+ height = param.fig_height;
+ break;
+ case HASH('(', 0):
+ case HASH(')', 0):
+ case HASH('[', 0):
+ case HASH(']', 0):
+ case HASH('{', 0):
+ case HASH('}', 0):
+ height = param.body_height;
+ depth = param.body_depth;
+ break;
+ case HASH('i', 's'):
+ height = (param.em*3)/4;
+ depth = param.em/4;
+ break;
+ case HASH('*', 'a'):
+ case HASH('*', 'e'):
+ case HASH('*', 'i'):
+ case HASH('*', 'k'):
+ case HASH('*', 'n'):
+ case HASH('*', 'o'):
+ case HASH('*', 'p'):
+ case HASH('*', 's'):
+ case HASH('*', 't'):
+ case HASH('*', 'u'):
+ case HASH('*', 'w'):
+ height = param.x_height;
+ break;
+ case HASH('*', 'd'):
+ case HASH('*', 'l'):
+ height = param.asc_height;
+ break;
+ case HASH('*', 'g'):
+ case HASH('*', 'h'):
+ case HASH('*', 'm'):
+ case HASH('*', 'r'):
+ case HASH('*', 'x'):
+ case HASH('*', 'y'):
+ height = param.x_height;
+ depth = param.desc_depth;
+ break;
+ case HASH('*', 'b'):
+ case HASH('*', 'c'):
+ case HASH('*', 'f'):
+ case HASH('*', 'q'):
+ case HASH('*', 'z'):
+ height = param.asc_height;
+ depth = param.desc_depth;
+ break;
+ case HASH('t', 's'):
+ height = param.x_height;
+ depth = param.desc_depth;
+ break;
+ case HASH('!', 0):
+ case HASH('?', 0):
+ case HASH('"', 0):
+ case HASH('#', 0):
+ case HASH('$', 0):
+ case HASH('%', 0):
+ case HASH('&', 0):
+ case HASH('*', 0):
+ case HASH('+', 0):
+ height = param.asc_height;
+ break;
+ case HASH('`', 0):
+ case HASH('\'', 0):
+ height = param.asc_height;
+ break;
+ case HASH('~', 0):
+ case HASH('^', 0):
+ case HASH('a', 'a'):
+ case HASH('g', 'a'):
+ height = param.asc_height;
+ break;
+ case HASH('r', 'u'):
+ case HASH('.', 0):
+ break;
+ case HASH(',', 0):
+ depth = param.comma_depth;
+ break;
+ case HASH('m', 'i'):
+ case HASH('-', 0):
+ case HASH('h', 'y'):
+ case HASH('e', 'm'):
+ height = param.x_height;
+ break;
+ case HASH(':', 0):
+ height = param.x_height;
+ break;
+ case HASH(';', 0):
+ height = param.x_height;
+ depth = param.comma_depth;
+ break;
+ case HASH('=', 0):
+ case HASH('e', 'q'):
+ height = param.x_height;
+ break;
+ case HASH('<', 0):
+ case HASH('>', 0):
+ case HASH('>', '='):
+ case HASH('<', '='):
+ case HASH('@', 0):
+ case HASH('/', 0):
+ case HASH('|', 0):
+ case HASH('\\', 0):
+ height = param.asc_height;
+ break;
+ case HASH('_', 0):
+ case HASH('u', 'l'):
+ case HASH('\\', '_'):
+ depth = param.em/4;
+ break;
+ case HASH('r', 'n'):
+ height = (param.em*3)/4;
+ break;
+ case HASH('s', 'r'):
+ height = (param.em*3)/4;
+ depth = param.em/4;
+ break;
+ case HASH('b', 'u'):
+ case HASH('s', 'q'):
+ case HASH('d', 'e'):
+ case HASH('d', 'g'):
+ case HASH('f', 'm'):
+ case HASH('c', 't'):
+ case HASH('r', 'g'):
+ case HASH('c', 'o'):
+ case HASH('p', 'l'):
+ case HASH('*', '*'):
+ case HASH('s', 'c'):
+ case HASH('s', 'l'):
+ case HASH('=', '='):
+ case HASH('~', '='):
+ case HASH('a', 'p'):
+ case HASH('!', '='):
+ case HASH('-', '>'):
+ case HASH('<', '-'):
+ case HASH('u', 'a'):
+ case HASH('d', 'a'):
+ case HASH('m', 'u'):
+ case HASH('d', 'i'):
+ case HASH('+', '-'):
+ case HASH('c', 'u'):
+ case HASH('c', 'a'):
+ case HASH('s', 'b'):
+ case HASH('s', 'p'):
+ case HASH('i', 'b'):
+ case HASH('i', 'p'):
+ case HASH('i', 'f'):
+ case HASH('p', 'd'):
+ case HASH('g', 'r'):
+ case HASH('n', 'o'):
+ case HASH('p', 't'):
+ case HASH('e', 's'):
+ case HASH('m', 'o'):
+ case HASH('b', 'r'):
+ case HASH('d', 'd'):
+ case HASH('r', 'h'):
+ case HASH('l', 'h'):
+ case HASH('o', 'r'):
+ case HASH('c', 'i'):
+ height = param.asc_height;
+ break;
+ case HASH('l', 't'):
+ case HASH('l', 'b'):
+ case HASH('r', 't'):
+ case HASH('r', 'b'):
+ case HASH('l', 'k'):
+ case HASH('r', 'k'):
+ case HASH('b', 'v'):
+ case HASH('l', 'f'):
+ case HASH('r', 'f'):
+ case HASH('l', 'c'):
+ case HASH('r', 'c'):
+ height = (param.em*3)/4;
+ depth = param.em/4;
+ break;
+#if 0
+ case HASH('%', '0'):
+ case HASH('-', '+'):
+ case HASH('-', 'D'):
+ case HASH('-', 'd'):
+ case HASH('-', 'd'):
+ case HASH('-', 'h'):
+ case HASH('.', 'i'):
+ case HASH('.', 'j'):
+ case HASH('/', 'L'):
+ case HASH('/', 'O'):
+ case HASH('/', 'l'):
+ case HASH('/', 'o'):
+ case HASH('=', '~'):
+ case HASH('A', 'E'):
+ case HASH('A', 'h'):
+ case HASH('A', 'N'):
+ case HASH('C', 's'):
+ case HASH('D', 'o'):
+ case HASH('F', 'c'):
+ case HASH('F', 'o'):
+ case HASH('I', 'J'):
+ case HASH('I', 'm'):
+ case HASH('O', 'E'):
+ case HASH('O', 'f'):
+ case HASH('O', 'K'):
+ case HASH('O', 'm'):
+ case HASH('O', 'R'):
+ case HASH('P', 'o'):
+ case HASH('R', 'e'):
+ case HASH('S', '1'):
+ case HASH('S', '2'):
+ case HASH('S', '3'):
+ case HASH('T', 'P'):
+ case HASH('T', 'p'):
+ case HASH('Y', 'e'):
+ case HASH('\\', '-'):
+ case HASH('a', '"'):
+ case HASH('a', '-'):
+ case HASH('a', '.'):
+ case HASH('a', '^'):
+ case HASH('a', 'b'):
+ case HASH('a', 'c'):
+ case HASH('a', 'd'):
+ case HASH('a', 'e'):
+ case HASH('a', 'h'):
+ case HASH('a', 'o'):
+ case HASH('a', 't'):
+ case HASH('a', '~'):
+ case HASH('b', 'a'):
+ case HASH('b', 'b'):
+ case HASH('b', 's'):
+ case HASH('c', '*'):
+ case HASH('c', '+'):
+ case HASH('f', '/'):
+ case HASH('f', 'a'):
+ case HASH('f', 'c'):
+ case HASH('f', 'o'):
+ case HASH('h', 'a'):
+ case HASH('h', 'o'):
+ case HASH('i', 'j'):
+ case HASH('l', 'A'):
+ case HASH('l', 'B'):
+ case HASH('l', 'C'):
+ case HASH('m', 'd'):
+ case HASH('n', 'c'):
+ case HASH('n', 'e'):
+ case HASH('n', 'm'):
+ case HASH('o', 'A'):
+ case HASH('o', 'a'):
+ case HASH('o', 'e'):
+ case HASH('o', 'q'):
+ case HASH('p', 'l'):
+ case HASH('p', 'p'):
+ case HASH('p', 's'):
+ case HASH('r', '!'):
+ case HASH('r', '?'):
+ case HASH('r', 'A'):
+ case HASH('r', 'B'):
+ case HASH('r', 'C'):
+ case HASH('r', 's'):
+ case HASH('s', 'h'):
+ case HASH('s', 's'):
+ case HASH('t', 'e'):
+ case HASH('t', 'f'):
+ case HASH('t', 'i'):
+ case HASH('t', 'm'):
+ case HASH('~', '~'):
+ case HASH('v', 'S'):
+ case HASH('v', 'Z'):
+ case HASH('v', 's'):
+ case HASH('v', 'z'):
+ case HASH('^', 'A'):
+ case HASH('^', 'E'):
+ case HASH('^', 'I'):
+ case HASH('^', 'O'):
+ case HASH('^', 'U'):
+ case HASH('^', 'a'):
+ case HASH('^', 'e'):
+ case HASH('^', 'i'):
+ case HASH('^', 'o'):
+ case HASH('^', 'u'):
+ case HASH('`', 'A'):
+ case HASH('`', 'E'):
+ case HASH('`', 'I'):
+ case HASH('`', 'O'):
+ case HASH('`', 'U'):
+ case HASH('`', 'a'):
+ case HASH('`', 'e'):
+ case HASH('`', 'i'):
+ case HASH('`', 'o'):
+ case HASH('`', 'u'):
+ case HASH('~', 'A'):
+ case HASH('~', 'N'):
+ case HASH('~', 'O'):
+ case HASH('~', 'a'):
+ case HASH('~', 'n'):
+ case HASH('~', 'o'):
+ case HASH('\'', 'A'):
+ case HASH('\'', 'C'):
+ case HASH('\'', 'E'):
+ case HASH('\'', 'I'):
+ case HASH('\'', 'O'):
+ case HASH('\'', 'U'):
+ case HASH('\'', 'a'):
+ case HASH('\'', 'c'):
+ case HASH('\'', 'e'):
+ case HASH('\'', 'i'):
+ case HASH('\'', 'o'):
+ case HASH('\'', 'u')
+ case HASH(':', 'A'):
+ case HASH(':', 'E'):
+ case HASH(':', 'I'):
+ case HASH(':', 'O'):
+ case HASH(':', 'U'):
+ case HASH(':', 'Y'):
+ case HASH(':', 'a'):
+ case HASH(':', 'e'):
+ case HASH(':', 'i'):
+ case HASH(':', 'o'):
+ case HASH(':', 'u'):
+ case HASH(':', 'y'):
+ case HASH(',', 'C'):
+ case HASH(',', 'c'):
+#endif
+ }
+}
diff --git a/gnu/usr.bin/groff/addftinfo/guess.h b/gnu/usr.bin/groff/addftinfo/guess.h
new file mode 100644
index 0000000..f13767c
--- /dev/null
+++ b/gnu/usr.bin/groff/addftinfo/guess.h
@@ -0,0 +1,44 @@
+// -*- C++ -*-
+/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
+ Written by James Clark (jjc@jclark.com)
+
+This file is part of groff.
+
+groff is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
+
+groff is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License along
+with groff; see the file COPYING. If not, write to the Free Software
+Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+struct font_params {
+ int italic;
+ int em;
+ int x_height;
+ int fig_height;
+ int cap_height;
+ int asc_height;
+ int body_height;
+ int comma_depth;
+ int desc_depth;
+ int body_depth;
+};
+
+struct char_metric {
+ int width;
+ int type;
+ int height;
+ int depth;
+ int ic;
+ int left_ic;
+ int sk;
+};
+
+void guess(const char *s, const font_params &param, char_metric *metric);
diff --git a/gnu/usr.bin/groff/afmtodit/Makefile.sub b/gnu/usr.bin/groff/afmtodit/Makefile.sub
new file mode 100644
index 0000000..fb5daac
--- /dev/null
+++ b/gnu/usr.bin/groff/afmtodit/Makefile.sub
@@ -0,0 +1,21 @@
+MAN1=afmtodit.n
+CLEANADD=afmtodit
+
+all: afmtodit
+
+afmtodit: afmtodit.pl
+ if test -n "$(PERLPATH)"; then \
+ sed -e 's;/usr/bin/perl;$(PERLPATH);' \
+ $(srcdir)/afmtodit.pl >afmtodit; \
+ else \
+ cp $(srcdir)/afmtodit.pl afmtodit; \
+ fi
+ chmod +x afmtodit
+
+install_data: afmtodit
+ -test -d $(bindir) || mkdir $(bindir)
+ -rm -f $(bindir)/afmtodit
+ $(INSTALL_PROGRAM) afmtodit $(bindir)/afmtodit
+
+uninstall_sub:
+ -rm -f $(bindir)/afmtodit
diff --git a/gnu/usr.bin/groff/afmtodit/afmtodit.man b/gnu/usr.bin/groff/afmtodit/afmtodit.man
new file mode 100644
index 0000000..3730b7a
--- /dev/null
+++ b/gnu/usr.bin/groff/afmtodit/afmtodit.man
@@ -0,0 +1,204 @@
+.\" -*- nroff -*-
+.\" Like TP, but if specified indent is more than half
+.\" the current line-length - indent, use the default indent.
+.de Tp
+.ie \\n(.$=0:((0\\$1)*2u>(\\n(.lu-\\n(.iu)) .TP
+.el .TP "\\$1"
+..
+.TH AFMTODIT @MAN1EXT@ "@MDATE@" "Groff Version @VERSION@"
+.SH NAME
+afmtodit \- create font files for use with groff \-Tps
+.SH SYNOPSIS
+.B afmtodit
+[
+.B \-ns
+]
+[
+.BI \-d desc_file
+]
+[
+.BI \-e enc_file
+]
+[
+.BI \-i n
+]
+[
+.BI \-a n
+]
+.I afm_file
+.I map_file
+.I font
+.SH DESCRIPTION
+.B afmtodit
+creates a font file for use with groff and
+.BR grops .
+.B afmtodit
+is written in perl;
+you must have perl version 3 installed in order to run
+.BR afmtodit .
+.I afm_file
+is the AFM (Adobe Font Metric) file for the font.
+.I map_file
+is a file that says which groff character names map onto
+each PostScript character name;
+this file should contain a sequence of lines of the form
+.IP
+.I
+ps_char groff_char
+.LP
+where
+.I ps_char
+is the PostScript name of the character
+and
+.I groff_char
+is the groff name of the character (as used in the groff font file.)
+The same
+.I ps_char
+can occur multiple times in the file;
+each
+.I groff_char
+must occur at most once.
+.I font
+is the groff name of the font.
+If a PostScript character is in the encoding to be used for the font
+but is not mentioned in
+.I map_file
+then
+.B afmtodit
+will put it in the groff font file as an unnamed character,
+which can be accessed by the
+.B \eN
+escape sequence in
+.BR troff .
+The groff font file will be output to a file called
+.IR font .
+.LP
+If there is a downloadable font file for the font, it may be listed in
+the file
+.BR @FONTDIR@/devps/download ;
+see
+.BR grops (@MAN1EXT@).
+.LP
+If the
+.B \-i
+option is used,
+.B afmtodit
+will automatically generate an italic correction,
+a left italic correction and a subscript correction
+for each character
+(the significance of these parameters is explained in
+.BR groff_font (@MAN5EXT@));
+these parameters may be specified for individual characters by
+adding to the
+.I afm_file
+lines of the form:
+.IP
+.BI italicCorrection\ ps_char\ n
+.br
+.BI leftItalicCorrection\ ps_char\ n
+.br
+.BI subscriptCorrection\ ps_char\ n
+.LP
+where
+.I ps_char
+is the PostScript name of the character,
+and
+.I n
+is the desired value of the corresponding parameter in thousandths of an em.
+These parameters are normally needed only for italic (or oblique) fonts.
+.SH OPTIONS
+.TP
+.B \-n
+Don't output a
+.B ligatures
+command for this font.
+Use this with constant-width fonts.
+.TP
+.B \-s
+The font is special.
+The effect of this option is to add the
+.B special
+command to the font file.
+.TP
+.BI \-d desc_file
+The device description file is
+.I desc_file
+rather than the default
+.BR DESC .
+.TP
+.BI \-e enc_file
+The PostScript font should be reencoded to use the encoding described
+in enc_file.
+The format of
+.I enc_file
+is described in
+.BR grops (@MAN1EXT@).
+.TP
+.BI \-a n
+Use
+.I n
+as the slant parameter in the font file;
+this is used by groff in the positioning of accents.
+By default
+.B afmtodit
+uses the negative of the ItalicAngle specified in the afm file;
+with true italic fonts it is sometimes desirable to use
+a slant that is less than this.
+If you find that characters from an italic font have accents
+placed too far to the right over them,
+then use the
+.B \-a
+option to give the font a smaller slant.
+.TP
+.BI \-i n
+Generate an italic correction for each character so that
+the character's width plus the character's italic correction
+is equal to
+.I n
+thousandths of an em
+plus the amount by which the right edge of the character's bounding
+is to the right of the character's origin.
+If this would result in a negative italic correction, use a zero
+italic correction instead.
+.IP
+Also generate a subscript correction equal to the
+product of the tangent of the slant of the font and
+four fifths of the x-height of the font.
+If this would result in a subscript correction greater than the italic
+correction, use a subscript correction equal to the italic correction
+instead.
+.IP
+Also generate a left italic correction for each character
+equal to
+.I n
+thousandths of an em
+plus the amount by which the left edge of the character's bounding box
+is to the left of the character's origin.
+The left italic correction may be negative.
+.IP
+This option is normally needed only with italic (or oblique) fonts.
+The font files distributed with groff were created using an option of
+.B \-i50
+for italic fonts.
+.SH FILES
+.Tp \w'\fB@FONTDIR@/devps/download'u+2n
+.B @FONTDIR@/devps/DESC
+Device description file.
+.TP
+.BI @FONTDIR@/devps/ F
+Font description file for font
+.IR F .
+.TP
+.B @FONTDIR@/devps/download
+List of downloadable fonts.
+.TP
+.B @FONTDIR@/devps/text.enc
+Encoding used for text fonts.
+.TP
+.B @FONTDIR@/devps/generate/textmap
+Standard mapping.
+.SH "SEE ALSO"
+.BR groff (@MAN1EXT@),
+.BR grops (@MAN1EXT@),
+.BR groff_font (@MAN5EXT@),
+.BR perl (1)
diff --git a/gnu/usr.bin/groff/afmtodit/afmtodit.pl b/gnu/usr.bin/groff/afmtodit/afmtodit.pl
new file mode 100644
index 0000000..60bee93
--- /dev/null
+++ b/gnu/usr.bin/groff/afmtodit/afmtodit.pl
@@ -0,0 +1,325 @@
+#! /usr/bin/perl -P- # -*- Perl -*-
+#Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
+# Written by James Clark (jjc@jclark.com)
+#
+#This file is part of groff.
+#
+#groff is free software; you can redistribute it and/or modify it under
+#the terms of the GNU General Public License as published by the Free
+#Software Foundation; either version 2, or (at your option) any later
+#version.
+#
+#groff is distributed in the hope that it will be useful, but WITHOUT ANY
+#WARRANTY; without even the implied warranty of MERCHANTABILITY or
+#FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+#for more details.
+#
+#You should have received a copy of the GNU General Public License along
+#with groff; see the file COPYING. If not, write to the Free Software
+#Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+$prog = $0;
+$prog =~ s@.*/@@;
+
+do 'getopts.pl';
+do Getopts('e:sd:i:a:n');
+
+if ($#ARGV != 2) {
+ die "Usage: $prog [-ns] [-d DESC] [-e encoding] [-i n] [-a angle] afmfile mapfile font\n";
+}
+
+$afm = $ARGV[0];
+$map = $ARGV[1];
+$font = $ARGV[2];
+$desc = $opt_d || "DESC";
+
+# read the afm file
+
+open(AFM, $afm) || die "$prog: can't open \`$ARGV[0]': $!\n";
+
+while (<AFM>) {
+ chop;
+ @field = split(' ');
+ if ($field[0] eq "FontName") {
+ $psname = $field[1];
+ }
+ elsif($field[0] eq "ItalicAngle") {
+ $italic_angle = -$field[1];
+ }
+ elsif ($field[0] eq "KPX") {
+ if ($#field == 3) {
+ push(kern1, $field[1]);
+ push(kern2, $field[2]);
+ push(kernx, $field[3]);
+ }
+ }
+ elsif ($field[0] eq "italicCorrection") {
+ $italic_correction{$field[1]} = $field[2];
+ }
+ elsif ($field[0] eq "leftItalicCorrection") {
+ $left_italic_correction{$field[1]} = $field[2];
+ }
+ elsif ($field[0] eq "subscriptCorrection") {
+ $subscript_correction{$field[1]} = $field[2];
+ }
+ elsif ($field[0] eq "StartCharMetrics") {
+ while (<AFM>) {
+ @field = split(' ');
+ last if ($field[0] eq "EndCharMetrics");
+ if ($field[0] eq "C") {
+ $c = -1;
+ $wx = 0;
+ $n = "";
+ $lly = 0;
+ $ury = 0;
+ $llx = 0;
+ $urx = 0;
+ $c = $field[1];
+ $i = 2;
+ while ($i <= $#field) {
+ if ($field[$i] eq "WX") {
+ $w = $field[$i + 1];
+ $i += 2;
+ }
+ elsif ($field[$i] eq "N") {
+ $n = $field[$i + 1];
+ $i += 2;
+ }
+ elsif ($field[$i] eq "B") {
+ $llx = $field[$i + 1];
+ $lly = $field[$i + 2];
+ $urx = $field[$i + 3];
+ $ury = $field[$i + 4];
+ $i += 5;
+ }
+ elsif ($field[$i] eq "L") {
+ push(ligatures, $field[$i + 2]);
+ $i += 3;
+ }
+ else {
+ while ($i <= $#field && $field[$i] ne ";") {
+ $i++;
+ }
+ $i++;
+ }
+ }
+ if (!$opt_e && $c != -1) {
+ $encoding[$c] = $n;
+ $in_encoding{$n} = 1;
+ }
+ $width{$n} = $w;
+ $height{$n} = $ury;
+ $depth{$n} = -$lly;
+ $left_side_bearing{$n} = -$llx;
+ $right_side_bearing{$n} = $urx - $w;
+ }
+ }
+ }
+}
+close(AFM);
+
+# read the DESC file
+
+$sizescale = 1;
+
+open(DESC, $desc) || die "$prog: can't open \`$desc': $!\n";
+while (<DESC>) {
+ next if /^#/;
+ chop;
+ @field = split(' ');
+ last if $field[0] eq "charset";
+ if ($field[0] eq "res") { $resolution = $field[1]; }
+ if ($field[0] eq "unitwidth") { $unitwidth = $field[1]; }
+ if ($field[0] eq "sizescale") { $sizescale = $field[1]; }
+}
+close(DESC);
+
+if ($opt_e) {
+ # read the encoding file
+
+ open(ENCODING, $opt_e) || die "$prog: can't open \`$opt_e': $!\n";
+ while (<ENCODING>) {
+ chop;
+ @field = split(' ');
+ if ($#field == 1) {
+ if ($field[1] >= 0 && defined $width{$field[0]}) {
+ $encoding[$field[1]] = $field[0];
+ $in_encoding{$field[0]} = 1;
+ }
+ }
+ }
+ close(ENCODING);
+}
+
+# read the map file
+
+open(MAP, $map) || die "$prog: can't open \`$map': $!\n";
+while (<MAP>) {
+ next if /^#/;
+ chop;
+ @field = split(' ');
+ if ($#field == 1 && $in_encoding{$field[0]}) {
+ if (defined $mapped{$field[1]}) {
+ warn "Both $mapped{$field[1]} and $field[0] map to $field[1]";
+ }
+ elsif ($field[1] eq "space") {
+ # the PostScript character "space" is automatically mapped
+ # to the groff character "space"; this is for grops
+ warn "you are not allowed to map to the groff character `space'";
+ }
+ elsif ($field[0] eq "space") {
+ warn "you are not allowed to map the PostScript character `space'";
+ }
+ else {
+ $nmap{$field[0]} += 0;
+ $map{$field[0],$nmap{$field[0]}} = $field[1];
+ $nmap{$field[0]} += 1;
+ $mapped{$field[1]} = $field[0];
+ }
+ }
+}
+close(MAP);
+
+$italic_angle = $opt_a if $opt_a;
+
+# print it all out
+
+open(FONT, ">$font") || die "$prog: can't open \`$font' for output: $!\n";
+select(FONT);
+
+print("name $font\n");
+print("internalname $psname\n") if $psname;
+print("special\n") if $opt_s;
+printf("slant %g\n", $italic_angle) if $italic_angle != 0;
+printf("spacewidth %d\n", do conv($width{"space"})) if defined $width{"space"};
+
+if ($opt_e) {
+ $e = $opt_e;
+ $e =~ s@.*/@@;
+ print("encoding $e\n");
+}
+
+if (!$opt_n && $#ligatures >= 0) {
+ print("ligatures");
+ foreach $lig (@ligatures) {
+ print(" $lig");
+ }
+ print(" 0\n");
+}
+
+if ($#kern1 >= 0) {
+ print("kernpairs\n");
+
+ for ($i = 0; $i <= $#kern1; $i++) {
+ $c1 = $kern1[$i];
+ $c2 = $kern2[$i];
+ if ($in_encoding{$c1} == 1 && $nmap{$c1} != 0
+ && $in_encoding{$c2} == 1 && $nmap{$c2} != 0) {
+ for ($j = 0; $j < $nmap{$c1}; $j++) {
+ for ($k = 0; $k < $nmap{$c2}; $k++) {
+ if ($kernx[$i] != 0) {
+ printf("%s %s %d\n",
+ $map{$c1,$j},
+ $map{$c2,$k},
+ do conv($kernx[$i]));
+ }
+ }
+ }
+ }
+ }
+}
+
+# characters not shorter than asc_boundary are considered to have ascenders
+$asc_boundary = $height{"t"} - 1;
+
+# likewise for descenders
+$desc_boundary = $depth{"g"};
+$desc_boundary = $depth{"j"} if $depth{"j"} < $desc_boundary;
+$desc_boundary = $depth{"p"} if $depth{"p"} < $desc_boundary;
+$desc_boundary = $depth{"q"} if $depth{"q"} < $desc_boundary;
+$desc_boundary = $depth{"y"} if $depth{"y"} < $desc_boundary;
+$desc_boundary -= 1;
+
+if (defined $height{"x"}) {
+ $xheight = $height{"x"};
+}
+elsif (defined $height{"alpha"}) {
+ $xheight = $height{"alpha"};
+}
+else {
+ $xheight = 450;
+}
+
+$italic_angle = $italic_angle*3.14159265358979323846/180.0;
+$slant = sin($italic_angle)/cos($italic_angle);
+$slant = 0 if $slant < 0;
+
+print("charset\n");
+for ($i = 0; $i < 256; $i++) {
+ $ch = $encoding[$i];
+ if ($ch ne "" && $ch ne "space") {
+ $map{$ch,"0"} = "---" if $nmap{$ch} == 0;
+ $type = 0;
+ $h = $height{$ch};
+ $h = 0 if $h < 0;
+ $d = $depth{$ch};
+ $d = 0 if $d < 0;
+ $type = 1 if $d >= $desc_boundary;
+ $type += 2 if $h >= $asc_boundary;
+ printf("%s\t%d", $map{$ch,"0"}, do conv($width{$ch}));
+ $italic_correction = 0;
+ $left_math_fit = 0;
+ $subscript_correction = 0;
+ if (defined $opt_i) {
+ $italic_correction = $right_side_bearing{$ch} + $opt_i;
+ $italic_correction = 0 if $italic_correction < 0;
+ $subscript_correction = $slant * $xheight * .8;
+ $subscript_correction = $italic_correction if
+ $subscript_correction > $italic_correction;
+ $left_math_fit = $left_side_bearing{$ch} + $opt_i;
+ }
+ if (defined $italic_correction{$ch}) {
+ $italic_correction = $italic_correction{$ch};
+ }
+ if (defined $left_italic_correction{$ch}) {
+ $left_math_fit = $left_italic_correction{$ch};
+ }
+ if (defined $subscript_correction{$ch}) {
+ $subscript_correction = $subscript_correction{$ch};
+ }
+ if ($subscript_correction != 0) {
+ printf(",%d,%d", do conv($h), do conv($d));
+ printf(",%d,%d,%d", do conv($italic_correction),
+ do conv($left_math_fit),
+ do conv($subscript_correction));
+ }
+ elsif ($left_math_fit != 0) {
+ printf(",%d,%d", do conv($h), do conv($d));
+ printf(",%d,%d", do conv($italic_correction),
+ do conv($left_math_fit));
+ }
+ elsif ($italic_correction != 0) {
+ printf(",%d,%d", do conv($h), do conv($d));
+ printf(",%d", do conv($italic_correction));
+ }
+ elsif ($d != 0) {
+ printf(",%d,%d", do conv($h), do conv($d));
+ }
+ else {
+ # always put the height in to stop groff guessing
+ printf(",%d", do conv($h));
+ }
+ printf("\t%d", $type);
+ printf("\t0%03o\t%s\n", $i, $ch);
+ for ($j = 1; $j < $nmap{$ch}; $j++) {
+ printf("%s\t\"\n", $map{$ch,$j});
+ }
+ }
+ if ($ch eq "space" && defined $width{"space"}) {
+ printf("space\t%d\t0\t0%03o\n", do conv($width{"space"}), $i);
+ }
+}
+
+sub conv {
+ $_[0]*$unitwidth*$resolution/(72*1000*$sizescale) + ($_[0] < 0 ? -.5 : .5);
+}
diff --git a/gnu/usr.bin/groff/configure b/gnu/usr.bin/groff/configure
new file mode 100755
index 0000000..16f1bf1
--- /dev/null
+++ b/gnu/usr.bin/groff/configure
@@ -0,0 +1,1409 @@
+#!/bin/sh
+# Guess values for system-dependent variables and create Makefiles.
+# Generated automatically using autoconf.
+# Copyright (C) 1991, 1992, 1993 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+# Usage: configure [--srcdir=DIR] [--host=HOST] [--gas] [--nfp]
+# [--prefix=PREFIX] [--exec-prefix=PREFIX] [--with-PACKAGE[=VALUE]]
+# Ignores all args except --srcdir, --prefix, --exec-prefix, and
+# --with-PACKAGE[=VALUE] unless this script has special code to handle it.
+
+for arg
+do
+ # Handle --exec-prefix with a space before the argument.
+ if test x$next_exec_prefix = xyes; then exec_prefix=$arg; next_exec_prefix=
+ # Handle --host with a space before the argument.
+ elif test x$next_host = xyes; then next_host=
+ # Handle --prefix with a space before the argument.
+ elif test x$next_prefix = xyes; then prefix=$arg; next_prefix=
+ # Handle --srcdir with a space before the argument.
+ elif test x$next_srcdir = xyes; then srcdir=$arg; next_srcdir=
+ else
+ case $arg in
+ # For backward compatibility, recognize -exec-prefix and --exec_prefix.
+ -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* | --exec=* | --exe=* | --ex=* | --e=*)
+ exec_prefix=`echo $arg | sed 's/[-a-z_]*=//'` ;;
+ -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- | --exec | --exe | --ex | --e)
+ next_exec_prefix=yes ;;
+
+ -gas | --gas | --ga | --g) ;;
+
+ -host=* | --host=* | --hos=* | --ho=* | --h=*) ;;
+ -host | --host | --hos | --ho | --h)
+ next_host=yes ;;
+
+ -nfp | --nfp | --nf) ;;
+
+ -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*)
+ prefix=`echo $arg | sed 's/[-a-z_]*=//'` ;;
+ -prefix | --prefix | --prefi | --pref | --pre | --pr | --p)
+ next_prefix=yes ;;
+
+ -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=* | --s=*)
+ srcdir=`echo $arg | sed 's/[-a-z_]*=//'` ;;
+ -srcdir | --srcdir | --srcdi | --srcd | --src | --sr | --s)
+ next_srcdir=yes ;;
+
+ -with-* | --with-*)
+ package=`echo $arg|sed -e 's/-*with-//' -e 's/=.*//'`
+ # Reject names that aren't valid shell variable names.
+ if test -n "`echo $package| sed 's/[-a-zA-Z0-9_]//g'`"; then
+ echo "configure: $package: invalid package name" >&2; exit 1
+ fi
+ package=`echo $package| sed 's/-/_/g'`
+ case "$arg" in
+ *=*) val="`echo $arg|sed 's/[^=]*=//'`" ;;
+ *) val=1 ;;
+ esac
+ eval "with_$package='$val'" ;;
+
+ -v | -verbose | --verbose | --verbos | --verbo | --verb | --ver | --ve | --v)
+ verbose=yes ;;
+
+ *) ;;
+ esac
+ fi
+done
+
+trap 'rm -fr conftest* confdefs* core; exit 1' 1 3 15
+trap 'rm -f confdefs*' 0
+
+# NLS nuisances.
+# These must not be set unconditionally because not all systems understand
+# e.g. LANG=C (notably SCO).
+if test "${LC_ALL+set}" = 'set' ; then LC_ALL=C; export LC_ALL; fi
+if test "${LANG+set}" = 'set' ; then LANG=C; export LANG; fi
+
+rm -f conftest* confdefs.h
+# AIX cpp loses on an empty file, so make sure it contains at least a newline.
+echo > confdefs.h
+compile='${CC-cc} $CFLAGS conftest.c -o conftest $LIBS >/dev/null 2>&1'
+
+# A filename unique to this package, relative to the directory that
+# configure is in, which we can look for to find out if srcdir is correct.
+unique_file=groff/groff.cc
+
+# Find the source files, if location was not specified.
+if test -z "$srcdir"; then
+ srcdirdefaulted=yes
+ # Try the directory containing this script, then `..'.
+ prog=$0
+ confdir=`echo $prog|sed 's%/[^/][^/]*$%%'`
+ test "X$confdir" = "X$prog" && confdir=.
+ srcdir=$confdir
+ if test ! -r $srcdir/$unique_file; then
+ srcdir=..
+ fi
+fi
+if test ! -r $srcdir/$unique_file; then
+ if test x$srcdirdefaulted = xyes; then
+ echo "configure: Can not find sources in \`${confdir}' or \`..'." 1>&2
+ else
+ echo "configure: Can not find sources in \`${srcdir}'." 1>&2
+ fi
+ exit 1
+fi
+# Preserve a srcdir of `.' to avoid automounter screwups with pwd.
+# But we can't avoid them for `..', to make subdirectories work.
+case $srcdir in
+ .|/*|~*) ;;
+ *) srcdir=`cd $srcdir; pwd` ;; # Make relative path absolute.
+esac
+
+
+# Save the original args to write them into config.status later.
+configure_args="$*"
+
+if test -z "$prefix"
+then
+ echo checking for grops to derive installation directory prefix
+ IFS="${IFS= }"; saveifs="$IFS"; IFS="$IFS:"
+ for dir in $PATH; do
+ test -z "$dir" && dir=.
+ if test $dir != . && test -f $dir/grops; then
+ # Not all systems have dirname.
+ prefix=`echo $dir|sed 's%/[^/][^/]*$%%'`
+ break
+ fi
+ done
+ IFS="$saveifs"
+ echo " chose installation directory prefix ${prefix}"
+fi
+if test -z "$prefix"
+then
+ echo checking for gcc to derive installation directory prefix
+ IFS="${IFS= }"; saveifs="$IFS"; IFS="$IFS:"
+ for dir in $PATH; do
+ test -z "$dir" && dir=.
+ if test $dir != . && test -f $dir/gcc; then
+ # Not all systems have dirname.
+ prefix=`echo $dir|sed 's%/[^/][^/]*$%%'`
+ break
+ fi
+ done
+ IFS="$saveifs"
+ echo " chose installation directory prefix ${prefix}"
+fi
+
+if test -z "$CC"; then
+ # Extract the first word of `gcc', so it can be a program name with args.
+ set dummy gcc; word=$2
+ echo checking for $word
+ IFS="${IFS= }"; saveifs="$IFS"; IFS="${IFS}:"
+ for dir in $PATH; do
+ test -z "$dir" && dir=.
+ if test -f $dir/$word; then
+ CC="gcc"
+ break
+ fi
+ done
+ IFS="$saveifs"
+fi
+test -z "$CC" && CC="cc"
+test -n "$CC" && test -n "$verbose" && echo " setting CC to $CC"
+
+# Find out if we are using GNU C, under whatever name.
+cat > conftest.c <<EOF
+#ifdef __GNUC__
+ yes
+#endif
+EOF
+${CC-cc} -E conftest.c > conftest.out 2>&1
+if egrep yes conftest.out >/dev/null 2>&1; then
+ GCC=1 # For later tests.
+fi
+rm -f conftest*
+
+cc_compile='$CCC conftest.cc -o conftest $CCLIBS $LIBS >/dev/null 2>&1'
+
+if test -z "$CCC"; then
+# See whether the C compiler is also a C++ compiler.
+echo checking if C compiler is also a C++ compiler
+cat <<EOF > conftest.cc
+#ifdef __cplusplus
+ yes
+#endif
+EOF
+$CC -E conftest.cc >conftest.out 2>&1
+if egrep yes conftest.out >/dev/null 2>&1; then
+ CCC="$CC"
+fi
+fi
+if test -z "$CCC"; then
+ # Extract the first word of `g++', so it can be a program name with args.
+ set dummy g++; word=$2
+ echo checking for $word
+ IFS="${IFS= }"; saveifs="$IFS"; IFS="${IFS}:"
+ for dir in $PATH; do
+ test -z "$dir" && dir=.
+ if test -f $dir/$word; then
+ CCC="g++"
+ break
+ fi
+ done
+ IFS="$saveifs"
+fi
+
+test -n "$CCC" && test -n "$verbose" && echo " setting CCC to $CCC"
+
+if test -z "$CCC"; then
+ # Extract the first word of `CC', so it can be a program name with args.
+ set dummy CC; word=$2
+ echo checking for $word
+ IFS="${IFS= }"; saveifs="$IFS"; IFS="${IFS}:"
+ for dir in $PATH; do
+ test -z "$dir" && dir=.
+ if test -f $dir/$word; then
+ CCC="CC"
+ break
+ fi
+ done
+ IFS="$saveifs"
+fi
+
+test -n "$CCC" && test -n "$verbose" && echo " setting CCC to $CCC"
+
+if test -z "$CCC"; then
+ # Extract the first word of `cc++', so it can be a program name with args.
+ set dummy cc++; word=$2
+ echo checking for $word
+ IFS="${IFS= }"; saveifs="$IFS"; IFS="${IFS}:"
+ for dir in $PATH; do
+ test -z "$dir" && dir=.
+ if test -f $dir/$word; then
+ CCC="cc++"
+ break
+ fi
+ done
+ IFS="$saveifs"
+fi
+
+test -n "$CCC" && test -n "$verbose" && echo " setting CCC to $CCC"
+
+if test -z "$CCC"; then
+cat <<EOM
+This package requires a C++ compiler, but I couldn't find one.
+Set the environment variable CCC to the name of your C++ compiler.
+EOM
+rm -f conftest* core; exit 1
+fi
+echo checking that C++ compiler can compile very simple C++ program
+cat <<EOF > conftest.cc
+
+int main() { return 0; }
+
+EOF
+rm -f conftest
+eval $cc_compile
+if test -s conftest && (./conftest) 2>/dev/null; then
+ :
+else
+ cat <<EOM
+$CCC was unable successfully to compile a very simple C++ program
+(the C++ program was in a file with a suffix of .cc)
+EOM
+rm -f conftest* core; exit 1
+
+fi
+rm -f conftest*
+echo checking that C++ static constructors and destructors are called
+cat <<EOF > conftest.cc
+
+extern "C" {
+ void _exit(int);
+}
+int i;
+struct A {
+ char dummy;
+ A() { i = 1; }
+ ~A() { if (i == 1) _exit(0); }
+};
+A a;
+int main() { return 1; }
+
+EOF
+rm -f conftest
+eval $cc_compile
+if test -s conftest && (./conftest) 2>/dev/null; then
+ :
+else
+ cat <<EOM
+$CCC is not installed correctly: static constructors and destructors do not work
+EOM
+rm -f conftest* core; exit 1
+
+fi
+rm -f conftest*
+echo checking for C++ header files
+cat <<EOF >conftest.cc
+#include <stdio.h>
+int main() { return 0; } void t() { fopen(0, 0); }
+EOF
+if eval $cc_compile; then
+ :
+else
+ cat <<\EOF
+Your header files do not appear to support C++.
+I was unable to compile and link a simple C++ program that used a function
+declared in <stdio.h>.
+If you're using a version of gcc/g++ earlier than 2.5,
+you should install libg++.
+EOF
+rm -f conftest* core; exit 1
+fi
+rm -f conftest*
+if test -z "$PSPRINT"
+then
+ for p in lpr
+do
+if test -z "$LPR"; then
+ # Extract the first word of `$p', so it can be a program name with args.
+ set dummy $p; word=$2
+ echo checking for $word
+ IFS="${IFS= }"; saveifs="$IFS"; IFS="${IFS}:"
+ for dir in $PATH; do
+ test -z "$dir" && dir=.
+ if test -f $dir/$word; then
+ LPR="$p"
+ break
+ fi
+ done
+ IFS="$saveifs"
+fi
+
+test -n "$LPR" && test -n "$verbose" && echo " setting LPR to $LPR"
+
+test -n "$LPR" && break
+done
+
+ for p in lp
+do
+if test -z "$LP"; then
+ # Extract the first word of `$p', so it can be a program name with args.
+ set dummy $p; word=$2
+ echo checking for $word
+ IFS="${IFS= }"; saveifs="$IFS"; IFS="${IFS}:"
+ for dir in $PATH; do
+ test -z "$dir" && dir=.
+ if test -f $dir/$word; then
+ LP="$p"
+ break
+ fi
+ done
+ IFS="$saveifs"
+fi
+
+test -n "$LP" && test -n "$verbose" && echo " setting LP to $LP"
+
+test -n "$LP" && break
+done
+
+ if test -n "$LPR" && test -n "$LP"
+ then
+ # HP-UX provides an lpr command that emulates lpr using lp,
+ # but it doesn't have lpq; in this case we want to use lp
+ # rather than lpr.
+ for p in lpq
+do
+if test -z "$LPQ"; then
+ # Extract the first word of `$p', so it can be a program name with args.
+ set dummy $p; word=$2
+ echo checking for $word
+ IFS="${IFS= }"; saveifs="$IFS"; IFS="${IFS}:"
+ for dir in $PATH; do
+ test -z "$dir" && dir=.
+ if test -f $dir/$word; then
+ LPQ="$p"
+ break
+ fi
+ done
+ IFS="$saveifs"
+fi
+
+test -n "$LPQ" && test -n "$verbose" && echo " setting LPQ to $LPQ"
+
+test -n "$LPQ" && break
+done
+
+ test -n "$LPQ" || LPR=
+ fi
+ if test -n "$LPR"
+ then
+ PSPRINT="$LPR"
+ elif test -n "$LP"
+ then
+ PSPRINT="$LP"
+ fi
+fi
+
+# Figure out DVIPRINT from PSPRINT.
+if test -n "$PSPRINT" && test -z "$DVIPRINT"
+then
+ if test "X$PSPRINT" = "Xlpr"
+ then
+ DVIPRINT="lpr -d"
+ else
+ DVIPRINT="$PSPRINT"
+ fi
+fi
+
+echo checking for perl
+PERLPATH=
+saveifs="$IFS"; IFS="${IFS}:"
+for dir in $PATH; do
+ test -z "$dir" && dir=.
+ if test -f $dir/perl; then
+ PERLPATH="$dir/perl"
+ break
+ fi
+done
+IFS="$saveifs"
+
+if test -z "$YACC"; then
+ # Extract the first word of `byacc', so it can be a program name with args.
+ set dummy byacc; word=$2
+ echo checking for $word
+ IFS="${IFS= }"; saveifs="$IFS"; IFS="${IFS}:"
+ for dir in $PATH; do
+ test -z "$dir" && dir=.
+ if test -f $dir/$word; then
+ YACC="byacc"
+ break
+ fi
+ done
+ IFS="$saveifs"
+fi
+
+test -n "$YACC" && test -n "$verbose" && echo " setting YACC to $YACC"
+
+if test -z "$YACC"; then
+ # Extract the first word of `bison', so it can be a program name with args.
+ set dummy bison; word=$2
+ echo checking for $word
+ IFS="${IFS= }"; saveifs="$IFS"; IFS="${IFS}:"
+ for dir in $PATH; do
+ test -z "$dir" && dir=.
+ if test -f $dir/$word; then
+ YACC="bison -y"
+ break
+ fi
+ done
+ IFS="$saveifs"
+fi
+test -z "$YACC" && YACC="yacc"
+test -n "$YACC" && test -n "$verbose" && echo " setting YACC to $YACC"
+
+
+if test -z "$RANLIB"; then
+ # Extract the first word of `ranlib', so it can be a program name with args.
+ set dummy ranlib; word=$2
+ echo checking for $word
+ IFS="${IFS= }"; saveifs="$IFS"; IFS="${IFS}:"
+ for dir in $PATH; do
+ test -z "$dir" && dir=.
+ if test -f $dir/$word; then
+ RANLIB="ranlib"
+ break
+ fi
+ done
+ IFS="$saveifs"
+fi
+test -z "$RANLIB" && RANLIB=":"
+test -n "$RANLIB" && test -n "$verbose" && echo " setting RANLIB to $RANLIB"
+
+# Make sure to not get the incompatible SysV /etc/install and
+# /usr/sbin/install, which might be in PATH before a BSD-like install,
+# or the SunOS /usr/etc/install directory, or the AIX /bin/install,
+# or the AFS install, which mishandles nonexistent args, or
+# /usr/ucb/install on SVR4, which tries to use the nonexistent group
+# `staff'. On most BSDish systems install is in /usr/bin, not /usr/ucb
+# anyway. Sigh.
+if test "z${INSTALL}" = "z" ; then
+ echo checking for install
+ IFS="${IFS= }"; saveifs="$IFS"; IFS="${IFS}:"
+ for dir in $PATH; do
+ test -z "$dir" && dir=.
+ case $dir in
+ /etc|/usr/sbin|/usr/etc|/usr/afsws/bin|/usr/ucb) ;;
+ *)
+ if test -f $dir/installbsd; then
+ INSTALL="$dir/installbsd -c" # OSF1
+ INSTALL_PROGRAM='$(INSTALL)'
+ INSTALL_DATA='$(INSTALL) -m 644'
+ break
+ fi
+ if test -f $dir/install; then
+ if grep dspmsg $dir/install >/dev/null 2>&1; then
+ : # AIX
+ else
+ INSTALL="$dir/install -c"
+ INSTALL_PROGRAM='$(INSTALL)'
+ INSTALL_DATA='$(INSTALL) -m 644'
+ break
+ fi
+ fi
+ ;;
+ esac
+ done
+ IFS="$saveifs"
+fi
+INSTALL=${INSTALL-cp}
+test -n "$verbose" && echo " setting INSTALL to $INSTALL"
+INSTALL_PROGRAM=${INSTALL_PROGRAM-'$(INSTALL)'}
+test -n "$verbose" && echo " setting INSTALL_PROGRAM to $INSTALL_PROGRAM"
+INSTALL_DATA=${INSTALL_DATA-'$(INSTALL)'}
+test -n "$verbose" && echo " setting INSTALL_DATA to $INSTALL_DATA"
+
+echo checking for ln -s
+rm -f conftestdata
+if ln -s X conftestdata 2>/dev/null
+then
+ rm -f conftestdata
+ LN_S="ln -s"
+else
+ LN_S=ln
+fi
+
+
+echo checking for etags C++ option
+for flag in p C
+do
+ test -z "$ETAGSCCFLAG" || break
+ >conftest.c
+ (etags -$flag -o /dev/null conftest.c >/dev/null 2>&1) 2>/dev/null &&
+ ETAGSCCFLAG="-$flag"
+ rm -f conftest.c
+done
+
+echo 'checking for csh # hack'
+cat <<EOF >conftest.sh
+#!/bin/sh
+true || exit 0
+export PATH || exit 0
+exit 1
+EOF
+chmod +x conftest.sh
+if echo ./conftest.sh | (csh >/dev/null 2>&1) >/dev/null 2>&1
+then
+ :; SH_SCRIPT_SED_CMD='1s/.*/:/'
+else
+ :; SH_SCRIPT_SED_CMD=''
+fi
+rm -f conftest.sh
+
+
+for hdr in unistd.h dirent.h limits.h sys/dir.h stdlib.h
+do
+trhdr=HAVE_`echo $hdr | tr '[a-z]./' '[A-Z]__'`
+echo checking for ${hdr}
+echo checking how to run the C preprocessor
+if test -z "$CPP"; then
+ # This must be in double quotes, not single quotes, because CPP may get
+ # substituted into the Makefile and ``${CC-cc}'' will simply confuse
+ # make. It must be expanded now.
+ CPP="${CC-cc} -E"
+ cat > conftest.c <<EOF
+#include "confdefs.h"
+#include <stdio.h>
+Syntax Error
+EOF
+err=`eval "($CPP conftest.c >/dev/null) 2>&1"`
+if test -z "$err"; then
+ :
+else
+ rm -rf conftest*
+ CPP=/lib/cpp
+fi
+rm -f conftest*
+fi
+test ".${verbose}" != "." && echo " setting CPP to $CPP"
+
+cat > conftest.c <<EOF
+#include "confdefs.h"
+#include <${hdr}>
+EOF
+err=`eval "($CPP conftest.c >/dev/null) 2>&1"`
+if test -z "$err"; then
+ rm -rf conftest*
+
+{
+test -n "$verbose" && \
+echo " defining ${trhdr}"
+echo "#define" ${trhdr} 1 >> confdefs.h
+DEFS="$DEFS -D${trhdr}=1"
+}
+
+
+fi
+rm -f conftest*
+done
+
+echo 'checking for ISC 3.x or 4.x'
+if grep '[34]\.' /usr/options/cb.name >/dev/null 2>&1
+then
+
+{
+test -n "$verbose" && \
+echo " defining _SYSV3"
+echo "#define" _SYSV3 1 >> confdefs.h
+DEFS="$DEFS -D_SYSV3=1"
+}
+
+fi
+echo checking for whether -D_POSIX_SOURCE is necessary
+cat <<EOF >conftest.cc
+#include <stdio.h>
+int main() { return 0; } void t() { (void)fileno(stdin); }
+EOF
+if eval $cc_compile; then
+ :
+else
+
+{
+test -n "$verbose" && \
+echo " defining _POSIX_SOURCE"
+echo "#define" _POSIX_SOURCE 1 >> confdefs.h
+DEFS="$DEFS -D_POSIX_SOURCE=1"
+}
+
+fi
+rm -f conftest*
+echo checking for 'C++ <limits.h>'
+cat <<EOF >conftest.cc
+#include <limits.h>
+int main() { return 0; } void t() { int x = INT_MIN; int y = INT_MAX; int z = UCHAR_MAX; }
+EOF
+if eval $cc_compile; then
+
+{
+test -n "$verbose" && \
+echo " defining HAVE_CC_LIMITS_H"
+echo "#define" HAVE_CC_LIMITS_H 1 >> confdefs.h
+DEFS="$DEFS -DHAVE_CC_LIMITS_H=1"
+}
+
+fi
+rm -f conftest*
+echo checking for 'C++ <osfcn.h>'
+cat <<EOF >conftest.cc
+#include <osfcn.h>
+int main() { return 0; } void t() { read(0, 0, 0); open(0, 0); }
+EOF
+if eval $cc_compile; then
+
+{
+test -n "$verbose" && \
+echo " defining HAVE_CC_OSFCN_H"
+echo "#define" HAVE_CC_OSFCN_H 1 >> confdefs.h
+DEFS="$DEFS -DHAVE_CC_OSFCN_H=1"
+}
+
+fi
+rm -f conftest*
+echo checking for declaration of getopt in stdlib.h
+cat <<EOF >conftest.cc
+#include <stdlib.h>
+extern "C" { void getopt(int); }
+int main() { return 0; } void t() { }
+EOF
+if eval $cc_compile; then
+ :
+else
+
+{
+test -n "$verbose" && \
+echo " defining STDLIB_H_DECLARES_GETOPT"
+echo "#define" STDLIB_H_DECLARES_GETOPT 1 >> confdefs.h
+DEFS="$DEFS -DSTDLIB_H_DECLARES_GETOPT=1"
+}
+
+fi
+rm -f conftest*
+echo checking for declaration of getopt in unistd.h
+cat <<EOF >conftest.cc
+#include <sys/types.h>
+#include <unistd.h>
+extern "C" { void getopt(int); }
+int main() { return 0; } void t() { }
+EOF
+if eval $cc_compile; then
+ :
+else
+
+{
+test -n "$verbose" && \
+echo " defining UNISTD_H_DECLARES_GETOPT"
+echo "#define" UNISTD_H_DECLARES_GETOPT 1 >> confdefs.h
+DEFS="$DEFS -DUNISTD_H_DECLARES_GETOPT=1"
+}
+
+fi
+rm -f conftest*
+
+echo checking for declaration of putenv
+cat <<EOF >conftest.cc
+#include <stdlib.h>
+extern "C" { void putenv(int); }
+int main() { return 0; } void t() { }
+EOF
+if eval $cc_compile; then
+ :
+else
+
+{
+test -n "$verbose" && \
+echo " defining STDLIB_H_DECLARES_PUTENV"
+echo "#define" STDLIB_H_DECLARES_PUTENV 1 >> confdefs.h
+DEFS="$DEFS -DSTDLIB_H_DECLARES_PUTENV=1"
+}
+
+fi
+rm -f conftest*
+echo checking for declaration of popen
+cat <<EOF >conftest.cc
+#include <stdio.h>
+extern "C" { void popen(int); }
+int main() { return 0; } void t() { }
+EOF
+if eval $cc_compile; then
+ :
+else
+
+{
+test -n "$verbose" && \
+echo " defining STDIO_H_DECLARES_POPEN"
+echo "#define" STDIO_H_DECLARES_POPEN 1 >> confdefs.h
+DEFS="$DEFS -DSTDIO_H_DECLARES_POPEN=1"
+}
+
+fi
+rm -f conftest*
+echo checking for declaration of pclose
+cat <<EOF >conftest.cc
+#include <stdio.h>
+extern "C" { void pclose(int); }
+int main() { return 0; } void t() { }
+EOF
+if eval $cc_compile; then
+ :
+else
+
+{
+test -n "$verbose" && \
+echo " defining STDIO_H_DECLARES_PCLOSE"
+echo "#define" STDIO_H_DECLARES_PCLOSE 1 >> confdefs.h
+DEFS="$DEFS -DSTDIO_H_DECLARES_PCLOSE=1"
+}
+
+fi
+rm -f conftest*
+echo checking for time_t
+cat <<EOF >conftest.cc
+#include <time.h>
+int main() { return 0; } void t() { time_t t = time(0); struct tm *p = localtime(&t); }
+EOF
+if eval $cc_compile; then
+ :
+else
+
+{
+test -n "$verbose" && \
+echo " defining LONG_FOR_TIME_T"
+echo "#define" LONG_FOR_TIME_T 1 >> confdefs.h
+DEFS="$DEFS -DLONG_FOR_TIME_T=1"
+}
+
+fi
+rm -f conftest*
+echo checking for return type of signal handlers
+cat > conftest.c <<EOF
+#include "confdefs.h"
+#include <sys/types.h>
+#include <signal.h>
+#ifdef signal
+#undef signal
+#endif
+extern void (*signal ()) ();
+int main() { exit(0); }
+int t() { int i; }
+EOF
+if eval $compile; then
+ rm -rf conftest*
+
+{
+test -n "$verbose" && \
+echo " defining" RETSIGTYPE to be void
+echo "#define" RETSIGTYPE void >> confdefs.h
+DEFS="$DEFS -DRETSIGTYPE=void"
+}
+
+
+else
+ rm -rf conftest*
+
+{
+test -n "$verbose" && \
+echo " defining" RETSIGTYPE to be int
+echo "#define" RETSIGTYPE int >> confdefs.h
+DEFS="$DEFS -DRETSIGTYPE=int"
+}
+
+fi
+rm -f conftest*
+
+
+echo checking for struct exception
+cat > conftest.c <<EOF
+#include "confdefs.h"
+#include <math.h>
+int main() { exit(0); }
+int t() { struct exception e; }
+EOF
+if eval $compile; then
+ rm -rf conftest*
+
+{
+test -n "$verbose" && \
+echo " defining HAVE_STRUCT_EXCEPTION"
+echo "#define" HAVE_STRUCT_EXCEPTION 1 >> confdefs.h
+DEFS="$DEFS -DHAVE_STRUCT_EXCEPTION=1"
+}
+
+
+fi
+rm -f conftest*
+
+echo checking for mmap
+cat > conftest.c <<EOF
+#include "confdefs.h"
+#include <sys/types.h>
+#include <sys/mman.h>
+int main() { exit(0); }
+int t() { char *p = mmap(0, 0, PROT_READ, MAP_PRIVATE, 0, 0); munmap(p, 0); }
+EOF
+if eval $compile; then
+ rm -rf conftest*
+
+{
+test -n "$verbose" && \
+echo " defining HAVE_MMAP"
+echo "#define" HAVE_MMAP 1 >> confdefs.h
+DEFS="$DEFS -DHAVE_MMAP=1"
+}
+
+
+fi
+rm -f conftest*
+
+echo checking for pid_t in sys/types.h
+echo '#include "confdefs.h"
+#include <sys/types.h>' > conftest.c
+eval "$CPP conftest.c > conftest.out 2>&1"
+if egrep "pid_t" conftest.out >/dev/null 2>&1; then
+ :
+else
+ rm -rf conftest*
+
+{
+test -n "$verbose" && \
+echo " defining" pid_t to be int
+echo "#define" pid_t int >> confdefs.h
+DEFS="$DEFS -Dpid_t=int"
+}
+
+fi
+rm -f conftest*
+
+echo checking for vfork.h
+cat > conftest.c <<EOF
+#include "confdefs.h"
+#include <vfork.h>
+EOF
+err=`eval "($CPP conftest.c >/dev/null) 2>&1"`
+if test -z "$err"; then
+ rm -rf conftest*
+
+{
+test -n "$verbose" && \
+echo " defining HAVE_VFORK_H"
+echo "#define" HAVE_VFORK_H 1 >> confdefs.h
+DEFS="$DEFS -DHAVE_VFORK_H=1"
+}
+
+
+fi
+rm -f conftest*
+
+echo checking for working vfork
+
+cat > conftest.c <<EOF
+#include "confdefs.h"
+/* Thanks to Paul Eggert for this test. */
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <signal.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#ifdef HAVE_VFORK_H
+#include <vfork.h>
+#endif
+static int signalled;
+static RETSIGTYPE catch (s) int s; { signalled = 1; }
+main() {
+ pid_t parent = getpid ();
+ pid_t child;
+
+ signal (SIGINT, catch);
+
+ child = vfork ();
+
+ if (child == 0) {
+ /* On sparc systems, changes by the child to local and incoming
+ argument registers are propagated back to the parent.
+ The compiler is told about this with #include <vfork.h>,
+ but some compilers (e.g. gcc -O) don't grok <vfork.h>.
+ Test for this by using lots of local variables, at least
+ as many local variables as main has allocated so far
+ including compiler temporaries. 4 locals are enough for
+ gcc 1.40.3 on a sparc, but we use 8 to be safe.
+ A buggy compiler should reuse the register of parent
+ for one of the local variables, since it will think that
+ parent can't possibly be used any more in this routine.
+ Assigning to the local variable will thus munge parent
+ in the parent process. */
+ pid_t
+ p = getpid(), p1 = getpid(), p2 = getpid(), p3 = getpid(),
+ p4 = getpid(), p5 = getpid(), p6 = getpid(), p7 = getpid();
+ /* Convince the compiler that p..p7 are live; otherwise, it might
+ use the same hardware register for all 8 local variables. */
+ if (p != p1 || p != p2 || p != p3 || p != p4
+ || p != p5 || p != p6 || p != p7)
+ _exit(1);
+
+ /* On some systems (e.g. SunOS 5.2), if the parent is catching
+ a signal, the child ignores the signal before execing,
+ and the parent later receives that signal, the parent dumps core.
+ Test for this by ignoring SIGINT in the child. */
+ signal (SIGINT, SIG_IGN);
+
+ /* On some systems (e.g. IRIX 3.3),
+ vfork doesn't separate parent from child file descriptors.
+ If the child closes a descriptor before it execs or exits,
+ this munges the parent's descriptor as well.
+ Test for this by closing stdout in the child. */
+ _exit(close(fileno(stdout)) != 0);
+ } else {
+ int status;
+ struct stat st;
+
+ while (wait(&status) != child)
+ ;
+ exit(
+ /* Was there some problem with vforking? */
+ child < 0
+
+ /* Did the child fail? (This shouldn't happen.) */
+ || status
+
+ /* Did the vfork/compiler bug occur? */
+ || parent != getpid()
+
+ /* Did the signal handling bug occur? */
+ || kill(parent, SIGINT) != 0
+ || signalled != 1
+
+ /* Did the file descriptor bug occur? */
+ || fstat(fileno(stdout), &st) != 0
+ );
+ }
+}
+EOF
+eval $compile
+if test -s conftest && (./conftest; exit) 2>/dev/null; then
+ :
+else
+
+{
+test -n "$verbose" && \
+echo " defining" vfork to be fork
+echo "#define" vfork fork >> confdefs.h
+DEFS="$DEFS -Dvfork=fork"
+}
+
+fi
+rm -fr conftest*
+
+saved_libs="$LIBS"
+LIBS="$LIBS -lm"
+for func in fmod strtol getcwd strerror putenv
+do
+echo checking for ${func}
+cat > conftest.c <<EOF
+#include "confdefs.h"
+#include <ctype.h>
+int main() { exit(0); }
+int t() {
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_${func}) || defined (__stub___${func})
+choke me
+#else
+/* Override any gcc2 internal prototype to avoid an error. */
+extern char ${func}(); ${func}();
+#endif
+ }
+EOF
+if eval $compile; then
+ :
+else
+ rm -rf conftest*
+ LIBOBJS="$LIBOBJS ${func}.o"
+test -n "$verbose" && echo " using ${func}.o instead"
+fi
+rm -f conftest*
+
+done
+
+LIBS="$saved_libs"
+for func in rename mkstemp
+do
+trfunc=HAVE_`echo $func | tr '[a-z]' '[A-Z]'`
+echo checking for ${func}
+cat > conftest.c <<EOF
+#include "confdefs.h"
+#include <ctype.h>
+int main() { exit(0); }
+int t() {
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_${func}) || defined (__stub___${func})
+choke me
+#else
+/* Override any gcc2 internal prototype to avoid an error. */
+extern char ${func}(); ${func}();
+#endif
+ }
+EOF
+if eval $compile; then
+ rm -rf conftest*
+ {
+test -n "$verbose" && \
+echo " defining ${trfunc}"
+echo "#define" ${trfunc} 1 >> confdefs.h
+DEFS="$DEFS -D${trfunc}=1"
+}
+
+
+fi
+rm -f conftest*
+done
+
+echo checking for sys_siglist
+cat > conftest.c <<EOF
+#include "confdefs.h"
+
+int main() { exit(0); }
+int t() { extern char *sys_siglist[]; sys_siglist[0] = 0; }
+EOF
+if eval $compile; then
+ rm -rf conftest*
+
+{
+test -n "$verbose" && \
+echo " defining HAVE_SYS_SIGLIST"
+echo "#define" HAVE_SYS_SIGLIST 1 >> confdefs.h
+DEFS="$DEFS -DHAVE_SYS_SIGLIST=1"
+}
+
+
+fi
+rm -f conftest*
+
+echo checking for gcc/g++ delete bug
+cat <<EOF > conftest.cc
+
+#include <stdlib.h>
+#include <stddef.h>
+
+int testit = 0;
+
+int main()
+{
+ testit = 1;
+ int *p = new int;
+ delete p;
+ testit = 0;
+ return 1;
+}
+
+static unsigned dummy[3];
+
+void *operator new(size_t n)
+{
+ if (testit) {
+ dummy[1] = -(unsigned)(dummy + 2);
+ return dummy + 2;
+ }
+ else
+ return (void *)malloc(n);
+}
+
+void operator delete(void *p)
+{
+ if (testit) {
+ if (p == dummy)
+ exit(0);
+ }
+ else
+ free(p);
+}
+
+EOF
+rm -f conftest
+eval $cc_compile
+if test -s conftest && (./conftest) 2>/dev/null; then
+
+{
+test -n "$verbose" && \
+echo " defining COOKIE_BUG"
+echo "#define" COOKIE_BUG 1 >> confdefs.h
+DEFS="$DEFS -DCOOKIE_BUG=1"
+}
+
+fi
+rm -f conftest*
+echo checking for cfront ANSI C INT_MIN bug
+cat <<EOF > conftest.cc
+#include <stdlib.h>
+#ifdef HAVE_CC_LIMITS_H
+#include <limits.h>
+#else
+#define INT_MAX 2147483647
+#endif
+
+#undef INT_MIN
+#define INT_MIN (-INT_MAX-1)
+
+int main()
+{
+ int z = 0;
+ return INT_MIN < z;
+}
+
+EOF
+rm -f conftest
+eval $cc_compile
+if test -s conftest && (./conftest) 2>/dev/null; then
+
+{
+test -n "$verbose" && \
+echo " defining CFRONT_ANSI_BUG"
+echo "#define" CFRONT_ANSI_BUG 1 >> confdefs.h
+DEFS="$DEFS -DCFRONT_ANSI_BUG=1"
+}
+
+fi
+rm -f conftest*
+echo checking for new array delete syntax
+cat <<EOF >conftest.cc
+
+int main() { return 0; } void t() { char *p = new char[5]; delete [] p; }
+EOF
+if eval $cc_compile; then
+ :
+else
+
+{
+test -n "$verbose" && \
+echo " defining ARRAY_DELETE_NEEDS_SIZE"
+echo "#define" ARRAY_DELETE_NEEDS_SIZE 1 >> confdefs.h
+DEFS="$DEFS -DARRAY_DELETE_NEEDS_SIZE=1"
+}
+
+fi
+rm -f conftest*
+echo checking for traditional preprocessor
+cat <<EOF >conftest.cc
+#define name2(a,b) a/**/b
+int main() { return 0; } void t() { int name2(foo,bar); }
+EOF
+if eval $cc_compile; then
+
+{
+test -n "$verbose" && \
+echo " defining TRADITIONAL_CPP"
+echo "#define" TRADITIONAL_CPP 1 >> confdefs.h
+DEFS="$DEFS -DTRADITIONAL_CPP=1"
+}
+
+fi
+rm -f conftest*
+echo checking for w_coredump
+cat > conftest.c <<EOF
+#include "confdefs.h"
+
+#include <sys/types.h>
+#include <sys/wait.h>
+main()
+{
+#ifdef WCOREFLAG
+ exit(1);
+#else
+ int i = 0;
+ ((union wait *)&i)->w_coredump = 1;
+ exit(i != 0200);
+#endif
+}
+
+EOF
+eval $compile
+if test -s conftest && (./conftest; exit) 2>/dev/null; then
+
+{
+test -n "$verbose" && \
+echo " defining" WCOREFLAG to be 0200
+echo "#define" WCOREFLAG 0200 >> confdefs.h
+DEFS="$DEFS -DWCOREFLAG=0200"
+}
+
+
+fi
+rm -fr conftest*
+test -n "${BROKEN_SPOOLER_FLAGS}" || BROKEN_SPOOLER_FLAGS=7
+echo using default value of ${BROKEN_SPOOLER_FLAGS} for grops -b option
+
+
+if test -z "$PAGE" && test -r $prefix/lib/groff/font/devps/DESC
+then
+ if grep "^paperlength 841890" \
+ $prefix/lib/groff/font/devps/DESC >/dev/null 2>&1
+ then
+ PAGE=A4
+ else
+ PAGE=letter
+ fi
+fi
+if test -z "$PAGE"
+then
+ dom=`awk '($1 == "dom" || $1 == "search") { print $2; exit}' \
+ /etc/resolv.conf 2>/dev/null`
+
+ if test -z "$dom"
+ then
+ dom=`(domainname) 2>/dev/null | tr -d '+'`
+ if test -z "$dom"
+ then
+ dom=`(hostname) 2>/dev/null | grep '\.'`
+ fi
+ fi
+
+ # If the top-level domain is two letters and it's not `us' or `ca'
+ # then they probably use A4 paper.
+ case "$dom" in
+ *.[Uu][Ss]|*.[Cc][Aa]) ;;
+ *.[A-Za-z][A-Za-z]) PAGE=A4 ;;
+ esac
+fi
+test -n "$PAGE" || PAGE=letter
+echo guessing $PAGE size paper
+
+# Set default prefixes.
+if test -n "$prefix"; then
+ test -z "$exec_prefix" && exec_prefix='${prefix}'
+ prsub="s%^prefix\\([ ]*\\)=\\([ ]*\\).*$%prefix\\1=\\2$prefix%"
+fi
+if test -n "$exec_prefix"; then
+ prsub="$prsub
+s%^exec_prefix\\([ ]*\\)=\\([ ]*\\).*$%exec_prefix\\1=\\2$exec_prefix%"
+fi
+# Quote sed substitution magic chars in DEFS.
+cat >conftest.def <<EOF
+$DEFS
+EOF
+escape_ampersand_and_backslash='s%[&\\]%\\&%g'
+DEFS=`sed "$escape_ampersand_and_backslash" <conftest.def`
+rm -f conftest.def
+# Substitute for predefined variables.
+
+trap 'rm -f config.status; exit 1' 1 3 15
+echo creating config.status
+rm -f config.status
+cat > config.status <<EOF
+#!/bin/sh
+# Generated automatically by configure.
+# Run this file to recreate the current configuration.
+# This directory was configured as follows,
+# on host `(hostname || uname -n) 2>/dev/null | sed 1q`:
+#
+# $0 $configure_args
+
+for arg
+do
+ case "\$arg" in
+ -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
+ echo running \${CONFIG_SHELL-/bin/sh} $0 $configure_args
+ exec \${CONFIG_SHELL-/bin/sh} $0 $configure_args ;;
+ *) echo "Usage: config.status --recheck" 2>&1; exit 1 ;;
+ esac
+done
+
+trap 'rm -f Makefile; exit 1' 1 3 15
+CC='$CC'
+CCLIBS='$CCLIBS'
+CCC='$CCC'
+LPR='$LPR'
+LP='$LP'
+LPQ='$LPQ'
+PSPRINT='$PSPRINT'
+DVIPRINT='$DVIPRINT'
+PERLPATH='$PERLPATH'
+YACC='$YACC'
+RANLIB='$RANLIB'
+INSTALL='$INSTALL'
+INSTALL_PROGRAM='$INSTALL_PROGRAM'
+INSTALL_DATA='$INSTALL_DATA'
+LN_S='$LN_S'
+ETAGSCCFLAG='$ETAGSCCFLAG'
+SH_SCRIPT_SED_CMD='$SH_SCRIPT_SED_CMD'
+CPP='$CPP'
+LIBOBJS='$LIBOBJS'
+BROKEN_SPOOLER_FLAGS='$BROKEN_SPOOLER_FLAGS'
+PAGE='$PAGE'
+LIBS='$LIBS'
+srcdir='$srcdir'
+DEFS='$DEFS'
+prefix='$prefix'
+exec_prefix='$exec_prefix'
+prsub='$prsub'
+extrasub='$extrasub'
+EOF
+cat >> config.status <<\EOF
+
+top_srcdir=$srcdir
+
+CONFIG_FILES=${CONFIG_FILES-"Makefile"}
+for file in .. ${CONFIG_FILES}; do if test "x$file" != x..; then
+ srcdir=$top_srcdir
+ # Remove last slash and all that follows it. Not all systems have dirname.
+ dir=`echo $file|sed 's%/[^/][^/]*$%%'`
+ if test "$dir" != "$file"; then
+ test "$top_srcdir" != . && srcdir=$top_srcdir/$dir
+ test ! -d $dir && mkdir $dir
+ fi
+ echo creating $file
+ rm -f $file
+ echo "# Generated automatically from `echo $file|sed 's|.*/||'`.in by configure." > $file
+ sed -e "
+$prsub
+$extrasub
+s%@CC@%$CC%g
+s%@CCLIBS@%$CCLIBS%g
+s%@CCC@%$CCC%g
+s%@LPR@%$LPR%g
+s%@LP@%$LP%g
+s%@LPQ@%$LPQ%g
+s%@PSPRINT@%$PSPRINT%g
+s%@DVIPRINT@%$DVIPRINT%g
+s%@PERLPATH@%$PERLPATH%g
+s%@YACC@%$YACC%g
+s%@RANLIB@%$RANLIB%g
+s%@INSTALL@%$INSTALL%g
+s%@INSTALL_PROGRAM@%$INSTALL_PROGRAM%g
+s%@INSTALL_DATA@%$INSTALL_DATA%g
+s%@LN_S@%$LN_S%g
+s%@ETAGSCCFLAG@%$ETAGSCCFLAG%g
+s%@SH_SCRIPT_SED_CMD@%$SH_SCRIPT_SED_CMD%g
+s%@CPP@%$CPP%g
+s%@LIBOBJS@%$LIBOBJS%g
+s%@BROKEN_SPOOLER_FLAGS@%$BROKEN_SPOOLER_FLAGS%g
+s%@PAGE@%$PAGE%g
+s%@LIBS@%$LIBS%g
+s%@srcdir@%$srcdir%g
+s%@DEFS@%$DEFS%
+" $top_srcdir/${file}.in >> $file
+fi; done
+
+
+exit 0
+EOF
+chmod +x config.status
+${CONFIG_SHELL-/bin/sh} config.status
+
diff --git a/gnu/usr.bin/groff/configure.in b/gnu/usr.bin/groff/configure.in
new file mode 100644
index 0000000..fccb8c8
--- /dev/null
+++ b/gnu/usr.bin/groff/configure.in
@@ -0,0 +1,50 @@
+dnl Process this file with autoconf to produce a configure script.
+builtin([include],[acgroff.m4])dnl
+AC_INIT(groff/groff.cc)
+GROFF_PREFIX
+dnl checks for programs
+AC_PROG_CC
+GROFF_PROG_CCC
+GROFF_PRINT
+GROFF_PERL_PATH
+GROFF_PROG_YACC
+AC_PROG_RANLIB
+AC_PROG_INSTALL
+AC_LN_S
+GROFF_ETAGSCCFLAG
+GROFF_CSH_HACK(SH_SCRIPT_SED_CMD='1s/.*/:/', SH_SCRIPT_SED_CMD='')
+AC_SUBST(SH_SCRIPT_SED_CMD)
+dnl checks for headers
+AC_HAVE_HEADERS(unistd.h dirent.h limits.h sys/dir.h stdlib.h)
+GROFF_ISC_SYSV3
+GROFF_POSIX
+GROFF_LIMITS_H
+GROFF_OSFCN_H
+GROFF_GETOPT
+GROFF_PUTENV
+GROFF_POPEN
+GROFF_PCLOSE
+dnl checks for typedefs
+GROFF_TIME_T
+AC_RETSIGTYPE
+GROFF_STRUCT_EXCEPTION
+dnl checks for functions
+GROFF_MMAP
+AC_VFORK
+saved_libs="$LIBS"
+LIBS="$LIBS -lm"
+AC_REPLACE_FUNCS(fmod strtol getcwd strerror putenv)
+LIBS="$saved_libs"
+AC_HAVE_FUNCS(rename mkstemp)
+GROFF_SYS_SIGLIST
+dnl checks for compiler characteristics
+GROFF_COOKIE_BUG
+GROFF_CFRONT_ANSI_BUG
+GROFF_ARRAY_DELETE
+GROFF_TRADITIONAL_CPP
+dnl checks for operating system services
+GROFF_WCOREFLAG
+dnl other random stuff
+GROFF_BROKEN_SPOOLER_FLAGS
+GROFF_PAGE
+AC_OUTPUT(Makefile)
diff --git a/gnu/usr.bin/groff/devX100-12/CB b/gnu/usr.bin/groff/devX100-12/CB
new file mode 100644
index 0000000..3751184a
--- /dev/null
+++ b/gnu/usr.bin/groff/devX100-12/CB
@@ -0,0 +1,306 @@
+name CB
+spacewidth 10
+charset
+--- 10,1 0 040
+! 10,11 0 041
+" 10,11 0 042
+# 10,11,1 0 043
+sh "
+$ 10,12,1 0 044
+Do "
+% 10,11 0 045
+& 10,9 0 046
+' 10,11 0 047
+( 10,11,2 0 050
+) 10,11,2 0 051
+* 10,11 0 052
++ 10,9 0 053
+, 10,2,3 0 054
+\- 10,6 0 055
+. 10,2 0 056
+/ 10,12,2 0 057
+sl "
+0 10,11 0 060
+1 10,11 0 061
+2 10,11 0 062
+3 10,11 0 063
+4 10,11 0 064
+5 10,11 0 065
+6 10,11 0 066
+7 10,11 0 067
+8 10,11 0 070
+9 10,11 0 071
+: 10,7 0 072
+; 10,7,3 0 073
+< 10,9 0 074
+= 10,7 0 075
+eq "
+> 10,9 0 076
+? 10,10 0 077
+@ 10,11,1 0 0100
+at "
+A 10,10 0 0101
+B 10,10 0 0102
+C 10,10 0 0103
+D 10,10 0 0104
+E 10,10 0 0105
+F 10,10 0 0106
+G 10,10 0 0107
+H 10,10 0 0110
+I 10,10 0 0111
+J 10,10 0 0112
+K 10,10 0 0113
+L 10,10 0 0114
+M 10,10 0 0115
+N 10,10 0 0116
+O 10,10 0 0117
+P 10,10 0 0120
+Q 10,10,2 0 0121
+R 10,10 0 0122
+S 10,10 0 0123
+T 10,10 0 0124
+U 10,10 0 0125
+V 10,10 0 0126
+W 10,10 0 0127
+X 10,10 0 0130
+Y 10,10 0 0131
+Z 10,10 0 0132
+[ 10,11,2 0 0133
+lB "
+\ 10,12,2 0 0134
+rs "
+] 10,11,2 0 0135
+rB "
+^ 10,11 0 0136
+a^ "
+ha "
+_ 10,0,3 0 0137
+` 10,11 0 0140
+oq "
+a 10,7 0 0141
+b 10,11 0 0142
+c 10,7 0 0143
+d 10,11 0 0144
+e 10,7 0 0145
+f 10,11 0 0146
+g 10,7,3 0 0147
+h 10,11 0 0150
+i 10,10 0 0151
+j 10,10,3 0 0152
+k 10,11 0 0153
+l 10,11 0 0154
+m 10,7 0 0155
+n 10,7 0 0156
+o 10,7 0 0157
+p 10,7,3 0 0160
+q 10,7,3 0 0161
+r 10,7 0 0162
+s 10,7 0 0163
+t 10,9 0 0164
+u 10,7 0 0165
+v 10,7 0 0166
+w 10,7 0 0167
+x 10,7 0 0170
+y 10,7,3 0 0171
+z 10,7 0 0172
+{ 10,11,2 0 0173
+lC "
+| 10,11,2 0 0174
+or "
+ba "
+} 10,11,2 0 0175
+rC "
+~ 10,6 0 0176
+a~ "
+ap "
+ti "
+r! 10,7,3 0 0241
+¡ "
+ct 10,10 0 0242
+¢ "
+Po 10,10 0 0243
+£ "
+Cs 10,8 0 0244
+¤ "
+Ye 10,10 0 0245
+¥ "
+bb 10,11,2 0 0246
+¦ "
+sc 10,11,1 0 0247
+§ "
+ad 10,10 0 0250
+¨ "
+co 10,10 0 0251
+© "
+Of 10,10 0 0252
+ª "
+Fo 10,7 0 0253
+« "
+no 10,7 0 0254
+¬ "
+- 10,6 0 0255
+hy "
+­ "
+rg 10,10 0 0256
+® "
+a- 10,10 0 0257
+¯ "
+de 10,11 0 0260
+° "
++- 10,9 0 0261
+± "
+S2 10,11 0 0262
+² "
+S3 10,11 0 0263
+³ "
+aa 10,11 0 0264
+´ "
+µ 10,7,3 0 0265
+ps 10,11,1 0 0266
+¶ "
+md 10,6 0 0267
+· "
+ac 10,1,3 0 0270
+¸ "
+S1 10,11 0 0271
+¹ "
+Om 10,10 0 0272
+º "
+Fc 10,7 0 0273
+» "
+14 10,11 0 0274
+¼ "
+12 10,11 0 0275
+½ "
+34 10,11 0 0276
+¾ "
+r? 10,7,3 0 0277
+¿ "
+`A 10,14 0 0300
+À "
+'A 10,14 0 0301
+Á "
+^A 10,14 0 0302
+Â "
+~A 10,13 0 0303
+Ã "
+:A 10,13 0 0304
+Ä "
+oA 10,14 0 0305
+Å "
+AE 10,10 0 0306
+Æ "
+,C 10,10,3 0 0307
+Ç "
+`E 10,14 0 0310
+È "
+'E 10,14 0 0311
+É "
+^E 10,14 0 0312
+Ê "
+:E 10,13 0 0313
+Ë "
+`I 10,14 0 0314
+Ì "
+'I 10,14 0 0315
+Í "
+^I 10,14 0 0316
+Î "
+:I 10,13 0 0317
+Ï "
+-D 10,10 0 0320
+Ð "
+~N 10,13 0 0321
+Ñ "
+`O 10,14 0 0322
+Ò "
+'O 10,14 0 0323
+Ó "
+^O 10,14 0 0324
+Ô "
+~O 10,13 0 0325
+Õ "
+:O 10,13 0 0326
+Ö "
+mu 10,8 0 0327
+× "
+/O 10,11,1 0 0330
+Ø "
+`U 10,14 0 0331
+Ù "
+'U 10,14 0 0332
+Ú "
+^U 10,14 0 0333
+Û "
+:U 10,13 0 0334
+Ü "
+'Y 10,14 0 0335
+Ý "
+TP 10,10 0 0336
+Þ "
+ss 10,11 0 0337
+ß "
+`a 10,11 0 0340
+à "
+'a 10,11 0 0341
+á "
+^a 10,11 0 0342
+â "
+~a 10,10 0 0343
+ã "
+:a 10,10 0 0344
+ä "
+oa 10,12 0 0345
+å "
+ae 10,7 0 0346
+æ "
+,c 10,7,3 0 0347
+ç "
+`e 10,11 0 0350
+è "
+'e 10,11 0 0351
+é "
+^e 10,11 0 0352
+ê "
+:e 10,10 0 0353
+ë "
+`i 10,11 0 0354
+ì "
+'i 10,11 0 0355
+í "
+^i 10,11 0 0356
+î "
+:i 10,10 0 0357
+ï "
+Sd 10,12 0 0360
+ð "
+~n 10,10 0 0361
+ñ "
+`o 10,11 0 0362
+ò "
+'o 10,11 0 0363
+ó "
+^o 10,11 0 0364
+ô "
+~o 10,10 0 0365
+õ "
+:o 10,10 0 0366
+ö "
+di 10,9 0 0367
+÷ "
+/o 10,8,1 0 0370
+ø "
+`u 10,11 0 0371
+ù "
+'u 10,11 0 0372
+ú "
+^u 10,11 0 0373
+û "
+:u 10,10 0 0374
+ü "
+'y 10,11,3 0 0375
+ý "
+Tp 10,11,3 0 0376
+þ "
+:y 10,10,3 0 0377
+ÿ "
diff --git a/gnu/usr.bin/groff/devX100-12/CBI b/gnu/usr.bin/groff/devX100-12/CBI
new file mode 100644
index 0000000..d7d0145
--- /dev/null
+++ b/gnu/usr.bin/groff/devX100-12/CBI
@@ -0,0 +1,306 @@
+name CBI
+spacewidth 10
+charset
+--- 10,1 0 040
+! 10,11 0 041
+" 10,11 0 042
+# 10,11,1 0 043
+sh "
+$ 10,12,1 0 044
+Do "
+% 10,11 0 045
+& 10,9 0 046
+' 10,11 0 047
+( 10,11,2 0 050
+) 10,11,2 0 051
+* 10,11 0 052
++ 10,9 0 053
+, 10,2,3 0 054
+\- 10,6 0 055
+. 10,2 0 056
+/ 10,12,2 0 057
+sl "
+0 10,11 0 060
+1 10,11 0 061
+2 10,11 0 062
+3 10,11 0 063
+4 10,11 0 064
+5 10,11 0 065
+6 10,11 0 066
+7 10,11 0 067
+8 10,11 0 070
+9 10,11 0 071
+: 10,7 0 072
+; 10,7,3 0 073
+< 10,9 0 074
+= 10,7 0 075
+eq "
+> 10,9 0 076
+? 10,10 0 077
+@ 10,11,1 0 0100
+at "
+A 10,10 0 0101
+B 10,10 0 0102
+C 10,10 0 0103
+D 10,10 0 0104
+E 10,10 0 0105
+F 10,10 0 0106
+G 10,10 0 0107
+H 10,10 0 0110
+I 10,10 0 0111
+J 10,10 0 0112
+K 10,10 0 0113
+L 10,10 0 0114
+M 10,10 0 0115
+N 10,10 0 0116
+O 10,10 0 0117
+P 10,10 0 0120
+Q 10,10,2 0 0121
+R 10,10 0 0122
+S 10,10 0 0123
+T 10,10 0 0124
+U 10,10 0 0125
+V 10,10 0 0126
+W 10,10 0 0127
+X 10,10 0 0130
+Y 10,10 0 0131
+Z 10,10 0 0132
+[ 10,11,2 0 0133
+lB "
+\ 10,12,2 0 0134
+rs "
+] 10,11,2 0 0135
+rB "
+^ 10,11 0 0136
+a^ "
+ha "
+_ 10,0,3 0 0137
+` 10,11 0 0140
+oq "
+a 10,7 0 0141
+b 10,11 0 0142
+c 10,7 0 0143
+d 10,11 0 0144
+e 10,7 0 0145
+f 10,11 0 0146
+g 10,7,3 0 0147
+h 10,11 0 0150
+i 10,10 0 0151
+j 10,10,3 0 0152
+k 10,11 0 0153
+l 10,11 0 0154
+m 10,7 0 0155
+n 10,7 0 0156
+o 10,7 0 0157
+p 10,7,3 0 0160
+q 10,7,3 0 0161
+r 10,7 0 0162
+s 10,7 0 0163
+t 10,9 0 0164
+u 10,7 0 0165
+v 10,7 0 0166
+w 10,7 0 0167
+x 10,7 0 0170
+y 10,7,3 0 0171
+z 10,7 0 0172
+{ 10,11,2 0 0173
+lC "
+| 10,11,2 0 0174
+or "
+ba "
+} 10,11,2 0 0175
+rC "
+~ 10,6 0 0176
+a~ "
+ap "
+ti "
+r! 10,7,4 0 0241
+¡ "
+ct 10,10 0 0242
+¢ "
+Po 10,10 0 0243
+£ "
+Cs 10,8 0 0244
+¤ "
+Ye 10,10 0 0245
+¥ "
+bb 10,11,2 0 0246
+¦ "
+sc 10,11,1 0 0247
+§ "
+ad 10,10 0 0250
+¨ "
+co 10,10 0 0251
+© "
+Of 10,10 0 0252
+ª "
+Fo 10,7 0 0253
+« "
+no 10,7 0 0254
+¬ "
+- 10,6 0 0255
+hy "
+­ "
+rg 10,10 0 0256
+® "
+a- 10,9 0 0257
+¯ "
+de 10,11 0 0260
+° "
++- 10,10 0 0261
+± "
+S2 10,11 0 0262
+² "
+S3 10,11 0 0263
+³ "
+aa 10,11 0 0264
+´ "
+µ 10,7,3 0 0265
+ps 10,11,1 0 0266
+¶ "
+md 10,6 0 0267
+· "
+ac 10,0,3 0 0270
+¸ "
+S1 10,11 0 0271
+¹ "
+Om 10,10 0 0272
+º "
+Fc 10,7 0 0273
+» "
+14 10,11 0 0274
+¼ "
+12 10,11 0 0275
+½ "
+34 10,11 0 0276
+¾ "
+r? 10,7,4 0 0277
+¿ "
+`A 10,14 0 0300
+À "
+'A 10,14 0 0301
+Á "
+^A 10,14 0 0302
+Â "
+~A 10,13 0 0303
+Ã "
+:A 10,13 0 0304
+Ä "
+oA 10,14 0 0305
+Å "
+AE 10,10 0 0306
+Æ "
+,C 10,10,3 0 0307
+Ç "
+`E 10,14 0 0310
+È "
+'E 10,14 0 0311
+É "
+^E 10,14 0 0312
+Ê "
+:E 10,13 0 0313
+Ë "
+`I 10,14 0 0314
+Ì "
+'I 10,14 0 0315
+Í "
+^I 10,14 0 0316
+Î "
+:I 10,13 0 0317
+Ï "
+-D 10,10 0 0320
+Ð "
+~N 10,13 0 0321
+Ñ "
+`O 10,14 0 0322
+Ò "
+'O 10,14 0 0323
+Ó "
+^O 10,14 0 0324
+Ô "
+~O 10,13 0 0325
+Õ "
+:O 10,13 0 0326
+Ö "
+mu 10,8 0 0327
+× "
+/O 10,10 0 0330
+Ø "
+`U 10,14 0 0331
+Ù "
+'U 10,14 0 0332
+Ú "
+^U 10,14 0 0333
+Û "
+:U 10,13 0 0334
+Ü "
+'Y 10,14 0 0335
+Ý "
+TP 10,10 0 0336
+Þ "
+ss 10,11 0 0337
+ß "
+`a 10,11 0 0340
+à "
+'a 10,11 0 0341
+á "
+^a 10,11 0 0342
+â "
+~a 10,10 0 0343
+ã "
+:a 10,10 0 0344
+ä "
+oa 10,11 0 0345
+å "
+ae 10,7 0 0346
+æ "
+,c 10,7,3 0 0347
+ç "
+`e 10,11 0 0350
+è "
+'e 10,11 0 0351
+é "
+^e 10,11 0 0352
+ê "
+:e 10,10 0 0353
+ë "
+`i 10,11 0 0354
+ì "
+'i 10,11 0 0355
+í "
+^i 10,11 0 0356
+î "
+:i 10,10 0 0357
+ï "
+Sd 10,12 0 0360
+ð "
+~n 10,10 0 0361
+ñ "
+`o 10,11 0 0362
+ò "
+'o 10,11 0 0363
+ó "
+^o 10,11 0 0364
+ô "
+~o 10,10 0 0365
+õ "
+:o 10,10 0 0366
+ö "
+di 10,9 0 0367
+÷ "
+/o 10,8,1 0 0370
+ø "
+`u 10,11 0 0371
+ù "
+'u 10,11 0 0372
+ú "
+^u 10,11 0 0373
+û "
+:u 10,10 0 0374
+ü "
+'y 10,11,3 0 0375
+ý "
+Tp 10,11,3 0 0376
+þ "
+:y 10,10,3 0 0377
+ÿ "
diff --git a/gnu/usr.bin/groff/devX100-12/CI b/gnu/usr.bin/groff/devX100-12/CI
new file mode 100644
index 0000000..804f71f
--- /dev/null
+++ b/gnu/usr.bin/groff/devX100-12/CI
@@ -0,0 +1,306 @@
+name CI
+spacewidth 10
+charset
+--- 10,1 0 040
+! 10,11 0 041
+" 10,11 0 042
+# 10,11,1 0 043
+sh "
+$ 10,12,1 0 044
+Do "
+% 10,11 0 045
+& 10,9 0 046
+' 10,11 0 047
+( 10,11,2 0 050
+) 10,11,2 0 051
+* 10,10 0 052
++ 10,9 0 053
+, 10,2,2 0 054
+\- 10,5 0 055
+. 10,2 0 056
+/ 10,11,2 0 057
+sl "
+0 10,11 0 060
+1 10,11 0 061
+2 10,11 0 062
+3 10,11 0 063
+4 10,11 0 064
+5 10,11 0 065
+6 10,11 0 066
+7 10,11 0 067
+8 10,11 0 070
+9 10,11 0 071
+: 10,7 0 072
+; 10,7,2 0 073
+< 10,9 0 074
+= 10,7 0 075
+eq "
+> 10,9 0 076
+? 10,10 0 077
+@ 10,11,1 0 0100
+at "
+A 10,10 0 0101
+B 10,10 0 0102
+C 10,10 0 0103
+D 10,10 0 0104
+E 10,10 0 0105
+F 10,10 0 0106
+G 10,10 0 0107
+H 10,10 0 0110
+I 10,10 0 0111
+J 10,10 0 0112
+K 10,10 0 0113
+L 10,10 0 0114
+M 10,10 0 0115
+N 10,10 0 0116
+O 10,10 0 0117
+P 10,10 0 0120
+Q 10,10,2 0 0121
+R 10,10 0 0122
+S 10,10 0 0123
+T 10,10 0 0124
+U 10,10 0 0125
+V 10,10 0 0126
+W 10,10 0 0127
+X 10,10 0 0130
+Y 10,10 0 0131
+Z 10,10 0 0132
+[ 10,11,2 0 0133
+lB "
+\ 10,11,2 0 0134
+rs "
+] 10,11,2 0 0135
+rB "
+^ 10,11 0 0136
+a^ "
+ha "
+_ 10,0,3 0 0137
+` 10,11 0 0140
+oq "
+a 10,7 0 0141
+b 10,10 0 0142
+c 10,7 0 0143
+d 10,10 0 0144
+e 10,7 0 0145
+f 10,10 0 0146
+g 10,7,3 0 0147
+h 10,10 0 0150
+i 10,11 0 0151
+j 10,11,3 0 0152
+k 10,10 0 0153
+l 10,10 0 0154
+m 10,7 0 0155
+n 10,7 0 0156
+o 10,7 0 0157
+p 10,7,3 0 0160
+q 10,7,3 0 0161
+r 10,7 0 0162
+s 10,7 0 0163
+t 10,9 0 0164
+u 10,7 0 0165
+v 10,7 0 0166
+w 10,7 0 0167
+x 10,7 0 0170
+y 10,7,3 0 0171
+z 10,7 0 0172
+{ 10,11,2 0 0173
+lC "
+| 10,10,2 0 0174
+or "
+ba "
+} 10,11,2 0 0175
+rC "
+~ 10,6 0 0176
+a~ "
+ap "
+ti "
+r! 10,7,4 0 0241
+¡ "
+ct 10,10 0 0242
+¢ "
+Po 10,10 0 0243
+£ "
+Cs 10,8 0 0244
+¤ "
+Ye 10,10 0 0245
+¥ "
+bb 10,11,2 0 0246
+¦ "
+sc 10,11,1 0 0247
+§ "
+ad 10,10 0 0250
+¨ "
+co 10,10 0 0251
+© "
+Of 10,10 0 0252
+ª "
+Fo 10,7 0 0253
+« "
+no 10,6 0 0254
+¬ "
+- 10,5 0 0255
+hy "
+­ "
+rg 10,10 0 0256
+® "
+a- 10,10 0 0257
+¯ "
+de 10,11 0 0260
+° "
++- 10,9 0 0261
+± "
+S2 10,11 0 0262
+² "
+S3 10,11 0 0263
+³ "
+aa 10,11 0 0264
+´ "
+µ 10,7,3 0 0265
+ps 10,11,1 0 0266
+¶ "
+md 10,6 0 0267
+· "
+ac 10,0,3 0 0270
+¸ "
+S1 10,11 0 0271
+¹ "
+Om 10,10 0 0272
+º "
+Fc 10,7 0 0273
+» "
+14 10,11 0 0274
+¼ "
+12 10,11 0 0275
+½ "
+34 10,11 0 0276
+¾ "
+r? 10,7,3 0 0277
+¿ "
+`A 10,14 0 0300
+À "
+'A 10,14 0 0301
+Á "
+^A 10,14 0 0302
+Â "
+~A 10,13 0 0303
+Ã "
+:A 10,13 0 0304
+Ä "
+oA 10,14 0 0305
+Å "
+AE 10,10 0 0306
+Æ "
+,C 10,10,3 0 0307
+Ç "
+`E 10,14 0 0310
+È "
+'E 10,14 0 0311
+É "
+^E 10,14 0 0312
+Ê "
+:E 10,13 0 0313
+Ë "
+`I 10,14 0 0314
+Ì "
+'I 10,14 0 0315
+Í "
+^I 10,14 0 0316
+Î "
+:I 10,13 0 0317
+Ï "
+-D 10,10 0 0320
+Ð "
+~N 10,13 0 0321
+Ñ "
+`O 10,14 0 0322
+Ò "
+'O 10,14 0 0323
+Ó "
+^O 10,14 0 0324
+Ô "
+~O 10,13 0 0325
+Õ "
+:O 10,13 0 0326
+Ö "
+mu 10,8 0 0327
+× "
+/O 10,10 0 0330
+Ø "
+`U 10,14 0 0331
+Ù "
+'U 10,14 0 0332
+Ú "
+^U 10,14 0 0333
+Û "
+:U 10,13 0 0334
+Ü "
+'Y 10,14 0 0335
+Ý "
+TP 10,10 0 0336
+Þ "
+ss 10,11 0 0337
+ß "
+`a 10,11 0 0340
+à "
+'a 10,11 0 0341
+á "
+^a 10,11 0 0342
+â "
+~a 10,10 0 0343
+ã "
+:a 10,10 0 0344
+ä "
+oa 10,11 0 0345
+å "
+ae 10,7 0 0346
+æ "
+,c 10,7,3 0 0347
+ç "
+`e 10,11 0 0350
+è "
+'e 10,11 0 0351
+é "
+^e 10,11 0 0352
+ê "
+:e 10,10 0 0353
+ë "
+`i 10,11 0 0354
+ì "
+'i 10,11 0 0355
+í "
+^i 10,11 0 0356
+î "
+:i 10,10 0 0357
+ï "
+Sd 10,11 0 0360
+ð "
+~n 10,10 0 0361
+ñ "
+`o 10,11 0 0362
+ò "
+'o 10,11 0 0363
+ó "
+^o 10,11 0 0364
+ô "
+~o 10,10 0 0365
+õ "
+:o 10,10 0 0366
+ö "
+di 10,8 0 0367
+÷ "
+/o 10,8,1 0 0370
+ø "
+`u 10,11 0 0371
+ù "
+'u 10,11 0 0372
+ú "
+^u 10,11 0 0373
+û "
+:u 10,10 0 0374
+ü "
+'y 10,11,3 0 0375
+ý "
+Tp 10,11,3 0 0376
+þ "
+:y 10,10,3 0 0377
+ÿ "
diff --git a/gnu/usr.bin/groff/devX100-12/CR b/gnu/usr.bin/groff/devX100-12/CR
new file mode 100644
index 0000000..140ec55
--- /dev/null
+++ b/gnu/usr.bin/groff/devX100-12/CR
@@ -0,0 +1,306 @@
+name CR
+spacewidth 10
+charset
+--- 10,1 0 040
+! 10,11 0 041
+" 10,11 0 042
+# 10,11,1 0 043
+sh "
+$ 10,12,1 0 044
+Do "
+% 10,11 0 045
+& 10,9 0 046
+' 10,11 0 047
+( 10,11,2 0 050
+) 10,11,2 0 051
+* 10,11 0 052
++ 10,9 0 053
+, 10,2,2 0 054
+\- 10,5 0 055
+. 10,2 0 056
+/ 10,11,2 0 057
+sl "
+0 10,11 0 060
+1 10,11 0 061
+2 10,11 0 062
+3 10,11 0 063
+4 10,11 0 064
+5 10,11 0 065
+6 10,11 0 066
+7 10,11 0 067
+8 10,11 0 070
+9 10,11 0 071
+: 10,7 0 072
+; 10,7,2 0 073
+< 10,9 0 074
+= 10,7 0 075
+eq "
+> 10,9 0 076
+? 10,10 0 077
+@ 10,11,1 0 0100
+at "
+A 10,10 0 0101
+B 10,10 0 0102
+C 10,10 0 0103
+D 10,10 0 0104
+E 10,10 0 0105
+F 10,10 0 0106
+G 10,10 0 0107
+H 10,10 0 0110
+I 10,10 0 0111
+J 10,10 0 0112
+K 10,10 0 0113
+L 10,10 0 0114
+M 10,10 0 0115
+N 10,10 0 0116
+O 10,10 0 0117
+P 10,10 0 0120
+Q 10,10,2 0 0121
+R 10,10 0 0122
+S 10,10 0 0123
+T 10,10 0 0124
+U 10,10 0 0125
+V 10,10 0 0126
+W 10,10 0 0127
+X 10,10 0 0130
+Y 10,10 0 0131
+Z 10,10 0 0132
+[ 10,11,2 0 0133
+lB "
+\ 10,11,2 0 0134
+rs "
+] 10,11,2 0 0135
+rB "
+^ 10,11 0 0136
+a^ "
+ha "
+_ 10,0,3 0 0137
+` 10,11 0 0140
+oq "
+a 10,7 0 0141
+b 10,10 0 0142
+c 10,7 0 0143
+d 10,10 0 0144
+e 10,7 0 0145
+f 10,10 0 0146
+g 10,7,3 0 0147
+h 10,10 0 0150
+i 10,10 0 0151
+j 10,10,3 0 0152
+k 10,10 0 0153
+l 10,10 0 0154
+m 10,7 0 0155
+n 10,7 0 0156
+o 10,7 0 0157
+p 10,7,3 0 0160
+q 10,7,3 0 0161
+r 10,7 0 0162
+s 10,7 0 0163
+t 10,9 0 0164
+u 10,7 0 0165
+v 10,7 0 0166
+w 10,7 0 0167
+x 10,7 0 0170
+y 10,7,3 0 0171
+z 10,7 0 0172
+{ 10,11,2 0 0173
+lC "
+| 10,10,2 0 0174
+or "
+ba "
+} 10,11,2 0 0175
+rC "
+~ 10,6 0 0176
+a~ "
+ap "
+ti "
+r! 10,7,3 0 0241
+¡ "
+ct 10,10 0 0242
+¢ "
+Po 10,10 0 0243
+£ "
+Cs 10,8 0 0244
+¤ "
+Ye 10,10 0 0245
+¥ "
+bb 10,10,2 0 0246
+¦ "
+sc 10,11,1 0 0247
+§ "
+ad 10,10 0 0250
+¨ "
+co 10,10 0 0251
+© "
+Of 10,10 0 0252
+ª "
+Fo 10,7 0 0253
+« "
+no 10,6 0 0254
+¬ "
+- 10,5 0 0255
+hy "
+­ "
+rg 10,10 0 0256
+® "
+a- 10,9 0 0257
+¯ "
+de 10,11 0 0260
+° "
++- 10,9 0 0261
+± "
+S2 10,11 0 0262
+² "
+S3 10,11 0 0263
+³ "
+aa 10,11 0 0264
+´ "
+µ 10,7,3 0 0265
+ps 10,11,1 0 0266
+¶ "
+md 10,6 0 0267
+· "
+ac 10,1,3 0 0270
+¸ "
+S1 10,11 0 0271
+¹ "
+Om 10,10 0 0272
+º "
+Fc 10,7 0 0273
+» "
+14 10,11 0 0274
+¼ "
+12 10,11 0 0275
+½ "
+34 10,11 0 0276
+¾ "
+r? 10,7,3 0 0277
+¿ "
+`A 10,14 0 0300
+À "
+'A 10,14 0 0301
+Á "
+^A 10,14 0 0302
+Â "
+~A 10,13 0 0303
+Ã "
+:A 10,13 0 0304
+Ä "
+oA 10,14 0 0305
+Å "
+AE 10,10 0 0306
+Æ "
+,C 10,10,3 0 0307
+Ç "
+`E 10,14 0 0310
+È "
+'E 10,14 0 0311
+É "
+^E 10,14 0 0312
+Ê "
+:E 10,13 0 0313
+Ë "
+`I 10,14 0 0314
+Ì "
+'I 10,14 0 0315
+Í "
+^I 10,14 0 0316
+Î "
+:I 10,13 0 0317
+Ï "
+-D 10,10 0 0320
+Ð "
+~N 10,13 0 0321
+Ñ "
+`O 10,14 0 0322
+Ò "
+'O 10,14 0 0323
+Ó "
+^O 10,14 0 0324
+Ô "
+~O 10,13 0 0325
+Õ "
+:O 10,13 0 0326
+Ö "
+mu 10,8 0 0327
+× "
+/O 10,10 0 0330
+Ø "
+`U 10,14 0 0331
+Ù "
+'U 10,14 0 0332
+Ú "
+^U 10,14 0 0333
+Û "
+:U 10,13 0 0334
+Ü "
+'Y 10,14 0 0335
+Ý "
+TP 10,10 0 0336
+Þ "
+ss 10,11 0 0337
+ß "
+`a 10,11 0 0340
+à "
+'a 10,11 0 0341
+á "
+^a 10,11 0 0342
+â "
+~a 10,10 0 0343
+ã "
+:a 10,10 0 0344
+ä "
+oa 10,12 0 0345
+å "
+ae 10,7 0 0346
+æ "
+,c 10,7,3 0 0347
+ç "
+`e 10,11 0 0350
+è "
+'e 10,11 0 0351
+é "
+^e 10,11 0 0352
+ê "
+:e 10,10 0 0353
+ë "
+`i 10,11 0 0354
+ì "
+'i 10,11 0 0355
+í "
+^i 10,11 0 0356
+î "
+:i 10,10 0 0357
+ï "
+Sd 10,11 0 0360
+ð "
+~n 10,10 0 0361
+ñ "
+`o 10,11 0 0362
+ò "
+'o 10,11 0 0363
+ó "
+^o 10,11 0 0364
+ô "
+~o 10,10 0 0365
+õ "
+:o 10,10 0 0366
+ö "
+di 10,8 0 0367
+÷ "
+/o 10,8,1 0 0370
+ø "
+`u 10,11 0 0371
+ù "
+'u 10,11 0 0372
+ú "
+^u 10,11 0 0373
+û "
+:u 10,10 0 0374
+ü "
+'y 10,11,3 0 0375
+ý "
+Tp 10,11,3 0 0376
+þ "
+:y 10,10,3 0 0377
+ÿ "
diff --git a/gnu/usr.bin/groff/devX100-12/DESC b/gnu/usr.bin/groff/devX100-12/DESC
new file mode 100644
index 0000000..ead70b9
--- /dev/null
+++ b/gnu/usr.bin/groff/devX100-12/DESC
@@ -0,0 +1,9 @@
+styles R I B BI
+fonts 6 0 0 0 0 0 S
+sizes 8 10 12 14 18 24 0
+res 100
+X11
+hor 1
+vert 1
+unitwidth 12
+postpro gxditview
diff --git a/gnu/usr.bin/groff/devX100-12/HB b/gnu/usr.bin/groff/devX100-12/HB
new file mode 100644
index 0000000..e68615e
--- /dev/null
+++ b/gnu/usr.bin/groff/devX100-12/HB
@@ -0,0 +1,306 @@
+name HB
+spacewidth 5
+charset
+--- 5,1 0 040
+! 6,12 0 041
+" 8,12 0 042
+# 9,12 0 043
+sh "
+$ 9,13,1 0 044
+Do "
+% 14,12 0 045
+& 12,12 0 046
+' 5,12 0 047
+( 6,12,3 0 050
+) 6,12,3 0 051
+* 6,12 0 052
++ 10,8 0 053
+, 4,2,3 0 054
+\- 10,5 0 055
+. 4,2 0 056
+/ 5,12 0 057
+sl "
+0 9,12 0 060
+1 9,12 0 061
+2 9,12 0 062
+3 9,12 0 063
+4 9,12 0 064
+5 9,12 0 065
+6 9,12 0 066
+7 9,12 0 067
+8 9,12 0 070
+9 9,12 0 071
+: 5,8 0 072
+; 5,8,3 0 073
+< 10,8 0 074
+= 10,7 0 075
+eq "
+> 10,8 0 076
+? 10,12 0 077
+@ 16,12,2 0 0100
+at "
+A 12,12 0 0101
+B 12,12 0 0102
+C 12,12 0 0103
+D 12,12 0 0104
+E 11,12 0 0105
+F 10,12 0 0106
+G 13,12 0 0107
+H 12,12 0 0110
+I 4,12 0 0111
+J 9,12 0 0112
+K 12,12 0 0113
+L 10,12 0 0114
+M 13,12 0 0115
+N 12,12 0 0116
+O 13,12 0 0117
+P 11,12 0 0120
+Q 13,12,1 0 0121
+R 12,12 0 0122
+S 11,12 0 0123
+T 10,12 0 0124
+U 12,12 0 0125
+V 11,12 0 0126
+W 15,12 0 0127
+X 11,12 0 0130
+Y 11,12 0 0131
+Z 10,12 0 0132
+[ 6,12,3 0 0133
+lB "
+\ 5,12 0 0134
+rs "
+] 6,12,3 0 0135
+rB "
+^ 10,12 0 0136
+a^ "
+ha "
+_ 9,0,3 0 0137
+` 5,12 0 0140
+oq "
+a 9,9 0 0141
+b 10,12 0 0142
+c 9,9 0 0143
+d 10,12 0 0144
+e 9,9 0 0145
+f 5,12 0 0146
+g 10,9,4 0 0147
+h 10,12 0 0150
+i 4,12 0 0151
+j 5,12,4 0 0152
+k 9,12 0 0153
+l 5,12 0 0154
+m 14,9 0 0155
+n 10,9 0 0156
+o 10,9 0 0157
+p 10,9,4 0 0160
+q 10,9,4 0 0161
+r 6,9 0 0162
+s 9,9 0 0163
+t 6,11 0 0164
+u 10,9 0 0165
+v 9,9 0 0166
+w 13,9 0 0167
+x 9,9 0 0170
+y 9,9,4 0 0171
+z 8,9 0 0172
+{ 6,12,3 0 0173
+lC "
+| 4,12,4 0 0174
+or "
+ba "
+} 6,12,3 0 0175
+rC "
+~ 10,6 0 0176
+a~ "
+ap "
+ti "
+r! 6,9,3 0 0241
+¡ "
+ct 9,10,1 0 0242
+¢ "
+Po 9,12 0 0243
+£ "
+Cs 9,9 0 0244
+¤ "
+Ye 9,12 0 0245
+¥ "
+bb 5,12,4 0 0246
+¦ "
+sc 9,12,3 0 0247
+§ "
+ad 6,12 0 0250
+¨ "
+co 12,12 0 0251
+© "
+Of 6,12 0 0252
+ª "
+Fo 9,8 0 0253
+« "
+no 10,7 0 0254
+¬ "
+- 5,5 0 0255
+hy "
+­ "
+rg 12,12 0 0256
+® "
+a- 6,11 0 0257
+¯ "
+de 7,12 0 0260
+° "
++- 10,11 0 0261
+± "
+S2 6,12 0 0262
+² "
+S3 6,12 0 0263
+³ "
+aa 6,13 0 0264
+´ "
+µ 10,9,3 0 0265
+ps 9,12,3 0 0266
+¶ "
+md 5,6 0 0267
+· "
+ac 6,0,4 0 0270
+¸ "
+S1 6,12 0 0271
+¹ "
+Om 6,12 0 0272
+º "
+Fc 9,8 0 0273
+» "
+14 14,12 0 0274
+¼ "
+12 14,12 0 0275
+½ "
+34 14,12 0 0276
+¾ "
+r? 10,9,3 0 0277
+¿ "
+`A 12,16 0 0300
+À "
+'A 12,16 0 0301
+Á "
+^A 12,16 0 0302
+Â "
+~A 12,15 0 0303
+Ã "
+:A 12,15 0 0304
+Ä "
+oA 12,16 0 0305
+Å "
+AE 16,12 0 0306
+Æ "
+,C 12,12,4 0 0307
+Ç "
+`E 11,16 0 0310
+È "
+'E 11,16 0 0311
+É "
+^E 11,16 0 0312
+Ê "
+:E 11,15 0 0313
+Ë "
+`I 4,16 0 0314
+Ì "
+'I 4,16 0 0315
+Í "
+^I 4,16 0 0316
+Î "
+:I 4,15 0 0317
+Ï "
+-D 12,12 0 0320
+Ð "
+~N 12,15 0 0321
+Ñ "
+`O 13,16 0 0322
+Ò "
+'O 13,16 0 0323
+Ó "
+^O 13,16 0 0324
+Ô "
+~O 13,15 0 0325
+Õ "
+:O 13,15 0 0326
+Ö "
+mu 10,9 0 0327
+× "
+/O 13,12 0 0330
+Ø "
+`U 12,16 0 0331
+Ù "
+'U 12,16 0 0332
+Ú "
+^U 12,16 0 0333
+Û "
+:U 12,15 0 0334
+Ü "
+'Y 11,16 0 0335
+Ý "
+TP 11,12 0 0336
+Þ "
+ss 10,12 0 0337
+ß "
+`a 9,13 0 0340
+à "
+'a 9,13 0 0341
+á "
+^a 9,13 0 0342
+â "
+~a 9,12 0 0343
+ã "
+:a 9,12 0 0344
+ä "
+oa 9,13 0 0345
+å "
+ae 15,9 0 0346
+æ "
+,c 9,9,4 0 0347
+ç "
+`e 9,13 0 0350
+è "
+'e 9,13 0 0351
+é "
+^e 9,13 0 0352
+ê "
+:e 9,12 0 0353
+ë "
+`i 4,13 0 0354
+ì "
+'i 4,13 0 0355
+í "
+^i 4,13 0 0356
+î "
+:i 4,12 0 0357
+ï "
+Sd 10,12 0 0360
+ð "
+~n 10,12 0 0361
+ñ "
+`o 10,13 0 0362
+ò "
+'o 10,13 0 0363
+ó "
+^o 10,13 0 0364
+ô "
+~o 10,12 0 0365
+õ "
+:o 10,12 0 0366
+ö "
+di 10,8 0 0367
+÷ "
+/o 10,9 0 0370
+ø "
+`u 10,13 0 0371
+ù "
+'u 10,13 0 0372
+ú "
+^u 10,13 0 0373
+û "
+:u 10,12 0 0374
+ü "
+'y 9,13,4 0 0375
+ý "
+Tp 10,12,4 0 0376
+þ "
+:y 9,12,4 0 0377
+ÿ "
diff --git a/gnu/usr.bin/groff/devX100-12/HBI b/gnu/usr.bin/groff/devX100-12/HBI
new file mode 100644
index 0000000..6723ddf
--- /dev/null
+++ b/gnu/usr.bin/groff/devX100-12/HBI
@@ -0,0 +1,306 @@
+name HBI
+spacewidth 5
+charset
+--- 5,1 0 040
+! 6,12 0 041
+" 8,12 0 042
+# 9,12 0 043
+sh "
+$ 9,13,1 0 044
+Do "
+% 14,12 0 045
+& 12,12 0 046
+' 5,12 0 047
+( 6,12,3 0 050
+) 6,12,3 0 051
+* 6,12 0 052
++ 10,8 0 053
+, 4,2,3 0 054
+\- 10,5 0 055
+. 4,2 0 056
+/ 5,12 0 057
+sl "
+0 10,12 0 060
+1 9,12 0 061
+2 10,12 0 062
+3 9,12 0 063
+4 9,12 0 064
+5 9,12 0 065
+6 9,12 0 066
+7 9,12 0 067
+8 9,12 0 070
+9 9,12 0 071
+: 5,8 0 072
+; 5,8,3 0 073
+< 10,8 0 074
+= 10,7 0 075
+eq "
+> 10,8 0 076
+? 10,12 0 077
+@ 16,12,2 0 0100
+at "
+A 12,12 0 0101
+B 12,12 0 0102
+C 12,12 0 0103
+D 12,12 0 0104
+E 11,12 0 0105
+F 10,12 0 0106
+G 13,12 0 0107
+H 12,12 0 0110
+I 4,12 0 0111
+J 9,12 0 0112
+K 12,12 0 0113
+L 10,12 0 0114
+M 13,12 0 0115
+N 12,12 0 0116
+O 13,12 0 0117
+P 11,12 0 0120
+Q 13,12,1 0 0121
+R 12,12 0 0122
+S 11,12 0 0123
+T 10,12 0 0124
+U 12,12 0 0125
+V 11,12 0 0126
+W 15,12 0 0127
+X 11,12 0 0130
+Y 11,12 0 0131
+Z 10,12 0 0132
+[ 6,12,3 0 0133
+lB "
+\ 5,12 0 0134
+rs "
+] 6,12,3 0 0135
+rB "
+^ 10,12 0 0136
+a^ "
+ha "
+_ 9,0,3 0 0137
+` 5,12 0 0140
+oq "
+a 9,9 0 0141
+b 10,12 0 0142
+c 9,9 0 0143
+d 10,12 0 0144
+e 9,9 0 0145
+f 5,12 0 0146
+g 10,9,4 0 0147
+h 10,12 0 0150
+i 4,12 0 0151
+j 5,12,4 0 0152
+k 9,12 0 0153
+l 5,12 0 0154
+m 14,9 0 0155
+n 10,9 0 0156
+o 10,9 0 0157
+p 10,9,4 0 0160
+q 10,9,4 0 0161
+r 6,9 0 0162
+s 9,9 0 0163
+t 6,12 0 0164
+u 10,9 0 0165
+v 9,9 0 0166
+w 13,9 0 0167
+x 9,9 0 0170
+y 9,9,4 0 0171
+z 8,9 0 0172
+{ 6,12,3 0 0173
+lC "
+| 3,12,4 0 0174
+or "
+ba "
+} 6,12,3 0 0175
+rC "
+~ 10,5 0 0176
+a~ "
+ap "
+ti "
+r! 6,9,3 0 0241
+¡ "
+ct 9,10,1 0 0242
+¢ "
+Po 9,12 0 0243
+£ "
+Cs 9,9 0 0244
+¤ "
+Ye 9,12 0 0245
+¥ "
+bb 5,12,4 0 0246
+¦ "
+sc 9,12,3 0 0247
+§ "
+ad 6,12 0 0250
+¨ "
+co 12,12 0 0251
+© "
+Of 6,12 0 0252
+ª "
+Fo 9,8 0 0253
+« "
+no 10,7 0 0254
+¬ "
+- 5,5 0 0255
+hy "
+­ "
+rg 12,12 0 0256
+® "
+a- 6,11 0 0257
+¯ "
+de 7,12 0 0260
+° "
++- 10,11 0 0261
+± "
+S2 6,12 0 0262
+² "
+S3 6,12 0 0263
+³ "
+aa 6,13 0 0264
+´ "
+µ 10,9,4 0 0265
+ps 9,12,3 0 0266
+¶ "
+md 5,6 0 0267
+· "
+ac 6,0,4 0 0270
+¸ "
+S1 6,12 0 0271
+¹ "
+Om 6,12 0 0272
+º "
+Fc 9,8 0 0273
+» "
+14 14,12 0 0274
+¼ "
+12 14,12 0 0275
+½ "
+34 14,12 0 0276
+¾ "
+r? 10,9,3 0 0277
+¿ "
+`A 12,16 0 0300
+À "
+'A 12,16 0 0301
+Á "
+^A 12,16 0 0302
+Â "
+~A 12,15 0 0303
+Ã "
+:A 12,15 0 0304
+Ä "
+oA 12,15 0 0305
+Å "
+AE 17,12 0 0306
+Æ "
+,C 12,12,4 0 0307
+Ç "
+`E 11,16 0 0310
+È "
+'E 11,16 0 0311
+É "
+^E 11,16 0 0312
+Ê "
+:E 11,15 0 0313
+Ë "
+`I 4,16 0 0314
+Ì "
+'I 4,16 0 0315
+Í "
+^I 4,16 0 0316
+Î "
+:I 4,15 0 0317
+Ï "
+-D 12,12 0 0320
+Ð "
+~N 12,15 0 0321
+Ñ "
+`O 13,16 0 0322
+Ò "
+'O 13,16 0 0323
+Ó "
+^O 13,16 0 0324
+Ô "
+~O 13,15 0 0325
+Õ "
+:O 13,15 0 0326
+Ö "
+mu 10,8 0 0327
+× "
+/O 13,12 0 0330
+Ø "
+`U 12,16 0 0331
+Ù "
+'U 12,16 0 0332
+Ú "
+^U 12,16 0 0333
+Û "
+:U 12,15 0 0334
+Ü "
+'Y 11,16 0 0335
+Ý "
+TP 11,12 0 0336
+Þ "
+ss 10,12 0 0337
+ß "
+`a 9,13 0 0340
+à "
+'a 9,13 0 0341
+á "
+^a 9,13 0 0342
+â "
+~a 9,12 0 0343
+ã "
+:a 9,12 0 0344
+ä "
+oa 9,13 0 0345
+å "
+ae 15,9 0 0346
+æ "
+,c 9,9,4 0 0347
+ç "
+`e 9,13 0 0350
+è "
+'e 9,13 0 0351
+é "
+^e 9,13 0 0352
+ê "
+:e 9,12 0 0353
+ë "
+`i 4,13 0 0354
+ì "
+'i 4,13 0 0355
+í "
+^i 4,13 0 0356
+î "
+:i 4,12 0 0357
+ï "
+Sd 10,13 0 0360
+ð "
+~n 10,12 0 0361
+ñ "
+`o 10,13 0 0362
+ò "
+'o 10,13 0 0363
+ó "
+^o 10,13 0 0364
+ô "
+~o 10,12 0 0365
+õ "
+:o 10,12 0 0366
+ö "
+di 10,8 0 0367
+÷ "
+/o 10,9 0 0370
+ø "
+`u 10,13 0 0371
+ù "
+'u 10,13 0 0372
+ú "
+^u 10,13 0 0373
+û "
+:u 10,12 0 0374
+ü "
+'y 9,13,4 0 0375
+ý "
+Tp 10,12,4 0 0376
+þ "
+:y 9,12,4 0 0377
+ÿ "
diff --git a/gnu/usr.bin/groff/devX100-12/HI b/gnu/usr.bin/groff/devX100-12/HI
new file mode 100644
index 0000000..f002cd6
--- /dev/null
+++ b/gnu/usr.bin/groff/devX100-12/HI
@@ -0,0 +1,306 @@
+name HI
+spacewidth 5
+charset
+--- 5,1 0 040
+! 5,12 0 041
+" 6,12 0 042
+# 9,12 0 043
+sh "
+$ 9,13,1 0 044
+Do "
+% 14,12 0 045
+& 11,12 0 046
+' 4,12 0 047
+( 6,12,3 0 050
+) 6,12,3 0 051
+* 6,12 0 052
++ 10,9 0 053
+, 4,2,2 0 054
+\- 10,5 0 055
+. 4,2 0 056
+/ 5,12 0 057
+sl "
+0 9,12 0 060
+1 9,12 0 061
+2 9,12 0 062
+3 9,12 0 063
+4 9,12 0 064
+5 9,12 0 065
+6 9,12 0 066
+7 9,12 0 067
+8 9,12 0 070
+9 9,12 0 071
+: 4,9 0 072
+; 4,9,2 0 073
+< 10,9 0 074
+= 10,6 0 075
+eq "
+> 10,9 0 076
+? 9,12 0 077
+@ 17,12,1 0 0100
+at "
+A 11,12 0 0101
+B 11,12 0 0102
+C 12,12 0 0103
+D 12,12 0 0104
+E 11,12 0 0105
+F 10,12 0 0106
+G 13,12 0 0107
+H 12,12 0 0110
+I 4,12 0 0111
+J 8,12 0 0112
+K 11,12 0 0113
+L 9,12 0 0114
+M 13,12 0 0115
+N 12,12 0 0116
+O 13,12 0 0117
+P 11,12 0 0120
+Q 13,12,1 0 0121
+R 12,12 0 0122
+S 11,12 0 0123
+T 10,12 0 0124
+U 12,12 0 0125
+V 11,12 0 0126
+W 16,12 0 0127
+X 11,12 0 0130
+Y 11,12 0 0131
+Z 10,12 0 0132
+[ 5,12,3 0 0133
+lB "
+\ 5,12 0 0134
+rs "
+] 5,12,3 0 0135
+rB "
+^ 8,12 0 0136
+a^ "
+ha "
+_ 9,0,3 0 0137
+` 4,12 0 0140
+oq "
+a 9,9 0 0141
+b 9,12 0 0142
+c 8,9 0 0143
+d 9,12 0 0144
+e 9,9 0 0145
+f 5,12 0 0146
+g 9,9,4 0 0147
+h 9,12 0 0150
+i 3,12 0 0151
+j 4,12,4 0 0152
+k 8,12 0 0153
+l 4,12 0 0154
+m 14,9 0 0155
+n 9,9 0 0156
+o 9,9 0 0157
+p 9,9,4 0 0160
+q 9,9,4 0 0161
+r 5,9 0 0162
+s 8,9 0 0163
+t 5,11 0 0164
+u 9,9 0 0165
+v 8,9 0 0166
+w 12,9 0 0167
+x 8,9 0 0170
+y 8,9,4 0 0171
+z 8,9 0 0172
+{ 6,12,3 0 0173
+lC "
+| 3,12,4 0 0174
+or "
+ba "
+} 6,12,3 0 0175
+rC "
+~ 10,6 0 0176
+a~ "
+ap "
+ti "
+r! 6,9,3 0 0241
+¡ "
+ct 9,10,1 0 0242
+¢ "
+Po 9,12 0 0243
+£ "
+Cs 9,10 0 0244
+¤ "
+Ye 9,12 0 0245
+¥ "
+bb 4,12,4 0 0246
+¦ "
+sc 9,12,3 0 0247
+§ "
+ad 5,12 0 0250
+¨ "
+co 12,12 0 0251
+© "
+Of 6,12 0 0252
+ª "
+Fo 9,8 0 0253
+« "
+no 10,6 0 0254
+¬ "
+- 5,5 0 0255
+hy "
+­ "
+rg 12,12 0 0256
+® "
+a- 6,11 0 0257
+¯ "
+de 7,12 0 0260
+° "
++- 10,11 0 0261
+± "
+S2 6,12 0 0262
+² "
+S3 6,12 0 0263
+³ "
+aa 6,13 0 0264
+´ "
+µ 9,9,4 0 0265
+ps 9,12,3 0 0266
+¶ "
+md 5,7 0 0267
+· "
+ac 6,0,4 0 0270
+¸ "
+S1 6,12 0 0271
+¹ "
+Om 6,12 0 0272
+º "
+Fc 9,8 0 0273
+» "
+14 14,12 0 0274
+¼ "
+12 14,13 0 0275
+½ "
+34 14,12 0 0276
+¾ "
+r? 10,9,3 0 0277
+¿ "
+`A 11,16 0 0300
+À "
+'A 11,16 0 0301
+Á "
+^A 11,16 0 0302
+Â "
+~A 11,15 0 0303
+Ã "
+:A 11,15 0 0304
+Ä "
+oA 11,15 0 0305
+Å "
+AE 16,12 0 0306
+Æ "
+,C 12,12,3 0 0307
+Ç "
+`E 11,16 0 0310
+È "
+'E 11,16 0 0311
+É "
+^E 11,16 0 0312
+Ê "
+:E 11,15 0 0313
+Ë "
+`I 4,16 0 0314
+Ì "
+'I 4,16 0 0315
+Í "
+^I 4,16 0 0316
+Î "
+:I 4,15 0 0317
+Ï "
+-D 12,12 0 0320
+Ð "
+~N 12,15 0 0321
+Ñ "
+`O 13,16 0 0322
+Ò "
+'O 13,16 0 0323
+Ó "
+^O 13,16 0 0324
+Ô "
+~O 13,15 0 0325
+Õ "
+:O 13,15 0 0326
+Ö "
+mu 10,8 0 0327
+× "
+/O 13,12 0 0330
+Ø "
+`U 12,16 0 0331
+Ù "
+'U 12,16 0 0332
+Ú "
+^U 12,16 0 0333
+Û "
+:U 12,15 0 0334
+Ü "
+'Y 11,16 0 0335
+Ý "
+TP 11,12 0 0336
+Þ "
+ss 10,12 0 0337
+ß "
+`a 9,13 0 0340
+à "
+'a 9,13 0 0341
+á "
+^a 9,13 0 0342
+â "
+~a 9,12 0 0343
+ã "
+:a 9,12 0 0344
+ä "
+oa 9,13 0 0345
+å "
+ae 15,9 0 0346
+æ "
+,c 8,9,3 0 0347
+ç "
+`e 9,13 0 0350
+è "
+'e 9,13 0 0351
+é "
+^e 9,13 0 0352
+ê "
+:e 9,12 0 0353
+ë "
+`i 4,13 0 0354
+ì "
+'i 4,13 0 0355
+í "
+^i 4,13 0 0356
+î "
+:i 4,12 0 0357
+ï "
+Sd 9,12 0 0360
+ð "
+~n 9,12 0 0361
+ñ "
+`o 9,13 0 0362
+ò "
+'o 9,13 0 0363
+ó "
+^o 9,13 0 0364
+ô "
+~o 9,12 0 0365
+õ "
+:o 9,12 0 0366
+ö "
+di 10,9 0 0367
+÷ "
+/o 10,9 0 0370
+ø "
+`u 9,13 0 0371
+ù "
+'u 9,13 0 0372
+ú "
+^u 9,13 0 0373
+û "
+:u 9,12 0 0374
+ü "
+'y 8,13,4 0 0375
+ý "
+Tp 9,12,4 0 0376
+þ "
+:y 8,12,4 0 0377
+ÿ "
diff --git a/gnu/usr.bin/groff/devX100-12/HR b/gnu/usr.bin/groff/devX100-12/HR
new file mode 100644
index 0000000..d2b296f
--- /dev/null
+++ b/gnu/usr.bin/groff/devX100-12/HR
@@ -0,0 +1,306 @@
+name HR
+spacewidth 5
+charset
+--- 5,1 0 040
+! 5,12 0 041
+" 6,12 0 042
+# 9,11 0 043
+sh "
+$ 9,13,2 0 044
+Do "
+% 14,12 0 045
+& 11,12 0 046
+' 4,12 0 047
+( 6,12,4 0 050
+) 6,12,4 0 051
+* 6,12 0 052
++ 10,9 0 053
+, 4,2,2 0 054
+\- 10,5 0 055
+. 4,2 0 056
+/ 5,12 0 057
+sl "
+0 9,12 0 060
+1 9,12 0 061
+2 9,12 0 062
+3 9,12 0 063
+4 9,12 0 064
+5 9,12 0 065
+6 9,12 0 066
+7 9,12 0 067
+8 9,12 0 070
+9 9,12 0 071
+: 4,9 0 072
+; 4,9,2 0 073
+< 10,9 0 074
+= 10,6 0 075
+eq "
+> 10,9 0 076
+? 9,12 0 077
+@ 17,12,2 0 0100
+at "
+A 11,12 0 0101
+B 11,12 0 0102
+C 12,12 0 0103
+D 12,12 0 0104
+E 11,12 0 0105
+F 10,12 0 0106
+G 13,12 0 0107
+H 12,12 0 0110
+I 4,12 0 0111
+J 8,12 0 0112
+K 11,12 0 0113
+L 9,12 0 0114
+M 13,12 0 0115
+N 12,12 0 0116
+O 13,12 0 0117
+P 11,12 0 0120
+Q 13,12,1 0 0121
+R 12,12 0 0122
+S 11,12 0 0123
+T 10,12 0 0124
+U 12,12 0 0125
+V 11,12 0 0126
+W 15,12 0 0127
+X 11,12 0 0130
+Y 11,12 0 0131
+Z 10,12 0 0132
+[ 5,12,3 0 0133
+lB "
+\ 5,12 0 0134
+rs "
+] 5,12,3 0 0135
+rB "
+^ 8,12 0 0136
+a^ "
+ha "
+_ 9,0,3 0 0137
+` 4,12 0 0140
+oq "
+a 9,9 0 0141
+b 9,12 0 0142
+c 8,9 0 0143
+d 9,12 0 0144
+e 9,9 0 0145
+f 5,12 0 0146
+g 9,9,4 0 0147
+h 9,12 0 0150
+i 3,12 0 0151
+j 4,12,4 0 0152
+k 8,12 0 0153
+l 3,12 0 0154
+m 14,9 0 0155
+n 9,9 0 0156
+o 9,9 0 0157
+p 9,9,4 0 0160
+q 9,9,4 0 0161
+r 5,9 0 0162
+s 8,9 0 0163
+t 5,11 0 0164
+u 9,9 0 0165
+v 8,9 0 0166
+w 12,9 0 0167
+x 8,9 0 0170
+y 8,9,3 0 0171
+z 8,9 0 0172
+{ 6,12,4 0 0173
+lC "
+| 4,12,4 0 0174
+or "
+ba "
+} 6,12,4 0 0175
+rC "
+~ 10,6 0 0176
+a~ "
+ap "
+ti "
+r! 6,9,3 0 0241
+¡ "
+ct 9,11,2 0 0242
+¢ "
+Po 9,12 0 0243
+£ "
+Cs 9,10 0 0244
+¤ "
+Ye 9,12 0 0245
+¥ "
+bb 4,12,4 0 0246
+¦ "
+sc 9,12,3 0 0247
+§ "
+ad 5,12 0 0250
+¨ "
+co 12,12 0 0251
+© "
+Of 6,12 0 0252
+ª "
+Fo 9,8 0 0253
+« "
+no 10,6 0 0254
+¬ "
+- 5,5 0 0255
+hy "
+­ "
+rg 12,12 0 0256
+® "
+a- 6,11 0 0257
+¯ "
+de 7,12 0 0260
+° "
++- 10,11 0 0261
+± "
+S2 6,12 0 0262
+² "
+S3 6,12 0 0263
+³ "
+aa 6,13 0 0264
+´ "
+µ 9,9,4 0 0265
+ps 9,12,3 0 0266
+¶ "
+md 5,6 0 0267
+· "
+ac 6,0,4 0 0270
+¸ "
+S1 6,12 0 0271
+¹ "
+Om 6,12 0 0272
+º "
+Fc 9,8 0 0273
+» "
+14 14,12 0 0274
+¼ "
+12 14,13 0 0275
+½ "
+34 14,12 0 0276
+¾ "
+r? 10,9,3 0 0277
+¿ "
+`A 11,16 0 0300
+À "
+'A 11,16 0 0301
+Á "
+^A 11,16 0 0302
+Â "
+~A 11,15 0 0303
+Ã "
+:A 11,15 0 0304
+Ä "
+oA 11,15 0 0305
+Å "
+AE 16,12 0 0306
+Æ "
+,C 12,12,4 0 0307
+Ç "
+`E 11,16 0 0310
+È "
+'E 11,16 0 0311
+É "
+^E 11,16 0 0312
+Ê "
+:E 11,15 0 0313
+Ë "
+`I 4,16 0 0314
+Ì "
+'I 4,16 0 0315
+Í "
+^I 4,16 0 0316
+Î "
+:I 4,15 0 0317
+Ï "
+-D 12,12 0 0320
+Ð "
+~N 12,15 0 0321
+Ñ "
+`O 13,16 0 0322
+Ò "
+'O 13,16 0 0323
+Ó "
+^O 13,16 0 0324
+Ô "
+~O 13,15 0 0325
+Õ "
+:O 13,15 0 0326
+Ö "
+mu 10,8 0 0327
+× "
+/O 13,13,1 0 0330
+Ø "
+`U 12,16 0 0331
+Ù "
+'U 12,16 0 0332
+Ú "
+^U 12,16 0 0333
+Û "
+:U 12,15 0 0334
+Ü "
+'Y 11,16 0 0335
+Ý "
+TP 11,12 0 0336
+Þ "
+ss 10,12 0 0337
+ß "
+`a 9,13 0 0340
+à "
+'a 9,13 0 0341
+á "
+^a 9,13 0 0342
+â "
+~a 9,12 0 0343
+ã "
+:a 9,12 0 0344
+ä "
+oa 9,13 0 0345
+å "
+ae 15,9 0 0346
+æ "
+,c 8,9,4 0 0347
+ç "
+`e 9,13 0 0350
+è "
+'e 9,13 0 0351
+é "
+^e 9,13 0 0352
+ê "
+:e 9,12 0 0353
+ë "
+`i 4,13 0 0354
+ì "
+'i 4,13 0 0355
+í "
+^i 4,13 0 0356
+î "
+:i 4,12 0 0357
+ï "
+Sd 9,12 0 0360
+ð "
+~n 9,12 0 0361
+ñ "
+`o 9,13 0 0362
+ò "
+'o 9,13 0 0363
+ó "
+^o 9,13 0 0364
+ô "
+~o 9,12 0 0365
+õ "
+:o 9,12 0 0366
+ö "
+di 10,9 0 0367
+÷ "
+/o 10,10 0 0370
+ø "
+`u 9,13 0 0371
+ù "
+'u 9,13 0 0372
+ú "
+^u 9,13 0 0373
+û "
+:u 9,12 0 0374
+ü "
+'y 8,13,3 0 0375
+ý "
+Tp 9,12,4 0 0376
+þ "
+:y 8,12,3 0 0377
+ÿ "
diff --git a/gnu/usr.bin/groff/devX100-12/Makefile b/gnu/usr.bin/groff/devX100-12/Makefile
new file mode 100644
index 0000000..4936ceb
--- /dev/null
+++ b/gnu/usr.bin/groff/devX100-12/Makefile
@@ -0,0 +1,10 @@
+# Makefile for devX100-12
+
+DEVICE= X100-12
+FONTFILES= CB CBI CI CR HB HBI HI HR NB NBI NI NR S TB TBI TI TR DESC
+
+NOOBJ= noobj
+
+clean cleandir:
+
+.include "../Makefile.dev"
diff --git a/gnu/usr.bin/groff/devX100-12/Makefile.sub b/gnu/usr.bin/groff/devX100-12/Makefile.sub
new file mode 100644
index 0000000..d074757
--- /dev/null
+++ b/gnu/usr.bin/groff/devX100-12/Makefile.sub
@@ -0,0 +1,2 @@
+DEV=X100-12
+DEVFILES=DESC TR TI TB TBI CR CI CB CBI HR HI HB HBI NR NI NB NBI S
diff --git a/gnu/usr.bin/groff/devX100-12/NB b/gnu/usr.bin/groff/devX100-12/NB
new file mode 100644
index 0000000..f997df5
--- /dev/null
+++ b/gnu/usr.bin/groff/devX100-12/NB
@@ -0,0 +1,306 @@
+name NB
+spacewidth 4
+charset
+--- 4,1 0 040
+! 5,12 0 041
+" 6,12 0 042
+# 10,12 0 043
+sh "
+$ 10,14,1 0 044
+Do "
+% 14,12 0 045
+& 14,12 0 046
+' 4,12 0 047
+( 6,12,2 0 050
+) 6,12,2 0 051
+* 8,12 0 052
++ 10,8 0 053
+, 5,3,3 0 054
+\- 10,5 0 055
+. 5,3 0 056
+/ 5,12 0 057
+sl "
+0 10,12 0 060
+1 9,12 0 061
+2 9,12 0 062
+3 10,12 0 063
+4 9,12 0 064
+5 10,12 0 065
+6 9,12 0 066
+7 9,12 0 067
+8 9,12 0 070
+9 10,12 0 071
+: 5,8 0 072
+; 5,8,3 0 073
+< 10,9 0 074
+= 10,7 0 075
+eq "
+> 10,9 0 076
+? 8,12 0 077
+@ 12,12,1 0 0100
+at "
+A 13,12 0 0101
+B 13,12 0 0102
+C 13,12 0 0103
+D 14,12 0 0104
+E 12,12 0 0105
+F 12,12 0 0106
+G 14,12 0 0107
+H 15,12 0 0110
+I 7,12 0 0111
+J 11,12 0 0112
+K 13,12 0 0113
+L 12,12 0 0114
+M 16,12 0 0115
+N 14,12 0 0116
+O 14,12 0 0117
+P 13,12 0 0120
+Q 14,12,3 0 0121
+R 14,12 0 0122
+S 11,12 0 0123
+T 12,12 0 0124
+U 14,12 0 0125
+V 13,12 0 0126
+W 16,12 0 0127
+X 12,12 0 0130
+Y 12,12 0 0131
+Z 11,12 0 0132
+[ 6,12,2 0 0133
+lB "
+\ 10,12 0 0134
+rs "
+] 7,12,2 0 0135
+rB "
+^ 10,12 0 0136
+a^ "
+ha "
+_ 8,0,2 0 0137
+` 4,12 0 0140
+oq "
+a 10,8 0 0141
+b 11,12 0 0142
+c 9,8 0 0143
+d 11,12 0 0144
+e 10,8 0 0145
+f 7,12 0 0146
+g 10,9,3 0 0147
+h 11,12 0 0150
+i 6,12 0 0151
+j 6,12,3 0 0152
+k 11,12 0 0153
+l 6,12 0 0154
+m 16,8 0 0155
+n 11,8 0 0156
+o 11,8 0 0157
+p 11,8,3 0 0160
+q 10,8,3 0 0161
+r 9,8 0 0162
+s 8,8 0 0163
+t 7,11 0 0164
+u 11,8 0 0165
+v 10,8 0 0166
+w 15,8 0 0167
+x 10,8 0 0170
+y 10,8,3 0 0171
+z 9,8 0 0172
+{ 6,12,2 0 0173
+lC "
+| 10,12 0 0174
+or "
+ba "
+} 6,12,2 0 0175
+rC "
+~ 10,6 0 0176
+a~ "
+ap "
+ti "
+r! 5,9,3 0 0241
+¡ "
+ct 10,10,2 0 0242
+¢ "
+Po 10,12 0 0243
+£ "
+Cs 10,10 0 0244
+¤ "
+Ye 10,12 0 0245
+¥ "
+bb 10,12 0 0246
+¦ "
+sc 9,12,3 0 0247
+§ "
+ad 6,11 0 0250
+¨ "
+co 12,12 0 0251
+© "
+Of 6,12 0 0252
+ª "
+Fo 8,7 0 0253
+« "
+no 10,7 0 0254
+¬ "
+- 5,5 0 0255
+hy "
+­ "
+rg 12,12 0 0256
+® "
+a- 6,11 0 0257
+¯ "
+de 7,12 0 0260
+° "
++- 10,9 0 0261
+± "
+S2 6,12 0 0262
+² "
+S3 6,12 0 0263
+³ "
+aa 6,12 0 0264
+´ "
+µ 11,8,3 0 0265
+ps 12,12 0 0266
+¶ "
+md 5,6 0 0267
+· "
+ac 6,1,3 0 0270
+¸ "
+S1 6,12 0 0271
+¹ "
+Om 6,12 0 0272
+º "
+Fc 8,7 0 0273
+» "
+14 14,12 0 0274
+¼ "
+12 14,12 0 0275
+½ "
+34 14,12 0 0276
+¾ "
+r? 8,9,3 0 0277
+¿ "
+`A 13,16 0 0300
+À "
+'A 13,16 0 0301
+Á "
+^A 13,16 0 0302
+Â "
+~A 13,15 0 0303
+Ã "
+:A 13,15 0 0304
+Ä "
+oA 13,16 0 0305
+Å "
+AE 16,12 0 0306
+Æ "
+,C 13,12,3 0 0307
+Ç "
+`E 12,16 0 0310
+È "
+'E 12,16 0 0311
+É "
+^E 12,16 0 0312
+Ê "
+:E 12,15 0 0313
+Ë "
+`I 7,16 0 0314
+Ì "
+'I 7,16 0 0315
+Í "
+^I 7,16 0 0316
+Î "
+:I 7,15 0 0317
+Ï "
+-D 14,12 0 0320
+Ð "
+~N 14,15 0 0321
+Ñ "
+`O 14,16 0 0322
+Ò "
+'O 14,16 0 0323
+Ó "
+^O 14,16 0 0324
+Ô "
+~O 14,15 0 0325
+Õ "
+:O 14,15 0 0326
+Ö "
+mu 10,8 0 0327
+× "
+/O 14,13,1 0 0330
+Ø "
+`U 14,16 0 0331
+Ù "
+'U 14,16 0 0332
+Ú "
+^U 14,16 0 0333
+Û "
+:U 14,15 0 0334
+Ü "
+'Y 12,16 0 0335
+Ý "
+TP 13,12 0 0336
+Þ "
+ss 10,12 0 0337
+ß "
+`a 10,12 0 0340
+à "
+'a 10,12 0 0341
+á "
+^a 10,12 0 0342
+â "
+~a 10,11 0 0343
+ã "
+:a 10,11 0 0344
+ä "
+oa 10,12 0 0345
+å "
+ae 15,8 0 0346
+æ "
+,c 9,8,3 0 0347
+ç "
+`e 10,12 0 0350
+è "
+'e 10,12 0 0351
+é "
+^e 10,12 0 0352
+ê "
+:e 10,11 0 0353
+ë "
+`i 6,12 0 0354
+ì "
+'i 6,12 0 0355
+í "
+^i 6,12 0 0356
+î "
+:i 6,11 0 0357
+ï "
+Sd 11,13 0 0360
+ð "
+~n 11,11 0 0361
+ñ "
+`o 11,12 0 0362
+ò "
+'o 11,12 0 0363
+ó "
+^o 11,12 0 0364
+ô "
+~o 11,11 0 0365
+õ "
+:o 11,11 0 0366
+ö "
+di 10,8 0 0367
+÷ "
+/o 10,10,2 0 0370
+ø "
+`u 11,12 0 0371
+ù "
+'u 11,12 0 0372
+ú "
+^u 11,12 0 0373
+û "
+:u 11,11 0 0374
+ü "
+'y 10,12,3 0 0375
+ý "
+Tp 11,12,3 0 0376
+þ "
+:y 10,11,3 0 0377
+ÿ "
diff --git a/gnu/usr.bin/groff/devX100-12/NBI b/gnu/usr.bin/groff/devX100-12/NBI
new file mode 100644
index 0000000..38c3281
--- /dev/null
+++ b/gnu/usr.bin/groff/devX100-12/NBI
@@ -0,0 +1,306 @@
+name NBI
+spacewidth 4
+charset
+--- 4,1 0 040
+! 6,12 0 041
+" 7,12 0 042
+# 10,12 0 043
+sh "
+$ 9,14,1 0 044
+Do "
+% 15,12 0 045
+& 15,12 0 046
+' 4,12 0 047
+( 7,12,2 0 050
+) 7,12,2 0 051
+* 8,12 0 052
++ 10,8 0 053
+, 5,3,3 0 054
+\- 10,5 0 055
+. 5,3 0 056
+/ 5,12 0 057
+sl "
+0 9,12 0 060
+1 9,12 0 061
+2 9,12 0 062
+3 9,12 0 063
+4 9,12 0 064
+5 10,12 0 065
+6 10,12 0 066
+7 9,12 0 067
+8 9,12 0 070
+9 9,12 0 071
+: 5,8 0 072
+; 5,8,3 0 073
+< 10,8 0 074
+= 10,7 0 075
+eq "
+> 10,8 0 076
+? 8,12 0 077
+@ 12,12 0 0100
+at "
+A 12,12 0 0101
+B 13,12 0 0102
+C 13,12 0 0103
+D 14,12 0 0104
+E 12,12 0 0105
+F 12,12 0 0106
+G 14,12 0 0107
+H 14,12 0 0110
+I 7,12 0 0111
+J 11,12 0 0112
+K 13,12 0 0113
+L 12,12 0 0114
+M 16,12 0 0115
+N 14,12 0 0116
+O 14,12 0 0117
+P 12,12 0 0120
+Q 14,12,3 0 0121
+R 14,12 0 0122
+S 11,12 0 0123
+T 12,12 0 0124
+U 14,12 0 0125
+V 12,12 0 0126
+W 16,12 0 0127
+X 12,12 0 0130
+Y 12,12 0 0131
+Z 12,12 0 0132
+[ 7,12,2 0 0133
+lB "
+\ 10,12 0 0134
+rs "
+] 7,12,2 0 0135
+rB "
+^ 10,12 0 0136
+a^ "
+ha "
+_ 8,0,3 0 0137
+` 4,12 0 0140
+oq "
+a 11,8 0 0141
+b 10,12 0 0142
+c 9,8 0 0143
+d 11,12 0 0144
+e 9,8 0 0145
+f 6,12,3 0 0146
+g 10,9,3 0 0147
+h 11,12 0 0150
+i 6,12 0 0151
+j 6,12,3 0 0152
+k 11,12 0 0153
+l 6,12 0 0154
+m 15,8 0 0155
+n 11,8 0 0156
+o 10,8 0 0157
+p 11,8,3 0 0160
+q 10,8,3 0 0161
+r 9,8 0 0162
+s 8,8 0 0163
+t 7,11 0 0164
+u 11,8 0 0165
+v 9,8 0 0166
+w 14,8 0 0167
+x 9,8 0 0170
+y 9,8,3 0 0171
+z 9,8 0 0172
+{ 7,12,2 0 0173
+lC "
+| 10,12 0 0174
+or "
+ba "
+} 7,12,2 0 0175
+rC "
+~ 10,6 0 0176
+a~ "
+ap "
+ti "
+r! 6,9,3 0 0241
+¡ "
+ct 10,10,2 0 0242
+¢ "
+Po 10,12 0 0243
+£ "
+Cs 10,10 0 0244
+¤ "
+Ye 10,12 0 0245
+¥ "
+bb 10,12 0 0246
+¦ "
+sc 9,12,3 0 0247
+§ "
+ad 6,11 0 0250
+¨ "
+co 12,12 0 0251
+© "
+Of 7,12 0 0252
+ª "
+Fo 8,7 0 0253
+« "
+no 10,7 0 0254
+¬ "
+- 5,5 0 0255
+hy "
+­ "
+rg 12,12 0 0256
+® "
+a- 6,11 0 0257
+¯ "
+de 7,12 0 0260
+° "
++- 10,8 0 0261
+± "
+S2 6,12 0 0262
+² "
+S3 6,12 0 0263
+³ "
+aa 6,12 0 0264
+´ "
+µ 11,8,3 0 0265
+ps 11,12 0 0266
+¶ "
+md 5,6 0 0267
+· "
+ac 5,1,3 0 0270
+¸ "
+S1 6,12 0 0271
+¹ "
+Om 6,12 0 0272
+º "
+Fc 8,7 0 0273
+» "
+14 14,12 0 0274
+¼ "
+12 14,12 0 0275
+½ "
+34 14,12 0 0276
+¾ "
+r? 8,9,3 0 0277
+¿ "
+`A 12,16 0 0300
+À "
+'A 12,16 0 0301
+Á "
+^A 12,16 0 0302
+Â "
+~A 12,15 0 0303
+Ã "
+:A 12,15 0 0304
+Ä "
+oA 12,16 0 0305
+Å "
+AE 15,12 0 0306
+Æ "
+,C 13,12,3 0 0307
+Ç "
+`E 12,16 0 0310
+È "
+'E 12,16 0 0311
+É "
+^E 12,16 0 0312
+Ê "
+:E 12,15 0 0313
+Ë "
+`I 7,16 0 0314
+Ì "
+'I 7,16 0 0315
+Í "
+^I 7,16 0 0316
+Î "
+:I 7,15 0 0317
+Ï "
+-D 14,12 0 0320
+Ð "
+~N 14,15 0 0321
+Ñ "
+`O 14,16 0 0322
+Ò "
+'O 14,16 0 0323
+Ó "
+^O 14,16 0 0324
+Ô "
+~O 14,15 0 0325
+Õ "
+:O 14,15 0 0326
+Ö "
+mu 10,8 0 0327
+× "
+/O 14,13,1 0 0330
+Ø "
+`U 14,16 0 0331
+Ù "
+'U 14,16 0 0332
+Ú "
+^U 14,16 0 0333
+Û "
+:U 14,15 0 0334
+Ü "
+'Y 12,16 0 0335
+Ý "
+TP 12,12 0 0336
+Þ "
+ss 10,12,3 0 0337
+ß "
+`a 11,12 0 0340
+à "
+'a 11,12 0 0341
+á "
+^a 11,12 0 0342
+â "
+~a 11,11 0 0343
+ã "
+:a 11,11 0 0344
+ä "
+oa 11,13 0 0345
+å "
+ae 14,8 0 0346
+æ "
+,c 9,8,3 0 0347
+ç "
+`e 9,12 0 0350
+è "
+'e 9,12 0 0351
+é "
+^e 9,12 0 0352
+ê "
+:e 9,11 0 0353
+ë "
+`i 6,12 0 0354
+ì "
+'i 6,12 0 0355
+í "
+^i 6,12 0 0356
+î "
+:i 6,11 0 0357
+ï "
+Sd 10,13 0 0360
+ð "
+~n 11,11 0 0361
+ñ "
+`o 10,12 0 0362
+ò "
+'o 10,12 0 0363
+ó "
+^o 10,12 0 0364
+ô "
+~o 10,11 0 0365
+õ "
+:o 10,11 0 0366
+ö "
+di 10,8 0 0367
+÷ "
+/o 10,10,2 0 0370
+ø "
+`u 11,12 0 0371
+ù "
+'u 11,12 0 0372
+ú "
+^u 11,12 0 0373
+û "
+:u 11,11 0 0374
+ü "
+'y 9,12,3 0 0375
+ý "
+Tp 11,11,3 0 0376
+þ "
+:y 9,11,3 0 0377
+ÿ "
diff --git a/gnu/usr.bin/groff/devX100-12/NI b/gnu/usr.bin/groff/devX100-12/NI
new file mode 100644
index 0000000..7a34f2a
--- /dev/null
+++ b/gnu/usr.bin/groff/devX100-12/NI
@@ -0,0 +1,306 @@
+name NI
+spacewidth 4
+charset
+--- 4,1 0 040
+! 6,12 0 041
+" 7,12 0 042
+# 9,12 0 043
+sh "
+$ 9,14,1 0 044
+Do "
+% 14,12 0 045
+& 14,12 0 046
+' 3,12 0 047
+( 6,12,2 0 050
+) 5,12,2 0 051
+* 8,12 0 052
++ 10,9 0 053
+, 4,2,3 0 054
+\- 10,5 0 055
+. 4,2 0 056
+/ 10,12,2 0 057
+sl "
+0 9,12 0 060
+1 9,12 0 061
+2 9,12 0 062
+3 9,12 0 063
+4 9,12 0 064
+5 9,12 0 065
+6 9,12 0 066
+7 9,12 0 067
+8 9,12 0 070
+9 9,12 0 071
+: 5,8 0 072
+; 5,8,3 0 073
+< 10,9 0 074
+= 10,6 0 075
+eq "
+> 10,9 0 076
+? 7,12 0 077
+@ 12,12 0 0100
+at "
+A 12,12 0 0101
+B 12,12 0 0102
+C 12,12 0 0103
+D 13,12 0 0104
+E 12,12 0 0105
+F 11,12 0 0106
+G 13,12 0 0107
+H 14,12 0 0110
+I 7,12 0 0111
+J 10,12 0 0112
+K 12,12 0 0113
+L 11,12 0 0114
+M 16,12 0 0115
+N 13,12 0 0116
+O 13,12 0 0117
+P 11,12 0 0120
+Q 13,12,3 0 0121
+R 13,12 0 0122
+S 11,12 0 0123
+T 11,12 0 0124
+U 13,12 0 0125
+V 11,12 0 0126
+W 15,12 0 0127
+X 12,12 0 0130
+Y 11,12 0 0131
+Z 11,12 0 0132
+[ 6,12,2 0 0133
+lB "
+\ 10,12 0 0134
+rs "
+] 6,12,2 0 0135
+rB "
+^ 10,12 0 0136
+a^ "
+ha "
+_ 8,0,3 0 0137
+` 3,12 0 0140
+oq "
+a 10,8 0 0141
+b 9,12 0 0142
+c 8,8 0 0143
+d 10,12 0 0144
+e 7,8 0 0145
+f 5,12,3 0 0146
+g 9,9,3 0 0147
+h 10,12 0 0150
+i 6,12 0 0151
+j 5,12,3 0 0152
+k 9,12 0 0153
+l 6,12 0 0154
+m 15,8 0 0155
+n 10,8 0 0156
+o 8,8 0 0157
+p 9,8,3 0 0160
+q 9,8,3 0 0161
+r 7,8 0 0162
+s 7,8 0 0163
+t 6,11 0 0164
+u 10,8 0 0165
+v 8,8 0 0166
+w 13,8 0 0167
+x 8,8 0 0170
+y 8,8,3 0 0171
+z 8,8 0 0172
+{ 6,12,2 0 0173
+lC "
+| 10,12 0 0174
+or "
+ba "
+} 6,12,2 0 0175
+rC "
+~ 10,5 0 0176
+a~ "
+ap "
+ti "
+r! 6,9,3 0 0241
+¡ "
+ct 9,10,2 0 0242
+¢ "
+Po 9,12 0 0243
+£ "
+Cs 9,10 0 0244
+¤ "
+Ye 9,12 0 0245
+¥ "
+bb 10,12 0 0246
+¦ "
+sc 8,12,3 0 0247
+§ "
+ad 6,11 0 0250
+¨ "
+co 12,12 0 0251
+© "
+Of 7,12 0 0252
+ª "
+Fo 7,6 0 0253
+« "
+no 10,6 0 0254
+¬ "
+- 5,4 0 0255
+hy "
+­ "
+rg 12,12 0 0256
+® "
+a- 5,10 0 0257
+¯ "
+de 7,12 0 0260
+° "
++- 10,9 0 0261
+± "
+S2 6,12 0 0262
+² "
+S3 6,12 0 0263
+³ "
+aa 5,12 0 0264
+´ "
+µ 10,8,3 0 0265
+ps 11,12 0 0266
+¶ "
+md 5,5 0 0267
+· "
+ac 5,1,3 0 0270
+¸ "
+S1 6,12 0 0271
+¹ "
+Om 6,12 0 0272
+º "
+Fc 7,6 0 0273
+» "
+14 14,12 0 0274
+¼ "
+12 14,12 0 0275
+½ "
+34 14,12 0 0276
+¾ "
+r? 7,9,3 0 0277
+¿ "
+`A 12,16 0 0300
+À "
+'A 12,16 0 0301
+Á "
+^A 12,16 0 0302
+Â "
+~A 12,15 0 0303
+Ã "
+:A 12,15 0 0304
+Ä "
+oA 12,16 0 0305
+Å "
+AE 14,12 0 0306
+Æ "
+,C 12,12,3 0 0307
+Ç "
+`E 12,16 0 0310
+È "
+'E 12,16 0 0311
+É "
+^E 12,16 0 0312
+Ê "
+:E 12,15 0 0313
+Ë "
+`I 7,16 0 0314
+Ì "
+'I 7,16 0 0315
+Í "
+^I 7,16 0 0316
+Î "
+:I 7,15 0 0317
+Ï "
+-D 13,12 0 0320
+Ð "
+~N 13,15 0 0321
+Ñ "
+`O 13,16 0 0322
+Ò "
+'O 13,16 0 0323
+Ó "
+^O 13,16 0 0324
+Ô "
+~O 13,15 0 0325
+Õ "
+:O 13,15 0 0326
+Ö "
+mu 10,8 0 0327
+× "
+/O 13,13,1 0 0330
+Ø "
+`U 13,16 0 0331
+Ù "
+'U 13,16 0 0332
+Ú "
+^U 13,16 0 0333
+Û "
+:U 13,15 0 0334
+Ü "
+'Y 11,16 0 0335
+Ý "
+TP 11,12 0 0336
+Þ "
+ss 9,12,3 0 0337
+ß "
+`a 10,12 0 0340
+à "
+'a 10,12 0 0341
+á "
+^a 10,12 0 0342
+â "
+~a 10,11 0 0343
+ã "
+:a 10,11 0 0344
+ä "
+oa 10,13 0 0345
+å "
+ae 12,8 0 0346
+æ "
+,c 8,8,3 0 0347
+ç "
+`e 7,12 0 0350
+è "
+'e 7,12 0 0351
+é "
+^e 7,12 0 0352
+ê "
+:e 7,11 0 0353
+ë "
+`i 6,12 0 0354
+ì "
+'i 6,12 0 0355
+í "
+^i 6,12 0 0356
+î "
+:i 6,11 0 0357
+ï "
+Sd 8,13 0 0360
+ð "
+~n 10,11 0 0361
+ñ "
+`o 8,12 0 0362
+ò "
+'o 8,12 0 0363
+ó "
+^o 8,12 0 0364
+ô "
+~o 8,11 0 0365
+õ "
+:o 8,11 0 0366
+ö "
+di 10,8 0 0367
+÷ "
+/o 8,10,2 0 0370
+ø "
+`u 10,12 0 0371
+ù "
+'u 10,12 0 0372
+ú "
+^u 10,12 0 0373
+û "
+:u 10,11 0 0374
+ü "
+'y 8,12,3 0 0375
+ý "
+Tp 9,11,3 0 0376
+þ "
+:y 8,11,3 0 0377
+ÿ "
diff --git a/gnu/usr.bin/groff/devX100-12/NR b/gnu/usr.bin/groff/devX100-12/NR
new file mode 100644
index 0000000..0a9a0cf
--- /dev/null
+++ b/gnu/usr.bin/groff/devX100-12/NR
@@ -0,0 +1,306 @@
+name NR
+spacewidth 4
+charset
+--- 4,1 0 040
+! 5,12 0 041
+" 6,12 0 042
+# 9,12 0 043
+sh "
+$ 9,13,2 0 044
+Do "
+% 14,12 0 045
+& 13,12 0 046
+' 3,12 0 047
+( 6,12,2 0 050
+) 6,12,2 0 051
+* 8,12 0 052
++ 10,9 0 053
+, 4,2,3 0 054
+\- 10,5 0 055
+. 4,2 0 056
+/ 5,12 0 057
+sl "
+0 9,12 0 060
+1 9,12 0 061
+2 9,12 0 062
+3 9,12 0 063
+4 9,12 0 064
+5 9,12 0 065
+6 9,12 0 066
+7 9,12 0 067
+8 9,12 0 070
+9 9,12 0 071
+: 4,8 0 072
+; 4,8,3 0 073
+< 10,8 0 074
+= 10,6 0 075
+eq "
+> 10,8 0 076
+? 7,12 0 077
+@ 12,12,1 0 0100
+at "
+A 12,12 0 0101
+B 12,12 0 0102
+C 12,12 0 0103
+D 13,12 0 0104
+E 12,12 0 0105
+F 11,12 0 0106
+G 13,12 0 0107
+H 14,12 0 0110
+I 7,12 0 0111
+J 9,12 0 0112
+K 13,12 0 0113
+L 11,12 0 0114
+M 16,12 0 0115
+N 13,12 0 0116
+O 13,12 0 0117
+P 11,12 0 0120
+Q 13,12,3 0 0121
+R 12,12 0 0122
+S 10,12 0 0123
+T 11,12 0 0124
+U 13,12 0 0125
+V 12,12 0 0126
+W 16,12 0 0127
+X 11,12 0 0130
+Y 12,12 0 0131
+Z 10,12 0 0132
+[ 6,12,2 0 0133
+lB "
+\ 10,12 0 0134
+rs "
+] 6,12,2 0 0135
+rB "
+^ 10,12 0 0136
+a^ "
+ha "
+_ 8,0,2 0 0137
+` 3,12 0 0140
+oq "
+a 9,8 0 0141
+b 9,12 0 0142
+c 7,8 0 0143
+d 10,12 0 0144
+e 8,8 0 0145
+f 6,12 0 0146
+g 9,8,3 0 0147
+h 10,12 0 0150
+i 5,12 0 0151
+j 5,12,3 0 0152
+k 10,12 0 0153
+l 5,12 0 0154
+m 15,8 0 0155
+n 10,8 0 0156
+o 8,8 0 0157
+p 9,8,3 0 0160
+q 9,8,3 0 0161
+r 7,8 0 0162
+s 8,8 0 0163
+t 7,11 0 0164
+u 10,8 0 0165
+v 9,8 0 0166
+w 13,8 0 0167
+x 9,8 0 0170
+y 9,8,3 0 0171
+z 8,8 0 0172
+{ 6,12,2 0 0173
+lC "
+| 10,12 0 0174
+or "
+ba "
+} 6,12,2 0 0175
+rC "
+~ 10,5 0 0176
+a~ "
+ap "
+ti "
+r! 5,9,3 0 0241
+¡ "
+ct 9,10,2 0 0242
+¢ "
+Po 9,12 0 0243
+£ "
+Cs 9,10 0 0244
+¤ "
+Ye 9,12 0 0245
+¥ "
+bb 10,12 0 0246
+¦ "
+sc 8,12,3 0 0247
+§ "
+ad 5,11 0 0250
+¨ "
+co 12,12 0 0251
+© "
+Of 6,12 0 0252
+ª "
+Fo 7,6 0 0253
+« "
+no 10,6 0 0254
+¬ "
+- 5,4 0 0255
+hy "
+­ "
+rg 12,12 0 0256
+® "
+a- 5,10 0 0257
+¯ "
+de 7,12 0 0260
+° "
++- 10,9 0 0261
+± "
+S2 6,12 0 0262
+² "
+S3 6,12 0 0263
+³ "
+aa 5,12 0 0264
+´ "
+µ 10,8,3 0 0265
+ps 10,12,3 0 0266
+¶ "
+md 5,5 0 0267
+· "
+ac 5,1,3 0 0270
+¸ "
+S1 6,12 0 0271
+¹ "
+Om 5,12 0 0272
+º "
+Fc 7,6 0 0273
+» "
+14 14,12 0 0274
+¼ "
+12 13,12 0 0275
+½ "
+34 14,12 0 0276
+¾ "
+r? 7,9,3 0 0277
+¿ "
+`A 12,16 0 0300
+À "
+'A 12,16 0 0301
+Á "
+^A 12,16 0 0302
+Â "
+~A 12,15 0 0303
+Ã "
+:A 12,15 0 0304
+Ä "
+oA 12,16 0 0305
+Å "
+AE 17,12 0 0306
+Æ "
+,C 12,12,3 0 0307
+Ç "
+`E 12,16 0 0310
+È "
+'E 12,16 0 0311
+É "
+^E 12,16 0 0312
+Ê "
+:E 12,15 0 0313
+Ë "
+`I 7,16 0 0314
+Ì "
+'I 7,16 0 0315
+Í "
+^I 7,16 0 0316
+Î "
+:I 7,15 0 0317
+Ï "
+-D 13,12 0 0320
+Ð "
+~N 13,15 0 0321
+Ñ "
+`O 13,16 0 0322
+Ò "
+'O 13,16 0 0323
+Ó "
+^O 13,16 0 0324
+Ô "
+~O 13,15 0 0325
+Õ "
+:O 13,15 0 0326
+Ö "
+mu 10,8 0 0327
+× "
+/O 13,13,1 0 0330
+Ø "
+`U 13,16 0 0331
+Ù "
+'U 13,16 0 0332
+Ú "
+^U 13,16 0 0333
+Û "
+:U 13,15 0 0334
+Ü "
+'Y 12,16 0 0335
+Ý "
+TP 11,12 0 0336
+Þ "
+ss 10,12 0 0337
+ß "
+`a 9,12 0 0340
+à "
+'a 9,12 0 0341
+á "
+^a 9,12 0 0342
+â "
+~a 9,11 0 0343
+ã "
+:a 9,11 0 0344
+ä "
+oa 9,13 0 0345
+å "
+ae 13,8 0 0346
+æ "
+,c 7,8,3 0 0347
+ç "
+`e 8,12 0 0350
+è "
+'e 8,12 0 0351
+é "
+^e 8,12 0 0352
+ê "
+:e 8,11 0 0353
+ë "
+`i 5,12 0 0354
+ì "
+'i 5,12 0 0355
+í "
+^i 5,12 0 0356
+î "
+:i 5,11 0 0357
+ï "
+Sd 8,13 0 0360
+ð "
+~n 10,11 0 0361
+ñ "
+`o 8,12 0 0362
+ò "
+'o 8,12 0 0363
+ó "
+^o 8,12 0 0364
+ô "
+~o 8,11 0 0365
+õ "
+:o 8,11 0 0366
+ö "
+di 10,8 0 0367
+÷ "
+/o 8,9,1 0 0370
+ø "
+`u 10,12 0 0371
+ù "
+'u 10,12 0 0372
+ú "
+^u 10,12 0 0373
+û "
+:u 10,11 0 0374
+ü "
+'y 9,12,3 0 0375
+ý "
+Tp 9,11,3 0 0376
+þ "
+:y 9,11,3 0 0377
+ÿ "
diff --git a/gnu/usr.bin/groff/devX100-12/S b/gnu/usr.bin/groff/devX100-12/S
new file mode 100644
index 0000000..453c295
--- /dev/null
+++ b/gnu/usr.bin/groff/devX100-12/S
@@ -0,0 +1,226 @@
+name S
+special
+spacewidth 4
+charset
+--- 4,1 0 040
+! 5,11 0 041
+fa 11,12 0 042
+# 8,11 0 043
+sh "
+te 9,12 0 044
+% 13,11,1 0 045
+& 13,11 0 046
+st 7,8 0 047
+( 5,12,2 0 050
+) 5,12,2 0 051
+** 8,8 0 052
++ 9,9 0 053
+pl "
+, 4,3,2 0 054
+\- 9,5 0 055
+mi "
+. 4,3 0 056
+/ 5,11 0 057
+sl "
+0 8,12 0 060
+1 8,12 0 061
+2 8,12 0 062
+3 8,12 0 063
+4 8,12 0 064
+5 8,12 0 065
+6 8,12 0 066
+7 8,12 0 067
+8 8,12 0 070
+9 8,12 0 071
+: 4,8 0 072
+; 4,8,2 0 073
+< 9,9 0 074
+= 9,6 0 075
+eq "
+> 9,9 0 076
+? 7,11 0 077
+=~ 9,8 0 0100
+*A 12,11 0 0101
+*B 11,11 0 0102
+*X 12,11 0 0103
+*D 10,11 0 0104
+*E 10,11 0 0105
+*F 12,11 0 0106
+*G 10,11 0 0107
+*Y 12,11 0 0110
+*I 6,11 0 0111
++h 10,12 0 0112
+*K 12,11 0 0113
+*L 11,11 0 0114
+*M 14,11 0 0115
+*N 11,11 0 0116
+*O 12,11 0 0117
+*P 12,11 0 0120
+*H 12,11 0 0121
+*R 9,11 0 0122
+*S 10,11 0 0123
+*T 10,11 0 0124
+--- 11,11 0 0125
+ts 8,8,4 0 0126
+*W 12,12 0 0127
+*C 11,11 0 0130
+*Q 13,11 0 0131
+*Z 10,11 0 0132
+[ 6,12,2 0 0133
+lB "
+tf 14,8 0 0134
+3d "
+] 5,12,2 0 0135
+rB "
+pp 11,11 0 0136
+_ 8,0,4 0 0137
+radicalex 8,13 0 0140
+*a 11,9 0 0141
+*b 9,13,4 0 0142
+*x 9,9,3 0 0143
+*d 8,12 0 0144
+*e 7,9 0 0145
+*f 9,11,3 0 0146
+*g 7,9,4 0 0147
+*y 10,9,3 0 0150
+*i 5,9 0 0151
++f 10,9,3 0 0152
+*k 9,9 0 0153
+*l 9,13 0 0154
+*m 9,9,4 0 0155
+µ "
+*n 8,9 0 0156
+*o 9,9 0 0157
+*p 9,9 0 0160
+*h 9,12 0 0161
+*r 9,9,4 0 0162
+*s 10,9 0 0163
+*t 7,9 0 0164
+*u 9,9 0 0165
++p 11,10 0 0166
+*w 11,9 0 0167
+*c 8,13,4 0 0170
+*q 11,9,4 0 0171
+*z 8,13,4 0 0172
+lC 8,12,2 0 0173
+{ "
+ba 3,11,3 0 0174
+or "
+| "
+rC 8,12,2 0 0175
+} "
+ap 9,5 0 0176
+*U 10,11 0 0241
+fm 4,12 0 0242
+<= 9,11 0 0243
+f/ 3,11 0 0244
+if 12,7 0 0245
+Fn 8,12,3 0 0246
+CL 12,9,1 0 0247
+DI 12,9 0 0250
+HE 12,9 0 0251
+SP 12,9,1 0 0252
+<> 17,9 0 0253
+<- 16,9 0 0254
+ua 10,13,2 0 0255
+arrowverttp "
+-> 16,9 0 0256
+da 10,13,2 0 0257
+arrowvertbt "
+de 6,11 0 0260
+° "
++- 9,11 0 0261
+± "
+sd 7,12 0 0262
+>= 9,11 0 0263
+mu 9,9 0 0264
+× "
+pt 11,7 0 0265
+pd 8,13,1 0 0266
+bu 8,8 0 0267
+di 9,8 0 0270
+÷ "
+!= 9,9,1 0 0271
+== 9,8 0 0272
+~= 9,7 0 0273
+~~ "
+--- 16,3 0 0274
+arrowvertex 10,13,4 0 0275
+an 16,5 0 0276
+CR 10,10,1 0 0277
+Ah 13,11 0 0300
+Im 11,13,1 0 0301
+Re 13,13 0 0302
+wp 16,9,4 0 0303
+c* 12,11 0 0304
+c+ 12,11 0 0305
+es 13,12 0 0306
+ca 12,9 0 0307
+cu 12,9 0 0310
+sp 11,8 0 0311
+ip 11,7,3 0 0312
+--- 11,9,1 0 0313
+sb 11,8 0 0314
+ib 11,8,2 0 0315
+mo 11,7 0 0316
+nm 11,8,1 0 0317
+/_ 12,11 0 0320
+gr 11,12 0 0321
+rg 13,11 0 0322
+co 13,11 0 0323
+tm 14,11 0 0324
+--- 13,13,2 0 0325
+sr 9,13,3 0 0326
+md 4,5 0 0327
+no 12,5 0 0330
+¬ "
+AN 10,8 0 0331
+OR 10,8 0 0332
+hA 17,9 0 0333
+lA 16,9 0 0334
+uA 10,13,2 0 0335
+rA 16,9 0 0336
+dA 10,13,2 0 0337
+lz 8,12 0 0340
+la 5,13,2 0 0341
+--- 13,11 0 0342
+--- 13,11 0 0343
+--- 13,11 0 0344
+--- 11,13,2 0 0345
+parenlefttp 6,13,4 0 0346
+parenleftex 6,13,4 0 0347
+parenleftbt 6,13,4 0 0350
+bracketlefttp 6,13,4 0 0351
+lc "
+bracketleftex 6,13,4 0 0352
+bracketleftbt 6,13,4 0 0353
+lf "
+bracelefttp 8,13,4 0 0354
+lt "
+braceleftmid 8,13,4 0 0355
+lk "
+braceleftbt 8,13,4 0 0356
+lb "
+bracerightex 8,13,4 0 0357
+braceleftex "
+bv "
+--- 13,13 0 0360
+ra 5,13,2 0 0361
+is 5,13,4 0 0362
+--- 11,13,4 0 0363
+--- 11,13,4 0 0364
+--- 11,13,4 0 0365
+parenrighttp 7,13,4 0 0366
+parenrightex 6,13,4 0 0367
+parenrightbt 6,13,4 0 0370
+bracketrighttp 6,13,4 0 0371
+rc "
+bracketrightex 6,13,4 0 0372
+bracketrightbt 6,13,4 0 0373
+rf "
+bracerighttp 8,13,4 0 0374
+rt "
+bracerightmid 8,13,4 0 0375
+rk "
+bracerightbt 8,13,4 0 0376
+rb "
diff --git a/gnu/usr.bin/groff/devX100-12/TB b/gnu/usr.bin/groff/devX100-12/TB
new file mode 100644
index 0000000..83073d5
--- /dev/null
+++ b/gnu/usr.bin/groff/devX100-12/TB
@@ -0,0 +1,306 @@
+name TB
+spacewidth 4
+charset
+--- 4,1 0 040
+! 6,11 0 041
+" 9,11 0 042
+# 8,11 0 043
+sh "
+$ 8,12,1 0 044
+Do "
+% 16,12 0 045
+& 14,11 0 046
+' 6,11 0 047
+( 6,11,3 0 050
+) 6,11,3 0 051
+* 8,11 0 052
++ 9,8 0 053
+, 4,2,3 0 054
+\- 9,5 0 055
+. 4,2 0 056
+/ 5,11 0 057
+sl "
+0 8,11 0 060
+1 8,11 0 061
+2 8,11 0 062
+3 8,11 0 063
+4 8,11 0 064
+5 8,11 0 065
+6 8,11 0 066
+7 8,11 0 067
+8 8,11 0 070
+9 8,11 0 071
+: 5,7 0 072
+; 5,7,3 0 073
+< 9,8 0 074
+= 9,7 0 075
+eq "
+> 9,8 0 076
+? 8,11 0 077
+@ 16,11,2 0 0100
+at "
+A 12,11 0 0101
+B 11,11 0 0102
+C 12,11 0 0103
+D 12,11 0 0104
+E 11,11 0 0105
+F 10,11 0 0106
+G 13,11 0 0107
+H 13,11 0 0110
+I 6,11 0 0111
+J 8,11,2 0 0112
+K 13,11 0 0113
+L 11,11 0 0114
+M 15,11 0 0115
+N 12,11 0 0116
+O 13,11 0 0117
+P 10,11 0 0120
+Q 13,11,3 0 0121
+R 12,11 0 0122
+S 9,11 0 0123
+T 11,11 0 0124
+U 12,11 0 0125
+V 12,11 0 0126
+W 16,11 0 0127
+X 12,11 0 0130
+Y 12,11 0 0131
+Z 11,11 0 0132
+[ 6,11,3 0 0133
+lB "
+\ 5,11 0 0134
+rs "
+] 6,11,3 0 0135
+rB "
+^ 9,11 0 0136
+a^ "
+ha "
+_ 8,0,4 0 0137
+` 6,11 0 0140
+oq "
+a 8,8 0 0141
+b 9,11 0 0142
+c 7,8 0 0143
+d 9,11 0 0144
+e 7,8 0 0145
+f 6,11 0 0146
+g 8,8,4 0 0147
+h 9,11 0 0150
+i 5,11 0 0151
+j 5,11,4 0 0152
+k 9,11 0 0153
+l 5,11 0 0154
+m 14,8 0 0155
+n 9,8 0 0156
+o 8,8 0 0157
+p 9,8,4 0 0160
+q 9,8,4 0 0161
+r 7,8 0 0162
+s 6,8 0 0163
+t 6,11 0 0164
+u 9,8 0 0165
+v 8,8 0 0166
+w 12,8 0 0167
+x 8,8 0 0170
+y 8,8,4 0 0171
+z 7,8 0 0172
+{ 7,11,3 0 0173
+lC "
+| 4,11,3 0 0174
+or "
+ba "
+} 7,11,3 0 0175
+rC "
+~ 9,8 0 0176
+a~ "
+ap "
+ti "
+r! 6,8,4 0 0241
+¡ "
+ct 8,10,2 0 0242
+¢ "
+Po 8,11 0 0243
+£ "
+Cs 8,8 0 0244
+¤ "
+Ye 8,11 0 0245
+¥ "
+bb 4,12,3 0 0246
+¦ "
+sc 8,11,4 0 0247
+§ "
+ad 6,11 0 0250
+¨ "
+co 12,11 0 0251
+© "
+Of 5,11 0 0252
+ª "
+Fo 8,7 0 0253
+« "
+no 9,7 0 0254
+¬ "
+- 5,5 0 0255
+hy "
+­ "
+rg 12,11 0 0256
+® "
+a- 6,10 0 0257
+¯ "
+de 7,11 0 0260
+° "
++- 9,9 0 0261
+± "
+S2 5,11 0 0262
+² "
+S3 5,11 0 0263
+³ "
+aa 6,12 0 0264
+´ "
+µ 9,8,3 0 0265
+ps 9,11,4 0 0266
+¶ "
+md 4,6 0 0267
+· "
+ac 6,0,4 0 0270
+¸ "
+S1 5,11 0 0271
+¹ "
+Om 6,11 0 0272
+º "
+Fc 8,7 0 0273
+» "
+14 12,11 0 0274
+¼ "
+12 12,11 0 0275
+½ "
+34 12,11 0 0276
+¾ "
+r? 8,8,3 0 0277
+¿ "
+`A 12,15 0 0300
+À "
+'A 12,15 0 0301
+Á "
+^A 12,15 0 0302
+Â "
+~A 12,14 0 0303
+Ã "
+:A 12,14 0 0304
+Ä "
+oA 12,16 0 0305
+Å "
+AE 16,11 0 0306
+Æ "
+,C 12,11,4 0 0307
+Ç "
+`E 11,15 0 0310
+È "
+'E 11,15 0 0311
+É "
+^E 11,15 0 0312
+Ê "
+:E 11,14 0 0313
+Ë "
+`I 6,15 0 0314
+Ì "
+'I 6,15 0 0315
+Í "
+^I 6,15 0 0316
+Î "
+:I 6,14 0 0317
+Ï "
+-D 12,11 0 0320
+Ð "
+~N 12,14 0 0321
+Ñ "
+`O 13,15 0 0322
+Ò "
+'O 13,15 0 0323
+Ó "
+^O 13,15 0 0324
+Ô "
+~O 13,15 0 0325
+Õ "
+:O 13,14 0 0326
+Ö "
+mu 9,8 0 0327
+× "
+/O 13,12,1 0 0330
+Ø "
+`U 12,15 0 0331
+Ù "
+'U 12,15 0 0332
+Ú "
+^U 12,15 0 0333
+Û "
+:U 12,14 0 0334
+Ü "
+'Y 12,15 0 0335
+Ý "
+TP 10,11 0 0336
+Þ "
+ss 9,11 0 0337
+ß "
+`a 8,12 0 0340
+à "
+'a 8,12 0 0341
+á "
+^a 8,12 0 0342
+â "
+~a 8,11 0 0343
+ã "
+:a 8,11 0 0344
+ä "
+oa 8,13 0 0345
+å "
+ae 12,8 0 0346
+æ "
+,c 7,8,4 0 0347
+ç "
+`e 7,12 0 0350
+è "
+'e 7,12 0 0351
+é "
+^e 7,12 0 0352
+ê "
+:e 7,11 0 0353
+ë "
+`i 5,12 0 0354
+ì "
+'i 5,12 0 0355
+í "
+^i 5,12 0 0356
+î "
+:i 5,11 0 0357
+ï "
+Sd 8,11 0 0360
+ð "
+~n 9,11 0 0361
+ñ "
+`o 8,12 0 0362
+ò "
+'o 8,12 0 0363
+ó "
+^o 8,12 0 0364
+ô "
+~o 8,11 0 0365
+õ "
+:o 8,11 0 0366
+ö "
+di 9,8 0 0367
+÷ "
+/o 8,9,1 0 0370
+ø "
+`u 9,12 0 0371
+ù "
+'u 9,12 0 0372
+ú "
+^u 9,12 0 0373
+û "
+:u 9,11 0 0374
+ü "
+'y 8,12,4 0 0375
+ý "
+Tp 9,11,4 0 0376
+þ "
+:y 8,11,4 0 0377
+ÿ "
diff --git a/gnu/usr.bin/groff/devX100-12/TBI b/gnu/usr.bin/groff/devX100-12/TBI
new file mode 100644
index 0000000..71ca713
--- /dev/null
+++ b/gnu/usr.bin/groff/devX100-12/TBI
@@ -0,0 +1,306 @@
+name TBI
+spacewidth 4
+charset
+--- 4,1 0 040
+! 6,11 0 041
+" 9,11 0 042
+# 8,11 0 043
+sh "
+$ 8,12,1 0 044
+Do "
+% 13,11 0 045
+& 13,11 0 046
+' 6,11 0 047
+( 6,11,3 0 050
+) 6,11,3 0 051
+* 8,11 0 052
++ 10,9 0 053
+, 4,2,3 0 054
+\- 10,6 0 055
+. 4,2 0 056
+/ 5,12 0 057
+sl "
+0 8,11 0 060
+1 8,11 0 061
+2 8,11 0 062
+3 8,11 0 063
+4 8,11 0 064
+5 8,11 0 065
+6 8,11 0 066
+7 8,11 0 067
+8 8,11 0 070
+9 8,11 0 071
+: 5,7 0 072
+; 5,7,3 0 073
+< 10,8 0 074
+= 10,7 0 075
+eq "
+> 10,8 0 076
+? 8,11 0 077
+@ 14,11,2 0 0100
+at "
+A 11,11 0 0101
+B 11,11 0 0102
+C 11,11 0 0103
+D 12,11 0 0104
+E 11,11 0 0105
+F 11,11 0 0106
+G 12,11 0 0107
+H 13,11 0 0110
+I 6,11 0 0111
+J 8,11,2 0 0112
+K 11,11 0 0113
+L 10,11 0 0114
+M 15,11 0 0115
+N 12,11 0 0116
+O 12,11 0 0117
+P 10,11 0 0120
+Q 12,11,4 0 0121
+R 11,11 0 0122
+S 9,11 0 0123
+T 10,11 0 0124
+U 12,11 0 0125
+V 11,11 0 0126
+W 15,11 0 0127
+X 11,11 0 0130
+Y 10,11 0 0131
+Z 10,11 0 0132
+[ 6,12,3 0 0133
+lB "
+\ 5,12 0 0134
+rs "
+] 6,12,3 0 0135
+rB "
+^ 10,11 0 0136
+a^ "
+ha "
+_ 8,0,2 0 0137
+` 6,11 0 0140
+oq "
+a 8,8 0 0141
+b 8,11 0 0142
+c 7,8 0 0143
+d 8,11 0 0144
+e 7,8 0 0145
+f 6,11,3 0 0146
+g 8,8,3 0 0147
+h 9,11 0 0150
+i 5,11 0 0151
+j 5,11,3 0 0152
+k 8,11 0 0153
+l 5,11 0 0154
+m 13,8 0 0155
+n 9,8 0 0156
+o 8,8 0 0157
+p 8,8,3 0 0160
+q 8,8,3 0 0161
+r 6,8 0 0162
+s 6,8 0 0163
+t 5,10 0 0164
+u 9,8 0 0165
+v 7,8 0 0166
+w 11,8 0 0167
+x 8,8 0 0170
+y 7,8,3 0 0171
+z 6,8,1 0 0172
+{ 6,12,3 0 0173
+lC "
+| 4,12 0 0174
+or "
+ba "
+} 6,12,3 0 0175
+rC "
+~ 10,6 0 0176
+a~ "
+ap "
+ti "
+r! 6,8,4 0 0241
+¡ "
+ct 8,10,2 0 0242
+¢ "
+Po 8,11 0 0243
+£ "
+Cs 8,9 0 0244
+¤ "
+Ye 8,11 0 0245
+¥ "
+bb 4,12 0 0246
+¦ "
+sc 8,11,3 0 0247
+§ "
+ad 6,11 0 0250
+¨ "
+co 12,11 0 0251
+© "
+Of 4,11 0 0252
+ª "
+Fo 8,7 0 0253
+« "
+no 10,5 0 0254
+¬ "
+- 5,5 0 0255
+hy "
+­ "
+rg 12,11 0 0256
+® "
+a- 6,10 0 0257
+¯ "
+de 7,11 0 0260
+° "
++- 10,10 0 0261
+± "
+S2 5,11 0 0262
+² "
+S3 5,11 0 0263
+³ "
+aa 6,12 0 0264
+´ "
+µ 9,8,3 0 0265
+ps 8,11,3 0 0266
+¶ "
+md 4,5 0 0267
+· "
+ac 6,1,3 0 0270
+¸ "
+S1 5,11 0 0271
+¹ "
+Om 5,11 0 0272
+º "
+Fc 8,7 0 0273
+» "
+14 13,11 0 0274
+¼ "
+12 13,11 0 0275
+½ "
+34 13,11 0 0276
+¾ "
+r? 8,8,4 0 0277
+¿ "
+`A 11,15 0 0300
+À "
+'A 11,15 0 0301
+Á "
+^A 11,15 0 0302
+Â "
+~A 11,14 0 0303
+Ã "
+:A 11,14 0 0304
+Ä "
+oA 11,15 0 0305
+Å "
+AE 15,11 0 0306
+Æ "
+,C 11,11,3 0 0307
+Ç "
+`E 11,15 0 0310
+È "
+'E 11,15 0 0311
+É "
+^E 11,15 0 0312
+Ê "
+:E 11,14 0 0313
+Ë "
+`I 6,15 0 0314
+Ì "
+'I 6,15 0 0315
+Í "
+^I 6,15 0 0316
+Î "
+:I 6,14 0 0317
+Ï "
+-D 12,11 0 0320
+Ð "
+~N 12,14 0 0321
+Ñ "
+`O 12,15 0 0322
+Ò "
+'O 12,15 0 0323
+Ó "
+^O 12,15 0 0324
+Ô "
+~O 12,14 0 0325
+Õ "
+:O 12,14 0 0326
+Ö "
+mu 10,9 0 0327
+× "
+/O 12,12,2 0 0330
+Ø "
+`U 12,15 0 0331
+Ù "
+'U 12,15 0 0332
+Ú "
+^U 12,15 0 0333
+Û "
+:U 12,14 0 0334
+Ü "
+'Y 10,15 0 0335
+Ý "
+TP 10,11 0 0336
+Þ "
+ss 8,12,3 0 0337
+ß "
+`a 8,12 0 0340
+à "
+'a 8,12 0 0341
+á "
+^a 8,12 0 0342
+â "
+~a 8,11 0 0343
+ã "
+:a 8,11 0 0344
+ä "
+oa 8,12 0 0345
+å "
+ae 12,8 0 0346
+æ "
+,c 7,8,3 0 0347
+ç "
+`e 7,12 0 0350
+è "
+'e 7,12 0 0351
+é "
+^e 7,12 0 0352
+ê "
+:e 7,11 0 0353
+ë "
+`i 5,12 0 0354
+ì "
+'i 5,12 0 0355
+í "
+^i 5,12 0 0356
+î "
+:i 5,11 0 0357
+ï "
+Sd 8,11 0 0360
+ð "
+~n 9,11 0 0361
+ñ "
+`o 8,12 0 0362
+ò "
+'o 8,12 0 0363
+ó "
+^o 8,12 0 0364
+ô "
+~o 8,11 0 0365
+õ "
+:o 8,11 0 0366
+ö "
+di 10,9 0 0367
+÷ "
+/o 8,10,2 0 0370
+ø "
+`u 9,12 0 0371
+ù "
+'u 9,12 0 0372
+ú "
+^u 9,12 0 0373
+û "
+:u 9,11 0 0374
+ü "
+'y 7,12,3 0 0375
+ý "
+Tp 8,11,3 0 0376
+þ "
+:y 7,11,3 0 0377
+ÿ "
diff --git a/gnu/usr.bin/groff/devX100-12/TI b/gnu/usr.bin/groff/devX100-12/TI
new file mode 100644
index 0000000..fad269f
--- /dev/null
+++ b/gnu/usr.bin/groff/devX100-12/TI
@@ -0,0 +1,306 @@
+name TI
+spacewidth 4
+charset
+--- 4,1 0 040
+! 6,11 0 041
+" 7,10 0 042
+# 8,11 0 043
+sh "
+$ 8,12,1 0 044
+Do "
+% 13,11 0 045
+& 13,11 0 046
+' 6,10 0 047
+( 6,11,3 0 050
+) 6,11,3 0 051
+* 8,11 0 052
++ 11,9 0 053
+, 4,2,2 0 054
+\- 11,5 0 055
+. 4,2 0 056
+/ 5,11 0 057
+sl "
+0 8,11 0 060
+1 8,11 0 061
+2 8,11 0 062
+3 8,11 0 063
+4 8,11 0 064
+5 8,11 0 065
+6 8,11 0 066
+7 8,11 0 067
+8 8,11 0 070
+9 8,11 0 071
+: 5,7 0 072
+; 5,7,2 0 073
+< 11,9 0 074
+= 11,6 0 075
+eq "
+> 11,9 0 076
+? 8,11 0 077
+@ 15,11,3 0 0100
+at "
+A 10,11 0 0101
+B 10,11 0 0102
+C 11,11 0 0103
+D 12,11 0 0104
+E 10,11 0 0105
+F 10,11 0 0106
+G 12,11 0 0107
+H 12,11 0 0110
+I 6,11 0 0111
+J 7,11 0 0112
+K 11,11 0 0113
+L 9,11 0 0114
+M 14,11 0 0115
+N 11,11 0 0116
+O 12,11 0 0117
+P 10,11 0 0120
+Q 12,11,3 0 0121
+R 10,11 0 0122
+S 8,11 0 0123
+T 9,11 0 0124
+U 12,11 0 0125
+V 10,11 0 0126
+W 14,11 0 0127
+X 10,11 0 0130
+Y 9,11 0 0131
+Z 9,11 0 0132
+[ 6,11,3 0 0133
+lB "
+\ 5,11 0 0134
+rs "
+] 6,11,3 0 0135
+rB "
+^ 7,11 0 0136
+a^ "
+ha "
+_ 8,0,4 0 0137
+` 6,10 0 0140
+oq "
+a 8,8 0 0141
+b 8,11 0 0142
+c 7,8 0 0143
+d 8,11 0 0144
+e 7,8 0 0145
+f 5,11,4 0 0146
+g 8,8,4 0 0147
+h 8,11 0 0150
+i 5,11 0 0151
+j 5,11,4 0 0152
+k 7,11 0 0153
+l 5,11 0 0154
+m 12,8 0 0155
+n 8,8 0 0156
+o 8,8 0 0157
+p 8,8,4 0 0160
+q 8,8,4 0 0161
+r 6,8 0 0162
+s 6,8 0 0163
+t 5,10 0 0164
+u 8,8 0 0165
+v 7,8 0 0166
+w 11,8 0 0167
+x 7,8 0 0170
+y 7,8,4 0 0171
+z 6,8 0 0172
+{ 7,11,3 0 0173
+lC "
+| 5,11,3 0 0174
+or "
+ba "
+} 7,11,3 0 0175
+rC "
+~ 9,6 0 0176
+a~ "
+ap "
+ti "
+r! 6,8,3 0 0241
+¡ "
+ct 8,9,1 0 0242
+¢ "
+Po 8,11 0 0243
+£ "
+Cs 8,9 0 0244
+¤ "
+Ye 8,11 0 0245
+¥ "
+bb 5,11,3 0 0246
+¦ "
+sc 8,12,1 0 0247
+§ "
+ad 6,11 0 0250
+¨ "
+co 13,11 0 0251
+© "
+Of 5,11 0 0252
+ª "
+Fo 8,6 0 0253
+« "
+no 11,6 0 0254
+¬ "
+- 5,4 0 0255
+hy "
+­ "
+rg 13,11 0 0256
+® "
+a- 6,10 0 0257
+¯ "
+de 7,11 0 0260
+° "
++- 11,11 0 0261
+± "
+S2 5,11 0 0262
+² "
+S3 5,11 0 0263
+³ "
+aa 6,12 0 0264
+´ "
+µ 8,8,4 0 0265
+ps 9,11,3 0 0266
+¶ "
+md 4,5 0 0267
+· "
+ac 6,1,3 0 0270
+¸ "
+S1 5,11 0 0271
+¹ "
+Om 5,11 0 0272
+º "
+Fc 8,6 0 0273
+» "
+14 13,11 0 0274
+¼ "
+12 13,11 0 0275
+½ "
+34 13,11 0 0276
+¾ "
+r? 8,8,3 0 0277
+¿ "
+`A 10,15 0 0300
+À "
+'A 10,15 0 0301
+Á "
+^A 10,15 0 0302
+Â "
+~A 10,14 0 0303
+Ã "
+:A 10,14 0 0304
+Ä "
+oA 10,15 0 0305
+Å "
+AE 15,11 0 0306
+Æ "
+,C 11,11,3 0 0307
+Ç "
+`E 10,15 0 0310
+È "
+'E 10,15 0 0311
+É "
+^E 10,15 0 0312
+Ê "
+:E 10,14 0 0313
+Ë "
+`I 6,15 0 0314
+Ì "
+'I 6,15 0 0315
+Í "
+^I 6,15 0 0316
+Î "
+:I 6,14 0 0317
+Ï "
+-D 12,11 0 0320
+Ð "
+~N 11,14 0 0321
+Ñ "
+`O 12,15 0 0322
+Ò "
+'O 12,15 0 0323
+Ó "
+^O 12,15 0 0324
+Ô "
+~O 12,14 0 0325
+Õ "
+:O 12,14 0 0326
+Ö "
+mu 11,9 0 0327
+× "
+/O 12,12,1 0 0330
+Ø "
+`U 12,15 0 0331
+Ù "
+'U 12,15 0 0332
+Ú "
+^U 12,15 0 0333
+Û "
+:U 12,14 0 0334
+Ü "
+'Y 9,15 0 0335
+Ý "
+TP 10,11 0 0336
+Þ "
+ss 8,11,4 0 0337
+ß "
+`a 8,12 0 0340
+à "
+'a 8,12 0 0341
+á "
+^a 8,12 0 0342
+â "
+~a 8,11 0 0343
+ã "
+:a 8,11 0 0344
+ä "
+oa 8,13 0 0345
+å "
+ae 11,8 0 0346
+æ "
+,c 7,8,3 0 0347
+ç "
+`e 7,12 0 0350
+è "
+'e 7,12 0 0351
+é "
+^e 7,12 0 0352
+ê "
+:e 7,11 0 0353
+ë "
+`i 5,12 0 0354
+ì "
+'i 5,12 0 0355
+í "
+^i 5,12 0 0356
+î "
+:i 5,11 0 0357
+ï "
+Sd 8,12 0 0360
+ð "
+~n 8,11 0 0361
+ñ "
+`o 8,12 0 0362
+ò "
+'o 8,12 0 0363
+ó "
+^o 8,12 0 0364
+ô "
+~o 8,11 0 0365
+õ "
+:o 8,11 0 0366
+ö "
+di 11,8 0 0367
+÷ "
+/o 8,9,1 0 0370
+ø "
+`u 8,12 0 0371
+ù "
+'u 8,12 0 0372
+ú "
+^u 8,12 0 0373
+û "
+:u 8,11 0 0374
+ü "
+'y 7,12,4 0 0375
+ý "
+Tp 8,11,4 0 0376
+þ "
+:y 7,11,4 0 0377
+ÿ "
diff --git a/gnu/usr.bin/groff/devX100-12/TR b/gnu/usr.bin/groff/devX100-12/TR
new file mode 100644
index 0000000..6db573e
--- /dev/null
+++ b/gnu/usr.bin/groff/devX100-12/TR
@@ -0,0 +1,306 @@
+name TR
+spacewidth 4
+charset
+--- 4,1 0 040
+! 5,11 0 041
+" 7,11 0 042
+# 8,11 0 043
+sh "
+$ 8,12,1 0 044
+Do "
+% 14,11 0 045
+& 13,11 0 046
+' 5,11 0 047
+( 5,11,3 0 050
+) 5,11,3 0 051
+* 8,11 0 052
++ 9,8 0 053
+, 4,2,1 0 054
+\- 9,5 0 055
+. 4,2 0 056
+/ 5,11,2 0 057
+sl "
+0 8,11 0 060
+1 8,11 0 061
+2 8,11 0 062
+3 8,11 0 063
+4 8,11 0 064
+5 8,11 0 065
+6 8,11 0 066
+7 8,11 0 067
+8 8,11 0 070
+9 8,11 0 071
+: 4,8 0 072
+; 4,8,1 0 073
+< 9,9 0 074
+= 9,6 0 075
+eq "
+> 9,9 0 076
+? 7,11 0 077
+@ 15,11,3 0 0100
+at "
+A 12,11 0 0101
+B 11,11 0 0102
+C 11,11 0 0103
+D 12,11 0 0104
+E 10,11 0 0105
+F 9,11 0 0106
+G 12,11 0 0107
+H 12,11 0 0110
+I 5,11 0 0111
+J 6,11 0 0112
+K 12,11 0 0113
+L 10,11 0 0114
+M 15,11 0 0115
+N 12,11 0 0116
+O 12,11 0 0117
+P 9,11 0 0120
+Q 12,11,3 0 0121
+R 11,11 0 0122
+S 9,11 0 0123
+T 10,11 0 0124
+U 12,11 0 0125
+V 12,11 0 0126
+W 16,11 0 0127
+X 12,11 0 0130
+Y 12,11 0 0131
+Z 10,11 0 0132
+[ 5,11,3 0 0133
+lB "
+\ 5,11 0 0134
+rs "
+] 5,11,3 0 0135
+rB "
+^ 8,11 0 0136
+a^ "
+ha "
+_ 8,0,2 0 0137
+` 5,11 0 0140
+oq "
+a 7,8 0 0141
+b 8,11 0 0142
+c 7,8 0 0143
+d 8,11 0 0144
+e 7,8 0 0145
+f 6,11 0 0146
+g 8,8,4 0 0147
+h 8,11 0 0150
+i 5,11 0 0151
+j 4,11,4 0 0152
+k 8,11 0 0153
+l 5,11 0 0154
+m 13,8 0 0155
+n 8,8 0 0156
+o 8,8 0 0157
+p 8,8,4 0 0160
+q 8,8,4 0 0161
+r 6,8 0 0162
+s 6,8 0 0163
+t 5,10 0 0164
+u 8,8 0 0165
+v 8,8 0 0166
+w 12,8 0 0167
+x 8,8 0 0170
+y 8,8,4 0 0171
+z 7,8 0 0172
+{ 8,11,3 0 0173
+lC "
+| 3,11 0 0174
+or "
+ba "
+} 8,11,3 0 0175
+rC "
+~ 9,6 0 0176
+a~ "
+ap "
+ti "
+r! 5,8,3 0 0241
+¡ "
+ct 8,10,2 0 0242
+¢ "
+Po 8,11 0 0243
+£ "
+Cs 8,10 0 0244
+¤ "
+Ye 8,11 0 0245
+¥ "
+bb 3,11 0 0246
+¦ "
+sc 8,11,3 0 0247
+§ "
+ad 6,11 0 0250
+¨ "
+co 13,11 0 0251
+© "
+Of 5,11 0 0252
+ª "
+Fo 8,7 0 0253
+« "
+no 9,5 0 0254
+¬ "
+- 5,5 0 0255
+hy "
+­ "
+rg 13,11 0 0256
+® "
+a- 6,10 0 0257
+¯ "
+de 7,11 0 0260
+° "
++- 9,9 0 0261
+± "
+S2 5,11 0 0262
+² "
+S3 5,11 0 0263
+³ "
+aa 6,11 0 0264
+´ "
+µ 8,8,3 0 0265
+ps 8,11,4 0 0266
+¶ "
+md 4,6 0 0267
+· "
+ac 6,0,4 0 0270
+¸ "
+S1 5,11 0 0271
+¹ "
+Om 5,11 0 0272
+º "
+Fc 8,7 0 0273
+» "
+14 13,11 0 0274
+¼ "
+12 13,11 0 0275
+½ "
+34 13,11 0 0276
+¾ "
+r? 7,8,3 0 0277
+¿ "
+`A 12,15 0 0300
+À "
+'A 12,15 0 0301
+Á "
+^A 12,15 0 0302
+Â "
+~A 12,14 0 0303
+Ã "
+:A 12,14 0 0304
+Ä "
+oA 12,14 0 0305
+Å "
+AE 15,11 0 0306
+Æ "
+,C 11,11,4 0 0307
+Ç "
+`E 10,15 0 0310
+È "
+'E 10,15 0 0311
+É "
+^E 10,15 0 0312
+Ê "
+:E 10,14 0 0313
+Ë "
+`I 5,15 0 0314
+Ì "
+'I 5,15 0 0315
+Í "
+^I 5,15 0 0316
+Î "
+:I 5,14 0 0317
+Ï "
+-D 12,11 0 0320
+Ð "
+~N 12,14 0 0321
+Ñ "
+`O 12,15 0 0322
+Ò "
+'O 12,15 0 0323
+Ó "
+^O 12,15 0 0324
+Ô "
+~O 12,14 0 0325
+Õ "
+:O 12,14 0 0326
+Ö "
+mu 9,7 0 0327
+× "
+/O 12,12,1 0 0330
+Ø "
+`U 12,15 0 0331
+Ù "
+'U 12,15 0 0332
+Ú "
+^U 12,15 0 0333
+Û "
+:U 12,14 0 0334
+Ü "
+'Y 12,15 0 0335
+Ý "
+TP 9,11 0 0336
+Þ "
+ss 8,11 0 0337
+ß "
+`a 7,12 0 0340
+à "
+'a 7,12 0 0341
+á "
+^a 7,12 0 0342
+â "
+~a 7,11 0 0343
+ã "
+:a 7,11 0 0344
+ä "
+oa 7,12 0 0345
+å "
+ae 11,8 0 0346
+æ "
+,c 7,8,4 0 0347
+ç "
+`e 7,12 0 0350
+è "
+'e 7,12 0 0351
+é "
+^e 7,12 0 0352
+ê "
+:e 7,11 0 0353
+ë "
+`i 5,12 0 0354
+ì "
+'i 5,12 0 0355
+í "
+^i 5,12 0 0356
+î "
+:i 5,11 0 0357
+ï "
+Sd 8,11 0 0360
+ð "
+~n 8,11 0 0361
+ñ "
+`o 8,12 0 0362
+ò "
+'o 8,12 0 0363
+ó "
+^o 8,12 0 0364
+ô "
+~o 8,11 0 0365
+õ "
+:o 8,11 0 0366
+ö "
+di 9,9 0 0367
+÷ "
+/o 8,10,2 0 0370
+ø "
+`u 8,12 0 0371
+ù "
+'u 8,12 0 0372
+ú "
+^u 8,12 0 0373
+û "
+:u 8,11 0 0374
+ü "
+'y 8,12,4 0 0375
+ý "
+Tp 8,11,4 0 0376
+þ "
+:y 8,11,4 0 0377
+ÿ "
diff --git a/gnu/usr.bin/groff/devX100/CB b/gnu/usr.bin/groff/devX100/CB
new file mode 100644
index 0000000..7239ed1
--- /dev/null
+++ b/gnu/usr.bin/groff/devX100/CB
@@ -0,0 +1,306 @@
+name CB
+spacewidth 9
+charset
+--- 9,1 0 040
+! 9,9 0 041
+" 9,10 0 042
+# 9,10,1 0 043
+sh "
+$ 9,11,1 0 044
+Do "
+% 9,10 0 045
+& 9,8 0 046
+' 9,10 0 047
+( 9,9,2 0 050
+) 9,9,2 0 051
+* 9,9 0 052
++ 9,8 0 053
+, 9,2,2 0 054
+\- 9,5 0 055
+. 9,2 0 056
+/ 9,10,2 0 057
+sl "
+0 9,10 0 060
+1 9,10 0 061
+2 9,10 0 062
+3 9,10 0 063
+4 9,10 0 064
+5 9,10 0 065
+6 9,10 0 066
+7 9,10 0 067
+8 9,10 0 070
+9 9,10 0 071
+: 9,7 0 072
+; 9,7,2 0 073
+< 9,8 0 074
+= 9,6 0 075
+eq "
+> 9,8 0 076
+? 9,9 0 077
+@ 9,9 0 0100
+at "
+A 9,9 0 0101
+B 9,9 0 0102
+C 9,9 0 0103
+D 9,9 0 0104
+E 9,9 0 0105
+F 9,9 0 0106
+G 9,9 0 0107
+H 9,9 0 0110
+I 9,9 0 0111
+J 9,9 0 0112
+K 9,9 0 0113
+L 9,9 0 0114
+M 9,9 0 0115
+N 9,9 0 0116
+O 9,9 0 0117
+P 9,9 0 0120
+Q 9,9,2 0 0121
+R 9,9 0 0122
+S 9,9 0 0123
+T 9,9 0 0124
+U 9,9 0 0125
+V 9,9 0 0126
+W 9,9 0 0127
+X 9,9 0 0130
+Y 9,9 0 0131
+Z 9,9 0 0132
+[ 9,9,2 0 0133
+lB "
+\ 9,10,2 0 0134
+rs "
+] 9,9,2 0 0135
+rB "
+^ 9,9 0 0136
+a^ "
+ha "
+_ 9,0,2 0 0137
+` 9,10 0 0140
+oq "
+a 9,7 0 0141
+b 9,10 0 0142
+c 9,7 0 0143
+d 9,10 0 0144
+e 9,7 0 0145
+f 9,10 0 0146
+g 9,7,3 0 0147
+h 9,10 0 0150
+i 9,10 0 0151
+j 9,10,3 0 0152
+k 9,10 0 0153
+l 9,10 0 0154
+m 9,7 0 0155
+n 9,7 0 0156
+o 9,7 0 0157
+p 9,7,3 0 0160
+q 9,7,3 0 0161
+r 9,7 0 0162
+s 9,7 0 0163
+t 9,9 0 0164
+u 9,7 0 0165
+v 9,7 0 0166
+w 9,7 0 0167
+x 9,7 0 0170
+y 9,7,3 0 0171
+z 9,7 0 0172
+{ 9,9,2 0 0173
+lC "
+| 9,9,2 0 0174
+or "
+ba "
+} 9,9,2 0 0175
+rC "
+~ 9,6 0 0176
+a~ "
+ap "
+ti "
+r! 9,7,2 0 0241
+¡ "
+ct 9,9,1 0 0242
+¢ "
+Po 9,9 0 0243
+£ "
+Cs 9,7 0 0244
+¤ "
+Ye 9,9 0 0245
+¥ "
+bb 9,9,2 0 0246
+¦ "
+sc 9,10,1 0 0247
+§ "
+ad 9,10 0 0250
+¨ "
+co 9,9 0 0251
+© "
+Of 9,9 0 0252
+ª "
+Fo 9,6 0 0253
+« "
+no 9,5 0 0254
+¬ "
+- 9,5 0 0255
+hy "
+­ "
+rg 9,9 0 0256
+® "
+a- 9,9 0 0257
+¯ "
+de 9,9 0 0260
+° "
++- 9,8 0 0261
+± "
+S2 9,10 0 0262
+² "
+S3 9,10 0 0263
+³ "
+aa 9,9 0 0264
+´ "
+µ 9,7,3 0 0265
+ps 9,10,1 0 0266
+¶ "
+md 9,5 0 0267
+· "
+ac 9,1,3 0 0270
+¸ "
+S1 9,10 0 0271
+¹ "
+Om 9,9 0 0272
+º "
+Fc 9,6 0 0273
+» "
+14 9,10 0 0274
+¼ "
+12 9,10 0 0275
+½ "
+34 9,10 0 0276
+¾ "
+r? 9,7,2 0 0277
+¿ "
+`A 9,12 0 0300
+À "
+'A 9,12 0 0301
+Á "
+^A 9,12 0 0302
+Â "
+~A 9,12 0 0303
+Ã "
+:A 9,12 0 0304
+Ä "
+oA 9,12 0 0305
+Å "
+AE 9,9 0 0306
+Æ "
+,C 9,9,4 0 0307
+Ç "
+`E 9,12 0 0310
+È "
+'E 9,12 0 0311
+É "
+^E 9,12 0 0312
+Ê "
+:E 9,12 0 0313
+Ë "
+`I 9,12 0 0314
+Ì "
+'I 9,12 0 0315
+Í "
+^I 9,12 0 0316
+Î "
+:I 9,12 0 0317
+Ï "
+-D 9,9 0 0320
+Ð "
+~N 9,12 0 0321
+Ñ "
+`O 9,12 0 0322
+Ò "
+'O 9,12 0 0323
+Ó "
+^O 9,12 0 0324
+Ô "
+~O 9,12 0 0325
+Õ "
+:O 9,12 0 0326
+Ö "
+mu 9,8 0 0327
+× "
+/O 9,10 0 0330
+Ø "
+`U 9,12 0 0331
+Ù "
+'U 9,12 0 0332
+Ú "
+^U 9,12 0 0333
+Û "
+:U 9,12 0 0334
+Ü "
+'Y 9,12 0 0335
+Ý "
+TP 9,9 0 0336
+Þ "
+ss 9,9 0 0337
+ß "
+`a 9,10 0 0340
+à "
+'a 9,10 0 0341
+á "
+^a 9,10 0 0342
+â "
+~a 9,10 0 0343
+ã "
+:a 9,10 0 0344
+ä "
+oa 9,10 0 0345
+å "
+ae 9,7 0 0346
+æ "
+,c 9,7,4 0 0347
+ç "
+`e 9,10 0 0350
+è "
+'e 9,10 0 0351
+é "
+^e 9,10 0 0352
+ê "
+:e 9,10 0 0353
+ë "
+`i 9,10 0 0354
+ì "
+'i 9,10 0 0355
+í "
+^i 9,10 0 0356
+î "
+:i 9,10 0 0357
+ï "
+Sd 9,10 0 0360
+ð "
+~n 9,10 0 0361
+ñ "
+`o 9,10 0 0362
+ò "
+'o 9,10 0 0363
+ó "
+^o 9,10 0 0364
+ô "
+~o 9,10 0 0365
+õ "
+:o 9,10 0 0366
+ö "
+di 9,8 0 0367
+÷ "
+/o 9,7 0 0370
+ø "
+`u 9,10 0 0371
+ù "
+'u 9,10 0 0372
+ú "
+^u 9,10 0 0373
+û "
+:u 9,10 0 0374
+ü "
+'y 9,10,3 0 0375
+ý "
+Tp 9,9,3 0 0376
+þ "
+:y 9,10,3 0 0377
+ÿ "
diff --git a/gnu/usr.bin/groff/devX100/CBI b/gnu/usr.bin/groff/devX100/CBI
new file mode 100644
index 0000000..384f91d
--- /dev/null
+++ b/gnu/usr.bin/groff/devX100/CBI
@@ -0,0 +1,306 @@
+name CBI
+spacewidth 9
+charset
+--- 9,1 0 040
+! 9,10 0 041
+" 9,9 0 042
+# 9,11,1 0 043
+sh "
+$ 9,11,1 0 044
+Do "
+% 9,10 0 045
+& 9,8 0 046
+' 9,9 0 047
+( 9,9,2 0 050
+) 9,9,2 0 051
+* 9,10 0 052
++ 9,8 0 053
+, 9,2,2 0 054
+\- 9,5 0 055
+. 9,2 0 056
+/ 9,10,2 0 057
+sl "
+0 9,10 0 060
+1 9,10 0 061
+2 9,10 0 062
+3 9,10 0 063
+4 9,10 0 064
+5 9,10 0 065
+6 9,10 0 066
+7 9,10 0 067
+8 9,10 0 070
+9 9,10 0 071
+: 9,7 0 072
+; 9,7,2 0 073
+< 9,8 0 074
+= 9,6 0 075
+eq "
+> 9,8 0 076
+? 9,9 0 077
+@ 9,9 0 0100
+at "
+A 9,9 0 0101
+B 9,9 0 0102
+C 9,9 0 0103
+D 9,9 0 0104
+E 9,9 0 0105
+F 9,9 0 0106
+G 9,9 0 0107
+H 9,9 0 0110
+I 9,9 0 0111
+J 9,9 0 0112
+K 9,9 0 0113
+L 9,9 0 0114
+M 9,9 0 0115
+N 9,9 0 0116
+O 9,9 0 0117
+P 9,9 0 0120
+Q 9,9,2 0 0121
+R 9,9 0 0122
+S 9,9 0 0123
+T 9,9 0 0124
+U 9,9 0 0125
+V 9,9 0 0126
+W 9,9 0 0127
+X 9,9 0 0130
+Y 9,9 0 0131
+Z 9,9 0 0132
+[ 9,9,2 0 0133
+lB "
+\ 9,10,2 0 0134
+rs "
+] 9,9,2 0 0135
+rB "
+^ 9,9 0 0136
+a^ "
+ha "
+_ 9,0,3 0 0137
+` 9,9 0 0140
+oq "
+a 9,7 0 0141
+b 9,10 0 0142
+c 9,7 0 0143
+d 9,10 0 0144
+e 9,7 0 0145
+f 9,10 0 0146
+g 9,7,3 0 0147
+h 9,10 0 0150
+i 9,10 0 0151
+j 9,10,3 0 0152
+k 9,10 0 0153
+l 9,10 0 0154
+m 9,7 0 0155
+n 9,7 0 0156
+o 9,7 0 0157
+p 9,7,3 0 0160
+q 9,7,3 0 0161
+r 9,7 0 0162
+s 9,7 0 0163
+t 9,9 0 0164
+u 9,7 0 0165
+v 9,7 0 0166
+w 9,7 0 0167
+x 9,7 0 0170
+y 9,7,3 0 0171
+z 9,7 0 0172
+{ 9,9,2 0 0173
+lC "
+| 9,9,2 0 0174
+or "
+ba "
+} 9,9,2 0 0175
+rC "
+~ 9,6 0 0176
+a~ "
+ap "
+ti "
+r! 9,7,3 0 0241
+¡ "
+ct 9,9,1 0 0242
+¢ "
+Po 9,9 0 0243
+£ "
+Cs 9,7 0 0244
+¤ "
+Ye 9,9 0 0245
+¥ "
+bb 9,10,2 0 0246
+¦ "
+sc 9,10,1 0 0247
+§ "
+ad 9,10 0 0250
+¨ "
+co 9,9 0 0251
+© "
+Of 9,9 0 0252
+ª "
+Fo 9,6 0 0253
+« "
+no 9,6 0 0254
+¬ "
+- 9,5 0 0255
+hy "
+­ "
+rg 9,9 0 0256
+® "
+a- 9,9 0 0257
+¯ "
+de 9,10 0 0260
+° "
++- 9,8 0 0261
+± "
+S2 9,10 0 0262
+² "
+S3 9,10 0 0263
+³ "
+aa 9,10 0 0264
+´ "
+µ 9,7,3 0 0265
+ps 9,10,1 0 0266
+¶ "
+md 9,5 0 0267
+· "
+ac 9,1,3 0 0270
+¸ "
+S1 9,10 0 0271
+¹ "
+Om 9,9 0 0272
+º "
+Fc 9,6 0 0273
+» "
+14 9,10 0 0274
+¼ "
+12 9,10 0 0275
+½ "
+34 9,10 0 0276
+¾ "
+r? 9,7,2 0 0277
+¿ "
+`A 9,12 0 0300
+À "
+'A 9,12 0 0301
+Á "
+^A 9,12 0 0302
+Â "
+~A 9,12 0 0303
+Ã "
+:A 9,12 0 0304
+Ä "
+oA 9,12 0 0305
+Å "
+AE 9,9 0 0306
+Æ "
+,C 9,9,4 0 0307
+Ç "
+`E 9,12 0 0310
+È "
+'E 9,12 0 0311
+É "
+^E 9,12 0 0312
+Ê "
+:E 9,12 0 0313
+Ë "
+`I 9,12 0 0314
+Ì "
+'I 9,12 0 0315
+Í "
+^I 9,12 0 0316
+Î "
+:I 9,12 0 0317
+Ï "
+-D 9,9 0 0320
+Ð "
+~N 9,12 0 0321
+Ñ "
+`O 9,12 0 0322
+Ò "
+'O 9,12 0 0323
+Ó "
+^O 9,12 0 0324
+Ô "
+~O 9,12 0 0325
+Õ "
+:O 9,12 0 0326
+Ö "
+mu 9,8 0 0327
+× "
+/O 9,9 0 0330
+Ø "
+`U 9,12 0 0331
+Ù "
+'U 9,12 0 0332
+Ú "
+^U 9,12 0 0333
+Û "
+:U 9,12 0 0334
+Ü "
+'Y 9,12 0 0335
+Ý "
+TP 9,9 0 0336
+Þ "
+ss 9,9 0 0337
+ß "
+`a 9,10 0 0340
+à "
+'a 9,10 0 0341
+á "
+^a 9,10 0 0342
+â "
+~a 9,10 0 0343
+ã "
+:a 9,10 0 0344
+ä "
+oa 9,10 0 0345
+å "
+ae 9,7 0 0346
+æ "
+,c 9,7,4 0 0347
+ç "
+`e 9,10 0 0350
+è "
+'e 9,10 0 0351
+é "
+^e 9,10 0 0352
+ê "
+:e 9,10 0 0353
+ë "
+`i 9,10 0 0354
+ì "
+'i 9,10 0 0355
+í "
+^i 9,10 0 0356
+î "
+:i 9,10 0 0357
+ï "
+Sd 9,10 0 0360
+ð "
+~n 9,10 0 0361
+ñ "
+`o 9,10 0 0362
+ò "
+'o 9,10 0 0363
+ó "
+^o 9,10 0 0364
+ô "
+~o 9,10 0 0365
+õ "
+:o 9,10 0 0366
+ö "
+di 9,8 0 0367
+÷ "
+/o 9,8 0 0370
+ø "
+`u 9,10 0 0371
+ù "
+'u 9,10 0 0372
+ú "
+^u 9,10 0 0373
+û "
+:u 9,10 0 0374
+ü "
+'y 9,10,3 0 0375
+ý "
+Tp 9,9,3 0 0376
+þ "
+:y 9,10,3 0 0377
+ÿ "
diff --git a/gnu/usr.bin/groff/devX100/CI b/gnu/usr.bin/groff/devX100/CI
new file mode 100644
index 0000000..07fd0a6
--- /dev/null
+++ b/gnu/usr.bin/groff/devX100/CI
@@ -0,0 +1,306 @@
+name CI
+spacewidth 9
+charset
+--- 9,1 0 040
+! 9,9 0 041
+" 9,10 0 042
+# 9,10,1 0 043
+sh "
+$ 9,10,1 0 044
+Do "
+% 9,10 0 045
+& 9,8 0 046
+' 9,10 0 047
+( 9,10,3 0 050
+) 9,10,3 0 051
+* 9,9 0 052
++ 9,8 0 053
+, 9,2,2 0 054
+\- 9,5 0 055
+. 9,2 0 056
+/ 9,10,2 0 057
+sl "
+0 9,10 0 060
+1 9,10 0 061
+2 9,10 0 062
+3 9,10 0 063
+4 9,10 0 064
+5 9,10 0 065
+6 9,10 0 066
+7 9,10 0 067
+8 9,10 0 070
+9 9,10 0 071
+: 9,7 0 072
+; 9,7,2 0 073
+< 9,8 0 074
+= 9,6 0 075
+eq "
+> 9,8 0 076
+? 9,9 0 077
+@ 9,9 0 0100
+at "
+A 9,9 0 0101
+B 9,9 0 0102
+C 9,9 0 0103
+D 9,9 0 0104
+E 9,9 0 0105
+F 9,9 0 0106
+G 9,9 0 0107
+H 9,9 0 0110
+I 9,9 0 0111
+J 9,9 0 0112
+K 9,9 0 0113
+L 9,9 0 0114
+M 9,9 0 0115
+N 9,9 0 0116
+O 9,9 0 0117
+P 9,9 0 0120
+Q 9,9,2 0 0121
+R 9,9 0 0122
+S 9,9 0 0123
+T 9,9 0 0124
+U 9,9 0 0125
+V 9,9 0 0126
+W 9,9 0 0127
+X 9,9 0 0130
+Y 9,9 0 0131
+Z 9,9 0 0132
+[ 9,10,3 0 0133
+lB "
+\ 9,10,2 0 0134
+rs "
+] 9,10,3 0 0135
+rB "
+^ 9,9 0 0136
+a^ "
+ha "
+_ 9,0,3 0 0137
+` 9,10 0 0140
+oq "
+a 9,7 0 0141
+b 9,10 0 0142
+c 9,7 0 0143
+d 9,10 0 0144
+e 9,7 0 0145
+f 9,10 0 0146
+g 9,7,3 0 0147
+h 9,10 0 0150
+i 9,10 0 0151
+j 9,10,3 0 0152
+k 9,10 0 0153
+l 9,10 0 0154
+m 9,7 0 0155
+n 9,7 0 0156
+o 9,7 0 0157
+p 9,7,3 0 0160
+q 9,7,3 0 0161
+r 9,7 0 0162
+s 9,7 0 0163
+t 9,9 0 0164
+u 9,7 0 0165
+v 9,7 0 0166
+w 9,7 0 0167
+x 9,7 0 0170
+y 9,7,3 0 0171
+z 9,7 0 0172
+{ 9,10,3 0 0173
+lC "
+| 9,9,2 0 0174
+or "
+ba "
+} 9,10,3 0 0175
+rC "
+~ 9,5 0 0176
+a~ "
+ap "
+ti "
+r! 9,7,2 0 0241
+¡ "
+ct 9,10 0 0242
+¢ "
+Po 9,9 0 0243
+£ "
+Cs 9,7 0 0244
+¤ "
+Ye 9,9 0 0245
+¥ "
+bb 9,9,2 0 0246
+¦ "
+sc 9,9,1 0 0247
+§ "
+ad 9,9 0 0250
+¨ "
+co 9,9 0 0251
+© "
+Of 9,9 0 0252
+ª "
+Fo 9,7 0 0253
+« "
+no 9,6 0 0254
+¬ "
+- 9,5 0 0255
+hy "
+­ "
+rg 9,9 0 0256
+® "
+a- 9,9 0 0257
+¯ "
+de 9,10 0 0260
+° "
++- 9,8 0 0261
+± "
+S2 9,10 0 0262
+² "
+S3 9,10 0 0263
+³ "
+aa 9,9 0 0264
+´ "
+µ 9,7,3 0 0265
+ps 9,9,1 0 0266
+¶ "
+md 9,5 0 0267
+· "
+ac 9,1,3 0 0270
+¸ "
+S1 9,10 0 0271
+¹ "
+Om 9,9 0 0272
+º "
+Fc 9,7 0 0273
+» "
+14 9,10 0 0274
+¼ "
+12 9,10 0 0275
+½ "
+34 9,10 0 0276
+¾ "
+r? 9,7,2 0 0277
+¿ "
+`A 9,12 0 0300
+À "
+'A 9,12 0 0301
+Á "
+^A 9,12 0 0302
+Â "
+~A 9,12 0 0303
+Ã "
+:A 9,11 0 0304
+Ä "
+oA 9,12 0 0305
+Å "
+AE 9,9 0 0306
+Æ "
+,C 9,9,3 0 0307
+Ç "
+`E 9,12 0 0310
+È "
+'E 9,12 0 0311
+É "
+^E 9,12 0 0312
+Ê "
+:E 9,11 0 0313
+Ë "
+`I 9,12 0 0314
+Ì "
+'I 9,12 0 0315
+Í "
+^I 9,12 0 0316
+Î "
+:I 9,11 0 0317
+Ï "
+-D 9,9 0 0320
+Ð "
+~N 9,12 0 0321
+Ñ "
+`O 9,12 0 0322
+Ò "
+'O 9,12 0 0323
+Ó "
+^O 9,12 0 0324
+Ô "
+~O 9,12 0 0325
+Õ "
+:O 9,11 0 0326
+Ö "
+mu 9,8 0 0327
+× "
+/O 9,9 0 0330
+Ø "
+`U 9,12 0 0331
+Ù "
+'U 9,12 0 0332
+Ú "
+^U 9,12 0 0333
+Û "
+:U 9,11 0 0334
+Ü "
+'Y 9,12 0 0335
+Ý "
+TP 9,9 0 0336
+Þ "
+ss 9,9 0 0337
+ß "
+`a 9,10 0 0340
+à "
+'a 9,10 0 0341
+á "
+^a 9,10 0 0342
+â "
+~a 9,10 0 0343
+ã "
+:a 9,9 0 0344
+ä "
+oa 9,11 0 0345
+å "
+ae 9,7 0 0346
+æ "
+,c 9,7,3 0 0347
+ç "
+`e 9,10 0 0350
+è "
+'e 9,10 0 0351
+é "
+^e 9,10 0 0352
+ê "
+:e 9,9 0 0353
+ë "
+`i 9,10 0 0354
+ì "
+'i 9,10 0 0355
+í "
+^i 9,10 0 0356
+î "
+:i 9,9 0 0357
+ï "
+Sd 9,10 0 0360
+ð "
+~n 9,10 0 0361
+ñ "
+`o 9,10 0 0362
+ò "
+'o 9,10 0 0363
+ó "
+^o 9,10 0 0364
+ô "
+~o 9,10 0 0365
+õ "
+:o 9,9 0 0366
+ö "
+di 9,8 0 0367
+÷ "
+/o 9,7 0 0370
+ø "
+`u 9,10 0 0371
+ù "
+'u 9,10 0 0372
+ú "
+^u 9,10 0 0373
+û "
+:u 9,9 0 0374
+ü "
+'y 9,10,3 0 0375
+ý "
+Tp 9,9,3 0 0376
+þ "
+:y 9,9,3 0 0377
+ÿ "
diff --git a/gnu/usr.bin/groff/devX100/CR b/gnu/usr.bin/groff/devX100/CR
new file mode 100644
index 0000000..e425fa6
--- /dev/null
+++ b/gnu/usr.bin/groff/devX100/CR
@@ -0,0 +1,306 @@
+name CR
+spacewidth 9
+charset
+--- 9,1 0 040
+! 9,9 0 041
+" 9,10 0 042
+# 9,9,1 0 043
+sh "
+$ 9,11,2 0 044
+Do "
+% 9,10 0 045
+& 9,8 0 046
+' 9,10 0 047
+( 9,10,2 0 050
+) 9,10,2 0 051
+* 9,9 0 052
++ 9,8 0 053
+, 9,2,2 0 054
+\- 9,5 0 055
+. 9,2 0 056
+/ 9,10,1 0 057
+sl "
+0 9,10 0 060
+1 9,10 0 061
+2 9,10 0 062
+3 9,10 0 063
+4 9,10 0 064
+5 9,10 0 065
+6 9,10 0 066
+7 9,10 0 067
+8 9,10 0 070
+9 9,10 0 071
+: 9,7 0 072
+; 9,7,2 0 073
+< 9,8 0 074
+= 9,6 0 075
+eq "
+> 9,8 0 076
+? 9,9 0 077
+@ 9,9,1 0 0100
+at "
+A 9,9 0 0101
+B 9,9 0 0102
+C 9,9 0 0103
+D 9,9 0 0104
+E 9,9 0 0105
+F 9,9 0 0106
+G 9,9 0 0107
+H 9,9 0 0110
+I 9,9 0 0111
+J 9,9 0 0112
+K 9,9 0 0113
+L 9,9 0 0114
+M 9,9 0 0115
+N 9,9 0 0116
+O 9,9 0 0117
+P 9,9 0 0120
+Q 9,9,2 0 0121
+R 9,9 0 0122
+S 9,9 0 0123
+T 9,9 0 0124
+U 9,9 0 0125
+V 9,9 0 0126
+W 9,9 0 0127
+X 9,9 0 0130
+Y 9,9 0 0131
+Z 9,9 0 0132
+[ 9,10,2 0 0133
+lB "
+\ 9,10,1 0 0134
+rs "
+] 9,10,2 0 0135
+rB "
+^ 9,9 0 0136
+a^ "
+ha "
+_ 9,0,3 0 0137
+` 9,10 0 0140
+oq "
+a 9,7 0 0141
+b 9,10 0 0142
+c 9,7 0 0143
+d 9,10 0 0144
+e 9,7 0 0145
+f 9,10 0 0146
+g 9,7,3 0 0147
+h 9,10 0 0150
+i 9,10 0 0151
+j 9,10,3 0 0152
+k 9,10 0 0153
+l 9,10 0 0154
+m 9,7 0 0155
+n 9,7 0 0156
+o 9,7 0 0157
+p 9,7,3 0 0160
+q 9,7,3 0 0161
+r 9,7 0 0162
+s 9,7 0 0163
+t 9,9 0 0164
+u 9,7 0 0165
+v 9,7 0 0166
+w 9,7 0 0167
+x 9,7 0 0170
+y 9,7,3 0 0171
+z 9,7 0 0172
+{ 9,10,2 0 0173
+lC "
+| 9,9,2 0 0174
+or "
+ba "
+} 9,10,2 0 0175
+rC "
+~ 9,5 0 0176
+a~ "
+ap "
+ti "
+r! 9,7,2 0 0241
+¡ "
+ct 9,9 0 0242
+¢ "
+Po 9,9 0 0243
+£ "
+Cs 9,7 0 0244
+¤ "
+Ye 9,9 0 0245
+¥ "
+bb 9,9,2 0 0246
+¦ "
+sc 9,9,1 0 0247
+§ "
+ad 9,9 0 0250
+¨ "
+co 9,9 0 0251
+© "
+Of 9,9 0 0252
+ª "
+Fo 9,7 0 0253
+« "
+no 9,6 0 0254
+¬ "
+- 9,5 0 0255
+hy "
+­ "
+rg 9,9 0 0256
+® "
+a- 9,9 0 0257
+¯ "
+de 9,10 0 0260
+° "
++- 9,8 0 0261
+± "
+S2 9,10 0 0262
+² "
+S3 9,10 0 0263
+³ "
+aa 9,10 0 0264
+´ "
+µ 9,7,3 0 0265
+ps 9,9,1 0 0266
+¶ "
+md 9,5 0 0267
+· "
+ac 9,0,3 0 0270
+¸ "
+S1 9,10 0 0271
+¹ "
+Om 9,9 0 0272
+º "
+Fc 9,7 0 0273
+» "
+14 9,10 0 0274
+¼ "
+12 9,10 0 0275
+½ "
+34 9,10 0 0276
+¾ "
+r? 9,7,2 0 0277
+¿ "
+`A 9,12 0 0300
+À "
+'A 9,12 0 0301
+Á "
+^A 9,12 0 0302
+Â "
+~A 9,12 0 0303
+Ã "
+:A 9,11 0 0304
+Ä "
+oA 9,12 0 0305
+Å "
+AE 9,9 0 0306
+Æ "
+,C 9,9,3 0 0307
+Ç "
+`E 9,12 0 0310
+È "
+'E 9,12 0 0311
+É "
+^E 9,12 0 0312
+Ê "
+:E 9,11 0 0313
+Ë "
+`I 9,12 0 0314
+Ì "
+'I 9,12 0 0315
+Í "
+^I 9,12 0 0316
+Î "
+:I 9,11 0 0317
+Ï "
+-D 9,9 0 0320
+Ð "
+~N 9,12 0 0321
+Ñ "
+`O 9,12 0 0322
+Ò "
+'O 9,12 0 0323
+Ó "
+^O 9,12 0 0324
+Ô "
+~O 9,12 0 0325
+Õ "
+:O 9,11 0 0326
+Ö "
+mu 9,8 0 0327
+× "
+/O 9,9 0 0330
+Ø "
+`U 9,12 0 0331
+Ù "
+'U 9,12 0 0332
+Ú "
+^U 9,12 0 0333
+Û "
+:U 9,11 0 0334
+Ü "
+'Y 9,12 0 0335
+Ý "
+TP 9,9 0 0336
+Þ "
+ss 9,9 0 0337
+ß "
+`a 9,10 0 0340
+à "
+'a 9,10 0 0341
+á "
+^a 9,10 0 0342
+â "
+~a 9,10 0 0343
+ã "
+:a 9,9 0 0344
+ä "
+oa 9,10 0 0345
+å "
+ae 9,7 0 0346
+æ "
+,c 9,7,3 0 0347
+ç "
+`e 9,10 0 0350
+è "
+'e 9,10 0 0351
+é "
+^e 9,10 0 0352
+ê "
+:e 9,9 0 0353
+ë "
+`i 9,10 0 0354
+ì "
+'i 9,10 0 0355
+í "
+^i 9,10 0 0356
+î "
+:i 9,9 0 0357
+ï "
+Sd 9,12 0 0360
+ð "
+~n 9,10 0 0361
+ñ "
+`o 9,10 0 0362
+ò "
+'o 9,10 0 0363
+ó "
+^o 9,10 0 0364
+ô "
+~o 9,10 0 0365
+õ "
+:o 9,9 0 0366
+ö "
+di 9,8 0 0367
+÷ "
+/o 9,7 0 0370
+ø "
+`u 9,10 0 0371
+ù "
+'u 9,10 0 0372
+ú "
+^u 9,10 0 0373
+û "
+:u 9,9 0 0374
+ü "
+'y 9,10,3 0 0375
+ý "
+Tp 9,9,3 0 0376
+þ "
+:y 9,9,3 0 0377
+ÿ "
diff --git a/gnu/usr.bin/groff/devX100/DESC b/gnu/usr.bin/groff/devX100/DESC
new file mode 100644
index 0000000..7f63535
--- /dev/null
+++ b/gnu/usr.bin/groff/devX100/DESC
@@ -0,0 +1,9 @@
+styles R I B BI
+fonts 6 0 0 0 0 0 S
+sizes 8 10 12 14 18 24 0
+res 100
+X11
+hor 1
+vert 1
+unitwidth 10
+postpro gxditview
diff --git a/gnu/usr.bin/groff/devX100/HB b/gnu/usr.bin/groff/devX100/HB
new file mode 100644
index 0000000..d877fd6
--- /dev/null
+++ b/gnu/usr.bin/groff/devX100/HB
@@ -0,0 +1,306 @@
+name HB
+spacewidth 4
+charset
+--- 4,1 0 040
+! 4,11 0 041
+" 7,11 0 042
+# 9,10 0 043
+sh "
+$ 8,12,2 0 044
+Do "
+% 13,11 0 045
+& 11,10 0 046
+' 5,11 0 047
+( 5,11,3 0 050
+) 5,11,3 0 051
+* 6,11 0 052
++ 9,8 0 053
+, 4,2,1 0 054
+\- 9,5 0 055
+. 4,2 0 056
+/ 4,11 0 057
+sl "
+0 8,11 0 060
+1 8,11 0 061
+2 8,11 0 062
+3 8,11 0 063
+4 8,11 0 064
+5 8,11 0 065
+6 8,11 0 066
+7 8,11 0 067
+8 8,11 0 070
+9 8,11 0 071
+: 5,8 0 072
+; 5,8,1 0 073
+< 8,7 0 074
+= 9,6 0 075
+eq "
+> 8,7 0 076
+? 9,11 0 077
+@ 14,11,1 0 0100
+at "
+A 10,11 0 0101
+B 10,11 0 0102
+C 11,11 0 0103
+D 11,11 0 0104
+E 9,11 0 0105
+F 9,11 0 0106
+G 11,11 0 0107
+H 10,11 0 0110
+I 4,11 0 0111
+J 8,11 0 0112
+K 10,11 0 0113
+L 8,11 0 0114
+M 13,11 0 0115
+N 11,11 0 0116
+O 12,11 0 0117
+P 10,11 0 0120
+Q 12,11 0 0121
+R 11,11 0 0122
+S 10,11 0 0123
+T 8,11 0 0124
+U 11,11 0 0125
+V 10,11 0 0126
+W 14,11 0 0127
+X 9,11 0 0130
+Y 10,11 0 0131
+Z 9,11 0 0132
+[ 5,11,3 0 0133
+lB "
+\ 4,11 0 0134
+rs "
+] 5,11,3 0 0135
+rB "
+^ 8,11 0 0136
+a^ "
+ha "
+_ 8,0,3 0 0137
+` 5,11 0 0140
+oq "
+a 8,8 0 0141
+b 9,11 0 0142
+c 8,8 0 0143
+d 9,11 0 0144
+e 8,8 0 0145
+f 4,11 0 0146
+g 9,8,3 0 0147
+h 9,11 0 0150
+i 4,11 0 0151
+j 4,11,3 0 0152
+k 8,11 0 0153
+l 4,11 0 0154
+m 12,8 0 0155
+n 9,8 0 0156
+o 9,8 0 0157
+p 9,8,3 0 0160
+q 9,8,3 0 0161
+r 6,8 0 0162
+s 8,8 0 0163
+t 5,10 0 0164
+u 9,8 0 0165
+v 8,8 0 0166
+w 10,8 0 0167
+x 7,8 0 0170
+y 8,8,3 0 0171
+z 6,8 0 0172
+{ 6,11,3 0 0173
+lC "
+| 4,11,3 0 0174
+or "
+ba "
+} 6,11,3 0 0175
+rC "
+~ 9,6 0 0176
+a~ "
+ap "
+ti "
+r! 4,8,3 0 0241
+¡ "
+ct 8,9,1 0 0242
+¢ "
+Po 8,11 0 0243
+£ "
+Cs 8,9 0 0244
+¤ "
+Ye 9,11 0 0245
+¥ "
+bb 4,11,3 0 0246
+¦ "
+sc 8,11,3 0 0247
+§ "
+ad 5,11 0 0250
+¨ "
+co 12,11 0 0251
+© "
+Of 6,11 0 0252
+ª "
+Fo 9,7 0 0253
+« "
+no 9,6 0 0254
+¬ "
+- 4,5 0 0255
+hy "
+­ "
+rg 12,11 0 0256
+® "
+a- 5,10 0 0257
+¯ "
+de 6,11 0 0260
+° "
++- 9,9 0 0261
+± "
+S2 5,11 0 0262
+² "
+S3 5,11 0 0263
+³ "
+aa 5,11 0 0264
+´ "
+µ 9,8,3 0 0265
+ps 8,11,3 0 0266
+¶ "
+md 4,5 0 0267
+· "
+ac 5,0,3 0 0270
+¸ "
+S1 4,11 0 0271
+¹ "
+Om 6,11 0 0272
+º "
+Fc 9,7 0 0273
+» "
+14 12,11 0 0274
+¼ "
+12 12,11 0 0275
+½ "
+34 12,11 0 0276
+¾ "
+r? 9,8,3 0 0277
+¿ "
+`A 10,14 0 0300
+À "
+'A 10,14 0 0301
+Á "
+^A 10,14 0 0302
+Â "
+~A 10,14 0 0303
+Ã "
+:A 10,14 0 0304
+Ä "
+oA 10,14 0 0305
+Å "
+AE 15,11 0 0306
+Æ "
+,C 11,11,3 0 0307
+Ç "
+`E 9,14 0 0310
+È "
+'E 9,14 0 0311
+É "
+^E 9,14 0 0312
+Ê "
+:E 9,14 0 0313
+Ë "
+`I 4,14 0 0314
+Ì "
+'I 4,14 0 0315
+Í "
+^I 4,14 0 0316
+Î "
+:I 4,14 0 0317
+Ï "
+-D 11,11 0 0320
+Ð "
+~N 11,14 0 0321
+Ñ "
+`O 12,14 0 0322
+Ò "
+'O 12,14 0 0323
+Ó "
+^O 12,14 0 0324
+Ô "
+~O 12,14 0 0325
+Õ "
+:O 12,14 0 0326
+Ö "
+mu 9,8 0 0327
+× "
+/O 12,11 0 0330
+Ø "
+`U 11,14 0 0331
+Ù "
+'U 11,14 0 0332
+Ú "
+^U 11,14 0 0333
+Û "
+:U 11,14 0 0334
+Ü "
+'Y 10,14 0 0335
+Ý "
+TP 10,11 0 0336
+Þ "
+ss 8,11 0 0337
+ß "
+`a 8,11 0 0340
+à "
+'a 8,11 0 0341
+á "
+^a 8,11 0 0342
+â "
+~a 8,11 0 0343
+ã "
+:a 8,11 0 0344
+ä "
+oa 8,11 0 0345
+å "
+ae 13,8 0 0346
+æ "
+,c 9,8,3 0 0347
+ç "
+`e 8,11 0 0350
+è "
+'e 8,11 0 0351
+é "
+^e 8,11 0 0352
+ê "
+:e 8,11 0 0353
+ë "
+`i 4,11 0 0354
+ì "
+'i 4,11 0 0355
+í "
+^i 4,11 0 0356
+î "
+:i 4,11 0 0357
+ï "
+Sd 9,11 0 0360
+ð "
+~n 9,11 0 0361
+ñ "
+`o 9,11 0 0362
+ò "
+'o 9,11 0 0363
+ó "
+^o 9,11 0 0364
+ô "
+~o 9,11 0 0365
+õ "
+:o 9,11 0 0366
+ö "
+di 9,8 0 0367
+÷ "
+/o 9,8 0 0370
+ø "
+`u 9,11 0 0371
+ù "
+'u 9,11 0 0372
+ú "
+^u 9,11 0 0373
+û "
+:u 9,11 0 0374
+ü "
+'y 8,11,3 0 0375
+ý "
+Tp 9,11,3 0 0376
+þ "
+:y 8,11,3 0 0377
+ÿ "
diff --git a/gnu/usr.bin/groff/devX100/HBI b/gnu/usr.bin/groff/devX100/HBI
new file mode 100644
index 0000000..1cf0e56
--- /dev/null
+++ b/gnu/usr.bin/groff/devX100/HBI
@@ -0,0 +1,306 @@
+name HBI
+spacewidth 4
+charset
+--- 4,1 0 040
+! 5,11 0 041
+" 7,11 0 042
+# 10,10 0 043
+sh "
+$ 8,12,1 0 044
+Do "
+% 13,11 0 045
+& 11,10 0 046
+' 5,11 0 047
+( 5,11,3 0 050
+) 6,11,3 0 051
+* 6,11 0 052
++ 9,8 0 053
+, 4,2,2 0 054
+\- 9,5 0 055
+. 4,2 0 056
+/ 4,11 0 057
+sl "
+0 8,11 0 060
+1 8,11 0 061
+2 8,11 0 062
+3 8,11 0 063
+4 8,11 0 064
+5 8,11 0 065
+6 8,11 0 066
+7 8,11 0 067
+8 8,11 0 070
+9 8,11 0 071
+: 5,8 0 072
+; 5,8,2 0 073
+< 8,7 0 074
+= 9,6 0 075
+eq "
+> 9,7 0 076
+? 9,11 0 077
+@ 14,11,2 0 0100
+at "
+A 9,11 0 0101
+B 10,11 0 0102
+C 11,11 0 0103
+D 11,11 0 0104
+E 9,11 0 0105
+F 8,11 0 0106
+G 11,11 0 0107
+H 10,11 0 0110
+I 4,11 0 0111
+J 8,11 0 0112
+K 10,11 0 0113
+L 8,11 0 0114
+M 13,11 0 0115
+N 11,11 0 0116
+O 12,11 0 0117
+P 10,11 0 0120
+Q 12,11 0 0121
+R 10,11 0 0122
+S 10,11 0 0123
+T 8,11 0 0124
+U 11,11 0 0125
+V 10,11 0 0126
+W 14,11 0 0127
+X 9,11 0 0130
+Y 10,11 0 0131
+Z 9,11 0 0132
+[ 5,11,3 0 0133
+lB "
+\ 6,11 0 0134
+rs "
+] 5,11,3 0 0135
+rB "
+^ 8,11 0 0136
+a^ "
+ha "
+_ 8,0,3 0 0137
+` 5,11 0 0140
+oq "
+a 8,8 0 0141
+b 9,11 0 0142
+c 8,8 0 0143
+d 9,11 0 0144
+e 8,8 0 0145
+f 5,11 0 0146
+g 9,8,3 0 0147
+h 9,11 0 0150
+i 4,11 0 0151
+j 4,11,3 0 0152
+k 8,11 0 0153
+l 4,11 0 0154
+m 12,8 0 0155
+n 9,8 0 0156
+o 8,8 0 0157
+p 9,8,3 0 0160
+q 9,8,3 0 0161
+r 6,8 0 0162
+s 8,8 0 0163
+t 5,10 0 0164
+u 9,8 0 0165
+v 8,8 0 0166
+w 11,8 0 0167
+x 7,8 0 0170
+y 7,8,3 0 0171
+z 6,8 0 0172
+{ 6,11,3 0 0173
+lC "
+| 4,11,3 0 0174
+or "
+ba "
+} 6,11,3 0 0175
+rC "
+~ 9,6 0 0176
+a~ "
+ap "
+ti "
+r! 5,8,3 0 0241
+¡ "
+ct 8,9,1 0 0242
+¢ "
+Po 9,11 0 0243
+£ "
+Cs 9,8 0 0244
+¤ "
+Ye 9,11 0 0245
+¥ "
+bb 4,11,3 0 0246
+¦ "
+sc 9,11,3 0 0247
+§ "
+ad 5,11 0 0250
+¨ "
+co 12,11 0 0251
+© "
+Of 6,11 0 0252
+ª "
+Fo 11,7 0 0253
+« "
+no 9,6 0 0254
+¬ "
+- 5,5 0 0255
+hy "
+­ "
+rg 12,11 0 0256
+® "
+a- 5,11 0 0257
+¯ "
+de 6,11 0 0260
+° "
++- 9,9 0 0261
+± "
+S2 5,11 0 0262
+² "
+S3 5,11 0 0263
+³ "
+aa 5,11 0 0264
+´ "
+µ 9,8,3 0 0265
+ps 8,11,3 0 0266
+¶ "
+md 4,5 0 0267
+· "
+ac 5,1,3 0 0270
+¸ "
+S1 5,11 0 0271
+¹ "
+Om 6,11 0 0272
+º "
+Fc 11,7 0 0273
+» "
+14 12,11 0 0274
+¼ "
+12 12,11 0 0275
+½ "
+34 13,11 0 0276
+¾ "
+r? 8,8,3 0 0277
+¿ "
+`A 9,14 0 0300
+À "
+'A 9,14 0 0301
+Á "
+^A 9,14 0 0302
+Â "
+~A 9,14 0 0303
+Ã "
+:A 9,14 0 0304
+Ä "
+oA 9,14 0 0305
+Å "
+AE 14,11 0 0306
+Æ "
+,C 11,11,3 0 0307
+Ç "
+`E 9,14 0 0310
+È "
+'E 9,14 0 0311
+É "
+^E 9,14 0 0312
+Ê "
+:E 9,14 0 0313
+Ë "
+`I 4,14 0 0314
+Ì "
+'I 4,14 0 0315
+Í "
+^I 4,14 0 0316
+Î "
+:I 4,14 0 0317
+Ï "
+-D 11,11 0 0320
+Ð "
+~N 11,14 0 0321
+Ñ "
+`O 12,14 0 0322
+Ò "
+'O 12,14 0 0323
+Ó "
+^O 12,14 0 0324
+Ô "
+~O 12,14 0 0325
+Õ "
+:O 12,14 0 0326
+Ö "
+mu 9,8 0 0327
+× "
+/O 12,11 0 0330
+Ø "
+`U 11,14 0 0331
+Ù "
+'U 11,14 0 0332
+Ú "
+^U 11,14 0 0333
+Û "
+:U 11,14 0 0334
+Ü "
+'Y 10,14 0 0335
+Ý "
+TP 10,11 0 0336
+Þ "
+ss 9,11 0 0337
+ß "
+`a 8,11 0 0340
+à "
+'a 8,11 0 0341
+á "
+^a 8,11 0 0342
+â "
+~a 8,11 0 0343
+ã "
+:a 8,11 0 0344
+ä "
+oa 8,11 0 0345
+å "
+ae 13,8 0 0346
+æ "
+,c 8,8,3 0 0347
+ç "
+`e 8,11 0 0350
+è "
+'e 8,11 0 0351
+é "
+^e 8,11 0 0352
+ê "
+:e 8,11 0 0353
+ë "
+`i 4,11 0 0354
+ì "
+'i 4,11 0 0355
+í "
+^i 4,11 0 0356
+î "
+:i 4,11 0 0357
+ï "
+Sd 8,11 0 0360
+ð "
+~n 9,11 0 0361
+ñ "
+`o 8,11 0 0362
+ò "
+'o 8,11 0 0363
+ó "
+^o 8,11 0 0364
+ô "
+~o 8,11 0 0365
+õ "
+:o 8,11 0 0366
+ö "
+di 9,8 0 0367
+÷ "
+/o 8,8 0 0370
+ø "
+`u 9,11 0 0371
+ù "
+'u 9,11 0 0372
+ú "
+^u 9,11 0 0373
+û "
+:u 9,11 0 0374
+ü "
+'y 7,11,3 0 0375
+ý "
+Tp 9,11,3 0 0376
+þ "
+:y 7,11,3 0 0377
+ÿ "
diff --git a/gnu/usr.bin/groff/devX100/HI b/gnu/usr.bin/groff/devX100/HI
new file mode 100644
index 0000000..7908492
--- /dev/null
+++ b/gnu/usr.bin/groff/devX100/HI
@@ -0,0 +1,306 @@
+name HI
+spacewidth 4
+charset
+--- 4,1 0 040
+! 4,11 0 041
+" 5,11 0 042
+# 9,10 0 043
+sh "
+$ 8,12,2 0 044
+Do "
+% 12,11 0 045
+& 10,10 0 046
+' 3,11 0 047
+( 5,11,3 0 050
+) 5,11,3 0 051
+* 8,11 0 052
++ 9,8 0 053
+, 3,2,2 0 054
+\- 9,5 0 055
+. 3,2 0 056
+/ 4,11 0 057
+sl "
+0 8,11 0 060
+1 8,11 0 061
+2 8,11 0 062
+3 8,11 0 063
+4 8,11 0 064
+5 8,11 0 065
+6 8,11 0 066
+7 8,11 0 067
+8 8,11 0 070
+9 8,11 0 071
+: 4,8 0 072
+; 4,8,2 0 073
+< 9,7 0 074
+= 9,6 0 075
+eq "
+> 9,7 0 076
+? 8,11 0 077
+@ 13,11,1 0 0100
+at "
+A 11,11 0 0101
+B 10,11 0 0102
+C 10,11 0 0103
+D 10,11 0 0104
+E 9,11 0 0105
+F 9,11 0 0106
+G 11,11 0 0107
+H 11,11 0 0110
+I 5,11 0 0111
+J 9,11 0 0112
+K 10,11 0 0113
+L 8,11 0 0114
+M 14,11 0 0115
+N 11,11 0 0116
+O 11,11 0 0117
+P 9,11 0 0120
+Q 11,11 0 0121
+R 10,11 0 0122
+S 9,11 0 0123
+T 8,11 0 0124
+U 11,11 0 0125
+V 11,11 0 0126
+W 14,11 0 0127
+X 10,11 0 0130
+Y 9,11 0 0131
+Z 9,11 0 0132
+[ 5,11,3 0 0133
+lB "
+\ 6,11 0 0134
+rs "
+] 5,11,3 0 0135
+rB "
+^ 7,11 0 0136
+a^ "
+ha "
+_ 8,0,3 0 0137
+` 3,11 0 0140
+oq "
+a 8,8 0 0141
+b 8,11 0 0142
+c 7,8 0 0143
+d 8,11 0 0144
+e 8,8 0 0145
+f 4,11 0 0146
+g 8,8,3 0 0147
+h 8,11 0 0150
+i 4,11 0 0151
+j 3,11,3 0 0152
+k 7,11 0 0153
+l 3,11 0 0154
+m 11,8 0 0155
+n 8,8 0 0156
+o 8,8 0 0157
+p 8,8,3 0 0160
+q 8,8,3 0 0161
+r 5,8 0 0162
+s 7,8 0 0163
+t 4,10 0 0164
+u 8,8 0 0165
+v 7,8 0 0166
+w 10,8 0 0167
+x 7,8 0 0170
+y 7,8,3 0 0171
+z 7,8 0 0172
+{ 5,11,3 0 0173
+lC "
+| 4,11,3 0 0174
+or "
+ba "
+} 5,11,3 0 0175
+rC "
+~ 8,6 0 0176
+a~ "
+ap "
+ti "
+r! 4,8,3 0 0241
+¡ "
+ct 8,9,1 0 0242
+¢ "
+Po 9,11 0 0243
+£ "
+Cs 8,8 0 0244
+¤ "
+Ye 9,11 0 0245
+¥ "
+bb 4,11,3 0 0246
+¦ "
+sc 8,11,3 0 0247
+§ "
+ad 5,10 0 0250
+¨ "
+co 12,11 0 0251
+© "
+Of 5,11 0 0252
+ª "
+Fo 8,6 0 0253
+« "
+no 9,6 0 0254
+¬ "
+- 5,5 0 0255
+hy "
+­ "
+rg 12,11 0 0256
+® "
+a- 4,10 0 0257
+¯ "
+de 6,11 0 0260
+° "
++- 9,9 0 0261
+± "
+S2 5,11 0 0262
+² "
+S3 5,11 0 0263
+³ "
+aa 4,11 0 0264
+´ "
+µ 8,8,3 0 0265
+ps 8,11,3 0 0266
+¶ "
+md 4,5 0 0267
+· "
+ac 3,0,3 0 0270
+¸ "
+S1 5,11 0 0271
+¹ "
+Om 5,11 0 0272
+º "
+Fc 8,6 0 0273
+» "
+14 12,11 0 0274
+¼ "
+12 12,11 0 0275
+½ "
+34 12,11 0 0276
+¾ "
+r? 8,8,3 0 0277
+¿ "
+`A 11,14 0 0300
+À "
+'A 11,14 0 0301
+Á "
+^A 11,14 0 0302
+Â "
+~A 11,14 0 0303
+Ã "
+:A 11,13 0 0304
+Ä "
+oA 11,14 0 0305
+Å "
+AE 15,11 0 0306
+Æ "
+,C 10,11,3 0 0307
+Ç "
+`E 9,14 0 0310
+È "
+'E 9,14 0 0311
+É "
+^E 9,14 0 0312
+Ê "
+:E 9,13 0 0313
+Ë "
+`I 5,14 0 0314
+Ì "
+'I 5,14 0 0315
+Í "
+^I 5,14 0 0316
+Î "
+:I 5,13 0 0317
+Ï "
+-D 10,11 0 0320
+Ð "
+~N 11,14 0 0321
+Ñ "
+`O 11,14 0 0322
+Ò "
+'O 11,14 0 0323
+Ó "
+^O 11,14 0 0324
+Ô "
+~O 11,14 0 0325
+Õ "
+:O 11,13 0 0326
+Ö "
+mu 9,8 0 0327
+× "
+/O 11,11 0 0330
+Ø "
+`U 11,14 0 0331
+Ù "
+'U 11,14 0 0332
+Ú "
+^U 11,14 0 0333
+Û "
+:U 11,13 0 0334
+Ü "
+'Y 9,14 0 0335
+Ý "
+TP 9,11 0 0336
+Þ "
+ss 8,11 0 0337
+ß "
+`a 8,11 0 0340
+à "
+'a 8,11 0 0341
+á "
+^a 8,11 0 0342
+â "
+~a 8,11 0 0343
+ã "
+:a 8,11 0 0344
+ä "
+oa 8,11 0 0345
+å "
+ae 12,8 0 0346
+æ "
+,c 7,8,3 0 0347
+ç "
+`e 8,11 0 0350
+è "
+'e 8,11 0 0351
+é "
+^e 8,11 0 0352
+ê "
+:e 8,11 0 0353
+ë "
+`i 3,11 0 0354
+ì "
+'i 3,11 0 0355
+í "
+^i 3,11 0 0356
+î "
+:i 3,11 0 0357
+ï "
+Sd 8,11 0 0360
+ð "
+~n 8,11 0 0361
+ñ "
+`o 8,11 0 0362
+ò "
+'o 8,11 0 0363
+ó "
+^o 8,11 0 0364
+ô "
+~o 8,11 0 0365
+õ "
+:o 8,11 0 0366
+ö "
+di 9,8 0 0367
+÷ "
+/o 8,9,1 0 0370
+ø "
+`u 8,11 0 0371
+ù "
+'u 8,11 0 0372
+ú "
+^u 8,11 0 0373
+û "
+:u 8,11 0 0374
+ü "
+'y 7,11,3 0 0375
+ý "
+Tp 8,11,3 0 0376
+þ "
+:y 7,11,3 0 0377
+ÿ "
diff --git a/gnu/usr.bin/groff/devX100/HR b/gnu/usr.bin/groff/devX100/HR
new file mode 100644
index 0000000..c2f6af3
--- /dev/null
+++ b/gnu/usr.bin/groff/devX100/HR
@@ -0,0 +1,306 @@
+name HR
+spacewidth 4
+charset
+--- 4,1 0 040
+! 4,11 0 041
+" 5,11 0 042
+# 8,10 0 043
+sh "
+$ 8,12,2 0 044
+Do "
+% 12,11 0 045
+& 10,10 0 046
+' 3,11 0 047
+( 5,11,3 0 050
+) 5,11,3 0 051
+* 7,11 0 052
++ 9,8 0 053
+, 3,2,2 0 054
+\- 9,5 0 055
+. 3,2 0 056
+/ 4,11 0 057
+sl "
+0 8,11 0 060
+1 8,11 0 061
+2 8,11 0 062
+3 8,11 0 063
+4 8,11 0 064
+5 8,11 0 065
+6 8,11 0 066
+7 8,11 0 067
+8 8,11 0 070
+9 8,11 0 071
+: 3,8 0 072
+; 4,8,2 0 073
+< 8,7 0 074
+= 9,6 0 075
+eq "
+> 8,7 0 076
+? 8,11 0 077
+@ 13,11,1 0 0100
+at "
+A 9,11 0 0101
+B 9,11 0 0102
+C 10,11 0 0103
+D 10,11 0 0104
+E 9,11 0 0105
+F 8,11 0 0106
+G 11,11 0 0107
+H 10,11 0 0110
+I 4,11 0 0111
+J 7,11 0 0112
+K 9,11 0 0113
+L 8,11 0 0114
+M 12,11 0 0115
+N 10,11 0 0116
+O 11,11 0 0117
+P 9,11 0 0120
+Q 11,11 0 0121
+R 10,11 0 0122
+S 9,11 0 0123
+T 9,11 0 0124
+U 10,11 0 0125
+V 9,11 0 0126
+W 13,11 0 0127
+X 9,11 0 0130
+Y 9,11 0 0131
+Z 9,11 0 0132
+[ 4,11,3 0 0133
+lB "
+\ 4,11 0 0134
+rs "
+] 4,11,3 0 0135
+rB "
+^ 7,11 0 0136
+a^ "
+ha "
+_ 8,0,3 0 0137
+` 3,11 0 0140
+oq "
+a 8,8 0 0141
+b 7,11 0 0142
+c 7,8 0 0143
+d 8,11 0 0144
+e 8,8 0 0145
+f 4,11 0 0146
+g 8,8,3 0 0147
+h 8,11 0 0150
+i 3,11 0 0151
+j 3,11,3 0 0152
+k 7,11 0 0153
+l 3,11 0 0154
+m 11,8 0 0155
+n 8,8 0 0156
+o 8,8 0 0157
+p 8,8,3 0 0160
+q 8,8,3 0 0161
+r 5,8 0 0162
+s 7,8 0 0163
+t 4,10 0 0164
+u 7,8 0 0165
+v 7,8 0 0166
+w 10,8 0 0167
+x 7,8 0 0170
+y 7,8,3 0 0171
+z 7,8 0 0172
+{ 5,11,3 0 0173
+lC "
+| 3,11,3 0 0174
+or "
+ba "
+} 5,11,3 0 0175
+rC "
+~ 8,6 0 0176
+a~ "
+ap "
+ti "
+r! 4,8,3 0 0241
+¡ "
+ct 8,9,1 0 0242
+¢ "
+Po 8,11 0 0243
+£ "
+Cs 8,8 0 0244
+¤ "
+Ye 7,11 0 0245
+¥ "
+bb 3,11,3 0 0246
+¦ "
+sc 8,11,3 0 0247
+§ "
+ad 5,10 0 0250
+¨ "
+co 12,11 0 0251
+© "
+Of 6,11 0 0252
+ª "
+Fo 8,7 0 0253
+« "
+no 9,6 0 0254
+¬ "
+- 4,5 0 0255
+hy "
+­ "
+rg 12,11 0 0256
+® "
+a- 4,10 0 0257
+¯ "
+de 6,11 0 0260
+° "
++- 9,9 0 0261
+± "
+S2 5,11 0 0262
+² "
+S3 5,11 0 0263
+³ "
+aa 5,11 0 0264
+´ "
+µ 8,8,3 0 0265
+ps 8,11,3 0 0266
+¶ "
+md 4,5 0 0267
+· "
+ac 5,0,3 0 0270
+¸ "
+S1 5,11 0 0271
+¹ "
+Om 6,11 0 0272
+º "
+Fc 8,7 0 0273
+» "
+14 12,11 0 0274
+¼ "
+12 12,11 0 0275
+½ "
+34 12,11 0 0276
+¾ "
+r? 8,8,3 0 0277
+¿ "
+`A 9,14 0 0300
+À "
+'A 9,14 0 0301
+Á "
+^A 9,14 0 0302
+Â "
+~A 9,13 0 0303
+Ã "
+:A 9,14 0 0304
+Ä "
+oA 9,14 0 0305
+Å "
+AE 14,11 0 0306
+Æ "
+,C 10,11,3 0 0307
+Ç "
+`E 9,14 0 0310
+È "
+'E 9,14 0 0311
+É "
+^E 9,14 0 0312
+Ê "
+:E 9,13 0 0313
+Ë "
+`I 4,14 0 0314
+Ì "
+'I 4,14 0 0315
+Í "
+^I 4,14 0 0316
+Î "
+:I 4,13 0 0317
+Ï "
+-D 10,11 0 0320
+Ð "
+~N 10,14 0 0321
+Ñ "
+`O 11,14 0 0322
+Ò "
+'O 11,14 0 0323
+Ó "
+^O 11,14 0 0324
+Ô "
+~O 11,14 0 0325
+Õ "
+:O 11,13 0 0326
+Ö "
+mu 9,8 0 0327
+× "
+/O 11,11 0 0330
+Ø "
+`U 10,14 0 0331
+Ù "
+'U 10,14 0 0332
+Ú "
+^U 10,14 0 0333
+Û "
+:U 10,13 0 0334
+Ü "
+'Y 9,14 0 0335
+Ý "
+TP 9,11 0 0336
+Þ "
+ss 7,11 0 0337
+ß "
+`a 8,11 0 0340
+à "
+'a 8,11 0 0341
+á "
+^a 8,11 0 0342
+â "
+~a 8,11 0 0343
+ã "
+:a 8,11 0 0344
+ä "
+oa 8,12 0 0345
+å "
+ae 13,8 0 0346
+æ "
+,c 8,8,3 0 0347
+ç "
+`e 8,11 0 0350
+è "
+'e 8,11 0 0351
+é "
+^e 8,11 0 0352
+ê "
+:e 8,11 0 0353
+ë "
+`i 3,11 0 0354
+ì "
+'i 3,11 0 0355
+í "
+^i 3,11 0 0356
+î "
+:i 3,11 0 0357
+ï "
+Sd 8,11 0 0360
+ð "
+~n 8,11 0 0361
+ñ "
+`o 8,11 0 0362
+ò "
+'o 8,11 0 0363
+ó "
+^o 8,11 0 0364
+ô "
+~o 8,11 0 0365
+õ "
+:o 8,11 0 0366
+ö "
+di 9,8 0 0367
+÷ "
+/o 8,8 0 0370
+ø "
+`u 8,11 0 0371
+ù "
+'u 8,11 0 0372
+ú "
+^u 8,11 0 0373
+û "
+:u 8,11 0 0374
+ü "
+'y 7,11,3 0 0375
+ý "
+Tp 8,11,3 0 0376
+þ "
+:y 7,10,3 0 0377
+ÿ "
diff --git a/gnu/usr.bin/groff/devX100/Makefile b/gnu/usr.bin/groff/devX100/Makefile
new file mode 100644
index 0000000..0cf8d28
--- /dev/null
+++ b/gnu/usr.bin/groff/devX100/Makefile
@@ -0,0 +1,10 @@
+# Makefile for devX100
+
+DEVICE= X100
+FONTFILES= CB CBI CI CR HB HBI HI HR NB NBI NI NR S TB TBI TI TR DESC
+
+NOOBJ= noobj
+
+clean cleandir:
+
+.include "../Makefile.dev"
diff --git a/gnu/usr.bin/groff/devX100/Makefile.sub b/gnu/usr.bin/groff/devX100/Makefile.sub
new file mode 100644
index 0000000..4d40f0f
--- /dev/null
+++ b/gnu/usr.bin/groff/devX100/Makefile.sub
@@ -0,0 +1,2 @@
+DEV=X100
+DEVFILES=DESC TR TI TB TBI CR CI CB CBI HR HI HB HBI NR NI NB NBI S
diff --git a/gnu/usr.bin/groff/devX100/NB b/gnu/usr.bin/groff/devX100/NB
new file mode 100644
index 0000000..d47fdb2
--- /dev/null
+++ b/gnu/usr.bin/groff/devX100/NB
@@ -0,0 +1,306 @@
+name NB
+spacewidth 11
+charset
+--- 11,1 0 040
+! 4,11 0 041
+" 5,11 0 042
+# 8,10 0 043
+sh "
+$ 8,12,1 0 044
+Do "
+% 13,11 0 045
+& 13,11 0 046
+' 4,11 0 047
+( 5,11,2 0 050
+) 5,11,2 0 051
+* 6,11 0 052
++ 8,8 0 053
+, 4,3,2 0 054
+\- 8,5 0 055
+. 4,3 0 056
+/ 5,11 0 057
+sl "
+0 8,11 0 060
+1 6,11 0 061
+2 8,11 0 062
+3 8,11 0 063
+4 8,11 0 064
+5 8,11 0 065
+6 8,11 0 066
+7 8,11 0 067
+8 8,11 0 070
+9 8,11 0 071
+: 4,7 0 072
+; 4,7,2 0 073
+< 8,8 0 074
+= 8,6 0 075
+eq "
+> 8,8 0 076
+? 7,11 0 077
+@ 14,11 0 0100
+at "
+A 11,11 0 0101
+B 10,11 0 0102
+C 11,11 0 0103
+D 12,11 0 0104
+E 10,11 0 0105
+F 10,11 0 0106
+G 12,11 0 0107
+H 12,11 0 0110
+I 7,11 0 0111
+J 9,11 0 0112
+K 12,11 0 0113
+L 10,11 0 0114
+M 14,11 0 0115
+N 12,11 0 0116
+O 12,11 0 0117
+P 10,11 0 0120
+Q 12,11,3 0 0121
+R 12,11 0 0122
+S 10,11 0 0123
+T 11,11 0 0124
+U 12,11 0 0125
+V 11,11 0 0126
+W 14,11 0 0127
+X 12,11 0 0130
+Y 11,11 0 0131
+Z 9,11 0 0132
+[ 5,11,2 0 0133
+lB "
+\ 7,11 0 0134
+rs "
+] 5,11,2 0 0135
+rB "
+^ 8,11 0 0136
+a^ "
+ha "
+_ 7,0,2 0 0137
+` 4,11 0 0140
+oq "
+a 9,7 0 0141
+b 10,11 0 0142
+c 8,7 0 0143
+d 10,11 0 0144
+e 9,7 0 0145
+f 6,11 0 0146
+g 8,8,3 0 0147
+h 10,11 0 0150
+i 5,10 0 0151
+j 5,10,3 0 0152
+k 9,11 0 0153
+l 5,11 0 0154
+m 15,7 0 0155
+n 10,7 0 0156
+o 9,7 0 0157
+p 10,7,3 0 0160
+q 9,7,3 0 0161
+r 7,7 0 0162
+s 7,7 0 0163
+t 6,10 0 0164
+u 10,7 0 0165
+v 7,7 0 0166
+w 12,7 0 0167
+x 9,7 0 0170
+y 7,7,3 0 0171
+z 7,7 0 0172
+{ 6,11,2 0 0173
+lC "
+| 8,11 0 0174
+or "
+ba "
+} 6,11,2 0 0175
+rC "
+~ 8,6 0 0176
+a~ "
+ap "
+ti "
+r! 5,8,3 0 0241
+¡ "
+ct 8,8,1 0 0242
+¢ "
+Po 9,11 0 0243
+£ "
+Cs 9,10 0 0244
+¤ "
+Ye 11,11 0 0245
+¥ "
+bb 8,11 0 0246
+¦ "
+sc 7,11,2 0 0247
+§ "
+ad 7,10 0 0250
+¨ "
+co 12,11 0 0251
+© "
+Of 6,11 0 0252
+ª "
+Fo 8,6 0 0253
+« "
+no 8,6 0 0254
+¬ "
+- 5,5 0 0255
+hy "
+­ "
+rg 12,11 0 0256
+® "
+a- 7,9 0 0257
+¯ "
+de 6,11 0 0260
+° "
++- 8,8 0 0261
+± "
+S2 5,11 0 0262
+² "
+S3 5,11 0 0263
+³ "
+aa 6,11 0 0264
+´ "
+µ 10,7,3 0 0265
+ps 10,11 0 0266
+¶ "
+md 5,6 0 0267
+· "
+ac 5,0,3 0 0270
+¸ "
+S1 5,11 0 0271
+¹ "
+Om 6,11 0 0272
+º "
+Fc 8,6 0 0273
+» "
+14 12,11 0 0274
+¼ "
+12 12,11 0 0275
+½ "
+34 12,11 0 0276
+¾ "
+r? 7,8,3 0 0277
+¿ "
+`A 11,15 0 0300
+À "
+'A 11,15 0 0301
+Á "
+^A 11,15 0 0302
+Â "
+~A 11,14 0 0303
+Ã "
+:A 11,14 0 0304
+Ä "
+oA 11,15 0 0305
+Å "
+AE 15,11 0 0306
+Æ "
+,C 11,11,3 0 0307
+Ç "
+`E 10,15 0 0310
+È "
+'E 10,15 0 0311
+É "
+^E 10,15 0 0312
+Ê "
+:E 10,14 0 0313
+Ë "
+`I 7,15 0 0314
+Ì "
+'I 7,15 0 0315
+Í "
+^I 7,15 0 0316
+Î "
+:I 7,14 0 0317
+Ï "
+-D 12,11 0 0320
+Ð "
+~N 12,14 0 0321
+Ñ "
+`O 12,15 0 0322
+Ò "
+'O 12,15 0 0323
+Ó "
+^O 12,15 0 0324
+Ô "
+~O 12,14 0 0325
+Õ "
+:O 12,14 0 0326
+Ö "
+mu 8,8 0 0327
+× "
+/O 12,11 0 0330
+Ø "
+`U 12,15 0 0331
+Ù "
+'U 12,15 0 0332
+Ú "
+^U 12,15 0 0333
+Û "
+:U 12,14 0 0334
+Ü "
+'Y 11,14 0 0335
+Ý "
+TP 10,11 0 0336
+Þ "
+ss 9,11 0 0337
+ß "
+`a 9,11 0 0340
+à "
+'a 9,11 0 0341
+á "
+^a 9,11 0 0342
+â "
+~a 9,10 0 0343
+ã "
+:a 9,10 0 0344
+ä "
+oa 9,11 0 0345
+å "
+ae 14,7 0 0346
+æ "
+,c 8,7,3 0 0347
+ç "
+`e 9,11 0 0350
+è "
+'e 9,11 0 0351
+é "
+^e 9,11 0 0352
+ê "
+:e 9,10 0 0353
+ë "
+`i 5,11 0 0354
+ì "
+'i 5,11 0 0355
+í "
+^i 5,11 0 0356
+î "
+:i 5,10 0 0357
+ï "
+Sd 9,11 0 0360
+ð "
+~n 10,10 0 0361
+ñ "
+`o 9,11 0 0362
+ò "
+'o 9,11 0 0363
+ó "
+^o 9,11 0 0364
+ô "
+~o 9,10 0 0365
+õ "
+:o 9,10 0 0366
+ö "
+di 8,8 0 0367
+÷ "
+/o 9,8,1 0 0370
+ø "
+`u 10,11 0 0371
+ù "
+'u 10,11 0 0372
+ú "
+^u 10,11 0 0373
+û "
+:u 10,10 0 0374
+ü "
+'y 7,11,3 0 0375
+ý "
+Tp 10,11,3 0 0376
+þ "
+:y 7,10,3 0 0377
+ÿ "
diff --git a/gnu/usr.bin/groff/devX100/NBI b/gnu/usr.bin/groff/devX100/NBI
new file mode 100644
index 0000000..c46b945
--- /dev/null
+++ b/gnu/usr.bin/groff/devX100/NBI
@@ -0,0 +1,306 @@
+name NBI
+spacewidth 4
+charset
+--- 4,1 0 040
+! 5,11 0 041
+" 6,11 0 042
+# 8,10 0 043
+sh "
+$ 8,12,1 0 044
+Do "
+% 13,11,1 0 045
+& 13,11 0 046
+' 4,11 0 047
+( 5,11,2 0 050
+) 6,11,2 0 051
+* 7,11 0 052
++ 8,8 0 053
+, 4,2,3 0 054
+\- 8,5 0 055
+. 4,2 0 056
+/ 5,11 0 057
+sl "
+0 8,11 0 060
+1 8,11 0 061
+2 8,11 0 062
+3 8,11 0 063
+4 8,11 0 064
+5 8,11 0 065
+6 8,11 0 066
+7 8,11 0 067
+8 8,11 0 070
+9 8,11 0 071
+: 4,7 0 072
+; 5,7,3 0 073
+< 9,9 0 074
+= 9,7 0 075
+eq "
+> 9,9 0 076
+? 7,11 0 077
+@ 13,11 0 0100
+at "
+A 11,11 0 0101
+B 10,11 0 0102
+C 11,11 0 0103
+D 12,11 0 0104
+E 10,11 0 0105
+F 10,11 0 0106
+G 11,11 0 0107
+H 12,11 0 0110
+I 6,11 0 0111
+J 8,11 0 0112
+K 12,11 0 0113
+L 10,11 0 0114
+M 15,11 0 0115
+N 13,11 0 0116
+O 12,11 0 0117
+P 11,11 0 0120
+Q 12,11,2 0 0121
+R 12,11 0 0122
+S 10,11 0 0123
+T 11,11 0 0124
+U 12,11 0 0125
+V 11,11 0 0126
+W 15,11 0 0127
+X 11,11 0 0130
+Y 9,11 0 0131
+Z 10,11 0 0132
+[ 7,11,2 0 0133
+lB "
+\ 9,11 0 0134
+rs "
+] 7,11,2 0 0135
+rB "
+^ 8,11 0 0136
+a^ "
+ha "
+_ 9,0,2 0 0137
+` 4,11 0 0140
+oq "
+a 10,7 0 0141
+b 8,11 0 0142
+c 8,7 0 0143
+d 10,11 0 0144
+e 8,7 0 0145
+f 5,11,3 0 0146
+g 8,9,3 0 0147
+h 10,11 0 0150
+i 5,10 0 0151
+j 4,10,3 0 0152
+k 9,11 0 0153
+l 5,11 0 0154
+m 15,7 0 0155
+n 10,7 0 0156
+o 8,7 0 0157
+p 8,7,3 0 0160
+q 9,7,3 0 0161
+r 7,7 0 0162
+s 8,7 0 0163
+t 5,9 0 0164
+u 10,7 0 0165
+v 8,7 0 0166
+w 13,7 0 0167
+x 9,7 0 0170
+y 9,7,3 0 0171
+z 9,7 0 0172
+{ 6,11,2 0 0173
+lC "
+| 9,11 0 0174
+or "
+ba "
+} 6,11,2 0 0175
+rC "
+~ 11,6 0 0176
+a~ "
+ap "
+ti "
+r! 5,8,3 0 0241
+¡ "
+ct 8,8,1 0 0242
+¢ "
+Po 10,11 0 0243
+£ "
+Cs 8,9 0 0244
+¤ "
+Ye 10,11 0 0245
+¥ "
+bb 8,11 0 0246
+¦ "
+sc 9,11,2 0 0247
+§ "
+ad 6,10 0 0250
+¨ "
+co 12,11 0 0251
+© "
+Of 8,11 0 0252
+ª "
+Fo 10,7 0 0253
+« "
+no 9,7 0 0254
+¬ "
+- 5,5 0 0255
+hy "
+­ "
+rg 12,11 0 0256
+® "
+a- 6,9 0 0257
+¯ "
+de 6,11 0 0260
+° "
++- 8,8 0 0261
+± "
+S2 5,11 0 0262
+² "
+S3 5,11 0 0263
+³ "
+aa 5,11 0 0264
+´ "
+µ 10,7,3 0 0265
+ps 9,11 0 0266
+¶ "
+md 5,6 0 0267
+· "
+ac 5,0,3 0 0270
+¸ "
+S1 5,11 0 0271
+¹ "
+Om 8,11 0 0272
+º "
+Fc 10,7 0 0273
+» "
+14 12,11 0 0274
+¼ "
+12 12,11 0 0275
+½ "
+34 12,11 0 0276
+¾ "
+r? 7,8,3 0 0277
+¿ "
+`A 11,15 0 0300
+À "
+'A 11,15 0 0301
+Á "
+^A 11,15 0 0302
+Â "
+~A 11,14 0 0303
+Ã "
+:A 11,14 0 0304
+Ä "
+oA 11,15 0 0305
+Å "
+AE 14,11 0 0306
+Æ "
+,C 11,11,3 0 0307
+Ç "
+`E 10,15 0 0310
+È "
+'E 10,15 0 0311
+É "
+^E 10,15 0 0312
+Ê "
+:E 10,14 0 0313
+Ë "
+`I 6,15 0 0314
+Ì "
+'I 6,15 0 0315
+Í "
+^I 6,15 0 0316
+Î "
+:I 6,14 0 0317
+Ï "
+-D 12,11 0 0320
+Ð "
+~N 13,14 0 0321
+Ñ "
+`O 12,15 0 0322
+Ò "
+'O 12,15 0 0323
+Ó "
+^O 12,15 0 0324
+Ô "
+~O 12,14 0 0325
+Õ "
+:O 12,14 0 0326
+Ö "
+mu 8,8 0 0327
+× "
+/O 12,11 0 0330
+Ø "
+`U 12,15 0 0331
+Ù "
+'U 12,15 0 0332
+Ú "
+^U 12,15 0 0333
+Û "
+:U 12,14 0 0334
+Ü "
+'Y 9,15 0 0335
+Ý "
+TP 11,11 0 0336
+Þ "
+ss 10,11,3 0 0337
+ß "
+`a 10,11 0 0340
+à "
+'a 10,11 0 0341
+á "
+^a 10,11 0 0342
+â "
+~a 10,10 0 0343
+ã "
+:a 10,10 0 0344
+ä "
+oa 10,11 0 0345
+å "
+ae 13,7 0 0346
+æ "
+,c 8,7,3 0 0347
+ç "
+`e 8,11 0 0350
+è "
+'e 8,11 0 0351
+é "
+^e 8,11 0 0352
+ê "
+:e 8,10 0 0353
+ë "
+`i 5,11 0 0354
+ì "
+'i 5,11 0 0355
+í "
+^i 5,11 0 0356
+î "
+:i 5,10 0 0357
+ï "
+Sd 8,11 0 0360
+ð "
+~n 10,10 0 0361
+ñ "
+`o 8,11 0 0362
+ò "
+'o 8,11 0 0363
+ó "
+^o 8,11 0 0364
+ô "
+~o 8,10 0 0365
+õ "
+:o 8,10 0 0366
+ö "
+di 8,8 0 0367
+÷ "
+/o 8,7 0 0370
+ø "
+`u 10,11 0 0371
+ù "
+'u 10,11 0 0372
+ú "
+^u 10,11 0 0373
+û "
+:u 10,10 0 0374
+ü "
+'y 9,11,3 0 0375
+ý "
+Tp 8,11,3 0 0376
+þ "
+:y 9,10,3 0 0377
+ÿ "
diff --git a/gnu/usr.bin/groff/devX100/NI b/gnu/usr.bin/groff/devX100/NI
new file mode 100644
index 0000000..3216f64
--- /dev/null
+++ b/gnu/usr.bin/groff/devX100/NI
@@ -0,0 +1,306 @@
+name NI
+spacewidth 4
+charset
+--- 4,1 0 040
+! 5,11 0 041
+" 6,11 0 042
+# 11,10 0 043
+sh "
+$ 8,12,1 0 044
+Do "
+% 12,11,1 0 045
+& 11,11 0 046
+' 4,11 0 047
+( 5,11,2 0 050
+) 5,11,2 0 051
+* 6,11 0 052
++ 8,8 0 053
+, 4,2,2 0 054
+\- 9,5 0 055
+. 4,2 0 056
+/ 9,11,3 0 057
+sl "
+0 8,11 0 060
+1 8,11 0 061
+2 8,11 0 062
+3 8,11 0 063
+4 8,11 0 064
+5 8,11 0 065
+6 8,11 0 066
+7 8,11 0 067
+8 8,11 0 070
+9 8,11 0 071
+: 4,7 0 072
+; 4,7,2 0 073
+< 9,8 0 074
+= 8,6 0 075
+eq "
+> 9,8 0 076
+? 6,11 0 077
+@ 12,11 0 0100
+at "
+A 11,11 0 0101
+B 9,11 0 0102
+C 10,11 0 0103
+D 11,11 0 0104
+E 9,11 0 0105
+F 8,11 0 0106
+G 10,11 0 0107
+H 11,11 0 0110
+I 7,11 0 0111
+J 8,11 0 0112
+K 10,11 0 0113
+L 9,11 0 0114
+M 14,11 0 0115
+N 12,11 0 0116
+O 10,11 0 0117
+P 10,11 0 0120
+Q 10,11,2 0 0121
+R 11,11 0 0122
+S 10,11 0 0123
+T 10,11 0 0124
+U 12,11 0 0125
+V 10,11 0 0126
+W 13,11 0 0127
+X 10,11 0 0130
+Y 9,11 0 0131
+Z 10,11 0 0132
+[ 6,11,2 0 0133
+lB "
+\ 8,11 0 0134
+rs "
+] 6,11,2 0 0135
+rB "
+^ 6,11 0 0136
+a^ "
+ha "
+_ 7,0,2 0 0137
+` 4,11 0 0140
+oq "
+a 9,7 0 0141
+b 7,11 0 0142
+c 6,7 0 0143
+d 9,11 0 0144
+e 6,7 0 0145
+f 5,11,3 0 0146
+g 7,8,3 0 0147
+h 9,11 0 0150
+i 4,11 0 0151
+j 4,11,3 0 0152
+k 8,11 0 0153
+l 4,11 0 0154
+m 14,7 0 0155
+n 9,7 0 0156
+o 7,7 0 0157
+p 7,7,3 0 0160
+q 8,7,3 0 0161
+r 7,7 0 0162
+s 7,7 0 0163
+t 5,9 0 0164
+u 9,7 0 0165
+v 7,7 0 0166
+w 11,7 0 0167
+x 8,7 0 0170
+y 7,7,3 0 0171
+z 8,7 0 0172
+{ 6,11,2 0 0173
+lC "
+| 9,11 0 0174
+or "
+ba "
+} 6,11,2 0 0175
+rC "
+~ 9,6 0 0176
+a~ "
+ap "
+ti "
+r! 4,8,3 0 0241
+¡ "
+ct 8,9,2 0 0242
+¢ "
+Po 9,11 0 0243
+£ "
+Cs 8,9 0 0244
+¤ "
+Ye 9,11 0 0245
+¥ "
+bb 8,11 0 0246
+¦ "
+sc 7,11,2 0 0247
+§ "
+ad 7,10 0 0250
+¨ "
+co 13,11 0 0251
+© "
+Of 6,11 0 0252
+ª "
+Fo 8,7 0 0253
+« "
+no 8,6 0 0254
+¬ "
+- 5,5 0 0255
+hy "
+­ "
+rg 13,11 0 0256
+® "
+a- 6,9 0 0257
+¯ "
+de 6,11 0 0260
+° "
++- 8,8 0 0261
+± "
+S2 5,11 0 0262
+² "
+S3 5,11 0 0263
+³ "
+aa 4,11 0 0264
+´ "
+µ 9,7,3 0 0265
+ps 9,11 0 0266
+¶ "
+md 5,6 0 0267
+· "
+ac 5,0,3 0 0270
+¸ "
+S1 5,11 0 0271
+¹ "
+Om 6,11 0 0272
+º "
+Fc 8,7 0 0273
+» "
+14 12,11 0 0274
+¼ "
+12 12,11 0 0275
+½ "
+34 12,11 0 0276
+¾ "
+r? 6,8,3 0 0277
+¿ "
+`A 11,14 0 0300
+À "
+'A 11,14 0 0301
+Á "
+^A 11,14 0 0302
+Â "
+~A 11,14 0 0303
+Ã "
+:A 11,14 0 0304
+Ä "
+oA 11,14 0 0305
+Å "
+AE 14,11 0 0306
+Æ "
+,C 10,11,3 0 0307
+Ç "
+`E 9,14 0 0310
+È "
+'E 9,14 0 0311
+É "
+^E 9,14 0 0312
+Ê "
+:E 9,14 0 0313
+Ë "
+`I 7,14 0 0314
+Ì "
+'I 7,14 0 0315
+Í "
+^I 7,14 0 0316
+Î "
+:I 7,14 0 0317
+Ï "
+-D 11,11 0 0320
+Ð "
+~N 12,14 0 0321
+Ñ "
+`O 10,14 0 0322
+Ò "
+'O 10,14 0 0323
+Ó "
+^O 10,14 0 0324
+Ô "
+~O 10,14 0 0325
+Õ "
+:O 10,14 0 0326
+Ö "
+mu 8,8 0 0327
+× "
+/O 10,11 0 0330
+Ø "
+`U 12,14 0 0331
+Ù "
+'U 12,14 0 0332
+Ú "
+^U 12,14 0 0333
+Û "
+:U 12,14 0 0334
+Ü "
+'Y 9,14 0 0335
+Ý "
+TP 10,11 0 0336
+Þ "
+ss 8,11,3 0 0337
+ß "
+`a 9,11 0 0340
+à "
+'a 9,11 0 0341
+á "
+^a 9,11 0 0342
+â "
+~a 9,10 0 0343
+ã "
+:a 9,10 0 0344
+ä "
+oa 9,11 0 0345
+å "
+ae 10,7 0 0346
+æ "
+,c 6,7,3 0 0347
+ç "
+`e 6,11 0 0350
+è "
+'e 6,11 0 0351
+é "
+^e 6,11 0 0352
+ê "
+:e 6,10 0 0353
+ë "
+`i 4,11 0 0354
+ì "
+'i 4,11 0 0355
+í "
+^i 4,11 0 0356
+î "
+:i 4,10 0 0357
+ï "
+Sd 7,11 0 0360
+ð "
+~n 9,10 0 0361
+ñ "
+`o 7,11 0 0362
+ò "
+'o 7,11 0 0363
+ó "
+^o 7,11 0 0364
+ô "
+~o 7,10 0 0365
+õ "
+:o 7,10 0 0366
+ö "
+di 8,8 0 0367
+÷ "
+/o 7,8,1 0 0370
+ø "
+`u 9,11 0 0371
+ù "
+'u 9,11 0 0372
+ú "
+^u 9,11 0 0373
+û "
+:u 9,10 0 0374
+ü "
+'y 7,11,3 0 0375
+ý "
+Tp 7,11,3 0 0376
+þ "
+:y 7,10,3 0 0377
+ÿ "
diff --git a/gnu/usr.bin/groff/devX100/NR b/gnu/usr.bin/groff/devX100/NR
new file mode 100644
index 0000000..8e6717e
--- /dev/null
+++ b/gnu/usr.bin/groff/devX100/NR
@@ -0,0 +1,306 @@
+name NR
+spacewidth 4
+charset
+--- 4,1 0 040
+! 3,11 0 041
+" 5,11 0 042
+# 8,11 0 043
+sh "
+$ 8,12,2 0 044
+Do "
+% 12,11 0 045
+& 13,11 0 046
+' 4,11 0 047
+( 5,11,2 0 050
+) 6,11,2 0 051
+* 7,11 0 052
++ 9,7 0 053
+, 4,2,2 0 054
+\- 9,4 0 055
+. 4,2 0 056
+/ 4,11 0 057
+sl "
+0 8,11 0 060
+1 8,11 0 061
+2 8,11 0 062
+3 8,11 0 063
+4 8,11 0 064
+5 8,11 0 065
+6 8,11 0 066
+7 8,11 0 067
+8 8,11 0 070
+9 8,11 0 071
+: 4,7 0 072
+; 4,7,2 0 073
+< 10,7 0 074
+= 9,6 0 075
+eq "
+> 10,7 0 076
+? 6,11 0 077
+@ 13,11 0 0100
+at "
+A 10,11 0 0101
+B 10,11 0 0102
+C 11,11 0 0103
+D 11,11 0 0104
+E 10,11 0 0105
+F 10,11 0 0106
+G 11,11 0 0107
+H 12,11 0 0110
+I 6,11 0 0111
+J 7,11 0 0112
+K 11,11 0 0113
+L 10,11 0 0114
+M 16,11 0 0115
+N 13,11 0 0116
+O 11,11 0 0117
+P 10,11 0 0120
+Q 11,11,2 0 0121
+R 11,11 0 0122
+S 8,11 0 0123
+T 10,11 0 0124
+U 13,11 0 0125
+V 10,11 0 0126
+W 16,11 0 0127
+X 13,11 0 0130
+Y 10,11 0 0131
+Z 9,11 0 0132
+[ 4,11,2 0 0133
+lB "
+\ 8,11 0 0134
+rs "
+] 4,11,2 0 0135
+rB "
+^ 7,11 0 0136
+a^ "
+ha "
+_ 7,0,2 0 0137
+` 4,11 0 0140
+oq "
+a 8,7 0 0141
+b 7,11 0 0142
+c 7,7 0 0143
+d 8,11 0 0144
+e 7,7 0 0145
+f 5,11 0 0146
+g 8,7,3 0 0147
+h 9,11 0 0150
+i 4,10 0 0151
+j 4,10,3 0 0152
+k 9,11 0 0153
+l 4,11 0 0154
+m 14,7 0 0155
+n 9,7 0 0156
+o 7,7 0 0157
+p 8,7,3 0 0160
+q 7,7,3 0 0161
+r 7,7 0 0162
+s 6,7 0 0163
+t 5,9 0 0164
+u 9,7 0 0165
+v 8,7 0 0166
+w 12,7 0 0167
+x 8,7 0 0170
+y 8,7,3 0 0171
+z 7,7 0 0172
+{ 4,11,2 0 0173
+lC "
+| 9,11 0 0174
+or "
+ba "
+} 5,11,2 0 0175
+rC "
+~ 9,5 0 0176
+a~ "
+ap "
+ti "
+r! 4,8,3 0 0241
+¡ "
+ct 8,9,2 0 0242
+¢ "
+Po 8,11 0 0243
+£ "
+Cs 8,9 0 0244
+¤ "
+Ye 8,11 0 0245
+¥ "
+bb 9,11 0 0246
+¦ "
+sc 7,11,2 0 0247
+§ "
+ad 6,10 0 0250
+¨ "
+co 14,11 0 0251
+© "
+Of 6,11 0 0252
+ª "
+Fo 7,6 0 0253
+« "
+no 9,5 0 0254
+¬ "
+- 5,4 0 0255
+hy "
+­ "
+rg 14,11 0 0256
+® "
+a- 5,9 0 0257
+¯ "
+de 6,11 0 0260
+° "
++- 9,7 0 0261
+± "
+S2 5,11 0 0262
+² "
+S3 5,11 0 0263
+³ "
+aa 5,11 0 0264
+´ "
+µ 9,7,3 0 0265
+ps 9,11,2 0 0266
+¶ "
+md 4,5 0 0267
+· "
+ac 5,1,3 0 0270
+¸ "
+S1 5,11 0 0271
+¹ "
+Om 5,11 0 0272
+º "
+Fc 7,6 0 0273
+» "
+14 12,11 0 0274
+¼ "
+12 12,11 0 0275
+½ "
+34 12,11 0 0276
+¾ "
+r? 6,8,3 0 0277
+¿ "
+`A 10,14 0 0300
+À "
+'A 10,14 0 0301
+Á "
+^A 10,14 0 0302
+Â "
+~A 10,14 0 0303
+Ã "
+:A 10,13 0 0304
+Ä "
+oA 10,14 0 0305
+Å "
+AE 15,11 0 0306
+Æ "
+,C 11,11,3 0 0307
+Ç "
+`E 10,14 0 0310
+È "
+'E 10,14 0 0311
+É "
+^E 10,14 0 0312
+Ê "
+:E 10,14 0 0313
+Ë "
+`I 6,14 0 0314
+Ì "
+'I 6,14 0 0315
+Í "
+^I 6,14 0 0316
+Î "
+:I 6,14 0 0317
+Ï "
+-D 11,11 0 0320
+Ð "
+~N 13,14 0 0321
+Ñ "
+`O 11,14 0 0322
+Ò "
+'O 11,14 0 0323
+Ó "
+^O 11,14 0 0324
+Ô "
+~O 11,14 0 0325
+Õ "
+:O 11,14 0 0326
+Ö "
+mu 9,7 0 0327
+× "
+/O 11,11 0 0330
+Ø "
+`U 13,14 0 0331
+Ù "
+'U 13,14 0 0332
+Ú "
+^U 13,14 0 0333
+Û "
+:U 13,14 0 0334
+Ü "
+'Y 10,14 0 0335
+Ý "
+TP 10,11 0 0336
+Þ "
+ss 8,11 0 0337
+ß "
+`a 8,11 0 0340
+à "
+'a 8,11 0 0341
+á "
+^a 8,11 0 0342
+â "
+~a 8,10 0 0343
+ã "
+:a 8,10 0 0344
+ä "
+oa 8,11 0 0345
+å "
+ae 12,7 0 0346
+æ "
+,c 7,7,3 0 0347
+ç "
+`e 7,11 0 0350
+è "
+'e 7,11 0 0351
+é "
+^e 7,11 0 0352
+ê "
+:e 7,10 0 0353
+ë "
+`i 4,11 0 0354
+ì "
+'i 4,11 0 0355
+í "
+^i 4,11 0 0356
+î "
+:i 4,10 0 0357
+ï "
+Sd 7,11 0 0360
+ð "
+~n 9,10 0 0361
+ñ "
+`o 7,11 0 0362
+ò "
+'o 7,11 0 0363
+ó "
+^o 7,11 0 0364
+ô "
+~o 7,10 0 0365
+õ "
+:o 7,10 0 0366
+ö "
+di 9,7 0 0367
+÷ "
+/o 7,8,1 0 0370
+ø "
+`u 9,11 0 0371
+ù "
+'u 9,11 0 0372
+ú "
+^u 9,11 0 0373
+û "
+:u 9,10 0 0374
+ü "
+'y 8,11,3 0 0375
+ý "
+Tp 8,11,3 0 0376
+þ "
+:y 8,10,3 0 0377
+ÿ "
diff --git a/gnu/usr.bin/groff/devX100/S b/gnu/usr.bin/groff/devX100/S
new file mode 100644
index 0000000..59af889
--- /dev/null
+++ b/gnu/usr.bin/groff/devX100/S
@@ -0,0 +1,226 @@
+name S
+special
+spacewidth 4
+charset
+--- 4,1 0 040
+! 5,10 0 041
+fa 9,10 0 042
+# 7,10 0 043
+sh "
+te 8,10 0 044
+% 12,10 0 045
+& 11,10 0 046
+st 6,7 0 047
+( 5,10,3 0 050
+) 5,10,3 0 051
+** 7,8 0 052
++ 8,7 0 053
+pl "
+, 3,2,2 0 054
+\- 8,4 0 055
+mi "
+. 3,2 0 056
+/ 4,10 0 057
+sl "
+0 7,10 0 060
+1 7,10 0 061
+2 7,10 0 062
+3 7,10 0 063
+4 7,10 0 064
+5 7,10 0 065
+6 7,10 0 066
+7 7,10 0 067
+8 7,10 0 070
+9 7,10 0 071
+: 4,7 0 072
+; 4,7,2 0 073
+< 8,7 0 074
+= 8,5 0 075
+eq "
+> 8,7 0 076
+? 6,10 0 077
+=~ 8,7 0 0100
+*A 11,10 0 0101
+*B 9,10 0 0102
+*X 11,10 0 0103
+*D 9,10 0 0104
+*E 9,10 0 0105
+*F 11,10 0 0106
+*G 9,10 0 0107
+*Y 11,10 0 0110
+*I 5,10 0 0111
++h 9,10 0 0112
+*K 10,10 0 0113
+*L 10,10 0 0114
+*M 13,10 0 0115
+*N 11,10 0 0116
+*O 10,10 0 0117
+*P 11,10 0 0120
+*H 10,10 0 0121
+*R 8,10 0 0122
+*S 9,10 0 0123
+*T 9,10 0 0124
+--- 9,10 0 0125
+ts 7,7,3 0 0126
+*W 11,10 0 0127
+*C 9,10 0 0130
+*Q 11,10 0 0131
+*Z 9,10 0 0132
+[ 5,10,3 0 0133
+lB "
+tf 10,7 0 0134
+3d "
+] 5,10,3 0 0135
+rB "
+pp 10,10 0 0136
+_ 7,0,3 0 0137
+radicalex 7,12 0 0140
+*a 9,7 0 0141
+*b 8,11,3 0 0142
+*x 8,7,3 0 0143
+*d 7,11 0 0144
+*e 6,7 0 0145
+*f 9,10,3 0 0146
+*g 6,7,3 0 0147
+*y 8,7,3 0 0150
+*i 5,7 0 0151
++f 9,7,3 0 0152
+*k 8,7 0 0153
+*l 8,10 0 0154
+*m 8,7,2 0 0155
+µ "
+*n 8,7 0 0156
+*o 8,7 0 0157
+*p 8,7 0 0160
+*h 7,10 0 0161
+*r 8,7,3 0 0162
+*s 8,7 0 0163
+*t 6,7 0 0164
+*u 8,7 0 0165
++p 11,8 0 0166
+*w 11,7 0 0167
+*c 7,12,3 0 0170
+*q 9,7,3 0 0171
+*z 7,11,3 0 0172
+lC 7,10,3 0 0173
+{ "
+ba 3,10,3 0 0174
+or "
+| "
+rC 7,10,3 0 0175
+} "
+ap 8,5 0 0176
+*U 9,10 0 0241
+fm 4,10 0 0242
+<= 8,9 0 0243
+f/ 4,10 0 0244
+if 10,6 0 0245
+Fn 7,10,3 0 0246
+CL 11,7 0 0247
+DI 11,7 0 0250
+HE 11,7 0 0251
+SP 11,7 0 0252
+<> 15,7 0 0253
+<- 14,7 0 0254
+ua 9,12,3 0 0255
+arrowverttp "
+-> 14,7 0 0256
+da 9,12,3 0 0257
+arrowvertbt "
+de 6,10 0 0260
+° "
++- 8,9 0 0261
+± "
+sd 6,10 0 0262
+>= 8,9 0 0263
+mu 8,7 0 0264
+× "
+pt 10,6 0 0265
+pd 7,11 0 0266
+bu 7,6 0 0267
+di 8,7 0 0270
+÷ "
+!= 8,7 0 0271
+== 8,6 0 0272
+~= 8,7 0 0273
+~~ "
+--- 15,2 0 0274
+arrowvertex 9,12,3 0 0275
+an 15,4 0 0276
+CR 10,9 0 0277
+Ah 12,10 0 0300
+Im 10,11,1 0 0301
+Re 12,11 0 0302
+wp 12,9,3 0 0303
+c* 11,9 0 0304
+c+ 11,9 0 0305
+es 12,11 0 0306
+ca 10,7 0 0307
+cu 10,7 0 0310
+sp 10,7 0 0311
+ip 10,7,2 0 0312
+--- 10,8,1 0 0313
+sb 10,7 0 0314
+ib 10,7,2 0 0315
+mo 10,7 0 0316
+nm 10,8,1 0 0317
+/_ 11,10 0 0320
+gr 10,11 0 0321
+rg 12,10 0 0322
+co 12,10 0 0323
+tm 11,10 0 0324
+--- 12,11,1 0 0325
+sr 8,12 0 0326
+md 4,5 0 0327
+no 10,5 0 0330
+¬ "
+AN 9,7 0 0331
+OR 9,7 0 0332
+hA 15,7 0 0333
+lA 14,7 0 0334
+uA 9,12 0 0335
+rA 14,7 0 0336
+dA 9,12 0 0337
+lz 7,11 0 0340
+la 5,12,3 0 0341
+--- 12,10 0 0342
+--- 12,10 0 0343
+--- 11,10 0 0344
+--- 10,11,1 0 0345
+parenlefttp 6,12,3 0 0346
+parenleftex 6,12,3 0 0347
+parenleftbt 6,12,3 0 0350
+bracketlefttp 6,12,3 0 0351
+lc "
+bracketleftex 6,12,3 0 0352
+bracketleftbt 6,12,3 0 0353
+lf "
+bracelefttp 7,12,3 0 0354
+lt "
+braceleftmid 7,12,3 0 0355
+lk "
+braceleftbt 7,12,3 0 0356
+lb "
+bracerightex 7,12,3 0 0357
+braceleftex "
+bv "
+--- 12,12 0 0360
+ra 5,12,3 0 0361
+is 4,12,1 0 0362
+--- 10,12,3 0 0363
+--- 10,12,3 0 0364
+--- 10,12,3 0 0365
+parenrighttp 6,12,3 0 0366
+parenrightex 6,12,3 0 0367
+parenrightbt 6,12,3 0 0370
+bracketrighttp 6,12,3 0 0371
+rc "
+bracketrightex 6,12,3 0 0372
+bracketrightbt 6,12,3 0 0373
+rf "
+bracerighttp 7,12,3 0 0374
+rt "
+bracerightmid 7,12,3 0 0375
+rk "
+bracerightbt 7,12,3 0 0376
+rb "
diff --git a/gnu/usr.bin/groff/devX100/TB b/gnu/usr.bin/groff/devX100/TB
new file mode 100644
index 0000000..ebafbac
--- /dev/null
+++ b/gnu/usr.bin/groff/devX100/TB
@@ -0,0 +1,306 @@
+name TB
+spacewidth 3
+charset
+--- 3,1 0 040
+! 4,10 0 041
+" 7,10 0 042
+# 7,10 0 043
+sh "
+$ 7,11,1 0 044
+Do "
+% 14,10 0 045
+& 12,10 0 046
+' 4,10 0 047
+( 5,10,3 0 050
+) 5,10,3 0 051
+* 7,10 0 052
++ 8,7 0 053
+, 3,2,2 0 054
+\- 9,4 0 055
+. 3,2 0 056
+/ 4,10 0 057
+sl "
+0 7,10 0 060
+1 7,10 0 061
+2 7,10 0 062
+3 7,10 0 063
+4 7,10 0 064
+5 7,10 0 065
+6 7,10 0 066
+7 7,10 0 067
+8 7,10 0 070
+9 7,10 0 071
+: 4,7 0 072
+; 4,7,2 0 073
+< 8,7 0 074
+= 8,5 0 075
+eq "
+> 8,7 0 076
+? 7,10 0 077
+@ 14,10,2 0 0100
+at "
+A 10,10 0 0101
+B 9,10 0 0102
+C 10,10 0 0103
+D 10,10 0 0104
+E 9,10 0 0105
+F 8,10 0 0106
+G 11,10 0 0107
+H 11,10 0 0110
+I 5,10 0 0111
+J 7,10,1 0 0112
+K 11,10 0 0113
+L 9,10 0 0114
+M 13,10 0 0115
+N 10,10 0 0116
+O 11,10 0 0117
+P 9,10 0 0120
+Q 11,10,3 0 0121
+R 10,10 0 0122
+S 8,10 0 0123
+T 9,10 0 0124
+U 10,10 0 0125
+V 10,10 0 0126
+W 14,10 0 0127
+X 10,10 0 0130
+Y 10,10 0 0131
+Z 9,10 0 0132
+[ 5,10,3 0 0133
+lB "
+\ 4,10 0 0134
+rs "
+] 5,10,3 0 0135
+rB "
+^ 8,10 0 0136
+a^ "
+ha "
+_ 7,0,3 0 0137
+` 4,10 0 0140
+oq "
+a 7,7 0 0141
+b 8,10 0 0142
+c 6,7 0 0143
+d 7,10 0 0144
+e 6,7 0 0145
+f 5,10 0 0146
+g 7,7,3 0 0147
+h 8,10 0 0150
+i 4,10 0 0151
+j 4,10,3 0 0152
+k 8,10 0 0153
+l 4,10 0 0154
+m 12,7 0 0155
+n 8,7 0 0156
+o 7,7 0 0157
+p 8,7,3 0 0160
+q 7,7,3 0 0161
+r 6,7 0 0162
+s 6,7 0 0163
+t 5,9 0 0164
+u 7,7 0 0165
+v 7,7 0 0166
+w 10,7 0 0167
+x 7,7 0 0170
+y 7,7,3 0 0171
+z 6,7 0 0172
+{ 7,10,3 0 0173
+lC "
+| 3,10,2 0 0174
+or "
+ba "
+} 7,10,3 0 0175
+rC "
+~ 8,7 0 0176
+a~ "
+ap "
+ti "
+r! 4,7,3 0 0241
+¡ "
+ct 7,9,2 0 0242
+¢ "
+Po 8,10 0 0243
+£ "
+Cs 8,8 0 0244
+¤ "
+Ye 8,10 0 0245
+¥ "
+bb 3,10,2 0 0246
+¦ "
+sc 7,10,2 0 0247
+§ "
+ad 5,10 0 0250
+¨ "
+co 12,10 0 0251
+© "
+Of 5,10 0 0252
+ª "
+Fo 9,6 0 0253
+« "
+no 9,5 0 0254
+¬ "
+- 4,4 0 0255
+hy "
+­ "
+rg 12,10 0 0256
+® "
+a- 5,9 0 0257
+¯ "
+de 6,10 0 0260
+° "
++- 8,9 0 0261
+± "
+S2 4,10 0 0262
+² "
+S3 4,10 0 0263
+³ "
+aa 5,11 0 0264
+´ "
+µ 7,7,3 0 0265
+ps 8,10,3 0 0266
+¶ "
+md 4,6 0 0267
+· "
+ac 5,0,3 0 0270
+¸ "
+S1 4,10 0 0271
+¹ "
+Om 5,10 0 0272
+º "
+Fc 9,6 0 0273
+» "
+14 10,10 0 0274
+¼ "
+12 10,10 0 0275
+½ "
+34 10,10 0 0276
+¾ "
+r? 7,7,3 0 0277
+¿ "
+`A 10,14 0 0300
+À "
+'A 10,14 0 0301
+Á "
+^A 10,14 0 0302
+Â "
+~A 10,13 0 0303
+Ã "
+:A 10,13 0 0304
+Ä "
+oA 10,14 0 0305
+Å "
+AE 14,10 0 0306
+Æ "
+,C 10,10,3 0 0307
+Ç "
+`E 9,14 0 0310
+È "
+'E 9,14 0 0311
+É "
+^E 9,14 0 0312
+Ê "
+:E 9,13 0 0313
+Ë "
+`I 5,14 0 0314
+Ì "
+'I 5,14 0 0315
+Í "
+^I 5,14 0 0316
+Î "
+:I 5,13 0 0317
+Ï "
+-D 11,10 0 0320
+Ð "
+~N 10,13 0 0321
+Ñ "
+`O 11,14 0 0322
+Ò "
+'O 11,14 0 0323
+Ó "
+^O 11,14 0 0324
+Ô "
+~O 11,13 0 0325
+Õ "
+:O 11,13 0 0326
+Ö "
+mu 8,7 0 0327
+× "
+/O 11,11,1 0 0330
+Ø "
+`U 10,14 0 0331
+Ù "
+'U 10,14 0 0332
+Ú "
+^U 10,14 0 0333
+Û "
+:U 10,13 0 0334
+Ü "
+'Y 10,14 0 0335
+Ý "
+TP 9,10 0 0336
+Þ "
+ss 8,10 0 0337
+ß "
+`a 7,11 0 0340
+à "
+'a 7,11 0 0341
+á "
+^a 7,11 0 0342
+â "
+~a 7,10 0 0343
+ã "
+:a 7,10 0 0344
+ä "
+oa 7,11 0 0345
+å "
+ae 11,7 0 0346
+æ "
+,c 7,7,3 0 0347
+ç "
+`e 7,11 0 0350
+è "
+'e 7,11 0 0351
+é "
+^e 7,11 0 0352
+ê "
+:e 7,10 0 0353
+ë "
+`i 4,11 0 0354
+ì "
+'i 4,11 0 0355
+í "
+^i 4,11 0 0356
+î "
+:i 4,10 0 0357
+ï "
+Sd 7,10 0 0360
+ð "
+~n 8,10 0 0361
+ñ "
+`o 7,11 0 0362
+ò "
+'o 7,11 0 0363
+ó "
+^o 7,11 0 0364
+ô "
+~o 7,10 0 0365
+õ "
+:o 7,10 0 0366
+ö "
+di 8,7 0 0367
+÷ "
+/o 7,8,1 0 0370
+ø "
+`u 7,11 0 0371
+ù "
+'u 7,11 0 0372
+ú "
+^u 7,11 0 0373
+û "
+:u 7,10 0 0374
+ü "
+'y 7,11,3 0 0375
+ý "
+Tp 8,10,3 0 0376
+þ "
+:y 7,10,3 0 0377
+ÿ "
diff --git a/gnu/usr.bin/groff/devX100/TBI b/gnu/usr.bin/groff/devX100/TBI
new file mode 100644
index 0000000..2297b4b
--- /dev/null
+++ b/gnu/usr.bin/groff/devX100/TBI
@@ -0,0 +1,306 @@
+name TBI
+spacewidth 3
+charset
+--- 3,1 0 040
+! 7,10 0 041
+" 7,10 0 042
+# 8,10 0 043
+sh "
+$ 7,11,1 0 044
+Do "
+% 14,10 0 045
+& 10,10 0 046
+' 5,10 0 047
+( 6,10,3 0 050
+) 6,10,3 0 051
+* 7,10 0 052
++ 9,7 0 053
+, 4,2,2 0 054
+\- 9,4 0 055
+. 3,2 0 056
+/ 6,10 0 057
+sl "
+0 7,10 0 060
+1 7,10 0 061
+2 7,10 0 062
+3 7,10 0 063
+4 7,10 0 064
+5 7,10 0 065
+6 7,10 0 066
+7 7,10 0 067
+8 7,10 0 070
+9 7,10 0 071
+: 5,7 0 072
+; 4,7,2 0 073
+< 8,6 0 074
+= 10,5 0 075
+eq "
+> 8,6 0 076
+? 8,10 0 077
+@ 15,10,2 0 0100
+at "
+A 9,10 0 0101
+B 9,10 0 0102
+C 9,10 0 0103
+D 10,10 0 0104
+E 10,10 0 0105
+F 9,10 0 0106
+G 10,10 0 0107
+H 11,10 0 0110
+I 5,10 0 0111
+J 7,10,1 0 0112
+K 11,10 0 0113
+L 9,10 0 0114
+M 13,10 0 0115
+N 11,10 0 0116
+O 10,10 0 0117
+P 9,10 0 0120
+Q 10,10,3 0 0121
+R 10,10 0 0122
+S 8,10 0 0123
+T 10,10 0 0124
+U 10,10 0 0125
+V 10,10 0 0126
+W 13,10 0 0127
+X 9,10 0 0130
+Y 8,10 0 0131
+Z 8,10 0 0132
+[ 6,10,3 0 0133
+lB "
+\ 6,10 0 0134
+rs "
+] 5,10,3 0 0135
+rB "
+^ 8,10 0 0136
+a^ "
+ha "
+_ 7,0,2 0 0137
+` 5,10 0 0140
+oq "
+a 8,7 0 0141
+b 7,10 0 0142
+c 6,7 0 0143
+d 7,10 0 0144
+e 7,7 0 0145
+f 5,10,3 0 0146
+g 6,7,3 0 0147
+h 8,10 0 0150
+i 4,10 0 0151
+j 4,10,3 0 0152
+k 7,10 0 0153
+l 4,10 0 0154
+m 11,7 0 0155
+n 8,7 0 0156
+o 7,7 0 0157
+p 7,7,3 0 0160
+q 7,7,3 0 0161
+r 6,7 0 0162
+s 6,7 0 0163
+t 4,9 0 0164
+u 7,7 0 0165
+v 6,7 0 0166
+w 9,7 0 0167
+x 6,7 0 0170
+y 6,7,3 0 0171
+z 6,7 0 0172
+{ 7,10,3 0 0173
+lC "
+| 4,10 0 0174
+or "
+ba "
+} 7,10,3 0 0175
+rC "
+~ 10,5 0 0176
+a~ "
+ap "
+ti "
+r! 7,7,3 0 0241
+¡ "
+ct 7,8,1 0 0242
+¢ "
+Po 7,10 0 0243
+£ "
+Cs 8,8 0 0244
+¤ "
+Ye 7,10 0 0245
+¥ "
+bb 4,10 0 0246
+¦ "
+sc 8,10,3 0 0247
+§ "
+ad 6,9 0 0250
+¨ "
+co 12,10 0 0251
+© "
+Of 6,10 0 0252
+ª "
+Fo 8,6 0 0253
+« "
+no 9,5 0 0254
+¬ "
+- 5,4 0 0255
+hy "
+­ "
+rg 12,10 0 0256
+® "
+a- 6,9 0 0257
+¯ "
+de 6,10 0 0260
+° "
++- 9,9 0 0261
+± "
+S2 4,10 0 0262
+² "
+S3 4,10 0 0263
+³ "
+aa 6,10 0 0264
+´ "
+µ 7,7,3 0 0265
+ps 8,10,3 0 0266
+¶ "
+md 4,5 0 0267
+· "
+ac 5,0,3 0 0270
+¸ "
+S1 4,10 0 0271
+¹ "
+Om 6,10 0 0272
+º "
+Fc 8,6 0 0273
+» "
+14 10,10 0 0274
+¼ "
+12 10,10 0 0275
+½ "
+34 10,10 0 0276
+¾ "
+r? 8,7,3 0 0277
+¿ "
+`A 9,13 0 0300
+À "
+'A 9,13 0 0301
+Á "
+^A 9,13 0 0302
+Â "
+~A 9,13 0 0303
+Ã "
+:A 9,13 0 0304
+Ä "
+oA 9,13 0 0305
+Å "
+AE 14,10 0 0306
+Æ "
+,C 9,10,3 0 0307
+Ç "
+`E 10,13 0 0310
+È "
+'E 10,13 0 0311
+É "
+^E 10,13 0 0312
+Ê "
+:E 10,13 0 0313
+Ë "
+`I 5,13 0 0314
+Ì "
+'I 5,13 0 0315
+Í "
+^I 5,13 0 0316
+Î "
+:I 5,13 0 0317
+Ï "
+-D 10,10 0 0320
+Ð "
+~N 11,13 0 0321
+Ñ "
+`O 10,13 0 0322
+Ò "
+'O 10,13 0 0323
+Ó "
+^O 10,13 0 0324
+Ô "
+~O 10,13 0 0325
+Õ "
+:O 10,13 0 0326
+Ö "
+mu 9,7 0 0327
+× "
+/O 10,11,1 0 0330
+Ø "
+`U 10,13 0 0331
+Ù "
+'U 10,13 0 0332
+Ú "
+^U 10,13 0 0333
+Û "
+:U 10,13 0 0334
+Ü "
+'Y 8,13 0 0335
+Ý "
+TP 9,10 0 0336
+Þ "
+ss 7,10,3 0 0337
+ß "
+`a 8,10 0 0340
+à "
+'a 8,10 0 0341
+á "
+^a 8,11 0 0342
+â "
+~a 8,10 0 0343
+ã "
+:a 8,10 0 0344
+ä "
+oa 8,11 0 0345
+å "
+ae 11,7 0 0346
+æ "
+,c 6,7,3 0 0347
+ç "
+`e 7,10 0 0350
+è "
+'e 7,10 0 0351
+é "
+^e 7,11 0 0352
+ê "
+:e 7,10 0 0353
+ë "
+`i 4,10 0 0354
+ì "
+'i 4,10 0 0355
+í "
+^i 4,11 0 0356
+î "
+:i 4,10 0 0357
+ï "
+Sd 7,10 0 0360
+ð "
+~n 8,10 0 0361
+ñ "
+`o 7,10 0 0362
+ò "
+'o 7,10 0 0363
+ó "
+^o 7,11 0 0364
+ô "
+~o 7,10 0 0365
+õ "
+:o 7,10 0 0366
+ö "
+di 9,7 0 0367
+÷ "
+/o 7,8,1 0 0370
+ø "
+`u 7,10 0 0371
+ù "
+'u 7,10 0 0372
+ú "
+^u 7,11 0 0373
+û "
+:u 7,10 0 0374
+ü "
+'y 6,10,2 0 0375
+ý "
+Tp 7,10,3 0 0376
+þ "
+:y 6,10,2 0 0377
+ÿ "
diff --git a/gnu/usr.bin/groff/devX100/TI b/gnu/usr.bin/groff/devX100/TI
new file mode 100644
index 0000000..80a2f1c
--- /dev/null
+++ b/gnu/usr.bin/groff/devX100/TI
@@ -0,0 +1,306 @@
+name TI
+spacewidth 3
+charset
+--- 3,1 0 040
+! 5,10 0 041
+" 6,10 0 042
+# 7,10 0 043
+sh "
+$ 7,11,1 0 044
+Do "
+% 12,10 0 045
+& 11,10 0 046
+' 5,10 0 047
+( 5,10,3 0 050
+) 5,10,3 0 051
+* 7,10 0 052
++ 10,7 0 053
+, 4,2,1 0 054
+\- 9,4 0 055
+. 3,2 0 056
+/ 4,10 0 057
+sl "
+0 7,10 0 060
+1 7,10 0 061
+2 7,10 0 062
+3 7,10 0 063
+4 7,10 0 064
+5 7,10 0 065
+6 7,10 0 066
+7 7,10 0 067
+8 7,10 0 070
+9 7,10 0 071
+: 4,7 0 072
+; 4,7,1 0 073
+< 10,7,1 0 074
+= 10,5 0 075
+eq "
+> 10,7,1 0 076
+? 7,10 0 077
+@ 13,10,3 0 0100
+at "
+A 9,10 0 0101
+B 8,10 0 0102
+C 9,10 0 0103
+D 10,10 0 0104
+E 9,10 0 0105
+F 9,10 0 0106
+G 10,10 0 0107
+H 10,10 0 0110
+I 5,10 0 0111
+J 6,10 0 0112
+K 10,10 0 0113
+L 8,10 0 0114
+M 12,10 0 0115
+N 11,10 0 0116
+O 10,10 0 0117
+P 9,10 0 0120
+Q 10,10,3 0 0121
+R 9,10 0 0122
+S 7,10 0 0123
+T 8,10 0 0124
+U 10,10 0 0125
+V 9,10 0 0126
+W 11,10 0 0127
+X 9,10 0 0130
+Y 8,10 0 0131
+Z 8,10 0 0132
+[ 6,10,3 0 0133
+lB "
+\ 4,10 0 0134
+rs "
+] 6,10,3 0 0135
+rB "
+^ 6,10 0 0136
+a^ "
+ha "
+_ 7,0,4 0 0137
+` 5,10 0 0140
+oq "
+a 7,7 0 0141
+b 7,10 0 0142
+c 6,7 0 0143
+d 7,10 0 0144
+e 7,7 0 0145
+f 5,10,3 0 0146
+g 6,7,3 0 0147
+h 7,10 0 0150
+i 4,10 0 0151
+j 4,10,3 0 0152
+k 7,10 0 0153
+l 4,10 0 0154
+m 10,7 0 0155
+n 7,7 0 0156
+o 7,7 0 0157
+p 7,7,3 0 0160
+q 7,7,3 0 0161
+r 5,7 0 0162
+s 6,7 0 0163
+t 5,9 0 0164
+u 7,7 0 0165
+v 6,7 0 0166
+w 9,7 0 0167
+x 7,7 0 0170
+y 7,7,3 0 0171
+z 6,7 0 0172
+{ 6,10,3 0 0173
+lC "
+| 4,10,3 0 0174
+or "
+ba "
+} 6,10,3 0 0175
+rC "
+~ 8,5 0 0176
+a~ "
+ap "
+ti "
+r! 6,7,3 0 0241
+¡ "
+ct 7,9,2 0 0242
+¢ "
+Po 7,10 0 0243
+£ "
+Cs 7,8 0 0244
+¤ "
+Ye 7,10 0 0245
+¥ "
+bb 4,10,3 0 0246
+¦ "
+sc 7,11,2 0 0247
+§ "
+ad 5,10 0 0250
+¨ "
+co 12,10 0 0251
+© "
+Of 5,10 0 0252
+ª "
+Fo 7,6 0 0253
+« "
+no 9,6 0 0254
+¬ "
+- 5,4 0 0255
+hy "
+­ "
+rg 12,10 0 0256
+® "
+a- 5,10 0 0257
+¯ "
+de 6,10 0 0260
+° "
++- 10,9 0 0261
+± "
+S2 4,10 0 0262
+² "
+S3 4,10 0 0263
+³ "
+aa 4,10 0 0264
+´ "
+µ 7,7,3 0 0265
+ps 8,10,3 0 0266
+¶ "
+md 4,4 0 0267
+· "
+ac 5,0,3 0 0270
+¸ "
+S1 4,10 0 0271
+¹ "
+Om 5,10 0 0272
+º "
+Fc 7,6 0 0273
+» "
+14 10,10 0 0274
+¼ "
+12 10,10 0 0275
+½ "
+34 10,10 0 0276
+¾ "
+r? 7,7,3 0 0277
+¿ "
+`A 9,13 0 0300
+À "
+'A 9,13 0 0301
+Á "
+^A 9,13 0 0302
+Â "
+~A 9,13 0 0303
+Ã "
+:A 9,12 0 0304
+Ä "
+oA 9,13 0 0305
+Å "
+AE 13,10 0 0306
+Æ "
+,C 9,10,3 0 0307
+Ç "
+`E 9,13 0 0310
+È "
+'E 9,13 0 0311
+É "
+^E 9,13 0 0312
+Ê "
+:E 9,12 0 0313
+Ë "
+`I 5,13 0 0314
+Ì "
+'I 5,13 0 0315
+Í "
+^I 5,13 0 0316
+Î "
+:I 5,12 0 0317
+Ï "
+-D 10,10 0 0320
+Ð "
+~N 11,13 0 0321
+Ñ "
+`O 10,13 0 0322
+Ò "
+'O 10,13 0 0323
+Ó "
+^O 10,13 0 0324
+Ô "
+~O 10,13 0 0325
+Õ "
+:O 10,12 0 0326
+Ö "
+mu 10,7 0 0327
+× "
+/O 10,11,1 0 0330
+Ø "
+`U 10,13 0 0331
+Ù "
+'U 10,13 0 0332
+Ú "
+^U 10,13 0 0333
+Û "
+:U 10,12 0 0334
+Ü "
+'Y 8,13 0 0335
+Ý "
+TP 9,10 0 0336
+Þ "
+ss 7,10,3 0 0337
+ß "
+`a 7,10 0 0340
+à "
+'a 7,10 0 0341
+á "
+^a 7,11 0 0342
+â "
+~a 7,10 0 0343
+ã "
+:a 7,9 0 0344
+ä "
+oa 7,10 0 0345
+å "
+ae 10,7 0 0346
+æ "
+,c 6,7,3 0 0347
+ç "
+`e 7,10 0 0350
+è "
+'e 7,10 0 0351
+é "
+^e 7,11 0 0352
+ê "
+:e 7,9 0 0353
+ë "
+`i 4,10 0 0354
+ì "
+'i 4,10 0 0355
+í "
+^i 4,11 0 0356
+î "
+:i 4,9 0 0357
+ï "
+Sd 7,10 0 0360
+ð "
+~n 7,10 0 0361
+ñ "
+`o 7,10 0 0362
+ò "
+'o 7,10 0 0363
+ó "
+^o 7,11 0 0364
+ô "
+~o 7,10 0 0365
+õ "
+:o 7,9 0 0366
+ö "
+di 10,7 0 0367
+÷ "
+/o 7,8,1 0 0370
+ø "
+`u 7,10 0 0371
+ù "
+'u 7,10 0 0372
+ú "
+^u 7,11 0 0373
+û "
+:u 7,9 0 0374
+ü "
+'y 7,10,3 0 0375
+ý "
+Tp 7,10,3 0 0376
+þ "
+:y 7,9,3 0 0377
+ÿ "
diff --git a/gnu/usr.bin/groff/devX100/TR b/gnu/usr.bin/groff/devX100/TR
new file mode 100644
index 0000000..eafc811
--- /dev/null
+++ b/gnu/usr.bin/groff/devX100/TR
@@ -0,0 +1,306 @@
+name TR
+spacewidth 3
+charset
+--- 3,1 0 040
+! 5,10 0 041
+" 6,10 0 042
+# 7,10 0 043
+sh "
+$ 7,11,1 0 044
+Do "
+% 12,10 0 045
+& 11,10 0 046
+' 4,10 0 047
+( 5,10,3 0 050
+) 5,10,3 0 051
+* 7,10 0 052
++ 8,7 0 053
+, 4,1,2 0 054
+\- 9,4 0 055
+. 4,1 0 056
+/ 4,10,2 0 057
+sl "
+0 7,10 0 060
+1 7,10 0 061
+2 7,10 0 062
+3 7,10 0 063
+4 7,10 0 064
+5 7,10 0 065
+6 7,10 0 066
+7 7,10 0 067
+8 7,10 0 070
+9 7,10 0 071
+: 4,7 0 072
+; 4,7,2 0 073
+< 8,7 0 074
+= 8,5 0 075
+eq "
+> 8,7 0 076
+? 6,10 0 077
+@ 13,10,2 0 0100
+at "
+A 11,10 0 0101
+B 9,10 0 0102
+C 10,10 0 0103
+D 10,10 0 0104
+E 9,10 0 0105
+F 8,10 0 0106
+G 11,10 0 0107
+H 10,10 0 0110
+I 5,10 0 0111
+J 6,10 0 0112
+K 10,10 0 0113
+L 9,10 0 0114
+M 13,10 0 0115
+N 11,10 0 0116
+O 10,10 0 0117
+P 8,10 0 0120
+Q 10,10,3 0 0121
+R 9,10 0 0122
+S 8,10 0 0123
+T 9,10 0 0124
+U 10,10 0 0125
+V 9,10 0 0126
+W 13,10 0 0127
+X 10,10 0 0130
+Y 9,10 0 0131
+Z 8,10 0 0132
+[ 5,10,3 0 0133
+lB "
+\ 4,10 0 0134
+rs "
+] 5,10,3 0 0135
+rB "
+^ 7,10 0 0136
+a^ "
+ha "
+_ 7,0,3 0 0137
+` 4,10 0 0140
+oq "
+a 7,7 0 0141
+b 7,10 0 0142
+c 7,7 0 0143
+d 7,10 0 0144
+e 7,7 0 0145
+f 4,10 0 0146
+g 7,7,3 0 0147
+h 7,10 0 0150
+i 3,10 0 0151
+j 4,10,3 0 0152
+k 7,10 0 0153
+l 3,10 0 0154
+m 11,7 0 0155
+n 7,7 0 0156
+o 7,7 0 0157
+p 7,7,3 0 0160
+q 7,7,3 0 0161
+r 5,7 0 0162
+s 6,7 0 0163
+t 4,8 0 0164
+u 7,7 0 0165
+v 7,7 0 0166
+w 11,7 0 0167
+x 7,7 0 0170
+y 7,7,3 0 0171
+z 6,7 0 0172
+{ 7,10,3 0 0173
+lC "
+| 3,10 0 0174
+or "
+ba "
+} 7,10,3 0 0175
+rC "
+~ 8,5 0 0176
+a~ "
+ap "
+ti "
+r! 5,7,3 0 0241
+¡ "
+ct 7,8,1 0 0242
+¢ "
+Po 8,10 0 0243
+£ "
+Cs 7,8 0 0244
+¤ "
+Ye 7,10 0 0245
+¥ "
+bb 3,10 0 0246
+¦ "
+sc 7,10,3 0 0247
+§ "
+ad 5,10 0 0250
+¨ "
+co 12,10 0 0251
+© "
+Of 4,10 0 0252
+ª "
+Fo 7,6 0 0253
+« "
+no 9,6 0 0254
+¬ "
+- 4,4 0 0255
+hy "
+­ "
+rg 12,10 0 0256
+® "
+a- 4,9 0 0257
+¯ "
+de 6,10 0 0260
+° "
++- 8,7 0 0261
+± "
+S2 4,10 0 0262
+² "
+S3 4,10 0 0263
+³ "
+aa 5,11 0 0264
+´ "
+µ 7,7,3 0 0265
+ps 7,10,3 0 0266
+¶ "
+md 4,5 0 0267
+· "
+ac 5,0,3 0 0270
+¸ "
+S1 4,10 0 0271
+¹ "
+Om 5,10 0 0272
+º "
+Fc 7,6 0 0273
+» "
+14 10,10 0 0274
+¼ "
+12 10,10 0 0275
+½ "
+34 10,10 0 0276
+¾ "
+r? 6,7,3 0 0277
+¿ "
+`A 11,14 0 0300
+À "
+'A 11,14 0 0301
+Á "
+^A 11,14 0 0302
+Â "
+~A 11,14 0 0303
+Ã "
+:A 11,13 0 0304
+Ä "
+oA 11,14 0 0305
+Å "
+AE 13,10 0 0306
+Æ "
+,C 10,10,3 0 0307
+Ç "
+`E 9,14 0 0310
+È "
+'E 9,14 0 0311
+É "
+^E 9,14 0 0312
+Ê "
+:E 9,13 0 0313
+Ë "
+`I 5,14 0 0314
+Ì "
+'I 5,14 0 0315
+Í "
+^I 5,14 0 0316
+Î "
+:I 5,13 0 0317
+Ï "
+-D 10,10 0 0320
+Ð "
+~N 11,14 0 0321
+Ñ "
+`O 10,14 0 0322
+Ò "
+'O 10,14 0 0323
+Ó "
+^O 10,14 0 0324
+Ô "
+~O 10,14 0 0325
+Õ "
+:O 10,13 0 0326
+Ö "
+mu 8,7 0 0327
+× "
+/O 10,11,1 0 0330
+Ø "
+`U 10,14 0 0331
+Ù "
+'U 10,14 0 0332
+Ú "
+^U 10,14 0 0333
+Û "
+:U 10,13 0 0334
+Ü "
+'Y 9,14 0 0335
+Ý "
+TP 8,10 0 0336
+Þ "
+ss 7,10 0 0337
+ß "
+`a 7,11 0 0340
+à "
+'a 7,11 0 0341
+á "
+^a 7,11 0 0342
+â "
+~a 7,11 0 0343
+ã "
+:a 7,10 0 0344
+ä "
+oa 7,11 0 0345
+å "
+ae 11,7 0 0346
+æ "
+,c 7,7,3 0 0347
+ç "
+`e 7,11 0 0350
+è "
+'e 7,11 0 0351
+é "
+^e 7,11 0 0352
+ê "
+:e 7,10 0 0353
+ë "
+`i 3,11 0 0354
+ì "
+'i 3,11 0 0355
+í "
+^i 3,11 0 0356
+î "
+:i 3,10 0 0357
+ï "
+Sd 7,10 0 0360
+ð "
+~n 7,11 0 0361
+ñ "
+`o 7,11 0 0362
+ò "
+'o 7,11 0 0363
+ó "
+^o 7,11 0 0364
+ô "
+~o 7,11 0 0365
+õ "
+:o 7,10 0 0366
+ö "
+di 8,7 0 0367
+÷ "
+/o 7,8,1 0 0370
+ø "
+`u 7,11 0 0371
+ù "
+'u 7,11 0 0372
+ú "
+^u 7,11 0 0373
+û "
+:u 7,10 0 0374
+ü "
+'y 7,11,3 0 0375
+ý "
+Tp 7,10,3 0 0376
+þ "
+:y 7,10,3 0 0377
+ÿ "
diff --git a/gnu/usr.bin/groff/devX75-12/CB b/gnu/usr.bin/groff/devX75-12/CB
new file mode 100644
index 0000000..a5d1baf
--- /dev/null
+++ b/gnu/usr.bin/groff/devX75-12/CB
@@ -0,0 +1,306 @@
+name CB
+spacewidth 7
+charset
+--- 7,1 0 040
+! 7,9 0 041
+" 7,8 0 042
+# 7,8 0 043
+sh "
+$ 7,10,2 0 044
+Do "
+% 7,8 0 045
+& 7,8 0 046
+' 7,8 0 047
+( 7,9,2 0 050
+) 7,9,2 0 051
+* 7,9 0 052
++ 7,6 0 053
+, 7,2,1 0 054
+\- 7,4 0 055
+. 7,2 0 056
+/ 7,8,2 0 057
+sl "
+0 7,9 0 060
+1 7,9 0 061
+2 7,9 0 062
+3 7,9 0 063
+4 7,9 0 064
+5 7,9 0 065
+6 7,9 0 066
+7 7,9 0 067
+8 7,9 0 070
+9 7,9 0 071
+: 7,6 0 072
+; 7,6,1 0 073
+< 7,7 0 074
+= 7,5 0 075
+eq "
+> 7,7 0 076
+? 7,8 0 077
+@ 7,8 0 0100
+at "
+A 7,8 0 0101
+B 7,8 0 0102
+C 7,8 0 0103
+D 7,8 0 0104
+E 7,8 0 0105
+F 7,8 0 0106
+G 7,8 0 0107
+H 7,8 0 0110
+I 7,8 0 0111
+J 7,8 0 0112
+K 7,8 0 0113
+L 7,8 0 0114
+M 7,8 0 0115
+N 7,8 0 0116
+O 7,8 0 0117
+P 7,8 0 0120
+Q 7,8,2 0 0121
+R 7,8 0 0122
+S 7,8 0 0123
+T 7,8 0 0124
+U 7,8 0 0125
+V 7,8 0 0126
+W 7,8 0 0127
+X 7,8 0 0130
+Y 7,8 0 0131
+Z 7,8 0 0132
+[ 7,9,2 0 0133
+lB "
+\ 7,8,2 0 0134
+rs "
+] 7,9,2 0 0135
+rB "
+^ 7,8 0 0136
+a^ "
+ha "
+_ 7,0,2 0 0137
+` 7,8 0 0140
+oq "
+a 7,6 0 0141
+b 7,9 0 0142
+c 7,6 0 0143
+d 7,9 0 0144
+e 7,6 0 0145
+f 7,9 0 0146
+g 7,6,3 0 0147
+h 7,9 0 0150
+i 7,9 0 0151
+j 7,9,3 0 0152
+k 7,9 0 0153
+l 7,9 0 0154
+m 7,6 0 0155
+n 7,6 0 0156
+o 7,6 0 0157
+p 7,6,3 0 0160
+q 7,6,3 0 0161
+r 7,6 0 0162
+s 7,6 0 0163
+t 7,8 0 0164
+u 7,6 0 0165
+v 7,6 0 0166
+w 7,6 0 0167
+x 7,6 0 0170
+y 7,6,3 0 0171
+z 7,6 0 0172
+{ 7,9,2 0 0173
+lC "
+| 7,8,2 0 0174
+or "
+ba "
+} 7,9,2 0 0175
+rC "
+~ 7,5 0 0176
+a~ "
+ap "
+ti "
+r! 7,6,3 0 0241
+¡ "
+ct 7,8,1 0 0242
+¢ "
+Po 7,8 0 0243
+£ "
+Cs 7,7 0 0244
+¤ "
+Ye 7,8 0 0245
+¥ "
+bb 7,8,2 0 0246
+¦ "
+sc 7,9,1 0 0247
+§ "
+ad 7,9 0 0250
+¨ "
+co 7,8 0 0251
+© "
+Of 7,9 0 0252
+ª "
+Fo 7,5 0 0253
+« "
+no 7,5 0 0254
+¬ "
+- 7,4 0 0255
+hy "
+­ "
+rg 7,8 0 0256
+® "
+a- 7,8 0 0257
+¯ "
+de 7,8 0 0260
+° "
++- 7,6 0 0261
+± "
+S2 7,8 0 0262
+² "
+S3 7,8 0 0263
+³ "
+aa 7,9 0 0264
+´ "
+µ 7,6,3 0 0265
+ps 7,9,1 0 0266
+¶ "
+md 7,5 0 0267
+· "
+ac 7,0,3 0 0270
+¸ "
+S1 7,8 0 0271
+¹ "
+Om 7,9 0 0272
+º "
+Fc 7,5 0 0273
+» "
+14 7,9,1 0 0274
+¼ "
+12 7,9,1 0 0275
+½ "
+34 7,9,1 0 0276
+¾ "
+r? 7,6,3 0 0277
+¿ "
+`A 7,11 0 0300
+À "
+'A 7,11 0 0301
+Á "
+^A 7,11 0 0302
+Â "
+~A 7,11 0 0303
+Ã "
+:A 7,10 0 0304
+Ä "
+oA 7,11 0 0305
+Å "
+AE 7,8 0 0306
+Æ "
+,C 7,8,3 0 0307
+Ç "
+`E 7,11 0 0310
+È "
+'E 7,11 0 0311
+É "
+^E 7,11 0 0312
+Ê "
+:E 7,10 0 0313
+Ë "
+`I 7,11 0 0314
+Ì "
+'I 7,11 0 0315
+Í "
+^I 7,11 0 0316
+Î "
+:I 7,10 0 0317
+Ï "
+-D 7,8 0 0320
+Ð "
+~N 7,11 0 0321
+Ñ "
+`O 7,11 0 0322
+Ò "
+'O 7,11 0 0323
+Ó "
+^O 7,11 0 0324
+Ô "
+~O 7,11 0 0325
+Õ "
+:O 7,10 0 0326
+Ö "
+mu 7,6 0 0327
+× "
+/O 7,8 0 0330
+Ø "
+`U 7,11 0 0331
+Ù "
+'U 7,11 0 0332
+Ú "
+^U 7,11 0 0333
+Û "
+:U 7,10 0 0334
+Ü "
+'Y 7,11 0 0335
+Ý "
+TP 7,8 0 0336
+Þ "
+ss 7,9 0 0337
+ß "
+`a 7,9 0 0340
+à "
+'a 7,9 0 0341
+á "
+^a 7,9 0 0342
+â "
+~a 7,9 0 0343
+ã "
+:a 7,8 0 0344
+ä "
+oa 7,10 0 0345
+å "
+ae 7,6 0 0346
+æ "
+,c 7,6,3 0 0347
+ç "
+`e 7,9 0 0350
+è "
+'e 7,9 0 0351
+é "
+^e 7,9 0 0352
+ê "
+:e 7,8 0 0353
+ë "
+`i 7,9 0 0354
+ì "
+'i 7,9 0 0355
+í "
+^i 7,9 0 0356
+î "
+:i 7,8 0 0357
+ï "
+Sd 7,9 0 0360
+ð "
+~n 7,9 0 0361
+ñ "
+`o 7,9 0 0362
+ò "
+'o 7,9 0 0363
+ó "
+^o 7,9 0 0364
+ô "
+~o 7,9 0 0365
+õ "
+:o 7,8 0 0366
+ö "
+di 7,6 0 0367
+÷ "
+/o 7,7,1 0 0370
+ø "
+`u 7,9 0 0371
+ù "
+'u 7,9 0 0372
+ú "
+^u 7,9 0 0373
+û "
+:u 7,8 0 0374
+ü "
+'y 7,9,3 0 0375
+ý "
+Tp 7,8,3 0 0376
+þ "
+:y 7,8,3 0 0377
+ÿ "
diff --git a/gnu/usr.bin/groff/devX75-12/CBI b/gnu/usr.bin/groff/devX75-12/CBI
new file mode 100644
index 0000000..764eaf7
--- /dev/null
+++ b/gnu/usr.bin/groff/devX75-12/CBI
@@ -0,0 +1,306 @@
+name CBI
+spacewidth 7
+charset
+--- 7,1 0 040
+! 7,9 0 041
+" 7,8 0 042
+# 7,9 0 043
+sh "
+$ 7,10,2 0 044
+Do "
+% 7,8 0 045
+& 7,8 0 046
+' 7,8 0 047
+( 7,9,2 0 050
+) 7,9,2 0 051
+* 7,8 0 052
++ 7,6 0 053
+, 7,2,1 0 054
+\- 7,4 0 055
+. 7,2 0 056
+/ 7,9,1 0 057
+sl "
+0 7,9 0 060
+1 7,9 0 061
+2 7,9 0 062
+3 7,9 0 063
+4 7,9 0 064
+5 7,9 0 065
+6 7,9 0 066
+7 7,9 0 067
+8 7,9 0 070
+9 7,9 0 071
+: 7,6 0 072
+; 7,6,1 0 073
+< 7,6 0 074
+= 7,5 0 075
+eq "
+> 7,6 0 076
+? 7,8 0 077
+@ 7,8,1 0 0100
+at "
+A 7,8 0 0101
+B 7,8 0 0102
+C 7,8 0 0103
+D 7,8 0 0104
+E 7,8 0 0105
+F 7,8 0 0106
+G 7,8 0 0107
+H 7,8 0 0110
+I 7,8 0 0111
+J 7,8 0 0112
+K 7,8 0 0113
+L 7,8 0 0114
+M 7,8 0 0115
+N 7,8 0 0116
+O 7,8 0 0117
+P 7,8 0 0120
+Q 7,8,2 0 0121
+R 7,8 0 0122
+S 7,8 0 0123
+T 7,8 0 0124
+U 7,8 0 0125
+V 7,8 0 0126
+W 7,8 0 0127
+X 7,8 0 0130
+Y 7,8 0 0131
+Z 7,8 0 0132
+[ 7,9,2 0 0133
+lB "
+\ 7,9,1 0 0134
+rs "
+] 7,9,2 0 0135
+rB "
+^ 7,8 0 0136
+a^ "
+ha "
+_ 7,0,2 0 0137
+` 7,8 0 0140
+oq "
+a 7,6 0 0141
+b 7,9 0 0142
+c 7,6 0 0143
+d 7,9 0 0144
+e 7,6 0 0145
+f 7,9 0 0146
+g 7,6,3 0 0147
+h 7,9 0 0150
+i 7,9 0 0151
+j 7,9,3 0 0152
+k 7,9 0 0153
+l 7,9 0 0154
+m 7,6 0 0155
+n 7,6 0 0156
+o 7,6 0 0157
+p 7,6,3 0 0160
+q 7,6,3 0 0161
+r 7,6 0 0162
+s 7,6 0 0163
+t 7,8 0 0164
+u 7,6 0 0165
+v 7,6 0 0166
+w 7,6 0 0167
+x 7,6 0 0170
+y 7,6,3 0 0171
+z 7,6 0 0172
+{ 7,9,2 0 0173
+lC "
+| 7,8,1 0 0174
+or "
+ba "
+} 7,9,2 0 0175
+rC "
+~ 7,5 0 0176
+a~ "
+ap "
+ti "
+r! 7,6,2 0 0241
+¡ "
+ct 7,8,1 0 0242
+¢ "
+Po 7,8 0 0243
+£ "
+Cs 7,7 0 0244
+¤ "
+Ye 7,8 0 0245
+¥ "
+bb 7,8,1 0 0246
+¦ "
+sc 7,9,1 0 0247
+§ "
+ad 7,9 0 0250
+¨ "
+co 7,8 0 0251
+© "
+Of 7,8 0 0252
+ª "
+Fo 7,5 0 0253
+« "
+no 7,5 0 0254
+¬ "
+- 7,4 0 0255
+hy "
+­ "
+rg 7,8 0 0256
+® "
+a- 7,8 0 0257
+¯ "
+de 7,8 0 0260
+° "
++- 7,6 0 0261
+± "
+S2 7,8 0 0262
+² "
+S3 7,8 0 0263
+³ "
+aa 7,9 0 0264
+´ "
+µ 7,6,3 0 0265
+ps 7,9,1 0 0266
+¶ "
+md 7,5 0 0267
+· "
+ac 7,0,3 0 0270
+¸ "
+S1 7,8 0 0271
+¹ "
+Om 7,8 0 0272
+º "
+Fc 7,5 0 0273
+» "
+14 7,9 0 0274
+¼ "
+12 7,9 0 0275
+½ "
+34 7,9 0 0276
+¾ "
+r? 7,6,2 0 0277
+¿ "
+`A 7,11 0 0300
+À "
+'A 7,11 0 0301
+Á "
+^A 7,11 0 0302
+Â "
+~A 7,11 0 0303
+Ã "
+:A 7,10 0 0304
+Ä "
+oA 7,11 0 0305
+Å "
+AE 7,8 0 0306
+Æ "
+,C 7,8,3 0 0307
+Ç "
+`E 7,11 0 0310
+È "
+'E 7,11 0 0311
+É "
+^E 7,11 0 0312
+Ê "
+:E 7,10 0 0313
+Ë "
+`I 7,11 0 0314
+Ì "
+'I 7,11 0 0315
+Í "
+^I 7,11 0 0316
+Î "
+:I 7,10 0 0317
+Ï "
+-D 7,8 0 0320
+Ð "
+~N 7,11 0 0321
+Ñ "
+`O 7,11 0 0322
+Ò "
+'O 7,11 0 0323
+Ó "
+^O 7,11 0 0324
+Ô "
+~O 7,11 0 0325
+Õ "
+:O 7,10 0 0326
+Ö "
+mu 7,6 0 0327
+× "
+/O 7,8 0 0330
+Ø "
+`U 7,11 0 0331
+Ù "
+'U 7,11 0 0332
+Ú "
+^U 7,11 0 0333
+Û "
+:U 7,10 0 0334
+Ü "
+'Y 7,11 0 0335
+Ý "
+TP 7,8 0 0336
+Þ "
+ss 7,8 0 0337
+ß "
+`a 7,9 0 0340
+à "
+'a 7,9 0 0341
+á "
+^a 7,9 0 0342
+â "
+~a 7,9 0 0343
+ã "
+:a 7,8 0 0344
+ä "
+oa 7,10 0 0345
+å "
+ae 7,6 0 0346
+æ "
+,c 7,6,3 0 0347
+ç "
+`e 7,9 0 0350
+è "
+'e 7,9 0 0351
+é "
+^e 7,9 0 0352
+ê "
+:e 7,8 0 0353
+ë "
+`i 7,9 0 0354
+ì "
+'i 7,9 0 0355
+í "
+^i 7,9 0 0356
+î "
+:i 7,8 0 0357
+ï "
+Sd 7,10 0 0360
+ð "
+~n 7,9 0 0361
+ñ "
+`o 7,9 0 0362
+ò "
+'o 7,9 0 0363
+ó "
+^o 7,9 0 0364
+ô "
+~o 7,9 0 0365
+õ "
+:o 7,8 0 0366
+ö "
+di 7,6 0 0367
+÷ "
+/o 7,7,1 0 0370
+ø "
+`u 7,9 0 0371
+ù "
+'u 7,9 0 0372
+ú "
+^u 7,9 0 0373
+û "
+:u 7,8 0 0374
+ü "
+'y 7,9,3 0 0375
+ý "
+Tp 7,8,3 0 0376
+þ "
+:y 7,8,3 0 0377
+ÿ "
diff --git a/gnu/usr.bin/groff/devX75-12/CI b/gnu/usr.bin/groff/devX75-12/CI
new file mode 100644
index 0000000..acc9ec8
--- /dev/null
+++ b/gnu/usr.bin/groff/devX75-12/CI
@@ -0,0 +1,306 @@
+name CI
+spacewidth 7
+charset
+--- 7,1 0 040
+! 7,8 0 041
+" 7,8 0 042
+# 7,8 0 043
+sh "
+$ 7,10,1 0 044
+Do "
+% 7,8 0 045
+& 7,8 0 046
+' 7,8 0 047
+( 7,9,2 0 050
+) 7,9,2 0 051
+* 7,8 0 052
++ 7,6 0 053
+, 7,2,1 0 054
+\- 7,4 0 055
+. 7,1 0 056
+/ 7,8,1 0 057
+sl "
+0 7,9 0 060
+1 7,9 0 061
+2 7,9 0 062
+3 7,9 0 063
+4 7,9 0 064
+5 7,9 0 065
+6 7,9 0 066
+7 7,9 0 067
+8 7,9 0 070
+9 7,9 0 071
+: 7,5 0 072
+; 7,5,1 0 073
+< 7,7 0 074
+= 7,5 0 075
+eq "
+> 7,7 0 076
+? 7,8 0 077
+@ 7,8 0 0100
+at "
+A 7,8 0 0101
+B 7,8 0 0102
+C 7,8 0 0103
+D 7,8 0 0104
+E 7,8 0 0105
+F 7,8 0 0106
+G 7,8 0 0107
+H 7,8 0 0110
+I 7,8 0 0111
+J 7,8 0 0112
+K 7,8 0 0113
+L 7,8 0 0114
+M 7,8 0 0115
+N 7,8 0 0116
+O 7,8 0 0117
+P 7,8 0 0120
+Q 7,8,2 0 0121
+R 7,8 0 0122
+S 7,8 0 0123
+T 7,8 0 0124
+U 7,8 0 0125
+V 7,8 0 0126
+W 7,8 0 0127
+X 7,8 0 0130
+Y 7,8 0 0131
+Z 7,8 0 0132
+[ 7,9,2 0 0133
+lB "
+\ 7,8,1 0 0134
+rs "
+] 7,9,2 0 0135
+rB "
+^ 7,8 0 0136
+a^ "
+ha "
+_ 7,0,3 0 0137
+` 7,8 0 0140
+oq "
+a 7,6 0 0141
+b 7,9 0 0142
+c 7,6 0 0143
+d 7,9 0 0144
+e 7,6 0 0145
+f 7,9 0 0146
+g 7,6,3 0 0147
+h 7,9 0 0150
+i 7,9 0 0151
+j 7,9,3 0 0152
+k 7,9 0 0153
+l 7,9 0 0154
+m 7,6 0 0155
+n 7,6 0 0156
+o 7,6 0 0157
+p 7,6,3 0 0160
+q 7,6,3 0 0161
+r 7,6 0 0162
+s 7,6 0 0163
+t 7,8 0 0164
+u 7,6 0 0165
+v 7,6 0 0166
+w 7,6 0 0167
+x 7,6 0 0170
+y 7,6,3 0 0171
+z 7,6 0 0172
+{ 7,9,2 0 0173
+lC "
+| 7,8,1 0 0174
+or "
+ba "
+} 7,9,2 0 0175
+rC "
+~ 7,4 0 0176
+a~ "
+ap "
+ti "
+r! 7,6,3 0 0241
+¡ "
+ct 7,8,1 0 0242
+¢ "
+Po 7,8 0 0243
+£ "
+Cs 7,7 0 0244
+¤ "
+Ye 7,8 0 0245
+¥ "
+bb 7,8,2 0 0246
+¦ "
+sc 7,9,1 0 0247
+§ "
+ad 7,8 0 0250
+¨ "
+co 7,8 0 0251
+© "
+Of 7,8 0 0252
+ª "
+Fo 7,6 0 0253
+« "
+no 7,5 0 0254
+¬ "
+- 7,4 0 0255
+hy "
+­ "
+rg 7,8 0 0256
+® "
+a- 7,8 0 0257
+¯ "
+de 7,8 0 0260
+° "
++- 7,6 0 0261
+± "
+S2 7,8 0 0262
+² "
+S3 7,8 0 0263
+³ "
+aa 7,9 0 0264
+´ "
+µ 7,6,3 0 0265
+ps 7,9,1 0 0266
+¶ "
+md 7,4 0 0267
+· "
+ac 7,0,3 0 0270
+¸ "
+S1 7,8 0 0271
+¹ "
+Om 7,8 0 0272
+º "
+Fc 7,6 0 0273
+» "
+14 7,9,1 0 0274
+¼ "
+12 7,9,1 0 0275
+½ "
+34 7,9,1 0 0276
+¾ "
+r? 7,6,2 0 0277
+¿ "
+`A 7,11 0 0300
+À "
+'A 7,11 0 0301
+Á "
+^A 7,11 0 0302
+Â "
+~A 7,11 0 0303
+Ã "
+:A 7,10 0 0304
+Ä "
+oA 7,11 0 0305
+Å "
+AE 7,8 0 0306
+Æ "
+,C 7,8,3 0 0307
+Ç "
+`E 7,11 0 0310
+È "
+'E 7,11 0 0311
+É "
+^E 7,11 0 0312
+Ê "
+:E 7,10 0 0313
+Ë "
+`I 7,11 0 0314
+Ì "
+'I 7,11 0 0315
+Í "
+^I 7,11 0 0316
+Î "
+:I 7,10 0 0317
+Ï "
+-D 7,8 0 0320
+Ð "
+~N 7,11 0 0321
+Ñ "
+`O 7,11 0 0322
+Ò "
+'O 7,11 0 0323
+Ó "
+^O 7,11 0 0324
+Ô "
+~O 7,11 0 0325
+Õ "
+:O 7,10 0 0326
+Ö "
+mu 7,6 0 0327
+× "
+/O 7,8 0 0330
+Ø "
+`U 7,11 0 0331
+Ù "
+'U 7,11 0 0332
+Ú "
+^U 7,11 0 0333
+Û "
+:U 7,10 0 0334
+Ü "
+'Y 7,11 0 0335
+Ý "
+TP 7,8 0 0336
+Þ "
+ss 7,9 0 0337
+ß "
+`a 7,9 0 0340
+à "
+'a 7,9 0 0341
+á "
+^a 7,9 0 0342
+â "
+~a 7,9 0 0343
+ã "
+:a 7,8 0 0344
+ä "
+oa 7,10 0 0345
+å "
+ae 7,6 0 0346
+æ "
+,c 7,6,3 0 0347
+ç "
+`e 7,9 0 0350
+è "
+'e 7,9 0 0351
+é "
+^e 7,9 0 0352
+ê "
+:e 7,8 0 0353
+ë "
+`i 7,9 0 0354
+ì "
+'i 7,9 0 0355
+í "
+^i 7,9 0 0356
+î "
+:i 7,8 0 0357
+ï "
+Sd 7,10 0 0360
+ð "
+~n 7,9 0 0361
+ñ "
+`o 7,9 0 0362
+ò "
+'o 7,9 0 0363
+ó "
+^o 7,9 0 0364
+ô "
+~o 7,9 0 0365
+õ "
+:o 7,8 0 0366
+ö "
+di 7,6 0 0367
+÷ "
+/o 7,7,1 0 0370
+ø "
+`u 7,9 0 0371
+ù "
+'u 7,9 0 0372
+ú "
+^u 7,9 0 0373
+û "
+:u 7,8 0 0374
+ü "
+'y 7,9,3 0 0375
+ý "
+Tp 7,9,3 0 0376
+þ "
+:y 7,8,3 0 0377
+ÿ "
diff --git a/gnu/usr.bin/groff/devX75-12/CR b/gnu/usr.bin/groff/devX75-12/CR
new file mode 100644
index 0000000..666e837
--- /dev/null
+++ b/gnu/usr.bin/groff/devX75-12/CR
@@ -0,0 +1,306 @@
+name CR
+spacewidth 7
+charset
+--- 7,1 0 040
+! 7,9 0 041
+" 7,8 0 042
+# 7,8 0 043
+sh "
+$ 7,9,1 0 044
+Do "
+% 7,8 0 045
+& 7,8 0 046
+' 7,8 0 047
+( 7,9,2 0 050
+) 7,9,2 0 051
+* 7,8 0 052
++ 7,6 0 053
+, 7,2,1 0 054
+\- 7,4 0 055
+. 7,1 0 056
+/ 7,9,1 0 057
+sl "
+0 7,9 0 060
+1 7,9 0 061
+2 7,9 0 062
+3 7,9 0 063
+4 7,9 0 064
+5 7,9 0 065
+6 7,9 0 066
+7 7,9 0 067
+8 7,9 0 070
+9 7,9 0 071
+: 7,5 0 072
+; 7,5,1 0 073
+< 7,7 0 074
+= 7,5 0 075
+eq "
+> 7,7 0 076
+? 7,8 0 077
+@ 7,8 0 0100
+at "
+A 7,8 0 0101
+B 7,8 0 0102
+C 7,8 0 0103
+D 7,8 0 0104
+E 7,8 0 0105
+F 7,8 0 0106
+G 7,8 0 0107
+H 7,8 0 0110
+I 7,8 0 0111
+J 7,8 0 0112
+K 7,8 0 0113
+L 7,8 0 0114
+M 7,8 0 0115
+N 7,8 0 0116
+O 7,8 0 0117
+P 7,8 0 0120
+Q 7,8,1 0 0121
+R 7,8 0 0122
+S 7,8 0 0123
+T 7,8 0 0124
+U 7,8 0 0125
+V 7,8 0 0126
+W 7,8 0 0127
+X 7,8 0 0130
+Y 7,8 0 0131
+Z 7,8 0 0132
+[ 7,9,2 0 0133
+lB "
+\ 7,9,1 0 0134
+rs "
+] 7,9,2 0 0135
+rB "
+^ 7,8 0 0136
+a^ "
+ha "
+_ 7,0,3 0 0137
+` 7,8 0 0140
+oq "
+a 7,6 0 0141
+b 7,9 0 0142
+c 7,6 0 0143
+d 7,9 0 0144
+e 7,6 0 0145
+f 7,9 0 0146
+g 7,6,3 0 0147
+h 7,9 0 0150
+i 7,9 0 0151
+j 7,9,3 0 0152
+k 7,9 0 0153
+l 7,9 0 0154
+m 7,6 0 0155
+n 7,6 0 0156
+o 7,6 0 0157
+p 7,6,3 0 0160
+q 7,6,3 0 0161
+r 7,6 0 0162
+s 7,6 0 0163
+t 7,8 0 0164
+u 7,6 0 0165
+v 7,6 0 0166
+w 7,6 0 0167
+x 7,6 0 0170
+y 7,6,3 0 0171
+z 7,6 0 0172
+{ 7,8,2 0 0173
+lC "
+| 7,8,2 0 0174
+or "
+ba "
+} 7,8,2 0 0175
+rC "
+~ 7,5 0 0176
+a~ "
+ap "
+ti "
+r! 7,6,3 0 0241
+¡ "
+ct 7,8,1 0 0242
+¢ "
+Po 7,8 0 0243
+£ "
+Cs 7,7 0 0244
+¤ "
+Ye 7,8 0 0245
+¥ "
+bb 7,8,2 0 0246
+¦ "
+sc 7,9,1 0 0247
+§ "
+ad 7,8 0 0250
+¨ "
+co 7,8 0 0251
+© "
+Of 7,8 0 0252
+ª "
+Fo 7,6 0 0253
+« "
+no 7,5 0 0254
+¬ "
+- 7,4 0 0255
+hy "
+­ "
+rg 7,8 0 0256
+® "
+a- 7,8 0 0257
+¯ "
+de 7,8 0 0260
+° "
++- 7,6 0 0261
+± "
+S2 7,8 0 0262
+² "
+S3 7,8 0 0263
+³ "
+aa 7,9 0 0264
+´ "
+µ 7,6,3 0 0265
+ps 7,9,1 0 0266
+¶ "
+md 7,4 0 0267
+· "
+ac 7,0,3 0 0270
+¸ "
+S1 7,8 0 0271
+¹ "
+Om 7,8 0 0272
+º "
+Fc 7,6 0 0273
+» "
+14 7,9,1 0 0274
+¼ "
+12 7,9,1 0 0275
+½ "
+34 7,9,1 0 0276
+¾ "
+r? 7,6,2 0 0277
+¿ "
+`A 7,11 0 0300
+À "
+'A 7,11 0 0301
+Á "
+^A 7,11 0 0302
+Â "
+~A 7,11 0 0303
+Ã "
+:A 7,10 0 0304
+Ä "
+oA 7,11 0 0305
+Å "
+AE 7,8 0 0306
+Æ "
+,C 7,8,3 0 0307
+Ç "
+`E 7,11 0 0310
+È "
+'E 7,11 0 0311
+É "
+^E 7,11 0 0312
+Ê "
+:E 7,10 0 0313
+Ë "
+`I 7,11 0 0314
+Ì "
+'I 7,11 0 0315
+Í "
+^I 7,11 0 0316
+Î "
+:I 7,10 0 0317
+Ï "
+-D 7,8 0 0320
+Ð "
+~N 7,11 0 0321
+Ñ "
+`O 7,11 0 0322
+Ò "
+'O 7,11 0 0323
+Ó "
+^O 7,11 0 0324
+Ô "
+~O 7,11 0 0325
+Õ "
+:O 7,10 0 0326
+Ö "
+mu 7,6 0 0327
+× "
+/O 7,9,1 0 0330
+Ø "
+`U 7,11 0 0331
+Ù "
+'U 7,11 0 0332
+Ú "
+^U 7,11 0 0333
+Û "
+:U 7,10 0 0334
+Ü "
+'Y 7,11 0 0335
+Ý "
+TP 7,8 0 0336
+Þ "
+ss 7,9 0 0337
+ß "
+`a 7,9 0 0340
+à "
+'a 7,9 0 0341
+á "
+^a 7,9 0 0342
+â "
+~a 7,9 0 0343
+ã "
+:a 7,8 0 0344
+ä "
+oa 7,9 0 0345
+å "
+ae 7,6 0 0346
+æ "
+,c 7,6,3 0 0347
+ç "
+`e 7,9 0 0350
+è "
+'e 7,9 0 0351
+é "
+^e 7,9 0 0352
+ê "
+:e 7,8 0 0353
+ë "
+`i 7,9 0 0354
+ì "
+'i 7,9 0 0355
+í "
+^i 7,9 0 0356
+î "
+:i 7,8 0 0357
+ï "
+Sd 7,10 0 0360
+ð "
+~n 7,9 0 0361
+ñ "
+`o 7,9 0 0362
+ò "
+'o 7,9 0 0363
+ó "
+^o 7,9 0 0364
+ô "
+~o 7,9 0 0365
+õ "
+:o 7,8 0 0366
+ö "
+di 7,6 0 0367
+÷ "
+/o 7,7,1 0 0370
+ø "
+`u 7,9 0 0371
+ù "
+'u 7,9 0 0372
+ú "
+^u 7,9 0 0373
+û "
+:u 7,8 0 0374
+ü "
+'y 7,9,3 0 0375
+ý "
+Tp 7,9,3 0 0376
+þ "
+:y 7,8,3 0 0377
+ÿ "
diff --git a/gnu/usr.bin/groff/devX75-12/DESC b/gnu/usr.bin/groff/devX75-12/DESC
new file mode 100644
index 0000000..4793e59
--- /dev/null
+++ b/gnu/usr.bin/groff/devX75-12/DESC
@@ -0,0 +1,9 @@
+styles R I B BI
+fonts 6 0 0 0 0 0 S
+sizes 8 10 12 14 18 24 0
+res 75
+X11
+hor 1
+vert 1
+unitwidth 12
+postpro gxditview
diff --git a/gnu/usr.bin/groff/devX75-12/HB b/gnu/usr.bin/groff/devX75-12/HB
new file mode 100644
index 0000000..b8cbb6e
--- /dev/null
+++ b/gnu/usr.bin/groff/devX75-12/HB
@@ -0,0 +1,306 @@
+name HB
+spacewidth 4
+charset
+--- 4,1 0 040
+! 4,9 0 041
+" 5,9 0 042
+# 8,8 0 043
+sh "
+$ 7,9,2 0 044
+Do "
+% 12,9 0 045
+& 9,9 0 046
+' 4,9 0 047
+( 6,9,3 0 050
+) 6,9,3 0 051
+* 6,9 0 052
++ 7,6 0 053
+, 4,2,2 0 054
+\- 8,4 0 055
+. 4,2 0 056
+/ 4,9 0 057
+sl "
+0 7,9 0 060
+1 7,9 0 061
+2 7,9 0 062
+3 7,9 0 063
+4 7,9 0 064
+5 7,9 0 065
+6 7,9 0 066
+7 7,9 0 067
+8 7,9 0 070
+9 7,9 0 071
+: 4,7 0 072
+; 4,7,2 0 073
+< 7,6 0 074
+= 7,5 0 075
+eq "
+> 7,6 0 076
+? 8,9 0 077
+@ 12,9,1 0 0100
+at "
+A 8,9 0 0101
+B 9,9 0 0102
+C 8,9 0 0103
+D 9,9 0 0104
+E 8,9 0 0105
+F 7,9 0 0106
+G 10,9 0 0107
+H 9,9 0 0110
+I 4,9 0 0111
+J 7,9 0 0112
+K 9,9 0 0113
+L 7,9 0 0114
+M 11,9 0 0115
+N 9,9 0 0116
+O 10,9 0 0117
+P 8,9 0 0120
+Q 10,9 0 0121
+R 9,9 0 0122
+S 9,9 0 0123
+T 8,9 0 0124
+U 9,9 0 0125
+V 8,9 0 0126
+W 10,9 0 0127
+X 8,9 0 0130
+Y 8,9 0 0131
+Z 7,9 0 0132
+[ 4,9,3 0 0133
+lB "
+\ 4,9 0 0134
+rs "
+] 4,9,3 0 0135
+rB "
+^ 7,9 0 0136
+a^ "
+ha "
+_ 7,0,3 0 0137
+` 4,9 0 0140
+oq "
+a 7,7 0 0141
+b 7,9 0 0142
+c 7,7 0 0143
+d 7,9 0 0144
+e 7,7 0 0145
+f 5,9 0 0146
+g 7,7,3 0 0147
+h 7,9 0 0150
+i 3,9 0 0151
+j 3,9,3 0 0152
+k 7,9 0 0153
+l 3,9 0 0154
+m 11,7 0 0155
+n 7,7 0 0156
+o 7,7 0 0157
+p 7,7,3 0 0160
+q 7,7,3 0 0161
+r 5,7 0 0162
+s 7,7 0 0163
+t 5,9 0 0164
+u 7,7 0 0165
+v 8,7 0 0166
+w 11,7 0 0167
+x 7,7 0 0170
+y 8,7,3 0 0171
+z 6,7 0 0172
+{ 5,9,3 0 0173
+lC "
+| 4,9,3 0 0174
+or "
+ba "
+} 5,9,3 0 0175
+rC "
+~ 7,5 0 0176
+a~ "
+ap "
+ti "
+r! 4,7,3 0 0241
+¡ "
+ct 7,8,1 0 0242
+¢ "
+Po 7,9 0 0243
+£ "
+Cs 7,7 0 0244
+¤ "
+Ye 7,9 0 0245
+¥ "
+bb 4,9,2 0 0246
+¦ "
+sc 7,9,3 0 0247
+§ "
+ad 5,9 0 0250
+¨ "
+co 11,9 0 0251
+© "
+Of 6,9 0 0252
+ª "
+Fo 8,6 0 0253
+« "
+no 8,6 0 0254
+¬ "
+- 5,4 0 0255
+hy "
+­ "
+rg 11,9 0 0256
+® "
+a- 4,9 0 0257
+¯ "
+de 5,8 0 0260
+° "
++- 7,7 0 0261
+± "
+S2 4,9 0 0262
+² "
+S3 4,9 0 0263
+³ "
+aa 4,10 0 0264
+´ "
+µ 7,7,3 0 0265
+ps 7,9,3 0 0266
+¶ "
+md 4,5 0 0267
+· "
+ac 4,1,3 0 0270
+¸ "
+S1 4,9 0 0271
+¹ "
+Om 6,9 0 0272
+º "
+Fc 8,6 0 0273
+» "
+14 10,9 0 0274
+¼ "
+12 10,9 0 0275
+½ "
+34 10,9 0 0276
+¾ "
+r? 8,7,3 0 0277
+¿ "
+`A 8,12 0 0300
+À "
+'A 8,12 0 0301
+Á "
+^A 8,12 0 0302
+Â "
+~A 8,12 0 0303
+Ã "
+:A 8,11 0 0304
+Ä "
+oA 8,12 0 0305
+Å "
+AE 13,9 0 0306
+Æ "
+,C 8,9,3 0 0307
+Ç "
+`E 8,12 0 0310
+È "
+'E 8,12 0 0311
+É "
+^E 8,12 0 0312
+Ê "
+:E 8,11 0 0313
+Ë "
+`I 4,12 0 0314
+Ì "
+'I 4,12 0 0315
+Í "
+^I 4,12 0 0316
+Î "
+:I 4,11 0 0317
+Ï "
+-D 9,9 0 0320
+Ð "
+~N 9,12 0 0321
+Ñ "
+`O 10,12 0 0322
+Ò "
+'O 10,12 0 0323
+Ó "
+^O 10,12 0 0324
+Ô "
+~O 10,12 0 0325
+Õ "
+:O 10,11 0 0326
+Ö "
+mu 7,6 0 0327
+× "
+/O 10,9,1 0 0330
+Ø "
+`U 9,12 0 0331
+Ù "
+'U 9,12 0 0332
+Ú "
+^U 9,12 0 0333
+Û "
+:U 9,11 0 0334
+Ü "
+'Y 8,12 0 0335
+Ý "
+TP 8,9 0 0336
+Þ "
+ss 8,9 0 0337
+ß "
+`a 7,10 0 0340
+à "
+'a 7,10 0 0341
+á "
+^a 7,10 0 0342
+â "
+~a 7,10 0 0343
+ã "
+:a 7,9 0 0344
+ä "
+oa 7,11 0 0345
+å "
+ae 11,7 0 0346
+æ "
+,c 7,7,3 0 0347
+ç "
+`e 7,10 0 0350
+è "
+'e 7,10 0 0351
+é "
+^e 7,10 0 0352
+ê "
+:e 7,9 0 0353
+ë "
+`i 3,10 0 0354
+ì "
+'i 3,10 0 0355
+í "
+^i 3,10 0 0356
+î "
+:i 3,9 0 0357
+ï "
+Sd 7,10 0 0360
+ð "
+~n 7,10 0 0361
+ñ "
+`o 7,10 0 0362
+ò "
+'o 7,10 0 0363
+ó "
+^o 7,10 0 0364
+ô "
+~o 7,10 0 0365
+õ "
+:o 7,9 0 0366
+ö "
+di 7,6 0 0367
+÷ "
+/o 7,7 0 0370
+ø "
+`u 7,10 0 0371
+ù "
+'u 7,10 0 0372
+ú "
+^u 7,10 0 0373
+û "
+:u 7,9 0 0374
+ü "
+'y 8,10,3 0 0375
+ý "
+Tp 7,9,3 0 0376
+þ "
+:y 8,9,3 0 0377
+ÿ "
diff --git a/gnu/usr.bin/groff/devX75-12/HBI b/gnu/usr.bin/groff/devX75-12/HBI
new file mode 100644
index 0000000..3014c90
--- /dev/null
+++ b/gnu/usr.bin/groff/devX75-12/HBI
@@ -0,0 +1,306 @@
+name HBI
+spacewidth 4
+charset
+--- 4,1 0 040
+! 4,9 0 041
+" 6,9 0 042
+# 7,8 0 043
+sh "
+$ 7,9,1 0 044
+Do "
+% 13,9 0 045
+& 9,9 0 046
+' 4,9 0 047
+( 5,9,3 0 050
+) 5,9,3 0 051
+* 6,9 0 052
++ 8,6 0 053
+, 3,2,2 0 054
+\- 8,4 0 055
+. 3,2 0 056
+/ 5,9 0 057
+sl "
+0 7,9 0 060
+1 7,9 0 061
+2 7,9 0 062
+3 7,9 0 063
+4 7,9 0 064
+5 7,9 0 065
+6 7,9 0 066
+7 7,9 0 067
+8 7,9 0 070
+9 7,9 0 071
+: 4,7 0 072
+; 4,7,2 0 073
+< 7,6 0 074
+= 7,5 0 075
+eq "
+> 7,6 0 076
+? 8,9 0 077
+@ 11,9,1 0 0100
+at "
+A 8,9 0 0101
+B 9,9 0 0102
+C 8,9 0 0103
+D 9,9 0 0104
+E 8,9 0 0105
+F 7,9 0 0106
+G 9,9 0 0107
+H 10,9 0 0110
+I 5,9 0 0111
+J 7,9 0 0112
+K 9,9 0 0113
+L 7,9 0 0114
+M 12,9 0 0115
+N 10,9 0 0116
+O 9,9 0 0117
+P 8,9 0 0120
+Q 9,9 0 0121
+R 9,9 0 0122
+S 8,9 0 0123
+T 7,9 0 0124
+U 8,9 0 0125
+V 9,9 0 0126
+W 10,9 0 0127
+X 9,9 0 0130
+Y 7,9 0 0131
+Z 7,9 0 0132
+[ 4,9,3 0 0133
+lB "
+\ 5,9 0 0134
+rs "
+] 4,9,3 0 0135
+rB "
+^ 6,9 0 0136
+a^ "
+ha "
+_ 7,0,3 0 0137
+` 4,9 0 0140
+oq "
+a 6,7 0 0141
+b 7,9 0 0142
+c 7,7 0 0143
+d 7,9 0 0144
+e 7,7 0 0145
+f 5,9 0 0146
+g 7,7,3 0 0147
+h 7,9 0 0150
+i 3,9 0 0151
+j 3,9,3 0 0152
+k 7,9 0 0153
+l 3,9 0 0154
+m 11,7 0 0155
+n 7,7 0 0156
+o 7,7 0 0157
+p 7,7,3 0 0160
+q 7,7,3 0 0161
+r 5,7 0 0162
+s 7,7 0 0163
+t 5,9 0 0164
+u 7,7 0 0165
+v 7,7 0 0166
+w 10,7 0 0167
+x 7,7 0 0170
+y 7,7,3 0 0171
+z 6,7 0 0172
+{ 5,9,3 0 0173
+lC "
+| 4,9,3 0 0174
+or "
+ba "
+} 5,9,3 0 0175
+rC "
+~ 7,5 0 0176
+a~ "
+ap "
+ti "
+r! 4,7,3 0 0241
+¡ "
+ct 7,8,1 0 0242
+¢ "
+Po 7,9 0 0243
+£ "
+Cs 7,7 0 0244
+¤ "
+Ye 7,9 0 0245
+¥ "
+bb 4,9,2 0 0246
+¦ "
+sc 7,9,3 0 0247
+§ "
+ad 5,9 0 0250
+¨ "
+co 11,9 0 0251
+© "
+Of 6,9 0 0252
+ª "
+Fo 10,6 0 0253
+« "
+no 8,5 0 0254
+¬ "
+- 5,4 0 0255
+hy "
+­ "
+rg 11,9 0 0256
+® "
+a- 4,9 0 0257
+¯ "
+de 5,8 0 0260
+° "
++- 8,7 0 0261
+± "
+S2 4,9 0 0262
+² "
+S3 4,9 0 0263
+³ "
+aa 4,9 0 0264
+´ "
+µ 7,7,3 0 0265
+ps 7,9,3 0 0266
+¶ "
+md 4,5 0 0267
+· "
+ac 4,1,3 0 0270
+¸ "
+S1 4,9 0 0271
+¹ "
+Om 6,9 0 0272
+º "
+Fc 10,6 0 0273
+» "
+14 10,9 0 0274
+¼ "
+12 10,9 0 0275
+½ "
+34 10,9 0 0276
+¾ "
+r? 7,7,2 0 0277
+¿ "
+`A 8,12 0 0300
+À "
+'A 8,12 0 0301
+Á "
+^A 8,12 0 0302
+Â "
+~A 8,12 0 0303
+Ã "
+:A 8,11 0 0304
+Ä "
+oA 8,12 0 0305
+Å "
+AE 11,9 0 0306
+Æ "
+,C 8,9,3 0 0307
+Ç "
+`E 8,12 0 0310
+È "
+'E 8,12 0 0311
+É "
+^E 8,12 0 0312
+Ê "
+:E 8,11 0 0313
+Ë "
+`I 5,12 0 0314
+Ì "
+'I 5,12 0 0315
+Í "
+^I 5,12 0 0316
+Î "
+:I 5,11 0 0317
+Ï "
+-D 9,9 0 0320
+Ð "
+~N 10,12 0 0321
+Ñ "
+`O 9,12 0 0322
+Ò "
+'O 9,12 0 0323
+Ó "
+^O 9,12 0 0324
+Ô "
+~O 9,12 0 0325
+Õ "
+:O 9,11 0 0326
+Ö "
+mu 8,6 0 0327
+× "
+/O 9,9 0 0330
+Ø "
+`U 8,12 0 0331
+Ù "
+'U 8,12 0 0332
+Ú "
+^U 8,12 0 0333
+Û "
+:U 8,11 0 0334
+Ü "
+'Y 7,12 0 0335
+Ý "
+TP 8,9 0 0336
+Þ "
+ss 7,9 0 0337
+ß "
+`a 6,10 0 0340
+à "
+'a 6,10 0 0341
+á "
+^a 6,10 0 0342
+â "
+~a 6,10 0 0343
+ã "
+:a 6,9 0 0344
+ä "
+oa 6,10 0 0345
+å "
+ae 10,7 0 0346
+æ "
+,c 7,7,3 0 0347
+ç "
+`e 7,10 0 0350
+è "
+'e 7,10 0 0351
+é "
+^e 7,10 0 0352
+ê "
+:e 7,9 0 0353
+ë "
+`i 3,10 0 0354
+ì "
+'i 3,10 0 0355
+í "
+^i 3,10 0 0356
+î "
+:i 3,9 0 0357
+ï "
+Sd 7,10 0 0360
+ð "
+~n 7,10 0 0361
+ñ "
+`o 7,10 0 0362
+ò "
+'o 7,10 0 0363
+ó "
+^o 7,10 0 0364
+ô "
+~o 7,10 0 0365
+õ "
+:o 7,9 0 0366
+ö "
+di 8,6 0 0367
+÷ "
+/o 7,8 0 0370
+ø "
+`u 7,10 0 0371
+ù "
+'u 7,10 0 0372
+ú "
+^u 7,10 0 0373
+û "
+:u 7,9 0 0374
+ü "
+'y 7,10,3 0 0375
+ý "
+Tp 7,9,3 0 0376
+þ "
+:y 7,9,3 0 0377
+ÿ "
diff --git a/gnu/usr.bin/groff/devX75-12/HI b/gnu/usr.bin/groff/devX75-12/HI
new file mode 100644
index 0000000..587e145
--- /dev/null
+++ b/gnu/usr.bin/groff/devX75-12/HI
@@ -0,0 +1,306 @@
+name HI
+spacewidth 4
+charset
+--- 4,1 0 040
+! 3,9 0 041
+" 5,9 0 042
+# 7,8 0 043
+sh "
+$ 7,9,1 0 044
+Do "
+% 11,9 0 045
+& 9,9 0 046
+' 3,9 0 047
+( 4,9,3 0 050
+) 4,9,3 0 051
+* 5,9 0 052
++ 7,6 0 053
+, 3,1,2 0 054
+\- 8,4 0 055
+. 3,1 0 056
+/ 4,9 0 057
+sl "
+0 7,9 0 060
+1 7,9 0 061
+2 7,9 0 062
+3 7,9 0 063
+4 7,9 0 064
+5 7,9 0 065
+6 7,9 0 066
+7 7,9 0 067
+8 7,9 0 070
+9 7,9 0 071
+: 3,6 0 072
+; 3,6,2 0 073
+< 8,6 0 074
+= 7,5 0 075
+eq "
+> 8,6 0 076
+? 7,9 0 077
+@ 12,9,1 0 0100
+at "
+A 9,9 0 0101
+B 8,9 0 0102
+C 8,9 0 0103
+D 9,9 0 0104
+E 8,9 0 0105
+F 8,9 0 0106
+G 8,9 0 0107
+H 10,9 0 0110
+I 4,9 0 0111
+J 8,9 0 0112
+K 8,9 0 0113
+L 7,9 0 0114
+M 12,9 0 0115
+N 10,9 0 0116
+O 9,9 0 0117
+P 8,9 0 0120
+Q 9,9 0 0121
+R 8,9 0 0122
+S 8,9 0 0123
+T 7,9 0 0124
+U 9,9 0 0125
+V 8,9 0 0126
+W 11,9 0 0127
+X 9,9 0 0130
+Y 8,9 0 0131
+Z 9,9 0 0132
+[ 4,9,3 0 0133
+lB "
+\ 4,9 0 0134
+rs "
+] 4,9,3 0 0135
+rB "
+^ 6,8 0 0136
+a^ "
+ha "
+_ 7,0,3 0 0137
+` 3,9 0 0140
+oq "
+a 7,7 0 0141
+b 7,9 0 0142
+c 6,7 0 0143
+d 7,9 0 0144
+e 6,7 0 0145
+f 3,9 0 0146
+g 7,7,3 0 0147
+h 7,9 0 0150
+i 3,9 0 0151
+j 3,9,3 0 0152
+k 6,9 0 0153
+l 3,9 0 0154
+m 9,7 0 0155
+n 7,7 0 0156
+o 7,7 0 0157
+p 7,7,3 0 0160
+q 7,7,3 0 0161
+r 4,7 0 0162
+s 6,7 0 0163
+t 4,9 0 0164
+u 7,7 0 0165
+v 6,7 0 0166
+w 9,7 0 0167
+x 6,7 0 0170
+y 6,7,3 0 0171
+z 6,7 0 0172
+{ 5,9,3 0 0173
+lC "
+| 4,9,3 0 0174
+or "
+ba "
+} 5,9,3 0 0175
+rC "
+~ 7,5 0 0176
+a~ "
+ap "
+ti "
+r! 4,6,3 0 0241
+¡ "
+ct 8,8,1 0 0242
+¢ "
+Po 8,9 0 0243
+£ "
+Cs 7,7 0 0244
+¤ "
+Ye 7,9 0 0245
+¥ "
+bb 4,9,2 0 0246
+¦ "
+sc 7,9,3 0 0247
+§ "
+ad 3,9 0 0250
+¨ "
+co 11,9 0 0251
+© "
+Of 5,9 0 0252
+ª "
+Fo 7,6 0 0253
+« "
+no 8,6 0 0254
+¬ "
+- 5,4 0 0255
+hy "
+­ "
+rg 11,9 0 0256
+® "
+a- 4,9 0 0257
+¯ "
+de 5,8 0 0260
+° "
++- 7,7 0 0261
+± "
+S2 4,8 0 0262
+² "
+S3 4,8 0 0263
+³ "
+aa 2,10 0 0264
+´ "
+µ 7,7,3 0 0265
+ps 8,9,3 0 0266
+¶ "
+md 3,4 0 0267
+· "
+ac 3,1,3 0 0270
+¸ "
+S1 4,8 0 0271
+¹ "
+Om 5,9 0 0272
+º "
+Fc 7,6 0 0273
+» "
+14 10,9 0 0274
+¼ "
+12 10,9 0 0275
+½ "
+34 10,9 0 0276
+¾ "
+r? 7,6,3 0 0277
+¿ "
+`A 9,12 0 0300
+À "
+'A 9,12 0 0301
+Á "
+^A 9,12 0 0302
+Â "
+~A 9,12 0 0303
+Ã "
+:A 9,11 0 0304
+Ä "
+oA 9,12 0 0305
+Å "
+AE 11,9 0 0306
+Æ "
+,C 8,9,3 0 0307
+Ç "
+`E 8,12 0 0310
+È "
+'E 8,12 0 0311
+É "
+^E 8,12 0 0312
+Ê "
+:E 8,11 0 0313
+Ë "
+`I 4,12 0 0314
+Ì "
+'I 4,12 0 0315
+Í "
+^I 4,12 0 0316
+Î "
+:I 4,11 0 0317
+Ï "
+-D 9,9 0 0320
+Ð "
+~N 10,12 0 0321
+Ñ "
+`O 9,12 0 0322
+Ò "
+'O 9,12 0 0323
+Ó "
+^O 9,12 0 0324
+Ô "
+~O 9,12 0 0325
+Õ "
+:O 9,11 0 0326
+Ö "
+mu 7,6 0 0327
+× "
+/O 10,9 0 0330
+Ø "
+`U 9,12 0 0331
+Ù "
+'U 9,12 0 0332
+Ú "
+^U 9,12 0 0333
+Û "
+:U 9,11 0 0334
+Ü "
+'Y 8,12 0 0335
+Ý "
+TP 8,9 0 0336
+Þ "
+ss 7,9 0 0337
+ß "
+`a 7,10 0 0340
+à "
+'a 7,10 0 0341
+á "
+^a 7,10 0 0342
+â "
+~a 7,10 0 0343
+ã "
+:a 7,9 0 0344
+ä "
+oa 7,10 0 0345
+å "
+ae 11,7 0 0346
+æ "
+,c 6,7,3 0 0347
+ç "
+`e 6,10 0 0350
+è "
+'e 6,10 0 0351
+é "
+^e 6,10 0 0352
+ê "
+:e 6,9 0 0353
+ë "
+`i 3,10 0 0354
+ì "
+'i 3,10 0 0355
+í "
+^i 3,10 0 0356
+î "
+:i 3,9 0 0357
+ï "
+Sd 7,11 0 0360
+ð "
+~n 7,10 0 0361
+ñ "
+`o 7,10 0 0362
+ò "
+'o 7,10 0 0363
+ó "
+^o 7,10 0 0364
+ô "
+~o 7,10 0 0365
+õ "
+:o 7,9 0 0366
+ö "
+di 7,6 0 0367
+÷ "
+/o 7,7 0 0370
+ø "
+`u 7,10 0 0371
+ù "
+'u 7,10 0 0372
+ú "
+^u 7,10 0 0373
+û "
+:u 7,9 0 0374
+ü "
+'y 6,10,3 0 0375
+ý "
+Tp 7,9,3 0 0376
+þ "
+:y 7,9,3 0 0377
+ÿ "
diff --git a/gnu/usr.bin/groff/devX75-12/HR b/gnu/usr.bin/groff/devX75-12/HR
new file mode 100644
index 0000000..86958ed
--- /dev/null
+++ b/gnu/usr.bin/groff/devX75-12/HR
@@ -0,0 +1,306 @@
+name HR
+spacewidth 4
+charset
+--- 4,1 0 040
+! 3,9 0 041
+" 5,9 0 042
+# 7,8 0 043
+sh "
+$ 6,9,2 0 044
+Do "
+% 11,9 0 045
+& 9,9 0 046
+' 3,9 0 047
+( 4,9,3 0 050
+) 4,9,3 0 051
+* 5,9 0 052
++ 7,6 0 053
+, 4,1,2 0 054
+\- 8,4 0 055
+. 3,1 0 056
+/ 4,9 0 057
+sl "
+0 7,9 0 060
+1 7,9 0 061
+2 7,9 0 062
+3 7,9 0 063
+4 7,9 0 064
+5 7,9 0 065
+6 7,9 0 066
+7 7,9 0 067
+8 7,9 0 070
+9 7,9 0 071
+: 3,6 0 072
+; 3,6,2 0 073
+< 7,6 0 074
+= 7,5 0 075
+eq "
+> 7,6 0 076
+? 7,9 0 077
+@ 12,9,1 0 0100
+at "
+A 9,9 0 0101
+B 8,9 0 0102
+C 9,9 0 0103
+D 9,9 0 0104
+E 8,9 0 0105
+F 8,9 0 0106
+G 9,9 0 0107
+H 9,9 0 0110
+I 3,9 0 0111
+J 7,9 0 0112
+K 8,9 0 0113
+L 7,9 0 0114
+M 11,9 0 0115
+N 9,9 0 0116
+O 10,9 0 0117
+P 8,9 0 0120
+Q 10,9 0 0121
+R 8,9 0 0122
+S 8,9 0 0123
+T 7,9 0 0124
+U 8,9 0 0125
+V 9,9 0 0126
+W 11,9 0 0127
+X 9,9 0 0130
+Y 9,9 0 0131
+Z 9,9 0 0132
+[ 3,9,3 0 0133
+lB "
+\ 4,9 0 0134
+rs "
+] 3,9,3 0 0135
+rB "
+^ 6,8 0 0136
+a^ "
+ha "
+_ 7,0,2 0 0137
+` 3,9 0 0140
+oq "
+a 7,7 0 0141
+b 7,9 0 0142
+c 7,7 0 0143
+d 7,9 0 0144
+e 7,7 0 0145
+f 3,9 0 0146
+g 7,7,3 0 0147
+h 7,9 0 0150
+i 3,9 0 0151
+j 3,9,3 0 0152
+k 6,9 0 0153
+l 3,9 0 0154
+m 9,7 0 0155
+n 7,7 0 0156
+o 7,7 0 0157
+p 7,7,3 0 0160
+q 7,7,3 0 0161
+r 4,7 0 0162
+s 6,7 0 0163
+t 4,9 0 0164
+u 7,7 0 0165
+v 7,7 0 0166
+w 9,7 0 0167
+x 6,7 0 0170
+y 7,7,3 0 0171
+z 6,7 0 0172
+{ 4,9,3 0 0173
+lC "
+| 3,9,3 0 0174
+or "
+ba "
+} 4,9,3 0 0175
+rC "
+~ 7,5 0 0176
+a~ "
+ap "
+ti "
+r! 3,7,3 0 0241
+¡ "
+ct 7,8,1 0 0242
+¢ "
+Po 7,9 0 0243
+£ "
+Cs 7,7 0 0244
+¤ "
+Ye 7,9 0 0245
+¥ "
+bb 3,9,2 0 0246
+¦ "
+sc 6,9,3 0 0247
+§ "
+ad 3,9 0 0250
+¨ "
+co 11,9 0 0251
+© "
+Of 5,9 0 0252
+ª "
+Fo 7,6 0 0253
+« "
+no 8,6 0 0254
+¬ "
+- 5,4 0 0255
+hy "
+­ "
+rg 11,9 0 0256
+® "
+a- 4,9 0 0257
+¯ "
+de 5,8 0 0260
+° "
++- 7,7 0 0261
+± "
+S2 4,8 0 0262
+² "
+S3 4,8 0 0263
+³ "
+aa 2,10 0 0264
+´ "
+µ 7,7,3 0 0265
+ps 7,9,3 0 0266
+¶ "
+md 3,4 0 0267
+· "
+ac 3,1,3 0 0270
+¸ "
+S1 4,8 0 0271
+¹ "
+Om 5,9 0 0272
+º "
+Fc 7,6 0 0273
+» "
+14 10,9 0 0274
+¼ "
+12 10,9 0 0275
+½ "
+34 10,9 0 0276
+¾ "
+r? 7,6,3 0 0277
+¿ "
+`A 9,12 0 0300
+À "
+'A 9,12 0 0301
+Á "
+^A 9,12 0 0302
+Â "
+~A 9,12 0 0303
+Ã "
+:A 9,11 0 0304
+Ä "
+oA 9,12 0 0305
+Å "
+AE 11,9 0 0306
+Æ "
+,C 9,9,3 0 0307
+Ç "
+`E 8,12 0 0310
+È "
+'E 8,12 0 0311
+É "
+^E 8,12 0 0312
+Ê "
+:E 8,11 0 0313
+Ë "
+`I 3,12 0 0314
+Ì "
+'I 3,12 0 0315
+Í "
+^I 3,12 0 0316
+Î "
+:I 3,11 0 0317
+Ï "
+-D 9,9 0 0320
+Ð "
+~N 9,12 0 0321
+Ñ "
+`O 10,12 0 0322
+Ò "
+'O 10,12 0 0323
+Ó "
+^O 10,12 0 0324
+Ô "
+~O 10,12 0 0325
+Õ "
+:O 10,11 0 0326
+Ö "
+mu 7,6 0 0327
+× "
+/O 10,10,1 0 0330
+Ø "
+`U 8,12 0 0331
+Ù "
+'U 8,12 0 0332
+Ú "
+^U 8,12 0 0333
+Û "
+:U 8,11 0 0334
+Ü "
+'Y 9,12 0 0335
+Ý "
+TP 8,9 0 0336
+Þ "
+ss 7,9 0 0337
+ß "
+`a 7,10 0 0340
+à "
+'a 7,10 0 0341
+á "
+^a 7,10 0 0342
+â "
+~a 7,10 0 0343
+ã "
+:a 7,9 0 0344
+ä "
+oa 7,10 0 0345
+å "
+ae 11,7 0 0346
+æ "
+,c 7,7,3 0 0347
+ç "
+`e 7,10 0 0350
+è "
+'e 7,10 0 0351
+é "
+^e 7,10 0 0352
+ê "
+:e 7,9 0 0353
+ë "
+`i 3,10 0 0354
+ì "
+'i 3,10 0 0355
+í "
+^i 3,10 0 0356
+î "
+:i 3,9 0 0357
+ï "
+Sd 7,10 0 0360
+ð "
+~n 7,10 0 0361
+ñ "
+`o 7,10 0 0362
+ò "
+'o 7,10 0 0363
+ó "
+^o 7,10 0 0364
+ô "
+~o 7,10 0 0365
+õ "
+:o 7,9 0 0366
+ö "
+di 7,6 0 0367
+÷ "
+/o 7,7 0 0370
+ø "
+`u 7,10 0 0371
+ù "
+'u 7,10 0 0372
+ú "
+^u 7,10 0 0373
+û "
+:u 7,9 0 0374
+ü "
+'y 7,10,3 0 0375
+ý "
+Tp 7,9,3 0 0376
+þ "
+:y 7,9,3 0 0377
+ÿ "
diff --git a/gnu/usr.bin/groff/devX75-12/Makefile b/gnu/usr.bin/groff/devX75-12/Makefile
new file mode 100644
index 0000000..705e3ea
--- /dev/null
+++ b/gnu/usr.bin/groff/devX75-12/Makefile
@@ -0,0 +1,10 @@
+# Makefile for devX75-12
+
+DEVICE= X75-12
+FONTFILES= CB CBI CI CR HB HBI HI HR NB NBI NI NR S TB TBI TI TR DESC
+
+NOOBJ= noobj
+
+clean cleandir:
+
+.include "../Makefile.dev"
diff --git a/gnu/usr.bin/groff/devX75-12/Makefile.sub b/gnu/usr.bin/groff/devX75-12/Makefile.sub
new file mode 100644
index 0000000..37f4b7c
--- /dev/null
+++ b/gnu/usr.bin/groff/devX75-12/Makefile.sub
@@ -0,0 +1,2 @@
+DEV=X75-12
+DEVFILES=DESC TR TI TB TBI CR CI CB CBI HR HI HB HBI NR NI NB NBI S
diff --git a/gnu/usr.bin/groff/devX75-12/NB b/gnu/usr.bin/groff/devX75-12/NB
new file mode 100644
index 0000000..5fea017
--- /dev/null
+++ b/gnu/usr.bin/groff/devX75-12/NB
@@ -0,0 +1,306 @@
+name NB
+spacewidth 4
+charset
+--- 4,1 0 040
+! 4,9 0 041
+" 6,9 0 042
+# 8,9 0 043
+sh "
+$ 7,10,1 0 044
+Do "
+% 13,9 0 045
+& 11,9 0 046
+' 3,9 0 047
+( 5,9,2 0 050
+) 5,9,2 0 051
+* 6,9 0 052
++ 8,7 0 053
+, 4,2,2 0 054
+\- 7,4 0 055
+. 4,2 0 056
+/ 4,9 0 057
+sl "
+0 7,9 0 060
+1 5,9 0 061
+2 7,9 0 062
+3 7,9 0 063
+4 7,9 0 064
+5 7,9 0 065
+6 7,9 0 066
+7 7,9 0 067
+8 7,9 0 070
+9 7,9 0 071
+: 4,6 0 072
+; 4,6,2 0 073
+< 7,6 0 074
+= 7,5 0 075
+eq "
+> 7,6 0 076
+? 7,9 0 077
+@ 11,9 0 0100
+at "
+A 11,9 0 0101
+B 9,9 0 0102
+C 9,9 0 0103
+D 10,9 0 0104
+E 9,9 0 0105
+F 9,9 0 0106
+G 10,9 0 0107
+H 11,9 0 0110
+I 5,9 0 0111
+J 8,9 0 0112
+K 10,9 0 0113
+L 9,9 0 0114
+M 12,9 0 0115
+N 11,9 0 0116
+O 10,9 0 0117
+P 9,9 0 0120
+Q 10,9,2 0 0121
+R 10,9 0 0122
+S 8,9 0 0123
+T 9,9 0 0124
+U 10,9 0 0125
+V 11,9 0 0126
+W 14,9 0 0127
+X 10,9 0 0130
+Y 9,9 0 0131
+Z 9,9 0 0132
+[ 5,9,2 0 0133
+lB "
+\ 6,9 0 0134
+rs "
+] 5,9,2 0 0135
+rB "
+^ 6,9 0 0136
+a^ "
+ha "
+_ 7,0,2 0 0137
+` 3,9 0 0140
+oq "
+a 8,6 0 0141
+b 8,9 0 0142
+c 7,6 0 0143
+d 9,9 0 0144
+e 7,6 0 0145
+f 5,9 0 0146
+g 7,7,3 0 0147
+h 9,9 0 0150
+i 5,9 0 0151
+j 3,9,3 0 0152
+k 8,9 0 0153
+l 5,9 0 0154
+m 13,6 0 0155
+n 9,6 0 0156
+o 8,6 0 0157
+p 8,6,3 0 0160
+q 8,6,3 0 0161
+r 6,6 0 0162
+s 6,6 0 0163
+t 5,9 0 0164
+u 9,6 0 0165
+v 7,6 0 0166
+w 11,6 0 0167
+x 8,6 0 0170
+y 7,6,3 0 0171
+z 7,6 0 0172
+{ 5,9,2 0 0173
+lC "
+| 8,9 0 0174
+or "
+ba "
+} 5,9,2 0 0175
+rC "
+~ 7,5 0 0176
+a~ "
+ap "
+ti "
+r! 4,6,3 0 0241
+¡ "
+ct 7,7,1 0 0242
+¢ "
+Po 8,9 0 0243
+£ "
+Cs 8,8 0 0244
+¤ "
+Ye 9,9 0 0245
+¥ "
+bb 8,9 0 0246
+¦ "
+sc 6,9,1 0 0247
+§ "
+ad 5,9 0 0250
+¨ "
+co 10,9 0 0251
+© "
+Of 6,9 0 0252
+ª "
+Fo 8,6 0 0253
+« "
+no 7,5 0 0254
+¬ "
+- 4,4 0 0255
+hy "
+­ "
+rg 11,9 0 0256
+® "
+a- 6,8 0 0257
+¯ "
+de 5,9 0 0260
+° "
++- 8,7 0 0261
+± "
+S2 4,9 0 0262
+² "
+S3 4,9 0 0263
+³ "
+aa 5,9 0 0264
+´ "
+µ 9,6,3 0 0265
+ps 10,9 0 0266
+¶ "
+md 3,5 0 0267
+· "
+ac 5,0,3 0 0270
+¸ "
+S1 4,9 0 0271
+¹ "
+Om 6,9 0 0272
+º "
+Fc 8,6 0 0273
+» "
+14 10,9 0 0274
+¼ "
+12 10,9 0 0275
+½ "
+34 10,9 0 0276
+¾ "
+r? 7,6,3 0 0277
+¿ "
+`A 11,12 0 0300
+À "
+'A 11,12 0 0301
+Á "
+^A 11,12 0 0302
+Â "
+~A 11,12 0 0303
+Ã "
+:A 11,12 0 0304
+Ä "
+oA 11,12 0 0305
+Å "
+AE 14,9 0 0306
+Æ "
+,C 9,9,3 0 0307
+Ç "
+`E 9,12 0 0310
+È "
+'E 9,12 0 0311
+É "
+^E 9,12 0 0312
+Ê "
+:E 9,12 0 0313
+Ë "
+`I 5,12 0 0314
+Ì "
+'I 5,12 0 0315
+Í "
+^I 5,12 0 0316
+Î "
+:I 5,12 0 0317
+Ï "
+-D 10,9 0 0320
+Ð "
+~N 11,12 0 0321
+Ñ "
+`O 10,12 0 0322
+Ò "
+'O 10,12 0 0323
+Ó "
+^O 10,12 0 0324
+Ô "
+~O 10,12 0 0325
+Õ "
+:O 10,12 0 0326
+Ö "
+mu 8,7 0 0327
+× "
+/O 10,9 0 0330
+Ø "
+`U 10,12 0 0331
+Ù "
+'U 10,12 0 0332
+Ú "
+^U 10,12 0 0333
+Û "
+:U 10,12 0 0334
+Ü "
+'Y 9,12 0 0335
+Ý "
+TP 9,9 0 0336
+Þ "
+ss 8,9 0 0337
+ß "
+`a 8,9 0 0340
+à "
+'a 8,9 0 0341
+á "
+^a 8,9 0 0342
+â "
+~a 8,9 0 0343
+ã "
+:a 8,9 0 0344
+ä "
+oa 8,9 0 0345
+å "
+ae 11,6 0 0346
+æ "
+,c 7,6,3 0 0347
+ç "
+`e 7,9 0 0350
+è "
+'e 7,9 0 0351
+é "
+^e 7,9 0 0352
+ê "
+:e 7,9 0 0353
+ë "
+`i 5,9 0 0354
+ì "
+'i 5,9 0 0355
+í "
+^i 5,9 0 0356
+î "
+:i 5,9 0 0357
+ï "
+Sd 8,9 0 0360
+ð "
+~n 9,9 0 0361
+ñ "
+`o 8,9 0 0362
+ò "
+'o 8,9 0 0363
+ó "
+^o 8,9 0 0364
+ô "
+~o 8,9 0 0365
+õ "
+:o 8,9 0 0366
+ö "
+di 8,7 0 0367
+÷ "
+/o 8,7,1 0 0370
+ø "
+`u 9,9 0 0371
+ù "
+'u 9,9 0 0372
+ú "
+^u 9,9 0 0373
+û "
+:u 9,9 0 0374
+ü "
+'y 7,9,3 0 0375
+ý "
+Tp 8,9,3 0 0376
+þ "
+:y 7,9,3 0 0377
+ÿ "
diff --git a/gnu/usr.bin/groff/devX75-12/NBI b/gnu/usr.bin/groff/devX75-12/NBI
new file mode 100644
index 0000000..0da124a
--- /dev/null
+++ b/gnu/usr.bin/groff/devX75-12/NBI
@@ -0,0 +1,306 @@
+name NBI
+spacewidth 4
+charset
+--- 4,1 0 040
+! 5,9 0 041
+" 6,9 0 042
+# 8,8 0 043
+sh "
+$ 7,10,1 0 044
+Do "
+% 12,9 0 045
+& 12,9 0 046
+' 3,9 0 047
+( 5,9,2 0 050
+) 5,9,2 0 051
+* 6,9 0 052
++ 8,7 0 053
+, 3,2,2 0 054
+\- 8,4 0 055
+. 3,2 0 056
+/ 6,9 0 057
+sl "
+0 7,9 0 060
+1 7,9 0 061
+2 7,9 0 062
+3 7,9 0 063
+4 7,9 0 064
+5 7,9 0 065
+6 7,9 0 066
+7 7,9 0 067
+8 7,9 0 070
+9 7,9 0 071
+: 4,6 0 072
+; 4,6,2 0 073
+< 7,7 0 074
+= 7,5 0 075
+eq "
+> 7,7 0 076
+? 6,9 0 077
+@ 11,9 0 0100
+at "
+A 10,9 0 0101
+B 9,9 0 0102
+C 9,9 0 0103
+D 10,9 0 0104
+E 9,9 0 0105
+F 8,9 0 0106
+G 10,9 0 0107
+H 11,9 0 0110
+I 6,9 0 0111
+J 8,9 0 0112
+K 10,9 0 0113
+L 9,9 0 0114
+M 14,9 0 0115
+N 11,9 0 0116
+O 10,9 0 0117
+P 9,9 0 0120
+Q 10,9,2 0 0121
+R 10,9 0 0122
+S 8,9 0 0123
+T 9,9 0 0124
+U 9,9 0 0125
+V 10,9 0 0126
+W 13,9 0 0127
+X 11,9 0 0130
+Y 9,9 0 0131
+Z 9,9 0 0132
+[ 6,9,2 0 0133
+lB "
+\ 6,9 0 0134
+rs "
+] 6,9,2 0 0135
+rB "
+^ 8,9 0 0136
+a^ "
+ha "
+_ 8,0,2 0 0137
+` 3,9 0 0140
+oq "
+a 8,6 0 0141
+b 7,9 0 0142
+c 6,6 0 0143
+d 8,9 0 0144
+e 7,6 0 0145
+f 5,9,3 0 0146
+g 7,8,3 0 0147
+h 8,9 0 0150
+i 4,9 0 0151
+j 4,9,3 0 0152
+k 8,9 0 0153
+l 4,9 0 0154
+m 12,6 0 0155
+n 8,6 0 0156
+o 7,6 0 0157
+p 8,6,3 0 0160
+q 8,6,3 0 0161
+r 6,6 0 0162
+s 7,6 0 0163
+t 5,8 0 0164
+u 8,6 0 0165
+v 7,6 0 0166
+w 11,6 0 0167
+x 7,6 0 0170
+y 6,6,3 0 0171
+z 7,6 0 0172
+{ 6,9,2 0 0173
+lC "
+| 8,9 0 0174
+or "
+ba "
+} 6,9,2 0 0175
+rC "
+~ 8,5 0 0176
+a~ "
+ap "
+ti "
+r! 5,6,3 0 0241
+¡ "
+ct 7,7,1 0 0242
+¢ "
+Po 9,9 0 0243
+£ "
+Cs 8,8 0 0244
+¤ "
+Ye 10,9 0 0245
+¥ "
+bb 8,9 0 0246
+¦ "
+sc 6,9,2 0 0247
+§ "
+ad 4,9 0 0250
+¨ "
+co 10,9 0 0251
+© "
+Of 6,9 0 0252
+ª "
+Fo 9,6 0 0253
+« "
+no 7,5 0 0254
+¬ "
+- 5,4 0 0255
+hy "
+­ "
+rg 10,9 0 0256
+® "
+a- 5,8 0 0257
+¯ "
+de 5,9 0 0260
+° "
++- 8,7 0 0261
+± "
+S2 4,9 0 0262
+² "
+S3 4,9 0 0263
+³ "
+aa 4,9 0 0264
+´ "
+µ 8,6,3 0 0265
+ps 8,9 0 0266
+¶ "
+md 5,5 0 0267
+· "
+ac 4,0,3 0 0270
+¸ "
+S1 4,9 0 0271
+¹ "
+Om 5,9 0 0272
+º "
+Fc 9,6 0 0273
+» "
+14 10,9 0 0274
+¼ "
+12 10,9 0 0275
+½ "
+34 10,9 0 0276
+¾ "
+r? 6,6,3 0 0277
+¿ "
+`A 10,12 0 0300
+À "
+'A 10,12 0 0301
+Á "
+^A 10,12 0 0302
+Â "
+~A 10,12 0 0303
+Ã "
+:A 10,12 0 0304
+Ä "
+oA 10,12 0 0305
+Å "
+AE 12,9 0 0306
+Æ "
+,C 9,9,3 0 0307
+Ç "
+`E 9,12 0 0310
+È "
+'E 9,12 0 0311
+É "
+^E 9,12 0 0312
+Ê "
+:E 9,12 0 0313
+Ë "
+`I 6,12 0 0314
+Ì "
+'I 6,12 0 0315
+Í "
+^I 6,12 0 0316
+Î "
+:I 6,12 0 0317
+Ï "
+-D 10,9 0 0320
+Ð "
+~N 11,12 0 0321
+Ñ "
+`O 10,12 0 0322
+Ò "
+'O 10,12 0 0323
+Ó "
+^O 10,12 0 0324
+Ô "
+~O 10,12 0 0325
+Õ "
+:O 10,12 0 0326
+Ö "
+mu 8,7 0 0327
+× "
+/O 10,9 0 0330
+Ø "
+`U 9,12 0 0331
+Ù "
+'U 9,12 0 0332
+Ú "
+^U 9,12 0 0333
+Û "
+:U 9,12 0 0334
+Ü "
+'Y 9,12 0 0335
+Ý "
+TP 9,9 0 0336
+Þ "
+ss 9,9,2 0 0337
+ß "
+`a 8,9 0 0340
+à "
+'a 8,9 0 0341
+á "
+^a 8,10 0 0342
+â "
+~a 8,9 0 0343
+ã "
+:a 8,9 0 0344
+ä "
+oa 8,10 0 0345
+å "
+ae 11,6 0 0346
+æ "
+,c 6,6,3 0 0347
+ç "
+`e 7,9 0 0350
+è "
+'e 7,9 0 0351
+é "
+^e 7,10 0 0352
+ê "
+:e 7,9 0 0353
+ë "
+`i 4,9 0 0354
+ì "
+'i 4,9 0 0355
+í "
+^i 4,10 0 0356
+î "
+:i 4,9 0 0357
+ï "
+Sd 7,9 0 0360
+ð "
+~n 8,9 0 0361
+ñ "
+`o 7,9 0 0362
+ò "
+'o 7,9 0 0363
+ó "
+^o 7,10 0 0364
+ô "
+~o 7,9 0 0365
+õ "
+:o 7,9 0 0366
+ö "
+di 8,7 0 0367
+÷ "
+/o 7,6 0 0370
+ø "
+`u 8,9 0 0371
+ù "
+'u 8,9 0 0372
+ú "
+^u 8,10 0 0373
+û "
+:u 8,9 0 0374
+ü "
+'y 6,9,3 0 0375
+ý "
+Tp 8,9,3 0 0376
+þ "
+:y 6,9,3 0 0377
+ÿ "
diff --git a/gnu/usr.bin/groff/devX75-12/NI b/gnu/usr.bin/groff/devX75-12/NI
new file mode 100644
index 0000000..05ee8cd
--- /dev/null
+++ b/gnu/usr.bin/groff/devX75-12/NI
@@ -0,0 +1,306 @@
+name NI
+spacewidth 3
+charset
+--- 3,1 0 040
+! 4,9 0 041
+" 6,9 0 042
+# 8,8 0 043
+sh "
+$ 6,10,1 0 044
+Do "
+% 10,9 0 045
+& 10,9 0 046
+' 3,9 0 047
+( 5,9,2 0 050
+) 5,9,2 0 051
+* 7,9 0 052
++ 8,7 0 053
+, 2,2,1 0 054
+\- 7,4 0 055
+. 2,2 0 056
+/ 8,9,1 0 057
+sl "
+0 6,9 0 060
+1 6,9 0 061
+2 6,9 0 062
+3 6,9 0 063
+4 6,9 0 064
+5 6,9 0 065
+6 6,9 0 066
+7 6,9 0 067
+8 6,9 0 070
+9 6,9 0 071
+: 3,6 0 072
+; 3,6,1 0 073
+< 7,6 0 074
+= 7,5 0 075
+eq "
+> 7,6 0 076
+? 5,9 0 077
+@ 11,9 0 0100
+at "
+A 8,9 0 0101
+B 8,9 0 0102
+C 9,9 0 0103
+D 10,9 0 0104
+E 9,9 0 0105
+F 9,9 0 0106
+G 9,9 0 0107
+H 10,9 0 0110
+I 5,9 0 0111
+J 7,9 0 0112
+K 9,9 0 0113
+L 8,9 0 0114
+M 13,9 0 0115
+N 11,9 0 0116
+O 9,9 0 0117
+P 8,9 0 0120
+Q 9,9,2 0 0121
+R 10,9 0 0122
+S 9,9 0 0123
+T 8,9 0 0124
+U 8,9 0 0125
+V 9,9 0 0126
+W 13,9 0 0127
+X 10,9 0 0130
+Y 8,9 0 0131
+Z 9,9 0 0132
+[ 6,9,2 0 0133
+lB "
+\ 8,9 0 0134
+rs "
+] 6,9,2 0 0135
+rB "
+^ 6,9 0 0136
+a^ "
+ha "
+_ 8,0,2 0 0137
+` 3,9 0 0140
+oq "
+a 8,6 0 0141
+b 7,9 0 0142
+c 6,6 0 0143
+d 8,9 0 0144
+e 6,6 0 0145
+f 4,9,3 0 0146
+g 6,7,3 0 0147
+h 8,9 0 0150
+i 4,9 0 0151
+j 3,9,3 0 0152
+k 7,9 0 0153
+l 4,9 0 0154
+m 12,6 0 0155
+n 8,6 0 0156
+o 6,6 0 0157
+p 7,6,3 0 0160
+q 7,6,3 0 0161
+r 5,6 0 0162
+s 6,6 0 0163
+t 4,8 0 0164
+u 8,6 0 0165
+v 7,6 0 0166
+w 10,6 0 0167
+x 6,6 0 0170
+y 6,6,3 0 0171
+z 6,6 0 0172
+{ 5,9,2 0 0173
+lC "
+| 6,9 0 0174
+or "
+ba "
+} 5,9,2 0 0175
+rC "
+~ 7,5 0 0176
+a~ "
+ap "
+ti "
+r! 4,7,2 0 0241
+¡ "
+ct 6,7,1 0 0242
+¢ "
+Po 8,9 0 0243
+£ "
+Cs 9,8 0 0244
+¤ "
+Ye 9,9 0 0245
+¥ "
+bb 6,9 0 0246
+¦ "
+sc 6,9,2 0 0247
+§ "
+ad 5,9 0 0250
+¨ "
+co 10,9 0 0251
+© "
+Of 5,9 0 0252
+ª "
+Fo 7,5 0 0253
+« "
+no 7,5 0 0254
+¬ "
+- 4,4 0 0255
+hy "
+­ "
+rg 10,9 0 0256
+® "
+a- 5,8 0 0257
+¯ "
+de 5,9 0 0260
+° "
++- 8,7 0 0261
+± "
+S2 4,9 0 0262
+² "
+S3 4,9 0 0263
+³ "
+aa 4,9 0 0264
+´ "
+µ 8,6,3 0 0265
+ps 9,9 0 0266
+¶ "
+md 5,5 0 0267
+· "
+ac 4,0,3 0 0270
+¸ "
+S1 4,9 0 0271
+¹ "
+Om 4,9 0 0272
+º "
+Fc 7,5 0 0273
+» "
+14 9,9 0 0274
+¼ "
+12 9,9 0 0275
+½ "
+34 9,9 0 0276
+¾ "
+r? 5,7,2 0 0277
+¿ "
+`A 8,12 0 0300
+À "
+'A 8,12 0 0301
+Á "
+^A 8,12 0 0302
+Â "
+~A 8,12 0 0303
+Ã "
+:A 8,12 0 0304
+Ä "
+oA 8,12 0 0305
+Å "
+AE 13,9 0 0306
+Æ "
+,C 9,9,3 0 0307
+Ç "
+`E 9,12 0 0310
+È "
+'E 9,12 0 0311
+É "
+^E 9,12 0 0312
+Ê "
+:E 9,12 0 0313
+Ë "
+`I 5,12 0 0314
+Ì "
+'I 5,12 0 0315
+Í "
+^I 5,12 0 0316
+Î "
+:I 5,12 0 0317
+Ï "
+-D 10,9 0 0320
+Ð "
+~N 11,12 0 0321
+Ñ "
+`O 9,12 0 0322
+Ò "
+'O 9,12 0 0323
+Ó "
+^O 9,12 0 0324
+Ô "
+~O 9,12 0 0325
+Õ "
+:O 9,12 0 0326
+Ö "
+mu 8,7 0 0327
+× "
+/O 9,9 0 0330
+Ø "
+`U 8,12 0 0331
+Ù "
+'U 8,12 0 0332
+Ú "
+^U 8,12 0 0333
+Û "
+:U 8,12 0 0334
+Ü "
+'Y 8,12 0 0335
+Ý "
+TP 8,9 0 0336
+Þ "
+ss 8,9,3 0 0337
+ß "
+`a 8,9 0 0340
+à "
+'a 8,9 0 0341
+á "
+^a 8,9 0 0342
+â "
+~a 8,9 0 0343
+ã "
+:a 8,9 0 0344
+ä "
+oa 8,10 0 0345
+å "
+ae 9,6 0 0346
+æ "
+,c 6,6,3 0 0347
+ç "
+`e 6,9 0 0350
+è "
+'e 6,9 0 0351
+é "
+^e 6,9 0 0352
+ê "
+:e 6,9 0 0353
+ë "
+`i 4,9 0 0354
+ì "
+'i 4,9 0 0355
+í "
+^i 4,9 0 0356
+î "
+:i 4,9 0 0357
+ï "
+Sd 6,9 0 0360
+ð "
+~n 8,9 0 0361
+ñ "
+`o 6,9 0 0362
+ò "
+'o 6,9 0 0363
+ó "
+^o 6,9 0 0364
+ô "
+~o 6,9 0 0365
+õ "
+:o 6,9 0 0366
+ö "
+di 8,7 0 0367
+÷ "
+/o 6,6 0 0370
+ø "
+`u 8,9 0 0371
+ù "
+'u 8,9 0 0372
+ú "
+^u 8,9 0 0373
+û "
+:u 8,9 0 0374
+ü "
+'y 6,9,3 0 0375
+ý "
+Tp 7,9,3 0 0376
+þ "
+:y 8,9,3 0 0377
+ÿ "
diff --git a/gnu/usr.bin/groff/devX75-12/NR b/gnu/usr.bin/groff/devX75-12/NR
new file mode 100644
index 0000000..a1df486
--- /dev/null
+++ b/gnu/usr.bin/groff/devX75-12/NR
@@ -0,0 +1,306 @@
+name NR
+spacewidth 3
+charset
+--- 3,1 0 040
+! 4,9 0 041
+" 6,9 0 042
+# 8,8 0 043
+sh "
+$ 6,10,1 0 044
+Do "
+% 11,9 0 045
+& 9,9 0 046
+' 4,9 0 047
+( 4,9,2 0 050
+) 4,9,2 0 051
+* 6,9 0 052
++ 8,7 0 053
+, 4,2,1 0 054
+\- 7,4 0 055
+. 4,2 0 056
+/ 4,9 0 057
+sl "
+0 6,9 0 060
+1 6,9 0 061
+2 6,9 0 062
+3 6,9 0 063
+4 6,9 0 064
+5 6,9 0 065
+6 6,9 0 066
+7 6,9 0 067
+8 6,9 0 070
+9 6,9 0 071
+: 4,6 0 072
+; 4,6,1 0 073
+< 7,6 0 074
+= 7,5 0 075
+eq "
+> 7,6 0 076
+? 5,9 0 077
+@ 10,9 0 0100
+at "
+A 10,9 0 0101
+B 8,9 0 0102
+C 9,9 0 0103
+D 9,9 0 0104
+E 8,9 0 0105
+F 8,9 0 0106
+G 10,9 0 0107
+H 10,9 0 0110
+I 6,9 0 0111
+J 7,9 0 0112
+K 9,9 0 0113
+L 8,9 0 0114
+M 12,9 0 0115
+N 10,9 0 0116
+O 9,9 0 0117
+P 8,9 0 0120
+Q 9,9,2 0 0121
+R 9,9 0 0122
+S 7,9 0 0123
+T 8,9 0 0124
+U 10,9 0 0125
+V 10,9 0 0126
+W 12,9 0 0127
+X 9,9 0 0130
+Y 10,9 0 0131
+Z 7,9 0 0132
+[ 4,9,2 0 0133
+lB "
+\ 6,9 0 0134
+rs "
+] 4,9,2 0 0135
+rB "
+^ 6,9 0 0136
+a^ "
+ha "
+_ 8,0,2 0 0137
+` 4,9 0 0140
+oq "
+a 7,6 0 0141
+b 6,9 0 0142
+c 6,6 0 0143
+d 7,9 0 0144
+e 6,6 0 0145
+f 4,9 0 0146
+g 7,7,3 0 0147
+h 8,9 0 0150
+i 4,9 0 0151
+j 4,9,3 0 0152
+k 7,9 0 0153
+l 4,9 0 0154
+m 12,6 0 0155
+n 8,6 0 0156
+o 6,6 0 0157
+p 7,6,3 0 0160
+q 6,6,3 0 0161
+r 6,6 0 0162
+s 6,6 0 0163
+t 4,8 0 0164
+u 8,6 0 0165
+v 6,6 0 0166
+w 10,6 0 0167
+x 7,6 0 0170
+y 6,6,3 0 0171
+z 6,6 0 0172
+{ 4,9,2 0 0173
+lC "
+| 8,9 0 0174
+or "
+ba "
+} 4,9,2 0 0175
+rC "
+~ 7,5 0 0176
+a~ "
+ap "
+ti "
+r! 4,7,2 0 0241
+¡ "
+ct 7,7,1 0 0242
+¢ "
+Po 8,9 0 0243
+£ "
+Cs 8,8 0 0244
+¤ "
+Ye 8,9 0 0245
+¥ "
+bb 8,9 0 0246
+¦ "
+sc 6,9,2 0 0247
+§ "
+ad 4,9 0 0250
+¨ "
+co 11,9 0 0251
+© "
+Of 5,9 0 0252
+ª "
+Fo 7,6 0 0253
+« "
+no 7,5 0 0254
+¬ "
+- 4,4 0 0255
+hy "
+­ "
+rg 11,9 0 0256
+® "
+a- 5,8 0 0257
+¯ "
+de 5,9 0 0260
+° "
++- 8,7 0 0261
+± "
+S2 4,9 0 0262
+² "
+S3 4,9 0 0263
+³ "
+aa 3,9 0 0264
+´ "
+µ 8,6,3 0 0265
+ps 8,9,2 0 0266
+¶ "
+md 4,5 0 0267
+· "
+ac 4,0,3 0 0270
+¸ "
+S1 4,9 0 0271
+¹ "
+Om 5,9 0 0272
+º "
+Fc 7,6 0 0273
+» "
+14 9,9 0 0274
+¼ "
+12 9,9 0 0275
+½ "
+34 9,9 0 0276
+¾ "
+r? 5,7,2 0 0277
+¿ "
+`A 10,12 0 0300
+À "
+'A 10,12 0 0301
+Á "
+^A 10,12 0 0302
+Â "
+~A 10,12 0 0303
+Ã "
+:A 10,12 0 0304
+Ä "
+oA 10,12 0 0305
+Å "
+AE 13,9 0 0306
+Æ "
+,C 9,9,3 0 0307
+Ç "
+`E 8,12 0 0310
+È "
+'E 8,12 0 0311
+É "
+^E 8,12 0 0312
+Ê "
+:E 8,12 0 0313
+Ë "
+`I 6,12 0 0314
+Ì "
+'I 6,12 0 0315
+Í "
+^I 6,12 0 0316
+Î "
+:I 6,12 0 0317
+Ï "
+-D 9,9 0 0320
+Ð "
+~N 10,12 0 0321
+Ñ "
+`O 9,12 0 0322
+Ò "
+'O 9,12 0 0323
+Ó "
+^O 9,12 0 0324
+Ô "
+~O 9,12 0 0325
+Õ "
+:O 9,12 0 0326
+Ö "
+mu 8,7 0 0327
+× "
+/O 9,9 0 0330
+Ø "
+`U 10,12 0 0331
+Ù "
+'U 10,12 0 0332
+Ú "
+^U 10,12 0 0333
+Û "
+:U 10,12 0 0334
+Ü "
+'Y 10,12 0 0335
+Ý "
+TP 8,9 0 0336
+Þ "
+ss 7,9 0 0337
+ß "
+`a 7,9 0 0340
+à "
+'a 7,9 0 0341
+á "
+^a 7,9 0 0342
+â "
+~a 7,9 0 0343
+ã "
+:a 7,9 0 0344
+ä "
+oa 7,9 0 0345
+å "
+ae 10,6 0 0346
+æ "
+,c 6,6,3 0 0347
+ç "
+`e 6,9 0 0350
+è "
+'e 6,9 0 0351
+é "
+^e 6,9 0 0352
+ê "
+:e 6,9 0 0353
+ë "
+`i 4,9 0 0354
+ì "
+'i 4,9 0 0355
+í "
+^i 4,9 0 0356
+î "
+:i 4,9 0 0357
+ï "
+Sd 6,9 0 0360
+ð "
+~n 8,9 0 0361
+ñ "
+`o 6,9 0 0362
+ò "
+'o 6,9 0 0363
+ó "
+^o 6,9 0 0364
+ô "
+~o 6,9 0 0365
+õ "
+:o 6,8 0 0366
+ö "
+di 8,7 0 0367
+÷ "
+/o 6,7,1 0 0370
+ø "
+`u 8,9 0 0371
+ù "
+'u 8,9 0 0372
+ú "
+^u 8,9 0 0373
+û "
+:u 8,9 0 0374
+ü "
+'y 6,9,3 0 0375
+ý "
+Tp 7,9,3 0 0376
+þ "
+:y 6,9,3 0 0377
+ÿ "
diff --git a/gnu/usr.bin/groff/devX75-12/S b/gnu/usr.bin/groff/devX75-12/S
new file mode 100644
index 0000000..2e66ad0
--- /dev/null
+++ b/gnu/usr.bin/groff/devX75-12/S
@@ -0,0 +1,226 @@
+name S
+special
+spacewidth 3
+charset
+--- 3,1 0 040
+! 4,9 0 041
+fa 9,9 0 042
+# 7,9 0 043
+sh "
+te 7,9 0 044
+% 10,9 0 045
+& 10,9 0 046
+st 6,6 0 047
+( 5,9,3 0 050
+) 5,9,3 0 051
+** 6,7 0 052
++ 7,6 0 053
+pl "
+, 3,1,2 0 054
+\- 7,4 0 055
+mi "
+. 3,1 0 056
+/ 3,9 0 057
+sl "
+0 6,9 0 060
+1 6,9 0 061
+2 6,9 0 062
+3 6,9 0 063
+4 6,9 0 064
+5 6,9 0 065
+6 6,9 0 066
+7 6,9 0 067
+8 6,9 0 070
+9 6,9 0 071
+: 3,6 0 072
+; 3,6,2 0 073
+< 7,6 0 074
+= 7,5 0 075
+eq "
+> 7,6 0 076
+? 6,9 0 077
+=~ 7,6 0 0100
+*A 9,9 0 0101
+*B 8,9 0 0102
+*X 9,9 0 0103
+*D 8,9 0 0104
+*E 8,9 0 0105
+*F 10,9 0 0106
+*G 8,9 0 0107
+*Y 9,9 0 0110
+*I 4,9 0 0111
++h 8,9 0 0112
+*K 9,9 0 0113
+*L 9,9 0 0114
+*M 11,9 0 0115
+*N 9,9 0 0116
+*O 9,9 0 0117
+*P 9,9 0 0120
+*H 9,9 0 0121
+*R 7,9 0 0122
+*S 7,9 0 0123
+*T 8,9 0 0124
+--- 9,9 0 0125
+ts 7,6,3 0 0126
+*W 10,9 0 0127
+*C 8,9 0 0130
+*Q 10,9 0 0131
+*Z 8,9 0 0132
+[ 5,9,3 0 0133
+lB "
+tf 9,6 0 0134
+3d "
+] 5,9,3 0 0135
+rB "
+pp 8,9 0 0136
+_ 6,0,3 0 0137
+radicalex 6,12 0 0140
+*a 8,6 0 0141
+*b 7,10,3 0 0142
+*x 7,6,3 0 0143
+*d 7,10 0 0144
+*e 6,6 0 0145
+*f 8,8,3 0 0146
+*g 7,6,3 0 0147
+*y 8,6,3 0 0150
+*i 3,6 0 0151
++f 8,6,3 0 0152
+*k 7,6 0 0153
+*l 7,9 0 0154
+*m 8,6,3 0 0155
+µ "
+*n 7,6 0 0156
+*o 7,6 0 0157
+*p 7,6 0 0160
+*h 7,9 0 0161
+*r 7,6,3 0 0162
+*s 8,6 0 0163
+*t 6,6 0 0164
+*u 8,6 0 0165
++p 9,7 0 0166
+*w 9,6 0 0167
+*c 6,11,3 0 0170
+*q 9,6,3 0 0171
+*z 6,10,3 0 0172
+lC 6,9,3 0 0173
+{ "
+ba 3,9,3 0 0174
+or "
+| "
+rC 6,9,3 0 0175
+} "
+ap 7,5 0 0176
+*U 8,9 0 0241
+fm 3,9 0 0242
+<= 7,7 0 0243
+f/ 4,9 0 0244
+if 9,5 0 0245
+Fn 6,9,3 0 0246
+CL 9,6,1 0 0247
+DI 7,6 0 0250
+HE 9,6 0 0251
+SP 9,6,1 0 0252
+<> 13,6 0 0253
+<- 12,6 0 0254
+ua 7,12,4 0 0255
+arrowverttp "
+-> 12,6 0 0256
+da 7,12,3 0 0257
+arrowvertbt "
+de 5,9 0 0260
+° "
++- 7,7 0 0261
+± "
+sd 5,9 0 0262
+>= 7,7 0 0263
+mu 7,6 0 0264
+× "
+pt 9,5 0 0265
+pd 6,10 0 0266
+bu 6,5 0 0267
+di 7,6 0 0270
+÷ "
+!= 7,7 0 0271
+== 7,6 0 0272
+~= 7,6 0 0273
+~~ "
+--- 11,1 0 0274
+arrowvertex 7,12,4 0 0275
+an 13,4 0 0276
+CR 8,8 0 0277
+Ah 10,9 0 0300
+Im 9,10,1 0 0301
+Re 10,10 0 0302
+wp 10,8,3 0 0303
+c* 10,9 0 0304
+c+ 10,9 0 0305
+es 10,9 0 0306
+ca 10,6 0 0307
+cu 10,6 0 0310
+sp 9,6 0 0311
+ip 9,6,2 0 0312
+--- 9,7,1 0 0313
+sb 9,6 0 0314
+ib 9,6,2 0 0315
+mo 8,6 0 0316
+nm 8,7,1 0 0317
+/_ 10,9 0 0320
+gr 9,9 0 0321
+rg 10,9 0 0322
+co 10,9 0 0323
+tm 11,9 0 0324
+--- 10,10,1 0 0325
+sr 7,12 0 0326
+md 3,4 0 0327
+no 9,4 0 0330
+¬ "
+AN 8,6 0 0331
+OR 8,6 0 0332
+hA 13,6 0 0333
+lA 12,6 0 0334
+uA 8,11,1 0 0335
+rA 12,6 0 0336
+dA 8,12 0 0337
+lz 6,9 0 0340
+la 4,10,1 0 0341
+--- 10,9 0 0342
+--- 10,9 0 0343
+--- 10,9 0 0344
+--- 9,10,1 0 0345
+parenlefttp 5,12,4 0 0346
+parenleftex 5,12,4 0 0347
+parenleftbt 5,12,4 0 0350
+bracketlefttp 5,12,4 0 0351
+lc "
+bracketleftex 5,12,4 0 0352
+bracketleftbt 5,12,3 0 0353
+lf "
+bracelefttp 6,12,4 0 0354
+lt "
+braceleftmid 6,12,4 0 0355
+lk "
+braceleftbt 6,12,3 0 0356
+lb "
+bracerightex 6,12,4 0 0357
+braceleftex "
+bv "
+--- 10,11 0 0360
+ra 4,10,2 0 0361
+is 4,12,3 0 0362
+--- 9,12,4 0 0363
+--- 9,12,4 0 0364
+--- 9,12,3 0 0365
+parenrighttp 5,12,4 0 0366
+parenrightex 5,12,4 0 0367
+parenrightbt 5,12,4 0 0370
+bracketrighttp 5,12,4 0 0371
+rc "
+bracketrightex 5,12,4 0 0372
+bracketrightbt 5,12,3 0 0373
+rf "
+bracerighttp 6,12,4 0 0374
+rt "
+bracerightmid 6,12,4 0 0375
+rk "
+bracerightbt 6,12,3 0 0376
+rb "
diff --git a/gnu/usr.bin/groff/devX75-12/TB b/gnu/usr.bin/groff/devX75-12/TB
new file mode 100644
index 0000000..348d388
--- /dev/null
+++ b/gnu/usr.bin/groff/devX75-12/TB
@@ -0,0 +1,306 @@
+name TB
+spacewidth 3
+charset
+--- 3,1 0 040
+! 4,9 0 041
+" 5,9 0 042
+# 6,9 0 043
+sh "
+$ 6,10,1 0 044
+Do "
+% 12,9 0 045
+& 10,9 0 046
+' 4,9 0 047
+( 4,9,3 0 050
+) 4,9,3 0 051
+* 6,9 0 052
++ 7,6 0 053
+, 4,2,2 0 054
+\- 8,4 0 055
+. 4,2 0 056
+/ 4,9 0 057
+sl "
+0 6,9 0 060
+1 6,9 0 061
+2 6,9 0 062
+3 6,9 0 063
+4 6,9 0 064
+5 6,9 0 065
+6 6,9 0 066
+7 6,9 0 067
+8 6,9 0 070
+9 6,9 0 071
+: 4,6 0 072
+; 4,6,2 0 073
+< 7,6 0 074
+= 7,5 0 075
+eq "
+> 8,6 0 076
+? 7,9 0 077
+@ 12,9,2 0 0100
+at "
+A 9,9 0 0101
+B 9,9 0 0102
+C 8,9 0 0103
+D 9,9 0 0104
+E 8,9 0 0105
+F 8,9 0 0106
+G 9,9 0 0107
+H 10,9 0 0110
+I 5,9 0 0111
+J 7,9,1 0 0112
+K 10,9 0 0113
+L 8,9 0 0114
+M 11,9 0 0115
+N 9,9 0 0116
+O 9,9 0 0117
+P 8,9 0 0120
+Q 9,9,2 0 0121
+R 9,9 0 0122
+S 7,9 0 0123
+T 9,9 0 0124
+U 9,9 0 0125
+V 9,9 0 0126
+W 12,9 0 0127
+X 9,9 0 0130
+Y 9,9 0 0131
+Z 8,9 0 0132
+[ 4,9,3 0 0133
+lB "
+\ 3,9 0 0134
+rs "
+] 4,9,3 0 0135
+rB "
+^ 7,9 0 0136
+a^ "
+ha "
+_ 6,0,3 0 0137
+` 4,9 0 0140
+oq "
+a 7,6 0 0141
+b 6,9 0 0142
+c 6,6 0 0143
+d 6,9 0 0144
+e 7,6 0 0145
+f 4,9 0 0146
+g 6,6,3 0 0147
+h 6,9 0 0150
+i 3,9 0 0151
+j 3,9,3 0 0152
+k 7,9 0 0153
+l 3,9 0 0154
+m 9,6 0 0155
+n 6,6 0 0156
+o 7,6 0 0157
+p 6,6,3 0 0160
+q 6,6,3 0 0161
+r 5,6 0 0162
+s 6,6 0 0163
+t 4,8 0 0164
+u 6,6 0 0165
+v 6,6 0 0166
+w 9,6 0 0167
+x 6,6 0 0170
+y 6,6,3 0 0171
+z 6,6 0 0172
+{ 5,9,3 0 0173
+lC "
+| 3,9,3 0 0174
+or "
+ba "
+} 5,9,3 0 0175
+rC "
+~ 7,6 0 0176
+a~ "
+ap "
+ti "
+r! 4,6,3 0 0241
+¡ "
+ct 6,7,2 0 0242
+¢ "
+Po 6,9 0 0243
+£ "
+Cs 7,8 0 0244
+¤ "
+Ye 8,9 0 0245
+¥ "
+bb 3,9,3 0 0246
+¦ "
+sc 6,9,3 0 0247
+§ "
+ad 4,9 0 0250
+¨ "
+co 11,9 0 0251
+© "
+Of 4,9 0 0252
+ª "
+Fo 8,6 0 0253
+« "
+no 8,5 0 0254
+¬ "
+- 4,4 0 0255
+hy "
+­ "
+rg 11,9 0 0256
+® "
+a- 4,8 0 0257
+¯ "
+de 5,9 0 0260
+° "
++- 7,7 0 0261
+± "
+S2 4,9 0 0262
+² "
+S3 4,9 0 0263
+³ "
+aa 4,9 0 0264
+´ "
+µ 6,6,3 0 0265
+ps 8,9,3 0 0266
+¶ "
+md 3,5 0 0267
+· "
+ac 4,0,3 0 0270
+¸ "
+S1 4,9 0 0271
+¹ "
+Om 4,9 0 0272
+º "
+Fc 8,6 0 0273
+» "
+14 9,9 0 0274
+¼ "
+12 9,9 0 0275
+½ "
+34 9,9 0 0276
+¾ "
+r? 7,6,3 0 0277
+¿ "
+`A 9,12 0 0300
+À "
+'A 9,12 0 0301
+Á "
+^A 9,12 0 0302
+Â "
+~A 9,12 0 0303
+Ã "
+:A 9,12 0 0304
+Ä "
+oA 9,12 0 0305
+Å "
+AE 13,9 0 0306
+Æ "
+,C 8,9,3 0 0307
+Ç "
+`E 8,12 0 0310
+È "
+'E 8,12 0 0311
+É "
+^E 8,12 0 0312
+Ê "
+:E 8,12 0 0313
+Ë "
+`I 5,12 0 0314
+Ì "
+'I 5,12 0 0315
+Í "
+^I 5,12 0 0316
+Î "
+:I 5,12 0 0317
+Ï "
+-D 9,9 0 0320
+Ð "
+~N 9,12 0 0321
+Ñ "
+`O 9,12 0 0322
+Ò "
+'O 9,12 0 0323
+Ó "
+^O 9,12 0 0324
+Ô "
+~O 9,12 0 0325
+Õ "
+:O 9,12 0 0326
+Ö "
+mu 7,6 0 0327
+× "
+/O 9,10,1 0 0330
+Ø "
+`U 9,12 0 0331
+Ù "
+'U 9,12 0 0332
+Ú "
+^U 9,12 0 0333
+Û "
+:U 9,12 0 0334
+Ü "
+'Y 9,12 0 0335
+Ý "
+TP 8,9 0 0336
+Þ "
+ss 8,9 0 0337
+ß "
+`a 7,9 0 0340
+à "
+'a 7,9 0 0341
+á "
+^a 7,9 0 0342
+â "
+~a 7,9 0 0343
+ã "
+:a 7,9 0 0344
+ä "
+oa 7,10 0 0345
+å "
+ae 8,6 0 0346
+æ "
+,c 6,6,3 0 0347
+ç "
+`e 7,9 0 0350
+è "
+'e 7,9 0 0351
+é "
+^e 7,9 0 0352
+ê "
+:e 7,9 0 0353
+ë "
+`i 3,9 0 0354
+ì "
+'i 3,9 0 0355
+í "
+^i 3,9 0 0356
+î "
+:i 3,9 0 0357
+ï "
+Sd 7,9 0 0360
+ð "
+~n 6,9 0 0361
+ñ "
+`o 7,9 0 0362
+ò "
+'o 7,9 0 0363
+ó "
+^o 7,9 0 0364
+ô "
+~o 7,9 0 0365
+õ "
+:o 7,9 0 0366
+ö "
+di 7,6 0 0367
+÷ "
+/o 7,7,1 0 0370
+ø "
+`u 6,9 0 0371
+ù "
+'u 6,9 0 0372
+ú "
+^u 6,9 0 0373
+û "
+:u 6,9 0 0374
+ü "
+'y 6,9,3 0 0375
+ý "
+Tp 6,9,3 0 0376
+þ "
+:y 6,9,3 0 0377
+ÿ "
diff --git a/gnu/usr.bin/groff/devX75-12/TBI b/gnu/usr.bin/groff/devX75-12/TBI
new file mode 100644
index 0000000..02793a5
--- /dev/null
+++ b/gnu/usr.bin/groff/devX75-12/TBI
@@ -0,0 +1,306 @@
+name TBI
+spacewidth 3
+charset
+--- 3,1 0 040
+! 5,9 0 041
+" 7,9 0 042
+# 7,9 0 043
+sh "
+$ 7,10,1 0 044
+Do "
+% 12,9 0 045
+& 9,9 0 046
+' 4,9 0 047
+( 6,9,2 0 050
+) 6,9,2 0 051
+* 6,9 0 052
++ 7,6 0 053
+, 4,2,1 0 054
+\- 8,4 0 055
+. 4,2 0 056
+/ 5,9 0 057
+sl "
+0 6,9 0 060
+1 6,9 0 061
+2 6,9 0 062
+3 6,9 0 063
+4 6,9 0 064
+5 6,9 0 065
+6 6,9 0 066
+7 6,9 0 067
+8 6,9 0 070
+9 6,9 0 071
+: 5,6 0 072
+; 5,6,1 0 073
+< 9,7 0 074
+= 8,5 0 075
+eq "
+> 9,7 0 076
+? 6,9 0 077
+@ 12,9,1 0 0100
+at "
+A 8,9 0 0101
+B 8,9 0 0102
+C 8,9 0 0103
+D 9,9 0 0104
+E 8,9 0 0105
+F 8,9 0 0106
+G 9,9 0 0107
+H 10,9 0 0110
+I 5,9 0 0111
+J 6,9,1 0 0112
+K 8,9 0 0113
+L 8,9 0 0114
+M 11,9 0 0115
+N 9,9 0 0116
+O 9,9 0 0117
+P 8,9 0 0120
+Q 9,9,3 0 0121
+R 8,9 0 0122
+S 8,9 0 0123
+T 7,9 0 0124
+U 10,9 0 0125
+V 8,9 0 0126
+W 11,9 0 0127
+X 8,9 0 0130
+Y 7,9 0 0131
+Z 7,9 0 0132
+[ 6,9,2 0 0133
+lB "
+\ 5,9 0 0134
+rs "
+] 7,9,2 0 0135
+rB "
+^ 8,9 0 0136
+a^ "
+ha "
+_ 6,0,2 0 0137
+` 5,9 0 0140
+oq "
+a 7,6 0 0141
+b 6,9 0 0142
+c 5,6 0 0143
+d 6,9 0 0144
+e 6,6 0 0145
+f 3,9,3 0 0146
+g 5,6,3 0 0147
+h 6,9 0 0150
+i 4,9 0 0151
+j 4,9,3 0 0152
+k 6,9 0 0153
+l 4,9 0 0154
+m 9,6 0 0155
+n 6,6 0 0156
+o 6,6 0 0157
+p 6,6,3 0 0160
+q 6,6,3 0 0161
+r 5,6 0 0162
+s 5,6 0 0163
+t 3,7 0 0164
+u 7,6 0 0165
+v 6,6 0 0166
+w 8,6 0 0167
+x 6,6 0 0170
+y 6,6,3 0 0171
+z 6,6,1 0 0172
+{ 6,9,2 0 0173
+lC "
+| 4,9 0 0174
+or "
+ba "
+} 6,9,2 0 0175
+rC "
+~ 9,5 0 0176
+a~ "
+ap "
+ti "
+r! 4,6,3 0 0241
+¡ "
+ct 6,8,2 0 0242
+¢ "
+Po 6,9 0 0243
+£ "
+Cs 8,7 0 0244
+¤ "
+Ye 6,9 0 0245
+¥ "
+bb 4,9 0 0246
+¦ "
+sc 7,9,3 0 0247
+§ "
+ad 5,9 0 0250
+¨ "
+co 11,9 0 0251
+© "
+Of 6,9 0 0252
+ª "
+Fo 9,6 0 0253
+« "
+no 8,6 0 0254
+¬ "
+- 6,4 0 0255
+hy "
+­ "
+rg 11,9 0 0256
+® "
+a- 4,8 0 0257
+¯ "
+de 5,9 0 0260
+° "
++- 7,7 0 0261
+± "
+S2 4,9 0 0262
+² "
+S3 4,9 0 0263
+³ "
+aa 4,9 0 0264
+´ "
+µ 7,6,3 0 0265
+ps 7,9,3 0 0266
+¶ "
+md 3,5 0 0267
+· "
+ac 4,0,3 0 0270
+¸ "
+S1 4,9 0 0271
+¹ "
+Om 6,9 0 0272
+º "
+Fc 9,6 0 0273
+» "
+14 9,9 0 0274
+¼ "
+12 9,9 0 0275
+½ "
+34 9,9 0 0276
+¾ "
+r? 6,6,3 0 0277
+¿ "
+`A 8,12 0 0300
+À "
+'A 8,12 0 0301
+Á "
+^A 8,12 0 0302
+Â "
+~A 8,12 0 0303
+Ã "
+:A 8,12 0 0304
+Ä "
+oA 8,12 0 0305
+Å "
+AE 12,9 0 0306
+Æ "
+,C 8,9,3 0 0307
+Ç "
+`E 8,12 0 0310
+È "
+'E 8,12 0 0311
+É "
+^E 8,12 0 0312
+Ê "
+:E 8,12 0 0313
+Ë "
+`I 5,12 0 0314
+Ì "
+'I 5,12 0 0315
+Í "
+^I 5,12 0 0316
+Î "
+:I 5,12 0 0317
+Ï "
+-D 9,9 0 0320
+Ð "
+~N 9,11 0 0321
+Ñ "
+`O 9,12 0 0322
+Ò "
+'O 9,12 0 0323
+Ó "
+^O 9,12 0 0324
+Ô "
+~O 9,12 0 0325
+Õ "
+:O 9,12 0 0326
+Ö "
+mu 7,6 0 0327
+× "
+/O 9,10,1 0 0330
+Ø "
+`U 10,12 0 0331
+Ù "
+'U 10,12 0 0332
+Ú "
+^U 10,12 0 0333
+Û "
+:U 10,12 0 0334
+Ü "
+'Y 7,12 0 0335
+Ý "
+TP 8,9 0 0336
+Þ "
+ss 7,9,3 0 0337
+ß "
+`a 7,9 0 0340
+à "
+'a 7,9 0 0341
+á "
+^a 7,9 0 0342
+â "
+~a 7,9 0 0343
+ã "
+:a 7,9 0 0344
+ä "
+oa 7,9 0 0345
+å "
+ae 10,6 0 0346
+æ "
+,c 5,6,3 0 0347
+ç "
+`e 6,9 0 0350
+è "
+'e 6,9 0 0351
+é "
+^e 6,9 0 0352
+ê "
+:e 6,9 0 0353
+ë "
+`i 3,9 0 0354
+ì "
+'i 3,9 0 0355
+í "
+^i 3,9 0 0356
+î "
+:i 3,9 0 0357
+ï "
+Sd 6,9 0 0360
+ð "
+~n 7,9 0 0361
+ñ "
+`o 6,9 0 0362
+ò "
+'o 6,9 0 0363
+ó "
+^o 6,9 0 0364
+ô "
+~o 6,9 0 0365
+õ "
+:o 6,9 0 0366
+ö "
+di 7,6 0 0367
+÷ "
+/o 6,7,1 0 0370
+ø "
+`u 7,9 0 0371
+ù "
+'u 7,9 0 0372
+ú "
+^u 7,9 0 0373
+û "
+:u 7,9 0 0374
+ü "
+'y 6,9,3 0 0375
+ý "
+Tp 6,9,3 0 0376
+þ "
+:y 6,9,3 0 0377
+ÿ "
diff --git a/gnu/usr.bin/groff/devX75-12/TI b/gnu/usr.bin/groff/devX75-12/TI
new file mode 100644
index 0000000..dd79bd1
--- /dev/null
+++ b/gnu/usr.bin/groff/devX75-12/TI
@@ -0,0 +1,306 @@
+name TI
+spacewidth 3
+charset
+--- 3,1 0 040
+! 4,9 0 041
+" 5,9 0 042
+# 6,9 0 043
+sh "
+$ 6,10,1 0 044
+Do "
+% 10,9 0 045
+& 9,9 0 046
+' 4,9 0 047
+( 4,9,3 0 050
+) 4,9,3 0 051
+* 6,9 0 052
++ 8,6 0 053
+, 3,1,2 0 054
+\- 8,4 0 055
+. 3,1 0 056
+/ 4,9 0 057
+sl "
+0 6,9 0 060
+1 6,9 0 061
+2 6,9 0 062
+3 6,9 0 063
+4 6,9 0 064
+5 6,9 0 065
+6 6,9 0 066
+7 6,9 0 067
+8 6,9 0 070
+9 6,9 0 071
+: 4,6 0 072
+; 4,6,2 0 073
+< 8,7 0 074
+= 8,5 0 075
+eq "
+> 8,7 0 076
+? 6,9 0 077
+@ 12,9,1 0 0100
+at "
+A 8,9 0 0101
+B 8,9 0 0102
+C 7,9 0 0103
+D 9,9 0 0104
+E 8,9 0 0105
+F 8,9 0 0106
+G 8,9 0 0107
+H 9,9 0 0110
+I 5,9 0 0111
+J 5,9 0 0112
+K 8,9 0 0113
+L 7,9 0 0114
+M 11,9 0 0115
+N 9,9 0 0116
+O 7,9 0 0117
+P 8,9 0 0120
+Q 7,9,2 0 0121
+R 8,9 0 0122
+S 6,9 0 0123
+T 7,9 0 0124
+U 8,9 0 0125
+V 7,9 0 0126
+W 10,9 0 0127
+X 8,9 0 0130
+Y 7,9 0 0131
+Z 7,9 0 0132
+[ 5,9,2 0 0133
+lB "
+\ 3,9 0 0134
+rs "
+] 5,9,2 0 0135
+rB "
+^ 5,9 0 0136
+a^ "
+ha "
+_ 6,0,3 0 0137
+` 4,9 0 0140
+oq "
+a 6,6 0 0141
+b 6,9 0 0142
+c 5,6 0 0143
+d 6,9 0 0144
+e 6,6 0 0145
+f 4,9,3 0 0146
+g 5,6,3 0 0147
+h 6,9 0 0150
+i 4,9 0 0151
+j 4,9,3 0 0152
+k 6,9 0 0153
+l 3,9 0 0154
+m 9,6 0 0155
+n 6,6 0 0156
+o 6,6 0 0157
+p 6,6,3 0 0160
+q 6,6,3 0 0161
+r 4,6 0 0162
+s 5,6 0 0163
+t 4,7 0 0164
+u 6,6 0 0165
+v 6,6 0 0166
+w 9,6 0 0167
+x 6,6 0 0170
+y 6,6,3 0 0171
+z 5,6 0 0172
+{ 5,9,3 0 0173
+lC "
+| 4,9,3 0 0174
+or "
+ba "
+} 5,9,3 0 0175
+rC "
+~ 7,5 0 0176
+a~ "
+ap "
+ti "
+r! 5,6,3 0 0241
+¡ "
+ct 6,8,2 0 0242
+¢ "
+Po 6,9 0 0243
+£ "
+Cs 7,7 0 0244
+¤ "
+Ye 6,9 0 0245
+¥ "
+bb 4,9,3 0 0246
+¦ "
+sc 6,9,2 0 0247
+§ "
+ad 4,8 0 0250
+¨ "
+co 11,9 0 0251
+© "
+Of 4,9 0 0252
+ª "
+Fo 6,6 0 0253
+« "
+no 8,5 0 0254
+¬ "
+- 4,4 0 0255
+hy "
+­ "
+rg 11,9 0 0256
+® "
+a- 4,8 0 0257
+¯ "
+de 5,9 0 0260
+° "
++- 8,7 0 0261
+± "
+S2 4,9 0 0262
+² "
+S3 4,9 0 0263
+³ "
+aa 4,9 0 0264
+´ "
+µ 6,6,3 0 0265
+ps 7,9,2 0 0266
+¶ "
+md 3,4 0 0267
+· "
+ac 4,0,3 0 0270
+¸ "
+S1 3,9 0 0271
+¹ "
+Om 4,9 0 0272
+º "
+Fc 6,6 0 0273
+» "
+14 9,9 0 0274
+¼ "
+12 9,9 0 0275
+½ "
+34 9,9 0 0276
+¾ "
+r? 6,6,3 0 0277
+¿ "
+`A 8,12 0 0300
+À "
+'A 8,12 0 0301
+Á "
+^A 8,12 0 0302
+Â "
+~A 8,12 0 0303
+Ã "
+:A 8,11 0 0304
+Ä "
+oA 8,12 0 0305
+Å "
+AE 11,9 0 0306
+Æ "
+,C 7,9,3 0 0307
+Ç "
+`E 8,12 0 0310
+È "
+'E 8,12 0 0311
+É "
+^E 8,12 0 0312
+Ê "
+:E 8,11 0 0313
+Ë "
+`I 5,12 0 0314
+Ì "
+'I 5,12 0 0315
+Í "
+^I 5,12 0 0316
+Î "
+:I 5,11 0 0317
+Ï "
+-D 9,9 0 0320
+Ð "
+~N 9,12 0 0321
+Ñ "
+`O 7,12 0 0322
+Ò "
+'O 7,12 0 0323
+Ó "
+^O 7,12 0 0324
+Ô "
+~O 7,12 0 0325
+Õ "
+:O 7,11 0 0326
+Ö "
+mu 8,6 0 0327
+× "
+/O 7,10,1 0 0330
+Ø "
+`U 8,12 0 0331
+Ù "
+'U 8,12 0 0332
+Ú "
+^U 8,12 0 0333
+Û "
+:U 8,11 0 0334
+Ü "
+'Y 7,12 0 0335
+Ý "
+TP 8,9 0 0336
+Þ "
+ss 6,9,3 0 0337
+ß "
+`a 7,9 0 0340
+à "
+'a 7,9 0 0341
+á "
+^a 7,9 0 0342
+â "
+~a 7,9 0 0343
+ã "
+:a 7,8 0 0344
+ä "
+oa 7,9 0 0345
+å "
+ae 9,6 0 0346
+æ "
+,c 5,6,3 0 0347
+ç "
+`e 6,9 0 0350
+è "
+'e 6,9 0 0351
+é "
+^e 6,9 0 0352
+ê "
+:e 6,8 0 0353
+ë "
+`i 4,9 0 0354
+ì "
+'i 4,9 0 0355
+í "
+^i 4,9 0 0356
+î "
+:i 4,8 0 0357
+ï "
+Sd 6,9 0 0360
+ð "
+~n 6,9 0 0361
+ñ "
+`o 6,9 0 0362
+ò "
+'o 6,9 0 0363
+ó "
+^o 6,9 0 0364
+ô "
+~o 6,9 0 0365
+õ "
+:o 6,8 0 0366
+ö "
+di 8,6 0 0367
+÷ "
+/o 6,7,1 0 0370
+ø "
+`u 6,9 0 0371
+ù "
+'u 6,9 0 0372
+ú "
+^u 6,9 0 0373
+û "
+:u 6,8 0 0374
+ü "
+'y 6,9,3 0 0375
+ý "
+Tp 6,9,3 0 0376
+þ "
+:y 6,8,3 0 0377
+ÿ "
diff --git a/gnu/usr.bin/groff/devX75-12/TR b/gnu/usr.bin/groff/devX75-12/TR
new file mode 100644
index 0000000..da7c961
--- /dev/null
+++ b/gnu/usr.bin/groff/devX75-12/TR
@@ -0,0 +1,306 @@
+name TR
+spacewidth 3
+charset
+--- 3,1 0 040
+! 3,9 0 041
+" 5,9 0 042
+# 6,8 0 043
+sh "
+$ 6,10,1 0 044
+Do "
+% 9,9 0 045
+& 10,9 0 046
+' 4,9 0 047
+( 5,9,3 0 050
+) 5,9,3 0 051
+* 6,9 0 052
++ 7,6 0 053
+, 3,1,2 0 054
+\- 8,4 0 055
+. 3,1 0 056
+/ 3,9 0 057
+sl "
+0 6,9 0 060
+1 6,9 0 061
+2 6,9 0 062
+3 6,9 0 063
+4 6,9 0 064
+5 6,9 0 065
+6 6,9 0 066
+7 6,9 0 067
+8 6,9 0 070
+9 6,9 0 071
+: 3,6 0 072
+; 3,6,2 0 073
+< 8,6 0 074
+= 7,5 0 075
+eq "
+> 8,6 0 076
+? 5,9 0 077
+@ 11,9,2 0 0100
+at "
+A 9,9 0 0101
+B 8,9 0 0102
+C 8,9 0 0103
+D 9,9 0 0104
+E 8,9 0 0105
+F 8,9 0 0106
+G 9,9 0 0107
+H 9,9 0 0110
+I 4,9 0 0111
+J 4,9 0 0112
+K 8,9 0 0113
+L 7,9 0 0114
+M 11,9 0 0115
+N 9,9 0 0116
+O 9,9 0 0117
+P 7,9 0 0120
+Q 9,9,2 0 0121
+R 8,9 0 0122
+S 7,9 0 0123
+T 7,9 0 0124
+U 8,9 0 0125
+V 9,9 0 0126
+W 12,9 0 0127
+X 8,9 0 0130
+Y 9,9 0 0131
+Z 8,9 0 0132
+[ 5,9,3 0 0133
+lB "
+\ 3,9 0 0134
+rs "
+] 5,9,3 0 0135
+rB "
+^ 6,9 0 0136
+a^ "
+ha "
+_ 6,0,3 0 0137
+` 4,9 0 0140
+oq "
+a 6,6 0 0141
+b 6,9 0 0142
+c 5,6 0 0143
+d 6,9 0 0144
+e 6,6 0 0145
+f 3,9 0 0146
+g 6,6,3 0 0147
+h 6,9 0 0150
+i 3,9 0 0151
+j 3,9,3 0 0152
+k 6,9 0 0153
+l 3,9 0 0154
+m 9,6 0 0155
+n 6,6 0 0156
+o 6,6 0 0157
+p 6,6,3 0 0160
+q 6,6,3 0 0161
+r 4,6 0 0162
+s 6,6 0 0163
+t 4,7 0 0164
+u 6,6 0 0165
+v 6,6 0 0166
+w 9,6 0 0167
+x 6,6 0 0170
+y 6,6,3 0 0171
+z 6,6 0 0172
+{ 6,9,3 0 0173
+lC "
+| 3,9 0 0174
+or "
+ba "
+} 6,9,3 0 0175
+rC "
+~ 7,5 0 0176
+a~ "
+ap "
+ti "
+r! 4,6,3 0 0241
+¡ "
+ct 6,7,1 0 0242
+¢ "
+Po 6,9 0 0243
+£ "
+Cs 7,8 0 0244
+¤ "
+Ye 6,9 0 0245
+¥ "
+bb 3,9 0 0246
+¦ "
+sc 6,9,3 0 0247
+§ "
+ad 3,8 0 0250
+¨ "
+co 11,9 0 0251
+© "
+Of 5,9 0 0252
+ª "
+Fo 7,5 0 0253
+« "
+no 8,5 0 0254
+¬ "
+- 6,4 0 0255
+hy "
+­ "
+rg 11,9 0 0256
+® "
+a- 4,8 0 0257
+¯ "
+de 5,9 0 0260
+° "
++- 7,7 0 0261
+± "
+S2 4,9 0 0262
+² "
+S3 4,9 0 0263
+³ "
+aa 4,9 0 0264
+´ "
+µ 6,6,3 0 0265
+ps 7,9,3 0 0266
+¶ "
+md 3,4 0 0267
+· "
+ac 3,0,3 0 0270
+¸ "
+S1 4,9 0 0271
+¹ "
+Om 5,9 0 0272
+º "
+Fc 7,5 0 0273
+» "
+14 9,9 0 0274
+¼ "
+12 9,9 0 0275
+½ "
+34 9,9 0 0276
+¾ "
+r? 5,6,3 0 0277
+¿ "
+`A 9,12 0 0300
+À "
+'A 9,12 0 0301
+Á "
+^A 9,12 0 0302
+Â "
+~A 9,12 0 0303
+Ã "
+:A 9,11 0 0304
+Ä "
+oA 9,12 0 0305
+Å "
+AE 11,9 0 0306
+Æ "
+,C 8,9,3 0 0307
+Ç "
+`E 8,12 0 0310
+È "
+'E 8,12 0 0311
+É "
+^E 8,12 0 0312
+Ê "
+:E 8,11 0 0313
+Ë "
+`I 4,12 0 0314
+Ì "
+'I 4,12 0 0315
+Í "
+^I 4,12 0 0316
+Î "
+:I 4,11 0 0317
+Ï "
+-D 9,9 0 0320
+Ð "
+~N 9,12 0 0321
+Ñ "
+`O 9,12 0 0322
+Ò "
+'O 9,12 0 0323
+Ó "
+^O 9,12 0 0324
+Ô "
+~O 9,12 0 0325
+Õ "
+:O 9,11 0 0326
+Ö "
+mu 7,6 0 0327
+× "
+/O 9,10 0 0330
+Ø "
+`U 8,12 0 0331
+Ù "
+'U 8,12 0 0332
+Ú "
+^U 8,12 0 0333
+Û "
+:U 8,11 0 0334
+Ü "
+'Y 9,12 0 0335
+Ý "
+TP 7,9 0 0336
+Þ "
+ss 6,9 0 0337
+ß "
+`a 6,9 0 0340
+à "
+'a 6,9 0 0341
+á "
+^a 6,9 0 0342
+â "
+~a 6,9 0 0343
+ã "
+:a 6,8 0 0344
+ä "
+oa 6,9 0 0345
+å "
+ae 9,6 0 0346
+æ "
+,c 5,6,3 0 0347
+ç "
+`e 6,9 0 0350
+è "
+'e 6,9 0 0351
+é "
+^e 6,9 0 0352
+ê "
+:e 6,8 0 0353
+ë "
+`i 3,9 0 0354
+ì "
+'i 3,9 0 0355
+í "
+^i 3,9 0 0356
+î "
+:i 3,8 0 0357
+ï "
+Sd 6,9 0 0360
+ð "
+~n 6,9 0 0361
+ñ "
+`o 6,9 0 0362
+ò "
+'o 6,9 0 0363
+ó "
+^o 6,9 0 0364
+ô "
+~o 6,9 0 0365
+õ "
+:o 6,8 0 0366
+ö "
+di 7,6 0 0367
+÷ "
+/o 6,6,1 0 0370
+ø "
+`u 6,9 0 0371
+ù "
+'u 6,9 0 0372
+ú "
+^u 6,9 0 0373
+û "
+:u 6,8 0 0374
+ü "
+'y 6,9,3 0 0375
+ý "
+Tp 6,9,3 0 0376
+þ "
+:y 6,8,3 0 0377
+ÿ "
diff --git a/gnu/usr.bin/groff/devX75/CB b/gnu/usr.bin/groff/devX75/CB
new file mode 100644
index 0000000..5583135
--- /dev/null
+++ b/gnu/usr.bin/groff/devX75/CB
@@ -0,0 +1,306 @@
+name CB
+spacewidth 6
+charset
+--- 6,1 0 040
+! 6,7 0 041
+" 6,6 0 042
+# 6,7 0 043
+sh "
+$ 6,7,1 0 044
+Do "
+% 6,6 0 045
+& 6,6 0 046
+' 6,7 0 047
+( 6,7,1 0 050
+) 6,7,1 0 051
+* 6,7 0 052
++ 6,6 0 053
+, 6,1,2 0 054
+\- 6,4 0 055
+. 6,1 0 056
+/ 6,7,1 0 057
+sl "
+0 6,7 0 060
+1 6,7 0 061
+2 6,7 0 062
+3 6,7 0 063
+4 6,7 0 064
+5 6,7 0 065
+6 6,7 0 066
+7 6,7 0 067
+8 6,7 0 070
+9 6,7 0 071
+: 6,4 0 072
+; 6,4,2 0 073
+< 6,6 0 074
+= 6,5 0 075
+eq "
+> 6,6 0 076
+? 6,6 0 077
+@ 6,7,1 0 0100
+at "
+A 6,6 0 0101
+B 6,6 0 0102
+C 6,6 0 0103
+D 6,6 0 0104
+E 6,6 0 0105
+F 6,6 0 0106
+G 6,6 0 0107
+H 6,6 0 0110
+I 6,6 0 0111
+J 6,6 0 0112
+K 6,6 0 0113
+L 6,6 0 0114
+M 6,6 0 0115
+N 6,6 0 0116
+O 6,6 0 0117
+P 6,6 0 0120
+Q 6,6,1 0 0121
+R 6,6 0 0122
+S 6,6 0 0123
+T 6,6 0 0124
+U 6,6 0 0125
+V 6,6 0 0126
+W 6,6 0 0127
+X 6,6 0 0130
+Y 6,6 0 0131
+Z 6,6 0 0132
+[ 6,7,1 0 0133
+lB "
+\ 6,7,1 0 0134
+rs "
+] 6,7,1 0 0135
+rB "
+^ 6,7 0 0136
+a^ "
+ha "
+_ 6,0,2 0 0137
+` 6,7 0 0140
+oq "
+a 6,5 0 0141
+b 6,7 0 0142
+c 6,5 0 0143
+d 6,7 0 0144
+e 6,5 0 0145
+f 6,7 0 0146
+g 6,5,2 0 0147
+h 6,7 0 0150
+i 6,7 0 0151
+j 6,7,2 0 0152
+k 6,7 0 0153
+l 6,7 0 0154
+m 6,5 0 0155
+n 6,5 0 0156
+o 6,5 0 0157
+p 6,5,2 0 0160
+q 6,5,2 0 0161
+r 6,5 0 0162
+s 6,5 0 0163
+t 6,7 0 0164
+u 6,5 0 0165
+v 6,5 0 0166
+w 6,5 0 0167
+x 6,5 0 0170
+y 6,5,2 0 0171
+z 6,5 0 0172
+{ 6,7,1 0 0173
+lC "
+| 6,7,2 0 0174
+or "
+ba "
+} 6,7,1 0 0175
+rC "
+~ 6,5 0 0176
+a~ "
+ap "
+ti "
+r! 6,5,2 0 0241
+¡ "
+ct 6,7,1 0 0242
+¢ "
+Po 6,7 0 0243
+£ "
+Cs 6,6 0 0244
+¤ "
+Ye 6,7 0 0245
+¥ "
+bb 6,7,2 0 0246
+¦ "
+sc 6,7,1 0 0247
+§ "
+ad 6,7 0 0250
+¨ "
+co 6,7 0 0251
+© "
+Of 6,7 0 0252
+ª "
+Fo 6,5 0 0253
+« "
+no 6,5 0 0254
+¬ "
+- 6,4 0 0255
+hy "
+­ "
+rg 6,7 0 0256
+® "
+a- 6,7 0 0257
+¯ "
+de 6,7 0 0260
+° "
++- 6,6 0 0261
+± "
+S2 6,7 0 0262
+² "
+S3 6,7 0 0263
+³ "
+aa 6,8 0 0264
+´ "
+µ 6,5,2 0 0265
+ps 6,7,1 0 0266
+¶ "
+md 6,5 0 0267
+· "
+ac 6,1,2 0 0270
+¸ "
+S1 6,7 0 0271
+¹ "
+Om 6,7 0 0272
+º "
+Fc 6,5 0 0273
+» "
+14 6,8,1 0 0274
+¼ "
+12 6,8,1 0 0275
+½ "
+34 6,8,1 0 0276
+¾ "
+r? 6,4,2 0 0277
+¿ "
+`A 6,9 0 0300
+À "
+'A 6,9 0 0301
+Á "
+^A 6,9 0 0302
+Â "
+~A 6,9 0 0303
+Ã "
+:A 6,9 0 0304
+Ä "
+oA 6,9 0 0305
+Å "
+AE 6,6 0 0306
+Æ "
+,C 6,6,2 0 0307
+Ç "
+`E 6,9 0 0310
+È "
+'E 6,9 0 0311
+É "
+^E 6,9 0 0312
+Ê "
+:E 6,9 0 0313
+Ë "
+`I 6,9 0 0314
+Ì "
+'I 6,9 0 0315
+Í "
+^I 6,9 0 0316
+Î "
+:I 6,9 0 0317
+Ï "
+-D 6,6 0 0320
+Ð "
+~N 6,9 0 0321
+Ñ "
+`O 6,9 0 0322
+Ò "
+'O 6,9 0 0323
+Ó "
+^O 6,9 0 0324
+Ô "
+~O 6,9 0 0325
+Õ "
+:O 6,9 0 0326
+Ö "
+mu 6,6 0 0327
+× "
+/O 6,6,1 0 0330
+Ø "
+`U 6,9 0 0331
+Ù "
+'U 6,9 0 0332
+Ú "
+^U 6,9 0 0333
+Û "
+:U 6,9 0 0334
+Ü "
+'Y 6,9 0 0335
+Ý "
+TP 6,6 0 0336
+Þ "
+ss 6,7 0 0337
+ß "
+`a 6,8 0 0340
+à "
+'a 6,8 0 0341
+á "
+^a 6,8 0 0342
+â "
+~a 6,8 0 0343
+ã "
+:a 6,8 0 0344
+ä "
+oa 6,9 0 0345
+å "
+ae 6,5 0 0346
+æ "
+,c 6,5,2 0 0347
+ç "
+`e 6,8 0 0350
+è "
+'e 6,8 0 0351
+é "
+^e 6,8 0 0352
+ê "
+:e 6,8 0 0353
+ë "
+`i 6,8 0 0354
+ì "
+'i 6,8 0 0355
+í "
+^i 6,8 0 0356
+î "
+:i 6,8 0 0357
+ï "
+Sd 6,8 0 0360
+ð "
+~n 6,8 0 0361
+ñ "
+`o 6,8 0 0362
+ò "
+'o 6,8 0 0363
+ó "
+^o 6,8 0 0364
+ô "
+~o 6,8 0 0365
+õ "
+:o 6,8 0 0366
+ö "
+di 6,6 0 0367
+÷ "
+/o 6,6,1 0 0370
+ø "
+`u 6,8 0 0371
+ù "
+'u 6,8 0 0372
+ú "
+^u 6,8 0 0373
+û "
+:u 6,8 0 0374
+ü "
+'y 6,8,2 0 0375
+ý "
+Tp 6,7,2 0 0376
+þ "
+:y 6,8,2 0 0377
+ÿ "
diff --git a/gnu/usr.bin/groff/devX75/CBI b/gnu/usr.bin/groff/devX75/CBI
new file mode 100644
index 0000000..e6281f4
--- /dev/null
+++ b/gnu/usr.bin/groff/devX75/CBI
@@ -0,0 +1,306 @@
+name CBI
+spacewidth 6
+charset
+--- 6,1 0 040
+! 6,7 0 041
+" 6,7 0 042
+# 6,7 0 043
+sh "
+$ 6,7,1 0 044
+Do "
+% 6,7 0 045
+& 6,6 0 046
+' 6,7 0 047
+( 6,7,2 0 050
+) 6,7,2 0 051
+* 6,7 0 052
++ 6,6 0 053
+, 6,1,2 0 054
+\- 6,4 0 055
+. 6,1 0 056
+/ 6,7,1 0 057
+sl "
+0 6,7 0 060
+1 6,7 0 061
+2 6,7 0 062
+3 6,7 0 063
+4 6,7 0 064
+5 6,7 0 065
+6 6,7 0 066
+7 6,7 0 067
+8 6,7 0 070
+9 6,7 0 071
+: 6,4 0 072
+; 6,4,2 0 073
+< 6,6 0 074
+= 6,5 0 075
+eq "
+> 6,6 0 076
+? 6,7 0 077
+@ 6,7,1 0 0100
+at "
+A 6,6 0 0101
+B 6,6 0 0102
+C 6,6 0 0103
+D 6,6 0 0104
+E 6,6 0 0105
+F 6,6 0 0106
+G 6,6 0 0107
+H 6,6 0 0110
+I 6,6 0 0111
+J 6,6 0 0112
+K 6,6 0 0113
+L 6,6 0 0114
+M 6,6 0 0115
+N 6,6 0 0116
+O 6,6 0 0117
+P 6,6 0 0120
+Q 6,6,1 0 0121
+R 6,6 0 0122
+S 6,6 0 0123
+T 6,6 0 0124
+U 6,6 0 0125
+V 6,6 0 0126
+W 6,6 0 0127
+X 6,6 0 0130
+Y 6,6 0 0131
+Z 6,6 0 0132
+[ 6,7,2 0 0133
+lB "
+\ 6,7,1 0 0134
+rs "
+] 6,7,2 0 0135
+rB "
+^ 6,7 0 0136
+a^ "
+ha "
+_ 6,0,2 0 0137
+` 6,7 0 0140
+oq "
+a 6,5 0 0141
+b 6,7 0 0142
+c 6,5 0 0143
+d 6,7 0 0144
+e 6,5 0 0145
+f 6,7 0 0146
+g 6,5,2 0 0147
+h 6,7 0 0150
+i 6,7 0 0151
+j 6,7,2 0 0152
+k 6,7 0 0153
+l 6,7 0 0154
+m 6,5 0 0155
+n 6,5 0 0156
+o 6,5 0 0157
+p 6,5,2 0 0160
+q 6,5,2 0 0161
+r 6,5 0 0162
+s 6,5 0 0163
+t 6,7 0 0164
+u 6,5 0 0165
+v 6,5 0 0166
+w 6,5 0 0167
+x 6,5 0 0170
+y 6,5,2 0 0171
+z 6,5 0 0172
+{ 6,7,2 0 0173
+lC "
+| 6,7,1 0 0174
+or "
+ba "
+} 6,7,2 0 0175
+rC "
+~ 6,5 0 0176
+a~ "
+ap "
+ti "
+r! 6,5,2 0 0241
+¡ "
+ct 6,7,1 0 0242
+¢ "
+Po 6,6 0 0243
+£ "
+Cs 6,6 0 0244
+¤ "
+Ye 6,6 0 0245
+¥ "
+bb 6,7,1 0 0246
+¦ "
+sc 6,7,1 0 0247
+§ "
+ad 6,7 0 0250
+¨ "
+co 6,7 0 0251
+© "
+Of 6,6 0 0252
+ª "
+Fo 6,4 0 0253
+« "
+no 6,5 0 0254
+¬ "
+- 6,4 0 0255
+hy "
+­ "
+rg 6,7 0 0256
+® "
+a- 6,7 0 0257
+¯ "
+de 6,7 0 0260
+° "
++- 6,6 0 0261
+± "
+S2 6,7 0 0262
+² "
+S3 6,7 0 0263
+³ "
+aa 6,8 0 0264
+´ "
+µ 6,5,2 0 0265
+ps 6,7,1 0 0266
+¶ "
+md 6,4 0 0267
+· "
+ac 6,0,2 0 0270
+¸ "
+S1 6,7 0 0271
+¹ "
+Om 6,6 0 0272
+º "
+Fc 6,4 0 0273
+» "
+14 6,8,1 0 0274
+¼ "
+12 6,8,1 0 0275
+½ "
+34 6,8,1 0 0276
+¾ "
+r? 6,6,2 0 0277
+¿ "
+`A 6,9 0 0300
+À "
+'A 6,9 0 0301
+Á "
+^A 6,9 0 0302
+Â "
+~A 6,9 0 0303
+Ã "
+:A 6,8 0 0304
+Ä "
+oA 6,9 0 0305
+Å "
+AE 6,6 0 0306
+Æ "
+,C 6,6,2 0 0307
+Ç "
+`E 6,9 0 0310
+È "
+'E 6,9 0 0311
+É "
+^E 6,9 0 0312
+Ê "
+:E 6,8 0 0313
+Ë "
+`I 6,9 0 0314
+Ì "
+'I 6,9 0 0315
+Í "
+^I 6,9 0 0316
+Î "
+:I 6,8 0 0317
+Ï "
+-D 6,6 0 0320
+Ð "
+~N 6,9 0 0321
+Ñ "
+`O 6,9 0 0322
+Ò "
+'O 6,9 0 0323
+Ó "
+^O 6,9 0 0324
+Ô "
+~O 6,9 0 0325
+Õ "
+:O 6,8 0 0326
+Ö "
+mu 6,6 0 0327
+× "
+/O 6,7 0 0330
+Ø "
+`U 6,9 0 0331
+Ù "
+'U 6,9 0 0332
+Ú "
+^U 6,9 0 0333
+Û "
+:U 6,8 0 0334
+Ü "
+'Y 6,9 0 0335
+Ý "
+TP 6,6 0 0336
+Þ "
+ss 6,7 0 0337
+ß "
+`a 6,8 0 0340
+à "
+'a 6,8 0 0341
+á "
+^a 6,8 0 0342
+â "
+~a 6,8 0 0343
+ã "
+:a 6,7 0 0344
+ä "
+oa 6,9 0 0345
+å "
+ae 6,5 0 0346
+æ "
+,c 6,5,2 0 0347
+ç "
+`e 6,8 0 0350
+è "
+'e 6,8 0 0351
+é "
+^e 6,8 0 0352
+ê "
+:e 6,7 0 0353
+ë "
+`i 6,8 0 0354
+ì "
+'i 6,8 0 0355
+í "
+^i 6,8 0 0356
+î "
+:i 6,7 0 0357
+ï "
+Sd 6,8 0 0360
+ð "
+~n 6,8 0 0361
+ñ "
+`o 6,8 0 0362
+ò "
+'o 6,8 0 0363
+ó "
+^o 6,8 0 0364
+ô "
+~o 6,8 0 0365
+õ "
+:o 6,7 0 0366
+ö "
+di 6,6 0 0367
+÷ "
+/o 6,5 0 0370
+ø "
+`u 6,8 0 0371
+ù "
+'u 6,8 0 0372
+ú "
+^u 6,8 0 0373
+û "
+:u 6,7 0 0374
+ü "
+'y 6,8,2 0 0375
+ý "
+Tp 6,7,2 0 0376
+þ "
+:y 6,7,2 0 0377
+ÿ "
diff --git a/gnu/usr.bin/groff/devX75/CI b/gnu/usr.bin/groff/devX75/CI
new file mode 100644
index 0000000..f19be18
--- /dev/null
+++ b/gnu/usr.bin/groff/devX75/CI
@@ -0,0 +1,306 @@
+name CI
+spacewidth 6
+charset
+--- 6,1 0 040
+! 6,7 0 041
+" 6,7 0 042
+# 6,7 0 043
+sh "
+$ 6,7,1 0 044
+Do "
+% 6,7 0 045
+& 6,6 0 046
+' 6,7 0 047
+( 6,7,1 0 050
+) 6,7,1 0 051
+* 6,7 0 052
++ 6,6 0 053
+, 6,1,2 0 054
+\- 6,4 0 055
+. 6,1 0 056
+/ 6,7,1 0 057
+sl "
+0 6,7 0 060
+1 6,7 0 061
+2 6,7 0 062
+3 6,7 0 063
+4 6,7 0 064
+5 6,7 0 065
+6 6,7 0 066
+7 6,7 0 067
+8 6,7 0 070
+9 6,7 0 071
+: 6,4 0 072
+; 6,4,2 0 073
+< 6,6 0 074
+= 6,5 0 075
+eq "
+> 6,6 0 076
+? 6,6 0 077
+@ 6,7 0 0100
+at "
+A 6,6 0 0101
+B 6,6 0 0102
+C 6,6 0 0103
+D 6,6 0 0104
+E 6,6 0 0105
+F 6,6 0 0106
+G 6,6 0 0107
+H 6,6 0 0110
+I 6,6 0 0111
+J 6,6 0 0112
+K 6,6 0 0113
+L 6,6 0 0114
+M 6,6 0 0115
+N 6,6 0 0116
+O 6,6 0 0117
+P 6,6 0 0120
+Q 6,6,2 0 0121
+R 6,6 0 0122
+S 6,6 0 0123
+T 6,6 0 0124
+U 6,6 0 0125
+V 6,6 0 0126
+W 6,6 0 0127
+X 6,6 0 0130
+Y 6,6 0 0131
+Z 6,6 0 0132
+[ 6,7,1 0 0133
+lB "
+\ 6,7,1 0 0134
+rs "
+] 6,7,1 0 0135
+rB "
+^ 6,7 0 0136
+a^ "
+ha "
+_ 6,0,2 0 0137
+` 6,7 0 0140
+oq "
+a 6,5 0 0141
+b 6,7 0 0142
+c 6,5 0 0143
+d 6,7 0 0144
+e 6,5 0 0145
+f 6,7 0 0146
+g 6,5,2 0 0147
+h 6,7 0 0150
+i 6,7 0 0151
+j 6,7,2 0 0152
+k 6,7 0 0153
+l 6,7 0 0154
+m 6,5 0 0155
+n 6,5 0 0156
+o 6,5 0 0157
+p 6,5,2 0 0160
+q 6,5,2 0 0161
+r 6,5 0 0162
+s 6,5 0 0163
+t 6,7 0 0164
+u 6,5 0 0165
+v 6,5 0 0166
+w 6,5 0 0167
+x 6,5 0 0170
+y 6,5,2 0 0171
+z 6,5 0 0172
+{ 6,7,1 0 0173
+lC "
+| 6,7,1 0 0174
+or "
+ba "
+} 6,7,1 0 0175
+rC "
+~ 6,5 0 0176
+a~ "
+ap "
+ti "
+r! 6,5,2 0 0241
+¡ "
+ct 6,6 0 0242
+¢ "
+Po 6,7 0 0243
+£ "
+Cs 6,6 0 0244
+¤ "
+Ye 6,6 0 0245
+¥ "
+bb 6,7,2 0 0246
+¦ "
+sc 6,7,1 0 0247
+§ "
+ad 6,7 0 0250
+¨ "
+co 6,7 0 0251
+© "
+Of 6,7 0 0252
+ª "
+Fo 6,4 0 0253
+« "
+no 6,5 0 0254
+¬ "
+- 6,4 0 0255
+hy "
+­ "
+rg 6,7 0 0256
+® "
+a- 6,7 0 0257
+¯ "
+de 6,7 0 0260
+° "
++- 6,6 0 0261
+± "
+S2 6,7 0 0262
+² "
+S3 6,7 0 0263
+³ "
+aa 6,8 0 0264
+´ "
+µ 6,5,2 0 0265
+ps 6,7,1 0 0266
+¶ "
+md 6,4 0 0267
+· "
+ac 6,0,2 0 0270
+¸ "
+S1 6,7 0 0271
+¹ "
+Om 6,7 0 0272
+º "
+Fc 6,4 0 0273
+» "
+14 6,8,1 0 0274
+¼ "
+12 6,8,1 0 0275
+½ "
+34 6,8,1 0 0276
+¾ "
+r? 6,4,2 0 0277
+¿ "
+`A 6,9 0 0300
+À "
+'A 6,9 0 0301
+Á "
+^A 6,9 0 0302
+Â "
+~A 6,9 0 0303
+Ã "
+:A 6,8 0 0304
+Ä "
+oA 6,9 0 0305
+Å "
+AE 6,6 0 0306
+Æ "
+,C 6,6,2 0 0307
+Ç "
+`E 6,9 0 0310
+È "
+'E 6,9 0 0311
+É "
+^E 6,9 0 0312
+Ê "
+:E 6,8 0 0313
+Ë "
+`I 6,9 0 0314
+Ì "
+'I 6,9 0 0315
+Í "
+^I 6,9 0 0316
+Î "
+:I 6,8 0 0317
+Ï "
+-D 6,6 0 0320
+Ð "
+~N 6,9 0 0321
+Ñ "
+`O 6,9 0 0322
+Ò "
+'O 6,9 0 0323
+Ó "
+^O 6,9 0 0324
+Ô "
+~O 6,9 0 0325
+Õ "
+:O 6,8 0 0326
+Ö "
+mu 6,6 0 0327
+× "
+/O 6,6 0 0330
+Ø "
+`U 6,9 0 0331
+Ù "
+'U 6,9 0 0332
+Ú "
+^U 6,9 0 0333
+Û "
+:U 6,8 0 0334
+Ü "
+'Y 6,9 0 0335
+Ý "
+TP 6,6 0 0336
+Þ "
+ss 6,7 0 0337
+ß "
+`a 6,8 0 0340
+à "
+'a 6,8 0 0341
+á "
+^a 6,8 0 0342
+â "
+~a 6,8 0 0343
+ã "
+:a 6,7 0 0344
+ä "
+oa 6,9 0 0345
+å "
+ae 6,5 0 0346
+æ "
+,c 6,5,2 0 0347
+ç "
+`e 6,8 0 0350
+è "
+'e 6,8 0 0351
+é "
+^e 6,8 0 0352
+ê "
+:e 6,7 0 0353
+ë "
+`i 6,8 0 0354
+ì "
+'i 6,8 0 0355
+í "
+^i 6,8 0 0356
+î "
+:i 6,7 0 0357
+ï "
+Sd 6,8 0 0360
+ð "
+~n 6,8 0 0361
+ñ "
+`o 6,8 0 0362
+ò "
+'o 6,8 0 0363
+ó "
+^o 6,8 0 0364
+ô "
+~o 6,8 0 0365
+õ "
+:o 6,7 0 0366
+ö "
+di 6,6 0 0367
+÷ "
+/o 6,6,1 0 0370
+ø "
+`u 6,8 0 0371
+ù "
+'u 6,8 0 0372
+ú "
+^u 6,8 0 0373
+û "
+:u 6,7 0 0374
+ü "
+'y 6,8,2 0 0375
+ý "
+Tp 6,7,2 0 0376
+þ "
+:y 6,7,2 0 0377
+ÿ "
diff --git a/gnu/usr.bin/groff/devX75/CR b/gnu/usr.bin/groff/devX75/CR
new file mode 100644
index 0000000..8bb40b2
--- /dev/null
+++ b/gnu/usr.bin/groff/devX75/CR
@@ -0,0 +1,306 @@
+name CR
+spacewidth 6
+charset
+--- 6,1 0 040
+! 6,7 0 041
+" 6,7 0 042
+# 6,7 0 043
+sh "
+$ 6,7,1 0 044
+Do "
+% 6,6 0 045
+& 6,6 0 046
+' 6,7 0 047
+( 6,7,2 0 050
+) 6,7,2 0 051
+* 6,7 0 052
++ 6,6 0 053
+, 6,1,2 0 054
+\- 6,4 0 055
+. 6,1 0 056
+/ 6,7,1 0 057
+sl "
+0 6,7 0 060
+1 6,7 0 061
+2 6,7 0 062
+3 6,7 0 063
+4 6,7 0 064
+5 6,7 0 065
+6 6,7 0 066
+7 6,7 0 067
+8 6,7 0 070
+9 6,7 0 071
+: 6,4 0 072
+; 6,4,2 0 073
+< 6,6 0 074
+= 6,5 0 075
+eq "
+> 6,6 0 076
+? 6,6 0 077
+@ 6,7,1 0 0100
+at "
+A 6,6 0 0101
+B 6,6 0 0102
+C 6,6 0 0103
+D 6,6 0 0104
+E 6,6 0 0105
+F 6,6 0 0106
+G 6,6 0 0107
+H 6,6 0 0110
+I 6,6 0 0111
+J 6,6 0 0112
+K 6,6 0 0113
+L 6,6 0 0114
+M 6,6 0 0115
+N 6,6 0 0116
+O 6,6 0 0117
+P 6,6 0 0120
+Q 6,6,1 0 0121
+R 6,6 0 0122
+S 6,6 0 0123
+T 6,6 0 0124
+U 6,6 0 0125
+V 6,6 0 0126
+W 6,6 0 0127
+X 6,6 0 0130
+Y 6,6 0 0131
+Z 6,6 0 0132
+[ 6,7,2 0 0133
+lB "
+\ 6,7,1 0 0134
+rs "
+] 6,7,2 0 0135
+rB "
+^ 6,7 0 0136
+a^ "
+ha "
+_ 6,0,2 0 0137
+` 6,7 0 0140
+oq "
+a 6,5 0 0141
+b 6,7 0 0142
+c 6,5 0 0143
+d 6,7 0 0144
+e 6,5 0 0145
+f 6,7 0 0146
+g 6,5,2 0 0147
+h 6,7 0 0150
+i 6,7 0 0151
+j 6,7,2 0 0152
+k 6,7 0 0153
+l 6,7 0 0154
+m 6,5 0 0155
+n 6,5 0 0156
+o 6,5 0 0157
+p 6,5,2 0 0160
+q 6,5,2 0 0161
+r 6,5 0 0162
+s 6,5 0 0163
+t 6,7 0 0164
+u 6,5 0 0165
+v 6,5 0 0166
+w 6,5 0 0167
+x 6,5 0 0170
+y 6,5,2 0 0171
+z 6,5 0 0172
+{ 6,7,2 0 0173
+lC "
+| 6,7,2 0 0174
+or "
+ba "
+} 6,7,2 0 0175
+rC "
+~ 6,5 0 0176
+a~ "
+ap "
+ti "
+r! 6,5,2 0 0241
+¡ "
+ct 6,7,1 0 0242
+¢ "
+Po 6,7 0 0243
+£ "
+Cs 6,6 0 0244
+¤ "
+Ye 6,7 0 0245
+¥ "
+bb 6,7,2 0 0246
+¦ "
+sc 6,6,1 0 0247
+§ "
+ad 6,7 0 0250
+¨ "
+co 6,7 0 0251
+© "
+Of 6,6 0 0252
+ª "
+Fo 6,4 0 0253
+« "
+no 6,5 0 0254
+¬ "
+- 6,4 0 0255
+hy "
+­ "
+rg 6,7 0 0256
+® "
+a- 6,7 0 0257
+¯ "
+de 6,7 0 0260
+° "
++- 6,6 0 0261
+± "
+S2 6,7 0 0262
+² "
+S3 6,7 0 0263
+³ "
+aa 6,8 0 0264
+´ "
+µ 6,5,2 0 0265
+ps 6,6,1 0 0266
+¶ "
+md 6,4 0 0267
+· "
+ac 6,1,2 0 0270
+¸ "
+S1 6,7 0 0271
+¹ "
+Om 6,6 0 0272
+º "
+Fc 6,4 0 0273
+» "
+14 6,8,1 0 0274
+¼ "
+12 6,8,1 0 0275
+½ "
+34 6,8,1 0 0276
+¾ "
+r? 6,4,2 0 0277
+¿ "
+`A 6,9 0 0300
+À "
+'A 6,9 0 0301
+Á "
+^A 6,9 0 0302
+Â "
+~A 6,9 0 0303
+Ã "
+:A 6,8 0 0304
+Ä "
+oA 6,9 0 0305
+Å "
+AE 6,6 0 0306
+Æ "
+,C 6,6,2 0 0307
+Ç "
+`E 6,9 0 0310
+È "
+'E 6,9 0 0311
+É "
+^E 6,9 0 0312
+Ê "
+:E 6,8 0 0313
+Ë "
+`I 6,9 0 0314
+Ì "
+'I 6,9 0 0315
+Í "
+^I 6,9 0 0316
+Î "
+:I 6,8 0 0317
+Ï "
+-D 6,6 0 0320
+Ð "
+~N 6,9 0 0321
+Ñ "
+`O 6,9 0 0322
+Ò "
+'O 6,9 0 0323
+Ó "
+^O 6,9 0 0324
+Ô "
+~O 6,9 0 0325
+Õ "
+:O 6,8 0 0326
+Ö "
+mu 6,6 0 0327
+× "
+/O 6,6 0 0330
+Ø "
+`U 6,9 0 0331
+Ù "
+'U 6,9 0 0332
+Ú "
+^U 6,9 0 0333
+Û "
+:U 6,8 0 0334
+Ü "
+'Y 6,9 0 0335
+Ý "
+TP 6,6 0 0336
+Þ "
+ss 6,7 0 0337
+ß "
+`a 6,8 0 0340
+à "
+'a 6,8 0 0341
+á "
+^a 6,8 0 0342
+â "
+~a 6,8 0 0343
+ã "
+:a 6,7 0 0344
+ä "
+oa 6,9 0 0345
+å "
+ae 6,5 0 0346
+æ "
+,c 6,5,2 0 0347
+ç "
+`e 6,8 0 0350
+è "
+'e 6,8 0 0351
+é "
+^e 6,8 0 0352
+ê "
+:e 6,7 0 0353
+ë "
+`i 6,8 0 0354
+ì "
+'i 6,8 0 0355
+í "
+^i 6,8 0 0356
+î "
+:i 6,7 0 0357
+ï "
+Sd 6,8 0 0360
+ð "
+~n 6,8 0 0361
+ñ "
+`o 6,8 0 0362
+ò "
+'o 6,8 0 0363
+ó "
+^o 6,8 0 0364
+ô "
+~o 6,8 0 0365
+õ "
+:o 6,7 0 0366
+ö "
+di 6,6 0 0367
+÷ "
+/o 6,5 0 0370
+ø "
+`u 6,8 0 0371
+ù "
+'u 6,8 0 0372
+ú "
+^u 6,8 0 0373
+û "
+:u 6,7 0 0374
+ü "
+'y 6,8,2 0 0375
+ý "
+Tp 6,7,2 0 0376
+þ "
+:y 6,7,2 0 0377
+ÿ "
diff --git a/gnu/usr.bin/groff/devX75/DESC b/gnu/usr.bin/groff/devX75/DESC
new file mode 100644
index 0000000..172170c
--- /dev/null
+++ b/gnu/usr.bin/groff/devX75/DESC
@@ -0,0 +1,9 @@
+styles R I B BI
+fonts 6 0 0 0 0 0 S
+sizes 8 10 12 14 18 24 0
+res 75
+X11
+hor 1
+vert 1
+unitwidth 10
+postpro gxditview
diff --git a/gnu/usr.bin/groff/devX75/HB b/gnu/usr.bin/groff/devX75/HB
new file mode 100644
index 0000000..26894e0
--- /dev/null
+++ b/gnu/usr.bin/groff/devX75/HB
@@ -0,0 +1,306 @@
+name HB
+spacewidth 3
+charset
+--- 3,1 0 040
+! 4,8 0 041
+" 5,8 0 042
+# 6,7 0 043
+sh "
+$ 6,8,1 0 044
+Do "
+% 8,8 0 045
+& 8,8 0 046
+' 3,8 0 047
+( 4,8,2 0 050
+) 4,8,2 0 051
+* 4,8 0 052
++ 6,6 0 053
+, 3,2,2 0 054
+\- 7,4 0 055
+. 3,2 0 056
+/ 4,8 0 057
+sl "
+0 6,8 0 060
+1 6,8 0 061
+2 6,8 0 062
+3 6,8 0 063
+4 6,8 0 064
+5 6,8 0 065
+6 6,8 0 066
+7 6,8 0 067
+8 6,8 0 070
+9 6,8 0 071
+: 3,6 0 072
+; 3,6,2 0 073
+< 5,6 0 074
+= 6,5 0 075
+eq "
+> 5,6 0 076
+? 6,8 0 077
+@ 11,7,2 0 0100
+at "
+A 8,8 0 0101
+B 7,8 0 0102
+C 8,8 0 0103
+D 7,8 0 0104
+E 6,8 0 0105
+F 6,8 0 0106
+G 8,8 0 0107
+H 7,8 0 0110
+I 3,8 0 0111
+J 6,8 0 0112
+K 7,8 0 0113
+L 6,8 0 0114
+M 10,8 0 0115
+N 8,8 0 0116
+O 8,8 0 0117
+P 7,8 0 0120
+Q 8,8,1 0 0121
+R 7,8 0 0122
+S 7,8 0 0123
+T 7,8 0 0124
+U 7,8 0 0125
+V 8,8 0 0126
+W 11,8 0 0127
+X 8,8 0 0130
+Y 9,8 0 0131
+Z 7,8 0 0132
+[ 4,8,2 0 0133
+lB "
+\ 4,8 0 0134
+rs "
+] 4,8,2 0 0135
+rB "
+^ 5,8 0 0136
+a^ "
+ha "
+_ 6,0,2 0 0137
+` 3,8 0 0140
+oq "
+a 6,6 0 0141
+b 6,8 0 0142
+c 5,6 0 0143
+d 6,8 0 0144
+e 6,6 0 0145
+f 4,8 0 0146
+g 6,6,2 0 0147
+h 6,8 0 0150
+i 3,8 0 0151
+j 3,8,2 0 0152
+k 6,8 0 0153
+l 3,8 0 0154
+m 9,6 0 0155
+n 6,6 0 0156
+o 6,6 0 0157
+p 6,6,2 0 0160
+q 6,6,2 0 0161
+r 4,6 0 0162
+s 6,6 0 0163
+t 4,8 0 0164
+u 6,6 0 0165
+v 6,6 0 0166
+w 8,6 0 0167
+x 7,6 0 0170
+y 6,6,2 0 0171
+z 6,6 0 0172
+{ 5,8,2 0 0173
+lC "
+| 3,8,2 0 0174
+or "
+ba "
+} 5,8,2 0 0175
+rC "
+~ 6,4 0 0176
+a~ "
+ap "
+ti "
+r! 4,6,2 0 0241
+¡ "
+ct 6,7,1 0 0242
+¢ "
+Po 6,8 0 0243
+£ "
+Cs 6,7 0 0244
+¤ "
+Ye 7,8 0 0245
+¥ "
+bb 3,8,2 0 0246
+¦ "
+sc 6,8,2 0 0247
+§ "
+ad 3,8 0 0250
+¨ "
+co 10,8 0 0251
+© "
+Of 5,8 0 0252
+ª "
+Fo 7,4 0 0253
+« "
+no 7,5 0 0254
+¬ "
+- 5,4 0 0255
+hy "
+­ "
+rg 10,8 0 0256
+® "
+a- 3,8 0 0257
+¯ "
+de 4,7 0 0260
+° "
++- 6,7 0 0261
+± "
+S2 3,7 0 0262
+² "
+S3 3,7 0 0263
+³ "
+aa 3,9 0 0264
+´ "
+µ 6,6,2 0 0265
+ps 6,8,2 0 0266
+¶ "
+md 3,4 0 0267
+· "
+ac 3,0,2 0 0270
+¸ "
+S1 3,7 0 0271
+¹ "
+Om 5,8 0 0272
+º "
+Fc 7,4 0 0273
+» "
+14 9,8 0 0274
+¼ "
+12 9,8 0 0275
+½ "
+34 9,8 0 0276
+¾ "
+r? 6,6,2 0 0277
+¿ "
+`A 8,11 0 0300
+À "
+'A 8,11 0 0301
+Á "
+^A 8,11 0 0302
+Â "
+~A 8,11 0 0303
+Ã "
+:A 8,10 0 0304
+Ä "
+oA 8,11 0 0305
+Å "
+AE 10,8 0 0306
+Æ "
+,C 8,8,2 0 0307
+Ç "
+`E 6,11 0 0310
+È "
+'E 6,11 0 0311
+É "
+^E 6,11 0 0312
+Ê "
+:E 6,10 0 0313
+Ë "
+`I 3,11 0 0314
+Ì "
+'I 3,11 0 0315
+Í "
+^I 3,11 0 0316
+Î "
+:I 3,10 0 0317
+Ï "
+-D 7,8 0 0320
+Ð "
+~N 8,11 0 0321
+Ñ "
+`O 8,11 0 0322
+Ò "
+'O 8,11 0 0323
+Ó "
+^O 8,11 0 0324
+Ô "
+~O 8,11 0 0325
+Õ "
+:O 8,10 0 0326
+Ö "
+mu 6,6 0 0327
+× "
+/O 8,8 0 0330
+Ø "
+`U 7,11 0 0331
+Ù "
+'U 7,11 0 0332
+Ú "
+^U 7,11 0 0333
+Û "
+:U 7,10 0 0334
+Ü "
+'Y 9,11 0 0335
+Ý "
+TP 7,8 0 0336
+Þ "
+ss 6,8 0 0337
+ß "
+`a 6,9 0 0340
+à "
+'a 6,9 0 0341
+á "
+^a 6,9 0 0342
+â "
+~a 6,9 0 0343
+ã "
+:a 6,9 0 0344
+ä "
+oa 6,9 0 0345
+å "
+ae 9,6 0 0346
+æ "
+,c 5,6,2 0 0347
+ç "
+`e 6,9 0 0350
+è "
+'e 6,9 0 0351
+é "
+^e 6,9 0 0352
+ê "
+:e 6,9 0 0353
+ë "
+`i 3,9 0 0354
+ì "
+'i 3,9 0 0355
+í "
+^i 3,9 0 0356
+î "
+:i 3,9 0 0357
+ï "
+Sd 6,9 0 0360
+ð "
+~n 6,9 0 0361
+ñ "
+`o 6,9 0 0362
+ò "
+'o 6,9 0 0363
+ó "
+^o 6,9 0 0364
+ô "
+~o 6,9 0 0365
+õ "
+:o 6,9 0 0366
+ö "
+di 6,6 0 0367
+÷ "
+/o 6,6 0 0370
+ø "
+`u 6,9 0 0371
+ù "
+'u 6,9 0 0372
+ú "
+^u 6,9 0 0373
+û "
+:u 6,9 0 0374
+ü "
+'y 6,9,2 0 0375
+ý "
+Tp 6,8,2 0 0376
+þ "
+:y 6,9,2 0 0377
+ÿ "
diff --git a/gnu/usr.bin/groff/devX75/HBI b/gnu/usr.bin/groff/devX75/HBI
new file mode 100644
index 0000000..6488003
--- /dev/null
+++ b/gnu/usr.bin/groff/devX75/HBI
@@ -0,0 +1,306 @@
+name HBI
+spacewidth 3
+charset
+--- 3,1 0 040
+! 4,8 0 041
+" 6,8 0 042
+# 7,7 0 043
+sh "
+$ 6,8,1 0 044
+Do "
+% 9,8 0 045
+& 8,8 0 046
+' 3,8 0 047
+( 5,8,2 0 050
+) 5,8,2 0 051
+* 6,8 0 052
++ 6,6 0 053
+, 3,2,2 0 054
+\- 7,4 0 055
+. 3,2 0 056
+/ 5,8 0 057
+sl "
+0 6,8 0 060
+1 6,8 0 061
+2 6,8 0 062
+3 6,8 0 063
+4 6,8 0 064
+5 6,8 0 065
+6 6,8 0 066
+7 6,8 0 067
+8 6,8 0 070
+9 6,8 0 071
+: 3,6 0 072
+; 3,6,2 0 073
+< 6,6 0 074
+= 6,5 0 075
+eq "
+> 7,6 0 076
+? 6,8 0 077
+@ 10,7,2 0 0100
+at "
+A 8,8 0 0101
+B 7,8 0 0102
+C 7,8 0 0103
+D 8,8 0 0104
+E 6,8 0 0105
+F 5,8 0 0106
+G 8,8 0 0107
+H 7,8 0 0110
+I 3,8 0 0111
+J 6,8 0 0112
+K 8,8 0 0113
+L 6,8 0 0114
+M 10,8 0 0115
+N 8,8 0 0116
+O 8,8 0 0117
+P 7,8 0 0120
+Q 8,8 0 0121
+R 8,8 0 0122
+S 7,8 0 0123
+T 6,8 0 0124
+U 7,8 0 0125
+V 8,8 0 0126
+W 10,8 0 0127
+X 7,8 0 0130
+Y 7,8 0 0131
+Z 7,8 0 0132
+[ 4,8,2 0 0133
+lB "
+\ 5,8 0 0134
+rs "
+] 4,8,2 0 0135
+rB "
+^ 6,8 0 0136
+a^ "
+ha "
+_ 6,0,2 0 0137
+` 4,8 0 0140
+oq "
+a 6,6 0 0141
+b 6,8 0 0142
+c 5,6 0 0143
+d 6,8 0 0144
+e 6,6 0 0145
+f 3,8 0 0146
+g 6,6,2 0 0147
+h 6,8 0 0150
+i 3,8 0 0151
+j 3,8,2 0 0152
+k 6,8 0 0153
+l 3,8 0 0154
+m 9,6 0 0155
+n 6,6 0 0156
+o 6,6 0 0157
+p 6,6,2 0 0160
+q 6,6,2 0 0161
+r 4,6 0 0162
+s 6,6 0 0163
+t 4,8 0 0164
+u 6,6 0 0165
+v 6,6 0 0166
+w 8,6 0 0167
+x 5,6 0 0170
+y 6,6,2 0 0171
+z 5,6 0 0172
+{ 5,8,2 0 0173
+lC "
+| 4,8,2 0 0174
+or "
+ba "
+} 5,8,2 0 0175
+rC "
+~ 6,5 0 0176
+a~ "
+ap "
+ti "
+r! 4,6,2 0 0241
+¡ "
+ct 7,7,1 0 0242
+¢ "
+Po 7,7 0 0243
+£ "
+Cs 6,7 0 0244
+¤ "
+Ye 7,8 0 0245
+¥ "
+bb 4,8,1 0 0246
+¦ "
+sc 7,8,2 0 0247
+§ "
+ad 4,8 0 0250
+¨ "
+co 10,8 0 0251
+© "
+Of 5,8 0 0252
+ª "
+Fo 8,5 0 0253
+« "
+no 7,5 0 0254
+¬ "
+- 5,4 0 0255
+hy "
+­ "
+rg 10,8 0 0256
+® "
+a- 4,8 0 0257
+¯ "
+de 4,7 0 0260
+° "
++- 6,7 0 0261
+± "
+S2 3,7 0 0262
+² "
+S3 3,7 0 0263
+³ "
+aa 3,9 0 0264
+´ "
+µ 6,6,2 0 0265
+ps 7,8,2 0 0266
+¶ "
+md 3,4 0 0267
+· "
+ac 3,1,2 0 0270
+¸ "
+S1 3,7 0 0271
+¹ "
+Om 5,8 0 0272
+º "
+Fc 8,5 0 0273
+» "
+14 9,8 0 0274
+¼ "
+12 9,8 0 0275
+½ "
+34 9,8 0 0276
+¾ "
+r? 6,6,2 0 0277
+¿ "
+`A 8,11 0 0300
+À "
+'A 8,11 0 0301
+Á "
+^A 8,11 0 0302
+Â "
+~A 8,11 0 0303
+Ã "
+:A 8,10 0 0304
+Ä "
+oA 8,11 0 0305
+Å "
+AE 10,8 0 0306
+Æ "
+,C 7,8,2 0 0307
+Ç "
+`E 6,11 0 0310
+È "
+'E 6,11 0 0311
+É "
+^E 6,11 0 0312
+Ê "
+:E 6,10 0 0313
+Ë "
+`I 3,11 0 0314
+Ì "
+'I 3,11 0 0315
+Í "
+^I 3,11 0 0316
+Î "
+:I 3,10 0 0317
+Ï "
+-D 8,8 0 0320
+Ð "
+~N 8,11 0 0321
+Ñ "
+`O 8,11 0 0322
+Ò "
+'O 8,11 0 0323
+Ó "
+^O 8,11 0 0324
+Ô "
+~O 8,11 0 0325
+Õ "
+:O 8,10 0 0326
+Ö "
+mu 6,6 0 0327
+× "
+/O 8,8 0 0330
+Ø "
+`U 7,11 0 0331
+Ù "
+'U 7,11 0 0332
+Ú "
+^U 7,11 0 0333
+Û "
+:U 7,10 0 0334
+Ü "
+'Y 7,11 0 0335
+Ý "
+TP 7,8 0 0336
+Þ "
+ss 7,8 0 0337
+ß "
+`a 6,9 0 0340
+à "
+'a 6,9 0 0341
+á "
+^a 6,9 0 0342
+â "
+~a 6,9 0 0343
+ã "
+:a 6,8 0 0344
+ä "
+oa 6,9 0 0345
+å "
+ae 9,6 0 0346
+æ "
+,c 5,6,2 0 0347
+ç "
+`e 6,9 0 0350
+è "
+'e 6,9 0 0351
+é "
+^e 6,9 0 0352
+ê "
+:e 6,8 0 0353
+ë "
+`i 3,9 0 0354
+ì "
+'i 3,9 0 0355
+í "
+^i 3,9 0 0356
+î "
+:i 3,8 0 0357
+ï "
+Sd 6,9 0 0360
+ð "
+~n 6,9 0 0361
+ñ "
+`o 6,9 0 0362
+ò "
+'o 6,9 0 0363
+ó "
+^o 6,9 0 0364
+ô "
+~o 6,9 0 0365
+õ "
+:o 6,8 0 0366
+ö "
+di 6,6 0 0367
+÷ "
+/o 8,6 0 0370
+ø "
+`u 6,9 0 0371
+ù "
+'u 6,9 0 0372
+ú "
+^u 6,9 0 0373
+û "
+:u 6,8 0 0374
+ü "
+'y 6,9,2 0 0375
+ý "
+Tp 6,8,2 0 0376
+þ "
+:y 6,8,2 0 0377
+ÿ "
diff --git a/gnu/usr.bin/groff/devX75/HI b/gnu/usr.bin/groff/devX75/HI
new file mode 100644
index 0000000..0750951
--- /dev/null
+++ b/gnu/usr.bin/groff/devX75/HI
@@ -0,0 +1,306 @@
+name HI
+spacewidth 3
+charset
+--- 3,1 0 040
+! 4,8 0 041
+" 4,8 0 042
+# 7,7 0 043
+sh "
+$ 6,8,1 0 044
+Do "
+% 9,8 0 045
+& 8,8 0 046
+' 3,8 0 047
+( 4,8,2 0 050
+) 4,8,2 0 051
+* 4,8 0 052
++ 6,6 0 053
+, 3,1,2 0 054
+\- 7,4 0 055
+. 3,1 0 056
+/ 3,8 0 057
+sl "
+0 6,8 0 060
+1 6,8 0 061
+2 6,8 0 062
+3 6,8 0 063
+4 6,8 0 064
+5 6,8 0 065
+6 6,8 0 066
+7 6,8 0 067
+8 6,8 0 070
+9 6,8 0 071
+: 3,6 0 072
+; 3,6,2 0 073
+< 6,6 0 074
+= 7,5 0 075
+eq "
+> 6,6 0 076
+? 6,8 0 077
+@ 11,8,2 0 0100
+at "
+A 7,8 0 0101
+B 7,8 0 0102
+C 8,8 0 0103
+D 8,8 0 0104
+E 7,8 0 0105
+F 6,8 0 0106
+G 8,8 0 0107
+H 8,8 0 0110
+I 3,8 0 0111
+J 5,8 0 0112
+K 7,8 0 0113
+L 5,8 0 0114
+M 9,8 0 0115
+N 8,8 0 0116
+O 8,8 0 0117
+P 7,8 0 0120
+Q 8,8,1 0 0121
+R 7,8 0 0122
+S 7,8 0 0123
+T 5,8 0 0124
+U 8,8 0 0125
+V 7,8 0 0126
+W 10,8 0 0127
+X 7,8 0 0130
+Y 7,8 0 0131
+Z 7,8 0 0132
+[ 4,8,2 0 0133
+lB "
+\ 3,8 0 0134
+rs "
+] 4,8,2 0 0135
+rB "
+^ 6,7 0 0136
+a^ "
+ha "
+_ 6,0,2 0 0137
+` 3,8 0 0140
+oq "
+a 5,6 0 0141
+b 5,8 0 0142
+c 5,6 0 0143
+d 5,8 0 0144
+e 5,6 0 0145
+f 4,8 0 0146
+g 5,6,2 0 0147
+h 6,8 0 0150
+i 2,8 0 0151
+j 2,8,2 0 0152
+k 5,8 0 0153
+l 2,8 0 0154
+m 8,6 0 0155
+n 6,6 0 0156
+o 6,6 0 0157
+p 5,6,2 0 0160
+q 5,6,2 0 0161
+r 4,6 0 0162
+s 5,6 0 0163
+t 4,8 0 0164
+u 5,6 0 0165
+v 6,6 0 0166
+w 8,6 0 0167
+x 6,6 0 0170
+y 5,6,2 0 0171
+z 5,6 0 0172
+{ 4,8,2 0 0173
+lC "
+| 3,8,2 0 0174
+or "
+ba "
+} 4,8,2 0 0175
+rC "
+~ 7,5 0 0176
+a~ "
+ap "
+ti "
+r! 4,6,2 0 0241
+¡ "
+ct 7,7,1 0 0242
+¢ "
+Po 6,8 0 0243
+£ "
+Cs 6,7 0 0244
+¤ "
+Ye 6,8 0 0245
+¥ "
+bb 3,8,2 0 0246
+¦ "
+sc 6,8,2 0 0247
+§ "
+ad 3,8 0 0250
+¨ "
+co 10,8 0 0251
+© "
+Of 5,8 0 0252
+ª "
+Fo 8,5 0 0253
+« "
+no 7,5 0 0254
+¬ "
+- 6,4 0 0255
+hy "
+­ "
+rg 10,8 0 0256
+® "
+a- 3,8 0 0257
+¯ "
+de 4,7 0 0260
+° "
++- 6,7 0 0261
+± "
+S2 3,8 0 0262
+² "
+S3 3,8 0 0263
+³ "
+aa 3,9 0 0264
+´ "
+µ 5,6,2 0 0265
+ps 6,8,2 0 0266
+¶ "
+md 3,5 0 0267
+· "
+ac 3,1,2 0 0270
+¸ "
+S1 3,8 0 0271
+¹ "
+Om 5,8 0 0272
+º "
+Fc 8,5 0 0273
+» "
+14 9,8,1 0 0274
+¼ "
+12 9,8,1 0 0275
+½ "
+34 9,8,1 0 0276
+¾ "
+r? 6,6,2 0 0277
+¿ "
+`A 7,11 0 0300
+À "
+'A 7,11 0 0301
+Á "
+^A 7,11 0 0302
+Â "
+~A 7,11 0 0303
+Ã "
+:A 7,10 0 0304
+Ä "
+oA 7,11 0 0305
+Å "
+AE 10,8 0 0306
+Æ "
+,C 8,8,2 0 0307
+Ç "
+`E 7,11 0 0310
+È "
+'E 7,11 0 0311
+É "
+^E 7,11 0 0312
+Ê "
+:E 7,10 0 0313
+Ë "
+`I 3,11 0 0314
+Ì "
+'I 3,11 0 0315
+Í "
+^I 3,11 0 0316
+Î "
+:I 3,10 0 0317
+Ï "
+-D 8,8 0 0320
+Ð "
+~N 8,11 0 0321
+Ñ "
+`O 8,11 0 0322
+Ò "
+'O 8,11 0 0323
+Ó "
+^O 8,11 0 0324
+Ô "
+~O 8,11 0 0325
+Õ "
+:O 8,10 0 0326
+Ö "
+mu 6,6 0 0327
+× "
+/O 8,8 0 0330
+Ø "
+`U 8,11 0 0331
+Ù "
+'U 8,11 0 0332
+Ú "
+^U 8,11 0 0333
+Û "
+:U 8,10 0 0334
+Ü "
+'Y 7,11 0 0335
+Ý "
+TP 7,8 0 0336
+Þ "
+ss 6,8 0 0337
+ß "
+`a 5,9 0 0340
+à "
+'a 5,9 0 0341
+á "
+^a 5,9 0 0342
+â "
+~a 5,9 0 0343
+ã "
+:a 5,8 0 0344
+ä "
+oa 5,9 0 0345
+å "
+ae 8,6 0 0346
+æ "
+,c 5,6,2 0 0347
+ç "
+`e 5,9 0 0350
+è "
+'e 5,9 0 0351
+é "
+^e 5,9 0 0352
+ê "
+:e 5,8 0 0353
+ë "
+`i 2,9 0 0354
+ì "
+'i 2,9 0 0355
+í "
+^i 2,9 0 0356
+î "
+:i 2,8 0 0357
+ï "
+Sd 6,9 0 0360
+ð "
+~n 6,9 0 0361
+ñ "
+`o 6,9 0 0362
+ò "
+'o 6,9 0 0363
+ó "
+^o 6,9 0 0364
+ô "
+~o 6,9 0 0365
+õ "
+:o 6,8 0 0366
+ö "
+di 6,6 0 0367
+÷ "
+/o 6,6 0 0370
+ø "
+`u 5,9 0 0371
+ù "
+'u 5,9 0 0372
+ú "
+^u 5,9 0 0373
+û "
+:u 5,8 0 0374
+ü "
+'y 5,9,2 0 0375
+ý "
+Tp 5,8,2 0 0376
+þ "
+:y 5,8,2 0 0377
+ÿ "
diff --git a/gnu/usr.bin/groff/devX75/HR b/gnu/usr.bin/groff/devX75/HR
new file mode 100644
index 0000000..aeac63e
--- /dev/null
+++ b/gnu/usr.bin/groff/devX75/HR
@@ -0,0 +1,306 @@
+name HR
+spacewidth 3
+charset
+--- 3,1 0 040
+! 3,8 0 041
+" 4,8 0 042
+# 6,7 0 043
+sh "
+$ 6,8,1 0 044
+Do "
+% 9,8 0 045
+& 8,8 0 046
+' 3,8 0 047
+( 4,8,2 0 050
+) 4,8,2 0 051
+* 4,8 0 052
++ 6,6 0 053
+, 3,1,2 0 054
+\- 7,4 0 055
+. 3,1 0 056
+/ 3,8 0 057
+sl "
+0 6,8 0 060
+1 6,8 0 061
+2 6,8 0 062
+3 6,8 0 063
+4 6,8 0 064
+5 6,8 0 065
+6 6,8 0 066
+7 6,8 0 067
+8 6,8 0 070
+9 6,8 0 071
+: 3,6 0 072
+; 3,6,2 0 073
+< 6,6 0 074
+= 5,5 0 075
+eq "
+> 6,6 0 076
+? 6,8 0 077
+@ 11,8,2 0 0100
+at "
+A 7,8 0 0101
+B 7,8 0 0102
+C 8,8 0 0103
+D 8,8 0 0104
+E 7,8 0 0105
+F 6,8 0 0106
+G 8,8 0 0107
+H 8,8 0 0110
+I 3,8 0 0111
+J 5,8 0 0112
+K 7,8 0 0113
+L 6,8 0 0114
+M 9,8 0 0115
+N 8,8 0 0116
+O 8,8 0 0117
+P 7,8 0 0120
+Q 8,8,1 0 0121
+R 7,8 0 0122
+S 7,8 0 0123
+T 5,8 0 0124
+U 8,8 0 0125
+V 7,8 0 0126
+W 9,8 0 0127
+X 7,8 0 0130
+Y 7,8 0 0131
+Z 7,8 0 0132
+[ 3,8,2 0 0133
+lB "
+\ 3,8 0 0134
+rs "
+] 3,8,2 0 0135
+rB "
+^ 6,8 0 0136
+a^ "
+ha "
+_ 6,0,2 0 0137
+` 3,8 0 0140
+oq "
+a 5,6 0 0141
+b 6,8 0 0142
+c 5,6 0 0143
+d 6,8 0 0144
+e 5,6 0 0145
+f 4,8 0 0146
+g 6,6,2 0 0147
+h 6,8 0 0150
+i 2,8 0 0151
+j 2,8,1 0 0152
+k 5,8 0 0153
+l 2,8 0 0154
+m 8,6 0 0155
+n 6,6 0 0156
+o 6,6 0 0157
+p 6,6,2 0 0160
+q 6,6,2 0 0161
+r 4,6 0 0162
+s 5,6 0 0163
+t 4,8 0 0164
+u 5,6 0 0165
+v 6,6 0 0166
+w 8,6 0 0167
+x 6,6 0 0170
+y 5,6,2 0 0171
+z 5,6 0 0172
+{ 3,8,2 0 0173
+lC "
+| 3,8,2 0 0174
+or "
+ba "
+} 3,8,2 0 0175
+rC "
+~ 7,5 0 0176
+a~ "
+ap "
+ti "
+r! 3,6,2 0 0241
+¡ "
+ct 6,7,1 0 0242
+¢ "
+Po 6,8 0 0243
+£ "
+Cs 5,7 0 0244
+¤ "
+Ye 6,8 0 0245
+¥ "
+bb 3,8,2 0 0246
+¦ "
+sc 6,8,2 0 0247
+§ "
+ad 3,8 0 0250
+¨ "
+co 9,7 0 0251
+© "
+Of 4,8 0 0252
+ª "
+Fo 6,5 0 0253
+« "
+no 7,5 0 0254
+¬ "
+- 4,4 0 0255
+hy "
+­ "
+rg 9,7 0 0256
+® "
+a- 3,8 0 0257
+¯ "
+de 4,7 0 0260
+° "
++- 6,7 0 0261
+± "
+S2 3,7 0 0262
+² "
+S3 3,7 0 0263
+³ "
+aa 3,8 0 0264
+´ "
+µ 5,6,2 0 0265
+ps 6,8,2 0 0266
+¶ "
+md 3,4 0 0267
+· "
+ac 3,0,2 0 0270
+¸ "
+S1 3,7 0 0271
+¹ "
+Om 4,8 0 0272
+º "
+Fc 6,5 0 0273
+» "
+14 9,8 0 0274
+¼ "
+12 9,8 0 0275
+½ "
+34 9,8 0 0276
+¾ "
+r? 6,6,2 0 0277
+¿ "
+`A 7,11 0 0300
+À "
+'A 7,11 0 0301
+Á "
+^A 7,11 0 0302
+Â "
+~A 7,11 0 0303
+Ã "
+:A 7,10 0 0304
+Ä "
+oA 7,11 0 0305
+Å "
+AE 10,8 0 0306
+Æ "
+,C 8,8,2 0 0307
+Ç "
+`E 7,11 0 0310
+È "
+'E 7,11 0 0311
+É "
+^E 7,11 0 0312
+Ê "
+:E 7,10 0 0313
+Ë "
+`I 3,11 0 0314
+Ì "
+'I 3,11 0 0315
+Í "
+^I 3,11 0 0316
+Î "
+:I 3,10 0 0317
+Ï "
+-D 8,8 0 0320
+Ð "
+~N 8,11 0 0321
+Ñ "
+`O 8,11 0 0322
+Ò "
+'O 8,11 0 0323
+Ó "
+^O 8,11 0 0324
+Ô "
+~O 8,11 0 0325
+Õ "
+:O 8,10 0 0326
+Ö "
+mu 6,6 0 0327
+× "
+/O 8,9,1 0 0330
+Ø "
+`U 8,11 0 0331
+Ù "
+'U 8,11 0 0332
+Ú "
+^U 8,11 0 0333
+Û "
+:U 8,10 0 0334
+Ü "
+'Y 7,11 0 0335
+Ý "
+TP 7,8 0 0336
+Þ "
+ss 5,8 0 0337
+ß "
+`a 5,9 0 0340
+à "
+'a 5,9 0 0341
+á "
+^a 5,9 0 0342
+â "
+~a 5,9 0 0343
+ã "
+:a 5,8 0 0344
+ä "
+oa 5,9 0 0345
+å "
+ae 8,6 0 0346
+æ "
+,c 5,6,2 0 0347
+ç "
+`e 5,9 0 0350
+è "
+'e 5,9 0 0351
+é "
+^e 5,9 0 0352
+ê "
+:e 5,8 0 0353
+ë "
+`i 2,9 0 0354
+ì "
+'i 2,9 0 0355
+í "
+^i 2,9 0 0356
+î "
+:i 2,8 0 0357
+ï "
+Sd 6,9 0 0360
+ð "
+~n 5,9 0 0361
+ñ "
+`o 6,9 0 0362
+ò "
+'o 6,9 0 0363
+ó "
+^o 6,9 0 0364
+ô "
+~o 6,9 0 0365
+õ "
+:o 6,8 0 0366
+ö "
+di 6,6 0 0367
+÷ "
+/o 6,6 0 0370
+ø "
+`u 5,9 0 0371
+ù "
+'u 5,9 0 0372
+ú "
+^u 5,9 0 0373
+û "
+:u 5,8 0 0374
+ü "
+'y 5,9,2 0 0375
+ý "
+Tp 6,8,2 0 0376
+þ "
+:y 5,8,2 0 0377
+ÿ "
diff --git a/gnu/usr.bin/groff/devX75/Makefile b/gnu/usr.bin/groff/devX75/Makefile
new file mode 100644
index 0000000..e53468a
--- /dev/null
+++ b/gnu/usr.bin/groff/devX75/Makefile
@@ -0,0 +1,10 @@
+# Makefile for devX75
+
+DEVICE= X75
+FONTFILES= CB CBI CI CR HB HBI HI HR NB NBI NI NR S TB TBI TI TR DESC
+
+NOOBJ= noobj
+
+clean cleandir:
+
+.include "../Makefile.dev"
diff --git a/gnu/usr.bin/groff/devX75/Makefile.sub b/gnu/usr.bin/groff/devX75/Makefile.sub
new file mode 100644
index 0000000..2a90fca
--- /dev/null
+++ b/gnu/usr.bin/groff/devX75/Makefile.sub
@@ -0,0 +1,2 @@
+DEV=X75
+DEVFILES=DESC TR TI TB TBI CR CI CB CBI HR HI HB HBI NR NI NB NBI S
diff --git a/gnu/usr.bin/groff/devX75/NB b/gnu/usr.bin/groff/devX75/NB
new file mode 100644
index 0000000..d783d02
--- /dev/null
+++ b/gnu/usr.bin/groff/devX75/NB
@@ -0,0 +1,306 @@
+name NB
+spacewidth 2
+charset
+--- 2,1 0 040
+! 3,8 0 041
+" 6,8 0 042
+# 8,8 0 043
+sh "
+$ 6,9,1 0 044
+Do "
+% 11,8 0 045
+& 9,8 0 046
+' 3,8 0 047
+( 5,8,2 0 050
+) 5,8,2 0 051
+* 6,8 0 052
++ 6,6 0 053
+, 3,2,2 0 054
+\- 6,4 0 055
+. 3,2 0 056
+/ 5,8 0 057
+sl "
+0 6,8 0 060
+1 5,8 0 061
+2 6,8 0 062
+3 6,8 0 063
+4 6,8 0 064
+5 6,8 0 065
+6 6,8 0 066
+7 5,8 0 067
+8 6,8 0 070
+9 6,8 0 071
+: 3,5 0 072
+; 3,5,2 0 073
+< 7,6 0 074
+= 6,5 0 075
+eq "
+> 7,6 0 076
+? 6,8 0 077
+@ 10,8 0 0100
+at "
+A 8,8 0 0101
+B 8,8 0 0102
+C 8,8 0 0103
+D 9,8 0 0104
+E 7,8 0 0105
+F 7,8 0 0106
+G 8,8 0 0107
+H 10,8 0 0110
+I 5,8 0 0111
+J 7,8 0 0112
+K 9,8 0 0113
+L 7,8 0 0114
+M 12,8 0 0115
+N 9,8 0 0116
+O 8,8 0 0117
+P 8,8 0 0120
+Q 8,8,1 0 0121
+R 9,8 0 0122
+S 7,8 0 0123
+T 7,8 0 0124
+U 9,8 0 0125
+V 9,8 0 0126
+W 12,8 0 0127
+X 9,8 0 0130
+Y 9,8 0 0131
+Z 7,8 0 0132
+[ 4,8,2 0 0133
+lB "
+\ 5,8 0 0134
+rs "
+] 4,8,2 0 0135
+rB "
+^ 6,8 0 0136
+a^ "
+ha "
+_ 6,0,2 0 0137
+` 3,8 0 0140
+oq "
+a 5,5 0 0141
+b 7,8 0 0142
+c 6,5 0 0143
+d 7,8 0 0144
+e 6,5 0 0145
+f 5,8 0 0146
+g 6,6,2 0 0147
+h 7,8 0 0150
+i 5,8 0 0151
+j 5,8,2 0 0152
+k 6,8 0 0153
+l 5,8 0 0154
+m 11,5 0 0155
+n 7,5 0 0156
+o 7,5 0 0157
+p 7,5,2 0 0160
+q 7,5,2 0 0161
+r 5,5 0 0162
+s 5,5 0 0163
+t 4,7 0 0164
+u 7,5 0 0165
+v 7,5 0 0166
+w 10,5 0 0167
+x 7,5 0 0170
+y 7,5,2 0 0171
+z 6,5 0 0172
+{ 5,8,2 0 0173
+lC "
+| 6,8 0 0174
+or "
+ba "
+} 5,8,2 0 0175
+rC "
+~ 7,5 0 0176
+a~ "
+ap "
+ti "
+r! 3,6,2 0 0241
+¡ "
+ct 6,6,1 0 0242
+¢ "
+Po 8,8 0 0243
+£ "
+Cs 8,6 0 0244
+¤ "
+Ye 9,8 0 0245
+¥ "
+bb 6,8 0 0246
+¦ "
+sc 5,8,2 0 0247
+§ "
+ad 4,8 0 0250
+¨ "
+co 9,8 0 0251
+© "
+Of 4,8 0 0252
+ª "
+Fo 7,5 0 0253
+« "
+no 6,5 0 0254
+¬ "
+- 4,4 0 0255
+hy "
+­ "
+rg 9,8 0 0256
+® "
+a- 5,7 0 0257
+¯ "
+de 4,8 0 0260
+° "
++- 6,6 0 0261
+± "
+S2 3,8 0 0262
+² "
+S3 3,8 0 0263
+³ "
+aa 4,8 0 0264
+´ "
+µ 7,5,2 0 0265
+ps 8,8 0 0266
+¶ "
+md 3,5 0 0267
+· "
+ac 4,1,2 0 0270
+¸ "
+S1 3,8 0 0271
+¹ "
+Om 5,8 0 0272
+º "
+Fc 7,5 0 0273
+» "
+14 9,8 0 0274
+¼ "
+12 9,8 0 0275
+½ "
+34 9,8 0 0276
+¾ "
+r? 6,6,2 0 0277
+¿ "
+`A 8,11 0 0300
+À "
+'A 8,11 0 0301
+Á "
+^A 8,11 0 0302
+Â "
+~A 8,11 0 0303
+Ã "
+:A 8,11 0 0304
+Ä "
+oA 8,11 0 0305
+Å "
+AE 11,8 0 0306
+Æ "
+,C 8,8,2 0 0307
+Ç "
+`E 7,11 0 0310
+È "
+'E 7,11 0 0311
+É "
+^E 7,11 0 0312
+Ê "
+:E 7,11 0 0313
+Ë "
+`I 5,11 0 0314
+Ì "
+'I 5,11 0 0315
+Í "
+^I 5,11 0 0316
+Î "
+:I 5,11 0 0317
+Ï "
+-D 9,8 0 0320
+Ð "
+~N 9,11 0 0321
+Ñ "
+`O 8,11 0 0322
+Ò "
+'O 8,11 0 0323
+Ó "
+^O 8,11 0 0324
+Ô "
+~O 8,11 0 0325
+Õ "
+:O 8,11 0 0326
+Ö "
+mu 6,6 0 0327
+× "
+/O 8,8 0 0330
+Ø "
+`U 9,11 0 0331
+Ù "
+'U 9,11 0 0332
+Ú "
+^U 9,11 0 0333
+Û "
+:U 9,11 0 0334
+Ü "
+'Y 9,11 0 0335
+Ý "
+TP 8,8 0 0336
+Þ "
+ss 8,8 0 0337
+ß "
+`a 5,8 0 0340
+à "
+'a 5,8 0 0341
+á "
+^a 5,9 0 0342
+â "
+~a 5,8 0 0343
+ã "
+:a 5,8 0 0344
+ä "
+oa 5,8 0 0345
+å "
+ae 9,5 0 0346
+æ "
+,c 6,5,2 0 0347
+ç "
+`e 6,8 0 0350
+è "
+'e 6,8 0 0351
+é "
+^e 6,9 0 0352
+ê "
+:e 6,8 0 0353
+ë "
+`i 5,8 0 0354
+ì "
+'i 5,8 0 0355
+í "
+^i 5,9 0 0356
+î "
+:i 5,8 0 0357
+ï "
+Sd 7,8 0 0360
+ð "
+~n 7,8 0 0361
+ñ "
+`o 7,8 0 0362
+ò "
+'o 7,8 0 0363
+ó "
+^o 7,9 0 0364
+ô "
+~o 7,8 0 0365
+õ "
+:o 7,8 0 0366
+ö "
+di 6,6 0 0367
+÷ "
+/o 7,6,1 0 0370
+ø "
+`u 7,8 0 0371
+ù "
+'u 7,8 0 0372
+ú "
+^u 7,9 0 0373
+û "
+:u 7,8 0 0374
+ü "
+'y 7,8,2 0 0375
+ý "
+Tp 7,8,2 0 0376
+þ "
+:y 7,8,2 0 0377
+ÿ "
diff --git a/gnu/usr.bin/groff/devX75/NBI b/gnu/usr.bin/groff/devX75/NBI
new file mode 100644
index 0000000..bdad105
--- /dev/null
+++ b/gnu/usr.bin/groff/devX75/NBI
@@ -0,0 +1,306 @@
+name NBI
+spacewidth 2
+charset
+--- 2,1 0 040
+! 5,8 0 041
+" 6,8 0 042
+# 8,7 0 043
+sh "
+$ 6,9,1 0 044
+Do "
+% 11,8 0 045
+& 10,8 0 046
+' 3,8 0 047
+( 4,8,1 0 050
+) 5,8,1 0 051
+* 6,8 0 052
++ 6,6 0 053
+, 3,2,2 0 054
+\- 7,4 0 055
+. 3,2 0 056
+/ 5,8 0 057
+sl "
+0 6,8 0 060
+1 6,8 0 061
+2 6,8 0 062
+3 6,8 0 063
+4 6,8 0 064
+5 6,8 0 065
+6 6,8 0 066
+7 6,8 0 067
+8 6,8 0 070
+9 6,8 0 071
+: 4,5 0 072
+; 4,5,2 0 073
+< 7,6 0 074
+= 6,5 0 075
+eq "
+> 7,6 0 076
+? 6,8 0 077
+@ 11,8 0 0100
+at "
+A 8,8 0 0101
+B 8,8 0 0102
+C 7,8 0 0103
+D 9,8 0 0104
+E 8,8 0 0105
+F 7,8 0 0106
+G 8,8 0 0107
+H 10,8 0 0110
+I 6,8 0 0111
+J 7,8 0 0112
+K 10,8 0 0113
+L 7,8 0 0114
+M 11,8 0 0115
+N 8,8 0 0116
+O 8,8 0 0117
+P 8,8 0 0120
+Q 8,8,2 0 0121
+R 9,8 0 0122
+S 7,8 0 0123
+T 7,8 0 0124
+U 8,8 0 0125
+V 8,8 0 0126
+W 11,8 0 0127
+X 8,8 0 0130
+Y 7,8 0 0131
+Z 8,8 0 0132
+[ 5,8,1 0 0133
+lB "
+\ 5,8 0 0134
+rs "
+] 5,8,1 0 0135
+rB "
+^ 6,8 0 0136
+a^ "
+ha "
+_ 7,0,2 0 0137
+` 3,8 0 0140
+oq "
+a 7,5 0 0141
+b 7,8 0 0142
+c 6,5 0 0143
+d 7,8 0 0144
+e 6,5 0 0145
+f 5,8,2 0 0146
+g 6,6,2 0 0147
+h 7,8 0 0150
+i 4,8 0 0151
+j 4,8,2 0 0152
+k 7,8 0 0153
+l 4,8 0 0154
+m 10,5 0 0155
+n 7,5 0 0156
+o 6,5 0 0157
+p 7,5,2 0 0160
+q 7,5,2 0 0161
+r 5,5 0 0162
+s 4,5 0 0163
+t 4,7 0 0164
+u 7,5 0 0165
+v 6,5 0 0166
+w 10,5 0 0167
+x 7,5 0 0170
+y 7,5,2 0 0171
+z 5,5 0 0172
+{ 5,8,1 0 0173
+lC "
+| 6,8 0 0174
+or "
+ba "
+} 5,8,1 0 0175
+rC "
+~ 7,5 0 0176
+a~ "
+ap "
+ti "
+r! 4,6,2 0 0241
+¡ "
+ct 6,6,1 0 0242
+¢ "
+Po 7,8 0 0243
+£ "
+Cs 7,7 0 0244
+¤ "
+Ye 7,8 0 0245
+¥ "
+bb 6,8 0 0246
+¦ "
+sc 6,8,2 0 0247
+§ "
+ad 4,8 0 0250
+¨ "
+co 9,8 0 0251
+© "
+Of 6,8 0 0252
+ª "
+Fo 8,5 0 0253
+« "
+no 6,5 0 0254
+¬ "
+- 4,4 0 0255
+hy "
+­ "
+rg 9,8 0 0256
+® "
+a- 5,7 0 0257
+¯ "
+de 4,8 0 0260
+° "
++- 6,6 0 0261
+± "
+S2 3,8 0 0262
+² "
+S3 3,8 0 0263
+³ "
+aa 4,8 0 0264
+´ "
+µ 7,5,2 0 0265
+ps 8,8 0 0266
+¶ "
+md 3,5 0 0267
+· "
+ac 4,1,2 0 0270
+¸ "
+S1 3,8 0 0271
+¹ "
+Om 5,8 0 0272
+º "
+Fc 8,5 0 0273
+» "
+14 9,8 0 0274
+¼ "
+12 9,8 0 0275
+½ "
+34 9,8 0 0276
+¾ "
+r? 6,6,2 0 0277
+¿ "
+`A 8,11 0 0300
+À "
+'A 8,11 0 0301
+Á "
+^A 8,11 0 0302
+Â "
+~A 8,11 0 0303
+Ã "
+:A 8,11 0 0304
+Ä "
+oA 8,11 0 0305
+Å "
+AE 10,8 0 0306
+Æ "
+,C 7,8,2 0 0307
+Ç "
+`E 8,11 0 0310
+È "
+'E 8,11 0 0311
+É "
+^E 8,11 0 0312
+Ê "
+:E 8,11 0 0313
+Ë "
+`I 6,11 0 0314
+Ì "
+'I 6,11 0 0315
+Í "
+^I 6,11 0 0316
+Î "
+:I 6,11 0 0317
+Ï "
+-D 9,8 0 0320
+Ð "
+~N 8,11 0 0321
+Ñ "
+`O 8,11 0 0322
+Ò "
+'O 8,11 0 0323
+Ó "
+^O 8,11 0 0324
+Ô "
+~O 8,11 0 0325
+Õ "
+:O 8,11 0 0326
+Ö "
+mu 6,6 0 0327
+× "
+/O 8,8 0 0330
+Ø "
+`U 8,11 0 0331
+Ù "
+'U 8,11 0 0332
+Ú "
+^U 8,11 0 0333
+Û "
+:U 8,11 0 0334
+Ü "
+'Y 7,11 0 0335
+Ý "
+TP 8,8 0 0336
+Þ "
+ss 8,8,2 0 0337
+ß "
+`a 7,8 0 0340
+à "
+'a 7,8 0 0341
+á "
+^a 7,8 0 0342
+â "
+~a 7,8 0 0343
+ã "
+:a 7,8 0 0344
+ä "
+oa 7,9 0 0345
+å "
+ae 9,5 0 0346
+æ "
+,c 6,5,2 0 0347
+ç "
+`e 6,8 0 0350
+è "
+'e 6,8 0 0351
+é "
+^e 6,8 0 0352
+ê "
+:e 6,8 0 0353
+ë "
+`i 4,8 0 0354
+ì "
+'i 4,8 0 0355
+í "
+^i 4,8 0 0356
+î "
+:i 4,8 0 0357
+ï "
+Sd 6,8 0 0360
+ð "
+~n 7,8 0 0361
+ñ "
+`o 6,8 0 0362
+ò "
+'o 6,8 0 0363
+ó "
+^o 6,8 0 0364
+ô "
+~o 6,8 0 0365
+õ "
+:o 6,8 0 0366
+ö "
+di 6,6 0 0367
+÷ "
+/o 6,5 0 0370
+ø "
+`u 7,8 0 0371
+ù "
+'u 7,8 0 0372
+ú "
+^u 7,8 0 0373
+û "
+:u 7,8 0 0374
+ü "
+'y 7,8,2 0 0375
+ý "
+Tp 7,8,2 0 0376
+þ "
+:y 7,8,2 0 0377
+ÿ "
diff --git a/gnu/usr.bin/groff/devX75/NI b/gnu/usr.bin/groff/devX75/NI
new file mode 100644
index 0000000..20c2c42
--- /dev/null
+++ b/gnu/usr.bin/groff/devX75/NI
@@ -0,0 +1,306 @@
+name NI
+spacewidth 2
+charset
+--- 2,1 0 040
+! 4,8 0 041
+" 6,8 0 042
+# 8,7 0 043
+sh "
+$ 5,9,1 0 044
+Do "
+% 9,8 0 045
+& 9,8 0 046
+' 3,8 0 047
+( 5,8,1 0 050
+) 5,8,1 0 051
+* 6,8 0 052
++ 6,5 0 053
+, 2,2,1 0 054
+\- 6,3 0 055
+. 2,2 0 056
+/ 5,8,1 0 057
+sl "
+0 5,8 0 060
+1 5,8 0 061
+2 5,8 0 062
+3 5,8 0 063
+4 5,8 0 064
+5 5,8 0 065
+6 5,8 0 066
+7 5,8 0 067
+8 5,8 0 070
+9 5,8 0 071
+: 3,5 0 072
+; 3,5,1 0 073
+< 7,5 0 074
+= 6,4 0 075
+eq "
+> 7,5 0 076
+? 6,8 0 077
+@ 9,8 0 0100
+at "
+A 8,8 0 0101
+B 7,8 0 0102
+C 6,8 0 0103
+D 8,8 0 0104
+E 7,8 0 0105
+F 7,8 0 0106
+G 8,8 0 0107
+H 9,8 0 0110
+I 5,8 0 0111
+J 5,8 0 0112
+K 8,8 0 0113
+L 7,8 0 0114
+M 12,8 0 0115
+N 9,8 0 0116
+O 7,8 0 0117
+P 7,8 0 0120
+Q 7,8,2 0 0121
+R 8,8 0 0122
+S 7,8 0 0123
+T 7,8 0 0124
+U 7,8 0 0125
+V 8,8 0 0126
+W 11,8 0 0127
+X 8,8 0 0130
+Y 8,8 0 0131
+Z 8,8 0 0132
+[ 5,8,1 0 0133
+lB "
+\ 5,8 0 0134
+rs "
+] 5,8,1 0 0135
+rB "
+^ 6,8 0 0136
+a^ "
+ha "
+_ 7,0,2 0 0137
+` 3,8 0 0140
+oq "
+a 6,5 0 0141
+b 6,8 0 0142
+c 5,5 0 0143
+d 6,8 0 0144
+e 5,5 0 0145
+f 4,8,2 0 0146
+g 5,6,2 0 0147
+h 6,8 0 0150
+i 3,8 0 0151
+j 3,8,2 0 0152
+k 6,8 0 0153
+l 3,8 0 0154
+m 9,5 0 0155
+n 6,5 0 0156
+o 6,5 0 0157
+p 6,5,2 0 0160
+q 6,5,2 0 0161
+r 5,5 0 0162
+s 4,5 0 0163
+t 3,7 0 0164
+u 6,5 0 0165
+v 6,5 0 0166
+w 9,5 0 0167
+x 6,5 0 0170
+y 6,5,2 0 0171
+z 6,5 0 0172
+{ 5,8,1 0 0173
+lC "
+| 6,8 0 0174
+or "
+ba "
+} 5,8,1 0 0175
+rC "
+~ 7,4 0 0176
+a~ "
+ap "
+ti "
+r! 4,6,2 0 0241
+¡ "
+ct 5,6,1 0 0242
+¢ "
+Po 6,8 0 0243
+£ "
+Cs 8,8 0 0244
+¤ "
+Ye 8,8 0 0245
+¥ "
+bb 6,8 0 0246
+¦ "
+sc 6,8,1 0 0247
+§ "
+ad 4,7 0 0250
+¨ "
+co 9,8 0 0251
+© "
+Of 5,8 0 0252
+ª "
+Fo 6,5 0 0253
+« "
+no 6,4 0 0254
+¬ "
+- 4,3 0 0255
+hy "
+­ "
+rg 9,8 0 0256
+® "
+a- 4,7 0 0257
+¯ "
+de 4,8 0 0260
+° "
++- 6,5 0 0261
+± "
+S2 3,8 0 0262
+² "
+S3 3,8 0 0263
+³ "
+aa 3,8 0 0264
+´ "
+µ 6,5,2 0 0265
+ps 8,8 0 0266
+¶ "
+md 3,4 0 0267
+· "
+ac 4,1,2 0 0270
+¸ "
+S1 3,8 0 0271
+¹ "
+Om 4,8 0 0272
+º "
+Fc 6,5 0 0273
+» "
+14 7,8 0 0274
+¼ "
+12 7,8 0 0275
+½ "
+34 7,8 0 0276
+¾ "
+r? 6,6,2 0 0277
+¿ "
+`A 8,11 0 0300
+À "
+'A 8,11 0 0301
+Á "
+^A 8,11 0 0302
+Â "
+~A 8,11 0 0303
+Ã "
+:A 8,10 0 0304
+Ä "
+oA 8,11 0 0305
+Å "
+AE 10,8 0 0306
+Æ "
+,C 6,8,2 0 0307
+Ç "
+`E 7,11 0 0310
+È "
+'E 7,11 0 0311
+É "
+^E 7,11 0 0312
+Ê "
+:E 7,10 0 0313
+Ë "
+`I 5,11 0 0314
+Ì "
+'I 5,11 0 0315
+Í "
+^I 5,11 0 0316
+Î "
+:I 5,10 0 0317
+Ï "
+-D 8,8 0 0320
+Ð "
+~N 9,11 0 0321
+Ñ "
+`O 7,11 0 0322
+Ò "
+'O 7,11 0 0323
+Ó "
+^O 7,11 0 0324
+Ô "
+~O 7,11 0 0325
+Õ "
+:O 7,10 0 0326
+Ö "
+mu 6,5 0 0327
+× "
+/O 7,8 0 0330
+Ø "
+`U 7,11 0 0331
+Ù "
+'U 7,11 0 0332
+Ú "
+^U 7,11 0 0333
+Û "
+:U 7,10 0 0334
+Ü "
+'Y 8,10 0 0335
+Ý "
+TP 7,8 0 0336
+Þ "
+ss 7,8,2 0 0337
+ß "
+`a 6,8 0 0340
+à "
+'a 6,8 0 0341
+á "
+^a 6,8 0 0342
+â "
+~a 6,8 0 0343
+ã "
+:a 6,7 0 0344
+ä "
+oa 6,9 0 0345
+å "
+ae 8,5 0 0346
+æ "
+,c 5,5,2 0 0347
+ç "
+`e 5,8 0 0350
+è "
+'e 5,8 0 0351
+é "
+^e 5,8 0 0352
+ê "
+:e 5,7 0 0353
+ë "
+`i 3,8 0 0354
+ì "
+'i 3,8 0 0355
+í "
+^i 3,8 0 0356
+î "
+:i 3,7 0 0357
+ï "
+Sd 6,8 0 0360
+ð "
+~n 6,8 0 0361
+ñ "
+`o 6,8 0 0362
+ò "
+'o 6,8 0 0363
+ó "
+^o 6,8 0 0364
+ô "
+~o 6,8 0 0365
+õ "
+:o 6,7 0 0366
+ö "
+di 6,5 0 0367
+÷ "
+/o 6,5 0 0370
+ø "
+`u 6,8 0 0371
+ù "
+'u 6,8 0 0372
+ú "
+^u 6,8 0 0373
+û "
+:u 6,7 0 0374
+ü "
+'y 6,8,2 0 0375
+ý "
+Tp 6,8,2 0 0376
+þ "
+:y 6,7,2 0 0377
+ÿ "
diff --git a/gnu/usr.bin/groff/devX75/NR b/gnu/usr.bin/groff/devX75/NR
new file mode 100644
index 0000000..aa05125
--- /dev/null
+++ b/gnu/usr.bin/groff/devX75/NR
@@ -0,0 +1,306 @@
+name NR
+spacewidth 2
+charset
+--- 2,1 0 040
+! 4,8 0 041
+" 6,8 0 042
+# 8,8 0 043
+sh "
+$ 5,9,1 0 044
+Do "
+% 9,8 0 045
+& 10,8 0 046
+' 3,8 0 047
+( 4,8,1 0 050
+) 4,8,1 0 051
+* 6,8 0 052
++ 6,5 0 053
+, 3,2,1 0 054
+\- 6,3 0 055
+. 4,2 0 056
+/ 4,8 0 057
+sl "
+0 5,8 0 060
+1 5,8 0 061
+2 5,8 0 062
+3 5,8 0 063
+4 5,8 0 064
+5 5,8 0 065
+6 5,8 0 066
+7 5,8 0 067
+8 5,8 0 070
+9 5,8 0 071
+: 4,5 0 072
+; 4,5,1 0 073
+< 7,5 0 074
+= 6,4 0 075
+eq "
+> 7,5 0 076
+? 5,8 0 077
+@ 9,8 0 0100
+at "
+A 8,8 0 0101
+B 7,8 0 0102
+C 7,8 0 0103
+D 8,8 0 0104
+E 7,8 0 0105
+F 7,8 0 0106
+G 8,8 0 0107
+H 9,8 0 0110
+I 4,8 0 0111
+J 5,8 0 0112
+K 8,8 0 0113
+L 7,8 0 0114
+M 10,8 0 0115
+N 9,8 0 0116
+O 8,8 0 0117
+P 7,8 0 0120
+Q 8,8,1 0 0121
+R 8,8 0 0122
+S 6,8 0 0123
+T 8,8 0 0124
+U 8,8 0 0125
+V 8,8 0 0126
+W 12,8 0 0127
+X 7,8 0 0130
+Y 8,8 0 0131
+Z 6,8 0 0132
+[ 3,8,1 0 0133
+lB "
+\ 5,8 0 0134
+rs "
+] 3,8,1 0 0135
+rB "
+^ 6,8 0 0136
+a^ "
+ha "
+_ 6,0,2 0 0137
+` 3,8 0 0140
+oq "
+a 6,5 0 0141
+b 5,8 0 0142
+c 5,5 0 0143
+d 6,8 0 0144
+e 5,5 0 0145
+f 4,8 0 0146
+g 6,5,2 0 0147
+h 6,8 0 0150
+i 4,7 0 0151
+j 4,7,2 0 0152
+k 7,8 0 0153
+l 4,8 0 0154
+m 10,5 0 0155
+n 7,5 0 0156
+o 5,5 0 0157
+p 5,5,2 0 0160
+q 6,5,2 0 0161
+r 5,5 0 0162
+s 5,5 0 0163
+t 3,7 0 0164
+u 6,5 0 0165
+v 6,5 0 0166
+w 8,5 0 0167
+x 6,5 0 0170
+y 6,5,2 0 0171
+z 5,5 0 0172
+{ 4,8,1 0 0173
+lC "
+| 6,8 0 0174
+or "
+ba "
+} 4,8,1 0 0175
+rC "
+~ 7,4 0 0176
+a~ "
+ap "
+ti "
+r! 4,6,2 0 0241
+¡ "
+ct 6,6,1 0 0242
+¢ "
+Po 7,8 0 0243
+£ "
+Cs 7,7 0 0244
+¤ "
+Ye 8,8 0 0245
+¥ "
+bb 6,8 0 0246
+¦ "
+sc 5,8,2 0 0247
+§ "
+ad 4,7 0 0250
+¨ "
+co 10,8 0 0251
+© "
+Of 5,8 0 0252
+ª "
+Fo 6,4 0 0253
+« "
+no 6,4 0 0254
+¬ "
+- 4,3 0 0255
+hy "
+­ "
+rg 10,8 0 0256
+® "
+a- 5,7 0 0257
+¯ "
+de 4,8 0 0260
+° "
++- 6,5 0 0261
+± "
+S2 3,8 0 0262
+² "
+S3 3,8 0 0263
+³ "
+aa 3,8 0 0264
+´ "
+µ 6,5,2 0 0265
+ps 7,8,2 0 0266
+¶ "
+md 4,4 0 0267
+· "
+ac 3,1,2 0 0270
+¸ "
+S1 3,8 0 0271
+¹ "
+Om 5,8 0 0272
+º "
+Fc 6,4 0 0273
+» "
+14 7,8 0 0274
+¼ "
+12 7,8 0 0275
+½ "
+34 7,8 0 0276
+¾ "
+r? 5,6,2 0 0277
+¿ "
+`A 8,11 0 0300
+À "
+'A 8,11 0 0301
+Á "
+^A 8,11 0 0302
+Â "
+~A 8,11 0 0303
+Ã "
+:A 8,10 0 0304
+Ä "
+oA 8,11 0 0305
+Å "
+AE 11,8 0 0306
+Æ "
+,C 7,8,2 0 0307
+Ç "
+`E 7,11 0 0310
+È "
+'E 7,11 0 0311
+É "
+^E 7,11 0 0312
+Ê "
+:E 7,10 0 0313
+Ë "
+`I 4,11 0 0314
+Ì "
+'I 4,11 0 0315
+Í "
+^I 4,11 0 0316
+Î "
+:I 4,10 0 0317
+Ï "
+-D 8,8 0 0320
+Ð "
+~N 9,11 0 0321
+Ñ "
+`O 8,11 0 0322
+Ò "
+'O 8,11 0 0323
+Ó "
+^O 8,11 0 0324
+Ô "
+~O 8,11 0 0325
+Õ "
+:O 8,10 0 0326
+Ö "
+mu 6,5 0 0327
+× "
+/O 8,8 0 0330
+Ø "
+`U 8,11 0 0331
+Ù "
+'U 8,11 0 0332
+Ú "
+^U 8,11 0 0333
+Û "
+:U 8,10 0 0334
+Ü "
+'Y 8,10 0 0335
+Ý "
+TP 7,8 0 0336
+Þ "
+ss 7,8 0 0337
+ß "
+`a 6,8 0 0340
+à "
+'a 6,8 0 0341
+á "
+^a 6,8 0 0342
+â "
+~a 6,8 0 0343
+ã "
+:a 6,7 0 0344
+ä "
+oa 6,8 0 0345
+å "
+ae 8,5 0 0346
+æ "
+,c 5,5,2 0 0347
+ç "
+`e 5,8 0 0350
+è "
+'e 5,8 0 0351
+é "
+^e 5,8 0 0352
+ê "
+:e 5,7 0 0353
+ë "
+`i 4,8 0 0354
+ì "
+'i 4,8 0 0355
+í "
+^i 4,8 0 0356
+î "
+:i 4,7 0 0357
+ï "
+Sd 5,8 0 0360
+ð "
+~n 7,8 0 0361
+ñ "
+`o 5,8 0 0362
+ò "
+'o 5,8 0 0363
+ó "
+^o 5,8 0 0364
+ô "
+~o 5,8 0 0365
+õ "
+:o 5,7 0 0366
+ö "
+di 6,5 0 0367
+÷ "
+/o 5,5,1 0 0370
+ø "
+`u 6,8 0 0371
+ù "
+'u 6,8 0 0372
+ú "
+^u 6,8 0 0373
+û "
+:u 6,7 0 0374
+ü "
+'y 6,8,2 0 0375
+ý "
+Tp 5,8,2 0 0376
+þ "
+:y 6,7,2 0 0377
+ÿ "
diff --git a/gnu/usr.bin/groff/devX75/S b/gnu/usr.bin/groff/devX75/S
new file mode 100644
index 0000000..b1cfbbf
--- /dev/null
+++ b/gnu/usr.bin/groff/devX75/S
@@ -0,0 +1,226 @@
+name S
+special
+spacewidth 3
+charset
+--- 3,1 0 040
+! 3,7 0 041
+fa 7,7 0 042
+# 5,7 0 043
+sh "
+te 6,7 0 044
+% 8,7 0 045
+& 7,7 0 046
+st 5,5 0 047
+( 4,7,2 0 050
+) 4,7,2 0 051
+** 5,6 0 052
++ 6,5 0 053
+pl "
+, 2,1,2 0 054
+\- 6,3 0 055
+mi "
+. 2,2 0 056
+/ 3,7 0 057
+sl "
+0 5,7 0 060
+1 5,7 0 061
+2 5,7 0 062
+3 5,7 0 063
+4 5,7 0 064
+5 5,7 0 065
+6 5,7 0 066
+7 5,7 0 067
+8 5,7 0 070
+9 5,7 0 071
+: 2,5 0 072
+; 2,5,2 0 073
+< 7,5 0 074
+= 6,4 0 075
+eq "
+> 6,5 0 076
+? 5,7 0 077
+=~ 6,6 0 0100
+*A 8,7 0 0101
+*B 6,7 0 0102
+*X 8,7 0 0103
+*D 7,7 0 0104
+*E 6,7 0 0105
+*F 8,7 0 0106
+*G 6,7 0 0107
+*Y 8,7 0 0110
+*I 3,7 0 0111
++h 7,7 0 0112
+*K 7,7 0 0113
+*L 7,7 0 0114
+*M 10,7 0 0115
+*N 8,7 0 0116
+*O 7,7 0 0117
+*P 8,7 0 0120
+*H 7,7 0 0121
+*R 6,7 0 0122
+*S 6,7 0 0123
+*T 6,7 0 0124
+--- 8,7 0 0125
+ts 5,5,2 0 0126
+*W 9,7 0 0127
+*C 7,7 0 0130
+*Q 9,7 0 0131
+*Z 6,7 0 0132
+[ 3,7,2 0 0133
+lB "
+tf 7,5 0 0134
+3d "
+] 3,7,2 0 0135
+rB "
+pp 7,7 0 0136
+_ 5,0,3 0 0137
+radicalex 5,10 0 0140
+*a 7,5 0 0141
+*b 5,8,2 0 0142
+*x 6,5,2 0 0143
+*d 5,8 0 0144
+*e 5,5 0 0145
+*f 6,7,2 0 0146
+*g 6,5,2 0 0147
+*y 6,5,2 0 0150
+*i 4,5 0 0151
++f 6,5,2 0 0152
+*k 6,5 0 0153
+*l 6,8 0 0154
+*m 6,5,2 0 0155
+µ "
+*n 6,5 0 0156
+*o 5,5 0 0157
+*p 6,5 0 0160
+*h 5,7 0 0161
+*r 5,5,3 0 0162
+*s 6,5 0 0163
+*t 5,5 0 0164
+*u 6,5 0 0165
++p 8,6 0 0166
+*w 8,5 0 0167
+*c 5,8,2 0 0170
+*q 7,5,2 0 0171
+*z 5,8,2 0 0172
+lC 5,7,2 0 0173
+{ "
+ba 2,7,2 0 0174
+or "
+| "
+rC 5,7,2 0 0175
+} "
+ap 6,4 0 0176
+*U 7,7 0 0241
+fm 3,8 0 0242
+<= 6,7 0 0243
+f/ 3,7 0 0244
+if 7,4 0 0245
+Fn 5,7,2 0 0246
+CL 7,5 0 0247
+DI 7,5 0 0250
+HE 7,5 0 0251
+SP 7,5 0 0252
+<> 10,5 0 0253
+<- 10,5 0 0254
+ua 6,10,4 0 0255
+arrowverttp "
+-> 10,5 0 0256
+da 6,10,2 0 0257
+arrowvertbt "
+de 4,7 0 0260
+° "
++- 6,7 0 0261
+± "
+sd 4,8 0 0262
+>= 6,7 0 0263
+mu 6,5 0 0264
+× "
+pt 7,4 0 0265
+pd 5,8 0 0266
+bu 5,4 0 0267
+di 6,5 0 0270
+÷ "
+!= 6,5 0 0271
+== 6,5 0 0272
+~= 6,5 0 0273
+~~ "
+--- 9,1 0 0274
+arrowvertex 6,10,4 0 0275
+an 10,3 0 0276
+CR 7,6 0 0277
+Ah 8,7 0 0300
+Im 7,8,1 0 0301
+Re 8,8 0 0302
+wp 9,6,2 0 0303
+c* 8,7 0 0304
+c+ 8,7 0 0305
+es 8,8,1 0 0306
+ca 8,5 0 0307
+cu 8,5 0 0310
+sp 7,5 0 0311
+ip 7,5,2 0 0312
+--- 7,6,1 0 0313
+sb 7,5 0 0314
+ib 7,5,2 0 0315
+mo 7,5 0 0316
+nm 7,6,1 0 0317
+/_ 8,7 0 0320
+gr 7,7 0 0321
+rg 8,7,1 0 0322
+co 8,7,1 0 0323
+tm 10,7 0 0324
+--- 9,8,1 0 0325
+sr 6,10 0 0326
+md 3,3 0 0327
+no 7,3 0 0330
+¬ "
+AN 6,5 0 0331
+OR 6,5 0 0332
+hA 11,5 0 0333
+lA 10,5 0 0334
+uA 6,10 0 0335
+rA 10,5 0 0336
+dA 6,10 0 0337
+lz 7,7 0 0340
+la 3,7,2 0 0341
+--- 8,7,1 0 0342
+--- 8,7,1 0 0343
+--- 9,7 0 0344
+--- 7,8,1 0 0345
+parenlefttp 4,10,4 0 0346
+parenleftex 4,10,4 0 0347
+parenleftbt 4,10,4 0 0350
+bracketlefttp 4,10,4 0 0351
+lc "
+bracketleftex 4,10,4 0 0352
+bracketleftbt 4,10,2 0 0353
+lf "
+bracelefttp 5,10,4 0 0354
+lt "
+braceleftmid 5,10,4 0 0355
+lk "
+braceleftbt 5,10,2 0 0356
+lb "
+bracerightex 5,10,4 0 0357
+braceleftex "
+bv "
+--- 8,9 0 0360
+ra 3,7,2 0 0361
+is 3,10,2 0 0362
+--- 7,10,4 0 0363
+--- 7,10,4 0 0364
+--- 7,10,2 0 0365
+parenrighttp 4,10,4 0 0366
+parenrightex 4,10,4 0 0367
+parenrightbt 4,10,4 0 0370
+bracketrighttp 4,10,4 0 0371
+rc "
+bracketrightex 4,10,4 0 0372
+bracketrightbt 4,10,2 0 0373
+rf "
+bracerighttp 5,10,4 0 0374
+rt "
+bracerightmid 5,10,4 0 0375
+rk "
+bracerightbt 5,10,2 0 0376
+rb "
diff --git a/gnu/usr.bin/groff/devX75/TB b/gnu/usr.bin/groff/devX75/TB
new file mode 100644
index 0000000..0907714
--- /dev/null
+++ b/gnu/usr.bin/groff/devX75/TB
@@ -0,0 +1,306 @@
+name TB
+spacewidth 2
+charset
+--- 2,1 0 040
+! 4,7 0 041
+" 5,7 0 042
+# 6,7 0 043
+sh "
+$ 5,8,1 0 044
+Do "
+% 9,7 0 045
+& 9,7 0 046
+' 4,7 0 047
+( 4,7,3 0 050
+) 4,7,3 0 051
+* 6,7 0 052
++ 6,5 0 053
+, 4,2,1 0 054
+\- 7,3 0 055
+. 3,2 0 056
+/ 3,7 0 057
+sl "
+0 5,7 0 060
+1 5,7 0 061
+2 5,7 0 062
+3 5,7 0 063
+4 5,7 0 064
+5 5,7 0 065
+6 5,7 0 066
+7 5,7 0 067
+8 5,7 0 070
+9 5,7 0 071
+: 4,5 0 072
+; 4,5,1 0 073
+< 6,5 0 074
+= 6,4 0 075
+eq "
+> 6,5 0 076
+? 6,7 0 077
+@ 11,7,2 0 0100
+at "
+A 7,7 0 0101
+B 7,7 0 0102
+C 7,7 0 0103
+D 8,7 0 0104
+E 7,7 0 0105
+F 7,7 0 0106
+G 7,7 0 0107
+H 9,7 0 0110
+I 5,7 0 0111
+J 5,7,1 0 0112
+K 8,7 0 0113
+L 7,7 0 0114
+M 10,7 0 0115
+N 8,7 0 0116
+O 7,7 0 0117
+P 6,7 0 0120
+Q 7,7,2 0 0121
+R 7,7 0 0122
+S 6,7 0 0123
+T 7,7 0 0124
+U 7,7 0 0125
+V 8,7 0 0126
+W 10,7 0 0127
+X 7,7 0 0130
+Y 8,7 0 0131
+Z 7,7 0 0132
+[ 4,7,3 0 0133
+lB "
+\ 3,7 0 0134
+rs "
+] 4,7,3 0 0135
+rB "
+^ 6,7 0 0136
+a^ "
+ha "
+_ 5,0,3 0 0137
+` 4,7 0 0140
+oq "
+a 5,5 0 0141
+b 5,7 0 0142
+c 5,5 0 0143
+d 6,7 0 0144
+e 5,5 0 0145
+f 3,7 0 0146
+g 5,5,3 0 0147
+h 5,7 0 0150
+i 3,8 0 0151
+j 4,8,2 0 0152
+k 5,7 0 0153
+l 3,7 0 0154
+m 8,5 0 0155
+n 6,5 0 0156
+o 6,5 0 0157
+p 5,5,2 0 0160
+q 5,5,2 0 0161
+r 4,5 0 0162
+s 4,5 0 0163
+t 4,7 0 0164
+u 5,5 0 0165
+v 5,5 0 0166
+w 6,5 0 0167
+x 5,5 0 0170
+y 5,5,2 0 0171
+z 5,5 0 0172
+{ 4,7,3 0 0173
+lC "
+| 3,7,2 0 0174
+or "
+ba "
+} 4,7,3 0 0175
+rC "
+~ 6,4 0 0176
+a~ "
+ap "
+ti "
+r! 4,4,3 0 0241
+¡ "
+ct 6,6,1 0 0242
+¢ "
+Po 6,7 0 0243
+£ "
+Cs 6,6 0 0244
+¤ "
+Ye 6,7 0 0245
+¥ "
+bb 3,7,2 0 0246
+¦ "
+sc 5,7,2 0 0247
+§ "
+ad 4,8 0 0250
+¨ "
+co 9,7 0 0251
+© "
+Of 4,7 0 0252
+ª "
+Fo 6,5 0 0253
+« "
+no 7,5 0 0254
+¬ "
+- 3,3 0 0255
+hy "
+­ "
+rg 9,7 0 0256
+® "
+a- 4,7 0 0257
+¯ "
+de 4,7 0 0260
+° "
++- 6,7 0 0261
+± "
+S2 3,7 0 0262
+² "
+S3 3,7 0 0263
+³ "
+aa 4,7 0 0264
+´ "
+µ 5,5,3 0 0265
+ps 6,7,3 0 0266
+¶ "
+md 3,4 0 0267
+· "
+ac 3,0,3 0 0270
+¸ "
+S1 3,7 0 0271
+¹ "
+Om 4,7 0 0272
+º "
+Fc 6,5 0 0273
+» "
+14 7,7 0 0274
+¼ "
+12 7,7 0 0275
+½ "
+34 7,7 0 0276
+¾ "
+r? 6,4,3 0 0277
+¿ "
+`A 7,10 0 0300
+À "
+'A 7,10 0 0301
+Á "
+^A 7,10 0 0302
+Â "
+~A 7,10 0 0303
+Ã "
+:A 7,10 0 0304
+Ä "
+oA 7,10 0 0305
+Å "
+AE 9,7 0 0306
+Æ "
+,C 7,7,3 0 0307
+Ç "
+`E 7,10 0 0310
+È "
+'E 7,10 0 0311
+É "
+^E 7,10 0 0312
+Ê "
+:E 7,10 0 0313
+Ë "
+`I 5,10 0 0314
+Ì "
+'I 5,10 0 0315
+Í "
+^I 5,10 0 0316
+Î "
+:I 5,10 0 0317
+Ï "
+-D 8,7 0 0320
+Ð "
+~N 8,10 0 0321
+Ñ "
+`O 7,10 0 0322
+Ò "
+'O 7,10 0 0323
+Ó "
+^O 7,10 0 0324
+Ô "
+~O 7,10 0 0325
+Õ "
+:O 7,10 0 0326
+Ö "
+mu 6,5 0 0327
+× "
+/O 7,8,1 0 0330
+Ø "
+`U 7,10 0 0331
+Ù "
+'U 7,10 0 0332
+Ú "
+^U 7,10 0 0333
+Û "
+:U 7,10 0 0334
+Ü "
+'Y 8,10 0 0335
+Ý "
+TP 6,7 0 0336
+Þ "
+ss 6,7 0 0337
+ß "
+`a 5,8 0 0340
+à "
+'a 5,8 0 0341
+á "
+^a 5,8 0 0342
+â "
+~a 5,8 0 0343
+ã "
+:a 5,8 0 0344
+ä "
+oa 5,8 0 0345
+å "
+ae 8,5 0 0346
+æ "
+,c 5,5,3 0 0347
+ç "
+`e 5,8 0 0350
+è "
+'e 5,8 0 0351
+é "
+^e 5,8 0 0352
+ê "
+:e 5,8 0 0353
+ë "
+`i 3,8 0 0354
+ì "
+'i 3,8 0 0355
+í "
+^i 3,8 0 0356
+î "
+:i 3,8 0 0357
+ï "
+Sd 6,8 0 0360
+ð "
+~n 6,8 0 0361
+ñ "
+`o 6,8 0 0362
+ò "
+'o 6,8 0 0363
+ó "
+^o 6,8 0 0364
+ô "
+~o 6,8 0 0365
+õ "
+:o 6,8 0 0366
+ö "
+di 6,5 0 0367
+÷ "
+/o 6,6,1 0 0370
+ø "
+`u 5,8 0 0371
+ù "
+'u 5,8 0 0372
+ú "
+^u 5,8 0 0373
+û "
+:u 5,8 0 0374
+ü "
+'y 5,8,3 0 0375
+ý "
+Tp 5,7,3 0 0376
+þ "
+:y 5,8,3 0 0377
+ÿ "
diff --git a/gnu/usr.bin/groff/devX75/TBI b/gnu/usr.bin/groff/devX75/TBI
new file mode 100644
index 0000000..37d92b0
--- /dev/null
+++ b/gnu/usr.bin/groff/devX75/TBI
@@ -0,0 +1,306 @@
+name TBI
+spacewidth 2
+charset
+--- 2,1 0 040
+! 6,7 0 041
+" 6,7 0 042
+# 8,7 0 043
+sh "
+$ 5,7 0 044
+Do "
+% 11,7 0 045
+& 8,7 0 046
+' 4,7 0 047
+( 6,7,2 0 050
+) 6,7,2 0 051
+* 7,8 0 052
++ 7,5 0 053
+, 4,2,1 0 054
+\- 7,3 0 055
+. 4,2 0 056
+/ 5,7 0 057
+sl "
+0 5,7 0 060
+1 5,7 0 061
+2 5,7 0 062
+3 5,7 0 063
+4 5,7 0 064
+5 5,7 0 065
+6 5,7 0 066
+7 5,7 0 067
+8 5,7 0 070
+9 5,7 0 071
+: 3,5 0 072
+; 5,5,1 0 073
+< 6,5 0 074
+= 7,4 0 075
+eq "
+> 6,5 0 076
+? 5,7 0 077
+@ 11,7,2 0 0100
+at "
+A 6,7 0 0101
+B 7,7 0 0102
+C 7,7 0 0103
+D 7,7 0 0104
+E 7,7 0 0105
+F 7,7 0 0106
+G 7,7 0 0107
+H 8,7 0 0110
+I 4,7 0 0111
+J 5,7,1 0 0112
+K 7,7 0 0113
+L 6,7 0 0114
+M 10,7 0 0115
+N 8,7 0 0116
+O 7,7 0 0117
+P 6,7 0 0120
+Q 7,7,2 0 0121
+R 7,7 0 0122
+S 6,7 0 0123
+T 6,7 0 0124
+U 8,7 0 0125
+V 7,7 0 0126
+W 9,7 0 0127
+X 7,7 0 0130
+Y 6,7 0 0131
+Z 6,7 0 0132
+[ 5,7,2 0 0133
+lB "
+\ 5,7 0 0134
+rs "
+] 5,7,2 0 0135
+rB "
+^ 7,7 0 0136
+a^ "
+ha "
+_ 5,0,2 0 0137
+` 4,7 0 0140
+oq "
+a 5,5 0 0141
+b 5,7 0 0142
+c 5,5 0 0143
+d 5,7 0 0144
+e 5,5 0 0145
+f 4,7,3 0 0146
+g 4,5,3 0 0147
+h 5,7 0 0150
+i 3,7 0 0151
+j 3,7,3 0 0152
+k 5,7 0 0153
+l 3,7 0 0154
+m 7,5 0 0155
+n 5,5 0 0156
+o 5,5 0 0157
+p 5,5,3 0 0160
+q 5,5,3 0 0161
+r 4,5 0 0162
+s 4,5 0 0163
+t 4,6 0 0164
+u 5,5 0 0165
+v 4,5 0 0166
+w 7,5 0 0167
+x 4,5 0 0170
+y 5,5,2 0 0171
+z 4,5 0 0172
+{ 5,7,2 0 0173
+lC "
+| 3,7 0 0174
+or "
+ba "
+} 5,7,2 0 0175
+rC "
+~ 6,4 0 0176
+a~ "
+ap "
+ti "
+r! 5,5,3 0 0241
+¡ "
+ct 5,6,1 0 0242
+¢ "
+Po 5,7 0 0243
+£ "
+Cs 7,6 0 0244
+¤ "
+Ye 5,7 0 0245
+¥ "
+bb 3,7 0 0246
+¦ "
+sc 5,7,2 0 0247
+§ "
+ad 5,7 0 0250
+¨ "
+co 9,7 0 0251
+© "
+Of 5,7 0 0252
+ª "
+Fo 8,5 0 0253
+« "
+no 7,5 0 0254
+¬ "
+- 3,3 0 0255
+hy "
+­ "
+rg 9,7 0 0256
+® "
+a- 4,7 0 0257
+¯ "
+de 4,7 0 0260
+° "
++- 7,7 0 0261
+± "
+S2 3,7 0 0262
+² "
+S3 3,7 0 0263
+³ "
+aa 4,7 0 0264
+´ "
+µ 5,5,3 0 0265
+ps 8,7,3 0 0266
+¶ "
+md 4,4 0 0267
+· "
+ac 3,0,3 0 0270
+¸ "
+S1 3,7 0 0271
+¹ "
+Om 5,7 0 0272
+º "
+Fc 8,5 0 0273
+» "
+14 7,7 0 0274
+¼ "
+12 7,7 0 0275
+½ "
+34 7,7 0 0276
+¾ "
+r? 5,5,3 0 0277
+¿ "
+`A 6,10 0 0300
+À "
+'A 6,10 0 0301
+Á "
+^A 6,10 0 0302
+Â "
+~A 6,10 0 0303
+Ã "
+:A 6,10 0 0304
+Ä "
+oA 6,10 0 0305
+Å "
+AE 9,7 0 0306
+Æ "
+,C 7,7,3 0 0307
+Ç "
+`E 7,10 0 0310
+È "
+'E 7,10 0 0311
+É "
+^E 7,10 0 0312
+Ê "
+:E 7,10 0 0313
+Ë "
+`I 4,10 0 0314
+Ì "
+'I 4,10 0 0315
+Í "
+^I 4,10 0 0316
+Î "
+:I 4,10 0 0317
+Ï "
+-D 7,7 0 0320
+Ð "
+~N 8,10 0 0321
+Ñ "
+`O 7,10 0 0322
+Ò "
+'O 7,10 0 0323
+Ó "
+^O 7,10 0 0324
+Ô "
+~O 7,10 0 0325
+Õ "
+:O 7,10 0 0326
+Ö "
+mu 7,5 0 0327
+× "
+/O 7,8,1 0 0330
+Ø "
+`U 8,10 0 0331
+Ù "
+'U 8,10 0 0332
+Ú "
+^U 8,10 0 0333
+Û "
+:U 8,10 0 0334
+Ü "
+'Y 6,10 0 0335
+Ý "
+TP 6,7 0 0336
+Þ "
+ss 6,7,3 0 0337
+ß "
+`a 5,8 0 0340
+à "
+'a 5,8 0 0341
+á "
+^a 5,8 0 0342
+â "
+~a 5,8 0 0343
+ã "
+:a 5,8 0 0344
+ä "
+oa 5,8 0 0345
+å "
+ae 8,5 0 0346
+æ "
+,c 5,5,3 0 0347
+ç "
+`e 5,8 0 0350
+è "
+'e 5,8 0 0351
+é "
+^e 5,8 0 0352
+ê "
+:e 5,8 0 0353
+ë "
+`i 3,8 0 0354
+ì "
+'i 3,8 0 0355
+í "
+^i 3,8 0 0356
+î "
+:i 3,8 0 0357
+ï "
+Sd 5,8 0 0360
+ð "
+~n 5,8 0 0361
+ñ "
+`o 5,8 0 0362
+ò "
+'o 5,8 0 0363
+ó "
+^o 5,8 0 0364
+ô "
+~o 5,8 0 0365
+õ "
+:o 5,8 0 0366
+ö "
+di 7,5 0 0367
+÷ "
+/o 5,6,1 0 0370
+ø "
+`u 5,8 0 0371
+ù "
+'u 5,8 0 0372
+ú "
+^u 5,8 0 0373
+û "
+:u 5,8 0 0374
+ü "
+'y 5,8,2 0 0375
+ý "
+Tp 5,7,3 0 0376
+þ "
+:y 5,8,2 0 0377
+ÿ "
diff --git a/gnu/usr.bin/groff/devX75/TI b/gnu/usr.bin/groff/devX75/TI
new file mode 100644
index 0000000..daa858e
--- /dev/null
+++ b/gnu/usr.bin/groff/devX75/TI
@@ -0,0 +1,306 @@
+name TI
+spacewidth 2
+charset
+--- 2,1 0 040
+! 3,7 0 041
+" 4,8 0 042
+# 5,7 0 043
+sh "
+$ 5,8,1 0 044
+Do "
+% 9,7 0 045
+& 8,7 0 046
+' 3,8 0 047
+( 3,7,2 0 050
+) 4,7,2 0 051
+* 5,7 0 052
++ 7,5 0 053
+, 3,1,2 0 054
+\- 7,3 0 055
+. 3,1 0 056
+/ 4,7 0 057
+sl "
+0 5,7 0 060
+1 5,7 0 061
+2 5,7 0 062
+3 5,7 0 063
+4 5,7 0 064
+5 5,7 0 065
+6 5,7 0 066
+7 5,7 0 067
+8 5,7 0 070
+9 5,7 0 071
+: 3,5 0 072
+; 3,5,2 0 073
+< 5,5 0 074
+= 7,4 0 075
+eq "
+> 5,5 0 076
+? 5,7 0 077
+@ 10,7,2 0 0100
+at "
+A 7,7 0 0101
+B 6,7 0 0102
+C 7,7 0 0103
+D 7,7 0 0104
+E 6,7 0 0105
+F 6,7 0 0106
+G 8,7 0 0107
+H 7,7 0 0110
+I 3,7 0 0111
+J 4,7 0 0112
+K 7,7 0 0113
+L 6,7 0 0114
+M 10,7 0 0115
+N 7,7 0 0116
+O 7,7 0 0117
+P 6,7 0 0120
+Q 7,7,2 0 0121
+R 6,7 0 0122
+S 5,7 0 0123
+T 6,7 0 0124
+U 7,7 0 0125
+V 6,7 0 0126
+W 9,7 0 0127
+X 6,7 0 0130
+Y 6,7 0 0131
+Z 6,7 0 0132
+[ 4,7,2 0 0133
+lB "
+\ 5,7 0 0134
+rs "
+] 4,7,2 0 0135
+rB "
+^ 5,7 0 0136
+a^ "
+ha "
+_ 5,0,3 0 0137
+` 3,8 0 0140
+oq "
+a 5,5 0 0141
+b 5,7 0 0142
+c 5,5 0 0143
+d 5,7 0 0144
+e 5,5 0 0145
+f 3,7,3 0 0146
+g 4,5,3 0 0147
+h 5,7 0 0150
+i 3,7 0 0151
+j 3,7,3 0 0152
+k 5,7 0 0153
+l 3,7 0 0154
+m 7,5 0 0155
+n 5,5 0 0156
+o 5,5 0 0157
+p 5,5,3 0 0160
+q 5,5,3 0 0161
+r 4,5 0 0162
+s 4,5 0 0163
+t 3,6 0 0164
+u 5,5 0 0165
+v 5,5 0 0166
+w 7,5 0 0167
+x 4,5 0 0170
+y 5,5,3 0 0171
+z 4,5 0 0172
+{ 4,7,2 0 0173
+lC "
+| 3,7,2 0 0174
+or "
+ba "
+} 4,7,2 0 0175
+rC "
+~ 6,4 0 0176
+a~ "
+ap "
+ti "
+r! 4,5,2 0 0241
+¡ "
+ct 5,6,1 0 0242
+¢ "
+Po 5,7 0 0243
+£ "
+Cs 5,7 0 0244
+¤ "
+Ye 7,7 0 0245
+¥ "
+bb 3,7,2 0 0246
+¦ "
+sc 5,7,2 0 0247
+§ "
+ad 3,7 0 0250
+¨ "
+co 9,7 0 0251
+© "
+Of 4,7 0 0252
+ª "
+Fo 5,5 0 0253
+« "
+no 7,4 0 0254
+¬ "
+- 4,3 0 0255
+hy "
+­ "
+rg 9,7 0 0256
+® "
+a- 3,7 0 0257
+¯ "
+de 4,7 0 0260
+° "
++- 7,7 0 0261
+± "
+S2 3,7 0 0262
+² "
+S3 3,7 0 0263
+³ "
+aa 3,8 0 0264
+´ "
+µ 5,5,3 0 0265
+ps 6,7,3 0 0266
+¶ "
+md 3,3 0 0267
+· "
+ac 3,0,2 0 0270
+¸ "
+S1 3,7 0 0271
+¹ "
+Om 3,7 0 0272
+º "
+Fc 5,5 0 0273
+» "
+14 7,7 0 0274
+¼ "
+12 7,7 0 0275
+½ "
+34 7,7 0 0276
+¾ "
+r? 5,5,2 0 0277
+¿ "
+`A 7,10 0 0300
+À "
+'A 7,10 0 0301
+Á "
+^A 7,10 0 0302
+Â "
+~A 7,10 0 0303
+Ã "
+:A 7,9 0 0304
+Ä "
+oA 7,10 0 0305
+Å "
+AE 8,7 0 0306
+Æ "
+,C 7,7,2 0 0307
+Ç "
+`E 6,10 0 0310
+È "
+'E 6,10 0 0311
+É "
+^E 6,10 0 0312
+Ê "
+:E 6,9 0 0313
+Ë "
+`I 3,10 0 0314
+Ì "
+'I 3,10 0 0315
+Í "
+^I 3,10 0 0316
+Î "
+:I 3,9 0 0317
+Ï "
+-D 7,7 0 0320
+Ð "
+~N 7,10 0 0321
+Ñ "
+`O 7,10 0 0322
+Ò "
+'O 7,10 0 0323
+Ó "
+^O 7,10 0 0324
+Ô "
+~O 7,10 0 0325
+Õ "
+:O 7,9 0 0326
+Ö "
+mu 7,5 0 0327
+× "
+/O 7,8,1 0 0330
+Ø "
+`U 7,10 0 0331
+Ù "
+'U 7,10 0 0332
+Ú "
+^U 7,10 0 0333
+Û "
+:U 7,9 0 0334
+Ü "
+'Y 6,9 0 0335
+Ý "
+TP 6,7 0 0336
+Þ "
+ss 6,7,2 0 0337
+ß "
+`a 5,8 0 0340
+à "
+'a 5,8 0 0341
+á "
+^a 5,8 0 0342
+â "
+~a 5,8 0 0343
+ã "
+:a 5,7 0 0344
+ä "
+oa 5,8 0 0345
+å "
+ae 7,5 0 0346
+æ "
+,c 5,5,2 0 0347
+ç "
+`e 5,8 0 0350
+è "
+'e 5,8 0 0351
+é "
+^e 5,8 0 0352
+ê "
+:e 5,7 0 0353
+ë "
+`i 3,8 0 0354
+ì "
+'i 3,8 0 0355
+í "
+^i 3,8 0 0356
+î "
+:i 3,7 0 0357
+ï "
+Sd 5,8 0 0360
+ð "
+~n 5,8 0 0361
+ñ "
+`o 5,8 0 0362
+ò "
+'o 5,8 0 0363
+ó "
+^o 5,8 0 0364
+ô "
+~o 5,8 0 0365
+õ "
+:o 5,7 0 0366
+ö "
+di 7,5 0 0367
+÷ "
+/o 5,6,1 0 0370
+ø "
+`u 5,8 0 0371
+ù "
+'u 5,8 0 0372
+ú "
+^u 5,8 0 0373
+û "
+:u 5,7 0 0374
+ü "
+'y 5,8,3 0 0375
+ý "
+Tp 5,7,3 0 0376
+þ "
+:y 5,7,3 0 0377
+ÿ "
diff --git a/gnu/usr.bin/groff/devX75/TR b/gnu/usr.bin/groff/devX75/TR
new file mode 100644
index 0000000..c1ac847
--- /dev/null
+++ b/gnu/usr.bin/groff/devX75/TR
@@ -0,0 +1,306 @@
+name TR
+spacewidth 2
+charset
+--- 2,1 0 040
+! 3,7 0 041
+" 4,7 0 042
+# 5,7 0 043
+sh "
+$ 5,8,1 0 044
+Do "
+% 8,7 0 045
+& 8,7 0 046
+' 3,7 0 047
+( 4,7,2 0 050
+) 4,7,2 0 051
+* 5,7 0 052
++ 6,5 0 053
+, 3,1,2 0 054
+\- 7,3 0 055
+. 3,1 0 056
+/ 3,7 0 057
+sl "
+0 5,7 0 060
+1 5,7 0 061
+2 5,7 0 062
+3 5,7 0 063
+4 5,7 0 064
+5 5,7 0 065
+6 5,7 0 066
+7 5,7 0 067
+8 5,7 0 070
+9 5,7 0 071
+: 3,5 0 072
+; 3,5,2 0 073
+< 5,5 0 074
+= 6,4 0 075
+eq "
+> 5,5 0 076
+? 4,7 0 077
+@ 9,7,2 0 0100
+at "
+A 8,7 0 0101
+B 6,7 0 0102
+C 7,7 0 0103
+D 7,7 0 0104
+E 6,7 0 0105
+F 6,7 0 0106
+G 7,7 0 0107
+H 8,7 0 0110
+I 4,7 0 0111
+J 4,7 0 0112
+K 7,7 0 0113
+L 6,7 0 0114
+M 10,7 0 0115
+N 8,7 0 0116
+O 7,7 0 0117
+P 6,7 0 0120
+Q 7,7,2 0 0121
+R 7,7 0 0122
+S 5,7 0 0123
+T 6,7 0 0124
+U 8,7 0 0125
+V 8,7 0 0126
+W 10,7 0 0127
+X 8,7 0 0130
+Y 8,7 0 0131
+Z 6,7 0 0132
+[ 3,7,2 0 0133
+lB "
+\ 3,7 0 0134
+rs "
+] 3,7,2 0 0135
+rB "
+^ 5,7 0 0136
+a^ "
+ha "
+_ 5,0,3 0 0137
+` 3,7 0 0140
+oq "
+a 4,5 0 0141
+b 5,7 0 0142
+c 4,5 0 0143
+d 5,7 0 0144
+e 4,5 0 0145
+f 4,7 0 0146
+g 5,5,2 0 0147
+h 5,7 0 0150
+i 3,7 0 0151
+j 3,7,2 0 0152
+k 5,7 0 0153
+l 4,7 0 0154
+m 8,5 0 0155
+n 5,5 0 0156
+o 5,5 0 0157
+p 5,5,2 0 0160
+q 5,5,2 0 0161
+r 4,5 0 0162
+s 4,5 0 0163
+t 4,6 0 0164
+u 5,5 0 0165
+v 5,5 0 0166
+w 8,5 0 0167
+x 6,5 0 0170
+y 5,5,2 0 0171
+z 5,5 0 0172
+{ 4,7,2 0 0173
+lC "
+| 2,7,2 0 0174
+or "
+ba "
+} 4,7,2 0 0175
+rC "
+~ 7,4 0 0176
+a~ "
+ap "
+ti "
+r! 3,5,2 0 0241
+¡ "
+ct 5,6,1 0 0242
+¢ "
+Po 5,7 0 0243
+£ "
+Cs 5,7 0 0244
+¤ "
+Ye 5,7 0 0245
+¥ "
+bb 2,7 0 0246
+¦ "
+sc 5,8,1 0 0247
+§ "
+ad 5,7 0 0250
+¨ "
+co 9,7 0 0251
+© "
+Of 4,7 0 0252
+ª "
+Fo 5,5 0 0253
+« "
+no 7,4 0 0254
+¬ "
+- 4,3 0 0255
+hy "
+­ "
+rg 9,7 0 0256
+® "
+a- 4,7 0 0257
+¯ "
+de 4,7 0 0260
+° "
++- 6,7 0 0261
+± "
+S2 3,7 0 0262
+² "
+S3 3,7 0 0263
+³ "
+aa 3,7 0 0264
+´ "
+µ 5,5,2 0 0265
+ps 6,7,2 0 0266
+¶ "
+md 2,3 0 0267
+· "
+ac 4,0,3 0 0270
+¸ "
+S1 3,7 0 0271
+¹ "
+Om 4,7 0 0272
+º "
+Fc 5,5 0 0273
+» "
+14 8,7 0 0274
+¼ "
+12 8,7 0 0275
+½ "
+34 8,7 0 0276
+¾ "
+r? 4,5,2 0 0277
+¿ "
+`A 8,10 0 0300
+À "
+'A 8,10 0 0301
+Á "
+^A 8,10 0 0302
+Â "
+~A 8,10 0 0303
+Ã "
+:A 8,9 0 0304
+Ä "
+oA 8,10 0 0305
+Å "
+AE 9,7 0 0306
+Æ "
+,C 7,7,3 0 0307
+Ç "
+`E 6,10 0 0310
+È "
+'E 6,10 0 0311
+É "
+^E 6,10 0 0312
+Ê "
+:E 6,9 0 0313
+Ë "
+`I 4,10 0 0314
+Ì "
+'I 4,10 0 0315
+Í "
+^I 4,10 0 0316
+Î "
+:I 4,9 0 0317
+Ï "
+-D 7,7 0 0320
+Ð "
+~N 8,10 0 0321
+Ñ "
+`O 7,10 0 0322
+Ò "
+'O 7,10 0 0323
+Ó "
+^O 7,10 0 0324
+Ô "
+~O 7,10 0 0325
+Õ "
+:O 7,9 0 0326
+Ö "
+mu 6,5 0 0327
+× "
+/O 8,8,1 0 0330
+Ø "
+`U 8,10 0 0331
+Ù "
+'U 8,10 0 0332
+Ú "
+^U 8,10 0 0333
+Û "
+:U 8,9 0 0334
+Ü "
+'Y 8,10 0 0335
+Ý "
+TP 6,7 0 0336
+Þ "
+ss 5,7 0 0337
+ß "
+`a 4,8 0 0340
+à "
+'a 4,8 0 0341
+á "
+^a 4,8 0 0342
+â "
+~a 4,8 0 0343
+ã "
+:a 4,7 0 0344
+ä "
+oa 4,8 0 0345
+å "
+ae 6,5 0 0346
+æ "
+,c 4,5,3 0 0347
+ç "
+`e 4,8 0 0350
+è "
+'e 4,8 0 0351
+é "
+^e 4,8 0 0352
+ê "
+:e 4,7 0 0353
+ë "
+`i 4,8 0 0354
+ì "
+'i 4,8 0 0355
+í "
+^i 4,8 0 0356
+î "
+:i 4,7 0 0357
+ï "
+Sd 5,8 0 0360
+ð "
+~n 5,8 0 0361
+ñ "
+`o 5,8 0 0362
+ò "
+'o 5,8 0 0363
+ó "
+^o 5,8 0 0364
+ô "
+~o 5,8 0 0365
+õ "
+:o 5,7 0 0366
+ö "
+di 6,5 0 0367
+÷ "
+/o 5,6,1 0 0370
+ø "
+`u 5,8 0 0371
+ù "
+'u 5,8 0 0372
+ú "
+^u 5,8 0 0373
+û "
+:u 5,7 0 0374
+ü "
+'y 5,8,2 0 0375
+ý "
+Tp 5,7,2 0 0376
+þ "
+:y 5,7,2 0 0377
+ÿ "
diff --git a/gnu/usr.bin/groff/devascii/DESC.proto b/gnu/usr.bin/groff/devascii/DESC.proto
new file mode 100644
index 0000000..041ceba
--- /dev/null
+++ b/gnu/usr.bin/groff/devascii/DESC.proto
@@ -0,0 +1,8 @@
+res 240
+hor 24
+vert 40
+unitwidth 10
+sizes 10 0
+fonts 6 R I B BI S L
+tcommand
+postpro grotty
diff --git a/gnu/usr.bin/groff/devascii/Makefile b/gnu/usr.bin/groff/devascii/Makefile
new file mode 100644
index 0000000..b57a34d
--- /dev/null
+++ b/gnu/usr.bin/groff/devascii/Makefile
@@ -0,0 +1,6 @@
+# Makefile for devascii
+
+DEVICE= ascii
+
+.include "../Makefile.tty"
+.include "../Makefile.dev"
diff --git a/gnu/usr.bin/groff/devascii/Makefile.sub b/gnu/usr.bin/groff/devascii/Makefile.sub
new file mode 100644
index 0000000..238f7b7
--- /dev/null
+++ b/gnu/usr.bin/groff/devascii/Makefile.sub
@@ -0,0 +1,31 @@
+DEV=ascii
+FONTS=R I B BI
+DEVFILES=$(FONTS) DESC
+CLEANADD=$(FONTS) DESC
+
+RES=240
+CPI=10
+LPI=6
+
+$(FONTS): R.proto
+ @echo Making $@
+ @-rm -f $@
+ @(charwidth=`expr $(RES) / $(CPI)` ; \
+ sed -e "s/^name [A-Z]*$$/name $@/" \
+ -e "s/^\\([^ ]*\\) [0-9]+ /\\1 $$charwidth /" \
+ -e "s/^spacewidth [0-9]+$$/spacewidth $$charwidth/" \
+ -e "s/^internalname .*$$/internalname $@/" \
+ -e "/^internalname/s/BI/3/" \
+ -e "/^internalname/s/B/2/" \
+ -e "/^internalname/s/I/1/" \
+ -e "/^internalname .*[^ 0-9]/d" \
+ $(srcdir)/R.proto >$@)
+
+DESC: DESC.proto
+ @echo Making $@
+ @-rm -f $@
+ @sed -e "s/^res .*$$/res $(RES)/" \
+ -e "s/^hor .*$$/hor `expr $(RES) / $(CPI)`/" \
+ -e "s/^vert .*$$/vert `expr $(RES) / $(LPI)`/" \
+ -e "s/^fonts .*$$/fonts `set $(FONTS); echo $$#` $(FONTS)/" \
+ $(srcdir)/DESC.proto >$@
diff --git a/gnu/usr.bin/groff/devascii/R.proto b/gnu/usr.bin/groff/devascii/R.proto
new file mode 100644
index 0000000..876c74c
--- /dev/null
+++ b/gnu/usr.bin/groff/devascii/R.proto
@@ -0,0 +1,165 @@
+name R
+internalname 0
+spacewidth 24
+charset
+! 24 0 0041
+" 24 0 0042
+lq "
+rq "
+# 24 0 0043
+sh "
+$ 24 0 0044
+Do "
+% 24 0 0045
+& 24 0 0046
+' 24 0 0047
+aa "
+fm "
+aq "
+( 24 0 0050
+) 24 0 0051
+* 24 0 0052
+** "
++ 24 0 0053
+pl "
+, 24 0 0054
+\- 24 0 0055
+hy "
+- "
+mi "
+en "
+. 24 0 0056
+/ 24 0 0057
+sl "
+f/ "
+0 24 0 0060
+1 24 0 0061
+2 24 0 0062
+3 24 0 0063
+4 24 0 0064
+5 24 0 0065
+6 24 0 0066
+7 24 0 0067
+8 24 0 0070
+9 24 0 0071
+: 24 0 0072
+; 24 0 0073
+< 24 0 0074
+la "
+fo "
+= 24 0 0075
+eq "
+> 24 0 0076
+ra "
+fc "
+? 24 0 0077
+@ 24 0 0100
+at "
+A 24 0 0101
+*A "
+B 24 0 0102
+*B "
+C 24 0 0103
+D 24 0 0104
+E 24 0 0105
+*E "
+F 24 0 0106
+G 24 0 0107
+H 24 0 0110
+*Y "
+I 24 0 0111
+*I "
+J 24 0 0112
+K 24 0 0113
+*K "
+L 24 0 0114
+M 24 0 0115
+*M "
+N 24 0 0116
+*N "
+O 24 0 0117
+ci "
+*O "
+P 24 0 0120
+*R "
+Q 24 0 0121
+R 24 0 0122
+S 24 0 0123
+T 24 0 0124
+*T "
+U 24 0 0125
+V 24 0 0126
+W 24 0 0127
+X 24 0 0130
+*X "
+Y 24 0 0131
+*U "
+Z 24 0 0132
+*Z "
+[ 24 0 0133
+lB "
+\ 24 0 0134
+rs "
+] 24 0 0135
+rB "
+a^ 24 0 0136
+^ "
+ha "
+_ 24 0 0137
+ru "
+ul "
+` 24 0 0140
+oq "
+ga "
+a 24 0 0141
+b 24 0 0142
+c 24 0 0143
+d 24 0 0144
+e 24 0 0145
+f 24 0 0146
+g 24 0 0147
+h 24 0 0150
+i 24 0 0151
+.i "
+j 24 0 0152
+k 24 0 0153
+l 24 0 0154
+m 24 0 0155
+n 24 0 0156
+o 24 0 0157
+*o "
+p 24 0 0160
+q 24 0 0161
+r 24 0 0162
+s 24 0 0163
+t 24 0 0164
+u 24 0 0165
+v 24 0 0166
+w 24 0 0167
+x 24 0 0170
+mu "
+y 24 0 0171
+z 24 0 0172
+lC 24 0 0173
+{ "
+ba 24 0 0174
+or "
+bv "
+br "
+| "
+lb "
+lc "
+lf "
+lk "
+lt "
+rb "
+rc "
+rf "
+rk "
+rt "
+rC 24 0 0175
+} "
+a~ 24 0 0176
+~ "
+ap "
+ti "
diff --git a/gnu/usr.bin/groff/devdvi/B b/gnu/usr.bin/groff/devdvi/B
new file mode 100644
index 0000000..240731a
--- /dev/null
+++ b/gnu/usr.bin/groff/devdvi/B
@@ -0,0 +1,347 @@
+name B
+internalname cmbx10
+spacewidth 401952
+ligatures ff fi fl ffi ffl 0
+checksum 452076118
+designsize 10485760
+kernpairs
+ff ' 114323
+ff ? 114323
+ff ! 114323
+ff ) 114323
+ff rB 114323
+ff ] 114323
+' ' -100488
+' ? 133984
+' ! 133984
+A t -33496
+A C -33496
+A O -33496
+A G -33496
+A U -33496
+A Q -33496
+A T -100488
+A Y -100488
+A V -133984
+A W -133984
+D X -33496
+D W -33496
+D A -33496
+D V -33496
+D Y -33496
+F o -100488
+F e -100488
+F u -100488
+F r -100488
+F a -100488
+F A -133984
+F O -33496
+F C -33496
+F G -33496
+F Q -33496
+I I 33496
+K O -33496
+K C -33496
+K G -33496
+K Q -33496
+L T -100488
+L Y -100488
+L V -133984
+L W -133984
+O X -33496
+O W -33496
+O A -33496
+O V -33496
+O Y -33496
+P A -100488
+P o -33496
+P e -33496
+P a -33496
+P . -100488
+P , -100488
+R t -33496
+R C -33496
+R O -33496
+R G -33496
+R U -33496
+R Q -33496
+R T -100488
+R Y -100488
+R V -133984
+R W -133984
+T y -33496
+T e -100488
+T o -100488
+T r -100488
+T a -100488
+T A -100488
+T u -100488
+V o -100488
+V e -100488
+V u -100488
+V r -100488
+V a -100488
+V A -133984
+V O -33496
+V C -33496
+V G -33496
+V Q -33496
+W o -100488
+W e -100488
+W u -100488
+W r -100488
+W a -100488
+W A -133984
+W O -33496
+W C -33496
+W G -33496
+W Q -33496
+X O -33496
+X C -33496
+X G -33496
+X Q -33496
+Y e -100488
+Y o -100488
+Y r -100488
+Y a -100488
+Y A -100488
+Y u -100488
+oq oq -100488
+oq ` -100488
+` oq -100488
+` ` -100488
+a v -33496
+a j 66992
+a y -33496
+a w -33496
+b e 33496
+b o 33496
+b x -33496
+b d 33496
+b c 33496
+b q 33496
+b v -33496
+b j 66992
+b y -33496
+b w -33496
+c h -33496
+c k -33496
+f ' 114323
+f ? 114323
+f ! 114323
+f ) 114323
+f rB 114323
+f ] 114323
+g j 33496
+h t -33496
+h u -33496
+h b -33496
+h y -33496
+h v -33496
+h w -33496
+k a -66992
+k e -33496
+k a -33496
+k o -33496
+k c -33496
+m t -33496
+m u -33496
+m b -33496
+m y -33496
+m v -33496
+m w -33496
+n t -33496
+n u -33496
+n b -33496
+n y -33496
+n v -33496
+n w -33496
+o e 33496
+o o 33496
+o x -33496
+o d 33496
+o c 33496
+o q 33496
+o v -33496
+o j 66992
+o y -33496
+o w -33496
+p e 33496
+p o 33496
+p x -33496
+p d 33496
+p c 33496
+p q 33496
+p v -33496
+p j 66992
+p y -33496
+p w -33496
+t y -33496
+t w -33496
+u w -33496
+v a -66992
+v e -33496
+v a -33496
+v o -33496
+v c -33496
+w e -33496
+w a -33496
+w o -33496
+w c -33496
+y o -33496
+y e -33496
+y a -33496
+y . -100488
+y , -100488
+charset
+*G 725261,719440,0,0,0,-167480 2 0000
+*D 1004880,719440 2 0001
+*H 937888,719440,0,0,-33496,-33496 2 0002
+*L 844682,719440 2 0003
+*C 803904,719440 2 0004
+*P 943714,719440 2 0005
+*S 870896,719440 2 0006
+*U 937888,719440,0,0,-33496,-167480 2 0007
+*F 870896,719440,0,0,-33496 2 0010
+*Q 937888,719440,0,0,-33496,-83741 2 0011
+*W 870896,719440 2 0012
+ff 703416,728178,0,114323 2 0013
+fi 669920,728178 2 0014
+fl 669920,728178 2 0015
+Fi 1004880,728178 2 0016
+Fl 1004880,728178 2 0017
+.i 334960,466034 0 0020
+.j 368456,466034,203890 1 0021
+ga 602928,728178 2 0022
+char180 602928,728178 2 0023
+aa "
+ah 602928,662642 2 0024
+ab 602928,728178 2 0025
+char175 602928,625066 2 0026
+a- "
+ao 911674,728178 2 0027
+char184 535936,0,178403 1 0030
+ac "
+char223 626230,728178 2 0031
+ss "
+char230 870896,466034 0 0032
+ae "
+oe 937888,466034 0 0033
+char248 602928,567979,101946 3 0034
+/o "
+char198 1092261,719440 2 0035
+AE "
+OE 1226245,719440 2 0036
+char216 937888,770413,50973 3 0037
+/O "
+--- 334960,466034 0 0040
+! 367000,728178 2 0041
+rq 632056,728178 2 0042
+sh 1004880,728178,203888 3 0043
+# "
+Do 602928,786432,58254 3 0044
+$ "
+% 1004880,786432,58254 3 0045
+& 937888,728178 2 0046
+' 334960,728178 2 0047
+( 468944,786432,262144 3 0050
+) 468944,786432,262144 3 0051
+* 602928,786432 2 0052
++ 937888,664096,139808 3 0053
+, 334960,163112,203890 1 0054
+char173 401952,466034 0 0055
+hy "
+- "
+. 334960,163112 0 0056
+sl 602928,786432,262144 3 0057
+/ "
+0 602928,675749 2 0060
+1 602928,675749 2 0061
+2 602928,675749 2 0062
+3 602928,675749 2 0063
+4 602928,675749 2 0064
+5 602928,675749 2 0065
+6 602928,675749 2 0066
+7 602928,675749 2 0067
+8 602928,675749 2 0070
+9 602928,675749 2 0071
+: 334960,466034 0 0072
+; 334960,466034,203890 1 0073
+char161 367000,524288,203890 3 0074
+r! "
+= 937888,410110,-114178 0 0075
+char191 569432,524288,203890 3 0076
+r? "
+? 569432,728178 2 0077
+at 937888,728178 2 0100
+@ "
+A 911674,719440 2 0101
+B 857789,719440 2 0102
+C 870896,719440,0,0,-33496 2 0103
+D 924781,719440,0,0,0,-33496 2 0104
+E 792253,719440 2 0105
+F 758757,719440,0,0,0,-167480 2 0106
+G 948083,719440,0,0,-33496 2 0107
+H 943714,719440 2 0110
+I 457294,719440 2 0111
+J 623317,719440,0,0,0,-33496 2 0112
+K 945170,719440 2 0113
+L 725261,719440,0,0,0,66992 2 0114
+M 1144690,719440 2 0115
+N 943714,719440 2 0116
+O 905848,719440,0,0,-33496,-33496 2 0117
+P 824293,719440,0,0,0,-167480 2 0120
+Q 905848,719440,203890,0,-33496 3 0121
+R 904392,719440 2 0122
+S 669920,719440 2 0123
+T 838856,719440,0,0,0,-167480 2 0124
+U 927694,719440,0,0,-20389 2 0125
+V 911674,719440,0,16749,50245,-251219 2 0126
+W 1246634,719440,0,16749,50245,-150731 2 0127
+X 911674,719440 2 0130
+Y 911674,719440,0,30146,33496,-237822 2 0131
+Z 736912,719440 2 0132
+lB 334960,786432,262144 3 0133
+[ "
+lq 632056,728178 2 0134
+rB 334960,786432,262144 3 0135
+] "
+ha 602928,728178 2 0136
+^ "
+a^ "
+a. 334960,728178 2 0137
+oq 334960,728178 2 0140
+` "
+a 586179,466034 0 0141
+b 669920,728178 2 0142
+c 535936,466034 0 0143
+d 669920,728178 2 0144
+e 552685,466034 0 0145
+f 368456,728178,0,114323 2 0146
+g 602928,466034,203890,16749 1 0147
+h 669920,728178 2 0150
+i 334960,728178 2 0151
+j 368456,728178,203890 3 0152
+k 636424,728178 2 0153
+l 334960,728178 2 0154
+m 1004880,466034 0 0155
+n 669920,466034 0 0156
+o 602928,466034 0 0157
+p 669920,466034,203890 1 0160
+q 636424,466034,203890 1 0161
+r 496616,466034 0 0162
+s 475643,466034 0 0163
+t 468944,665763 2 0164
+u 669920,466034 0 0165
+v 636424,466034,0,16749 0 0166
+w 870896,466034,0,16749 0 0167
+x 636424,466034 0 0170
+y 636424,466034,203890,16749 1 0171
+z 535936,466034 0 0172
+en 602928,466034,0,33496 0 0173
+em 1205856,466034,0,33496 0 0174
+a" 602928,728178 2 0175
+~ 602928,728178 2 0176
+a~ "
+char168 602928,728178 2 0177
+ad "
diff --git a/gnu/usr.bin/groff/devdvi/BI b/gnu/usr.bin/groff/devdvi/BI
new file mode 100644
index 0000000..16d0193
--- /dev/null
+++ b/gnu/usr.bin/groff/devdvi/BI
@@ -0,0 +1,352 @@
+name BI
+internalname cmbxti10
+spacewidth 434573
+slant 14.036243
+ligatures ff fi fl ffi ffl 0
+checksum 1175274390
+designsize 10485760
+kernpairs
+ff ' 111848
+ff ? 111848
+ff ! 111848
+ff ) 111848
+ff rB 111848
+ff ] 111848
+' ' -92624
+' ? 123498
+' ! 123498
+A n -30875
+A l -30875
+A r -30875
+A u -30875
+A m -30875
+A t -30875
+A i -30875
+A C -30875
+A O -30875
+A G -30875
+A h -30875
+A b -30875
+A U -30875
+A k -30875
+A v -30875
+A w -30875
+A Q -30875
+A T -92624
+A Y -92624
+A V -123498
+A W -123498
+A e -61749
+A a -61749
+A o -61749
+A d -61749
+A c -61749
+A g -61749
+A q -61749
+D X -30875
+D W -30875
+D A -30875
+D V -30875
+D Y -30875
+F o -92624
+F e -92624
+F u -92624
+F r -92624
+F a -92624
+F A -123498
+F O -30875
+F C -30875
+F G -30875
+F Q -30875
+K O -30875
+K C -30875
+K G -30875
+K Q -30875
+L T -92624
+L Y -92624
+L V -123498
+L W -123498
+L e -61749
+L a -61749
+L o -61749
+L d -61749
+L c -61749
+L g -61749
+L q -61749
+O X -30875
+O W -30875
+O A -30875
+O V -30875
+O Y -30875
+P A -92624
+R n -30875
+R l -30875
+R r -30875
+R u -30875
+R m -30875
+R t -30875
+R i -30875
+R C -30875
+R O -30875
+R G -30875
+R h -30875
+R b -30875
+R U -30875
+R k -30875
+R v -30875
+R w -30875
+R Q -30875
+R T -92624
+R Y -92624
+R V -123498
+R W -123498
+R e -61749
+R a -61749
+R o -61749
+R d -61749
+R c -61749
+R g -61749
+R q -61749
+T y -92624
+T e -92624
+T o -92624
+T r -92624
+T a -92624
+T u -92624
+T A -92624
+V o -92624
+V e -92624
+V u -92624
+V r -92624
+V a -92624
+V A -123498
+V O -30875
+V C -30875
+V G -30875
+V Q -30875
+W A -92624
+X O -30875
+X C -30875
+X G -30875
+X Q -30875
+Y e -92624
+Y o -92624
+Y r -92624
+Y a -92624
+Y u -92624
+Y A -92624
+oq oq -92624
+oq ` -92624
+` oq -92624
+` ` -92624
+b e -61749
+b a -61749
+b o -61749
+b d -61749
+b c -61749
+b g -61749
+b q -61749
+c e -61749
+c a -61749
+c o -61749
+c d -61749
+c c -61749
+c g -61749
+c q -61749
+d l 61749
+e e -61749
+e a -61749
+e o -61749
+e d -61749
+e c -61749
+e g -61749
+e q -61749
+Fn ' 111848
+f ' 111848
+Fn ? 111848
+f ? 111848
+Fn ! 111848
+f ! 111848
+Fn ) 111848
+f ) 111848
+Fn rB 111848
+Fn ] 111848
+f rB 111848
+f ] 111848
+l l 61749
+n ' -123498
+o e -61749
+o a -61749
+o o -61749
+o d -61749
+o c -61749
+o g -61749
+o q -61749
+p e -61749
+p a -61749
+p o -61749
+p d -61749
+p c -61749
+p g -61749
+p q -61749
+r e -61749
+r a -61749
+r o -61749
+r d -61749
+r c -61749
+r g -61749
+r q -61749
+w l 61749
+charset
+*G 731666,719440,0,135298,0,-19075 2 0000
+*D 990312,719440 2 0001
+*H 928563,719440,0,95027,-84834,64152 2 0002
+*L 845843,719440 2 0003
+*C 805066,719440,0,158248,0,79125 2 0004
+*P 939632,719440,0,180443,0,90222 2 0005
+*S 866814,719440,0,119859,0,59930 2 0006
+*U 928563,719440,0,113013,-174763,-41360 2 0007
+*F 866814,719440,0,59054,-120805,59054 2 0010
+*Q 928563,719440,0,113013,-174763,-5243 2 0011
+*W 866814,719440,0,104021,0,52011 2 0012
+ff 792256,728178,203890,228357 3 0013
+fi 707205,728178,203890,113890 3 0014
+fl 738078,728178,203890,113890 3 0015
+Fi 1095466,728178,203890,113890 3 0016
+Fl 1110902,728178,203890,113890 3 0017
+.i 372824,466034,0,98840 0 0020
+.j 403699,466034,203890,48354 1 0021
+ga 619819,728178 2 0022
+char180 619819,728178,0,89421 2 0023
+aa "
+ah 619819,662642,0,86728 2 0024
+ab 619819,728178,0,108354 2 0025
+char175 619819,623318,0,109518 2 0026
+a- "
+ao 994973,728178 2 0027
+char184 558070,0,178403 1 0030
+ac "
+char223 697302,728178,203890,102090 3 0031
+ss "
+char230 866814,466034,0,89131 0 0032
+ae "
+oe 866814,466034,0,89131 0 0033
+char248 619819,567979,101946,99179 3 0034
+/o "
+char198 1072450,719440,0,119859 2 0035
+AE "
+OE 1195947,719440,0,119859 2 0036
+char216 928563,770413,50973,95027 3 0037
+/O "
+--- 311075,466034 0 0040
+! 404864,728178,0,119714 2 0041
+rq 650696,728178,0,83248 2 0042
+sh 990312,728178,203888,71653 3 0043
+# "
+char163 910723,728178 2 0044
+Po "
+% 990312,786432,58254,134859 3 0045
+& 928563,728178,0,89421 2 0046
+' 372824,728178,0,135734 2 0047
+( 496322,786432,262144,165733 3 0050
+) 496322,786432,262144,34661 3 0051
+* 619819,786432,0,150296 2 0052
++ 928563,632637,108349,34661 3 0053
+, 372824,154374,203890 1 0054
+char173 434573,466034,0,27379 0 0055
+hy "
+- "
+. 372824,154374 0 0056
+sl 619819,786432,262144,165733 3 0057
+/ "
+0 619819,675749,0,138062 2 0060
+1 619819,675749,0,138062 2 0061
+2 619819,675749,0,138062 2 0062
+3 619819,675749,0,138062 2 0063
+4 619819,675749,203890,138062 3 0064
+5 619819,675749,0,138062 2 0065
+6 619819,675749,0,138062 2 0066
+7 619819,675749,203890,138062 3 0067
+8 619819,675749,0,138062 2 0070
+9 619819,675749,0,138062 2 0071
+: 372824,466034,0,70198 0 0072
+; 372824,466034,203890,70198 1 0073
+char161 404864,524288,203890,68741 3 0074
+r! "
+= 928563,410110,-114178,71653 0 0075
+char191 619819,524288,203890 3 0076
+r? "
+? 619819,728178,0,120296 2 0077
+at 928563,728178,0,96555 2 0100
+@ "
+A 907592,719440 2 0101
+B 856330,719440,0,104021,0,52011 2 0102
+C 866814,719440,0,148986,-84834,74493 2 0103
+D 918078,719440,0,95027,0,64152 2 0104
+E 793414,719440,0,119859,0,59930 2 0105
+F 762541,719440,0,135298,0,-19075 2 0106
+G 938758,719440,0,77042,-84834,77042 2 0107
+H 939632,719440,0,180443,0,90222 2 0110
+I 494576,719440,0,164424,0,82213 2 0111
+J 640208,719440,0,152045,0,45147 2 0112
+K 938467,719440,0,148986,0,74493 2 0113
+L 731666,719440,0,0,0,61749 2 0114
+M 1124878,719440,0,180443,0,59347 2 0115
+N 939632,719440,0,180443,0,59347 2 0116
+O 896523,719440,0,95027,-84834,64152 2 0117
+P 825454,719440,0,104021,0,-50352 2 0120
+Q 896523,719440,203890,95027,-84834,95027 3 0121
+R 901186,719440,0,26835,0,20126 2 0122
+S 681568,719440,0,118112,0,59056 2 0123
+T 834774,719440,0,135298,-134896,-19075 2 0124
+U 923613,719440,0,180443,-136096,59347 2 0125
+V 907592,719440,0,195298,-133549,-51698 2 0126
+W 1216336,719440,0,195298,-133549,40925 2 0127
+X 907592,719440,0,164424,0,82213 2 0130
+Y 907592,719440,0,207648,-148986,-39347 2 0131
+Z 743317,719440,0,148986,0,74493 2 0132
+lB 373408,786432,262144,196608 3 0133
+[ "
+lq 650696,728178,0,175869 2 0134
+rB 373408,786432,262144,104568 3 0135
+] "
+ha 619819,728178,0,70344 2 0136
+^ "
+a^ "
+a. 372824,728178,0,135734 2 0137
+oq 372824,728178,0,135734 2 0140
+` "
+a 619819,466034,0,98840,-34078,98840 0 0141
+b 558070,728178,0,82430,-34078,82430 2 0142
+c 558070,466034,0,54760,-34078,54760 0 0143
+d 619819,728178,0,113890,-34078,113890 2 0144
+e 558070,466034,0,89131,-34078,89131 0 0145
+Fn 419432,728178,203890,228357,112722,116509 3 0146
+f "
+g 558070,466034,203890,110102,-35829,71266 1 0147
+h 619819,728178,0,98840,0,98840 2 0150
+i 372824,726931,0,119403,-17669,119403 2 0151
+j 372824,726931,203890,175326,50973,110102 3 0152
+k 558070,728178,0,116509,0,98840 2 0153
+l 311075,728178,0,113890,-30875,129714 2 0154
+m 990312,466034,0,98840,-17669,98840 0 0155
+n 681568,466034,0,98840,-17669,98840 0 0156
+o 619819,466034,0,82430,-34078,82430 0 0157
+p 619819,466034,203890,82430,-17182,82430 1 0160
+q 558070,466034,203890,110102,-34078,71266 1 0161
+r 526034,466034,0,116509,-17669,85634 0 0162
+s 510595,466034,0,85634,0,85634 0 0163
+t 403699,665763,0,101072,-39323,101072 2 0164
+u 650694,466034,0,98840,-17669,98840 0 0165
+v 558070,466034,0,116509,-17669,77672 0 0166
+w 805066,466034,0,116509,-17669,87382 0 0167
+x 587782,466034,0,131946,0,131946 0 0170
+y 588946,466034,203890,110102,-17669,71266 1 0171
+z 514382,466034,0,145637,0,98840 0 0172
+en 619819,466034,0,102880 0 0173
+em 1239638,466034,0,102880 0 0174
+a" 619819,728178,0,120296 2 0175
+~ 619819,728178,0,120296 2 0176
+a~ "
+char168 619819,728178,0,120298 2 0177
+ad "
diff --git a/gnu/usr.bin/groff/devdvi/CW b/gnu/usr.bin/groff/devdvi/CW
new file mode 100644
index 0000000..fd94235
--- /dev/null
+++ b/gnu/usr.bin/groff/devdvi/CW
@@ -0,0 +1,158 @@
+name CW
+special
+internalname cmtt10
+spacewidth 550498
+checksum -538297224
+designsize 10485760
+charset
+*G 550498,640797 2 0000
+*D 550498,640797 2 0001
+*H 550498,640797 2 0002
+*L 550498,640797 2 0003
+*C 550498,640797 2 0004
+*P 550498,640797 2 0005
+*S 550498,640797 2 0006
+*U 550498,640797 2 0007
+*F 550498,640797 2 0010
+*Q 550498,640797 2 0011
+*W 550498,640797 2 0012
+ff 550498,640797 2 0013
+fi 550498,640797 2 0014
+fl 550498,640797 2 0015
+Fi 550498,407779,233018 1 0016
+Fl 550498,407779,233018 1 0017
+.i 550498,451470 0 0020
+.j 550498,451470,233018 1 0021
+ga 550498,640797 2 0022
+char180 550498,640797 2 0023
+aa "
+ah 550498,593466 2 0024
+ab 550498,640797 2 0025
+char175 550498,593027 2 0026
+a- "
+ao 550498,640797 2 0027
+char184 550498,0,203891 1 0030
+ac "
+char223 550498,640797 2 0031
+ss "
+char230 550498,451470 0 0032
+ae "
+oe 550498,451470 0 0033
+char248 550498,567979,116509 3 0034
+/o "
+char198 550498,640797 2 0035
+AE "
+OE 550498,640797 2 0036
+char216 550498,699051,58254 3 0037
+/O "
+--- 550498,230104,116509 1 0040
+! 550498,640797 2 0041
+" 550498,640797 2 0042
+sh 550498,640797 2 0043
+# "
+Do 550498,728178,87381 3 0044
+$ "
+% 550498,728178,87381 3 0045
+& 550498,640797 2 0046
+' 550498,640797 2 0047
+( 550498,728178,87379 3 0050
+) 550498,728178,87379 3 0051
+* 550498,546134 2 0052
++ 550498,556326,-84470 2 0053
+, 550498,131072,145635 1 0054
+\- 550498,556326,-84470 2 0055
+- "
+. 550498,131072 0 0056
+sl 550498,728178,87379 3 0057
+/ "
+0 550498,640797 2 0060
+1 550498,640797 2 0061
+2 550498,640797 2 0062
+3 550498,640797 2 0063
+4 550498,640797 2 0064
+5 550498,640797 2 0065
+6 550498,640797 2 0066
+7 550498,640797 2 0067
+8 550498,640797 2 0070
+9 550498,640797 2 0071
+: 550498,451470 0 0072
+; 550498,451470,145635 1 0073
+< 550498,582542,-58254 2 0074
+= 550498,435813,-204984 0 0075
+> 550498,582542,-58254 2 0076
+? 550498,640797 2 0077
+at 550498,640797 2 0100
+@ "
+A 550498,640797 2 0101
+B 550498,640797 2 0102
+C 550498,640797 2 0103
+D 550498,640797 2 0104
+E 550498,640797 2 0105
+F 550498,640797 2 0106
+G 550498,640797 2 0107
+H 550498,640797 2 0110
+I 550498,640797 2 0111
+J 550498,640797 2 0112
+K 550498,640797 2 0113
+L 550498,640797 2 0114
+M 550498,640797 2 0115
+N 550498,640797 2 0116
+O 550498,640797 2 0117
+P 550498,640797 2 0120
+Q 550498,640797,145635 3 0121
+R 550498,640797 2 0122
+S 550498,640797 2 0123
+T 550498,640797 2 0124
+U 550498,640797 2 0125
+V 550498,640797 2 0126
+W 550498,640797 2 0127
+X 550498,640797 2 0130
+Y 550498,640797 2 0131
+Z 550498,640797 2 0132
+lB 550498,728178,87379 3 0133
+[ "
+rs 550498,728178,87379 3 0134
+\ "
+rB 550498,728178,87379 3 0135
+] "
+ha 550498,640797 2 0136
+^ "
+a^ "
+_ 550498,0,99757 1 0137
+oq 550498,640797 2 0140
+` "
+a 550498,451470 0 0141
+b 550498,640797 2 0142
+c 550498,451470 0 0143
+d 550498,640797 2 0144
+e 550498,451470 0 0145
+f 550498,640797 2 0146
+g 550498,451470,233018 1 0147
+h 550498,640797 2 0150
+i 550498,640797 2 0151
+j 550498,640797,233018 3 0152
+k 550498,640797 2 0153
+l 550498,640797 2 0154
+m 550498,451470 0 0155
+n 550498,451470 0 0156
+o 550498,451470 0 0157
+p 550498,451470,233018 1 0160
+q 550498,451470,233018 1 0161
+r 550498,451470 0 0162
+s 550498,451470 0 0163
+t 550498,580466 2 0164
+u 550498,451470 0 0165
+v 550498,451470 0 0166
+w 550498,451470 0 0167
+x 550498,451470 0 0170
+y 550498,451470,233018 1 0171
+z 550498,451470 0 0172
+{ 550498,728178,87379 3 0173
+lC "
+| 550498,728178,87379 3 0174
+ba "
+} 550498,728178,87379 3 0175
+rC "
+~ 550498,640797 2 0176
+a~ "
+--- 550498,640797 2 0177
diff --git a/gnu/usr.bin/groff/devdvi/DESC.in b/gnu/usr.bin/groff/devdvi/DESC.in
new file mode 100644
index 0000000..b605255
--- /dev/null
+++ b/gnu/usr.bin/groff/devdvi/DESC.in
@@ -0,0 +1,10 @@
+sizescale 100
+unitwidth 131072
+res 57816
+hor 1
+vert 1
+sizes 500 600 700 800 900 1000 1100 1200 1400 1440 1600 1728 1800
+2000 2074 2200 2400 2488 2800 3600 0
+fonts 13 R I B BI 0 0 0 0 0 MI S EX CW
+tcommand
+postpro grodvi
diff --git a/gnu/usr.bin/groff/devdvi/EX b/gnu/usr.bin/groff/devdvi/EX
new file mode 100644
index 0000000..6e83d02
--- /dev/null
+++ b/gnu/usr.bin/groff/devdvi/EX
@@ -0,0 +1,144 @@
+name EX
+special
+internalname cmex10
+checksum -89033454
+designsize 10485760
+charset
+parenleft0 480600,41942,1216362 1 0000
+parenright0 480600,41942,1216362 1 0001
+bracketleft0 436909,41942,1216362 1 0002
+bracketright0 436909,41942,1216362 1 0003
+floorleft0 495163,41942,1216362 1 0004
+floorright0 495163,41942,1216362 1 0005
+ceilingleft0 495163,41942,1216362 1 0006
+ceilingright0 495163,41942,1216362 1 0007
+braceleft0 611672,41942,1216362 1 0010
+braceright0 611672,41942,1216362 1 0011
+angleleft0 495163,41942,1216362 1 0012
+angleright0 495163,41942,1216362 1 0013
+barex 349526,0,629152 1 0014
+bardblex 582544,0,629152 1 0015
+slash0 605845,41942,1216362 1 0016
+backslash0 605845,41942,1216362 1 0017
+parenleft1 626235,41942,1845514 1 0020
+parenright1 626235,41942,1845514 1 0021
+parenleft2 771872,41942,2474666 1 0022
+parenright2 771872,41942,2474666 1 0023
+bracketleft2 553418,41942,2474666 1 0024
+bracketright2 553418,41942,2474666 1 0025
+floorleft2 611672,41942,2474666 1 0026
+floorright2 611672,41942,2474666 1 0027
+ceilingleft2 611672,41942,2474666 1 0030
+ceilingright2 611672,41942,2474666 1 0031
+braceleft2 786434,41942,2474666 1 0032
+braceright2 786434,41942,2474666 1 0033
+angleleft2 786434,41942,2474666 1 0034
+angleright2 786434,41942,2474666 1 0035
+slash2 1095182,41942,2474666 1 0036
+backslash2 1095182,41942,2474666 1 0037
+parenleft3 830126,41942,3103818 1 0040
+parenright3 830126,41942,3103818 1 0041
+bracketleft3 611672,41942,3103818 1 0042
+bracketright3 611672,41942,3103818 1 0043
+floorleft3 669926,41942,3103818 1 0044
+floorright3 669926,41942,3103818 1 0045
+ceilingleft3 669926,41942,3103818 1 0046
+ceilingright3 669926,41942,3103818 1 0047
+braceleft3 844691,41942,3103818 1 0050
+braceright3 844691,41942,3103818 1 0051
+angleleft3 844691,41942,3103818 1 0052
+angleright3 844691,41942,3103818 1 0053
+slash3 1339851,41942,3103818 1 0054
+backslash3 1339851,41942,3103818 1 0055
+slash1 850515,41942,1845514 1 0056
+backslash1 850515,41942,1845514 1 0057
+parenlefttp 917507,41942,1845514 1 0060
+parenrighttp 917507,41942,1845514 1 0061
+bracketlefttp 699053,41942,1845514 1 0062
+bracketrighttp 699053,41942,1845514 1 0063
+bracketleftbt 699053,41942,1845514 1 0064
+bracketrightbt 699053,41942,1845514 1 0065
+bracketleftex 699053,0,629152 1 0066
+bracketrightex 699053,0,629152 1 0067
+lt 932070,0,943728 1 0070
+bracelefttp "
+rt 932070,0,943728 1 0071
+bracerighttp "
+lb 932070,0,943728 1 0072
+braceleftbt "
+rb 932070,0,943728 1 0073
+bracerightbt "
+lk 932070,0,1887456 1 0074
+braceleftmid "
+rk 932070,0,1887456 1 0075
+bracerightmid "
+braceleftex 932070,0,314576 1 0076
+bracerightex "
+braceex "
+arrowvertex 699053,0,629152 1 0077
+parenleftbt 917507,41942,1845514 1 0100
+parenrightbt 917507,41942,1845514 1 0101
+parenleftex 917507,0,629152 1 0102
+parenrightex 917507,0,629152 1 0103
+angleleft1 640798,41942,1845514 1 0104
+angleright1 640798,41942,1845514 1 0105
+--- 873816,0,1048590 1 0106
+--- 1165088,104859,1572877 1 0107
+--- 495162,0,1165096,203891 1 0110
+ointegral 582544,0,2330194,466035 1 0111
+ois "
+--- 1165088,0,1048590 1 0112
+bigcircledot 1584520,104859,1572877 1 0113
+--- 1165088,0,1048590 1 0114
+bigcircleplus 1584520,104859,1572877 1 0115
+--- 1165088,0,1048590 1 0116
+bigcirclemultiply 1584520,104859,1572877 1 0117
+--- 1106834,0,1048590 1 0120
+--- 990325,0,1048590 1 0121
+--- 495162,0,1165096,203891 1 0122
+--- 873816,0,1048590 1 0123
+--- 873816,0,1048590 1 0124
+--- 873816,0,1048590 1 0125
+--- 873816,0,1048590 1 0126
+--- 873816,0,1048590 1 0127
+sum 1514614,104859,1572877 1 0130
+product 1339851,104859,1572877 1 0131
+integral 582544,0,2330194,466035 1 0132
+is "
+bigunion 1165088,104859,1572877 1 0133
+bigintersection 1165088,104859,1572877 1 0134
+bigunionplus 1165088,104859,1572877 1 0135
+biglogicaland 1165088,104859,1572877 1 0136
+biglogicalor 1165088,104859,1572877 1 0137
+--- 990325,0,1048590 1 0140
+coproduct 1339851,104859,1572877 1 0141
+--- 582544,757306 2 0142
+--- 1048579,786432 2 0143
+--- 1514614,786432 2 0144
+--- 582544,757306 2 0145
+--- 1048579,786432 2 0146
+--- 1514614,786432 2 0147
+bracketleft1 495163,41942,1845514 1 0150
+bracketright1 495163,41942,1845514 1 0151
+floorleft1 553418,41942,1845514 1 0152
+floorright1 553418,41942,1845514 1 0153
+ceilingleft1 553418,41942,1845514 1 0154
+ceilingright1 553418,41942,1845514 1 0155
+braceleft1 699053,41942,1845514 1 0156
+braceright1 699053,41942,1845514 1 0157
+sr0 1048579,41942,1216362 1 0160
+sr1 1048579,41942,1845514 1 0161
+sr2 1048579,41942,2474666 1 0162
+sr3 1048579,41942,3103818 1 0163
+--- 1106834,0,1887456 1 0164
+--- 1106834,0,629152 1 0165
+--- 1106834,41942,587210 1 0166
+arrowvertdblex 815562,0,629152 1 0167
+arrowverttp 699053,0,629152 1 0170
+arrowvertbt 699053,0,629152 1 0171
+--- 471864,125827 0 0172
+--- 471864,125827 0 0173
+--- 471864,125827 0 0174
+--- 471864,125827 0 0175
+arrowvertdbltp 815562,0,629152 1 0176
+arrowvertdblbt 815562,0,629152 1 0177
diff --git a/gnu/usr.bin/groff/devdvi/H b/gnu/usr.bin/groff/devdvi/H
new file mode 100644
index 0000000..96ae0f5
--- /dev/null
+++ b/gnu/usr.bin/groff/devdvi/H
@@ -0,0 +1,302 @@
+name H
+internalname cmss10
+spacewidth 349526
+ligatures ff fi fl ffi ffl 0
+checksum 1831058770
+designsize 10485760
+kernpairs
+ff ' 72818
+ff ? 72818
+ff ! 72818
+ff ) 72818
+ff rB 72818
+ff ] 72818
+' ? 116509
+' ! 116509
+A t -29128
+A C -29128
+A O -29128
+A G -29128
+A U -29128
+A Q -29128
+A T -87382
+A Y -87382
+A V -116509
+A W -116509
+D X -29128
+D W -29128
+D A -29128
+D V -29128
+D Y -29128
+F o -29128
+F e -29128
+F u -29128
+F r -29128
+F a -29128
+F A -87382
+F O -29128
+F C -29128
+F G -29128
+F Q -29128
+I I 29128
+K O -29128
+K C -29128
+K G -29128
+K Q -29128
+L T -87382
+L Y -87382
+L V -116509
+L W -116509
+O X -29128
+O W -29128
+O A -29128
+O V -29128
+O Y -29128
+P A -87382
+P o -29128
+P e -29128
+P a -29128
+P . -87382
+P , -87382
+T y -87382
+T e -87382
+T o -87382
+T r -87382
+T a -87382
+T A -87382
+T u -87382
+V o -29128
+V e -29128
+V u -29128
+V r -29128
+V a -29128
+V A -87382
+V O -29128
+V C -29128
+V G -29128
+V Q -29128
+W o -29128
+W e -29128
+W u -29128
+W r -29128
+W a -29128
+W A -87382
+W O -29128
+W C -29128
+W G -29128
+W Q -29128
+X O -29128
+X C -29128
+X G -29128
+X Q -29128
+Y e -87382
+Y o -87382
+Y r -87382
+Y a -87382
+Y A -87382
+Y u -87382
+a r -29128
+a y -29128
+a w -29128
+b e 29128
+b o 29128
+b x -29128
+b d 29128
+b c 29128
+b q 29128
+b r -29128
+b y -29128
+b w -29128
+f ' 72818
+f ? 72818
+f ! 72818
+f ) 72818
+f rB 72818
+f ] 72818
+g j 29128
+k e -29128
+k a -29128
+k o -29128
+k c -29128
+o e 29128
+o o 29128
+o x -29128
+o d 29128
+o c 29128
+o q 29128
+o r -29128
+o y -29128
+o w -29128
+p e 29128
+p o 29128
+p x -29128
+p d 29128
+p c 29128
+p q 29128
+p r -29128
+p y -29128
+p w -29128
+t y -29128
+t w -29128
+u w -29128
+w e -29128
+w a -29128
+w o -29128
+w c -29128
+y o -29128
+y e -29128
+y a -29128
+y . -87382
+y , -87382
+charset
+*G 567981,728178,0,0,0,-145637 2 0000
+*D 873816,728178 2 0001
+*H 815562,728178,0,0,-29128,-29128 2 0002
+*L 640800,728178 2 0003
+*C 699053,728178 2 0004
+*P 742746,728178 2 0005
+*S 757307,728178 2 0006
+*U 815562,728178,0,0,-29128,-145637 2 0007
+*F 757307,728178,0,0,-29128 2 0010
+*Q 815562,728178,0,0,-29128,-72818 2 0011
+*W 757307,728178 2 0012
+ff 611672,728178,0,72818 2 0013
+fi 562155,728178 2 0014
+fl 562155,728178 2 0015
+Fi 853427,728178 2 0016
+Fl 853427,728178 2 0017
+.i 250494,466034 0 0020
+.j 279622,466034,203890 1 0021
+ga 524290,728178 2 0022
+char180 524290,728178 2 0023
+aa "
+ah 524290,662642 2 0024
+ab 524290,728178 2 0025
+char175 524290,638464 2 0026
+a- "
+ao 699054,728178 2 0027
+char184 466035,0,178403 1 0030
+ac "
+char223 503902,728178 2 0031
+ss "
+char230 757307,466034 0 0032
+ae "
+oe 815562,466034 0 0033
+char248 524290,567979,101946 3 0034
+/o "
+char198 902944,728178 2 0035
+AE "
+OE 1019453,728178 2 0036
+char216 815562,779150,50973 3 0037
+/O "
+--- 250494,466034 0 0040
+! 334963,728178 2 0041
+rq 524290,728178 2 0042
+sh 873816,728178,203888 3 0043
+# "
+Do 524290,786432,58254 3 0044
+$ "
+% 873816,786432,58254 3 0045
+& 795173,728178 2 0046
+' 291272,728178 2 0047
+( 407781,786432,262144 3 0050
+) 407781,786432,262144 3 0051
+* 524290,786432 2 0052
++ 815562,611670,87382 3 0053
+, 291272,87381,131072 1 0054
+char173 349526,466034 0 0055
+hy "
+- "
+. 291272,87381 0 0056
+sl 524290,786432,262144 3 0057
+/ "
+0 524290,687400 2 0060
+1 524290,687400 2 0061
+2 524290,687400 2 0062
+3 524290,687400 2 0063
+4 524290,687400 2 0064
+5 524290,687400 2 0065
+6 524290,687400 2 0066
+7 524290,687400 2 0067
+8 524290,687400 2 0070
+9 524290,687400 2 0071
+: 291272,466034 0 0072
+; 291272,466034,131072 1 0073
+char161 334963,524288,203890 3 0074
+r! "
+= 815562,387973,-136315 0 0075
+char191 495163,524288,203890 3 0076
+r? "
+? 495163,728178 2 0077
+at 699053,728178 2 0100
+@ "
+A 699054,728178 2 0101
+B 699054,728178 2 0102
+C 669926,728178,0,0,-29128 2 0103
+D 757309,728178,0,0,0,-29128 2 0104
+E 626235,728178 2 0105
+F 597109,728178,0,0,0,-145637 2 0106
+G 699053,728178,0,0,-29128 2 0107
+H 742746,728178 2 0110
+I 291274,728178 2 0111
+J 495163,728178,0,0,0,-29128 2 0112
+K 728182,728178 2 0113
+L 567981,728178,0,0,0,58254 2 0114
+M 917509,728178 2 0115
+N 742746,728178 2 0116
+O 771870,728178,0,0,-29128,-29128 2 0117
+P 669926,728178,0,0,0,-145637 2 0120
+Q 771870,728178,131072,0,-29128 3 0121
+R 677208,728178 2 0122
+S 582544,728178 2 0123
+T 713616,728178,0,0,0,-145637 2 0124
+U 720901,728178,0,0,29126 2 0125
+V 699054,728178,0,14563,43691,-218454 2 0126
+W 990326,728178,0,14563,43691,-131074 2 0127
+X 699054,728178 2 0130
+Y 699054,728178,0,26214,29128,-206803 2 0131
+Z 640798,728178 2 0132
+lB 302923,786432,262144 3 0133
+[ "
+lq 524290,728178 2 0134
+rB 302923,786432,262144 3 0135
+] "
+ha 524290,728178 2 0136
+^ "
+a^ "
+a. 291272,712366 2 0137
+oq 291272,728178 2 0140
+` "
+a 503901,466034 0 0141
+b 541766,728178 2 0142
+c 466035,466034 0 0143
+d 541766,728178 2 0144
+e 466035,466034 0 0145
+f 320400,728178,0,72818 2 0146
+g 524290,466034,203890,14563 1 0147
+h 541766,728178 2 0150
+i 250494,712366 2 0151
+j 279622,712366,203890 3 0152
+k 512640,728178 2 0153
+l 250494,728178 2 0154
+m 833038,466034 0 0155
+n 541766,466034 0 0156
+o 524290,466034 0 0157
+p 541766,466034,203890 1 0160
+q 541766,466034,203890 1 0161
+r 358266,466034,0,14563 0 0162
+s 401955,466034 0 0163
+t 378653,599189 2 0164
+u 541766,466034 0 0165
+v 483512,466034,0,14563 0 0166
+w 716530,466034,0,14563 0 0167
+x 483512,466034 0 0170
+y 483512,466034,203890,14563 1 0171
+z 455840,466034 0 0172
+en 524290,466034,0,29128 0 0173
+em 1048579,466034,0,29128 0 0174
+a" 524290,728178 2 0175
+~ 524290,709454 2 0176
+a~ "
+char168 524290,712366 2 0177
+ad "
diff --git a/gnu/usr.bin/groff/devdvi/HB b/gnu/usr.bin/groff/devdvi/HB
new file mode 100644
index 0000000..aaff896
--- /dev/null
+++ b/gnu/usr.bin/groff/devdvi/HB
@@ -0,0 +1,302 @@
+name HB
+internalname cmssbx10
+spacewidth 384480
+ligatures ff fi fl ffi ffl 0
+checksum -244629176
+designsize 10485760
+kernpairs
+ff ' 80101
+ff ? 80101
+ff ! 80101
+ff ) 80101
+ff rB 80101
+ff ] 80101
+' ? 128160
+' ! 128160
+A t -32040
+A C -32040
+A O -32040
+A G -32040
+A U -32040
+A Q -32040
+A T -96120
+A Y -96120
+A V -128160
+A W -128160
+D X -32040
+D W -32040
+D A -32040
+D V -32040
+D Y -32040
+F o -32040
+F e -32040
+F u -32040
+F r -32040
+F a -32040
+F A -96120
+F O -32040
+F C -32040
+F G -32040
+F Q -32040
+I I 32040
+K O -32040
+K C -32040
+K G -32040
+K Q -32040
+L T -96120
+L Y -96120
+L V -128160
+L W -128160
+O X -32040
+O W -32040
+O A -32040
+O V -32040
+O Y -32040
+P A -96120
+P o -32040
+P e -32040
+P a -32040
+P . -96120
+P , -96120
+T y -96120
+T e -96120
+T o -96120
+T r -96120
+T a -96120
+T A -96120
+T u -96120
+V o -32040
+V e -32040
+V u -32040
+V r -32040
+V a -32040
+V A -96120
+V O -32040
+V C -32040
+V G -32040
+V Q -32040
+W o -32040
+W e -32040
+W u -32040
+W r -32040
+W a -32040
+W A -96120
+W O -32040
+W C -32040
+W G -32040
+W Q -32040
+X O -32040
+X C -32040
+X G -32040
+X Q -32040
+Y e -96120
+Y o -96120
+Y r -96120
+Y a -96120
+Y A -96120
+Y u -96120
+a r -32040
+a y -32040
+a w -32040
+b e 32040
+b o 32040
+b x -32040
+b d 32040
+b c 32040
+b q 32040
+b r -32040
+b y -32040
+b w -32040
+f ' 80101
+f ? 80101
+f ! 80101
+f ) 80101
+f rB 80101
+f ] 80101
+g j 32040
+k e -32040
+k a -32040
+k o -32040
+k c -32040
+o e 32040
+o o 32040
+o x -32040
+o d 32040
+o c 32040
+o q 32040
+o r -32040
+o y -32040
+o w -32040
+p e 32040
+p o 32040
+p x -32040
+p d 32040
+p c 32040
+p q 32040
+p r -32040
+p y -32040
+p w -32040
+t y -32040
+t w -32040
+u w -32040
+w e -32040
+w a -32040
+w o -32040
+w c -32040
+y o -32040
+y e -32040
+y a -32040
+y . -96120
+y , -96120
+charset
+*G 608760,728178,0,0,0,-160200 2 0000
+*D 961200,728178 2 0001
+*H 897120,728178,0,0,-32040,-32040 2 0002
+*L 704880,728178 2 0003
+*C 768960,728178 2 0004
+*P 833040,728178 2 0005
+*S 833040,728178 2 0006
+*U 897120,728178,0,0,-32040,-160200 2 0007
+*F 833040,728178,0,0,-32040 2 0010
+*Q 897120,728178,0,0,-32040,-80101 2 0011
+*W 833040,728178 2 0012
+ff 672840,728178,0,80101 2 0013
+fi 614586,728178 2 0014
+fl 614586,728178 2 0015
+Fi 934986,728178 2 0016
+Fl 934986,728178 2 0017
+.i 267971,480597 0 0020
+.j 300011,480597,203890 1 0021
+ga 576720,728178 2 0022
+char180 576720,728178 2 0023
+aa "
+ah 576720,666283 2 0024
+ab 576720,728178 2 0025
+char175 576720,668757 2 0026
+a- "
+ao 768960,728178 2 0027
+char184 512640,0,178403 1 0030
+ac "
+char223 592739,728178 2 0031
+ss "
+char230 833040,480597 0 0032
+ae "
+oe 897120,480597 0 0033
+char248 576720,582542,101946 3 0034
+/o "
+char198 993240,728178 2 0035
+AE "
+OE 1121400,728178 2 0036
+char216 897120,779150,50973 3 0037
+/O "
+--- 267971,480597 0 0040
+! 384480,728178 2 0041
+rq 585458,728178 2 0042
+sh 961200,728178,203888 3 0043
+# "
+Do 576720,786432,58254 3 0044
+$ "
+% 1079109,786432,58254 3 0045
+& 870906,728178 2 0046
+' 320400,728178 2 0047
+( 448560,786432,262144 3 0050
+) 448560,786432,262144 3 0051
+* 576720,786432 2 0052
++ 897120,646624,122336 3 0053
+, 320400,136898,110683 1 0054
+char173 384480,480597 0 0055
+hy "
+- "
+. 320400,136898 0 0056
+sl 576720,786432,262144 3 0057
+/ "
+0 576720,728178 2 0060
+1 576720,728178 2 0061
+2 576720,728178 2 0062
+3 576720,728178 2 0063
+4 576720,728178 2 0064
+5 576720,728178 2 0065
+6 576720,728178 2 0066
+7 576720,728178 2 0067
+8 576720,728178 2 0070
+9 576720,728178 2 0071
+: 320400,480597 0 0072
+; 320400,480597,110683 1 0073
+char161 384480,524288,203890 3 0074
+r! "
+= 897120,425984,-98304 0 0075
+char191 544680,524288,203890 3 0076
+r? "
+? 544680,728178 2 0077
+at 768960,728178 2 0100
+@ "
+A 768960,728178 2 0101
+B 768960,728178 2 0102
+C 736920,728178,0,0,-32040 2 0103
+D 833040,728178,0,0,0,-32040 2 0104
+E 672840,728178 2 0105
+F 640800,728178,0,0,0,-160200 2 0106
+G 768960,728178,0,0,-32040 2 0107
+H 833040,728178 2 0110
+I 346614,728178 2 0111
+J 544680,728178,0,0,0,-32040 2 0112
+K 801000,728178 2 0113
+L 608760,728178,0,0,0,64080 2 0114
+M 1025280,728178 2 0115
+N 833040,728178 2 0116
+O 833040,728178,0,0,-32040,-32040 2 0117
+P 736920,728178,0,0,0,-160200 2 0120
+Q 833040,728178,110683,0,-32040 3 0121
+R 736920,728178 2 0122
+S 640800,728178 2 0123
+T 768960,728178,0,0,0,-160200 2 0124
+U 801000,728178,0,0,32040 2 0125
+V 768960,728178,0,16021,48061,-240299 2 0126
+W 1089360,728178,0,16021,48061,-144179 2 0127
+X 768960,728178 2 0130
+Y 768960,728178,0,28835,32040,-227485 2 0131
+Z 704880,728178 2 0132
+lB 359722,786432,262144 3 0133
+[ "
+lq 585458,728178 2 0134
+rB 359722,786432,262144 3 0135
+] "
+ha 576720,728178 2 0136
+^ "
+a^ "
+a. 320400,728178 2 0137
+oq 320400,728178 2 0140
+` "
+a 550506,480597 0 0141
+b 588371,728178 2 0142
+c 512640,480597 0 0143
+d 588371,728178 2 0144
+e 535942,480597 0 0145
+f 352440,728178,0,80101 2 0146
+g 576720,480597,203890,16021 1 0147
+h 588371,728178 2 0150
+i 267971,728178 2 0151
+j 300011,728178,203890 3 0152
+k 556331,728178 2 0153
+l 267971,728178 2 0154
+m 908771,480597 0 0155
+n 588371,480597 0 0156
+o 576720,480597 0 0157
+p 588371,480597,203890 1 0160
+q 588371,480597,203890 1 0161
+r 390306,480597,0,16021 0 0162
+s 442152,480597 0 0163
+t 423802,617914 2 0164
+u 588371,480597 0 0165
+v 524291,480597,0,16021 0 0166
+w 780611,480597,0,16021 0 0167
+x 524291,480597 0 0170
+y 524291,480597,203890,16021 1 0171
+z 499533,480597 0 0172
+en 576720,480597,0,32040 0 0173
+em 1153440,480597,0,32040 0 0174
+a" 576720,728178 2 0175
+~ 576720,728178 2 0176
+a~ "
+char168 576720,728178 2 0177
+ad "
diff --git a/gnu/usr.bin/groff/devdvi/HI b/gnu/usr.bin/groff/devdvi/HI
new file mode 100644
index 0000000..dcfcced
--- /dev/null
+++ b/gnu/usr.bin/groff/devdvi/HI
@@ -0,0 +1,303 @@
+name HI
+internalname cmssi10
+spacewidth 349526
+slant 11.999911
+ligatures ff fi fl ffi ffl 0
+checksum -984248855
+designsize 10485760
+kernpairs
+ff ' 72818
+ff ? 72818
+ff ! 72818
+ff ) 72818
+ff rB 72818
+ff ] 72818
+' ? 116509
+' ! 116509
+A t -29128
+A C -29128
+A O -29128
+A G -29128
+A U -29128
+A Q -29128
+A T -87382
+A Y -87382
+A V -116509
+A W -116509
+D X -29128
+D W -29128
+D A -29128
+D V -29128
+D Y -29128
+F o -29128
+F e -29128
+F u -29128
+F r -29128
+F a -29128
+F A -87382
+F O -29128
+F C -29128
+F G -29128
+F Q -29128
+I I 29128
+K O -29128
+K C -29128
+K G -29128
+K Q -29128
+L T -87382
+L Y -87382
+L V -116509
+L W -116509
+O X -29128
+O W -29128
+O A -29128
+O V -29128
+O Y -29128
+P A -87382
+P o -29128
+P e -29128
+P a -29128
+P . -87382
+P , -87382
+T y -87382
+T e -87382
+T o -87382
+T r -87382
+T a -87382
+T A -87382
+T u -87382
+V o -29128
+V e -29128
+V u -29128
+V r -29128
+V a -29128
+V A -87382
+V O -29128
+V C -29128
+V G -29128
+V Q -29128
+W o -29128
+W e -29128
+W u -29128
+W r -29128
+W a -29128
+W A -87382
+W O -29128
+W C -29128
+W G -29128
+W Q -29128
+X O -29128
+X C -29128
+X G -29128
+X Q -29128
+Y e -87382
+Y o -87382
+Y r -87382
+Y a -87382
+Y A -87382
+Y u -87382
+a r -29128
+a y -29128
+a w -29128
+b e 29128
+b o 29128
+b x -29128
+b d 29128
+b c 29128
+b q 29128
+b r -29128
+b y -29128
+b w -29128
+f ' 72818
+f ? 72818
+f ! 72818
+f ) 72818
+f rB 72818
+f ] 72818
+g j 29128
+k e -29128
+k a -29128
+k o -29128
+k c -29128
+o e 29128
+o o 29128
+o x -29128
+o d 29128
+o c 29128
+o q 29128
+o r -29128
+o y -29128
+o w -29128
+p e 29128
+p o 29128
+p x -29128
+p d 29128
+p c 29128
+p q 29128
+p r -29128
+p y -29128
+p w -29128
+t y -29128
+t w -29128
+u w -29128
+w e -29128
+w a -29128
+w o -29128
+w c -29128
+y o -29128
+y e -29128
+y a -29128
+y . -87382
+y , -87382
+charset
+*G 567981,728178,0,140214,0,-5422 2 0000
+*D 873816,728178 2 0001
+*H 815562,728178,0,79216,-75562,50088 2 0002
+*L 640800,728178 2 0003
+*C 699053,728178,0,134389,0,67195 2 0004
+*P 742746,728178,0,84870,0,42435 2 0005
+*S 757307,728178,0,125650,0,62826 2 0006
+*U 815562,728178,0,94694,-152950,-50942 2 0007
+*F 757307,728178,0,48261,-106517,48261 2 0010
+*Q 815562,728178,0,94694,-152950,-10907 2 0011
+*W 757307,728178,0,86955,0,43478 2 0012
+ff 611672,728178,0,227595 2 0013
+fi 562155,728178,0,102349 2 0014
+fl 562155,728178,0,99435 2 0015
+Fi 853427,728178,0,102349 2 0016
+Fl 853427,728178,0,99435 2 0017
+.i 250494,466034,0,43715 0 0020
+.j 279622,466034,203890,43715 1 0021
+ga 524290,728178 2 0022
+char180 524290,728178,0,96523 2 0023
+aa "
+ah 524290,662642,0,88419 2 0024
+ab 524290,728178,0,99435 2 0025
+char175 524290,638464,0,92018 2 0026
+a- "
+ao 773347,728178 2 0027
+char184 466035,0,178403 1 0030
+ac "
+char223 503902,728178,0,96523 2 0031
+ss "
+char230 757307,466034,0,71070 0 0032
+ae "
+oe 815562,466034,0,71070 0 0033
+char248 524290,567979,101946,50821 3 0034
+/o "
+char198 902944,728178,0,125650 2 0035
+AE "
+OE 1019453,728178,0,125650 2 0036
+char216 815562,779150,50973,79216 3 0037
+/O "
+--- 250494,466034 0 0040
+! 334963,728178,0,60114 2 0041
+rq 524290,728178,0,3315 2 0042
+sh 873816,728178,203888,53338 3 0043
+# "
+Do 524290,786432,58254,116982 3 0044
+$ "
+% 873816,786432,58254,32782 3 0045
+& 795173,728178,0,32064 2 0046
+' 291272,728178,0,81960 2 0047
+( 407781,786432,262144,138032 3 0050
+) 407781,786432,262144,26592 3 0051
+* 524290,786432,0,123469 2 0052
++ 815562,611670,87382,26592 3 0053
+, 291272,87381,131072 1 0054
+char173 349526,466034,0,20402 0 0055
+hy "
+- "
+. 291272,87381 0 0056
+sl 524290,786432,262144,138032 3 0057
+/ "
+0 524290,687400,0,116982 2 0060
+1 524290,687400,0,116982 2 0061
+2 524290,687400,0,116982 2 0062
+3 524290,687400,0,116982 2 0063
+4 524290,687400,0,116982 2 0064
+5 524290,687400,0,116982 2 0065
+6 524290,687400,0,116982 2 0066
+7 524290,687400,0,116982 2 0067
+8 524290,687400,0,116982 2 0070
+9 524290,687400,0,116982 2 0071
+: 291272,466034,0,26240 0 0072
+; 291272,466034,131072,26240 1 0073
+char161 334963,524288,203890,16776 3 0074
+r! "
+= 815562,387973,-136315,53338 0 0075
+char191 495163,524288,203890 3 0076
+r? "
+? 495163,728178,0,123822 2 0077
+at 699053,728178,0,79216 2 0100
+@ "
+A 699054,728178 2 0101
+B 699054,728178,0,86955,0,43478 2 0102
+C 669926,728178,0,125650,-75562,62826 2 0103
+D 757309,728178,0,79216,0,50088 2 0104
+E 626235,728178,0,125650,0,62826 2 0105
+F 597109,728178,0,140214,0,-5422 2 0106
+G 699053,728178,0,125650,-75562,62826 2 0107
+H 742746,728178,0,84870,0,42435 2 0110
+I 291274,728178,0,140214,0,70107 2 0111
+J 495163,728178,0,84870,0,13307 2 0112
+K 728182,728178,0,125650,0,62826 2 0113
+L 567981,728178,0,0,0,58254 2 0114
+M 917509,728178,0,84870,0,13307 2 0115
+N 742746,728178,0,84870,0,13307 2 0116
+O 771870,728178,0,79216,-75562,50088 2 0117
+P 669926,728178,0,86955,0,-58682 2 0120
+Q 771870,728178,131072,79216,-75562,79216 3 0121
+R 677208,728178,0,86955,0,65216 2 0122
+S 582544,728178,0,96523,0,48262 2 0123
+T 713616,728178,0,140214,-116083,-5422 2 0124
+U 720901,728178,0,84870,-75562,13307 2 0125
+V 699054,728178,0,169341,-111086,-63677 2 0126
+W 990326,728178,0,169341,-111086,23704 2 0127
+X 699054,728178,0,140214,0,70107 2 0130
+Y 699054,728178,0,180992,-125650,-52026 2 0131
+Z 640798,728178,0,125650,0,62826 2 0132
+lB 302923,786432,262144,167160 3 0133
+[ "
+lq 524290,728178,0,148952 2 0134
+rB 302923,786432,262144,91429 3 0135
+] "
+ha 524290,728178,0,83776 2 0136
+^ "
+a^ "
+a. 291272,712366,0,81512 2 0137
+oq 291272,728178,0,81960 2 0140
+` "
+a 503901,466034,0,10283 0 0141
+b 541766,728178,0,32053 2 0142
+c 466035,466034,0,87406 0 0143
+d 541766,728178,0,99435 2 0144
+e 466035,466034,0,71070 0 0145
+f 320400,728178,0,227595 2 0146
+g 524290,466034,203890,113621 1 0147
+h 541766,728178,0,18642 2 0150
+i 250494,712366,0,101901 2 0151
+j 279622,712366,203890,96075 3 0152
+k 512640,728178,0,87406 2 0153
+l 250494,728178,0,99435 2 0154
+m 833038,466034,0,18642 0 0155
+n 541766,466034,0,18642 0 0156
+o 524290,466034,0,69341 0 0157
+p 541766,466034,203890,40790 1 0160
+q 541766,466034,203890,43715 1 0161
+r 358266,466034,0,113621 0 0162
+s 401955,466034,0,81581 0 0163
+t 378653,599189,0,75757 2 0164
+u 541766,466034,0,43715 0 0165
+v 483512,466034,0,113621 0 0166
+w 716530,466034,0,113621 0 0167
+x 483512,466034,0,96144 0 0170
+y 483512,466034,203890,113621 1 0171
+z 455840,466034,0,91776 0 0172
+en 524290,466034,0,90349 0 0173
+em 1048579,466034,0,90349 0 0174
+a" 524290,728178,0,96523 2 0175
+~ 524290,709454,0,92544 2 0176
+a~ "
+char168 524290,712366,0,66949 2 0177
+ad "
diff --git a/gnu/usr.bin/groff/devdvi/I b/gnu/usr.bin/groff/devdvi/I
new file mode 100644
index 0000000..a465016
--- /dev/null
+++ b/gnu/usr.bin/groff/devdvi/I
@@ -0,0 +1,353 @@
+name I
+special
+internalname cmti10
+spacewidth 375155
+slant 14.036243
+ligatures ff fi fl ffi ffl 0
+checksum -50321606
+designsize 10485760
+kernpairs
+ff ' 109373
+ff ? 109373
+ff ! 109373
+ff ) 109373
+ff rB 109373
+ff ] 109373
+' ' -80390
+' ? 107187
+' ! 107187
+A n -26797
+A l -26797
+A r -26797
+A u -26797
+A m -26797
+A t -26797
+A i -26797
+A C -26797
+A O -26797
+A G -26797
+A h -26797
+A b -26797
+A U -26797
+A k -26797
+A v -26797
+A w -26797
+A Q -26797
+A T -80390
+A Y -80390
+A V -107187
+A W -107187
+A e -53594
+A a -53594
+A o -53594
+A d -53594
+A c -53594
+A g -53594
+A q -53594
+D X -26797
+D W -26797
+D A -26797
+D V -26797
+D Y -26797
+F o -80390
+F e -80390
+F u -80390
+F r -80390
+F a -80390
+F A -107187
+F O -26797
+F C -26797
+F G -26797
+F Q -26797
+K O -26797
+K C -26797
+K G -26797
+K Q -26797
+L T -80390
+L Y -80390
+L V -107187
+L W -107187
+L e -53594
+L a -53594
+L o -53594
+L d -53594
+L c -53594
+L g -53594
+L q -53594
+O X -26797
+O W -26797
+O A -26797
+O V -26797
+O Y -26797
+P A -80390
+R n -26797
+R l -26797
+R r -26797
+R u -26797
+R m -26797
+R t -26797
+R i -26797
+R C -26797
+R O -26797
+R G -26797
+R h -26797
+R b -26797
+R U -26797
+R k -26797
+R v -26797
+R w -26797
+R Q -26797
+R T -80390
+R Y -80390
+R V -107187
+R W -107187
+R e -53594
+R a -53594
+R o -53594
+R d -53594
+R c -53594
+R g -53594
+R q -53594
+T y -80390
+T e -80390
+T o -80390
+T r -80390
+T a -80390
+T u -80390
+T A -80390
+V o -80390
+V e -80390
+V u -80390
+V r -80390
+V a -80390
+V A -107187
+V O -26797
+V C -26797
+V G -26797
+V Q -26797
+W A -80390
+X O -26797
+X C -26797
+X G -26797
+X Q -26797
+Y e -80390
+Y o -80390
+Y r -80390
+Y a -80390
+Y u -80390
+Y A -80390
+oq oq -80390
+oq ` -80390
+` oq -80390
+` ` -80390
+b e -53594
+b a -53594
+b o -53594
+b d -53594
+b c -53594
+b g -53594
+b q -53594
+c e -53594
+c a -53594
+c o -53594
+c d -53594
+c c -53594
+c g -53594
+c q -53594
+d l 53594
+e e -53594
+e a -53594
+e o -53594
+e d -53594
+e c -53594
+e g -53594
+e q -53594
+Fn ' 109373
+f ' 109373
+Fn ? 109373
+f ? 109373
+Fn ! 109373
+f ! 109373
+Fn ) 109373
+f ) 109373
+Fn rB 109373
+Fn ] 109373
+f rB 109373
+f ] 109373
+l l 53594
+n ' -107187
+o e -53594
+o a -53594
+o o -53594
+o d -53594
+o c -53594
+o g -53594
+o q -53594
+p e -53594
+p a -53594
+p o -53594
+p d -53594
+p c -53594
+p g -53594
+p q -53594
+r e -53594
+r a -53594
+r o -53594
+r d -53594
+r c -53594
+r g -53594
+r q -53594
+w l 53594
+charset
+*G 657686,716526,0,139518,0,5534 2 0000
+*D 857498,716526 2 0001
+*H 803904,716526,0,98595,-80538,71798 2 0002
+*L 725843,716526 2 0003
+*C 696717,716526,0,160373,0,80187 2 0004
+*P 779437,716526,0,171851,0,85926 2 0005
+*S 750310,716526,0,126120,0,63061 2 0006
+*U 803904,716526,0,116509,-170102,-17475 2 0007
+*F 750310,716526,0,62770,-116363,62770 2 0010
+*Q 803904,716526,0,116509,-170102,4659 2 0011
+*W 750310,716526,0,107552,0,53776 2 0012
+ff 643123,728178,203890,222240 3 0013
+fi 589530,728178,203890,108354 3 0014
+fl 616326,728178,203890,108354 3 0015
+Fi 924490,728178,203890,108354 3 0016
+Fl 937888,728178,203890,108354 3 0017
+.i 321562,451470,0,80440 0 0020
+.j 348358,451470,203890,39176 1 0021
+ga 535936,728178 2 0022
+char180 535936,728178,0,101654 2 0023
+aa "
+ah 535936,659002,0,86982 2 0024
+ab 535936,728178,0,113306 2 0025
+char175 535936,588949,0,108354 2 0026
+a- "
+ao 871672,728178 2 0027
+char184 482342,0,178403 1 0030
+ac "
+char223 562733,728178,203890,110245 3 0031
+ss "
+char230 750310,451470,0,78789 0 0032
+ae "
+oe 750310,451470,0,78789 0 0033
+char248 535936,553416,101946,96411 3 0034
+/o "
+char198 925654,716526,0,126120 2 0035
+AE "
+OE 1032842,716526,0,126120 2 0036
+char216 803904,767499,50973,98595 3 0037
+/O "
+--- 267968,451470 0 0040
+! 321562,728178,0,130200 2 0041
+rq 539432,728178,0,72994 2 0042
+sh 857498,728178,203888,69378 3 0043
+# "
+char163 806453,728178 2 0044
+Po "
+% 857498,786432,58254,143014 3 0045
+& 803904,728178,0,101654 2 0046
+' 321562,728178,0,130200 2 0047
+( 428749,786432,262144,169811 3 0050
+) 428749,786432,262144,38739 3 0051
+* 535936,786432,0,156413 2 0052
++ 803904,588949,59418,38739 3 0053
+, 321562,110683,203890 1 0054
+char173 375155,451470,0,29637 0 0055
+hy "
+- "
+. 321562,110683 0 0056
+sl 535936,786432,262144,169811 3 0057
+/ "
+0 535936,675749,0,142141 2 0060
+1 535936,675749,0,142141 2 0061
+2 535936,675749,0,142141 2 0062
+3 535936,675749,0,142141 2 0063
+4 535936,675749,203890,142141 3 0064
+5 535936,675749,0,142141 2 0065
+6 535936,675749,0,142141 2 0066
+7 535936,675749,203890,142141 3 0067
+8 535936,675749,0,142141 2 0070
+9 535936,675749,0,142141 2 0071
+: 321562,451470,0,61022 0 0072
+; 321562,451470,203890,61022 1 0073
+char161 321562,524288,203890,79227 3 0074
+r! "
+= 803904,384696,-139592,69378 0 0075
+char191 535936,524288,203890 3 0076
+r? "
+? 535936,728178,0,128451 2 0077
+at 803904,728178,0,100634 2 0100
+@ "
+A 779437,716526 2 0101
+B 738077,716526,0,107552,0,53776 2 0102
+C 750310,716526,0,152334,-80538,76168 2 0103
+D 791670,716526,0,98595,0,71798 2 0104
+E 711280,716526,0,126120,0,63061 2 0105
+F 684483,716526,0,139518,0,5534 2 0106
+G 811186,716526,0,91459,-80538,91459 2 0107
+H 779437,716526,0,171851,0,85926 2 0110
+I 404282,716526,0,165733,0,82867 2 0111
+J 550499,716526,0,147093,0,46750 2 0112
+K 806234,716526,0,152334,0,76168 2 0113
+L 657686,716526,0,0,0,53594 2 0114
+M 940218,716526,0,171851,0,59130 2 0115
+N 779437,716526,0,171851,0,59130 2 0116
+O 803904,716526,0,98595,-80538,71798 2 0117
+P 711280,716526,0,107552,0,-26432 2 0120
+Q 803904,716526,203890,98595,-80538,98595 3 0121
+R 764874,716526,0,40560,0,30421 2 0122
+S 589530,716526,0,125538,0,62770 2 0123
+T 750310,716526,0,139518,-134349,5534 2 0124
+U 779437,716526,0,171851,-121898,59130 2 0125
+V 779437,716526,0,192530,-138936,-21845 2 0126
+W 1047405,716526,0,192530,-138936,58546 2 0127
+X 779437,716526,0,165733,0,82867 2 0130
+Y 779437,716526,0,203248,-152334,-11126 2 0131
+Z 643123,716526,0,152334,0,76168 2 0132
+lB 321562,786432,262144,196608 3 0133
+[ "
+lq 539432,728178,0,176685 2 0134
+rB 321562,786432,262144,110392 3 0135
+] "
+ha 535936,728178,0,69688 2 0136
+^ "
+a^ "
+a. 321562,700301,0,123230 2 0137
+oq 321562,728178,0,130200 2 0140
+` "
+a 535936,451470,0,80440,-46677,80440 0 0141
+b 482342,728178,0,66190,-46677,66190 2 0142
+c 482342,451470,0,59274,-46677,59274 0 0143
+d 535936,728178,0,108354,-46677,108354 2 0144
+e 482342,451470,0,78789,-46677,78789 0 0145
+Fn 321562,728178,203890,222240,104566,112867 3 0146
+f "
+g 482342,451470,203890,92770,-21045,55147 1 0147
+h 535936,728178,0,80440,0,80440 2 0150
+i 321562,687194,0,106846,-32427,106846 2 0151
+j 321562,687194,203890,151701,50973,92770 3 0152
+k 482342,728178,0,112867,0,80440 2 0153
+l 267968,728178,0,108354,-26797,107237 2 0154
+m 857498,451470,0,80440,-32427,80440 0 0155
+n 589530,451470,0,80440,-32427,80440 0 0156
+o 535936,451470,0,66190,-46677,66190 0 0157
+p 535936,451470,203890,66190,-22718,66190 1 0160
+q 482342,451470,203890,92770,-46677,55147 1 0161
+r 442147,451470,0,112867,-32427,86070 0 0162
+s 428749,451470,0,86070,0,86070 0 0163
+t 348358,644958,0,99469,-45875,99469 2 0164
+u 562733,451470,0,80440,-32427,80440 0 0165
+v 482342,451470,0,112867,-32427,75245 0 0166
+w 696717,451470,0,112867,-32427,84651 0 0167
+x 486421,451470,0,126266,0,126266 0 0170
+y 509139,451470,203890,92770,-32427,55147 1 0171
+z 428749,451470,0,128888,0,80440 0 0172
+en 535936,451470,0,96552 0 0173
+em 1071872,451470,0,96552 0 0174
+a" 535936,728178,0,128451 2 0175
+~ 535936,700301,0,121482 2 0176
+a~ "
+char168 535936,700301,0,109832 2 0177
+ad "
diff --git a/gnu/usr.bin/groff/devdvi/MI b/gnu/usr.bin/groff/devdvi/MI
new file mode 100644
index 0000000..2b2e349
--- /dev/null
+++ b/gnu/usr.bin/groff/devdvi/MI
@@ -0,0 +1,136 @@
+name MI
+special
+internalname cmmi10
+slant 14.036243
+checksum 195060286
+designsize 10485760
+charset
+--- 645166,716526,0,145637 2 0000
+--- 873816,716526 2 0001
+--- 799829,716526,0,29128 2 0002
+--- 728179,716526 2 0003
+--- 778424,716526,0,79371 2 0004
+--- 871630,716526,0,85195 2 0005
+--- 817746,716526,0,60438 2 0006
+--- 611669,716526,0,145637 2 0007
+--- 699051,716526 2 0010
+--- 641962,716526,0,115344 2 0011
+--- 809918,716526,0,52610 2 0012
+*a 670776,451470,0,3882 0 0013
+*b 593102,728178,203890,55342 3 0014
+*g 542880,451470,203890,58254 1 0015
+*d 466034,728178,0,39685 2 0016
+*e 425621,451470 0 0017
+*z 458754,728178,203890,77368 3 0020
+*y 520651,451470,203890,37622 1 0021
+*h 492248,728178,0,29128 2 0022
+*i 371130,451470 0 0023
+*k 604147,451470 0 0024
+*l 611672,728178 2 0025
+char181 631819,451470,203890 1 0026
+*m "
+*n 517979,451470,0,66750 0 0027
+*c 458754,728178,203890,48242 3 0030
+*p 597717,451470,0,37622 0 0031
+*r 542130,451470,203890 1 0032
+*s 599171,451470,0,37622 0 0033
+*t 458390,451470,0,118694 0 0034
+*u 566525,451470,0,37622 0 0035
+*f 624778,728178,203890 3 0036
+*x 656086,451470,203890 1 0037
+*q 683034,728178,203890,37622 3 0040
+*w 652691,451470,0,37622 0 0041
+--- 488970,451470 0 0042
++h 620170,728178 2 0043
++p 868357,451470,0,29128 0 0044
+--- 542130,451470,203890 1 0045
+ts 380474,451470,101946,83739 1 0046
++f 685944,451470,203890 1 0047
+--- 1048579,384696,-139592 0 0050
+--- 1048579,384696,-139592 0 0051
+--- 1048579,384696,-139592 0 0052
+--- 1048579,384696,-139592 0 0053
+--- 291272,486275,-38013 2 0054
+--- 291272,486275,-38013 2 0055
+--- 524290,487880,-36408 2 0056
+--- 524290,487880,-36408 2 0057
+--- 524290,451470 0 0060
+--- 524290,451470 0 0061
+--- 524290,451470 0 0062
+--- 524290,451470,203890 1 0063
+--- 524290,451470,203890 1 0064
+--- 524290,451470,203890 1 0065
+--- 524290,675749 2 0066
+--- 524290,451470,203890 1 0067
+--- 524290,675749 2 0070
+--- 524290,451470,203890 1 0071
+--- 291272,110683 0 0072
+--- 291272,110683,203890 1 0073
+< 815562,565285,40997 3 0074
+--- 524290,786432,262144 3 0075
+> 815562,565285,40997 3 0076
+--- 524290,487880,-36408 2 0077
+pd 556693,728178,0,58254 2 0100
+--- 786434,716526 2 0101
+--- 795355,716526,0,52610 2 0102
+--- 749440,716526,0,75002 2 0103
+--- 868134,716526,0,29128 2 0104
+--- 774054,716526,0,60438 2 0105
+--- 674294,716526,0,145637 2 0106
+--- 824442,716526 2 0107
+--- 871630,716526,0,85195 2 0110
+--- 460938,716526,0,82283 2 0111
+--- 581450,716526,0,100853 2 0112
+--- 890563,716526,0,75002 2 0113
+--- 713616,716526 2 0114
+--- 1017266,716526,0,114323 2 0115
+--- 842502,716526,0,114323 2 0116
+--- 799829,716526,0,29128 2 0117
+--- 673200,716526,0,145637 2 0120
+--- 828957,716526,203890 3 0121
+--- 796173,716526,0,8101 2 0122
+--- 642982,716526,0,60438 2 0123
+--- 612763,716526,0,145637 2 0124
+--- 715944,716526,0,114323 2 0125
+--- 611670,716526,0,233018 2 0126
+--- 990323,716526,0,145637 2 0127
+--- 868718,716526,0,82283 2 0130
+--- 608758,716526,0,233018 2 0131
+--- 715800,716526,0,75002 2 0132
+--- 407781,786432 2 0133
+--- 407781,728178,203890 3 0134
+--- 407781,728178,203890 3 0135
+--- 1048579,375013,-149275 0 0136
+--- 1048579,375013,-149275 0 0137
+--- 436910,728178 2 0140
+--- 554267,451470 0 0141
+--- 450014,728178 2 0142
+--- 453778,451470 0 0143
+--- 545771,728178 2 0144
+--- 488245,451470 0 0145
+--- 513368,728178,203890,112869 3 0146
+--- 500138,451470,203890,37622 1 0147
+--- 604147,728178 2 0150
+--- 361248,691562 2 0151
+--- 431811,691562,203890,60024 3 0152
+--- 545893,728178,0,33010 2 0153
+--- 312874,728178,0,20634 2 0154
+--- 920664,451470 0 0155
+--- 629392,451470 0 0156
+*o 508269,451470 0 0157
+--- 527566,451470,203890 1 0160
+--- 468099,451470,203890,37622 1 0161
+--- 473075,451470,0,29128 0 0162
+--- 491520,451470 0 0163
+--- 378654,644958 2 0164
+--- 600266,451470 0 0165
+--- 508270,451470,0,37622 0 0166
+--- 750694,451470,0,28216 0 0167
+--- 599291,451470 0 0170
+--- 514098,451470,203890,37622 1 0171
+--- 487640,451470,0,46117 0 0172
+--- 338120,451470 0 0173
+--- 402685,451470,203890 1 0174
+wp 667376,451470,203890 1 0175
+--- 524290,749149,0,161291 2 0176
+--- 291272,728178,0,418866 2 0177
diff --git a/gnu/usr.bin/groff/devdvi/Makefile b/gnu/usr.bin/groff/devdvi/Makefile
new file mode 100644
index 0000000..c851566
--- /dev/null
+++ b/gnu/usr.bin/groff/devdvi/Makefile
@@ -0,0 +1,14 @@
+DEVICE= dvi
+FONTFILES= R I B BI CW MI S EX H HI HB SA SB DESC $(DEVGENFILES)
+DEVGENFILES= generate/CompileFonts generate/Makefile generate/msam.map\
+ generate/msbm.map generate/texb.map generate/texex.map \
+ generate/texi.map generate/texmi.map generate/texr.map \
+ generate/texsy.map generate/textt.map generate/cork.map
+
+CLEANFILES+= DESC
+
+DESC: DESC.in
+ cat ${.CURDIR}/DESC.in >DESC
+ test -z '${DVIPRINT}' || echo print '${DVIPRINT}' >>DESC
+
+.include "../Makefile.dev"
diff --git a/gnu/usr.bin/groff/devdvi/Makefile.sub b/gnu/usr.bin/groff/devdvi/Makefile.sub
new file mode 100644
index 0000000..8c3248f
--- /dev/null
+++ b/gnu/usr.bin/groff/devdvi/Makefile.sub
@@ -0,0 +1,11 @@
+DEV=dvi
+DEVFILES=DESC R I B BI CW MI S EX H HI HB SA SB \
+ generate/CompileFonts generate/Makefile generate/msam.map generate/msbm.map \
+ generate/texb.map generate/texex.map generate/texi.map generate/texmi.map \
+ generate/texr.map generate/texsy.map generate/textt.map
+
+CLEANADD=DESC
+
+DESC: DESC.in
+ cat $(srcdir)/DESC.in >DESC
+ test -z '$(DVIPRINT)' || echo print '$(DVIPRINT)' >>DESC
diff --git a/gnu/usr.bin/groff/devdvi/R b/gnu/usr.bin/groff/devdvi/R
new file mode 100644
index 0000000..3e49b93
--- /dev/null
+++ b/gnu/usr.bin/groff/devdvi/R
@@ -0,0 +1,430 @@
+name R
+special
+internalname cmr10
+spacewidth 349526
+ligatures ff fi fl ffi ffl 0
+checksum 1274110073
+designsize 10485760
+kernpairs
+ff ' 81557
+ff ? 81557
+ff ! 81557
+ff ) 81557
+ff rB 81557
+ff ] 81557
+' ' -87382
+' ? 116509
+' ! 116509
+*A t -29128
+A t -29128
+*A C -29128
+A C -29128
+*A *O -29128
+*A O -29128
+A *O -29128
+A O -29128
+*A G -29128
+A G -29128
+*A U -29128
+A U -29128
+*A Q -29128
+A Q -29128
+*A *T -87382
+*A T -87382
+A *T -87382
+A T -87382
+*A Y -87382
+A Y -87382
+*A V -116509
+A V -116509
+*A W -116509
+A W -116509
+D *X -29128
+D X -29128
+D W -29128
+D *A -29128
+D A -29128
+D V -29128
+D Y -29128
+F o -87382
+F e -87382
+F u -87382
+F r -87382
+F a -87382
+F *A -116509
+F A -116509
+F *O -29128
+F O -29128
+F C -29128
+F G -29128
+F Q -29128
+*I *I 29128
+*I I 29128
+I *I 29128
+I I 29128
+*K *O -29128
+*K O -29128
+K *O -29128
+K O -29128
+*K C -29128
+K C -29128
+*K G -29128
+K G -29128
+*K Q -29128
+K Q -29128
+L *T -87382
+L T -87382
+L Y -87382
+L V -116509
+L W -116509
+*O *X -29128
+*O X -29128
+O *X -29128
+O X -29128
+*O W -29128
+O W -29128
+*O *A -29128
+*O A -29128
+O *A -29128
+O A -29128
+*O V -29128
+O V -29128
+*O Y -29128
+O Y -29128
+*R *A -87382
+*R A -87382
+P *A -87382
+P A -87382
+*R o -29128
+P o -29128
+*R e -29128
+P e -29128
+*R a -29128
+P a -29128
+*R . -87382
+P . -87382
+*R , -87382
+P , -87382
+R t -29128
+R C -29128
+R *O -29128
+R O -29128
+R G -29128
+R U -29128
+R Q -29128
+R *T -87382
+R T -87382
+R Y -87382
+R V -116509
+R W -116509
+*T y -29128
+T y -29128
+*T e -87382
+T e -87382
+*T o -87382
+T o -87382
+*T r -87382
+T r -87382
+*T a -87382
+T a -87382
+*T *A -87382
+*T A -87382
+T *A -87382
+T A -87382
+*T u -87382
+T u -87382
+V o -87382
+V e -87382
+V u -87382
+V r -87382
+V a -87382
+V *A -116509
+V A -116509
+V *O -29128
+V O -29128
+V C -29128
+V G -29128
+V Q -29128
+W o -87382
+W e -87382
+W u -87382
+W r -87382
+W a -87382
+W *A -116509
+W A -116509
+W *O -29128
+W O -29128
+W C -29128
+W G -29128
+W Q -29128
+*X *O -29128
+*X O -29128
+X *O -29128
+X O -29128
+*X C -29128
+X C -29128
+*X G -29128
+X G -29128
+*X Q -29128
+X Q -29128
+Y e -87382
+Y o -87382
+Y r -87382
+Y a -87382
+Y *A -87382
+Y A -87382
+Y u -87382
+oq oq -87382
+oq ` -87382
+` oq -87382
+` ` -87382
+a v -29128
+a j 58254
+a y -29128
+a w -29128
+b e 29128
+b o 29128
+b x -29128
+b d 29128
+b c 29128
+b q 29128
+b v -29128
+b j 58254
+b y -29128
+b w -29128
+c h -29128
+c k -29128
+f ' 81557
+f ? 81557
+f ! 81557
+f ) 81557
+f rB 81557
+f ] 81557
+g j 29128
+h t -29128
+h u -29128
+h b -29128
+h y -29128
+h v -29128
+h w -29128
+k a -58254
+k e -29128
+k a -29128
+k o -29128
+k c -29128
+m t -29128
+m u -29128
+m b -29128
+m y -29128
+m v -29128
+m w -29128
+n t -29128
+n u -29128
+n b -29128
+n y -29128
+n v -29128
+n w -29128
+o e 29128
+o o 29128
+o x -29128
+o d 29128
+o c 29128
+o q 29128
+o v -29128
+o j 58254
+o y -29128
+o w -29128
+p e 29128
+p o 29128
+p x -29128
+p d 29128
+p c 29128
+p q 29128
+p v -29128
+p j 58254
+p y -29128
+p w -29128
+t y -29128
+t w -29128
+u w -29128
+v a -58254
+v e -29128
+v a -29128
+v o -29128
+v c -29128
+w e -29128
+w a -29128
+w o -29128
+w c -29128
+y o -29128
+y e -29128
+y a -29128
+y . -87382
+y , -87382
+charset
+*G 655362,716526,0,0,0,-145637 2 0000
+*D 873816,716526 2 0001
+*H 815562,716526,0,0,-29128,-29128 2 0002
+*L 728179,716526 2 0003
+*C 699053,716526 2 0004
+*P 786434,716526 2 0005
+*S 757307,716526 2 0006
+*U 815562,716526,0,0,-29128,-145637 2 0007
+*F 757307,716526,0,0,-29128 2 0010
+*Q 815562,716526,0,0,-29128,-72818 2 0011
+*W 757307,716526 2 0012
+ff 611672,728178,0,81557 2 0013
+fi 582544,728178 2 0014
+fl 582544,728178 2 0015
+Fi 873816,728178 2 0016
+Fl 873816,728178 2 0017
+.i 291272,451470 0 0020
+.j 320400,451470,203890 1 0021
+ga 524290,728178 2 0022
+char180 524290,728178 2 0023
+aa "
+ah 524290,659002 2 0024
+ab 524290,728178 2 0025
+char175 524290,595357 2 0026
+a- "
+ao 786434,728178 2 0027
+char184 466035,0,178403 1 0030
+ac "
+char223 524291,728178 2 0031
+ss "
+char230 757307,451470 0 0032
+ae "
+oe 815562,451470 0 0033
+char248 524290,553416,101946 3 0034
+/o "
+char198 946634,716526 2 0035
+AE "
+OE 1063142,716526 2 0036
+char216 815562,767499,50973 3 0037
+/O "
+--- 291272,451470 0 0040
+! 291272,728178 2 0041
+rq 524290,728178 2 0042
+sh 873816,728178,203888 3 0043
+# "
+Do 524290,786432,58254 3 0044
+$ "
+% 873816,786432,58254 3 0045
+& 815562,728178 2 0046
+' 291272,728178 2 0047
+( 407781,786432,262144 3 0050
+) 407781,786432,262144 3 0051
+* 524290,786432 2 0052
+pl 815562,611670,87382 3 0053
++ "
+, 291272,110683,203890 1 0054
+char173 349526,451470 0 0055
+hy "
+- "
+. 291272,110683 0 0056
+sl 524290,786432,262144 3 0057
+/ "
+0 524290,675749 2 0060
+1 524290,675749 2 0061
+2 524290,675749 2 0062
+3 524290,675749 2 0063
+4 524290,675749 2 0064
+5 524290,675749 2 0065
+6 524290,675749 2 0066
+7 524290,675749 2 0067
+8 524290,675749 2 0070
+9 524290,675749 2 0071
+: 291272,451470 0 0072
+; 291272,451470,203890 1 0073
+char161 291272,524288,203890 3 0074
+r! "
+eq 815562,384696,-139592 0 0075
+= "
+char191 495163,524288,203890 3 0076
+r? "
+? 495163,728178 2 0077
+at 815562,728178 2 0100
+@ "
+*A 786434,716526 2 0101
+A "
+*B 742744,716526 2 0102
+B "
+C 757307,716526,0,0,-29128 2 0103
+D 800998,716526,0,0,0,-29128 2 0104
+*E 713616,716526 2 0105
+E "
+F 684490,716526,0,0,0,-145637 2 0106
+G 822843,716526,0,0,-29128 2 0107
+*Y 786434,716526 2 0110
+H "
+*I 378653,716526 2 0111
+I "
+J 538853,716526,0,0,0,-29128 2 0112
+*K 815562,716526 2 0113
+K "
+L 655362,716526,0,0,0,58254 2 0114
+*M 961197,716526 2 0115
+M "
+*N 786434,716526 2 0116
+N "
+*O 815562,716526,0,0,-29128,-29128 2 0117
+O "
+*R 713616,716526,0,0,0,-145637 2 0120
+P "
+Q 815562,716526,203890,0,-29128 3 0121
+R 771870,716526 2 0122
+S 582544,716526 2 0123
+*T 757307,716526,0,0,0,-145637 2 0124
+T "
+U 786434,716526,0,0,-14563 2 0125
+V 786434,716526,0,14563,43691,-218454 2 0126
+W 1077706,716526,0,14563,43691,-131074 2 0127
+*X 786434,716526 2 0130
+X "
+Y 786434,716526,0,26214,29128,-206803 2 0131
+*Z 640798,716526 2 0132
+Z "
+lB 291272,786432,262144 3 0133
+[ "
+lq 524290,728178 2 0134
+rB 291272,786432,262144 3 0135
+] "
+ha 524290,728178 2 0136
+^ "
+a^ "
+a. 291272,700301 2 0137
+oq 291272,728178 2 0140
+` "
+a 524290,451470 0 0141
+b 582544,728178 2 0142
+c 466035,451470 0 0143
+d 582544,728178 2 0144
+e 466035,451470 0 0145
+f 320400,728178,0,81557 2 0146
+g 524290,451470,203890,14563 1 0147
+h 582544,728178 2 0150
+i 291272,700301 2 0151
+j 320400,700301,203890 3 0152
+k 553418,728178 2 0153
+l 291272,728178 2 0154
+m 873816,451470 0 0155
+n 582544,451470 0 0156
+o 524290,451470 0 0157
+p 582544,451470,203890 1 0160
+q 553416,451470,203890 1 0161
+r 410694,451470 0 0162
+s 413606,451470 0 0163
+t 407781,644958 2 0164
+u 582544,451470 0 0165
+v 553418,451470,0,14563 0 0166
+w 757307,451470,0,14563 0 0167
+x 553418,451470 0 0170
+y 553418,451470,203890,14563 1 0171
+z 466035,451470 0 0172
+en 524290,451470,0,29128 0 0173
+em 1048579,451470,0,29128 0 0174
+a" 524290,728178 2 0175
+~ 524290,700301 2 0176
+a~ "
+char168 524290,700301 2 0177
+ad "
diff --git a/gnu/usr.bin/groff/devdvi/S b/gnu/usr.bin/groff/devdvi/S
new file mode 100644
index 0000000..11b79ff
--- /dev/null
+++ b/gnu/usr.bin/groff/devdvi/S
@@ -0,0 +1,152 @@
+name S
+special
+internalname cmsy10
+slant 14.036243
+checksum 555887770
+designsize 10485760
+charset
+mi 815562,611670,87382 3 0000
+\- "
+md 291272,466035,-58253 2 0001
+char215 815562,611670,87382 3 0002
+mu "
+** 524290,487880,-36408 2 0003
+char247 815562,611670,87382 3 0004
+di "
+--- 524290,466035,-58253 2 0005
+char177 815562,611670,87382 3 0006
++- "
+-+ 815562,611670,87382 3 0007
+c+ 815562,611670,87382 3 0010
+--- 815562,611670,87382 3 0011
+c* 815562,611670,87382 3 0012
+--- 815562,611670,87382 3 0013
+--- 815562,611670,87382 3 0014
+ci 1048579,728178,203890 3 0015
+--- 524290,466035,-58253 2 0016
+bu 524290,466035,-58253 2 0017
+--- 815562,486275,-38013 2 0020
+== 815562,486275,-38013 2 0021
+ib 815562,666864,142576 3 0022
+ip 815562,666864,142576 3 0023
+<= 815562,666864,142576 3 0024
+>= 815562,666864,142576 3 0025
+--- 815562,666864,142576 3 0026
+--- 815562,666864,142576 3 0027
+ti 815562,384696,-139592 0 0030
+ap "
+~~ 815562,506590,-17698 2 0031
+sb 815562,565285,40997 3 0032
+sp 815562,565285,40997 3 0033
+<< 1048579,565285,40997 3 0034
+>> 1048579,565285,40997 3 0035
+--- 815562,565285,40997 3 0036
+--- 815562,565285,40997 3 0037
+<- 1048579,384696,-139592 0 0040
+-> 1048579,384696,-139592 0 0041
+ua 524290,728178,203888 3 0042
+da 524290,728178,203888 3 0043
+<> 1048579,384696,-139592 0 0044
+--- 1048579,728178,203888 3 0045
+--- 1048579,728178,203888 3 0046
+~= 815562,486275,-38013 2 0047
+lh 1048579,384696,-139592 0 0050
+lA "
+rh 1048579,384696,-139592 0 0051
+rA "
+uA 640798,728178,203888 3 0052
+dA 640798,728178,203888 3 0053
+hA 1048579,384696,-139592 0 0054
+--- 1048579,728178,203888 3 0055
+--- 1048579,728178,203888 3 0056
+pt 815562,451470 0 0057
+prime 288358,582544 2 0060
+if 1048579,451470 0 0061
+mo 699053,565285,40997 3 0062
+st 699053,565285,40997 3 0063
+--- 932070,728178,203890 3 0064
+--- 932070,728178,203890 3 0065
+slashnot 0,728178,203888 3 0066
+--- 0,384696,-139592 0 0067
+fa 582544,728178 2 0070
+te 582544,728178 2 0071
+char172 699053,451470 0 0072
+no "
+es 524290,786432,58254 3 0073
+Re 757307,728178 2 0074
+Im 757307,728178 2 0075
+--- 815562,728178 2 0076
+pp 815562,728178 2 0077
+Ah 640798,728178 2 0100
+A 837258,716526 2 0101
+B 688715,716526,0,31890 2 0102
+C 552106,716526,0,61170 2 0103
+D 808864,716526,0,29128 2 0104
+E 553419,716526,0,93786 2 0105
+F 753662,716526,0,104130 2 0106
+G 623762,716526,101946,62184 3 0107
+H 885541,716526,0,10123 2 0110
+I 570966,716526,0,77408 2 0111
+J 710704,716526,101946,193694 3 0112
+K 798963,716526,0,15147 2 0113
+L 723229,716526 2 0114
+M 1259235,716526 2 0115
+N 860347,716526,0,154518 2 0116
+O 834786,716526,0,29128 2 0117
+P 729347,716526,0,86216 2 0120
+Q 856341,716526,101946 3 0121
+R 888672,716526 2 0122
+S 634974,716526,0,78638 2 0123
+T 571101,716526,0,266514 2 0124
+U 656232,716526,0,104130 2 0125
+V 642549,716526,0,86216 2 0126
+W 1035766,716526,0,86216 2 0127
+X 747946,716526,0,153541 2 0130
+Y 700802,716526,101946,86216 3 0131
+Z 759930,716526,0,83302 2 0132
+cu 699053,582544 2 0133
+ca 699053,582544 2 0134
+--- 699053,582544 2 0135
+AN 699053,582544 2 0136
+OR 699053,582544 2 0137
+--- 640798,728178 2 0140
+--- 640798,728178 2 0141
+lf 466035,786432,262144 3 0142
+rf 466035,786432,262144 3 0143
+lc 466035,786432,262144 3 0144
+rc 466035,786432,262144 3 0145
+{ 524290,786432,262144 3 0146
+lC "
+} 524290,786432,262144 3 0147
+rC "
+la 407781,786432,262144 3 0150
+ra 407781,786432,262144 3 0151
+bar 291272,786432,262144 3 0152
+or "
+bv "
+| "
+ba "
+bardbl 524290,786432,262144 3 0153
+va 524290,786432,262144 3 0154
+vA 640798,786432,262144 3 0155
+rs 524290,786432,262144 3 0156
+\ "
+--- 291272,728178,203888 3 0157
+sr 873816,41942,1006634 1 0160
+--- 786434,716526 2 0161
+gr 873816,716526 2 0162
+--- 436909,728178,203890,116509 3 0163
+--- 699053,582544 2 0164
+--- 699053,582544 2 0165
+--- 815562,666864,142576 3 0166
+--- 815562,666864,142576 3 0167
+char167 466037,728178,203890 3 0170
+sc "
+dg 466035,728178,203890 3 0171
+dd 466035,728178,203890 3 0172
+char182 640798,728178,203890 3 0173
+ps "
+CL 815562,728178,135926 3 0174
+DI 815562,728178,135926 3 0175
+HE 815562,728178,135926 3 0176
+SP 815562,728178,135926 3 0177
diff --git a/gnu/usr.bin/groff/devdvi/SA b/gnu/usr.bin/groff/devdvi/SA
new file mode 100644
index 0000000..f2b258f
--- /dev/null
+++ b/gnu/usr.bin/groff/devdvi/SA
@@ -0,0 +1,143 @@
+name SA
+special
+internalname msam10
+checksum -1749815603
+designsize 10485760
+charset
+boxdot 815562,709446 2 0000
+boxplus 815562,709446 2 0001
+boxtimes 815562,709446 2 0002
+square 815562,709446 2 0003
+blacksquare 815562,709446 2 0004
+centerdot 291272,576570 2 0005
+lz 699053,728178,116509 3 0006
+lozenge "
+blacklozenge 699053,728178,116509 3 0007
+circlearrowright 815562,610248,85960 3 0010
+circlearrowleft 815562,610248,85960 3 0011
+rightleftharpoons 1048579,547770,14197 3 0012
+leftrightharpoons 1048579,547770,14197 3 0013
+boxminus 815562,709446 2 0014
+Vdash 757307,728178 2 0015
+Vvdash 932070,728178 2 0016
+vDash 640798,728178 2 0017
+twoheadrightarrow 1048579,547770,14197 3 0020
+twoheadleftarrow 1048579,547770,14197 3 0021
+leftleftarrows 1048579,709446,189584 3 0022
+rightrightarrows 1048579,709446,189584 3 0023
+upuparrows 873816,728178,203888 3 0024
+downdownarrows 873816,728178,203888 3 0025
+upharpoonright 436909,728178,203888 3 0026
+downharpoonright 436909,728178,203888 3 0027
+upharpoonleft 436909,728178,203888 3 0030
+downharpoonleft 436909,728178,203888 3 0031
+rightarrowtail 1165088,547770,14197 3 0032
+leftarrowtail 1165088,547770,14197 3 0033
+leftrightarrows 1048579,709446,189584 3 0034
+rightleftarrows 1048579,709446,189584 3 0035
+Lsh 524290,728178 2 0036
+Rsh 524290,728178 2 0037
+rightsquigarrow 1048579,396238,-139592 0 0040
+leftrightsquigarrow 1456360,396238,-139592 0 0041
+looparrowleft 1048579,576570 2 0042
+looparrowright 1048579,576570 2 0043
+circeq 815562,765021,240733 3 0044
+succsim 815562,765021,240733 3 0045
+gtrsim 815562,765021,240733 3 0046
+gtrapprox 815562,792549,268261 3 0047
+multimap 1165088,576570 2 0050
+3d 699053,728178 2 0051
+tf "
+therefore "
+because 699053,728178 2 0052
+doteqdot 815562,610248,85960 3 0053
+triangleq 815562,961197,85960 3 0054
+precsim 815562,765021,240733 3 0055
+lesssim 815562,765021,240733 3 0056
+lessapprox 815562,792549,268261 3 0057
+eqslantless 815562,667592,143304 3 0060
+eqslantgtr 815562,667592,143304 3 0061
+curlyeqprec 815562,667592,143304 3 0062
+curlyeqsucc 815562,667592,143304 3 0063
+preccurlyeq 815562,667592,143304 3 0064
+leqq 815562,792549,268261 3 0065
+leqslant 815562,667592,143304 3 0066
+lessgtr 815562,709446,189584 3 0067
+backprime 288358,576570 2 0070
+--- 524290,486557,-37731 2 0071
+risingdotseq 815562,610248,85960 3 0072
+fallingdotseq 815562,610248,85960 3 0073
+succcurlyeq 815562,667592,143304 3 0074
+geqq 815562,792549,268261 3 0075
+geqslant 815562,667592,143304 3 0076
+gtrless 815562,709446,189584 3 0077
+sqsubset 815562,576570,36882 3 0100
+sqsupset 815562,576570,36882 3 0101
+vartriangleright 815562,576570,36882 3 0102
+vartriangleleft 815562,576570,36882 3 0103
+trianglerighteq 815562,667592,143304 3 0104
+trianglelefteq 815562,667592,143304 3 0105
+bigstar 990323,728178,203888 3 0106
+between 524290,792549,268261 3 0107
+blacktriangledown 757307,576570 2 0110
+blacktriangleright 815562,576570,36882 3 0111
+blacktriangleleft 815562,576570,36882 3 0112
+--- 524290,486557,-37731 2 0113
+--- 524290,486557,-37731 2 0114
+vartriangle 757307,576570 2 0115
+blacktriangle 757307,576570 2 0116
+triangledown 757307,576570 2 0117
+eqcirc 815562,728178 2 0120
+lesseqgtr 815562,928714,404426 3 0121
+gtreqless 815562,928714,404426 3 0122
+lesseqqgtr 815562,1030294,506006 3 0123
+gtreqqless 815562,1030294,506006 3 0124
+char165 786434,709446,0,26214 2 0125
+Ye "
+yen "
+Rrightarrow 1048579,667592,143304 3 0126
+Lleftarrow 1048579,667592,143304 3 0127
+OK 873816,728178 2 0130
+checkmark "
+veebar 640798,728178,203888 3 0131
+barwedge 640798,728178,203888 3 0132
+doublebarwedge 640798,792549,203888 3 0133
+/_ 757307,728178 2 0134
+angle "
+measuredangle 757307,728178 2 0135
+sphericalangle 757307,547770,36882 3 0136
+varpropto 815562,728178 2 0137
+smallsmile 815562,728178,203888 3 0140
+smallfrown 815562,728178,203888 3 0141
+Subset 815562,576570,36882 3 0142
+Supset 815562,576570,36882 3 0143
+Cup 699053,576570 2 0144
+Cap 699053,576570 2 0145
+curlywedge 797355,576570 2 0146
+curlyvee 797355,576570 2 0147
+leftthreetimes 815562,728178 2 0150
+rightthreetimes 815562,728178 2 0151
+subseteqq 815562,792549,268261 3 0152
+supseteqq 815562,792549,268261 3 0153
+bumpeq 815562,576570,63568 3 0154
+Bumpeq 815562,576570,63568 3 0155
+lll 1398106,576570,36882 3 0156
+ggg 1398106,576570,36882 3 0157
+ulcorner 524290,728178 2 0160
+urcorner 524290,728178 2 0161
+rg 992648,709446,159430 3 0162
+char174 "
+circledR "
+circledS 946045,709446,159430 3 0163
+pitchfork 699053,728178 2 0164
+dotplus 815562,728178,85960 3 0165
+backsim 815562,396238,-139592 0 0166
+backsimeq 815562,486557,-37731 2 0167
+llcorner 524290,396238 0 0170
+lrcorner 524290,396238 0 0171
+maltese 873816,728178 2 0172
+complement 524290,865080 2 0173
+intercal 582544,451470,203888 1 0174
+circledcirc 815562,610248,85960 3 0175
+circledast 815562,610248,85960 3 0176
+circleddash 815562,610248,85960 3 0177
diff --git a/gnu/usr.bin/groff/devdvi/SB b/gnu/usr.bin/groff/devdvi/SB
new file mode 100644
index 0000000..a4be59d
--- /dev/null
+++ b/gnu/usr.bin/groff/devdvi/SB
@@ -0,0 +1,132 @@
+name SB
+special
+internalname msbm10
+spacewidth 314576
+slant 87.709390
+checksum -2001332536
+designsize 10485760
+charset
+lvertneqq 815562,794042,263635 3 0000
+gvertneqq 815562,794042,263635 3 0001
+nleq 815562,832390,317448 3 0002
+ngeq 815562,832390,317448 3 0003
+nless 815562,740048,215760 3 0004
+ngtr 815562,740048,215760 3 0005
+nprec 815562,740048,215760 3 0006
+nsucc 815562,740048,215760 3 0007
+lneqq 815562,794042,263635 3 0010
+gneqq 815562,794042,263635 3 0011
+nleqslant 815562,832390,317448 3 0012
+ngeqslant 815562,832390,317448 3 0013
+lneq 815562,666864,142576 3 0014
+gneq 815562,666864,142576 3 0015
+npreceq 815562,832390,317448 3 0016
+nsucceq 815562,832390,317448 3 0017
+precnsim 815562,777110,243501 3 0020
+succnsim 815562,777110,243501 3 0021
+lnsim 815562,777110,243501 3 0022
+gnsim 815562,777110,243501 3 0023
+nleqq 815562,964179,439891 3 0024
+ngeqq 815562,964179,439891 3 0025
+precneqq 815562,794042,263635 3 0026
+succneqq 815562,794042,263635 3 0027
+precnapprox 815562,794042,274379 3 0030
+succnapprox 815562,794042,274379 3 0031
+lnapprox 815562,794042,274379 3 0032
+gnapprox 815562,794042,274379 3 0033
+nsim 815562,384696,-139592 0 0034
+ncong 815562,832390,317448 3 0035
+diagup 932070,722352,203888 3 0036
+diagdown 932070,777110,203888 3 0037
+varsubsetneq 815562,666864,142576 3 0040
+varsupsetneq 815562,666864,142576 3 0041
+nsubseteqq 815562,794042,263635 3 0042
+nsupseteqq 815562,794042,263635 3 0043
+subsetneqq 815562,832390,298650 3 0044
+supsetneqq 815562,832390,298650 3 0045
+varsubsetneqq 815562,794042,263635 3 0046
+varsupsetneqq 815562,794042,263635 3 0047
+subsetneq 815562,666864,142576 3 0050
+supsetneq 815562,666864,142576 3 0051
+nsubseteq 815562,832390,317448 3 0052
+nsupseteq 815562,832390,317448 3 0053
+nparallel 524290,777110,263635 3 0054
+nmid 291272,777110,263635 3 0055
+nshortmid 233018,609920,85632 3 0056
+nshortparallel 407781,609920,85632 3 0057
+nvdash 640798,722352 2 0060
+nVdash 757307,722352 2 0061
+nvDash 640798,722352 2 0062
+nVDash 757307,722352 2 0063
+ntrianglerighteq 815562,832390,317448 3 0064
+ntrianglelefteq 815562,832390,317448 3 0065
+ntriangleleft 815562,740048,215760 3 0066
+ntriangleright 815562,740048,215760 3 0067
+nleftarrow 1048579,384696,-139592 0 0070
+nrightarrow 1048579,384696,-139592 0 0071
+nLeftarrow 1048579,384696,-139592 0 0072
+nRightarrow 1048579,384696,-139592 0 0073
+nLeftrightarrow 1048579,384696,-139592 0 0074
+nleftrightarrow 1048579,384696,-139592 0 0075
+divideontimes 815562,609920,85632 3 0076
+varnothing 815562,609920,85632 3 0077
+nexists 582544,722352 2 0100
+BbbA 757307,722352 2 0101
+BbbB 699053,722352 2 0102
+BbbC 757307,722352 2 0103
+BbbD 757307,722352 2 0104
+BbbE 699053,722352 2 0105
+BbbF 640798,722352 2 0106
+BbbG 815562,722352 2 0107
+BbbH 815562,722352 2 0110
+BbbI 407781,722352 2 0111
+BbbJ 524290,722352,174763 3 0112
+BbbK 815562,722352 2 0113
+BbbL 699053,722352 2 0114
+BbbM 990325,722352 2 0115
+BbbN 757307,722352 2 0116
+BbbO 815562,722352,174763 3 0117
+BbbP 640798,722352 2 0120
+BbbQ 815562,722352,174763 3 0121
+BbbR 757307,722352 2 0122
+BbbS 582544,722352 2 0123
+BbbT 699053,722352 2 0124
+BbbU 757307,722352 2 0125
+BbbV 757307,722352 2 0126
+BbbW 1048579,722352 2 0127
+BbbX 757307,722352 2 0130
+BbbY 757307,722352 2 0131
+BbbZ 699053,722352 2 0132
+--- 1980650,865080 2 0133
+--- 2446685,865080 2 0134
+--- 1980650,865080 2 0135
+--- 2446685,943717 2 0136
+Finv 582544,722352 2 0140
+Game 669925,722352 2 0141
+mho 757307,722352 2 0146
+eth 582544,722352 2 0147
+eqsim 815562,486275,-38013 2 0150
+beth 699053,722352 2 0151
+gimel 466035,722352 2 0152
+daleth 699053,722352 2 0153
+lessdot 815562,565285,40997 3 0154
+gtrdot 815562,565285,40997 3 0155
+ltimes 815562,609920,85632 3 0156
+rtimes 815562,609920,85632 3 0157
+shortmid 233018,609920,85632 3 0160
+shortparallel 407781,609920,85632 3 0161
+smallsetminus 815562,609920,85632 3 0162
+thicksim 815562,384696,-139592 0 0163
+thickapprox 815562,506590,-17698 2 0164
+approxeq 815562,609920,85632 3 0165
+succapprox 815562,794042,274379 3 0166
+precapprox 815562,794042,274379 3 0167
+curvearrowleft 1048579,451470 0 0170
+curvearrowright 1048579,451470 0 0171
+digamma 815562,609920,85632 3 0172
+varkappa 699053,451470,0,42235 0 0173
+Bbbk 582544,722352 2 0174
+hslash 566525,722352 2 0175
+-h 566525,722352 2 0176
+hbar "
+backepsilon 450016,451470 0 0177
diff --git a/gnu/usr.bin/groff/devdvi/generate/CompileFonts b/gnu/usr.bin/groff/devdvi/generate/CompileFonts
new file mode 100755
index 0000000..8859f8e
--- /dev/null
+++ b/gnu/usr.bin/groff/devdvi/generate/CompileFonts
@@ -0,0 +1,15 @@
+#! /bin/sh
+# Compile fonts in the sizes needed by groff.
+sizes="5 6 7 8 9 10 11 12 14 16 18 20 22 24 28 36"
+fonts="cmr10 cmti10 cmbx10 cmbxti10 cmtt10 cmex10 cmmi10 cmsy10 cmss10 cmssbx10 cmssi10"
+mode=cx
+dpi=300
+
+for f in $fonts; do
+ for s in $sizes; do
+ virmf "&cm \\mode=$mode; mag=$s/10; batchmode; input $f" >/dev/null
+ mag=`expr $s \* $dpi / 10`
+ gftopk $f.${mag}gf >/dev/null
+ rm $f.${mag}gf
+ done
+done
diff --git a/gnu/usr.bin/groff/devdvi/generate/Makefile b/gnu/usr.bin/groff/devdvi/generate/Makefile
new file mode 100644
index 0000000..f133ab6
--- /dev/null
+++ b/gnu/usr.bin/groff/devdvi/generate/Makefile
@@ -0,0 +1,93 @@
+#Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
+# Written by James Clark (jjc@jclark.com)
+#
+#This file is part of groff.
+#
+#groff is free software; you can redistribute it and/or modify it under
+#the terms of the GNU General Public License as published by the Free
+#Software Foundation; either version 2, or (at your option) any later
+#version.
+#
+#groff is distributed in the hope that it will be useful, but WITHOUT ANY
+#WARRANTY; without even the implied warranty of MERCHANTABILITY or
+#FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+#for more details.
+#
+#You should have received a copy of the GNU General Public License along
+#with groff; see the file COPYING. If not, write to the Free Software
+#Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+# This is set up so you can do:
+# make -f generate/Makefile
+# in the parent directory of the directory containing this file.
+
+srcdir=.
+tfmdir=/usr/local/lib/groff-tfm
+gfdir=/usr/local/lib/groff-gf
+
+TFMTODIT=tfmtodit
+FONTS=R I B BI CW MI S EX H HI HB SA SB
+SPECIALFLAG=-s
+
+all: $(FONTS)
+
+# R is special because it contains \(pl \(eq
+
+R: $(srcdir)/texr.map
+ $(TFMTODIT) $(SPECIALFLAG) -g $(gfdir)/cmr10.300gf \
+ $(tfmdir)/cmr10.tfm $(srcdir)/texr.map $@
+
+# I is special because it contains \(Po
+
+I: $(srcdir)/texi.map
+ $(TFMTODIT) $(SPECIALFLAG) -g $(gfdir)/cmti10.300gf \
+ $(tfmdir)/cmti10.tfm $(srcdir)/texi.map $@
+
+B: $(srcdir)/texb.map
+ $(TFMTODIT) -g $(gfdir)/cmbx10.300gf \
+ $(tfmdir)/cmbx10.tfm $(srcdir)/texb.map $@
+
+BI: $(srcdir)/texi.map
+ $(TFMTODIT) -g $(gfdir)/cmbxti10.300gf \
+ $(tfmdir)/cmbxti10.tfm $(srcdir)/texi.map $@
+
+# CW is special because it contains "
+
+CW: $(srcdir)/textt.map
+ $(TFMTODIT) $(SPECIALFLAG) $(tfmdir)/cmtt10.tfm $(srcdir)/textt.map $@
+
+MI: $(srcdir)/texmi.map
+ $(TFMTODIT) $(SPECIALFLAG) -k 0177 $(tfmdir)/cmmi10.tfm $(srcdir)/texmi.map $@
+
+S: $(srcdir)/texsy.map
+ $(TFMTODIT) $(SPECIALFLAG) -k 060 $(tfmdir)/cmsy10.tfm $(srcdir)/texsy.map $@
+
+EX: $(srcdir)/texex.map
+ $(TFMTODIT) $(SPECIALFLAG) $(tfmdir)/cmex10.tfm $(srcdir)/texex.map $@
+
+H: $(srcdir)/texr.map
+ $(TFMTODIT) -g $(gfdir)/cmss10.300gf $(tfmdir)/cmss10.tfm $(srcdir)/texb.map $@
+
+HB: $(srcdir)/texr.map
+ $(TFMTODIT) -g $(gfdir)/cmssbx10.300gf \
+ $(tfmdir)/cmssbx10.tfm $(srcdir)/texb.map $@
+
+HI: $(srcdir)/texr.map
+ $(TFMTODIT) -g $(gfdir)/cmssi10.300gf \
+ $(tfmdir)/cmssi10.tfm $(srcdir)/texb.map $@
+
+SA: $(srcdir)/msam.map
+ $(TFMTODIT) $(SPECIALFLAG) $(tfmdir)/msam10.tfm $(srcdir)/msam.map $@
+
+SB: $(srcdir)/msbm.map
+ $(TFMTODIT) $(SPECIALFLAG) $(tfmdir)/msbm10.tfm $(srcdir)/msbm.map $@
+
+clean:
+
+realclean:
+ -rm -f $(FONTS)
+
+extraclean: realclean
+ -rm -f core *~ \#*
+
+.PHONY: clean realclean extraclean all
diff --git a/gnu/usr.bin/groff/devdvi/generate/cork.map b/gnu/usr.bin/groff/devdvi/generate/cork.map
new file mode 100644
index 0000000..52cac9c
--- /dev/null
+++ b/gnu/usr.bin/groff/devdvi/generate/cork.map
@@ -0,0 +1,206 @@
+# Map for DC/EC fonts with Cork encoding.
+# Contributed by Andreas Schwab <schwab@issan.informatik.uni-dortmund.de>
+0 ga
+1 aa char180
+2 a^
+3 a~
+4 ad char168
+5 a"
+6 ao
+7 ah
+8 ab
+9 a- char175
+10 a.
+11 ac char184
+12 ho
+13 bq
+14 fo
+15 fc
+16 lq
+17 rq
+18 Bq
+19 Fo char171
+20 Fc char187
+21 en
+22 em
+25 .i
+26 .j
+27 ff
+28 fi
+29 fl
+30 Fi
+31 Fl
+33 !
+34 "
+35 # sh
+36 $ Do
+37 %
+38 &
+39 ' aq
+40 (
+41 )
+42 *
+43 + pl
+44 ,
+45 -
+46 .
+47 / sl
+48 0
+49 1
+50 2
+51 3
+52 4
+53 5
+54 6
+55 7
+56 8
+57 9
+58 :
+59 ;
+60 <
+61 = eq
+62 >
+63 ?
+64 @ at
+65 A
+66 B
+67 C
+68 D
+69 E
+70 F
+71 G
+72 H
+73 I
+74 J
+75 K
+76 L
+77 M
+78 N
+79 O
+80 P
+81 Q
+82 R
+83 S
+84 T
+85 U
+86 V
+87 W
+88 X
+89 Y
+90 Z
+91 [ lB
+92 \ rs
+93 ] rB
+94 ^ ha
+95 _
+96 ` oq
+97 a
+98 b
+99 c
+100 d
+101 e
+102 f
+103 g
+104 h
+105 i
+106 j
+107 k
+108 l
+109 m
+110 n
+111 o
+112 p
+113 q
+114 r
+115 s
+116 t
+117 u
+118 v
+119 w
+120 x
+121 y
+122 z
+123 { lC
+124 | or bv ba
+125 } rC
+126 ~
+127 hy char173
+130 'C
+138 /L
+146 vS
+152 :Y
+154 vZ
+156 IJ
+159 sc char167
+162 'c
+170 (l
+178 vs
+184 :y char255
+186 vz
+188 ij
+189 r! char161
+190 r? char191
+191 Po char163
+192 `A char192
+193 'A char193
+194 ^A char194
+195 ~A char195
+196 :A char196
+197 oA char197
+198 AE char198
+199 ,C char199
+200 `E char200
+201 'E char201
+202 ^E char202
+203 :E char203
+204 `I char204
+205 'I char205
+206 ^I char206
+207 :I char207
+208 -D char208
+209 ~N char209
+210 `O char210
+211 'O char211
+212 ^O char212
+213 ~O char213
+214 :O char214
+215 OE
+216 /O char216
+217 `U char217
+218 'U char218
+219 ^U char219
+220 :U char220
+221 char221
+222 TP char222
+224 `a char224
+225 'a char225
+226 ^a char226
+227 ~a char227
+228 :a char228
+229 oa char229
+230 ae char230
+231 ,c char231
+232 `e char232
+233 'e char233
+234 ^e char234
+235 :e char235
+236 `i char236
+237 'i char237
+238 ^i char238
+239 :i char239
+240 Sd char240
+241 ~n char241
+242 `o char242
+243 'o char243
+244 ^o char244
+245 ~o char245
+246 :o char246
+247 oe
+248 /o char248
+249 `u char249
+250 'u char250
+251 ^u char251
+252 :u char252
+253 char253
+254 Tp char254
+255 ss char223
diff --git a/gnu/usr.bin/groff/devdvi/generate/msam.map b/gnu/usr.bin/groff/devdvi/generate/msam.map
new file mode 100644
index 0000000..90006c9
--- /dev/null
+++ b/gnu/usr.bin/groff/devdvi/generate/msam.map
@@ -0,0 +1,127 @@
+# Map for the AMSFonts 2.0 msam font using TeX names.
+# Contributed by Zdzislaw Meglicki (Zdzislaw.Meglicki@arp.anu.edu.au).
+0 boxdot
+1 boxplus
+2 boxtimes
+3 square
+4 blacksquare
+5 centerdot
+6 lozenge lz
+7 blacklozenge
+8 circlearrowright
+9 circlearrowleft
+10 rightleftharpoons
+11 leftrightharpoons
+12 boxminus
+13 Vdash
+14 Vvdash
+15 vDash
+16 twoheadrightarrow
+17 twoheadleftarrow
+18 leftleftarrows
+19 rightrightarrows
+20 upuparrows
+21 downdownarrows
+22 upharpoonright
+23 downharpoonright
+24 upharpoonleft
+25 downharpoonleft
+26 rightarrowtail
+27 leftarrowtail
+28 leftrightarrows
+29 rightleftarrows
+30 Lsh
+31 Rsh
+32 rightsquigarrow
+33 leftrightsquigarrow
+34 looparrowleft
+35 looparrowright
+36 circeq
+37 succsim
+38 gtrsim
+39 gtrapprox
+40 multimap
+41 therefore tf 3d
+42 because
+43 doteqdot
+44 triangleq
+45 precsim
+46 lesssim
+47 lessapprox
+48 eqslantless
+49 eqslantgtr
+50 curlyeqprec
+51 curlyeqsucc
+52 preccurlyeq
+53 leqq
+54 leqslant
+55 lessgtr
+56 backprime
+58 risingdotseq
+59 fallingdotseq
+60 succcurlyeq
+61 geqq
+62 geqslant
+63 gtrless
+64 sqsubset
+65 sqsupset
+66 vartriangleright
+67 vartriangleleft
+68 trianglerighteq
+69 trianglelefteq
+70 bigstar
+71 between
+72 blacktriangledown
+73 blacktriangleright
+74 blacktriangleleft
+77 vartriangle
+78 blacktriangle
+79 triangledown
+80 eqcirc
+81 lesseqgtr
+82 gtreqless
+83 lesseqqgtr
+84 gtreqqless
+85 yen Ye char165
+86 Rrightarrow
+87 Lleftarrow
+88 checkmark OK
+89 veebar
+90 barwedge
+91 doublebarwedge
+92 angle /_
+93 measuredangle
+94 sphericalangle
+95 varpropto
+96 smallsmile
+97 smallfrown
+98 Subset
+99 Supset
+100 Cup
+101 Cap
+102 curlywedge
+103 curlyvee
+104 leftthreetimes
+105 rightthreetimes
+106 subseteqq
+107 supseteqq
+108 bumpeq
+109 Bumpeq
+110 lll
+111 ggg
+112 ulcorner
+113 urcorner
+114 circledR char174 rg
+115 circledS
+116 pitchfork
+117 dotplus
+118 backsim
+119 backsimeq
+120 llcorner
+121 lrcorner
+122 maltese
+123 complement
+124 intercal
+125 circledcirc
+126 circledast
+127 circleddash
diff --git a/gnu/usr.bin/groff/devdvi/generate/msbm.map b/gnu/usr.bin/groff/devdvi/generate/msbm.map
new file mode 100644
index 0000000..07ee095
--- /dev/null
+++ b/gnu/usr.bin/groff/devdvi/generate/msbm.map
@@ -0,0 +1,121 @@
+# Map for the AMSFonts 2.0 msbm font using TeX names.
+# Contributed by Zdzislaw Meglicki (Zdzislaw.Meglicki@arp.anu.edu.au).
+0 lvertneqq
+1 gvertneqq
+2 nleq
+3 ngeq
+4 nless
+5 ngtr
+6 nprec
+7 nsucc
+8 lneqq
+9 gneqq
+10 nleqslant
+11 ngeqslant
+12 lneq
+13 gneq
+14 npreceq
+15 nsucceq
+16 precnsim
+17 succnsim
+18 lnsim
+19 gnsim
+20 nleqq
+21 ngeqq
+22 precneqq
+23 succneqq
+24 precnapprox
+25 succnapprox
+26 lnapprox
+27 gnapprox
+28 nsim
+29 ncong
+30 diagup
+31 diagdown
+32 varsubsetneq
+33 varsupsetneq
+34 nsubseteqq
+35 nsupseteqq
+36 subsetneqq
+37 supsetneqq
+38 varsubsetneqq
+39 varsupsetneqq
+40 subsetneq
+41 supsetneq
+42 nsubseteq
+43 nsupseteq
+44 nparallel
+45 nmid
+46 nshortmid
+47 nshortparallel
+48 nvdash
+49 nVdash
+50 nvDash
+51 nVDash
+52 ntrianglerighteq
+53 ntrianglelefteq
+54 ntriangleleft
+55 ntriangleright
+56 nleftarrow
+57 nrightarrow
+58 nLeftarrow
+59 nRightarrow
+60 nLeftrightarrow
+61 nleftrightarrow
+62 divideontimes
+63 varnothing
+64 nexists
+65 BbbA
+66 BbbB
+67 BbbC
+68 BbbD
+69 BbbE
+70 BbbF
+71 BbbG
+72 BbbH
+73 BbbI
+74 BbbJ
+75 BbbK
+76 BbbL
+77 BbbM
+78 BbbN
+79 BbbO
+80 BbbP
+81 BbbQ
+82 BbbR
+83 BbbS
+84 BbbT
+85 BbbU
+86 BbbV
+87 BbbW
+88 BbbX
+89 BbbY
+90 BbbZ
+96 Finv
+97 Game
+102 mho
+103 eth
+104 eqsim
+105 beth
+106 gimel
+107 daleth
+108 lessdot
+109 gtrdot
+110 ltimes
+111 rtimes
+112 shortmid
+113 shortparallel
+114 smallsetminus
+115 thicksim
+116 thickapprox
+117 approxeq
+118 succapprox
+119 precapprox
+120 curvearrowleft
+121 curvearrowright
+122 digamma
+123 varkappa
+124 Bbbk
+125 hslash
+126 hbar -h
+127 backepsilon
diff --git a/gnu/usr.bin/groff/devdvi/generate/texb.map b/gnu/usr.bin/groff/devdvi/generate/texb.map
new file mode 100644
index 0000000..6700833
--- /dev/null
+++ b/gnu/usr.bin/groff/devdvi/generate/texb.map
@@ -0,0 +1,127 @@
+0 *G
+1 *D
+2 *H
+3 *L
+4 *C
+5 *P
+6 *S
+7 *U
+8 *F
+9 *Q
+10 *W
+11 ff
+12 fi
+13 fl
+14 Fi
+15 Fl
+16 .i
+17 .j
+18 ga
+19 aa char180
+20 ah
+21 ab
+22 a- char175
+23 ao
+24 ac char184
+25 ss char223
+26 ae char230
+27 oe
+28 /o char248
+29 AE char198
+30 OE
+31 /O char216
+33 !
+34 rq
+35 # sh
+36 $ Do
+37 %
+38 &
+39 '
+40 (
+41 )
+42 *
+43 +
+44 ,
+45 - hy char173
+46 .
+47 / sl
+48 0
+49 1
+50 2
+51 3
+52 4
+53 5
+54 6
+55 7
+56 8
+57 9
+58 :
+59 ;
+60 r! char161
+61 =
+62 r? char191
+63 ?
+64 @ at
+65 A
+66 B
+67 C
+68 D
+69 E
+70 F
+71 G
+72 H
+73 I
+74 J
+75 K
+76 L
+77 M
+78 N
+79 O
+80 P
+81 Q
+82 R
+83 S
+84 T
+85 U
+86 V
+87 W
+88 X
+89 Y
+90 Z
+91 [ lB
+92 lq
+93 ] rB
+94 a^ ^ ha
+95 a.
+96 ` oq
+97 a
+98 b
+99 c
+100 d
+101 e
+102 f
+103 g
+104 h
+105 i
+106 j
+107 k
+108 l
+109 m
+110 n
+111 o
+112 p
+113 q
+114 r
+115 s
+116 t
+117 u
+118 v
+119 w
+120 x
+121 y
+122 z
+123 en
+124 em
+125 a"
+126 a~ ~
+127 ad char168
diff --git a/gnu/usr.bin/groff/devdvi/generate/texex.map b/gnu/usr.bin/groff/devdvi/generate/texex.map
new file mode 100644
index 0000000..a5b2690
--- /dev/null
+++ b/gnu/usr.bin/groff/devdvi/generate/texex.map
@@ -0,0 +1,100 @@
+0 parenleft0
+1 parenright0
+2 bracketleft0
+3 bracketright0
+4 floorleft0
+5 floorright0
+6 ceilingleft0
+7 ceilingright0
+8 braceleft0
+9 braceright0
+10 angleleft0
+11 angleright0
+12 barex
+13 bardblex
+14 slash0
+15 backslash0
+16 parenleft1
+17 parenright1
+18 parenleft2
+19 parenright2
+20 bracketleft2
+21 bracketright2
+22 floorleft2
+23 floorright2
+24 ceilingleft2
+25 ceilingright2
+26 braceleft2
+27 braceright2
+28 angleleft2
+29 angleright2
+30 slash2
+31 backslash2
+32 parenleft3
+33 parenright3
+34 bracketleft3
+35 bracketright3
+36 floorleft3
+37 floorright3
+38 ceilingleft3
+39 ceilingright3
+40 braceleft3
+41 braceright3
+42 angleleft3
+43 angleright3
+44 slash3
+45 backslash3
+46 slash1
+47 backslash1
+48 parenlefttp
+49 parenrighttp
+50 bracketlefttp
+51 bracketrighttp
+52 bracketleftbt
+53 bracketrightbt
+54 bracketleftex
+55 bracketrightex
+56 bracelefttp lt
+57 bracerighttp rt
+58 braceleftbt lb
+59 bracerightbt rb
+60 braceleftmid lk
+61 bracerightmid rk
+62 braceex bracerightex braceleftex
+63 arrowvertex
+64 parenleftbt
+65 parenrightbt
+66 parenleftex
+67 parenrightex
+68 angleleft1
+69 angleright1
+73 ois ointegral
+75 bigcircledot
+77 bigcircleplus
+79 bigcirclemultiply
+88 sum
+89 product
+90 is integral
+91 bigunion
+92 bigintersection
+93 bigunionplus
+94 biglogicaland
+95 biglogicalor
+97 coproduct
+104 bracketleft1
+105 bracketright1
+106 floorleft1
+107 floorright1
+108 ceilingleft1
+109 ceilingright1
+110 braceleft1
+111 braceright1
+112 sr0
+113 sr1
+114 sr2
+115 sr3
+119 arrowvertdblex
+120 arrowverttp
+121 arrowvertbt
+126 arrowvertdbltp
+127 arrowvertdblbt
diff --git a/gnu/usr.bin/groff/devdvi/generate/texi.map b/gnu/usr.bin/groff/devdvi/generate/texi.map
new file mode 100644
index 0000000..835c642
--- /dev/null
+++ b/gnu/usr.bin/groff/devdvi/generate/texi.map
@@ -0,0 +1,127 @@
+0 *G
+1 *D
+2 *H
+3 *L
+4 *C
+5 *P
+6 *S
+7 *U
+8 *F
+9 *Q
+10 *W
+11 ff
+12 fi
+13 fl
+14 Fi
+15 Fl
+16 .i
+17 .j
+18 ga
+19 aa char180
+20 ah
+21 ab
+22 a- char175
+23 ao
+24 ac char184
+25 ss char223
+26 ae char230
+27 oe
+28 /o char248
+29 AE char198
+30 OE
+31 /O char216
+33 !
+34 rq
+35 # sh
+36 Po char163
+37 %
+38 &
+39 '
+40 (
+41 )
+42 *
+43 +
+44 ,
+45 - hy char173
+46 .
+47 / sl
+48 0
+49 1
+50 2
+51 3
+52 4
+53 5
+54 6
+55 7
+56 8
+57 9
+58 :
+59 ;
+60 r! char161
+61 =
+62 r? char191
+63 ?
+64 @ at
+65 A
+66 B
+67 C
+68 D
+69 E
+70 F
+71 G
+72 H
+73 I
+74 J
+75 K
+76 L
+77 M
+78 N
+79 O
+80 P
+81 Q
+82 R
+83 S
+84 T
+85 U
+86 V
+87 W
+88 X
+89 Y
+90 Z
+91 [ lB
+92 lq
+93 ] rB
+94 a^ ^ ha
+95 a.
+96 ` oq
+97 a
+98 b
+99 c
+100 d
+101 e
+102 f Fn
+103 g
+104 h
+105 i
+106 j
+107 k
+108 l
+109 m
+110 n
+111 o
+112 p
+113 q
+114 r
+115 s
+116 t
+117 u
+118 v
+119 w
+120 x
+121 y
+122 z
+123 en
+124 em
+125 a"
+126 a~ ~
+127 ad char168
diff --git a/gnu/usr.bin/groff/devdvi/generate/texmi.map b/gnu/usr.bin/groff/devdvi/generate/texmi.map
new file mode 100644
index 0000000..6d01dc4
--- /dev/null
+++ b/gnu/usr.bin/groff/devdvi/generate/texmi.map
@@ -0,0 +1,32 @@
+11 *a
+12 *b
+13 *g
+14 *d
+15 *e
+16 *z
+17 *y
+18 *h
+19 *i
+20 *k
+21 *l
+22 *m char181
+23 *n
+24 *c
+25 *p
+26 *r
+27 *s
+28 *t
+29 *u
+30 *f
+31 *x
+32 *q
+33 *w
+35 +h
+36 +p
+38 ts
+39 +f
+60 <
+62 >
+64 pd
+111 *o
+125 wp
diff --git a/gnu/usr.bin/groff/devdvi/generate/texr.map b/gnu/usr.bin/groff/devdvi/generate/texr.map
new file mode 100644
index 0000000..bebf67b
--- /dev/null
+++ b/gnu/usr.bin/groff/devdvi/generate/texr.map
@@ -0,0 +1,127 @@
+0 *G
+1 *D
+2 *H
+3 *L
+4 *C
+5 *P
+6 *S
+7 *U
+8 *F
+9 *Q
+10 *W
+11 ff
+12 fi
+13 fl
+14 Fi
+15 Fl
+16 .i
+17 .j
+18 ga
+19 aa char180
+20 ah
+21 ab
+22 a- char175
+23 ao
+24 ac char184
+25 ss char223
+26 ae char230
+27 oe
+28 /o char248
+29 AE char198
+30 OE
+31 /O char216
+33 !
+34 rq
+35 # sh
+36 $ Do
+37 %
+38 &
+39 '
+40 (
+41 )
+42 *
+43 + pl
+44 ,
+45 - hy char173
+46 .
+47 / sl
+48 0
+49 1
+50 2
+51 3
+52 4
+53 5
+54 6
+55 7
+56 8
+57 9
+58 :
+59 ;
+60 r! char161
+61 = eq
+62 r? char191
+63 ?
+64 @ at
+65 A *A
+66 B *B
+67 C
+68 D
+69 E *E
+70 F
+71 G
+72 H *Y
+73 I *I
+74 J
+75 K *K
+76 L
+77 M *M
+78 N *N
+79 O *O
+80 P *R
+81 Q
+82 R
+83 S
+84 T *T
+85 U
+86 V
+87 W
+88 X *X
+89 Y
+90 Z *Z
+91 [ lB
+92 lq
+93 ] rB
+94 a^ ^ ha
+95 a.
+96 ` oq
+97 a
+98 b
+99 c
+100 d
+101 e
+102 f
+103 g
+104 h
+105 i
+106 j
+107 k
+108 l
+109 m
+110 n
+111 o
+112 p
+113 q
+114 r
+115 s
+116 t
+117 u
+118 v
+119 w
+120 x
+121 y
+122 z
+123 en
+124 em
+125 a"
+126 a~ ~
+127 ad char168
diff --git a/gnu/usr.bin/groff/devdvi/generate/texsy.map b/gnu/usr.bin/groff/devdvi/generate/texsy.map
new file mode 100644
index 0000000..2c970bc
--- /dev/null
+++ b/gnu/usr.bin/groff/devdvi/generate/texsy.map
@@ -0,0 +1,100 @@
+0 \- mi
+1 md
+2 mu char215
+3 **
+4 di char247
+6 +- char177
+7 -+
+8 c+
+10 c*
+13 ci
+15 bu
+17 ==
+18 ib
+19 ip
+20 <=
+21 >=
+24 ap ti
+25 ~~
+26 sb
+27 sp
+28 <<
+29 >>
+32 <-
+33 ->
+34 ua
+35 da
+36 <>
+39 ~=
+40 lA lh
+41 rA rh
+42 uA
+43 dA
+44 hA
+47 pt
+48 prime
+49 if
+50 mo
+51 st
+54 slashnot
+56 fa
+57 te
+58 no char172
+59 es
+60 Re
+61 Im
+63 pp
+64 Ah
+65 A
+66 B
+67 C
+68 D
+69 E
+70 F
+71 G
+72 H
+73 I
+74 J
+75 K
+76 L
+77 M
+78 N
+79 O
+80 P
+81 Q
+82 R
+83 S
+84 T
+85 U
+86 V
+87 W
+88 X
+89 Y
+90 Z
+91 cu
+92 ca
+94 AN
+95 OR
+98 lf
+99 rf
+100 lc
+101 rc
+102 lC {
+103 rC }
+104 la
+105 ra
+106 ba | bv or bar
+107 bardbl
+108 va
+109 vA
+110 \ rs
+112 sr
+114 gr
+120 sc char167
+121 dg
+122 dd
+123 ps char182
+124 CL
+125 DI
+126 HE
+127 SP
diff --git a/gnu/usr.bin/groff/devdvi/generate/textt.map b/gnu/usr.bin/groff/devdvi/generate/textt.map
new file mode 100644
index 0000000..1461d0a
--- /dev/null
+++ b/gnu/usr.bin/groff/devdvi/generate/textt.map
@@ -0,0 +1,126 @@
+0 *G
+1 *D
+2 *H
+3 *L
+4 *C
+5 *P
+6 *S
+7 *U
+8 *F
+9 *Q
+10 *W
+11 ff
+12 fi
+13 fl
+14 Fi
+15 Fl
+16 .i
+17 .j
+18 ga
+19 aa char180
+20 ah
+21 ab
+22 a- char175
+23 ao
+24 ac char184
+25 ss char223
+26 ae char230
+27 oe
+28 /o char248
+29 AE char198
+30 OE
+31 /O char216
+33 !
+34 "
+35 # sh
+36 $ Do
+37 %
+38 &
+39 '
+40 (
+41 )
+42 *
+43 +
+44 ,
+45 - \-
+46 .
+47 / sl
+48 0
+49 1
+50 2
+51 3
+52 4
+53 5
+54 6
+55 7
+56 8
+57 9
+58 :
+59 ;
+60 <
+61 =
+62 >
+63 ?
+64 @ at
+65 A
+66 B
+67 C
+68 D
+69 E
+70 F
+71 G
+72 H
+73 I
+74 J
+75 K
+76 L
+77 M
+78 N
+79 O
+80 P
+81 Q
+82 R
+83 S
+84 T
+85 U
+86 V
+87 W
+88 X
+89 Y
+90 Z
+91 [ lB
+92 \ rs
+93 ] rB
+94 a^ ^ ha
+95 _
+96 ` oq
+97 a
+98 b
+99 c
+100 d
+101 e
+102 f
+103 g
+104 h
+105 i
+106 j
+107 k
+108 l
+109 m
+110 n
+111 o
+112 p
+113 q
+114 r
+115 s
+116 t
+117 u
+118 v
+119 w
+120 x
+121 y
+122 z
+123 lC {
+124 ba |
+125 rC }
+126 a~ ~
diff --git a/gnu/usr.bin/groff/devkoi8-r/DESC.proto b/gnu/usr.bin/groff/devkoi8-r/DESC.proto
new file mode 100644
index 0000000..041ceba
--- /dev/null
+++ b/gnu/usr.bin/groff/devkoi8-r/DESC.proto
@@ -0,0 +1,8 @@
+res 240
+hor 24
+vert 40
+unitwidth 10
+sizes 10 0
+fonts 6 R I B BI S L
+tcommand
+postpro grotty
diff --git a/gnu/usr.bin/groff/devkoi8-r/Makefile b/gnu/usr.bin/groff/devkoi8-r/Makefile
new file mode 100644
index 0000000..09f5a91
--- /dev/null
+++ b/gnu/usr.bin/groff/devkoi8-r/Makefile
@@ -0,0 +1,6 @@
+# Makefile for devkoi8-r
+
+DEVICE= koi8-r
+
+.include "../Makefile.tty"
+.include "../Makefile.dev"
diff --git a/gnu/usr.bin/groff/devkoi8-r/Makefile.sub b/gnu/usr.bin/groff/devkoi8-r/Makefile.sub
new file mode 100644
index 0000000..8962e5b
--- /dev/null
+++ b/gnu/usr.bin/groff/devkoi8-r/Makefile.sub
@@ -0,0 +1,32 @@
+DEV=koi8-r
+FONTS=R I B BI
+DEVFILES=$(FONTS) DESC
+CLEANADD=$(FONTS) DESC
+
+RES=240
+CPI=10
+LPI=6
+
+$(FONTS): R.proto
+ @echo Making $@
+ @-rm -f $@
+ @(charwidth=`expr $(RES) / $(CPI)` ; \
+ sed -e "s/^name [A-Z]*$$/name $@/" \
+ -e "s/^\\([^ ]*\\) [0-9]+ /\\1 $$charwidth /" \
+ -e "s/^spacewidth [0-9]+$$/spacewidth $$charwidth/" \
+ -e "s/^internalname .*$$/internalname $@/" \
+ -e "/^internalname/s/BI/3/" \
+ -e "/^internalname/s/B/2/" \
+ -e "/^internalname/s/I/1/" \
+ -e "/^internalname .*[^ 0-9]/d" \
+ $(srcdir)/R.proto >$@)
+
+DESC: DESC.proto
+ @echo Making $@
+ @-rm -f $@
+ @sed -e "s/^res .*$$/res $(RES)/" \
+ -e "s/^hor .*$$/hor `expr $(RES) / $(CPI)`/" \
+ -e "s/^vert .*$$/vert `expr $(RES) / $(LPI)`/" \
+ -e "s/^fonts .*$$/fonts `set $(FONTS); echo $$#` $(FONTS)/" \
+ $(srcdir)/DESC.proto >$@
+
diff --git a/gnu/usr.bin/groff/devkoi8-r/R.proto b/gnu/usr.bin/groff/devkoi8-r/R.proto
new file mode 100644
index 0000000..7ccb83f
--- /dev/null
+++ b/gnu/usr.bin/groff/devkoi8-r/R.proto
@@ -0,0 +1,239 @@
+name R
+internalname 0
+spacewidth 24
+charset
+! 24 0 0041
+" 24 0 0042
+lq "
+rq "
+# 24 0 0043
+sh "
+$ 24 0 0044
+Do "
+% 24 0 0045
+& 24 0 0046
+' 24 0 0047
+aa "
+fm "
+aq "
+( 24 0 0050
+) 24 0 0051
+* 24 0 0052
+** "
++ 24 0 0053
+pl "
+, 24 0 0054
+\- 24 0 0055
+hy "
+- "
+mi "
+en "
+. 24 0 0056
+/ 24 0 0057
+sl "
+f/ "
+0 24 0 0060
+1 24 0 0061
+2 24 0 0062
+3 24 0 0063
+4 24 0 0064
+5 24 0 0065
+6 24 0 0066
+7 24 0 0067
+8 24 0 0070
+9 24 0 0071
+: 24 0 0072
+; 24 0 0073
+< 24 0 0074
+la "
+fo "
+= 24 0 0075
+eq "
+> 24 0 0076
+ra "
+fc "
+? 24 0 0077
+@ 24 0 0100
+at "
+A 24 0 0101
+*A "
+B 24 0 0102
+*B "
+C 24 0 0103
+D 24 0 0104
+E 24 0 0105
+*E "
+F 24 0 0106
+G 24 0 0107
+H 24 0 0110
+*Y "
+I 24 0 0111
+*I "
+J 24 0 0112
+K 24 0 0113
+*K "
+L 24 0 0114
+M 24 0 0115
+*M "
+N 24 0 0116
+*N "
+O 24 0 0117
+ci "
+*O "
+P 24 0 0120
+*R "
+Q 24 0 0121
+R 24 0 0122
+S 24 0 0123
+T 24 0 0124
+*T "
+U 24 0 0125
+V 24 0 0126
+W 24 0 0127
+X 24 0 0130
+*X "
+Y 24 0 0131
+*U "
+Z 24 0 0132
+*Z "
+[ 24 0 0133
+lB "
+\ 24 0 0134
+rs "
+] 24 0 0135
+rB "
+a^ 24 0 0136
+^ "
+ha "
+_ 24 0 0137
+ru "
+ul "
+` 24 0 0140
+oq "
+ga "
+a 24 0 0141
+b 24 0 0142
+c 24 0 0143
+d 24 0 0144
+e 24 0 0145
+f 24 0 0146
+g 24 0 0147
+h 24 0 0150
+i 24 0 0151
+.i "
+j 24 0 0152
+k 24 0 0153
+l 24 0 0154
+m 24 0 0155
+n 24 0 0156
+o 24 0 0157
+*o "
+p 24 0 0160
+q 24 0 0161
+r 24 0 0162
+s 24 0 0163
+t 24 0 0164
+u 24 0 0165
+v 24 0 0166
+w 24 0 0167
+x 24 0 0170
+mu "
+y 24 0 0171
+z 24 0 0172
+lC 24 0 0173
+{ "
+ba 24 0 0174
+or "
+bv "
+br "
+| "
+lb "
+lc "
+lf "
+lk "
+lt "
+rb "
+rc "
+rf "
+rk "
+rt "
+rC 24 0 0175
+} "
+a~ 24 0 0176
+~ "
+ap "
+ti "
+em 24 0 0200
+bu 24 0 0224
+~= 24 0 0227
+<= 24 0 0230
+>= 24 0 0231
+de 24 0 0234
+di 24 0 0237
+char163 24 0 0243
+char179 24 0 0263
+co 24 0 0277
+char192 24 0 0300
+char193 24 0 0301
+char194 24 0 0302
+char195 24 0 0303
+char196 24 0 0304
+char197 24 0 0305
+char198 24 0 0306
+char199 24 0 0307
+char200 24 0 0310
+char201 24 0 0311
+char202 24 0 0312
+char203 24 0 0313
+char204 24 0 0314
+char205 24 0 0315
+char206 24 0 0316
+char207 24 0 0317
+char208 24 0 0320
+char209 24 0 0321
+char210 24 0 0322
+char211 24 0 0323
+char212 24 0 0324
+char213 24 0 0325
+char214 24 0 0326
+char215 24 0 0327
+char216 24 0 0330
+char217 24 0 0331
+char218 24 0 0332
+char219 24 0 0333
+char220 24 0 0334
+char221 24 0 0335
+char222 24 0 0336
+char223 24 0 0337
+char224 24 0 0340
+char225 24 0 0341
+char226 24 0 0342
+char227 24 0 0343
+char228 24 0 0344
+char229 24 0 0345
+char230 24 0 0346
+char231 24 0 0347
+char232 24 0 0350
+char233 24 0 0351
+char234 24 0 0352
+char235 24 0 0353
+char236 24 0 0354
+char237 24 0 0355
+char238 24 0 0356
+char239 24 0 0357
+char240 24 0 0360
+char241 24 0 0361
+char242 24 0 0362
+char243 24 0 0363
+char244 24 0 0364
+char245 24 0 0365
+char246 24 0 0366
+char247 24 0 0367
+char248 24 0 0370
+char249 24 0 0371
+char250 24 0 0372
+char251 24 0 0373
+char252 24 0 0374
+char253 24 0 0375
+char254 24 0 0376
+char255 24 0 0377
diff --git a/gnu/usr.bin/groff/devlatin1/DESC.proto b/gnu/usr.bin/groff/devlatin1/DESC.proto
new file mode 100644
index 0000000..041ceba
--- /dev/null
+++ b/gnu/usr.bin/groff/devlatin1/DESC.proto
@@ -0,0 +1,8 @@
+res 240
+hor 24
+vert 40
+unitwidth 10
+sizes 10 0
+fonts 6 R I B BI S L
+tcommand
+postpro grotty
diff --git a/gnu/usr.bin/groff/devlatin1/Makefile b/gnu/usr.bin/groff/devlatin1/Makefile
new file mode 100644
index 0000000..b431078
--- /dev/null
+++ b/gnu/usr.bin/groff/devlatin1/Makefile
@@ -0,0 +1,6 @@
+# Makefile for devlatin1
+
+DEVICE= latin1
+
+.include "../Makefile.tty"
+.include "../Makefile.dev"
diff --git a/gnu/usr.bin/groff/devlatin1/Makefile.sub b/gnu/usr.bin/groff/devlatin1/Makefile.sub
new file mode 100644
index 0000000..25de3f7
--- /dev/null
+++ b/gnu/usr.bin/groff/devlatin1/Makefile.sub
@@ -0,0 +1,32 @@
+DEV=latin1
+FONTS=R I B BI
+DEVFILES=$(FONTS) DESC
+CLEANADD=$(FONTS) DESC
+
+RES=240
+CPI=10
+LPI=6
+
+$(FONTS): R.proto
+ @echo Making $@
+ @-rm -f $@
+ @(charwidth=`expr $(RES) / $(CPI)` ; \
+ sed -e "s/^name [A-Z]*$$/name $@/" \
+ -e "s/^\\([^ ]*\\) [0-9]+ /\\1 $$charwidth /" \
+ -e "s/^spacewidth [0-9]+$$/spacewidth $$charwidth/" \
+ -e "s/^internalname .*$$/internalname $@/" \
+ -e "/^internalname/s/BI/3/" \
+ -e "/^internalname/s/B/2/" \
+ -e "/^internalname/s/I/1/" \
+ -e "/^internalname .*[^ 0-9]/d" \
+ $(srcdir)/R.proto >$@)
+
+DESC: DESC.proto
+ @echo Making $@
+ @-rm -f $@
+ @sed -e "s/^res .*$$/res $(RES)/" \
+ -e "s/^hor .*$$/hor `expr $(RES) / $(CPI)`/" \
+ -e "s/^vert .*$$/vert `expr $(RES) / $(LPI)`/" \
+ -e "s/^fonts .*$$/fonts `set $(FONTS); echo $$#` $(FONTS)/" \
+ $(srcdir)/DESC.proto >$@
+
diff --git a/gnu/usr.bin/groff/devlatin1/R.proto b/gnu/usr.bin/groff/devlatin1/R.proto
new file mode 100644
index 0000000..29a8875
--- /dev/null
+++ b/gnu/usr.bin/groff/devlatin1/R.proto
@@ -0,0 +1,353 @@
+name R
+internalname 0
+spacewidth 24
+charset
+! 24 0 0041
+" 24 0 0042
+lq "
+rq "
+# 24 0 0043
+sh "
+$ 24 0 0044
+Do "
+% 24 0 0045
+& 24 0 0046
+' 24 0 0047
+fm "
+aq "
+( 24 0 0050
+) 24 0 0051
+* 24 0 0052
+** "
++ 24 0 0053
+pl "
+, 24 0 0054
+\- 24 0 0055
+mi "
+- "
+hy "
+en "
+. 24 0 0056
+/ 24 0 0057
+sl "
+f/ "
+0 24 0 0060
+1 24 0 0061
+2 24 0 0062
+3 24 0 0063
+4 24 0 0064
+5 24 0 0065
+6 24 0 0066
+7 24 0 0067
+8 24 0 0070
+9 24 0 0071
+: 24 0 0072
+; 24 0 0073
+< 24 0 0074
+la "
+fo "
+= 24 0 0075
+eq "
+> 24 0 0076
+ra "
+fc "
+? 24 0 0077
+@ 24 0 0100
+at "
+A 24 0 0101
+*A "
+B 24 0 0102
+*B "
+C 24 0 0103
+D 24 0 0104
+E 24 0 0105
+*E "
+F 24 0 0106
+G 24 0 0107
+H 24 0 0110
+*Y "
+I 24 0 0111
+*I "
+J 24 0 0112
+K 24 0 0113
+*K "
+L 24 0 0114
+M 24 0 0115
+*M "
+N 24 0 0116
+*N "
+O 24 0 0117
+ci "
+*O "
+P 24 0 0120
+*R "
+Q 24 0 0121
+R 24 0 0122
+S 24 0 0123
+T 24 0 0124
+*T "
+U 24 0 0125
+V 24 0 0126
+W 24 0 0127
+X 24 0 0130
+*X "
+Y 24 0 0131
+*U "
+Z 24 0 0132
+*Z "
+[ 24 0 0133
+lB "
+\ 24 0 0134
+rs "
+] 24 0 0135
+rB "
+a^ 24 0 0136
+^ "
+ha "
+_ 24 0 0137
+ru "
+ul "
+` 24 0 0140
+oq "
+ga "
+a 24 0 0141
+b 24 0 0142
+c 24 0 0143
+d 24 0 0144
+e 24 0 0145
+f 24 0 0146
+g 24 0 0147
+h 24 0 0150
+i 24 0 0151
+.i "
+j 24 0 0152
+k 24 0 0153
+l 24 0 0154
+m 24 0 0155
+n 24 0 0156
+o 24 0 0157
+*o "
+p 24 0 0160
+q 24 0 0161
+r 24 0 0162
+s 24 0 0163
+t 24 0 0164
+u 24 0 0165
+v 24 0 0166
+w 24 0 0167
+x 24 0 0170
+y 24 0 0171
+z 24 0 0172
+lC 24 0 0173
+{ "
+ba 24 0 0174
+or "
+bv "
+br "
+| "
+lb "
+lc "
+lf "
+lk "
+lt "
+rb "
+rc "
+rf "
+rk "
+rt "
+rC 24 0 0175
+} "
+a~ 24 0 0176
+~ "
+ap "
+ti "
+r! 24 0 0241
+char161 "
+ct 24 0 0242
+char162 "
+Po 24 0 0243
+char163 "
+Cs 24 0 0244
+char164 "
+Ye 24 0 0245
+char165 "
+bb 24 0 0246
+char166 "
+sc 24 0 0247
+char167 "
+ad 24 0 0250
+char168 "
+co 24 0 0251
+char169 "
+Of 24 0 0252
+char170 "
+Fo 24 0 0253
+char171 "
+no 24 0 0254
+char172 "
+char173 24 0 0255
+rg 24 0 0256
+char174 "
+a- 24 0 0257
+char175 "
+de 24 0 0260
+char176 "
+ao "
++- 24 0 0261
+char177 "
+S2 24 0 0262
+char178 "
+S3 24 0 0263
+char179 "
+aa 24 0 0264
+char180 "
+*m 24 0 0265
+char181 "
+ps 24 0 0266
+char182 "
+md 24 0 0267
+char183 "
+ac 24 0 0270
+char184 "
+S1 24 0 0271
+char185 "
+Om 24 0 0272
+char186 "
+Fc 24 0 0273
+char187 "
+14 24 0 0274
+char188 "
+12 24 0 0275
+char189 "
+34 24 0 0276
+char190 "
+r? 24 0 0277
+char191 "
+`A 24 0 0300
+char192 "
+'A 24 0 0301
+char193 "
+^A 24 0 0302
+char194 "
+~A 24 0 0303
+char195 "
+:A 24 0 0304
+char196 "
+oA 24 0 0305
+char197 "
+AE 24 0 0306
+char198 "
+,C 24 0 0307
+char199 "
+`E 24 0 0310
+char200 "
+'E 24 0 0311
+char201 "
+^E 24 0 0312
+char202 "
+:E 24 0 0313
+char203 "
+`I 24 0 0314
+char204 "
+'I 24 0 0315
+char205 "
+^I 24 0 0316
+char206 "
+:I 24 0 0317
+char207 "
+-D 24 0 0320
+char208 "
+~N 24 0 0321
+char209 "
+`O 24 0 0322
+char210 "
+'O 24 0 0323
+char211 "
+^O 24 0 0324
+char212 "
+~O 24 0 0325
+char213 "
+:O 24 0 0326
+char214 "
+mu 24 0 0327
+char215 "
+/O 24 0 0330
+char216 "
+`U 24 0 0331
+char217 "
+'U 24 0 0332
+char218 "
+^U 24 0 0333
+char219 "
+:U 24 0 0334
+char220 "
+'Y 24 0 0335
+char221 "
+TP 24 0 0336
+char222 "
+ss 24 0 0337
+char223 "
+`a 24 0 0340
+char224 "
+'a 24 0 0341
+char225 "
+^a 24 0 0342
+char226 "
+~a 24 0 0343
+char227 "
+:a 24 0 0344
+char228 "
+oa 24 0 0345
+char229 "
+ae 24 0 0346
+char230 "
+,c 24 0 0347
+char231 "
+`e 24 0 0350
+char232 "
+'e 24 0 0351
+char233 "
+^e 24 0 0352
+char234 "
+:e 24 0 0353
+char235 "
+`i 24 0 0354
+char236 "
+'i 24 0 0355
+char237 "
+^i 24 0 0356
+char238 "
+:i 24 0 0357
+char239 "
+Sd 24 0 0360
+char240 "
+~n 24 0 0361
+char241 "
+`o 24 0 0362
+char242 "
+'o 24 0 0363
+char243 "
+^o 24 0 0364
+char244 "
+~o 24 0 0365
+char245 "
+:o 24 0 0366
+char246 "
+di 24 0 0367
+char247 "
+/o 24 0 0370
+char248 "
+`u 24 0 0371
+char249 "
+'u 24 0 0372
+char250 "
+^u 24 0 0373
+char251 "
+:u 24 0 0374
+char252 "
+'y 24 0 0375
+char253 "
+Tp 24 0 0376
+char254 "
+:y 24 0 0377
+char255 "
diff --git a/gnu/usr.bin/groff/devps/AB b/gnu/usr.bin/groff/devps/AB
new file mode 100644
index 0000000..d5313f0
--- /dev/null
+++ b/gnu/usr.bin/groff/devps/AB
@@ -0,0 +1,559 @@
+name AB
+internalname AvantGarde-Demi
+spacewidth 280
+encoding text.enc
+ligatures fi fl 0
+kernpairs
+A y -50
+A w -65
+A v -70
+A u -20
+A ' -90
+A Y -80
+A W -60
+A V -102
+A U -40
+A T -25
+A Q -50
+A O -50
+A G -40
+A C -40
+B A -10
+C A -40
+D . -20
+D , -20
+D Y -45
+D W -25
+D V -50
+D A -50
+F . -129
+F e -20
+F , -162
+F a -20
+F A -75
+G . -20
+G , -20
+G Y -15
+J . -15
+J a -20
+J A -30
+K y -20
+K u -15
+K o -45
+K e -40
+K O -30
+L y -23
+L ' -30
+L rq -30
+L Y -80
+L W -55
+L V -85
+L T -46
+O . -30
+O , -30
+O Y -30
+O X -30
+O W -20
+O V -45
+O T -15
+O A -60
+P . -200
+P o -20
+P e -20
+P , -220
+P a -20
+P A -100
+Q , 20
+R W 25
+R V -10
+R U 25
+R T 40
+R O 25
+S , 20
+T y -10
+T w -55
+T u -46
+T ; -29
+T r -30
+T . -91
+T o -49
+T - -75
+T hy -75
+T char173 -75
+T e -49
+T , -82
+T : -15
+T a -70
+T O -15
+T A -25
+U . -20
+U , -20
+U A -40
+V u -55
+V ; -33
+V . -145
+V o -101
+V i -15
+V - -75
+V hy -75
+V char173 -75
+V e -101
+V , -145
+V : -18
+V a -95
+V O -45
+V G -20
+V A -102
+W y -15
+W u -30
+W ; -33
+W . -106
+W o -46
+W i -10
+W - -35
+W hy -35
+W char173 -35
+W e -47
+W , -106
+W : -15
+W a -50
+W O -20
+W A -58
+Y u -52
+Y ; -23
+Y . -145
+Y o -89
+Y - -100
+Y hy -100
+Y char173 -100
+Y e -89
+Y , -145
+Y : -10
+Y a -93
+Y O -30
+Y A -80
+a t 5
+a p 20
+a b 5
+b y -20
+b v -20
+c y -20
+c l -15
+c k -15
+, ' -70
+, rq -70
+e y -20
+e x -20
+e w -20
+e v -20
+f . -40
+f o -20
+f l -15
+f i -15
+f f -20
+f .i -15
+f , -40
+f a -15
+g i 25
+g a 15
+h y -30
+k y -5
+k o -30
+k e -40
+m y -20
+m u -20
+n y -15
+n v -30
+o y -20
+o x -30
+o w -20
+o v -30
+p y -20
+. ' -70
+. rq -70
+lq A -50
+` ` -80
+` oq -80
+oq ` -80
+oq oq -80
+` A -50
+oq A -50
+' v -10
+' t 10
+' s -15
+' r -20
+' ' -80
+' d -50
+r y 40
+r v 40
+r u 20
+r t 20
+r s 20
+r q -8
+r . -73
+r p 20
+r o -15
+r n 21
+r m 15
+r l 20
+r k 5
+r i 20
+r - -60
+r hy -60
+r char173 -60
+r g 1
+r e -4
+r d -6
+r , -75
+r c -7
+s . 20
+s , 20
+v . -90
+v o -20
+v e -20
+v , -90
+v a -30
+w . -90
+w o -30
+w e -20
+w , -90
+w a -30
+x e -20
+y . -100
+y o -30
+y e -20
+y , -100
+y c -35
+y a -30
+charset
+ha 600,740 2 0000 asciicircum
+ti 600,347 0 0001 asciitilde
+vS 520,944,15 2 0002 Scaron
+vZ 500,944 2 0003 Zcaron
+vs 440,774,18 2 0004 scaron
+vz 460,774 2 0005 zcaron
+:Y 620,939 2 0006 Ydieresis
+tm 1000,740 2 0007 trademark
+aq 220,740 2 0010 quotesingle
+space 280 0 0040
+! 280,740 2 0041 exclam
+" 360,740 2 0042 quotedbl
+# 560,700 0 0043 numbersign
+sh "
+$ 560,857,86 2 0044 dollar
+Do "
+% 860,755,15 2 0045 percent
+& 680,755,15 2 0046 ampersand
+' 280,740 2 0047 quoteright
+( 380,754,157 2 0050 parenleft
+) 380,754,157 2 0051 parenright
+* 440,755 2 0052 asterisk
++ 600,506 0 0053 plus
+, 280,133,141 0 0054 comma
+- 420,348 0 0055 hyphen
+hy "
+char173 "
+. 280,133 0 0056 period
+/ 460,740,100 2 0057 slash
+sl "
+0 560,755,15 2 0060 zero
+1 560,740 2 0061 one
+2 560,755 2 0062 two
+3 560,755,15 2 0063 three
+4 560,740 2 0064 four
+5 560,740,15 2 0065 five
+6 560,739,15 2 0066 six
+7 560,740 2 0067 seven
+8 560,755,15 2 0070 eight
+9 560,754 2 0071 nine
+: 280,555 0 0072 colon
+; 280,555,141 0 0073 semicolon
+< 600,514,8 0 0074 less
+= 600,425 0 0075 equal
+> 600,514,8 0 0076 greater
+? 560,755 2 0077 question
+@ 740,712,12 0 0100 at
+at "
+A 740,740 2 0101 A
+B 580,740 2 0102 B
+C 780,755,15 2 0103 C
+D 700,740 2 0104 D
+E 520,740 2 0105 E
+F 480,740 2 0106 F
+G 840,755,15 2 0107 G
+H 680,740 2 0110 H
+I 280,740 2 0111 I
+J 480,740,15 2 0112 J
+K 620,740 2 0113 K
+L 440,740 2 0114 L
+M 900,740 2 0115 M
+N 740,740 2 0116 N
+O 840,755,15 2 0117 O
+P 560,740 2 0120 P
+Q 840,755,15 2 0121 Q
+R 580,740 2 0122 R
+S 520,755,15 2 0123 S
+T 420,740 2 0124 T
+U 640,740,15 2 0125 U
+V 700,740 2 0126 V
+W 900,740 2 0127 W
+X 680,740 2 0130 X
+Y 620,740 2 0131 Y
+Z 500,740 2 0132 Z
+[ 320,754,157 2 0133 bracketleft
+lB "
+\ 640,740,100 2 0134 backslash
+rs "
+] 320,754,157 2 0135 bracketright
+rB "
+a^ 540,774 2 0136 circumflex
+^ "
+_ 500,0,125 0 0137 underscore
+` 280,740 2 0140 quoteleft
+oq "
+a 660,574,18 0 0141 a
+b 660,740,18 2 0142 b
+c 640,574,18 0 0143 c
+d 660,740,18 2 0144 d
+e 640,577,18 0 0145 e
+f 280,755 2 0146 f
+g 660,574,226 1 0147 g
+h 600,740 2 0150 h
+i 240,740 2 0151 i
+j 260,740,185 3 0152 j
+k 580,740 2 0153 k
+l 240,740 2 0154 l
+m 940,574 0 0155 m
+n 600,574 0 0156 n
+o 640,574,18 0 0157 o
+p 660,574,185 1 0160 p
+q 660,574,185 1 0161 q
+r 320,574 0 0162 r
+s 440,574,18 0 0163 s
+t 300,740 2 0164 t
+u 600,555,18 0 0165 u
+v 560,555 0 0166 v
+w 800,555 0 0167 w
+x 560,555 0 0170 x
+y 580,555,185 1 0171 y
+z 460,555 0 0172 z
+lC 340,747,191 3 0173 braceleft
+{ "
+ba 600,740,100 2 0174 bar
+| "
+rC 340,747,191 3 0175 braceright
+} "
+a~ 480,767 2 0176 tilde
+~ "
+bq 280,133,141 0 0200 quotesinglbase
+Fo 460,469 0 0201 guillemotleft
+char171 "
+Fc 460,469 0 0202 guillemotright
+char187 "
+bu 600,532 0 0203 bullet
+Fn 560,824,151 2 0204 florin
+f/ 160,740 2 0205 fraction
+%0 1280,755,15 2 0206 perthousand
+dg 560,740,142 2 0207 dagger
+dd 560,740,142 2 0210 daggerdbl
+en 500,348 0 0211 endash
+em 1000,348 0 0212 emdash
+fi 520,755 2 0214 fi
+fl 520,755 2 0215 fl
+.i 240,555 0 0220 dotlessi
+ga 420,851 2 0222 grave
+a" 700,862 2 0223 hungarumlaut
+a. 280,769 2 0224 dotaccent
+ab 480,770 2 0225 breve
+ah 540,774 2 0226 caron
+ao 360,834 2 0227 ring
+ho 340,9,195 1 0230 ogonek
+lq 480,740 2 0231 quotedblleft
+rq 480,740 2 0232 quotedblright
+oe 1080,574,18 0 0233 oe
+/l 320,740 2 0234 lslash
+Bq 480,133,141 0 0235 quotedblbase
+OE 1060,755,15 2 0236 OE
+/L 480,740 2 0237 Lslash
+r! 280,555,185 1 0241 exclamdown
+char161 "
+ct 560,715 0 0242 cent
+char162 "
+Po 560,755 2 0243 sterling
+char163 "
+Cs 560,577 0 0244 currency
+char164 "
+Ye 560,740 2 0245 yen
+char165 "
+bb 600,740,100 2 0246 brokenbar
+char166 "
+sc 560,755,158 2 0247 section
+char167 "
+ad 500,769 2 0250 dieresis
+char168 "
+co 740,752,12 2 0251 copyright
+char169 "
+Of 360,755 2 0252 ordfeminine
+char170 "
+fo 240,469 0 0253 guilsinglleft
+no 600,425 0 0254 logicalnot
+char172 "
+\- 600,313 0 0255 minus
+rg 740,752,12 2 0256 registered
+char174 "
+a- 420,759 2 0257 macron
+char175 "
+de 400,712 0 0260 degree
+char176 "
+char177 600,556,62 0 0261 plusminus
+S2 336,749 2 0262 twosuperior
+char178 "
+S3 336,749 2 0263 threesuperior
+char179 "
+aa 420,849 2 0264 acute
+char180 "
+char181 576,555,187 1 0265 mu
+ps 600,740,103 2 0266 paragraph
+char182 "
+char183 280,320 0 0267 periodcentered
+ac 340,6,251 1 0270 cedilla
+char184 "
+S1 336,740 2 0271 onesuperior
+char185 "
+Om 360,755 2 0272 ordmasculine
+char186 "
+fc 240,469 0 0273 guilsinglright
+14 840,740 2 0274 onequarter
+char188 "
+12 840,740 2 0275 onehalf
+char189 "
+34 840,749 2 0276 threequarters
+char190 "
+r? 560,555,200 1 0277 questiondown
+char191 "
+`A 740,1021 2 0300 Agrave
+char192 "
+'A 740,1019 2 0301 Aacute
+char193 "
+^A 740,944 2 0302 Acircumflex
+char194 "
+~A 740,937 2 0303 Atilde
+char195 "
+:A 740,939 2 0304 Adieresis
+char196 "
+oA 740,969 2 0305 Aring
+char197 "
+AE 900,740 2 0306 AE
+char198 "
+,C 780,755,251 3 0307 Ccedilla
+char199 "
+`E 520,1021 2 0310 Egrave
+char200 "
+'E 520,1019 2 0311 Eacute
+char201 "
+^E 520,944 2 0312 Ecircumflex
+char202 "
+:E 520,939 2 0313 Edieresis
+char203 "
+`I 280,1021 2 0314 Igrave
+char204 "
+'I 280,1019 2 0315 Iacute
+char205 "
+^I 280,944 2 0316 Icircumflex
+char206 "
+:I 280,939 2 0317 Idieresis
+char207 "
+-D 742,740 2 0320 Eth
+char208 "
+~N 740,937 2 0321 Ntilde
+char209 "
+`O 840,1021,15 2 0322 Ograve
+char210 "
+'O 840,1019,15 2 0323 Oacute
+char211 "
+^O 840,944,15 2 0324 Ocircumflex
+char212 "
+~O 840,937,15 2 0325 Otilde
+char213 "
+:O 840,939,15 2 0326 Odieresis
+char214 "
+char215 600,494 0 0327 multiply
+/O 840,814,71 2 0330 Oslash
+char216 "
+`U 640,1021,15 2 0331 Ugrave
+char217 "
+'U 640,1019,15 2 0332 Uacute
+char218 "
+^U 640,944,15 2 0333 Ucircumflex
+char219 "
+:U 640,939,15 2 0334 Udieresis
+char220 "
+'Y 620,1019 2 0335 Yacute
+char221 "
+TP 560,740 2 0336 Thorn
+char222 "
+ss 600,755,18 2 0337 germandbls
+char223 "
+`a 660,851,18 2 0340 agrave
+char224 "
+'a 660,849,18 2 0341 aacute
+char225 "
+^a 660,774,18 2 0342 acircumflex
+char226 "
+~a 660,767,18 2 0343 atilde
+char227 "
+:a 660,769,18 2 0344 adieresis
+char228 "
+oa 660,834,18 2 0345 aring
+char229 "
+ae 1080,574,18 0 0346 ae
+char230 "
+,c 640,574,251 1 0347 ccedilla
+char231 "
+`e 640,851,18 2 0350 egrave
+char232 "
+'e 640,849,18 2 0351 eacute
+char233 "
+^e 640,774,18 2 0352 ecircumflex
+char234 "
+:e 640,769,18 2 0353 edieresis
+char235 "
+`i 240,851 2 0354 igrave
+char236 "
+'i 240,849 2 0355 iacute
+char237 "
+^i 240,774 2 0356 icircumflex
+char238 "
+:i 240,769 2 0357 idieresis
+char239 "
+Sd 640,754,18 2 0360 eth
+char240 "
+~n 600,767 2 0361 ntilde
+char241 "
+`o 640,851,18 2 0362 ograve
+char242 "
+'o 640,849,18 2 0363 oacute
+char243 "
+^o 640,774,18 2 0364 ocircumflex
+char244 "
+~o 640,767,18 2 0365 otilde
+char245 "
+:o 640,769,18 2 0366 odieresis
+char246 "
+char247 600,526,20 0 0367 divide
+/o 660,608,50 0 0370 oslash
+char248 "
+`u 600,851,18 2 0371 ugrave
+char249 "
+'u 600,849,18 2 0372 uacute
+char250 "
+^u 600,774,18 2 0373 ucircumflex
+char251 "
+:u 600,769,18 2 0374 udieresis
+char252 "
+'y 580,849,185 3 0375 yacute
+char253 "
+Tp 660,740,185 3 0376 thorn
+char254 "
+:y 580,769,185 3 0377 ydieresis
+char255 "
diff --git a/gnu/usr.bin/groff/devps/ABI b/gnu/usr.bin/groff/devps/ABI
new file mode 100644
index 0000000..000d958
--- /dev/null
+++ b/gnu/usr.bin/groff/devps/ABI
@@ -0,0 +1,560 @@
+name ABI
+internalname AvantGarde-DemiOblique
+slant 10.5
+spacewidth 280
+encoding text.enc
+ligatures fi fl 0
+kernpairs
+A y -50
+A w -65
+A v -70
+A u -20
+A ' -90
+A Y -80
+A W -60
+A V -102
+A U -40
+A T -25
+A Q -50
+A O -50
+A G -40
+A C -40
+B A -10
+C A -40
+D . -20
+D , -20
+D Y -45
+D W -25
+D V -50
+D A -50
+F . -129
+F e -20
+F , -162
+F a -20
+F A -75
+G . -20
+G , -20
+G Y -15
+J . -15
+J a -20
+J A -30
+K y -20
+K u -15
+K o -45
+K e -40
+K O -30
+L y -23
+L ' -30
+L rq -30
+L Y -80
+L W -55
+L V -85
+L T -46
+O . -30
+O , -30
+O Y -30
+O X -30
+O W -20
+O V -45
+O T -15
+O A -60
+P . -200
+P o -20
+P e -20
+P , -220
+P a -20
+P A -100
+Q , 20
+R W 25
+R V -10
+R U 25
+R T 40
+R O 25
+S , 20
+T y -10
+T w -55
+T u -46
+T ; -29
+T r -30
+T . -91
+T o -49
+T - -75
+T hy -75
+T char173 -75
+T e -49
+T , -82
+T : -15
+T a -70
+T O -15
+T A -25
+U . -20
+U , -20
+U A -40
+V u -55
+V ; -33
+V . -145
+V o -101
+V i -15
+V - -75
+V hy -75
+V char173 -75
+V e -101
+V , -145
+V : -18
+V a -95
+V O -45
+V G -20
+V A -102
+W y -15
+W u -30
+W ; -33
+W . -106
+W o -46
+W i -10
+W - -35
+W hy -35
+W char173 -35
+W e -47
+W , -106
+W : -15
+W a -50
+W O -20
+W A -58
+Y u -52
+Y ; -23
+Y . -145
+Y o -89
+Y - -100
+Y hy -100
+Y char173 -100
+Y e -89
+Y , -145
+Y : -10
+Y a -93
+Y O -30
+Y A -80
+a t 5
+a p 20
+a b 5
+b y -20
+b v -20
+c y -20
+c l -15
+c k -15
+, ' -70
+, rq -70
+e y -20
+e x -20
+e w -20
+e v -20
+f . -40
+f o -20
+f l -15
+f i -15
+f f -20
+f .i -15
+f , -40
+f a -15
+g i 25
+g a 15
+h y -30
+k y -5
+k o -30
+k e -40
+m y -20
+m u -20
+n y -15
+n v -30
+o y -20
+o x -30
+o w -20
+o v -30
+p y -20
+. ' -70
+. rq -70
+lq A -50
+` ` -80
+` oq -80
+oq ` -80
+oq oq -80
+` A -50
+oq A -50
+' v -10
+' t 10
+' s -15
+' r -20
+' ' -80
+' d -50
+r y 40
+r v 40
+r u 20
+r t 20
+r s 20
+r q -8
+r . -73
+r p 20
+r o -15
+r n 21
+r m 15
+r l 20
+r k 5
+r i 20
+r - -60
+r hy -60
+r char173 -60
+r g 1
+r e -4
+r d -6
+r , -75
+r c -7
+s . 20
+s , 20
+v . -90
+v o -20
+v e -20
+v , -90
+v a -30
+w . -90
+w o -30
+w e -20
+w , -90
+w a -30
+x e -20
+y . -100
+y o -30
+y e -20
+y , -100
+y c -35
+y a -30
+charset
+ha 600,740,0,46,-92,46 2 0000 asciicircum
+ti 600,347,0,29,-64,29 0 0001 asciitilde
+vS 520,944,15,165,1,82 2 0002 Scaron
+vZ 500,944,0,200,31,82 2 0003 Zcaron
+vs 440,774,18,173,1,82 2 0004 scaron
+vz 460,774,0,188,30,82 2 0005 zcaron
+:Y 620,939,0,189,-85,82 2 0006 Ydieresis
+tm 1000,740,0,8,-81,8 2 0007 trademark
+aq 220,740,0,144,-102,82 2 0010 quotesingle
+space 280 0 0040
+! 280,740,0,113,-23,82 2 0041 exclam
+" 360,740,0,168,-77,82 2 0042 quotedbl
+# 560,700,0,108,-16,82 0 0043 numbersign
+sh "
+$ 560,857,86,72,-49,72 2 0044 dollar
+Do "
+% 860,755,15,46,-89,46 2 0045 percent
+& 680,755,15,112,-21,82 2 0046 ampersand
+' 280,740,0,112,-109,82 2 0047 quoteright
+( 380,754,157,160,-70,82 2 0050 parenleft
+) 380,754,157,48,42,48 2 0051 parenright
+* 440,755,0,102,-124,82 2 0052 asterisk
++ 600,506,0,60,-34,60 0 0053 plus
+, 280,133,141,1,2,1 0 0054 comma
+- 420,348,0,43,-64,43 0 0055 hyphen
+hy "
+char173 "
+. 280,133,0,1,-23,1 0 0056 period
+/ 460,740,100,181,63,82 2 0057 slash
+sl "
+0 560,755,15,118,-20,82 2 0060 zero
+1 560,740,0,0,-180 2 0061 one
+2 560,755,0,112,6,82 2 0062 two
+3 560,755,15,75,-17,75 2 0063 three
+4 560,740,0,94,14,82 2 0064 four
+5 560,740,15,90,-14,82 2 0065 five
+6 560,739,15,77,-14,77 2 0066 six
+7 560,740,0,125,-33,82 2 0067 seven
+8 560,755,15,80,-21,80 2 0070 eight
+9 560,754,0,123,-60,82 2 0071 nine
+: 280,555,0,79,-23,79 0 0072 colon
+; 280,555,141,79,2,79 0 0073 semicolon
+< 600,514,8,99,-34,82 0 0074 less
+= 600,425,0,81,-13,81 0 0075 equal
+> 600,514,8,60,5,60 0 0076 greater
+? 560,755,0,83,-85,82 2 0077 question
+@ 740,712,12,142,-59,82 0 0100 at
+at "
+A 740,740,0,42,43,42 2 0101 A
+B 580,740,0,80,-20,80 2 0102 B
+C 780,755,15,134,-47,82 2 0103 C
+D 700,740,0,82,-13,82 2 0104 D
+E 520,740,0,126,-11,82 2 0105 E
+F 480,740,0,145,-11,82 2 0106 F
+G 840,755,15,97,-39,82 2 0107 G
+H 680,740,0,117,-21,82 2 0110 H
+I 280,740,0,116,-22,82 2 0111 I
+J 480,740,15,116,16,82 2 0112 J
+K 620,740,0,187,-39,82 2 0113 K
+L 440,740,0,69,-22,69 2 0114 L
+M 900,740,0,124,-13,82 2 0115 M
+N 740,740,0,118,-20,82 2 0116 N
+O 840,755,15,92,-45,82 2 0117 O
+P 560,740,0,135,-22,82 2 0120 P
+Q 840,755,15,92,-44,82 2 0121 Q
+R 580,740,0,126,-14,82 2 0122 R
+S 520,755,15,108,1,82 2 0123 S
+T 420,740,0,185,-69,82 2 0124 T
+U 640,740,15,132,-47,82 2 0125 U
+V 700,740,0,182,-95,82 2 0126 V
+W 900,740,0,186,-94,82 2 0127 W
+X 680,740,0,183,46,82 2 0130 X
+Y 620,740,0,189,-85,82 2 0131 Y
+Z 500,740,0,149,31,82 2 0132 Z
+[ 320,754,157,154,-39,82 2 0133 bracketleft
+lB "
+\ 640,740,100,0,-183 2 0134 backslash
+rs "
+] 320,754,157,72,43,72 2 0135 bracketright
+rB "
+a^ 540,774,0,98,-139,82 2 0136 circumflex
+^ "
+_ 500,0,125,36,73,36 0 0137 underscore
+` 280,740,0,111,-108,82 2 0140 quoteleft
+oq "
+a 660,574,18,106,-23,82 0 0141 a
+b 660,740,18,79,3,79 2 0142 b
+c 640,574,18,89,-34,82 0 0143 c
+d 660,740,18,145,-30,82 2 0144 d
+e 640,577,18,77,-27,77 0 0145 e
+f 280,755,0,190,-12,82 2 0146 f
+g 660,574,226,116,17,82 1 0147 g
+h 600,740,0,64,-4,64 2 0150 h
+i 240,740,0,133,-3,82 2 0151 i
+j 260,740,185,132,68,82 3 0152 j
+k 580,740,0,118,-30,82 2 0153 k
+l 240,740,0,134,-4,82 2 0154 l
+m 940,574,0,64,-4,64 0 0155 m
+n 600,574,0,63,-4,63 0 0156 n
+o 640,574,18,82,-21,82 0 0157 o
+p 660,574,185,76,37,76 1 0160 p
+q 660,574,185,106,-28,82 1 0161 q
+r 320,574,0,153,-13,82 0 0162 r
+s 440,574,18,93,1,82 0 0163 s
+t 300,740,0,152,-36,82 2 0164 t
+u 600,555,18,97,-37,82 0 0165 u
+v 560,555,0,149,-56,82 0 0166 v
+w 800,555,0,142,-64,82 0 0167 w
+x 560,555,0,122,47,82 0 0170 x
+y 580,555,185,144,-25,82 1 0171 y
+z 460,555,0,118,30,82 0 0172 z
+lC 340,747,191,165,10,82 3 0173 braceleft
+{ "
+ba 600,740,100,0,-164 2 0174 bar
+| "
+rC 340,747,191,115,62,82 3 0175 braceright
+} "
+a~ 480,767,0,134,-128,82 2 0176 tilde
+~ "
+bq 280,133,141,0,3 0 0200 quotesinglbase
+Fo 460,469,0,77,-55,77 0 0201 guillemotleft
+char171 "
+Fc 460,469,0,53,-31,53 0 0202 guillemotright
+char187 "
+bu 600,532,0,0,-165 0 0203 bullet
+Fn 560,824,151,154,77,82 2 0204 florin
+f/ 160,740,0,309,173,82 2 0205 fraction
+%0 1280,755,15,26,-89,26 2 0206 perthousand
+dg 560,740,142,102,-83,82 2 0207 dagger
+dd 560,740,142,108,-13,82 2 0210 daggerdbl
+en 500,348,0,79,-28,79 0 0211 endash
+em 1000,348,0,79,-28,79 0 0212 emdash
+fi 520,755,0,128,-22,82 2 0214 fi
+fl 520,755,0,128,-22,82 2 0215 fl
+.i 240,555,0,99,-3,82 0 0220 dotlessi
+ga 420,851,0,92,-139,82 2 0222 grave
+a" 700,862,0,104,-208,82 2 0223 hungarumlaut
+a. 280,769,0,120,-142,82 2 0224 dotaccent
+ab 480,770,0,152,-135,82 2 0225 breve
+ah 540,774,0,123,-164,82 2 0226 caron
+ao 360,834,0,114,-156,82 2 0227 ring
+ho 340,9,195,0,-9 1 0230 ogonek
+lq 480,740,0,116,-106,82 2 0231 quotedblleft
+rq 480,740,0,117,-107,82 2 0232 quotedblright
+oe 1080,574,18,78,-26,78 0 0233 oe
+/l 320,740,0,134,-24,82 2 0234 lslash
+Bq 480,133,141,5,5,5 0 0235 quotedblbase
+OE 1060,755,15,134,-48,82 2 0236 OE
+/L 480,740,0,54,-18,54 2 0237 Lslash
+r! 280,555,185,80,10,80 1 0241 exclamdown
+char161 "
+ct 560,715,0,89,-60,82 0 0242 cent
+char162 "
+Po 560,755,0,105,12,82 2 0243 sterling
+char163 "
+Cs 560,577,0,118,-3,82 0 0244 currency
+char164 "
+Ye 560,740,0,197,-33,82 2 0245 yen
+char165 "
+bb 600,740,100,0,-164 2 0246 brokenbar
+char166 "
+sc 560,755,158,92,-15,82 2 0247 section
+char167 "
+ad 500,769,0,115,-146,82 2 0250 dieresis
+char168 "
+co 740,752,12,137,0,82 2 0251 copyright
+char169 "
+Of 360,755,0,162,-77,82 2 0252 ordfeminine
+char170 "
+fo 240,469,0,87,-44,82 0 0253 guilsinglleft
+no 600,425,0,81,-55,81 0 0254 logicalnot
+char172 "
+\- 600,313,0,60,-34,60 0 0255 minus
+rg 740,752,12,137,0,82 2 0256 registered
+char174 "
+a- 420,759,0,120,-142,82 2 0257 macron
+char175 "
+de 400,712,0,101,-110,82 0 0260 degree
+char176 "
+char177 600,556,62,76,13,76 0 0261 plusminus
+S2 336,749,0,150,-23,82 2 0262 twosuperior
+char178 "
+S3 336,749,0,127,-37,82 2 0263 threesuperior
+char179 "
+aa 420,849,0,138,-174,82 2 0264 acute
+char180 "
+char181 576,555,187,116,47,82 1 0265 mu
+ps 600,740,103,194,-40,82 2 0266 paragraph
+char182 "
+char183 280,320,0,35,-58,35 0 0267 periodcentered
+ac 340,6,251,0,-17 1 0270 cedilla
+char184 "
+S1 336,740,0,74,-132,74 2 0271 onesuperior
+char185 "
+Om 360,755,0,141,-81,82 2 0272 ordmasculine
+char186 "
+fc 240,469,0,63,-20,63 0 0273 guilsinglright
+14 840,740,0,0,-137 2 0274 onequarter
+char188 "
+12 840,740,0,40,-107,40 2 0275 onehalf
+char189 "
+34 840,749,0,46,-47,46 2 0276 threequarters
+char190 "
+r? 560,555,200,17,-19,17 1 0277 questiondown
+char191 "
+`A 740,1021,0,42,43,42 2 0300 Agrave
+char192 "
+'A 740,1019,0,42,43,42 2 0301 Aacute
+char193 "
+^A 740,944,0,42,43,42 2 0302 Acircumflex
+char194 "
+~A 740,937,0,42,43,42 2 0303 Atilde
+char195 "
+:A 740,939,0,42,43,42 2 0304 Adieresis
+char196 "
+oA 740,969,0,42,43,42 2 0305 Aring
+char197 "
+AE 900,740,0,111,55,82 2 0306 AE
+char198 "
+,C 780,755,251,134,-47,82 3 0307 Ccedilla
+char199 "
+`E 520,1021,0,126,-11,82 2 0310 Egrave
+char200 "
+'E 520,1019,0,126,-11,82 2 0311 Eacute
+char201 "
+^E 520,944,0,139,-11,82 2 0312 Ecircumflex
+char202 "
+:E 520,939,0,136,-11,82 2 0313 Edieresis
+char203 "
+`I 280,1021,0,168,-22,82 2 0314 Igrave
+char204 "
+'I 280,1019,0,264,-22,82 2 0315 Iacute
+char205 "
+^I 280,944,0,259,-22,82 2 0316 Icircumflex
+char206 "
+:I 280,939,0,256,-22,82 2 0317 Idieresis
+char207 "
+-D 742,740,0,74,-33,74 2 0320 Eth
+char208 "
+~N 740,937,0,118,-20,82 2 0321 Ntilde
+char209 "
+`O 840,1021,15,92,-45,82 2 0322 Ograve
+char210 "
+'O 840,1019,15,92,-45,82 2 0323 Oacute
+char211 "
+^O 840,944,15,92,-45,82 2 0324 Ocircumflex
+char212 "
+~O 840,937,15,92,-45,82 2 0325 Otilde
+char213 "
+:O 840,939,15,92,-45,82 2 0326 Odieresis
+char214 "
+char215 600,494,0,67,-26,67 0 0327 multiply
+/O 840,814,71,101,-44,82 2 0330 Oslash
+char216 "
+`U 640,1021,15,132,-47,82 2 0331 Ugrave
+char217 "
+'U 640,1019,15,132,-47,82 2 0332 Uacute
+char218 "
+^U 640,944,15,132,-47,82 2 0333 Ucircumflex
+char219 "
+:U 640,939,15,132,-47,82 2 0334 Udieresis
+char220 "
+'Y 620,1019,0,189,-85,82 2 0335 Yacute
+char221 "
+TP 560,740,0,109,-22,82 2 0336 Thorn
+char222 "
+ss 600,755,18,79,-1,79 2 0337 germandbls
+char223 "
+`a 660,851,18,106,-23,82 2 0340 agrave
+char224 "
+'a 660,849,18,106,-23,82 2 0341 aacute
+char225 "
+^a 660,774,18,106,-23,82 2 0342 acircumflex
+char226 "
+~a 660,767,18,106,-23,82 2 0343 atilde
+char227 "
+:a 660,769,18,106,-23,82 2 0344 adieresis
+char228 "
+oa 660,834,18,106,-23,82 2 0345 aring
+char229 "
+ae 1080,574,18,75,-25,75 0 0346 ae
+char230 "
+,c 640,574,251,89,-33,82 1 0347 ccedilla
+char231 "
+`e 640,851,18,77,-27,77 2 0350 egrave
+char232 "
+'e 640,849,18,77,-27,77 2 0351 eacute
+char233 "
+^e 640,774,18,77,-27,77 2 0352 ecircumflex
+char234 "
+:e 640,769,18,77,-27,77 2 0353 edieresis
+char235 "
+`i 240,851,0,157,-3,82 2 0354 igrave
+char236 "
+'i 240,849,0,253,-3,82 2 0355 iacute
+char237 "
+^i 240,774,0,248,11,82 2 0356 icircumflex
+char238 "
+:i 240,769,0,245,-3,82 2 0357 idieresis
+char239 "
+Sd 640,754,18,109,-23,82 2 0360 eth
+char240 "
+~n 600,767,0,74,-4,74 2 0361 ntilde
+char241 "
+`o 640,851,18,82,-21,82 2 0362 ograve
+char242 "
+'o 640,849,18,82,-21,82 2 0363 oacute
+char243 "
+^o 640,774,18,82,-21,82 2 0364 ocircumflex
+char244 "
+~o 640,767,18,82,-21,82 2 0365 otilde
+char245 "
+:o 640,769,18,82,-21,82 2 0366 odieresis
+char246 "
+char247 600,526,20,60,-34,60 0 0367 divide
+/o 660,608,50,75,-31,75 0 0370 oslash
+char248 "
+`u 600,851,18,97,-37,82 2 0371 ugrave
+char249 "
+'u 600,849,18,97,-37,82 2 0372 uacute
+char250 "
+^u 600,774,18,97,-37,82 2 0373 ucircumflex
+char251 "
+:u 600,769,18,97,-37,82 2 0374 udieresis
+char252 "
+'y 580,849,185,144,-25,82 3 0375 yacute
+char253 "
+Tp 660,740,185,76,37,76 3 0376 thorn
+char254 "
+:y 580,769,185,144,-25,82 3 0377 ydieresis
+char255 "
diff --git a/gnu/usr.bin/groff/devps/AI b/gnu/usr.bin/groff/devps/AI
new file mode 100644
index 0000000..6868237
--- /dev/null
+++ b/gnu/usr.bin/groff/devps/AI
@@ -0,0 +1,559 @@
+name AI
+internalname AvantGarde-BookOblique
+slant 10.5
+spacewidth 277
+encoding text.enc
+ligatures fi fl 0
+kernpairs
+A y -62
+A w -65
+A v -70
+A u -20
+A ' -100
+A rq -100
+A Y -92
+A W -60
+A V -102
+A U -40
+A T -45
+A Q -40
+A O -50
+A G -40
+A C -40
+B A -10
+C A -40
+D . -20
+D , -20
+D Y -30
+D W -10
+D V -50
+D A -50
+F . -160
+F e -20
+F , -180
+F a -20
+F A -75
+G . -20
+G , -20
+G Y -20
+J . -15
+J a -20
+J A -30
+K o -15
+K e -20
+K O -20
+L y -23
+L ' -130
+L rq -130
+L Y -91
+L W -67
+L V -113
+L T -46
+O . -30
+O , -30
+O Y -30
+O X -30
+O W -20
+O V -60
+O T -30
+O A -60
+P . -300
+P o -60
+P e -20
+P , -280
+P a -20
+P A -114
+Q , 20
+R Y -10
+R W 10
+R V -10
+R T 6
+S , 20
+T y -50
+T w -55
+T u -46
+T ; -29
+T r -30
+T . -91
+T o -70
+T i 10
+T - -75
+T hy -75
+T char173 -75
+T e -49
+T , -82
+T : -15
+T a -90
+T O -30
+T A -45
+U . -20
+U , -20
+U A -40
+V u -40
+V ; -33
+V . -165
+V o -101
+V i -5
+V - -75
+V hy -75
+V char173 -75
+V e -101
+V , -145
+V : -18
+V a -104
+V O -60
+V G -20
+V A -102
+W y -2
+W u -30
+W ; -33
+W . -106
+W o -46
+W i 6
+W - -35
+W hy -35
+W char173 -35
+W e -47
+W , -106
+W : -15
+W a -50
+W O -20
+W A -58
+Y u -52
+Y ; -23
+Y . -175
+Y o -89
+Y - -85
+Y hy -85
+Y char173 -85
+Y e -89
+Y , -145
+Y : -10
+Y a -93
+Y O -30
+Y A -92
+a p 20
+a b 20
+b y -20
+b v -20
+c y -20
+c k -15
+, ' -120
+, rq -120
+e y -20
+e w -20
+e v -20
+f . -50
+f o -40
+f l -30
+f i -34
+f f -60
+f e -20
+f .i -34
+f , -50
+f a -40
+g a -15
+h y -30
+k y -5
+k e -15
+m y -20
+m u -20
+m a -20
+n y -15
+n v -20
+o y -20
+o x -15
+o w -20
+o v -30
+p y -20
+. ' -120
+. rq -120
+lq ` -35
+lq oq -35
+lq A -100
+` ` -203
+` oq -203
+oq ` -203
+oq oq -203
+` A -100
+oq A -100
+' v -30
+' t 10
+' s -15
+' r -20
+' ' -203
+' rq -35
+' d -110
+r y 40
+r v 40
+r u 20
+r t 20
+r s 20
+r q -8
+r . -73
+r p 20
+r o -20
+r n 21
+r m 28
+r l 20
+r k 20
+r i 20
+r - -60
+r hy -60
+r char173 -60
+r g -15
+r e -4
+r d -6
+r , -75
+r c -20
+r a -20
+s . 20
+s , 20
+v . -130
+v o -30
+v e -20
+v , -100
+v a -30
+w . -100
+w o -30
+w h 15
+w e -20
+w , -90
+w a -30
+y . -125
+y o -30
+y e -20
+y , -110
+y a -30
+charset
+ha 606,740,0,54,-60,54 2 0000 asciicircum
+ti 606,319,0,28,-64,28 0 0001 asciitilde
+vS 498,927,13,145,-7,81 2 0002 Scaron
+vZ 480,927,0,166,38,81 2 0003 Zcaron
+vs 388,764,13,170,1,81 2 0004 scaron
+vz 425,764,0,152,40,81 2 0005 zcaron
+:Y 592,928,0,187,-88,81 2 0006 Ydieresis
+tm 1000,740,0,3,-87,3 2 0007 trademark
+aq 198,740,0,129,-103,81 2 0010 quotesingle
+space 277 0 0040
+! 295,740,0,77,-61,77 2 0041 exclam
+" 309,740,0,151,-80,81 2 0042 quotedbl
+# 554,740,0,116,-21,81 2 0043 numbersign
+sh "
+$ 554,811,70,77,-57,77 2 0044 dollar
+Do "
+% 775,751,13,62,-74,62 2 0045 percent
+& 757,753,12,68,-42,68 2 0046 ampersand
+' 351,740,0,92,-145,81 2 0047 quoteright
+( 369,757,205,176,-39,81 3 0050 parenleft
+) 369,757,205,63,74,63 3 0051 parenright
+* 425,740,0,104,-120,81 2 0052 asterisk
++ 606,506,0,52,-42,52 0 0053 plus
+, 277,126,67,0,48 0 0054 comma
+- 332,315,0,78,-26,78 0 0055 hyphen
+hy "
+char173 "
+. 277,126,0,0,-52 0 0056 period
+/ 437,740,100,153,25,81 2 0057 slash
+sl "
+0 554,753,13,118,-21,81 2 0060 zero
+1 554,740,0,0,-210 2 0061 one
+2 554,753,0,111,10,81 2 0062 two
+3 554,753,13,61,-23,61 2 0063 three
+4 554,740,0,94,11,81 2 0064 four
+5 554,740,13,101,-19,81 2 0065 five
+6 554,739,13,76,-15,76 2 0066 six
+7 554,740,0,124,-60,81 2 0067 seven
+8 554,753,13,76,-27,76 2 0070 eight
+9 554,752,0,122,-61,81 2 0071 nine
+: 277,548,0,51,-52,51 0 0072 colon
+; 277,548,67,51,48,51 0 0073 semicolon
+< 606,514,8,93,-37,81 0 0074 less
+= 606,388,0,71,-23,71 0 0075 equal
+> 606,514,8,57,-1,57 0 0076 greater
+? 591,752,0,87,-108,81 2 0077 question
+@ 867,753,13,71,-76,71 2 0100 at
+at "
+A 740,740,0,39,38,39 2 0101 A
+B 574,740,0,82,-24,81 2 0102 B
+C 813,752,13,107,-55,81 2 0103 C
+D 744,740,0,79,-24,79 2 0104 D
+E 536,740,0,126,-20,81 2 0105 E
+F 485,740,0,146,-20,81 2 0106 F
+G 872,753,13,69,-53,69 2 0107 G
+H 683,740,0,111,-26,81 2 0110 H
+I 226,740,0,111,-26,81 2 0111 I
+J 482,740,13,107,13,81 2 0112 J
+K 591,740,0,187,-31,81 2 0113 K
+L 462,740,0,62,-32,62 2 0114 L
+M 919,740,0,111,-26,81 2 0115 M
+N 740,740,0,111,-25,81 2 0116 N
+O 869,753,13,82,-55,81 2 0117 O
+P 592,740,0,122,-25,81 2 0120 P
+Q 871,753,13,91,-52,81 2 0121 Q
+R 607,740,0,112,-20,81 2 0122 R
+S 498,753,13,113,-7,81 2 0123 S
+T 426,740,0,180,-81,81 2 0124 T
+U 655,740,13,111,-68,81 2 0125 U
+V 702,740,0,178,-95,81 2 0126 V
+W 960,740,0,177,-98,81 2 0127 W
+X 609,740,0,165,42,81 2 0130 X
+Y 592,740,0,187,-88,81 2 0131 Y
+Z 480,740,0,166,38,81 2 0132 Z
+[ 351,753,179,176,-95,81 2 0133 bracketleft
+lB "
+\ 605,740,100,0,-205 2 0134 backslash
+rs "
+] 351,753,179,11,69,11 2 0135 bracketright
+rB "
+a^ 502,764,0,94,-142,81 2 0136 circumflex
+^ "
+_ 500,0,125,36,73,36 0 0137 underscore
+` 351,740,0,57,-182,57 2 0140 quoteleft
+oq "
+a 683,561,13,89,-38,81 0 0141 a
+b 682,740,13,71,-18,71 2 0142 b
+c 647,561,13,81,-37,81 0 0143 c
+d 685,740,13,120,-35,81 2 0144 d
+e 650,561,13,64,-34,64 0 0145 e
+f 314,753,0,190,-54,81 2 0146 f
+g 673,561,215,84,-6,81 1 0147 g
+h 610,740,0,46,-12,46 2 0150 h
+i 200,740,0,122,-15,81 2 0151 i
+j 203,740,192,121,130,81 3 0152 j
+k 502,740,0,136,-20,81 2 0153 k
+l 200,740,0,122,-15,81 2 0154 l
+m 938,561,0,50,-16,50 0 0155 m
+n 610,561,0,49,-15,49 0 0156 n
+o 655,561,13,64,-38,64 0 0157 o
+p 682,561,192,67,22,67 1 0160 p
+q 682,561,192,85,-33,81 1 0161 q
+r 301,561,0,144,-15,81 0 0162 r
+s 388,561,13,86,1,81 0 0163 s
+t 339,740,0,142,-54,81 2 0164 t
+u 608,547,13,84,-50,81 0 0165 u
+v 554,547,0,143,-58,81 0 0166 v
+w 831,547,0,140,-64,81 0 0167 w
+x 480,547,0,139,38,81 0 0170 x
+y 536,547,192,138,-47,81 1 0171 y
+z 425,547,0,123,40,81 0 0172 z
+lC 351,740,189,167,-65,81 2 0173 braceleft
+{ "
+ba 672,740,100,0,-230 2 0174 bar
+| "
+rC 351,740,189,37,65,37 2 0175 braceright
+} "
+a~ 439,754,0,131,-129,81 2 0176 tilde
+~ "
+bq 354,126,68,0,-26 0 0200 quotesinglbase
+Fo 425,481,0,94,-42,81 0 0201 guillemotleft
+char171 "
+Fc 425,481,0,62,-10,62 0 0202 guillemotright
+char187 "
+bu 606,532,0,0,-167 0 0203 bullet
+Fn 554,818,153,165,89,81 2 0204 florin
+f/ 166,740,0,301,163,81 2 0205 fraction
+%0 1174,751,13,58,-78,58 2 0206 perthousand
+dg 553,740,133,90,-96,81 2 0207 dagger
+dd 553,740,133,90,-22,81 2 0210 daggerdbl
+en 500,315,0,73,-31,73 0 0211 endash
+em 1000,315,0,73,-31,73 0 0212 emdash
+fi 487,753,0,122,-54,81 2 0214 fi
+fl 485,753,0,122,-54,81 2 0215 fl
+.i 200,547,0,86,-15,81 0 0220 dotlessi
+ga 378,786,0,97,-154,81 2 0222 grave
+a" 552,800,0,92,-189,81 2 0223 hungarumlaut
+a. 222,765,0,118,-142,81 2 0224 dotaccent
+ab 453,754,0,138,-142,81 2 0225 breve
+ah 502,764,0,113,-160,81 2 0226 caron
+ao 332,807,0,119,-141,81 2 0227 ring
+ho 302,0,191,0,-3 1 0230 ogonek
+lq 502,740,0,55,-184,55 2 0231 quotedblleft
+rq 484,740,0,108,-147,81 2 0232 quotedblright
+oe 1137,561,13,73,-30,73 0 0233 oe
+/l 300,740,0,104,-45,81 2 0234 lslash
+Bq 502,126,68,0,-26 0 0235 quotedblbase
+OE 1194,753,13,135,-57,81 2 0236 OE
+/L 517,740,0,62,-57,62 2 0237 Lslash
+r! 295,548,192,41,-24,41 1 0241 exclamdown
+char161 "
+ct 554,707,0,92,-65,81 0 0242 cent
+char162 "
+Po 554,753,0,110,21,81 2 0243 sterling
+char163 "
+Cs 554,580,0,141,26,81 0 0244 currency
+char164 "
+Ye 554,740,0,183,-25,81 2 0245 yen
+char165 "
+bb 672,740,100,0,-230 2 0246 brokenbar
+char166 "
+sc 615,753,141,32,-68,32 2 0247 section
+char167 "
+ad 369,765,0,118,-141,81 2 0250 dieresis
+char168 "
+co 747,752,12,133,-3,81 2 0251 copyright
+char169 "
+Of 369,753,0,175,-52,81 2 0252 ordfeminine
+char170 "
+fo 251,481,0,94,-42,81 0 0253 guilsinglleft
+no 606,388,0,71,-60,71 0 0254 logicalnot
+char172 "
+\- 606,287,0,52,-42,52 0 0255 minus
+rg 747,752,12,133,-3,81 2 0256 registered
+char174 "
+a- 485,736,0,112,-147,81 0 0257 macron
+char175 "
+de 400,709,0,101,-108,81 0 0260 degree
+char176 "
+char177 606,518,24,62,3,62 0 0261 plusminus
+S2 332,747,0,151,-24,81 2 0262 twosuperior
+char178 "
+S3 332,747,0,126,-48,81 2 0263 threesuperior
+char179 "
+aa 375,786,0,119,-153,81 2 0264 acute
+char180 "
+char181 608,547,184,70,4,70 0 0265 mu
+ps 564,740,110,174,-69,81 2 0266 paragraph
+char182 "
+char183 277,316,0,8,-87,8 0 0267 periodcentered
+ac 324,0,222,0,-2 1 0270 cedilla
+char184 "
+S1 332,740,0,53,-140,53 2 0271 onesuperior
+char185 "
+Om 369,753,0,147,-66,81 2 0272 ordmasculine
+char186 "
+fc 251,481,0,62,-10,62 0 0273 guilsinglright
+14 831,740,0,0,-133 2 0274 onequarter
+char188 "
+12 831,740,0,29,-114,29 2 0275 onehalf
+char189 "
+34 831,747,0,44,-76,44 2 0276 threequarters
+char190 "
+r? 591,548,205,0,-14 1 0277 questiondown
+char191 "
+`A 740,949,0,39,38,39 2 0300 Agrave
+char192 "
+'A 740,949,0,39,38,39 2 0301 Aacute
+char193 "
+^A 740,927,0,39,38,39 2 0302 Acircumflex
+char194 "
+~A 740,917,0,39,38,39 2 0303 Atilde
+char195 "
+:A 740,928,0,39,38,39 2 0304 Adieresis
+char196 "
+oA 740,955,0,39,38,39 2 0305 Aring
+char197 "
+AE 992,740,0,102,70,81 2 0306 AE
+char198 "
+,C 813,752,222,107,-55,81 3 0307 Ccedilla
+char199 "
+`E 536,949,0,126,-20,81 2 0310 Egrave
+char200 "
+'E 536,949,0,126,-20,81 2 0311 Eacute
+char201 "
+^E 536,927,0,126,-20,81 2 0312 Ecircumflex
+char202 "
+:E 536,928,0,126,-20,81 2 0313 Edieresis
+char203 "
+`I 226,949,0,164,-26,81 2 0314 Igrave
+char204 "
+'I 226,949,0,264,-26,81 2 0315 Iacute
+char205 "
+^I 226,927,0,263,-26,81 2 0316 Icircumflex
+char206 "
+:I 226,928,0,220,-26,81 2 0317 Idieresis
+char207 "
+-D 790,740,0,73,-54,73 2 0320 Eth
+char208 "
+~N 740,917,0,111,-25,81 2 0321 Ntilde
+char209 "
+`O 869,949,13,82,-55,81 2 0322 Ograve
+char210 "
+'O 869,949,13,82,-55,81 2 0323 Oacute
+char211 "
+^O 869,927,13,82,-55,81 2 0324 Ocircumflex
+char212 "
+~O 869,917,13,82,-55,81 2 0325 Otilde
+char213 "
+:O 869,928,13,82,-55,81 2 0326 Odieresis
+char214 "
+char215 606,482,0,56,-37,56 0 0327 multiply
+/O 868,819,83,111,-26,81 2 0330 Oslash
+char216 "
+`U 655,949,13,111,-68,81 2 0331 Ugrave
+char217 "
+'U 655,949,13,111,-68,81 2 0332 Uacute
+char218 "
+^U 655,927,13,111,-68,81 2 0333 Ucircumflex
+char219 "
+:U 655,928,13,111,-68,81 2 0334 Udieresis
+char220 "
+'Y 592,949,0,187,-88,81 2 0335 Yacute
+char221 "
+TP 592,740,0,79,-10,79 2 0336 Thorn
+char222 "
+ss 554,753,13,74,-11,74 2 0337 germandbls
+char223 "
+`a 683,786,13,89,-38,81 2 0340 agrave
+char224 "
+'a 683,786,13,89,-38,81 2 0341 aacute
+char225 "
+^a 683,764,13,89,-38,81 2 0342 acircumflex
+char226 "
+~a 683,754,13,89,-38,81 2 0343 atilde
+char227 "
+:a 683,765,13,89,-38,81 2 0344 adieresis
+char228 "
+oa 683,807,13,89,-38,81 2 0345 aring
+char229 "
+ae 1157,561,13,62,-30,62 0 0346 ae
+char230 "
+,c 647,561,222,81,-37,81 1 0347 ccedilla
+char231 "
+`e 650,786,13,64,-34,64 2 0350 egrave
+char232 "
+'e 650,786,13,64,-34,64 2 0351 eacute
+char233 "
+^e 650,764,13,64,-34,64 2 0352 ecircumflex
+char234 "
+:e 650,765,13,64,-34,64 2 0353 edieresis
+char235 "
+`i 200,786,0,146,-15,81 2 0354 igrave
+char236 "
+'i 200,786,0,247,-15,81 2 0355 iacute
+char237 "
+^i 200,764,0,245,9,81 2 0356 icircumflex
+char238 "
+:i 200,765,0,203,-15,81 2 0357 idieresis
+char239 "
+Sd 655,753,12,70,-38,70 2 0360 eth
+char240 "
+~n 610,754,0,49,-15,49 2 0361 ntilde
+char241 "
+`o 655,786,13,64,-38,64 2 0362 ograve
+char242 "
+'o 655,786,13,64,-38,64 2 0363 oacute
+char243 "
+^o 655,764,13,64,-38,64 2 0364 ocircumflex
+char244 "
+~o 655,754,13,64,-38,64 2 0365 otilde
+char245 "
+:o 655,765,13,64,-38,64 2 0366 odieresis
+char246 "
+char247 606,519,13,52,-42,52 0 0367 divide
+/o 653,614,64,100,-1,81 0 0370 oslash
+char248 "
+`u 608,786,13,84,-50,81 2 0371 ugrave
+char249 "
+'u 608,786,13,84,-50,81 2 0372 uacute
+char250 "
+^u 608,764,13,84,-50,81 2 0373 ucircumflex
+char251 "
+:u 608,765,13,84,-50,81 2 0374 udieresis
+char252 "
+'y 536,786,192,138,-47,81 3 0375 yacute
+char253 "
+Tp 682,740,192,67,22,67 3 0376 thorn
+char254 "
+:y 536,765,192,138,-47,81 3 0377 ydieresis
+char255 "
diff --git a/gnu/usr.bin/groff/devps/AR b/gnu/usr.bin/groff/devps/AR
new file mode 100644
index 0000000..00fd632
--- /dev/null
+++ b/gnu/usr.bin/groff/devps/AR
@@ -0,0 +1,558 @@
+name AR
+internalname AvantGarde-Book
+spacewidth 277
+encoding text.enc
+ligatures fi fl 0
+kernpairs
+A y -62
+A w -65
+A v -70
+A u -20
+A ' -100
+A rq -100
+A Y -92
+A W -60
+A V -102
+A U -40
+A T -45
+A Q -40
+A O -50
+A G -40
+A C -40
+B A -10
+C A -40
+D . -20
+D , -20
+D Y -30
+D W -10
+D V -50
+D A -50
+F . -160
+F e -20
+F , -180
+F a -20
+F A -75
+G . -20
+G , -20
+G Y -20
+J . -15
+J a -20
+J A -30
+K o -15
+K e -20
+K O -20
+L y -23
+L ' -130
+L rq -130
+L Y -91
+L W -67
+L V -113
+L T -46
+O . -30
+O , -30
+O Y -30
+O X -30
+O W -20
+O V -60
+O T -30
+O A -60
+P . -300
+P o -60
+P e -20
+P , -280
+P a -20
+P A -114
+Q , 20
+R Y -10
+R W 10
+R V -10
+R T 6
+S , 20
+T y -50
+T w -55
+T u -46
+T ; -29
+T r -30
+T . -91
+T o -70
+T i 10
+T - -75
+T hy -75
+T char173 -75
+T e -49
+T , -82
+T : -15
+T a -90
+T O -30
+T A -45
+U . -20
+U , -20
+U A -40
+V u -40
+V ; -33
+V . -165
+V o -101
+V i -5
+V - -75
+V hy -75
+V char173 -75
+V e -101
+V , -145
+V : -18
+V a -104
+V O -60
+V G -20
+V A -102
+W y -2
+W u -30
+W ; -33
+W . -106
+W o -46
+W i 6
+W - -35
+W hy -35
+W char173 -35
+W e -47
+W , -106
+W : -15
+W a -50
+W O -20
+W A -58
+Y u -52
+Y ; -23
+Y . -175
+Y o -89
+Y - -85
+Y hy -85
+Y char173 -85
+Y e -89
+Y , -145
+Y : -10
+Y a -93
+Y O -30
+Y A -92
+a p 20
+a b 20
+b y -20
+b v -20
+c y -20
+c k -15
+, ' -120
+, rq -120
+e y -20
+e w -20
+e v -20
+f . -50
+f o -40
+f l -30
+f i -34
+f f -60
+f e -20
+f .i -34
+f , -50
+f a -40
+g a -15
+h y -30
+k y -5
+k e -15
+m y -20
+m u -20
+m a -20
+n y -15
+n v -20
+o y -20
+o x -15
+o w -20
+o v -30
+p y -20
+. ' -120
+. rq -120
+lq ` -35
+lq oq -35
+lq A -100
+` ` -203
+` oq -203
+oq ` -203
+oq oq -203
+` A -100
+oq A -100
+' v -30
+' t 10
+' s -15
+' r -20
+' ' -203
+' rq -35
+' d -110
+r y 40
+r v 40
+r u 20
+r t 20
+r s 20
+r q -8
+r . -73
+r p 20
+r o -20
+r n 21
+r m 28
+r l 20
+r k 20
+r i 20
+r - -60
+r hy -60
+r char173 -60
+r g -15
+r e -4
+r d -6
+r , -75
+r c -20
+r a -20
+s . 20
+s , 20
+v . -130
+v o -30
+v e -20
+v , -100
+v a -30
+w . -100
+w o -30
+w h 15
+w e -20
+w , -90
+w a -30
+y . -125
+y o -30
+y e -20
+y , -110
+y a -30
+charset
+ha 606,740 2 0000 asciicircum
+ti 606,319 0 0001 asciitilde
+vS 498,927,13 2 0002 Scaron
+vZ 480,927 2 0003 Zcaron
+vs 388,764,13 2 0004 scaron
+vz 425,764 2 0005 zcaron
+:Y 592,928 2 0006 Ydieresis
+tm 1000,740 2 0007 trademark
+aq 198,740 2 0010 quotesingle
+space 277 0 0040
+! 295,740 2 0041 exclam
+" 309,740 2 0042 quotedbl
+# 554,740 2 0043 numbersign
+sh "
+$ 554,811,70 2 0044 dollar
+Do "
+% 775,751,13 2 0045 percent
+& 757,753,12 2 0046 ampersand
+' 351,740 2 0047 quoteright
+( 369,757,205 3 0050 parenleft
+) 369,757,205 3 0051 parenright
+* 425,740 2 0052 asterisk
++ 606,506 0 0053 plus
+, 277,126,67 0 0054 comma
+- 332,315 0 0055 hyphen
+hy "
+char173 "
+. 277,126 0 0056 period
+/ 437,740,100 2 0057 slash
+sl "
+0 554,753,13 2 0060 zero
+1 554,740 2 0061 one
+2 554,753 2 0062 two
+3 554,753,13 2 0063 three
+4 554,740 2 0064 four
+5 554,740,13 2 0065 five
+6 554,739,13 2 0066 six
+7 554,740 2 0067 seven
+8 554,753,13 2 0070 eight
+9 554,752 2 0071 nine
+: 277,548 0 0072 colon
+; 277,548,67 0 0073 semicolon
+< 606,514,8 0 0074 less
+= 606,388 0 0075 equal
+> 606,514,8 0 0076 greater
+? 591,752 2 0077 question
+@ 867,753,13 2 0100 at
+at "
+A 740,740 2 0101 A
+B 574,740 2 0102 B
+C 813,752,13 2 0103 C
+D 744,740 2 0104 D
+E 536,740 2 0105 E
+F 485,740 2 0106 F
+G 872,753,13 2 0107 G
+H 683,740 2 0110 H
+I 226,740 2 0111 I
+J 482,740,13 2 0112 J
+K 591,740 2 0113 K
+L 462,740 2 0114 L
+M 919,740 2 0115 M
+N 740,740 2 0116 N
+O 869,753,13 2 0117 O
+P 592,740 2 0120 P
+Q 871,753,13 2 0121 Q
+R 607,740 2 0122 R
+S 498,753,13 2 0123 S
+T 426,740 2 0124 T
+U 655,740,13 2 0125 U
+V 702,740 2 0126 V
+W 960,740 2 0127 W
+X 609,740 2 0130 X
+Y 592,740 2 0131 Y
+Z 480,740 2 0132 Z
+[ 351,753,179 2 0133 bracketleft
+lB "
+\ 605,740,100 2 0134 backslash
+rs "
+] 351,753,179 2 0135 bracketright
+rB "
+a^ 502,764 2 0136 circumflex
+^ "
+_ 500,0,125 0 0137 underscore
+` 351,740 2 0140 quoteleft
+oq "
+a 683,561,13 0 0141 a
+b 682,740,13 2 0142 b
+c 647,561,13 0 0143 c
+d 685,740,13 2 0144 d
+e 650,561,13 0 0145 e
+f 314,753 2 0146 f
+g 673,561,215 1 0147 g
+h 610,740 2 0150 h
+i 200,740 2 0151 i
+j 203,740,192 3 0152 j
+k 502,740 2 0153 k
+l 200,740 2 0154 l
+m 938,561 0 0155 m
+n 610,561 0 0156 n
+o 655,561,13 0 0157 o
+p 682,561,192 1 0160 p
+q 682,561,192 1 0161 q
+r 301,561 0 0162 r
+s 388,561,13 0 0163 s
+t 339,740 2 0164 t
+u 608,547,13 0 0165 u
+v 554,547 0 0166 v
+w 831,547 0 0167 w
+x 480,547 0 0170 x
+y 536,547,192 1 0171 y
+z 425,547 0 0172 z
+lC 351,740,189 2 0173 braceleft
+{ "
+ba 672,740,100 2 0174 bar
+| "
+rC 351,740,189 2 0175 braceright
+} "
+a~ 439,754 2 0176 tilde
+~ "
+bq 354,126,68 0 0200 quotesinglbase
+Fo 425,481 0 0201 guillemotleft
+char171 "
+Fc 425,481 0 0202 guillemotright
+char187 "
+bu 606,532 0 0203 bullet
+Fn 554,818,153 2 0204 florin
+f/ 166,740 2 0205 fraction
+%0 1174,751,13 2 0206 perthousand
+dg 553,740,133 2 0207 dagger
+dd 553,740,133 2 0210 daggerdbl
+en 500,315 0 0211 endash
+em 1000,315 0 0212 emdash
+fi 487,753 2 0214 fi
+fl 485,753 2 0215 fl
+.i 200,547 0 0220 dotlessi
+ga 378,786 2 0222 grave
+a" 552,800 2 0223 hungarumlaut
+a. 222,765 2 0224 dotaccent
+ab 453,754 2 0225 breve
+ah 502,764 2 0226 caron
+ao 332,807 2 0227 ring
+ho 302,0,191 1 0230 ogonek
+lq 502,740 2 0231 quotedblleft
+rq 484,740 2 0232 quotedblright
+oe 1137,561,13 0 0233 oe
+/l 300,740 2 0234 lslash
+Bq 502,126,68 0 0235 quotedblbase
+OE 1194,753,13 2 0236 OE
+/L 517,740 2 0237 Lslash
+r! 295,548,192 1 0241 exclamdown
+char161 "
+ct 554,707 0 0242 cent
+char162 "
+Po 554,753 2 0243 sterling
+char163 "
+Cs 554,580 0 0244 currency
+char164 "
+Ye 554,740 2 0245 yen
+char165 "
+bb 672,740,100 2 0246 brokenbar
+char166 "
+sc 615,753,141 2 0247 section
+char167 "
+ad 369,765 2 0250 dieresis
+char168 "
+co 747,752,12 2 0251 copyright
+char169 "
+Of 369,753 2 0252 ordfeminine
+char170 "
+fo 251,481 0 0253 guilsinglleft
+no 606,388 0 0254 logicalnot
+char172 "
+\- 606,287 0 0255 minus
+rg 747,752,12 2 0256 registered
+char174 "
+a- 485,736 0 0257 macron
+char175 "
+de 400,709 0 0260 degree
+char176 "
+char177 606,518,24 0 0261 plusminus
+S2 332,747 2 0262 twosuperior
+char178 "
+S3 332,747 2 0263 threesuperior
+char179 "
+aa 375,786 2 0264 acute
+char180 "
+char181 608,547,184 0 0265 mu
+ps 564,740,110 2 0266 paragraph
+char182 "
+char183 277,316 0 0267 periodcentered
+ac 324,0,222 1 0270 cedilla
+char184 "
+S1 332,740 2 0271 onesuperior
+char185 "
+Om 369,753 2 0272 ordmasculine
+char186 "
+fc 251,481 0 0273 guilsinglright
+14 831,740 2 0274 onequarter
+char188 "
+12 831,740 2 0275 onehalf
+char189 "
+34 831,747 2 0276 threequarters
+char190 "
+r? 591,548,205 1 0277 questiondown
+char191 "
+`A 740,949 2 0300 Agrave
+char192 "
+'A 740,949 2 0301 Aacute
+char193 "
+^A 740,927 2 0302 Acircumflex
+char194 "
+~A 740,917 2 0303 Atilde
+char195 "
+:A 740,928 2 0304 Adieresis
+char196 "
+oA 740,955 2 0305 Aring
+char197 "
+AE 992,740 2 0306 AE
+char198 "
+,C 813,752,222 3 0307 Ccedilla
+char199 "
+`E 536,949 2 0310 Egrave
+char200 "
+'E 536,949 2 0311 Eacute
+char201 "
+^E 536,927 2 0312 Ecircumflex
+char202 "
+:E 536,928 2 0313 Edieresis
+char203 "
+`I 226,949 2 0314 Igrave
+char204 "
+'I 226,949 2 0315 Iacute
+char205 "
+^I 226,927 2 0316 Icircumflex
+char206 "
+:I 226,928 2 0317 Idieresis
+char207 "
+-D 790,740 2 0320 Eth
+char208 "
+~N 740,917 2 0321 Ntilde
+char209 "
+`O 869,949,13 2 0322 Ograve
+char210 "
+'O 869,949,13 2 0323 Oacute
+char211 "
+^O 869,927,13 2 0324 Ocircumflex
+char212 "
+~O 869,917,13 2 0325 Otilde
+char213 "
+:O 869,928,13 2 0326 Odieresis
+char214 "
+char215 606,482 0 0327 multiply
+/O 868,819,83 2 0330 Oslash
+char216 "
+`U 655,949,13 2 0331 Ugrave
+char217 "
+'U 655,949,13 2 0332 Uacute
+char218 "
+^U 655,927,13 2 0333 Ucircumflex
+char219 "
+:U 655,928,13 2 0334 Udieresis
+char220 "
+'Y 592,949 2 0335 Yacute
+char221 "
+TP 592,740 2 0336 Thorn
+char222 "
+ss 554,753,13 2 0337 germandbls
+char223 "
+`a 683,786,13 2 0340 agrave
+char224 "
+'a 683,786,13 2 0341 aacute
+char225 "
+^a 683,764,13 2 0342 acircumflex
+char226 "
+~a 683,754,13 2 0343 atilde
+char227 "
+:a 683,765,13 2 0344 adieresis
+char228 "
+oa 683,807,13 2 0345 aring
+char229 "
+ae 1157,561,13 0 0346 ae
+char230 "
+,c 647,561,222 1 0347 ccedilla
+char231 "
+`e 650,786,13 2 0350 egrave
+char232 "
+'e 650,786,13 2 0351 eacute
+char233 "
+^e 650,764,13 2 0352 ecircumflex
+char234 "
+:e 650,765,13 2 0353 edieresis
+char235 "
+`i 200,786 2 0354 igrave
+char236 "
+'i 200,786 2 0355 iacute
+char237 "
+^i 200,764 2 0356 icircumflex
+char238 "
+:i 200,765 2 0357 idieresis
+char239 "
+Sd 655,753,12 2 0360 eth
+char240 "
+~n 610,754 2 0361 ntilde
+char241 "
+`o 655,786,13 2 0362 ograve
+char242 "
+'o 655,786,13 2 0363 oacute
+char243 "
+^o 655,764,13 2 0364 ocircumflex
+char244 "
+~o 655,754,13 2 0365 otilde
+char245 "
+:o 655,765,13 2 0366 odieresis
+char246 "
+char247 606,519,13 0 0367 divide
+/o 653,614,64 0 0370 oslash
+char248 "
+`u 608,786,13 2 0371 ugrave
+char249 "
+'u 608,786,13 2 0372 uacute
+char250 "
+^u 608,764,13 2 0373 ucircumflex
+char251 "
+:u 608,765,13 2 0374 udieresis
+char252 "
+'y 536,786,192 3 0375 yacute
+char253 "
+Tp 682,740,192 3 0376 thorn
+char254 "
+:y 536,765,192 3 0377 ydieresis
+char255 "
diff --git a/gnu/usr.bin/groff/devps/BMB b/gnu/usr.bin/groff/devps/BMB
new file mode 100644
index 0000000..270f7db
--- /dev/null
+++ b/gnu/usr.bin/groff/devps/BMB
@@ -0,0 +1,438 @@
+name BMB
+internalname Bookman-Demi
+spacewidth 340
+encoding text.enc
+ligatures fi fl 0
+kernpairs
+A y -1
+A w -9
+A v -8
+A Y -52
+A W -20
+A V -68
+A T -40
+F . -132
+F , -130
+F A -59
+L y 19
+L Y -35
+L W -41
+L V -50
+L T -4
+P . -128
+P , -129
+P A -46
+R y -8
+R Y -20
+R W -24
+R V -29
+R T -4
+T ; 5
+T s -10
+T r 27
+T . -122
+T o -28
+T i 27
+T - -10
+T hy -10
+T char173 -10
+T e -29
+T , -122
+T : 7
+T c -29
+T a -24
+T A -42
+V y 12
+V u -11
+V ; -38
+V r -15
+V . -105
+V o -79
+V i 15
+V - -10
+V hy -10
+V char173 -10
+V e -80
+V , -103
+V : -37
+V a -74
+V A -88
+W y 12
+W u -11
+W ; -38
+W r -15
+W . -105
+W o -78
+W i 15
+W - -10
+W hy -10
+W char173 -10
+W e -79
+W , -103
+W : -37
+W a -73
+W A -60
+Y v 24
+Y u -13
+Y ; -34
+Y q -66
+Y . -105
+Y p -23
+Y o -66
+Y i 2
+Y - -10
+Y hy -10
+Y char173 -10
+Y e -67
+Y , -103
+Y : -32
+Y a -60
+Y A -56
+f f 21
+r q -9
+r . -102
+r o -9
+r n 20
+r m 20
+r - -10
+r hy -10
+r char173 -10
+r h -23
+r g -9
+r f 20
+r e -10
+r d -10
+r , -101
+r c -9
+charset
+ha 600,681 2 0000 asciicircum
+ti 600,368 0 0001 asciitilde
+vS 660,896,17 2 0002 Scaron
+vZ 640,896 2 0003 Zcaron
+vs 520,717,8 2 0004 scaron
+vz 560,717 2 0005 zcaron
+:Y 700,877 2 0006 Ydieresis
+tm 980,681 2 0007 trademark
+aq 240,698 2 0010 quotesingle
+space 340 0 0040
+! 360,698,8 2 0041 exclam
+" 420,698 2 0042 quotedbl
+# 660,681 2 0043 numbersign
+sh "
+$ 660,805,119 2 0044 dollar
+Do "
+% 940,698,8 2 0045 percent
+& 800,698,17 2 0046 ampersand
+' 320,698 2 0047 quoteright
+( 320,749,150 2 0050 parenleft
+) 320,749,150 2 0051 parenright
+* 460,697 2 0052 asterisk
++ 600,514 0 0053 plus
+, 340,162,124 0 0054 comma
+- 360,318 0 0055 hyphen
+hy "
+char173 "
+. 340,172,8 0 0056 period
+/ 600,725,149 2 0057 slash
+sl "
+0 660,698,17 2 0060 zero
+1 660,681 2 0061 one
+2 660,698 2 0062 two
+3 660,698,17 2 0063 three
+4 660,681 2 0064 four
+5 660,723,17 2 0065 five
+6 660,698,17 2 0066 six
+7 660,681 2 0067 seven
+8 660,698,17 2 0070 eight
+9 660,698,17 2 0071 nine
+: 340,515,8 0 0072 colon
+; 340,515,124 0 0073 semicolon
+< 600,542,9 0 0074 less
+= 600,421 0 0075 equal
+> 600,542,9 0 0076 greater
+? 660,698,8 2 0077 question
+@ 820,698,17 2 0100 at
+at "
+A 720,681 2 0101 A
+B 720,681 2 0102 B
+C 740,698,17 2 0103 C
+D 780,681 2 0104 D
+E 720,681 2 0105 E
+F 680,681 2 0106 F
+G 780,698,17 2 0107 G
+H 820,681 2 0110 H
+I 400,681 2 0111 I
+J 640,681,17 2 0112 J
+K 800,681 2 0113 K
+L 640,681 2 0114 L
+M 940,681 2 0115 M
+N 740,681 2 0116 N
+O 800,698,17 2 0117 O
+P 660,681 2 0120 P
+Q 800,698,226 3 0121 Q
+R 780,681 2 0122 R
+S 660,698,17 2 0123 S
+T 700,681 2 0124 T
+U 740,681,17 2 0125 U
+V 720,681 2 0126 V
+W 940,681 2 0127 W
+X 780,681 2 0130 X
+Y 700,681 2 0131 Y
+Z 640,681 2 0132 Z
+[ 300,725,138 2 0133 bracketleft
+lB "
+\ 600,725 2 0134 backslash
+rs "
+] 300,725,138 2 0135 bracketright
+rB "
+a^ 500,731 2 0136 circumflex
+^ "
+_ 500,0,155 0 0137 underscore
+` 320,698 2 0140 quoteleft
+oq "
+a 580,515,8 0 0141 a
+b 600,725,8 2 0142 b
+c 580,515,8 0 0143 c
+d 640,725,8 2 0144 d
+e 580,515,8 0 0145 e
+f 380,741 2 0146 f
+g 580,595,243 1 0147 g
+h 680,725 2 0150 h
+i 360,729 2 0151 i
+j 340,729,221 3 0152 j
+k 660,725 2 0153 k
+l 340,725 2 0154 l
+m 1000,515 0 0155 m
+n 680,515 0 0156 n
+o 620,515,8 0 0157 o
+p 640,515,212 1 0160 p
+q 620,515,212 1 0161 q
+r 460,502 0 0162 r
+s 520,515,8 0 0163 s
+t 460,660,8 2 0164 t
+u 660,502,8 0 0165 u
+v 600,502 0 0166 v
+w 800,502 0 0167 w
+x 600,502 0 0170 x
+y 620,502,221 1 0171 y
+z 560,502 0 0172 z
+lC 320,726,139 2 0173 braceleft
+{ "
+ba 600,725 2 0174 bar
+| "
+rC 320,726,139 2 0175 braceright
+} "
+a~ 480,691 2 0176 tilde
+~ "
+bq 320,144,114 0 0200 quotesinglbase
+Fo 400,457 0 0201 guillemotleft
+char171 "
+Fc 400,457 0 0202 guillemotright
+char187 "
+bu 460,511 0 0203 bullet
+Fn 660,749,209 2 0204 florin
+f/ 120,681 2 0205 fraction
+%0 1360,698,8 2 0206 perthousand
+dg 440,698,156 2 0207 dagger
+dd 380,698,156 2 0210 daggerdbl
+en 500,318 0 0211 endash
+em 1000,318 0 0212 emdash
+fi 740,741 2 0214 fi
+fl 740,741 2 0215 fl
+.i 360,502 0 0220 dotlessi
+ga 400,730 2 0222 grave
+a" 440,741 2 0223 hungarumlaut
+a. 320,730 2 0224 dotaccent
+ab 500,722 2 0225 breve
+ah 500,717 2 0226 caron
+ao 340,755 2 0227 ring
+ho 320,0,163 0 0230 ogonek
+lq 540,698 2 0231 quotedblleft
+rq 540,698 2 0232 quotedblright
+oe 940,515,8 0 0233 oe
+/l 340,725 2 0234 lslash
+Bq 540,144,114 0 0235 quotedblbase
+OE 1220,698,17 2 0236 OE
+/L 640,681 2 0237 Lslash
+r! 360,515,191 0 0241 exclamdown
+char161 "
+ct 660,674 2 0242 cent
+char162 "
+Po 660,698,17 2 0243 sterling
+char163 "
+Cs 660,593 0 0244 currency
+char164 "
+Ye 660,681 2 0245 yen
+char165 "
+bb 600,725 2 0246 brokenbar
+char166 "
+sc 600,698,153 2 0247 section
+char167 "
+ad 500,698 2 0250 dieresis
+char168 "
+co 740,698,17 2 0251 copyright
+char169 "
+Of 400,698 2 0252 ordfeminine
+char170 "
+fo 220,457 0 0253 guilsinglleft
+no 600,421 0 0254 logicalnot
+char172 "
+\- 600,323 0 0255 minus
+rg 740,698,17 2 0256 registered
+char174 "
+a- 460,663 2 0257 macron
+char175 "
+de 400,698 2 0260 degree
+char176 "
+char177 600,514 0 0261 plusminus
+S2 396,698 2 0262 twosuperior
+char178 "
+S3 396,698 2 0263 threesuperior
+char179 "
+aa 400,731 2 0264 acute
+char180 "
+char181 660,502,221 1 0265 mu
+ps 800,681,101 2 0266 paragraph
+char182 "
+char183 340,355 0 0267 periodcentered
+ac 360,0,213 1 0270 cedilla
+char184 "
+S1 396,687 2 0271 onesuperior
+char185 "
+Om 400,698 2 0272 ordmasculine
+char186 "
+fc 220,457 0 0273 guilsinglright
+14 990,681 2 0274 onequarter
+char188 "
+12 990,681 2 0275 onehalf
+char189 "
+34 990,692 2 0276 threequarters
+char190 "
+r? 660,515,191 0 0277 questiondown
+char191 "
+`A 720,909 2 0300 Agrave
+char192 "
+'A 720,910 2 0301 Aacute
+char193 "
+^A 720,910 2 0302 Acircumflex
+char194 "
+~A 720,870 2 0303 Atilde
+char195 "
+:A 720,877 2 0304 Adieresis
+char196 "
+oA 720,934 2 0305 Aring
+char197 "
+AE 1140,681 2 0306 AE
+char198 "
+,C 740,698,213 3 0307 Ccedilla
+char199 "
+`E 720,909 2 0310 Egrave
+char200 "
+'E 720,910 2 0311 Eacute
+char201 "
+^E 720,910 2 0312 Ecircumflex
+char202 "
+:E 720,877 2 0313 Edieresis
+char203 "
+`I 400,909 2 0314 Igrave
+char204 "
+'I 400,910 2 0315 Iacute
+char205 "
+^I 400,910 2 0316 Icircumflex
+char206 "
+:I 400,877 2 0317 Idieresis
+char207 "
+-D 780,681 2 0320 Eth
+char208 "
+~N 740,870 2 0321 Ntilde
+char209 "
+`O 800,909,17 2 0322 Ograve
+char210 "
+'O 800,910,17 2 0323 Oacute
+char211 "
+^O 800,910,17 2 0324 Ocircumflex
+char212 "
+~O 800,870,17 2 0325 Otilde
+char213 "
+:O 800,877,17 2 0326 Odieresis
+char214 "
+char215 600,514 0 0327 multiply
+/O 800,781,110 2 0330 Oslash
+char216 "
+`U 740,909,17 2 0331 Ugrave
+char217 "
+'U 740,910,17 2 0332 Uacute
+char218 "
+^U 740,910,17 2 0333 Ucircumflex
+char219 "
+:U 740,877,17 2 0334 Udieresis
+char220 "
+'Y 700,910 2 0335 Yacute
+char221 "
+TP 660,681 2 0336 Thorn
+char222 "
+ss 660,699,91 2 0337 germandbls
+char223 "
+`a 580,730,8 2 0340 agrave
+char224 "
+'a 580,731,8 2 0341 aacute
+char225 "
+^a 580,731,8 2 0342 acircumflex
+char226 "
+~a 580,691,8 2 0343 atilde
+char227 "
+:a 580,698,8 2 0344 adieresis
+char228 "
+oa 580,755,8 2 0345 aring
+char229 "
+ae 880,515,8 0 0346 ae
+char230 "
+,c 580,515,213 1 0347 ccedilla
+char231 "
+`e 580,730,8 2 0350 egrave
+char232 "
+'e 580,731,8 2 0351 eacute
+char233 "
+^e 580,731,8 2 0352 ecircumflex
+char234 "
+:e 580,698,8 2 0353 edieresis
+char235 "
+`i 360,730 2 0354 igrave
+char236 "
+'i 360,731 2 0355 iacute
+char237 "
+^i 360,731 2 0356 icircumflex
+char238 "
+:i 360,698 2 0357 idieresis
+char239 "
+Sd 620,741,8 2 0360 eth
+char240 "
+~n 680,691 2 0361 ntilde
+char241 "
+`o 620,730,8 2 0362 ograve
+char242 "
+'o 620,731,8 2 0363 oacute
+char243 "
+^o 620,731,8 2 0364 ocircumflex
+char244 "
+~o 620,691,8 2 0365 otilde
+char245 "
+:o 620,698,8 2 0366 odieresis
+char246 "
+char247 600,521 0 0367 divide
+/o 620,551,40 0 0370 oslash
+char248 "
+`u 660,730,8 2 0371 ugrave
+char249 "
+'u 660,731,8 2 0372 uacute
+char250 "
+^u 660,731,8 2 0373 ucircumflex
+char251 "
+:u 660,698,8 2 0374 udieresis
+char252 "
+'y 620,731,221 3 0375 yacute
+char253 "
+Tp 640,725,212 3 0376 thorn
+char254 "
+:y 620,698,221 3 0377 ydieresis
+char255 "
diff --git a/gnu/usr.bin/groff/devps/BMBI b/gnu/usr.bin/groff/devps/BMBI
new file mode 100644
index 0000000..0670451
--- /dev/null
+++ b/gnu/usr.bin/groff/devps/BMBI
@@ -0,0 +1,441 @@
+name BMBI
+internalname Bookman-DemiItalic
+slant 10
+spacewidth 340
+encoding text.enc
+ligatures fi fl 0
+kernpairs
+A y 20
+A w 20
+A v 20
+A Y -25
+A W -35
+A V -40
+A T -17
+F . -105
+F , -98
+F A -35
+L y 62
+L Y -5
+L W -15
+L V -19
+L T -26
+P . -105
+P , -98
+P A -31
+R y 27
+R Y 4
+R W -4
+R V -8
+R T -3
+T y 56
+T w 69
+T u 42
+T ; 31
+T s -1
+T r 41
+T . -107
+T o -5
+T i 42
+T - -20
+T hy -20
+T char173 -20
+T e -10
+T , -100
+T : 26
+T c -8
+T a -8
+T A -42
+V y 17
+V u -1
+V ; -22
+V r 2
+V . -115
+V o -50
+V i 32
+V - -20
+V hy -20
+V char173 -20
+V e -50
+V , -137
+V : -28
+V a -50
+V A -50
+W y -51
+W u -69
+W ; -81
+W r -66
+W . -183
+W o -100
+W i -36
+W - -22
+W hy -22
+W char173 -22
+W e -100
+W , -201
+W : -86
+W a -100
+W A -77
+Y v 26
+Y u -1
+Y ; -4
+Y q -43
+Y . -113
+Y o -41
+Y i 20
+Y - -20
+Y hy -20
+Y char173 -20
+Y e -46
+Y , -106
+Y : -9
+Y a -45
+Y A -30
+f f 10
+r q -3
+r . -120
+r o -1
+r n 39
+r m 39
+r - -20
+r hy -20
+r char173 -20
+r h -35
+r g -23
+r f 42
+r e -6
+r d -3
+r , -113
+r c -5
+charset
+ha 620,681,0,24,-42,24 2 0000 asciicircum
+ti 620,368,0,35,-51,35 0 0001 asciitilde
+vS 700,915,17,81,-9,73 2 0002 Scaron
+vZ 680,915,0,110,27,73 2 0003 Zcaron
+vs 540,749,8,83,18,73 2 0004 scaron
+vz 560,749,8,76,14,73 2 0005 zcaron
+:Y 660,900,0,207,-22,73 2 0006 Ydieresis
+tm 940,681,0,92,8,73 2 0007 trademark
+aq 180,696,0,165,-76,73 2 0010 quotesingle
+space 340 0 0040
+! 320,698,8,96,-36,73 2 0041 exclam
+" 380,697,0,177,-90,73 2 0042 quotedbl
+# 680,681,0,19,-107,19 2 0043 numbersign
+sh "
+$ 680,790,164,67,5,67 2 0044 dollar
+Do "
+% 880,698,17,69,-56,69 2 0045 percent
+& 980,698,17,86,2,73 2 0046 ampersand
+' 320,698,0,79,-121,73 2 0047 quoteright
+( 260,741,134,178,19,73 2 0050 parenleft
+) 260,741,134,112,85,73 2 0051 parenright
+* 460,698,0,98,-76,73 2 0052 asterisk
++ 600,514,0,45,-41,45 0 0053 plus
+, 340,185,124,8,-50,8 0 0054 comma
+- 280,313,0,89,-9,73 0 0055 hyphen
+hy "
+char173 "
+. 340,177,8,6,-56,6 0 0056 period
+/ 360,742,106,192,41,73 2 0057 slash
+sl "
+0 680,698,17,73,-37,73 2 0060 zero
+1 680,681,0,0,-73 2 0061 one
+2 680,698,0,44,-17,44 2 0062 two
+3 680,698,17,53,-22,53 2 0063 three
+4 680,681,0,78,-13,73 2 0064 four
+5 680,681,17,39,-28,39 2 0065 five
+6 680,698,17,74,-38,73 2 0066 six
+7 680,681,0,109,-73,73 2 0067 seven
+8 680,698,17,56,-18,56 2 0070 eight
+9 680,698,17,82,-21,73 2 0071 nine
+: 340,515,8,66,-56,66 0 0072 colon
+; 340,515,124,62,-50,62 0 0073 semicolon
+< 620,540,9,18,-29,18 0 0074 less
+= 600,421,0,45,-41,45 0 0075 equal
+> 620,540,9,28,-39,28 0 0076 greater
+? 620,698,8,98,-95,73 2 0077 question
+@ 780,698,17,60,-30,60 2 0100 at
+at "
+A 720,681,0,99,77,73 2 0101 A
+B 720,681,0,92,36,73 2 0102 B
+C 700,698,17,104,-28,73 2 0103 C
+D 760,681,0,95,36,73 2 0104 D
+E 720,681,0,107,36,73 2 0105 E
+F 660,681,0,153,36,73 2 0106 F
+G 760,698,17,118,-27,73 2 0107 G
+H 800,681,0,160,36,73 2 0110 H
+I 380,681,0,155,36,73 2 0111 I
+J 620,681,17,151,42,73 2 0112 J
+K 780,681,0,149,36,73 2 0113 K
+L 640,681,0,135,36,73 2 0114 L
+M 860,681,0,160,36,73 2 0115 M
+N 740,681,0,155,36,73 2 0116 N
+O 760,698,17,96,-28,73 2 0117 O
+P 640,681,0,134,56,73 2 0120 P
+Q 760,698,213,95,13,73 3 0121 Q
+R 740,681,0,75,36,73 2 0122 R
+S 700,698,17,81,-9,73 2 0123 S
+T 700,681,0,152,-20,73 2 0124 T
+U 740,681,17,165,-62,73 2 0125 U
+V 660,681,0,209,-22,73 2 0126 V
+W 1000,681,0,140,-22,73 2 0127 W
+X 740,681,0,145,57,73 2 0130 X
+Y 660,681,0,207,-22,73 2 0131 Y
+Z 680,681,0,110,27,73 2 0132 Z
+[ 260,741,118,164,41,73 2 0133 bracketleft
+lB "
+\ 580,741,0,45,-23,45 2 0134 backslash
+rs "
+] 260,741,118,137,68,73 2 0135 bracketright
+rB "
+a^ 480,749,0,93,-133,73 2 0136 circumflex
+^ "
+_ 500,0,155,50,50,50 0 0137 underscore
+` 320,698,0,63,-105,63 2 0140 quoteleft
+oq "
+a 680,515,8,105,-34,73 0 0141 a
+b 600,732,8,83,-7,73 2 0142 b
+c 560,515,8,87,-8,73 0 0143 c
+d 680,732,8,84,-10,73 2 0144 d
+e 560,515,8,86,-9,73 0 0145 e
+f 420,741,213,271,242,73 3 0146 f
+g 620,515,213,99,29,73 1 0147 g
+h 700,732,8,86,-43,73 2 0150 h
+i 380,755,8,90,-33,73 2 0151 i
+j 320,755,213,122,210,73 3 0152 j
+k 700,732,8,82,-47,73 2 0153 k
+l 380,732,8,80,-59,73 2 0154 l
+m 960,515,8,86,-33,73 0 0155 m
+n 680,515,8,85,-33,73 0 0156 n
+o 600,515,8,77,-9,73 0 0157 o
+p 660,515,213,72,74,72 1 0160 p
+q 620,515,213,70,-10,70 1 0161 q
+r 500,515,0,132,-34,73 0 0162 r
+s 540,515,8,83,18,73 0 0163 s
+t 440,658,8,98,-56,73 2 0164 t
+u 680,507,8,90,-33,73 0 0165 u
+v 540,515,8,82,-6,73 0 0166 v
+w 860,515,8,81,-6,73 0 0167 w
+x 620,515,8,84,40,73 0 0170 x
+y 600,507,213,92,25,73 1 0171 y
+z 560,515,8,76,14,73 0 0172 z
+lC 300,742,123,159,-3,73 2 0173 braceleft
+{ "
+ba 620,741,0,0,-253 2 0174 bar
+| "
+rC 300,742,123,102,54,73 2 0175 braceright
+} "
+a~ 480,709,0,103,-128,73 2 0176 tilde
+~ "
+bq 300,166,112,34,-56,34 0 0200 quotesinglbase
+Fo 380,503,0,76,-12,73 0 0201 guillemotleft
+char171 "
+Fc 380,503,0,76,-12,73 0 0202 guillemotright
+char187 "
+bu 360,511,0,94,-10,73 0 0203 bullet
+Fn 680,741,199,113,78,73 2 0204 florin
+f/ 120,681,0,312,194,73 2 0205 fraction
+%0 1360,698,17,23,-56,23 2 0206 perthousand
+dg 420,698,137,96,-39,73 2 0207 dagger
+dd 420,698,137,116,-29,73 2 0210 daggerdbl
+en 500,311,0,123,10,73 0 0211 endash
+em 1000,311,0,123,10,73 0 0212 emdash
+fi 820,741,213,80,241,73 3 0214 fi
+fl 820,741,213,80,241,73 3 0215 fl
+.i 380,507,8,90,-33,73 0 0220 dotlessi
+ga 380,771,0,94,-143,73 2 0222 grave
+a" 560,775,0,106,-131,73 2 0223 hungarumlaut
+a. 380,734,0,15,-130,15 2 0224 dotaccent
+ab 460,707,0,106,-127,73 2 0225 breve
+ah 480,749,0,93,-133,73 2 0226 caron
+ao 360,775,0,96,-135,73 2 0227 ring
+ho 320,0,182,0,-18 0 0230 ogonek
+lq 520,698,0,75,-106,73 2 0231 quotedblleft
+rq 520,698,0,90,-121,73 2 0232 quotedblright
+oe 920,515,8,91,2,73 0 0233 oe
+/l 380,732,8,82,-13,73 2 0234 lslash
+Bq 520,166,112,25,-56,25 0 0235 quotedblbase
+OE 1180,698,17,115,-44,73 2 0236 OE
+/L 640,681,0,134,36,73 2 0237 Lslash
+r! 320,515,191,74,-14,73 0 0241 exclamdown
+char161 "
+ct 680,718,0,0,-111 2 0242 cent
+char162 "
+Po 680,698,17,157,50,73 2 0243 sterling
+char163 "
+Cs 680,571,0,7,-98,7 0 0244 currency
+char164 "
+Ye 680,681,0,152,-42,73 2 0245 yen
+char165 "
+bb 620,741,0,0,-253 2 0246 brokenbar
+char166 "
+sc 620,698,137,68,4,68 2 0247 section
+char167 "
+ad 520,734,0,99,-130,73 2 0250 dieresis
+char168 "
+co 780,698,17,53,-33,53 2 0251 copyright
+char169 "
+Of 440,685,0,105,-5,73 2 0252 ordfeminine
+char170 "
+fo 220,503,0,79,-12,73 0 0253 guilsinglleft
+no 620,421,0,15,-31,15 0 0254 logicalnot
+char172 "
+\- 600,323,0,45,-41,45 0 0255 minus
+rg 780,698,17,53,-33,53 2 0256 registered
+char174 "
+a- 480,691,0,101,-127,73 2 0257 macron
+char175 "
+de 400,698,0,80,-80,73 2 0260 degree
+char176 "
+char177 600,514,0,45,-41,45 0 0261 plusminus
+S2 408,698,0,127,-41,73 2 0262 twosuperior
+char178 "
+S3 408,698,0,125,-36,73 2 0263 threesuperior
+char179 "
+aa 340,771,0,117,-126,73 2 0264 acute
+char180 "
+char181 680,507,213,90,-4,73 1 0265 mu
+ps 680,681,204,96,-20,73 2 0266 paragraph
+char182 "
+char183 340,358,0,26,-76,26 0 0267 periodcentered
+ac 360,0,220,0,-18 1 0270 cedilla
+char184 "
+S1 408,688,0,48,-68,48 2 0271 onesuperior
+char185 "
+Om 440,685,0,77,3,73 2 0272 ordmasculine
+char186 "
+fc 220,503,0,79,-12,73 0 0273 guilsinglright
+14 1020,681,0,84,-68,73 2 0274 onequarter
+char188 "
+12 1020,681,0,66,-68,66 2 0275 onehalf
+char189 "
+34 1020,691,0,84,-36,73 2 0276 threequarters
+char190 "
+r? 620,515,189,36,-33,36 0 0277 questiondown
+char191 "
+`A 720,937,0,99,77,73 2 0300 Agrave
+char192 "
+'A 720,937,0,99,77,73 2 0301 Aacute
+char193 "
+^A 720,915,0,99,77,73 2 0302 Acircumflex
+char194 "
+~A 720,875,0,99,77,73 2 0303 Atilde
+char195 "
+:A 720,900,0,99,77,73 2 0304 Adieresis
+char196 "
+oA 720,941,0,99,77,73 2 0305 Aring
+char197 "
+AE 1140,681,0,117,77,73 2 0306 AE
+char198 "
+,C 700,698,220,104,-28,73 3 0307 Ccedilla
+char199 "
+`E 720,937,0,107,36,73 2 0310 Egrave
+char200 "
+'E 720,937,0,107,36,73 2 0311 Eacute
+char201 "
+^E 720,915,0,107,36,73 2 0312 Ecircumflex
+char202 "
+:E 720,900,0,107,36,73 2 0313 Edieresis
+char203 "
+`I 380,937,0,155,36,73 2 0314 Igrave
+char204 "
+'I 380,937,0,155,36,73 2 0315 Iacute
+char205 "
+^I 380,915,0,163,36,73 2 0316 Icircumflex
+char206 "
+:I 380,900,0,169,36,73 2 0317 Idieresis
+char207 "
+-D 760,681,0,95,36,73 2 0320 Eth
+char208 "
+~N 740,875,0,155,36,73 2 0321 Ntilde
+char209 "
+`O 760,937,17,96,-28,73 2 0322 Ograve
+char210 "
+'O 760,937,17,96,-28,73 2 0323 Oacute
+char211 "
+^O 760,915,17,96,-28,73 2 0324 Ocircumflex
+char212 "
+~O 760,875,17,96,-28,73 2 0325 Otilde
+char213 "
+:O 760,900,17,96,-28,73 2 0326 Odieresis
+char214 "
+char215 600,514,0,45,-41,45 0 0327 multiply
+/O 760,725,29,137,29,73 2 0330 Oslash
+char216 "
+`U 740,937,17,165,-62,73 2 0331 Ugrave
+char217 "
+'U 740,937,17,165,-62,73 2 0332 Uacute
+char218 "
+^U 740,915,17,165,-62,73 2 0333 Ucircumflex
+char219 "
+:U 740,900,17,165,-62,73 2 0334 Udieresis
+char220 "
+'Y 660,937,0,207,-22,73 2 0335 Yacute
+char221 "
+TP 640,681,0,111,56,73 2 0336 Thorn
+char222 "
+ss 660,741,213,92,281,73 3 0337 germandbls
+char223 "
+`a 680,771,8,105,-34,73 2 0340 agrave
+char224 "
+'a 680,771,8,105,-34,73 2 0341 aacute
+char225 "
+^a 680,749,8,105,-34,73 2 0342 acircumflex
+char226 "
+~a 680,709,8,105,-34,73 2 0343 atilde
+char227 "
+:a 680,734,8,105,-34,73 2 0344 adieresis
+char228 "
+oa 680,775,8,105,-34,73 2 0345 aring
+char229 "
+ae 880,515,8,83,11,73 0 0346 ae
+char230 "
+,c 560,515,220,87,-8,73 1 0347 ccedilla
+char231 "
+`e 560,771,8,86,-9,73 2 0350 egrave
+char232 "
+'e 560,771,8,86,-9,73 2 0351 eacute
+char233 "
+^e 560,749,8,86,-9,73 2 0352 ecircumflex
+char234 "
+:e 560,734,8,86,-9,73 2 0353 edieresis
+char235 "
+`i 380,771,8,94,-33,73 2 0354 igrave
+char236 "
+'i 380,771,8,90,-33,73 2 0355 iacute
+char237 "
+^i 380,749,8,103,-33,73 2 0356 icircumflex
+char238 "
+:i 380,734,8,149,-33,73 2 0357 idieresis
+char239 "
+Sd 600,741,8,112,-9,73 2 0360 eth
+char240 "
+~n 680,709,8,85,-33,73 2 0361 ntilde
+char241 "
+`o 600,771,8,77,-9,73 2 0362 ograve
+char242 "
+'o 600,771,8,77,-9,73 2 0363 oacute
+char243 "
+^o 600,749,8,77,-9,73 2 0364 ocircumflex
+char244 "
+~o 600,709,8,77,-9,73 2 0365 otilde
+char245 "
+:o 600,734,8,77,-9,73 2 0366 odieresis
+char246 "
+char247 600,521,0,45,-41,45 0 0367 divide
+/o 600,571,54,111,33,73 0 0370 oslash
+char248 "
+`u 680,771,8,90,-33,73 2 0371 ugrave
+char249 "
+'u 680,771,8,90,-33,73 2 0372 uacute
+char250 "
+^u 680,749,8,90,-33,73 2 0373 ucircumflex
+char251 "
+:u 680,734,8,90,-33,73 2 0374 udieresis
+char252 "
+'y 600,771,213,92,25,73 3 0375 yacute
+char253 "
+Tp 660,732,213,72,74,72 3 0376 thorn
+char254 "
+:y 600,734,213,92,25,73 3 0377 ydieresis
+char255 "
diff --git a/gnu/usr.bin/groff/devps/BMI b/gnu/usr.bin/groff/devps/BMI
new file mode 100644
index 0000000..7eaa3f1
--- /dev/null
+++ b/gnu/usr.bin/groff/devps/BMI
@@ -0,0 +1,434 @@
+name BMI
+internalname Bookman-LightItalic
+slant 10
+spacewidth 300
+encoding text.enc
+ligatures fi fl 0
+kernpairs
+A Y -62
+A W -73
+A V -78
+A T -5
+F . -97
+F , -98
+F A -16
+L y 20
+L Y 7
+L W 9
+L V 4
+P . -105
+P , -106
+P A -30
+R Y 11
+R W 2
+R V 2
+R T 65
+T ; 48
+T s -7
+T r 67
+T . -78
+T o 14
+T i 71
+T - 20
+T hy 20
+T char173 20
+T e 10
+T , -79
+T : 48
+T c 16
+T a 9
+T A -14
+V y -14
+V u -10
+V ; -44
+V r -20
+V . -100
+V o -70
+V i 3
+V - 20
+V hy 20
+V char173 20
+V e -70
+V , -109
+V : -35
+V a -70
+V A -70
+W y -14
+W u -20
+W ; -42
+W r -30
+W . -100
+W o -60
+W i 3
+W - 20
+W hy 20
+W char173 20
+W e -60
+W , -109
+W : -35
+W a -60
+W A -60
+Y v -19
+Y u -31
+Y ; -40
+Y q -72
+Y . -100
+Y p -37
+Y o -75
+Y i -11
+Y - 20
+Y hy 20
+Y char173 20
+Y e -78
+Y , -109
+Y : -35
+Y a -79
+Y A -82
+f f -19
+r q -14
+r . -134
+r o -10
+r n 38
+r m 37
+r - 20
+r hy 20
+r char173 20
+r h -20
+r g -3
+r f -9
+r e -15
+r d -9
+r , -143
+r c -8
+charset
+ha 600,681,0,49,-47,49 2 0000 asciicircum
+ti 600,386,0,45,-41,45 0 0001 asciitilde
+vS 640,871,17,78,-11,70 2 0002 Scaron
+vZ 580,871,0,165,42,70 2 0003 Zcaron
+vs 540,684,8,57,-15,57 2 0004 scaron
+vz 520,684,8,91,12,70 2 0005 zcaron
+:Y 660,875,0,199,-37,70 2 0006 Ydieresis
+tm 980,681,0,35,-19,35 2 0007 trademark
+aq 200,698,0,97,-49,70 2 0010 quotesingle
+space 300 0 0040
+! 320,698,8,72,-53,70 2 0041 exclam
+" 360,698,0,92,-57,70 2 0042 quotedbl
+# 620,681,0,28,-57,28 2 0043 numbersign
+sh "
+$ 620,762,85,49,-28,49 2 0044 dollar
+Do "
+% 800,691,8,61,-6,61 2 0045 percent
+& 820,698,18,78,-15,70 2 0046 ampersand
+' 280,698,0,58,-98,58 2 0047 quoteright
+( 280,727,146,153,-46,70 2 0050 parenleft
+) 280,727,146,49,58,49 2 0051 parenright
+* 440,698,0,115,-89,70 2 0052 asterisk
++ 600,548,0,45,-41,45 0 0053 plus
+, 300,112,115,0,-38 0 0054 comma
+- 320,325,0,66,-28,66 0 0055 hyphen
+hy "
+char173 "
+. 300,127,8,0,-46 0 0056 period
+/ 600,717,149,12,-54,12 2 0057 slash
+sl "
+0 620,698,17,76,-36,70 2 0060 zero
+1 620,681,0,0,-104 2 0061 one
+2 620,698,0,66,-16,66 2 0062 two
+3 620,698,17,52,-5,52 2 0063 three
+4 620,681,0,64,-19,64 2 0064 four
+5 620,681,17,44,-20,44 2 0065 five
+6 620,698,17,87,-39,70 2 0066 six
+7 620,681,0,102,-93,70 2 0067 seven
+8 620,698,17,85,-11,70 2 0070 eight
+9 620,698,17,79,-27,70 2 0071 nine
+: 300,494,8,42,-46,42 0 0072 colon
+; 300,494,114,42,-38,42 0 0073 semicolon
+< 600,561,0,38,-29,38 0 0074 less
+= 600,433,0,45,-41,45 0 0075 equal
+> 600,561,0,52,-43,52 0 0076 greater
+? 540,698,8,114,-64,70 2 0077 question
+@ 780,698,17,72,-52,70 2 0100 at
+at "
+A 700,681,0,70,75,70 2 0101 A
+B 720,681,0,76,29,70 2 0102 B
+C 720,698,17,76,-38,70 2 0103 C
+D 740,681,0,92,29,70 2 0104 D
+E 680,681,0,106,29,70 2 0105 E
+F 620,681,0,173,29,70 2 0106 F
+G 760,698,17,103,-38,70 2 0107 G
+H 800,681,0,138,29,70 2 0110 H
+I 320,681,0,142,29,70 2 0111 I
+J 560,681,17,156,52,70 2 0112 J
+K 720,681,0,134,29,70 2 0113 K
+L 580,681,0,126,29,70 2 0114 L
+M 860,681,0,146,32,70 2 0115 M
+N 720,681,0,153,32,70 2 0116 N
+O 760,698,17,89,-38,70 2 0117 O
+P 600,681,0,131,29,70 2 0120 P
+Q 780,698,191,82,-11,70 2 0121 Q
+R 700,681,0,86,29,70 2 0122 R
+S 640,698,17,78,-11,70 2 0123 S
+T 600,681,0,175,0,70 2 0124 T
+U 720,681,17,172,-68,70 2 0125 U
+V 680,681,0,185,-37,70 2 0126 V
+W 960,681,0,185,-37,70 2 0127 W
+X 700,681,0,165,75,70 2 0130 X
+Y 660,681,0,199,-37,70 2 0131 Y
+Z 580,681,0,165,42,70 2 0132 Z
+[ 260,717,136,141,-6,70 2 0133 bracketleft
+lB "
+\ 600,717,0,0,-34 2 0134 backslash
+rs "
+] 260,717,136,99,35,70 2 0135 bracketright
+rB "
+a^ 440,685,0,89,-126,70 2 0136 circumflex
+^ "
+_ 500,0,155,50,50,50 0 0137 underscore
+` 280,698,0,100,-141,70 2 0140 quoteleft
+oq "
+a 620,494,8,116,-21,70 0 0141 a
+b 600,717,8,71,-38,70 2 0142 b
+c 480,494,8,92,-15,70 0 0143 c
+d 640,717,8,105,-15,70 2 0144 d
+e 540,494,8,85,-15,70 0 0145 e
+f 340,725,218,267,210,70 3 0146 f
+g 560,494,221,71,46,70 1 0147 g
+h 620,717,8,119,-38,70 2 0150 h
+i 280,663,8,121,-38,70 2 0151 i
+j 280,663,221,78,250,70 3 0152 j
+k 600,717,8,107,-38,70 2 0153 k
+l 280,717,8,112,-50,70 2 0154 l
+m 880,494,8,122,-38,70 0 0155 m
+n 620,494,8,103,-38,70 0 0156 n
+o 540,494,8,82,-15,70 0 0157 o
+p 600,494,212,70,74,70 1 0160 p
+q 560,494,212,74,-15,70 1 0161 q
+r 400,494,0,131,-38,70 0 0162 r
+s 540,494,8,57,-15,57 0 0163 s
+t 340,664,8,121,-38,70 2 0164 t
+u 620,484,8,116,-38,70 0 0165 u
+v 540,494,8,72,-38,70 0 0166 v
+w 880,494,8,63,-38,63 0 0167 w
+x 540,494,8,136,41,70 0 0170 x
+y 600,484,221,59,-10,59 1 0171 y
+z 520,494,8,91,12,70 0 0172 z
+lC 360,717,191,129,-75,70 2 0173 braceleft
+{ "
+ba 600,717,0,0,-244 2 0174 bar
+| "
+rC 380,717,191,0,35 2 0175 braceright
+} "
+a~ 440,671,0,98,-130,70 2 0176 tilde
+~ "
+bq 320,113,114,0,-37 0 0200 quotesinglbase
+Fo 300,434,0,63,-20,63 0 0201 guillemotleft
+char171 "
+Fc 300,434,0,53,-10,53 0 0202 guillemotright
+char187 "
+bu 460,511,0,34,-50,34 0 0203 bullet
+Fn 620,725,218,122,76,70 3 0204 florin
+f/ 20,681,0,353,278,70 2 0205 fraction
+%0 1180,691,8,69,-6,69 2 0206 perthousand
+dg 620,698,130,0,-142 2 0207 dagger
+dd 620,698,122,0,-94 2 0210 daggerdbl
+en 500,325,0,111,17,70 0 0211 endash
+em 1000,325,0,111,17,70 0 0212 emdash
+fi 640,725,222,119,209,70 3 0214 fi
+fl 660,725,218,103,209,70 3 0215 fl
+.i 280,484,8,121,-38,70 0 0220 dotlessi
+ga 340,706,0,87,-132,70 2 0222 grave
+a" 340,738,0,112,-117,70 2 0223 hungarumlaut
+a. 260,664,0,80,-119,70 2 0224 dotaccent
+ab 440,680,0,110,-141,70 2 0225 breve
+ah 440,684,0,91,-128,70 2 0226 caron
+ao 300,706,0,84,-128,70 2 0227 ring
+ho 260,0,173,0,-1 0 0230 ogonek
+lq 440,698,0,103,-141,70 2 0231 quotedblleft
+rq 440,698,0,61,-98,61 2 0232 quotedblright
+oe 900,494,8,98,-15,70 0 0233 oe
+/l 340,717,8,108,0,70 2 0234 lslash
+Bq 480,113,114,0,-37 0 0235 quotedblbase
+OE 1180,698,17,107,-38,70 2 0236 OE
+/L 580,681,0,126,29,70 2 0237 Lslash
+r! 320,494,213,31,-23,31 1 0241 exclamdown
+char161 "
+ct 620,715,29,26,-98,26 2 0242 cent
+char162 "
+Po 620,698,17,132,46,70 2 0243 sterling
+char163 "
+Cs 620,591,0,35,-50,35 0 0244 currency
+char164 "
+Ye 620,681,0,165,-21,70 2 0245 yen
+char165 "
+bb 600,717,0,0,-244 2 0246 brokenbar
+char166 "
+sc 620,698,178,68,12,68 2 0247 section
+char167 "
+ad 420,688,0,97,-135,70 2 0250 dieresis
+char168 "
+co 740,698,17,94,-34,70 2 0251 copyright
+char169 "
+Of 440,698,0,123,-44,70 2 0252 ordfeminine
+char170 "
+fo 180,434,0,78,-25,70 0 0253 guilsinglleft
+no 600,433,0,45,-41,45 0 0254 logicalnot
+char172 "
+\- 600,335,0,45,-41,45 0 0255 minus
+rg 740,698,17,94,-34,70 2 0256 registered
+char174 "
+a- 440,658,0,94,-128,70 0 0257 macron
+char175 "
+de 400,698,0,70,-70,70 2 0260 degree
+char176 "
+char177 600,548,0,45,-41,45 0 0261 plusminus
+S2 372,698,0,117,-18,70 2 0262 twosuperior
+char178 "
+S3 372,698,0,117,-20,70 2 0263 threesuperior
+char179 "
+aa 320,706,0,103,-128,70 2 0264 acute
+char180 "
+char181 620,484,221,116,-3,70 1 0265 mu
+ps 620,681,0,148,-62,70 2 0266 paragraph
+char182 "
+char183 300,364,0,22,-87,22 0 0267 periodcentered
+ac 320,0,178,0,5 0 0270 cedilla
+char184 "
+S1 372,688,0,17,-64,17 2 0271 onesuperior
+char185 "
+Om 400,698,0,105,-44,70 2 0272 ordmasculine
+char186 "
+fc 180,434,0,73,-20,70 0 0273 guilsinglright
+14 930,681,0,33,-41,33 2 0274 onequarter
+char188 "
+12 930,681,0,45,-41,45 2 0275 onehalf
+char189 "
+34 930,691,0,33,-49,33 2 0276 threequarters
+char190 "
+r? 540,494,212,18,32,18 1 0277 questiondown
+char191 "
+`A 700,893,0,70,75,70 2 0300 Agrave
+char192 "
+'A 700,893,0,70,75,70 2 0301 Aacute
+char193 "
+^A 700,872,0,70,75,70 2 0302 Acircumflex
+char194 "
+~A 700,858,0,70,75,70 2 0303 Atilde
+char195 "
+:A 700,875,0,70,75,70 2 0304 Adieresis
+char196 "
+oA 700,893,0,70,75,70 2 0305 Aring
+char197 "
+AE 1220,681,0,99,95,70 2 0306 AE
+char198 "
+,C 720,698,178,76,-38,70 2 0307 Ccedilla
+char199 "
+`E 680,893,0,106,29,70 2 0310 Egrave
+char200 "
+'E 680,893,0,106,29,70 2 0311 Eacute
+char201 "
+^E 680,872,0,106,29,70 2 0312 Ecircumflex
+char202 "
+:E 680,875,0,106,29,70 2 0313 Edieresis
+char203 "
+`I 320,893,0,142,29,70 2 0314 Igrave
+char204 "
+'I 320,893,0,142,29,70 2 0315 Iacute
+char205 "
+^I 320,872,0,149,29,70 2 0316 Icircumflex
+char206 "
+:I 320,875,0,147,29,70 2 0317 Idieresis
+char207 "
+-D 740,681,0,92,29,70 2 0320 Eth
+char208 "
+~N 720,858,0,153,32,70 2 0321 Ntilde
+char209 "
+`O 760,893,17,89,-38,70 2 0322 Ograve
+char210 "
+'O 760,893,17,89,-38,70 2 0323 Oacute
+char211 "
+^O 760,872,17,89,-38,70 2 0324 Ocircumflex
+char212 "
+~O 760,858,17,89,-38,70 2 0325 Otilde
+char213 "
+:O 760,875,17,89,-38,70 2 0326 Odieresis
+char214 "
+char215 600,548,0,45,-41,45 0 0327 multiply
+/O 760,777,95,89,-38,70 2 0330 Oslash
+char216 "
+`U 720,893,17,172,-68,70 2 0331 Ugrave
+char217 "
+'U 720,893,17,172,-68,70 2 0332 Uacute
+char218 "
+^U 720,872,17,172,-68,70 2 0333 Ucircumflex
+char219 "
+:U 720,875,17,172,-68,70 2 0334 Udieresis
+char220 "
+'Y 660,893,0,199,-37,70 2 0335 Yacute
+char221 "
+TP 600,681,0,106,29,70 2 0336 Thorn
+char222 "
+ss 620,698,111,83,171,70 2 0337 germandbls
+char223 "
+`a 620,706,8,116,-21,70 2 0340 agrave
+char224 "
+'a 620,706,8,116,-21,70 2 0341 aacute
+char225 "
+^a 620,685,8,116,-21,70 2 0342 acircumflex
+char226 "
+~a 620,671,8,116,-21,70 2 0343 atilde
+char227 "
+:a 620,688,8,116,-21,70 2 0344 adieresis
+char228 "
+oa 620,706,8,116,-21,70 2 0345 aring
+char229 "
+ae 880,494,8,88,-21,70 0 0346 ae
+char230 "
+,c 480,494,178,92,-15,70 0 0347 ccedilla
+char231 "
+`e 540,706,8,85,-15,70 2 0350 egrave
+char232 "
+'e 540,706,8,85,-15,70 2 0351 eacute
+char233 "
+^e 540,685,8,85,-15,70 2 0352 ecircumflex
+char234 "
+:e 540,688,8,85,-15,70 2 0353 edieresis
+char235 "
+`i 280,706,8,121,-38,70 2 0354 igrave
+char236 "
+'i 280,706,8,121,-38,70 2 0355 iacute
+char237 "
+^i 280,685,8,149,-26,70 2 0356 icircumflex
+char238 "
+:i 280,688,8,147,-38,70 2 0357 idieresis
+char239 "
+Sd 540,725,8,152,-15,70 2 0360 eth
+char240 "
+~n 620,671,8,103,-38,70 2 0361 ntilde
+char241 "
+`o 540,706,8,82,-15,70 2 0362 ograve
+char242 "
+'o 540,706,8,82,-15,70 2 0363 oacute
+char243 "
+^o 540,685,8,82,-15,70 2 0364 ocircumflex
+char244 "
+~o 540,671,8,82,-15,70 2 0365 otilde
+char245 "
+:o 540,688,8,82,-15,70 2 0366 odieresis
+char246 "
+char247 600,548,0,45,-41,45 0 0367 divide
+/o 540,532,49,81,-15,70 0 0370 oslash
+char248 "
+`u 620,706,8,116,-38,70 2 0371 ugrave
+char249 "
+'u 620,706,8,116,-38,70 2 0372 uacute
+char250 "
+^u 620,685,8,116,-38,70 2 0373 ucircumflex
+char251 "
+:u 620,688,8,116,-38,70 2 0374 udieresis
+char252 "
+'y 600,706,221,59,-10,59 3 0375 yacute
+char253 "
+Tp 600,717,212,70,74,70 3 0376 thorn
+char254 "
+:y 600,688,221,59,-10,59 3 0377 ydieresis
+char255 "
diff --git a/gnu/usr.bin/groff/devps/BMR b/gnu/usr.bin/groff/devps/BMR
new file mode 100644
index 0000000..8e90c10
--- /dev/null
+++ b/gnu/usr.bin/groff/devps/BMR
@@ -0,0 +1,430 @@
+name BMR
+internalname Bookman-Light
+spacewidth 320
+encoding text.enc
+ligatures fi fl 0
+kernpairs
+A y 32
+A w 4
+A v 7
+A Y -35
+A W -40
+A V -56
+A T 1
+F . -46
+F , -41
+F A -21
+L y 79
+L Y 13
+L W 1
+L V -4
+L T 28
+P . -60
+P , -55
+P A -8
+R y 59
+R Y 26
+R W 13
+R V 8
+R T 71
+T s 16
+T r 38
+T . -33
+T o 15
+T i 42
+T - 90
+T hy 90
+T char173 90
+T e 13
+T , -28
+T c 14
+T a 17
+T A 1
+V y 15
+V u -38
+V r -41
+V . -40
+V o -71
+V i -20
+V - 11
+V hy 11
+V char173 11
+V e -72
+V , -34
+V a -69
+V A -66
+W y 15
+W u -38
+W r -41
+W . -40
+W o -68
+W i -20
+W - 11
+W hy 11
+W char173 11
+W e -69
+W , -34
+W a -66
+W A -64
+Y v 15
+Y u -38
+Y q -55
+Y . -40
+Y p -31
+Y o -57
+Y i -37
+Y - 11
+Y hy 11
+Y char173 11
+Y e -58
+Y , -34
+Y a -54
+Y A -53
+f f 29
+r q 9
+r . -64
+r o 8
+r n 31
+r m 31
+r - 70
+r hy 70
+r char173 70
+r h -21
+r g -4
+r f 33
+r e 7
+r d 7
+r , -58
+r c 7
+charset
+ha 600,681 2 0000 asciicircum
+ti 600,352 0 0001 asciitilde
+vS 660,869,17 2 0002 Scaron
+vZ 640,869 2 0003 Zcaron
+vs 520,672,8 2 0004 scaron
+vz 480,672 2 0005 zcaron
+:Y 640,871 2 0006 Ydieresis
+tm 980,681 2 0007 trademark
+aq 220,698 2 0010 quotesingle
+space 320 0 0040
+! 300,698,8 2 0041 exclam
+" 380,698 2 0042 quotedbl
+# 620,681 2 0043 numbersign
+sh "
+$ 620,791,109 2 0044 dollar
+Do "
+% 900,698,8 2 0045 percent
+& 800,698,17 2 0046 ampersand
+' 220,698 2 0047 quoteright
+( 300,727,145 2 0050 parenleft
+) 300,727,146 2 0051 parenright
+* 440,698 2 0052 asterisk
++ 600,513 0 0053 plus
+, 320,114,114 0 0054 comma
+- 400,292 0 0055 hyphen
+hy "
+char173 "
+. 320,123,8 0 0056 period
+/ 600,717,149 2 0057 slash
+sl "
+0 620,698,17 2 0060 zero
+1 620,681 2 0061 one
+2 620,698 2 0062 two
+3 620,698,17 2 0063 three
+4 620,681 2 0064 four
+5 620,717,17 2 0065 five
+6 620,698,17 2 0066 six
+7 620,681 2 0067 seven
+8 620,698,17 2 0070 eight
+9 620,698,17 2 0071 nine
+: 320,494,8 0 0072 colon
+; 320,494,114 0 0073 semicolon
+< 600,526,2 0 0074 less
+= 600,398 0 0075 equal
+> 600,526,2 0 0076 greater
+? 540,698,8 2 0077 question
+@ 820,698,17 2 0100 at
+at "
+A 680,681 2 0101 A
+B 740,681 2 0102 B
+C 740,698,17 2 0103 C
+D 800,681 2 0104 D
+E 720,681 2 0105 E
+F 640,681 2 0106 F
+G 800,698,17 2 0107 G
+H 800,681 2 0110 H
+I 340,681 2 0111 I
+J 600,681,17 2 0112 J
+K 720,681 2 0113 K
+L 600,681 2 0114 L
+M 920,681 2 0115 M
+N 740,681 2 0116 N
+O 800,698,17 2 0117 O
+P 620,681 2 0120 P
+Q 820,698,189 2 0121 Q
+R 720,681 2 0122 R
+S 660,698,17 2 0123 S
+T 620,681 2 0124 T
+U 780,681,17 2 0125 U
+V 700,681 2 0126 V
+W 960,681 2 0127 W
+X 720,681 2 0130 X
+Y 640,681 2 0131 Y
+Z 640,681 2 0132 Z
+[ 300,717,136 2 0133 bracketleft
+lB "
+\ 600,717 2 0134 backslash
+rs "
+] 300,717,136 2 0135 bracketright
+rB "
+a^ 420,685 2 0136 circumflex
+^ "
+_ 500,0,155 0 0137 underscore
+` 220,698 2 0140 quoteleft
+oq "
+a 580,494,8 0 0141 a
+b 620,717,8 2 0142 b
+c 520,494,8 0 0143 c
+d 620,717,8 2 0144 d
+e 520,494,8 0 0145 e
+f 320,734 2 0146 f
+g 540,567,243 1 0147 g
+h 660,717 2 0150 h
+i 300,654 0 0151 i
+j 300,654,251 1 0152 j
+k 620,717 2 0153 k
+l 300,717 2 0154 l
+m 940,494 0 0155 m
+n 660,494 0 0156 n
+o 560,494,8 0 0157 o
+p 620,494,228 1 0160 p
+q 580,494,228 1 0161 q
+r 440,494 0 0162 r
+s 520,494,8 0 0163 s
+t 380,667,8 2 0164 t
+u 680,484,8 0 0165 u
+v 520,484 0 0166 v
+w 780,484 0 0167 w
+x 560,484 0 0170 x
+y 540,484,236 1 0171 y
+z 480,484 0 0172 z
+lC 280,717,136 2 0173 braceleft
+{ "
+ba 600,717 2 0174 bar
+| "
+rC 280,717,136 2 0175 braceright
+} "
+a~ 440,661 0 0176 tilde
+~ "
+bq 220,110,108 0 0200 quotesinglbase
+Fo 360,437 0 0201 guillemotleft
+char171 "
+Fc 360,437 0 0202 guillemotright
+char187 "
+bu 460,511 0 0203 bullet
+Fn 620,749,155 2 0204 florin
+f/ 140,681 2 0205 fraction
+%0 1280,698,8 2 0206 perthousand
+dg 540,698,156 2 0207 dagger
+dd 540,698,156 2 0210 daggerdbl
+en 500,292 0 0211 endash
+em 1000,292 0 0212 emdash
+fi 620,734 2 0214 fi
+fl 620,734 2 0215 fl
+.i 300,484 0 0220 dotlessi
+ga 340,689 2 0222 grave
+a" 380,699 2 0223 hungarumlaut
+a. 260,672 2 0224 dotaccent
+ab 460,687 2 0225 breve
+ah 420,672 2 0226 caron
+ao 320,731 2 0227 ring
+ho 320,0,145 0 0230 ogonek
+lq 400,698 2 0231 quotedblleft
+rq 400,698 2 0232 quotedblright
+oe 900,494,8 0 0233 oe
+/l 320,717 2 0234 lslash
+Bq 400,110,108 0 0235 quotedblbase
+OE 1240,698,17 2 0236 OE
+/L 600,681 2 0237 Lslash
+r! 300,494,214 0 0241 exclamdown
+char161 "
+ct 620,651 0 0242 cent
+char162 "
+Po 620,698,17 2 0243 sterling
+char163 "
+Cs 620,591 0 0244 currency
+char164 "
+Ye 620,681 2 0245 yen
+char165 "
+bb 600,717 2 0246 brokenbar
+char166 "
+sc 520,698,178 2 0247 section
+char167 "
+ad 420,674 2 0250 dieresis
+char168 "
+co 740,698,17 2 0251 copyright
+char169 "
+Of 420,698 2 0252 ordfeminine
+char170 "
+fo 240,437 0 0253 guilsinglleft
+no 600,398 0 0254 logicalnot
+char172 "
+\- 600,300 0 0255 minus
+rg 740,698,17 2 0256 registered
+char174 "
+a- 440,635 0 0257 macron
+char175 "
+de 400,698 2 0260 degree
+char176 "
+char177 600,513 0 0261 plusminus
+S2 372,698 2 0262 twosuperior
+char178 "
+S3 372,698 2 0263 threesuperior
+char179 "
+aa 340,689 2 0264 acute
+char180 "
+char181 680,484,251 1 0265 mu
+ps 600,681 2 0266 paragraph
+char182 "
+char183 320,327 0 0267 periodcentered
+ac 320,0,200 0 0270 cedilla
+char184 "
+S1 372,688 2 0271 onesuperior
+char185 "
+Om 420,698 2 0272 ordmasculine
+char186 "
+fc 240,437 0 0273 guilsinglright
+14 930,681 2 0274 onequarter
+char188 "
+12 930,681 2 0275 onehalf
+char189 "
+34 930,691 2 0276 threequarters
+char190 "
+r? 540,494,217 0 0277 questiondown
+char191 "
+`A 680,886 2 0300 Agrave
+char192 "
+'A 680,886 2 0301 Aacute
+char193 "
+^A 680,882 2 0302 Acircumflex
+char194 "
+~A 680,858 2 0303 Atilde
+char195 "
+:A 680,871 2 0304 Adieresis
+char196 "
+oA 680,928 2 0305 Aring
+char197 "
+AE 1260,681 2 0306 AE
+char198 "
+,C 740,698,200 2 0307 Ccedilla
+char199 "
+`E 720,886 2 0310 Egrave
+char200 "
+'E 720,886 2 0311 Eacute
+char201 "
+^E 720,882 2 0312 Ecircumflex
+char202 "
+:E 720,871 2 0313 Edieresis
+char203 "
+`I 340,886 2 0314 Igrave
+char204 "
+'I 340,886 2 0315 Iacute
+char205 "
+^I 340,882 2 0316 Icircumflex
+char206 "
+:I 340,871 2 0317 Idieresis
+char207 "
+-D 800,681 2 0320 Eth
+char208 "
+~N 740,858 2 0321 Ntilde
+char209 "
+`O 800,886,17 2 0322 Ograve
+char210 "
+'O 800,886,17 2 0323 Oacute
+char211 "
+^O 800,882,17 2 0324 Ocircumflex
+char212 "
+~O 800,858,17 2 0325 Otilde
+char213 "
+:O 800,871,17 2 0326 Odieresis
+char214 "
+char215 600,513 0 0327 multiply
+/O 800,733,53 2 0330 Oslash
+char216 "
+`U 780,886,17 2 0331 Ugrave
+char217 "
+'U 780,886,17 2 0332 Uacute
+char218 "
+^U 780,882,17 2 0333 Ucircumflex
+char219 "
+:U 780,871,17 2 0334 Udieresis
+char220 "
+'Y 640,886 2 0335 Yacute
+char221 "
+TP 620,681 2 0336 Thorn
+char222 "
+ss 660,698,110 2 0337 germandbls
+char223 "
+`a 580,689,8 2 0340 agrave
+char224 "
+'a 580,689,8 2 0341 aacute
+char225 "
+^a 580,685,8 2 0342 acircumflex
+char226 "
+~a 580,661,8 0 0343 atilde
+char227 "
+:a 580,674,8 2 0344 adieresis
+char228 "
+oa 580,731,8 2 0345 aring
+char229 "
+ae 860,494,8 0 0346 ae
+char230 "
+,c 520,494,200 0 0347 ccedilla
+char231 "
+`e 520,689,8 2 0350 egrave
+char232 "
+'e 520,689,8 2 0351 eacute
+char233 "
+^e 520,685,8 2 0352 ecircumflex
+char234 "
+:e 520,674,8 2 0353 edieresis
+char235 "
+`i 300,689 2 0354 igrave
+char236 "
+'i 300,689 2 0355 iacute
+char237 "
+^i 300,685 2 0356 icircumflex
+char238 "
+:i 300,674 2 0357 idieresis
+char239 "
+Sd 560,734,8 2 0360 eth
+char240 "
+~n 660,661 0 0361 ntilde
+char241 "
+`o 560,689,8 2 0362 ograve
+char242 "
+'o 560,689,8 2 0363 oacute
+char243 "
+^o 560,685,8 2 0364 ocircumflex
+char244 "
+~o 560,661,8 0 0365 otilde
+char245 "
+:o 560,674,8 2 0366 odieresis
+char246 "
+char247 600,514 0 0367 divide
+/o 560,534,40 0 0370 oslash
+char248 "
+`u 680,689,8 2 0371 ugrave
+char249 "
+'u 680,689,8 2 0372 uacute
+char250 "
+^u 680,685,8 2 0373 ucircumflex
+char251 "
+:u 680,674,8 2 0374 udieresis
+char252 "
+'y 540,689,236 3 0375 yacute
+char253 "
+Tp 620,717,228 3 0376 thorn
+char254 "
+:y 540,674,236 3 0377 ydieresis
+char255 "
diff --git a/gnu/usr.bin/groff/devps/CB b/gnu/usr.bin/groff/devps/CB
new file mode 100644
index 0000000..c199fd9
--- /dev/null
+++ b/gnu/usr.bin/groff/devps/CB
@@ -0,0 +1,336 @@
+name CB
+internalname Courier-Bold
+spacewidth 600
+encoding text.enc
+charset
+ha 600,616 2 0000 asciicircum
+ti 600,356 0 0001 asciitilde
+vS 600,790,22 2 0002 Scaron
+vZ 600,790 2 0003 Zcaron
+vs 600,667,17 2 0004 scaron
+vz 600,667 2 0005 zcaron
+:Y 600,748 2 0006 Ydieresis
+tm 600,562 2 0007 trademark
+aq 600,562 2 0010 quotesingle
+space 600 0 0040
+! 600,572,15 2 0041 exclam
+" 600,562 2 0042 quotedbl
+# 600,651,45 2 0043 numbersign
+sh "
+$ 600,666,126 2 0044 dollar
+Do "
+% 600,616,15 2 0045 percent
+& 600,543,15 0 0046 ampersand
+' 600,562 2 0047 quoteright
+( 600,616,102 2 0050 parenleft
+) 600,616,102 2 0051 parenright
+* 600,601 2 0052 asterisk
++ 600,478 0 0053 plus
+, 600,174,111 0 0054 comma
+- 600,313 0 0055 hyphen
+hy "
+char173 "
+. 600,171,15 0 0056 period
+/ 600,626,77 2 0057 slash
+sl "
+0 600,616,15 2 0060 zero
+1 600,616 2 0061 one
+2 600,616 2 0062 two
+3 600,616,15 2 0063 three
+4 600,616 2 0064 four
+5 600,601,15 2 0065 five
+6 600,616,15 2 0066 six
+7 600,601 2 0067 seven
+8 600,616,15 2 0070 eight
+9 600,616,15 2 0071 nine
+: 600,425,15 0 0072 colon
+; 600,425,111 0 0073 semicolon
+< 600,501 0 0074 less
+= 600,398 0 0075 equal
+> 600,501 0 0076 greater
+? 600,580,14 2 0077 question
+@ 600,616,15 2 0100 at
+at "
+A 600,562 2 0101 A
+B 600,562 2 0102 B
+C 600,580,18 2 0103 C
+D 600,562 2 0104 D
+E 600,562 2 0105 E
+F 600,562 2 0106 F
+G 600,580,18 2 0107 G
+H 600,562 2 0110 H
+I 600,562 2 0111 I
+J 600,562,18 2 0112 J
+K 600,562 2 0113 K
+L 600,562 2 0114 L
+M 600,562 2 0115 M
+N 600,562,12 2 0116 N
+O 600,580,18 2 0117 O
+P 600,562 2 0120 P
+Q 600,580,138 2 0121 Q
+R 600,562 2 0122 R
+S 600,582,22 2 0123 S
+T 600,562 2 0124 T
+U 600,562,18 2 0125 U
+V 600,562 2 0126 V
+W 600,562 2 0127 W
+X 600,562 2 0130 X
+Y 600,562 2 0131 Y
+Z 600,562 2 0132 Z
+[ 600,616,102 2 0133 bracketleft
+lB "
+\ 600,626,77 2 0134 backslash
+rs "
+] 600,616,102 2 0135 bracketright
+rB "
+a^ 600,657 2 0136 circumflex
+^ "
+_ 600,0,125 0 0137 underscore
+` 600,562 2 0140 quoteleft
+oq "
+a 600,454,15 0 0141 a
+b 600,626,15 2 0142 b
+c 600,459,15 0 0143 c
+d 600,626,15 2 0144 d
+e 600,454,15 0 0145 e
+f 600,626 2 0146 f
+g 600,454,146 1 0147 g
+h 600,626 2 0150 h
+i 600,658 2 0151 i
+j 600,658,146 3 0152 j
+k 600,626 2 0153 k
+l 600,626 2 0154 l
+m 600,454 0 0155 m
+n 600,454 0 0156 n
+o 600,454,15 0 0157 o
+p 600,454,142 1 0160 p
+q 600,454,142 1 0161 q
+r 600,454 0 0162 r
+s 600,459,17 0 0163 s
+t 600,562,15 2 0164 t
+u 600,439,15 0 0165 u
+v 600,439 0 0166 v
+w 600,439 0 0167 w
+x 600,439 0 0170 x
+y 600,439,142 1 0171 y
+z 600,439 0 0172 z
+lC 600,616,102 2 0173 braceleft
+{ "
+ba 600,750,250 3 0174 bar
+| "
+rC 600,616,102 2 0175 braceright
+} "
+a~ 600,636 2 0176 tilde
+~ "
+bq 600,143,142 1 0200 quotesinglbase
+Fo 600,446 0 0201 guillemotleft
+char171 "
+Fc 600,446 0 0202 guillemotright
+char187 "
+bu 600,430 0 0203 bullet
+Fn 600,616,131 2 0204 florin
+f/ 600,661,60 2 0205 fraction
+%0 600,616,15 2 0206 perthousand
+dg 600,580,70 2 0207 dagger
+dd 600,580,70 2 0210 daggerdbl
+en 600,313 0 0211 endash
+em 600,313 0 0212 emdash
+fi 600,626 2 0214 fi
+fl 600,626 2 0215 fl
+.i 600,439 0 0220 dotlessi
+ga 600,661 2 0222 grave
+a" 600,661 2 0223 hungarumlaut
+a. 600,625 2 0224 dotaccent
+ab 600,631 2 0225 breve
+ah 600,667 2 0226 caron
+ao 600,678 2 0227 ring
+ho 600,0,199 1 0230 ogonek
+lq 600,562 2 0231 quotedblleft
+rq 600,562 2 0232 quotedblright
+oe 600,454,15 0 0233 oe
+/l 600,626 2 0234 lslash
+Bq 600,143,142 1 0235 quotedblbase
+OE 600,562 2 0236 OE
+/L 600,562 2 0237 Lslash
+r! 600,449,146 1 0241 exclamdown
+char161 "
+ct 600,614,49 2 0242 cent
+char162 "
+Po 600,611,28 2 0243 sterling
+char163 "
+Cs 600,517 0 0244 currency
+char164 "
+Ye 600,562 2 0245 yen
+char165 "
+bb 600,675,175 3 0246 brokenbar
+char166 "
+sc 600,580,70 2 0247 section
+char167 "
+ad 600,625 2 0250 dieresis
+char168 "
+co 600,580,18 2 0251 copyright
+char169 "
+Of 600,580 2 0252 ordfeminine
+char170 "
+fo 600,446 0 0253 guilsinglleft
+no 600,413 0 0254 logicalnot
+char172 "
+\- 600,313 0 0255 minus
+rg 600,580,18 2 0256 registered
+char174 "
+a- 600,585 2 0257 macron
+char175 "
+de 600,616 2 0260 degree
+char176 "
+char177 600,515 0 0261 plusminus
+S2 600,616 2 0262 twosuperior
+char178 "
+S3 600,616 2 0263 threesuperior
+char179 "
+aa 600,661 2 0264 acute
+char180 "
+char181 600,439,142 1 0265 mu
+ps 600,580,70 2 0266 paragraph
+char182 "
+char183 600,351 0 0267 periodcentered
+ac 600,0,206 1 0270 cedilla
+char184 "
+S1 600,616 2 0271 onesuperior
+char185 "
+Om 600,580 2 0272 ordmasculine
+char186 "
+fc 600,446 0 0273 guilsinglright
+14 600,661,60 2 0274 onequarter
+char188 "
+12 600,661,60 2 0275 onehalf
+char189 "
+34 600,661,60 2 0276 threequarters
+char190 "
+r? 600,449,146 1 0277 questiondown
+char191 "
+`A 600,784 2 0300 Agrave
+char192 "
+'A 600,784 2 0301 Aacute
+char193 "
+^A 600,780 2 0302 Acircumflex
+char194 "
+~A 600,759 2 0303 Atilde
+char195 "
+:A 600,748 2 0304 Adieresis
+char196 "
+oA 600,801 2 0305 Aring
+char197 "
+AE 600,562 2 0306 AE
+char198 "
+,C 600,580,206 3 0307 Ccedilla
+char199 "
+`E 600,784 2 0310 Egrave
+char200 "
+'E 600,784 2 0311 Eacute
+char201 "
+^E 600,780 2 0312 Ecircumflex
+char202 "
+:E 600,748 2 0313 Edieresis
+char203 "
+`I 600,784 2 0314 Igrave
+char204 "
+'I 600,784 2 0315 Iacute
+char205 "
+^I 600,780 2 0316 Icircumflex
+char206 "
+:I 600,748 2 0317 Idieresis
+char207 "
+-D 600,562 2 0320 Eth
+char208 "
+~N 600,759,12 2 0321 Ntilde
+char209 "
+`O 600,784,18 2 0322 Ograve
+char210 "
+'O 600,784,18 2 0323 Oacute
+char211 "
+^O 600,780,18 2 0324 Ocircumflex
+char212 "
+~O 600,759,18 2 0325 Otilde
+char213 "
+:O 600,748,18 2 0326 Odieresis
+char214 "
+char215 600,478 0 0327 multiply
+/O 600,584,22 2 0330 Oslash
+char216 "
+`U 600,784,18 2 0331 Ugrave
+char217 "
+'U 600,784,18 2 0332 Uacute
+char218 "
+^U 600,780,18 2 0333 Ucircumflex
+char219 "
+:U 600,748,18 2 0334 Udieresis
+char220 "
+'Y 600,784 2 0335 Yacute
+char221 "
+TP 600,562 2 0336 Thorn
+char222 "
+ss 600,626,15 2 0337 germandbls
+char223 "
+`a 600,661,15 2 0340 agrave
+char224 "
+'a 600,661,15 2 0341 aacute
+char225 "
+^a 600,657,15 2 0342 acircumflex
+char226 "
+~a 600,636,15 2 0343 atilde
+char227 "
+:a 600,625,15 2 0344 adieresis
+char228 "
+oa 600,678,15 2 0345 aring
+char229 "
+ae 600,454,15 0 0346 ae
+char230 "
+,c 600,459,206 1 0347 ccedilla
+char231 "
+`e 600,661,15 2 0350 egrave
+char232 "
+'e 600,661,15 2 0351 eacute
+char233 "
+^e 600,657,15 2 0352 ecircumflex
+char234 "
+:e 600,625,15 2 0353 edieresis
+char235 "
+`i 600,661 2 0354 igrave
+char236 "
+'i 600,661 2 0355 iacute
+char237 "
+^i 600,657 2 0356 icircumflex
+char238 "
+:i 600,625 2 0357 idieresis
+char239 "
+Sd 600,626,27 2 0360 eth
+char240 "
+~n 600,636 2 0361 ntilde
+char241 "
+`o 600,661,15 2 0362 ograve
+char242 "
+'o 600,661,15 2 0363 oacute
+char243 "
+^o 600,657,15 2 0364 ocircumflex
+char244 "
+~o 600,636,15 2 0365 otilde
+char245 "
+:o 600,625,15 2 0366 odieresis
+char246 "
+char247 600,500 0 0367 divide
+/o 600,463,24 0 0370 oslash
+char248 "
+`u 600,661,15 2 0371 ugrave
+char249 "
+'u 600,661,15 2 0372 uacute
+char250 "
+^u 600,657,15 2 0373 ucircumflex
+char251 "
+:u 600,625,15 2 0374 udieresis
+char252 "
+'y 600,661,142 3 0375 yacute
+char253 "
+Tp 600,626,142 3 0376 thorn
+char254 "
+:y 600,625,142 3 0377 ydieresis
+char255 "
diff --git a/gnu/usr.bin/groff/devps/CBI b/gnu/usr.bin/groff/devps/CBI
new file mode 100644
index 0000000..802e336
--- /dev/null
+++ b/gnu/usr.bin/groff/devps/CBI
@@ -0,0 +1,337 @@
+name CBI
+internalname Courier-BoldOblique
+slant 12
+spacewidth 600
+encoding text.enc
+charset
+ha 600,616,0,5,-121,5 2 0000 asciicircum
+ti 600,356,0,39,-70,39 0 0001 asciitilde
+vS 600,790,22,122,-4,75 2 0002 Scaron
+vZ 600,790,0,109,-12,75 2 0003 Zcaron
+vs 600,667,17,82,-17,75 2 0004 scaron
+vz 600,667,0,82,-31,75 2 0005 zcaron
+:Y 600,748,0,158,-59,75 2 0006 Ydieresis
+tm 600,562,0,318,-36,75 2 0007 trademark
+aq 600,562,0,0,-254 2 0010 quotesingle
+space 600 0 0040
+! 600,572,15,0,-166 2 0041 exclam
+" 600,562,0,34,-162,34 2 0042 quotedbl
+# 600,651,45,90,-38,75 2 0043 numbersign
+sh "
+$ 600,666,126,79,-37,75 2 0044 dollar
+Do "
+% 600,616,15,74,-52,74 2 0045 percent
+& 600,543,15,44,-12,44 0 0046 ampersand
+' 600,562,0,0,-180 2 0047 quoteright
+( 600,616,102,42,-216,42 2 0050 parenleft
+) 600,616,102,0,-67 2 0051 parenright
+* 600,601,0,47,-129,47 2 0052 asterisk
++ 600,478,0,46,-64,46 0 0053 plus
+, 600,174,111,0,-49 0 0054 comma
+- 600,313,0,17,-93,17 0 0055 hyphen
+hy "
+char173 "
+. 600,171,15,0,-157 0 0056 period
+/ 600,626,77,76,-41,75 2 0057 slash
+sl "
+0 600,616,15,42,-86,42 2 0060 zero
+1 600,616,0,11,-43,11 2 0061 one
+2 600,616,0,43,-11,43 2 0062 two
+3 600,616,15,21,-22,21 2 0063 three
+4 600,616,0,8,-32,8 2 0064 four
+5 600,601,15,71,-27,71 2 0065 five
+6 600,616,15,102,-86,75 2 0066 six
+7 600,601,0,72,-97,72 2 0067 seven
+8 600,616,15,54,-65,54 2 0070 eight
+9 600,616,15,42,-26,42 2 0071 nine
+: 600,425,15,0,-156 0 0072 colon
+; 600,425,111,0,-49 0 0073 semicolon
+< 600,501,0,62,-71,62 0 0074 less
+= 600,398,0,64,-46,64 0 0075 equal
+> 600,501,0,39,-47,39 0 0076 greater
+? 600,580,14,41,-133,41 2 0077 question
+@ 600,616,15,91,-16,75 2 0100 at
+at "
+A 600,562,0,81,59,75 2 0101 A
+B 600,562,0,79,20,75 2 0102 B
+C 600,580,18,124,-25,75 2 0103 C
+D 600,562,0,114,20,75 2 0104 D
+E 600,562,0,119,25,75 2 0105 E
+F 600,562,0,133,11,75 2 0106 F
+G 600,580,18,124,-25,75 2 0107 G
+H 600,562,0,149,30,75 2 0110 H
+I 600,562,0,92,-27,75 2 0111 I
+J 600,562,18,170,-9,75 2 0112 J
+K 600,562,0,141,29,75 2 0113 K
+L 600,562,0,85,11,75 2 0114 L
+M 600,562,0,171,52,75 2 0115 M
+N 600,562,12,179,42,75 2 0116 N
+O 600,580,18,95,-24,75 2 0117 O
+P 600,562,0,92,2,75 2 0120 P
+Q 600,580,138,86,-34,75 2 0121 Q
+R 600,562,0,67,26,67 2 0122 R
+S 600,582,22,122,-4,75 2 0123 S
+T 600,562,0,128,-36,75 2 0124 T
+U 600,562,18,165,-51,75 2 0125 U
+V 600,562,0,182,-34,75 2 0126 V
+W 600,562,0,187,-34,75 2 0127 W
+X 600,562,0,139,38,75 2 0130 X
+Y 600,562,0,158,-59,75 2 0131 Y
+Z 600,562,0,86,-12,75 2 0132 Z
+[ 600,616,102,56,-173,56 2 0133 bracketleft
+lB "
+\ 600,626,77,0,-173 2 0134 backslash
+rs "
+] 600,616,102,0,-53 2 0135 bracketright
+rB "
+a^ 600,657,0,56,-162,56 2 0136 circumflex
+^ "
+_ 600,0,125,34,77,34 0 0137 underscore
+` 600,562,0,0,-247 2 0140 quoteleft
+oq "
+a 600,454,15,42,-12,42 0 0141 a
+b 600,626,15,86,37,75 2 0142 b
+c 600,459,15,81,-31,75 0 0143 c
+d 600,626,15,94,-11,75 2 0144 d
+e 600,454,15,54,-31,54 0 0145 e
+f 600,626,0,127,-33,75 2 0146 f
+g 600,454,146,123,9,75 1 0147 g
+h 600,626,0,64,32,64 2 0150 h
+i 600,658,0,0,-27 2 0151 i
+j 600,658,146,30,13,30 3 0152 j
+k 600,626,0,92,17,75 2 0153 k
+l 600,626,0,0,-27 2 0154 l
+m 600,454,0,98,72,75 0 0155 m
+n 600,454,0,64,32,64 0 0156 n
+o 600,454,15,72,-21,72 0 0157 o
+p 600,454,142,72,81,72 1 0160 p
+q 600,454,142,134,-11,75 1 0161 q
+r 600,454,0,104,3,75 0 0162 r
+s 600,459,17,57,-17,57 0 0163 s
+t 600,562,15,16,-68,16 2 0164 t
+u 600,439,15,41,-20,41 0 0165 u
+v 600,439,0,144,-20,75 0 0166 v
+w 600,439,0,161,-3,75 0 0167 w
+x 600,439,0,120,44,75 0 0170 x
+y 600,439,142,144,70,75 1 0171 y
+z 600,439,0,63,-31,63 0 0172 z
+lC 600,616,102,45,-154,45 2 0173 braceleft
+{ "
+ba 600,750,250,0,-152 3 0174 bar
+| "
+rC 600,616,102,0,-64 2 0175 braceright
+} "
+a~ 600,636,0,92,-150,75 2 0176 tilde
+~ "
+bq 600,143,142,0,-95 1 0200 quotesinglbase
+Fo 600,446,0,88,-13,75 0 0201 guillemotleft
+char171 "
+Fc 600,446,0,97,-22,75 0 0202 guillemotright
+char187 "
+bu 600,430,0,0,-147 0 0203 bullet
+Fn 600,616,131,151,106,75 2 0204 florin
+f/ 600,661,60,157,28,75 2 0205 fraction
+%0 600,616,15,192,94,75 2 0206 perthousand
+dg 600,580,70,36,-126,36 2 0207 dagger
+dd 600,580,70,36,-72,36 2 0210 daggerdbl
+en 600,313,0,52,-58,52 0 0211 endash
+em 600,313,0,127,17,75 0 0212 emdash
+fi 600,626,0,93,38,75 2 0214 fi
+fl 600,626,0,93,38,75 2 0215 fl
+.i 600,439,0,0,-27 0 0220 dotlessi
+ga 600,661,0,0,-222 2 0222 grave
+a" 600,661,0,178,-122,75 2 0223 hungarumlaut
+a. 600,625,0,0,-296 2 0224 dotaccent
+ab 600,631,0,101,-167,75 2 0225 breve
+ah 600,667,0,82,-188,75 2 0226 caron
+ao 600,678,0,0,-269 2 0227 ring
+ho 600,0,199,0,-94 1 0230 ogonek
+lq 600,562,0,44,-140,44 2 0231 quotedblleft
+rq 600,562,0,94,-70,75 2 0232 quotedblright
+oe 600,454,15,111,31,75 0 0233 oe
+/l 600,626,0,28,-27,28 2 0234 lslash
+Bq 600,143,142,9,15,9 1 0235 quotedblbase
+OE 600,562,0,150,24,75 2 0236 OE
+/L 600,562,0,85,11,75 2 0237 Lslash
+r! 600,449,146,0,-147 1 0241 exclamdown
+char161 "
+ct 600,614,49,54,-71,54 2 0242 cent
+char162 "
+Po 600,611,28,100,-57,75 2 0243 sterling
+char163 "
+Cs 600,517,0,93,-27,75 0 0244 currency
+char164 "
+Ye 600,562,0,159,-48,75 2 0245 yen
+char165 "
+bb 600,675,175,0,-168 3 0246 brokenbar
+char166 "
+sc 600,580,70,69,-24,69 2 0247 section
+char167 "
+ad 600,625,0,42,-194,42 2 0250 dieresis
+char168 "
+co 600,580,18,117,-3,75 2 0251 copyright
+char169 "
+Of 600,580,0,0,-139 2 0252 ordfeminine
+char170 "
+fo 600,446,0,0,-146 0 0253 guilsinglleft
+no 600,413,0,67,-85,67 0 0254 logicalnot
+char172 "
+\- 600,313,0,46,-64,46 0 0255 minus
+rg 600,580,18,117,-3,75 2 0256 registered
+char174 "
+a- 600,585,0,86,-145,75 2 0257 macron
+char175 "
+de 600,616,0,19,-123,19 2 0260 degree
+char176 "
+char177 600,515,0,64,-26,64 0 0261 plusminus
+S2 600,616,0,0,-142 2 0262 twosuperior
+char178 "
+S3 600,616,0,0,-143 2 0263 threesuperior
+char179 "
+aa 600,661,0,58,-263,58 2 0264 acute
+char180 "
+char181 600,439,142,41,0,41 1 0265 mu
+ps 600,580,70,149,-11,75 2 0266 paragraph
+char182 "
+char183 600,351,0,0,-199 0 0267 periodcentered
+ac 600,0,206,0,-119 1 0270 cedilla
+char184 "
+S1 600,616,0,0,-163 2 0271 onesuperior
+char185 "
+Om 600,580,0,0,-139 2 0272 ordmasculine
+char186 "
+fc 600,446,0,0,-116 0 0273 guilsinglright
+14 600,661,60,156,36,75 2 0274 onequarter
+char188 "
+12 600,661,60,165,27,75 2 0275 onehalf
+char189 "
+34 600,661,60,148,42,75 2 0276 threequarters
+char190 "
+r? 600,449,146,0,-51 1 0277 questiondown
+char191 "
+`A 600,784,0,81,59,75 2 0300 Agrave
+char192 "
+'A 600,784,0,115,59,75 2 0301 Aacute
+char193 "
+^A 600,780,0,81,59,75 2 0302 Acircumflex
+char194 "
+~A 600,759,0,88,59,75 2 0303 Atilde
+char195 "
+:A 600,748,0,81,59,75 2 0304 Adieresis
+char196 "
+oA 600,801,0,81,59,75 2 0305 Aring
+char197 "
+AE 600,562,0,157,79,75 2 0306 AE
+char198 "
+,C 600,580,206,124,-24,75 3 0307 Ccedilla
+char199 "
+`E 600,784,0,119,25,75 2 0310 Egrave
+char200 "
+'E 600,784,0,119,25,75 2 0311 Eacute
+char201 "
+^E 600,780,0,119,25,75 2 0312 Ecircumflex
+char202 "
+:E 600,748,0,119,25,75 2 0313 Edieresis
+char203 "
+`I 600,784,0,92,-27,75 2 0314 Igrave
+char204 "
+'I 600,784,0,92,-27,75 2 0315 Iacute
+char205 "
+^I 600,780,0,92,-27,75 2 0316 Icircumflex
+char206 "
+:I 600,748,0,92,-27,75 2 0317 Idieresis
+char207 "
+-D 600,562,0,114,20,75 2 0320 Eth
+char208 "
+~N 600,759,12,179,42,75 2 0321 Ntilde
+char209 "
+`O 600,784,18,95,-24,75 2 0322 Ograve
+char210 "
+'O 600,784,18,95,-24,75 2 0323 Oacute
+char211 "
+^O 600,780,18,95,-24,75 2 0324 Ocircumflex
+char212 "
+~O 600,759,18,118,-24,75 2 0325 Otilde
+char213 "
+:O 600,748,18,95,-24,75 2 0326 Odieresis
+char214 "
+char215 600,478,0,56,-55,56 0 0327 multiply
+/O 600,584,22,122,2,75 2 0330 Oslash
+char216 "
+`U 600,784,18,165,-51,75 2 0331 Ugrave
+char217 "
+'U 600,784,18,165,-51,75 2 0332 Uacute
+char218 "
+^U 600,780,18,165,-51,75 2 0333 Ucircumflex
+char219 "
+:U 600,748,18,165,-51,75 2 0334 Udieresis
+char220 "
+'Y 600,784,0,158,-59,75 2 0335 Yacute
+char221 "
+TP 600,562,0,69,2,69 2 0336 Thorn
+char222 "
+ss 600,626,15,78,28,75 2 0337 germandbls
+char223 "
+`a 600,661,15,42,-12,42 2 0340 agrave
+char224 "
+'a 600,661,15,58,-12,58 2 0341 aacute
+char225 "
+^a 600,657,15,42,-12,42 2 0342 acircumflex
+char226 "
+~a 600,636,15,92,-12,75 2 0343 atilde
+char227 "
+:a 600,625,15,42,-12,42 2 0344 adieresis
+char228 "
+oa 600,678,15,42,-12,42 2 0345 aring
+char229 "
+ae 600,454,15,101,29,75 0 0346 ae
+char230 "
+,c 600,459,206,81,-31,75 1 0347 ccedilla
+char231 "
+`e 600,661,15,54,-31,54 2 0350 egrave
+char232 "
+'e 600,661,15,58,-31,58 2 0351 eacute
+char233 "
+^e 600,657,15,56,-31,56 2 0352 ecircumflex
+char234 "
+:e 600,625,15,54,-31,54 2 0353 edieresis
+char235 "
+`i 600,661,0,0,-27 2 0354 igrave
+char236 "
+'i 600,661,0,58,-27,58 2 0355 iacute
+char237 "
+^i 600,657,0,16,-27,16 2 0356 icircumflex
+char238 "
+:i 600,625,0,2,-27,2 2 0357 idieresis
+char239 "
+Sd 600,626,27,111,-43,75 2 0360 eth
+char240 "
+~n 600,636,0,92,32,75 2 0361 ntilde
+char241 "
+`o 600,661,15,72,-21,72 2 0362 ograve
+char242 "
+'o 600,661,15,72,-21,72 2 0363 oacute
+char243 "
+^o 600,657,15,72,-21,72 2 0364 ocircumflex
+char244 "
+~o 600,636,15,92,-21,75 2 0365 otilde
+char245 "
+:o 600,625,15,72,-21,72 2 0366 odieresis
+char246 "
+char247 600,500,0,46,-64,46 0 0367 divide
+/o 600,463,24,87,-5,75 0 0370 oslash
+char248 "
+`u 600,661,15,41,-20,41 2 0371 ugrave
+char249 "
+'u 600,661,15,58,-20,58 2 0372 uacute
+char250 "
+^u 600,657,15,41,-20,41 2 0373 ucircumflex
+char251 "
+:u 600,625,15,41,-20,41 2 0374 udieresis
+char252 "
+'y 600,661,142,144,70,75 3 0375 yacute
+char253 "
+Tp 600,626,142,72,81,72 3 0376 thorn
+char254 "
+:y 600,625,142,144,70,75 3 0377 ydieresis
+char255 "
diff --git a/gnu/usr.bin/groff/devps/CI b/gnu/usr.bin/groff/devps/CI
new file mode 100644
index 0000000..f63f193
--- /dev/null
+++ b/gnu/usr.bin/groff/devps/CI
@@ -0,0 +1,337 @@
+name CI
+internalname Courier-Oblique
+slant 12
+spacewidth 600
+encoding text.enc
+charset
+ha 600,622,0,37,-125,37 2 0000 asciicircum
+ti 600,320,0,50,-66,50 0 0001 asciitilde
+vS 600,805,20,123,-26,72 2 0002 Scaron
+vZ 600,805,0,93,-36,72 2 0003 Zcaron
+vs 600,669,15,64,-28,64 2 0004 scaron
+vz 600,669,0,74,-49,72 2 0005 zcaron
+:Y 600,731,0,145,-83,72 2 0006 Ydieresis
+tm 600,562,0,192,-25,72 2 0007 trademark
+aq 600,562,0,0,-295 2 0010 quotesingle
+space 600 0 0040
+! 600,572,15,0,-193 2 0041 exclam
+" 600,562,0,0,-223 2 0042 quotedbl
+# 600,639,32,46,-83,46 2 0043 numbersign
+sh "
+$ 600,662,126,46,-58,46 2 0044 dollar
+Do "
+% 600,622,15,49,-84,49 2 0045 percent
+& 600,543,15,30,-37,30 0 0046 ampersand
+' 600,562,0,0,-233 2 0047 quoteright
+( 600,622,108,22,-263,22 2 0050 parenleft
+) 600,622,108,0,-87 2 0051 parenright
+* 600,607,0,30,-162,30 2 0052 asterisk
++ 600,470,0,30,-79,30 0 0053 plus
+, 600,122,112,0,-107 0 0054 comma
+- 600,285,0,8,-102,8 0 0055 hyphen
+hy "
+char173 "
+. 600,109,15,0,-188 0 0056 period
+/ 600,629,80,54,-62,54 2 0057 slash
+sl "
+0 600,622,15,25,-104,25 2 0060 zero
+1 600,622,0,0,-48 2 0061 one
+2 600,622,0,18,-20,18 2 0062 two
+3 600,622,15,0,-32 2 0063 three
+4 600,622,0,0,-58 2 0064 four
+5 600,607,15,39,-49,39 2 0065 five
+6 600,622,15,79,-105,72 2 0066 six
+7 600,607,0,62,-132,62 2 0067 seven
+8 600,622,15,38,-82,38 2 0070 eight
+9 600,622,15,24,-43,24 2 0071 nine
+: 600,385,15,0,-188 0 0072 colon
+; 600,385,112,0,-107 0 0073 semicolon
+< 600,472,0,60,-46,60 0 0074 less
+= 600,376,0,50,-59,50 0 0075 equal
+> 600,472,0,49,-35,49 0 0076 greater
+? 600,572,15,33,-172,33 2 0077 question
+@ 600,622,15,32,-77,32 2 0100 at
+at "
+A 600,562,0,57,47,57 2 0101 A
+B 600,562,0,66,7,66 2 0102 B
+C 600,580,18,105,-43,72 2 0103 C
+D 600,562,0,95,7,72 2 0104 D
+E 600,562,0,110,-3,72 2 0105 E
+F 600,562,0,110,-3,72 2 0106 F
+G 600,580,18,95,-33,72 2 0107 G
+H 600,562,0,137,18,72 2 0110 H
+I 600,562,0,73,-46,72 2 0111 I
+J 600,562,18,135,-2,72 2 0112 J
+K 600,562,0,121,12,72 2 0113 K
+L 600,562,0,57,3,57 2 0114 L
+M 600,562,0,165,46,72 2 0115 M
+N 600,562,13,162,43,72 2 0116 N
+O 600,580,18,75,-44,72 2 0117 O
+P 600,562,0,94,-29,72 2 0120 P
+Q 600,580,138,75,-45,72 2 0121 Q
+R 600,562,0,48,12,48 2 0122 R
+S 600,580,20,100,-26,72 2 0123 S
+T 600,562,0,115,-58,72 2 0124 T
+U 600,562,18,152,-75,72 2 0125 U
+V 600,562,13,173,-55,72 2 0126 V
+W 600,562,13,172,-56,72 2 0127 W
+X 600,562,0,125,27,72 2 0130 X
+Y 600,562,0,145,-83,72 2 0131 Y
+Z 600,562,0,60,-36,60 2 0132 Z
+[ 600,622,108,24,-196,24 2 0133 bracketleft
+lB "
+\ 600,629,80,0,-199 2 0134 backslash
+rs "
+] 600,622,108,0,-85 2 0135 bracketright
+rB "
+a^ 600,654,0,31,-179,31 2 0136 circumflex
+^ "
+_ 600,0,125,34,77,34 0 0137 underscore
+` 600,562,0,0,-293 2 0140 quoteleft
+oq "
+a 600,441,15,19,-26,19 0 0141 a
+b 600,629,15,75,21,72 2 0142 b
+c 600,441,15,58,-56,58 0 0143 c
+d 600,629,15,90,-35,72 2 0144 d
+e 600,441,15,48,-56,48 0 0145 e
+f 600,629,0,112,-64,72 2 0146 f
+g 600,441,157,107,-11,72 1 0147 g
+h 600,629,0,42,17,42 2 0150 h
+i 600,657,0,0,-45 2 0151 i
+j 600,657,157,0,-2 3 0152 j
+k 600,629,0,83,-8,72 2 0153 k
+l 600,629,0,0,-45 2 0154 l
+m 600,441,0,65,55,65 0 0155 m
+n 600,441,0,35,24,35 0 0156 n
+o 600,441,15,38,-52,38 0 0157 o
+p 600,441,157,55,74,55 1 0160 p
+q 600,441,157,132,-35,72 1 0161 q
+r 600,441,0,86,-10,72 0 0162 r
+s 600,441,15,34,-28,34 0 0163 s
+t 600,561,15,11,-117,11 2 0164 t
+u 600,426,15,22,-51,22 0 0165 u
+v 600,426,10,131,-40,72 0 0166 v
+w 600,426,10,145,-26,72 0 0167 w
+x 600,426,0,105,30,72 0 0170 x
+y 600,426,157,133,54,72 1 0171 y
+z 600,426,0,43,-49,43 0 0172 z
+lC 600,622,108,19,-183,19 2 0173 braceleft
+{ "
+ba 600,750,250,0,-172 3 0174 bar
+| "
+rC 600,622,108,0,-90 2 0175 braceright
+} "
+a~ 600,606,0,79,-162,72 2 0176 tilde
+~ "
+bq 600,100,134,0,-135 0 0200 quotesinglbase
+Fo 600,446,0,102,-42,72 0 0201 guillemotleft
+char171 "
+Fc 600,446,0,68,-8,68 0 0202 guillemotright
+char187 "
+bu 600,383,0,0,-174 0 0203 bullet
+Fn 600,622,143,121,76,72 2 0204 florin
+f/ 600,665,57,96,-34,72 2 0205 fraction
+%0 600,622,15,77,-9,72 2 0206 perthousand
+dg 600,580,78,0,-167 2 0207 dagger
+dd 600,580,78,0,-113 2 0210 daggerdbl
+en 600,285,0,36,-74,36 0 0211 endash
+em 600,285,0,111,1,72 0 0212 emdash
+fi 600,629,0,69,47,69 2 0214 fi
+fl 600,629,0,69,47,69 2 0215 fl
+.i 600,426,0,0,-45 0 0220 dotlessi
+ga 600,672,0,0,-244 2 0222 grave
+a" 600,672,0,133,-189,72 2 0223 hungarumlaut
+a. 600,580,0,0,-310 2 0224 dotaccent
+ab 600,609,0,26,-229,26 2 0225 breve
+ah 600,669,0,64,-212,64 2 0226 caron
+ao 600,627,0,0,-282 2 0227 ring
+ho 600,0,151,0,-157 0 0230 ogonek
+lq 600,562,0,0,-212 2 0231 quotedblleft
+rq 600,562,0,26,-163,26 2 0232 quotedblright
+oe 600,441,15,65,-4,65 0 0233 oe
+/l 600,629,0,33,-45,33 2 0234 lslash
+Bq 600,100,134,0,-65 0 0235 quotedblbase
+OE 600,562,0,122,-9,72 2 0236 OE
+/L 600,562,0,57,3,57 2 0237 Lslash
+r! 600,430,157,0,-175 1 0241 exclamdown
+char161 "
+ct 600,614,49,38,-101,38 2 0242 cent
+char162 "
+Po 600,611,21,71,-74,71 2 0243 sterling
+char163 "
+Cs 600,506,0,78,-44,72 0 0244 currency
+char164 "
+Ye 600,562,0,143,-70,72 2 0245 yen
+char165 "
+bb 600,675,175,0,-188 3 0246 brokenbar
+char166 "
+sc 600,580,78,40,-54,40 2 0247 section
+char167 "
+ad 600,595,0,20,-212,20 2 0250 dieresis
+char168 "
+co 600,580,18,117,-3,72 2 0251 copyright
+char169 "
+Of 600,580,0,0,-159 2 0252 ordfeminine
+char170 "
+fo 600,446,0,0,-154 0 0253 guilsinglleft
+no 600,369,0,41,-105,41 0 0254 logicalnot
+char172 "
+\- 600,283,0,30,-79,30 0 0255 minus
+rg 600,580,18,117,-3,72 2 0256 registered
+char174 "
+a- 600,565,0,50,-182,50 2 0257 macron
+char175 "
+de 600,622,0,26,-164,26 2 0260 degree
+char176 "
+char177 600,558,0,44,-46,44 0 0261 plusminus
+S2 600,622,0,0,-180 2 0262 twosuperior
+char178 "
+S3 600,622,0,0,-163 2 0263 threesuperior
+char179 "
+aa 600,672,0,62,-298,62 2 0264 acute
+char180 "
+char181 600,426,157,22,-22,22 1 0265 mu
+ps 600,562,78,80,-50,72 2 0266 paragraph
+char182 "
+char183 600,327,0,0,-225 0 0267 periodcentered
+ac 600,10,151,0,-147 0 0270 cedilla
+char184 "
+S1 600,622,0,0,-181 2 0271 onesuperior
+char185 "
+Om 600,580,0,0,-160 2 0272 ordmasculine
+char186 "
+fc 600,446,0,0,-120 0 0273 guilsinglright
+14 600,665,57,124,-15,72 2 0274 onequarter
+char188 "
+12 600,665,57,119,-15,72 2 0275 onehalf
+char189 "
+34 600,666,56,109,-23,72 2 0276 threequarters
+char190 "
+r? 600,430,157,0,-55 1 0277 questiondown
+char191 "
+`A 600,793,0,57,47,57 2 0300 Agrave
+char192 "
+'A 600,793,0,108,47,72 2 0301 Aacute
+char193 "
+^A 600,775,0,57,47,57 2 0302 Acircumflex
+char194 "
+~A 600,732,0,106,47,72 2 0303 Atilde
+char195 "
+:A 600,731,0,57,47,57 2 0304 Adieresis
+char196 "
+oA 600,753,0,57,47,57 2 0305 Aring
+char197 "
+AE 600,562,0,105,47,72 2 0306 AE
+char198 "
+,C 600,580,151,108,-43,72 2 0307 Ccedilla
+char199 "
+`E 600,793,0,110,-3,72 2 0310 Egrave
+char200 "
+'E 600,793,0,118,-3,72 2 0311 Eacute
+char201 "
+^E 600,775,0,110,-3,72 2 0312 Ecircumflex
+char202 "
+:E 600,731,0,110,-3,72 2 0313 Edieresis
+char203 "
+`I 600,793,0,73,-46,72 2 0314 Igrave
+char204 "
+'I 600,793,0,88,-46,72 2 0315 Iacute
+char205 "
+^I 600,775,0,73,-46,72 2 0316 Icircumflex
+char206 "
+:I 600,731,0,73,-46,72 2 0317 Idieresis
+char207 "
+-D 600,562,0,95,7,72 2 0320 Eth
+char208 "
+~N 600,732,13,162,43,72 2 0321 Ntilde
+char209 "
+`O 600,793,18,75,-44,72 2 0322 Ograve
+char210 "
+'O 600,793,18,88,-44,72 2 0323 Oacute
+char211 "
+^O 600,775,18,75,-44,72 2 0324 Ocircumflex
+char212 "
+~O 600,732,18,106,-44,72 2 0325 Otilde
+char213 "
+:O 600,731,18,75,-44,72 2 0326 Odieresis
+char214 "
+char215 600,470,0,57,-53,57 0 0327 multiply
+/O 600,629,80,75,-44,72 2 0330 Oslash
+char216 "
+`U 600,793,18,152,-75,72 2 0331 Ugrave
+char217 "
+'U 600,793,18,152,-75,72 2 0332 Uacute
+char218 "
+^U 600,775,18,152,-75,72 2 0333 Ucircumflex
+char219 "
+:U 600,731,18,152,-75,72 2 0334 Udieresis
+char220 "
+'Y 600,793,0,145,-83,72 2 0335 Yacute
+char221 "
+TP 600,562,0,56,-29,56 2 0336 Thorn
+char222 "
+ss 600,629,15,67,2,67 2 0337 germandbls
+char223 "
+`a 600,672,15,19,-26,19 2 0340 agrave
+char224 "
+'a 600,672,15,62,-26,62 2 0341 aacute
+char225 "
+^a 600,654,15,31,-26,31 2 0342 acircumflex
+char226 "
+~a 600,606,15,79,-26,72 2 0343 atilde
+char227 "
+:a 600,595,15,20,-26,20 2 0344 adieresis
+char228 "
+oa 600,627,15,19,-26,19 2 0345 aring
+char229 "
+ae 600,441,15,76,9,72 0 0346 ae
+char230 "
+,c 600,441,151,64,-56,64 0 0347 ccedilla
+char231 "
+`e 600,672,15,48,-56,48 2 0350 egrave
+char232 "
+'e 600,672,15,62,-56,62 2 0351 eacute
+char233 "
+^e 600,654,15,48,-56,48 2 0352 ecircumflex
+char234 "
+:e 600,595,15,48,-56,48 2 0353 edieresis
+char235 "
+`i 600,672,0,0,-45 2 0354 igrave
+char236 "
+'i 600,672,0,62,-45,62 2 0355 iacute
+char237 "
+^i 600,654,0,1,-45,1 2 0356 icircumflex
+char238 "
+:i 600,595,0,0,-45 2 0357 idieresis
+char239 "
+Sd 600,629,15,89,-52,72 2 0360 eth
+char240 "
+~n 600,606,0,79,24,72 2 0361 ntilde
+char241 "
+`o 600,672,15,38,-52,38 2 0362 ograve
+char242 "
+'o 600,672,15,62,-52,62 2 0363 oacute
+char243 "
+^o 600,654,15,38,-52,38 2 0364 ocircumflex
+char244 "
+~o 600,606,15,79,-52,72 2 0365 otilde
+char245 "
+:o 600,595,15,38,-52,38 2 0366 odieresis
+char246 "
+char247 600,467,0,23,-86,23 0 0367 divide
+/o 600,506,80,38,-52,38 0 0370 oslash
+char248 "
+`u 600,672,15,22,-51,22 2 0371 ugrave
+char249 "
+'u 600,672,15,52,-51,52 2 0372 uacute
+char250 "
+^u 600,654,15,22,-51,22 2 0373 ucircumflex
+char251 "
+:u 600,595,15,22,-51,22 2 0374 udieresis
+char252 "
+'y 600,672,157,133,54,72 3 0375 yacute
+char253 "
+Tp 600,629,157,55,74,55 3 0376 thorn
+char254 "
+:y 600,595,157,133,54,72 3 0377 ydieresis
+char255 "
diff --git a/gnu/usr.bin/groff/devps/CR b/gnu/usr.bin/groff/devps/CR
new file mode 100644
index 0000000..c6a92a1
--- /dev/null
+++ b/gnu/usr.bin/groff/devps/CR
@@ -0,0 +1,336 @@
+name CR
+internalname Courier
+spacewidth 600
+encoding text.enc
+charset
+ha 600,622 2 0000 asciicircum
+ti 600,320 0 0001 asciitilde
+vS 600,805,20 2 0002 Scaron
+vZ 600,805 2 0003 Zcaron
+vs 600,669,15 2 0004 scaron
+vz 600,669 2 0005 zcaron
+:Y 600,731 2 0006 Ydieresis
+tm 600,562 2 0007 trademark
+aq 600,562 2 0010 quotesingle
+space 600 0 0040
+! 600,572,15 2 0041 exclam
+" 600,562 2 0042 quotedbl
+# 600,639,32 2 0043 numbersign
+sh "
+$ 600,662,126 2 0044 dollar
+Do "
+% 600,622,15 2 0045 percent
+& 600,543,15 0 0046 ampersand
+' 600,562 2 0047 quoteright
+( 600,622,108 2 0050 parenleft
+) 600,622,108 2 0051 parenright
+* 600,607 2 0052 asterisk
++ 600,470 0 0053 plus
+, 600,122,112 0 0054 comma
+- 600,285 0 0055 hyphen
+hy "
+char173 "
+. 600,109,15 0 0056 period
+/ 600,629,80 2 0057 slash
+sl "
+0 600,622,15 2 0060 zero
+1 600,622 2 0061 one
+2 600,622 2 0062 two
+3 600,622,15 2 0063 three
+4 600,622 2 0064 four
+5 600,607,15 2 0065 five
+6 600,622,15 2 0066 six
+7 600,607 2 0067 seven
+8 600,622,15 2 0070 eight
+9 600,622,15 2 0071 nine
+: 600,385,15 0 0072 colon
+; 600,385,112 0 0073 semicolon
+< 600,472 0 0074 less
+= 600,376 0 0075 equal
+> 600,472 0 0076 greater
+? 600,572,15 2 0077 question
+@ 600,622,15 2 0100 at
+at "
+A 600,562 2 0101 A
+B 600,562 2 0102 B
+C 600,580,18 2 0103 C
+D 600,562 2 0104 D
+E 600,562 2 0105 E
+F 600,562 2 0106 F
+G 600,580,18 2 0107 G
+H 600,562 2 0110 H
+I 600,562 2 0111 I
+J 600,562,18 2 0112 J
+K 600,562 2 0113 K
+L 600,562 2 0114 L
+M 600,562 2 0115 M
+N 600,562,13 2 0116 N
+O 600,580,18 2 0117 O
+P 600,562 2 0120 P
+Q 600,580,138 2 0121 Q
+R 600,562 2 0122 R
+S 600,580,20 2 0123 S
+T 600,562 2 0124 T
+U 600,562,18 2 0125 U
+V 600,562,13 2 0126 V
+W 600,562,13 2 0127 W
+X 600,562 2 0130 X
+Y 600,562 2 0131 Y
+Z 600,562 2 0132 Z
+[ 600,622,108 2 0133 bracketleft
+lB "
+\ 600,629,80 2 0134 backslash
+rs "
+] 600,622,108 2 0135 bracketright
+rB "
+a^ 600,654 2 0136 circumflex
+^ "
+_ 600,0,125 0 0137 underscore
+` 600,562 2 0140 quoteleft
+oq "
+a 600,441,15 0 0141 a
+b 600,629,15 2 0142 b
+c 600,441,15 0 0143 c
+d 600,629,15 2 0144 d
+e 600,441,15 0 0145 e
+f 600,629 2 0146 f
+g 600,441,157 1 0147 g
+h 600,629 2 0150 h
+i 600,657 2 0151 i
+j 600,657,157 3 0152 j
+k 600,629 2 0153 k
+l 600,629 2 0154 l
+m 600,441 0 0155 m
+n 600,441 0 0156 n
+o 600,441,15 0 0157 o
+p 600,441,157 1 0160 p
+q 600,441,157 1 0161 q
+r 600,441 0 0162 r
+s 600,441,15 0 0163 s
+t 600,561,15 2 0164 t
+u 600,426,15 0 0165 u
+v 600,426,10 0 0166 v
+w 600,426,10 0 0167 w
+x 600,426 0 0170 x
+y 600,426,157 1 0171 y
+z 600,426 0 0172 z
+lC 600,622,108 2 0173 braceleft
+{ "
+ba 600,750,250 3 0174 bar
+| "
+rC 600,622,108 2 0175 braceright
+} "
+a~ 600,606 2 0176 tilde
+~ "
+bq 600,100,134 0 0200 quotesinglbase
+Fo 600,446 0 0201 guillemotleft
+char171 "
+Fc 600,446 0 0202 guillemotright
+char187 "
+bu 600,383 0 0203 bullet
+Fn 600,622,143 2 0204 florin
+f/ 600,665,57 2 0205 fraction
+%0 600,622,15 2 0206 perthousand
+dg 600,580,78 2 0207 dagger
+dd 600,580,78 2 0210 daggerdbl
+en 600,285 0 0211 endash
+em 600,285 0 0212 emdash
+fi 600,629 2 0214 fi
+fl 600,629 2 0215 fl
+.i 600,426 0 0220 dotlessi
+ga 600,672 2 0222 grave
+a" 600,672 2 0223 hungarumlaut
+a. 600,580 2 0224 dotaccent
+ab 600,609 2 0225 breve
+ah 600,669 2 0226 caron
+ao 600,627 2 0227 ring
+ho 600,0,151 0 0230 ogonek
+lq 600,562 2 0231 quotedblleft
+rq 600,562 2 0232 quotedblright
+oe 600,441,15 0 0233 oe
+/l 600,629 2 0234 lslash
+Bq 600,100,134 0 0235 quotedblbase
+OE 600,562 2 0236 OE
+/L 600,562 2 0237 Lslash
+r! 600,430,157 1 0241 exclamdown
+char161 "
+ct 600,614,49 2 0242 cent
+char162 "
+Po 600,611,21 2 0243 sterling
+char163 "
+Cs 600,506 0 0244 currency
+char164 "
+Ye 600,562 2 0245 yen
+char165 "
+bb 600,675,175 3 0246 brokenbar
+char166 "
+sc 600,580,78 2 0247 section
+char167 "
+ad 600,595 2 0250 dieresis
+char168 "
+co 600,580,18 2 0251 copyright
+char169 "
+Of 600,580 2 0252 ordfeminine
+char170 "
+fo 600,446 0 0253 guilsinglleft
+no 600,369 0 0254 logicalnot
+char172 "
+\- 600,283 0 0255 minus
+rg 600,580,18 2 0256 registered
+char174 "
+a- 600,565 2 0257 macron
+char175 "
+de 600,622 2 0260 degree
+char176 "
+char177 600,558 0 0261 plusminus
+S2 600,622 2 0262 twosuperior
+char178 "
+S3 600,622 2 0263 threesuperior
+char179 "
+aa 600,672 2 0264 acute
+char180 "
+char181 600,426,157 1 0265 mu
+ps 600,562,78 2 0266 paragraph
+char182 "
+char183 600,327 0 0267 periodcentered
+ac 600,10,151 0 0270 cedilla
+char184 "
+S1 600,622 2 0271 onesuperior
+char185 "
+Om 600,580 2 0272 ordmasculine
+char186 "
+fc 600,446 0 0273 guilsinglright
+14 600,665,57 2 0274 onequarter
+char188 "
+12 600,665,57 2 0275 onehalf
+char189 "
+34 600,666,56 2 0276 threequarters
+char190 "
+r? 600,430,157 1 0277 questiondown
+char191 "
+`A 600,793 2 0300 Agrave
+char192 "
+'A 600,793 2 0301 Aacute
+char193 "
+^A 600,775 2 0302 Acircumflex
+char194 "
+~A 600,732 2 0303 Atilde
+char195 "
+:A 600,731 2 0304 Adieresis
+char196 "
+oA 600,753 2 0305 Aring
+char197 "
+AE 600,562 2 0306 AE
+char198 "
+,C 600,580,151 2 0307 Ccedilla
+char199 "
+`E 600,793 2 0310 Egrave
+char200 "
+'E 600,793 2 0311 Eacute
+char201 "
+^E 600,775 2 0312 Ecircumflex
+char202 "
+:E 600,731 2 0313 Edieresis
+char203 "
+`I 600,793 2 0314 Igrave
+char204 "
+'I 600,793 2 0315 Iacute
+char205 "
+^I 600,775 2 0316 Icircumflex
+char206 "
+:I 600,731 2 0317 Idieresis
+char207 "
+-D 600,562 2 0320 Eth
+char208 "
+~N 600,732,13 2 0321 Ntilde
+char209 "
+`O 600,793,18 2 0322 Ograve
+char210 "
+'O 600,793,18 2 0323 Oacute
+char211 "
+^O 600,775,18 2 0324 Ocircumflex
+char212 "
+~O 600,732,18 2 0325 Otilde
+char213 "
+:O 600,731,18 2 0326 Odieresis
+char214 "
+char215 600,470 0 0327 multiply
+/O 600,629,80 2 0330 Oslash
+char216 "
+`U 600,793,18 2 0331 Ugrave
+char217 "
+'U 600,793,18 2 0332 Uacute
+char218 "
+^U 600,775,18 2 0333 Ucircumflex
+char219 "
+:U 600,731,18 2 0334 Udieresis
+char220 "
+'Y 600,793 2 0335 Yacute
+char221 "
+TP 600,562 2 0336 Thorn
+char222 "
+ss 600,629,15 2 0337 germandbls
+char223 "
+`a 600,672,15 2 0340 agrave
+char224 "
+'a 600,672,15 2 0341 aacute
+char225 "
+^a 600,654,15 2 0342 acircumflex
+char226 "
+~a 600,606,15 2 0343 atilde
+char227 "
+:a 600,595,15 2 0344 adieresis
+char228 "
+oa 600,627,15 2 0345 aring
+char229 "
+ae 600,441,15 0 0346 ae
+char230 "
+,c 600,441,151 0 0347 ccedilla
+char231 "
+`e 600,672,15 2 0350 egrave
+char232 "
+'e 600,672,15 2 0351 eacute
+char233 "
+^e 600,654,15 2 0352 ecircumflex
+char234 "
+:e 600,595,15 2 0353 edieresis
+char235 "
+`i 600,672 2 0354 igrave
+char236 "
+'i 600,672 2 0355 iacute
+char237 "
+^i 600,654 2 0356 icircumflex
+char238 "
+:i 600,595 2 0357 idieresis
+char239 "
+Sd 600,629,15 2 0360 eth
+char240 "
+~n 600,606 2 0361 ntilde
+char241 "
+`o 600,672,15 2 0362 ograve
+char242 "
+'o 600,672,15 2 0363 oacute
+char243 "
+^o 600,654,15 2 0364 ocircumflex
+char244 "
+~o 600,606,15 2 0365 otilde
+char245 "
+:o 600,595,15 2 0366 odieresis
+char246 "
+char247 600,467 0 0367 divide
+/o 600,506,80 0 0370 oslash
+char248 "
+`u 600,672,15 2 0371 ugrave
+char249 "
+'u 600,672,15 2 0372 uacute
+char250 "
+^u 600,654,15 2 0373 ucircumflex
+char251 "
+:u 600,595,15 2 0374 udieresis
+char252 "
+'y 600,672,157 3 0375 yacute
+char253 "
+Tp 600,629,157 3 0376 thorn
+char254 "
+:y 600,595,157 3 0377 ydieresis
+char255 "
diff --git a/gnu/usr.bin/groff/devps/DESC.in b/gnu/usr.bin/groff/devps/DESC.in
new file mode 100644
index 0000000..e9d26c8
--- /dev/null
+++ b/gnu/usr.bin/groff/devps/DESC.in
@@ -0,0 +1,11 @@
+res 72000
+hor 1
+vert 1
+sizescale 1000
+unitwidth 1000
+sizes 1000-10000000 0
+styles R I B BI
+family T
+fonts 9 0 0 0 0 0 SS S ZD ZDR
+tcommand
+postpro grops
diff --git a/gnu/usr.bin/groff/devps/HB b/gnu/usr.bin/groff/devps/HB
new file mode 100644
index 0000000..8c2ed08
--- /dev/null
+++ b/gnu/usr.bin/groff/devps/HB
@@ -0,0 +1,546 @@
+name HB
+internalname Helvetica-Bold
+spacewidth 278
+encoding text.enc
+ligatures fi fl 0
+kernpairs
+A y -30
+A w -30
+A v -40
+A u -30
+A Y -110
+A W -60
+A V -80
+A U -50
+A T -90
+A Q -40
+A O -40
+A G -50
+A C -40
+B U -10
+B A -30
+D . -30
+D , -30
+D Y -70
+D W -40
+D V -40
+D A -40
+F . -100
+F , -100
+F a -20
+F A -80
+J u -20
+J . -20
+J , -20
+J A -20
+K y -40
+K u -30
+K o -35
+K e -15
+K O -30
+L y -30
+L ' -140
+L rq -140
+L Y -120
+L W -80
+L V -110
+L T -90
+O . -40
+O , -40
+O Y -70
+O X -50
+O W -50
+O V -50
+O T -40
+O A -50
+P . -120
+P o -40
+P e -30
+P , -120
+P a -30
+P A -100
+Q . 20
+Q , 20
+Q U -10
+R Y -50
+R W -40
+R V -50
+R U -20
+R T -20
+R O -20
+T y -60
+T w -60
+T u -90
+T ; -40
+T r -80
+T . -80
+T o -80
+T - -120
+T hy -120
+T char173 -120
+T e -60
+T , -80
+T : -40
+T a -80
+T O -40
+T A -90
+U . -30
+U , -30
+U A -50
+V u -60
+V ; -40
+V . -120
+V o -90
+V - -80
+V hy -80
+V char173 -80
+V e -50
+V , -120
+V : -40
+V a -60
+V O -50
+V G -50
+V A -80
+W y -20
+W u -45
+W ; -10
+W . -80
+W o -60
+W - -40
+W hy -40
+W char173 -40
+W e -35
+W , -80
+W : -10
+W a -40
+W O -20
+W A -60
+Y u -100
+Y ; -50
+Y . -100
+Y o -100
+Y e -80
+Y , -100
+Y : -50
+Y a -90
+Y O -70
+Y A -110
+a y -20
+a w -15
+a v -15
+a g -10
+b y -20
+b v -20
+b u -20
+b l -10
+c y -10
+c l -20
+c k -20
+c h -10
+, ' -120
+, rq -120
+d y -15
+d w -15
+d v -15
+d d -10
+e y -15
+e x -15
+e w -15
+e v -15
+e . 20
+e , 10
+f ' 30
+f rq 30
+f . -10
+f o -20
+f e -10
+f , -10
+g g -10
+g e 10
+h y -20
+k o -15
+l y -15
+l w -15
+m y -30
+m u -20
+n y -20
+n v -40
+n u -10
+o y -20
+o x -30
+o w -15
+o v -20
+p y -15
+. ' -120
+. rq -120
+` ` -46
+` oq -46
+oq ` -46
+oq oq -46
+' v -20
+' s -60
+' r -40
+' ' -46
+' l -20
+' d -80
+r y 10
+r v 10
+r t 20
+r s -15
+r q -20
+r . -60
+r o -20
+r - -20
+r hy -20
+r char173 -20
+r g -15
+r d -20
+r , -60
+r c -20
+s w -15
+v . -80
+v o -30
+v , -80
+v a -20
+w . -40
+w o -20
+w , -40
+x e -10
+y . -80
+y o -25
+y e -10
+y , -80
+y a -30
+z e 10
+charset
+ha 584,698 2 0000 asciicircum
+ti 584,343 0 0001 asciitilde
+vS 667,936,19 2 0002 Scaron
+vZ 611,936 2 0003 Zcaron
+vs 556,750,14 2 0004 scaron
+vz 500,750 2 0005 zcaron
+:Y 667,915 2 0006 Ydieresis
+tm 1000,718 2 0007 trademark
+aq 238,718 2 0010 quotesingle
+space 278 0 0040
+! 333,718 2 0041 exclam
+" 474,718 2 0042 quotedbl
+# 556,698 2 0043 numbersign
+sh "
+$ 556,775,115 2 0044 dollar
+Do "
+% 889,710,19 2 0045 percent
+& 722,718,19 2 0046 ampersand
+' 278,718 2 0047 quoteright
+( 333,734,208 3 0050 parenleft
+) 333,734,208 3 0051 parenright
+* 389,718 2 0052 asterisk
++ 584,506 0 0053 plus
+, 278,146,168 0 0054 comma
+- 333,345 0 0055 hyphen
+hy "
+char173 "
+. 278,146 0 0056 period
+/ 278,737,19 2 0057 slash
+sl "
+0 556,710,19 2 0060 zero
+1 556,710 2 0061 one
+2 556,710 2 0062 two
+3 556,710,19 2 0063 three
+4 556,710 2 0064 four
+5 556,698,19 2 0065 five
+6 556,710,19 2 0066 six
+7 556,698 2 0067 seven
+8 556,710,19 2 0070 eight
+9 556,710,19 2 0071 nine
+: 333,512 0 0072 colon
+; 333,512,168 0 0073 semicolon
+< 584,514,8 0 0074 less
+= 584,419 0 0075 equal
+> 584,514,8 0 0076 greater
+? 611,727 2 0077 question
+@ 975,737,19 2 0100 at
+at "
+A 722,718 2 0101 A
+B 722,718 2 0102 B
+C 722,737,19 2 0103 C
+D 722,718 2 0104 D
+E 667,718 2 0105 E
+F 611,718 2 0106 F
+G 778,737,19 2 0107 G
+H 722,718 2 0110 H
+I 278,718 2 0111 I
+J 556,718,18 2 0112 J
+K 722,718 2 0113 K
+L 611,718 2 0114 L
+M 833,718 2 0115 M
+N 722,718 2 0116 N
+O 778,737,19 2 0117 O
+P 667,718 2 0120 P
+Q 778,737,52 2 0121 Q
+R 722,718 2 0122 R
+S 667,737,19 2 0123 S
+T 611,718 2 0124 T
+U 722,718,19 2 0125 U
+V 667,718 2 0126 V
+W 944,718 2 0127 W
+X 667,718 2 0130 X
+Y 667,718 2 0131 Y
+Z 611,718 2 0132 Z
+[ 333,722,196 2 0133 bracketleft
+lB "
+\ 278,737,19 2 0134 backslash
+rs "
+] 333,722,196 2 0135 bracketright
+rB "
+a^ 333,750 2 0136 circumflex
+^ "
+_ 556,0,125 0 0137 underscore
+` 278,727 2 0140 quoteleft
+oq "
+a 556,546,14 0 0141 a
+b 611,718,14 2 0142 b
+c 556,546,14 0 0143 c
+d 611,718,14 2 0144 d
+e 556,546,14 0 0145 e
+f 333,727 2 0146 f
+g 611,546,217 1 0147 g
+h 611,718 2 0150 h
+i 278,725 2 0151 i
+j 278,725,214 3 0152 j
+k 556,718 2 0153 k
+l 278,718 2 0154 l
+m 889,546 0 0155 m
+n 611,546 0 0156 n
+o 611,546,14 0 0157 o
+p 611,546,207 1 0160 p
+q 611,546,207 1 0161 q
+r 389,546 0 0162 r
+s 556,546,14 0 0163 s
+t 333,676,6 2 0164 t
+u 611,532,14 0 0165 u
+v 556,532 0 0166 v
+w 778,532 0 0167 w
+x 556,532 0 0170 x
+y 556,532,214 1 0171 y
+z 500,532 0 0172 z
+lC 389,722,196 2 0173 braceleft
+{ "
+ba 280,737,19 2 0174 bar
+| "
+rC 389,722,196 2 0175 braceright
+} "
+a~ 333,737 2 0176 tilde
+~ "
+bq 278,127,146 0 0200 quotesinglbase
+Fo 556,484 0 0201 guillemotleft
+char171 "
+Fc 556,484 0 0202 guillemotright
+char187 "
+bu 350,524 0 0203 bullet
+Fn 556,737,210 3 0204 florin
+f/ 167,710,19 2 0205 fraction
+%0 1000,710,19 2 0206 perthousand
+dg 556,718,171 2 0207 dagger
+dd 556,718,171 2 0210 daggerdbl
+en 556,333 0 0211 endash
+em 1000,333 0 0212 emdash
+fi 611,727 2 0214 fi
+fl 611,727 2 0215 fl
+.i 278,532 0 0220 dotlessi
+ga 333,750 2 0222 grave
+a" 333,750 2 0223 hungarumlaut
+a. 333,729 2 0224 dotaccent
+ab 333,750 2 0225 breve
+ah 333,750 2 0226 caron
+ao 333,776 2 0227 ring
+ho 333,0,228 1 0230 ogonek
+lq 500,727 2 0231 quotedblleft
+rq 500,718 2 0232 quotedblright
+oe 944,546,14 0 0233 oe
+/l 278,718 2 0234 lslash
+Bq 500,127,146 0 0235 quotedblbase
+OE 1000,737,19 2 0236 OE
+/L 611,718 2 0237 Lslash
+r! 333,532,186 0 0241 exclamdown
+char161 "
+ct 556,628,118 0 0242 cent
+char162 "
+Po 556,718,16 2 0243 sterling
+char163 "
+Cs 556,636 0 0244 currency
+char164 "
+Ye 556,698 2 0245 yen
+char165 "
+bb 280,737,19 2 0246 brokenbar
+char166 "
+sc 556,727,184 2 0247 section
+char167 "
+ad 333,729 2 0250 dieresis
+char168 "
+co 737,737,19 2 0251 copyright
+char169 "
+Of 370,737 2 0252 ordfeminine
+char170 "
+fo 333,484 0 0253 guilsinglleft
+no 584,419 0 0254 logicalnot
+char172 "
+\- 584,309 0 0255 minus
+rg 737,737,19 2 0256 registered
+char174 "
+a- 333,678 2 0257 macron
+char175 "
+de 400,712 2 0260 degree
+char176 "
+char177 584,506 0 0261 plusminus
+S2 333,710 2 0262 twosuperior
+char178 "
+S3 333,710 2 0263 threesuperior
+char179 "
+aa 333,750 2 0264 acute
+char180 "
+char181 611,532,207 1 0265 mu
+ps 556,700,191 2 0266 paragraph
+char182 "
+char183 278,334 0 0267 periodcentered
+ac 333,0,228 1 0270 cedilla
+char184 "
+S1 333,710 2 0271 onesuperior
+char185 "
+Om 365,737 2 0272 ordmasculine
+char186 "
+fc 333,484 0 0273 guilsinglright
+14 834,710,19 2 0274 onequarter
+char188 "
+12 834,710,19 2 0275 onehalf
+char189 "
+34 834,710,19 2 0276 threequarters
+char190 "
+r? 611,532,195 0 0277 questiondown
+char191 "
+`A 722,936 2 0300 Agrave
+char192 "
+'A 722,936 2 0301 Aacute
+char193 "
+^A 722,936 2 0302 Acircumflex
+char194 "
+~A 722,923 2 0303 Atilde
+char195 "
+:A 722,915 2 0304 Adieresis
+char196 "
+oA 722,962 2 0305 Aring
+char197 "
+AE 1000,718 2 0306 AE
+char198 "
+,C 722,737,228 3 0307 Ccedilla
+char199 "
+`E 667,936 2 0310 Egrave
+char200 "
+'E 667,936 2 0311 Eacute
+char201 "
+^E 667,936 2 0312 Ecircumflex
+char202 "
+:E 667,915 2 0313 Edieresis
+char203 "
+`I 278,936 2 0314 Igrave
+char204 "
+'I 278,936 2 0315 Iacute
+char205 "
+^I 278,936 2 0316 Icircumflex
+char206 "
+:I 278,915 2 0317 Idieresis
+char207 "
+-D 722,718 2 0320 Eth
+char208 "
+~N 722,923 2 0321 Ntilde
+char209 "
+`O 778,936,19 2 0322 Ograve
+char210 "
+'O 778,936,19 2 0323 Oacute
+char211 "
+^O 778,936,19 2 0324 Ocircumflex
+char212 "
+~O 778,923,19 2 0325 Otilde
+char213 "
+:O 778,915,19 2 0326 Odieresis
+char214 "
+char215 584,505 0 0327 multiply
+/O 778,745,27 2 0330 Oslash
+char216 "
+`U 722,936,19 2 0331 Ugrave
+char217 "
+'U 722,936,19 2 0332 Uacute
+char218 "
+^U 722,936,19 2 0333 Ucircumflex
+char219 "
+:U 722,915,19 2 0334 Udieresis
+char220 "
+'Y 667,936 2 0335 Yacute
+char221 "
+TP 667,718 2 0336 Thorn
+char222 "
+ss 611,731,14 2 0337 germandbls
+char223 "
+`a 556,750,14 2 0340 agrave
+char224 "
+'a 556,750,14 2 0341 aacute
+char225 "
+^a 556,750,14 2 0342 acircumflex
+char226 "
+~a 556,737,14 2 0343 atilde
+char227 "
+:a 556,729,14 2 0344 adieresis
+char228 "
+oa 556,776,14 2 0345 aring
+char229 "
+ae 889,546,14 0 0346 ae
+char230 "
+,c 556,546,228 1 0347 ccedilla
+char231 "
+`e 556,750,14 2 0350 egrave
+char232 "
+'e 556,750,14 2 0351 eacute
+char233 "
+^e 556,750,14 2 0352 ecircumflex
+char234 "
+:e 556,729,14 2 0353 edieresis
+char235 "
+`i 278,750 2 0354 igrave
+char236 "
+'i 278,750 2 0355 iacute
+char237 "
+^i 278,750 2 0356 icircumflex
+char238 "
+:i 278,729 2 0357 idieresis
+char239 "
+Sd 611,737,14 2 0360 eth
+char240 "
+~n 611,737 2 0361 ntilde
+char241 "
+`o 611,750,14 2 0362 ograve
+char242 "
+'o 611,750,14 2 0363 oacute
+char243 "
+^o 611,750,14 2 0364 ocircumflex
+char244 "
+~o 611,737,14 2 0365 otilde
+char245 "
+:o 611,729,14 2 0366 odieresis
+char246 "
+char247 584,548,42 0 0367 divide
+/o 611,560,29 0 0370 oslash
+char248 "
+`u 611,750,14 2 0371 ugrave
+char249 "
+'u 611,750,14 2 0372 uacute
+char250 "
+^u 611,750,14 2 0373 ucircumflex
+char251 "
+:u 611,729,14 2 0374 udieresis
+char252 "
+'y 556,750,214 3 0375 yacute
+char253 "
+Tp 611,718,208 3 0376 thorn
+char254 "
+:y 556,729,214 3 0377 ydieresis
+char255 "
diff --git a/gnu/usr.bin/groff/devps/HBI b/gnu/usr.bin/groff/devps/HBI
new file mode 100644
index 0000000..595e58f
--- /dev/null
+++ b/gnu/usr.bin/groff/devps/HBI
@@ -0,0 +1,547 @@
+name HBI
+internalname Helvetica-BoldOblique
+slant 12
+spacewidth 278
+encoding text.enc
+ligatures fi fl 0
+kernpairs
+A y -30
+A w -30
+A v -40
+A u -30
+A Y -110
+A W -60
+A V -80
+A U -50
+A T -90
+A Q -40
+A O -40
+A G -50
+A C -40
+B U -10
+B A -30
+D . -30
+D , -30
+D Y -70
+D W -40
+D V -40
+D A -40
+F . -100
+F , -100
+F a -20
+F A -80
+J u -20
+J . -20
+J , -20
+J A -20
+K y -40
+K u -30
+K o -35
+K e -15
+K O -30
+L y -30
+L ' -140
+L rq -140
+L Y -120
+L W -80
+L V -110
+L T -90
+O . -40
+O , -40
+O Y -70
+O X -50
+O W -50
+O V -50
+O T -40
+O A -50
+P . -120
+P o -40
+P e -30
+P , -120
+P a -30
+P A -100
+Q . 20
+Q , 20
+Q U -10
+R Y -50
+R W -40
+R V -50
+R U -20
+R T -20
+R O -20
+T y -60
+T w -60
+T u -90
+T ; -40
+T r -80
+T . -80
+T o -80
+T - -120
+T hy -120
+T char173 -120
+T e -60
+T , -80
+T : -40
+T a -80
+T O -40
+T A -90
+U . -30
+U , -30
+U A -50
+V u -60
+V ; -40
+V . -120
+V o -90
+V - -80
+V hy -80
+V char173 -80
+V e -50
+V , -120
+V : -40
+V a -60
+V O -50
+V G -50
+V A -80
+W y -20
+W u -45
+W ; -10
+W . -80
+W o -60
+W - -40
+W hy -40
+W char173 -40
+W e -35
+W , -80
+W : -10
+W a -40
+W O -20
+W A -60
+Y u -100
+Y ; -50
+Y . -100
+Y o -100
+Y e -80
+Y , -100
+Y : -50
+Y a -90
+Y O -70
+Y A -110
+a y -20
+a w -15
+a v -15
+a g -10
+b y -20
+b v -20
+b u -20
+b l -10
+c y -10
+c l -20
+c k -20
+c h -10
+, ' -120
+, rq -120
+d y -15
+d w -15
+d v -15
+d d -10
+e y -15
+e x -15
+e w -15
+e v -15
+e . 20
+e , 10
+f ' 30
+f rq 30
+f . -10
+f o -20
+f e -10
+f , -10
+g g -10
+g e 10
+h y -20
+k o -15
+l y -15
+l w -15
+m y -30
+m u -20
+n y -20
+n v -40
+n u -10
+o y -20
+o x -30
+o w -15
+o v -20
+p y -15
+. ' -120
+. rq -120
+` ` -46
+` oq -46
+oq ` -46
+oq oq -46
+' v -20
+' s -60
+' r -40
+' ' -46
+' l -20
+' d -80
+r y 10
+r v 10
+r t 20
+r s -15
+r q -20
+r . -60
+r o -20
+r - -20
+r hy -20
+r char173 -20
+r g -15
+r d -20
+r , -60
+r c -20
+s w -15
+v . -80
+v o -30
+v , -80
+v a -20
+w . -40
+w o -20
+w , -40
+x e -10
+y . -80
+y o -25
+y e -10
+y , -80
+y a -30
+z e 10
+charset
+ha 584,698,0,57,-81,57 2 0000 asciicircum
+ti 584,343,0,43,-65,43 0 0001 asciitilde
+vS 667,936,19,101,-31,90 2 0002 Scaron
+vZ 611,936,0,176,25,90 2 0003 Zcaron
+vs 556,750,14,108,-13,90 2 0004 scaron
+vz 500,750,0,136,30,90 2 0005 zcaron
+:Y 667,915,0,189,-118,90 2 0006 Ydieresis
+tm 1000,718,0,159,-129,90 2 0007 trademark
+aq 238,718,0,133,-115,90 2 0010 quotesingle
+space 278 0 0040
+! 333,718,0,114,-44,90 2 0041 exclam
+" 474,718,0,105,-143,90 2 0042 quotedbl
+# 556,698,0,138,-10,90 2 0043 numbersign
+sh "
+$ 556,775,115,116,-17,90 2 0044 dollar
+Do "
+% 889,710,19,62,-86,62 2 0045 percent
+& 722,718,19,60,-39,60 2 0046 ampersand
+' 278,718,0,134,-117,90 2 0047 quoteright
+( 333,734,208,187,-26,90 3 0050 parenleft
+) 333,734,208,86,75,86 3 0051 parenright
+* 389,718,0,142,-96,90 2 0052 asterisk
++ 584,506,0,76,-32,76 0 0053 plus
+, 278,146,168,17,22,17 0 0054 comma
+- 333,345,0,96,-23,90 0 0055 hyphen
+hy "
+char173 "
+. 278,146,0,17,-14,17 0 0056 period
+/ 278,737,19,240,87,90 2 0057 slash
+sl "
+0 556,710,19,111,-36,90 2 0060 zero
+1 556,710,0,23,-123,23 2 0061 one
+2 556,710,0,113,24,90 2 0062 two
+3 556,710,19,102,-15,90 2 0063 three
+4 556,710,0,92,-10,90 2 0064 four
+5 556,698,19,130,-14,90 2 0065 five
+6 556,710,19,113,-35,90 2 0066 six
+7 556,698,0,170,-75,90 2 0067 seven
+8 556,710,19,110,-19,90 2 0070 eight
+9 556,710,19,109,-28,90 2 0071 nine
+: 333,512,0,68,-42,68 0 0072 colon
+; 333,512,168,68,-6,68 0 0073 semicolon
+< 584,514,8,121,-32,90 0 0074 less
+= 584,419,0,99,-8,90 0 0075 equal
+> 584,514,8,75,14,75 0 0076 greater
+? 611,727,0,110,-115,90 2 0077 question
+@ 975,737,19,29,-136,29 2 0100 at
+at "
+A 722,718,0,30,30,30 2 0101 A
+B 722,718,0,92,-26,90 2 0102 B
+C 722,737,19,117,-57,90 2 0103 C
+D 722,718,0,105,-26,90 2 0104 D
+E 667,718,0,140,-26,90 2 0105 E
+F 611,718,0,179,-26,90 2 0106 F
+G 778,737,19,89,-58,89 2 0107 G
+H 722,718,0,132,-21,90 2 0110 H
+I 278,718,0,139,-14,90 2 0111 I
+J 556,718,18,131,-10,90 2 0112 J
+K 722,718,0,186,-37,90 2 0113 K
+L 611,718,0,50,-26,50 2 0114 L
+M 833,718,0,135,-19,90 2 0115 M
+N 722,718,0,135,-19,90 2 0116 N
+O 778,737,19,95,-57,90 2 0117 O
+P 667,718,0,121,-26,90 2 0120 P
+Q 778,737,52,95,-57,90 2 0121 Q
+R 722,718,0,106,-26,90 2 0122 R
+S 667,737,19,101,-31,90 2 0123 S
+T 611,718,0,190,-90,90 2 0124 T
+U 722,718,19,132,-66,90 2 0125 U
+V 667,718,0,184,-122,90 2 0126 V
+W 944,718,0,188,-119,90 2 0127 W
+X 667,718,0,174,36,90 2 0130 X
+Y 667,718,0,189,-118,90 2 0131 Y
+Z 611,718,0,176,25,90 2 0132 Z
+[ 333,722,196,179,29,90 2 0133 bracketleft
+lB "
+\ 278,737,19,79,-74,79 2 0134 backslash
+rs "
+] 333,722,196,140,68,90 2 0135 bracketright
+rB "
+a^ 333,750,0,188,-68,90 2 0136 circumflex
+^ "
+_ 556,0,125,34,77,34 0 0137 underscore
+` 278,727,0,133,-115,90 2 0140 quoteleft
+oq "
+a 556,546,14,77,-5,77 0 0141 a
+b 611,718,14,84,-11,84 2 0142 b
+c 556,546,14,93,-29,90 0 0143 c
+d 611,718,14,143,-32,90 2 0144 d
+e 556,546,14,87,-20,87 0 0145 e
+f 333,727,0,186,-37,90 2 0146 f
+g 611,546,217,105,12,90 1 0147 g
+h 611,718,0,68,-15,68 2 0150 h
+i 278,725,0,135,-19,90 2 0151 i
+j 278,725,214,135,92,90 3 0152 j
+k 556,718,0,164,-19,90 2 0153 k
+l 278,718,0,134,-19,90 2 0154 l
+m 889,546,0,70,-14,70 0 0155 m
+n 611,546,0,68,-15,68 0 0156 n
+o 611,546,14,82,-32,82 0 0157 o
+p 611,546,207,84,32,84 1 0160 p
+q 611,546,207,104,-30,90 1 0161 q
+r 389,546,0,150,-14,90 0 0162 r
+s 556,546,14,78,-13,78 0 0163 s
+t 333,676,6,139,-50,90 2 0164 t
+u 611,532,14,97,-48,90 0 0165 u
+v 556,532,0,150,-76,90 0 0166 v
+w 778,532,0,154,-73,90 0 0167 w
+x 556,532,0,142,35,90 0 0170 x
+y 556,532,214,146,8,90 1 0171 y
+z 500,532,0,133,30,90 0 0172 z
+lC 389,722,196,179,-44,90 2 0173 braceleft
+{ "
+ba 280,737,19,123,-30,90 2 0174 bar
+| "
+rC 389,722,196,68,68,68 2 0175 braceright
+} "
+a~ 333,737,0,224,-63,90 2 0176 tilde
+~ "
+bq 278,127,146,8,9,8 0 0200 quotesinglbase
+Fo 556,484,0,65,-85,65 0 0201 guillemotleft
+char171 "
+Fc 556,484,0,34,-54,34 0 0202 guillemotright
+char187 "
+bu 350,524,0,120,-33,90 0 0203 bullet
+Fn 556,737,210,163,100,90 3 0204 florin
+f/ 167,710,19,370,224,90 2 0205 fraction
+%0 1000,710,19,88,-26,88 2 0206 perthousand
+dg 556,718,171,120,-68,90 2 0207 dagger
+dd 556,718,171,122,4,90 2 0210 daggerdbl
+en 556,333,0,121,2,90 0 0211 endash
+em 1000,333,0,121,2,90 0 0212 emdash
+fi 611,727,0,135,-37,90 2 0214 fi
+fl 611,727,0,134,-37,90 2 0215 fl
+.i 278,532,0,94,-19,90 0 0220 dotlessi
+ga 333,750,0,70,-86,70 2 0222 grave
+a" 333,750,0,362,-87,90 2 0223 hungarumlaut
+a. 333,729,0,102,-185,90 2 0224 dotaccent
+ab 333,750,0,211,-106,90 2 0225 breve
+ah 333,750,0,219,-99,90 2 0226 caron
+ao 333,776,0,137,-150,90 2 0227 ring
+ho 333,0,228,0,9 1 0230 ogonek
+lq 500,727,0,138,-110,90 2 0231 quotedblleft
+rq 500,718,0,139,-112,90 2 0232 quotedblright
+oe 944,546,14,83,-32,83 0 0233 oe
+/l 278,718,0,179,10,90 2 0234 lslash
+Bq 500,127,146,13,14,13 0 0235 quotedblbase
+OE 1000,737,19,164,-49,90 2 0236 OE
+/L 611,718,0,50,16,50 2 0237 Lslash
+r! 333,532,186,70,0,70 0 0241 exclamdown
+char161 "
+ct 556,628,118,93,-29,90 0 0242 cent
+char162 "
+Po 556,718,16,129,0,90 2 0243 sterling
+char163 "
+Cs 556,636,0,174,23,90 0 0244 currency
+char164 "
+Ye 556,698,0,207,-10,90 2 0245 yen
+char165 "
+bb 280,737,19,123,-30,90 2 0246 brokenbar
+char166 "
+sc 556,727,184,92,-11,90 2 0247 section
+char167 "
+ad 333,729,0,199,-87,90 2 0250 dieresis
+char168 "
+co 737,737,19,148,-6,90 2 0251 copyright
+char169 "
+Of 370,737,0,145,-42,90 2 0252 ordfeminine
+char170 "
+fo 333,484,0,70,-80,70 0 0253 guilsinglleft
+no 584,419,0,99,-55,90 0 0254 logicalnot
+char172 "
+\- 584,309,0,76,-32,76 0 0255 minus
+rg 737,737,19,147,-5,90 2 0256 registered
+char174 "
+a- 333,678,0,200,-72,90 2 0257 macron
+char175 "
+de 400,712,0,117,-125,90 2 0260 degree
+char176 "
+char177 584,506,0,91,10,90 0 0261 plusminus
+S2 333,710,0,166,-19,90 2 0262 twosuperior
+char178 "
+S3 333,710,0,158,-41,90 2 0263 threesuperior
+char179 "
+aa 333,750,0,232,-186,90 2 0264 acute
+char180 "
+char181 611,532,207,97,28,90 1 0265 mu
+ps 556,700,191,182,-48,90 2 0266 paragraph
+char182 "
+char183 278,334,0,48,-60,48 0 0267 periodcentered
+ac 333,0,228,0,87 1 0270 cedilla
+char184 "
+S1 333,710,0,105,-98,90 2 0271 onesuperior
+char185 "
+Om 365,737,0,170,-42,90 2 0272 ordmasculine
+char186 "
+fc 333,484,0,39,-49,39 0 0273 guilsinglright
+14 834,710,19,22,-82,22 2 0274 onequarter
+char188 "
+12 834,710,19,74,-82,74 2 0275 onehalf
+char189 "
+34 834,710,19,55,-49,55 2 0276 threequarters
+char190 "
+r? 611,532,195,0,-3 0 0277 questiondown
+char191 "
+`A 722,936,0,30,30,30 2 0300 Agrave
+char192 "
+'A 722,936,0,78,30,78 2 0301 Aacute
+char193 "
+^A 722,936,0,34,30,34 2 0302 Acircumflex
+char194 "
+~A 722,923,0,69,30,69 2 0303 Atilde
+char195 "
+:A 722,915,0,44,30,44 2 0304 Adieresis
+char196 "
+oA 722,962,0,30,30,30 2 0305 Aring
+char197 "
+AE 1000,718,0,150,45,90 2 0306 AE
+char198 "
+,C 722,737,228,117,-57,90 3 0307 Ccedilla
+char199 "
+`E 667,936,0,140,-26,90 2 0310 Egrave
+char200 "
+'E 667,936,0,140,-26,90 2 0311 Eacute
+char201 "
+^E 667,936,0,140,-26,90 2 0312 Ecircumflex
+char202 "
+:E 667,915,0,140,-26,90 2 0313 Edieresis
+char203 "
+`I 278,936,0,139,-14,90 2 0314 Igrave
+char204 "
+'I 278,936,0,300,-14,90 2 0315 Iacute
+char205 "
+^I 278,936,0,256,-14,90 2 0316 Icircumflex
+char206 "
+:I 278,915,0,266,-14,90 2 0317 Idieresis
+char207 "
+-D 722,718,0,105,-12,90 2 0320 Eth
+char208 "
+~N 722,923,0,135,-19,90 2 0321 Ntilde
+char209 "
+`O 778,936,19,95,-57,90 2 0322 Ograve
+char210 "
+'O 778,936,19,95,-57,90 2 0323 Oacute
+char211 "
+^O 778,936,19,95,-57,90 2 0324 Ocircumflex
+char212 "
+~O 778,923,19,95,-57,90 2 0325 Otilde
+char213 "
+:O 778,915,19,95,-57,90 2 0326 Odieresis
+char214 "
+char215 584,505,0,101,-7,90 0 0327 multiply
+/O 778,745,27,166,15,90 2 0330 Oslash
+char216 "
+`U 722,936,19,132,-66,90 2 0331 Ugrave
+char217 "
+'U 722,936,19,132,-66,90 2 0332 Uacute
+char218 "
+^U 722,936,19,132,-66,90 2 0333 Ucircumflex
+char219 "
+:U 722,915,19,132,-66,90 2 0334 Udieresis
+char220 "
+'Y 667,936,0,189,-118,90 2 0335 Yacute
+char221 "
+TP 667,718,0,99,-26,90 2 0336 Thorn
+char222 "
+ss 611,731,14,96,-19,90 2 0337 germandbls
+char223 "
+`a 556,750,14,77,-5,77 2 0340 agrave
+char224 "
+'a 556,750,14,121,-5,90 2 0341 aacute
+char225 "
+^a 556,750,14,77,-5,77 2 0342 acircumflex
+char226 "
+~a 556,737,14,113,-5,90 2 0343 atilde
+char227 "
+:a 556,729,14,88,-5,88 2 0344 adieresis
+char228 "
+oa 556,776,14,77,-5,77 2 0345 aring
+char229 "
+ae 889,546,14,84,-6,84 0 0346 ae
+char230 "
+,c 556,546,228,93,-29,90 1 0347 ccedilla
+char231 "
+`e 556,750,14,87,-20,87 2 0350 egrave
+char232 "
+'e 556,750,14,121,-20,90 2 0351 eacute
+char233 "
+^e 556,750,14,87,-20,87 2 0352 ecircumflex
+char234 "
+:e 556,729,14,88,-20,88 2 0353 edieresis
+char235 "
+`i 278,750,0,98,-19,90 2 0354 igrave
+char236 "
+'i 278,750,0,260,-19,90 2 0355 iacute
+char237 "
+^i 278,750,0,216,-19,90 2 0356 icircumflex
+char238 "
+:i 278,729,0,227,-19,90 2 0357 idieresis
+char239 "
+Sd 611,737,14,109,-32,90 2 0360 eth
+char240 "
+~n 611,737,0,85,-15,85 2 0361 ntilde
+char241 "
+`o 611,750,14,82,-32,82 2 0362 ograve
+char242 "
+'o 611,750,14,93,-32,90 2 0363 oacute
+char243 "
+^o 611,750,14,82,-32,82 2 0364 ocircumflex
+char244 "
+~o 611,737,14,85,-32,85 2 0365 otilde
+char245 "
+:o 611,729,14,82,-32,82 2 0366 odieresis
+char246 "
+char247 584,548,42,76,-32,76 0 0367 divide
+/o 611,560,29,140,28,90 0 0370 oslash
+char248 "
+`u 611,750,14,97,-48,90 2 0371 ugrave
+char249 "
+'u 611,750,14,97,-48,90 2 0372 uacute
+char250 "
+^u 611,750,14,97,-48,90 2 0373 ucircumflex
+char251 "
+:u 611,729,14,97,-48,90 2 0374 udieresis
+char252 "
+'y 556,750,214,146,8,90 3 0375 yacute
+char253 "
+Tp 611,718,208,84,32,84 3 0376 thorn
+char254 "
+:y 556,729,214,146,8,90 3 0377 ydieresis
+char255 "
diff --git a/gnu/usr.bin/groff/devps/HI b/gnu/usr.bin/groff/devps/HI
new file mode 100644
index 0000000..bfdcb32
--- /dev/null
+++ b/gnu/usr.bin/groff/devps/HI
@@ -0,0 +1,617 @@
+name HI
+internalname Helvetica-Oblique
+slant 12
+spacewidth 278
+encoding text.enc
+ligatures fi fl 0
+kernpairs
+A y -40
+A w -40
+A v -40
+A u -30
+A Y -100
+A W -50
+A V -70
+A U -50
+A T -120
+A Q -30
+A O -30
+A G -30
+A C -30
+B . -20
+B , -20
+B U -10
+C . -30
+C , -30
+D . -70
+D , -70
+D Y -90
+D W -40
+D V -70
+D A -40
+F r -45
+F . -150
+F o -30
+F e -30
+F , -150
+F a -50
+F A -80
+J u -20
+J . -30
+J , -30
+J a -20
+J A -20
+K y -50
+K u -30
+K o -40
+K e -40
+K O -50
+L y -30
+L ' -160
+L rq -140
+L Y -140
+L W -70
+L V -110
+L T -110
+O . -40
+O , -40
+O Y -70
+O X -60
+O W -30
+O V -50
+O T -40
+O A -20
+P . -180
+P o -50
+P e -50
+P , -180
+P a -40
+P A -120
+Q U -10
+R Y -50
+R W -30
+R V -50
+R U -40
+R T -30
+R O -20
+S . -20
+S , -20
+T y -120
+T w -120
+T u -120
+T ; -20
+T r -120
+T . -120
+T o -120
+T - -140
+T hy -140
+T char173 -140
+T e -120
+T , -120
+T : -20
+T a -120
+T O -40
+T A -120
+U . -40
+U , -40
+U A -40
+V u -70
+V ; -40
+V . -125
+V o -80
+V - -80
+V hy -80
+V char173 -80
+V e -80
+V , -125
+V : -40
+V a -70
+V O -40
+V G -40
+V A -80
+W y -20
+W u -30
+W . -80
+W o -30
+W - -40
+W hy -40
+W char173 -40
+W e -30
+W , -80
+W a -40
+W O -20
+W A -50
+Y u -110
+Y ; -60
+Y . -140
+Y o -140
+Y i -20
+Y - -140
+Y hy -140
+Y char173 -140
+Y e -140
+Y , -140
+Y : -60
+Y a -140
+Y O -85
+Y A -110
+a y -30
+a w -20
+a v -20
+b y -20
+b v -20
+b u -20
+b . -40
+b l -20
+b , -40
+b b -10
+c k -20
+c , -15
+, ' -100
+, rq -100
+e y -20
+e x -30
+e w -20
+e v -30
+e . -15
+e , -15
+f ' 50
+f rq 60
+f . -30
+f o -30
+f e -30
+f .i -28
+f , -30
+f a -30
+g r -10
+h y -30
+k o -20
+k e -20
+m y -15
+m u -10
+n y -15
+n v -20
+n u -10
+o y -30
+o x -30
+o w -15
+o v -15
+o . -40
+o , -40
+/o z -55
+char248 z -55
+/o y -70
+char248 y -70
+/o x -85
+char248 x -85
+/o w -70
+char248 w -70
+/o v -70
+char248 v -70
+/o u -55
+char248 u -55
+/o t -55
+char248 t -55
+/o s -55
+char248 s -55
+/o r -55
+char248 r -55
+/o q -55
+char248 q -55
+/o . -95
+char248 . -95
+/o p -55
+char248 p -55
+/o o -55
+char248 o -55
+/o n -55
+char248 n -55
+/o m -55
+char248 m -55
+/o l -55
+char248 l -55
+/o k -55
+char248 k -55
+/o j -55
+char248 j -55
+/o i -55
+char248 i -55
+/o h -55
+char248 h -55
+/o g -55
+char248 g -55
+/o f -55
+char248 f -55
+/o e -55
+char248 e -55
+/o d -55
+char248 d -55
+/o , -95
+char248 , -95
+/o c -55
+char248 c -55
+/o b -55
+char248 b -55
+/o a -55
+char248 a -55
+p y -30
+p . -35
+p , -35
+. ' -100
+. rq -100
+` ` -57
+` oq -57
+oq ` -57
+oq oq -57
+' s -50
+' r -50
+' ' -57
+' d -50
+r y 30
+r v 30
+r u 15
+r t 40
+r ; 30
+r . -50
+r p 30
+r n 25
+r m 25
+r l 15
+r k 15
+r i 15
+r , -50
+r : 30
+r a -10
+s w -30
+s . -15
+s , -15
+v . -80
+v o -25
+v e -25
+v , -80
+v a -25
+w . -60
+w o -10
+w e -10
+w , -60
+w a -15
+x e -30
+y . -100
+y o -20
+y e -20
+y , -100
+y a -20
+z o -15
+z e -15
+charset
+ha 469,688,0,120,8,89 2 0000 asciicircum
+ti 584,326,0,46,-61,46 0 0001 asciitilde
+vS 667,929,19,96,-40,89 2 0002 Scaron
+vZ 611,929,0,180,27,89 2 0003 Zcaron
+vs 500,734,15,102,-13,89 2 0004 scaron
+vz 500,734,0,121,19,89 2 0005 zcaron
+:Y 667,901,0,189,-117,89 2 0006 Ydieresis
+tm 1000,718,0,106,-136,89 2 0007 trademark
+aq 191,718,0,144,-107,89 2 0010 quotesingle
+space 278 0 0040
+! 278,718,0,112,-40,89 2 0041 exclam
+" 355,718,0,133,-118,89 2 0042 quotedbl
+# 556,688,0,125,-23,89 2 0043 numbersign
+sh "
+$ 556,775,115,111,-19,89 2 0044 dollar
+Do "
+% 889,703,19,50,-97,50 2 0045 percent
+& 667,718,15,30,-27,30 2 0046 ampersand
+' 222,718,0,138,-101,89 2 0047 quoteright
+( 333,733,207,171,-58,89 3 0050 parenleft
+) 333,733,207,54,59,54 3 0051 parenright
+* 389,718,0,136,-115,89 2 0052 asterisk
++ 584,505,0,72,-35,72 0 0053 plus
+, 278,106,147,0,-6 0 0054 comma
+- 333,322,0,74,-43,74 0 0055 hyphen
+hy "
+char173 "
+. 278,106,0,0,-37 0 0056 period
+/ 278,737,19,224,71,89 2 0057 slash
+sl "
+0 556,703,19,102,-43,89 2 0060 zero
+1 556,703,0,2,-157,2 2 0061 one
+2 556,703,0,111,24,89 2 0062 two
+3 556,703,19,104,-25,89 2 0063 three
+4 556,703,0,70,-11,70 2 0064 four
+5 556,688,19,115,-18,89 2 0065 five
+6 556,703,19,109,-41,89 2 0066 six
+7 556,688,0,163,-87,89 2 0067 seven
+8 556,703,19,101,-24,89 2 0070 eight
+9 556,703,19,103,-32,89 2 0071 nine
+: 278,516,0,73,-37,73 0 0072 colon
+; 278,516,147,73,-6,73 0 0073 semicolon
+< 584,495,0,107,-44,89 0 0074 less
+= 584,390,0,94,-13,89 0 0075 equal
+> 584,495,0,63,0,63 0 0076 greater
+? 556,727,0,104,-111,89 2 0077 question
+@ 1015,737,19,0,-165 2 0100 at
+at "
+A 667,718,0,37,36,37 2 0101 A
+B 667,718,0,95,-24,89 2 0102 B
+C 722,737,19,110,-58,89 2 0103 C
+D 722,718,0,92,-31,89 2 0104 D
+E 667,718,0,145,-36,89 2 0105 E
+F 611,718,0,175,-36,89 2 0106 F
+G 778,737,19,71,-61,71 2 0107 G
+H 722,718,0,127,-27,89 2 0110 H
+I 278,718,0,113,-41,89 2 0111 I
+J 500,718,19,131,3,89 2 0112 J
+K 667,718,0,191,-26,89 2 0113 K
+L 556,718,0,49,-26,49 2 0114 L
+M 833,718,0,131,-23,89 2 0115 M
+N 722,718,0,127,-26,89 2 0116 N
+O 778,737,19,98,-55,89 2 0117 O
+P 667,718,0,120,-36,89 2 0120 P
+Q 778,737,56,98,-55,89 2 0121 Q
+R 722,718,0,101,-38,89 2 0122 R
+S 667,737,19,96,-40,89 2 0123 S
+T 611,718,0,189,-98,89 2 0124 T
+U 722,718,19,125,-73,89 2 0125 U
+V 667,718,0,183,-123,89 2 0126 V
+W 944,718,0,187,-119,89 2 0127 W
+X 667,718,0,173,31,89 2 0130 X
+Y 667,718,0,189,-117,89 2 0131 Y
+Z 611,718,0,180,27,89 2 0132 Z
+[ 278,722,196,175,29,89 2 0133 bracketleft
+lB "
+\ 278,737,19,63,-90,63 2 0134 backslash
+rs "
+] 278,722,196,140,64,89 2 0135 bracketright
+rB "
+a^ 333,734,0,155,-97,89 2 0136 circumflex
+^ "
+_ 556,0,125,34,77,34 0 0137 underscore
+` 222,725,0,151,-115,89 2 0140 quoteleft
+oq "
+a 556,538,15,53,-11,53 0 0141 a
+b 556,718,15,78,-8,78 2 0142 b
+c 500,538,15,103,-24,89 0 0143 c
+d 556,718,15,146,-34,89 2 0144 d
+e 556,538,15,72,-34,72 0 0145 e
+f 278,728,0,188,-36,89 2 0146 f
+g 556,538,220,104,8,89 1 0147 g
+h 556,718,0,67,-15,67 2 0150 h
+i 222,718,0,136,-17,89 2 0151 i
+j 222,718,210,136,110,89 3 0152 j
+k 500,718,0,150,-17,89 2 0153 k
+l 222,718,0,136,-17,89 2 0154 l
+m 833,538,0,69,-15,69 0 0155 m
+n 556,538,0,67,-15,67 0 0156 n
+o 556,538,14,79,-33,79 0 0157 o
+p 556,538,207,78,36,78 1 0160 p
+q 556,538,207,99,-34,89 1 0161 q
+r 333,538,0,163,-27,89 0 0162 r
+s 500,538,15,79,-13,79 0 0163 s
+t 278,669,7,140,-52,89 2 0164 t
+u 556,523,15,94,-44,89 0 0165 u
+v 500,523,0,153,-69,89 0 0166 v
+w 722,523,0,148,-75,89 0 0167 w
+x 500,523,0,144,39,89 0 0170 x
+y 500,523,214,150,35,89 1 0171 y
+z 500,523,0,121,19,89 0 0172 z
+lC 334,722,196,161,-42,89 2 0173 braceleft
+{ "
+ba 260,737,19,114,-40,89 2 0174 bar
+| "
+rC 334,722,196,70,50,70 2 0175 braceright
+} "
+a~ 333,722,0,207,-75,89 2 0176 tilde
+~ "
+bq 222,106,149,8,29,8 0 0200 quotesinglbase
+Fo 556,446,0,48,-96,48 0 0201 guillemotleft
+char171 "
+Fc 556,446,0,22,-70,22 0 0202 guillemotright
+char187 "
+bu 350,517,0,113,-41,89 0 0203 bullet
+Fn 556,737,207,148,102,89 3 0204 florin
+f/ 167,703,19,365,220,89 2 0205 fraction
+%0 1000,703,19,79,-38,79 2 0206 perthousand
+dg 556,718,159,116,-85,89 2 0207 dagger
+dd 556,718,159,117,-2,89 2 0210 daggerdbl
+en 556,313,0,117,-1,89 0 0211 endash
+em 1000,313,0,117,-1,89 0 0212 emdash
+fi 500,728,0,137,-36,89 2 0214 fi
+fl 500,728,0,135,-36,89 2 0215 fl
+.i 278,523,0,66,-45,66 0 0220 dotlessi
+ga 333,734,0,54,-120,54 2 0222 grave
+a" 333,734,0,282,-107,89 2 0223 hungarumlaut
+a. 333,706,0,79,-199,79 2 0224 dotaccent
+ab 333,731,0,193,-117,89 2 0225 breve
+ah 333,734,0,185,-127,89 2 0226 caron
+ao 333,756,0,119,-164,89 2 0227 ring
+ho 333,0,225,0,7 1 0230 ogonek
+lq 333,725,0,178,-88,89 2 0231 quotedblleft
+rq 333,718,0,165,-74,89 2 0232 quotedblright
+oe 944,538,15,70,-33,70 0 0233 oe
+/l 222,718,0,175,9,89 2 0234 lslash
+Bq 333,106,149,35,56,35 0 0235 quotedblbase
+OE 1000,737,19,166,-48,89 2 0236 OE
+/L 556,718,0,49,9,49 2 0237 Lslash
+r! 333,523,195,43,-27,43 0 0241 exclamdown
+char161 "
+ct 556,623,115,78,-45,78 0 0242 cent
+char162 "
+Po 556,718,16,128,1,89 2 0243 sterling
+char163 "
+Cs 556,603,0,140,-10,89 0 0244 currency
+char164 "
+Ye 556,688,0,193,-31,89 2 0245 yen
+char165 "
+bb 260,737,19,114,-40,89 2 0246 brokenbar
+char166 "
+sc 556,737,191,78,-26,78 2 0247 section
+char167 "
+ad 333,706,0,160,-118,89 2 0250 dieresis
+char168 "
+co 737,737,19,150,-4,89 2 0251 copyright
+char169 "
+Of 370,737,0,129,-50,89 2 0252 ordfeminine
+char170 "
+fo 333,446,0,57,-87,57 0 0253 guilsinglleft
+no 584,390,0,94,-56,89 0 0254 logicalnot
+char172 "
+\- 584,289,0,72,-35,72 0 0255 minus
+rg 737,737,19,150,-4,89 2 0256 registered
+char174 "
+a- 333,684,0,185,-93,89 2 0257 macron
+char175 "
+de 400,703,0,118,-119,89 2 0260 degree
+char176 "
+char177 584,506,0,84,11,84 0 0261 plusminus
+S2 333,703,0,166,-14,89 2 0262 twosuperior
+char178 "
+S3 333,703,0,153,-40,89 2 0263 threesuperior
+char179 "
+aa 333,734,0,192,-198,89 2 0264 acute
+char180 "
+char181 556,523,207,94,26,89 1 0265 mu
+ps 537,718,173,163,-76,89 2 0266 paragraph
+char182 "
+char183 278,315,0,29,-79,29 0 0267 periodcentered
+ac 333,0,225,0,48 1 0270 cedilla
+char184 "
+S1 333,703,0,88,-116,88 2 0271 onesuperior
+char185 "
+Om 365,737,0,153,-50,89 2 0272 ordmasculine
+char186 "
+fc 333,446,0,31,-61,31 0 0273 guilsinglright
+14 834,703,19,18,-100,18 2 0274 onequarter
+char188 "
+12 834,703,19,55,-64,55 2 0275 onehalf
+char189 "
+34 834,703,19,77,-80,77 2 0276 threequarters
+char190 "
+r? 611,525,201,0,-35 0 0277 questiondown
+char191 "
+`A 667,929,0,37,36,37 2 0300 Agrave
+char192 "
+'A 667,929,0,66,36,66 2 0301 Aacute
+char193 "
+^A 667,929,0,37,36,37 2 0302 Acircumflex
+char194 "
+~A 667,917,0,82,36,82 2 0303 Atilde
+char195 "
+:A 667,901,0,37,36,37 2 0304 Adieresis
+char196 "
+oA 667,931,0,37,36,37 2 0305 Aring
+char197 "
+AE 1000,718,0,147,42,89 2 0306 AE
+char198 "
+,C 722,737,225,110,-58,89 3 0307 Ccedilla
+char199 "
+`E 667,929,0,145,-36,89 2 0310 Egrave
+char200 "
+'E 667,929,0,145,-36,89 2 0311 Eacute
+char201 "
+^E 667,929,0,145,-36,89 2 0312 Ecircumflex
+char202 "
+:E 667,901,0,145,-36,89 2 0313 Edieresis
+char203 "
+`I 278,929,0,123,-41,89 2 0314 Igrave
+char204 "
+'I 278,929,0,261,-41,89 2 0315 Iacute
+char205 "
+^I 278,929,0,224,-41,89 2 0316 Icircumflex
+char206 "
+:I 278,901,0,230,-41,89 2 0317 Idieresis
+char207 "
+-D 722,718,0,92,-19,89 2 0320 Eth
+char208 "
+~N 722,917,0,127,-26,89 2 0321 Ntilde
+char209 "
+`O 778,929,19,98,-55,89 2 0322 Ograve
+char210 "
+'O 778,929,19,98,-55,89 2 0323 Oacute
+char211 "
+^O 778,929,19,98,-55,89 2 0324 Ocircumflex
+char212 "
+~O 778,917,19,98,-55,89 2 0325 Otilde
+char213 "
+:O 778,901,19,98,-55,89 2 0326 Odieresis
+char214 "
+char215 584,506,0,108,0,89 0 0327 multiply
+/O 778,737,19,162,7,89 2 0330 Oslash
+char216 "
+`U 722,929,19,125,-73,89 2 0331 Ugrave
+char217 "
+'U 722,929,19,125,-73,89 2 0332 Uacute
+char218 "
+^U 722,929,19,125,-73,89 2 0333 Ucircumflex
+char219 "
+:U 722,901,19,125,-73,89 2 0334 Udieresis
+char220 "
+'Y 667,929,0,189,-117,89 2 0335 Yacute
+char221 "
+TP 667,718,0,95,-36,89 2 0336 Thorn
+char222 "
+ss 611,728,15,97,-17,89 2 0337 germandbls
+char223 "
+`a 556,734,15,53,-11,53 2 0340 agrave
+char224 "
+'a 556,734,15,81,-11,81 2 0341 aacute
+char225 "
+^a 556,734,15,53,-11,53 2 0342 acircumflex
+char226 "
+~a 556,722,15,86,-11,86 2 0343 atilde
+char227 "
+:a 556,706,15,53,-11,53 2 0344 adieresis
+char228 "
+oa 556,756,15,53,-11,53 2 0345 aring
+char229 "
+ae 889,538,15,70,-11,70 0 0346 ae
+char230 "
+,c 500,538,225,103,-24,89 1 0347 ccedilla
+char231 "
+`e 556,734,15,72,-34,72 2 0350 egrave
+char232 "
+'e 556,734,15,81,-34,81 2 0351 eacute
+char233 "
+^e 556,734,15,72,-34,72 2 0352 ecircumflex
+char234 "
+:e 556,706,15,72,-34,72 2 0353 edieresis
+char235 "
+`i 278,734,0,82,-45,82 2 0354 igrave
+char236 "
+'i 278,734,0,220,-45,89 2 0355 iacute
+char237 "
+^i 278,734,0,183,-45,89 2 0356 icircumflex
+char238 "
+:i 278,706,0,188,-45,89 2 0357 idieresis
+char239 "
+Sd 556,737,15,111,-31,89 2 0360 eth
+char240 "
+~n 556,722,0,86,-15,86 2 0361 ntilde
+char241 "
+`o 556,734,14,79,-33,79 2 0362 ograve
+char242 "
+'o 556,734,14,81,-33,81 2 0363 oacute
+char243 "
+^o 556,734,14,79,-33,79 2 0364 ocircumflex
+char244 "
+~o 556,722,14,96,-33,89 2 0365 otilde
+char245 "
+:o 556,706,14,79,-33,79 2 0366 odieresis
+char246 "
+char247 584,524,19,72,-35,72 0 0367 divide
+/o 611,545,22,86,21,86 0 0370 oslash
+char248 "
+`u 556,734,15,94,-44,89 2 0371 ugrave
+char249 "
+'u 556,734,15,94,-44,89 2 0372 uacute
+char250 "
+^u 556,734,15,94,-44,89 2 0373 ucircumflex
+char251 "
+:u 556,706,15,94,-44,89 2 0374 udieresis
+char252 "
+'y 500,734,214,150,35,89 3 0375 yacute
+char253 "
+Tp 556,718,207,78,36,78 3 0376 thorn
+char254 "
+:y 500,706,214,150,35,89 3 0377 ydieresis
+char255 "
diff --git a/gnu/usr.bin/groff/devps/HNB b/gnu/usr.bin/groff/devps/HNB
new file mode 100644
index 0000000..6e64674
--- /dev/null
+++ b/gnu/usr.bin/groff/devps/HNB
@@ -0,0 +1,546 @@
+name HNB
+internalname Helvetica-Narrow-Bold
+spacewidth 228
+encoding text.enc
+ligatures fi fl 0
+kernpairs
+A y -24
+A w -24
+A v -32
+A u -24
+A Y -89
+A W -48
+A V -65
+A U -40
+A T -73
+A Q -32
+A O -32
+A G -40
+A C -32
+B U -7
+B A -24
+D . -24
+D , -24
+D Y -56
+D W -32
+D V -32
+D A -32
+F . -81
+F , -81
+F a -15
+F A -65
+J u -15
+J . -15
+J , -15
+J A -15
+K y -32
+K u -24
+K o -28
+K e -11
+K O -24
+L y -24
+L ' -114
+L rq -114
+L Y -97
+L W -65
+L V -89
+L T -73
+O . -32
+O , -32
+O Y -56
+O X -40
+O W -40
+O V -40
+O T -32
+O A -40
+P . -97
+P o -32
+P e -24
+P , -97
+P a -24
+P A -81
+Q . 16
+Q , 16
+Q U -7
+R Y -40
+R W -32
+R V -40
+R U -15
+R T -15
+R O -15
+T y -48
+T w -48
+T u -73
+T ; -32
+T r -65
+T . -65
+T o -65
+T - -97
+T hy -97
+T char173 -97
+T e -48
+T , -65
+T : -32
+T a -65
+T O -32
+T A -73
+U . -24
+U , -24
+U A -40
+V u -48
+V ; -32
+V . -97
+V o -73
+V - -65
+V hy -65
+V char173 -65
+V e -40
+V , -97
+V : -32
+V a -48
+V O -40
+V G -40
+V A -65
+W y -15
+W u -36
+W ; -7
+W . -65
+W o -48
+W - -32
+W hy -32
+W char173 -32
+W e -28
+W , -65
+W : -7
+W a -32
+W O -15
+W A -48
+Y u -81
+Y ; -40
+Y . -81
+Y o -81
+Y e -65
+Y , -81
+Y : -40
+Y a -73
+Y O -56
+Y A -89
+a y -15
+a w -11
+a v -11
+a g -7
+b y -15
+b v -15
+b u -15
+b l -7
+c y -7
+c l -15
+c k -15
+c h -7
+, ' -97
+, rq -97
+d y -11
+d w -11
+d v -11
+d d -7
+e y -11
+e x -11
+e w -11
+e v -11
+e . 16
+e , 8
+f ' 25
+f rq 25
+f . -7
+f o -15
+f e -7
+f , -7
+g g -7
+g e 8
+h y -15
+k o -11
+l y -11
+l w -11
+m y -24
+m u -15
+n y -15
+n v -32
+n u -7
+o y -15
+o x -24
+o w -11
+o v -15
+p y -11
+. ' -97
+. rq -97
+` ` -37
+` oq -37
+oq ` -37
+oq oq -37
+' v -15
+' s -48
+' r -32
+' ' -37
+' l -15
+' d -65
+r y 8
+r v 8
+r t 16
+r s -11
+r q -15
+r . -48
+r o -15
+r - -15
+r hy -15
+r char173 -15
+r g -11
+r d -15
+r , -48
+r c -15
+s w -11
+v . -65
+v o -24
+v , -65
+v a -15
+w . -32
+w o -15
+w , -32
+x e -7
+y . -65
+y o -20
+y e -7
+y , -65
+y a -24
+z e 8
+charset
+ha 479,698 2 0000 asciicircum
+ti 479,343 0 0001 asciitilde
+vS 547,936,19 2 0002 Scaron
+vZ 501,936 2 0003 Zcaron
+vs 456,750,14 2 0004 scaron
+vz 410,750 2 0005 zcaron
+:Y 547,915 2 0006 Ydieresis
+tm 820,718 2 0007 trademark
+aq 195,718 2 0010 quotesingle
+space 228 0 0040
+! 273,718 2 0041 exclam
+" 389,718 2 0042 quotedbl
+# 456,698 2 0043 numbersign
+sh "
+$ 456,775,115 2 0044 dollar
+Do "
+% 729,710,19 2 0045 percent
+& 592,718,19 2 0046 ampersand
+' 228,718 2 0047 quoteright
+( 273,734,208 3 0050 parenleft
+) 273,734,208 3 0051 parenright
+* 319,718 2 0052 asterisk
++ 479,506 0 0053 plus
+, 228,146,168 0 0054 comma
+- 273,345 0 0055 hyphen
+hy "
+char173 "
+. 228,146 0 0056 period
+/ 228,737,19 2 0057 slash
+sl "
+0 456,710,19 2 0060 zero
+1 456,710 2 0061 one
+2 456,710 2 0062 two
+3 456,710,19 2 0063 three
+4 456,710 2 0064 four
+5 456,698,19 2 0065 five
+6 456,710,19 2 0066 six
+7 456,698 2 0067 seven
+8 456,710,19 2 0070 eight
+9 456,710,19 2 0071 nine
+: 273,512 0 0072 colon
+; 273,512,168 0 0073 semicolon
+< 479,514,8 0 0074 less
+= 479,419 0 0075 equal
+> 479,514,8 0 0076 greater
+? 501,727 2 0077 question
+@ 800,737,19 2 0100 at
+at "
+A 592,718 2 0101 A
+B 592,718 2 0102 B
+C 592,737,19 2 0103 C
+D 592,718 2 0104 D
+E 547,718 2 0105 E
+F 501,718 2 0106 F
+G 638,737,19 2 0107 G
+H 592,718 2 0110 H
+I 228,718 2 0111 I
+J 456,718,18 2 0112 J
+K 592,718 2 0113 K
+L 501,718 2 0114 L
+M 683,718 2 0115 M
+N 592,718 2 0116 N
+O 638,737,19 2 0117 O
+P 547,718 2 0120 P
+Q 638,737,52 2 0121 Q
+R 592,718 2 0122 R
+S 547,737,19 2 0123 S
+T 501,718 2 0124 T
+U 592,718,19 2 0125 U
+V 547,718 2 0126 V
+W 774,718 2 0127 W
+X 547,718 2 0130 X
+Y 547,718 2 0131 Y
+Z 501,718 2 0132 Z
+[ 273,722,196 2 0133 bracketleft
+lB "
+\ 228,737,19 2 0134 backslash
+rs "
+] 273,722,196 2 0135 bracketright
+rB "
+a^ 273,750 2 0136 circumflex
+^ "
+_ 456,0,125 0 0137 underscore
+` 228,727 2 0140 quoteleft
+oq "
+a 456,546,14 0 0141 a
+b 501,718,14 2 0142 b
+c 456,546,14 0 0143 c
+d 501,718,14 2 0144 d
+e 456,546,14 0 0145 e
+f 273,727 2 0146 f
+g 501,546,217 1 0147 g
+h 501,718 2 0150 h
+i 228,725 2 0151 i
+j 228,725,214 3 0152 j
+k 456,718 2 0153 k
+l 228,718 2 0154 l
+m 729,546 0 0155 m
+n 501,546 0 0156 n
+o 501,546,14 0 0157 o
+p 501,546,207 1 0160 p
+q 501,546,207 1 0161 q
+r 319,546 0 0162 r
+s 456,546,14 0 0163 s
+t 273,676,6 2 0164 t
+u 501,532,14 0 0165 u
+v 456,532 0 0166 v
+w 638,532 0 0167 w
+x 456,532 0 0170 x
+y 456,532,214 1 0171 y
+z 410,532 0 0172 z
+lC 319,722,196 2 0173 braceleft
+{ "
+ba 230,737,19 2 0174 bar
+| "
+rC 319,722,196 2 0175 braceright
+} "
+a~ 273,737 2 0176 tilde
+~ "
+bq 228,127,146 0 0200 quotesinglbase
+Fo 456,484 0 0201 guillemotleft
+char171 "
+Fc 456,484 0 0202 guillemotright
+char187 "
+bu 287,524 0 0203 bullet
+Fn 456,737,210 3 0204 florin
+f/ 137,710,19 2 0205 fraction
+%0 820,710,19 2 0206 perthousand
+dg 456,718,171 2 0207 dagger
+dd 456,718,171 2 0210 daggerdbl
+en 456,333 0 0211 endash
+em 820,333 0 0212 emdash
+fi 501,727 2 0214 fi
+fl 501,727 2 0215 fl
+.i 228,532 0 0220 dotlessi
+ga 273,750 2 0222 grave
+a" 273,750 2 0223 hungarumlaut
+a. 273,729 2 0224 dotaccent
+ab 273,750 2 0225 breve
+ah 273,750 2 0226 caron
+ao 273,776 2 0227 ring
+ho 273,0,228 1 0230 ogonek
+lq 410,727 2 0231 quotedblleft
+rq 410,718 2 0232 quotedblright
+oe 774,546,14 0 0233 oe
+/l 228,718 2 0234 lslash
+Bq 410,127,146 0 0235 quotedblbase
+OE 820,737,19 2 0236 OE
+/L 501,718 2 0237 Lslash
+r! 273,532,186 0 0241 exclamdown
+char161 "
+ct 456,628,118 0 0242 cent
+char162 "
+Po 456,718,16 2 0243 sterling
+char163 "
+Cs 456,636 0 0244 currency
+char164 "
+Ye 456,698 2 0245 yen
+char165 "
+bb 230,737,19 2 0246 brokenbar
+char166 "
+sc 456,727,184 2 0247 section
+char167 "
+ad 273,729 2 0250 dieresis
+char168 "
+co 604,737,19 2 0251 copyright
+char169 "
+Of 303,737 2 0252 ordfeminine
+char170 "
+fo 273,484 0 0253 guilsinglleft
+no 479,419 0 0254 logicalnot
+char172 "
+\- 479,309 0 0255 minus
+rg 604,737,19 2 0256 registered
+char174 "
+a- 273,678 2 0257 macron
+char175 "
+de 328,712 2 0260 degree
+char176 "
+char177 479,506 0 0261 plusminus
+S2 273,710 2 0262 twosuperior
+char178 "
+S3 273,710 2 0263 threesuperior
+char179 "
+aa 273,750 2 0264 acute
+char180 "
+char181 501,532,207 1 0265 mu
+ps 456,700,191 2 0266 paragraph
+char182 "
+char183 228,334 0 0267 periodcentered
+ac 273,0,228 1 0270 cedilla
+char184 "
+S1 273,710 2 0271 onesuperior
+char185 "
+Om 299,737 2 0272 ordmasculine
+char186 "
+fc 273,484 0 0273 guilsinglright
+14 684,710,19 2 0274 onequarter
+char188 "
+12 684,710,19 2 0275 onehalf
+char189 "
+34 684,710,19 2 0276 threequarters
+char190 "
+r? 501,532,195 0 0277 questiondown
+char191 "
+`A 592,936 2 0300 Agrave
+char192 "
+'A 592,936 2 0301 Aacute
+char193 "
+^A 592,936 2 0302 Acircumflex
+char194 "
+~A 592,923 2 0303 Atilde
+char195 "
+:A 592,915 2 0304 Adieresis
+char196 "
+oA 592,962 2 0305 Aring
+char197 "
+AE 820,718 2 0306 AE
+char198 "
+,C 592,737,228 3 0307 Ccedilla
+char199 "
+`E 547,936 2 0310 Egrave
+char200 "
+'E 547,936 2 0311 Eacute
+char201 "
+^E 547,936 2 0312 Ecircumflex
+char202 "
+:E 547,915 2 0313 Edieresis
+char203 "
+`I 228,936 2 0314 Igrave
+char204 "
+'I 228,936 2 0315 Iacute
+char205 "
+^I 228,936 2 0316 Icircumflex
+char206 "
+:I 228,915 2 0317 Idieresis
+char207 "
+-D 592,718 2 0320 Eth
+char208 "
+~N 592,923 2 0321 Ntilde
+char209 "
+`O 638,936,19 2 0322 Ograve
+char210 "
+'O 638,936,19 2 0323 Oacute
+char211 "
+^O 638,936,19 2 0324 Ocircumflex
+char212 "
+~O 638,923,19 2 0325 Otilde
+char213 "
+:O 638,915,19 2 0326 Odieresis
+char214 "
+char215 479,505 0 0327 multiply
+/O 638,745,27 2 0330 Oslash
+char216 "
+`U 592,936,19 2 0331 Ugrave
+char217 "
+'U 592,936,19 2 0332 Uacute
+char218 "
+^U 592,936,19 2 0333 Ucircumflex
+char219 "
+:U 592,915,19 2 0334 Udieresis
+char220 "
+'Y 547,936 2 0335 Yacute
+char221 "
+TP 547,718 2 0336 Thorn
+char222 "
+ss 501,731,14 2 0337 germandbls
+char223 "
+`a 456,750,14 2 0340 agrave
+char224 "
+'a 456,750,14 2 0341 aacute
+char225 "
+^a 456,750,14 2 0342 acircumflex
+char226 "
+~a 456,737,14 2 0343 atilde
+char227 "
+:a 456,729,14 2 0344 adieresis
+char228 "
+oa 456,776,14 2 0345 aring
+char229 "
+ae 729,546,14 0 0346 ae
+char230 "
+,c 456,546,228 1 0347 ccedilla
+char231 "
+`e 456,750,14 2 0350 egrave
+char232 "
+'e 456,750,14 2 0351 eacute
+char233 "
+^e 456,750,14 2 0352 ecircumflex
+char234 "
+:e 456,729,14 2 0353 edieresis
+char235 "
+`i 228,750 2 0354 igrave
+char236 "
+'i 228,750 2 0355 iacute
+char237 "
+^i 228,750 2 0356 icircumflex
+char238 "
+:i 228,729 2 0357 idieresis
+char239 "
+Sd 501,737,14 2 0360 eth
+char240 "
+~n 501,737 2 0361 ntilde
+char241 "
+`o 501,750,14 2 0362 ograve
+char242 "
+'o 501,750,14 2 0363 oacute
+char243 "
+^o 501,750,14 2 0364 ocircumflex
+char244 "
+~o 501,737,14 2 0365 otilde
+char245 "
+:o 501,729,14 2 0366 odieresis
+char246 "
+char247 479,548,42 0 0367 divide
+/o 501,560,29 0 0370 oslash
+char248 "
+`u 501,750,14 2 0371 ugrave
+char249 "
+'u 501,750,14 2 0372 uacute
+char250 "
+^u 501,750,14 2 0373 ucircumflex
+char251 "
+:u 501,729,14 2 0374 udieresis
+char252 "
+'y 456,750,214 3 0375 yacute
+char253 "
+Tp 501,718,208 3 0376 thorn
+char254 "
+:y 456,729,214 3 0377 ydieresis
+char255 "
diff --git a/gnu/usr.bin/groff/devps/HNBI b/gnu/usr.bin/groff/devps/HNBI
new file mode 100644
index 0000000..c0bb37e
--- /dev/null
+++ b/gnu/usr.bin/groff/devps/HNBI
@@ -0,0 +1,547 @@
+name HNBI
+internalname Helvetica-Narrow-BoldOblique
+slant 12
+spacewidth 228
+encoding text.enc
+ligatures fi fl 0
+kernpairs
+A y -30
+A w -30
+A v -40
+A u -30
+A Y -110
+A W -60
+A V -80
+A U -50
+A T -90
+A Q -40
+A O -40
+A G -50
+A C -40
+B U -10
+B A -30
+D . -30
+D , -30
+D Y -70
+D W -40
+D V -40
+D A -40
+F . -100
+F , -100
+F a -20
+F A -80
+J u -20
+J . -20
+J , -20
+J A -20
+K y -40
+K u -30
+K o -35
+K e -15
+K O -30
+L y -30
+L ' -140
+L rq -140
+L Y -120
+L W -80
+L V -110
+L T -90
+O . -40
+O , -40
+O Y -70
+O X -50
+O W -50
+O V -50
+O T -40
+O A -50
+P . -120
+P o -40
+P e -30
+P , -120
+P a -30
+P A -100
+Q . 20
+Q , 20
+Q U -10
+R Y -50
+R W -40
+R V -50
+R U -20
+R T -20
+R O -20
+T y -60
+T w -60
+T u -90
+T ; -40
+T r -80
+T . -80
+T o -80
+T - -120
+T hy -120
+T char173 -120
+T e -60
+T , -80
+T : -40
+T a -80
+T O -40
+T A -90
+U . -30
+U , -30
+U A -50
+V u -60
+V ; -40
+V . -120
+V o -90
+V - -80
+V hy -80
+V char173 -80
+V e -50
+V , -120
+V : -40
+V a -60
+V O -50
+V G -50
+V A -80
+W y -20
+W u -45
+W ; -10
+W . -80
+W o -60
+W - -40
+W hy -40
+W char173 -40
+W e -35
+W , -80
+W : -10
+W a -40
+W O -20
+W A -60
+Y u -100
+Y ; -50
+Y . -100
+Y o -100
+Y e -80
+Y , -100
+Y : -50
+Y a -90
+Y O -70
+Y A -110
+a y -20
+a w -15
+a v -15
+a g -10
+b y -20
+b v -20
+b u -20
+b l -10
+c y -10
+c l -20
+c k -20
+c h -10
+, ' -120
+, rq -120
+d y -15
+d w -15
+d v -15
+d d -10
+e y -15
+e x -15
+e w -15
+e v -15
+e . 20
+e , 10
+f ' 30
+f rq 30
+f . -10
+f o -20
+f e -10
+f , -10
+g g -10
+g e 10
+h y -20
+k o -15
+l y -15
+l w -15
+m y -30
+m u -20
+n y -20
+n v -40
+n u -10
+o y -20
+o x -30
+o w -15
+o v -20
+p y -15
+. ' -120
+. rq -120
+` ` -46
+` oq -46
+oq ` -46
+oq oq -46
+' v -20
+' s -60
+' r -40
+' ' -46
+' l -20
+' d -80
+r y 10
+r v 10
+r t 20
+r s -15
+r q -20
+r . -60
+r o -20
+r - -20
+r hy -20
+r char173 -20
+r g -15
+r d -20
+r , -60
+r c -20
+s w -15
+v . -80
+v o -30
+v , -80
+v a -20
+w . -40
+w o -20
+w , -40
+x e -10
+y . -80
+y o -25
+y e -10
+y , -80
+y a -30
+z e 10
+charset
+ha 479,698,0,55,-57,55 2 0000 asciicircum
+ti 479,343,0,44,-44,44 0 0001 asciitilde
+vS 547,936,19,91,-16,90 2 0002 Scaron
+vZ 501,936,0,153,30,90 2 0003 Zcaron
+vs 456,750,14,98,-2,90 2 0004 scaron
+vz 410,750,0,121,34,90 2 0005 zcaron
+:Y 547,915,0,164,-87,90 2 0006 Ydieresis
+tm 820,718,0,139,-96,90 2 0007 trademark
+aq 195,718,0,118,-85,90 2 0010 quotesingle
+space 228 0 0040
+! 273,718,0,102,-27,90 2 0041 exclam
+" 389,718,0,94,-108,90 2 0042 quotedbl
+# 456,698,0,122,1,90 2 0043 numbersign
+sh "
+$ 456,775,115,104,-5,90 2 0044 dollar
+Do "
+% 729,710,19,60,-62,60 2 0045 percent
+& 592,718,19,58,-23,58 2 0046 ampersand
+' 228,718,0,119,-87,90 2 0047 quoteright
+( 273,734,208,162,-12,90 3 0050 parenleft
+) 273,734,208,79,71,79 3 0051 parenright
+* 319,718,0,125,-70,90 2 0052 asterisk
++ 479,506,0,71,-17,71 0 0053 plus
+, 228,146,168,23,27,23 0 0054 comma
+- 273,345,0,88,-10,88 0 0055 hyphen
+hy "
+char173 "
+. 228,146,0,23,-2,23 0 0056 period
+/ 228,737,19,205,80,90 2 0057 slash
+sl "
+0 456,710,19,100,-21,90 2 0060 zero
+1 456,710,0,28,-92,28 2 0061 one
+2 456,710,0,102,29,90 2 0062 two
+3 456,710,19,93,-4,90 2 0063 three
+4 456,710,0,84,0,84 2 0064 four
+5 456,698,19,116,-3,90 2 0065 five
+6 456,710,19,101,-20,90 2 0066 six
+7 456,698,0,149,-52,90 2 0067 seven
+8 456,710,19,99,-7,90 2 0070 eight
+9 456,710,19,98,-14,90 2 0071 nine
+: 273,512,0,65,-25,65 0 0072 colon
+; 273,512,168,65,4,65 0 0073 semicolon
+< 479,514,8,108,-17,90 0 0074 less
+= 479,419,0,90,2,90 0 0075 equal
+> 479,514,8,71,20,71 0 0076 greater
+? 501,727,0,99,-85,90 2 0077 question
+@ 800,737,19,32,-102,32 2 0100 at
+at "
+A 592,718,0,34,34,34 2 0101 A
+B 592,718,0,84,-12,84 2 0102 B
+C 592,737,19,105,-38,90 2 0103 C
+D 592,718,0,95,-12,90 2 0104 D
+E 547,718,0,123,-12,90 2 0105 E
+F 501,718,0,155,-12,90 2 0106 F
+G 638,737,19,82,-39,82 2 0107 G
+H 592,718,0,117,-8,90 2 0110 H
+I 228,718,0,123,-2,90 2 0111 I
+J 456,718,18,116,1,90 2 0112 J
+K 592,718,0,161,-21,90 2 0113 K
+L 501,718,0,50,-12,50 2 0114 L
+M 683,718,0,119,-7,90 2 0115 M
+N 592,718,0,119,-7,90 2 0116 N
+O 638,737,19,87,-38,87 2 0117 O
+P 547,718,0,108,-12,90 2 0120 P
+Q 638,737,52,87,-38,87 2 0121 Q
+R 592,718,0,96,-12,90 2 0122 R
+S 547,737,19,91,-16,90 2 0123 S
+T 501,718,0,164,-64,90 2 0124 T
+U 592,718,19,117,-46,90 2 0125 U
+V 547,718,0,159,-91,90 2 0126 V
+W 774,718,0,163,-88,90 2 0127 W
+X 547,718,0,151,39,90 2 0130 X
+Y 547,718,0,164,-87,90 2 0131 Y
+Z 501,718,0,153,30,90 2 0132 Z
+[ 273,722,196,156,33,90 2 0133 bracketleft
+lB "
+\ 228,737,19,74,-51,74 2 0134 backslash
+rs "
+] 273,722,196,124,64,90 2 0135 bracketright
+rB "
+a^ 273,750,0,164,-47,90 2 0136 circumflex
+^ "
+_ 456,0,125,37,72,37 0 0137 underscore
+` 228,727,0,118,-86,90 2 0140 quoteleft
+oq "
+a 456,546,14,72,5,72 0 0141 a
+b 501,718,14,78,0,78 2 0142 b
+c 456,546,14,85,-15,85 0 0143 c
+d 501,718,14,126,-17,90 2 0144 d
+e 456,546,14,80,-8,80 0 0145 e
+f 273,727,0,162,-21,90 2 0146 f
+g 501,546,217,95,19,90 1 0147 g
+h 501,718,0,65,-3,65 2 0150 h
+i 228,725,0,120,-7,90 2 0151 i
+j 228,725,214,120,85,90 3 0152 j
+k 456,718,0,143,-7,90 2 0153 k
+l 228,718,0,119,-7,90 2 0154 l
+m 729,546,0,67,-2,67 0 0155 m
+n 501,546,0,65,-3,65 0 0156 n
+o 501,546,14,76,-17,76 0 0157 o
+p 501,546,207,78,35,78 1 0160 p
+q 501,546,207,94,-16,90 1 0161 q
+r 319,546,0,132,-2,90 0 0162 r
+s 456,546,14,73,-2,73 0 0163 s
+t 273,676,6,123,-32,90 2 0164 t
+u 501,532,14,89,-30,89 0 0165 u
+v 456,532,0,132,-53,90 0 0166 v
+w 638,532,0,135,-51,90 0 0167 w
+x 456,532,0,125,38,90 0 0170 x
+y 456,532,214,129,16,90 1 0171 y
+z 410,532,0,118,34,90 0 0172 z
+lC 319,722,196,156,-27,90 2 0173 braceleft
+{ "
+ba 230,737,19,109,-16,90 2 0174 bar
+| "
+rC 319,722,196,64,64,64 2 0175 braceright
+} "
+a~ 273,737,0,192,-42,90 2 0176 tilde
+~ "
+bq 228,127,146,16,16,16 0 0200 quotesinglbase
+Fo 456,484,0,62,-61,62 0 0201 guillemotleft
+char171 "
+Fc 456,484,0,37,-35,37 0 0202 guillemotright
+char187 "
+bu 287,524,0,108,-18,90 0 0203 bullet
+Fn 456,737,210,142,91,90 3 0204 florin
+f/ 137,710,19,312,193,90 2 0205 fraction
+%0 820,710,19,81,-12,81 2 0206 perthousand
+dg 456,718,171,107,-47,90 2 0207 dagger
+dd 456,718,171,109,12,90 2 0210 daggerdbl
+en 456,333,0,108,10,90 0 0211 endash
+em 820,333,0,108,10,90 0 0212 emdash
+fi 501,727,0,120,-21,90 2 0214 fi
+fl 501,727,0,119,-21,90 2 0215 fl
+.i 228,532,0,86,-7,86 0 0220 dotlessi
+ga 273,750,0,67,-62,67 2 0222 grave
+a" 273,750,0,306,-63,90 2 0223 hungarumlaut
+a. 273,729,0,93,-142,90 2 0224 dotaccent
+ab 273,750,0,182,-78,90 2 0225 breve
+ah 273,750,0,189,-73,90 2 0226 caron
+ao 273,776,0,121,-114,90 2 0227 ring
+ho 273,0,228,0,17 1 0230 ogonek
+lq 410,727,0,122,-82,90 2 0231 quotedblleft
+rq 410,718,0,123,-82,90 2 0232 quotedblright
+oe 774,546,14,77,-17,77 0 0233 oe
+/l 228,718,0,156,17,90 2 0234 lslash
+Bq 410,127,146,20,21,20 0 0235 quotedblbase
+OE 820,737,19,143,-31,90 2 0236 OE
+/L 501,718,0,50,22,50 2 0237 Lslash
+r! 273,532,186,67,9,67 0 0241 exclamdown
+char161 "
+ct 456,628,118,85,-15,85 0 0242 cent
+char162 "
+Po 456,718,16,114,9,90 2 0243 sterling
+char163 "
+Cs 456,636,0,152,28,90 0 0244 currency
+char164 "
+Ye 456,698,0,179,1,90 2 0245 yen
+char165 "
+bb 230,737,19,109,-16,90 2 0246 brokenbar
+char166 "
+sc 456,727,184,85,0,85 2 0247 section
+char167 "
+ad 273,729,0,172,-62,90 2 0250 dieresis
+char168 "
+co 604,737,19,131,4,90 2 0251 copyright
+char169 "
+Of 303,737,0,128,-25,90 2 0252 ordfeminine
+char170 "
+fo 273,484,0,66,-56,66 0 0253 guilsinglleft
+no 479,419,0,90,-36,90 0 0254 logicalnot
+char172 "
+\- 479,309,0,71,-17,71 0 0255 minus
+rg 604,737,19,130,5,90 2 0256 registered
+char174 "
+a- 273,678,0,173,-50,90 2 0257 macron
+char175 "
+de 328,712,0,105,-93,90 2 0260 degree
+char176 "
+char177 479,506,0,83,17,83 0 0261 plusminus
+S2 273,710,0,145,-7,90 2 0262 twosuperior
+char178 "
+S3 273,710,0,138,-25,90 2 0263 threesuperior
+char179 "
+aa 273,750,0,200,-144,90 2 0264 acute
+char180 "
+char181 501,532,207,89,32,89 1 0265 mu
+ps 456,700,191,158,-30,90 2 0266 paragraph
+char182 "
+char183 228,334,0,48,-40,48 0 0267 periodcentered
+ac 273,0,228,0,80 1 0270 cedilla
+char184 "
+S1 273,710,0,95,-71,90 2 0271 onesuperior
+char185 "
+Om 299,737,0,149,-25,90 2 0272 ordmasculine
+char186 "
+fc 273,484,0,41,-31,41 0 0273 guilsinglright
+14 684,710,19,27,-58,27 2 0274 onequarter
+char188 "
+12 684,710,19,70,-58,70 2 0275 onehalf
+char189 "
+34 684,710,19,54,-32,54 2 0276 threequarters
+char190 "
+r? 501,532,195,8,6,8 0 0277 questiondown
+char191 "
+`A 592,936,0,34,34,34 2 0300 Agrave
+char192 "
+'A 592,936,0,73,34,73 2 0301 Aacute
+char193 "
+^A 592,936,0,37,34,37 2 0302 Acircumflex
+char194 "
+~A 592,923,0,66,34,66 2 0303 Atilde
+char195 "
+:A 592,915,0,46,34,46 2 0304 Adieresis
+char196 "
+oA 592,962,0,34,34,34 2 0305 Aring
+char197 "
+AE 820,718,0,132,46,90 2 0306 AE
+char198 "
+,C 592,737,228,105,-38,90 3 0307 Ccedilla
+char199 "
+`E 547,936,0,123,-12,90 2 0310 Egrave
+char200 "
+'E 547,936,0,123,-12,90 2 0311 Eacute
+char201 "
+^E 547,936,0,123,-12,90 2 0312 Ecircumflex
+char202 "
+:E 547,915,0,123,-12,90 2 0313 Edieresis
+char203 "
+`I 228,936,0,123,-2,90 2 0314 Igrave
+char204 "
+'I 228,936,0,255,-2,90 2 0315 Iacute
+char205 "
+^I 228,936,0,219,-2,90 2 0316 Icircumflex
+char206 "
+:I 228,915,0,227,-2,90 2 0317 Idieresis
+char207 "
+-D 592,718,0,95,-1,90 2 0320 Eth
+char208 "
+~N 592,923,0,119,-7,90 2 0321 Ntilde
+char209 "
+`O 638,936,19,87,-38,87 2 0322 Ograve
+char210 "
+'O 638,936,19,87,-38,87 2 0323 Oacute
+char211 "
+^O 638,936,19,87,-38,87 2 0324 Ocircumflex
+char212 "
+~O 638,923,19,87,-38,87 2 0325 Otilde
+char213 "
+:O 638,915,19,87,-38,87 2 0326 Odieresis
+char214 "
+char215 479,505,0,91,3,90 0 0327 multiply
+/O 638,745,27,145,21,90 2 0330 Oslash
+char216 "
+`U 592,936,19,117,-46,90 2 0331 Ugrave
+char217 "
+'U 592,936,19,117,-46,90 2 0332 Uacute
+char218 "
+^U 592,936,19,117,-46,90 2 0333 Ucircumflex
+char219 "
+:U 592,915,19,117,-46,90 2 0334 Udieresis
+char220 "
+'Y 547,936,0,164,-87,90 2 0335 Yacute
+char221 "
+TP 547,718,0,91,-12,90 2 0336 Thorn
+char222 "
+ss 501,731,14,88,-7,88 2 0337 germandbls
+char223 "
+`a 456,750,14,72,5,72 2 0340 agrave
+char224 "
+'a 456,750,14,108,5,90 2 0341 aacute
+char225 "
+^a 456,750,14,72,5,72 2 0342 acircumflex
+char226 "
+~a 456,737,14,101,5,90 2 0343 atilde
+char227 "
+:a 456,729,14,81,5,81 2 0344 adieresis
+char228 "
+oa 456,776,14,72,5,72 2 0345 aring
+char229 "
+ae 729,546,14,78,4,78 0 0346 ae
+char230 "
+,c 456,546,228,85,-15,85 1 0347 ccedilla
+char231 "
+`e 456,750,14,80,-8,80 2 0350 egrave
+char232 "
+'e 456,750,14,108,-8,90 2 0351 eacute
+char233 "
+^e 456,750,14,80,-8,80 2 0352 ecircumflex
+char234 "
+:e 456,729,14,81,-8,81 2 0353 edieresis
+char235 "
+`i 228,750,0,90,-7,90 2 0354 igrave
+char236 "
+'i 228,750,0,222,-7,90 2 0355 iacute
+char237 "
+^i 228,750,0,186,-7,90 2 0356 icircumflex
+char238 "
+:i 228,729,0,195,-7,90 2 0357 idieresis
+char239 "
+Sd 501,737,14,98,-17,90 2 0360 eth
+char240 "
+~n 501,737,0,78,-3,78 2 0361 ntilde
+char241 "
+`o 501,750,14,76,-17,76 2 0362 ograve
+char242 "
+'o 501,750,14,86,-17,86 2 0363 oacute
+char243 "
+^o 501,750,14,76,-17,76 2 0364 ocircumflex
+char244 "
+~o 501,737,14,78,-17,78 2 0365 otilde
+char245 "
+:o 501,729,14,76,-17,76 2 0366 odieresis
+char246 "
+char247 479,548,42,71,-17,71 0 0367 divide
+/o 501,560,29,124,32,90 0 0370 oslash
+char248 "
+`u 501,750,14,89,-30,89 2 0371 ugrave
+char249 "
+'u 501,750,14,89,-30,89 2 0372 uacute
+char250 "
+^u 501,750,14,89,-30,89 2 0373 ucircumflex
+char251 "
+:u 501,729,14,89,-30,89 2 0374 udieresis
+char252 "
+'y 456,750,214,129,16,90 3 0375 yacute
+char253 "
+Tp 501,718,208,78,35,78 3 0376 thorn
+char254 "
+:y 456,729,214,129,16,90 3 0377 ydieresis
+char255 "
diff --git a/gnu/usr.bin/groff/devps/HNI b/gnu/usr.bin/groff/devps/HNI
new file mode 100644
index 0000000..e9ded2f
--- /dev/null
+++ b/gnu/usr.bin/groff/devps/HNI
@@ -0,0 +1,617 @@
+name HNI
+internalname Helvetica-Narrow-Oblique
+slant 12
+spacewidth 228
+encoding text.enc
+ligatures fi fl 0
+kernpairs
+A y -40
+A w -40
+A v -40
+A u -30
+A Y -100
+A W -50
+A V -70
+A U -50
+A T -120
+A Q -30
+A O -30
+A G -30
+A C -30
+B . -20
+B , -20
+B U -10
+C . -30
+C , -30
+D . -70
+D , -70
+D Y -90
+D W -40
+D V -70
+D A -40
+F r -45
+F . -150
+F o -30
+F e -30
+F , -150
+F a -50
+F A -80
+J u -20
+J . -30
+J , -30
+J a -20
+J A -20
+K y -50
+K u -30
+K o -40
+K e -40
+K O -50
+L y -30
+L ' -160
+L rq -140
+L Y -140
+L W -70
+L V -110
+L T -110
+O . -40
+O , -40
+O Y -70
+O X -60
+O W -30
+O V -50
+O T -40
+O A -20
+P . -180
+P o -50
+P e -50
+P , -180
+P a -40
+P A -120
+Q U -10
+R Y -50
+R W -30
+R V -50
+R U -40
+R T -30
+R O -20
+S . -20
+S , -20
+T y -120
+T w -120
+T u -120
+T ; -20
+T r -120
+T . -120
+T o -120
+T - -140
+T hy -140
+T char173 -140
+T e -120
+T , -120
+T : -20
+T a -120
+T O -40
+T A -120
+U . -40
+U , -40
+U A -40
+V u -70
+V ; -40
+V . -125
+V o -80
+V - -80
+V hy -80
+V char173 -80
+V e -80
+V , -125
+V : -40
+V a -70
+V O -40
+V G -40
+V A -80
+W y -20
+W u -30
+W . -80
+W o -30
+W - -40
+W hy -40
+W char173 -40
+W e -30
+W , -80
+W a -40
+W O -20
+W A -50
+Y u -110
+Y ; -60
+Y . -140
+Y o -140
+Y i -20
+Y - -140
+Y hy -140
+Y char173 -140
+Y e -140
+Y , -140
+Y : -60
+Y a -140
+Y O -85
+Y A -110
+a y -30
+a w -20
+a v -20
+b y -20
+b v -20
+b u -20
+b . -40
+b l -20
+b , -40
+b b -10
+c k -20
+c , -15
+, ' -100
+, rq -100
+e y -20
+e x -30
+e w -20
+e v -30
+e . -15
+e , -15
+f ' 50
+f rq 60
+f . -30
+f o -30
+f e -30
+f .i -28
+f , -30
+f a -30
+g r -10
+h y -30
+k o -20
+k e -20
+m y -15
+m u -10
+n y -15
+n v -20
+n u -10
+o y -30
+o x -30
+o w -15
+o v -15
+o . -40
+o , -40
+/o z -55
+char248 z -55
+/o y -70
+char248 y -70
+/o x -85
+char248 x -85
+/o w -70
+char248 w -70
+/o v -70
+char248 v -70
+/o u -55
+char248 u -55
+/o t -55
+char248 t -55
+/o s -55
+char248 s -55
+/o r -55
+char248 r -55
+/o q -55
+char248 q -55
+/o . -95
+char248 . -95
+/o p -55
+char248 p -55
+/o o -55
+char248 o -55
+/o n -55
+char248 n -55
+/o m -55
+char248 m -55
+/o l -55
+char248 l -55
+/o k -55
+char248 k -55
+/o j -55
+char248 j -55
+/o i -55
+char248 i -55
+/o h -55
+char248 h -55
+/o g -55
+char248 g -55
+/o f -55
+char248 f -55
+/o e -55
+char248 e -55
+/o d -55
+char248 d -55
+/o , -95
+char248 , -95
+/o c -55
+char248 c -55
+/o b -55
+char248 b -55
+/o a -55
+char248 a -55
+p y -30
+p . -35
+p , -35
+. ' -100
+. rq -100
+` ` -57
+` oq -57
+oq ` -57
+oq oq -57
+' s -50
+' r -50
+' ' -57
+' d -50
+r y 30
+r v 30
+r u 15
+r t 40
+r ; 30
+r . -50
+r p 30
+r n 25
+r m 25
+r l 15
+r k 15
+r i 15
+r , -50
+r : 30
+r a -10
+s w -30
+s . -15
+s , -15
+v . -80
+v o -25
+v e -25
+v , -80
+v a -25
+w . -60
+w o -10
+w e -10
+w , -60
+w a -15
+x e -30
+y . -100
+y o -20
+y e -20
+y , -100
+y a -20
+z o -15
+z e -15
+charset
+ha 385,688,0,107,15,89 2 0000 asciicircum
+ti 479,326,0,47,-41,47 0 0001 asciitilde
+vS 547,929,19,87,-24,87 2 0002 Scaron
+vZ 501,929,0,156,31,89 2 0003 Zcaron
+vs 410,734,15,93,-2,89 2 0004 scaron
+vz 410,734,0,108,25,89 2 0005 zcaron
+:Y 547,901,0,164,-87,89 2 0006 Ydieresis
+tm 820,718,0,96,-102,89 2 0007 trademark
+aq 157,718,0,126,-79,89 2 0010 quotesingle
+space 228 0 0040
+! 228,718,0,100,-24,89 2 0041 exclam
+" 291,718,0,118,-88,89 2 0042 quotedbl
+# 456,688,0,111,-10,89 2 0043 numbersign
+sh "
+$ 456,775,115,100,-7,89 2 0044 dollar
+Do "
+% 729,703,19,50,-70,50 2 0045 percent
+& 547,718,15,33,-13,33 2 0046 ampersand
+' 182,718,0,122,-74,89 2 0047 quoteright
+( 273,733,207,149,-39,89 3 0050 parenleft
+) 273,733,207,53,57,53 3 0051 parenright
+* 319,718,0,120,-85,89 2 0052 asterisk
++ 479,505,0,68,-20,68 0 0053 plus
+, 228,106,147,0,4 0 0054 comma
+- 273,322,0,70,-27,70 0 0055 hyphen
+hy "
+char173 "
+. 228,106,0,0,-21 0 0056 period
+/ 228,737,19,192,67,89 2 0057 slash
+sl "
+0 456,703,19,93,-27,89 2 0060 zero
+1 456,703,0,11,-120,11 2 0061 one
+2 456,703,0,100,29,89 2 0062 two
+3 456,703,19,94,-11,89 2 0063 three
+4 456,703,0,66,0,66 2 0064 four
+5 456,688,19,103,-5,89 2 0065 five
+6 456,703,19,98,-24,89 2 0066 six
+7 456,688,0,143,-62,89 2 0067 seven
+8 456,703,19,91,-10,89 2 0070 eight
+9 456,703,19,93,-17,89 2 0071 nine
+: 228,516,0,69,-21,69 0 0072 colon
+; 228,516,147,69,4,69 0 0073 semicolon
+< 479,495,0,97,-27,89 0 0074 less
+= 479,390,0,86,-2,86 0 0075 equal
+> 479,495,0,61,9,61 0 0076 greater
+? 456,727,0,94,-82,89 2 0077 question
+@ 832,737,19,9,-126,9 2 0100 at
+at "
+A 547,718,0,39,39,39 2 0101 A
+B 547,718,0,86,-11,86 2 0102 B
+C 592,737,19,98,-38,89 2 0103 C
+D 592,718,0,84,-16,84 2 0104 D
+E 547,718,0,128,-21,89 2 0105 E
+F 501,718,0,152,-21,89 2 0106 F
+G 638,737,19,67,-41,67 2 0107 G
+H 592,718,0,113,-13,89 2 0110 H
+I 228,718,0,101,-25,89 2 0111 I
+J 410,718,19,116,11,89 2 0112 J
+K 547,718,0,165,-12,89 2 0113 K
+L 456,718,0,49,-12,49 2 0114 L
+M 683,718,0,116,-10,89 2 0115 M
+N 592,718,0,113,-12,89 2 0116 N
+O 638,737,19,89,-36,89 2 0117 O
+P 547,718,0,107,-21,89 2 0120 P
+Q 638,737,56,89,-36,89 2 0121 Q
+R 592,718,0,92,-22,89 2 0122 R
+S 547,737,19,87,-24,87 2 0123 S
+T 501,718,0,164,-72,89 2 0124 T
+U 592,718,19,111,-51,89 2 0125 U
+V 547,718,0,159,-92,89 2 0126 V
+W 774,718,0,162,-88,89 2 0127 W
+X 547,718,0,150,34,89 2 0130 X
+Y 547,718,0,164,-87,89 2 0131 Y
+Z 501,718,0,156,31,89 2 0132 Z
+[ 228,722,196,153,33,89 2 0133 bracketleft
+lB "
+\ 228,737,19,61,-65,61 2 0134 backslash
+rs "
+] 228,722,196,124,61,89 2 0135 bracketright
+rB "
+a^ 273,734,0,136,-71,89 2 0136 circumflex
+^ "
+_ 456,0,125,37,72,37 0 0137 underscore
+` 182,725,0,133,-85,89 2 0140 quoteleft
+oq "
+a 456,538,15,52,0,52 0 0141 a
+b 456,718,15,73,2,73 2 0142 b
+c 410,538,15,94,-11,89 0 0143 c
+d 456,718,15,128,-19,89 2 0144 d
+e 456,538,15,68,-19,68 0 0145 e
+f 228,728,0,163,-21,89 2 0146 f
+g 456,538,220,94,16,89 1 0147 g
+h 456,718,0,64,-3,64 2 0150 h
+i 182,718,0,120,-5,89 2 0151 i
+j 182,718,210,120,99,89 3 0152 j
+k 410,718,0,132,-5,89 2 0153 k
+l 182,718,0,120,-5,89 2 0154 l
+m 683,538,0,66,-3,66 0 0155 m
+n 456,538,0,64,-3,64 0 0156 n
+o 456,538,14,73,-18,73 0 0157 o
+p 456,538,207,73,39,73 1 0160 p
+q 456,538,207,90,-19,89 1 0161 q
+r 273,538,0,142,-13,89 0 0162 r
+s 410,538,15,74,-2,74 0 0163 s
+t 228,669,7,124,-34,89 2 0164 t
+u 456,523,15,86,-27,86 0 0165 u
+v 410,523,0,135,-48,89 0 0166 v
+w 592,523,0,131,-53,89 0 0167 w
+x 410,523,0,127,41,89 0 0170 x
+y 410,523,214,132,38,89 1 0171 y
+z 410,523,0,108,25,89 0 0172 z
+lC 274,722,196,141,-25,89 2 0173 braceleft
+{ "
+ba 213,737,19,102,-24,89 2 0174 bar
+| "
+rC 274,722,196,67,50,67 2 0175 braceright
+} "
+a~ 273,722,0,179,-52,89 2 0176 tilde
+~ "
+bq 182,106,149,15,33,15 0 0200 quotesinglbase
+Fo 456,446,0,48,-70,48 0 0201 guillemotleft
+char171 "
+Fc 456,446,0,27,-48,27 0 0202 guillemotright
+char187 "
+bu 287,517,0,102,-24,89 0 0203 bullet
+Fn 456,737,207,131,93,89 3 0204 florin
+f/ 137,703,19,309,189,89 2 0205 fraction
+%0 820,703,19,74,-22,74 2 0206 perthousand
+dg 456,718,159,104,-60,89 2 0207 dagger
+dd 456,718,159,105,7,89 2 0210 daggerdbl
+en 456,313,0,104,8,89 0 0211 endash
+em 820,313,0,105,8,89 0 0212 emdash
+fi 410,728,0,121,-21,89 2 0214 fi
+fl 410,728,0,119,-21,89 2 0215 fl
+.i 228,523,0,63,-28,63 0 0220 dotlessi
+ga 273,734,0,53,-89,53 2 0222 grave
+a" 273,734,0,240,-79,89 2 0223 hungarumlaut
+a. 273,706,0,74,-154,74 2 0224 dotaccent
+ab 273,731,0,168,-87,89 2 0225 breve
+ah 273,734,0,161,-95,89 2 0226 caron
+ao 273,756,0,107,-125,89 2 0227 ring
+ho 273,0,225,0,15 1 0230 ogonek
+lq 273,725,0,155,-63,89 2 0231 quotedblleft
+rq 273,718,0,144,-52,89 2 0232 quotedblright
+oe 774,538,15,67,-18,67 0 0233 oe
+/l 182,718,0,152,16,89 2 0234 lslash
+Bq 273,106,149,37,55,37 0 0235 quotedblbase
+OE 820,737,19,145,-30,89 2 0236 OE
+/L 456,718,0,49,16,49 2 0237 Lslash
+r! 273,523,195,44,-13,44 0 0241 exclamdown
+char161 "
+ct 456,623,115,73,-28,73 0 0242 cent
+char162 "
+Po 456,718,16,114,10,89 2 0243 sterling
+char163 "
+Cs 456,603,0,124,1,89 0 0244 currency
+char164 "
+Ye 456,688,0,167,-17,89 2 0245 yen
+char165 "
+bb 213,737,19,102,-24,89 2 0246 brokenbar
+char166 "
+sc 456,737,191,73,-13,73 2 0247 section
+char167 "
+ad 273,706,0,140,-88,89 2 0250 dieresis
+char168 "
+co 604,737,19,133,6,89 2 0251 copyright
+char169 "
+Of 303,737,0,115,-32,89 2 0252 ordfeminine
+char170 "
+fo 273,446,0,56,-62,56 0 0253 guilsinglleft
+no 479,390,0,86,-37,86 0 0254 logicalnot
+char172 "
+\- 479,289,0,68,-20,68 0 0255 minus
+rg 604,737,19,133,6,89 2 0256 registered
+char174 "
+a- 273,684,0,161,-67,89 2 0257 macron
+char175 "
+de 328,703,0,106,-88,89 2 0260 degree
+char176 "
+char177 479,506,0,78,18,78 0 0261 plusminus
+S2 273,703,0,145,-2,89 2 0262 twosuperior
+char178 "
+S3 273,703,0,135,-24,89 2 0263 threesuperior
+char179 "
+aa 273,734,0,167,-153,89 2 0264 acute
+char180 "
+char181 456,523,207,86,30,86 1 0265 mu
+ps 440,718,173,143,-53,89 2 0266 paragraph
+char182 "
+char183 228,315,0,33,-56,33 0 0267 periodcentered
+ac 273,0,225,0,48 1 0270 cedilla
+char184 "
+S1 273,703,0,82,-86,82 2 0271 onesuperior
+char185 "
+Om 299,737,0,135,-32,89 2 0272 ordmasculine
+char186 "
+fc 273,446,0,34,-41,34 0 0273 guilsinglright
+14 684,703,19,24,-73,24 2 0274 onequarter
+char188 "
+12 684,703,19,54,-43,54 2 0275 onehalf
+char189 "
+34 684,703,19,72,-56,72 2 0276 threequarters
+char190 "
+r? 501,525,201,0,-20 0 0277 questiondown
+char191 "
+`A 547,929,0,39,39,39 2 0300 Agrave
+char192 "
+'A 547,929,0,63,39,63 2 0301 Aacute
+char193 "
+^A 547,929,0,39,39,39 2 0302 Acircumflex
+char194 "
+~A 547,917,0,76,39,76 2 0303 Atilde
+char195 "
+:A 547,901,0,39,39,39 2 0304 Adieresis
+char196 "
+oA 547,931,0,39,39,39 2 0305 Aring
+char197 "
+AE 820,718,0,129,43,89 2 0306 AE
+char198 "
+,C 592,737,225,98,-38,89 3 0307 Ccedilla
+char199 "
+`E 547,929,0,128,-21,89 2 0310 Egrave
+char200 "
+'E 547,929,0,128,-21,89 2 0311 Eacute
+char201 "
+^E 547,929,0,128,-21,89 2 0312 Ecircumflex
+char202 "
+:E 547,901,0,128,-21,89 2 0313 Edieresis
+char203 "
+`I 228,929,0,110,-25,89 2 0314 Igrave
+char204 "
+'I 228,929,0,223,-25,89 2 0315 Iacute
+char205 "
+^I 228,929,0,193,-25,89 2 0316 Icircumflex
+char206 "
+:I 228,901,0,197,-25,89 2 0317 Idieresis
+char207 "
+-D 592,718,0,84,-7,84 2 0320 Eth
+char208 "
+~N 592,917,0,113,-12,89 2 0321 Ntilde
+char209 "
+`O 638,929,19,89,-36,89 2 0322 Ograve
+char210 "
+'O 638,929,19,89,-36,89 2 0323 Oacute
+char211 "
+^O 638,929,19,89,-36,89 2 0324 Ocircumflex
+char212 "
+~O 638,917,19,89,-36,89 2 0325 Otilde
+char213 "
+:O 638,901,19,89,-36,89 2 0326 Odieresis
+char214 "
+char215 479,506,0,97,9,89 0 0327 multiply
+/O 638,737,19,142,15,89 2 0330 Oslash
+char216 "
+`U 592,929,19,111,-51,89 2 0331 Ugrave
+char217 "
+'U 592,929,19,111,-51,89 2 0332 Uacute
+char218 "
+^U 592,929,19,111,-51,89 2 0333 Ucircumflex
+char219 "
+:U 592,901,19,111,-51,89 2 0334 Udieresis
+char220 "
+'Y 547,929,0,164,-87,89 2 0335 Yacute
+char221 "
+TP 547,718,0,87,-21,87 2 0336 Thorn
+char222 "
+ss 501,728,15,88,-5,88 2 0337 germandbls
+char223 "
+`a 456,734,15,52,0,52 2 0340 agrave
+char224 "
+'a 456,734,15,75,0,75 2 0341 aacute
+char225 "
+^a 456,734,15,52,0,52 2 0342 acircumflex
+char226 "
+~a 456,722,15,80,0,80 2 0343 atilde
+char227 "
+:a 456,706,15,52,0,52 2 0344 adieresis
+char228 "
+oa 456,756,15,52,0,52 2 0345 aring
+char229 "
+ae 729,538,15,67,0,67 0 0346 ae
+char230 "
+,c 410,538,225,94,-11,89 1 0347 ccedilla
+char231 "
+`e 456,734,15,68,-19,68 2 0350 egrave
+char232 "
+'e 456,734,15,75,-19,75 2 0351 eacute
+char233 "
+^e 456,734,15,68,-19,68 2 0352 ecircumflex
+char234 "
+:e 456,706,15,68,-19,68 2 0353 edieresis
+char235 "
+`i 228,734,0,76,-28,76 2 0354 igrave
+char236 "
+'i 228,734,0,189,-28,89 2 0355 iacute
+char237 "
+^i 228,734,0,159,-28,89 2 0356 icircumflex
+char238 "
+:i 228,706,0,163,-28,89 2 0357 idieresis
+char239 "
+Sd 456,737,15,100,-17,89 2 0360 eth
+char240 "
+~n 456,722,0,80,-3,80 2 0361 ntilde
+char241 "
+`o 456,734,14,73,-18,73 2 0362 ograve
+char242 "
+'o 456,734,14,75,-18,75 2 0363 oacute
+char243 "
+^o 456,734,14,73,-18,73 2 0364 ocircumflex
+char244 "
+~o 456,722,14,88,-18,88 2 0365 otilde
+char245 "
+:o 456,706,14,73,-18,73 2 0366 odieresis
+char246 "
+char247 479,524,19,68,-20,68 0 0367 divide
+/o 501,545,22,80,26,80 0 0370 oslash
+char248 "
+`u 456,734,15,86,-27,86 2 0371 ugrave
+char249 "
+'u 456,734,15,86,-27,86 2 0372 uacute
+char250 "
+^u 456,734,15,86,-27,86 2 0373 ucircumflex
+char251 "
+:u 456,706,15,86,-27,86 2 0374 udieresis
+char252 "
+'y 410,734,214,132,38,89 3 0375 yacute
+char253 "
+Tp 456,718,207,73,39,73 3 0376 thorn
+char254 "
+:y 410,706,214,132,38,89 3 0377 ydieresis
+char255 "
diff --git a/gnu/usr.bin/groff/devps/HNR b/gnu/usr.bin/groff/devps/HNR
new file mode 100644
index 0000000..ecd9115
--- /dev/null
+++ b/gnu/usr.bin/groff/devps/HNR
@@ -0,0 +1,616 @@
+name HNR
+internalname Helvetica-Narrow
+spacewidth 228
+encoding text.enc
+ligatures fi fl 0
+kernpairs
+A y -32
+A w -32
+A v -32
+A u -24
+A Y -81
+A W -40
+A V -56
+A U -40
+A T -97
+A Q -24
+A O -24
+A G -24
+A C -24
+B . -15
+B , -15
+B U -7
+C . -24
+C , -24
+D . -56
+D , -56
+D Y -73
+D W -32
+D V -56
+D A -32
+F r -36
+F . -122
+F o -24
+F e -24
+F , -122
+F a -40
+F A -65
+J u -15
+J . -24
+J , -24
+J a -15
+J A -15
+K y -40
+K u -24
+K o -32
+K e -32
+K O -40
+L y -24
+L ' -130
+L rq -114
+L Y -114
+L W -56
+L V -89
+L T -89
+O . -32
+O , -32
+O Y -56
+O X -48
+O W -24
+O V -40
+O T -32
+O A -15
+P . -147
+P o -40
+P e -40
+P , -147
+P a -32
+P A -97
+Q U -7
+R Y -40
+R W -24
+R V -40
+R U -32
+R T -24
+R O -15
+S . -15
+S , -15
+T y -97
+T w -97
+T u -97
+T ; -15
+T r -97
+T . -97
+T o -97
+T - -114
+T hy -114
+T char173 -114
+T e -97
+T , -97
+T : -15
+T a -97
+T O -32
+T A -97
+U . -32
+U , -32
+U A -32
+V u -56
+V ; -32
+V . -102
+V o -65
+V - -65
+V hy -65
+V char173 -65
+V e -65
+V , -102
+V : -32
+V a -56
+V O -32
+V G -32
+V A -65
+W y -15
+W u -24
+W . -65
+W o -24
+W - -32
+W hy -32
+W char173 -32
+W e -24
+W , -65
+W a -32
+W O -15
+W A -40
+Y u -89
+Y ; -48
+Y . -114
+Y o -114
+Y i -15
+Y - -114
+Y hy -114
+Y char173 -114
+Y e -114
+Y , -114
+Y : -48
+Y a -114
+Y O -69
+Y A -89
+a y -24
+a w -15
+a v -15
+b y -15
+b v -15
+b u -15
+b . -32
+b l -15
+b , -32
+b b -7
+c k -15
+c , -11
+, ' -81
+, rq -81
+e y -15
+e x -24
+e w -15
+e v -24
+e . -11
+e , -11
+f ' 41
+f rq 49
+f . -24
+f o -24
+f e -24
+f .i -22
+f , -24
+f a -24
+g r -7
+h y -24
+k o -15
+k e -15
+m y -11
+m u -7
+n y -11
+n v -15
+n u -7
+o y -24
+o x -24
+o w -11
+o v -11
+o . -32
+o , -32
+/o z -44
+char248 z -44
+/o y -56
+char248 y -56
+/o x -69
+char248 x -69
+/o w -56
+char248 w -56
+/o v -56
+char248 v -56
+/o u -44
+char248 u -44
+/o t -44
+char248 t -44
+/o s -44
+char248 s -44
+/o r -44
+char248 r -44
+/o q -44
+char248 q -44
+/o . -77
+char248 . -77
+/o p -44
+char248 p -44
+/o o -44
+char248 o -44
+/o n -44
+char248 n -44
+/o m -44
+char248 m -44
+/o l -44
+char248 l -44
+/o k -44
+char248 k -44
+/o j -44
+char248 j -44
+/o i -44
+char248 i -44
+/o h -44
+char248 h -44
+/o g -44
+char248 g -44
+/o f -44
+char248 f -44
+/o e -44
+char248 e -44
+/o d -44
+char248 d -44
+/o , -77
+char248 , -77
+/o c -44
+char248 c -44
+/o b -44
+char248 b -44
+/o a -44
+char248 a -44
+p y -24
+p . -28
+p , -28
+. ' -81
+. rq -81
+` ` -46
+` oq -46
+oq ` -46
+oq oq -46
+' s -40
+' r -40
+' ' -46
+' d -40
+r y 25
+r v 25
+r u 12
+r t 33
+r ; 25
+r . -40
+r p 25
+r n 21
+r m 21
+r l 12
+r k 12
+r i 12
+r , -40
+r : 25
+r a -7
+s w -24
+s . -11
+s , -11
+v . -65
+v o -20
+v e -20
+v , -65
+v a -20
+w . -48
+w o -7
+w e -7
+w , -48
+w a -11
+x e -24
+y . -81
+y o -15
+y e -15
+y , -81
+y a -15
+z o -11
+z e -11
+charset
+ha 385,688 2 0000 asciicircum
+ti 479,326 0 0001 asciitilde
+vS 547,929,19 2 0002 Scaron
+vZ 501,929 2 0003 Zcaron
+vs 410,734,15 2 0004 scaron
+vz 410,734 2 0005 zcaron
+:Y 547,901 2 0006 Ydieresis
+tm 820,718 2 0007 trademark
+aq 157,718 2 0010 quotesingle
+space 228 0 0040
+! 228,718 2 0041 exclam
+" 291,718 2 0042 quotedbl
+# 456,688 2 0043 numbersign
+sh "
+$ 456,775,115 2 0044 dollar
+Do "
+% 729,703,19 2 0045 percent
+& 547,718,15 2 0046 ampersand
+' 182,718 2 0047 quoteright
+( 273,733,207 3 0050 parenleft
+) 273,733,207 3 0051 parenright
+* 319,718 2 0052 asterisk
++ 479,505 0 0053 plus
+, 228,106,147 0 0054 comma
+- 273,322 0 0055 hyphen
+hy "
+char173 "
+. 228,106 0 0056 period
+/ 228,737,19 2 0057 slash
+sl "
+0 456,703,19 2 0060 zero
+1 456,703 2 0061 one
+2 456,703 2 0062 two
+3 456,703,19 2 0063 three
+4 456,703 2 0064 four
+5 456,688,19 2 0065 five
+6 456,703,19 2 0066 six
+7 456,688 2 0067 seven
+8 456,703,19 2 0070 eight
+9 456,703,19 2 0071 nine
+: 228,516 0 0072 colon
+; 228,516,147 0 0073 semicolon
+< 479,495 0 0074 less
+= 479,390 0 0075 equal
+> 479,495 0 0076 greater
+? 456,727 2 0077 question
+@ 832,737,19 2 0100 at
+at "
+A 547,718 2 0101 A
+B 547,718 2 0102 B
+C 592,737,19 2 0103 C
+D 592,718 2 0104 D
+E 547,718 2 0105 E
+F 501,718 2 0106 F
+G 638,737,19 2 0107 G
+H 592,718 2 0110 H
+I 228,718 2 0111 I
+J 410,718,19 2 0112 J
+K 547,718 2 0113 K
+L 456,718 2 0114 L
+M 683,718 2 0115 M
+N 592,718 2 0116 N
+O 638,737,19 2 0117 O
+P 547,718 2 0120 P
+Q 638,737,56 2 0121 Q
+R 592,718 2 0122 R
+S 547,737,19 2 0123 S
+T 501,718 2 0124 T
+U 592,718,19 2 0125 U
+V 547,718 2 0126 V
+W 774,718 2 0127 W
+X 547,718 2 0130 X
+Y 547,718 2 0131 Y
+Z 501,718 2 0132 Z
+[ 228,722,196 2 0133 bracketleft
+lB "
+\ 228,737,19 2 0134 backslash
+rs "
+] 228,722,196 2 0135 bracketright
+rB "
+a^ 273,734 2 0136 circumflex
+^ "
+_ 456,0,125 0 0137 underscore
+` 182,725 2 0140 quoteleft
+oq "
+a 456,538,15 0 0141 a
+b 456,718,15 2 0142 b
+c 410,538,15 0 0143 c
+d 456,718,15 2 0144 d
+e 456,538,15 0 0145 e
+f 228,728 2 0146 f
+g 456,538,220 1 0147 g
+h 456,718 2 0150 h
+i 182,718 2 0151 i
+j 182,718,210 3 0152 j
+k 410,718 2 0153 k
+l 182,718 2 0154 l
+m 683,538 0 0155 m
+n 456,538 0 0156 n
+o 456,538,14 0 0157 o
+p 456,538,207 1 0160 p
+q 456,538,207 1 0161 q
+r 273,538 0 0162 r
+s 410,538,15 0 0163 s
+t 228,669,7 2 0164 t
+u 456,523,15 0 0165 u
+v 410,523 0 0166 v
+w 592,523 0 0167 w
+x 410,523 0 0170 x
+y 410,523,214 1 0171 y
+z 410,523 0 0172 z
+lC 274,722,196 2 0173 braceleft
+{ "
+ba 213,737,19 2 0174 bar
+| "
+rC 274,722,196 2 0175 braceright
+} "
+a~ 273,722 2 0176 tilde
+~ "
+bq 182,106,149 0 0200 quotesinglbase
+Fo 456,446 0 0201 guillemotleft
+char171 "
+Fc 456,446 0 0202 guillemotright
+char187 "
+bu 287,517 0 0203 bullet
+Fn 456,737,207 3 0204 florin
+f/ 137,703,19 2 0205 fraction
+%0 820,703,19 2 0206 perthousand
+dg 456,718,159 2 0207 dagger
+dd 456,718,159 2 0210 daggerdbl
+en 456,313 0 0211 endash
+em 820,313 0 0212 emdash
+fi 410,728 2 0214 fi
+fl 410,728 2 0215 fl
+.i 228,523 0 0220 dotlessi
+ga 273,734 2 0222 grave
+a" 273,734 2 0223 hungarumlaut
+a. 273,706 2 0224 dotaccent
+ab 273,731 2 0225 breve
+ah 273,734 2 0226 caron
+ao 273,756 2 0227 ring
+ho 273,0,225 1 0230 ogonek
+lq 273,725 2 0231 quotedblleft
+rq 273,718 2 0232 quotedblright
+oe 774,538,15 0 0233 oe
+/l 182,718 2 0234 lslash
+Bq 273,106,149 0 0235 quotedblbase
+OE 820,737,19 2 0236 OE
+/L 456,718 2 0237 Lslash
+r! 273,523,195 0 0241 exclamdown
+char161 "
+ct 456,623,115 0 0242 cent
+char162 "
+Po 456,718,16 2 0243 sterling
+char163 "
+Cs 456,603 0 0244 currency
+char164 "
+Ye 456,688 2 0245 yen
+char165 "
+bb 213,737,19 2 0246 brokenbar
+char166 "
+sc 456,737,191 2 0247 section
+char167 "
+ad 273,706 2 0250 dieresis
+char168 "
+co 604,737,19 2 0251 copyright
+char169 "
+Of 303,737 2 0252 ordfeminine
+char170 "
+fo 273,446 0 0253 guilsinglleft
+no 479,390 0 0254 logicalnot
+char172 "
+\- 479,289 0 0255 minus
+rg 604,737,19 2 0256 registered
+char174 "
+a- 273,684 2 0257 macron
+char175 "
+de 328,703 2 0260 degree
+char176 "
+char177 479,506 0 0261 plusminus
+S2 273,703 2 0262 twosuperior
+char178 "
+S3 273,703 2 0263 threesuperior
+char179 "
+aa 273,734 2 0264 acute
+char180 "
+char181 456,523,207 1 0265 mu
+ps 440,718,173 2 0266 paragraph
+char182 "
+char183 228,315 0 0267 periodcentered
+ac 273,0,225 1 0270 cedilla
+char184 "
+S1 273,703 2 0271 onesuperior
+char185 "
+Om 299,737 2 0272 ordmasculine
+char186 "
+fc 273,446 0 0273 guilsinglright
+14 684,703,19 2 0274 onequarter
+char188 "
+12 684,703,19 2 0275 onehalf
+char189 "
+34 684,703,19 2 0276 threequarters
+char190 "
+r? 501,525,201 0 0277 questiondown
+char191 "
+`A 547,929 2 0300 Agrave
+char192 "
+'A 547,929 2 0301 Aacute
+char193 "
+^A 547,929 2 0302 Acircumflex
+char194 "
+~A 547,917 2 0303 Atilde
+char195 "
+:A 547,901 2 0304 Adieresis
+char196 "
+oA 547,931 2 0305 Aring
+char197 "
+AE 820,718 2 0306 AE
+char198 "
+,C 592,737,225 3 0307 Ccedilla
+char199 "
+`E 547,929 2 0310 Egrave
+char200 "
+'E 547,929 2 0311 Eacute
+char201 "
+^E 547,929 2 0312 Ecircumflex
+char202 "
+:E 547,901 2 0313 Edieresis
+char203 "
+`I 228,929 2 0314 Igrave
+char204 "
+'I 228,929 2 0315 Iacute
+char205 "
+^I 228,929 2 0316 Icircumflex
+char206 "
+:I 228,901 2 0317 Idieresis
+char207 "
+-D 592,718 2 0320 Eth
+char208 "
+~N 592,917 2 0321 Ntilde
+char209 "
+`O 638,929,19 2 0322 Ograve
+char210 "
+'O 638,929,19 2 0323 Oacute
+char211 "
+^O 638,929,19 2 0324 Ocircumflex
+char212 "
+~O 638,917,19 2 0325 Otilde
+char213 "
+:O 638,901,19 2 0326 Odieresis
+char214 "
+char215 479,506 0 0327 multiply
+/O 638,737,19 2 0330 Oslash
+char216 "
+`U 592,929,19 2 0331 Ugrave
+char217 "
+'U 592,929,19 2 0332 Uacute
+char218 "
+^U 592,929,19 2 0333 Ucircumflex
+char219 "
+:U 592,901,19 2 0334 Udieresis
+char220 "
+'Y 547,929 2 0335 Yacute
+char221 "
+TP 547,718 2 0336 Thorn
+char222 "
+ss 501,728,15 2 0337 germandbls
+char223 "
+`a 456,734,15 2 0340 agrave
+char224 "
+'a 456,734,15 2 0341 aacute
+char225 "
+^a 456,734,15 2 0342 acircumflex
+char226 "
+~a 456,722,15 2 0343 atilde
+char227 "
+:a 456,706,15 2 0344 adieresis
+char228 "
+oa 456,756,15 2 0345 aring
+char229 "
+ae 729,538,15 0 0346 ae
+char230 "
+,c 410,538,225 1 0347 ccedilla
+char231 "
+`e 456,734,15 2 0350 egrave
+char232 "
+'e 456,734,15 2 0351 eacute
+char233 "
+^e 456,734,15 2 0352 ecircumflex
+char234 "
+:e 456,706,15 2 0353 edieresis
+char235 "
+`i 228,734 2 0354 igrave
+char236 "
+'i 228,734 2 0355 iacute
+char237 "
+^i 228,734 2 0356 icircumflex
+char238 "
+:i 228,706 2 0357 idieresis
+char239 "
+Sd 456,737,15 2 0360 eth
+char240 "
+~n 456,722 2 0361 ntilde
+char241 "
+`o 456,734,14 2 0362 ograve
+char242 "
+'o 456,734,14 2 0363 oacute
+char243 "
+^o 456,734,14 2 0364 ocircumflex
+char244 "
+~o 456,722,14 2 0365 otilde
+char245 "
+:o 456,706,14 2 0366 odieresis
+char246 "
+char247 479,524,19 0 0367 divide
+/o 501,545,22 0 0370 oslash
+char248 "
+`u 456,734,15 2 0371 ugrave
+char249 "
+'u 456,734,15 2 0372 uacute
+char250 "
+^u 456,734,15 2 0373 ucircumflex
+char251 "
+:u 456,706,15 2 0374 udieresis
+char252 "
+'y 410,734,214 3 0375 yacute
+char253 "
+Tp 456,718,207 3 0376 thorn
+char254 "
+:y 410,706,214 3 0377 ydieresis
+char255 "
diff --git a/gnu/usr.bin/groff/devps/HR b/gnu/usr.bin/groff/devps/HR
new file mode 100644
index 0000000..9dd2687
--- /dev/null
+++ b/gnu/usr.bin/groff/devps/HR
@@ -0,0 +1,616 @@
+name HR
+internalname Helvetica
+spacewidth 278
+encoding text.enc
+ligatures fi fl 0
+kernpairs
+A y -40
+A w -40
+A v -40
+A u -30
+A Y -100
+A W -50
+A V -70
+A U -50
+A T -120
+A Q -30
+A O -30
+A G -30
+A C -30
+B . -20
+B , -20
+B U -10
+C . -30
+C , -30
+D . -70
+D , -70
+D Y -90
+D W -40
+D V -70
+D A -40
+F r -45
+F . -150
+F o -30
+F e -30
+F , -150
+F a -50
+F A -80
+J u -20
+J . -30
+J , -30
+J a -20
+J A -20
+K y -50
+K u -30
+K o -40
+K e -40
+K O -50
+L y -30
+L ' -160
+L rq -140
+L Y -140
+L W -70
+L V -110
+L T -110
+O . -40
+O , -40
+O Y -70
+O X -60
+O W -30
+O V -50
+O T -40
+O A -20
+P . -180
+P o -50
+P e -50
+P , -180
+P a -40
+P A -120
+Q U -10
+R Y -50
+R W -30
+R V -50
+R U -40
+R T -30
+R O -20
+S . -20
+S , -20
+T y -120
+T w -120
+T u -120
+T ; -20
+T r -120
+T . -120
+T o -120
+T - -140
+T hy -140
+T char173 -140
+T e -120
+T , -120
+T : -20
+T a -120
+T O -40
+T A -120
+U . -40
+U , -40
+U A -40
+V u -70
+V ; -40
+V . -125
+V o -80
+V - -80
+V hy -80
+V char173 -80
+V e -80
+V , -125
+V : -40
+V a -70
+V O -40
+V G -40
+V A -80
+W y -20
+W u -30
+W . -80
+W o -30
+W - -40
+W hy -40
+W char173 -40
+W e -30
+W , -80
+W a -40
+W O -20
+W A -50
+Y u -110
+Y ; -60
+Y . -140
+Y o -140
+Y i -20
+Y - -140
+Y hy -140
+Y char173 -140
+Y e -140
+Y , -140
+Y : -60
+Y a -140
+Y O -85
+Y A -110
+a y -30
+a w -20
+a v -20
+b y -20
+b v -20
+b u -20
+b . -40
+b l -20
+b , -40
+b b -10
+c k -20
+c , -15
+, ' -100
+, rq -100
+e y -20
+e x -30
+e w -20
+e v -30
+e . -15
+e , -15
+f ' 50
+f rq 60
+f . -30
+f o -30
+f e -30
+f .i -28
+f , -30
+f a -30
+g r -10
+h y -30
+k o -20
+k e -20
+m y -15
+m u -10
+n y -15
+n v -20
+n u -10
+o y -30
+o x -30
+o w -15
+o v -15
+o . -40
+o , -40
+/o z -55
+char248 z -55
+/o y -70
+char248 y -70
+/o x -85
+char248 x -85
+/o w -70
+char248 w -70
+/o v -70
+char248 v -70
+/o u -55
+char248 u -55
+/o t -55
+char248 t -55
+/o s -55
+char248 s -55
+/o r -55
+char248 r -55
+/o q -55
+char248 q -55
+/o . -95
+char248 . -95
+/o p -55
+char248 p -55
+/o o -55
+char248 o -55
+/o n -55
+char248 n -55
+/o m -55
+char248 m -55
+/o l -55
+char248 l -55
+/o k -55
+char248 k -55
+/o j -55
+char248 j -55
+/o i -55
+char248 i -55
+/o h -55
+char248 h -55
+/o g -55
+char248 g -55
+/o f -55
+char248 f -55
+/o e -55
+char248 e -55
+/o d -55
+char248 d -55
+/o , -95
+char248 , -95
+/o c -55
+char248 c -55
+/o b -55
+char248 b -55
+/o a -55
+char248 a -55
+p y -30
+p . -35
+p , -35
+. ' -100
+. rq -100
+` ` -57
+` oq -57
+oq ` -57
+oq oq -57
+' s -50
+' r -50
+' ' -57
+' d -50
+r y 30
+r v 30
+r u 15
+r t 40
+r ; 30
+r . -50
+r p 30
+r n 25
+r m 25
+r l 15
+r k 15
+r i 15
+r , -50
+r : 30
+r a -10
+s w -30
+s . -15
+s , -15
+v . -80
+v o -25
+v e -25
+v , -80
+v a -25
+w . -60
+w o -10
+w e -10
+w , -60
+w a -15
+x e -30
+y . -100
+y o -20
+y e -20
+y , -100
+y a -20
+z o -15
+z e -15
+charset
+ha 469,688 2 0000 asciicircum
+ti 584,326 0 0001 asciitilde
+vS 667,929,19 2 0002 Scaron
+vZ 611,929 2 0003 Zcaron
+vs 500,734,15 2 0004 scaron
+vz 500,734 2 0005 zcaron
+:Y 667,901 2 0006 Ydieresis
+tm 1000,718 2 0007 trademark
+aq 191,718 2 0010 quotesingle
+space 278 0 0040
+! 278,718 2 0041 exclam
+" 355,718 2 0042 quotedbl
+# 556,688 2 0043 numbersign
+sh "
+$ 556,775,115 2 0044 dollar
+Do "
+% 889,703,19 2 0045 percent
+& 667,718,15 2 0046 ampersand
+' 222,718 2 0047 quoteright
+( 333,733,207 3 0050 parenleft
+) 333,733,207 3 0051 parenright
+* 389,718 2 0052 asterisk
++ 584,505 0 0053 plus
+, 278,106,147 0 0054 comma
+- 333,322 0 0055 hyphen
+hy "
+char173 "
+. 278,106 0 0056 period
+/ 278,737,19 2 0057 slash
+sl "
+0 556,703,19 2 0060 zero
+1 556,703 2 0061 one
+2 556,703 2 0062 two
+3 556,703,19 2 0063 three
+4 556,703 2 0064 four
+5 556,688,19 2 0065 five
+6 556,703,19 2 0066 six
+7 556,688 2 0067 seven
+8 556,703,19 2 0070 eight
+9 556,703,19 2 0071 nine
+: 278,516 0 0072 colon
+; 278,516,147 0 0073 semicolon
+< 584,495 0 0074 less
+= 584,390 0 0075 equal
+> 584,495 0 0076 greater
+? 556,727 2 0077 question
+@ 1015,737,19 2 0100 at
+at "
+A 667,718 2 0101 A
+B 667,718 2 0102 B
+C 722,737,19 2 0103 C
+D 722,718 2 0104 D
+E 667,718 2 0105 E
+F 611,718 2 0106 F
+G 778,737,19 2 0107 G
+H 722,718 2 0110 H
+I 278,718 2 0111 I
+J 500,718,19 2 0112 J
+K 667,718 2 0113 K
+L 556,718 2 0114 L
+M 833,718 2 0115 M
+N 722,718 2 0116 N
+O 778,737,19 2 0117 O
+P 667,718 2 0120 P
+Q 778,737,56 2 0121 Q
+R 722,718 2 0122 R
+S 667,737,19 2 0123 S
+T 611,718 2 0124 T
+U 722,718,19 2 0125 U
+V 667,718 2 0126 V
+W 944,718 2 0127 W
+X 667,718 2 0130 X
+Y 667,718 2 0131 Y
+Z 611,718 2 0132 Z
+[ 278,722,196 2 0133 bracketleft
+lB "
+\ 278,737,19 2 0134 backslash
+rs "
+] 278,722,196 2 0135 bracketright
+rB "
+a^ 333,734 2 0136 circumflex
+^ "
+_ 556,0,125 0 0137 underscore
+` 222,725 2 0140 quoteleft
+oq "
+a 556,538,15 0 0141 a
+b 556,718,15 2 0142 b
+c 500,538,15 0 0143 c
+d 556,718,15 2 0144 d
+e 556,538,15 0 0145 e
+f 278,728 2 0146 f
+g 556,538,220 1 0147 g
+h 556,718 2 0150 h
+i 222,718 2 0151 i
+j 222,718,210 3 0152 j
+k 500,718 2 0153 k
+l 222,718 2 0154 l
+m 833,538 0 0155 m
+n 556,538 0 0156 n
+o 556,538,14 0 0157 o
+p 556,538,207 1 0160 p
+q 556,538,207 1 0161 q
+r 333,538 0 0162 r
+s 500,538,15 0 0163 s
+t 278,669,7 2 0164 t
+u 556,523,15 0 0165 u
+v 500,523 0 0166 v
+w 722,523 0 0167 w
+x 500,523 0 0170 x
+y 500,523,214 1 0171 y
+z 500,523 0 0172 z
+lC 334,722,196 2 0173 braceleft
+{ "
+ba 260,737,19 2 0174 bar
+| "
+rC 334,722,196 2 0175 braceright
+} "
+a~ 333,722 2 0176 tilde
+~ "
+bq 222,106,149 0 0200 quotesinglbase
+Fo 556,446 0 0201 guillemotleft
+char171 "
+Fc 556,446 0 0202 guillemotright
+char187 "
+bu 350,517 0 0203 bullet
+Fn 556,737,207 3 0204 florin
+f/ 167,703,19 2 0205 fraction
+%0 1000,703,19 2 0206 perthousand
+dg 556,718,159 2 0207 dagger
+dd 556,718,159 2 0210 daggerdbl
+en 556,313 0 0211 endash
+em 1000,313 0 0212 emdash
+fi 500,728 2 0214 fi
+fl 500,728 2 0215 fl
+.i 278,523 0 0220 dotlessi
+ga 333,734 2 0222 grave
+a" 333,734 2 0223 hungarumlaut
+a. 333,706 2 0224 dotaccent
+ab 333,731 2 0225 breve
+ah 333,734 2 0226 caron
+ao 333,756 2 0227 ring
+ho 333,0,225 1 0230 ogonek
+lq 333,725 2 0231 quotedblleft
+rq 333,718 2 0232 quotedblright
+oe 944,538,15 0 0233 oe
+/l 222,718 2 0234 lslash
+Bq 333,106,149 0 0235 quotedblbase
+OE 1000,737,19 2 0236 OE
+/L 556,718 2 0237 Lslash
+r! 333,523,195 0 0241 exclamdown
+char161 "
+ct 556,623,115 0 0242 cent
+char162 "
+Po 556,718,16 2 0243 sterling
+char163 "
+Cs 556,603 0 0244 currency
+char164 "
+Ye 556,688 2 0245 yen
+char165 "
+bb 260,737,19 2 0246 brokenbar
+char166 "
+sc 556,737,191 2 0247 section
+char167 "
+ad 333,706 2 0250 dieresis
+char168 "
+co 737,737,19 2 0251 copyright
+char169 "
+Of 370,737 2 0252 ordfeminine
+char170 "
+fo 333,446 0 0253 guilsinglleft
+no 584,390 0 0254 logicalnot
+char172 "
+\- 584,289 0 0255 minus
+rg 737,737,19 2 0256 registered
+char174 "
+a- 333,684 2 0257 macron
+char175 "
+de 400,703 2 0260 degree
+char176 "
+char177 584,506 0 0261 plusminus
+S2 333,703 2 0262 twosuperior
+char178 "
+S3 333,703 2 0263 threesuperior
+char179 "
+aa 333,734 2 0264 acute
+char180 "
+char181 556,523,207 1 0265 mu
+ps 537,718,173 2 0266 paragraph
+char182 "
+char183 278,315 0 0267 periodcentered
+ac 333,0,225 1 0270 cedilla
+char184 "
+S1 333,703 2 0271 onesuperior
+char185 "
+Om 365,737 2 0272 ordmasculine
+char186 "
+fc 333,446 0 0273 guilsinglright
+14 834,703,19 2 0274 onequarter
+char188 "
+12 834,703,19 2 0275 onehalf
+char189 "
+34 834,703,19 2 0276 threequarters
+char190 "
+r? 611,525,201 0 0277 questiondown
+char191 "
+`A 667,929 2 0300 Agrave
+char192 "
+'A 667,929 2 0301 Aacute
+char193 "
+^A 667,929 2 0302 Acircumflex
+char194 "
+~A 667,917 2 0303 Atilde
+char195 "
+:A 667,901 2 0304 Adieresis
+char196 "
+oA 667,931 2 0305 Aring
+char197 "
+AE 1000,718 2 0306 AE
+char198 "
+,C 722,737,225 3 0307 Ccedilla
+char199 "
+`E 667,929 2 0310 Egrave
+char200 "
+'E 667,929 2 0311 Eacute
+char201 "
+^E 667,929 2 0312 Ecircumflex
+char202 "
+:E 667,901 2 0313 Edieresis
+char203 "
+`I 278,929 2 0314 Igrave
+char204 "
+'I 278,929 2 0315 Iacute
+char205 "
+^I 278,929 2 0316 Icircumflex
+char206 "
+:I 278,901 2 0317 Idieresis
+char207 "
+-D 722,718 2 0320 Eth
+char208 "
+~N 722,917 2 0321 Ntilde
+char209 "
+`O 778,929,19 2 0322 Ograve
+char210 "
+'O 778,929,19 2 0323 Oacute
+char211 "
+^O 778,929,19 2 0324 Ocircumflex
+char212 "
+~O 778,917,19 2 0325 Otilde
+char213 "
+:O 778,901,19 2 0326 Odieresis
+char214 "
+char215 584,506 0 0327 multiply
+/O 778,737,19 2 0330 Oslash
+char216 "
+`U 722,929,19 2 0331 Ugrave
+char217 "
+'U 722,929,19 2 0332 Uacute
+char218 "
+^U 722,929,19 2 0333 Ucircumflex
+char219 "
+:U 722,901,19 2 0334 Udieresis
+char220 "
+'Y 667,929 2 0335 Yacute
+char221 "
+TP 667,718 2 0336 Thorn
+char222 "
+ss 611,728,15 2 0337 germandbls
+char223 "
+`a 556,734,15 2 0340 agrave
+char224 "
+'a 556,734,15 2 0341 aacute
+char225 "
+^a 556,734,15 2 0342 acircumflex
+char226 "
+~a 556,722,15 2 0343 atilde
+char227 "
+:a 556,706,15 2 0344 adieresis
+char228 "
+oa 556,756,15 2 0345 aring
+char229 "
+ae 889,538,15 0 0346 ae
+char230 "
+,c 500,538,225 1 0347 ccedilla
+char231 "
+`e 556,734,15 2 0350 egrave
+char232 "
+'e 556,734,15 2 0351 eacute
+char233 "
+^e 556,734,15 2 0352 ecircumflex
+char234 "
+:e 556,706,15 2 0353 edieresis
+char235 "
+`i 278,734 2 0354 igrave
+char236 "
+'i 278,734 2 0355 iacute
+char237 "
+^i 278,734 2 0356 icircumflex
+char238 "
+:i 278,706 2 0357 idieresis
+char239 "
+Sd 556,737,15 2 0360 eth
+char240 "
+~n 556,722 2 0361 ntilde
+char241 "
+`o 556,734,14 2 0362 ograve
+char242 "
+'o 556,734,14 2 0363 oacute
+char243 "
+^o 556,734,14 2 0364 ocircumflex
+char244 "
+~o 556,722,14 2 0365 otilde
+char245 "
+:o 556,706,14 2 0366 odieresis
+char246 "
+char247 584,524,19 0 0367 divide
+/o 611,545,22 0 0370 oslash
+char248 "
+`u 556,734,15 2 0371 ugrave
+char249 "
+'u 556,734,15 2 0372 uacute
+char250 "
+^u 556,734,15 2 0373 ucircumflex
+char251 "
+:u 556,706,15 2 0374 udieresis
+char252 "
+'y 500,734,214 3 0375 yacute
+char253 "
+Tp 556,718,207 3 0376 thorn
+char254 "
+:y 500,706,214 3 0377 ydieresis
+char255 "
diff --git a/gnu/usr.bin/groff/devps/Makefile b/gnu/usr.bin/groff/devps/Makefile
new file mode 100644
index 0000000..7560034
--- /dev/null
+++ b/gnu/usr.bin/groff/devps/Makefile
@@ -0,0 +1,37 @@
+DEVICE= ps
+FONTFILES= $(FONTS) $(SUPPORT) $(DEVGENFILES) DESC
+FONTS= S ZD ZDR SS AB ABI AI AR BMB BMBI BMI BMR \
+ CB CBI CI CR HB HBI HI HR HNB HNBI HNI HNR \
+ NB NBI NI NR PB PBI PI PR TB TBI TI TR ZCMI
+SUPPORT= download prologue symbolsl.pfa text.enc zapfdr.pfa
+DEVGENFILES= generate/Makefile generate/afmname generate/dingbatsmap \
+ generate/dingbatsrmap generate/lgreekmap generate/symbol.sed \
+ generate/symbolchars generate/symbolsl.afm generate/textmap
+PSFILES= prologue symbolsl.pfa zapfdr.pfa
+
+CLEANFILES+= DESC ${PSFILES}
+
+DESC: DESC.in
+ -rm -f DESC
+ cat ${.CURDIR}/DESC.in >DESC
+ echo broken ${BROKEN_SPOOLER_FLAGS} >>DESC
+ if test "${PAGE}" = A4; then \
+ echo "paperlength 841890" >>DESC; \
+ else \
+ echo "paperlength 792000" >>DESC; \
+ fi
+ test -z '${PSPRINT}' || echo print '${PSPRINT}' >>DESC
+
+${PSFILES}:
+ -rm -f $@
+ sed -f ${.CURDIR}/psstrip.sed $? >$@
+
+fonts: DESC
+ ${MAKE} -f ${.CURDIR}/generate/Makefile \
+ srcdir=${.CURDIR}/generate DESC=${.CURDIR}/DESC.in
+
+prologue: prologue.ps
+zapfdr.pfa: zapfdr.ps
+symbolsl.pfa: symbolsl.ps
+
+.include "../Makefile.dev"
diff --git a/gnu/usr.bin/groff/devps/Makefile.sub b/gnu/usr.bin/groff/devps/Makefile.sub
new file mode 100644
index 0000000..a46693f
--- /dev/null
+++ b/gnu/usr.bin/groff/devps/Makefile.sub
@@ -0,0 +1,35 @@
+DEV=ps
+DISTFILES=text.enc download \
+ S ZD ZDR SS AB ABI AI AR BMB BMBI BMI BMR \
+ CB CBI CI CR HB HBI HI HR HNB HNBI HNI HNR \
+ NB NBI NI NR PB PBI PI PR TB TBI TI TR ZCMI
+PSFILES=prologue symbolsl.pfa zapfdr.pfa
+DEVGENFILES=generate/Makefile generate/afmname generate/dingbatsmap \
+ generate/dingbatsrmap generate/lgreekmap generate/symbol.sed \
+ generate/symbolchars generate/symbolsl.afm generate/textmap
+DEVFILES=DESC $(PSFILES) $(DISTFILES) $(DEVGENFILES)
+
+CLEANADD=DESC $(PSFILES)
+
+DESC: DESC.in
+ -rm -f DESC
+ cat $(srcdir)/DESC.in >DESC
+ echo broken $(BROKEN_SPOOLER_FLAGS) >>DESC
+ if test "$(PAGE)" = A4; then \
+ echo "paperlength 841890" >>DESC; \
+ else \
+ echo "paperlength 792000" >>DESC; \
+ fi
+ test -z '$(PSPRINT)' || echo print '$(PSPRINT)' >>DESC
+
+fonts: DESC
+ $(MAKE) -f $(srcdir)/generate/Makefile \
+ srcdir=$(srcdir)/generate DESC=$(srcdir)/DESC.in
+
+prologue: prologue.ps
+zapfdr.pfa: zapfdr.ps
+symbolsl.pfa: symbolsl.ps
+
+$(PSFILES):
+ -rm -f $@
+ sed -f $(srcdir)/psstrip.sed $? >$@
diff --git a/gnu/usr.bin/groff/devps/NB b/gnu/usr.bin/groff/devps/NB
new file mode 100644
index 0000000..2805367
--- /dev/null
+++ b/gnu/usr.bin/groff/devps/NB
@@ -0,0 +1,446 @@
+name NB
+internalname NewCenturySchlbk-Bold
+spacewidth 287
+encoding text.enc
+ligatures fi fl 0
+kernpairs
+A y -74
+A w -74
+A v -74
+A ' -74
+A Y -92
+A W -74
+A V -92
+A T -55
+F . -111
+F , -111
+F A -74
+L y -55
+L ' -55
+L Y -92
+L W -74
+L V -92
+L T -55
+P . -129
+P , -129
+P A -74
+R y -18
+R Y -37
+R W -37
+R V -37
+T y -52
+T w -71
+T u -71
+T ; -55
+T s -62
+T r -62
+T . -92
+T o -92
+T i -25
+T - -92
+T hy -92
+T char173 -92
+T e -92
+T , -92
+T : -55
+T c -81
+T a -62
+T A -55
+V y -92
+V u -74
+V ; -74
+V r -74
+V . -129
+V o -92
+V i -44
+V - -92
+V hy -92
+V char173 -92
+V e -92
+V : -74
+V a -92
+V A -92
+W y -74
+W u -55
+W ; -37
+W r -55
+W . -111
+W o -55
+W i -37
+W - -37
+W hy -37
+W char173 -37
+W e -55
+W , -111
+W : -37
+W a -74
+W A -74
+Y v -81
+Y u -92
+Y ; -92
+Y q -111
+Y . -111
+Y p -81
+Y o -111
+Y i -44
+Y - -111
+Y hy -111
+Y char173 -111
+Y e -111
+Y , -111
+Y : -92
+Y a -111
+Y A -92
+f ' 94
+1 1 -55
+` ` -18
+` oq -18
+oq ` -18
+oq oq -18
+' t -18
+' s -37
+' ' -18
+r ' 55
+r . -74
+r - -18
+r hy -18
+r char173 -18
+r , -74
+v . -111
+v , -111
+w . -92
+w , -92
+y . -111
+y , -111
+charset
+ha 606,722 2 0000 asciicircum
+ti 606,347 0 0001 asciitilde
+vS 667,970,15 2 0002 Scaron
+vZ 667,970 2 0003 Zcaron
+vs 500,723,15 2 0004 scaron
+vz 537,723 2 0005 zcaron
+:Y 722,940 2 0006 Ydieresis
+tm 1000,722 2 0007 trademark
+aq 241,737 2 0010 quotesingle
+space 287 0 0040
+! 296,737,15 2 0041 exclam
+" 333,737 2 0042 quotedbl
+# 574,705 2 0043 numbersign
+sh "
+$ 574,801,140 2 0044 dollar
+Do "
+% 833,704,18 2 0045 percent
+& 852,737,15 2 0046 ampersand
+' 241,737 2 0047 quoteright
+( 389,737,122 2 0050 parenleft
+) 389,737,122 2 0051 parenright
+* 500,738 2 0052 asterisk
++ 606,514 0 0053 plus
+, 278,169,189 0 0054 comma
+- 333,309 0 0055 hyphen
+hy "
+char173 "
+. 278,172,15 0 0056 period
+/ 278,737,15 2 0057 slash
+sl "
+0 574,705,15 2 0060 zero
+1 574,705 2 0061 one
+2 574,705,4 2 0062 two
+3 574,705,15 2 0063 three
+4 574,705 2 0064 four
+5 574,705,15 2 0065 five
+6 574,705,15 2 0066 six
+7 574,705,15 2 0067 seven
+8 574,705,15 2 0070 eight
+9 574,705,15 2 0071 nine
+: 278,485,15 0 0072 colon
+; 278,485,189 0 0073 semicolon
+< 606,538,13 0 0074 less
+= 606,399 0 0075 equal
+> 606,538,13 0 0076 greater
+? 500,737,15 2 0077 question
+@ 747,737,15 2 0100 at
+at "
+A 759,737 2 0101 A
+B 778,722 2 0102 B
+C 778,737,15 2 0103 C
+D 833,722 2 0104 D
+E 759,722 2 0105 E
+F 722,722 2 0106 F
+G 833,737,15 2 0107 G
+H 870,722 2 0110 H
+I 444,722 2 0111 I
+J 648,722,15 2 0112 J
+K 815,722 2 0113 K
+L 722,722 2 0114 L
+M 981,722 2 0115 M
+N 833,722,8 2 0116 N
+O 833,737,15 2 0117 O
+P 759,722 2 0120 P
+Q 833,737,189 2 0121 Q
+R 815,722,15 2 0122 R
+S 667,737,15 2 0123 S
+T 722,722 2 0124 T
+U 833,722,15 2 0125 U
+V 759,722,15 2 0126 V
+W 981,722,15 2 0127 W
+X 722,722 2 0130 X
+Y 722,722 2 0131 Y
+Z 667,722 2 0132 Z
+[ 389,722,113 2 0133 bracketleft
+lB "
+\ 606,737 2 0134 backslash
+rs "
+] 389,722,113 2 0135 bracketright
+rB "
+a^ 333,723 2 0136 circumflex
+^ "
+_ 500,0,148 0 0137 underscore
+` 241,747 2 0140 quoteleft
+oq "
+a 611,485,15 0 0141 a
+b 648,737,15 2 0142 b
+c 556,485,15 0 0143 c
+d 667,737,15 2 0144 d
+e 574,485,15 0 0145 e
+f 389,737 2 0146 f
+g 611,536,205 1 0147 g
+h 685,737 2 0150 h
+i 370,737 2 0151 i
+j 352,737,205 3 0152 j
+k 667,737 2 0153 k
+l 352,737 2 0154 l
+m 963,485 0 0155 m
+n 685,485 0 0156 n
+o 611,485,15 0 0157 o
+p 667,485,205 1 0160 p
+q 648,485,205 1 0161 q
+r 519,485 0 0162 r
+s 500,485,15 0 0163 s
+t 426,675,15 2 0164 t
+u 685,475,15 0 0165 u
+v 611,475,8 0 0166 v
+w 889,475,8 0 0167 w
+x 611,475 0 0170 x
+y 611,475,207 1 0171 y
+z 537,475 0 0172 z
+lC 389,723,111 2 0173 braceleft
+{ "
+ba 606,737 2 0174 bar
+| "
+rC 389,723,111 2 0175 braceright
+} "
+a~ 333,704 2 0176 tilde
+~ "
+bq 241,169,189 0 0200 quotesinglbase
+Fo 500,405 0 0201 guillemotleft
+char171 "
+Fc 500,405 0 0202 guillemotright
+char187 "
+bu 606,511 0 0203 bullet
+Fn 574,737,205 3 0204 florin
+f/ 167,705 2 0205 fraction
+%0 1000,694,27 2 0206 perthousand
+dg 500,737,88 2 0207 dagger
+dd 500,736,89 2 0210 daggerdbl
+en 500,296 0 0211 endash
+em 1000,296 0 0212 emdash
+fi 685,737 2 0214 fi
+fl 685,737 2 0215 fl
+.i 370,475 0 0220 dotlessi
+ga 333,734 2 0222 grave
+a" 333,737 2 0223 hungarumlaut
+a. 333,693 2 0224 dotaccent
+ab 333,712 2 0225 breve
+ah 333,723 2 0226 caron
+ao 333,760 2 0227 ring
+ho 333,0,163 0 0230 ogonek
+lq 481,747 2 0231 quotedblleft
+rq 481,737 2 0232 quotedblright
+oe 907,485,15 0 0233 oe
+/l 352,737 2 0234 lslash
+Bq 481,169,189 0 0235 quotedblbase
+OE 1000,722 2 0236 OE
+/L 722,722 2 0237 Lslash
+r! 296,547,205 1 0241 exclamdown
+char161 "
+ct 574,566,108 0 0242 cent
+char162 "
+Po 574,705,15 2 0243 sterling
+char163 "
+Cs 574,591 0 0244 currency
+char164 "
+Ye 574,705 2 0245 yen
+char165 "
+bb 606,737 2 0246 brokenbar
+char166 "
+sc 500,737,86 2 0247 section
+char167 "
+ad 333,693 2 0250 dieresis
+char168 "
+co 747,737,15 2 0251 copyright
+char169 "
+Of 367,737 2 0252 ordfeminine
+char170 "
+fo 333,405 0 0253 guilsinglleft
+no 606,399 0 0254 logicalnot
+char172 "
+\- 606,302 0 0255 minus
+rg 747,737,15 2 0256 registered
+char174 "
+a- 333,663 0 0257 macron
+char175 "
+de 400,705 2 0260 degree
+char176 "
+char177 606,514 0 0261 plusminus
+S2 344,705 2 0262 twosuperior
+char178 "
+S3 344,705 2 0263 threesuperior
+char179 "
+aa 333,737 2 0264 acute
+char180 "
+char181 685,475,205 1 0265 mu
+ps 747,722 2 0266 paragraph
+char182 "
+char183 278,338 0 0267 periodcentered
+ac 333,0,221 1 0270 cedilla
+char184 "
+S1 344,705 2 0271 onesuperior
+char185 "
+Om 367,737 2 0272 ordmasculine
+char186 "
+fc 333,408 0 0273 guilsinglright
+14 861,705 2 0274 onequarter
+char188 "
+12 861,705,2 2 0275 onehalf
+char189 "
+34 861,705 2 0276 threequarters
+char190 "
+r? 500,547,205 1 0277 questiondown
+char191 "
+`A 759,981 2 0300 Agrave
+char192 "
+'A 759,984 2 0301 Aacute
+char193 "
+^A 759,970 2 0302 Acircumflex
+char194 "
+~A 759,951 2 0303 Atilde
+char195 "
+:A 759,940 2 0304 Adieresis
+char196 "
+oA 759,1007 2 0305 Aring
+char197 "
+AE 981,722 2 0306 AE
+char198 "
+,C 778,737,221 3 0307 Ccedilla
+char199 "
+`E 759,981 2 0310 Egrave
+char200 "
+'E 759,984 2 0311 Eacute
+char201 "
+^E 759,970 2 0312 Ecircumflex
+char202 "
+:E 759,940 2 0313 Edieresis
+char203 "
+`I 444,981 2 0314 Igrave
+char204 "
+'I 444,984 2 0315 Iacute
+char205 "
+^I 444,970 2 0316 Icircumflex
+char206 "
+:I 444,940 2 0317 Idieresis
+char207 "
+-D 833,722 2 0320 Eth
+char208 "
+~N 833,951,8 2 0321 Ntilde
+char209 "
+`O 833,981,15 2 0322 Ograve
+char210 "
+'O 833,984,15 2 0323 Oacute
+char211 "
+^O 833,970,15 2 0324 Ocircumflex
+char212 "
+~O 833,951,15 2 0325 Otilde
+char213 "
+:O 833,940,15 2 0326 Odieresis
+char214 "
+char215 606,504 0 0327 multiply
+/O 833,768,60 2 0330 Oslash
+char216 "
+`U 833,981,15 2 0331 Ugrave
+char217 "
+'U 833,984,15 2 0332 Uacute
+char218 "
+^U 833,970,15 2 0333 Ucircumflex
+char219 "
+:U 833,940,15 2 0334 Udieresis
+char220 "
+'Y 722,984 2 0335 Yacute
+char221 "
+TP 759,722 2 0336 Thorn
+char222 "
+ss 611,737,15 2 0337 germandbls
+char223 "
+`a 611,734,15 2 0340 agrave
+char224 "
+'a 611,737,15 2 0341 aacute
+char225 "
+^a 611,723,15 2 0342 acircumflex
+char226 "
+~a 611,704,15 2 0343 atilde
+char227 "
+:a 611,693,15 2 0344 adieresis
+char228 "
+oa 611,760,15 2 0345 aring
+char229 "
+ae 870,485,15 0 0346 ae
+char230 "
+,c 556,485,221 1 0347 ccedilla
+char231 "
+`e 574,734,15 2 0350 egrave
+char232 "
+'e 574,737,15 2 0351 eacute
+char233 "
+^e 574,723,15 2 0352 ecircumflex
+char234 "
+:e 574,693,15 2 0353 edieresis
+char235 "
+`i 370,734 2 0354 igrave
+char236 "
+'i 370,737 2 0355 iacute
+char237 "
+^i 370,723 2 0356 icircumflex
+char238 "
+:i 370,693 2 0357 idieresis
+char239 "
+Sd 611,737,15 2 0360 eth
+char240 "
+~n 685,704 2 0361 ntilde
+char241 "
+`o 611,734,15 2 0362 ograve
+char242 "
+'o 611,737,15 2 0363 oacute
+char243 "
+^o 611,723,15 2 0364 ocircumflex
+char244 "
+~o 611,704,15 2 0365 otilde
+char245 "
+:o 611,693,15 2 0366 odieresis
+char246 "
+char247 606,514 0 0367 divide
+/o 611,565,111 0 0370 oslash
+char248 "
+`u 685,734,15 2 0371 ugrave
+char249 "
+'u 685,737,15 2 0372 uacute
+char250 "
+^u 685,723,15 2 0373 ucircumflex
+char251 "
+:u 685,693,15 2 0374 udieresis
+char252 "
+'y 611,737,207 3 0375 yacute
+char253 "
+Tp 667,675,205 3 0376 thorn
+char254 "
+:y 611,693,207 3 0377 ydieresis
+char255 "
diff --git a/gnu/usr.bin/groff/devps/NBI b/gnu/usr.bin/groff/devps/NBI
new file mode 100644
index 0000000..3471b41
--- /dev/null
+++ b/gnu/usr.bin/groff/devps/NBI
@@ -0,0 +1,447 @@
+name NBI
+internalname NewCenturySchlbk-BoldItalic
+slant 16
+spacewidth 287
+encoding text.enc
+ligatures fi fl 0
+kernpairs
+A y -50
+A w -20
+A v -20
+A ' -74
+A Y -74
+A W -92
+A V -111
+A T -74
+F . -129
+F f -18
+F , -129
+F A -74
+L y -55
+L ' -55
+L Y -55
+L W -55
+L V -74
+L T -55
+P . -129
+P , -129
+P A -92
+R y -50
+R Y -20
+R W -20
+R V -20
+R T -20
+T y -89
+T w -89
+T u -89
+T ; -72
+T s -89
+T r -89
+T . -111
+T o -109
+T i -71
+T - -129
+T hy -129
+T char173 -129
+T e -109
+T , -111
+T : -62
+T c -89
+T a -74
+T A -50
+V y -89
+V u -89
+V ; -74
+V r -109
+V . -111
+V o -129
+V i -72
+V - -74
+V hy -74
+V char173 -74
+V e -129
+V , -111
+V : -74
+V a -129
+V A -129
+W y -74
+W u -74
+W ; -37
+W r -74
+W . -55
+W o -74
+W i -74
+W - -37
+W hy -37
+W char173 -37
+W e -74
+W , -55
+W : -37
+W a -74
+W A -89
+Y v -129
+Y u -129
+Y ; -111
+Y q -129
+Y . -129
+Y p -129
+Y o -129
+Y i -90
+Y - -129
+Y hy -129
+Y char173 -129
+Y e -129
+Y , -129
+Y : -111
+Y a -129
+Y A -111
+f ' 74
+1 1 -74
+` ` -18
+` oq -18
+oq ` -18
+oq oq -18
+' t -37
+' s -37
+' ' -18
+r ' 55
+r . -129
+r , -129
+v . -37
+v , -37
+w . -37
+w , -37
+y . -55
+y , -55
+charset
+ha 606,722,0,0,-2 2 0000 asciicircum
+ti 606,353,0,0,-1 0 0001 asciitilde
+vS 685,954,15,31,49,31 2 0002 Scaron
+vZ 704,954,0,61,79,61 2 0003 Zcaron
+vs 481,709,15,46,48,46 2 0004 scaron
+vz 519,709,15,27,69,27 2 0005 zcaron
+:Y 704,930,0,123,35,109 2 0006 Ydieresis
+tm 950,722,0,82,8,82 2 0007 trademark
+aq 287,736,0,32,-50,32 2 0010 quotesingle
+space 287 0 0040
+! 333,737,15,53,47,53 2 0041 exclam
+" 400,737,0,157,-50,109 2 0042 quotedbl
+# 574,705,0,9,9,9 2 0043 numbersign
+sh "
+$ 574,799,143,35,47,35 2 0044 dollar
+Do "
+% 889,721,34,0,-1 2 0045 percent
+& 889,737,15,0,19 2 0046 ampersand
+' 259,739,0,92,-20,92 2 0047 quoteright
+( 407,740,123,95,-21,95 2 0050 parenleft
+) 407,740,123,0,120 2 0051 parenright
+* 500,704,0,22,18,22 2 0052 asterisk
++ 606,505,0,0,9 0 0053 plus
+, 287,159,190,0,98 0 0054 comma
+- 333,297,0,0,40 0 0055 hyphen
+hy "
+char173 "
+. 287,159,15,0,38 0 0056 period
+/ 278,737,15,83,75,83 2 0057 slash
+sl "
+0 574,705,15,29,29,29 2 0060 zero
+1 574,705,0,0,25 2 0061 one
+2 574,705,0,14,90,14 2 0062 two
+3 574,705,15,14,55,14 2 0063 three
+4 574,705,0,20,63,20 2 0064 four
+5 574,705,15,49,50,49 2 0065 five
+6 574,705,15,49,20,49 2 0066 six
+7 574,705,15,69,-14,69 2 0067 seven
+8 574,705,15,27,50,27 2 0070 eight
+9 574,705,15,20,49,20 2 0071 nine
+: 287,477,15,20,52,20 0 0072 colon
+; 287,477,190,20,89,20 0 0073 semicolon
+< 606,524,14,0,36 0 0074 less
+= 606,402,0,0,9 0 0075 equal
+> 606,524,14,0,12 0 0076 greater
+? 481,737,15,21,-29,21 2 0077 question
+@ 747,737,15,25,28,25 2 0100 at
+at "
+A 741,737,0,25,125,25 2 0101 A
+B 759,722,0,11,100,11 2 0102 B
+C 759,737,15,50,15,50 2 0103 C
+D 833,722,0,13,99,13 2 0104 D
+E 741,722,0,37,91,37 2 0105 E
+F 704,722,0,72,91,72 2 0106 F
+G 815,737,15,37,16,37 2 0107 G
+H 870,722,0,92,91,92 2 0110 H
+I 444,722,0,92,91,92 2 0111 I
+J 667,722,15,101,59,101 2 0112 J
+K 778,722,0,104,91,104 2 0113 K
+L 704,722,0,16,91,16 2 0114 L
+M 944,722,0,94,74,94 2 0115 M
+N 852,722,16,110,107,109 2 0116 N
+O 833,737,15,14,14,14 2 0117 O
+P 741,722,0,40,88,40 2 0120 P
+Q 833,737,186,13,15,13 2 0121 Q
+R 796,722,15,5,91,5 2 0122 R
+S 685,737,15,31,49,31 2 0123 S
+T 722,722,0,90,6,90 2 0124 T
+U 833,722,15,112,-38,109 2 0125 U
+V 741,722,15,111,18,109 2 0126 V
+W 944,722,15,100,10,100 2 0127 W
+X 741,722,0,120,122,109 2 0130 X
+Y 704,722,0,123,35,109 2 0131 Y
+Z 704,722,0,61,79,61 2 0132 Z
+[ 407,737,110,75,81,75 2 0133 bracketleft
+lB "
+\ 606,737,0,0,-31 2 0134 backslash
+rs "
+] 407,737,110,57,99,57 2 0135 bracketright
+rB "
+a^ 333,709,0,82,27,82 2 0136 circumflex
+^ "
+_ 500,0,129,50,50,50 0 0137 underscore
+` 259,747,0,61,11,61 2 0140 quoteleft
+oq "
+a 667,477,15,29,35,29 0 0141 a
+b 611,737,15,0,22 2 0142 b
+c 537,477,15,0,47 0 0143 c
+d 667,737,15,46,50,46 2 0144 d
+e 519,477,15,9,52,9 0 0145 e
+f 389,737,205,211,98,109 3 0146 f
+g 611,529,205,41,116,41 1 0147 g
+h 685,737,15,2,50,2 2 0150 h
+i 389,737,15,4,22,4 2 0151 i
+j 370,737,205,61,220,61 3 0152 j
+k 648,737,15,0,55 2 0153 k
+l 389,737,15,31,24,31 2 0154 l
+m 944,477,15,26,41,26 0 0155 m
+n 685,477,15,7,47,7 0 0156 n
+o 574,477,15,16,40,16 0 0157 o
+p 648,477,205,0,168 1 0160 p
+q 630,477,205,7,50,7 1 0161 q
+r 519,486,0,55,47,55 0 0162 r
+s 481,477,15,6,48,6 0 0163 s
+t 407,650,15,47,26,47 2 0164 t
+u 685,477,15,4,12,4 0 0165 u
+v 556,477,15,0,18 0 0166 v
+w 833,477,15,5,28,5 0 0167 w
+x 574,477,15,47,99,47 0 0170 x
+y 519,477,205,23,116,23 1 0171 y
+z 519,477,15,2,69,2 0 0172 z
+lC 407,738,115,45,-2,45 2 0173 braceleft
+{ "
+ba 606,737,0,0,-212 2 0174 bar
+| "
+rC 407,738,115,0,80 2 0175 braceright
+} "
+a~ 333,683,0,121,16,109 2 0176 tilde
+~ "
+bq 259,159,191,0,93 0 0200 quotesinglbase
+Fo 481,409,0,0,85 0 0201 guillemotleft
+char171 "
+Fc 481,408,0,25,56,25 0 0202 guillemotright
+char187 "
+bu 606,537,0,0,-59 0 0203 bullet
+Fn 574,737,205,64,77,64 3 0204 florin
+f/ 167,705,15,216,216,109 2 0205 fraction
+%0 1167,721,34,34,24,34 2 0206 perthousand
+dg 500,737,146,60,0,60 2 0207 dagger
+dd 500,737,147,64,98,64 2 0210 daggerdbl
+en 500,286,0,68,68,68 0 0211 endash
+em 1000,286,0,68,68,68 0 0212 emdash
+fi 685,737,205,11,120,11 3 0214 fi
+fl 685,737,205,46,120,46 3 0215 fl
+.i 389,477,15,14,12,14 0 0220 dotlessi
+ga 333,719,0,11,-24,11 2 0222 grave
+a" 333,719,0,189,27,109 2 0223 hungarumlaut
+a. 333,685,0,5,-95,5 2 0224 dotaccent
+ab 333,698,0,107,-17,107 2 0225 breve
+ah 333,709,0,120,-10,109 2 0226 caron
+ao 333,745,0,149,-167,109 2 0227 ring
+ho 333,0,155,0,-18 0 0230 ogonek
+lq 481,747,0,91,-2,91 2 0231 quotedblleft
+rq 481,739,0,102,-11,102 2 0232 quotedblright
+oe 852,477,15,8,55,8 0 0233 oe
+/l 389,737,15,58,24,58 2 0234 lslash
+Bq 481,159,191,0,120 0 0235 quotedblbase
+OE 963,722,0,67,31,67 2 0236 OE
+/L 704,722,0,16,91,16 2 0237 Lslash
+r! 333,544,205,6,89,6 1 0241 exclamdown
+char161 "
+ct 574,600,124,0,20 0 0242 cent
+char162 "
+Po 574,705,15,42,68,42 2 0243 sterling
+char163 "
+Cs 574,612,0,22,10,22 0 0244 currency
+char164 "
+Ye 574,705,0,111,27,109 2 0245 yen
+char165 "
+bb 606,737,0,0,-212 2 0246 brokenbar
+char166 "
+sc 500,737,145,55,90,55 2 0247 section
+char167 "
+ad 333,685,0,109,16,109 2 0250 dieresis
+char168 "
+co 747,737,15,26,27,26 2 0251 copyright
+char169 "
+Of 412,737,0,87,21,87 2 0252 ordfeminine
+char170 "
+fo 278,409,0,0,85 0 0253 guilsinglleft
+no 606,402,0,0,9 0 0254 logicalnot
+char172 "
+\- 606,304,0,0,9 0 0255 minus
+rg 747,737,15,26,27,26 2 0256 registered
+char174 "
+a- 333,649,0,104,18,104 2 0257 macron
+char175 "
+de 400,705,0,20,-20,20 2 0260 degree
+char176 "
+char177 606,505,0,0,9 0 0261 plusminus
+S2 344,705,0,66,66,66 2 0262 twosuperior
+char178 "
+S3 344,705,0,54,54,54 2 0263 threesuperior
+char179 "
+aa 333,719,0,88,-73,88 2 0264 acute
+char180 "
+char181 685,477,205,4,140,4 1 0265 mu
+ps 650,737,0,61,-17,61 2 0266 paragraph
+char182 "
+char183 287,342,0,0,9 0 0267 periodcentered
+ac 333,3,220,0,137 1 0270 cedilla
+char184 "
+S1 344,705,0,29,29,29 2 0271 onesuperior
+char185 "
+Om 356,737,0,77,21,77 2 0272 ordmasculine
+char186 "
+fc 278,408,0,25,56,25 0 0273 guilsinglright
+14 861,705,15,15,29,15 2 0274 onequarter
+char188 "
+12 861,705,15,46,29,46 2 0275 onehalf
+char189 "
+34 861,705,15,15,54,15 2 0276 threequarters
+char190 "
+r? 481,544,205,0,49 1 0277 questiondown
+char191 "
+`A 741,964,0,25,125,25 2 0300 Agrave
+char192 "
+'A 741,964,0,25,125,25 2 0301 Aacute
+char193 "
+^A 741,954,0,25,125,25 2 0302 Acircumflex
+char194 "
+~A 741,928,0,25,125,25 2 0303 Atilde
+char195 "
+:A 741,930,0,25,125,25 2 0304 Adieresis
+char196 "
+oA 741,990,0,25,125,25 2 0305 Aring
+char197 "
+AE 889,722,0,64,131,64 2 0306 AE
+char198 "
+,C 759,737,220,50,15,50 3 0307 Ccedilla
+char199 "
+`E 741,964,0,37,91,37 2 0310 Egrave
+char200 "
+'E 741,964,0,37,91,37 2 0311 Eacute
+char201 "
+^E 741,954,0,37,91,37 2 0312 Ecircumflex
+char202 "
+:E 741,930,0,37,91,37 2 0313 Edieresis
+char203 "
+`I 444,964,0,92,91,92 2 0314 Igrave
+char204 "
+'I 444,964,0,92,91,92 2 0315 Iacute
+char205 "
+^I 444,954,0,92,91,92 2 0316 Icircumflex
+char206 "
+:I 444,930,0,104,91,104 2 0317 Idieresis
+char207 "
+-D 833,722,0,13,99,13 2 0320 Eth
+char208 "
+~N 852,928,16,110,107,109 2 0321 Ntilde
+char209 "
+`O 833,964,15,14,14,14 2 0322 Ograve
+char210 "
+'O 833,964,15,14,14,14 2 0323 Oacute
+char211 "
+^O 833,954,15,14,14,14 2 0324 Ocircumflex
+char212 "
+~O 833,928,15,14,14,14 2 0325 Otilde
+char213 "
+:O 833,930,15,14,14,14 2 0326 Odieresis
+char214 "
+char215 606,507,0,0,9 0 0327 multiply
+/O 833,775,82,14,33,14 2 0330 Oslash
+char216 "
+`U 833,964,15,112,-38,109 2 0331 Ugrave
+char217 "
+'U 833,964,15,112,-38,109 2 0332 Uacute
+char218 "
+^U 833,954,15,112,-38,109 2 0333 Ucircumflex
+char219 "
+:U 833,930,15,112,-38,109 2 0334 Udieresis
+char220 "
+'Y 704,964,0,123,35,109 2 0335 Yacute
+char221 "
+TP 741,722,0,0,88 2 0336 Thorn
+char222 "
+ss 574,737,205,0,116 3 0337 germandbls
+char223 "
+`a 667,719,15,29,35,29 2 0340 agrave
+char224 "
+'a 667,719,15,29,35,29 2 0341 aacute
+char225 "
+^a 667,709,15,29,35,29 2 0342 acircumflex
+char226 "
+~a 667,683,15,29,35,29 2 0343 atilde
+char227 "
+:a 667,685,15,29,35,29 2 0344 adieresis
+char228 "
+oa 667,745,15,29,35,29 2 0345 aring
+char229 "
+ae 815,477,15,9,69,9 0 0346 ae
+char230 "
+,c 537,477,220,0,47 1 0347 ccedilla
+char231 "
+`e 519,719,15,9,52,9 2 0350 egrave
+char232 "
+'e 519,719,15,9,52,9 2 0351 eacute
+char233 "
+^e 519,709,15,9,52,9 2 0352 ecircumflex
+char234 "
+:e 519,685,15,26,52,26 2 0353 edieresis
+char235 "
+`i 389,719,15,14,12,14 2 0354 igrave
+char236 "
+'i 389,719,15,60,12,60 2 0355 iacute
+char237 "
+^i 389,709,15,44,12,44 2 0356 icircumflex
+char238 "
+:i 389,685,15,71,12,71 2 0357 idieresis
+char239 "
+Sd 574,737,15,16,40,16 2 0360 eth
+char240 "
+~n 685,683,15,7,47,7 2 0361 ntilde
+char241 "
+`o 574,719,15,16,40,16 2 0362 ograve
+char242 "
+'o 574,719,15,16,40,16 2 0363 oacute
+char243 "
+^o 574,709,15,16,40,16 2 0364 ocircumflex
+char244 "
+~o 574,683,15,16,40,16 2 0365 otilde
+char245 "
+:o 574,685,15,16,40,16 2 0366 odieresis
+char246 "
+char247 606,505,0,0,9 0 0367 divide
+/o 574,578,126,16,40,16 0 0370 oslash
+char248 "
+`u 685,719,15,4,12,4 2 0371 ugrave
+char249 "
+'u 685,719,15,4,12,4 2 0372 uacute
+char250 "
+^u 685,709,15,4,12,4 2 0373 ucircumflex
+char251 "
+:u 685,685,15,4,12,4 2 0374 udieresis
+char252 "
+'y 519,719,205,23,116,23 3 0375 yacute
+char253 "
+Tp 648,650,205,0,168 3 0376 thorn
+char254 "
+:y 519,685,205,23,116,23 3 0377 ydieresis
+char255 "
diff --git a/gnu/usr.bin/groff/devps/NI b/gnu/usr.bin/groff/devps/NI
new file mode 100644
index 0000000..eb250d7
--- /dev/null
+++ b/gnu/usr.bin/groff/devps/NI
@@ -0,0 +1,447 @@
+name NI
+internalname NewCenturySchlbk-Italic
+slant 16
+spacewidth 278
+encoding text.enc
+ligatures fi fl 0
+kernpairs
+A y -54
+A w -20
+A v -20
+A ' -74
+A Y -74
+A W -92
+A V -111
+A T -74
+F . -129
+F f -18
+F , -129
+F A -74
+L y -55
+L ' -55
+L Y -55
+L W -55
+L V -74
+L T -55
+P . -129
+P , -129
+P A -92
+R y -54
+R Y -74
+R W -55
+R V -20
+R T -20
+T y -89
+T w -89
+T u -89
+T ; -92
+T s -89
+T r -89
+T . -111
+T o -89
+T i -71
+T - -129
+T hy -129
+T char173 -129
+T e -89
+T , -111
+T : -92
+T c -89
+T a -74
+T A -18
+V y -109
+V u -109
+V ; -74
+V r -109
+V . -111
+V o -129
+V i -62
+V - -74
+V hy -74
+V char173 -74
+V e -129
+V , -140
+V : -74
+V a -129
+V A -111
+W y -74
+W u -74
+W ; -37
+W r -74
+W . -55
+W o -74
+W i -74
+W - -37
+W hy -37
+W char173 -37
+W e -74
+W , -55
+W : -37
+W a -74
+W A -74
+Y v -99
+Y u -99
+Y ; -111
+Y q -129
+Y . -129
+Y p -129
+Y o -129
+Y i -70
+Y - -129
+Y hy -129
+Y char173 -129
+Y e -129
+Y , -129
+Y : -111
+Y a -129
+Y A -74
+f ' 94
+1 1 -74
+` ` -18
+` oq -18
+oq ` -18
+oq oq -18
+' t -37
+' s -37
+' ' -18
+r ' 55
+r . -129
+r , -129
+v . -37
+v , -37
+w . -37
+w , -37
+y . -55
+y , -55
+charset
+ha 606,722,0,0,-2 2 0000 asciicircum
+ti 606,335,0,0,9 0 0001 asciitilde
+vS 667,944,15,15,50,15 2 0002 Scaron
+vZ 667,944,0,50,75,50 2 0003 Zcaron
+vs 444,688,15,40,51,40 2 0004 scaron
+vz 463,688,15,30,83,30 2 0005 zcaron
+:Y 685,900,0,123,18,107 2 0006 Ydieresis
+tm 950,722,0,71,2,71 2 0007 trademark
+aq 278,737,0,34,-64,34 2 0010 quotesingle
+space 278 0 0040
+! 333,737,15,33,20,33 2 0041 exclam
+" 400,737,0,45,-50,45 2 0042 quotedbl
+# 556,705,0,18,17,18 2 0043 numbersign
+sh "
+$ 556,800,133,30,47,30 2 0044 dollar
+Do "
+% 833,705,17,9,4,9 2 0045 percent
+& 852,737,15,0,26 2 0046 ampersand
+' 204,737,0,76,11,76 2 0047 quoteright
+( 333,737,124,116,10,107 2 0050 parenleft
+) 333,737,124,0,143 2 0051 parenright
+* 500,705,0,2,16,2 2 0052 asterisk
++ 606,504,0,0,13 0 0053 plus
+, 278,109,165,0,89 0 0054 comma
+- 333,273,0,0,18 0 0055 hyphen
+hy "
+char173 "
+. 278,109,15,0,33 0 0056 period
+/ 606,737,102,0,-90 2 0057 slash
+sl "
+0 556,705,15,21,21,21 2 0060 zero
+1 556,705 2 0061 one
+2 556,705,0,2,85,2 2 0062 two
+3 556,705,15,0,52 2 0063 three
+4 556,705,0,6,58,6 2 0064 four
+5 556,705,15,34,46,34 2 0065 five
+6 556,705,15,41,14,41 2 0066 six
+7 556,705,15,55,-19,55 2 0067 seven
+8 556,705,15,21,42,21 2 0070 eight
+9 556,705,15,13,43,13 2 0071 nine
+: 278,466,15,26,8,26 0 0072 colon
+; 278,466,165,33,64,33 0 0073 semicolon
+< 606,518,10,0,16 0 0074 less
+= 606,381,0,0,14 0 0075 equal
+> 606,518,10,6,-3,6 0 0076 greater
+? 444,737,15,23,-52,23 2 0077 question
+@ 747,737,15,31,22,31 2 0100 at
+at "
+A 704,737,0,14,132,14 2 0101 A
+B 722,722,0,0,81 2 0102 B
+C 722,737,15,41,10,41 2 0103 C
+D 778,722,0,7,88,7 2 0104 D
+E 722,722,0,29,87,29 2 0105 E
+F 667,722,0,81,84,81 2 0106 F
+G 778,737,15,35,11,35 2 0107 G
+H 833,722,0,84,88,84 2 0110 H
+I 407,722,0,74,83,74 2 0111 I
+J 611,722,17,85,63,85 2 0112 J
+K 741,722,0,123,90,107 2 0113 K
+L 667,722,0,13,87,13 2 0114 L
+M 944,722,0,79,76,79 2 0115 M
+N 815,722,17,94,98,94 2 0116 N
+O 778,737,15,7,10,7 2 0117 O
+P 667,722,0,46,83,46 2 0120 P
+Q 778,737,190,7,10,7 2 0121 Q
+R 741,722,17,0,91 2 0122 R
+S 667,737,15,15,50,15 2 0123 S
+T 685,722,0,91,10,91 2 0124 T
+U 815,722,15,95,-43,95 2 0125 U
+V 704,722,15,118,14,107 2 0126 V
+W 926,722,15,97,-3,97 2 0127 W
+X 704,722,0,116,123,107 2 0130 X
+Y 685,722,0,123,18,107 2 0131 Y
+Z 667,722,0,50,75,50 2 0132 Z
+[ 333,737,109,127,83,107 2 0133 bracketleft
+lB "
+\ 606,737,0,0,-39 2 0134 backslash
+rs "
+] 333,737,109,76,133,76 2 0135 bracketright
+rB "
+a^ 333,688,0,48,13,48 2 0136 circumflex
+^ "
+_ 500,0,123,50,50,50 0 0137 underscore
+` 204,749,0,98,-11,98 2 0140 quoteleft
+oq "
+a 574,466,15,0,49 0 0141 a
+b 556,737,15,0,18 2 0142 b
+c 444,466,15,7,45,7 0 0143 c
+d 611,737,15,25,47,25 2 0144 d
+e 444,466,15,0,56 0 0145 e
+f 333,737,205,187,118,107 3 0146 f
+g 537,499,205,36,129,36 1 0147 g
+h 611,737,15,0,50 2 0150 h
+i 333,715,15,0,23 2 0151 i
+j 315,715,205,52,216,52 3 0152 j
+k 556,737,15,0,55 2 0153 k
+l 333,737,15,11,34,11 2 0154 l
+m 889,466,15,0,35 0 0155 m
+n 611,466,15,1,36,1 0 0156 n
+o 500,466,15,0,45 0 0157 o
+p 574,466,205,0,151 1 0160 p
+q 556,466,205,0,50 1 0161 q
+r 444,466,0,39,41,39 0 0162 r
+s 444,466,15,0,51 0 0163 s
+t 352,619,15,27,25,27 2 0164 t
+u 611,466,15,0,9 0 0165 u
+v 519,466,15,0,16 0 0166 v
+w 778,466,15,0,18 0 0167 w
+x 500,466,15,21,83,21 0 0170 x
+y 500,466,205,4,129,4 1 0171 y
+z 463,466,15,4,83,4 0 0172 z
+lC 333,737,116,98,-2,98 2 0173 braceleft
+{ "
+ba 606,737,0,0,-219 2 0174 bar
+| "
+rC 333,737,116,0,148 2 0175 braceright
+} "
+a~ 333,650,0,97,-2,97 2 0176 tilde
+~ "
+bq 204,109,167,0,129 0 0200 quotesinglbase
+Fo 426,399,0,26,65,26 0 0201 guillemotleft
+char171 "
+Fc 426,394,0,24,67,24 0 0202 guillemotright
+char187 "
+bu 606,537,0,0,-64 0 0203 bullet
+Fn 556,737,205,57,107,57 3 0204 florin
+f/ 167,705,17,216,154,107 2 0205 fraction
+%0 1000,705,15,53,56,53 2 0206 perthousand
+dg 500,737,147,68,-14,68 2 0207 dagger
+dd 500,737,148,78,80,78 2 0210 daggerdbl
+en 500,260,0,68,68,68 0 0211 endash
+em 1000,260,0,68,68,68 0 0212 emdash
+fi 611,737,205,3,110,3 3 0214 fi
+fl 611,737,205,33,110,33 3 0215 fl
+.i 333,466,15,0,23 0 0220 dotlessi
+ga 333,691,0,0,-23 2 0222 grave
+a" 333,689,0,237,-84,107 2 0223 hungarumlaut
+a. 333,644,0,0,-68 2 0224 dotaccent
+ab 333,677,0,87,-19,87 2 0225 breve
+ah 333,688,0,95,-23,95 2 0226 caron
+ao 333,712,0,146,-180,107 2 0227 ring
+ho 333,0,155,0,-18 0 0230 ogonek
+lq 389,749,0,93,-13,93 2 0231 quotedblleft
+rq 389,737,0,68,12,68 2 0232 quotedblright
+oe 778,466,17,0,50 0 0233 oe
+/l 333,737,15,59,34,59 2 0234 lslash
+Bq 389,109,167,0,129 0 0235 quotedblbase
+OE 981,722,0,32,14,32 2 0236 OE
+/L 667,722,0,13,87,13 2 0237 Lslash
+r! 333,542,205,0,57 1 0241 exclamdown
+char161 "
+ct 556,595,129,0,-11 0 0242 cent
+char162 "
+Po 556,705,15,39,58,39 2 0243 sterling
+char163 "
+Cs 556,603,0,24,25,24 0 0244 currency
+char164 "
+Ye 556,705,0,117,10,107 2 0245 yen
+char165 "
+bb 606,737,0,0,-219 2 0246 brokenbar
+char166 "
+sc 500,737,147,30,61,30 2 0247 section
+char167 "
+ad 333,644,0,76,-9,76 2 0250 dieresis
+char168 "
+co 747,737,15,27,26,27 2 0251 copyright
+char169 "
+Of 422,737,0,50,-33,50 2 0252 ordfeminine
+char170 "
+fo 333,399,0,0,8 0 0253 guilsinglleft
+no 606,381,0,0,9 0 0254 logicalnot
+char172 "
+\- 606,287,0,0,9 0 0255 minus
+rg 747,737,15,26,27,26 2 0256 registered
+char174 "
+a- 333,610,0,80,-1,80 0 0257 macron
+char175 "
+de 400,705,0,20,-20,20 2 0260 degree
+char176 "
+char177 606,504,0,0,13 0 0261 plusminus
+S2 333,705,0,70,50,70 2 0262 twosuperior
+char178 "
+S3 333,705,0,48,49,48 2 0263 threesuperior
+char179 "
+aa 333,689,0,72,-82,72 2 0264 acute
+char180 "
+char181 611,466,205,0,120 1 0265 mu
+ps 650,737,0,45,-38,45 2 0266 paragraph
+char182 "
+char183 278,316,0,0,-27 0 0267 periodcentered
+ac 333,0,227,0,47 1 0270 cedilla
+char184 "
+S1 333,705,0,26,7,26 2 0271 onesuperior
+char185 "
+Om 372,738,0,50,-33,50 2 0272 ordmasculine
+char186 "
+fc 333,394,0,0,10 0 0273 guilsinglright
+14 834,705,17,49,17,49 2 0274 onequarter
+char188 "
+12 834,705,17,60,17,60 2 0275 onehalf
+char189 "
+34 834,705,17,49,49,49 2 0276 threequarters
+char190 "
+r? 444,542,205,0,43 1 0277 questiondown
+char191 "
+`A 704,947,0,14,132,14 2 0300 Agrave
+char192 "
+'A 704,945,0,14,132,14 2 0301 Aacute
+char193 "
+^A 704,944,0,14,132,14 2 0302 Acircumflex
+char194 "
+~A 704,906,0,14,132,14 2 0303 Atilde
+char195 "
+:A 704,900,0,14,132,14 2 0304 Adieresis
+char196 "
+oA 704,968,0,14,132,14 2 0305 Aring
+char197 "
+AE 870,722,0,50,142,50 2 0306 AE
+char198 "
+,C 722,737,227,41,10,41 3 0307 Ccedilla
+char199 "
+`E 722,947,0,29,87,29 2 0310 Egrave
+char200 "
+'E 722,945,0,29,87,29 2 0311 Eacute
+char201 "
+^E 722,944,0,29,87,29 2 0312 Ecircumflex
+char202 "
+:E 722,900,0,29,87,29 2 0313 Edieresis
+char203 "
+`I 407,947,0,74,83,74 2 0314 Igrave
+char204 "
+'I 407,945,0,74,83,74 2 0315 Iacute
+char205 "
+^I 407,944,0,74,83,74 2 0316 Icircumflex
+char206 "
+:I 407,900,0,89,83,89 2 0317 Idieresis
+char207 "
+-D 778,722,0,7,88,7 2 0320 Eth
+char208 "
+~N 815,906,17,94,98,94 2 0321 Ntilde
+char209 "
+`O 778,947,15,7,10,7 2 0322 Ograve
+char210 "
+'O 778,945,15,7,10,7 2 0323 Oacute
+char211 "
+^O 778,944,15,7,10,7 2 0324 Ocircumflex
+char212 "
+~O 778,906,15,7,10,7 2 0325 Otilde
+char213 "
+:O 778,900,15,7,10,7 2 0326 Odieresis
+char214 "
+char215 606,504,0,0,13 0 0327 multiply
+/O 778,755,87,7,49,7 2 0330 Oslash
+char216 "
+`U 815,947,15,95,-43,95 2 0331 Ugrave
+char217 "
+'U 815,945,15,95,-43,95 2 0332 Uacute
+char218 "
+^U 815,944,15,95,-43,95 2 0333 Ucircumflex
+char219 "
+:U 815,900,15,95,-43,95 2 0334 Udieresis
+char220 "
+'Y 685,945,0,123,18,107 2 0335 Yacute
+char221 "
+TP 667,722,0,7,83,7 2 0336 Thorn
+char222 "
+ss 556,737,205,19,126,19 3 0337 germandbls
+char223 "
+`a 574,691,15,0,49 2 0340 agrave
+char224 "
+'a 574,689,15,0,49 2 0341 aacute
+char225 "
+^a 574,688,15,0,49 2 0342 acircumflex
+char226 "
+~a 574,650,15,0,49 2 0343 atilde
+char227 "
+:a 574,644,15,0,49 2 0344 adieresis
+char228 "
+oa 574,712,15,0,49 2 0345 aring
+char229 "
+ae 722,466,15,0,68 0 0346 ae
+char230 "
+,c 444,466,227,7,45,7 1 0347 ccedilla
+char231 "
+`e 444,691,15,0,56 2 0350 egrave
+char232 "
+'e 444,689,15,17,56,17 2 0351 eacute
+char233 "
+^e 444,688,15,0,56 2 0352 ecircumflex
+char234 "
+:e 444,644,15,11,56,11 2 0353 edieresis
+char235 "
+`i 333,691,15,0,23 2 0354 igrave
+char236 "
+'i 333,689,15,72,23,72 2 0355 iacute
+char237 "
+^i 333,688,15,8,53,8 2 0356 icircumflex
+char238 "
+:i 333,644,15,66,23,66 2 0357 idieresis
+char239 "
+Sd 500,737,15,0,45 2 0360 eth
+char240 "
+~n 611,650,15,1,36,1 2 0361 ntilde
+char241 "
+`o 500,691,15,0,45 2 0362 ograve
+char242 "
+'o 500,689,15,0,45 2 0363 oacute
+char243 "
+^o 500,688,15,0,45 2 0364 ocircumflex
+char244 "
+~o 500,650,15,4,45,4 2 0365 otilde
+char245 "
+:o 500,644,15,0,45 2 0366 odieresis
+char246 "
+char247 606,504,0,0,13 0 0367 divide
+/o 500,549,121,0,55 0 0370 oslash
+char248 "
+`u 611,691,15,0,9 2 0371 ugrave
+char249 "
+'u 611,689,15,0,9 2 0372 uacute
+char250 "
+^u 611,688,15,0,9 2 0373 ucircumflex
+char251 "
+:u 611,644,15,0,9 2 0374 udieresis
+char252 "
+'y 500,689,205,4,129,4 3 0375 yacute
+char253 "
+Tp 574,656,205,0,151 3 0376 thorn
+char254 "
+:y 500,644,205,4,129,4 3 0377 ydieresis
+char255 "
diff --git a/gnu/usr.bin/groff/devps/NR b/gnu/usr.bin/groff/devps/NR
new file mode 100644
index 0000000..d545b2a
--- /dev/null
+++ b/gnu/usr.bin/groff/devps/NR
@@ -0,0 +1,447 @@
+name NR
+internalname NewCenturySchlbk-Roman
+spacewidth 278
+encoding text.enc
+ligatures fi fl 0
+kernpairs
+A y -74
+A w -74
+A v -74
+A ' -74
+A Y -92
+A W -92
+A V -111
+A T -55
+F . -111
+F , -111
+F A -74
+L y -55
+L ' -55
+L Y -92
+L W -74
+L V -92
+L T -55
+P . -129
+P , -129
+P A -74
+R y -18
+R Y -37
+R W -37
+R V -37
+T y -52
+T w -71
+T u -71
+T ; -55
+T s -62
+T r -62
+T . -92
+T o -92
+T i -25
+T - -92
+T hy -92
+T char173 -92
+T e -92
+T , -92
+T : -55
+T c -81
+T a -62
+T A -55
+V y -92
+V u -74
+V ; -74
+V r -74
+V . -129
+V o -92
+V i -44
+V - -92
+V hy -92
+V char173 -92
+V e -92
+V , -129
+V : -74
+V a -92
+V A -111
+W y -74
+W u -55
+W ; -37
+W r -55
+W . -111
+W o -55
+W i -37
+W - -37
+W hy -37
+W char173 -37
+W e -55
+W , -111
+W : -37
+W a -74
+W A -92
+Y v -111
+Y u -92
+Y ; -92
+Y q -111
+Y . -111
+Y p -111
+Y o -111
+Y i -44
+Y - -111
+Y hy -111
+Y char173 -111
+Y e -111
+Y , -111
+Y : -92
+Y a -111
+Y A -92
+f ' 114
+1 1 -55
+` ` -18
+` oq -18
+oq ` -18
+oq oq -18
+' t -18
+' s -37
+' ' -18
+r ' 55
+r . -74
+r - -18
+r hy -18
+r char173 -18
+r , -74
+v . -111
+v , -111
+w . -92
+w , -92
+y . -111
+y , -111
+charset
+ha 606,722 2 0000 asciicircum
+ti 606,329 0 0001 asciitilde
+vS 630,952,15 2 0002 Scaron
+vZ 611,952 2 0003 Zcaron
+vs 463,694,15 2 0004 scaron
+vz 481,694 2 0005 zcaron
+:Y 704,902 2 0006 Ydieresis
+tm 1000,737 2 0007 trademark
+aq 204,737 2 0010 quotesingle
+space 278 0 0040
+! 296,737,15 2 0041 exclam
+" 389,737 2 0042 quotedbl
+# 556,690 2 0043 numbersign
+sh "
+$ 556,804,129 2 0044 dollar
+Do "
+% 833,707,18 2 0045 percent
+& 815,737,15 2 0046 ampersand
+' 204,737 2 0047 quoteright
+( 333,737,124 2 0050 parenleft
+) 333,737,124 2 0051 parenright
+* 500,737 2 0052 asterisk
++ 606,492,13 0 0053 plus
+, 278,109,184 0 0054 comma
+- 333,279 0 0055 hyphen
+hy "
+char173 "
+. 278,109,15 0 0056 period
+/ 278,737,15 2 0057 slash
+sl "
+0 556,705,15 2 0060 zero
+1 556,705 2 0061 one
+2 556,705,4 2 0062 two
+3 556,705,15 2 0063 three
+4 556,705 2 0064 four
+5 556,705,15 2 0065 five
+6 556,705,15 2 0066 six
+7 556,705,15 2 0067 seven
+8 556,705,15 2 0070 eight
+9 556,705,15 2 0071 nine
+: 278,475,15 0 0072 colon
+; 278,475,189 0 0073 semicolon
+< 606,503,25 0 0074 less
+= 606,374 0 0075 equal
+> 606,503,25 0 0076 greater
+? 444,737,15 2 0077 question
+@ 737,737,15 2 0100 at
+at "
+A 722,737 2 0101 A
+B 722,722 2 0102 B
+C 722,737,15 2 0103 C
+D 778,722 2 0104 D
+E 722,722 2 0105 E
+F 667,722 2 0106 F
+G 778,737,15 2 0107 G
+H 833,722 2 0110 H
+I 407,722 2 0111 I
+J 556,722,15 2 0112 J
+K 778,722 2 0113 K
+L 667,722 2 0114 L
+M 944,722 2 0115 M
+N 815,722,15 2 0116 N
+O 778,737,15 2 0117 O
+P 667,722 2 0120 P
+Q 778,737,189 2 0121 Q
+R 722,722,15 2 0122 R
+S 630,737,15 2 0123 S
+T 667,722 2 0124 T
+U 815,722,15 2 0125 U
+V 722,722,15 2 0126 V
+W 981,722,15 2 0127 W
+X 704,722 2 0130 X
+Y 704,722 2 0131 Y
+Z 611,722 2 0132 Z
+[ 333,722,109 2 0133 bracketleft
+lB "
+\ 606,737 2 0134 backslash
+rs "
+] 333,723,108 2 0135 bracketright
+rB "
+a^ 333,694 2 0136 circumflex
+^ "
+_ 500,0,134 0 0137 underscore
+` 204,737 2 0140 quoteleft
+oq "
+a 556,479,15 0 0141 a
+b 556,737,15 2 0142 b
+c 444,479,15 0 0143 c
+d 574,737,15 2 0144 d
+e 500,479,15 0 0145 e
+f 333,737 2 0146 f
+g 537,494,205 1 0147 g
+h 611,737 2 0150 h
+i 315,716 2 0151 i
+j 296,716,205 3 0152 j
+k 593,737 2 0153 k
+l 315,737 2 0154 l
+m 889,479 0 0155 m
+n 611,479 0 0156 n
+o 500,479,15 0 0157 o
+p 574,479,205 1 0160 p
+q 556,479,205 1 0161 q
+r 444,479 0 0162 r
+s 463,479,15 0 0163 s
+t 389,666,15 2 0164 t
+u 611,464,15 0 0165 u
+v 537,464,15 0 0166 v
+w 778,464,15 0 0167 w
+x 537,464 0 0170 x
+y 537,464,205 1 0171 y
+z 481,464 0 0172 z
+lC 333,722,109 2 0173 braceleft
+{ "
+ba 606,737 2 0174 bar
+| "
+rC 333,722,109 2 0175 braceright
+} "
+a~ 333,659 0 0176 tilde
+~ "
+bq 204,104,189 0 0200 quotesinglbase
+Fo 426,397 0 0201 guillemotleft
+char171 "
+Fc 426,399 0 0202 guillemotright
+char187 "
+bu 606,554 0 0203 bullet
+Fn 556,737,205 3 0204 florin
+f/ 167,705 2 0205 fraction
+%0 1000,699,1 2 0206 perthousand
+dg 500,737,147 2 0207 dagger
+dd 500,737,151 2 0210 daggerdbl
+en 556,269 0 0211 endash
+em 1000,269 0 0212 emdash
+fi 611,737 2 0214 fi
+fl 611,737 2 0215 fl
+.i 315,464 0 0220 dotlessi
+ga 333,699 2 0222 grave
+a" 333,714 2 0223 hungarumlaut
+a. 333,644 0 0224 dotaccent
+ab 333,685 2 0225 breve
+ah 333,694 2 0226 caron
+ao 333,722 2 0227 ring
+ho 333,0,163 0 0230 ogonek
+lq 389,737 2 0231 quotedblleft
+rq 389,737 2 0232 quotedblright
+oe 833,479,15 0 0233 oe
+/l 315,737 2 0234 lslash
+Bq 389,104,189 0 0235 quotedblbase
+OE 1000,722 2 0236 OE
+/L 667,722 2 0237 Lslash
+r! 296,547,205 1 0241 exclamdown
+char161 "
+ct 556,584,141 0 0242 cent
+char162 "
+Po 556,705,15 2 0243 sterling
+char163 "
+Cs 556,603 0 0244 currency
+char164 "
+Ye 556,705 2 0245 yen
+char165 "
+bb 606,737 2 0246 brokenbar
+char166 "
+sc 500,737,147 2 0247 section
+char167 "
+ad 333,644 0 0250 dieresis
+char168 "
+co 737,737,15 2 0251 copyright
+char169 "
+Of 334,722 2 0252 ordfeminine
+char170 "
+fo 259,397 0 0253 guilsinglleft
+no 606,374 0 0254 logicalnot
+char172 "
+\- 606,277 0 0255 minus
+rg 737,737,15 2 0256 registered
+char174 "
+a- 333,622 0 0257 macron
+char175 "
+de 400,705 2 0260 degree
+char176 "
+char177 606,492 0 0261 plusminus
+S2 333,705 2 0262 twosuperior
+char178 "
+S3 333,705 2 0263 threesuperior
+char179 "
+aa 333,699 2 0264 acute
+char180 "
+char181 611,464,205 1 0265 mu
+ps 606,722,147 2 0266 paragraph
+char182 "
+char183 278,302 0 0267 periodcentered
+ac 333,0,215 1 0270 cedilla
+char184 "
+S1 333,705 2 0271 onesuperior
+char185 "
+Om 300,722 2 0272 ordmasculine
+char186 "
+fc 259,399 0 0273 guilsinglright
+14 834,705 2 0274 onequarter
+char188 "
+12 834,705,2 2 0275 onehalf
+char189 "
+34 834,705 2 0276 threequarters
+char190 "
+r? 444,547,205 1 0277 questiondown
+char191 "
+`A 722,957 2 0300 Agrave
+char192 "
+'A 722,957 2 0301 Aacute
+char193 "
+^A 722,952 2 0302 Acircumflex
+char194 "
+~A 722,917 2 0303 Atilde
+char195 "
+:A 722,902 2 0304 Adieresis
+char196 "
+oA 722,980 2 0305 Aring
+char197 "
+AE 1000,722 2 0306 AE
+char198 "
+,C 722,737,215 3 0307 Ccedilla
+char199 "
+`E 722,957 2 0310 Egrave
+char200 "
+'E 722,957 2 0311 Eacute
+char201 "
+^E 722,952 2 0312 Ecircumflex
+char202 "
+:E 722,902 2 0313 Edieresis
+char203 "
+`I 407,957 2 0314 Igrave
+char204 "
+'I 407,957 2 0315 Iacute
+char205 "
+^I 407,952 2 0316 Icircumflex
+char206 "
+:I 407,902 2 0317 Idieresis
+char207 "
+-D 778,722 2 0320 Eth
+char208 "
+~N 815,917,15 2 0321 Ntilde
+char209 "
+`O 778,957,15 2 0322 Ograve
+char210 "
+'O 778,957,15 2 0323 Oacute
+char211 "
+^O 778,952,15 2 0324 Ocircumflex
+char212 "
+~O 778,917,15 2 0325 Otilde
+char213 "
+:O 778,902,15 2 0326 Odieresis
+char214 "
+char215 606,491,13 0 0327 multiply
+/O 778,760,74 2 0330 Oslash
+char216 "
+`U 815,957,15 2 0331 Ugrave
+char217 "
+'U 815,957,15 2 0332 Uacute
+char218 "
+^U 815,952,15 2 0333 Ucircumflex
+char219 "
+:U 815,902,15 2 0334 Udieresis
+char220 "
+'Y 704,957 2 0335 Yacute
+char221 "
+TP 667,722 2 0336 Thorn
+char222 "
+ss 574,737,15 2 0337 germandbls
+char223 "
+`a 556,699,15 2 0340 agrave
+char224 "
+'a 556,699,15 2 0341 aacute
+char225 "
+^a 556,694,15 2 0342 acircumflex
+char226 "
+~a 556,659,15 0 0343 atilde
+char227 "
+:a 556,644,15 0 0344 adieresis
+char228 "
+oa 556,722,15 2 0345 aring
+char229 "
+ae 796,479,15 0 0346 ae
+char230 "
+,c 444,479,215 1 0347 ccedilla
+char231 "
+`e 500,699,15 2 0350 egrave
+char232 "
+'e 500,699,15 2 0351 eacute
+char233 "
+^e 500,694,15 2 0352 ecircumflex
+char234 "
+:e 500,644,15 0 0353 edieresis
+char235 "
+`i 315,699 2 0354 igrave
+char236 "
+'i 315,699 2 0355 iacute
+char237 "
+^i 315,694 2 0356 icircumflex
+char238 "
+:i 315,644 0 0357 idieresis
+char239 "
+Sd 500,740,15 2 0360 eth
+char240 "
+~n 611,659 0 0361 ntilde
+char241 "
+`o 500,699,15 2 0362 ograve
+char242 "
+'o 500,699,15 2 0363 oacute
+char243 "
+^o 500,694,15 2 0364 ocircumflex
+char244 "
+~o 500,659,15 0 0365 otilde
+char245 "
+:o 500,644,15 0 0366 odieresis
+char246 "
+char247 606,493,11 0 0367 divide
+/o 500,556,102 0 0370 oslash
+char248 "
+`u 611,699,15 2 0371 ugrave
+char249 "
+'u 611,699,15 2 0372 uacute
+char250 "
+^u 611,694,15 2 0373 ucircumflex
+char251 "
+:u 611,644,15 0 0374 udieresis
+char252 "
+'y 537,699,205 3 0375 yacute
+char253 "
+Tp 574,737,205 3 0376 thorn
+char254 "
+:y 537,644,205 1 0377 ydieresis
+char255 "
diff --git a/gnu/usr.bin/groff/devps/PB b/gnu/usr.bin/groff/devps/PB
new file mode 100644
index 0000000..348281a
--- /dev/null
+++ b/gnu/usr.bin/groff/devps/PB
@@ -0,0 +1,449 @@
+name PB
+internalname Palatino-Bold
+spacewidth 250
+encoding text.enc
+ligatures fi fl 0
+kernpairs
+A y -70
+A w -70
+A v -70
+A ' -92
+A Y -111
+A W -90
+A V -129
+A T -92
+F . -111
+F , -111
+F A -55
+L y -74
+L ' -74
+L Y -92
+L W -92
+L V -92
+L T -74
+P . -129
+P , -129
+P A -74
+R y -30
+R Y -55
+R W -37
+R V -74
+R T -55
+T y -90
+T w -90
+T u -129
+T ; -74
+T s -111
+T r -111
+T . -92
+T o -111
+T i -55
+T - -92
+T hy -92
+T char173 -92
+T e -111
+T , -92
+T : -74
+T c -129
+T a -111
+T A -92
+V y -90
+V u -92
+V ; -74
+V r -111
+V . -129
+V o -111
+V i -55
+V - -92
+V hy -92
+V char173 -92
+V e -111
+V , -129
+V : -74
+V a -111
+V A -129
+W y -74
+W u -74
+W ; -37
+W r -74
+W . -37
+W o -74
+W i -37
+W - -37
+W hy -37
+W char173 -37
+W e -74
+W , -92
+W : -37
+W a -74
+W A -90
+Y v -74
+Y u -74
+Y ; -55
+Y q -92
+Y . -74
+Y p -74
+Y o -74
+Y i -55
+Y - -74
+Y hy -74
+Y char173 -74
+Y e -74
+Y , -74
+Y : -55
+Y a -74
+Y A -55
+f ' 37
+f f -18
+1 1 -37
+` ` -55
+` oq -55
+oq ` -55
+oq oq -55
+' t -18
+' s -55
+' ' -55
+r ' 55
+r . -55
+r - -18
+r hy -18
+r char173 -18
+r , -55
+v . -111
+v , -111
+w . -92
+w , -92
+y . -92
+y , -92
+charset
+ha 606,678 2 0000 asciicircum
+ti 606,342 0 0001 asciitilde
+vS 611,909,17 2 0002 Scaron
+vZ 667,909,3 2 0003 Zcaron
+vs 444,693,17 2 0004 scaron
+vz 500,693,3 2 0005 zcaron
+:Y 667,895,3 2 0006 Ydieresis
+tm 998,678 2 0007 trademark
+aq 227,695 2 0010 quotesingle
+space 250 0 0040
+! 278,688,12 2 0041 exclam
+" 402,695 2 0042 quotedbl
+# 500,673 2 0043 numbersign
+sh "
+$ 500,721,114 2 0044 dollar
+Do "
+% 889,714,9 2 0045 percent
+& 833,684,17 2 0046 ampersand
+' 278,695 2 0047 quoteright
+( 333,723,104 2 0050 parenleft
+) 333,723,104 2 0051 parenright
+* 444,695 2 0052 asterisk
++ 606,505 0 0053 plus
+, 250,141,166 0 0054 comma
+- 333,305 0 0055 hyphen
+hy "
+char173 "
+. 250,144,12 0 0056 period
+/ 296,720,17 2 0057 slash
+sl "
+0 500,660,17 2 0060 zero
+1 500,670,3 2 0061 one
+2 500,660,3 2 0062 two
+3 500,660,17 2 0063 three
+4 500,672,3 2 0064 four
+5 500,656,17 2 0065 five
+6 500,660,17 2 0066 six
+7 500,656,3 2 0067 seven
+8 500,660,17 2 0070 eight
+9 500,660,17 2 0071 nine
+: 250,454,12 0 0072 colon
+; 250,454,166 0 0073 semicolon
+< 606,519,15 0 0074 less
+= 606,396 0 0075 equal
+> 606,519,15 0 0076 greater
+? 444,687,12 2 0077 question
+@ 747,681,12 2 0100 at
+at "
+A 778,686,3 2 0101 A
+B 667,681,3 2 0102 B
+C 722,695,17 2 0103 C
+D 833,681,3 2 0104 D
+E 611,681,4 2 0105 E
+F 556,681,3 2 0106 F
+G 833,695,17 2 0107 G
+H 833,681,3 2 0110 H
+I 389,681,3 2 0111 I
+J 389,681,213 2 0112 J
+K 778,681,3 2 0113 K
+L 611,681,4 2 0114 L
+M 1000,681,10 2 0115 M
+N 833,681,16 2 0116 N
+O 833,695,17 2 0117 O
+P 611,681,3 2 0120 P
+Q 833,695,184 2 0121 Q
+R 722,681,3 2 0122 R
+S 611,695,17 2 0123 S
+T 667,681,3 2 0124 T
+U 778,681,17 2 0125 U
+V 778,681,3 2 0126 V
+W 1000,686,3 2 0127 W
+X 667,695,3 2 0130 X
+Y 667,695,3 2 0131 Y
+Z 667,681,3 2 0132 Z
+[ 333,720,104 2 0133 bracketleft
+lB "
+\ 606,720 2 0134 backslash
+rs "
+] 333,720,104 2 0135 bracketright
+rB "
+a^ 333,681 2 0136 circumflex
+^ "
+_ 500,0,125 0 0137 underscore
+` 278,695 2 0140 quoteleft
+oq "
+a 500,471,17 0 0141 a
+b 611,720,17 2 0142 b
+c 444,471,17 0 0143 c
+d 611,720,17 2 0144 d
+e 500,471,17 0 0145 e
+f 389,720,3 2 0146 f
+g 556,471,266 1 0147 g
+h 611,720,3 2 0150 h
+i 333,706,3 2 0151 i
+j 333,706,266 3 0152 j
+k 611,720,3 2 0153 k
+l 333,720,3 2 0154 l
+m 889,471,3 0 0155 m
+n 611,471,3 0 0156 n
+o 556,471,17 0 0157 o
+p 611,471,258 1 0160 p
+q 611,471,258 1 0161 q
+r 389,471,3 0 0162 r
+s 444,471,17 0 0163 s
+t 333,632,17 2 0164 t
+u 611,471,17 0 0165 u
+v 556,459,3 0 0166 v
+w 833,471,3 0 0167 w
+x 500,471,3 0 0170 x
+y 556,459,266 1 0171 y
+z 500,459,3 0 0172 z
+lC 310,725,117 2 0173 braceleft
+{ "
+ba 606,720 2 0174 bar
+| "
+rC 310,725,117 2 0175 braceright
+} "
+a~ 333,661 2 0176 tilde
+~ "
+bq 333,130,160 0 0200 quotesinglbase
+Fo 500,438 0 0201 guillemotleft
+char171 "
+Fc 500,438 0 0202 guillemotright
+char187 "
+bu 606,516 0 0203 bullet
+Fn 500,703,242 2 0204 florin
+f/ 167,660 2 0205 fraction
+%0 1000,724,9 2 0206 perthousand
+dg 500,682,6 2 0207 dagger
+dd 500,682,245 2 0210 daggerdbl
+en 500,291 0 0211 endash
+em 1000,291 0 0212 emdash
+fi 611,720,3 2 0214 fi
+fl 611,720,3 2 0215 fl
+.i 333,471,3 0 0220 dotlessi
+ga 333,691 2 0222 grave
+a" 333,691 2 0223 hungarumlaut
+a. 333,671 2 0224 dotaccent
+ab 333,669 2 0225 breve
+ah 333,685 2 0226 caron
+ao 333,700 2 0227 ring
+ho 333,0,246 0 0230 ogonek
+lq 500,695 2 0231 quotedblleft
+rq 500,695 2 0232 quotedblright
+oe 833,471,17 0 0233 oe
+/l 333,720,3 2 0234 lslash
+Bq 500,130,160 0 0235 quotedblbase
+OE 1000,695,17 2 0236 OE
+/L 611,681,4 2 0237 Lslash
+r! 278,471,227 0 0241 exclamdown
+char161 "
+ct 500,554,106 0 0242 cent
+char162 "
+Po 500,676,19 2 0243 sterling
+char163 "
+Cs 500,533 0 0244 currency
+char164 "
+Ye 500,695,3 2 0245 yen
+char165 "
+bb 606,720 2 0246 brokenbar
+char166 "
+sc 500,695,217 2 0247 section
+char167 "
+ad 333,671 2 0250 dieresis
+char168 "
+co 747,695,17 2 0251 copyright
+char169 "
+Of 438,660 2 0252 ordfeminine
+char170 "
+fo 389,438 0 0253 guilsinglleft
+no 606,396 0 0254 logicalnot
+char172 "
+\- 606,298 0 0255 minus
+rg 747,695,17 2 0256 registered
+char174 "
+a- 333,609 0 0257 macron
+char175 "
+de 400,660 2 0260 degree
+char176 "
+char177 606,505 0 0261 plusminus
+S2 300,660 2 0262 twosuperior
+char178 "
+S3 300,667 2 0263 threesuperior
+char179 "
+aa 333,691 2 0264 acute
+char180 "
+char181 611,471,225 0 0265 mu
+ps 641,683,161 2 0266 paragraph
+char182 "
+char183 250,335 0 0267 periodcentered
+ac 333,0,225 0 0270 cedilla
+char184 "
+S1 300,665 2 0271 onesuperior
+char185 "
+Om 488,660 2 0272 ordmasculine
+char186 "
+fc 389,438 0 0273 guilsinglright
+14 750,665,2 2 0274 onequarter
+char188 "
+12 750,665,2 2 0275 onehalf
+char189 "
+34 750,667,2 2 0276 threequarters
+char190 "
+r? 444,471,231 0 0277 questiondown
+char191 "
+`A 778,915,3 2 0300 Agrave
+char192 "
+'A 778,915,3 2 0301 Aacute
+char193 "
+^A 778,905,3 2 0302 Acircumflex
+char194 "
+~A 778,885,3 2 0303 Atilde
+char195 "
+:A 778,895,3 2 0304 Adieresis
+char196 "
+oA 778,924,3 2 0305 Aring
+char197 "
+AE 1000,681,4 2 0306 AE
+char198 "
+,C 722,695,225 2 0307 Ccedilla
+char199 "
+`E 611,915,4 2 0310 Egrave
+char200 "
+'E 611,915,4 2 0311 Eacute
+char201 "
+^E 611,905,4 2 0312 Ecircumflex
+char202 "
+:E 611,895,4 2 0313 Edieresis
+char203 "
+`I 389,915,3 2 0314 Igrave
+char204 "
+'I 389,915,3 2 0315 Iacute
+char205 "
+^I 389,905,3 2 0316 Icircumflex
+char206 "
+:I 389,895,3 2 0317 Idieresis
+char207 "
+-D 833,681,3 2 0320 Eth
+char208 "
+~N 833,885,16 2 0321 Ntilde
+char209 "
+`O 833,915,17 2 0322 Ograve
+char210 "
+'O 833,915,17 2 0323 Oacute
+char211 "
+^O 833,905,17 2 0324 Ocircumflex
+char212 "
+~O 833,885,17 2 0325 Otilde
+char213 "
+:O 833,895,17 2 0326 Odieresis
+char214 "
+char215 606,483 0 0327 multiply
+/O 833,698,20 2 0330 Oslash
+char216 "
+`U 778,915,17 2 0331 Ugrave
+char217 "
+'U 778,915,17 2 0332 Uacute
+char218 "
+^U 778,905,17 2 0333 Ucircumflex
+char219 "
+:U 778,895,17 2 0334 Udieresis
+char220 "
+'Y 667,915,3 2 0335 Yacute
+char221 "
+TP 611,681,3 2 0336 Thorn
+char222 "
+ss 611,720,17 2 0337 germandbls
+char223 "
+`a 500,711,17 2 0340 agrave
+char224 "
+'a 500,711,17 2 0341 aacute
+char225 "
+^a 500,701,17 2 0342 acircumflex
+char226 "
+~a 500,673,17 2 0343 atilde
+char227 "
+:a 500,691,17 2 0344 adieresis
+char228 "
+oa 500,700,17 2 0345 aring
+char229 "
+ae 778,471,17 0 0346 ae
+char230 "
+,c 444,471,225 0 0347 ccedilla
+char231 "
+`e 500,711,17 2 0350 egrave
+char232 "
+'e 500,711,17 2 0351 eacute
+char233 "
+^e 500,701,17 2 0352 ecircumflex
+char234 "
+:e 500,691,17 2 0353 edieresis
+char235 "
+`i 333,711,3 2 0354 igrave
+char236 "
+'i 333,711,3 2 0355 iacute
+char237 "
+^i 333,701,3 2 0356 icircumflex
+char238 "
+:i 333,691,3 2 0357 idieresis
+char239 "
+Sd 556,720,17 2 0360 eth
+char240 "
+~n 611,673,3 2 0361 ntilde
+char241 "
+`o 556,711,17 2 0362 ograve
+char242 "
+'o 556,711,17 2 0363 oacute
+char243 "
+^o 556,701,17 2 0364 ocircumflex
+char244 "
+~o 556,673,17 2 0365 otilde
+char245 "
+:o 556,691,17 2 0366 odieresis
+char246 "
+char247 606,510 0 0367 divide
+/o 556,471,18 0 0370 oslash
+char248 "
+`u 611,711,17 2 0371 ugrave
+char249 "
+'u 611,711,17 2 0372 uacute
+char250 "
+^u 611,701,17 2 0373 ucircumflex
+char251 "
+:u 611,691,17 2 0374 udieresis
+char252 "
+'y 556,711,266 3 0375 yacute
+char253 "
+Tp 611,720,258 3 0376 thorn
+char254 "
+:y 556,691,266 3 0377 ydieresis
+char255 "
diff --git a/gnu/usr.bin/groff/devps/PBI b/gnu/usr.bin/groff/devps/PBI
new file mode 100644
index 0000000..37facbe
--- /dev/null
+++ b/gnu/usr.bin/groff/devps/PBI
@@ -0,0 +1,451 @@
+name PBI
+internalname Palatino-BoldItalic
+slant 10
+spacewidth 250
+encoding text.enc
+ligatures fi fl 0
+kernpairs
+A y -55
+A w -37
+A v -55
+A ' -55
+A Y -74
+A W -74
+A V -74
+A T -55
+F . -111
+F , -111
+F A -74
+L y -37
+L ' -55
+L Y -74
+L W -74
+L V -74
+L T -74
+P . -129
+P , -129
+P A -92
+R y -20
+R Y -37
+R W -55
+R V -55
+R T -37
+T y -80
+T w -50
+T u -92
+T ; -55
+T s -92
+T r -92
+T . -55
+T o -111
+T i -74
+T - -92
+T hy -92
+T char173 -92
+T e -111
+T , -55
+T : -55
+T c -92
+T a -111
+T O -18
+T A -55
+V y -50
+V u -50
+V ; -37
+V r -74
+V . -111
+V o -74
+V i -50
+V - -37
+V hy -37
+V char173 -37
+V e -74
+V , -111
+V : -37
+V a -92
+V A -74
+W y -30
+W u -30
+W ; -18
+W r -30
+W . -55
+W o -55
+W i -30
+W e -55
+W , -55
+W : -28
+W a -74
+W A -74
+Y v -30
+Y u -50
+Y ; -55
+Y q -92
+Y . -55
+Y p -74
+Y o -111
+Y i -54
+Y - -55
+Y hy -55
+Y char173 -55
+Y e -92
+Y , -55
+Y : -55
+Y a -111
+Y A -55
+f ' 37
+f f -37
+1 1 -55
+` ` -55
+` oq -55
+oq ` -55
+oq oq -55
+' t -18
+' s -37
+' ' -55
+r ' 55
+r q -18
+r . -55
+r o -18
+r h -18
+r g -18
+r e -18
+r , -55
+r c -18
+v . -55
+v , -55
+w . -55
+w , -55
+y . -37
+y , -37
+charset
+ha 606,678,0,0,-13 2 0000 asciicircum
+ti 606,346,0,0,-1 0 0001 asciitilde
+vS 556,896,17,51,0,51 2 0002 Scaron
+vZ 667,896,3,59,49,59 2 0003 Zcaron
+vs 444,692,17,95,25,66 2 0004 scaron
+vz 500,692,17,67,19,66 2 0005 zcaron
+:Y 611,880,3,114,-4,66 2 0006 Ydieresis
+tm 1000,678,0,11,12,11 2 0007 trademark
+aq 250,720,0,93,-77,66 2 0010 quotesingle
+space 250 0 0040
+! 333,695,17,39,-8,39 2 0041 exclam
+" 500,720,0,43,-87,43 2 0042 quotedbl
+# 500,673,0,46,46,46 2 0043 numbersign
+sh "
+$ 500,737,108,27,30,27 2 0044 dollar
+Do "
+% 889,697,17,0,-6 2 0045 percent
+& 833,695,17,28,-24,28 2 0046 ampersand
+' 278,720,0,74,-26,66 2 0047 quoteright
+( 333,723,129,85,-8,66 2 0050 parenleft
+) 333,723,129,15,62,15 2 0051 parenright
+* 444,695,0,45,-34,45 2 0052 asterisk
++ 606,501,5 0 0053 plus
+, 250,147,164,8,83,8 0 0054 comma
+- 389,300,0,23,13,23 0 0055 hyphen
+hy "
+char173 "
+. 250,135,17,0,2 0 0056 period
+/ 315,720,17,50,49,50 2 0057 slash
+sl "
+0 500,683,17,40,8,40 2 0060 zero
+1 500,678,3,0,9 2 0061 one
+2 500,683,3,4,49,4 2 0062 two
+3 500,683,17,0,42 2 0063 three
+4 500,683,3,37,47,37 2 0064 four
+5 500,675,17,31,36,31 2 0065 five
+6 500,683,17,38,11,38 2 0066 six
+7 500,674,3,94,-19,66 2 0067 seven
+8 500,683,17,34,24,34 2 0070 eight
+9 500,683,17,41,23,41 2 0071 nine
+: 250,452,17,36,12,36 0 0072 colon
+; 250,452,164,47,83,47 0 0073 semicolon
+< 606,517,21,2,1,2 0 0074 less
+= 606,390,0,0,-1 0 0075 equal
+> 606,517,21,1,2,1 0 0076 greater
+? 444,695,17,56,-41,56 2 0077 question
+@ 833,681,12,0,-32 2 0100 at
+at "
+A 722,683,3,13,85,13 2 0101 A
+B 667,681,3,12,42,12 2 0102 B
+C 685,695,17,60,-19,60 2 0103 C
+D 778,682,3,19,50,19 2 0104 D
+E 611,681,3,45,39,45 2 0105 E
+F 556,681,3,87,56,66 2 0106 F
+G 778,695,17,22,-22,22 2 0107 G
+H 778,681,3,98,62,66 2 0110 H
+I 389,681,3,73,51,66 2 0111 I
+J 389,681,207,78,79,66 2 0112 J
+K 722,681,3,74,60,66 2 0113 K
+L 611,681,3,17,24,17 2 0114 L
+M 944,681,17,91,73,66 2 0115 M
+N 778,681,3,101,52,66 2 0116 N
+O 833,695,17,11,-26,11 2 0117 O
+P 667,681,3,56,39,56 2 0120 P
+Q 833,695,222,11,-26,11 2 0121 Q
+R 722,681,3,25,46,25 2 0122 R
+S 556,695,17,11,0,11 2 0123 S
+T 611,681,3,113,-6,66 2 0124 T
+U 778,681,17,97,-33,66 2 0125 U
+V 667,681,3,128,-17,66 2 0126 V
+W 1000,689,3,123,-17,66 2 0127 W
+X 722,681,3,100,59,66 2 0130 X
+Y 611,695,3,114,-4,66 2 0131 Y
+Z 667,681,3,59,49,59 2 0132 Z
+[ 333,723,102,98,5,66 2 0133 bracketleft
+lB "
+\ 606,720,0,0,-22 2 0134 backslash
+rs "
+] 333,723,102,32,71,32 2 0135 bracketright
+rB "
+a^ 333,684,0,132,-38,66 2 0136 circumflex
+^ "
+_ 500,0,125,50,50,50 0 0137 underscore
+` 278,720,0,63,-15,63 2 0140 quoteleft
+oq "
+a 556,470,17,13,6,13 0 0141 a
+b 537,726,17,7,6,7 2 0142 b
+c 444,469,17,42,18,42 0 0143 c
+d 556,726,17,44,12,44 2 0144 d
+e 444,469,17,24,22,24 0 0145 e
+f 333,726,271,166,180,66 3 0146 f
+g 500,469,271,79,100,66 1 0147 g
+h 556,726,17,16,28,16 2 0150 h
+i 333,695,17,29,24,29 2 0151 i
+j 333,695,271,40,114,40 3 0152 j
+k 556,726,17,22,16,22 2 0153 k
+l 333,726,17,35,-14,35 2 0154 l
+m 833,469,17,20,31,20 0 0155 m
+n 556,469,17,15,33,15 0 0156 n
+o 556,469,17,0,2 0 0157 o
+p 556,469,271,10,71,10 1 0160 p
+q 537,469,271,26,18,26 1 0161 q
+r 389,469,17,72,30,66 0 0162 r
+s 444,469,17,12,25,12 0 0163 s
+t 389,636,17,70,8,66 2 0164 t
+u 556,469,17,15,28,15 0 0165 u
+v 556,469,17,7,31,7 0 0166 v
+w 833,469,17,19,23,19 0 0167 w
+x 500,469,17,50,58,50 0 0170 x
+y 556,469,271,35,37,35 1 0171 y
+z 500,469,17,20,19,20 0 0172 z
+lC 333,720,105,51,32,51 2 0173 braceleft
+{ "
+ba 606,720,0,0,-209 2 0174 bar
+| "
+rC 333,720,105,32,51,32 2 0175 braceright
+} "
+a~ 333,654,0,158,-32,66 2 0176 tilde
+~ "
+bq 250,145,144,20,53,20 0 0200 quotesinglbase
+Fo 500,446,0,8,15,8 0 0201 guillemotleft
+char171 "
+Fc 500,443,0,8,15,8 0 0202 guillemotright
+char187 "
+bu 606,516,0,0,-81 0 0203 bullet
+Fn 500,690,242,29,42,29 2 0204 florin
+f/ 167,683,0,221,220,66 2 0205 fraction
+%0 1000,691,17,0,-15 2 0206 perthousand
+dg 556,685,3,0,-17 2 0207 dagger
+dd 556,693,153,31,17,31 2 0210 daggerdbl
+en 500,282,0,62,62,62 0 0211 endash
+em 1000,282,0,62,62,62 0 0212 emdash
+fi 611,726,271,27,180,27 3 0214 fi
+fl 611,726,271,70,180,66 3 0215 fl
+.i 333,469,17,10,24,10 0 0220 dotlessi
+ga 333,699,0,39,-60,39 2 0222 grave
+a" 333,699,0,126,78,66 2 0223 hungarumlaut
+a. 333,668,0,42,-152,42 2 0224 dotaccent
+ab 333,680,0,129,-46,66 2 0225 breve
+ah 333,684,0,162,-63,66 2 0226 caron
+ao 556,714,0,0,-227 2 0227 ring
+ho 333,0,206,0,18 0 0230 ogonek
+lq 500,720,0,61,-15,61 2 0231 quotedblleft
+rq 500,720,0,69,-23,66 2 0232 quotedblright
+oe 778,469,17,27,2,27 0 0233 oe
+/l 333,726,17,82,37,66 2 0234 lslash
+Bq 500,145,144,0,68 0 0235 quotedblbase
+OE 944,695,17,67,11,66 2 0236 OE
+/L 611,681,3,17,44,17 2 0237 Lslash
+r! 333,479,225,0,48 0 0241 exclamdown
+char161 "
+ct 500,547,105,6,-2,6 0 0242 cent
+char162 "
+Po 500,683,5,51,29,51 2 0243 sterling
+char163 "
+Cs 500,533,0,18,18,18 0 0244 currency
+char164 "
+Ye 500,695,3,88,39,66 2 0245 yen
+char165 "
+bb 606,720,0,0,-209 2 0246 brokenbar
+char166 "
+sc 556,695,151,0,3 2 0247 section
+char167 "
+ad 333,668,0,143,-40,66 2 0250 dieresis
+char168 "
+co 747,695,17,23,24,23 2 0251 copyright
+char169 "
+Of 333,684,0,72,3,66 2 0252 ordfeminine
+char170 "
+fo 333,446,0,9,-10,9 0 0253 guilsinglleft
+no 606,390,0,0,-1 0 0254 logicalnot
+char172 "
+\- 606,292,0,0,-1 0 0255 minus
+rg 747,695,17,23,24,23 2 0256 registered
+char174 "
+a- 333,608,0,135,-26,66 0 0257 macron
+char175 "
+de 400,683 2 0260 degree
+char176 "
+char177 606,501 0 0261 plusminus
+S2 300,683,0,71,24,66 2 0262 twosuperior
+char178 "
+S3 300,683,0,60,27,60 2 0263 threesuperior
+char179 "
+aa 333,699,0,109,-103,66 2 0264 acute
+char180 "
+char181 556,469,232,15,65,15 0 0265 mu
+ps 556,681,204,123,36,66 2 0266 paragraph
+char182 "
+char183 250,324,0,6,-17,6 0 0267 periodcentered
+ac 333,5,218,0,38 0 0270 cedilla
+char184 "
+S1 300,680,0,48,9,48 2 0271 onesuperior
+char185 "
+Om 333,683,0,63,-1,63 2 0272 ordmasculine
+char186 "
+fc 333,443,0,0,15 0 0273 guilsinglright
+14 750,683,2,32,32,32 2 0274 onequarter
+char188 "
+12 750,683,2,36,36,36 2 0275 onehalf
+char189 "
+34 750,683,2,32,32,32 2 0276 threequarters
+char190 "
+r? 444,479,226,0,62 0 0277 questiondown
+char191 "
+`A 722,911,3,13,85,13 2 0300 Agrave
+char192 "
+'A 722,911,3,13,85,13 2 0301 Aacute
+char193 "
+^A 722,896,3,13,85,13 2 0302 Acircumflex
+char194 "
+~A 722,866,3,13,85,13 2 0303 Atilde
+char195 "
+:A 722,880,3,13,85,13 2 0304 Adieresis
+char196 "
+oA 722,926,3,13,85,13 2 0305 Aring
+char197 "
+AE 944,681,3,33,79,33 2 0306 AE
+char198 "
+,C 685,695,218,60,-19,60 2 0307 Ccedilla
+char199 "
+`E 611,911,3,45,39,45 2 0310 Egrave
+char200 "
+'E 611,911,3,45,39,45 2 0311 Eacute
+char201 "
+^E 611,896,3,45,39,45 2 0312 Ecircumflex
+char202 "
+:E 611,880,3,45,39,45 2 0313 Edieresis
+char203 "
+`I 389,911,3,73,51,66 2 0314 Igrave
+char204 "
+'I 389,911,3,81,51,66 2 0315 Iacute
+char205 "
+^I 389,896,3,104,51,66 2 0316 Icircumflex
+char206 "
+:I 389,880,3,115,51,66 2 0317 Idieresis
+char207 "
+-D 778,682,3,19,50,19 2 0320 Eth
+char208 "
+~N 778,866,3,101,52,66 2 0321 Ntilde
+char209 "
+`O 833,911,17,11,-26,11 2 0322 Ograve
+char210 "
+'O 833,911,17,11,-26,11 2 0323 Oacute
+char211 "
+^O 833,896,17,11,-26,11 2 0324 Ocircumflex
+char212 "
+~O 833,866,17,11,-26,11 2 0325 Otilde
+char213 "
+:O 833,880,17,11,-26,11 2 0326 Odieresis
+char214 "
+char215 606,479,0,0,-22 0 0327 multiply
+/O 833,730,54,14,-7,14 2 0330 Oslash
+char216 "
+`U 778,911,17,97,-33,66 2 0331 Ugrave
+char217 "
+'U 778,911,17,97,-33,66 2 0332 Uacute
+char218 "
+^U 778,896,17,97,-33,66 2 0333 Ucircumflex
+char219 "
+:U 778,880,17,97,-33,66 2 0334 Udieresis
+char220 "
+'Y 611,911,3,114,-4,66 2 0335 Yacute
+char221 "
+TP 667,681,3,27,39,27 2 0336 Thorn
+char222 "
+ss 556,726,271,43,181,43 3 0337 germandbls
+char223 "
+`a 556,719,17,13,6,13 2 0340 agrave
+char224 "
+'a 556,719,17,13,6,13 2 0341 aacute
+char225 "
+^a 556,704,17,21,6,21 2 0342 acircumflex
+char226 "
+~a 556,666,17,47,6,47 2 0343 atilde
+char227 "
+:a 556,688,17,32,6,32 2 0344 adieresis
+char228 "
+oa 556,714,17,13,6,13 2 0345 aring
+char229 "
+ae 738,469,17,23,6,23 0 0346 ae
+char230 "
+,c 444,469,218,42,18,42 0 0347 ccedilla
+char231 "
+`e 444,719,17,24,22,24 2 0350 egrave
+char232 "
+'e 444,719,17,54,22,54 2 0351 eacute
+char233 "
+^e 444,704,17,77,22,66 2 0352 ecircumflex
+char234 "
+:e 444,688,17,88,22,66 2 0353 edieresis
+char235 "
+`i 333,719,17,39,24,39 2 0354 igrave
+char236 "
+'i 333,719,17,109,24,66 2 0355 iacute
+char237 "
+^i 333,704,17,120,24,66 2 0356 icircumflex
+char238 "
+:i 333,688,17,143,24,66 2 0357 idieresis
+char239 "
+Sd 556,726,17,40,2,40 2 0360 eth
+char240 "
+~n 556,666,17,47,33,47 2 0361 ntilde
+char241 "
+`o 556,719,17,0,2 2 0362 ograve
+char242 "
+'o 556,719,17,0,2 2 0363 oacute
+char243 "
+^o 556,704,17,9,2,9 2 0364 ocircumflex
+char244 "
+~o 556,666,17,47,2,47 2 0365 otilde
+char245 "
+:o 556,688,17,32,2,32 2 0366 odieresis
+char246 "
+char247 606,501,5 0 0367 divide
+/o 556,506,50,16,36,16 0 0370 oslash
+char248 "
+`u 556,719,17,15,28,15 2 0371 ugrave
+char249 "
+'u 556,719,17,15,28,15 2 0372 uacute
+char250 "
+^u 556,704,17,15,28,15 2 0373 ucircumflex
+char251 "
+:u 556,688,17,32,28,32 2 0374 udieresis
+char252 "
+'y 556,719,271,35,37,35 3 0375 yacute
+char253 "
+Tp 556,726,271,10,71,10 3 0376 thorn
+char254 "
+:y 556,688,271,35,37,35 3 0377 ydieresis
+char255 "
diff --git a/gnu/usr.bin/groff/devps/PI b/gnu/usr.bin/groff/devps/PI
new file mode 100644
index 0000000..7839606
--- /dev/null
+++ b/gnu/usr.bin/groff/devps/PI
@@ -0,0 +1,453 @@
+name PI
+internalname Palatino-Italic
+slant 10
+spacewidth 250
+encoding text.enc
+ligatures fi fl 0
+kernpairs
+A y -55
+A w -37
+A v -37
+A ' -55
+A Y -55
+A W -55
+A V -74
+A T -55
+F . -111
+F , -111
+F A -111
+L y -37
+L ' -37
+L Y -74
+L W -74
+L V -74
+L T -74
+P . -129
+P , -129
+P A -129
+R y -37
+R Y -55
+R W -55
+R V -74
+R T -55
+T y -92
+T w -92
+T u -111
+T ; -74
+T s -111
+T r -111
+T . -74
+T o -111
+T i -55
+T - -55
+T hy -55
+T char173 -55
+T e -111
+T , -74
+T : -74
+T c -111
+T a -111
+T O -18
+T A -92
+V y -74
+V u -74
+V ; -37
+V r -92
+V . -129
+V o -74
+V i -74
+V - -55
+V hy -55
+V char173 -55
+V e -92
+V , -129
+V : -37
+V a -74
+V A -210
+W y -20
+W u -20
+W ; -18
+W r -20
+W . -55
+W o -20
+W i -20
+W - -18
+W hy -18
+W char173 -18
+W e -20
+W , -55
+W : -18
+W a -20
+W A -92
+Y v -74
+Y u -92
+Y ; -74
+Y q -92
+Y . -92
+Y p -74
+Y o -111
+Y i -55
+Y - -74
+Y hy -74
+Y char173 -74
+Y e -111
+Y , -92
+Y : -74
+Y a -92
+Y A -92
+f ' 55
+1 1 -55
+` ` -74
+` oq -74
+oq ` -74
+oq oq -74
+' t -37
+' s -55
+' ' -74
+r ' 37
+r q -18
+r . -74
+r o -18
+r h -18
+r g -18
+r e -18
+r , -74
+r c -18
+v . -55
+v , -55
+w . -55
+w , -55
+y . -37
+y , -37
+charset
+ha 606,689,0,0,-1 2 0000 asciicircum
+ti 606,339,0,0,-1 0 0001 asciitilde
+vS 556,907,18,33,8,33 2 0002 Scaron
+vZ 667,907,3,20,30,20 2 0003 Zcaron
+vs 389,687,11,80,41,68 2 0004 scaron
+vz 444,687,11,53,51,53 2 0005 zcaron
+:Y 667,847,3,58,-2,58 2 0006 Ydieresis
+tm 1000,689,0,1,-2,1 2 0007 trademark
+aq 333,733,0,5,-90,5 2 0010 quotesingle
+space 250 0 0040
+! 333,733,8,9,-26,9 2 0041 exclam
+" 500,733,0,5,-90,5 2 0042 quotedbl
+# 500,692,0,45,46,45 2 0043 numbersign
+sh "
+$ 500,733,113,2,35,2 2 0044 dollar
+Do "
+% 889,710,7,0,-24 2 0045 percent
+& 778,692,18,38,3,38 2 0046 ampersand
+' 278,733,0,30,-28,30 2 0047 quoteright
+( 333,733,106,48,-4,48 2 0050 parenleft
+) 333,733,106,0,48 2 0051 parenright
+* 389,706,0,61,-26,61 2 0052 asterisk
++ 606,504,0,0,-1 0 0053 plus
+, 250,123,143,3,42,3 0 0054 comma
+- 333,281,0,21,31,21 0 0055 hyphen
+hy "
+char173 "
+. 250,112,5,0,-3 0 0056 period
+/ 296,733,119,146,90,68 2 0057 slash
+sl "
+0 500,699,11,30,14,30 2 0060 zero
+1 500,699,3,0,-4 2 0061 one
+2 500,699,3,0,38 2 0062 two
+3 500,699,11,0,28 2 0063 three
+4 500,699,3,28,35,28 2 0064 four
+5 500,693,11,41,36,41 2 0065 five
+6 500,699,11,19,1,19 2 0066 six
+7 500,692,3,52,-3,52 2 0067 seven
+8 500,699,11,19,14,19 2 0070 eight
+9 500,699,11,18,18,18 2 0071 nine
+: 250,458,5,7,6,7 0 0072 colon
+; 250,456,146,19,59,19 0 0073 semicolon
+< 606,516,6,0,-3 0 0074 less
+= 606,378,0,0,-1 0 0075 equal
+> 606,516,6,0,-3 0 0076 greater
+? 500,706,8,0,-64 2 0077 question
+@ 747,706,18,21,23,21 2 0100 at
+at "
+A 722,705,3,5,69,5 2 0101 A
+B 611,692,6,0,24 2 0102 B
+C 667,706,18,34,5,34 2 0103 C
+D 778,692,3,13,22,13 2 0104 D
+E 611,692,3,9,20,9 2 0105 E
+F 556,692,3,42,50,42 2 0106 F
+G 722,706,18,22,0,22 2 0107 G
+H 778,692,3,72,53,68 2 0110 H
+I 333,692,3,71,43,68 2 0111 I
+J 333,692,206,75,85,68 2 0112 J
+K 667,692,3,66,37,66 2 0113 K
+L 556,692,3,17,34,17 2 0114 L
+M 944,692,18,46,69,46 2 0115 M
+N 778,692,11,76,48,68 2 0116 N
+O 778,706,18,20,-3,20 2 0117 O
+P 611,692,3,33,41,33 2 0120 P
+Q 778,706,201,20,-3,20 2 0121 Q
+R 667,692,3,22,41,22 2 0122 R
+S 556,706,18,0,8 2 0123 S
+T 611,692,3,74,-3,68 2 0124 T
+U 778,692,18,70,-38,68 2 0125 U
+V 722,692,8,82,-25,68 2 0126 V
+W 944,700,8,86,-21,68 2 0127 W
+X 722,692,3,62,30,62 2 0130 X
+Y 667,705,3,58,-2,58 2 0131 Y
+Z 667,692,3,20,30,20 2 0132 Z
+[ 333,733,100,43,32,43 2 0133 bracketleft
+lB "
+\ 606,733,0,0,-31 2 0134 backslash
+rs "
+] 333,733,100,32,43,32 2 0135 bracketright
+rB "
+a^ 333,679,0,67,-6,67 2 0136 circumflex
+^ "
+_ 500,0,125,50,50,50 0 0137 underscore
+` 278,733,0,30,-28,30 2 0140 quoteleft
+oq "
+a 444,482,11,12,46,12 0 0141 a
+b 463,733,11,20,13,20 2 0142 b
+c 407,482,11,32,25,32 0 0143 c
+d 500,733,11,33,33,33 2 0144 d
+e 389,482,11,35,35,35 0 0145 e
+f 278,733,276,185,212,68 3 0146 f
+g 500,482,276,48,87,48 1 0147 g
+h 500,733,9,21,40,21 2 0150 h
+i 278,712,9,36,16,36 2 0151 i
+j 278,712,276,37,120,37 3 0152 j
+k 444,733,9,55,42,55 2 0153 k
+l 278,733,9,23,14,23 2 0154 l
+m 778,482,9,12,26,12 0 0155 m
+n 556,482,9,8,26,8 0 0156 n
+o 444,482,11,17,33,17 0 0157 o
+p 500,482,276,15,57,15 1 0160 p
+q 463,482,276,19,26,19 1 0161 q
+r 389,482,9,45,24,45 0 0162 r
+s 389,482,11,6,41,6 0 0163 s
+t 333,646,9,27,9,27 2 0164 t
+u 556,482,11,6,18,6 0 0165 u
+v 500,482,11,27,29,27 0 0166 v
+w 722,482,11,27,29,27 0 0167 w
+x 500,482,11,34,41,34 0 0170 x
+y 500,482,276,40,58,40 1 0171 y
+z 444,482,11,22,51,22 0 0172 z
+lC 333,733,100,36,35,36 2 0173 braceleft
+{ "
+ba 606,733,0,0,-225 2 0174 bar
+| "
+rC 333,733,100,35,36,35 2 0175 braceright
+} "
+a~ 333,638,0,107,-13,68 0 0176 tilde
+~ "
+bq 278,120,122,0,23 0 0200 quotesinglbase
+Fo 500,440,0,0,-7 0 0201 guillemotleft
+char171 "
+Fc 500,440,0,0,-13 0 0202 guillemotright
+char187 "
+bu 500,526,0,0,-36 0 0203 bullet
+Fn 500,708,276,20,45,20 3 0204 florin
+f/ 167,699,0,220,220,68 2 0205 fraction
+%0 1000,717,6,0,-22 2 0206 perthousand
+dg 500,692,0,19,2,19 2 0207 dagger
+dd 500,692,162,44,40,44 2 0210 daggerdbl
+en 500,278,0,60,60,60 0 0211 endash
+em 1000,278,0,60,60,60 0 0212 emdash
+fi 528,733,276,24,212,24 3 0214 fi
+fl 545,733,276,25,212,25 3 0215 fl
+.i 278,482,9,13,16,13 0 0220 dotlessi
+ga 333,687,0,27,-36,27 2 0222 grave
+a" 333,730,0,102,4,68 2 0223 hungarumlaut
+a. 333,645,0,0,-125 2 0224 dotaccent
+ab 333,677,0,110,-42,68 2 0225 breve
+ah 333,679,0,126,-54,68 2 0226 caron
+ao 333,708,0,76,-109,68 2 0227 ring
+ho 333,0,207,0,12 0 0230 ogonek
+lq 500,733,0,25,-48,25 2 0231 quotedblleft
+rq 500,733,0,25,-48,25 2 0232 quotedblright
+oe 669,482,11,35,33,35 0 0233 oe
+/l 278,733,9,74,60,68 2 0234 lslash
+Bq 500,120,122,0,7 0 0235 quotedblbase
+OE 1028,706,18,11,-6,11 2 0236 OE
+/L 556,692,3,17,66,17 2 0237 Lslash
+r! 333,467,276,0,35 1 0241 exclamdown
+char161 "
+ct 500,551,96,0,-6 0 0242 cent
+char162 "
+Po 500,708,18,29,48,29 2 0243 sterling
+char163 "
+Cs 500,577,0,36,36,36 0 0244 currency
+char164 "
+Ye 500,699,3,62,15,62 2 0245 yen
+char165 "
+bb 606,733,0,0,-225 2 0246 brokenbar
+char166 "
+sc 500,706,220,13,36,13 2 0247 section
+char167 "
+ad 333,637,0,95,-28,68 0 0250 dieresis
+char168 "
+co 747,706,18,39,39,39 2 0251 copyright
+char169 "
+Of 333,699,0,38,-10,38 2 0252 ordfeminine
+char170 "
+fo 333,440,0,0,-7 0 0253 guilsinglleft
+no 606,378,0,0,-1 0 0254 logicalnot
+char172 "
+\- 606,280,0,0,-1 0 0255 minus
+rg 747,706,18,39,39,39 2 0256 registered
+char174 "
+a- 333,589,0,103,-24,68 0 0257 macron
+char175 "
+de 400,689,0,40,-40,40 2 0260 degree
+char176 "
+char177 606,504,0,0,-1 0 0261 plusminus
+S2 300,699,0,40,37,40 2 0262 twosuperior
+char178 "
+S3 300,699,0,54,22,54 2 0263 threesuperior
+char179 "
+aa 333,687,0,63,-72,63 2 0264 acute
+char180 "
+char181 556,482,226,6,35,6 0 0265 mu
+ps 500,692,224,161,17,68 2 0266 paragraph
+char182 "
+char183 250,312,0,0,-3 0 0267 periodcentered
+ac 333,0,216,0,59 0 0270 cedilla
+char184 "
+S1 300,699,0,35,-11,35 2 0271 onesuperior
+char185 "
+Om 333,699,0,39,-16,39 2 0272 ordmasculine
+char186 "
+fc 333,440,0,0,-13 0 0273 guilsinglright
+14 750,699,2,15,19,15 2 0274 onequarter
+char188 "
+12 750,699,2,21,19,21 2 0275 onehalf
+char189 "
+34 750,699,2,15,15,15 2 0276 threequarters
+char190 "
+r? 500,467,246,0,-7 0 0277 questiondown
+char191 "
+`A 722,897,3,5,69,5 2 0300 Agrave
+char192 "
+'A 722,897,3,5,69,5 2 0301 Aacute
+char193 "
+^A 722,889,3,5,69,5 2 0302 Acircumflex
+char194 "
+~A 722,866,3,5,69,5 2 0303 Atilde
+char195 "
+:A 722,847,3,5,69,5 2 0304 Adieresis
+char196 "
+oA 722,918,3,5,69,5 2 0305 Aring
+char197 "
+AE 941,692,3,11,54,11 2 0306 AE
+char198 "
+,C 667,706,216,34,5,34 2 0307 Ccedilla
+char199 "
+`E 611,897,3,9,20,9 2 0310 Egrave
+char200 "
+'E 611,897,3,9,20,9 2 0311 Eacute
+char201 "
+^E 611,889,3,9,20,9 2 0312 Ecircumflex
+char202 "
+:E 611,847,3,9,20,9 2 0313 Edieresis
+char203 "
+`I 333,897,3,71,43,68 2 0314 Igrave
+char204 "
+'I 333,897,3,123,43,68 2 0315 Iacute
+char205 "
+^I 333,889,3,107,43,68 2 0316 Icircumflex
+char206 "
+:I 333,847,3,135,43,68 2 0317 Idieresis
+char207 "
+-D 778,692,3,13,31,13 2 0320 Eth
+char208 "
+~N 778,866,11,76,48,68 2 0321 Ntilde
+char209 "
+`O 778,897,18,20,-3,20 2 0322 Ograve
+char210 "
+'O 778,897,18,20,-3,20 2 0323 Oacute
+char211 "
+^O 778,889,18,20,-3,20 2 0324 Ocircumflex
+char212 "
+~O 778,866,18,20,-3,20 2 0325 Otilde
+char213 "
+:O 778,847,18,20,-3,20 2 0326 Odieresis
+char214 "
+char215 606,474,0,0,-33 0 0327 multiply
+/O 778,721,39,34,18,34 2 0330 Oslash
+char216 "
+`U 778,897,18,70,-38,68 2 0331 Ugrave
+char217 "
+'U 778,897,18,70,-38,68 2 0332 Uacute
+char218 "
+^U 778,889,18,70,-38,68 2 0333 Ucircumflex
+char219 "
+:U 778,847,18,70,-38,68 2 0334 Udieresis
+char220 "
+'Y 667,897,3,58,-2,58 2 0335 Yacute
+char221 "
+TP 611,692,3,9,41,9 2 0336 Thorn
+char222 "
+ss 500,733,276,38,210,38 3 0337 germandbls
+char223 "
+`a 444,707,11,12,46,12 2 0340 agrave
+char224 "
+'a 444,707,11,20,46,20 2 0341 aacute
+char225 "
+^a 444,699,11,12,46,12 2 0342 acircumflex
+char226 "
+~a 444,650,11,52,46,52 2 0343 atilde
+char227 "
+:a 444,657,11,40,46,40 2 0344 adieresis
+char228 "
+oa 444,728,11,12,46,12 2 0345 aring
+char229 "
+ae 638,482,11,35,49,35 0 0346 ae
+char230 "
+,c 407,482,216,32,25,32 0 0347 ccedilla
+char231 "
+`e 389,707,11,35,35,35 2 0350 egrave
+char232 "
+'e 389,707,11,55,35,55 2 0351 eacute
+char233 "
+^e 389,699,11,59,35,59 2 0352 ecircumflex
+char234 "
+:e 389,657,11,67,35,67 2 0353 edieresis
+char235 "
+`i 278,707,9,43,16,43 2 0354 igrave
+char236 "
+'i 278,707,9,103,16,68 2 0355 iacute
+char237 "
+^i 278,699,9,95,21,68 2 0356 icircumflex
+char238 "
+:i 278,657,9,123,16,68 2 0357 idieresis
+char239 "
+Sd 444,733,11,84,33,68 2 0360 eth
+char240 "
+~n 556,650,9,8,26,8 2 0361 ntilde
+char241 "
+`o 444,707,11,17,33,17 2 0362 ograve
+char242 "
+'o 444,707,11,20,33,20 2 0363 oacute
+char243 "
+^o 444,699,11,17,33,17 2 0364 ocircumflex
+char244 "
+~o 444,650,11,52,33,52 2 0365 otilde
+char245 "
+:o 444,657,11,40,33,40 2 0366 odieresis
+char246 "
+char247 606,504,0,0,-1 0 0367 divide
+/o 444,510,24,66,68,66 0 0370 oslash
+char248 "
+`u 556,707,11,6,18,6 2 0371 ugrave
+char249 "
+'u 556,707,11,6,18,6 2 0372 uacute
+char250 "
+^u 556,699,11,6,18,6 2 0373 ucircumflex
+char251 "
+:u 556,657,11,6,18,6 2 0374 udieresis
+char252 "
+'y 500,707,276,40,58,40 3 0375 yacute
+char253 "
+Tp 500,733,276,0,89 3 0376 thorn
+char254 "
+:y 500,657,276,40,58,40 3 0377 ydieresis
+char255 "
diff --git a/gnu/usr.bin/groff/devps/PR b/gnu/usr.bin/groff/devps/PR
new file mode 100644
index 0000000..4dd5626
--- /dev/null
+++ b/gnu/usr.bin/groff/devps/PR
@@ -0,0 +1,456 @@
+name PR
+internalname Palatino-Roman
+spacewidth 250
+encoding text.enc
+ligatures fi fl 0
+kernpairs
+A y -74
+A w -74
+A v -92
+A ' -74
+A Y -111
+A W -74
+A V -111
+A T -74
+F . -92
+F , -92
+F A -74
+L y -55
+L ' -74
+L Y -92
+L W -74
+L V -92
+L T -74
+P . -129
+P , -129
+P A -92
+R y -37
+R Y -37
+R W -37
+R V -55
+R T -37
+T y -90
+T w -90
+T u -90
+T ; -55
+T s -90
+T r -90
+T . -74
+T o -92
+T i -55
+T - -55
+T hy -55
+T char173 -55
+T e -92
+T , -74
+T : -55
+T c -111
+T a -92
+T O -18
+T A -74
+V y -92
+V u -92
+V ; -55
+V r -92
+V . -129
+V o -111
+V i -55
+V - -74
+V hy -74
+V char173 -74
+V e -111
+V , -129
+V : -55
+V a -92
+V A -111
+W y -50
+W u -50
+W ; -18
+W r -74
+W . -92
+W o -92
+W i -55
+W - -55
+W hy -55
+W char173 -55
+W e -92
+W , -92
+W : -18
+W a -92
+W A -92
+Y v -90
+Y u -90
+Y ; -74
+Y q -90
+Y . -111
+Y p -111
+Y o -92
+Y i -55
+Y - -92
+Y hy -92
+Y char173 -92
+Y e -92
+Y , -111
+Y : -74
+Y a -92
+Y A -92
+f ' 55
+f f -18
+1 1 -55
+` ` -37
+` oq -37
+oq ` -37
+oq oq -37
+' ' -37
+r u -8
+r ' 74
+r q -18
+r . -74
+r o -18
+r - -18
+r hy -18
+r char173 -18
+r h -18
+r g -18
+r e -18
+r d -18
+r , -74
+r c -18
+v . -111
+v , -111
+w . -92
+w , -92
+y . -111
+y , -111
+charset
+ha 606,689 2 0000 asciicircum
+ti 606,347 0 0001 asciitilde
+vS 525,908,20 2 0002 Scaron
+vZ 667,908,3 2 0003 Zcaron
+vs 424,685,20 2 0004 scaron
+vz 500,685,3 2 0005 zcaron
+:Y 667,868,3 2 0006 Ydieresis
+tm 979,689 2 0007 trademark
+aq 208,709 2 0010 quotesingle
+space 250 0 0040
+! 278,694,5 2 0041 exclam
+" 371,709 2 0042 quotedbl
+# 500,684 2 0043 numbersign
+sh "
+$ 500,731,116 2 0044 dollar
+Do "
+% 840,709,20 2 0045 percent
+& 778,689,20 2 0046 ampersand
+' 278,709 2 0047 quoteright
+( 333,726,215 2 0050 parenleft
+) 333,726,215 2 0051 parenright
+* 389,689 2 0052 asterisk
++ 606,512 0 0053 plus
+, 250,123,155 0 0054 comma
+- 333,287 0 0055 hyphen
+hy "
+char173 "
+. 250,111,5 0 0056 period
+/ 606,726,119 2 0057 slash
+sl "
+0 500,689,20 2 0060 zero
+1 500,694,3 2 0061 one
+2 500,689,3 2 0062 two
+3 500,689,20 2 0063 three
+4 500,694,3 2 0064 four
+5 500,689,20 2 0065 five
+6 500,689,20 2 0066 six
+7 500,689,3 2 0067 seven
+8 500,689,20 2 0070 eight
+9 500,689,20 2 0071 nine
+: 250,456,5 0 0072 colon
+; 250,456,153 0 0073 semicolon
+< 606,522 0 0074 less
+= 606,386 0 0075 equal
+> 606,522 0 0076 greater
+? 444,694,5 2 0077 question
+@ 747,694,20 2 0100 at
+at "
+A 778,700,3 2 0101 A
+B 611,692,3 2 0102 B
+C 709,709,20 2 0103 C
+D 774,692,3 2 0104 D
+E 611,692,3 2 0105 E
+F 556,692,3 2 0106 F
+G 763,709,20 2 0107 G
+H 832,692,3 2 0110 H
+I 337,692,3 2 0111 I
+J 333,692,194 2 0112 J
+K 726,692,3 2 0113 K
+L 611,692,3 2 0114 L
+M 946,692,13 2 0115 M
+N 831,692,20 2 0116 N
+O 786,709,20 2 0117 O
+P 604,692,3 2 0120 P
+Q 786,709,176 2 0121 Q
+R 668,692,3 2 0122 R
+S 525,709,20 2 0123 S
+T 613,692,3 2 0124 T
+U 778,692,20 2 0125 U
+V 722,692,9 2 0126 V
+W 1000,700,9 2 0127 W
+X 667,700,3 2 0130 X
+Y 667,704,3 2 0131 Y
+Z 667,692,3 2 0132 Z
+[ 333,726,184 2 0133 bracketleft
+lB "
+\ 606,726 2 0134 backslash
+rs "
+] 333,726,184 2 0135 bracketright
+rB "
+a^ 333,677 2 0136 circumflex
+^ "
+_ 500,0,125 0 0137 underscore
+` 278,709 2 0140 quoteleft
+oq "
+a 500,469,12 0 0141 a
+b 553,726,12 2 0142 b
+c 444,469,20 0 0143 c
+d 611,726,12 2 0144 d
+e 479,469,20 0 0145 e
+f 333,728,3 2 0146 f
+g 556,469,283 1 0147 g
+h 582,726,3 2 0150 h
+i 291,687,3 2 0151 i
+j 234,688,283 3 0152 j
+k 556,726,12 2 0153 k
+l 291,726,3 2 0154 l
+m 883,469,3 0 0155 m
+n 582,469,3 0 0156 n
+o 546,469,20 0 0157 o
+p 601,469,281 1 0160 p
+q 560,469,281 1 0161 q
+r 395,469,3 0 0162 r
+s 424,469,20 0 0163 s
+t 326,621,12 2 0164 t
+u 603,469,12 0 0165 u
+v 565,459,7 0 0166 v
+w 834,469,7 0 0167 w
+x 516,469,3 0 0170 x
+y 556,459,283 1 0171 y
+z 500,462,3 0 0172 z
+lC 333,726,175 2 0173 braceleft
+{ "
+ba 606,726 2 0174 bar
+| "
+rC 333,726,175 2 0175 braceright
+} "
+a~ 333,640 2 0176 tilde
+~ "
+bq 278,110,153 0 0200 quotesinglbase
+Fo 500,428 0 0201 guillemotleft
+char171 "
+Fc 500,428 0 0202 guillemotright
+char187 "
+bu 606,516 0 0203 bullet
+Fn 500,706,262 2 0204 florin
+f/ 167,689 2 0205 fraction
+%0 1144,709,20 2 0206 perthousand
+dg 500,694,5 2 0207 dagger
+dd 500,694,249 2 0210 daggerdbl
+en 500,277 0 0211 endash
+em 1000,277 0 0212 emdash
+fi 605,728,3 2 0214 fi
+fl 608,728,3 2 0215 fl
+.i 287,469,3 0 0220 dotlessi
+ga 333,677 2 0222 grave
+a" 380,687 2 0223 hungarumlaut
+a. 250,637 2 0224 dotaccent
+ab 333,664 2 0225 breve
+ah 333,677 2 0226 caron
+ao 333,696 2 0227 ring
+ho 313,0,165 0 0230 ogonek
+lq 500,709 2 0231 quotedblleft
+rq 500,709 2 0232 quotedblright
+oe 827,469,20 0 0233 oe
+/l 291,726,3 2 0234 lslash
+Bq 500,110,153 0 0235 quotedblbase
+OE 998,709,20 2 0236 OE
+/L 611,692,3 2 0237 Lslash
+r! 278,469,225 0 0241 exclamdown
+char161 "
+ct 500,562,101 0 0242 cent
+char162 "
+Po 500,694,13 2 0243 sterling
+char163 "
+Cs 500,531 0 0244 currency
+char164 "
+Ye 500,701,3 2 0245 yen
+char165 "
+bb 606,726 2 0246 brokenbar
+char166 "
+sc 500,709,219 2 0247 section
+char167 "
+ad 333,637 2 0250 dieresis
+char168 "
+co 747,706,18 2 0251 copyright
+char169 "
+Of 333,709 2 0252 ordfeminine
+char170 "
+fo 331,428 0 0253 guilsinglleft
+no 606,386 0 0254 logicalnot
+char172 "
+\- 606,289 0 0255 minus
+rg 747,706,18 2 0256 registered
+char174 "
+a- 333,591 0 0257 macron
+char175 "
+de 400,689 2 0260 degree
+char176 "
+char177 606,512 0 0261 plusminus
+S2 300,689 2 0262 twosuperior
+char178 "
+S3 300,689 2 0263 threesuperior
+char179 "
+aa 333,677 2 0264 acute
+char180 "
+char181 603,469,236 0 0265 mu
+ps 628,694,150 2 0266 paragraph
+char182 "
+char183 250,319 0 0267 periodcentered
+ac 333,0,225 0 0270 cedilla
+char184 "
+S1 300,692 2 0271 onesuperior
+char185 "
+Om 333,709 2 0272 ordmasculine
+char186 "
+fc 331,428 0 0273 guilsinglright
+14 750,692,3 2 0274 onequarter
+char188 "
+12 750,692,3 2 0275 onehalf
+char189 "
+34 750,689,3 2 0276 threequarters
+char190 "
+r? 444,469,231 0 0277 questiondown
+char191 "
+`A 778,908,3 2 0300 Agrave
+char192 "
+'A 778,908,3 2 0301 Aacute
+char193 "
+^A 778,908,3 2 0302 Acircumflex
+char194 "
+~A 778,871,3 2 0303 Atilde
+char195 "
+:A 778,868,3 2 0304 Adieresis
+char196 "
+oA 778,927,3 2 0305 Aring
+char197 "
+AE 944,692,3 2 0306 AE
+char198 "
+,C 709,709,225 2 0307 Ccedilla
+char199 "
+`E 611,908,3 2 0310 Egrave
+char200 "
+'E 611,908,3 2 0311 Eacute
+char201 "
+^E 611,908,3 2 0312 Ecircumflex
+char202 "
+:E 611,868,3 2 0313 Edieresis
+char203 "
+`I 337,908,3 2 0314 Igrave
+char204 "
+'I 337,908,3 2 0315 Iacute
+char205 "
+^I 337,908,3 2 0316 Icircumflex
+char206 "
+:I 337,868,3 2 0317 Idieresis
+char207 "
+-D 774,692,3 2 0320 Eth
+char208 "
+~N 831,871,20 2 0321 Ntilde
+char209 "
+`O 786,908,20 2 0322 Ograve
+char210 "
+'O 786,908,20 2 0323 Oacute
+char211 "
+^O 786,908,20 2 0324 Ocircumflex
+char212 "
+~O 786,883,20 2 0325 Otilde
+char213 "
+:O 786,868,20 2 0326 Odieresis
+char214 "
+char215 606,474 0 0327 multiply
+/O 833,709,20 2 0330 Oslash
+char216 "
+`U 778,908,20 2 0331 Ugrave
+char217 "
+'U 778,908,20 2 0332 Uacute
+char218 "
+^U 778,908,20 2 0333 Ucircumflex
+char219 "
+:U 778,868,20 2 0334 Udieresis
+char220 "
+'Y 667,908,3 2 0335 Yacute
+char221 "
+TP 604,692,3 2 0336 Thorn
+char222 "
+ss 556,731,9 2 0337 germandbls
+char223 "
+`a 500,697,12 2 0340 agrave
+char224 "
+'a 500,697,12 2 0341 aacute
+char225 "
+^a 500,697,12 2 0342 acircumflex
+char226 "
+~a 500,652,12 2 0343 atilde
+char227 "
+:a 500,657,12 2 0344 adieresis
+char228 "
+oa 500,716,12 2 0345 aring
+char229 "
+ae 758,469,20 0 0346 ae
+char230 "
+,c 444,469,225 0 0347 ccedilla
+char231 "
+`e 479,697,20 2 0350 egrave
+char232 "
+'e 479,697,20 2 0351 eacute
+char233 "
+^e 479,697,20 2 0352 ecircumflex
+char234 "
+:e 479,657,20 2 0353 edieresis
+char235 "
+`i 287,697,3 2 0354 igrave
+char236 "
+'i 287,697,3 2 0355 iacute
+char237 "
+^i 287,697,3 2 0356 icircumflex
+char238 "
+:i 287,657,3 2 0357 idieresis
+char239 "
+Sd 546,728,20 2 0360 eth
+char240 "
+~n 582,652,3 2 0361 ntilde
+char241 "
+`o 546,697,20 2 0362 ograve
+char242 "
+'o 546,697,20 2 0363 oacute
+char243 "
+^o 546,697,20 2 0364 ocircumflex
+char244 "
+~o 546,652,20 2 0365 otilde
+char245 "
+:o 546,657,20 2 0366 odieresis
+char246 "
+char247 606,512 0 0367 divide
+/o 556,474,23 0 0370 oslash
+char248 "
+`u 603,697,12 2 0371 ugrave
+char249 "
+'u 603,697,12 2 0372 uacute
+char250 "
+^u 603,697,12 2 0373 ucircumflex
+char251 "
+:u 603,657,12 2 0374 udieresis
+char252 "
+'y 556,697,283 3 0375 yacute
+char253 "
+Tp 601,726,281 3 0376 thorn
+char254 "
+:y 556,657,283 3 0377 ydieresis
+char255 "
diff --git a/gnu/usr.bin/groff/devps/S b/gnu/usr.bin/groff/devps/S
new file mode 100644
index 0000000..2a4c0e7
--- /dev/null
+++ b/gnu/usr.bin/groff/devps/S
@@ -0,0 +1,227 @@
+name S
+internalname Symbol
+special
+spacewidth 250
+charset
+space 250 0 0040
+! 333,672,17 3 0041 exclam
+fa 713,705 3 0042 universal
+# 500,673,16 3 0043 numbersign
+sh "
+te 549,707 3 0044 existential
+% 833,655,36 3 0045 percent
+& 778,661,18 3 0046 ampersand
+st 439,500,17 3 0047 suchthat
+( 333,673,191 3 0050 parenleft
+) 333,673,191 3 0051 parenright
+** 500,551 3 0052 asteriskmath
++ 549,533 3 0053 plus
+pl "
+, 250,104,152 3 0054 comma
+\- 549,288 3 0055 minus
+mi "
+. 250,95,17 3 0056 period
+/ 278,646,18 3 0057 slash
+sl "
+0 500,685,17 3 0060 zero
+1 500,673 3 0061 one
+2 500,686 3 0062 two
+3 500,685,17 3 0063 three
+4 500,685 3 0064 four
+5 500,685,17 3 0065 five
+6 500,685,17 3 0066 six
+7 500,673,16 3 0067 seven
+8 500,685,18 3 0070 eight
+9 500,685,18 3 0071 nine
+: 278,460,17 3 0072 colon
+; 278,460,152 3 0073 semicolon
+< 549,522 3 0074 less
+= 549,390 3 0075 equal
+eq "
+> 549,522 3 0076 greater
+? 444,686,17 3 0077 question
+=~ 549,475 3 0100 congruent
+*A 722,673 3 0101 Alpha
+*B 667,673 3 0102 Beta
+*X 722,673 3 0103 Chi
+*D 612,688 3 0104 Delta
+*E 611,673 3 0105 Epsilon
+*F 763,673 3 0106 Phi
+*G 603,673 3 0107 Gamma
+*Y 722,673 3 0110 Eta
+*I 333,673 3 0111 Iota
++h 631,689,18 3 0112 theta1
+*K 722,673 3 0113 Kappa
+*L 686,688 3 0114 Lambda
+*M 889,673 3 0115 Mu
+*N 722,673,8 3 0116 Nu
+*O 722,685,17 3 0117 Omicron
+*P 768,673 3 0120 Pi
+*H 741,685,17 3 0121 Theta
+*R 556,673 3 0122 Rho
+*S 592,673 3 0123 Sigma
+*T 611,673 3 0124 Tau
+--- 690,673 3 0125 Upsilon
+ts 439,500,233 3 0126 sigma1
+*W 768,688 3 0127 Omega
+*C 645,673 3 0130 Xi
+*Q 795,684 3 0131 Psi
+*Z 611,673 3 0132 Zeta
+[ 333,674,155 3 0133 bracketleft
+lB "
+3d 863,478 3 0134 therefore
+tf "
+] 333,674,155 3 0135 bracketright
+rB "
+pp 658,674 3 0136 perpendicular
+_ 500,0,252 3 0137 underscore
+radicalex 500,917 3 0140 radicalex
+*a 631,500,18 3 0141 alpha
+*b 549,741,223 3 0142 beta
+*x 549,499,231 3 0143 chi
+*d 494,740,19 3 0144 delta
+*e 439,502,19 3 0145 epsilon
+*f 521,671,224 3 0146 phi
+*g 411,499,225 3 0147 gamma
+*y 603,514,202 3 0150 eta
+*i 329,503,17 3 0151 iota
++f 603,499,224 3 0152 phi1
+*k 549,501 3 0153 kappa
+*l 549,739,17 3 0154 lambda
+char181 576,500,223 3 0155 mu
+*m "
+*n 521,507,16 3 0156 nu
+*o 549,499,19 3 0157 omicron
+*p 549,487,19 3 0160 pi
+*h 521,690,17 3 0161 theta
+*r 549,499,230 3 0162 rho
+*s 603,500,21 3 0163 sigma
+*t 439,500,19 3 0164 tau
+*u 576,507,18 3 0165 upsilon
++p 713,583,18 3 0166 omega1
+*w 686,500,17 3 0167 omega
+*c 493,766,224 3 0170 xi
+*q 686,500,228 3 0171 psi
+*z 494,756,225 3 0172 zeta
+lC 480,673,183 3 0173 braceleft
+{ "
+ba 200,673,177 3 0174 bar
+| "
+rC 480,673,183 3 0175 braceright
+} "
+ap 549,307 3 0176 similar
+*U 620,685 3 0241 Upsilon1
+fm 247,735 3 0242 minute
+<= 549,639 3 0243 lessequal
+f/ 167,677,12 3 0244 fraction
+if 713,404 3 0245 infinity
+Fn 500,686,193 3 0246 florin
+CL 753,533,26 3 0247 club
+DI 753,550,36 3 0250 diamond
+HE 753,532,33 3 0251 heart
+SP 753,548,36 3 0252 spade
+<> 1042,511,15 3 0253 arrowboth
+<- 987,511,15 3 0254 arrowleft
+ua 603,910 3 0255 arrowup
+arrowverttp "
+-> 987,511,15 3 0256 arrowright
+da 603,888,22 3 0257 arrowdown
+arrowvertbt "
+de 400,685 3 0260 degree
+char176 "
+char177 549,645 3 0261 plusminus
++- "
+sd 411,737 3 0262 second
+>= 549,639 3 0263 greaterequal
+char215 549,524 3 0264 multiply
+mu "
+pt 713,404 3 0265 proportional
+pd 494,746,20 3 0266 partialdiff
+bu 460,473 3 0267 bullet
+char247 549,456 3 0270 divide
+di "
+!= 549,549,25 3 0271 notequal
+== 549,443 3 0272 equivalence
+~~ 549,394 3 0273 approxequal
+~= "
+--- 1000,95,17 3 0274 ellipsis
+arrowvertex 603,1010,120 3 0275 arrowvertex
+--- 1000,276 3 0276 arrowhorizex
+CR 658,629,16 3 0277 carriagereturn
+Ah 823,658,18 3 0300 aleph
+Im 686,740,53 3 0301 Ifraktur
+Re 795,734,15 3 0302 Rfraktur
+wp 987,573,211 3 0303 weierstrass
+c* 768,673,17 3 0304 circlemultiply
+c+ 768,675,15 3 0305 circleplus
+es 823,719,24 3 0306 emptyset
+ca 768,509 3 0307 intersection
+cu 768,492,17 3 0310 union
+sp 713,470 3 0311 propersuperset
+ip 713,470,125 3 0312 reflexsuperset
+--- 713,540,70 3 0313 notsubset
+sb 713,470 3 0314 propersubset
+ib 713,470,125 3 0315 reflexsubset
+mo 713,468 3 0316 element
+nm 713,555,58 3 0317 notelement
+/_ 768,673 3 0320 angle
+gr 713,718,19 3 0321 gradient
+--- 790,673,17 3 0322 registerserif
+--- 790,675,15 3 0323 copyrightserif
+--- 890,673 3 0324 trademarkserif
+product 823,751,101 3 0325 product
+sr 549,917,38 3 0326 radical
+md 250,310 3 0327 dotmath
+no 713,288 3 0330 logicalnot
+char172 "
+AN 603,454 3 0331 logicaland
+OR 603,477 3 0332 logicalor
+hA 1042,510,20 3 0333 arrowdblboth
+lA 987,513,15 3 0334 arrowdblleft
+uA 603,911 3 0335 arrowdblup
+rA 987,508,20 3 0336 arrowdblright
+dA 603,890,19 3 0337 arrowdbldown
+lz 494,745 3 0340 lozenge
+la 329,746,198 3 0341 angleleft
+--- 790,670,20 3 0342 registersans
+--- 790,675,15 3 0343 copyrightsans
+--- 786,673 3 0344 trademarksans
+sum 713,752,108 3 0345 summation
+parenlefttp 384,926,293 3 0346 parenlefttp
+parenleftex 384,920,80 3 0347 parenleftex
+parenleftbt 384,920,293 3 0350 parenleftbt
+bracketlefttp 384,925,75 3 0351 bracketlefttp
+lc "
+bracketleftex 384,925,75 3 0352 bracketleftex
+bracketleftbt 384,925,75 3 0353 bracketleftbt
+lf "
+bracelefttp 494,925,75 3 0354 bracelefttp
+lt "
+braceleftmid 494,925,75 3 0355 braceleftmid
+lk "
+braceleftbt 494,925,75 3 0356 braceleftbt
+lb "
+braceex 494,925,75 3 0357 braceex
+bracerightex "
+braceleftex "
+barex "
+bv "
+ra 329,746,198 3 0361 angleright
+is 274,916,107,67,52,-10 3 0362 integral
+--- 686,921,83 3 0363 integraltp
+--- 686,975,88 3 0364 integralex
+--- 686,921,81 3 0365 integralbt
+parenrighttp 384,926,293 3 0366 parenrighttp
+parenrightex 384,920,80 3 0367 parenrightex
+parenrightbt 384,920,293 3 0370 parenrightbt
+bracketrighttp 384,925,75 3 0371 bracketrighttp
+rc "
+bracketrightex 384,925,75 3 0372 bracketrightex
+bracketrightbt 384,925,75 3 0373 bracketrightbt
+rf "
+bracerighttp 494,925,75 3 0374 bracerighttp
+rt "
+bracerightmid 494,925,75 3 0375 bracerightmid
+rk "
+bracerightbt 494,925,75 3 0376 bracerightbt
+rb "
diff --git a/gnu/usr.bin/groff/devps/SS b/gnu/usr.bin/groff/devps/SS
new file mode 100644
index 0000000..02b999c
--- /dev/null
+++ b/gnu/usr.bin/groff/devps/SS
@@ -0,0 +1,194 @@
+name SS
+internalname Symbol-Slanted
+special
+slant 15.5
+spacewidth 223
+charset
+space 223 0 0040
+--- 296,599,15,137,-72,99 3 0041 exclam
+--- 635,627,0,216,-173,99 3 0042 universal
+--- 445,599,15,162,-21,99 3 0043 numbersign
+--- 489,629,0,183,28,99 3 0044 existential
+--- 741,583,32,75,-97,75 3 0045 percent
+--- 692,589,16,103,-18,99 3 0046 ampersand
+--- 391,444,15,109,6,99 3 0047 suchthat
+--- 296,599,170,203,-39,99 3 0050 parenleft
+--- 296,600,170,93,72,93 3 0051 parenright
+--- 445,490,0,105,-76,99 3 0052 asteriskmath
+--- 489,474,0,123,-26,99 3 0053 plus
+--- 223,93,136,10,41,10 3 0054 comma
+--- 489,256,0,117,-24,99 3 0055 minus
+--- 223,85,15,1,-20,1 3 0056 period
+--- 247,575,15,208,55,99 3 0057 slash
+--- 445,610,15,142,-40,99 3 0060 zero
+--- 445,599,0,56,-57,56 3 0061 one
+--- 445,611,0,129,28,99 3 0062 two
+--- 445,611,16,115,-6,99 3 0063 three
+--- 445,610,0,135,-8,99 3 0064 four
+--- 445,610,15,188,14,99 3 0065 five
+--- 445,610,16,193,-37,99 3 0066 six
+--- 445,599,15,190,-101,99 3 0067 seven
+--- 445,611,16,141,-32,99 3 0070 eight
+--- 445,609,15,140,-2,99 3 0071 nine
+--- 247,409,15,89,-31,89 3 0072 colon
+--- 247,409,136,99,17,99 3 0073 semicolon
+--- 489,464,0,171,-37,99 3 0074 less
+--- 489,347,0,147,1,99 3 0075 equal
+--- 489,464,0,108,27,99 3 0076 greater
+--- 395,610,15,172,-113,99 3 0077 question
+--- 489,423,0,158,40,99 3 0100 congruent
+--- 643,599,0,21,47,21 3 0101 Alpha
+--- 594,598,0,101,24,99 3 0102 Beta
+--- 643,599,0,205,58,99 3 0103 Chi
+--- 545,612,0,46,45,46 3 0104 Delta
+--- 544,599,0,194,22,99 3 0105 Epsilon
+--- 679,598,0,132,-55,99 3 0106 Phi
+--- 537,599,0,227,19,99 3 0107 Gamma
+--- 643,599,0,243,15,99 3 0110 Eta
+--- 296,599,0,222,22,99 3 0111 Iota
++h 562,614,15,133,-58,99 3 0112 theta1
+--- 643,598,0,185,19,99 3 0113 Kappa
+--- 611,612,0,49,45,49 3 0114 Lambda
+--- 791,599,0,233,22,99 3 0115 Mu
+--- 643,599,7,234,24,99 3 0116 Nu
+--- 643,610,15,154,-62,99 3 0117 Omicron
+--- 684,599,0,213,28,99 3 0120 Pi
+--- 659,610,15,138,-62,99 3 0121 Theta
+--- 495,599,0,200,25,99 3 0122 Rho
+--- 527,599,0,186,45,99 3 0123 Sigma
+--- 544,599,0,229,-109,99 3 0124 Tau
+--- 614,599,0,240,-125,99 3 0125 Upsilon
+ts 391,445,208,151,-28,99 3 0126 sigma1
+--- 684,612,0,126,20,99 3 0127 Omega
+--- 574,598,0,176,14,99 3 0130 Xi
+--- 708,608,0,227,-138,99 3 0131 Psi
+--- 544,599,0,231,11,99 3 0132 Zeta
+--- 296,599,138,207,16,99 3 0133 bracketleft
+--- 768,426,0,0,-110 3 0134 therefore
+--- 296,599,138,159,64,99 3 0135 bracketright
+--- 586,600,0,60,37,60 3 0136 perpendicular
+--- 445,0,224,0,122 3 0137 underscore
+--- 445,816,0,829,-622,99 3 0140 radicalex
+*a 562,445,15,146,-34,99 3 0141 alpha
+*b 489,659,198,139,57,99 3 0142 beta
+*x 489,445,206,134,98,99 3 0143 chi
+*d 440,658,16,181,-33,99 3 0144 delta
+*e 391,447,17,127,1,99 3 0145 epsilon
+*f 464,596,200,103,-28,99 3 0146 phi
+*g 366,444,200,252,-42,99 3 0147 gamma
+*y 537,457,180,68,-50,68 3 0150 eta
+*i 293,448,16,53,-47,53 3 0151 iota
++f 537,444,199,117,-42,99 3 0152 phi1
+*k 489,447,0,182,-56,99 3 0153 kappa
+*l 489,658,16,91,29,91 3 0154 lambda
+*m 513,445,198,70,68,70 3 0155 mu
+*n 464,451,15,134,-69,99 3 0156 nu
+*o 489,444,17,87,-36,87 3 0157 omicron
+*p 489,433,18,160,-8,99 3 0160 pi
+*h 464,614,16,140,-53,99 3 0161 theta
+*r 489,444,205,82,69,82 3 0162 rho
+*s 537,445,19,175,-37,99 3 0163 sigma
+*t 391,445,16,170,-45,99 3 0164 tau
+*u 513,451,15,95,-55,95 3 0165 upsilon
++p 635,519,15,173,-28,99 3 0166 omega1
+*w 611,445,16,126,-35,99 3 0167 omega
+*c 439,681,200,126,-20,99 3 0170 xi
+*q 611,445,203,198,-91,99 3 0171 psi
+*z 440,673,200,190,-50,99 3 0172 zeta
+--- 427,599,163,163,-66,99 3 0173 braceleft
+--- 178,599,158,179,41,99 3 0174 bar
+--- 427,599,163,67,31,67 3 0175 braceright
+--- 489,273,0,110,-28,99 3 0176 similar
+--- 552,609,0,208,-84,99 3 0241 Upsilon1
+--- 220,654,0,223,-106,99 3 0242 minute
+--- 489,569,0,206,24,99 3 0243 lessequal
+--- 149,603,11,391,214,99 3 0244 fraction
+--- 635,360,0,107,-41,99 3 0245 infinity
+--- 445,612,172,219,86,99 3 0246 florin
+--- 670,474,23,25,-69,25 3 0247 club
+--- 670,490,32,0,-148 3 0250 diamond
+--- 670,473,29,59,-155,59 3 0251 heart
+--- 670,488,32,0,-82 3 0252 spade
+--- 927,455,13,103,-40,99 3 0253 arrowboth
+--- 878,455,13,87,-47,87 3 0254 arrowleft
+--- 537,810,0,204,-173,99 3 0255 arrowup
+--- 878,455,13,94,-55,94 3 0256 arrowright
+--- 537,790,20,85,-54,85 3 0257 arrowdown
+--- 356,609,0,160,-137,99 3 0260 degree
+--- 489,574,0,154,41,99 3 0261 plusminus
+--- 366,656,0,244,-100,99 3 0262 second
+--- 489,569,0,143,24,99 3 0263 greaterequal
+--- 489,466,0,170,22,99 3 0264 multiply
+--- 635,360,0,82,-40,82 3 0265 proportional
+--- 440,664,18,152,-12,99 3 0266 partialdiff
+--- 409,421,0,95,-68,95 3 0267 bullet
+--- 489,406,0,119,-24,99 3 0270 divide
+--- 489,489,22,148,-1,99 3 0271 notequal
+--- 489,394,0,163,15,99 3 0272 equivalence
+--- 489,351,0,133,-7,99 3 0273 approxequal
+--- 890,85,15,0,-57 3 0274 ellipsis
+--- 537,899,107,92,-166,92 3 0275 arrowvertex
+--- 890,246,0,171,42,99 3 0276 arrowhorizex
+--- 586,560,14,174,10,99 3 0277 carriagereturn
+--- 732,586,16,58,-109,58 3 0300 aleph
+--- 611,659,47,123,24,99 3 0301 Ifraktur
+--- 708,653,13,175,-21,99 3 0302 Rfraktur
+--- 878,510,188,50,-62,50 3 0303 weierstrass
+--- 684,599,15,124,-64,99 3 0304 circlemultiply
+--- 684,601,13,125,-65,99 3 0305 circleplus
+--- 732,640,21,202,12,99 3 0306 emptyset
+--- 684,453,0,80,14,80 3 0307 intersection
+--- 684,438,15,154,-60,99 3 0310 union
+--- 635,418,0,90,32,90 3 0311 propersuperset
+--- 635,418,111,89,67,89 3 0312 reflexsuperset
+--- 635,481,62,159,-37,99 3 0313 notsubset
+--- 635,418,0,159,-37,99 3 0314 propersubset
+--- 635,418,111,159,34,99 3 0315 reflexsubset
+--- 635,417,0,0,-43 3 0316 element
+--- 635,494,52,0,-24 3 0317 notelement
+--- 684,599,0,199,27,99 3 0320 angle
+--- 635,639,17,220,-181,99 3 0321 gradient
+--- 703,596,18,110,-70,99 3 0322 registerserif
+--- 703,601,13,113,-72,99 3 0323 copyrightserif
+--- 792,599,0,205,-119,99 3 0324 trademarkserif
+--- 732,668,90,238,56,99 3 0325 product
+--- 489,816,34,272,-84,99 3 0326 radical
+--- 223,276,0,52,-81,52 3 0327 dotmath
+--- 635,256,0,100,-28,99 3 0330 logicalnot
+--- 537,404,0,32,29,32 3 0331 logicaland
+--- 537,424,0,152,-101,99 3 0332 logicalor
+--- 927,454,18,101,-42,99 3 0333 arrowdblboth
+--- 878,457,13,114,-46,99 3 0334 arrowdblleft
+--- 537,811,0,201,-102,99 3 0335 arrowdblup
+--- 878,452,18,89,-21,89 3 0336 arrowdblright
+--- 537,792,17,152,-53,99 3 0337 arrowdbldown
+--- 440,663,0,129,-71,99 3 0340 lozenge
+--- 293,664,176,229,-48,99 3 0341 angleleft
+--- 703,596,18,110,-70,99 3 0342 registersans
+--- 703,601,13,111,-70,99 3 0343 copyrightsans
+--- 700,599,0,182,-129,99 3 0344 trademarksans
+--- 635,669,96,171,65,99 3 0345 summation
+--- 342,824,261,350,96,99 3 0346 parenlefttp
+--- 342,823,76,46,38,46 3 0347 parenleftex
+--- 342,824,261,47,-63,47 3 0350 parenleftbt
+--- 342,824,71,268,72,99 3 0351 bracketlefttp
+--- 342,823,70,13,72,13 3 0352 bracketleftex
+--- 342,824,71,14,72,14 3 0353 bracketleftbt
+--- 440,824,67,258,-108,99 3 0354 bracelefttp
+--- 440,832,76,96,-76,96 3 0355 braceleftmid
+--- 440,824,62,94,-169,94 3 0356 braceleftbt
+--- 440,832,71,96,-107,96 3 0357 braceex
+--- 293,664,176,102,79,99 3 0361 angleright
+--- 244,815,95,305,63,99 3 0362 integral
+--- 611,820,74,312,-222,99 3 0363 integraltp
+--- 611,868,78,79,-221,79 3 0364 integralex
+--- 611,820,72,64,20,64 3 0365 integralbt
+--- 342,824,261,206,-223,99 3 0366 parenrighttp
+--- 342,823,76,365,-281,99 3 0367 parenrightex
+--- 342,824,261,365,80,99 3 0370 parenrightbt
+--- 342,824,71,285,-199,99 3 0371 bracketrighttp
+--- 342,823,70,285,-200,99 3 0372 bracketrightex
+--- 342,824,71,285,54,99 3 0373 bracketrightbt
+--- 440,824,67,35,-108,35 3 0374 bracerighttp
+--- 440,832,76,127,-105,99 3 0375 bracerightmid
+--- 440,824,62,94,54,94 3 0376 bracerightbt
diff --git a/gnu/usr.bin/groff/devps/TB b/gnu/usr.bin/groff/devps/TB
new file mode 100644
index 0000000..9dae3ad
--- /dev/null
+++ b/gnu/usr.bin/groff/devps/TB
@@ -0,0 +1,533 @@
+name TB
+internalname Times-Bold
+spacewidth 250
+encoding text.enc
+ligatures fi fl 0
+kernpairs
+A y -74
+A w -90
+A v -100
+A u -50
+A ' -74
+A p -25
+A Y -100
+A W -130
+A V -145
+A U -50
+A T -95
+A Q -45
+A O -45
+A G -55
+A C -55
+B U -10
+B A -30
+D . -20
+D Y -40
+D W -40
+D V -40
+D A -35
+F . -110
+F o -25
+F e -25
+F , -92
+F a -25
+F A -90
+J u -15
+J . -20
+J o -15
+J e -15
+J a -15
+J A -30
+K y -45
+K u -15
+K o -25
+K e -25
+K O -30
+L y -55
+L ' -110
+L rq -20
+L Y -92
+L W -92
+L V -92
+L T -92
+N A -20
+O Y -50
+O X -40
+O W -50
+O V -50
+O T -40
+O A -40
+P . -110
+P o -20
+P e -20
+P , -92
+P a -10
+P A -74
+Q . -20
+Q U -10
+R Y -35
+R W -35
+R V -55
+R U -30
+R T -40
+R O -30
+T y -74
+T w -74
+T u -92
+T ; -74
+T r -74
+T . -90
+T o -92
+T i -18
+T - -92
+T hy -92
+T char173 -92
+T e -92
+T , -74
+T : -74
+T a -92
+T O -18
+T A -90
+U . -50
+U , -50
+U A -60
+V u -92
+V ; -92
+V . -145
+V o -100
+V i -37
+V - -74
+V hy -74
+V char173 -74
+V e -100
+V , -129
+V : -92
+V a -92
+V O -45
+V G -30
+V A -135
+W y -60
+W u -50
+W ; -55
+W . -92
+W o -75
+W i -18
+W - -37
+W hy -37
+W char173 -37
+W e -65
+W , -92
+W : -55
+W a -65
+W O -10
+W A -120
+Y u -92
+Y ; -92
+Y . -92
+Y o -111
+Y i -37
+Y - -92
+Y hy -92
+Y char173 -92
+Y e -111
+Y , -92
+Y : -92
+Y a -85
+Y O -35
+Y A -110
+a v -25
+b v -15
+b u -20
+b . -40
+b b -10
+, ' -55
+, rq -45
+d w -15
+e v -15
+f ' 55
+f rq 50
+f . -15
+f o -25
+f i -25
+f .i -35
+f , -15
+g . -15
+h y -15
+i v -10
+k y -15
+k o -15
+k e -10
+n v -40
+o w -10
+o v -10
+. ' -55
+. rq -55
+lq A -10
+` ` -63
+` oq -63
+oq ` -63
+oq oq -63
+` A -10
+oq A -10
+' v -20
+' s -37
+' r -20
+' ' -63
+' d -20
+r v -10
+r q -18
+r . -100
+r p -10
+r o -18
+r n -15
+r - -37
+r hy -37
+r char173 -37
+r g -10
+r e -18
+r , -92
+r c -18
+v . -70
+v o -10
+v e -10
+v , -55
+v a -10
+w . -70
+w o -10
+w , -55
+y . -70
+y o -25
+y e -10
+y , -55
+charset
+ha 581,676 2 0000 asciicircum
+ti 520,333 0 0001 asciitilde
+vS 556,914,19 2 0002 Scaron
+vZ 667,914 2 0003 Zcaron
+vs 389,704,14 2 0004 scaron
+vz 444,704 2 0005 zcaron
+:Y 722,877 2 0006 Ydieresis
+tm 1000,676 2 0007 trademark
+aq 278,691 2 0010 quotesingle
+space 250 0 0040
+! 333,691,13 2 0041 exclam
+" 555,691 2 0042 quotedbl
+# 500,700 2 0043 numbersign
+sh "
+$ 500,750,99 2 0044 dollar
+Do "
+% 1000,692,14 2 0045 percent
+& 833,691,16 2 0046 ampersand
+' 333,691 2 0047 quoteright
+( 333,694,168 2 0050 parenleft
+) 333,694,168 2 0051 parenright
+* 500,691 2 0052 asterisk
++ 570,506 0 0053 plus
+, 250,155,180 0 0054 comma
+- 333,287 0 0055 hyphen
+hy "
+char173 "
+. 250,156,13 0 0056 period
+/ 278,691,19 2 0057 slash
+sl "
+0 500,688,13 2 0060 zero
+1 500,688 2 0061 one
+2 500,688 2 0062 two
+3 500,688,14 2 0063 three
+4 500,688 2 0064 four
+5 500,676,8 2 0065 five
+6 500,688,13 2 0066 six
+7 500,676 2 0067 seven
+8 500,688,13 2 0070 eight
+9 500,688,13 2 0071 nine
+: 333,472,13 0 0072 colon
+; 333,472,180 0 0073 semicolon
+< 570,514,8 0 0074 less
+= 570,399 0 0075 equal
+> 570,514,8 0 0076 greater
+? 500,689,13 2 0077 question
+@ 930,691,19 2 0100 at
+at "
+A 722,690 2 0101 A
+B 667,676 2 0102 B
+C 722,691,19 2 0103 C
+D 722,676 2 0104 D
+E 667,676 2 0105 E
+F 611,676 2 0106 F
+G 778,691,19 2 0107 G
+H 778,676 2 0110 H
+I 389,676 2 0111 I
+J 500,676,96 2 0112 J
+K 778,676 2 0113 K
+L 667,676 2 0114 L
+M 944,676 2 0115 M
+N 722,676,18 2 0116 N
+O 778,691,19 2 0117 O
+P 611,676 2 0120 P
+Q 778,691,176 2 0121 Q
+R 722,676 2 0122 R
+S 556,692,19 2 0123 S
+T 667,676 2 0124 T
+U 722,676,19 2 0125 U
+V 722,676,18 2 0126 V
+W 1000,676,15 2 0127 W
+X 722,676 2 0130 X
+Y 722,676 2 0131 Y
+Z 667,676 2 0132 Z
+[ 333,678,149 2 0133 bracketleft
+lB "
+\ 278,691,19 2 0134 backslash
+rs "
+] 333,678,149 2 0135 bracketright
+rB "
+a^ 333,704 2 0136 circumflex
+^ "
+_ 500,0,125 0 0137 underscore
+` 333,691 2 0140 quoteleft
+oq "
+a 500,473,14 0 0141 a
+b 556,676,14 2 0142 b
+c 444,473,14 0 0143 c
+d 556,676,14 2 0144 d
+e 444,473,14 0 0145 e
+f 333,691 2 0146 f
+g 500,473,206 1 0147 g
+h 556,676 2 0150 h
+i 278,691 2 0151 i
+j 333,691,203 3 0152 j
+k 556,676 2 0153 k
+l 278,676 2 0154 l
+m 833,473 0 0155 m
+n 556,473 0 0156 n
+o 500,473,14 0 0157 o
+p 556,473,205 1 0160 p
+q 556,473,205 1 0161 q
+r 444,473 0 0162 r
+s 389,473,14 0 0163 s
+t 333,630,12 2 0164 t
+u 556,461,14 0 0165 u
+v 500,461,14 0 0166 v
+w 722,461,14 0 0167 w
+x 500,461 0 0170 x
+y 500,461,205 1 0171 y
+z 444,461 0 0172 z
+lC 394,698,175 2 0173 braceleft
+{ "
+ba 220,691,19 2 0174 bar
+| "
+rC 394,698,175 2 0175 braceright
+} "
+a~ 333,674 2 0176 tilde
+~ "
+bq 333,155,180 0 0200 quotesinglbase
+Fo 500,415 0 0201 guillemotleft
+char171 "
+Fc 500,415 0 0202 guillemotright
+char187 "
+bu 350,478 0 0203 bullet
+Fn 500,706,155 2 0204 florin
+f/ 167,688,12 2 0205 fraction
+%0 1000,706,29 2 0206 perthousand
+dg 500,691,134 2 0207 dagger
+dd 500,691,132 2 0210 daggerdbl
+en 500,271 0 0211 endash
+em 1000,271 0 0212 emdash
+fi 556,691 2 0214 fi
+fl 556,691 2 0215 fl
+.i 278,461 0 0220 dotlessi
+ga 333,713 2 0222 grave
+a" 333,713 2 0223 hungarumlaut
+a. 333,667 2 0224 dotaccent
+ab 333,691 2 0225 breve
+ah 333,704 2 0226 caron
+ao 333,740 2 0227 ring
+ho 333,44,173 0 0230 ogonek
+lq 500,691 2 0231 quotedblleft
+rq 500,691 2 0232 quotedblright
+oe 722,473,14 0 0233 oe
+/l 278,676 2 0234 lslash
+Bq 500,155,180 0 0235 quotedblbase
+OE 1000,684,5 2 0236 OE
+/L 667,676 2 0237 Lslash
+r! 333,501,203 1 0241 exclamdown
+char161 "
+ct 500,588,140 0 0242 cent
+char162 "
+Po 500,684,14 2 0243 sterling
+char163 "
+Cs 500,613 0 0244 currency
+char164 "
+Ye 500,676 2 0245 yen
+char165 "
+bb 220,691,19 2 0246 brokenbar
+char166 "
+sc 500,691,132 2 0247 section
+char167 "
+ad 333,667 2 0250 dieresis
+char168 "
+co 747,691,19 2 0251 copyright
+char169 "
+Of 300,688 2 0252 ordfeminine
+char170 "
+fo 333,415 0 0253 guilsinglleft
+no 570,399 0 0254 logicalnot
+char172 "
+\- 570,297 0 0255 minus
+rg 747,691,19 2 0256 registered
+char174 "
+a- 333,637 2 0257 macron
+char175 "
+de 400,688 2 0260 degree
+char176 "
+char177 570,506 0 0261 plusminus
+S2 300,688 2 0262 twosuperior
+char178 "
+S3 300,688 2 0263 threesuperior
+char179 "
+aa 333,713 2 0264 acute
+char180 "
+char181 556,461,206 1 0265 mu
+ps 540,676,186 2 0266 paragraph
+char182 "
+char183 250,417 0 0267 periodcentered
+ac 333,0,218 1 0270 cedilla
+char184 "
+S1 300,688 2 0271 onesuperior
+char185 "
+Om 330,688 2 0272 ordmasculine
+char186 "
+fc 333,415 0 0273 guilsinglright
+14 750,688,12 2 0274 onequarter
+char188 "
+12 750,688,12 2 0275 onehalf
+char189 "
+34 750,688,12 2 0276 threequarters
+char190 "
+r? 500,501,201 0 0277 questiondown
+char191 "
+`A 722,923 2 0300 Agrave
+char192 "
+'A 722,923 2 0301 Aacute
+char193 "
+^A 722,914 2 0302 Acircumflex
+char194 "
+~A 722,884 2 0303 Atilde
+char195 "
+:A 722,877 2 0304 Adieresis
+char196 "
+oA 722,935 2 0305 Aring
+char197 "
+AE 1000,676 2 0306 AE
+char198 "
+,C 722,691,218 3 0307 Ccedilla
+char199 "
+`E 667,923 2 0310 Egrave
+char200 "
+'E 667,923 2 0311 Eacute
+char201 "
+^E 667,914 2 0312 Ecircumflex
+char202 "
+:E 667,877 2 0313 Edieresis
+char203 "
+`I 389,923 2 0314 Igrave
+char204 "
+'I 389,923 2 0315 Iacute
+char205 "
+^I 389,914 2 0316 Icircumflex
+char206 "
+:I 389,877 2 0317 Idieresis
+char207 "
+-D 722,676 2 0320 Eth
+char208 "
+~N 722,884,18 2 0321 Ntilde
+char209 "
+`O 778,923,19 2 0322 Ograve
+char210 "
+'O 778,923,19 2 0323 Oacute
+char211 "
+^O 778,914,19 2 0324 Ocircumflex
+char212 "
+~O 778,884,19 2 0325 Otilde
+char213 "
+:O 778,877,19 2 0326 Odieresis
+char214 "
+char215 570,490 0 0327 multiply
+/O 778,737,74 2 0330 Oslash
+char216 "
+`U 722,923,19 2 0331 Ugrave
+char217 "
+'U 722,923,19 2 0332 Uacute
+char218 "
+^U 722,914,19 2 0333 Ucircumflex
+char219 "
+:U 722,877,19 2 0334 Udieresis
+char220 "
+'Y 722,928 2 0335 Yacute
+char221 "
+TP 611,676 2 0336 Thorn
+char222 "
+ss 556,691,12 2 0337 germandbls
+char223 "
+`a 500,713,14 2 0340 agrave
+char224 "
+'a 500,713,14 2 0341 aacute
+char225 "
+^a 500,704,14 2 0342 acircumflex
+char226 "
+~a 500,674,14 2 0343 atilde
+char227 "
+:a 500,667,14 2 0344 adieresis
+char228 "
+oa 500,740,14 2 0345 aring
+char229 "
+ae 722,473,14 0 0346 ae
+char230 "
+,c 444,473,218 1 0347 ccedilla
+char231 "
+`e 444,713,14 2 0350 egrave
+char232 "
+'e 444,713,14 2 0351 eacute
+char233 "
+^e 444,704,14 2 0352 ecircumflex
+char234 "
+:e 444,667,14 2 0353 edieresis
+char235 "
+`i 278,713 2 0354 igrave
+char236 "
+'i 278,713 2 0355 iacute
+char237 "
+^i 278,704 2 0356 icircumflex
+char238 "
+:i 278,667 2 0357 idieresis
+char239 "
+Sd 500,691,14 2 0360 eth
+char240 "
+~n 556,674 2 0361 ntilde
+char241 "
+`o 500,713,14 2 0362 ograve
+char242 "
+'o 500,713,14 2 0363 oacute
+char243 "
+^o 500,704,14 2 0364 ocircumflex
+char244 "
+~o 500,674,14 2 0365 otilde
+char245 "
+:o 500,667,14 2 0366 odieresis
+char246 "
+char247 570,537,31 0 0367 divide
+/o 500,549,92 0 0370 oslash
+char248 "
+`u 556,713,14 2 0371 ugrave
+char249 "
+'u 556,713,14 2 0372 uacute
+char250 "
+^u 556,704,14 2 0373 ucircumflex
+char251 "
+:u 556,667,14 2 0374 udieresis
+char252 "
+'y 500,713,205 3 0375 yacute
+char253 "
+Tp 556,676,205 3 0376 thorn
+char254 "
+:y 500,667,205 3 0377 ydieresis
+char255 "
diff --git a/gnu/usr.bin/groff/devps/TBI b/gnu/usr.bin/groff/devps/TBI
new file mode 100644
index 0000000..ba58a3a
--- /dev/null
+++ b/gnu/usr.bin/groff/devps/TBI
@@ -0,0 +1,515 @@
+name TBI
+internalname Times-BoldItalic
+slant 15
+spacewidth 250
+encoding text.enc
+ligatures fi fl 0
+kernpairs
+A y -74
+A w -74
+A v -74
+A u -30
+A ' -74
+A Y -70
+A W -100
+A V -95
+A U -50
+A T -55
+A Q -55
+A O -50
+A G -60
+A C -65
+B U -10
+B A -25
+D Y -50
+D W -40
+D V -50
+D A -25
+F r -50
+F . -129
+F o -70
+F i -40
+F e -100
+F , -129
+F a -95
+F A -100
+J u -40
+J . -10
+J o -40
+J e -40
+J , -10
+J a -40
+J A -25
+K y -20
+K u -20
+K o -25
+K e -25
+K O -30
+L y -37
+L ' -55
+L Y -37
+L W -37
+L V -37
+L T -18
+N A -30
+O Y -50
+O X -40
+O W -50
+O V -50
+O T -40
+O A -40
+P . -129
+P o -55
+P e -50
+P , -129
+P a -40
+P A -85
+Q U -10
+R Y -18
+R W -18
+R V -18
+R U -40
+R T -30
+R O -40
+T y -37
+T w -37
+T u -37
+T ; -74
+T r -37
+T . -92
+T o -95
+T i -37
+T - -92
+T hy -92
+T char173 -92
+T e -92
+T , -92
+T : -74
+T a -92
+T O -18
+T A -55
+U A -45
+V u -55
+V ; -74
+V . -129
+V o -111
+V i -55
+V - -70
+V hy -70
+V char173 -70
+V e -111
+V , -129
+V : -74
+V a -111
+V O -30
+V G -10
+V A -85
+W y -55
+W u -55
+W ; -55
+W . -74
+W o -80
+W i -37
+W - -50
+W hy -50
+W char173 -50
+W e -90
+W , -74
+W : -55
+W a -85
+W O -15
+W A -74
+Y u -92
+Y ; -92
+Y . -74
+Y o -111
+Y i -55
+Y - -92
+Y hy -92
+Y char173 -92
+Y e -111
+Y , -92
+Y : -92
+Y a -92
+Y O -25
+Y A -74
+b u -20
+b . -40
+b b -10
+c k -10
+c h -10
+, ' -95
+, rq -95
+e b -10
+f ' 55
+f . -10
+f o -10
+f f -18
+f e -10
+f .i -30
+f , -10
+k o -10
+k e -30
+n v -40
+o y -10
+o x -10
+o w -25
+o v -15
+. ' -95
+. rq -95
+` ` -74
+` oq -74
+oq ` -74
+oq oq -74
+' v -15
+' t -37
+' s -74
+' r -15
+' ' -74
+' d -15
+r . -65
+r , -65
+v . -37
+v o -15
+v e -15
+v , -37
+w . -37
+w o -15
+w e -10
+w , -37
+w a -10
+x e -10
+y . -37
+y , -37
+charset
+ha 570,669,0,0,-17 2 0000 asciicircum
+ti 570,333,0,0,-4 0 0001 asciitilde
+vS 556,897,18,20,48,20 2 0002 Scaron
+vZ 611,897,0,29,61,29 2 0003 Zcaron
+vs 389,690,13,100,69,99 2 0004 scaron
+vz 389,690,78,85,93,85 2 0005 zcaron
+:Y 611,862,0,98,-23,98 2 0006 Ydieresis
+tm 1000,669,0,18,18,18 2 0007 trademark
+aq 278,685,0,40,-78,40 2 0010 quotesingle
+space 250 0 0040
+! 389,684,13,31,-17,31 2 0041 exclam
+" 555,685,0,31,-86,31 2 0042 quotedbl
+# 500,700,0,83,83,83 2 0043 numbersign
+sh "
+$ 500,733,100,47,70,47 2 0044 dollar
+Do "
+% 833,692,10,10,11,10 2 0045 percent
+& 778,682,19,0,45 2 0046 ampersand
+' 333,685,0,19,-48,19 2 0047 quoteright
+( 333,685,179,61,22,61 2 0050 parenleft
+) 333,685,179,0,94 2 0051 parenright
+* 500,685,0,6,-15,6 2 0052 asterisk
++ 570,506,0,17,17,17 0 0053 plus
+, 250,134,182,0,110 0 0054 comma
+- 333,282,0,0,48 0 0055 hyphen
+hy "
+char173 "
+. 250,135,13,0,59 0 0056 period
+/ 278,685,18,114,114,99 2 0057 slash
+sl "
+0 500,683,14,27,33,27 2 0060 zero
+1 500,683,0,0,45 2 0061 one
+2 500,683,0,0,77 2 0062 two
+3 500,683,13,0,65 2 0063 three
+4 500,683,0,53,65,53 2 0064 four
+5 500,669,13,37,61,37 2 0065 five
+6 500,679,15,59,27,59 2 0066 six
+7 500,669,0,75,-2,75 2 0067 seven
+8 500,683,13,26,47,26 2 0070 eight
+9 500,683,10,25,62,25 2 0071 nine
+: 333,459,13,0,27 0 0072 colon
+; 333,459,183,0,75 0 0073 semicolon
+< 570,514,8,19,19,19 0 0074 less
+= 570,399,0,17,17,17 0 0075 equal
+> 570,514,8,19,19,19 0 0076 greater
+? 500,684,13,20,-29,20 2 0077 question
+@ 832,685,18,0,-13 2 0100 at
+at "
+A 667,683,0,0,117 2 0101 A
+B 667,669,0,7,74,7 2 0102 B
+C 667,685,18,60,18,60 2 0103 C
+D 722,669,0,13,96,13 2 0104 D
+E 667,669,0,36,77,36 2 0105 E
+F 667,669,0,43,63,43 2 0106 F
+G 722,685,18,34,29,34 2 0107 G
+H 778,669,0,71,74,71 2 0110 H
+I 389,669,0,67,82,67 2 0111 I
+J 500,669,99,74,96,74 2 0112 J
+K 667,669,0,85,71,85 2 0113 K
+L 611,669,0,29,72,29 2 0114 L
+M 889,669,12,78,79,78 2 0115 M
+N 722,669,15,76,77,76 2 0116 N
+O 722,685,18,19,23,19 2 0117 O
+P 611,669,0,52,77,52 2 0120 P
+Q 722,685,208,19,23,19 3 0121 Q
+R 667,669,0,6,79,6 2 0122 R
+S 556,685,18,20,48,20 2 0123 S
+T 611,669,0,89,0,89 2 0124 T
+U 722,669,18,72,-17,72 2 0125 U
+V 667,669,18,98,-15,98 2 0126 V
+W 889,669,18,101,-15,99 2 0127 W
+X 667,669,0,77,74,77 2 0130 X
+Y 611,669,0,98,-23,98 2 0131 Y
+Z 611,669,0,29,61,29 2 0132 Z
+[ 333,674,159,79,87,79 2 0133 bracketleft
+lB "
+\ 278,685,18,51,51,51 2 0134 backslash
+rs "
+] 333,674,157,60,106,60 2 0135 bracketright
+rB "
+a^ 333,690,0,84,10,84 2 0136 circumflex
+^ "
+_ 500,0,125,50,50,50 0 0137 underscore
+` 333,685,0,49,-78,49 2 0140 quoteleft
+oq "
+a 500,462,14,5,71,5 0 0141 a
+b 500,699,13,0,64 2 0142 b
+c 444,462,13,0,55 0 0143 c
+d 500,699,13,67,71,67 2 0144 d
+e 444,462,13,4,45,4 0 0145 e
+f 333,698,205,163,219,99 3 0146 f
+g 500,462,203,28,102,28 1 0147 g
+h 556,699,9,0,63 2 0150 h
+i 278,684,9,35,48,35 2 0151 i
+j 278,684,207,51,239,51 3 0152 j
+k 500,699,8,33,73,33 2 0153 k
+l 278,699,9,62,48,62 2 0154 l
+m 778,462,9,0,64 0 0155 m
+n 556,462,9,0,56 0 0156 n
+o 500,462,13,0,53 0 0157 o
+p 500,462,205,0,170 1 0160 p
+q 500,462,205,21,49,21 1 0161 q
+r 389,462,0,50,71,50 0 0162 r
+s 389,462,13,0,69 0 0163 s
+t 278,594,9,53,61,53 2 0164 t
+u 556,462,9,0,35 0 0165 u
+v 444,462,13,7,34,7 0 0166 v
+w 667,462,13,0,34 0 0167 w
+x 500,462,13,19,96,19 0 0170 x
+y 444,462,205,0,144 1 0171 y
+z 389,449,78,29,93,29 0 0172 z
+lC 348,686,187,138,45,99 2 0173 braceleft
+{ "
+ba 220,685,18,0,-16 2 0174 bar
+| "
+rC 348,686,187,4,179,4 2 0175 braceright
+} "
+a~ 333,655,0,124,2,99 2 0176 tilde
+~ "
+bq 333,134,182,0,55 0 0200 quotesinglbase
+Fo 500,415,0,18,38,18 0 0201 guillemotleft
+char171 "
+Fc 500,415,0,18,38,18 0 0202 guillemotright
+char187 "
+bu 350,525,0,50,50,50 0 0203 bullet
+Fn 500,707,156,87,137,87 2 0204 florin
+f/ 167,683,14,207,219,99 2 0205 fraction
+%0 1000,706,29,46,43,46 2 0206 perthousand
+dg 500,685,145,44,-41,44 2 0207 dagger
+dd 500,685,139,43,40,43 2 0210 daggerdbl
+en 500,269,0,27,90,27 0 0211 endash
+em 1000,269,0,27,90,27 0 0212 emdash
+fi 556,703,205,8,238,8 3 0214 fi
+fl 556,704,205,47,236,47 3 0215 fl
+.i 278,462,9,10,48,10 0 0220 dotlessi
+ga 333,697,0,14,-35,14 2 0222 grave
+a" 333,697,0,215,-19,99 2 0223 hungarumlaut
+a. 333,655,0,10,-113,10 2 0224 dotaccent
+ab 333,678,0,104,-21,99 2 0225 breve
+ah 333,690,0,128,-29,99 2 0226 caron
+ao 333,729,0,57,-77,57 2 0227 ring
+ho 333,44,173,0,90 0 0230 ogonek
+lq 500,685,0,63,-3,63 2 0231 quotedblleft
+rq 500,685,0,63,-3,63 2 0232 quotedblright
+oe 722,462,13,2,44,2 0 0233 oe
+/l 278,699,9,73,63,73 2 0234 lslash
+Bq 500,134,182,0,107 0 0235 quotedblbase
+OE 944,677,8,52,27,52 2 0236 OE
+/L 611,669,0,29,72,29 2 0237 Lslash
+r! 389,492,205,0,31 1 0241 exclamdown
+char161 "
+ct 500,576,143,0,8 0 0242 cent
+char162 "
+Po 500,683,12,60,82,60 2 0243 sterling
+char163 "
+Cs 500,586,0,76,76,76 0 0244 currency
+char164 "
+Ye 500,669,0,178,17,99 2 0245 yen
+char165 "
+bb 220,685,18,0,-16 2 0246 brokenbar
+char166 "
+sc 500,685,143,9,14,9 2 0247 section
+char167 "
+ad 333,655,0,114,-5,99 2 0250 dieresis
+char168 "
+co 747,685,18,21,20,21 2 0251 copyright
+char169 "
+Of 266,685,0,114,34,99 2 0252 ordfeminine
+char170 "
+fo 333,415,0,20,18,20 0 0253 guilsinglleft
+no 606,399,0,0,-1 0 0254 logicalnot
+char172 "
+\- 606,297,0,0,-1 0 0255 minus
+rg 747,685,18,21,20,21 2 0256 registered
+char174 "
+a- 333,623,0,110,-1,99 2 0257 macron
+char175 "
+de 400,683,0,19,-33,19 2 0260 degree
+char176 "
+char177 570,506,0,17,17,17 0 0261 plusminus
+S2 300,683,0,63,48,63 2 0262 twosuperior
+char178 "
+S3 300,683,0,71,33,71 2 0263 threesuperior
+char179 "
+aa 333,697,0,96,-89,96 2 0264 acute
+char180 "
+char181 576,449,207,0,110 1 0265 mu
+ps 500,669,193,112,107,99 2 0266 paragraph
+char182 "
+char183 250,405,0,0,-1 0 0267 periodcentered
+ac 333,5,218,0,130 1 0270 cedilla
+char184 "
+S1 300,683,0,51,20,51 2 0271 onesuperior
+char185 "
+Om 300,685,0,97,-6,97 2 0272 ordmasculine
+char186 "
+fc 333,415,0,0,40 0 0273 guilsinglright
+14 750,683,14,21,43,21 2 0274 onequarter
+char188 "
+12 750,683,14,23,59,23 2 0275 onehalf
+char189 "
+34 750,683,14,26,43,26 2 0276 threequarters
+char190 "
+r? 500,492,205,0,20 1 0277 questiondown
+char191 "
+`A 667,904,0,0,117 2 0300 Agrave
+char192 "
+'A 667,904,0,0,117 2 0301 Aacute
+char193 "
+^A 667,897,0,0,117 2 0302 Acircumflex
+char194 "
+~A 667,862,0,0,117 2 0303 Atilde
+char195 "
+:A 667,862,0,0,117 2 0304 Adieresis
+char196 "
+oA 667,921,0,0,117 2 0305 Aring
+char197 "
+AE 944,669,0,24,114,24 2 0306 AE
+char198 "
+,C 667,685,218,60,18,60 3 0307 Ccedilla
+char199 "
+`E 667,904,0,36,77,36 2 0310 Egrave
+char200 "
+'E 667,904,0,36,77,36 2 0311 Eacute
+char201 "
+^E 667,897,0,36,77,36 2 0312 Ecircumflex
+char202 "
+:E 667,862,0,36,77,36 2 0313 Edieresis
+char203 "
+`I 389,904,0,67,82,67 2 0314 Igrave
+char204 "
+'I 389,904,0,73,82,73 2 0315 Iacute
+char205 "
+^I 389,897,0,81,82,81 2 0316 Icircumflex
+char206 "
+:I 389,862,0,106,82,99 2 0317 Idieresis
+char207 "
+-D 722,669,0,28,81,28 2 0320 Eth
+char208 "
+~N 722,862,15,76,77,76 2 0321 Ntilde
+char209 "
+`O 722,904,18,19,23,19 2 0322 Ograve
+char210 "
+'O 722,904,18,19,23,19 2 0323 Oacute
+char211 "
+^O 722,897,18,19,23,19 2 0324 Ocircumflex
+char212 "
+~O 722,862,18,19,23,19 2 0325 Otilde
+char213 "
+:O 722,862,18,19,23,19 2 0326 Odieresis
+char214 "
+char215 570,490,0,2,2,2 0 0327 multiply
+/O 722,764,125,19,23,19 2 0330 Oslash
+char216 "
+`U 722,904,18,72,-17,72 2 0331 Ugrave
+char217 "
+'U 722,904,18,72,-17,72 2 0332 Uacute
+char218 "
+^U 722,897,18,72,-17,72 2 0333 Ucircumflex
+char219 "
+:U 722,862,18,72,-17,72 2 0334 Udieresis
+char220 "
+'Y 611,904,0,98,-23,98 2 0335 Yacute
+char221 "
+TP 611,669,0,12,77,12 2 0336 Thorn
+char222 "
+ss 500,705,200,23,250,23 2 0337 germandbls
+char223 "
+`a 500,697,14,5,71,5 2 0340 agrave
+char224 "
+'a 500,697,14,13,71,13 2 0341 aacute
+char225 "
+^a 500,690,14,5,71,5 2 0342 acircumflex
+char226 "
+~a 500,655,14,41,71,41 2 0343 atilde
+char227 "
+:a 500,655,14,21,71,21 2 0344 adieresis
+char228 "
+oa 500,729,14,5,71,5 2 0345 aring
+char229 "
+ae 722,462,13,1,55,1 0 0346 ae
+char230 "
+,c 444,462,218,0,74 1 0347 ccedilla
+char231 "
+`e 444,697,13,4,45,4 2 0350 egrave
+char232 "
+'e 444,697,13,41,45,41 2 0351 eacute
+char233 "
+^e 444,690,13,29,45,29 2 0352 ecircumflex
+char234 "
+:e 444,655,13,49,45,49 2 0353 edieresis
+char235 "
+`i 278,697,9,32,48,32 2 0354 igrave
+char236 "
+'i 278,697,9,124,48,99 2 0355 iacute
+char237 "
+^i 278,690,9,97,52,97 2 0356 icircumflex
+char238 "
+:i 278,655,9,132,48,99 2 0357 idieresis
+char239 "
+Sd 500,699,13,4,53,4 2 0360 eth
+char240 "
+~n 556,655,9,0,56 2 0361 ntilde
+char241 "
+`o 500,697,13,0,53 2 0362 ograve
+char242 "
+'o 500,697,13,13,53,13 2 0363 oacute
+char243 "
+^o 500,690,13,1,53,1 2 0364 ocircumflex
+char244 "
+~o 500,655,13,41,53,41 2 0365 otilde
+char245 "
+:o 500,655,13,16,53,16 2 0366 odieresis
+char246 "
+char247 570,535,29,17,17,17 0 0367 divide
+/o 500,560,119,0,53 0 0370 oslash
+char248 "
+`u 556,697,9,0,35 2 0371 ugrave
+char249 "
+'u 556,697,9,0,35 2 0372 uacute
+char250 "
+^u 556,690,9,0,35 2 0373 ucircumflex
+char251 "
+:u 556,655,9,0,35 2 0374 udieresis
+char252 "
+'y 444,697,205,41,144,41 3 0375 yacute
+char253 "
+Tp 500,699,205,0,170 3 0376 thorn
+char254 "
+:y 444,655,205,44,144,44 3 0377 ydieresis
+char255 "
diff --git a/gnu/usr.bin/groff/devps/TI b/gnu/usr.bin/groff/devps/TI
new file mode 100644
index 0000000..156cba7
--- /dev/null
+++ b/gnu/usr.bin/groff/devps/TI
@@ -0,0 +1,528 @@
+name TI
+internalname Times-Italic
+slant 7
+spacewidth 250
+encoding text.enc
+ligatures fi fl 0
+kernpairs
+A y -55
+A w -55
+A v -55
+A u -20
+A ' -37
+A Y -55
+A W -95
+A V -105
+A U -50
+A T -37
+A Q -40
+A O -40
+A G -35
+A C -30
+B U -10
+B A -25
+D Y -40
+D W -40
+D V -40
+D A -35
+F r -55
+F . -135
+F o -105
+F i -45
+F e -75
+F , -135
+F a -75
+F A -115
+J u -35
+J . -25
+J o -25
+J e -25
+J , -25
+J a -35
+J A -40
+K y -40
+K u -40
+K o -40
+K e -35
+K O -50
+L y -30
+L ' -37
+L Y -20
+L W -55
+L V -55
+L T -20
+N A -27
+O Y -50
+O X -40
+O W -50
+O V -50
+O T -40
+O A -55
+P . -135
+P o -80
+P e -80
+P , -135
+P a -80
+P A -90
+Q U -10
+R Y -18
+R W -18
+R V -18
+R U -40
+R O -40
+T y -74
+T w -74
+T u -55
+T ; -65
+T r -55
+T . -74
+T o -92
+T i -55
+T - -74
+T hy -74
+T char173 -74
+T e -92
+T , -74
+T : -55
+T a -92
+T O -18
+T A -50
+U . -25
+U , -25
+U A -40
+V u -74
+V ; -74
+V . -129
+V o -111
+V i -74
+V - -55
+V hy -55
+V char173 -55
+V e -111
+V , -129
+V : -65
+V a -111
+V O -30
+V A -60
+W y -70
+W u -55
+W ; -65
+W . -92
+W o -92
+W i -55
+W - -37
+W hy -37
+W char173 -37
+W e -92
+W , -92
+W : -65
+W a -92
+W O -25
+W A -60
+Y u -92
+Y ; -65
+Y . -92
+Y o -92
+Y i -74
+Y - -74
+Y hy -74
+Y char173 -74
+Y e -92
+Y , -92
+Y : -65
+Y a -92
+Y O -15
+Y A -50
+a g -10
+b u -20
+b . -40
+c k -20
+c h -15
+, ' -140
+, rq -140
+e y -30
+e x -20
+e w -15
+e v -15
+e . -15
+e g -40
+e , -10
+f ' 92
+f . -15
+f i -20
+f f -18
+f .i -60
+f , -10
+g . -15
+g g -10
+g e -10
+g , -10
+k y -10
+k o -10
+k e -10
+n v -40
+o v -10
+o g -10
+. ' -140
+. rq -140
+` ` -111
+` oq -111
+oq ` -111
+oq oq -111
+' v -10
+' t -30
+' s -40
+' r -25
+' ' -111
+' d -25
+r s -10
+r q -37
+r . -111
+r o -45
+r - -20
+r hy -20
+r char173 -20
+r g -37
+r e -37
+r d -37
+r , -111
+r c -37
+r a -15
+v . -74
+v , -74
+w . -74
+w , -74
+y . -55
+y , -55
+charset
+ha 422,666,0,50,50,43 2 0000 asciicircum
+ti 541,323,0,11,10,11 0 0001 asciitilde
+vS 500,873,18,70,33,43 2 0002 Scaron
+vZ 556,873,0,100,56,43 2 0003 Zcaron
+vs 389,661,13,115,34,43 2 0004 scaron
+vz 389,661,81,95,52,43 2 0005 zcaron
+:Y 556,818,0,127,-28,43 2 0006 Ydieresis
+tm 980,653,0,27,20,27 2 0007 trademark
+aq 214,666,0,77,-82,43 2 0010 quotesingle
+space 250 0 0040
+! 333,667,11,19,11,19 2 0041 exclam
+" 420,666,0,62,-94,43 2 0042 quotedbl
+# 500,676,0,90,48,43 2 0043 numbersign
+sh "
+$ 500,731,89,47,19,43 2 0044 dollar
+Do "
+% 833,676,13,7,-29,7 2 0045 percent
+& 778,666,18,0,-26 2 0046 ampersand
+' 333,666,0,7,-101,7 2 0047 quoteright
+( 333,669,181,32,8,32 2 0050 parenleft
+) 333,669,180,6,34,6 2 0051 parenright
+* 500,666,0,42,-78,42 2 0052 asterisk
++ 675,506,0,0,-36 0 0053 plus
+, 250,101,129,0,54 0 0054 comma
+- 333,255,0,0,1 0 0055 hyphen
+hy "
+char173 "
+. 250,100,11,0,23 0 0056 period
+/ 278,666,18,158,115,43 2 0057 slash
+sl "
+0 500,676,7,47,18,43 2 0060 zero
+1 500,676,0,0,1 2 0061 one
+2 500,676,0,2,38,2 2 0062 two
+3 500,676,7,15,35,15 2 0063 three
+4 500,676,0,29,49,29 2 0064 four
+5 500,666,7,41,35,41 2 0065 five
+6 500,686,7,71,20,43 2 0066 six
+7 500,666,8,87,-25,43 2 0067 seven
+8 500,676,7,43,20,43 2 0070 eight
+9 500,676,17,42,27,42 2 0071 nine
+: 333,441,11 0 0072 colon
+; 333,441,129,0,23 0 0073 semicolon
+< 675,514,8,0,-34 0 0074 less
+= 675,386,0,0,-36 0 0075 equal
+> 675,514,8,0,-34 0 0076 greater
+? 500,664,12,22,-82,22 2 0077 question
+@ 920,666,18,0,-68 2 0100 at
+at "
+A 611,668,0,3,101,3 2 0101 A
+B 611,653,0,27,58,27 2 0102 B
+C 667,666,18,72,-16,43 2 0103 C
+D 722,653,0,28,58,28 2 0104 D
+E 611,653,0,73,51,43 2 0105 E
+F 611,653,0,84,42,43 2 0106 F
+G 722,666,18,50,-2,43 2 0107 G
+H 722,653,0,95,58,43 2 0110 H
+I 333,653,0,101,58,43 2 0111 I
+J 444,653,18,97,56,43 2 0112 J
+K 667,653,0,105,43,43 2 0113 K
+L 556,653,0,53,58,43 2 0114 L
+M 833,653,0,90,68,43 2 0115 M
+N 667,653,15,110,70,43 2 0116 N
+O 722,666,18,27,-10,27 2 0117 O
+P 611,653,0,44,50,43 2 0120 P
+Q 722,666,182,27,-9,27 2 0121 Q
+R 611,653,0,27,63,27 2 0122 R
+S 500,667,18,58,33,43 2 0123 S
+T 556,653,0,127,-9,43 2 0124 T
+U 722,653,18,93,-52,43 2 0125 U
+V 611,653,18,127,-26,43 2 0126 V
+W 833,653,18,123,-21,43 2 0127 W
+X 611,653,0,94,79,43 2 0130 X
+Y 556,653,0,127,-28,43 2 0131 Y
+Z 556,653,0,100,56,43 2 0132 Z
+[ 389,663,153,52,29,43 2 0133 bracketleft
+lB "
+\ 278,666,18,91,91,43 2 0134 backslash
+rs "
+] 389,663,153,43,38,43 2 0135 bracketright
+rB "
+a^ 333,661,0,102,-41,43 2 0136 circumflex
+^ "
+_ 500,0,125,50,50,43 0 0137 underscore
+` 333,666,0,27,-121,27 2 0140 quoteleft
+oq "
+a 500,441,11,26,33,26 0 0141 a
+b 500,683,11,23,27,23 2 0142 b
+c 444,441,11,31,20,31 0 0143 c
+d 500,683,13,77,35,43 2 0144 d
+e 444,441,11,18,19,18 0 0145 e
+f 278,678,207,196,197,43 3 0146 f
+g 500,441,206,22,42,22 1 0147 g
+h 500,683,9,28,31,28 2 0150 h
+i 278,654,11,36,1,36 2 0151 i
+j 278,654,207,48,174,43 3 0152 j
+k 444,683,11,67,36,43 2 0153 k
+l 278,683,11,51,9,43 2 0154 l
+m 722,441,9,32,38,32 0 0155 m
+n 500,441,9,24,36,24 0 0156 n
+o 500,441,11,18,23,18 0 0157 o
+p 500,441,205,19,125,19 1 0160 p
+q 500,441,209,33,25,33 1 0161 q
+r 389,441,0,73,5,43 0 0162 r
+s 389,442,13,27,34,27 0 0163 s
+t 278,546,11,68,13,43 2 0164 t
+u 500,441,11,25,8,25 0 0165 u
+v 444,441,18,32,29,32 0 0166 v
+w 667,441,18,31,34,31 0 0167 w
+x 444,441,11,53,77,43 0 0170 x
+y 444,441,206,32,74,32 1 0171 y
+z 389,428,81,41,52,41 0 0172 z
+lC 400,687,177,57,-1,43 2 0173 braceleft
+{ "
+ba 275,666,18,0,-55 2 0174 bar
+| "
+rC 400,687,177,0,57 2 0175 braceright
+} "
+a~ 333,624,0,144,-50,43 2 0176 tilde
+~ "
+bq 333,101,129,0,6 0 0200 quotesinglbase
+Fo 500,403,0,0,-3 0 0201 guillemotleft
+char171 "
+Fc 500,403,0,0,-5 0 0202 guillemotright
+char187 "
+bu 350,461,0,10,10,10 0 0203 bullet
+Fn 500,682,182,57,25,43 2 0204 florin
+f/ 167,676,10,220,219,43 2 0205 fraction
+%0 1000,706,19,60,25,43 2 0206 perthousand
+dg 500,666,159,38,-51,38 2 0207 dagger
+dd 500,666,143,41,28,41 2 0210 daggerdbl
+en 500,243,0,55,56,43 0 0211 endash
+em 889,243,0,55,56,43 0 0212 emdash
+fi 500,681,207,31,191,31 3 0214 fi
+fl 500,682,204,68,191,43 3 0215 fl
+.i 278,441,11,7,1,7 0 0220 dotlessi
+ga 333,664,0,28,-71,28 2 0222 grave
+a" 333,664,0,203,-43,43 2 0223 hungarumlaut
+a. 333,606,0,22,-157,22 2 0224 dotaccent
+ab 333,650,0,135,-67,43 2 0225 breve
+ah 333,661,0,143,-71,43 2 0226 caron
+ao 333,691,0,72,-105,43 2 0227 ring
+ho 333,40,169,0,70 0 0230 ogonek
+lq 556,666,0,8,-116,8 2 0231 quotedblleft
+rq 556,666,0,0,-101 2 0232 quotedblright
+oe 667,441,12,29,30,29 0 0233 oe
+/l 278,683,11,79,13,43 2 0234 lslash
+Bq 556,101,129,0,-7 0 0235 quotedblbase
+OE 944,666,8,70,1,43 2 0236 OE
+/L 556,653,0,53,58,43 2 0237 Lslash
+r! 389,473,205,0,-9 1 0241 exclamdown
+char161 "
+ct 500,560,143,22,-27,22 2 0242 cent
+char162 "
+Po 500,670,6,67,40,43 2 0243 sterling
+char163 "
+Cs 500,597,0,72,72,43 2 0244 currency
+char164 "
+Ye 500,653,0,153,23,43 2 0245 yen
+char165 "
+bb 275,666,18,0,-55 2 0246 brokenbar
+char166 "
+sc 500,666,162,11,-3,11 2 0247 section
+char167 "
+ad 333,606,0,122,-57,43 2 0250 dieresis
+char168 "
+co 760,666,18,9,9,9 2 0251 copyright
+char169 "
+Of 276,676,0,126,8,43 2 0252 ordfeminine
+char170 "
+fo 333,403,0,0,-1 0 0253 guilsinglleft
+no 675,386,0,0,-36 0 0254 logicalnot
+char172 "
+\- 675,286,0,0,-36 0 0255 minus
+rg 760,666,18,9,9,9 2 0256 registered
+char174 "
+a- 333,583,0,128,-49,43 2 0257 macron
+char175 "
+de 400,676,0,37,-51,37 2 0260 degree
+char176 "
+char177 675,506,0,0,-36 0 0261 plusminus
+S2 300,676,0,74,17,43 2 0262 twosuperior
+char178 "
+S3 300,676,0,89,7,43 2 0263 threesuperior
+char179 "
+aa 333,664,0,120,-130,43 2 0264 acute
+char180 "
+char181 500,428,209,47,80,43 1 0265 mu
+ps 523,653,123,143,-5,43 2 0266 paragraph
+char182 "
+char183 250,310,0,0,-20 0 0267 periodcentered
+ac 333,0,217,0,80 1 0270 cedilla
+char184 "
+S1 300,676,0,34,7,34 2 0271 onesuperior
+char185 "
+Om 310,676,0,102,-17,43 2 0272 ordmasculine
+char186 "
+fc 333,403,0,0,-2 0 0273 guilsinglright
+14 750,676,10,36,17,36 2 0274 onequarter
+char188 "
+12 750,676,10,49,16,43 2 0275 onehalf
+char189 "
+34 750,676,10,36,27,36 2 0276 threequarters
+char190 "
+r? 500,471,205,0,22 1 0277 questiondown
+char191 "
+`A 611,876,0,3,101,3 2 0300 Agrave
+char192 "
+'A 611,876,0,3,101,3 2 0301 Aacute
+char193 "
+^A 611,873,0,3,101,3 2 0302 Acircumflex
+char194 "
+~A 611,836,0,5,101,5 2 0303 Atilde
+char195 "
+:A 611,818,0,3,101,3 2 0304 Adieresis
+char196 "
+oA 611,883,0,3,101,3 2 0305 Aring
+char197 "
+AE 889,653,0,72,77,43 2 0306 AE
+char198 "
+,C 667,666,217,72,-16,43 3 0307 Ccedilla
+char199 "
+`E 611,876,0,73,51,43 2 0310 Egrave
+char200 "
+'E 611,876,0,73,51,43 2 0311 Eacute
+char201 "
+^E 611,873,0,73,51,43 2 0312 Ecircumflex
+char202 "
+:E 611,818,0,73,51,43 2 0313 Edieresis
+char203 "
+`I 333,876,0,101,58,43 2 0314 Igrave
+char204 "
+'I 333,876,0,130,58,43 2 0315 Iacute
+char205 "
+^I 333,873,0,142,58,43 2 0316 Icircumflex
+char206 "
+:I 333,818,0,152,58,43 2 0317 Idieresis
+char207 "
+-D 722,653,0,28,58,28 2 0320 Eth
+char208 "
+~N 667,836,15,110,70,43 2 0321 Ntilde
+char209 "
+`O 722,876,18,27,-10,27 2 0322 Ograve
+char210 "
+'O 722,876,18,27,-10,27 2 0323 Oacute
+char211 "
+^O 722,873,18,27,-10,27 2 0324 Ocircumflex
+char212 "
+~O 722,836,18,27,-10,27 2 0325 Otilde
+char213 "
+:O 722,818,18,27,-10,27 2 0326 Odieresis
+char214 "
+char215 675,497,0,0,-43 0 0327 multiply
+/O 722,722,105,27,-10,27 2 0330 Oslash
+char216 "
+`U 722,876,18,93,-52,43 2 0331 Ugrave
+char217 "
+'U 722,876,18,93,-52,43 2 0332 Uacute
+char218 "
+^U 722,873,18,93,-52,43 2 0333 Ucircumflex
+char219 "
+:U 722,818,18,93,-52,43 2 0334 Udieresis
+char220 "
+'Y 556,876,0,127,-28,43 2 0335 Yacute
+char221 "
+TP 611,653,0,8,50,8 2 0336 Thorn
+char222 "
+ss 500,679,207,43,218,43 3 0337 germandbls
+char223 "
+`a 500,664,11,26,33,26 2 0340 agrave
+char224 "
+'a 500,664,11,37,33,37 2 0341 aacute
+char225 "
+^a 500,661,11,26,33,26 2 0342 acircumflex
+char226 "
+~a 500,624,11,61,33,43 2 0343 atilde
+char227 "
+:a 500,606,11,39,33,39 2 0344 adieresis
+char228 "
+oa 500,691,11,26,33,26 2 0345 aring
+char229 "
+ae 667,441,11,23,27,23 0 0346 ae
+char230 "
+,c 444,441,217,31,24,31 1 0347 ccedilla
+char231 "
+`e 444,664,11,18,19,18 2 0350 egrave
+char232 "
+'e 444,664,11,65,19,43 2 0351 eacute
+char233 "
+^e 444,661,11,47,19,43 2 0352 ecircumflex
+char234 "
+:e 444,606,11,57,19,43 2 0353 edieresis
+char235 "
+`i 278,664,11,56,1,43 2 0354 igrave
+char236 "
+'i 278,664,11,128,1,43 2 0355 iacute
+char237 "
+^i 278,661,11,100,16,43 2 0356 icircumflex
+char238 "
+:i 278,606,11,125,1,43 2 0357 idieresis
+char239 "
+Sd 500,683,11,32,23,32 2 0360 eth
+char240 "
+~n 500,624,9,26,36,26 2 0361 ntilde
+char241 "
+`o 500,664,11,18,23,18 2 0362 ograve
+char242 "
+'o 500,664,11,37,23,37 2 0363 oacute
+char243 "
+^o 500,661,11,18,23,18 2 0364 ocircumflex
+char244 "
+~o 500,624,11,46,23,43 2 0365 otilde
+char245 "
+:o 500,606,11,39,23,39 2 0366 odieresis
+char246 "
+char247 675,517,11,0,-36 0 0367 divide
+/o 500,554,135,19,22,19 2 0370 oslash
+char248 "
+`u 500,664,11,25,8,25 2 0371 ugrave
+char249 "
+'u 500,664,11,27,8,27 2 0372 uacute
+char250 "
+^u 500,661,11,25,8,25 2 0373 ucircumflex
+char251 "
+:u 500,606,11,29,8,29 2 0374 udieresis
+char252 "
+'y 444,664,206,65,74,43 3 0375 yacute
+char253 "
+Tp 500,683,205,19,125,19 3 0376 thorn
+char254 "
+:y 444,606,206,47,74,43 3 0377 ydieresis
+char255 "
diff --git a/gnu/usr.bin/groff/devps/TR b/gnu/usr.bin/groff/devps/TR
new file mode 100644
index 0000000..25232c6
--- /dev/null
+++ b/gnu/usr.bin/groff/devps/TR
@@ -0,0 +1,519 @@
+name TR
+internalname Times-Roman
+spacewidth 250
+encoding text.enc
+ligatures fi fl 0
+kernpairs
+A y -92
+A w -92
+A v -74
+A ' -111
+A Y -105
+A W -90
+A V -135
+A U -55
+A T -111
+A Q -55
+A O -55
+A G -40
+A C -40
+B U -10
+B A -35
+D Y -55
+D W -30
+D V -40
+D A -40
+F . -80
+F o -15
+F , -80
+F a -15
+F A -74
+J A -60
+K y -25
+K u -15
+K o -35
+K e -25
+K O -30
+L y -55
+L ' -92
+L Y -100
+L W -74
+L V -100
+L T -92
+N A -35
+O Y -50
+O X -40
+O W -35
+O V -50
+O T -40
+O A -35
+P . -111
+P , -111
+P a -15
+P A -92
+Q U -10
+R Y -65
+R W -55
+R V -80
+R U -40
+R T -60
+R O -40
+T y -80
+T w -80
+T u -45
+T ; -55
+T r -35
+T . -74
+T o -80
+T i -35
+T - -92
+T hy -92
+T char173 -92
+T e -70
+T , -74
+T : -50
+T a -80
+T O -18
+T A -93
+U A -40
+V u -75
+V ; -74
+V . -129
+V o -129
+V i -60
+V - -100
+V hy -100
+V char173 -100
+V e -111
+V , -129
+V : -74
+V a -111
+V O -40
+V G -15
+V A -135
+W y -73
+W u -50
+W ; -37
+W . -92
+W o -80
+W i -40
+W - -65
+W hy -65
+W char173 -65
+W e -80
+W , -92
+W : -37
+W a -80
+W O -10
+W A -120
+Y u -111
+Y ; -92
+Y . -129
+Y o -110
+Y i -55
+Y - -111
+Y hy -111
+Y char173 -111
+Y e -100
+Y , -129
+Y : -92
+Y a -100
+Y O -30
+Y A -120
+a w -15
+a v -20
+b v -15
+b u -20
+b . -40
+c y -15
+, ' -70
+, rq -70
+e y -15
+e x -15
+e w -25
+e v -25
+e g -15
+f ' 55
+f i -20
+f f -25
+f .i -50
+f a -10
+g a -5
+h y -5
+i v -25
+k y -15
+k o -10
+k e -10
+l w -10
+n y -15
+n v -40
+o y -10
+o w -25
+o v -15
+p y -10
+. ' -70
+. rq -70
+lq A -80
+` ` -74
+` oq -74
+oq ` -74
+oq oq -74
+` A -80
+oq A -80
+' v -50
+' t -18
+' s -55
+' r -50
+' ' -74
+' l -10
+' d -50
+r . -55
+r - -20
+r hy -20
+r char173 -20
+r g -18
+r , -40
+v . -65
+v o -20
+v e -15
+v , -65
+v a -25
+w . -65
+w o -10
+w , -65
+w a -10
+x e -15
+y . -65
+y , -65
+charset
+ha 469,662 2 0000 asciicircum
+ti 541,323 0 0001 asciitilde
+vS 556,886,14 2 0002 Scaron
+vZ 611,886 2 0003 Zcaron
+vs 389,674,10 2 0004 scaron
+vz 444,674 2 0005 zcaron
+:Y 722,835 2 0006 Ydieresis
+tm 980,662 2 0007 trademark
+aq 180,676 2 0010 quotesingle
+space 250 0 0040
+! 333,676,9 2 0041 exclam
+" 408,676 2 0042 quotedbl
+# 500,662 2 0043 numbersign
+sh "
+$ 500,727,87 2 0044 dollar
+Do "
+% 833,676,13 2 0045 percent
+& 778,676,13 2 0046 ampersand
+' 333,676 2 0047 quoteright
+( 333,676,177 2 0050 parenleft
+) 333,676,177 2 0051 parenright
+* 500,676 2 0052 asterisk
++ 564,506 0 0053 plus
+, 250,102,141 0 0054 comma
+- 333,257 0 0055 hyphen
+hy "
+char173 "
+. 250,100,11 0 0056 period
+/ 278,676,14 2 0057 slash
+sl "
+0 500,676,14 2 0060 zero
+1 500,676 2 0061 one
+2 500,676 2 0062 two
+3 500,676,14 2 0063 three
+4 500,676 2 0064 four
+5 500,688,14 2 0065 five
+6 500,684,14 2 0066 six
+7 500,662,8 2 0067 seven
+8 500,676,14 2 0070 eight
+9 500,676,22 2 0071 nine
+: 278,459,11 0 0072 colon
+; 278,459,141 0 0073 semicolon
+< 564,514,8 0 0074 less
+= 564,386 0 0075 equal
+> 564,514,8 0 0076 greater
+? 444,676,8 2 0077 question
+@ 921,676,14 2 0100 at
+at "
+A 722,674 2 0101 A
+B 667,662 2 0102 B
+C 667,676,14 2 0103 C
+D 722,662 2 0104 D
+E 611,662 2 0105 E
+F 556,662 2 0106 F
+G 722,676,14 2 0107 G
+H 722,662 2 0110 H
+I 333,662 2 0111 I
+J 389,662,14 2 0112 J
+K 722,662 2 0113 K
+L 611,662 2 0114 L
+M 889,662 2 0115 M
+N 722,662,11 2 0116 N
+O 722,676,14 2 0117 O
+P 556,662 2 0120 P
+Q 722,676,178 2 0121 Q
+R 667,662 2 0122 R
+S 556,676,14 2 0123 S
+T 611,662 2 0124 T
+U 722,662,14 2 0125 U
+V 722,662,11 2 0126 V
+W 944,662,11 2 0127 W
+X 722,662 2 0130 X
+Y 722,662 2 0131 Y
+Z 611,662 2 0132 Z
+[ 333,662,156 2 0133 bracketleft
+lB "
+\ 278,676,14 2 0134 backslash
+rs "
+] 333,662,156 2 0135 bracketright
+rB "
+a^ 333,674 2 0136 circumflex
+^ "
+_ 500,0,125 0 0137 underscore
+` 333,676 2 0140 quoteleft
+oq "
+a 444,460,10 0 0141 a
+b 500,683,10 2 0142 b
+c 444,460,10 0 0143 c
+d 500,683,10 2 0144 d
+e 444,460,10 0 0145 e
+f 333,683 2 0146 f
+g 500,460,218 1 0147 g
+h 500,683 2 0150 h
+i 278,683 2 0151 i
+j 278,683,218 3 0152 j
+k 500,683 2 0153 k
+l 278,683 2 0154 l
+m 778,460 0 0155 m
+n 500,460 0 0156 n
+o 500,460,10 0 0157 o
+p 500,460,217 1 0160 p
+q 500,460,217 1 0161 q
+r 333,460 0 0162 r
+s 389,460,10 0 0163 s
+t 278,579,10 2 0164 t
+u 500,450,10 0 0165 u
+v 500,450,14 0 0166 v
+w 722,450,14 0 0167 w
+x 500,450 0 0170 x
+y 500,450,218 1 0171 y
+z 444,450 0 0172 z
+lC 480,680,181 2 0173 braceleft
+{ "
+ba 200,676,14 2 0174 bar
+| "
+rC 480,680,181 2 0175 braceright
+} "
+a~ 333,638 2 0176 tilde
+~ "
+bq 333,102,141 0 0200 quotesinglbase
+Fo 500,416 0 0201 guillemotleft
+char171 "
+Fc 500,416 0 0202 guillemotright
+char187 "
+bu 350,466 0 0203 bullet
+Fn 500,676,189 2 0204 florin
+f/ 167,676,14 2 0205 fraction
+%0 1000,706,19 2 0206 perthousand
+dg 500,676,149 2 0207 dagger
+dd 500,676,153 2 0210 daggerdbl
+en 500,250 0 0211 endash
+em 1000,250 0 0212 emdash
+fi 556,683 2 0214 fi
+fl 556,683 2 0215 fl
+.i 278,460 0 0220 dotlessi
+ga 333,678 2 0222 grave
+a" 333,678 2 0223 hungarumlaut
+a. 333,623 2 0224 dotaccent
+ab 333,664 2 0225 breve
+ah 333,674 2 0226 caron
+ao 333,711 2 0227 ring
+ho 333,0,165 0 0230 ogonek
+lq 444,676 2 0231 quotedblleft
+rq 444,676 2 0232 quotedblright
+oe 722,460,10 0 0233 oe
+/l 278,683 2 0234 lslash
+Bq 444,102,141 0 0235 quotedblbase
+OE 889,668,6 2 0236 OE
+/L 611,662 2 0237 Lslash
+r! 333,467,218 1 0241 exclamdown
+char161 "
+ct 500,579,138 2 0242 cent
+char162 "
+Po 500,676,8 2 0243 sterling
+char163 "
+Cs 500,602 2 0244 currency
+char164 "
+Ye 500,662 2 0245 yen
+char165 "
+bb 200,676,14 2 0246 brokenbar
+char166 "
+sc 500,676,148 2 0247 section
+char167 "
+ad 333,623 2 0250 dieresis
+char168 "
+co 760,676,14 2 0251 copyright
+char169 "
+Of 276,676 2 0252 ordfeminine
+char170 "
+fo 333,416 0 0253 guilsinglleft
+no 564,386 0 0254 logicalnot
+char172 "
+\- 564,286 0 0255 minus
+rg 760,676,14 2 0256 registered
+char174 "
+a- 333,601 2 0257 macron
+char175 "
+de 400,676 2 0260 degree
+char176 "
+char177 564,506 0 0261 plusminus
+S2 300,676 2 0262 twosuperior
+char178 "
+S3 300,676 2 0263 threesuperior
+char179 "
+aa 333,678 2 0264 acute
+char180 "
+char181 500,450,218 1 0265 mu
+ps 453,662,154 2 0266 paragraph
+char182 "
+char183 250,310 0 0267 periodcentered
+ac 333,0,215 0 0270 cedilla
+char184 "
+S1 300,676 2 0271 onesuperior
+char185 "
+Om 310,676 2 0272 ordmasculine
+char186 "
+fc 333,416 0 0273 guilsinglright
+14 750,676,14 2 0274 onequarter
+char188 "
+12 750,676,14 2 0275 onehalf
+char189 "
+34 750,676,14 2 0276 threequarters
+char190 "
+r? 444,466,218 1 0277 questiondown
+char191 "
+`A 722,890 2 0300 Agrave
+char192 "
+'A 722,890 2 0301 Aacute
+char193 "
+^A 722,886 2 0302 Acircumflex
+char194 "
+~A 722,850 2 0303 Atilde
+char195 "
+:A 722,835 2 0304 Adieresis
+char196 "
+oA 722,898 2 0305 Aring
+char197 "
+AE 889,662 2 0306 AE
+char198 "
+,C 667,676,215 2 0307 Ccedilla
+char199 "
+`E 611,890 2 0310 Egrave
+char200 "
+'E 611,890 2 0311 Eacute
+char201 "
+^E 611,886 2 0312 Ecircumflex
+char202 "
+:E 611,835 2 0313 Edieresis
+char203 "
+`I 333,890 2 0314 Igrave
+char204 "
+'I 333,890 2 0315 Iacute
+char205 "
+^I 333,886 2 0316 Icircumflex
+char206 "
+:I 333,835 2 0317 Idieresis
+char207 "
+-D 722,662 2 0320 Eth
+char208 "
+~N 722,850,11 2 0321 Ntilde
+char209 "
+`O 722,890,14 2 0322 Ograve
+char210 "
+'O 722,890,14 2 0323 Oacute
+char211 "
+^O 722,886,14 2 0324 Ocircumflex
+char212 "
+~O 722,850,14 2 0325 Otilde
+char213 "
+:O 722,835,14 2 0326 Odieresis
+char214 "
+char215 564,497 0 0327 multiply
+/O 722,734,80 2 0330 Oslash
+char216 "
+`U 722,890,14 2 0331 Ugrave
+char217 "
+'U 722,890,14 2 0332 Uacute
+char218 "
+^U 722,886,14 2 0333 Ucircumflex
+char219 "
+:U 722,835,14 2 0334 Udieresis
+char220 "
+'Y 722,890 2 0335 Yacute
+char221 "
+TP 556,662 2 0336 Thorn
+char222 "
+ss 500,683,9 2 0337 germandbls
+char223 "
+`a 444,678,10 2 0340 agrave
+char224 "
+'a 444,678,10 2 0341 aacute
+char225 "
+^a 444,674,10 2 0342 acircumflex
+char226 "
+~a 444,638,10 2 0343 atilde
+char227 "
+:a 444,623,10 2 0344 adieresis
+char228 "
+oa 444,711,10 2 0345 aring
+char229 "
+ae 667,460,10 0 0346 ae
+char230 "
+,c 444,460,215 0 0347 ccedilla
+char231 "
+`e 444,678,10 2 0350 egrave
+char232 "
+'e 444,678,10 2 0351 eacute
+char233 "
+^e 444,674,10 2 0352 ecircumflex
+char234 "
+:e 444,623,10 2 0353 edieresis
+char235 "
+`i 278,678 2 0354 igrave
+char236 "
+'i 278,678 2 0355 iacute
+char237 "
+^i 278,674 2 0356 icircumflex
+char238 "
+:i 278,623 2 0357 idieresis
+char239 "
+Sd 500,686,10 2 0360 eth
+char240 "
+~n 500,638 2 0361 ntilde
+char241 "
+`o 500,678,10 2 0362 ograve
+char242 "
+'o 500,678,10 2 0363 oacute
+char243 "
+^o 500,674,10 2 0364 ocircumflex
+char244 "
+~o 500,638,10 2 0365 otilde
+char245 "
+:o 500,623,10 2 0366 odieresis
+char246 "
+char247 564,516,10 0 0367 divide
+/o 500,551,112 0 0370 oslash
+char248 "
+`u 500,678,10 2 0371 ugrave
+char249 "
+'u 500,678,10 2 0372 uacute
+char250 "
+^u 500,674,10 2 0373 ucircumflex
+char251 "
+:u 500,623,10 2 0374 udieresis
+char252 "
+'y 500,678,218 3 0375 yacute
+char253 "
+Tp 500,683,217 3 0376 thorn
+char254 "
+:y 500,623,218 3 0377 ydieresis
+char255 "
diff --git a/gnu/usr.bin/groff/devps/ZCMI b/gnu/usr.bin/groff/devps/ZCMI
new file mode 100644
index 0000000..53e56fd
--- /dev/null
+++ b/gnu/usr.bin/groff/devps/ZCMI
@@ -0,0 +1,477 @@
+name ZCMI
+internalname ZapfChancery-MediumItalic
+slant 14
+spacewidth 220
+encoding text.enc
+ligatures fi fl 0
+kernpairs
+A ' -40
+A rq -40
+A U -10
+A T 10
+A Q 10
+A O 10
+A G -30
+A C 20
+D . -30
+D , -20
+D Y 10
+D A -10
+F . -40
+F i 10
+F , -30
+G . -20
+G , -10
+J . -20
+J , -10
+K u -20
+K o -20
+K e -20
+L y -10
+L ' -25
+L rq -25
+L W -10
+L V -20
+O . -20
+O , -10
+O Y 10
+O T 20
+O A -20
+P . -50
+P o -10
+P e -10
+P , -40
+P a -20
+P A -10
+Q U -10
+R Y 10
+R W 10
+R T 20
+T o -20
+T i 20
+T - -20
+T hy -20
+T char173 -20
+T h 20
+T e -20
+T a -20
+T O 30
+T A 10
+V . -100
+V o -20
+V e -20
+V , -90
+V a -20
+V O 10
+V G -20
+W . -50
+W o -20
+W i 10
+W h 10
+W e -20
+W , -40
+W a -20
+W O 10
+Y u -20
+Y . -50
+Y o -50
+Y i 10
+Y e -40
+Y , -40
+Y a -60
+b . -30
+b l -20
+b , -20
+b b -20
+c k -10
+, ' -70
+, rq -70
+d w -20
+d v -10
+d d -40
+e y 10
+f ' 30
+f rq 30
+f . -50
+f f -50
+f e -10
+f , -40
+f a -20
+g y 10
+g . -30
+g i 10
+g e 10
+g , -20
+g a 10
+k y 10
+k o -10
+k e -20
+m y 10
+m u 10
+n y 20
+o . -30
+o , -20
+p . -30
+p p -10
+p , -20
+. ' -80
+. rq -80
+lq ` 20
+lq oq 20
+lq A 10
+` ` -115
+` oq -115
+oq ` -115
+oq oq -115
+` A 10
+oq A 10
+' v 30
+' t 20
+' s -25
+' r 30
+' ' -115
+' rq 20
+' l 20
+r . -50
+r i 10
+r , -40
+s . -20
+s , -10
+v . -30
+v , -20
+w . -30
+w o 10
+w h 20
+w , -20
+charset
+ha 520,594,0,62,-82,62 2 0000 asciicircum
+ti 520,320,0,69,-73,69 0 0001 asciitilde
+vS 460,831,81,184,5,87 2 0002 Scaron
+vZ 620,831,19,99,8,87 2 0003 Zcaron
+vs 320,659,14,194,4,87 2 0004 scaron
+vz 440,659,14,124,24,87 2 0005 zcaron
+:Y 560,762,168,264,9,87 2 0006 Ydieresis
+tm 1000,594,0,96,-77,87 2 0007 trademark
+aq 160,610,0,105,-95,87 2 0010 quotesingle
+space 220 0 0040
+! 280,610,14,123,-69,87 2 0041 exclam
+" 220,610,0,163,-70,87 2 0042 quotedbl
+# 440,594,0,131,-33,87 2 0043 numbersign
+sh "
+$ 440,709,144,118,-10,87 2 0044 dollar
+Do "
+% 680,700,160,80,-82,80 2 0045 percent
+& 780,610,16,185,-76,87 2 0046 ampersand
+' 240,610,0,148,-118,87 2 0047 quoteright
+( 260,664,216,201,-46,87 2 0050 parenleft
+) 220,664,216,132,63,87 2 0051 parenright
+* 420,610,0,109,-89,87 2 0052 asterisk
++ 520,426,0,73,-67,73 0 0053 plus
+, 220,148,140,43,25,43 0 0054 comma
+- 280,248,0,104,-19,87 0 0055 hyphen
+hy "
+char173 "
+. 220,128,14,58,-52,58 0 0056 period
+/ 340,610,16,168,-24,87 2 0057 slash
+sl "
+0 440,610,16,148,-29,87 2 0060 zero
+1 440,610,0,38,9,38 2 0061 one
+2 440,610,16,95,33,87 2 0062 two
+3 440,610,16,95,49,87 2 0063 three
+4 440,610,35,109,-27,87 2 0064 four
+5 440,679,16,205,-10,87 2 0065 five
+6 440,610,16,166,-40,87 2 0066 six
+7 440,645,33,171,-107,87 2 0067 seven
+8 440,610,16,139,-15,87 2 0070 eight
+9 440,610,16,127,18,87 2 0071 nine
+: 260,438,14,86,-48,86 0 0072 colon
+; 240,438,140,109,21,87 0 0073 semicolon
+< 520,468,0,57,-89,57 0 0074 less
+= 520,340,0,73,-67,73 0 0075 equal
+> 520,468,0,57,-89,57 0 0076 greater
+? 380,610,14,125,-100,87 2 0077 question
+@ 700,610,16,103,-77,87 2 0100 at
+at "
+A 620,632,16,127,37,87 2 0101 A
+B 600,640,6,124,-35,87 2 0102 B
+C 520,610,16,161,-43,87 2 0103 C
+D 700,640,6,118,-36,87 2 0104 D
+E 620,618,12,139,-41,87 2 0105 E
+F 580,629,118,263,-70,87 2 0106 F
+G 620,610,242,139,-98,87 2 0107 G
+H 680,708,16,248,32,87 2 0110 H
+I 380,594,0,174,-49,87 2 0111 I
+J 400,594,147,188,64,87 2 0112 J
+K 660,610,153,234,-3,87 2 0113 K
+L 580,610,16,127,-3,87 2 0114 L
+M 840,722,16,230,-8,87 2 0115 M
+N 700,708,168,265,-35,87 2 0116 N
+O 600,610,16,110,-44,87 2 0117 O
+P 540,628,0,168,8,87 2 0120 P
+Q 600,610,177,225,-34,87 2 0121 Q
+R 600,640,168,255,-8,87 2 0122 R
+S 460,610,81,148,5,87 2 0123 S
+T 500,667,0,294,-13,87 2 0124 T
+U 740,617,16,102,-76,87 2 0125 U
+V 640,714,16,220,-74,87 2 0126 V
+W 880,723,16,216,-44,87 2 0127 W
+X 560,610,16,189,80,87 2 0130 X
+Y 560,647,168,264,9,87 2 0131 Y
+Z 620,624,19,99,8,87 2 0132 Z
+[ 240,655,207,215,63,87 2 0133 bracketleft
+lB "
+\ 480,610,16,94,-90,87 2 0134 backslash
+rs "
+] 320,655,207,121,77,87 2 0135 bracketright
+rB "
+a^ 340,649,0,153,-173,87 2 0136 circumflex
+^ "
+_ 500,0,125,50,50,50 0 0137 underscore
+` 240,610,0,149,-119,87 2 0140 quoteleft
+oq "
+a 420,438,15,115,-42,87 0 0141 a
+b 420,714,23,122,-32,87 2 0142 b
+c 340,438,14,116,-37,87 0 0143 c
+d 440,714,14,261,-52,87 2 0144 d
+e 340,438,14,113,-37,87 0 0145 e
+f 320,714,314,277,169,87 3 0146 f
+g 400,438,314,153,158,87 1 0147 g
+h 440,714,14,134,-5,87 2 0150 h
+i 240,635,14,151,-50,87 2 0151 i
+j 220,635,314,162,162,87 3 0152 j
+k 440,714,184,238,-37,87 2 0153 k
+l 240,714,14,290,-52,87 2 0154 l
+m 620,438,14,134,-36,87 0 0155 m
+n 460,438,14,134,-51,87 0 0156 n
+o 400,438,14,99,-37,87 0 0157 o
+p 440,432,314,94,73,87 1 0160 p
+q 400,510,300,140,-37,87 1 0161 q
+r 300,438,14,174,-51,87 0 0162 r
+s 320,438,14,133,4,87 0 0163 s
+t 320,539,14,156,-56,87 2 0164 t
+u 460,438,14,118,-52,87 0 0165 u
+v 440,488,14,143,-37,87 0 0166 v
+w 680,488,14,152,-37,87 0 0167 w
+x 420,438,195,219,-20,87 0 0170 x
+y 400,438,314,133,74,87 1 0171 y
+z 440,445,14,118,24,87 0 0172 z
+lC 240,655,207,193,-5,87 2 0173 braceleft
+{ "
+ba 520,714,16,0,-270 2 0174 bar
+| "
+rC 240,655,207,128,60,87 2 0175 braceright
+} "
+a~ 440,619,0,132,-193,87 2 0176 tilde
+~ "
+bq 180,146,121,61,29,61 0 0200 quotesinglbase
+Fo 340,414,0,66,-48,66 0 0201 guillemotleft
+char171 "
+Fc 380,414,0,45,-67,45 0 0202 guillemotright
+char187 "
+bu 600,445,0,0,-178 0 0203 bullet
+Fn 440,610,314,192,114,87 3 0204 florin
+f/ 60,610,16,310,231,87 2 0205 fraction
+%0 960,700,160,95,-62,87 2 0206 perthousand
+dg 460,610,37,158,-88,87 2 0207 dagger
+dd 480,610,59,103,-88,87 2 0210 daggerdbl
+en 500,239,0,115,-1,87 0 0211 endash
+em 1000,239,0,115,-1,87 0 0212 emdash
+fi 520,714,314,135,174,87 3 0214 fi
+fl 520,714,314,200,174,87 3 0215 fl
+.i 240,438,14,116,-50,87 0 0220 dotlessi
+ga 220,659,0,169,-143,87 2 0222 grave
+a" 400,659,0,145,-158,87 2 0223 hungarumlaut
+a. 220,610,0,158,-186,87 2 0224 dotaccent
+ab 440,631,0,111,-203,87 2 0225 breve
+ah 340,659,0,184,-204,87 2 0226 caron
+ao 300,659,0,166,-190,87 2 0227 ring
+ho 280,6,191,3,12,3 0 0230 ogonek
+lq 340,610,0,174,-119,87 2 0231 quotedblleft
+rq 360,610,0,143,-108,87 2 0232 quotedblright
+oe 560,438,14,118,-28,87 0 0233 oe
+/l 300,714,14,265,-71,87 2 0234 lslash
+Bq 280,146,121,51,64,51 0 0235 quotedblbase
+OE 820,610,16,139,-13,87 2 0236 OE
+/L 580,610,16,127,1,87 2 0237 Lslash
+r! 280,438,186,76,-22,76 0 0241 exclamdown
+char161 "
+ct 440,543,134,86,-72,86 2 0242 cent
+char162 "
+Po 440,610,52,116,66,87 2 0243 sterling
+char163 "
+Cs 440,509,0,84,0,84 0 0244 currency
+char164 "
+Ye 440,647,168,223,51,87 2 0245 yen
+char165 "
+bb 520,714,16,0,-270 2 0246 brokenbar
+char166 "
+sc 420,610,215,144,-3,87 2 0247 section
+char167 "
+ad 360,610,0,159,-193,87 2 0250 dieresis
+char168 "
+co 740,610,16,73,-87,73 2 0251 copyright
+char169 "
+Of 260,610,0,176,-61,87 2 0252 ordfeminine
+char170 "
+fo 240,414,0,68,-48,68 0 0253 guilsinglleft
+no 520,340,0,73,-67,73 0 0254 logicalnot
+char172 "
+\- 520,242,0,73,-67,73 0 0255 minus
+rg 740,610,16,73,-87,73 2 0256 registered
+char174 "
+a- 440,578,0,75,-172,75 2 0257 macron
+char175 "
+de 400,610,0,107,-121,87 2 0260 degree
+char176 "
+char177 520,436,0,73,-67,73 0 0261 plusminus
+S2 264,610,0,140,-22,87 2 0262 twosuperior
+char178 "
+S3 264,610,0,134,-9,87 2 0263 threesuperior
+char179 "
+aa 300,659,0,172,-215,87 2 0264 acute
+char180 "
+char181 460,438,314,113,43,87 1 0265 mu
+ps 500,594,199,188,-55,87 2 0266 paragraph
+char182 "
+char183 220,310,0,71,-89,71 0 0267 periodcentered
+ac 300,6,191,0,38 0 0270 cedilla
+char184 "
+S1 264,610,0,97,-33,87 2 0271 onesuperior
+char185 "
+Om 260,610,0,163,-78,87 2 0272 ordmasculine
+char186 "
+fc 260,414,0,56,-56,56 0 0273 guilsinglright
+14 660,610,16,92,-6,87 2 0274 onequarter
+char188 "
+12 660,610,16,92,-6,87 2 0275 onehalf
+char189 "
+34 660,610,16,96,11,87 2 0276 threequarters
+char190 "
+r? 400,438,186,37,-32,37 0 0277 questiondown
+char191 "
+`A 620,821,16,127,37,87 2 0300 Agrave
+char192 "
+'A 620,821,16,132,37,87 2 0301 Aacute
+char193 "
+^A 620,821,16,127,37,87 2 0302 Acircumflex
+char194 "
+~A 620,771,16,132,37,87 2 0303 Atilde
+char195 "
+:A 620,762,16,139,37,87 2 0304 Adieresis
+char196 "
+oA 620,831,16,127,37,87 2 0305 Aring
+char197 "
+AE 740,594,16,109,71,87 2 0306 AE
+char198 "
+,C 520,610,191,161,-43,87 2 0307 Ccedilla
+char199 "
+`E 620,821,12,139,-41,87 2 0310 Egrave
+char200 "
+'E 620,821,12,139,-41,87 2 0311 Eacute
+char201 "
+^E 620,821,12,139,-41,87 2 0312 Ecircumflex
+char202 "
+:E 620,762,12,139,-41,87 2 0313 Edieresis
+char203 "
+`I 380,821,0,174,-49,87 2 0314 Igrave
+char204 "
+'I 380,821,0,202,-49,87 2 0315 Iacute
+char205 "
+^I 380,821,0,174,-49,87 2 0316 Icircumflex
+char206 "
+:I 380,762,0,189,-49,87 2 0317 Idieresis
+char207 "
+-D 700,640,6,118,-36,87 2 0320 Eth
+char208 "
+~N 700,761,168,265,-35,87 2 0321 Ntilde
+char209 "
+`O 600,821,16,110,-44,87 2 0322 Ograve
+char210 "
+'O 600,821,16,110,-44,87 2 0323 Oacute
+char211 "
+^O 600,821,16,110,-44,87 2 0324 Ocircumflex
+char212 "
+~O 600,761,16,110,-44,87 2 0325 Otilde
+char213 "
+:O 600,762,16,110,-44,87 2 0326 Odieresis
+char214 "
+char215 520,410,0,57,-83,57 0 0327 multiply
+/O 660,672,78,141,-33,87 2 0330 Oslash
+char216 "
+`U 740,821,16,102,-76,87 2 0331 Ugrave
+char217 "
+'U 740,821,16,102,-76,87 2 0332 Uacute
+char218 "
+^U 740,821,16,102,-76,87 2 0333 Ucircumflex
+char219 "
+:U 740,762,16,102,-76,87 2 0334 Udieresis
+char220 "
+'Y 560,821,168,264,9,87 2 0335 Yacute
+char221 "
+TP 540,623,0,157,-2,87 2 0336 Thorn
+char222 "
+ss 420,714,314,172,177,87 3 0337 germandbls
+char223 "
+`a 420,659,15,115,-42,87 2 0340 agrave
+char224 "
+'a 420,659,15,122,-42,87 2 0341 aacute
+char225 "
+^a 420,649,15,115,-42,87 2 0342 acircumflex
+char226 "
+~a 420,619,15,152,-42,87 2 0343 atilde
+char227 "
+:a 420,610,15,115,-42,87 2 0344 adieresis
+char228 "
+oa 420,659,15,115,-42,87 2 0345 aring
+char229 "
+ae 540,468,14,134,-17,87 0 0346 ae
+char230 "
+,c 340,438,191,116,-12,87 0 0347 ccedilla
+char231 "
+`e 340,659,14,113,-37,87 2 0350 egrave
+char232 "
+'e 340,659,14,172,-37,87 2 0351 eacute
+char233 "
+^e 340,649,14,143,-37,87 2 0352 ecircumflex
+char234 "
+:e 340,610,14,159,-37,87 2 0353 edieresis
+char235 "
+`i 240,659,14,116,-50,87 2 0354 igrave
+char236 "
+'i 240,659,14,202,-50,87 2 0355 iacute
+char237 "
+^i 240,649,14,173,-50,87 2 0356 icircumflex
+char238 "
+:i 240,610,14,179,-50,87 2 0357 idieresis
+char239 "
+Sd 400,714,14,172,-37,87 2 0360 eth
+char240 "
+~n 460,619,14,134,-51,87 2 0361 ntilde
+char241 "
+`o 400,659,14,99,-37,87 2 0362 ograve
+char242 "
+'o 400,659,14,132,-37,87 2 0363 oacute
+char243 "
+^o 400,649,14,103,-37,87 2 0364 ocircumflex
+char244 "
+~o 400,619,14,152,-37,87 2 0365 otilde
+char245 "
+:o 400,610,14,129,-37,87 2 0366 odieresis
+char246 "
+char247 520,440,14,73,-67,73 0 0367 divide
+/o 440,488,64,150,4,87 0 0370 oslash
+char248 "
+`u 460,659,14,118,-52,87 2 0371 ugrave
+char249 "
+'u 460,659,14,118,-52,87 2 0372 uacute
+char250 "
+^u 460,649,14,118,-52,87 2 0373 ucircumflex
+char251 "
+:u 460,610,14,118,-52,87 2 0374 udieresis
+char252 "
+'y 400,659,314,133,74,87 3 0375 yacute
+char253 "
+Tp 440,714,314,115,88,87 3 0376 thorn
+char254 "
+:y 400,610,314,133,74,87 3 0377 ydieresis
+char255 "
diff --git a/gnu/usr.bin/groff/devps/ZD b/gnu/usr.bin/groff/devps/ZD
new file mode 100644
index 0000000..c2bd4eb
--- /dev/null
+++ b/gnu/usr.bin/groff/devps/ZD
@@ -0,0 +1,193 @@
+name ZD
+internalname ZapfDingbats
+special
+spacewidth 278
+charset
+space 278 0 0040
+--- 974,621 3 0041 a1
+--- 961,611 3 0042 a2
+--- 974,621 3 0043 a202
+--- 980,692 3 0044 a3
+--- 719,566 3 0045 a4
+--- 789,705,14 3 0046 a5
+--- 790,705,14 3 0047 a119
+--- 791,705,13 3 0050 a118
+--- 690,553 3 0051 a117
+--- 960,568 3 0052 a11
+rh 939,559 3 0053 a12
+--- 549,705,11 3 0054 a13
+--- 855,632 3 0055 a14
+--- 911,642 3 0056 a15
+--- 933,550 3 0057 a16
+--- 911,642 3 0060 a105
+--- 945,553 3 0061 a17
+--- 974,587 3 0062 a18
+OK 755,705,13 3 0063 a19
+--- 846,705,14 3 0064 a20
+--- 762,692 3 0065 a21
+--- 761,692 3 0066 a22
+--- 571,661,68 3 0067 a23
+--- 677,705,13 3 0070 a24
+--- 763,692 3 0071 a25
+--- 760,692 3 0072 a26
+--- 759,692 3 0073 a27
+--- 754,692 3 0074 a28
+--- 494,692 3 0075 a6
+--- 552,692 3 0076 a7
+--- 537,692 3 0077 a8
+--- 577,596 3 0100 a9
+--- 692,705,14 3 0101 a10
+--- 786,705,14 3 0102 a29
+--- 788,705,14 3 0103 a30
+--- 788,705,14 3 0104 a31
+--- 790,705,14 3 0105 a32
+--- 793,705,13 3 0106 a33
+--- 794,705,13 3 0107 a34
+--- 816,705,14 3 0110 a35
+--- 823,705,14 3 0111 a36
+--- 789,705,14 3 0112 a37
+--- 841,705,14 3 0113 a38
+--- 823,705,14 3 0114 a39
+--- 833,705,14 3 0115 a40
+--- 816,705,13 3 0116 a41
+--- 831,705,14 3 0117 a42
+--- 923,705,14 3 0120 a43
+--- 744,692 3 0121 a44
+--- 723,692 3 0122 a45
+--- 749,692 3 0123 a46
+--- 790,705,14 3 0124 a47
+--- 792,705,14 3 0125 a48
+--- 695,706,14 3 0126 a49
+--- 776,699,6 3 0127 a50
+--- 768,699,7 3 0130 a51
+--- 792,705,14 3 0131 a52
+--- 759,692 3 0132 a53
+--- 707,704,13 3 0133 a54
+--- 708,705,14 3 0134 a55
+--- 682,705,14 3 0135 a56
+--- 701,705,14 3 0136 a57
+--- 826,705,14 3 0137 a58
+--- 815,705,14 3 0140 a59
+--- 789,705,14 3 0141 a60
+--- 789,705,14 3 0142 a61
+--- 707,705,14 3 0143 a62
+--- 687,692 3 0144 a63
+--- 696,691 3 0145 a64
+--- 689,692 3 0146 a65
+--- 786,705,14 3 0147 a66
+--- 787,705,14 3 0150 a67
+--- 713,705,14 3 0151 a68
+--- 791,705,14 3 0152 a69
+--- 785,705,14 3 0153 a70
+--- 791,705,14 3 0154 a71
+--- 873,705,14 3 0155 a72
+--- 761,692 3 0156 a73
+--- 762,692 3 0157 a74
+--- 762,692 3 0160 a203
+--- 759,692 3 0161 a75
+--- 759,692 3 0162 a204
+--- 892,705 3 0163 a76
+--- 892,692,14 3 0164 a77
+--- 788,705,14 3 0165 a78
+--- 784,705,14 3 0166 a79
+--- 438,705,14 3 0167 a81
+--- 138,692 3 0170 a82
+--- 277,692 3 0171 a83
+--- 415,692 3 0172 a84
+--- 392,705 3 0173 a97
+--- 392,705 3 0174 a98
+--- 668,705 3 0175 a99
+--- 668,705 3 0176 a100
+--- 732,806,143 3 0241 a101
+--- 544,706,14 3 0242 a102
+--- 544,705,14 3 0243 a103
+--- 910,651 3 0244 a104
+--- 667,705,14 3 0245 a106
+--- 760,705,14 3 0246 a107
+--- 760,569 3 0247 a108
+--- 776,705 3 0250 a112
+--- 595,705,14 3 0251 a111
+--- 694,705,14 3 0252 a110
+--- 626,705 3 0253 a109
+--- 788,705,14 3 0254 a120
+--- 788,705,14 3 0255 a121
+--- 788,705,14 3 0256 a122
+--- 788,705,14 3 0257 a123
+--- 788,705,14 3 0260 a124
+--- 788,705,14 3 0261 a125
+--- 788,705,14 3 0262 a126
+--- 788,705,14 3 0263 a127
+--- 788,705,14 3 0264 a128
+--- 788,705,14 3 0265 a129
+--- 788,705,14 3 0266 a130
+--- 788,705,14 3 0267 a131
+--- 788,705,14 3 0270 a132
+--- 788,705,14 3 0271 a133
+--- 788,705,14 3 0272 a134
+--- 788,705,14 3 0273 a135
+--- 788,705,14 3 0274 a136
+--- 788,705,14 3 0275 a137
+--- 788,705,14 3 0276 a138
+--- 788,705,14 3 0277 a139
+--- 788,705,14 3 0300 a140
+--- 788,705,14 3 0301 a141
+--- 788,705,14 3 0302 a142
+--- 788,705,14 3 0303 a143
+--- 788,705,14 3 0304 a144
+--- 788,705,14 3 0305 a145
+--- 788,705,14 3 0306 a146
+--- 788,705,14 3 0307 a147
+--- 788,705,14 3 0310 a148
+--- 788,705,14 3 0311 a149
+--- 788,705,14 3 0312 a150
+--- 788,705,14 3 0313 a151
+--- 788,705,14 3 0314 a152
+--- 788,705,14 3 0315 a153
+--- 788,705,14 3 0316 a154
+--- 788,705,14 3 0317 a155
+--- 788,705,14 3 0320 a156
+--- 788,705,14 3 0321 a157
+--- 788,705,14 3 0322 a158
+--- 788,705,14 3 0323 a159
+--- 894,634 3 0324 a160
+--- 838,540 3 0325 a161
+--- 1016,540 3 0326 a163
+--- 458,820,127 3 0327 a164
+--- 748,597 3 0330 a196
+--- 924,552 3 0331 a165
+--- 748,597 3 0332 a192
+--- 918,526 3 0333 a166
+--- 927,660 3 0334 a167
+--- 928,562 3 0335 a168
+--- 928,563 3 0336 a169
+--- 834,537 3 0337 a170
+--- 873,599 3 0340 a171
+--- 828,588 3 0341 a172
+--- 924,594 3 0342 a173
+--- 924,594 3 0343 a162
+--- 917,692 3 0344 a174
+--- 930,608 3 0345 a175
+--- 931,608 3 0346 a176
+--- 463,791,99 3 0347 a177
+--- 883,623 3 0350 a178
+--- 836,648 3 0351 a179
+--- 836,648 3 0352 a193
+--- 867,591 3 0353 a180
+--- 867,591 3 0354 a199
+--- 696,648 3 0355 a181
+--- 696,648 3 0356 a200
+--- 874,619 3 0357 a182
+--- 874,615 3 0361 a201
+--- 760,692 3 0362 a183
+--- 946,533 3 0363 a184
+--- 771,655 3 0364 a197
+--- 865,481 3 0365 a185
+--- 771,655 3 0366 a194
+--- 888,712,19 3 0367 a198
+--- 967,568 3 0370 a186
+--- 888,712,19 3 0371 a195
+--- 831,579 3 0372 a187
+--- 873,578 3 0373 a188
+--- 927,542 3 0374 a189
+--- 970,616 3 0375 a190
+--- 918,593 3 0376 a191
diff --git a/gnu/usr.bin/groff/devps/ZDR b/gnu/usr.bin/groff/devps/ZDR
new file mode 100644
index 0000000..3b7f0a6
--- /dev/null
+++ b/gnu/usr.bin/groff/devps/ZDR
@@ -0,0 +1,193 @@
+name ZDR
+internalname ZapfDingbats-Reverse
+special
+spacewidth 278
+charset
+space 278 0 0040
+--- 974,621 3 0041 a1
+--- 961,611 3 0042 a2
+--- 974,621 3 0043 a202
+--- 980,692 3 0044 a3
+--- 719,566 3 0045 a4
+--- 789,705,14 3 0046 a5
+--- 790,705,14 3 0047 a119
+--- 791,705,13 3 0050 a118
+--- 690,553 3 0051 a117
+--- 960,568 3 0052 a11
+lh 939,559 3 0053 a12
+--- 549,705,11 3 0054 a13
+--- 855,632 3 0055 a14
+--- 911,642 3 0056 a15
+--- 933,550 3 0057 a16
+--- 911,642 3 0060 a105
+--- 945,553 3 0061 a17
+--- 974,587 3 0062 a18
+--- 755,705,13 3 0063 a19
+--- 846,705,14 3 0064 a20
+--- 762,692 3 0065 a21
+--- 761,692 3 0066 a22
+--- 571,661,68 3 0067 a23
+--- 677,705,13 3 0070 a24
+--- 763,692 3 0071 a25
+--- 760,692 3 0072 a26
+--- 759,692 3 0073 a27
+--- 754,692 3 0074 a28
+--- 494,692 3 0075 a6
+--- 552,692 3 0076 a7
+--- 537,692 3 0077 a8
+--- 577,596 3 0100 a9
+--- 692,705,14 3 0101 a10
+--- 786,705,14 3 0102 a29
+--- 788,705,14 3 0103 a30
+--- 788,705,14 3 0104 a31
+--- 790,705,14 3 0105 a32
+--- 793,705,13 3 0106 a33
+--- 794,705,13 3 0107 a34
+--- 816,705,14 3 0110 a35
+--- 823,705,14 3 0111 a36
+--- 789,705,14 3 0112 a37
+--- 841,705,14 3 0113 a38
+--- 823,705,14 3 0114 a39
+--- 833,705,14 3 0115 a40
+--- 816,705,13 3 0116 a41
+--- 831,705,14 3 0117 a42
+--- 923,705,14 3 0120 a43
+--- 744,692 3 0121 a44
+--- 723,692 3 0122 a45
+--- 749,692 3 0123 a46
+--- 790,705,14 3 0124 a47
+--- 792,705,14 3 0125 a48
+--- 695,706,14 3 0126 a49
+--- 776,699,6 3 0127 a50
+--- 768,699,7 3 0130 a51
+--- 792,705,14 3 0131 a52
+--- 759,692 3 0132 a53
+--- 707,704,13 3 0133 a54
+--- 708,705,14 3 0134 a55
+--- 682,705,14 3 0135 a56
+--- 701,705,14 3 0136 a57
+--- 826,705,14 3 0137 a58
+--- 815,705,14 3 0140 a59
+--- 789,705,14 3 0141 a60
+--- 789,705,14 3 0142 a61
+--- 707,705,14 3 0143 a62
+--- 687,692 3 0144 a63
+--- 696,691 3 0145 a64
+--- 689,692 3 0146 a65
+--- 786,705,14 3 0147 a66
+--- 787,705,14 3 0150 a67
+--- 713,705,14 3 0151 a68
+--- 791,705,14 3 0152 a69
+--- 785,705,14 3 0153 a70
+--- 791,705,14 3 0154 a71
+--- 873,705,14 3 0155 a72
+--- 761,692 3 0156 a73
+--- 762,692 3 0157 a74
+--- 762,692 3 0160 a203
+--- 759,692 3 0161 a75
+--- 759,692 3 0162 a204
+--- 892,705 3 0163 a76
+--- 892,692,14 3 0164 a77
+--- 788,705,14 3 0165 a78
+--- 784,705,14 3 0166 a79
+--- 438,705,14 3 0167 a81
+--- 138,692 3 0170 a82
+--- 277,692 3 0171 a83
+--- 415,692 3 0172 a84
+--- 392,705 3 0173 a97
+--- 392,705 3 0174 a98
+--- 668,705 3 0175 a99
+--- 668,705 3 0176 a100
+--- 732,806,143 3 0241 a101
+--- 544,706,14 3 0242 a102
+--- 544,705,14 3 0243 a103
+--- 910,651 3 0244 a104
+--- 667,705,14 3 0245 a106
+--- 760,705,14 3 0246 a107
+--- 760,569 3 0247 a108
+--- 776,705 3 0250 a112
+--- 595,705,14 3 0251 a111
+--- 694,705,14 3 0252 a110
+--- 626,705 3 0253 a109
+--- 788,705,14 3 0254 a120
+--- 788,705,14 3 0255 a121
+--- 788,705,14 3 0256 a122
+--- 788,705,14 3 0257 a123
+--- 788,705,14 3 0260 a124
+--- 788,705,14 3 0261 a125
+--- 788,705,14 3 0262 a126
+--- 788,705,14 3 0263 a127
+--- 788,705,14 3 0264 a128
+--- 788,705,14 3 0265 a129
+--- 788,705,14 3 0266 a130
+--- 788,705,14 3 0267 a131
+--- 788,705,14 3 0270 a132
+--- 788,705,14 3 0271 a133
+--- 788,705,14 3 0272 a134
+--- 788,705,14 3 0273 a135
+--- 788,705,14 3 0274 a136
+--- 788,705,14 3 0275 a137
+--- 788,705,14 3 0276 a138
+--- 788,705,14 3 0277 a139
+--- 788,705,14 3 0300 a140
+--- 788,705,14 3 0301 a141
+--- 788,705,14 3 0302 a142
+--- 788,705,14 3 0303 a143
+--- 788,705,14 3 0304 a144
+--- 788,705,14 3 0305 a145
+--- 788,705,14 3 0306 a146
+--- 788,705,14 3 0307 a147
+--- 788,705,14 3 0310 a148
+--- 788,705,14 3 0311 a149
+--- 788,705,14 3 0312 a150
+--- 788,705,14 3 0313 a151
+--- 788,705,14 3 0314 a152
+--- 788,705,14 3 0315 a153
+--- 788,705,14 3 0316 a154
+--- 788,705,14 3 0317 a155
+--- 788,705,14 3 0320 a156
+--- 788,705,14 3 0321 a157
+--- 788,705,14 3 0322 a158
+--- 788,705,14 3 0323 a159
+--- 894,634 3 0324 a160
+--- 838,540 3 0325 a161
+--- 1016,540 3 0326 a163
+--- 458,820,127 3 0327 a164
+--- 748,597 3 0330 a196
+--- 924,552 3 0331 a165
+--- 748,597 3 0332 a192
+--- 918,526 3 0333 a166
+--- 927,660 3 0334 a167
+--- 928,562 3 0335 a168
+--- 928,563 3 0336 a169
+--- 834,537 3 0337 a170
+--- 873,599 3 0340 a171
+--- 828,588 3 0341 a172
+--- 924,594 3 0342 a173
+--- 924,594 3 0343 a162
+--- 917,692 3 0344 a174
+--- 930,608 3 0345 a175
+--- 931,608 3 0346 a176
+--- 463,791,99 3 0347 a177
+--- 883,623 3 0350 a178
+--- 836,648 3 0351 a179
+--- 836,648 3 0352 a193
+--- 867,591 3 0353 a180
+--- 867,591 3 0354 a199
+--- 696,648 3 0355 a181
+--- 696,648 3 0356 a200
+--- 874,619 3 0357 a182
+--- 874,615 3 0361 a201
+--- 760,692 3 0362 a183
+--- 946,533 3 0363 a184
+--- 771,655 3 0364 a197
+--- 865,481 3 0365 a185
+--- 771,655 3 0366 a194
+--- 888,712,19 3 0367 a198
+--- 967,568 3 0370 a186
+--- 888,712,19 3 0371 a195
+--- 831,579 3 0372 a187
+--- 873,578 3 0373 a188
+--- 927,542 3 0374 a189
+--- 970,616 3 0375 a190
+--- 918,593 3 0376 a191
diff --git a/gnu/usr.bin/groff/devps/download b/gnu/usr.bin/groff/devps/download
new file mode 100644
index 0000000..b98885c
--- /dev/null
+++ b/gnu/usr.bin/groff/devps/download
@@ -0,0 +1,5 @@
+# List of downloadable fonts
+# PostScript-name Filename
+
+Symbol-Slanted symbolsl.pfa
+ZapfDingbats-Reverse zapfdr.pfa
diff --git a/gnu/usr.bin/groff/devps/generate/Makefile b/gnu/usr.bin/groff/devps/generate/Makefile
new file mode 100644
index 0000000..3382cc6
--- /dev/null
+++ b/gnu/usr.bin/groff/devps/generate/Makefile
@@ -0,0 +1,224 @@
+#Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
+# Written by James Clark (jjc@jclark.com)
+#
+#This file is part of groff.
+#
+#groff is free software; you can redistribute it and/or modify it under
+#the terms of the GNU General Public License as published by the Free
+#Software Foundation; either version 2, or (at your option) any later
+#version.
+#
+#groff is distributed in the hope that it will be useful, but WITHOUT ANY
+#WARRANTY; without even the implied warranty of MERCHANTABILITY or
+#FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+#for more details.
+#
+#You should have received a copy of the GNU General Public License along
+#with groff; see the file COPYING. If not, write to the Free Software
+#Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+# This is set up so you can do
+# make -f generate/Makefile
+# in the parent directory of this directory.
+
+# Directory containing AFM files. Must not be current directory.
+# Either long names (eg Times-Roman.afm) or short names (eg timesr.afm)
+# may be used. See the afmname script.
+afmdir=/usr/local/afm
+srcdir=generate
+
+SPECIALFONTS=S
+DINGBATSFONTS=ZD ZDR
+GREEKFONTS=SS
+TEXTFONTS=AB ABI AI AR BMB BMBI BMI BMR CB CBI CI CR HB HBI HI HR HNB HNBI \
+ HNI HNR NB NBI NI NR PB PBI PI PR TB TBI TI TR ZCMI
+
+FONTS=$(TEXTFONTS) $(SPECIALFONTS) $(GREEKFONTS) $(DINGBATSFONTS)
+
+DESC=$(srcdir)/../DESC
+AFMTODIT=afmtodit -d$(DESC)
+IFLAG=-i 50
+NOLIGFLAG=-n
+TEXTENC=$(srcdir)/../text.enc
+EFLAG=-e $(TEXTENC)
+TEXTMAP=$(srcdir)/textmap
+SHELL=/bin/sh
+AFMNAME=$(SHELL) $(srcdir)/afmname
+
+all: $(FONTS)
+
+TR:
+ $(AFMTODIT) $(EFLAG) \
+ `$(AFMNAME) $(afmdir)/Times-Roman.afm` $(TEXTMAP) $@
+
+TB:
+ $(AFMTODIT) $(EFLAG) \
+ `$(AFMNAME) $(afmdir)/Times-Bold.afm` $(TEXTMAP) $@
+
+TI:
+ $(AFMTODIT) $(EFLAG) $(IFLAG) -a 7 \
+ `$(AFMNAME) $(afmdir)/Times-Italic.afm` $(TEXTMAP) $@
+
+TBI:
+ $(AFMTODIT) $(EFLAG) $(IFLAG) \
+ `$(AFMNAME) $(afmdir)/Times-BoldItalic.afm` $(TEXTMAP) $@
+
+HR:
+ $(AFMTODIT) $(EFLAG) \
+ `$(AFMNAME) $(afmdir)/Helvetica.afm` $(TEXTMAP) $@
+
+HB:
+ $(AFMTODIT) $(EFLAG) \
+ `$(AFMNAME) $(afmdir)/Helvetica-Bold.afm` $(TEXTMAP) $@
+
+HI:
+ $(AFMTODIT) $(EFLAG) $(IFLAG) \
+ `$(AFMNAME) $(afmdir)/Helvetica-Oblique.afm` $(TEXTMAP) $@
+
+HBI:
+ $(AFMTODIT) $(EFLAG) $(IFLAG) \
+ `$(AFMNAME) $(afmdir)/Helvetica-BoldOblique.afm` $(TEXTMAP) $@
+
+CR:
+ $(AFMTODIT) $(NOLIGFLAG) $(EFLAG) \
+ `$(AFMNAME) $(afmdir)/Courier.afm` $(TEXTMAP) $@
+
+CB:
+ $(AFMTODIT) $(NOLIGFLAG) $(EFLAG) \
+ `$(AFMNAME) $(afmdir)/Courier-Bold.afm` $(TEXTMAP) $@
+
+CI:
+ $(AFMTODIT) $(NOLIGFLAG) $(EFLAG) $(IFLAG) \
+ `$(AFMNAME) $(afmdir)/Courier-Oblique.afm` $(TEXTMAP) $@
+
+CBI:
+ $(AFMTODIT) $(NOLIGFLAG) $(EFLAG) $(IFLAG) \
+ `$(AFMNAME) $(afmdir)/Courier-BoldOblique.afm` $(TEXTMAP) $@
+
+PR:
+ $(AFMTODIT) $(EFLAG) \
+ `$(AFMNAME) $(afmdir)/Palatino-Roman.afm` $(TEXTMAP) $@
+
+PB:
+ $(AFMTODIT) $(EFLAG) \
+ `$(AFMNAME) $(afmdir)/Palatino-Bold.afm` $(TEXTMAP) $@
+
+PI:
+ $(AFMTODIT) $(EFLAG) $(IFLAG) \
+ `$(AFMNAME) $(afmdir)/Palatino-Italic.afm` $(TEXTMAP) $@
+
+PBI:
+ $(AFMTODIT) $(EFLAG) $(IFLAG) \
+ `$(AFMNAME) $(afmdir)/Palatino-BoldItalic.afm` $(TEXTMAP) $@
+
+NR:
+ $(AFMTODIT) $(EFLAG) \
+ `$(AFMNAME) $(afmdir)/NewCenturySchlbk-Roman.afm` $(TEXTMAP) $@
+
+NB:
+ $(AFMTODIT) $(EFLAG) \
+ `$(AFMNAME) $(afmdir)/NewCenturySchlbk-Bold.afm` $(TEXTMAP) $@
+
+NI:
+ $(AFMTODIT) $(EFLAG) $(IFLAG) \
+ `$(AFMNAME) $(afmdir)/NewCenturySchlbk-Italic.afm` $(TEXTMAP) $@
+
+NBI:
+ $(AFMTODIT) $(EFLAG) $(IFLAG) \
+ `$(AFMNAME) $(afmdir)/NewCenturySchlbk-BoldItalic.afm` $(TEXTMAP) $@
+
+BMR:
+ $(AFMTODIT) $(EFLAG) \
+ `$(AFMNAME) $(afmdir)/Bookman-Light.afm` $(TEXTMAP) $@
+
+BMB:
+ $(AFMTODIT) $(EFLAG) \
+ `$(AFMNAME) $(afmdir)/Bookman-Demi.afm` $(TEXTMAP) $@
+
+BMI:
+ $(AFMTODIT) $(EFLAG) $(IFLAG) \
+ `$(AFMNAME) $(afmdir)/Bookman-LightItalic.afm` $(TEXTMAP) $@
+
+BMBI:
+ $(AFMTODIT) $(EFLAG) $(IFLAG) \
+ `$(AFMNAME) $(afmdir)/Bookman-DemiItalic.afm` $(TEXTMAP) $@
+
+AR:
+ $(AFMTODIT) $(EFLAG) \
+ `$(AFMNAME) $(afmdir)/AvantGarde-Book.afm` $(TEXTMAP) $@
+
+AB:
+ $(AFMTODIT) $(EFLAG) \
+ `$(AFMNAME) $(afmdir)/AvantGarde-Demi.afm` $(TEXTMAP) $@
+
+AI:
+ $(AFMTODIT) $(EFLAG) $(IFLAG) \
+ `$(AFMNAME) $(afmdir)/AvantGarde-BookOblique.afm` $(TEXTMAP) $@
+
+ABI:
+ $(AFMTODIT) $(EFLAG) $(IFLAG) \
+ `$(AFMNAME) $(afmdir)/AvantGarde-DemiOblique.afm` $(TEXTMAP) $@
+
+HNR:
+ $(AFMTODIT) $(EFLAG) \
+ `$(AFMNAME) $(afmdir)/Helvetica-Narrow.afm` $(TEXTMAP) $@
+
+HNB:
+ $(AFMTODIT) $(EFLAG) \
+ `$(AFMNAME) $(afmdir)/Helvetica-Narrow-Bold.afm` $(TEXTMAP) $@
+
+HNI:
+ $(AFMTODIT) $(EFLAG) $(IFLAG) \
+ `$(AFMNAME) $(afmdir)/Helvetica-Narrow-Oblique.afm` $(TEXTMAP) $@
+
+HNBI:
+ $(AFMTODIT) $(EFLAG) $(IFLAG) \
+ `$(AFMNAME) $(afmdir)/Helvetica-Narrow-BoldOblique.afm` $(TEXTMAP) $@
+
+ZCMI:
+ $(AFMTODIT) $(EFLAG) $(IFLAG) \
+ `$(AFMNAME) $(afmdir)/ZapfChancery-MediumItalic.afm` $(TEXTMAP) $@
+
+ZD:
+ $(AFMTODIT) -s \
+ `$(AFMNAME) $(afmdir)/ZapfDingbats.afm` $(srcdir)/dingbatsmap $@
+
+SS: $(srcdir)/symbolsl.afm
+ $(AFMTODIT) -s $(IFLAG) $(srcdir)/symbolsl.afm $(srcdir)/lgreekmap $@
+
+S: symbol.afm
+ $(AFMTODIT) -s symbol.afm symbolmap $@
+
+ZDR: zapfdr.afm
+ $(AFMTODIT) -s zapfdr.afm $(srcdir)/dingbatsrmap $@
+
+symbol.afm: $(srcdir)/symbol.sed
+ -rm -f $@
+ sed -f $(srcdir)/symbol.sed `$(AFMNAME) $(afmdir)/Symbol.afm` >$@
+
+zapfdr.afm:
+ -rm -f $@
+ sed -e '/^FontName /s/ZapfDingbats/ZapfDingbats-Reverse/' \
+ `$(AFMNAME) $(afmdir)/ZapfDingbats.afm` >$@
+
+ZD: $(srcdir)/dingbatsmap
+ZDR: $(srcdir)/dingbatsrmap
+$(TEXTFONTS): $(TEXTMAP) $(TEXTENC)
+$(SPECIALFONTS): symbolmap
+$(GREEKFONTS): $(srcdir)/lgreekmap
+$(FONTS): $(DESC)
+
+symbolmap: $(TEXTMAP) $(srcdir)/symbolchars
+ cat $(TEXTMAP) $(srcdir)/symbolchars >$@
+
+clean:
+ -rm -f symbolmap symbol.afm zapfdr.afm
+
+realclean: clean
+ -rm -f $(FONTS)
+
+extraclean: realclean
+ -rm -f core *~ \#*
+
+.PHONY: all clean realclean extraclean
+
diff --git a/gnu/usr.bin/groff/devps/generate/afmname b/gnu/usr.bin/groff/devps/generate/afmname
new file mode 100755
index 0000000..8503d46
--- /dev/null
+++ b/gnu/usr.bin/groff/devps/generate/afmname
@@ -0,0 +1,44 @@
+#!/bin/sh
+# Fix the path name of an AFM file.
+if test -f "$1"
+then
+ echo "$1"
+else
+ echo `dirname $1`/`basename $1 .afm | awk -e '
+/^AvantGarde-Book$/ { print "avangbk" }
+/^AvantGarde-BookOblique$/ { print "avangbko" }
+/^AvantGarde-Demi$/ { print "avangd" }
+/^AvantGarde-DemiOblique$/ { print "avangdo" }
+/^Bookman-Demi$/ { print "bookmd" }
+/^Bookman-DemiItalic$/ { print "bookmdi" }
+/^Bookman-Light$/ { print "bookml" }
+/^Bookman-LightItalic$/ { print "bookmli" }
+/^Courier$/ { print "couri" }
+/^Courier-Bold$/ { print "courib" }
+/^Courier-BoldOblique$/ { print "couribo" }
+/^Courier-Oblique$/ { print "courio" }
+/^Helvetica$/ { print "helve" }
+/^Helvetica-Bold$/ { print "helveb" }
+/^Helvetica-BoldOblique$/ { print "helvebo" }
+/^Helvetica-Narrow$/ { print "helven" }
+/^Helvetica-Narrow-Bold$/ { print "helvenb" }
+/^Helvetica-Narrow-BoldOblique$/ { print "helvenbo" }
+/^Helvetica-Narrow-Oblique$/ { print "helveno" }
+/^Helvetica-Oblique$/ { print "helveo" }
+/^NewCenturySchlbk-Bold$/ { print "newcsb" }
+/^NewCenturySchlbk-BoldItalic$/ { print "newcsbi" }
+/^NewCenturySchlbk-Italic$/ { print "newcsi" }
+/^NewCenturySchlbk-Roman$/ { print "newcsr" }
+/^Palatino-Bold$/ { print "palatb" }
+/^Palatino-BoldItalic$/ { print "palatbi" }
+/^Palatino-Italic$/ { print "palati" }
+/^Palatino-Roman$/ { print "palatr" }
+/^Symbol$/ { print "symbol" }
+/^Times-Bold$/ { print "timesb" }
+/^Times-BoldItalic$/ { print "timesbi" }
+/^Times-Italic$/ { print "timesi" }
+/^Times-Roman$/ { print "timesr" }
+/^ZapfChancery-MediumItalic$/ { print "zapfcmi" }
+/^ZapfDingbats$/ { print "zapfd" }
+' `.afm
+fi
diff --git a/gnu/usr.bin/groff/devps/generate/dingbatsmap b/gnu/usr.bin/groff/devps/generate/dingbatsmap
new file mode 100644
index 0000000..3a97fa9
--- /dev/null
+++ b/gnu/usr.bin/groff/devps/generate/dingbatsmap
@@ -0,0 +1,2 @@
+a19 OK
+a12 rh
diff --git a/gnu/usr.bin/groff/devps/generate/dingbatsrmap b/gnu/usr.bin/groff/devps/generate/dingbatsrmap
new file mode 100644
index 0000000..ccc14cb
--- /dev/null
+++ b/gnu/usr.bin/groff/devps/generate/dingbatsrmap
@@ -0,0 +1 @@
+a12 lh
diff --git a/gnu/usr.bin/groff/devps/generate/lgreekmap b/gnu/usr.bin/groff/devps/generate/lgreekmap
new file mode 100644
index 0000000..0b0c197
--- /dev/null
+++ b/gnu/usr.bin/groff/devps/generate/lgreekmap
@@ -0,0 +1,28 @@
+alpha *a
+beta *b
+chi *x
+delta *d
+epsilon *e
+eta *y
+gamma *g
+iota *i
+kappa *k
+lambda *l
+mu *m
+nu *n
+omega *w
+omega1 +p
+omicron *o
+phi *f
+phi1 +f
+pi *p
+psi *q
+rho *r
+sigma *s
+tau *t
+theta *h
+theta1 +h
+upsilon *u
+xi *c
+zeta *z
+sigma1 ts
diff --git a/gnu/usr.bin/groff/devps/generate/symbol.sed b/gnu/usr.bin/groff/devps/generate/symbol.sed
new file mode 100644
index 0000000..b4b02ab
--- /dev/null
+++ b/gnu/usr.bin/groff/devps/generate/symbol.sed
@@ -0,0 +1,33 @@
+#! /bin/sed -f
+# Tweak the AFM file for the Symbol font.
+/^C .*[ ;]N bracketlefttp[ ;]/bx
+/^C .*[ ;]N bracketleftex[ ;]/bx
+/^C .*[ ;]N bracketleftbt[ ;]/bx
+/^C .*[ ;]N bracketrighttp[ ;]/bx
+/^C .*[ ;]N bracketrightex[ ;]/bx
+/^C .*[ ;]N bracketrightbt[ ;]/bx
+/^C .*[ ;]N bracelefttp[ ;]/bx
+/^C .*[ ;]N braceleftmid[ ;]/bx
+/^C .*[ ;]N braceleftbt[ ;]/bx
+/^C .*[ ;]N bracerighttp[ ;]/bx
+/^C .*[ ;]N bracerightmid[ ;]/bx
+/^C .*[ ;]N bracerightbt[ ;]/bx
+/^C .*[ ;]N braceex[ ;]/bx
+/^C .*[ ;]N parenleftex[ ;]/by
+/^C .*[ ;]N parenrightex[ ;]/by
+/^C .*[ ;]N parenleftbt[ ;]/bz
+/^C .*[ ;]N parenrightbt[ ;]/bz
+/^EndCharMetrics/a\
+italicCorrection integral 67\
+leftItalicCorrection integral 52\
+subscriptCorrection integral -10
+b
+:x
+s/B \([-0-9][0-9]*\) [-0-9][0-9]* \([-0-9][0-9]*\) [-0-9][0-9]*/B \1 -75 \2 925/
+b
+:y
+s/B \([-0-9][0-9]*\) [-0-9][0-9]* \([-0-9][0-9]*\) [-0-9][0-9]*/B \1 -80 \2 920/
+b
+:z
+s/B \([-0-9][0-9]*\) \([-0-9][0-9]*\) \([-0-9][0-9]*\) [-0-9][0-9]*/B \1 \2 \3 920/
+b
diff --git a/gnu/usr.bin/groff/devps/generate/symbolchars b/gnu/usr.bin/groff/devps/generate/symbolchars
new file mode 100644
index 0000000..41ec3e4
--- /dev/null
+++ b/gnu/usr.bin/groff/devps/generate/symbolchars
@@ -0,0 +1,60 @@
+plus pl
+minus mi
+plusminus +-
+equal eq
+divide di
+multiply mu
+arrowup arrowverttp
+arrowdown arrowvertbt
+Alpha *A
+Beta *B
+Chi *X
+Delta *D
+Epsilon *E
+Eta *Y
+Gamma *G
+Iota *I
+Kappa *K
+Lambda *L
+Mu *M
+Nu *N
+Omega *W
+Omicron *O
+Phi *F
+Pi *P
+Psi *Q
+Rho *R
+Sigma *S
+Tau *T
+Theta *H
+Upsilon1 *U
+Xi *C
+Zeta *Z
+alpha *a
+beta *b
+chi *x
+delta *d
+epsilon *e
+eta *y
+gamma *g
+iota *i
+kappa *k
+lambda *l
+mu *m
+nu *n
+omega *w
+omega1 +p
+omicron *o
+phi *f
+phi1 +f
+pi *p
+psi *q
+rho *r
+sigma *s
+sigma1 ts
+tau *t
+theta *h
+theta1 +h
+upsilon *u
+xi *c
+zeta *z
diff --git a/gnu/usr.bin/groff/devps/generate/symbolsl.afm b/gnu/usr.bin/groff/devps/generate/symbolsl.afm
new file mode 100644
index 0000000..90939ad
--- /dev/null
+++ b/gnu/usr.bin/groff/devps/generate/symbolsl.afm
@@ -0,0 +1,203 @@
+StartFontMetrics 2.0
+FontName Symbol-Slanted
+Version 001.001
+FamilyName Symbol
+ItalicAngle -15.5
+IsFixedPitch false
+UnderlineThickness 54
+Weight Medium
+UnderlinePosition -98
+FullName Symbol
+FontBBox -241 -261 1250 899
+StartCharMetrics 189
+C 32 ; WX 223 ; N space ; B 223 0 223 0 ;
+C 33 ; WX 296 ; N exclam ; B 122 -15 383 599 ;
+C 34 ; WX 635 ; N universal ; B 223 0 801 627 ;
+C 35 ; WX 445 ; N numbersign ; B 71 -15 557 599 ;
+C 36 ; WX 489 ; N existential ; B 22 0 622 629 ;
+C 37 ; WX 741 ; N percent ; B 147 -32 766 583 ;
+C 38 ; WX 692 ; N ampersand ; B 68 -16 745 589 ;
+C 39 ; WX 391 ; N suchthat ; B 44 -15 450 444 ;
+C 40 ; WX 296 ; N parenleft ; B 89 -170 449 599 ;
+C 41 ; WX 296 ; N parenright ; B -22 -170 339 600 ;
+C 42 ; WX 445 ; N asteriskmath ; B 126 119 500 490 ;
+C 43 ; WX 489 ; N plus ; B 76 0 562 474 ;
+C 44 ; WX 223 ; N comma ; B 9 -136 183 93 ;
+C 45 ; WX 489 ; N minus ; B 74 207 556 256 ;
+C 46 ; WX 223 ; N period ; B 70 -15 174 85 ;
+C 47 ; WX 247 ; N slash ; B -5 -15 405 575 ;
+C 48 ; WX 445 ; N zero ; B 90 -15 537 610 ;
+C 49 ; WX 445 ; N one ; B 107 0 451 599 ;
+C 50 ; WX 445 ; N two ; B 22 0 524 611 ;
+C 51 ; WX 445 ; N three ; B 56 -16 510 611 ;
+C 52 ; WX 445 ; N four ; B 58 0 530 610 ;
+C 53 ; WX 445 ; N five ; B 36 -15 583 610 ;
+C 54 ; WX 445 ; N six ; B 87 -16 588 610 ;
+C 55 ; WX 445 ; N seven ; B 151 -15 585 599 ;
+C 56 ; WX 445 ; N eight ; B 82 -16 536 611 ;
+C 57 ; WX 445 ; N nine ; B 52 -15 535 609 ;
+C 58 ; WX 247 ; N colon ; B 81 -15 286 409 ;
+C 59 ; WX 247 ; N semicolon ; B 33 -136 296 409 ;
+C 60 ; WX 489 ; N less ; B 87 0 610 464 ;
+C 61 ; WX 489 ; N equal ; B 49 126 586 347 ;
+C 62 ; WX 489 ; N greater ; B 23 0 547 464 ;
+C 63 ; WX 395 ; N question ; B 163 -15 517 610 ;
+C 64 ; WX 489 ; N congruent ; B 10 0 597 423 ;
+C 65 ; WX 643 ; N Alpha ; B 3 0 614 599 ;
+C 66 ; WX 594 ; N Beta ; B 26 0 645 598 ;
+C 67 ; WX 643 ; N Chi ; B -8 0 798 599 ;
+C 68 ; WX 545 ; N Delta ; B 5 0 541 612 ;
+C 69 ; WX 544 ; N Epsilon ; B 28 0 688 599 ;
+C 70 ; WX 679 ; N Phi ; B 105 0 761 598 ;
+C 71 ; WX 537 ; N Gamma ; B 31 0 714 599 ;
+C 72 ; WX 643 ; N Eta ; B 35 0 836 599 ;
+C 73 ; WX 296 ; N Iota ; B 28 0 468 599 ;
+C 74 ; WX 562 ; N theta1 ; B 108 -15 645 614 ;
+C 75 ; WX 643 ; N Kappa ; B 31 0 778 598 ;
+C 76 ; WX 611 ; N Lambda ; B 5 0 610 612 ;
+C 77 ; WX 791 ; N Mu ; B 28 0 974 599 ;
+C 78 ; WX 643 ; N Nu ; B 26 -7 827 599 ;
+C 79 ; WX 643 ; N Omicron ; B 112 -15 747 610 ;
+C 80 ; WX 684 ; N Pi ; B 22 0 847 599 ;
+C 81 ; WX 659 ; N Theta ; B 112 -15 747 610 ;
+C 82 ; WX 495 ; N Rho ; B 25 0 645 599 ;
+C 83 ; WX 527 ; N Sigma ; B 5 0 663 599 ;
+C 84 ; WX 544 ; N Tau ; B 159 0 723 599 ;
+C 85 ; WX 614 ; N Upsilon ; B 175 0 804 599 ;
+C 86 ; WX 391 ; N sigma1 ; B 78 -208 492 445 ;
+C 87 ; WX 684 ; N Omega ; B 30 0 760 612 ;
+C 88 ; WX 574 ; N Xi ; B 36 0 700 598 ;
+C 89 ; WX 708 ; N Psi ; B 188 0 885 608 ;
+C 90 ; WX 544 ; N Zeta ; B 39 0 725 599 ;
+C 91 ; WX 296 ; N bracketleft ; B 34 -138 453 599 ;
+C 92 ; WX 768 ; N therefore ; B 160 0 645 426 ;
+C 93 ; WX 296 ; N bracketright ; B -14 -138 405 599 ;
+C 94 ; WX 586 ; N perpendicular ; B 13 0 596 600 ;
+C 95 ; WX 445 ; N underscore ; B -72 -224 390 -183 ;
+C 96 ; WX 445 ; N radicalex ; B 672 784 1224 816 ;
+C 97 ; WX 562 ; N alpha ; B 84 -15 658 445 ;
+C 98 ; WX 489 ; N beta ; B -7 -198 578 659 ;
+C 99 ; WX 489 ; N chi ; B -48 -206 573 445 ;
+C 100 ; WX 440 ; N delta ; B 83 -16 571 658 ;
+C 101 ; WX 391 ; N epsilon ; B 49 -17 468 447 ;
+C 102 ; WX 464 ; N phi ; B 78 -200 517 596 ;
+C 103 ; WX 366 ; N gamma ; B 92 -200 568 444 ;
+C 104 ; WX 537 ; N eta ; B 100 -180 555 457 ;
+C 105 ; WX 293 ; N iota ; B 97 -16 296 448 ;
+C 106 ; WX 537 ; N phi1 ; B 92 -199 604 444 ;
+C 107 ; WX 489 ; N kappa ; B 106 0 621 447 ;
+C 108 ; WX 489 ; N lambda ; B 21 -16 530 658 ;
+C 109 ; WX 513 ; N mu ; B -18 -198 533 445 ;
+C 110 ; WX 464 ; N nu ; B 119 -15 548 451 ;
+C 111 ; WX 489 ; N omicron ; B 86 -17 526 444 ;
+C 112 ; WX 489 ; N pi ; B 58 -18 599 433 ;
+C 113 ; WX 464 ; N theta ; B 103 -16 554 614 ;
+C 114 ; WX 489 ; N rho ; B -19 -205 521 444 ;
+C 115 ; WX 537 ; N sigma ; B 87 -19 662 445 ;
+C 116 ; WX 391 ; N tau ; B 95 -16 511 445 ;
+C 117 ; WX 513 ; N upsilon ; B 105 -15 558 451 ;
+C 118 ; WX 635 ; N omega1 ; B 78 -15 758 519 ;
+C 119 ; WX 611 ; N omega ; B 85 -16 687 445 ;
+C 120 ; WX 439 ; N xi ; B 70 -200 515 681 ;
+C 121 ; WX 611 ; N psi ; B 141 -203 759 445 ;
+C 122 ; WX 440 ; N zeta ; B 100 -200 580 673 ;
+C 123 ; WX 427 ; N braceleft ; B 116 -163 540 599 ;
+C 124 ; WX 178 ; N bar ; B 9 -158 307 599 ;
+C 125 ; WX 427 ; N braceright ; B 19 -163 444 599 ;
+C 126 ; WX 489 ; N similar ; B 78 181 549 273 ;
+C 161 ; WX 552 ; N Upsilon1 ; B 134 0 710 609 ;
+C 162 ; WX 220 ; N minute ; B 156 408 393 654 ;
+C 163 ; WX 489 ; N lessequal ; B 26 0 645 569 ;
+C 164 ; WX 149 ; N fraction ; B -164 -11 490 603 ;
+C 165 ; WX 635 ; N infinity ; B 91 111 692 360 ;
+C 166 ; WX 445 ; N florin ; B -36 -172 614 612 ;
+C 167 ; WX 670 ; N club ; B 119 -23 645 474 ;
+C 168 ; WX 670 ; N diamond ; B 198 -32 605 490 ;
+C 169 ; WX 670 ; N heart ; B 205 -29 679 473 ;
+C 170 ; WX 670 ; N spade ; B 132 -32 604 488 ;
+C 171 ; WX 927 ; N arrowboth ; B 90 -13 980 455 ;
+C 172 ; WX 878 ; N arrowleft ; B 97 -13 915 455 ;
+C 173 ; WX 537 ; N arrowup ; B 223 0 691 810 ;
+C 174 ; WX 878 ; N arrowright ; B 105 -13 922 455 ;
+C 175 ; WX 537 ; N arrowdown ; B 104 -20 572 790 ;
+C 176 ; WX 356 ; N degree ; B 187 343 466 609 ;
+C 177 ; WX 489 ; N plusminus ; B 9 0 593 574 ;
+C 178 ; WX 366 ; N second ; B 150 408 560 656 ;
+C 179 ; WX 489 ; N greaterequal ; B 26 0 582 569 ;
+C 180 ; WX 489 ; N multiply ; B 28 7 609 466 ;
+C 181 ; WX 635 ; N proportional ; B 90 110 667 360 ;
+C 182 ; WX 440 ; N partialdiff ; B 62 -18 542 664 ;
+C 183 ; WX 409 ; N bullet ; B 118 101 454 421 ;
+C 184 ; WX 489 ; N divide ; B 74 63 558 406 ;
+C 185 ; WX 489 ; N notequal ; B 51 -22 587 489 ;
+C 186 ; WX 489 ; N equivalence ; B 35 73 602 394 ;
+C 187 ; WX 489 ; N approxequal ; B 57 120 572 351 ;
+C 188 ; WX 890 ; N ellipsis ; B 107 -15 804 85 ;
+C 189 ; WX 537 ; N arrowvertex ; B 216 -107 579 899 ;
+C 190 ; WX 890 ; N arrowhorizex ; B 8 196 1011 246 ;
+C 191 ; WX 586 ; N carriagereturn ; B 40 -14 710 560 ;
+C 192 ; WX 732 ; N aleph ; B 159 -16 740 586 ;
+C 193 ; WX 611 ; N Ifraktur ; B 26 -47 684 659 ;
+C 194 ; WX 708 ; N Rfraktur ; B 71 -13 833 653 ;
+C 195 ; WX 878 ; N weierstrass ; B 112 -188 878 510 ;
+C 196 ; WX 684 ; N circlemultiply ; B 114 -15 758 599 ;
+C 197 ; WX 684 ; N circleplus ; B 115 -13 759 601 ;
+C 198 ; WX 732 ; N emptyset ; B 38 -21 884 640 ;
+C 199 ; WX 684 ; N intersection ; B 36 0 714 453 ;
+C 200 ; WX 684 ; N union ; B 110 -15 788 438 ;
+C 201 ; WX 635 ; N propersuperset ; B 18 0 675 418 ;
+C 202 ; WX 635 ; N reflexsuperset ; B -17 -111 674 418 ;
+C 203 ; WX 635 ; N notsubset ; B 87 -62 744 481 ;
+C 204 ; WX 635 ; N propersubset ; B 87 0 744 418 ;
+C 205 ; WX 635 ; N reflexsubset ; B 16 -111 744 418 ;
+C 206 ; WX 635 ; N element ; B 93 0 579 417 ;
+C 207 ; WX 635 ; N notelement ; B 74 -52 579 494 ;
+C 208 ; WX 684 ; N angle ; B 23 0 833 599 ;
+C 209 ; WX 635 ; N gradient ; B 231 -17 805 639 ;
+C 210 ; WX 703 ; N registerserif ; B 120 -18 763 596 ;
+C 211 ; WX 703 ; N copyrightserif ; B 122 -13 766 601 ;
+C 212 ; WX 792 ; N trademarkserif ; B 169 261 947 599 ;
+C 213 ; WX 732 ; N product ; B -6 -90 920 668 ;
+C 214 ; WX 489 ; N radical ; B 134 -34 711 816 ;
+C 215 ; WX 223 ; N dotmath ; B 131 187 225 276 ;
+C 216 ; WX 635 ; N logicalnot ; B 78 0 685 256 ;
+C 217 ; WX 537 ; N logicaland ; B 21 0 519 404 ;
+C 218 ; WX 537 ; N logicalor ; B 151 0 639 424 ;
+C 219 ; WX 927 ; N arrowdblboth ; B 92 -18 978 454 ;
+C 220 ; WX 878 ; N arrowdblleft ; B 96 -13 942 457 ;
+C 221 ; WX 537 ; N arrowdblup ; B 152 2 688 811 ;
+C 222 ; WX 878 ; N arrowdblright ; B 71 -18 917 452 ;
+C 223 ; WX 537 ; N arrowdbldown ; B 103 -17 639 792 ;
+C 224 ; WX 440 ; N lozenge ; B 121 0 519 663 ;
+C 225 ; WX 293 ; N angleleft ; B 98 -176 472 664 ;
+C 226 ; WX 703 ; N registersans ; B 120 -18 763 596 ;
+C 227 ; WX 703 ; N copyrightsans ; B 120 -13 764 601 ;
+C 228 ; WX 700 ; N trademarksans ; B 179 261 832 599 ;
+C 229 ; WX 635 ; N summation ; B -15 -96 756 669 ;
+C 230 ; WX 342 ; N parenlefttp ; B -46 -261 642 824 ;
+C 231 ; WX 342 ; N parenleftex ; B 12 -76 338 823 ;
+C 232 ; WX 342 ; N parenleftbt ; B 113 -261 339 824 ;
+C 233 ; WX 342 ; N bracketlefttp ; B -22 -71 560 824 ;
+C 234 ; WX 342 ; N bracketleftex ; B -22 -70 305 823 ;
+C 235 ; WX 342 ; N bracketleftbt ; B -22 -71 306 824 ;
+C 236 ; WX 440 ; N bracelefttp ; B 158 -67 648 824 ;
+C 237 ; WX 440 ; N braceleftmid ; B 126 -76 486 832 ;
+C 238 ; WX 440 ; N braceleftbt ; B 219 -62 484 824 ;
+C 239 ; WX 440 ; N braceex ; B 157 -71 486 832 ;
+C 241 ; WX 293 ; N angleright ; B -29 -176 345 664 ;
+C 242 ; WX 244 ; N integral ; B -13 -95 499 815 ;
+C 243 ; WX 611 ; N integraltp ; B 272 -74 873 820 ;
+C 244 ; WX 611 ; N integralex ; B 271 -78 640 868 ;
+C 245 ; WX 611 ; N integralbt ; B 30 -72 625 820 ;
+C 246 ; WX 342 ; N parenrighttp ; B 273 -261 498 824 ;
+C 247 ; WX 342 ; N parenrightex ; B 331 -76 657 823 ;
+C 248 ; WX 342 ; N parenrightbt ; B -30 -261 657 824 ;
+C 249 ; WX 342 ; N bracketrighttp ; B 249 -71 577 824 ;
+C 250 ; WX 342 ; N bracketrightex ; B 250 -70 577 823 ;
+C 251 ; WX 342 ; N bracketrightbt ; B -4 -71 577 824 ;
+C 252 ; WX 440 ; N bracerighttp ; B 158 -67 425 824 ;
+C 253 ; WX 440 ; N bracerightmid ; B 155 -76 517 832 ;
+C 254 ; WX 440 ; N bracerightbt ; B -4 -62 484 824 ;
+C -1 ; WX 703 ; N apple ; B 136 -2 784 719 ;
+EndCharMetrics
+EndFontMetrics
diff --git a/gnu/usr.bin/groff/devps/generate/textmap b/gnu/usr.bin/groff/devps/generate/textmap
new file mode 100644
index 0000000..a4b51a3
--- /dev/null
+++ b/gnu/usr.bin/groff/devps/generate/textmap
@@ -0,0 +1,449 @@
+a a
+b b
+c c
+d d
+e e
+f f
+g g
+h h
+i i
+j j
+k k
+l l
+m m
+n n
+o o
+p p
+q q
+r r
+s s
+t t
+u u
+v v
+w w
+x x
+y y
+z z
+A A
+B B
+C C
+D D
+E E
+F F
+G G
+H H
+I I
+J J
+K K
+L L
+M M
+N N
+O O
+P P
+Q Q
+R R
+S S
+T T
+U U
+V V
+W W
+X X
+Y Y
+Z Z
+AE AE
+Aacute 'A
+Acircumflex ^A
+Adieresis :A
+Agrave `A
+Aring oA
+Atilde ~A
+Cacute 'C
+Ccedilla ,C
+Eacute 'E
+Ecircumflex ^E
+Edieresis :E
+Egrave `E
+Eth -D
+IJ IJ
+Iacute 'I
+Icircumflex ^I
+Idieresis :I
+Ifraktur Im
+Igrave `I
+Lslash /L
+Ntilde ~N
+OE OE
+Oacute 'O
+Ocircumflex ^O
+Odieresis :O
+Ograve `O
+Oslash /O
+Otilde ~O
+Rfraktur Re
+Scaron vS
+Thorn TP
+Uacute 'U
+Ucircumflex ^U
+Udieresis :U
+Ugrave `U
+Yacute 'Y
+Ydieresis :Y
+Zcaron vZ
+aacute 'a
+acircumflex ^a
+acute aa
+adieresis :a
+ae ae
+agrave `a
+angle /_
+angleleft la
+angleright ra
+aleph Ah
+ampersand &
+approxequal ~~
+aring oa
+arrowboth <>
+arrowdblboth hA
+arrowdbldown dA
+arrowdblleft lA
+arrowdblright rA
+arrowdblup uA
+arrowdown da
+arrowleft <-
+arrowright ->
+arrowup ua
+asciicircum ha
+asciitilde ti
+asterisk *
+asteriskmath **
+at @
+at at
+atilde ~a
+backslash \
+backslash rs
+bar ba
+bar |
+bell bs
+braceleft lC
+braceleft {
+braceright rC
+braceright }
+bracketleft [
+bracketleft lB
+bracketright ]
+bracketright rB
+breve ab
+brokenbar bb
+bullet bu
+cacute 'c
+caron ah
+ccedilla ,c
+cedilla ac
+cent ct
+checkmark OK
+circle ci
+circlemultiply c*
+circleplus c+
+circumflex a^
+circumflex ^
+colon :
+comma ,
+congruent =~
+copyright co
+currency Cs
+dagger dg
+daggerdbl dd
+degree de
+dieresis ad
+dollar $
+dollar Do
+dotaccent a.
+dotlessi .i
+dotlessj .j
+dotmath md
+eacute 'e
+ecircumflex ^e
+edieresis :e
+egrave `e
+eight 8
+element mo
+emdash em
+emptyset es
+endash en
+equal =
+equalmath eq
+equivalence ==
+eth Sd
+exclam !
+exclamdown r!
+existential te
+ff ff
+ffi Fi
+ffl Fl
+fi fi
+five 5
+fl fl
+florin Fn
+four 4
+germandbls ss
+gradient gr
+grave ga
+greater >
+greaterequal >=
+guillemotleft Fo
+guillemotright Fc
+guilsinglleft fo
+guilsinglright fc
+handleft lh
+handright rh
+hbar -h
+hungarumlaut a"
+hyphen -
+hyphen hy
+iacute 'i
+icircumflex ^i
+idieresis :i
+igrave `i
+ij ij
+infinity if
+integral is
+intersection ca
+less <
+lessequal <=
+logicaland AN
+logicalnot no
+logicalor OR
+lozenge lz
+lslash /l
+macron a-
+minus \-
+minusplus -+
+minute fm
+nine 9
+notelement nm
+notequal !=
+notequivalence ne
+notpropersuperset nc
+ntilde ~n
+numbersign #
+numbersign sh
+oacute 'o
+ocircumflex ^o
+odieresis :o
+oe oe
+ogonek ho
+ograve `o
+one 1
+onehalf 12
+onequarter 14
+onesuperior S1
+ordfeminine Of
+ordmasculine Om
+oslash /o
+otilde ~o
+paragraph ps
+parenleft (
+parenright )
+partialdiff pd
+percent %
+period .
+perthousand %0
+perpendicular pp
+plus +
+plusmath pl
+propersubset sb
+propersuperset sp
+proportional pt
+question ?
+questiondown r?
+quotedbl "
+quotedblbase Bq
+quotedblleft lq
+quotedblright rq
+quoteleft `
+quoteleft oq
+quoteright '
+quotesingle aq
+quotesinglbase bq
+reflexsubset ib
+reflexsuperset ip
+registered rg
+ring ao
+scaron vs
+second sd
+section sc
+semicolon ;
+seven 7
+similar ap
+similarequal ~=
+six 6
+slash /
+slash sl
+square sq
+sterling Po
+therefore 3d
+therefore tf
+thorn Tp
+three 3
+threequarters 34
+threesuperior S3
+tilde a~
+tilde ~
+trademark tm
+two 2
+twosuperior S2
+uacute 'u
+ucircumflex ^u
+udieresis :u
+ugrave `u
+underscore _
+union cu
+universal fa
+weierstrass wp
+yacute 'y
+ydieresis :y
+yen Ye
+zcaron vz
+zero 0
+exclamdown char161
+cent char162
+sterling char163
+currency char164
+yen char165
+brokenbar char166
+section char167
+dieresis char168
+copyright char169
+ordfeminine char170
+guillemotleft char171
+logicalnot char172
+hyphen char173
+registered char174
+macron char175
+degree char176
+plusminus char177
+twosuperior char178
+threesuperior char179
+acute char180
+mu char181
+paragraph char182
+periodcentered char183
+cedilla char184
+onesuperior char185
+ordmasculine char186
+guillemotright char187
+onequarter char188
+onehalf char189
+threequarters char190
+questiondown char191
+Agrave char192
+Aacute char193
+Acircumflex char194
+Atilde char195
+Adieresis char196
+Aring char197
+AE char198
+Ccedilla char199
+Egrave char200
+Eacute char201
+Ecircumflex char202
+Edieresis char203
+Igrave char204
+Iacute char205
+Icircumflex char206
+Idieresis char207
+Eth char208
+Ntilde char209
+Ograve char210
+Oacute char211
+Ocircumflex char212
+Otilde char213
+Odieresis char214
+multiply char215
+Oslash char216
+Ugrave char217
+Uacute char218
+Ucircumflex char219
+Udieresis char220
+Yacute char221
+Thorn char222
+germandbls char223
+agrave char224
+aacute char225
+acircumflex char226
+atilde char227
+adieresis char228
+aring char229
+ae char230
+ccedilla char231
+egrave char232
+eacute char233
+ecircumflex char234
+edieresis char235
+igrave char236
+iacute char237
+icircumflex char238
+idieresis char239
+eth char240
+ntilde char241
+ograve char242
+oacute char243
+ocircumflex char244
+otilde char245
+odieresis char246
+divide char247
+oslash char248
+ugrave char249
+uacute char250
+ucircumflex char251
+udieresis char252
+yacute char253
+thorn char254
+ydieresis char255
+fraction f/
+club CL
+diamond DI
+heart HE
+spade SP
+carriagereturn CR
+suchthat st
+bracelefttp bracelefttp
+braceleftmid braceleftmid
+braceleftbt braceleftbt
+braceex braceex
+braceex bracerightex
+braceex braceleftex
+braceex barex
+bracerighttp bracerighttp
+bracerightmid bracerightmid
+bracerightbt bracerightbt
+parenlefttp parenlefttp
+parenleftbt parenleftbt
+parenleftex parenleftex
+parenrighttp parenrighttp
+parenrightbt parenrightbt
+parenrightex parenrightex
+bracketlefttp bracketlefttp
+bracketleftbt bracketleftbt
+bracketleftex bracketleftex
+bracketrighttp bracketrighttp
+bracketrightbt bracketrightbt
+bracketrightex bracketrightex
+radical sr
+radicalex radicalex
+approxequal ~=
+bracketlefttp lc
+bracketleftbt lf
+bracketrighttp rc
+bracketrightbt rf
+bracelefttp lt
+braceleftmid lk
+braceleftbt lb
+braceex bv
+bracerighttp rt
+bracerightmid rk
+bracerightbt rb
+summation sum
+product product
+arrowvertex arrowvertex
+arrowhorizex an
diff --git a/gnu/usr.bin/groff/devps/prologue.ps b/gnu/usr.bin/groff/devps/prologue.ps
new file mode 100644
index 0000000..3c238bc
--- /dev/null
+++ b/gnu/usr.bin/groff/devps/prologue.ps
@@ -0,0 +1,221 @@
+%!PS-Adobe-3.0 Resource-ProcSet
+
+/setpacking where {
+ pop
+ currentpacking
+ true setpacking
+} if
+
+/grops 120 dict dup begin
+
+% The ASCII code of the space character.
+/SC 32 def
+
+/A /show load def
+/B { 0 SC 3 -1 roll widthshow } bind def
+/C { 0 exch ashow } bind def
+/D { 0 exch 0 SC 5 2 roll awidthshow } bind def
+/E { 0 rmoveto show } bind def
+/F { 0 rmoveto 0 SC 3 -1 roll widthshow } bind def
+/G { 0 rmoveto 0 exch ashow } bind def
+/H { 0 rmoveto 0 exch 0 SC 5 2 roll awidthshow } bind def
+/I { 0 exch rmoveto show } bind def
+/J { 0 exch rmoveto 0 SC 3 -1 roll widthshow } bind def
+/K { 0 exch rmoveto 0 exch ashow } bind def
+/L { 0 exch rmoveto 0 exch 0 SC 5 2 roll awidthshow } bind def
+/M { rmoveto show } bind def
+/N { rmoveto 0 SC 3 -1 roll widthshow } bind def
+/O { rmoveto 0 exch ashow } bind def
+/P { rmoveto 0 exch 0 SC 5 2 roll awidthshow } bind def
+/Q { moveto show } bind def
+/R { moveto 0 SC 3 -1 roll widthshow } bind def
+/S { moveto 0 exch ashow } bind def
+/T { moveto 0 exch 0 SC 5 2 roll awidthshow } bind def
+
+% name size font SF -
+
+/SF {
+ findfont exch
+ [ exch dup 0 exch 0 exch neg 0 0 ] makefont
+ dup setfont
+ [ exch /setfont cvx ] cvx bind def
+} bind def
+
+% name a c d font MF -
+
+/MF {
+ findfont
+ [ 5 2 roll
+ 0 3 1 roll % b
+ neg 0 0 ] makefont
+ dup setfont
+ [ exch /setfont cvx ] cvx bind def
+} bind def
+
+/level0 0 def
+/RES 0 def
+/PL 0 def
+/LS 0 def
+
+% Guess the page length.
+% This assumes that the imageable area is vertically centered on the page.
+% PLG - length
+
+/PLG {
+ gsave newpath clippath pathbbox grestore
+ exch pop add exch pop
+} bind def
+
+% BP -
+
+/BP {
+ /level0 save def
+ 1 setlinecap
+ 1 setlinejoin
+ 72 RES div dup scale
+ LS {
+ 90 rotate
+ } {
+ 0 PL translate
+ } ifelse
+ 1 -1 scale
+} bind def
+
+/EP {
+ level0 restore
+ showpage
+} bind def
+
+
+% centerx centery radius startangle endangle DA -
+
+/DA {
+ newpath arcn stroke
+} bind def
+
+% x y SN - x' y'
+% round a position to nearest (pixel + (.25,.25))
+
+/SN {
+ transform
+ .25 sub exch .25 sub exch
+ round .25 add exch round .25 add exch
+ itransform
+} bind def
+
+% endx endy startx starty DL -
+% we round the endpoints of the line, so that parallel horizontal
+% and vertical lines will appear even
+
+/DL {
+ SN
+ moveto
+ SN
+ lineto stroke
+} bind def
+
+% centerx centery radius DC -
+
+/DC {
+ newpath 0 360 arc closepath
+} bind def
+
+
+/TM matrix def
+
+% width height centerx centery DE -
+
+/DE {
+ TM currentmatrix pop
+ translate scale newpath 0 0 .5 0 360 arc closepath
+ TM setmatrix
+} bind def
+
+% these are for splines
+
+/RC /rcurveto load def
+/RL /rlineto load def
+/ST /stroke load def
+/MT /moveto load def
+/CL /closepath load def
+
+% fill the last path
+
+% amount FL -
+
+/FL {
+ currentgray exch setgray fill setgray
+} bind def
+
+% fill with the ``current color''
+
+/BL /fill load def
+
+/LW /setlinewidth load def
+% new_font_name encoding_vector old_font_name RE -
+
+/RE {
+ findfont
+ dup maxlength 1 index /FontName known not { 1 add } if dict begin
+ {
+ 1 index /FID ne { def } { pop pop } ifelse
+ } forall
+ /Encoding exch def
+ dup /FontName exch def
+ currentdict end definefont pop
+} bind def
+
+/DEFS 0 def
+
+% hpos vpos EBEGIN -
+
+/EBEGIN {
+ moveto
+ DEFS begin
+} bind def
+
+/EEND /end load def
+
+/CNT 0 def
+/level1 0 def
+
+% llx lly newwid wid newht ht newllx newlly PBEGIN -
+
+/PBEGIN {
+ /level1 save def
+ translate
+ div 3 1 roll div exch scale
+ neg exch neg exch translate
+ % set the graphics state to default values
+ 0 setgray
+ 0 setlinecap
+ 1 setlinewidth
+ 0 setlinejoin
+ 10 setmiterlimit
+ [] 0 setdash
+ /setstrokeadjust where {
+ pop
+ false setstrokeadjust
+ } if
+ /setoverprint where {
+ pop
+ false setoverprint
+ } if
+ newpath
+ /CNT countdictstack def
+ userdict begin
+ /showpage {} def
+} bind def
+
+/PEND {
+ clear
+ countdictstack CNT sub { end } repeat
+ level1 restore
+} bind def
+
+end def
+
+/setpacking where {
+ pop
+ setpacking
+} if
diff --git a/gnu/usr.bin/groff/devps/psstrip.sed b/gnu/usr.bin/groff/devps/psstrip.sed
new file mode 100644
index 0000000..8c9e90c
--- /dev/null
+++ b/gnu/usr.bin/groff/devps/psstrip.sed
@@ -0,0 +1,6 @@
+/^%[%!]/b
+s/^[ ][ ]*//
+s/[ ][ ]*$//
+s/%.*//
+/^$/d
+s|[ ]*\([][}{/]\)[ ]*|\1|g
diff --git a/gnu/usr.bin/groff/devps/symbol.afm b/gnu/usr.bin/groff/devps/symbol.afm
new file mode 100644
index 0000000..eccf6c2
--- /dev/null
+++ b/gnu/usr.bin/groff/devps/symbol.afm
@@ -0,0 +1,215 @@
+(c) 1987, 1988, 1989, 1990, 1991 Adobe Systems Incorporated.
+All rights reserved.
+
+StartFontMetrics 2.0
+Comment Copyright (c) 1985, 1987, 1989, 1990 Adobe Systems Incorporated. All rights reserved.
+Comment Creation Date: Wed Jan 17 21:48:26 1990
+Comment UniqueID 27004
+Comment VMusage 28489 37622
+FontName Symbol
+FullName Symbol
+FamilyName Symbol
+Weight Medium
+ItalicAngle 0
+IsFixedPitch false
+FontBBox -180 -293 1090 1010
+UnderlinePosition -98
+UnderlineThickness 54
+Version 001.007
+Notice Copyright (c) 1985, 1987, 1989, 1990 Adobe Systems Incorporated. All rights reserved.
+EncodingScheme FontSpecific
+StartCharMetrics 189
+C 32 ; WX 250 ; N space ; B 0 0 0 0 ;
+C 33 ; WX 333 ; N exclam ; B 128 -17 240 672 ;
+C 34 ; WX 713 ; N universal ; B 31 0 681 705 ;
+C 35 ; WX 500 ; N numbersign ; B 20 -16 481 673 ;
+C 36 ; WX 549 ; N existential ; B 25 0 478 707 ;
+C 37 ; WX 833 ; N percent ; B 63 -36 771 655 ;
+C 38 ; WX 778 ; N ampersand ; B 41 -18 750 661 ;
+C 39 ; WX 439 ; N suchthat ; B 48 -17 414 500 ;
+C 40 ; WX 333 ; N parenleft ; B 53 -191 300 673 ;
+C 41 ; WX 333 ; N parenright ; B 30 -191 277 673 ;
+C 42 ; WX 500 ; N asteriskmath ; B 65 134 427 551 ;
+C 43 ; WX 549 ; N plus ; B 10 0 539 533 ;
+C 44 ; WX 250 ; N comma ; B 56 -152 194 104 ;
+C 45 ; WX 549 ; N minus ; B 11 233 535 288 ;
+C 46 ; WX 250 ; N period ; B 69 -17 181 95 ;
+C 47 ; WX 278 ; N slash ; B 0 -18 254 646 ;
+C 48 ; WX 500 ; N zero ; B 23 -17 471 685 ;
+C 49 ; WX 500 ; N one ; B 117 0 390 673 ;
+C 50 ; WX 500 ; N two ; B 25 0 475 686 ;
+C 51 ; WX 500 ; N three ; B 39 -17 435 685 ;
+C 52 ; WX 500 ; N four ; B 16 0 469 685 ;
+C 53 ; WX 500 ; N five ; B 29 -17 443 685 ;
+C 54 ; WX 500 ; N six ; B 36 -17 467 685 ;
+C 55 ; WX 500 ; N seven ; B 24 -16 448 673 ;
+C 56 ; WX 500 ; N eight ; B 54 -18 440 685 ;
+C 57 ; WX 500 ; N nine ; B 31 -18 460 685 ;
+C 58 ; WX 278 ; N colon ; B 81 -17 193 460 ;
+C 59 ; WX 278 ; N semicolon ; B 83 -152 221 460 ;
+C 60 ; WX 549 ; N less ; B 26 0 523 522 ;
+C 61 ; WX 549 ; N equal ; B 11 141 537 390 ;
+C 62 ; WX 549 ; N greater ; B 26 0 523 522 ;
+C 63 ; WX 444 ; N question ; B 70 -17 412 686 ;
+C 64 ; WX 549 ; N congruent ; B 11 0 537 475 ;
+C 65 ; WX 722 ; N Alpha ; B 4 0 684 673 ;
+C 66 ; WX 667 ; N Beta ; B 29 0 592 673 ;
+C 67 ; WX 722 ; N Chi ; B -9 0 704 673 ;
+C 68 ; WX 612 ; N Delta ; B 6 0 608 688 ;
+C 69 ; WX 611 ; N Epsilon ; B 32 0 617 673 ;
+C 70 ; WX 763 ; N Phi ; B 26 0 741 673 ;
+C 71 ; WX 603 ; N Gamma ; B 24 0 609 673 ;
+C 72 ; WX 722 ; N Eta ; B 39 0 729 673 ;
+C 73 ; WX 333 ; N Iota ; B 32 0 316 673 ;
+C 74 ; WX 631 ; N theta1 ; B 18 -18 623 689 ;
+C 75 ; WX 722 ; N Kappa ; B 35 0 722 673 ;
+C 76 ; WX 686 ; N Lambda ; B 6 0 680 688 ;
+C 77 ; WX 889 ; N Mu ; B 28 0 887 673 ;
+C 78 ; WX 722 ; N Nu ; B 29 -8 720 673 ;
+C 79 ; WX 722 ; N Omicron ; B 41 -17 715 685 ;
+C 80 ; WX 768 ; N Pi ; B 25 0 745 673 ;
+C 81 ; WX 741 ; N Theta ; B 41 -17 715 685 ;
+C 82 ; WX 556 ; N Rho ; B 28 0 563 673 ;
+C 83 ; WX 592 ; N Sigma ; B 5 0 589 673 ;
+C 84 ; WX 611 ; N Tau ; B 33 0 607 673 ;
+C 85 ; WX 690 ; N Upsilon ; B -8 0 694 673 ;
+C 86 ; WX 439 ; N sigma1 ; B 40 -233 436 500 ;
+C 87 ; WX 768 ; N Omega ; B 34 0 736 688 ;
+C 88 ; WX 645 ; N Xi ; B 40 0 599 673 ;
+C 89 ; WX 795 ; N Psi ; B 15 0 781 684 ;
+C 90 ; WX 611 ; N Zeta ; B 44 0 636 673 ;
+C 91 ; WX 333 ; N bracketleft ; B 86 -155 299 674 ;
+C 92 ; WX 863 ; N therefore ; B 163 0 701 478 ;
+C 93 ; WX 333 ; N bracketright ; B 33 -155 246 674 ;
+C 94 ; WX 658 ; N perpendicular ; B 15 0 652 674 ;
+C 95 ; WX 500 ; N underscore ; B -2 -252 502 -206 ;
+C 96 ; WX 500 ; N radicalex ; B 480 881 1090 917 ;
+C 97 ; WX 631 ; N alpha ; B 41 -18 622 500 ;
+C 98 ; WX 549 ; N beta ; B 61 -223 515 741 ;
+C 99 ; WX 549 ; N chi ; B 12 -231 522 499 ;
+C 100 ; WX 494 ; N delta ; B 40 -19 481 740 ;
+C 101 ; WX 439 ; N epsilon ; B 22 -19 427 502 ;
+C 102 ; WX 521 ; N phi ; B 27 -224 490 671 ;
+C 103 ; WX 411 ; N gamma ; B 5 -225 484 499 ;
+C 104 ; WX 603 ; N eta ; B 0 -202 527 514 ;
+C 105 ; WX 329 ; N iota ; B 0 -17 301 503 ;
+C 106 ; WX 603 ; N phi1 ; B 36 -224 587 499 ;
+C 107 ; WX 549 ; N kappa ; B 33 0 558 501 ;
+C 108 ; WX 549 ; N lambda ; B 24 -17 548 739 ;
+C 109 ; WX 576 ; N mu ; B 33 -223 567 500 ;
+C 110 ; WX 521 ; N nu ; B -9 -16 475 507 ;
+C 111 ; WX 549 ; N omicron ; B 35 -19 501 499 ;
+C 112 ; WX 549 ; N pi ; B 10 -19 530 487 ;
+C 113 ; WX 521 ; N theta ; B 43 -17 485 690 ;
+C 114 ; WX 549 ; N rho ; B 50 -230 490 499 ;
+C 115 ; WX 603 ; N sigma ; B 30 -21 588 500 ;
+C 116 ; WX 439 ; N tau ; B 10 -19 418 500 ;
+C 117 ; WX 576 ; N upsilon ; B 7 -18 535 507 ;
+C 118 ; WX 713 ; N omega1 ; B 12 -18 671 583 ;
+C 119 ; WX 686 ; N omega ; B 42 -17 684 500 ;
+C 120 ; WX 493 ; N xi ; B 27 -224 469 766 ;
+C 121 ; WX 686 ; N psi ; B 12 -228 701 500 ;
+C 122 ; WX 494 ; N zeta ; B 60 -225 467 756 ;
+C 123 ; WX 480 ; N braceleft ; B 58 -183 397 673 ;
+C 124 ; WX 200 ; N bar ; B 65 -177 135 673 ;
+C 125 ; WX 480 ; N braceright ; B 79 -183 418 673 ;
+C 126 ; WX 549 ; N similar ; B 17 203 529 307 ;
+C 161 ; WX 620 ; N Upsilon1 ; B -2 0 610 685 ;
+C 162 ; WX 247 ; N minute ; B 27 459 228 735 ;
+C 163 ; WX 549 ; N lessequal ; B 29 0 526 639 ;
+C 164 ; WX 167 ; N fraction ; B -180 -12 340 677 ;
+C 165 ; WX 713 ; N infinity ; B 26 124 688 404 ;
+C 166 ; WX 500 ; N florin ; B 2 -193 494 686 ;
+C 167 ; WX 753 ; N club ; B 86 -26 660 533 ;
+C 168 ; WX 753 ; N diamond ; B 142 -36 600 550 ;
+C 169 ; WX 753 ; N heart ; B 117 -33 631 532 ;
+C 170 ; WX 753 ; N spade ; B 113 -36 629 548 ;
+C 171 ; WX 1042 ; N arrowboth ; B 24 -15 1024 511 ;
+C 172 ; WX 987 ; N arrowleft ; B 32 -15 942 511 ;
+C 173 ; WX 603 ; N arrowup ; B 45 0 571 910 ;
+C 174 ; WX 987 ; N arrowright ; B 49 -15 959 511 ;
+C 175 ; WX 603 ; N arrowdown ; B 45 -22 571 888 ;
+C 176 ; WX 400 ; N degree ; B 50 385 350 685 ;
+C 177 ; WX 549 ; N plusminus ; B 10 0 539 645 ;
+C 178 ; WX 411 ; N second ; B 20 459 413 737 ;
+C 179 ; WX 549 ; N greaterequal ; B 29 0 526 639 ;
+C 180 ; WX 549 ; N multiply ; B 17 8 533 524 ;
+C 181 ; WX 713 ; N proportional ; B 27 123 639 404 ;
+C 182 ; WX 494 ; N partialdiff ; B 26 -20 462 746 ;
+C 183 ; WX 460 ; N bullet ; B 50 113 410 473 ;
+C 184 ; WX 549 ; N divide ; B 10 71 536 456 ;
+C 185 ; WX 549 ; N notequal ; B 15 -25 540 549 ;
+C 186 ; WX 549 ; N equivalence ; B 14 82 538 443 ;
+C 187 ; WX 549 ; N approxequal ; B 14 135 527 394 ;
+C 188 ; WX 1000 ; N ellipsis ; B 111 -17 889 95 ;
+C 189 ; WX 603 ; N arrowvertex ; B 280 -120 336 1010 ;
+C 190 ; WX 1000 ; N arrowhorizex ; B -60 220 1050 276 ;
+C 191 ; WX 658 ; N carriagereturn ; B 15 -16 602 629 ;
+C 192 ; WX 823 ; N aleph ; B 175 -18 661 658 ;
+C 193 ; WX 686 ; N Ifraktur ; B 10 -53 578 740 ;
+C 194 ; WX 795 ; N Rfraktur ; B 26 -15 759 734 ;
+C 195 ; WX 987 ; N weierstrass ; B 159 -211 870 573 ;
+C 196 ; WX 768 ; N circlemultiply ; B 43 -17 733 673 ;
+C 197 ; WX 768 ; N circleplus ; B 43 -15 733 675 ;
+C 198 ; WX 823 ; N emptyset ; B 39 -24 781 719 ;
+C 199 ; WX 768 ; N intersection ; B 40 0 732 509 ;
+C 200 ; WX 768 ; N union ; B 40 -17 732 492 ;
+C 201 ; WX 713 ; N propersuperset ; B 20 0 673 470 ;
+C 202 ; WX 713 ; N reflexsuperset ; B 20 -125 673 470 ;
+C 203 ; WX 713 ; N notsubset ; B 36 -70 690 540 ;
+C 204 ; WX 713 ; N propersubset ; B 37 0 690 470 ;
+C 205 ; WX 713 ; N reflexsubset ; B 37 -125 690 470 ;
+C 206 ; WX 713 ; N element ; B 45 0 505 468 ;
+C 207 ; WX 713 ; N notelement ; B 45 -58 505 555 ;
+C 208 ; WX 768 ; N angle ; B 26 0 738 673 ;
+C 209 ; WX 713 ; N gradient ; B 36 -19 681 718 ;
+C 210 ; WX 790 ; N registerserif ; B 50 -17 740 673 ;
+C 211 ; WX 790 ; N copyrightserif ; B 51 -15 741 675 ;
+C 212 ; WX 890 ; N trademarkserif ; B 18 293 855 673 ;
+C 213 ; WX 823 ; N product ; B 25 -101 803 751 ;
+C 214 ; WX 549 ; N radical ; B 10 -38 515 917 ;
+C 215 ; WX 250 ; N dotmath ; B 69 210 169 310 ;
+C 216 ; WX 713 ; N logicalnot ; B 15 0 680 288 ;
+C 217 ; WX 603 ; N logicaland ; B 23 0 583 454 ;
+C 218 ; WX 603 ; N logicalor ; B 30 0 578 477 ;
+C 219 ; WX 1042 ; N arrowdblboth ; B 27 -20 1023 510 ;
+C 220 ; WX 987 ; N arrowdblleft ; B 30 -15 939 513 ;
+C 221 ; WX 603 ; N arrowdblup ; B 39 2 567 911 ;
+C 222 ; WX 987 ; N arrowdblright ; B 45 -20 954 508 ;
+C 223 ; WX 603 ; N arrowdbldown ; B 44 -19 572 890 ;
+C 224 ; WX 494 ; N lozenge ; B 18 0 466 745 ;
+C 225 ; WX 329 ; N angleleft ; B 25 -198 306 746 ;
+C 226 ; WX 790 ; N registersans ; B 50 -20 740 670 ;
+C 227 ; WX 790 ; N copyrightsans ; B 49 -15 739 675 ;
+C 228 ; WX 786 ; N trademarksans ; B 5 293 725 673 ;
+C 229 ; WX 713 ; N summation ; B 14 -108 695 752 ;
+C 230 ; WX 384 ; N parenlefttp ; B 40 -293 436 926 ;
+C 231 ; WX 384 ; N parenleftex ; B 40 -80 92 920 ;
+C 232 ; WX 384 ; N parenleftbt ; B 40 -293 436 920 ;
+C 233 ; WX 384 ; N bracketlefttp ; B 0 -75 341 925 ;
+C 234 ; WX 384 ; N bracketleftex ; B 0 -75 55 925 ;
+C 235 ; WX 384 ; N bracketleftbt ; B 0 -75 340 925 ;
+C 236 ; WX 494 ; N bracelefttp ; B 201 -75 439 925 ;
+C 237 ; WX 494 ; N braceleftmid ; B 14 -75 255 925 ;
+C 238 ; WX 494 ; N braceleftbt ; B 201 -75 439 925 ;
+C 239 ; WX 494 ; N braceex ; B 201 -75 255 925 ;
+C 241 ; WX 329 ; N angleright ; B 21 -198 302 746 ;
+C 242 ; WX 274 ; N integral ; B 2 -107 291 916 ;
+C 243 ; WX 686 ; N integraltp ; B 332 -83 715 921 ;
+C 244 ; WX 686 ; N integralex ; B 332 -88 415 975 ;
+C 245 ; WX 686 ; N integralbt ; B 39 -81 415 921 ;
+C 246 ; WX 384 ; N parenrighttp ; B 54 -293 450 926 ;
+C 247 ; WX 384 ; N parenrightex ; B 398 -80 450 920 ;
+C 248 ; WX 384 ; N parenrightbt ; B 54 -293 450 920 ;
+C 249 ; WX 384 ; N bracketrighttp ; B 22 -75 360 925 ;
+C 250 ; WX 384 ; N bracketrightex ; B 305 -75 360 925 ;
+C 251 ; WX 384 ; N bracketrightbt ; B 20 -75 360 925 ;
+C 252 ; WX 494 ; N bracerighttp ; B 17 -75 255 925 ;
+C 253 ; WX 494 ; N bracerightmid ; B 201 -75 442 925 ;
+C 254 ; WX 494 ; N bracerightbt ; B 17 -75 255 925 ;
+C -1 ; WX 790 ; N apple ; B 56 -3 733 808 ;
+EndCharMetrics
+italicCorrection integral 67
+leftItalicCorrection integral 52
+subscriptCorrection integral -10
+EndFontMetrics
diff --git a/gnu/usr.bin/groff/devps/symbolmap b/gnu/usr.bin/groff/devps/symbolmap
new file mode 100644
index 0000000..63e9c06
--- /dev/null
+++ b/gnu/usr.bin/groff/devps/symbolmap
@@ -0,0 +1,508 @@
+a a
+b b
+c c
+d d
+e e
+f f
+g g
+h h
+i i
+j j
+k k
+l l
+m m
+n n
+o o
+p p
+q q
+r r
+s s
+t t
+u u
+v v
+w w
+x x
+y y
+z z
+A A
+B B
+C C
+D D
+E E
+F F
+G G
+H H
+I I
+J J
+K K
+L L
+M M
+N N
+O O
+P P
+Q Q
+R R
+S S
+T T
+U U
+V V
+W W
+X X
+Y Y
+Z Z
+AE AE
+Aacute 'A
+Acircumflex ^A
+Adieresis :A
+Agrave `A
+Aring oA
+Atilde ~A
+Cacute 'C
+Ccedilla ,C
+Eacute 'E
+Ecircumflex ^E
+Edieresis :E
+Egrave `E
+Eth -D
+IJ IJ
+Iacute 'I
+Icircumflex ^I
+Idieresis :I
+Ifraktur Im
+Igrave `I
+Lslash /L
+Ntilde ~N
+OE OE
+Oacute 'O
+Ocircumflex ^O
+Odieresis :O
+Ograve `O
+Oslash /O
+Otilde ~O
+Rfraktur Re
+Scaron vS
+Thorn TP
+Uacute 'U
+Ucircumflex ^U
+Udieresis :U
+Ugrave `U
+Yacute 'Y
+Ydieresis :Y
+Zcaron vZ
+aacute 'a
+acircumflex ^a
+acute aa
+adieresis :a
+ae ae
+agrave `a
+angle /_
+angleleft la
+angleright ra
+aleph Ah
+ampersand &
+approxequal ~~
+aring oa
+arrowboth <>
+arrowdblboth hA
+arrowdbldown dA
+arrowdblleft lA
+arrowdblright rA
+arrowdblup uA
+arrowdown da
+arrowleft <-
+arrowright ->
+arrowup ua
+asciicircum ha
+asciitilde ti
+asterisk *
+asteriskmath **
+at @
+at at
+atilde ~a
+backslash \
+backslash rs
+bar ba
+bar |
+bell bs
+braceleft lC
+braceleft {
+braceright rC
+braceright }
+bracketleft [
+bracketleft lB
+bracketright ]
+bracketright rB
+breve ab
+brokenbar bb
+bullet bu
+cacute 'c
+caron ah
+ccedilla ,c
+cedilla ac
+cent ct
+checkmark OK
+circle ci
+circlemultiply c*
+circleplus c+
+circumflex a^
+circumflex ^
+colon :
+comma ,
+congruent =~
+copyright co
+currency Cs
+dagger dg
+daggerdbl dd
+degree de
+dieresis ad
+dollar $
+dollar Do
+dotaccent a.
+dotlessi .i
+dotlessj .j
+dotmath md
+eacute 'e
+ecircumflex ^e
+edieresis :e
+egrave `e
+eight 8
+element mo
+emdash em
+emptyset es
+endash en
+equal =
+equalmath eq
+equivalence ==
+eth Sd
+exclam !
+exclamdown r!
+existential te
+ff ff
+ffi Fi
+ffl Fl
+fi fi
+five 5
+fl fl
+florin Fn
+four 4
+germandbls ss
+gradient gr
+grave ga
+greater >
+greaterequal >=
+guillemotleft Fo
+guillemotright Fc
+guilsinglleft fo
+guilsinglright fc
+handleft lh
+handright rh
+hbar -h
+hungarumlaut a"
+hyphen -
+hyphen hy
+iacute 'i
+icircumflex ^i
+idieresis :i
+igrave `i
+ij ij
+infinity if
+integral is
+intersection ca
+less <
+lessequal <=
+logicaland AN
+logicalnot no
+logicalor OR
+lozenge lz
+lslash /l
+macron a-
+minus \-
+minusplus -+
+minute fm
+nine 9
+notelement nm
+notequal !=
+notequivalence ne
+notpropersuperset nc
+ntilde ~n
+numbersign #
+numbersign sh
+oacute 'o
+ocircumflex ^o
+odieresis :o
+oe oe
+ogonek ho
+ograve `o
+one 1
+onehalf 12
+onequarter 14
+onesuperior S1
+ordfeminine Of
+ordmasculine Om
+oslash /o
+otilde ~o
+paragraph ps
+parenleft (
+parenright )
+partialdiff pd
+percent %
+period .
+perthousand %0
+perpendicular pp
+plus +
+plusmath pl
+propersubset sb
+propersuperset sp
+proportional pt
+question ?
+questiondown r?
+quotedbl "
+quotedblbase Bq
+quotedblleft lq
+quotedblright rq
+quoteleft `
+quoteleft oq
+quoteright '
+quotesingle aq
+quotesinglbase bq
+reflexsubset ib
+reflexsuperset ip
+registered rg
+ring ao
+scaron vs
+second sd
+section sc
+semicolon ;
+seven 7
+similar ap
+similarequal ~=
+six 6
+slash /
+slash sl
+square sq
+sterling Po
+therefore 3d
+therefore tf
+thorn Tp
+three 3
+threequarters 34
+threesuperior S3
+tilde a~
+tilde ~
+trademark tm
+two 2
+twosuperior S2
+uacute 'u
+ucircumflex ^u
+udieresis :u
+ugrave `u
+underscore _
+union cu
+universal fa
+weierstrass wp
+yacute 'y
+ydieresis :y
+yen Ye
+zcaron vz
+zero 0
+exclamdown char161
+cent char162
+sterling char163
+currency char164
+yen char165
+brokenbar char166
+section char167
+dieresis char168
+copyright char169
+ordfeminine char170
+guillemotleft char171
+logicalnot char172
+hyphen char173
+registered char174
+macron char175
+degree char176
+plusminus char177
+twosuperior char178
+threesuperior char179
+acute char180
+mu char181
+paragraph char182
+periodcentered char183
+cedilla char184
+onesuperior char185
+ordmasculine char186
+guillemotright char187
+onequarter char188
+onehalf char189
+threequarters char190
+questiondown char191
+Agrave char192
+Aacute char193
+Acircumflex char194
+Atilde char195
+Adieresis char196
+Aring char197
+AE char198
+Ccedilla char199
+Egrave char200
+Eacute char201
+Ecircumflex char202
+Edieresis char203
+Igrave char204
+Iacute char205
+Icircumflex char206
+Idieresis char207
+Eth char208
+Ntilde char209
+Ograve char210
+Oacute char211
+Ocircumflex char212
+Otilde char213
+Odieresis char214
+multiply char215
+Oslash char216
+Ugrave char217
+Uacute char218
+Ucircumflex char219
+Udieresis char220
+Yacute char221
+Thorn char222
+germandbls char223
+agrave char224
+aacute char225
+acircumflex char226
+atilde char227
+adieresis char228
+aring char229
+ae char230
+ccedilla char231
+egrave char232
+eacute char233
+ecircumflex char234
+edieresis char235
+igrave char236
+iacute char237
+icircumflex char238
+idieresis char239
+eth char240
+ntilde char241
+ograve char242
+oacute char243
+ocircumflex char244
+otilde char245
+odieresis char246
+divide char247
+oslash char248
+ugrave char249
+uacute char250
+ucircumflex char251
+udieresis char252
+yacute char253
+thorn char254
+ydieresis char255
+fraction f/
+club CL
+diamond DI
+heart HE
+spade SP
+carriagereturn CR
+suchthat st
+bracelefttp bracelefttp
+braceleftmid braceleftmid
+braceleftbt braceleftbt
+braceex braceex
+braceex bracerightex
+braceex braceleftex
+braceex barex
+bracerighttp bracerighttp
+bracerightmid bracerightmid
+bracerightbt bracerightbt
+parenlefttp parenlefttp
+parenleftbt parenleftbt
+parenleftex parenleftex
+parenrighttp parenrighttp
+parenrightbt parenrightbt
+parenrightex parenrightex
+bracketlefttp bracketlefttp
+bracketleftbt bracketleftbt
+bracketleftex bracketleftex
+bracketrighttp bracketrighttp
+bracketrightbt bracketrightbt
+bracketrightex bracketrightex
+radical sr
+radicalex rn
+approxequal ~=
+bracketlefttp lc
+bracketleftbt lf
+bracketrighttp rc
+bracketrightbt rf
+bracelefttp lt
+braceleftmid lk
+braceleftbt lb
+braceex bv
+bracerighttp rt
+bracerightmid rk
+bracerightbt rb
+summation sum
+product product
+arrowvertex arrowvertex
+plus pl
+minus mi
+plusminus +-
+equal eq
+divide di
+multiply mu
+arrowup arrowverttp
+arrowdown arrowvertbt
+Alpha *A
+Beta *B
+Chi *X
+Delta *D
+Epsilon *E
+Eta *Y
+Gamma *G
+Iota *I
+Kappa *K
+Lambda *L
+Mu *M
+Nu *N
+Omega *W
+Omicron *O
+Phi *F
+Pi *P
+Psi *Q
+Rho *R
+Sigma *S
+Tau *T
+Theta *H
+Upsilon1 *U
+Xi *C
+Zeta *Z
+alpha *a
+beta *b
+chi *x
+delta *d
+epsilon *e
+eta *y
+gamma *g
+iota *i
+kappa *k
+lambda *l
+mu *m
+nu *n
+omega *w
+omega1 +p
+omicron *o
+phi *f
+phi1 +f
+pi *p
+psi *q
+rho *r
+sigma *s
+sigma1 ts
+tau *t
+theta *h
+theta1 +h
+upsilon *u
+xi *c
+zeta *z
diff --git a/gnu/usr.bin/groff/devps/symbolsl.ps b/gnu/usr.bin/groff/devps/symbolsl.ps
new file mode 100644
index 0000000..d384203
--- /dev/null
+++ b/gnu/usr.bin/groff/devps/symbolsl.ps
@@ -0,0 +1,41 @@
+%!PS-Adobe-3.0 Resource-Font
+%%DocumentNeededResources: font Symbol
+
+% newfontname matrix oldfontname MakeTransformedFont
+
+/MakeTransformedFont {
+ findfont dup maxlength dict begin
+ {
+ exch dup dup /FID ne exch /UniqueID ne and {
+ exch def
+ } {
+ pop pop
+ } ifelse
+ } forall
+ % first copy FontBBox
+ /FontBBox
+ % FontBBox sometimes seems to have the executable
+ % attribute set
+ % so to get the array on the stack, we have to do this
+ currentdict /FontBBox get
+ 4 array copy def
+ % now transform it
+ FontBBox aload pop
+ 4 index transform 4 2 roll
+ 4 index transform 4 2 roll
+ FontBBox astore pop
+ % matrix
+ % now transform FontMatrix
+ FontMatrix exch matrix concatmatrix
+ /FontMatrix exch def
+ dup /FontName exch def
+ currentdict end
+ definefont pop
+} bind def
+
+%%IncludeResource: font Symbol
+
+/Symbol-Slanted
+[.89 0.0 15.5 dup sin exch cos div .89 0.0 0.0]
+/Symbol
+MakeTransformedFont
diff --git a/gnu/usr.bin/groff/devps/text.enc b/gnu/usr.bin/groff/devps/text.enc
new file mode 100644
index 0000000..dde5bb7
--- /dev/null
+++ b/gnu/usr.bin/groff/devps/text.enc
@@ -0,0 +1,231 @@
+asciicircum 0
+asciitilde 1
+Scaron 2
+Zcaron 3
+scaron 4
+zcaron 5
+Ydieresis 6
+trademark 7
+quotesingle 8
+space 32
+exclam 33
+quotedbl 34
+numbersign 35
+dollar 36
+percent 37
+ampersand 38
+quoteright 39
+parenleft 40
+parenright 41
+asterisk 42
+plus 43
+comma 44
+hyphen 45
+period 46
+slash 47
+zero 48
+one 49
+two 50
+three 51
+four 52
+five 53
+six 54
+seven 55
+eight 56
+nine 57
+colon 58
+semicolon 59
+less 60
+equal 61
+greater 62
+question 63
+at 64
+A 65
+B 66
+C 67
+D 68
+E 69
+F 70
+G 71
+H 72
+I 73
+J 74
+K 75
+L 76
+M 77
+N 78
+O 79
+P 80
+Q 81
+R 82
+S 83
+T 84
+U 85
+V 86
+W 87
+X 88
+Y 89
+Z 90
+bracketleft 91
+backslash 92
+bracketright 93
+circumflex 94
+underscore 95
+quoteleft 96
+a 97
+b 98
+c 99
+d 100
+e 101
+f 102
+g 103
+h 104
+i 105
+j 106
+k 107
+l 108
+m 109
+n 110
+o 111
+p 112
+q 113
+r 114
+s 115
+t 116
+u 117
+v 118
+w 119
+x 120
+y 121
+z 122
+braceleft 123
+bar 124
+braceright 125
+tilde 126
+quotesinglbase 128
+guillemotleft 129
+guillemotright 130
+bullet 131
+florin 132
+fraction 133
+perthousand 134
+dagger 135
+daggerdbl 136
+endash 137
+emdash 138
+ff 139
+fi 140
+fl 141
+ffi 142
+ffl 143
+dotlessi 144
+dotlessj 145
+grave 146
+hungarumlaut 147
+dotaccent 148
+breve 149
+caron 150
+ring 151
+ogonek 152
+quotedblleft 153
+quotedblright 154
+oe 155
+lslash 156
+quotedblbase 157
+OE 158
+Lslash 159
+exclamdown 161
+cent 162
+sterling 163
+currency 164
+yen 165
+brokenbar 166
+section 167
+dieresis 168
+copyright 169
+ordfeminine 170
+guilsinglleft 171
+logicalnot 172
+registered 174
+minus 173
+macron 175
+degree 176
+plusminus 177
+twosuperior 178
+threesuperior 179
+acute 180
+mu 181
+paragraph 182
+periodcentered 183
+cedilla 184
+onesuperior 185
+ordmasculine 186
+guilsinglright 187
+onequarter 188
+onehalf 189
+threequarters 190
+questiondown 191
+Agrave 192
+Aacute 193
+Acircumflex 194
+Atilde 195
+Adieresis 196
+Aring 197
+AE 198
+Ccedilla 199
+Egrave 200
+Eacute 201
+Ecircumflex 202
+Edieresis 203
+Igrave 204
+Iacute 205
+Icircumflex 206
+Idieresis 207
+Eth 208
+Ntilde 209
+Ograve 210
+Oacute 211
+Ocircumflex 212
+Otilde 213
+Odieresis 214
+multiply 215
+Oslash 216
+Ugrave 217
+Uacute 218
+Ucircumflex 219
+Udieresis 220
+Yacute 221
+Thorn 222
+germandbls 223
+agrave 224
+aacute 225
+acircumflex 226
+atilde 227
+adieresis 228
+aring 229
+ae 230
+ccedilla 231
+egrave 232
+eacute 233
+ecircumflex 234
+edieresis 235
+igrave 236
+iacute 237
+icircumflex 238
+idieresis 239
+eth 240
+ntilde 241
+ograve 242
+oacute 243
+ocircumflex 244
+otilde 245
+odieresis 246
+divide 247
+oslash 248
+ugrave 249
+uacute 250
+ucircumflex 251
+udieresis 252
+yacute 253
+thorn 254
+ydieresis 255
diff --git a/gnu/usr.bin/groff/devps/zapfdr.afm b/gnu/usr.bin/groff/devps/zapfdr.afm
new file mode 100644
index 0000000..ce216de
--- /dev/null
+++ b/gnu/usr.bin/groff/devps/zapfdr.afm
@@ -0,0 +1,222 @@
+StartFontMetrics 2.0
+Comment Copyright (c) 1985, 1987, 1988, 1989 Adobe Systems Incorporated. All rights reserved.
+Comment Creation Date: Fri Dec 1 12:57:42 1989
+Comment UniqueID 26200
+Comment VMusage 39281 49041
+FontName ZapfDingbats-Reverse
+FullName ITC Zapf Dingbats
+FamilyName ITC Zapf Dingbats
+Weight Medium
+ItalicAngle 0
+IsFixedPitch false
+FontBBox -1 -143 981 820
+UnderlinePosition -98
+UnderlineThickness 54
+Version 001.004
+Notice Copyright (c) 1985, 1987, 1988, 1989 Adobe Systems Incorporated. All rights reserved.ITC Zapf Dingbats is a registered trademark of International Typeface Corporation.
+EncodingScheme FontSpecific
+StartCharMetrics 202
+C 32 ; WX 278 ; N space ; B 0 0 0 0 ;
+C 33 ; WX 974 ; N a1 ; B 35 72 939 621 ;
+C 34 ; WX 961 ; N a2 ; B 35 81 927 611 ;
+C 35 ; WX 974 ; N a202 ; B 35 72 939 621 ;
+C 36 ; WX 980 ; N a3 ; B 35 0 945 692 ;
+C 37 ; WX 719 ; N a4 ; B 34 139 685 566 ;
+C 38 ; WX 789 ; N a5 ; B 35 -14 755 705 ;
+C 39 ; WX 790 ; N a119 ; B 35 -14 755 705 ;
+C 40 ; WX 791 ; N a118 ; B 35 -13 761 705 ;
+C 41 ; WX 690 ; N a117 ; B 35 138 655 553 ;
+C 42 ; WX 960 ; N a11 ; B 35 123 925 568 ;
+C 43 ; WX 939 ; N a12 ; B 35 134 904 559 ;
+C 44 ; WX 549 ; N a13 ; B 29 -11 516 705 ;
+C 45 ; WX 855 ; N a14 ; B 34 59 820 632 ;
+C 46 ; WX 911 ; N a15 ; B 35 50 876 642 ;
+C 47 ; WX 933 ; N a16 ; B 35 139 899 550 ;
+C 48 ; WX 911 ; N a105 ; B 35 50 876 642 ;
+C 49 ; WX 945 ; N a17 ; B 35 139 909 553 ;
+C 50 ; WX 974 ; N a18 ; B 35 104 938 587 ;
+C 51 ; WX 755 ; N a19 ; B 34 -13 721 705 ;
+C 52 ; WX 846 ; N a20 ; B 36 -14 811 705 ;
+C 53 ; WX 762 ; N a21 ; B 35 0 727 692 ;
+C 54 ; WX 761 ; N a22 ; B 35 0 727 692 ;
+C 55 ; WX 571 ; N a23 ; B -1 -68 571 661 ;
+C 56 ; WX 677 ; N a24 ; B 36 -13 642 705 ;
+C 57 ; WX 763 ; N a25 ; B 35 0 728 692 ;
+C 58 ; WX 760 ; N a26 ; B 35 0 726 692 ;
+C 59 ; WX 759 ; N a27 ; B 35 0 725 692 ;
+C 60 ; WX 754 ; N a28 ; B 35 0 720 692 ;
+C 61 ; WX 494 ; N a6 ; B 35 0 460 692 ;
+C 62 ; WX 552 ; N a7 ; B 35 0 517 692 ;
+C 63 ; WX 537 ; N a8 ; B 35 0 503 692 ;
+C 64 ; WX 577 ; N a9 ; B 35 96 542 596 ;
+C 65 ; WX 692 ; N a10 ; B 35 -14 657 705 ;
+C 66 ; WX 786 ; N a29 ; B 35 -14 751 705 ;
+C 67 ; WX 788 ; N a30 ; B 35 -14 752 705 ;
+C 68 ; WX 788 ; N a31 ; B 35 -14 753 705 ;
+C 69 ; WX 790 ; N a32 ; B 35 -14 756 705 ;
+C 70 ; WX 793 ; N a33 ; B 35 -13 759 705 ;
+C 71 ; WX 794 ; N a34 ; B 35 -13 759 705 ;
+C 72 ; WX 816 ; N a35 ; B 35 -14 782 705 ;
+C 73 ; WX 823 ; N a36 ; B 35 -14 787 705 ;
+C 74 ; WX 789 ; N a37 ; B 35 -14 754 705 ;
+C 75 ; WX 841 ; N a38 ; B 35 -14 807 705 ;
+C 76 ; WX 823 ; N a39 ; B 35 -14 789 705 ;
+C 77 ; WX 833 ; N a40 ; B 35 -14 798 705 ;
+C 78 ; WX 816 ; N a41 ; B 35 -13 782 705 ;
+C 79 ; WX 831 ; N a42 ; B 35 -14 796 705 ;
+C 80 ; WX 923 ; N a43 ; B 35 -14 888 705 ;
+C 81 ; WX 744 ; N a44 ; B 35 0 710 692 ;
+C 82 ; WX 723 ; N a45 ; B 35 0 688 692 ;
+C 83 ; WX 749 ; N a46 ; B 35 0 714 692 ;
+C 84 ; WX 790 ; N a47 ; B 34 -14 756 705 ;
+C 85 ; WX 792 ; N a48 ; B 35 -14 758 705 ;
+C 86 ; WX 695 ; N a49 ; B 35 -14 661 706 ;
+C 87 ; WX 776 ; N a50 ; B 35 -6 741 699 ;
+C 88 ; WX 768 ; N a51 ; B 35 -7 734 699 ;
+C 89 ; WX 792 ; N a52 ; B 35 -14 757 705 ;
+C 90 ; WX 759 ; N a53 ; B 35 0 725 692 ;
+C 91 ; WX 707 ; N a54 ; B 35 -13 672 704 ;
+C 92 ; WX 708 ; N a55 ; B 35 -14 672 705 ;
+C 93 ; WX 682 ; N a56 ; B 35 -14 647 705 ;
+C 94 ; WX 701 ; N a57 ; B 35 -14 666 705 ;
+C 95 ; WX 826 ; N a58 ; B 35 -14 791 705 ;
+C 96 ; WX 815 ; N a59 ; B 35 -14 780 705 ;
+C 97 ; WX 789 ; N a60 ; B 35 -14 754 705 ;
+C 98 ; WX 789 ; N a61 ; B 35 -14 754 705 ;
+C 99 ; WX 707 ; N a62 ; B 34 -14 673 705 ;
+C 100 ; WX 687 ; N a63 ; B 36 0 651 692 ;
+C 101 ; WX 696 ; N a64 ; B 35 0 661 691 ;
+C 102 ; WX 689 ; N a65 ; B 35 0 655 692 ;
+C 103 ; WX 786 ; N a66 ; B 34 -14 751 705 ;
+C 104 ; WX 787 ; N a67 ; B 35 -14 752 705 ;
+C 105 ; WX 713 ; N a68 ; B 35 -14 678 705 ;
+C 106 ; WX 791 ; N a69 ; B 35 -14 756 705 ;
+C 107 ; WX 785 ; N a70 ; B 36 -14 751 705 ;
+C 108 ; WX 791 ; N a71 ; B 35 -14 757 705 ;
+C 109 ; WX 873 ; N a72 ; B 35 -14 838 705 ;
+C 110 ; WX 761 ; N a73 ; B 35 0 726 692 ;
+C 111 ; WX 762 ; N a74 ; B 35 0 727 692 ;
+C 112 ; WX 762 ; N a203 ; B 35 0 727 692 ;
+C 113 ; WX 759 ; N a75 ; B 35 0 725 692 ;
+C 114 ; WX 759 ; N a204 ; B 35 0 725 692 ;
+C 115 ; WX 892 ; N a76 ; B 35 0 858 705 ;
+C 116 ; WX 892 ; N a77 ; B 35 -14 858 692 ;
+C 117 ; WX 788 ; N a78 ; B 35 -14 754 705 ;
+C 118 ; WX 784 ; N a79 ; B 35 -14 749 705 ;
+C 119 ; WX 438 ; N a81 ; B 35 -14 403 705 ;
+C 120 ; WX 138 ; N a82 ; B 35 0 104 692 ;
+C 121 ; WX 277 ; N a83 ; B 35 0 242 692 ;
+C 122 ; WX 415 ; N a84 ; B 35 0 380 692 ;
+C 123 ; WX 392 ; N a97 ; B 35 263 357 705 ;
+C 124 ; WX 392 ; N a98 ; B 34 263 357 705 ;
+C 125 ; WX 668 ; N a99 ; B 35 263 633 705 ;
+C 126 ; WX 668 ; N a100 ; B 36 263 634 705 ;
+C 161 ; WX 732 ; N a101 ; B 35 -143 697 806 ;
+C 162 ; WX 544 ; N a102 ; B 56 -14 488 706 ;
+C 163 ; WX 544 ; N a103 ; B 34 -14 508 705 ;
+C 164 ; WX 910 ; N a104 ; B 35 40 875 651 ;
+C 165 ; WX 667 ; N a106 ; B 35 -14 633 705 ;
+C 166 ; WX 760 ; N a107 ; B 35 -14 726 705 ;
+C 167 ; WX 760 ; N a108 ; B 0 121 758 569 ;
+C 168 ; WX 776 ; N a112 ; B 35 0 741 705 ;
+C 169 ; WX 595 ; N a111 ; B 34 -14 560 705 ;
+C 170 ; WX 694 ; N a110 ; B 35 -14 659 705 ;
+C 171 ; WX 626 ; N a109 ; B 34 0 591 705 ;
+C 172 ; WX 788 ; N a120 ; B 35 -14 754 705 ;
+C 173 ; WX 788 ; N a121 ; B 35 -14 754 705 ;
+C 174 ; WX 788 ; N a122 ; B 35 -14 754 705 ;
+C 175 ; WX 788 ; N a123 ; B 35 -14 754 705 ;
+C 176 ; WX 788 ; N a124 ; B 35 -14 754 705 ;
+C 177 ; WX 788 ; N a125 ; B 35 -14 754 705 ;
+C 178 ; WX 788 ; N a126 ; B 35 -14 754 705 ;
+C 179 ; WX 788 ; N a127 ; B 35 -14 754 705 ;
+C 180 ; WX 788 ; N a128 ; B 35 -14 754 705 ;
+C 181 ; WX 788 ; N a129 ; B 35 -14 754 705 ;
+C 182 ; WX 788 ; N a130 ; B 35 -14 754 705 ;
+C 183 ; WX 788 ; N a131 ; B 35 -14 754 705 ;
+C 184 ; WX 788 ; N a132 ; B 35 -14 754 705 ;
+C 185 ; WX 788 ; N a133 ; B 35 -14 754 705 ;
+C 186 ; WX 788 ; N a134 ; B 35 -14 754 705 ;
+C 187 ; WX 788 ; N a135 ; B 35 -14 754 705 ;
+C 188 ; WX 788 ; N a136 ; B 35 -14 754 705 ;
+C 189 ; WX 788 ; N a137 ; B 35 -14 754 705 ;
+C 190 ; WX 788 ; N a138 ; B 35 -14 754 705 ;
+C 191 ; WX 788 ; N a139 ; B 35 -14 754 705 ;
+C 192 ; WX 788 ; N a140 ; B 35 -14 754 705 ;
+C 193 ; WX 788 ; N a141 ; B 35 -14 754 705 ;
+C 194 ; WX 788 ; N a142 ; B 35 -14 754 705 ;
+C 195 ; WX 788 ; N a143 ; B 35 -14 754 705 ;
+C 196 ; WX 788 ; N a144 ; B 35 -14 754 705 ;
+C 197 ; WX 788 ; N a145 ; B 35 -14 754 705 ;
+C 198 ; WX 788 ; N a146 ; B 35 -14 754 705 ;
+C 199 ; WX 788 ; N a147 ; B 35 -14 754 705 ;
+C 200 ; WX 788 ; N a148 ; B 35 -14 754 705 ;
+C 201 ; WX 788 ; N a149 ; B 35 -14 754 705 ;
+C 202 ; WX 788 ; N a150 ; B 35 -14 754 705 ;
+C 203 ; WX 788 ; N a151 ; B 35 -14 754 705 ;
+C 204 ; WX 788 ; N a152 ; B 35 -14 754 705 ;
+C 205 ; WX 788 ; N a153 ; B 35 -14 754 705 ;
+C 206 ; WX 788 ; N a154 ; B 35 -14 754 705 ;
+C 207 ; WX 788 ; N a155 ; B 35 -14 754 705 ;
+C 208 ; WX 788 ; N a156 ; B 35 -14 754 705 ;
+C 209 ; WX 788 ; N a157 ; B 35 -14 754 705 ;
+C 210 ; WX 788 ; N a158 ; B 35 -14 754 705 ;
+C 211 ; WX 788 ; N a159 ; B 35 -14 754 705 ;
+C 212 ; WX 894 ; N a160 ; B 35 58 860 634 ;
+C 213 ; WX 838 ; N a161 ; B 35 152 803 540 ;
+C 214 ; WX 1016 ; N a163 ; B 34 152 981 540 ;
+C 215 ; WX 458 ; N a164 ; B 35 -127 422 820 ;
+C 216 ; WX 748 ; N a196 ; B 35 94 698 597 ;
+C 217 ; WX 924 ; N a165 ; B 35 140 890 552 ;
+C 218 ; WX 748 ; N a192 ; B 35 94 698 597 ;
+C 219 ; WX 918 ; N a166 ; B 35 166 884 526 ;
+C 220 ; WX 927 ; N a167 ; B 35 32 892 660 ;
+C 221 ; WX 928 ; N a168 ; B 35 129 891 562 ;
+C 222 ; WX 928 ; N a169 ; B 35 128 893 563 ;
+C 223 ; WX 834 ; N a170 ; B 35 155 799 537 ;
+C 224 ; WX 873 ; N a171 ; B 35 93 838 599 ;
+C 225 ; WX 828 ; N a172 ; B 35 104 791 588 ;
+C 226 ; WX 924 ; N a173 ; B 35 98 889 594 ;
+C 227 ; WX 924 ; N a162 ; B 35 98 889 594 ;
+C 228 ; WX 917 ; N a174 ; B 35 0 882 692 ;
+C 229 ; WX 930 ; N a175 ; B 35 84 896 608 ;
+C 230 ; WX 931 ; N a176 ; B 35 84 896 608 ;
+C 231 ; WX 463 ; N a177 ; B 35 -99 429 791 ;
+C 232 ; WX 883 ; N a178 ; B 35 71 848 623 ;
+C 233 ; WX 836 ; N a179 ; B 35 44 802 648 ;
+C 234 ; WX 836 ; N a193 ; B 35 44 802 648 ;
+C 235 ; WX 867 ; N a180 ; B 35 101 832 591 ;
+C 236 ; WX 867 ; N a199 ; B 35 101 832 591 ;
+C 237 ; WX 696 ; N a181 ; B 35 44 661 648 ;
+C 238 ; WX 696 ; N a200 ; B 35 44 661 648 ;
+C 239 ; WX 874 ; N a182 ; B 35 77 840 619 ;
+C 241 ; WX 874 ; N a201 ; B 35 73 840 615 ;
+C 242 ; WX 760 ; N a183 ; B 35 0 725 692 ;
+C 243 ; WX 946 ; N a184 ; B 35 160 911 533 ;
+C 244 ; WX 771 ; N a197 ; B 34 37 736 655 ;
+C 245 ; WX 865 ; N a185 ; B 35 207 830 481 ;
+C 246 ; WX 771 ; N a194 ; B 34 37 736 655 ;
+C 247 ; WX 888 ; N a198 ; B 34 -19 853 712 ;
+C 248 ; WX 967 ; N a186 ; B 35 124 932 568 ;
+C 249 ; WX 888 ; N a195 ; B 34 -19 853 712 ;
+C 250 ; WX 831 ; N a187 ; B 35 113 796 579 ;
+C 251 ; WX 873 ; N a188 ; B 36 118 838 578 ;
+C 252 ; WX 927 ; N a189 ; B 35 150 891 542 ;
+C 253 ; WX 970 ; N a190 ; B 35 76 931 616 ;
+C 254 ; WX 918 ; N a191 ; B 34 99 884 593 ;
+C -1 ; WX 410 ; N a86 ; B 35 0 375 692 ;
+C -1 ; WX 509 ; N a85 ; B 35 0 475 692 ;
+C -1 ; WX 334 ; N a95 ; B 35 0 299 692 ;
+C -1 ; WX 509 ; N a205 ; B 35 0 475 692 ;
+C -1 ; WX 390 ; N a89 ; B 35 -14 356 705 ;
+C -1 ; WX 234 ; N a87 ; B 35 -14 199 705 ;
+C -1 ; WX 276 ; N a91 ; B 35 0 242 692 ;
+C -1 ; WX 390 ; N a90 ; B 35 -14 355 705 ;
+C -1 ; WX 410 ; N a206 ; B 35 0 375 692 ;
+C -1 ; WX 317 ; N a94 ; B 35 0 283 692 ;
+C -1 ; WX 317 ; N a93 ; B 35 0 283 692 ;
+C -1 ; WX 276 ; N a92 ; B 35 0 242 692 ;
+C -1 ; WX 334 ; N a96 ; B 35 0 299 692 ;
+C -1 ; WX 234 ; N a88 ; B 35 -14 199 705 ;
+EndCharMetrics
+EndFontMetrics
diff --git a/gnu/usr.bin/groff/devps/zapfdr.ps b/gnu/usr.bin/groff/devps/zapfdr.ps
new file mode 100644
index 0000000..8283be2
--- /dev/null
+++ b/gnu/usr.bin/groff/devps/zapfdr.ps
@@ -0,0 +1,225 @@
+%!PS-Adobe-3.0 Resource-Font
+%%DocumentNeededResources: font ZapfDingbats
+
+%%IncludeResource: font ZapfDingbats
+
+/ZapfDingbats findfont [-1 0 0 1 0 0] makefont
+
+dup length 1 add dict begin
+{
+ exch dup dup /FID ne exch /UniqueID ne and {
+ exch def
+ } {
+ pop pop
+ } ifelse
+} forall
+
+/FontName /ZapfDingbats-Reverse def
+
+/Metrics 202 dict dup begin
+ /space [0 -278] def
+ /a1 [-939 -974] def
+ /a2 [-926 -961] def
+ /a202 [-939 -974] def
+ /a3 [-945 -980] def
+ /a4 [-685 -719] def
+ /a5 [-754 -789] def
+ /a119 [-755 -790] def
+ /a118 [-756 -791] def
+ /a117 [-655 -690] def
+ /a11 [-925 -960] def
+ /a12 [-904 -939] def
+ /a13 [-520 -549] def
+ /a14 [-821 -855] def
+ /a15 [-876 -911] def
+ /a16 [-898 -933] def
+ /a105 [-876 -911] def
+ /a17 [-910 -945] def
+ /a18 [-939 -974] def
+ /a19 [-721 -755] def
+ /a20 [-811 -846] def
+ /a21 [-727 -762] def
+ /a22 [-726 -761] def
+ /a23 [-572 -571] def
+ /a24 [-641 -677] def
+ /a25 [-728 -763] def
+ /a26 [-725 -760] def
+ /a27 [-724 -759] def
+ /a28 [-719 -754] def
+ /a6 [-459 -494] def
+ /a7 [-517 -552] def
+ /a8 [-502 -537] def
+ /a9 [-542 -577] def
+ /a10 [-657 -692] def
+ /a29 [-751 -786] def
+ /a30 [-753 -788] def
+ /a31 [-753 -788] def
+ /a32 [-755 -790] def
+ /a33 [-758 -793] def
+ /a34 [-759 -794] def
+ /a35 [-781 -816] def
+ /a36 [-788 -823] def
+ /a37 [-754 -789] def
+ /a38 [-806 -841] def
+ /a39 [-788 -823] def
+ /a40 [-798 -833] def
+ /a41 [-781 -816] def
+ /a42 [-796 -831] def
+ /a43 [-888 -923] def
+ /a44 [-709 -744] def
+ /a45 [-688 -723] def
+ /a46 [-714 -749] def
+ /a47 [-756 -790] def
+ /a48 [-757 -792] def
+ /a49 [-660 -695] def
+ /a50 [-741 -776] def
+ /a51 [-733 -768] def
+ /a52 [-757 -792] def
+ /a53 [-724 -759] def
+ /a54 [-672 -707] def
+ /a55 [-673 -708] def
+ /a56 [-647 -682] def
+ /a57 [-666 -701] def
+ /a58 [-791 -826] def
+ /a59 [-780 -815] def
+ /a60 [-754 -789] def
+ /a61 [-754 -789] def
+ /a62 [-673 -707] def
+ /a63 [-651 -687] def
+ /a64 [-661 -696] def
+ /a65 [-654 -689] def
+ /a66 [-752 -786] def
+ /a67 [-752 -787] def
+ /a68 [-678 -713] def
+ /a69 [-756 -791] def
+ /a70 [-749 -785] def
+ /a71 [-756 -791] def
+ /a72 [-838 -873] def
+ /a73 [-726 -761] def
+ /a74 [-727 -762] def
+ /a203 [-727 -762] def
+ /a75 [-724 -759] def
+ /a204 [-724 -759] def
+ /a76 [-857 -892] def
+ /a77 [-857 -892] def
+ /a78 [-753 -788] def
+ /a79 [-749 -784] def
+ /a81 [-403 -438] def
+ /a82 [-103 -138] def
+ /a83 [-242 -277] def
+ /a84 [-380 -415] def
+ /a97 [-357 -392] def
+ /a98 [-358 -392] def
+ /a99 [-633 -668] def
+ /a100 [-632 -668] def
+ /a101 [-697 -732] def
+ /a102 [-488 -544] def
+ /a103 [-510 -544] def
+ /a104 [-875 -910] def
+ /a106 [-632 -667] def
+ /a107 [-725 -760] def
+ /a108 [-760 -760] def
+ /a112 [-741 -776] def
+ /a111 [-561 -595] def
+ /a110 [-659 -694] def
+ /a109 [-592 -626] def
+ /a120 [-753 -788] def
+ /a121 [-753 -788] def
+ /a122 [-753 -788] def
+ /a123 [-753 -788] def
+ /a124 [-753 -788] def
+ /a125 [-753 -788] def
+ /a126 [-753 -788] def
+ /a127 [-753 -788] def
+ /a128 [-753 -788] def
+ /a129 [-753 -788] def
+ /a130 [-753 -788] def
+ /a131 [-753 -788] def
+ /a132 [-753 -788] def
+ /a133 [-753 -788] def
+ /a134 [-753 -788] def
+ /a135 [-753 -788] def
+ /a136 [-753 -788] def
+ /a137 [-753 -788] def
+ /a138 [-753 -788] def
+ /a139 [-753 -788] def
+ /a140 [-753 -788] def
+ /a141 [-753 -788] def
+ /a142 [-753 -788] def
+ /a143 [-753 -788] def
+ /a144 [-753 -788] def
+ /a145 [-753 -788] def
+ /a146 [-753 -788] def
+ /a147 [-753 -788] def
+ /a148 [-753 -788] def
+ /a149 [-753 -788] def
+ /a150 [-753 -788] def
+ /a151 [-753 -788] def
+ /a152 [-753 -788] def
+ /a153 [-753 -788] def
+ /a154 [-753 -788] def
+ /a155 [-753 -788] def
+ /a156 [-753 -788] def
+ /a157 [-753 -788] def
+ /a158 [-753 -788] def
+ /a159 [-753 -788] def
+ /a160 [-859 -894] def
+ /a161 [-803 -838] def
+ /a163 [-982 -1016] def
+ /a164 [-423 -458] def
+ /a196 [-713 -748] def
+ /a165 [-889 -924] def
+ /a192 [-713 -748] def
+ /a166 [-883 -918] def
+ /a167 [-892 -927] def
+ /a168 [-893 -928] def
+ /a169 [-893 -928] def
+ /a170 [-799 -834] def
+ /a171 [-838 -873] def
+ /a172 [-793 -828] def
+ /a173 [-889 -924] def
+ /a162 [-889 -924] def
+ /a174 [-882 -917] def
+ /a175 [-895 -930] def
+ /a176 [-896 -931] def
+ /a177 [-428 -463] def
+ /a178 [-848 -883] def
+ /a179 [-801 -836] def
+ /a193 [-801 -836] def
+ /a180 [-832 -867] def
+ /a199 [-832 -867] def
+ /a181 [-661 -696] def
+ /a200 [-661 -696] def
+ /a182 [-839 -874] def
+ /a201 [-839 -874] def
+ /a183 [-725 -760] def
+ /a184 [-911 -946] def
+ /a197 [-737 -771] def
+ /a185 [-830 -865] def
+ /a194 [-737 -771] def
+ /a198 [-854 -888] def
+ /a186 [-932 -967] def
+ /a195 [-854 -888] def
+ /a187 [-796 -831] def
+ /a188 [-837 -873] def
+ /a189 [-892 -927] def
+ /a190 [-935 -970] def
+ /a191 [-884 -918] def
+ /a205 [-474 -509] def
+ /a206 [-375 -410] def
+ /a85 [-474 -509] def
+ /a86 [-375 -410] def
+ /a87 [-199 -234] def
+ /a88 [-199 -234] def
+ /a89 [-355 -390] def
+ /a90 [-355 -390] def
+ /a91 [-241 -276] def
+ /a92 [-241 -276] def
+ /a93 [-282 -317] def
+ /a94 [-282 -317] def
+ /a95 [-299 -334] def
+ /a96 [-299 -334] def
+
+end def
+
+/ZapfDingbats-Reverse currentdict end definefont pop
diff --git a/gnu/usr.bin/groff/doc/Makefile b/gnu/usr.bin/groff/doc/Makefile
new file mode 100644
index 0000000..2d9ae08
--- /dev/null
+++ b/gnu/usr.bin/groff/doc/Makefile
@@ -0,0 +1,55 @@
+#Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
+# Written by James Clark (jjc@jclark.com)
+#
+#This file is part of groff.
+#
+#groff is free software; you can redistribute it and/or modify it under
+#the terms of the GNU General Public License as published by the Free
+#Software Foundation; either version 2, or (at your option) any later
+#version.
+#
+#groff is distributed in the hope that it will be useful, but WITHOUT ANY
+#WARRANTY; without even the implied warranty of MERCHANTABILITY or
+#FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+#for more details.
+#
+#You should have received a copy of the GNU General Public License along
+#with groff; see the file COPYING. If not, write to the Free Software
+#Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+FFLAG=-F..
+TROFF=../troff/troff -M../tmac $(FFLAG)
+GROPS=../grops/grops $(FFLAG)
+DOCS=meref.PS meintro.PS
+MEMACROS=../macros/tmac.e
+SOELIM=../soelim/soelim
+
+all: $(DOCS)
+
+.SUFFIXES: .tr .me .PS .dit
+
+.dit.PS:
+ $(GROPS) $< >$@
+
+.me.dit:
+ $(SOELIM) $< \
+ | sed -e "s;@VERSION@;`cat ../VERSION`;" \
+ | $(TROFF) -Tps $(FFLAG) -me >$@
+
+.tr.dit:
+ $(TROFF) -Tps $< >$@
+
+meref.PS: meref.dit
+meintro.PS: meintro.dit
+
+install:
+
+clean:
+ -rm -f *.PS *.dit core
+
+distclean: clean
+
+realclean: distclean
+
+extraclean: clean
+ -rm -f core *~ \#* junk temp grot
diff --git a/gnu/usr.bin/groff/doc/meintro.me b/gnu/usr.bin/groff/doc/meintro.me
new file mode 100644
index 0000000..192edb7
--- /dev/null
+++ b/gnu/usr.bin/groff/doc/meintro.me
@@ -0,0 +1,2246 @@
+.\" Copyright (c) 1986 The Regents of the University of California.
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms are permitted
+.\" provided that the above copyright notice and this paragraph are
+.\" duplicated in all such forms and that any documentation,
+.\" advertising materials, and other materials related to such
+.\" distribution and use acknowledge that the software was developed
+.\" by the University of California, Berkeley. The name of the
+.\" University may not be used to endorse or promote products derived
+.\" from this software without specific prior written permission.
+.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+.\" IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+.\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+.\"
+.\" @(#)intro.me 6.4 (Berkeley) 7/17/89
+.\"
+.\" Modified for groff by jjc@jclark.com.
+.\"UC 7
+.ll 6.5i
+.lt 6.5i
+.ds MO @VERSION@
+.nr si 3n
+.he 'USING GROFF AND \-ME''%'
+.\"eh 'USD:22-%''Writing Papers with NROFF using \-me'
+.\"oh 'Writing Papers with NROFF using \-me''USD:22-%'
+.ds U \s-1UNIX\s0
+.ds N \s-1NROFF\s0
+.ds T \s-1TROFF\s0
+.ds G \s-1GROFF\s0
+.+c
+.(l C
+.sz 14
+.b "Writing Papers with GROFF using \-me"
+.sz
+.sp 2
+.ul
+Eric P. Allman*
+.(f
+*Author's current address:
+Britton Lee, Inc.,
+1919 Addison Suite 105,
+Berkeley, California 94704.
+.)f
+.sp
+Project INGRES
+Electronics Research Laboratory
+University of California, Berkeley
+Berkeley, California 94720
+.sp 2
+.i "Modified for \*G by James Clark"
+.)l
+.sp 4
+.pp
+This document describes
+the text processing facilities
+available on the \*U\(dg
+.(f
+\(dg\*U is a trademark
+of AT&T Bell Laboratories
+.)f
+operating system
+via \*G and the
+\-me
+macro package.
+It is assumed
+that the reader
+already is generally familiar
+with the \*U operating system
+and a text editor
+such as
+.b ex .
+This is intended to be a casual introduction,
+and
+as such not all material is covered.
+In particular,
+many variations and additional features
+of the \-me macro package
+are not explained.
+For a complete discussion of this
+and other issues,
+see
+.ul
+The \-me Reference Manual
+and
+.ul
+The \*N/\*T Reference Manual.
+.pp
+\*G, a computer program
+that runs on the \*U operating system,
+reads an input file
+prepared by the user
+and outputs a formatted paper
+suitable for publication or framing.
+The input consists of
+.i text ,
+or words to be printed,
+and
+.i requests ,
+which give instructions
+to the \*G program
+telling how to format the printed copy.
+.pp
+Section 1
+describes the basics
+of text processing.
+Section 2
+describes the basic requests.
+Section 3
+introduces displays.
+Annotations,
+such as footnotes,
+are handled in
+section 4.
+The more complex requests
+which are not discussed in section 2
+are covered in section 5.
+Finally,
+section 6
+discusses things you will need
+to know
+if you want to typeset documents.
+If you are a novice,
+you probably won't want to read beyond section 4
+until you have tried some of the basic features out.
+.pp
+When you have your raw text ready,
+call the \*G formatter by typing
+as a request to the \*U shell:
+.(b
+groff \-me \-T\c
+.i "type files"
+.)b
+where
+.i type
+describes the type of
+output device you are using.
+A complete description of options
+to the \*G command can be found in
+.b groff (1).
+.pp
+The word
+.i argument
+is used in this manual
+to mean a word or number
+which appears on the same line
+as a request
+which modifies the meaning
+of that request.
+For example,
+the request
+.(b
+\&.sp
+.)b
+spaces one line,
+but
+.(b
+\&.sp 4
+.)b
+spaces four lines.
+The number
+.b 4
+is an
+.i argument
+to the
+.b .sp
+request
+which says to space four lines
+instead of one.
+Arguments are separated from the request
+and from each other
+by spaces.
+.sh 1 "Basics of Text Processing"
+.pp
+The primary function
+of \*G
+is to
+.i collect
+words from input lines,
+.i fill
+output lines with those words,
+.i justify
+the right hand margin by inserting extra spaces
+in the line,
+and output the result.
+For example,
+the input:
+.(b
+Now is the time
+for all good men
+to come to the aid
+of their party.
+Four score and seven
+years ago,...
+.)b
+will be read,
+packed onto output lines,
+and justified
+to produce:
+.(b F
+Now is the time
+for all good men
+to come to the aid
+of their party.
+Four score and seven
+years ago,...
+.)b
+Sometimes you may want to start a new output line
+even though the line you are on
+is not yet full;
+for example,
+at the end of a paragraph.
+To do this
+you can cause a
+.i break ,
+which
+starts a new output line.
+Some requests
+cause a break automatically,
+as do blank input lines
+and input lines beginning with a space.
+.pp
+Not all input lines
+are text to be formatted.
+Some of the input lines
+are
+.i requests
+which describe
+how to format the text.
+Requests always have a period
+or an apostrophe
+(\c
+.q "\|\(aa\|" )
+as the first character
+of the input line.
+.pp
+The text formatter
+also does more complex things,
+such as automatically numbering pages,
+skipping over page folds,
+putting footnotes in the correct place,
+and so forth.
+.pp
+I can offer you a few hints
+for preparing text
+for input to \*G.
+First,
+keep the input lines short.
+Short input lines are easier to edit,
+and \*G will pack words onto longer lines
+for you anyhow.
+In keeping with this,
+it is helpful
+to begin a new line
+after every period,
+comma,
+or phrase,
+since common corrections
+are to add or delete sentences
+or phrases.
+Second,
+do not put spaces at the end of lines,
+since this can sometimes confuse the \*N
+processor.
+Third,
+do not hyphenate words at the end of lines
+(except words that should have hyphens in them,
+such as
+.q mother-in-law );
+\*G is smart enough to hyphenate words
+for you as needed,
+but is not smart enough
+to take hyphens out
+and join a word back together.
+Also,
+words such as
+.q mother-in-law
+should not be broken
+over a line,
+since then you will get a space
+where not wanted,
+such as
+.tr @-
+.nh
+.q "mother@\ in@law" .
+.br
+.tr @@
+.hy 14
+.sh 1 "Basic Requests"
+.sh 2 "Paragraphs"
+.pp
+Paragraphs are begun
+by using the
+.b .pp
+request.
+For example,
+the input:
+.(b
+\&.pp
+Now is the time for all good men
+to come to the aid of their party.
+Four score and seven years ago,...
+.)b
+produces a blank line
+followed by an indented first line.
+The result is:
+.(b F
+.ti +\n(piu
+Now is the time for all good men
+to come to the aid of their party.
+Four score and seven years ago,...
+.)b
+.pp
+Notice that the sentences
+of the paragraphs
+.i "must not"
+begin with a space,
+since blank lines
+and lines beginning with spaces
+cause a break.
+For example,
+if I had typed:
+.(b
+\&.pp
+Now is the time for all good men
+ to come to the aid of their party.
+Four score and seven years ago,...
+.)b
+The output would be:
+.(b F
+.ti +\n(piu
+Now is the time for all good men
+ to come to the aid of their party.
+Four score and seven years ago,...
+.)b
+A new line begins after the word
+.q men
+because the second line began with a space character.
+.pp
+There are many
+fancier
+types of paragraphs,
+which will be described later.
+.sh 2 "Headers and Footers"
+.pp
+Arbitrary headers and footers
+can be put
+at the top and bottom
+of every page.
+Two requests
+of the form
+.b .he \ \c
+.i title
+and
+.b .fo \ \c
+.i title
+define the titles to put at the head and the foot
+of every page,
+respectively.
+The titles are called
+.i three-part
+titles,
+that is,
+there is a left-justified part,
+a centered part,
+and a right-justified part.
+To separate these three parts
+the first character of
+.i title
+(whatever it may be)
+is used as a delimiter.
+Any character may be used,
+but
+backslash
+and double quote marks
+should be avoided.
+The percent sign
+is replaced by the current page number
+whenever found in the title.
+For example,
+the input:
+.(b
+\&.he \(aa\(aa%\(aa\(aa
+\&.fo \(aaJane Jones\(aa\(aaMy Book\(aa
+.)b
+results in the page number
+centered at the top
+of each page,
+.q "Jane Jones"
+in the lower left corner,
+and
+.q "My Book"
+in the lower right corner.
+.sh 2 "Double Spacing"
+.pp
+.ls 2
+\*G will double space output text automatically if you
+use the request
+.b ".ls\ 2" ,
+as is done in this section.
+You can revert to single spaced mode
+by typing
+.b ".ls\ 1" .
+.ls 1
+.sh 2 "Page Layout"
+.pp
+A number of requests allow
+you to change the way the printed copy looks,
+sometimes called the
+.i layout
+of the output page.
+Most of these requests adjust the placing
+of
+.q "white space"
+(blank lines or spaces).
+In these explanations,
+characters in italics
+should be replaced with values you wish to use;
+bold characters
+represent characters which should actually be typed.
+.pp
+The
+.b .bp
+request
+starts a new page.
+.pp
+The request
+.b .sp \ \c
+.i N
+leaves
+.i N
+lines of blank space.
+.i N
+can be omitted
+(meaning skip a single line)
+or can be of the form
+.i N \^\c
+.b i
+(for
+.i N
+inches)
+or
+.i N \^\c
+.b c
+(for
+.i N
+centimeters).
+For example, the input:
+.(b
+\&.sp 1.5i
+My thoughts on the subject
+\&.sp
+.)b
+leaves one and a half inches of space,
+followed by the line
+.q "My thoughts on the subject" ,
+followed by a single blank line.
+.pp
+The
+.b .in \ \c
+.i +N
+request
+changes the amount of white space
+on the left of the page
+(the
+.i indent ).
+The argument
+.i N
+can be of the form
+.b + \c
+.i N
+(meaning leave
+.i N
+spaces more than you are already leaving),
+.b \- \c
+.i N
+(meaning leave less than you do now),
+or just
+.i N
+(meaning leave exactly
+.i N
+spaces).
+.i N
+can be of the form
+.i N \^\c
+.b i
+or
+.i N \^\c
+.b c
+also.
+For example,
+the input:
+.(b
+initial text
+\&.in 5
+some text
+\&.in +1i
+more text
+\&.in \-2c
+final text
+.)b
+produces
+.q "some text"
+indented exactly five spaces
+from the left margin,
+.q "more text"
+indented five spaces
+plus one inch
+from the left margin
+(fifteen spaces
+on a pica typewriter),
+and
+.q "final text"
+indented five spaces
+plus one inch
+minus two centimeters
+from the margin.
+That is,
+the output is:
+.(b
+initial text
+.in +5
+some text
+.in +1i
+more text
+.in -2c
+final text
+.)b
+.pp
+The
+.b .ti \ \c
+.i +N
+(temporary indent)
+request is used like
+.b .in \ \c
+.i +N
+when the indent
+should apply to one line only,
+after which it should revert
+to the previous indent.
+For example,
+the input:
+.(b
+\&.in 1i
+\&.ti 0
+Ware, James R. The Best of Confucius,
+Halcyon House, 1950.
+An excellent book containing translations of
+most of Confucius\(aa most delightful sayings.
+A definite must for anyone interested in the early foundations
+of Chinese philosophy.
+.)b
+produces:
+.in 1i+\n($iu
+.ti \n($iu
+Ware, James R. The Best of Confucius,
+Halcyon House, 1950.
+An excellent book containing translations of
+most of Confucius' most delightful sayings.
+A definite must for anyone interested in the early foundations
+of Chinese philosophy.
+.pp
+Text lines can be centered
+by using the
+.b .ce
+request.
+The line after the
+.b .ce
+is centered
+(horizontally)
+on the page.
+To center more than one line,
+use
+.b .ce \ \c
+.i N
+(where
+.i N
+is the number of lines to center),
+followed by the
+.i N
+lines.
+If you want to center many lines
+but don't want to count them,
+type:
+.(b
+\&.ce 1000
+lines to center
+\&.ce 0
+.)b
+The
+.b ".ce\ 0"
+request tells \*G to center zero more lines,
+in other words,
+stop centering.
+.pp
+All of these requests
+cause a break;
+that is,
+they always start
+a new line.
+If you want to start a new line
+without performing any other action,
+use
+.b .br .
+.sh 1 "Displays"
+.pp
+Displays are sections of text
+to be set off
+from the body of the paper.
+Major quotes,
+tables,
+and figures
+are types of displays,
+as are all the examples
+used in this document.
+All displays
+except centered blocks
+are output
+single spaced.
+.sh 2 "Major Quotes"
+.pp
+Major quotes
+are quotes which are several lines long,
+and hence are set in from the rest
+of the text
+without quote marks
+around them.
+These can be generated
+using the commands
+.b .(q
+and
+.b .)q
+to surround the quote.
+For example,
+the input:
+.(b
+As Weizenbaum points out:
+\&.(q
+It is said that to explain is to explain away.
+This maxim is nowhere so well fulfilled
+as in the areas of computer programming,...
+\&.)q
+.)b
+generates as output:
+.lp
+As Weizenbaum points out:
+.(q
+It is said that to explain is to explain away.
+This maxim is nowhere so well fulfilled
+as in the areas of computer programming,...
+.)q
+.sh 2 "Lists"
+.pp
+A
+.i list
+is an indented,
+single spaced,
+unfilled display.
+Lists should be used
+when the material to be printed
+should not be filled and justified
+like normal text,
+such as columns of figures
+or the examples used in this paper.
+Lists are surrounded
+by the requests
+.b .(l
+and
+.b .)l .
+For example,
+type:
+.(b
+Alternatives to avoid deadlock are:
+\&.(l
+Lock in a specified order
+Detect deadlock and back out one process
+Lock all resources needed before proceeding
+\&.)l
+.)b
+will produce:
+.br
+Alternatives to avoid deadlock are:
+.(l
+Lock in a specified order
+Detect deadlock and back out one process
+Lock all resources needed before proceeding
+.)l
+.sh 2 "Keeps"
+.pp
+A
+.i keep
+is a display of lines
+which are kept on a single page
+if possible.
+An example of where you would use a keep
+might be a diagram.
+Keeps differ from lists
+in that lists may be broken
+over a page boundary
+whereas keeps will not.
+.pp
+Blocks are the basic kind of keep.
+They begin with the request
+.b .(b
+and end with the request
+.b .)b .
+If there is not room on the current page
+for everything in the block,
+a new page is begun.
+This has the unpleasant effect
+of leaving blank space
+at the bottom of the page.
+When this is not appropriate,
+you can use the alternative,
+called
+.i "floating keeps" .
+.pp
+.i "Floating keeps"
+move relative to the text.
+Hence,
+they are good for things
+which will be referred to
+by name,
+such as
+.q "See figure 3" .
+A floating keep will appear
+at the bottom of the current page
+if it will fit;
+otherwise,
+it will appear at the top
+of the next page.
+Floating keeps begin with the line
+.b .(z
+and end with the line
+.b .)z .
+For an example of a floating keep,
+see figure 1.
+.(z
+.in 1i
+.xl -1i
+.hl
+\&.(z
+\&.hl
+Text of keep to be floated.
+\&.sp
+\&.ce
+Figure 1. Example of a Floating Keep.
+\&.hl
+\&.)z
+.sp
+.ce
+Figure 1. Example of a Floating Keep.
+.hl
+.)z
+The
+.b .hl
+request is used
+to draw a horizontal line
+so that the figure
+stands out from the text.
+.sh 2 "Fancier Displays"
+.pp
+Keeps and lists are normally collected in
+.i nofill
+mode,
+so that they are good for tables and such.
+If you want a display
+in fill mode
+(for text),
+type
+.b ".(l\ F"
+(Throughout this section,
+comments applied to
+.b .(l
+also apply to
+.b .(b
+and
+.b .(z ).
+This kind of display
+will be indented from both margins.
+For example,
+the input:
+.(b
+\&.(l F
+And now boys and girls,
+a newer, bigger, better toy than ever before!
+Be the first on your block to have your own computer!
+Yes kids, you too can have one of these modern
+data processing devices.
+You too can produce beautifully formatted papers
+without even batting an eye!
+\&.)l
+.)b
+will be output as:
+.(b F
+And now boys and girls,
+a newer, bigger, better toy than ever before!
+Be the first on your block to have your own computer!
+Yes kids, you too can have one of these modern
+data processing devices.
+You too can produce beautifully formatted papers
+without even batting an eye!
+.)b
+.pp
+Lists and blocks are also normally indented
+(floating keeps are normally left justified).
+To get a left-justified list,
+type
+.b ".(l\ L" .
+To get a list centered
+line-for-line,
+type
+.b ".(l C" .
+For example,
+to get a filled,
+left justified list, enter:
+.(b
+\&.(l L F
+text of block
+\&.)l
+.)b
+The input:
+.(b
+\&.(l
+first line of unfilled display
+more lines
+\&.)l
+.)b
+produces the indented text:
+.(b
+first line of unfilled display
+more lines
+.)b
+Typing the character
+.b L
+after the
+.b .(l
+request produces the left justified result:
+.(b L
+first line of unfilled display
+more lines
+.)b
+Using
+.b C
+instead of
+.b L
+produces the line-at-a-time centered output:
+.(b C
+first line of unfilled display
+more lines
+.)b
+.pp
+Sometimes it may be
+that you want to center several lines
+as a group,
+rather than centering them
+one line at a time.
+To do this
+use centered blocks,
+which are surrounded by the requests
+.b .(c
+and
+.b .)c .
+All the lines are centered as a unit,
+such that the longest line is centered
+and the rest are
+lined up around that line.
+Notice that lines
+do not move
+relative to each other
+using centered blocks,
+whereas they do
+using the
+.b C
+argument to keeps.
+.pp
+Centered blocks are
+.i not
+keeps,
+and may be used
+in conjunction
+with keeps.
+For example,
+to center a group of lines
+as a unit
+and keep them
+on one page,
+use:
+.(b
+\&.(b L
+\&.(c
+first line of unfilled display
+more lines
+\&.)c
+\&.)b
+.)b
+to produce:
+.(b L
+.(c
+first line of unfilled display
+more lines
+.)c
+.)b
+If the block requests
+(\c
+.b .(b
+and
+.b .)b )
+had been omitted
+the result would have been the same,
+but with no guarantee
+that the lines of the centered block
+would have all been on one page.
+Note the use of the
+.b L
+argument to
+.b .(b ;
+this causes the centered block
+to center within the entire line
+rather than within the line
+minus the indent.
+Also,
+the center requests
+must
+be nested
+.i inside
+the keep requests.
+.sh 1 "Annotations"
+.pp
+There are a number of requests
+to save text
+for later printing.
+.i Footnotes
+are printed at the bottom of the current page.
+.i "Delayed text"
+is intended to be a variant form
+of footnote;
+the text is printed only
+when explicitly called for,
+such as at the end of each chapter.
+.i Indexes
+are a type of delayed text
+having a tag
+(usually the page number)
+attached to each entry
+after a row of dots.
+Indexes are also saved
+until called for explicitly.
+.sh 2 "Footnotes"
+.pp
+Footnotes begin with the request
+.b .(f
+and end with the request
+.b .)f .
+The current footnote number is maintained
+automatically,
+and can be used by typing \e**,
+to produce a footnote number\**.
+.(f
+\**Like this.
+.)f
+The number is automatically incremented
+after every footnote.
+For example,
+the input:
+.(b
+\&.(q
+A man who is not upright
+and at the same time is presumptuous;
+one who is not diligent and at the same time is ignorant;
+one who is untruthful and at the same time is incompetent;
+such men I do not count among acquaintances.\e**
+\&.(f
+\e**James R. Ware,
+\&.ul
+The Best of Confucius,
+Halcyon House, 1950.
+Page 77.
+\&.)f
+\&.)q
+.)b
+generates the result:
+.(q
+A man who is not upright
+and at the same time is presumptuous;
+one who is not diligent and at the same time is ignorant;
+one who is untruthful and at the same time is incompetent;
+such men I do not count among acquaintances.\**
+.(f
+\**James R. Ware,
+.ul
+The Best of Confucius,
+Halcyon House, 1950.
+Page 77.
+.)f
+.)q
+It is important
+that the footnote
+appears
+.i inside
+the quote,
+so that you can be sure
+that the footnote
+will appear
+on the same page
+as the quote.
+.sh 2 "Delayed Text"
+.pp
+Delayed text
+is very similar to a footnote
+except that it is printed
+when called for explicitly.
+This allows a list of
+references to
+appear
+(for example)
+at the end of each chapter,
+as is the convention in some disciplines.
+Use
+.b \e*#
+on delayed text
+instead of
+.b \e**
+as on footnotes.
+.pp
+If you are using delayed text
+as your standard reference mechanism,
+you can still use footnotes,
+except that you may want to reference them
+with special characters*
+.(f
+*Such as an asterisk.
+.)f
+rather than numbers.
+.sh 2 "Indexes"
+.pp
+An
+.q index
+(actually more like a table of contents,
+since the entries are not sorted alphabetically)
+resembles delayed text,
+in that it is saved until called for.
+However,
+each entry has the page number
+(or some other tag)
+appended to the last line
+of the index entry
+after a row of dots.
+.pp
+Index entries begin with the request
+.b .(x
+and end with
+.b .)x .
+The
+.b .)x
+request may have a argument,
+which is the value to print
+as the
+.q "page number" .
+It defaults to the current page number.
+If the page number given is an underscore
+(\c
+.q _ )
+no page number
+or line of dots
+is printed at all.
+To get the line of dots
+without a page number,
+type
+.b ".)x """"" ,
+which specifies an explicitly null page number.
+.pp
+The
+.b .xp
+request prints the index.
+.pp
+For example,
+the input:
+.(b
+\&.(x
+Sealing wax
+\&.)x
+\&.(x
+Cabbages and kings
+\&.)x _
+\&.(x
+Why the sea is boiling hot
+\&.)x 2.5a
+\&.(x
+Whether pigs have wings
+\&.)x ""
+\&.(x
+This is a terribly long index entry, such as might be used
+for a list of illustrations, tables, or figures; I expect it to
+take at least two lines.
+\&.)x
+\&.xp
+.)b
+generates:
+.(x
+Sealing wax
+.)x
+.(x
+Cabbages and kings
+.)x _
+.(x
+Why the sea is boiling hot
+.)x 2.5a
+.(x
+Whether pigs have wings
+.)x ""
+.(x
+This is a terribly long index entry, such as might be used
+for a list of illustrations, tables, or figures; I expect it to
+take at least two lines.
+.)x
+.xp
+.pp
+The
+.b .(x
+request may have a single character
+argument,
+specifying the
+.q name
+of the index;
+the normal index is
+.b x .
+Thus,
+several
+.q indices
+may be maintained simultaneously
+(such as a list of tables, table of contents, etc.).
+.pp
+Notice that the index must be printed
+at the
+.i end
+of the paper,
+rather than at the beginning
+where it will probably appear
+(as a table of contents);
+the pages may have to be physically rearranged
+after printing.
+.sh 1 "Fancier Features"
+.pp
+A large number of fancier requests
+exist,
+notably requests to provide other sorts of paragraphs,
+numbered sections of the form
+.b 1.2.3
+(such as used in this document),
+and multicolumn output.
+.sh 2 "More Paragraphs"
+.pp
+Paragraphs generally start with
+a blank line
+and with the first line
+indented.
+It is possible to get
+left-justified block-style paragraphs
+by using
+.b .lp
+instead of
+.b .pp ,
+as demonstrated by the next paragraph.
+.lp
+Sometimes you want to use paragraphs
+that have the
+.i body
+indented,
+and the first line
+exdented
+(opposite of indented)
+with a label.
+This can be done with the
+.b .ip
+request.
+A word specified on the same line as
+.b .ip
+is printed in the margin,
+and the body is lined up
+at a prespecified position
+(normally five spaces).
+For example,
+the input:
+.(b
+\&.ip one
+This is the first paragraph.
+Notice how the first line
+of the resulting paragraph lines up
+with the other lines in the paragraph.
+\&.ip two
+And here we are at the second paragraph already.
+You may notice that the argument to \c
+.b .ip
+appears
+in the margin.
+\&.lp
+We can continue text...
+.)b
+produces as output:
+.ip one
+This is the first paragraph.
+Notice how the first line of the resulting paragraph lines up
+with the other lines in the paragraph.
+.ip two
+And here we are at the second paragraph already.
+You may notice that the argument to
+.b .ip
+appears
+in the margin.
+.lp
+We can continue text without starting a new indented
+paragraph
+by using the
+.b .lp
+request.
+.pp
+If you have spaces in the label of a
+.b .ip
+request,
+you must use an
+.q "unpaddable space"
+instead of a regular space.
+This is typed as a backslash character
+(\c
+.q \e )
+followed by a space.
+For example,
+to print the label
+.q "Part 1" ,
+enter:
+.(b
+\&.ip "Part\e 1"
+.)b
+.pp
+If a label of an indented paragraph
+(that is, the argument to
+.b .ip )
+is longer than the space allocated for the label,
+.b .ip
+will begin a new line after the label.
+For example,
+the input:
+.(b
+\&.ip longlabel
+This paragraph had a long label.
+The first character of text on the first line
+will not line up with the text on second and subsequent lines,
+although they will line up with each other.
+.)b
+will produce:
+.ip longlabel
+This paragraph had a long label.
+The first character of text on the first line
+will not line up with the text on second and subsequent lines,
+although they will line up with each other.
+.pp
+It is possible to change the size of the label
+by using a second argument
+which is the size of the label.
+For example,
+the above example could be done correctly
+by saying:
+.(b
+\&.ip longlabel 10
+.)b
+which will make the paragraph indent
+10 spaces for this paragraph only.
+If you have many paragraphs to indent
+all the same amount,
+use the
+.i "number register"
+.b ii .
+For example, to leave one inch of space
+for the label,
+type:
+.(b
+\&.nr ii 1i
+.)b
+somewhere before the first call to
+.b .ip .
+Refer to the reference manual
+for more information.
+.pp
+If
+.b .ip
+is used
+with no argument at all
+no hanging tag will be printed.
+For example,
+the input:
+.(b
+\&.ip [a]
+This is the first paragraph of the example.
+We have seen this sort of example before.
+\&.ip
+This paragraph is lined up with the previous paragraph,
+but it has no tag in the margin.
+.)b
+produces as output:
+.ip [a]
+This is the first paragraph of the example.
+We have seen this sort of example before.
+.ip
+This paragraph is lined up with the previous paragraph,
+but it has no tag in the margin.
+.pp
+A special case of
+.b .ip
+is
+.b .np ,
+which automatically
+numbers paragraphs sequentially from 1.
+The numbering is reset at the next
+.b .pp ,
+.b .lp ,
+or
+.b .sh
+(to be described in the next section)
+request.
+For example,
+the input:
+.(b
+\&.np
+This is the first point.
+\&.np
+This is the second point.
+Points are just regular paragraphs
+which are given sequence numbers automatically
+by the .np request.
+\&.pp
+This paragraph will reset numbering by .np.
+\&.np
+For example,
+we have reverted to numbering from one now.
+.)b
+generates:
+.np
+This is the first point.
+.np
+This is the second point.
+Points are just regular paragraphs
+which are given sequence numbers automatically
+by the .np request.
+.pp
+This paragraph will reset numbering by .np.
+.np
+For example,
+we have reverted to numbering from one now.
+.pp
+The
+.b .bu
+request gives lists of this sort that are identified with
+bullets rather than numbers.
+The paragraphs are also crunched together.
+For example,
+the input:
+.(b
+\&.bu
+\&One egg yolk
+\&.bu
+\&One tablespoon cream or top milk
+\&.bu
+\&Salt, cayenne, and lemon juice to taste
+\&.bu
+\&A generous two tablespoonfuls of butter
+.)b
+produces\**:
+.(f
+\**By the way,
+if you put the first three ingredients in a a heavy, deep pan
+and whisk the ingredients madly over a medium flame
+(never taking your hand off the handle of the pot)
+until the mixture reaches the consistency of custard
+(just a minute or two),
+then mix in the butter off-heat,
+you will have a wonderful Hollandaise sauce.
+.)f
+.bu
+One egg yolk
+.bu
+One tablespoon cream or top milk
+.bu
+Salt, cayenne, and lemon juice to taste
+.bu
+A generous two tablespoonfuls of butter
+.sh 2 "Section Headings"
+.pp
+Section numbers
+(such as the ones used in this document)
+can be automatically generated
+using the
+.b .sh
+request.
+You must tell
+.b .sh
+the
+.i depth
+of the section number
+and a section title.
+The depth
+specifies how many numbers
+are to appear
+(separated by decimal points)
+in the section number.
+For example,
+the section number
+.b 4.2.5
+has a depth of three.
+.pp
+Section numbers
+are incremented
+in a fairly intuitive fashion.
+If you add a number
+(increase the depth),
+the new number starts out
+at one.
+If you subtract section numbers
+(or keep the same number)
+the final number is incremented.
+For example,
+the input:
+.(b
+\&.sh 1 "The Preprocessor"
+\&.sh 2 "Basic Concepts"
+\&.sh 2 "Control Inputs"
+\&.sh 3
+\&.sh 3
+\&.sh 1 "Code Generation"
+\&.sh 3
+.)b
+produces as output the result:
+.(b
+.b
+1. The Preprocessor
+1.1. Basic Concepts
+1.2. Control Inputs
+1.2.1.
+1.2.2.
+2. Code Generation
+2.1.1.
+.)b
+.pp
+You can specify the section number to begin
+by placing the section number after the section title,
+using spaces instead of dots.
+For example,
+the request:
+.(b
+\&.sh 3 "Another section" 7 3 4
+.)b
+will begin the section numbered
+.b 7.3.4 ;
+all subsequent
+.b .sh
+requests will number relative to this number.
+.pp
+There are more complex features
+which will cause each section to be indented
+proportionally to the depth of the section.
+For example, if you enter:
+.(b
+\&.nr si \c
+.i N
+.)b
+each section will be indented by an amount
+.i N .
+.i N
+must have a scaling factor attached,
+that is, it must be of the form
+.i Nx ,
+where
+.i x
+is a character telling what units
+.i N
+is in.
+Common values for
+.i x
+are
+.b i
+for inches,
+.b c
+for centimeters,
+and
+.b n
+for
+.i ens
+(the width of a single character).
+For example,
+to indent each section
+one-half inch,
+type:
+.(b
+\&.nr si 0.5i
+.)b
+After this,
+sections will be indented by
+one-half inch
+per level of depth in the section number.
+For example,
+this document was produced
+using the request
+.(b
+\&.nr si 3n
+.)b
+at the beginning of the input file,
+giving three spaces of indent
+per section depth.
+.pp
+Section headers without automatically generated numbers
+can be done using:
+.(b
+\&.uh "Title"
+.)b
+which will do a section heading,
+but will put no number on the section.
+.sh 2 "Parts of the Basic Paper"
+.pp
+There are some requests
+which assist in setting up
+papers.
+The
+.b .tp
+request
+initializes for a title page.
+There are no headers or footers
+on a title page,
+and unlike other pages
+you can space down
+and leave blank space
+at the top.
+For example,
+a typical title page might appear as:
+.(b
+\&.tp
+\&.sp 2i
+\&.(l C
+THE GROWTH OF TOENAILS
+IN UPPER PRIMATES
+\&.sp
+by
+\&.sp
+Frank N. Furter
+\&.)l
+\&.bp
+.)b
+.pp
+The
+.b .+c \ \c
+.i T
+request can be used
+to start chapters.
+Each chapter is automatically numbered
+from one,
+and a heading is printed at the top of each chapter
+with the chapter number
+and the chapter name
+.i T .
+For example,
+to begin a chapter called
+.q Conclusions ,
+use the request:
+.(b
+\&.+c "CONCLUSIONS"
+.)b
+which will produce,
+on a new page,
+the lines
+.(b C
+CHAPTER 5
+CONCLUSIONS
+.)b
+with appropriate spacing for a thesis.
+Also, the header is moved to the foot of the page
+on the first page of a chapter.
+Although the
+.b .+c
+request was not designed to work only with the
+.b .th
+request,
+it is tuned for the format acceptable
+for a PhD thesis
+at Berkeley.
+.pp
+If the
+title parameter
+.i T
+is omitted from the
+.b .+c
+request,
+the result is a chapter with no heading.
+This can also be used at the beginning
+of a paper;
+for example,
+.b .+c
+was used to generate page one
+of this document.
+.pp
+Although
+papers traditionally have the abstract,
+table of contents,
+and so forth at the front of the paper,
+it is more convenient to format
+and print them last
+when using \*G.
+This is so that index entries
+can be collected and then printed
+for the table of contents
+(or whatever).
+At the end of the paper,
+issue the
+.b ".++ P"
+request,
+which begins the preliminary part
+of the paper.
+After issuing this request,
+the
+.b .+c
+request will begin a preliminary section
+of the paper.
+Most notably,
+this prints the page number
+restarted from one
+in lower case Roman numbers.
+.b .+c
+may be used repeatedly
+to begin different parts of the
+front material
+for example,
+the abstract,
+the table of contents,
+acknowledgments,
+list of illustrations,
+etc.
+The request
+.b ".++ B"
+may also be used
+to begin the bibliographic section
+at the end of the paper.
+For example,
+the paper might appear
+as outlined in figure 2.
+(In this figure,
+comments begin with the sequence
+.b \e" .)
+.(z
+.hl
+.if t .in 0.5i
+.if t .ta 2i
+.if n .ta 3i
+\&.th \e" set for thesis mode
+\&.fo \(aa\(aaDRAFT\(aa\(aa \e" define footer for each page
+\&.tp \e" begin title page
+\&.(l C \e" center a large block
+THE GROWTH OF TOENAILS
+IN UPPER PRIMATES
+\&.sp
+by
+\&.sp
+Frank Furter
+\&.)l \e" end centered part
+\&.+c INTRODUCTION \e" begin chapter named "INTRODUCTION"
+\&.(x t \e" make an entry into index `t'
+Introduction
+\&.)x \e" end of index entry
+text of chapter one
+\&.+c "NEXT CHAPTER" \e" begin another chapter
+\&.(x t \e" enter into index `t' again
+Next Chapter
+\&.)x
+text of chapter two
+\&.+c CONCLUSIONS
+\&.(x t
+Conclusions
+\&.)x
+text of chapter three
+\&.++ B \e" begin bibliographic information
+\&.+c BIBLIOGRAPHY \e" begin another `chapter'
+\&.(x t
+Bibliography
+\&.)x
+text of bibliography
+\&.++ P \e" begin preliminary material
+\&.+c "TABLE OF CONTENTS"
+\&.xp t \e" print index `t' collected above
+\&.+c PREFACE \e" begin another preliminary section
+text of preface
+.sp 2
+.in 0
+.ce
+Figure 2. Outline of a Sample Paper
+.hl
+.)z
+.sh 2 "Equations and Tables"
+.pp
+Two special \*U programs exist
+to format special types of material.
+.b Eqn
+sets equations.
+.b Tbl
+arranges to print
+extremely pretty tables
+in a variety of formats.
+This document will only describe
+the embellishments
+to the standard features;
+consult the reference manuals
+for those processors
+for a description of their use.
+.pp
+The
+.b eqn
+program is described fully
+in the document
+.ul
+Typesetting Mathematics \- User's Guide
+by Brian W. Kernighan
+and Lorinda L. Cherry.
+Equations are centered,
+and are kept on one page.
+They are introduced by the
+.b .EQ
+request and terminated by the
+.b .EN
+request.
+.pp
+The
+.b .EQ
+request may take an
+equation number as an
+optional argument,
+which is printed vertically centered
+on the right hand side
+of the equation.
+If the equation becomes too long
+it should be split
+between two lines.
+To do this, type:
+.(b
+\&.EQ (eq 34)
+text of equation 34
+\&.EN C
+\&.EQ
+continuation of equation 34
+\&.EN
+.)b
+The
+.b C
+on the
+.b .EN
+request
+specifies that the equation
+will be continued.
+.pp
+The
+.b tbl
+program produces tables.
+It is fully described
+(including numerous examples)
+in the document
+.ul
+Tbl \- A Program to Format Tables
+by M. E. Lesk.
+Tables begin with the
+.b .TS
+request
+and end with the
+.b .TE
+request.
+Tables are normally kept on a single page.
+If you have a table which is too big
+to fit on a single page,
+so that you know it will extend
+to several pages,
+begin the table with the request
+.b ".TS\ H"
+and put the request
+.b .TH
+after the part of the table
+which you want
+duplicated at the top of every page
+that the table is printed on.
+For example, a table definition
+for a long table might look like:
+.ds TA \|\h'.4n'\v'-.2n'\s-4\zT\s0\v'.2n'\h'-.4n'\(ci\|
+.if n .ds TA \ \o'-T'\ \"
+.(b
+\&.TS H
+c s s
+n n n.
+THE TABLE TITLE
+\&.TH
+text of the table
+\&.TE
+.)b
+.pp
+.sh 2 "Two Column Output"
+.pp
+You can get two column output
+automatically
+by using the request
+.b .2c .
+This causes everything after it
+to be output in two-column form.
+The request
+.b .bc
+will start a new column;
+it differs from
+.b .bp
+in that
+.b .bp
+may leave a totally blank column
+when it starts a new page.
+To revert to single column output,
+use
+.b .1c .
+.sh 2 "Defining Macros"
+.pp
+A
+.i macro
+is a collection of requests and text
+which may be used
+by stating a simple request.
+Macros begin with the line
+.b ".de" \ \c
+.i xx
+(where
+.i xx
+is the name of the macro to be defined)
+and end with the line consisting of two dots.
+After defining the macro,
+stating the line
+.b . \c
+.i xx
+is the same as stating all the other lines.
+For example,
+to define a macro
+that spaces 3 lines
+and then centers the next input line,
+enter:
+.(b
+\&.de SS
+\&.sp 3
+\&.ce
+\&..
+.)b
+and use it by typing:
+.(b
+\&.SS
+\&Title Line
+(beginning of text)
+.)b
+.pp
+Macro names may be one or two characters.
+In order to avoid conflicts
+with names in \-me,
+always use upper case letters as names.
+The only names to avoid are
+.b TS ,
+.b TH ,
+.b TE ,
+.b EQ ,
+and
+.b EN .
+.sh 2 "Annotations Inside Keeps"
+.pp
+Sometimes you may want to put
+a footnote
+or index entry inside a keep.
+For example,
+if you want to maintain a
+.q "list of figures"
+you will want to do something like:
+.(b
+\&.(z
+\&.(c
+text of figure
+\&.)c
+\&.ce
+Figure 5.
+\&.(x f
+Figure 5
+\&.)x
+\&.)z
+.)b
+which you may hope
+will give you a figure
+with a label
+and an entry in the index
+.b f
+(presumably a list of figures index).
+Unfortunately,
+the
+index entry
+is read and interpreted
+when the keep is read,
+not when it is printed,
+so the page number in the index is likely to be wrong.
+The solution is to use the magic string
+.b \e!
+at the beginning of all the lines dealing with the index.
+In other words,
+you should use:
+.(b
+\&.(z
+\&.(c
+Text of figure
+\&.)c
+\&.ce
+Figure 5.
+\e!.(x f
+\e!Figure 5
+\e!.)x
+\&.)z
+.)b
+which will defer the processing of the index
+until the figure is output.
+This will guarantee
+that the page number in the index
+is correct.
+The same comments apply
+to
+blocks
+(with
+.b .(b
+and
+.b .)b )
+as well.
+.sh 1 "\*T and the Photosetter"
+.pp
+With a little care,
+you can prepare
+documents that
+will print nicely
+on either a regular terminal
+or when phototypeset
+using the \*T formatting program.
+.sh 2 "Fonts"
+.pp
+A
+.i font
+is a style of type.
+There are three fonts
+that are available simultaneously,
+Times Roman,
+Times Italic,
+and Times Bold,
+plus the special math font.
+The normal font is Roman.
+.pp
+There are ways of switching between fonts.
+The requests
+.b .r ,
+.b .i ,
+.b .b ,
+and
+.b .bi
+switch to Roman,
+italic,
+bold,
+and bold-italic fonts respectively.
+You can set a single word
+in some font
+by typing (for example):
+.(b
+\&.i word
+.)b
+which will set
+.i word
+in italics
+but does not affect the surrounding text.
+.pp
+Notice that if you are setting more than one word
+in whatever font,
+you must surround that word with double quote marks
+(`\|"\|')
+so that it will appear to the \*G processor as a single word.
+The quote marks will not appear in the formatted text.
+If you do want a quote mark to appear,
+you should quote the entire string
+(even if a single word),
+and use
+.i two
+quote marks where you want one to appear.
+For example,
+if you want to produce the text:
+.(b
+.i """Master Control\|"""
+.)b
+in italics, you must type:
+.(b
+\&.i """Master Control\e|"""
+.)b
+The
+.b \e|
+produces a very narrow space
+so that the
+.q l
+does not overlap the quote sign in \*G,
+like this:
+.(b
+.i """Master Control"""
+.)b
+.pp
+There are also some
+.q pseudo-fonts
+available.
+The input:
+.(b
+\&.(b
+\&.u underlined
+\&.bx "words in a box"
+\&.)b
+.)b
+generates
+.(b
+.u underlined
+.bx "words in a box"
+.)b
+Notice that pseudo font requests
+set only the single parameter in the pseudo font;
+ordinary font requests will begin setting all text
+in the special font
+if you do not provide a parameter.
+No more than one word
+should appear
+with these three font requests
+in the middle of lines.
+This is because
+of the way \*G justifies text.
+For example,
+if you were to issue the requests:
+.(b
+\&.u "some bold italics"
+and
+\&.bx "words in a box"
+.)b
+in the middle of a line
+\*G would produce
+.u "some bold italics"
+and
+.bx "words in a box" ,\p
+which I think you will agree does not look good.
+.pp
+The second parameter
+of all font requests
+is set in the original font.
+For example,
+the font request:
+.(b
+\&.b bold face
+.)b
+generates
+.q bold
+in bold font,
+but sets
+.q face
+in the font of the surrounding text,
+resulting in:
+.(b
+.b bold face.
+.)b
+To set the two words
+.b bold
+and
+.b face
+both in
+.b "bold face" ,
+type:
+.(b
+\&.b "bold face"
+.)b
+.pp
+You can mix fonts in a word by using the
+special sequence
+.b \ec
+at the end of a line
+to indicate
+.q "continue text processing" ;
+this allows input lines
+to be joined together
+without a space between them.
+For example, the input:
+.(b
+\&.u under \ec
+\&.i italics
+.)b
+generates
+.u under \c
+.i italics ,
+but if we had typed:
+.(b
+\&.u under
+\&.i italics
+.)b
+the result would have been
+.u under
+.i italics
+as two words.
+.sh 2 "Point Sizes"
+.pp
+The phototypesetter
+supports different sizes of type,
+measured in points.
+The default point size
+is 10 points
+for most text,
+8 points for footnotes.
+To change the pointsize,
+type:
+.(b
+\&.sz \c
+.i +N
+.)b
+where
+.i N
+is the size wanted in points.
+The
+.i "vertical spacing"
+(distance between the bottom of most letters
+(the
+.i baseline )
+between adjacent lines)
+is set to be proportional
+to the type size.
+.pp
+These pointsize changes are
+.i temporary !!!
+For example,
+to reset the pointsize of basic text to twelve point, use:
+.(b
+\&.nr pp 12
+\&.nr sp 12
+\&.nr tp 12
+.)b
+to reset the default pointsize of
+paragraphs,
+section headers,
+and titles respectively.
+If you only want to set the names of sections in a larger pointsize,
+use:
+.(b
+\&.nr sp 11
+.)b
+alone \*- this sets section titles
+(e.g.,
+.b "Point Sizes"
+above)
+in a larger font than the default.
+.pp
+A single word or phrase can be set in a smaller pointsize
+than the surrounding text
+using the
+.b .sm
+request.
+This is especially convenient for words that are all capitals,
+due to the optical illusion that makes them look even larger
+than they actually are.
+For example:
+.(b
+\&.sm UNIX
+.)b
+prints as
+.sm UNIX
+rather than
+UNIX.
+.pp
+Warning:
+changing point sizes
+on the phototypesetter
+is a slow mechanical operation.
+On laser printers it may require loading new fonts.
+Size changes
+should be considered carefully.
+.sh 2 "Quotes"
+.pp
+It is conventional when using
+the typesetter to
+use pairs of grave and acute accents
+to generate double quotes,
+rather than the
+double quote character
+(`\|"\|').
+This is because it looks better
+to use grave and acute accents;
+for example, compare
+"quote" to
+``quote''.
+.pp
+You may use the sequences
+.b \e*(lq
+and
+.b \e*(rq
+to stand for the left and right quote
+respectively.
+For example,
+use:
+.(b
+\e*(lqSome things aren\(aat true
+even if they did happen.\e*(rq
+.)b
+to generate the result:
+.(b
+.q "Some things aren't true even if they did happen."
+.)b
+As a shorthand,
+the special font request:
+.(b
+\&.q "quoted text"
+.)b
+will generate
+.q "quoted text" .
+Notice that you must surround
+the material to be quoted
+with double quote marks
+if it is more than one word.
+.sh 0
+.sp 1i
+.b Acknowledgments
+.pp
+I would like to thank
+Bob Epstein,
+Bill Joy,
+and Larry Rowe
+for having the courage
+to use the \-me macros
+to produce non-trivial papers
+during the development stages;
+Ricki Blau,
+Pamela Humphrey,
+and Jim Joyce
+for their help with the documentation phase;
+peter kessler
+for numerous complaints years after I was
+.q done
+with this project,
+most accompanied by fixes
+(hence forcing me to fix several small bugs);
+and the plethora of people who have contributed ideas
+and have given support for the project.
+.sp 1i
+This document was
+\*G'ed
+on \*(td
+and applies to the version of the \-me macros
+included with \*G version \*(MO.
diff --git a/gnu/usr.bin/groff/doc/meref.me b/gnu/usr.bin/groff/doc/meref.me
new file mode 100644
index 0000000..9cc2c76
--- /dev/null
+++ b/gnu/usr.bin/groff/doc/meref.me
@@ -0,0 +1,2194 @@
+.\" Copyright (c) 1986 The Regents of the University of California.
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms are permitted
+.\" provided that the above copyright notice and this paragraph are
+.\" duplicated in all such forms and that any documentation,
+.\" advertising materials, and other materials related to such
+.\" distribution and use acknowledge that the software was developed
+.\" by the University of California, Berkeley. The name of the
+.\" University may not be used to endorse or promote products derived
+.\" from this software without specific prior written permission.
+.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+.\" IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+.\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+.\"
+.\" @(#)ref.me 6.4 (Berkeley) 7/17/89
+.\"
+.\" Modified by jjc@jclark.com for groff.
+.\"UC 7
+.ll 6.5i
+.lt 6.5i
+.\"pn 0
+.ds MO @VERSION@
+.de TL \" *** title line
+.lp
+.di XX
+..
+.ie \n(.g \{\
+.de DE
+\?\h'|\\n(DIu'\c\?
+..
+.\}
+.el \{\
+.de DE
+\\\\h'|\\\\n(DIu'\\\\c
+..
+.\}
+.am DE
+.br
+.di
+.in +\\n(DIu
+.ti 0
+.cu 1000
+.XX
+.rm XX
+.cu 0
+..
+.ds G \s-1GROFF\s0
+.ds N \s-1NROFF\s0
+.ds T \s-1TROFF\s0
+.nr DI 1.5i
+.he '\-ME REFERENCE MANUAL''%'
+.de NR
+.b "\en\\$1" "\\$2"
+..
+.de ST
+.b "\e*\\$1" "\\$2"
+..
+.\"sc
+.\"eh 'USD:23-%''\-me Reference Manual'
+.\"oh '\-me Reference Manual''USD:23-%'
+.+c
+.ce 20
+.sz 14
+.b "\-ME REFERENCE MANUAL"
+.sz
+.sp
+.i "\*G Version \*(MO\(dg"
+.(f
+\(dgBased on Berkeley Release 2.31.
+.)f
+.sp 2
+.ul
+Eric P. Allman*
+.(f
+*Author's current address:
+Britton Lee, Inc.,
+1919 Addison Suite 105,
+Berkeley, California 94704.
+.)f
+.sp
+Project INGRES
+Electronics Research Laboratory
+University of California, Berkeley
+Berkeley, California 94720
+.sp 2
+.i "Modified for \*G by James Clark"
+.ce 0
+.sp 4
+.pp
+This document describes
+in extremely terse form
+the features
+of the
+.b \-me
+macro package
+for \*G.
+Some familiarity is assumed
+with
+\*G.
+Specifically,
+the reader should understand
+breaks,
+fonts,
+pointsizes,
+the use and definition of number registers
+and strings,
+how to define macros,
+and scaling factors for ens, points,
+.b v 's
+(vertical line spaces),
+etc.
+.pp
+For a more casual introduction
+to text processing
+using \*G,
+refer to the document
+.ul
+Writing Papers with \*G using \-me.
+.pp
+There are a number of macro parameters
+that may be adjusted.
+Fonts may be set to a font number only.
+Font 0 is no font change;
+the font of the surrounding text
+is used instead.
+Notice that font 0 is a
+.q pseudo-font ;
+that is,
+it is simulated by the macros.
+This means that although it is legal to set a font register
+to zero,
+it is not legal to use the escape character form,
+such as:
+.(b
+\ef0
+.)b
+.pp
+All distances
+are in basic units,
+so it is nearly always necessary
+to use a scaling factor.
+For example,
+the request
+to set the paragraph indent
+to eight one-en spaces is:
+.(b
+\&.nr pi 8n
+.)b
+and not
+.(b
+\&.nr pi 8
+.)b
+which would set the paragraph indent to eight basic units,
+or about 0.02 inch.
+Default parameter values are given in brackets
+in the remainder of this document.
+.pp
+Registers and strings
+of the form
+.b $ \c
+.i x
+may be used in expressions
+but should not be changed.
+Macros of the form
+.b $ \c
+.i x
+perform some function
+(as described)
+and may be redefined
+to change this function.
+This may be a sensitive operation;
+look at the body of the original macro
+before changing it.
+.pp
+All names in \-me
+follow a rigid naming convention.
+The user may define number registers,
+strings,
+and macros,
+provided that s/he
+uses single character upper case names
+or double character names
+consisting of letters and digits,
+with at least one upper case letter.
+In no case should special characters
+be used in user-defined names.
+Locally defined macros
+should all be of the form
+.b .* \c
+.i X ,
+where
+.i X
+is any letter
+(upper or lower case)
+or digit.
+.pp
+This documentation was \*G'ed
+on \*(td
+and applies to \*G version
+\*(MO
+of the \-me macros.
+.sh 1 "Paragraphing"
+.pp
+These macros are used
+to begin paragraphs.
+The standard paragraph macro
+is
+.b .pp ;
+the others are all variants
+to be used for special purposes.
+.pp
+After the first call to one of the paragraphing macros
+defined in this section
+or the
+.b .sh
+macro
+(defined in the next session),
+the effects of changing parameters
+which will have a global effect
+on the format of the page
+(notably page length and header and footer margins)
+are not well defined
+and should be avoided.
+.TL
+.b .lp
+.DE
+Begin left-justified paragraph.
+Centering and underlining
+are turned off if they were on,
+the font is set to
+.NR (pf
+[1]
+the type size
+is set to
+.NR (pp
+[10p],
+and a
+.NR (ps
+space is inserted
+before the paragraph
+[0.35v]
+The indent is reset
+to
+.NR ($i
+[0]
+plus
+.NR (po
+[0]
+unless the paragraph
+is inside a display.
+(see
+.b .ba ).
+At least
+the first two lines
+of the paragraph
+are kept together
+on a page.
+.TL
+.b .pp
+.DE
+Like
+.b .lp ,
+except that it puts
+.NR (pi
+[5n]
+units of indent.
+This is the standard paragraph macro.
+.TL
+.b .ip
+.i T
+.i I
+.DE
+Indented paragraph
+with hanging tag.
+The body of the following paragraph
+is indented
+.i I
+spaces
+(or
+.NR (ii
+[5n]
+spaces
+if
+.i I
+is not specified)
+more than a non-indented paragraph
+(such as with
+.b .pp )
+is.
+The title
+.i T
+is exdented (opposite of indented).
+The result is a paragraph
+with an even left edge
+and
+.i T
+printed in the margin.
+Any spaces in
+.i T
+must be unpaddable.
+If
+.i T
+will not fit in the space provided,
+.b .ip
+will start a new line.
+.TL
+.b .np
+.DE
+A variant of .ip which numbers paragraphs.
+Numbering is reset
+after a
+.b .lp ,
+.b .pp ,
+or
+.b .sh .
+The current paragraph number
+is in
+.NR ($p .
+.TL
+.b .bu
+.DE
+Like
+.b .np
+except that paragraphs are marked with bullets (\(bu).
+Leading space is eliminated to create compact lists.
+.sh 1 "Section Headings"
+.pp
+Numbered sections
+are similar to paragraphs
+except that a
+section number
+is automatically
+generated for each one.
+The section numbers are of the form
+.b 1.2.3 .
+The
+.i depth
+of the section
+is the count of numbers
+(separated by decimal points)
+in the section number.
+.pp
+Unnumbered section headings are similar,
+except that no number is attached
+to the heading.
+.TL
+.b .sh
+.i +N
+.i T
+.i "a b c d e f"
+.DE
+Begin numbered section
+of depth
+.i N .
+If
+.i N
+is missing
+the current depth
+(maintained in
+the number register
+.NR ($0 )
+is used.
+The values of
+the individual parts of the section number
+are maintained in
+.NR ($1
+through
+.NR ($6 .
+There is a
+.NR (ss
+[1v]
+space before the section.
+.i T
+is printed
+as a section title
+in font
+.NR (sf
+[8]
+and size
+.NR (sp
+[10p].
+The
+.q name
+of the section may be accessed via
+.ST ($n .
+If
+.NR (si
+is non-zero,
+the base indent
+is set to
+.NR (si
+times the section depth,
+and the section title
+is exdented.
+(See
+.b .ba .)
+Also,
+an additional indent of
+.NR (so
+[0]
+is added to the section title
+(but not to the body of the section).
+The font is then set
+to the paragraph font,
+so that more information may occur
+on the line
+with the section number
+and title.
+.b .sh
+insures that there is enough room
+to print the section head
+plus the beginning of a paragraph
+(about 3 lines total).
+If
+.i a
+through
+.i f
+are specified,
+the section number is set to that number
+rather than incremented automatically.
+If any of
+.i a
+through
+.i f
+are a hyphen
+that number is not reset.
+If
+.i T
+is a single underscore
+(\c
+.q _ )
+then the section depth and numbering is reset,
+but the base indent is not reset
+and nothing is printed out.
+This is useful to automatically
+coordinate section numbers with
+chapter numbers.
+.TL
+.b .sx
+.i +N
+.DE
+Go to section depth
+.i N
+[\c
+.b \-1 ],
+but do not print the number
+and title,
+and do not increment the section number
+at level
+.i N .
+This has the effect
+of starting a new paragraph
+at level
+.i N .
+.TL
+.b .uh
+.i T
+.DE
+Unnumbered section heading.
+The title
+.i T
+is printed
+with the same rules for spacing,
+font, etc.,
+as for
+.b .sh .
+.TL
+.b .$p
+.i T
+.i B
+.i N
+.DE
+Print section heading.
+May be redefined
+to get fancier headings.
+.i T
+is the title passed on the
+.b .sh
+or
+.b .uh
+line;
+.i B
+is the section number for this section,
+and
+.i N
+is the depth of this section.
+These parameters are not always present;
+in particular,
+.b .sh
+passes all three,
+.b .uh
+passes only the first,
+and
+.b .sx
+passes three,
+but the first two
+are null strings.
+Care should be taken if this macro
+is redefined;
+it is quite complex and subtle.
+.TL
+.b .$0
+.i T
+.i B
+.i N
+.DE
+This macro is called automatically
+after every call to
+.b .$p .
+It is normally undefined,
+but may be used
+to automatically put
+every section title
+into the table of contents
+or for some similar function.
+.i T
+is the section title
+for the section title which was just printed,
+.i B
+is the section number,
+and
+.i N
+is the section depth.
+.TL
+.b .$1
+\-
+.b .$6
+.DE
+Traps called just before printing that depth section.
+May be defined to
+(for example)
+give variable spacing
+before sections.
+These macros are called from
+.b .$p ,
+so if you redefine that macro
+you may lose this feature.
+.sh 1 "Headers and Footers"
+.ds TP \fI\(aal\|\(aam\^\(aar\^\(aa\fP
+.pp
+Headers and footers
+are put at the top and bottom
+of every page
+automatically.
+They are set in font
+.NR (tf
+[3]
+and size
+.NR (tp
+[10p].
+Each of the definitions
+apply as of the
+.i next
+page.
+Three-part titles
+must be quoted
+if there are two blanks adjacent
+anywhere in the title
+or more than eight blanks total.
+.pp
+The spacing
+of headers and footers
+are controlled by three number registers.
+.NR (hm
+[4v]
+is the distance from the top of the page
+to the top of the header,
+.NR (fm
+[3v]
+is the distance from the bottom of the page
+to the bottom of the footer,
+.NR (tm
+[7v]
+is the distance from the top of the page
+to the top of the text,
+and
+.NR (bm
+[6v]
+is the distance from the bottom of the page
+to the bottom of the text
+(nominal).
+The macros
+.b .m1 ,
+.b .m2 ,
+.b .m3 ,
+and
+.b .m4
+are also supplied for compatibility
+with
+\s-1ROFF\s0 documents.
+.TL
+.b .he
+\*(TP
+.DE
+Define three-part header,
+to be printed on the top
+of every page.
+.TL
+.b .fo
+\*(TP
+.DE
+Define footer,
+to be printed at the bottom
+of every page.
+.TL
+.b .eh
+\*(TP
+.DE
+Define header,
+to be printed at the top of every
+even-numbered page.
+.TL
+.b .oh
+\*(TP
+.DE
+Define header,
+to be printed at the top of every
+odd-numbered page.
+.TL
+.b .ef
+\*(TP
+.DE
+Define footer,
+to be printed at the bottom
+of every even-numbered page.
+.TL
+.b .of
+\*(TP
+.DE
+Define footer,
+to be printed at the bottom
+of every odd-numbered page.
+.TL
+.b .hx
+.DE
+Suppress headers and footers
+on the next page.
+.TL
+.b .m1
+.i +N
+.DE
+Set the space between the top of the page
+and the header
+[4v].
+.TL
+.b .m2
+.i +N
+.DE
+Set the space between the header
+and the first line of text
+[2v].
+.TL
+.b .m3
+.i +N
+.DE
+Set the space
+between the bottom of the text
+and the footer
+[2v].
+.TL
+.b .m4
+.i +N
+.DE
+Set the space
+between the footer
+and the bottom of the page
+[4v].
+.TL
+.b .ep
+.DE
+End this page,
+but do not begin the next page.
+Useful for forcing out footnotes,
+but other than
+that hardly every used.
+Must be followed by a
+.b .bp
+or the end of input.
+.TL
+.b .$h
+.DE
+Called at every page
+to print the header.
+May be redefined
+to provide fancy
+(e.g.,
+multi-line)
+headers,
+but doing so
+loses the function of the
+.b .he ,
+.b .fo ,
+.b .eh ,
+.b .oh ,
+.b .ef ,
+and
+.b .of
+requests,
+as well as the chapter-style title feature
+of
+.b .+c .
+.TL
+.b .$f
+.DE
+Print footer;
+same comments apply
+as in
+.b .$h .
+.TL
+.b .$H
+.DE
+A normally undefined macro
+which is called
+at the top of each page
+(after putting out
+the header,
+initial saved floating keeps,
+etc.);
+in other words,
+this macro is called immediately before
+printing text
+on a page.
+It can be used for column headings
+and the like.
+.sh 1 "Displays"
+.pp
+All displays except centered blocks
+and block quotes
+are preceded and followed
+by an extra
+.NR (bs
+[same as
+.NR (ps ]
+space.
+Quote spacing is stored in a separate register;
+centered blocks have no default initial or trailing space.
+The vertical spacing of all displays except quotes
+and centered blocks
+is stored in register
+.NR ($V
+instead of
+.NR ($v .
+.TL
+.b .(l
+.i m
+.i f
+.DE
+Begin list.
+Lists are single spaced,
+unfilled text.
+If
+.i f
+is
+.b F ,
+the list will be filled.
+If
+.i m
+[\c
+.b I ]
+is
+.b I
+the list is indented by
+.NR (bi
+[4m];
+if
+.b M
+the list is indented to the left margin;
+if
+.b L
+the list is left justified with respect to the text
+(different from
+.b M
+only if the base indent
+(stored in
+.NR ($i
+and set with
+.b .ba )
+is not zero);
+and if
+.b C
+the list is centered on a line-by-line basis.
+The list is set in font
+.NR (df
+[0].
+Must be matched by a
+.b .)l .
+This macro is almost like
+.b .(b
+except that no attempt is made
+to keep the display on one page.
+.TL
+.b .)l
+.DE
+End list.
+.TL
+.b .(q
+.DE
+Begin major quote.
+These are single spaced,
+filled,
+moved in from the text
+on both sides
+by
+.NR (qi
+[4n],
+preceded and followed
+by
+.NR (qs
+[same as
+.NR (bs ]
+space,
+and are set in point size
+.NR (qp
+[one point smaller than surrounding text].
+.TL
+.b .)q
+.DE
+End major quote.
+.TL
+.b .(b
+.i m
+.i f
+.DE
+Begin block.
+Blocks are a form of
+.i keep ,
+where the text of a keep
+is kept together on one page
+if possible
+(keeps are useful
+for tables and figures
+which should not be broken
+over a page).
+If the block will not fit
+on the current page
+a new page is begun,
+.i unless
+that would leave more than
+.NR (bt
+[0]
+white space
+at the bottom of the text.
+If
+.NR (bt
+is zero, the threshold feature
+is turned off.
+Blocks are not filled
+unless
+.i f
+is
+.b F ,
+when they are filled.
+The block will be left-justified
+if
+.i m
+is
+.b L ,
+indented by
+.NR (bi
+[4m]
+if
+.i m
+is
+.b I
+or absent,
+centered
+(line-for-line)
+if
+.i m
+is
+.b C ,
+and left justified to the margin
+(not to the base indent)
+if
+.i m
+is
+.b M .
+The block is set in font
+.NR (df
+[0].
+.TL
+.b .)b
+.DE
+End block.
+.TL
+.b .(z
+.i m
+.i f
+.DE
+Begin floating keep.
+Like
+.b .(b
+except that the keep is
+.i floated
+to the bottom of the page
+or the top of the next page.
+Therefore,
+its position relative to the text changes.
+The floating keep is preceded and followed
+by
+.NR (zs
+[1v]
+space.
+Also,
+it defaults to mode
+.b M .
+.TL
+.b .)z
+.DE
+End floating keep.
+.TL
+.b .(c
+.DE
+Begin centered block.
+The next keep
+is centered as a block,
+rather than on a line-by-line basis
+as with
+.b ".(b C" .
+This call may be nested
+inside keeps.
+.TL
+.b .)c
+.DE
+End centered block.
+.sh 1 Annotations
+.TL
+.b .(d
+.DE
+Begin delayed text.
+Everything in the next keep
+is saved for output
+later with
+.b .pd ,
+in a manner
+similar to footnotes.
+.TL
+.b .)d
+.i n
+.DE
+End delayed text.
+The delayed text number register
+.NR ($d
+and the associated string
+.ST #
+are incremented if
+.ST #
+has been referenced.
+.TL
+.b .pd
+.DE
+Print delayed text.
+Everything diverted via
+.b .(d
+is printed and truncated.
+This might be used
+at the end of each chapter.
+.TL
+.b .(f
+.DE
+Begin footnote.
+The text of the footnote
+is floated to the bottom
+of the page
+and set in font
+.NR (ff
+[1]
+and size
+.NR (fp
+[8p].
+Each entry
+is preceded by
+.NR (fs
+[0.2v]
+space,
+is indented
+.NR (fi
+[3n]
+on the first line,
+and is indented
+.NR (fu
+[0]
+from the right margin.
+Footnotes line up underneath
+two column output.
+If the text of the footnote
+will not all fit on one page
+it will be carried over
+to the next page.
+.TL
+.b .)f
+.i n
+.DE
+End footnote.
+The number register
+.NR ($f
+and the associated string
+.ST *
+are incremented
+if they have been referenced.
+.TL
+.b .$s
+.DE
+The macro to output the footnote separator.
+This macro may be redefined
+to give other size lines or other types
+of separators.
+Currently
+it draws a 1.5i line.
+.TL
+.b .(x
+.i x
+.DE
+Begin index entry.
+Index entries are saved in the index
+.i x
+[\c
+.b x ]
+until called up with
+.b .xp.
+Each entry is preceded
+by a
+.NR (xs
+[0.2v]
+space.
+Each entry is
+.q undented
+by
+.NR (xu
+[0.5i];
+this register tells how far the page number
+extends into the right margin.
+.TL
+.b .)x
+.i P
+.i A
+.DE
+End index entry.
+The index entry
+is finished with a row of dots
+with
+.i A
+[null]
+right justified on the last line
+(such as for an author's name),
+followed by P
+[\c
+.NR % ].
+If
+.i A
+is specified,
+.i P
+must be specified;
+.NR %
+can be used to print the current page number.
+If
+.i P
+is an underscore,
+no page number
+and no row of dots
+are printed.
+.TL
+.b .xp
+.i x
+.DE
+Print index
+.i x
+[\c
+.b x ].
+The index is formatted in the font, size, and so forth
+in effect at the time it is printed,
+rather than at the time it is collected.
+.sh 1 "Columned Output"
+.TL
+.b .2c
+.i +S
+.i N
+.DE
+Enter two-column mode.
+The column separation is set to
+.i +S
+[4n, 0.5i in ACM mode]
+(saved in
+.NR ($s ).
+The column width,
+calculated to fill the single column line length
+with both columns,
+is stored in
+.NR ($l .
+The current column
+is in
+.NR ($c .
+You can test register
+.NR ($m
+[1]
+to see if you are in single column
+or double column mode.
+Actually,
+the request enters
+.i N
+[2]
+column output.
+.TL
+.b .1c
+.DE
+Revert to single-column mode.
+.TL
+.b .bc
+.DE
+Begin column.
+This is like
+.b .bp
+except that it begins a new column
+on a new page
+only if necessary,
+rather than forcing a whole new page
+if there is another column left
+on the current page.
+.sh 1 "Fonts and Sizes"
+.TL
+.b .sz
+.i +P
+.DE
+The pointsize is set to
+.i P
+[10p],
+and the line spacing is set proportionally.
+The line spacing as a percentage of the pointsize expressed in units
+is stored in
+.NR ($v .
+The percentage used internally
+by displays and annotations
+is stored in
+.NR ($V
+(although this is not used by
+.b .sz ).
+This size is
+.i not
+sticky beyond many macros:
+in particular,
+.NR (pp
+(paragraph pointsize)
+modifies the pointsize every time a new paragraph is begun
+using the
+.b \&.pp ,
+.b \&.lp ,
+.b \&.ip ,
+.b \&.np ,
+or
+.b \&.bu
+macros.
+Also,
+.NR (fp
+(footnote pointsize),
+.NR (qp
+(quote pointsize),
+.NR (sp
+(section header pointsize),
+and
+.NR (tp
+(title pointsize)
+may modify the pointsize.
+.TL
+.b .r
+.i W
+.i X
+.DE
+Set
+.i W
+in roman font,
+appending
+.i X
+in the previous font.
+To append different font requests,
+use
+.i X
+=
+.b \ec .
+If no parameters,
+change to roman font.
+.TL
+.b .i
+.i W
+.i X
+.DE
+Set
+.i W
+in italics,
+appending
+.i X
+in the previous font.
+If no parameters,
+change to italic font.
+.TL
+.b .b
+.i W
+.i X
+.DE
+Set
+.i W
+in bold font
+and append
+.i X
+in the previous font.
+If no parameters,
+switch to bold font.
+.TL
+.b .u
+.i W
+.i X
+.DE
+Underline
+.i W
+and append
+.i X .
+This is a true underlining,
+as opposed to the
+.b .ul
+request,
+which changes to
+.q "underline font"
+(usually italics in \*G).
+It won't work right
+if
+.i W
+is spread or broken (including hyphenated).
+In other words,
+it is safe in nofill mode only.
+.TL
+.b .q
+.i W
+.i X
+.DE
+Quote
+.i W
+and append
+.i X .
+In \*G
+this surrounds
+.i W
+with
+.b \*(lq ,
+and
+.b \*(rq .
+.TL
+.b .bi
+.i W
+.i X
+.DE
+Set
+.i W
+in bold italics
+and append
+.i X .
+.TL
+.b .bx
+.i W
+.i X
+.DE
+Sets
+.i W
+in a box,
+with
+.i X
+appended.
+It won't work right
+if
+.i W
+is spread or broken (including hyphenated).
+In other words,
+it is safe in nofill mode only.
+.TL
+.b sm
+.i W
+.i X
+.DE
+Sets
+.i W
+in a smaller pointsize,
+with
+.i X
+appended.
+.sh 1 "Roff Support"
+.TL
+.b .ix
+.i +N
+.DE
+Indent,
+no break.
+Equivalent to
+.b \(aain
+.i N .
+.TL
+.b .bl
+.i N
+.DE
+Leave
+.i N
+contiguous white space,
+on the next page if not enough room
+on this page.
+Equivalent to a
+.b .sp
+.i N
+inside a block.
+.TL
+.b .pa
+.i +N
+.DE
+Equivalent to
+.b .bp .
+.TL
+.b .ro
+.DE
+Set page number
+in roman numerals.
+Equivalent to
+.b ".af % i" .
+.TL
+.b .ar
+.DE
+Set page number in Arabic.
+Equivalent to
+.b ".af % 1" .
+.TL
+.b .n1
+.DE
+Number lines in margin from one
+on each page.
+.TL
+.b .n2
+.i N
+.DE
+Number lines from
+.i N ,
+stop if
+.i N
+= 0.
+.TL
+.b .sk
+.DE
+Leave the next output page blank,
+except for headers and footers.
+This is used to leave space
+for a full-page diagram
+which is produced externally
+and pasted in later.
+To get a partial-page paste-in display,
+say
+.b .sv \ \c
+.i N ,
+where
+.i N
+is the amount of space
+to leave;
+this space will be output immediately
+if there is room,
+and will otherwise be output
+at the top of the next page.
+However, be warned:
+if
+.i N
+is greater than the amount of available space
+on an empty page,
+no space will ever be output.
+.sh 1 "Preprocessor Support"
+.TL
+.b .EQ
+.i m
+.i T
+.DE
+Begin equation.
+The equation is centered
+if
+.i m
+is
+.b C
+or omitted,
+indented
+.NR (bi
+[4m]
+if
+.i m
+is
+.b I ,
+and left justified if
+.i m
+is
+.b L .
+.i T
+is a title printed on the right margin
+next to the equation.
+See
+.i "Typesetting Mathematics \- User's Guide"
+by Brian W. Kernighan
+and Lorinda L. Cherry.
+.TL
+.b .EN
+.i c
+.DE
+End equation.
+If
+.i c
+is
+.b C
+the equation must be continued
+by immediately following
+with another
+.b .EQ ,
+the text of which
+can be centered
+along with this one.
+Otherwise,
+the equation is printed,
+always on one page,
+with
+.NR (es
+[0.5v]
+space
+above and below it.
+.TL
+.b .TS
+.i h
+.DE
+Table start.
+Tables are single spaced
+and kept on one page
+if possible.
+If you have a large table
+which will not fit on one page,
+use
+.i h
+=
+.b H
+and follow the header part
+(to be printed on every page of the table)
+with a
+.b .TH .
+See
+.i "Tbl \- A Program to Format Tables"
+by M. E. Lesk.
+.TL
+.b .TH
+.DE
+With
+.b ".TS H" ,
+ends the header portion of the table.
+.TL
+.b .TE
+.DE
+Table end.
+Note that this table
+does not float,
+in fact,
+it is not even guaranteed to stay on one page
+if you use requests such as
+.b .sp
+intermixed with the text
+of the table.
+If you want it to float
+(or if you use requests
+inside the table),
+surround the entire table
+(including the
+.b .TS
+and
+.b .TE
+requests)
+with the requests
+.b .(z
+and
+.b .)z .
+.TL
+.b .PS
+.i h
+.i w
+.DE
+Begin
+.i pic
+picture.
+.i H
+is the height and
+.i w
+is the width,
+both in basic units.
+.TL
+.b .PE
+.DE
+End picture.
+.TL
+.b .IS
+.DE
+Begin
+.i ideal
+picture.
+.TL
+.b .IE
+.DE
+End
+.i ideal
+picture.
+.TL
+.b .IF
+.DE
+End
+.i ideal
+picture (alternate form).
+.TL
+.b .GS
+.DE
+Begin
+.i gremlin
+picture.
+.TL
+.b .GE
+.DE
+End
+.i gremlin
+picture.
+.TL
+.b .GF
+.DE
+End
+.i gremlin
+picture (alternate form).
+.sh 1 "Miscellaneous"
+.TL
+.b .re
+.DE
+Reset tabs every 0.5i.
+.TL
+.b .ba
+.i +N
+.DE
+Set the base indent
+to
+.i +N
+[0]
+(saved in
+.NR ($i ).
+All paragraphs,
+sections,
+and displays
+come out indented by this amount.
+Titles and footnotes
+are unaffected.
+The
+.b .sh
+request performs a
+.b .ba
+request
+if
+.NR (si
+[0] is not zero,
+and sets the base indent to
+.NR (si \c
+.b * \c
+.NR ($0 .
+.TL
+.b .xl
+.i +N
+.DE
+Set the line length to
+.i N
+[6.0i].
+This differs
+from
+.b .ll
+because it only affects the current environment.
+.TL
+.b .ll
+.i +N
+.DE
+Set line length in all environments
+to
+.i N
+[6.0i].
+This should not be used
+after output has begun,
+and particularly not in two-column output.
+The current line length is stored in
+.NR ($l .
+.TL
+.b .hl
+.DE
+Draws a horizontal line
+the length of the page.
+This is useful
+inside floating keeps
+to differentiate
+between the text
+and the figure.
+.sh 1 "Standard Papers"
+.TL
+.b .tp
+.DE
+Begin title page.
+Spacing at the top of the page
+can occur,
+and headers and footers are suppressed.
+Also,
+the page number
+is not incremented
+for this page.
+.TL
+.b .++
+.i m
+.i H
+.DE
+This request defines the section of the paper
+which we are entering.
+The section type is defined by
+.i m .
+.b C
+means that we are entering the chapter portion
+of the paper,
+.b A
+means that we are entering the appendix portion
+of the paper,
+.b P
+means that the material following
+should be the preliminary portion
+(abstract, table of contents, etc.)
+portion of the paper,
+.b AB
+means that we are entering the abstract
+(numbered independently from 1
+in Arabic numerals),
+and
+.b B
+means that we are entering the bibliographic
+portion at the end of the paper.
+Also, the variants
+.b RC
+and
+.b RA
+are allowed,
+which specify renumbering of pages
+from one at the beginning of each
+chapter or appendix,
+respectively.
+The
+.i H
+parameter defines the new header.
+If there are any spaces in it,
+the entire header must be quoted.
+If you want the header to have the chapter number
+in it,
+Use the string
+.b "\e\e\e\en(ch" .
+For example, to number appendixes
+.b A.1
+etc.,
+type
+.b ".++ RA \(aa\(aa\(aa\e\e\e\en(ch.%\(aa" .
+Each section
+(chapter, appendix, etc.)
+should be preceded by the
+.b .+c
+request.
+It should be mentioned
+that it is easier when using
+\*T to put the front material
+at the end of the paper,
+so that the table of contents
+can be collected and put out;
+this material can then be physically
+moved to the beginning of the paper.
+.TL
+.b .+c
+.i T
+.DE
+Begin chapter with title
+.i T .
+The chapter number
+is maintained in
+.NR (ch .
+This register is incremented
+every time
+.b .+c
+is called with a parameter.
+The title and chapter number
+are printed by
+.b .$c .
+The header is moved to the footer
+on the first page
+of each chapter.
+If
+.i T
+is omitted,
+.b .$c
+is not called;
+this is useful for doing your own
+.q "title page"
+at the beginning of papers
+without a title page proper.
+.b .$c
+calls
+.b .$C
+as a hook so that chapter titles can be inserted
+into a table of contents automatically.
+The footnote numbering is reset to one.
+.TL
+.b .$c
+.i T
+.DE
+Print chapter number
+(from
+.NR (ch )
+and
+.i T .
+This macro can be redefined to your liking.
+It is defined by default
+to be acceptable
+for a PhD thesis
+at Berkeley.
+This macro calls
+.b $C ,
+which can be defined to make index entries,
+or whatever.
+.TL
+.b .$C
+.i K
+.i N
+.i T
+.DE
+This macro is called by
+.b .$c .
+It is normally undefined,
+but can be used to automatically insert
+index entries,
+or whatever.
+.i K
+is a keyword,
+either
+.q Chapter
+or
+.q Appendix
+(depending on the
+.b .++
+mode);
+.i N
+is the chapter or appendix number,
+and
+.i T
+is the chapter or appendix title.
+.sh 1 "Predefined Strings"
+.TL
+.ST *
+.DE
+Footnote number, actually
+.ST [ \c
+.NR ($f \c
+.ST ] .
+This macro is incremented
+after each call to
+.b .)f .
+.TL
+.ST #
+.DE
+Delayed text number.
+Actually
+[\c
+.NR ($d ].
+.TL
+.ST {
+.DE
+Superscript.
+This string gives upward movement
+and a change to a smaller point size.
+Extra space is left above the line
+to allow room for the superscript.
+.TL
+.ST }
+.DE
+Unsuperscript.
+Inverse to
+.ST { .
+For example,
+to produce a superscript
+you might type
+.b x \c
+.ST { \c
+.b 2 \c
+.ST } ,
+which will produce
+.b x\*{2\*} .
+.TL
+.ST <
+.DE
+Subscript.
+Extra space is left below the line
+to allow for the subscript.
+.TL
+.ST >
+.DE
+Inverse to
+.ST < .
+.TL
+.ST (dw
+.DE
+The day of the week,
+as a word.
+.TL
+.ST (mo
+.DE
+The month,
+as a word.
+.TL
+.ST (td
+.DE
+Today's date,
+directly printable.
+The date is of the form \*(td.
+Other forms of the date can be used
+by using
+.NR (dy
+(the day of the month;
+for example, \n(dy),
+.ST (mo
+(as noted above)
+or
+.NR (mo
+(the same,
+but as an ordinal number;
+for example, \*(mo is \n(mo),
+and
+.NR (yr
+(the last two digits of the current year).
+.TL
+.ST (lq
+.DE
+Left quote marks.
+.TL
+.ST (rq
+.DE
+Right quote.
+.TL
+.ST \-
+.DE
+.ie \w'\(34'>0 \(34
+.el 3/4
+em dash.
+.sh 1 "Special Characters and Marks"
+.pp
+There are a number of special characters
+and diacritical marks
+(such as accents)
+available through \-me.
+.ta 15 +5 +6
+.nf
+Name Usage Example
+Acute accent \e*\(aa a\e*\(aa a\*'
+Grave accent \e*\(ga e\e*\(ga e\*`
+Umlaut \e*: u\e*: u\*:
+Tilde \e*~ n\e*~ n\*~
+Caret \e*^ e\e*^ e\*^
+Cedilla \e*, c\e*, c\*,
+Czech \e*v e\e*v e\*v
+Circle \e*o A\e*o A\*o
+There exists \e*(qe \*(qe
+For all \e*(qa \*(qa
+.fi
+.sp 1i
+.b Acknowledgments
+.pp
+I would like to thank
+Bob Epstein,
+Bill Joy,
+and Larry Rowe
+for having the courage
+to use the \-me macros
+to produce non-trivial papers
+during the development stages;
+Ricki Blau,
+Pamela Humphrey,
+and Jim Joyce
+for their help with the documentation phase;
+peter kessler
+for numerous complaints,
+most accompanied by fixes;
+and the plethora of people who have contributed ideas
+and have given support for the project.
+.bp
+.b Summary
+.pp
+This alphabetical list summarizes all macros, strings, and number registers
+available in the \-me macros.
+Selected
+.i troff
+commands, registers, and functions are included as well;
+those listed can generally be used with impunity.
+.pp
+The columns are the name of the
+command, macro, register, or string;
+the type of the object,
+and the description.
+Types are
+.b M
+for macro or builtin command
+(invoked with
+.b \&.
+or
+.b \&\'
+in the first input column),
+.b S
+for a string
+(invoked with
+.b \e*
+or
+.b \e*( ),
+.b R
+for a number register
+(invoked with
+.b \en
+or
+.b \en( ),
+and
+.b F
+for a
+.i troff
+builtin function
+(invoked by preceding it with a single backslash).
+.pp
+Lines marked with \(sc are
+.i troff
+internal codes.
+Lines marked with \(dg or \(dd
+may be defined by the user to get special functions;
+\(dd indicates that these are defined by default
+and changing them may have unexpected side effects.
+Lines marked with \(de
+are specific to
+.i ditroff
+(device-independent
+.i troff ).
+.de $H
+.ev 1
+.ta \w'\e(space)\(sc\ 'u +\w'TYPE 'u
+NAME TYPE DESCRIPTION
+.ev
+..
+.(l
+.$H
+\e(space) F\(sc unpaddable space
+\e" F\(sc comment (to end of line)
+\e*# S optional delayed text tag string
+\e$\fI\&N\fP F\(sc interpolate argument \fI\&N\fP
+\en($0 R section depth
+\&.$0 M\(dg invoked after section title printed
+\en($1 R first section number
+\&.$1 M\(dg invoked before printing depth 1 section
+\en($2 R second section number
+\&.$2 M\(dg invoked before printing depth 2 section
+\en($3 R third section number
+\&.$3 M\(dg invoked before printing depth 3 section
+\en($4 R fourth section number
+\&.$4 M\(dg invoked before printing depth 4 section
+\en($5 R fifth section number
+\&.$5 M\(dg invoked before printing depth 5 section
+\en($6 R sixth section number
+\&.$6 M\(dg invoked before printing depth 6 section
+\&.$C M\(dg called at beginning of chapter
+\&.$H M\(dg text header
+\en($V R\(dd relative vertical spacing in displays
+\en($c R current column number
+\&.$c M\(dd print chapter title
+\en($d R delayed text number
+\en($f R footnote number
+\&.$f M\(dd print footer
+\&.$h M\(dd print header
+\en($i R paragraph base indent
+\en($l R column width
+\en($m R number of columns in effect
+\e*($n S section name
+\en($p R numbered paragraph number
+\&.$p M\(dd print section heading (internal macro)
+\en($s R column indent
+\&.$s M\(dd footnote separator (from text)
+\en($v R\(dd relative vertical spacing in text
+\en% R\(sc current page number
+\e& F\(sc zero width character, useful for hiding controls
+\e(\fI\&xx\fP F\(sc interpolate special character \fI\&xx\fP
+\&.(b M begin block
+\&.(c M begin centered block
+\&.(d M begin delayed text
+\&.(f M begin footnote
+\&.(l M begin list
+\&.(q M begin quote
+\&.(x M begin index entry
+\&.(z M begin floating keep
+\&.)b M end block
+\&.)c M end centered block
+\&.)d M end delayed text
+\&.)f M end footnote
+\&.)l M end list
+\&.)q M end quote
+\&.)x M end index entry
+\&.)z M end floating keep
+\e*\fI\&x\fP F\(sc interpolate string \fI\&x\fP
+\e*(\fI\&xx\fP F\(sc interpolate string \fI\&xx\fP
+\e** S optional footnote tag string
+\&.++ M set paper section type
+\&.+c M begin chapter
+\e*, S cedilla
+\e\- F\(sc minus sign
+\e*\- S 3/4 em dash
+\e0 F\(sc unpaddable digit-width space
+\&.1c M revert to single column output
+\&.2c M begin two column output
+\e*: S umlat
+\e*< S begin subscript
+\e*> S end subscript
+\&.EN M end equation
+\&.EQ M begin equation
+\eL\'\fI\&d\fP\' F\(sc vertical line drawing function for distance \fI\&d\fP
+\&.GE M\(de end \fIgremlin\fP picture
+\&.GF M\(de end \fIgremlin\fP picture (with flyback)
+\&.GS M\(de start \fIgremlin\fP picture
+\&.IE M\(de end \fIideal\fP picture
+\&.IF M\(de end \fIideal\fP picture (with flyback)
+\&.IS M\(de start \fIideal\fP picture
+\&.PE M\(de end \fIpic\fP picture
+\&.PF M\(de end \fIpic\fP picture (with flyback)
+\&.PS M\(de start \fIpic\fP picture
+\&.TE M end table
+\&.TH M end header of table
+\&.TS M begin table
+\e*{ S begin superscript
+\en(\&.$ R\(sc number of arguments to macro
+\en(\&.i R\(sc current indent
+\en(\&.l R\(sc current line length
+\en(\&.s R\(sc current point size
+\e*(\&\' S acute accent
+\e*(\&\` S grave accent
+\e(\' F\(sc acute accent
+\e(\` F\(sc grave accent
+\e*} S end superscript
+\e^ F\(sc 1/12 em narrow space
+\e*^ S caret
+\&.ad M\(sc set text adjustment
+\&.af M\(sc assign format to register
+\&.am M\(sc append to macro
+\&.ar M set page numbers in Arabic
+\&.as M\(sc append to string
+\&.b M bold font
+\&.ba M set base indent
+\&.bc M begin new column
+\&.bi M bold italic
+\en(bi R display (block) indent
+\&.bl M blank lines (even at top of page)
+\en(bm R bottom title margin
+\&.bp M\(sc begin page
+\&.br M\(sc break (start new line)
+\en(bs R display (block) pre/post spacing
+\en(bt R block keep threshold
+\&.bx M boxed
+\ec F\(sc continue input
+\&.ce M\(sc center lines
+\en(ch R current chapter number
+\&.de M\(sc define macro
+\en(df R display font
+\&.ds M\(sc define string
+\en(dw R\(sc current day of week
+\e*(dw S current day of week
+\en(dy R\(sc day of month
+\ee F\(sc printable version of \e
+\&.ef M set footer (even numbered pages only)
+\&.eh M set header (even numbered pages only)
+\&.el M\(sc else part of conditional
+\&.ep M end page
+\en(es R equation pre/post space
+\ef\fI\&f\fP F\(sc inline font change to font \fI\&f\fP
+\ef(\fI\&ff\fP F\(sc inline font change to font \fI\&ff\fP
+\&.fc M\(sc set field characters
+\en(ff R footnote font
+\&.fi M\(sc fill output lines
+\en(fi R footnote indent (first line only)
+\en(fm R footer margin
+\&.fo M set footer
+\en(fp R footnote pointsize
+\en(fs R footnote prespace
+\en(fu R footnote undent (from right margin)
+\eh\'\fI\&d\fP\' F\(sc local horizontal motion for distance \fI\&d\fP
+\&.hc M\(sc set hyphenation character
+\&.he M set header
+\&.hl M draw horizontal line
+\en(hm R header margin
+\&.hx M suppress headers and footers on next page
+\&.hy M\(sc set hyphenation mode
+\&.i M italic font
+\&.ie M\(sc conditional with else
+\&.if M\(sc conditional
+\en(ii R indented paragraph indent
+\&.in M\(sc indent (transient, use .ba for pervasive)
+\&.ip M begin indented paragraph
+\&.ix M indent, no break
+\el\'\fI\&d\fP\' F\(sc horizontal line drawing function for distance \fI\&d\fP
+\&.lc M\(sc set leader repetition character
+\&.ll M set line length
+\&.lp M begin left justified paragraph
+\e*(lq S left quote marks
+\&.ls M\(sc set multi-line spacing
+\&.m1 M set space from top of page to header
+\&.m2 M set space from header to text
+\&.m3 M set space from text to footer
+\&.m4 M set space from footer to bottom of page
+\&.mc M\(sc insert margin character
+\&.mk M\(sc mark vertical position
+\en(mo R\(sc month of year
+\e*(mo S current month
+\en\fI\&x\fP F\(sc interpolate number register \fI\&x\fP
+\en(\fI\&xx\fP F\(sc interpolate number register \fI\&xx\fP
+\&.n1 M number lines in margin
+\&.n2 M number lines in margin
+\&.na M\(sc turn off text adjustment
+\&.ne M\(sc need vertical space
+\&.nf M\(sc don't fill output lines
+\&.nh M\(sc turn off hyphenation
+\&.np M begin numbered paragraph
+\&.nr M\(sc set number register
+\&.ns M\(sc no space mode
+\e*o S circle (e.g., for Norse A\*o)
+\&.of M set footer (odd numbered pages only)
+\&.oh M set header (odd numbered pages only)
+\&.pa M begin page
+\&.pd M print delayed text
+\en(pf R paragraph font
+\en(pi R paragraph indent
+\&.pl M\(sc set page length
+\&.pn M\(sc set next page number
+\&.po M\(sc page offset
+\en(po R simulated page offset
+\&.pp M begin paragraph
+\en(pp R paragraph pointsize
+\en(ps R paragraph prespace
+\&.q M quoted
+\e*(qa S for all
+\e*(qe S there exists
+\en(qi R quote indent (also shortens line)
+\en(qp R quote pointsize
+\en(qs R quote pre/post space
+\&.r M roman font
+\&.rb M real bold font
+\&.re M reset tabs
+\&.rm M\(sc remove macro or string
+\&.rn M\(sc rename macro or string
+\&.ro M set page numbers in roman
+\e*(rq S right quote marks
+\&.rr M\(sc remove register
+\&.rs M\(sc restore spacing
+\&.rt M\(sc return to vertical position
+\es\fI\&S\fP F\(sc inline size change to size \fI\&S\fP
+\en(sf R section title font
+\&.sh M begin numbered section
+\en(si R relative base indent per section depth
+\&.sk M skip next page
+\&.sm M set argument in a smaller pointsize
+\&.so M\(sc source input file
+\en(so R additional section title offset
+\&.sp M\(sc vertical space
+\en(sp R section title pointsize
+\en(ss R section prespace
+\&.sx M change section depth
+\&.sz M set pointsize and vertical spacing
+\&.ta M\(sc set tab stops
+\&.tc M\(sc set tab repetition character
+\e*(td S today's date
+\en(tf R title font
+\&.ti M\(sc temporary indent (next line only)
+\&.tl M\(sc three part title
+\en(tm R top title margin
+\&.tp M begin title page
+\en(tp R title pointsize
+\&.tr M\(sc translate
+\&.u M underlined
+\&.uh M unnumbered section
+\&.ul M\(sc underline next line
+\ev\'\fI\&d\fP\' F\(sc local vertical motion for distance \fI\&d\fP
+\e*v S inverted `v' for czeck ``e\*v''
+\ew\'\fI\&S\fP\' F\(sc return width of string \fI\&S\fP
+\&.xl M set line length (local)
+\&.xp M print index
+\en(xs R index entry prespace
+\en(xu R index undent (from right margin)
+\en(yr R\(sc year (last two digits only)
+\en(zs R floating keep pre/post space
+\e{ F\(sc begin conditional group
+\e| F\(sc 1/6 em narrow space
+\e} F\(sc end conditional group
+\e*~ S tilde
+.)l
+.rm $H
diff --git a/gnu/usr.bin/groff/eqn/Makefile b/gnu/usr.bin/groff/eqn/Makefile
new file mode 100644
index 0000000..fa1784b
--- /dev/null
+++ b/gnu/usr.bin/groff/eqn/Makefile
@@ -0,0 +1,22 @@
+# Makefile for eqn
+
+PROG= eqn
+SRCS= main.cc lex.cc box.cc limit.cc list.cc over.cc text.cc\
+ script.cc mark.cc other.cc delim.cc sqrt.cc pile.cc special.cc
+OBJS= eqn.o
+CFLAGS+= -I. -I${.CURDIR}/../include
+LDADD+= ${LIBGROFF}
+DPADD+= ${LIBGROFF}
+
+MANDEPEND= eqn.1
+CLEANFILES+= eqn.cc eqn.tab.h ${MANDEPEND}
+
+afterinstall:
+ sed -e 's/@g@/${g}/g' ${.CURDIR}/neqn.sh > ${DESTDIR}${BINDIR}/neqn
+ chown ${BINOWN}.${BINGRP} ${DESTDIR}${BINDIR}/neqn
+ chmod ${BINMODE} ${DESTDIR}${BINDIR}/neqn
+
+beforedepend: eqn.cc
+
+.include "../Makefile.cfg"
+.include <bsd.prog.mk>
diff --git a/gnu/usr.bin/groff/eqn/Makefile.dep b/gnu/usr.bin/groff/eqn/Makefile.dep
new file mode 100644
index 0000000..4fccfee
--- /dev/null
+++ b/gnu/usr.bin/groff/eqn/Makefile.dep
@@ -0,0 +1,31 @@
+main.o : main.cc eqn.h ../include/cset.h ../include/errarg.h \
+ ../include/error.h ../include/lib.h box.h ../include/stringclass.h \
+ ../include/device.h ../include/searchpath.h ../include/macropath.h
+lex.o : lex.cc eqn.h ../include/cset.h ../include/errarg.h \
+ ../include/error.h ../include/lib.h box.h eqn.cc \
+ ../include/stringclass.h ../include/ptable.h
+box.o : box.cc eqn.h ../include/cset.h ../include/errarg.h \
+ ../include/error.h ../include/lib.h box.h pbox.h
+limit.o : limit.cc eqn.h ../include/cset.h ../include/errarg.h \
+ ../include/error.h ../include/lib.h box.h pbox.h
+list.o : list.cc eqn.h ../include/cset.h ../include/errarg.h \
+ ../include/error.h ../include/lib.h box.h pbox.h
+over.o : over.cc eqn.h ../include/cset.h ../include/errarg.h \
+ ../include/error.h ../include/lib.h box.h pbox.h
+text.o : text.cc eqn.h ../include/cset.h ../include/errarg.h \
+ ../include/error.h ../include/lib.h box.h pbox.h ../include/ptable.h
+script.o : script.cc eqn.h ../include/cset.h ../include/errarg.h \
+ ../include/error.h ../include/lib.h box.h pbox.h
+mark.o : mark.cc eqn.h ../include/cset.h ../include/errarg.h \
+ ../include/error.h ../include/lib.h box.h pbox.h
+other.o : other.cc eqn.h ../include/cset.h ../include/errarg.h \
+ ../include/error.h ../include/lib.h box.h pbox.h
+delim.o : delim.cc eqn.h ../include/cset.h ../include/errarg.h \
+ ../include/error.h ../include/lib.h box.h pbox.h
+sqrt.o : sqrt.cc eqn.h ../include/cset.h ../include/errarg.h \
+ ../include/error.h ../include/lib.h box.h pbox.h
+pile.o : pile.cc eqn.h ../include/cset.h ../include/errarg.h \
+ ../include/error.h ../include/lib.h box.h pbox.h
+special.o : special.cc eqn.h ../include/cset.h ../include/errarg.h \
+ ../include/error.h ../include/lib.h box.h pbox.h
+eqn.o : eqn.cc ../include/lib.h box.h
diff --git a/gnu/usr.bin/groff/eqn/Makefile.sub b/gnu/usr.bin/groff/eqn/Makefile.sub
new file mode 100644
index 0000000..692bf42
--- /dev/null
+++ b/gnu/usr.bin/groff/eqn/Makefile.sub
@@ -0,0 +1,27 @@
+PROG=eqn
+MAN1=eqn.n
+XLIBS=$(LIBGROFF)
+OBJS=eqn.o main.o lex.o box.o limit.o list.o over.o text.o script.o \
+ mark.o other.o delim.o sqrt.o pile.o special.o
+CCSRCS=main.cc lex.cc box.cc limit.cc list.cc over.cc text.cc \
+ script.cc mark.cc other.cc delim.cc sqrt.cc pile.cc special.cc
+HDRS=box.h eqn.h pbox.h
+GRAM=eqn.y
+YTABC=eqn.cc
+YTABH=eqn.tab.h
+NAMEPREFIX=$(g)
+CLEANADD=neqn
+
+all: neqn
+
+neqn: neqn.sh
+ -rm -f neqn
+ sed -e 's/@g@/$(g)/g' -e "$(SH_SCRIPT_SED_CMD)" $(srcdir)/neqn.sh >neqn
+ chmod +x neqn
+
+install_data: neqn
+ -rm -f $(bindir)/$(NAMEPREFIX)neqn
+ $(INSTALL_PROGRAM) neqn $(bindir)/$(NAMEPREFIX)neqn
+
+uninstall_sub:
+ -rm -f $(bindir)/$(NAMEPREFIX)neqn
diff --git a/gnu/usr.bin/groff/eqn/TODO b/gnu/usr.bin/groff/eqn/TODO
new file mode 100644
index 0000000..8179357
--- /dev/null
+++ b/gnu/usr.bin/groff/eqn/TODO
@@ -0,0 +1,41 @@
+Use the same size increases for sum prod int as eqn does.
+
+Perhaps chartype should be renamed.
+
+TeX makes {sub,super}script on a single character with an accent
+into an accent onto the (character with the script). Should we do this?
+
+Implement mark and lineups within scripts, matrices and piles, and accents.
+(Why would this be useful?)
+
+Perhaps push hmotions down through lists to avoid upsetting spacing
+adjustments.
+
+Possibly generate .lf commands during compute_metrics phase.
+
+Consider whether there should be extra space at the side of piles.
+
+Provide scriptstyle displaystyle etc.
+
+Provide a nicer matrix syntax, eg
+matrix ccc {
+a then b then c above
+e then f then g above
+h then i then k
+}
+
+Perhaps generate syntax error messages using the style of gpic.
+
+Wide accents.
+
+More use of \Z.
+
+Extensible square roots.
+
+Vphantom
+
+Smash.
+
+Provide a variant of vec that extends over the length of the accentee.
+
+Support vertical arrow delimiters.
diff --git a/gnu/usr.bin/groff/eqn/box.cc b/gnu/usr.bin/groff/eqn/box.cc
new file mode 100644
index 0000000..3a17cdf
--- /dev/null
+++ b/gnu/usr.bin/groff/eqn/box.cc
@@ -0,0 +1,611 @@
+// -*- C++ -*-
+/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
+ Written by James Clark (jjc@jclark.com)
+
+This file is part of groff.
+
+groff is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
+
+groff is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License along
+with groff; see the file COPYING. If not, write to the Free Software
+Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "eqn.h"
+#include "pbox.h"
+
+const char *current_roman_font;
+
+char *gfont = 0;
+char *grfont = 0;
+char *gbfont = 0;
+int gsize = 0;
+
+int script_size_reduction = -1; // negative means reduce by a percentage
+
+int positive_space = -1;
+int negative_space = -1;
+
+int minimum_size = 5;
+
+int fat_offset = 4;
+int body_height = 85;
+int body_depth = 35;
+
+int over_hang = 0;
+int accent_width = 31;
+int delimiter_factor = 900;
+int delimiter_shortfall = 50;
+
+int null_delimiter_space = 12;
+int script_space = 5;
+int thin_space = 17;
+int medium_space = 22;
+int thick_space = 28;
+
+int num1 = 70;
+int num2 = 40;
+// we don't use num3, because we don't have \atop
+int denom1 = 70;
+int denom2 = 36;
+int axis_height = 26; // in 100ths of an em
+int sup1 = 42;
+int sup2 = 37;
+int sup3 = 28;
+int default_rule_thickness = 4;
+int sub1 = 20;
+int sub2 = 23;
+int sup_drop = 38;
+int sub_drop = 5;
+int x_height = 45;
+int big_op_spacing1 = 11;
+int big_op_spacing2 = 17;
+int big_op_spacing3 = 20;
+int big_op_spacing4 = 60;
+int big_op_spacing5 = 10;
+
+// These are for piles and matrices.
+
+int baseline_sep = 140; // = num1 + denom1
+int shift_down = 26; // = axis_height
+int column_sep = 100; // = em space
+int matrix_side_sep = 17; // = thin space
+
+int nroff = 0; // should we grok ndefine or tdefine?
+
+struct {
+ const char *name;
+ int *ptr;
+} param_table[] = {
+ { "fat_offset", &fat_offset },
+ { "over_hang", &over_hang },
+ { "accent_width", &accent_width },
+ { "delimiter_factor", &delimiter_factor },
+ { "delimiter_shortfall", &delimiter_shortfall },
+ { "null_delimiter_space", &null_delimiter_space },
+ { "script_space", &script_space },
+ { "thin_space", &thin_space },
+ { "medium_space", &medium_space },
+ { "thick_space", &thick_space },
+ { "num1", &num1 },
+ { "num2", &num2 },
+ { "denom1", &denom1 },
+ { "denom2", &denom2 },
+ { "axis_height", &axis_height },
+ { "sup1", &sup1 },
+ { "sup2", &sup2 },
+ { "sup3", &sup3 },
+ { "default_rule_thickness", &default_rule_thickness },
+ { "sub1", &sub1 },
+ { "sub2", &sub2 },
+ { "sup_drop", &sup_drop },
+ { "sub_drop", &sub_drop },
+ { "x_height", &x_height },
+ { "big_op_spacing1", &big_op_spacing1 },
+ { "big_op_spacing2", &big_op_spacing2 },
+ { "big_op_spacing3", &big_op_spacing3 },
+ { "big_op_spacing4", &big_op_spacing4 },
+ { "big_op_spacing5", &big_op_spacing5 },
+ { "minimum_size", &minimum_size },
+ { "baseline_sep", &baseline_sep },
+ { "shift_down", &shift_down },
+ { "column_sep", &column_sep },
+ { "matrix_side_sep", &matrix_side_sep },
+ { "draw_lines", &draw_flag },
+ { "body_height", &body_height },
+ { "body_depth", &body_depth },
+ { "nroff", &nroff },
+ { 0, 0 }
+};
+
+void set_param(const char *name, int value)
+{
+ for (int i = 0; param_table[i].name != 0; i++)
+ if (strcmp(param_table[i].name, name) == 0) {
+ *param_table[i].ptr = value;
+ return;
+ }
+ error("unrecognised parameter `%1'", name);
+}
+
+int script_style(int style)
+{
+ return style > SCRIPT_STYLE ? style - 2 : style;
+}
+
+int cramped_style(int style)
+{
+ return (style & 1) ? style - 1 : style;
+}
+
+void set_space(int n)
+{
+ if (n < 0)
+ negative_space = -n;
+ else
+ positive_space = n;
+}
+
+// Return 0 if the specified size is bad.
+// The caller is responsible for giving the error message.
+
+int set_gsize(const char *s)
+{
+ const char *p = (*s == '+' || *s == '-') ? s + 1 : s;
+ char *end;
+ long n = strtol(p, &end, 10);
+ if (n <= 0 || *end != '\0' || n > INT_MAX)
+ return 0;
+ if (p > s) {
+ if (!gsize)
+ gsize = 10;
+ if (*s == '+') {
+ if (gsize > INT_MAX - n)
+ return 0;
+ gsize += int(n);
+ }
+ else {
+ if (gsize - n <= 0)
+ return 0;
+ gsize -= int(n);
+ }
+ }
+ else
+ gsize = int(n);
+ return 1;
+}
+
+void set_script_reduction(int n)
+{
+ script_size_reduction = n;
+}
+
+const char *get_gfont()
+{
+ return gfont ? gfont : "I";
+}
+
+const char *get_grfont()
+{
+ return grfont ? grfont : "R";
+}
+
+const char *get_gbfont()
+{
+ return gbfont ? gbfont : "B";
+}
+
+void set_gfont(const char *s)
+{
+ a_delete gfont;
+ gfont = strsave(s);
+}
+
+void set_grfont(const char *s)
+{
+ a_delete grfont;
+ grfont = strsave(s);
+}
+
+void set_gbfont(const char *s)
+{
+ a_delete gbfont;
+ gbfont = strsave(s);
+}
+
+// this must be precisely 2 characters in length
+#define COMPATIBLE_REG "0C"
+
+void start_string()
+{
+ printf(".nr " COMPATIBLE_REG " \\n(.C\n");
+ printf(".cp 0\n");
+ printf(".ds " LINE_STRING "\n");
+}
+
+void output_string()
+{
+ printf("\\*[" LINE_STRING "]\n");
+}
+
+void restore_compatibility()
+{
+ printf(".cp \\n(" COMPATIBLE_REG "\n");
+}
+
+void do_text(const char *s)
+{
+ printf(".eo\n");
+ printf(".as " LINE_STRING " \"%s\n", s);
+ printf(".ec\n");
+}
+
+void set_minimum_size(int n)
+{
+ minimum_size = n;
+}
+
+void set_script_size()
+{
+ if (minimum_size < 0)
+ minimum_size = 0;
+ if (script_size_reduction >= 0)
+ printf(".ps \\n[.s]-%d>?%d\n", script_size_reduction, minimum_size);
+ else
+ printf(".ps (u;\\n[.s]*7+5/10>?%d)*1z\n", minimum_size);
+}
+
+int box::next_uid = 0;
+
+box::box() : uid(next_uid++), spacing_type(ORDINARY_TYPE)
+{
+}
+
+box::~box()
+{
+}
+
+void box::top_level()
+{
+ // debug_print();
+ // putc('\n', stderr);
+ box *b = this;
+ printf(".nr " SAVED_FONT_REG " \\n[.f]\n");
+ printf(".ft\n");
+ printf(".nr " SAVED_PREV_FONT_REG " \\n[.f]\n");
+ printf(".ft %s\n", get_gfont());
+ printf(".nr " SAVED_SIZE_REG " \\n[.s]z\n");
+ if (gsize > 0) {
+ char buf[INT_DIGITS + 1];
+ sprintf(buf, "%d", gsize);
+ b = new size_box(strsave(buf), b);
+ }
+ current_roman_font = get_grfont();
+ // This catches tabs used within \Z (which aren't allowed).
+ b->check_tabs(0);
+ int r = b->compute_metrics(DISPLAY_STYLE);
+ printf(".ft \\n[" SAVED_PREV_FONT_REG "]\n");
+ printf(".ft \\n[" SAVED_FONT_REG "]\n");
+ printf(".nr " MARK_OR_LINEUP_FLAG_REG " %d\n", r);
+ if (r == FOUND_MARK) {
+ printf(".nr " SAVED_MARK_REG " \\n[" MARK_REG "]\n");
+ printf(".nr " MARK_WIDTH_REG " 0\\n[" WIDTH_FORMAT "]\n", b->uid);
+ }
+ else if (r == FOUND_LINEUP)
+ printf(".if r" SAVED_MARK_REG " .as " LINE_STRING " \\h'\\n["
+ SAVED_MARK_REG "]u-\\n[" MARK_REG "]u'\n");
+ else
+ assert(r == FOUND_NOTHING);
+ // The problem here is that the argument to \f is read in copy mode,
+ // so we cannot use \E there; so we hide it in a string instead.
+ // Another problem is that if we use \R directly, then the space will
+ // prevent it working in a macro argument.
+ printf(".ds " SAVE_FONT_STRING " "
+ "\\R'" SAVED_INLINE_FONT_REG " \\\\n[.f]'"
+ "\\fP"
+ "\\R'" SAVED_INLINE_PREV_FONT_REG " \\\\n[.f]'"
+ "\\R'" SAVED_INLINE_SIZE_REG " \\\\n[.s]z'"
+ "\\s0"
+ "\\R'" SAVED_INLINE_PREV_SIZE_REG " \\\\n[.s]z'"
+ "\n"
+ ".ds " RESTORE_FONT_STRING " "
+ "\\f[\\\\n[" SAVED_INLINE_PREV_FONT_REG "]]"
+ "\\f[\\\\n[" SAVED_INLINE_FONT_REG "]]"
+ "\\s'\\\\n[" SAVED_INLINE_PREV_SIZE_REG "]u'"
+ "\\s'\\\\n[" SAVED_INLINE_SIZE_REG "]u'"
+ "\n");
+ printf(".as " LINE_STRING " \\&\\E*[" SAVE_FONT_STRING "]");
+ printf("\\f[%s]", get_gfont());
+ printf("\\s'\\En[" SAVED_SIZE_REG "]u'");
+ current_roman_font = get_grfont();
+ b->output();
+ printf("\\E*[" RESTORE_FONT_STRING "]\n");
+ if (r == FOUND_LINEUP)
+ printf(".if r" SAVED_MARK_REG " .as " LINE_STRING " \\h'\\n["
+ MARK_WIDTH_REG "]u-\\n[" SAVED_MARK_REG "]u-(\\n["
+ WIDTH_FORMAT "]u-\\n[" MARK_REG "]u)'\n",
+ b->uid);
+ b->extra_space();
+ if (!inline_flag)
+ printf(".ne \\n[" HEIGHT_FORMAT "]u-%dM>?0+(\\n["
+ DEPTH_FORMAT "]u-%dM>?0)\n",
+ b->uid, body_height, b->uid, body_depth);
+ delete b;
+ next_uid = 0;
+}
+
+// gpic defines this register so as to make geqn not produce `\x's
+#define EQN_NO_EXTRA_SPACE_REG "0x"
+
+void box::extra_space()
+{
+ printf(".if !r" EQN_NO_EXTRA_SPACE_REG " "
+ ".nr " EQN_NO_EXTRA_SPACE_REG " 0\n");
+ if (positive_space >= 0 || negative_space >= 0) {
+ if (positive_space > 0)
+ printf(".if !\\n[" EQN_NO_EXTRA_SPACE_REG "] "
+ ".as " LINE_STRING " \\x'-%dM'\n", positive_space);
+ if (negative_space > 0)
+ printf(".if !\\n[" EQN_NO_EXTRA_SPACE_REG "] "
+ ".as " LINE_STRING " \\x'%dM'\n", negative_space);
+ positive_space = negative_space = -1;
+ }
+ else {
+ printf(".if !\\n[" EQN_NO_EXTRA_SPACE_REG "] "
+ ".if \\n[" HEIGHT_FORMAT "]>%dM .as " LINE_STRING
+ " \\x'-(\\n[" HEIGHT_FORMAT
+ "]u-%dM)'\n",
+ uid, body_height, uid, body_height);
+ printf(".if !\\n[" EQN_NO_EXTRA_SPACE_REG "] "
+ ".if \\n[" DEPTH_FORMAT "]>%dM .as " LINE_STRING
+ " \\x'\\n[" DEPTH_FORMAT
+ "]u-%dM'\n",
+ uid, body_depth, uid, body_depth);
+ }
+}
+
+int box::compute_metrics(int)
+{
+ printf(".nr " WIDTH_FORMAT " 0\n", uid);
+ printf(".nr " HEIGHT_FORMAT " 0\n", uid);
+ printf(".nr " DEPTH_FORMAT " 0\n", uid);
+ return FOUND_NOTHING;
+}
+
+void box::compute_subscript_kern()
+{
+ printf(".nr " SUB_KERN_FORMAT " 0\n", uid);
+}
+
+void box::compute_skew()
+{
+ printf(".nr " SKEW_FORMAT " 0\n", uid);
+}
+
+void box::output()
+{
+}
+
+void box::check_tabs(int)
+{
+}
+
+int box::is_char()
+{
+ return 0;
+}
+
+int box::left_is_italic()
+{
+ return 0;
+}
+
+int box::right_is_italic()
+{
+ return 0;
+}
+
+void box::hint(unsigned)
+{
+}
+
+void box::handle_char_type(int, int)
+{
+}
+
+
+box_list::box_list(box *pp)
+{
+ p = new box*[10];
+ for (int i = 0; i < 10; i++)
+ p[i] = 0;
+ maxlen = 10;
+ len = 1;
+ p[0] = pp;
+}
+
+void box_list::append(box *pp)
+{
+ if (len + 1 > maxlen) {
+ box **oldp = p;
+ maxlen *= 2;
+ p = new box*[maxlen];
+ memcpy(p, oldp, sizeof(box*)*len);
+ a_delete oldp;
+ }
+ p[len++] = pp;
+}
+
+box_list::~box_list()
+{
+ for (int i = 0; i < len; i++)
+ delete p[i];
+ a_delete p;
+}
+
+void box_list::list_check_tabs(int level)
+{
+ for (int i = 0; i < len; i++)
+ p[i]->check_tabs(level);
+}
+
+
+pointer_box::pointer_box(box *pp) : p(pp)
+{
+ spacing_type = p->spacing_type;
+}
+
+pointer_box::~pointer_box()
+{
+ delete p;
+}
+
+int pointer_box::compute_metrics(int style)
+{
+ int r = p->compute_metrics(style);
+ printf(".nr " WIDTH_FORMAT " 0\\n[" WIDTH_FORMAT "]\n", uid, p->uid);
+ printf(".nr " HEIGHT_FORMAT " \\n[" HEIGHT_FORMAT "]\n", uid, p->uid);
+ printf(".nr " DEPTH_FORMAT " \\n[" DEPTH_FORMAT "]\n", uid, p->uid);
+ return r;
+}
+
+void pointer_box::compute_subscript_kern()
+{
+ p->compute_subscript_kern();
+ printf(".nr " SUB_KERN_FORMAT " \\n[" SUB_KERN_FORMAT "]\n", uid, p->uid);
+}
+
+void pointer_box::compute_skew()
+{
+ p->compute_skew();
+ printf(".nr " SKEW_FORMAT " 0\\n[" SKEW_FORMAT "]\n",
+ uid, p->uid);
+}
+
+void pointer_box::check_tabs(int level)
+{
+ p->check_tabs(level);
+}
+
+int simple_box::compute_metrics(int)
+{
+ printf(".nr " WIDTH_FORMAT " 0\\w" DELIMITER_CHAR, uid);
+ output();
+ printf(DELIMITER_CHAR "\n");
+ printf(".nr " HEIGHT_FORMAT " 0>?\\n[rst]\n", uid);
+ printf(".nr " DEPTH_FORMAT " 0-\\n[rsb]>?0\n", uid);
+ printf(".nr " SUB_KERN_FORMAT " 0-\\n[ssc]>?0\n", uid);
+ printf(".nr " SKEW_FORMAT " 0\\n[skw]\n", uid);
+ return FOUND_NOTHING;
+}
+
+void simple_box::compute_subscript_kern()
+{
+ // do nothing, we already computed it in do_metrics
+}
+
+void simple_box::compute_skew()
+{
+ // do nothing, we already computed it in do_metrics
+}
+
+int box::is_simple()
+{
+ return 0;
+}
+
+int simple_box::is_simple()
+{
+ return 1;
+}
+
+quoted_text_box::quoted_text_box(char *s) : text(s)
+{
+}
+
+quoted_text_box::~quoted_text_box()
+{
+ a_delete text;
+}
+
+void quoted_text_box::output()
+{
+ if (text)
+ fputs(text, stdout);
+}
+
+tab_box::tab_box() : disabled(0)
+{
+}
+
+// We treat a tab_box as having width 0 for width computations.
+
+void tab_box::output()
+{
+ if (!disabled)
+ printf("\\t");
+}
+
+void tab_box::check_tabs(int level)
+{
+ if (level > 0) {
+ error("tabs allowed only at outermost level");
+ disabled = 1;
+ }
+}
+
+space_box::space_box()
+{
+ spacing_type = SUPPRESS_TYPE;
+}
+
+void space_box::output()
+{
+ printf("\\h'%dM'", thick_space);
+}
+
+half_space_box::half_space_box()
+{
+ spacing_type = SUPPRESS_TYPE;
+}
+
+void half_space_box::output()
+{
+ printf("\\h'%dM'", thin_space);
+}
+
+void box_list::list_debug_print(const char *sep)
+{
+ p[0]->debug_print();
+ for (int i = 1; i < len; i++) {
+ fprintf(stderr, "%s", sep);
+ p[i]->debug_print();
+ }
+}
+
+void quoted_text_box::debug_print()
+{
+ fprintf(stderr, "\"%s\"", (text ? text : ""));
+}
+
+void half_space_box::debug_print()
+{
+ fprintf(stderr, "^");
+}
+
+void space_box::debug_print()
+{
+ fprintf(stderr, "~");
+}
+
+void tab_box::debug_print()
+{
+ fprintf(stderr, "<tab>");
+}
diff --git a/gnu/usr.bin/groff/eqn/box.h b/gnu/usr.bin/groff/eqn/box.h
new file mode 100644
index 0000000..a6da83e
--- /dev/null
+++ b/gnu/usr.bin/groff/eqn/box.h
@@ -0,0 +1,277 @@
+// -*- C++ -*-
+/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
+ Written by James Clark (jjc@jclark.com)
+
+This file is part of groff.
+
+groff is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
+
+groff is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License along
+with groff; see the file COPYING. If not, write to the Free Software
+Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+struct list_box;
+
+class box {
+private:
+ static int next_uid;
+public:
+ int spacing_type;
+ const int uid;
+ box();
+ virtual void debug_print() = 0;
+ virtual ~box();
+ void top_level();
+ virtual int compute_metrics(int);
+ virtual void compute_subscript_kern();
+ virtual void compute_skew();
+ virtual void output();
+ void extra_space();
+ virtual list_box *to_list_box();
+ virtual int is_simple();
+ virtual int is_char();
+ virtual int left_is_italic();
+ virtual int right_is_italic();
+ virtual void handle_char_type(int, int);
+ enum { FOUND_NOTHING = 0, FOUND_MARK = 1, FOUND_LINEUP = 2 };
+ void set_spacing_type(char *type);
+ virtual void hint(unsigned);
+ virtual void check_tabs(int);
+};
+
+class box_list {
+private:
+ int maxlen;
+public:
+ box **p;
+ int len;
+
+ box_list(box *);
+ ~box_list();
+ void append(box *);
+ void list_check_tabs(int);
+ void list_debug_print(const char *sep);
+ friend class list_box;
+};
+
+class list_box : public box {
+ int is_script;
+ box_list list;
+ int sty;
+public:
+ list_box(box *);
+ void debug_print();
+ int compute_metrics(int);
+ void compute_subscript_kern();
+ void output();
+ void check_tabs(int);
+ void append(box *);
+ list_box *to_list_box();
+ void handle_char_type(int, int);
+ void compute_sublist_width(int n);
+ friend box *make_script_box(box *, box *, box *);
+ friend box *make_mark_box(box *);
+ friend box *make_lineup_box(box *);
+};
+
+enum alignment { LEFT_ALIGN, RIGHT_ALIGN, CENTER_ALIGN };
+
+class column : public box_list {
+ alignment align;
+ int space;
+public:
+ column(box *);
+ void set_alignment(alignment);
+ void set_space(int);
+ void debug_print(const char *);
+
+ friend class matrix_box;
+ friend class pile_box;
+};
+
+class pile_box : public box {
+ column col;
+public:
+ pile_box(box *);
+ int compute_metrics(int);
+ void output();
+ void debug_print();
+ void check_tabs(int);
+ void set_alignment(alignment a) { col.set_alignment(a); }
+ void set_space(int n) { col.set_space(n); }
+ void append(box *p) { col.append(p); }
+};
+
+class matrix_box : public box {
+private:
+ int len;
+ int maxlen;
+ column **p;
+public:
+ matrix_box(column *);
+ ~matrix_box();
+ void append(column *);
+ int compute_metrics(int);
+ void output();
+ void check_tabs(int);
+ void debug_print();
+};
+
+class pointer_box : public box {
+protected:
+ box *p;
+public:
+ pointer_box(box *);
+ ~pointer_box();
+ int compute_metrics(int);
+ void compute_subscript_kern();
+ void compute_skew();
+ void debug_print() = 0;
+ void check_tabs(int);
+};
+
+class vcenter_box : public pointer_box {
+public:
+ vcenter_box(box *);
+ int compute_metrics(int);
+ void output();
+ void debug_print();
+};
+
+class simple_box : public box {
+public:
+ int compute_metrics(int);
+ void compute_subscript_kern();
+ void compute_skew();
+ void output() = 0;
+ void debug_print() = 0;
+ int is_simple();
+};
+
+class quoted_text_box : public simple_box {
+ char *text;
+public:
+ quoted_text_box(char *);
+ ~quoted_text_box();
+ void debug_print();
+ void output();
+};
+
+class half_space_box : public simple_box {
+public:
+ half_space_box();
+ void output();
+ void debug_print();
+};
+
+class space_box : public simple_box {
+public:
+ space_box();
+ void output();
+ void debug_print();
+};
+
+class tab_box : public box {
+ int disabled;
+public:
+ tab_box();
+ void output();
+ void debug_print();
+ void check_tabs(int);
+};
+
+class size_box : public pointer_box {
+private:
+ char *size;
+public:
+ size_box(char *, box *);
+ ~size_box();
+ int compute_metrics(int);
+ void output();
+ void debug_print();
+};
+
+class font_box : public pointer_box {
+private:
+ char *f;
+public:
+ font_box(char *, box *);
+ ~font_box();
+ int compute_metrics(int);
+ void output();
+ void debug_print();
+};
+
+class fat_box : public pointer_box {
+public:
+ fat_box(box *);
+ int compute_metrics(int);
+ void output();
+ void debug_print();
+};
+
+class vmotion_box : public pointer_box {
+private:
+ int n; // up is >= 0
+public:
+ vmotion_box(int, box *);
+ int compute_metrics(int);
+ void output();
+ void debug_print();
+};
+
+class hmotion_box : public pointer_box {
+ int n;
+public:
+ hmotion_box(int, box *);
+ int compute_metrics(int);
+ void output();
+ void debug_print();
+};
+
+box *split_text(char *);
+box *make_script_box(box *, box *, box *);
+box *make_mark_box(box *);
+box *make_lineup_box(box *);
+box *make_delim_box(char *, box *, char *);
+box *make_sqrt_box(box *);
+box *make_prime_box(box *);
+box *make_over_box(box *, box *);
+box *make_small_over_box(box *, box *);
+box *make_limit_box(box *, box *, box *);
+box *make_accent_box(box *, box *);
+box *make_uaccent_box(box *, box *);
+box *make_overline_box(box *);
+box *make_underline_box(box *);
+box *make_special_box(char *, box *);
+
+void set_space(int);
+int set_gsize(const char *);
+void set_gfont(const char *);
+void set_grfont(const char *);
+void set_gbfont(const char *);
+const char *get_gfont();
+const char *get_grfont();
+const char *get_gbfont();
+void start_string();
+void output_string();
+void do_text(const char *);
+void restore_compatibility();
+void set_script_reduction(int n);
+void set_minimum_size(int n);
+void set_param(const char *name, int value);
+
+void set_char_type(const char *type, char *ch);
+
+void init_char_table();
+void init_extensible();
+void define_extensible(const char *name, const char *ext, const char *top = 0,
+ const char *mid = 0, const char *bot = 0);
diff --git a/gnu/usr.bin/groff/eqn/delim.cc b/gnu/usr.bin/groff/eqn/delim.cc
new file mode 100644
index 0000000..4fc4d50
--- /dev/null
+++ b/gnu/usr.bin/groff/eqn/delim.cc
@@ -0,0 +1,380 @@
+// -*- C++ -*-
+/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
+ Written by James Clark (jjc@jclark.com)
+
+This file is part of groff.
+
+groff is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
+
+groff is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License along
+with groff; see the file COPYING. If not, write to the Free Software
+Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "eqn.h"
+#include "pbox.h"
+
+enum left_or_right_t { LEFT_DELIM = 01, RIGHT_DELIM = 02 };
+
+// Small must be none-zero and must exist in each device.
+// Small will be put in the roman font, others are assumed to be
+// on the special font (so no font change will be necessary.)
+
+struct delimiter {
+ const char *name;
+ int flags;
+ const char *small;
+ const char *chain_format;
+ const char *ext;
+ const char *top;
+ const char *mid;
+ const char *bot;
+} delim_table[] = {
+ {
+ "(", LEFT_DELIM|RIGHT_DELIM, "(", "\\[parenleft%s]",
+ "\\[parenleftex]",
+ "\\[parenlefttp]",
+ 0,
+ "\\[parenleftbt]",
+ },
+ {
+ ")", LEFT_DELIM|RIGHT_DELIM, ")", "\\[parenright%s]",
+ "\\[parenrightex]",
+ "\\[parenrighttp]",
+ 0,
+ "\\[parenrightbt]",
+ },
+ {
+ "[", LEFT_DELIM|RIGHT_DELIM, "[", "\\[bracketleft%s]",
+ "\\[bracketleftex]",
+ "\\[bracketlefttp]",
+ 0,
+ "\\[bracketleftbt]",
+ },
+ {
+ "]", LEFT_DELIM|RIGHT_DELIM, "]", "\\[bracketright%s]",
+ "\\[bracketrightex]",
+ "\\[bracketrighttp]",
+ 0,
+ "\\[bracketrightbt]",
+ },
+ {
+ "{", LEFT_DELIM|RIGHT_DELIM, "{", "\\[braceleft%s]",
+ "\\[braceleftex]",
+ "\\[bracelefttp]",
+ "\\[braceleftmid]",
+ "\\[braceleftbt]",
+ },
+ {
+ "}", LEFT_DELIM|RIGHT_DELIM, "}", "\\[braceright%s]",
+ "\\[bracerightex]",
+ "\\[bracerighttp]",
+ "\\[bracerightmid]",
+ "\\[bracerightbt]",
+ },
+ {
+ "|", LEFT_DELIM|RIGHT_DELIM, "|", "\\[bar%s]",
+ "\\[barex]",
+ },
+ {
+ "floor", LEFT_DELIM, "\\(lf", "\\[floorleft%s]",
+ "\\[bracketleftex]",
+ 0,
+ 0,
+ "\\[bracketleftbt]",
+ },
+ {
+ "floor", RIGHT_DELIM, "\\(rf", "\\[floorright%s]",
+ "\\[bracketrightex]",
+ 0,
+ 0,
+ "\\[bracketrightbt]",
+ },
+ {
+ "ceiling", LEFT_DELIM, "\\(lc", "\\[ceilingleft%s]",
+ "\\[bracketleftex]",
+ "\\[bracketlefttp]",
+ },
+ {
+ "ceiling", RIGHT_DELIM, "\\(rc", "\\[ceilingright%s]",
+ "\\[bracketrightex]",
+ "\\[bracketrighttp]",
+ },
+ {
+ "||", LEFT_DELIM|RIGHT_DELIM, "|", "\\[bar%s]",
+ "\\[bardblex]",
+ },
+ {
+ "<", LEFT_DELIM|RIGHT_DELIM, "\\(la", "\\[angleleft%s]",
+ },
+ {
+ ">", LEFT_DELIM|RIGHT_DELIM, "\\(ra", "\\[angleright%s]",
+ },
+ {
+ "uparrow", LEFT_DELIM|RIGHT_DELIM, "\\(ua", "\\[arrowup%s]",
+ "\\[arrowvertex]",
+ "\\[arrowverttp]",
+ },
+ {
+ "downarrow", LEFT_DELIM|RIGHT_DELIM, "\\(da", "\\[arrowdown%s]",
+ "\\[arrowvertex]",
+ 0,
+ 0,
+ "\\[arrowvertbt]",
+ },
+ {
+ "updownarrow", LEFT_DELIM|RIGHT_DELIM, "\\(va", "\\[arrowupdown%s]",
+ "\\[arrowvertex]",
+ "\\[arrowverttp]",
+ 0,
+ "\\[arrowvertbt]",
+ },
+};
+
+const int DELIM_TABLE_SIZE = int(sizeof(delim_table)/sizeof(delim_table[0]));
+
+class delim_box : public box {
+private:
+ char *left;
+ char *right;
+ box *p;
+public:
+ delim_box(char *, box *, char *);
+ ~delim_box();
+ int compute_metrics(int);
+ void output();
+ void check_tabs(int);
+ void debug_print();
+};
+
+box *make_delim_box(char *l, box *pp, char *r)
+{
+ if (l != 0 && *l == '\0') {
+ a_delete l;
+ l = 0;
+ }
+ if (r != 0 && *r == '\0') {
+ a_delete r;
+ r = 0;
+ }
+ return new delim_box(l, pp, r);
+}
+
+delim_box::delim_box(char *l, box *pp, char *r)
+: left(l), right(r), p(pp)
+{
+}
+
+delim_box::~delim_box()
+{
+ a_delete left;
+ a_delete right;
+ delete p;
+}
+
+static void build_extensible(const char *ext, const char *top, const char *mid,
+ const char *bot)
+{
+ assert(ext != 0);
+ printf(".nr " DELIM_WIDTH_REG " 0\\w" DELIMITER_CHAR "%s" DELIMITER_CHAR "\n",
+ ext);
+ printf(".nr " EXT_HEIGHT_REG " 0\\n[rst]\n");
+ printf(".nr " EXT_DEPTH_REG " 0-\\n[rsb]\n");
+ if (top) {
+ printf(".nr " DELIM_WIDTH_REG " 0\\n[" DELIM_WIDTH_REG "]"
+ ">?\\w" DELIMITER_CHAR "%s" DELIMITER_CHAR "\n",
+ top);
+ printf(".nr " TOP_HEIGHT_REG " 0\\n[rst]\n");
+ printf(".nr " TOP_DEPTH_REG " 0-\\n[rsb]\n");
+ }
+ if (mid) {
+ printf(".nr " DELIM_WIDTH_REG " 0\\n[" DELIM_WIDTH_REG "]"
+ ">?\\w" DELIMITER_CHAR "%s" DELIMITER_CHAR "\n",
+ mid);
+ printf(".nr " MID_HEIGHT_REG " 0\\n[rst]\n");
+ printf(".nr " MID_DEPTH_REG " 0-\\n[rsb]\n");
+ }
+ if (bot) {
+ printf(".nr " DELIM_WIDTH_REG " 0\\n[" DELIM_WIDTH_REG "]"
+ ">?\\w" DELIMITER_CHAR "%s" DELIMITER_CHAR "\n",
+ bot);
+ printf(".nr " BOT_HEIGHT_REG " 0\\n[rst]\n");
+ printf(".nr " BOT_DEPTH_REG " 0-\\n[rsb]\n");
+ }
+ printf(".nr " TOTAL_HEIGHT_REG " 0");
+ if (top)
+ printf("+\\n[" TOP_HEIGHT_REG "]+\\n[" TOP_DEPTH_REG "]");
+ if (bot)
+ printf("+\\n[" BOT_HEIGHT_REG "]+\\n[" BOT_DEPTH_REG "]");
+ if (mid)
+ printf("+\\n[" MID_HEIGHT_REG "]+\\n[" MID_DEPTH_REG "]");
+ printf("\n");
+ // determine how many extensible characters we need
+ printf(".nr " TEMP_REG " \\n[" DELTA_REG "]-\\n[" TOTAL_HEIGHT_REG "]");
+ if (mid)
+ printf("/2");
+ printf(">?0+\\n[" EXT_HEIGHT_REG "]+\\n[" EXT_DEPTH_REG "]-1/(\\n["
+ EXT_HEIGHT_REG "]+\\n[" EXT_DEPTH_REG "])\n");
+
+ printf(".nr " TOTAL_HEIGHT_REG " +(\\n[" EXT_HEIGHT_REG "]+\\n["
+ EXT_DEPTH_REG "]*\\n[" TEMP_REG "]");
+ if (mid)
+ printf("*2");
+ printf(")\n");
+ printf(".ds " DELIM_STRING " \\Z" DELIMITER_CHAR
+ "\\v'-%dM-(\\n[" TOTAL_HEIGHT_REG "]u/2u)'\n",
+ axis_height);
+ if (top)
+ printf(".as " DELIM_STRING " \\v'\\n[" TOP_HEIGHT_REG "]u'"
+ "\\Z" DELIMITER_CHAR "%s" DELIMITER_CHAR
+ "\\v'\\n[" TOP_DEPTH_REG "]u'\n",
+ top);
+
+ // this macro appends $2 copies of $3 to string $1
+ printf(".de " REPEAT_APPEND_STRING_MACRO "\n"
+ ".if \\\\$2 \\{.as \\\\$1 \"\\\\$3\n"
+ "." REPEAT_APPEND_STRING_MACRO " \\\\$1 \\\\$2-1 \"\\\\$3\"\n"
+ ".\\}\n"
+ "..\n");
+
+ printf("." REPEAT_APPEND_STRING_MACRO " " DELIM_STRING " \\n[" TEMP_REG "] "
+ "\\v'\\n[" EXT_HEIGHT_REG "]u'"
+ "\\Z" DELIMITER_CHAR "%s" DELIMITER_CHAR
+ "\\v'\\n[" EXT_DEPTH_REG "]u'\n",
+ ext);
+
+ if (mid) {
+ printf(".as " DELIM_STRING " \\v'\\n[" MID_HEIGHT_REG "]u'"
+ "\\Z" DELIMITER_CHAR "%s" DELIMITER_CHAR
+ "\\v'\\n[" MID_DEPTH_REG "]u'\n",
+ mid);
+ printf("." REPEAT_APPEND_STRING_MACRO " " DELIM_STRING
+ " \\n[" TEMP_REG "] "
+ "\\v'\\n[" EXT_HEIGHT_REG "]u'"
+ "\\Z" DELIMITER_CHAR "%s" DELIMITER_CHAR
+ "\\v'\\n[" EXT_DEPTH_REG "]u'\n",
+ ext);
+ }
+ if (bot)
+ printf(".as " DELIM_STRING " \\v'\\n[" BOT_HEIGHT_REG "]u'"
+ "\\Z" DELIMITER_CHAR "%s" DELIMITER_CHAR
+ "\\v'\\n[" BOT_DEPTH_REG "]u'\n",
+ bot);
+ printf(".as " DELIM_STRING " " DELIMITER_CHAR "\n");
+}
+
+static void define_extensible_string(char *delim, int uid,
+ left_or_right_t left_or_right)
+{
+ printf(".ds " DELIM_STRING "\n");
+ delimiter *d = delim_table;
+ int delim_len = strlen(delim);
+ for (int i = 0; i < DELIM_TABLE_SIZE; i++, d++)
+ if (strncmp(delim, d->name, delim_len) == 0
+ && (left_or_right & d->flags) != 0)
+ break;
+ if (i >= DELIM_TABLE_SIZE) {
+ error("there is no `%1' delimiter", delim);
+ printf(".nr " DELIM_WIDTH_REG " 0\n");
+ return;
+ }
+
+ printf(".nr " DELIM_WIDTH_REG " 0\\w" DELIMITER_CHAR "\\f[%s]%s\\fP" DELIMITER_CHAR "\n"
+ ".ds " DELIM_STRING " \\Z" DELIMITER_CHAR
+ "\\v'\\n[rsb]u+\\n[rst]u/2u-%dM'\\f[%s]%s\\fP" DELIMITER_CHAR "\n"
+ ".nr " TOTAL_HEIGHT_REG " \\n[rst]-\\n[rsb]\n"
+ ".if \\n[" TOTAL_HEIGHT_REG "]<\\n[" DELTA_REG "] "
+ "\\{",
+ current_roman_font, d->small, axis_height,
+ current_roman_font, d->small);
+
+ char buf[256];
+ sprintf(buf, d->chain_format, "\\\\n[" INDEX_REG "]");
+ printf(".nr " INDEX_REG " 0\n"
+ ".de " TEMP_MACRO "\n"
+ ".ie c%s \\{\\\n"
+ ".nr " DELIM_WIDTH_REG " 0\\w" DELIMITER_CHAR "%s" DELIMITER_CHAR "\n"
+ ".ds " DELIM_STRING " \\Z" DELIMITER_CHAR
+ "\\v'\\\\n[rsb]u+\\\\n[rst]u/2u-%dM'%s" DELIMITER_CHAR "\n"
+ ".nr " TOTAL_HEIGHT_REG " \\\\n[rst]-\\\\n[rsb]\n"
+ ".if \\\\n[" TOTAL_HEIGHT_REG "]<\\n[" DELTA_REG "] "
+ "\\{.nr " INDEX_REG " +1\n"
+ "." TEMP_MACRO "\n"
+ ".\\}\\}\n"
+ ".el .nr " INDEX_REG " 0-1\n"
+ "..\n"
+ "." TEMP_MACRO "\n",
+ buf, buf, axis_height, buf);
+ if (d->ext) {
+ printf(".if \\n[" INDEX_REG "]<0 \\{.if c%s \\{\\\n", d->ext);
+ build_extensible(d->ext, d->top, d->mid, d->bot);
+ printf(".\\}\\}\n");
+ }
+ printf(".\\}\n");
+ printf(".as " DELIM_STRING " \\h'\\n[" DELIM_WIDTH_REG "]u'\n");
+ printf(".nr " WIDTH_FORMAT " +\\n[" DELIM_WIDTH_REG "]\n", uid);
+ printf(".nr " HEIGHT_FORMAT " \\n[" HEIGHT_FORMAT "]"
+ ">?(\\n[" TOTAL_HEIGHT_REG "]/2+%dM)\n",
+ uid, uid, axis_height);
+ printf(".nr " DEPTH_FORMAT " \\n[" DEPTH_FORMAT "]"
+ ">?(\\n[" TOTAL_HEIGHT_REG "]/2-%dM)\n",
+ uid, uid, axis_height);
+}
+
+int delim_box::compute_metrics(int style)
+{
+ int r = p->compute_metrics(style);
+ printf(".nr " WIDTH_FORMAT " 0\\n[" WIDTH_FORMAT "]\n", uid, p->uid);
+ printf(".nr " HEIGHT_FORMAT " \\n[" HEIGHT_FORMAT "]\n", uid, p->uid);
+ printf(".nr " DEPTH_FORMAT " \\n[" DEPTH_FORMAT "]\n", uid, p->uid);
+ printf(".nr " DELTA_REG " \\n[" HEIGHT_FORMAT "]-%dM"
+ ">?(\\n[" DEPTH_FORMAT "]+%dM)\n",
+ p->uid, axis_height, p->uid, axis_height);
+ printf(".nr " DELTA_REG " 0\\n[" DELTA_REG "]*%d/500"
+ ">?(\\n[" DELTA_REG "]*2-%dM)\n",
+ delimiter_factor, delimiter_shortfall);
+ if (left) {
+ define_extensible_string(left, uid, LEFT_DELIM);
+ printf(".rn " DELIM_STRING " " LEFT_DELIM_STRING_FORMAT "\n",
+ uid);
+ if (r)
+ printf(".nr " MARK_REG " +\\n[" DELIM_WIDTH_REG "]\n");
+ }
+ if (right) {
+ define_extensible_string(right, uid, RIGHT_DELIM);
+ printf(".rn " DELIM_STRING " " RIGHT_DELIM_STRING_FORMAT "\n",
+ uid);
+ }
+ return r;
+}
+
+void delim_box::output()
+{
+ if (left)
+ printf("\\*[" LEFT_DELIM_STRING_FORMAT "]", uid);
+ p->output();
+ if (right)
+ printf("\\*[" RIGHT_DELIM_STRING_FORMAT "]", uid);
+}
+
+void delim_box::check_tabs(int level)
+{
+ p->check_tabs(level);
+}
+
+void delim_box::debug_print()
+{
+ fprintf(stderr, "left \"%s\" { ", left ? left : "");
+ p->debug_print();
+ fprintf(stderr, " }");
+ if (right)
+ fprintf(stderr, " right \"%s\"", right);
+}
+
diff --git a/gnu/usr.bin/groff/eqn/eqn.h b/gnu/usr.bin/groff/eqn/eqn.h
new file mode 100644
index 0000000..e854a6b
--- /dev/null
+++ b/gnu/usr.bin/groff/eqn/eqn.h
@@ -0,0 +1,51 @@
+// -*- C++ -*-
+/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
+ Written by James Clark (jjc@jclark.com)
+
+This file is part of groff.
+
+groff is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
+
+groff is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License along
+with groff; see the file COPYING. If not, write to the Free Software
+Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+#include <stdlib.h>
+#include <errno.h>
+#include "cset.h"
+#include "errarg.h"
+#include "error.h"
+#include "lib.h"
+
+#include "box.h"
+
+extern char start_delim;
+extern char end_delim;
+extern int non_empty_flag;
+extern int inline_flag;
+extern int draw_flag;
+extern int one_size_reduction_flag;
+extern int compatible_flag;
+extern int nroff;
+
+void init_lex(const char *str, const char *filename, int lineno);
+void lex_error(const char *message,
+ const errarg &arg1 = empty_errarg,
+ const errarg &arg2 = empty_errarg,
+ const errarg &arg3 = empty_errarg);
+
+void init_table(const char *device);
+
+// prefix for all registers, strings, macros
+#define PREFIX "0"
diff --git a/gnu/usr.bin/groff/eqn/eqn.man b/gnu/usr.bin/groff/eqn/eqn.man
new file mode 100644
index 0000000..81b6842
--- /dev/null
+++ b/gnu/usr.bin/groff/eqn/eqn.man
@@ -0,0 +1,862 @@
+.\" -*- nroff -*-
+.ie \n(.V<\n(.v .ds tx T\h'-.1667m'\v'.224m'E\v'-.224m'\h'-.125m'X
+.el .ds tx TeX
+.\" Like TP, but if specified indent is more than half
+.\" the current line-length - indent, use the default indent.
+.de Tp
+.ie \\n(.$=0:((0\\$1)*2u>(\\n(.lu-\\n(.iu)) .TP
+.el .TP "\\$1"
+..
+.\" The BSD man macros can't handle " in arguments to font change macros,
+.\" so use \(ts instead of ".
+.tr \(ts"
+.TH @G@EQN @MAN1EXT@ "@MDATE@" "Groff Version @VERSION@"
+.SH NAME
+@g@eqn \- format equations for troff
+.SH SYNOPSIS
+.B @g@eqn
+[
+.B \-rvCNR
+]
+[
+.BI \-d cc
+]
+[
+.BI \-T name
+]
+[
+.BI \-M dir
+]
+[
+.BI \-f F
+]
+[
+.BI \-s n
+]
+[
+.BI \-p n
+]
+[
+.BI \-m n
+]
+[
+.IR files \|.\|.\|.
+]
+.SH DESCRIPTION
+This manual page describes the GNU version of
+.BR eqn ,
+which is part of the groff document formatting system.
+.B eqn
+compiles descriptions of equations embedded within
+.B troff
+input files into commands that are understood by
+.BR troff .
+Normally, it should be invoked using the
+.B \-e
+option of
+.BR groff .
+The syntax is quite compatible with Unix eqn.
+The output of GNU eqn cannot be processed with Unix troff;
+it must be processed with GNU troff.
+If no files are given on the command line, the standard input
+will be read.
+A filename of
+.B \-
+will cause the standard input to be read.
+.LP
+.B eqn
+searches for the file
+.B eqnrc
+using the path
+.BR @MACROPATH@ .
+If it exists, eqn will process it before the other input files.
+The
+.B \-R
+option prevents this.
+.LP
+GNU eqn does not provide the functionality of neqn:
+it does not support low-resolution, typewriter-like devices
+(although it may work adequately for very simple input).
+.SH OPTIONS
+.TP
+.B \-C
+Recognize
+.B .EQ
+and
+.B .EN
+even when followed by a character other than space or newline.
+.TP
+.B \-N
+Don't allow newlines within delimiters.
+This option allows
+.B eqn
+to recover better from missing closing delimiters.
+.TP
+.B \-v
+Print the version number.
+.TP
+.B \-r
+Only one size reduction.
+.TP
+.BI \-m n
+The minimum point-size is
+.IR n .
+eqn will not reduce the size of subscripts or superscripts to
+a smaller size than
+.IR n .
+.TP
+.BI \-T name
+The output is for device
+.IR name .
+The only effect of this is to define a macro
+.I name
+with a value of
+.BR 1 .
+Typically
+.B eqnrc
+will use this to provide definitions appropriate for the output device.
+The default output device is
+.BR @DEVICE@ .
+.TP
+.BI \-M dir
+Search
+.I dir
+for
+.B eqnrc
+before the default directories.
+.TP
+.B \-R
+Don't load
+.BR eqnrc .
+.TP
+.BI \-f F
+This is equivalent to a
+.BI gfont\ F
+command.
+.TP
+.BI \-s n
+This is equivalent to a
+.BI gsize\ n
+command.
+This option is deprecated.
+eqn will normally set equations at whatever the current point size
+is when the equation is encountered.
+.TP
+.BI \-p n
+This says that subscripts and superscripts should be
+.I n
+points smaller than the surrounding text.
+This option is deprecated.
+Normally eqn makes sets subscripts and superscripts at 70%
+of the size of the surrounding text.
+.SH USAGE
+Only the differences between GNU eqn and Unix eqn are described here.
+.LP
+Most of the new features of GNU eqn
+are based on \*(tx.
+There are some references to the differences between \*(tx and GNU eqn below;
+these may safely be ignored if you do not know \*(tx.
+.SS Automatic spacing
+.LP
+.B eqn
+gives each component of an equation a type, and adjusts the spacing
+between components using that type.
+Possible types are:
+.TP \w'punctuation'u+2n
+ordinary
+an ordinary character such as 1 or
+.IR x ;
+.TP
+operator
+a large operator such as
+.ds Su \s+5\(*S\s0
+.if \n(.g .if !c\(*S .ds Su the summation operator
+\*(Su;
+.TP
+binary
+a binary operator such as +;
+.TP
+relation
+a relation such as =;
+.TP
+opening
+a opening bracket such as (;
+.TP
+closing
+a closing bracket such as );
+.TP
+punctuation
+a punctuation character such as ,;
+.TP
+inner
+a subformula contained within brackets;
+.TP
+suppress
+spacing that suppresses automatic spacing adjustment.
+.LP
+Components of an equation get a type in one of two ways.
+.TP
+.BI type\ t\ e
+This yields an equation component that contains
+.I e
+but that has type
+.IR t ,
+where
+.I t
+is one of the types mentioned above.
+For example,
+.B times
+is defined as
+.RS
+.IP
+.B
+type "binary" \e(mu
+.RE
+.IP
+The name of the type doesn't have to be quoted, but quoting protects
+from macro expansion.
+.TP
+.BI chartype\ t\ text
+Unquoted groups of characters are split up into individual characters,
+and the type of each character is looked up;
+this changes the type that is stored for each character;
+it says that the characters in
+.I text
+from now on have type
+.IR t .
+For example,
+.RS
+.IP
+.B
+chartype "punctuation" .,;:
+.RE
+.IP
+would make the characters
+.B .,;:
+have type punctuation
+whenever they subsequently appeared in an equation.
+The type
+.I t
+can also be
+.B letter
+or
+.BR digit ;
+in these cases
+.B chartype
+changes the font type of the characters.
+See the Fonts subsection.
+.SS New primitives
+.TP
+.IB e1\ smallover\ e2
+This is similar to
+.BR over ;
+.B smallover
+reduces the size of
+.I e1
+and
+.IR e2 ;
+it also puts less vertical space between
+.I e1
+or
+.I e2
+and the fraction bar.
+The
+.B over
+primitive corresponds to the \*(tx
+.B \eover
+primitive in display styles;
+.B smallover
+corresponds to
+.B \eover
+in non-display styles.
+.TP
+.BI vcenter\ e
+This vertically centers
+.I e
+about the math axis.
+The math axis is the vertical position about which characters
+such as + and - are centered; also it is the vertical position
+used for the bar of fractions.
+For example,
+.B sum
+is defined as
+.RS
+.IP
+.B
+{ type "operator" vcenter size +5 \e(*S }
+.RE
+.TP
+.IB e1\ accent\ e2
+This sets
+.I e2
+as an accent over
+.IR e1 .
+.I e2
+is assumed to be at the correct height for a lowercase letter;
+.I e2
+will be moved down according if
+.I e1
+is taller or shorter than a lowercase letter.
+For example,
+.B hat
+is defined as
+.RS
+.IP
+.B
+accent { "^" }
+.RE
+.IP
+.BR dotdot ,
+.BR dot ,
+.BR tilde ,
+.B vec
+and
+.B dyad
+are also defined using the
+.B accent
+primitive.
+.TP
+.IB e1\ uaccent\ e2
+This sets
+.I e2
+as an accent under
+.IR e1 .
+.I e2
+is assumed to be at the correct height for a character without a descender;
+.I e2
+will be moved down if
+.I e1
+has a descender.
+.B utilde
+is pre-defined using
+.B uaccent
+as a tilde accent below the baseline.
+.TP
+.BI split\ \(ts text \(ts
+This has the same effect as simply
+.RS
+.IP
+.I text
+.RE
+.IP
+but
+.I text
+is not subject to macro expansion because it is quoted;
+.I text
+will be split up and the spacing between individual characters
+will be adjusted.
+.TP
+.BI nosplit\ text
+This has the same effect as
+.RS
+.IP
+.BI \(ts text \(ts
+.RE
+.IP
+but because
+.I text
+is not quoted it will be subject to macro expansion;
+.I text
+will not be split up
+and the spacing between individual characters will not be adjusted.
+.TP
+.IB e\ opprime
+This is a variant of
+.B prime
+that acts as an operator on
+.IR e .
+It produces a different result from
+.B prime
+in a case such as
+.BR A\ opprime\ sub\ 1 :
+with
+.B opprime
+the
+.B 1
+will be tucked under the prime as a subscript to the
+.B A
+(as is conventional in mathematical typesetting),
+whereas with
+.B prime
+the
+.B 1
+will be a subscript to the prime character.
+The precedence of
+.B opprime
+is the same as that of
+.B bar
+and
+.BR under ,
+which is higher than that of everything except
+.B accent
+and
+.BR uaccent .
+In unquoted text a
+.B '
+that is not the first character will be treated like
+.BR opprime .
+.TP
+.BI special\ text\ e
+This constructs a new object from
+.I e
+using a
+.BR @g@troff (@MAN1EXT@)
+macro named
+.IR text .
+When the macro is called,
+the string
+.B 0s
+will contain the output for
+.IR e ,
+and the number registers
+.BR 0w ,
+.BR 0h ,
+.BR 0d ,
+.BR 0skern
+and
+.BR 0skew
+will contain the width, height, depth, subscript kern, and skew of
+.IR e .
+(The
+.I "subscript kern"
+of an object says how much a subscript on that object should be tucked in;
+the
+.I skew
+of an object says how far to the right of the center of the object an
+accent over the object should be placed.)
+The macro must modify
+.B 0s
+so that it will output the desired result with its origin at the current
+point, and increase the current horizontal position by the width
+of the object.
+The number registers must also be modified so that they correspond to the
+result.
+.RS
+.LP
+For example, suppose you wanted a construct that `cancels' an expression
+by drawing a diagonal line through it.
+.IP
+.nf
+.ft B
+.ne 6+\n(.Vu
+\&.EQ
+define cancel 'special Ca'
+\&.EN
+\&.de Ca
+\&.ds 0s \eZ'\e\e*(0s'\ev'\e\en(0du'\eD'l \e\en(0wu -\e\en(0hu-\e\en(0du'\ev'\e\en(0hu'
+\&..
+.ft
+.fi
+.LP
+Then you could cancel an expression
+.I e
+with
+.BI cancel\ {\ e\ }
+.LP
+Here's a more complicated construct that draws a box round an expression:
+.IP
+.nf
+.ft B
+.ne 11+\n(.Vu
+\&.EQ
+define box 'special Bx'
+\&.EN
+\&.de Bx
+\&.ds 0s \eZ'\eh'1n'\e\e*(0s'\e
+\eZ'\ev'\e\en(0du+1n'\eD'l \e\en(0wu+2n 0'\eD'l 0 -\e\en(0hu-\e\en(0du-2n'\e
+\eD'l -\e\en(0wu-2n 0'\eD'l 0 \e\en(0hu+\e\en(0du+2n''\eh'\e\en(0wu+2n'
+\&.nr 0w +2n
+\&.nr 0d +1n
+\&.nr 0h +1n
+\&..
+.ft
+.fi
+.RE
+.SS Customization
+The appearance of equations is controlled by
+a large number of parameters. These can be set using
+the
+.B set
+command.
+.TP
+.BI set\ p\ n
+This sets parameter
+.I p
+to value
+.I n ;
+.I n
+is an integer.
+For example,
+.RS
+.IP
+.B
+set x_height 45
+.RE
+.IP
+says that
+.B eqn
+should assume an x height of 0.45 ems.
+.RS
+.LP
+Possible parameters are as follows.
+Values are in units of hundredths of an em unless otherwise stated.
+These descriptions are intended to be expository rather than
+definitive.
+.TP \w'\fBdefault_rule_thickness'u+2n
+.B minimum_size
+.B eqn
+will not set anything at a smaller point-size than this.
+The value is in points.
+.TP
+.B fat_offset
+The
+.B fat
+primitive emboldens an equation
+by overprinting two copies of the equation
+horizontally offset by this amount.
+.TP
+.B over_hang
+A fraction bar will be longer by twice this amount than
+the maximum of the widths of the numerator and denominator;
+in other words, it will overhang the numerator and
+denominator by at least this amount.
+.TP
+.B accent_width
+When
+.B bar
+or
+.B under
+is applied to a single character,
+the line will be this long.
+Normally,
+.B bar
+or
+.B under
+produces a line whose length is the width of the object to which it applies;
+in the case of a single character,
+this tends to produce a line that looks too long.
+.TP
+.B delimiter_factor
+Extensible delimiters produced with the
+.B left
+and
+.B right
+primitives will have a combined height and depth of at least this many
+thousandths of twice the maximum amount by which the sub-equation that
+the delimiters enclose extends away from the axis.
+.TP
+.B delimiter_shortfall
+Extensible delimiters produced with the
+.B left
+and
+.B right
+primitives will have a combined height and depth
+not less than the difference of
+twice the maximum amount by which the sub-equation that
+the delimiters enclose extends away from the axis
+and this amount.
+.TP
+.B null_delimiter_space
+This much horizontal space is inserted
+on each side of a fraction.
+.TP
+.B script_space
+The width of subscripts and superscripts is increased by this amount.
+.TP
+.B thin_space
+This amount of space is automatically inserted after punctuation
+characters.
+.TP
+.B medium_space
+This amount of space is automatically inserted on either side
+of binary operators.
+.TP
+.B thick_space
+This amount of space is automatically inserted on either side of
+relations.
+.TP
+.B x_height
+The height of lowercase letters without ascenders such as x.
+.TP
+.B axis_height
+The height above the baseline of the center of characters
+such as \(pl and \(mi.
+It is important that this value is correct for the font
+you are using.
+.TP
+.B default_rule_thickness
+This should set to the thickness of the
+.B \e(ru
+character, or the thickness of horizontal lines produced with the
+.B \eD
+escape sequence.
+.TP
+.B num1
+The
+.B over
+command will shift up the numerator by at least this amount.
+.TP
+.B num2
+The
+.B smallover
+command will shift up the numerator by at least this amount.
+.TP
+.B denom1
+The
+.B over
+command will shift down the denominator by at least this amount.
+.TP
+.B denom2
+The
+.B smallover
+command will shift down the denominator by at least this amount.
+.TP
+.B sup1
+Normally superscripts will be shifted up by at least this amount.
+.TP
+.B sup2
+Superscripts within superscripts or upper limits
+or numerators of
+.B smallover
+fractions
+will be shifted up by at least this amount.
+This is usually less than sup1.
+.TP
+.B sup3
+Superscripts within denominators or square roots
+or subscripts or lower limits will be shifted up by at least
+this amount.
+This is usually less than sup2.
+.TP
+.B sub1
+Subscripts will normally be shifted down by at least this amount.
+.TP
+.B sub2
+When there is both a subscript and a superscript, the subscript
+will be shifted down by at least this amount.
+.TP
+.B sup_drop
+The baseline of a superscript will be no more
+than this much amount below the top of the object on
+which the superscript is set.
+.TP
+.B sub_drop
+The baseline of a subscript will be at least this much below
+the bottom of the object on which the subscript is set.
+.TP
+.B big_op_spacing1
+The baseline of an upper limit will be at least this
+much above the top of the object on which the limit is set.
+.TP
+.B big_op_spacing2
+The baseline of a lower limit will be at least this
+much below the bottom of the object on which the limit is set.
+.TP
+.B big_op_spacing3
+The bottom of an upper limit will be at least this much above the
+top of the object on which the limit is set.
+.TP
+.B big_op_spacing4
+The top of a lower limit will be at least this much below
+the bottom of the object on which the limit is set.
+.TP
+.B big_op_spacing5
+This much vertical space will be added above and below limits.
+.TP
+.B baseline_sep
+The baselines of the rows in a pile or matrix will normally be
+this far apart.
+In most cases this should be equal to the sum of
+.B num1
+and
+.BR denom1 .
+.TP
+.B shift_down
+The midpoint between the top baseline and the bottom baseline
+in a matrix or pile will be shifted down by this much from the axis.
+In most cases this should be equal to
+.BR axis_height .
+.TP
+.B column_sep
+This much space will be added between columns in a matrix.
+.TP
+.B matrix_side_sep
+This much space will be added at each side of a matrix.
+.TP
+.B draw_lines
+If this is non-zero, lines will be drawn using the
+.B \eD
+escape sequence, rather than with the
+.B \el
+escape sequence and the
+.B \e(ru
+character.
+.TP
+.B body_height
+The amount by which the height of the equation exceeds this
+will be added as extra space before the line containing the equation
+(using
+.BR \ex .)
+The default value is 85.
+.TP
+.B body_depth
+The amount by which the depth of the equation exceeds this
+will be added as extra space after the line containing the equation
+(using
+.BR \ex .)
+The default value is 35.
+.TP
+.B nroff
+If this is non-zero,
+then
+.B ndefine
+will behave like
+.B define
+and
+.B tdefine
+will be ignored,
+otherwise
+.B tdefine
+will behave like
+.B define
+and
+.B ndefine
+will be ignored.
+The default value is 0
+(This is typically changed to 1 by the
+.B eqnrc
+file for the
+.B ascii
+and
+.B latin1
+devices.)
+.LP
+A more precise description of the role of many of these
+parameters can be found in Appendix H of
+.IR The\ \*(txbook .
+.RE
+.SS Macros
+Macros can take arguments.
+In a macro body,
+.BI $ n
+where
+.I n
+is between 1 and 9,
+will be replaced by the
+.IR n-th
+argument if the macro is called with arguments;
+if there are fewer than
+.I n
+arguments, it will be replaced by nothing.
+A word containing a left parenthesis where the part of the word
+before the left parenthesis has been defined using the
+.B define
+command
+will be recognized as a macro call with arguments;
+characters following the left parenthesis
+up to a matching right parenthesis will be treated as comma-separated
+arguments;
+commas inside nested parentheses do not terminate an argument.
+.TP
+.BI sdefine\ name\ X\ anything\ X
+This is like the
+.B define
+command, but
+.I name
+will not be recognized if called with arguments.
+.TP
+.BI include\ \(ts file \(ts
+Include the contents of
+.IR file .
+Lines of
+.I file
+beginning with
+.B .EQ
+or
+.B .EN
+will be ignored.
+.TP
+.BI ifdef\ name\ X\ anything\ X
+If
+.I name
+has been defined by
+.B define
+(or has been automatically defined because
+.I name
+is the output device)
+process
+.IR anything ;
+otherwise ignore
+.IR anything .
+.I X
+can be any character not appearing in
+.IR anything .
+.SS Fonts
+.B eqn
+normally uses at least two fonts to set an equation:
+an italic font for letters,
+and a roman font for everything else.
+The existing
+.B gfont
+command
+changes the font that is used as the italic font.
+By default this is
+.BR I .
+The font that is used as the roman font can be changed
+using the new
+.B grfont
+command.
+.TP
+.BI grfont\ f
+Set the roman font to
+.IR f .
+.LP
+The
+.B italic
+primitive uses the current italic font set by
+.BR gfont ;
+the
+.B roman
+primitive uses the current roman font set by
+.BR grfont .
+There is also a new
+.B gbfont
+command, which changes the font used by the
+.B bold
+primitive.
+If you only use the
+.BR roman ,
+.B italic
+and
+.B bold
+primitives to changes fonts within an equation,
+you can change all the fonts used by your equations
+just by using
+.BR gfont ,
+.B grfont
+and
+.B gbfont
+commands.
+.LP
+You can control which characters are treated as letters
+(and therefore set in italics) by using the
+.B chartype
+command described above.
+A type of
+.B letter
+will cause a character to be set in italic type.
+A type of
+.B digit
+will cause a character to be set in roman type.
+.SH FILES
+.Tp \w'\fB@MACRODIR@/eqnrc'u+2n
+.B @MACRODIR@/eqnrc
+Initialization file.
+.SH BUGS
+Inline equations will be set at the point size that is current at the
+beginning of the input line.
+.SH "SEE ALSO"
+.BR groff (@MAN1EXT@),
+.BR @g@troff (@MAN1EXT@),
+.BR groff_font (@MAN5EXT@),
+.I The\ \*(txbook
diff --git a/gnu/usr.bin/groff/eqn/eqn.y b/gnu/usr.bin/groff/eqn/eqn.y
new file mode 100644
index 0000000..28011fb
--- /dev/null
+++ b/gnu/usr.bin/groff/eqn/eqn.y
@@ -0,0 +1,331 @@
+/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
+ Written by James Clark (jjc@jclark.com)
+
+This file is part of groff.
+
+groff is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
+
+groff is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License along
+with groff; see the file COPYING. If not, write to the Free Software
+Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+%{
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "lib.h"
+#include "box.h"
+extern int non_empty_flag;
+char *strsave(const char *);
+int yylex();
+void yyerror(const char *);
+%}
+
+%union {
+ char *str;
+ box *b;
+ pile_box *pb;
+ matrix_box *mb;
+ int n;
+ column *col;
+}
+
+%token OVER
+%token SMALLOVER
+%token SQRT
+%token SUB
+%token SUP
+%token LPILE
+%token RPILE
+%token CPILE
+%token PILE
+%token LEFT
+%token RIGHT
+%token TO
+%token FROM
+%token SIZE
+%token FONT
+%token ROMAN
+%token BOLD
+%token ITALIC
+%token FAT
+%token ACCENT
+%token BAR
+%token UNDER
+%token ABOVE
+%token <str> TEXT
+%token <str> QUOTED_TEXT
+%token FWD
+%token BACK
+%token DOWN
+%token UP
+%token MATRIX
+%token COL
+%token LCOL
+%token RCOL
+%token CCOL
+%token MARK
+%token LINEUP
+%token TYPE
+%token VCENTER
+%token PRIME
+%token SPLIT
+%token NOSPLIT
+%token UACCENT
+%token SPECIAL
+
+/* these are handled in the lexer */
+%token SPACE
+%token GFONT
+%token GSIZE
+%token DEFINE
+%token NDEFINE
+%token TDEFINE
+%token SDEFINE
+%token UNDEF
+%token IFDEF
+%token INCLUDE
+%token DELIM
+%token CHARTYPE
+%token SET
+%token GRFONT
+%token GBFONT
+
+/* The original eqn manual says that `left' is right associative. It's lying.
+Consider `left ( ~ left ( ~ right ) right )'. */
+
+%right LEFT
+%left RIGHT
+%right LPILE RPILE CPILE PILE TEXT QUOTED_TEXT MATRIX MARK LINEUP '^' '~' '\t' '{' SPLIT NOSPLIT
+%right FROM TO
+%left SQRT OVER SMALLOVER
+%right SUB SUP
+%right ROMAN BOLD ITALIC FAT FONT SIZE FWD BACK DOWN UP TYPE VCENTER SPECIAL
+%right BAR UNDER PRIME
+%left ACCENT UACCENT
+
+%type <b> mark from_to sqrt_over script simple equation nonsup
+%type <n> number
+%type <str> text delim
+%type <pb> pile_element_list pile_arg
+%type <mb> column_list
+%type <col> column column_arg column_element_list
+
+%%
+top:
+ /* empty */
+ | equation
+ { $1->top_level(); non_empty_flag = 1; }
+ ;
+
+equation:
+ mark
+ { $$ = $1; }
+ | equation mark
+ {
+ list_box *lb = $1->to_list_box();
+ if (!lb)
+ lb = new list_box($1);
+ lb->append($2);
+ $$ = lb;
+ }
+ ;
+
+mark:
+ from_to
+ { $$ = $1; }
+ | MARK mark
+ { $$ = make_mark_box($2); }
+ | LINEUP mark
+ { $$ = make_lineup_box($2); }
+ ;
+
+from_to:
+ sqrt_over %prec FROM
+ { $$ = $1; }
+ | sqrt_over TO from_to
+ { $$ = make_limit_box($1, 0, $3); }
+ | sqrt_over FROM sqrt_over
+ { $$ = make_limit_box($1, $3, 0); }
+ | sqrt_over FROM sqrt_over TO from_to
+ { $$ = make_limit_box($1, $3, $5); }
+ | sqrt_over FROM sqrt_over FROM from_to
+ { $$ = make_limit_box($1, make_limit_box($3, $5, 0), 0); }
+ ;
+
+sqrt_over:
+ script
+ { $$ = $1; }
+ | SQRT sqrt_over
+ { $$ = make_sqrt_box($2); }
+ | sqrt_over OVER sqrt_over
+ { $$ = make_over_box($1, $3); }
+ | sqrt_over SMALLOVER sqrt_over
+ { $$ = make_small_over_box($1, $3); }
+ ;
+
+script:
+ nonsup
+ { $$ = $1; }
+ | simple SUP script
+ { $$ = make_script_box($1, 0, $3); }
+ ;
+
+nonsup:
+ simple %prec SUP
+ { $$ = $1; }
+ | simple SUB nonsup
+ { $$ = make_script_box($1, $3, 0); }
+ | simple SUB simple SUP script
+ { $$ = make_script_box($1, $3, $5); }
+ ;
+
+simple:
+ TEXT
+ { $$ = split_text($1); }
+ | QUOTED_TEXT
+ { $$ = new quoted_text_box($1); }
+ | SPLIT QUOTED_TEXT
+ { $$ = split_text($2); }
+ | NOSPLIT TEXT
+ { $$ = new quoted_text_box($2); }
+ | '^'
+ { $$ = new half_space_box; }
+ | '~'
+ { $$ = new space_box; }
+ | '\t'
+ { $$ = new tab_box; }
+ | '{' equation '}'
+ { $$ = $2; }
+ | PILE pile_arg
+ { $2->set_alignment(CENTER_ALIGN); $$ = $2; }
+ | LPILE pile_arg
+ { $2->set_alignment(LEFT_ALIGN); $$ = $2; }
+ | RPILE pile_arg
+ { $2->set_alignment(RIGHT_ALIGN); $$ = $2; }
+ | CPILE pile_arg
+ { $2->set_alignment(CENTER_ALIGN); $$ = $2; }
+ | MATRIX '{' column_list '}'
+ { $$ = $3; }
+ | LEFT delim equation RIGHT delim
+ { $$ = make_delim_box($2, $3, $5); }
+ | LEFT delim equation
+ { $$ = make_delim_box($2, $3, 0); }
+ | simple BAR
+ { $$ = make_overline_box($1); }
+ | simple UNDER
+ { $$ = make_underline_box($1); }
+ | simple PRIME
+ { $$ = make_prime_box($1); }
+ | simple ACCENT simple
+ { $$ = make_accent_box($1, $3); }
+ | simple UACCENT simple
+ { $$ = make_uaccent_box($1, $3); }
+ | ROMAN simple
+ { $$ = new font_box(strsave(get_grfont()), $2); }
+ | BOLD simple
+ { $$ = new font_box(strsave(get_gbfont()), $2); }
+ | ITALIC simple
+ { $$ = new font_box(strsave(get_gfont()), $2); }
+ | FAT simple
+ { $$ = new fat_box($2); }
+ | FONT text simple
+ { $$ = new font_box($2, $3); }
+ | SIZE text simple
+ { $$ = new size_box($2, $3); }
+ | FWD number simple
+ { $$ = new hmotion_box($2, $3); }
+ | BACK number simple
+ { $$ = new hmotion_box(-$2, $3); }
+ | UP number simple
+ { $$ = new vmotion_box($2, $3); }
+ | DOWN number simple
+ { $$ = new vmotion_box(-$2, $3); }
+ | TYPE text simple
+ { $3->set_spacing_type($2); $$ = $3; }
+ | VCENTER simple
+ { $$ = new vcenter_box($2); }
+ | SPECIAL text simple
+ { $$ = make_special_box($2, $3); }
+ ;
+
+number:
+ text
+ {
+ int n;
+ if (sscanf($1, "%d", &n) == 1)
+ $$ = n;
+ a_delete $1;
+ }
+ ;
+
+pile_element_list:
+ equation
+ { $$ = new pile_box($1); }
+ | pile_element_list ABOVE equation
+ { $1->append($3); $$ = $1; }
+ ;
+
+pile_arg:
+ '{' pile_element_list '}'
+ { $$ = $2; }
+ | number '{' pile_element_list '}'
+ { $3->set_space($1); $$ = $3; }
+ ;
+
+column_list:
+ column
+ { $$ = new matrix_box($1); }
+ | column_list column
+ { $1->append($2); $$ = $1; }
+ ;
+
+column_element_list:
+ equation
+ { $$ = new column($1); }
+ | column_element_list ABOVE equation
+ { $1->append($3); $$ = $1; }
+ ;
+
+column_arg:
+ '{' column_element_list '}'
+ { $$ = $2; }
+ | number '{' column_element_list '}'
+ { $3->set_space($1); $$ = $3; }
+ ;
+
+column:
+ COL column_arg
+ { $2->set_alignment(CENTER_ALIGN); $$ = $2; }
+ | LCOL column_arg
+ { $2->set_alignment(LEFT_ALIGN); $$ = $2; }
+ | RCOL column_arg
+ { $2->set_alignment(RIGHT_ALIGN); $$ = $2; }
+ | CCOL column_arg
+ { $2->set_alignment(CENTER_ALIGN); $$ = $2; }
+ ;
+
+text: TEXT
+ { $$ = $1; }
+ | QUOTED_TEXT
+ { $$ = $1; }
+ ;
+
+delim:
+ text
+ { $$ = $1; }
+ | '{'
+ { $$ = strsave("{"); }
+ | '}'
+ { $$ = strsave("}"); }
+ ;
+
+%%
diff --git a/gnu/usr.bin/groff/eqn/lex.cc b/gnu/usr.bin/groff/eqn/lex.cc
new file mode 100644
index 0000000..5537f91
--- /dev/null
+++ b/gnu/usr.bin/groff/eqn/lex.cc
@@ -0,0 +1,1160 @@
+// -*- C++ -*-
+/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
+ Written by James Clark (jjc@jclark.com)
+
+This file is part of groff.
+
+groff is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
+
+groff is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License along
+with groff; see the file COPYING. If not, write to the Free Software
+Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "eqn.h"
+#include "eqn.tab.h"
+#include "stringclass.h"
+#include "ptable.h"
+
+struct definition {
+ char is_macro;
+ char is_simple;
+ union {
+ int tok;
+ char *contents;
+ };
+ definition();
+ ~definition();
+};
+
+definition::definition() : is_macro(1), is_simple(0)
+{
+ contents = 0;
+}
+
+definition::~definition()
+{
+ if (is_macro)
+ a_delete contents;
+}
+
+declare_ptable(definition)
+implement_ptable(definition)
+
+PTABLE(definition) macro_table;
+
+static struct {
+ const char *name;
+ int token;
+} token_table[] = {
+ { "over", OVER },
+ { "smallover", SMALLOVER },
+ { "sqrt", SQRT },
+ { "sub", SUB },
+ { "sup", SUP },
+ { "lpile", LPILE },
+ { "rpile", RPILE },
+ { "cpile", CPILE },
+ { "pile", PILE },
+ { "left", LEFT },
+ { "right", RIGHT },
+ { "to", TO },
+ { "from", FROM },
+ { "size", SIZE },
+ { "font", FONT },
+ { "roman", ROMAN },
+ { "bold", BOLD },
+ { "italic", ITALIC },
+ { "fat", FAT },
+ { "bar", BAR },
+ { "under", UNDER },
+ { "accent", ACCENT },
+ { "uaccent", UACCENT },
+ { "above", ABOVE },
+ { "fwd", FWD },
+ { "back", BACK },
+ { "down", DOWN },
+ { "up", UP },
+ { "matrix", MATRIX },
+ { "col", COL },
+ { "lcol", LCOL },
+ { "rcol", RCOL },
+ { "ccol", CCOL },
+ { "mark", MARK },
+ { "lineup", LINEUP },
+ { "space", SPACE },
+ { "gfont", GFONT },
+ { "gsize", GSIZE },
+ { "define", DEFINE },
+ { "sdefine", SDEFINE },
+ { "ndefine", NDEFINE },
+ { "tdefine", TDEFINE },
+ { "undef", UNDEF },
+ { "ifdef", IFDEF },
+ { "include", INCLUDE },
+ { "copy", INCLUDE },
+ { "delim", DELIM },
+ { "chartype", CHARTYPE },
+ { "type", TYPE },
+ { "vcenter", VCENTER },
+ { "set", SET },
+ { "opprime", PRIME },
+ { "grfont", GRFONT },
+ { "gbfont", GBFONT },
+ { "split", SPLIT },
+ { "nosplit", NOSPLIT },
+ { "special", SPECIAL },
+};
+
+static struct {
+ const char *name;
+ const char *def;
+} def_table[] = {
+ { "ALPHA", "\\(*A" },
+ { "BETA", "\\(*B" },
+ { "CHI", "\\(*X" },
+ { "DELTA", "\\(*D" },
+ { "EPSILON", "\\(*E" },
+ { "ETA", "\\(*Y" },
+ { "GAMMA", "\\(*G" },
+ { "IOTA", "\\(*I" },
+ { "KAPPA", "\\(*K" },
+ { "LAMBDA", "\\(*L" },
+ { "MU", "\\(*M" },
+ { "NU", "\\(*N" },
+ { "OMEGA", "\\(*W" },
+ { "OMICRON", "\\(*O" },
+ { "PHI", "\\(*F" },
+ { "PI", "\\(*P" },
+ { "PSI", "\\(*Q" },
+ { "RHO", "\\(*R" },
+ { "SIGMA", "\\(*S" },
+ { "TAU", "\\(*T" },
+ { "THETA", "\\(*H" },
+ { "UPSILON", "\\(*U" },
+ { "XI", "\\(*C" },
+ { "ZETA", "\\(*Z" },
+ { "Alpha", "\\(*A" },
+ { "Beta", "\\(*B" },
+ { "Chi", "\\(*X" },
+ { "Delta", "\\(*D" },
+ { "Epsilon", "\\(*E" },
+ { "Eta", "\\(*Y" },
+ { "Gamma", "\\(*G" },
+ { "Iota", "\\(*I" },
+ { "Kappa", "\\(*K" },
+ { "Lambda", "\\(*L" },
+ { "Mu", "\\(*M" },
+ { "Nu", "\\(*N" },
+ { "Omega", "\\(*W" },
+ { "Omicron", "\\(*O" },
+ { "Phi", "\\(*F" },
+ { "Pi", "\\(*P" },
+ { "Psi", "\\(*Q" },
+ { "Rho", "\\(*R" },
+ { "Sigma", "\\(*S" },
+ { "Tau", "\\(*T" },
+ { "Theta", "\\(*H" },
+ { "Upsilon", "\\(*U" },
+ { "Xi", "\\(*C" },
+ { "Zeta", "\\(*Z" },
+ { "alpha", "\\(*a" },
+ { "beta", "\\(*b" },
+ { "chi", "\\(*x" },
+ { "delta", "\\(*d" },
+ { "epsilon", "\\(*e" },
+ { "eta", "\\(*y" },
+ { "gamma", "\\(*g" },
+ { "iota", "\\(*i" },
+ { "kappa", "\\(*k" },
+ { "lambda", "\\(*l" },
+ { "mu", "\\(*m" },
+ { "nu", "\\(*n" },
+ { "omega", "\\(*w" },
+ { "omicron", "\\(*o" },
+ { "phi", "\\(*f" },
+ { "pi", "\\(*p" },
+ { "psi", "\\(*q" },
+ { "rho", "\\(*r" },
+ { "sigma", "\\(*s" },
+ { "tau", "\\(*t" },
+ { "theta", "\\(*h" },
+ { "upsilon", "\\(*u" },
+ { "xi", "\\(*c" },
+ { "zeta", "\\(*z" },
+ { "max", "{type \"operator\" roman \"max\"}" },
+ { "min", "{type \"operator\" roman \"min\"}" },
+ { "lim", "{type \"operator\" roman \"lim\"}" },
+ { "sin", "{type \"operator\" roman \"sin\"}" },
+ { "cos", "{type \"operator\" roman \"cos\"}" },
+ { "tan", "{type \"operator\" roman \"tan\"}" },
+ { "sinh", "{type \"operator\" roman \"sinh\"}" },
+ { "cosh", "{type \"operator\" roman \"cosh\"}" },
+ { "tanh", "{type \"operator\" roman \"tanh\"}" },
+ { "arc", "{type \"operator\" roman \"arc\"}" },
+ { "log", "{type \"operator\" roman \"log\"}" },
+ { "ln", "{type \"operator\" roman \"ln\"}" },
+ { "exp", "{type \"operator\" roman \"exp\"}" },
+ { "Re", "{type \"operator\" roman \"Re\"}" },
+ { "Im", "{type \"operator\" roman \"Im\"}" },
+ { "det", "{type \"operator\" roman \"det\"}" },
+ { "and", "{roman \"and\"}" },
+ { "if", "{roman \"if\"}" },
+ { "for", "{roman \"for\"}" },
+ { "sum", "{type \"operator\" vcenter size +5 \\(*S}" },
+ { "prod", "{type \"operator\" vcenter size +5 \\(*P}" },
+ { "int", "{type \"operator\" vcenter size +8 \\(is}" },
+ { "union", "{type \"operator\" vcenter size +5 \\(cu}" },
+ { "inter", "{type \"operator\" vcenter size +5 \\(ca}" },
+ { "times", "type \"binary\" \\(mu" },
+ { "ldots", "type \"inner\" { . . . }" },
+ { "inf", "\\(if" },
+ { "partial", "\\(pd" },
+ { "nothing", "\"\"" },
+ { "half", "{1 smallover 2}" },
+ { "hat_def", "roman \"^\"" },
+ { "hat", "accent { hat_def }" },
+ { "dot_def", "back 15 \"\\v'-52M'.\\v'52M'\"" },
+ { "dot", "accent { dot_def }" },
+ { "dotdot_def", "back 25 \"\\v'-52M'..\\v'52M'\"" },
+ { "dotdot", "accent { dotdot_def }" },
+ { "tilde_def", "\"~\"" },
+ { "tilde", "accent { tilde_def }" },
+ { "utilde_def", "\"\\v'75M'~\\v'-75M'\"" },
+ { "utilde", "uaccent { utilde_def }" },
+ { "vec_def", "up 52 size -5 \\(->" },
+ { "vec", "accent { vec_def }" },
+ { "dyad_def", "up 52 size -5 {\\(<- back 60 \\(->}" },
+ { "dyad", "accent { dyad_def }" },
+ { "==", "type \"relation\" \\(==" },
+ { "!=", "type \"relation\" \\(!=" },
+ { "+-", "type \"binary\" \\(+-" },
+ { "->", "type \"relation\" \\(->" },
+ { "<-", "type \"relation\" \\(<-" },
+ { "<<", "{ < back 20 < }" },
+ { ">>", "{ > back 20 > }" },
+ { "...", "type \"inner\" vcenter { . . . }" },
+ { "prime", "'" },
+ { "approx", "type \"relation\" \"\\(~=\"" },
+ { "grad", "\\(gr" },
+ { "del", "\\(gr" },
+ { "cdot", "type \"binary\" vcenter ." },
+ { "dollar", "$" },
+};
+
+void init_table(const char *device)
+{
+ for (int i = 0; i < sizeof(token_table)/sizeof(token_table[0]); i++) {
+ definition *def = new definition;
+ def->is_macro = 0;
+ def->tok = token_table[i].token;
+ macro_table.define(token_table[i].name, def);
+ }
+ for (i = 0; i < sizeof(def_table)/sizeof(def_table[0]); i++) {
+ definition *def = new definition;
+ def->is_macro = 1;
+ def->contents = strsave(def_table[i].def);
+ def->is_simple = 1;
+ macro_table.define(def_table[i].name, def);
+ }
+ definition *def = new definition;
+ def->is_macro = 1;
+ def->contents = strsave("1");
+ macro_table.define(device, def);
+}
+
+class input {
+ input *next;
+public:
+ input(input *p);
+ virtual ~input();
+ virtual int get() = 0;
+ virtual int peek() = 0;
+ virtual int get_location(char **, int *);
+
+ friend int get_char();
+ friend int peek_char();
+ friend int get_location(char **, int *);
+ friend void init_lex(const char *str, const char *filename, int lineno);
+};
+
+class file_input : public input {
+ FILE *fp;
+ char *filename;
+ int lineno;
+ string line;
+ const char *ptr;
+ int read_line();
+public:
+ file_input(FILE *, const char *, input *);
+ ~file_input();
+ int get();
+ int peek();
+ int get_location(char **, int *);
+};
+
+
+class macro_input : public input {
+ char *s;
+ char *p;
+public:
+ macro_input(const char *, input *);
+ ~macro_input();
+ int get();
+ int peek();
+};
+
+class top_input : public macro_input {
+ char *filename;
+ int lineno;
+ public:
+ top_input(const char *, const char *, int, input *);
+ ~top_input();
+ int get();
+ int get_location(char **, int *);
+};
+
+class argument_macro_input: public input {
+ char *s;
+ char *p;
+ char *ap;
+ int argc;
+ char *argv[9];
+public:
+ argument_macro_input(const char *, int, char **, input *);
+ ~argument_macro_input();
+ int get();
+ int peek();
+};
+
+input::input(input *x) : next(x)
+{
+}
+
+input::~input()
+{
+}
+
+int input::get_location(char **, int *)
+{
+ return 0;
+}
+
+file_input::file_input(FILE *f, const char *fn, input *p)
+: input(p), lineno(0), ptr("")
+{
+ fp = f;
+ filename = strsave(fn);
+}
+
+file_input::~file_input()
+{
+ a_delete filename;
+ fclose(fp);
+}
+
+int file_input::read_line()
+{
+ for (;;) {
+ line.clear();
+ lineno++;
+ for (;;) {
+ int c = getc(fp);
+ if (c == EOF)
+ break;
+ else if (illegal_input_char(c))
+ lex_error("illegal input character code %1", c);
+ else {
+ line += char(c);
+ if (c == '\n')
+ break;
+ }
+ }
+ if (line.length() == 0)
+ return 0;
+ if (!(line.length() >= 3 && line[0] == '.' && line[1] == 'E'
+ && (line[2] == 'Q' || line[2] == 'N')
+ && (line.length() == 3 || line[3] == ' ' || line[3] == '\n'
+ || compatible_flag))) {
+ line += '\0';
+ ptr = line.contents();
+ return 1;
+ }
+ }
+}
+
+int file_input::get()
+{
+ if (*ptr != '\0' || read_line())
+ return *ptr++ & 0377;
+ else
+ return EOF;
+}
+
+int file_input::peek()
+{
+ if (*ptr != '\0' || read_line())
+ return *ptr;
+ else
+ return EOF;
+}
+
+int file_input::get_location(char **fnp, int *lnp)
+{
+ *fnp = filename;
+ *lnp = lineno;
+ return 1;
+}
+
+macro_input::macro_input(const char *str, input *x) : input(x)
+{
+ p = s = strsave(str);
+}
+
+macro_input::~macro_input()
+{
+ a_delete s;
+}
+
+int macro_input::get()
+{
+ if (p == 0 || *p == '\0')
+ return EOF;
+ else
+ return *p++ & 0377;
+}
+
+int macro_input::peek()
+{
+ if (p == 0 || *p == '\0')
+ return EOF;
+ else
+ return *p & 0377;
+}
+
+top_input::top_input(const char *str, const char *fn, int ln, input *x)
+: macro_input(str, x), lineno(ln)
+{
+ filename = strsave(fn);
+}
+
+top_input::~top_input()
+{
+ a_delete filename;
+}
+
+int top_input::get()
+{
+ int c = macro_input::get();
+ if (c == '\n')
+ lineno++;
+ return c;
+}
+
+int top_input::get_location(char **fnp, int *lnp)
+{
+ *fnp = filename;
+ *lnp = lineno;
+ return 1;
+}
+
+// Character representing $1. Must be illegal input character.
+#define ARG1 14
+
+argument_macro_input::argument_macro_input(const char *body, int ac,
+ char **av, input *x)
+: input(x), argc(ac), ap(0)
+{
+ for (int i = 0; i < argc; i++)
+ argv[i] = av[i];
+ p = s = strsave(body);
+ int j = 0;
+ for (i = 0; s[i] != '\0'; i++)
+ if (s[i] == '$' && s[i+1] >= '0' && s[i+1] <= '9') {
+ if (s[i+1] != '0')
+ s[j++] = ARG1 + s[++i] - '1';
+ }
+ else
+ s[j++] = s[i];
+ s[j] = '\0';
+}
+
+
+argument_macro_input::~argument_macro_input()
+{
+ for (int i = 0; i < argc; i++)
+ a_delete argv[i];
+ a_delete s;
+}
+
+int argument_macro_input::get()
+{
+ if (ap) {
+ if (*ap != '\0')
+ return *ap++ & 0377;
+ ap = 0;
+ }
+ if (p == 0)
+ return EOF;
+ while (*p >= ARG1 && *p <= ARG1 + 8) {
+ int i = *p++ - ARG1;
+ if (i < argc && argv[i] != 0 && argv[i][0] != '\0') {
+ ap = argv[i];
+ return *ap++ & 0377;
+ }
+ }
+ if (*p == '\0')
+ return EOF;
+ return *p++ & 0377;
+}
+
+int argument_macro_input::peek()
+{
+ if (ap) {
+ if (*ap != '\0')
+ return *ap & 0377;
+ ap = 0;
+ }
+ if (p == 0)
+ return EOF;
+ while (*p >= ARG1 && *p <= ARG1 + 8) {
+ int i = *p++ - ARG1;
+ if (i < argc && argv[i] != 0 && argv[i][0] != '\0') {
+ ap = argv[i];
+ return *ap & 0377;
+ }
+ }
+ if (*p == '\0')
+ return EOF;
+ return *p & 0377;
+}
+
+static input *current_input = 0;
+
+/* we insert a newline between input from different levels */
+
+int get_char()
+{
+ if (current_input == 0)
+ return EOF;
+ else {
+ int c = current_input->get();
+ if (c != EOF)
+ return c;
+ else {
+ input *tem = current_input;
+ current_input = current_input->next;
+ delete tem;
+ return '\n';
+ }
+ }
+}
+
+int peek_char()
+{
+ if (current_input == 0)
+ return EOF;
+ else {
+ int c = current_input->peek();
+ if (c != EOF)
+ return c;
+ else
+ return '\n';
+ }
+}
+
+int get_location(char **fnp, int *lnp)
+{
+ for (input *p = current_input; p; p = p->next)
+ if (p->get_location(fnp, lnp))
+ return 1;
+ return 0;
+}
+
+string token_buffer;
+const int NCONTEXT = 4;
+string context_ring[NCONTEXT];
+int context_index = 0;
+
+void flush_context()
+{
+ for (int i = 0; i < NCONTEXT; i++)
+ context_ring[i] = "";
+ context_index = 0;
+}
+
+void show_context()
+{
+ int i = context_index;
+ fputs(" context is\n\t", stderr);
+ for (;;) {
+ int j = (i + 1) % NCONTEXT;
+ if (j == context_index) {
+ fputs(">>> ", stderr);
+ put_string(context_ring[i], stderr);
+ fputs(" <<<", stderr);
+ break;
+ }
+ else if (context_ring[i].length() > 0) {
+ put_string(context_ring[i], stderr);
+ putc(' ', stderr);
+ }
+ i = j;
+ }
+ putc('\n', stderr);
+}
+
+void add_context(const string &s)
+{
+ context_ring[context_index] = s;
+ context_index = (context_index + 1) % NCONTEXT;
+}
+
+void add_context(char c)
+{
+ context_ring[context_index] = c;
+ context_index = (context_index + 1) % NCONTEXT;
+}
+
+void add_quoted_context(const string &s)
+{
+ string &r = context_ring[context_index];
+ r = '"';
+ for (int i = 0; i < s.length(); i++)
+ if (s[i] == '"')
+ r += "\\\"";
+ else
+ r += s[i];
+ r += '"';
+ context_index = (context_index + 1) % NCONTEXT;
+}
+
+void init_lex(const char *str, const char *filename, int lineno)
+{
+ while (current_input != 0) {
+ input *tem = current_input;
+ current_input = current_input->next;
+ delete tem;
+ }
+ current_input = new top_input(str, filename, lineno, 0);
+ flush_context();
+}
+
+
+void get_delimited_text()
+{
+ char *filename;
+ int lineno;
+ int got_location = get_location(&filename, &lineno);
+ int start = get_char();
+ while (start == ' ' || start == '\t' || start == '\n')
+ start = get_char();
+ token_buffer.clear();
+ if (start == EOF) {
+ if (got_location)
+ error_with_file_and_line(filename, lineno,
+ "end of input while defining macro");
+ else
+ error("end of input while defining macro");
+ return;
+ }
+ for (;;) {
+ int c = get_char();
+ if (c == EOF) {
+ if (got_location)
+ error_with_file_and_line(filename, lineno,
+ "end of input while defining macro");
+ else
+ error("end of input while defining macro");
+ add_context(start + token_buffer);
+ return;
+ }
+ if (c == start)
+ break;
+ token_buffer += char(c);
+ }
+ add_context(start + token_buffer + start);
+}
+
+void interpolate_macro_with_args(const char *body)
+{
+ char *argv[9];
+ int argc = 0;
+ for (int i = 0; i < 9; i++)
+ argv[i] = 0;
+ int level = 0;
+ int c;
+ do {
+ token_buffer.clear();
+ for (;;) {
+ c = get_char();
+ if (c == EOF) {
+ lex_error("end of input while scanning macro arguments");
+ break;
+ }
+ if (level == 0 && (c == ',' || c == ')')) {
+ if (token_buffer.length() > 0) {
+ token_buffer += '\0';
+ argv[argc] = strsave(token_buffer.contents());
+ }
+ // for `foo()', argc = 0
+ if (argc > 0 || c != ')' || i > 0)
+ argc++;
+ break;
+ }
+ token_buffer += char(c);
+ if (c == '(')
+ level++;
+ else if (c == ')')
+ level--;
+ }
+ } while (c != ')' && c != EOF);
+ current_input = new argument_macro_input(body, argc, argv, current_input);
+}
+
+/* If lookup flag is non-zero the token will be looked up to see
+if it is macro. If it's 1, it will looked up to see if it's a token.
+*/
+
+int get_token(int lookup_flag = 0)
+{
+ for (;;) {
+ int c = get_char();
+ while (c == ' ' || c == '\n')
+ c = get_char();
+ switch (c) {
+ case EOF:
+ add_context("end of input");
+ return 0;
+ case '"':
+ {
+ int quoted = 0;
+ token_buffer.clear();
+ for (;;) {
+ c = get_char();
+ if (c == EOF) {
+ lex_error("missing \"");
+ break;
+ }
+ else if (c == '\n') {
+ lex_error("newline before end of quoted text");
+ break;
+ }
+ else if (c == '"') {
+ if (!quoted)
+ break;
+ token_buffer[token_buffer.length() - 1] = '"';
+ quoted = 0;
+ }
+ else {
+ token_buffer += c;
+ quoted = quoted ? 0 : c == '\\';
+ }
+ }
+ }
+ add_quoted_context(token_buffer);
+ return QUOTED_TEXT;
+ case '{':
+ case '}':
+ case '^':
+ case '~':
+ case '\t':
+ add_context(c);
+ return c;
+ default:
+ {
+ int break_flag = 0;
+ int quoted = 0;
+ token_buffer.clear();
+ if (c == '\\')
+ quoted = 1;
+ else
+ token_buffer += c;
+ int done = 0;
+ while (!done) {
+ c = peek_char();
+ if (!quoted && lookup_flag != 0 && c == '(') {
+ token_buffer += '\0';
+ definition *def = macro_table.lookup(token_buffer.contents());
+ if (def && def->is_macro && !def->is_simple) {
+ (void)get_char(); // skip initial '('
+ interpolate_macro_with_args(def->contents);
+ break_flag = 1;
+ break;
+ }
+ token_buffer.set_length(token_buffer.length() - 1);
+ }
+ if (quoted) {
+ quoted = 0;
+ switch (c) {
+ case EOF:
+ lex_error("`\\' ignored at end of equation");
+ done = 1;
+ break;
+ case '\n':
+ lex_error("`\\' ignored because followed by newline");
+ done = 1;
+ break;
+ case '\t':
+ lex_error("`\\' ignored because followed by tab");
+ done = 1;
+ break;
+ case '"':
+ (void)get_char();
+ token_buffer += '"';
+ break;
+ default:
+ (void)get_char();
+ token_buffer += '\\';
+ token_buffer += c;
+ break;
+ }
+ }
+ else {
+ switch (c) {
+ case EOF:
+ case '{':
+ case '}':
+ case '^':
+ case '~':
+ case '"':
+ case ' ':
+ case '\t':
+ case '\n':
+ done = 1;
+ break;
+ case '\\':
+ (void)get_char();
+ quoted = 1;
+ break;
+ default:
+ (void)get_char();
+ token_buffer += char(c);
+ break;
+ }
+ }
+ }
+ if (break_flag || token_buffer.length() == 0)
+ break;
+ if (lookup_flag != 0) {
+ token_buffer += '\0';
+ definition *def = macro_table.lookup(token_buffer.contents());
+ token_buffer.set_length(token_buffer.length() - 1);
+ if (def) {
+ if (def->is_macro) {
+ current_input = new macro_input(def->contents, current_input);
+ break;
+ }
+ else if (lookup_flag == 1) {
+ add_context(token_buffer);
+ return def->tok;
+ }
+ }
+ }
+ add_context(token_buffer);
+ return TEXT;
+ }
+ }
+ }
+}
+
+void do_include()
+{
+ int t = get_token(2);
+ if (t != TEXT && t != QUOTED_TEXT) {
+ lex_error("bad filename for include");
+ return;
+ }
+ token_buffer += '\0';
+ const char *filename = token_buffer.contents();
+ errno = 0;
+ FILE *fp = fopen(filename, "r");
+ if (fp == 0) {
+ lex_error("can't open included file `%1'", filename);
+ return;
+ }
+ current_input = new file_input(fp, filename, current_input);
+}
+
+void ignore_definition()
+{
+ int t = get_token();
+ if (t != TEXT) {
+ lex_error("bad definition");
+ return;
+ }
+ get_delimited_text();
+}
+
+void do_definition(int is_simple)
+{
+ int t = get_token();
+ if (t != TEXT) {
+ lex_error("bad definition");
+ return;
+ }
+ token_buffer += '\0';
+ const char *name = token_buffer.contents();
+ definition *def = macro_table.lookup(name);
+ if (def == 0) {
+ def = new definition;
+ macro_table.define(name, def);
+ }
+ else if (def->is_macro) {
+ a_delete def->contents;
+ }
+ get_delimited_text();
+ token_buffer += '\0';
+ def->is_macro = 1;
+ def->contents = strsave(token_buffer.contents());
+ def->is_simple = is_simple;
+}
+
+void do_undef()
+{
+ int t = get_token();
+ if (t != TEXT) {
+ lex_error("bad undef command");
+ return;
+ }
+ token_buffer += '\0';
+ macro_table.define(token_buffer.contents(), 0);
+}
+
+void do_gsize()
+{
+ int t = get_token(2);
+ if (t != TEXT && t != QUOTED_TEXT) {
+ lex_error("bad argument to gsize command");
+ return;
+ }
+ token_buffer += '\0';
+ if (!set_gsize(token_buffer.contents()))
+ lex_error("invalid size `%1'", token_buffer.contents());
+}
+
+void do_gfont()
+{
+ int t = get_token(2);
+ if (t != TEXT && t != QUOTED_TEXT) {
+ lex_error("bad argument to gfont command");
+ return;
+ }
+ token_buffer += '\0';
+ set_gfont(token_buffer.contents());
+}
+
+void do_grfont()
+{
+ int t = get_token(2);
+ if (t != TEXT && t != QUOTED_TEXT) {
+ lex_error("bad argument to grfont command");
+ return;
+ }
+ token_buffer += '\0';
+ set_grfont(token_buffer.contents());
+}
+
+void do_gbfont()
+{
+ int t = get_token(2);
+ if (t != TEXT && t != QUOTED_TEXT) {
+ lex_error("bad argument to gbfont command");
+ return;
+ }
+ token_buffer += '\0';
+ set_gbfont(token_buffer.contents());
+}
+
+void do_space()
+{
+ int t = get_token(2);
+ if (t != TEXT && t != QUOTED_TEXT) {
+ lex_error("bad argument to space command");
+ return;
+ }
+ token_buffer += '\0';
+ char *ptr;
+ long n = strtol(token_buffer.contents(), &ptr, 10);
+ if (n == 0 && ptr == token_buffer.contents())
+ lex_error("bad argument `%1' to space command");
+ else
+ set_space(int(n));
+}
+
+void do_ifdef()
+{
+ int t = get_token();
+ if (t != TEXT) {
+ lex_error("bad ifdef");
+ return;
+ }
+ token_buffer += '\0';
+ definition *def = macro_table.lookup(token_buffer.contents());
+ int result = def && def->is_macro && !def->is_simple;
+ get_delimited_text();
+ if (result) {
+ token_buffer += '\0';
+ current_input = new macro_input(token_buffer.contents(), current_input);
+ }
+}
+
+void do_delim()
+{
+ int c = get_char();
+ while (c == ' ' || c == '\n')
+ c = get_char();
+ int d;
+ if (c == EOF || (d = get_char()) == EOF)
+ lex_error("end of file while reading argument to `delim'");
+ else {
+ if (c == 'o' && d == 'f' && peek_char() == 'f') {
+ (void)get_char();
+ start_delim = end_delim = '\0';
+ }
+ else {
+ start_delim = c;
+ end_delim = d;
+ }
+ }
+}
+
+void do_chartype()
+{
+ int t = get_token(2);
+ if (t != TEXT && t != QUOTED_TEXT) {
+ lex_error("bad chartype");
+ return;
+ }
+ token_buffer += '\0';
+ string type = token_buffer;
+ t = get_token();
+ if (t != TEXT && t != QUOTED_TEXT) {
+ lex_error("bad chartype");
+ return;
+ }
+ token_buffer += '\0';
+ set_char_type(type.contents(), strsave(token_buffer.contents()));
+}
+
+void do_set()
+{
+ int t = get_token(2);
+ if (t != TEXT && t != QUOTED_TEXT) {
+ lex_error("bad set");
+ return;
+ }
+ token_buffer += '\0';
+ string param = token_buffer;
+ t = get_token();
+ if (t != TEXT && t != QUOTED_TEXT) {
+ lex_error("bad set");
+ return;
+ }
+ token_buffer += '\0';
+ int n;
+ if (sscanf(&token_buffer[0], "%d", &n) != 1) {
+ lex_error("bad number `%1'", token_buffer.contents());
+ return;
+ }
+ set_param(param.contents(), n);
+}
+
+int yylex()
+{
+ for (;;) {
+ int tk = get_token(1);
+ switch(tk) {
+ case UNDEF:
+ do_undef();
+ break;
+ case SDEFINE:
+ do_definition(1);
+ break;
+ case DEFINE:
+ do_definition(0);
+ break;
+ case TDEFINE:
+ if (!nroff)
+ do_definition(0);
+ else
+ ignore_definition();
+ break;
+ case NDEFINE:
+ if (nroff)
+ do_definition(0);
+ else
+ ignore_definition();
+ break;
+ case GSIZE:
+ do_gsize();
+ break;
+ case GFONT:
+ do_gfont();
+ break;
+ case GRFONT:
+ do_grfont();
+ break;
+ case GBFONT:
+ do_gbfont();
+ break;
+ case SPACE:
+ do_space();
+ break;
+ case INCLUDE:
+ do_include();
+ break;
+ case IFDEF:
+ do_ifdef();
+ break;
+ case DELIM:
+ do_delim();
+ break;
+ case CHARTYPE:
+ do_chartype();
+ break;
+ case SET:
+ do_set();
+ break;
+ case QUOTED_TEXT:
+ case TEXT:
+ token_buffer += '\0';
+ yylval.str = strsave(token_buffer.contents());
+ // fall through
+ default:
+ return tk;
+ }
+ }
+}
+
+void lex_error(const char *message,
+ const errarg &arg1,
+ const errarg &arg2,
+ const errarg &arg3)
+{
+ char *filename;
+ int lineno;
+ if (!get_location(&filename, &lineno))
+ error(message, arg1, arg2, arg3);
+ else
+ error_with_file_and_line(filename, lineno, message, arg1, arg2, arg3);
+}
+
+void yyerror(const char *s)
+{
+ char *filename;
+ int lineno;
+ if (!get_location(&filename, &lineno))
+ error(s);
+ else
+ error_with_file_and_line(filename, lineno, s);
+ show_context();
+}
+
diff --git a/gnu/usr.bin/groff/eqn/limit.cc b/gnu/usr.bin/groff/eqn/limit.cc
new file mode 100644
index 0000000..04abced
--- /dev/null
+++ b/gnu/usr.bin/groff/eqn/limit.cc
@@ -0,0 +1,195 @@
+// -*- C++ -*-
+/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
+ Written by James Clark (jjc@jclark.com)
+
+This file is part of groff.
+
+groff is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
+
+groff is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License along
+with groff; see the file COPYING. If not, write to the Free Software
+Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "eqn.h"
+#include "pbox.h"
+
+class limit_box : public box {
+private:
+ box *p;
+ box *from;
+ box *to;
+public:
+ limit_box(box *, box *, box *);
+ ~limit_box();
+ int compute_metrics(int);
+ void output();
+ void debug_print();
+ void check_tabs(int);
+};
+
+box *make_limit_box(box *pp, box *qq, box *rr)
+{
+ return new limit_box(pp, qq, rr);
+}
+
+limit_box::limit_box(box *pp, box *qq, box *rr)
+: p(pp), from(qq), to(rr)
+{
+ spacing_type = p->spacing_type;
+}
+
+limit_box::~limit_box()
+{
+ delete p;
+ delete from;
+ delete to;
+}
+
+int limit_box::compute_metrics(int style)
+{
+ printf(".nr " SIZE_FORMAT " \\n[.s]\n", uid);
+ if (!(style <= SCRIPT_STYLE && one_size_reduction_flag))
+ set_script_size();
+ printf(".nr " SMALL_SIZE_FORMAT " \\n[.s]\n", uid);
+ int res = 0;
+ int mark_uid = -1;
+ if (from != 0) {
+ res = from->compute_metrics(cramped_style(script_style(style)));
+ if (res)
+ mark_uid = from->uid;
+ }
+ if (to != 0) {
+ int r = to->compute_metrics(script_style(style));
+ if (res && r)
+ error("multiple marks and lineups");
+ else {
+ mark_uid = to->uid;
+ res = r;
+ }
+ }
+ printf(".ps \\n[" SIZE_FORMAT "]\n", uid);
+ int r = p->compute_metrics(style);
+ p->compute_subscript_kern();
+ if (res && r)
+ error("multiple marks and lineups");
+ else {
+ mark_uid = p->uid;
+ res = r;
+ }
+ printf(".nr " LEFT_WIDTH_FORMAT " "
+ "0\\n[" WIDTH_FORMAT "]",
+ uid, p->uid);
+ if (from != 0)
+ printf(">?(\\n[" SUB_KERN_FORMAT "]+\\n[" WIDTH_FORMAT "])",
+ p->uid, from->uid);
+ if (to != 0)
+ printf(">?(-\\n[" SUB_KERN_FORMAT "]+\\n[" WIDTH_FORMAT "])",
+ p->uid, to->uid);
+ printf("/2\n");
+ printf(".nr " WIDTH_FORMAT " "
+ "0\\n[" WIDTH_FORMAT "]",
+ uid, p->uid);
+ if (from != 0)
+ printf(">?(-\\n[" SUB_KERN_FORMAT "]+\\n[" WIDTH_FORMAT "])",
+ p->uid, from->uid);
+ if (to != 0)
+ printf(">?(\\n[" SUB_KERN_FORMAT "]+\\n[" WIDTH_FORMAT "])",
+ p->uid, to->uid);
+ printf("/2+\\n[" LEFT_WIDTH_FORMAT "]\n", uid);
+ printf(".nr " WIDTH_FORMAT " 0\\n[" WIDTH_FORMAT "]", uid, p->uid);
+ if (to != 0)
+ printf(">?\\n[" WIDTH_FORMAT "]", to->uid);
+ if (from != 0)
+ printf(">?\\n[" WIDTH_FORMAT "]", from->uid);
+ printf("\n");
+ if (res)
+ printf(".nr " MARK_REG " +(\\n[" LEFT_WIDTH_FORMAT "]"
+ "-(\\n[" WIDTH_FORMAT "]/2))\n",
+ uid, mark_uid);
+ if (to != 0) {
+ printf(".nr " SUP_RAISE_FORMAT " %dM+\\n[" DEPTH_FORMAT
+ "]>?%dM+\\n[" HEIGHT_FORMAT "]\n",
+ uid, big_op_spacing1, to->uid, big_op_spacing3, p->uid);
+ printf(".nr " HEIGHT_FORMAT " \\n[" SUP_RAISE_FORMAT "]+\\n["
+ HEIGHT_FORMAT "]+%dM\n",
+ uid, uid, to->uid, big_op_spacing5);
+ }
+ else
+ printf(".nr " HEIGHT_FORMAT " \\n[" HEIGHT_FORMAT "]\n", uid, p->uid);
+ if (from != 0) {
+ printf(".nr " SUB_LOWER_FORMAT " %dM+\\n[" HEIGHT_FORMAT
+ "]>?%dM+\\n[" DEPTH_FORMAT "]\n",
+ uid, big_op_spacing2, from->uid, big_op_spacing4, p->uid);
+ printf(".nr " DEPTH_FORMAT " \\n[" SUB_LOWER_FORMAT "]+\\n["
+ DEPTH_FORMAT "]+%dM\n",
+ uid, uid, from->uid, big_op_spacing5);
+ }
+ else
+ printf(".nr " DEPTH_FORMAT " \\n[" DEPTH_FORMAT "]\n", uid, p->uid);
+ return res;
+}
+
+void limit_box::output()
+{
+ printf("\\s[\\n[" SMALL_SIZE_FORMAT "]]", uid);
+ if (to != 0) {
+ printf("\\Z" DELIMITER_CHAR);
+ printf("\\v'-\\n[" SUP_RAISE_FORMAT "]u'", uid);
+ printf("\\h'\\n[" LEFT_WIDTH_FORMAT "]u"
+ "+(-\\n[" WIDTH_FORMAT "]u+\\n[" SUB_KERN_FORMAT "]u/2u)'",
+ uid, to->uid, p->uid);
+ to->output();
+ printf(DELIMITER_CHAR);
+ }
+ if (from != 0) {
+ printf("\\Z" DELIMITER_CHAR);
+ printf("\\v'\\n[" SUB_LOWER_FORMAT "]u'", uid);
+ printf("\\h'\\n[" LEFT_WIDTH_FORMAT "]u"
+ "+(-\\n[" SUB_KERN_FORMAT "]u-\\n[" WIDTH_FORMAT "]u/2u)'",
+ uid, p->uid, from->uid);
+ from->output();
+ printf(DELIMITER_CHAR);
+ }
+ printf("\\s[\\n[" SIZE_FORMAT "]]", uid);
+ printf("\\Z" DELIMITER_CHAR);
+ printf("\\h'\\n[" LEFT_WIDTH_FORMAT "]u"
+ "-(\\n[" WIDTH_FORMAT "]u/2u)'",
+ uid, p->uid);
+ p->output();
+ printf(DELIMITER_CHAR);
+ printf("\\h'\\n[" WIDTH_FORMAT "]u'", uid);
+}
+
+void limit_box::debug_print()
+{
+ fprintf(stderr, "{ ");
+ p->debug_print();
+ fprintf(stderr, " }");
+ if (from) {
+ fprintf(stderr, " from { ");
+ from->debug_print();
+ fprintf(stderr, " }");
+ }
+ if (to) {
+ fprintf(stderr, " to { ");
+ to->debug_print();
+ fprintf(stderr, " }");
+ }
+}
+
+void limit_box::check_tabs(int level)
+{
+ if (to)
+ to->check_tabs(level + 1);
+ if (from)
+ from->check_tabs(level + 1);
+ p->check_tabs(level + 1);
+}
diff --git a/gnu/usr.bin/groff/eqn/list.cc b/gnu/usr.bin/groff/eqn/list.cc
new file mode 100644
index 0000000..7c8d1d6
--- /dev/null
+++ b/gnu/usr.bin/groff/eqn/list.cc
@@ -0,0 +1,236 @@
+// -*- C++ -*-
+/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
+ Written by James Clark (jjc@jclark.com)
+
+This file is part of groff.
+
+groff is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
+
+groff is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License along
+with groff; see the file COPYING. If not, write to the Free Software
+Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "eqn.h"
+#include "pbox.h"
+
+list_box *box::to_list_box()
+{
+ return 0;
+}
+
+list_box *list_box::to_list_box()
+{
+ return this;
+}
+
+void list_box::append(box *pp)
+{
+ list_box *q = pp->to_list_box();
+ if (q == 0)
+ list.append(pp);
+ else {
+ for (int i = 0; i < q->list.len; i++) {
+ list.append(q->list.p[i]);
+ q->list.p[i] = 0;
+ }
+ q->list.len = 0;
+ delete q;
+ }
+}
+
+list_box::list_box(box *pp) : list(pp), sty(-1)
+{
+ list_box *q = pp->to_list_box();
+ if (q != 0) {
+ // flatten it
+ list.p[0] = q->list.p[0];
+ for (int i = 1; i < q->list.len; i++) {
+ list.append(q->list.p[i]);
+ q->list.p[i] = 0;
+ }
+ q->list.len = 0;
+ delete q;
+ }
+}
+
+static int compute_spacing(int is_script, int left, int right)
+{
+ if (left == SUPPRESS_TYPE || right == SUPPRESS_TYPE)
+ return 0;
+ if (left == PUNCTUATION_TYPE)
+ return is_script ? 0 : thin_space;
+ if (left == OPENING_TYPE || right == CLOSING_TYPE)
+ return 0;
+ if (right == BINARY_TYPE || left == BINARY_TYPE)
+ return is_script ? 0 : medium_space;
+ if (right == RELATION_TYPE) {
+ if (left == RELATION_TYPE)
+ return 0;
+ else
+ return is_script ? 0 : thick_space;
+ }
+ if (left == RELATION_TYPE)
+ return is_script ? 0 : thick_space;
+ if (right == OPERATOR_TYPE)
+ return thin_space;
+ if (left == INNER_TYPE || right == INNER_TYPE)
+ return is_script ? 0 : thin_space;
+ if (left == OPERATOR_TYPE && right == ORDINARY_TYPE)
+ return thin_space;
+ return 0;
+}
+
+int list_box::compute_metrics(int style)
+{
+ sty = style;
+ int i;
+ for (i = 0; i < list.len; i++) {
+ int t = list.p[i]->spacing_type;
+ // 5
+ if (t == BINARY_TYPE) {
+ int prevt;
+ if (i == 0
+ || (prevt = list.p[i-1]->spacing_type) == BINARY_TYPE
+ || prevt == OPERATOR_TYPE
+ || prevt == RELATION_TYPE
+ || prevt == OPENING_TYPE
+ || prevt == PUNCTUATION_TYPE)
+ list.p[i]->spacing_type = ORDINARY_TYPE;
+ }
+ // 7
+ else if ((t == RELATION_TYPE || t == CLOSING_TYPE
+ || t == PUNCTUATION_TYPE)
+ && i > 0 && list.p[i-1]->spacing_type == BINARY_TYPE)
+ list.p[i-1]->spacing_type = ORDINARY_TYPE;
+ }
+ for (i = 0; i < list.len; i++) {
+ unsigned flags = 0;
+ if (i - 1 >= 0 && list.p[i - 1]->right_is_italic())
+ flags |= HINT_PREV_IS_ITALIC;
+ if (i + 1 < list.len && list.p[i + 1]->left_is_italic())
+ flags |= HINT_NEXT_IS_ITALIC;
+ if (flags)
+ list.p[i]->hint(flags);
+ }
+ is_script = (style <= SCRIPT_STYLE);
+ int total_spacing = 0;
+ for (i = 1; i < list.len; i++)
+ total_spacing += compute_spacing(is_script, list.p[i-1]->spacing_type,
+ list.p[i]->spacing_type);
+ int res = 0;
+ for (i = 0; i < list.len; i++)
+ if (!list.p[i]->is_simple()) {
+ int r = list.p[i]->compute_metrics(style);
+ if (r) {
+ if (res)
+ error("multiple marks and lineups");
+ else {
+ compute_sublist_width(i);
+ printf(".nr " MARK_REG " +\\n[" TEMP_REG"]\n");
+ res = r;
+ }
+ }
+ }
+ printf(".nr " WIDTH_FORMAT " %dM", uid, total_spacing);
+ for (i = 0; i < list.len; i++)
+ if (!list.p[i]->is_simple())
+ printf("+\\n[" WIDTH_FORMAT "]", list.p[i]->uid);
+ printf("\n");
+ printf(".nr " HEIGHT_FORMAT " 0", uid);
+ for (i = 0; i < list.len; i++)
+ if (!list.p[i]->is_simple())
+ printf(">?\\n[" HEIGHT_FORMAT "]", list.p[i]->uid);
+ printf("\n");
+ printf(".nr " DEPTH_FORMAT " 0", uid);
+ for (i = 0; i < list.len; i++)
+ if (!list.p[i]->is_simple())
+ printf(">?\\n[" DEPTH_FORMAT "]", list.p[i]->uid);
+ printf("\n");
+ int have_simple = 0;
+ for (i = 0; i < list.len && !have_simple; i++)
+ have_simple = list.p[i]->is_simple();
+ if (have_simple) {
+ printf(".nr " WIDTH_FORMAT " +\\w" DELIMITER_CHAR, uid);
+ for (int i = 0; i < list.len; i++)
+ if (list.p[i]->is_simple())
+ list.p[i]->output();
+ printf(DELIMITER_CHAR "\n");
+ printf(".nr " HEIGHT_FORMAT " \\n[rst]>?\\n[" HEIGHT_FORMAT "]\n",
+ uid, uid);
+ printf(".nr " DEPTH_FORMAT " 0-\\n[rsb]>?\\n[" DEPTH_FORMAT "]\n",
+ uid, uid);
+ }
+ return res;
+}
+
+void list_box::compute_sublist_width(int n)
+{
+ int total_spacing = 0;
+ for (int i = 1; i < n + 1 && i < list.len; i++)
+ total_spacing += compute_spacing(is_script, list.p[i-1]->spacing_type,
+ list.p[i]->spacing_type);
+ printf(".nr " TEMP_REG " %dM", total_spacing);
+ for (i = 0; i < n; i++)
+ if (!list.p[i]->is_simple())
+ printf("+\\n[" WIDTH_FORMAT "]", list.p[i]->uid);
+ int have_simple = 0;
+ for (i = 0; i < n && !have_simple; i++)
+ have_simple = list.p[i]->is_simple();
+ if (have_simple) {
+ printf("+\\w" DELIMITER_CHAR);
+ for (int i = 0; i < n; i++)
+ if (list.p[i]->is_simple())
+ list.p[i]->output();
+ printf(DELIMITER_CHAR);
+ }
+ printf("\n");
+}
+
+void list_box::compute_subscript_kern()
+{
+ // We can only call compute_subscript_kern if we have called
+ // compute_metrics first.
+ if (list.p[list.len-1]->is_simple())
+ list.p[list.len-1]->compute_metrics(sty);
+ list.p[list.len-1]->compute_subscript_kern();
+ printf(".nr " SUB_KERN_FORMAT " \\n[" SUB_KERN_FORMAT "]\n",
+ uid, list.p[list.len-1]->uid);
+}
+
+void list_box::output()
+{
+ for (int i = 0; i < list.len; i++) {
+ if (i > 0) {
+ int n = compute_spacing(is_script,
+ list.p[i-1]->spacing_type,
+ list.p[i]->spacing_type);
+ if (n > 0)
+ printf("\\h'%dM'", n);
+ }
+ list.p[i]->output();
+ }
+}
+
+void list_box::handle_char_type(int st, int ft)
+{
+ for (int i = 0; i < list.len; i++)
+ list.p[i]->handle_char_type(st, ft);
+}
+
+void list_box::debug_print()
+{
+ list.list_debug_print(" ");
+}
+
+void list_box::check_tabs(int level)
+{
+ list.list_check_tabs(level);
+}
diff --git a/gnu/usr.bin/groff/eqn/main.cc b/gnu/usr.bin/groff/eqn/main.cc
new file mode 100644
index 0000000..534b7f8
--- /dev/null
+++ b/gnu/usr.bin/groff/eqn/main.cc
@@ -0,0 +1,352 @@
+// -*- C++ -*-
+/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
+ Written by James Clark (jjc@jclark.com)
+
+This file is part of groff.
+
+groff is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
+
+groff is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License along
+with groff; see the file COPYING. If not, write to the Free Software
+Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "eqn.h"
+#include "stringclass.h"
+#include "device.h"
+#include "searchpath.h"
+#include "macropath.h"
+
+#define STARTUP_FILE "eqnrc"
+
+extern int yyparse();
+
+static char *delim_search(char *, int);
+static int inline_equation(FILE *, string &, string &);
+
+char start_delim = '\0';
+char end_delim = '\0';
+int non_empty_flag;
+int inline_flag;
+int draw_flag = 0;
+int one_size_reduction_flag = 0;
+int compatible_flag = 0;
+int no_newline_in_delim_flag = 0;
+
+int read_line(FILE *fp, string *p)
+{
+ p->clear();
+ int c = -1;
+ while ((c = getc(fp)) != EOF) {
+ if (!illegal_input_char(c))
+ *p += char(c);
+ else
+ error("illegal input character code `%1'", c);
+ if (c == '\n')
+ break;
+ }
+ current_lineno++;
+ return p->length() > 0;
+}
+
+void do_file(FILE *fp, const char *filename)
+{
+ string linebuf;
+ string str;
+ printf(".lf 1 %s\n", filename);
+ current_filename = filename;
+ current_lineno = 0;
+ while (read_line(fp, &linebuf)) {
+ if (linebuf.length() >= 4
+ && linebuf[0] == '.' && linebuf[1] == 'l' && linebuf[2] == 'f'
+ && (linebuf[3] == ' ' || linebuf[3] == '\n' || compatible_flag)) {
+ put_string(linebuf, stdout);
+ linebuf += '\0';
+ if (interpret_lf_args(linebuf.contents() + 3))
+ current_lineno--;
+ }
+ else if (linebuf.length() >= 4
+ && linebuf[0] == '.'
+ && linebuf[1] == 'E'
+ && linebuf[2] == 'Q'
+ && (linebuf[3] == ' ' || linebuf[3] == '\n' || compatible_flag)) {
+ put_string(linebuf, stdout);
+ int start_lineno = current_lineno + 1;
+ str.clear();
+ for (;;) {
+ if (!read_line(fp, &linebuf))
+ fatal("end of file before .EN");
+ if (linebuf.length() >= 3 && linebuf[0] == '.' && linebuf[1] == 'E') {
+ if (linebuf[2] == 'N'
+ && (linebuf.length() == 3 || linebuf[3] == ' '
+ || linebuf[3] == '\n' || compatible_flag))
+ break;
+ else if (linebuf[2] == 'Q' && linebuf.length() > 3
+ && (linebuf[3] == ' ' || linebuf[3] == '\n'
+ || compatible_flag))
+ fatal("nested .EQ");
+ }
+ str += linebuf;
+ }
+ str += '\0';
+ start_string();
+ init_lex(str.contents(), current_filename, start_lineno);
+ non_empty_flag = 0;
+ inline_flag = 0;
+ yyparse();
+ if (non_empty_flag) {
+ printf(".lf %d\n", current_lineno - 1);
+ output_string();
+ }
+ restore_compatibility();
+ printf(".lf %d\n", current_lineno);
+ put_string(linebuf, stdout);
+ }
+ else if (start_delim != '\0' && linebuf.search(start_delim) >= 0
+ && inline_equation(fp, linebuf, str))
+ ;
+ else
+ put_string(linebuf, stdout);
+ }
+ current_filename = 0;
+ current_lineno = 0;
+}
+
+/* Handle an inline equation. Return 1 if it was an inline equation,
+0 otherwise. */
+
+static int inline_equation(FILE *fp, string &linebuf, string &str)
+{
+ linebuf += '\0';
+ char *ptr = &linebuf[0];
+ char *start = delim_search(ptr, start_delim);
+ if (!start) {
+ // It wasn't a delimiter after all.
+ linebuf.set_length(linebuf.length() - 1); // strip the '\0'
+ return 0;
+ }
+ start_string();
+ inline_flag = 1;
+ for (;;) {
+ if (no_newline_in_delim_flag && strchr(start + 1, end_delim) == 0) {
+ error("missing `%1'", end_delim);
+ char *nl = strchr(start + 1, '\n');
+ if (nl != 0)
+ *nl = '\0';
+ do_text(ptr);
+ break;
+ }
+ int start_lineno = current_lineno;
+ *start = '\0';
+ do_text(ptr);
+ ptr = start + 1;
+ str.clear();
+ for (;;) {
+ char *end = strchr(ptr, end_delim);
+ if (end != 0) {
+ *end = '\0';
+ str += ptr;
+ ptr = end + 1;
+ break;
+ }
+ str += ptr;
+ if (!read_line(fp, &linebuf))
+ fatal("end of file before `%1'", end_delim);
+ linebuf += '\0';
+ ptr = &linebuf[0];
+ }
+ str += '\0';
+ init_lex(str.contents(), current_filename, start_lineno);
+ yyparse();
+ start = delim_search(ptr, start_delim);
+ if (start == 0) {
+ char *nl = strchr(ptr, '\n');
+ if (nl != 0)
+ *nl = '\0';
+ do_text(ptr);
+ break;
+ }
+ }
+ printf(".lf %d\n", current_lineno);
+ output_string();
+ restore_compatibility();
+ printf(".lf %d\n", current_lineno + 1);
+ return 1;
+}
+
+/* Search for delim. Skip over number register and string names etc. */
+
+static char *delim_search(char *ptr, int delim)
+{
+ while (*ptr) {
+ if (*ptr == delim)
+ return ptr;
+ if (*ptr++ == '\\') {
+ switch (*ptr) {
+ case 'n':
+ case '*':
+ case 'f':
+ case 'g':
+ case 'k':
+ switch (*++ptr) {
+ case '\0':
+ case '\\':
+ break;
+ case '(':
+ if (*++ptr != '\\' && *ptr != '\0' && *++ptr != '\\' && *ptr != '\0')
+ ptr++;
+ break;
+ case '[':
+ while (*++ptr != '\0')
+ if (*ptr == ']') {
+ ptr++;
+ break;
+ }
+ break;
+ default:
+ ptr++;
+ break;
+ }
+ break;
+ case '\\':
+ case '\0':
+ break;
+ default:
+ ptr++;
+ break;
+ }
+ }
+ }
+ return 0;
+}
+
+void usage()
+{
+ fprintf(stderr,
+ "usage: %s [ -rvDCNR ] -dxx -fn -sn -pn -mn -Mdir -Ts [ files ... ]\n",
+ program_name);
+ exit(1);
+}
+
+int main(int argc, char **argv)
+{
+ program_name = argv[0];
+ static char stderr_buf[BUFSIZ];
+ setbuf(stderr, stderr_buf);
+ int opt;
+ int load_startup_file = 1;
+ while ((opt = getopt(argc, argv, "DCRvd:f:p:s:m:T:M:rN")) != EOF)
+ switch (opt) {
+ case 'C':
+ compatible_flag = 1;
+ break;
+ case 'R': // don't load eqnchar
+ load_startup_file = 0;
+ break;
+ case 'M':
+ macro_path.command_line_dir(optarg);
+ break;
+ case 'v':
+ {
+ extern const char *version_string;
+ fprintf(stderr, "GNU eqn version %s\n", version_string);
+ fflush(stderr);
+ break;
+ }
+ case 'd':
+ if (optarg[0] == '\0' || optarg[1] == '\0')
+ error("-d requires two character argument");
+ else if (illegal_input_char(optarg[0]))
+ error("bad delimiter `%1'", optarg[0]);
+ else if (illegal_input_char(optarg[1]))
+ error("bad delimiter `%1'", optarg[1]);
+ else {
+ start_delim = optarg[0];
+ end_delim = optarg[1];
+ }
+ break;
+ case 'f':
+ set_gfont(optarg);
+ break;
+ case 'T':
+ device = optarg;
+ break;
+ case 's':
+ if (!set_gsize(optarg))
+ error("invalid size `%1'", optarg);
+ break;
+ case 'p':
+ {
+ int n;
+ if (sscanf(optarg, "%d", &n) == 1)
+ set_script_reduction(n);
+ else
+ error("bad size `%1'", optarg);
+ }
+ break;
+ case 'm':
+ {
+ int n;
+ if (sscanf(optarg, "%d", &n) == 1)
+ set_minimum_size(n);
+ else
+ error("bad size `%1'", optarg);
+ }
+ break;
+ case 'r':
+ one_size_reduction_flag = 1;
+ break;
+ case 'D':
+ warning("-D option is obsolete: use `set draw_lines 1' instead");
+ draw_flag = 1;
+ break;
+ case 'N':
+ no_newline_in_delim_flag = 1;
+ break;
+ case '?':
+ usage();
+ break;
+ default:
+ assert(0);
+ }
+ init_table(device);
+ init_char_table();
+ printf(".if !'\\*(.T'%s' "
+ ".tm warning: %s should have been given a `-T\\*(.T' option\n",
+ device, program_name);
+ if (load_startup_file) {
+ char *path;
+ FILE *fp = macro_path.open_file(STARTUP_FILE, &path);
+ if (fp) {
+ do_file(fp, path);
+ fclose(fp);
+ a_delete path;
+ }
+ }
+ if (optind >= argc)
+ do_file(stdin, "-");
+ else
+ for (int i = optind; i < argc; i++)
+ if (strcmp(argv[i], "-") == 0)
+ do_file(stdin, "-");
+ else {
+ errno = 0;
+ FILE *fp = fopen(argv[i], "r");
+ if (!fp)
+ fatal("can't open `%1': %2", argv[i], strerror(errno));
+ else {
+ do_file(fp, argv[i]);
+ fclose(fp);
+ }
+ }
+ if (ferror(stdout) || fflush(stdout) < 0)
+ fatal("output error");
+ return 0;
+}
diff --git a/gnu/usr.bin/groff/eqn/mark.cc b/gnu/usr.bin/groff/eqn/mark.cc
new file mode 100644
index 0000000..fa5916d
--- /dev/null
+++ b/gnu/usr.bin/groff/eqn/mark.cc
@@ -0,0 +1,121 @@
+// -*- C++ -*-
+/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
+ Written by James Clark (jjc@jclark.com)
+
+This file is part of groff.
+
+groff is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
+
+groff is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License along
+with groff; see the file COPYING. If not, write to the Free Software
+Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "eqn.h"
+#include "pbox.h"
+
+class mark_box : public pointer_box {
+public:
+ mark_box(box *);
+ int compute_metrics(int);
+ void output();
+ void debug_print();
+};
+
+// we push down marks so that they don't interfere with spacing
+
+box *make_mark_box(box *p)
+{
+ list_box *b = p->to_list_box();
+ if (b != 0) {
+ b->list.p[0] = make_mark_box(b->list.p[0]);
+ return b;
+ }
+ else
+ return new mark_box(p);
+}
+
+mark_box::mark_box(box *pp) : pointer_box(pp)
+{
+}
+
+void mark_box::output()
+{
+ p->output();
+}
+
+int mark_box::compute_metrics(int style)
+{
+ int res = p->compute_metrics(style);
+ if (res)
+ error("multiple marks and lineups");
+ printf(".nr " WIDTH_FORMAT " 0\\n[" WIDTH_FORMAT "]\n", uid, p->uid);
+ printf(".nr " HEIGHT_FORMAT " \\n[" HEIGHT_FORMAT "]\n", uid, p->uid);
+ printf(".nr " DEPTH_FORMAT " \\n[" DEPTH_FORMAT "]\n", uid, p->uid);
+ printf(".nr " MARK_REG " 0\n");
+ return FOUND_MARK;
+}
+
+void mark_box::debug_print()
+{
+ fprintf(stderr, "mark { ");
+ p->debug_print();
+ fprintf(stderr, " }");
+}
+
+
+class lineup_box : public pointer_box {
+public:
+ lineup_box(box *);
+ void output();
+ int compute_metrics(int style);
+ void debug_print();
+};
+
+// we push down lineups so that they don't interfere with spacing
+
+box *make_lineup_box(box *p)
+{
+ list_box *b = p->to_list_box();
+ if (b != 0) {
+ b->list.p[0] = make_lineup_box(b->list.p[0]);
+ return b;
+ }
+ else
+ return new lineup_box(p);
+}
+
+lineup_box::lineup_box(box *pp) : pointer_box(pp)
+{
+}
+
+void lineup_box::output()
+{
+ p->output();
+}
+
+int lineup_box::compute_metrics(int style)
+{
+ int res = p->compute_metrics(style);
+ if (res)
+ error("multiple marks and lineups");
+ printf(".nr " WIDTH_FORMAT " 0\\n[" WIDTH_FORMAT "]\n", uid, p->uid);
+ printf(".nr " HEIGHT_FORMAT " \\n[" HEIGHT_FORMAT "]\n", uid, p->uid);
+ printf(".nr " DEPTH_FORMAT " \\n[" DEPTH_FORMAT "]\n", uid, p->uid);
+ printf(".nr " MARK_REG " 0\n");
+ return FOUND_LINEUP;
+}
+
+void lineup_box::debug_print()
+{
+ fprintf(stderr, "lineup { ");
+ p->debug_print();
+ fprintf(stderr, " }");
+}
diff --git a/gnu/usr.bin/groff/eqn/neqn.sh b/gnu/usr.bin/groff/eqn/neqn.sh
new file mode 100644
index 0000000..7703767
--- /dev/null
+++ b/gnu/usr.bin/groff/eqn/neqn.sh
@@ -0,0 +1,5 @@
+#!/bin/sh
+# Provision of this shell script should not be taken to imply that use of
+# GNU eqn with groff -Tascii|-Tlatin1 is supported.
+
+exec @g@eqn -Tascii ${1+"$@"}
diff --git a/gnu/usr.bin/groff/eqn/other.cc b/gnu/usr.bin/groff/eqn/other.cc
new file mode 100644
index 0000000..5b8b9c2
--- /dev/null
+++ b/gnu/usr.bin/groff/eqn/other.cc
@@ -0,0 +1,601 @@
+// -*- C++ -*-
+/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
+ Written by James Clark (jjc@jclark.com)
+
+This file is part of groff.
+
+groff is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
+
+groff is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License along
+with groff; see the file COPYING. If not, write to the Free Software
+Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "eqn.h"
+#include "pbox.h"
+
+class accent_box : public pointer_box {
+private:
+ box *ab;
+public:
+ accent_box(box *, box *);
+ ~accent_box();
+ int compute_metrics(int);
+ void output();
+ void debug_print();
+ void check_tabs(int);
+};
+
+box *make_accent_box(box *p, box *q)
+{
+ return new accent_box(p, q);
+}
+
+accent_box::accent_box(box *pp, box *qq) : ab(qq), pointer_box(pp)
+{
+}
+
+accent_box::~accent_box()
+{
+ delete ab;
+}
+
+#if 0
+int accent_box::compute_metrics(int style)
+{
+ int r = p->compute_metrics(style);
+ p->compute_skew();
+ ab->compute_metrics(style);
+ printf(".nr " WIDTH_FORMAT " 0\\n[" WIDTH_FORMAT "]\n", uid, p->uid);
+ printf(".nr " DEPTH_FORMAT " \\n[" DEPTH_FORMAT "]\n", uid, p->uid);
+ printf(".nr " SUP_RAISE_FORMAT " \\n[" HEIGHT_FORMAT "]-%dM>?0\n",
+ uid, p->uid, x_height);
+ printf(".nr " HEIGHT_FORMAT " \\n[" HEIGHT_FORMAT "]+\\n["
+ SUP_RAISE_FORMAT "]\n",
+ uid, ab->uid, uid);
+ return r;
+}
+
+void accent_box::output()
+{
+ printf("\\h'\\n[" WIDTH_FORMAT "]u-\\n[" WIDTH_FORMAT "]u/2u+\\n["
+ SKEW_FORMAT "]u'",
+ p->uid, ab->uid, p->uid);
+ printf("\\v'-\\n[" SUP_RAISE_FORMAT "]u'", uid);
+ ab->output();
+ printf("\\h'-\\n[" WIDTH_FORMAT "]u'", ab->uid);
+ printf("\\v'\\n[" SUP_RAISE_FORMAT "]u'", uid);
+ printf("\\h'-(\\n[" WIDTH_FORMAT "]u-\\n[" WIDTH_FORMAT "]u/2u+\\n["
+ SKEW_FORMAT "]u)'",
+ p->uid, ab->uid, p->uid);
+ p->output();
+}
+#endif
+
+/* This version copes with the possibility of an accent's being wider
+than its accentee. LEFT_WIDTH_FORMAT gives the distance from the
+left edge of the resulting box to the middle of the accentee's box.*/
+
+int accent_box::compute_metrics(int style)
+{
+ int r = p->compute_metrics(style);
+ p->compute_skew();
+ ab->compute_metrics(style);
+ printf(".nr " LEFT_WIDTH_FORMAT " 0\\n[" WIDTH_FORMAT "]/2"
+ ">?(\\n[" WIDTH_FORMAT "]/2-\\n[" SKEW_FORMAT "])\n",
+ uid, p->uid, ab->uid, p->uid);
+ printf(".nr " WIDTH_FORMAT " 0\\n[" WIDTH_FORMAT "]/2"
+ ">?(\\n[" WIDTH_FORMAT "]/2+\\n[" SKEW_FORMAT "])"
+ "+\\n[" LEFT_WIDTH_FORMAT "]\n",
+ uid, p->uid, ab->uid, p->uid, uid);
+ printf(".nr " DEPTH_FORMAT " \\n[" DEPTH_FORMAT "]\n", uid, p->uid);
+ printf(".nr " SUP_RAISE_FORMAT " \\n[" HEIGHT_FORMAT "]-%dM>?0\n",
+ uid, p->uid, x_height);
+ printf(".nr " HEIGHT_FORMAT " \\n[" HEIGHT_FORMAT "]+\\n["
+ SUP_RAISE_FORMAT "]\n",
+ uid, ab->uid, uid);
+ if (r)
+ printf(".nr " MARK_REG " +\\n[" LEFT_WIDTH_FORMAT "]"
+ "-(\\n[" WIDTH_FORMAT "]/2)'\n",
+ uid, p->uid);
+ return r;
+}
+
+void accent_box::output()
+{
+ printf("\\Z" DELIMITER_CHAR);
+ printf("\\h'\\n[" LEFT_WIDTH_FORMAT "]u+\\n[" SKEW_FORMAT "]u"
+ "-(\\n[" WIDTH_FORMAT "]u/2u)'",
+ uid, p->uid, ab->uid);
+ printf("\\v'-\\n[" SUP_RAISE_FORMAT "]u'", uid);
+ ab->output();
+ printf(DELIMITER_CHAR);
+ printf("\\Z" DELIMITER_CHAR);
+ printf("\\h'\\n[" LEFT_WIDTH_FORMAT "]u-(\\n[" WIDTH_FORMAT "]u/2u)'",
+ uid, p->uid);
+ p->output();
+ printf(DELIMITER_CHAR);
+ printf("\\h'\\n[" WIDTH_FORMAT "]u'", uid);
+}
+
+void accent_box::check_tabs(int level)
+{
+ ab->check_tabs(level + 1);
+ p->check_tabs(level + 1);
+}
+
+void accent_box::debug_print()
+{
+ fprintf(stderr, "{ ");
+ p->debug_print();
+ fprintf(stderr, " } accent { ");
+ ab->debug_print();
+ fprintf(stderr, " }");
+}
+
+class overline_char_box : public simple_box {
+public:
+ overline_char_box();
+ void output();
+ void debug_print();
+};
+
+overline_char_box::overline_char_box()
+{
+}
+
+void overline_char_box::output()
+{
+ printf("\\v'-%dM/2u-%dM'", 7*default_rule_thickness, x_height);
+ printf((draw_flag ? "\\D'l%dM 0'" : "\\l'%dM\\&\\(ru'"),
+ accent_width);
+ printf("\\v'%dM/2u+%dM'", 7*default_rule_thickness, x_height);
+}
+
+void overline_char_box::debug_print()
+{
+ fprintf(stderr, "<overline char>");
+}
+
+class overline_box : public pointer_box {
+public:
+ overline_box(box *);
+ int compute_metrics(int);
+ void output();
+ void debug_print();
+};
+
+box *make_overline_box(box *p)
+{
+ if (p->is_char())
+ return new accent_box(p, new overline_char_box);
+ else
+ return new overline_box(p);
+}
+
+overline_box::overline_box(box *pp) : pointer_box(pp)
+{
+}
+
+int overline_box::compute_metrics(int style)
+{
+ int r = p->compute_metrics(cramped_style(style));
+ // 9
+ printf(".nr " HEIGHT_FORMAT " \\n[" HEIGHT_FORMAT "]+%dM\n",
+ uid, p->uid, default_rule_thickness*5);
+ printf(".nr " WIDTH_FORMAT " 0\\n[" WIDTH_FORMAT "]\n", uid, p->uid);
+ printf(".nr " DEPTH_FORMAT " \\n[" DEPTH_FORMAT "]\n", uid, p->uid);
+ return r;
+}
+
+void overline_box::output()
+{
+ // 9
+ printf("\\Z" DELIMITER_CHAR);
+ printf("\\v'-\\n[" HEIGHT_FORMAT "]u-(%dM/2u)'",
+ p->uid, 7*default_rule_thickness);
+ if (draw_flag)
+ printf("\\D'l\\n[" WIDTH_FORMAT "]u 0'", p->uid);
+ else
+ printf("\\l'\\n[" WIDTH_FORMAT "]u\\&\\(ru'", p->uid);
+ printf(DELIMITER_CHAR);
+ p->output();
+}
+
+void overline_box::debug_print()
+{
+ fprintf(stderr, "{ ");
+ p->debug_print();
+ fprintf(stderr, " } bar");
+}
+
+class uaccent_box : public pointer_box {
+ box *ab;
+public:
+ uaccent_box(box *, box *);
+ ~uaccent_box();
+ int compute_metrics(int);
+ void output();
+ void compute_subscript_kern();
+ void check_tabs(int);
+ void debug_print();
+};
+
+box *make_uaccent_box(box *p, box *q)
+{
+ return new uaccent_box(p, q);
+}
+
+uaccent_box::uaccent_box(box *pp, box *qq)
+: pointer_box(pp), ab(qq)
+{
+}
+
+uaccent_box::~uaccent_box()
+{
+ delete ab;
+}
+
+int uaccent_box::compute_metrics(int style)
+{
+ int r = p->compute_metrics(style);
+ ab->compute_metrics(style);
+ printf(".nr " LEFT_WIDTH_FORMAT " 0\\n[" WIDTH_FORMAT "]/2"
+ ">?(\\n[" WIDTH_FORMAT "]/2)\n",
+ uid, p->uid, ab->uid);
+ printf(".nr " WIDTH_FORMAT " 0\\n[" WIDTH_FORMAT "]/2"
+ ">?(\\n[" WIDTH_FORMAT "]/2)"
+ "+\\n[" LEFT_WIDTH_FORMAT "]\n",
+ uid, p->uid, ab->uid, uid);
+ printf(".nr " HEIGHT_FORMAT " \\n[" HEIGHT_FORMAT "]\n", uid, p->uid);
+ printf(".nr " DEPTH_FORMAT " \\n[" DEPTH_FORMAT "]"
+ "+\\n[" DEPTH_FORMAT "]\n",
+ uid, p->uid, ab->uid);
+ if (r)
+ printf(".nr " MARK_REG " +\\n[" LEFT_WIDTH_FORMAT "]"
+ "-(\\n[" WIDTH_FORMAT "]/2)'\n",
+ uid, p->uid);
+ return r;
+}
+
+void uaccent_box::output()
+{
+ printf("\\Z" DELIMITER_CHAR);
+ printf("\\h'\\n[" LEFT_WIDTH_FORMAT "]u-(\\n[" WIDTH_FORMAT "]u/2u)'",
+ uid, ab->uid);
+ printf("\\v'\\n[" DEPTH_FORMAT "]u'", p->uid);
+ ab->output();
+ printf(DELIMITER_CHAR);
+ printf("\\Z" DELIMITER_CHAR);
+ printf("\\h'\\n[" LEFT_WIDTH_FORMAT "]u-(\\n[" WIDTH_FORMAT "]u/2u)'",
+ uid, p->uid);
+ p->output();
+ printf(DELIMITER_CHAR);
+ printf("\\h'\\n[" WIDTH_FORMAT "]u'", uid);
+}
+
+void uaccent_box::check_tabs(int level)
+{
+ ab->check_tabs(level + 1);
+ p->check_tabs(level + 1);
+}
+
+void uaccent_box::compute_subscript_kern()
+{
+ box::compute_subscript_kern(); // want 0 subscript kern
+}
+
+void uaccent_box::debug_print()
+{
+ fprintf(stderr, "{ ");
+ p->debug_print();
+ fprintf(stderr, " } uaccent { ");
+ ab->debug_print();
+ fprintf(stderr, " }");
+}
+
+class underline_char_box : public simple_box {
+public:
+ underline_char_box();
+ void output();
+ void debug_print();
+};
+
+underline_char_box::underline_char_box()
+{
+}
+
+void underline_char_box::output()
+{
+ printf("\\v'%dM/2u'", 7*default_rule_thickness);
+ printf((draw_flag ? "\\D'l%dM 0'" : "\\l'%dM\\&\\(ru'"),
+ accent_width);
+ printf("\\v'-%dM/2u'", 7*default_rule_thickness);
+}
+
+void underline_char_box::debug_print()
+{
+ fprintf(stderr, "<underline char>");
+}
+
+
+class underline_box : public pointer_box {
+public:
+ underline_box(box *);
+ int compute_metrics(int);
+ void output();
+ void compute_subscript_kern();
+ void debug_print();
+};
+
+box *make_underline_box(box *p)
+{
+ if (p->is_char())
+ return new uaccent_box(p, new underline_char_box);
+ else
+ return new underline_box(p);
+}
+
+underline_box::underline_box(box *pp) : pointer_box(pp)
+{
+}
+
+int underline_box::compute_metrics(int style)
+{
+ int r = p->compute_metrics(style);
+ // 10
+ printf(".nr " DEPTH_FORMAT " \\n[" DEPTH_FORMAT "]+%dM\n",
+ uid, p->uid, default_rule_thickness*5);
+ printf(".nr " WIDTH_FORMAT " 0\\n[" WIDTH_FORMAT "]\n", uid, p->uid);
+ printf(".nr " HEIGHT_FORMAT " \\n[" HEIGHT_FORMAT "]\n", uid, p->uid);
+ return r;
+}
+
+void underline_box::output()
+{
+ // 10
+ printf("\\Z" DELIMITER_CHAR);
+ printf("\\v'\\n[" DEPTH_FORMAT "]u+(%dM/2u)'",
+ p->uid, 7*default_rule_thickness);
+ if (draw_flag)
+ printf("\\D'l\\n[" WIDTH_FORMAT "]u 0'", p->uid);
+ else
+ printf("\\l'\\n[" WIDTH_FORMAT "]u\\&\\(ru'", p->uid);
+ printf(DELIMITER_CHAR);
+ p->output();
+}
+
+// we want an underline box to have 0 subscript kern
+
+void underline_box::compute_subscript_kern()
+{
+ box::compute_subscript_kern();
+}
+
+void underline_box::debug_print()
+{
+ fprintf(stderr, "{ ");
+ p->debug_print();
+ fprintf(stderr, " } under");
+}
+
+size_box::size_box(char *s, box *pp) : size(s), pointer_box(pp)
+{
+}
+
+int size_box::compute_metrics(int style)
+{
+ printf(".nr " SIZE_FORMAT " \\n[.s]\n", uid);
+ printf(".ps %s\n", size);
+ printf(".nr " SMALL_SIZE_FORMAT " \\n[.s]\n", uid);
+ int r = p->compute_metrics(style);
+ printf(".ps \\n[" SIZE_FORMAT "]\n", uid);
+ printf(".nr " WIDTH_FORMAT " 0\\n[" WIDTH_FORMAT "]\n", uid, p->uid);
+ printf(".nr " HEIGHT_FORMAT " \\n[" HEIGHT_FORMAT "]\n", uid, p->uid);
+ printf(".nr " DEPTH_FORMAT " \\n[" DEPTH_FORMAT "]\n", uid, p->uid);
+ return r;
+}
+
+void size_box::output()
+{
+ printf("\\s[\\n[" SMALL_SIZE_FORMAT "]]", uid);
+ p->output();
+ printf("\\s[\\n[" SIZE_FORMAT "]]", uid);
+}
+
+size_box::~size_box()
+{
+ a_delete size;
+}
+
+void size_box::debug_print()
+{
+ fprintf(stderr, "size %s { ", size);
+ p->debug_print();
+ fprintf(stderr, " }");
+}
+
+
+font_box::font_box(char *s, box *pp) : pointer_box(pp), f(s)
+{
+}
+
+font_box::~font_box()
+{
+ a_delete f;
+}
+
+int font_box::compute_metrics(int style)
+{
+ const char *old_roman_font = current_roman_font;
+ current_roman_font = f;
+ printf(".nr " FONT_FORMAT " \\n[.f]\n", uid);
+ printf(".ft %s\n", f);
+ int r = p->compute_metrics(style);
+ current_roman_font = old_roman_font;
+ printf(".ft \\n[" FONT_FORMAT "]\n", uid);
+ printf(".nr " WIDTH_FORMAT " 0\\n[" WIDTH_FORMAT "]\n", uid, p->uid);
+ printf(".nr " HEIGHT_FORMAT " \\n[" HEIGHT_FORMAT "]\n", uid, p->uid);
+ printf(".nr " DEPTH_FORMAT " \\n[" DEPTH_FORMAT "]\n", uid, p->uid);
+ return r;
+}
+
+void font_box::output()
+{
+ printf("\\f[%s]", f);
+ const char *old_roman_font = current_roman_font;
+ current_roman_font = f;
+ p->output();
+ current_roman_font = old_roman_font;
+ printf("\\f[\\n[" FONT_FORMAT "]]", uid);
+}
+
+void font_box::debug_print()
+{
+ fprintf(stderr, "font %s { ", f);
+ p->debug_print();
+ fprintf(stderr, " }");
+}
+
+fat_box::fat_box(box *pp) : pointer_box(pp)
+{
+}
+
+int fat_box::compute_metrics(int style)
+{
+ int r = p->compute_metrics(style);
+ printf(".nr " WIDTH_FORMAT " 0\\n[" WIDTH_FORMAT "]+%dM\n",
+ uid, p->uid, fat_offset);
+ printf(".nr " HEIGHT_FORMAT " \\n[" HEIGHT_FORMAT "]\n", uid, p->uid);
+ printf(".nr " DEPTH_FORMAT " \\n[" DEPTH_FORMAT "]\n", uid, p->uid);
+ return r;
+}
+
+void fat_box::output()
+{
+ p->output();
+ printf("\\h'-\\n[" WIDTH_FORMAT "]u'", p->uid);
+ printf("\\h'%dM'", fat_offset);
+ p->output();
+}
+
+
+void fat_box::debug_print()
+{
+ fprintf(stderr, "fat { ");
+ p->debug_print();
+ fprintf(stderr, " }");
+}
+
+
+vmotion_box::vmotion_box(int i, box *pp) : n(i), pointer_box(pp)
+{
+}
+
+int vmotion_box::compute_metrics(int style)
+{
+ int r = p->compute_metrics(style);
+ printf(".nr " WIDTH_FORMAT " 0\\n[" WIDTH_FORMAT "]\n", uid, p->uid);
+ if (n > 0) {
+ printf(".nr " HEIGHT_FORMAT " %dM+\\n[" HEIGHT_FORMAT "]\n",
+ uid, n, p->uid);
+ printf(".nr " DEPTH_FORMAT " \\n[" DEPTH_FORMAT "]\n", uid, p->uid);
+ }
+ else {
+ printf(".nr " DEPTH_FORMAT " %dM+\\n[" DEPTH_FORMAT "]>?0\n",
+ uid, -n, p->uid);
+ printf(".nr " HEIGHT_FORMAT " \\n[" HEIGHT_FORMAT "]\n",
+ uid, p->uid);
+ }
+ return r;
+}
+
+void vmotion_box::output()
+{
+ printf("\\v'%dM'", -n);
+ p->output();
+ printf("\\v'%dM'", n);
+}
+
+void vmotion_box::debug_print()
+{
+ if (n >= 0)
+ fprintf(stderr, "up %d { ", n);
+ else
+ fprintf(stderr, "down %d { ", -n);
+ p->debug_print();
+ fprintf(stderr, " }");
+}
+
+hmotion_box::hmotion_box(int i, box *pp) : n(i), pointer_box(pp)
+{
+}
+
+int hmotion_box::compute_metrics(int style)
+{
+ int r = p->compute_metrics(style);
+ printf(".nr " WIDTH_FORMAT " 0\\n[" WIDTH_FORMAT "]+%dM\n",
+ uid, p->uid, n);
+ printf(".nr " HEIGHT_FORMAT " \\n[" HEIGHT_FORMAT "]\n", uid, p->uid);
+ printf(".nr " DEPTH_FORMAT " \\n[" DEPTH_FORMAT "]\n", uid, p->uid);
+ if (r)
+ printf(".nr " MARK_REG " +%dM\n", n);
+ return r;
+}
+
+void hmotion_box::output()
+{
+ printf("\\h'%dM'", n);
+ p->output();
+}
+
+void hmotion_box::debug_print()
+{
+ if (n >= 0)
+ fprintf(stderr, "fwd %d { ", n);
+ else
+ fprintf(stderr, "back %d { ", -n);
+ p->debug_print();
+ fprintf(stderr, " }");
+}
+
+vcenter_box::vcenter_box(box *pp) : pointer_box(pp)
+{
+}
+
+int vcenter_box::compute_metrics(int style)
+{
+ int r = p->compute_metrics(style);
+ printf(".nr " WIDTH_FORMAT " 0\\n[" WIDTH_FORMAT "]\n", uid, p->uid);
+ printf(".nr " SUP_RAISE_FORMAT " \\n[" DEPTH_FORMAT "]-\\n["
+ HEIGHT_FORMAT "]/2+%dM\n",
+ uid, p->uid, p->uid, axis_height);
+ printf(".nr " HEIGHT_FORMAT " \\n[" HEIGHT_FORMAT "]+\\n["
+ SUP_RAISE_FORMAT "]>?0\n", uid, p->uid, uid);
+ printf(".nr " DEPTH_FORMAT " \\n[" DEPTH_FORMAT "]-\\n["
+ SUP_RAISE_FORMAT "]>?0\n", uid, p->uid, uid);
+
+ return r;
+}
+
+void vcenter_box::output()
+{
+ printf("\\v'-\\n[" SUP_RAISE_FORMAT "]u'", uid);
+ p->output();
+ printf("\\v'\\n[" SUP_RAISE_FORMAT "]u'", uid);
+}
+
+void vcenter_box::debug_print()
+{
+ fprintf(stderr, "vcenter { ");
+ p->debug_print();
+ fprintf(stderr, " }");
+}
+
diff --git a/gnu/usr.bin/groff/eqn/over.cc b/gnu/usr.bin/groff/eqn/over.cc
new file mode 100644
index 0000000..5ea0121
--- /dev/null
+++ b/gnu/usr.bin/groff/eqn/over.cc
@@ -0,0 +1,196 @@
+// -*- C++ -*-
+/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
+ Written by James Clark (jjc@jclark.com)
+
+This file is part of groff.
+
+groff is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
+
+groff is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License along
+with groff; see the file COPYING. If not, write to the Free Software
+Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "eqn.h"
+#include "pbox.h"
+
+class over_box : public box {
+private:
+ int reduce_size;
+ box *num;
+ box *den;
+public:
+ over_box(int small, box *, box *);
+ ~over_box();
+ void debug_print();
+ int compute_metrics(int);
+ void output();
+ void check_tabs(int);
+};
+
+box *make_over_box(box *pp, box *qq)
+{
+ return new over_box(0, pp, qq);
+}
+
+box *make_small_over_box(box *pp, box *qq)
+{
+ return new over_box(1, pp, qq);
+}
+
+over_box::over_box(int is_small, box *pp, box *qq)
+: num(pp), den(qq), reduce_size(is_small)
+{
+ spacing_type = INNER_TYPE;
+}
+
+over_box::~over_box()
+{
+ delete num;
+ delete den;
+}
+
+int over_box::compute_metrics(int style)
+{
+ if (reduce_size) {
+ style = script_style(style);
+ printf(".nr " SIZE_FORMAT " \\n[.s]\n", uid);
+ set_script_size();
+ printf(".nr " SMALL_SIZE_FORMAT " \\n[.s]\n", uid);
+ }
+ int mark_uid;
+ int res = num->compute_metrics(style);
+ if (res)
+ mark_uid = num->uid;
+ int r = den->compute_metrics(cramped_style(style));
+ if (r && res)
+ error("multiple marks and lineups");
+ else {
+ mark_uid = den->uid;
+ res = r;
+ }
+ if (reduce_size)
+ printf(".ps \\n[" SIZE_FORMAT "]\n", uid);
+ printf(".nr " WIDTH_FORMAT " (\\n[" WIDTH_FORMAT "]>?\\n[" WIDTH_FORMAT "]",
+ uid, num->uid, den->uid);
+ // allow for \(ru being wider than both the numerator and denominator
+ if (!draw_flag)
+ fputs(">?\\w" DELIMITER_CHAR "\\(ru" DELIMITER_CHAR, stdout);
+ printf(")+%dM\n", null_delimiter_space*2 + over_hang*2);
+ // 15b
+ printf(".nr " SUP_RAISE_FORMAT " %dM\n",
+ uid, (reduce_size ? num2 : num1));
+ printf(".nr " SUB_LOWER_FORMAT " %dM\n",
+ uid, (reduce_size ? denom2 : denom1));
+
+ // 15d
+ printf(".nr " SUP_RAISE_FORMAT " +(\\n[" DEPTH_FORMAT
+ "]-\\n[" SUP_RAISE_FORMAT "]+%dM+(%dM/2)+%dM)>?0\n",
+ uid, num->uid, uid, axis_height, default_rule_thickness,
+ default_rule_thickness*(reduce_size ? 1 : 3));
+ printf(".nr " SUB_LOWER_FORMAT " +(\\n[" HEIGHT_FORMAT
+ "]-\\n[" SUB_LOWER_FORMAT "]-%dM+(%dM/2)+%dM)>?0\n",
+ uid, den->uid, uid, axis_height, default_rule_thickness,
+ default_rule_thickness*(reduce_size ? 1 : 3));
+
+
+ printf(".nr " HEIGHT_FORMAT " \\n[" SUP_RAISE_FORMAT "]+\\n["
+ HEIGHT_FORMAT "]\n",
+ uid, uid, num->uid);
+ printf(".nr " DEPTH_FORMAT " \\n[" SUB_LOWER_FORMAT "]+\\n["
+ DEPTH_FORMAT "]\n",
+ uid, uid, den->uid);
+ if (res)
+ printf(".nr " MARK_REG " +(\\n[" WIDTH_FORMAT "]-\\n["
+ WIDTH_FORMAT "]/2)\n", uid, mark_uid);
+ return res;
+}
+
+#define USE_Z
+
+void over_box::output()
+{
+ if (reduce_size)
+ printf("\\s[\\n[" SMALL_SIZE_FORMAT "]]", uid);
+#ifdef USE_Z
+ printf("\\Z" DELIMITER_CHAR);
+#endif
+ // move up to the numerator baseline
+ printf("\\v'-\\n[" SUP_RAISE_FORMAT "]u'", uid);
+ // move across so that it's centered
+ printf("\\h'\\n[" WIDTH_FORMAT "]u-\\n[" WIDTH_FORMAT "]u/2u'",
+ uid, num->uid);
+
+ // print the numerator
+ num->output();
+
+#ifdef USE_Z
+ printf(DELIMITER_CHAR);
+#else
+ // back again
+ printf("\\h'-\\n[" WIDTH_FORMAT "]u'", num->uid);
+ printf("\\h'-(\\n[" WIDTH_FORMAT "]u-\\n[" WIDTH_FORMAT "]u/2u)'",
+ uid, num->uid);
+ // down again
+ printf("\\v'\\n[" SUP_RAISE_FORMAT "]u'", uid);
+#endif
+#ifdef USE_Z
+ printf("\\Z" DELIMITER_CHAR);
+#endif
+ // move down to the denominator baseline
+ printf("\\v'\\n[" SUB_LOWER_FORMAT "]u'", uid);
+
+ // move across so that it's centered
+ printf("\\h'\\n[" WIDTH_FORMAT "]u-\\n[" WIDTH_FORMAT "]u/2u'",
+ uid, den->uid);
+
+ // print the the denominator
+ den->output();
+
+#ifdef USE_Z
+ printf(DELIMITER_CHAR);
+#else
+ // back again
+ printf("\\h'-\\n[" WIDTH_FORMAT "]u'", den->uid);
+ printf("\\h'-(\\n[" WIDTH_FORMAT "]u-\\n[" WIDTH_FORMAT "]u/2u)'",
+ uid, den->uid);
+ // up again
+ printf("\\v'-\\n[" SUB_LOWER_FORMAT "]u'", uid);
+#endif
+ if (reduce_size)
+ printf("\\s[\\n[" SIZE_FORMAT "]]", uid);
+ // draw the line
+ printf("\\h'%dM'", null_delimiter_space);
+ printf("\\v'-%dM'", axis_height);
+ fputs(draw_flag ? "\\D'l" : "\\l'", stdout);
+ printf("\\n[" WIDTH_FORMAT "]u-%dM",
+ uid, 2*null_delimiter_space);
+ fputs(draw_flag ? " 0'" : "\\&\\(ru'", stdout);
+ printf("\\v'%dM'", axis_height);
+ printf("\\h'%dM'", null_delimiter_space);
+}
+
+void over_box::debug_print()
+{
+ fprintf(stderr, "{ ");
+ num->debug_print();
+ if (reduce_size)
+ fprintf(stderr, " } smallover { ");
+ else
+ fprintf(stderr, " } over { ");
+ den->debug_print();
+ fprintf(stderr, " }");
+}
+
+void over_box::check_tabs(int level)
+{
+ num->check_tabs(level + 1);
+ den->check_tabs(level + 1);
+}
diff --git a/gnu/usr.bin/groff/eqn/pbox.h b/gnu/usr.bin/groff/eqn/pbox.h
new file mode 100644
index 0000000..adee780
--- /dev/null
+++ b/gnu/usr.bin/groff/eqn/pbox.h
@@ -0,0 +1,141 @@
+// -*- C++ -*-
+/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
+ Written by James Clark (jjc@jclark.com)
+
+This file is part of groff.
+
+groff is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
+
+groff is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License along
+with groff; see the file COPYING. If not, write to the Free Software
+Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+extern int fat_offset;
+
+extern int over_hang;
+extern int accent_width;
+
+extern int delimiter_factor;
+extern int delimiter_shortfall;
+
+extern int null_delimiter_space;
+extern int script_space;
+extern int thin_space;
+extern int medium_space;
+extern int thick_space;
+
+extern int num1;
+extern int num2;
+// we don't use num3, because we don't have \atop
+extern int denom1;
+extern int denom2;
+extern int axis_height;
+extern int sup1;
+extern int sup2;
+extern int sup3;
+extern int default_rule_thickness;
+extern int sub1;
+extern int sub2;
+extern int sup_drop;
+extern int sub_drop;
+extern int x_height;
+extern int big_op_spacing1;
+extern int big_op_spacing2;
+extern int big_op_spacing3;
+extern int big_op_spacing4;
+extern int big_op_spacing5;
+
+extern int baseline_sep;
+extern int shift_down;
+extern int column_sep;
+extern int matrix_side_sep;
+
+// ms.eqn relies on this!
+
+#define LINE_STRING "10"
+#define MARK_OR_LINEUP_FLAG_REG "MK"
+
+#define WIDTH_FORMAT PREFIX "w%d"
+#define HEIGHT_FORMAT PREFIX "h%d"
+#define DEPTH_FORMAT PREFIX "d%d"
+#define TOTAL_FORMAT PREFIX "t%d"
+#define SIZE_FORMAT PREFIX "z%d"
+#define SMALL_SIZE_FORMAT PREFIX "Z%d"
+#define SUP_RAISE_FORMAT PREFIX "p%d"
+#define SUB_LOWER_FORMAT PREFIX "b%d"
+#define SUB_KERN_FORMAT PREFIX "k%d"
+#define FONT_FORMAT PREFIX "f%d"
+#define SKEW_FORMAT PREFIX "s%d"
+#define LEFT_WIDTH_FORMAT PREFIX "lw%d"
+#define LEFT_DELIM_STRING_FORMAT PREFIX "l%d"
+#define RIGHT_DELIM_STRING_FORMAT PREFIX "r%d"
+#define SQRT_STRING_FORMAT PREFIX "sqr%d"
+#define SQRT_WIDTH_FORMAT PREFIX "sq%d"
+#define BASELINE_SEP_FORMAT PREFIX "bs%d"
+// this needs two parameters, the uid and the column index
+#define COLUMN_WIDTH_FORMAT PREFIX "cw%d,%d"
+
+#define BAR_STRING PREFIX "sqb"
+#define TEMP_REG PREFIX "temp"
+#define MARK_REG PREFIX "mark"
+#define MARK_WIDTH_REG PREFIX "mwidth"
+#define SAVED_MARK_REG PREFIX "smark"
+#define MAX_SIZE_REG PREFIX "mxsz"
+#define REPEAT_APPEND_STRING_MACRO PREFIX "ras"
+#define TOP_HEIGHT_REG PREFIX "th"
+#define TOP_DEPTH_REG PREFIX "td"
+#define MID_HEIGHT_REG PREFIX "mh"
+#define MID_DEPTH_REG PREFIX "md"
+#define BOT_HEIGHT_REG PREFIX "bh"
+#define BOT_DEPTH_REG PREFIX "bd"
+#define EXT_HEIGHT_REG PREFIX "eh"
+#define EXT_DEPTH_REG PREFIX "ed"
+#define TOTAL_HEIGHT_REG PREFIX "tot"
+#define DELTA_REG PREFIX "delta"
+#define DELIM_STRING PREFIX "delim"
+#define DELIM_WIDTH_REG PREFIX "dwidth"
+#define SAVED_FONT_REG PREFIX "sfont"
+#define SAVED_PREV_FONT_REG PREFIX "spfont"
+#define SAVED_INLINE_FONT_REG PREFIX "sifont"
+#define SAVED_INLINE_PREV_FONT_REG PREFIX "sipfont"
+#define SAVED_SIZE_REG PREFIX "ssize"
+#define SAVED_INLINE_SIZE_REG PREFIX "sisize"
+#define SAVED_INLINE_PREV_SIZE_REG PREFIX "sipsize"
+#define SAVE_FONT_STRING PREFIX "sfont"
+#define RESTORE_FONT_STRING PREFIX "rfont"
+#define INDEX_REG PREFIX "i"
+#define TEMP_MACRO PREFIX "tempmac"
+
+#define DELIMITER_CHAR "\\(EQ"
+
+const int CRAMPED_SCRIPT_STYLE = 0;
+const int SCRIPT_STYLE = 1;
+const int CRAMPED_DISPLAY_STYLE = 2;
+const int DISPLAY_STYLE = 3;
+
+extern int script_style(int);
+extern int cramped_style(int);
+
+const int ORDINARY_TYPE = 0;
+const int OPERATOR_TYPE = 1;
+const int BINARY_TYPE = 2;
+const int RELATION_TYPE = 3;
+const int OPENING_TYPE = 4;
+const int CLOSING_TYPE = 5;
+const int PUNCTUATION_TYPE = 6;
+const int INNER_TYPE = 7;
+const int SUPPRESS_TYPE = 8;
+
+void set_script_size();
+
+enum { HINT_PREV_IS_ITALIC = 01, HINT_NEXT_IS_ITALIC = 02 };
+
+extern const char *current_roman_font;
diff --git a/gnu/usr.bin/groff/eqn/pile.cc b/gnu/usr.bin/groff/eqn/pile.cc
new file mode 100644
index 0000000..9aa4306
--- /dev/null
+++ b/gnu/usr.bin/groff/eqn/pile.cc
@@ -0,0 +1,293 @@
+// -*- C++ -*-
+/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
+ Written by James Clark (jjc@jclark.com)
+
+This file is part of groff.
+
+groff is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
+
+groff is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License along
+with groff; see the file COPYING. If not, write to the Free Software
+Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+// piles and matrices
+
+#include "eqn.h"
+#include "pbox.h"
+
+// SUP_RAISE_FORMAT gives the first baseline
+// BASELINE_SEP_FORMAT gives the separation between baselines
+
+int pile_box::compute_metrics(int style)
+{
+ int i;
+ for (i = 0; i < col.len; i++)
+ col.p[i]->compute_metrics(style);
+ printf(".nr " WIDTH_FORMAT " 0", uid);
+ for (i = 0; i < col.len; i++)
+ printf(">?\\n[" WIDTH_FORMAT "]", col.p[i]->uid);
+ printf("\n");
+ printf(".nr " BASELINE_SEP_FORMAT " %dM",
+ uid, baseline_sep+col.space);
+ for (i = 1; i < col.len; i++)
+ printf(">?(\\n[" DEPTH_FORMAT "]+\\n[" HEIGHT_FORMAT "]+%dM)",
+ col.p[i-1]->uid, col.p[i]->uid, default_rule_thickness*5);
+ // round it so that it's a multiple of the vertical resolution
+ printf("/\\n(.V+(\\n(.V/2)*\\n(.V\n");
+
+ printf(".nr " SUP_RAISE_FORMAT " \\n[" BASELINE_SEP_FORMAT "]*%d/2"
+ "+%dM\n",
+ uid, uid, col.len-1, axis_height - shift_down);
+ printf(".nr " HEIGHT_FORMAT " \\n[" SUP_RAISE_FORMAT "]+\\n["
+ HEIGHT_FORMAT "]\n",
+ uid, uid, col.p[0]->uid);
+ printf(".nr " DEPTH_FORMAT " \\n[" BASELINE_SEP_FORMAT "]*%d+\\n["
+ DEPTH_FORMAT "]-\\n[" SUP_RAISE_FORMAT "]\n",
+ uid, uid, col.len-1, col.p[col.len-1]->uid, uid);
+ return FOUND_NOTHING;
+}
+
+void pile_box::output()
+{
+ int i;
+ printf("\\v'-\\n[" SUP_RAISE_FORMAT "]u'", uid);
+ for (i = 0; i < col.len; i++) {
+ switch (col.align) {
+ case LEFT_ALIGN:
+ break;
+ case CENTER_ALIGN:
+ printf("\\h'\\n[" WIDTH_FORMAT "]u-\\n[" WIDTH_FORMAT "]u/2u'",
+ uid, col.p[i]->uid);
+ break;
+ case RIGHT_ALIGN:
+ printf("\\h'\\n[" WIDTH_FORMAT "]u-\\n[" WIDTH_FORMAT "]u'",
+ uid, col.p[i]->uid);
+ break;
+ default:
+ assert(0);
+ }
+ col.p[i]->output();
+ printf("\\h'-\\n[" WIDTH_FORMAT "]u'", col.p[i]->uid);
+ switch (col.align) {
+ case LEFT_ALIGN:
+ break;
+ case CENTER_ALIGN:
+ printf("\\h'\\n[" WIDTH_FORMAT "]u-\\n[" WIDTH_FORMAT "]u/2u'",
+ col.p[i]->uid, uid);
+ break;
+ case RIGHT_ALIGN:
+ printf("\\h'\\n[" WIDTH_FORMAT "]u-\\n[" WIDTH_FORMAT "]u'",
+ col.p[i]->uid, uid);
+ break;
+ default:
+ assert(0);
+ }
+ if (i != col.len - 1)
+ printf("\\v'\\n[" BASELINE_SEP_FORMAT "]u'", uid);
+ }
+ printf("\\v'\\n[" SUP_RAISE_FORMAT "]u'", uid);
+ printf("\\v'-(%du*\\n[" BASELINE_SEP_FORMAT "]u)'", col.len - 1, uid);
+ printf("\\h'\\n[" WIDTH_FORMAT "]u'", uid);
+}
+
+pile_box::pile_box(box *pp) : col(pp)
+{
+}
+
+void pile_box::check_tabs(int level)
+{
+ col.list_check_tabs(level);
+}
+
+void pile_box::debug_print()
+{
+ col.debug_print("pile");
+}
+
+int matrix_box::compute_metrics(int style)
+{
+ int i, j;
+ int maxlen = 0;
+ int space = 0;
+ for (i = 0; i < len; i++) {
+ for (j = 0; j < p[i]->len; j++)
+ p[i]->p[j]->compute_metrics(style);
+ if (p[i]->len > maxlen)
+ maxlen = p[i]->len;
+ if (p[i]->space > space)
+ space = p[i]->space;
+ }
+ for (i = 0; i < len; i++) {
+ printf(".nr " COLUMN_WIDTH_FORMAT " 0", uid, i);
+ for (j = 0; j < p[i]->len; j++)
+ printf(">?\\n[" WIDTH_FORMAT "]", p[i]->p[j]->uid);
+ printf("\n");
+ }
+ printf(".nr " WIDTH_FORMAT " %dM",
+ uid, column_sep*(len-1)+2*matrix_side_sep);
+ for (i = 0; i < len; i++)
+ printf("+\\n[" COLUMN_WIDTH_FORMAT "]", uid, i);
+ printf("\n");
+ printf(".nr " BASELINE_SEP_FORMAT " %dM",
+ uid, baseline_sep+space);
+ for (i = 0; i < len; i++)
+ for (j = 1; j < p[i]->len; j++)
+ printf(">?(\\n[" DEPTH_FORMAT "]+\\n[" HEIGHT_FORMAT "]+%dM)",
+ p[i]->p[j-1]->uid, p[i]->p[j]->uid, default_rule_thickness*5);
+ // round it so that it's a multiple of the vertical resolution
+ printf("/\\n(.V+(\\n(.V/2)*\\n(.V\n");
+ printf(".nr " SUP_RAISE_FORMAT " \\n[" BASELINE_SEP_FORMAT "]*%d/2"
+ "+%dM\n",
+ uid, uid, maxlen-1, axis_height - shift_down);
+ printf(".nr " HEIGHT_FORMAT " 0\\n[" SUP_RAISE_FORMAT "]+(0",
+ uid, uid);
+ for (i = 0; i < len; i++)
+ printf(">?\\n[" HEIGHT_FORMAT "]", p[i]->p[0]->uid);
+ printf(")>?0\n");
+ printf(".nr " DEPTH_FORMAT " \\n[" BASELINE_SEP_FORMAT "]*%d-\\n["
+ SUP_RAISE_FORMAT "]+(0",
+ uid, uid, maxlen-1, uid);
+ for (i = 0; i < len; i++)
+ if (p[i]->len == maxlen)
+ printf(">?\\n[" DEPTH_FORMAT "]", p[i]->p[maxlen-1]->uid);
+ printf(")>?0\n");
+ return FOUND_NOTHING;
+}
+
+void matrix_box::output()
+{
+ printf("\\h'%dM'", matrix_side_sep);
+ for (int i = 0; i < len; i++) {
+ int j;
+ printf("\\v'-\\n[" SUP_RAISE_FORMAT "]u'", uid);
+ for (j = 0; j < p[i]->len; j++) {
+ switch (p[i]->align) {
+ case LEFT_ALIGN:
+ break;
+ case CENTER_ALIGN:
+ printf("\\h'\\n[" COLUMN_WIDTH_FORMAT "]u-\\n[" WIDTH_FORMAT "]u/2u'",
+ uid, i, p[i]->p[j]->uid);
+ break;
+ case RIGHT_ALIGN:
+ printf("\\h'\\n[" COLUMN_WIDTH_FORMAT "]u-\\n[" WIDTH_FORMAT "]u'",
+ uid, i, p[i]->p[j]->uid);
+ break;
+ default:
+ assert(0);
+ }
+ p[i]->p[j]->output();
+ printf("\\h'-\\n[" WIDTH_FORMAT "]u'", p[i]->p[j]->uid);
+ switch (p[i]->align) {
+ case LEFT_ALIGN:
+ break;
+ case CENTER_ALIGN:
+ printf("\\h'\\n[" WIDTH_FORMAT "]u-\\n[" COLUMN_WIDTH_FORMAT "]u/2u'",
+ p[i]->p[j]->uid, uid, i);
+ break;
+ case RIGHT_ALIGN:
+ printf("\\h'\\n[" WIDTH_FORMAT "]u-\\n[" COLUMN_WIDTH_FORMAT "]u'",
+ p[i]->p[j]->uid, uid, i);
+ break;
+ default:
+ assert(0);
+ }
+ if (j != p[i]->len - 1)
+ printf("\\v'\\n[" BASELINE_SEP_FORMAT "]u'", uid);
+ }
+ printf("\\v'\\n[" SUP_RAISE_FORMAT "]u'", uid);
+ printf("\\v'-(%du*\\n[" BASELINE_SEP_FORMAT "]u)'", p[i]->len - 1, uid);
+ printf("\\h'\\n[" COLUMN_WIDTH_FORMAT "]u'", uid, i);
+ if (i != len - 1)
+ printf("\\h'%dM'", column_sep);
+ }
+ printf("\\h'%dM'", matrix_side_sep);
+}
+
+matrix_box::matrix_box(column *pp)
+{
+ p = new column*[10];
+ for (int i = 0; i < 10; i++)
+ p[i] = 0;
+ maxlen = 10;
+ len = 1;
+ p[0] = pp;
+}
+
+matrix_box::~matrix_box()
+{
+ for (int i = 0; i < len; i++)
+ delete p[i];
+ a_delete p;
+}
+
+void matrix_box::append(column *pp)
+{
+ if (len + 1 > maxlen) {
+ column **oldp = p;
+ maxlen *= 2;
+ p = new column*[maxlen];
+ memcpy(p, oldp, sizeof(column*)*len);
+ a_delete oldp;
+ }
+ p[len++] = pp;
+}
+
+void matrix_box::check_tabs(int level)
+{
+ for (int i = 0; i < len; i++)
+ p[i]->list_check_tabs(level);
+}
+
+void matrix_box::debug_print()
+{
+ fprintf(stderr, "matrix { ");
+ p[0]->debug_print("col");
+ for (int i = 1; i < len; i++) {
+ fprintf(stderr, " ");
+ p[i]->debug_print("col");
+ }
+ fprintf(stderr, " }");
+}
+
+column::column(box *pp) : box_list(pp), align(CENTER_ALIGN), space(0)
+{
+}
+
+void column::set_alignment(alignment a)
+{
+ align = a;
+}
+
+void column::set_space(int n)
+{
+ space = n;
+}
+
+void column::debug_print(const char *s)
+{
+ char c = '\0'; // shut up -Wall
+ switch (align) {
+ case LEFT_ALIGN:
+ c = 'l';
+ break;
+ case RIGHT_ALIGN:
+ c = 'r';
+ break;
+ case CENTER_ALIGN:
+ c = 'c';
+ break;
+ default:
+ assert(0);
+ }
+ fprintf(stderr, "%c%s %d { ", c, s, space);
+ list_debug_print(" above ");
+ fprintf(stderr, " }");
+}
+
diff --git a/gnu/usr.bin/groff/eqn/script.cc b/gnu/usr.bin/groff/eqn/script.cc
new file mode 100644
index 0000000..3ee83ba
--- /dev/null
+++ b/gnu/usr.bin/groff/eqn/script.cc
@@ -0,0 +1,221 @@
+// -*- C++ -*-
+/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
+ Written by James Clark (jjc@jclark.com)
+
+This file is part of groff.
+
+groff is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
+
+groff is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License along
+with groff; see the file COPYING. If not, write to the Free Software
+Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "eqn.h"
+#include "pbox.h"
+
+class script_box : public pointer_box {
+private:
+ box *sub;
+ box *sup;
+public:
+ script_box(box *, box *, box *);
+ ~script_box();
+ int compute_metrics(int);
+ void output();
+ void debug_print();
+ int left_is_italic();
+ void hint(unsigned);
+ void check_tabs(int);
+};
+
+/* The idea is that the script should attach to the rightmost box
+of a list. For example, given `2x sup 3', the superscript should
+attach to `x' rather than `2x'. */
+
+box *make_script_box(box *nuc, box *sub, box *sup)
+{
+ list_box *b = nuc->to_list_box();
+ if (b != 0) {
+ b->list.p[b->list.len-1] = make_script_box(b->list.p[b->list.len - 1],
+ sub,
+ sup);
+ return b;
+ }
+ else
+ return new script_box(nuc, sub, sup);
+}
+
+script_box::script_box(box *pp, box *qq, box *rr)
+: pointer_box(pp), sub(qq), sup(rr)
+{
+}
+
+script_box::~script_box()
+{
+ delete sub;
+ delete sup;
+}
+
+int script_box::left_is_italic()
+{
+ return p->left_is_italic();
+}
+
+int script_box::compute_metrics(int style)
+{
+ int res = p->compute_metrics(style);
+ p->compute_subscript_kern();
+ printf(".nr " SIZE_FORMAT " \\n[.s]\n", uid);
+ if (!(style <= SCRIPT_STYLE && one_size_reduction_flag))
+ set_script_size();
+ printf(".nr " SMALL_SIZE_FORMAT " \\n[.s]\n", uid);
+ if (sub != 0)
+ sub->compute_metrics(cramped_style(script_style(style)));
+ if (sup != 0)
+ sup->compute_metrics(script_style(style));
+ // 18a
+ if (p->is_char()) {
+ printf(".nr " SUP_RAISE_FORMAT " 0\n", uid);
+ printf(".nr " SUB_LOWER_FORMAT " 0\n", uid);
+ }
+ else {
+ printf(".nr " SUP_RAISE_FORMAT " \\n[" HEIGHT_FORMAT "]-%dM>?0\n",
+ uid, p->uid, sup_drop);
+ printf(".nr " SUB_LOWER_FORMAT " \\n[" DEPTH_FORMAT "]+%dM\n",
+ uid, p->uid, sub_drop);
+ }
+ printf(".ps \\n[" SIZE_FORMAT "]\n", uid);
+ if (sup == 0) {
+ assert(sub != 0);
+ // 18b
+ printf(".nr " SUB_LOWER_FORMAT " \\n[" SUB_LOWER_FORMAT "]>?%dM>?(\\n["
+ HEIGHT_FORMAT "]-(%dM*4/5))\n",
+ uid, uid, sub1, sub->uid, x_height);
+ }
+ else {
+ // sup != 0
+ // 18c
+ int p;
+ if (style == DISPLAY_STYLE)
+ p = sup1;
+ else if (style & 1) // not cramped
+ p = sup2;
+ else
+ p = sup3;
+ printf(".nr " SUP_RAISE_FORMAT " \\n[" SUP_RAISE_FORMAT
+ "]>?%dM>?(\\n[" DEPTH_FORMAT "]+(%dM/4))\n",
+ uid, uid, p, sup->uid, x_height);
+ // 18d
+ if (sub != 0) {
+ printf(".nr " SUB_LOWER_FORMAT " \\n[" SUB_LOWER_FORMAT "]>?%dM\n",
+ uid, uid, sub2);
+ // 18e
+ printf(".nr " TEMP_REG " \\n[" DEPTH_FORMAT "]-\\n["
+ SUP_RAISE_FORMAT "]+\\n[" HEIGHT_FORMAT "]-\\n["
+ SUB_LOWER_FORMAT "]+(4*%dM)\n",
+ sup->uid, uid, sub->uid, uid, default_rule_thickness);
+ printf(".if \\n[" TEMP_REG "] \\{");
+ printf(".nr " SUB_LOWER_FORMAT " +\\n[" TEMP_REG "]\n", uid);
+ printf(".nr " TEMP_REG " (%dM*4/5)-\\n[" SUP_RAISE_FORMAT
+ "]+\\n[" DEPTH_FORMAT "]>?0\n",
+ x_height, uid, sup->uid);
+ printf(".nr " SUP_RAISE_FORMAT " +\\n[" TEMP_REG "]\n", uid);
+ printf(".nr " SUB_LOWER_FORMAT " -\\n[" TEMP_REG "]\n", uid);
+ printf(".\\}\n");
+ }
+ }
+ printf(".nr " WIDTH_FORMAT " 0\\n[" WIDTH_FORMAT "]", uid, p->uid);
+ if (sub != 0 && sup != 0)
+ printf("+((\\n[" WIDTH_FORMAT "]-\\n[" SUB_KERN_FORMAT "]>?\\n["
+ WIDTH_FORMAT "])+%dM)>?0\n",
+ sub->uid, p->uid, sup->uid, script_space);
+ else if (sub != 0)
+ printf("+(\\n[" WIDTH_FORMAT "]-\\n[" SUB_KERN_FORMAT "]+%dM)>?0\n",
+ sub->uid, p->uid, script_space);
+ else if (sup != 0)
+ printf("+(\\n[" WIDTH_FORMAT "]+%dM)>?0\n", sup->uid, script_space);
+ else
+ printf("\n");
+ printf(".nr " HEIGHT_FORMAT " \\n[" HEIGHT_FORMAT "]",
+ uid, p->uid);
+ if (sup != 0)
+ printf(">?(\\n[" SUP_RAISE_FORMAT "]+\\n[" HEIGHT_FORMAT "])",
+ uid, sup->uid);
+ if (sub != 0)
+ printf(">?(-\\n[" SUB_LOWER_FORMAT "]+\\n[" HEIGHT_FORMAT "])",
+ uid, sub->uid);
+ printf("\n");
+ printf(".nr " DEPTH_FORMAT " \\n[" DEPTH_FORMAT "]",
+ uid, p->uid);
+ if (sub != 0)
+ printf(">?(\\n[" SUB_LOWER_FORMAT "]+\\n[" DEPTH_FORMAT "])",
+ uid, sub->uid);
+ if (sup != 0)
+ printf(">?(-\\n[" SUP_RAISE_FORMAT "]+\\n[" DEPTH_FORMAT "])",
+ uid, sup->uid);
+ printf("\n");
+ return res;
+}
+
+void script_box::output()
+{
+ p->output();
+ if (sup != 0) {
+ printf("\\Z" DELIMITER_CHAR);
+ printf("\\v'-\\n[" SUP_RAISE_FORMAT "]u'", uid);
+ printf("\\s[\\n[" SMALL_SIZE_FORMAT "]]", uid);
+ sup->output();
+ printf("\\s[\\n[" SIZE_FORMAT "]]", uid);
+ printf(DELIMITER_CHAR);
+ }
+ if (sub != 0) {
+ printf("\\Z" DELIMITER_CHAR);
+ printf("\\v'\\n[" SUB_LOWER_FORMAT "]u'", uid);
+ printf("\\s[\\n[" SMALL_SIZE_FORMAT "]]", uid);
+ printf("\\h'-\\n[" SUB_KERN_FORMAT "]u'", p->uid);
+ sub->output();
+ printf("\\s[\\n[" SIZE_FORMAT "]]", uid);
+ printf(DELIMITER_CHAR);
+ }
+ printf("\\h'\\n[" WIDTH_FORMAT "]u-\\n[" WIDTH_FORMAT "]u'",
+ uid, p->uid);
+}
+
+void script_box::hint(unsigned flags)
+{
+ p->hint(flags & ~HINT_NEXT_IS_ITALIC);
+}
+
+void script_box::debug_print()
+{
+ fprintf(stderr, "{ ");
+ p->debug_print();
+ fprintf(stderr, " }");
+ if (sub) {
+ fprintf(stderr, " sub { ");
+ sub->debug_print();
+ fprintf(stderr, " }");
+ }
+ if (sup) {
+ fprintf(stderr, " sup { ");
+ sup->debug_print();
+ fprintf(stderr, " }");
+ }
+}
+
+void script_box::check_tabs(int level)
+{
+ if (sup)
+ sup->check_tabs(level + 1);
+ if (sub)
+ sub->check_tabs(level + 1);
+ p->check_tabs(level);
+}
diff --git a/gnu/usr.bin/groff/eqn/special.cc b/gnu/usr.bin/groff/eqn/special.cc
new file mode 100644
index 0000000..be73543
--- /dev/null
+++ b/gnu/usr.bin/groff/eqn/special.cc
@@ -0,0 +1,115 @@
+// -*- C++ -*-
+/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
+ Written by James Clark (jjc@jclark.com)
+
+This file is part of groff.
+
+groff is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
+
+groff is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License along
+with groff; see the file COPYING. If not, write to the Free Software
+Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "eqn.h"
+#include "pbox.h"
+
+#define STRING_FORMAT PREFIX "str%d"
+
+#define SPECIAL_STRING "0s"
+#define SPECIAL_WIDTH_REG "0w"
+#define SPECIAL_HEIGHT_REG "0h"
+#define SPECIAL_DEPTH_REG "0d"
+#define SPECIAL_SUB_KERN_REG "0skern"
+#define SPECIAL_SKEW_REG "0skew"
+
+/*
+For example:
+
+.de Cl
+.ds 0s \Z'\\*[0s]'\v'\\n(0du'\D'l \\n(0wu -\\n(0hu-\\n(0du'\v'\\n(0hu'
+..
+.EQ
+define cancel 'special Cl'
+.EN
+*/
+
+
+class special_box : public pointer_box {
+ char *macro_name;
+public:
+ special_box(char *, box *);
+ ~special_box();
+ int compute_metrics(int);
+ void compute_subscript_kern();
+ void compute_skew();
+ void output();
+ void debug_print();
+};
+
+box *make_special_box(char *s, box *p)
+{
+ return new special_box(s, p);
+}
+
+special_box::special_box(char *s, box *pp) :macro_name(s), pointer_box(pp)
+{
+}
+
+special_box::~special_box()
+{
+ a_delete macro_name;
+}
+
+int special_box::compute_metrics(int style)
+{
+ int r = p->compute_metrics(style);
+ p->compute_subscript_kern();
+ p->compute_skew();
+ printf(".ds " SPECIAL_STRING " \"");
+ p->output();
+ printf("\n");
+ printf(".nr " SPECIAL_WIDTH_REG " 0\\n[" WIDTH_FORMAT "]\n", p->uid);
+ printf(".nr " SPECIAL_HEIGHT_REG " \\n[" HEIGHT_FORMAT "]\n", p->uid);
+ printf(".nr " SPECIAL_DEPTH_REG " \\n[" DEPTH_FORMAT "]\n", p->uid);
+ printf(".nr " SPECIAL_SUB_KERN_REG " \\n[" SUB_KERN_FORMAT "]\n", p->uid);
+ printf(".nr " SPECIAL_SKEW_REG " 0\\n[" SKEW_FORMAT "]\n", p->uid);
+ printf(".%s\n", macro_name);
+ printf(".rn " SPECIAL_STRING " " STRING_FORMAT "\n", uid);
+ printf(".nr " WIDTH_FORMAT " 0\\n[" SPECIAL_WIDTH_REG "]\n", uid);
+ printf(".nr " HEIGHT_FORMAT " 0>?\\n[" SPECIAL_HEIGHT_REG "]\n", uid);
+ printf(".nr " DEPTH_FORMAT " 0>?\\n[" SPECIAL_DEPTH_REG "]\n", uid);
+ printf(".nr " SUB_KERN_FORMAT " 0>?\\n[" SPECIAL_SUB_KERN_REG "]\n", uid);
+ printf(".nr " SKEW_FORMAT " 0\\n[" SPECIAL_SKEW_REG "]\n", uid);
+ // User will have to change MARK_REG if appropriate.
+ return r;
+}
+
+void special_box::compute_subscript_kern()
+{
+ // Already computed in compute_metrics(), so do nothing.
+}
+
+void special_box::compute_skew()
+{
+ // Already computed in compute_metrics(), so do nothing.
+}
+
+void special_box::output()
+{
+ printf("\\*[" STRING_FORMAT "]", uid);
+}
+
+void special_box::debug_print()
+{
+ fprintf(stderr, "special %s { ", macro_name);
+ p->debug_print();
+ fprintf(stderr, " }");
+}
diff --git a/gnu/usr.bin/groff/eqn/sqrt.cc b/gnu/usr.bin/groff/eqn/sqrt.cc
new file mode 100644
index 0000000..3488d03
--- /dev/null
+++ b/gnu/usr.bin/groff/eqn/sqrt.cc
@@ -0,0 +1,179 @@
+// -*- C++ -*-
+/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
+ Written by James Clark (jjc@jclark.com)
+
+This file is part of groff.
+
+groff is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
+
+groff is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License along
+with groff; see the file COPYING. If not, write to the Free Software
+Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "eqn.h"
+#include "pbox.h"
+
+
+class sqrt_box : public pointer_box {
+public:
+ sqrt_box(box *);
+ int compute_metrics(int style);
+ void output();
+ void debug_print();
+ void check_tabs(int);
+};
+
+box *make_sqrt_box(box *pp)
+{
+ return new sqrt_box(pp);
+}
+
+sqrt_box::sqrt_box(box *pp) : pointer_box(pp)
+{
+}
+
+#define SQRT_CHAR "\\(sr"
+#define RADICAL_EXTENSION_CHAR "\\[radicalex]"
+
+#define SQRT_CHAIN "\\[sr\\\\n[" INDEX_REG "]]"
+#define BAR_CHAIN "\\[radicalex\\\\n[" INDEX_REG "]]"
+
+int sqrt_box::compute_metrics(int style)
+{
+ // 11
+ int r = p->compute_metrics(cramped_style(style));
+ printf(".nr " TEMP_REG " \\n[" HEIGHT_FORMAT "]+\\n[" DEPTH_FORMAT
+ "]+%dM+(%dM/4)\n",
+ p->uid, p->uid, default_rule_thickness,
+ (style > SCRIPT_STYLE ? x_height : default_rule_thickness));
+ printf(".nr " SIZE_FORMAT " \\n[.s]\n", uid);
+ printf(".ds " SQRT_STRING_FORMAT " " SQRT_CHAR "\n", uid);
+ printf(".ds " BAR_STRING " " RADICAL_EXTENSION_CHAR "\n");
+ printf(".nr " SQRT_WIDTH_FORMAT
+ " 0\\w" DELIMITER_CHAR SQRT_CHAR DELIMITER_CHAR "\n",
+ uid);
+ printf(".if \\n[rst]-\\n[rsb]-%dM<\\n[" TEMP_REG "] \\{",
+ default_rule_thickness);
+
+ printf(".nr " INDEX_REG " 0\n"
+ ".de " TEMP_MACRO "\n"
+ ".ie c" SQRT_CHAIN " \\{"
+ ".ds " SQRT_STRING_FORMAT " " SQRT_CHAIN "\n"
+ ".ie c" BAR_CHAIN " .ds " BAR_STRING " " BAR_CHAIN "\n"
+ ".el .ds " BAR_STRING " " RADICAL_EXTENSION_CHAR "\n"
+ ".nr " SQRT_WIDTH_FORMAT
+ " 0\\w" DELIMITER_CHAR SQRT_CHAIN DELIMITER_CHAR "\n"
+ ".if \\\\n[rst]-\\\\n[rsb]-%dM<\\n[" TEMP_REG "] \\{"
+ ".nr " INDEX_REG " +1\n"
+ "." TEMP_MACRO "\n"
+ ".\\}\\}\n"
+ ".el .nr " INDEX_REG " 0-1\n"
+ "..\n"
+ "." TEMP_MACRO "\n",
+ uid, uid, default_rule_thickness);
+
+ printf(".if \\n[" INDEX_REG "]<0 \\{");
+
+ // Determine the maximum point size
+ printf(".ps 1000\n");
+ printf(".nr " MAX_SIZE_REG " \\n[.s]\n");
+ printf(".ps \\n[" SIZE_FORMAT "]\n", uid);
+ // We define a macro that will increase the current point size
+ // until we get a radical sign that's tall enough or we reach
+ // the maximum point size.
+ printf(".de " TEMP_MACRO "\n"
+ ".nr " SQRT_WIDTH_FORMAT
+ " 0\\w" DELIMITER_CHAR "\\*[" SQRT_STRING_FORMAT "]" DELIMITER_CHAR "\n"
+ ".if \\\\n[rst]-\\\\n[rsb]-%dM<\\n[" TEMP_REG "]"
+ "&(\\\\n[.s]<\\n[" MAX_SIZE_REG "]) \\{"
+ ".ps +1\n"
+ "." TEMP_MACRO "\n"
+ ".\\}\n"
+ "..\n"
+ "." TEMP_MACRO "\n",
+ uid, uid, default_rule_thickness);
+
+ printf(".\\}\\}\n");
+
+ printf(".nr " SMALL_SIZE_FORMAT " \\n[.s]\n", uid);
+ // set TEMP_REG to the amount by which the radical sign is too big
+ printf(".nr " TEMP_REG " \\n[rst]-\\n[rsb]-%dM-\\n[" TEMP_REG "]\n",
+ default_rule_thickness);
+ // If TEMP_REG is negative, the bottom of the radical sign should
+ // be -TEMP_REG above the bottom of p. If it's positive, the bottom
+ // of the radical sign should be TEMP_REG/2 below the bottom of p.
+ // This calculates the amount by which the baseline of the radical
+ // should be raised.
+ printf(".nr " SUP_RAISE_FORMAT " (-\\n[" TEMP_REG "]>?(-\\n[" TEMP_REG "]/2))"
+ "-\\n[rsb]-\\n[" DEPTH_FORMAT "]\n", uid, p->uid);
+ printf(".nr " HEIGHT_FORMAT " \\n[" HEIGHT_FORMAT "]"
+ ">?(\\n[" SUP_RAISE_FORMAT "]+\\n[rst])\n",
+ uid, p->uid, uid);
+ printf(".nr " DEPTH_FORMAT " \\n[" DEPTH_FORMAT "]"
+ ">?(-\\n[" SUP_RAISE_FORMAT "]-\\n[rsb])\n",
+ uid, p->uid, uid);
+ // Do this last, so we don't lose height and depth information on
+ // the radical sign.
+ // Remember that the width of the bar might be greater than the width of p.
+
+ printf(".nr " TEMP_REG " "
+ "\\n[" WIDTH_FORMAT "]"
+ ">?\\w" DELIMITER_CHAR "\\*[" BAR_STRING "]" DELIMITER_CHAR "\n",
+ p->uid);
+ printf(".as " SQRT_STRING_FORMAT " "
+ "\\l'\\n[" TEMP_REG "]u\\&\\*[" BAR_STRING "]'\n",
+ uid);
+ printf(".nr " WIDTH_FORMAT " \\n[" TEMP_REG "]"
+ "+\\n[" SQRT_WIDTH_FORMAT "]\n",
+ uid, uid);
+
+ if (r)
+ printf(".nr " MARK_REG " +\\n[" SQRT_WIDTH_FORMAT "]\n", uid);
+ // the top of the bar might be higher than the top of the radical sign
+ printf(".nr " HEIGHT_FORMAT " \\n[" HEIGHT_FORMAT "]"
+ ">?(\\n[" SUP_RAISE_FORMAT "]+\\n[rst])\n",
+ uid, p->uid, uid);
+ // put a bit of extra space above the bar
+ printf(".nr " HEIGHT_FORMAT " +%dM\n", uid, default_rule_thickness);
+ printf(".ps \\n[" SIZE_FORMAT "]\n", uid);
+ return r;
+}
+
+void sqrt_box::output()
+{
+ printf("\\Z" DELIMITER_CHAR);
+ printf("\\s[\\n[" SMALL_SIZE_FORMAT "]]", uid);
+ printf("\\v'-\\n[" SUP_RAISE_FORMAT "]u'", uid);
+ printf("\\*[" SQRT_STRING_FORMAT "]", uid);
+ printf("\\s[\\n[" SIZE_FORMAT "]]", uid);
+ printf(DELIMITER_CHAR);
+
+ printf("\\Z" DELIMITER_CHAR);
+ printf("\\h'\\n[" WIDTH_FORMAT "]u-\\n[" WIDTH_FORMAT "]u"
+ "+\\n[" SQRT_WIDTH_FORMAT "]u/2u'",
+ uid, p->uid, uid);
+ p->output();
+ printf(DELIMITER_CHAR);
+
+ printf("\\h'\\n[" WIDTH_FORMAT "]u'", uid);
+}
+
+void sqrt_box::debug_print()
+{
+ fprintf(stderr, "sqrt { ");
+ p->debug_print();
+ fprintf(stderr, " }");
+}
+
+void sqrt_box::check_tabs(int level)
+{
+ p->check_tabs(level + 1);
+}
diff --git a/gnu/usr.bin/groff/eqn/text.cc b/gnu/usr.bin/groff/eqn/text.cc
new file mode 100644
index 0000000..ee6618f
--- /dev/null
+++ b/gnu/usr.bin/groff/eqn/text.cc
@@ -0,0 +1,528 @@
+// -*- C++ -*-
+/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
+ Written by James Clark (jjc@jclark.com)
+
+This file is part of groff.
+
+groff is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
+
+groff is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License along
+with groff; see the file COPYING. If not, write to the Free Software
+Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "eqn.h"
+#include "pbox.h"
+#include "ptable.h"
+
+class char_box : public simple_box {
+ unsigned char c;
+ char next_is_italic;
+ char prev_is_italic;
+public:
+ char_box(unsigned char);
+ void debug_print();
+ void output();
+ int is_char();
+ int left_is_italic();
+ int right_is_italic();
+ void hint(unsigned);
+ void handle_char_type(int, int);
+};
+
+class special_char_box : public simple_box {
+ char *s;
+public:
+ special_char_box(const char *);
+ ~special_char_box();
+ void output();
+ void debug_print();
+ int is_char();
+ void handle_char_type(int, int);
+};
+
+const char *spacing_type_table[] = {
+ "ordinary",
+ "operator",
+ "binary",
+ "relation",
+ "opening",
+ "closing",
+ "punctuation",
+ "inner",
+ "suppress",
+ 0,
+};
+
+const int DIGIT_TYPE = 0;
+const int LETTER_TYPE = 1;
+
+const char *font_type_table[] = {
+ "digit",
+ "letter",
+ 0,
+};
+
+struct char_info {
+ int spacing_type;
+ int font_type;
+ char_info();
+};
+
+char_info::char_info()
+: spacing_type(ORDINARY_TYPE), font_type(DIGIT_TYPE)
+{
+}
+
+static char_info char_table[256];
+
+declare_ptable(char_info)
+implement_ptable(char_info)
+
+PTABLE(char_info) special_char_table;
+
+static int get_special_char_spacing_type(const char *ch)
+{
+ char_info *p = special_char_table.lookup(ch);
+ return p ? p->spacing_type : ORDINARY_TYPE;
+}
+
+static int get_special_char_font_type(const char *ch)
+{
+ char_info *p = special_char_table.lookup(ch);
+ return p ? p->font_type : DIGIT_TYPE;
+}
+
+static void set_special_char_type(const char *ch, int st, int ft)
+{
+ char_info *p = special_char_table.lookup(ch);
+ if (!p) {
+ p = new char_info;
+ special_char_table.define(ch, p);
+ }
+ if (st >= 0)
+ p->spacing_type = st;
+ if (ft >= 0)
+ p->font_type = ft;
+}
+
+void init_char_table()
+{
+ set_special_char_type("pl", 2, -1); // binary
+ set_special_char_type("mi", 2, -1);
+ set_special_char_type("eq", 3, -1); // relation
+ set_special_char_type("<=", 3, -1);
+ set_special_char_type(">=", 3, -1);
+ char_table['}'].spacing_type = 5; // closing
+ char_table[')'].spacing_type = 5;
+ char_table[']'].spacing_type = 5;
+ char_table['{'].spacing_type = 4; // opening
+ char_table['('].spacing_type = 4;
+ char_table['['].spacing_type = 4;
+ char_table[','].spacing_type = 6; // punctuation
+ char_table[';'].spacing_type = 6;
+ char_table[':'].spacing_type = 6;
+ char_table['.'].spacing_type = 6;
+ char_table['>'].spacing_type = 3;
+ char_table['<'].spacing_type = 3;
+ char_table['*'].spacing_type = 2; // binary
+ for (int i = 0; i < 256; i++)
+ if (csalpha(i))
+ char_table[i].font_type = LETTER_TYPE;
+}
+
+static int lookup_spacing_type(const char *type)
+{
+ for (int i = 0; spacing_type_table[i] != 0; i++)
+ if (strcmp(spacing_type_table[i], type) == 0)
+ return i;
+ return -1;
+}
+
+static int lookup_font_type(const char *type)
+{
+ for (int i = 0; font_type_table[i] != 0; i++)
+ if (strcmp(font_type_table[i], type) == 0)
+ return i;
+ return -1;
+}
+
+void box::set_spacing_type(char *type)
+{
+ int t = lookup_spacing_type(type);
+ if (t < 0)
+ error("unrecognised type `%1'", type);
+ else
+ spacing_type = t;
+ a_delete type;
+}
+
+char_box::char_box(unsigned char cc)
+: c(cc), prev_is_italic(0), next_is_italic(0)
+{
+ spacing_type = char_table[c].spacing_type;
+}
+
+void char_box::hint(unsigned flags)
+{
+ if (flags & HINT_PREV_IS_ITALIC)
+ prev_is_italic = 1;
+ if (flags & HINT_NEXT_IS_ITALIC)
+ next_is_italic = 1;
+}
+
+void char_box::output()
+{
+ int font_type = char_table[c].font_type;
+ if (font_type != LETTER_TYPE)
+ printf("\\f[%s]", current_roman_font);
+ if (!prev_is_italic)
+ fputs("\\,", stdout);
+ if (c == '\\')
+ fputs("\\e", stdout);
+ else
+ putchar(c);
+ if (!next_is_italic)
+ fputs("\\/", stdout);
+ else
+ fputs("\\&", stdout); // suppress ligaturing and kerning
+ if (font_type != LETTER_TYPE)
+ fputs("\\fP", stdout);
+}
+
+int char_box::left_is_italic()
+{
+ int font_type = char_table[c].font_type;
+ return font_type == LETTER_TYPE;
+}
+
+int char_box::right_is_italic()
+{
+ int font_type = char_table[c].font_type;
+ return font_type == LETTER_TYPE;
+}
+
+int char_box::is_char()
+{
+ return 1;
+}
+
+void char_box::debug_print()
+{
+ if (c == '\\') {
+ putc('\\', stderr);
+ putc('\\', stderr);
+ }
+ else
+ putc(c, stderr);
+}
+
+special_char_box::special_char_box(const char *t)
+{
+ s = strsave(t);
+ spacing_type = get_special_char_spacing_type(s);
+}
+
+special_char_box::~special_char_box()
+{
+ a_delete s;
+}
+
+void special_char_box::output()
+{
+ int font_type = get_special_char_font_type(s);
+ if (font_type != LETTER_TYPE)
+ printf("\\f[%s]", current_roman_font);
+ printf("\\,\\[%s]\\/", s);
+ if (font_type != LETTER_TYPE)
+ printf("\\fP");
+}
+
+int special_char_box::is_char()
+{
+ return 1;
+}
+
+void special_char_box::debug_print()
+{
+ fprintf(stderr, "\\[%s]", s);
+}
+
+
+void char_box::handle_char_type(int st, int ft)
+{
+ if (st >= 0)
+ char_table[c].spacing_type = st;
+ if (ft >= 0)
+ char_table[c].font_type = ft;
+}
+
+void special_char_box::handle_char_type(int st, int ft)
+{
+ set_special_char_type(s, st, ft);
+}
+
+void set_char_type(const char *type, char *ch)
+{
+ assert(ch != 0);
+ int st = lookup_spacing_type(type);
+ int ft = lookup_font_type(type);
+ if (st < 0 && ft < 0) {
+ error("bad character type `%1'", type);
+ a_delete ch;
+ return;
+ }
+ box *b = split_text(ch);
+ b->handle_char_type(st, ft);
+ delete b;
+}
+
+/* We give primes special treatment so that in ``x' sub 2'', the ``2''
+will be tucked under the prime */
+
+class prime_box : public pointer_box {
+ box *pb;
+public:
+ prime_box(box *);
+ ~prime_box();
+ int compute_metrics(int style);
+ void output();
+ void compute_subscript_kern();
+ void debug_print();
+ void handle_char_type(int, int);
+};
+
+box *make_prime_box(box *pp)
+{
+ return new prime_box(pp);
+}
+
+prime_box::prime_box(box *pp) : pointer_box(pp)
+{
+ pb = new special_char_box("fm");
+}
+
+prime_box::~prime_box()
+{
+ delete pb;
+}
+
+int prime_box::compute_metrics(int style)
+{
+ int res = p->compute_metrics(style);
+ pb->compute_metrics(style);
+ printf(".nr " WIDTH_FORMAT " 0\\n[" WIDTH_FORMAT "]"
+ "+\\n[" WIDTH_FORMAT "]\n",
+ uid, p->uid, pb->uid);
+ printf(".nr " HEIGHT_FORMAT " \\n[" HEIGHT_FORMAT "]"
+ ">?\\n[" HEIGHT_FORMAT "]\n",
+ uid, p->uid, pb->uid);
+ printf(".nr " DEPTH_FORMAT " \\n[" DEPTH_FORMAT "]"
+ ">?\\n[" DEPTH_FORMAT "]\n",
+ uid, p->uid, pb->uid);
+ return res;
+}
+
+void prime_box::compute_subscript_kern()
+{
+ p->compute_subscript_kern();
+ printf(".nr " SUB_KERN_FORMAT " 0\\n[" WIDTH_FORMAT "]"
+ "+\\n[" SUB_KERN_FORMAT "]>?0\n",
+ uid, pb->uid, p->uid);
+}
+
+void prime_box::output()
+{
+ p->output();
+ pb->output();
+}
+
+void prime_box::handle_char_type(int st, int ft)
+{
+ p->handle_char_type(st, ft);
+ pb->handle_char_type(st, ft);
+}
+
+void prime_box::debug_print()
+{
+ p->debug_print();
+ putc('\'', stderr);
+}
+
+box *split_text(char *text)
+{
+ list_box *lb = 0;
+ box *fb = 0;
+ char *s = text;
+ while (*s != '\0') {
+ char c = *s++;
+ box *b = 0;
+ switch (c) {
+ case '+':
+ b = new special_char_box("pl");
+ break;
+ case '-':
+ b = new special_char_box("mi");
+ break;
+ case '=':
+ b = new special_char_box("eq");
+ break;
+ case '\'':
+ b = new special_char_box("fm");
+ break;
+ case '<':
+ if (*s == '=') {
+ b = new special_char_box("<=");
+ s++;
+ break;
+ }
+ goto normal_char;
+ case '>':
+ if (*s == '=') {
+ b = new special_char_box(">=");
+ s++;
+ break;
+ }
+ goto normal_char;
+ case '\\':
+ if (*s == '\0') {
+ lex_error("bad escape");
+ break;
+ }
+ c = *s++;
+ switch (c) {
+ case '(':
+ {
+ char buf[3];
+ if (*s != '\0') {
+ buf[0] = *s++;
+ if (*s != '\0') {
+ buf[1] = *s++;
+ buf[2] = '\0';
+ b = new special_char_box(buf);
+ }
+ else {
+ lex_error("bad escape");
+ }
+ }
+ else {
+ lex_error("bad escape");
+ }
+ }
+ break;
+ case '[':
+ {
+ char *ch = s;
+ while (*s != ']' && *s != '\0')
+ s++;
+ if (*s == '\0')
+ lex_error("bad escape");
+ else {
+ *s++ = '\0';
+ b = new special_char_box(ch);
+ }
+ }
+ break;
+ case 'f':
+ case 'g':
+ case 'k':
+ case 'n':
+ case '*':
+ {
+ char *escape_start = s - 2;
+ switch (*s) {
+ case '(':
+ if (*++s != '\0')
+ ++s;
+ break;
+ case '[':
+ for (++s; *s != '\0' && *s != ']'; s++)
+ ;
+ break;
+ }
+ if (*s == '\0')
+ lex_error("bad escape");
+ else {
+ ++s;
+ char *buf = new char[s - escape_start + 1];
+ memcpy(buf, escape_start, s - escape_start);
+ buf[s - escape_start] = '\0';
+ b = new quoted_text_box(buf);
+ }
+ }
+ break;
+ case '-':
+ case '_':
+ {
+ char buf[2];
+ buf[0] = c;
+ buf[1] = '\0';
+ b = new special_char_box(buf);
+ }
+ break;
+ case '`':
+ b = new special_char_box("ga");
+ break;
+ case '\'':
+ b = new special_char_box("aa");
+ break;
+ case 'e':
+ case '\\':
+ b = new char_box('\\');
+ break;
+ case '^':
+ case '|':
+ case '0':
+ {
+ char buf[3];
+ buf[0] = '\\';
+ buf[1] = c;
+ buf[2] = '\0';
+ b = new quoted_text_box(strsave(buf));
+ break;
+ }
+ default:
+ lex_error("unquoted escape");
+ b = new quoted_text_box(strsave(s - 2));
+ s = strchr(s, '\0');
+ break;
+ }
+ break;
+ default:
+ normal_char:
+ b = new char_box(c);
+ break;
+ }
+ while (*s == '\'') {
+ if (b == 0)
+ b = new quoted_text_box(0);
+ b = new prime_box(b);
+ s++;
+ }
+ if (b != 0) {
+ if (lb != 0)
+ lb->append(b);
+ else if (fb != 0) {
+ lb = new list_box(fb);
+ lb->append(b);
+ }
+ else
+ fb = b;
+ }
+ }
+ delete text;
+ if (lb != 0)
+ return lb;
+ else if (fb != 0)
+ return fb;
+ else
+ return new quoted_text_box(0);
+}
+
diff --git a/gnu/usr.bin/groff/font/Makefile.dev b/gnu/usr.bin/groff/font/Makefile.dev
new file mode 100644
index 0000000..2aa71f8
--- /dev/null
+++ b/gnu/usr.bin/groff/font/Makefile.dev
@@ -0,0 +1,27 @@
+# @(#)Makefile.dev 6.2 (Berkeley) 3/16/91
+
+# Client Makefiles define DEVICE and FONTFILES and provide rules for
+# individual font files
+
+.include "../Makefile.cfg"
+
+FONTDIR?= /usr/share/groff_font
+DEVICEDIR?= $(FONTDIR)/dev$(DEVICE)
+FONTOWN?= bin
+FONTGRP?= bin
+FONTMODE?= 444
+
+all: $(FONTFILES)
+
+.for f in $(FONTFILES)
+.if exists($f)
+beforeinstall: $f
+.else
+beforeinstall: $(.CURDIR)/$f
+.endif
+.endfor
+beforeinstall:
+ $(INSTALL) -c -o $(FONTOWN) -g $(FONTGRP) -m $(FONTMODE) \
+ ${.ALLSRC} $(DESTDIR)$(DEVICEDIR)
+
+.include <bsd.prog.mk>
diff --git a/gnu/usr.bin/groff/font/Makefile.tty b/gnu/usr.bin/groff/font/Makefile.tty
new file mode 100644
index 0000000..95cd6ca
--- /dev/null
+++ b/gnu/usr.bin/groff/font/Makefile.tty
@@ -0,0 +1,53 @@
+# @(#)Makefile.tty 6.1 (Berkeley) 3/3/91
+#
+# Modified for Berkeley Unix by Donn Seeley, donn@okeeffe.berkeley.edu
+#
+#Copyright (C) 1989, 1990 Free Software Foundation, Inc.
+# Written by James Clark (jjc@jclark.uucp)
+#
+#This file is part of groff.
+#
+#groff is free software; you can redistribute it and/or modify it under
+#the terms of the GNU General Public License as published by the Free
+#Software Foundation; either version 1, or (at your option) any later
+#version.
+#
+#groff is distributed in the hope that it will be useful, but WITHOUT ANY
+#WARRANTY; without even the implied warranty of MERCHANTABILITY or
+#FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+#for more details.
+#
+#You should have received a copy of the GNU General Public License along
+#with groff; see the file LICENSE. If not, write to the Free Software
+#Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+.MAIN: all
+
+RES=240
+CPI=10
+LPI=6
+FONTS=R I B BI S L
+
+FONTFILES=$(FONTS) DESC
+CLEANFILES=$(FONTFILES)
+
+$(FONTS): R.proto
+ @${ECHO} Making $@
+ @(charwidth=`echo $(RES) / $(CPI) | bc` ; \
+ sed -e "s/^name [A-Z]*$$/name $@/" \
+ -e "s/^\\([^ ]*\\) [0-9]+ /\\1 $$charwidth /" \
+ -e "s/^spacewidth [0-9]+$$/spacewidth $$charwidth/" \
+ -e "s/^internalname .*$$/internalname $@/" \
+ -e "/^internalname/s/BI/3/" \
+ -e "/^internalname/s/B/2/" \
+ -e "/^internalname/s/I/1/" \
+ -e "/^internalname .*[^ 0-9]/d" \
+ $(.CURDIR)/R.proto >$@)
+
+DESC: DESC.proto
+ @${ECHO} Making $@
+ @sed -e "s/^res .*$$/res $(RES)/" \
+ -e "s/^hor .*$$/hor `echo $(RES) / $(CPI) | bc`/" \
+ -e "s/^vert .*$$/vert `echo $(RES) / $(LPI) | bc`/" \
+ -e "s/^fonts .*$$/fonts `set $(FONTS); echo $$#` $(FONTS)/" \
+ $(.CURDIR)/DESC.proto >$@
diff --git a/gnu/usr.bin/groff/gendef.sh b/gnu/usr.bin/groff/gendef.sh
new file mode 100644
index 0000000..e2b2575
--- /dev/null
+++ b/gnu/usr.bin/groff/gendef.sh
@@ -0,0 +1,24 @@
+# gendef filename var=val var=val
+
+file=$1
+shift
+
+defs="#define $1"
+shift
+for def
+do
+ defs="$defs
+#define $def"
+done
+
+t=/tmp/groff.$$
+
+sed -e 's/=/ /' >$t <<EOF
+$defs
+EOF
+
+test -r $file && cmp -s $t $file || cp $t $file
+
+rm -f $t
+
+exit 0
diff --git a/gnu/usr.bin/groff/grodvi/Makefile b/gnu/usr.bin/groff/grodvi/Makefile
new file mode 100644
index 0000000..de4a712
--- /dev/null
+++ b/gnu/usr.bin/groff/grodvi/Makefile
@@ -0,0 +1,13 @@
+# Makefile for grodvi
+
+PROG= grodvi
+SRCS= dvi.cc
+CFLAGS+= -I${.CURDIR}/../include
+LDADD+= ${LIBDRIVER} ${LIBGROFF} -lm
+DPADD+= ${LIBDRIVER} ${LIBGROFF} ${LIBM}
+
+MANDEPEND= grodvi.1
+CLEANFILES+= ${MANDEPEND}
+
+.include "../Makefile.cfg"
+.include <bsd.prog.mk>
diff --git a/gnu/usr.bin/groff/grodvi/Makefile.dep b/gnu/usr.bin/groff/grodvi/Makefile.dep
new file mode 100644
index 0000000..6f9489e
--- /dev/null
+++ b/gnu/usr.bin/groff/grodvi/Makefile.dep
@@ -0,0 +1,2 @@
+dvi.o : dvi.cc ../include/driver.h ../include/errarg.h ../include/error.h \
+ ../include/font.h ../include/printer.h ../include/lib.h
diff --git a/gnu/usr.bin/groff/grodvi/Makefile.sub b/gnu/usr.bin/groff/grodvi/Makefile.sub
new file mode 100644
index 0000000..a63905d
--- /dev/null
+++ b/gnu/usr.bin/groff/grodvi/Makefile.sub
@@ -0,0 +1,6 @@
+PROG=grodvi
+MAN1=grodvi.n
+XLIBS=$(LIBDRIVER) $(LIBGROFF)
+MLIB=$(LIBM)
+OBJS=dvi.o
+CCSRCS=dvi.cc
diff --git a/gnu/usr.bin/groff/grodvi/dvi.cc b/gnu/usr.bin/groff/grodvi/dvi.cc
new file mode 100644
index 0000000..6064143
--- /dev/null
+++ b/gnu/usr.bin/groff/grodvi/dvi.cc
@@ -0,0 +1,895 @@
+// -*- C++ -*-
+/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
+ Written by James Clark (jjc@jclark.com)
+
+This file is part of groff.
+
+groff is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
+
+groff is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License along
+with groff; see the file COPYING. If not, write to the Free Software
+Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "driver.h"
+
+#define DEFAULT_LINEWIDTH 40
+static int linewidth = DEFAULT_LINEWIDTH;
+
+static int draw_flag = 1;
+
+/* These values were chosen because:
+
+(MULTIPLIER*SIZESCALE)/(RES*UNITWIDTH) == 1/(2^20 * 72.27)
+
+and 57816 is an exact multiple of both 72.27*SIZESCALE and 72.
+
+The width in the groff font file is the product of MULTIPLIER and the
+width in the tfm file. */
+
+#define RES 57816
+#define RES_7227 (RES/7227)
+#define UNITWIDTH 131072
+#define SIZESCALE 100
+#define MULTIPLIER 1
+
+#define FILL_MAX 1000
+
+class dvi_font : public font {
+ dvi_font(const char *);
+public:
+ int checksum;
+ int design_size;
+ ~dvi_font();
+ void handle_unknown_font_command(const char *command, const char *arg,
+ const char *filename, int lineno);
+ static dvi_font *load_dvi_font(const char *);
+};
+
+dvi_font *dvi_font::load_dvi_font(const char *s)
+{
+ dvi_font *f = new dvi_font(s);
+ if (!f->load()) {
+ delete f;
+ return 0;
+ }
+ return f;
+}
+
+dvi_font::dvi_font(const char *nm)
+: font(nm), checksum(0), design_size(0)
+{
+}
+
+dvi_font::~dvi_font()
+{
+}
+
+void dvi_font::handle_unknown_font_command(const char *command,
+ const char *arg,
+ const char *filename, int lineno)
+{
+ char *ptr;
+ if (strcmp(command, "checksum") == 0) {
+ if (arg == 0)
+ fatal_with_file_and_line(filename, lineno,
+ "`checksum' command requires an argument");
+ checksum = int(strtol(arg, &ptr, 10));
+ if (checksum == 0 && ptr == arg) {
+ fatal_with_file_and_line(filename, lineno, "bad checksum");
+ }
+ }
+ else if (strcmp(command, "designsize") == 0) {
+ if (arg == 0)
+ fatal_with_file_and_line(filename, lineno,
+ "`designsize' command requires an argument");
+ design_size = int(strtol(arg, &ptr, 10));
+ if (design_size == 0 && ptr == arg) {
+ fatal_with_file_and_line(filename, lineno, "bad design size");
+ }
+ }
+}
+
+#define FONTS_MAX 256
+
+struct output_font {
+ dvi_font *f;
+ int point_size;
+ output_font() : f(0) { }
+};
+
+class dvi_printer : public printer {
+ FILE *fp;
+ int max_drift;
+ int byte_count;
+ int last_bop;
+ int page_count;
+ int cur_h;
+ int cur_v;
+ int end_h;
+ int max_h;
+ int max_v;
+ output_font output_font_table[FONTS_MAX];
+ font *cur_font;
+ int cur_point_size;
+ int pushed;
+ int pushed_h;
+ int pushed_v;
+ int have_pushed;
+ void preamble();
+ void postamble();
+ void define_font(int);
+ void set_font(int);
+ void possibly_begin_line();
+protected:
+ enum {
+ id_byte = 2,
+ set1 = 128,
+ put1 = 133,
+ put_rule = 137,
+ bop = 139,
+ eop = 140,
+ push = 141,
+ pop = 142,
+ right1 = 143,
+ down1 = 157,
+ fnt_num_0 = 171,
+ fnt1 = 235,
+ xxx1 = 239,
+ fnt_def1 = 243,
+ pre = 247,
+ post = 248,
+ post_post = 249,
+ filler = 223
+ };
+ int line_thickness;
+
+ void out1(int);
+ void out2(int);
+ void out3(int);
+ void out4(int);
+ void moveto(int, int);
+ void out_string(const char *);
+ void out_signed(unsigned char, int);
+ void out_unsigned(unsigned char, int);
+ void do_special(const char *);
+public:
+ dvi_printer();
+ ~dvi_printer();
+ font *make_font(const char *);
+ void begin_page(int);
+ void end_page(int);
+ void set_char(int, font *, const environment *, int w);
+ void special(char *arg, const environment *env);
+ void end_of_line();
+ void draw(int code, int *p, int np, const environment *env);
+};
+
+
+class draw_dvi_printer : public dvi_printer {
+ int output_pen_size;
+ int fill;
+ void set_line_thickness(const environment *);
+ void fill_next();
+public:
+ draw_dvi_printer();
+ ~draw_dvi_printer();
+ void draw(int code, int *p, int np, const environment *env);
+ void end_page(int);
+};
+
+dvi_printer::dvi_printer()
+: byte_count(0), last_bop(-1), page_count(0), cur_font(0), fp(stdout),
+ max_h(0), max_v(0), pushed(0), line_thickness(-1), cur_point_size(-1)
+{
+ if (font::res != RES)
+ fatal("resolution must be %1", RES);
+ if (font::unitwidth != UNITWIDTH)
+ fatal("unitwidth must be %1", UNITWIDTH);
+ if (font::hor != 1)
+ fatal("hor must be equal to 1");
+ if (font::vert != 1)
+ fatal("vert must be equal to 1");
+ if (font::sizescale != SIZESCALE)
+ fatal("sizescale must be equal to %1", SIZESCALE);
+ max_drift = font::res/1000; // this is fairly arbitrary
+ preamble();
+}
+
+dvi_printer::~dvi_printer()
+{
+ postamble();
+}
+
+
+draw_dvi_printer::draw_dvi_printer()
+: output_pen_size(-1), fill(FILL_MAX)
+{
+}
+
+draw_dvi_printer::~draw_dvi_printer()
+{
+}
+
+
+void dvi_printer::out1(int n)
+{
+ byte_count += 1;
+ putc(n & 0xff, fp);
+}
+
+void dvi_printer::out2(int n)
+{
+ byte_count += 2;
+ putc((n >> 8) & 0xff, fp);
+ putc(n & 0xff, fp);
+}
+
+void dvi_printer::out3(int n)
+{
+ byte_count += 3;
+ putc((n >> 16) & 0xff, fp);
+ putc((n >> 8) & 0xff, fp);
+ putc(n & 0xff, fp);
+}
+
+void dvi_printer::out4(int n)
+{
+ byte_count += 4;
+ putc((n >> 24) & 0xff, fp);
+ putc((n >> 16) & 0xff, fp);
+ putc((n >> 8) & 0xff, fp);
+ putc(n & 0xff, fp);
+}
+
+void dvi_printer::out_string(const char *s)
+{
+ out1(strlen(s));
+ while (*s != 0)
+ out1(*s++);
+}
+
+
+void dvi_printer::end_of_line()
+{
+ if (pushed) {
+ out1(pop);
+ pushed = 0;
+ cur_h = pushed_h;
+ cur_v = pushed_v;
+ }
+}
+
+void dvi_printer::possibly_begin_line()
+{
+ if (!pushed) {
+ have_pushed = pushed = 1;
+ pushed_h = cur_h;
+ pushed_v = cur_v;
+ out1(push);
+ }
+}
+
+int scale(int x, int z)
+{
+ int sw;
+ int a, b, c, d;
+ int alpha, beta;
+ alpha = 16*z; beta = 16;
+ while (z >= 040000000L) {
+ z /= 2; beta /= 2;
+ }
+ d = x & 255;
+ c = (x >> 8) & 255;
+ b = (x >> 16) & 255;
+ a = (x >> 24) & 255;
+ sw = (((((d * z) / 0400) + (c * z)) / 0400) + (b * z)) / beta;
+ if (a == 255)
+ sw -= alpha;
+ else
+ assert(a == 0);
+ return sw;
+}
+
+
+void dvi_printer::set_char(int index, font *f, const environment *env, int w)
+{
+ int code = f->get_code(index);
+ if (env->size != cur_point_size || f != cur_font) {
+ cur_font = f;
+ cur_point_size = env->size;
+ for (int i = 0;; i++) {
+ if (i >= FONTS_MAX) {
+ fatal("too many output fonts required");
+ }
+ if (output_font_table[i].f == 0) {
+ output_font_table[i].f = (dvi_font *)cur_font;
+ output_font_table[i].point_size = cur_point_size;
+ define_font(i);
+ }
+ if (output_font_table[i].f == cur_font
+ && output_font_table[i].point_size == cur_point_size)
+ break;
+ }
+ set_font(i);
+ }
+ int distance = env->hpos - cur_h;
+ if (env->hpos != end_h && distance != 0) {
+ out_signed(right1, distance);
+ cur_h = env->hpos;
+ }
+ else if (distance > max_drift) {
+ out_signed(right1, distance - max_drift);
+ cur_h = env->hpos - max_drift;
+ }
+ else if (distance < -max_drift) {
+ out_signed(right1, distance + max_drift);
+ cur_h = env->hpos + max_drift;
+ }
+ if (env->vpos != cur_v) {
+ out_signed(down1, env->vpos - cur_v);
+ cur_v = env->vpos;
+ }
+ possibly_begin_line();
+ end_h = env->hpos + w;
+ cur_h += scale(f->get_width(index, UNITWIDTH)/MULTIPLIER,
+ cur_point_size*RES_7227);
+ if (cur_h > max_h)
+ max_h = cur_h;
+ if (cur_v > max_v)
+ max_v = cur_v;
+ if (code >= 0 && code <= 127)
+ out1(code);
+ else
+ out_unsigned(set1, code);
+}
+
+void dvi_printer::define_font(int i)
+{
+ out_unsigned(fnt_def1, i);
+ dvi_font *f = output_font_table[i].f;
+ out4(f->checksum);
+ out4(output_font_table[i].point_size*RES_7227);
+ out4(int((double(f->design_size)/(1<<20))*RES_7227*100 + .5));
+ const char *nm = f->get_internal_name();
+ out1(0);
+ out_string(nm);
+}
+
+void dvi_printer::set_font(int i)
+{
+ if (i >= 0 && i <= 63)
+ out1(fnt_num_0 + i);
+ else
+ out_unsigned(fnt1, i);
+}
+
+void dvi_printer::out_signed(unsigned char base, int param)
+{
+ if (-128 <= param && param < 128) {
+ out1(base);
+ out1(param);
+ }
+ else if (-32768 <= param && param < 32768) {
+ out1(base+1);
+ out2(param);
+ }
+ else if (-(1 << 23) <= param && param < (1 << 23)) {
+ out1(base+2);
+ out3(param);
+ }
+ else {
+ out1(base+3);
+ out4(param);
+ }
+}
+
+void dvi_printer::out_unsigned(unsigned char base, int param)
+{
+ if (param >= 0) {
+ if (param < 256) {
+ out1(base);
+ out1(param);
+ }
+ else if (param < 65536) {
+ out1(base+1);
+ out2(param);
+ }
+ else if (param < (1 << 24)) {
+ out1(base+2);
+ out3(param);
+ }
+ else {
+ out1(base+3);
+ out4(param);
+ }
+ }
+ else {
+ out1(base+3);
+ out4(param);
+ }
+}
+
+void dvi_printer::preamble()
+{
+ out1(pre);
+ out1(id_byte);
+ out4(254000);
+ out4(font::res);
+ out4(1000);
+ out1(0);
+}
+
+void dvi_printer::postamble()
+{
+ int tem = byte_count;
+ out1(post);
+ out4(last_bop);
+ out4(254000);
+ out4(font::res);
+ out4(1000);
+ out4(max_v);
+ out4(max_h);
+ out2(have_pushed); // stack depth
+ out2(page_count);
+ int i;
+ for (i = 0; i < FONTS_MAX && output_font_table[i].f != 0; i++)
+ define_font(i);
+ out1(post_post);
+ out4(tem);
+ out1(id_byte);
+ for (i = 0; i < 4 || byte_count % 4 != 0; i++)
+ out1(filler);
+}
+
+void dvi_printer::begin_page(int i)
+{
+ page_count++;
+ int tem = byte_count;
+ out1(bop);
+ out4(i);
+ for (int j = 1; j < 10; j++)
+ out4(0);
+ out4(last_bop);
+ last_bop = tem;
+ // By convention position (0,0) in a dvi file is placed at (1in, 1in).
+ cur_h = font::res;
+ cur_v = font::res;
+ end_h = 0;
+}
+
+void dvi_printer::end_page(int)
+{
+ if (pushed)
+ end_of_line();
+ out1(eop);
+ cur_font = 0;
+}
+
+void draw_dvi_printer::end_page(int len)
+{
+ dvi_printer::end_page(len);
+ output_pen_size = -1;
+}
+
+void dvi_printer::do_special(const char *s)
+{
+ int len = strlen(s);
+ if (len == 0)
+ return;
+ possibly_begin_line();
+ out_unsigned(xxx1, len);
+ while (*s)
+ out1(*s++);
+}
+
+void dvi_printer::special(char *arg, const environment *env)
+{
+ moveto(env->hpos, env->vpos);
+ do_special(arg);
+}
+
+void dvi_printer::moveto(int h, int v)
+{
+ if (h != cur_h) {
+ out_signed(right1, h - cur_h);
+ cur_h = h;
+ if (cur_h > max_h)
+ max_h = cur_h;
+ }
+ if (v != cur_v) {
+ out_signed(down1, v - cur_v);
+ cur_v = v;
+ if (cur_v > max_v)
+ max_v = cur_v;
+ }
+ end_h = 0;
+}
+
+void dvi_printer::draw(int code, int *p, int np, const environment *env)
+{
+ if (code == 'l') {
+ int x, y;
+ int height = 0, width;
+ int thickness;
+ if (line_thickness < 0)
+ thickness = env->size*RES_7227*linewidth/1000;
+ else if (line_thickness > 0)
+ thickness = line_thickness;
+ else
+ thickness = 1;
+ if (np != 2) {
+ error("2 arguments required for line");
+ }
+ else if (p[0] == 0) {
+ // vertical rule
+ if (p[1] > 0) {
+ x = env->hpos - thickness/2;
+ y = env->vpos + p[1] + thickness/2;
+ height = p[1] + thickness;
+ width = thickness;
+ }
+ else if (p[1] < 0) {
+ x = env->hpos - thickness/2;
+ y = env->vpos + thickness/2;
+ height = thickness - p[1];
+ width = thickness;
+ }
+ }
+ else if (p[1] == 0) {
+ if (p[0] > 0) {
+ x = env->hpos - thickness/2;
+ y = env->vpos + thickness/2;
+ height = thickness;
+ width = p[0] + thickness;
+ }
+ else if (p[0] < 0) {
+ x = env->hpos - p[0] - thickness/2;
+ y = env->vpos + thickness/2;
+ height = thickness;
+ width = thickness - p[0];
+ }
+ }
+ if (height != 0) {
+ moveto(x, y);
+ out1(put_rule);
+ out4(height);
+ out4(width);
+ }
+ }
+ else if (code == 't') {
+ if (np == 0) {
+ line_thickness = -1;
+ }
+ else {
+ // troff gratuitously adds an extra 0
+ if (np != 1 && np != 2)
+ error("0 or 1 argument required for thickness");
+ else
+ line_thickness = p[0];
+ }
+ }
+ else if (code == 'R') {
+ if (np != 2)
+ error("2 arguments required for rule");
+ else if (p[0] != 0 || p[1] != 0) {
+ int dh = p[0];
+ int dv = p[1];
+ int oh = env->hpos;
+ int ov = env->vpos;
+ if (dv > 0) {
+ ov += dv;
+ dv = -dv;
+ }
+ if (dh < 0) {
+ oh += dh;
+ dh = -dh;
+ }
+ moveto(oh, ov);
+ out1(put_rule);
+ out4(-dv);
+ out4(dh);
+ }
+ }
+}
+
+// XXX Will this overflow?
+
+inline int milliinches(int n)
+{
+ return (n*1000 + font::res/2)/font::res;
+}
+
+void draw_dvi_printer::set_line_thickness(const environment *env)
+{
+ int desired_pen_size
+ = milliinches(line_thickness < 0
+ // Will this overflow?
+ ? env->size*RES_7227*linewidth/1000
+ : line_thickness);
+ if (desired_pen_size != output_pen_size) {
+ char buf[256];
+ sprintf(buf, "pn %d", desired_pen_size);
+ do_special(buf);
+ output_pen_size = desired_pen_size;
+ }
+}
+
+void draw_dvi_printer::fill_next()
+{
+ char buf[256];
+ sprintf(buf, "sh %.3f", double(fill)/FILL_MAX);
+ do_special(buf);
+}
+
+void draw_dvi_printer::draw(int code, int *p, int np, const environment *env)
+{
+ char buf[1024];
+ int fill_flag = 0;
+ switch (code) {
+ case 'C':
+ fill_flag = 1;
+ // fall through
+ case 'c':
+ // troff adds an extra argument to C
+ if (np != 1 && !(code == 'C' && np == 2)) {
+ error("1 argument required for circle");
+ break;
+ }
+ moveto(env->hpos+p[0]/2, env->vpos);
+ if (fill_flag)
+ fill_next();
+ else
+ set_line_thickness(env);
+ int rad;
+ rad = milliinches(p[0]/2);
+ sprintf(buf, "%s 0 0 %d %d 0 6.28319",
+ (fill_flag ? "ia" : "ar"),
+ rad,
+ rad);
+ do_special(buf);
+ break;
+ case 'l':
+ if (np != 2) {
+ error("2 arguments required for line");
+ break;
+ }
+ moveto(env->hpos, env->vpos);
+ set_line_thickness(env);
+ do_special("pa 0 0");
+ sprintf(buf, "pa %d %d", milliinches(p[0]), milliinches(p[1]));
+ do_special(buf);
+ do_special("fp");
+ break;
+ case 'E':
+ fill_flag = 1;
+ // fall through
+ case 'e':
+ if (np != 2) {
+ error("2 arguments required for ellipse");
+ break;
+ }
+ moveto(env->hpos+p[0]/2, env->vpos);
+ if (fill_flag)
+ fill_next();
+ sprintf(buf, "%s 0 0 %d %d 0 6.28319",
+ (fill_flag ? "ia" : "ar"),
+ milliinches(p[0]/2),
+ milliinches(p[1]/2));
+ do_special(buf);
+ break;
+ case 'P':
+ fill_flag = 1;
+ // fall through
+ case 'p':
+ {
+ if (np & 1) {
+ error("even number of arguments required for polygon");
+ break;
+ }
+ if (np == 0) {
+ error("no arguments for polygon");
+ break;
+ }
+ moveto(env->hpos, env->vpos);
+ if (fill_flag)
+ fill_next();
+ else
+ set_line_thickness(env);
+ do_special("pa 0 0");
+ int h = 0, v = 0;
+ for (int i = 0; i < np; i += 2) {
+ h += p[i];
+ v += p[i+1];
+ sprintf(buf, "pa %d %d", milliinches(h), milliinches(v));
+ do_special(buf);
+ }
+ do_special("pa 0 0");
+ do_special(fill_flag ? "ip" : "fp");
+ break;
+ }
+ case '~':
+ {
+ if (np & 1) {
+ error("even number of arguments required for spline");
+ break;
+ }
+ if (np == 0) {
+ error("no arguments for spline");
+ break;
+ }
+ moveto(env->hpos, env->vpos);
+ set_line_thickness(env);
+ do_special("pa 0 0");
+ int h = 0, v = 0;
+ for (int i = 0; i < np; i += 2) {
+ h += p[i];
+ v += p[i+1];
+ sprintf(buf, "pa %d %d", milliinches(h), milliinches(v));
+ do_special(buf);
+ }
+ do_special("sp");
+ break;
+ }
+ case 'a':
+ {
+ if (np != 4) {
+ error("4 arguments required for arc");
+ break;
+ }
+ set_line_thickness(env);
+ double c[2];
+ if (adjust_arc_center(p, c)) {
+ int rad = milliinches(int(sqrt(c[0]*c[0] + c[1]*c[1]) + .5));
+ moveto(env->hpos + int(c[0]), env->vpos + int(c[1]));
+ sprintf(buf, "ar 0 0 %d %d %f %f",
+ rad,
+ rad,
+ atan2(p[1] + p[3] - c[1], p[0] + p[2] - c[0]),
+ atan2(-c[1], -c[0]));
+ do_special(buf);
+ }
+ else {
+ moveto(env->hpos, env->vpos);
+ do_special("pa 0 0");
+ sprintf(buf,
+ "pa %d %d",
+ milliinches(p[0] + p[2]),
+ milliinches(p[1] + p[3]));
+ do_special(buf);
+ do_special("fp");
+ }
+ break;
+ }
+ case 't':
+ {
+ if (np == 0) {
+ line_thickness = -1;
+ }
+ else {
+ // troff gratuitously adds an extra 0
+ if (np != 1 && np != 2) {
+ error("0 or 1 argument required for thickness");
+ break;
+ }
+ line_thickness = p[0];
+ }
+ break;
+ }
+ case 'f':
+ {
+ if (np != 1 && np != 2) {
+ error("1 argument required for fill");
+ break;
+ }
+ fill = p[0];
+ if (fill < 0 || fill > FILL_MAX)
+ fill = FILL_MAX;
+ break;
+ }
+ case 'R':
+ {
+ if (np != 2) {
+ error("2 arguments required for rule");
+ break;
+ }
+ int dh = p[0];
+ if (dh == 0)
+ break;
+ int dv = p[1];
+ if (dv == 0)
+ break;
+ int oh = env->hpos;
+ int ov = env->vpos;
+ if (dv > 0) {
+ ov += dv;
+ dv = -dv;
+ }
+ if (dh < 0) {
+ oh += dh;
+ dh = -dh;
+ }
+ moveto(oh, ov);
+ out1(put_rule);
+ out4(-dv);
+ out4(dh);
+ break;
+ }
+ default:
+ error("unrecognised drawing command `%1'", char(code));
+ break;
+ }
+}
+
+font *dvi_printer::make_font(const char *nm)
+{
+ return dvi_font::load_dvi_font(nm);
+}
+
+printer *make_printer()
+{
+ if (draw_flag)
+ return new draw_dvi_printer;
+ else
+ return new dvi_printer;
+}
+
+static void usage();
+
+int main(int argc, char **argv)
+{
+ program_name = argv[0];
+ static char stderr_buf[BUFSIZ];
+ setbuf(stderr, stderr_buf);
+ int c;
+ while ((c = getopt(argc, argv, "F:vw:d")) != EOF)
+ switch(c) {
+ case 'v':
+ {
+ extern const char *version_string;
+ fprintf(stderr, "grodvi version %s\n", version_string);
+ fflush(stderr);
+ break;
+ }
+ case 'w':
+ if (sscanf(optarg, "%d", &linewidth) != 1
+ || linewidth < 0 || linewidth > 1000) {
+ error("bad line width");
+ linewidth = DEFAULT_LINEWIDTH;
+ }
+ break;
+ case 'd':
+ draw_flag = 0;
+ break;
+ case 'F':
+ font::command_line_font_dir(optarg);
+ break;
+ case '?':
+ usage();
+ break;
+ default:
+ assert(0);
+ }
+ if (optind >= argc)
+ do_file("-");
+ else {
+ for (int i = optind; i < argc; i++)
+ do_file(argv[i]);
+ }
+ delete pr;
+ return 0;
+}
+
+static void usage()
+{
+ fprintf(stderr, "usage: %s [-dv] [-F dir] [-w n] [files ...]\n",
+ program_name);
+ exit(1);
+}
diff --git a/gnu/usr.bin/groff/grodvi/grodvi.man b/gnu/usr.bin/groff/grodvi/grodvi.man
new file mode 100644
index 0000000..f51f3e7
--- /dev/null
+++ b/gnu/usr.bin/groff/grodvi/grodvi.man
@@ -0,0 +1,154 @@
+.\" -*- nroff -*-
+.ie t .ds tx T\h'-.1667m'\v'.224m'E\v'-.224m'\h'-.125m'X
+.el .ds tx TeX
+.\" Like TP, but if specified indent is more than half
+.\" the current line-length - indent, use the default indent.
+.de Tp
+.ie \\n(.$=0:((0\\$1)*2u>(\\n(.lu-\\n(.iu)) .TP
+.el .TP "\\$1"
+..
+.TH GRODVI @MAN1EXT@ "@MDATE@" "Groff Version @VERSION@"
+.SH NAME
+grodvi \- convert groff output to TeX dvi format
+.SH SYNOPSIS
+.B grodvi
+[
+.B \-dv
+] [
+.BI \-w n
+] [
+.BI \-F dir
+] [
+.IR files \|.\|.\|.
+]
+.SH DESCRIPTION
+.B grodvi
+is a driver for
+.B groff
+that produces \*(tx dvi format.
+Normally it should be run by
+.BR groff\ \-Tdvi .
+This will run
+.BR @g@troff\ \-Tdvi ;
+it will also input the macros
+.BR @MACRODIR@/tmac.dvi ;
+if the input is being preprocessed with
+.B @g@eqn
+it will also input
+.BR @FONTDIR@/devdvi/eqnchar .
+.LP
+The dvi file generated by
+.B grodvi
+can be printed by any correctly-written dvi driver.
+The troff drawing primitives are implemented
+using the tpic version 2 specials.
+If the driver does not support these, the
+.B \eD
+commands will not produce any output.
+.LP
+There is an additional drawing command available:
+.TP
+.BI \eD'R\ dh\ dv '
+Draw a rule (solid black rectangle), with one corner
+at the current position, and the diagonally opposite corner
+at the current position
+.RI +( dh , dv ).
+Afterwards the current position will be at the opposite corner. This
+produces a rule in the dvi file and so can be printed even with a
+driver that does not support the tpic specials unlike the other
+.B \eD
+commands.
+.LP
+The groff command
+.BI \eX' anything '
+is translated into the same command in the dvi file as would be
+produced by
+.BI \especial{ anything }
+in \*(tx;
+.I anything may not contain a newline.
+.LP
+Font files for
+.B grodvi
+can be created from tfm files using
+.BR tfmtodit (@MAN1EXT@).
+The font description file should contain the following
+additional commands:
+.Tp \w'\fBinternalname'u+2n
+.BI internalname\ name
+The name of the tfm file (without the
+.B .tfm
+extension) is
+.IR name .
+.TP
+.BI checksum\ n
+The checksum in the tfm file is
+.IR n .
+.TP
+.BI designsize\ n
+The designsize in the tfm file is
+.IR n .
+.LP
+These are automatically generated by
+.B tfmtodit.
+.LP
+In
+.B troff
+the
+.B \eN
+escape sequence can be used to access characters by their position
+in the corresponding tfm file;
+all characters in the tfm file can be accessed this way.
+.SH OPTIONS
+.TP
+.B \-d
+Do not use tpic specials to implement drawing commands.
+Horizontal and vertical lines will be implemented by rules.
+Other drawing commands will be ignored.
+.TP
+.B \-v
+Print the version number.
+.TP
+.BI \-w n
+Set the default line thickness to
+.I n
+thousandths of an em.
+.TP
+.BI \-F dir
+Search directory
+.IB dir /devdvi
+for font and device description files.
+.SH FILES
+.TP
+.B @FONTDIR@/devdvi/DESC
+Device description file.
+.TP
+.B @FONTDIR@/devdvi/ F
+Font description file for font
+.IR F .
+.TP
+.B @MACRODIR@/tmac.dvi
+Macros for use with
+.BR grodvi .
+.SH BUGS
+Dvi files produced by
+.B grodvi
+use a different resolution (57816 units per inch) to those produced by
+\*(tx.
+Incorrectly written drivers which assume the resolution used by \*(tx,
+rather than using the resolution specified in the dvi file will not
+work with grodvi.
+.LP
+When using the
+.B \-d
+option with boxed tables,
+vertical and horizontal lines can sometimes protrude by one pixel.
+This is a consequence of the way \*(tx requires that the heights
+and widths of rules be rounded.
+.SH "SEE ALSO"
+.BR tfmtodit (@MAN1EXT@),
+.BR groff (@MAN1EXT@),
+.BR @g@troff (@MAN1EXT@),
+.BR @g@eqn (@MAN1EXT@),
+.BR groff_out (@MAN5EXT@),
+.BR groff_font (@MAN5EXT@),
+.BR groff_char (@MAN7EXT@)
diff --git a/gnu/usr.bin/groff/groff/Makefile b/gnu/usr.bin/groff/groff/Makefile
new file mode 100644
index 0000000..9539f70
--- /dev/null
+++ b/gnu/usr.bin/groff/groff/Makefile
@@ -0,0 +1,13 @@
+# Makefile for groff
+
+PROG= groff
+SRCS= groff.cc pipeline.c
+CFLAGS+= -I${.CURDIR}/../include
+LDADD+= ${LIBGROFF} -lm
+DPADD+= ${LIBGROFF} ${LIBM}
+
+MANDEPEND= groff.1
+CLEANFILES+= ${MANDEPEND}
+
+.include "../Makefile.cfg"
+.include <bsd.prog.mk>
diff --git a/gnu/usr.bin/groff/groff/Makefile.dep b/gnu/usr.bin/groff/groff/Makefile.dep
new file mode 100644
index 0000000..e333ea2
--- /dev/null
+++ b/gnu/usr.bin/groff/groff/Makefile.dep
@@ -0,0 +1,4 @@
+groff.o : groff.cc ../include/lib.h ../include/assert.h ../include/errarg.h \
+ ../include/error.h ../include/stringclass.h ../include/cset.h \
+ ../include/font.h ../include/device.h pipeline.h ../include/defs.h
+pipeline.o : pipeline.c pipeline.h
diff --git a/gnu/usr.bin/groff/groff/Makefile.sub b/gnu/usr.bin/groff/groff/Makefile.sub
new file mode 100644
index 0000000..0acd882
--- /dev/null
+++ b/gnu/usr.bin/groff/groff/Makefile.sub
@@ -0,0 +1,8 @@
+PROG=groff
+MAN1=groff.n
+XLIBS=$(LIBGROFF)
+MLIB=$(LIBM)
+OBJS=groff.o pipeline.o
+CCSRCS=groff.cc
+CSRCS=pipeline.c
+HDRS=pipeline.h
diff --git a/gnu/usr.bin/groff/groff/groff.cc b/gnu/usr.bin/groff/groff/groff.cc
new file mode 100644
index 0000000..8ef9262
--- /dev/null
+++ b/gnu/usr.bin/groff/groff/groff.cc
@@ -0,0 +1,588 @@
+// -*- C++ -*-
+/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
+ Written by James Clark (jjc@jclark.com)
+
+This file is part of groff.
+
+groff is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
+
+groff is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License along
+with groff; see the file COPYING. If not, write to the Free Software
+Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+// A front end for groff.
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <errno.h>
+
+#include "lib.h"
+#include "assert.h"
+#include "errarg.h"
+#include "error.h"
+#include "stringclass.h"
+#include "cset.h"
+#include "font.h"
+#include "device.h"
+#include "pipeline.h"
+#include "defs.h"
+
+#define BSHELL "/bin/sh"
+#define GXDITVIEW "gxditview"
+
+// troff will be passed an argument of -rXREG=1 if the -X option is
+// specified
+#define XREG ".X"
+
+#ifndef STDLIB_H_DECLARES_PUTENV
+extern "C" {
+ int putenv(const char *);
+}
+#endif /* not STDLIB_H_DECLARES_PUTENV */
+
+const int SOELIM_INDEX = 0;
+const int REFER_INDEX = SOELIM_INDEX + 1;
+const int PIC_INDEX = REFER_INDEX + 1;
+const int TBL_INDEX = PIC_INDEX + 1;
+const int EQN_INDEX = TBL_INDEX + 1;
+const int TROFF_INDEX = EQN_INDEX + 1;
+const int POST_INDEX = TROFF_INDEX + 1;
+const int SPOOL_INDEX = POST_INDEX + 1;
+
+const int NCOMMANDS = SPOOL_INDEX + 1;
+
+class possible_command {
+ char *name;
+ string args;
+ char **argv;
+
+ void build_argv();
+public:
+ possible_command();
+ ~possible_command();
+ void set_name(const char *);
+ void set_name(const char *, const char *);
+ const char *get_name();
+ void append_arg(const char *, const char * = 0);
+ void clear_args();
+ char **get_argv();
+ void print(int is_last, FILE *fp);
+};
+
+int lflag = 0;
+char *spooler = 0;
+char *driver = 0;
+
+possible_command commands[NCOMMANDS];
+
+int run_commands();
+void print_commands();
+void append_arg_to_string(const char *arg, string &str);
+void handle_unknown_desc_command(const char *command, const char *arg,
+ const char *filename, int lineno);
+const char *basename(const char *);
+
+void usage();
+void help();
+
+int main(int argc, char **argv)
+{
+ program_name = argv[0];
+ static char stderr_buf[BUFSIZ];
+ setbuf(stderr, stderr_buf);
+ assert(NCOMMANDS <= MAX_COMMANDS);
+ string Pargs, Largs, Fargs;
+ int Vflag = 0;
+ int zflag = 0;
+ int iflag = 0;
+ int Xflag = 0;
+ int opt;
+ const char *command_prefix = getenv("GROFF_COMMAND_PREFIX");
+ if (!command_prefix)
+ command_prefix = PROG_PREFIX;
+ commands[TROFF_INDEX].set_name(command_prefix, "troff");
+ while ((opt = getopt(argc, argv,
+ "itpeRszavVhblCENXZF:m:T:f:w:W:M:d:r:n:o:P:L:"))
+ != EOF) {
+ char buf[3];
+ buf[0] = '-';
+ buf[1] = opt;
+ buf[2] = '\0';
+ switch (opt) {
+ case 'i':
+ iflag = 1;
+ break;
+ case 't':
+ commands[TBL_INDEX].set_name(command_prefix, "tbl");
+ break;
+ case 'p':
+ commands[PIC_INDEX].set_name(command_prefix, "pic");
+ break;
+ case 'e':
+ commands[EQN_INDEX].set_name(command_prefix, "eqn");
+ break;
+ case 's':
+ commands[SOELIM_INDEX].set_name(command_prefix, "soelim");
+ break;
+ case 'R':
+ commands[REFER_INDEX].set_name(command_prefix, "refer");
+ break;
+ case 'z':
+ case 'a':
+ commands[TROFF_INDEX].append_arg(buf);
+ // fall through
+ case 'Z':
+ zflag++;
+ break;
+ case 'l':
+ lflag++;
+ break;
+ case 'V':
+ Vflag++;
+ break;
+ case 'v':
+ case 'C':
+ commands[SOELIM_INDEX].append_arg(buf);
+ commands[PIC_INDEX].append_arg(buf);
+ commands[TBL_INDEX].append_arg(buf);
+ commands[EQN_INDEX].append_arg(buf);
+ commands[TROFF_INDEX].append_arg(buf);
+ break;
+ case 'N':
+ commands[EQN_INDEX].append_arg(buf);
+ break;
+ case 'h':
+ help();
+ break;
+ case 'E':
+ case 'b':
+ commands[TROFF_INDEX].append_arg(buf);
+ break;
+ case 'T':
+ if (strcmp(optarg, "Xps") == 0) {
+ warning("-TXps option is obsolete: use -X -Tps instead");
+ device = "ps";
+ Xflag++;
+ }
+ else
+ device = optarg;
+ break;
+ case 'F':
+ font::command_line_font_dir(optarg);
+ if (Fargs.length() > 0) {
+ Fargs += ':';
+ Fargs += optarg;
+ }
+ else
+ Fargs = optarg;
+ break;
+ case 'f':
+ case 'o':
+ case 'm':
+ case 'r':
+ case 'd':
+ case 'n':
+ case 'w':
+ case 'W':
+ commands[TROFF_INDEX].append_arg(buf, optarg);
+ break;
+ case 'M':
+ commands[EQN_INDEX].append_arg(buf, optarg);
+ commands[TROFF_INDEX].append_arg(buf, optarg);
+ break;
+ case 'P':
+ Pargs += optarg;
+ Pargs += '\0';
+ break;
+ case 'L':
+ append_arg_to_string(optarg, Largs);
+ break;
+ case 'X':
+ Xflag++;
+ break;
+ case '?':
+ usage();
+ break;
+ default:
+ assert(0);
+ break;
+ }
+ }
+ font::set_unknown_desc_command_handler(handle_unknown_desc_command);
+ if (!font::load_desc())
+ fatal("invalid device `%1'", device);
+ if (!driver)
+ fatal("no `postpro' command in DESC file for device `%1'", device);
+ const char *real_driver = 0;
+ if (Xflag) {
+ real_driver = driver;
+ driver = GXDITVIEW;
+ commands[TROFF_INDEX].append_arg("-r" XREG "=", "1");
+ }
+ if (driver)
+ commands[POST_INDEX].set_name(driver);
+ int gxditview_flag = driver && strcmp(basename(driver), GXDITVIEW) == 0;
+ if (gxditview_flag && argc - optind == 1) {
+ commands[POST_INDEX].append_arg("-title");
+ commands[POST_INDEX].append_arg(argv[optind]);
+ commands[POST_INDEX].append_arg("-xrm");
+ commands[POST_INDEX].append_arg("*iconName:", argv[optind]);
+ string filename_string("|");
+ append_arg_to_string(argv[0], filename_string);
+ append_arg_to_string("-Z", filename_string);
+ for (int i = 1; i < argc; i++)
+ append_arg_to_string(argv[i], filename_string);
+ filename_string += '\0';
+ commands[POST_INDEX].append_arg("-filename");
+ commands[POST_INDEX].append_arg(filename_string.contents());
+ }
+ if (gxditview_flag && Xflag) {
+ string print_string(real_driver);
+ if (spooler) {
+ print_string += " | ";
+ print_string += spooler;
+ print_string += Largs;
+ }
+ print_string += '\0';
+ commands[POST_INDEX].append_arg("-printCommand");
+ commands[POST_INDEX].append_arg(print_string.contents());
+ }
+ const char *p = Pargs.contents();
+ const char *end = p + Pargs.length();
+ while (p < end) {
+ commands[POST_INDEX].append_arg(p);
+ p = strchr(p, '\0') + 1;
+ }
+ if (gxditview_flag)
+ commands[POST_INDEX].append_arg("-");
+ if (lflag && !Xflag && spooler) {
+ commands[SPOOL_INDEX].set_name(BSHELL);
+ commands[SPOOL_INDEX].append_arg("-c");
+ Largs += '\0';
+ Largs = spooler + Largs;
+ commands[SPOOL_INDEX].append_arg(Largs.contents());
+ }
+ if (zflag) {
+ commands[POST_INDEX].set_name(0);
+ commands[SPOOL_INDEX].set_name(0);
+ }
+ commands[TROFF_INDEX].append_arg("-T", device);
+ commands[EQN_INDEX].append_arg("-T", device);
+
+ for (int first_index = 0; first_index < TROFF_INDEX; first_index++)
+ if (commands[first_index].get_name() != 0)
+ break;
+ if (optind < argc) {
+ if (argv[optind][0] == '-' && argv[optind][1] != '\0')
+ commands[first_index].append_arg("--");
+ for (int i = optind; i < argc; i++)
+ commands[first_index].append_arg(argv[i]);
+ if (iflag)
+ commands[first_index].append_arg("-");
+ }
+ if (Fargs.length() > 0) {
+ string e = "GROFF_FONT_PATH";
+ e += '=';
+ e += Fargs;
+ char *fontpath = getenv("GROFF_FONT_PATH");
+ if (fontpath && *fontpath) {
+ e += ':';
+ e += fontpath;
+ }
+ e += '\0';
+ if (putenv(strsave(e.contents())))
+ fatal("putenv failed");
+ }
+ if (Vflag) {
+ print_commands();
+ exit(0);
+ }
+ return run_commands();
+}
+
+const char *basename(const char *s)
+{
+ if (!s)
+ return 0;
+ const char *p = strrchr(s, '/');
+ return p ? p + 1 : s;
+}
+
+void handle_unknown_desc_command(const char *command, const char *arg,
+ const char *filename, int lineno)
+{
+ if (strcmp(command, "print") == 0) {
+ if (arg == 0)
+ error_with_file_and_line(filename, lineno,
+ "`print' command requires an argument");
+ else
+ spooler = strsave(arg);
+ }
+ if (strcmp(command, "postpro") == 0) {
+ if (arg == 0)
+ error_with_file_and_line(filename, lineno,
+ "`postpro' command requires an argument");
+ else {
+ for (const char *p = arg; *p; p++)
+ if (csspace(*p)) {
+ error_with_file_and_line(filename, lineno,
+ "invalid `postpro' argument `%1'"
+ ": program name required", arg);
+ return;
+ }
+ driver = strsave(arg);
+ }
+ }
+}
+
+void print_commands()
+{
+ for (int last = SPOOL_INDEX; last >= 0; last--)
+ if (commands[last].get_name() != 0)
+ break;
+ for (int i = 0; i <= last; i++)
+ if (commands[i].get_name() != 0)
+ commands[i].print(i == last, stdout);
+}
+
+// Run the commands. Return the code with which to exit.
+
+int run_commands()
+{
+ char **v[NCOMMANDS];
+ int j = 0;
+ for (int i = 0; i < NCOMMANDS; i++)
+ if (commands[i].get_name() != 0)
+ v[j++] = commands[i].get_argv();
+ return run_pipeline(j, v);
+}
+
+possible_command::possible_command()
+: name(0), argv(0)
+{
+}
+
+possible_command::~possible_command()
+{
+ a_delete name;
+ a_delete argv;
+}
+
+void possible_command::set_name(const char *s)
+{
+ a_delete name;
+ name = strsave(s);
+}
+
+void possible_command::set_name(const char *s1, const char *s2)
+{
+ a_delete name;
+ name = new char[strlen(s1) + strlen(s2) + 1];
+ strcpy(name, s1);
+ strcat(name, s2);
+}
+
+const char *possible_command::get_name()
+{
+ return name;
+}
+
+void possible_command::clear_args()
+{
+ args.clear();
+}
+
+void possible_command::append_arg(const char *s, const char *t)
+{
+ args += s;
+ if (t)
+ args += t;
+ args += '\0';
+}
+
+void possible_command::build_argv()
+{
+ if (argv)
+ return;
+ // Count the number of arguments.
+ int len = args.length();
+ int argc = 1;
+ char *p = 0;
+ if (len > 0) {
+ p = &args[0];
+ for (int i = 0; i < len; i++)
+ if (p[i] == '\0')
+ argc++;
+ }
+ // Build an argument vector.
+ argv = new char *[argc + 1];
+ argv[0] = name;
+ for (int i = 1; i < argc; i++) {
+ argv[i] = p;
+ p = strchr(p, '\0') + 1;
+ }
+ argv[argc] = 0;
+}
+
+void possible_command::print(int is_last, FILE *fp)
+{
+ build_argv();
+ if (argv[0] != 0 && strcmp(argv[0], BSHELL) == 0
+ && argv[1] != 0 && strcmp(argv[1], "-c") == 0
+ && argv[2] != 0 && argv[3] == 0)
+ fputs(argv[2], fp);
+ else {
+ fputs(argv[0], fp);
+ string str;
+ for (int i = 1; argv[i] != 0; i++) {
+ str.clear();
+ append_arg_to_string(argv[i], str);
+ put_string(str, fp);
+ }
+ }
+ if (is_last)
+ putc('\n', fp);
+ else
+ fputs(" | ", fp);
+}
+
+void append_arg_to_string(const char *arg, string &str)
+{
+ str += ' ';
+ int needs_quoting = 0;
+ int contains_single_quote = 0;
+ for (const char *p = arg; *p != '\0'; p++)
+ switch (*p) {
+ case ';':
+ case '&':
+ case '(':
+ case ')':
+ case '|':
+ case '^':
+ case '<':
+ case '>':
+ case '\n':
+ case ' ':
+ case '\t':
+ case '\\':
+ case '"':
+ case '$':
+ case '?':
+ case '*':
+ needs_quoting = 1;
+ break;
+ case '\'':
+ contains_single_quote = 1;
+ break;
+ }
+ if (contains_single_quote || arg[0] == '\0') {
+ str += '"';
+ for (p = arg; *p != '\0'; p++)
+ switch (*p) {
+ case '"':
+ case '\\':
+ case '$':
+ str += '\\';
+ // fall through
+ default:
+ str += *p;
+ break;
+ }
+ str += '"';
+ }
+ else if (needs_quoting) {
+ str += '\'';
+ str += arg;
+ str += '\'';
+ }
+ else
+ str += arg;
+}
+
+char **possible_command::get_argv()
+{
+ build_argv();
+ return argv;
+}
+
+void synopsis()
+{
+ fprintf(stderr,
+"usage: %s [-abehilpstvzCENRVXZ] [-Fdir] [-mname] [-Tdev] [-ffam] [-wname]\n"
+" [-Wname] [ -Mdir] [-dcs] [-rcn] [-nnum] [-olist] [-Parg] [-Larg]\n"
+" [files...]\n",
+ program_name);
+}
+
+void help()
+{
+ synopsis();
+ fputs("\n"
+"-h\tprint this message\n"
+"-t\tpreprocess with tbl\n"
+"-p\tpreprocess with pic\n"
+"-e\tpreprocess with eqn\n"
+"-s\tpreprocess with soelim\n"
+"-R\tpreprocess with refer\n"
+"-Tdev\tuse device dev\n"
+"-X\tuse X11 previewer rather than usual postprocessor\n"
+"-mname\tread macros tmac.name\n"
+"-dcs\tdefine a string c as s\n"
+"-rcn\tdefine a number register c as n\n"
+"-nnum\tnumber first page n\n"
+"-olist\toutput only pages in list\n"
+"-ffam\tuse fam as the default font family\n"
+"-Fdir\tsearch directory dir for device directories\n"
+"-Mdir\tsearch dir for macro files\n"
+"-v\tprint version number\n"
+"-z\tsuppress formatted output\n"
+"-Z\tdon't postprocess\n"
+"-a\tproduce ASCII description of output\n"
+"-i\tread standard input after named input files\n"
+"-wname\tenable warning name\n"
+"-Wname\tinhibit warning name\n"
+"-E\tinhibit all errors\n"
+"-b\tprint backtraces with errors or warnings\n"
+"-l\tspool the output\n"
+"-C\tenable compatibility mode\n"
+"-V\tprint commands on stdout instead of running them\n"
+"-Parg\tpass arg to the postprocessor\n"
+"-Larg\tpass arg to the spooler\n"
+"-N\tdon't allow newlines within eqn delimiters\n"
+"\n",
+ stderr);
+ exit(0);
+}
+
+void usage()
+{
+ synopsis();
+ fprintf(stderr, "%s -h gives more help\n", program_name);
+ exit(1);
+}
+
+extern "C" {
+
+void c_error(const char *format, const char *arg1, const char *arg2,
+ const char *arg3)
+{
+ error(format, arg1, arg2, arg3);
+}
+
+void c_fatal(const char *format, const char *arg1, const char *arg2,
+ const char *arg3)
+{
+ fatal(format, arg1, arg2, arg3);
+}
+
+}
diff --git a/gnu/usr.bin/groff/groff/groff.man b/gnu/usr.bin/groff/groff/groff.man
new file mode 100644
index 0000000..40961cc
--- /dev/null
+++ b/gnu/usr.bin/groff/groff/groff.man
@@ -0,0 +1,365 @@
+.\" -*- nroff -*-
+.de TQ
+.br
+.ns
+.TP \\$1
+..
+.\" Like TP, but if specified indent is more than half
+.\" the current line-length - indent, use the default indent.
+.de Tp
+.ie \\n(.$=0:((0\\$1)*2u>(\\n(.lu-\\n(.iu)) .TP
+.el .TP "\\$1"
+..
+.TH GROFF @MAN1EXT@ "@MDATE@" "Groff Version @VERSION@"
+.SH NAME
+groff \- front end for the groff document formatting system
+.SH SYNOPSIS
+.B groff
+[
+.B \-tpeszaivhblCENRVXZ
+]
+[
+.BI \-w name
+]
+[
+.BI \-W name
+]
+[
+.BI \-m name
+]
+[
+.BI \-F dir
+]
+[
+.BI \-T dev
+]
+[
+.BI \-f fam
+]
+[
+.BI \-M dir
+]
+[
+.BI \-d cs
+]
+[
+.BI \-r cn
+]
+[
+.BI \-n num
+]
+[
+.BI \-o list
+]
+[
+.BI \-P arg
+]
+[
+.IR files \|.\|.\|.\|
+]
+.SH DESCRIPTION
+.B groff
+is a front-end to the groff document formatting system.
+Normally it runs the
+.B @g@troff
+program and a postprocessor appropriate for the selected
+device.
+Available devices are:
+.TP
+.B ps
+For PostScript printers and previewers
+.TP
+.B dvi
+For TeX dvi format
+.TP
+.B X75
+For a 75 dpi X11 previewer
+.TP
+.B X100
+For a 100dpi X11 previewer
+.TP
+.B ascii
+For typewriter-like devices
+.TP
+.B latin1
+For typewriter-like devices using the ISO Latin-1 character set.
+.TP
+.B koi8-r
+For typewriter-like devices using the russian KOI8-R character set.
+.LP
+The postprocessor to be used for a device is specified by the
+.B postpro
+command in the device description file.
+This can be overridden with the
+.B \-X
+option.
+.LP
+The default device is
+.BR @DEVICE@ .
+It can optionally preprocess with any of
+.BR @g@pic ,
+.BR @g@eqn ,
+.BR @g@tbl ,
+.BR @g@refer ,
+or
+.B @g@soelim.
+.LP
+Options without an argument can be grouped behind a single
+.BR \- .
+A filename of
+.B \-
+denotes the standard input.
+.LP
+The
+.B grog
+command can be used to guess the correct groff command to use to
+format a file.
+.SH OPTIONS
+.TP
+.B \-h
+Print a help message.
+.TP
+.B \-e
+Preprocess with @g@eqn.
+.TP
+.B \-t
+Preprocess with @g@tbl.
+.TP
+.B \-p
+Preprocess with @g@pic.
+.TP
+.B \-s
+Preprocess with @g@soelim.
+.TP
+.B \-R
+Preprocess with @g@refer.
+No mechanism is provided for passing arguments to
+.B @g@refer
+because most @g@refer options have equivalent commands
+which can be included in the file.
+See
+.BR @g@refer (@MAN1EXT@)
+for more details.
+.TP
+.B \-v
+Make programs run by
+.B groff
+print out their version number.
+.TP
+.B \-V
+Print the pipeline on stdout instead of executing it.
+.TP
+.B \-z
+Suppress output from
+.BR @g@troff .
+Only error messages will be printed.
+.TP
+.B \-Z
+Do not postprocess the output of
+.BR @g@troff .
+Normally
+.B groff
+will automatically run the appropriate postprocessor.
+.TP
+.BI \-P arg
+Pass
+.I arg
+to the postprocessor.
+Each argument should be passed with a separate
+.B \-P
+option.
+Note that
+.B groff
+does not prepend
+.B \-
+to
+.I arg
+before passing it to the postprocessor.
+.TP
+.B \-l
+Send the output to a printer.
+The command used for this is specified by the
+.B print
+command in the device description file.
+.TP
+.BI \-L arg
+Pass
+.I arg
+to the spooler.
+Each argument should be passed with a separate
+.B \-L
+option.
+Note that
+.B groff
+does not prepend
+.B \-
+to
+.I arg
+before passing it to the postprocessor.
+.TP
+.BI \-T dev
+Prepare output for device
+.IR dev .
+The default device is
+.BR @DEVICE@ .
+.TP
+.B \-X
+Preview with
+.B gxditview
+instead of using the usual postprocessor.
+This is unlikely to produce good results except with
+.BR \-Tps .
+.TP
+.B \-N
+Don't allow newlines with eqn delimiters.
+This is the same as the
+.B \-N
+option in
+.BR @g@eqn .
+.TP
+.B \-a
+.TQ
+.B \-b
+.TQ
+.B \-i
+.TQ
+.B \-C
+.TQ
+.B \-E
+.TQ
+.BI \-w name
+.TQ
+.BI \-W name
+.TQ
+.BI \-m name
+.TQ
+.BI \-o list
+.TQ
+.BI \-d cs
+.TQ
+.BI \-r cn
+.TQ
+.BI \-F dir
+.TQ
+.BI \-M dir
+.TQ
+.BI \-f fam
+.TQ
+.BI \-n num
+These are as described in
+.BR @g@troff (@MAN1EXT@) .
+.SH ENVIRONMENT
+.TP
+.SM
+.B GROFF_COMMAND_PREFIX
+If this is set
+.IR X ,
+then
+.B groff
+will run
+.IB X troff
+instead of
+.BR @g@troff .
+This also applies to
+.BR tbl ,
+.BR pic ,
+.BR eqn ,
+.B refer
+and
+.BR soelim .
+It does not apply to
+.BR grops ,
+.BR grodvi ,
+.BR grotty
+and
+.BR gxditview .
+.TP
+.SM
+.B GROFF_TMAC_PATH
+A colon separated list of directories in which to search for
+macro files.
+.TP
+.SM
+.B GROFF_TYPESETTER
+Default device.
+.TP
+.SM
+.B GROFF_FONT_PATH
+A colon separated list of directories in which to search for the
+.BI dev name
+directory.
+.TP
+.SM
+.B PATH
+The search path for commands executed by
+.BR groff .
+.TP
+.SM
+.B GROFF_TMPDIR
+The directory in which temporary files will be created.
+If this is not set and
+.B
+.SM TMPDIR
+is set, temporary files will be created in that directory.
+Otherwise temporary files will be created in
+.BR /tmp .
+The
+.BR grops (@MAN1EXT@)
+and
+.BR @g@refer (@MAN1EXT@)
+commands can create temporary files.
+.SH FILES
+.Tp \w'\fB@FONTDIR@/dev\fIname\fB/DESC'u+3n
+.BI @FONTDIR@/dev name /DESC
+Device description file for device
+.IR name .
+.TP
+.BI @FONTDIR@/dev name / F
+Font file for font
+.I F
+of device
+.IR name .
+.SH AUTHOR
+James Clark <jjc@jclark.com>
+.SH BUGS
+Report bugs to bug-groff@prep.ai.mit.edu.
+Include a complete, self-contained example
+that will allow the bug to be reproduced,
+and say which version of groff you are using.
+.SH COPYRIGHT
+Copyright \(co 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
+.LP
+groff is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
+.LP
+groff is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+.LP
+You should have received a copy of the GNU General Public License along
+with groff; see the file COPYING. If not, write to the Free Software
+Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+.SH AVAILABILITY
+The most recent released version of groff is always available for
+anonymous ftp from prep.ai.mit.edu (18.71.0.38) in the directory
+pub/gnu.
+.SH "SEE ALSO"
+.\" .BR grog (@MAN1EXT@),
+.BR @g@troff (@MAN1EXT@),
+.BR @g@tbl (@MAN1EXT@),
+.BR @g@pic (@MAN1EXT@),
+.BR @g@eqn (@MAN1EXT@),
+.BR @g@soelim (@MAN1EXT@) ,
+.BR @g@refer (@MAN1EXT@),
+.BR grops (@MAN1EXT@),
+.BR grodvi (@MAN1EXT@),
+.BR grotty (@MAN1EXT@),
+.\" .BR gxditview (@MAN1EXT@),
+.BR groff_font (@MAN5EXT@),
+.BR groff_out (@MAN5EXT@),
+.BR groff_ms (@MAN7EXT@),
+.BR groff_me (@MAN7EXT@),
+.BR groff_char (@MAN7EXT@)
diff --git a/gnu/usr.bin/groff/groff/pipeline.c b/gnu/usr.bin/groff/groff/pipeline.c
new file mode 100644
index 0000000..f8be66b
--- /dev/null
+++ b/gnu/usr.bin/groff/groff/pipeline.c
@@ -0,0 +1,234 @@
+/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
+ Written by James Clark (jjc@jclark.com)
+
+This file is part of groff.
+
+groff is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
+
+groff is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License along
+with groff; see the file COPYING. If not, write to the Free Software
+Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/*
+Compile options are:
+
+-DWCOREFLAG=0200 (or whatever)
+-DHAVE_VFORK_H
+-Dvfork=fork
+-DHAVE_SYS_SIGLIST
+-DHAVE_UNISTD_H
+*/
+
+#include <stdio.h>
+#include <signal.h>
+#include <errno.h>
+#include <sys/types.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#ifdef HAVE_VFORK_H
+#include <vfork.h>
+#endif
+
+#ifndef errno
+extern int errno;
+#endif
+
+extern char *strerror();
+
+#ifdef _POSIX_VERSION
+
+#include <sys/wait.h>
+
+#define PID_T pid_t
+
+#else /* not _POSIX_VERSION */
+
+/* traditional Unix */
+
+#define WIFEXITED(s) (((s) & 0377) == 0)
+#define WIFSTOPPED(s) (((s) & 0377) == 0177)
+#define WIFSIGNALED(s) (((s) & 0377) != 0 && (((s) & 0377) != 0177))
+#define WEXITSTATUS(s) (((s) >> 8) & 0377)
+#define WTERMSIG(s) ((s) & 0177)
+#define WSTOPSIG(s) (((s) >> 8) & 0377)
+
+#ifndef WCOREFLAG
+#define WCOREFLAG 0200
+#endif
+
+#define PID_T int
+
+#endif /* not _POSIX_VERSION */
+
+/* SVR4 uses WCOREFLG; Net 2 uses WCOREFLAG. */
+#ifndef WCOREFLAG
+#ifdef WCOREFLG
+#define WCOREFLAG WCOREFLG
+#endif /* WCOREFLG */
+#endif /* not WCOREFLAG */
+
+#ifndef WCOREDUMP
+#ifdef WCOREFLAG
+#define WCOREDUMP(s) ((s) & WCOREFLAG)
+#else /* not WCOREFLAG */
+#define WCOREDUMP(s) (0)
+#endif /* WCOREFLAG */
+#endif /* not WCOREDUMP */
+
+#include "pipeline.h"
+
+#ifdef __STDC__
+#define P(parms) parms
+#else
+#define P(parms) ()
+#endif
+
+#define error c_error
+extern void error P((char *, char *, char *, char *));
+extern void c_fatal P((char *, char *, char *, char *));
+
+static void sys_fatal P((char *));
+static char *xstrsignal P((int));
+static char *itoa P((int));
+
+int run_pipeline(ncommands, commands)
+ int ncommands;
+ char ***commands;
+{
+ int i;
+ int last_input = 0;
+ PID_T pids[MAX_COMMANDS];
+ int ret = 0;
+ int proc_count = ncommands;
+
+ for (i = 0; i < ncommands; i++) {
+ int pdes[2];
+ PID_T pid;
+ if (i != ncommands - 1) {
+ if (pipe(pdes) < 0)
+ sys_fatal("pipe");
+ }
+ pid = vfork();
+ if (pid < 0)
+ sys_fatal("fork");
+ if (pid == 0) {
+ /* child */
+ if (last_input != 0) {
+ if (close(0) < 0)
+ sys_fatal("close");
+ if (dup(last_input) < 0)
+ sys_fatal("dup");
+ if (close(last_input) < 0)
+ sys_fatal("close");
+ }
+ if (i != ncommands - 1) {
+ if (close(1) < 0)
+ sys_fatal("close");
+ if (dup(pdes[1]) < 0)
+ sys_fatal("dup");
+ if (close(pdes[1]) < 0)
+ sys_fatal("close");
+ if (close(pdes[0]))
+ sys_fatal("close");
+ }
+ execvp(commands[i][0], commands[i]);
+ error("couldn't exec %1: %2", commands[i][0],
+ strerror(errno), (char *)0);
+ fflush(stderr); /* just in case error() doesn't */
+ _exit(EXEC_FAILED_EXIT_STATUS);
+ }
+ /* in the parent */
+ if (last_input != 0) {
+ if (close(last_input) < 0)
+ sys_fatal("close");
+ }
+ if (i != ncommands - 1) {
+ if (close(pdes[1]) < 0)
+ sys_fatal("close");
+ last_input = pdes[0];
+ }
+ pids[i] = pid;
+ }
+ while (proc_count > 0) {
+ int status;
+ PID_T pid = wait(&status);
+ if (pid < 0)
+ sys_fatal("wait");
+ for (i = 0; i < ncommands; i++)
+ if (pids[i] == pid) {
+ pids[i] = -1;
+ --proc_count;
+ if (WIFSIGNALED(status)) {
+ int sig = WTERMSIG(status);
+#ifdef SIGPIPE
+ if (sig == SIGPIPE) {
+ if (i == ncommands - 1) {
+
+ /* This works around a problem that occurred when using the
+ rerasterize action in gxditview. What seemed to be
+ happening (on SunOS 4.1.1) was that pclose() closed the
+ pipe and waited for groff, gtroff got a SIGPIPE, but
+ gpic blocked writing to gtroff, and so groff blocked
+ waiting for gpic and gxditview blocked waiting for
+ groff. I don't understand why gpic wasn't getting a
+ SIGPIPE. */
+ int j;
+ for (j = 0; j < ncommands; j++)
+ if (pids[j] > 0)
+ (void)kill(pids[j], SIGPIPE);
+ }
+ }
+ else
+#endif /* SIGPIPE */
+ {
+ error("%1: %2%3",
+ commands[i][0],
+ xstrsignal(sig),
+ WCOREDUMP(status) ? " (core dumped)" : "");
+ ret |= 2;
+ }
+ }
+ else if (WIFEXITED(status)) {
+ int exit_status = WEXITSTATUS(status);
+ if (exit_status == EXEC_FAILED_EXIT_STATUS)
+ ret |= 4;
+ else if (exit_status != 0)
+ ret |= 1;
+ }
+ else
+ error("unexpected status %1",
+ itoa(status), (char *)0, (char *)0);
+ break;
+ }
+ }
+ return ret;
+}
+
+static void sys_fatal(s)
+ char *s;
+{
+ c_fatal("%1: %2", s, strerror(errno), (char *)0);
+}
+
+static char *itoa(n)
+ int n;
+{
+ static char buf[12];
+ sprintf(buf, "%d", n);
+ return buf;
+}
+
+static char *xstrsignal(n)
+ int n;
+{
+ return strerror(n);
+}
diff --git a/gnu/usr.bin/groff/groff/pipeline.h b/gnu/usr.bin/groff/groff/pipeline.h
new file mode 100644
index 0000000..032b0bb
--- /dev/null
+++ b/gnu/usr.bin/groff/groff/pipeline.h
@@ -0,0 +1,30 @@
+/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
+ Written by James Clark (jjc@jclark.com)
+
+This file is part of groff.
+
+groff is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
+
+groff is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License along
+with groff; see the file COPYING. If not, write to the Free Software
+Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#ifdef __cplusplus
+extern "C" {
+ int run_pipeline(int, char ***);
+}
+#endif
+
+/* run_pipeline can handle at most this many commands */
+#define MAX_COMMANDS 10
+
+/* Children exit with this status if execvp fails. */
+#define EXEC_FAILED_EXIT_STATUS 0xff
diff --git a/gnu/usr.bin/groff/grog/Makefile.sub b/gnu/usr.bin/groff/grog/Makefile.sub
new file mode 100644
index 0000000..5b8f089
--- /dev/null
+++ b/gnu/usr.bin/groff/grog/Makefile.sub
@@ -0,0 +1,22 @@
+MAN1=grog.n
+CLEANADD=grog
+
+all: grog
+
+grog: grog.pl grog.sh
+ if test -n "$(PERLPATH)" && test -f "$(PERLPATH)"; then \
+ rm -f $@; \
+ sed -e 's;/usr/bin/perl;$(PERLPATH);' $(srcdir)/grog.pl >$@; \
+ else \
+ rm -f $@; \
+ sed "$(SH_SCRIPT_SED_CMD)" $(srcdir)/grog.sh >$@; \
+ fi
+ chmod +x $@
+
+install_data: grog
+ -test -d $(bindir) || mkdir $(bindir)
+ -rm -f $(bindir)/grog
+ $(INSTALL_PROGRAM) grog $(bindir)/grog
+
+uninstall_sub:
+ -rm -f $(bindir)/grog
diff --git a/gnu/usr.bin/groff/grog/grog.man b/gnu/usr.bin/groff/grog/grog.man
new file mode 100644
index 0000000..8264165
--- /dev/null
+++ b/gnu/usr.bin/groff/grog/grog.man
@@ -0,0 +1,54 @@
+.TH GROG @MAN1EXT@ "@MDATE@" "Groff Version @VERSION@"
+.SH NAME
+grog \- guess options for groff command
+.SH SYNOPSIS
+.B grog
+[
+.BI \- option
+\|.\|.\|.
+]
+[
+.IR files \|.\|.\|.
+]
+.SH DESCRIPTION
+.B grog
+reads
+.I files
+and guesses which of the
+.BR groff (@MAN1EXT@)
+options
+.BR \-e ,
+.BR \-man ,
+.BR \-me ,
+.BR \-mm ,
+.BR \-ms ,
+.BR \-p ,
+.BR \-s ,
+and
+.BR \-t
+are required for printing
+.IR files ,
+and prints the groff command including those options on the standard output.
+A filename of
+.B \-
+is taken to refer to the standard input.
+If no files are specified the standard input will be read.
+Any specified options will be included in the printed command.
+No space is allowed between options and their arguments.
+For example,
+.IP
+.B `grog \-Tdvi paper.ms`
+.LP
+will guess the appropriate command to print
+.B paper.ms
+and then run it after adding the
+.B \-Tdvi
+option.
+.SH "SEE ALSO"
+.BR doctype (1),
+.BR groff (@MAN1EXT@),
+.BR @g@troff (@MAN1EXT@),
+.BR @g@tbl (@MAN1EXT@),
+.BR @g@pic (@MAN1EXT@),
+.BR @g@eqn (@MAN1EXT@),
+.BR @g@soelim (@MAN1EXT@)
diff --git a/gnu/usr.bin/groff/grog/grog.pl b/gnu/usr.bin/groff/grog/grog.pl
new file mode 100644
index 0000000..b131da6
--- /dev/null
+++ b/gnu/usr.bin/groff/grog/grog.pl
@@ -0,0 +1,149 @@
+#!/usr/bin/perl
+# grog -- guess options for groff command
+# Inspired by doctype script in Kernighan & Pike, Unix Programming
+# Environment, pp 306-8.
+
+$prog = $0;
+$prog =~ s@.*/@@;
+
+push(@command, "groff");
+
+while ($ARGV[0] =~ /^-./) {
+ $arg = shift(@ARGV);
+ last if $arg eq "--";
+ push(@command, $arg);
+}
+
+if (@ARGV) {
+ foreach $arg (@ARGV) {
+ &process($arg, 0);
+ }
+}
+else {
+ &process("-", 0);
+}
+
+sub process {
+ local($filename, $level) = @_;
+ local(*FILE);
+
+ if (!open(FILE, $filename eq "-" ? $filename : "< $filename")) {
+ print STDERR "$prog: can't open \`$filename': $!\n";
+ exit 1 unless $level;
+ return;
+ }
+ while (<FILE>) {
+ if (/^\.TS/) {
+ $_ = <FILE>;
+ if (!/^\./) {
+ $tbl++;
+ $soelim++ if $level;
+ }
+ }
+ elsif (/^\.EQ/) {
+ $_ = <FILE>;
+ if (!/^\./ || /^\.[0-9]/) {
+ $eqn++;
+ $soelim++ if $level;
+ }
+ }
+ elsif (/^\.PS([ 0-9.<].*)?$/) {
+ if (/^\.PS\s*<\s*(\S+)/) {
+ $pic++;
+ $soelim++ if $level;
+ &process($1, $level);
+ }
+ else {
+ $_ = <FILE>;
+ if (!/^\./ || /^\.ps/) {
+ $pic++;
+ $soelim++ if $level;
+ }
+ }
+ }
+ elsif (/^\.R1/ || /^\.\[/) {
+ $refer++;
+ $soelim++ if $level;
+ }
+ elsif (/^\.[PLI]P/) {
+ $PP++;
+ }
+ elsif (/^\.P$/) {
+ $P++;
+ }
+ elsif (/^\.(PH|SA)/) {
+ $mm++;
+ }
+ elsif (/^\.TH/) {
+ $TH++;
+ }
+ elsif (/^\.SH/) {
+ $SH++;
+ }
+ elsif (/^\.([pnil]p|sh)/) {
+ $me++;
+ }
+ elsif (/^\.Dd/) {
+ $mdoc++;
+ }
+ elsif (/^\.(Tp|Dp|De|Cx|Cl)/) {
+ $mdoc_old = 1;
+ }
+ # In the old version of -mdoc `Oo' is a toggle, in the new it's
+ # closed by `Oc'.
+ elsif (/^\.Oo/) {
+ $Oo++;
+ }
+ elsif (/^\.Oc/) {
+ $Oo--;
+ }
+ if (/^\.so/) {
+ chop;
+ s/^.so *//;
+ s/\\\".*//;
+ s/ .*$//;
+ &process($_, $level + 1) unless /\\/ || $_ eq "";
+ }
+ }
+ close(FILE);
+}
+
+if ($pic || $tbl || $eqn || $refer) {
+ $s = "-";
+ $s .= "s" if $soelim;
+ $s .= "R" if $refer;
+ $s .= "p" if $pic;
+ $s .= "t" if $tbl;
+ $s .= "e" if $eqn;
+ push(@command, $s);
+}
+
+if ($me > 0) {
+ push(@command, "-me");
+}
+elsif ($SH > 0 && $TH > 0) {
+ push(@command, "-man");
+}
+elsif ($PP > 0) {
+ push(@command, "-ms");
+}
+elsif ($P > 0 || $mm > 0) {
+ push(@command, "-mm");
+}
+elsif ($mdoc > 0) {
+ push(@command, ($mdoc_old || $Oo > 0) ? "-mdoc.old" : "-mdoc");
+}
+
+push(@command, "--") if @ARGV && $ARGV[0] =~ /^-./;
+
+push(@command, @ARGV);
+
+# We could implement an option to execute the command here.
+
+foreach (@command) {
+ next unless /[\$\\\"\';&()|<> \t\n]/;
+ s/\'/\'\\\'\'/;
+ $_ = "'" . $_ . "'";
+}
+
+print join(' ', @command), "\n";
diff --git a/gnu/usr.bin/groff/grog/grog.sh b/gnu/usr.bin/groff/grog/grog.sh
new file mode 100644
index 0000000..755c891
--- /dev/null
+++ b/gnu/usr.bin/groff/grog/grog.sh
@@ -0,0 +1,78 @@
+#!/bin/sh
+# grog -- guess options for groff command
+# Like doctype in Kernighan & Pike, Unix Programming Environment, pp 306-8.
+
+soelim=gsoelim
+
+opts=
+
+for arg
+do
+ case "$arg" in
+ --)
+ shift; break;;
+ -)
+ break;;
+ -*)
+ opts="$opts $arg"; shift;;
+ *)
+ break;;
+ esac
+done
+
+egrep -h '^\.(P|[LI]P|[pnil]p|sh|Dd|Tp|Dp|De|Cx|Cl|Oo|Oc|TS|EQ|TH|SH|so|\[|R1|PH|SA)' $* \
+| sed -e '/^\.so/s/^.*$/.SO_START\
+&\
+.SO_END/' \
+| $soelim \
+| egrep '^\.(P|[LI]P|[pnil]p|sh|Dd|Tp|Dp|De|Cx|Cl|Oo|Oc|TS|EQ|TH|SH|\[|R1|PH|SA|SO_START|SO_END)' \
+| awk '
+/^\.SO_START$/ { so = 1 }
+/^\.SO_END$/ { so = 0 }
+/^\.TS/ { tbl++; if (so > 0) soelim++ }
+/^\.PS([ 0-9.<].*)?$/ { pic++; if (so > 0) soelim++ }
+/^\.EQ/ { eqn++; if (so > 0) soelim++ }
+/^\.(R1|\[)/ { refer++; if (so > 0) soelim++ }
+/^\.TH/ { TH++ }
+/^\.[PLI]P/ { PP++ }
+/^\.P$/ { P++ }
+/^\.SH/ { SH++ }
+/^\.(PH|SA)/ { mm++ }
+/^\.([pnil]p|sh)/ { me++ }
+/^\.Dd/ { mdoc++ }
+/^\.(Tp|Dp|De|Cx|Cl)/ { mdoc_old++ }
+/^\.Oo/ { Oo++ }
+/^\.Oc/ { Oo-- }
+
+END {
+ if (files ~ /^-/)
+ files = "-- " files
+ printf "groff"
+ if (pic > 0 || tbl > 0 || eqn > 0 || refer > 0) {
+ printf " -"
+ if (soelim > 0) printf "s"
+ if (refer > 0) printf "R"
+ if (pic > 0) printf "p"
+ if (tbl > 0) printf "t"
+ if (eqn > 0) printf "e"
+ }
+ if (me > 0)
+ printf " -me"
+ else if (SH > 0 && TH > 0)
+ printf " -man"
+ else if (PP > 0)
+ printf " -ms"
+ else if (P > 0 || mm > 0)
+ printf " -mm"
+ else if (mdoc > 0) {
+ if (mdoc_old > 0 || Oo > 0)
+ printf " -mdoc.old"
+ else
+ printf " -mdoc"
+ }
+ if (opts != "")
+ printf "%s", opts
+ if (files != "")
+ printf " %s", files
+ print
+}' "opts=$opts" "files=$*" -
diff --git a/gnu/usr.bin/groff/grops/Makefile b/gnu/usr.bin/groff/grops/Makefile
new file mode 100644
index 0000000..7b68bc1
--- /dev/null
+++ b/gnu/usr.bin/groff/grops/Makefile
@@ -0,0 +1,13 @@
+# Makefile for grops
+
+PROG= grops
+SRCS= ps.cc psrm.cc
+CFLAGS+= -I${.CURDIR}/../include
+LDADD+= ${LIBDRIVER} ${LIBGROFF} -lm
+DPADD+= ${LIBDRIVER} ${LIBGROFF} ${LIBM}
+
+MANDEPEND= grops.1
+CLEANFILES+= ${MANDEPEND}
+
+.include "../Makefile.cfg"
+.include <bsd.prog.mk>
diff --git a/gnu/usr.bin/groff/grops/Makefile.dep b/gnu/usr.bin/groff/grops/Makefile.dep
new file mode 100644
index 0000000..2320a9e
--- /dev/null
+++ b/gnu/usr.bin/groff/grops/Makefile.dep
@@ -0,0 +1,6 @@
+ps.o : ps.cc ../include/driver.h ../include/errarg.h ../include/error.h \
+ ../include/font.h ../include/printer.h ../include/lib.h \
+ ../include/stringclass.h ../include/cset.h ps.h
+psrm.o : psrm.cc ../include/driver.h ../include/errarg.h ../include/error.h \
+ ../include/font.h ../include/printer.h ../include/lib.h \
+ ../include/stringclass.h ../include/cset.h ps.h
diff --git a/gnu/usr.bin/groff/grops/Makefile.sub b/gnu/usr.bin/groff/grops/Makefile.sub
new file mode 100644
index 0000000..891472b
--- /dev/null
+++ b/gnu/usr.bin/groff/grops/Makefile.sub
@@ -0,0 +1,7 @@
+PROG=grops
+MAN1=grops.n
+XLIBS=$(LIBDRIVER) $(LIBGROFF)
+MLIB=$(LIBM)
+OBJS=ps.o psrm.o
+CCSRCS=ps.cc psrm.cc
+HDRS=ps.h
diff --git a/gnu/usr.bin/groff/grops/TODO b/gnu/usr.bin/groff/grops/TODO
new file mode 100644
index 0000000..da67973
--- /dev/null
+++ b/gnu/usr.bin/groff/grops/TODO
@@ -0,0 +1,29 @@
+Read PFB files directly.
+
+Generate %%DocumentMedia comment.
+
+Generate %%For comment.
+
+Generate %%Title comment.
+
+For efficiency it might be better to have the printer interface have
+support for the t and u commands.
+
+Angles in arc command: don't generate more digits after the decimal
+point than are necessary.
+
+Possibly generate BoundingBox comment.
+
+Per font composite character mechanism (sufficient for fractions).
+
+Consider whether we ought to do rounding of graphical objects other
+than lines. What's the point?
+
+Error messages should refer to output page number.
+
+Search for downloadable fonts using their PostScript names if not
+found in download file.
+
+Separate path for searching for downloadable font files.
+
+Clip to the BoundingBox when importing documents.
diff --git a/gnu/usr.bin/groff/grops/grops.man b/gnu/usr.bin/groff/grops/grops.man
new file mode 100644
index 0000000..1f4947e
--- /dev/null
+++ b/gnu/usr.bin/groff/grops/grops.man
@@ -0,0 +1,817 @@
+.\" -*- nroff -*-
+.\" Like TP, but if specified indent is more than half
+.\" the current line-length - indent, use the default indent.
+.de Tp
+.ie \\n(.$=0:((0\\$1)*2u>(\\n(.lu-\\n(.iu)) .TP
+.el .TP "\\$1"
+..
+.TH GROPS @MAN1EXT@ "@MDATE@" "Groff Version @VERSION@"
+.SH NAME
+grops \- PostScript driver for groff
+.SH SYNOPSIS
+.B grops
+[
+.B \-glv
+] [
+.BI \-b n
+] [
+.BI \-c n
+] [
+.BI \-w n
+] [
+.BI \-F dir
+] [
+.IR files \|.\|.\|.
+]
+.SH DESCRIPTION
+.B grops
+translates the output of GNU
+.B troff
+to PostScript.
+Normally
+.B grops
+should be invoked by using the groff command
+with a
+.B \-Tps
+option.
+.if '@DEVICE@'ps' (Actually, this is the default for groff.)
+If no files are given,
+.B grops
+will read the standard input.
+A filename of
+.B \-
+will also cause
+.B grops
+to read the standard input.
+PostScript output is written to the standard output.
+When
+.B grops
+is run by
+.B groff
+options can be passed to
+.B grops
+using the
+.B groff
+.B \-P
+option.
+.SH OPTIONS
+.TP
+.BI \-b n
+Workaround broken spoolers and previewers.
+Normally
+.B grops
+produces output that conforms
+the Document Structuring Conventions version 3.0.
+Unfortunately some spoolers and previewers can't handle such output.
+The value of
+.I n
+controls what
+.B grops
+does to its output acceptable to such programs.
+A value of 0 will cause grops not to employ any workarounds.
+Add 1 if no
+.B %%BeginDocumentSetup
+and
+.B %%EndDocumentSetup
+comments should be generated;
+this is needed for early versions of TranScript that get confused by
+anything between the
+.B %%EndProlog
+comment and the first
+.B %%Page
+comment.
+Add 2 if lines in included files beginning with
+.B %!
+should be stripped out; this is needed for Sun's pageview previewer.
+Add 4 if
+.BR %%Page ,
+.BR %%Trailer
+and
+.B %%EndProlog
+comments should be
+stripped out of included files; this is needed for spoolers that
+don't understand the
+.B %%BeginDocument
+and
+.B %%EndDocument
+comments.
+Add 8 if the first line of the PostScript output should be
+.B %!PS-Adobe-2.0
+rather than
+.BR %!PS-Adobe-3.0 ;
+this is needed when using Sun's Newsprint with a printer that requires
+page reversal.
+The default value can be specified by a
+.RS
+.IP
+.BI broken\ n
+.LP
+command in the DESC file.
+Otherwise the default value is 0.
+.RE
+.TP
+.BI \-c n
+Print
+.I n
+copies of each page.
+.TP
+.BI \-g
+Guess the page length.
+This generates PostScript code that guesses the page length.
+The guess will be correct only if the imageable area is vertically
+centered on the page.
+This option allows you to generate documents that can be printed
+both on letter (8.5\(mu11) paper and on A4 paper without change.
+.TP
+.BI \-l
+Print the document in landscape format.
+.TP
+.BI \-F dir
+Search the directory
+.IB dir /dev name
+for font and device description files;
+.I name
+is the name of the device, usually
+.BR ps .
+.TP
+.BI \-w n
+Lines should be drawn using a thickness of
+.I n
+thousandths of an em.
+.TP
+.B \-v
+Print the version number.
+.SH USAGE
+There are styles called
+.BR R ,
+.BR I ,
+.BR B ,
+and
+.B BI
+mounted at font positions 1 to 4.
+The fonts are grouped into families
+.BR A ,
+.BR BM ,
+.BR C ,
+.BR H ,
+.BR HN ,
+.BR N ,
+.B P
+and
+.B T
+having members in each of these styles:
+.de FT
+.if '\\*(.T'ps' .ft \\$1
+..
+.TP
+.B AR
+.FT AR
+AvantGarde-Book
+.FT
+.TP
+.B AI
+.FT AI
+AvantGarde-BookOblique
+.FT
+.TP
+.B AB
+.FT AB
+AvantGarde-Demi
+.FT
+.TP
+.B ABI
+.FT ABI
+AvantGarde-DemiOblique
+.FT
+.TP
+.B BMR
+.FT BMR
+Bookman-Light
+.FT
+.TP
+.B BMI
+.FT BMI
+Bookman-LightItalic
+.FT
+.TP
+.B BMB
+.FT BMB
+Bookman-Demi
+.FT
+.TP
+.B BMBI
+.FT BMBI
+Bookman-DemiItalic
+.FT
+.TP
+.B CR
+.FT CR
+Courier
+.FT
+.TP
+.B CI
+.FT CI
+Courier-Oblique
+.FT
+.TP
+.B CB
+.FT CB
+Courier-Bold
+.FT
+.TP
+.B CBI
+.FT CBI
+Courier-BoldOblique
+.FT
+.TP
+.B HR
+.FT HR
+Helvetica
+.FT
+.TP
+.B HI
+.FT HI
+Helvetica-Oblique
+.FT
+.TP
+.B HB
+.FT HB
+Helvetica-Bold
+.FT
+.TP
+.B HBI
+.FT HBI
+Helvetica-BoldOblique
+.FT
+.TP
+.B HNR
+.FT HNR
+Helvetica-Narrow
+.FT
+.TP
+.B HNI
+.FT HNI
+Helvetica-Narrow-Oblique
+.FT
+.TP
+.B HNB
+.FT HNB
+Helvetica-Narrow-Bold
+.FT
+.TP
+.B HNBI
+.FT HNBI
+Helvetica-Narrow-BoldOblique
+.FT
+.TP
+.B NR
+.FT NR
+NewCenturySchlbk-Roman
+.FT
+.TP
+.B NI
+.FT NI
+NewCenturySchlbk-Italic
+.FT
+.TP
+.B NB
+.FT NB
+NewCenturySchlbk-Bold
+.FT
+.TP
+.B NBI
+.FT NBI
+NewCenturySchlbk-BoldItalic
+.FT
+.TP
+.B PR
+.FT PR
+Palatino-Roman
+.FT
+.TP
+.B PI
+.FT PI
+Palatino-Italic
+.FT
+.TP
+.B PB
+.FT PB
+Palatino-Bold
+.FT
+.TP
+.B PBI
+.FT PBI
+Palatino-BoldItalic
+.FT
+.TP
+.B TR
+.FT TR
+Times-Roman
+.FT
+.TP
+.B TI
+.FT TI
+Times-Italic
+.FT
+.TP
+.B TB
+.FT TB
+Times-Bold
+.FT
+.TP
+.B TBI
+.FT TBI
+Times-BoldItalic
+.FT
+.LP
+There is also the following font which is not a member of a family:
+.TP
+.B ZCMI
+.FT ZCMI
+ZapfChancery-MediumItalic
+.FT
+.LP
+There are also some special fonts called
+.B SS
+and
+.BR S .
+Zapf Dingbats is available as
+.BR ZD
+and a reversed version of ZapfDingbats (with symbols pointing in the opposite
+direction) is available as
+.BR ZDR ;
+most characters in these fonts are unnamed and must be accessed using
+.BR \eN .
+.LP
+.B grops
+understands various X commands produced using the
+.B \eX
+escape sequence;
+.B grops
+will only interpret commands that begin with a
+.B ps:
+tag.
+.TP
+.BI \eX'ps:\ exec\ code '
+This executes the arbitrary PostScript commands in
+.IR code .
+The PostScript currentpoint will be set to the position of the
+.B \eX
+command before executing
+.IR code .
+The origin will be at the top left corner of the page,
+and y coordinates will increase down the page.
+A procedure
+.B u
+will be defined that converts groff units
+to the coordinate system in effect.
+For example,
+.RS
+.IP
+.B
+\&.nr x 1i
+.br
+.B
+\eX'ps: exec \enx u 0 rlineto stroke'
+.br
+.RE
+.IP
+will draw a horizontal line one inch long.
+.I code
+may make changes to the graphics state,
+but any changes will persist only to the
+end of the page.
+A dictionary containing the definitions specified by the
+.B def
+and
+.B mdef
+will be on top of the dictionary stack.
+If your code adds definitions to this dictionary,
+you should allocate space for them using
+.BI \eX'ps\ mdef \ n '\fR.
+Any definitions will persist only until the end of the page.
+If you use the
+.B \eY
+escape sequence with an argument that names a macro,
+.I code
+can extend over multiple lines.
+For example,
+.RS
+.IP
+.nf
+.ft B
+\&.nr x 1i
+\&.de y
+\&ps: exec
+\&\enx u 0 rlineto
+\&stroke
+\&..
+\&\eYy
+.fi
+.ft R
+.LP
+is another way to draw a horizontal line one inch long.
+.RE
+.TP
+.BI \eX'ps:\ file\ name '
+This is the same as the
+.B exec
+command except that the PostScript code is read from file
+.IR name .
+.TP
+.BI \eX'ps:\ def\ code '
+Place a PostScript definition contained in
+.I code
+in the prologue.
+There should be at most one definition per
+.B \eX
+command.
+Long definitions can be split over several
+.B \eX
+commands;
+all the
+.I code
+arguments are simply joined together separated by newlines.
+The definitions are placed in a dictionary which is automatically
+pushed on the dictionary stack when an
+.B exec
+command is executed.
+If you use the
+.B \eY
+escape sequence with an argument that names a macro,
+.I code
+can extend over multiple lines.
+.TP
+.BI \eX'ps:\ mdef\ n\ code '
+Like
+.BR def ,
+except that
+.I code
+may contain up to
+.I n
+definitions.
+.B grops
+needs to know how many definitions
+.I code
+contains
+so that it can create an appropriately sized PostScript dictionary
+to contain them.
+.TP
+.BI \eX'ps:\ import\ file\ llx\ lly\ urx\ ury\ width\ \fR[\fP\ height\ \fR]\fP '
+Import a PostScript graphic from
+.IR file .
+The arguments
+.IR llx ,
+.IR lly ,
+.IR urx ,
+and
+.I ury
+give the bounding box of the graphic in the default PostScript
+coordinate system; they should all be integers;
+.I llx
+and
+.I lly
+are the x and y coordinates of the lower left
+corner of the graphic;
+.I urx
+and
+.I ury
+are the x and y coordinates of the upper right corner of the graphic;
+.I width
+and
+.I height
+are integers that give the desired width and height in groff
+units of the graphic.
+The graphic will be scaled so that it has this width and height
+and translated so that the lower left corner of the graphic is
+located at the position associated with
+.B \eX
+command.
+If the height argument is omitted it will be scaled uniformly in the
+x and y directions so that it has the specified width.
+Note that the contents of the
+.B \eX
+command are not interpreted by
+.BR troff ;
+so vertical space for the graphic is not automatically added,
+and the
+.I width
+and
+.I height
+arguments are not allowed to have attached scaling indicators.
+If the PostScript file complies with the Adobe Document Structuring
+Conventions and contains a
+.B %%BoundingBox
+comment, then the bounding box can be automatically
+extracted from within groff by using the
+.B sy
+request to run the
+.B psbb
+command.
+.RS
+.LP
+The
+.B \-mps
+macros (which are automatically loaded when
+.B grops
+is run by the groff command) include a
+.B PSPIC
+macro which allows a picture to be easily imported.
+This has the format
+.IP
+\&\fB.PSPIC\fP \fI\|file\fP [ \fB\-L\fP | \fB-R\fP | \fB\-I\fP \fIn\fP ]\
+[ \fIwidth\fP [ \fIheight\fP ]]
+.LP
+.I file
+is the name of the file containing the illustration;
+.I width
+and
+.I height
+give the desired width and height of the graphic.
+The
+.I width
+and
+.I height
+arguments may have scaling indicators attached;
+the default scaling indicator is
+.BR i .
+This macro will scale the graphic uniformly
+in the x and y directions so that it is no more than
+.I width
+wide
+and
+.I height
+high.
+By default, the graphic will be horizontally centered.
+The
+.BI \-L
+and
+.BI \-R
+cause the graphic to be left-aligned and right-aligned
+respectively.
+The
+.B \-I
+option causes the graphic to be indented by
+.IR n .
+.RE
+.TP
+.B \eX'ps:\ invis'
+.br
+.ns
+.TP
+.B \eX'ps:\ endinvis'
+No output will be generated for text and drawing commands
+that are bracketed with these
+.B \eX
+commands.
+These commands are intended for use when output from
+.B troff
+will be previewed before being processed with
+.BR grops ;
+if the previewer is unable to display certain characters
+or other constructs, then other substitute characters or constructs
+can be used for previewing by bracketing them with these
+.B \eX
+commands.
+.RS
+.LP
+For example,
+.B gxditview
+is not able to display a proper
+.B \e(em
+character because the standard X11 fonts do not provide it;
+this problem can be overcome by executing the following
+request
+.IP
+.ft B
+.nf
+\&.char \e(em \eX'ps: invis'\e
+\eZ'\ev'-.25m'\eh'.05m'\eD'l .9m 0'\eh'.05m''\e
+\eX'ps: endinvis'\e(em
+.ft
+.fi
+.LP
+In this case,
+.B gxditview
+will be unable to display the
+.B \e(em
+character and will draw the line,
+whereas
+.B grops
+will print the
+.B \e(em
+character
+and ignore the line.
+.RE
+.LP
+The input to
+.B grops
+must be in the format output by
+.BR @g@troff (@MAN1EXT@).
+This is described in
+.BR groff_out (@MAN5EXT@).
+In addition the device and font description files for the device used
+must meet certain requirements.
+The device and font description files supplied for
+.B ps
+device meet all these requirements.
+.BR afmtodit (@MAN1EXT@)
+can be used to create font files from AFM files.
+The resolution must be an integer multiple of 72 times the
+.BR sizescale .
+The
+.B ps
+device uses a resolution of 72000 and a sizescale of 1000.
+The device description file should contain a command
+.IP
+.BI paperlength\ n
+.LP
+which says that output should be generated which is suitable for
+printing on a page whose length is
+.I n
+machine units.
+Each font description file must contain a command
+.IP
+.BI internalname\ psname
+.LP
+which says that the PostScript name of the font is
+.IR psname .
+It may also contain a command
+.IP
+.BI encoding\ enc_file
+.LP
+which says that
+the PostScript font should be reencoded using the encoding described in
+.IR enc_file ;
+this file should consist of a sequence of lines of the form:
+.IP
+.I
+pschar code
+.LP
+where
+.I pschar
+is the PostScript name of the character,
+and
+.I code
+is its position in the encoding expressed as a decimal integer.
+The code for each character given in the font file must correspond
+to the code for the character in encoding file, or to the code in the default
+encoding for the font if the PostScript font is not to be reencoded.
+This code can be used with the
+.B \eN
+escape sequence in
+.B troff
+to select the character,
+even if the character does not have a groff name.
+Every character in the font file must exist in the PostScript font, and
+the widths given in the font file must match the widths used
+in the PostScript font.
+.B grops
+will assume that a character with a groff name of
+.B space
+is blank (makes no marks on the page);
+it can make use of such a character to generate more efficient and
+compact PostScript output.
+.LP
+.B grops
+can automatically include the downloadable fonts necessary
+to print the document.
+Any downloadable fonts which should, when required, be included by
+.B grops
+must be listed in the file
+.BR @FONTDIR@/devps/download ;
+this should consist of lines of the form
+.IP
+.I
+font filename
+.LP
+where
+.I font
+is the PostScript name of the font,
+and
+.I filename
+is the name of the file containing the font;
+lines beginning with
+.B #
+and blank lines are ignored;
+fields may be separated by tabs or spaces;
+.I filename
+will be searched for using the same mechanism that is used
+for groff font metric files.
+The
+.B download
+file itself will also be searched for using this mechanism.
+.LP
+If the file containing a downloadable font or imported document
+conforms to the Adobe Document Structuring Conventions,
+then
+.B grops
+will interpret any comments in the files sufficiently to ensure that its
+own output is conforming.
+It will also supply any needed font resources that are listed in the
+.B download
+file
+as well as any needed file resources.
+It is also able to handle inter-resource dependencies.
+For example, suppose that you have a downloadable font called Garamond,
+and also a downloadable font called Garamond-Outline
+which depends on Garamond
+(typically it would be defined to copy Garamond's font dictionary,
+and change the PaintType),
+then it is necessary for Garamond to be appear before Garamond-Outline
+in the PostScript document.
+.B grops
+will handle this automatically
+provided that the downloadable font file for Garamond-Outline
+indicates its dependence on Garamond by means of
+the Document Structuring Conventions,
+for example by beginning with the following lines
+.IP
+.B
+%!PS-Adobe-3.0 Resource-Font
+.br
+.B
+%%DocumentNeededResources: font Garamond
+.br
+.B
+%%EndComments
+.br
+.B
+%%IncludeResource: font Garamond
+.LP
+In this case both Garamond and Garamond-Outline would need to be listed
+in the
+.B download
+file.
+A downloadable font should not include its own name in a
+.B %%DocumentSuppliedResources
+comment.
+.LP
+.B grops
+will not interpret
+.B %%DocumentFonts
+comments.
+The
+.BR %%DocumentNeededResources ,
+.BR %%DocumentSuppliedResources ,
+.BR %%IncludeResource ,
+.BR %%BeginResource
+and
+.BR %%EndResource
+comments
+(or possibly the old
+.BR %%DocumentNeededFonts ,
+.BR %%DocumentSuppliedFonts ,
+.BR %%IncludeFont ,
+.BR %%BeginFont
+and
+.BR %%EndFont
+comments)
+should be used.
+.SH FILES
+.Tp \w'\fB@FONTDIR@/devps/download'u+2n
+.B @FONTDIR@/devps/DESC
+Device description file.
+.TP
+.BI @FONTDIR@/devps/ F
+Font description file for font
+.IR F .
+.TP
+.B @FONTDIR@/devps/download
+List of downloadable fonts.
+.TP
+.B @FONTDIR@/devps/text.enc
+Encoding used for text fonts.
+.TP
+.B @MACRODIR@/tmac.ps
+Macros for use with
+.BR grops ;
+automatically loaded by
+.BR troffrc
+.TP
+.B @MACRODIR@/tmac.pspic
+Definition of
+.B PSPIC
+macro,
+automatically loaded by
+.BR tmac.ps .
+.TP
+.B @MACRODIR@/tmac.psold
+Macros to disable use of characters not present in older
+PostScript printers; automatically loaded by
+.BR tmac.ps .
+.TP
+.B @MACRODIR@/tmac.psnew
+Macros to undo the effect of
+.BR tmac.psold .
+.TP
+.BI /tmp/grops XXXXXX
+Temporary file.
+.SH "SEE ALSO"
+.\" .BR afmtodit (@MAN1EXT@),
+.BR groff (@MAN1EXT@),
+.BR @g@troff (@MAN1EXT@),
+.BR psbb (@MAN1EXT@),
+.BR groff_out (@MAN5EXT@),
+.BR groff_font (@MAN5EXT@),
+.BR groff_char (@MAN7EXT@)
diff --git a/gnu/usr.bin/groff/grops/ps.cc b/gnu/usr.bin/groff/grops/ps.cc
new file mode 100644
index 0000000..2a78981
--- /dev/null
+++ b/gnu/usr.bin/groff/grops/ps.cc
@@ -0,0 +1,1516 @@
+// -*- C++ -*-
+/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
+ Written by James Clark (jjc@jclark.com)
+
+This file is part of groff.
+
+groff is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
+
+groff is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License along
+with groff; see the file COPYING. If not, write to the Free Software
+Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "driver.h"
+#include "stringclass.h"
+#include "cset.h"
+
+#include "ps.h"
+#include <time.h>
+
+static int landscape_flag = 0;
+static int ncopies = 1;
+static int linewidth = -1;
+// Non-zero means generate PostScript code that guesses the paper
+// length using the imageable area.
+static int guess_flag = 0;
+
+// Non-zero if -b was specified on the command line.
+static int bflag = 0;
+unsigned broken_flags = 0;
+
+#define DEFAULT_LINEWIDTH 40 /* in ems/1000 */
+#define MAX_LINE_LENGTH 72
+#define FILL_MAX 1000
+
+const char *const dict_name = "grops";
+const char *const defs_dict_name = "DEFS";
+const int DEFS_DICT_SPARE = 50;
+
+double degrees(double r)
+{
+ return r*180.0/PI;
+}
+
+double radians(double d)
+{
+ return d*PI/180.0;
+}
+
+inline double transform_fill(int fill)
+{
+ return 1 - fill/double(FILL_MAX);
+}
+
+// This is used for testing whether a character should be output in the
+// PostScript file using \nnn, so we really want the character to be
+// less than 0200.
+
+inline int is_ascii(char c)
+{
+ return (unsigned char)c < 0200;
+}
+
+ps_output::ps_output(FILE *f, int n)
+: fp(f), max_line_length(n), col(0), need_space(0), fixed_point(0)
+{
+}
+
+ps_output &ps_output::set_file(FILE *f)
+{
+ fp = f;
+ col = 0;
+ return *this;
+}
+
+ps_output &ps_output::copy_file(FILE *infp)
+{
+ int c;
+ while ((c = getc(infp)) != EOF)
+ putc(c, fp);
+ return *this;
+}
+
+ps_output &ps_output::end_line()
+{
+ if (col != 0) {
+ putc('\n', fp);
+ col = 0;
+ need_space = 0;
+ }
+ return *this;
+}
+
+ps_output &ps_output::special(const char *s)
+{
+ if (s == 0 || *s == '\0')
+ return *this;
+ if (col != 0) {
+ putc('\n', fp);
+ col = 0;
+ }
+ fputs(s, fp);
+ if (strchr(s, '\0')[-1] != '\n')
+ putc('\n', fp);
+ need_space = 0;
+ return *this;
+}
+
+ps_output &ps_output::simple_comment(const char *s)
+{
+ if (col != 0)
+ putc('\n', fp);
+ putc('%', fp);
+ putc('%', fp);
+ fputs(s, fp);
+ putc('\n', fp);
+ col = 0;
+ need_space = 0;
+ return *this;
+}
+
+ps_output &ps_output::begin_comment(const char *s)
+{
+ if (col != 0)
+ putc('\n', fp);
+ putc('%', fp);
+ putc('%', fp);
+ fputs(s, fp);
+ col = 2 + strlen(s);
+ return *this;
+}
+
+ps_output &ps_output::end_comment()
+{
+ if (col != 0) {
+ putc('\n', fp);
+ col = 0;
+ }
+ need_space = 0;
+ return *this;
+}
+
+ps_output &ps_output::comment_arg(const char *s)
+{
+ int len = strlen(s);
+ if (col + len + 1 > max_line_length) {
+ putc('\n', fp);
+ fputs("%%+", fp);
+ col = 3;
+ }
+ putc(' ', fp);
+ fputs(s, fp);
+ col += len + 1;
+ return *this;
+}
+
+ps_output &ps_output::set_fixed_point(int n)
+{
+ assert(n >= 0 && n <= 10);
+ fixed_point = n;
+ return *this;
+}
+
+ps_output &ps_output::put_delimiter(char c)
+{
+ if (col + 1 > max_line_length) {
+ putc('\n', fp);
+ col = 0;
+ }
+ putc(c, fp);
+ col++;
+ need_space = 0;
+ return *this;
+}
+
+ps_output &ps_output::put_string(const char *s, int n)
+{
+ int len = 0;
+ for (int i = 0; i < n; i++) {
+ char c = s[i];
+ if (is_ascii(c) && csprint(c)) {
+ if (c == '(' || c == ')' || c == '\\')
+ len += 2;
+ else
+ len += 1;
+ }
+ else
+ len += 4;
+ }
+ if (len > n*2) {
+ if (col + n*2 + 2 > max_line_length && n*2 + 2 <= max_line_length) {
+ putc('\n', fp);
+ col = 0;
+ }
+ if (col + 1 > max_line_length) {
+ putc('\n', fp);
+ col = 0;
+ }
+ putc('<', fp);
+ col++;
+ for (i = 0; i < n; i++) {
+ if (col + 2 > max_line_length) {
+ putc('\n', fp);
+ col = 0;
+ }
+ fprintf(fp, "%02x", s[i] & 0377);
+ col += 2;
+ }
+ putc('>', fp);
+ col++;
+ }
+ else {
+ if (col + len + 2 > max_line_length && len + 2 <= max_line_length) {
+ putc('\n', fp);
+ col = 0;
+ }
+ if (col + 2 > max_line_length) {
+ putc('\n', fp);
+ col = 0;
+ }
+ putc('(', fp);
+ col++;
+ for (i = 0; i < n; i++) {
+ char c = s[i];
+ if (is_ascii(c) && csprint(c)) {
+ if (c == '(' || c == ')' || c == '\\')
+ len = 2;
+ else
+ len = 1;
+ }
+ else
+ len = 4;
+ if (col + len + 1 > max_line_length) {
+ putc('\\', fp);
+ putc('\n', fp);
+ col = 0;
+ }
+ switch (len) {
+ case 1:
+ putc(c, fp);
+ break;
+ case 2:
+ putc('\\', fp);
+ putc(c, fp);
+ break;
+ case 4:
+ fprintf(fp, "\\%03o", c & 0377);
+ break;
+ default:
+ assert(0);
+ }
+ col += len;
+ }
+ putc(')', fp);
+ col++;
+ }
+ need_space = 0;
+ return *this;
+}
+
+ps_output &ps_output::put_number(int n)
+{
+ char buf[1 + INT_DIGITS + 1];
+ sprintf(buf, "%d", n);
+ int len = strlen(buf);
+ if (col > 0 && col + len + need_space > max_line_length) {
+ putc('\n', fp);
+ col = 0;
+ need_space = 0;
+ }
+ if (need_space) {
+ putc(' ', fp);
+ col++;
+ }
+ fputs(buf, fp);
+ col += len;
+ need_space = 1;
+ return *this;
+}
+
+ps_output &ps_output::put_fix_number(int i)
+{
+ const char *p = iftoa(i, fixed_point);
+ int len = strlen(p);
+ if (col > 0 && col + len + need_space > max_line_length) {
+ putc('\n', fp);
+ col = 0;
+ need_space = 0;
+ }
+ if (need_space) {
+ putc(' ', fp);
+ col++;
+ }
+ fputs(p, fp);
+ col += len;
+ need_space = 1;
+ return *this;
+}
+
+ps_output &ps_output::put_float(double d)
+{
+ char buf[128];
+ sprintf(buf, "%.4f", d);
+ int len = strlen(buf);
+ if (col > 0 && col + len + need_space > max_line_length) {
+ putc('\n', fp);
+ col = 0;
+ need_space = 0;
+ }
+ if (need_space) {
+ putc(' ', fp);
+ col++;
+ }
+ fputs(buf, fp);
+ col += len;
+ need_space = 1;
+ return *this;
+}
+
+ps_output &ps_output::put_symbol(const char *s)
+{
+ int len = strlen(s);
+ if (col > 0 && col + len + need_space > max_line_length) {
+ putc('\n', fp);
+ col = 0;
+ need_space = 0;
+ }
+ if (need_space) {
+ putc(' ', fp);
+ col++;
+ }
+ fputs(s, fp);
+ col += len;
+ need_space = 1;
+ return *this;
+}
+
+ps_output &ps_output::put_literal_symbol(const char *s)
+{
+ int len = strlen(s);
+ if (col > 0 && col + len + 1 > max_line_length) {
+ putc('\n', fp);
+ col = 0;
+ }
+ putc('/', fp);
+ fputs(s, fp);
+ col += len + 1;
+ need_space = 1;
+ return *this;
+}
+
+class ps_font : public font {
+ ps_font(const char *);
+public:
+ int encoding_index;
+ char *encoding;
+ char *reencoded_name;
+ ~ps_font();
+ void handle_unknown_font_command(const char *command, const char *arg,
+ const char *filename, int lineno);
+ static ps_font *load_ps_font(const char *);
+};
+
+ps_font *ps_font::load_ps_font(const char *s)
+{
+ ps_font *f = new ps_font(s);
+ if (!f->load()) {
+ delete f;
+ return 0;
+ }
+ return f;
+}
+
+ps_font::ps_font(const char *nm)
+: font(nm), encoding(0), reencoded_name(0), encoding_index(-1)
+{
+}
+
+ps_font::~ps_font()
+{
+ a_delete encoding;
+ a_delete reencoded_name;
+}
+
+void ps_font::handle_unknown_font_command(const char *command, const char *arg,
+ const char *filename, int lineno)
+{
+ if (strcmp(command, "encoding") == 0) {
+ if (arg == 0)
+ error_with_file_and_line(filename, lineno,
+ "`encoding' command requires an argument");
+ else
+ encoding = strsave(arg);
+ }
+}
+
+static void handle_unknown_desc_command(const char *command, const char *arg,
+ const char *filename, int lineno)
+{
+ if (strcmp(command, "broken") == 0) {
+ if (arg == 0)
+ error_with_file_and_line(filename, lineno,
+ "`broken' command requires an argument");
+ else if (!bflag)
+ broken_flags = atoi(arg);
+ }
+}
+
+struct style {
+ font *f;
+ int point_size;
+ int height;
+ int slant;
+ style();
+ style(font *, int, int, int);
+ int operator==(const style &) const;
+ int operator!=(const style &) const;
+};
+
+style::style() : f(0)
+{
+}
+
+style::style(font *p, int sz, int h, int sl)
+: f(p), point_size(sz), height(h), slant(sl)
+{
+}
+
+int style::operator==(const style &s) const
+{
+ return (f == s.f && point_size == s.point_size
+ && height == s.height && slant == s.slant);
+}
+
+int style::operator!=(const style &s) const
+{
+ return !(*this == s);
+}
+
+class ps_printer : public printer {
+ FILE *tempfp;
+ ps_output out;
+ int res;
+ int space_char_index;
+ int pages_output;
+ int paper_length;
+ int equalise_spaces;
+ enum { SBUF_SIZE = 256 };
+ char sbuf[SBUF_SIZE];
+ int sbuf_len;
+ int sbuf_start_hpos;
+ int sbuf_vpos;
+ int sbuf_end_hpos;
+ int sbuf_space_width;
+ int sbuf_space_count;
+ int sbuf_space_diff_count;
+ int sbuf_space_code;
+ int sbuf_kern;
+ style sbuf_style;
+ style output_style;
+ int output_hpos;
+ int output_vpos;
+ int output_draw_point_size;
+ int line_thickness;
+ int output_line_thickness;
+ int fill;
+ unsigned char output_space_code;
+ enum { MAX_DEFINED_STYLES = 50 };
+ style defined_styles[MAX_DEFINED_STYLES];
+ int ndefined_styles;
+ int next_encoding_index;
+ string defs;
+ int ndefs;
+ resource_manager rm;
+ int invis_count;
+
+ void flush_sbuf();
+ void set_style(const style &);
+ void set_space_code(unsigned char c);
+ int set_encoding_index(ps_font *);
+ void do_exec(char *, const environment *);
+ void do_import(char *, const environment *);
+ void do_def(char *, const environment *);
+ void do_mdef(char *, const environment *);
+ void do_file(char *, const environment *);
+ void do_invis(char *, const environment *);
+ void do_endinvis(char *, const environment *);
+ void set_line_thickness(const environment *);
+ void fill_path();
+ void encode_fonts();
+ void define_encoding(const char *, int);
+ void reencode_font(ps_font *);
+public:
+ ps_printer();
+ ~ps_printer();
+ void set_char(int i, font *f, const environment *env, int w);
+ void draw(int code, int *p, int np, const environment *env);
+ void begin_page(int);
+ void end_page(int);
+ void special(char *arg, const environment *env);
+ font *make_font(const char *);
+ void end_of_line();
+};
+
+ps_printer::ps_printer()
+: pages_output(0),
+ sbuf_len(0),
+ output_hpos(-1),
+ output_vpos(-1),
+ out(0, MAX_LINE_LENGTH),
+ ndefined_styles(0),
+ next_encoding_index(0),
+ line_thickness(-1),
+ fill(FILL_MAX + 1),
+ ndefs(0),
+ invis_count(0)
+{
+ tempfp = xtmpfile();
+ out.set_file(tempfp);
+ if (linewidth < 0)
+ linewidth = DEFAULT_LINEWIDTH;
+ if (font::hor != 1)
+ fatal("horizontal resolution must be 1");
+ if (font::vert != 1)
+ fatal("vertical resolution must be 1");
+ if (font::res % (font::sizescale*72) != 0)
+ fatal("res must be a multiple of 72*sizescale");
+ int r = font::res;
+ int point = 0;
+ while (r % 10 == 0) {
+ r /= 10;
+ point++;
+ }
+ res = r;
+ out.set_fixed_point(point);
+ space_char_index = font::name_to_index("space");
+ paper_length = font::paperlength;
+ if (paper_length == 0)
+ paper_length = 11*font::res;
+ equalise_spaces = font::res >= 72000;
+}
+
+int ps_printer::set_encoding_index(ps_font *f)
+{
+ if (f->encoding_index >= 0)
+ return f->encoding_index;
+ for (font_pointer_list *p = font_list; p; p = p->next)
+ if (p->p != f) {
+ char *encoding = ((ps_font *)p->p)->encoding;
+ int encoding_index = ((ps_font *)p->p)->encoding_index;
+ if (encoding != 0 && encoding_index >= 0
+ && strcmp(f->encoding, encoding) == 0) {
+ return f->encoding_index = encoding_index;
+ }
+ }
+ return f->encoding_index = next_encoding_index++;
+}
+
+void ps_printer::set_char(int i, font *f, const environment *env, int w)
+{
+ if (i == space_char_index || invis_count > 0)
+ return;
+ unsigned char code = f->get_code(i);
+ style sty(f, env->size, env->height, env->slant);
+ if (sty.slant != 0) {
+ if (sty.slant > 80 || sty.slant < -80) {
+ error("silly slant `%1' degrees", sty.slant);
+ sty.slant = 0;
+ }
+ }
+ if (sbuf_len > 0) {
+ if (sbuf_len < SBUF_SIZE
+ && sty == sbuf_style
+ && sbuf_vpos == env->vpos) {
+ if (sbuf_end_hpos == env->hpos) {
+ sbuf[sbuf_len++] = code;
+ sbuf_end_hpos += w + sbuf_kern;
+ return;
+ }
+ if (sbuf_len == 1 && sbuf_kern == 0) {
+ sbuf_kern = env->hpos - sbuf_end_hpos;
+ sbuf_end_hpos = env->hpos + sbuf_kern + w;
+ sbuf[sbuf_len++] = code;
+ return;
+ }
+ /* If sbuf_end_hpos - sbuf_kern == env->hpos, we are better off
+ starting a new string. */
+ if (sbuf_len < SBUF_SIZE - 1 && env->hpos >= sbuf_end_hpos
+ && (sbuf_kern == 0 || sbuf_end_hpos - sbuf_kern != env->hpos)) {
+ if (sbuf_space_code < 0) {
+ if (f->contains(space_char_index)) {
+ sbuf_space_code = f->get_code(space_char_index);
+ sbuf_space_width = env->hpos - sbuf_end_hpos;
+ sbuf_end_hpos = env->hpos + w + sbuf_kern;
+ sbuf[sbuf_len++] = sbuf_space_code;
+ sbuf[sbuf_len++] = code;
+ sbuf_space_count++;
+ return;
+ }
+ }
+ else {
+ int diff = env->hpos - sbuf_end_hpos - sbuf_space_width;
+ if (diff == 0 || (equalise_spaces && (diff == 1 || diff == -1))) {
+ sbuf_end_hpos = env->hpos + w + sbuf_kern;
+ sbuf[sbuf_len++] = sbuf_space_code;
+ sbuf[sbuf_len++] = code;
+ sbuf_space_count++;
+ if (diff == 1)
+ sbuf_space_diff_count++;
+ else if (diff == -1)
+ sbuf_space_diff_count--;
+ return;
+ }
+ }
+ }
+ }
+ flush_sbuf();
+ }
+ sbuf_len = 1;
+ sbuf[0] = code;
+ sbuf_end_hpos = env->hpos + w;
+ sbuf_start_hpos = env->hpos;
+ sbuf_vpos = env->vpos;
+ sbuf_style = sty;
+ sbuf_space_code = -1;
+ sbuf_space_width = 0;
+ sbuf_space_count = sbuf_space_diff_count = 0;
+ sbuf_kern = 0;
+}
+
+static char *make_encoding_name(int encoding_index)
+{
+ static char buf[3 + INT_DIGITS + 1];
+ sprintf(buf, "ENC%d", encoding_index);
+ return buf;
+}
+
+const char *const WS = " \t\n\r";
+
+void ps_printer::define_encoding(const char *encoding, int encoding_index)
+{
+ char *vec[256];
+ for (int i = 0; i < 256; i++)
+ vec[i] = 0;
+ char *path;
+ FILE *fp = font::open_file(encoding, &path);
+ if (fp == 0)
+ fatal("can't open encoding file `%1'", encoding);
+ int lineno = 1;
+ char buf[256];
+ while (fgets(buf, 512, fp) != 0) {
+ char *p = buf;
+ while (csspace(*p))
+ p++;
+ if (*p != '#' && *p != '\0' && (p = strtok(buf, WS)) != 0) {
+ char *q = strtok(0, WS);
+ int n;
+ if (q == 0 || sscanf(q, "%d", &n) != 1 || n < 0 || n >= 256)
+ fatal_with_file_and_line(path, lineno, "bad second field");
+ vec[n] = new char[strlen(p) + 1];
+ strcpy(vec[n], p);
+ }
+ lineno++;
+ }
+ a_delete path;
+ out.put_literal_symbol(make_encoding_name(encoding_index));
+ out.put_delimiter('[');
+ for (i = 0; i < 256; i++) {
+ if (vec[i] == 0)
+ out.put_literal_symbol(".notdef");
+ else {
+ out.put_literal_symbol(vec[i]);
+ a_delete vec[i];
+ }
+ }
+ out.put_delimiter(']').put_symbol("def");
+}
+
+void ps_printer::reencode_font(ps_font *f)
+{
+ out.put_literal_symbol(f->reencoded_name)
+ .put_symbol(make_encoding_name(f->encoding_index))
+ .put_literal_symbol(f->get_internal_name())
+ .put_symbol("RE");
+}
+
+void ps_printer::encode_fonts()
+{
+ if (next_encoding_index == 0)
+ return;
+ char *done_encoding = new char[next_encoding_index];
+ for (int i = 0; i < next_encoding_index; i++)
+ done_encoding[i] = 0;
+ for (font_pointer_list *f = font_list; f; f = f->next) {
+ int encoding_index = ((ps_font *)f->p)->encoding_index;
+ if (encoding_index >= 0) {
+ assert(encoding_index < next_encoding_index);
+ if (!done_encoding[encoding_index]) {
+ done_encoding[encoding_index] = 1;
+ define_encoding(((ps_font *)f->p)->encoding, encoding_index);
+ }
+ reencode_font((ps_font *)f->p);
+ }
+ }
+ a_delete done_encoding;
+}
+
+void ps_printer::set_style(const style &sty)
+{
+ char buf[1 + INT_DIGITS + 1];
+ for (int i = 0; i < ndefined_styles; i++)
+ if (sty == defined_styles[i]) {
+ sprintf(buf, "F%d", i);
+ out.put_symbol(buf);
+ return;
+ }
+ if (ndefined_styles >= MAX_DEFINED_STYLES)
+ ndefined_styles = 0;
+ sprintf(buf, "F%d", ndefined_styles);
+ out.put_literal_symbol(buf);
+ const char *psname = sty.f->get_internal_name();
+ if (psname == 0)
+ fatal("no internalname specified for font `%1'", sty.f->get_name());
+ char *encoding = ((ps_font *)sty.f)->encoding;
+ if (encoding != 0) {
+ char *s = ((ps_font *)sty.f)->reencoded_name;
+ if (s == 0) {
+ int ei = set_encoding_index((ps_font *)sty.f);
+ char *tem = new char[strlen(psname) + 1 + INT_DIGITS + 1];
+ sprintf(tem, "%s@%d", psname, ei);
+ psname = tem;
+ ((ps_font *)sty.f)->reencoded_name = tem;
+ }
+ else
+ psname = s;
+ }
+ out.put_fix_number((font::res/(72*font::sizescale))*sty.point_size);
+ if (sty.height != 0 || sty.slant != 0) {
+ int h = sty.height == 0 ? sty.point_size : sty.height;
+ h *= font::res/(72*font::sizescale);
+ int c = int(h*tan(radians(sty.slant)) + .5);
+ out.put_fix_number(c).put_fix_number(h).put_literal_symbol(psname)
+ .put_symbol("MF");
+ }
+ else {
+ out.put_literal_symbol(psname).put_symbol("SF");
+ }
+ defined_styles[ndefined_styles++] = sty;
+}
+
+void ps_printer::set_space_code(unsigned char c)
+{
+ out.put_literal_symbol("SC").put_number(c).put_symbol("def");
+}
+
+void ps_printer::end_of_line()
+{
+ flush_sbuf();
+ // this ensures that we do an absolute motion to the beginning of a line
+ output_vpos = output_hpos = -1;
+}
+
+void ps_printer::flush_sbuf()
+{
+ enum {
+ NONE,
+ RELATIVE_H,
+ RELATIVE_V,
+ RELATIVE_HV,
+ ABSOLUTE
+ } motion = NONE;
+ int space_flag = 0;
+ if (sbuf_len == 0)
+ return;
+ if (output_style != sbuf_style) {
+ set_style(sbuf_style);
+ output_style = sbuf_style;
+ }
+ int extra_space = 0;
+ if (output_hpos < 0 || output_vpos < 0)
+ motion = ABSOLUTE;
+ else {
+ if (output_hpos != sbuf_start_hpos)
+ motion = RELATIVE_H;
+ if (output_vpos != sbuf_vpos) {
+ if (motion != NONE)
+ motion = RELATIVE_HV;
+ else
+ motion = RELATIVE_V;
+ }
+ }
+ if (sbuf_space_code >= 0) {
+ int w = sbuf_style.f->get_width(space_char_index, sbuf_style.point_size);
+ if (w + sbuf_kern != sbuf_space_width) {
+ if (sbuf_space_code != output_space_code) {
+ set_space_code(sbuf_space_code);
+ output_space_code = sbuf_space_code;
+ }
+ space_flag = 1;
+ extra_space = sbuf_space_width - w - sbuf_kern;
+ if (sbuf_space_diff_count > sbuf_space_count/2)
+ extra_space++;
+ else if (sbuf_space_diff_count < -(sbuf_space_count/2))
+ extra_space--;
+ }
+ }
+ if (space_flag)
+ out.put_fix_number(extra_space);
+ if (sbuf_kern != 0)
+ out.put_fix_number(sbuf_kern);
+ out.put_string(sbuf, sbuf_len);
+ char sym[2];
+ sym[0] = 'A' + motion*4 + space_flag + 2*(sbuf_kern != 0);
+ sym[1] = '\0';
+ switch (motion) {
+ case NONE:
+ break;
+ case ABSOLUTE:
+ out.put_fix_number(sbuf_start_hpos)
+ .put_fix_number(sbuf_vpos);
+ break;
+ case RELATIVE_H:
+ out.put_fix_number(sbuf_start_hpos - output_hpos);
+ break;
+ case RELATIVE_V:
+ out.put_fix_number(sbuf_vpos - output_vpos);
+ break;
+ case RELATIVE_HV:
+ out.put_fix_number(sbuf_start_hpos - output_hpos)
+ .put_fix_number(sbuf_vpos - output_vpos);
+ break;
+ default:
+ assert(0);
+ }
+ out.put_symbol(sym);
+ output_hpos = sbuf_end_hpos;
+ output_vpos = sbuf_vpos;
+ sbuf_len = 0;
+}
+
+
+void ps_printer::set_line_thickness(const environment *env)
+{
+ if (line_thickness < 0) {
+ if (output_draw_point_size != env->size) {
+ // we ought to check for overflow here
+ int lw = ((font::res/(72*font::sizescale))*linewidth*env->size)/1000;
+ out.put_fix_number(lw).put_symbol("LW");
+ output_draw_point_size = env->size;
+ output_line_thickness = -1;
+ }
+ }
+ else {
+ if (output_line_thickness != line_thickness) {
+ out.put_fix_number(line_thickness).put_symbol("LW");
+ output_line_thickness = line_thickness;
+ output_draw_point_size = -1;
+ }
+ }
+}
+
+void ps_printer::fill_path()
+{
+ if (fill > FILL_MAX)
+ out.put_symbol("BL");
+ else
+ out.put_float(transform_fill(fill)).put_symbol("FL");
+}
+
+void ps_printer::draw(int code, int *p, int np, const environment *env)
+{
+ if (invis_count > 0)
+ return;
+ int fill_flag = 0;
+ switch (code) {
+ case 'C':
+ fill_flag = 1;
+ // fall through
+ case 'c':
+ // troff adds an extra argument to C
+ if (np != 1 && !(code == 'C' && np == 2)) {
+ error("1 argument required for circle");
+ break;
+ }
+ out.put_fix_number(env->hpos + p[0]/2)
+ .put_fix_number(env->vpos)
+ .put_fix_number(p[0]/2)
+ .put_symbol("DC");
+ if (fill_flag) {
+ fill_path();
+ }
+ else {
+ set_line_thickness(env);
+ out.put_symbol("ST");
+ }
+ break;
+ case 'l':
+ if (np != 2) {
+ error("2 arguments required for line");
+ break;
+ }
+ set_line_thickness(env);
+ out.put_fix_number(p[0] + env->hpos)
+ .put_fix_number(p[1] + env->vpos)
+ .put_fix_number(env->hpos)
+ .put_fix_number(env->vpos)
+ .put_symbol("DL");
+ break;
+ case 'E':
+ fill_flag = 1;
+ // fall through
+ case 'e':
+ if (np != 2) {
+ error("2 arguments required for ellipse");
+ break;
+ }
+ out.put_fix_number(p[0])
+ .put_fix_number(p[1])
+ .put_fix_number(env->hpos + p[0]/2)
+ .put_fix_number(env->vpos)
+ .put_symbol("DE");
+ if (fill_flag) {
+ fill_path();
+ }
+ else {
+ set_line_thickness(env);
+ out.put_symbol("ST");
+ }
+ break;
+ case 'P':
+ fill_flag = 1;
+ // fall through
+ case 'p':
+ {
+ if (np & 1) {
+ error("even number of arguments required for polygon");
+ break;
+ }
+ if (np == 0) {
+ error("no arguments for polygon");
+ break;
+ }
+ out.put_fix_number(env->hpos)
+ .put_fix_number(env->vpos)
+ .put_symbol("MT");
+ for (int i = 0; i < np; i += 2)
+ out.put_fix_number(p[i])
+ .put_fix_number(p[i+1])
+ .put_symbol("RL");
+ out.put_symbol("CL");
+ if (fill_flag) {
+ fill_path();
+ }
+ else {
+ set_line_thickness(env);
+ out.put_symbol("ST");
+ }
+ break;
+ }
+ case '~':
+ {
+ if (np & 1) {
+ error("even number of arguments required for spline");
+ break;
+ }
+ if (np == 0) {
+ error("no arguments for spline");
+ break;
+ }
+ out.put_fix_number(env->hpos)
+ .put_fix_number(env->vpos)
+ .put_symbol("MT");
+ out.put_fix_number(p[0]/2)
+ .put_fix_number(p[1]/2)
+ .put_symbol("RL");
+ /* tnum/tden should be between 0 and 1; the closer it is to 1
+ the tighter the curve will be to the guiding lines; 2/3
+ is the standard value */
+ const int tnum = 2;
+ const int tden = 3;
+ for (int i = 0; i < np - 2; i += 2) {
+ out.put_fix_number((p[i]*tnum)/(2*tden))
+ .put_fix_number((p[i + 1]*tnum)/(2*tden))
+ .put_fix_number(p[i]/2 + (p[i + 2]*(tden - tnum))/(2*tden))
+ .put_fix_number(p[i + 1]/2 + (p[i + 3]*(tden - tnum))/(2*tden))
+ .put_fix_number((p[i] - p[i]/2) + p[i + 2]/2)
+ .put_fix_number((p[i + 1] - p[i + 1]/2) + p[i + 3]/2)
+ .put_symbol("RC");
+ }
+ out.put_fix_number(p[np - 2] - p[np - 2]/2)
+ .put_fix_number(p[np - 1] - p[np - 1]/2)
+ .put_symbol("RL");
+ set_line_thickness(env);
+ out.put_symbol("ST");
+ }
+ break;
+ case 'a':
+ {
+ if (np != 4) {
+ error("4 arguments required for arc");
+ break;
+ }
+ set_line_thickness(env);
+ double c[2];
+ if (adjust_arc_center(p, c))
+ out.put_fix_number(env->hpos + int(c[0]))
+ .put_fix_number(env->vpos + int(c[1]))
+ .put_fix_number(int(sqrt(c[0]*c[0] + c[1]*c[1])))
+ .put_float(degrees(atan2(-c[1], -c[0])))
+ .put_float(degrees(atan2(p[1] + p[3] - c[1], p[0] + p[2] - c[0])))
+ .put_symbol("DA");
+ else
+ out.put_fix_number(p[0] + p[2] + env->hpos)
+ .put_fix_number(p[1] + p[3] + env->vpos)
+ .put_fix_number(env->hpos)
+ .put_fix_number(env->vpos)
+ .put_symbol("DL");
+ }
+ break;
+ case 't':
+ {
+ if (np == 0) {
+ line_thickness = -1;
+ }
+ else {
+ // troff gratuitously adds an extra 0
+ if (np != 1 && np != 2) {
+ error("0 or 1 argument required for thickness");
+ break;
+ }
+ line_thickness = p[0];
+ }
+ break;
+ }
+ case 'f':
+ {
+ if (np != 1 && np != 2) {
+ error("1 argument required for fill");
+ break;
+ }
+ fill = p[0];
+ if (fill < 0 || fill > FILL_MAX) {
+ // This means fill with the current color.
+ fill = FILL_MAX + 1;
+ }
+ break;
+ }
+ default:
+ error("unrecognised drawing command `%1'", char(code));
+ break;
+ }
+
+ output_hpos = output_vpos = -1;
+}
+
+
+void ps_printer::begin_page(int n)
+{
+ out.begin_comment("Page:").comment_arg(itoa(n));
+ out.comment_arg(itoa(++pages_output)).end_comment();
+ output_style.f = 0;
+ output_space_code = 32;
+ output_draw_point_size = -1;
+ output_line_thickness = -1;
+ output_hpos = output_vpos = -1;
+ ndefined_styles = 0;
+ out.simple_comment("BeginPageSetup");
+ out.put_symbol("BP");
+ out.simple_comment("EndPageSetup");
+}
+
+void ps_printer::end_page(int)
+{
+ flush_sbuf();
+ out.put_symbol("EP");
+ if (invis_count != 0) {
+ error("missing `endinvis' command");
+ invis_count = 0;
+ }
+}
+
+font *ps_printer::make_font(const char *nm)
+{
+ return ps_font::load_ps_font(nm);
+}
+
+ps_printer::~ps_printer()
+{
+ out.simple_comment("Trailer");
+ out.put_symbol("end");
+ out.simple_comment("EOF");
+ if (fseek(tempfp, 0L, 0) < 0)
+ fatal("fseek on temporary file failed");
+ fputs("%!PS-Adobe-", stdout);
+ fputs((broken_flags & USE_PS_ADOBE_2_0) ? "2.0" : "3.0", stdout);
+ putchar('\n');
+ out.set_file(stdout);
+ {
+ extern const char *version_string;
+ out.begin_comment("Creator:")
+ .comment_arg("groff")
+ .comment_arg("version")
+ .comment_arg(version_string)
+ .end_comment();
+ }
+ {
+ fputs("%%CreationDate: ", out.get_file());
+#ifdef LONG_FOR_TIME_T
+ long
+#else
+ time_t
+#endif
+ t = time(0);
+ fputs(ctime(&t), out.get_file());
+ }
+ for (font_pointer_list *f = font_list; f; f = f->next) {
+ ps_font *psf = (ps_font *)(f->p);
+ rm.need_font(psf->get_internal_name());
+ }
+ rm.print_header_comments(out);
+ out.begin_comment("Pages:").comment_arg(itoa(pages_output)).end_comment();
+ out.begin_comment("PageOrder:").comment_arg("Ascend").end_comment();
+#if 0
+ fprintf(out.get_file(), "%%%%DocumentMedia: () %g %g 0 () ()\n",
+ font::paperwidth*72.0/font::res,
+ paper_length*72.0/font::res);
+#endif
+ out.begin_comment("Orientation:")
+ .comment_arg(landscape_flag ? "Landscape" : "Portrait")
+ .end_comment();
+ if (ncopies != 1) {
+ out.end_line();
+ fprintf(out.get_file(), "%%%%Requirements: numcopies(%d)\n", ncopies);
+ }
+ out.simple_comment("EndComments");
+ out.simple_comment("BeginProlog");
+ rm.output_prolog(out);
+ if (!(broken_flags & NO_SETUP_SECTION)) {
+ out.simple_comment("EndProlog");
+ out.simple_comment("BeginSetup");
+ }
+ rm.document_setup(out);
+ out.put_symbol(dict_name).put_symbol("begin");
+ if (ndefs > 0)
+ ndefs += DEFS_DICT_SPARE;
+ out.put_literal_symbol(defs_dict_name)
+ .put_number(ndefs + 1)
+ .put_symbol("dict")
+ .put_symbol("def");
+ out.put_symbol(defs_dict_name)
+ .put_symbol("begin");
+ out.put_literal_symbol("u")
+ .put_delimiter('{')
+ .put_fix_number(1)
+ .put_symbol("mul")
+ .put_delimiter('}')
+ .put_symbol("bind")
+ .put_symbol("def");
+ defs += '\0';
+ out.special(defs.contents());
+ out.put_symbol("end");
+ if (ncopies != 1)
+ out.put_literal_symbol("#copies").put_number(ncopies).put_symbol("def");
+ out.put_literal_symbol("RES").put_number(res).put_symbol("def");
+ out.put_literal_symbol("PL");
+ if (guess_flag)
+ out.put_symbol("PLG");
+ else
+ out.put_fix_number(paper_length);
+ out.put_symbol("def");
+ out.put_literal_symbol("LS")
+ .put_symbol(landscape_flag ? "true" : "false")
+ .put_symbol("def");
+ encode_fonts();
+ out.simple_comment((broken_flags & NO_SETUP_SECTION)
+ ? "EndProlog"
+ : "EndSetup");
+ out.end_line();
+ out.copy_file(tempfp);
+ fclose(tempfp);
+}
+
+void ps_printer::special(char *arg, const environment *env)
+{
+ typedef void (ps_printer::*SPECIAL_PROCP)(char *, const environment *);
+ static struct {
+ const char *name;
+ SPECIAL_PROCP proc;
+ } proc_table[] = {
+ { "exec", &ps_printer::do_exec },
+ { "def", &ps_printer::do_def },
+ { "mdef", &ps_printer::do_mdef },
+ { "import", &ps_printer::do_import },
+ { "file", &ps_printer::do_file },
+ { "invis", &ps_printer::do_invis },
+ { "endinvis", &ps_printer::do_endinvis },
+ };
+ for (char *p = arg; *p == ' ' || *p == '\n'; p++)
+ ;
+ char *tag = p;
+ for (; *p != '\0' && *p != ':' && *p != ' ' && *p != '\n'; p++)
+ ;
+ if (*p == '\0' || strncmp(tag, "ps", p - tag) != 0) {
+ error("X command without `ps:' tag ignored");
+ return;
+ }
+ p++;
+ for (; *p == ' ' || *p == '\n'; p++)
+ ;
+ char *command = p;
+ for (; *p != '\0' && *p != ' ' && *p != '\n'; p++)
+ ;
+ if (*command == '\0') {
+ error("X command without `ps:' tag ignored");
+ return;
+ }
+ for (int i = 0; i < sizeof(proc_table)/sizeof(proc_table[0]); i++)
+ if (strncmp(command, proc_table[i].name, p - command) == 0) {
+ (this->*(proc_table[i].proc))(p, env);
+ return;
+ }
+ error("X command `%1' not recognised", command);
+}
+
+// A conforming PostScript document must not have lines longer
+// than 255 characters (excluding line termination characters).
+
+static int check_line_lengths(const char *p)
+{
+ for (;;) {
+ const char *end = strchr(p, '\n');
+ if (end == 0)
+ end = strchr(p, '\0');
+ if (end - p > 255)
+ return 0;
+ if (*end == '\0')
+ break;
+ p = end + 1;
+ }
+ return 1;
+}
+
+void ps_printer::do_exec(char *arg, const environment *env)
+{
+ flush_sbuf();
+ while (csspace(*arg))
+ arg++;
+ if (*arg == '\0') {
+ error("missing argument to X exec command");
+ return;
+ }
+ if (!check_line_lengths(arg)) {
+ error("lines in X exec command must not be more than 255 characters long");
+ return;
+ }
+ out.put_fix_number(env->hpos)
+ .put_fix_number(env->vpos)
+ .put_symbol("EBEGIN")
+ .special(arg)
+ .put_symbol("EEND");
+ output_hpos = output_vpos = -1;
+ output_style.f = 0;
+ output_draw_point_size = -1;
+ output_line_thickness = -1;
+ ndefined_styles = 0;
+ if (!ndefs)
+ ndefs = 1;
+}
+
+void ps_printer::do_file(char *arg, const environment *env)
+{
+ flush_sbuf();
+ while (csspace(*arg))
+ arg++;
+ if (*arg == '\0') {
+ error("missing argument to X file command");
+ return;
+ }
+ const char *filename = arg;
+ do {
+ ++arg;
+ } while (*arg != '\0' && *arg != ' ' && *arg != '\n');
+ out.put_fix_number(env->hpos)
+ .put_fix_number(env->vpos)
+ .put_symbol("EBEGIN");
+ rm.import_file(filename, out);
+ out.put_symbol("EEND");
+ output_hpos = output_vpos = -1;
+ output_style.f = 0;
+ output_draw_point_size = -1;
+ output_line_thickness = -1;
+ ndefined_styles = 0;
+ if (!ndefs)
+ ndefs = 1;
+}
+
+void ps_printer::do_def(char *arg, const environment *)
+{
+ flush_sbuf();
+ while (csspace(*arg))
+ arg++;
+ if (!check_line_lengths(arg)) {
+ error("lines in X def command must not be more than 255 characters long");
+ return;
+ }
+ defs += arg;
+ if (*arg != '\0' && strchr(arg, '\0')[-1] != '\n')
+ defs += '\n';
+ ndefs++;
+}
+
+// Like def, but the first argument says how many definitions it contains.
+
+void ps_printer::do_mdef(char *arg, const environment *)
+{
+ flush_sbuf();
+ char *p;
+ int n = (int)strtol(arg, &p, 10);
+ if (n == 0 && p == arg) {
+ error("first argument to X mdef must be an integer");
+ return;
+ }
+ if (n < 0) {
+ error("out of range argument `%1' to X mdef command", int(n));
+ return;
+ }
+ arg = p;
+ while (csspace(*arg))
+ arg++;
+ if (!check_line_lengths(arg)) {
+ error("lines in X mdef command must not be more than 255 characters long");
+ return;
+ }
+ defs += arg;
+ if (*arg != '\0' && strchr(arg, '\0')[-1] != '\n')
+ defs += '\n';
+ ndefs += n;
+}
+
+void ps_printer::do_import(char *arg, const environment *env)
+{
+ flush_sbuf();
+ while (*arg == ' ' || *arg == '\n')
+ arg++;
+ for (char *p = arg; *p != '\0' && *p != ' ' && *p != '\n'; p++)
+ ;
+ if (*p != '\0')
+ *p++ = '\0';
+ int parms[6];
+ int nparms = 0;
+ while (nparms < 6) {
+ char *end;
+ long n = strtol(p, &end, 10);
+ if (n == 0 && end == p)
+ break;
+ parms[nparms++] = int(n);
+ p = end;
+ }
+ if (csalpha(*p) && (p[1] == '\0' || p[1] == ' ' || p[1] == '\n')) {
+ error("scaling indicators not allowed in arguments for X import command");
+ return;
+ }
+ while (*p == ' ' || *p == '\n')
+ p++;
+ if (nparms < 5) {
+ if (*p == '\0')
+ error("too few arguments for X import command");
+ else
+ error("invalid argument `%1' for X import command", p);
+ return;
+ }
+ if (*p != '\0') {
+ error("superflous argument `%1' for X import command", p);
+ return;
+ }
+ int llx = parms[0];
+ int lly = parms[1];
+ int urx = parms[2];
+ int ury = parms[3];
+ int desired_width = parms[4];
+ int desired_height = parms[5];
+ if (desired_width <= 0) {
+ error("bad width argument `%1' for X import command: must be > 0",
+ desired_width);
+ return;
+ }
+ if (nparms == 6 && desired_height <= 0) {
+ error("bad height argument `%1' for X import command: must be > 0",
+ desired_height);
+ return;
+ }
+ if (llx == urx) {
+ error("llx and urx arguments for X import command must not be equal");
+ return;
+ }
+ if (lly == ury) {
+ error("lly and ury arguments for X import command must not be equal");
+ return;
+ }
+ if (nparms == 5) {
+ int old_wid = urx - llx;
+ int old_ht = ury - lly;
+ if (old_wid < 0)
+ old_wid = -old_wid;
+ if (old_ht < 0)
+ old_ht = -old_ht;
+ desired_height = int(desired_width*(double(old_ht)/double(old_wid)) + .5);
+ }
+ if (env->vpos - desired_height < 0)
+ warning("top of imported graphic is above the top of the page");
+ out.put_number(llx)
+ .put_number(lly)
+ .put_fix_number(desired_width)
+ .put_number(urx - llx)
+ .put_fix_number(-desired_height)
+ .put_number(ury - lly)
+ .put_fix_number(env->hpos)
+ .put_fix_number(env->vpos)
+ .put_symbol("PBEGIN");
+ rm.import_file(arg, out);
+ // do this here just in case application defines PEND
+ out.put_symbol("end");
+ out.put_symbol("PEND");
+}
+
+void ps_printer::do_invis(char *, const environment *)
+{
+ invis_count++;
+}
+
+void ps_printer::do_endinvis(char *, const environment *)
+{
+ if (invis_count == 0)
+ error("unbalanced `endinvis' command");
+ else
+ --invis_count;
+}
+
+printer *make_printer()
+{
+ return new ps_printer;
+}
+
+static void usage();
+
+int main(int argc, char **argv)
+{
+ program_name = argv[0];
+ static char stderr_buf[BUFSIZ];
+ setbuf(stderr, stderr_buf);
+ int c;
+ while ((c = getopt(argc, argv, "F:glc:w:vb:")) != EOF)
+ switch(c) {
+ case 'v':
+ {
+ extern const char *version_string;
+ fprintf(stderr, "grops version %s\n", version_string);
+ fflush(stderr);
+ break;
+ }
+ case 'c':
+ if (sscanf(optarg, "%d", &ncopies) != 1 || ncopies <= 0) {
+ error("bad number of copies `%s'", optarg);
+ ncopies = 1;
+ }
+ break;
+ case 'g':
+ guess_flag = 1;
+ break;
+ case 'l':
+ landscape_flag = 1;
+ break;
+ case 'F':
+ font::command_line_font_dir(optarg);
+ break;
+ case 'w':
+ if (sscanf(optarg, "%d", &linewidth) != 1 || linewidth < 0) {
+ error("bad linewidth `%s'", optarg);
+ linewidth = -1;
+ }
+ break;
+ case 'b':
+ // XXX check this
+ broken_flags = atoi(optarg);
+ bflag = 1;
+ break;
+ case '?':
+ usage();
+ break;
+ default:
+ assert(0);
+ }
+ font::set_unknown_desc_command_handler(handle_unknown_desc_command);
+ if (optind >= argc)
+ do_file("-");
+ else {
+ for (int i = optind; i < argc; i++)
+ do_file(argv[i]);
+ }
+ delete pr;
+ return 0;
+}
+
+static void usage()
+{
+ fprintf(stderr, "usage: %s [-glv] [-b n] [-c n] [-w n] [-F dir] [files ...]\n",
+ program_name);
+ exit(1);
+}
diff --git a/gnu/usr.bin/groff/grops/ps.h b/gnu/usr.bin/groff/grops/ps.h
new file mode 100644
index 0000000..50be4e8
--- /dev/null
+++ b/gnu/usr.bin/groff/grops/ps.h
@@ -0,0 +1,122 @@
+// -*- C++ -*-
+/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
+ Written by James Clark (jjc@jclark.com)
+
+This file is part of groff.
+
+groff is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
+
+groff is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License along
+with groff; see the file COPYING. If not, write to the Free Software
+Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+class ps_output {
+public:
+ ps_output(FILE *, int max_line_length);
+ ps_output &put_string(const char *, int);
+ ps_output &put_number(int);
+ ps_output &put_fix_number(int);
+ ps_output &put_float(double);
+ ps_output &put_symbol(const char *);
+ ps_output &put_literal_symbol(const char *);
+ ps_output &set_fixed_point(int);
+ ps_output &simple_comment(const char *);
+ ps_output &begin_comment(const char *);
+ ps_output &comment_arg(const char *);
+ ps_output &end_comment();
+ ps_output &set_file(FILE *);
+ ps_output &include_file(FILE *);
+ ps_output &copy_file(FILE *);
+ ps_output &end_line();
+ ps_output &put_delimiter(char);
+ ps_output &special(const char *);
+ FILE *get_file();
+private:
+ FILE *fp;
+ int col;
+ int max_line_length; // not including newline
+ int need_space;
+ int fixed_point;
+};
+
+inline FILE *ps_output::get_file()
+{
+ return fp;
+}
+
+enum resource_type {
+ RESOURCE_FONT,
+ RESOURCE_PROCSET,
+ RESOURCE_FILE,
+ RESOURCE_ENCODING,
+ RESOURCE_FORM,
+ RESOURCE_PATTERN
+ };
+
+struct resource;
+
+extern string an_empty_string;
+
+class resource_manager {
+public:
+ resource_manager();
+ ~resource_manager();
+ void import_file(const char *filename, ps_output &);
+ void need_font(const char *name);
+ void print_header_comments(ps_output &);
+ void document_setup(ps_output &);
+ void output_prolog(ps_output &);
+private:
+ unsigned extensions;
+ unsigned language_level;
+ resource *procset_resource;
+ resource *resource_list;
+ resource *lookup_resource(resource_type type, string &name,
+ string &version = an_empty_string,
+ unsigned revision = 0);
+ resource *lookup_font(const char *name);
+ void read_download_file();
+ void supply_resource(resource *r, int rank, FILE *outfp,
+ int is_document = 0);
+ void process_file(int rank, FILE *fp, const char *filename, FILE *outfp);
+ resource *read_file_arg(const char **);
+ resource *read_procset_arg(const char **);
+ resource *read_font_arg(const char **);
+ resource *read_resource_arg(const char **);
+ void print_resources_comment(unsigned flag, FILE *outfp);
+ void print_extensions_comment(FILE *outfp);
+ void print_language_level_comment(FILE *outfp);
+ int do_begin_resource(const char *ptr, int rank, FILE *fp, FILE *outfp);
+ int do_include_resource(const char *ptr, int rank, FILE *fp, FILE *outfp);
+ int do_begin_document(const char *ptr, int rank, FILE *fp, FILE *outfp);
+ int do_include_document(const char *ptr, int rank, FILE *fp, FILE *outfp);
+ int do_begin_procset(const char *ptr, int rank, FILE *fp, FILE *outfp);
+ int do_include_procset(const char *ptr, int rank, FILE *fp, FILE *outfp);
+ int do_begin_font(const char *ptr, int rank, FILE *fp, FILE *outfp);
+ int do_include_font(const char *ptr, int rank, FILE *fp, FILE *outfp);
+ int do_begin_file(const char *ptr, int rank, FILE *fp, FILE *outfp);
+ int do_include_file(const char *ptr, int rank, FILE *fp, FILE *outfp);
+ int change_to_end_resource(const char *ptr, int rank, FILE *fp, FILE *outfp);
+ int do_begin_preview(const char *ptr, int rank, FILE *fp, FILE *outfp);
+ int do_begin_data(const char *ptr, int rank, FILE *fp, FILE *outfp);
+ int do_begin_binary(const char *ptr, int rank, FILE *fp, FILE *outfp);
+};
+
+extern unsigned broken_flags;
+
+// broken_flags is ored from these
+
+enum {
+ NO_SETUP_SECTION = 01,
+ STRIP_PERCENT_BANG = 02,
+ STRIP_STRUCTURE_COMMENTS = 04,
+ USE_PS_ADOBE_2_0 = 010
+};
diff --git a/gnu/usr.bin/groff/grops/psfig.diff b/gnu/usr.bin/groff/grops/psfig.diff
new file mode 100644
index 0000000..5be080d
--- /dev/null
+++ b/gnu/usr.bin/groff/grops/psfig.diff
@@ -0,0 +1,106 @@
+These are patches to makes psfig work with groff. They apply to the
+version of psfig in comp.sources.unix/Volume11. After applying them,
+psfig should be recompiled with -DGROFF. The resulting psfig will
+work only with groff, so you might want to install it under a
+different name. The output of this psfig must be processed using the
+macros in the file ../tmac/tmac.psfig. These will automatically add
+the necessary PostScript code to the prologue output by grops. Use of
+the `global' feature in psfig will result in non-conformant PostScript
+which will fail if processed by a page reversal program. Note that
+psfig is unsupported by me (I'm not interested in hearing about psfig
+problems.) For new documents, I recommend using the PostScript
+inclusion features provided by grops.
+
+James Clark
+jjc@jclark.com
+
+*** cmds.c.~1~ Thu Feb 14 16:09:45 1991
+--- cmds.c Mon Mar 4 12:49:26 1991
+***************
+*** 245,253 ****
+--- 245,261 ----
+ (void) sprintf(x, "%.2fp", fx);
+ (void) sprintf(y, "%.2fp", fy);
+ } else if (!*x) {
++ #ifndef GROFF
+ (void) sprintf(x,"(%.2fp*%s/%.2fp)", fx, y, fy);
++ #else /* GROFF */
++ (void) sprintf(x,"(%.0fu*%s/%.0fu)", fx, y, fy);
++ #endif /* GROFF */
+ } else if (!*y) {
++ #ifndef GROFF
+ (void) sprintf(y,"(%.2fp*%s/%.2fp)", fy, x, fx);
++ #else /* GROFF */
++ (void) sprintf(y,"(%.0fu*%s/%.0fu)", fy, x, fx);
++ #endif /* GROFF */
+ }
+
+ /*
+*** troff.c.~1~ Thu Feb 14 16:09:48 1991
+--- troff.c Mon Mar 4 12:48:46 1991
+***************
+*** 26,32 ****
+--- 26,36 ----
+ }
+
+
++ #ifndef GROFF
+ char incl_file_s[] = "\\X'f%s'";
++ #else /* GROFF */
++ char incl_file_s[] = "\\X'ps: file %s'";
++ #endif /* GROFF */
+ includeFile(filenm)
+ char *filenm; {
+ printf(incl_file_s, filenm);
+***************
+*** 40,52 ****
+--- 44,64 ----
+ error("buffer overflow");
+ }
+
++ #ifndef GROFF
+ char endfig_s[] = "\\X'pendFig'";
++ #else /* GROFF */
++ char endfig_s[] = "\\X'ps: exec psfigend'";
++ #endif /* GROFF */
+ endfig() {
+ printf(endfig_s);
+ }
+
+ char startfig_s[] =
++ #ifndef GROFF
+ "\\X'p\\w@\\h@%s@@'\\X'p\\w@\\h@%s@@'\\X'p%.2f'\\X'p%.2f'\\X'p%.2f'\\X'p%.2f'\\X'pstartFig'";
++ #else /* GROFF */
++ "\\X'ps: exec \\w@\\h@%s@@ \\w@\\h@%s@@ %.2f %.2f %.2f %.2f psfigstart'";
++ #endif /* GROFF */
+
+ startfig(x, y, llx, lly, urx, ury)
+ char *x, *y;
+***************
+*** 57,63 ****
+--- 69,79 ----
+ }
+
+ emitDoClip() {
++ #ifndef GROFF
+ printf("\\X'pdoclip'");
++ #else /* GROFF */
++ printf("\\X'ps: exec psfigclip'");
++ #endif /* GROFF */
+ }
+
+ flushX()
+***************
+*** 116,122 ****
+--- 132,142 ----
+
+ #define isWhite(ch) ((ch) == ' ' || (ch) == '\t' || (ch) == '\n')
+
++ #ifndef GROFF
+ char literal_s[] = "\\X'p%s'";
++ #else /* GROFF */
++ char literal_s[] = "\\X'ps: exec %s'";
++ #endif /* GROFF */
+ emitLiteral(text)
+ char *text; {
+ static char litbuf[BUFSZ];
diff --git a/gnu/usr.bin/groff/grops/psrm.cc b/gnu/usr.bin/groff/grops/psrm.cc
new file mode 100644
index 0000000..95492c7
--- /dev/null
+++ b/gnu/usr.bin/groff/grops/psrm.cc
@@ -0,0 +1,1091 @@
+// -*- C++ -*-
+/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
+ Written by James Clark (jjc@jclark.com)
+
+This file is part of groff.
+
+groff is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
+
+groff is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License along
+with groff; see the file COPYING. If not, write to the Free Software
+Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "driver.h"
+#include "stringclass.h"
+#include "cset.h"
+
+#include "ps.h"
+
+#define PROLOGUE "prologue"
+
+static void print_ps_string(const string &s, FILE *outfp);
+
+cset white_space("\n\r \t");
+string an_empty_string;
+
+const char *extension_table[] = {
+ "DPS",
+ "CMYK",
+ "Composite",
+ "FileSystem",
+};
+
+const int NEXTENSIONS = sizeof(extension_table)/sizeof(extension_table[0]);
+
+const char *resource_table[] = {
+ "font",
+ "procset",
+ "file",
+ "encoding",
+ "form",
+ "pattern",
+};
+
+const int NRESOURCES = sizeof(resource_table)/sizeof(resource_table[0]);
+
+struct resource {
+ resource *next;
+ resource_type type;
+ string name;
+ enum { NEEDED = 01, SUPPLIED = 02, FONT_NEEDED = 04, BUSY = 010 };
+ unsigned flags;
+ string version;
+ unsigned revision;
+ char *filename;
+ int rank;
+ resource(resource_type, string &, string & = an_empty_string, unsigned = 0);
+ ~resource();
+ void print_type_and_name(FILE *outfp);
+};
+
+resource::resource(resource_type t, string &n, string &v, unsigned r)
+: type(t), revision(r), flags (0), filename(0), rank(-1), next(0)
+{
+ name.move(n);
+ version.move(v);
+ if (type == RESOURCE_FILE) {
+ if (name.search('\0') >= 0)
+ error("filename contains a character with code 0");
+ filename = name.extract();
+ }
+}
+
+resource::~resource()
+{
+ a_delete filename;
+}
+
+void resource::print_type_and_name(FILE *outfp)
+{
+ fputs(resource_table[type], outfp);
+ putc(' ', outfp);
+ print_ps_string(name, outfp);
+ if (type == RESOURCE_PROCSET) {
+ putc(' ', outfp);
+ print_ps_string(version, outfp);
+ fprintf(outfp, " %u", revision);
+ }
+}
+
+resource_manager::resource_manager()
+: resource_list(0), extensions(0), language_level(0)
+{
+ read_download_file();
+ string procset_name("grops");
+ extern const char *version_string;
+ string procset_version(version_string);
+ procset_resource = lookup_resource(RESOURCE_PROCSET, procset_name,
+ procset_version, 0);
+ procset_resource->flags |= resource::SUPPLIED;
+}
+
+resource_manager::~resource_manager()
+{
+ while (resource_list) {
+ resource *tem = resource_list;
+ resource_list = resource_list->next;
+ delete tem;
+ }
+}
+
+resource *resource_manager::lookup_resource(resource_type type,
+ string &name,
+ string &version,
+ unsigned revision)
+{
+ for (resource *r = resource_list; r; r = r->next)
+ if (r->type == type
+ && r->name == name
+ && r->version == version
+ && r->revision == revision)
+ return r;
+ r = new resource(type, name, version, revision);
+ r->next = resource_list;
+ resource_list = r;
+ return r;
+}
+
+// Just a specialized version of lookup_resource().
+
+resource *resource_manager::lookup_font(const char *name)
+{
+ for (resource *r = resource_list; r; r = r->next)
+ if (r->type == RESOURCE_FONT
+ && strlen(name) == r->name.length()
+ && memcmp(name, r->name.contents(), r->name.length()) == 0)
+ return r;
+ string s(name);
+ r = new resource(RESOURCE_FONT, s);
+ r->next = resource_list;
+ resource_list = r;
+ return r;
+}
+
+void resource_manager::need_font(const char *name)
+{
+ lookup_font(name)->flags |= resource::FONT_NEEDED;
+}
+
+typedef resource *Presource; // Work around g++ bug.
+
+void resource_manager::document_setup(ps_output &out)
+{
+ int nranks = 0;
+ for (resource *r = resource_list; r; r = r->next)
+ if (r->rank >= nranks)
+ nranks = r->rank + 1;
+ if (nranks > 0) {
+ // Sort resource_list in reverse order of rank.
+ Presource *head = new Presource[nranks + 1];
+ Presource **tail = new Presource *[nranks + 1];
+ for (int i = 0; i < nranks + 1; i++) {
+ head[i] = 0;
+ tail[i] = &head[i];
+ }
+ for (r = resource_list; r; r = r->next) {
+ i = r->rank < 0 ? 0 : r->rank + 1;
+ *tail[i] = r;
+ tail[i] = &(*tail[i])->next;
+ }
+ resource_list = 0;
+ for (i = 0; i < nranks + 1; i++)
+ if (head[i]) {
+ *tail[i] = resource_list;
+ resource_list = head[i];
+ }
+ a_delete head;
+ a_delete tail;
+ // check it
+ for (r = resource_list; r; r = r->next)
+ if (r->next)
+ assert(r->rank >= r->next->rank);
+ for (r = resource_list; r; r = r->next)
+ if (r->type == RESOURCE_FONT && r->rank >= 0)
+ supply_resource(r, -1, out.get_file());
+ }
+}
+
+void resource_manager::print_resources_comment(unsigned flag, FILE *outfp)
+{
+ int continued = 0;
+ for (resource *r = resource_list; r; r = r->next)
+ if (r->flags & flag) {
+ if (continued)
+ fputs("%%+ ", outfp);
+ else {
+ fputs(flag == resource::NEEDED
+ ? "%%DocumentNeededResources: "
+ : "%%DocumentSuppliedResources: ",
+ outfp);
+ continued = 1;
+ }
+ r->print_type_and_name(outfp);
+ putc('\n', outfp);
+ }
+}
+
+void resource_manager::print_header_comments(ps_output &out)
+{
+ for (resource *r = resource_list; r; r = r->next)
+ if (r->type == RESOURCE_FONT && (r->flags & resource::FONT_NEEDED))
+ supply_resource(r, 0, 0);
+ print_resources_comment(resource::NEEDED, out.get_file());
+ print_resources_comment(resource::SUPPLIED, out.get_file());
+ print_language_level_comment(out.get_file());
+ print_extensions_comment(out.get_file());
+}
+
+void resource_manager::output_prolog(ps_output &out)
+{
+ FILE *outfp = out.get_file();
+ out.end_line();
+ char *path;
+ FILE *fp = font::open_file(PROLOGUE, &path);
+ if (!fp)
+ fatal("can't find `%1'", PROLOGUE);
+ fputs("%%BeginResource: ", outfp);
+ procset_resource->print_type_and_name(outfp);
+ putc('\n', outfp);
+ process_file(-1, fp, path, outfp);
+ fclose(fp);
+ a_delete path;
+ fputs("%%EndResource\n", outfp);
+}
+
+void resource_manager::import_file(const char *filename, ps_output &out)
+{
+ out.end_line();
+ string name(filename);
+ resource *r = lookup_resource(RESOURCE_FILE, name);
+ supply_resource(r, -1, out.get_file(), 1);
+}
+
+void resource_manager::supply_resource(resource *r, int rank, FILE *outfp,
+ int is_document)
+{
+ if (r->flags & resource::BUSY) {
+ r->name += '\0';
+ fatal("loop detected in dependency graph for %1 `%2'",
+ resource_table[r->type],
+ r->name.contents());
+ }
+ r->flags |= resource::BUSY;
+ if (rank > r->rank)
+ r->rank = rank;
+ char *path;
+ FILE *fp = 0;
+ if (r->filename != 0) {
+ if (r->type == RESOURCE_FONT) {
+ fp = font::open_file(r->filename, &path);
+ if (!fp) {
+ error("can't find `%1'", r->filename);
+ a_delete r->filename;
+ r->filename = 0;
+ }
+ }
+ else {
+ errno = 0;
+ fp = fopen(r->filename, "r");
+ if (!fp) {
+ error("can't open `%1': %2", r->filename, strerror(errno));
+ a_delete r->filename;
+ r->filename = 0;
+ }
+ else
+ path = r->filename;
+ }
+ }
+ if (fp) {
+ if (outfp) {
+ if (r->type == RESOURCE_FILE && is_document) {
+ fputs("%%BeginDocument: ", outfp);
+ print_ps_string(r->name, outfp);
+ putc('\n', outfp);
+ }
+ else {
+ fputs("%%BeginResource: ", outfp);
+ r->print_type_and_name(outfp);
+ putc('\n', outfp);
+ }
+ }
+ process_file(rank, fp, path, outfp);
+ fclose(fp);
+ if (r->type == RESOURCE_FONT)
+ a_delete path;
+ if (outfp) {
+ if (r->type == RESOURCE_FILE && is_document)
+ fputs("%%EndDocument\n", outfp);
+ else
+ fputs("%%EndResource\n", outfp);
+ }
+ r->flags |= resource::SUPPLIED;
+ }
+ else {
+ if (outfp) {
+ if (r->type == RESOURCE_FILE && is_document) {
+ fputs("%%IncludeDocument: ", outfp);
+ print_ps_string(r->name, outfp);
+ putc('\n', outfp);
+ }
+ else {
+ fputs("%%IncludeResource: ", outfp);
+ r->print_type_and_name(outfp);
+ putc('\n', outfp);
+ }
+ }
+ r->flags |= resource::NEEDED;
+ }
+ r->flags &= ~resource::BUSY;
+}
+
+
+#define PS_LINE_MAX 255
+#define PS_MAGIC "%!PS-Adobe-"
+
+static int ps_get_line(char *buf, FILE *fp)
+{
+ int c = getc(fp);
+ if (c == EOF) {
+ buf[0] = '\0';
+ return 0;
+ }
+ current_lineno++;
+ int i = 0;
+ int err = 0;
+ while (c != '\r' && c != '\n' && c != EOF) {
+ if ((c < 0x1b && !white_space(c)) || c == 0x7f)
+ error("illegal input character code %1", int(c));
+ else if (i < PS_LINE_MAX)
+ buf[i++] = c;
+ else if (!err) {
+ err = 1;
+ error("PostScript file non-conforming "
+ "because length of line exceeds 255");
+ }
+ c = getc(fp);
+ }
+ buf[i++] = '\n';
+ buf[i] = '\0';
+ if (c == '\r') {
+ c = getc(fp);
+ if (c != EOF && c != '\n')
+ ungetc(c, fp);
+ }
+ return 1;
+}
+
+static int read_text_arg(const char **pp, string &res)
+{
+ res.clear();
+ while (white_space(**pp))
+ *pp += 1;
+ if (**pp == '\0') {
+ error("missing argument");
+ return 0;
+ }
+ if (**pp != '(') {
+ for (; **pp != '\0' && !white_space(**pp); *pp += 1)
+ res += **pp;
+ return 1;
+ }
+ *pp += 1;
+ res.clear();
+ int level = 0;
+ for (;;) {
+ if (**pp == '\0' || **pp == '\r' || **pp == '\n') {
+ error("missing ')'");
+ return 0;
+ }
+ if (**pp == ')') {
+ if (level == 0) {
+ *pp += 1;
+ break;
+ }
+ res += **pp;
+ level--;
+ }
+ else if (**pp == '(') {
+ level++;
+ res += **pp;
+ }
+ else if (**pp == '\\') {
+ *pp += 1;
+ switch (**pp) {
+ case 'n':
+ res += '\n';
+ break;
+ case 'r':
+ res += '\n';
+ break;
+ case 't':
+ res += '\t';
+ break;
+ case 'b':
+ res += '\b';
+ break;
+ case 'f':
+ res += '\f';
+ break;
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ {
+ int val = **pp - '0';
+ if ((*pp)[1] >= '0' && (*pp)[1] <= '7') {
+ *pp += 1;
+ val = val*8 + (**pp - '0');
+ if ((*pp)[1] >= '0' && (*pp)[1] <= '7') {
+ *pp += 1;
+ val = val*8 + (**pp - '0');
+ }
+ }
+ }
+ break;
+ default:
+ res += **pp;
+ break;
+ }
+ }
+ else
+ res += **pp;
+ *pp += 1;
+ }
+ return 1;
+}
+
+static int read_uint_arg(const char **pp, unsigned *res)
+{
+ while (white_space(**pp))
+ *pp += 1;
+ if (**pp == '\0') {
+ error("missing argument");
+ return 0;
+ }
+ const char *start = *pp;
+ // XXX use strtoul
+ long n = strtol(start, (char **)pp, 10);
+ if (n == 0 && *pp == start) {
+ error("not an integer");
+ return 0;
+ }
+ if (n < 0) {
+ error("argument must not be negative");
+ return 0;
+ }
+ *res = unsigned(n);
+ return 1;
+}
+
+resource *resource_manager::read_file_arg(const char **ptr)
+{
+ string arg;
+ if (!read_text_arg(ptr, arg))
+ return 0;
+ return lookup_resource(RESOURCE_FILE, arg);
+}
+
+resource *resource_manager::read_font_arg(const char **ptr)
+{
+ string arg;
+ if (!read_text_arg(ptr, arg))
+ return 0;
+ return lookup_resource(RESOURCE_FONT, arg);
+}
+
+resource *resource_manager::read_procset_arg(const char **ptr)
+{
+ string arg;
+ if (!read_text_arg(ptr, arg))
+ return 0;
+ string version;
+ if (!read_text_arg(ptr, version))
+ return 0;
+ unsigned revision;
+ if (!read_uint_arg(ptr, &revision))
+ return 0;
+ return lookup_resource(RESOURCE_PROCSET, arg, version, revision);
+}
+
+resource *resource_manager::read_resource_arg(const char **ptr)
+{
+ while (white_space(**ptr))
+ *ptr += 1;
+ const char *name = *ptr;
+ while (**ptr != '\0' && !white_space(**ptr))
+ *ptr += 1;
+ if (name == *ptr) {
+ error("missing resource type");
+ return 0;
+ }
+ for (int ri = 0; ri < NRESOURCES; ri++)
+ if (strlen(resource_table[ri]) == *ptr - name
+ && memcmp(resource_table[ri], name, *ptr - name) == 0)
+ break;
+ if (ri >= NRESOURCES) {
+ error("unknown resource type");
+ return 0;
+ }
+ if (ri == RESOURCE_PROCSET)
+ return read_procset_arg(ptr);
+ string arg;
+ if (!read_text_arg(ptr, arg))
+ return 0;
+ return lookup_resource(resource_type(ri), arg);
+}
+
+static const char *matches_comment(const char *buf, const char *comment)
+{
+ if (buf[0] != '%' || buf[1] != '%')
+ return 0;
+ for (buf += 2; *comment; comment++, buf++)
+ if (*buf != *comment)
+ return 0;
+ if (comment[-1] == ':')
+ return buf;
+ if (*buf == '\0' || white_space(*buf))
+ return buf;
+ return 0;
+}
+
+// Return 1 if the line should be copied out.
+
+int resource_manager::do_begin_resource(const char *ptr, int, FILE *,
+ FILE *)
+{
+ resource *r = read_resource_arg(&ptr);
+ if (r)
+ r->flags |= resource::SUPPLIED;
+ return 1;
+}
+
+int resource_manager::do_include_resource(const char *ptr, int rank, FILE *,
+ FILE *outfp)
+{
+ resource *r = read_resource_arg(&ptr);
+ if (r) {
+ if (r->type == RESOURCE_FONT) {
+ if (rank >= 0)
+ supply_resource(r, rank + 1, outfp);
+ else
+ r->flags |= resource::FONT_NEEDED;
+ }
+ else
+ supply_resource(r, rank, outfp);
+ }
+ return 0;
+}
+
+int resource_manager::do_begin_document(const char *ptr, int, FILE *,
+ FILE *)
+{
+ resource *r = read_file_arg(&ptr);
+ if (r)
+ r->flags |= resource::SUPPLIED;
+ return 1;
+}
+
+int resource_manager::do_include_document(const char *ptr, int rank, FILE *,
+ FILE *outfp)
+{
+ resource *r = read_file_arg(&ptr);
+ if (r)
+ supply_resource(r, rank, outfp, 1);
+ return 0;
+}
+
+int resource_manager::do_begin_procset(const char *ptr, int, FILE *,
+ FILE *outfp)
+{
+ resource *r = read_procset_arg(&ptr);
+ if (r) {
+ r->flags |= resource::SUPPLIED;
+ if (outfp) {
+ fputs("%%BeginResource: ", outfp);
+ r->print_type_and_name(outfp);
+ putc('\n', outfp);
+ }
+ }
+ return 0;
+}
+
+int resource_manager::do_include_procset(const char *ptr, int rank, FILE *,
+ FILE *outfp)
+{
+ resource *r = read_procset_arg(&ptr);
+ if (r)
+ supply_resource(r, rank, outfp);
+ return 0;
+}
+
+int resource_manager::do_begin_file(const char *ptr, int, FILE *,
+ FILE *outfp)
+{
+ resource *r = read_file_arg(&ptr);
+ if (r) {
+ r->flags |= resource::SUPPLIED;
+ if (outfp) {
+ fputs("%%BeginResource: ", outfp);
+ r->print_type_and_name(outfp);
+ putc('\n', outfp);
+ }
+ }
+ return 0;
+}
+
+int resource_manager::do_include_file(const char *ptr, int rank, FILE *,
+ FILE *outfp)
+{
+ resource *r = read_file_arg(&ptr);
+ if (r)
+ supply_resource(r, rank, outfp);
+ return 0;
+}
+
+int resource_manager::do_begin_font(const char *ptr, int, FILE *,
+ FILE *outfp)
+{
+ resource *r = read_font_arg(&ptr);
+ if (r) {
+ r->flags |= resource::SUPPLIED;
+ if (outfp) {
+ fputs("%%BeginResource: ", outfp);
+ r->print_type_and_name(outfp);
+ putc('\n', outfp);
+ }
+ }
+ return 0;
+}
+
+int resource_manager::do_include_font(const char *ptr, int rank, FILE *,
+ FILE *outfp)
+{
+ resource *r = read_font_arg(&ptr);
+ if (r) {
+ if (rank >= 0)
+ supply_resource(r, rank + 1, outfp);
+ else
+ r->flags |= resource::FONT_NEEDED;
+ }
+ return 0;
+}
+
+int resource_manager::change_to_end_resource(const char *, int, FILE *,
+ FILE *outfp)
+{
+ if (outfp)
+ fputs("%%EndResource\n", outfp);
+ return 0;
+}
+
+int resource_manager::do_begin_preview(const char *, int, FILE *fp, FILE *)
+{
+ char buf[PS_LINE_MAX + 2];
+ do {
+ if (!ps_get_line(buf, fp)) {
+ error("end of file in preview section");
+ break;
+ }
+ } while (!matches_comment(buf, "EndPreview"));
+ return 0;
+}
+
+int read_one_of(const char **ptr, const char **s, int n)
+{
+ while (white_space(**ptr))
+ *ptr += 1;
+ if (**ptr == '\0')
+ return -1;
+ const char *start = *ptr;
+ do {
+ ++ptr;
+ } while (**ptr != '\0' && !white_space(**ptr));
+ for (int i = 0; i < n; i++)
+ if (strlen(s[i]) == *ptr - start
+ && memcmp(s[i], start, *ptr - start) == 0)
+ return i;
+ return -1;
+}
+
+int resource_manager::do_begin_data(const char *ptr, int, FILE *fp,
+ FILE *outfp)
+{
+ while (white_space(*ptr))
+ ptr++;
+ const char *start = ptr;
+ unsigned numberof;
+ if (!read_uint_arg(&ptr, &numberof))
+ return 0;
+ static const char *types[] = { "Binary", "Hex", "ASCII" };
+ const int Binary = 0;
+ int type = 0;
+ static const char *units[] = { "Bytes", "Lines" };
+ const int Bytes = 0;
+ int unit = Bytes;
+ while (white_space(*ptr))
+ ptr++;
+ if (*ptr != '\0') {
+ type = read_one_of(&ptr, types, 3);
+ if (type < 0) {
+ error("bad data type");
+ return 0;
+ }
+ while (white_space(*ptr))
+ ptr++;
+ if (*ptr != '\0') {
+ unit = read_one_of(&ptr, units, 2);
+ if (unit < 0) {
+ error("expected `Bytes' or `Lines'");
+ return 0;
+ }
+ }
+ }
+ if (type != Binary)
+ return 1;
+ if (outfp) {
+ fputs("%%BeginData: ", outfp);
+ fputs(start, outfp);
+ }
+ if (numberof > 0) {
+ unsigned bytecount = 0;
+ unsigned linecount = 0;
+ do {
+ int c = getc(fp);
+ if (c == EOF) {
+ error("end of file within data section");
+ return 0;
+ }
+ if (outfp)
+ putc(c, outfp);
+ bytecount++;
+ if (c == '\r') {
+ int cc = getc(fp);
+ if (cc != '\n') {
+ linecount++;
+ current_lineno++;
+ }
+ if (cc != EOF)
+ ungetc(c, fp);
+ }
+ else if (c == '\n') {
+ linecount++;
+ current_lineno++;
+ }
+ } while ((unit == Bytes ? bytecount : linecount) < numberof);
+ }
+ char buf[PS_LINE_MAX + 2];
+ if (!ps_get_line(buf, fp)) {
+ error("missing %%%%EndData line");
+ return 0;
+ }
+ if (!matches_comment(buf, "EndData"))
+ error("bad %%%%EndData line");
+ if (outfp)
+ fputs(buf, outfp);
+ return 0;
+}
+
+int resource_manager::do_begin_binary(const char *ptr, int, FILE *fp,
+ FILE *outfp)
+{
+ if (!outfp)
+ return 0;
+ unsigned count;
+ if (!read_uint_arg(&ptr, &count))
+ return 0;
+ if (outfp)
+ fprintf(outfp, "%%%%BeginData: %u Binary Bytes\n", count);
+ while (count != 0) {
+ int c = getc(fp);
+ if (c == EOF) {
+ error("end of file within binary section");
+ return 0;
+ }
+ if (outfp)
+ putc(c, outfp);
+ --count;
+ if (c == '\r') {
+ int cc = getc(fp);
+ if (cc != '\n')
+ current_lineno++;
+ if (cc != EOF)
+ ungetc(c, fp);
+ }
+ else if (c == '\n')
+ current_lineno++;
+ }
+ char buf[PS_LINE_MAX + 2];
+ if (!ps_get_line(buf, fp)) {
+ error("missing %%%%EndBinary line");
+ return 0;
+ }
+ if (!matches_comment(buf, "EndBinary")) {
+ error("bad %%%%EndBinary line");
+ if (outfp)
+ fputs(buf, outfp);
+ }
+ else if (outfp)
+ fputs("%%EndData\n", outfp);
+ return 0;
+}
+
+static unsigned parse_extensions(const char *ptr)
+{
+ unsigned flags = 0;
+ for (;;) {
+ while (white_space(*ptr))
+ ptr++;
+ if (*ptr == '\0')
+ break;
+ const char *name = ptr;
+ do {
+ ++ptr;
+ } while (*ptr != '\0' && !white_space(*ptr));
+ for (int i = 0; i < NEXTENSIONS; i++)
+ if (strlen(extension_table[i]) == ptr - name
+ && memcmp(extension_table[i], name, ptr - name) == 0) {
+ flags |= (1 << i);
+ break;
+ }
+ if (i >= NEXTENSIONS) {
+ string s(name, ptr - name);
+ s += '\0';
+ error("unknown extension `%1'", s.contents());
+ }
+ }
+ return flags;
+}
+
+// XXX if it has not been surrounded with {Begin,End}Document need to strip
+// out Page: Trailer {Begin,End}Prolog {Begin,End}Setup sections.
+
+// XXX Perhaps the decision whether to use BeginDocument or
+// BeginResource: file should be postponed till we have seen
+// the first line of the file.
+
+void resource_manager::process_file(int rank, FILE *fp, const char *filename,
+ FILE *outfp)
+{
+ // If none of these comments appear in the header section, and we are
+ // just analyzing the file (ie outfp is 0), then we can return immediately.
+ static const char *header_comment_table[] = {
+ "DocumentNeededResources:",
+ "DocumentSuppliedResources:",
+ "DocumentNeededFonts:",
+ "DocumentSuppliedFonts:",
+ "DocumentNeededProcSets:",
+ "DocumentSuppliedProcSets:",
+ "DocumentNeededFiles:",
+ "DocumentSuppliedFiles:",
+ };
+
+ const int NHEADER_COMMENTS = (sizeof(header_comment_table)
+ / sizeof(header_comment_table[0]));
+ struct comment_info {
+ const char *name;
+ int (resource_manager::*proc)(const char *, int, FILE *, FILE *);
+ };
+
+ static comment_info comment_table[] = {
+ { "BeginResource:", &resource_manager::do_begin_resource },
+ { "IncludeResource:", &resource_manager::do_include_resource },
+ { "BeginDocument:", &resource_manager::do_begin_document },
+ { "IncludeDocument:", &resource_manager::do_include_document },
+ { "BeginProcSet:", &resource_manager::do_begin_procset },
+ { "IncludeProcSet:", &resource_manager::do_include_procset },
+ { "BeginFont:", &resource_manager::do_begin_font },
+ { "IncludeFont:", &resource_manager::do_include_font },
+ { "BeginFile:", &resource_manager::do_begin_file },
+ { "IncludeFile:", &resource_manager::do_include_file },
+ { "EndProcSet", &resource_manager::change_to_end_resource },
+ { "EndFont", &resource_manager::change_to_end_resource },
+ { "EndFile", &resource_manager::change_to_end_resource },
+ { "BeginPreview:", &resource_manager::do_begin_preview },
+ { "BeginData:", &resource_manager::do_begin_data },
+ { "BeginBinary:", &resource_manager::do_begin_binary },
+ };
+
+ const int NCOMMENTS = sizeof(comment_table)/sizeof(comment_table[0]);
+ char buf[PS_LINE_MAX + 2];
+ int saved_lineno = current_lineno;
+ const char *saved_filename = current_filename;
+ current_filename = filename;
+ current_lineno = 0;
+ if (!ps_get_line(buf, fp)) {
+ current_filename = saved_filename;
+ current_lineno = saved_lineno;
+ return;
+ }
+ if (strlen(buf) < sizeof(PS_MAGIC) - 1
+ || memcmp(buf, PS_MAGIC, sizeof(PS_MAGIC) - 1) != 0) {
+ if (outfp) {
+ do {
+ if (!(broken_flags & STRIP_PERCENT_BANG)
+ || buf[0] != '%' || buf[1] != '!')
+ fputs(buf, outfp);
+ } while (ps_get_line(buf, fp));
+ }
+ }
+ else {
+ if (!(broken_flags & STRIP_PERCENT_BANG) && outfp)
+ fputs(buf, outfp);
+ int in_header = 1;
+ int interesting = 0;
+ int had_extensions_comment = 0;
+ int had_language_level_comment = 0;
+ for (;;) {
+ if (!ps_get_line(buf, fp))
+ break;
+ int copy_this_line = 1;
+ if (buf[0] == '%') {
+ if (buf[1] == '%') {
+ const char *ptr;
+ for (int i = 0; i < NCOMMENTS; i++)
+ if (ptr = matches_comment(buf, comment_table[i].name)) {
+ copy_this_line
+ = (this->*(comment_table[i].proc))(ptr, rank, fp, outfp);
+ break;
+ }
+ if (i >= NCOMMENTS && in_header) {
+ if (ptr = matches_comment(buf, "EndComments"))
+ in_header = 0;
+ else if (!had_extensions_comment
+ && (ptr = matches_comment(buf, "Extensions:"))) {
+ extensions |= parse_extensions(ptr);
+ // XXX handle possibility that next line is %%+
+ had_extensions_comment = 1;
+ }
+ else if (!had_language_level_comment
+ && (ptr = matches_comment(buf, "LanguageLevel:"))) {
+ unsigned ll;
+ if (read_uint_arg(&ptr, &ll) && ll > language_level)
+ language_level = ll;
+ had_language_level_comment = 1;
+ }
+ else {
+ for (int i = 0; i < NHEADER_COMMENTS; i++)
+ if (matches_comment(buf, header_comment_table[i])) {
+ interesting = 1;
+ break;
+ }
+ }
+ }
+ if ((broken_flags & STRIP_STRUCTURE_COMMENTS)
+ && (matches_comment(buf, "EndProlog")
+ || matches_comment(buf, "Page:")
+ || matches_comment(buf, "Trailer")))
+ copy_this_line = 0;
+ }
+ else if (buf[1] == '!') {
+ if (broken_flags & STRIP_PERCENT_BANG)
+ copy_this_line = 0;
+ }
+ }
+ else
+ in_header = 0;
+ if (!outfp && !in_header && !interesting)
+ break;
+ if (copy_this_line && outfp)
+ fputs(buf, outfp);
+ }
+ }
+ current_filename = saved_filename;
+ current_lineno = saved_lineno;
+}
+
+void resource_manager::read_download_file()
+{
+ char *path = 0;
+ FILE *fp = font::open_file("download", &path);
+ if (!fp)
+ fatal("can't find `download'");
+ char buf[512];
+ int lineno = 0;
+ while (fgets(buf, sizeof(buf), fp)) {
+ lineno++;
+ char *p = strtok(buf, " \t\r\n");
+ if (p == 0 || *p == '#')
+ continue;
+ char *q = strtok(0, " \t\r\n");
+ if (!q)
+ fatal_with_file_and_line(path, lineno, "missing filename");
+ lookup_font(p)->filename = strsave(q);
+ }
+ a_delete path;
+ fclose(fp);
+}
+
+// XXX Can we share some code with ps_output::put_string()?
+
+static void print_ps_string(const string &s, FILE *outfp)
+{
+ int len = s.length();
+ const char *str = s.contents();
+ int funny = 0;
+ if (str[0] == '(')
+ funny = 1;
+ else {
+ for (int i = 0; i < len; i++)
+ if (str[i] <= 040 || str[i] > 0176) {
+ funny = 1;
+ break;
+ }
+ }
+ if (!funny) {
+ put_string(s, outfp);
+ return;
+ }
+ int level = 0;
+ for (int i = 0; i < len; i++)
+ if (str[i] == '(')
+ level++;
+ else if (str[i] == ')' && --level < 0)
+ break;
+ putc('(', outfp);
+ for (i = 0; i < len; i++)
+ switch (str[i]) {
+ case '(':
+ case ')':
+ if (level != 0)
+ putc('\\', outfp);
+ putc(str[i], outfp);
+ break;
+ case '\\':
+ fputs("\\\\", outfp);
+ break;
+ case '\n':
+ fputs("\\n", outfp);
+ break;
+ case '\r':
+ fputs("\\r", outfp);
+ break;
+ case '\t':
+ fputs("\\t", outfp);
+ break;
+ case '\b':
+ fputs("\\b", outfp);
+ break;
+ case '\f':
+ fputs("\\f", outfp);
+ break;
+ default:
+ if (str[i] < 040 || str[i] > 0176)
+ fprintf(outfp, "\\%03o", str[i] & 0377);
+ else
+ putc(str[i], outfp);
+ break;
+ }
+ putc(')', outfp);
+}
+
+void resource_manager::print_extensions_comment(FILE *outfp)
+{
+ if (extensions) {
+ fputs("%%Extensions:", outfp);
+ for (int i = 0; i < NEXTENSIONS; i++)
+ if (extensions & (1 << i)) {
+ putc(' ', outfp);
+ fputs(extension_table[i], outfp);
+ }
+ putc('\n', outfp);
+ }
+}
+
+void resource_manager::print_language_level_comment(FILE *outfp)
+{
+ if (language_level)
+ fprintf(outfp, "%%%%LanguageLevel: %u\n", language_level);
+}
+
diff --git a/gnu/usr.bin/groff/grotty/Makefile b/gnu/usr.bin/groff/grotty/Makefile
new file mode 100644
index 0000000..18bd9ba
--- /dev/null
+++ b/gnu/usr.bin/groff/grotty/Makefile
@@ -0,0 +1,13 @@
+# Makefile for grotty
+
+PROG= grotty
+SRCS= tty.cc
+CFLAGS+= -I${.CURDIR}/../include
+LDADD+= ${LIBDRIVER} ${LIBGROFF} -lm
+DPADD+= ${LIBDRIVER} ${LIBGROFF} ${LIBM}
+
+MANDEPEND= grotty.1
+CLEANFILES+= ${MANDEPEND}
+
+.include "../Makefile.cfg"
+.include <bsd.prog.mk>
diff --git a/gnu/usr.bin/groff/grotty/Makefile.dep b/gnu/usr.bin/groff/grotty/Makefile.dep
new file mode 100644
index 0000000..eca128e
--- /dev/null
+++ b/gnu/usr.bin/groff/grotty/Makefile.dep
@@ -0,0 +1,2 @@
+tty.o : tty.cc ../include/driver.h ../include/errarg.h ../include/error.h \
+ ../include/font.h ../include/printer.h ../include/lib.h
diff --git a/gnu/usr.bin/groff/grotty/Makefile.sub b/gnu/usr.bin/groff/grotty/Makefile.sub
new file mode 100644
index 0000000..b0002cb
--- /dev/null
+++ b/gnu/usr.bin/groff/grotty/Makefile.sub
@@ -0,0 +1,6 @@
+PROG=grotty
+MAN1=grotty.n
+XLIBS=$(LIBDRIVER) $(LIBGROFF)
+MLIB=$(LIBM)
+OBJS=tty.o
+CCSRCS=tty.cc
diff --git a/gnu/usr.bin/groff/grotty/TODO b/gnu/usr.bin/groff/grotty/TODO
new file mode 100644
index 0000000..3f23dc3
--- /dev/null
+++ b/gnu/usr.bin/groff/grotty/TODO
@@ -0,0 +1,3 @@
+Document font and device description file usage of grotty.
+
+With -h avoid using a tab when a single space will do.
diff --git a/gnu/usr.bin/groff/grotty/grotty.man b/gnu/usr.bin/groff/grotty/grotty.man
new file mode 100644
index 0000000..9e7d31c
--- /dev/null
+++ b/gnu/usr.bin/groff/grotty/grotty.man
@@ -0,0 +1,195 @@
+.\" -*- nroff -*-
+.TH GROTTY @MAN1EXT@ "@MDATE@" "Groff Version @VERSION@"
+.SH NAME
+grotty \- groff driver for typewriter-like devices
+.SH SYNOPSIS
+.B grotty
+[
+.B \-hfbuodBUv
+] [
+.BI \-F dir
+] [
+.IR files \|.\|.\|.
+]
+.SH DESCRIPTION
+.B grotty
+translates the output of GNU
+.B troff
+into a form suitable for typewriter-like devices.
+Normally
+.B grotty
+should invoked by using the
+.B groff
+command
+with a
+.BR \-Tascii ,
+.B \-Tkoi8-r
+or
+.B \-Tlatin1
+option.
+If no files are given,
+.B grotty
+will read the standard input.
+A filename of
+.B \-
+will also cause
+.B grotty
+to read the standard input.
+Output is written to the standard output.
+.LP
+Normally
+.B grotty
+prints a bold character
+.I c
+using the sequence
+.RI ` c
+.SM BACKSPACE
+.IR c '
+and a italic character
+.I c
+by the sequence
+.RB ` _
+.SM BACKSPACE
+.IR c '.
+These sequences can be displayed on a terminal
+by piping through
+.BR ul (1).
+Pagers such as
+.BR more (1)
+or
+.BR less (1)
+are also able to display these sequences.
+Use either
+.B \-B
+or
+.B \-U
+when piping into
+.BR less (1);
+use
+.B \-b
+when piping into
+.BR more (1).
+There is no need to filter the output through
+.BR col (1)
+since
+.B grotty
+never outputs reverse line feeds.
+.LP
+The font description file may contain a command
+.IP
+.BI internalname\ n
+.LP
+where
+.I n
+is a decimal integer.
+If the 01 bit in
+.I n
+is set,
+then the font will be treated as an italic font;
+if the 02 bit is set,
+then it will be treated as a bold font.
+The code field in the font description field gives the
+code which will be used to output the character.
+This code can also be used in the
+.B \eN
+escape sequence in
+.BR troff .
+.SH OPTIONS
+.TP
+.BI \-F dir
+Search the directory
+.IB dir /dev name
+for font and device description files;
+.I name
+is the name of the device, usually
+.BR ascii ,
+.B koi8-r
+or
+.BR latin1 .
+.TP
+.B \-h
+Use horizontal tabs in the output.
+Tabs are assumed to be set every 8 columns.
+.TP
+.B \-f
+Use form feeds in the output.
+A form feed will be output at the end of each page that has no output
+on its last line.
+.TP
+.B \-b
+Suppress the use of overstriking for bold characters.
+.TP
+.B \-u
+Suppress the use of underlining for italic characters.
+.TP
+.B \-B
+Use only overstriking for bold-italic characters.
+.TP
+.B \-U
+Use only underlining for bold-italic characters.
+.TP
+.B \-o
+Suppress overstriking (other than for bold or underlined characters).
+.TP
+.B \-d
+Ignore all
+.B \eD
+commands.
+Without this
+.B grotty
+will render
+.B \eD'l\|.\|.\|.'
+commands that have at least at least one zero argument
+(and so are either horizontal or vertical)
+using
+.BR \- ,
+.B |
+and
+.B +
+characters.
+.TP
+.B \-v
+Print the version number.
+.SH FILES
+.TP
+.B @FONTDIR@/dev\fIname\fB/DESC
+Device description file for
+.I name
+device.
+.TP
+.BI @FONTDIR@/dev\fIname\fB/ F
+Font description file for font
+.I F
+of
+.I name
+device.
+.TP
+.B @MACRODIR@/tmac.tty
+Macros for use with
+.BR grotty .
+.TP
+.B @MACRODIR@/tmac.tty-char
+Additional klugey character definitions for use with
+.BR grotty .
+.SH BUGS
+.LP
+.B grotty
+is intended only for simple documents.
+.LP
+There is no support for fractional horizontal or vertical motions.
+.LP
+There is no support for
+.B \eD
+commands
+other than horizontal and vertical lines.
+.LP
+Characters above the first line (ie with a vertical position of 0)
+cannot be printed.
+.SH "SEE ALSO"
+.BR groff (@MAN1EXT@),
+.BR @g@troff (@MAN1EXT@),
+.BR groff_out (@MAN5EXT@),
+.BR groff_font (@MAN5EXT@),
+.BR groff_char (@MAN7EXT@),
+.BR ul (1),
+.BR more (1)
diff --git a/gnu/usr.bin/groff/grotty/tty.cc b/gnu/usr.bin/groff/grotty/tty.cc
new file mode 100644
index 0000000..087c19c
--- /dev/null
+++ b/gnu/usr.bin/groff/grotty/tty.cc
@@ -0,0 +1,441 @@
+// -*- C++ -*-
+/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
+ Written by James Clark (jjc@jclark.com)
+
+This file is part of groff.
+
+groff is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
+
+groff is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License along
+with groff; see the file COPYING. If not, write to the Free Software
+Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "driver.h"
+
+#ifndef SHRT_MIN
+#define SHRT_MIN (-32768)
+#endif
+
+#ifndef SHRT_MAX
+#define SHRT_MAX 32767
+#endif
+
+#define TAB_WIDTH 8
+
+static int horizontal_tab_flag = 0;
+static int form_feed_flag = 0;
+static int bold_flag = 1;
+static int underline_flag = 1;
+static int overstrike_flag = 1;
+static int draw_flag = 1;
+
+enum {
+ UNDERLINE_MODE = 01,
+ BOLD_MODE = 02,
+ VDRAW_MODE = 04,
+ HDRAW_MODE = 010
+};
+
+// Mode to use for bold-underlining.
+static unsigned char bold_underline_mode = BOLD_MODE|UNDERLINE_MODE;
+
+class tty_font : public font {
+ tty_font(const char *);
+ unsigned char mode;
+public:
+ ~tty_font();
+ unsigned char get_mode() { return mode; }
+#if 0
+ void handle_x_command(int argc, const char **argv);
+#endif
+ static tty_font *load_tty_font(const char *);
+};
+
+tty_font *tty_font::load_tty_font(const char *s)
+{
+ tty_font *f = new tty_font(s);
+ if (!f->load()) {
+ delete f;
+ return 0;
+ }
+ const char *num = f->get_internal_name();
+ long n;
+ if (num != 0 && (n = strtol(num, 0, 0)) != 0)
+ f->mode = int(n & (BOLD_MODE|UNDERLINE_MODE));
+ if (!underline_flag)
+ f->mode &= ~UNDERLINE_MODE;
+ if (!bold_flag)
+ f->mode &= ~BOLD_MODE;
+ if ((f->mode & (BOLD_MODE|UNDERLINE_MODE)) == (BOLD_MODE|UNDERLINE_MODE))
+ f->mode = (f->mode & ~(BOLD_MODE|UNDERLINE_MODE)) | bold_underline_mode;
+ return f;
+}
+
+tty_font::tty_font(const char *nm)
+: font(nm), mode(0)
+{
+}
+
+tty_font::~tty_font()
+{
+}
+
+#if 0
+void tty_font::handle_x_command(int argc, const char **argv)
+{
+ if (argc >= 1 && strcmp(argv[0], "bold") == 0)
+ mode |= BOLD_MODE;
+ else if (argc >= 1 && strcmp(argv[0], "underline") == 0)
+ mode |= UNDERLINE_MODE;
+}
+#endif
+
+class glyph {
+ static glyph *free_list;
+public:
+ glyph *next;
+ short hpos;
+ unsigned char code;
+ unsigned char mode;
+ void *operator new(size_t);
+ void operator delete(void *);
+ inline int draw_mode() { return mode & (VDRAW_MODE|HDRAW_MODE); }
+};
+
+glyph *glyph::free_list = 0;
+
+void *glyph::operator new(size_t)
+{
+ if (!free_list) {
+ const int BLOCK = 1024;
+ free_list = (glyph *)new char[sizeof(glyph)*BLOCK];
+ for (int i = 0; i < BLOCK - 1; i++)
+ free_list[i].next = free_list + i + 1;
+ free_list[BLOCK - 1].next = 0;
+ }
+ glyph *p = free_list;
+ free_list = free_list->next;
+ p->next = 0;
+ return p;
+}
+
+void glyph::operator delete(void *p)
+{
+ if (p) {
+ ((glyph *)p)->next = free_list;
+ free_list = (glyph *)p;
+ }
+}
+
+class tty_printer : public printer {
+ glyph **lines;
+ int nlines;
+ int cached_v;
+ int cached_vpos;
+ void add_char(unsigned char, int, int, unsigned char);
+public:
+ tty_printer();
+ ~tty_printer();
+ void set_char(int, font *, const environment *, int);
+ void draw(int code, int *p, int np, const environment *env);
+ void begin_page(int) { }
+ void end_page(int page_length);
+ font *make_font(const char *);
+};
+
+tty_printer::tty_printer() : cached_v(0)
+{
+ nlines = 66;
+ lines = new glyph *[nlines];
+ for (int i = 0; i < nlines; i++)
+ lines[i] = 0;
+}
+
+tty_printer::~tty_printer()
+{
+ a_delete lines;
+}
+
+void tty_printer::set_char(int i, font *f, const environment *env, int w)
+{
+ if (w != font::hor)
+ fatal("width of character not equal to horizontal resolution");
+ add_char(f->get_code(i), env->hpos, env->vpos, ((tty_font *)f)->get_mode());
+}
+
+void tty_printer::add_char(unsigned char c, int h, int v, unsigned char mode)
+{
+#if 0
+ // This is too expensive.
+ if (h % font::hor != 0)
+ fatal("horizontal position not a multiple of horizontal resolution");
+#endif
+ int hpos = h / font::hor;
+ if (hpos < SHRT_MIN || hpos > SHRT_MAX) {
+ error("character with ridiculous horizontal position discarded");
+ return;
+ }
+ int vpos;
+ if (v == cached_v && cached_v != 0)
+ vpos = cached_vpos;
+ else {
+ if (v % font::vert != 0)
+ fatal("vertical position not a multiple of vertical resolution");
+ vpos = v / font::vert;
+ if (vpos > nlines) {
+ glyph **old_lines = lines;
+ lines = new glyph *[vpos + 1];
+ memcpy(lines, old_lines, nlines*sizeof(glyph *));
+ for (int i = nlines; i <= vpos; i++)
+ lines[i] = 0;
+ a_delete old_lines;
+ nlines = vpos + 1;
+ }
+ // Note that the first output line corresponds to groff
+ // position font::vert.
+ if (vpos <= 0) {
+ error("character above first line discarded");
+ return;
+ }
+ cached_v = v;
+ cached_vpos = vpos;
+ }
+ glyph *g = new glyph;
+ g->hpos = hpos;
+ g->code = c;
+ g->mode = mode;
+
+ // The list will be reversed later. After reversal, it must be in
+ // increasing order of hpos, with HDRAW characters before VDRAW
+ // characters before normal characters at each hpos, and otherwise
+ // in order of occurrence.
+
+ for (glyph **pp = lines + (vpos - 1); *pp; pp = &(*pp)->next)
+ if ((*pp)->hpos < hpos
+ || ((*pp)->hpos == hpos && (*pp)->draw_mode() >= g->draw_mode()))
+ break;
+
+ g->next = *pp;
+ *pp = g;
+}
+
+void tty_printer::draw(int code, int *p, int np, const environment *env)
+{
+ if (code != 'l' || !draw_flag)
+ return;
+ if (np != 2) {
+ error("2 arguments required for line");
+ return;
+ }
+ if (p[0] == 0) {
+ // vertical line
+ int v = env->vpos;
+ int len = p[1];
+ if (len < 0) {
+ v += len;
+ len = -len;
+ }
+ while (len >= 0) {
+ add_char('|', env->hpos, v, VDRAW_MODE);
+ len -= font::vert;
+ v += font::vert;
+ }
+ }
+ if (p[1] == 0) {
+ // horizontal line
+ int h = env->hpos;
+ int len = p[0];
+ if (len < 0) {
+ h += len;
+ len = -len;
+ }
+ while (len >= 0) {
+ add_char('-', h, env->vpos, HDRAW_MODE);
+ len -= font::hor;
+ h += font::hor;
+ }
+ }
+}
+
+void tty_printer::end_page(int page_length)
+{
+ if (page_length % font::vert != 0)
+ error("vertical position at end of page not multiple of vertical resolution");
+ int lines_per_page = page_length / font::vert;
+ for (int last_line = nlines; last_line > 0; last_line--)
+ if (lines[last_line - 1])
+ break;
+#if 0
+ if (last_line > lines_per_page) {
+ error("characters past last line discarded");
+ do {
+ --last_line;
+ while (lines[last_line]) {
+ glyph *tem = lines[last_line];
+ lines[last_line] = tem->next;
+ delete tem;
+ }
+ } while (last_line > lines_per_page);
+ }
+#endif
+ for (int i = 0; i < last_line; i++) {
+ glyph *p = lines[i];
+ lines[i] = 0;
+ glyph *g = 0;
+ while (p) {
+ glyph *tem = p->next;
+ p->next = g;
+ g = p;
+ p = tem;
+ }
+ int hpos = 0;
+
+ glyph *nextp;
+ for (p = g; p; delete p, p = nextp) {
+ nextp = p->next;
+ if (nextp && p->hpos == nextp->hpos) {
+ if (p->draw_mode() == HDRAW_MODE && nextp->draw_mode() == VDRAW_MODE) {
+ nextp->code = '+';
+ continue;
+ }
+ if (p->draw_mode() != 0 && p->draw_mode() == nextp->draw_mode()) {
+ nextp->code = p->code;
+ continue;
+ }
+ if (!overstrike_flag)
+ continue;
+ }
+ if (hpos > p->hpos) {
+ do {
+ putchar('\b');
+ hpos--;
+ } while (hpos > p->hpos);
+ }
+ else {
+ if (horizontal_tab_flag) {
+ for (;;) {
+ int next_tab_pos = ((hpos + TAB_WIDTH) / TAB_WIDTH) * TAB_WIDTH;
+ if (next_tab_pos > p->hpos)
+ break;
+ putchar('\t');
+ hpos = next_tab_pos;
+ }
+ }
+ for (; hpos < p->hpos; hpos++)
+ putchar(' ');
+ }
+ assert(hpos == p->hpos);
+ if (p->mode & UNDERLINE_MODE) {
+ putchar('_');
+ putchar('\b');
+ }
+ if (p->mode & BOLD_MODE) {
+ putchar(p->code);
+ putchar('\b');
+ }
+ putchar(p->code);
+ hpos++;
+ }
+ putchar('\n');
+ }
+ if (form_feed_flag) {
+ if (last_line < lines_per_page)
+ putchar('\f');
+ }
+ else {
+ for (; last_line < lines_per_page; last_line++)
+ putchar('\n');
+ }
+}
+
+font *tty_printer::make_font(const char *nm)
+{
+ return tty_font::load_tty_font(nm);
+}
+
+printer *make_printer()
+{
+ return new tty_printer;
+}
+
+static void usage();
+
+int main(int argc, char **argv)
+{
+ program_name = argv[0];
+ static char stderr_buf[BUFSIZ];
+ setbuf(stderr, stderr_buf);
+ int c;
+ while ((c = getopt(argc, argv, "F:vhfbuoBUd")) != EOF)
+ switch(c) {
+ case 'v':
+ {
+ extern const char *version_string;
+ fprintf(stderr, "grotty version %s\n", version_string);
+ fflush(stderr);
+ break;
+ }
+ case 'b':
+ // Do not embolden by overstriking.
+ bold_flag = 0;
+ break;
+ case 'u':
+ // Do not underline.
+ underline_flag = 0;
+ break;
+ case 'o':
+ // Do not overstrike (other than emboldening and underlining).
+ overstrike_flag = 0;
+ break;
+ case 'B':
+ // Do bold-underlining as bold.
+ bold_underline_mode = BOLD_MODE;
+ break;
+ case 'U':
+ // Do bold-underlining as underlining.
+ bold_underline_mode = UNDERLINE_MODE;
+ break;
+ case 'h':
+ // Use horizontal tabs.
+ horizontal_tab_flag = 1;
+ break;
+ case 'f':
+ form_feed_flag = 1;
+ break;
+ case 'F':
+ font::command_line_font_dir(optarg);
+ break;
+ case 'd':
+ // Ignore \D commands.
+ draw_flag = 0;
+ break;
+ case '?':
+ usage();
+ break;
+ default:
+ assert(0);
+ }
+ if (optind >= argc)
+ do_file("-");
+ else {
+ for (int i = optind; i < argc; i++)
+ do_file(argv[i]);
+ }
+ delete pr;
+ return 0;
+}
+
+static void usage()
+{
+ fprintf(stderr, "usage: %s [-hfvbuodBU] [-F dir] [files ...]\n",
+ program_name);
+ exit(1);
+}
diff --git a/gnu/usr.bin/groff/include/Makefile.sub b/gnu/usr.bin/groff/include/Makefile.sub
new file mode 100644
index 0000000..35d3440
--- /dev/null
+++ b/gnu/usr.bin/groff/include/Makefile.sub
@@ -0,0 +1,19 @@
+HDRS=assert.h cmap.h cset.h device.h driver.h errarg.h error.h font.h index.h \
+ lib.h macropath.h printer.h ptable.h refid.h search.h searchpath.h \
+ stringclass.h
+GENHDRS=defs.h
+CLEANADD=$(GENHDRS)
+
+all depend: $(GENHDRS)
+
+defs.h: FORCE
+ @$(SHELL) $(srcdir)/../gendef.sh defs.h \
+ "PROG_PREFIX=\"$(g)\"" "DEVICE=\"$(DEVICE)\"" \
+ "FONTPATH=\"$(fontpath)\"" "MACROPATH=\"$(tmacpath)\"" \
+ "INDEX_SUFFIX=\"$(indexext)\"" \
+ "COMMON_WORDS_FILE=\"$(common_words_file)\"" \
+ "DEFAULT_INDEX_DIR=\"$(indexdir)\"" \
+ "DEFAULT_INDEX_NAME=\"$(indexname)\"" \
+ "DEFAULT_INDEX=\"$(indexdir)/$(indexname)\""
+
+FORCE:
diff --git a/gnu/usr.bin/groff/include/assert.h b/gnu/usr.bin/groff/include/assert.h
new file mode 100644
index 0000000..fe988ee
--- /dev/null
+++ b/gnu/usr.bin/groff/include/assert.h
@@ -0,0 +1,39 @@
+// -*- C++ -*-
+/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
+ Written by James Clark (jjc@jclark.com)
+
+This file is part of groff.
+
+groff is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
+
+groff is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License along
+with groff; see the file COPYING. If not, write to the Free Software
+Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#ifndef ASSERT_H
+#define ASSERT_H
+
+void assertion_failed(int, const char *);
+
+inline void do_assert(int expr, int line, const char *file)
+{
+ if (!expr)
+ assertion_failed(line, file);
+}
+#endif /* ASSERT_H */
+
+#undef assert
+
+#ifdef NDEBUG
+#define assert(ignore) /* as nothing */
+#else
+#define assert(expr) do_assert(expr, __LINE__, __FILE__)
+#endif
diff --git a/gnu/usr.bin/groff/include/cmap.h b/gnu/usr.bin/groff/include/cmap.h
new file mode 100644
index 0000000..18c88fb
--- /dev/null
+++ b/gnu/usr.bin/groff/include/cmap.h
@@ -0,0 +1,56 @@
+// -*- C++ -*-
+/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
+ Written by James Clark (jjc@jclark.com)
+
+This file is part of groff.
+
+groff is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
+
+groff is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License along
+with groff; see the file COPYING. If not, write to the Free Software
+Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#ifndef UCHAR_MAX
+#define UCHAR_MAX 255
+#endif
+
+enum cmap_builtin { CMAP_BUILTIN };
+
+class cmap {
+public:
+ cmap();
+ cmap(cmap_builtin);
+ int operator()(unsigned char) const;
+ unsigned char &operator[](unsigned char);
+
+ friend class cmap_init;
+private:
+ unsigned char v[UCHAR_MAX+1];
+};
+
+inline int cmap::operator()(unsigned char c) const
+{
+ return v[c];
+}
+
+inline unsigned char &cmap::operator[](unsigned char c)
+{
+ return v[c];
+}
+
+extern cmap cmlower;
+extern cmap cmupper;
+
+static class cmap_init {
+ static int initialised;
+public:
+ cmap_init();
+} _cmap_init;
diff --git a/gnu/usr.bin/groff/include/cset.h b/gnu/usr.bin/groff/include/cset.h
new file mode 100644
index 0000000..b160782
--- /dev/null
+++ b/gnu/usr.bin/groff/include/cset.h
@@ -0,0 +1,75 @@
+// -*- C++ -*-
+/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
+ Written by James Clark (jjc@jclark.com)
+
+This file is part of groff.
+
+groff is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
+
+groff is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License along
+with groff; see the file COPYING. If not, write to the Free Software
+Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#ifdef HAVE_CC_LIMITS_H
+#include <limits.h>
+#else /* not HAVE_CC_LIMITS_H */
+#ifndef UCHAR_MAX
+#define UCHAR_MAX 255
+#endif
+#endif /* not HAVE_CC_LIMITS_H */
+
+enum cset_builtin { CSET_BUILTIN };
+
+class cset {
+public:
+ cset();
+ cset(cset_builtin);
+ cset(const char *);
+ cset(const unsigned char *);
+ int operator()(unsigned char) const;
+
+ cset &operator|=(const cset &);
+ cset &operator|=(unsigned char);
+
+ friend class cset_init;
+private:
+ char v[UCHAR_MAX+1];
+ void clear();
+};
+
+inline int cset::operator()(unsigned char c) const
+{
+ return v[c];
+}
+
+inline cset &cset::operator|=(unsigned char c)
+{
+ v[c] = 1;
+ return *this;
+}
+
+extern cset csalpha;
+extern cset csupper;
+extern cset cslower;
+extern cset csdigit;
+extern cset csxdigit;
+extern cset csspace;
+extern cset cspunct;
+extern cset csalnum;
+extern cset csprint;
+extern cset csgraph;
+extern cset cscntrl;
+
+static class cset_init {
+ static int initialised;
+public:
+ cset_init();
+} _cset_init;
diff --git a/gnu/usr.bin/groff/include/defs.h b/gnu/usr.bin/groff/include/defs.h
new file mode 100644
index 0000000..df2efba
--- /dev/null
+++ b/gnu/usr.bin/groff/include/defs.h
@@ -0,0 +1,9 @@
+#define PROG_PREFIX ""
+#define DEVICE "ps"
+#define FONTPATH "/usr/share/groff_font"
+#define MACROPATH "/usr/share/tmac"
+#define INDEX_SUFFIX ".i"
+#define COMMON_WORDS_FILE "/usr/share/dict/eign"
+#define DEFAULT_INDEX_DIR "/usr/share/dict/papers"
+#define DEFAULT_INDEX_NAME "Ind"
+#define DEFAULT_INDEX "/usr/share/dict/papers/Ind"
diff --git a/gnu/usr.bin/groff/include/device.h b/gnu/usr.bin/groff/include/device.h
new file mode 100644
index 0000000..76be133
--- /dev/null
+++ b/gnu/usr.bin/groff/include/device.h
@@ -0,0 +1,21 @@
+// -*- C++ -*-
+/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
+ Written by James Clark (jjc@jclark.com)
+
+This file is part of groff.
+
+groff is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
+
+groff is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License along
+with groff; see the file COPYING. If not, write to the Free Software
+Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+extern const char *device;
diff --git a/gnu/usr.bin/groff/include/driver.h b/gnu/usr.bin/groff/include/driver.h
new file mode 100644
index 0000000..be7a6dc
--- /dev/null
+++ b/gnu/usr.bin/groff/include/driver.h
@@ -0,0 +1,36 @@
+// -*- C++ -*-
+/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
+ Written by James Clark (jjc@jclark.com)
+
+This file is part of groff.
+
+groff is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
+
+groff is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License along
+with groff; see the file COPYING. If not, write to the Free Software
+Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <errno.h>
+#include <assert.h>
+#include <math.h>
+#include "errarg.h"
+#include "error.h"
+#include "font.h"
+#include "printer.h"
+#include "lib.h"
+
+void do_file(const char *);
+extern printer *pr;
diff --git a/gnu/usr.bin/groff/include/errarg.h b/gnu/usr.bin/groff/include/errarg.h
new file mode 100644
index 0000000..2f5ea5f
--- /dev/null
+++ b/gnu/usr.bin/groff/include/errarg.h
@@ -0,0 +1,46 @@
+// -*- C++ -*-
+/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
+ Written by James Clark (jjc@jclark.com)
+
+This file is part of groff.
+
+groff is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
+
+groff is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License along
+with groff; see the file COPYING. If not, write to the Free Software
+Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+class errarg {
+ enum { EMPTY, STRING, CHAR, INTEGER, DOUBLE } type;
+ union {
+ const char *s;
+ int n;
+ char c;
+ double d;
+ };
+ public:
+ errarg();
+ errarg(const char *);
+ errarg(char);
+ errarg(unsigned char);
+ errarg(int);
+ errarg(double);
+ int empty() const;
+ void print() const;
+};
+
+extern errarg empty_errarg;
+
+extern void errprint(const char *,
+ const errarg &arg1 = empty_errarg,
+ const errarg &arg2 = empty_errarg,
+ const errarg &arg3 = empty_errarg);
+
diff --git a/gnu/usr.bin/groff/include/error.h b/gnu/usr.bin/groff/include/error.h
new file mode 100644
index 0000000..7a68712
--- /dev/null
+++ b/gnu/usr.bin/groff/include/error.h
@@ -0,0 +1,58 @@
+// -*- C++ -*-
+/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
+ Written by James Clark (jjc@jclark.com)
+
+This file is part of groff.
+
+groff is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
+
+groff is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License along
+with groff; see the file COPYING. If not, write to the Free Software
+Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+extern void fatal_with_file_and_line(const char *filename, int lineno,
+ const char *format,
+ const errarg &arg1 = empty_errarg,
+ const errarg &arg2 = empty_errarg,
+ const errarg &arg3 = empty_errarg);
+
+extern void error_with_file_and_line(const char *filename, int lineno,
+ const char *format,
+ const errarg &arg1 = empty_errarg,
+ const errarg &arg2 = empty_errarg,
+ const errarg &arg3 = empty_errarg);
+
+extern void warning_with_file_and_line(const char *filename, int lineno,
+ const char *format,
+ const errarg &arg1 = empty_errarg,
+ const errarg &arg2 = empty_errarg,
+ const errarg &arg3 = empty_errarg);
+
+extern void fatal(const char *,
+ const errarg &arg1 = empty_errarg,
+ const errarg &arg2 = empty_errarg,
+ const errarg &arg3 = empty_errarg);
+
+extern void error(const char *,
+ const errarg &arg1 = empty_errarg,
+ const errarg &arg2 = empty_errarg,
+ const errarg &arg3 = empty_errarg);
+
+extern void warning(const char *,
+ const errarg &arg1 = empty_errarg,
+ const errarg &arg2 = empty_errarg,
+ const errarg &arg3 = empty_errarg);
+
+
+extern const char *program_name;
+extern int current_lineno;
+extern const char *current_filename;
+
diff --git a/gnu/usr.bin/groff/include/font.h b/gnu/usr.bin/groff/include/font.h
new file mode 100644
index 0000000..6470b65
--- /dev/null
+++ b/gnu/usr.bin/groff/include/font.h
@@ -0,0 +1,113 @@
+// -*- C++ -*-
+/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
+ Written by James Clark (jjc@jclark.com)
+
+This file is part of groff.
+
+groff is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
+
+groff is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License along
+with groff; see the file COPYING. If not, write to the Free Software
+Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+typedef void (*FONT_COMMAND_HANDLER)(const char *, const char *,
+ const char *, int);
+
+struct font_kern_list;
+struct font_char_metric;
+struct font_widths_cache;
+
+class font {
+public:
+ enum {
+ LIG_ff = 1,
+ LIG_fi = 2,
+ LIG_fl = 4,
+ LIG_ffi = 8,
+ LIG_ffl = 16
+ };
+
+ virtual ~font();
+ int contains(int index);
+ int is_special();
+ int get_width(int index, int point_size);
+ int get_height(int index, int point_size);
+ int get_depth(int index, int point_size);
+ int get_space_width(int point_size);
+ int get_character_type(int index);
+ int get_kern(int index1, int index2, int point_size);
+ int get_skew(int index, int point_size, int slant);
+ int has_ligature(int);
+ int get_italic_correction(int index, int point_size);
+ int get_left_italic_correction(int index, int point_size);
+ int get_subscript_correction(int index, int point_size);
+ int get_code(int i);
+ const char *get_name();
+ const char *get_internal_name();
+
+ static font *load_font(const char *, int *not_found = 0);
+ static void command_line_font_dir(const char *path);
+ static FILE *open_file(const char *name, char **pathp);
+ static int load_desc();
+ static int name_to_index(const char *);
+ static int number_to_index(int);
+ static FONT_COMMAND_HANDLER
+ set_unknown_desc_command_handler(FONT_COMMAND_HANDLER);
+
+ static int res;
+ static int hor;
+ static int vert;
+ static int unitwidth;
+ static int paperwidth;
+ static int paperlength;
+ static int biggestfont;
+ static int spare2;
+ static int sizescale;
+ static int tcommand;
+
+ static const char **font_name_table;
+ static const char **style_table;
+ static const char *family;
+ static int *sizes;
+private:
+ unsigned ligatures;
+ font_kern_list **kern_hash_table;
+ int space_width;
+ short *ch_index;
+ int nindices;
+ font_char_metric *ch;
+ int ch_used;
+ int ch_size;
+ int special;
+ char *name;
+ char *internalname;
+ double slant;
+ font_widths_cache *widths_cache;
+ static FONT_COMMAND_HANDLER unknown_desc_command_handler;
+
+ enum { KERN_HASH_TABLE_SIZE = 503 };
+
+ void add_entry(int index, const font_char_metric &);
+ void copy_entry(int new_index, int old_index);
+ void add_kern(int index1, int index2, int amount);
+ static int hash_kern(int i1, int i2);
+ void alloc_ch_index(int);
+ void extend_ch();
+ void compact();
+
+ static int scale(int w, int pointsize);
+ virtual void handle_unknown_font_command(const char *command,
+ const char *arg,
+ const char *file, int lineno);
+protected:
+ font(const char *);
+ int load(int *not_found = 0);
+};
diff --git a/gnu/usr.bin/groff/include/index.h b/gnu/usr.bin/groff/include/index.h
new file mode 100644
index 0000000..719b026
--- /dev/null
+++ b/gnu/usr.bin/groff/include/index.h
@@ -0,0 +1,42 @@
+// -*- C++ -*-
+/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
+ Written by James Clark (jjc@jclark.com)
+
+This file is part of groff.
+
+groff is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
+
+groff is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License along
+with groff; see the file COPYING. If not, write to the Free Software
+Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#define INDEX_MAGIC 0x23021964
+#define INDEX_VERSION 1
+
+struct index_header {
+ int magic;
+ int version;
+ int tags_size;
+ int table_size;
+ int lists_size;
+ int strings_size;
+ int truncate;
+ int shortest;
+ int common;
+};
+
+struct tag {
+ int filename_index;
+ int start;
+ int length;
+};
+
+unsigned hash(const char *s, int len);
diff --git a/gnu/usr.bin/groff/include/lib.h b/gnu/usr.bin/groff/include/lib.h
new file mode 100644
index 0000000..3ca1557
--- /dev/null
+++ b/gnu/usr.bin/groff/include/lib.h
@@ -0,0 +1,125 @@
+// -*- C++ -*-
+/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
+ Written by James Clark (jjc@jclark.com)
+
+This file is part of groff.
+
+groff is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
+
+groff is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License along
+with groff; see the file COPYING. If not, write to the Free Software
+Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+extern "C" {
+#ifndef strerror
+ char *strerror(int);
+#endif
+#ifndef __BORLANDC__
+ const char *itoa(int);
+ const char *iftoa(int, int);
+#endif /* __BORLANDC__ */
+}
+
+#ifdef STDLIB_H_DECLARES_GETOPT
+#include <stdlib.h>
+#else /* not STDLIB_H_DECLARES_GETOPT */
+#ifdef UNISTD_H_DECLARES_GETOPT
+#include <sys/types.h>
+#include <unistd.h>
+#else /* not UNISTD_H_DECLARES_GETOPT */
+extern "C" {
+ int getopt(int, char **, const char *);
+}
+#endif /* not UNISTD_H_DECLARES_GETOPT */
+
+extern "C" {
+ extern char *optarg;
+ extern int optind;
+ extern int opterr;
+}
+
+#endif /* not STDLIB_H_DECLARES_GETOPT */
+
+char *strsave(const char *s);
+int is_prime(unsigned);
+
+#include <stdio.h>
+
+FILE *xtmpfile();
+
+#ifndef STDIO_H_DECLARES_POPEN
+
+extern "C" { FILE *popen(const char *, const char *); }
+
+#endif /* not STDIO_H_DECLARES_POPEN */
+
+#ifndef STDIO_H_DECLARES_PCLOSE
+
+extern "C" { int pclose (FILE *); }
+
+#endif /* not STDIO_H_DECLARES_PCLOSE */
+
+int interpret_lf_args(const char *p);
+
+extern char illegal_char_table[];
+
+inline int illegal_input_char(int c)
+{
+ return c >= 0 && illegal_char_table[c];
+}
+
+#ifdef HAVE_CC_LIMITS_H
+#include <limits.h>
+#else /* not HAVE_CC_LIMITS_H */
+#define INT_MAX 2147483647
+#endif /* not HAVE_CC_LIMITS_H */
+
+/* It's not safe to rely on people getting INT_MIN right (ie signed). */
+
+#ifdef INT_MIN
+#undef INT_MIN
+#endif
+
+#ifdef CFRONT_ANSI_BUG
+
+/* This works around a bug in cfront 2.0 used with ANSI C compilers. */
+
+#define INT_MIN ((long)(-INT_MAX-1))
+
+#else /* not CFRONT_ANSI_BUG */
+
+#define INT_MIN (-INT_MAX-1)
+
+#endif /* not CFRONT_ANSI_BUG */
+
+/* Maximum number of digits in the decimal representation of an int
+(not including the -). */
+
+#define INT_DIGITS 10
+
+#ifdef PI
+#undef PI
+#endif
+
+const double PI = 3.14159265358979323846;
+
+/* ad_delete deletes an array of objects with destructors;
+a_delete deletes an array of objects without destructors */
+
+#ifdef ARRAY_DELETE_NEEDS_SIZE
+/* for 2.0 systems */
+#define ad_delete(size) delete [size]
+#define a_delete delete
+#else /* not ARRAY_DELETE_NEEDS_SIZE */
+/* for ARM systems */
+#define ad_delete(size) delete []
+#define a_delete delete []
+#endif /* not ARRAY_DELETE_NEEDS_SIZE */
diff --git a/gnu/usr.bin/groff/include/macropath.h b/gnu/usr.bin/groff/include/macropath.h
new file mode 100644
index 0000000..0b0f5c3
--- /dev/null
+++ b/gnu/usr.bin/groff/include/macropath.h
@@ -0,0 +1,21 @@
+// -*- C++ -*-
+/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
+ Written by James Clark (jjc@jclark.com)
+
+This file is part of groff.
+
+groff is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
+
+groff is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License along
+with groff; see the file COPYING. If not, write to the Free Software
+Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+extern search_path macro_path;
diff --git a/gnu/usr.bin/groff/include/posix.h b/gnu/usr.bin/groff/include/posix.h
new file mode 100644
index 0000000..d3ff8f5
--- /dev/null
+++ b/gnu/usr.bin/groff/include/posix.h
@@ -0,0 +1,49 @@
+// -*- C++ -*-
+/* Copyright (C) 1992 Free Software Foundation, Inc.
+ Written by James Clark (jjc@jclark.com)
+
+This file is part of groff.
+
+groff is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
+
+groff is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License along
+with groff; see the file COPYING. If not, write to the Free Software
+Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#ifdef HAVE_CC_OSFCN_H
+#include <osfcn.h>
+#else
+#include <unistd.h>
+#endif
+
+#ifndef S_IRUSR
+#define S_IRUSR 0400
+#endif
+
+#ifndef S_IRGRP
+#define S_IRGRP 0040
+#endif
+
+#ifndef S_IROTH
+#define S_IROTH 0004
+#endif
+
+#ifndef S_ISREG
+#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
+#endif
+
+#ifndef O_RDONLY
+#define O_RDONLY 0
+#endif
diff --git a/gnu/usr.bin/groff/include/printer.h b/gnu/usr.bin/groff/include/printer.h
new file mode 100644
index 0000000..d517add
--- /dev/null
+++ b/gnu/usr.bin/groff/include/printer.h
@@ -0,0 +1,66 @@
+// -*- C++ -*-
+/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
+ Written by James Clark (jjc@jclark.com)
+
+This file is part of groff.
+
+groff is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
+
+groff is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License along
+with groff; see the file COPYING. If not, write to the Free Software
+Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+struct environment {
+ int fontno;
+ int size;
+ int hpos;
+ int vpos;
+ int height;
+ int slant;
+};
+
+struct font;
+
+struct font_pointer_list {
+ font *p;
+ font_pointer_list *next;
+
+ font_pointer_list(font *, font_pointer_list *);
+};
+
+class printer {
+public:
+ printer();
+ virtual ~printer();
+ void load_font(int i, const char *name);
+ void set_ascii_char(unsigned char c, const environment *env,
+ int *widthp = 0);
+ void set_special_char(const char *nm, const environment *env,
+ int *widthp = 0);
+ void set_numbered_char(int n, const environment *env, int *widthp = 0);
+ virtual void draw(int code, int *p, int np, const environment *env);
+ virtual void begin_page(int) = 0;
+ virtual void end_page(int page_length) = 0;
+ virtual font *make_font(const char *nm);
+ virtual void end_of_line();
+ virtual void special(char *arg, const environment *env);
+ static int adjust_arc_center(const int *, double *);
+protected:
+ font_pointer_list *font_list;
+private:
+ font **font_table;
+ int nfonts;
+ font *find_font(const char *);
+ virtual void set_char(int index, font *f, const environment *env,
+ int w) = 0;
+};
+
+printer *make_printer();
diff --git a/gnu/usr.bin/groff/include/ptable.h b/gnu/usr.bin/groff/include/ptable.h
new file mode 100644
index 0000000..0e7c199
--- /dev/null
+++ b/gnu/usr.bin/groff/include/ptable.h
@@ -0,0 +1,166 @@
+// -*- C++ -*-
+/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
+ Written by James Clark (jjc@jclark.com)
+
+This file is part of groff.
+
+groff is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
+
+groff is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License along
+with groff; see the file COPYING. If not, write to the Free Software
+Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <assert.h>
+#include <string.h>
+
+#ifdef TRADITIONAL_CPP
+#define name2(a,b) a/**/b
+#else /* not TRADITIONAL_CPP */
+#define name2(a,b) name2x(a,b)
+#define name2x(a,b) a ## b
+#endif /* not TRADITIONAL_CPP */
+
+#define PTABLE(T) name2(T,_ptable)
+#define PASSOC(T) name2(T,_passoc)
+#define PTABLE_ITERATOR(T) name2(T,_ptable_iterator)
+
+extern unsigned next_ptable_size(unsigned);
+extern unsigned long hash_string(const char *);
+
+#define declare_ptable(T) \
+ \
+struct PASSOC(T) { \
+ char *key; \
+ T *val; \
+ PASSOC(T)(); \
+}; \
+ \
+struct PTABLE(T); \
+ \
+class PTABLE_ITERATOR(T) { \
+ PTABLE(T) *p; \
+ unsigned i; \
+public: \
+ PTABLE_ITERATOR(T)(PTABLE(T) *); \
+ int next(const char **, T **); \
+}; \
+ \
+class PTABLE(T) { \
+ PASSOC(T) *v; \
+ unsigned size; \
+ unsigned used; \
+ enum { FULL_NUM = 2, FULL_DEN = 3, INITIAL_SIZE = 17 }; \
+public: \
+ PTABLE(T)(); \
+ ~PTABLE(T)(); \
+ void define(const char *, T *); \
+ T *lookup(const char *); \
+ friend class PTABLE_ITERATOR(T); \
+};
+
+
+#define implement_ptable(T) \
+ \
+PASSOC(T)::PASSOC(T)() \
+: key(0), val(0) \
+{ \
+} \
+ \
+PTABLE(T)::PTABLE(T)() \
+{ \
+ v = new PASSOC(T)[size = INITIAL_SIZE]; \
+ used = 0; \
+} \
+ \
+PTABLE(T)::~PTABLE(T)() \
+{ \
+ for (unsigned i = 0; i < size; i++) { \
+ a_delete v[i].key; \
+ delete v[i].val; \
+ } \
+ a_delete v; \
+} \
+ \
+void PTABLE(T)::define(const char *key, T *val) \
+{ \
+ assert(key != 0); \
+ unsigned long h = hash_string(key); \
+ for (unsigned n = unsigned(h % size); \
+ v[n].key != 0; \
+ n = (n == 0 ? size - 1 : n - 1)) \
+ if (strcmp(v[n].key, key) == 0) { \
+ delete v[n].val; \
+ v[n].val = val; \
+ return; \
+ } \
+ if (val == 0) \
+ return; \
+ if (used*FULL_DEN >= size*FULL_NUM) { \
+ PASSOC(T) *oldv = v; \
+ unsigned old_size = size; \
+ size = next_ptable_size(size); \
+ v = new PASSOC(T)[size]; \
+ for (unsigned i = 0; i < old_size; i++) \
+ if (oldv[i].key != 0) { \
+ if (oldv[i].val == 0) \
+ a_delete oldv[i].key; \
+ else { \
+ for (unsigned j = unsigned(hash_string(oldv[i].key) % size); \
+ v[j].key != 0; \
+ j = (j == 0 ? size - 1 : j - 1)) \
+ ; \
+ v[j].key = oldv[i].key; \
+ v[j].val = oldv[i].val; \
+ } \
+ } \
+ for (n = unsigned(h % size); \
+ v[n].key != 0; \
+ n = (n == 0 ? size - 1 : n - 1)) \
+ ; \
+ a_delete oldv; \
+ } \
+ char *temp = new char[strlen(key)+1]; \
+ strcpy(temp, key); \
+ v[n].key = temp; \
+ v[n].val = val; \
+ used++; \
+} \
+ \
+T *PTABLE(T)::lookup(const char *key) \
+{ \
+ assert(key != 0); \
+ for (unsigned n = unsigned(hash_string(key) % size); \
+ v[n].key != 0; \
+ n = (n == 0 ? size - 1 : n - 1)) \
+ if (strcmp(v[n].key, key) == 0) \
+ return v[n].val; \
+ return 0; \
+} \
+ \
+PTABLE_ITERATOR(T)::PTABLE_ITERATOR(T)(PTABLE(T) *t) \
+: p(t), i(0) \
+{ \
+} \
+ \
+int PTABLE_ITERATOR(T)::next(const char **keyp, T **valp) \
+{ \
+ unsigned size = p->size; \
+ PASSOC(T) *v = p->v; \
+ for (; i < size; i++) \
+ if (v[i].key != 0) { \
+ *keyp = v[i].key; \
+ *valp = v[i].val; \
+ i++; \
+ return 1; \
+ } \
+ return 0; \
+}
+
diff --git a/gnu/usr.bin/groff/include/refid.h b/gnu/usr.bin/groff/include/refid.h
new file mode 100644
index 0000000..a0e86a3
--- /dev/null
+++ b/gnu/usr.bin/groff/include/refid.h
@@ -0,0 +1,35 @@
+// -*- C++ -*-
+/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
+ Written by James Clark (jjc@jclark.com)
+
+This file is part of groff.
+
+groff is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
+
+groff is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License along
+with groff; see the file COPYING. If not, write to the Free Software
+Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+class reference_id {
+ int filename_id;
+ int pos;
+public:
+ reference_id() : filename_id(-1) { }
+ reference_id(int fid, int off) : filename_id(fid), pos(off) { }
+ unsigned hash() const { return (filename_id << 4) + pos; }
+ int is_null() const { return filename_id < 0; }
+ friend inline int operator==(const reference_id &, const reference_id &);
+};
+
+inline int operator==(const reference_id &r1, const reference_id &r2)
+{
+ return r1.filename_id == r2.filename_id && r1.pos == r2.pos;
+}
diff --git a/gnu/usr.bin/groff/include/search.h b/gnu/usr.bin/groff/include/search.h
new file mode 100644
index 0000000..e1fdb84
--- /dev/null
+++ b/gnu/usr.bin/groff/include/search.h
@@ -0,0 +1,96 @@
+// -*- C++ -*-
+/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
+ Written by James Clark (jjc@jclark.com)
+
+This file is part of groff.
+
+groff is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
+
+groff is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License along
+with groff; see the file COPYING. If not, write to the Free Software
+Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+struct search_item;
+struct search_item_iterator;
+
+class search_list {
+public:
+ search_list();
+ ~search_list();
+ void add_file(const char *fn, int silent = 0);
+ int nfiles() const;
+private:
+ search_item *list;
+ int niterators;
+ int next_fid;
+ friend class search_list_iterator;
+};
+
+struct bmpattern;
+
+class linear_searcher {
+ const char *ignore_fields;
+ int truncate_len;
+ bmpattern **keys;
+ int nkeys;
+ const char *search_and_check(const bmpattern *key, const char *buf,
+ const char *bufend, const char **start = 0)
+ const;
+ int check_match(const char *buf, const char *bufend, const char *match,
+ int matchlen, const char **cont, const char **start)
+ const;
+public:
+ linear_searcher(const char *query, int query_len,
+ const char *ign, int trunc);
+ ~linear_searcher();
+ int search(const char *buf, const char *bufend,
+ const char **startp, int *lengthp) const;
+};
+
+class search_list_iterator {
+ search_list *list;
+ search_item *ptr;
+ search_item_iterator *iter;
+ char *query;
+ linear_searcher searcher;
+public:
+ search_list_iterator(search_list *, const char *query);
+ ~search_list_iterator();
+ int next(const char **, int *, reference_id * = 0);
+};
+
+class search_item {
+protected:
+ char *name;
+ int filename_id;
+public:
+ search_item *next;
+ search_item(const char *nm, int fid);
+ virtual search_item_iterator *make_search_item_iterator(const char *) = 0;
+ virtual ~search_item();
+ int is_named(const char *) const;
+ virtual int next_filename_id() const;
+};
+
+class search_item_iterator {
+ char shut_g_plus_plus_up;
+public:
+ virtual ~search_item_iterator();
+ virtual int next(const linear_searcher &, const char **ptr, int *lenp,
+ reference_id *) = 0;
+};
+
+search_item *make_index_search_item(const char *filename, int fid);
+search_item *make_linear_search_item(int fd, const char *filename, int fid);
+
+extern int linear_truncate_len;
+extern const char *linear_ignore_fields;
+extern int verify_flag;
diff --git a/gnu/usr.bin/groff/include/searchpath.h b/gnu/usr.bin/groff/include/searchpath.h
new file mode 100644
index 0000000..14a74f6
--- /dev/null
+++ b/gnu/usr.bin/groff/include/searchpath.h
@@ -0,0 +1,29 @@
+// -*- C++ -*-
+/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
+ Written by James Clark (jjc@jclark.com)
+
+This file is part of groff.
+
+groff is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
+
+groff is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License along
+with groff; see the file COPYING. If not, write to the Free Software
+Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+class search_path {
+ char *dirs;
+ unsigned init_len;
+public:
+ search_path(const char *envvar, const char *standard);
+ ~search_path();
+ void command_line_dir(const char *);
+ FILE *open_file(const char *, char **);
+};
diff --git a/gnu/usr.bin/groff/include/stringclass.h b/gnu/usr.bin/groff/include/stringclass.h
new file mode 100644
index 0000000..9f85233
--- /dev/null
+++ b/gnu/usr.bin/groff/include/stringclass.h
@@ -0,0 +1,187 @@
+// -*- C++ -*-
+/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
+ Written by James Clark (jjc@jclark.com)
+
+This file is part of groff.
+
+groff is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
+
+groff is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License along
+with groff; see the file COPYING. If not, write to the Free Software
+Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <string.h>
+#include <stdio.h>
+#include <assert.h>
+
+// Ensure that the first declaration of functions that are later
+// declared as inline declares them as inline.
+
+class string;
+
+inline string operator+(const string &, const string &);
+inline string operator+(const string &, const char *);
+inline string operator+(const char *, const string &);
+inline string operator+(const string &, char);
+inline string operator+(char, const string &);
+inline int operator==(const string &, const string &);
+inline int operator!=(const string &, const string &);
+
+class string {
+public:
+ string();
+ string(const string &);
+ string(const char *);
+ string(const char *, int);
+ string(char);
+
+ ~string();
+
+ string &operator=(const string &);
+ string &operator=(const char *);
+ string &operator=(char);
+
+ string &operator+=(const string &);
+ string &operator+=(const char *);
+ string &operator+=(char);
+ void append(const char *, int);
+
+ int length() const;
+ int empty() const;
+ int operator*() const;
+
+ string substring(int i, int n) const;
+
+ char &operator[](int);
+ char operator[](int) const;
+
+ void set_length(int i);
+ const char *contents() const;
+ int search(char) const;
+ char *extract() const;
+ void clear();
+ void move(string &);
+
+ friend string operator+(const string &, const string &);
+ friend string operator+(const string &, const char *);
+ friend string operator+(const char *, const string &);
+ friend string operator+(const string &, char);
+ friend string operator+(char, const string &);
+
+ friend int operator==(const string &, const string &);
+ friend int operator!=(const string &, const string &);
+ friend int operator<=(const string &, const string &);
+ friend int operator<(const string &, const string &);
+ friend int operator>=(const string &, const string &);
+ friend int operator>(const string &, const string &);
+
+private:
+ char *ptr;
+ int len;
+ int sz;
+
+ string(const char *, int, const char *, int); // for use by operator+
+ void grow1();
+};
+
+
+inline char &string::operator[](int i)
+{
+ assert(i >= 0 && i < len);
+ return ptr[i];
+}
+
+inline char string::operator[](int i) const
+{
+ assert(i >= 0 && i < len);
+ return ptr[i];
+}
+
+inline int string::length() const
+{
+ return len;
+}
+
+inline int string::empty() const
+{
+ return len == 0;
+}
+
+inline int string::operator*() const
+{
+ return len;
+}
+
+inline const char *string::contents() const
+{
+ return ptr;
+}
+
+inline string operator+(const string &s1, const string &s2)
+{
+ return string(s1.ptr, s1.len, s2.ptr, s2.len);
+}
+
+inline string operator+(const string &s1, const char *s2)
+{
+ if (s2 == 0)
+ return s1;
+ else
+ return string(s1.ptr, s1.len, s2, strlen(s2));
+}
+
+inline string operator+(const char *s1, const string &s2)
+{
+ if (s1 == 0)
+ return s2;
+ else
+ return string(s1, strlen(s1), s2.ptr, s2.len);
+}
+
+inline string operator+(const string &s, char c)
+{
+ return string(s.ptr, s.len, &c, 1);
+}
+
+inline string operator+(char c, const string &s)
+{
+ return string(&c, 1, s.ptr, s.len);
+}
+
+inline int operator==(const string &s1, const string &s2)
+{
+ return (s1.len == s2.len
+ && (s1.len == 0 || memcmp(s1.ptr, s2.ptr, s1.len) == 0));
+}
+
+inline int operator!=(const string &s1, const string &s2)
+{
+ return (s1.len != s2.len
+ || (s1.len != 0 && memcmp(s1.ptr, s2.ptr, s1.len) != 0));
+}
+
+inline string string::substring(int i, int n) const
+{
+ assert(i >= 0 && i + n <= len);
+ return string(ptr + i, n);
+}
+
+inline string &string::operator+=(char c)
+{
+ if (len >= sz)
+ grow1();
+ ptr[len++] = c;
+ return *this;
+}
+
+void put_string(const string &, FILE *);
+
+string as_string(int);
diff --git a/gnu/usr.bin/groff/include/unix.h b/gnu/usr.bin/groff/include/unix.h
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/gnu/usr.bin/groff/include/unix.h
diff --git a/gnu/usr.bin/groff/indxbib/Makefile b/gnu/usr.bin/groff/indxbib/Makefile
new file mode 100644
index 0000000..0508c66
--- /dev/null
+++ b/gnu/usr.bin/groff/indxbib/Makefile
@@ -0,0 +1,21 @@
+# Makefile for indxbib
+
+PROG= indxbib
+SRCS= indxbib.cc dirnamemax.c signal.c
+CFLAGS+= -I${.CURDIR}/../include
+LDADD+= ${LIBBIB} ${LIBGROFF} -lm
+DPADD+= ${LIBBIB} ${LIBGROFF} ${LIBM}
+
+MANDEPEND= indxbib.1
+CLEANFILES+= ${MANDEPEND}
+
+# Ugh - I can't grab /usr/share from ../../../share/Makefile.inc
+# since I've already grabbed a BINDIR file for installing indxbib.
+# Sigh... Hardcode it. - jkh
+#
+afterinstall:
+ ${INSTALL} -c -o ${BINOWN} -g ${BINGRP} -m 444 ${.CURDIR}/eign \
+ ${DESTDIR}${SHAREDIR}/dict
+
+.include "../Makefile.cfg"
+.include <bsd.prog.mk>
diff --git a/gnu/usr.bin/groff/indxbib/Makefile.dep b/gnu/usr.bin/groff/indxbib/Makefile.dep
new file mode 100644
index 0000000..0b1d969
--- /dev/null
+++ b/gnu/usr.bin/groff/indxbib/Makefile.dep
@@ -0,0 +1,5 @@
+indxbib.o : indxbib.cc ../include/posix.h ../include/lib.h \
+ ../include/errarg.h ../include/error.h ../include/stringclass.h \
+ ../include/cset.h ../include/cmap.h ../include/defs.h ../include/index.h
+dirnamemax.o : dirnamemax.c
+signal.o : signal.c
diff --git a/gnu/usr.bin/groff/indxbib/Makefile.sub b/gnu/usr.bin/groff/indxbib/Makefile.sub
new file mode 100644
index 0000000..b23b425
--- /dev/null
+++ b/gnu/usr.bin/groff/indxbib/Makefile.sub
@@ -0,0 +1,24 @@
+PROG=indxbib
+MAN1=indxbib.n
+XLIBS=$(LIBBIB) $(LIBGROFF)
+MLIB=$(LIBM)
+OBJS=indxbib.o dirnamemax.o signal.o
+CCSRCS=indxbib.cc
+CSRCS=dirnamemax.c signal.c
+NAMEPREFIX=$(g)
+
+install_data: eign
+ -test -d $(datadir) || mkdir $(datadir)
+ -test -d $(datasubdir) || mkdir $(datasubdir)
+ if test -f /usr/lib/eign; then \
+ rm -f $(common_words_file); \
+ ln -s /usr/lib/eign $(common_words_file) 2>/dev/null \
+ || ln /usr/lib/eign $(common_words_file) 2>/dev/null \
+ || cp /usr/lib/eign $(common_words_file); \
+ else \
+ rm -f $(common_words_file); \
+ $(INSTALL_DATA) $(srcdir)/eign $(common_words_file); \
+ fi
+
+uninstall_sub:
+ -rm -f $(common_words_file)
diff --git a/gnu/usr.bin/groff/indxbib/dirnamemax.c b/gnu/usr.bin/groff/indxbib/dirnamemax.c
new file mode 100644
index 0000000..a8cd992
--- /dev/null
+++ b/gnu/usr.bin/groff/indxbib/dirnamemax.c
@@ -0,0 +1,49 @@
+/* dir_name_max(dir) does the same as pathconf(dir, _PC_NAME_MAX) */
+
+#include <sys/types.h>
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif /* HAVE_UNISTD_H */
+
+#ifdef _POSIX_VERSION
+
+long dir_name_max(dir)
+ char *dir;
+{
+ return pathconf(dir, _PC_NAME_MAX);
+}
+
+#else /* not _POSIX_VERSION */
+
+#ifdef HAVE_LIMITS_H
+#include <limits.h>
+#endif /* HAVE_LIMITS_H */
+
+#ifdef HAVE_DIRENT_H
+#include <dirent.h>
+#else /* not HAVE_DIRENT_H */
+#ifdef HAVE_SYS_DIR_H
+#include <sys/dir.h>
+#endif /* HAVE_SYS_DIR_H */
+#endif /* not HAVE_DIRENT_H */
+
+#ifndef NAME_MAX
+#ifdef MAXNAMLEN
+#define NAME_MAX MAXNAMLEN
+#else /* !MAXNAMLEN */
+#ifdef MAXNAMELEN
+#define NAME_MAX MAXNAMELEN
+#else /* !MAXNAMELEN */
+#define NAME_MAX 14
+#endif /* !MAXNAMELEN */
+#endif /* !MAXNAMLEN */
+#endif /* !NAME_MAX */
+
+long dir_name_max(dir)
+ char *dir;
+{
+ return NAME_MAX;
+}
+
+#endif /* not _POSIX_VERSION */
diff --git a/gnu/usr.bin/groff/indxbib/eign b/gnu/usr.bin/groff/indxbib/eign
new file mode 100644
index 0000000..7718c8b
--- /dev/null
+++ b/gnu/usr.bin/groff/indxbib/eign
@@ -0,0 +1,133 @@
+a
+i
+the
+to
+of
+and
+in
+is
+it
+for
+that
+if
+you
+this
+be
+on
+with
+not
+have
+are
+or
+as
+from
+can
+but
+by
+at
+an
+will
+no
+all
+was
+do
+there
+my
+one
+so
+we
+they
+what
+would
+any
+which
+about
+get
+your
+use
+some
+me
+then
+name
+like
+out
+when
+up
+time
+other
+more
+only
+just
+end
+also
+know
+how
+new
+should
+been
+than
+them
+he
+who
+make
+may
+people
+these
+now
+their
+here
+into
+first
+could
+way
+had
+see
+work
+well
+were
+two
+very
+where
+while
+us
+because
+good
+same
+even
+much
+most
+many
+such
+long
+his
+over
+last
+since
+right
+before
+our
+without
+too
+those
+why
+must
+part
+being
+current
+back
+still
+go
+point
+value
+each
+did
+both
+true
+off
+say
+another
+state
+might
+under
+start
+try
diff --git a/gnu/usr.bin/groff/indxbib/indxbib.cc b/gnu/usr.bin/groff/indxbib/indxbib.cc
new file mode 100644
index 0000000..c69142c
--- /dev/null
+++ b/gnu/usr.bin/groff/indxbib/indxbib.cc
@@ -0,0 +1,743 @@
+// -*- C++ -*-
+/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
+ Written by James Clark (jjc@jclark.com)
+
+This file is part of groff.
+
+groff is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
+
+groff is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License along
+with groff; see the file COPYING. If not, write to the Free Software
+Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <errno.h>
+
+#include "posix.h"
+#include "lib.h"
+#include "errarg.h"
+#include "error.h"
+#include "stringclass.h"
+#include "cset.h"
+#include "cmap.h"
+
+#include "defs.h"
+#include "index.h"
+
+extern "C" {
+ // Sun's stdlib.h fails to declare this.
+ char *mktemp(char *);
+}
+
+#define DEFAULT_HASH_TABLE_SIZE 997
+#define TEMP_INDEX_TEMPLATE "indxbibXXXXXX"
+
+// (2^n - MALLOC_OVERHEAD) should be a good argument for malloc().
+
+#define MALLOC_OVERHEAD 16
+
+#ifdef BLOCK_SIZE
+#undef BLOCK_SIZE
+#endif
+
+const int BLOCK_SIZE = ((1024 - MALLOC_OVERHEAD - sizeof(struct block *)
+ - sizeof(int)) / sizeof(int));
+struct block {
+ block *next;
+ int used;
+ int v[BLOCK_SIZE];
+
+ block(block *p = 0) : next(p), used(0) { }
+};
+
+struct block;
+
+union table_entry {
+ block *ptr;
+ int count;
+};
+
+struct word_list {
+ word_list *next;
+ char *str;
+ int len;
+ word_list(const char *, int, word_list *);
+};
+
+table_entry *hash_table;
+int hash_table_size = DEFAULT_HASH_TABLE_SIZE;
+// We make this the same size as hash_table so we only have to do one
+// mod per key.
+static word_list **common_words_table = 0;
+char *key_buffer;
+
+FILE *indxfp;
+int ntags = 0;
+string filenames;
+char *temp_index_file = 0;
+
+const char *ignore_fields = "XYZ";
+const char *common_words_file = COMMON_WORDS_FILE;
+int n_ignore_words = 100;
+int truncate_len = 6;
+int shortest_len = 3;
+int max_keys_per_item = 100;
+
+static void usage();
+static void write_hash_table();
+static void init_hash_table();
+static void read_common_words_file();
+static int store_key(char *s, int len);
+static void possibly_store_key(char *s, int len);
+static int do_whole_file(const char *filename);
+static int do_file(const char *filename);
+static void store_reference(int filename_index, int pos, int len);
+static void check_integer_arg(char opt, const char *arg, int min, int *res);
+static void store_filename(const char *);
+static void fwrite_or_die(const void *ptr, int size, int nitems, FILE *fp);
+static char *get_cwd();
+
+extern "C" {
+ void cleanup();
+ long dir_name_max(const char *);
+ void catch_fatal_signals();
+ void ignore_fatal_signals();
+}
+
+int main(int argc, char **argv)
+{
+ program_name = argv[0];
+ static char stderr_buf[BUFSIZ];
+ setbuf(stderr, stderr_buf);
+
+ const char *basename = 0;
+ typedef int (*parser_t)(const char *);
+ parser_t parser = do_file;
+ const char *directory = 0;
+ const char *foption = 0;
+ int opt;
+ while ((opt = getopt(argc, argv, "c:o:h:i:k:l:t:n:c:d:f:vw")) != EOF)
+ switch (opt) {
+ case 'c':
+ common_words_file = optarg;
+ break;
+ case 'd':
+ directory = optarg;
+ break;
+ case 'f':
+ foption = optarg;
+ break;
+ case 'h':
+ check_integer_arg('h', optarg, 1, &hash_table_size);
+ if (!is_prime(hash_table_size)) {
+ while (!is_prime(++hash_table_size))
+ ;
+ warning("%1 not prime: using %2 instead", optarg, hash_table_size);
+ }
+ break;
+ case 'i':
+ ignore_fields = optarg;
+ break;
+ case 'k':
+ check_integer_arg('k', optarg, 1, &max_keys_per_item);
+ break;
+ case 'l':
+ check_integer_arg('l', optarg, 0, &shortest_len);
+ break;
+ case 'n':
+ check_integer_arg('n', optarg, 0, &n_ignore_words);
+ break;
+ case 'o':
+ basename = optarg;
+ break;
+ case 't':
+ check_integer_arg('t', optarg, 1, &truncate_len);
+ break;
+ case 'w':
+ parser = do_whole_file;
+ break;
+ case 'v':
+ {
+ extern const char *version_string;
+ fprintf(stderr, "GNU indxbib version %s\n", version_string);
+ fflush(stderr);
+ break;
+ }
+ case '?':
+ usage();
+ break;
+ default:
+ assert(0);
+ break;
+ }
+ if (optind >= argc && foption == 0)
+ fatal("no files and no -f option");
+ if (!directory) {
+ char *path = get_cwd();
+ store_filename(path);
+ a_delete path;
+ }
+ else
+ store_filename(directory);
+ init_hash_table();
+ store_filename(common_words_file);
+ store_filename(ignore_fields);
+ key_buffer = new char[truncate_len];
+ read_common_words_file();
+ if (!basename)
+ basename = optind < argc ? argv[optind] : DEFAULT_INDEX_NAME;
+ const char *p = strrchr(basename, '/');
+ long name_max;
+ if (p) {
+ char *dir = strsave(basename);
+ dir[p - basename] = '\0';
+ name_max = dir_name_max(dir);
+ a_delete dir;
+ }
+ else
+ name_max = dir_name_max(".");
+ const char *filename = p ? p + 1 : basename;
+ if (name_max >= 0 && strlen(filename) + sizeof(INDEX_SUFFIX) - 1 > name_max)
+ fatal("`%1.%2' is too long for a filename", filename, INDEX_SUFFIX);
+ if (p) {
+ p++;
+ temp_index_file = new char[p - basename + sizeof(TEMP_INDEX_TEMPLATE)];
+ memcpy(temp_index_file, basename, p - basename);
+ strcpy(temp_index_file + (p - basename), TEMP_INDEX_TEMPLATE);
+ }
+ else {
+ temp_index_file = strsave(TEMP_INDEX_TEMPLATE);
+ }
+ if (!mktemp(temp_index_file) || !temp_index_file[0])
+ fatal("cannot create file name for temporary file");
+ catch_fatal_signals();
+ int fd = creat(temp_index_file, S_IRUSR|S_IRGRP|S_IROTH);
+ if (fd < 0)
+ fatal("can't create temporary index file: %1", strerror(errno));
+ indxfp = fdopen(fd, "w");
+ if (indxfp == 0)
+ fatal("fdopen failed");
+ if (fseek(indxfp, sizeof(index_header), 0) < 0)
+ fatal("can't seek past index header: %1", strerror(errno));
+ int failed = 0;
+ if (foption) {
+ FILE *fp = stdin;
+ if (strcmp(foption, "-") != 0) {
+ errno = 0;
+ fp = fopen(foption, "r");
+ if (!fp)
+ fatal("can't open `%1': %2", foption, strerror(errno));
+ }
+ string path;
+ int lineno = 1;
+ for (;;) {
+ for (int c = getc(fp); c != '\n' && c != EOF; c = getc(fp)) {
+ if (c == '\0')
+ error_with_file_and_line(foption, lineno,
+ "nul character in pathname ignored");
+ else
+ path += c;
+ }
+ if (path.length() > 0) {
+ path += '\0';
+ if (!(*parser)(path.contents()))
+ failed = 1;
+ path.clear();
+ }
+ if (c == EOF)
+ break;
+ lineno++;
+ }
+ if (fp != stdin)
+ fclose(fp);
+ }
+ for (int i = optind; i < argc; i++)
+ if (!(*parser)(argv[i]))
+ failed = 1;
+ write_hash_table();
+ if (fclose(indxfp) < 0)
+ fatal("error closing temporary index file: %1", strerror(errno));
+ char *index_file = new char[strlen(basename) + sizeof(INDEX_SUFFIX)];
+ strcpy(index_file, basename);
+ strcat(index_file, INDEX_SUFFIX);
+#ifdef HAVE_RENAME
+ if (rename(temp_index_file, index_file) < 0)
+ fatal("can't rename temporary index file: %1", strerror(errno));
+#else /* not HAVE_RENAME */
+ ignore_fatal_signals();
+ if (unlink(index_file) < 0) {
+ if (errno != ENOENT)
+ fatal("can't unlink `%1': %2", index_file, strerror(errno));
+ }
+ if (link(temp_index_file, index_file) < 0)
+ fatal("can't link temporary index file: %1", strerror(errno));
+ if (unlink(temp_index_file) < 0)
+ fatal("can't unlink temporary index file: %1", strerror(errno));
+#endif /* not HAVE_RENAME */
+ temp_index_file = 0;
+ return failed;
+}
+
+static void usage()
+{
+ fprintf(stderr,
+"usage: %s [-vw] [-c file] [-d dir] [-f file] [-h n] [-i XYZ] [-k n]\n"
+" [-l n] [-n n] [-o base] [-t n] [files...]\n",
+ program_name);
+ exit(1);
+}
+
+static void check_integer_arg(char opt, const char *arg, int min, int *res)
+{
+ char *ptr;
+ long n = strtol(arg, &ptr, 10);
+ if (n == 0 && ptr == arg)
+ error("argument to -%1 not an integer", opt);
+ else if (n < min)
+ error("argument to -%1 must not be less than %2", opt, min);
+ else {
+ if (n > INT_MAX)
+ error("argument to -%1 greater than maximum integer", opt);
+ else if (*ptr != '\0')
+ error("junk after integer argument to -%1", opt);
+ *res = int(n);
+ }
+}
+
+static char *get_cwd()
+{
+ char *buf;
+ int size = 12;
+
+ for (;;) {
+ buf = new char[size];
+ if (getcwd(buf, size))
+ break;
+ if (errno != ERANGE)
+ fatal("cannot get current working directory: %1", strerror(errno));
+ a_delete buf;
+ if (size == INT_MAX)
+ fatal("current working directory longer than INT_MAX");
+ if (size > INT_MAX/2)
+ size = INT_MAX;
+ else
+ size *= 2;
+ }
+ return buf;
+}
+
+word_list::word_list(const char *s, int n, word_list *p)
+: next(p), len(n)
+{
+ str = new char[n];
+ memcpy(str, s, n);
+}
+
+static void read_common_words_file()
+{
+ if (n_ignore_words <= 0)
+ return;
+ errno = 0;
+ FILE *fp = fopen(common_words_file, "r");
+ if (!fp)
+ fatal("can't open `%1': %2", common_words_file, strerror(errno));
+ common_words_table = new word_list * [hash_table_size];
+ for (int i = 0; i < hash_table_size; i++)
+ common_words_table[i] = 0;
+ int count = 0;
+ int key_len = 0;
+ for (;;) {
+ int c = getc(fp);
+ while (c != EOF && !csalnum(c))
+ c = getc(fp);
+ if (c == EOF)
+ break;
+ do {
+ if (key_len < truncate_len)
+ key_buffer[key_len++] = cmlower(c);
+ c = getc(fp);
+ } while (c != EOF && csalnum(c));
+ if (key_len >= shortest_len) {
+ int h = hash(key_buffer, key_len) % hash_table_size;
+ common_words_table[h] = new word_list(key_buffer, key_len,
+ common_words_table[h]);
+ }
+ if (++count >= n_ignore_words)
+ break;
+ key_len = 0;
+ if (c == EOF)
+ break;
+ }
+ n_ignore_words = count;
+ fclose(fp);
+}
+
+static int do_whole_file(const char *filename)
+{
+ errno = 0;
+ FILE *fp = fopen(filename, "r");
+ if (!fp) {
+ error("can't open `%1': %2", filename, strerror(errno));
+ return 0;
+ }
+ int count = 0;
+ int key_len = 0;
+ int c;
+ while ((c = getc(fp)) != EOF) {
+ if (csalnum(c)) {
+ key_len = 1;
+ key_buffer[0] = c;
+ while ((c = getc(fp)) != EOF) {
+ if (!csalnum(c))
+ break;
+ if (key_len < truncate_len)
+ key_buffer[key_len++] = c;
+ }
+ if (store_key(key_buffer, key_len)) {
+ if (++count >= max_keys_per_item)
+ break;
+ }
+ if (c == EOF)
+ break;
+ }
+ }
+ store_reference(filenames.length(), 0, 0);
+ store_filename(filename);
+ fclose(fp);
+ return 1;
+}
+
+static int do_file(const char *filename)
+{
+ errno = 0;
+ FILE *fp = fopen(filename, "r");
+ if (fp == 0) {
+ error("can't open `%1': %2", filename, strerror(errno));
+ return 0;
+ }
+ int filename_index = filenames.length();
+ store_filename(filename);
+
+ enum {
+ START, // at the start of the file; also in between references
+ BOL, // in the middle of a reference, at the beginning of the line
+ PERCENT, // seen a percent at the beginning of the line
+ IGNORE, // ignoring a field
+ IGNORE_BOL, // at the beginning of a line ignoring a field
+ KEY, // in the middle of a key
+ DISCARD, // after truncate_len bytes of a key
+ MIDDLE // in between keys
+ } state = START;
+
+ // In states START, BOL, IGNORE_BOL, space_count how many spaces at
+ // the beginning have been seen. In states PERCENT, IGNORE, KEY,
+ // MIDDLE space_count must be 0.
+ int space_count = 0;
+ int byte_count = 0; // bytes read
+ int key_len = 0;
+ int ref_start = -1; // position of start of current reference
+ for (;;) {
+ int c = getc(fp);
+ if (c == EOF)
+ break;
+ byte_count++;
+ switch (state) {
+ case START:
+ if (c == ' ' || c == '\t') {
+ space_count++;
+ break;
+ }
+ if (c == '\n') {
+ space_count = 0;
+ break;
+ }
+ ref_start = byte_count - space_count - 1;
+ space_count = 0;
+ if (c == '%')
+ state = PERCENT;
+ else if (csalnum(c)) {
+ state = KEY;
+ key_buffer[0] = c;
+ key_len = 1;
+ }
+ else
+ state = MIDDLE;
+ break;
+ case BOL:
+ switch (c) {
+ case '%':
+ if (space_count > 0) {
+ space_count = 0;
+ state = MIDDLE;
+ }
+ else
+ state = PERCENT;
+ break;
+ case ' ':
+ case '\t':
+ space_count++;
+ break;
+ case '\n':
+ store_reference(filename_index, ref_start,
+ byte_count - 1 - space_count - ref_start);
+ state = START;
+ space_count = 0;
+ break;
+ default:
+ space_count = 0;
+ if (csalnum(c)) {
+ state = KEY;
+ key_buffer[0] = c;
+ key_len = 1;
+ }
+ else
+ state = MIDDLE;
+ }
+ break;
+ case PERCENT:
+ if (strchr(ignore_fields, c) != 0)
+ state = IGNORE;
+ else if (c == '\n')
+ state = BOL;
+ else
+ state = MIDDLE;
+ break;
+ case IGNORE:
+ if (c == '\n')
+ state = IGNORE_BOL;
+ break;
+ case IGNORE_BOL:
+ switch (c) {
+ case '%':
+ if (space_count > 0) {
+ state = IGNORE;
+ space_count = 0;
+ }
+ else
+ state = PERCENT;
+ break;
+ case ' ':
+ case '\t':
+ space_count++;
+ break;
+ case '\n':
+ store_reference(filename_index, ref_start,
+ byte_count - 1 - space_count - ref_start);
+ state = START;
+ space_count = 0;
+ break;
+ default:
+ space_count = 0;
+ state = IGNORE;
+ }
+ break;
+ case KEY:
+ if (csalnum(c)) {
+ if (key_len < truncate_len)
+ key_buffer[key_len++] = c;
+ else
+ state = DISCARD;
+ }
+ else {
+ possibly_store_key(key_buffer, key_len);
+ key_len = 0;
+ if (c == '\n')
+ state = BOL;
+ else
+ state = MIDDLE;
+ }
+ break;
+ case DISCARD:
+ if (!csalnum(c)) {
+ possibly_store_key(key_buffer, key_len);
+ key_len = 0;
+ if (c == '\n')
+ state = BOL;
+ else
+ state = MIDDLE;
+ }
+ break;
+ case MIDDLE:
+ if (csalnum(c)) {
+ state = KEY;
+ key_buffer[0] = c;
+ key_len = 1;
+ }
+ else if (c == '\n')
+ state = BOL;
+ break;
+ default:
+ assert(0);
+ }
+ }
+ switch (state) {
+ case START:
+ break;
+ case DISCARD:
+ case KEY:
+ possibly_store_key(key_buffer, key_len);
+ // fall through
+ case BOL:
+ case PERCENT:
+ case IGNORE_BOL:
+ case IGNORE:
+ case MIDDLE:
+ store_reference(filename_index, ref_start,
+ byte_count - ref_start - space_count);
+ break;
+ default:
+ assert(0);
+ }
+ fclose(fp);
+ return 1;
+}
+
+static void store_reference(int filename_index, int pos, int len)
+{
+ tag t;
+ t.filename_index = filename_index;
+ t.start = pos;
+ t.length = len;
+ fwrite_or_die(&t, sizeof(t), 1, indxfp);
+ ntags++;
+}
+
+static void store_filename(const char *fn)
+{
+ filenames += fn;
+ filenames += '\0';
+}
+
+static void init_hash_table()
+{
+ hash_table = new table_entry[hash_table_size];
+ for (int i = 0; i < hash_table_size; i++)
+ hash_table[i].ptr = 0;
+}
+
+static void possibly_store_key(char *s, int len)
+{
+ static int last_tagno = -1;
+ static int key_count;
+ if (last_tagno != ntags) {
+ last_tagno = ntags;
+ key_count = 0;
+ }
+ if (key_count < max_keys_per_item) {
+ if (store_key(s, len))
+ key_count++;
+ }
+}
+
+static int store_key(char *s, int len)
+{
+ if (len < shortest_len)
+ return 0;
+ int is_number = 1;
+ for (int i = 0; i < len; i++)
+ if (!csdigit(s[i])) {
+ is_number = 0;
+ s[i] = cmlower(s[i]);
+ }
+ if (is_number && !(len == 4 && s[0] == '1' && s[1] == '9'))
+ return 0;
+ int h = hash(s, len) % hash_table_size;
+ if (common_words_table) {
+ for (word_list *ptr = common_words_table[h]; ptr; ptr = ptr->next)
+ if (len == ptr->len && memcmp(s, ptr->str, len) == 0)
+ return 0;
+ }
+ table_entry *pp = hash_table + h;
+ if (!pp->ptr)
+ pp->ptr = new block;
+ else if (pp->ptr->v[pp->ptr->used - 1] == ntags)
+ return 1;
+ else if (pp->ptr->used >= BLOCK_SIZE)
+ pp->ptr = new block(pp->ptr);
+ pp->ptr->v[(pp->ptr->used)++] = ntags;
+ return 1;
+}
+
+static void write_hash_table()
+{
+ const int minus_one = -1;
+ int li = 0;
+ for (int i = 0; i < hash_table_size; i++) {
+ block *ptr = hash_table[i].ptr;
+ if (!ptr)
+ hash_table[i].count = -1;
+ else {
+ hash_table[i].count = li;
+ block *rev = 0;
+ while (ptr) {
+ block *tem = ptr;
+ ptr = ptr->next;
+ tem->next = rev;
+ rev = tem;
+ }
+ while (rev) {
+ fwrite_or_die(rev->v, sizeof(int), rev->used, indxfp);
+ li += rev->used;
+ block *tem = rev;
+ rev = rev->next;
+ delete tem;
+ }
+ fwrite_or_die(&minus_one, sizeof(int), 1, indxfp);
+ li += 1;
+ }
+ }
+ if (sizeof(table_entry) == sizeof(int))
+ fwrite_or_die(hash_table, sizeof(int), hash_table_size, indxfp);
+ else {
+ // write it out word by word
+ for (int i = 0; i < hash_table_size; i++)
+ fwrite_or_die(&hash_table[i].count, sizeof(int), 1, indxfp);
+ }
+ fwrite_or_die(filenames.contents(), 1, filenames.length(), indxfp);
+ if (fseek(indxfp, 0, 0) < 0)
+ fatal("error seeking on index file: %1", strerror(errno));
+ index_header h;
+ h.magic = INDEX_MAGIC;
+ h.version = INDEX_VERSION;
+ h.tags_size = ntags;
+ h.lists_size = li;
+ h.table_size = hash_table_size;
+ h.strings_size = filenames.length();
+ h.truncate = truncate_len;
+ h.shortest = shortest_len;
+ h.common = n_ignore_words;
+ fwrite_or_die(&h, sizeof(h), 1, indxfp);
+}
+
+static void fwrite_or_die(const void *ptr, int size, int nitems, FILE *fp)
+{
+ if (fwrite(ptr, size, nitems, fp) != nitems)
+ fatal("fwrite failed: %1", strerror(errno));
+}
+
+void fatal_error_exit()
+{
+ cleanup();
+ exit(3);
+}
+
+extern "C" {
+
+void cleanup()
+{
+ if (temp_index_file)
+ unlink(temp_index_file);
+}
+
+}
diff --git a/gnu/usr.bin/groff/indxbib/indxbib.man b/gnu/usr.bin/groff/indxbib/indxbib.man
new file mode 100644
index 0000000..984cf79
--- /dev/null
+++ b/gnu/usr.bin/groff/indxbib/indxbib.man
@@ -0,0 +1,187 @@
+.\" -*- nroff -*-
+.TH @G@INDXBIB @MAN1EXT@ "@MDATE@" "Groff Version @VERSION@"
+.SH NAME
+@g@indxbib \- make inverted index for bibliographic databases
+.SH SYNOPSIS
+.nr a \n(.j
+.ad l
+.nr i \n(.i
+.in +\w'\fB@g@indxbib 'u
+.ti \niu
+.B @g@indxbib
+.de OP
+.ie \\n(.$-1 .RI "[\ \fB\\$1\fP" "\\$2" "\ ]"
+.el .RB "[\ " "\\$1" "\ ]"
+..
+.OP \-vw
+.OP \-c file
+.OP \-d dir
+.OP \-f file
+.OP \-h n
+.OP \-i string
+.OP \-k n
+.OP \-l n
+.OP \-n n
+.OP \-o file
+.OP \-t n
+.RI [\ filename \|.\|.\|.\ ]
+.ad \na
+.SH DESCRIPTION
+.B @g@indxbib
+makes an inverted index for the bibliographic databases in
+.IR filename \|.\|.\|.
+for use with
+.BR @g@refer (@MAN1EXT@),
+.BR @g@lookbib (@MAN1EXT@),
+and
+.BR lkbib (@MAN1EXT@).
+The index will be named
+.IB filename @INDEX_SUFFIX@\fR;
+the index is written to a temporary file which is then renamed to this.
+If no filenames are given on the command line because the
+.B \-f
+option has been used, and no
+.B \-o
+option is given, the index will be named
+.BR @DEFAULT_INDEX_NAME@@INDEX_SUFFIX@ .
+.LP
+Bibliographic databases are divided into records by blank lines.
+Within a record, each fields starts with a
+.B %
+character at the beginning of a line.
+Fields have a one letter name which follows the
+.B %
+character.
+.LP
+The values set by the
+.BR \-c ,
+.BR \-n ,
+.BR \-l
+and
+.B \-t
+options are stored in the index;
+when the index is searched, keys will be discarded and truncated in a
+manner appropriate to these options;
+the original keys will be used for verifying that any record
+found using the index actually contains the keys.
+This means that a user of an index need not know whether these
+options were used in the creation of the index,
+provided that not all the keys to be searched for
+would have been discarded during indexing
+and that the user supplies at least the part of each key
+that would have remained after being truncated during indexing.
+The value set by the
+.B \-i
+option is also stored in the index
+and will be used in verifying records found using the index.
+.SH OPTIONS
+.TP
+.B \-v
+Print the version number.
+.TP
+.B \-w
+Index whole files.
+Each file is a separate record.
+.TP
+.BI \-c file
+Read the list of common words from
+.I file
+instead of
+.BR @COMMON_WORDS_FILE@ .
+.TP
+.BI \-d dir
+Use
+.I dir
+as the pathname of the current working directory to store in the index,
+instead of the path printed by
+.BR pwd (1).
+Usually
+.I dir
+will be a symbolic link that points to the directory printed by
+.BR pwd (1).
+.TP
+.BI \-f file
+Read the files to be indexed from
+.IR file .
+If
+.I file
+is
+.BR \- ,
+files will be read from the standard input.
+The
+.B \-f
+option can be given at most once.
+.TP
+.BI \-i string
+Don't index the contents of fields whose names are in
+.IR string .
+Initially
+.I string
+is
+.BR XYZ .
+.TP
+.BI \-h n
+Use the first prime greater than or equal to
+.I n
+for the size of the hash table.
+Larger values of
+.I n
+will usually make searching faster,
+but will make the index larger
+and
+.B @g@indxbib
+use more memory.
+Initially
+.I n
+is 997.
+.TP
+.BI \-k n
+Use at most
+.I n
+keys per input record.
+Initially
+.I n
+is 100.
+.TP
+.BI \-l n
+Discard keys that are shorter than
+.IR n .
+Initially
+.I n
+is 3.
+.TP
+.BI \-n n
+Discard the
+.I n
+most common words.
+Initially
+.I n
+is 100.
+.TP
+.BI \-o basename
+The index should be named
+.IB basename @INDEX_SUFFIX@\fR.
+.TP
+.BI \-t n
+Truncate keys to
+.IR n .
+Initially
+.I n
+is 6.
+.SH FILES
+.TP \w'\fBindxbib\fIXXXXXX'u+2n
+.IB filename @INDEX_SUFFIX@
+Index.
+.TP
+.B @DEFAULT_INDEX_NAME@@INDEX_SUFFIX@
+Default index name.
+.TP
+.B @COMMON_WORDS_FILE@
+List of common words.
+.TP
+.BI indxbib XXXXXX
+Temporary file.
+.SH "SEE ALSO"
+.BR @g@refer (@MAN1EXT@),
+.BR lkbib (@MAN1EXT@),
+.BR @g@lookbib (@MAN1EXT@)
diff --git a/gnu/usr.bin/groff/indxbib/signal.c b/gnu/usr.bin/groff/indxbib/signal.c
new file mode 100644
index 0000000..7c81f91
--- /dev/null
+++ b/gnu/usr.bin/groff/indxbib/signal.c
@@ -0,0 +1,63 @@
+/* Copyright (C) 1992 Free Software Foundation, Inc.
+ Written by James Clark (jjc@jclark.com)
+
+This file is part of groff.
+
+groff is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
+
+groff is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License along
+with groff; see the file COPYING. If not, write to the Free Software
+Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* Unfortunately vendors seem to have problems writing a <signal.h>
+that is correct for C++, so we implement all signal handling in C. */
+
+#include <sys/types.h>
+#include <signal.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#ifndef RETSIGTYPE
+#define RETSIGTYPE void
+#endif
+
+extern void cleanup();
+
+static RETSIGTYPE handle_fatal_signal(signum)
+ int signum;
+{
+ signal(signum, SIG_DFL);
+ cleanup();
+ kill(getpid(), signum);
+}
+
+void catch_fatal_signals()
+{
+#ifdef SIGHUP
+ signal(SIGHUP, handle_fatal_signal);
+#endif
+ signal(SIGINT, handle_fatal_signal);
+ signal(SIGTERM, handle_fatal_signal);
+}
+
+#ifndef HAVE_RENAME
+
+void ignore_fatal_signals()
+{
+#ifdef SIGHUP
+ signal(SIGHUP, SIG_IGN);
+#endif
+ signal(SIGINT, SIG_IGN);
+ signal(SIGTERM, SIG_IGN);
+}
+
+#endif /* not HAVE_RENAME */
diff --git a/gnu/usr.bin/groff/libbib/Makefile b/gnu/usr.bin/groff/libbib/Makefile
new file mode 100644
index 0000000..df2c5a9
--- /dev/null
+++ b/gnu/usr.bin/groff/libbib/Makefile
@@ -0,0 +1,13 @@
+# Makefile for libbib
+
+LIB= bib
+SRCS= common.cc index.cc linear.cc search.cc map.c
+CFLAGS+= -I$(.CURDIR)/../include
+
+NOMAN= noman
+NOPROFILE= noprofile
+
+install:
+
+.include "../Makefile.cfg"
+.include <bsd.lib.mk>
diff --git a/gnu/usr.bin/groff/libbib/Makefile.dep b/gnu/usr.bin/groff/libbib/Makefile.dep
new file mode 100644
index 0000000..906a38a
--- /dev/null
+++ b/gnu/usr.bin/groff/libbib/Makefile.dep
@@ -0,0 +1,12 @@
+common.o : common.cc
+index.o : index.cc ../include/posix.h ../include/lib.h ../include/cset.h \
+ ../include/cmap.h ../include/errarg.h ../include/error.h \
+ ../include/refid.h ../include/search.h ../include/index.h \
+ ../include/defs.h
+linear.o : linear.cc ../include/posix.h ../include/lib.h \
+ ../include/errarg.h ../include/error.h ../include/cset.h \
+ ../include/cmap.h ../include/refid.h ../include/search.h
+search.o : search.cc ../include/posix.h ../include/lib.h \
+ ../include/errarg.h ../include/error.h ../include/refid.h \
+ ../include/search.h
+map.o : map.c
diff --git a/gnu/usr.bin/groff/libbib/Makefile.sub b/gnu/usr.bin/groff/libbib/Makefile.sub
new file mode 100644
index 0000000..e941828
--- /dev/null
+++ b/gnu/usr.bin/groff/libbib/Makefile.sub
@@ -0,0 +1,4 @@
+LIB=bib
+OBJS=common.o index.o linear.o search.o map.o
+CCSRCS=common.cc index.cc linear.cc search.cc
+CSRCS=map.c
diff --git a/gnu/usr.bin/groff/libbib/common.cc b/gnu/usr.bin/groff/libbib/common.cc
new file mode 100644
index 0000000..25f4078
--- /dev/null
+++ b/gnu/usr.bin/groff/libbib/common.cc
@@ -0,0 +1,38 @@
+/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
+ Written by James Clark (jjc@jclark.com)
+
+This file is part of groff.
+
+groff is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
+
+groff is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License along
+with groff; see the file COPYING. If not, write to the Free Software
+Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+unsigned hash(const char *s, int len)
+{
+#if 0
+ unsigned h = 0, g;
+ while (*s != '\0') {
+ h <<= 4;
+ h += *s++;
+ if ((g = h & 0xf0000000) != 0) {
+ h ^= g >> 24;
+ h ^= g;
+ }
+ }
+#endif
+ unsigned h = 0;
+ while (--len >= 0)
+ h = *s++ + 65587*h;
+ return h;
+}
+
diff --git a/gnu/usr.bin/groff/libbib/index.cc b/gnu/usr.bin/groff/libbib/index.cc
new file mode 100644
index 0000000..1766849
--- /dev/null
+++ b/gnu/usr.bin/groff/libbib/index.cc
@@ -0,0 +1,618 @@
+// -*- C++ -*-
+/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
+ Written by James Clark (jjc@jclark.com)
+
+This file is part of groff.
+
+groff is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
+
+groff is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License along
+with groff; see the file COPYING. If not, write to the Free Software
+Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+
+#include "posix.h"
+#include "lib.h"
+#include "cset.h"
+#include "cmap.h"
+#include "errarg.h"
+#include "error.h"
+
+#include "refid.h"
+#include "search.h"
+#include "index.h"
+#include "defs.h"
+
+// Interface to mmap.
+extern "C" {
+ void *mapread(int fd, int len);
+ int unmap(void *, int len);
+}
+
+const int minus_one = -1;
+
+int verify_flag = 0;
+
+struct word_list;
+
+class index_search_item : public search_item {
+ search_item *out_of_date_files;
+ index_header header;
+ char *buffer;
+ void *map_addr;
+ int map_len;
+ tag *tags;
+ int *table;
+ int *lists;
+ char *pool;
+ char *key_buffer;
+ char *filename_buffer;
+ int filename_buflen;
+ char **common_words_table;
+ int common_words_table_size;
+ const char *ignore_fields;
+ time_t mtime;
+
+ const char *do_verify();
+ const int *search1(const char **pp, const char *end);
+ const int *search(const char *ptr, int length, int **temp_listp);
+ const char *munge_filename(const char *);
+ void read_common_words_file();
+ void add_out_of_date_file(int fd, const char *filename, int fid);
+public:
+ index_search_item(const char *, int);
+ ~index_search_item();
+ int load(int fd);
+ search_item_iterator *make_search_item_iterator(const char *);
+ int verify();
+ void check_files();
+ int next_filename_id() const;
+ friend class index_search_item_iterator;
+};
+
+class index_search_item_iterator : public search_item_iterator {
+ index_search_item *indx;
+ search_item_iterator *out_of_date_files_iter;
+ search_item *next_out_of_date_file;
+ const int *found_list;
+ int *temp_list;
+ char *buf;
+ int buflen;
+ linear_searcher searcher;
+ char *query;
+ int get_tag(int tagno, const linear_searcher &, const char **, int *,
+ reference_id *);
+public:
+ index_search_item_iterator(index_search_item *, const char *);
+ ~index_search_item_iterator();
+ int next(const linear_searcher &, const char **, int *, reference_id *);
+};
+
+
+index_search_item::index_search_item(const char *filename, int fid)
+: search_item(filename, fid), out_of_date_files(0), key_buffer(0),
+ filename_buffer(0), filename_buflen(0), common_words_table(0),
+ map_addr(0), map_len(0), buffer(0)
+{
+}
+
+index_search_item::~index_search_item()
+{
+ if (buffer)
+ free(buffer);
+ if (map_addr) {
+ if (unmap(map_addr, map_len) < 0)
+ error("unmap: %1", strerror(errno));
+ }
+ while (out_of_date_files) {
+ search_item *tem = out_of_date_files;
+ out_of_date_files = out_of_date_files->next;
+ delete tem;
+ }
+ a_delete filename_buffer;
+ a_delete key_buffer;
+ if (common_words_table) {
+ for (int i = 0; i < common_words_table_size; i++)
+ a_delete common_words_table[i];
+ a_delete common_words_table;
+ }
+}
+
+class file_closer {
+ int *fdp;
+public:
+ file_closer(int &fd) : fdp(&fd) { }
+ ~file_closer() { close(*fdp); }
+};
+
+// Tell the compiler that a variable is intentionally unused.
+inline void unused(void *) { }
+
+int index_search_item::load(int fd)
+{
+ file_closer fd_closer(fd); // close fd on return
+ unused(&fd_closer);
+ struct stat sb;
+ if (fstat(fd, &sb) < 0) {
+ error("can't fstat `%1': %2", name, strerror(errno));
+ return 0;
+ }
+ if (!S_ISREG(sb.st_mode)) {
+ error("`%1' is not a regular file", name);
+ return 0;
+ }
+ mtime = sb.st_mtime;
+ int size = int(sb.st_size);
+ char *addr;
+ map_addr = mapread(fd, size);
+ if (map_addr) {
+ addr = (char *)map_addr;
+ map_len = size;
+ }
+ else {
+ addr = buffer = (char *)malloc(size);
+ if (buffer == 0) {
+ error("can't allocate buffer for `%1'", name);
+ return 0;
+ }
+ char *ptr = buffer;
+ int bytes_to_read = size;
+ while (bytes_to_read > 0) {
+ int nread = read(fd, ptr, bytes_to_read);
+ if (nread == 0) {
+ error("unexpected EOF on `%1'", name);
+ return 0;
+ }
+ if (nread < 0) {
+ error("read error on `%1': %2", name, strerror(errno));
+ return 0;
+ }
+ bytes_to_read -= nread;
+ ptr += nread;
+ }
+ }
+ header = *(index_header *)addr;
+ if (header.magic != INDEX_MAGIC) {
+ error("`%1' is not an index file: wrong magic number", name);
+ return 0;
+ }
+ if (header.version != INDEX_VERSION) {
+ error("version number in `%1' is wrong: was %2, should be %3",
+ name, header.version, INDEX_VERSION);
+ return 0;
+ }
+ int sz = (header.tags_size * sizeof(tag)
+ + header.lists_size * sizeof(int)
+ + header.table_size * sizeof(int)
+ + header.strings_size
+ + sizeof(header));
+ if (sz != size) {
+ error("size of `%1' is wrong: was %2, should be %3",
+ name, size, sz);
+ return 0;
+ }
+ tags = (tag *)(addr + sizeof(header));
+ lists = (int *)(tags + header.tags_size);
+ table = (int *)(lists + header.lists_size);
+ pool = (char *)(table + header.table_size);
+ ignore_fields = strchr(strchr(pool, '\0') + 1, '\0') + 1;
+ key_buffer = new char[header.truncate];
+ read_common_words_file();
+ return 1;
+}
+
+const char *index_search_item::do_verify()
+{
+ if (tags == 0)
+ return "not loaded";
+ if (lists[header.lists_size - 1] >= 0)
+ return "last list element not negative";
+ int i;
+ for (i = 0; i < header.table_size; i++) {
+ int li = table[i];
+ if (li >= header.lists_size)
+ return "bad list index";
+ if (li >= 0) {
+ for (int *ptr = lists + li; *ptr >= 0; ptr++) {
+ if (*ptr >= header.tags_size)
+ return "bad tag index";
+ if (*ptr >= ptr[1] && ptr[1] >= 0)
+ return "list not ordered";
+ }
+ }
+ }
+ for (i = 0; i < header.tags_size; i++) {
+ if (tags[i].filename_index >= header.strings_size)
+ return "bad index in tags";
+ if (tags[i].length < 0)
+ return "bad length in tags";
+ if (tags[i].start < 0)
+ return "bad start in tags";
+ }
+ if (pool[header.strings_size - 1] != '\0')
+ return "last character in pool not nul";
+ return 0;
+}
+
+int index_search_item::verify()
+{
+ const char *reason = do_verify();
+ if (!reason)
+ return 1;
+ error("`%1' is bad: %2", name, reason);
+ return 0;
+}
+
+int index_search_item::next_filename_id() const
+{
+ return filename_id + header.strings_size + 1;
+}
+
+search_item_iterator *index_search_item::make_search_item_iterator(
+ const char *query)
+{
+ return new index_search_item_iterator(this, query);
+}
+
+search_item *make_index_search_item(const char *filename, int fid)
+{
+ char *index_filename = new char[strlen(filename) + sizeof(INDEX_SUFFIX)];
+ strcpy(index_filename, filename);
+ strcat(index_filename, INDEX_SUFFIX);
+ int fd = open(index_filename, O_RDONLY);
+ if (fd < 0)
+ return 0;
+ index_search_item *item = new index_search_item(index_filename, fid);
+ a_delete index_filename;
+ if (!item->load(fd)) {
+ close(fd);
+ delete item;
+ return 0;
+ }
+ else if (verify_flag && !item->verify()) {
+ delete item;
+ return 0;
+ }
+ else {
+ item->check_files();
+ return item;
+ }
+}
+
+
+index_search_item_iterator::index_search_item_iterator(index_search_item *ind,
+ const char *q)
+: indx(ind), buf(0), buflen(0), temp_list(0), query(strsave(q)),
+ searcher(q, strlen(q), ind->ignore_fields, ind->header.truncate),
+ out_of_date_files_iter(0), next_out_of_date_file(0)
+{
+ found_list = indx->search(q, strlen(q), &temp_list);
+ if (!found_list) {
+ found_list = &minus_one;
+ warning("all keys would have been discarded in constructing index `%1'",
+ indx->name);
+ }
+}
+
+index_search_item_iterator::~index_search_item_iterator()
+{
+ a_delete temp_list;
+ a_delete buf;
+ a_delete query;
+ delete out_of_date_files_iter;
+}
+
+int index_search_item_iterator::next(const linear_searcher &,
+ const char **pp, int *lenp,
+ reference_id *ridp)
+{
+ if (found_list) {
+ for (;;) {
+ int tagno = *found_list;
+ if (tagno == -1)
+ break;
+ found_list++;
+ if (get_tag(tagno, searcher, pp, lenp, ridp))
+ return 1;
+ }
+ found_list = 0;
+ next_out_of_date_file = indx->out_of_date_files;
+ }
+ while (next_out_of_date_file) {
+ if (out_of_date_files_iter == 0)
+ out_of_date_files_iter
+ = next_out_of_date_file->make_search_item_iterator(query);
+ if (out_of_date_files_iter->next(searcher, pp, lenp, ridp))
+ return 1;
+ delete out_of_date_files_iter;
+ out_of_date_files_iter = 0;
+ next_out_of_date_file = next_out_of_date_file->next;
+ }
+ return 0;
+}
+
+int index_search_item_iterator::get_tag(int tagno,
+ const linear_searcher &searcher,
+ const char **pp, int *lenp,
+ reference_id *ridp)
+{
+ if (tagno < 0 || tagno >= indx->header.tags_size) {
+ error("bad tag number");
+ return 0;
+ }
+ tag *tp = indx->tags + tagno;
+ const char *filename = indx->munge_filename(indx->pool + tp->filename_index);
+ int fd = open(filename, O_RDONLY);
+ if (fd < 0) {
+ error("can't open `%1': %2", filename, strerror(errno));
+ return 0;
+ }
+ struct stat sb;
+ if (fstat(fd, &sb) < 0) {
+ error("can't fstat: %1", strerror(errno));
+ close(fd);
+ return 0;
+ }
+ time_t mtime = sb.st_mtime;
+ if (mtime > indx->mtime) {
+ indx->add_out_of_date_file(fd, filename,
+ indx->filename_id + tp->filename_index);
+ return 0;
+ }
+ int res = 0;
+ FILE *fp = fdopen(fd, "r");
+ if (!fp) {
+ error("fdopen failed");
+ close(fd);
+ return 0;
+ }
+ if (tp->start != 0 && fseek(fp, long(tp->start), 0) < 0)
+ error("can't seek on `%1': %2", filename, strerror(errno));
+ else {
+ int length = tp->length;
+ int err = 0;
+ if (length == 0) {
+ struct stat sb;
+ if (fstat(fileno(fp), &sb) < 0) {
+ error("can't stat `%1': %2", filename, strerror(errno));
+ err = 1;
+ }
+ else if (!S_ISREG(sb.st_mode)) {
+ error("`%1' is not a regular file", filename);
+ err = 1;
+ }
+ else
+ length = int(sb.st_size);
+ }
+ if (!err) {
+ if (length + 2 > buflen) {
+ a_delete buf;
+ buflen = length + 2;
+ buf = new char[buflen];
+ }
+ if (fread(buf + 1, 1, length, fp) != length)
+ error("fread on `%1' failed: %2", filename, strerror(errno));
+ else {
+ buf[0] = '\n';
+ buf[length + 1] = '\n';
+ res = searcher.search(buf + 1, buf + 2 + length, pp, lenp);
+ if (res && ridp)
+ *ridp = reference_id(indx->filename_id + tp->filename_index,
+ tp->start);
+ }
+ }
+ }
+ fclose(fp);
+ return res;
+}
+
+const char *index_search_item::munge_filename(const char *filename)
+{
+ if (filename[0] == '/')
+ return filename;
+ const char *cwd = pool;
+ int need_slash = (cwd[0] != 0 && strchr(cwd, '\0')[-1] != '/');
+ int len = strlen(cwd) + strlen(filename) + need_slash + 1;
+ if (len > filename_buflen) {
+ a_delete filename_buffer;
+ filename_buflen = len;
+ filename_buffer = new char[len];
+ }
+ strcpy(filename_buffer, cwd);
+ if (need_slash)
+ strcat(filename_buffer, "/");
+ strcat(filename_buffer, filename);
+ return filename_buffer;
+}
+
+const int *index_search_item::search1(const char **pp, const char *end)
+{
+ while (*pp < end && !csalnum(**pp))
+ *pp += 1;
+ if (*pp >= end)
+ return 0;
+ const char *start = *pp;
+ while (*pp < end && csalnum(**pp))
+ *pp += 1;
+ int len = *pp - start;
+ if (len < header.shortest)
+ return 0;
+ if (len > header.truncate)
+ len = header.truncate;
+ int is_number = 1;
+ for (int i = 0; i < len; i++)
+ if (csdigit(start[i]))
+ key_buffer[i] = start[i];
+ else {
+ key_buffer[i] = cmlower(start[i]);
+ is_number = 0;
+ }
+ if (is_number && !(len == 4 && start[0] == '1' && start[1] == '9'))
+ return 0;
+ unsigned hc = hash(key_buffer, len);
+ if (common_words_table) {
+ for (int h = hc % common_words_table_size;
+ common_words_table[h];
+ --h) {
+ if (strlen(common_words_table[h]) == len
+ && memcmp(common_words_table[h], key_buffer, len) == 0)
+ return 0;
+ if (h == 0)
+ h = common_words_table_size;
+ }
+ }
+ int li = table[int(hc % header.table_size)];
+ return li < 0 ? &minus_one : lists + li;
+}
+
+static void merge(int *result, const int *s1, const int *s2)
+{
+ for (; *s1 >= 0; s1++) {
+ while (*s2 >= 0 && *s2 < *s1)
+ s2++;
+ if (*s2 == *s1)
+ *result++ = *s2;
+ }
+ *result++ = -1;
+}
+
+const int *index_search_item::search(const char *ptr, int length,
+ int **temp_listp)
+{
+ const char *end = ptr + length;
+ if (*temp_listp) {
+ a_delete *temp_listp;
+ *temp_listp = 0;
+ }
+ const int *first_list = 0;
+ while (ptr < end && (first_list = search1(&ptr, end)) == 0)
+ ;
+ if (!first_list)
+ return 0;
+ if (*first_list < 0)
+ return first_list;
+ const int *second_list = 0;
+ while (ptr < end && (second_list = search1(&ptr, end)) == 0)
+ ;
+ if (!second_list)
+ return first_list;
+ if (*second_list < 0)
+ return second_list;
+ for (const int *p = first_list; *p >= 0; p++)
+ ;
+ int len = p - first_list;
+ for (p = second_list; *p >= 0; p++)
+ ;
+ if (p - second_list < len)
+ len = p - second_list;
+ int *matches = new int[len + 1];
+ merge(matches, first_list, second_list);
+ while (ptr < end) {
+ const int *list = search1(&ptr, end);
+ if (list != 0) {
+ if (*list < 0) {
+ a_delete matches;
+ return list;
+ }
+ merge(matches, matches, list);
+ if (*matches < 0) {
+ a_delete matches;
+ return &minus_one;
+ }
+ }
+ }
+ *temp_listp = matches;
+ return matches;
+}
+
+void index_search_item::read_common_words_file()
+{
+ if (header.common <= 0)
+ return;
+ const char *common_words_file = munge_filename(strchr(pool, '\0') + 1);
+ errno = 0;
+ FILE *fp = fopen(common_words_file, "r");
+ if (!fp) {
+ error("can't open `%1': %2", common_words_file, strerror(errno));
+ return;
+ }
+ common_words_table_size = 2*header.common + 1;
+ while (!is_prime(common_words_table_size))
+ common_words_table_size++;
+ common_words_table = new char *[common_words_table_size];
+ for (int i = 0; i < common_words_table_size; i++)
+ common_words_table[i] = 0;
+ int count = 0;
+ int key_len = 0;
+ for (;;) {
+ int c = getc(fp);
+ while (c != EOF && !csalnum(c))
+ c = getc(fp);
+ if (c == EOF)
+ break;
+ do {
+ if (key_len < header.truncate)
+ key_buffer[key_len++] = cmlower(c);
+ c = getc(fp);
+ } while (c != EOF && csalnum(c));
+ if (key_len >= header.shortest) {
+ int h = hash(key_buffer, key_len) % common_words_table_size;
+ while (common_words_table[h]) {
+ if (h == 0)
+ h = common_words_table_size;
+ --h;
+ }
+ common_words_table[h] = new char[key_len + 1];
+ memcpy(common_words_table[h], key_buffer, key_len);
+ common_words_table[h][key_len] = '\0';
+ }
+ if (++count >= header.common)
+ break;
+ key_len = 0;
+ if (c == EOF)
+ break;
+ }
+ fclose(fp);
+}
+
+void index_search_item::add_out_of_date_file(int fd, const char *filename,
+ int fid)
+{
+ for (search_item **pp = &out_of_date_files; *pp; pp = &(*pp)->next)
+ if ((*pp)->is_named(filename))
+ return;
+ *pp = make_linear_search_item(fd, filename, fid);
+ warning("`%1' modified since `%2' created", filename, name);
+}
+
+void index_search_item::check_files()
+{
+ const char *pool_end = pool + header.strings_size;
+ for (const char *ptr = strchr(ignore_fields, '\0') + 1;
+ ptr < pool_end;
+ ptr = strchr(ptr, '\0') + 1) {
+ const char *path = munge_filename(ptr);
+ struct stat sb;
+ if (stat(path, &sb) < 0)
+ error("can't stat `%1': %2", path, strerror(errno));
+ else if (sb.st_mtime > mtime) {
+ int fd = open(path, O_RDONLY);
+ if (fd < 0)
+ error("can't open `%1': %2", path, strerror(errno));
+ else
+ add_out_of_date_file(fd, path, filename_id + (ptr - pool));
+ }
+ }
+}
diff --git a/gnu/usr.bin/groff/libbib/linear.cc b/gnu/usr.bin/groff/libbib/linear.cc
new file mode 100644
index 0000000..2aa0584
--- /dev/null
+++ b/gnu/usr.bin/groff/libbib/linear.cc
@@ -0,0 +1,484 @@
+// -*- C++ -*-
+/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
+ Written by James Clark (jjc@jclark.com)
+
+This file is part of groff.
+
+groff is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
+
+groff is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License along
+with groff; see the file COPYING. If not, write to the Free Software
+Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+
+#include <string.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <errno.h>
+
+#include "posix.h"
+#include "lib.h"
+#include "errarg.h"
+#include "error.h"
+#include "cset.h"
+#include "cmap.h"
+
+#include "refid.h"
+#include "search.h"
+
+class file_buffer {
+ char *buffer;
+ char *bufend;
+public:
+ file_buffer();
+ ~file_buffer();
+ int load(int fd, const char *filename);
+ const char *get_start() const;
+ const char *get_end() const;
+};
+
+typedef unsigned char uchar;
+
+static uchar map[256];
+static uchar inv_map[256][3];
+
+struct map_init {
+ map_init();
+};
+
+static map_init the_map_init;
+
+map_init::map_init()
+{
+ for (int i = 0; i < 256; i++)
+ map[i] = csalnum(i) ? cmlower(i) : '\0';
+ for (i = 0; i < 256; i++) {
+ if (cslower(i)) {
+ inv_map[i][0] = i;
+ inv_map[i][1] = cmupper(i);
+ inv_map[i][2] = '\0';
+ }
+ else if (csdigit(i)) {
+ inv_map[i][0] = i;
+ inv_map[i][1] = 0;
+ }
+ else
+ inv_map[i][0] = '\0';
+ }
+}
+
+
+class bmpattern {
+ char *pat;
+ int len;
+ int delta[256];
+public:
+ bmpattern(const char *pattern, int pattern_length);
+ ~bmpattern();
+ const char *search(const char *p, const char *end) const;
+ int length() const;
+};
+
+bmpattern::bmpattern(const char *pattern, int pattern_length)
+: len(pattern_length)
+{
+ pat = new char[len];
+ int i;
+ for (i = 0; i < len; i++)
+ pat[i] = map[uchar(pattern[i])];
+ for (i = 0; i < 256; i++)
+ delta[i] = len;
+ for (i = 0; i < len; i++)
+ for (const unsigned char *inv = inv_map[uchar(pat[i])]; *inv; inv++)
+ delta[*inv] = len - i - 1;
+}
+
+const char *bmpattern::search(const char *buf, const char *end) const
+{
+ int buflen = end - buf;
+ if (len > buflen)
+ return 0;
+ const char *strend;
+ if (buflen > len*4)
+ strend = end - len*4;
+ else
+ strend = buf;
+ const char *k = buf + len - 1;
+ const int *del = delta;
+ const char *pattern = pat;
+ for (;;) {
+ while (k < strend) {
+ int t = del[uchar(*k)];
+ if (!t)
+ break;
+ k += t;
+ k += del[uchar(*k)];
+ k += del[uchar(*k)];
+ }
+ while (k < end && del[uchar(*k)] != 0)
+ k++;
+ if (k == end)
+ break;
+ int j = len - 1;
+ const char *s = k;
+ for (;;) {
+ if (j == 0)
+ return s;
+ if (map[uchar(*--s)] != uchar(pattern[--j]))
+ break;
+ }
+ k++;
+ }
+ return 0;
+}
+
+bmpattern::~bmpattern()
+{
+ a_delete pat;
+}
+
+inline int bmpattern::length() const
+{
+ return len;
+}
+
+
+static const char *find_end(const char *bufend, const char *p);
+
+const char *linear_searcher::search_and_check(const bmpattern *key,
+ const char *buf, const char *bufend, const char **start) const
+{
+ assert(buf[-1] == '\n');
+ assert(bufend[-1] == '\n');
+ const char *ptr = buf;
+ for (;;) {
+ const char *found = key->search(ptr, bufend);
+ if (!found)
+ break;
+ if (check_match(buf, bufend, found, key->length(), &ptr, start))
+ return found;
+ }
+ return 0;
+}
+
+static const char *skip_field(const char *end, const char *p)
+{
+ for (;;)
+ if (*p++ == '\n') {
+ if (p == end || *p == '%')
+ break;
+ for (const char *q = p; *q == ' ' || *q == '\t'; q++)
+ ;
+ if (*q == '\n')
+ break;
+ p = q + 1;
+ }
+ return p;
+}
+
+static const char *find_end(const char *bufend, const char *p)
+{
+ for (;;)
+ if (*p++ == '\n') {
+ if (p == bufend)
+ break;
+ for (const char *q = p; *q == ' ' || *q == '\t'; q++)
+ ;
+ if (*q == '\n')
+ break;
+ p = q + 1;
+ }
+ return p;
+}
+
+
+int linear_searcher::check_match(const char *buf, const char *bufend,
+ const char *match, int matchlen,
+ const char **cont, const char **start) const
+{
+ *cont = match + 1;
+ // The user is required to supply only the first truncate_len characters
+ // of the key. If truncate_len <= 0, he must supply all the key.
+ if ((truncate_len <= 0 || matchlen < truncate_len)
+ && map[uchar(match[matchlen])] != '\0')
+ return 0;
+
+ // The character before the match must not be an alphanumeric
+ // character (unless the alphanumeric character follows one or two
+ // percent characters at the beginning of the line), nor must it be
+ // a percent character at the beginning of a line, nor a percent
+ // character following a percent character at the beginning of a
+ // line.
+
+ switch (match - buf) {
+ case 0:
+ break;
+ case 1:
+ if (match[-1] == '%' || map[uchar(match[-1])] != '\0')
+ return 0;
+ break;
+ case 2:
+ if (map[uchar(match[-1])] != '\0' && match[-2] != '%')
+ return 0;
+ if (match[-1] == '%'
+ && (match[-2] == '\n' || match[-2] == '%'))
+ return 0;
+ break;
+ default:
+ if (map[uchar(match[-1])] != '\0'
+ && !(match[-2] == '%'
+ && (match[-3] == '\n'
+ || (match[-3] == '%' && match[-4] == '\n'))))
+ return 0;
+ if (match[-1] == '%'
+ && (match[-2] == '\n'
+ || (match[-2] == '%' && match[-3] == '\n')))
+ return 0;
+ }
+
+ const char *p = match;
+ int had_percent = 0;
+ for (;;) {
+ if (*p == '\n') {
+ if (!had_percent && p[1] == '%') {
+ if (p[2] != '\0' && strchr(ignore_fields, p[2]) != 0) {
+ *cont = skip_field(bufend, match + matchlen);
+ return 0;
+ }
+ if (!start)
+ break;
+ had_percent = 1;
+ }
+ if (p <= buf) {
+ if (start)
+ *start = p + 1;
+ return 1;
+ }
+ for (const char *q = p - 1; *q == ' ' || *q == '\t'; q--)
+ ;
+ if (*q == '\n') {
+ if (start)
+ *start = p + 1;
+ break;
+ }
+ p = q;
+ }
+ p--;
+ }
+ return 1;
+}
+
+file_buffer::file_buffer()
+: buffer(0), bufend(0)
+{
+}
+
+file_buffer::~file_buffer()
+{
+ a_delete buffer;
+}
+
+const char *file_buffer::get_start() const
+{
+ return buffer ? buffer + 4 : 0;
+}
+
+const char *file_buffer::get_end() const
+{
+ return bufend;
+}
+
+int file_buffer::load(int fd, const char *filename)
+{
+ struct stat sb;
+ if (fstat(fd, &sb) < 0)
+ error("can't fstat `%1': %2", filename, strerror(errno));
+ else if (!S_ISREG(sb.st_mode))
+ error("`%1' is not a regular file", filename);
+ else {
+ // We need one character extra at the beginning for an additional newline
+ // used as a sentinel. We get 4 instead so that the read buffer will be
+ // word-aligned. This seems to make the read slightly faster. We also
+ // need one character at the end also for an additional newline used as a
+ // sentinel.
+ int size = int(sb.st_size);
+ buffer = new char[size + 4 + 1];
+ int nread = read(fd, buffer + 4, size);
+ if (nread < 0)
+ error("error reading `%1': %2", filename, strerror(errno));
+ else if (nread != size)
+ error("size of `%1' decreased", filename);
+ else {
+ char c;
+ nread = read(fd, &c, 1);
+ if (nread != 0)
+ error("size of `%1' increased", filename);
+ else if (memchr(buffer + 4, '\0', size < 1024 ? size : 1024) != 0)
+ error("database `%1' is a binary file", filename);
+ else {
+ close(fd);
+ buffer[3] = '\n';
+ bufend = buffer + 4 + size;
+ if (bufend[-1] != '\n')
+ *bufend++ = '\n';
+ return 1;
+ }
+ }
+ a_delete buffer;
+ buffer = 0;
+ }
+ close(fd);
+ return 0;
+}
+
+linear_searcher::linear_searcher(const char *query, int query_len,
+ const char *ign, int trunc)
+: keys(0), nkeys(0), truncate_len(trunc), ignore_fields(ign)
+{
+ const char *query_end = query + query_len;
+ int nk = 0;
+ const char *p;
+ for (p = query; p < query_end; p++)
+ if (map[uchar(*p)] != '\0'
+ && (p[1] == '\0' || map[uchar(p[1])] == '\0'))
+ nk++;
+ if (nk == 0)
+ return;
+ keys = new bmpattern*[nk];
+ p = query;
+ for (;;) {
+ while (p < query_end && map[uchar(*p)] == '\0')
+ p++;
+ if (p == query_end)
+ break;
+ const char *start = p;
+ while (p < query_end && map[uchar(*p)] != '\0')
+ p++;
+ keys[nkeys++] = new bmpattern(start, p - start);
+ }
+ assert(nkeys <= nk);
+ if (nkeys == 0) {
+ a_delete keys;
+ keys = 0;
+ }
+}
+
+linear_searcher::~linear_searcher()
+{
+ for (int i = 0; i < nkeys; i++)
+ delete keys[i];
+ a_delete keys;
+}
+
+int linear_searcher::search(const char *buffer, const char *bufend,
+ const char **startp, int *lengthp) const
+{
+ assert(bufend - buffer > 0);
+ assert(buffer[-1] == '\n');
+ assert(bufend[-1] == '\n');
+ if (nkeys == 0)
+ return 0;
+ for (;;) {
+ const char *refstart;
+ const char *found = search_and_check(keys[0], buffer, bufend, &refstart);
+ if (!found)
+ break;
+ const char *refend = find_end(bufend, found + keys[0]->length());
+ for (int i = 1; i < nkeys; i++)
+ if (!search_and_check(keys[i], refstart, refend))
+ break;
+ if (i >= nkeys) {
+ *startp = refstart;
+ *lengthp = refend - refstart;
+ return 1;
+ }
+ buffer = refend;
+ }
+ return 0;
+}
+
+class linear_search_item : public search_item {
+ file_buffer fbuf;
+public:
+ linear_search_item(const char *filename, int fid);
+ ~linear_search_item();
+ int load(int fd);
+ search_item_iterator *make_search_item_iterator(const char *);
+ friend class linear_search_item_iterator;
+};
+
+class linear_search_item_iterator : public search_item_iterator {
+ linear_search_item *lsi;
+ int pos;
+public:
+ linear_search_item_iterator(linear_search_item *, const char *query);
+ ~linear_search_item_iterator();
+ int next(const linear_searcher &, const char **ptr, int *lenp,
+ reference_id *ridp);
+};
+
+search_item *make_linear_search_item(int fd, const char *filename, int fid)
+{
+ linear_search_item *item = new linear_search_item(filename, fid);
+ if (!item->load(fd)) {
+ delete item;
+ return 0;
+ }
+ else
+ return item;
+}
+
+linear_search_item::linear_search_item(const char *filename, int fid)
+: search_item(filename, fid)
+{
+}
+
+linear_search_item::~linear_search_item()
+{
+}
+
+int linear_search_item::load(int fd)
+{
+ return fbuf.load(fd, name);
+}
+
+search_item_iterator *linear_search_item::make_search_item_iterator(
+ const char *query)
+{
+ return new linear_search_item_iterator(this, query);
+}
+
+linear_search_item_iterator::linear_search_item_iterator(
+ linear_search_item *p, const char *)
+: lsi(p), pos(0)
+{
+}
+
+linear_search_item_iterator::~linear_search_item_iterator()
+{
+}
+
+int linear_search_item_iterator::next(const linear_searcher &searcher,
+ const char **startp, int *lengthp,
+ reference_id *ridp)
+{
+ const char *bufstart = lsi->fbuf.get_start();
+ const char *bufend = lsi->fbuf.get_end();
+ const char *ptr = bufstart + pos;
+ if (ptr < bufend && searcher.search(ptr, bufend, startp, lengthp)) {
+ pos = *startp + *lengthp - bufstart;
+ if (ridp)
+ *ridp = reference_id(lsi->filename_id, *startp - bufstart);
+ return 1;
+ }
+ else
+ return 0;
+}
diff --git a/gnu/usr.bin/groff/libbib/map.c b/gnu/usr.bin/groff/libbib/map.c
new file mode 100644
index 0000000..9d0f13f
--- /dev/null
+++ b/gnu/usr.bin/groff/libbib/map.c
@@ -0,0 +1,75 @@
+/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
+ Written by James Clark (jjc@jclark.com)
+
+This file is part of groff.
+
+groff is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
+
+groff is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License along
+with groff; see the file COPYING. If not, write to the Free Software
+Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#ifdef HAVE_MMAP
+
+#include <sys/types.h>
+#include <sys/mman.h>
+
+/* The Net-2 man pages says that a MAP_FILE flag is required. */
+#ifndef MAP_FILE
+#define MAP_FILE 0
+#endif
+
+char *mapread(fd, nbytes)
+ int fd;
+ int nbytes;
+{
+ char *p = (char *)mmap((caddr_t)0, (size_t)nbytes, PROT_READ,
+ MAP_FILE|MAP_PRIVATE, fd, (off_t)0);
+ if (p == (char *)-1)
+ return 0;
+ /* mmap() shouldn't return 0 since MAP_FIXED wasn't specified. */
+ if (p == 0)
+ abort();
+ return p;
+}
+
+int unmap(p, len)
+ char *p;
+ int len;
+{
+ return munmap((caddr_t)p, len);
+}
+
+#else /* not HAVE_MMAP */
+
+#include <errno.h>
+
+#ifndef errno
+extern int errno;
+#endif
+
+char *mapread(fd, nbytes)
+ int fd;
+ int nbytes;
+{
+ errno = ENODEV;
+ return 0;
+}
+
+int unmap(p, len)
+ char *p;
+ int len;
+{
+ errno = EINVAL;
+ return -1;
+}
+
+#endif /* not HAVE_MMAP */
diff --git a/gnu/usr.bin/groff/libbib/search.cc b/gnu/usr.bin/groff/libbib/search.cc
new file mode 100644
index 0000000..ffdd872
--- /dev/null
+++ b/gnu/usr.bin/groff/libbib/search.cc
@@ -0,0 +1,130 @@
+// -*- C++ -*-
+/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
+ Written by James Clark (jjc@jclark.com)
+
+This file is part of groff.
+
+groff is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
+
+groff is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License along
+with groff; see the file COPYING. If not, write to the Free Software
+Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <errno.h>
+
+#include "posix.h"
+#include "lib.h"
+#include "errarg.h"
+#include "error.h"
+
+#include "refid.h"
+#include "search.h"
+
+int linear_truncate_len = 6;
+const char *linear_ignore_fields = "XYZ";
+
+search_list::search_list()
+: list(0), niterators(0), next_fid(1)
+{
+}
+
+search_list::~search_list()
+{
+ assert(niterators == 0);
+ while (list) {
+ search_item *tem = list->next;
+ delete list;
+ list = tem;
+ }
+}
+
+void search_list::add_file(const char *filename, int silent)
+{
+ search_item *p = make_index_search_item(filename, next_fid);
+ if (!p) {
+ int fd = open(filename, O_RDONLY);
+ if (fd < 0) {
+ if (!silent)
+ error("can't open `%1': %2", filename, strerror(errno));
+ }
+ else
+ p = make_linear_search_item(fd, filename, next_fid);
+ }
+ if (p) {
+ for (search_item **pp = &list; *pp; pp = &(*pp)->next)
+ ;
+ *pp = p;
+ next_fid = p->next_filename_id();
+ }
+}
+
+int search_list::nfiles() const
+{
+ int n = 0;
+ for (search_item *ptr = list; ptr; ptr = ptr->next)
+ n++;
+ return n;
+}
+
+search_list_iterator::search_list_iterator(search_list *p, const char *q)
+: list(p), ptr(p->list), iter(0), query(strsave(q)),
+ searcher(q, strlen(q), linear_ignore_fields, linear_truncate_len)
+{
+ list->niterators += 1;
+}
+
+search_list_iterator::~search_list_iterator()
+{
+ list->niterators -= 1;
+ a_delete query;
+ delete iter;
+}
+
+int search_list_iterator::next(const char **pp, int *lenp, reference_id *ridp)
+{
+ while (ptr) {
+ if (iter == 0)
+ iter = ptr->make_search_item_iterator(query);
+ if (iter->next(searcher, pp, lenp, ridp))
+ return 1;
+ delete iter;
+ iter = 0;
+ ptr = ptr->next;
+ }
+ return 0;
+}
+
+search_item::search_item(const char *nm, int fid)
+: next(0), name(strsave(nm)), filename_id(fid)
+{
+}
+
+search_item::~search_item()
+{
+ a_delete name;
+}
+
+int search_item::is_named(const char *nm) const
+{
+ return strcmp(name, nm) == 0;
+}
+
+int search_item::next_filename_id() const
+{
+ return filename_id + 1;
+}
+
+search_item_iterator::~search_item_iterator()
+{
+}
diff --git a/gnu/usr.bin/groff/libdriver/Makefile b/gnu/usr.bin/groff/libdriver/Makefile
new file mode 100644
index 0000000..780a0e1
--- /dev/null
+++ b/gnu/usr.bin/groff/libdriver/Makefile
@@ -0,0 +1,13 @@
+# Makefile for libdriver
+
+LIB= driver
+SRCS= input.cc printer.cc
+CFLAGS+= -I$(.CURDIR)/../include
+
+NOMAN= noman
+NOPROFILE= noprofile
+
+install:
+
+.include "../Makefile.cfg"
+.include <bsd.lib.mk>
diff --git a/gnu/usr.bin/groff/libdriver/Makefile.dep b/gnu/usr.bin/groff/libdriver/Makefile.dep
new file mode 100644
index 0000000..0a67585
--- /dev/null
+++ b/gnu/usr.bin/groff/libdriver/Makefile.dep
@@ -0,0 +1,6 @@
+input.o : input.cc ../include/driver.h ../include/errarg.h \
+ ../include/error.h ../include/font.h ../include/printer.h \
+ ../include/lib.h ../include/device.h
+printer.o : printer.cc ../include/driver.h ../include/errarg.h \
+ ../include/error.h ../include/font.h ../include/printer.h \
+ ../include/lib.h
diff --git a/gnu/usr.bin/groff/libdriver/Makefile.sub b/gnu/usr.bin/groff/libdriver/Makefile.sub
new file mode 100644
index 0000000..1b3c09f
--- /dev/null
+++ b/gnu/usr.bin/groff/libdriver/Makefile.sub
@@ -0,0 +1,3 @@
+LIB=driver
+OBJS=input.o printer.o
+CCSRCS=input.cc printer.cc
diff --git a/gnu/usr.bin/groff/libdriver/input.cc b/gnu/usr.bin/groff/libdriver/input.cc
new file mode 100644
index 0000000..c44fdbe
--- /dev/null
+++ b/gnu/usr.bin/groff/libdriver/input.cc
@@ -0,0 +1,474 @@
+// -*- C++ -*-
+/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
+ Written by James Clark (jjc@jclark.com)
+
+This file is part of groff.
+
+groff is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
+
+groff is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License along
+with groff; see the file COPYING. If not, write to the Free Software
+Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "driver.h"
+#include "device.h"
+#include "cset.h"
+
+const char *current_filename;
+int current_lineno;
+const char *device = 0;
+FILE *current_file;
+
+int get_integer(); // don't read the newline
+int possibly_get_integer(int *);
+char *get_string(int is_long = 0);
+void skip_line();
+
+struct environment_list {
+ environment env;
+ environment_list *next;
+
+ environment_list(const environment &, environment_list *);
+};
+
+environment_list::environment_list(const environment &e, environment_list *p)
+: env(e), next(p)
+{
+}
+
+inline int get_char()
+{
+ return getc(current_file);
+}
+
+void do_file(const char *filename)
+{
+ int npages = 0;
+ if (filename[0] == '-' && filename[1] == '\0') {
+ current_filename = "<standard input>";
+ current_file = stdin;
+ }
+ else {
+ errno = 0;
+ current_file = fopen(filename, "r");
+ if (current_file == 0) {
+ error("can't open `%1'", filename);
+ return;
+ }
+ current_filename = filename;
+ }
+ environment env;
+ env.vpos = -1;
+ env.hpos = -1;
+ env.fontno = -1;
+ env.height = 0;
+ env.slant = 0;
+ environment_list *env_list = 0;
+ current_lineno = 1;
+ int command;
+ char *s;
+ command = get_char();
+ if (command == EOF)
+ return;
+ if (command != 'x')
+ fatal("the first command must be `x T'");
+ s = get_string();
+ if (s[0] != 'T')
+ fatal("the first command must be `x T'");
+ char *dev = get_string();
+ if (pr == 0) {
+ device = strsave(dev);
+ if (!font::load_desc())
+ fatal("sorry, I can't continue");
+ }
+ else {
+ if (device == 0 || strcmp(device, dev) != 0)
+ fatal("all files must use the same device");
+ }
+ skip_line();
+ env.size = 10*font::sizescale;
+ command = get_char();
+ if (command != 'x')
+ fatal("the second command must be `x res'");
+ s = get_string();
+ if (s[0] != 'r')
+ fatal("the second command must be `x res'");
+ int n = get_integer();
+ if (n != font::res)
+ fatal("resolution does not match");
+ n = get_integer();
+ if (n != font::hor)
+ fatal("horizontal resolution does not match");
+ n = get_integer();
+ if (n != font::vert)
+ fatal("vertical resolution does not match");
+ skip_line();
+ command = get_char();
+ if (command != 'x')
+ fatal("the third command must be `x init'");
+ s = get_string();
+ if (s[0] != 'i')
+ fatal("the third command must be `x init'");
+ skip_line();
+ if (pr == 0)
+ pr = make_printer();
+ while ((command = get_char()) != EOF) {
+ switch (command) {
+ case 's':
+ env.size = get_integer();
+ if (env.height == env.size)
+ env.height = 0;
+ break;
+ case 'f':
+ env.fontno = get_integer();
+ break;
+ case 'C':
+ {
+ if (npages == 0)
+ fatal("`C' command illegal before first `p' command");
+ char *s = get_string();
+ pr->set_special_char(s, &env);
+ }
+ break;
+ case 'N':
+ {
+ if (npages == 0)
+ fatal("`N' command illegal before first `p' command");
+ pr->set_numbered_char(get_integer(), &env);
+ }
+ break;
+ case 'H':
+ env.hpos = get_integer();
+ break;
+ case 'h':
+ env.hpos += get_integer();
+ break;
+ case 'V':
+ env.vpos = get_integer();
+ break;
+ case 'v':
+ env.vpos += get_integer();
+ break;
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ {
+ int c = get_char();
+ if (!csdigit(c))
+ fatal("digit expected");
+ env.hpos += (command - '0')*10 + (c - '0');
+ }
+ // fall through
+ case 'c':
+ {
+ if (npages == 0)
+ fatal("`c' command illegal before first `p' command");
+ int c = get_char();
+ if (c == EOF)
+ fatal("missing argument to `c' command");
+ pr->set_ascii_char(c, &env);
+ }
+ break;
+ case 'n':
+ if (npages == 0)
+ fatal("`n' command illegal before first `p' command");
+ pr->end_of_line();
+ (void)get_integer();
+ (void)get_integer();
+ break;
+ case 'w':
+ case ' ':
+ break;
+ case '\n':
+ current_lineno++;
+ break;
+ case 'p':
+ if (npages)
+ pr->end_page(env.vpos);
+ npages++;
+ pr->begin_page(get_integer());
+ env.vpos = 0;
+ break;
+ case '{':
+ env_list = new environment_list(env, env_list);
+ break;
+ case '}':
+ if (!env_list) {
+ fatal("can't pop");
+ }
+ else {
+ env = env_list->env;
+ environment_list *tem = env_list;
+ env_list = env_list->next;
+ delete tem;
+ }
+ break;
+ case 'u':
+ {
+ if (npages == 0)
+ fatal("`u' command illegal before first `p' command");
+ int kern = get_integer();
+ int c = get_char();
+ while (c == ' ')
+ c = get_char();
+ while (c != EOF) {
+ if (c == '\n') {
+ current_lineno++;
+ break;
+ }
+ int w;
+ pr->set_ascii_char(c, &env, &w);
+ env.hpos += w + kern;
+ c = get_char();
+ if (c == ' ')
+ break;
+ }
+ }
+ break;
+ case 't':
+ {
+ if (npages == 0)
+ fatal("`t' command illegal before first `p' command");
+ int c;
+ while ((c = get_char()) != EOF && c != ' ') {
+ if (c == '\n') {
+ current_lineno++;
+ break;
+ }
+ int w;
+ pr->set_ascii_char(c, &env, &w);
+ env.hpos += w;
+ }
+ }
+ break;
+ case '#':
+ skip_line();
+ break;
+ case 'D':
+ {
+ if (npages == 0)
+ fatal("`D' command illegal before first `p' command");
+ int c;
+ while ((c = get_char()) == ' ')
+ ;
+ int n;
+ int *p = 0;
+ int szp = 0;
+ for (int np = 0; possibly_get_integer(&n); np++) {
+ if (np >= szp) {
+ if (szp == 0) {
+ szp = 16;
+ p = new int[szp];
+ }
+ else {
+ int *oldp = p;
+ p = new int[szp*2];
+ memcpy(p, oldp, szp*sizeof(int));
+ szp *= 2;
+ a_delete oldp;
+ }
+ }
+ p[np] = n;
+ }
+ pr->draw(c, p, np, &env);
+ if (c == 'e') {
+ if (np > 0)
+ env.hpos += p[0];
+ }
+ else {
+ for (int i = 0; i < np/2; i++) {
+ env.hpos += p[i*2];
+ env.vpos += p[i*2 + 1];
+ }
+ // there might be an odd number of characters
+ if (i*2 < np)
+ env.hpos += p[i*2];
+ }
+ a_delete p;
+ skip_line();
+ }
+ break;
+ case 'x':
+ {
+ char *s = get_string();
+ int suppress_skip = 0;
+ switch (s[0]) {
+ case 'i':
+ error("duplicate `x init' command");
+ break;
+ case 'T':
+ error("duplicate `x T' command");
+ break;
+ case 'r':
+ error("duplicate `x res' command");
+ break;
+ case 'p':
+ break;
+ case 's':
+ break;
+ case 't':
+ break;
+ case 'f':
+ {
+ int n = get_integer();
+ char *name = get_string();
+ pr->load_font(n, name);
+ }
+ break;
+ case 'H':
+ env.height = get_integer();
+ if (env.height == env.size)
+ env.height = 0;
+ break;
+ case 'S':
+ env.slant = get_integer();
+ break;
+ case 'X':
+ if (npages == 0)
+ fatal("`x X' command illegal before first `p' command");
+ pr->special(get_string(1), &env);
+ suppress_skip = 1;
+ break;
+ default:
+ error("unrecognised x command `%1'", s);
+ }
+ if (!suppress_skip)
+ skip_line();
+ }
+ break;
+ default:
+ error("unrecognised command code %1", int(command));
+ skip_line();
+ break;
+ }
+ }
+ if (npages)
+ pr->end_page(env.vpos);
+}
+
+int get_integer()
+{
+ int c = get_char();
+ while (c == ' ')
+ c = get_char();
+ int neg = 0;
+ if (c == '-') {
+ neg = 1;
+ c = get_char();
+ }
+ if (!csdigit(c))
+ fatal("integer expected");
+ int total = 0;
+ do {
+ total = total*10;
+ if (neg)
+ total -= c - '0';
+ else
+ total += c - '0';
+ c = get_char();
+ } while (csdigit(c));
+ if (c != EOF)
+ ungetc(c, current_file);
+ return total;
+}
+
+int possibly_get_integer(int *res)
+{
+ int c = get_char();
+ while (c == ' ')
+ c = get_char();
+ int neg = 0;
+ if (c == '-') {
+ neg = 1;
+ c = get_char();
+ }
+ if (!csdigit(c)) {
+ if (c != EOF)
+ ungetc(c, current_file);
+ return 0;
+ }
+ int total = 0;
+ do {
+ total = total*10;
+ if (neg)
+ total -= c - '0';
+ else
+ total += c - '0';
+ c = get_char();
+ } while (csdigit(c));
+ if (c != EOF)
+ ungetc(c, current_file);
+ *res = total;
+ return 1;
+}
+
+
+char *get_string(int is_long)
+{
+ static char *buf;
+ static int buf_size;
+ int c = get_char();
+ while (c == ' ')
+ c = get_char();
+ for (int i = 0;; i++) {
+ if (i >= buf_size) {
+ if (buf_size == 0) {
+ buf_size = 16;
+ buf = new char[buf_size];
+ }
+ else {
+ char *old_buf = buf;
+ int old_size = buf_size;
+ buf_size *= 2;
+ buf = new char[buf_size];
+ memcpy(buf, old_buf, old_size);
+ a_delete old_buf;
+ }
+ }
+ if ((!is_long && (c == ' ' || c == '\n')) || c == EOF) {
+ buf[i] = '\0';
+ break;
+ }
+ if (is_long && c == '\n') {
+ current_lineno++;
+ c = get_char();
+ if (c == '+')
+ c = '\n';
+ else {
+ buf[i] = '\0';
+ break;
+ }
+ }
+ buf[i] = c;
+ c = get_char();
+ }
+ if (c != EOF)
+ ungetc(c, current_file);
+ return buf;
+}
+
+void skip_line()
+{
+ int c;
+ while ((c = get_char()) != EOF)
+ if (c == '\n') {
+ current_lineno++;
+ break;
+ }
+}
+
diff --git a/gnu/usr.bin/groff/libdriver/printer.cc b/gnu/usr.bin/groff/libdriver/printer.cc
new file mode 100644
index 0000000..f7e0b5f
--- /dev/null
+++ b/gnu/usr.bin/groff/libdriver/printer.cc
@@ -0,0 +1,240 @@
+// -*- C++ -*-
+/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
+ Written by James Clark (jjc@jclark.com)
+
+This file is part of groff.
+
+groff is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
+
+groff is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License along
+with groff; see the file COPYING. If not, write to the Free Software
+Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "driver.h"
+
+printer *pr = 0;
+
+font_pointer_list::font_pointer_list(font *f, font_pointer_list *fp)
+: p(f), next(fp)
+{
+}
+
+printer::printer()
+: font_table(0), nfonts(0), font_list(0)
+{
+}
+
+printer::~printer()
+{
+ a_delete font_table;
+ while (font_list) {
+ font_pointer_list *tem = font_list;
+ font_list = font_list->next;
+ delete tem->p;
+ delete tem;
+ }
+ if (ferror(stdout) || fflush(stdout) < 0)
+ fatal("output error");
+}
+
+void printer::load_font(int n, const char *nm)
+{
+ assert(n >= 0);
+ if (n >= nfonts) {
+ if (nfonts == 0) {
+ nfonts = 10;
+ if (nfonts <= n)
+ nfonts = n + 1;
+ font_table = new font *[nfonts];
+ for (int i = 0; i < nfonts; i++)
+ font_table[i] = 0;
+ }
+ else {
+ font **old_font_table = font_table;
+ int old_nfonts = nfonts;
+ nfonts *= 2;
+ if (n >= nfonts)
+ nfonts = n + 1;
+ font_table = new font *[nfonts];
+ for (int i = 0; i < old_nfonts; i++)
+ font_table[i] = old_font_table[i];
+ for (i = old_nfonts; i < nfonts; i++)
+ font_table[i] = 0;
+ a_delete old_font_table;
+ }
+ }
+ font *f = find_font(nm);
+ font_table[n] = f;
+}
+
+font *printer::find_font(const char *nm)
+{
+ for (font_pointer_list *p = font_list; p; p = p->next)
+ if (strcmp(p->p->get_name(), nm) == 0)
+ return p->p;
+ font *f = make_font(nm);
+ if (!f)
+ fatal("sorry, I can't continue");
+ font_list = new font_pointer_list(f, font_list);
+ return f;
+}
+
+font *printer::make_font(const char *nm)
+{
+ return font::load_font(nm);
+}
+
+void printer::end_of_line()
+{
+}
+
+void printer::special(char *, const environment *)
+{
+}
+
+void printer::draw(int, int *, int, const environment *)
+{
+}
+
+void printer::set_ascii_char(unsigned char c, const environment *env,
+ int *widthp)
+{
+ char buf[2];
+ buf[0] = c;
+ buf[1] = '\0';
+ set_special_char(buf, env, widthp);
+}
+
+void printer::set_special_char(const char *nm, const environment *env,
+ int *widthp)
+{
+ int i = font::name_to_index(nm);
+ int fn = env->fontno;
+ if (fn < 0 || fn >= nfonts) {
+ error("bad font position `%1'", fn);
+ return;
+ }
+ font *f = font_table[fn];
+ if (f == 0) {
+ error("no font mounted at `%1'", fn);
+ return;
+ }
+ if (!f->contains(i)) {
+ if (nm[0] != '\0' && nm[1] == '\0')
+ error("font `%1' does not contain ascii character `%2'",
+ f->get_name(),
+ nm[0]);
+ else
+ error("font `%1' does not contain special character `%2'",
+ f->get_name(),
+ nm);
+ return;
+ }
+ int w = f->get_width(i, env->size);
+ if (widthp)
+ *widthp = w;
+ set_char(i, f, env, w);
+}
+
+void printer::set_numbered_char(int num, const environment *env, int *widthp)
+{
+ int i = font::number_to_index(num);
+ int fn = env->fontno;
+ if (fn < 0 || fn >= nfonts) {
+ error("bad font position `%1'", fn);
+ return;
+ }
+ font *f = font_table[fn];
+ if (f == 0) {
+ error("no font mounted at `%1'", fn);
+ return;
+ }
+ if (!f->contains(i)) {
+ error("font `%1' does not contain numbered character %2",
+ f->get_name(),
+ num);
+ return;
+ }
+ int w = f->get_width(i, env->size);
+ if (widthp)
+ *widthp = w;
+ set_char(i, f, env, w);
+}
+
+// This utility function adjusts the specified center of the
+// arc so that it is equidistant between the specified start
+// and end points. (p[0], p[1]) is a vector from the current
+// point to the center; (p[2], p[3]) is a vector from the
+// center to the end point. If the center can be adjusted,
+// a vector from the current point to the adjusted center is
+// stored in c[0], c[1] and 1 is returned. Otherwise 0 is
+// returned.
+
+#if 1
+int printer::adjust_arc_center(const int *p, double *c)
+{
+ // We move the center along a line parallel to the line between
+ // the specified start point and end point so that the center
+ // is equidistant between the start and end point.
+ // It can be proved (using Lagrange multipliers) that this will
+ // give the point nearest to the specified center that is equidistant
+ // between the start and end point.
+
+ double x = p[0] + p[2]; // (x, y) is the end point
+ double y = p[1] + p[3];
+ double n = x*x + y*y;
+ if (n != 0) {
+ c[0]= double(p[0]);
+ c[1] = double(p[1]);
+ double k = .5 - (c[0]*x + c[1]*y)/n;
+ c[0] += k*x;
+ c[1] += k*y;
+ return 1;
+ }
+ else
+ return 0;
+}
+#else
+int printer::adjust_arc_center(const int *p, double *c)
+{
+ int x = p[0] + p[2]; // (x, y) is the end point
+ int y = p[1] + p[3];
+ // Start at the current point; go in the direction of the specified
+ // center point until we reach a point that is equidistant between
+ // the specified starting point and the specified end point. Place
+ // the center of the arc there.
+ double n = p[0]*double(x) + p[1]*double(y);
+ if (n > 0) {
+ double k = (double(x)*x + double(y)*y)/(2.0*n);
+ // (cx, cy) is our chosen center
+ c[0] = k*p[0];
+ c[1] = k*p[1];
+ return 1;
+ }
+ else {
+ // We would never reach such a point. So instead start at the
+ // specified end point of the arc. Go towards the specified
+ // center point until we reach a point that is equidistant between
+ // the specified start point and specified end point. Place
+ // the center of the arc there.
+ n = p[2]*double(x) + p[3]*double(y);
+ if (n > 0) {
+ double k = 1 - (double(x)*x + double(y)*y)/(2.0*n);
+ // (c[0], c[1]) is our chosen center
+ c[0] = p[0] + k*p[2];
+ c[1] = p[1] + k*p[3];
+ return 1;
+ }
+ else
+ return 0;
+ }
+}
+#endif
diff --git a/gnu/usr.bin/groff/libgroff/Makefile b/gnu/usr.bin/groff/libgroff/Makefile
new file mode 100644
index 0000000..7463a60
--- /dev/null
+++ b/gnu/usr.bin/groff/libgroff/Makefile
@@ -0,0 +1,23 @@
+# Makefile for libgroff
+
+LIB= groff
+SRCS= assert.cc change_lf.cc cmap.cc cset.cc device.cc errarg.cc\
+ error.cc fatal.cc filename.cc font.cc fontfile.cc lf.cc\
+ lineno.cc macropath.cc nametoindex.cc new.cc prime.cc\
+ progname.cc ptable.cc searchpath.cc string.cc strsave.cc\
+ tmpfile.cc illegal.cc version.cc
+SRCS+= iftoa.c itoa.c matherr.c
+CFLAGS+= -I$(.CURDIR)/../include
+
+NOMAN= noman
+NOPROFILE= noprofile
+
+CLEANFILES+= version.cc
+version.cc: $(.CURDIR)/../VERSION
+ @${ECHO} Making version.cc
+ @echo const char \*version_string = \"`cat $(.CURDIR)/../VERSION`\"\; >$@
+
+install:
+
+.include "../Makefile.cfg"
+.include <bsd.lib.mk>
diff --git a/gnu/usr.bin/groff/libgroff/Makefile.dep b/gnu/usr.bin/groff/libgroff/Makefile.dep
new file mode 100644
index 0000000..f135af7d
--- /dev/null
+++ b/gnu/usr.bin/groff/libgroff/Makefile.dep
@@ -0,0 +1,39 @@
+assert.o : assert.cc ../include/assert.h
+change_lf.o : change_lf.cc
+cmap.o : cmap.cc ../include/cmap.h
+cset.o : cset.cc ../include/cset.h
+device.o : device.cc ../include/device.h ../include/defs.h
+errarg.o : errarg.cc ../include/assert.h ../include/errarg.h
+error.o : error.cc ../include/errarg.h ../include/error.h
+fatal.o : fatal.cc
+filename.o : filename.cc
+font.o : font.cc ../include/errarg.h ../include/error.h ../include/cset.h \
+ ../include/font.h ../include/lib.h
+fontfile.o : fontfile.cc ../include/font.h ../include/lib.h \
+ ../include/searchpath.h ../include/device.h ../include/defs.h
+lf.o : lf.cc ../include/cset.h ../include/stringclass.h
+lineno.o : lineno.cc
+macropath.o : macropath.cc ../include/lib.h ../include/searchpath.h \
+ ../include/macropath.h ../include/defs.h
+nametoindex.o : nametoindex.cc ../include/lib.h ../include/errarg.h \
+ ../include/error.h ../include/font.h ../include/ptable.h
+new.o : new.cc ../include/posix.h
+prime.o : prime.cc
+progname.o : progname.cc
+ptable.o : ptable.cc ../include/ptable.h ../include/errarg.h \
+ ../include/error.h
+searchpath.o : searchpath.cc ../include/lib.h ../include/searchpath.h
+string.o : string.cc ../include/stringclass.h ../include/lib.h
+strsave.o : strsave.cc
+tmpfile.o : tmpfile.cc ../include/posix.h ../include/lib.h \
+ ../include/errarg.h ../include/error.h
+version.o : version.cc
+illegal.o : illegal.cc ../include/lib.h
+fmod.o : fmod.c
+getcwd.o : getcwd.c
+iftoa.o : iftoa.c
+itoa.o : itoa.c
+matherr.o : matherr.c
+strerror.o : strerror.c
+strtol.o : strtol.c
+putenv.o : putenv.c
diff --git a/gnu/usr.bin/groff/libgroff/Makefile.sub b/gnu/usr.bin/groff/libgroff/Makefile.sub
new file mode 100644
index 0000000..a3126bf
--- /dev/null
+++ b/gnu/usr.bin/groff/libgroff/Makefile.sub
@@ -0,0 +1,15 @@
+LIB=groff
+OBJS=assert.o change_lf.o cmap.o cset.o device.o errarg.o error.o fatal.o \
+ filename.o font.o fontfile.o lf.o lineno.o macropath.o nametoindex.o new.o \
+ prime.o progname.o ptable.o searchpath.o string.o strsave.o tmpfile.o \
+ iftoa.o itoa.o matherr.o version.o illegal.o $(LIBOBJS)
+CCSRCS=assert.cc change_lf.cc cmap.cc cset.cc device.cc errarg.cc error.cc \
+ fatal.cc filename.cc font.cc fontfile.cc lf.cc lineno.cc macropath.cc \
+ nametoindex.cc new.cc prime.cc progname.cc ptable.cc searchpath.cc \
+ string.cc strsave.cc tmpfile.cc version.cc illegal.cc
+CSRCS=fmod.c getcwd.c iftoa.c itoa.c matherr.c strerror.c strtol.c putenv.c
+GENSRCS=version.cc
+
+version.cc: $(srcdir)/../VERSION
+ @echo Making version.cc
+ @echo const char \*version_string = \"`cat $(srcdir)/../VERSION`\"\; >$@
diff --git a/gnu/usr.bin/groff/libgroff/assert.cc b/gnu/usr.bin/groff/libgroff/assert.cc
new file mode 100644
index 0000000..ed39dba
--- /dev/null
+++ b/gnu/usr.bin/groff/libgroff/assert.cc
@@ -0,0 +1,34 @@
+/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
+ Written by James Clark (jjc@jclark.com)
+
+This file is part of groff.
+
+groff is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
+
+groff is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License along
+with groff; see the file COPYING. If not, write to the Free Software
+Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "assert.h"
+
+extern const char *program_name;
+
+void assertion_failed(int lineno, const char *filename)
+{
+ if (program_name != 0)
+ fprintf(stderr, "%s: ", program_name);
+ fprintf(stderr, "Failed assertion at line %d, file `%s'.\n",
+ lineno, filename);
+ fflush(stderr);
+ abort();
+}
diff --git a/gnu/usr.bin/groff/libgroff/change_lf.cc b/gnu/usr.bin/groff/libgroff/change_lf.cc
new file mode 100644
index 0000000..cc0fb92
--- /dev/null
+++ b/gnu/usr.bin/groff/libgroff/change_lf.cc
@@ -0,0 +1,37 @@
+/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
+ Written by James Clark (jjc@jclark.com)
+
+This file is part of groff.
+
+groff is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
+
+groff is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License along
+with groff; see the file COPYING. If not, write to the Free Software
+Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <string.h>
+
+extern char *strsave(const char *);
+
+extern const char *current_filename;
+extern int current_lineno;
+
+void change_filename(const char *f)
+{
+ if (current_filename != 0 && strcmp(current_filename, f) == 0)
+ return;
+ current_filename = strsave(f);
+}
+
+void change_lineno(int ln)
+{
+ current_lineno = ln;
+}
diff --git a/gnu/usr.bin/groff/libgroff/cmap.cc b/gnu/usr.bin/groff/libgroff/cmap.cc
new file mode 100644
index 0000000..7c35253
--- /dev/null
+++ b/gnu/usr.bin/groff/libgroff/cmap.cc
@@ -0,0 +1,62 @@
+// -*- C++ -*-
+/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
+ Written by James Clark (jjc@jclark.com)
+
+This file is part of groff.
+
+groff is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
+
+groff is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License along
+with groff; see the file COPYING. If not, write to the Free Software
+Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <ctype.h>
+#ifdef __FreeBSD__
+#include <locale.h>
+#endif
+#include "cmap.h"
+
+cmap cmlower(CMAP_BUILTIN);
+cmap cmupper(CMAP_BUILTIN);
+
+#if defined(isascii) && !defined(__FreeBSD__)
+#define ISASCII(c) isascii(c)
+#else
+#define ISASCII(c) (1)
+#endif
+
+cmap::cmap()
+{
+ unsigned char *p = v;
+ for (int i = 0; i <= UCHAR_MAX; i++)
+ p[i] = i;
+}
+
+cmap::cmap(cmap_builtin)
+{
+ // these are initialised by cmap_init::cmap_init()
+}
+
+int cmap_init::initialised = 0;
+
+cmap_init::cmap_init()
+{
+ if (initialised)
+ return;
+ initialised = 1;
+#ifdef __FreeBSD__
+ (void) setlocale(LC_CTYPE, "");
+#endif
+ for (int i = 0; i <= UCHAR_MAX; i++) {
+ cmupper.v[i] = ISASCII(i) && islower(i) ? toupper(i) : i;
+ cmlower.v[i] = ISASCII(i) && isupper(i) ? tolower(i) : i;
+ }
+}
diff --git a/gnu/usr.bin/groff/libgroff/cset.cc b/gnu/usr.bin/groff/libgroff/cset.cc
new file mode 100644
index 0000000..c720d1b
--- /dev/null
+++ b/gnu/usr.bin/groff/libgroff/cset.cc
@@ -0,0 +1,108 @@
+// -*- C++ -*-
+/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
+ Written by James Clark (jjc@jclark.com)
+
+This file is part of groff.
+
+groff is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
+
+groff is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License along
+with groff; see the file COPYING. If not, write to the Free Software
+Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <ctype.h>
+#ifdef __FreeBSD__
+#include <locale.h>
+#endif
+#include "cset.h"
+
+cset csalpha(CSET_BUILTIN);
+cset csupper(CSET_BUILTIN);
+cset cslower(CSET_BUILTIN);
+cset csdigit(CSET_BUILTIN);
+cset csxdigit(CSET_BUILTIN);
+cset csspace(CSET_BUILTIN);
+cset cspunct(CSET_BUILTIN);
+cset csalnum(CSET_BUILTIN);
+cset csprint(CSET_BUILTIN);
+cset csgraph(CSET_BUILTIN);
+cset cscntrl(CSET_BUILTIN);
+
+#if defined(isascii) && !defined(__FreeBSD__)
+#define ISASCII(c) isascii(c)
+#else
+#define ISASCII(c) (1)
+#endif
+
+void cset::clear()
+{
+ char *p = v;
+ for (int i = 0; i <= UCHAR_MAX; i++)
+ p[i] = 0;
+}
+
+cset::cset()
+{
+ clear();
+}
+
+cset::cset(const char *s)
+{
+ clear();
+ while (*s)
+ v[(unsigned char)*s++] = 1;
+}
+
+cset::cset(const unsigned char *s)
+{
+ clear();
+ while (*s)
+ v[*s++] = 1;
+}
+
+cset::cset(cset_builtin)
+{
+ // these are initialised by cset_init::cset_init()
+}
+
+cset &cset::operator|=(const cset &cs)
+{
+ for (int i = 0; i <= UCHAR_MAX; i++)
+ if (cs.v[i])
+ v[i] = 1;
+ return *this;
+}
+
+
+int cset_init::initialised = 0;
+
+cset_init::cset_init()
+{
+ if (initialised)
+ return;
+ initialised = 1;
+#ifdef __FreeBSD__
+ (void) setlocale(LC_CTYPE, "");
+#endif
+ for (int i = 0; i <= UCHAR_MAX; i++) {
+ csalpha.v[i] = ISASCII(i) && isalpha(i);
+ csupper.v[i] = ISASCII(i) && isupper(i);
+ cslower.v[i] = ISASCII(i) && islower(i);
+ csdigit.v[i] = ISASCII(i) && isdigit(i);
+ csxdigit.v[i] = ISASCII(i) && isxdigit(i);
+ csspace.v[i] = ISASCII(i) && isspace(i);
+ cspunct.v[i] = ISASCII(i) && ispunct(i);
+ csalnum.v[i] = ISASCII(i) && isalnum(i);
+ csprint.v[i] = ISASCII(i) && isprint(i);
+ csgraph.v[i] = ISASCII(i) && isgraph(i);
+ cscntrl.v[i] = ISASCII(i) && iscntrl(i);
+ }
+}
diff --git a/gnu/usr.bin/groff/libgroff/device.cc b/gnu/usr.bin/groff/libgroff/device.cc
new file mode 100644
index 0000000..b86ef1e
--- /dev/null
+++ b/gnu/usr.bin/groff/libgroff/device.cc
@@ -0,0 +1,36 @@
+// -*- C++ -*-
+/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
+ Written by James Clark (jjc@jclark.com)
+
+This file is part of groff.
+
+groff is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
+
+groff is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License along
+with groff; see the file COPYING. If not, write to the Free Software
+Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <stdlib.h>
+#include "device.h"
+#include "defs.h"
+
+const char *device = DEVICE;
+
+struct device_init {
+ device_init();
+} _device_init;
+
+device_init::device_init()
+{
+ char *tem = getenv("GROFF_TYPESETTER");
+ if (tem)
+ device = tem;
+}
diff --git a/gnu/usr.bin/groff/libgroff/errarg.cc b/gnu/usr.bin/groff/libgroff/errarg.cc
new file mode 100644
index 0000000..995d55d
--- /dev/null
+++ b/gnu/usr.bin/groff/libgroff/errarg.cc
@@ -0,0 +1,118 @@
+// -*- C++ -*-
+/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
+ Written by James Clark (jjc@jclark.com)
+
+This file is part of groff.
+
+groff is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
+
+groff is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License along
+with groff; see the file COPYING. If not, write to the Free Software
+Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <stdio.h>
+#include "assert.h"
+#include "errarg.h"
+
+errarg::errarg(const char *p) : type(STRING)
+{
+ s = p ? p : "(null)";
+}
+
+errarg::errarg() : type(EMPTY)
+{
+}
+
+errarg::errarg(unsigned char cc) : type(CHAR)
+{
+ c = cc;
+}
+
+errarg::errarg(int nn) : type(INTEGER)
+{
+ n = nn;
+}
+
+errarg::errarg(char cc) : type(CHAR)
+{
+ c = cc;
+}
+
+errarg::errarg(double dd) : type(DOUBLE)
+{
+ d = dd;
+}
+
+int errarg::empty() const
+{
+ return type == EMPTY;
+}
+
+extern "C" {
+ const char *itoa(int);
+}
+
+void errarg::print() const
+{
+ switch (type) {
+ case INTEGER:
+ fputs(itoa(n), stderr);
+ break;
+ case CHAR:
+ putc(c, stderr);
+ break;
+ case STRING:
+ fputs(s, stderr);
+ break;
+ case DOUBLE:
+ fprintf(stderr, "%g", d);
+ break;
+ case EMPTY:
+ break;
+ }
+}
+
+errarg empty_errarg;
+
+void errprint(const char *format,
+ const errarg &arg1,
+ const errarg &arg2,
+ const errarg &arg3)
+{
+ assert(format != 0);
+ char c;
+ while ((c = *format++) != '\0') {
+ if (c == '%') {
+ c = *format++;
+ switch(c) {
+ case '%':
+ fputc('%', stderr);
+ break;
+ case '1':
+ assert(!arg1.empty());
+ arg1.print();
+ break;
+ case '2':
+ assert(!arg2.empty());
+ arg2.print();
+ break;
+ case '3':
+ assert(!arg3.empty());
+ arg3.print();
+ break;
+ default:
+ assert(0);
+ }
+ }
+ else
+ putc(c, stderr);
+ }
+}
diff --git a/gnu/usr.bin/groff/libgroff/error.cc b/gnu/usr.bin/groff/libgroff/error.cc
new file mode 100644
index 0000000..f0c6998
--- /dev/null
+++ b/gnu/usr.bin/groff/libgroff/error.cc
@@ -0,0 +1,137 @@
+// -*- C++ -*-
+/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
+ Written by James Clark (jjc@jclark.com)
+
+This file is part of groff.
+
+groff is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
+
+groff is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License along
+with groff; see the file COPYING. If not, write to the Free Software
+Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "errarg.h"
+#include "error.h"
+
+extern void fatal_error_exit();
+
+enum error_type { WARNING, ERROR, FATAL };
+
+static void do_error_with_file_and_line(const char *filename, int lineno,
+ error_type type,
+ const char *format,
+ const errarg &arg1,
+ const errarg &arg2,
+ const errarg &arg3)
+{
+ int need_space = 0;
+ if (program_name) {
+ fprintf(stderr, "%s:", program_name);
+ need_space = 1;
+ }
+ if (lineno >= 0 && filename != 0) {
+ if (strcmp(filename, "-") == 0)
+ filename = "<standard input>";
+ fprintf(stderr, "%s:%d:", filename, lineno);
+ need_space = 1;
+ }
+ switch (type) {
+ case FATAL:
+ fputs("fatal error:", stderr);
+ need_space = 1;
+ break;
+ case ERROR:
+ break;
+ case WARNING:
+ fputs("warning:", stderr);
+ need_space = 1;
+ break;
+ }
+ if (need_space)
+ fputc(' ', stderr);
+ errprint(format, arg1, arg2, arg3);
+ fputc('\n', stderr);
+ fflush(stderr);
+ if (type == FATAL)
+ fatal_error_exit();
+}
+
+
+static void do_error(error_type type,
+ const char *format,
+ const errarg &arg1,
+ const errarg &arg2,
+ const errarg &arg3)
+{
+ do_error_with_file_and_line(current_filename, current_lineno,
+ type, format, arg1, arg2, arg3);
+}
+
+
+void error(const char *format,
+ const errarg &arg1,
+ const errarg &arg2,
+ const errarg &arg3)
+{
+ do_error(ERROR, format, arg1, arg2, arg3);
+}
+
+void warning(const char *format,
+ const errarg &arg1,
+ const errarg &arg2,
+ const errarg &arg3)
+{
+ do_error(WARNING, format, arg1, arg2, arg3);
+}
+
+void fatal(const char *format,
+ const errarg &arg1,
+ const errarg &arg2,
+ const errarg &arg3)
+{
+ do_error(FATAL, format, arg1, arg2, arg3);
+}
+
+void error_with_file_and_line(const char *filename,
+ int lineno,
+ const char *format,
+ const errarg &arg1,
+ const errarg &arg2,
+ const errarg &arg3)
+{
+ do_error_with_file_and_line(filename, lineno,
+ ERROR, format, arg1, arg2, arg3);
+}
+
+void warning_with_file_and_line(const char *filename,
+ int lineno,
+ const char *format,
+ const errarg &arg1,
+ const errarg &arg2,
+ const errarg &arg3)
+{
+ do_error_with_file_and_line(filename, lineno,
+ WARNING, format, arg1, arg2, arg3);
+}
+
+void fatal_with_file_and_line(const char *filename,
+ int lineno,
+ const char *format,
+ const errarg &arg1,
+ const errarg &arg2,
+ const errarg &arg3)
+{
+ do_error_with_file_and_line(filename, lineno,
+ FATAL, format, arg1, arg2, arg3);
+}
diff --git a/gnu/usr.bin/groff/libgroff/fatal.cc b/gnu/usr.bin/groff/libgroff/fatal.cc
new file mode 100644
index 0000000..2087a84
--- /dev/null
+++ b/gnu/usr.bin/groff/libgroff/fatal.cc
@@ -0,0 +1,27 @@
+/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
+ Written by James Clark (jjc@jclark.com)
+
+This file is part of groff.
+
+groff is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
+
+groff is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License along
+with groff; see the file COPYING. If not, write to the Free Software
+Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <stdlib.h>
+
+#define FATAL_ERROR_EXIT_CODE 3
+
+void fatal_error_exit()
+{
+ exit(FATAL_ERROR_EXIT_CODE);
+}
diff --git a/gnu/usr.bin/groff/libgroff/filename.cc b/gnu/usr.bin/groff/libgroff/filename.cc
new file mode 100644
index 0000000..1cbaa93
--- /dev/null
+++ b/gnu/usr.bin/groff/libgroff/filename.cc
@@ -0,0 +1 @@
+const char *current_filename = 0;
diff --git a/gnu/usr.bin/groff/libgroff/fmod.c b/gnu/usr.bin/groff/libgroff/fmod.c
new file mode 100644
index 0000000..74c5c36
--- /dev/null
+++ b/gnu/usr.bin/groff/libgroff/fmod.c
@@ -0,0 +1,28 @@
+/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
+ Written by James Clark (jjc@jclark.com)
+
+This file is part of groff.
+
+groff is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
+
+groff is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License along
+with groff; see the file COPYING. If not, write to the Free Software
+Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <math.h>
+
+double fmod(x, y)
+ double x, y;
+{
+ double quot = x/y;
+ return x - (quot < 0.0 ? ceil(quot) : floor(quot)) * y;
+}
+
diff --git a/gnu/usr.bin/groff/libgroff/font.cc b/gnu/usr.bin/groff/libgroff/font.cc
new file mode 100644
index 0000000..6e05a8a
--- /dev/null
+++ b/gnu/usr.bin/groff/libgroff/font.cc
@@ -0,0 +1,911 @@
+// -*- C++ -*-
+/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
+ Written by James Clark (jjc@jclark.com)
+
+This file is part of groff.
+
+groff is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
+
+groff is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License along
+with groff; see the file COPYING. If not, write to the Free Software
+Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <assert.h>
+#include <math.h>
+#include <stdlib.h>
+#include "errarg.h"
+#include "error.h"
+#include "cset.h"
+#include "font.h"
+#include "lib.h"
+
+const char *const WS = " \t\n\r";
+
+struct font_char_metric {
+ char type;
+ int code;
+ int width;
+ int height;
+ int depth;
+ int pre_math_space;
+ int italic_correction;
+ int subscript_correction;
+};
+
+struct font_kern_list {
+ int i1;
+ int i2;
+ int amount;
+ font_kern_list *next;
+
+ font_kern_list(int, int, int, font_kern_list * = 0);
+};
+
+struct font_widths_cache {
+ font_widths_cache *next;
+ int point_size;
+ int *width;
+
+ font_widths_cache(int, int, font_widths_cache *);
+ ~font_widths_cache();
+};
+
+/* text_file */
+
+struct text_file {
+ FILE *fp;
+ char *path;
+ int lineno;
+ int size;
+ int skip_comments;
+ char *buf;
+ text_file(FILE *fp, char *p);
+ ~text_file();
+ int next();
+ void error(const char *format,
+ const errarg &arg1 = empty_errarg,
+ const errarg &arg2 = empty_errarg,
+ const errarg &arg3 = empty_errarg);
+};
+
+text_file::text_file(FILE *p, char *s)
+: lineno(0), buf(0), size(0), skip_comments(1), fp(p), path(s)
+{
+}
+
+text_file::~text_file()
+{
+ a_delete buf;
+ a_delete path;
+ if (fp)
+ fclose(fp);
+}
+
+
+int text_file::next()
+{
+ if (fp == 0)
+ return 0;
+ if (buf == 0) {
+ buf = new char [128];
+ size = 128;
+ }
+ for (;;) {
+ int i = 0;
+ for (;;) {
+ int c = getc(fp);
+ if (c == EOF)
+ break;
+ if (illegal_input_char(c))
+ error("illegal input character code `%1'", int(c));
+ else {
+ if (i + 1 >= size) {
+ char *old_buf = buf;
+ buf = new char[size*2];
+ memcpy(buf, old_buf, size);
+ a_delete old_buf;
+ size *= 2;
+ }
+ buf[i++] = c;
+ if (c == '\n')
+ break;
+ }
+ }
+ if (i == 0)
+ break;
+ buf[i] = '\0';
+ lineno++;
+ char *ptr = buf;
+ while (csspace(*ptr))
+ ptr++;
+ if (*ptr != 0 && (!skip_comments || *ptr != '#'))
+ return 1;
+ }
+ return 0;
+}
+
+void text_file::error(const char *format,
+ const errarg &arg1,
+ const errarg &arg2,
+ const errarg &arg3)
+{
+ error_with_file_and_line(path, lineno, format, arg1, arg2, arg3);
+}
+
+
+/* font functions */
+
+font::font(const char *s)
+: special(0), ligatures(0), kern_hash_table(0), space_width(0),
+ ch(0), ch_used(0), ch_size(0), ch_index(0), nindices(0), widths_cache(0)
+{
+ name = new char[strlen(s) + 1];
+ strcpy(name, s);
+ internalname = 0;
+ slant = 0.0;
+ // load(); // for testing
+}
+
+font::~font()
+{
+ a_delete ch;
+ a_delete ch_index;
+ if (kern_hash_table) {
+ for (int i = 0; i < KERN_HASH_TABLE_SIZE; i++) {
+ font_kern_list *kerns = kern_hash_table[i];
+ while (kerns) {
+ font_kern_list *tem = kerns;
+ kerns = kerns->next;
+ delete tem;
+ }
+ }
+ a_delete kern_hash_table;
+ }
+ a_delete name;
+ a_delete internalname;
+ while (widths_cache) {
+ font_widths_cache *tem = widths_cache;
+ widths_cache = widths_cache->next;
+ delete tem;
+ }
+}
+
+static int scale_round(int n, int x, int y)
+{
+ assert(x >= 0 && y > 0);
+ int y2 = y/2;
+ if (x == 0)
+ return 0;
+ if (n >= 0) {
+ if (n <= (INT_MAX - y2)/x)
+ return (n*x + y2)/y;
+ return int(n*double(x)/double(y) + .5);
+ }
+ else {
+ if (-(unsigned)n <= (-(unsigned)INT_MIN - y2)/x)
+ {
+ // XXX simplify expression to work around bug in gcc-2.6.0
+ int tmp = n*x - y2;
+ return tmp/y;
+ }
+ return int(n*double(x)/double(y) - .5);
+ }
+}
+
+inline int font::scale(int w, int sz)
+{
+ return sz == unitwidth ? w : scale_round(w, sz, unitwidth);
+}
+
+int font::get_skew(int c, int point_size, int sl)
+{
+ int h = get_height(c, point_size);
+ return int(h*tan((slant+sl)*PI/180.0) + .5);
+}
+
+int font::contains(int c)
+{
+ return c >= 0 && c < nindices && ch_index[c] >= 0;
+}
+
+int font::is_special()
+{
+ return special;
+}
+
+font_widths_cache::font_widths_cache(int ps, int ch_size,
+ font_widths_cache *p = 0)
+: next(p), point_size(ps)
+{
+ width = new int[ch_size];
+ for (int i = 0; i < ch_size; i++)
+ width[i] = -1;
+}
+
+font_widths_cache::~font_widths_cache()
+{
+ a_delete width;
+}
+
+int font::get_width(int c, int point_size)
+{
+ assert(c >= 0 && c < nindices);
+ int i = ch_index[c];
+ assert(i >= 0);
+
+ if (point_size == unitwidth)
+ return ch[i].width;
+
+ if (!widths_cache)
+ widths_cache = new font_widths_cache(point_size, ch_size);
+ else if (widths_cache->point_size != point_size) {
+ for (font_widths_cache **p = &widths_cache; *p; p = &(*p)->next)
+ if ((*p)->point_size == point_size)
+ break;
+ if (*p) {
+ font_widths_cache *tem = *p;
+ *p = (*p)->next;
+ tem->next = widths_cache;
+ widths_cache = tem;
+ }
+ else
+ widths_cache = new font_widths_cache(point_size, ch_size, widths_cache);
+ }
+ int &w = widths_cache->width[i];
+ if (w < 0)
+ w = scale(ch[i].width, point_size);
+ return w;
+}
+
+int font::get_height(int c, int point_size)
+{
+ assert(c >= 0 && c < nindices && ch_index[c] >= 0);
+ return scale(ch[ch_index[c]].height, point_size);
+}
+
+int font::get_depth(int c, int point_size)
+{
+ assert(c >= 0 && c < nindices && ch_index[c] >= 0);
+ return scale(ch[ch_index[c]].depth, point_size);
+}
+
+int font::get_italic_correction(int c, int point_size)
+{
+ assert(c >= 0 && c < nindices && ch_index[c] >= 0);
+ return scale(ch[ch_index[c]].italic_correction, point_size);
+}
+
+int font::get_left_italic_correction(int c, int point_size)
+{
+ assert(c >= 0 && c < nindices && ch_index[c] >= 0);
+ return scale(ch[ch_index[c]].pre_math_space, point_size);
+}
+
+int font::get_subscript_correction(int c, int point_size)
+{
+ assert(c >= 0 && c < nindices && ch_index[c] >= 0);
+ return scale(ch[ch_index[c]].subscript_correction, point_size);
+}
+
+int font::get_space_width(int point_size)
+{
+ return scale(space_width, point_size);
+}
+
+font_kern_list::font_kern_list(int c1, int c2, int n, font_kern_list *p)
+ : i1(c1), i2(c2), amount(n), next(p)
+{
+}
+
+inline int font::hash_kern(int i1, int i2)
+{
+ int n = ((i1 << 10) + i2) % KERN_HASH_TABLE_SIZE;
+ return n < 0 ? -n : n;
+}
+
+void font::add_kern(int i1, int i2, int amount)
+{
+ if (!kern_hash_table) {
+ kern_hash_table = new font_kern_list *[KERN_HASH_TABLE_SIZE];
+ for (int i = 0; i < KERN_HASH_TABLE_SIZE; i++)
+ kern_hash_table[i] = 0;
+ }
+ font_kern_list **p = kern_hash_table + hash_kern(i1, i2);
+ *p = new font_kern_list(i1, i2, amount, *p);
+}
+
+int font::get_kern(int i1, int i2, int point_size)
+{
+ if (kern_hash_table) {
+ for (font_kern_list *p = kern_hash_table[hash_kern(i1, i2)]; p; p = p->next)
+ if (i1 == p->i1 && i2 == p->i2)
+ return scale(p->amount, point_size);
+ }
+ return 0;
+}
+
+int font::has_ligature(int mask)
+{
+ return mask & ligatures;
+}
+
+int font::get_character_type(int c)
+{
+ assert(c >= 0 && c < nindices && ch_index[c] >= 0);
+ return ch[ch_index[c]].type;
+}
+
+int font::get_code(int c)
+{
+ assert(c >= 0 && c < nindices && ch_index[c] >= 0);
+ return ch[ch_index[c]].code;
+}
+
+const char *font::get_name()
+{
+ return name;
+}
+
+const char *font::get_internal_name()
+{
+ return internalname;
+}
+
+void font::alloc_ch_index(int index)
+{
+ if (nindices == 0) {
+ nindices = 128;
+ if (index >= nindices)
+ nindices = index + 10;
+ ch_index = new short[nindices];
+ for (int i = 0; i < nindices; i++)
+ ch_index[i] = -1;
+ }
+ else {
+ int old_nindices = nindices;
+ nindices *= 2;
+ if (index >= nindices)
+ nindices = index + 10;
+ short *old_ch_index = ch_index;
+ ch_index = new short[nindices];
+ memcpy(ch_index, old_ch_index, sizeof(short)*old_nindices);
+ for (int i = old_nindices; i < nindices; i++)
+ ch_index[i] = -1;
+ a_delete old_ch_index;
+ }
+}
+
+void font::extend_ch()
+{
+ if (ch == 0)
+ ch = new font_char_metric[ch_size = 16];
+ else {
+ int old_ch_size = ch_size;
+ ch_size *= 2;
+ font_char_metric *old_ch = ch;
+ ch = new font_char_metric[ch_size];
+ memcpy(ch, old_ch, old_ch_size*sizeof(font_char_metric));
+ a_delete old_ch;
+ }
+}
+
+void font::compact()
+{
+ for (int i = nindices - 1; i >= 0; i--)
+ if (ch_index[i] >= 0)
+ break;
+ i++;
+ if (i < nindices) {
+ short *old_ch_index = ch_index;
+ ch_index = new short[i];
+ memcpy(ch_index, old_ch_index, i*sizeof(short));
+ a_delete old_ch_index;
+ nindices = i;
+ }
+ if (ch_used < ch_size) {
+ font_char_metric *old_ch = ch;
+ ch = new font_char_metric[ch_used];
+ memcpy(ch, old_ch, ch_used*sizeof(font_char_metric));
+ a_delete old_ch;
+ ch_size = ch_used;
+ }
+}
+
+void font::add_entry(int index, const font_char_metric &metric)
+{
+ assert(index >= 0);
+ if (index >= nindices)
+ alloc_ch_index(index);
+ assert(index < nindices);
+ if (ch_used + 1 >= ch_size)
+ extend_ch();
+ assert(ch_used + 1 < ch_size);
+ ch_index[index] = ch_used;
+ ch[ch_used++] = metric;
+}
+
+void font::copy_entry(int new_index, int old_index)
+{
+ assert(new_index >= 0 && old_index >= 0 && old_index < nindices);
+ if (new_index >= nindices)
+ alloc_ch_index(new_index);
+ ch_index[new_index] = ch_index[old_index];
+}
+
+font *font::load_font(const char *s, int *not_found)
+{
+ font *f = new font(s);
+ if (!f->load(not_found)) {
+ delete f;
+ return 0;
+ }
+ return f;
+}
+
+static char *trim_arg(char *p)
+{
+ if (!p)
+ return 0;
+ while (csspace(*p))
+ p++;
+ char *q = strchr(p, '\0');
+ while (q > p && csspace(q[-1]))
+ q--;
+ *q = '\0';
+ return p;
+}
+
+// If the font can't be found, then if not_found is NULL it will be set
+// to 1 otherwise a message will be printed.
+
+int font::load(int *not_found)
+{
+ char *path;
+ FILE *fp;
+ if ((fp = open_file(name, &path)) == NULL) {
+ if (not_found)
+ *not_found = 1;
+ else
+ error("can't find font file `%1'", name);
+ return 0;
+ }
+ text_file t(fp, path);
+ t.skip_comments = 1;
+ char *p;
+ for (;;) {
+ if (!t.next()) {
+ t.error("missing charset command");
+ return 0;
+ }
+ p = strtok(t.buf, WS);
+ if (strcmp(p, "name") == 0) {
+ }
+ else if (strcmp(p, "spacewidth") == 0) {
+ p = strtok(0, WS);
+ int n;
+ if (p == 0 || sscanf(p, "%d", &n) != 1 || n <= 0) {
+ t.error("bad argument for spacewidth command");
+ return 0;
+ }
+ space_width = n;
+ }
+ else if (strcmp(p, "slant") == 0) {
+ p = strtok(0, WS);
+ double n;
+ if (p == 0 || sscanf(p, "%lf", &n) != 1 || n >= 90.0 || n <= -90.0) {
+ t.error("bad argument for slant command", p);
+ return 0;
+ }
+ slant = n;
+ }
+ else if (strcmp(p, "ligatures") == 0) {
+ for (;;) {
+ p = strtok(0, WS);
+ if (p == 0 || strcmp(p, "0") == 0)
+ break;
+ if (strcmp(p, "ff") == 0)
+ ligatures |= LIG_ff;
+ else if (strcmp(p, "fi") == 0)
+ ligatures |= LIG_fi;
+ else if (strcmp(p, "fl") == 0)
+ ligatures |= LIG_fl;
+ else if (strcmp(p, "ffi") == 0)
+ ligatures |= LIG_ffi;
+ else if (strcmp(p, "ffl") == 0)
+ ligatures |= LIG_ffl;
+ else {
+ t.error("unrecognised ligature `%1'", p);
+ return 0;
+ }
+ }
+ }
+ else if (strcmp(p, "internalname") == 0) {
+ p = strtok(0, WS);
+ if (!p) {
+ t.error("`internalname command requires argument");
+ return 0;
+ }
+ internalname = new char[strlen(p) + 1];
+ strcpy(internalname, p);
+ }
+ else if (strcmp(p, "special") == 0) {
+ special = 1;
+ }
+ else if (strcmp(p, "kernpairs") != 0 && strcmp(p, "charset") != 0) {
+ char *command = p;
+ p = strtok(0, "\n");
+ handle_unknown_font_command(command, trim_arg(p), t.path, t.lineno);
+ }
+ else
+ break;
+ }
+ char *command = p;
+ int had_charset = 0;
+ t.skip_comments = 0;
+ while (command) {
+ if (strcmp(command, "kernpairs") == 0) {
+ for (;;) {
+ if (!t.next()) {
+ command = 0;
+ break;
+ }
+ char *c1 = strtok(t.buf, WS);
+ if (c1 == 0)
+ continue;
+ char *c2 = strtok(0, WS);
+ if (c2 == 0) {
+ command = c1;
+ break;
+ }
+ p = strtok(0, WS);
+ if (p == 0) {
+ t.error("missing kern amount");
+ return 0;
+ }
+ int n;
+ if (sscanf(p, "%d", &n) != 1) {
+ t.error("bad kern amount `%1'", p);
+ return 0;
+ }
+ int i1 = name_to_index(c1);
+ if (i1 < 0) {
+ t.error("illegal character `%1'", c1);
+ return 0;
+ }
+ int i2 = name_to_index(c2);
+ if (i2 < 0) {
+ t.error("illegal character `%1'", c2);
+ return 0;
+ }
+ add_kern(i1, i2, n);
+ }
+ }
+ else if (strcmp(command, "charset") == 0) {
+ had_charset = 1;
+ int last_index = -1;
+ for (;;) {
+ if (!t.next()) {
+ command = 0;
+ break;
+ }
+ char *nm = strtok(t.buf, WS);
+ if (nm == 0)
+ continue; // I dont think this should happen
+ p = strtok(0, WS);
+ if (p == 0) {
+ command = nm;
+ break;
+ }
+ if (p[0] == '"') {
+ if (last_index == -1) {
+ t.error("first charset entry is duplicate");
+ return 0;
+ }
+ if (strcmp(nm, "---") == 0) {
+ t.error("unnamed character cannot be duplicate");
+ return 0;
+ }
+ int index = name_to_index(nm);
+ if (index < 0) {
+ t.error("illegal character `%1'", nm);
+ return 0;
+ }
+ copy_entry(index, last_index);
+ }
+ else {
+ font_char_metric metric;
+ metric.height = 0;
+ metric.depth = 0;
+ metric.pre_math_space = 0;
+ metric.italic_correction = 0;
+ metric.subscript_correction = 0;
+ int nparms = sscanf(p, "%d,%d,%d,%d,%d,%d",
+ &metric.width, &metric.height, &metric.depth,
+ &metric.italic_correction,
+ &metric.pre_math_space,
+ &metric.subscript_correction);
+ if (nparms < 1) {
+ t.error("bad width for `%1'", nm);
+ return 0;
+ }
+ p = strtok(0, WS);
+ if (p == 0) {
+ t.error("missing character type for `%1'", nm);
+ return 0;
+ }
+ int type;
+ if (sscanf(p, "%d", &type) != 1) {
+ t.error("bad character type for `%1'", nm);
+ return 0;
+ }
+ if (type < 0 || type > 255) {
+ t.error("character code `%1' out of range", type);
+ return 0;
+ }
+ metric.type = type;
+ p = strtok(0, WS);
+ if (p == 0) {
+ t.error("missing code for `%1'", nm);
+ return 0;
+ }
+ char *ptr;
+ metric.code = (int)strtol(p, &ptr, 0);
+ if (metric.code == 0 && ptr == p) {
+ t.error("bad code `%1' for character `%2'", p, nm);
+ return 0;
+ }
+ if (strcmp(nm, "---") == 0) {
+ last_index = number_to_index(metric.code);
+ add_entry(last_index, metric);
+ }
+ else {
+ last_index = name_to_index(nm);
+ if (last_index < 0) {
+ t.error("illegal character `%1'", nm);
+ return 0;
+ }
+ add_entry(last_index, metric);
+ copy_entry(number_to_index(metric.code), last_index);
+ }
+ }
+ }
+ if (last_index == -1) {
+ t.error("I didn't seem to find any characters");
+ return 0;
+ }
+ }
+ else {
+ t.error("unrecognised command `%1' after `kernpairs' or `charset' command", command);
+ return 0;
+ }
+ }
+ if (!had_charset) {
+ t.error("missing charset command");
+ return 0;
+ }
+ if (space_width == 0)
+ space_width = scale_round(unitwidth, res, 72*3*sizescale);
+ compact();
+ return 1;
+}
+
+static struct {
+ const char *command;
+ int *ptr;
+} table[] = {
+ { "res", &font::res },
+ { "hor", &font::hor },
+ { "vert", &font::vert },
+ { "unitwidth", &font::unitwidth },
+ { "paperwidth", &font::paperwidth },
+ { "paperlength", &font::paperlength },
+ { "spare1", &font::biggestfont },
+ { "biggestfont", &font::biggestfont },
+ { "spare2", &font::spare2 },
+ { "sizescale", &font::sizescale }
+ };
+
+
+int font::load_desc()
+{
+ int nfonts = 0;
+ FILE *fp;
+ char *path;
+ if ((fp = open_file("DESC", &path)) == 0) {
+ error("can't find `DESC' file");
+ return 0;
+ }
+ text_file t(fp, path);
+ t.skip_comments = 1;
+ res = 0;
+ while (t.next()) {
+ char *p = strtok(t.buf, WS);
+ int found = 0;
+ for (int i = 0; !found && i < sizeof(table)/sizeof(table[0]); i++)
+ if (strcmp(table[i].command, p) == 0)
+ found = 1;
+ if (found) {
+ char *q = strtok(0, WS);
+ if (!q) {
+ t.error("missing value for command `%1'", p);
+ return 0;
+ }
+ //int *ptr = &(this->*(table[i-1].ptr));
+ int *ptr = table[i-1].ptr;
+ if (sscanf(q, "%d", ptr) != 1) {
+ t.error("bad number `%1'", q);
+ return 0;
+ }
+ }
+ else if (strcmp("tcommand", p) == 0) {
+ tcommand = 1;
+ }
+ else if (strcmp("family", p) == 0) {
+ p = strtok(0, WS);
+ if (!p) {
+ t.error("family command requires an argument");
+ return 0;
+ }
+ char *tem = new char[strlen(p)+1];
+ strcpy(tem, p);
+ family = tem;
+ }
+ else if (strcmp("fonts", p) == 0) {
+ p = strtok(0, WS);
+ if (!p || sscanf(p, "%d", &nfonts) != 1 || nfonts <= 0) {
+ t.error("bad number of fonts `%1'", p);
+ return 0;
+ }
+ font_name_table = (const char **)new char *[nfonts+1];
+ for (int i = 0; i < nfonts; i++) {
+ p = strtok(0, WS);
+ while (p == 0) {
+ if (!t.next()) {
+ t.error("end of file while reading list of fonts");
+ return 0;
+ }
+ p = strtok(t.buf, WS);
+ }
+ char *temp = new char[strlen(p)+1];
+ strcpy(temp, p);
+ font_name_table[i] = temp;
+ }
+ p = strtok(0, WS);
+ if (p != 0) {
+ t.error("font count does not match number of fonts");
+ return 0;
+ }
+ font_name_table[nfonts] = 0;
+ }
+ else if (strcmp("sizes", p) == 0) {
+ int n = 16;
+ sizes = new int[n];
+ int i = 0;
+ for (;;) {
+ p = strtok(0, WS);
+ while (p == 0) {
+ if (!t.next()) {
+ t.error("list of sizes must be terminated by `0'");
+ return 0;
+ }
+ p = strtok(t.buf, WS);
+ }
+ int lower, upper;
+ switch (sscanf(p, "%d-%d", &lower, &upper)) {
+ case 1:
+ upper = lower;
+ // fall through
+ case 2:
+ if (lower <= upper && lower >= 0)
+ break;
+ // fall through
+ default:
+ t.error("bad size range `%1'", p);
+ return 0;
+ }
+ if (i + 2 > n) {
+ int *old_sizes = sizes;
+ sizes = new int[n*2];
+ memcpy(sizes, old_sizes, n*sizeof(int));
+ n *= 2;
+ a_delete old_sizes;
+ }
+ sizes[i++] = lower;
+ if (lower == 0)
+ break;
+ sizes[i++] = upper;
+ }
+ if (i == 1) {
+ t.error("must have some sizes");
+ return 0;
+ }
+ }
+ else if (strcmp("styles", p) == 0) {
+ int style_table_size = 5;
+ style_table = (const char **)new char *[style_table_size];
+ for (int j = 0; j < style_table_size; j++)
+ style_table[j] = 0;
+ int i = 0;
+ for (;;) {
+ p = strtok(0, WS);
+ if (p == 0)
+ break;
+ // leave room for terminating 0
+ if (i + 1 >= style_table_size) {
+ const char **old_style_table = style_table;
+ style_table_size *= 2;
+ style_table = (const char **)new char*[style_table_size];
+ for (j = 0; j < i; j++)
+ style_table[j] = old_style_table[j];
+ for (; j < style_table_size; j++)
+ style_table[j] = 0;
+ a_delete old_style_table;
+ }
+ char *tem = new char[strlen(p) + 1];
+ strcpy(tem, p);
+ style_table[i++] = tem;
+ }
+ }
+ else if (strcmp("charset", p) == 0)
+ break;
+ else if (unknown_desc_command_handler) {
+ char *command = p;
+ p = strtok(0, "\n");
+ (*unknown_desc_command_handler)(command, trim_arg(p), t.path, t.lineno);
+ }
+ }
+ if (res == 0) {
+ t.error("missing `res' command");
+ return 0;
+ }
+ if (unitwidth == 0) {
+ t.error("missing `unitwidth' command");
+ return 0;
+ }
+ if (font_name_table == 0) {
+ t.error("missing `fonts' command");
+ return 0;
+ }
+ if (sizes == 0) {
+ t.error("missing `sizes' command");
+ return 0;
+ }
+ if (sizescale < 1) {
+ t.error("bad `sizescale' value");
+ return 0;
+ }
+ if (hor < 1) {
+ t.error("bad `hor' value");
+ return 0;
+ }
+ if (vert < 1) {
+ t.error("bad `vert' value");
+ return 0;
+ }
+ return 1;
+}
+
+void font::handle_unknown_font_command(const char *, const char *,
+ const char *, int)
+{
+}
+
+FONT_COMMAND_HANDLER
+font::set_unknown_desc_command_handler(FONT_COMMAND_HANDLER func)
+{
+ FONT_COMMAND_HANDLER prev = unknown_desc_command_handler;
+ unknown_desc_command_handler = func;
+ return prev;
+}
+
diff --git a/gnu/usr.bin/groff/libgroff/fontfile.cc b/gnu/usr.bin/groff/libgroff/fontfile.cc
new file mode 100644
index 0000000..5353958
--- /dev/null
+++ b/gnu/usr.bin/groff/libgroff/fontfile.cc
@@ -0,0 +1,64 @@
+// -*- C++ -*-
+/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
+ Written by James Clark (jjc@jclark.com)
+
+This file is part of groff.
+
+groff is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
+
+groff is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License along
+with groff; see the file COPYING. If not, write to the Free Software
+Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+#include <stdlib.h>
+#include <errno.h>
+#include "font.h"
+#include "lib.h"
+#include "searchpath.h"
+#include "device.h"
+#include "defs.h"
+
+const char *const FONT_ENV_VAR = "GROFF_FONT_PATH";
+
+static search_path font_path(FONT_ENV_VAR, FONTPATH);
+
+int font::res = 0;
+int font::hor = 1;
+int font::vert = 1;
+int font::unitwidth = 0;
+int font::paperwidth = 0;
+int font::paperlength = 0;
+int font::biggestfont = 0;
+int font::spare2 = 0;
+int font::sizescale = 1;
+int font::tcommand = 0;
+const char **font::font_name_table = 0;
+int *font::sizes = 0;
+const char *font::family = 0;
+const char **font::style_table = 0;
+FONT_COMMAND_HANDLER font::unknown_desc_command_handler = 0;
+
+void font::command_line_font_dir(const char *dir)
+{
+ font_path.command_line_dir(dir);
+}
+
+FILE *font::open_file(const char *name, char **pathp)
+{
+ char *filename = new char[strlen(name) + strlen(device) + 5];
+ sprintf(filename, "dev%s/%s", device, name);
+ FILE *fp = font_path.open_file(filename, pathp);
+ a_delete filename;
+ return fp;
+}
diff --git a/gnu/usr.bin/groff/libgroff/getcwd.c b/gnu/usr.bin/groff/libgroff/getcwd.c
new file mode 100644
index 0000000..208e811
--- /dev/null
+++ b/gnu/usr.bin/groff/libgroff/getcwd.c
@@ -0,0 +1,38 @@
+/* Partial emulation of getcwd in terms of getwd. */
+
+#include <sys/param.h>
+#include <string.h>
+#include <errno.h>
+#ifndef errno
+extern int errno;
+#endif
+
+char *getwd();
+
+char *getcwd(buf, size)
+ char *buf;
+ int size; /* POSIX says this should be size_t */
+{
+ if (size <= 0) {
+ errno = EINVAL;
+ return 0;
+ }
+ else {
+ char mybuf[MAXPATHLEN];
+ int saved_errno = errno;
+
+ errno = 0;
+ if (!getwd(mybuf)) {
+ if (errno == 0)
+ ; /* what to do? */
+ return 0;
+ }
+ errno = saved_errno;
+ if (strlen(mybuf) + 1 > size) {
+ errno = ERANGE;
+ return 0;
+ }
+ strcpy(buf, mybuf);
+ return buf;
+ }
+}
diff --git a/gnu/usr.bin/groff/libgroff/iftoa.c b/gnu/usr.bin/groff/libgroff/iftoa.c
new file mode 100644
index 0000000..2b16ab2
--- /dev/null
+++ b/gnu/usr.bin/groff/libgroff/iftoa.c
@@ -0,0 +1,65 @@
+/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
+ Written by James Clark (jjc@jclark.com)
+
+This file is part of groff.
+
+groff is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
+
+groff is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License along
+with groff; see the file COPYING. If not, write to the Free Software
+Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#define INT_DIGITS 19 /* enough for 64-bit integer */
+
+char *iftoa(i, decimal_point)
+ int i, decimal_point;
+{
+ /* room for a -, INT_DIGITS digits, a decimal point, and a terminating '\0' */
+ static char buf[INT_DIGITS + 3];
+ char *p = buf + INT_DIGITS + 2;
+ int point = 0;
+ buf[INT_DIGITS + 2] = '\0';
+ /* assert(decimal_point <= INT_DIGITS); */
+ if (i >= 0) {
+ do {
+ *--p = '0' + (i % 10);
+ i /= 10;
+ if (++point == decimal_point)
+ *--p = '.';
+ } while (i != 0 || point < decimal_point);
+ }
+ else { /* i < 0 */
+ do {
+ *--p = '0' - (i % 10);
+ i /= 10;
+ if (++point == decimal_point)
+ *--p = '.';
+ } while (i != 0 || point < decimal_point);
+ *--p = '-';
+ }
+ if (decimal_point > 0) {
+ char *q;
+ /* there must be a dot, so this will terminate */
+ for (q = buf + INT_DIGITS + 2; q[-1] == '0'; --q)
+ ;
+ if (q[-1] == '.') {
+ if (q - 1 == p) {
+ q[-1] = '0';
+ q[0] = '\0';
+ }
+ else
+ q[-1] = '\0';
+ }
+ else
+ *q = '\0';
+ }
+ return p;
+}
diff --git a/gnu/usr.bin/groff/libgroff/illegal.cc b/gnu/usr.bin/groff/libgroff/illegal.cc
new file mode 100644
index 0000000..10f4d5b
--- /dev/null
+++ b/gnu/usr.bin/groff/libgroff/illegal.cc
@@ -0,0 +1,22 @@
+#include "lib.h"
+
+// Table of illegal input characters.
+
+char illegal_char_table[256]= {
+ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 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,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+};
diff --git a/gnu/usr.bin/groff/libgroff/itoa.c b/gnu/usr.bin/groff/libgroff/itoa.c
new file mode 100644
index 0000000..e10d9dc
--- /dev/null
+++ b/gnu/usr.bin/groff/libgroff/itoa.c
@@ -0,0 +1,43 @@
+/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
+ Written by James Clark (jjc@jclark.com)
+
+This file is part of groff.
+
+groff is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
+
+groff is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License along
+with groff; see the file COPYING. If not, write to the Free Software
+Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#define INT_DIGITS 19 /* enough for 64 bit integer */
+
+char *itoa(i)
+ int i;
+{
+ /* Room for INT_DIGITS digits, - and '\0' */
+ static char buf[INT_DIGITS + 2];
+ char *p = buf + INT_DIGITS + 1; /* points to terminating '\0' */
+ if (i >= 0) {
+ do {
+ *--p = '0' + (i % 10);
+ i /= 10;
+ } while (i != 0);
+ return p;
+ }
+ else { /* i < 0 */
+ do {
+ *--p = '0' - (i % 10);
+ i /= 10;
+ } while (i != 0);
+ *--p = '-';
+ }
+ return p;
+}
diff --git a/gnu/usr.bin/groff/libgroff/lf.cc b/gnu/usr.bin/groff/libgroff/lf.cc
new file mode 100644
index 0000000..9f1a848
--- /dev/null
+++ b/gnu/usr.bin/groff/libgroff/lf.cc
@@ -0,0 +1,61 @@
+// -*- C++ -*-
+/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
+ Written by James Clark (jjc@jclark.com)
+
+This file is part of groff.
+
+groff is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
+
+groff is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License along
+with groff; see the file COPYING. If not, write to the Free Software
+Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <string.h>
+#include <ctype.h>
+#include "cset.h"
+#include "stringclass.h"
+
+extern void change_filename(const char *);
+extern void change_lineno(int);
+
+int interpret_lf_args(const char *p)
+{
+ while (*p == ' ')
+ p++;
+ if (!csdigit(*p))
+ return 0;
+ int ln = 0;
+ do {
+ ln *= 10;
+ ln += *p++ - '0';
+ } while (csdigit(*p));
+ if (*p != ' ' && *p != '\n' && *p != '\0')
+ return 0;
+ while (*p == ' ')
+ p++;
+ if (*p == '\0' || *p == '\n') {
+ change_lineno(ln);
+ return 1;
+ }
+ for (const char *q = p;
+ *q != '\0' && *q != ' ' && *q != '\n' && *q != '\\';
+ q++)
+ ;
+ string tem(p, q - p);
+ while (*q == ' ')
+ q++;
+ if (*q != '\n' && *q != '\0')
+ return 0;
+ tem += '\0';
+ change_filename(tem.contents());
+ change_lineno(ln);
+ return 1;
+}
diff --git a/gnu/usr.bin/groff/libgroff/lineno.cc b/gnu/usr.bin/groff/libgroff/lineno.cc
new file mode 100644
index 0000000..f7138db
--- /dev/null
+++ b/gnu/usr.bin/groff/libgroff/lineno.cc
@@ -0,0 +1 @@
+int current_lineno = 0;
diff --git a/gnu/usr.bin/groff/libgroff/macropath.cc b/gnu/usr.bin/groff/libgroff/macropath.cc
new file mode 100644
index 0000000..d6e6774
--- /dev/null
+++ b/gnu/usr.bin/groff/libgroff/macropath.cc
@@ -0,0 +1,28 @@
+// -*- C++ -*-
+/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
+ Written by James Clark (jjc@jclark.com)
+
+This file is part of groff.
+
+groff is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
+
+groff is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License along
+with groff; see the file COPYING. If not, write to the Free Software
+Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "lib.h"
+#include "searchpath.h"
+#include "macropath.h"
+#include "defs.h"
+
+#define MACROPATH_ENVVAR "GROFF_TMAC_PATH"
+
+search_path macro_path(MACROPATH_ENVVAR, MACROPATH);
diff --git a/gnu/usr.bin/groff/libgroff/matherr.c b/gnu/usr.bin/groff/libgroff/matherr.c
new file mode 100644
index 0000000..1f334f4
--- /dev/null
+++ b/gnu/usr.bin/groff/libgroff/matherr.c
@@ -0,0 +1,45 @@
+/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
+ Written by James Clark (jjc@jclark.com)
+
+This file is part of groff.
+
+groff is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
+
+groff is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License along
+with groff; see the file COPYING. If not, write to the Free Software
+Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <math.h>
+#include <errno.h>
+
+#ifdef HAVE_STRUCT_EXCEPTION
+#ifdef TLOSS
+
+int matherr(exc)
+struct exception *exc;
+{
+ switch (exc->type) {
+ case SING:
+ case DOMAIN:
+ errno = EDOM;
+ break;
+ case OVERFLOW:
+ case UNDERFLOW:
+ case TLOSS:
+ case PLOSS:
+ errno = ERANGE;
+ break;
+ }
+ return 1;
+}
+
+#endif /* TLOSS */
+#endif /* HAVE_STRUCT_EXCEPTION */
diff --git a/gnu/usr.bin/groff/libgroff/nametoindex.cc b/gnu/usr.bin/groff/libgroff/nametoindex.cc
new file mode 100644
index 0000000..827e15a
--- /dev/null
+++ b/gnu/usr.bin/groff/libgroff/nametoindex.cc
@@ -0,0 +1,117 @@
+// -*- C++ -*-
+/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
+ Written by James Clark (jjc@jclark.com)
+
+This file is part of groff.
+
+groff is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
+
+groff is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License along
+with groff; see the file COPYING. If not, write to the Free Software
+Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <assert.h>
+#include <stdlib.h>
+#include "lib.h"
+#include "errarg.h"
+#include "error.h"
+#include "font.h"
+#include "ptable.h"
+
+declare_ptable(int)
+implement_ptable(int)
+
+class character_indexer {
+public:
+ character_indexer();
+ ~character_indexer();
+ int ascii_char_index(unsigned char);
+ int named_char_index(const char *);
+ int numbered_char_index(int);
+private:
+ enum { NSMALL = 256 };
+ int next_index;
+ int ascii_index[256];
+ int small_number_index[NSMALL];
+ PTABLE(int) table;
+ int lookup_char(const char *, int);
+};
+
+character_indexer::character_indexer()
+: next_index(0)
+{
+ for (int i = 0; i < 256; i++)
+ ascii_index[i] = -1;
+ for (i = 0; i < NSMALL; i++)
+ small_number_index[i] = -1;
+}
+
+character_indexer::~character_indexer()
+{
+}
+
+int character_indexer::ascii_char_index(unsigned char c)
+{
+ if (ascii_index[c] < 0)
+ ascii_index[c] = next_index++;
+ return ascii_index[c];
+}
+
+int character_indexer::numbered_char_index(int n)
+{
+ if (n >= 0 && n < NSMALL) {
+ if (small_number_index[n] < 0)
+ small_number_index[n] = next_index++;
+ return small_number_index[n];
+ }
+ // Not the most efficient possible implementation.
+ char buf[INT_DIGITS + 3];
+ buf[0] = ' ';
+ strcpy(buf + 1, itoa(n));
+ return named_char_index(buf);
+}
+
+int character_indexer::named_char_index(const char *s)
+{
+ int *np = table.lookup(s);
+ if (!np) {
+ np = new int;
+ *np = next_index++;
+ table.define(s, np);
+ }
+ return *np;
+}
+
+static character_indexer indexer;
+
+int font::number_to_index(int n)
+{
+ return indexer.numbered_char_index(n);
+}
+
+int font::name_to_index(const char *s)
+{
+ assert(s != 0 && s[0] != '\0' && s[0] != ' ');
+ if (s[1] == '\0')
+ return indexer.ascii_char_index(s[0]);
+ /* char128 and \200 are synonyms */
+ if (s[0] == 'c' && s[1] == 'h' && s[2] == 'a' && s[3] == 'r') {
+ char *res;
+ long n = strtol(s + 4, &res, 10);
+ if (res != s + 4 && *res == '\0' && n >= 0 && n < 256)
+ return indexer.ascii_char_index((unsigned char)n);
+ }
+ return indexer.named_char_index(s);
+}
+
diff --git a/gnu/usr.bin/groff/libgroff/new.cc b/gnu/usr.bin/groff/libgroff/new.cc
new file mode 100644
index 0000000..21b533e
--- /dev/null
+++ b/gnu/usr.bin/groff/libgroff/new.cc
@@ -0,0 +1,67 @@
+/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
+ Written by James Clark (jjc@jclark.com)
+
+This file is part of groff.
+
+groff is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
+
+groff is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License along
+with groff; see the file COPYING. If not, write to the Free Software
+Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "posix.h"
+
+extern const char *program_name;
+
+static void ewrite(const char *s)
+{
+ write(2, s, strlen(s));
+}
+
+void *operator new(size_t size)
+{
+ // Avoid relying on the behaviour of malloc(0).
+ if (size == 0)
+ size++;
+#ifdef COOKIE_BUG
+ char *p = (char *)malloc(unsigned(size + 8));
+#else /* not COOKIE_BUG */
+ char *p = (char *)malloc(unsigned(size));
+#endif /* not COOKIE_BUG */
+ if (p == 0) {
+ if (program_name) {
+ ewrite(program_name);
+ ewrite(": ");
+ }
+ ewrite("out of memory\n");
+ _exit(-1);
+ }
+#ifdef COOKIE_BUG
+ ((unsigned *)p)[1] = 0;
+ return p + 8;
+#else /* not COOKIE_BUG */
+ return p;
+#endif /* not COOKIE_BUG */
+}
+
+#ifdef COOKIE_BUG
+
+void operator delete(void *p)
+{
+ if (p)
+ free((void *)((char *)p - 8));
+}
+
+#endif /* COOKIE_BUG */
diff --git a/gnu/usr.bin/groff/libgroff/prime.cc b/gnu/usr.bin/groff/libgroff/prime.cc
new file mode 100644
index 0000000..f0b1ead
--- /dev/null
+++ b/gnu/usr.bin/groff/libgroff/prime.cc
@@ -0,0 +1,26 @@
+#include <math.h>
+
+int is_prime(unsigned n)
+{
+ if (n <= 3)
+ return 1;
+ if (!(n & 1))
+ return 0;
+ if (n % 3 == 0)
+ return 0;
+ unsigned lim = unsigned(sqrt((double)n));
+ unsigned d = 5;
+ for (;;) {
+ if (d > lim)
+ break;
+ if (n % d == 0)
+ return 0;
+ d += 2;
+ if (d > lim)
+ break;
+ if (n % d == 0)
+ return 0;
+ d += 4;
+ }
+ return 1;
+}
diff --git a/gnu/usr.bin/groff/libgroff/progname.cc b/gnu/usr.bin/groff/libgroff/progname.cc
new file mode 100644
index 0000000..a70e341
--- /dev/null
+++ b/gnu/usr.bin/groff/libgroff/progname.cc
@@ -0,0 +1 @@
+const char *program_name = 0;
diff --git a/gnu/usr.bin/groff/libgroff/ptable.cc b/gnu/usr.bin/groff/libgroff/ptable.cc
new file mode 100644
index 0000000..a6086de
--- /dev/null
+++ b/gnu/usr.bin/groff/libgroff/ptable.cc
@@ -0,0 +1,51 @@
+/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
+ Written by James Clark (jjc@jclark.com)
+
+This file is part of groff.
+
+groff is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
+
+groff is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License along
+with groff; see the file COPYING. If not, write to the Free Software
+Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "ptable.h"
+#include "errarg.h"
+#include "error.h"
+
+unsigned long hash_string(const char *s)
+{
+ assert(s != 0);
+ unsigned long h = 0, g;
+ while (*s != 0) {
+ h <<= 4;
+ h += *s++;
+ if ((g = h & 0xf0000000) != 0) {
+ h ^= g >> 24;
+ h ^= g;
+ }
+ }
+ return h;
+}
+
+static const unsigned table_sizes[] = {
+101, 503, 1009, 2003, 3001, 4001, 5003, 10007, 20011, 40009,
+80021, 160001, 500009, 1000003, 2000003, 4000037, 8000009,
+16000057, 32000011, 64000031, 128000003, 0
+};
+
+unsigned next_ptable_size(unsigned n)
+{
+ for (const unsigned *p = table_sizes; *p <= n; p++)
+ if (*p == 0)
+ fatal("cannot expand table");
+ return *p;
+}
diff --git a/gnu/usr.bin/groff/libgroff/putenv.c b/gnu/usr.bin/groff/libgroff/putenv.c
new file mode 100644
index 0000000..9e1cd32
--- /dev/null
+++ b/gnu/usr.bin/groff/libgroff/putenv.c
@@ -0,0 +1,96 @@
+/* Copyright (C) 1991 Free Software Foundation, Inc.
+This file is part of the GNU C Library.
+
+The GNU C Library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public License as
+published by the Free Software Foundation; either version 2 of the
+License, or (at your option) any later version.
+
+The GNU C Library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with the GNU C Library; see the file COPYING.LIB. If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA. */
+
+/* Hacked slightly by jjc@jclark.com for groff. */
+
+#include <string.h>
+
+#ifdef __STDC__
+#include <stddef.h>
+typedef void *PTR;
+typedef size_t SIZE_T;
+#else /* not __STDC__ */
+typedef char *PTR;
+typedef int SIZE_T;
+#endif /* not __STDC__ */
+
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#else /* not HAVE_STDLIB_H */
+PTR malloc();
+#endif /* not HAVE_STDLIB_H */
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+extern char **environ;
+
+/* Put STRING, which is of the form "NAME=VALUE", in the environment. */
+
+int putenv(string)
+ char *string;
+{
+ char *name_end = strchr(string, '=');
+ SIZE_T size;
+ char **ep;
+
+ if (name_end == NULL)
+ {
+ /* Remove the variable from the environment. */
+ size = strlen(string);
+ for (ep = environ; *ep != NULL; ++ep)
+ if (!strncmp(*ep, string, size) && (*ep)[size] == '=')
+ {
+ while (ep[1] != NULL)
+ {
+ ep[0] = ep[1];
+ ++ep;
+ }
+ *ep = NULL;
+ return 0;
+ }
+ }
+
+ size = 0;
+ for (ep = environ; *ep != NULL; ++ep)
+ if (!strncmp(*ep, string, name_end - string)
+ && (*ep)[name_end - string] == '=')
+ break;
+ else
+ ++size;
+
+ if (*ep == NULL)
+ {
+ static char **last_environ = NULL;
+ char **new_environ = (char **) malloc((size + 2) * sizeof(char *));
+ if (new_environ == NULL)
+ return -1;
+ (void) memcpy((PTR) new_environ, (PTR) environ, size * sizeof(char *));
+ new_environ[size] = (char *) string;
+ new_environ[size + 1] = NULL;
+ if (last_environ != NULL)
+ free((PTR) last_environ);
+ last_environ = new_environ;
+ environ = new_environ;
+ }
+ else
+ *ep = (char *) string;
+
+ return 0;
+}
diff --git a/gnu/usr.bin/groff/libgroff/searchpath.cc b/gnu/usr.bin/groff/libgroff/searchpath.cc
new file mode 100644
index 0000000..eb7a669
--- /dev/null
+++ b/gnu/usr.bin/groff/libgroff/searchpath.cc
@@ -0,0 +1,117 @@
+// -*- C++ -*-
+/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
+ Written by James Clark (jjc@jclark.com)
+
+This file is part of groff.
+
+groff is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
+
+groff is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License along
+with groff; see the file COPYING. If not, write to the Free Software
+Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <assert.h>
+
+#include "lib.h"
+#include "searchpath.h"
+
+search_path::search_path(const char *envvar, const char *standard)
+{
+ char *e = envvar ? getenv(envvar) : 0;
+ if (e && standard) {
+ dirs = new char[strlen(e) + strlen(standard) + 2];
+ strcpy(dirs, e);
+ strcat(dirs, ":");
+ strcat(dirs, standard);
+ }
+ else
+ dirs = strsave(e ? e : standard);
+ init_len = dirs ? strlen(dirs) : 0;
+}
+
+search_path::~search_path()
+{
+ if (dirs)
+ a_delete dirs;
+}
+
+void search_path::command_line_dir(const char *s)
+{
+ if (!dirs)
+ dirs = strsave(s);
+ else {
+ char *old = dirs;
+ unsigned old_len = strlen(old);
+ unsigned slen = strlen(s);
+ dirs = new char[old_len + 1 + slen + 1];
+ memcpy(dirs, old, old_len - init_len);
+ char *p = dirs;
+ p += old_len - init_len;
+ if (init_len == 0)
+ *p++ = ':';
+ memcpy(p, s, slen);
+ p += slen;
+ if (init_len > 0) {
+ *p++ = ':';
+ memcpy(p, old + old_len - init_len, init_len);
+ p += init_len;
+ }
+ *p++ = '\0';
+ a_delete old;
+ }
+}
+
+FILE *search_path::open_file(const char *name, char **pathp)
+{
+ assert(name != 0);
+ if (*name == '/' || dirs == 0 || *dirs == '\0') {
+ FILE *fp = fopen(name, "r");
+ if (fp) {
+ if (pathp)
+ *pathp = strsave(name);
+ return fp;
+ }
+ else
+ return 0;
+ }
+ unsigned namelen = strlen(name);
+ char *p = dirs;
+ for (;;) {
+ char *end = strchr(p, ':');
+ if (!end)
+ end = strchr(p, '\0');
+ int need_slash = end > p && end[-1] != '/';
+ char *path = new char[(end - p) + need_slash + namelen + 1];
+ memcpy(path, p, end - p);
+ if (need_slash)
+ path[end - p] = '/';
+ strcpy(path + (end - p) + need_slash, name);
+#if 0
+ fprintf(stderr, "trying `%s'\n", path);
+#endif
+ FILE *fp = fopen(path, "r");
+ if (fp) {
+ if (pathp)
+ *pathp = path;
+ else
+ a_delete path;
+ return fp;
+ }
+ a_delete path;
+ if (*end == '\0')
+ break;
+ p = end + 1;
+ }
+ return 0;
+}
diff --git a/gnu/usr.bin/groff/libgroff/strerror.c b/gnu/usr.bin/groff/libgroff/strerror.c
new file mode 100644
index 0000000..de42b83
--- /dev/null
+++ b/gnu/usr.bin/groff/libgroff/strerror.c
@@ -0,0 +1,37 @@
+/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
+ Written by James Clark (jjc@jclark.com)
+
+This file is part of groff.
+
+groff is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
+
+groff is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License along
+with groff; see the file COPYING. If not, write to the Free Software
+Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <stdio.h>
+
+#define INT_DIGITS 19 /* enough for 64 bit integer */
+
+extern int sys_nerr;
+extern char *sys_errlist[];
+
+char *strerror(n)
+ int n;
+{
+ static char buf[sizeof("Error ") + 1 + INT_DIGITS];
+ if (n >= 0 && n < sys_nerr && sys_errlist[n] != 0)
+ return sys_errlist[n];
+ else {
+ sprintf(buf, "Error %d", n);
+ return buf;
+ }
+}
diff --git a/gnu/usr.bin/groff/libgroff/string.cc b/gnu/usr.bin/groff/libgroff/string.cc
new file mode 100644
index 0000000..e20e249
--- /dev/null
+++ b/gnu/usr.bin/groff/libgroff/string.cc
@@ -0,0 +1,310 @@
+// -*- C++ -*-
+/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
+ Written by James Clark (jjc@jclark.com)
+
+This file is part of groff.
+
+groff is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
+
+groff is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License along
+with groff; see the file COPYING. If not, write to the Free Software
+Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <stdio.h>
+#include "stringclass.h"
+#include "lib.h"
+
+static char *salloc(int len, int *sizep);
+static void sfree(char *ptr, int size);
+static char *sfree_alloc(char *ptr, int size, int len, int *sizep);
+static char *srealloc(char *ptr, int size, int oldlen, int newlen, int *sizep);
+
+static char *salloc(int len, int *sizep)
+{
+ if (len == 0) {
+ *sizep = 0;
+ return 0;
+ }
+ else
+ return new char[*sizep = len*2];
+}
+
+static void sfree(char *ptr, int)
+{
+ a_delete ptr;
+}
+
+static char *sfree_alloc(char *ptr, int oldsz, int len, int *sizep)
+{
+ if (oldsz >= len) {
+ *sizep = oldsz;
+ return ptr;
+ }
+ a_delete ptr;
+ if (len == 0) {
+ *sizep = 0;
+ return 0;
+ }
+ else
+ return new char[*sizep = len*2];
+}
+
+static char *srealloc(char *ptr, int oldsz, int oldlen, int newlen, int *sizep)
+{
+ if (oldsz >= newlen) {
+ *sizep = oldsz;
+ return ptr;
+ }
+ if (newlen == 0) {
+ a_delete ptr;
+ *sizep = 0;
+ return 0;
+ }
+ else {
+ char *p = new char[*sizep = newlen*2];
+ if (oldlen < newlen && oldlen != 0)
+ memcpy(p, ptr, oldlen);
+ a_delete ptr;
+ return p;
+ }
+}
+
+string::string() : len(0), ptr(0), sz(0)
+{
+}
+
+string::string(const char *p, int n) : len(n)
+{
+ assert(n >= 0);
+ ptr = salloc(n, &sz);
+ if (n != 0)
+ memcpy(ptr, p, n);
+}
+
+string::string(const char *p)
+{
+ if (p == 0) {
+ len = 0;
+ ptr = 0;
+ sz = 0;
+ }
+ else {
+ len = strlen(p);
+ ptr = salloc(len, &sz);
+ memcpy(ptr, p, len);
+ }
+}
+
+string::string(char c) : len(1)
+{
+ ptr = salloc(1, &sz);
+ *ptr = c;
+}
+
+string::string(const string &s) : len(s.len)
+{
+ ptr = salloc(len, &sz);
+ if (len != 0)
+ memcpy(ptr, s.ptr, len);
+}
+
+string::~string()
+{
+ sfree(ptr, sz);
+}
+
+string &string::operator=(const string &s)
+{
+ ptr = sfree_alloc(ptr, sz, s.len, &sz);
+ len = s.len;
+ if (len != 0)
+ memcpy(ptr, s.ptr, len);
+ return *this;
+}
+
+string &string::operator=(const char *p)
+{
+ if (p == 0) {
+ sfree(ptr, len);
+ len = 0;
+ ptr = 0;
+ sz = 0;
+ }
+ else {
+ int slen = strlen(p);
+ ptr = sfree_alloc(ptr, sz, slen, &sz);
+ len = slen;
+ memcpy(ptr, p, len);
+ }
+ return *this;
+}
+
+string &string::operator=(char c)
+{
+ ptr = sfree_alloc(ptr, sz, 1, &sz);
+ len = 1;
+ *ptr = c;
+ return *this;
+}
+
+void string::move(string &s)
+{
+ sfree(ptr, sz);
+ ptr = s.ptr;
+ len = s.len;
+ sz = s.sz;
+ s.ptr = 0;
+ s.len = 0;
+ s.sz = 0;
+}
+
+void string::grow1()
+{
+ ptr = srealloc(ptr, sz, len, len + 1, &sz);
+}
+
+string &string::operator+=(const char *p)
+{
+ if (p != 0) {
+ int n = strlen(p);
+ int newlen = len + n;
+ if (newlen > sz)
+ ptr = srealloc(ptr, sz, len, newlen, &sz);
+ memcpy(ptr + len, p, n);
+ len = newlen;
+ }
+ return *this;
+}
+
+string &string::operator+=(const string &s)
+{
+ if (s.len != 0) {
+ int newlen = len + s.len;
+ if (newlen > sz)
+ ptr = srealloc(ptr, sz, len, newlen, &sz);
+ memcpy(ptr + len, s.ptr, s.len);
+ len = newlen;
+ }
+ return *this;
+}
+
+void string::append(const char *p, int n)
+{
+ if (n > 0) {
+ int newlen = len + n;
+ if (newlen > sz)
+ ptr = srealloc(ptr, sz, len, newlen, &sz);
+ memcpy(ptr + len, p, n);
+ len = newlen;
+ }
+}
+
+string::string(const char *s1, int n1, const char *s2, int n2)
+{
+ assert(n1 >= 0 && n2 >= 0);
+ len = n1 + n2;
+ if (len == 0) {
+ sz = 0;
+ ptr = 0;
+ }
+ else {
+ ptr = salloc(len, &sz);
+ if (n1 == 0)
+ memcpy(ptr, s2, n2);
+ else {
+ memcpy(ptr, s1, n1);
+ if (n2 != 0)
+ memcpy(ptr + n1, s2, n2);
+ }
+ }
+}
+
+int operator<=(const string &s1, const string &s2)
+{
+ return (s1.len <= s2.len
+ ? s1.len == 0 || memcmp(s1.ptr, s2.ptr, s1.len) <= 0
+ : s2.len != 0 && memcmp(s1.ptr, s2.ptr, s2.len) < 0);
+}
+
+int operator<(const string &s1, const string &s2)
+{
+ return (s1.len < s2.len
+ ? s1.len == 0 || memcmp(s1.ptr, s2.ptr, s1.len) <= 0
+ : s2.len != 0 && memcmp(s1.ptr, s2.ptr, s2.len) < 0);
+}
+
+int operator>=(const string &s1, const string &s2)
+{
+ return (s1.len >= s2.len
+ ? s2.len == 0 || memcmp(s1.ptr, s2.ptr, s2.len) >= 0
+ : s1.len != 0 && memcmp(s1.ptr, s2.ptr, s1.len) > 0);
+}
+
+int operator>(const string &s1, const string &s2)
+{
+ return (s1.len > s2.len
+ ? s2.len == 0 || memcmp(s1.ptr, s2.ptr, s2.len) >= 0
+ : s1.len != 0 && memcmp(s1.ptr, s2.ptr, s1.len) > 0);
+}
+
+void string::set_length(int i)
+{
+ assert(i >= 0);
+ if (i > sz)
+ ptr = srealloc(ptr, sz, len, i, &sz);
+ len = i;
+}
+
+void string::clear()
+{
+ len = 0;
+}
+
+int string::search(char c) const
+{
+ char *p = (char *)memchr(ptr, c, len);
+ return p ? p - ptr : -1;
+}
+
+// we silently strip nuls
+
+char *string::extract() const
+{
+ char *p = ptr;
+ int n = len;
+ int nnuls = 0;
+ for (int i = 0; i < n; i++)
+ if (p[i] == '\0')
+ nnuls++;
+ char *q = new char[n + 1 - nnuls];
+ char *r = q;
+ for (i = 0; i < n; i++)
+ if (p[i] != '\0')
+ *r++ = p[i];
+ q[n] = '\0';
+ return q;
+}
+
+void put_string(const string &s, FILE *fp)
+{
+ int len = s.length();
+ const char *ptr = s.contents();
+ for (int i = 0; i < len; i++)
+ putc(ptr[i], fp);
+}
+
+string as_string(int i)
+{
+ static char buf[INT_DIGITS + 2];
+ sprintf(buf, "%d", i);
+ return string(buf);
+}
+
diff --git a/gnu/usr.bin/groff/libgroff/strsave.cc b/gnu/usr.bin/groff/libgroff/strsave.cc
new file mode 100644
index 0000000..5a4b5da
--- /dev/null
+++ b/gnu/usr.bin/groff/libgroff/strsave.cc
@@ -0,0 +1,31 @@
+// -*- C++ -*-
+/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
+ Written by James Clark (jjc@jclark.com)
+
+This file is part of groff.
+
+groff is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
+
+groff is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License along
+with groff; see the file COPYING. If not, write to the Free Software
+Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <string.h>
+
+char *strsave(const char *s)
+{
+ if (s == 0)
+ return 0;
+ char *p = new char[strlen(s) + 1];
+ strcpy(p, s);
+ return p;
+}
+
diff --git a/gnu/usr.bin/groff/libgroff/strtol.c b/gnu/usr.bin/groff/libgroff/strtol.c
new file mode 100644
index 0000000..3caf4e2
--- /dev/null
+++ b/gnu/usr.bin/groff/libgroff/strtol.c
@@ -0,0 +1,131 @@
+/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
+ Written by James Clark (jjc@jclark.com)
+
+This file is part of groff.
+
+groff is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
+
+groff is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License along
+with groff; see the file COPYING. If not, write to the Free Software
+Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+#ifndef errno
+extern int errno;
+#endif
+
+#ifdef HAVE_LIMITS_H
+#include <limits.h>
+#endif
+
+#ifndef LONG_MAX
+#define LONG_MAX 2147483647
+#endif
+
+#ifndef LONG_MIN
+#define LONG_MIN (-LONG_MAX-1)
+#endif
+
+#ifdef isascii
+#define ISASCII(c) isascii(c)
+#else
+#define ISASCII(c) (1)
+#endif
+
+long strtol(str, ptr, base)
+ char *str, **ptr;
+ int base;
+{
+ char *start = str;
+ int neg = 0;
+ long val;
+ char *p;
+ static char digits[] = "0123456789abcdefghijklmnopqrstuvwxyz";
+
+ while (ISASCII((unsigned char)*str) && isspace((unsigned char)*str))
+ str++;
+
+ if (*str == '-') {
+ neg = 1;
+ str++;
+ }
+ if (base == 0) {
+ if (*str == '0') {
+ if (str[1] == 'x' || str[1] == 'X') {
+ str += 2;
+ base = 16;
+ }
+ else
+ base = 8;
+ }
+ else
+ base = 10;
+ }
+ if (base < 2 || base > 36)
+ base = 10;
+ else if (base == 16 && *str == '0' && (str[1] == 'x' || str[1] == 'X'))
+ str += 2;
+
+ p = strchr(digits, (ISASCII((unsigned char)*str)
+ && isupper((unsigned char)*str)
+ ? tolower((unsigned char)*str)
+ : *str));
+ if (p == 0 || (val = (p - digits)) >= base) {
+ if (base == 16 && str > start && (str[-1] == 'x' || str[-1] == 'X')) {
+ if (ptr)
+ *ptr = str - 1;
+ }
+ else {
+ if (ptr)
+ *ptr = start;
+ errno = ERANGE;
+ }
+ return 0;
+ }
+ if (neg)
+ val = -val;
+
+ while (*++str != '\0') {
+ int n;
+
+ p = strchr(digits, (ISASCII((unsigned char)*str)
+ && isupper((unsigned char)*str)
+ ? tolower((unsigned char)*str) : *str));
+ if (p == 0)
+ break;
+ n = p - digits;
+ if (n >= base)
+ break;
+ if (neg) {
+ if (-(unsigned long)val > (-(unsigned long)LONG_MIN - n)/base) {
+ val = LONG_MIN;
+ errno = ERANGE;
+ }
+ else
+ val = val*base - n;
+ }
+ else {
+ if (val > (LONG_MAX - n)/base) {
+ val = LONG_MAX;
+ errno = ERANGE;
+ }
+ else
+ val = val*base + n;
+ }
+ }
+
+ if (ptr)
+ *ptr = str;
+
+ return val;
+}
diff --git a/gnu/usr.bin/groff/libgroff/tmpfile.cc b/gnu/usr.bin/groff/libgroff/tmpfile.cc
new file mode 100644
index 0000000..bd6f8ad
--- /dev/null
+++ b/gnu/usr.bin/groff/libgroff/tmpfile.cc
@@ -0,0 +1,99 @@
+// -*- C++ -*-
+/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
+ Written by James Clark (jjc@jclark.com)
+
+This file is part of groff.
+
+groff is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
+
+groff is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License along
+with groff; see the file COPYING. If not, write to the Free Software
+Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "posix.h"
+#include "lib.h"
+#include "errarg.h"
+#include "error.h"
+
+extern "C" {
+ // Sun's stdlib.h fails to declare this.
+ char *mktemp(char *);
+ int mkstemp(char *);
+}
+
+// If this is set, create temporary files there
+#define GROFF_TMPDIR_ENVVAR "GROFF_TMPDIR"
+// otherwise if this is set, create temporary files there
+#define TMPDIR_ENVVAR "TMPDIR"
+// otherwise create temporary files here.
+#define DEFAULT_TMPDIR "/tmp"
+// Use this as the prefix for temporary filenames.
+#define TMPFILE_PREFIX "groff"
+
+// Open a temporary file with fatal error on failure.
+
+FILE *xtmpfile()
+{
+ const char *dir = getenv(GROFF_TMPDIR_ENVVAR);
+ if (!dir) {
+ dir = getenv(TMPDIR_ENVVAR);
+ if (!dir)
+ dir = DEFAULT_TMPDIR;
+ }
+
+ const char *p = strrchr(dir, '/');
+ int needs_slash = (!p || p[1]);
+ char *templ = new char[strlen(dir) + needs_slash
+ + sizeof(TMPFILE_PREFIX) - 1 + 6 + 1];
+ strcpy(templ, dir);
+ if (needs_slash)
+ strcat(templ, "/");
+ strcat(templ, TMPFILE_PREFIX);
+ strcat(templ, "XXXXXX");
+
+#ifdef HAVE_MKSTEMP
+ errno = 0;
+ int fd = mkstemp(templ);
+ if (fd < 0)
+ fatal("cannot create temporary file: %1", strerror(errno));
+ errno = 0;
+ FILE *fp = fdopen(fd, "w+");
+ if (!fp)
+ fatal("fdopen: %1", strerror(errno));
+#else /* not HAVE_MKSTEMP */
+ if (!mktemp(templ) || !templ[0])
+ fatal("cannot create file name for temporary file");
+ errno = 0;
+ FILE *fp = fopen(templ, "w+");
+ if (!fp)
+ fatal("cannot open `%1': %2", templ, strerror(errno));
+#endif /* not HAVE_MKSTEMP */
+ if (unlink(templ) < 0)
+ error("cannot unlink `%1': %2", templ, strerror(errno));
+ a_delete templ;
+ return fp;
+}
+
+#if 0
+// If you're not running Unix, the following will do:
+FILE *xtmpfile()
+{
+ FILE *fp = tmpfile();
+ if (!fp)
+ fatal("couldn't create temporary file");
+ return fp;
+}
+#endif
diff --git a/gnu/usr.bin/groff/lkbib/Makefile b/gnu/usr.bin/groff/lkbib/Makefile
new file mode 100644
index 0000000..d00f0f6
--- /dev/null
+++ b/gnu/usr.bin/groff/lkbib/Makefile
@@ -0,0 +1,13 @@
+# Makefile for lkbib
+
+PROG= lkbib
+SRCS= lkbib.cc
+CFLAGS+= -I${.CURDIR}/../include
+LDADD+= ${LIBBIB} ${LIBGROFF} -lm
+DPADD+= ${LIBBIB} ${LIBGROFF} ${LIBM}
+
+MANDEPEND= lkbib.1
+CLEANFILES+= ${MANDEPEND}
+
+.include "../Makefile.cfg"
+.include <bsd.prog.mk>
diff --git a/gnu/usr.bin/groff/lkbib/Makefile.dep b/gnu/usr.bin/groff/lkbib/Makefile.dep
new file mode 100644
index 0000000..b6845ea
--- /dev/null
+++ b/gnu/usr.bin/groff/lkbib/Makefile.dep
@@ -0,0 +1,2 @@
+lkbib.o : lkbib.cc ../include/lib.h ../include/errarg.h ../include/error.h \
+ ../include/defs.h ../include/refid.h ../include/search.h
diff --git a/gnu/usr.bin/groff/lkbib/Makefile.sub b/gnu/usr.bin/groff/lkbib/Makefile.sub
new file mode 100644
index 0000000..30035bc
--- /dev/null
+++ b/gnu/usr.bin/groff/lkbib/Makefile.sub
@@ -0,0 +1,6 @@
+PROG=lkbib
+MAN1=lkbib.n
+XLIBS=$(LIBBIB) $(LIBGROFF)
+MLIB=$(LIBM)
+OBJS=lkbib.o
+CCSRCS=lkbib.cc
diff --git a/gnu/usr.bin/groff/lkbib/lkbib.cc b/gnu/usr.bin/groff/lkbib/lkbib.cc
new file mode 100644
index 0000000..74459b7
--- /dev/null
+++ b/gnu/usr.bin/groff/lkbib/lkbib.cc
@@ -0,0 +1,122 @@
+// -*- C++ -*-
+/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
+ Written by James Clark (jjc@jclark.com)
+
+This file is part of groff.
+
+groff is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
+
+groff is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License along
+with groff; see the file COPYING. If not, write to the Free Software
+Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <assert.h>
+
+#include "lib.h"
+#include "errarg.h"
+#include "error.h"
+
+#include "defs.h"
+#include "refid.h"
+#include "search.h"
+
+static void usage()
+{
+ fprintf(stderr, "usage: %s [-nv] [-p database] [-i XYZ] [-t N] keys ...\n",
+ program_name);
+ exit(1);
+}
+
+int main(int argc, char **argv)
+{
+ program_name = argv[0];
+ static char stderr_buf[BUFSIZ];
+ setbuf(stderr, stderr_buf);
+ int search_default = 1;
+ search_list list;
+ int opt;
+ while ((opt = getopt(argc, argv, "nvVi:t:p:")) != EOF)
+ switch (opt) {
+ case 'V':
+ verify_flag = 1;
+ break;
+ case 'n':
+ search_default = 0;
+ break;
+ case 'i':
+ linear_ignore_fields = optarg;
+ break;
+ case 't':
+ {
+ char *ptr;
+ long n = strtol(optarg, &ptr, 10);
+ if (n == 0 && ptr == optarg) {
+ error("bad integer `%1' in `t' option", optarg);
+ break;
+ }
+ if (n < 1)
+ n = 1;
+ linear_truncate_len = int(n);
+ break;
+ }
+ case 'v':
+ {
+ extern const char *version_string;
+ fprintf(stderr, "GNU lkbib version %s\n", version_string);
+ fflush(stderr);
+ break;
+ }
+ case 'p':
+ list.add_file(optarg);
+ break;
+ case '?':
+ usage();
+ default:
+ assert(0);
+ }
+ if (optind >= argc)
+ usage();
+ char *filename = getenv("REFER");
+ if (filename)
+ list.add_file(filename);
+ else if (search_default)
+ list.add_file(DEFAULT_INDEX, 1);
+ if (list.nfiles() == 0)
+ fatal("no databases");
+ int total_len = 0;
+ for (int i = optind; i < argc; i++)
+ total_len += strlen(argv[i]);
+ total_len += argc - optind - 1 + 1; // for spaces and '\0'
+ char *buffer = new char[total_len];
+ char *ptr = buffer;
+ for (i = optind; i < argc; i++) {
+ if (i > optind)
+ *ptr++ = ' ';
+ strcpy(ptr, argv[i]);
+ ptr = strchr(ptr, '\0');
+ }
+ search_list_iterator iter(&list, buffer);
+ const char *start;
+ int len;
+ for (int count = 0; iter.next(&start, &len); count++) {
+ if (fwrite(start, 1, len, stdout) != len)
+ fatal("write error on stdout: %1", strerror(errno));
+ // Can happen for last reference in file.
+ if (start[len - 1] != '\n')
+ putchar('\n');
+ putchar('\n');
+ }
+ return !count;
+}
diff --git a/gnu/usr.bin/groff/lkbib/lkbib.man b/gnu/usr.bin/groff/lkbib/lkbib.man
new file mode 100644
index 0000000..6450764
--- /dev/null
+++ b/gnu/usr.bin/groff/lkbib/lkbib.man
@@ -0,0 +1,90 @@
+.\" -*- nroff -*-
+.ds g \" empty
+.ds G \" empty
+.\" Like TP, but if specified indent is more than half
+.\" the current line-length - indent, use the default indent.
+.de Tp
+.ie \\n(.$=0:((0\\$1)*2u>(\\n(.lu-\\n(.iu)) .TP
+.el .TP "\\$1"
+..
+.TH LKBIB @MAN1EXT@ "@MDATE@" "Groff Version @VERSION@"
+.SH NAME
+lkbib \- search bibliographic databases
+.SH SYNOPSIS
+.B lkbib
+[
+.B \-v
+]
+[
+.BI \-i fields
+]
+[
+.BI \-p filename
+]
+[
+.BI \-t n
+]
+.IR key \|.\|.\|.
+.SH DESCRIPTION
+.B lkbib
+searches bibliographic databases for references that contain the keys
+.IR key \|.\|.\|.
+and prints any references found on the standard output.
+.B lkbib
+will search any databases given by
+.B \-p
+options, and then a default database.
+The default database is taken from the
+.SB REFER
+environment variable if it is set,
+otherwise it is
+.BR @DEFAULT_INDEX@ .
+For each database
+.I filename
+to be searched,
+if an index
+.IB filename @INDEX_SUFFIX@
+created by
+.BR @g@indxbib (@MAN1EXT@)
+exists, then it will be searched instead;
+each index can cover multiple databases.
+.SH OPTIONS
+.TP
+.B \-v
+Print the version number.
+.TP
+.BI \-p filename
+Search
+.IR filename .
+Multiple
+.B \-p
+options can be used.
+.TP
+.BI \-i string
+When searching files for which no index exists,
+ignore the contents of fields whose names are in
+.IR string .
+.TP
+.BI \-t n
+Only require the first
+.I n
+characters of keys to be given.
+Initially
+.I n
+is 6.
+.SH ENVIRONMENT
+.TP \w'\fBREFER'u+2n
+.SB REFER
+Default database.
+.SH FILES
+.Tp \w'\fB@DEFAULT_INDEX@'u+2n
+.B @DEFAULT_INDEX@
+Default database to be used if the
+.SB REFER
+environment variable is not set.
+.IB filename @INDEX_SUFFIX@
+Index files.
+.SH "SEE ALSO"
+.BR @g@refer (@MAN1EXT@),
+.BR @g@lookbib (@MAN1EXT@),
+.BR @g@indxbib (@MAN1EXT@)
diff --git a/gnu/usr.bin/groff/lookbib/Makefile b/gnu/usr.bin/groff/lookbib/Makefile
new file mode 100644
index 0000000..fb1a65c
--- /dev/null
+++ b/gnu/usr.bin/groff/lookbib/Makefile
@@ -0,0 +1,13 @@
+# Makefile for lookbib
+
+PROG= lookbib
+SRCS= lookbib.cc
+CFLAGS+= -I$(.CURDIR)/../include
+LDADD+= $(LIBBIB) $(LIBGROFF) -lm
+DPADD+= $(LIBBIB) $(LIBGROFF) $(LIBM)
+
+MANDEPEND= lookbib.1
+CLEANFILES+= ${MANDEPEND}
+
+.include "../Makefile.cfg"
+.include <bsd.prog.mk>
diff --git a/gnu/usr.bin/groff/lookbib/Makefile.dep b/gnu/usr.bin/groff/lookbib/Makefile.dep
new file mode 100644
index 0000000..e6597d4
--- /dev/null
+++ b/gnu/usr.bin/groff/lookbib/Makefile.dep
@@ -0,0 +1,2 @@
+lookbib.o : lookbib.cc ../include/errarg.h ../include/error.h \
+ ../include/lib.h ../include/cset.h ../include/refid.h ../include/search.h
diff --git a/gnu/usr.bin/groff/lookbib/Makefile.sub b/gnu/usr.bin/groff/lookbib/Makefile.sub
new file mode 100644
index 0000000..1183812
--- /dev/null
+++ b/gnu/usr.bin/groff/lookbib/Makefile.sub
@@ -0,0 +1,7 @@
+PROG=lookbib
+MAN1=lookbib.n
+XLIBS=$(LIBBIB) $(LIBGROFF)
+MLIB=$(LIBM)
+OBJS=lookbib.o
+CCSRCS=lookbib.cc
+NAMEPREFIX=$(g)
diff --git a/gnu/usr.bin/groff/lookbib/lookbib.cc b/gnu/usr.bin/groff/lookbib/lookbib.cc
new file mode 100644
index 0000000..e721e94
--- /dev/null
+++ b/gnu/usr.bin/groff/lookbib/lookbib.cc
@@ -0,0 +1,127 @@
+// -*- C++ -*-
+/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
+ Written by James Clark (jjc@jclark.com)
+
+This file is part of groff.
+
+groff is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
+
+groff is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License along
+with groff; see the file COPYING. If not, write to the Free Software
+Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <errno.h>
+
+#include "errarg.h"
+#include "error.h"
+#include "lib.h"
+#include "cset.h"
+
+#include "refid.h"
+#include "search.h"
+
+extern "C" {
+ int isatty(int);
+}
+
+static void usage()
+{
+ fprintf(stderr, "usage: %s [-v] [-i XYZ] [-t N] database ...\n",
+ program_name);
+ exit(1);
+}
+
+int main(int argc, char **argv)
+{
+ program_name = argv[0];
+ static char stderr_buf[BUFSIZ];
+ setbuf(stderr, stderr_buf);
+ int opt;
+ while ((opt = getopt(argc, argv, "vVi:t:")) != EOF)
+ switch (opt) {
+ case 'V':
+ verify_flag = 1;
+ break;
+ case 'i':
+ linear_ignore_fields = optarg;
+ break;
+ case 't':
+ {
+ char *ptr;
+ long n = strtol(optarg, &ptr, 10);
+ if (n == 0 && ptr == optarg) {
+ error("bad integer `%1' in `t' option", optarg);
+ break;
+ }
+ if (n < 1)
+ n = 1;
+ linear_truncate_len = int(n);
+ break;
+ }
+ case 'v':
+ {
+ extern const char *version_string;
+ fprintf(stderr, "GNU lookbib version %s\n", version_string);
+ fflush(stderr);
+ break;
+ }
+ case '?':
+ usage();
+ default:
+ assert(0);
+ }
+ if (optind >= argc)
+ usage();
+ search_list list;
+ for (int i = optind; i < argc; i++)
+ list.add_file(argv[i]);
+ if (list.nfiles() == 0)
+ fatal("no databases");
+ char line[1024];
+ int interactive = isatty(fileno(stdin));
+ for (;;) {
+ if (interactive) {
+ fputs("> ", stderr);
+ fflush(stderr);
+ }
+ if (!fgets(line, sizeof(line), stdin))
+ break;
+ char *ptr = line;
+ while (csspace(*ptr))
+ ptr++;
+ if (*ptr == '\0')
+ continue;
+ search_list_iterator iter(&list, line);
+ const char *start;
+ int len;
+ for (int count = 0; iter.next(&start, &len); count++) {
+ if (fwrite(start, 1, len, stdout) != len)
+ fatal("write error on stdout: %1", strerror(errno));
+ // Can happen for last reference in file.
+ if (start[len - 1] != '\n')
+ putchar('\n');
+ putchar('\n');
+ }
+ fflush(stdout);
+ if (interactive) {
+ fprintf(stderr, "%d found\n", count);
+ fflush(stderr);
+ }
+ }
+ if (interactive)
+ putc('\n', stderr);
+ return 0;
+}
+
diff --git a/gnu/usr.bin/groff/lookbib/lookbib.man b/gnu/usr.bin/groff/lookbib/lookbib.man
new file mode 100644
index 0000000..641f5bc
--- /dev/null
+++ b/gnu/usr.bin/groff/lookbib/lookbib.man
@@ -0,0 +1,58 @@
+.\" -*- nroff -*-
+.TH @G@LOOKBIB @MAN1EXT@ "@MDATE@" "Groff Version @VERSION@"
+.SH NAME
+@g@lookbib \- search bibliographic databases
+.SH SYNOPSIS
+.B @g@lookbib
+[
+.B \-v
+]
+[
+.BI \-i string
+]
+[
+.BI \-t n
+]
+.IR filename \|.\|.\|.
+.SH DESCRIPTION
+@g@lookbib prints a prompt on the standard error (unless the standard input is not a terminal),
+reads from the standard input a line containing a set of keywords,
+searches the bibliographic databases
+.IR filename \|.\|.\|.
+for references containing those keywords,
+prints any references found on the standard output,
+and repeats this process until the end of input.
+For each database
+.I filename
+to be searched,
+if an index
+.IB filename @INDEX_SUFFIX@
+created by
+.BR @g@indxbib (@MAN1EXT@)
+exists, then it will be searched instead;
+each index can cover multiple databases.
+.SH OPTIONS
+.TP
+.B \-v
+Print the version number.
+.TP
+.BI \-i string
+When searching files for which no index exists,
+ignore the contents of fields whose names are in
+.IR string .
+.TP
+.BI \-t n
+Only require the first
+.I n
+characters of keys to be given.
+Initially
+.I n
+is 6.
+.SH FILES
+.TP \w'\fIfilename\fB@INDEX_SUFFIX@'u+2n
+.IB filename @INDEX_SUFFIX@
+Index files.
+.SH "SEE ALSO"
+.BR @g@refer (@MAN1EXT@),
+.BR lkbib (@MAN1EXT@),
+.BR @g@indxbib (@MAN1EXT@)
diff --git a/gnu/usr.bin/groff/man/Makefile b/gnu/usr.bin/groff/man/Makefile
new file mode 100644
index 0000000..4723c0a
--- /dev/null
+++ b/gnu/usr.bin/groff/man/Makefile
@@ -0,0 +1,10 @@
+# Makefile for manpages
+
+MAN5= groff_font.5 groff_out.5
+MAN7= groff_char.7
+
+MANDEPEND= ${MAN5} ${MAN7}
+CLEANFILES+= ${MANDEPEND}
+
+.include "../Makefile.cfg"
+.include <bsd.prog.mk>
diff --git a/gnu/usr.bin/groff/man/Makefile.sub b/gnu/usr.bin/groff/man/Makefile.sub
new file mode 100644
index 0000000..9b87114
--- /dev/null
+++ b/gnu/usr.bin/groff/man/Makefile.sub
@@ -0,0 +1,2 @@
+MAN5=groff_font.n groff_out.n
+MAN7=groff_char.n
diff --git a/gnu/usr.bin/groff/man/groff_char.man b/gnu/usr.bin/groff/man/groff_char.man
new file mode 100644
index 0000000..b722f91
--- /dev/null
+++ b/gnu/usr.bin/groff/man/groff_char.man
@@ -0,0 +1,545 @@
+.\" -*- nroff -*-
+.\" For best results, print this with groff.
+.ds aq \(aq
+.ie !\n(.g .if '\(aq'' .ds aq \'
+.el \{\
+. tr \(aq\(aq
+. if !c\(aq .ds aq \'
+.\}
+.if !\n(.g .ig
+.\" .Ac accented-char accent char
+.de Ac
+.char \\$1 \\$3\
+\k[acc]\
+\h'(u;-\w'\\$2'-\w'\\$3'/2+\\\\n[skw]+(\w'x'*0)-\\\\n[skw])'\
+\v'(u;\w'x'*0+\\\\n[rst]+(\w'\\$3'*0)-\\\\n[rst])'\
+\\$2\
+\v'(u;\w'x'*0-\\\\n[rst]+(\w'\\$3'*0)+\\\\n[rst])'\
+\h'|\\\\n[acc]u'
+.hcode \\$1\\$3
+..
+.Ac \(vc \(ah c
+.Ac \(vC \(ah C
+.TH GROFF_CHAR @MAN7EXT@ "@MDATE@" "Groff Version @VERSION@"
+.SH NAME
+groff_char \- groff character names
+.SH DESCRIPTION
+This manual page lists the standard
+.B groff
+input characters.
+Only the characters that are available for the device that
+is being used to print this manual page will be displayed.
+The
+.I "Input code"
+column applies to characters which can be
+input with a single character, and gives the ISO Latin-1 code
+of that input character.
+The
+.I "PostScript name\"
+column gives the usual PostScript name of the output character.
+.LP
+The ISO Latin-1 no-break space (code 0240 octal) is equivalent to
+.BR \e (space).
+All other ISO Latin-1 characters print as themselves with the following
+exceptions:
+.B \`
+prints as `,
+.B \*(aq
+prints as ';
+the corresponding ISO Latin-1 characters can be obtained with
+.B \e`
+and
+.BR \e(aq .
+The ISO Latin-1 `Hyphen, Minus Sign' (code 45) prints as a hyphen;
+a minus sign can be obtained with
+.BR \e- .
+The ISO Latin-1 `Tilde' (code 126) prints as ~;
+the larger glyph can be obtained with
+.BR \e(ti .
+The ISO Latin-1 `Circumflex Accent' (code 94) prints as ^;
+a larger glyph can be obtained with
+.BR \e(ha .
+.sp
+'nf
+.nr Sp 3n
+.ta \w'\fIOutput'u+\n(Spu +\w'\fIInput'u+\n(Spu +\w'\fIInput'u+\n(Spu \
++\w'periodcentered'u+\n(Spu
+.de C0
+.C \\$1 "" \\$1 \\$2 "\\$3"
+..
+.de C1
+.C \e\\$1 "" \\\\\\$1 \\$2 "\\$3"
+..
+.de C2
+.C \e(\\$1 "" \\(\\$1 \\$2 "\\$3"
+..
+.if !\n(.g .ig
+.de CD
+.C \[char\\$1] \\$1 \[char\\$1] \\$2 "\\$3"
+..
+.do fspecial CR R
+.\" input-name decimal-code output-name ps-name description
+.if !\n(.g .ig
+.de C
+.if c\\$3 \{\
+.ft CR
+.tr `\`'\*(aq
+.in 0
+.di CH
+\&\\$1
+.br
+.di
+.in
+.ft
+.ds CH \\*(CH\
+.tr ``''
+\&\\$3\t\\*(CH\t\\$2\t\\$4\t\\$5
+.\}
+..
+.if \n(.g .ig
+.de C
+.if !'\\$3'' \{\
+.ft B
+.tr `\`'\*(aq
+.in 0
+.di CH
+\&\\$1
+.br
+.di
+.in
+.ft
+.ds CH \\*(CH\
+.tr ``''
+\&\\$3\t\\*(CH\t\\$2\t\\$4\t\\$5
+.\}
+..
+.wh \n(nlu+\n(.tu-\n(.Vu Fo
+.de Fo
+'bp
+.He
+..
+.de He
+.ft I
+Output Input Input PostScript Notes
+ name code name
+.ft
+.LP
+'nf
+..
+.He
+.CD 33 exclam
+.CD 34 quotedbl
+.CD 35 numbersign
+.CD 36 dollar
+.CD 37 percent
+.CD 38 ampersand
+.CD 39 quoteright
+.CD 40 parenleft
+.CD 41 parenright
+.CD 42 asterisk
+.CD 43 plus
+.CD 44 comma
+.CD 45 hyphen
+.CD 46 period
+.CD 47 slash
+.CD 58 colon
+.CD 59 semicolon
+.CD 60 less
+.CD 61 equal
+.CD 62 greater
+.CD 63 question
+.CD 64 at
+.CD 91 bracketleft
+.CD 92 backslash
+.CD 93 bracketright
+.CD 94 circumflex "circumflex accent"
+.CD 95 underscore
+.CD 96 quoteleft
+.CD 123 braceleft
+.CD 124 bar
+.CD 125 braceright
+.CD 126 tilde "tilde accent"
+.CD 161 exclamdown
+.CD 162 cent
+.CD 163 sterling
+.CD 164 currency
+.CD 165 yen
+.CD 166 brokenbar
+.CD 167 section
+.CD 168 dieresis
+.CD 169 copyright
+.CD 170 ordfeminine
+.CD 171 guillemotleft
+.CD 172 logicalnot
+.CD 173 hyphen
+.CD 174 registered
+.CD 175 macron
+.CD 176 degree
+.CD 177 plusminus
+.CD 178 twosuperior
+.CD 179 threesuperior
+.CD 180 acute "acute accent"
+.CD 181 mu
+.CD 182 paragraph
+.CD 183 periodcentered
+.CD 184 cedilla
+.CD 185 onesuperior
+.CD 186 ordmasculine
+.CD 187 guillemotright
+.CD 188 onequarter
+.CD 189 onehalf
+.CD 190 threequarters
+.CD 191 questiondown
+.CD 192 Agrave
+.CD 193 Aacute
+.CD 194 Acircumflex
+.CD 195 Atilde
+.CD 196 Adieresis
+.CD 197 Aring
+.CD 198 AE
+.CD 199 Ccedilla
+.CD 200 Egrave
+.CD 201 Eacute
+.CD 202 Ecircumflex
+.CD 203 Edieresis
+.CD 204 Igrave
+.CD 205 Iacute
+.CD 206 Icircumflex
+.CD 207 Idieresis
+.CD 208 Eth
+.CD 209 Ntilde
+.CD 210 Ograve
+.CD 211 Oacute
+.CD 212 Ocircumflex
+.CD 213 Otilde
+.CD 214 Odieresis
+.CD 215 multiply
+.CD 216 Oslash
+.CD 217 Ugrave
+.CD 218 Uacute
+.CD 219 Ucircumflex
+.CD 220 Udieresis
+.CD 221 Yacute
+.CD 222 Thorn
+.CD 223 germandbls
+.CD 224 agrave
+.CD 225 aacute
+.CD 226 acircumflex
+.CD 227 atilde
+.CD 228 adieresis
+.CD 229 aring
+.CD 230 ae
+.CD 231 ccedilla
+.CD 232 egrave
+.CD 233 eacute
+.CD 234 ecircumflex
+.CD 235 edieresis
+.CD 236 igrave
+.CD 237 iacute
+.CD 238 icircumflex
+.CD 239 idieresis
+.CD 240 eth
+.CD 241 ntilde
+.CD 242 ograve
+.CD 243 oacute
+.CD 244 ocircumflex
+.CD 245 otilde
+.CD 246 odieresis
+.CD 247 divide
+.CD 248 oslash
+.CD 249 ugrave
+.CD 250 uacute
+.CD 251 ucircumflex
+.CD 252 udieresis
+.CD 253 yacute
+.CD 254 thorn
+.CD 255 ydieresis
+.C2 -D Eth "Icelandic uppercase eth"
+.C2 Sd eth "Icelandic lowercase eth"
+.C2 TP Thorn "Icelandic uppercase thorn"
+.C2 Tp thorn "Icelandic lowercase thorn"
+.C2 AE AE
+.C2 ae ae
+.C2 OE OE
+.C2 oe oe
+.C2 IJ IJ "Dutch IJ ligature"
+.C2 ij ij "Dutch ij ligature"
+.C2 ss germandbls
+.C2 'A Aacute
+.C2 'C Cacute
+.C2 'E Eacute
+.C2 'I Iacute
+.C2 'O Oacute
+.C2 'U Uacute
+.C2 'a aacute
+.C2 'c cacute
+.C2 'e eacute
+.C2 'i iacute
+.C2 'o oacute
+.C2 'u uacute
+.C2 :A Adieresis
+.C2 :E Edieresis
+.C2 :I Idieresis
+.C2 :O Odieresis
+.C2 :U Udieresis
+.C2 :Y Ydieresis
+.C2 :a adieresis
+.C2 :e edieresis
+.C2 :i idieresis
+.C2 :o odieresis
+.C2 :u udieresis
+.C2 :y ydieresis
+.C2 ^A Acircumflex
+.C2 ^E Ecircumflex
+.C2 ^I Icircumflex
+.C2 ^O Ocircumflex
+.C2 ^U Ucircumflex
+.C2 ^a acircumflex
+.C2 ^e ecircumflex
+.C2 ^i icircumflex
+.C2 ^o ocircumflex
+.C2 ^u ucircumflex
+.C2 `A Agrave
+.C2 `E Egrave
+.C2 `I Igrave
+.C2 `O Ograve
+.C2 `U Ugrave
+.C2 `a agrave
+.C2 `e egrave
+.C2 `i igrave
+.C2 `o ograve
+.C2 `u ugrave
+.C2 ~A Atilde
+.C2 ~N Ntilde
+.C2 ~O Otilde
+.C2 ~a atilde
+.C2 ~n ntilde
+.C2 ~o otilde
+.C2 vS Scaron
+.C2 vs scaron
+.C2 vZ Zcaron
+.C2 vz zcaron
+.C2 ,C Ccedilla
+.C2 ,c ccedilla
+.C2 /L Lslash "Polish L with a slash"
+.C2 /l lslash "Polish l with a slash"
+.C2 /O Oslash
+.C2 /o oslash
+.C2 oA Aring
+.C2 oa aring
+.C2 a" hungarumlaut "Hungarian umlaut"
+.C2 a- macron "macron or bar accent"
+.C2 a. dotaccent "dot accent"
+.C2 a^ circumflex "circumflex accent"
+.C2 aa acute "acute accent"
+.C2 ga grave "grave accent"
+.C2 ab breve "breve accent"
+.C2 ac cedilla "cedilla accent"
+.C2 ad dieresis "umlaut or dieresis"
+.C2 ah caron "h\('a\(vcek accent"
+.C2 ao ring "ring or circle accent"
+.C2 a~ tilde "tilde accent"
+.C2 ho ogonek "hook or ogonek accent"
+.C2 .i dotlessi "i without a dot"
+.C2 .j dotlessj "j without a dot"
+.C2 Cs currency "Scandinavian currency sign"
+.C2 Do dollar
+.C2 Po sterling
+.C2 Ye yen
+.C2 Fn florin
+.C2 ct cent
+.C2 Fo guillemotleft
+.C2 Fc guillemotright
+.C2 fo guilsinglleft
+.C2 fc guilsinglright
+.C2 r! exclamdown
+.C2 r? questiondown
+.C2 ff ff "ff ligature"
+.C2 fi fi "fi ligature"
+.C2 fl fl "fl ligature"
+.C2 Fi ffi "ffi ligature"
+.C2 Fl ffl "ffl ligature"
+.C2 OK \& "check mark, tick"
+.C2 Of ordfeminine
+.C2 Om ordmasculine
+.C2 S1 onesuperior
+.C2 S2 twosuperior
+.C2 S3 threesuperior
+.C2 <- arrowleft
+.C2 -> arrowright
+.C2 <> arrowboth "horizontal double-headed arrow"
+.C2 da arrowdown
+.C2 ua arrowup
+.C2 va \& "vertical double-headed arrow"
+.C2 lA arrowdblleft
+.C2 rA arrowdblright
+.C2 hA arrowdblboth "horizontal double-headed double arrow"
+.C2 dA arrowdbldown
+.C2 uA arrowdblup
+.C2 vA \& "vertical double-headed double arrow"
+.C2 ba bar
+.C2 bb brokenbar
+.C2 br br "box rule with traditional troff metrics"
+.C2 ru ru "baseline rule"
+.C2 ul ul "underline with traditional troff metrics"
+.C2 bv bv "bold vertical"
+.C2 bs bell
+.C2 ci circle
+.C2 bu bullet
+.C2 co copyright
+.C2 rg registered
+.C2 tm trademark
+.C2 dd daggerdbl "double dagger sign"
+.C2 dg dagger
+.C2 ps paragraph
+.C2 sc section
+.C2 de degree
+.C2 em emdash "em dash"
+.C2 en endash "en dash"
+.C2 %0 perthousand "per thousand, per mille sign"
+.C2 12 onehalf
+.C2 14 onequarter
+.C2 34 threequarters
+.C2 f/ fraction "bar for fractions"
+.C2 fm minute "footmark, prime"
+.C2 sd second
+.C2 ha asciicircum "\s-2ASCII\s+2 circumflex, hat, caret"
+.C2 ti asciitilde "\s-2ASCII\s0 tilde, large tilde"
+.C2 hy hyphen
+.C2 lB bracketleft
+.C2 rB bracketright
+.C2 lC braceleft
+.C2 rC braceright
+.C2 la angleleft "left angle bracket"
+.C2 ra angleright "right angle bracket"
+.C2 lh handleft
+.C2 rh handright
+.C2 Bq quotedblbase "low double comma quote"
+.C2 bq quotesinglbase "low single comma quote"
+.C2 lq quotedblleft
+.C2 rq quotedblright
+.C2 oq quoteleft "single open quote"
+.C2 aq quotesingle "apostrophe quote"
+.C2 or bar
+.C2 at at
+.C1 - minus "minus sign from current font"
+.C2 sh numbersign
+.C2 sl slash
+.C2 rs backslash
+.C2 sq square
+.C2 3d therefore
+.C2 tf therefore
+.C2 *A Alpha
+.C2 *B Beta
+.C2 *C Xi
+.C2 *D Delta
+.C2 *E Epsilon
+.C2 *F Phi
+.C2 *G Gamma
+.C2 *H Theta
+.C2 *I Iota
+.C2 *K Kappa
+.C2 *L Lambda
+.C2 *M Mu
+.C2 *N Nu
+.C2 *O Omicron
+.C2 *P Pi
+.C2 *Q Psi
+.C2 *R Rho
+.C2 *S Sigma
+.C2 *T Tau
+.C2 *U Upsilon
+.C2 *W Omega
+.C2 *X Chi
+.C2 *Y Eta
+.C2 *Z Zeta
+.C2 *a alpha
+.C2 *b beta
+.C2 *c xi
+.C2 *d delta
+.C2 *e epsilon
+.C2 *f phi
+.C2 +f phi1 "variant phi"
+.C2 *g gamma
+.C2 *h theta
+.C2 +h theta1 "variant theta"
+.C2 *i iota
+.C2 *k kappa
+.C2 *l lambda
+.C2 *m mu
+.C2 *n nu
+.C2 *o omicron
+.C2 *p pi
+.C2 +p omega1 "variant pi, looking like omega"
+.C2 *q psi
+.C2 *r rho
+.C2 *s sigma
+.C2 *t tau
+.C2 *u upsilon
+.C2 *w omega
+.C2 *x chi
+.C2 *y eta
+.C2 *z zeta
+.C2 ts sigma1 "terminal sigma"
+.C2 ~~ approxequal
+.C2 ~= approxequal
+.C2 != notequal
+.C2 ** asteriskmath
+.C2 -+ minusplus
+.C2 +- plusminus
+.C2 <= lessequal
+.C2 == equivalence
+.C2 =~ congruent
+.C2 >= greaterequal
+.C2 AN logicaland
+.C2 OR logicalor
+.C2 no logicalnot
+.C2 te existential "there exists, existential quantifier"
+.C2 fa universal "for all, universal quantifier"
+.C2 Ah aleph
+.C2 Im Ifraktur "Fraktur I, imaginary"
+.C2 Re Rfraktur "Fraktur R, real"
+.C2 if infinity
+.C2 md dotmath
+.C2 mo element
+.C2 mu multiply
+.C2 nc notpropersuperset
+.C2 ne notequivalence
+.C2 nm notelement
+.C2 pl plusmath "plus sign in special font"
+.C2 eq equalmath "equals sign in special font"
+.C2 pt proportional
+.C2 pp perpendicular
+.C2 sb propersubset
+.C2 sp propersuperset
+.C2 ib reflexsubset
+.C2 ip reflexsuperset
+.C2 ap similar
+.C2 pd partialdiff "partial differentiation sign"
+.C2 c* circlemultiply "multiply sign in a circle"
+.C2 c+ circleplus "plus sign in a circle"
+.C2 ca intersection "intersection, cap"
+.C2 cu union "union, cup"
+.C2 di divide "division sign"
+.C2 -h hbar
+.C2 gr gradient
+.C2 es emptyset
+.C2 CL club "club suit"
+.C2 SP spade "spade suit"
+.C2 HE heart "heart suit"
+.C2 DI diamond "diamond suit"
+.C2 CR carriagereturn "carriage return symbol"
+.C2 st suchthat
+.C2 /_ angle
+.C2 << "" "much less"
+.C2 >> "" "much greater"
+.C2 wp weierstrass "Weierstrass p"
+.C2 lz lozenge
+.C2 an arrowhorizex "horizontal arrow extension"
+.ch Fo
+.SH "SEE ALSO"
+.BR groff (@MAN1EXT@)
+.br
+.IR "An extension to the troff character set for Europe" ,
+E.G. Keizer, K.J. Simonsen, J. Akkerhuis,
+EUUG Newsletter, Volume 9, No. 2, Summer 1989
diff --git a/gnu/usr.bin/groff/man/groff_font.man b/gnu/usr.bin/groff/man/groff_font.man
new file mode 100644
index 0000000..a0b0cf4
--- /dev/null
+++ b/gnu/usr.bin/groff/man/groff_font.man
@@ -0,0 +1,351 @@
+.\" -*- nroff -*-
+.de TQ
+.br
+.ns
+.TP \\$1
+..
+.\" Like TP, but if specified indent is more than half
+.\" the current line-length - indent, use the default indent.
+.de Tp
+.ie \\n(.$=0:((0\\$1)*2u>(\\n(.lu-\\n(.iu)) .TP
+.el .TP "\\$1"
+..
+.TH GROFF_FONT @MAN5EXT@ "@MDATE@" "Groff Version @VERSION@"
+.SH NAME
+groff_font \- format of groff device and font description files
+.SH DESCRIPTION
+The groff font format is roughly a superset of the ditroff
+font format.
+Unlike the ditroff font format, there is no associated binary
+format.
+The font files for device
+.I name
+are stored in a directory
+.BI dev name.
+There are two types of file: a
+device description file called
+.B DESC
+and for each font
+.I F
+a font file called
+.IR F .
+These are text files;
+there is no associated binary format.
+.SS DESC file format
+The DESC file can contain the following types of line:
+.TP
+.BI res\ n
+There are
+.I n
+machine units per inch.
+.TP
+.BI hor\ n
+The horizontal resolution is
+.I n
+machine units.
+.TP
+.BI vert\ n
+The vertical resolution is
+.I n
+machine units.
+.TP
+.BI sizescale\ n
+The scale factor for pointsizes.
+By default this has a value of 1.
+One
+.I
+scaled point
+is equal to
+one
+.RI point/ n .
+The arguments to the
+.B unitwidth
+and
+.B sizes
+commands are given in scaled points.
+.TP
+.BI unitwidth\ n
+Quantities in the font files are given in machine units
+for fonts whose point size is
+.I n
+scaled points.
+.TP
+.B tcommand
+This means that the postprocessor can handle the
+.B t
+and
+.B u
+output commands.
+.TP
+.BI sizes\ s1\ s2\|.\|.\|.\|sn\ 0
+This means that the device has fonts at
+.IR s1 ,
+.IR s2 ,\|.\|.\|.\| sn
+scaled points.
+The list of sizes must be terminated by a
+.BR 0 .
+Each
+.BI s i
+can also be a range of sizes
+.IR m \- n .
+The list can extend over more than one line.
+.TP
+.BI styles\ S1\ S2\|.\|.\|.\|Sm
+The first
+.I m
+font positions will be associated with styles
+.IR S1\|.\|.\|.\|Sm .
+.TP
+.BI fonts\ n\ F1\ F2\ F3\|.\|.\|.\|Fn
+Fonts
+.I F1\|.\|.\|.\|Fn
+will be mounted in the font positions
+.IR m +1,\|.\|.\|., m + n
+where
+.I m
+is the number of styles.
+This command may extend over more than one line.
+A font name of
+.B 0
+will cause no font to be mounted on the corresponding font position.
+.TP
+.BI family\ fam
+The default font family is
+.IR fam .
+.TP
+.B charset
+This line and everything following in the file are ignored.
+It is allowed for the sake of backwards compatibility.
+.LP
+The res, unitwidth, fonts and sizes lines are compulsory.
+Other commands are ignored by
+.B troff
+but may be used by postprocessors to store arbitrary information
+about the device in the DESC file.
+.SS Font file format
+A font file has two sections. The first section is a sequence
+of lines each containing a sequence of blank delimited
+words; the first word in the line is a key, and subsequent
+words give a value for that key.
+.TP
+.BI name\ F
+The name of the font is
+.IR F .
+.TP
+.BI spacewidth\ n
+The normal width of a space is
+.IR n .
+.TP
+.BI slant\ n
+The characters of the font have a slant of
+.I n
+degrees. (Positive means forward.)
+.TP
+.BI ligatures\ lig1\ lig2\|.\|.\|.\|lign\ \fR[ 0 \fR]
+Characters
+.IR lig1 ,
+.IR lig2 ,\|.\|.\|., lign
+are ligatures; possible ligatures are
+.BR ff ,
+.BR fi ,
+.BR fl
+and
+.BR ffl .
+For backwards compatibility, the list of ligatures may be terminated
+with a
+.BR 0.
+The list of ligatures may not extend over more than one line.
+.TP
+.B special
+The font is
+.IR special ;
+this means that when a character is requested that is not present in
+the current font, it will be searched for in any special fonts that
+are mounted.
+.LP
+Other commands are ignored by
+.B troff
+but may be used by postprocessors to store arbitrary information
+about the font in the font file.
+.LP
+The first section can contain comments which start with the
+.B #
+character and extend to the end of a line.
+.LP
+The second section contains one or two subsections.
+It must contain a
+.I charset
+subsection
+and it may also contain a
+.I kernpairs
+subsection.
+These subsections can appear in any order.
+Each subsection starts with a word on a line by itself.
+.LP
+The word
+.B charset
+starts the charset subsection.
+The
+.B charset
+line is followed by a sequence of lines.
+Each line gives information for one character.
+A line comprises a number of fields separated
+by blanks or tabs. The format is
+.IP
+.I
+name metrics type code comment
+.LP
+.I name
+identifies the character:
+if
+.I name
+is a single character
+.I c
+then it corresponds to the groff input character
+.IR c ;
+if it is of the form
+.BI \e c
+where c is a single character, then it
+corresponds to the groff input character
+.BI \e c\fR;
+otherwise it corresponds to the groff input character
+.BI \e[ name ]
+(if it is exactly two characters
+.I xx
+it can be entered as
+.BI \e( xx\fR.)
+Groff supports eight bit characters; however some utilities
+has difficulties with eight bit characters.
+For this reason, there is a convention that the name
+.BI char n
+is equivalent to the single character whose code is
+.I n .
+For example,
+.B char163
+would be equivalent to the character with code 163
+which is the pounds sterling sign in ISO Latin-1.
+The name
+.B \-\-\-
+is special and indicates that the character is unnamed;
+such characters can only be used by means of the
+.B \eN
+escape sequence in
+.BR troff .
+.LP
+The
+.I type
+field gives the character type:
+.TP
+1
+means the character has an descender, for example, p;
+.TP
+2
+means the character has an ascender, for example, b;
+.TP
+3
+means the character has both an ascender and a descender, for example,
+(.
+.LP
+The
+.I code
+field gives the code which the postprocessor uses to print the character.
+The character can also be input to groff using this code by means of the
+.B \eN
+escape sequence.
+The code can be any integer.
+If it starts with a
+.B 0
+it will be interpreted as octal;
+if it starts with
+.B 0x
+or
+.B 0X
+it will be intepreted as hexadecimal.
+.LP
+Anything on the line after the code field will be ignored.
+.LP
+The
+.I metrics
+field has the form:
+.IP
+.IR width [\fB, height [\fB, depth [\fB, italic_correction [\fB, \
+left_italic_correction [\fB, subscript_correction ]]]]]
+.LP
+There must not be any spaces between these subfields.
+Missing subfields are assumed to be 0.
+The subfields are all decimal integers.
+Since there is no associated binary format, these
+values are not required to fit into a variable of type
+.B char
+as they are in ditroff.
+The
+.I width
+subfields gives the width of the character.
+The
+.I height
+subfield gives the height of the character (upwards is positive);
+if a character does not extend above the baseline, it should be
+given a zero height, rather than a negative height.
+The
+.I depth
+subfield gives the depth of the character, that is, the distance
+below the lowest point below the baseline to which the
+character extends (downwards is positive);
+if a character does not extend below above the baseline, it should be
+given a zero depth, rather than a negative depth.
+The
+.I italic_correction
+subfield gives the amount of space that should be added after the
+character when it is immediately to be followed by a character
+from a roman font.
+The
+.I left_italic_correction
+subfield gives the amount of space that should be added before the
+character when it is immediately to be preceded by a character
+from a roman font.
+The
+.I subscript_correction
+gives the amount of space that should be added after a character
+before adding a subscript.
+This should be less than the italic correction.
+.LP
+A line in the charset section can also have the format
+.IP
+.I
+name \fB"
+.LP
+This indicates that
+.I name
+is just another name for the character mentioned in the
+preceding line.
+.LP
+The word
+.B kernpairs
+starts the kernpairs section.
+This contains a sequence of lines of the form:
+.IP
+.I
+c1 c2 n
+.LP
+This means that when character
+.I c1
+appears next to character
+.I c2
+the space between them should be increased by
+.IR n .
+Most entries in kernpairs section will have a negative value for
+.IR n .
+.SH FILES
+.Tp \w'@FONTDIR@/devname/DESC'u+3n
+.BI @FONTDIR@/dev name /DESC
+Device description file for device
+.IR name .
+.TP
+.BI @FONTDIR@/dev name / F
+Font file for font
+.I F
+of device
+.IR name .
+.SH "SEE ALSO"
+.BR groff_out (@MAN5EXT@),
+.BR @g@troff (@MAN1EXT@).
diff --git a/gnu/usr.bin/groff/man/groff_out.man b/gnu/usr.bin/groff/man/groff_out.man
new file mode 100644
index 0000000..209ee3d
--- /dev/null
+++ b/gnu/usr.bin/groff/man/groff_out.man
@@ -0,0 +1,215 @@
+'\" e
+.\" -*- nroff -*-
+.\" This man page must be preprocessed with eqn.
+.ie \n(.g .ds ic \/
+.el .ds ic \^
+.TH GROFF_OUT @MAN5EXT@ "@MDATE@" "Groff Version @VERSION@"
+.SH NAME
+groff_out \- groff intermediate output format
+.SH DESCRIPTION
+This manual page describes the format output by GNU troff.
+The output format used by GNU troff is very similar to that used
+by Unix device-independent troff. Only the differences are documented
+here.
+.LP
+The argument to the
+.B s
+command is in scaled points (units of
+.IR points/ n ,
+where
+.I n
+is the argument to the
+.B sizescale
+command in the DESC file.)
+The argument to the
+.B x\ Height
+command is also in scaled points.
+.LP
+The first three output commands are guaranteed to be:
+.IP
+.BI x\ T\ device
+.br
+.BI x\ res\ n\ h\ v
+.br
+.B x init
+.LP
+If the
+.B tcommand
+line is present in the DESC file, troff will use the following
+two commands
+.TP
+.BI t xxx
+.I xxx
+is any sequence of characters terminated by a space or a newline;
+the first character should be printed at the current position,
+the the current horizontal position should be increased by
+the width of the first character, and so on for each character.
+The width of the character is that given in the font file,
+appropriately scaled for the current point size, and rounded
+so that it is a multiple of the horizontal resolution.
+Special characters cannot be printed using this command.
+.TP
+.BI u n\ xxx
+This is same as the
+.B t
+command except that after printing each character, the current horizontal
+position is increased by the sum of the width of that character
+and
+.IR n .
+.LP
+Note that single characters can have the eighth bit set, as can the
+names of fonts and special characters.
+.LP
+The names of characters and fonts an be of arbitrary length; drivers
+should not assume that they will be only two characters long.
+.LP
+When a character is to be printed, that character will always be
+in the current font.
+Unlike device-independent troff, it is not necessary
+for drivers to search special fonts to find a character.
+.LP
+The
+.B D
+drawing command has been extended.
+These extensions will not be used by GNU pic if the
+.B \-n
+option is given.
+.TP
+\fBDf \fIn\fR\*(ic\en
+Set the shade of gray to be used for filling solid objects to
+.IR n ;
+.I n
+must be an integer between 0 and 1000, where 0 corresponds solid white
+and 1000 to solid black, and values in between correspond to
+intermediate shades of gray.
+This applies only to solid circles, solid ellipses and solid
+polygons.
+By default, a level of 1000 will be used.
+Whatever color a solid object has, it should completely obscure
+everything beneath it.
+A value greater than 1000 or less than 0 can also be used:
+this means fill with the shade of gray that is currently being used
+for lines and text.
+Normally this will be black, but some drivers may provide
+a way of changing this.
+.TP
+\fBDC \fId\fR\*(ic\en
+Draw a solid circle with a diameter of
+.I d
+with the leftmost point at the current position.
+.TP
+\fBDE \fIdx dy\fR\*(ic\en
+Draw a solid ellipse with a horizontal diameter of
+.I dx
+and a vertical diameter of
+.I dy
+with the leftmost point at the current position.
+.EQ
+delim $$
+.EN
+.TP
+\fBDp\fR $dx sub 1$ $dy sub 1$ $dx sub 2$ $dy sub 2$ $...$ $dx sub n$ $dy sub n$\en
+Draw a polygon with,
+for $i = 1 ,..., n+1$, the
+.IR i -th
+vertex at the current position
+$+ sum from j=1 to i-1 ( dx sub j , dy sub j )$.
+At the moment,
+GNU pic only uses this command to generate triangles and rectangles.
+.TP
+\fBDP\fR $dx sub 1$ $dy sub 1$ $dx sub 2$ $dy sub 2$ $...$ $dx sub n$ $dy sub n$\en
+Like
+.B Dp
+but draw a solid rather than outlined polygon.
+.TP
+\fBDt \fIn\fR\*(ic\en
+Set the current line thickness to
+.I n
+machine units.
+Traditionally Unix troff drivers use a line thickness proportional to the current
+point size; drivers should continue to do this if no
+.B Dt
+command has been given, or if a
+.B Dt
+command has been given with a negative value of
+.IR n .
+A zero value of
+.I n
+selects the smallest available line thickness.
+.LP
+A difficulty arises in how the current position should be changed after
+the execution of these commands.
+This is not of great importance since the code generated by GNU pic
+does not depend on this.
+Given a drawing command of the form
+.IP
+\fB\eD\(fm\fIc\fR $x sub 1$ $y sub 1$ $x sub 2$ $y sub 2$ $...$ $x sub n$ $y sub n$\(fm
+.LP
+where
+.I c
+is not one of
+.BR c ,
+.BR e ,
+.BR l ,
+.B a
+or
+.BR ~ ,
+Unix troff will treat each of the $x sub i$ as a horizontal quantity,
+and each of the $y sub i$ as a vertical quantity and will assume that
+the width of the drawn object is $sum from i=1 to n x sub i$,
+and that the height is $sum from i=1 to n y sub i$.
+(The assumption about the height can be seen by examining the
+.B st
+and
+.B sb
+registers after using such a
+.B D
+command in a \ew escape sequence.)
+This rule also holds for all the original drawing commands
+with the exception of
+.BR De .
+For the sake of compatibility GNU troff also follows this rule,
+even though it produces an ugly result in the case of the
+.BR Df ,
+.BR Dt ,
+and, to a lesser extent,
+.B DE
+commands.
+Thus after executing a
+.B D
+command of the form
+.IP
+\fBD\fIc\fR $x sub 1$ $y sub 1$ $x sub 2$ $y sub 2$ $...$ $x sub n$ $y sub n$\en
+.LP
+the current position should be increased by
+$( sum from i=1 to n x sub i , sum from i=1 to n y sub i )$.
+.LP
+There is a continuation convention which permits the argument to the
+.B x\ X
+command to contain newlines:
+when outputting the argument to the
+.B x\ X
+command, GNU troff
+will follow each newline in the argument with a
+.B +
+character
+(as usual, it will terminate the entire argument with a newline);
+thus if the line after the line containing the
+.B x\ X
+command starts with
+.BR + ,
+then the newline ending the line containing the
+.B x\ X
+command should be treated as part of the argument to the
+.B x\ X
+command,
+the
+.B +
+should be ignored,
+and the part of the line following the
+.B +
+should be treated like the part of the line following the
+.B x\ X
+command.
+.SH "SEE ALSO"
+.BR groff_font (@MAN5EXT@)
diff --git a/gnu/usr.bin/groff/mdate.sh b/gnu/usr.bin/groff/mdate.sh
new file mode 100755
index 0000000..6bdac9d
--- /dev/null
+++ b/gnu/usr.bin/groff/mdate.sh
@@ -0,0 +1,41 @@
+#! /bin/sh
+
+# Print the modification date of $1 `nicely'.
+
+# Don't want foreign dates.
+
+LANGUAGE=
+
+
+(date;
+if ls -L /dev/null 1>/dev/null 2>&1; then ls -L -l $1; else ls -l $1; fi
+) | awk '
+BEGIN {
+ full["Jan"] = "January"; number["Jan"] = 1;
+ full["Feb"] = "February"; number["Feb"] = 2;
+ full["Mar"] = "March"; number["Mar"] = 3;
+ full["Apr"] = "April"; number["Apr"] = 4;
+ full["May"] = "May"; number["May"] = 5;
+ full["Jun"] = "June"; number["Jun"] = 6;
+ full["Jul"] = "July"; number["Jul"] = 7;
+ full["Aug"] = "August"; number["Aug"] = 8;
+ full["Sep"] = "September"; number["Sep"] = 9;
+ full["Oct"] = "October"; number["Oct"] = 10;
+ full["Nov"] = "November"; number["Nov"] = 11;
+ full["Dec"] = "December"; number["Dec"] = 12;
+}
+
+NR == 1 {
+ month = $2;
+ year = $NF;
+}
+
+NR == 2 {
+ if ($(NF-1) ~ /:/) {
+ if (number[$(NF-3)] > number[month])
+ year--;
+ }
+ else
+ year = $(NF-1);
+ print $(NF-2), full[$(NF-3)], year
+}'
diff --git a/gnu/usr.bin/groff/mm/ChangeLog b/gnu/usr.bin/groff/mm/ChangeLog
new file mode 100644
index 0000000..1eb5be4
--- /dev/null
+++ b/gnu/usr.bin/groff/mm/ChangeLog
@@ -0,0 +1,288 @@
+Tue Sep 7 08:37:00 1993 Jörgen Hägg (jh at efd.lth.se)
+
+ * version 1.19
+ * .lt is called in the header for .TP also.
+ * Variable Pgps added to control the header and footer point-size.
+ * Error-text printed with .APP removed.
+ * Error with .FG, .TB, .EC and .EX indentation fixed.
+ * header and footer line-length is not changed by MC or 2C.
+ * Default for page-length and page-offset is now taken from
+ \n[.p] and \n[.o].
+ * Argument to .ab (abort) is supplied.
+ * Argument to .1C added.
+ * Argument to .PGFORM added.
+ * RP/RS/RF totally rewritten. Should work with 2C now.
+
+Fri Apr 23 10:37:25 1993 Joergen Haegg (jh at efd.lth.se)
+
+ * version 1.18
+ * Height of display is now more exactly calculated.
+ * tabs and blankspaces where wrong in .VERBON.
+ * error in manual for escape-character in VERBON.
+ * Makefile.sub: installed tmac.m as tmac.m and tmac.mse
+ * Installation of tmac.mse now supports TMAC_M.
+ * bug with N fixed.
+
+Mon Apr 5 09:36:01 1993 Joergen Haegg (jh at efd.lth.se)
+
+ * version 1.17
+ * MULB preserves size.
+ * bug in VERBON fixed, causing strange errors.
+ * section-page footer fixed.
+ * added support for numberregister S
+ * fixed bug with floating displays wich made floats to
+ generate space on a page, but broke page anyway.
+ * end-of-page trap reinstalled.
+
+Mon Mar 29 10:53:13 1993 Joergen Haegg (jh at efd.lth.se)
+
+ * version 1.16
+ * MUL* now use the previous font and family.
+ * extra blank page at end-of-text eliminated.
+
+Mon Mar 8 10:27:47 1993 Joergen Haegg (jh at efd.lth.se)
+
+ * version 1.15
+ * Didn't restore pointsize to current size in .H.
+ * B1/B2 did not work with indent. (MULE and friends)
+ * fixed old problem with trailing empty pages.
+
+Fri Mar 5 15:20:49 1993 Joergen Haegg (jh at efd.lth.se)
+
+ * version 1.14
+ * Sigh. Amazing what a missing \} can do. If the string
+ HP was set, then all text disappeared...
+
+Fri Mar 5 14:12:43 1993 Joergen Haegg (jh at efd.lth.se)
+
+ * version 1.13
+ * Fixed bug with handling ps/vs in .H. (again, sigh... )
+
+Wed Mar 3 09:21:20 1993 Joergen Haegg (jh at efd.lth.se)
+
+ * version 1.12
+ * Line-break added to PGFORM.
+ * added more features to VERBON
+ * .S is not used anymore in H, it caused confusion with
+ normal text, but it will still set .vs.
+ * SK was broken, will now produce the requested number of
+ empty pages.
+ * dotted lines added to LIST OF FIGURES adn friends.
+ Also better linespacing.
+
+Mon Feb 22 12:41:06 1993 Joergen Haegg (jh at efd.lth.se)
+
+ * version 1.11
+ * missing left-parenthesis gave ") .sp" when N=4.
+ * N=4 removed user-specified header also.
+ * MOVE made linelength pageoffset wider than wanted.
+ * fixed (again) parenthesis in RP.
+
+Thu Jan 21 12:10:39 1993 Joergen Haegg (jh at efd.lth.se)
+
+ * version 1.10
+ * changed PROG_PREFIX to g in the manual-pages.
+ * Better check if new page is needed in .H, when Ej>0.
+ * Usage of variable Lsp now more complete.
+ * Space added in TOC when mark is equal to size.
+ * Usermacro HY moved after font-calulations.
+ * .S used instead of .ps, which will use .vs correct.
+ * Now possible to set Hps1/2 inside HX.
+ * .FD "" 1 is now fixed.
+ * section-page numbering bug fixed.
+ * several bugs in VERBON/OFF fixed.
+
+Tue Dec 8 16:43:15 1992 Joergen Haegg (jh at efd.lth.se)
+
+ * version 1.09
+ * N==4 gives no default header
+
+Sat Nov 21 14:28:20 1992 Joergen Haegg (jh at efd.lth.se)
+
+ * version 1.08
+ * Escape-character disabled between
+ VERBON/VERBOFF (turned on by an argument).
+ Pointsize and fontchange also added as arguments.
+ * MULB, MULN and MULE added to get multicolumn output
+ with different width.
+ * Number register N can now use 1-5.
+ * Register Sectp and Sectf added.
+ * Register P is now updated correctly for "section-page" numbering.
+
+Thu Nov 19 11:19:33 1992 Joergen Haegg (jh at efd.lth.se)
+
+ * version 1.07
+ * .OP fixed to eject a blank page if not odd.
+
+Fri Nov 13 09:46:09 1992 Joergen Haegg (jh at efd.lth.se)
+
+ * version 1.06
+ * Macro TL rewritten. TL depends now on a following .AU.
+ * NOTES updated.
+ * .lt is now used more frequent when linelength is changed.
+ * macro AST added.
+ * removed PH/EH/OH not needed in ?.MT.
+
+Wed Oct 28 14:35:43 1992 Joergen Haegg (jh at efd.lth.se)
+
+ * version 1.05
+ * .VM implemented.
+ * Possible bug in page heading fixed. Changed .sp to 'sp in HEADER.
+
+Thu Aug 20 13:56:31 1992 Joergen Haegg (jh at efd.lth.se)
+
+ * version 1.04
+ * page-break in .EQ moved.
+ * changed unit for footer-size and header-size from units to lines.
+ Fixes problems with .S and page-breaks.
+ * \n[%] is now treated as a string, wich makes it possible
+ to assign new formats to it. Unfortunately, it was necessary
+ to change the page-number-variable in GETPN to a string.
+ * Makefile.sub included. (Thank you, James)
+
+Thu May 7 16:14:10 1992 Joergen Haegg (jh at efd.lth.se)
+
+ * version 1.03
+ * Typo and centering in DS/DE fixed.
+ Even and odd pageheaders were reversed.
+ * LI: pad and mark-indent was lost in some earlier versions. Now fixed.
+ * fixed bug in reference to .FG, .TB, ...
+ * APP did not clear headercounters.
+ * Pointsize in titles is now only set at the beginning and
+ when PH, PF, OH, OF, EH and EF are used.
+
+Thu May 6 16:01:35 1992 Joergen Haegg (jh at efd.lth.se)
+
+ * version 1.02
+ * OP fixed.
+
+Fri Mar 6 09:36:09 1992 Joergen Haegg (jh at efd.lth.se)
+
+ * version 1.01
+ * two .LI without text between should not be printed
+ on the same row. Now fixed.
+ * figure titles and friends fixed, now possible with many .FG
+ in a DS/DE. Didn't always position correctly in previous version,
+ but is now always printed as it should.
+ * Makefile fixed for Ultrix.
+ * DS/DF could not handle empty arguments correct
+ * Missing .br i EQ added.
+
+Sat Jan 25 15:47:21 1992 Joergen Haegg (jh at efd.lth.se)
+
+ * version 1.00
+ * No betaversion anymore!
+ * Fixed headernumbers within appendixes.
+ * DS did not keep the same font as before DS.
+ * mmse did a line break.
+
+Fri Jan 24 14:38:16 1992 Joergen Haegg (jh at efd.lth.se)
+
+ * version 0.16
+ * bug in TC, multiple line headers did not wrap correctly.
+ * added support for mm/locale and mm/language_locale.
+ * cov*default-firm in locale sets name of firm in the MT covers.
+ * cov*location-xxxx in locale sets location xxxx to the contents
+ of cov*location-xxxx. Used in the MT covers.
+ * hanging indent in lists fixed.
+ * use larger empty lines if .nroff is defined.
+ * macros, like .P, can now be used inside abstracts.
+ * .S do not reset indentation anymore.
+ * .RS aA now sets a string, not an integer.
+ * appendix with .APP or .APPSK added.
+
+Thu Nov 28 22:00:59 1991 Joergen Haegg (jh at efd.lth.se)
+
+ * version 0.15
+ * Fixed .AU in MT 0-3, added support for variable Au.
+ * Bug in the positioning of the foot-notes.
+ * lists not indented properly.
+ * Hps1 and Hps2 added.
+ * COVER had to have an argument.
+ * table of contents can now have multiline header.
+ * .HU now increments headingvariable H?
+ * added the inclusion of a locale file.
+
+Sat Nov 23 14:40:17 1991 Joergen Haegg (jh at efd.lth.se)
+
+ * version 0.14
+ * bug when using -rO fixed.
+ * MT 1-4 added.
+ * default is now MT 1
+ * .EQ/.EN can be used outside of .DS/.DE without complaints. But
+ I don't recommend it. Neither does the DWB books.
+ * LI don't break lines now if arg too big.
+ * PGFORM did not reset indent.
+ * Added the numbervariable Hps.
+ * Rewritten and added MT 0-5 + "string".
+ * Added TM.
+ * Indent to AS added
+
+Wed Nov 6 15:18:40 1991 Joergen Haegg (jh at efd.lth.se)
+
+ * version 0.13
+ * ds*format nod defined if PS/PE is used without DS/DE.
+ * GETST added, fourth argument to EX, FG, TB and EC added.
+
+Mon Nov 4 13:38:01 1991 Joergen Haegg (jh at efd.lth.se)
+
+ * version 0.12
+ * Fixed C,D,P,+-size in .S
+
+Sun Jan 1 00:00:00 1991 Joergen Haegg (jh at efd.lth.se)
+ * Next version will have ChangeLog entries...
+ * Bug in INITR fixed.
+ * VERBON/VERBOFF added to include programlistings
+ * Bug in .DE fixed, addition overflow
+Sun Jan 1 00:00:00 1991 Joergen Haegg (jh at efd.lth.se)
+ * spelling error in month-names.
+ * WC should work now (no warranty :-)
+ * FD almost finished, some details missing.
+ * incorrect calculation of foot-notes fixed.
+ * DS/DE did not break page when the size was smaller than the paper
+ * Forward/backward referencesystem added. Se .INITR in README.
+ * mgmsw changed name to mgmse.
+Sun Jan 1 00:00:00 1991 Joergen Haegg (jh at efd.lth.se)
+ * embarrassing bug in .P fixed
+ * .H did always eject page, now fixed.
+ * lost floating displays now found.
+ * accents added (from mgs)
+ * empty line in .EQ/.EN removed
+ * indentation in .TC corrected.
+ * indentation of DS/DE in lists fixed.
+ * .TB and friends now work inside DS/DE and outside.
+ * .WC partially implemented (WF and WD). Still working on it.
+ * .mso used if version>=1.02
+Sun Jan 1 00:00:00 1991 Joergen Haegg (jh at efd.lth.se)
+ * register P was not working.
+ * support for register Fg, Tb, Ec and Ex.
+ * list items was left on the previous page at a page break.
+ * tlevel in .TC now defaults to 2.
+ * string DT, EM and Tm supported.
+ * new macro: PGNH, see comments.
+ * bug in MOVE fixed.
+ * pagenumber in .TC fixed.
+ * a blank page was ejected if Ej==1, now fixed
+ * bug in floating display fixed (did break and SP wrong)
+ * bug in .SP fixed, no lines is now printed at top of page
+ * There are still problems with footnotes and displays in two column mode.
+Sun Jan 1 00:00:00 1991 Joergen Haegg (jh at efd.lth.se)
+ * register P added (same as %)
+ * bug in floating displays fixed
+ * MOVE added
+ * MT added, see comment below
+ * COVER/COVEND added
+ * fixed bug in figure titles
+ * extended S, se comment below
+ * MT 0 added
+ * ms-cover added (COVER ms)
+Sun Jan 1 00:00:00 1991 Joergen Haegg (jh at efd.lth.se)
+ * bugs in RD and comb. fonts fixed
+Sun Jan 1 00:00:00 1991 Joergen Haegg (jh at efd.lth.se)
+ * HC added
+ * Combined fonts (IB,BI...)
+ * HM added
+ * RD added
+ * OP added
+ * TP&PX supported
+ * warnings for unimplemented macros
diff --git a/gnu/usr.bin/groff/mm/Makefile b/gnu/usr.bin/groff/mm/Makefile
new file mode 100644
index 0000000..9023bb8
--- /dev/null
+++ b/gnu/usr.bin/groff/mm/Makefile
@@ -0,0 +1,36 @@
+TMACOWN?= bin
+TMACGRP?= bin
+TMACMODE?= 444
+TMACDIR?= /usr/share/tmac
+
+FILES= 0.MT 5.MT 4.MT ms.cov se_ms.cov
+LOCALE= locale se_locale
+
+MAN7= groff_mm.7 groff_mmse.7
+MLINKS= groff_mm.7 mm.7 groff_mmse.7 mmse.7
+
+MANDEPEND= ${MAN7}
+CLEANFILES+= ${MANDEPEND}
+
+afterinstall:
+ ${INSTALL} -c -o $(TMACOWN) -g $(TMACGRP) -m $(TMACMODE) \
+ $(.CURDIR)/tmac.m $(DESTDIR)$(TMACDIR)/tmac.m
+ ${INSTALL} -c -o $(TMACOWN) -g $(TMACGRP) -m $(TMACMODE) \
+ $(.CURDIR)/tmac.m $(DESTDIR)$(TMACDIR)/tmac.mse
+
+ test -d $(DESTDIR)$(TMACDIR)/mm || mkdir $(DESTDIR)$(TMACDIR)/mm
+ chown $(TMACOWN).$(TMACGRP) $(DESTDIR)$(TMACDIR)/mm
+ chmod 755 $(DESTDIR)$(TMACDIR)/mm
+
+ for f in $(FILES); do \
+ $(INSTALL) -c -o $(TMACOWN) -g $(TMACGRP) -m $(TMACMODE) \
+ $(.CURDIR)/mm/$$f $(DESTDIR)$(TMACDIR)/mm/$$f; \
+ done
+ for f in $(LOCALE); do \
+ test -f $(DESTDIR)$(TMACDIR)/mm/$$f || touch $(DESTDIR)$(TMACDIR)/mm/$$f; \
+ chown $(TMACOWN).$(TMACGRP) $(DESTDIR)$(TMACDIR)/mm/$$f; \
+ chmod $(TMACMODE) $(DESTDIR)$(TMACDIR)/mm/$$f; \
+ done
+
+.include "../Makefile.cfg"
+.include <bsd.prog.mk>
diff --git a/gnu/usr.bin/groff/mm/Makefile.sub b/gnu/usr.bin/groff/mm/Makefile.sub
new file mode 100644
index 0000000..7ca7eed
--- /dev/null
+++ b/gnu/usr.bin/groff/mm/Makefile.sub
@@ -0,0 +1,35 @@
+#
+MAN7=groff_mm.n groff_mmse.n
+FILES=0.MT 5.MT 4.MT ms.cov se_ms.cov
+# Local configuration files with default values.
+LOCALE = locale se_locale
+CLEANADD=temp
+install: install_mm
+
+install_mm: install_m
+ -test -d $(tmacdir)/mm || mkdir $(tmacdir)/mm
+ -for f in $(FILES); do \
+ rm -f $(tmacdir)/mm/$$f; \
+ $(INSTALL_DATA) $(srcdir)/mm/$$f $(tmacdir)/mm/$$f; \
+ done
+ -for f in $(LOCALE); do \
+ test -f $(tmacdir)/mm/$$f || touch $(tmacdir)/mm/$$f; \
+ done
+
+install_m:
+ -test -d $(tmacdir) || mkdir $(tmacdir)
+ -rm -f $(tmacdir)/tmac.$(tmac_m)
+ $(INSTALL_DATA) $(srcdir)/tmac.m $(tmacdir)/tmac.$(tmac_m)
+ @sed -e "s;^.mso tmac.m;.mso $(tmac_m);g" $(srcdir)/tmac.mse \
+ > $(tmacdir)/tmac.$(tmac_m)se
+
+
+
+uninstall_sub:
+ -for f in $(FILES); do rm -f $(tmacdir)/mm/$$f; done
+ -for f in $(LOCALE); do \
+ test -s $(tmacdir)/mm/$$f || rm -f $(tmacdir)/mm/$$f; \
+ done
+ -rm -f $(tmacdir)/tmac.$(tmac_m)
+ -rm -f $(tmacdir)/tmac.$(tmac_m)se
+ -rmdir $(tmacdir)/mm
diff --git a/gnu/usr.bin/groff/mm/NOTES b/gnu/usr.bin/groff/mm/NOTES
new file mode 100644
index 0000000..ee258d3
--- /dev/null
+++ b/gnu/usr.bin/groff/mm/NOTES
@@ -0,0 +1,101 @@
+######################################################################
+
+Implementation notes. (Or how to make your own national mm)
+
+Different commands:
+
+COVER [arg]
+MT [arg [addressee]]
+The arg is part of a filename in mm/*.MT or mm/*.cov.
+This file is read when the macro is executed. Therefore it must be
+put before any text output.
+In each file there are definitions of all extra macros needed for the
+cover sheet. MT files is only for compatibility reasons, and has several
+limits due to that it don't know when the cover starts, and cannot
+change sizes. Use COVER for new coversheet macros.
+
+But with MT it is possible to write all of the AT&T covers.
+An example can be found in mm/0.MT.
+
+When writing a new cover using COVER, have in mind that the cover
+should print the page with the COVEND macro. This macro
+should be defined by the new macrofile.
+
+Here is a part of ms.cov:
+> .\"-----------------
+> .de COVEND
+> .sp |4.2c
+> .cov@print-title
+> .cov@print-authors
+> .cov@print-firm
+> .cov@print-abstract
+> .cov@print-date
+This is important, since COVER disables the page header.
+> .pg@enable-top-trap
+Should begin with page one (normally).
+> .bp 1
+And enable the trap at the page footer.
+> .pg@enable-trap
+> ..
+
+#########################
+
+Variables for covers:
+I = integer
+S = string
+D = diversion
+M = macro
+
+Name Type Desc.
+cov*au I The number of authors.
+
+cov*title M Title collected with .TL.
+
+cov*au!x!y S Author(s) given to .AU
+cov*at!x!y S Author(s) title given to .AT
+ x is the author-index [1-cov*au],
+ y is the argument-index [1-9].
+ Look at the table with indexes.
+
+cov*firm I Author(s) firm.
+
+cov*abs-arg I Argument to abstract.
+
+cov*abs-ind I Indent for abstract.
+
+cov*abs-name S The string 'ABSTRACT', changed with .AST
+
+cov*abstract M The abstract.
+
+cov*new-date S The date (todays date if ND is not used)
+
+cov*mt-type S MT type
+cov*mt-addresse S MT addressee
+
+
+##########################
+Argument-index for cov*au:
+
+Index Desc.
+1 name
+2 initials
+3 location
+4 department
+5 extension
+6 room
+7 arg 7
+8 arg 8
+9 arg 9
+
+The location is set to the contents of string cov*location-xxxx
+if location is equal to xxxx and cov*location-xxxx is defined
+in the file locale.
+
+
+Argument-index for cov*at:
+
+Index Desc.
+1 title 1
+. .
+. .
+9 title 9
diff --git a/gnu/usr.bin/groff/mm/README b/gnu/usr.bin/groff/mm/README
new file mode 100644
index 0000000..54b32d2
--- /dev/null
+++ b/gnu/usr.bin/groff/mm/README
@@ -0,0 +1,26 @@
+This is mgm, a macro package for groff.
+
+It is supposed to be compatible with the DWB mm macros,
+and has several extensions.
+
+Send bug reports to jh@efd.lth.se with a description of the problem
+and a sample of text which reproduces the error.
+
+Don't forget to mention the version of mgm (look in the beginning
+of tmac.m) and the version of groff.
+
+Any new ideas or improvements are welcome.
+
+Newest version is available with anonymous FTP
+at ftp.efd.lth.se [130.235.48.11], as pub/groff/mm<something>.Z
+
+You can install mgm as a separate package without the configure in groff
+with the following command:
+
+make -f Makefile.sim install
+
+This README should be bigger :-)
+
+Jörgen.
+
+Thanks to everyone who have send me bug-reports and fixes.
diff --git a/gnu/usr.bin/groff/mm/groff_mm.man b/gnu/usr.bin/groff/mm/groff_mm.man
new file mode 100644
index 0000000..0ef488b
--- /dev/null
+++ b/gnu/usr.bin/groff/mm/groff_mm.man
@@ -0,0 +1,763 @@
+.TH GROFF_MM @MAN7EXT@ "@MDATE@" "Groff Version @VERSION@"
+.SH NAME
+groff_mm \- groff mm macros
+.SH SYNOPSIS
+.B groff
+.B \-m@TMAC_M@
+[
+.IR options .\|.\|.
+]
+[
+.IR files .\|.\|.
+]
+.SH DESCRIPTION
+The groff mm macros are intended to be compatible with the DWB mm macros
+with the following limitations:
+.TP
+.B \(bu
+no letter macros implemented (yet).
+.TP
+.B \(bu
+no Bell Labs localisms implemented.
+.TP
+.B \(bu
+the macros OK and PM is not implemented.
+.TP
+.B \(bu
+groff mm does not support cut marks
+.LP
+\fBm@TMAC_M@\fP is intended to be international. Therefore it is
+possible to write short national macrofiles which change all
+english text to the preferred language. Use \fBm@TMAC_M@se\fP as an example.
+.LP
+Groff mm has several extensions:
+.TP
+.B "1C [1]"
+Begin one column processing. An \fB1\fP as argmunet disabled the page-break.
+.TP
+.B "APP name text"
+Begin an appendix with name \fIname\fP. Automatic naming occurs if
+\fIname\fP is "". The appendixes starts with \fBA\fP if auto is used.
+An new page is ejected, and a header is also produced if the number
+variable \fBAph\fP is non-zero. This is the default.
+The appendix always appear in the 'List of contents' with correct
+pagenumber. The name \fIAPPENDIX\fP can be changed by setting
+the string \fBApp\fP to the desired text.
+.TP
+.B "APPSK name pages text"
+Same as \fB.APP\fP, but the pagenr is incremented with \fIpages\fP.
+This is used when diagrams or other non-formatted documents are
+included as appendixes.
+.TP
+.B B1
+Begin box (as the ms macro)
+Draws a box around the text.
+.TP
+.B B2
+End box. Finish the box.
+.TP
+.B BVL
+Start of
+broken variable-item list.
+As VL but text begins always at the next line
+.TP
+.B "COVER [arg]"
+\&\fBCOVER\fP begins a coversheet definition. It is important
+that \fB.COVER\fP appears before any normal text.
+\&\fB.COVER\fP uses \fIarg\fP to build the filename
+@TMAC_MDIR@/\fIarg\fP.cov. Therefore it is possible to create unlimited
+types of coversheets.
+\fIms.cov\fP is supposed to look like the \fBms\fP coversheet.
+\&\fB.COVER\fP requires a \fB.COVEND\fP at the end of the coverdefinition.
+Always use this order of the covermacros:
+.nf
+\&.COVER
+\&.TL
+\&.AF
+\&.AU
+\&.AT
+\&.AS
+\&.AE
+\&.COVEND
+.fi
+However, only \fB.TL\fP and \fB.AU\fP are required.
+.TP
+.B COVEND
+This finish the cover description and prints the cover-page.
+It is defined in the cover file.
+.TP
+.B "GETHN refname [varname]"
+Includes the headernumber where the corresponding \fBSETR\fP \fIrefname\fP
+was placed. Will be X.X.X. in pass 1. See \fBINITR\fP.
+If varname is used, \fBGETHN\fP sets the stringvariable \fIvarname\fP to the
+headernumber.
+.TP
+.B "GETPN refname [varname]"
+Includes the pagenumber where the corresponding \fBSETR\fP \fIrefname\fP
+was placed. Will be 9999 in pass 1. See \fBINITR\fP.
+If varname is used, \fBGETPN\fP sets the stringvariable \fIvarname\fP
+to the pagenumber.
+.TP
+.B "GETR refname"
+Combines \fBGETHN\fP and \fBGETPN\fP with the text 'chapter' and ', page'.
+The string \fIQrf\fP contains the text for reference:
+.ti +.5i
+\&.ds Qrf See chapter \e\e*[Qrfh], page \e\e*[Qrfp].
+.br
+\fIQrf\fP may be changed to support other languages.
+Strings \fIQrfh\fP and \fIQrfp\fP are set by \fBGETR\fP
+and contains the page and headernumber.
+.TP
+.B "GETST refname [varname]"
+Includes the string saved with the second argument to \fB.SETR\fP.
+Will be dummystring in pass 1.
+If varname is used, \fBGETST\fP sets the stringvariable \fIvarname\fP to the
+saved string. See \fBINITR\fP.
+.TP
+.B "INITR filename"
+Initialize the refencemacros. References will be written to
+\fIfilename.tmp\fP and \fIfilename.qrf\fP. Requires two passes with groff.
+The first looks for references and the second includes them.
+\fBINITR\fP can be used several times, but it is only the first
+occurrence of \fBINITR\fP that is active.
+See also \fBSETR\fP, \fBGETPN\fP and \fBGETHN\fP.
+.TP
+.B "MC column-size [column-separation] "
+Begin multiple columns. Return to normal with 1C.
+.TP
+.B "MT [arg [addressee]]"
+Memorandum type.
+The \fIarg\fP is part of a filename in \fI@TMAC_MDIR@/*.MT\fP.
+Memorandum type 0 thru 5 are supported, including \fI"string"\fP.
+\fIAddresse\fP just sets a variable, used in the AT&T macros.
+.TP
+.B "MOVE y-pos [x-pos [line-length]]"
+Move to a position, pageoffset set to \fIx-pos\fP.
+If \fIline-length\fP is not given, the difference between
+current and new pageoffset is used.
+Use \fBPGFORM\fP without arguments to return to normal.
+.TP
+.B "MULB cw1 space1 [cw2 space2 [cw3 ...]]"
+Begin a special multi-column mode. Every columns width must be specified.
+Also the space between the columns must be specified. The last column
+does not need any space-definition. MULB starts a diversion and MULE
+ends the diversion and prints the columns.
+The unit for width and space is 'n', but MULB accepts all
+normal unitspecifications like 'c' and 'i'.
+MULB operates in a separate environment.
+.TP
+.B "MULN"
+Begin the next column. This is the only way to switch column.
+.TP
+.B "MULE"
+End the multi-column mode and print the columns.
+.TP
+.B "PGFORM [linelength [pagelength [pageoffset [1]]]]"
+Sets linelength, pagelength and/or pageoffset.
+This macro can be used for special formatting, like letterheads
+and other.
+\fBPGFORM\fP can be used without arguments
+to reset everything after a \fBMOVE\fP.
+A line-break is done unless the fourth argument is given.
+This can be used to avoid the pagenumber on the first page while setting
+new width and length.
+.TP
+.B PGNH
+No header is printed on the next page. Used to get rid off
+the header in letters or other special texts
+This macro must be used before any text to inhibit the pageheader
+on the first page.
+.TP
+.B "SETR refname [string]"
+Remember the current header and page-number as refname.
+Saves \fIstring\fP if \fIstring\fP is defined. \fIstring\fP is retrieved
+with \fB.GETST\fP.
+See \fBINITR\fP.
+.TP
+.B TAB
+reset tabs to every 5n. Normally used to reset any previous tabpositions.
+.TP
+.B VERBON [flag [pointsize [font]]]
+Begin verbatim output using courier font.
+Usually for printing programs.
+All character has equal width.
+The pointsize can be changed with
+the second argument. By specifying the font-argument
+it is possible to use another font instead of courier.
+\fIflag\fP control several special features.
+It contains the sum of all wanted features.
+.in +.5i
+.ti -.5i
+Value
+.sp -1
+Description
+.ti -.5i
+1
+.sp -1
+Disable the escape-character (\e). This is normally turned on during
+verbose output.
+.ti -.5i
+2
+.sp -1
+Add en empty line before the verbose text.
+.ti -.5i
+4
+.sp -1
+Add en empty line after the verbose text.
+.ti -.5i
+8
+.sp -1
+Print the verbose text with numbered lines. This adds four digitsized
+spaces in the beginning of each line. Finer control is available with
+the string-variable \fBVerbnm\fP. It contains all arguments to the
+\fBtroff\fP-command \fB.nm\fP, normally '1'.
+.ti -.5i
+16
+.sp -1
+Indent the verbose text with five 'n':s. This is controlled by the
+number-variable \fBVerbin\fP (in units).
+.in
+.TP
+.B VERBOFF
+End verbatim output.
+.sp
+.LP
+.\"########################################################################
+New variables in m@TMAC_M@:
+.TP
+.B App
+A string containing the word "APPENDIX".
+.TP
+.B Aph
+Print an appendix-page for every new appendix
+if this numbervariable is non-zero.
+No output will occur if \fBAph\fP is zero, but there will always
+be an appendix-entry in the 'List of contents'.
+.TP
+.B Hps
+Numbervariable with the heading pre-space level. If the heading-level
+is less than or equal to \fBHps\fP, then two lines will precede the
+section heading instead of one. Default is first level only.
+The real amount of lines is controlled by the variables \fBHps1\fP and
+\fBHps2\fP.
+.TP
+.B Hps1
+This is the number of lines preceding \fB.H\fP when the heading-level
+is greater than \fBHps\fP. Value is in units, normally 0.5v.
+.TP
+.B Hps2
+This is the number of lines preceding \fB.H\fP when the heading-level
+is less than or equal to \fBHps\fP. Value is in units, normally 1v.
+.TP
+.B Lifg
+String containing \fIFigure\fP.
+.TP
+.B Litb
+String containing \fITABLE\fP.
+.TP
+.B Liex
+String containing \fIExhibit\fP.
+.TP
+.B Liec
+String containing \fIEquation\fP.
+.TP
+.B Licon
+String containing \fICONTENTS\fP.
+.TP
+.B Lsp
+.TP
+The size of an empty line. Normally 0.5v, but it is 1v
+if \fBn\fP is set (\fB.nroff\fP).
+.B "MO1 - MO12"
+Strings containing \fIJanuary\fI to \fIDecember\fP.
+.TP
+.B Qrf
+String containing "See chapter \e\e*[Qrfh], page \e\en[Qrfp].".
+.TP
+.B Pgps
+Controls whether header and footer pointsize should follow the current
+setting or just change when the header and footer is defined.
+.in +.5i
+.ti -.5i
+Value
+.sp -1
+Description
+.ti -.5i
+0
+.sp -1
+Pointsize will only change to the current setting when \fB.PH\fP, \fB.PF\fP,
+\&\fB.OH\fP, \fP.EH\fP, \fB.OF\fP or \fB.OE\fP is executed.
+.ti -.5i
+1
+.sp -1
+Pointsize will change after every \fB.S\fP. This is the default.
+.ti -.5i
+.in
+.TP
+.B Sectf
+Flag controlling "section-figures". A non-zero value enables this.
+Se also register N.
+.TP
+.B Sectp
+Flag controlling "section-page-numbers". A non-zero value enables this.
+Se also register N.
+.TP
+.B .mgm
+Always 1.
+.\"########################################################################
+.LP
+A file called \fBlocale\fP or \fIlang\fP\fB_locale\fP is read
+after the initiation of the global variables. It is therefore
+possible to localize the macros with companyname and so on.
+.sp 3
+.LP
+The following standard macros are implemented:
+.TP
+.B 2C
+Begin two column processing
+.TP
+.B AE
+Abstract end
+.TP
+.B "AF [name of firm]"
+Authors firm
+.TP
+.B "AL [type [text-indent [1]]]]"
+Start autoincrement list
+.TP
+.B "AS [arg [indent]]"
+Abstract start. Indent is specified in 'ens', but scaling is allowed.
+.TP
+.B "AST [title]"
+Abstract title. Default is 'ABSTRACT'.
+.TP
+.B "AT title1 [title2 ...]"
+Authors title
+.TP
+.B "AU name [initials [loc [dept [ext [room [arg [arg [arg]]]]]]]]"
+Author information
+.TP
+.B "B [bold-text [prev-font-tex [...]]]"
+Begin boldface
+No limit on the number of arguments.
+.TP
+.B BE
+End bottom block
+.TP
+.B "BI [bold-text [italic-text [bold-text [...]]]"
+Bold-italic.
+No limit on the number of arguments.
+.TP
+.B "BL [text-indent [1]]"
+Start bullet list
+.TP
+.B "BR [bold-text [roman-text [bold-text [...]]]"
+Bold-roman.
+No limit on the number of arguments.
+.TP
+.B BS
+Bottom block start
+.TP
+.B DE
+Display end
+.TP
+.B "DF [format [fill [rindent]]]"
+Begin floating display (no nesting allowed)
+.TP
+.B "DL [text-indent [1]]"
+Dash list start
+.TP
+.B "DS [format [fill [rindent]]]"
+Static display start.
+Can now have unlimited nesting. Also
+right adjusted text and block may be used (R or RB as \fIformat\fP).
+.TP
+.B "EC [title [override [flag [refname]]]]"
+Equation title.
+If \fIrefname\fP is used, then the equationnumber is saved with
+\&\fB.SETR\fP, and can be retrieved with \fB.GETST\fP \fIrefname\fP.
+.TP
+.B "EF [arg]"
+Even-page footer.
+.TP
+.B "EH [arg]"
+Even-page header.
+.TP
+.B EN
+Equation end.
+.TP
+.B "EQ [label]"
+Equation start.
+.TP
+.B "EX [title [override [flag [refname]]]]"
+Exhibit title.
+If \fIrefname\fP is used, then the exhibitnumber is saved with
+\&\fB.SETR\fP, and can be retrieved with \fB.GETST\fP \fIrefname\fP.
+.TP
+.B "FD [arg [1]]"
+Footnote default format.
+.TP
+.B FE
+Footnote end.
+.TP
+.B "FG [title [override [flag [refname]]]]"
+Figure title.
+If \fIrefname\fP is used, then the figurenumber is saved with
+\&\fB.SETR\fP, and can be retrieved with \fB.GETST\fP \fIrefname\fP.
+.TP
+.B FS
+Footnote start.
+Footnotes in displays is now possible.
+.TP
+.B "H level [heading-text [heading-suffix]]"
+Numbered heading.
+.TP
+.B "HC [hyphenation-character]"
+Set hyphenation character.
+.TP
+.B "HM [arg1 [arg2 [... [arg7]]]]"
+Heading mark style.
+.TP
+.B "HU heading-text"
+Unnumbered header.
+.TP
+.B "HX dlevel rlevel heading-text"
+Userdefined heading exit.
+Called just before printing the header.
+.TP
+.B "HY dlevel rlevel heading-text"
+Userdefined heading exit.
+Called just before printing the header.
+.TP
+.B "HZ dlevel rlevel heading-text"
+Userdefined heading exit.
+Called just after printing the header.
+.TP
+.B "I [italic-text [prev-font-text [italic-text [...]]]"
+Italic.
+.TP
+.B "IB [italic-text [bold-text [italic-text [...]]]"
+Italic-bold
+.TP
+.B "IR [italic-text [roman-text [italic-text [...]]]"
+Italic-roman
+.TP
+.B "LB text-indent mark-indent pad type [mark [LI-space [LB-space]]]"
+List begin macro.
+.TP
+.B "LC [list level]"
+List-status clear
+.TP
+.B LE
+List end.
+.TP
+.B "LI [mark [1]]"
+List item
+.TP
+.B "ML mark [text-indent]"
+Marked list start
+.TP
+.B "MT [arg [addressee]]"
+Memorandum type. See above note about MT.
+.TP
+.B "ND new-date"
+New date.
+.TP
+.B "OF [arg]"
+Odd-page footer
+.TP
+.B "OH [arg]"
+Odd-page header
+.TP
+.B OP
+Skip to odd page.
+.TP
+.B "P [type]"
+Begin new paragraph.
+.TP
+.B PE
+Picture end.
+.TP
+.B "PF [arg]"
+Page footer
+.TP
+.B "PH [arg]"
+Page header
+.TP
+.B PS
+Picture start (from pic)
+.TP
+.B PX
+Page-header user-defined exit.
+.TP
+.B R
+Roman.
+.TP
+.B "RB [roman-text [bold-text [roman-text [...]]]"
+Roman-bold.
+.TP
+.B "RD [prompt [diversion [string]]]"
+Read to diversion and/or string.
+.TP
+.B RF
+Reference end
+.TP
+.B "RI [roman-text [italic-text [roman-text [...]]]"
+Roman-italic.
+.TP
+.B "RL [text-indent [1]]"
+Reference list start
+.TP
+.B "RP [arg [arg]]"
+Produce reference page.
+.TP
+.B "RS [string-name]"
+Reference start.
+.TP
+.B "S [size [spacing]]"
+Set point size and vertical spacing. If any argument is equal 'P', then
+the previous value is used. A 'C' means current value, and 'D' default value.
+If '+' or '-' is used before the value, then increment or decrement of
+the current value will be done.
+.TP
+.B "SA [arg]"
+Set adjustment.
+.TP
+.B "SK [pages]"
+Skip pages.
+.TP
+.B "SM string1 [string2 [string3]]"
+Make a string smaller.
+.TP
+.B "SP [lines]"
+Space vertically. \fIlines\fP can have any scalingfactor, like \fI3i\fP or
+\fI8v\fP.
+.TP
+.B "TB [title [override [flag [refname]]]]"
+Table title.
+If \fIrefname\fP is used, then the tablenumber is saved with
+\&\fB.SETR\fP, and can be retrieved with \fB.GETST\fP \fIrefname\fP.
+.TP
+.B "TC [slevel [spacing [tlevel [tab [h1 [h2 [h3 [h4 [h5]]]]]]]]]"
+Table of contents.
+All texts can be redefined, new stringvariables
+\fILifg\fP, \fILitb\fP, \fILiex\fP, \fILiec\fP and \fILicon\fP contains
+"Figure", "TABLE", "Exhibit", "Equation" and "CONTENTS".
+These can be redefined to other languages.
+.TP
+.B TE
+Table end.
+.TP
+.B "TH [N]"
+Table header.
+.TP
+.B TL
+Begin title of memorandum.
+.TP
+.B TM [num1 [num2 [...]]]
+Technical memorandumnumbers used in \fB.MT\fP. Unlimited number
+of arguments may be given.
+.TP
+.B TP
+Top of page user-defined macro.
+Note that header and footer is printed in a separate environment.
+Linelength is preserved though.
+.TP
+.B "TS [H]"
+Table start
+.TP
+.B TX
+Userdefined table of contents exit.
+.TP
+.B TY
+Userdefined tbale of contents exit (no "CONTENTS").
+.TP
+.B "VL [text-indent [mark-indent [1]]]"
+Variable-item list start
+.TP
+.B "VM [top [bottom]]"
+Vertical margin.
+.TP
+.B "WC [format]"
+Footnote and display width control.
+.sp 3
+.LP
+Strings used in m@TMAC_M@:
+.TP
+.B "EM"
+Em dash string
+.TP
+.B HF
+Fontlist for headings, normally "2 2 2 2 2 2 2".
+Nonnumeric fontnames may also be used.
+.TP
+.B HP
+Pointsize list for headings. Normally "0 0 0 0 0 0 0" which is the same as
+"10 10 10 10 10 10 10".
+.TP
+.B Lf
+Contains "LIST OF FIGURES".
+.TP
+.B Lt
+Contains "LIST OF TABLES".
+.TP
+.B Lx
+Contains "LIST OF EXHIBITS".
+.TP
+.B Le
+Contains "LIST OF EQUATIONS".
+.TP
+.B Rp
+Contains "REFERENCES".
+.TP
+.B Tm
+Contains \e(tm, trade mark.
+.\"-----------------------------------
+.LP
+Number variables used in m@TMAC_M@:
+.TP
+.B Cl=2
+Contents level [0:7], contents saved if heading level <= Cl
+.TP
+.B Cp=0
+Eject page between LIST OF XXXX if Cp == 0
+.TP
+.B D=0
+Debugflag, values >0 produces varying degree of debug. A value of 1
+gives information about the progress of formatting.
+.TP
+.B De=0
+Eject after floating display is output [0:1]
+.TP
+.B Df=5
+Floating keep output [0:5]
+.TP
+.B Ds=1
+space before and after display if == 1 [0:1]
+.TP
+.B Ej=0
+Eject page
+.TP
+.B Eq=0
+Equation lable adjust 0=left, 1=right
+.TP
+.B Fs=1
+Footnote spacing
+.TP
+.B "H1-H7"
+Heading counters
+.TP
+.B Hb=2
+Heading break level [0:7]
+.TP
+.B Hc=0
+Heading centering level, [0:7]
+.TP
+.B Hi=1
+Heading temporary indent [0:2]
+0 -> 0 indent, left margin
+.br
+1 -> indent to right , like .P 1
+.br
+2 -> indent to line up with text part of preceding heading
+.TP
+.B Hs=2
+Heading space level [0:7]
+.TP
+.B Ht=0
+Heading numbering type
+0 -> multiple (1.1.1 ...)
+.br
+1 -> single
+.TP
+.B Hu=2
+Unnumbered heading level
+.TP
+.B Hy=1
+Hyphenation in body
+0 -> no hyphenation
+.br
+1 -> hyphenation 14 on
+.TP
+.B "Lf=1, Lt=1, Lx=1, Le=0"
+Enables (1) or disables (0) the printing of List of figures,
+List of tables, List of exhibits and List of equations.
+.TP
+.B Li=6
+List indent, used by .AL
+.TP
+.B Ls=99
+List space, if current listlevel > Ls then no spacing will occur around lists.
+.TP
+.B N=0
+Numbering style [0:5]
+0 == (default) normal header for all pages.
+.br
+1 == header replaces footer on first page, header is empty.
+.br
+2 == page header is removed on the first page.
+.br
+3 == "section-page" numbering enabled.
+.br
+4 == page header is removed on the first page.
+.br
+5 == "section-page" and "section-figure" numbering enabled.
+Se also the number-register Sectf and Sectp.
+.TP
+.B Np=0
+Numbered paragraphs.
+.br
+0 == not numbered
+.br
+1 == numbered in first level headings.
+.TP
+.B Of=0
+Format of figure,table,exhibit,equation titles.
+.br
+0= ". "
+.br
+1= " - "
+.TP
+.B P
+Current page-number, normally the same as % unless "section-page" numbering
+is enabled.
+.TP
+.B Pi=5
+paragraph indent
+.TP
+.B Ps=1
+paragraph spacing
+.TP
+.B Pt=0
+Paragraph type.
+.br
+0 == left-justified
+.br
+1 == indented .P
+.br
+2 == indented .P except after .H, .DE or .LE.
+.TP
+.B Si=5
+Display indent.
+.LP
+.\".SH BUGS
+.SH AUTHOR
+Jörgen Hägg, Lund Institute of Technology, Sweden <jh@efd.lth.se>
+.SH FILES
+.TP
+.B @MACRODIR@/tmac.@TMAC_M@
+.TP
+.B @TMAC_MDIR@/*.cov
+.TP
+.B @TMAC_MDIR@/*.MT
+.TP
+.B @TMAC_MDIR@/locale
+.SH "SEE ALSO"
+.BR groff (@MAN1EXT@),
+.BR @g@troff (@MAN1EXT@),
+.BR @g@tbl (@MAN1EXT@),
+.BR @g@pic (@MAN1EXT@),
+.BR @g@eqn (@MAN1EXT@)
+.br
+.BR mm (@MAN7EXT@)
+.BR m@TMAC_M@se (@MAN7EXT@)
diff --git a/gnu/usr.bin/groff/mm/groff_mmse.man b/gnu/usr.bin/groff/mm/groff_mmse.man
new file mode 100644
index 0000000..5f79c01
--- /dev/null
+++ b/gnu/usr.bin/groff/mm/groff_mmse.man
@@ -0,0 +1,36 @@
+.\"
+.\" Skrivet av Jörgen Hägg, Lund, Sverige
+.\"
+.TH GROFF_MMSE @MAN7EXT@ "@MDATE@" "Groff Version @VERSION@"
+.SH NAMN
+groff_mmse \- svenska mm makro för groff
+.SH SYNTAX
+.B groff
+.B \-m@TMAC_M@se
+[
+.IR flaggor .\|.\|.
+]
+[
+.IR filer .\|.\|.
+]
+.SH BESKRIVNING
+\fBm@TMAC_M@se\fP är en svensk variant av \fBm@TMAC_M@\fP. Alla texter
+är översatta. En A4 sida får text som är 13 cm bred, 3.5 cm indragning
+samt är 28.5 cm hög.
+.LP
+\fBCOVER\fP kan använda \fIse_ms\fP som argument. Detta ger ett
+svenskt försättsblad.
+Se \fBgroff_mm(@MAN7EXT@)\fP för övriga detaljer.
+.SH "SKRIVET AV"
+Jörgen Hägg, Lunds Tekniska Högskola <jh@efd.lth.se>
+.SH FILER
+.B @MACRODIR@/tmac.@TMAC_M@se
+.B @TMAC_MDIR@/se_*.cov
+.SH "SE OCKSÅ"
+.BR groff (@MAN1EXT@),
+.BR @g@troff (@MAN1EXT@),
+.BR @g@tbl (@MAN1EXT@),
+.BR @g@pic (@MAN1EXT@),
+.BR @g@eqn (@MAN1EXT@)
+.br
+.BR m@TMAC_M@ (@MAN7EXT@)
diff --git a/gnu/usr.bin/groff/mm/mm/0.MT b/gnu/usr.bin/groff/mm/mm/0.MT
new file mode 100644
index 0000000..02a423e
--- /dev/null
+++ b/gnu/usr.bin/groff/mm/mm/0.MT
@@ -0,0 +1,145 @@
+.\"------------
+.\" Cover sheet. Memorandum type 0-3 and "string".
+.\"------------
+.if !r Au .nr Au 1
+.nr cov*mt0-ind 1.1c
+.de cov@print-title
+.MOVE 4.8c 1.5c
+.S 8
+subject:
+.sp -1.1
+.S
+.PGFORM
+.B
+.ll 9c
+.fi
+.cov*title
+.R
+.ll
+.nf
+.if d cov*title-charge-case \fBCharge Case \\*[cov*title-charge-case]\fP
+.if d cov*title-file-case \fBFile Case \\*[cov*title-file-case]\fP
+.fi
+..
+.\"------------
+.de cov@print-authors
+.MOVE 5.7c 13.3c
+.nf
+.S 8
+\\$1:
+.br
+.S
+.sp -1
+.in 0.8c
+.B
+.nr cov*i 0 1
+.while \\n+[cov*i]<=\\n[cov*au] \{\
+. cov@print-au1 \\n[cov*i] 1
+. if \\n[Au] \{\
+. cov@print-au2 \\n[cov*i] 3 4
+. cov@print-au2 \\n[cov*i] 6 5
+. cov@print-au1 \\n[cov*i] 7
+. cov@print-au1 \\n[cov*i] 8
+. cov@print-au1 \\n[cov*i] 9
+. \}
+. if \\n[cov*i]<\\n[cov*au] .SP 1
+.\}
+.R
+.if r cov*mt-tm-max \{\
+. SP 1
+. nr cov*i 0 1
+. B
+TM
+. in 1.5c
+. sp -1
+. while \\n+[cov*i]<\\n[cov*mt-tm-max] \\*[cov*mt-tm!\\n[cov*i]]
+. in
+. R
+.\}
+.fi
+.PGFORM
+..
+.\"------------
+.\" index arg1
+.de cov@print-au1
+.if d cov*au!\\$1!\\$2 \\*[cov*au!\\$1!\\$2]
+..
+.\"------------
+.de cov@print-au2
+.\" index arg1 arg2
+.if d cov*au!\\$1!\\$2 \\*[cov*au!\\$1!\\$2] \c
+.if \\$3=5 .if d cov*au!\\$1!\\$3 x\c
+.if d cov*au!\\$1!\\$3 \\*[cov*au!\\$1!\\$3]\c
+.br
+..
+.\"------------
+.de cov@print-date
+.MOVE 4.8c 13.3c
+.S 8
+.nf
+\\$1:
+.br
+.S
+.sp -1
+.in 0.8c
+.B "\\*[cov*new-date]"
+.br
+.fi
+.PGFORM
+..
+.\"------------
+.de cov@print-firm
+.if d cov*firm \{\
+. MOVE 2.8c 0 17.7c
+. S 18
+. rj 1
+\fB\\*[cov*firm]\fP
+. S
+. PGFORM
+.\}
+..
+.\"------------
+.de cov@print-abstract
+.SP 3
+.if d cov*abstract \{\
+. misc@ev-keep cov*ev
+. if \\n[cov*abs-ind]>0 \{\
+. in +\\n[cov*abs-ind]u
+. ll -\\n[cov*abs-ind]u
+. \}
+. ce
+\fI\\$1\fP
+. SP 1.5
+. fi
+. cov*abstract
+. br
+. ev
+.\}
+..
+.\"-----------------
+.ds cov*mt0-txt!1 MEMORANDUM FOR FILE
+.ds cov*mt0-txt!2 PROGRAMMER'S NOTES
+.ds cov*mt0-txt!3 ENGINEER'S NOTES
+.if d cov*default-firm .if !d cov*firm .ds cov*firm \\*[cov*default-firm]
+.\"
+.if !d cov*mt-printed \{\
+. cov@print-firm
+. cov@print-title subject
+. cov@print-date date
+. cov@print-authors from
+. cov@print-abstract \\*[cov*abs-name]
+. SP 3
+. if (\*[cov*mt-type]>=1)&(\*[cov*mt-type]<=3) \{\
+. ce
+\fI\*[cov*mt0-txt!\*[cov*mt-type]]\fP
+. SP 1.5
+. \}
+. if \*[cov*mt-type]=6 \{\
+. ce
+\fI\*[cov*mt-type-text]\fP
+. SP 1.5
+. \}
+. pg@enable-top-trap
+. pg@enable-trap
+. ds cov*mt-printed
+.\}
diff --git a/gnu/usr.bin/groff/mm/mm/4.MT b/gnu/usr.bin/groff/mm/mm/4.MT
new file mode 100644
index 0000000..e361132
--- /dev/null
+++ b/gnu/usr.bin/groff/mm/mm/4.MT
@@ -0,0 +1,65 @@
+.\"------------
+.\" Cover sheet. Memorandum type 4
+.\"------------
+.de cov@print-title
+.MOVE 2.4c
+.S 12
+.ad c
+.fi
+.B
+.cov*title
+.br
+.S
+.R
+.ad b
+.PGFORM
+..
+.\"------------
+.de cov@print-authors
+.SP 0.5
+.I
+.nr cov*i 0 1
+.while \\n+[cov*i]<=\\n[cov*au] \{\
+.ce
+\\*[cov*au!\\n[cov*i]!1]
+.br
+.\}
+.R
+.PGFORM
+..
+.\"------------
+.de cov@print-firm
+.SP 0.5
+.ce
+\\*[cov*firm]
+..
+.\"------------
+.de cov@print-abstract
+.SP 2
+.if d cov*abstract \{\
+. misc@ev-keep cov*ev
+. if \\n[cov*abs-ind]>0 \{\
+. in +\\n[cov*abs-ind]u
+. ll -\\n[cov*abs-ind]u
+. \}
+. ce
+\fI\\*[cov*abs-name]\fP
+. SP 2
+. fi
+. cov*abstract
+. br
+. ev
+.\}
+..
+.\"-----------------
+.if d cov*default-firm .if !d cov*firm .ds cov*firm \\*[cov*default-firm]
+.if !d cov*mt-printed \{\
+. cov@print-title
+. cov@print-authors
+. cov@print-firm
+. cov@print-abstract
+. SP 3
+. ds cov*mt-printed
+. pg@enable-top-trap
+. pg@enable-trap
+.\}
diff --git a/gnu/usr.bin/groff/mm/mm/5.MT b/gnu/usr.bin/groff/mm/mm/5.MT
new file mode 100644
index 0000000..654fc95
--- /dev/null
+++ b/gnu/usr.bin/groff/mm/mm/5.MT
@@ -0,0 +1,33 @@
+.\"------------
+.\" Cover sheet. Memorandum type 5
+.\"------------
+.nr cov*mt0-ind 1.1c
+.de cov@print-title
+.B
+.ll 9c
+.fi
+.cov*title
+.R
+.ll
+.nf
+.if d cov*title-charge-case \fBCharge Case \\*[cov*title-charge-case]\fP
+.if d cov*title-file-case \fBFile Case \\*[cov*title-file-case]\fP
+.fi
+..
+.\"------------
+.de cov@print-date
+.rj 1
+.B "\\*[cov*new-date]"
+.br
+..
+.\"------------
+.if !d cov*mt-printed \{\
+. SP 1.9c
+. cov@print-title
+. SP 1.2c
+. cov@print-date
+. SP 3
+. pg@enable-top-trap
+. pg@enable-trap
+. ds cov*mt-printed
+.\}
diff --git a/gnu/usr.bin/groff/mm/mm/ms.cov b/gnu/usr.bin/groff/mm/mm/ms.cov
new file mode 100644
index 0000000..1c66215
--- /dev/null
+++ b/gnu/usr.bin/groff/mm/mm/ms.cov
@@ -0,0 +1,83 @@
+.\"------------
+.\" Cover sheet. Mostly like ms cover.
+.\"------------
+.de cov@print-title
+.in 0
+.misc@ev-keep cov*ev
+.init@reset
+.ad c
+.hy 0
+.fi
+.B
+.cov*title
+.br
+.ad b
+.R
+.ev
+..
+.\"------------
+.de cov@print-authors
+.SP
+.nr cov*i 0 1
+.while \\n+[cov*i]<=\\n[cov*au] \{\
+. ce
+\fI\\*[cov*au!\\n[cov*i]!1]\fP
+. nr cov*j 0 1
+. while \\n+[cov*j]<=9 \{\
+. if d cov*at!\\n[cov*i]!\\n[cov*j] \{\
+. if \w'\\*[cov*at!\\n[cov*i]!\\n[cov*j]]' \{\
+. ce
+\s-1\\*[cov*at!\\n[cov*i]!\\n[cov*j]]\s0
+. .\}
+. \}
+. \}
+.\}
+..
+.\"------------
+.de cov@print-firm
+.SP .5
+.ce
+\\*[cov*firm]
+..
+.\"------------
+.de cov@print-abstract
+.SP 2
+.if d cov*abstract \{\
+. misc@ev-keep cov*ev
+. init@reset
+. if \\n[cov*abs-ind]>0 \{\
+. in +\\n[cov*abs-ind]u
+. ll -\\n[cov*abs-ind]u
+. \}
+. ce
+\fI\\$1\fP
+. SP 1.5
+. fi
+. cov*abstract
+. br
+. ev
+.\}
+..
+.\"------------
+.de cov@print-date
+.SP 2
+\\*[cov*new-date]
+..
+.\"-----------------
+.de COVEND
+.br
+.if d cov*default-firm .if !d cov*firm .ds cov*firm \\*[cov*default-firm]
+.sp |4.2c
+.cov@print-title
+.cov@print-authors
+.cov@print-firm
+.cov@print-abstract \\*[cov*abs-name]
+.cov@print-date
+.pg@enable-top-trap
+.bp 1
+.pg@enable-trap
+.if d cov*abs-arg .if \\n[cov*abs-arg] \{\
+. cov@print-abstract ABSTRACT
+. SP 2
+.\}
+..
diff --git a/gnu/usr.bin/groff/mm/mm/se_ms.cov b/gnu/usr.bin/groff/mm/mm/se_ms.cov
new file mode 100644
index 0000000..e6431f2
--- /dev/null
+++ b/gnu/usr.bin/groff/mm/mm/se_ms.cov
@@ -0,0 +1,2 @@
+.mso mm/ms.cov
+.nr cur*abstract-ll 11c
diff --git a/gnu/usr.bin/groff/mm/tmac.m b/gnu/usr.bin/groff/mm/tmac.m
new file mode 100644
index 0000000..8c86a60
--- /dev/null
+++ b/gnu/usr.bin/groff/mm/tmac.m
@@ -0,0 +1,2635 @@
+.\" Version:
+.ds RE 1.19
+.ig
+
+Copyright (C) 1991, 1992, 1993 Free Software Foundation, Inc.
+mgm is written by Jörgen Hägg (jh@efd.lth.se)
+
+mgm is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
+
+mgm is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License along
+with groff; see the file COPYING. If not, write to the Free Software
+Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+Almost complete. The letter format is not included.
+Maybe as a separate package.
+Should be better as time goes.
+
+Please send bugreports with examples to jh@efd.lth.se.
+
+Naming convention stolen from mgs.
+Local names module*name
+Extern names module@name
+Env.var environ:name
+Index array!index
+..
+.warn
+.\" ####### init ######
+.\" Contents level [0:7], contents saved if heading level <= Cl
+.nr Cl 2
+.\" Eject page between LIST OF XXXX if Cp == 0
+.nr Cp 0
+.\" Debugflag
+.if !r D .nr D 0
+.\" Eject after floating display is output [0:1]
+.nr De 0
+.\" Floating keep output [0;5]
+.nr Df 5
+.\" space before and after display if == 1 [0:1]
+.nr Ds 1
+.\" Eject page
+.nr Ej 0
+.\" Equation lable adjust 0=left, 1=right
+.nr Eq 0
+.\" Em dash string
+.ds EM \-
+.\" Footnote spacing
+.nr Fs 1
+.\" H1-H7 heading counters
+.nr H1 0 1
+.nr H2 0 1
+.nr H3 0 1
+.nr H4 0 1
+.nr H5 0 1
+.nr H6 0 1
+.nr H7 0 1
+.\" Heading break level [0:7]
+.nr Hb 2
+.\" heading centering level, [0:7]
+.nr Hc 0
+.\" header format
+.ds HF 2 2 2 2 2 2 2
+.\" heading temp. indent [0:2]
+.\" 0 -> 0 indent, left margin
+.\" 1 -> indent to right , like .P 1
+.\" 2 -> indent to line up with text part of preceding heading
+.nr Hi 1
+.\" header pointsize
+.ds HP 0 0 0 0 0 0 0
+.\" heading space level [0:7]
+.nr Hs 2
+.\" heading numbering type
+.\" 0 -> multiple (1.1.1 ...)
+.\" 1 -> single
+.nr Ht 0
+.\" Unnumbered heading level
+.nr Hu 2
+.\" hyphenation in body
+.\" 0 -> no hyphenation
+.\" 1 -> hyphenation 14 on
+.nr Hy 1
+.\" text for toc, selfexplanatory. Look in the new variable section
+.ds Lf LIST OF FIGURES
+.nr Lf 1
+.ds Lt LIST OF TABLES
+.nr Lt 1
+.ds Lx LIST OF EXHIBITS
+.nr Lx 1
+.ds Le LIST OF EQUATIONS
+.nr Le 0
+.\" List indent, used by .AL
+.nr Li 6
+.\" List space, if listlevel > Ls then no spacing will occur around lists.
+.nr Ls 99
+.\" Numbering style [0:5]
+.if !r N .nr N 0
+.\" numbered paragraphs
+.\" 0 == not numbered
+.\" 1 == numbered in first level headings.
+.nr Np 0
+.\" Format of figure,table,exhibit,equation titles.
+.\" 0= ". ", 1=" - "
+.nr Of 0
+.\" Page-number, normally same as %.
+.nr P 0
+.\" paragraph indent
+.nr Pi 5
+.\" paragraph spacing
+.nr Ps 1
+.\" paragraph type
+.\" 0 == left-justified
+.\" 1 == indented .P
+.\" 2 == indented .P except after .H, .DE or .LE.
+.nr Pt 0
+.\" Reference title
+.ds Rp REFERENCES
+.\" Display indent
+.nr Si 5
+.\"
+.ds Tm \(tm
+.\"
+.\"---------------------------------------------
+.\" Internal global variables
+.\"
+.\" These two are for cover macro .MT
+.\" Change @langage in the national file.
+.ds @cur-lib /usr/local/lib/groff/tmac
+.\" .ds @language
+.\"
+.\" Current pointsize and vertical space, always in points.
+.ie r S \{\
+. nr @ps \n[S]
+. nr @vs \n[S]+2
+.\}
+.el \{\
+. nr @ps 10
+. nr @vs 12
+.\}
+.\"
+.\" Page length
+.ie r L .nr @pl \n[L]
+.el .nr @pl \n[.p]
+.\" page width
+.ie r W .nr @ll \n[W]
+.el .nr @ll 6i
+.\" page offset
+.ie r O .nr @po \n[O]
+.el .nr @po \n(.o
+.\"
+.\" cheating...
+.pl \n[@pl]u
+.ll \n[@ll]u
+.lt \n[@ll]u
+.po \n[@po]u
+.nr @cur-ll \n[@ll]
+.\"
+.\" non-zero if escape mechanism is turned off. Used by VERBON/OFF
+.nr @verbose-flag 0
+.\"---------------------------------------------
+.\" New variables
+.\"
+.\" Appendix name
+.ds App APPENDIX
+.\" print appendixheader, 0 == don't
+.nr Aph 1
+.\"
+.\" header prespace level. If level <= Hps, then two lines will be printed
+.\" before the header instead of one.
+.nr Hps 1
+.\"
+.\" These variables controls the number of lines preceding .H.
+.\" Hps1 is the number of lines when level > Hps
+.nr Hps1 0.5v
+.if n .nr Hps1 1v
+.\"
+.\" Hps2 is the number of lines when level >= Hps
+.nr Hps2 1v
+.if n .nr Hps2 2v
+.\"
+.\" flag for mkindex
+.if !r Idxf .nr Idxf 0
+.\" Change these in the national configuration file
+.ds Lifg Figure
+.ds Litb TABLE
+.ds Liex Exhibit
+.ds Liec Equation
+.ds Licon CONTENTS
+.\"
+.\" Lsp controls the height of an empty line. Normally 0.5v
+.\" Normally used for nroff compatibility.
+.nr Lsp 0.5v
+.if n .nr Lsp 1v
+.ds MO1 January
+.ds MO2 February
+.ds MO3 March
+.ds MO4 April
+.ds MO5 May
+.ds MO6 June
+.ds MO7 July
+.ds MO8 August
+.ds MO9 September
+.ds MO10 October
+.ds MO11 November
+.ds MO12 December
+.\" for GETR
+.ds Qrf See chapter \\*[Qrfh], page \\*[Qrfp].
+.\"
+.\" header- and footer-size will only change to the current
+.\" if Pgps is > 0.
+.nr Pgps 1
+.\"
+.\" section-page if Sectp > 0
+.nr Sectp 0
+.if (\n[N]=3):(\n[N]=5) \{\
+. nr Sectp 1
+. nr Ej 1
+.\}
+.\" section-figure if Sectf > 0
+.nr Sectf 0
+.if \n[N]=5 .nr Sectf 1
+.\"
+.\" argument to .nm in .VERBON.
+.ds Verbnm "1
+.\" indent for VERBON
+.nr Verbin 5n
+.\"
+.\" test for mgm macro. This can be used if the text must test
+.\" what macros is used.
+.nr .mgm 1
+.\"
+.\"---------------------------------------------
+.\" set local variables.
+.ie d @language .mso mm/\\*[@language]_locale
+.el .mso mm/locale
+.\"---------------------------------------------
+.if \n[D] .tm Groff mm, version \*[RE].
+.\" ####### module init ######
+.\" reset all things
+.de init@reset
+.ie \\n[misc@adjust] 'ad
+.el 'na
+.ie \\n[Hy] 'hy 14
+.el 'nh
+'in 0
+'ti 0
+'ps \\n[@ps]
+'vs \\n[@vs]
+..
+.de @error
+.tm ******************
+.tm ERROR:(\\n[.F]) input line \\n[.c]:\\$*
+.if \\n[D] .backtrace
+.tm ******************
+.ab "Input aborted, syntax error"
+..
+.\" ####### module debug #################################
+.de debug
+.tm \\$1:\\n[.F]:\\n[c.] ll=\\n[.l] vs=\\n[.v] ps=\\n[.s],\\n[.ps] \
+in=\\n[.i] fi=\\n[.u] .d=\\n[.d] nl=\\n[nl] pg=\\n[%]
+..
+.de debug-all
+.nr debug*n 1n
+.nr debug*m 1m
+.tm \\$1:\\n[.F]:\\n[c.] ll=\\n[.l] vs=\\n[.v] ps=\\n[.s] in=\\n[.i]\
+ ad=\\n[.j] fi=\\n[.u] pl=\\n[.p] page=\\n[%] .o=\\n[.o]
+.tm _______ .d=\\n[.d] .f=\\n[.f] .h=\\n[.h] .k=\\n[.k] .n=\\n[.n]\
+ .p=\\n[.p] .t=\\n[.t] .z=\\n[.z] nl=\\n[nl] dn=\\n[dn] n=\\n[debug*n]
+..
+.\" ####### module par #################################
+.nr par@ind-flag 1 \" indent on following P if Pt=2
+.nr hd*last-pos -1
+.nr hd*last-hpos -1
+.nr par*number 0 1
+.af par*number 01
+.nr par*num-count 0 1
+.af par*num-count 01
+.\" reset numbered paragraphs, arg1 = headerlevel
+.de par@reset-num
+.if \\$1<3 .nr par*num-count 0
+.if (\\$1=1)&(\\n[Np]=1) .nr par*number 0
+..
+.\"------------
+.\" paragraph
+.de P
+.\" skip P if previous heading
+.ie !((\\n[nl]=\\n[hd*last-pos]):(\\n[nl]=(\\n[hd*last-pos]-.5v))) \{\
+. if \\n[D]>2 .tm Paragraph
+. par@doit \\$*
+.\}
+.el .if !(\\n[hd*last-hpos]=\\n[.k]) \{\
+. if \\n[D]>2 .tm Paragraph
+. par@doit \\$*
+.\}
+.nr par@ind-flag 1
+..
+.de par@doit
+.SP (u;\\n[Ps]*\\n[Lsp])
+.ie \\n[.$] \{\
+. if \\$1=1 .ti +\\n[Pi]n
+.\}
+.el \{\
+. if \\n[Pt]=1 .ti +\\n[Pi]n
+. if (\\n[Pt]=2)&\\n[par@ind-flag] .ti +\\n[Pi]n
+.\}
+.if \\n[Np] \{\
+\\n[H1].\\n+[par*number]\ \ \c
+.\" $$$ 'br
+.\}
+..
+.\" ####### module line #######################################
+.de SP
+.br
+.if !r line*lp\\n[.z] .nr line*lp\\n[.z] 0
+.if !r line*ac\\n[.z] .nr line*ac\\n[.z] 0
+.ie \\n[.$] .nr line*temp (v;\\$1)
+.el .nr line*temp 1v
+.\"
+.ie \\n[line*lp\\n[.z]]=\\n[.d] \{\
+. \" go here if no output since the last .SP
+. nr line*output \\n[line*temp]-\\n[line*ac\\n[.z]]
+. if \\n[line*output]<0 .nr line*output 0
+. nr line*ac\\n[.z] +\\n[line*output]
+.\}
+.el \{\
+. nr line*ac\\n[.z] \\n[line*temp]
+. nr line*output \\n[line*temp]
+. \" no extra space in the beginning of a page
+. if (\\n[.d]<0):(\\n[pg*head-mark]=\\n[.d]) .nr line*output 0
+.\}
+.if \\n[line*output] .sp \\n[line*output]u
+.nr line*lp\\n[.z] \\n[.d]
+..
+.\" ######## module misc ###############
+.nr misc@adjust 14
+.de SA
+.if \\n[.$] \{\
+. if \\$1-1 .@error "SA: bad arg: \\$1"
+. nr misc@adjust 0\\$1
+.\}
+.ie \\n[misc@adjust] 'ad
+.el 'na
+..
+.\"-------------
+.\" switch environment, keep all important settings.
+.de misc@ev-keep
+.nr misc*ll \\n[.l]
+.ev \\$1
+.ll \\n[misc*ll]u
+.lt \\n[misc*ll]u
+..
+.\"-------------
+.\" .misc@push stackname value
+.de misc@push
+.ie d misc*st-\\$1 .ds misc*st-\\$1 \\$2 \\*[misc*st-\\$1]
+.el .ds misc*st-\\$1 \\$2
+..
+.\"-------------
+.\" .misc@pop stackname
+.\" value returned in the string misc*pop
+.de misc@pop
+.misc@pop-set misc*st-\\$1 \\*[misc*st-\\$1]
+..
+.\"-------------
+.de misc@pop-set
+.ds misc*st-name \\$1
+.shift
+.if \\n[.$]<1 .@error "stack \\*[misc*st-name] empty"
+.ds misc*pop \\$1
+.shift
+.ds \\*[misc*st-name] \\$*
+..
+.\"-------------
+.\" .misc@pop-nr stackname varname
+.de misc@pop-nr
+.misc@pop \\$1
+.nr \\$2 \\*[misc*pop]
+..
+.\"-------------
+.\" .misc@pop-ds stackname varname
+.de misc@pop-ds
+.misc@pop \\$1
+.ds \\$2 \\*[misc*pop]
+..
+.\"-----------
+.\" reset tabs
+.de TAB
+.ta T 5n
+..
+.\"-------------
+.\" .PGFORM linelength [ pagelength [ pageoffset [1]]]
+.de PGFORM
+.\" Break here to avoid problems with new linesetting of the previous line.
+.\" Hope this doesn't break anything else :-)
+.\" Don't break if arg_4 is a '1'.
+.if ''\\$4' .br
+.if !''\\$1' .nr @ll \\$1
+.if !''\\$2' .nr @pl \\$2
+.if !''\\$3' .nr @po \\$3
+.ll \\n[@ll]u
+.lt \\n[@ll]u
+.po \\n[@po]u
+.pl \\n[@pl]u
+.nr @cur-ll \\n[@ll]
+'in 0
+.pg@move-trap
+..
+.\"-------------
+.\" .MOVE y [[x] linelength]
+.\" move to line y, indent to x
+.de MOVE
+.if !\\n[.$] .@error "MOVE y [x]: no arguments"
+.if \\n[nl]<0 \c
+.\" move to Y-pos
+.sp |(v;\\$1)
+.\" calc linelength
+.ie \\n[.$]>2 .nr pg*i (n;\\$3)
+.el \{\
+. ie \\n[.$]>1 .nr pg*i (n;\\n[@ll]u-\\$2)
+. el .nr pg*i \\n[@ll]u
+.\}
+.\" move to X-pos, if any
+.if !''\\$2' .po \\$2
+.\" set linelength
+.ll \\n[pg*i]u
+..
+.\"-------------
+.de SM
+.if !\\n[.$] .@error "SM: no arguments"
+.if \\n[.$]=1 \s-1\\$1\s0
+.if \\n[.$]=2 \s-1\\$1\s0\\$2
+.if \\n[.$]=3 \\$1\s-1\\$2\s0\\$3
+..
+.\"-------------
+.nr misc*S-ps \n[@ps]
+.nr misc*S-vs \n[@vs]
+.nr misc*S-ps1 \n[@ps]
+.nr misc*S-vs1 \n[@vs]
+.ds misc*a
+.ds misc*b
+.de S
+.ie !\\n[.$] \{\
+. ds misc*a P
+. ds misc*b P
+.\}
+.el \{\
+. ie \\n[.$]=1 .ds misc*b D
+. el \{\
+. ie \w@\\$2@=0 .ds misc*b C
+. el .ds misc*b \\$2
+. \}
+. ie \w@\\$1@=0 .ds misc*a C
+. el .ds misc*a \\$1
+.\}
+.\"
+.\" set point size
+.if !'\\*[misc*a]'C' \{\
+. ie '\\*[misc*a]'P' .nr @ps \\n[misc*S-ps]
+. el \{\
+. ie '\\*[misc*a]'D' .nr @ps 10
+. el .nr @ps \\*[misc*a]
+. \}
+.\}
+.\"
+.\" set vertical spacing
+.if !'\\*[misc*b]'C' \{\
+. ie '\\*[misc*b]'P' .nr @vs \\n[misc*S-vs]
+. el \{\
+. ie '\\*[misc*b]'D' .nr @vs \\n[@ps]+2
+. el .nr @vs \\*[misc*b]
+. \}
+.\}
+'ps \\n[@ps]
+'vs \\n[@vs]
+.if \\n[D]>1 .tm point-size \\n[@ps] (\\n[.s]), vertical spacing \\n[@vs] (\\n[.v])
+.nr misc*S-ps \\n[misc*S-ps1]
+.nr misc*S-vs \\n[misc*S-vs1]
+.nr misc*S-ps1 \\n[@ps]
+.nr misc*S-vs1 \\n[@vs]
+..
+.\"------------
+.de HC
+.ev 0
+.hc \\$1
+.ev
+.ev 1
+.hc \\$1
+.ev
+.ev 2
+.hc \\$1
+.ev
+..
+.\"------------
+.de RD
+.di misc*rd
+'fl
+.rd \\$1
+.br
+.di
+.ie !''\\$3' \{\
+. di misc*rd2
+. ds \\$3 "\\*[misc*rd]
+. br
+. di
+.\}
+.if !''\\$2' .rn misc*rd \\$2
+.rm misc*rd misc*rd2
+..
+.\"------------
+.\" VERBON [flag [pointsize [font]]]
+.\" flag
+.\" bit function
+.\" 0 escape on
+.\" 1 add an empty line before verbose text
+.\" 2 add an empty line after verbose text
+.\" 3 numbered lines (controlled by the string Verbnm)
+.\" 4 indent text by the numbervariable Verbin.
+.de VERBON
+.br
+.nr misc*verb 0\\$1
+.if (0\\n[misc*verb]%4)/2 .SP \\n[Lsp]u
+.misc@ev-keep misc*verb-ev
+.nf
+.if (0\\n[misc*verb]%16)/8 .nm \\*[Verbnm]
+.ie !'\\$3'' .ft \\$3
+.el .ft CR
+.ie 0\\$2 \{\
+. ss \\$2
+. ps \\$2
+. vs \\$2
+.\}
+.el .ss 12
+.ta T 8u*\w@n@u
+.if (0\\n[misc*verb]%32)/16 .in +\\n[Verbin]u
+.if 0\\n[misc*verb]%2 \{\
+. eo
+. nr @verbose-flag 1 \" tell pageheader to set ec/eo
+.\}
+..
+.de VERBOFF
+.ec
+.br
+.if (0\\n[misc*verb]%8)/4 .SP \\n[Lsp]u
+.if (0\\n[misc*verb]%16)/8 .nm
+.if (0\\n[misc*verb]%32)/16 .in
+.ev
+.nr @verbose-flag 0
+..
+.\" ######## module acc #################
+.\"-----------
+.\" accents. These are copied from mgs, written by James Clark.
+.de acc@over-def
+.ds \\$1 \Z'\v'(u;\w'x'*0+\En[rst]-\En[.cht])'\
+\h'(u;-\En[skw]+(-\En[.w]-\w'\\$2'/2)+\En[.csk])'\\$2'
+..
+.de acc@under-def
+.ds \\$1 \Z'\v'\En[.cdp]u'\h'(u;-\En[.w]-\w'\\$2'/2)'\\$2'
+..
+.acc@over-def ` \`
+.acc@over-def ' \'
+.acc@over-def ^ ^
+.acc@over-def ~ ~
+.acc@over-def : \(ad
+.acc@over-def ; \(ad
+.acc@under-def , \(ac
+.\" ######## module uni #################
+.\" unimplemented macros
+.de OK
+.tm "OK: not implemented"
+..
+.de PM
+.tm "PM: not implemented"
+..
+.\" ######## module hd #################
+.\" support for usermacro
+.nr hd*h1-page 1 \" last page-number for level 1 header.
+.nr hd*htype 0
+.ds hd*sect-pg
+.ds hd*mark
+.ds hd*suf-space
+.nr hd*need 0
+.aln ;0 hd*htype
+.als }0 hd*mark
+.als }2 hd*suf-space
+.aln ;3 hd*need
+.\"-------------
+.\" .hd@split varable index name val1 val2 ...
+.de hd@split
+.if \\$2>(\\n[.$]-3) .@error "\\$3 must have at least \\$2 values (\\*[\\$3]).
+.nr hd*sp-tmp \\$2+3
+.ds \\$1 \\$[\\n[hd*sp-tmp]]
+..
+.de HU
+.H 0 "\\$1"
+..
+.\"-------------
+.de H
+.if !r hd*cur-bline .nr hd*cur-bline \\n[nl]
+.br
+.ds@print-float 2\" $$$ could be wrong...
+.\" terminate all lists
+.LC 0
+.init@reset
+.nr hd*level 0\\$1
+.nr hd*arg1 0\\$1
+.if !\\n[hd*level] .nr hd*level \\n[Hu]
+.\"
+.\" clear lower counters
+.nr hd*i 1 1
+.while \\n+[hd*i]<8 .if \\n[hd*level]<\\n[hd*i] .nr H\\n[hd*i] 0 1
+.\"
+.\" Check if it's time for new page. Only if text has
+.\" appeared before.
+.if \\n[Ej]&(\\n[Ej]>=\\n[hd*level])&(\\n[nl]>\\n[hd*cur-bline]) .pg@next-page
+.\"
+.\" increment current counter
+.nr H\\n[hd*level] +1
+.\"
+.\" update pagenumber if section-page is used
+.if \\n[hd*level]=1 .hd@set-page \\n[%]
+.\"
+.\"
+.\" hd*mark is the text written to the left of the header.
+.ds hd*mark \\n[H1].
+.\"
+.if \\n[hd*level]>1 .as hd*mark \\n[H2]
+.\"
+.nr hd*i 2 1
+.while \\n+[hd*i]<8 .if \\n[hd*level]>(\\n[hd*i]-1) .as hd*mark .\\n[H\\n[hd*i]]
+.if \\n[Ht] .ds hd*mark \\n[H\\n[hd*level]].
+.\"
+.\" toc-mark is sent to the table of contents
+.ds hd*toc-mark \\*[hd*mark]
+.as hd*mark \ \ \" add spaces between mark and heading
+.if !\\n[hd*arg1] \{\
+. ds hd*mark\" no mark for unnumbered
+. ds hd*toc-mark
+.\}
+.\"
+.if \\n[D]>1 .tm At header \\*[hd*toc-mark] "\\$2"
+.nr hd*htype 0 \" hd*htype = check break and space
+. \" 0 = run-in, 1 = break only, 2 = space
+.if \\n[hd*level]<=\\n[Hb] .nr hd*htype 1
+.if \\n[hd*level]<=\\n[Hs] .nr hd*htype 2
+. \" two spaces if hd*htype == 0
+.ie (\\n[hd*htype]=0)&(\w@\\$2@) .ds hd*suf-space " \"
+.el .ds hd*suf-space
+.nr hd*need 2v \" hd*need = header need space
+.if \\n[hd*htype]<2 .nr hd*need +\\n[Lsp]u \" add some extra space
+.\"---------- user macro HX ------------
+.\" User exit macro to override numbering.
+.\" May change hd*mark (}0), hd*suf-space (}2) and hd*need (;3)
+.\" Can also change Hps1/2.
+.if d HX .HX \\n[hd*level] \\n[hd*arg1] "\\$2\\$3"
+.\"--------------------------------------
+.\" pre-space
+.ie \\n[hd*level]<=\\n[Hps] .SP \\n[Hps2]u
+.el .SP \\n[Hps1]u
+.\"
+.par@reset-num \\n[hd*level]\" reset numbered paragraph
+.\" start diversion to measure size of header
+.di hd*div
+\\*[hd*mark]\\$2\\$3\\*[hd*suf-space]
+.br
+.di
+.rm hd*div
+.ne \\n[hd*need]u+\\n[dn]u+.5p \" this is the needed space for a header
+.if \\n[hd*htype] .na \" no adjust if run-in
+.\"
+.\" size and font calculations
+.hd@split hd*font \\n[hd*level] HF \\*[HF]\" get font for this level
+.ft \\*[hd*font]\" set new font
+.hd@split hd*new-ps \\n[hd*level] HP \\*[HP]\" get point size
+.ie (\\*[hd*new-ps]=0):(\w@\\*[hd*new-ps]@=0) \{\
+. if \\n[hd*htype] \{\
+. if '\\*[hd*font]'3' \{\
+. ps -1
+. vs -1
+. \}
+. if '\\*[hd*font]'B' \{\
+. ps -1
+. vs -1
+. \}
+. \}
+.\}
+.el \{\
+. ps \\*[hd*new-ps]
+. vs \\*[hd*new-ps]+2
+.\}
+.\"
+.\"---------- user macro HY -------------
+.\" user macro to reset indents
+.if d HY .HY \\n[hd*level] \\n[hd*arg1] "\\$2\\$3"
+.\"--------------------------------------
+.nr hd*mark-size \w@\\*[hd*mark]@
+.if (\\n[hd*level]<=\\n[Hc])&\\n[hd*htype] .ce\" center if level<=Hc
+.\"
+.\" finally, output the header
+\\*[hd*mark]\&\c
+.\" and the rest of the header
+.ie \\n[hd*htype] \{\
+\\$2\\$3
+. br
+.\}
+.el \\$2\\$3\\*[hd*suf-space]\&\c
+.ft 1
+.\" restore pointsize and vertical size.
+.ps \\n[@ps]
+.vs \\n[@vs]
+.\"
+.\" table of contents
+.if (\\n[hd*level]<=\\n[Cl])&\w@\\$2@ \{\
+. ie \\n[Sectp] \{\
+. toc@save \\n[hd*level] "\\*[hd*toc-mark]" "\\$2" \\*[hd*sect-pg]
+. \}
+. el .toc@save \\n[hd*level] "\\*[hd*toc-mark]" "\\$2" \\n[%]
+.\}
+.\" set adjust to previous value
+.SA
+.\" do break or space
+.if \\n[hd*htype] .br
+.if \\n[hd*htype]>1 .SP \\n[Lsp]u
+.if \\n[hd*htype] \{\
+. \" indent if Hi=1 and Pt=1
+. if (\\n[Hi]=1)&(\\n[Pt]=1) .ti +\\n[Pi]n
+. \" indent size of mark if Hi=2
+. if \\n[hd*htype]&(\\n[Hi]>1) .ti +\\n[hd*mark-size]u
+.\}
+.nr par@ind-flag 0 \" no indent on .P if Pt=2
+.\"
+.\" check if it is time to reset footnotes
+.if (\\n[hd*level]=1)&\\n[ft*clear-at-header] .nr ft*nr 0 1
+.\"
+.\" check if it is time to reset indexes
+.if (\\n[hd*level]=1)&\\n[Sectf] \{\
+. nr lix*fg-nr 0 1
+. nr lix*tb-nr 0 1
+. nr lix*ec-nr 0 1
+. nr lix*ex-nr 0 1
+.\}
+.\"---------- user macro HZ ----------
+.if d HZ .HZ \\n[hd*level] \\n[hd*arg1] "\\$2\\$3"
+.nr hd*last-pos \\n[nl]
+.nr hd*last-hpos \\n[.k]
+.nr par@ind-flag 0
+..
+.\"--------
+.de HM
+.nr hd*i 0 1
+.while \\n+[hd*i]<8 .af H\\n[hd*i] \\$[\\n[hd*i]] 1
+..
+.\"----------------------
+.\" set page-nr, called from header
+.\"
+.de hd@set-page
+.if \\n[.$]>0 .nr hd*h1-page \\$1
+.\"
+.ie \\n[Sectp] .nr P \\n[%]-\\n[hd*h1-page]+1
+.el .nr P \\n[%]
+.\"
+.\" Set section-page-string
+.ds hd*sect-pg \\n[H1]-\\n[P]
+.if \\n[Sectp]>1 .if '\\n[H1]'0' .ds hd*sect-pg "
+..
+.\"########### module pg ####################
+.\" set end of text trap
+.wh 0 pg@header
+.em pg@end-of-text
+.\"
+.ds pg*header ''- % -''
+.ds pg*footer
+.if \n[N]=4 .ds pg*header ''''
+.if \n[N]=5 \{\
+. ds pg*header ''''
+. ds pg*footer ''\\*[hd*sect-pg]''
+.\}
+.ds pg*even-footer
+.ds pg*odd-footer
+.ds pg*even-header
+.ds pg*odd-header
+.\"
+.nr pg*top-margin 0
+.nr pg*foot-margin 0
+.nr pg*block-size 0
+.nr pg*footer-size 5\" 1v+footer+even/odd footer+2v
+.nr pg*header-size 7\" 3v+header+even/odd header+2v
+.nr pg*extra-footer-size 0
+.nr pg*extra-header-size 0
+.nr ft*note-size 0
+.nr pg*cur-column 0
+.nr pg*cols-per-page 1
+.nr pg*cur-po \n[@po]
+.nr pg*head-mark 0
+.\"
+.nr pg*ps \n[@ps]
+.nr pg*vs \n[@vs]
+.\"-------------------------
+.\" footer traps: set, enable and disable
+.de pg@set-new-trap
+.nr pg*foot-trap \\n[@pl]u-(\\n[pg*block-size]u+\\n[ft*note-size]u+\\n[pg*foot-margin]u+\\n[pg*footer-size]v+\\n[pg*extra-footer-size]u)
+.if \\n[D]>2 .tm pg*foot-trap \\n[@pl]u-(\\n[pg*block-size]u+\\n[ft*note-size]u+\\n[pg*foot-margin]u+\\n[pg*footer-size]v) = \\n[pg*foot-trap]
+.\" last-pos points to the position of the footer and bottom
+.\" block below foot-notes.
+.nr pg*last-pos \\n[@pl]u-(\\n[pg*block-size]u+\\n[pg*foot-margin]u+\\n[pg*footer-size]v)
+..
+.de pg@enable-trap
+.wh \\n[pg*foot-trap]u pg@footer
+.if \\n[D]>2 .tm pg@enable-trap .t=\\n[.t] nl=\\n[nl]
+..
+.de pg@disable-trap
+.ch pg@footer
+..
+.\" move to new trap (if changed).
+.de pg@move-trap
+.pg@disable-trap
+.pg@set-new-trap
+.pg@enable-trap
+..
+.de pg@enable-top-trap
+.\" set trap for pageheader.
+.nr pg*top-enabled 1
+..
+.de pg@disable-top-trap
+.\" remove trap for pageheader.
+.nr pg*top-enabled 0
+..
+.\" no header on the next page
+.de PGNH
+.nr pg*top-enabled -1
+..
+.\" set first trap for pagefooter
+.pg@enable-top-trap
+.pg@set-new-trap
+.pg@enable-trap
+.\"-------------------------
+.\" stop output and begin on next page. Fix footnotes and all that.
+.de pg@next-page
+.\".debug next-page
+.ne 999i \" activate trap
+.\" .pg@footer
+..
+.\"-------------------------
+.\" support for PX and TP
+.als }t pg*header
+.als }e pg*even-header
+.als }o pg*odd-header
+.\"------------------------------------------------------------
+.\" HEADER
+.de pg@header
+.if \\n[D]>1 .tm Page# \\n[%] (\\n[.F]:\\n[c.])
+.if \\n[Idxf] \{\
+.tl '<pagenr\ \\n[%]>'''
+.\}
+.\" assign current page-number to P
+.hd@set-page
+.\"
+.\" suppress pageheader if pagenumber == 1 and N == [124]
+.if \\n[pg*top-enabled] \{\
+. if \\n[pg*extra-header-size] 'sp \\n[pg*extra-header-size]u
+. if \\n[pg*top-margin] 'sp \\n[pg*top-margin]u
+. ev pg*tl-ev
+. pg@set-env
+. ie !d TP \{\
+' sp 3
+. ie ((\\n[%]=1)&((\\n[N]=1):(\\n[N]=2))) .sp
+. el .tl \\*[pg*header]
+. ie o .tl \\*[pg*odd-header]
+. el .tl \\*[pg*even-header]
+' sp 2
+. \}
+. el .TP
+. ev
+. \" why no-space??
+. if d PX \{\
+. ns
+. PX
+. rs
+. \}
+. \" check for pending footnotes
+. ft@check-old
+. \"
+. \" back to normal text processing
+. pg@enable-trap
+. \" mark for multicolumn
+. nr pg*head-mark \\n[nl]u
+. \" set multicolumn
+. \"
+. pg@set-po
+. \" print floating displays
+. ds@print-float 4
+. tbl@top-hook
+. ns
+.\}
+.if \\n[pg*top-enabled]<0 .nr pg*top-enabled 1
+.nr hd*cur-bline \\n[nl] \" .H needs to know if output has occured
+..
+.\"---------------------------------------------------------
+.\" FOOTER
+.de pg@footer
+.ec
+.if \\n[D]>2 .tm Footer# \\n[%] (\\n[.F]:\\n[c.])
+.pg@disable-trap
+.\".debug footer
+.tbl@bottom-hook
+.\" increment pageoffset for MC
+.\" move to the exact start of footer.
+'sp |\\n[pg*foot-trap]u+1v
+.\"
+.if \\n[D]>3 .tm FOOTER after .sp
+.\" print footnotes
+.if d ft*div .ft@print
+.\"
+.pg@inc-po
+.if !\\n[pg*cur-column] .pg@print-footer
+.\" next column
+.pg@set-po
+.pg@enable-trap
+.if \\n[@verbose-flag] .eo \" to help VERBON/VERBOFF
+..
+.\"-------------------------
+.de pg@print-footer
+.\" jump to the position just below the foot-notes.
+'sp |\\n[pg*last-pos]u+1v
+.\" check if there are any bottom block
+.if d pg*block-div .pg@block
+.\"
+.\" print the footer and eject new page
+.ev pg*tl-ev
+.pg@set-env
+.ie o .tl \\*[pg*odd-footer]
+.el .tl \\*[pg*even-footer]
+.ie (\\n[%]=1)&(\\n[N]=1) .tl \\*[pg*header]
+.el .tl \\*[pg*footer]
+.ev
+.ie (\\n[ds*fnr]>=\\n[ds*o-fnr]):\\n[ft*exist] \{\
+. ev ne
+' bp
+. ev
+.\}
+.el 'bp
+..
+.\"-------------------------
+.\"
+.\" Initialize the title environment
+.de pg@set-env
+'na
+'nh
+'in 0
+'ti 0
+.ie \\n[Pgps] \{\
+. ps \\n[@ps]
+. vs \\n[@vs]
+.\}
+.el \{\
+. ps \\n[pg*ps]
+. vs \\n[pg*vs]
+.\}
+.lt \\n[@ll]u
+..
+.\"-------------------------
+.de PH
+.ds pg*header "\\$1
+.pg@set-new-size
+..
+.de PF
+.ds pg*footer "\\$1
+.pg@set-new-size
+..
+.de OH
+.ds pg*odd-header "\\$1
+.pg@set-new-size
+..
+.de EH
+.ds pg*even-header "\\$1
+.pg@set-new-size
+..
+.de OF
+.ds pg*odd-footer "\\$1
+.pg@set-new-size
+..
+.de EF
+.ds pg*even-footer "\\$1
+.pg@set-new-size
+..
+.de pg@clear-hd
+.ds pg*even-header
+.ds pg*odd-header
+.ds pg*header
+..
+.de pg@clear-ft
+.ds pg*even-footer
+.ds pg*odd-footer
+.ds pg*footer
+..
+.de pg@set-new-size
+.nr pg*ps \\n[@ps]
+.nr pg*vs \\n[@vs]
+.pg@move-trap
+..
+.\"-------------------------
+.\" end of page processing
+.de pg@footnotes
+.\".debug footnotes
+.\" output footnotes. set trap for block
+.\"
+..
+.\"-------------------------
+.\" print bottom block
+.de pg@block
+.ev pg*block-ev
+'nf
+'in 0
+.ll 100i
+.pg*block-div
+.br
+.ev
+..
+.\"-------------------------
+.\" define bottom block
+.de BS
+.misc@ev-keep pg*block-ev
+.init@reset
+.br
+.di pg*block-div
+..
+.\"-------------------------
+.de BE
+.br
+.di
+.nr pg*block-size \\n[dn]u
+.ev
+.pg@move-trap
+..
+.\"-------------------------
+.\" print out all pending text
+.de pg@end-of-text
+.if \\n[D]>2 .tm ---------- End of text processing ----------------
+.ds@eot-print
+.ref@eot-print
+..
+.\"-------------------------
+.\" set top and bottom margins
+.de VM
+.if \\n[.$]=0 \{\
+. nr pg*extra-footer-size 0
+. nr pg*extra-header-size 0
+.\}
+.if \\n[.$]>0 .nr pg*extra-header-size (v;\\$1)
+.if \\n[.$]>1 .nr pg*extra-footer-size (v;\\$2)
+.if \\n[D]>2 \{\
+. tm extra top \\n[pg*extra-footer-size]
+. tm extra bottom \\n[pg*extra-header-size]
+.\}
+.pg@move-trap
+..
+.\"---------------------
+.\" multicolumn output.
+.de pg@set-po
+.if \\n[pg*cols-per-page]>1 \{\
+. ll \\n[pg*column-size]u
+.\}
+..
+.de pg@inc-po
+.if \\n[pg*cols-per-page]>1 \{\
+. ie \\n+[pg*cur-column]>=\\n[pg*cols-per-page] \{\
+. nr pg*cur-column 0 1
+. nr pg*cur-po \\n[@po]u
+. po \\n[@po]u
+. ll \\n[@ll]u
+. \}
+. el \{\
+. nr pg*cur-po +(\\n[pg*column-size]u+\\n[pg*column-sep]u)
+. po \\n[pg*cur-po]u
+' sp |\\n[pg*head-mark]u
+. tbl@top-hook
+. \}
+.\}
+..
+.\" An argument disables the page-break.
+.de 1C
+.br
+.if \\n[pg*cols-per-page]<=1 .@error "1C: multicolumn mode not active"
+.nr pg*cols-per-page 1
+.nr pg*column-sep 0
+.nr pg*column-size \\n[@ll]
+.nr pg*cur-column 0 1
+.nr pg*cur-po \\n[@po]u
+.PGFORM
+.if !'\\$1'1' .SK
+..
+.de 2C
+.br
+.nr pg*head-mark \\n[nl]u
+.if \\n[pg*cols-per-page]>1 .@error "2C: multicolumn mode already active"
+.nr pg*cols-per-page 2
+.nr pg*column-sep \\n[@ll]/15
+.nr pg*column-size (\\n[@ll]u*7)/15
+.nr pg*cur-column 0 1
+.nr pg*cur-po \\n[@po]u
+.ll \\n[pg*column-size]u
+.\" .lt \\n[pg*column-size]u
+..
+.\" MC column-size [ column-separation ]
+.de MC
+.br
+.nr pg*head-mark \\n[nl]u
+.if \\n[pg*cols-per-page]>1 .@error "MC: multicolumn mode already active"
+.ie ''\\$1' .nr pg*column-size \\n[.l]
+.el .nr pg*column-size (n;\\$1)
+.ie ''\\$2' .nr pg*column-sep \\n[pg*column-size]/15
+.el .nr pg*column-sep (n;\\$2)
+.\"
+.nr pg*cols-per-page (u;\\n[.l]/(\\n[pg*column-size]+\\n[pg*column-sep]+1))
+.nr pg*cur-column 0 1
+.nr pg*cur-po \\n[@po]u
+.ll \\n[pg*column-size]u
+.\" .lt \\n[pg*column-size]u
+..
+.\" begin a new column
+.de NCOL
+.br
+.pg@footer
+..
+.\" skip pages
+.de SK
+.br
+.bp
+.nr pg*i 0 1
+.\" force new page by writing something invisible.
+.while \\n+[pg*i]<=(0\\$1) \{\
+\&
+. bp
+.\}
+..
+.\"-------------------------------
+.\" MULB width1 space1 width2 space2 width3 space3 ...
+.de MULB
+.br
+.nr pg*i 0 1
+.nr pg*mul-x 0 1
+.nr pg*mul-ind 0
+.nr pg*mul-last 0
+.while \\n[.$] \{\
+. nr pg*mul!\\n+[pg*i] (n;0\\$1)
+. nr pg*muls!\\n[pg*i] (n;0\\$2)
+. shift 2
+.\}
+.nr pg*mul-max-col \\n[pg*i]
+.ds pg*mul-fam \\n[.fam]
+.nr pg*mul-font \\n[.f]
+.ev pg*mul-ev
+.ps \\n[@ps]
+.vs \\n[@vs]
+.fam \\*[pg*mul-fam]
+.ft \\n[pg*mul-font]
+.fi
+.hy 14
+.di pg*mul-div
+.MULN
+..
+.\"-----------
+.de MULN
+.if \\n[pg*mul-x]>=\\n[pg*mul-max-col] .@error "MULN: Undefined columnwidth"
+.br
+.if \\n[.d]>\\n[pg*mul-last] .nr pg*mul-last \\n[.d]
+.rt +0
+.in \\n[pg*mul-ind]u
+.ll (u;\\n[.i]+\\n[pg*mul!\\n+[pg*mul-x]])u
+.nr pg*mul-ind +(u;\\n[pg*mul!\\n[pg*mul-x]]+\\n[pg*muls!\\n[pg*mul-x]])
+..
+.\"-----------
+.\" MULE
+.de MULE
+.br
+.if \\n[.d]>\\n[pg*mul-last] .nr pg*mul-last \\n[.d]
+.di
+.ev
+.ne \\n[pg*mul-last]u
+.nf
+.mk
+.pg*mul-div
+.rt
+.sp \\n[pg*mul-last]u
+.fi
+..
+.\"-----------
+.de OP
+.br
+.ie o .if !\\n[pg*head-mark]=\\n[nl] \{\
+. bp +1
+. bp +1
+.\}
+.el .bp
+..
+.\"########### module footnotes ###################
+.nr ft*note-size 0
+.nr ft*busy 0
+.nr ft*nr 0 1
+.nr ft*wide 0
+.nr ft*hyphen 0\" hyphenation value
+.nr ft*adjust 1\" >0 if adjust true
+.nr ft*indent 1\" >0 if text indent true (not imp. $$$)
+.nr ft*just 0\" 0=left justification, 1=right (not imp. $$$)
+.nr ft*exist 0\" not zero if there are any footnotes to be printed
+.nr ft*clear-at-header 0\" >0 if footnotes should be reset at first level head.
+.\"
+.ds F \v'-.4m'\s-3\\n+[ft*nr]\s0\v'.4m'
+.\"
+.\"-----------------
+.\" init footnote environment
+.de ft@init
+.\" indentcontrol not implemented $$$
+.\" label justification not implemented $$$
+'in 0
+'fi
+.ie \\n[ft*adjust] 'ad
+.el 'na
+.ie \\n[ft*hyphen] 'hy 14
+.el 'hy 0
+.ll \\n[@cur-ll]u
+.lt \\n[@cur-ll]u
+.ps (\\n[@ps]-2)
+.vs (\\n[@vs]-1)
+..
+.\"-----------------
+.\" set footnote format
+.\" no support for two column processing (yet). $$$
+.de FD
+.if \\n[.$]=0 .@error "FD: bad arg \\$1"
+.ie \\n[.$]=2 .nr ft*clear-at-header 1
+.el .nr ft*clear-at-header 0
+.\"
+.if !'\\$1'' \{\
+. ie \\$1>11 .nr ft*format 0
+. el .nr ft*format \\$1
+. \"
+. nr ft*hyphen (\\n[ft*format]%2)*14
+. nr ft*format \\n[ft*format]/2
+. \"
+. nr ft*adjust 1-(\\n[ft*format]%2)
+. nr ft*format \\n[ft*format]/2
+. \"
+. nr ft*indent 1-(\\n[ft*format]%2)
+. nr ft*format \\n[ft*format]/2
+. \"
+. nr ft*just \\n[ft*format]%2
+.\}
+..
+.\"---------------
+.\" Footnote and display width control $$$
+.de WC
+.nr ft*i 0 1
+.while \\n+[ft*i]<=\\n[.$] \{\
+. ds ft*x \\$[\\n[ft*i]]
+. if '\\*[ft*x]'N' \{\
+. nr ft*wide 0
+. nr ft*first-fn 0
+. nr ds*wide 0
+. nr ds*float-break 1
+. \}
+. if '\\*[ft*x]'-WF' .nr ft*wide 0
+. if '\\*[ft*x]'WF' .nr ft*wide 1
+. if '\\*[ft*x]'-FF' .nr ft*first-fn 0
+. if '\\*[ft*x]'FF' .nr ft*first-fn 1
+. if '\\*[ft*x]'-WD' .nr ds*wide 0
+. if '\\*[ft*x]'WD' .nr ds*wide 1
+. if '\\*[ft*x]'-FB' .nr ds*float-break 0
+. if '\\*[ft*x]'FB' .nr ds*float-break 1
+.\}
+..
+.\"-----------------
+.\" begin footnote
+.de FS
+.if \\n[ft*busy] .@error "FS: missing FE"
+.nr ft*busy 1
+.ev ft*ev
+.ft@init
+.if !\\n[ft*wide] .pg@set-po
+.if !d ft*div .ft@init-footnote
+.di ft*tmp-div
+.nr ft*space (u;\\n[Fs]*\\n[Lsp])
+.sp \\n[ft*space]u
+.\" print mark
+.ie \\n[.$] .ds ft*mark \\$1
+.el .ds ft*mark \\n[ft*nr].
+\\*[ft*mark]
+.in +.75c
+.sp -1
+.nr ft*exist 1
+..
+.\"-----------------
+.\" init footnote diversion
+.de ft@init-footnote
+.di ft*div
+\l'20n'
+.br
+.di
+.nr ft*note-size \\n[dn]
+..
+.\"-----------------
+.\" end footnote
+.de FE
+.nr ft*busy 0
+.br
+.di
+'in 0
+'nf
+.if \\n[@pl]u<\\n[dn]u .@error "FE: too big footnote"
+.ie (\\n[pg*foot-trap]u-\\n[.d]u)<\\n[dn]u \{\
+. da ft*next-div
+. ft*tmp-div
+. br
+. di
+.\}
+.el \{\
+. da ft*div
+. ft*tmp-div
+. di
+. nr ft*note-size +\\n[dn]
+.\}
+.rm ft*tmp-div
+.ev
+.pg@move-trap
+..
+.\"-----------------
+.\" print footnotes, see pg@footer
+.de ft@print
+.ev ft*print-ev
+'nf
+'in 0
+.ll 100i
+.ft*div
+.br
+.ev
+.rm ft*div
+.nr ft*note-size 0
+.pg@move-trap
+..
+.\"-----------------
+.\" check if any pending footnotes, see pg@header
+.de ft@check-old
+.if d ft*next-div \{\
+. ev ft*ev
+. ft@init
+. ft@init-footnote
+. nf
+. in 0
+. da ft*div
+. ft*next-div
+. di
+. nr ft*note-size +\\n[dn]
+. rm ft*next-div
+. ev
+. nr ft*exist 0
+. pg@move-trap
+.\}
+..
+.\"########### module display ###################
+.nr ds*wide 0\" >0 if wide displays wanted
+.nr ds*fnr 0 1\" floating display counter
+.nr ds*o-fnr 1\" floating display counter, already printed
+.nr ds*snr 0 1\" static display counter
+.nr ds*lvl 0 1\" display level
+.nr ds*float-busy 0\" >0 if printing float
+.nr ds*ffloat 0\" >0 if DF, 0 if DS
+.\" static display start
+.\" nested DS/DE is allowed. No limit on depth.
+.de DS
+.br
+.ds@start 0 DS \\$@
+..
+.\" floating display start
+.\" nested DF/DE is not allowed.
+.de DF
+.if \\n[ds*lvl] .@error "DF:nested floating is not allowed. Use DS."
+.ds@start 1 DF \\$@
+..
+.\"---------------
+.nr ds*format 0\" dummy value for .En/.EQ
+.nr ds*format! 0\" no indent
+.nr ds*format!0 0\" no indent
+.nr ds*format!L 0\" no indent
+.nr ds*format!I 1\" indent
+.nr ds*format!1 1\" indent
+.nr ds*format!C 2\" center each line
+.nr ds*format!2 2\" center each line
+.nr ds*format!CB 3\" center as block
+.nr ds*format!3 3\" center as block
+.nr ds*format!R 4\" right justify each line
+.nr ds*format!4 4\" right justify each line
+.nr ds*format!RB 5\" right justify as block
+.nr ds*format!5 5\" right justify as block
+.\"---------------
+.nr ds*fill! 0\" no fill
+.nr ds*fill!N 0\" no fill
+.nr ds*fill!0 0\" no fill
+.nr ds*fill!F 1\" fill on
+.nr ds*fill!1 1\" fill on
+.\"---------------
+.de ds@start
+.nr ds*ffloat \\$1
+.ds ds*type \\$2
+.shift 2
+.nr ds*lvl +1
+.\" get format of the display
+.ie \\n[.$] \{\
+. ie r ds*format!\\$1 .nr ds*format \\n[ds*format!\\$1]
+. el .@error "\\*[ds*type]:wrong format:\\$1"
+.\}
+.el .nr ds*format 0
+.\" fill or not to fill, that is the...
+.nr ds*fill 0
+.ie \\n[.$]>1 \{\
+. ie r ds*fill!\\$2 .nr ds*fill \\n[ds*fill!\\$2]
+. el .@error "\\*[ds*type]:wrong fill:\\$2"
+.\}
+.nr ds*rindent 0
+.if \\n[.$]>2 .nr ds*rindent \\$3
+.\"
+.\"---------------
+.nr ds*old-ll \\n[.l]
+.misc@push ds-ll \\n[.l]
+.misc@push ds-form \\n[ds*format]
+.misc@push ds-ffloat \\n[ds*ffloat]
+.nr ds*i \\n[.i]
+.nr ds*ftmp \\n[.f]
+.misc@ev-keep ds*ev!\\n+[ds*snr]
+.ft \\n[ds*ftmp]
+.\"
+.init@reset
+'in \\n[ds*i]u
+.di ds*div!\\n[ds*snr]
+.\"
+.ll \\n[ds*old-ll]u
+.lt \\n[ds*old-ll]u
+.if \\n[ds*rindent] \{\
+. ll -\\n[ds*rindent]n
+. lt -\\n[ds*rindent]n
+.\}
+.if \\n[ds*wide] \{\
+. ll \\n[@ll]u
+. lt \\n[@ll]u
+.\}
+.\"
+.ie \\n[ds*fill] 'fi
+.el 'nf
+.\"
+.if \\n[ds*format]=1 \{\
+. ll -\\n[Si]n
+. lt -\\n[Si]n
+' in +\\n[Si]n
+.\}
+.if (\\n[ds*format]=3):(\\n[ds*format]=5) 'in 0
+..
+.\"---------------
+.de DE
+.if \\n-[ds*lvl]<0 .@error "DE: no corresponding DS or DF"
+.br
+.if \\n[ds*ffloat] .SP \\n[Lsp]u
+.di
+.\" find out the real size of the diversion
+.di ds*test
+.ds*div!\\n[ds*snr]
+.di
+.nr ds*width \\n[dl]
+.nr ds*height \\n[dn]
+.rm ds*test
+.misc@pop-nr ds-ll ds*old-ll
+.misc@pop-nr ds-form ds*format
+.misc@pop-nr ds-ffloat ds*ffloat
+.if (\\n[ds*format]>=2)&(\\n[ds*width]>\\n[ds*old-ll]) \{\
+. @error "DE: display too wide for current line-length"
+.\}
+.\" prepare copy to floating display
+.if \\n[ds*ffloat] .di ds*fdiv!\\n+[ds*fnr]
+.\"
+'in 0
+'nf
+.if \\n[ds*format]=2 'ce 9999
+.if \\n[ds*format]=3 'in (u;(\\n[ds*old-ll]-\\n[ds*width])/2)
+.if \\n[ds*format]=4 'rj 9999
+.if \\n[ds*format]=5 'in (u;\\n[ds*old-ll]-\\n[ds*width])
+.\"
+.ie !\\n[ds*ffloat] \{\
+. \"
+. \" Print static display
+. \" Eject page if display will fit one page and
+. \" there are less than half of the page left.
+. nr ds*i \\n[pg*foot-trap]-\\n[pg*header-size]v-\\n[pg*extra-header-size]v
+. if (\\n[ds*height]>\\n[ds*i])&(\\n[.t]<(\\n[ds*i]/2)) \{\
+. ne \\n[.t]u+1v
+. \}
+. if (\\n[ds*height]<\\n[ds*i])&(\\n[.t]<(\\n[ds*height])) \{\
+. ne \\n[.t]u+1v
+. \}
+. if \\n[Ds] .SP \\n[Lsp]u
+.\}
+.el .SP \\n[Lsp]u
+.ds*div!\\n[ds*snr]
+.ie !\\n[ds*ffloat] .if \\n[Ds] .SP \\n[Lsp]u
+.el \{\
+. SP \\n[Lsp]u
+. di
+.\}
+.if \\n[ds*format]=2 'ce 0
+.if \\n[ds*format]=4 'rj 0
+.rm ds*div!\\n[ds*snr]
+.nr ds*snr -1
+.nr par@ind-flag 0
+.\" move div to the floating display list
+.ev
+.if \\n[ds*ffloat] \{\
+. nr ds*fsize!\\n[ds*fnr] \\n[dn]
+. \" print float if queue is empty and the display fits into
+. \" the current page
+. if ((\\n[ds*fnr]>\\n[ds*o-fnr])&(\\n[ds*height]<\\n[.t])) \{\
+. ds@print-float 1
+. \}
+.\}
+..
+.\"-------------
+.\" called by end-of-text
+.de ds@eot-print
+.if \\n[ds*o-fnr]<=\\n[ds*fnr] \{\
+. if \\n[D]>2 .tm Print remaining displays.
+.\" still some floats left, make non-empty environment
+. misc@ev-keep ne
+. init@reset
+\c
+. ds@print-float 3
+. ev
+.\}
+..
+.\"---------------
+.\" print according to Df and De.
+.\" .ds@print-float type
+.\" type called from
+.\" 1 .DE
+.\" 2 end of section
+.\" 3 end of document
+.\" 4 beginning of new page
+.\"
+.de ds@print-float
+.if \\n[Df]>5 .@error "Df=\\n[Df], max value is 5"
+.if !\\n[ds*float-busy] \{\
+. nr ds*float-busy 1
+.\" at .DE
+. if (\\$1=1)&((\\n[Df]%2)=1) \{\
+. if \\n[.t]>\\n[ds*fsize!\\n[ds*o-fnr]] \{\
+. \" Df = 1,3 or 5
+. ds@print-one-float
+. \}
+. \}
+.\" print all if Df<2 and end of section
+. if (\\$1=2)&(\\n[Df]<2) .ds@print-all-floats
+.\" print all if end of document. Where should they go instead?
+. if \\$1=3 .ds@print-all-floats
+.\" new page
+. if (\\$1=4)&(\\n[Df]>1) \{\
+. if \\n[Df]=2 .ds@print-one-float
+. if \\n[Df]=3 .ds@print-one-float
+. if \\n[Df]>3 \{\
+. ie \\n[De] .ds@print-all-floats
+. el .ds@print-this-page
+. \}
+. \}
+. nr ds*float-busy 0
+.\}
+..
+.\"---------------
+.\" print a floating diversion
+.de ds@output-div
+.ev ds*fev
+.in 0
+.nf
+.ds*fdiv!\\n[ds*o-fnr]
+.ev
+.rm ds*fdiv!\\n[ds*o-fnr]
+.rm ds*fsize!\\n[ds*o-fnr]
+.rm ds*fformat!\\n[ds*o-fnr]
+.nr ds*o-fnr +1
+..
+.\"---------------
+.\" print one floating display if there is one.
+.de ds@print-one-float
+.if \\n[ds*o-fnr]<=\\n[ds*fnr] \{\
+. if \\n[.t]<\\n[ds*fsize!\\n[ds*o-fnr]] .pg@next-page
+. ds@output-div
+. if \\n[De] .pg@next-page
+.\}
+..
+.\"---------------
+.\" print all queued floats.
+.\" if De>0 do a page eject between the floats.
+.de ds@print-all-floats
+.while \\n[ds*o-fnr]<=\\n[ds*fnr] \{\
+. if \\n[.t]<\\n[ds*fsize!\\n[ds*o-fnr]] .pg@next-page
+. ds@output-div
+. if \\n[De] .pg@next-page
+.\}
+..
+.\"---------------
+.\" print as many floats as will fit on the current page
+.de ds@print-this-page
+.while \\n[ds*o-fnr]<=\\n[ds*fnr] \{\
+. if \\n[.t]<\\n[ds*fsize!\\n[ds*o-fnr]] .break
+. ds@output-div
+.\}
+..
+.\"########### module list ###################
+.\" .LI text-indent mark-indent pad type [mark [LI-space [LB-space] ] ]
+.\"
+.nr li*tind 0
+.nr li*mind 0
+.nr li*pad 0
+.nr li*type 0
+.ds li*mark 0
+.nr li*li-spc 0
+.nr li*lvl 0 1
+.nr li*cur-vpos 0
+.\"--------------------------
+.\" the major list-begin macro.
+.\" If type == -1 a 'break' will occur.
+.de LB
+.if \\n[.$]<4 .@error "LB: not enough arguments, min 4"
+.misc@push cind \\n[.i]
+.misc@push tind \\n[li*tind]
+.misc@push mind \\n[li*mind]
+.misc@push pad \\n[li*pad]
+.misc@push type \\n[li*type]
+.misc@push li-spc \\n[li*li-spc]
+.ds li*mark-list!\\n[li*lvl] \\*[li*mark]
+.nr li*lvl +1
+.\"
+.nr li*tind (n;0\\$1)\" text-indent
+.nr li*mind (n;0\\$2)\" mark-indent
+.nr li*pad (n;0\\$3)\" pad
+.nr li*type 0\\$4\" type
+.ds li*mark \\$5\" mark
+.ie !'\\$6'' .nr li*li-spc \\$6\" LI-space
+.el .nr li*li-spc 1
+.ie !'\\$7'' .nr li*lb-spc \\$6\" LB-space
+.el .nr li*lb-spc 0
+.\" init listcounter
+.nr li*cnt!\\n[li*lvl] 0 1
+.\" assign format
+.af li*cnt!\\n[li*lvl] 1
+.if \\n[li*type] .if !'\\*[li*mark]'' .af li*cnt!\\n[li*lvl] \\*[li*mark]
+.\"
+.if \\n[li*lb-spc] .SP (u;\\n[li*lb-spc]*\\n[Lsp])
+.in +\\n[li*tind]u
+..
+.\"---------------
+.de LI
+.if \\n[li*lvl]<1 .@error "LI:no lists active"
+.if \\n[li*li-spc]&(\\n[Ls]>=\\n[li*lvl]) .SP (u;\\n[li*li-spc]*\\n[Lsp])
+.ne 2v
+.\"
+.ds li*c-mark \\*[li*mark]
+.nr li*cnt!\\n[li*lvl] +1
+.if \\n[li*type]=1 .ds li*c-mark \\n[li*cnt!\\n[li*lvl]].
+.if \\n[li*type]=2 .ds li*c-mark \\n[li*cnt!\\n[li*lvl]])
+.if \\n[li*type]=3 .ds li*c-mark (\\n[li*cnt!\\n[li*lvl]])
+.if \\n[li*type]=4 .ds li*c-mark [\\n[li*cnt!\\n[li*lvl]]]
+.if \\n[li*type]=5 .ds li*c-mark <\\n[li*cnt!\\n[li*lvl]]>
+.if \\n[li*type]=6 .ds li*c-mark {\\n[li*cnt!\\n[li*lvl]]}
+.if \\n[.$]=1 .ds li*c-mark \\$1
+.if \\n[.$]=2 .ds li*c-mark \\$1\ \\*[li*c-mark]
+.if '\\*[li*c-mark]'\ ' .ds li*c-mark
+.\"
+.\" determine where the text begins
+.nr li*text-begin \\n[li*tind]>?\w@\\*[li*c-mark]\ @
+.nr x \w@\\*[li*c-mark]\ @
+.\"
+.\" determine where the mark begin
+.ie !\\n[li*pad] .nr li*in \\n[li*mind]
+.el .nr li*in \\n[li*text-begin]-\\n[li*pad]-\w@\\*[li*c-mark]@
+.if !\\n[li*in] .nr li*in 0
+.\"
+.ti -\\n[li*tind]u
+.\" no indentation if hanging indent
+.if (\w@\\*[li*c-mark]@=0)&((\\n[.$]=0):(\w@\\$1@=0)) .nr li*text-begin 0
+\Z'\&\h'\\n[li*in]u'\\*[li*c-mark]'\h'\\n[li*text-begin]u'\&\c
+.if \\n[li*type]=-1 .br
+..
+.\"
+.\"-------------
+.de li@pop
+.nr li*lvl -1
+.misc@pop-nr cind li*tmp
+.in \\n[li*tmp]u
+.misc@pop-nr tind li*tind
+.misc@pop-nr mind li*mind
+.misc@pop-nr pad li*pad
+.misc@pop-nr type li*type
+.misc@pop-nr li-spc li*li-spc
+.ds li*mark \\*[li*mark-list!\\n[li*lvl]]
+..
+.de LE
+.if \\n[li*lvl]<1 .@error "LE:mismatched"
+.li@pop
+.if '\\$1'1' .SP \\n[Lsp]u
+..
+.\"-------------
+.\" list status clear.
+.de LC
+.if !\\n[.$]=1 .@error "LC: no argument"
+.if \\$1>\\n[li*lvl] .@error "LC: incorrect argument: \\$1 (too big)"
+.while \\n[li*lvl]>\\$1 .li@pop
+.nr par@ind-flag 0
+..
+.\"-------------
+.de AL
+.if \\n[.$]>3 .@error "AL: too many arguments"
+.if \\n[D]>2 .tm AL $*
+.ie \\n[.$]<=1 .LB \\n[Li] 0 2 1 "\\$1"
+.el \{\
+. ie \\n[.$]=2 .LB 0\\$2 0 2 1 "\\$1"
+. el \{\
+. ie !'\\$2'' .LB \\$2 0 2 1 "\\$1" 0 1
+. el .LB \\n[Li] 0 2 1 "\\$1" 0 1
+. \}
+.\}
+..
+.de ML
+.if \\n[.$]>3 .@error "ML: too many arguments"
+.if \\n[D]>2 .tm ML $*
+.nr li*ml-width \w@\\$1@u+1n
+.if \\n[.$]<2 .LB \\n[li*ml-width]u 0 1 0 "\\$1"
+.if \\n[.$]=2 .LB 0\\$2 0 1 0 "\\$1"
+.if \\n[.$]=3 \{\
+. ie '\\$2'' .LB \\n[li*ml-width]u 0 1 0 "\\$1" 0 1
+. el .LB \\n[Li] 0 1 0 "\\$1" 0 1
+.\}
+..
+.de VL
+.if \\n[D]>2 .tm VL $*
+.if \\n[.$]>3 .@error "VL: too many arguments"
+.if \\n[.$]<1 .@error "VL: missing text-indent"
+.ie \\n[.$]<3 .LB 0\\$1 0\\$2 0 0
+.el .LB 0\\$1 0\\$2 0 0 \& 0 1
+..
+.\" Bullet (for .BL)
+.de BL
+.if \\n[D]>2 .tm BL $*
+.ds BU \s-2\(bu\s0
+.if \\n[.$]>2 .@error "BL: too many arguments"
+.if \\n[.$]<1 .LB \\n[Pi] 0 1 0 \\*[BU]
+.if \\n[.$]=1 .LB 0\\$1 0 1 0 \\*[BU]
+.if \\n[.$]=2 \{\
+. ie '\\$1'' .LB \\n[Pi] 0 1 0 \\*[BU] 0 1
+. el .LB 0\\$1 0 1 0 \\*[BU] 0 1
+.\}
+..
+.de DL
+.if \\n[D]>2 .tm DL $*
+.if \\n[.$]>2 .@error "DL: too many arguments"
+.if \\n[.$]<1 .LB \\n[Pi] 0 1 0 \(em
+.if \\n[.$]=1 .LB 0\\$1 0 1 0 \(em
+.if \\n[.$]=2 \{\
+. ie '\\$1'' .LB \\n[Pi] 0 1 0 \(em 0 1
+. el .LB 0\\$1 0 1 0 \(em 0 1
+.\}
+..
+.de RL
+.if \\n[D]>2 .tm RL $*
+.if \\n[.$]>2 .@error "RL: too many arguments"
+.if \\n[.$]<1 .LB 6 0 2 4
+.if \\n[.$]=1 .LB 0\\$1 0 2 4
+.if \\n[.$]=2 \{\
+. ie '\\$1'' .LB 6 0 2 4 1 0 1
+. el .LB 0\\$1 0 2 4 1 0 1
+.\}
+..
+.\" Broken Variable List. As .VL but text begin on the next line
+.de BVL
+.if \\n[D]>2 .tm BVL $*
+.if \\n[.$]>3 .@error "BVL: too many arguments"
+.if \\n[.$]<1 .@error "BVL: missing text-indent"
+.ie \\n[.$]<3 .LB 0\\$1 0\\$2 0 -1
+.el .LB 0\\$1 0\\$2 0 -1 \& 0 1
+..
+.\" ####### module tbl #######################################
+.\" This module is copied from groff_ms and modified for mgm.
+.\" Yes, it does not resemble the original anymore :-).
+.\" Don't know if I missed something important.
+.\" Groff_ms is written by James Clark.
+.nr tbl*have-header 0
+.nr tbl*header-written 0
+.de TS
+.br
+.if ''\\n[.z]' .SP
+.if '\\$1'H' .di tbl*header-div
+..
+.de tbl@top-hook
+.if \\n[tbl*have-header] \{\
+. ie \\n[.t]-\\n[tbl*header-ht]-1v .tbl@print-header
+. el .sp \\n[.t]u
+.\}
+..
+.de tbl@bottom-hook
+.if \\n[tbl*have-header] \{\
+. nr T. 1
+.\" draw bottom and side lines of boxed tables.
+. T#
+.\}
+.nr tbl*header-written 0
+..
+.de tbl@print-header
+.ev tbl*ev
+'nf
+.tbl*header-div
+.ev
+.mk #T
+.nr tbl*header-written 1
+..
+.de TH
+.ie '\\n[.z]'tbl*header-div' \{\
+. nr T. 0
+. T#
+. br
+. di
+. nr tbl*header-ht \\n[dn]
+. ne \\n[dn]u+1v
+. nr tbl*have-header 1
+. ie '\\$1'N' .if !\\n[tbl*header-written] .tbl@print-header
+. el .tbl@print-header
+.\}
+.el .@error ".TH without .TS H"
+..
+.de TE
+.ie '\\n(.z'tbl*header-div' .@error ".TS H but no .TH before .TE"
+.el \{\
+. nr tbl*have-header 0
+.\}
+.\" reset tabs
+.TAB
+..
+.de T&
+..
+.\" ####### module pic #######################################
+.de PS
+.nr pic*in 0
+.br
+.SP .5
+.ie \\n[.$]<2 .@error "PS: bad arguments. Probably not processed with pic."
+.el \{\
+. if !\\n[ds*lvl] .ne (u;\\$1)+1v
+.\" should be contained between .DS/.DE
+.if r ds*format \{\
+. if \\n[ds*lvl]&((\\n[ds*format]=2):(\\n[ds*format]=3)) \{\
+. nr pic*in \\n[.i]
+.\" . in +(u;\\n[.l]-\\n[.i]-\\$2/2)
+. \}
+. \}
+.\}
+..
+.de PE
+.init@reset
+.SP .5
+..
+.\" ####### module eq #######################################
+.\"
+.nr eq*number 0 1
+.de EQ
+.ds eq*lable "\\$1
+.di eq*div
+.misc@ev-keep eq*ev
+.in 0
+.nf
+..
+.de EN
+.br
+.di
+.ta
+.\" equation with lable.
+.if \\n[dl] \{\
+. br
+. chop eq*div
+. ie (\\n[Eq]%2) \{\
+. \" lable to the left
+. if \\n[ds*format]<2 \{\
+. ta (u;(\\n[.l]/7)+\\n[.i]) \\n[.l]u\" L
+\\*[eq*lable]\t\\*[eq*div]\t\&
+. \}
+. if (\\n[ds*format]=2):(\\n[ds*format]=3) \{\
+. ta (u;(\\n[.l]-\\n[.i])/2+\\n[.i])C \\n[.l]u\" C
+\\*[eq*lable]\t\\*[eq*div]\t\&
+. \}
+. if \\n[ds*format]>3 \{\
+. ta \\n[.l]uR\" R
+\\*[eq*lable]\t\\*[eq*div]
+. \}
+. \}
+. el \{\
+. \" lable to the right
+. if \\n[ds*format]<2 \{\
+. ta \\n[.l]uR\" L
+\\*[eq*div]\t\\*[eq*lable]
+. \}
+. if (\\n[ds*format]=2):(\\n[ds*format]=3) \{\
+. ta (u;(\\n[.l]-\\n[.i])/2+\\n[.i])C \\n[.l]uR\" C
+\t\\*[eq*div]\t\\*[eq*lable]
+. \}
+. if \\n[ds*format]>3 \{\
+. ta (\\n[.l]u-\w@\\*[eq*lable]@u-1m)R \\n[.l]uR\" R
+\t\\*[eq*div]\t\\*[eq*lable]
+. \}
+. \}
+.\}
+.TAB
+.ev
+..
+.\"########### module toc ###################
+.\" table of contents
+.nr toc*slevel 1
+.nr toc*spacing \n[Lsp]u
+.nr toc*tlevel 2
+.nr toc*tab 0
+.\"-----------
+.\" Table of contents with friends (module lix)
+.de TC
+.br
+.\" print any pending displays and references
+.ds@print-float 3
+.if \\n[ref*flag] .RP 0 1
+.\"
+.if \w@\\$1@>0 .nr toc*slevel \\$1
+.if \w@\\$2@>0 .nr toc*spacing (u;\\$2*\\n[Lsp])
+.if \w@\\$3@>0 .nr toc*tlevel \\$3
+.if \w@\\$4@>0 .nr toc*tab \\$4
+.if \\n[pg*cols-per-page]>1 .1C
+.pg@clear-hd
+.pg@next-page
+.pg@clear-ft
+.\"-------------
+.if d Ci .toc@read-Ci \\*[Ci]
+.nf
+.in 0
+.nr toc*pn 0 1
+.af toc*pn i
+.PF "''\\\\\\\\n+[toc*pn]''"
+.nr toc*i 4 1
+.while \\n+[toc*i]<10 \{\
+. if !'\\$\\n[toc*i]'' \{\
+. ce
+\\$\\n[toc*i]
+. br
+. \}
+.\}
+.if \\n[.$]<=4 .if d TX .TX
+.ie d TY .if \\n[.$]<=4 .TY
+.el \{\
+. ce
+\\*[Licon]
+. br
+. SP 3
+.\}
+.if d toc*list .toc*list
+.\" print LIST OF XXX
+.if d lix*dsfg .lix@print-ds fg "\\*[Lf]"
+.if d lix*dstb .lix@print-ds tb "\\*[Lt]"
+.if d lix*dsec .lix@print-ds ec "\\*[Le]"
+.if d lix*dsex .lix@print-ds ex "\\*[Lx]"
+..
+.\"-----------
+.\" .toc@read-Ci lev1 lev2 lev3 lev4 ... lev7
+.de toc@read-Ci
+.nr toc*i 0 1
+.while \\n+[toc*i]<8 \{\
+. nr toc*hl!\\n[toc*i] \\$\\n[toc*i]
+.\}
+..
+.\"-----------
+.de toc@save
+.\" collect maxsize of mark if string Ci don't exist.
+.if !d Ci \{\
+. if !r toc*hl!\\$1 .nr toc*hl!\\$1 0
+. if \\n[toc*hl!\\$1]<=\w@\\$2@ \{\
+. nr toc*hl!\\$1 \w@\\$2@u+1m
+. \}
+.\}
+.am toc*list
+.\" .toc@set level headernumber text pagenr
+.toc@set \\$1 "\\$2" "\\$3" \\$4
+\\..
+..
+.\"-----------
+.\" level mark text pagenumber
+.de toc@set
+.if \\$1<=\\n[toc*slevel] .SP \\n[toc*spacing]u
+.ne 2v
+.na
+.fi
+.nr toc*ind 0
+.nr toc*i 0 1
+.ie d Ci \{\
+. nr toc*ind +\\n[toc*hl!\\$1]u
+.\}
+.el \{\
+. while \\n+[toc*i]<\\$1 \{\
+. nr toc*ind +\\n[toc*hl!\\n[toc*i]]u
+. \}
+.\}
+.nr toc*text \\n[toc*ind]u+\\n[toc*hl!\\$1]u
+.in \\n[toc*text]u
+.ti -\\n[toc*hl!\\$1]u
+.\"
+.\" length of headernum space
+.nr toc*i \\n[toc*hl!\\$1]-\w@\\$2@
+.\"
+.ll \\n[@ll]u-\w@\\$4@u-2m
+.\" ragged right ---------------------------------
+.ie \\$1>\\n[toc*tlevel] \{\
+\\$2
+. sp -1
+\\$3\ \ \ \\$4
+. br
+.\}
+.el \{\
+. \" unnumbered heading --------------------
+. ie '\\$2'' \{\
+. in \\n[toc*ind]u
+\\$3\h'1m'
+. \}
+. \" normal heading ------------------------
+. el \{\
+\\$2
+. sp -1
+\\$3\h'1m'
+. \}
+. ll \\n[@ll]u
+. sp -1
+. nr toc*sep (u;\\n[.l]-\\n[.n]-\\n[.i]-\w@\\$4@)-1m
+\h'|\\n[.n]u'\l'\\n[toc*sep]u.'\h'1m'\\$4
+.\}
+.ll \\n[@ll]u
+..
+.\"########################### module lix ############################
+.\" LIST OF figures, tables, exhibits and equations
+.nr lix*fg-nr 0 1
+.nr lix*tb-nr 0 1
+.nr lix*ec-nr 0 1
+.nr lix*ex-nr 0 1
+.aln Fg lix*fg-nr
+.aln Tb lix*tb-nr
+.aln Ec lix*ec-nr
+.aln Ex lix*ex-nr
+.\"------------
+.de FG
+.lix@print-line fg Lf \\n+[lix*fg-nr] "\\$1" "\\$2" "\\$3" "\\$4"
+..
+.de TB
+.lix@print-line tb Lt \\n+[lix*tb-nr] "\\$1" "\\$2" "\\$3" "\\$4"
+..
+.de EC
+.lix@print-line ec Le \\n+[lix*ec-nr] "\\$1" "\\$2" "\\$3" "\\$4"
+..
+.de EX
+.lix@print-line ex Lx \\n+[lix*ex-nr] "\\$1" "\\$2" "\\$3" "\\$4"
+..
+.\"------------
+.\" print line with 'figure' in the text
+.\" type stringvar number text override flag refname
+.de lix@print-line
+.ds lix*text "\\$4
+.\"
+.ie \\n[Sectf] .ds lix*numb \\n[H1]-\\$3
+.el .ds lix*numb \\$3
+.\"
+.ie !\\n[Of] .ds lix*ds-form .\ \ \"
+.el .ds lix*ds-form "\ \(em\ \"
+.nr lix*in \\n[.i]
+.ds lix*lable \\*[Li\\$1]\ \\*[lix*numb]\\*[lix*ds-form]
+.if !'\\$5'' \{\
+. if !0\\$6 .ds lix*lable \\*[Li\\$1]\ \\$5\\*[lix*numb]\\*[lix*ds-form]
+. if 0\\$6=1 .ds lix*lable \\*[Li\\$1]\ \\*[lix*numb]\\$5\\*[lix*ds-form]
+. if 0\\$6=2 .ds lix*lable \\*[Li\\$1]\ \\$5\\*[lix*ds-form]
+.\}
+.ie \\n[Sectp] .ds lix*pgnr \\*[hd*sect-pg]
+.el .ds lix*pgnr \\n[%]
+.\" print line if not between DS/DE
+.ie \\n[ds*lvl]<1 .lix@print-text "\\*[lix*lable]" "\\*[lix*text]"
+.el .lix@embedded-text "\\*[lix*lable]" "\\*[lix*text]"
+.\"
+.\" save line for LIST OF XXX
+.if !r lix*wth\\$1 .nr lix*wth\\$1 0
+.if \w@\\*[lix*lable]@>\\n[lix*wth\\$1] .nr lix*wth\\$1 \w@\\*[lix*lable]@
+.if \\n[\\$2] .lix@ds-save \\$1 \\*[lix*pgnr] "\\$4" "\\*[lix*lable]"
+.if !'\\$7'' .SETR \\$7 \\*[lix*numb]
+..
+.\"-----------
+.de lix@print-text
+.SP \\n[Lsp]u
+.misc@ev-keep lix
+.init@reset
+.br
+.ie (\w@\\$1\\$2@)>(\\n[.l]-\\n[.i]) \{\
+. in +\w@\\$1@u
+. ti 0
+.\}
+.el .ce 1
+\fB\\$1\fP\\$2
+.br
+.ev
+..
+.\" hide printout until diversion is evaluated
+.de lix@embedded-text
+\!.SP \\n[Lsp]u
+\!.misc@ev-keep lix
+\!.init@reset
+\!.br
+\!.ie (\w@\\$1\\$2@)>(\\n[.l]-\\n[.i]) \{\
+. in +\w@\\$1@u
+\!. ti 0
+\!.\}
+\!.el .ce 1
+\!\fB\\$1\fP\\$2
+\!.br
+\!.ev
+..
+.\"------------
+.\" print complete list of XXXX
+.de lix@print-ds
+.\" arg: fg,tb,ec,ex text
+.if !\\n[Cp] .pg@next-page
+.\" print LIST OF XXXX
+.ce
+\\$2
+.SP 3
+.in \\n[lix*wth\\$1]u
+.fi
+.lix*ds\\$1
+..
+.\"------------
+.\" save line of list in macro
+.de lix@ds-save
+.\" type pagenumber text
+.am lix*ds\\$1
+.lix@dsln \\$1 \\$2 "\\$3" "\\$4" \\$5
+\\..
+..
+.\"------------
+.\" print appended macro
+.\" lix@dsln type pagenumber text headernr
+.de lix@dsln
+.nr lix*i \\n[lix*wth\\$1]-\w@\\$4@
+.ne 2v
+.nr lix*sep \\n[.l]-\\n[lix*i]-\w'\\$4\\$3\\$2'-1m-1n-\\n[.i]
+\h'\\n[lix*i]u'\\$4\\$3\h'1n'\l'\\n[lix*sep]u.'\h'1m'\\$2
+.SP \\n[toc*spacing]u
+..
+.\"########################### module fnt ############################
+.\" some font macros.
+.de R
+.ft R
+.ul 0
+..
+.\"-----------
+.de fnt@switch
+.ul 0
+.ds fnt*tmp
+.nr fnt*prev \\n[.f]
+.nr fnt*i 2 1
+.while \\n+[fnt*i]<=\\n[.$] \{\
+. if \\n[fnt*i]>3 .as fnt*tmp \,
+. ie (\\n[fnt*i]%2)=1 .as fnt*tmp \\$1\\$[\\n[fnt*i]]
+. el .as fnt*tmp \\$2\\$[\\n[fnt*i]]
+. if \\n[fnt*i]<\\n[.$] .as fnt*tmp \/
+.\}
+\&\\*[fnt*tmp]\f[\\n[fnt*prev]]
+..
+.\"-----------
+.de B
+.ie \\n[.$] .fnt@switch \fB \f[\\n[.f]] \\$@
+.el .ft B
+..
+.de I
+.ie \\n[.$] .fnt@switch \fI \f[\\n[.f]] \\$@
+.el .ft I
+..
+.de IB
+.if \\n[.$] .fnt@switch \fI \fB \\$@
+..
+.de BI
+.if \\n[.$] .fnt@switch \fB \fI \\$@
+..
+.de IR
+.if \\n[.$] .fnt@switch \fI \fR \\$@
+..
+.de RI
+.if \\n[.$] .fnt@switch \fR \fI \\$@
+..
+.de RB
+.if \\n[.$] .fnt@switch \fR \fB \\$@
+..
+.de BR
+.if \\n[.$] .fnt@switch \fB \fR \\$@
+..
+.\"########################### module box ############################
+.\" draw a box around some text. Text will be kept on the same page.
+.\"
+.nr box*ll 0
+.\" .B1 and .B2 works like .DS
+.de B1
+.if \\n[box*ll] .@error "B1: missing B2"
+.nr box*ll \\n[.l]
+.nr box*ind \\n[.i]
+.nr box*hyp \\n[.hy]
+.nr box*wid \\n[.l]-\\n[.i]
+.\"
+.\" jump to new environment.
+.ev box*ev
+.di box*div
+.ps \\n[@ps]
+.vs \\n[@vs]
+.in 1n
+.ll (u;\\n[box*wid]-1n)
+.hy \\n[.hy]
+..
+.de B2
+.if !\\n[box*ll] .@error "B2: missing B1"
+.br
+.di
+.nr box*height \\n[dn]
+.ne \\n[dn]u+1v
+.ll \\n[box*ll]u
+.in \\n[box*ind]u
+.nr box*y-pos \\n[.d]u
+.nf
+.box*div
+.fi
+\v'-1v+.25m'\
+\D'l \\n[box*wid]u 0'\
+\D'l 0 -\\n[box*height]u'\
+\D'l -\\n[box*wid]u 0'\
+\D'l 0 \\n[box*height]u'
+.br
+.sp -1
+.ev
+.sp .20v
+.in \\n[box*ind]u
+.ll \\n[box*ll]u
+.rm box*div
+.nr box*ll 0
+..
+.\"########################### module ref ############################
+.nr ref*nr 0 1
+.nr ref*nr-width 5n
+.nr ref*flag 0 \" for end-of-text
+.ds Rf \v'-.4m'\s-3[\\n+[ref*nr]]\s0\v'.4m'
+.\"
+.\" start reference
+.\"------------
+.de RS
+.if !''\\$1' .ds \\$1 \\n[ref*nr]
+.nr ref*flag 1
+.am ref*mac
+.ref@start-print \\n[ref*nr]
+\\..
+.eo
+.am ref*mac RF
+..
+.\"------------
+.de RF
+.ec
+.am ref*mac
+.ref@stop-print
+\\..
+..
+.\"------------
+.de ref@start-print
+.di ref*div
+.in \\n[ref*nr-width]u
+.ti -(\w@\\$1.@u+1n)
+\\$1.
+.sp -1
+..
+.de ref@stop-print
+.br
+.di
+.ne \\n[dn]u
+.ev ref*ev2
+.nf
+.ref*div
+.ev
+.rm ref*div
+.if \\n[Ls] .SP \\n[Lsp]u
+..
+.\"-----------
+.de RP
+.if !d ref*mac .@error "RP: No references!"
+.nr ref*i 0\\$2
+.if \\n[ref*i]<2 .SK
+.SP 2
+.ref@print-refs
+.if 0\\$1<1 .nr ref*nr 0 1
+.if ((\\n[ref*i]=0):(\\n[ref*i]=2)) .SK
+..
+.\"-----------
+.\" called by end-of-text!
+.de ref@eot-print
+.\".if \\n[ref*flag] \{
+.if d ref*mac \{\
+. if \\n[D]>2 .tm Print references, called by eot
+. nr ref*flag 0
+. br
+. misc@ev-keep ne
+. init@reset
+\c
+' bp
+. ev
+. ref@print-refs
+.\}
+..
+.\"-----------
+.\" prints the references
+.de ref@print-refs
+.toc@save 1 "" "\\*[Rp]" \\n[%]
+.ce
+\fI\\*[Rp]\fP
+.sp
+.nr ref*ll \\n[.l]
+.misc@ev-keep ref*ev
+.ll \\n[ref*ll]u
+.in 0
+.ref*mac
+.in
+.rm ref*mac
+.ev
+..
+.\"########################### module app ############################
+.\"
+.nr app*nr 0 1
+.af app*nr A
+.nr app*dnr 0 1
+.\"------------
+.\" .APP name text
+.\" name == "" -> autonumber
+.de APP
+.\" .if \\n[.$]<2 .@error "APP: too few arguments"
+.app@set-ind "\\$1"
+.\"
+.ie \\n[Aph] .app@header \\*[app*ind] "\\$2"
+.el .bp
+.app@index "\\*[app*ind]" "\\$2"
+..
+.\"------------
+.\" .APPSK name pages text
+.\" name == "" -> autonumber
+.de APPSK
+.if \\n[.$]<2 .@error "APPSK: too few arguments"
+.app@set-ind "\\$1"
+.\"
+.ie \\n[Aph] .app@header \\*[app*ind] "\\$3"
+.el .bp
+.app@index "\\*[app*ind]" "\\$3"
+.pn +\\$2
+..
+.\"------------
+.de app@set-ind
+.ie \w@\\$1@ .ds app*ind \\$1
+.el \{\
+. if !\\n[app*dnr] \{\
+. nr H1 0 1
+. af H1 A
+. \}
+. ds app*ind \\n+[app*nr]
+. nr H1 \\n+[app*dnr]
+.\}
+.\" clear lower counters
+.nr app*i 1 1
+.while \\n+[app*i]<8 .nr H\\n[app*i] 0 1
+..
+.\"------------
+.de app@index
+.toc@save 1 "" "\\*[App] \\$1: \\$2" \\n[%]
+..
+.\"------------
+.\" app@heaer name text
+.de app@header
+.bp
+.SP (u;\\n[Lsp]*4)
+.ce 1
+\s+4\fB\\*[App]\ \\$1\fP\s0
+.SP (u;\\n[Lsp]*2)
+.if \w@\\$2@<\\n[.l] .ce 1
+\fB\s+2\\$2\s0\fP
+.SP (u;\\n[Lsp]*4)
+..
+.\"########################### module cov ############################
+.\" title stored in diversion cov*title
+.\" abstract stored in diversion cov*abstract
+.\" arg to abstract stored in cov*abs-arg
+.\" indent stored in cov*abs-ind
+.\" number of authors stored in cov*au
+.\" author(s) stored in cov*au!x!y
+.\" author(s) title stored in cov*at!x!y
+.\" x is the author-index [1-cov*au], y is the argument-index [1-9].
+.\" author(s) firm stored in cov*firm
+.\" new date (if .ND exists) is stored in cov*new-date
+.\"
+.\"
+.ds cov*abs-name ABSTRACT
+.\"
+.nr cov*au 0
+.de TL
+.if \\n[.$]>0 .ds cov*title-charge-case \\$1
+.if \\n[.$]>1 .ds cov*title-file-case \\$2
+.pg@disable-top-trap
+.eo
+.de cov*title AU
+..
+.\"-------------------
+.de cov@title-end
+.ec
+..
+.\"-------------------
+.\" .AU name [initials [loc [dept [ext [room [arg [arg [arg]]]]]]]]
+.de AU
+.cov@title-end
+.pg@disable-top-trap
+.if \\n[.$]<1 .@error "AU: no arguments"
+.nr cov*au +1
+.nr cov*i 0 1
+.while \\n[.$]>=\\n+[cov*i] \{\
+. ds cov*au!\\n[cov*au]!\\n[cov*i] "\\$[\\n[cov*i]]
+.\}
+.if (\\n[.$]>=3)&(\w@\\$3@) \{\
+. if d cov*location-\\$3] \{\
+. ds cov*au!3!\\n[cov*au] \\*[cov*location-\\$3]
+. \}
+.\}
+..
+.\"-------------------
+.\" .AT title1 [title2 [... [title9] ]]]]
+.\" Well, thats all that COVEND look for.
+.\" Must appear directly after .AU
+.de AT
+.if \\n[.$]<1 .@error "AT: no arguments"
+.nr cov*i 0 1
+.while \\n[.$]>=\\n+[cov*i] \{\
+. ds cov*at!\\n[cov*au]!\\n[cov*i] "\\$[\\n[cov*i]]
+.\}
+..
+.\"-------------------
+.de AF
+.cov@title-end
+.if \\n[.$]<1 .@error "AF: no arguments"
+.ds cov*firm \\$1
+..
+.de AST
+.ds cov*abs-name \\$1
+..
+.de AS
+.pg@disable-top-trap
+.if d cov*abstract .@error "AS: only one abstract allowed"
+.if !''\\n[.z]' .@error "AS: no diversion allowed (previous .AS?)"
+.nr cov*abs-arg 0\\$1
+.nr cov*abs-ind (n;0\\$2)
+.de cov*abstract AE
+..
+.de AE
+..
+.\" I am planning to use mgm some time :-)
+.ie \\n[yr]<50 .ds cov*new-date \\*[MO\\n[mo]] \\n[dy], 20\\n[yr]
+.el .ds cov*new-date \\*[MO\\n[mo]] \\n[dy], 19\\n[yr]
+.als DT cov*new-date
+.de ND
+.\" don't remember why I did this: .pg@disable-top-trap
+.ds cov*new-date \\$1
+..
+.\"-------------------
+.\" save technical numbers.
+.de TM
+.nr cov*i 0 1
+.while \\n[.$]>=\\n+[cov*i] .ds cov*mt-tm!\\n[cov*i] \\$[\\n[cov*i]]
+.nr cov*mt-tm-max \\n[.$]
+..
+.\"-----------------------
+.\" cover sheet
+.\" the file must have the following last lines (somewhere):
+.\" .pg@enable-top-trap
+.\" .bp 1
+.\" .pg@enable-trap
+.ds cov*mt-file!0 0.MT
+.ds cov*mt-file!1 0.MT
+.ds cov*mt-file!2 0.MT
+.ds cov*mt-file!3 0.MT
+.ds cov*mt-file!4 4.MT
+.ds cov*mt-file!5 5.MT
+.ds cov*mt-file!6 0.MT
+.\"------------
+.de MT
+.ie \\n[.$] \{\
+. ie d cov*mt-file!\\$1 .ds cov*mt-type \\$1
+. el .ds cov*mt-type 6
+.\}
+.el .ds cov*mt-type 1
+.ds cov*mt-addresse "\\$2
+.ds cov*mt-type-text "\\$1
+.ie d @language .ds cov*str mm/\\*[@language]_
+.el .ds cov*str mm/
+.mso \\*[cov*str]\\*[cov*mt-file!\\*[cov*mt-type]]
+..
+.de COVER
+.ie !\\n[.$] .ds cov*cov-type ms
+.el .ds cov*cov-type \\$1
+.pg@disable-top-trap
+.ie d @language .ds cov*str mm/\\*[@language]_\\*[cov*cov-type].cov
+.el .ds cov*str mm/\\*[cov*cov-type].cov
+.mso \\*[cov*str]
+..
+.\"########################### module qrf ############################
+.\" forward and backward reference thru special files.
+.\"
+.\" init reference system
+.de INITR
+.if \\n[.$]<1 .@error "INITR:filename missing"
+.\" ignore if INITR has already been used
+.if !r qrf*pass \{\
+.\"
+. ds qrf*file \\$1
+. sy test -f \\*[qrf*file].tmp
+. ie \\n[systat] \{\
+. \" PASS 1
+. if \\n[D]=1 .tm PASS 1
+. if \\n[D]>1 .tm INITR: file \\*[qrf*file].tmp, PASS 1
+. nr qrf*pass 1
+. open qrf*stream \\*[qrf*file].tmp
+. write qrf*stream .\\\\" references for \\*[qrf*file]
+. close qrf*stream
+. \}
+. el \{\
+. nr qrf*pass 2
+. if \\n[D]=1 .tm PASS 2
+. if \\n[D]>1 .tm INITR: file \\*[qrf*file].tmp, PASS 2
+. sy mv \\*[qrf*file].tmp \\*[qrf*file].qrf
+' so \\*[qrf*file].qrf
+. \}
+.\}
+..
+.\"---------------
+.\" set a reference.
+.de SETR
+.if \\n[.$]<1 .@error "SETR:reference name missing"
+.ie !r qrf*pass .tm "SETR: No .INITR in this file"
+.el \{\
+. ds qrf*name qrf*ref-\\$1
+.\" probably pass two if already defined
+. if \\n[qrf*pass]<2 \{\
+. if \\n[D]>2 .tm SETR: ref \\*[qrf*name]=\\*[hd*toc-mark],\\n[%]
+. \" heading-number
+. ds \\*[qrf*name]-hn \\*[hd*toc-mark]
+. \" page-number
+. ds \\*[qrf*name]-pn \\n[%]
+. \"
+. \" append to file
+. opena qrf*stream \\*[qrf*file].tmp
+. write qrf*stream .ds \\*[qrf*name]-hn \\*[hd*toc-mark]
+. write qrf*stream .ds \\*[qrf*name]-pn \\n[%]
+. if !'\\$2'' .write qrf*stream .ds \\*[qrf*name]-xx \\$2
+. close qrf*stream
+. \}
+.\}
+..
+.\"---------------
+.\" get misc-string, output <->42<-> in pass 1
+.\" If two arg -> set var. arg to misc-string.
+.de GETST
+.if \\n[.$]<1 .@error "GETST:reference name missing"
+.if !r qrf*pass .tm "GETST: No .INITR in this file"
+.ds qrf*name qrf*ref-\\$1
+.ie \\n[qrf*pass]=2 \{\
+. ie !d \\*[qrf*name]-xx .tm "GETHN:\\$1 not defined"
+. el \{\
+. ie \\n[.$]>1 .ds \\$2 \\*[\\*[qrf*name]-xx]
+. el \\*[\\*[qrf*name]-xx]\c
+. \}
+.\}
+.\" The answer...
+.el <->42<->\c
+..
+.\"---------------
+.\" get header-number, output X.X.X. in pass 1
+.\" If two arg -> set var. arg to header-number.
+.de GETHN
+.if \\n[.$]<1 .@error "GETHN:reference name missing"
+.if !r qrf*pass .tm "GETHN: No .INITR in this file"
+.ds qrf*name qrf*ref-\\$1
+.ie \\n[qrf*pass]=2 \{\
+. ie !d \\*[qrf*name]-hn .tm "GETHN:\\$1 not defined"
+. el \{\
+. ie \\n[.$]>1 .ds \\$2 \\*[\\*[qrf*name]-hn]
+. el \\*[\\*[qrf*name]-hn]\c
+. \}
+.\}
+.el X.X.X.\c
+..
+.\"---------------
+.\" get page-number, output 9999 in pass 1
+.\" If two arg -> set var. arg to page-number.
+.de GETPN
+.if \\n[.$]<1 .@error "GETPN:reference name missing"
+.if !r qrf*pass .tm "GETPN: No .INITR in this file"
+.ds qrf*name qrf*ref-\\$1
+.ie \\n[qrf*pass]=2 \{\
+. ie !d \\*[qrf*name]-pn .tm "GETPN:\\$1 not defined"
+. el \{\
+. ie \\n[.$]>1 .ds \\$2 \\*[\\*[qrf*name]-pn]
+. el \\*[\\*[qrf*name]-pn]\c
+. \}
+.\}
+.el 9999\c
+..
+.\"----------
+.de GETR
+.if \\n[.$]<1 .@error "GETR:reference name missing"
+.ie !r qrf*pass \{\
+. tm "GETR: No .INITR in this file"
+.\}
+.el \{\
+. if \\n[qrf*pass]=2 \{\
+. GETHN \\$1 Qrfh
+. GETPN \\$1 Qrfp
+\\*[Qrf]
+. \}
+.\}
+..
diff --git a/gnu/usr.bin/groff/mm/tmac.mse b/gnu/usr.bin/groff/mm/tmac.mse
new file mode 100644
index 0000000..e84babf
--- /dev/null
+++ b/gnu/usr.bin/groff/mm/tmac.mse
@@ -0,0 +1,42 @@
+.\" swedish version of mm
+.\" See tmac.m for version-information.
+.mso tmac.m
+.ds @language se
+.\"
+.ds Lf Figurer
+.ds Lt Tabeller
+.ds Lx Uppställningar
+.ds Le Ekvationer
+.\" Page length
+.if !r L .nr @pl 28.5c
+.\" page width
+.if !r W .nr @ll 13c
+.\" page offset
+.if !r O .nr @po 3.5c
+.\" set the above parameters
+.ll \n[@ll]u
+.po \n[@po]u
+.pl \n[@pl]u
+.ds Lifg Figur
+.ds Litb Tabell
+.ds Liex Uppställning
+.ds Liec Ekvation
+.ds Licon Innehållsförteckning
+.ds Qrf Se kapitel \\*[Qrfh], sidan \\*[Qrfp].
+.ds Rp Referenser
+.\"
+.ds MO1 januari
+.ds MO2 februari
+.ds MO3 mars
+.ds MO4 april
+.ds MO5 maj
+.ds MO6 juni
+.ds MO7 juli
+.ds MO8 augusti
+.ds MO9 september
+.ds MO10 oktober
+.ds MO11 november
+.ds MO12 december
+.ie \\n[yr]<50 .ds cov*new-date \\n[dy] \\*[MO\\n[mo]] 20\\n[yr]
+.el .ds cov*new-date \\n[dy] \\*[MO\\n[mo]] 19\\n[yr]
+.nr pg*footer-size 4\" 1v+footer+even/odd footer+1v
diff --git a/gnu/usr.bin/groff/nroff/Makefile b/gnu/usr.bin/groff/nroff/Makefile
new file mode 100644
index 0000000..6758dd4
--- /dev/null
+++ b/gnu/usr.bin/groff/nroff/Makefile
@@ -0,0 +1,13 @@
+MAN1= nroff.1
+MANDEPEND= nroff.1
+
+CLEANFILES+= ${MANDEPEND}
+
+afterinstall:
+ ${INSTALL} -c -o ${BINOWN} -g ${BINGRP} -m ${BINMODE} \
+ $(.CURDIR)/nroff.sh $(DESTDIR)$(BINDIR)/nroff
+ ${INSTALL} -c -o ${BINOWN} -g ${BINGRP} -m ${BINMODE} \
+ $(.CURDIR)/psroff.sh $(DESTDIR)$(BINDIR)/psroff
+
+.include <../Makefile.cfg>
+.include <bsd.prog.mk>
diff --git a/gnu/usr.bin/groff/nroff/Makefile.sub b/gnu/usr.bin/groff/nroff/Makefile.sub
new file mode 100644
index 0000000..096c046
--- /dev/null
+++ b/gnu/usr.bin/groff/nroff/Makefile.sub
@@ -0,0 +1,17 @@
+MAN1=nroff.n
+NAMEPREFIX=$(g)
+CLEANADD=nroff
+
+all: nroff
+
+nroff: nroff.sh
+ rm -f $@
+ sed "$(SH_SCRIPT_SED_CMD)" $(srcdir)/nroff.sh >$@
+ chmod +x $@
+
+install_data: nroff
+ -rm -f $(bindir)/$(NAMEPREFIX)nroff
+ $(INSTALL_PROGRAM) nroff $(bindir)/$(NAMEPREFIX)nroff
+
+uninstall_sub:
+ -rm -f $(bindir)/$(NAMEPREFIX)nroff
diff --git a/gnu/usr.bin/groff/nroff/conftest.sh b/gnu/usr.bin/groff/nroff/conftest.sh
new file mode 100755
index 0000000..71d21b9
--- /dev/null
+++ b/gnu/usr.bin/groff/nroff/conftest.sh
@@ -0,0 +1,4 @@
+#!/bin/csh
+true || exit 0
+export PATH || exit 0
+exit 1
diff --git a/gnu/usr.bin/groff/nroff/nroff.man b/gnu/usr.bin/groff/nroff/nroff.man
new file mode 100644
index 0000000..fb4bfa7
--- /dev/null
+++ b/gnu/usr.bin/groff/nroff/nroff.man
@@ -0,0 +1,71 @@
+.TH @G@NROFF @MAN1EXT@ "@MDATE@" "Groff Version @VERSION@"
+.SH NAME
+@g@nroff \- emulate nroff command with groff
+.SH SYNOPSIS
+.B @g@nroff
+[
+.B \-h
+]
+[
+.B \-i
+]
+[
+.BI \-m name
+]
+[
+.BI \-n num
+]
+[
+.BI \-o list
+]
+[
+.BI \-r cn
+]
+[
+.BI \-T name
+]
+[
+.I file\|.\|.\|.
+]
+.SH DESCRIPTION
+The
+.B @g@nroff
+script emulates the
+.B nroff
+command using groff.
+The
+.B \-T
+option with an argument other than
+.B ascii
+and
+.B latin1
+and
+.B koi8-r
+will be ignored.
+The
+.B \-h
+option
+is equivalent to the
+.B grotty
+.B \-h
+option.
+The
+.BR \-i ,
+.BR \-n ,
+.BR \-m ,
+.B \-o
+and
+.B \-r
+options have the effect described in
+.BR @g@troff (@MAN1EXT@).
+In addition
+.B @g@nroff
+silently ignores options of
+.BR \-e ,
+.B \-q
+or
+.BR \-s .
+.SH "SEE ALSO"
+.BR groff (@MAN1EXT@),
+.BR @g@troff (@MAN1EXT@),
+.BR grotty (@MAN1EXT@)
diff --git a/gnu/usr.bin/groff/nroff/nroff.sh b/gnu/usr.bin/groff/nroff/nroff.sh
new file mode 100755
index 0000000..246085d
--- /dev/null
+++ b/gnu/usr.bin/groff/nroff/nroff.sh
@@ -0,0 +1,56 @@
+#!/bin/sh
+# Emulate nroff with groff.
+
+prog="$0"
+# Default device.
+T=-Tascii
+opts=
+
+for i
+do
+ case $1 in
+ -h)
+ opts="$opts -P-h"
+ ;;
+ -[eq]|-s*)
+ # ignore these options
+ ;;
+ -[mrnoT])
+ echo "$prog: option $1 requires an argument" >&2
+ exit 1
+ ;;
+ -i|-[mrno]*)
+ opts="$opts $1";
+ ;;
+
+ -Tascii|-Tlatin1|-Tkoi8-r)
+ T=$1
+ ;;
+ -T*)
+ # ignore other devices
+ ;;
+ -u*)
+ # Solaris 2.2 `man' uses -u0; ignore it,
+ # since `less' and `more' can use the emboldening info.
+ ;;
+ --)
+ shift
+ break
+ ;;
+ -)
+ break
+ ;;
+ -*)
+ echo "$prog: invalid option $1" >&2
+ exit 1
+ ;;
+ *)
+ break
+ ;;
+ esac
+ shift
+done
+
+# This shell script is intended for use with man, so warnings are
+# probably not wanted. Also load nroff-style character definitions.
+exec groff -Wall -mtty-char $T $opts ${1+"$@"}
diff --git a/gnu/usr.bin/groff/nroff/psroff.sh b/gnu/usr.bin/groff/nroff/psroff.sh
new file mode 100755
index 0000000..8a90082
--- /dev/null
+++ b/gnu/usr.bin/groff/nroff/psroff.sh
@@ -0,0 +1,2 @@
+#! /bin/sh -
+exec groff -Tps -l -C ${1+"$@"}
diff --git a/gnu/usr.bin/groff/pfbtops/Makefile b/gnu/usr.bin/groff/pfbtops/Makefile
new file mode 100644
index 0000000..b2773a8
--- /dev/null
+++ b/gnu/usr.bin/groff/pfbtops/Makefile
@@ -0,0 +1,12 @@
+# Makefile for pfbtops
+
+PROG= pfbtops
+SRCS= pfbtops.c
+LDADD+= ${LIBGROFF}
+DPADD+= ${LIBGROFF}
+
+MANDEPEND= pfbtops.1
+CLEANFILES+= ${MANDEPEND}
+
+.include "../Makefile.cfg"
+.include <bsd.prog.mk>
diff --git a/gnu/usr.bin/groff/pfbtops/Makefile.dep b/gnu/usr.bin/groff/pfbtops/Makefile.dep
new file mode 100644
index 0000000..2cc41ed
--- /dev/null
+++ b/gnu/usr.bin/groff/pfbtops/Makefile.dep
@@ -0,0 +1 @@
+pfbtops.o : pfbtops.c
diff --git a/gnu/usr.bin/groff/pfbtops/Makefile.sub b/gnu/usr.bin/groff/pfbtops/Makefile.sub
new file mode 100644
index 0000000..a06748e
--- /dev/null
+++ b/gnu/usr.bin/groff/pfbtops/Makefile.sub
@@ -0,0 +1,5 @@
+PROG=pfbtops
+MAN1=pfbtops.n
+OBJS=pfbtops.o
+CSRCS=pfbtops.c
+XLIBS=$(LIBGROFF)
diff --git a/gnu/usr.bin/groff/pfbtops/pfbtops.c b/gnu/usr.bin/groff/pfbtops/pfbtops.c
new file mode 100644
index 0000000..fb370ab
--- /dev/null
+++ b/gnu/usr.bin/groff/pfbtops/pfbtops.c
@@ -0,0 +1,112 @@
+/* This translates ps fonts in .pfb format to ASCII ps files. */
+
+#include <stdio.h>
+
+/* Binary bytes per output line. */
+#define BYTES_PER_LINE (64/2)
+#define HEX_DIGITS "0123456789abcdef"
+
+static char *program_name;
+
+static void error(s)
+ char *s;
+{
+ fprintf(stderr, "%s: %s\n", program_name, s);
+ exit(2);
+}
+
+static void usage()
+{
+ fprintf(stderr, "usage: %s [-v] [pfb_file]\n", program_name);
+ exit(1);
+}
+
+int main(argc, argv)
+ int argc;
+ char **argv;
+{
+ int opt;
+ extern int optind;
+
+ program_name = argv[0];
+
+ while ((opt = getopt(argc, argv, "v")) != EOF) {
+ switch (opt) {
+ case 'v':
+ {
+ extern char *version_string;
+ fprintf(stderr, "pfbtops groff version %s\n", version_string);
+ fflush(stderr);
+ break;
+ }
+ case '?':
+ usage();
+ }
+ }
+
+ if (argc - optind > 1)
+ usage();
+ if (argc > optind && !freopen(argv[optind], "r", stdin))
+ {
+ perror(argv[optind]);
+ exit(1);
+ }
+ for (;;)
+ {
+ int type, c, i;
+ long n;
+
+ c = getchar();
+ if (c != 0x80)
+ error("first byte of packet not 0x80");
+ type = getchar();
+ if (type == 3)
+ break;
+ if (type != 1 && type != 2)
+ error("bad packet type");
+ n = 0;
+ for (i = 0; i < 4; i++)
+ {
+ c = getchar();
+ if (c == EOF)
+ error("end of file in packet header");
+ n |= (long)c << (i << 3);
+ }
+ if (n < 0)
+ error("negative packet length");
+ if (type == 1)
+ {
+ while (--n >= 0)
+ {
+ c = getchar();
+ if (c == EOF)
+ error("end of file in text packet");
+ if (c == '\r')
+ c = '\n';
+ putchar(c);
+ }
+ if (c != '\n')
+ putchar('\n');
+ }
+ else
+ {
+ int count = 0;
+ while (--n >= 0)
+ {
+ c = getchar();
+ if (c == EOF)
+ error("end of file in binary packet");
+ if (count >= BYTES_PER_LINE)
+ {
+ putchar('\n');
+ count = 0;
+ }
+ count++;
+ putchar(HEX_DIGITS[(c >> 4) & 0xf]);
+ putchar(HEX_DIGITS[c & 0xf]);
+ }
+ putchar('\n');
+ }
+ }
+ exit(0);
+}
diff --git a/gnu/usr.bin/groff/pfbtops/pfbtops.man b/gnu/usr.bin/groff/pfbtops/pfbtops.man
new file mode 100644
index 0000000..6e8f5e4
--- /dev/null
+++ b/gnu/usr.bin/groff/pfbtops/pfbtops.man
@@ -0,0 +1,27 @@
+.\" -*- nroff -*-
+.TH PFBTOPS @MAN1EXT@ "@MDATE@" "Groff Version @VERSION@"
+.SH NAME
+pfbtops \- translate a PostScript font in .pfb format to ASCII
+.SH SYNOPSIS
+.B pfbtops
+[
+.I pfb_file
+]
+.SH DESCRIPTION
+.B pfbtops
+translates a PostScript font in
+.B .pfb
+format to ASCII.
+If
+.I pfb_file
+is omitted the pfb file will be read from the standard input.
+The ASCII format PostScript font will be written on the standard output.
+PostScript fonts for MS-DOS are normally supplied in
+.B .pfb
+format.
+.LP
+The resulting ASCII format PostScript font can be used with groff.
+It must first be listed in
+.BR @FONTDIR@/devps/download .
+.SH "SEE ALSO"
+.BR grops (@MAN1EXT@)
diff --git a/gnu/usr.bin/groff/pic/Makefile b/gnu/usr.bin/groff/pic/Makefile
new file mode 100644
index 0000000..5a0e171
--- /dev/null
+++ b/gnu/usr.bin/groff/pic/Makefile
@@ -0,0 +1,16 @@
+# Makefile for pic
+
+PROG= pic
+SRCS= lex.cc main.cc object.cc common.cc troff.cc tex.cc
+OBJS= pic.o
+CFLAGS+= -I. -I${.CURDIR}/../include
+LDADD+= ${LIBGROFF} -lm
+DPADD+= ${LIBGROFF} ${LIBM}
+
+MANDEPEND= pic.1
+CLEANFILES+= pic.cc pic.tab.h ${MANDEPEND}
+
+beforedepend: pic.cc
+
+.include "../Makefile.cfg"
+.include <bsd.prog.mk>
diff --git a/gnu/usr.bin/groff/pic/Makefile.dep b/gnu/usr.bin/groff/pic/Makefile.dep
new file mode 100644
index 0000000..f16199c
--- /dev/null
+++ b/gnu/usr.bin/groff/pic/Makefile.dep
@@ -0,0 +1,22 @@
+lex.o : lex.cc pic.h ../include/assert.h ../include/cset.h ../include/lib.h \
+ ../include/stringclass.h ../include/errarg.h ../include/error.h \
+ position.h text.h output.h ../include/ptable.h object.h pic.cc
+main.o : main.cc pic.h ../include/assert.h ../include/cset.h \
+ ../include/lib.h ../include/stringclass.h ../include/errarg.h \
+ ../include/error.h position.h text.h output.h
+object.o : object.cc pic.h ../include/assert.h ../include/cset.h \
+ ../include/lib.h ../include/stringclass.h ../include/errarg.h \
+ ../include/error.h position.h text.h output.h ../include/ptable.h \
+ object.h
+common.o : common.cc pic.h ../include/assert.h ../include/cset.h \
+ ../include/lib.h ../include/stringclass.h ../include/errarg.h \
+ ../include/error.h position.h text.h output.h common.h
+troff.o : troff.cc pic.h ../include/assert.h ../include/cset.h \
+ ../include/lib.h ../include/stringclass.h ../include/errarg.h \
+ ../include/error.h position.h text.h output.h common.h
+tex.o : tex.cc pic.h ../include/assert.h ../include/cset.h ../include/lib.h \
+ ../include/stringclass.h ../include/errarg.h ../include/error.h \
+ position.h text.h output.h common.h
+pic.o : pic.cc pic.h ../include/assert.h ../include/cset.h ../include/lib.h \
+ ../include/stringclass.h ../include/errarg.h ../include/error.h \
+ position.h text.h output.h ../include/ptable.h object.h
diff --git a/gnu/usr.bin/groff/pic/Makefile.sub b/gnu/usr.bin/groff/pic/Makefile.sub
new file mode 100644
index 0000000..d8ed426
--- /dev/null
+++ b/gnu/usr.bin/groff/pic/Makefile.sub
@@ -0,0 +1,11 @@
+PROG=pic
+MAN1=pic.n
+XLIBS=$(LIBGROFF)
+MLIB=$(LIBM)
+OBJS=pic.o lex.o main.o object.o common.o troff.o tex.o # fig.o
+CCSRCS=lex.cc main.cc object.cc common.cc troff.cc tex.cc
+HDRS=common.h object.h output.h pic.h position.h text.h
+GRAM=pic.y
+YTABC=pic.cc
+YTABH=pic.tab.h
+NAMEPREFIX=$(g)
diff --git a/gnu/usr.bin/groff/pic/TODO b/gnu/usr.bin/groff/pic/TODO
new file mode 100644
index 0000000..2346b57
--- /dev/null
+++ b/gnu/usr.bin/groff/pic/TODO
@@ -0,0 +1,37 @@
+Dotted and dashed ellipses.
+
+In troff mode, dotted and dashed splines.
+
+Make DELIMITED have type lstr; this would allow us to give better
+error messages for problems within the body of for and if constructs.
+
+In troff mode without -x, fake \D't' with .ps commands.
+
+Perhaps an option to set command char.
+
+Add an output class for dumb line printers. It wouldn't be pretty but
+it would be better than nothing. Integrate it with texinfo. Useful
+for groff -Tascii as well.
+
+Option to allow better positioning of arrowheads on arcs.
+
+Perhaps add PostScript output mode.
+
+Change the interface to the output class so that output devices have
+the opportunity to handle arrowheads themselves.
+
+Consider whether the line thickness should scale.
+
+Consider whether the test in a for loop should be fuzzy (as it
+apparently is in grap).
+
+Possibly change fillval so that zero is black.
+
+Provide a way of getting text blocks (positioned with `.in' rather
+than \h), into pic. Should be possible to use block of diverted text
+in pic. Possibly something similar to T{ and T} in tbl.
+
+Option to provide macro backtraces.
+
+Have a path that is searched by `copy' statement. Set by environment
+variable or command line option.
diff --git a/gnu/usr.bin/groff/pic/common.cc b/gnu/usr.bin/groff/pic/common.cc
new file mode 100644
index 0000000..817f1a9
--- /dev/null
+++ b/gnu/usr.bin/groff/pic/common.cc
@@ -0,0 +1,497 @@
+// -*- C++ -*-
+/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
+ Written by James Clark (jjc@jclark.com)
+
+This file is part of groff.
+
+groff is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
+
+groff is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License along
+with groff; see the file COPYING. If not, write to the Free Software
+Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "pic.h"
+#include "common.h"
+
+// output a dashed circle as a series of arcs
+
+void common_output::dashed_circle(const position &cent, double rad,
+ const line_type &lt)
+{
+ assert(lt.type == line_type::dashed);
+ line_type slt = lt;
+ slt.type = line_type::solid;
+ double dash_angle = lt.dash_width/rad;
+ int ndashes;
+ double gap_angle;
+ if (dash_angle >= M_PI/4.0) {
+ if (dash_angle < M_PI/2.0) {
+ gap_angle = M_PI/2.0 - dash_angle;
+ ndashes = 4;
+ }
+ else if (dash_angle < M_PI) {
+ gap_angle = M_PI - dash_angle;
+ ndashes = 2;
+ }
+ else {
+ circle(cent, rad, slt, -1.0);
+ return;
+ }
+ }
+ else {
+ ndashes = 4*int(ceil(M_PI/(4.0*dash_angle)));
+ gap_angle = (M_PI*2.0)/ndashes - dash_angle;
+ }
+ for (int i = 0; i < ndashes; i++) {
+ double start_angle = i*(dash_angle+gap_angle) - dash_angle/2.0;
+ solid_arc(cent, rad, start_angle, start_angle + dash_angle, lt);
+ }
+}
+
+// output a dotted circle as a series of dots
+
+void common_output::dotted_circle(const position &cent, double rad,
+ const line_type &lt)
+{
+ assert(lt.type == line_type::dotted);
+ double gap_angle = lt.dash_width/rad;
+ int ndots;
+ if (gap_angle >= M_PI/2.0) {
+ // always have at least 2 dots
+ gap_angle = M_PI;
+ ndots = 2;
+ }
+ else {
+ ndots = 4*int(M_PI/(2.0*gap_angle));
+ gap_angle = (M_PI*2.0)/ndots;
+ }
+ double ang = 0.0;
+ for (int i = 0; i < ndots; i++, ang += gap_angle)
+ dot(cent + position(cos(ang), sin(ang))*rad, lt);
+}
+
+// return non-zero iff we can compute a center
+
+int compute_arc_center(const position &start, const position &cent,
+ const position &end, position *result)
+{
+ // This finds the point along the vector from start to cent that
+ // is equidistant between start and end.
+ distance c = cent - start;
+ distance e = end - start;
+ double n = c*e;
+ if (n == 0.0)
+ return 0;
+ *result = start + c*((e*e)/(2.0*n));
+ return 1;
+}
+
+// output a dashed arc as a series of arcs
+
+void common_output::dashed_arc(const position &start, const position &cent,
+ const position &end, const line_type &lt)
+{
+ assert(lt.type == line_type::dashed);
+ position c;
+ if (!compute_arc_center(start, cent, end, &c)) {
+ line(start, &end, 1, lt);
+ return;
+ }
+ distance start_offset = start - c;
+ distance end_offset = end - c;
+ double start_angle = atan2(start_offset.y, start_offset.x);
+ double end_angle = atan2(end_offset.y, end_offset.x);
+ double rad = hypot(c - start);
+ double dash_angle = lt.dash_width/rad;
+ double total_angle = end_angle - start_angle;
+ while (total_angle < 0)
+ total_angle += M_PI + M_PI;
+ if (total_angle <= dash_angle*2.0) {
+ solid_arc(cent, rad, start_angle, end_angle, lt);
+ return;
+ }
+ int ndashes = int((total_angle - dash_angle)/(dash_angle*2.0) + .5);
+ double dash_and_gap_angle = (total_angle - dash_angle)/ndashes;
+ for (int i = 0; i <= ndashes; i++)
+ solid_arc(cent, rad, start_angle + i*dash_and_gap_angle,
+ start_angle + i*dash_and_gap_angle + dash_angle, lt);
+}
+
+// output a dotted arc as a series of dots
+
+void common_output::dotted_arc(const position &start, const position &cent,
+ const position &end, const line_type &lt)
+{
+ assert(lt.type == line_type::dotted);
+ position c;
+ if (!compute_arc_center(start, cent, end, &c)) {
+ line(start, &end, 1, lt);
+ return;
+ }
+ distance start_offset = start - c;
+ distance end_offset = end - c;
+ double start_angle = atan2(start_offset.y, start_offset.x);
+ double total_angle = atan2(end_offset.y, end_offset.x) - start_angle;
+ while (total_angle < 0)
+ total_angle += M_PI + M_PI;
+ double rad = hypot(c - start);
+ int ndots = int(total_angle/(lt.dash_width/rad) + .5);
+ if (ndots == 0)
+ dot(start, lt);
+ else {
+ for (int i = 0; i <= ndots; i++) {
+ double a = start_angle + (total_angle*i)/ndots;
+ dot(cent + position(cos(a), sin(a))*rad, lt);
+ }
+ }
+}
+
+void common_output::solid_arc(const position &cent, double rad,
+ double start_angle, double end_angle,
+ const line_type &lt)
+{
+ line_type slt = lt;
+ slt.type = line_type::solid;
+ arc(cent + position(cos(start_angle), sin(start_angle))*rad,
+ cent,
+ cent + position(cos(end_angle), sin(end_angle))*rad,
+ slt);
+}
+
+
+void common_output::rounded_box(const position &cent, const distance &dim,
+ double rad, const line_type &lt, double fill)
+{
+ if (fill >= 0.0)
+ filled_rounded_box(cent, dim, rad, fill);
+ switch (lt.type) {
+ case line_type::invisible:
+ break;
+ case line_type::dashed:
+ dashed_rounded_box(cent, dim, rad, lt);
+ break;
+ case line_type::dotted:
+ dotted_rounded_box(cent, dim, rad, lt);
+ break;
+ case line_type::solid:
+ solid_rounded_box(cent, dim, rad, lt);
+ break;
+ default:
+ assert(0);
+ }
+}
+
+
+void common_output::dashed_rounded_box(const position &cent,
+ const distance &dim, double rad,
+ const line_type &lt)
+{
+ line_type slt = lt;
+ slt.type = line_type::solid;
+
+ double hor_length = dim.x + (M_PI/2.0 - 2.0)*rad;
+ int n_hor_dashes = int(hor_length/(lt.dash_width*2.0) + .5);
+ double hor_gap_width = (n_hor_dashes != 0
+ ? hor_length/n_hor_dashes - lt.dash_width
+ : 0.0);
+
+ double vert_length = dim.y + (M_PI/2.0 - 2.0)*rad;
+ int n_vert_dashes = int(vert_length/(lt.dash_width*2.0) + .5);
+ double vert_gap_width = (n_vert_dashes != 0
+ ? vert_length/n_vert_dashes - lt.dash_width
+ : 0.0);
+ // Note that each corner arc has to be split into two for dashing,
+ // because one part is dashed using vert_gap_width, and the other
+ // using hor_gap_width.
+ double offset = lt.dash_width/2.0;
+ dash_arc(cent + position(dim.x/2.0 - rad, -dim.y/2.0 + rad), rad,
+ -M_PI/4.0, 0, slt, lt.dash_width, vert_gap_width, &offset);
+ dash_line(cent + position(dim.x/2.0, -dim.y/2.0 + rad),
+ cent + position(dim.x/2.0, dim.y/2.0 - rad),
+ slt, lt.dash_width, vert_gap_width, &offset);
+ dash_arc(cent + position(dim.x/2.0 - rad, dim.y/2.0 - rad), rad,
+ 0, M_PI/4.0, slt, lt.dash_width, vert_gap_width, &offset);
+
+ offset = lt.dash_width/2.0;
+ dash_arc(cent + position(dim.x/2.0 - rad, dim.y/2.0 - rad), rad,
+ M_PI/4.0, M_PI/2, slt, lt.dash_width, hor_gap_width, &offset);
+ dash_line(cent + position(dim.x/2.0 - rad, dim.y/2.0),
+ cent + position(-dim.x/2.0 + rad, dim.y/2.0),
+ slt, lt.dash_width, hor_gap_width, &offset);
+ dash_arc(cent + position(-dim.x/2.0 + rad, dim.y/2.0 - rad), rad,
+ M_PI/2, 3*M_PI/4.0, slt, lt.dash_width, hor_gap_width, &offset);
+
+ offset = lt.dash_width/2.0;
+ dash_arc(cent + position(-dim.x/2.0 + rad, dim.y/2.0 - rad), rad,
+ 3.0*M_PI/4.0, M_PI, slt, lt.dash_width, vert_gap_width, &offset);
+ dash_line(cent + position(-dim.x/2.0, dim.y/2.0 - rad),
+ cent + position(-dim.x/2.0, -dim.y/2.0 + rad),
+ slt, lt.dash_width, vert_gap_width, &offset);
+ dash_arc(cent + position(-dim.x/2.0 + rad, -dim.y/2.0 + rad), rad,
+ M_PI, 5.0*M_PI/4.0, slt, lt.dash_width, vert_gap_width, &offset);
+
+ offset = lt.dash_width/2.0;
+ dash_arc(cent + position(-dim.x/2.0 + rad, -dim.y/2.0 + rad), rad,
+ 5*M_PI/4.0, 3*M_PI/2.0, slt, lt.dash_width, hor_gap_width, &offset);
+ dash_line(cent + position(-dim.x/2.0 + rad, -dim.y/2.0),
+ cent + position(dim.x/2.0 - rad, -dim.y/2.0),
+ slt, lt.dash_width, hor_gap_width, &offset);
+ dash_arc(cent + position(dim.x/2.0 - rad, -dim.y/2.0 + rad), rad,
+ 3*M_PI/2, 7*M_PI/4, slt, lt.dash_width, hor_gap_width, &offset);
+}
+
+// Used by dashed_rounded_box.
+
+void common_output::dash_arc(const position &cent, double rad,
+ double start_angle, double end_angle,
+ const line_type &lt,
+ double dash_width, double gap_width,
+ double *offsetp)
+{
+ double length = (end_angle - start_angle)*rad;
+ double pos = 0.0;
+ for (;;) {
+ if (*offsetp >= dash_width) {
+ double rem = dash_width + gap_width - *offsetp;
+ if (pos + rem > length) {
+ *offsetp += length - pos;
+ break;
+ }
+ else {
+ pos += rem;
+ *offsetp = 0.0;
+ }
+ }
+ else {
+ double rem = dash_width - *offsetp;
+ if (pos + rem > length) {
+ solid_arc(cent, rad, start_angle + pos/rad, end_angle, lt);
+ *offsetp += length - pos;
+ break;
+ }
+ else {
+ solid_arc(cent, rad, start_angle + pos/rad,
+ start_angle + (pos + rem)/rad, lt);
+ pos += rem;
+ *offsetp = dash_width;
+ }
+ }
+ }
+}
+
+// Used by dashed_rounded_box.
+
+void common_output::dash_line(const position &start, const position &end,
+ const line_type &lt,
+ double dash_width, double gap_width,
+ double *offsetp)
+{
+ distance dist = end - start;
+ double length = hypot(dist);
+ if (length == 0.0)
+ return;
+ double pos = 0.0;
+ for (;;) {
+ if (*offsetp >= dash_width) {
+ double rem = dash_width + gap_width - *offsetp;
+ if (pos + rem > length) {
+ *offsetp += length - pos;
+ break;
+ }
+ else {
+ pos += rem;
+ *offsetp = 0.0;
+ }
+ }
+ else {
+ double rem = dash_width - *offsetp;
+ if (pos + rem > length) {
+ line(start + dist*(pos/length), &end, 1, lt);
+ *offsetp += length - pos;
+ break;
+ }
+ else {
+ position p(start + dist*((pos + rem)/length));
+ line(start + dist*(pos/length), &p, 1, lt);
+ pos += rem;
+ *offsetp = dash_width;
+ }
+ }
+ }
+}
+
+void common_output::dotted_rounded_box(const position &cent,
+ const distance &dim, double rad,
+ const line_type &lt)
+{
+ line_type slt = lt;
+ slt.type = line_type::solid;
+
+ double hor_length = dim.x + (M_PI/2.0 - 2.0)*rad;
+ int n_hor_dots = int(hor_length/lt.dash_width + .5);
+ double hor_gap_width = (n_hor_dots != 0
+ ? hor_length/n_hor_dots
+ : lt.dash_width);
+
+ double vert_length = dim.y + (M_PI/2.0 - 2.0)*rad;
+ int n_vert_dots = int(vert_length/lt.dash_width + .5);
+ double vert_gap_width = (n_vert_dots != 0
+ ? vert_length/n_vert_dots
+ : lt.dash_width);
+ double epsilon = lt.dash_width/(rad*100.0);
+
+ double offset = 0.0;
+ dot_arc(cent + position(dim.x/2.0 - rad, -dim.y/2.0 + rad), rad,
+ -M_PI/4.0, 0, slt, vert_gap_width, &offset);
+ dot_line(cent + position(dim.x/2.0, -dim.y/2.0 + rad),
+ cent + position(dim.x/2.0, dim.y/2.0 - rad),
+ slt, vert_gap_width, &offset);
+ dot_arc(cent + position(dim.x/2.0 - rad, dim.y/2.0 - rad), rad,
+ 0, M_PI/4.0 - epsilon, slt, vert_gap_width, &offset);
+
+ offset = 0.0;
+ dot_arc(cent + position(dim.x/2.0 - rad, dim.y/2.0 - rad), rad,
+ M_PI/4.0, M_PI/2, slt, hor_gap_width, &offset);
+ dot_line(cent + position(dim.x/2.0 - rad, dim.y/2.0),
+ cent + position(-dim.x/2.0 + rad, dim.y/2.0),
+ slt, hor_gap_width, &offset);
+ dot_arc(cent + position(-dim.x/2.0 + rad, dim.y/2.0 - rad), rad,
+ M_PI/2, 3*M_PI/4.0 - epsilon, slt, hor_gap_width, &offset);
+
+ offset = 0.0;
+ dot_arc(cent + position(-dim.x/2.0 + rad, dim.y/2.0 - rad), rad,
+ 3.0*M_PI/4.0, M_PI, slt, vert_gap_width, &offset);
+ dot_line(cent + position(-dim.x/2.0, dim.y/2.0 - rad),
+ cent + position(-dim.x/2.0, -dim.y/2.0 + rad),
+ slt, vert_gap_width, &offset);
+ dot_arc(cent + position(-dim.x/2.0 + rad, -dim.y/2.0 + rad), rad,
+ M_PI, 5.0*M_PI/4.0 - epsilon, slt, vert_gap_width, &offset);
+
+ offset = 0.0;
+ dot_arc(cent + position(-dim.x/2.0 + rad, -dim.y/2.0 + rad), rad,
+ 5*M_PI/4.0, 3*M_PI/2.0, slt, hor_gap_width, &offset);
+ dot_line(cent + position(-dim.x/2.0 + rad, -dim.y/2.0),
+ cent + position(dim.x/2.0 - rad, -dim.y/2.0),
+ slt, hor_gap_width, &offset);
+ dot_arc(cent + position(dim.x/2.0 - rad, -dim.y/2.0 + rad), rad,
+ 3*M_PI/2, 7*M_PI/4 - epsilon, slt, hor_gap_width, &offset);
+}
+
+// Used by dotted_rounded_box.
+
+void common_output::dot_arc(const position &cent, double rad,
+ double start_angle, double end_angle,
+ const line_type &lt, double gap_width,
+ double *offsetp)
+{
+ double length = (end_angle - start_angle)*rad;
+ double pos = 0.0;
+ for (;;) {
+ if (*offsetp == 0.0) {
+ double ang = start_angle + pos/rad;
+ dot(cent + position(cos(ang), sin(ang))*rad, lt);
+ }
+ double rem = gap_width - *offsetp;
+ if (pos + rem > length) {
+ *offsetp += length - pos;
+ break;
+ }
+ else {
+ pos += rem;
+ *offsetp = 0.0;
+ }
+ }
+}
+
+// Used by dotted_rounded_box.
+
+void common_output::dot_line(const position &start, const position &end,
+ const line_type &lt, double gap_width,
+ double *offsetp)
+{
+ distance dist = end - start;
+ double length = hypot(dist);
+ if (length == 0.0)
+ return;
+ double pos = 0.0;
+ for (;;) {
+ if (*offsetp == 0.0)
+ dot(start + dist*(pos/length), lt);
+ double rem = gap_width - *offsetp;
+ if (pos + rem > length) {
+ *offsetp += length - pos;
+ break;
+ }
+ else {
+ pos += rem;
+ *offsetp = 0.0;
+ }
+ }
+}
+
+
+void common_output::solid_rounded_box(const position &cent,
+ const distance &dim, double rad,
+ const line_type &lt)
+{
+ position tem = cent - dim/2.0;
+ arc(tem + position(0.0, rad),
+ tem + position(rad, rad),
+ tem + position(rad, 0.0),
+ lt);
+ tem = cent + position(-dim.x/2.0, dim.y/2.0);
+ arc(tem + position(rad, 0.0),
+ tem + position(rad, -rad),
+ tem + position(0.0, -rad),
+ lt);
+ tem = cent + dim/2.0;
+ arc(tem + position(0.0, -rad),
+ tem + position(-rad, -rad),
+ tem + position(-rad, 0.0),
+ lt);
+ tem = cent + position(dim.x/2.0, -dim.y/2.0);
+ arc(tem + position(-rad, 0.0),
+ tem + position(-rad, rad),
+ tem + position(0.0, rad),
+ lt);
+ position end;
+ end = cent + position(-dim.x/2.0, dim.y/2.0 - rad);
+ line(cent - dim/2.0 + position(0.0, rad), &end, 1, lt);
+ end = cent + position(dim.x/2.0 - rad, dim.y/2.0);
+ line(cent + position(-dim.x/2.0 + rad, dim.y/2.0), &end, 1, lt);
+ end = cent + position(dim.x/2.0, -dim.y/2.0 + rad);
+ line(cent + position(dim.x/2.0, dim.y/2.0 - rad), &end, 1, lt);
+ end = cent + position(-dim.x/2.0 + rad, -dim.y/2.0);
+ line(cent + position(dim.x/2.0 - rad, -dim.y/2.0), &end, 1, lt);
+}
+
+void common_output::filled_rounded_box(const position &cent,
+ const distance &dim, double rad,
+ double fill)
+{
+ line_type ilt;
+ ilt.type = line_type::invisible;
+ circle(cent + position(dim.x/2.0 - rad, dim.y/2.0 - rad), rad, ilt, fill);
+ circle(cent + position(-dim.x/2.0 + rad, dim.y/2.0 - rad), rad, ilt, fill);
+ circle(cent + position(-dim.x/2.0 + rad, -dim.y/2.0 + rad), rad, ilt, fill);
+ circle(cent + position(dim.x/2.0 - rad, -dim.y/2.0 + rad), rad, ilt, fill);
+ position vec[4];
+ vec[0] = cent + position(dim.x/2.0, dim.y/2.0 - rad);
+ vec[1] = cent + position(-dim.x/2.0, dim.y/2.0 - rad);
+ vec[2] = cent + position(-dim.x/2.0, -dim.y/2.0 + rad);
+ vec[3] = cent + position(dim.x/2.0, -dim.y/2.0 + rad);
+ polygon(vec, 4, ilt, fill);
+ vec[0] = cent + position(dim.x/2.0 - rad, dim.y/2.0);
+ vec[1] = cent + position(-dim.x/2.0 + rad, dim.y/2.0);
+ vec[2] = cent + position(-dim.x/2.0 + rad, -dim.y/2.0);
+ vec[3] = cent + position(dim.x/2.0 - rad, -dim.y/2.0);
+ polygon(vec, 4, ilt, fill);
+}
diff --git a/gnu/usr.bin/groff/pic/common.h b/gnu/usr.bin/groff/pic/common.h
new file mode 100644
index 0000000..47560ce
--- /dev/null
+++ b/gnu/usr.bin/groff/pic/common.h
@@ -0,0 +1,70 @@
+// -*- C++ -*-
+/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
+ Written by James Clark (jjc@jclark.com)
+
+This file is part of groff.
+
+groff is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
+
+groff is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License along
+with groff; see the file COPYING. If not, write to the Free Software
+Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+class common_output : public output {
+private:
+ void dash_line(const position &start, const position &end,
+ const line_type &lt, double dash_width, double gap_width,
+ double *offsetp);
+ void dash_arc(const position &cent, double rad,
+ double start_angle, double end_angle, const line_type &lt,
+ double dash_width, double gap_width, double *offsetp);
+ void dot_line(const position &start, const position &end,
+ const line_type &lt, double gap_width, double *offsetp);
+ void dot_arc(const position &cent, double rad,
+ double start_angle, double end_angle, const line_type &lt,
+ double gap_width, double *offsetp);
+protected:
+ virtual void dot(const position &, const line_type &) = 0;
+ void dashed_circle(const position &, double rad, const line_type &);
+ void dotted_circle(const position &, double rad, const line_type &);
+ void dashed_arc(const position &, const position &, const position &,
+ const line_type &);
+ void dotted_arc(const position &, const position &, const position &,
+ const line_type &);
+ virtual void solid_arc(const position &cent, double rad, double start_angle,
+ double end_angle, const line_type &lt);
+ void dashed_rounded_box(const position &, const distance &, double,
+ const line_type &);
+ void dotted_rounded_box(const position &, const distance &, double,
+ const line_type &);
+ void solid_rounded_box(const position &, const distance &, double,
+ const line_type &);
+ void filled_rounded_box(const position &, const distance &, double, double);
+public:
+ void start_picture(double sc, const position &ll, const position &ur) = 0;
+ void finish_picture() = 0;
+ void circle(const position &, double rad, const line_type &, double) = 0;
+ void text(const position &, text_piece *, int, double) = 0;
+ void line(const position &, const position *, int n, const line_type &) = 0;
+ void polygon(const position *, int n, const line_type &, double) = 0;
+ void spline(const position &, const position *, int n,
+ const line_type &) = 0;
+ void arc(const position &, const position &, const position &,
+ const line_type &) = 0;
+ void ellipse(const position &, const distance &,
+ const line_type &, double) = 0;
+ void rounded_box(const position &, const distance &, double,
+ const line_type &, double);
+};
+
+int compute_arc_center(const position &start, const position &cent,
+ const position &end, position *result);
+
diff --git a/gnu/usr.bin/groff/pic/depend b/gnu/usr.bin/groff/pic/depend
new file mode 100644
index 0000000..73ac3ab
--- /dev/null
+++ b/gnu/usr.bin/groff/pic/depend
@@ -0,0 +1,21 @@
+pic.tab.o : pic.tab.cc pic.h ../lib/assert.h ../lib/cset.h ../lib/lib.h \
+ ../lib/stringclass.h ../lib/errarg.h ../lib/error.h position.h text.h \
+ output.h ../lib/ptable.h object.h
+lex.o : lex.cc pic.h ../lib/assert.h ../lib/cset.h ../lib/lib.h \
+ ../lib/stringclass.h ../lib/errarg.h ../lib/error.h position.h text.h \
+ output.h ../lib/ptable.h object.h pic.tab.h
+main.o : main.cc pic.h ../lib/assert.h ../lib/cset.h ../lib/lib.h \
+ ../lib/stringclass.h ../lib/errarg.h ../lib/error.h position.h text.h \
+ output.h
+object.o : object.cc pic.h ../lib/assert.h ../lib/cset.h ../lib/lib.h \
+ ../lib/stringclass.h ../lib/errarg.h ../lib/error.h position.h text.h \
+ output.h ../lib/ptable.h object.h
+common.o : common.cc pic.h ../lib/assert.h ../lib/cset.h ../lib/lib.h \
+ ../lib/stringclass.h ../lib/errarg.h ../lib/error.h position.h text.h \
+ output.h common.h
+troff.o : troff.cc pic.h ../lib/assert.h ../lib/cset.h ../lib/lib.h \
+ ../lib/stringclass.h ../lib/errarg.h ../lib/error.h position.h text.h \
+ output.h common.h
+tex.o : tex.cc pic.h ../lib/assert.h ../lib/cset.h ../lib/lib.h \
+ ../lib/stringclass.h ../lib/errarg.h ../lib/error.h position.h text.h \
+ output.h common.h
diff --git a/gnu/usr.bin/groff/pic/lex.cc b/gnu/usr.bin/groff/pic/lex.cc
new file mode 100644
index 0000000..33e243e
--- /dev/null
+++ b/gnu/usr.bin/groff/pic/lex.cc
@@ -0,0 +1,1938 @@
+// -*- C++ -*-
+/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
+ Written by James Clark (jjc@jclark.com)
+
+This file is part of groff.
+
+groff is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
+
+groff is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License along
+with groff; see the file COPYING. If not, write to the Free Software
+Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "pic.h"
+#include "ptable.h"
+#include "object.h"
+#include "pic.tab.h"
+
+declare_ptable(char)
+implement_ptable(char)
+
+PTABLE(char) macro_table;
+
+class macro_input : public input {
+ char *s;
+ char *p;
+public:
+ macro_input(const char *);
+ ~macro_input();
+ int get();
+ int peek();
+};
+
+class argument_macro_input : public input {
+ char *s;
+ char *p;
+ char *ap;
+ int argc;
+ char *argv[9];
+public:
+ argument_macro_input(const char *, int, char **);
+ ~argument_macro_input();
+ int get();
+ int peek();
+};
+
+input::input() : next(0)
+{
+}
+
+input::~input()
+{
+}
+
+int input::get_location(const char **, int *)
+{
+ return 0;
+}
+
+file_input::file_input(FILE *f, const char *fn)
+: lineno(0), ptr(""), filename(fn)
+{
+ fp = f;
+}
+
+file_input::~file_input()
+{
+ fclose(fp);
+}
+
+int file_input::read_line()
+{
+ for (;;) {
+ line.clear();
+ lineno++;
+ for (;;) {
+ int c = getc(fp);
+ if (c == EOF)
+ break;
+ else if (illegal_input_char(c))
+ lex_error("illegal input character code %1", c);
+ else {
+ line += char(c);
+ if (c == '\n')
+ break;
+ }
+ }
+ if (line.length() == 0)
+ return 0;
+ if (!(line.length() >= 3 && line[0] == '.' && line[1] == 'P'
+ && (line[2] == 'S' || line[2] == 'E' || line[2] == 'F')
+ && (line.length() == 3 || line[3] == ' ' || line[3] == '\n'
+ || compatible_flag))) {
+ line += '\0';
+ ptr = line.contents();
+ return 1;
+ }
+ }
+}
+
+int file_input::get()
+{
+ if (*ptr != '\0' || read_line())
+ return (unsigned char)*ptr++;
+ else
+ return EOF;
+}
+
+int file_input::peek()
+{
+ if (*ptr != '\0' || read_line())
+ return (unsigned char)*ptr;
+ else
+ return EOF;
+}
+
+int file_input::get_location(const char **fnp, int *lnp)
+{
+ *fnp = filename;
+ *lnp = lineno;
+ return 1;
+}
+
+macro_input::macro_input(const char *str)
+{
+ p = s = strsave(str);
+}
+
+macro_input::~macro_input()
+{
+ a_delete s;
+}
+
+int macro_input::get()
+{
+ if (p == 0 || *p == '\0')
+ return EOF;
+ else
+ return (unsigned char)*p++;
+}
+
+int macro_input::peek()
+{
+ if (p == 0 || *p == '\0')
+ return EOF;
+ else
+ return (unsigned char)*p;
+}
+
+// Character representing $1. Must be illegal input character.
+#define ARG1 14
+
+char *process_body(const char *body)
+{
+ char *s = strsave(body);
+ int j = 0;
+ for (int i = 0; s[i] != '\0'; i++)
+ if (s[i] == '$' && s[i+1] >= '0' && s[i+1] <= '9') {
+ if (s[i+1] != '0')
+ s[j++] = ARG1 + s[++i] - '1';
+ }
+ else
+ s[j++] = s[i];
+ s[j] = '\0';
+ return s;
+}
+
+
+argument_macro_input::argument_macro_input(const char *body, int ac, char **av)
+: argc(ac), ap(0)
+{
+ for (int i = 0; i < argc; i++)
+ argv[i] = av[i];
+ p = s = process_body(body);
+}
+
+
+argument_macro_input::~argument_macro_input()
+{
+ for (int i = 0; i < argc; i++)
+ a_delete argv[i];
+ a_delete s;
+}
+
+int argument_macro_input::get()
+{
+ if (ap) {
+ if (*ap != '\0')
+ return (unsigned char)*ap++;
+ ap = 0;
+ }
+ if (p == 0)
+ return EOF;
+ while (*p >= ARG1 && *p <= ARG1 + 8) {
+ int i = *p++ - ARG1;
+ if (i < argc && argv[i] != 0 && argv[i][0] != '\0') {
+ ap = argv[i];
+ return (unsigned char)*ap++;
+ }
+ }
+ if (*p == '\0')
+ return EOF;
+ return (unsigned char)*p++;
+}
+
+int argument_macro_input::peek()
+{
+ if (ap) {
+ if (*ap != '\0')
+ return (unsigned char)*ap;
+ ap = 0;
+ }
+ if (p == 0)
+ return EOF;
+ while (*p >= ARG1 && *p <= ARG1 + 8) {
+ int i = *p++ - ARG1;
+ if (i < argc && argv[i] != 0 && argv[i][0] != '\0') {
+ ap = argv[i];
+ return (unsigned char)*ap;
+ }
+ }
+ if (*p == '\0')
+ return EOF;
+ return (unsigned char)*p;
+}
+
+class input_stack {
+ static input *current_input;
+ static int bol_flag;
+public:
+ static void push(input *);
+ static void clear();
+ static int get_char();
+ static int peek_char();
+ static int get_location(const char **fnp, int *lnp);
+ static void push_back(unsigned char c, int was_bol = 0);
+ static int bol();
+};
+
+input *input_stack::current_input = 0;
+int input_stack::bol_flag = 0;
+
+inline int input_stack::bol()
+{
+ return bol_flag;
+}
+
+void input_stack::clear()
+{
+ while (current_input != 0) {
+ input *tem = current_input;
+ current_input = current_input->next;
+ delete tem;
+ }
+ bol_flag = 1;
+}
+
+void input_stack::push(input *in)
+{
+ in->next = current_input;
+ current_input = in;
+}
+
+void lex_init(input *top)
+{
+ input_stack::clear();
+ input_stack::push(top);
+}
+
+void lex_cleanup()
+{
+ while (input_stack::get_char() != EOF)
+ ;
+}
+
+int input_stack::get_char()
+{
+ while (current_input != 0) {
+ int c = current_input->get();
+ if (c != EOF) {
+ bol_flag = c == '\n';
+ return c;
+ }
+ // don't pop the top-level input off the stack
+ if (current_input->next == 0)
+ return EOF;
+ input *tem = current_input;
+ current_input = current_input->next;
+ delete tem;
+ }
+ return EOF;
+}
+
+int input_stack::peek_char()
+{
+ while (current_input != 0) {
+ int c = current_input->peek();
+ if (c != EOF)
+ return c;
+ if (current_input->next == 0)
+ return EOF;
+ input *tem = current_input;
+ current_input = current_input->next;
+ delete tem;
+ }
+ return EOF;
+}
+
+class char_input : public input {
+ int c;
+public:
+ char_input(int);
+ int get();
+ int peek();
+};
+
+char_input::char_input(int n) : c((unsigned char)n)
+{
+}
+
+int char_input::get()
+{
+ int n = c;
+ c = EOF;
+ return n;
+}
+
+int char_input::peek()
+{
+ return c;
+}
+
+void input_stack::push_back(unsigned char c, int was_bol)
+{
+ push(new char_input(c));
+ bol_flag = was_bol;
+}
+
+int input_stack::get_location(const char **fnp, int *lnp)
+{
+ for (input *p = current_input; p; p = p->next)
+ if (p->get_location(fnp, lnp))
+ return 1;
+ return 0;
+}
+
+string context_buffer;
+
+string token_buffer;
+double token_double;
+int token_int;
+
+void interpolate_macro_with_args(const char *body)
+{
+ char *argv[9];
+ int argc = 0;
+ for (int i = 0; i < 9; i++)
+ argv[i] = 0;
+ int level = 0;
+ int c;
+ enum { NORMAL, IN_STRING, IN_STRING_QUOTED } state = NORMAL;
+ do {
+ token_buffer.clear();
+ for (;;) {
+ c = input_stack::get_char();
+ if (c == EOF) {
+ lex_error("end of input while scanning macro arguments");
+ break;
+ }
+ if (state == NORMAL && level == 0 && (c == ',' || c == ')')) {
+ if (token_buffer.length() > 0) {
+ token_buffer += '\0';
+ argv[argc] = strsave(token_buffer.contents());
+ }
+ // for `foo()', argc = 0
+ if (argc > 0 || c != ')' || i > 0)
+ argc++;
+ break;
+ }
+ token_buffer += char(c);
+ switch (state) {
+ case NORMAL:
+ if (c == '"')
+ state = IN_STRING;
+ else if (c == '(')
+ level++;
+ else if (c == ')')
+ level--;
+ break;
+ case IN_STRING:
+ if (c == '"')
+ state = NORMAL;
+ else if (c == '\\')
+ state = IN_STRING_QUOTED;
+ break;
+ case IN_STRING_QUOTED:
+ state = IN_STRING;
+ break;
+ }
+ }
+ } while (c != ')' && c != EOF);
+ input_stack::push(new argument_macro_input(body, argc, argv));
+}
+
+static int docmp(const char *s1, int n1, const char *s2, int n2)
+{
+ if (n1 < n2) {
+ int r = memcmp(s1, s2, n1);
+ return r ? r : -1;
+ }
+ else if (n1 > n2) {
+ int r = memcmp(s1, s2, n2);
+ return r ? r : 1;
+ }
+ else
+ return memcmp(s1, s2, n1);
+}
+
+int lookup_keyword(const char *str, int len)
+{
+ static struct keyword {
+ const char *name;
+ int token;
+ } table[] = {
+ { "Here", HERE },
+ { "above", ABOVE },
+ { "aligned", ALIGNED },
+ { "and", AND },
+ { "arc", ARC },
+ { "arrow", ARROW },
+ { "at", AT },
+ { "atan2", ATAN2 },
+ { "below", BELOW },
+ { "between", BETWEEN },
+ { "bottom", BOTTOM },
+ { "box", BOX },
+ { "by", BY },
+ { "ccw", CCW },
+ { "center", CENTER },
+ { "chop", CHOP },
+ { "circle", CIRCLE },
+ { "command", COMMAND },
+ { "copy", COPY },
+ { "cos", COS },
+ { "cw", CW },
+ { "dashed", DASHED },
+ { "define", DEFINE },
+ { "diam", DIAMETER },
+ { "diameter", DIAMETER },
+ { "do", DO },
+ { "dotted", DOTTED },
+ { "down", DOWN },
+ { "ellipse", ELLIPSE },
+ { "else", ELSE },
+ { "end", END },
+ { "exp", EXP },
+ { "fill", FILL },
+ { "filled", FILL },
+ { "for", FOR },
+ { "from", FROM },
+ { "height", HEIGHT },
+ { "ht", HEIGHT },
+ { "if", IF },
+ { "int", INT },
+ { "invis", INVISIBLE },
+ { "invisible", INVISIBLE },
+ { "last", LAST },
+ { "left", LEFT },
+ { "line", LINE },
+ { "ljust", LJUST },
+ { "log", LOG },
+ { "lower", LOWER },
+ { "max", K_MAX },
+ { "min", K_MIN },
+ { "move", MOVE },
+ { "of", OF },
+ { "plot", PLOT },
+ { "print", PRINT },
+ { "rad", RADIUS },
+ { "radius", RADIUS },
+ { "rand", RAND },
+ { "reset", RESET },
+ { "right", RIGHT },
+ { "rjust", RJUST },
+ { "same", SAME },
+ { "sh", SH },
+ { "sin", SIN },
+ { "spline", SPLINE },
+ { "sprintf", SPRINTF },
+ { "sqrt", SQRT },
+ { "start", START },
+ { "the", THE },
+ { "then", THEN },
+ { "thick", THICKNESS },
+ { "thickness", THICKNESS },
+ { "thru", THRU },
+ { "to", TO },
+ { "top", TOP },
+ { "undef", UNDEF },
+ { "until", UNTIL },
+ { "up", UP },
+ { "upper", UPPER },
+ { "way", WAY },
+ { "wid", WIDTH },
+ { "width", WIDTH },
+ { "with", WITH },
+ };
+
+ const keyword *start = table;
+ const keyword *end = table + sizeof(table)/sizeof(table[0]);
+ while (start < end) {
+ // start <= target < end
+ const keyword *mid = start + (end - start)/2;
+
+ int cmp = docmp(str, len, mid->name, strlen(mid->name));
+ if (cmp == 0)
+ return mid->token;
+ if (cmp < 0)
+ end = mid;
+ else
+ start = mid + 1;
+ }
+ return 0;
+}
+
+int get_token_after_dot(int c)
+{
+ // get_token deals with the case where c is a digit
+ switch (c) {
+ case 'h':
+ input_stack::get_char();
+ c = input_stack::peek_char();
+ if (c == 't') {
+ input_stack::get_char();
+ context_buffer = ".ht";
+ return DOT_HT;
+ }
+ else if (c == 'e') {
+ input_stack::get_char();
+ c = input_stack::peek_char();
+ if (c == 'i') {
+ input_stack::get_char();
+ c = input_stack::peek_char();
+ if (c == 'g') {
+ input_stack::get_char();
+ c = input_stack::peek_char();
+ if (c == 'h') {
+ input_stack::get_char();
+ c = input_stack::peek_char();
+ if (c == 't') {
+ input_stack::get_char();
+ context_buffer = ".height";
+ return DOT_HT;
+ }
+ input_stack::push_back('h');
+ }
+ input_stack::push_back('g');
+ }
+ input_stack::push_back('i');
+ }
+ input_stack::push_back('e');
+ }
+ input_stack::push_back('h');
+ return '.';
+ case 'x':
+ input_stack::get_char();
+ context_buffer = ".x";
+ return DOT_X;
+ case 'y':
+ input_stack::get_char();
+ context_buffer = ".y";
+ return DOT_Y;
+ case 'c':
+ input_stack::get_char();
+ c = input_stack::peek_char();
+ if (c == 'e') {
+ input_stack::get_char();
+ c = input_stack::peek_char();
+ if (c == 'n') {
+ input_stack::get_char();
+ c = input_stack::peek_char();
+ if (c == 't') {
+ input_stack::get_char();
+ c = input_stack::peek_char();
+ if (c == 'e') {
+ input_stack::get_char();
+ c = input_stack::peek_char();
+ if (c == 'r') {
+ input_stack::get_char();
+ context_buffer = ".center";
+ return DOT_C;
+ }
+ input_stack::push_back('e');
+ }
+ input_stack::push_back('t');
+ }
+ input_stack::push_back('n');
+ }
+ input_stack::push_back('e');
+ }
+ context_buffer = ".c";
+ return DOT_C;
+ case 'n':
+ input_stack::get_char();
+ c = input_stack::peek_char();
+ if (c == 'e') {
+ input_stack::get_char();
+ context_buffer = ".ne";
+ return DOT_NE;
+ }
+ else if (c == 'w') {
+ input_stack::get_char();
+ context_buffer = ".nw";
+ return DOT_NW;
+ }
+ else {
+ context_buffer = ".n";
+ return DOT_N;
+ }
+ break;
+ case 'e':
+ input_stack::get_char();
+ c = input_stack::peek_char();
+ if (c == 'n') {
+ input_stack::get_char();
+ c = input_stack::peek_char();
+ if (c == 'd') {
+ input_stack::get_char();
+ context_buffer = ".end";
+ return DOT_END;
+ }
+ input_stack::push_back('n');
+ context_buffer = ".e";
+ return DOT_E;
+ }
+ context_buffer = ".e";
+ return DOT_E;
+ case 'w':
+ input_stack::get_char();
+ c = input_stack::peek_char();
+ if (c == 'i') {
+ input_stack::get_char();
+ c = input_stack::peek_char();
+ if (c == 'd') {
+ input_stack::get_char();
+ c = input_stack::peek_char();
+ if (c == 't') {
+ input_stack::get_char();
+ c = input_stack::peek_char();
+ if (c == 'h') {
+ input_stack::get_char();
+ context_buffer = ".width";
+ return DOT_WID;
+ }
+ input_stack::push_back('t');
+ }
+ context_buffer = ".wid";
+ return DOT_WID;
+ }
+ input_stack::push_back('i');
+ }
+ context_buffer = ".w";
+ return DOT_W;
+ case 's':
+ input_stack::get_char();
+ c = input_stack::peek_char();
+ if (c == 'e') {
+ input_stack::get_char();
+ context_buffer = ".se";
+ return DOT_SE;
+ }
+ else if (c == 'w') {
+ input_stack::get_char();
+ context_buffer = ".sw";
+ return DOT_SW;
+ }
+ else {
+ if (c == 't') {
+ input_stack::get_char();
+ c = input_stack::peek_char();
+ if (c == 'a') {
+ input_stack::get_char();
+ c = input_stack::peek_char();
+ if (c == 'r') {
+ input_stack::get_char();
+ c = input_stack::peek_char();
+ if (c == 't') {
+ input_stack::get_char();
+ context_buffer = ".start";
+ return DOT_START;
+ }
+ input_stack::push_back('r');
+ }
+ input_stack::push_back('a');
+ }
+ input_stack::push_back('t');
+ }
+ context_buffer = ".s";
+ return DOT_S;
+ }
+ break;
+ case 't':
+ input_stack::get_char();
+ c = input_stack::peek_char();
+ if (c == 'o') {
+ input_stack::get_char();
+ c = input_stack::peek_char();
+ if (c == 'p') {
+ input_stack::get_char();
+ context_buffer = ".top";
+ return DOT_N;
+ }
+ input_stack::push_back('o');
+ }
+ context_buffer = ".t";
+ return DOT_N;
+ case 'l':
+ input_stack::get_char();
+ c = input_stack::peek_char();
+ if (c == 'e') {
+ input_stack::get_char();
+ c = input_stack::peek_char();
+ if (c == 'f') {
+ input_stack::get_char();
+ c = input_stack::peek_char();
+ if (c == 't') {
+ input_stack::get_char();
+ context_buffer = ".left";
+ return DOT_W;
+ }
+ input_stack::push_back('f');
+ }
+ input_stack::push_back('e');
+ }
+ context_buffer = ".l";
+ return DOT_W;
+ case 'r':
+ input_stack::get_char();
+ c = input_stack::peek_char();
+ if (c == 'a') {
+ input_stack::get_char();
+ c = input_stack::peek_char();
+ if (c == 'd') {
+ input_stack::get_char();
+ context_buffer = ".rad";
+ return DOT_RAD;
+ }
+ input_stack::push_back('a');
+ }
+ else if (c == 'i') {
+ input_stack::get_char();
+ c = input_stack::peek_char();
+ if (c == 'g') {
+ input_stack::get_char();
+ c = input_stack::peek_char();
+ if (c == 'h') {
+ input_stack::get_char();
+ c = input_stack::peek_char();
+ if (c == 't') {
+ input_stack::get_char();
+ context_buffer = ".right";
+ return DOT_E;
+ }
+ input_stack::push_back('h');
+ }
+ input_stack::push_back('g');
+ }
+ input_stack::push_back('i');
+ }
+ context_buffer = ".r";
+ return DOT_E;
+ case 'b':
+ input_stack::get_char();
+ c = input_stack::peek_char();
+ if (c == 'o') {
+ input_stack::get_char();
+ c = input_stack::peek_char();
+ if (c == 't') {
+ input_stack::get_char();
+ c = input_stack::peek_char();
+ if (c == 't') {
+ input_stack::get_char();
+ c = input_stack::peek_char();
+ if (c == 'o') {
+ input_stack::get_char();
+ c = input_stack::peek_char();
+ if (c == 'm') {
+ input_stack::get_char();
+ context_buffer = ".bottom";
+ return DOT_S;
+ }
+ input_stack::push_back('o');
+ }
+ input_stack::push_back('t');
+ }
+ context_buffer = ".bot";
+ return DOT_S;
+ }
+ input_stack::push_back('o');
+ }
+ context_buffer = ".b";
+ return DOT_S;
+ default:
+ context_buffer = '.';
+ return '.';
+ }
+}
+
+int get_token(int lookup_flag)
+{
+ context_buffer.clear();
+ for (;;) {
+ int n = 0;
+ int bol = input_stack::bol();
+ int c = input_stack::get_char();
+ if (bol && c == command_char) {
+ token_buffer.clear();
+ token_buffer += c;
+ // the newline is not part of the token
+ for (;;) {
+ c = input_stack::peek_char();
+ if (c == EOF || c == '\n')
+ break;
+ input_stack::get_char();
+ token_buffer += char(c);
+ }
+ context_buffer = token_buffer;
+ return COMMAND_LINE;
+ }
+ switch (c) {
+ case EOF:
+ return EOF;
+ case ' ':
+ case '\t':
+ break;
+ case '\\':
+ {
+ int d = input_stack::peek_char();
+ if (d != '\n') {
+ context_buffer = '\\';
+ return '\\';
+ }
+ input_stack::get_char();
+ break;
+ }
+ case '#':
+ do {
+ c = input_stack::get_char();
+ } while (c != '\n' && c != EOF);
+ if (c == '\n')
+ context_buffer = '\n';
+ return c;
+ case '"':
+ context_buffer = '"';
+ token_buffer.clear();
+ for (;;) {
+ c = input_stack::get_char();
+ if (c == '\\') {
+ context_buffer += '\\';
+ c = input_stack::peek_char();
+ if (c == '"') {
+ input_stack::get_char();
+ token_buffer += '"';
+ context_buffer += '"';
+ }
+ else
+ token_buffer += '\\';
+ }
+ else if (c == '\n') {
+ error("newline in string");
+ break;
+ }
+ else if (c == EOF) {
+ error("missing `\"'");
+ break;
+ }
+ else if (c == '"') {
+ context_buffer += '"';
+ break;
+ }
+ else {
+ context_buffer += char(c);
+ token_buffer += char(c);
+ }
+ }
+ return TEXT;
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ {
+ int overflow = 0;
+ n = 0;
+ for (;;) {
+ if (n > (INT_MAX - 9)/10) {
+ overflow = 1;
+ break;
+ }
+ n *= 10;
+ n += c - '0';
+ context_buffer += char(c);
+ c = input_stack::peek_char();
+ if (c == EOF || !csdigit(c))
+ break;
+ c = input_stack::get_char();
+ }
+ token_double = n;
+ if (overflow) {
+ for (;;) {
+ token_double *= 10.0;
+ token_double += c - '0';
+ context_buffer += char(c);
+ c = input_stack::peek_char();
+ if (c == EOF || !csdigit(c))
+ break;
+ c = input_stack::get_char();
+ }
+ // if somebody asks for 1000000000000th, we will silently
+ // give them INT_MAXth
+ double temp = token_double; // work around gas 1.34/sparc bug
+ if (token_double > INT_MAX)
+ n = INT_MAX;
+ else
+ n = int(temp);
+ }
+ }
+ switch (c) {
+ case 'i':
+ case 'I':
+ context_buffer += char(c);
+ input_stack::get_char();
+ return NUMBER;
+ case '.':
+ {
+ context_buffer += '.';
+ input_stack::get_char();
+ got_dot:
+ double factor = 1.0;
+ for (;;) {
+ c = input_stack::peek_char();
+ if (!c == EOF || !csdigit(c))
+ break;
+ input_stack::get_char();
+ context_buffer += char(c);
+ factor /= 10.0;
+ if (c != '0')
+ token_double += factor*(c - '0');
+ }
+ if (c != 'e' && c != 'E') {
+ if (c == 'i' || c == 'I') {
+ context_buffer += char(c);
+ input_stack::get_char();
+ }
+ return NUMBER;
+ }
+ }
+ // fall through
+ case 'e':
+ case 'E':
+ {
+ int echar = c;
+ input_stack::get_char();
+ c = input_stack::peek_char();
+ int sign = '+';
+ if (c == '+' || c == '-') {
+ sign = c;
+ input_stack::get_char();
+ c = input_stack::peek_char();
+ if (c == EOF || !csdigit(c)) {
+ input_stack::push_back(sign);
+ input_stack::push_back(echar);
+ return NUMBER;
+ }
+ context_buffer += char(echar);
+ context_buffer += char(sign);
+ }
+ else {
+ if (c == EOF || !csdigit(c)) {
+ input_stack::push_back(echar);
+ return NUMBER;
+ }
+ context_buffer += char(echar);
+ }
+ input_stack::get_char();
+ context_buffer += char(c);
+ n = c - '0';
+ for (;;) {
+ c = input_stack::peek_char();
+ if (c == EOF || !csdigit(c))
+ break;
+ input_stack::get_char();
+ context_buffer += char(c);
+ n = n*10 + (c - '0');
+ }
+ if (sign == '-')
+ n = -n;
+ if (c == 'i' || c == 'I') {
+ context_buffer += char(c);
+ input_stack::get_char();
+ }
+ token_double *= pow(10.0, n);
+ return NUMBER;
+ }
+ case 'n':
+ input_stack::get_char();
+ c = input_stack::peek_char();
+ if (c == 'd') {
+ input_stack::get_char();
+ token_int = n;
+ context_buffer += "nd";
+ return ORDINAL;
+ }
+ input_stack::push_back('n');
+ return NUMBER;
+ case 'r':
+ input_stack::get_char();
+ c = input_stack::peek_char();
+ if (c == 'd') {
+ input_stack::get_char();
+ token_int = n;
+ context_buffer += "rd";
+ return ORDINAL;
+ }
+ input_stack::push_back('r');
+ return NUMBER;
+ case 't':
+ input_stack::get_char();
+ c = input_stack::peek_char();
+ if (c == 'h') {
+ input_stack::get_char();
+ token_int = n;
+ context_buffer += "th";
+ return ORDINAL;
+ }
+ input_stack::push_back('t');
+ return NUMBER;
+ case 's':
+ input_stack::get_char();
+ c = input_stack::peek_char();
+ if (c == 't') {
+ input_stack::get_char();
+ token_int = n;
+ context_buffer += "st";
+ return ORDINAL;
+ }
+ input_stack::push_back('s');
+ return NUMBER;
+ default:
+ return NUMBER;
+ }
+ break;
+ case '\'':
+ {
+ c = input_stack::peek_char();
+ if (c == 't') {
+ input_stack::get_char();
+ c = input_stack::peek_char();
+ if (c == 'h') {
+ input_stack::get_char();
+ context_buffer = "'th";
+ return TH;
+ }
+ else
+ input_stack::push_back('t');
+ }
+ context_buffer = "'";
+ return '\'';
+ }
+ case '.':
+ {
+ c = input_stack::peek_char();
+ if (c != EOF && csdigit(c)) {
+ n = 0;
+ token_double = 0.0;
+ context_buffer = '.';
+ goto got_dot;
+ }
+ return get_token_after_dot(c);
+ }
+ case '<':
+ c = input_stack::peek_char();
+ if (c == '-') {
+ input_stack::get_char();
+ c = input_stack::peek_char();
+ if (c == '>') {
+ input_stack::get_char();
+ context_buffer = "<->";
+ return DOUBLE_ARROW_HEAD;
+ }
+ context_buffer = "<-";
+ return LEFT_ARROW_HEAD;
+ }
+ else if (c == '=') {
+ input_stack::get_char();
+ context_buffer = "<=";
+ return LESSEQUAL;
+ }
+ context_buffer = "<";
+ return '<';
+ case '-':
+ c = input_stack::peek_char();
+ if (c == '>') {
+ input_stack::get_char();
+ context_buffer = "->";
+ return RIGHT_ARROW_HEAD;
+ }
+ context_buffer = "-";
+ return '-';
+ case '!':
+ c = input_stack::peek_char();
+ if (c == '=') {
+ input_stack::get_char();
+ context_buffer = "!=";
+ return NOTEQUAL;
+ }
+ context_buffer = "!";
+ return '!';
+ case '>':
+ c = input_stack::peek_char();
+ if (c == '=') {
+ input_stack::get_char();
+ context_buffer = ">=";
+ return GREATEREQUAL;
+ }
+ context_buffer = ">";
+ return '>';
+ case '=':
+ c = input_stack::peek_char();
+ if (c == '=') {
+ input_stack::get_char();
+ context_buffer = "==";
+ return EQUALEQUAL;
+ }
+ context_buffer = "=";
+ return '=';
+ case '&':
+ c = input_stack::peek_char();
+ if (c == '&') {
+ input_stack::get_char();
+ context_buffer = "&&";
+ return ANDAND;
+ }
+ context_buffer = "&";
+ return '&';
+ case '|':
+ c = input_stack::peek_char();
+ if (c == '|') {
+ input_stack::get_char();
+ context_buffer = "||";
+ return OROR;
+ }
+ context_buffer = "|";
+ return '|';
+ default:
+ if (c != EOF && csalpha(c)) {
+ token_buffer.clear();
+ token_buffer = c;
+ for (;;) {
+ c = input_stack::peek_char();
+ if (c == EOF || (!csalnum(c) && c != '_'))
+ break;
+ input_stack::get_char();
+ token_buffer += char(c);
+ }
+ int tok = lookup_keyword(token_buffer.contents(),
+ token_buffer.length());
+ if (tok != 0) {
+ context_buffer = token_buffer;
+ return tok;
+ }
+ char *def = 0;
+ if (lookup_flag) {
+ token_buffer += '\0';
+ def = macro_table.lookup(token_buffer.contents());
+ token_buffer.set_length(token_buffer.length() - 1);
+ if (def) {
+ if (c == '(') {
+ input_stack::get_char();
+ interpolate_macro_with_args(def);
+ }
+ else
+ input_stack::push(new macro_input(def));
+ }
+ }
+ if (!def) {
+ context_buffer = token_buffer;
+ if (csupper(token_buffer[0]))
+ return LABEL;
+ else
+ return VARIABLE;
+ }
+ }
+ else {
+ context_buffer = char(c);
+ return (unsigned char)c;
+ }
+ break;
+ }
+ }
+}
+
+int get_delimited()
+{
+ token_buffer.clear();
+ int c = input_stack::get_char();
+ while (c == ' ' || c == '\t' || c == '\n')
+ c = input_stack::get_char();
+ if (c == EOF) {
+ lex_error("missing delimiter");
+ return 0;
+ }
+ context_buffer = char(c);
+ int had_newline = 0;
+ int start = c;
+ int level = 0;
+ enum { NORMAL, IN_STRING, IN_STRING_QUOTED, DELIM_END } state = NORMAL;
+ for (;;) {
+ c = input_stack::get_char();
+ if (c == EOF) {
+ lex_error("missing closing delimiter");
+ return 0;
+ }
+ if (c == '\n')
+ had_newline = 1;
+ else if (!had_newline)
+ context_buffer += char(c);
+ switch (state) {
+ case NORMAL:
+ if (start == '{') {
+ if (c == '{') {
+ level++;
+ break;
+ }
+ if (c == '}') {
+ if (--level < 0)
+ state = DELIM_END;
+ break;
+ }
+ }
+ else {
+ if (c == start) {
+ state = DELIM_END;
+ break;
+ }
+ }
+ if (c == '"')
+ state = IN_STRING;
+ break;
+ case IN_STRING_QUOTED:
+ if (c == '\n')
+ state = NORMAL;
+ else
+ state = IN_STRING;
+ break;
+ case IN_STRING:
+ if (c == '"' || c == '\n')
+ state = NORMAL;
+ else if (c == '\\')
+ state = IN_STRING_QUOTED;
+ break;
+ case DELIM_END:
+ // This case it just to shut cfront 2.0 up.
+ default:
+ assert(0);
+ }
+ if (state == DELIM_END)
+ break;
+ token_buffer += c;
+ }
+ return 1;
+}
+
+void do_define()
+{
+ int t = get_token(0); // do not expand what we are defining
+ if (t != VARIABLE && t != LABEL) {
+ lex_error("can only define variable or placename");
+ return;
+ }
+ token_buffer += '\0';
+ string nm = token_buffer;
+ const char *name = nm.contents();
+ if (!get_delimited())
+ return;
+ token_buffer += '\0';
+ macro_table.define(name, strsave(token_buffer.contents()));
+}
+
+void do_undef()
+{
+ int t = get_token(0); // do not expand what we are undefining
+ if (t != VARIABLE && t != LABEL) {
+ lex_error("can only define variable or placename");
+ return;
+ }
+ token_buffer += '\0';
+ macro_table.define(token_buffer.contents(), 0);
+}
+
+
+class for_input : public input {
+ char *var;
+ char *body;
+ double to;
+ int by_is_multiplicative;
+ double by;
+ const char *p;
+ int done_newline;
+public:
+ for_input(char *, double, int, double, char *);
+ ~for_input();
+ int get();
+ int peek();
+};
+
+for_input::for_input(char *vr, double t, int bim, double b, char *bd)
+: var(vr), to(t), by_is_multiplicative(bim), by(b), body(bd), p(body),
+ done_newline(0)
+{
+}
+
+for_input::~for_input()
+{
+ a_delete var;
+ a_delete body;
+}
+
+int for_input::get()
+{
+ if (p == 0)
+ return EOF;
+ for (;;) {
+ if (*p != '\0')
+ return (unsigned char)*p++;
+ if (!done_newline) {
+ done_newline = 1;
+ return '\n';
+ }
+ double val;
+ if (!lookup_variable(var, &val)) {
+ lex_error("body of `for' terminated enclosing block");
+ return EOF;
+ }
+ if (by_is_multiplicative)
+ val *= by;
+ else
+ val += by;
+ define_variable(var, val);
+ if (val > to) {
+ p = 0;
+ return EOF;
+ }
+ p = body;
+ done_newline = 0;
+ }
+}
+
+int for_input::peek()
+{
+ if (p == 0)
+ return EOF;
+ if (*p != '\0')
+ return (unsigned char)*p;
+ if (!done_newline)
+ return '\n';
+ double val;
+ if (!lookup_variable(var, &val))
+ return EOF;
+ if (by_is_multiplicative) {
+ if (val * by > to)
+ return EOF;
+ }
+ else {
+ if (val + by > to)
+ return EOF;
+ }
+ if (*body == '\0')
+ return EOF;
+ return (unsigned char)*body;
+}
+
+void do_for(char *var, double from, double to, int by_is_multiplicative,
+ double by, char *body)
+{
+ define_variable(var, from);
+ if (from <= to)
+ input_stack::push(new for_input(var, to, by_is_multiplicative, by, body));
+}
+
+
+void do_copy(const char *filename)
+{
+ errno = 0;
+ FILE *fp = fopen(filename, "r");
+ if (fp == 0) {
+ lex_error("can't open `%1': %2", filename, strerror(errno));
+ return;
+ }
+ input_stack::push(new file_input(fp, filename));
+}
+
+class copy_thru_input : public input {
+ int done;
+ char *body;
+ char *until;
+ const char *p;
+ const char *ap;
+ int argv[9];
+ int argc;
+ string line;
+ int get_line();
+ virtual int inget() = 0;
+public:
+ copy_thru_input(const char *b, const char *u);
+ ~copy_thru_input();
+ int get();
+ int peek();
+};
+
+class copy_file_thru_input : public copy_thru_input {
+ input *in;
+public:
+ copy_file_thru_input(input *, const char *b, const char *u);
+ ~copy_file_thru_input();
+ int inget();
+};
+
+copy_file_thru_input::copy_file_thru_input(input *i, const char *b,
+ const char *u)
+: in(i), copy_thru_input(b, u)
+{
+}
+
+copy_file_thru_input::~copy_file_thru_input()
+{
+ delete in;
+}
+
+int copy_file_thru_input::inget()
+{
+ if (!in)
+ return EOF;
+ else
+ return in->get();
+}
+
+class copy_rest_thru_input : public copy_thru_input {
+public:
+ copy_rest_thru_input(const char *, const char *u);
+ int inget();
+};
+
+copy_rest_thru_input::copy_rest_thru_input(const char *b, const char *u)
+: copy_thru_input(b, u)
+{
+}
+
+int copy_rest_thru_input::inget()
+{
+ while (next != 0) {
+ int c = next->get();
+ if (c != EOF)
+ return c;
+ if (next->next == 0)
+ return EOF;
+ input *tem = next;
+ next = next->next;
+ delete tem;
+ }
+ return EOF;
+
+}
+
+copy_thru_input::copy_thru_input(const char *b, const char *u)
+: done(0)
+{
+ ap = 0;
+ body = process_body(b);
+ p = 0;
+ until = strsave(u);
+}
+
+
+copy_thru_input::~copy_thru_input()
+{
+ a_delete body;
+ a_delete until;
+}
+
+int copy_thru_input::get()
+{
+ if (ap) {
+ if (*ap != '\0')
+ return (unsigned char)*ap++;
+ ap = 0;
+ }
+ for (;;) {
+ if (p == 0) {
+ if (!get_line())
+ break;
+ p = body;
+ }
+ if (*p == '\0') {
+ p = 0;
+ return '\n';
+ }
+ while (*p >= ARG1 && *p <= ARG1 + 8) {
+ int i = *p++ - ARG1;
+ if (i < argc && line[argv[i]] != '\0') {
+ ap = line.contents() + argv[i];
+ return (unsigned char)*ap++;
+ }
+ }
+ if (*p != '\0')
+ return (unsigned char)*p++;
+ }
+ return EOF;
+}
+
+int copy_thru_input::peek()
+{
+ if (ap) {
+ if (*ap != '\0')
+ return (unsigned char)*ap;
+ ap = 0;
+ }
+ for (;;) {
+ if (p == 0) {
+ if (!get_line())
+ break;
+ p = body;
+ }
+ if (*p == '\0')
+ return '\n';
+ while (*p >= ARG1 && *p <= ARG1 + 8) {
+ int i = *p++ - ARG1;
+ if (i < argc && line[argv[i]] != '\0') {
+ ap = line.contents() + argv[i];
+ return (unsigned char)*ap;
+ }
+ }
+ if (*p != '\0')
+ return (unsigned char)*p;
+ }
+ return EOF;
+}
+
+int copy_thru_input::get_line()
+{
+ if (done)
+ return 0;
+ line.clear();
+ argc = 0;
+ int c = inget();
+ for (;;) {
+ while (c == ' ')
+ c = inget();
+ if (c == EOF || c == '\n')
+ break;
+ if (argc == 9) {
+ do {
+ c = inget();
+ } while (c != '\n' && c != EOF);
+ break;
+ }
+ argv[argc++] = line.length();
+ do {
+ line += char(c);
+ c = inget();
+ } while (c != ' ' && c != '\n');
+ line += '\0';
+ }
+ if (until != 0 && argc > 0 && strcmp(&line[argv[0]], until) == 0) {
+ done = 1;
+ return 0;
+ }
+ return argc > 0 || c == '\n';
+}
+
+class simple_file_input : public input {
+ const char *filename;
+ int lineno;
+ FILE *fp;
+public:
+ simple_file_input(FILE *, const char *);
+ ~simple_file_input();
+ int get();
+ int peek();
+ int get_location(const char **, int *);
+};
+
+simple_file_input::simple_file_input(FILE *p, const char *s)
+: filename(s), fp(p), lineno(1)
+{
+}
+
+simple_file_input::~simple_file_input()
+{
+ // don't delete the filename
+ fclose(fp);
+}
+
+int simple_file_input::get()
+{
+ int c = getc(fp);
+ while (illegal_input_char(c)) {
+ error("illegal input character code %1", c);
+ c = getc(fp);
+ }
+ if (c == '\n')
+ lineno++;
+ return c;
+}
+
+int simple_file_input::peek()
+{
+ int c = getc(fp);
+ while (illegal_input_char(c)) {
+ error("illegal input character code %1", c);
+ c = getc(fp);
+ }
+ if (c != EOF)
+ ungetc(c, fp);
+ return c;
+}
+
+int simple_file_input::get_location(const char **fnp, int *lnp)
+{
+ *fnp = filename;
+ *lnp = lineno;
+ return 1;
+}
+
+
+void copy_file_thru(const char *filename, const char *body, const char *until)
+{
+ errno = 0;
+ FILE *fp = fopen(filename, "r");
+ if (fp == 0) {
+ lex_error("can't open `%1': %2", filename, strerror(errno));
+ return;
+ }
+ input *in = new copy_file_thru_input(new simple_file_input(fp, filename),
+ body, until);
+ input_stack::push(in);
+}
+
+void copy_rest_thru(const char *body, const char *until)
+{
+ input_stack::push(new copy_rest_thru_input(body, until));
+}
+
+void push_body(const char *s)
+{
+ input_stack::push(new char_input('\n'));
+ input_stack::push(new macro_input(s));
+}
+
+int delim_flag = 0;
+
+char *get_thru_arg()
+{
+ int c = input_stack::peek_char();
+ while (c == ' ') {
+ input_stack::get_char();
+ c = input_stack::peek_char();
+ }
+ if (c != EOF && csalpha(c)) {
+ // looks like a macro
+ input_stack::get_char();
+ token_buffer = c;
+ for (;;) {
+ c = input_stack::peek_char();
+ if (c == EOF || (!csalnum(c) && c != '_'))
+ break;
+ input_stack::get_char();
+ token_buffer += char(c);
+ }
+ context_buffer = token_buffer;
+ token_buffer += '\0';
+ char *def = macro_table.lookup(token_buffer.contents());
+ if (def)
+ return strsave(def);
+ // I guess it wasn't a macro after all; so push the macro name back.
+ // -2 because we added a '\0'
+ for (int i = token_buffer.length() - 2; i >= 0; i--)
+ input_stack::push_back(token_buffer[i]);
+ }
+ if (get_delimited()) {
+ token_buffer += '\0';
+ return strsave(token_buffer.contents());
+ }
+ else
+ return 0;
+}
+
+int lookahead_token = -1;
+string old_context_buffer;
+
+void do_lookahead()
+{
+ if (lookahead_token == -1) {
+ old_context_buffer = context_buffer;
+ lookahead_token = get_token(1);
+ }
+}
+
+int yylex()
+{
+ if (delim_flag) {
+ assert(lookahead_token == -1);
+ if (delim_flag == 2) {
+ if ((yylval.str = get_thru_arg()) != 0)
+ return DELIMITED;
+ else
+ return 0;
+ }
+ else {
+ if (get_delimited()) {
+ token_buffer += '\0';
+ yylval.str = strsave(token_buffer.contents());
+ return DELIMITED;
+ }
+ else
+ return 0;
+ }
+ }
+ for (;;) {
+ int t;
+ if (lookahead_token >= 0) {
+ t = lookahead_token;
+ lookahead_token = -1;
+ }
+ else
+ t = get_token(1);
+ switch (t) {
+ case '\n':
+ return ';';
+ case EOF:
+ return 0;
+ case DEFINE:
+ do_define();
+ break;
+ case UNDEF:
+ do_undef();
+ break;
+ case ORDINAL:
+ yylval.n = token_int;
+ return t;
+ case NUMBER:
+ yylval.x = token_double;
+ return t;
+ case COMMAND_LINE:
+ case TEXT:
+ token_buffer += '\0';
+ if (!input_stack::get_location(&yylval.lstr.filename,
+ &yylval.lstr.lineno)) {
+ yylval.lstr.filename = 0;
+ yylval.lstr.lineno = -1;
+ }
+ yylval.lstr.str = strsave(token_buffer.contents());
+ return t;
+ case LABEL:
+ case VARIABLE:
+ token_buffer += '\0';
+ yylval.str = strsave(token_buffer.contents());
+ return t;
+ case LEFT:
+ // change LEFT to LEFT_CORNER when followed by OF
+ old_context_buffer = context_buffer;
+ lookahead_token = get_token(1);
+ if (lookahead_token == OF)
+ return LEFT_CORNER;
+ else
+ return t;
+ case RIGHT:
+ // change RIGHT to RIGHT_CORNER when followed by OF
+ old_context_buffer = context_buffer;
+ lookahead_token = get_token(1);
+ if (lookahead_token == OF)
+ return RIGHT_CORNER;
+ else
+ return t;
+ case UPPER:
+ // recognise UPPER only before LEFT or RIGHT
+ old_context_buffer = context_buffer;
+ lookahead_token = get_token(1);
+ if (lookahead_token != LEFT && lookahead_token != RIGHT) {
+ yylval.str = strsave("upper");
+ return VARIABLE;
+ }
+ else
+ return t;
+ case LOWER:
+ // recognise LOWER only before LEFT or RIGHT
+ old_context_buffer = context_buffer;
+ lookahead_token = get_token(1);
+ if (lookahead_token != LEFT && lookahead_token != RIGHT) {
+ yylval.str = strsave("lower");
+ return VARIABLE;
+ }
+ else
+ return t;
+ case TOP:
+ // recognise TOP only before OF
+ old_context_buffer = context_buffer;
+ lookahead_token = get_token(1);
+ if (lookahead_token != OF) {
+ yylval.str = strsave("top");
+ return VARIABLE;
+ }
+ else
+ return t;
+ case BOTTOM:
+ // recognise BOTTOM only before OF
+ old_context_buffer = context_buffer;
+ lookahead_token = get_token(1);
+ if (lookahead_token != OF) {
+ yylval.str = strsave("bottom");
+ return VARIABLE;
+ }
+ else
+ return t;
+ case CENTER:
+ // recognise CENTER only before OF
+ old_context_buffer = context_buffer;
+ lookahead_token = get_token(1);
+ if (lookahead_token != OF) {
+ yylval.str = strsave("center");
+ return VARIABLE;
+ }
+ else
+ return t;
+ case START:
+ // recognise START only before OF
+ old_context_buffer = context_buffer;
+ lookahead_token = get_token(1);
+ if (lookahead_token != OF) {
+ yylval.str = strsave("start");
+ return VARIABLE;
+ }
+ else
+ return t;
+ case END:
+ // recognise END only before OF
+ old_context_buffer = context_buffer;
+ lookahead_token = get_token(1);
+ if (lookahead_token != OF) {
+ yylval.str = strsave("end");
+ return VARIABLE;
+ }
+ else
+ return t;
+ default:
+ return t;
+ }
+ }
+}
+
+void lex_error(const char *message,
+ const errarg &arg1,
+ const errarg &arg2,
+ const errarg &arg3)
+{
+ const char *filename;
+ int lineno;
+ if (!input_stack::get_location(&filename, &lineno))
+ error(message, arg1, arg2, arg3);
+ else
+ error_with_file_and_line(filename, lineno, message, arg1, arg2, arg3);
+}
+
+void lex_warning(const char *message,
+ const errarg &arg1,
+ const errarg &arg2,
+ const errarg &arg3)
+{
+ const char *filename;
+ int lineno;
+ if (!input_stack::get_location(&filename, &lineno))
+ warning(message, arg1, arg2, arg3);
+ else
+ warning_with_file_and_line(filename, lineno, message, arg1, arg2, arg3);
+}
+
+void yyerror(const char *s)
+{
+ const char *filename;
+ int lineno;
+ const char *context = 0;
+ if (lookahead_token == -1) {
+ if (context_buffer.length() > 0) {
+ context_buffer += '\0';
+ context = context_buffer.contents();
+ }
+ }
+ else {
+ if (old_context_buffer.length() > 0) {
+ old_context_buffer += '\0';
+ context = old_context_buffer.contents();
+ }
+ }
+ if (!input_stack::get_location(&filename, &lineno)) {
+ if (context) {
+ if (context[0] == '\n' && context[1] == '\0')
+ error("%1 before newline", s);
+ else
+ error("%1 before `%2'", s, context);
+ }
+ else
+ error("%1 at end of picture", s);
+ }
+ else {
+ if (context) {
+ if (context[0] == '\n' && context[1] == '\0')
+ error_with_file_and_line(filename, lineno, "%1 before newline", s);
+ else
+ error_with_file_and_line(filename, lineno, "%1 before `%2'",
+ s, context);
+ }
+ else
+ error_with_file_and_line(filename, lineno, "%1 at end of picture", s);
+ }
+}
+
diff --git a/gnu/usr.bin/groff/pic/main.cc b/gnu/usr.bin/groff/pic/main.cc
new file mode 100644
index 0000000..7b82ec7
--- /dev/null
+++ b/gnu/usr.bin/groff/pic/main.cc
@@ -0,0 +1,611 @@
+// -*- C++ -*-
+/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
+ Written by James Clark (jjc@jclark.com)
+
+This file is part of groff.
+
+groff is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
+
+groff is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License along
+with groff; see the file COPYING. If not, write to the Free Software
+Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "pic.h"
+
+extern int yyparse();
+
+output *out;
+
+int flyback_flag;
+int zero_length_line_flag = 0;
+// Non-zero means we're using a groff driver.
+int driver_extension_flag = 1;
+int compatible_flag = 0;
+int command_char = '.'; // the character that introduces lines
+ // that should be passed through tranparently
+static int lf_flag = 1; // non-zero if we should attempt to understand
+ // lines beginning with `.lf'
+
+void do_file(const char *filename);
+
+class top_input : public input {
+ FILE *fp;
+ int bol;
+ int eof;
+ int push_back[3];
+ int start_lineno;
+public:
+ top_input(FILE *);
+ int get();
+ int peek();
+ int get_location(const char **, int *);
+};
+
+top_input::top_input(FILE *p) : fp(p), bol(1), eof(0)
+{
+ push_back[0] = push_back[1] = push_back[2] = EOF;
+ start_lineno = current_lineno;
+}
+
+int top_input::get()
+{
+ if (eof)
+ return EOF;
+ if (push_back[2] != EOF) {
+ int c = push_back[2];
+ push_back[2] = EOF;
+ return c;
+ }
+ else if (push_back[1] != EOF) {
+ int c = push_back[1];
+ push_back[1] = EOF;
+ return c;
+ }
+ else if (push_back[0] != EOF) {
+ int c = push_back[0];
+ push_back[0] = EOF;
+ return c;
+ }
+ int c = getc(fp);
+ while (illegal_input_char(c)) {
+ error("illegal input character code %1", int(c));
+ c = getc(fp);
+ bol = 0;
+ }
+ if (bol && c == '.') {
+ c = getc(fp);
+ if (c == 'P') {
+ c = getc(fp);
+ if (c == 'F' || c == 'E') {
+ int d = getc(fp);
+ if (d != EOF)
+ ungetc(d, fp);
+ if (d == EOF || d == ' ' || d == '\n' || compatible_flag) {
+ eof = 1;
+ flyback_flag = c == 'F';
+ return EOF;
+ }
+ push_back[0] = c;
+ push_back[1] = 'P';
+ return '.';
+ }
+ if (c == 'S') {
+ c = getc(fp);
+ if (c != EOF)
+ ungetc(c, fp);
+ if (c == EOF || c == ' ' || c == '\n' || compatible_flag) {
+ error("nested .PS");
+ eof = 1;
+ return EOF;
+ }
+ push_back[0] = 'S';
+ push_back[1] = 'P';
+ return '.';
+ }
+ if (c != EOF)
+ ungetc(c, fp);
+ push_back[0] = 'P';
+ return '.';
+ }
+ else {
+ if (c != EOF)
+ ungetc(c, fp);
+ return '.';
+ }
+ }
+ if (c == '\n') {
+ bol = 1;
+ current_lineno++;
+ return '\n';
+ }
+ bol = 0;
+ if (c == EOF) {
+ eof = 1;
+ error("end of file before .PE or .PF");
+ error_with_file_and_line(current_filename, start_lineno - 1,
+ ".PS was here");
+ }
+ return c;
+}
+
+int top_input::peek()
+{
+ if (eof)
+ return EOF;
+ if (push_back[2] != EOF)
+ return push_back[2];
+ if (push_back[1] != EOF)
+ return push_back[1];
+ if (push_back[0] != EOF)
+ return push_back[0];
+ int c = getc(fp);
+ while (illegal_input_char(c)) {
+ error("illegal input character code %1", int(c));
+ c = getc(fp);
+ bol = 0;
+ }
+ if (bol && c == '.') {
+ c = getc(fp);
+ if (c == 'P') {
+ c = getc(fp);
+ if (c == 'F' || c == 'E') {
+ int d = getc(fp);
+ if (d != EOF)
+ ungetc(d, fp);
+ if (d == EOF || d == ' ' || d == '\n' || compatible_flag) {
+ eof = 1;
+ flyback_flag = c == 'F';
+ return EOF;
+ }
+ push_back[0] = c;
+ push_back[1] = 'P';
+ push_back[2] = '.';
+ return '.';
+ }
+ if (c == 'S') {
+ c = getc(fp);
+ if (c != EOF)
+ ungetc(c, fp);
+ if (c == EOF || c == ' ' || c == '\n' || compatible_flag) {
+ error("nested .PS");
+ eof = 1;
+ return EOF;
+ }
+ push_back[0] = 'S';
+ push_back[1] = 'P';
+ push_back[2] = '.';
+ return '.';
+ }
+ if (c != EOF)
+ ungetc(c, fp);
+ push_back[0] = 'P';
+ push_back[1] = '.';
+ return '.';
+ }
+ else {
+ if (c != EOF)
+ ungetc(c, fp);
+ push_back[0] = '.';
+ return '.';
+ }
+ }
+ if (c != EOF)
+ ungetc(c, fp);
+ if (c == '\n')
+ return '\n';
+ return c;
+}
+
+int top_input::get_location(const char **filenamep, int *linenop)
+{
+ *filenamep = current_filename;
+ *linenop = current_lineno;
+ return 1;
+}
+
+void do_picture(FILE *fp)
+{
+ flyback_flag = 0;
+ int c;
+ while ((c = getc(fp)) == ' ')
+ ;
+ if (c == '<') {
+ string filename;
+ while ((c = getc(fp)) == ' ')
+ ;
+ while (c != EOF && c != ' ' && c != '\n') {
+ filename += char(c);
+ c = getc(fp);
+ }
+ if (c == ' ') {
+ do {
+ c = getc(fp);
+ } while (c != EOF && c != '\n');
+ }
+ if (c == '\n')
+ current_lineno++;
+ if (filename.length() == 0)
+ error("missing filename after `<'");
+ else {
+ filename += '\0';
+ const char *old_filename = current_filename;
+ int old_lineno = current_lineno;
+ // filenames must be permanent
+ do_file(strsave(filename.contents()));
+ current_filename = old_filename;
+ current_lineno = old_lineno;
+ }
+ out->set_location(current_filename, current_lineno);
+ }
+ else {
+ out->set_location(current_filename, current_lineno);
+ string start_line;
+ while (c != EOF) {
+ if (c == '\n') {
+ current_lineno++;
+ break;
+ }
+ start_line += c;
+ c = getc(fp);
+ }
+ if (c == EOF)
+ return;
+ start_line += '\0';
+ double wid, ht;
+ switch (sscanf(&start_line[0], "%lf %lf", &wid, &ht)) {
+ case 1:
+ ht = 0.0;
+ break;
+ case 2:
+ break;
+ default:
+ ht = wid = 0.0;
+ break;
+ }
+ out->set_desired_width_height(wid, ht);
+ out->set_args(start_line.contents());
+ lex_init(new top_input(fp));
+ if (yyparse())
+ lex_error("giving up on this picture");
+ parse_cleanup();
+ lex_cleanup();
+
+ // skip the rest of the .PF/.PE line
+ while ((c = getc(fp)) != EOF && c != '\n')
+ ;
+ if (c == '\n')
+ current_lineno++;
+ out->set_location(current_filename, current_lineno);
+ }
+}
+
+void do_file(const char *filename)
+{
+ FILE *fp;
+ if (strcmp(filename, "-") == 0)
+ fp = stdin;
+ else {
+ errno = 0;
+ fp = fopen(filename, "r");
+ if (fp == 0)
+ fatal("can't open `%1': %2", filename, strerror(errno));
+ }
+ out->set_location(filename, 1);
+ current_filename = filename;
+ current_lineno = 1;
+ enum { START, MIDDLE, HAD_DOT, HAD_P, HAD_PS, HAD_l, HAD_lf } state = START;
+ for (;;) {
+ int c = getc(fp);
+ if (c == EOF)
+ break;
+ switch (state) {
+ case START:
+ if (c == '.')
+ state = HAD_DOT;
+ else {
+ putchar(c);
+ if (c == '\n') {
+ current_lineno++;
+ state = START;
+ }
+ else
+ state = MIDDLE;
+ }
+ break;
+ case MIDDLE:
+ putchar(c);
+ if (c == '\n') {
+ current_lineno++;
+ state = START;
+ }
+ break;
+ case HAD_DOT:
+ if (c == 'P')
+ state = HAD_P;
+ else if (lf_flag && c == 'l')
+ state = HAD_l;
+ else {
+ putchar('.');
+ putchar(c);
+ if (c == '\n') {
+ current_lineno++;
+ state = START;
+ }
+ else
+ state = MIDDLE;
+ }
+ break;
+ case HAD_P:
+ if (c == 'S')
+ state = HAD_PS;
+ else {
+ putchar('.');
+ putchar('P');
+ putchar(c);
+ if (c == '\n') {
+ current_lineno++;
+ state = START;
+ }
+ else
+ state = MIDDLE;
+ }
+ break;
+ case HAD_PS:
+ if (c == ' ' || c == '\n' || compatible_flag) {
+ ungetc(c, fp);
+ do_picture(fp);
+ state = START;
+ }
+ else {
+ fputs(".PS", stdout);
+ putchar(c);
+ state = MIDDLE;
+ }
+ break;
+ case HAD_l:
+ if (c == 'f')
+ state = HAD_lf;
+ else {
+ putchar('.');
+ putchar('l');
+ putchar(c);
+ if (c == '\n') {
+ current_lineno++;
+ state = START;
+ }
+ else
+ state = MIDDLE;
+ }
+ break;
+ case HAD_lf:
+ if (c == ' ' || c == '\n' || compatible_flag) {
+ string line;
+ while (c != EOF) {
+ line += c;
+ if (c == '\n') {
+ current_lineno++;
+ break;
+ }
+ c = getc(fp);
+ }
+ line += '\0';
+ interpret_lf_args(line.contents());
+ printf(".lf%s", line.contents());
+ state = START;
+ }
+ else {
+ fputs(".lf", stdout);
+ putchar(c);
+ state = MIDDLE;
+ }
+ break;
+ default:
+ assert(0);
+ }
+ }
+ switch (state) {
+ case START:
+ break;
+ case MIDDLE:
+ putchar('\n');
+ break;
+ case HAD_DOT:
+ fputs(".\n", stdout);
+ break;
+ case HAD_P:
+ fputs(".P\n", stdout);
+ break;
+ case HAD_PS:
+ fputs(".PS\n", stdout);
+ break;
+ case HAD_l:
+ fputs(".l\n", stdout);
+ break;
+ case HAD_lf:
+ fputs(".lf\n", stdout);
+ break;
+ }
+ if (fp != stdin)
+ fclose(fp);
+}
+
+#ifdef FIG_SUPPORT
+void do_whole_file(const char *filename)
+{
+ // Do not set current_filename.
+ FILE *fp;
+ if (strcmp(filename, "-") == 0)
+ fp = stdin;
+ else {
+ errno = 0;
+ fp = fopen(filename, "r");
+ if (fp == 0)
+ fatal("can't open `%1': %2", filename, strerror(errno));
+ }
+ lex_init(new file_input(fp, filename));
+ yyparse();
+ parse_cleanup();
+ lex_cleanup();
+}
+#endif
+
+void usage()
+{
+ fprintf(stderr, "usage: %s [ -nvC ] [ filename ... ]\n", program_name);
+#ifdef TEX_SUPPORT
+ fprintf(stderr, " %s -t [ -cvzC ] [ filename ... ]\n", program_name);
+#endif
+#ifdef FIG_SUPPORT
+ fprintf(stderr, " %s -f [ -v ] [ filename ]\n", program_name);
+#endif
+ exit(1);
+}
+
+#ifdef __MSDOS__
+static char *fix_program_name(char *arg, char *dflt)
+{
+ if (!arg)
+ return dflt;
+ char *prog = strchr(arg, '\0');
+ for (;;) {
+ if (prog == arg)
+ break;
+ --prog;
+ if (strchr("\\/:", *prog)) {
+ prog++;
+ break;
+ }
+ }
+ char *ext = strchr(prog, '.');
+ if (ext)
+ *ext = '\0';
+ for (char *p = prog; *p; p++)
+ if ('A' <= *p && *p <= 'Z')
+ *p = 'a' + (*p - 'A');
+ return prog;
+}
+#endif /* __MSDOS__ */
+
+int main(int argc, char **argv)
+{
+#ifdef __MSDOS__
+ argv[0] = fix_program_name(argv[0], "pic");
+#endif /* __MSDOS__ */
+ program_name = argv[0];
+ static char stderr_buf[BUFSIZ];
+ setbuf(stderr, stderr_buf);
+ int opt;
+#ifdef TEX_SUPPORT
+ int tex_flag = 0;
+ int tpic_flag = 0;
+#endif
+#ifdef FIG_SUPPORT
+ int whole_file_flag = 0;
+ int fig_flag = 0;
+#endif
+ while ((opt = getopt(argc, argv, "T:CDtcvnxzpf")) != EOF)
+ switch (opt) {
+ case 'C':
+ compatible_flag = 1;
+ break;
+ case 'D':
+ case 'T':
+ break;
+ case 'f':
+#ifdef FIG_SUPPORT
+ whole_file_flag++;
+ fig_flag++;
+#else
+ fatal("fig support not included");
+#endif
+ break;
+ case 'n':
+ driver_extension_flag = 0;
+ break;
+ case 'p':
+ case 'x':
+ warning("-%1 option is obsolete", char(opt));
+ break;
+ case 't':
+#ifdef TEX_SUPPORT
+ tex_flag++;
+#else
+ fatal("TeX support not included");
+#endif
+ break;
+ case 'c':
+#ifdef TEX_SUPPORT
+ tpic_flag++;
+#else
+ fatal("TeX support not included");
+#endif
+ break;
+ case 'v':
+ {
+ extern const char *version_string;
+ fprintf(stderr, "GNU pic version %s\n", version_string);
+ fflush(stderr);
+ break;
+ }
+ case 'z':
+ // zero length lines will be printed as dots
+ zero_length_line_flag++;
+ break;
+ case '?':
+ usage();
+ break;
+ default:
+ assert(0);
+ }
+ parse_init();
+#ifdef TEX_SUPPORT
+ if (tpic_flag) {
+ out = make_tpic_output();
+ lf_flag = 0;
+ }
+ else if (tex_flag) {
+ out = make_tex_output();
+ command_char = '\\';
+ lf_flag = 0;
+ }
+ else
+#endif
+#ifdef FIG_SUPPORT
+ if (fig_flag)
+ out = make_fig_output();
+ else
+#endif
+ out = make_troff_output();
+#ifdef FIG_SUPPORT
+ if (whole_file_flag) {
+ if (optind >= argc)
+ do_whole_file("-");
+ else if (argc - optind > 1)
+ usage();
+ else
+ do_whole_file(argv[optind]);
+ }
+ else {
+#endif
+ if (optind >= argc)
+ do_file("-");
+ else
+ for (int i = optind; i < argc; i++)
+ do_file(argv[i]);
+#ifdef FIG_SUPPORT
+ }
+#endif
+ delete out;
+ if (ferror(stdout) || fflush(stdout) < 0)
+ fatal("output error");
+ return 0;
+}
+
diff --git a/gnu/usr.bin/groff/pic/make-dos-dist b/gnu/usr.bin/groff/pic/make-dos-dist
new file mode 100755
index 0000000..9f546a0
--- /dev/null
+++ b/gnu/usr.bin/groff/pic/make-dos-dist
@@ -0,0 +1,299 @@
+#! /bin/sh
+
+# This creates a compressed (14 bits) tar file that can be copied to a DOS
+# machine, unpacked and compiled with Borland C++ 2.0.
+
+# This is for groff version 1.04. It will probably need work for
+# other versions.
+
+# The grammar is yacced here, because I don't have a yacc on my DOS
+# machine. The resulting .tab.c file is split up; I found the
+# compiler ran out of memory otherwise. The sed command that does the
+# splitting assumes you're using the SunOS 4.1.1 yacc.
+# (Bison-generated parsers need alloca() which Borland C++ does not
+# have.) You'll need to tweak it for other yaccs: in particular you'll
+# need to change the `tabs' variable, so that it matches the names of
+# the external arrays of ints generated by your version yacc: it is
+# these that are split off into another file. You may also need to
+# change tabtype to `short' if the tables are arrays of shorts.
+
+picdir=`pwd`
+tarfile=pic_tar
+tabs="yyexca yyact yypact yypgo yyr1 yyr2 yychk yydef"
+tabtype=int
+file1=pic_tab1.c
+file2=pic_tab2.c
+
+rm -fr temp
+mkdir temp
+cd temp
+
+
+yacc -d $picdir/pic.y
+
+for tab in $tabs; do echo "/$tabtype $tab\\[]/i\\
+extern $tabtype $tab[];
+/$tabtype $tab\\[]/,/;/{
+w $file2
+d
+}"; done >split.sed
+
+sed -f split.sed y.tab.c >$file1
+
+rm -f split.sed y.tab.c
+
+mv y.tab.h pic_tab.h
+
+libfiles="change_lf.c cset.c cset.h errarg.c errarg.h error.c error.h \
+fatal.c filename.c version.c lf.c lib.h lineno.c new.c string.c \
+stringclass.h progname.c strerror.c strsave.c ptable.c ptable.h"
+
+picfiles="common.c common.h lex.c main.c object.c object.h output.h \
+pic.h position.h tex.c text.h troff.c"
+
+for file in $picfiles
+do
+ sed -e '/^#include/s/pic\.tab\.h/pic_tab.h/' $picdir/$file >$file
+done
+
+for file in $libfiles; do cp $picdir/../lib/$file $file; done
+
+mv stringclass.h stringcl.h
+mv change_lf.c changelf.c
+
+cat >makefile <<'EOF'
+# Makefile for pic with Borland C++ 2.0.
+CC=bcc -P -V
+OLDCC=bcc -V
+MODEL=l
+WARN=
+DEBUG=
+MAP=-M
+CFLAGS=-m$(MODEL) $(WARN) $(DEBUG) -I. -DSWITCHAR
+LDFLAGS=-m$(MODEL) $(DEBUG) $(MAP)
+
+OBJS=changelf.obj \
+common.obj \
+cset.obj \
+errarg.obj \
+error.obj \
+fatal.obj \
+filename.obj \
+lex.obj \
+lf.obj \
+lineno.obj \
+main.obj \
+new.obj \
+object.obj \
+pic_tab1.obj \
+pic_tab2.obj \
+progname.obj \
+ptable.obj \
+string.obj \
+strsave.obj \
+tex.obj \
+troff.obj \
+version.obj \
+getopt.obj \
+strerror.obj
+
+PROG=pic
+
+.c.obj:
+ $(CC) -c $(CFLAGS) {$< }
+
+$(PROG).exe: $(OBJS)
+ $(CC) $(LDFLAGS) -e$(PROG) @&&!
+$(OBJS)
+!
+
+strerror.obj: strerror.c
+ $(OLDCC) -c $(CFLAGS) strerror.c
+
+getopt.obj: getopt.c
+ $(OLDCC) -c $(CFLAGS) getopt.c
+
+# Enable auto-dependency checking.
+.autodepend
+EOF
+
+cat >osfcn.h <<'EOF'
+#include <io.h>
+
+extern "C" {
+ int getopt(int, char **, const char *);
+ extern int optind;
+ extern int opterr;
+}
+EOF
+
+cat >getopt.c <<'EOF'
+/* getopt() for those systems that don't have it. */
+/* Derived from comp.sources.unix/volume3/att_getopt. */
+
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+
+#ifdef SWITCHAR
+#include <dos.h>
+#endif
+
+int opterr = 1;
+int optind = 1;
+int optopt;
+char *optarg;
+
+#ifndef OPTION_CHAR
+#define OPTION_CHAR '-'
+#endif
+
+#ifdef isascii
+#define ISASCII(c) isascii(c)
+#else
+#define ISASCII(c) (1)
+#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 = (unsigned char)argv[optind][sp];
+#ifdef CASE_INSENSITIVE_OPTIONS
+ if (ISASCII(c) && isupper(c))
+ optopt = c = tolower(c);
+#endif
+ 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 '?';
+}
+
+/*
+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:
+*/
+EOF
+
+for file in *; do sed -e 's/$/ /' $file >temp; mv temp $file; done
+
+tar cf ../$tarfile *
+cd ..
+compress -b14 $tarfile
+rm -fr temp
+
+echo Now move $tarfile.Z to a MSDOS machine with Borland C++ 2.0,
+echo unpack and compile with make -S.
diff --git a/gnu/usr.bin/groff/pic/object.cc b/gnu/usr.bin/groff/pic/object.cc
new file mode 100644
index 0000000..b5fbf59
--- /dev/null
+++ b/gnu/usr.bin/groff/pic/object.cc
@@ -0,0 +1,1815 @@
+// -*- C++ -*-
+/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
+ Written by James Clark (jjc@jclark.com)
+
+This file is part of groff.
+
+groff is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
+
+groff is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License along
+with groff; see the file COPYING. If not, write to the Free Software
+Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "pic.h"
+#include "ptable.h"
+#include "object.h"
+
+void print_object_list(object *);
+
+line_type::line_type()
+: type(solid), thickness(1.0)
+{
+}
+
+output::output() : desired_height(0.0), desired_width(0.0), args(0)
+{
+}
+
+output::~output()
+{
+ a_delete args;
+}
+
+void output::set_desired_width_height(double wid, double ht)
+{
+ desired_width = wid;
+ desired_height = ht;
+}
+
+void output::set_args(const char *s)
+{
+ a_delete args;
+ if (s == 0 || *s == '\0')
+ args = 0;
+ else
+ args = strsave(s);
+}
+
+void output::command(const char *, const char *, int)
+{
+}
+
+void output::set_location(const char *, int)
+{
+}
+
+int output::supports_filled_polygons()
+{
+ return 0;
+}
+
+void output::begin_block(const position &, const position &)
+{
+}
+
+void output::end_block()
+{
+}
+
+double output::compute_scale(double sc, const position &ll, const position &ur)
+{
+ distance dim = ur - ll;
+ if (desired_width != 0.0 || desired_height != 0.0) {
+ sc = 0.0;
+ if (desired_width != 0.0) {
+ if (dim.x == 0.0)
+ error("width specified for picture with zero width");
+ else
+ sc = dim.x/desired_width;
+ }
+ if (desired_height != 0.0) {
+ if (dim.y == 0.0)
+ error("height specified for picture with zero height");
+ else {
+ double tem = dim.y/desired_height;
+ if (tem > sc)
+ sc = tem;
+ }
+ }
+ return sc == 0.0 ? 1.0 : sc;
+ }
+ else {
+ if (sc <= 0.0)
+ sc = 1.0;
+ distance sdim = dim/sc;
+ double max_width = 0.0;
+ lookup_variable("maxpswid", &max_width);
+ double max_height = 0.0;
+ lookup_variable("maxpsht", &max_height);
+ if ((max_width > 0.0 && sdim.x > max_width)
+ || (max_height > 0.0 && sdim.y > max_height)) {
+ double xscale = dim.x/max_width;
+ double yscale = dim.y/max_height;
+ return xscale > yscale ? xscale : yscale;
+ }
+ else
+ return sc;
+ }
+}
+
+position::position(const place &pl)
+{
+ if (pl.obj != 0) {
+ // Use two statements to work around bug in SGI C++.
+ object *tem = pl.obj;
+ *this = tem->origin();
+ }
+ else {
+ x = pl.x;
+ y = pl.y;
+ }
+}
+
+position::position() : x(0.0), y(0.0)
+{
+}
+
+position::position(double a, double b) : x(a), y(b)
+{
+}
+
+
+int operator==(const position &a, const position &b)
+{
+ return a.x == b.x && a.y == b.y;
+}
+
+int operator!=(const position &a, const position &b)
+{
+ return a.x != b.x || a.y != b.y;
+}
+
+position &position::operator+=(const position &a)
+{
+ x += a.x;
+ y += a.y;
+ return *this;
+}
+
+position &position::operator-=(const position &a)
+{
+ x -= a.x;
+ y -= a.y;
+ return *this;
+}
+
+position &position::operator*=(double a)
+{
+ x *= a;
+ y *= a;
+ return *this;
+}
+
+position &position::operator/=(double a)
+{
+ x /= a;
+ y /= a;
+ return *this;
+}
+
+position operator-(const position &a)
+{
+ return position(-a.x, -a.y);
+}
+
+position operator+(const position &a, const position &b)
+{
+ return position(a.x + b.x, a.y + b.y);
+}
+
+position operator-(const position &a, const position &b)
+{
+ return position(a.x - b.x, a.y - b.y);
+}
+
+position operator/(const position &a, double n)
+{
+ return position(a.x/n, a.y/n);
+}
+
+position operator*(const position &a, double n)
+{
+ return position(a.x*n, a.y*n);
+}
+
+// dot product
+
+double operator*(const position &a, const position &b)
+{
+ return a.x*b.x + a.y*b.y;
+}
+
+double hypot(const position &a)
+{
+ return hypot(a.x, a.y);
+}
+
+struct arrow_head_type {
+ double height;
+ double width;
+ int solid;
+};
+
+void draw_arrow(const position &pos, const distance &dir,
+ const arrow_head_type &aht, const line_type &lt)
+{
+ double hyp = hypot(dir);
+ if (hyp == 0.0) {
+ error("cannot draw arrow on object with zero length");
+ return;
+ }
+ position base = -dir;
+ base *= aht.height/hyp;
+ position n(dir.y, -dir.x);
+ n *= aht.width/(hyp*2.0);
+ line_type slt = lt;
+ slt.type = line_type::solid;
+ if (aht.solid && out->supports_filled_polygons()) {
+ position v[3];
+ v[0] = pos;
+ v[1] = pos + base + n;
+ v[2] = pos + base - n;
+ // A value > 1 means fill with the current color.
+ out->polygon(v, 3, slt, 2.0);
+ }
+ else {
+ position v[2];
+ v[0] = pos;
+ v[1] = pos + base + n;
+ out->line(pos + base - n, v, 2, slt);
+ }
+}
+
+object::object() : prev(0), next(0)
+{
+}
+
+object::~object()
+{
+}
+
+void object::move_by(const position &)
+{
+}
+
+void object::print()
+{
+}
+
+void object::print_text()
+{
+}
+
+int object::blank()
+{
+ return 0;
+}
+
+struct bounding_box {
+ int blank;
+ position ll;
+ position ur;
+
+ bounding_box();
+ void encompass(const position &);
+};
+
+bounding_box::bounding_box()
+: blank(1)
+{
+}
+
+void bounding_box::encompass(const position &pos)
+{
+ if (blank) {
+ ll = pos;
+ ur = pos;
+ blank = 0;
+ }
+ else {
+ if (pos.x < ll.x)
+ ll.x = pos.x;
+ if (pos.y < ll.y)
+ ll.y = pos.y;
+ if (pos.x > ur.x)
+ ur.x = pos.x;
+ if (pos.y > ur.y)
+ ur.y = pos.y;
+ }
+}
+
+void object::update_bounding_box(bounding_box *)
+{
+}
+
+position object::origin()
+{
+ return position(0.0,0.0);
+}
+
+position object::north()
+{
+ return origin();
+}
+
+position object::south()
+{
+ return origin();
+}
+
+position object::east()
+{
+ return origin();
+}
+
+position object::west()
+{
+ return origin();
+}
+
+position object::north_east()
+{
+ return origin();
+}
+
+position object::north_west()
+{
+ return origin();
+}
+
+position object::south_east()
+{
+ return origin();
+}
+
+position object::south_west()
+{
+ return origin();
+}
+
+position object::start()
+{
+ return origin();
+}
+
+position object::end()
+{
+ return origin();
+}
+
+position object::center()
+{
+ return origin();
+}
+
+double object::width()
+{
+ return 0.0;
+}
+
+double object::radius()
+{
+ return 0.0;
+}
+
+double object::height()
+{
+ return 0.0;
+}
+
+place *object::find_label(const char *)
+{
+ return 0;
+}
+
+segment::segment(const position &a, int n, segment *p)
+: pos(a), is_absolute(n), next(p)
+{
+}
+
+text_item::text_item(char *t, const char *fn, int ln)
+: filename(fn), lineno(ln), text(t), next(0)
+{
+ adj.h = CENTER_ADJUST;
+ adj.v = NONE_ADJUST;
+}
+
+text_item::~text_item()
+{
+ a_delete text;
+}
+
+object_spec::object_spec(object_type t) : type(t)
+{
+ flags = 0;
+ tbl = 0;
+ segment_list = 0;
+ segment_width = segment_height = 0.0;
+ segment_is_absolute = 0;
+ text = 0;
+ with = 0;
+ dir = RIGHT_DIRECTION;
+}
+
+object_spec::~object_spec()
+{
+ delete tbl;
+ while (segment_list != 0) {
+ segment *tem = segment_list;
+ segment_list = segment_list->next;
+ delete tem;
+ }
+ object *p = oblist.head;
+ while (p != 0) {
+ object *tem = p;
+ p = p->next;
+ delete tem;
+ }
+ while (text != 0) {
+ text_item *tem = text;
+ text = text->next;
+ delete tem;
+ }
+ delete with;
+}
+
+class command_object : public object {
+ char *s;
+ const char *filename;
+ int lineno;
+public:
+ command_object(char *, const char *, int);
+ ~command_object();
+ object_type type() { return OTHER_OBJECT; }
+ void print();
+};
+
+command_object::command_object(char *p, const char *fn, int ln)
+: s(p), filename(fn), lineno(ln)
+{
+}
+
+command_object::~command_object()
+{
+ a_delete s;
+}
+
+void command_object::print()
+{
+ out->command(s, filename, lineno);
+}
+
+object *make_command_object(char *s, const char *fn, int ln)
+{
+ return new command_object(s, fn, ln);
+}
+
+class mark_object : public object {
+public:
+ mark_object();
+ object_type type();
+};
+
+object *make_mark_object()
+{
+ return new mark_object();
+}
+
+mark_object::mark_object()
+{
+}
+
+object_type mark_object::type()
+{
+ return MARK_OBJECT;
+}
+
+object_list::object_list() : head(0), tail(0)
+{
+}
+
+void object_list::append(object *obj)
+{
+ if (tail == 0) {
+ obj->next = obj->prev = 0;
+ head = tail = obj;
+ }
+ else {
+ obj->prev = tail;
+ obj->next = 0;
+ tail->next = obj;
+ tail = obj;
+ }
+}
+
+void object_list::wrap_up_block(object_list *ol)
+{
+ for (object *p = tail; p && p->type() != MARK_OBJECT; p = p->prev)
+ ;
+ assert(p != 0);
+ ol->head = p->next;
+ if (ol->head) {
+ ol->tail = tail;
+ ol->head->prev = 0;
+ }
+ else
+ ol->tail = 0;
+ tail = p->prev;
+ if (tail)
+ tail->next = 0;
+ else
+ head = 0;
+ delete p;
+}
+
+text_piece::text_piece()
+: text(0), filename(0), lineno(-1)
+{
+ adj.h = CENTER_ADJUST;
+ adj.v = NONE_ADJUST;
+}
+
+text_piece::~text_piece()
+{
+ a_delete text;
+}
+
+class graphic_object : public object {
+ int ntext;
+ text_piece *text;
+ int aligned;
+protected:
+ line_type lt;
+public:
+ graphic_object();
+ ~graphic_object();
+ object_type type() = 0;
+ void print_text();
+ void add_text(text_item *, int);
+ void set_dotted(double);
+ void set_dashed(double);
+ void set_thickness(double);
+ void set_invisible();
+ virtual void set_fill(double);
+};
+
+graphic_object::graphic_object() : ntext(0), text(0), aligned(0)
+{
+}
+
+void graphic_object::set_dotted(double wid)
+{
+ lt.type = line_type::dotted;
+ lt.dash_width = wid;
+}
+
+void graphic_object::set_dashed(double wid)
+{
+ lt.type = line_type::dashed;
+ lt.dash_width = wid;
+}
+
+void graphic_object::set_thickness(double th)
+{
+ lt.thickness = th;
+}
+
+void graphic_object::set_fill(double)
+{
+}
+
+void graphic_object::set_invisible()
+{
+ lt.type = line_type::invisible;
+}
+
+void graphic_object::add_text(text_item *t, int a)
+{
+ aligned = a;
+ int len = 0;
+ for (text_item *p = t; p; p = p->next)
+ len++;
+ if (len == 0)
+ text = 0;
+ else {
+ text = new text_piece[len];
+ for (p = t, len = 0; p; p = p->next, len++) {
+ text[len].text = p->text;
+ p->text = 0;
+ text[len].adj = p->adj;
+ text[len].filename = p->filename;
+ text[len].lineno = p->lineno;
+ }
+ }
+ ntext = len;
+}
+
+void graphic_object::print_text()
+{
+ double angle = 0.0;
+ if (aligned) {
+ position d(end() - start());
+ if (d.x != 0.0 || d.y != 0.0)
+ angle = atan2(d.y, d.x);
+ }
+ if (text != 0)
+ out->text(center(), text, ntext, angle);
+}
+
+graphic_object::~graphic_object()
+{
+ if (text)
+ ad_delete(ntext) text;
+}
+
+class rectangle_object : public graphic_object {
+protected:
+ position cent;
+ position dim;
+public:
+ rectangle_object(const position &);
+ double width() { return dim.x; }
+ double height() { return dim.y; }
+ position origin() { return cent; }
+ position center() { return cent; }
+ position north() { return position(cent.x, cent.y + dim.y/2.0); }
+ position south() { return position(cent.x, cent.y - dim.y/2.0); }
+ position east() { return position(cent.x + dim.x/2.0, cent.y); }
+ position west() { return position(cent.x - dim.x/2.0, cent.y); }
+ position north_east() { return position(cent.x + dim.x/2.0, cent.y + dim.y/2.0); }
+ position north_west() { return position(cent.x - dim.x/2.0, cent.y + dim.y/2.0); }
+ position south_east() { return position(cent.x + dim.x/2.0, cent.y - dim.y/2.0); }
+ position south_west() { return position(cent.x - dim.x/2.0, cent.y - dim.y/2.0); }
+ object_type type() = 0;
+ void update_bounding_box(bounding_box *);
+ void move_by(const position &);
+};
+
+rectangle_object::rectangle_object(const position &d)
+: dim(d)
+{
+}
+
+void rectangle_object::update_bounding_box(bounding_box *p)
+{
+ p->encompass(cent - dim/2.0);
+ p->encompass(cent + dim/2.0);
+}
+
+void rectangle_object::move_by(const position &a)
+{
+ cent += a;
+}
+
+class closed_object : public rectangle_object {
+public:
+ closed_object(const position &);
+ object_type type() = 0;
+ void set_fill(double);
+protected:
+ double fill; // < 0 if not filled
+};
+
+closed_object::closed_object(const position &pos)
+: rectangle_object(pos), fill(-1.0)
+{
+}
+
+void closed_object::set_fill(double f)
+{
+ assert(f >= 0.0);
+ fill = f;
+}
+
+
+class box_object : public closed_object {
+ double xrad;
+ double yrad;
+public:
+ box_object(const position &, double);
+ object_type type() { return BOX_OBJECT; }
+ void print();
+ position north_east();
+ position north_west();
+ position south_east();
+ position south_west();
+};
+
+box_object::box_object(const position &pos, double r)
+: closed_object(pos), xrad(dim.x > 0 ? r : -r), yrad(dim.y > 0 ? r : -r)
+{
+}
+
+const double CHOP_FACTOR = 1.0 - 1.0/M_SQRT2;
+
+position box_object::north_east()
+{
+ return position(cent.x + dim.x/2.0 - CHOP_FACTOR*xrad,
+ cent.y + dim.y/2.0 - CHOP_FACTOR*yrad);
+}
+
+position box_object::north_west()
+{
+ return position(cent.x - dim.x/2.0 + CHOP_FACTOR*xrad,
+ cent.y + dim.y/2.0 - CHOP_FACTOR*yrad);
+}
+
+position box_object::south_east()
+{
+ return position(cent.x + dim.x/2.0 - CHOP_FACTOR*xrad,
+ cent.y - dim.y/2.0 + CHOP_FACTOR*yrad);
+}
+
+position box_object::south_west()
+{
+ return position(cent.x - dim.x/2.0 + CHOP_FACTOR*xrad,
+ cent.y - dim.y/2.0 + CHOP_FACTOR*yrad);
+}
+
+void box_object::print()
+{
+ if (lt.type == line_type::invisible && fill < 0.0)
+ return;
+ if (xrad == 0.0) {
+ distance dim2 = dim/2.0;
+ position vec[4];
+ vec[0] = cent + position(dim2.x, -dim2.y);
+ vec[1] = cent + position(dim2.x, dim2.y);
+ vec[2] = cent + position(-dim2.x, dim2.y);
+ vec[3] = cent + position(-dim2.x, -dim2.y);
+ out->polygon(vec, 4, lt, fill);
+ }
+ else {
+ distance abs_dim(fabs(dim.x), fabs(dim.y));
+ out->rounded_box(cent, abs_dim, fabs(xrad), lt, fill);
+ }
+}
+
+graphic_object *object_spec::make_box(position *curpos, direction *dirp)
+{
+ static double last_box_height;
+ static double last_box_width;
+ static double last_box_radius;
+ static int have_last_box = 0;
+ if (!(flags & HAS_HEIGHT)) {
+ if ((flags & IS_SAME) && have_last_box)
+ height = last_box_height;
+ else
+ lookup_variable("boxht", &height);
+ }
+ if (!(flags & HAS_WIDTH)) {
+ if ((flags & IS_SAME) && have_last_box)
+ width = last_box_width;
+ else
+ lookup_variable("boxwid", &width);
+ }
+ if (!(flags & HAS_RADIUS)) {
+ if ((flags & IS_SAME) && have_last_box)
+ radius = last_box_radius;
+ else
+ lookup_variable("boxrad", &radius);
+ }
+ last_box_width = width;
+ last_box_height = height;
+ last_box_radius = radius;
+ have_last_box = 1;
+ radius = fabs(radius);
+ if (radius*2.0 > fabs(width))
+ radius = fabs(width/2.0);
+ if (radius*2.0 > fabs(height))
+ radius = fabs(height/2.0);
+ box_object *p = new box_object(position(width, height), radius);
+ if (!position_rectangle(p, curpos, dirp)) {
+ delete p;
+ p = 0;
+ }
+ return p;
+}
+
+// return non-zero for success
+
+int object_spec::position_rectangle(rectangle_object *p,
+ position *curpos, direction *dirp)
+{
+ position pos;
+ dir = *dirp; // ignore any direction in attribute list
+ position motion;
+ switch (dir) {
+ case UP_DIRECTION:
+ motion.y = p->height()/2.0;
+ break;
+ case DOWN_DIRECTION:
+ motion.y = -p->height()/2.0;
+ break;
+ case LEFT_DIRECTION:
+ motion.x = -p->width()/2.0;
+ break;
+ case RIGHT_DIRECTION:
+ motion.x = p->width()/2.0;
+ break;
+ default:
+ assert(0);
+ }
+ if (flags & HAS_AT) {
+ pos = at;
+ if (flags & HAS_WITH) {
+ place offset;
+ place here;
+ here.obj = p;
+ if (!with->follow(here, &offset))
+ return 0;
+ pos -= offset;
+ }
+ }
+ else {
+ pos = *curpos;
+ pos += motion;
+ }
+ p->move_by(pos);
+ pos += motion;
+ *curpos = pos;
+ return 1;
+}
+
+class block_object : public rectangle_object {
+ object_list oblist;
+ PTABLE(place) *tbl;
+public:
+ block_object(const position &, const object_list &ol, PTABLE(place) *t);
+ ~block_object();
+ place *find_label(const char *);
+ object_type type();
+ void move_by(const position &);
+ void print();
+};
+
+block_object::block_object(const position &d, const object_list &ol,
+ PTABLE(place) *t)
+: oblist(ol), tbl(t), rectangle_object(d)
+{
+}
+
+block_object::~block_object()
+{
+ delete tbl;
+ object *p = oblist.head;
+ while (p != 0) {
+ object *tem = p;
+ p = p->next;
+ delete tem;
+ }
+}
+
+void block_object::print()
+{
+ out->begin_block(south_west(), north_east());
+ print_object_list(oblist.head);
+ out->end_block();
+}
+
+static void adjust_objectless_places(PTABLE(place) *tbl, const position &a)
+{
+ // Adjust all the labels that aren't attached to objects.
+ PTABLE_ITERATOR(place) iter(tbl);
+ const char *key;
+ place *pl;
+ while (iter.next(&key, &pl))
+ if (key && csupper(key[0]) && pl->obj == 0) {
+ pl->x += a.x;
+ pl->y += a.y;
+ }
+}
+
+void block_object::move_by(const position &a)
+{
+ cent += a;
+ for (object *p = oblist.head; p; p = p->next)
+ p->move_by(a);
+ adjust_objectless_places(tbl, a);
+}
+
+
+place *block_object::find_label(const char *name)
+{
+ return tbl->lookup(name);
+}
+
+object_type block_object::type()
+{
+ return BLOCK_OBJECT;
+}
+
+graphic_object *object_spec::make_block(position *curpos, direction *dirp)
+{
+ bounding_box bb;
+ for (object *p = oblist.head; p; p = p->next)
+ p->update_bounding_box(&bb);
+ position dim;
+ if (!bb.blank) {
+ position m = -(bb.ll + bb.ur)/2.0;
+ for (object *p = oblist.head; p; p = p->next)
+ p->move_by(m);
+ adjust_objectless_places(tbl, m);
+ dim = bb.ur - bb.ll;
+ }
+ if (flags & HAS_WIDTH)
+ dim.x = width;
+ if (flags & HAS_HEIGHT)
+ dim.y = height;
+ block_object *block = new block_object(dim, oblist, tbl);
+ if (!position_rectangle(block, curpos, dirp)) {
+ delete block;
+ block = 0;
+ }
+ tbl = 0;
+ oblist.head = oblist.tail = 0;
+ return block;
+}
+
+class text_object : public rectangle_object {
+public:
+ text_object(const position &);
+ object_type type() { return TEXT_OBJECT; }
+};
+
+text_object::text_object(const position &d)
+: rectangle_object(d)
+{
+}
+
+graphic_object *object_spec::make_text(position *curpos, direction *dirp)
+{
+ if (!(flags & HAS_HEIGHT)) {
+ lookup_variable("textht", &height);
+ int nitems = 0;
+ for (text_item *t = text; t; t = t->next)
+ nitems++;
+ height *= nitems;
+ }
+ if (!(flags & HAS_WIDTH))
+ lookup_variable("textwid", &width);
+ text_object *p = new text_object(position(width, height));
+ if (!position_rectangle(p, curpos, dirp)) {
+ delete p;
+ p = 0;
+ }
+ return p;
+}
+
+
+class ellipse_object : public closed_object {
+public:
+ ellipse_object(const position &);
+ position north_east() { return position(cent.x + dim.x/(M_SQRT2*2.0),
+ cent.y + dim.y/(M_SQRT2*2.0)); }
+ position north_west() { return position(cent.x - dim.x/(M_SQRT2*2.0),
+ cent.y + dim.y/(M_SQRT2*2.0)); }
+ position south_east() { return position(cent.x + dim.x/(M_SQRT2*2.0),
+ cent.y - dim.y/(M_SQRT2*2.0)); }
+ position south_west() { return position(cent.x - dim.x/(M_SQRT2*2.0),
+ cent.y - dim.y/(M_SQRT2*2.0)); }
+ double radius() { return dim.x/2.0; }
+ object_type type() { return ELLIPSE_OBJECT; }
+ void print();
+};
+
+ellipse_object::ellipse_object(const position &d)
+: closed_object(d)
+{
+}
+
+void ellipse_object::print()
+{
+ if (lt.type == line_type::invisible && fill < 0.0)
+ return;
+ out->ellipse(cent, dim, lt, fill);
+}
+
+graphic_object *object_spec::make_ellipse(position *curpos, direction *dirp)
+{
+ static double last_ellipse_height;
+ static double last_ellipse_width;
+ static int have_last_ellipse = 0;
+ if (!(flags & HAS_HEIGHT)) {
+ if ((flags & IS_SAME) && have_last_ellipse)
+ height = last_ellipse_height;
+ else
+ lookup_variable("ellipseht", &height);
+ }
+ if (!(flags & HAS_WIDTH)) {
+ if ((flags & IS_SAME) && have_last_ellipse)
+ width = last_ellipse_width;
+ else
+ lookup_variable("ellipsewid", &width);
+ }
+ last_ellipse_width = width;
+ last_ellipse_height = height;
+ have_last_ellipse = 1;
+ ellipse_object *p = new ellipse_object(position(width, height));
+ if (!position_rectangle(p, curpos, dirp)) {
+ delete p;
+ return 0;
+ }
+ return p;
+}
+
+class circle_object : public ellipse_object {
+public:
+ circle_object(double);
+ object_type type() { return CIRCLE_OBJECT; }
+ void print();
+};
+
+circle_object::circle_object(double diam)
+: ellipse_object(position(diam, diam))
+{
+}
+
+void circle_object::print()
+{
+ if (lt.type == line_type::invisible && fill < 0.0)
+ return;
+ out->circle(cent, dim.x/2.0, lt, fill);
+}
+
+graphic_object *object_spec::make_circle(position *curpos, direction *dirp)
+{
+ static double last_circle_radius;
+ static int have_last_circle = 0;
+ if (!(flags & HAS_RADIUS)) {
+ if ((flags & IS_SAME) && have_last_circle)
+ radius = last_circle_radius;
+ else
+ lookup_variable("circlerad", &radius);
+ }
+ last_circle_radius = radius;
+ have_last_circle = 1;
+ circle_object *p = new circle_object(radius*2.0);
+ if (!position_rectangle(p, curpos, dirp)) {
+ delete p;
+ return 0;
+ }
+ return p;
+}
+
+class move_object : public graphic_object {
+ position strt;
+ position en;
+public:
+ move_object(const position &s, const position &e);
+ position origin() { return en; }
+ object_type type() { return MOVE_OBJECT; }
+ void update_bounding_box(bounding_box *);
+ void move_by(const position &);
+};
+
+move_object::move_object(const position &s, const position &e)
+: strt(s), en(e)
+{
+}
+
+void move_object::update_bounding_box(bounding_box *p)
+{
+ p->encompass(strt);
+ p->encompass(en);
+}
+
+void move_object::move_by(const position &a)
+{
+ strt += a;
+ en += a;
+}
+
+graphic_object *object_spec::make_move(position *curpos, direction *dirp)
+{
+ static position last_move;
+ static int have_last_move = 0;
+ *dirp = dir;
+ // No need to look at at since `at' attribute sets `from' attribute.
+ position startpos = (flags & HAS_FROM) ? from : *curpos;
+ if (!(flags & HAS_SEGMENT)) {
+ if ((flags && IS_SAME) && have_last_move)
+ segment_pos = last_move;
+ else {
+ switch (dir) {
+ case UP_DIRECTION:
+ segment_pos.y = segment_height;
+ break;
+ case DOWN_DIRECTION:
+ segment_pos.y = -segment_height;
+ break;
+ case LEFT_DIRECTION:
+ segment_pos.x = -segment_width;
+ break;
+ case RIGHT_DIRECTION:
+ segment_pos.x = segment_width;
+ break;
+ default:
+ assert(0);
+ }
+ }
+ }
+ segment_list = new segment(segment_pos, segment_is_absolute, segment_list);
+ // Reverse the segment_list so that it's in forward order.
+ segment *old = segment_list;
+ segment_list = 0;
+ while (old != 0) {
+ segment *tem = old->next;
+ old->next = segment_list;
+ segment_list = old;
+ old = tem;
+ }
+ // Compute the end position.
+ position endpos = startpos;
+ for (segment *s = segment_list; s; s = s->next)
+ if (s->is_absolute)
+ endpos = s->pos;
+ else
+ endpos += s->pos;
+ have_last_move = 1;
+ last_move = endpos - startpos;
+ move_object *p = new move_object(startpos, endpos);
+ *curpos = endpos;
+ return p;
+}
+
+class linear_object : public graphic_object {
+protected:
+ char arrow_at_start;
+ char arrow_at_end;
+ arrow_head_type aht;
+ position strt;
+ position en;
+public:
+ linear_object(const position &s, const position &e);
+ position start() { return strt; }
+ position end() { return en; }
+ void move_by(const position &);
+ void update_bounding_box(bounding_box *) = 0;
+ object_type type() = 0;
+ void add_arrows(int at_start, int at_end, const arrow_head_type &);
+};
+
+class line_object : public linear_object {
+protected:
+ position *v;
+ int n;
+public:
+ line_object(const position &s, const position &e, position *, int);
+ ~line_object();
+ position origin() { return strt; }
+ position center() { return (strt + en)/2.0; }
+ position north() { return (en.y - strt.y) > 0 ? en : strt; }
+ position south() { return (en.y - strt.y) < 0 ? en : strt; }
+ position east() { return (en.x - strt.x) > 0 ? en : strt; }
+ position west() { return (en.x - strt.x) < 0 ? en : strt; }
+ object_type type() { return LINE_OBJECT; }
+ void update_bounding_box(bounding_box *);
+ void print();
+ void move_by(const position &);
+};
+
+class arrow_object : public line_object {
+public:
+ arrow_object(const position &, const position &, position *, int);
+ object_type type() { return ARROW_OBJECT; }
+};
+
+class spline_object : public line_object {
+public:
+ spline_object(const position &, const position &, position *, int);
+ object_type type() { return SPLINE_OBJECT; }
+ void print();
+ void update_bounding_box(bounding_box *);
+};
+
+linear_object::linear_object(const position &s, const position &e)
+: strt(s), en(e), arrow_at_start(0), arrow_at_end(0)
+{
+}
+
+void linear_object::move_by(const position &a)
+{
+ strt += a;
+ en += a;
+}
+
+void linear_object::add_arrows(int at_start, int at_end,
+ const arrow_head_type &a)
+{
+ arrow_at_start = at_start;
+ arrow_at_end = at_end;
+ aht = a;
+}
+
+line_object::line_object(const position &s, const position &e,
+ position *p, int i)
+: v(p), n(i), linear_object(s, e)
+{
+}
+
+void line_object::print()
+{
+ if (lt.type == line_type::invisible)
+ return;
+ out->line(strt, v, n, lt);
+ if (arrow_at_start)
+ draw_arrow(strt, strt-v[0], aht, lt);
+ if (arrow_at_end)
+ draw_arrow(en, v[n-1] - (n > 1 ? v[n - 2] : strt), aht, lt);
+}
+
+void line_object::update_bounding_box(bounding_box *p)
+{
+ p->encompass(strt);
+ for (int i = 0; i < n; i++)
+ p->encompass(v[i]);
+}
+
+void line_object::move_by(const position &pos)
+{
+ linear_object::move_by(pos);
+ for (int i = 0; i < n; i++)
+ v[i] += pos;
+}
+
+void spline_object::update_bounding_box(bounding_box *p)
+{
+ p->encompass(strt);
+ p->encompass(en);
+ /*
+
+ If
+
+ p1 = q1/2 + q2/2
+ p2 = q1/6 + q2*5/6
+ p3 = q2*5/6 + q3/6
+ p4 = q2/2 + q3/2
+ [ the points for the Bezier cubic ]
+
+ and
+
+ t = .5
+
+ then
+
+ (1-t)^3*p1 + 3*t*(t - 1)^2*p2 + 3*t^2*(1-t)*p3 + t^3*p4
+ [ the equation for the Bezier cubic ]
+
+ = .125*q1 + .75*q2 + .125*q3
+
+ */
+ for (int i = 1; i < n; i++)
+ p->encompass((i == 1 ? strt : v[i-2])*.125 + v[i-1]*.75 + v[i]*.125);
+}
+
+arrow_object::arrow_object(const position &s, const position &e,
+ position *p, int i)
+: line_object(s, e, p, i)
+{
+}
+
+spline_object::spline_object(const position &s, const position &e,
+ position *p, int i)
+: line_object(s, e, p, i)
+{
+}
+
+void spline_object::print()
+{
+ if (lt.type == line_type::invisible)
+ return;
+ out->spline(strt, v, n, lt);
+ if (arrow_at_start)
+ draw_arrow(strt, strt-v[0], aht, lt);
+ if (arrow_at_end)
+ draw_arrow(en, v[n-1] - (n > 1 ? v[n - 2] : strt), aht, lt);
+}
+
+line_object::~line_object()
+{
+ a_delete v;
+}
+
+linear_object *object_spec::make_line(position *curpos, direction *dirp)
+{
+ static position last_line;
+ static int have_last_line = 0;
+ *dirp = dir;
+ // No need to look at at since `at' attribute sets `from' attribute.
+ position startpos = (flags & HAS_FROM) ? from : *curpos;
+ if (!(flags & HAS_SEGMENT)) {
+ if ((flags & IS_SAME) && (type == LINE_OBJECT || type == ARROW_OBJECT)
+ && have_last_line)
+ segment_pos = last_line;
+ else
+ switch (dir) {
+ case UP_DIRECTION:
+ segment_pos.y = segment_height;
+ break;
+ case DOWN_DIRECTION:
+ segment_pos.y = -segment_height;
+ break;
+ case LEFT_DIRECTION:
+ segment_pos.x = -segment_width;
+ break;
+ case RIGHT_DIRECTION:
+ segment_pos.x = segment_width;
+ break;
+ default:
+ assert(0);
+ }
+ }
+ segment_list = new segment(segment_pos, segment_is_absolute, segment_list);
+ // reverse the segment_list so that it's in forward order
+ segment *old = segment_list;
+ segment_list = 0;
+ while (old != 0) {
+ segment *tem = old->next;
+ old->next = segment_list;
+ segment_list = old;
+ old = tem;
+ }
+ // Absolutise all movements
+ position endpos = startpos;
+ int nsegments = 0;
+ for (segment *s = segment_list; s; s = s->next, nsegments++)
+ if (s->is_absolute)
+ endpos = s->pos;
+ else {
+ endpos += s->pos;
+ s->pos = endpos;
+ s->is_absolute = 1; // to avoid confusion
+ }
+ // handle chop
+ line_object *p = 0;
+ position *v = new position[nsegments];
+ int i = 0;
+ for (s = segment_list; s; s = s->next, i++)
+ v[i] = s->pos;
+ if (flags & IS_DEFAULT_CHOPPED) {
+ lookup_variable("circlerad", &start_chop);
+ end_chop = start_chop;
+ flags |= IS_CHOPPED;
+ }
+ if (flags & IS_CHOPPED) {
+ position start_chop_vec, end_chop_vec;
+ if (start_chop != 0.0) {
+ start_chop_vec = v[0] - startpos;
+ start_chop_vec *= start_chop / hypot(start_chop_vec);
+ }
+ if (end_chop != 0.0) {
+ end_chop_vec = (v[nsegments - 1]
+ - (nsegments > 1 ? v[nsegments - 2] : startpos));
+ end_chop_vec *= end_chop / hypot(end_chop_vec);
+ }
+ startpos += start_chop_vec;
+ v[nsegments - 1] -= end_chop_vec;
+ endpos -= end_chop_vec;
+ }
+ switch (type) {
+ case SPLINE_OBJECT:
+ p = new spline_object(startpos, endpos, v, nsegments);
+ break;
+ case ARROW_OBJECT:
+ p = new arrow_object(startpos, endpos, v, nsegments);
+ break;
+ case LINE_OBJECT:
+ p = new line_object(startpos, endpos, v, nsegments);
+ break;
+ default:
+ assert(0);
+ }
+ have_last_line = 1;
+ last_line = endpos - startpos;
+ *curpos = endpos;
+ return p;
+}
+
+class arc_object : public linear_object {
+ int clockwise;
+ position cent;
+ double rad;
+public:
+ arc_object(int, const position &, const position &, const position &);
+ position origin() { return cent; }
+ position center() { return cent; }
+ double radius() { return rad; }
+ position north();
+ position south();
+ position east();
+ position west();
+ position north_east();
+ position north_west();
+ position south_east();
+ position south_west();
+ void update_bounding_box(bounding_box *);
+ object_type type() { return ARC_OBJECT; }
+ void print();
+ void move_by(const position &pos);
+};
+
+arc_object::arc_object(int cw, const position &s, const position &e,
+ const position &c)
+: linear_object(s, e), clockwise(cw), cent(c)
+{
+ rad = hypot(c - s);
+}
+
+void arc_object::move_by(const position &pos)
+{
+ linear_object::move_by(pos);
+ cent += pos;
+}
+
+// we get arc corners from the corresponding circle
+
+position arc_object::north()
+{
+ position result(cent);
+ result.y += rad;
+ return result;
+}
+
+position arc_object::south()
+{
+ position result(cent);
+ result.y -= rad;
+ return result;
+}
+
+position arc_object::east()
+{
+ position result(cent);
+ result.x += rad;
+ return result;
+}
+
+position arc_object::west()
+{
+ position result(cent);
+ result.x -= rad;
+ return result;
+}
+
+position arc_object::north_east()
+{
+ position result(cent);
+ result.x += rad/M_SQRT2;
+ result.y += rad/M_SQRT2;
+ return result;
+}
+
+position arc_object::north_west()
+{
+ position result(cent);
+ result.x -= rad/M_SQRT2;
+ result.y += rad/M_SQRT2;
+ return result;
+}
+
+position arc_object::south_east()
+{
+ position result(cent);
+ result.x += rad/M_SQRT2;
+ result.y -= rad/M_SQRT2;
+ return result;
+}
+
+position arc_object::south_west()
+{
+ position result(cent);
+ result.x -= rad/M_SQRT2;
+ result.y -= rad/M_SQRT2;
+ return result;
+}
+
+
+void arc_object::print()
+{
+ if (lt.type == line_type::invisible)
+ return;
+ if (clockwise)
+ out->arc(en, cent, strt, lt);
+ else
+ out->arc(strt, cent, en, lt);
+ if (arrow_at_start) {
+ position c = cent - strt;
+ draw_arrow(strt,
+ (clockwise ? position(c.y, -c.x) : position(-c.y, c.x)),
+ aht, lt);
+ }
+ if (arrow_at_end) {
+ position e = en - cent;
+ draw_arrow(en,
+ (clockwise ? position(e.y, -e.x) : position(-e.y, e.x)),
+ aht, lt);
+ }
+}
+
+inline double max(double a, double b)
+{
+ return a > b ? a : b;
+}
+
+void arc_object::update_bounding_box(bounding_box *p)
+{
+ p->encompass(strt);
+ p->encompass(en);
+ position start_offset = strt - cent;
+ if (start_offset.x == 0.0 && start_offset.y == 0.0)
+ return;
+ position end_offset = en - cent;
+ if (end_offset.x == 0.0 && end_offset.y == 0.0)
+ return;
+ double start_quad = atan2(start_offset.y, start_offset.x)/(M_PI/2.0);
+ double end_quad = atan2(end_offset.y, end_offset.x)/(M_PI/2.0);
+ if (clockwise) {
+ double temp = start_quad;
+ start_quad = end_quad;
+ end_quad = temp;
+ }
+ if (start_quad < 0.0)
+ start_quad += 4.0;
+ while (end_quad <= start_quad)
+ end_quad += 4.0;
+ double radius = max(hypot(start_offset), hypot(end_offset));
+ for (int q = int(start_quad) + 1; q < end_quad; q++) {
+ position offset;
+ switch (q % 4) {
+ case 0:
+ offset.x = radius;
+ break;
+ case 1:
+ offset.y = radius;
+ break;
+ case 2:
+ offset.x = -radius;
+ break;
+ case 3:
+ offset.y = -radius;
+ break;
+ }
+ p->encompass(cent + offset);
+ }
+}
+
+// We ignore the with attribute. The at attribute always refers to the center.
+
+linear_object *object_spec::make_arc(position *curpos, direction *dirp)
+{
+ *dirp = dir;
+ int cw = (flags & IS_CLOCKWISE) != 0;
+ // compute the start
+ position startpos;
+ if (flags & HAS_FROM)
+ startpos = from;
+ else
+ startpos = *curpos;
+ if (!(flags & HAS_RADIUS))
+ lookup_variable("arcrad", &radius);
+ // compute the end
+ position endpos;
+ if (flags & HAS_TO)
+ endpos = to;
+ else {
+ position m(radius, radius);
+ // Adjust the signs.
+ if (cw) {
+ if (dir == DOWN_DIRECTION || dir == LEFT_DIRECTION)
+ m.x = -m.x;
+ if (dir == DOWN_DIRECTION || dir == RIGHT_DIRECTION)
+ m.y = -m.y;
+ *dirp = direction((dir + 3) % 4);
+ }
+ else {
+ if (dir == UP_DIRECTION || dir == LEFT_DIRECTION)
+ m.x = -m.x;
+ if (dir == DOWN_DIRECTION || dir == LEFT_DIRECTION)
+ m.y = -m.y;
+ *dirp = direction((dir + 1) % 4);
+ }
+ endpos = startpos + m;
+ }
+ // compute the center
+ position centerpos;
+ if (flags & HAS_AT)
+ centerpos = at;
+ else if (startpos == endpos)
+ centerpos = startpos;
+ else {
+ position h = (endpos - startpos)/2.0;
+ double d = hypot(h);
+ if (radius <= 0)
+ radius = .25;
+ // make the radius big enough
+ while (radius < d)
+ radius *= 2.0;
+ double alpha = acos(d/radius);
+ double theta = atan2(h.y, h.x);
+ if (cw)
+ theta -= alpha;
+ else
+ theta += alpha;
+ centerpos = position(cos(theta), sin(theta))*radius + startpos;
+ }
+ arc_object *p = new arc_object(cw, startpos, endpos, centerpos);
+ *curpos = endpos;
+ return p;
+}
+
+graphic_object *object_spec::make_linear(position *curpos, direction *dirp)
+{
+ linear_object *obj;
+ if (type == ARC_OBJECT)
+ obj = make_arc(curpos, dirp);
+ else
+ obj = make_line(curpos, dirp);
+ if (type == ARROW_OBJECT
+ && (flags & (HAS_LEFT_ARROW_HEAD|HAS_RIGHT_ARROW_HEAD)) == 0)
+ flags |= HAS_RIGHT_ARROW_HEAD;
+ if (obj && (flags & (HAS_LEFT_ARROW_HEAD|HAS_RIGHT_ARROW_HEAD))) {
+ arrow_head_type a;
+ int at_start = (flags & HAS_LEFT_ARROW_HEAD) != 0;
+ int at_end = (flags & HAS_RIGHT_ARROW_HEAD) != 0;
+ if (flags & HAS_HEIGHT)
+ a.height = height;
+ else
+ lookup_variable("arrowht", &a.height);
+ if (flags & HAS_WIDTH)
+ a.width = width;
+ else
+ lookup_variable("arrowwid", &a.width);
+ double solid;
+ lookup_variable("arrowhead", &solid);
+ a.solid = solid != 0.0;
+ obj->add_arrows(at_start, at_end, a);
+ }
+ return obj;
+}
+
+object *object_spec::make_object(position *curpos, direction *dirp)
+{
+ graphic_object *obj = 0;
+ switch (type) {
+ case BLOCK_OBJECT:
+ obj = make_block(curpos, dirp);
+ break;
+ case BOX_OBJECT:
+ obj = make_box(curpos, dirp);
+ break;
+ case TEXT_OBJECT:
+ obj = make_text(curpos, dirp);
+ break;
+ case ELLIPSE_OBJECT:
+ obj = make_ellipse(curpos, dirp);
+ break;
+ case CIRCLE_OBJECT:
+ obj = make_circle(curpos, dirp);
+ break;
+ case MOVE_OBJECT:
+ obj = make_move(curpos, dirp);
+ break;
+ case ARC_OBJECT:
+ case LINE_OBJECT:
+ case SPLINE_OBJECT:
+ case ARROW_OBJECT:
+ obj = make_linear(curpos, dirp);
+ break;
+ case MARK_OBJECT:
+ case OTHER_OBJECT:
+ default:
+ assert(0);
+ break;
+ }
+ if (obj) {
+ if (flags & IS_INVISIBLE)
+ obj->set_invisible();
+ if (text != 0)
+ obj->add_text(text, (flags & IS_ALIGNED) != 0);
+ if (flags & IS_DOTTED)
+ obj->set_dotted(dash_width);
+ else if (flags & IS_DASHED)
+ obj->set_dashed(dash_width);
+ double th;
+ if (flags & HAS_THICKNESS)
+ th = thickness;
+ else
+ lookup_variable("linethick", &th);
+ obj->set_thickness(th);
+ if (flags & (IS_DEFAULT_FILLED|IS_FILLED)) {
+ if (flags & IS_DEFAULT_FILLED)
+ lookup_variable("fillval", &fill);
+ if (fill < 0.0)
+ error("bad fill value %1", fill);
+ else
+ obj->set_fill(fill);
+ }
+ }
+ return obj;
+}
+
+struct string_list {
+ string_list *next;
+ char *str;
+ string_list(char *);
+ ~string_list();
+};
+
+string_list::string_list(char *s)
+: next(0), str(s)
+{
+}
+
+string_list::~string_list()
+{
+ a_delete str;
+}
+
+/* A path is used to hold the argument to the with attribute. For example,
+`.nw' or `.A.s' or `.A'. The major operation on a path is to take a
+place and follow the path through the place to place within the place.
+Note that `.A.B.C.sw' will work. */
+
+path::path(corner c)
+: label_list(0), crn(c)
+{
+}
+
+path::path(char *l, corner c)
+: crn(c)
+{
+ label_list = new string_list(l);
+}
+
+path::~path()
+{
+ while (label_list) {
+ string_list *tem = label_list;
+ label_list = label_list->next;
+ delete tem;
+ }
+}
+
+void path::append(corner c)
+{
+ assert(crn == 0);
+ crn = c;
+}
+
+void path::append(char *s)
+{
+ for (string_list **p = &label_list; *p; p = &(*p)->next)
+ ;
+ *p = new string_list(s);
+}
+
+// return non-zero for success
+
+int path::follow(const place &pl, place *result) const
+{
+ const place *p = &pl;
+ for (string_list *lb = label_list; lb; lb = lb->next)
+ if (p->obj == 0 || (p = p->obj->find_label(lb->str)) == 0) {
+ lex_error("object does not contain a place `%1'", lb->str);
+ return 0;
+ }
+ if (crn == 0 || p->obj == 0)
+ *result = *p;
+ else {
+ position pos = ((p->obj)->*(crn))();
+ result->x = pos.x;
+ result->y = pos.y;
+ result->obj = 0;
+ }
+ return 1;
+}
+
+void print_object_list(object *p)
+{
+ for (; p; p = p->next) {
+ p->print();
+ p->print_text();
+ }
+}
+
+void print_picture(object *obj)
+{
+ bounding_box bb;
+ for (object *p = obj; p; p = p->next)
+ p->update_bounding_box(&bb);
+ double scale;
+ lookup_variable("scale", &scale);
+ out->start_picture(scale, bb.ll, bb.ur);
+ print_object_list(obj);
+ out->finish_picture();
+}
+
diff --git a/gnu/usr.bin/groff/pic/object.h b/gnu/usr.bin/groff/pic/object.h
new file mode 100644
index 0000000..fe3dd76
--- /dev/null
+++ b/gnu/usr.bin/groff/pic/object.h
@@ -0,0 +1,215 @@
+// -*- C++ -*-
+/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
+ Written by James Clark (jjc@jclark.com)
+
+This file is part of groff.
+
+groff is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
+
+groff is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License along
+with groff; see the file COPYING. If not, write to the Free Software
+Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+struct place;
+
+enum object_type {
+ OTHER_OBJECT,
+ BOX_OBJECT,
+ CIRCLE_OBJECT,
+ ELLIPSE_OBJECT,
+ ARC_OBJECT,
+ SPLINE_OBJECT,
+ LINE_OBJECT,
+ ARROW_OBJECT,
+ MOVE_OBJECT,
+ TEXT_OBJECT,
+ BLOCK_OBJECT,
+ MARK_OBJECT
+ };
+
+struct bounding_box;
+
+struct object {
+ object *prev;
+ object *next;
+ object();
+ virtual ~object();
+ virtual position origin();
+ virtual double width();
+ virtual double radius();
+ virtual double height();
+ virtual position north();
+ virtual position south();
+ virtual position east();
+ virtual position west();
+ virtual position north_east();
+ virtual position north_west();
+ virtual position south_east();
+ virtual position south_west();
+ virtual position start();
+ virtual position end();
+ virtual position center();
+ virtual place *find_label(const char *);
+ virtual void move_by(const position &);
+ virtual int blank();
+ virtual void update_bounding_box(bounding_box *);
+ virtual object_type type() = 0;
+ virtual void print();
+ virtual void print_text();
+};
+
+typedef position (object::*corner)();
+
+struct place {
+ object *obj;
+ double x, y;
+};
+
+struct string_list;
+
+class path {
+ corner crn;
+ string_list *label_list;
+public:
+ path(corner = 0);
+ path(char *, corner = 0);
+ ~path();
+ void append(corner);
+ void append(char *);
+ int follow(const place &, place *) const;
+};
+
+struct object_list {
+ object *head;
+ object *tail;
+ object_list();
+ void append(object *);
+ void wrap_up_block(object_list *);
+};
+
+declare_ptable(place)
+
+// these go counterclockwise
+enum direction {
+ RIGHT_DIRECTION,
+ UP_DIRECTION,
+ LEFT_DIRECTION,
+ DOWN_DIRECTION
+ };
+
+struct graphics_state {
+ double x, y;
+ direction dir;
+};
+
+struct saved_state : public graphics_state {
+ saved_state *prev;
+ PTABLE(place) *tbl;
+};
+
+
+struct text_item {
+ text_item *next;
+ char *text;
+ adjustment adj;
+ const char *filename;
+ int lineno;
+
+ text_item(char *, const char *, int);
+ ~text_item();
+};
+
+const unsigned long IS_DOTTED = 01;
+const unsigned long IS_DASHED = 02;
+const unsigned long IS_CLOCKWISE = 04;
+const unsigned long IS_INVISIBLE = 020;
+const unsigned long HAS_LEFT_ARROW_HEAD = 040;
+const unsigned long HAS_RIGHT_ARROW_HEAD = 0100;
+const unsigned long HAS_SEGMENT = 0200;
+const unsigned long IS_SAME = 0400;
+const unsigned long HAS_FROM = 01000;
+const unsigned long HAS_AT = 02000;
+const unsigned long HAS_WITH = 04000;
+const unsigned long HAS_HEIGHT = 010000;
+const unsigned long HAS_WIDTH = 020000;
+const unsigned long HAS_RADIUS = 040000;
+const unsigned long HAS_TO = 0100000;
+const unsigned long IS_CHOPPED = 0200000;
+const unsigned long IS_DEFAULT_CHOPPED = 0400000;
+const unsigned long HAS_THICKNESS = 01000000;
+const unsigned long IS_FILLED = 02000000;
+const unsigned long IS_DEFAULT_FILLED = 04000000;
+const unsigned long IS_ALIGNED = 010000000;
+
+struct segment {
+ int is_absolute;
+ position pos;
+ segment *next;
+ segment(const position &, int, segment *);
+};
+
+struct rectangle_object;
+struct graphic_object;
+struct linear_object;
+
+struct object_spec {
+ unsigned long flags;
+ object_type type;
+ object_list oblist;
+ PTABLE(place) *tbl;
+ double dash_width;
+ position from;
+ position to;
+ position at;
+ position by;
+ path *with;
+ text_item *text;
+ double height;
+ double radius;
+ double width;
+ double segment_width;
+ double segment_height;
+ double start_chop;
+ double end_chop;
+ double thickness;
+ double fill;
+ direction dir;
+ segment *segment_list;
+ position segment_pos;
+ int segment_is_absolute;
+
+ object_spec(object_type);
+ ~object_spec();
+ object *make_object(position *, direction *);
+ graphic_object *make_box(position *, direction *);
+ graphic_object *make_block(position *, direction *);
+ graphic_object *make_text(position *, direction *);
+ graphic_object *make_ellipse(position *, direction *);
+ graphic_object *make_circle(position *, direction *);
+ linear_object *make_line(position *, direction *);
+ linear_object *make_arc(position *, direction *);
+ graphic_object *make_linear(position *, direction *);
+ graphic_object *make_move(position *, direction *);
+ int position_rectangle(rectangle_object *p, position *curpos,
+ direction *dirp);
+};
+
+
+object *make_object(object_spec *, position *, direction *);
+
+object *make_mark_object();
+object *make_command_object(char *, const char *, int);
+
+int lookup_variable(const char *name, double *val);
+void define_variable(const char *name, double val);
+
+void print_picture(object *);
+
diff --git a/gnu/usr.bin/groff/pic/output.h b/gnu/usr.bin/groff/pic/output.h
new file mode 100644
index 0000000..ddcc4b5
--- /dev/null
+++ b/gnu/usr.bin/groff/pic/output.h
@@ -0,0 +1,79 @@
+// -*- C++ -*-
+/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
+ Written by James Clark (jjc@jclark.com)
+
+This file is part of groff.
+
+groff is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
+
+groff is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License along
+with groff; see the file COPYING. If not, write to the Free Software
+Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+struct line_type {
+ enum { invisible, solid, dotted, dashed } type;
+ double dash_width;
+ double thickness; // the thickness is in points
+
+ line_type();
+};
+
+
+class output {
+protected:
+ char *args;
+ double desired_height; // zero if no height specified
+ double desired_width; // zero if no depth specified
+ double compute_scale(double, const position &, const position &);
+public:
+ output();
+ virtual ~output();
+ void set_desired_width_height(double wid, double ht);
+ void set_args(const char *);
+ virtual void start_picture(double sc, const position &ll, const position &ur) = 0;
+ virtual void finish_picture() = 0;
+ virtual void circle(const position &, double rad,
+ const line_type &, double) = 0;
+ virtual void text(const position &, text_piece *, int, double) = 0;
+ virtual void line(const position &, const position *, int n,
+ const line_type &) = 0;
+ virtual void polygon(const position *, int n,
+ const line_type &, double) = 0;
+ virtual void spline(const position &, const position *, int n,
+ const line_type &) = 0;
+ virtual void arc(const position &, const position &, const position &,
+ const line_type &) = 0;
+ virtual void ellipse(const position &, const distance &,
+ const line_type &, double) = 0;
+ virtual void rounded_box(const position &, const distance &, double,
+ const line_type &, double) = 0;
+ virtual void command(const char *, const char *, int);
+ virtual void set_location(const char *, int);
+ virtual int supports_filled_polygons();
+ virtual void begin_block(const position &ll, const position &ur);
+ virtual void end_block();
+};
+
+extern output *out;
+
+/* #define FIG_SUPPORT 1 */
+#define TEX_SUPPORT 1
+
+output *make_troff_output();
+
+#ifdef TEX_SUPPORT
+output *make_tex_output();
+output *make_tpic_output();
+#endif /* TEX_SUPPORT */
+
+#ifdef FIG_SUPPORT
+output *make_fig_output();
+#endif /* FIG_SUPPORT */
diff --git a/gnu/usr.bin/groff/pic/pic.h b/gnu/usr.bin/groff/pic/pic.h
new file mode 100644
index 0000000..11979d9
--- /dev/null
+++ b/gnu/usr.bin/groff/pic/pic.h
@@ -0,0 +1,101 @@
+// -*- C++ -*-
+/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
+ Written by James Clark (jjc@jclark.com)
+
+This file is part of groff.
+
+groff is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
+
+groff is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License along
+with groff; see the file COPYING. If not, write to the Free Software
+Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <stdio.h>
+#include <string.h>
+#include <math.h>
+#include <stdlib.h>
+#include <errno.h>
+
+extern "C" {
+ double hypot(double, double);
+}
+
+#include "assert.h"
+#include "cset.h"
+#include "lib.h"
+#include "stringclass.h"
+#include "errarg.h"
+#include "error.h"
+#include "position.h"
+#include "text.h"
+#include "output.h"
+
+#ifndef M_SQRT2
+#define M_SQRT2 1.41421356237309504880
+#endif
+
+#ifndef M_PI
+#define M_PI 3.14159265358979323846
+#endif
+
+class input {
+ input *next;
+public:
+ input();
+ virtual ~input();
+ virtual int get() = 0;
+ virtual int peek() = 0;
+ virtual int get_location(const char **, int *);
+ friend class input_stack;
+ friend class copy_rest_thru_input;
+};
+
+class file_input : public input {
+ FILE *fp;
+ const char *filename;
+ int lineno;
+ string line;
+ const char *ptr;
+ int read_line();
+public:
+ file_input(FILE *, const char *);
+ ~file_input();
+ int get();
+ int peek();
+ int get_location(const char **, int *);
+};
+
+void lex_init(input *);
+int get_location(char **, int *);
+
+void do_copy(const char *file);
+void parse_init();
+void parse_cleanup();
+
+void lex_error(const char *message,
+ const errarg &arg1 = empty_errarg,
+ const errarg &arg2 = empty_errarg,
+ const errarg &arg3 = empty_errarg);
+
+void lex_warning(const char *message,
+ const errarg &arg1 = empty_errarg,
+ const errarg &arg2 = empty_errarg,
+ const errarg &arg3 = empty_errarg);
+
+void lex_cleanup();
+
+extern int flyback_flag;
+extern int command_char;
+// zero_length_line_flag is non-zero if zero-length lines are drawn
+// as dots by the output device
+extern int zero_length_line_flag;
+extern int driver_extension_flag;
+extern int compatible_flag;
diff --git a/gnu/usr.bin/groff/pic/pic.man b/gnu/usr.bin/groff/pic/pic.man
new file mode 100644
index 0000000..1ace459
--- /dev/null
+++ b/gnu/usr.bin/groff/pic/pic.man
@@ -0,0 +1,730 @@
+.\" -*- nroff -*-
+.\" Like TP, but if specified indent is more than half
+.\" the current line-length - indent, use the default indent.
+.de Tp
+.ie \\n(.$=0:((0\\$1)*2u>(\\n(.lu-\\n(.iu)) .TP
+.el .TP "\\$1"
+..
+.ie t .ds tx T\h'-.1667m'\v'.224m'E\v'-.224m'\h'-.125m'X
+.el .ds tx TeX
+.ie \n(.g .ds ic \/
+.el .ds ic \^
+.\" The BSD man macros can't handle " in arguments to font change macros,
+.\" so use \(ts instead of ".
+.tr \(ts"
+.TH @G@PIC @MAN1EXT@ "@MDATE@" "Groff Version @VERSION@"
+.SH NAME
+@g@pic \- compile pictures for troff or TeX
+.SH SYNOPSIS
+.B @g@pic
+[
+.B \-nvC
+]
+[
+.I filename
+\&.\|.\|.
+]
+.br
+.B @g@pic
+.B \-t
+[
+.B \-cvzC
+]
+[
+.I filename
+\&.\|.\|.
+]
+.SH DESCRIPTION
+.LP
+This manual page describes the GNU version of
+.BR pic ,
+which is part of the groff document formatting system.
+.B pic
+compiles descriptions of pictures embedded within
+.B troff
+or \*(tx input files into commands that are understood by \*(tx or
+.BR troff .
+Each picture starts with a line beginning with
+.B .PS
+and ends with a line beginning with
+.BR .PE .
+Anything outside of
+.B .PS
+and
+.B .PE
+is passed through without change.
+.LP
+It is the user's responsibility to provide appropriate definitions of the
+.B PS
+and
+.B PE
+macros.
+When the macro package being used does not supply such definitions
+(for example, old versions of \-ms),
+appropriate definitions can be obtained with
+.BR \-mpic :
+these will center each picture.
+.SH OPTIONS
+.LP
+Options that do not take arguments may be grouped behind a single
+.BR \- .
+The special option
+.B \-\^\-
+can be used to mark the end of the options.
+A filename of
+.B \-
+refers to the standard input.
+.TP
+.B \-C
+Recognize
+.B .PS
+and
+.B .PE
+even when followed by a character other than space or newline.
+.TP
+.B \-n
+Don't use the groff extensions to the troff drawing commands.
+You should use this if you are using a postprocessor that doesn't support
+these extensions.
+The extensions are described in
+.BR groff_out (@MAN5EXT@).
+The
+.B \-n
+option also causes pic
+not to use zero-length lines to draw dots in troff mode.
+.TP
+.B \-t
+\*(tx mode.
+.TP
+.B \-c
+Be more compatible with
+.BR tpic .
+Implies
+.BR \-t .
+Lines beginning with
+.B \e
+are not passed through transparently.
+Lines beginning with
+.B .
+are passed through with the initial
+.B .
+changed to
+.BR \e .
+A line beginning with
+.B .ps
+is given special treatment:
+it takes an optional integer argument specifying
+the line thickness (pen size) in milliinches;
+a missing argument restores the previous line thickness;
+the default line thickness is 8 milliinches.
+The line thickness thus specified takes effect only
+when a non-negative line thickness has not been
+specified by use of the
+.B thickness
+attribute or by setting the
+.B linethick
+variable.
+.TP
+.B \-v
+Print the version number.
+.TP
+.B \-z
+In \*(tx mode draw dots using zero-length lines.
+.LP
+The following options supported by other versions of
+.B pic
+are ignored:
+.TP
+.B \-D
+Draw all lines using the \eD escape sequence.
+.B pic
+always does this.
+.TP
+.BI \-T \ dev
+Generate output for the
+.B troff
+device
+.IR dev .
+This is unnecessary because the
+.B troff
+output generated by
+.B pic
+is device-independent.
+.SH USAGE
+This section describes only the differences between GNU pic and the original
+version of pic.
+Many of these differences also apply to newer versions of Unix pic.
+.SS \*(tx mode
+.LP
+\*(tx mode is enabled by the
+.B \-t
+option.
+In \*(tx mode, pic will define a vbox called
+.B \egraph
+for each picture.
+You must yourself print that vbox using, for example, the command
+.RS
+.LP
+.B
+\ecenterline{\ebox\egraph}
+.RE
+.LP
+Actually, since the vbox has a height of zero this will produce
+slightly more vertical space above the picture than below it;
+.RS
+.LP
+.B
+\ecenterline{\eraise 1em\ebox\egraph}
+.RE
+.LP
+would avoid this.
+.LP
+You must use a \*(tx driver that supports the
+.B tpic
+specials, version 2.
+.LP
+Lines beginning with
+.B \e
+are passed through transparently; a
+.B %
+is added to the end of the line to avoid unwanted spaces.
+You can safely use this feature to change fonts or to
+change the value of
+.BR \ebaselineskip .
+Anything else may well produce undesirable results; use at your own risk.
+Lines beginning with a period are not given any special treatment.
+.SS Commands
+.TP
+\fBfor\fR \fIvariable\fR \fB=\fR \fIexpr1\fR \fBto\fR \fIexpr2\fR \
+[\fBby\fR [\fB*\fR]\fIexpr3\fR] \fBdo\fR \fIX\fR \fIbody\fR \fIX\fR
+Set
+.I variable
+to
+.IR expr1 .
+While the value of
+.I variable
+is less than or equal to
+.IR expr2 ,
+do
+.I body
+and increment
+.I variable
+by
+.IR expr3 ;
+if
+.B by
+is not given, increment
+.I variable
+by 1.
+If
+.I expr3
+is prefixed by
+.B *
+then
+.I variable
+will instead be multiplied by
+.IR expr3 .
+.I X
+can be any character not occurring in
+.IR body .
+.TP
+\fBif\fR \fIexpr\fR \fBthen\fR \fIX\fR \fIif-true\fR \fIX\fR \
+[\fBelse\fR \fIY\fR \fIif-false\fR \fIY\fR]
+Evaluate
+.IR expr ;
+if it is non-zero then do
+.IR if-true ,
+otherwise do
+.IR if-false .
+.I X
+can be any character not occurring in
+.IR if-true .
+.I Y
+can be any character not occurring in
+.IR if-false .
+.TP
+\fBprint\fR \fIarg\fR\|.\|.\|.
+Concatenate the arguments and print as a line on stderr.
+Each
+.I arg
+must be an expression, a position, or text.
+This is useful for debugging.
+.TP
+\fBcommand\fR \fIarg\fR\|.\|.\|.
+Concatenate the arguments
+and pass them through as a line to troff or\*(tx.
+Each
+.I arg
+must be an expression, a position, or text.
+This has a similar effect to a line beginning with
+.B .
+or
+.BR \e ,
+but allows the values of variables to be passed through.
+.TP
+\fBsh\fR \fIX\fR \fIcommand\fR \fIX\fR
+Pass
+.I command
+to a shell.
+.I X
+can be any character not occurring in
+.IR command .
+.TP
+\fBcopy\fR \fB"\fIfilename\fB"\fR
+Include
+.I filename
+at this point in the file.
+.TP
+\fBcopy\fR [\fB"\fIfilename\fB"\fR] \fBthru\fR \fIX\fR \fIbody\fR \fIX\fR \
+[\fBuntil\fR \fB"\fIword\*(ic\fB"\fR]
+.ns
+.TP
+\fBcopy\fR [\fB"\fIfilename\fB"\fR] \fBthru\fR \fImacro\fR \
+[\fBuntil\fR \fB"\fIword\*(ic\fB"\fR]
+This construct does
+.I body
+once for each line of
+.IR filename ;
+the line is split into blank-delimited words,
+and occurrences of
+.BI $ i
+in
+.IR body ,
+for
+.I i
+between 1 and 9,
+are replaced by the
+.IR i -th
+word of the line.
+If
+.I filename
+is not given, lines are taken from the current input up to
+.BR .PE .
+If an
+.B until
+clause is specified,
+lines will be read only until a line the first word of which is
+.IR word ;
+that line will then be discarded.
+.I X
+can be any character not occurring in
+.IR body .
+For example,
+.RS
+.IP
+.ft B
+.nf
+\&.PS
+copy thru % circle at ($1,$2) % until "END"
+1 2
+3 4
+5 6
+END
+box
+\&.PE
+.ft
+.fi
+.RE
+.IP
+is equivalent to
+.RS
+.IP
+.ft B
+.nf
+\&.PS
+circle at (1,2)
+circle at (3,4)
+circle at (5,6)
+box
+\&.PE
+.ft
+.fi
+.RE
+.IP
+The commands to be performed for each line can also be taken
+from a macro defined earlier by giving the name of the macro
+as the argument to
+.BR thru .
+.LP
+.B reset
+.br
+.ns
+.TP
+\fBreset\fI variable1\fB,\fI variable2 .\^.\^.
+Reset pre-defined variables
+.IR variable1 ,
+.I variable2
+\&.\^.\^. to their default values.
+If no arguments are given, reset all pre-defined variables
+to their default values.
+Note that assigning a value to
+.B scale
+also causes all pre-defined variables that control dimensions
+to be reset to their default values times the new value of scale.
+.TP
+\fBplot\fR \fIexpr\fR [\fB"\fItext\*(ic\fB"\fR]
+This is a text object which is constructed by using
+.I text
+as a format string for sprintf
+with an argument of
+.IR expr .
+If
+.I text
+is omitted a format string of
+.B "\(ts%g\(ts"
+is used.
+Attributes can be specified in the same way as for a normal text
+object.
+Be very careful that you specify an appropriate format string;
+pic does only very limited checking of the string.
+This is deprecated in favour of
+.BR sprintf .
+.TP
+.IB variable := expr
+This is similar to
+.B =
+except
+.I variable
+must already be defined,
+and the value of
+.I variable
+will be changed only in the innermost block in which it is defined.
+(By contrast,
+.B =
+defines the variable in the current block if it is not already defined there,
+and then changes the value in the current block.)
+.LP
+Arguments of the form
+.IP
+.IR X\ anything\ X
+.LP
+are also allowed to be of the form
+.IP
+.BI {\ anything\ }
+.LP
+In this case
+.I anything
+can contain balanced occurrences of
+.B {
+and
+.BR } .
+Strings may contain
+.I X
+or imbalanced occurrences of
+.B {
+and
+.BR } .
+.SS Expressions
+The syntax for expressions has been significantly extended:
+.LP
+.IB x\ ^\ y
+(exponentiation)
+.br
+.BI sin( x )
+.br
+.BI cos( x )
+.br
+.BI atan2( y , \ x )
+.br
+.BI log( x )
+(base 10)
+.br
+.BI exp( x )
+(base 10, ie 10\v'-.4m'\fIx\*(ic\fR\v'.4m')
+.br
+.BI sqrt( x )
+.br
+.BI int( x )
+.br
+.B rand()
+(return a random number between 0 and 1)
+.br
+.BI rand( x )
+(return a random number between 1 and
+.IR x ;
+deprecated)
+.br
+.BI max( e1 , \ e2 )
+.br
+.BI min( e1 , \ e2 )
+.br
+.BI ! e
+.br
+\fIe1\fB && \fIe2\fR
+.br
+\fIe1\fB || \fIe2\fR
+.br
+\fIe1\fB == \fIe2\fR
+.br
+\fIe1\fB != \fIe2\fR
+.br
+\fIe1\fB >= \fIe2\fR
+.br
+\fIe1\fB > \fIe2\fR
+.br
+\fIe1\fB <= \fIe2\fR
+.br
+\fIe1\fB < \fIe2\fR
+.br
+\fB"\fIstr1\*(ic\fB" == "\fIstr2\*(ic\fB"\fR
+.br
+\fB"\fIstr1\*(ic\fB" != "\fIstr2\*(ic\fB"\fR
+.br
+.LP
+String comparison expressions must be parenthesised in some contexts
+to avoid ambiguity.
+.SS Other Changes
+.LP
+A bare expression,
+.IR expr ,
+is acceptable as an attribute;
+it is equivalent to
+.IR dir\ expr ,
+where
+.I dir
+is the current direction.
+For example
+.IP
+.B line 2i
+.LP
+means draw a line 2 inches long in the current direction.
+.LP
+The maximum width and height of the picture are taken from the variables
+.B maxpswid
+and
+.BR maxpsht .
+Initially these have values 8.5 and 11.
+.LP
+Scientific notation is allowed for numbers.
+For example
+.RS
+.B
+x = 5e\-2
+.RE
+.LP
+Text attributes can be compounded.
+For example,
+.RS
+.B
+"foo" above ljust
+.RE
+is legal.
+.LP
+There is no limit to the depth to which blocks can be examined.
+For example,
+.RS
+.B
+[A: [B: [C: box ]]] with .A.B.C.sw at 1,2
+.br
+.B
+circle at last [\^].A.B.C
+.RE
+is acceptable.
+.LP
+Arcs now have compass points
+determined by the circle of which the arc is a part.
+.LP
+Circles and arcs can be dotted or dashed.
+In \*(tx mode splines can be dotted or dashed.
+.LP
+Boxes can have rounded corners.
+The
+.B rad
+attribute specifies the radius of the quarter-circles at each corner.
+If no
+.B rad
+or
+.B diam
+attribute is given, a radius of
+.B boxrad
+is used.
+Initially,
+.B boxrad
+has a value of 0.
+A box with rounded corners can be dotted or dashed.
+.LP
+The
+.B .PS
+line can have a second argument specifying a maximum height for
+the picture.
+If the width of zero is specified the width will be ignored in computing
+the scaling factor for the picture.
+Note that GNU pic will always scale a picture by the same amount
+vertically as horizontally.
+This is different from the
+.SM DWB
+2.0 pic which may scale a picture by a
+different amount vertically than horizontally if a height is
+specified.
+.LP
+Each text object has an invisible box associated with it.
+The compass points of a text object are determined by this box.
+The implicit motion associated with the object is also determined
+by this box.
+The dimensions of this box are taken from the width and height attributes;
+if the width attribute is not supplied then the width will be taken to be
+.BR textwid ;
+if the height attribute is not supplied then the height will be taken to be
+the number of text strings associated with the object
+times
+.BR textht .
+Initially
+.B textwid
+and
+.B textht
+have a value of 0.
+.LP
+In places where a quoted text string can be used,
+an expression of the form
+.IP
+.BI sprintf(\(ts format \(ts,\ arg ,\fR.\|.\|.\fB)
+.LP
+can also be used;
+this will produce the arguments formatted according to
+.IR format ,
+which should be a string as described in
+.BR printf (3)
+appropriate for the number of arguments supplied,
+using only the
+.BR e ,
+.BR f ,
+.B g
+or
+.B %
+format characters.
+.LP
+The thickness of the lines used to draw objects is controlled by the
+.B linethick
+variable.
+This gives the thickness of lines in points.
+A negative value means use the default thickness:
+in \*(tx output mode, this means use a thickness of 8 milliinches;
+in \*(tx output mode with the
+.B -c
+option, this means use the line thickness specified by
+.B .ps
+lines;
+in troff output mode, this means use a thickness proportional
+to the pointsize.
+A zero value means draw the thinnest possible line supported by
+the output device.
+Initially it has a value of -1.
+There is also a
+.BR thick [ ness ]
+attribute.
+For example,
+.RS
+.LP
+.B circle thickness 1.5
+.RE
+.LP
+would draw a circle using a line with a thickness of 1.5 points.
+The thickness of lines is not affected by the
+value of the
+.B scale
+variable, nor by the width or height given in the
+.B .PS
+line.
+.LP
+Boxes (including boxes with rounded corners),
+circles and ellipses can be filled by giving then an attribute of
+.BR fill [ ed ].
+This takes an optional argument of an expression with a value between
+0 and 1; 0 will fill it with white, 1 with black, values in between
+with a proportionally gray shade.
+A value greater than 1 can also be used:
+this means fill with the
+shade of gray that is currently being used for text and lines.
+Normally this will be black, but output devices may provide
+a mechanism for changing this.
+Without an argument, then the value of the variable
+.B fillval
+will be used.
+Initially this has a value of 0.5.
+The invisible attribute does not affect the filling of objects.
+Any text associated with a filled object will be added after the
+object has been filled, so that the text will not be obscured
+by the filling.
+.LP
+Arrow heads will be drawn as solid triangles if the variable
+.B arrowhead
+is non-zero and either \*(tx mode is enabled or
+the
+.B \-x
+option has been given.
+Initially
+.B arrowhead
+has a value of 1.
+.LP
+The troff output of pic is device-independent.
+The
+.B \-T
+option is therefore redundant.
+All numbers are taken to be in inches; numbers are never interpreted
+to be in troff machine units.
+.LP
+Objects can have an
+.B aligned
+attribute.
+This will only work when the postprocessor is
+.BR grops .
+Any text associated with an object having the
+.B aligned
+attribute will be rotated about the center of the object
+so that it is aligned in the direction from the start point
+to the end point of the object.
+Note that this attribute will have no effect for objects whose start and
+end points are coincident.
+.LP
+In places where
+.IB n th
+is allowed
+.BI ` expr 'th
+is also allowed.
+Note that
+.B 'th
+is a single token: no space is allowed between the
+.B '
+and the
+.BR th .
+For example,
+.IP
+.B
+.nf
+for i = 1 to 4 do {
+ line from `i'th box.nw to `i+1'th box.se
+}
+.fi
+.SH FILES
+.Tp \w'\fB@MACRODIR@/tmac.pic'u+3n
+.B
+@MACRODIR@/tmac.pic
+Example definitions of the
+.B PS
+and
+.B PE
+macros.
+.SH "SEE ALSO"
+.BR @g@troff (@MAN1EXT@),
+.BR groff_out (@MAN5EXT@),
+.BR tex (1)
+.br
+Tpic: Pic for \*(tx
+.br
+AT&T Bell Laboratories, Computing Science Technical Report No.\ 116,
+PIC \(em A Graphics Language for Typesetting.
+(This can be obtained by sending a mail message to netlib@research.att.com
+with a body of `send\ 116\ from\ research/cstr'.)
+.SH BUGS
+.LP
+Input characters that are illegal for
+.B groff
+(ie those with
+.SM ASCII
+code 0 or between 013 and 037 octal or between 0200 and 0237 octal)
+are rejected even in \*(tx mode.
+.LP
+The interpretation of
+.B fillval
+is incompatible with the pic in 10th edition Unix,
+which interprets 0 as black and 1 as white.
diff --git a/gnu/usr.bin/groff/pic/pic.y b/gnu/usr.bin/groff/pic/pic.y
new file mode 100644
index 0000000..a572dce
--- /dev/null
+++ b/gnu/usr.bin/groff/pic/pic.y
@@ -0,0 +1,1780 @@
+/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
+ Written by James Clark (jjc@jclark.com)
+
+This file is part of groff.
+
+groff is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
+
+groff is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License along
+with groff; see the file COPYING. If not, write to the Free Software
+Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+%{
+#include "pic.h"
+#include "ptable.h"
+#include "object.h"
+
+extern int delim_flag;
+extern void do_copy(const char *);
+extern void copy_rest_thru(const char *, const char *);
+extern void copy_file_thru(const char *, const char *, const char *);
+extern void push_body(const char *);
+extern void do_for(char *var, double from, double to,
+ int by_is_multiplicative, double by, char *body);
+extern void do_lookahead();
+
+#undef fmod
+#undef rand
+
+extern "C" {
+ double fmod(double, double);
+ int rand();
+}
+
+/* Maximum number of characters produced by printf("%g") */
+#define GDIGITS 14
+
+int yylex();
+void yyerror(const char *);
+
+void reset(const char *nm);
+void reset_all();
+
+place *lookup_label(const char *);
+void define_label(const char *label, const place *pl);
+
+direction current_direction;
+position current_position;
+
+implement_ptable(place)
+
+PTABLE(place) top_table;
+
+PTABLE(place) *current_table = &top_table;
+saved_state *current_saved_state = 0;
+
+object_list olist;
+
+const char *ordinal_postfix(int n);
+const char *object_type_name(object_type type);
+char *format_number(const char *form, double n);
+char *do_sprintf(const char *form, const double *v, int nv);
+
+%}
+
+
+%union {
+ char *str;
+ int n;
+ double x;
+ struct { double x, y; } pair;
+ struct { double x; char *body; } if_data;
+ struct { char *str; const char *filename; int lineno; } lstr;
+ struct { double *v; int nv; int maxv; } dv;
+ struct { double val; int is_multiplicative; } by;
+ place pl;
+ object *obj;
+ corner crn;
+ path *pth;
+ object_spec *spec;
+ saved_state *pstate;
+ graphics_state state;
+ object_type obtype;
+}
+
+%token <str> LABEL
+%token <str> VARIABLE
+%token <x> NUMBER
+%token <lstr> TEXT
+%token <lstr> COMMAND_LINE
+%token <str> DELIMITED
+%token <n> ORDINAL
+%token TH
+%token LEFT_ARROW_HEAD
+%token RIGHT_ARROW_HEAD
+%token DOUBLE_ARROW_HEAD
+%token LAST
+%token UP
+%token DOWN
+%token LEFT
+%token RIGHT
+%token BOX
+%token CIRCLE
+%token ELLIPSE
+%token ARC
+%token LINE
+%token ARROW
+%token MOVE
+%token SPLINE
+%token HEIGHT
+%token RADIUS
+%token WIDTH
+%token DIAMETER
+%token UP
+%token DOWN
+%token RIGHT
+%token LEFT
+%token FROM
+%token TO
+%token AT
+%token WITH
+%token BY
+%token THEN
+%token DOTTED
+%token DASHED
+%token CHOP
+%token SAME
+%token INVISIBLE
+%token LJUST
+%token RJUST
+%token ABOVE
+%token BELOW
+%token OF
+%token THE
+%token WAY
+%token BETWEEN
+%token AND
+%token HERE
+%token DOT_N
+%token DOT_E
+%token DOT_W
+%token DOT_S
+%token DOT_NE
+%token DOT_SE
+%token DOT_NW
+%token DOT_SW
+%token DOT_C
+%token DOT_START
+%token DOT_END
+%token DOT_X
+%token DOT_Y
+%token DOT_HT
+%token DOT_WID
+%token DOT_RAD
+%token SIN
+%token COS
+%token ATAN2
+%token LOG
+%token EXP
+%token SQRT
+%token K_MAX
+%token K_MIN
+%token INT
+%token RAND
+%token COPY
+%token THRU
+%token TOP
+%token BOTTOM
+%token UPPER
+%token LOWER
+%token SH
+%token PRINT
+%token CW
+%token CCW
+%token FOR
+%token DO
+%token IF
+%token ELSE
+%token ANDAND
+%token OROR
+%token NOTEQUAL
+%token EQUALEQUAL
+%token LESSEQUAL
+%token GREATEREQUAL
+%token LEFT_CORNER
+%token RIGHT_CORNER
+%token CENTER
+%token END
+%token START
+%token RESET
+%token UNTIL
+%token PLOT
+%token THICKNESS
+%token FILL
+%token ALIGNED
+%token SPRINTF
+%token COMMAND
+
+%token DEFINE
+%token UNDEF
+
+/* this ensures that plot 17 "%g" parses as (plot 17 "%g") */
+%left PLOT
+%left TEXT SPRINTF
+
+/* give text adjustments higher precedence than TEXT, so that
+box "foo" above ljust == box ("foo" above ljust)
+*/
+
+%left LJUST RJUST ABOVE BELOW
+
+%left LEFT RIGHT
+/* Give attributes that take an optional expression a higher
+precedence than left and right, so that eg `line chop left'
+parses properly. */
+%left CHOP DASHED DOTTED UP DOWN FILL
+%left LABEL
+
+%left VARIABLE NUMBER '(' SIN COS ATAN2 LOG EXP SQRT K_MAX K_MIN INT RAND LAST
+%left ORDINAL HERE '`'
+
+/* these need to be lower than '-' */
+%left HEIGHT RADIUS WIDTH DIAMETER FROM TO AT THICKNESS
+
+/* these must have higher precedence than CHOP so that `label %prec CHOP'
+works */
+%left DOT_N DOT_E DOT_W DOT_S DOT_NE DOT_SE DOT_NW DOT_SW DOT_C
+%left DOT_START DOT_END TOP BOTTOM LEFT_CORNER RIGHT_CORNER
+%left UPPER LOWER CENTER START END
+
+%left ','
+%left OROR
+%left ANDAND
+%left EQUALEQUAL NOTEQUAL
+%left '<' '>' LESSEQUAL GREATEREQUAL
+
+%left BETWEEN OF
+%left AND
+
+%left '+' '-'
+%left '*' '/' '%'
+%right '!'
+%right '^'
+
+%type <x> expr any_expr text_expr
+%type <by> optional_by
+%type <pair> expr_pair position_not_place
+%type <if_data> simple_if
+%type <obj> nth_primitive
+%type <crn> corner
+%type <pth> path label_path relative_path
+%type <pl> place label element element_list middle_element_list
+%type <spec> object_spec
+%type <pair> position
+%type <obtype> object_type
+%type <n> optional_ordinal_last ordinal
+%type <str> until
+%type <dv> sprintf_args
+%type <lstr> text print_args print_arg
+
+%%
+
+top:
+ optional_separator
+ | element_list
+ {
+ if (olist.head)
+ print_picture(olist.head);
+ }
+ ;
+
+
+element_list:
+ optional_separator middle_element_list optional_separator
+ { $$ = $2; }
+ ;
+
+middle_element_list:
+ element
+ { $$ = $1; }
+ | middle_element_list separator element
+ { $$ = $1; }
+ ;
+
+optional_separator:
+ /* empty */
+ | separator
+ ;
+
+separator:
+ ';'
+ | separator ';'
+ ;
+
+placeless_element:
+ VARIABLE '=' any_expr
+ {
+ define_variable($1, $3);
+ a_delete $1;
+ }
+ | VARIABLE ':' '=' any_expr
+ {
+ place *p = lookup_label($1);
+ if (!p) {
+ lex_error("variable `%1' not defined", $1);
+ YYABORT;
+ }
+ p->obj = 0;
+ p->x = $4;
+ p->y = 0.0;
+ a_delete $1;
+ }
+ | UP
+ { current_direction = UP_DIRECTION; }
+ | DOWN
+ { current_direction = DOWN_DIRECTION; }
+ | LEFT
+ { current_direction = LEFT_DIRECTION; }
+ | RIGHT
+ { current_direction = RIGHT_DIRECTION; }
+ | COMMAND_LINE
+ {
+ olist.append(make_command_object($1.str, $1.filename,
+ $1.lineno));
+ }
+ | COMMAND print_args
+ {
+ olist.append(make_command_object($2.str, $2.filename,
+ $2.lineno));
+ }
+ | PRINT print_args
+ {
+ fprintf(stderr, "%s\n", $2.str);
+ a_delete $2.str;
+ fflush(stderr);
+ }
+ | SH
+ { delim_flag = 1; }
+ DELIMITED
+ {
+ delim_flag = 0;
+ system($3);
+ a_delete $3;
+ }
+ | COPY TEXT
+ {
+ if (yychar < 0)
+ do_lookahead();
+ do_copy($2.str);
+ // do not delete the filename
+ }
+ | COPY TEXT THRU
+ { delim_flag = 2; }
+ DELIMITED
+ { delim_flag = 0; }
+ until
+ {
+ if (yychar < 0)
+ do_lookahead();
+ copy_file_thru($2.str, $5, $7);
+ // do not delete the filename
+ a_delete $5;
+ a_delete $7;
+ }
+ | COPY THRU
+ { delim_flag = 2; }
+ DELIMITED
+ { delim_flag = 0; }
+ until
+ {
+ if (yychar < 0)
+ do_lookahead();
+ copy_rest_thru($4, $6);
+ a_delete $4;
+ a_delete $6;
+ }
+ | FOR VARIABLE '=' expr TO expr optional_by DO
+ { delim_flag = 1; }
+ DELIMITED
+ {
+ delim_flag = 0;
+ if (yychar < 0)
+ do_lookahead();
+ do_for($2, $4, $6, $7.is_multiplicative, $7.val, $10);
+ }
+ | simple_if
+ {
+ if (yychar < 0)
+ do_lookahead();
+ if ($1.x != 0.0)
+ push_body($1.body);
+ a_delete $1.body;
+ }
+ | simple_if ELSE
+ { delim_flag = 1; }
+ DELIMITED
+ {
+ delim_flag = 0;
+ if (yychar < 0)
+ do_lookahead();
+ if ($1.x != 0.0)
+ push_body($1.body);
+ else
+ push_body($4);
+ a_delete $1.body;
+ a_delete $4;
+ }
+ | reset_variables
+ | RESET
+ { define_variable("scale", 1.0); }
+ ;
+
+reset_variables:
+ RESET VARIABLE
+ { reset($2); a_delete $2; }
+ | reset_variables VARIABLE
+ { reset($2); a_delete $2; }
+ | reset_variables ',' VARIABLE
+ { reset($3); a_delete $3; }
+ ;
+
+print_args:
+ print_arg
+ { $$ = $1; }
+ | print_args print_arg
+ {
+ $$.str = new char[strlen($1.str) + strlen($2.str) + 1];
+ strcpy($$.str, $1.str);
+ strcat($$.str, $2.str);
+ a_delete $1.str;
+ a_delete $2.str;
+ if ($1.filename) {
+ $$.filename = $1.filename;
+ $$.lineno = $1.lineno;
+ }
+ else if ($2.filename) {
+ $$.filename = $2.filename;
+ $$.lineno = $2.lineno;
+ }
+ }
+ ;
+
+print_arg:
+ expr %prec ','
+ {
+ $$.str = new char[GDIGITS + 1];
+ sprintf($$.str, "%g", $1);
+ $$.filename = 0;
+ $$.lineno = 0;
+ }
+ | text
+ { $$ = $1; }
+ | position %prec ','
+ {
+ $$.str = new char[GDIGITS + 2 + GDIGITS + 1];
+ sprintf($$.str, "%g, %g", $1.x, $1.y);
+ $$.filename = 0;
+ $$.lineno = 0;
+ }
+
+simple_if:
+ IF any_expr THEN
+ { delim_flag = 1; }
+ DELIMITED
+ { delim_flag = 0; $$.x = $2; $$.body = $5; }
+ ;
+
+until:
+ /* empty */
+ { $$ = 0; }
+ | UNTIL TEXT
+ { $$ = $2.str; }
+ ;
+
+any_expr:
+ expr
+ { $$ = $1; }
+ | text_expr
+ { $$ = $1; }
+ ;
+
+text_expr:
+ text EQUALEQUAL text
+ {
+ $$ = strcmp($1.str, $3.str) == 0;
+ a_delete $1.str;
+ a_delete $3.str;
+ }
+ | text NOTEQUAL text
+ {
+ $$ = strcmp($1.str, $3.str) != 0;
+ a_delete $1.str;
+ a_delete $3.str;
+ }
+ | text_expr ANDAND text_expr
+ { $$ = ($1 != 0.0 && $3 != 0.0); }
+ | text_expr ANDAND expr
+ { $$ = ($1 != 0.0 && $3 != 0.0); }
+ | expr ANDAND text_expr
+ { $$ = ($1 != 0.0 && $3 != 0.0); }
+ | text_expr OROR text_expr
+ { $$ = ($1 != 0.0 || $3 != 0.0); }
+ | text_expr OROR expr
+ { $$ = ($1 != 0.0 || $3 != 0.0); }
+ | expr OROR text_expr
+ { $$ = ($1 != 0.0 || $3 != 0.0); }
+ | '!' text_expr
+ { $$ = ($2 == 0.0); }
+ ;
+
+
+optional_by:
+ /* empty */
+ { $$.val = 1.0; $$.is_multiplicative = 0; }
+ | BY expr
+ { $$.val = $2; $$.is_multiplicative = 0; }
+ | BY '*' expr
+ { $$.val = $3; $$.is_multiplicative = 1; }
+ ;
+
+element:
+ object_spec
+ {
+ $$.obj = $1->make_object(&current_position,
+ &current_direction);
+ if ($$.obj == 0)
+ YYABORT;
+ delete $1;
+ if ($$.obj)
+ olist.append($$.obj);
+ else {
+ $$.x = current_position.x;
+ $$.y = current_position.y;
+ }
+ }
+ | LABEL ':' optional_separator element
+ { $$ = $4; define_label($1, & $$); a_delete $1; }
+ | LABEL ':' optional_separator position_not_place
+ {
+ $$.obj = 0;
+ $$.x = $4.x;
+ $$.y = $4.y;
+ define_label($1, & $$);
+ a_delete $1;
+ }
+ | LABEL ':' optional_separator place
+ {
+ $$ = $4;
+ define_label($1, & $$);
+ a_delete $1;
+ }
+ | '{'
+ {
+ $<state>$.x = current_position.x;
+ $<state>$.y = current_position.y;
+ $<state>$.dir = current_direction;
+ }
+ element_list '}'
+ {
+ current_position.x = $<state>2.x;
+ current_position.y = $<state>2.y;
+ current_direction = $<state>2.dir;
+ }
+ optional_element
+ {
+ $$ = $3;
+ }
+ | placeless_element
+ {
+ $$.obj = 0;
+ $$.x = current_position.x;
+ $$.y = current_position.y;
+ }
+ ;
+
+optional_element:
+ /* empty */
+ {}
+ | element
+ {}
+ ;
+
+object_spec:
+ BOX
+ {
+ $$ = new object_spec(BOX_OBJECT);
+ }
+ | CIRCLE
+ {
+ $$ = new object_spec(CIRCLE_OBJECT);
+ }
+ | ELLIPSE
+ {
+ $$ = new object_spec(ELLIPSE_OBJECT);
+ }
+ | ARC
+ {
+ $$ = new object_spec(ARC_OBJECT);
+ $$->dir = current_direction;
+ }
+ | LINE
+ {
+ $$ = new object_spec(LINE_OBJECT);
+ lookup_variable("lineht", & $$->segment_height);
+ lookup_variable("linewid", & $$->segment_width);
+ $$->dir = current_direction;
+ }
+ | ARROW
+ {
+ $$ = new object_spec(ARROW_OBJECT);
+ lookup_variable("lineht", & $$->segment_height);
+ lookup_variable("linewid", & $$->segment_width);
+ $$->dir = current_direction;
+ }
+ | MOVE
+ {
+ $$ = new object_spec(MOVE_OBJECT);
+ lookup_variable("moveht", & $$->segment_height);
+ lookup_variable("movewid", & $$->segment_width);
+ $$->dir = current_direction;
+ }
+ | SPLINE
+ {
+ $$ = new object_spec(SPLINE_OBJECT);
+ lookup_variable("lineht", & $$->segment_height);
+ lookup_variable("linewid", & $$->segment_width);
+ $$->dir = current_direction;
+ }
+ | text %prec TEXT
+ {
+ $$ = new object_spec(TEXT_OBJECT);
+ $$->text = new text_item($1.str, $1.filename, $1.lineno);
+ }
+ | PLOT expr
+ {
+ $$ = new object_spec(TEXT_OBJECT);
+ $$->text = new text_item(format_number(0, $2), 0, -1);
+ }
+ | PLOT expr text
+ {
+ $$ = new object_spec(TEXT_OBJECT);
+ $$->text = new text_item(format_number($3.str, $2),
+ $3.filename, $3.lineno);
+ a_delete $3.str;
+ }
+ | '['
+ {
+ saved_state *p = new saved_state;
+ $<pstate>$ = p;
+ p->x = current_position.x;
+ p->y = current_position.y;
+ p->dir = current_direction;
+ p->tbl = current_table;
+ p->prev = current_saved_state;
+ current_position.x = 0.0;
+ current_position.y = 0.0;
+ current_table = new PTABLE(place);
+ current_saved_state = p;
+ olist.append(make_mark_object());
+ }
+ element_list ']'
+ {
+ current_position.x = $<pstate>2->x;
+ current_position.y = $<pstate>2->y;
+ current_direction = $<pstate>2->dir;
+ $$ = new object_spec(BLOCK_OBJECT);
+ olist.wrap_up_block(& $$->oblist);
+ $$->tbl = current_table;
+ current_table = $<pstate>2->tbl;
+ current_saved_state = $<pstate>2->prev;
+ delete $<pstate>2;
+ }
+ | object_spec HEIGHT expr
+ {
+ $$ = $1;
+ $$->height = $3;
+ $$->flags |= HAS_HEIGHT;
+ }
+ | object_spec RADIUS expr
+ {
+ $$ = $1;
+ $$->radius = $3;
+ $$->flags |= HAS_RADIUS;
+ }
+ | object_spec WIDTH expr
+ {
+ $$ = $1;
+ $$->width = $3;
+ $$->flags |= HAS_WIDTH;
+ }
+ | object_spec DIAMETER expr
+ {
+ $$ = $1;
+ $$->radius = $3/2.0;
+ $$->flags |= HAS_RADIUS;
+ }
+ | object_spec expr %prec HEIGHT
+ {
+ $$ = $1;
+ $$->flags |= HAS_SEGMENT;
+ switch ($$->dir) {
+ case UP_DIRECTION:
+ $$->segment_pos.y += $2;
+ break;
+ case DOWN_DIRECTION:
+ $$->segment_pos.y -= $2;
+ break;
+ case RIGHT_DIRECTION:
+ $$->segment_pos.x += $2;
+ break;
+ case LEFT_DIRECTION:
+ $$->segment_pos.x -= $2;
+ break;
+ }
+ }
+ | object_spec UP
+ {
+ $$ = $1;
+ $$->dir = UP_DIRECTION;
+ $$->flags |= HAS_SEGMENT;
+ $$->segment_pos.y += $$->segment_height;
+ }
+ | object_spec UP expr
+ {
+ $$ = $1;
+ $$->dir = UP_DIRECTION;
+ $$->flags |= HAS_SEGMENT;
+ $$->segment_pos.y += $3;
+ }
+ | object_spec DOWN
+ {
+ $$ = $1;
+ $$->dir = DOWN_DIRECTION;
+ $$->flags |= HAS_SEGMENT;
+ $$->segment_pos.y -= $$->segment_height;
+ }
+ | object_spec DOWN expr
+ {
+ $$ = $1;
+ $$->dir = DOWN_DIRECTION;
+ $$->flags |= HAS_SEGMENT;
+ $$->segment_pos.y -= $3;
+ }
+ | object_spec RIGHT
+ {
+ $$ = $1;
+ $$->dir = RIGHT_DIRECTION;
+ $$->flags |= HAS_SEGMENT;
+ $$->segment_pos.x += $$->segment_width;
+ }
+ | object_spec RIGHT expr
+ {
+ $$ = $1;
+ $$->dir = RIGHT_DIRECTION;
+ $$->flags |= HAS_SEGMENT;
+ $$->segment_pos.x += $3;
+ }
+ | object_spec LEFT
+ {
+ $$ = $1;
+ $$->dir = LEFT_DIRECTION;
+ $$->flags |= HAS_SEGMENT;
+ $$->segment_pos.x -= $$->segment_width;
+ }
+ | object_spec LEFT expr
+ {
+ $$ = $1;
+ $$->dir = LEFT_DIRECTION;
+ $$->flags |= HAS_SEGMENT;
+ $$->segment_pos.x -= $3;
+ }
+ | object_spec FROM position
+ {
+ $$ = $1;
+ $$->flags |= HAS_FROM;
+ $$->from.x = $3.x;
+ $$->from.y = $3.y;
+ }
+ | object_spec TO position
+ {
+ $$ = $1;
+ if ($$->flags & HAS_SEGMENT)
+ $$->segment_list = new segment($$->segment_pos,
+ $$->segment_is_absolute,
+ $$->segment_list);
+ $$->flags |= HAS_SEGMENT;
+ $$->segment_pos.x = $3.x;
+ $$->segment_pos.y = $3.y;
+ $$->segment_is_absolute = 1;
+ $$->flags |= HAS_TO;
+ $$->to.x = $3.x;
+ $$->to.y = $3.y;
+ }
+ | object_spec AT position
+ {
+ $$ = $1;
+ $$->flags |= HAS_AT;
+ $$->at.x = $3.x;
+ $$->at.y = $3.y;
+ if ($$->type != ARC_OBJECT) {
+ $$->flags |= HAS_FROM;
+ $$->from.x = $3.x;
+ $$->from.y = $3.y;
+ }
+ }
+ | object_spec WITH path
+ {
+ $$ = $1;
+ $$->flags |= HAS_WITH;
+ $$->with = $3;
+ }
+ | object_spec BY expr_pair
+ {
+ $$ = $1;
+ $$->flags |= HAS_SEGMENT;
+ $$->segment_pos.x += $3.x;
+ $$->segment_pos.y += $3.y;
+ }
+ | object_spec THEN
+ {
+ $$ = $1;
+ if ($$->flags & HAS_SEGMENT) {
+ $$->segment_list = new segment($$->segment_pos,
+ $$->segment_is_absolute,
+ $$->segment_list);
+ $$->flags &= ~HAS_SEGMENT;
+ $$->segment_pos.x = $$->segment_pos.y = 0.0;
+ $$->segment_is_absolute = 0;
+ }
+ }
+ | object_spec DOTTED
+ {
+ $$ = $1;
+ $$->flags |= IS_DOTTED;
+ lookup_variable("dashwid", & $$->dash_width);
+ }
+ | object_spec DOTTED expr
+ {
+ $$ = $1;
+ $$->flags |= IS_DOTTED;
+ $$->dash_width = $3;
+ }
+ | object_spec DASHED
+ {
+ $$ = $1;
+ $$->flags |= IS_DASHED;
+ lookup_variable("dashwid", & $$->dash_width);
+ }
+ | object_spec DASHED expr
+ {
+ $$ = $1;
+ $$->flags |= IS_DASHED;
+ $$->dash_width = $3;
+ }
+ | object_spec FILL
+ {
+ $$ = $1;
+ $$->flags |= IS_DEFAULT_FILLED;
+ }
+ | object_spec FILL expr
+ {
+ $$ = $1;
+ $$->flags |= IS_FILLED;
+ $$->fill = $3;
+ }
+ | object_spec CHOP
+ {
+ $$ = $1;
+ // line chop chop means line chop 0 chop 0
+ if ($$->flags & IS_DEFAULT_CHOPPED) {
+ $$->flags |= IS_CHOPPED;
+ $$->flags &= ~IS_DEFAULT_CHOPPED;
+ $$->start_chop = $$->end_chop = 0.0;
+ }
+ else if ($$->flags & IS_CHOPPED) {
+ $$->end_chop = 0.0;
+ }
+ else {
+ $$->flags |= IS_DEFAULT_CHOPPED;
+ }
+ }
+ | object_spec CHOP expr
+ {
+ $$ = $1;
+ if ($$->flags & IS_DEFAULT_CHOPPED) {
+ $$->flags |= IS_CHOPPED;
+ $$->flags &= ~IS_DEFAULT_CHOPPED;
+ $$->start_chop = 0.0;
+ $$->end_chop = $3;
+ }
+ else if ($$->flags & IS_CHOPPED) {
+ $$->end_chop = $3;
+ }
+ else {
+ $$->start_chop = $$->end_chop = $3;
+ $$->flags |= IS_CHOPPED;
+ }
+ }
+ | object_spec SAME
+ {
+ $$ = $1;
+ $$->flags |= IS_SAME;
+ }
+ | object_spec INVISIBLE
+ {
+ $$ = $1;
+ $$->flags |= IS_INVISIBLE;
+ }
+ | object_spec LEFT_ARROW_HEAD
+ {
+ $$ = $1;
+ $$->flags |= HAS_LEFT_ARROW_HEAD;
+ }
+ | object_spec RIGHT_ARROW_HEAD
+ {
+ $$ = $1;
+ $$->flags |= HAS_RIGHT_ARROW_HEAD;
+ }
+ | object_spec DOUBLE_ARROW_HEAD
+ {
+ $$ = $1;
+ $$->flags |= (HAS_LEFT_ARROW_HEAD|HAS_RIGHT_ARROW_HEAD);
+ }
+ | object_spec CW
+ {
+ $$ = $1;
+ $$->flags |= IS_CLOCKWISE;
+ }
+ | object_spec CCW
+ {
+ $$ = $1;
+ $$->flags &= ~IS_CLOCKWISE;
+ }
+ | object_spec text %prec TEXT
+ {
+ $$ = $1;
+ for (text_item **p = & $$->text; *p; p = &(*p)->next)
+ ;
+ *p = new text_item($2.str, $2.filename, $2.lineno);
+ }
+ | object_spec LJUST
+ {
+ $$ = $1;
+ if ($$->text) {
+ for (text_item *p = $$->text; p->next; p = p->next)
+ ;
+ p->adj.h = LEFT_ADJUST;
+ }
+ }
+ | object_spec RJUST
+ {
+ $$ = $1;
+ if ($$->text) {
+ for (text_item *p = $$->text; p->next; p = p->next)
+ ;
+ p->adj.h = RIGHT_ADJUST;
+ }
+ }
+ | object_spec ABOVE
+ {
+ $$ = $1;
+ if ($$->text) {
+ for (text_item *p = $$->text; p->next; p = p->next)
+ ;
+ p->adj.v = ABOVE_ADJUST;
+ }
+ }
+ | object_spec BELOW
+ {
+ $$ = $1;
+ if ($$->text) {
+ for (text_item *p = $$->text; p->next; p = p->next)
+ ;
+ p->adj.v = BELOW_ADJUST;
+ }
+ }
+ | object_spec THICKNESS expr
+ {
+ $$ = $1;
+ $$->flags |= HAS_THICKNESS;
+ $$->thickness = $3;
+ }
+ | object_spec ALIGNED
+ {
+ $$ = $1;
+ $$->flags |= IS_ALIGNED;
+ }
+ ;
+
+text:
+ TEXT
+ {
+ $$ = $1;
+ }
+ | SPRINTF '(' TEXT sprintf_args ')'
+ {
+ $$.filename = $3.filename;
+ $$.lineno = $3.lineno;
+ $$.str = do_sprintf($3.str, $4.v, $4.nv);
+ a_delete $4.v;
+ a_delete $3.str;
+ }
+ ;
+
+sprintf_args:
+ /* empty */
+ {
+ $$.v = 0;
+ $$.nv = 0;
+ $$.maxv = 0;
+ }
+ | sprintf_args ',' expr
+ {
+ $$ = $1;
+ if ($$.nv >= $$.maxv) {
+ if ($$.nv == 0) {
+ $$.v = new double[4];
+ $$.maxv = 4;
+ }
+ else {
+ double *oldv = $$.v;
+ $$.maxv *= 2;
+ $$.v = new double[$$.maxv];
+ memcpy($$.v, oldv, $$.nv*sizeof(double));
+ a_delete oldv;
+ }
+ }
+ $$.v[$$.nv] = $3;
+ $$.nv += 1;
+ }
+ ;
+
+position:
+ position_not_place
+ { $$ = $1; }
+ | place
+ {
+ position pos = $1;
+ $$.x = pos.x;
+ $$.y = pos.y;
+ }
+ ;
+
+position_not_place:
+ expr_pair
+ { $$ = $1; }
+ | position '+' expr_pair
+ {
+ $$.x = $1.x + $3.x;
+ $$.y = $1.y + $3.y;
+ }
+ | position '-' expr_pair
+ {
+ $$.x = $1.x - $3.x;
+ $$.y = $1.y - $3.y;
+ }
+ | '(' position ',' position ')'
+ {
+ $$.x = $2.x;
+ $$.y = $4.y;
+ }
+ | expr between position AND position
+ {
+ $$.x = (1.0 - $1)*$3.x + $1*$5.x;
+ $$.y = (1.0 - $1)*$3.y + $1*$5.y;
+ }
+ | expr '<' position ',' position '>'
+ {
+ $$.x = (1.0 - $1)*$3.x + $1*$5.x;
+ $$.y = (1.0 - $1)*$3.y + $1*$5.y;
+ }
+ ;
+
+between:
+ BETWEEN
+ | OF THE WAY BETWEEN
+ ;
+
+expr_pair:
+ expr ',' expr
+ { $$.x = $1; $$.y = $3; }
+ | '(' expr_pair ')'
+ { $$ = $2; }
+ ;
+
+place:
+ label %prec CHOP /* line at A left == line (at A) left */
+ { $$ = $1; }
+ | label corner
+ {
+ path pth($2);
+ if (!pth.follow($1, & $$))
+ YYABORT;
+ }
+ | corner label
+ {
+ path pth($1);
+ if (!pth.follow($2, & $$))
+ YYABORT;
+ }
+ | corner OF label
+ {
+ path pth($1);
+ if (!pth.follow($3, & $$))
+ YYABORT;
+ }
+ | HERE
+ {
+ $$.x = current_position.x;
+ $$.y = current_position.y;
+ $$.obj = 0;
+ }
+ ;
+
+label:
+ LABEL
+ {
+ place *p = lookup_label($1);
+ if (!p) {
+ lex_error("there is no place `%1'", $1);
+ YYABORT;
+ }
+ $$ = *p;
+ a_delete $1;
+ }
+ | nth_primitive
+ {
+ $$.obj = $1;
+ }
+ | label '.' LABEL
+ {
+ path pth($3);
+ if (!pth.follow($1, & $$))
+ YYABORT;
+ }
+ ;
+
+ordinal:
+ ORDINAL
+ { $$ = $1; }
+ | '`' any_expr TH
+ {
+ // XXX Check for overflow (and non-integers?).
+ $$ = (int)$2;
+ }
+ ;
+
+optional_ordinal_last:
+ LAST
+ { $$ = 1; }
+ | ordinal LAST
+ { $$ = $1; }
+ ;
+
+nth_primitive:
+ ordinal object_type
+ {
+ int count = 0;
+ for (object *p = olist.head; p != 0; p = p->next)
+ if (p->type() == $2 && ++count == $1) {
+ $$ = p;
+ break;
+ }
+ if (p == 0) {
+ lex_error("there is no %1%2 %3", $1, ordinal_postfix($1),
+ object_type_name($2));
+ YYABORT;
+ }
+ }
+ | optional_ordinal_last object_type
+ {
+ int count = 0;
+ for (object *p = olist.tail; p != 0; p = p->prev)
+ if (p->type() == $2 && ++count == $1) {
+ $$ = p;
+ break;
+ }
+ if (p == 0) {
+ lex_error("there is no %1%2 last %3", $1,
+ ordinal_postfix($1), object_type_name($2));
+ YYABORT;
+ }
+ }
+ ;
+
+object_type:
+ BOX
+ { $$ = BOX_OBJECT; }
+ | CIRCLE
+ { $$ = CIRCLE_OBJECT; }
+ | ELLIPSE
+ { $$ = ELLIPSE_OBJECT; }
+ | ARC
+ { $$ = ARC_OBJECT; }
+ | LINE
+ { $$ = LINE_OBJECT; }
+ | ARROW
+ { $$ = ARROW_OBJECT; }
+ | SPLINE
+ { $$ = SPLINE_OBJECT; }
+ | '[' ']'
+ { $$ = BLOCK_OBJECT; }
+ | TEXT
+ { $$ = TEXT_OBJECT; }
+ ;
+
+label_path:
+ '.' LABEL
+ {
+ $$ = new path($2);
+ }
+ | label_path '.' LABEL
+ {
+ $$ = $1;
+ $$->append($3);
+ }
+ ;
+
+relative_path:
+ corner
+ {
+ $$ = new path($1);
+ }
+ /* give this a lower precedence than LEFT and RIGHT so that
+ [A: box] with .A left == [A: box] with (.A left) */
+
+ | label_path %prec TEXT
+ {
+ $$ = $1;
+ }
+ | label_path corner
+ {
+ $$ = $1;
+ $$->append($2);
+ }
+ ;
+
+path:
+ relative_path
+ {
+ $$ = $1;
+ }
+ /* The rest of these rules are a compatibility sop. */
+ | ORDINAL LAST object_type relative_path
+ {
+ lex_warning("`%1%2 last %3' in `with' argument ignored",
+ $1, ordinal_postfix($1), object_type_name($3));
+ $$ = $4;
+ }
+ | LAST object_type relative_path
+ {
+ lex_warning("`last %1' in `with' argument ignored",
+ object_type_name($2));
+ $$ = $3;
+ }
+ | ORDINAL object_type relative_path
+ {
+ lex_warning("`%1%2 %3' in `with' argument ignored",
+ $1, ordinal_postfix($1), object_type_name($2));
+ $$ = $3;
+ }
+ | LABEL relative_path
+ {
+ lex_warning("initial `%1' in `with' argument ignored", $1);
+ a_delete $1;
+ $$ = $2;
+ }
+ ;
+
+corner:
+ DOT_N
+ { $$ = &object::north; }
+ | DOT_E
+ { $$ = &object::east; }
+ | DOT_W
+ { $$ = &object::west; }
+ | DOT_S
+ { $$ = &object::south; }
+ | DOT_NE
+ { $$ = &object::north_east; }
+ | DOT_SE
+ { $$ = &object:: south_east; }
+ | DOT_NW
+ { $$ = &object::north_west; }
+ | DOT_SW
+ { $$ = &object::south_west; }
+ | DOT_C
+ { $$ = &object::center; }
+ | DOT_START
+ { $$ = &object::start; }
+ | DOT_END
+ { $$ = &object::end; }
+ | TOP
+ { $$ = &object::north; }
+ | BOTTOM
+ { $$ = &object::south; }
+ | LEFT
+ { $$ = &object::west; }
+ | RIGHT
+ { $$ = &object::east; }
+ | UPPER LEFT
+ { $$ = &object::north_west; }
+ | LOWER LEFT
+ { $$ = &object::south_west; }
+ | UPPER RIGHT
+ { $$ = &object::north_east; }
+ | LOWER RIGHT
+ { $$ = &object::south_east; }
+ | LEFT_CORNER
+ { $$ = &object::west; }
+ | RIGHT_CORNER
+ { $$ = &object::east; }
+ | UPPER LEFT_CORNER
+ { $$ = &object::north_west; }
+ | LOWER LEFT_CORNER
+ { $$ = &object::south_west; }
+ | UPPER RIGHT_CORNER
+ { $$ = &object::north_east; }
+ | LOWER RIGHT_CORNER
+ { $$ = &object::south_east; }
+ | CENTER
+ { $$ = &object::center; }
+ | START
+ { $$ = &object::start; }
+ | END
+ { $$ = &object::end; }
+ ;
+
+expr:
+ VARIABLE
+ {
+ if (!lookup_variable($1, & $$)) {
+ lex_error("there is no variable `%1'", $1);
+ YYABORT;
+ }
+ a_delete $1;
+ }
+ | NUMBER
+ { $$ = $1; }
+ | place DOT_X
+ {
+ if ($1.obj != 0)
+ $$ = $1.obj->origin().x;
+ else
+ $$ = $1.x;
+ }
+ | place DOT_Y
+ {
+ if ($1.obj != 0)
+ $$ = $1.obj->origin().y;
+ else
+ $$ = $1.y;
+ }
+ | place DOT_HT
+ {
+ if ($1.obj != 0)
+ $$ = $1.obj->height();
+ else
+ $$ = 0.0;
+ }
+ | place DOT_WID
+ {
+ if ($1.obj != 0)
+ $$ = $1.obj->width();
+ else
+ $$ = 0.0;
+ }
+ | place DOT_RAD
+ {
+ if ($1.obj != 0)
+ $$ = $1.obj->radius();
+ else
+ $$ = 0.0;
+ }
+ | expr '+' expr
+ { $$ = $1 + $3; }
+ | expr '-' expr
+ { $$ = $1 - $3; }
+ | expr '*' expr
+ { $$ = $1 * $3; }
+ | expr '/' expr
+ {
+ if ($3 == 0.0) {
+ lex_error("division by zero");
+ YYABORT;
+ }
+ $$ = $1/$3;
+ }
+ | expr '%' expr
+ {
+ if ($3 == 0.0) {
+ lex_error("modulus by zero");
+ YYABORT;
+ }
+ $$ = fmod($1, $3);
+ }
+ | expr '^' expr
+ {
+ errno = 0;
+ $$ = pow($1, $3);
+ if (errno == EDOM) {
+ lex_error("arguments to `^' operator out of domain");
+ YYABORT;
+ }
+ if (errno == ERANGE) {
+ lex_error("result of `^' operator out of range");
+ YYABORT;
+ }
+ }
+ | '-' expr %prec '!'
+ { $$ = -$2; }
+ | '(' any_expr ')'
+ { $$ = $2; }
+ | SIN '(' any_expr ')'
+ {
+ errno = 0;
+ $$ = sin($3);
+ if (errno == ERANGE) {
+ lex_error("sin result out of range");
+ YYABORT;
+ }
+ }
+ | COS '(' any_expr ')'
+ {
+ errno = 0;
+ $$ = cos($3);
+ if (errno == ERANGE) {
+ lex_error("cos result out of range");
+ YYABORT;
+ }
+ }
+ | ATAN2 '(' any_expr ',' any_expr ')'
+ {
+ errno = 0;
+ $$ = atan2($3, $5);
+ if (errno == EDOM) {
+ lex_error("atan2 argument out of domain");
+ YYABORT;
+ }
+ if (errno == ERANGE) {
+ lex_error("atan2 result out of range");
+ YYABORT;
+ }
+ }
+ | LOG '(' any_expr ')'
+ {
+ errno = 0;
+ $$ = log10($3);
+ if (errno == ERANGE) {
+ lex_error("log result out of range");
+ YYABORT;
+ }
+ }
+ | EXP '(' any_expr ')'
+ {
+ errno = 0;
+ $$ = pow(10.0, $3);
+ if (errno == ERANGE) {
+ lex_error("exp result out of range");
+ YYABORT;
+ }
+ }
+ | SQRT '(' any_expr ')'
+ {
+ errno = 0;
+ $$ = sqrt($3);
+ if (errno == EDOM) {
+ lex_error("sqrt argument out of domain");
+ YYABORT;
+ }
+ }
+ | K_MAX '(' any_expr ',' any_expr ')'
+ { $$ = $3 > $5 ? $3 : $5; }
+ | K_MIN '(' any_expr ',' any_expr ')'
+ { $$ = $3 < $5 ? $3 : $5; }
+ | INT '(' any_expr ')'
+ { $$ = floor($3); }
+ | RAND '(' any_expr ')'
+ { $$ = 1.0 + floor(((rand()&0x7fff)/double(0x7fff))*$3); }
+ | RAND '(' ')'
+ {
+ /* return a random number in the range [0,1) */
+ /* portable, but not very random */
+ $$ = (rand() & 0x7fff) / double(0x8000);
+ }
+ | expr '<' expr
+ { $$ = ($1 < $3); }
+ | expr LESSEQUAL expr
+ { $$ = ($1 <= $3); }
+ | expr '>' expr
+ { $$ = ($1 > $3); }
+ | expr GREATEREQUAL expr
+ { $$ = ($1 >= $3); }
+ | expr EQUALEQUAL expr
+ { $$ = ($1 == $3); }
+ | expr NOTEQUAL expr
+ { $$ = ($1 != $3); }
+ | expr ANDAND expr
+ { $$ = ($1 != 0.0 && $3 != 0.0); }
+ | expr OROR expr
+ { $$ = ($1 != 0.0 || $3 != 0.0); }
+ | '!' expr
+ { $$ = ($2 == 0.0); }
+
+ ;
+
+%%
+
+/* bison defines const to be empty unless __STDC__ is defined, which it
+isn't under cfront */
+
+#ifdef const
+#undef const
+#endif
+
+static struct {
+ const char *name;
+ double val;
+ int scaled; // non-zero if val should be multiplied by scale
+} defaults_table[] = {
+ { "arcrad", .25, 1 },
+ { "arrowht", .1, 1 },
+ { "arrowwid", .05, 1 },
+ { "circlerad", .25, 1 },
+ { "boxht", .5, 1 },
+ { "boxwid", .75, 1 },
+ { "boxrad", 0.0, 1 },
+ { "dashwid", .05, 1 },
+ { "ellipseht", .5, 1 },
+ { "ellipsewid", .75, 1 },
+ { "moveht", .5, 1 },
+ { "movewid", .5, 1 },
+ { "lineht", .5, 1 },
+ { "linewid", .5, 1 },
+ { "textht", 0.0, 1 },
+ { "textwid", 0.0, 1 },
+ { "scale", 1.0, 0 },
+ { "linethick", -1.0, 0 }, // in points
+ { "fillval", .5, 0 },
+ { "arrowhead", 1.0, 0 },
+ { "maxpswid", 8.5, 0 },
+ { "maxpsht", 11.0, 0 },
+};
+
+place *lookup_label(const char *label)
+{
+ saved_state *state = current_saved_state;
+ PTABLE(place) *tbl = current_table;
+ for (;;) {
+ place *pl = tbl->lookup(label);
+ if (pl)
+ return pl;
+ if (!state)
+ return 0;
+ tbl = state->tbl;
+ state = state->prev;
+ }
+}
+
+void define_label(const char *label, const place *pl)
+{
+ place *p = new place;
+ *p = *pl;
+ current_table->define(label, p);
+}
+
+int lookup_variable(const char *name, double *val)
+{
+ place *pl = lookup_label(name);
+ if (pl) {
+ *val = pl->x;
+ return 1;
+ }
+ return 0;
+}
+
+void define_variable(const char *name, double val)
+{
+ place *p = new place;
+ p->obj = 0;
+ p->x = val;
+ p->y = 0.0;
+ current_table->define(name, p);
+ if (strcmp(name, "scale") == 0) {
+ // When the scale changes, reset all scaled pre-defined variables to
+ // their default values.
+ for (int i = 0; i < sizeof(defaults_table)/sizeof(defaults_table[0]); i++)
+ if (defaults_table[i].scaled)
+ define_variable(defaults_table[i].name, val*defaults_table[i].val);
+ }
+}
+
+// called once only (not once per parse)
+
+void parse_init()
+{
+ current_direction = RIGHT_DIRECTION;
+ current_position.x = 0.0;
+ current_position.y = 0.0;
+ // This resets everything to its default value.
+ reset_all();
+}
+
+void reset(const char *nm)
+{
+ for (int i = 0; i < sizeof(defaults_table)/sizeof(defaults_table[0]); i++)
+ if (strcmp(nm, defaults_table[i].name) == 0) {
+ double val = defaults_table[i].val;
+ if (defaults_table[i].scaled) {
+ double scale;
+ lookup_variable("scale", &scale);
+ val *= scale;
+ }
+ define_variable(defaults_table[i].name, val);
+ return;
+ }
+ lex_error("`%1' is not a predefined variable", nm);
+}
+
+void reset_all()
+{
+ // We only have to explicitly reset the pre-defined variables that
+ // aren't scaled because `scale' is not scaled, and changing the
+ // value of `scale' will reset all the pre-defined variables that
+ // are scaled.
+ for (int i = 0; i < sizeof(defaults_table)/sizeof(defaults_table[0]); i++)
+ if (!defaults_table[i].scaled)
+ define_variable(defaults_table[i].name, defaults_table[i].val);
+}
+
+// called after each parse
+
+void parse_cleanup()
+{
+ while (current_saved_state != 0) {
+ delete current_table;
+ current_table = current_saved_state->tbl;
+ saved_state *tem = current_saved_state;
+ current_saved_state = current_saved_state->prev;
+ delete tem;
+ }
+ assert(current_table == &top_table);
+ PTABLE_ITERATOR(place) iter(current_table);
+ const char *key;
+ place *pl;
+ while (iter.next(&key, &pl))
+ if (pl->obj != 0) {
+ position pos = pl->obj->origin();
+ pl->obj = 0;
+ pl->x = pos.x;
+ pl->y = pos.y;
+ }
+ while (olist.head != 0) {
+ object *tem = olist.head;
+ olist.head = olist.head->next;
+ delete tem;
+ }
+ olist.tail = 0;
+ current_direction = RIGHT_DIRECTION;
+ current_position.x = 0.0;
+ current_position.y = 0.0;
+}
+
+const char *ordinal_postfix(int n)
+{
+ if (n < 10 || n > 20)
+ switch (n % 10) {
+ case 1:
+ return "st";
+ case 2:
+ return "nd";
+ case 3:
+ return "rd";
+ }
+ return "th";
+}
+
+const char *object_type_name(object_type type)
+{
+ switch (type) {
+ case BOX_OBJECT:
+ return "box";
+ case CIRCLE_OBJECT:
+ return "circle";
+ case ELLIPSE_OBJECT:
+ return "ellipse";
+ case ARC_OBJECT:
+ return "arc";
+ case SPLINE_OBJECT:
+ return "spline";
+ case LINE_OBJECT:
+ return "line";
+ case ARROW_OBJECT:
+ return "arrow";
+ case MOVE_OBJECT:
+ return "move";
+ case TEXT_OBJECT:
+ return "\"\"";
+ case BLOCK_OBJECT:
+ return "[]";
+ case OTHER_OBJECT:
+ case MARK_OBJECT:
+ default:
+ break;
+ }
+ return "object";
+}
+
+static char sprintf_buf[1024];
+
+char *format_number(const char *form, double n)
+{
+ if (form == 0)
+ form = "%g";
+ else {
+ // this is a fairly feeble attempt at validation of the format
+ int nspecs = 0;
+ for (const char *p = form; *p != '\0'; p++)
+ if (*p == '%') {
+ if (p[1] == '%')
+ p++;
+ else
+ nspecs++;
+ }
+ if (nspecs > 1) {
+ lex_error("bad format `%1'", form);
+ return strsave(form);
+ }
+ }
+ sprintf(sprintf_buf, form, n);
+ return strsave(sprintf_buf);
+}
+
+char *do_sprintf(const char *form, const double *v, int nv)
+{
+ string result;
+ int i = 0;
+ string one_format;
+ while (*form) {
+ if (*form == '%') {
+ one_format += *form++;
+ for (; *form != '\0' && strchr("#-+ 0123456789.", *form) != 0; form++)
+ one_format += *form;
+ if (*form == '\0' || strchr("eEfgG%", *form) == 0) {
+ lex_error("bad sprintf format");
+ result += one_format;
+ result += form;
+ break;
+ }
+ if (*form == '%') {
+ one_format += *form++;
+ one_format += '\0';
+ sprintf(sprintf_buf, one_format.contents());
+ }
+ else {
+ if (i >= nv) {
+ lex_error("too few arguments to sprintf");
+ result += one_format;
+ result += form;
+ break;
+ }
+ one_format += *form++;
+ one_format += '\0';
+ sprintf(sprintf_buf, one_format.contents(), v[i++]);
+ }
+ one_format.clear();
+ result += sprintf_buf;
+ }
+ else
+ result += *form++;
+ }
+ result += '\0';
+ return strsave(result.contents());
+}
diff --git a/gnu/usr.bin/groff/pic/position.h b/gnu/usr.bin/groff/pic/position.h
new file mode 100644
index 0000000..6706fb1
--- /dev/null
+++ b/gnu/usr.bin/groff/pic/position.h
@@ -0,0 +1,47 @@
+// -*- C++ -*-
+/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
+ Written by James Clark (jjc@jclark.com)
+
+This file is part of groff.
+
+groff is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
+
+groff is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License along
+with groff; see the file COPYING. If not, write to the Free Software
+Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+struct place;
+struct position {
+ double x;
+ double y;
+ position(double, double );
+ position();
+ position(const place &);
+ position &operator+=(const position &);
+ position &operator-=(const position &);
+ position &operator*=(double);
+ position &operator/=(double);
+};
+
+position operator-(const position &);
+position operator+(const position &, const position &);
+position operator-(const position &, const position &);
+position operator/(const position &, double);
+position operator*(const position &, double);
+// dot product
+double operator*(const position &, const position &);
+int operator==(const position &, const position &);
+int operator!=(const position &, const position &);
+
+double hypot(const position &a);
+
+typedef position distance;
+
diff --git a/gnu/usr.bin/groff/pic/tex.cc b/gnu/usr.bin/groff/pic/tex.cc
new file mode 100644
index 0000000..d0fd962
--- /dev/null
+++ b/gnu/usr.bin/groff/pic/tex.cc
@@ -0,0 +1,411 @@
+// -*- C++ -*-
+/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
+ Written by James Clark (jjc@jclark.com)
+
+This file is part of groff.
+
+groff is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
+
+groff is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License along
+with groff; see the file COPYING. If not, write to the Free Software
+Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "pic.h"
+
+#ifdef TEX_SUPPORT
+
+#include "common.h"
+
+class tex_output : public common_output {
+public:
+ tex_output();
+ ~tex_output();
+ void start_picture(double, const position &ll, const position &ur);
+ void finish_picture();
+ void text(const position &, text_piece *, int, double);
+ void line(const position &, const position *, int n,
+ const line_type &);
+ void polygon(const position *, int n,
+ const line_type &, double);
+ void spline(const position &, const position *, int n,
+ const line_type &);
+ void arc(const position &, const position &, const position &,
+ const line_type &);
+ void circle(const position &, double rad, const line_type &, double);
+ void ellipse(const position &, const distance &, const line_type &, double);
+ void command(const char *, const char *, int);
+ int supports_filled_polygons();
+private:
+ position upper_left;
+ double height;
+ double width;
+ double scale;
+ double pen_size;
+
+ void point(const position &);
+ void dot(const position &, const line_type &);
+ void solid_arc(const position &cent, double rad, double start_angle,
+ double end_angle, const line_type &lt);
+ position transform(const position &);
+protected:
+ virtual void set_pen_size(double ps);
+};
+
+// convert inches to milliinches
+
+inline int milliinches(double x)
+{
+ return int(x*1000.0 + .5);
+}
+
+inline position tex_output::transform(const position &pos)
+{
+ return position((pos.x - upper_left.x)/scale,
+ (upper_left.y - pos.y)/scale);
+}
+
+output *make_tex_output()
+{
+ return new tex_output;
+}
+
+tex_output::tex_output()
+{
+}
+
+tex_output::~tex_output()
+{
+}
+
+const int DEFAULT_PEN_SIZE = 8;
+
+void tex_output::set_pen_size(double ps)
+{
+ if (ps < 0.0)
+ ps = -1.0;
+ if (ps != pen_size) {
+ pen_size = ps;
+ printf(" \\special{pn %d}%%\n",
+ ps < 0.0 ? DEFAULT_PEN_SIZE : int(ps*(1000.0/72.0) + .5));
+ }
+}
+
+void tex_output::start_picture(double sc, const position &ll,
+ const position &ur)
+{
+ upper_left.x = ll.x;
+ upper_left.y = ur.y;
+ scale = compute_scale(sc, ll, ur);
+ height = (ur.y - ll.y)/scale;
+ width = (ur.x - ll.x)/scale;
+ /* the point of \vskip 0pt is to ensure that the vtop gets
+ a height of 0 rather than the height of the hbox; this
+ might be non-zero if text from text attributes lies outside pic's
+ idea of the bounding box of the picture. */
+ fputs("\\expandafter\\ifx\\csname graph\\endcsname\\relax \\csname newbox\\endcsname\\graph\\fi\n"
+ "\\expandafter\\ifx\\csname graphtemp\\endcsname\\relax \\csname newdimen\\endcsname\\graphtemp\\fi\n"
+ "\\setbox\\graph=\\vtop{\\vskip 0pt\\hbox{%\n",
+ stdout);
+ pen_size = -2.0;
+}
+
+void tex_output::finish_picture()
+{
+ printf(" \\hbox{\\vrule depth%.3fin width0pt height 0pt}%%\n"
+ " \\kern %.3fin\n"
+ " }%%\n"
+ "}%%\n",
+ height, width);
+}
+
+void tex_output::text(const position &center, text_piece *v, int n, double)
+{
+ position c = transform(center);
+ for (int i = 0; i < n; i++)
+ if (v[i].text != 0 && *v[i].text != '\0') {
+ int j = 2*i - n + 1;
+ if (v[i].adj.v == ABOVE_ADJUST)
+ j--;
+ else if (v[i].adj.v == BELOW_ADJUST)
+ j++;
+ if (j == 0) {
+ printf(" \\graphtemp=.5ex\\advance\\graphtemp by %.3fin\n", c.y);
+ }
+ else {
+ printf(" \\graphtemp=\\baselineskip"
+ "\\multiply\\graphtemp by %d"
+ "\\divide\\graphtemp by 2\n"
+ " \\advance\\graphtemp by .5ex"
+ "\\advance\\graphtemp by %.3fin\n",
+ j, c.y);
+ }
+ printf(" \\rlap{\\kern %.3fin\\lower\\graphtemp", c.x);
+ fputs("\\hbox to 0pt{", stdout);
+ if (v[i].adj.h != LEFT_ADJUST)
+ fputs("\\hss ", stdout);
+ fputs(v[i].text, stdout);
+ if (v[i].adj.h != RIGHT_ADJUST)
+ fputs("\\hss", stdout);
+ fputs("}}%\n", stdout);
+ }
+}
+
+void tex_output::point(const position &pos)
+{
+ position p = transform(pos);
+ printf(" \\special{pa %d %d}%%\n", milliinches(p.x), milliinches(p.y));
+}
+
+void tex_output::line(const position &start, const position *v, int n,
+ const line_type &lt)
+{
+ set_pen_size(lt.thickness);
+ point(start);
+ for (int i = 0; i < n; i++)
+ point(v[i]);
+ fputs(" \\special{", stdout);
+ switch(lt.type) {
+ case line_type::invisible:
+ fputs("ip", stdout);
+ break;
+ case line_type::solid:
+ fputs("fp", stdout);
+ break;
+ case line_type::dotted:
+ printf("dt %.3f", lt.dash_width/scale);
+ break;
+ case line_type::dashed:
+ printf("da %.3f", lt.dash_width/scale);
+ break;
+ }
+ fputs("}%\n", stdout);
+}
+
+void tex_output::polygon(const position *v, int n,
+ const line_type &lt, double fill)
+{
+ if (fill >= 0.0) {
+ if (fill > 1.0)
+ fill = 1.0;
+ printf(" \\special{sh %.3f}%%\n", fill);
+ }
+ line(v[n-1], v, n, lt);
+}
+
+void tex_output::spline(const position &start, const position *v, int n,
+ const line_type &lt)
+{
+ if (lt.type == line_type::invisible)
+ return;
+ set_pen_size(lt.thickness);
+ point(start);
+ for (int i = 0; i < n; i++)
+ point(v[i]);
+ fputs(" \\special{sp", stdout);
+ switch(lt.type) {
+ case line_type::solid:
+ break;
+ case line_type::dotted:
+ printf(" %.3f", -lt.dash_width/scale);
+ break;
+ case line_type::dashed:
+ printf(" %.3f", lt.dash_width/scale);
+ break;
+ case line_type::invisible:
+ assert(0);
+ }
+ fputs("}%\n", stdout);
+}
+
+void tex_output::solid_arc(const position &cent, double rad,
+ double start_angle, double end_angle,
+ const line_type &lt)
+{
+ set_pen_size(lt.thickness);
+ position c = transform(cent);
+ printf(" \\special{ar %d %d %d %d %f %f}%%\n",
+ milliinches(c.x),
+ milliinches(c.y),
+ milliinches(rad/scale),
+ milliinches(rad/scale),
+ -end_angle,
+ (-end_angle > -start_angle) ? M_PI * 2 - start_angle : -start_angle);
+}
+
+void tex_output::arc(const position &start, const position &cent,
+ const position &end, const line_type &lt)
+{
+ switch (lt.type) {
+ case line_type::invisible:
+ break;
+ case line_type::dashed:
+ dashed_arc(start, cent, end, lt);
+ break;
+ case line_type::dotted:
+ dotted_arc(start, cent, end, lt);
+ break;
+ case line_type::solid:
+ {
+ position c;
+ if (!compute_arc_center(start, cent, end, &c)) {
+ line(start, &end, 1, lt);
+ break;
+ }
+ solid_arc(c,
+ hypot(cent - start),
+ atan2(start.y - c.y, start.x - c.x),
+ atan2(end.y - c.y, end.x - c.x),
+ lt);
+ break;
+ }
+ }
+}
+
+void tex_output::circle(const position &cent, double rad,
+ const line_type &lt, double fill)
+{
+ if (fill >= 0.0 && lt.type != line_type::solid) {
+ if (fill > 1.0)
+ fill = 1.0;
+ line_type ilt;
+ ilt.type = line_type::invisible;
+ ellipse(cent, position(rad*2.0, rad*2.0), ilt, fill);
+ }
+ switch (lt.type) {
+ case line_type::dashed:
+ dashed_circle(cent, rad, lt);
+ break;
+ case line_type::invisible:
+ break;
+ case line_type::solid:
+ ellipse(cent, position(rad*2.0,rad*2.0), lt, fill);
+ break;
+ case line_type::dotted:
+ dotted_circle(cent, rad, lt);
+ break;
+ default:
+ assert(0);
+ }
+}
+
+void tex_output::ellipse(const position &cent, const distance &dim,
+ const line_type &lt, double fill)
+{
+ if (lt.type == line_type::invisible) {
+ if (fill < 0.0)
+ return;
+ }
+ else
+ set_pen_size(lt.thickness);
+ if (fill >= 0.0) {
+ if (fill > 1.0)
+ fill = 1.0;
+ printf(" \\special{sh %.3f}%%\n", fill);
+ }
+ position c = transform(cent);
+ printf(" \\special{%s %d %d %d %d 0 6.28319}%%\n",
+ (lt.type == line_type::invisible ? "ia" : "ar"),
+ milliinches(c.x),
+ milliinches(c.y),
+ milliinches(dim.x/(2.0*scale)),
+ milliinches(dim.y/(2.0*scale)));
+}
+
+void tex_output::command(const char *s, const char *, int)
+{
+ fputs(s, stdout);
+ putchar('%'); // avoid unwanted spaces
+ putchar('\n');
+}
+
+int tex_output::supports_filled_polygons()
+{
+ return 1;
+}
+
+void tex_output::dot(const position &pos, const line_type &lt)
+{
+ if (zero_length_line_flag) {
+ line_type slt = lt;
+ slt.type = line_type::solid;
+ line(pos, &pos, 1, slt);
+ }
+ else {
+ int dot_rad = int(lt.thickness*(1000.0/(72.0*2)) + .5);
+ if (dot_rad == 0)
+ dot_rad = 1;
+ position p = transform(pos);
+ printf(" \\special{sh 1}%%\n"
+ " \\special{ia %d %d %d %d 0 6.28319}%%\n",
+ milliinches(p.x), milliinches(p.y), dot_rad, dot_rad);
+ }
+}
+
+class tpic_output : public tex_output {
+public:
+ tpic_output();
+ void command(const char *, const char *, int);
+private:
+ void set_pen_size(double ps);
+ int default_pen_size;
+ int prev_default_pen_size;
+};
+
+tpic_output::tpic_output()
+: default_pen_size(DEFAULT_PEN_SIZE), prev_default_pen_size(DEFAULT_PEN_SIZE)
+{
+}
+
+void tpic_output::command(const char *s, const char *filename, int lineno)
+{
+ assert(s[0] == '.');
+ if (s[1] == 'p' && s[2] == 's' && (s[3] == '\0' || !csalpha(s[3]))) {
+ const char *p = s + 3;
+ while (csspace(*p))
+ p++;
+ if (*p == '\0') {
+ int temp = default_pen_size;
+ default_pen_size = prev_default_pen_size;
+ prev_default_pen_size = temp;
+ }
+ else {
+ char *ptr;
+ int temp = (int)strtol(p, &ptr, 10);
+ if (temp == 0 && ptr == p)
+ error_with_file_and_line(filename, lineno,
+ "argument to `.ps' not an integer");
+ else if (temp < 0)
+ error_with_file_and_line(filename, lineno,
+ "negative pen size");
+ else {
+ prev_default_pen_size = default_pen_size;
+ default_pen_size = temp;
+ }
+ }
+ }
+ else
+ printf("\\%s%%\n", s + 1);
+}
+
+void tpic_output::set_pen_size(double ps)
+{
+ if (ps < 0.0)
+ printf(" \\special{pn %d}%%\n", default_pen_size);
+ else
+ tex_output::set_pen_size(ps);
+}
+
+output *make_tpic_output()
+{
+ return new tpic_output;
+}
+
+#endif
diff --git a/gnu/usr.bin/groff/pic/text.h b/gnu/usr.bin/groff/pic/text.h
new file mode 100644
index 0000000..f9d3487
--- /dev/null
+++ b/gnu/usr.bin/groff/pic/text.h
@@ -0,0 +1,28 @@
+// -*- C++ -*-
+
+enum hadjustment {
+ CENTER_ADJUST,
+ LEFT_ADJUST,
+ RIGHT_ADJUST
+ };
+
+enum vadjustment {
+ NONE_ADJUST,
+ ABOVE_ADJUST,
+ BELOW_ADJUST
+ };
+
+struct adjustment {
+ hadjustment h;
+ vadjustment v;
+};
+
+struct text_piece {
+ char *text;
+ adjustment adj;
+ const char *filename;
+ int lineno;
+
+ text_piece();
+ ~text_piece();
+};
diff --git a/gnu/usr.bin/groff/pic/troff.cc b/gnu/usr.bin/groff/pic/troff.cc
new file mode 100644
index 0000000..6fd561c
--- /dev/null
+++ b/gnu/usr.bin/groff/pic/troff.cc
@@ -0,0 +1,500 @@
+// -*- C++ -*-
+/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
+ Written by James Clark (jjc@jclark.com)
+
+This file is part of groff.
+
+groff is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
+
+groff is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License along
+with groff; see the file COPYING. If not, write to the Free Software
+Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "pic.h"
+#include "common.h"
+
+
+const double RELATIVE_THICKNESS = -1.0;
+const double BAD_THICKNESS = -2.0;
+
+class simple_output : public common_output {
+ virtual void simple_line(const position &, const position &) = 0;
+ virtual void simple_spline(const position &, const position *, int n) = 0;
+ virtual void simple_arc(const position &, const position &,
+ const position &) = 0;
+ virtual void simple_circle(int, const position &, double rad) = 0;
+ virtual void simple_ellipse(int, const position &, const distance &) = 0;
+ virtual void simple_polygon(int, const position *, int) = 0;
+ virtual void line_thickness(double) = 0;
+ virtual void set_fill(double) = 0;
+ void dot(const position &, const line_type &) = 0;
+public:
+ void start_picture(double sc, const position &ll, const position &ur) = 0;
+ void finish_picture() = 0;
+ void text(const position &, text_piece *, int, double) = 0;
+ void line(const position &, const position *, int n,
+ const line_type &);
+ void polygon(const position *, int n,
+ const line_type &, double);
+ void spline(const position &, const position *, int n,
+ const line_type &);
+ void arc(const position &, const position &, const position &,
+ const line_type &);
+ void circle(const position &, double rad, const line_type &, double);
+ void ellipse(const position &, const distance &, const line_type &, double);
+ int supports_filled_polygons();
+};
+
+int simple_output::supports_filled_polygons()
+{
+ return driver_extension_flag != 0;
+}
+
+void simple_output::arc(const position &start, const position &cent,
+ const position &end, const line_type &lt)
+{
+ switch (lt.type) {
+ case line_type::solid:
+ line_thickness(lt.thickness);
+ simple_arc(start, cent, end);
+ break;
+ case line_type::invisible:
+ break;
+ case line_type::dashed:
+ dashed_arc(start, cent, end, lt);
+ break;
+ case line_type::dotted:
+ dotted_arc(start, cent, end, lt);
+ break;
+ }
+}
+
+void simple_output::line(const position &start, const position *v, int n,
+ const line_type &lt)
+{
+ position pos = start;
+ line_thickness(lt.thickness);
+ for (int i = 0; i < n; i++) {
+ switch (lt.type) {
+ case line_type::solid:
+ simple_line(pos, v[i]);
+ break;
+ case line_type::dotted:
+ {
+ distance vec(v[i] - pos);
+ double dist = hypot(vec);
+ int ndots = int(dist/lt.dash_width + .5);
+ if (ndots == 0)
+ dot(pos, lt);
+ else {
+ vec /= double(ndots);
+ for (int j = 0; j <= ndots; j++)
+ dot(pos + vec*j, lt);
+ }
+ }
+ break;
+ case line_type::dashed:
+ {
+ distance vec(v[i] - pos);
+ double dist = hypot(vec);
+ if (dist <= lt.dash_width*2.0)
+ simple_line(pos, v[i]);
+ else {
+ int ndashes = int((dist - lt.dash_width)/(lt.dash_width*2.0) + .5);
+ distance dash_vec = vec*(lt.dash_width/dist);
+ double dash_gap = (dist - lt.dash_width)/ndashes;
+ distance dash_gap_vec = vec*(dash_gap/dist);
+ for (int j = 0; j <= ndashes; j++) {
+ position s(pos + dash_gap_vec*j);
+ simple_line(s, s + dash_vec);
+ }
+ }
+ }
+ break;
+ case line_type::invisible:
+ break;
+ default:
+ assert(0);
+ }
+ pos = v[i];
+ }
+}
+
+void simple_output::spline(const position &start, const position *v, int n,
+ const line_type &lt)
+{
+ line_thickness(lt.thickness);
+ simple_spline(start, v, n);
+}
+
+void simple_output::polygon(const position *v, int n,
+ const line_type &lt, double fill)
+{
+ if (driver_extension_flag) {
+ if (fill >= 0.0) {
+ set_fill(fill);
+ simple_polygon(1, v, n);
+ }
+ }
+ if (lt.type == line_type::solid && driver_extension_flag) {
+ line_thickness(lt.thickness);
+ simple_polygon(0, v, n);
+ }
+ else if (lt.type != line_type::invisible) {
+ line_thickness(lt.thickness);
+ line(v[n - 1], v, n, lt);
+ }
+}
+
+void simple_output::circle(const position &cent, double rad,
+ const line_type &lt, double fill)
+{
+ if (driver_extension_flag && fill >= 0.0) {
+ set_fill(fill);
+ simple_circle(1, cent, rad);
+ }
+ line_thickness(lt.thickness);
+ switch (lt.type) {
+ case line_type::invisible:
+ break;
+ case line_type::dashed:
+ dashed_circle(cent, rad, lt);
+ break;
+ case line_type::dotted:
+ dotted_circle(cent, rad, lt);
+ break;
+ case line_type::solid:
+ simple_circle(0, cent, rad);
+ break;
+ default:
+ assert(0);
+ }
+}
+
+void simple_output::ellipse(const position &cent, const distance &dim,
+ const line_type &lt, double fill)
+{
+ if (driver_extension_flag && fill >= 0.0) {
+ set_fill(fill);
+ simple_ellipse(1, cent, dim);
+ }
+ if (lt.type != line_type::invisible)
+ line_thickness(lt.thickness);
+ switch (lt.type) {
+ case line_type::invisible:
+ break;
+ case line_type::dotted:
+ case line_type::dashed:
+ case line_type::solid:
+ simple_ellipse(0, cent, dim);
+ break;
+ default:
+ assert(0);
+ }
+}
+
+#define FILL_MAX 1000
+
+class troff_output : public simple_output {
+ const char *last_filename;
+ position upper_left;
+ double height;
+ double scale;
+ double last_line_thickness;
+ double last_fill;
+public:
+ troff_output();
+ ~troff_output();
+ void start_picture(double, const position &ll, const position &ur);
+ void finish_picture();
+ void text(const position &, text_piece *, int, double);
+ void dot(const position &, const line_type &);
+ void command(const char *, const char *, int);
+ void set_location(const char *, int);
+ void simple_line(const position &, const position &);
+ void simple_spline(const position &, const position *, int n);
+ void simple_arc(const position &, const position &, const position &);
+ void simple_circle(int, const position &, double rad);
+ void simple_ellipse(int, const position &, const distance &);
+ void simple_polygon(int, const position *, int);
+ void line_thickness(double p);
+ void set_fill(double);
+ position transform(const position &);
+};
+
+output *make_troff_output()
+{
+ return new troff_output;
+}
+
+troff_output::troff_output()
+: last_filename(0), last_line_thickness(BAD_THICKNESS), last_fill(-1.0)
+{
+}
+
+troff_output::~troff_output()
+{
+}
+
+inline position troff_output::transform(const position &pos)
+{
+ return position((pos.x - upper_left.x)/scale,
+ (upper_left.y - pos.y)/scale);
+}
+
+#define FILL_REG "00"
+
+// If this register > 0, then pic will generate \X'ps: ...' commands
+// if the aligned attribute is used.
+#define GROPS_REG "0p"
+
+// If this register is defined, geqn won't produce `\x's.
+#define EQN_NO_EXTRA_SPACE_REG "0x"
+
+void troff_output::start_picture(double sc,
+ const position &ll, const position &ur)
+{
+ upper_left.x = ll.x;
+ upper_left.y = ur.y;
+ scale = compute_scale(sc, ll, ur);
+ height = (ur.y - ll.y)/scale;
+ double width = (ur.x - ll.x)/scale;
+ printf(".PS %.3fi %.3fi", height, width);
+ if (args)
+ printf(" %s\n", args);
+ else
+ putchar('\n');
+ printf(".\\\" %g %g %g %g\n", ll.x, ll.y, ur.x, ur.y);
+ printf(".\\\" %.3fi %.3fi %.3fi %.3fi\n", 0.0, height, width, 0.0);
+ printf(".nr " FILL_REG " \\n(.u\n.nf\n");
+ printf(".nr " EQN_NO_EXTRA_SPACE_REG " 1\n");
+ // This guarantees that if the picture is used in a diversion it will
+ // have the right width.
+ printf("\\h'%.3fi'\n.sp -1\n", width);
+}
+
+void troff_output::finish_picture()
+{
+ line_thickness(BAD_THICKNESS);
+ last_fill = -1.0; // force it to be reset for each picture
+ if (!flyback_flag)
+ printf(".sp %.3fi+1\n", height);
+ printf(".if \\n(" FILL_REG " .fi\n");
+ printf(".br\n");
+ printf(".nr " EQN_NO_EXTRA_SPACE_REG " 0\n");
+ // this is a little gross
+ set_location(current_filename, current_lineno);
+ fputs(flyback_flag ? ".PF\n" : ".PE\n", stdout);
+}
+
+void troff_output::command(const char *s,
+ const char *filename, int lineno)
+{
+ if (filename != 0)
+ set_location(filename, lineno);
+ fputs(s, stdout);
+ putchar('\n');
+}
+
+void troff_output::simple_circle(int filled, const position &cent, double rad)
+{
+ position c = transform(cent);
+ printf("\\h'%.3fi'"
+ "\\v'%.3fi'"
+ "\\D'%c%.3fi'"
+ "\n.sp -1\n",
+ c.x - rad/scale,
+ c.y,
+ (filled ? 'C' : 'c'),
+ rad*2.0/scale);
+}
+
+void troff_output::simple_ellipse(int filled, const position &cent,
+ const distance &dim)
+{
+ position c = transform(cent);
+ printf("\\h'%.3fi'"
+ "\\v'%.3fi'"
+ "\\D'%c%.3fi %.3fi'"
+ "\n.sp -1\n",
+ c.x - dim.x/(2.0*scale),
+ c.y,
+ (filled ? 'E' : 'e'),
+ dim.x/scale, dim.y/scale);
+}
+
+void troff_output::simple_arc(const position &start, const distance &cent,
+ const distance &end)
+{
+ position s = transform(start);
+ position c = transform(cent);
+ distance cv = c - s;
+ distance ev = transform(end) - c;
+ printf("\\h'%.3fi'"
+ "\\v'%.3fi'"
+ "\\D'a%.3fi %.3fi %.3fi %.3fi'"
+ "\n.sp -1\n",
+ s.x, s.y, cv.x, cv.y, ev.x, ev.y);
+}
+
+void troff_output::simple_line(const position &start, const position &end)
+{
+ position s = transform(start);
+ distance ev = transform(end) - s;
+ printf("\\h'%.3fi'"
+ "\\v'%.3fi'"
+ "\\D'l%.3fi %.3fi'"
+ "\n.sp -1\n",
+ s.x, s.y, ev.x, ev.y);
+}
+
+void troff_output::simple_spline(const position &start,
+ const position *v, int n)
+{
+ position pos = transform(start);
+ printf("\\h'%.3fi'"
+ "\\v'%.3fi'",
+ pos.x, pos.y);
+ fputs("\\D'~", stdout);
+ for (int i = 0; i < n; i++) {
+ position temp = transform(v[i]);
+ distance d = temp - pos;
+ pos = temp;
+ if (i != 0)
+ putchar(' ');
+ printf("%.3fi %.3fi", d.x, d.y);
+ }
+ printf("'\n.sp -1\n");
+}
+
+// a solid polygon
+
+void troff_output::simple_polygon(int filled, const position *v, int n)
+{
+ position pos = transform(v[0]);
+ printf("\\h'%.3fi'"
+ "\\v'%.3fi'",
+ pos.x, pos.y);
+ printf("\\D'%c", (filled ? 'P' : 'p'));
+ for (int i = 1; i < n; i++) {
+ position temp = transform(v[i]);
+ distance d = temp - pos;
+ pos = temp;
+ if (i != 1)
+ putchar(' ');
+ printf("%.3fi %.3fi", d.x, d.y);
+ }
+ printf("'\n.sp -1\n");
+}
+
+const double TEXT_AXIS = 0.22; // in ems
+
+static const char *choose_delimiter(const char *text)
+{
+ if (strchr(text, '\'') == 0)
+ return "'";
+ else
+ return "\\(ts";
+}
+
+void troff_output::text(const position &center, text_piece *v, int n,
+ double ang)
+{
+ line_thickness(BAD_THICKNESS); // the text might use lines (eg in equations)
+ int rotate_flag = 0;
+ if (driver_extension_flag && ang != 0.0) {
+ rotate_flag = 1;
+ position c = transform(center);
+ printf(".if \\n(" GROPS_REG " \\{\\\n"
+ "\\h'%.3fi'"
+ "\\v'%.3fi'"
+ "\\X'ps: exec gsave currentpoint 2 copy translate %.4f rotate neg exch neg exch translate'"
+ "\n.sp -1\n"
+ ".\\}\n",
+ c.x, c.y, -ang*180.0/M_PI);
+ }
+ for (int i = 0; i < n; i++)
+ if (v[i].text != 0 && *v[i].text != '\0') {
+ position c = transform(center);
+ if (v[i].filename != 0)
+ set_location(v[i].filename, v[i].lineno);
+ printf("\\h'%.3fi", c.x);
+ const char *delim = choose_delimiter(v[i].text);
+ if (v[i].adj.h == RIGHT_ADJUST)
+ printf("-\\w%s%s%su", delim, v[i].text, delim);
+ else if (v[i].adj.h != LEFT_ADJUST)
+ printf("-(\\w%s%s%su/2u)", delim, v[i].text, delim);
+ putchar('\'');
+ printf("\\v'%.3fi-(%dv/2u)+%dv+%.2fm",
+ c.y,
+ n - 1,
+ i,
+ TEXT_AXIS);
+ if (v[i].adj.v == ABOVE_ADJUST)
+ printf("-.5v");
+ else if (v[i].adj.v == BELOW_ADJUST)
+ printf("+.5v");
+ putchar('\'');
+ fputs(v[i].text, stdout);
+ fputs("\n.sp -1\n", stdout);
+ }
+ if (rotate_flag)
+ printf(".if '\\*(.T'ps' \\{\\\n"
+ "\\X'ps: exec grestore'\n.sp -1\n"
+ ".\\}\n");
+}
+
+void troff_output::line_thickness(double p)
+{
+ if (p < 0.0)
+ p = RELATIVE_THICKNESS;
+ if (driver_extension_flag && p != last_line_thickness) {
+ printf("\\D't %.3fp'\\h'%.3fp'\n.sp -1\n", p, -p);
+ last_line_thickness = p;
+ }
+}
+
+void troff_output::set_fill(double f)
+{
+ if (driver_extension_flag && f != last_fill) {
+ printf("\\D'f %du'\\h'%du'\n.sp -1\n", int(f*FILL_MAX), -int(f*FILL_MAX));
+ last_fill = f;
+ }
+}
+
+const double DOT_AXIS = .044;
+
+void troff_output::dot(const position &cent, const line_type &lt)
+{
+ if (driver_extension_flag) {
+ line_thickness(lt.thickness);
+ simple_line(cent, cent);
+ }
+ else {
+ position c = transform(cent);
+ printf("\\h'%.3fi-(\\w'.'u/2u)'"
+ "\\v'%.3fi+%.2fm'"
+ ".\n.sp -1\n",
+ c.x,
+ c.y,
+ DOT_AXIS);
+ }
+}
+
+void troff_output::set_location(const char *s, int n)
+{
+ if (last_filename != 0 && strcmp(s, last_filename) == 0)
+ printf(".lf %d\n", n);
+ else {
+ printf(".lf %d %s\n", n, s);
+ last_filename = s;
+ }
+}
diff --git a/gnu/usr.bin/groff/psbb/Makefile b/gnu/usr.bin/groff/psbb/Makefile
new file mode 100644
index 0000000..1339f53
--- /dev/null
+++ b/gnu/usr.bin/groff/psbb/Makefile
@@ -0,0 +1,10 @@
+# Makefile for psbb
+
+PROG= psbb
+SRCS= psbb.c
+
+MANDEPEND= psbb.1
+CLEANFILES+= ${MANDEPEND}
+
+.include "../Makefile.cfg"
+.include <bsd.prog.mk>
diff --git a/gnu/usr.bin/groff/psbb/Makefile.dep b/gnu/usr.bin/groff/psbb/Makefile.dep
new file mode 100644
index 0000000..640782e
--- /dev/null
+++ b/gnu/usr.bin/groff/psbb/Makefile.dep
@@ -0,0 +1 @@
+psbb.o : psbb.c
diff --git a/gnu/usr.bin/groff/psbb/Makefile.sub b/gnu/usr.bin/groff/psbb/Makefile.sub
new file mode 100644
index 0000000..106721a
--- /dev/null
+++ b/gnu/usr.bin/groff/psbb/Makefile.sub
@@ -0,0 +1,5 @@
+PROG=psbb
+MAN1=psbb.n
+OBJS=psbb.o
+CSRCS=psbb.c
+XLIBS=
diff --git a/gnu/usr.bin/groff/psbb/psbb.c b/gnu/usr.bin/groff/psbb/psbb.c
new file mode 100644
index 0000000..8879cc8
--- /dev/null
+++ b/gnu/usr.bin/groff/psbb/psbb.c
@@ -0,0 +1,169 @@
+/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
+ Written by James Clark (jjc@jclark.com)
+
+This file is part of groff.
+
+groff is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
+
+groff is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License along
+with groff; see the file COPYING. If not, write to the Free Software
+Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#ifndef errno
+extern int errno;
+#endif
+
+struct bounding_box {
+ int llx, lly, urx, ury;
+};
+
+#ifdef __STDC__
+const char *do_file(FILE *, struct bounding_box *);
+int parse_bounding_box(char *, struct bounding_box *);
+#else
+#define const /* as nothing */
+const char *do_file();
+int parse_bounding_box();
+#endif
+
+int main(argc, argv)
+int argc;
+char **argv;
+{
+ FILE *fp;
+ const char *message;
+ struct bounding_box bb;
+ if (argc != 2) {
+ fprintf(stderr, "usage: %s filename\n", argv[0]);
+ exit(3);
+ }
+ errno = 0;
+ fp = fopen(argv[1], "r");
+ if (fp == NULL) {
+ fprintf(stderr, "%s: can't open `%s': ", argv[0], argv[1]);
+ perror((char *)NULL);
+ exit(2);
+ }
+ message = do_file(fp, &bb);
+ if (message) {
+ fprintf(stderr, "%s: ", argv[0]);
+ fprintf(stderr, message, argv[1]);
+ putc('\n', stderr);
+ exit(1);
+ }
+ printf("%d %d %d %d\n", bb.llx, bb.lly, bb.urx, bb.ury);
+ exit(0);
+}
+
+/* If the bounding box was found return NULL, and store the bounding box
+in bb. If the bounding box was not found return a string suitable for
+giving to printf with the filename as an argument saying why not. */
+
+const char *do_file(fp, bb)
+FILE *fp;
+struct bounding_box *bb;
+{
+ int bb_at_end = 0;
+ char buf[256];
+ if (!fgets(buf, sizeof(buf), fp))
+ return "%s is empty";
+ if (strncmp("%!PS-Adobe-", buf, 11) != 0)
+ return "%s is not conforming";
+ while (fgets(buf, sizeof(buf), fp) != 0) {
+ if (buf[0] != '%' || buf[1] != '%'
+ || strncmp(buf + 2, "EndComments", 11) == 0)
+ break;
+ if (strncmp(buf + 2, "BoundingBox:", 12) == 0) {
+ int res = parse_bounding_box(buf + 14, bb);
+ if (res == 1)
+ return NULL;
+ else if (res == 2) {
+ bb_at_end = 1;
+ break;
+ }
+ else
+ return "the arguments to the %%%%BoundingBox comment in %s are bad";
+ }
+ }
+ if (bb_at_end) {
+ long offset;
+ int last_try = 0;
+ /* in the trailer, the last BoundingBox comment is significant */
+ for (offset = 512; !last_try; offset *= 2) {
+ int had_trailer = 0;
+ int got_bb = 0;
+ if (offset > 32768 || fseek(fp, -offset, 2) == -1) {
+ last_try = 1;
+ if (fseek(fp, 0L, 0) == -1)
+ break;
+ }
+ while (fgets(buf, sizeof(buf), fp) != 0) {
+ if (buf[0] == '%' && buf[1] == '%') {
+ if (!had_trailer) {
+ if (strncmp(buf + 2, "Trailer", 7) == 0)
+ had_trailer = 1;
+ }
+ else {
+ if (strncmp(buf + 2, "BoundingBox:", 12) == 0) {
+ int res = parse_bounding_box(buf + 14, bb);
+ if (res == 1)
+ got_bb = 1;
+ else if (res == 2)
+ return "`(atend)' not allowed in trailer";
+ else
+ return "the arguments to the %%%%BoundingBox comment in %s are bad";
+ }
+ }
+ }
+ }
+ if (got_bb)
+ return NULL;
+ }
+ }
+ return "%%%%BoundingBox comment not found in %s";
+}
+
+/* Parse the argument to a %%BoundingBox comment. Return 1 if it
+contains 4 numbers, 2 if it contains (atend), 0 otherwise. */
+
+int parse_bounding_box(p, bb)
+char *p;
+struct bounding_box *bb;
+{
+ if (sscanf(p, "%d %d %d %d",
+ &bb->llx, &bb->lly, &bb->urx, &bb->ury) == 4)
+ return 1;
+ else {
+ /* The Document Structuring Conventions say that the numbers
+ should be integers. Unfortunately some broken applications
+ get this wrong. */
+ double x1, x2, x3, x4;
+ if (sscanf(p, "%lf %lf %lf %lf", &x1, &x2, &x3, &x4) == 4) {
+ bb->llx = (int)x1;
+ bb->lly = (int)x2;
+ bb->urx = (int)x3;
+ bb->ury = (int)x4;
+ return 1;
+ }
+ else {
+ for (; *p == ' ' || *p == '\t'; p++)
+ ;
+ if (strncmp(p, "(atend)", 7) == 0) {
+ return 2;
+ }
+ }
+ }
+ return 0;
+}
+
diff --git a/gnu/usr.bin/groff/psbb/psbb.man b/gnu/usr.bin/groff/psbb/psbb.man
new file mode 100644
index 0000000..bc38381
--- /dev/null
+++ b/gnu/usr.bin/groff/psbb/psbb.man
@@ -0,0 +1,26 @@
+.\" -*- nroff -*-
+.TH PSBB @MAN1EXT@ "@MDATE@" "Groff Version @VERSION@"
+.SH NAME
+psbb \- extract bounding box from PostScript document
+.SH SYNOPSIS
+.B psbb
+.I file
+.SH DESCRIPTION
+psbb reads
+.I file
+which should be a PostScript document conforming to
+the Document Structuring conventions
+and looks for a
+.B %%BoundingBox
+comment.
+If it finds one,
+it prints a line
+.IP
+.I
+llx lly urx ury
+.LP
+on the standard output and exits with zero status.
+If it doesn't find such a line or if the line is invalid
+it prints a message and exits with non-zero status.
+.SH "SEE ALSO"
+.BR grops (@MAN1EXT@)
diff --git a/gnu/usr.bin/groff/refer/Makefile b/gnu/usr.bin/groff/refer/Makefile
new file mode 100644
index 0000000..ac8d5f0
--- /dev/null
+++ b/gnu/usr.bin/groff/refer/Makefile
@@ -0,0 +1,14 @@
+# Makefile for refer
+
+PROG= refer
+SRCS= command.cc ref.cc refer.cc token.cc
+OBJS= label.o
+CFLAGS+= -I. -I${.CURDIR}/../include
+LDADD+= ${LIBBIB} ${LIBGROFF} -lm
+DPADD+= ${LIBBIB} ${LIBGROFF} ${LIBM}
+
+MANDEPEND= refer.1
+CLEANFILES+= label.cc label.tab.h ${MANDEPEND}
+
+.include "../Makefile.cfg"
+.include <bsd.prog.mk>
diff --git a/gnu/usr.bin/groff/refer/Makefile.dep b/gnu/usr.bin/groff/refer/Makefile.dep
new file mode 100644
index 0000000..6a6c987
--- /dev/null
+++ b/gnu/usr.bin/groff/refer/Makefile.dep
@@ -0,0 +1,17 @@
+command.o : command.cc refer.h ../include/errarg.h ../include/error.h \
+ ../include/lib.h ../include/stringclass.h ../include/cset.h \
+ ../include/cmap.h ../include/defs.h ../include/refid.h \
+ ../include/search.h command.h
+ref.o : ref.cc refer.h ../include/errarg.h ../include/error.h \
+ ../include/lib.h ../include/stringclass.h ../include/cset.h \
+ ../include/cmap.h ../include/defs.h ../include/refid.h ref.h token.h
+refer.o : refer.cc refer.h ../include/errarg.h ../include/error.h \
+ ../include/lib.h ../include/stringclass.h ../include/cset.h \
+ ../include/cmap.h ../include/defs.h ../include/refid.h ref.h token.h \
+ ../include/search.h command.h
+token.o : token.cc refer.h ../include/errarg.h ../include/error.h \
+ ../include/lib.h ../include/stringclass.h ../include/cset.h \
+ ../include/cmap.h ../include/defs.h token.h
+label.o : label.cc refer.h ../include/errarg.h ../include/error.h \
+ ../include/lib.h ../include/stringclass.h ../include/cset.h \
+ ../include/cmap.h ../include/defs.h ../include/refid.h ref.h token.h
diff --git a/gnu/usr.bin/groff/refer/Makefile.sub b/gnu/usr.bin/groff/refer/Makefile.sub
new file mode 100644
index 0000000..2873462
--- /dev/null
+++ b/gnu/usr.bin/groff/refer/Makefile.sub
@@ -0,0 +1,10 @@
+PROG=refer
+MAN1=refer.n
+XLIBS=$(LIBBIB) $(LIBGROFF)
+MLIB=$(LIBM)
+OBJS=command.o label.o ref.o refer.o token.o
+CCSRCS=command.cc ref.cc refer.cc token.cc
+HDRS=refer.h token.h command.h ref.h
+GRAM=label.y
+YTABC=label.cc
+NAMEPREFIX=$(g)
diff --git a/gnu/usr.bin/groff/refer/TODO b/gnu/usr.bin/groff/refer/TODO
new file mode 100644
index 0000000..5bbd9bf
--- /dev/null
+++ b/gnu/usr.bin/groff/refer/TODO
@@ -0,0 +1,124 @@
+inline references
+
+Some sort of macro/subroutine that can cover several references.
+
+move-punctuation should ignore multiple punctuation characters.
+
+Make the index files machine independent.
+
+Allow search keys to be negated (with !) to indicate that the
+reference should not contain the key. Ignore negated keys during
+indexed searching.
+
+Provide an option with lkbib and lookbib that prints the location
+(filename, position) of each reference. Need to map filename_id's
+back to filenames.
+
+Rename join-authors to join-fields. Have a separate label-join-fields
+command used by @ and #.
+
+Have some sort of quantifier: eg $.n#A means execute `$.n' for each
+instance of an A field, setting $ to that field, and then join the
+results using the join-authors command.
+
+no-text-in-bracket command which says not to allow post_text and
+pre_text when the [] flags has been given. Useful for superscripted
+footnotes.
+
+Make it possible to translate - to \(en in page ranges.
+
+Trim eign a bit.
+
+In indexed searching discard all numeric keys except dates.
+
+Allow `\ ' to separate article from first word.
+
+%also
+
+Option automatically to supply [] flags in every reference.
+
+See if we can avoid requiring a comma before jr. and so on
+in find_last_name().
+
+Cache sortified authors in authors string during tentative evaluation of
+label specification.
+
+Possibly don't allow * and % expressions in the first part of ?:, | or
+& expressions.
+
+Handle better the case where <> occurs inside functions and in the
+first operand of ~. Or perhaps implement <> using some magic character
+in the string.
+
+Should special treatment be given to lines beginning with . in
+references? (Unix refer seems to treat them like `%').
+
+Add global flag to control whether all files should be stat-ed after
+loading, and whether they should be stat-ed before each search.
+Perhaps make this dependent on the number of files there are.
+
+Option to truncate keys to truncate_len in linear searching.
+
+Allow multiple -f options in indxbib.
+
+In indxbib, possibly store common words rather than common words
+filename. In this case store only words that are actually present in
+the file.
+
+Perhaps we should put out an obnoxious copyright message when lookbib
+starts up.
+
+Provide an option that writes a file containing just the references
+actually used. Useful if you want to distribute a document.
+
+Have a magic token such that
+%A <sort stuff><magic token><print stuff>
+will print as though it were
+%A <print stuff>
+but sort as though it were
+%A <sort stuff>
+Do we need this if we can specify author alternatives for sorting?
+No, provided we have separate alternatives for @.
+
+In consider_authors when last names are ambiguous we might be able to
+use just the first name and not Jr. bit. Or we might be able to
+abbreviate the author.
+
+It ought to be possible to specify an alternative field to sort on
+instead of date. (ie if there's a field giving the type of document --
+these references should sort after any years)
+
+Provide a way to execute a command using a command-line option.
+
+Option to set the label-spec as a command-line option (-L).
+
+Command to to specify which fields can occur multiple times:
+multiple AE
+
+Command to specify how various fields sort:
+aort-as-name A
+sort-as-date D
+sort-as-title T
+sort-as-other O
+
+Command to specify which fields are author fields:
+# if we don't have A use field Q
+author-fields AQ
+
+Commands to set properties of tokens.
+sortify-token \(ae ae
+uppercase-token \[ae] \[AE]
+
+Command to set the names of months:
+months january february march april may ...
+
+Perhaps provide some sort of macro capability:
+# perhaps a macro capability
+defmacro foo
+annotation-field $1
+endef
+
+Command to control strings used in capitalization
+capitalize-start \s+2
+capitalize-end \s-2
+(perhaps make these arguments to the capitalize command.)
diff --git a/gnu/usr.bin/groff/refer/command.cc b/gnu/usr.bin/groff/refer/command.cc
new file mode 100644
index 0000000..ee60627
--- /dev/null
+++ b/gnu/usr.bin/groff/refer/command.cc
@@ -0,0 +1,807 @@
+// -*- C++ -*-
+/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
+ Written by James Clark (jjc@jclark.com)
+
+This file is part of groff.
+
+groff is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
+
+groff is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License along
+with groff; see the file COPYING. If not, write to the Free Software
+Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "refer.h"
+#include "refid.h"
+#include "search.h"
+#include "command.h"
+
+cset cs_field_name = csalpha;
+
+class input_item {
+ input_item *next;
+ char *filename;
+ int first_lineno;
+ string buffer;
+ const char *ptr;
+ const char *end;
+public:
+ input_item(string &, const char *, int = 1);
+ ~input_item();
+ int get_char();
+ int peek_char();
+ void skip_char();
+ int get_location(const char **, int *);
+
+ friend class input_stack;
+};
+
+input_item::input_item(string &s, const char *fn, int ln)
+: filename(strsave(fn)), first_lineno(ln)
+{
+ buffer.move(s);
+ ptr = buffer.contents();
+ end = ptr + buffer.length();
+}
+
+input_item::~input_item()
+{
+ a_delete filename;
+}
+
+inline int input_item::peek_char()
+{
+ if (ptr >= end)
+ return EOF;
+ else
+ return (unsigned char)*ptr;
+}
+
+inline int input_item::get_char()
+{
+ if (ptr >= end)
+ return EOF;
+ else
+ return (unsigned char)*ptr++;
+}
+
+inline void input_item::skip_char()
+{
+ ptr++;
+}
+
+int input_item::get_location(const char **filenamep, int *linenop)
+{
+ *filenamep = filename;
+ if (ptr == buffer.contents())
+ *linenop = first_lineno;
+ else {
+ int ln = first_lineno;
+ const char *e = ptr - 1;
+ for (const char *p = buffer.contents(); p < e; p++)
+ if (*p == '\n')
+ ln++;
+ *linenop = ln;
+ }
+ return 1;
+}
+
+class input_stack {
+ static input_item *top;
+public:
+ static void init();
+ static int get_char();
+ static int peek_char();
+ static void skip_char() { top->skip_char(); }
+ static void push_file(const char *);
+ static void push_string(string &, const char *, int);
+ static void error(const char *format,
+ const errarg &arg1 = empty_errarg,
+ const errarg &arg2 = empty_errarg,
+ const errarg &arg3 = empty_errarg);
+};
+
+input_item *input_stack::top = 0;
+
+void input_stack::init()
+{
+ while (top) {
+ input_item *tem = top;
+ top = top->next;
+ delete tem;
+ }
+}
+
+int input_stack::get_char()
+{
+ while (top) {
+ int c = top->get_char();
+ if (c >= 0)
+ return c;
+ input_item *tem = top;
+ top = top->next;
+ delete tem;
+ }
+ return -1;
+}
+
+int input_stack::peek_char()
+{
+ while (top) {
+ int c = top->peek_char();
+ if (c >= 0)
+ return c;
+ input_item *tem = top;
+ top = top->next;
+ delete tem;
+ }
+ return -1;
+}
+
+void input_stack::push_file(const char *fn)
+{
+ FILE *fp;
+ if (strcmp(fn, "-") == 0) {
+ fp = stdin;
+ fn = "<standard input>";
+ }
+ else {
+ errno = 0;
+ fp = fopen(fn, "r");
+ if (fp == 0) {
+ error("can't open `%1': %2", fn, strerror(errno));
+ return;
+ }
+ }
+ string buf;
+ int bol = 1;
+ int lineno = 1;
+ for (;;) {
+ int c = getc(fp);
+ if (bol && c == '.') {
+ // replace lines beginning with .R1 or .R2 with a blank line
+ c = getc(fp);
+ if (c == 'R') {
+ c = getc(fp);
+ if (c == '1' || c == '2') {
+ int cc = c;
+ c = getc(fp);
+ if (compatible_flag || c == ' ' || c == '\n' || c == EOF) {
+ while (c != '\n' && c != EOF)
+ c = getc(fp);
+ }
+ else {
+ buf += '.';
+ buf += 'R';
+ buf += cc;
+ }
+ }
+ else {
+ buf += '.';
+ buf += 'R';
+ }
+ }
+ else
+ buf += '.';
+ }
+ if (c == EOF)
+ break;
+ if (illegal_input_char(c))
+ error_with_file_and_line(fn, lineno,
+ "illegal input character code %1", int(c));
+ else {
+ buf += c;
+ if (c == '\n') {
+ bol = 1;
+ lineno++;
+ }
+ else
+ bol = 0;
+ }
+ }
+ if (fp != stdin)
+ fclose(fp);
+ if (buf.length() > 0 && buf[buf.length() - 1] != '\n')
+ buf += '\n';
+ input_item *it = new input_item(buf, fn);
+ it->next = top;
+ top = it;
+}
+
+void input_stack::push_string(string &s, const char *filename, int lineno)
+{
+ input_item *it = new input_item(s, filename, lineno);
+ it->next = top;
+ top = it;
+}
+
+void input_stack::error(const char *format, const errarg &arg1,
+ const errarg &arg2, const errarg &arg3)
+{
+ const char *filename;
+ int lineno;
+ for (input_item *it = top; it; it = it->next)
+ if (it->get_location(&filename, &lineno)) {
+ error_with_file_and_line(filename, lineno, format, arg1, arg2, arg3);
+ return;
+ }
+ ::error(format, arg1, arg2, arg3);
+}
+
+void command_error(const char *format, const errarg &arg1,
+ const errarg &arg2, const errarg &arg3)
+{
+ input_stack::error(format, arg1, arg2, arg3);
+}
+
+// # not recognized in ""
+// \<newline> is recognized in ""
+// # does not conceal newline
+// if missing closing quote, word extends to end of line
+// no special treatment of \ other than before newline
+// \<newline> not recognized after #
+// ; allowed as alternative to newline
+// ; not recognized in ""
+// don't clear word_buffer; just append on
+// return -1 for EOF, 0 for newline, 1 for word
+
+int get_word(string &word_buffer)
+{
+ int c = input_stack::get_char();
+ for (;;) {
+ if (c == '#') {
+ do {
+ c = input_stack::get_char();
+ } while (c != '\n' && c != EOF);
+ break;
+ }
+ if (c == '\\' && input_stack::peek_char() == '\n')
+ input_stack::skip_char();
+ else if (c != ' ' && c != '\t')
+ break;
+ c = input_stack::get_char();
+ }
+ if (c == EOF)
+ return -1;
+ if (c == '\n' || c == ';')
+ return 0;
+ if (c == '"') {
+ for (;;) {
+ c = input_stack::peek_char();
+ if (c == EOF || c == '\n')
+ break;
+ input_stack::skip_char();
+ if (c == '"') {
+ int d = input_stack::peek_char();
+ if (d == '"')
+ input_stack::skip_char();
+ else
+ break;
+ }
+ else if (c == '\\') {
+ int d = input_stack::peek_char();
+ if (d == '\n')
+ input_stack::skip_char();
+ else
+ word_buffer += '\\';
+ }
+ else
+ word_buffer += c;
+ }
+ return 1;
+ }
+ word_buffer += c;
+ for (;;) {
+ c = input_stack::peek_char();
+ if (c == ' ' || c == '\t' || c == '\n' || c == '#' || c == ';')
+ break;
+ input_stack::skip_char();
+ if (c == '\\') {
+ int d = input_stack::peek_char();
+ if (d == '\n')
+ input_stack::skip_char();
+ else
+ word_buffer += '\\';
+ }
+ else
+ word_buffer += c;
+ }
+ return 1;
+}
+
+union argument {
+ const char *s;
+ int n;
+};
+
+// This is for debugging.
+
+static void echo_command(int argc, argument *argv)
+{
+ for (int i = 0; i < argc; i++)
+ fprintf(stderr, "%s\n", argv[i].s);
+}
+
+static void include_command(int argc, argument *argv)
+{
+ assert(argc == 1);
+ input_stack::push_file(argv[0].s);
+}
+
+static void capitalize_command(int argc, argument *argv)
+{
+ if (argc > 0)
+ capitalize_fields = argv[0].s;
+ else
+ capitalize_fields.clear();
+}
+
+static void accumulate_command(int, argument *)
+{
+ accumulate = 1;
+}
+
+static void no_accumulate_command(int, argument *)
+{
+ accumulate = 0;
+}
+
+static void move_punctuation_command(int, argument *)
+{
+ move_punctuation = 1;
+}
+
+static void no_move_punctuation_command(int, argument *)
+{
+ move_punctuation = 0;
+}
+
+static void sort_command(int argc, argument *argv)
+{
+ if (argc == 0)
+ sort_fields = "AD";
+ else
+ sort_fields = argv[0].s;
+ accumulate = 1;
+}
+
+static void no_sort_command(int, argument *)
+{
+ sort_fields.clear();
+}
+
+static void articles_command(int argc, argument *argv)
+{
+ articles.clear();
+ int i;
+ for (i = 0; i < argc; i++) {
+ articles += argv[i].s;
+ articles += '\0';
+ }
+ int len = articles.length();
+ for (i = 0; i < len; i++)
+ articles[i] = cmlower(articles[i]);
+}
+
+static void database_command(int argc, argument *argv)
+{
+ for (int i = 0; i < argc; i++)
+ database_list.add_file(argv[i].s);
+}
+
+static void default_database_command(int, argument *)
+{
+ search_default = 1;
+}
+
+static void no_default_database_command(int, argument *)
+{
+ search_default = 0;
+}
+
+static void bibliography_command(int argc, argument *argv)
+{
+ const char *saved_filename = current_filename;
+ int saved_lineno = current_lineno;
+ int saved_label_in_text = label_in_text;
+ label_in_text = 0;
+ if (!accumulate)
+ fputs(".]<\n", stdout);
+ for (int i = 0; i < argc; i++)
+ do_bib(argv[i].s);
+ if (accumulate)
+ output_references();
+ else
+ fputs(".]>\n", stdout);
+ current_filename = saved_filename;
+ current_lineno = saved_lineno;
+ label_in_text = saved_label_in_text;
+}
+
+static void annotate_command(int argc, argument *argv)
+{
+ if (argc > 0)
+ annotation_field = argv[0].s[0];
+ else
+ annotation_field = 'X';
+ if (argc == 2)
+ annotation_macro = argv[1].s;
+ else
+ annotation_macro = "AP";
+}
+
+static void no_annotate_command(int, argument *)
+{
+ annotation_macro.clear();
+ annotation_field = -1;
+}
+
+static void reverse_command(int, argument *argv)
+{
+ reverse_fields = argv[0].s;
+}
+
+static void no_reverse_command(int, argument *)
+{
+ reverse_fields.clear();
+}
+
+static void abbreviate_command(int argc, argument *argv)
+{
+ abbreviate_fields = argv[0].s;
+ period_before_initial = argc > 1 ? argv[1].s : ". ";
+ period_before_last_name = argc > 2 ? argv[2].s : ". ";
+ period_before_other = argc > 3 ? argv[3].s : ". ";
+ period_before_hyphen = argc > 4 ? argv[4].s : ".";
+}
+
+static void no_abbreviate_command(int, argument *)
+{
+ abbreviate_fields.clear();
+}
+
+string search_ignore_fields;
+
+static void search_ignore_command(int argc, argument *argv)
+{
+ if (argc > 0)
+ search_ignore_fields = argv[0].s;
+ else
+ search_ignore_fields = "XYZ";
+ search_ignore_fields += '\0';
+ linear_ignore_fields = search_ignore_fields.contents();
+}
+
+static void no_search_ignore_command(int, argument *)
+{
+ linear_ignore_fields = "";
+}
+
+static void search_truncate_command(int argc, argument *argv)
+{
+ if (argc > 0)
+ linear_truncate_len = argv[0].n;
+ else
+ linear_truncate_len = 6;
+}
+
+static void no_search_truncate_command(int, argument *)
+{
+ linear_truncate_len = -1;
+}
+
+static void discard_command(int argc, argument *argv)
+{
+ if (argc == 0)
+ discard_fields = "XYZ";
+ else
+ discard_fields = argv[0].s;
+ accumulate = 1;
+}
+
+static void no_discard_command(int, argument *)
+{
+ discard_fields.clear();
+}
+
+static void label_command(int, argument *argv)
+{
+ set_label_spec(argv[0].s);
+}
+
+static void abbreviate_label_ranges_command(int argc, argument *argv)
+{
+ abbreviate_label_ranges = 1;
+ label_range_indicator = argc > 0 ? argv[0].s : "-";
+}
+
+static void no_abbreviate_label_ranges_command(int, argument *)
+{
+ abbreviate_label_ranges = 0;
+}
+
+static void label_in_reference_command(int, argument *)
+{
+ label_in_reference = 1;
+}
+
+static void no_label_in_reference_command(int, argument *)
+{
+ label_in_reference = 0;
+}
+
+static void label_in_text_command(int, argument *)
+{
+ label_in_text = 1;
+}
+
+static void no_label_in_text_command(int, argument *)
+{
+ label_in_text = 0;
+}
+
+static void sort_adjacent_labels_command(int, argument *)
+{
+ sort_adjacent_labels = 1;
+}
+
+static void no_sort_adjacent_labels_command(int, argument *)
+{
+ sort_adjacent_labels = 0;
+}
+
+static void date_as_label_command(int argc, argument *argv)
+{
+ if (set_date_label_spec(argc > 0 ? argv[0].s : "D%a*"))
+ date_as_label = 1;
+}
+
+static void no_date_as_label_command(int, argument *)
+{
+ date_as_label = 0;
+}
+
+static void short_label_command(int, argument *argv)
+{
+ if (set_short_label_spec(argv[0].s))
+ short_label_flag = 1;
+}
+
+static void no_short_label_command(int, argument *)
+{
+ short_label_flag = 0;
+}
+
+static void compatible_command(int, argument *)
+{
+ compatible_flag = 1;
+}
+
+static void no_compatible_command(int, argument *)
+{
+ compatible_flag = 0;
+}
+
+static void join_authors_command(int argc, argument *argv)
+{
+ join_authors_exactly_two = argv[0].s;
+ join_authors_default = argc > 1 ? argv[1].s : argv[0].s;
+ join_authors_last_two = argc == 3 ? argv[2].s : argv[0].s;
+}
+
+static void bracket_label_command(int, argument *argv)
+{
+ pre_label = argv[0].s;
+ post_label = argv[1].s;
+ sep_label = argv[2].s;
+}
+
+static void separate_label_second_parts_command(int, argument *argv)
+{
+ separate_label_second_parts = argv[0].s;
+}
+
+static void et_al_command(int argc, argument *argv)
+{
+ et_al = argv[0].s;
+ et_al_min_elide = argv[1].n;
+ if (et_al_min_elide < 1)
+ et_al_min_elide = 1;
+ et_al_min_total = argc >= 3 ? argv[2].n : 0;
+}
+
+static void no_et_al_command(int, argument *)
+{
+ et_al.clear();
+ et_al_min_elide = 0;
+}
+
+typedef void (*command_t)(int, argument *);
+
+/* arg_types is a string describing the numbers and types of arguments.
+s means a string, i means an integer, f is a list of fields, F is
+a single field,
+? means that the previous argument is optional, * means that the
+previous argument can occur any number of times. */
+
+struct {
+ const char *name;
+ command_t func;
+ const char *arg_types;
+} command_table[] = {
+ { "include", include_command, "s" },
+ { "echo", echo_command, "s*" },
+ { "capitalize", capitalize_command, "f?" },
+ { "accumulate", accumulate_command, "" },
+ { "no-accumulate", no_accumulate_command, "" },
+ { "move-punctuation", move_punctuation_command, "" },
+ { "no-move-punctuation", no_move_punctuation_command, "" },
+ { "sort", sort_command, "s?" },
+ { "no-sort", no_sort_command, "" },
+ { "articles", articles_command, "s*" },
+ { "database", database_command, "ss*" },
+ { "default-database", default_database_command, "" },
+ { "no-default-database", no_default_database_command, "" },
+ { "bibliography", bibliography_command, "ss*" },
+ { "annotate", annotate_command, "F?s?" },
+ { "no-annotate", no_annotate_command, "" },
+ { "reverse", reverse_command, "s" },
+ { "no-reverse", no_reverse_command, "" },
+ { "abbreviate", abbreviate_command, "ss?s?s?s?" },
+ { "no-abbreviate", no_abbreviate_command, "" },
+ { "search-ignore", search_ignore_command, "f?" },
+ { "no-search-ignore", no_search_ignore_command, "" },
+ { "search-truncate", search_truncate_command, "i?" },
+ { "no-search-truncate", no_search_truncate_command, "" },
+ { "discard", discard_command, "f?" },
+ { "no-discard", no_discard_command, "" },
+ { "label", label_command, "s" },
+ { "abbreviate-label-ranges", abbreviate_label_ranges_command, "s?" },
+ { "no-abbreviate-label-ranges", no_abbreviate_label_ranges_command, "" },
+ { "label-in-reference", label_in_reference_command, "" },
+ { "no-label-in-reference", no_label_in_reference_command, "" },
+ { "label-in-text", label_in_text_command, "" },
+ { "no-label-in-text", no_label_in_text_command, "" },
+ { "sort-adjacent-labels", sort_adjacent_labels_command, "" },
+ { "no-sort-adjacent-labels", no_sort_adjacent_labels_command, "" },
+ { "date-as-label", date_as_label_command, "s?" },
+ { "no-date-as-label", no_date_as_label_command, "" },
+ { "short-label", short_label_command, "s" },
+ { "no-short-label", no_short_label_command, "" },
+ { "compatible", compatible_command, "" },
+ { "no-compatible", no_compatible_command, "" },
+ { "join-authors", join_authors_command, "sss?" },
+ { "bracket-label", bracket_label_command, "sss" },
+ { "separate-label-second-parts", separate_label_second_parts_command, "s" },
+ { "et-al", et_al_command, "sii?" },
+ { "no-et-al", no_et_al_command, "" },
+};
+
+static int check_args(const char *types, const char *name,
+ int argc, argument *argv)
+{
+ int argno = 0;
+ while (*types) {
+ if (argc == 0) {
+ if (types[1] == '?')
+ break;
+ else if (types[1] == '*') {
+ assert(types[2] == '\0');
+ break;
+ }
+ else {
+ input_stack::error("missing argument for command `%1'", name);
+ return 0;
+ }
+ }
+ switch (*types) {
+ case 's':
+ break;
+ case 'i':
+ {
+ char *ptr;
+ long n = strtol(argv->s, &ptr, 10);
+ if ((n == 0 && ptr == argv->s)
+ || *ptr != '\0') {
+ input_stack::error("argument %1 for command `%2' must be an integer",
+ argno + 1, name);
+ return 0;
+ }
+ argv->n = (int)n;
+ break;
+ }
+ case 'f':
+ {
+ for (const char *ptr = argv->s; *ptr != '\0'; ptr++)
+ if (!cs_field_name(*ptr)) {
+ input_stack::error("argument %1 for command `%2' must be a list of fields",
+ argno + 1, name);
+ return 0;
+ }
+ break;
+ }
+ case 'F':
+ if (argv->s[0] == '\0' || argv->s[1] != '\0'
+ || !cs_field_name(argv->s[0])) {
+ input_stack::error("argument %1 for command `%2' must be a field name",
+ argno + 1, name);
+ return 0;
+ }
+ break;
+ default:
+ assert(0);
+ }
+ if (types[1] == '?')
+ types += 2;
+ else if (types[1] != '*')
+ types += 1;
+ --argc;
+ ++argv;
+ ++argno;
+ }
+ if (argc > 0) {
+ input_stack::error("too many arguments for command `%1'", name);
+ return 0;
+ }
+ return 1;
+}
+
+static void execute_command(const char *name, int argc, argument *argv)
+{
+ for (int i = 0; i < sizeof(command_table)/sizeof(command_table[0]); i++)
+ if (strcmp(name, command_table[i].name) == 0) {
+ if (check_args(command_table[i].arg_types, name, argc, argv))
+ (*command_table[i].func)(argc, argv);
+ return;
+ }
+ input_stack::error("unknown command `%1'", name);
+}
+
+static void command_loop()
+{
+ string command;
+ for (;;) {
+ command.clear();
+ int res = get_word(command);
+ if (res != 1) {
+ if (res == 0)
+ continue;
+ break;
+ }
+ int argc = 0;
+ command += '\0';
+ while ((res = get_word(command)) == 1) {
+ argc++;
+ command += '\0';
+ }
+ argument *argv = new argument[argc];
+ const char *ptr = command.contents();
+ for (int i = 0; i < argc; i++)
+ argv[i].s = ptr = strchr(ptr, '\0') + 1;
+ execute_command(command.contents(), argc, argv);
+ a_delete argv;
+ if (res == -1)
+ break;
+ }
+}
+
+void process_commands(const char *file)
+{
+ input_stack::init();
+ input_stack::push_file(file);
+ command_loop();
+}
+
+void process_commands(string &s, const char *file, int lineno)
+{
+ input_stack::init();
+ input_stack::push_string(s, file, lineno);
+ command_loop();
+}
diff --git a/gnu/usr.bin/groff/refer/command.h b/gnu/usr.bin/groff/refer/command.h
new file mode 100644
index 0000000..2b977ea
--- /dev/null
+++ b/gnu/usr.bin/groff/refer/command.h
@@ -0,0 +1,36 @@
+// -*- C++ -*-
+/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
+ Written by James Clark (jjc@jclark.com)
+
+This file is part of groff.
+
+groff is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
+
+groff is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License along
+with groff; see the file COPYING. If not, write to the Free Software
+Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+void process_commands(const char *file);
+void process_commands(string &s, const char *file, int lineno);
+
+extern int accumulate;
+extern int move_punctuation;
+extern int search_default;
+extern search_list database_list;
+extern int label_in_text;
+extern int label_in_reference;
+extern int sort_adjacent_labels;
+extern string pre_label;
+extern string post_label;
+extern string sep_label;
+
+extern void do_bib(const char *);
+extern void output_references();
diff --git a/gnu/usr.bin/groff/refer/label.y b/gnu/usr.bin/groff/refer/label.y
new file mode 100644
index 0000000..d4b7fd3
--- /dev/null
+++ b/gnu/usr.bin/groff/refer/label.y
@@ -0,0 +1,1173 @@
+/* -*- C++ -*-
+ Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
+ Written by James Clark (jjc@jclark.com)
+
+This file is part of groff.
+
+groff is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
+
+groff is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License along
+with groff; see the file COPYING. If not, write to the Free Software
+Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+%{
+
+#include "refer.h"
+#include "refid.h"
+#include "ref.h"
+#include "token.h"
+
+int yylex();
+void yyerror(const char *);
+int yyparse();
+
+static const char *format_serial(char c, int n);
+
+struct label_info {
+ int start;
+ int length;
+ int count;
+ int total;
+ label_info(const string &);
+};
+
+label_info *lookup_label(const string &label);
+
+struct expression {
+ enum {
+ // Does the tentative label depend on the reference?
+ CONTAINS_VARIABLE = 01,
+ CONTAINS_STAR = 02,
+ CONTAINS_FORMAT = 04,
+ CONTAINS_AT = 010
+ };
+ virtual ~expression() { }
+ virtual void evaluate(int, const reference &, string &,
+ substring_position &) = 0;
+ virtual unsigned analyze() { return 0; }
+};
+
+class at_expr : public expression {
+public:
+ at_expr() { }
+ void evaluate(int, const reference &, string &, substring_position &);
+ unsigned analyze() { return CONTAINS_VARIABLE|CONTAINS_AT; }
+};
+
+class format_expr : public expression {
+ char type;
+ int width;
+ int first_number;
+public:
+ format_expr(char c, int w = 0, int f = 1)
+ : type(c), width(w), first_number(f) { }
+ void evaluate(int, const reference &, string &, substring_position &);
+ unsigned analyze() { return CONTAINS_FORMAT; }
+};
+
+class field_expr : public expression {
+ int number;
+ char name;
+public:
+ field_expr(char nm, int num) : name(nm), number(num) { }
+ void evaluate(int, const reference &, string &, substring_position &);
+ unsigned analyze() { return CONTAINS_VARIABLE; }
+};
+
+class literal_expr : public expression {
+ string s;
+public:
+ literal_expr(const char *ptr, int len) : s(ptr, len) { }
+ void evaluate(int, const reference &, string &, substring_position &);
+};
+
+class unary_expr : public expression {
+protected:
+ expression *expr;
+public:
+ unary_expr(expression *e) : expr(e) { }
+ ~unary_expr() { delete expr; }
+ void evaluate(int, const reference &, string &, substring_position &) = 0;
+ unsigned analyze() { return expr ? expr->analyze() : 0; }
+};
+
+// This caches the analysis of an expression.
+
+class analyzed_expr : public unary_expr {
+ unsigned flags;
+public:
+ analyzed_expr(expression *);
+ void evaluate(int, const reference &, string &, substring_position &);
+ unsigned analyze() { return flags; }
+};
+
+class star_expr : public unary_expr {
+public:
+ star_expr(expression *e) : unary_expr(e) { }
+ void evaluate(int, const reference &, string &, substring_position &);
+ unsigned analyze() {
+ return ((expr ? (expr->analyze() & ~CONTAINS_VARIABLE) : 0)
+ | CONTAINS_STAR);
+ }
+};
+
+typedef void map_func(const char *, const char *, string &);
+
+class map_expr : public unary_expr {
+ map_func *func;
+public:
+ map_expr(expression *e, map_func *f) : unary_expr(e), func(f) { }
+ void evaluate(int, const reference &, string &, substring_position &);
+};
+
+typedef const char *extractor_func(const char *, const char *, const char **);
+
+class extractor_expr : public unary_expr {
+ int part;
+ extractor_func *func;
+public:
+ enum { BEFORE = +1, MATCH = 0, AFTER = -1 };
+ extractor_expr(expression *e, extractor_func *f, int pt)
+ : unary_expr(e), func(f), part(pt) { }
+ void evaluate(int, const reference &, string &, substring_position &);
+};
+
+class truncate_expr : public unary_expr {
+ int n;
+public:
+ truncate_expr(expression *e, int i) : n(i), unary_expr(e) { }
+ void evaluate(int, const reference &, string &, substring_position &);
+};
+
+class separator_expr : public unary_expr {
+public:
+ separator_expr(expression *e) : unary_expr(e) { }
+ void evaluate(int, const reference &, string &, substring_position &);
+};
+
+class binary_expr : public expression {
+protected:
+ expression *expr1;
+ expression *expr2;
+public:
+ binary_expr(expression *e1, expression *e2) : expr1(e1), expr2(e2) { }
+ ~binary_expr() { delete expr1; delete expr2; }
+ void evaluate(int, const reference &, string &, substring_position &) = 0;
+ unsigned analyze() {
+ return (expr1 ? expr1->analyze() : 0) | (expr2 ? expr2->analyze() : 0);
+ }
+};
+
+class alternative_expr : public binary_expr {
+public:
+ alternative_expr(expression *e1, expression *e2) : binary_expr(e1, e2) { }
+ void evaluate(int, const reference &, string &, substring_position &);
+};
+
+class list_expr : public binary_expr {
+public:
+ list_expr(expression *e1, expression *e2) : binary_expr(e1, e2) { }
+ void evaluate(int, const reference &, string &, substring_position &);
+};
+
+class substitute_expr : public binary_expr {
+public:
+ substitute_expr(expression *e1, expression *e2) : binary_expr(e1, e2) { }
+ void evaluate(int, const reference &, string &, substring_position &);
+};
+
+class ternary_expr : public expression {
+protected:
+ expression *expr1;
+ expression *expr2;
+ expression *expr3;
+public:
+ ternary_expr(expression *e1, expression *e2, expression *e3)
+ : expr1(e1), expr2(e2), expr3(e3) { }
+ ~ternary_expr() { delete expr1; delete expr2; delete expr3; }
+ void evaluate(int, const reference &, string &, substring_position &) = 0;
+ unsigned analyze() {
+ return ((expr1 ? expr1->analyze() : 0)
+ | (expr2 ? expr2->analyze() : 0)
+ | (expr3 ? expr3->analyze() : 0));
+ }
+};
+
+class conditional_expr : public ternary_expr {
+public:
+ conditional_expr(expression *e1, expression *e2, expression *e3)
+ : ternary_expr(e1, e2, e3) { }
+ void evaluate(int, const reference &, string &, substring_position &);
+};
+
+static expression *parsed_label = 0;
+static expression *parsed_date_label = 0;
+static expression *parsed_short_label = 0;
+
+static expression *parse_result;
+
+string literals;
+
+%}
+
+%union {
+ int num;
+ expression *expr;
+ struct { int ndigits; int val; } dig;
+ struct { int start; int len; } str;
+}
+
+/* uppercase or lowercase letter */
+%token <num> TOKEN_LETTER
+/* literal characters */
+%token <str> TOKEN_LITERAL
+/* digit */
+%token <num> TOKEN_DIGIT
+
+%type <expr> conditional
+%type <expr> alternative
+%type <expr> list
+%type <expr> string
+%type <expr> substitute
+%type <expr> optional_conditional
+%type <num> number
+%type <dig> digits
+%type <num> optional_number
+%type <num> flag
+
+%%
+
+expr:
+ optional_conditional
+ { parse_result = ($1 ? new analyzed_expr($1) : 0); }
+ ;
+
+conditional:
+ alternative
+ { $$ = $1; }
+ | alternative '?' optional_conditional ':' conditional
+ { $$ = new conditional_expr($1, $3, $5); }
+ ;
+
+optional_conditional:
+ /* empty */
+ { $$ = 0; }
+ | conditional
+ { $$ = $1; }
+ ;
+
+alternative:
+ list
+ { $$ = $1; }
+ | alternative '|' list
+ { $$ = new alternative_expr($1, $3); }
+ | alternative '&' list
+ { $$ = new conditional_expr($1, $3, 0); }
+ ;
+
+list:
+ substitute
+ { $$ = $1; }
+ | list substitute
+ { $$ = new list_expr($1, $2); }
+ ;
+
+substitute:
+ string
+ { $$ = $1; }
+ | substitute '~' string
+ { $$ = new substitute_expr($1, $3); }
+ ;
+
+string:
+ '@'
+ { $$ = new at_expr; }
+ | TOKEN_LITERAL
+ {
+ $$ = new literal_expr(literals.contents() + $1.start,
+ $1.len);
+ }
+ | TOKEN_LETTER
+ { $$ = new field_expr($1, 0); }
+ | TOKEN_LETTER number
+ { $$ = new field_expr($1, $2 - 1); }
+ | '%' TOKEN_LETTER
+ {
+ switch ($2) {
+ case 'I':
+ case 'i':
+ case 'A':
+ case 'a':
+ $$ = new format_expr($2);
+ break;
+ default:
+ command_error("unrecognized format `%1'", char($2));
+ $$ = new format_expr('a');
+ break;
+ }
+ }
+
+ | '%' digits
+ {
+ $$ = new format_expr('0', $2.ndigits, $2.val);
+ }
+ | string '.' flag TOKEN_LETTER optional_number
+ {
+ switch ($4) {
+ case 'l':
+ $$ = new map_expr($1, lowercase);
+ break;
+ case 'u':
+ $$ = new map_expr($1, uppercase);
+ break;
+ case 'c':
+ $$ = new map_expr($1, capitalize);
+ break;
+ case 'r':
+ $$ = new map_expr($1, reverse_name);
+ break;
+ case 'a':
+ $$ = new map_expr($1, abbreviate_name);
+ break;
+ case 'y':
+ $$ = new extractor_expr($1, find_year, $3);
+ break;
+ case 'n':
+ $$ = new extractor_expr($1, find_last_name, $3);
+ break;
+ default:
+ $$ = $1;
+ command_error("unknown function `%1'", char($4));
+ break;
+ }
+ }
+
+ | string '+' number
+ { $$ = new truncate_expr($1, $3); }
+ | string '-' number
+ { $$ = new truncate_expr($1, -$3); }
+ | string '*'
+ { $$ = new star_expr($1); }
+ | '(' optional_conditional ')'
+ { $$ = $2; }
+ | '<' optional_conditional '>'
+ { $$ = new separator_expr($2); }
+ ;
+
+optional_number:
+ /* empty */
+ { $$ = -1; }
+ | number
+ { $$ = $1; }
+ ;
+
+number:
+ TOKEN_DIGIT
+ { $$ = $1; }
+ | number TOKEN_DIGIT
+ { $$ = $1*10 + $2; }
+ ;
+
+digits:
+ TOKEN_DIGIT
+ { $$.ndigits = 1; $$.val = $1; }
+ | digits TOKEN_DIGIT
+ { $$.ndigits = $1.ndigits + 1; $$.val = $1.val*10 + $2; }
+ ;
+
+
+flag:
+ /* empty */
+ { $$ = 0; }
+ | '+'
+ { $$ = 1; }
+ | '-'
+ { $$ = -1; }
+ ;
+
+%%
+
+/* bison defines const to be empty unless __STDC__ is defined, which it
+isn't under cfront */
+
+#ifdef const
+#undef const
+#endif
+
+const char *spec_ptr;
+const char *spec_end;
+const char *spec_cur;
+
+int yylex()
+{
+ while (spec_ptr < spec_end && csspace(*spec_ptr))
+ spec_ptr++;
+ spec_cur = spec_ptr;
+ if (spec_ptr >= spec_end)
+ return 0;
+ unsigned char c = *spec_ptr++;
+ if (csalpha(c)) {
+ yylval.num = c;
+ return TOKEN_LETTER;
+ }
+ if (csdigit(c)) {
+ yylval.num = c - '0';
+ return TOKEN_DIGIT;
+ }
+ if (c == '\'') {
+ yylval.str.start = literals.length();
+ for (; spec_ptr < spec_end; spec_ptr++) {
+ if (*spec_ptr == '\'') {
+ if (++spec_ptr < spec_end && *spec_ptr == '\'')
+ literals += '\'';
+ else {
+ yylval.str.len = literals.length() - yylval.str.start;
+ return TOKEN_LITERAL;
+ }
+ }
+ else
+ literals += *spec_ptr;
+ }
+ yylval.str.len = literals.length() - yylval.str.start;
+ return TOKEN_LITERAL;
+ }
+ return c;
+}
+
+int set_label_spec(const char *label_spec)
+{
+ spec_cur = spec_ptr = label_spec;
+ spec_end = strchr(label_spec, '\0');
+ literals.clear();
+ if (yyparse())
+ return 0;
+ delete parsed_label;
+ parsed_label = parse_result;
+ return 1;
+}
+
+int set_date_label_spec(const char *label_spec)
+{
+ spec_cur = spec_ptr = label_spec;
+ spec_end = strchr(label_spec, '\0');
+ literals.clear();
+ if (yyparse())
+ return 0;
+ delete parsed_date_label;
+ parsed_date_label = parse_result;
+ return 1;
+}
+
+int set_short_label_spec(const char *label_spec)
+{
+ spec_cur = spec_ptr = label_spec;
+ spec_end = strchr(label_spec, '\0');
+ literals.clear();
+ if (yyparse())
+ return 0;
+ delete parsed_short_label;
+ parsed_short_label = parse_result;
+ return 1;
+}
+
+void yyerror(const char *message)
+{
+ if (spec_cur < spec_end)
+ command_error("label specification %1 before `%2'", message, spec_cur);
+ else
+ command_error("label specification %1 at end of string",
+ message, spec_cur);
+}
+
+void at_expr::evaluate(int tentative, const reference &ref,
+ string &result, substring_position &)
+{
+ if (tentative)
+ ref.canonicalize_authors(result);
+ else {
+ const char *end, *start = ref.get_authors(&end);
+ if (start)
+ result.append(start, end - start);
+ }
+}
+
+void format_expr::evaluate(int tentative, const reference &ref,
+ string &result, substring_position &)
+{
+ if (tentative)
+ return;
+ const label_info *lp = ref.get_label_ptr();
+ int num = lp == 0 ? ref.get_number() : lp->count;
+ if (type != '0')
+ result += format_serial(type, num + 1);
+ else {
+ const char *ptr = itoa(num + first_number);
+ int pad = width - strlen(ptr);
+ while (--pad >= 0)
+ result += '0';
+ result += ptr;
+ }
+}
+
+static const char *format_serial(char c, int n)
+{
+ assert(n > 0);
+ static char buf[128]; // more than enough.
+ switch (c) {
+ case 'i':
+ case 'I':
+ {
+ char *p = buf;
+ // troff uses z and w to represent 10000 and 5000 in Roman
+ // numerals; I can find no historical basis for this usage
+ const char *s = c == 'i' ? "zwmdclxvi" : "ZWMDCLXVI";
+ if (n >= 40000)
+ return itoa(n);
+ while (n >= 10000) {
+ *p++ = s[0];
+ n -= 10000;
+ }
+ for (int i = 1000; i > 0; i /= 10, s += 2) {
+ int m = n/i;
+ n -= m*i;
+ switch (m) {
+ case 3:
+ *p++ = s[2];
+ /* falls through */
+ case 2:
+ *p++ = s[2];
+ /* falls through */
+ case 1:
+ *p++ = s[2];
+ break;
+ case 4:
+ *p++ = s[2];
+ *p++ = s[1];
+ break;
+ case 8:
+ *p++ = s[1];
+ *p++ = s[2];
+ *p++ = s[2];
+ *p++ = s[2];
+ break;
+ case 7:
+ *p++ = s[1];
+ *p++ = s[2];
+ *p++ = s[2];
+ break;
+ case 6:
+ *p++ = s[1];
+ *p++ = s[2];
+ break;
+ case 5:
+ *p++ = s[1];
+ break;
+ case 9:
+ *p++ = s[2];
+ *p++ = s[0];
+ }
+ }
+ *p = 0;
+ break;
+ }
+ case 'a':
+ case 'A':
+ {
+ char *p = buf;
+ // this is derived from troff/reg.c
+ while (n > 0) {
+ int d = n % 26;
+ if (d == 0)
+ d = 26;
+ n -= d;
+ n /= 26;
+ *p++ = c + d - 1; // ASCII dependent
+ }
+ *p-- = 0;
+ // Reverse it.
+ char *q = buf;
+ while (q < p) {
+ char temp = *q;
+ *q = *p;
+ *p = temp;
+ --p;
+ ++q;
+ }
+ break;
+ }
+ default:
+ assert(0);
+ }
+ return buf;
+}
+
+void field_expr::evaluate(int, const reference &ref,
+ string &result, substring_position &)
+{
+ const char *end;
+ const char *start = ref.get_field(name, &end);
+ if (start) {
+ start = nth_field(number, start, &end);
+ if (start)
+ result.append(start, end - start);
+ }
+}
+
+void literal_expr::evaluate(int, const reference &,
+ string &result, substring_position &)
+{
+ result += s;
+}
+
+analyzed_expr::analyzed_expr(expression *e)
+: unary_expr(e), flags(e ? e->analyze() : 0)
+{
+}
+
+void analyzed_expr::evaluate(int tentative, const reference &ref,
+ string &result, substring_position &pos)
+{
+ if (expr)
+ expr->evaluate(tentative, ref, result, pos);
+}
+
+void star_expr::evaluate(int tentative, const reference &ref,
+ string &result, substring_position &pos)
+{
+ const label_info *lp = ref.get_label_ptr();
+ if (!tentative
+ && (lp == 0 || lp->total > 1)
+ && expr)
+ expr->evaluate(tentative, ref, result, pos);
+}
+
+void separator_expr::evaluate(int tentative, const reference &ref,
+ string &result, substring_position &pos)
+{
+ int start_length = result.length();
+ int is_first = pos.start < 0;
+ if (expr)
+ expr->evaluate(tentative, ref, result, pos);
+ if (is_first) {
+ pos.start = start_length;
+ pos.length = result.length() - start_length;
+ }
+}
+
+void map_expr::evaluate(int tentative, const reference &ref,
+ string &result, substring_position &)
+{
+ if (expr) {
+ string temp;
+ substring_position temp_pos;
+ expr->evaluate(tentative, ref, temp, temp_pos);
+ (*func)(temp.contents(), temp.contents() + temp.length(), result);
+ }
+}
+
+void extractor_expr::evaluate(int tentative, const reference &ref,
+ string &result, substring_position &)
+{
+ if (expr) {
+ string temp;
+ substring_position temp_pos;
+ expr->evaluate(tentative, ref, temp, temp_pos);
+ const char *end, *start = (*func)(temp.contents(),
+ temp.contents() + temp.length(),
+ &end);
+ switch (part) {
+ case BEFORE:
+ if (start)
+ result.append(temp.contents(), start - temp.contents());
+ else
+ result += temp;
+ break;
+ case MATCH:
+ if (start)
+ result.append(start, end - start);
+ break;
+ case AFTER:
+ if (start)
+ result.append(end, temp.contents() + temp.length() - end);
+ break;
+ default:
+ assert(0);
+ }
+ }
+}
+
+static void first_part(int len, const char *ptr, const char *end,
+ string &result)
+{
+ for (;;) {
+ const char *token_start = ptr;
+ if (!get_token(&ptr, end))
+ break;
+ const token_info *ti = lookup_token(token_start, ptr);
+ int counts = ti->sortify_non_empty(token_start, ptr);
+ if (counts && --len < 0)
+ break;
+ if (counts || ti->is_accent())
+ result.append(token_start, ptr - token_start);
+ }
+}
+
+static void last_part(int len, const char *ptr, const char *end,
+ string &result)
+{
+ const char *start = ptr;
+ int count = 0;
+ for (;;) {
+ const char *token_start = ptr;
+ if (!get_token(&ptr, end))
+ break;
+ const token_info *ti = lookup_token(token_start, ptr);
+ if (ti->sortify_non_empty(token_start, ptr))
+ count++;
+ }
+ ptr = start;
+ int skip = count - len;
+ if (skip > 0) {
+ for (;;) {
+ const char *token_start = ptr;
+ if (!get_token(&ptr, end))
+ assert(0);
+ const token_info *ti = lookup_token(token_start, ptr);
+ if (ti->sortify_non_empty(token_start, ptr) && --skip < 0) {
+ ptr = token_start;
+ break;
+ }
+ }
+ }
+ first_part(len, ptr, end, result);
+}
+
+void truncate_expr::evaluate(int tentative, const reference &ref,
+ string &result, substring_position &)
+{
+ if (expr) {
+ string temp;
+ substring_position temp_pos;
+ expr->evaluate(tentative, ref, temp, temp_pos);
+ const char *start = temp.contents();
+ const char *end = start + temp.length();
+ if (n > 0)
+ first_part(n, start, end, result);
+ else if (n < 0)
+ last_part(-n, start, end, result);
+ }
+}
+
+void alternative_expr::evaluate(int tentative, const reference &ref,
+ string &result, substring_position &pos)
+{
+ int start_length = result.length();
+ if (expr1)
+ expr1->evaluate(tentative, ref, result, pos);
+ if (result.length() == start_length && expr2)
+ expr2->evaluate(tentative, ref, result, pos);
+}
+
+void list_expr::evaluate(int tentative, const reference &ref,
+ string &result, substring_position &pos)
+{
+ if (expr1)
+ expr1->evaluate(tentative, ref, result, pos);
+ if (expr2)
+ expr2->evaluate(tentative, ref, result, pos);
+}
+
+void substitute_expr::evaluate(int tentative, const reference &ref,
+ string &result, substring_position &pos)
+{
+ int start_length = result.length();
+ if (expr1)
+ expr1->evaluate(tentative, ref, result, pos);
+ if (result.length() > start_length && result[result.length() - 1] == '-') {
+ // ought to see if pos covers the -
+ result.set_length(result.length() - 1);
+ if (expr2)
+ expr2->evaluate(tentative, ref, result, pos);
+ }
+}
+
+void conditional_expr::evaluate(int tentative, const reference &ref,
+ string &result, substring_position &pos)
+{
+ string temp;
+ substring_position temp_pos;
+ if (expr1)
+ expr1->evaluate(tentative, ref, temp, temp_pos);
+ if (temp.length() > 0) {
+ if (expr2)
+ expr2->evaluate(tentative, ref, result, pos);
+ }
+ else {
+ if (expr3)
+ expr3->evaluate(tentative, ref, result, pos);
+ }
+}
+
+void reference::pre_compute_label()
+{
+ if (parsed_label != 0
+ && (parsed_label->analyze() & expression::CONTAINS_VARIABLE)) {
+ label.clear();
+ substring_position temp_pos;
+ parsed_label->evaluate(1, *this, label, temp_pos);
+ label_ptr = lookup_label(label);
+ }
+}
+
+void reference::compute_label()
+{
+ label.clear();
+ if (parsed_label)
+ parsed_label->evaluate(0, *this, label, separator_pos);
+ if (short_label_flag && parsed_short_label)
+ parsed_short_label->evaluate(0, *this, short_label, short_separator_pos);
+ if (date_as_label) {
+ string new_date;
+ if (parsed_date_label) {
+ substring_position temp_pos;
+ parsed_date_label->evaluate(0, *this, new_date, temp_pos);
+ }
+ set_date(new_date);
+ }
+ if (label_ptr)
+ label_ptr->count += 1;
+}
+
+void reference::immediate_compute_label()
+{
+ if (label_ptr)
+ label_ptr->total = 2; // force use of disambiguator
+ compute_label();
+}
+
+int reference::merge_labels(reference **v, int n, label_type type,
+ string &result)
+{
+ if (abbreviate_label_ranges)
+ return merge_labels_by_number(v, n, type, result);
+ else
+ return merge_labels_by_parts(v, n, type, result);
+}
+
+int reference::merge_labels_by_number(reference **v, int n, label_type type,
+ string &result)
+{
+ if (n <= 1)
+ return 0;
+ int num = get_number();
+ // Only merge three or more labels.
+ if (v[0]->get_number() != num + 1
+ || v[1]->get_number() != num + 2)
+ return 0;
+ for (int i = 2; i < n; i++)
+ if (v[i]->get_number() != num + i + 1)
+ break;
+ result = get_label(type);
+ result += label_range_indicator;
+ result += v[i - 1]->get_label(type);
+ return i;
+}
+
+const substring_position &reference::get_separator_pos(label_type type) const
+{
+ if (type == SHORT_LABEL && short_label_flag)
+ return short_separator_pos;
+ else
+ return separator_pos;
+}
+
+const string &reference::get_label(label_type type) const
+{
+ if (type == SHORT_LABEL && short_label_flag)
+ return short_label;
+ else
+ return label;
+}
+
+int reference::merge_labels_by_parts(reference **v, int n, label_type type,
+ string &result)
+{
+ if (n <= 0)
+ return 0;
+ const string &lb = get_label(type);
+ const substring_position &sp = get_separator_pos(type);
+ if (sp.start < 0
+ || sp.start != v[0]->get_separator_pos(type).start
+ || memcmp(lb.contents(), v[0]->get_label(type).contents(),
+ sp.start) != 0)
+ return 0;
+ result = lb;
+ int i = 0;
+ do {
+ result += separate_label_second_parts;
+ const substring_position &s = v[i]->get_separator_pos(type);
+ int sep_end_pos = s.start + s.length;
+ result.append(v[i]->get_label(type).contents() + sep_end_pos,
+ v[i]->get_label(type).length() - sep_end_pos);
+ } while (++i < n
+ && sp.start == v[i]->get_separator_pos(type).start
+ && memcmp(lb.contents(), v[i]->get_label(type).contents(),
+ sp.start) == 0);
+ return i;
+}
+
+string label_pool;
+
+label_info::label_info(const string &s)
+: count(0), total(1), length(s.length()), start(label_pool.length())
+{
+ label_pool += s;
+}
+
+static label_info **label_table = 0;
+static int label_table_size = 0;
+static int label_table_used = 0;
+
+label_info *lookup_label(const string &label)
+{
+ if (label_table == 0) {
+ label_table = new label_info *[17];
+ label_table_size = 17;
+ for (int i = 0; i < 17; i++)
+ label_table[i] = 0;
+ }
+ unsigned h = hash_string(label.contents(), label.length()) % label_table_size;
+ for (label_info **ptr = label_table + h;
+ *ptr != 0;
+ (ptr == label_table)
+ ? (ptr = label_table + label_table_size - 1)
+ : ptr--)
+ if ((*ptr)->length == label.length()
+ && memcmp(label_pool.contents() + (*ptr)->start, label.contents(),
+ label.length()) == 0) {
+ (*ptr)->total += 1;
+ return *ptr;
+ }
+ label_info *result = *ptr = new label_info(label);
+ if (++label_table_used * 2 > label_table_size) {
+ // Rehash the table.
+ label_info **old_table = label_table;
+ int old_size = label_table_size;
+ label_table_size = next_size(label_table_size);
+ label_table = new label_info *[label_table_size];
+ int i;
+ for (i = 0; i < label_table_size; i++)
+ label_table[i] = 0;
+ for (i = 0; i < old_size; i++)
+ if (old_table[i]) {
+ unsigned h = hash_string(label_pool.contents() + old_table[i]->start,
+ old_table[i]->length);
+ for (label_info **p = label_table + (h % label_table_size);
+ *p != 0;
+ (p == label_table)
+ ? (p = label_table + label_table_size - 1)
+ : --p)
+ ;
+ *p = old_table[i];
+ }
+ a_delete old_table;
+ }
+ return result;
+}
+
+void clear_labels()
+{
+ for (int i = 0; i < label_table_size; i++) {
+ delete label_table[i];
+ label_table[i] = 0;
+ }
+ label_table_used = 0;
+ label_pool.clear();
+}
+
+static void consider_authors(reference **start, reference **end, int i);
+
+void compute_labels(reference **v, int n)
+{
+ if (parsed_label
+ && (parsed_label->analyze() & expression::CONTAINS_AT)
+ && sort_fields.length() >= 2
+ && sort_fields[0] == 'A'
+ && sort_fields[1] == '+')
+ consider_authors(v, v + n, 0);
+ for (int i = 0; i < n; i++)
+ v[i]->compute_label();
+}
+
+
+/* A reference with a list of authors <A0,A1,...,AN> _needs_ author i
+where 0 <= i <= N if there exists a reference with a list of authors
+<B0,B1,...,BM> such that <A0,A1,...,AN> != <B0,B1,...,BM> and M >= i
+and Aj = Bj for 0 <= j < i. In this case if we can't say ``A0,
+A1,...,A(i-1) et al'' because this would match both <A0,A1,...,AN> and
+<B0,B1,...,BM>. If a reference needs author i we only have to call
+need_author(j) for some j >= i such that the reference also needs
+author j. */
+
+/* This function handles 2 tasks:
+determine which authors are needed (cannot be elided with et al.);
+determine which authors can have only last names in the labels.
+
+References >= start and < end have the same first i author names.
+Also they're sorted by A+. */
+
+static void consider_authors(reference **start, reference **end, int i)
+{
+ if (start >= end)
+ return;
+ reference **p = start;
+ if (i >= (*p)->get_nauthors()) {
+ for (++p; p < end && i >= (*p)->get_nauthors(); p++)
+ ;
+ if (p < end && i > 0) {
+ // If we have an author list <A B C> and an author list <A B C D>,
+ // then both lists need C.
+ for (reference **q = start; q < end; q++)
+ (*q)->need_author(i - 1);
+ }
+ start = p;
+ }
+ while (p < end) {
+ reference **last_name_start = p;
+ reference **name_start = p;
+ for (++p;
+ p < end && i < (*p)->get_nauthors()
+ && same_author_last_name(**last_name_start, **p, i);
+ p++) {
+ if (!same_author_name(**name_start, **p, i)) {
+ consider_authors(name_start, p, i + 1);
+ name_start = p;
+ }
+ }
+ consider_authors(name_start, p, i + 1);
+ if (last_name_start == name_start) {
+ for (reference **q = last_name_start; q < p; q++)
+ (*q)->set_last_name_unambiguous(i);
+ }
+ // If we have an author list <A B C D> and <A B C E>, then the lists
+ // need author D and E respectively.
+ if (name_start > start || p < end) {
+ for (reference **q = last_name_start; q < p; q++)
+ (*q)->need_author(i);
+ }
+ }
+}
+
+int same_author_last_name(const reference &r1, const reference &r2, int n)
+{
+ const char *ae1;
+ const char *as1 = r1.get_sort_field(0, n, 0, &ae1);
+ assert(as1 != 0);
+ const char *ae2;
+ const char *as2 = r2.get_sort_field(0, n, 0, &ae2);
+ assert(as2 != 0);
+ return ae1 - as1 == ae2 - as2 && memcmp(as1, as2, ae1 - as1) == 0;
+}
+
+int same_author_name(const reference &r1, const reference &r2, int n)
+{
+ const char *ae1;
+ const char *as1 = r1.get_sort_field(0, n, -1, &ae1);
+ assert(as1 != 0);
+ const char *ae2;
+ const char *as2 = r2.get_sort_field(0, n, -1, &ae2);
+ assert(as2 != 0);
+ return ae1 - as1 == ae2 - as2 && memcmp(as1, as2, ae1 - as1) == 0;
+}
+
+
+void int_set::set(int i)
+{
+ assert(i >= 0);
+ int bytei = i >> 3;
+ if (bytei >= v.length()) {
+ int old_length = v.length();
+ v.set_length(bytei + 1);
+ for (int j = old_length; j <= bytei; j++)
+ v[j] = 0;
+ }
+ v[bytei] |= 1 << (i & 7);
+}
+
+int int_set::get(int i) const
+{
+ assert(i >= 0);
+ int bytei = i >> 3;
+ return bytei >= v.length() ? 0 : (v[bytei] & (1 << (i & 7))) != 0;
+}
+
+void reference::set_last_name_unambiguous(int i)
+{
+ last_name_unambiguous.set(i);
+}
+
+void reference::need_author(int n)
+{
+ if (n > last_needed_author)
+ last_needed_author = n;
+}
+
+const char *reference::get_authors(const char **end) const
+{
+ if (!computed_authors) {
+ ((reference *)this)->computed_authors = 1;
+ string &result = ((reference *)this)->authors;
+ int na = get_nauthors();
+ result.clear();
+ for (int i = 0; i < na; i++) {
+ if (last_name_unambiguous.get(i)) {
+ const char *e, *start = get_author_last_name(i, &e);
+ assert(start != 0);
+ result.append(start, e - start);
+ }
+ else {
+ const char *e, *start = get_author(i, &e);
+ assert(start != 0);
+ result.append(start, e - start);
+ }
+ if (i == last_needed_author
+ && et_al.length() > 0
+ && et_al_min_elide > 0
+ && last_needed_author + et_al_min_elide < na
+ && na >= et_al_min_total) {
+ result += et_al;
+ break;
+ }
+ if (i < na - 1) {
+ if (na == 2)
+ result += join_authors_exactly_two;
+ else if (i < na - 2)
+ result += join_authors_default;
+ else
+ result += join_authors_last_two;
+ }
+ }
+ }
+ const char *start = authors.contents();
+ *end = start + authors.length();
+ return start;
+}
+
+int reference::get_nauthors() const
+{
+ if (nauthors < 0) {
+ const char *dummy;
+ for (int na = 0; get_author(na, &dummy) != 0; na++)
+ ;
+ ((reference *)this)->nauthors = na;
+ }
+ return nauthors;
+}
diff --git a/gnu/usr.bin/groff/refer/ref.cc b/gnu/usr.bin/groff/refer/ref.cc
new file mode 100644
index 0000000..0b78813
--- /dev/null
+++ b/gnu/usr.bin/groff/refer/ref.cc
@@ -0,0 +1,1144 @@
+// -*- C++ -*-
+/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
+Written by James Clark (jjc@jclark.com)
+
+This file is part of groff.
+
+groff is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
+
+groff is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License along
+with groff; see the file COPYING. If not, write to the Free Software
+Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "refer.h"
+#include "refid.h"
+#include "ref.h"
+#include "token.h"
+
+static const char *find_day(const char *, const char *, const char **);
+static int find_month(const char *start, const char *end);
+static void abbreviate_names(string &);
+
+#define DEFAULT_ARTICLES "the\000a\000an"
+
+string articles(DEFAULT_ARTICLES, sizeof(DEFAULT_ARTICLES));
+
+// Multiple occurrences of fields are separated by FIELD_SEPARATOR.
+const char FIELD_SEPARATOR = '\0';
+
+const char MULTI_FIELD_NAMES[] = "AE";
+const char *AUTHOR_FIELDS = "AQ";
+
+enum { OTHER, JOURNAL_ARTICLE, BOOK, ARTICLE_IN_BOOK, TECH_REPORT, BELL_TM };
+
+const char *reference_types[] = {
+ "other",
+ "journal-article",
+ "book",
+ "article-in-book",
+ "tech-report",
+ "bell-tm",
+};
+
+static string temp_fields[256];
+
+reference::reference(const char *start, int len, reference_id *ridp)
+: no(-1), field(0), nfields(0), h(0), merged(0), label_ptr(0),
+ computed_authors(0), last_needed_author(-1), nauthors(-1)
+{
+ for (int i = 0; i < 256; i++)
+ field_index[i] = NULL_FIELD_INDEX;
+ if (ridp)
+ rid = *ridp;
+ if (start == 0)
+ return;
+ if (len <= 0)
+ return;
+ const char *end = start + len;
+ const char *ptr = start;
+ assert(*ptr == '%');
+ while (ptr < end) {
+ if (ptr + 1 < end && ptr[1] != '\0'
+ && ((ptr[1] != '%' && ptr[1] == annotation_field)
+ || (ptr + 2 < end && ptr[1] == '%' && ptr[2] != '\0'
+ && discard_fields.search(ptr[2]) < 0))) {
+ if (ptr[1] == '%')
+ ptr++;
+ string &f = temp_fields[(unsigned char)ptr[1]];
+ ptr += 2;
+ while (ptr < end && csspace(*ptr))
+ ptr++;
+ for (;;) {
+ for (;;) {
+ if (ptr >= end) {
+ f += '\n';
+ break;
+ }
+ f += *ptr;
+ if (*ptr++ == '\n')
+ break;
+ }
+ if (ptr >= end || *ptr == '%')
+ break;
+ }
+ }
+ else if (ptr + 1 < end && ptr[1] != '\0' && ptr[1] != '%'
+ && discard_fields.search(ptr[1]) < 0) {
+ string &f = temp_fields[(unsigned char)ptr[1]];
+ if (f.length() > 0) {
+ if (strchr(MULTI_FIELD_NAMES, ptr[1]) != 0)
+ f += FIELD_SEPARATOR;
+ else
+ f.clear();
+ }
+ ptr += 2;
+ if (ptr < end) {
+ if (*ptr == ' ')
+ ptr++;
+ for (;;) {
+ const char *p = ptr;
+ while (ptr < end && *ptr != '\n')
+ ptr++;
+ // strip trailing white space
+ const char *q = ptr;
+ while (q > p && q[-1] != '\n' && csspace(q[-1]))
+ q--;
+ while (p < q)
+ f += *p++;
+ if (ptr >= end)
+ break;
+ ptr++;
+ if (ptr >= end)
+ break;
+ if (*ptr == '%')
+ break;
+ f += ' ';
+ }
+ }
+ }
+ else {
+ // skip this field
+ for (;;) {
+ while (ptr < end && *ptr++ != '\n')
+ ;
+ if (ptr >= end || *ptr == '%')
+ break;
+ }
+ }
+ }
+ for (i = 0; i < 256; i++)
+ if (temp_fields[i].length() > 0)
+ nfields++;
+ field = new string[nfields];
+ int j = 0;
+ for (i = 0; i < 256; i++)
+ if (temp_fields[i].length() > 0) {
+ field[j].move(temp_fields[i]);
+ if (abbreviate_fields.search(i) >= 0)
+ abbreviate_names(field[j]);
+ field_index[i] = j;
+ j++;
+ }
+}
+
+reference::~reference()
+{
+ if (nfields > 0)
+ ad_delete(nfields) field;
+}
+
+// ref is the inline, this is the database ref
+
+void reference::merge(reference &ref)
+{
+ int i;
+ for (i = 0; i < 256; i++)
+ if (field_index[i] != NULL_FIELD_INDEX)
+ temp_fields[i].move(field[field_index[i]]);
+ for (i = 0; i < 256; i++)
+ if (ref.field_index[i] != NULL_FIELD_INDEX)
+ temp_fields[i].move(ref.field[ref.field_index[i]]);
+ for (i = 0; i < 256; i++)
+ field_index[i] = NULL_FIELD_INDEX;
+ int old_nfields = nfields;
+ nfields = 0;
+ for (i = 0; i < 256; i++)
+ if (temp_fields[i].length() > 0)
+ nfields++;
+ if (nfields != old_nfields) {
+ if (old_nfields > 0)
+ ad_delete(old_nfields) field;
+ field = new string[nfields];
+ }
+ int j = 0;
+ for (i = 0; i < 256; i++)
+ if (temp_fields[i].length() > 0) {
+ field[j].move(temp_fields[i]);
+ field_index[i] = j;
+ j++;
+ }
+ merged = 1;
+}
+
+void reference::insert_field(unsigned char c, string &s)
+{
+ assert(s.length() > 0);
+ if (field_index[c] != NULL_FIELD_INDEX) {
+ field[field_index[c]].move(s);
+ return;
+ }
+ assert(field_index[c] == NULL_FIELD_INDEX);
+ string *old_field = field;
+ field = new string[nfields + 1];
+ int pos = 0;
+ for (int i = 0; i < int(c); i++)
+ if (field_index[i] != NULL_FIELD_INDEX)
+ pos++;
+ for (i = 0; i < pos; i++)
+ field[i].move(old_field[i]);
+ field[pos].move(s);
+ for (i = pos; i < nfields; i++)
+ field[i + 1].move(old_field[i]);
+ if (nfields > 0)
+ ad_delete(nfields) old_field;
+ nfields++;
+ field_index[c] = pos;
+ for (i = c + 1; i < 256; i++)
+ if (field_index[i] != NULL_FIELD_INDEX)
+ field_index[i] += 1;
+}
+
+void reference::delete_field(unsigned char c)
+{
+ if (field_index[c] == NULL_FIELD_INDEX)
+ return;
+ string *old_field = field;
+ field = new string[nfields - 1];
+ for (int i = 0; i < int(field_index[c]); i++)
+ field[i].move(old_field[i]);
+ for (i = field_index[c]; i < nfields - 1; i++)
+ field[i].move(old_field[i + 1]);
+ if (nfields > 0)
+ ad_delete(nfields) old_field;
+ nfields--;
+ field_index[c] = NULL_FIELD_INDEX;
+ for (i = c + 1; i < 256; i++)
+ if (field_index[i] != NULL_FIELD_INDEX)
+ field_index[i] -= 1;
+}
+
+void reference::compute_hash_code()
+{
+ if (!rid.is_null())
+ h = rid.hash();
+ else {
+ h = 0;
+ for (int i = 0; i < nfields; i++)
+ if (field[i].length() > 0) {
+ h <<= 4;
+ h ^= hash_string(field[i].contents(), field[i].length());
+ }
+ }
+}
+
+void reference::set_number(int n)
+{
+ no = n;
+}
+
+const char SORT_SEP = '\001';
+const char SORT_SUB_SEP = '\002';
+const char SORT_SUB_SUB_SEP = '\003';
+
+// sep specifies additional word separators
+
+void sortify_words(const char *s, const char *end, const char *sep,
+ string &result)
+{
+ int non_empty = 0;
+ int need_separator = 0;
+ for (;;) {
+ const char *token_start = s;
+ if (!get_token(&s, end))
+ break;
+ if ((s - token_start == 1
+ && (*token_start == ' '
+ || *token_start == '\n'
+ || (sep && *token_start != '\0'
+ && strchr(sep, *token_start) != 0)))
+ || (s - token_start == 2
+ && token_start[0] == '\\' && token_start[1] == ' ')) {
+ if (non_empty)
+ need_separator = 1;
+ }
+ else {
+ const token_info *ti = lookup_token(token_start, s);
+ if (ti->sortify_non_empty(token_start, s)) {
+ if (need_separator) {
+ result += ' ';
+ need_separator = 0;
+ }
+ ti->sortify(token_start, s, result);
+ non_empty = 1;
+ }
+ }
+ }
+}
+
+void sortify_word(const char *s, const char *end, string &result)
+{
+ for (;;) {
+ const char *token_start = s;
+ if (!get_token(&s, end))
+ break;
+ const token_info *ti = lookup_token(token_start, s);
+ ti->sortify(token_start, s, result);
+ }
+}
+
+void sortify_other(const char *s, int len, string &key)
+{
+ sortify_words(s, s + len, 0, key);
+}
+
+void sortify_title(const char *s, int len, string &key)
+{
+ const char *end = s + len;
+ for (; s < end && (*s == ' ' || *s == '\n'); s++)
+ ;
+ const char *ptr = s;
+ for (;;) {
+ const char *token_start = ptr;
+ if (!get_token(&ptr, end))
+ break;
+ if (ptr - token_start == 1
+ && (*token_start == ' ' || *token_start == '\n'))
+ break;
+ }
+ if (ptr < end) {
+ int first_word_len = ptr - s - 1;
+ const char *ae = articles.contents() + articles.length();
+ for (const char *a = articles.contents();
+ a < ae;
+ a = strchr(a, '\0') + 1)
+ if (first_word_len == strlen(a)) {
+ for (int j = 0; j < first_word_len; j++)
+ if (a[j] != cmlower(s[j]))
+ break;
+ if (j >= first_word_len) {
+ s = ptr;
+ for (; s < end && (*s == ' ' || *s == '\n'); s++)
+ ;
+ break;
+ }
+ }
+ }
+ sortify_words(s, end, 0, key);
+}
+
+void sortify_name(const char *s, int len, string &key)
+{
+ const char *last_name_end;
+ const char *last_name = find_last_name(s, s + len, &last_name_end);
+ sortify_word(last_name, last_name_end, key);
+ key += SORT_SUB_SUB_SEP;
+ if (last_name > s)
+ sortify_words(s, last_name, ".", key);
+ key += SORT_SUB_SUB_SEP;
+ if (last_name_end < s + len)
+ sortify_words(last_name_end, s + len, ".,", key);
+}
+
+void sortify_date(const char *s, int len, string &key)
+{
+ const char *year_end;
+ const char *year_start = find_year(s, s + len, &year_end);
+ if (!year_start) {
+ // Things without years are often `forthcoming', so it makes sense
+ // that they sort after things with explicit years.
+ key += 'A';
+ sortify_words(s, s + len, 0, key);
+ return;
+ }
+ int n = year_end - year_start;
+ while (n < 4) {
+ key += '0';
+ n++;
+ }
+ while (year_start < year_end)
+ key += *year_start++;
+ int m = find_month(s, s + len);
+ if (m < 0)
+ return;
+ key += 'A' + m;
+ const char *day_end;
+ const char *day_start = find_day(s, s + len, &day_end);
+ if (!day_start)
+ return;
+ if (day_end - day_start == 1)
+ key += '0';
+ while (day_start < day_end)
+ key += *day_start++;
+}
+
+// SORT_{SUB,SUB_SUB}_SEP can creep in from use of @ in label specification.
+
+void sortify_label(const char *s, int len, string &key)
+{
+ const char *end = s + len;
+ for (;;) {
+ for (const char *ptr = s;
+ ptr < end && *ptr != SORT_SUB_SEP && *ptr != SORT_SUB_SUB_SEP;
+ ptr++)
+ ;
+ if (ptr > s)
+ sortify_words(s, ptr, 0, key);
+ s = ptr;
+ if (s >= end)
+ break;
+ key += *s++;
+ }
+}
+
+void reference::compute_sort_key()
+{
+ if (sort_fields.length() == 0)
+ return;
+ sort_fields += '\0';
+ const char *sf = sort_fields.contents();
+ while (*sf != '\0') {
+ if (sf > sort_fields)
+ sort_key += SORT_SEP;
+ char f = *sf++;
+ int n = 1;
+ if (*sf == '+') {
+ n = INT_MAX;
+ sf++;
+ }
+ else if (csdigit(*sf)) {
+ char *ptr;
+ long l = strtol(sf, &ptr, 10);
+ if (l == 0 && ptr == sf)
+ ;
+ else {
+ sf = ptr;
+ if (l < 0) {
+ n = 1;
+ }
+ else {
+ n = int(l);
+ }
+ }
+ }
+ if (f == '.')
+ sortify_label(label.contents(), label.length(), sort_key);
+ else if (f == AUTHOR_FIELDS[0])
+ sortify_authors(n, sort_key);
+ else
+ sortify_field(f, n, sort_key);
+ }
+ sort_fields.set_length(sort_fields.length() - 1);
+}
+
+void reference::sortify_authors(int n, string &result) const
+{
+ for (const char *p = AUTHOR_FIELDS; *p != '\0'; p++)
+ if (contains_field(*p)) {
+ sortify_field(*p, n, result);
+ return;
+ }
+ sortify_field(AUTHOR_FIELDS[0], n, result);
+}
+
+void reference::canonicalize_authors(string &result) const
+{
+ int len = result.length();
+ sortify_authors(INT_MAX, result);
+ if (result.length() > len)
+ result += SORT_SUB_SEP;
+}
+
+void reference::sortify_field(unsigned char f, int n, string &result) const
+{
+ typedef void (*sortify_t)(const char *, int, string &);
+ sortify_t sortifier = sortify_other;
+ switch (f) {
+ case 'A':
+ case 'E':
+ sortifier = sortify_name;
+ break;
+ case 'D':
+ sortifier = sortify_date;
+ break;
+ case 'B':
+ case 'J':
+ case 'T':
+ sortifier = sortify_title;
+ break;
+ }
+ int fi = field_index[(unsigned char)f];
+ if (fi != NULL_FIELD_INDEX) {
+ string &str = field[fi];
+ const char *start = str.contents();
+ const char *end = start + str.length();
+ for (int i = 0; i < n && start < end; i++) {
+ const char *p = start;
+ while (start < end && *start != FIELD_SEPARATOR)
+ start++;
+ if (i > 0)
+ result += SORT_SUB_SEP;
+ (*sortifier)(p, start - p, result);
+ if (start < end)
+ start++;
+ }
+ }
+}
+
+int compare_reference(const reference &r1, const reference &r2)
+{
+ assert(r1.no >= 0);
+ assert(r2.no >= 0);
+ const char *s1 = r1.sort_key.contents();
+ int n1 = r1.sort_key.length();
+ const char *s2 = r2.sort_key.contents();
+ int n2 = r2.sort_key.length();
+ for (; n1 > 0 && n2 > 0; --n1, --n2, ++s1, ++s2)
+ if (*s1 != *s2)
+ return (int)(unsigned char)*s1 - (int)(unsigned char)*s2;
+ if (n2 > 0)
+ return -1;
+ if (n1 > 0)
+ return 1;
+ return r1.no - r2.no;
+}
+
+int same_reference(const reference &r1, const reference &r2)
+{
+ if (!r1.rid.is_null() && r1.rid == r2.rid)
+ return 1;
+ if (r1.h != r2.h)
+ return 0;
+ if (r1.nfields != r2.nfields)
+ return 0;
+ int i = 0;
+ for (i = 0; i < 256; i++)
+ if (r1.field_index != r2.field_index)
+ return 0;
+ for (i = 0; i < r1.nfields; i++)
+ if (r1.field[i] != r2.field[i])
+ return 0;
+ return 1;
+}
+
+const char *find_last_name(const char *start, const char *end,
+ const char **endp)
+{
+ const char *ptr = start;
+ const char *last_word = start;
+ for (;;) {
+ const char *token_start = ptr;
+ if (!get_token(&ptr, end))
+ break;
+ if (ptr - token_start == 1) {
+ if (*token_start == ',') {
+ *endp = token_start;
+ return last_word;
+ }
+ else if (*token_start == ' ' || *token_start == '\n') {
+ if (ptr < end && *ptr != ' ' && *ptr != '\n')
+ last_word = ptr;
+ }
+ }
+ }
+ *endp = end;
+ return last_word;
+}
+
+void abbreviate_name(const char *ptr, const char *end, string &result)
+{
+ const char *last_name_end;
+ const char *last_name_start = find_last_name(ptr, end, &last_name_end);
+ int need_period = 0;
+ for (;;) {
+ const char *token_start = ptr;
+ if (!get_token(&ptr, last_name_start))
+ break;
+ const token_info *ti = lookup_token(token_start, ptr);
+ if (need_period) {
+ if ((ptr - token_start == 1 && *token_start == ' ')
+ || (ptr - token_start == 2 && token_start[0] == '\\'
+ && token_start[1] == ' '))
+ continue;
+ if (ti->is_upper())
+ result += period_before_initial;
+ else
+ result += period_before_other;
+ need_period = 0;
+ }
+ result.append(token_start, ptr - token_start);
+ if (ti->is_upper()) {
+ const char *lower_ptr = ptr;
+ int first_token = 1;
+ for (;;) {
+ token_start = ptr;
+ if (!get_token(&ptr, last_name_start))
+ break;
+ if ((ptr - token_start == 1 && *token_start == ' ')
+ || (ptr - token_start == 2 && token_start[0] == '\\'
+ && token_start[1] == ' '))
+ break;
+ ti = lookup_token(token_start, ptr);
+ if (ti->is_hyphen()) {
+ const char *ptr1 = ptr;
+ if (get_token(&ptr1, last_name_start)) {
+ ti = lookup_token(ptr, ptr1);
+ if (ti->is_upper()) {
+ result += period_before_hyphen;
+ result.append(token_start, ptr1 - token_start);
+ ptr = ptr1;
+ }
+ }
+ }
+ else if (ti->is_upper()) {
+ // MacDougal -> MacD.
+ result.append(lower_ptr, ptr - lower_ptr);
+ lower_ptr = ptr;
+ first_token = 1;
+ }
+ else if (first_token && ti->is_accent()) {
+ result.append(token_start, ptr - token_start);
+ lower_ptr = ptr;
+ }
+ first_token = 0;
+ }
+ need_period = 1;
+ }
+ }
+ if (need_period)
+ result += period_before_last_name;
+ result.append(last_name_start, end - last_name_start);
+}
+
+static void abbreviate_names(string &result)
+{
+ string str;
+ str.move(result);
+ const char *ptr = str.contents();
+ const char *end = ptr + str.length();
+ while (ptr < end) {
+ const char *name_end = (char *)memchr(ptr, FIELD_SEPARATOR, end - ptr);
+ if (name_end == 0)
+ name_end = end;
+ abbreviate_name(ptr, name_end, result);
+ if (name_end >= end)
+ break;
+ ptr = name_end + 1;
+ result += FIELD_SEPARATOR;
+ }
+}
+
+void reverse_name(const char *ptr, const char *name_end, string &result)
+{
+ const char *last_name_end;
+ const char *last_name_start = find_last_name(ptr, name_end, &last_name_end);
+ result.append(last_name_start, last_name_end - last_name_start);
+ while (last_name_start > ptr
+ && (last_name_start[-1] == ' ' || last_name_start[-1] == '\n'))
+ last_name_start--;
+ if (last_name_start > ptr) {
+ result += ", ";
+ result.append(ptr, last_name_start - ptr);
+ }
+ if (last_name_end < name_end)
+ result.append(last_name_end, name_end - last_name_end);
+}
+
+void reverse_names(string &result, int n)
+{
+ if (n <= 0)
+ return;
+ string str;
+ str.move(result);
+ const char *ptr = str.contents();
+ const char *end = ptr + str.length();
+ while (ptr < end) {
+ if (--n < 0) {
+ result.append(ptr, end - ptr);
+ break;
+ }
+ const char *name_end = (char *)memchr(ptr, FIELD_SEPARATOR, end - ptr);
+ if (name_end == 0)
+ name_end = end;
+ reverse_name(ptr, name_end, result);
+ if (name_end >= end)
+ break;
+ ptr = name_end + 1;
+ result += FIELD_SEPARATOR;
+ }
+}
+
+// Return number of field separators.
+
+int join_fields(string &f)
+{
+ const char *ptr = f.contents();
+ int len = f.length();
+ int nfield_seps = 0;
+ for (int j = 0; j < len; j++)
+ if (ptr[j] == FIELD_SEPARATOR)
+ nfield_seps++;
+ if (nfield_seps == 0)
+ return 0;
+ string temp;
+ int field_seps_left = nfield_seps;
+ for (j = 0; j < len; j++) {
+ if (ptr[j] == FIELD_SEPARATOR) {
+ if (nfield_seps == 1)
+ temp += join_authors_exactly_two;
+ else if (--field_seps_left == 0)
+ temp += join_authors_last_two;
+ else
+ temp += join_authors_default;
+ }
+ else
+ temp += ptr[j];
+ }
+ f = temp;
+ return nfield_seps;
+}
+
+void uppercase(const char *start, const char *end, string &result)
+{
+ for (;;) {
+ const char *token_start = start;
+ if (!get_token(&start, end))
+ break;
+ const token_info *ti = lookup_token(token_start, start);
+ ti->upper_case(token_start, start, result);
+ }
+}
+
+void lowercase(const char *start, const char *end, string &result)
+{
+ for (;;) {
+ const char *token_start = start;
+ if (!get_token(&start, end))
+ break;
+ const token_info *ti = lookup_token(token_start, start);
+ ti->lower_case(token_start, start, result);
+ }
+}
+
+void capitalize(const char *ptr, const char *end, string &result)
+{
+ int in_small_point_size = 0;
+ for (;;) {
+ const char *start = ptr;
+ if (!get_token(&ptr, end))
+ break;
+ const token_info *ti = lookup_token(start, ptr);
+ const char *char_end = ptr;
+ int is_lower = ti->is_lower();
+ if ((is_lower || ti->is_upper()) && get_token(&ptr, end)) {
+ const token_info *ti2 = lookup_token(char_end, ptr);
+ if (!ti2->is_accent())
+ ptr = char_end;
+ }
+ if (is_lower) {
+ if (!in_small_point_size) {
+ result += "\\s-2";
+ in_small_point_size = 1;
+ }
+ ti->upper_case(start, char_end, result);
+ result.append(char_end, ptr - char_end);
+ }
+ else {
+ if (in_small_point_size) {
+ result += "\\s+2";
+ in_small_point_size = 0;
+ }
+ result.append(start, ptr - start);
+ }
+ }
+ if (in_small_point_size)
+ result += "\\s+2";
+}
+
+void capitalize_field(string &str)
+{
+ string temp;
+ capitalize(str.contents(), str.contents() + str.length(), temp);
+ str.move(temp);
+}
+
+int is_terminated(const char *ptr, const char *end)
+{
+ const char *last_token = end;
+ for (;;) {
+ const char *p = ptr;
+ if (!get_token(&ptr, end))
+ break;
+ last_token = p;
+ }
+ return end - last_token == 1
+ && (*last_token == '.' || *last_token == '!' || *last_token == '?');
+}
+
+void reference::output(FILE *fp)
+{
+ fputs(".]-\n", fp);
+ for (int i = 0; i < 256; i++)
+ if (field_index[i] != NULL_FIELD_INDEX && i != annotation_field) {
+ string &f = field[field_index[i]];
+ if (!csdigit(i)) {
+ int j = reverse_fields.search(i);
+ if (j >= 0) {
+ int n;
+ int len = reverse_fields.length();
+ if (++j < len && csdigit(reverse_fields[j])) {
+ n = reverse_fields[j] - '0';
+ for (++j; j < len && csdigit(reverse_fields[j]); j++)
+ // should check for overflow
+ n = n*10 + reverse_fields[j] - '0';
+ }
+ else
+ n = INT_MAX;
+ reverse_names(f, n);
+ }
+ }
+ int is_multiple = join_fields(f) > 0;
+ if (capitalize_fields.search(i) >= 0)
+ capitalize_field(f);
+ if (memchr(f.contents(), '\n', f.length()) == 0) {
+ fprintf(fp, ".ds [%c ", i);
+ if (f[0] == ' ' || f[0] == '\\' || f[0] == '"')
+ putc('"', fp);
+ put_string(f, fp);
+ putc('\n', fp);
+ }
+ else {
+ fprintf(fp, ".de [%c\n", i);
+ put_string(f, fp);
+ fputs("..\n", fp);
+ }
+ if (i == 'P') {
+ int multiple_pages = 0;
+ if (f.length() > 0 && memchr(f.contents(), '-', f.length()) != 0)
+ multiple_pages = 1;
+ fprintf(fp, ".nr [P %d\n", multiple_pages);
+ }
+ else if (i == 'E')
+ fprintf(fp, ".nr [E %d\n", is_multiple);
+ }
+ for (const char *p = "TAO"; *p; p++) {
+ int fi = field_index[(unsigned char)*p];
+ if (fi != NULL_FIELD_INDEX) {
+ string &f = field[fi];
+ fprintf(fp, ".nr [%c %d\n", *p,
+ is_terminated(f.contents(), f.contents() + f.length()));
+ }
+ }
+ int t = classify();
+ fprintf(fp, ".][ %d %s\n", t, reference_types[t]);
+ if (annotation_macro.length() > 0 && annotation_field >= 0
+ && field_index[annotation_field] != NULL_FIELD_INDEX) {
+ putc('.', fp);
+ put_string(annotation_macro, fp);
+ putc('\n', fp);
+ put_string(field[field_index[annotation_field]], fp);
+ }
+}
+
+void reference::print_sort_key_comment(FILE *fp)
+{
+ fputs(".\\\"", fp);
+ put_string(sort_key, fp);
+ putc('\n', fp);
+}
+
+const char *find_year(const char *start, const char *end, const char **endp)
+{
+ for (;;) {
+ while (start < end && !csdigit(*start))
+ start++;
+ const char *ptr = start;
+ if (start == end)
+ break;
+ while (ptr < end && csdigit(*ptr))
+ ptr++;
+ if (ptr - start == 4 || ptr - start == 3
+ || (ptr - start == 2
+ && (start[0] >= '4' || (start[0] == '3' && start[1] >= '2')))) {
+ *endp = ptr;
+ return start;
+ }
+ start = ptr;
+ }
+ return 0;
+}
+
+static const char *find_day(const char *start, const char *end,
+ const char **endp)
+{
+ for (;;) {
+ while (start < end && !csdigit(*start))
+ start++;
+ const char *ptr = start;
+ if (start == end)
+ break;
+ while (ptr < end && csdigit(*ptr))
+ ptr++;
+ if ((ptr - start == 1 && start[0] != '0')
+ || (ptr - start == 2 &&
+ (start[0] == '1'
+ || start[0] == '2'
+ || (start[0] == '3' && start[1] <= '1')
+ || (start[0] == '0' && start[1] != '0')))) {
+ *endp = ptr;
+ return start;
+ }
+ start = ptr;
+ }
+ return 0;
+}
+
+static int find_month(const char *start, const char *end)
+{
+ static const char *months[] = {
+ "january",
+ "february",
+ "march",
+ "april",
+ "may",
+ "june",
+ "july",
+ "august",
+ "september",
+ "october",
+ "november",
+ "december",
+ };
+ for (;;) {
+ while (start < end && !csalpha(*start))
+ start++;
+ const char *ptr = start;
+ if (start == end)
+ break;
+ while (ptr < end && csalpha(*ptr))
+ ptr++;
+ if (ptr - start >= 3) {
+ for (int i = 0; i < sizeof(months)/sizeof(months[0]); i++) {
+ const char *q = months[i];
+ const char *p = start;
+ for (; p < ptr; p++, q++)
+ if (cmlower(*p) != *q)
+ break;
+ if (p >= ptr)
+ return i;
+ }
+ }
+ start = ptr;
+ }
+ return -1;
+}
+
+int reference::contains_field(char c) const
+{
+ return field_index[(unsigned char)c] != NULL_FIELD_INDEX;
+}
+
+int reference::classify()
+{
+ if (contains_field('J'))
+ return JOURNAL_ARTICLE;
+ if (contains_field('B'))
+ return ARTICLE_IN_BOOK;
+ if (contains_field('G'))
+ return TECH_REPORT;
+ if (contains_field('R'))
+ return TECH_REPORT;
+ if (contains_field('I'))
+ return BOOK;
+ if (contains_field('M'))
+ return BELL_TM;
+ return OTHER;
+}
+
+const char *reference::get_year(const char **endp) const
+{
+ if (field_index['D'] != NULL_FIELD_INDEX) {
+ string &date = field[field_index['D']];
+ const char *start = date.contents();
+ const char *end = start + date.length();
+ return find_year(start, end, endp);
+ }
+ else
+ return 0;
+}
+
+const char *reference::get_field(unsigned char c, const char **endp) const
+{
+ if (field_index[c] != NULL_FIELD_INDEX) {
+ string &f = field[field_index[c]];
+ const char *start = f.contents();
+ *endp = start + f.length();
+ return start;
+ }
+ else
+ return 0;
+}
+
+const char *reference::get_date(const char **endp) const
+{
+ return get_field('D', endp);
+}
+
+const char *nth_field(int i, const char *start, const char **endp)
+{
+ while (--i >= 0) {
+ start = (char *)memchr(start, FIELD_SEPARATOR, *endp - start);
+ if (!start)
+ return 0;
+ start++;
+ }
+ const char *e = (char *)memchr(start, FIELD_SEPARATOR, *endp - start);
+ if (e)
+ *endp = e;
+ return start;
+}
+
+const char *reference::get_author(int i, const char **endp) const
+{
+ for (const char *f = AUTHOR_FIELDS; *f != '\0'; f++) {
+ const char *start = get_field(*f, endp);
+ if (start) {
+ if (strchr(MULTI_FIELD_NAMES, *f) != 0)
+ return nth_field(i, start, endp);
+ else if (i == 0)
+ return start;
+ else
+ return 0;
+ }
+ }
+ return 0;
+}
+
+const char *reference::get_author_last_name(int i, const char **endp) const
+{
+ for (const char *f = AUTHOR_FIELDS; *f != '\0'; f++) {
+ const char *start = get_field(*f, endp);
+ if (start) {
+ if (strchr(MULTI_FIELD_NAMES, *f) != 0) {
+ start = nth_field(i, start, endp);
+ if (!start)
+ return 0;
+ }
+ if (*f == 'A')
+ return find_last_name(start, *endp, endp);
+ else
+ return start;
+ }
+ }
+ return 0;
+}
+
+void reference::set_date(string &d)
+{
+ if (d.length() == 0)
+ delete_field('D');
+ else
+ insert_field('D', d);
+}
+
+int same_year(const reference &r1, const reference &r2)
+{
+ const char *ye1;
+ const char *ys1 = r1.get_year(&ye1);
+ const char *ye2;
+ const char *ys2 = r2.get_year(&ye2);
+ if (ys1 == 0) {
+ if (ys2 == 0)
+ return same_date(r1, r2);
+ else
+ return 0;
+ }
+ else if (ys2 == 0)
+ return 0;
+ else if (ye1 - ys1 != ye2 - ys2)
+ return 0;
+ else
+ return memcmp(ys1, ys2, ye1 - ys1) == 0;
+}
+
+int same_date(const reference &r1, const reference &r2)
+{
+ const char *e1;
+ const char *s1 = r1.get_date(&e1);
+ const char *e2;
+ const char *s2 = r2.get_date(&e2);
+ if (s1 == 0)
+ return s2 == 0;
+ else if (s2 == 0)
+ return 0;
+ else if (e1 - s1 != e2 - s2)
+ return 0;
+ else
+ return memcmp(s1, s2, e1 - s1) == 0;
+}
+
+const char *reference::get_sort_field(int i, int si, int ssi,
+ const char **endp) const
+{
+ const char *start = sort_key.contents();
+ const char *end = start + sort_key.length();
+ if (i < 0) {
+ *endp = end;
+ return start;
+ }
+ while (--i >= 0) {
+ start = (char *)memchr(start, SORT_SEP, end - start);
+ if (!start)
+ return 0;
+ start++;
+ }
+ const char *e = (char *)memchr(start, SORT_SEP, end - start);
+ if (e)
+ end = e;
+ if (si < 0) {
+ *endp = end;
+ return start;
+ }
+ while (--si >= 0) {
+ start = (char *)memchr(start, SORT_SUB_SEP, end - start);
+ if (!start)
+ return 0;
+ start++;
+ }
+ e = (char *)memchr(start, SORT_SUB_SEP, end - start);
+ if (e)
+ end = e;
+ if (ssi < 0) {
+ *endp = end;
+ return start;
+ }
+ while (--ssi >= 0) {
+ start = (char *)memchr(start, SORT_SUB_SUB_SEP, end - start);
+ if (!start)
+ return 0;
+ start++;
+ }
+ e = (char *)memchr(start, SORT_SUB_SUB_SEP, end - start);
+ if (e)
+ end = e;
+ *endp = end;
+ return start;
+}
+
diff --git a/gnu/usr.bin/groff/refer/ref.h b/gnu/usr.bin/groff/refer/ref.h
new file mode 100644
index 0000000..28e498d
--- /dev/null
+++ b/gnu/usr.bin/groff/refer/ref.h
@@ -0,0 +1,120 @@
+// -*- C++ -*-
+/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
+ Written by James Clark (jjc@jclark.com)
+
+This file is part of groff.
+
+groff is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
+
+groff is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License along
+with groff; see the file COPYING. If not, write to the Free Software
+Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+struct label_info;
+
+enum label_type { NORMAL_LABEL, SHORT_LABEL };
+const int N_LABEL_TYPES = 2;
+
+struct substring_position {
+ int start;
+ int length;
+ substring_position() : start(-1) { }
+};
+
+class int_set {
+ string v;
+public:
+ int_set() { }
+ void set(int i);
+ int get(int i) const;
+};
+
+class reference {
+private:
+ unsigned h;
+ reference_id rid;
+ int merged;
+ string sort_key;
+ int no;
+ string *field;
+ int nfields;
+ unsigned char field_index[256];
+ enum { NULL_FIELD_INDEX = 255 };
+ string label;
+ substring_position separator_pos;
+ string short_label;
+ substring_position short_separator_pos;
+ label_info *label_ptr;
+ string authors;
+ int computed_authors;
+ int last_needed_author;
+ int nauthors;
+ int_set last_name_unambiguous;
+
+ int contains_field(char) const;
+ void insert_field(unsigned char, string &s);
+ void delete_field(unsigned char);
+ void set_date(string &);
+ const char *get_sort_field(int i, int si, int ssi, const char **endp) const;
+ int merge_labels_by_parts(reference **, int, label_type, string &);
+ int merge_labels_by_number(reference **, int, label_type, string &);
+public:
+ reference(const char * = 0, int = -1, reference_id * = 0);
+ ~reference();
+ void output(FILE *);
+ void print_sort_key_comment(FILE *);
+ void set_number(int);
+ int get_number() const { return no; }
+ unsigned hash() const { return h; }
+ const string &get_label(label_type type) const;
+ const substring_position &get_separator_pos(label_type) const;
+ int is_merged() const { return merged; }
+ void compute_sort_key();
+ void compute_hash_code();
+ void pre_compute_label();
+ void compute_label();
+ void immediate_compute_label();
+ int classify();
+ void merge(reference &);
+ int merge_labels(reference **, int, label_type, string &);
+ int get_nauthors() const;
+ void need_author(int);
+ void set_last_name_unambiguous(int);
+ void sortify_authors(int, string &) const;
+ void canonicalize_authors(string &) const;
+ void sortify_field(unsigned char, int, string &) const;
+ const char *get_author(int, const char **) const;
+ const char *get_author_last_name(int, const char **) const;
+ const char *get_date(const char **) const;
+ const char *get_year(const char **) const;
+ const char *get_field(unsigned char, const char **) const;
+ const label_info *get_label_ptr() const { return label_ptr; }
+ const char *get_authors(const char **) const;
+ // for sorting
+ friend int compare_reference(const reference &r1, const reference &r2);
+ // for merging
+ friend int same_reference(const reference &, const reference &);
+ friend int same_year(const reference &, const reference &);
+ friend int same_date(const reference &, const reference &);
+ friend int same_author_last_name(const reference &, const reference &, int);
+ friend int same_author_name(const reference &, const reference &, int);
+};
+
+const char *find_year(const char *, const char *, const char **);
+const char *find_last_name(const char *, const char *, const char **);
+
+const char *nth_field(int i, const char *start, const char **endp);
+
+void capitalize(const char *ptr, const char *end, string &result);
+void reverse_name(const char *ptr, const char *end, string &result);
+void uppercase(const char *ptr, const char *end, string &result);
+void lowercase(const char *ptr, const char *end, string &result);
+void abbreviate_name(const char *ptr, const char *end, string &result);
diff --git a/gnu/usr.bin/groff/refer/refer.cc b/gnu/usr.bin/groff/refer/refer.cc
new file mode 100644
index 0000000..0f66410
--- /dev/null
+++ b/gnu/usr.bin/groff/refer/refer.cc
@@ -0,0 +1,1221 @@
+// -*- C++ -*-
+/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
+ Written by James Clark (jjc@jclark.com)
+
+This file is part of groff.
+
+groff is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
+
+groff is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License along
+with groff; see the file COPYING. If not, write to the Free Software
+Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "refer.h"
+#include "refid.h"
+#include "ref.h"
+#include "token.h"
+#include "search.h"
+#include "command.h"
+
+const char PRE_LABEL_MARKER = '\013';
+const char POST_LABEL_MARKER = '\014';
+const char LABEL_MARKER = '\015'; // label_type is added on
+
+#define FORCE_LEFT_BRACKET 04
+#define FORCE_RIGHT_BRACKET 010
+
+static FILE *outfp = stdout;
+
+string capitalize_fields;
+string reverse_fields;
+string abbreviate_fields;
+string period_before_last_name = ". ";
+string period_before_initial = ".";
+string period_before_hyphen = "";
+string period_before_other = ". ";
+string sort_fields;
+int annotation_field = -1;
+string annotation_macro;
+string discard_fields = "XYZ";
+string pre_label = "\\*([.";
+string post_label = "\\*(.]";
+string sep_label = ", ";
+int accumulate = 0;
+int move_punctuation = 0;
+int abbreviate_label_ranges = 0;
+string label_range_indicator;
+int label_in_text = 1;
+int label_in_reference = 1;
+int date_as_label = 0;
+int sort_adjacent_labels = 0;
+// Join exactly two authors with this.
+string join_authors_exactly_two = " and ";
+// When there are more than two authors join the last two with this.
+string join_authors_last_two = ", and ";
+// Otherwise join authors with this.
+string join_authors_default = ", ";
+string separate_label_second_parts = ", ";
+// Use this string to represent that there are other authors.
+string et_al = " et al";
+// Use et al only if it can replace at least this many authors.
+int et_al_min_elide = 2;
+// Use et al only if the total number of authors is at least this.
+int et_al_min_total = 3;
+
+
+int compatible_flag = 0;
+
+int short_label_flag = 0;
+
+static int recognize_R1_R2 = 1;
+
+search_list database_list;
+int search_default = 1;
+static int default_database_loaded = 0;
+
+static reference **citation = 0;
+static int ncitations = 0;
+static int citation_max = 0;
+
+static reference **reference_hash_table = 0;
+static int hash_table_size;
+static int nreferences = 0;
+
+static int need_syncing = 0;
+string pending_line;
+string pending_lf_lines;
+
+static void output_pending_line();
+static unsigned immediately_handle_reference(const string &);
+static void immediately_output_references();
+static unsigned store_reference(const string &);
+static void divert_to_temporary_file();
+static reference *make_reference(const string &, unsigned *);
+static void usage();
+static void do_file(const char *);
+static void split_punct(string &line, string &punct);
+static void output_citation_group(reference **v, int n, label_type, FILE *fp);
+static void possibly_load_default_database();
+
+int main(int argc, char **argv)
+{
+ program_name = argv[0];
+ static char stderr_buf[BUFSIZ];
+ setbuf(stderr, stderr_buf);
+ outfp = stdout;
+ int finished_options = 0;
+ int bib_flag = 0;
+ int done_spec = 0;
+
+ for (--argc, ++argv;
+ !finished_options && argc > 0 && argv[0][0] == '-'
+ && argv[0][1] != '\0';
+ argv++, argc--) {
+ const char *opt = argv[0] + 1;
+ while (opt != 0 && *opt != '\0') {
+ switch (*opt) {
+ case 'C':
+ compatible_flag = 1;
+ opt++;
+ break;
+ case 'B':
+ bib_flag = 1;
+ label_in_reference = 0;
+ label_in_text = 0;
+ ++opt;
+ if (*opt == '\0') {
+ annotation_field = 'X';
+ annotation_macro = "AP";
+ }
+ else if (csalnum(opt[0]) && opt[1] == '.' && opt[2] != '\0') {
+ annotation_field = opt[0];
+ annotation_macro = opt + 2;
+ }
+ opt = 0;
+ break;
+ case 'P':
+ move_punctuation = 1;
+ opt++;
+ break;
+ case 'R':
+ recognize_R1_R2 = 0;
+ opt++;
+ break;
+ case 'S':
+ // Not a very useful spec.
+ set_label_spec("(A.n|Q)', '(D.y|D)");
+ done_spec = 1;
+ pre_label = " (";
+ post_label = ")";
+ sep_label = "; ";
+ opt++;
+ break;
+ case 'V':
+ verify_flag = 1;
+ opt++;
+ break;
+ case 'f':
+ {
+ const char *num = 0;
+ if (*++opt == '\0') {
+ if (argc > 1) {
+ num = *++argv;
+ --argc;
+ }
+ else {
+ error("option `f' requires an argument");
+ usage();
+ }
+ }
+ else {
+ num = opt;
+ opt = 0;
+ }
+ for (const char *ptr = num; *ptr; ptr++)
+ if (!csdigit(*ptr)) {
+ error("bad character `%1' in argument to -f option", *ptr);
+ break;
+ }
+ if (*ptr == '\0') {
+ string spec;
+ spec = '%';
+ spec += num;
+ spec += '\0';
+ set_label_spec(spec.contents());
+ done_spec = 1;
+ }
+ break;
+ }
+ case 'b':
+ label_in_text = 0;
+ label_in_reference = 0;
+ opt++;
+ break;
+ case 'e':
+ accumulate = 1;
+ opt++;
+ break;
+ case 'c':
+ capitalize_fields = ++opt;
+ opt = 0;
+ break;
+ case 'k':
+ {
+ char buf[5];
+ if (csalpha(*++opt))
+ buf[0] = *opt++;
+ else {
+ if (*opt != '\0')
+ error("bad field name `%1'", *opt++);
+ buf[0] = 'L';
+ }
+ buf[1] = '~';
+ buf[2] = '%';
+ buf[3] = 'a';
+ buf[4] = '\0';
+ set_label_spec(buf);
+ done_spec = 1;
+ }
+ break;
+ case 'a':
+ {
+ for (const char *ptr = ++opt; *ptr; ptr++)
+ if (!csdigit(*ptr)) {
+ error("argument to `a' option not a number");
+ break;
+ }
+ if (*ptr == '\0') {
+ reverse_fields = 'A';
+ reverse_fields += opt;
+ }
+ opt = 0;
+ }
+ break;
+ case 'i':
+ linear_ignore_fields = ++opt;
+ opt = 0;
+ break;
+ case 'l':
+ {
+ char buf[INT_DIGITS*2 + 11]; // A.n+2D.y-3%a
+ strcpy(buf, "A.n");
+ if (*++opt != '\0' && *opt != ',') {
+ char *ptr;
+ long n = strtol(opt, &ptr, 10);
+ if (n == 0 && ptr == opt) {
+ error("bad integer `%1' in `l' option", opt);
+ opt = 0;
+ break;
+ }
+ if (n < 0)
+ n = 0;
+ opt = ptr;
+ sprintf(strchr(buf, '\0'), "+%ld", n);
+ }
+ strcat(buf, "D.y");
+ if (*opt == ',')
+ opt++;
+ if (*opt != '\0') {
+ char *ptr;
+ long n = strtol(opt, &ptr, 10);
+ if (n == 0 && ptr == opt) {
+ error("bad integer `%1' in `l' option", opt);
+ opt = 0;
+ break;
+ }
+ if (n < 0)
+ n = 0;
+ sprintf(strchr(buf, '\0'), "-%ld", n);
+ opt = ptr;
+ if (*opt != '\0')
+ error("argument to `l' option not of form `m,n'");
+ }
+ strcat(buf, "%a");
+ if (!set_label_spec(buf))
+ assert(0);
+ done_spec = 1;
+ }
+ break;
+ case 'n':
+ search_default = 0;
+ opt++;
+ break;
+ case 'p':
+ {
+ const char *filename = 0;
+ if (*++opt == '\0') {
+ if (argc > 1) {
+ filename = *++argv;
+ argc--;
+ }
+ else {
+ error("option `p' requires an argument");
+ usage();
+ }
+ }
+ else {
+ filename = opt;
+ opt = 0;
+ }
+ database_list.add_file(filename);
+ }
+ break;
+ case 's':
+ if (*++opt == '\0')
+ sort_fields = "AD";
+ else {
+ sort_fields = opt;
+ opt = 0;
+ }
+ accumulate = 1;
+ break;
+ case 't':
+ {
+ char *ptr;
+ long n = strtol(opt, &ptr, 10);
+ if (n == 0 && ptr == opt) {
+ error("bad integer `%1' in `t' option", opt);
+ opt = 0;
+ break;
+ }
+ if (n < 1)
+ n = 1;
+ linear_truncate_len = int(n);
+ opt = ptr;
+ break;
+ }
+ case 'v':
+ {
+ extern const char *version_string;
+ fprintf(stderr, "GNU refer version %s\n", version_string);
+ fflush(stderr);
+ opt++;
+ break;
+ }
+ case '-':
+ if (opt[1] == '\0') {
+ finished_options = 1;
+ opt++;
+ break;
+ }
+ // fall through
+ default:
+ error("unrecognized option `%1'", *opt);
+ usage();
+ break;
+ }
+ }
+ }
+ if (!done_spec)
+ set_label_spec("%1");
+ if (argc <= 0) {
+ if (bib_flag)
+ do_bib("-");
+ else
+ do_file("-");
+ }
+ else {
+ for (int i = 0; i < argc; i++) {
+ if (bib_flag)
+ do_bib(argv[i]);
+ else
+ do_file(argv[i]);
+ }
+ }
+ if (accumulate)
+ output_references();
+ if (fflush(stdout) < 0)
+ fatal("output error");
+ return 0;
+}
+
+static void usage()
+{
+ fprintf(stderr,
+"usage: %s [-benvCPRS] [-aN] [-cXYZ] [-fN] [-iXYZ] [-kX] [-lM,N] [-p file]\n"
+" [-sXYZ] [-tN] [-BL.M] [files ...]\n",
+ program_name);
+ exit(1);
+}
+
+static void possibly_load_default_database()
+{
+ if (search_default && !default_database_loaded) {
+ char *filename = getenv("REFER");
+ if (filename)
+ database_list.add_file(filename);
+ else
+ database_list.add_file(DEFAULT_INDEX, 1);
+ default_database_loaded = 1;
+ }
+}
+
+static int is_list(const string &str)
+{
+ const char *start = str.contents();
+ const char *end = start + str.length();
+ while (end > start && csspace(end[-1]))
+ end--;
+ while (start < end && csspace(*start))
+ start++;
+ return end - start == 6 && memcmp(start, "$LIST$", 6) == 0;
+}
+
+static void do_file(const char *filename)
+{
+ FILE *fp;
+ if (strcmp(filename, "-") == 0) {
+ fp = stdin;
+ }
+ else {
+ errno = 0;
+ fp = fopen(filename, "r");
+ if (fp == 0) {
+ error("can't open `%1': %2", filename, strerror(errno));
+ return;
+ }
+ }
+ current_filename = filename;
+ fprintf(outfp, ".lf 1 %s\n", filename);
+ string line;
+ current_lineno = 0;
+ for (;;) {
+ line.clear();
+ for (;;) {
+ int c = getc(fp);
+ if (c == EOF) {
+ if (line.length() > 0)
+ line += '\n';
+ break;
+ }
+ if (illegal_input_char(c))
+ error("illegal input character code %1", c);
+ else {
+ line += c;
+ if (c == '\n')
+ break;
+ }
+ }
+ int len = line.length();
+ if (len == 0)
+ break;
+ current_lineno++;
+ if (len >= 2 && line[0] == '.' && line[1] == '[') {
+ int start_lineno = current_lineno;
+ int start_of_line = 1;
+ string str;
+ string post;
+ string pre(line.contents() + 2, line.length() - 3);
+ for (;;) {
+ int c = getc(fp);
+ if (c == EOF) {
+ error_with_file_and_line(current_filename, start_lineno,
+ "missing `.]' line");
+ break;
+ }
+ if (start_of_line)
+ current_lineno++;
+ if (start_of_line && c == '.') {
+ int d = getc(fp);
+ if (d == ']') {
+ while ((d = getc(fp)) != '\n' && d != EOF) {
+ if (illegal_input_char(d))
+ error("illegal input character code %1", d);
+ else
+ post += d;
+ }
+ break;
+ }
+ if (d != EOF)
+ ungetc(d, fp);
+ }
+ if (illegal_input_char(c))
+ error("illegal input character code %1", c);
+ else
+ str += c;
+ start_of_line = (c == '\n');
+ }
+ if (is_list(str)) {
+ output_pending_line();
+ if (accumulate)
+ output_references();
+ else
+ error("found `$LIST$' but not accumulating references");
+ }
+ else {
+ unsigned flags = (accumulate
+ ? store_reference(str)
+ : immediately_handle_reference(str));
+ if (label_in_text) {
+ if (accumulate && outfp == stdout)
+ divert_to_temporary_file();
+ if (pending_line.length() == 0) {
+ warning("can't attach citation to previous line");
+ }
+ else
+ pending_line.set_length(pending_line.length() - 1);
+ string punct;
+ if (move_punctuation)
+ split_punct(pending_line, punct);
+ int have_text = pre.length() > 0 || post.length() > 0;
+ label_type lt = label_type(flags & ~(FORCE_LEFT_BRACKET
+ |FORCE_RIGHT_BRACKET));
+ if ((flags & FORCE_LEFT_BRACKET) || !have_text)
+ pending_line += PRE_LABEL_MARKER;
+ pending_line += pre;
+ pending_line += LABEL_MARKER + lt;
+ pending_line += post;
+ if ((flags & FORCE_RIGHT_BRACKET) || !have_text)
+ pending_line += POST_LABEL_MARKER;
+ pending_line += punct;
+ pending_line += '\n';
+ }
+ }
+ need_syncing = 1;
+ }
+ else if (len >= 4
+ && line[0] == '.' && line[1] == 'l' && line[2] == 'f'
+ && (compatible_flag || line[3] == '\n' || line[3] == ' ')) {
+ pending_lf_lines += line;
+ line += '\0';
+ if (interpret_lf_args(line.contents() + 3))
+ current_lineno--;
+ }
+ else if (recognize_R1_R2
+ && len >= 4
+ && line[0] == '.' && line[1] == 'R' && line[2] == '1'
+ && (compatible_flag || line[3] == '\n' || line[3] == ' ')) {
+ line.clear();
+ int start_of_line = 1;
+ int start_lineno = current_lineno;
+ for (;;) {
+ int c = getc(fp);
+ if (c != EOF && start_of_line)
+ current_lineno++;
+ if (start_of_line && c == '.') {
+ c = getc(fp);
+ if (c == 'R') {
+ c = getc(fp);
+ if (c == '2') {
+ c = getc(fp);
+ if (compatible_flag || c == ' ' || c == '\n' || c == EOF) {
+ while (c != EOF && c != '\n')
+ c = getc(fp);
+ break;
+ }
+ else {
+ line += '.';
+ line += 'R';
+ line += '2';
+ }
+ }
+ else {
+ line += '.';
+ line += 'R';
+ }
+ }
+ else
+ line += '.';
+ }
+ if (c == EOF) {
+ error_with_file_and_line(current_filename, start_lineno,
+ "missing `.R2' line");
+ break;
+ }
+ if (illegal_input_char(c))
+ error("illegal input character code %1", int(c));
+ else {
+ line += c;
+ start_of_line = c == '\n';
+ }
+ }
+ output_pending_line();
+ if (accumulate)
+ output_references();
+ else
+ nreferences = 0;
+ process_commands(line, current_filename, start_lineno + 1);
+ need_syncing = 1;
+ }
+ else {
+ output_pending_line();
+ pending_line = line;
+ }
+ }
+ need_syncing = 0;
+ output_pending_line();
+ if (fp != stdin)
+ fclose(fp);
+}
+
+class label_processing_state {
+ enum {
+ NORMAL,
+ PENDING_LABEL,
+ PENDING_LABEL_POST,
+ PENDING_LABEL_POST_PRE,
+ PENDING_POST
+ } state;
+ label_type type; // type of pending labels
+ int count; // number of pending labels
+ reference **rptr; // pointer to next reference
+ int rcount; // number of references left
+ FILE *fp;
+ int handle_pending(int c);
+public:
+ label_processing_state(reference **, int, FILE *);
+ ~label_processing_state();
+ void process(int c);
+};
+
+static void output_pending_line()
+{
+ if (label_in_text && !accumulate && ncitations > 0) {
+ label_processing_state state(citation, ncitations, outfp);
+ int len = pending_line.length();
+ for (int i = 0; i < len; i++)
+ state.process((unsigned char)(pending_line[i]));
+ }
+ else
+ put_string(pending_line, outfp);
+ pending_line.clear();
+ if (pending_lf_lines.length() > 0) {
+ put_string(pending_lf_lines, outfp);
+ pending_lf_lines.clear();
+ }
+ if (!accumulate)
+ immediately_output_references();
+ if (need_syncing) {
+ fprintf(outfp, ".lf %d %s\n", current_lineno, current_filename);
+ need_syncing = 0;
+ }
+}
+
+static void split_punct(string &line, string &punct)
+{
+ const char *start = line.contents();
+ const char *end = start + line.length();
+ const char *ptr = start;
+ const char *last_token_start = 0;
+ for (;;) {
+ if (ptr >= end)
+ break;
+ last_token_start = ptr;
+ if (*ptr == PRE_LABEL_MARKER || *ptr == POST_LABEL_MARKER
+ || (*ptr >= LABEL_MARKER && *ptr < LABEL_MARKER + N_LABEL_TYPES))
+ ptr++;
+ else if (!get_token(&ptr, end))
+ break;
+ }
+ if (last_token_start) {
+ const token_info *ti = lookup_token(last_token_start, end);
+ if (ti->is_punct()) {
+ punct.append(last_token_start, end - last_token_start);
+ line.set_length(last_token_start - start);
+ }
+ }
+}
+
+static void divert_to_temporary_file()
+{
+ outfp = xtmpfile();
+}
+
+static void store_citation(reference *ref)
+{
+ if (ncitations >= citation_max) {
+ if (citation == 0)
+ citation = new reference*[citation_max = 100];
+ else {
+ reference **old_citation = citation;
+ citation_max *= 2;
+ citation = new reference *[citation_max];
+ memcpy(citation, old_citation, ncitations*sizeof(reference *));
+ a_delete old_citation;
+ }
+ }
+ citation[ncitations++] = ref;
+}
+
+static unsigned store_reference(const string &str)
+{
+ if (reference_hash_table == 0) {
+ reference_hash_table = new reference *[17];
+ hash_table_size = 17;
+ for (int i = 0; i < hash_table_size; i++)
+ reference_hash_table[i] = 0;
+ }
+ unsigned flags;
+ reference *ref = make_reference(str, &flags);
+ ref->compute_hash_code();
+ unsigned h = ref->hash();
+ for (reference **ptr = reference_hash_table + (h % hash_table_size);
+ *ptr != 0;
+ ((ptr == reference_hash_table)
+ ? (ptr = reference_hash_table + hash_table_size - 1)
+ : --ptr))
+ if (same_reference(**ptr, *ref))
+ break;
+ if (*ptr != 0) {
+ if (ref->is_merged())
+ warning("fields ignored because reference already used");
+ delete ref;
+ ref = *ptr;
+ }
+ else {
+ *ptr = ref;
+ ref->set_number(nreferences);
+ nreferences++;
+ ref->pre_compute_label();
+ ref->compute_sort_key();
+ if (nreferences*2 >= hash_table_size) {
+ // Rehash it.
+ reference **old_table = reference_hash_table;
+ int old_size = hash_table_size;
+ hash_table_size = next_size(hash_table_size);
+ reference_hash_table = new reference*[hash_table_size];
+ int i;
+ for (i = 0; i < hash_table_size; i++)
+ reference_hash_table[i] = 0;
+ for (i = 0; i < old_size; i++)
+ if (old_table[i]) {
+ for (reference **p = (reference_hash_table
+ + (old_table[i]->hash() % hash_table_size));
+ *p;
+ ((p == reference_hash_table)
+ ? (p = reference_hash_table + hash_table_size - 1)
+ : --p))
+ ;
+ *p = old_table[i];
+ }
+ a_delete old_table;
+ }
+ }
+ if (label_in_text)
+ store_citation(ref);
+ return flags;
+}
+
+unsigned immediately_handle_reference(const string &str)
+{
+ unsigned flags;
+ reference *ref = make_reference(str, &flags);
+ ref->set_number(nreferences);
+ if (label_in_text || label_in_reference) {
+ ref->pre_compute_label();
+ ref->immediate_compute_label();
+ }
+ nreferences++;
+ store_citation(ref);
+ return flags;
+}
+
+static void immediately_output_references()
+{
+ for (int i = 0; i < ncitations; i++) {
+ reference *ref = citation[i];
+ if (label_in_reference) {
+ fputs(".ds [F ", outfp);
+ const string &label = ref->get_label(NORMAL_LABEL);
+ if (label.length() > 0
+ && (label[0] == ' ' || label[0] == '\\' || label[0] == '"'))
+ putc('"', outfp);
+ put_string(label, outfp);
+ putc('\n', outfp);
+ }
+ ref->output(outfp);
+ delete ref;
+ }
+ ncitations = 0;
+}
+
+static void output_citation_group(reference **v, int n, label_type type,
+ FILE *fp)
+{
+ if (sort_adjacent_labels) {
+ // Do an insertion sort. Usually n will be very small.
+ for (int i = 1; i < n; i++) {
+ int num = v[i]->get_number();
+ reference *temp = v[i];
+ for (int j = i - 1; j >= 0 && v[j]->get_number() > num; j--)
+ v[j + 1] = v[j];
+ v[j + 1] = temp;
+ }
+ }
+ // This messes up if !accumulate.
+ if (accumulate && n > 1) {
+ // remove duplicates
+ int j = 1;
+ for (int i = 1; i < n; i++)
+ if (v[i]->get_label(type) != v[i - 1]->get_label(type))
+ v[j++] = v[i];
+ n = j;
+ }
+ string merged_label;
+ for (int i = 0; i < n; i++) {
+ int nmerged = v[i]->merge_labels(v + i + 1, n - i - 1, type, merged_label);
+ if (nmerged > 0) {
+ put_string(merged_label, fp);
+ i += nmerged;
+ }
+ else
+ put_string(v[i]->get_label(type), fp);
+ if (i < n - 1)
+ put_string(sep_label, fp);
+ }
+}
+
+
+label_processing_state::label_processing_state(reference **p, int n, FILE *f)
+: state(NORMAL), count(0), rptr(p), rcount(n), fp(f)
+{
+}
+
+label_processing_state::~label_processing_state()
+{
+ int handled = handle_pending(EOF);
+ assert(!handled);
+ assert(rcount == 0);
+}
+
+int label_processing_state::handle_pending(int c)
+{
+ switch (state) {
+ case NORMAL:
+ break;
+ case PENDING_LABEL:
+ if (c == POST_LABEL_MARKER) {
+ state = PENDING_LABEL_POST;
+ return 1;
+ }
+ else {
+ output_citation_group(rptr, count, type, fp);
+ rptr += count ;
+ rcount -= count;
+ state = NORMAL;
+ }
+ break;
+ case PENDING_LABEL_POST:
+ if (c == PRE_LABEL_MARKER) {
+ state = PENDING_LABEL_POST_PRE;
+ return 1;
+ }
+ else {
+ output_citation_group(rptr, count, type, fp);
+ rptr += count;
+ rcount -= count;
+ put_string(post_label, fp);
+ state = NORMAL;
+ }
+ break;
+ case PENDING_LABEL_POST_PRE:
+ if (c >= LABEL_MARKER
+ && c < LABEL_MARKER + N_LABEL_TYPES
+ && c - LABEL_MARKER == type) {
+ count += 1;
+ state = PENDING_LABEL;
+ return 1;
+ }
+ else {
+ output_citation_group(rptr, count, type, fp);
+ rptr += count;
+ rcount -= count;
+ put_string(sep_label, fp);
+ state = NORMAL;
+ }
+ break;
+ case PENDING_POST:
+ if (c == PRE_LABEL_MARKER) {
+ put_string(sep_label, fp);
+ state = NORMAL;
+ return 1;
+ }
+ else {
+ put_string(post_label, fp);
+ state = NORMAL;
+ }
+ break;
+ }
+ return 0;
+}
+
+void label_processing_state::process(int c)
+{
+ if (handle_pending(c))
+ return;
+ assert(state == NORMAL);
+ switch (c) {
+ case PRE_LABEL_MARKER:
+ put_string(pre_label, fp);
+ state = NORMAL;
+ break;
+ case POST_LABEL_MARKER:
+ state = PENDING_POST;
+ break;
+ case LABEL_MARKER:
+ case LABEL_MARKER + 1:
+ count = 1;
+ state = PENDING_LABEL;
+ type = label_type(c - LABEL_MARKER);
+ break;
+ default:
+ state = NORMAL;
+ putc(c, fp);
+ break;
+ }
+}
+
+extern "C" {
+
+static int rcompare(const void *p1, const void *p2)
+{
+ return compare_reference(**(reference **)p1, **(reference **)p2);
+}
+
+}
+
+void output_references()
+{
+ assert(accumulate);
+ if (nreferences > 0) {
+ int j = 0;
+ int i;
+ for (i = 0; i < hash_table_size; i++)
+ if (reference_hash_table[i] != 0)
+ reference_hash_table[j++] = reference_hash_table[i];
+ assert(j == nreferences);
+ for (; j < hash_table_size; j++)
+ reference_hash_table[j] = 0;
+ qsort(reference_hash_table, nreferences, sizeof(reference*), rcompare);
+ for (i = 0; i < nreferences; i++)
+ reference_hash_table[i]->set_number(i);
+ compute_labels(reference_hash_table, nreferences);
+ }
+ if (outfp != stdout) {
+ rewind(outfp);
+ {
+ label_processing_state state(citation, ncitations, stdout);
+ int c;
+ while ((c = getc(outfp)) != EOF)
+ state.process(c);
+ }
+ ncitations = 0;
+ fclose(outfp);
+ outfp = stdout;
+ }
+ if (nreferences > 0) {
+ fputs(".]<\n", outfp);
+ for (int i = 0; i < nreferences; i++) {
+ if (sort_fields.length() > 0)
+ reference_hash_table[i]->print_sort_key_comment(outfp);
+ if (label_in_reference) {
+ fputs(".ds [F ", outfp);
+ const string &label = reference_hash_table[i]->get_label(NORMAL_LABEL);
+ if (label.length() > 0
+ && (label[0] == ' ' || label[0] == '\\' || label[0] == '"'))
+ putc('"', outfp);
+ put_string(label, outfp);
+ putc('\n', outfp);
+ }
+ reference_hash_table[i]->output(outfp);
+ delete reference_hash_table[i];
+ reference_hash_table[i] = 0;
+ }
+ fputs(".]>\n", outfp);
+ nreferences = 0;
+ }
+ clear_labels();
+}
+
+static reference *find_reference(const char *query, int query_len)
+{
+ // This is so that error messages look better.
+ while (query_len > 0 && csspace(query[query_len - 1]))
+ query_len--;
+ string str;
+ for (int i = 0; i < query_len; i++)
+ str += query[i] == '\n' ? ' ' : query[i];
+ str += '\0';
+ possibly_load_default_database();
+ search_list_iterator iter(&database_list, str.contents());
+ reference_id rid;
+ const char *start;
+ int len;
+ if (!iter.next(&start, &len, &rid)) {
+ error("no matches for `%1'", str.contents());
+ return 0;
+ }
+ const char *end = start + len;
+ while (start < end) {
+ if (*start == '%')
+ break;
+ while (start < end && *start++ != '\n')
+ ;
+ }
+ if (start >= end) {
+ error("found a reference for `%1' but it didn't contain any fields",
+ str.contents());
+ return 0;
+ }
+ reference *result = new reference(start, end - start, &rid);
+ if (iter.next(&start, &len, &rid))
+ warning("multiple matches for `%1'", str.contents());
+ return result;
+}
+
+static reference *make_reference(const string &str, unsigned *flagsp)
+{
+ const char *start = str.contents();
+ const char *end = start + str.length();
+ const char *ptr = start;
+ while (ptr < end) {
+ if (*ptr == '%')
+ break;
+ while (ptr < end && *ptr++ != '\n')
+ ;
+ }
+ *flagsp = 0;
+ for (; start < ptr; start++) {
+ if (*start == '#')
+ *flagsp = (SHORT_LABEL | (*flagsp & (FORCE_RIGHT_BRACKET
+ | FORCE_LEFT_BRACKET)));
+ else if (*start == '[')
+ *flagsp |= FORCE_LEFT_BRACKET;
+ else if (*start == ']')
+ *flagsp |= FORCE_RIGHT_BRACKET;
+ else if (!csspace(*start))
+ break;
+ }
+ if (start >= end) {
+ error("empty reference");
+ return new reference;
+ }
+ reference *database_ref = 0;
+ if (start < ptr)
+ database_ref = find_reference(start, ptr - start);
+ reference *inline_ref = 0;
+ if (ptr < end)
+ inline_ref = new reference(ptr, end - ptr);
+ if (inline_ref) {
+ if (database_ref) {
+ database_ref->merge(*inline_ref);
+ delete inline_ref;
+ return database_ref;
+ }
+ else
+ return inline_ref;
+ }
+ else if (database_ref)
+ return database_ref;
+ else
+ return new reference;
+}
+
+static void do_ref(const string &str)
+{
+ if (accumulate)
+ (void)store_reference(str);
+ else {
+ (void)immediately_handle_reference(str);
+ immediately_output_references();
+ }
+}
+
+static void trim_blanks(string &str)
+{
+ const char *start = str.contents();
+ const char *end = start + str.length();
+ while (end > start && end[-1] != '\n' && csspace(end[-1]))
+ --end;
+ str.set_length(end - start);
+}
+
+void do_bib(const char *filename)
+{
+ FILE *fp;
+ if (strcmp(filename, "-") == 0)
+ fp = stdin;
+ else {
+ errno = 0;
+ fp = fopen(filename, "r");
+ if (fp == 0) {
+ error("can't open `%1': %2", filename, strerror(errno));
+ return;
+ }
+ current_filename = filename;
+ }
+ enum {
+ START, MIDDLE, BODY, BODY_START, BODY_BLANK, BODY_DOT
+ } state = START;
+ string body;
+ for (;;) {
+ int c = getc(fp);
+ if (c == EOF)
+ break;
+ if (illegal_input_char(c)) {
+ error("illegal input character code %1", c);
+ continue;
+ }
+ switch (state) {
+ case START:
+ if (c == '%') {
+ body = c;
+ state = BODY;
+ }
+ else if (c != '\n')
+ state = MIDDLE;
+ break;
+ case MIDDLE:
+ if (c == '\n')
+ state = START;
+ break;
+ case BODY:
+ body += c;
+ if (c == '\n')
+ state = BODY_START;
+ break;
+ case BODY_START:
+ if (c == '\n') {
+ do_ref(body);
+ state = START;
+ }
+ else if (c == '.')
+ state = BODY_DOT;
+ else if (csspace(c)) {
+ state = BODY_BLANK;
+ body += c;
+ }
+ else {
+ body += c;
+ state = BODY;
+ }
+ break;
+ case BODY_BLANK:
+ if (c == '\n') {
+ trim_blanks(body);
+ do_ref(body);
+ state = START;
+ }
+ else if (csspace(c))
+ body += c;
+ else {
+ body += c;
+ state = BODY;
+ }
+ break;
+ case BODY_DOT:
+ if (c == ']') {
+ do_ref(body);
+ state = MIDDLE;
+ }
+ else {
+ body += '.';
+ body += c;
+ state = c == '\n' ? BODY_START : BODY;
+ }
+ break;
+ default:
+ assert(0);
+ }
+ if (c == '\n')
+ current_lineno++;
+ }
+ switch (state) {
+ case START:
+ case MIDDLE:
+ break;
+ case BODY:
+ body += '\n';
+ do_ref(body);
+ break;
+ case BODY_DOT:
+ case BODY_START:
+ do_ref(body);
+ break;
+ case BODY_BLANK:
+ trim_blanks(body);
+ do_ref(body);
+ break;
+ }
+ fclose(fp);
+}
+
+// from the Dragon Book
+
+unsigned hash_string(const char *s, int len)
+{
+ const char *end = s + len;
+ unsigned h = 0, g;
+ while (s < end) {
+ h <<= 4;
+ h += *s++;
+ if ((g = h & 0xf0000000) != 0) {
+ h ^= g >> 24;
+ h ^= g;
+ }
+ }
+ return h;
+}
+
+int next_size(int n)
+{
+ static const int table_sizes[] = {
+ 101, 503, 1009, 2003, 3001, 4001, 5003, 10007, 20011, 40009,
+ 80021, 160001, 500009, 1000003, 2000003, 4000037, 8000009,
+ 16000057, 32000011, 64000031, 128000003, 0
+ };
+
+ for (const int *p = table_sizes; *p <= n && *p != 0; p++)
+ ;
+ assert(*p != 0);
+ return *p;
+}
+
diff --git a/gnu/usr.bin/groff/refer/refer.h b/gnu/usr.bin/groff/refer/refer.h
new file mode 100644
index 0000000..932b855
--- /dev/null
+++ b/gnu/usr.bin/groff/refer/refer.h
@@ -0,0 +1,78 @@
+// -*- C++ -*-
+/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
+ Written by James Clark (jjc@jclark.com)
+
+This file is part of groff.
+
+groff is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
+
+groff is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License along
+with groff; see the file COPYING. If not, write to the Free Software
+Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <string.h>
+#include <errno.h>
+
+#include "errarg.h"
+#include "error.h"
+#include "lib.h"
+#include "stringclass.h"
+#include "cset.h"
+#include "cmap.h"
+
+#include "defs.h"
+
+unsigned hash_string(const char *, int);
+int next_size(int);
+
+extern string capitalize_fields;
+extern string reverse_fields;
+extern string abbreviate_fields;
+extern string period_before_last_name;
+extern string period_before_initial;
+extern string period_before_hyphen;
+extern string period_before_other;
+extern string sort_fields;
+extern int annotation_field;
+extern string annotation_macro;
+extern string discard_fields;
+extern string articles;
+extern int abbreviate_label_ranges;
+extern string label_range_indicator;
+extern int date_as_label;
+extern string join_authors_exactly_two;
+extern string join_authors_last_two;
+extern string join_authors_default;
+extern string separate_label_second_parts;
+extern string et_al;
+extern int et_al_min_elide;
+extern int et_al_min_total;
+
+extern int compatible_flag;
+
+extern int set_label_spec(const char *);
+extern int set_date_label_spec(const char *);
+extern int set_short_label_spec(const char *);
+
+extern int short_label_flag;
+
+void clear_labels();
+void command_error(const char *,
+ const errarg &arg1 = empty_errarg,
+ const errarg &arg2 = empty_errarg,
+ const errarg &arg3 = empty_errarg);
+
+struct reference;
+
+void compute_labels(reference **, int);
diff --git a/gnu/usr.bin/groff/refer/refer.man b/gnu/usr.bin/groff/refer/refer.man
new file mode 100644
index 0000000..ed2f2bd
--- /dev/null
+++ b/gnu/usr.bin/groff/refer/refer.man
@@ -0,0 +1,1282 @@
+.\" -*- nroff -*-
+.de TQ
+.br
+.ns
+.TP \\$1
+..
+.\" Like TP, but if specified indent is more than half
+.\" the current line-length - indent, use the default indent.
+.de Tp
+.ie \\n(.$=0:((0\\$1)*2u>(\\n(.lu-\\n(.iu)) .TP
+.el .TP "\\$1"
+..
+.\" The BSD man macros can't handle " in arguments to font change macros,
+.\" so use \(ts instead of ".
+.tr \(ts"
+.TH @G@REFER @MAN1EXT@ "@MDATE@" "Groff Version @VERSION@"
+.SH NAME
+@g@refer \- preprocess bibliographic references for groff
+.SH SYNOPSIS
+.nr a \n(.j
+.ad l
+.nr i \n(.i
+.in +\w'\fB@g@refer 'u
+.ti \niu
+.B @g@refer
+.de OP
+.ie \\n(.$-1 .RI "[\ \fB\\$1\fP" "\\$2" "\ ]"
+.el .RB "[\ " "\\$1" "\ ]"
+..
+.OP \-benvCPRS
+.OP \-a n
+.OP \-c fields
+.OP \-f n
+.OP \-i fields
+.OP \-k field
+.OP \-l m,n
+.OP \-p filename
+.OP \-s fields
+.OP \-t n
+.OP \-B field.macro
+.RI [\ filename \|.\|.\|.\ ]
+.br
+.ad \na
+.SH DESCRIPTION
+This file documents the GNU version of
+.BR refer ,
+which is part of the groff document formatting system.
+.B refer
+copies the contents of
+.IR filename \|.\|.\|.
+to the standard output,
+except that lines between
+.B .[
+and
+.B .]
+are interpreted as citations,
+and lines between
+.B .R1
+and
+.B .R2
+are interpreted as commands about how citations are to be processed.
+.LP
+Each citation specifies a reference.
+The citation can specify a reference that is contained in
+a bibliographic database by giving a set of keywords
+that only that reference contains.
+Alternatively it can specify a reference by supplying a database
+record in the citation.
+A combination of these alternatives is also possible.
+.LP
+For each citation,
+.B refer
+can produce a mark in the text.
+This mark consists of some label which can be separated from
+the text and from other labels in various ways.
+For each reference it also outputs
+.B groff
+commands that can be used by a macro package to produce a formatted
+reference for each citation.
+The output of
+.B refer
+must therefore be processed using a suitable macro package.
+The
+.B \-ms
+and
+.B \-me
+macros are both suitable.
+The commands to format a citation's reference can be output immediately after
+the citation,
+or the references may be accumulated,
+and the commands output at some later point.
+If the references are accumulated, then multiple citations of the same
+reference will produce a single formatted reference.
+.LP
+The interpretation of lines between
+.B .R1
+and
+.B .R2
+as commands is a new feature of GNU refer.
+Documents making use of this feature can still be processed by
+Unix refer just by adding the lines
+.RS
+.LP
+.nf
+.ft B
+\&.de R1
+\&.ig R2
+\&..
+.ft
+.fi
+.RE
+to the beginning of the document.
+This will cause
+.B troff
+to ignore everything between
+.B .R1
+and
+.BR .R2 .
+The effect of some commands can also be achieved by options.
+These options are supported mainly for compatibility with Unix refer.
+It is usually more convenient to use commands.
+.LP
+.B refer
+generates
+.B .lf
+lines so that filenames and line numbers in messages produced
+by commands that read
+.B refer
+output will be correct;
+it also interprets lines beginning with
+.B .lf
+so that filenames and line numbers in the messages and
+.B .lf
+lines that it produces will be accurate even if the input has been
+preprocessed by a command such as
+.BR @g@soelim (@MAN1EXT@).
+.SH OPTIONS
+.LP
+Most options are equivalent to commands
+(for a description of these commands see the
+.B Commands
+subsection):
+.TP
+.B \-b
+.B
+no-label-in-text; no-label-in-reference
+.TP
+.B \-e
+.B accumulate
+.TP
+.B \-n
+.B no-default-database
+.TP
+.B \-C
+.B compatible
+.TP
+.B \-P
+.B move-punctuation
+.TP
+.B \-S
+.B
+label "(A.n|Q) ', ' (D.y|D)"; bracket-label " (" ) "; "
+.TP
+.BI \-a n
+.B reverse
+.BI A n
+.TP
+.BI \-c fields
+.B capitalize
+.I fields
+.TP
+.BI \-f n
+.B label
+.BI % n
+.TP
+.BI \-i fields
+.B search-ignore
+.I fields
+.TP
+.B \-k
+.B label
+.B L\(ti%a
+.TP
+.BI \-k field
+.B label
+.IB field \(ti%a
+.TP
+.B \-l
+.B label
+.BI A.nD.y%a
+.TP
+.BI \-l m
+.B label
+.BI A.n+ m D.y%a
+.TP
+.BI \-l, n
+.B label
+.BI A.nD.y\- n %a
+.TP
+.BI \-l m , n
+.B label
+.BI A.n+ m D.y\- n %a
+.TP
+.BI \-p filename
+.B database
+.I filename
+.TP
+.BI \-s spec
+.B sort
+.I spec
+.TP
+.BI \-t n
+.B search-truncate
+.I n
+.LP
+These options are equivalent to the following commands with the
+addition that the filenames specified on the command line are
+processed as if they were arguments to the
+.B bibliography
+command instead of in the normal way:
+.TP
+.B \-B
+.B
+annotate X AP; no-label-in-reference
+.TP
+.BI \-B field . macro
+.B annotate
+.I field
+.IB macro ;
+.B no-label-in-reference
+.LP
+The following options have no equivalent commands:
+.TP
+.B \-v
+Print the version number.
+.TP
+.B \-R
+Don't recognize lines beginning with
+.BR .R1 / .R2 .
+.SH USAGE
+.SS Bibliographic databases
+The bibliographic database is a text file consisting of records
+separated by one or more blank lines.
+Within each record fields start with a
+.B %
+at the beginning of a line.
+Each field has a one character name that immediately follows the
+.BR % .
+It is best to use only upper and lower case letters for the names
+of fields.
+The name of the field should be followed by exactly one space,
+and then by the contents of the field.
+Empty fields are ignored.
+The conventional meaning of each field is as follows:
+.TP
+.B A
+The name of an author.
+If the name contains a title such as
+.B Jr.
+at the end,
+it should be separated from the last name by a comma.
+There can be multiple occurrences of the
+.B A
+field.
+The order is significant.
+It is a good idea always to supply an
+.B A
+field or a
+.B Q
+field.
+.TP
+.B B
+For an article that is part of a book, the title of the book
+.TP
+.B C
+The place (city) of publication.
+.TP
+.B D
+The date of publication.
+The year should be specified in full.
+If the month is specified, the name rather than the number of the month
+should be used, but only the first three letters are required.
+It is a good idea always to supply a
+.B D
+field;
+if the date is unknown, a value such as
+.B in press
+or
+.B unknown
+can be used.
+.TP
+.B E
+For an article that is part of a book, the name of an editor of the book.
+Where the work has editors and no authors,
+the names of the editors should be given as
+.B A
+fields and
+.B ,\ (ed)
+or
+.B ,\ (eds)
+should be appended to the last author.
+.TP
+.B G
+US Government ordering number.
+.TP
+.B I
+The publisher (issuer).
+.TP
+.B J
+For an article in a journal, the name of the journal.
+.TP
+.B K
+Keywords to be used for searching.
+.TP
+.B L
+Label.
+.TP
+.B N
+Journal issue number.
+.TP
+.B O
+Other information.
+This is usually printed at the end of the reference.
+.TP
+.B P
+Page number.
+A range of pages can be specified as
+.IB m \- n\fR.
+.TP
+.B Q
+The name of the author, if the author is not a person.
+This will only be used if there are no
+.B A
+fields.
+There can only be one
+.B Q
+field.
+.TP
+.B R
+Technical report number.
+.TP
+.B S
+Series name.
+.TP
+.B T
+Title.
+For an article in a book or journal,
+this should be the title of the article.
+.TP
+.B V
+Volume number of the journal or book.
+.TP
+.B X
+Annotation.
+.LP
+For all fields except
+.B A
+and
+.BR E ,
+if there is more than one occurernce of a particular field in a record,
+only the last such field will be used.
+.LP
+If accent strings are used, they should follow the character to be accented.
+This means that the
+.B AM
+macro must be used with the
+.B \-ms
+macros.
+Accent strings should not be quoted:
+use one
+.B \e
+rather than two.
+.SS Citations
+The format of a citation is
+.RS
+.BI .[ opening-text
+.br
+.I
+flags keywords
+.br
+.I fields
+.br
+.BI .] closing-text
+.RE
+.LP
+The
+.IR opening-text ,
+.IR closing-text
+and
+.I flags
+components are optional.
+Only one of the
+.I keywords
+and
+.I fields
+components need be specified.
+.LP
+The
+.I keywords
+component says to search the bibliographic databases for a reference
+that contains all the words in
+.IR keywords .
+It is an error if more than one reference if found.
+.LP
+The
+.I fields
+components specifies additional fields to replace or supplement
+those specified in the reference.
+When references are being accumulated and the
+.I keywords
+component is non-empty,
+then additional fields should be specified only on the first
+occasion that a particular reference is cited,
+and will apply to all citations of that reference.
+.LP
+The
+.I opening-text
+and
+.I closing-text
+component specifies strings to be used to bracket the label instead
+of the strings specified in the
+.B bracket-label
+command.
+If either of these components is non-empty,
+the strings specified in the
+.B bracket-label
+command will not be used;
+this behaviour can be altered using the
+.B [
+and
+.B ]
+flags.
+Note that leading and trailing spaces are significant for these components.
+.LP
+The
+.I flags
+component is a list of
+non-alphanumeric characters each of which modifies the treatment
+of this particular citation.
+Unix refer will treat these flags as part of the keywords and
+so will ignore them since they are non-alphanumeric.
+The following flags are currently recognized:
+.TP
+.B #
+This says to use the label specified by the
+.B short-label
+command,
+instead of that specified by the
+.B label
+command.
+If no short label has been specified, the normal label will be used.
+Typically the short label is used with author-date labels
+and consists of only the date and possibly a disambiguating letter;
+the
+.B #
+is supposed to be suggestive of a numeric type of label.
+.TP
+.B [
+Precede
+.I opening-text
+with the first string specified in the
+.B bracket-label
+command.
+.TP
+.B ]
+Follow
+.I closing-text
+with the second string specified in the
+.B bracket-label
+command.
+.LP
+One advantages of using the
+.B [
+and
+.B ]
+flags rather than including the brackets in
+.I opening-text
+and
+.I closing-text
+is that
+you can change the style of bracket used in the document just by changing the
+.B bracket-label
+command.
+Another advantage is that sorting and merging of citations
+will not necessarily be inhibited if the flags are used.
+.LP
+If a label is to be inserted into the text,
+it will be attached to the line preceding the
+.B .[
+line.
+If there is no such line, then an extra line will be inserted before the
+.B .[
+line and a warning will be given.
+.LP
+There is no special notation for making a citation to multiple references.
+Just use a sequence of citations, one for each reference.
+Don't put anything between the citations.
+The labels for all the citations will be attached to the line preceding
+the first citation.
+The labels may also be sorted or merged.
+See the description of the
+.B <>
+label expression, and of the
+.B sort-adjacent-labels
+and
+.B abbreviate-label-ranges
+command.
+A label will not be merged if its citation has a non-empty
+.I opening-text
+or
+.IR closing-text .
+However, the labels for a citation using the
+.B ]
+flag and without any
+.I closing-text
+immediately followed by a citation using the
+.B [
+flag and without any
+.I opening-text
+may be sorted and merged
+even though the first citation's
+.I opening-text
+or the second citation's
+.I closing-text
+is non-empty.
+(If you wish to prevent this just make the first citation's
+.I closing-text
+.BR \e& .)
+.SS Commands
+Commands are contained between lines starting with
+.B .R1
+and
+.BR .R2 .
+Recognition of these lines can be prevented by the
+.B \-R
+option.
+When a
+.B .R1
+line is recognized any accumulated references are flushed out.
+Neither
+.B .R1
+nor
+.B .R2
+lines,
+nor anything between them
+is output.
+.LP
+Commands are separated by newlines or
+.BR ; s.
+.B #
+introduces a comment that extends to the end of the line
+(but does not conceal the newline).
+Each command is broken up into words.
+Words are separated by spaces or tabs.
+A word that begins with
+.B \(ts
+extends to the next
+.B \(ts
+that is not followed by another
+.BR \(ts .
+If there is no such
+.B \(ts
+the word extends to the end of the line.
+Pairs of
+.B \(ts
+in a word beginning with
+.B \(ts
+collapse to a single
+.BR \(ts .
+Neither
+.B #
+nor
+.B ;
+are recognized inside
+.BR \(ts s.
+A line can be continued by ending it with
+.BR \e ;
+this works everywhere except after a
+.BR # .
+.LP
+.ds n \fR*
+Each command
+.I name
+that is marked with \*n has an associated negative command
+.BI no- name
+that undoes the effect of
+.IR name .
+For example, the
+.B no-sort
+command specifies that references should not be sorted.
+The negative commands take no arguments.
+.LP
+In the following description each argument must be a single word;
+.I field
+is used for a single upper or lower case letter naming a field;
+.I fields
+is used for a sequence of such letters;
+.I m
+and
+.I n
+are used for a non-negative numbers;
+.I string
+is used for an arbitrary string;
+.I filename
+is used for the name of a file.
+.Tp \w'\fBabbreviate-label-ranges'u+2n
+.BI abbreviate\*n\ fields\ string1\ string2\ string3\ string4
+Abbreviate the first names of
+.IR fields .
+An initial letter will be separated from another initial letter by
+.IR string1 ,
+from the last name by
+.IR string2 ,
+and from anything else
+(such as a
+.B von
+or
+.BR de )
+by
+.IR string3 .
+These default to a period followed by a space.
+In a hyphenated first name,
+the initial of the first part of the name will be separated from the hyphen by
+.IR string4 ;
+this defaults to a period.
+No attempt is made to handle any ambiguities that might
+result from abbreviation.
+Names are abbreviated before sorting and before
+label construction.
+.TP
+.BI abbreviate-label-ranges\*n\ string
+Three or more adjacent labels that refer to consecutive references
+will be abbreviated to a label consisting
+of the first label, followed by
+.I string
+followed by the last label.
+This is mainly useful with numeric labels.
+If
+.I string
+is omitted it defaults to
+.BR \- .
+.TP
+.B accumulate\*n
+Accumulate references instead of writing out each reference
+as it is encountered.
+Accumulated references will be written out whenever a reference
+of the form
+.RS
+.IP
+.B .[
+.br
+.B $LIST$
+.br
+.B .]
+.LP
+is encountered,
+after all input files hve been processed,
+and whenever
+.B .R1
+line is recognized.
+.RE
+.TP
+.BI annotate\*n\ field\ string
+.I field
+is an annotation;
+print it at the end of the reference as a paragraph preceded by the line
+.RS
+.IP
+.BI . string
+.LP
+If
+.I macro
+is omitted it will default to
+.BR AP ;
+if
+.I field
+is also omitted it will default to
+.BR X .
+Only one field can be an annotation.
+.RE
+.TP
+.BI articles\ string \fR\|.\|.\|.
+.IR string \|.\|.\|.
+are definite or indefinite articles, and should be ignored at the beginning of
+.B T
+fields when sorting.
+Initially,
+.BR the ,
+.B a
+and
+.B an
+are recognized as articles.
+.TP
+.BI bibliography\ filename \fR\|.\|.\|.
+Write out all the references contained in the bibliographic databases
+.IR filename \|.\|.\|.
+.TP
+.BI bracket-label\ string1\ string2\ string3
+In the text, bracket each label
+with
+.I string1
+and
+.IR string2 .
+An occurrence of
+.I string2
+immediately followed by
+.I string1
+will be turned into
+.IR string3 .
+The default behaviour is
+.RS
+.IP
+.B
+bracket-label \e*([. \e*(.] ", "
+.RE
+.TP
+.BI capitalize\ fields
+Convert
+.I fields
+to caps and small caps.
+.TP
+.B compatible\*n
+Recognize
+.B .R1
+and
+.B .R2
+even when followed by a character other than space or newline.
+.TP
+.BI database\ filename \fR\|.\|.\|.
+Search the bibliographic databases
+.IR filename \|.\|.\|.
+For each
+.I filename
+if an index
+.IB filename @INDEX_SUFFIX@
+created by
+.BR @g@indxbib (@MAN1EXT@)
+exists, then it will be searched instead;
+each index can cover multiple databases.
+.TP
+.BI date-as-label\*n\ string
+.I string
+is a label expression that specifies a string with which to replace the
+.B D
+field after constructing the label.
+See the
+.B "Label expressions"
+subsection for a description of label expressions.
+This command is useful if you do not want explicit labels in the
+reference list, but instead want to handle any necessary
+disambiguation by qualifying the date in some way.
+The label used in the text would typically be some combination of the
+author and date.
+In most cases you should also use the
+.B no-label-in-reference
+command.
+For example,
+.RS
+.IP
+.B
+date-as-label D.+yD.y%a*D.-y
+.LP
+would attach a disambiguating letter to the year part of the
+.B D
+field in the reference.
+.RE
+.TP
+.B default-database\*n
+The default database should be searched.
+This is the default behaviour, so the negative version of
+this command is more useful.
+refer determines whether the default database should be searched
+on the first occasion that it needs to do a search.
+Thus a
+.B no-default-database
+command must be given before then,
+in order to be effective.
+.TP
+.BI discard\*n\ fields
+When the reference is read,
+.I fields
+should be discarded;
+no string definitions for
+.I fields
+will be output.
+Initially,
+.I fields
+are
+.BR XYZ .
+.TP
+.BI et-al\*n\ string\ m\ n
+Control use of
+.B
+et al
+in the evaluation of
+.B @
+expressions in label expressions.
+If the number of authors needed to make the author sequence
+unambiguous is
+.I u
+and the total number of authors is
+.I t
+then the last
+.IR t \|\-\| u
+authors will be replaced by
+.I string
+provided that
+.IR t \|\-\| u
+is not less than
+.I m
+and
+.I t
+is not less than
+.IR n .
+The default behaviour is
+.RS
+.IP
+.B
+et-al " et al" 2 3
+.RE
+.TP
+.BI include\ filename
+Include
+.I filename
+and interpret the contents as commands.
+.TP
+.BI join-authors\ string1\ string2\ string3
+This says how authors should be joined together.
+When there are exactly two authors, they will be joined with
+.IR string1 .
+When there are more than two authors, all but the last two will
+be joined with
+.IR string2 ,
+and the last two authors will be joined with
+.IR string3 .
+If
+.I string3
+is omitted,
+it will default to
+.IR string1 ;
+if
+.I string2
+is also omitted it will also default to
+.IR string1 .
+For example,
+.RS
+.IP
+.B
+join-authors " and " ", " ", and "
+.LP
+will restore the default method for joining authors.
+.RE
+.TP
+.B label-in-reference\*n
+When outputting the reference,
+define the string
+.B [F
+to be the reference's label.
+This is the default behaviour; so the negative version
+of this command is more useful.
+.TP
+.B label-in-text\*n
+For each reference output a label in the text.
+The label will be separated from the surrounding text as described in the
+.B bracket-label
+command.
+This is the default behaviour; so the negative version
+of this command is more useful.
+.TP
+.BI label\ string
+.I string
+is a label expression describing how to label each reference.
+.TP
+.BI separate-label-second-parts\ string
+When merging two-part labels, separate the second part of the second
+label from the first label with
+.IR string .
+See the description of the
+.B <>
+label expression.
+.TP
+.B move-punctuation\*n
+In the text, move any punctuation at the end of line past the label.
+It is usually a good idea to give this command unless you are using
+superscripted numbers as labels.
+.TP
+.BI reverse\*n\ string
+Reverse the fields whose names
+are in
+.IR string .
+Each field name can be followed by a number which says
+how many such fields should be reversed.
+If no number is given for a field, all such fields will be reversed.
+.TP
+.BI search-ignore\*n\ fields
+While searching for keys in databases for which no index exists,
+ignore the contents of
+.IR fields .
+Initially, fields
+.B XYZ
+are ignored.
+.TP
+.BI search-truncate\*n\ n
+Only require the first
+.I n
+characters of keys to be given.
+In effect when searching for a given key
+words in the database are truncated to the maximum of
+.I n
+and the length of the key.
+Initially
+.I n
+is 6.
+.TP
+.BI short-label\*n\ string
+.I string
+is a label expression that specifies an alternative (usually shorter)
+style of label.
+This is used when the
+.B #
+flag is given in the citation.
+When using author-date style labels, the identity of the author
+or authors is sometimes clear from the context, and so it
+may be desirable to omit the author or authors from the label.
+The
+.B short-label
+command will typically be used to specify a label containing just
+a date and possibly a disambiguating letter.
+.TP
+.BI sort\*n\ string
+Sort references according to
+.BR string .
+References will automatically be accumulated.
+.I string
+should be a list of field names, each followed by a number,
+indicating how many fields with the name should be used for sorting.
+.B +
+can be used to indicate that all the fields with the name should be used.
+Also
+.B .
+can be used to indicate the references should be sorted using the
+(tentative) label.
+(The
+.B
+Label expressions
+subsection describes the concept of a tentative label.)
+.TP
+.B sort-adjacent-labels\*n
+Sort labels that are adjacent in the text according to their
+position in the reference list.
+This command should usually be given if the
+.B abbreviate-label-ranges
+command has been given,
+or if the label expression contains a
+.B <>
+expression.
+This will have no effect unless references are being accumulated.
+.SS Label expressions
+.LP
+Label expressions can be evaluated both normally and tentatively.
+The result of normal evaluation is used for output.
+The result of tentative evaluation, called the
+.I
+tentative label,
+is used to gather the information
+that normal evaluation needs to disambiguate the label.
+Label expressions specified by the
+.B date-as-label
+and
+.B short-label
+commands are not evaluated tentatively.
+Normal and tentative evaluation are the same for all types
+of expression other than
+.BR @ ,
+.BR * ,
+and
+.B %
+expressions.
+The description below applies to normal evaluation,
+except where otherwise specified.
+.TP
+.I field
+.TQ
+.I field\ n
+The
+.IR n -th
+part of
+.IR field .
+If
+.I n
+is omitted, it defaults to 1.
+.TP
+.BI ' string '
+The characters in
+.I string
+literally.
+.TP
+.B @
+All the authors joined as specified by the
+.B join-authors
+command.
+The whole of each author's name will be used.
+However, if the references are sorted by author
+(that is the sort specification starts with
+.BR A+ ),
+then authors' last names will be used instead, provided that this does
+not introduce ambiguity,
+and also an initial subsequence of the authors may be used
+instead of all the authors, again provided that this does not
+introduce ambiguity.
+The use of only the last name for the
+.IR i -th
+author of some reference
+is considered to be ambiguous if
+there is some other reference,
+such that the first
+.IR i \|-\|1
+authors of the references are the same,
+the
+.IR i -th
+authors are not the same,
+but the
+.IR i -th
+authors' last names are the same.
+A proper initial subsequence of the sequence
+of authors for some reference is considered to be ambiguous if there is
+a reference with some other sequence of authors which also has
+that subsequence as a proper initial subsequence.
+When an initial subsequence of authors is used, the remaining
+authors are replaced by the string specified by the
+.B et-al
+command;
+this command may also specify additional requirements that must be
+met before an initial subsequence can be used.
+.B @
+tentatively evaluates to a canonical representation of the authors,
+such that authors that compare equally for sorting purpose
+will have the same representation.
+.TP
+.BI % n
+.TQ
+.B %a
+.TQ
+.B %A
+.TQ
+.B %i
+.TQ
+.B %I
+The serial number of the reference formatted according to the character
+following the
+.BR % .
+The serial number of a reference is 1 plus the number of earlier references
+with same tentative label as this reference.
+These expressions tentatively evaluate to an empty string.
+.TP
+.IB expr *
+If there is another reference with the same tentative label as
+this reference, then
+.IR expr ,
+otherwise an empty string.
+It tentatively evaluates to an empty string.
+.TP
+.IB expr + n
+.TQ
+.IB expr \- n
+The first
+.RB ( + )
+or last
+.RB ( \- )
+.I n
+upper or lower case letters or digits of
+.IR expr .
+Troff special characters (such as
+.BR \e('a )
+count as a single letter.
+Accent strings are retained but do not count towards the total.
+.TP
+.IB expr .l
+.I expr
+converted to lowercase.
+.TP
+.IB expr .u
+.I expr
+converted to uppercase.
+.TP
+.IB expr .c
+.I expr
+converted to caps and small caps.
+.TP
+.IB expr .r
+.I expr
+reversed so that the last name is first.
+.TP
+.IB expr .a
+.I expr
+with first names abbreviated.
+Note that fields specified in the
+.B abbreviate
+command are abbreviated before any labels are evaluated.
+Thus
+.B .a
+is useful only when you want a field to be abbreviated in a label
+but not in a reference.
+.TP
+.IB expr .y
+The year part of
+.IR expr .
+.TP
+.IB expr .+y
+The part of
+.I expr
+before the year, or the whole of
+.I expr
+if it does not contain a year.
+.TP
+.IB expr .\-y
+The part of
+.I expr
+after the year, or an empty string if
+.I expr
+does not contain a year.
+.TP
+.IB expr .n
+The last name part of
+.IR expr .
+.TP
+.IB expr1 \(ti expr2
+.I expr1
+except that if the last character of
+.I expr1
+is
+.B \-
+then it will be replaced by
+.IR expr2 .
+.TP
+.I expr1\ expr2
+The concatenation of
+.I expr1
+and
+.IR expr2 .
+.TP
+.IB expr1 | expr2
+If
+.I expr1
+is non-empty then
+.I expr1
+otherwise
+.IR expr2 .
+.TP
+.IB expr1 & expr2
+If
+.I expr1
+is non-empty
+then
+.I expr2
+otherwise an empty string.
+.TP
+.IB expr1 ? expr2 : expr3
+If
+.I expr1
+is non-empty
+then
+.I expr2
+otherwise
+.IR expr3 .
+.TP
+.BI < expr >
+The label is in two parts, which are separated by
+.IR expr .
+Two adjacent two-part labels which have the same first part will be
+merged by appending the second part of the second label onto the first
+label separated by the string specified in the
+.B separate-label-second-parts
+command (initially, a comma followed by a space); the resulting label
+will also be a two-part label with the same first part as before
+merging, and so additional labels can be merged into it.
+Note that it is permissible for the first part to be empty;
+this maybe desirable for expressions used in the
+.B short-label
+command.
+.TP
+.BI ( expr )
+The same as
+.IR expr .
+Used for grouping.
+.LP
+The above expressions are listed in order of precedence
+(highest first);
+.B &
+and
+.B |
+have the same precedence.
+.SS Macro interface
+Each reference starts with a call to the macro
+.BR ]- .
+The string
+.B [F
+will be defined to be the label for this reference,
+unless the
+.B no-label-in-reference
+command has been given.
+There then follows a series of string definitions,
+one for each field:
+string
+.BI [ X
+corresponds to field
+.IR X .
+The number register
+.B [P
+is set to 1 if the
+.B P
+field contains a range of pages.
+The
+.BR [T ,
+.B [A
+and
+.B [O
+number registers are set to 1 according as the
+.BR T ,
+.B A
+and
+.B O
+fields end with one of the characters
+.BR .?! .
+The
+.B [E
+number register will be set to 1 if the
+.B [E
+string contains more than one name.
+The reference is followed by a call to the
+.B ][
+macro.
+The first argument to this macro gives a number representing
+the type of the reference.
+If a reference contains a
+.B J
+field, it will be classified as type 1,
+otherwise if it contains a
+.B B
+field, it will type 3,
+otherwise if it contains a
+.B G
+or
+.B R
+field it will be type 4,
+otherwise if contains a
+.B I
+field it will be type 2,
+otherwise it will be type 0.
+The second argument is a symbolic name for the type:
+.BR other ,
+.BR journal-article ,
+.BR book ,
+.B article-in-book
+or
+.BR tech-report .
+Groups of references that have been accumulated
+or are produced by the
+.B bibliography
+command are preceded by a call to the
+.B ]<
+macro and followed by a call to the
+.B ]>
+macro.
+.SH FILES
+.Tp \w'\fB@DEFAULT_INDEX@'u+2n
+.B @DEFAULT_INDEX@
+Default database.
+.TP
+.IB file @INDEX_SUFFIX@
+Index files.
+.SH "SEE ALSO"
+.BR @g@indxbib (@MAN1EXT@),
+.BR @g@lookbib (@MAN1EXT@),
+.BR lkbib (@MAN1EXT@)
+.br
+.SH BUGS
+In label expressions,
+.B <>
+expressions are ignored inside
+.BI . char
+expressions.
diff --git a/gnu/usr.bin/groff/refer/token.cc b/gnu/usr.bin/groff/refer/token.cc
new file mode 100644
index 0000000..1ec7acd
--- /dev/null
+++ b/gnu/usr.bin/groff/refer/token.cc
@@ -0,0 +1,374 @@
+// -*- C++ -*-
+/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
+ Written by James Clark (jjc@jclark.com)
+
+This file is part of groff.
+
+groff is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
+
+groff is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License along
+with groff; see the file COPYING. If not, write to the Free Software
+Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "refer.h"
+#include "token.h"
+
+#define TOKEN_TABLE_SIZE 1009
+// I believe in Icelandic thorn sorts after z.
+#define THORN_SORT_KEY "{"
+
+struct token_table_entry {
+ const char *tok;
+ token_info ti;
+ token_table_entry();
+};
+
+token_table_entry token_table[TOKEN_TABLE_SIZE];
+int ntokens = 0;
+
+static void skip_name(const char **ptr, const char *end)
+{
+ if (*ptr < end) {
+ switch (*(*ptr)++) {
+ case '(':
+ if (*ptr < end) {
+ *ptr += 1;
+ if (*ptr < end)
+ *ptr += 1;
+ }
+ break;
+ case '[':
+ while (*ptr < end)
+ if (*(*ptr)++ == ']')
+ break;
+ break;
+ }
+ }
+}
+
+int get_token(const char **ptr, const char *end)
+{
+ if (*ptr >= end)
+ return 0;
+ char c = *(*ptr)++;
+ if (c == '\\' && *ptr < end) {
+ switch (**ptr) {
+ default:
+ *ptr += 1;
+ break;
+ case '(':
+ case '[':
+ skip_name(ptr, end);
+ break;
+ case '*':
+ case 'f':
+ *ptr += 1;
+ skip_name(ptr, end);
+ break;
+ }
+ }
+ return 1;
+}
+
+token_info::token_info()
+: type(TOKEN_OTHER), sort_key(0), other_case(0)
+{
+}
+
+void token_info::set(token_type t, const char *sk, const char *oc)
+{
+ assert(oc == 0 || t == TOKEN_UPPER || t == TOKEN_LOWER);
+ type = t;
+ sort_key = sk;
+ other_case = oc;
+}
+
+void token_info::sortify(const char *start, const char *end, string &result)
+ const
+{
+ if (sort_key)
+ result += sort_key;
+ else if (type == TOKEN_UPPER || type == TOKEN_LOWER) {
+ for (; start < end; start++)
+ if (csalpha(*start))
+ result += cmlower(*start);
+ }
+}
+
+int token_info::sortify_non_empty(const char *start, const char *end) const
+{
+ if (sort_key)
+ return *sort_key != '\0';
+ if (type != TOKEN_UPPER && type != TOKEN_LOWER)
+ return 0;
+ for (; start < end; start++)
+ if (csalpha(*start))
+ return 1;
+ return 0;
+}
+
+
+void token_info::lower_case(const char *start, const char *end,
+ string &result) const
+{
+ if (type != TOKEN_UPPER) {
+ while (start < end)
+ result += *start++;
+ }
+ else if (other_case)
+ result += other_case;
+ else {
+ while (start < end)
+ result += cmlower(*start++);
+ }
+}
+
+void token_info::upper_case(const char *start, const char *end,
+ string &result) const
+{
+ if (type != TOKEN_LOWER) {
+ while (start < end)
+ result += *start++;
+ }
+ else if (other_case)
+ result += other_case;
+ else {
+ while (start < end)
+ result += cmupper(*start++);
+ }
+}
+
+token_table_entry::token_table_entry()
+: tok(0)
+{
+}
+
+static void store_token(const char *tok, token_type typ,
+ const char *sk = 0, const char *oc = 0)
+{
+ unsigned n = hash_string(tok, strlen(tok)) % TOKEN_TABLE_SIZE;
+ for (;;) {
+ if (token_table[n].tok == 0) {
+ if (++ntokens == TOKEN_TABLE_SIZE)
+ assert(0);
+ token_table[n].tok = tok;
+ break;
+ }
+ if (strcmp(tok, token_table[n].tok) == 0)
+ break;
+ if (n == 0)
+ n = TOKEN_TABLE_SIZE - 1;
+ else
+ --n;
+ }
+ token_table[n].ti.set(typ, sk, oc);
+}
+
+
+token_info default_token_info;
+
+const token_info *lookup_token(const char *start, const char *end)
+{
+ unsigned n = hash_string(start, end - start) % TOKEN_TABLE_SIZE;
+ for (;;) {
+ if (token_table[n].tok == 0)
+ break;
+ if (strlen(token_table[n].tok) == end - start
+ && memcmp(token_table[n].tok, start, end - start) == 0)
+ return &(token_table[n].ti);
+ if (n == 0)
+ n = TOKEN_TABLE_SIZE - 1;
+ else
+ --n;
+ }
+ return &default_token_info;
+}
+
+static void init_ascii()
+{
+ for (const char *p = "abcdefghijklmnopqrstuvwxyz"; *p; p++) {
+ char buf[2];
+ buf[0] = *p;
+ buf[1] = '\0';
+ store_token(strsave(buf), TOKEN_LOWER);
+ buf[0] = cmupper(buf[0]);
+ store_token(strsave(buf), TOKEN_UPPER);
+ }
+ for (p = "0123456789"; *p; p++) {
+ char buf[2];
+ buf[0] = *p;
+ buf[1] = '\0';
+ const char *s = strsave(buf);
+ store_token(s, TOKEN_OTHER, s);
+ }
+ for (p = ".,:;?!"; *p; p++) {
+ char buf[2];
+ buf[0] = *p;
+ buf[1] = '\0';
+ store_token(strsave(buf), TOKEN_PUNCT);
+ }
+ store_token("-", TOKEN_HYPHEN);
+}
+
+static void store_letter(const char *lower, const char *upper,
+ const char *sort_key = 0)
+{
+ store_token(lower, TOKEN_LOWER, sort_key, upper);
+ store_token(upper, TOKEN_UPPER, sort_key, lower);
+}
+
+static void init_letter(unsigned char uc_code, unsigned char lc_code,
+ const char *sort_key)
+{
+ char lbuf[2];
+ lbuf[0] = lc_code;
+ lbuf[1] = 0;
+ char ubuf[2];
+ ubuf[0] = uc_code;
+ ubuf[1] = 0;
+ store_letter(strsave(lbuf), strsave(ubuf), sort_key);
+}
+
+static void init_latin1()
+{
+ init_letter(0xc0, 0xe0, "a");
+ init_letter(0xc1, 0xe1, "a");
+ init_letter(0xc2, 0xe2, "a");
+ init_letter(0xc3, 0xe3, "a");
+ init_letter(0xc4, 0xe4, "a");
+ init_letter(0xc5, 0xe5, "a");
+ init_letter(0xc6, 0xe6, "ae");
+ init_letter(0xc7, 0xe7, "c");
+ init_letter(0xc8, 0xe8, "e");
+ init_letter(0xc9, 0xe9, "e");
+ init_letter(0xca, 0xea, "e");
+ init_letter(0xcb, 0xeb, "e");
+ init_letter(0xcc, 0xec, "i");
+ init_letter(0xcd, 0xed, "i");
+ init_letter(0xce, 0xee, "i");
+ init_letter(0xcf, 0xef, "i");
+
+ init_letter(0xd0, 0xf0, "d");
+ init_letter(0xd1, 0xf1, "n");
+ init_letter(0xd2, 0xf2, "o");
+ init_letter(0xd3, 0xf3, "o");
+ init_letter(0xd4, 0xf4, "o");
+ init_letter(0xd5, 0xf5, "o");
+ init_letter(0xd6, 0xf6, "o");
+ init_letter(0xd8, 0xf8, "o");
+ init_letter(0xd9, 0xf9, "u");
+ init_letter(0xda, 0xfa, "u");
+ init_letter(0xdb, 0xfb, "u");
+ init_letter(0xdc, 0xfc, "u");
+ init_letter(0xdd, 0xfd, "y");
+ init_letter(0xde, 0xfe, THORN_SORT_KEY);
+
+ store_token("\337", TOKEN_LOWER, "ss", "SS");
+ store_token("\377", TOKEN_LOWER, "y", "Y");
+}
+
+static void init_two_char_letter(char l1, char l2, char u1, char u2,
+ const char *sk = 0)
+{
+ char buf[6];
+ buf[0] = '\\';
+ buf[1] = '(';
+ buf[2] = l1;
+ buf[3] = l2;
+ buf[4] = '\0';
+ const char *p = strsave(buf);
+ buf[2] = u1;
+ buf[3] = u2;
+ store_letter(p, strsave(buf), sk);
+ buf[1] = '[';
+ buf[4] = ']';
+ buf[5] = '\0';
+ p = strsave(buf);
+ buf[2] = l1;
+ buf[3] = l2;
+ store_letter(strsave(buf), p, sk);
+
+}
+
+static void init_special_chars()
+{
+ for (const char *p = "':^`~"; *p; p++)
+ for (const char *q = "aeiouy"; *q; q++) {
+ // Use a variable to work around bug in gcc 2.0
+ char c = cmupper(*q);
+ init_two_char_letter(*p, *q, *p, c);
+ }
+ for (p = "/l/o~n,coeaeij"; *p; p += 2) {
+ // Use variables to work around bug in gcc 2.0
+ char c0 = cmupper(p[0]);
+ char c1 = cmupper(p[1]);
+ init_two_char_letter(p[0], p[1], c0, c1);
+ }
+ init_two_char_letter('v', 's', 'v', 'S', "s");
+ init_two_char_letter('v', 'z', 'v', 'Z', "z");
+ init_two_char_letter('o', 'a', 'o', 'A', "a");
+ init_two_char_letter('T', 'p', 'T', 'P', THORN_SORT_KEY);
+ init_two_char_letter('-', 'd', '-', 'D');
+
+ store_token("\\(ss", TOKEN_LOWER, 0, "SS");
+ store_token("\\[ss]", TOKEN_LOWER, 0, "SS");
+
+ store_token("\\(Sd", TOKEN_LOWER, "d", "\\(-D");
+ store_token("\\[Sd]", TOKEN_LOWER, "d", "\\[-D]");
+ store_token("\\(hy", TOKEN_HYPHEN);
+ store_token("\\[hy]", TOKEN_HYPHEN);
+}
+
+static void init_strings()
+{
+ char buf[6];
+ buf[0] = '\\';
+ buf[1] = '*';
+ for (const char *p = "'`^^,:~v_o./;"; *p; p++) {
+ buf[2] = *p;
+ buf[3] = '\0';
+ store_token(strsave(buf), TOKEN_ACCENT);
+ buf[2] = '[';
+ buf[3] = *p;
+ buf[4] = ']';
+ buf[5] = '\0';
+ store_token(strsave(buf), TOKEN_ACCENT);
+ }
+
+ // -ms special letters
+ store_letter("\\*(th", "\\*(Th", THORN_SORT_KEY);
+ store_letter("\\*[th]", "\\*[Th]", THORN_SORT_KEY);
+ store_letter("\\*(d-", "\\*(D-");
+ store_letter("\\*[d-]", "\\*[D-]");
+ store_letter("\\*(ae", "\\*(Ae", "ae");
+ store_letter("\\*[ae]", "\\*[Ae]", "ae");
+ store_letter("\\*(oe", "\\*(Oe", "oe");
+ store_letter("\\*[oe]", "\\*[Oe]", "oe");
+
+ store_token("\\*3", TOKEN_LOWER, "y", "Y");
+ store_token("\\*8", TOKEN_LOWER, "ss", "SS");
+ store_token("\\*q", TOKEN_LOWER, "o", "O");
+}
+
+struct token_initer {
+ token_initer();
+};
+
+static token_initer the_token_initer;
+
+token_initer::token_initer()
+{
+ init_ascii();
+ init_latin1();
+ init_special_chars();
+ init_strings();
+ default_token_info.set(TOKEN_OTHER);
+}
diff --git a/gnu/usr.bin/groff/refer/token.h b/gnu/usr.bin/groff/refer/token.h
new file mode 100644
index 0000000..c6445d2
--- /dev/null
+++ b/gnu/usr.bin/groff/refer/token.h
@@ -0,0 +1,81 @@
+// -*- C++ -*-
+/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
+ Written by James Clark (jjc@jclark.com)
+
+This file is part of groff.
+
+groff is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
+
+groff is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License along
+with groff; see the file COPYING. If not, write to the Free Software
+Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+enum token_type {
+ TOKEN_OTHER,
+ TOKEN_UPPER,
+ TOKEN_LOWER,
+ TOKEN_ACCENT,
+ TOKEN_PUNCT,
+ TOKEN_HYPHEN
+};
+
+class token_info {
+private:
+ token_type type;
+ const char *sort_key;
+ const char *other_case;
+public:
+ token_info();
+ void set(token_type, const char *sk = 0, const char *oc = 0);
+ void lower_case(const char *start, const char *end, string &result) const;
+ void upper_case(const char *start, const char *end, string &result) const;
+ void sortify(const char *start, const char *end, string &result) const;
+ int sortify_non_empty(const char *start, const char *end) const;
+ int is_upper() const;
+ int is_lower() const;
+ int is_accent() const;
+ int is_other() const;
+ int is_punct() const;
+ int is_hyphen() const;
+};
+
+inline int token_info::is_upper() const
+{
+ return type == TOKEN_UPPER;
+}
+
+inline int token_info::is_lower() const
+{
+ return type == TOKEN_LOWER;
+}
+
+inline int token_info::is_accent() const
+{
+ return type == TOKEN_ACCENT;
+}
+
+inline int token_info::is_other() const
+{
+ return type == TOKEN_OTHER;
+}
+
+inline int token_info::is_punct() const
+{
+ return type == TOKEN_PUNCT;
+}
+
+inline int token_info::is_hyphen() const
+{
+ return type == TOKEN_HYPHEN;
+}
+
+int get_token(const char **ptr, const char *end);
+const token_info *lookup_token(const char *start, const char *end);
diff --git a/gnu/usr.bin/groff/soelim/Makefile.dep b/gnu/usr.bin/groff/soelim/Makefile.dep
new file mode 100644
index 0000000..6cfd475
--- /dev/null
+++ b/gnu/usr.bin/groff/soelim/Makefile.dep
@@ -0,0 +1,2 @@
+soelim.o : soelim.cc ../include/lib.h ../include/errarg.h \
+ ../include/error.h ../include/stringclass.h
diff --git a/gnu/usr.bin/groff/soelim/Makefile.sub b/gnu/usr.bin/groff/soelim/Makefile.sub
new file mode 100644
index 0000000..7c873a6
--- /dev/null
+++ b/gnu/usr.bin/groff/soelim/Makefile.sub
@@ -0,0 +1,6 @@
+PROG=soelim
+MAN1=soelim.n
+XLIBS=$(LIBGROFF)
+OBJS=soelim.o
+CCSRCS=soelim.cc
+NAMEPREFIX=$(g)
diff --git a/gnu/usr.bin/groff/soelim/TODO b/gnu/usr.bin/groff/soelim/TODO
new file mode 100644
index 0000000..f2a3924
--- /dev/null
+++ b/gnu/usr.bin/groff/soelim/TODO
@@ -0,0 +1 @@
+Understand .pso.
diff --git a/gnu/usr.bin/groff/soelim/soelim.cc b/gnu/usr.bin/groff/soelim/soelim.cc
new file mode 100644
index 0000000..405f184
--- /dev/null
+++ b/gnu/usr.bin/groff/soelim/soelim.cc
@@ -0,0 +1,278 @@
+// -*- C++ -*-
+/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
+ Written by James Clark (jjc@jclark.com)
+
+This file is part of groff.
+
+groff is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
+
+groff is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License along
+with groff; see the file COPYING. If not, write to the Free Software
+Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+#include <assert.h>
+#include <stdlib.h>
+#include <errno.h>
+#include "lib.h"
+#include "errarg.h"
+#include "error.h"
+#include "stringclass.h"
+
+int compatible_flag = 0;
+
+extern int interpret_lf_args(const char *);
+
+int do_file(const char *filename);
+
+void usage()
+{
+ fprintf(stderr, "usage: %s [ -vC ] [ files ]\n", program_name);
+ exit(1);
+}
+
+int main(int argc, char **argv)
+{
+ program_name = argv[0];
+ int opt;
+ while ((opt = getopt(argc, argv, "vC")) != EOF)
+ switch (opt) {
+ case 'v':
+ {
+ extern const char *version_string;
+ fprintf(stderr, "GNU soelim version %s\n", version_string);
+ fflush(stderr);
+ break;
+ }
+ case 'C':
+ compatible_flag = 1;
+ break;
+ case '?':
+ usage();
+ break;
+ default:
+ assert(0);
+ }
+ int nbad = 0;
+ if (optind >= argc)
+ nbad += !do_file("-");
+ else
+ for (int i = optind; i < argc; i++)
+ nbad += !do_file(argv[i]);
+ if (ferror(stdout) || fflush(stdout) < 0)
+ fatal("output error");
+ return nbad != 0;
+}
+
+void set_location()
+{
+ printf(".lf %d %s\n", current_lineno, current_filename);
+}
+
+void do_so(const char *line)
+{
+ const char *p = line;
+ while (*p == ' ')
+ p++;
+ string filename;
+ int success = 1;
+ for (const char *q = p;
+ success && *q != '\0' && *q != '\n' && *q != ' ';
+ q++)
+ if (*q == '\\') {
+ switch (*++q) {
+ case 'e':
+ case '\\':
+ filename += '\\';
+ break;
+ case ' ':
+ filename += ' ';
+ break;
+ default:
+ success = 0;
+ break;
+ }
+ }
+ else
+ filename += char(*q);
+ if (success && filename.length() > 0) {
+ filename += '\0';
+ const char *fn = current_filename;
+ int ln = current_lineno;
+ current_lineno--;
+ if (do_file(filename.contents())) {
+ current_filename = fn;
+ current_lineno = ln;
+ set_location();
+ return;
+ }
+ current_lineno++;
+ }
+ fputs(".so", stdout);
+ fputs(line, stdout);
+}
+
+int do_file(const char *filename)
+{
+ FILE *fp;
+ if (strcmp(filename, "-") == 0)
+ fp = stdin;
+ else {
+ errno = 0;
+ fp = fopen(filename, "r");
+ if (fp == 0) {
+ error("can't open `%1': %2", filename, strerror(errno));
+ return 0;
+ }
+ }
+ current_filename = filename;
+ current_lineno = 1;
+ set_location();
+ enum { START, MIDDLE, HAD_DOT, HAD_s, HAD_so, HAD_l, HAD_lf } state = START;
+ for (;;) {
+ int c = getc(fp);
+ if (c == EOF)
+ break;
+ switch (state) {
+ case START:
+ if (c == '.')
+ state = HAD_DOT;
+ else {
+ putchar(c);
+ if (c == '\n') {
+ current_lineno++;
+ state = START;
+ }
+ else
+ state = MIDDLE;
+ }
+ break;
+ case MIDDLE:
+ putchar(c);
+ if (c == '\n') {
+ current_lineno++;
+ state = START;
+ }
+ break;
+ case HAD_DOT:
+ if (c == 's')
+ state = HAD_s;
+ else if (c == 'l')
+ state = HAD_l;
+ else {
+ putchar('.');
+ putchar(c);
+ if (c == '\n') {
+ current_lineno++;
+ state = START;
+ }
+ else
+ state = MIDDLE;
+ }
+ break;
+ case HAD_s:
+ if (c == 'o')
+ state = HAD_so;
+ else {
+ putchar('.');
+ putchar('s');
+ putchar(c);
+ if (c == '\n') {
+ current_lineno++;
+ state = START;
+ }
+ else
+ state = MIDDLE;
+ }
+ break;
+ case HAD_so:
+ if (c == ' ' || c == '\n' || compatible_flag) {
+ string line;
+ for (; c != EOF && c != '\n'; c = getc(fp))
+ line += c;
+ current_lineno++;
+ line += '\n';
+ line += '\0';
+ do_so(line.contents());
+ state = START;
+ }
+ else {
+ fputs(".so", stdout);
+ putchar(c);
+ state = MIDDLE;
+ }
+ break;
+ case HAD_l:
+ if (c == 'f')
+ state = HAD_lf;
+ else {
+ putchar('.');
+ putchar('l');
+ putchar(c);
+ if (c == '\n') {
+ current_lineno++;
+ state = START;
+ }
+ else
+ state = MIDDLE;
+ }
+ break;
+ case HAD_lf:
+ if (c == ' ' || c == '\n' || compatible_flag) {
+ string line;
+ for (; c != EOF && c != '\n'; c = getc(fp))
+ line += c;
+ current_lineno++;
+ line += '\n';
+ line += '\0';
+ interpret_lf_args(line.contents());
+ printf(".lf%s", line.contents());
+ state = START;
+ }
+ else {
+ fputs(".lf", stdout);
+ putchar(c);
+ state = MIDDLE;
+ }
+ break;
+ default:
+ assert(0);
+ }
+ }
+ switch (state) {
+ case HAD_DOT:
+ fputs(".\n", stdout);
+ break;
+ case HAD_l:
+ fputs(".l\n", stdout);
+ break;
+ case HAD_s:
+ fputs(".s\n", stdout);
+ break;
+ case HAD_lf:
+ fputs(".lf\n", stdout);
+ break;
+ case HAD_so:
+ fputs(".so\n", stdout);
+ break;
+ case MIDDLE:
+ putc('\n', stdout);
+ break;
+ case START:
+ break;
+ }
+ if (fp != stdin)
+ fclose(fp);
+ current_filename = 0;
+ return 1;
+}
diff --git a/gnu/usr.bin/groff/soelim/soelim.man b/gnu/usr.bin/groff/soelim/soelim.man
new file mode 100644
index 0000000..b8c275c
--- /dev/null
+++ b/gnu/usr.bin/groff/soelim/soelim.man
@@ -0,0 +1,42 @@
+.\" -*- nroff -*-
+.TH @G@SOELIM @MAN1EXT@ "@MDATE@" "Groff Version @VERSION@"
+.SH NAME
+@g@soelim \- interpret .so requests in groff input
+.SH SYNOPSIS
+.B @g@soelim
+[
+.B \-Cv
+]
+[
+.IR files \|.\|.\|.\|
+]
+.SH DESCRIPTION
+.B @g@soelim
+reads
+.I files
+and replaces lines of the form
+.IP
+.BI .so\ file
+.LP
+by the contents of
+.IR file .
+It is useful if files included with
+.B so
+need to be preprocessed.
+Normally,
+.B @g@soelim
+should be invoked with the
+.B \-s
+option of
+.BR groff .
+.SH OPTIONS
+.TP
+.B \-C
+Recognize
+.B .so
+even when followed by a character other than space or newline.
+.TP
+.B \-v
+Print the version number.
+.SH "SEE ALSO"
+.BR groff (@MAN1EXT@)
diff --git a/gnu/usr.bin/groff/src/include/defs.h b/gnu/usr.bin/groff/src/include/defs.h
new file mode 100644
index 0000000..df2efba
--- /dev/null
+++ b/gnu/usr.bin/groff/src/include/defs.h
@@ -0,0 +1,9 @@
+#define PROG_PREFIX ""
+#define DEVICE "ps"
+#define FONTPATH "/usr/share/groff_font"
+#define MACROPATH "/usr/share/tmac"
+#define INDEX_SUFFIX ".i"
+#define COMMON_WORDS_FILE "/usr/share/dict/eign"
+#define DEFAULT_INDEX_DIR "/usr/share/dict/papers"
+#define DEFAULT_INDEX_NAME "Ind"
+#define DEFAULT_INDEX "/usr/share/dict/papers/Ind"
diff --git a/gnu/usr.bin/groff/tbl/Makefile b/gnu/usr.bin/groff/tbl/Makefile
new file mode 100644
index 0000000..bdf9431
--- /dev/null
+++ b/gnu/usr.bin/groff/tbl/Makefile
@@ -0,0 +1,13 @@
+# Makefile for tbl
+
+PROG= tbl
+SRCS= main.cc table.cc
+CFLAGS+= -I${.CURDIR}/../include
+LDADD+= ${LIBGROFF} -lm
+DPADD+= ${LIBGROFF} ${LIBM}
+
+MANDEPEND= tbl.1
+CLEANFILES+= ${MANDEPEND}
+
+.include "../Makefile.cfg"
+.include <bsd.prog.mk>
diff --git a/gnu/usr.bin/groff/tbl/Makefile.dep b/gnu/usr.bin/groff/tbl/Makefile.dep
new file mode 100644
index 0000000..0e6938b
--- /dev/null
+++ b/gnu/usr.bin/groff/tbl/Makefile.dep
@@ -0,0 +1,6 @@
+main.o : main.cc table.h ../include/cset.h ../include/cmap.h \
+ ../include/stringclass.h ../include/errarg.h ../include/error.h \
+ ../include/lib.h
+table.o : table.cc table.h ../include/cset.h ../include/cmap.h \
+ ../include/stringclass.h ../include/errarg.h ../include/error.h \
+ ../include/lib.h
diff --git a/gnu/usr.bin/groff/tbl/Makefile.sub b/gnu/usr.bin/groff/tbl/Makefile.sub
new file mode 100644
index 0000000..8ab4a74
--- /dev/null
+++ b/gnu/usr.bin/groff/tbl/Makefile.sub
@@ -0,0 +1,7 @@
+PROG=tbl
+MAN1=tbl.n
+XLIBS=$(LIBGROFF)
+OBJS=main.o table.o
+CCSRCS=main.cc table.cc
+HDRS=table.h
+NAMEPREFIX=$(g)
diff --git a/gnu/usr.bin/groff/tbl/main.cc b/gnu/usr.bin/groff/tbl/main.cc
new file mode 100644
index 0000000..0003b83
--- /dev/null
+++ b/gnu/usr.bin/groff/tbl/main.cc
@@ -0,0 +1,1497 @@
+// -*- C++ -*-
+/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
+ Written by James Clark (jjc@jclark.com)
+
+This file is part of groff.
+
+groff is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
+
+groff is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License along
+with groff; see the file COPYING. If not, write to the Free Software
+Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "table.h"
+
+#define MAX_POINT_SIZE 99
+#define MAX_VERTICAL_SPACING 72
+
+static int compatible_flag = 0;
+
+class table_input {
+ FILE *fp;
+ enum { START, MIDDLE, REREAD_T, REREAD_TE, REREAD_E, END, ERROR } state;
+ string unget_stack;
+public:
+ table_input(FILE *);
+ int get();
+ int ended() { return unget_stack.empty() && state == END; }
+ void unget(char);
+};
+
+table_input::table_input(FILE *p)
+: fp(p), state(START)
+{
+}
+
+void table_input::unget(char c)
+{
+ assert(c != '\0');
+ unget_stack += c;
+ if (c == '\n')
+ current_lineno--;
+}
+
+int table_input::get()
+{
+ int len = unget_stack.length();
+ if (len != 0) {
+ unsigned char c = unget_stack[len - 1];
+ unget_stack.set_length(len - 1);
+ if (c == '\n')
+ current_lineno++;
+ return c;
+ }
+ int c;
+ for (;;) {
+ switch (state) {
+ case START:
+ if ((c = getc(fp)) == '.') {
+ if ((c = getc(fp)) == 'T') {
+ if ((c = getc(fp)) == 'E') {
+ if (compatible_flag) {
+ state = END;
+ return EOF;
+ }
+ else {
+ c = getc(fp);
+ if (c != EOF)
+ ungetc(c, fp);
+ if (c == EOF || c == ' ' || c == '\n') {
+ state = END;
+ return EOF;
+ }
+ state = REREAD_TE;
+ return '.';
+ }
+ }
+ else {
+ if (c != EOF)
+ ungetc(c, fp);
+ state = REREAD_T;
+ return '.';
+ }
+ }
+ else {
+ if (c != EOF)
+ ungetc(c, fp);
+ state = MIDDLE;
+ return '.';
+ }
+ }
+ else if (c == EOF) {
+ state = ERROR;
+ return EOF;
+ }
+ else {
+ if (c == '\n')
+ current_lineno++;
+ else {
+ state = MIDDLE;
+ if (c == '\0') {
+ error("illegal input character code 0");
+ break;
+ }
+ }
+ return c;
+ }
+ break;
+ case MIDDLE:
+ // handle line continuation
+ if ((c = getc(fp)) == '\\') {
+ c = getc(fp);
+ if (c == '\n')
+ c = getc(fp); // perhaps state ought to be START now
+ else {
+ if (c != EOF)
+ ungetc(c, fp);
+ c = '\\';
+ }
+ }
+ if (c == EOF) {
+ state = ERROR;
+ return EOF;
+ }
+ else {
+ if (c == '\n') {
+ state = START;
+ current_lineno++;
+ }
+ else if (c == '\0') {
+ error("illegal input character code 0");
+ break;
+ }
+ return c;
+ }
+ case REREAD_T:
+ state = MIDDLE;
+ return 'T';
+ case REREAD_TE:
+ state = REREAD_E;
+ return 'T';
+ case REREAD_E:
+ state = MIDDLE;
+ return 'E';
+ case END:
+ case ERROR:
+ return EOF;
+ }
+ }
+}
+
+void process_input_file(FILE *);
+void process_table(table_input &in);
+
+void process_input_file(FILE *fp)
+{
+ enum { START, MIDDLE, HAD_DOT, HAD_T, HAD_TS, HAD_l, HAD_lf } state;
+ state = START;
+ int c;
+ while ((c = getc(fp)) != EOF)
+ switch (state) {
+ case START:
+ if (c == '.')
+ state = HAD_DOT;
+ else {
+ if (c == '\n')
+ current_lineno++;
+ else
+ state = MIDDLE;
+ putchar(c);
+ }
+ break;
+ case MIDDLE:
+ if (c == '\n') {
+ current_lineno++;
+ state = START;
+ }
+ putchar(c);
+ break;
+ case HAD_DOT:
+ if (c == 'T')
+ state = HAD_T;
+ else if (c == 'l')
+ state = HAD_l;
+ else {
+ putchar('.');
+ putchar(c);
+ if (c == '\n') {
+ current_lineno++;
+ state = START;
+ }
+ else
+ state = MIDDLE;
+ }
+ break;
+ case HAD_T:
+ if (c == 'S')
+ state = HAD_TS;
+ else {
+ putchar('.');
+ putchar('T');
+ putchar(c);
+ if (c == '\n') {
+ current_lineno++;
+ state = START;
+ }
+ else
+ state = MIDDLE;
+ }
+ break;
+ case HAD_TS:
+ if (c == ' ' || c == '\n' || compatible_flag) {
+ putchar('.');
+ putchar('T');
+ putchar('S');
+ while (c != '\n') {
+ if (c == EOF) {
+ error("end of file at beginning of table");
+ return;
+ }
+ putchar(c);
+ c = getc(fp);
+ }
+ putchar('\n');
+ current_lineno++;
+ {
+ table_input input(fp);
+ process_table(input);
+ set_troff_location(current_filename, current_lineno);
+ if (input.ended()) {
+ fputs(".TE", stdout);
+ while ((c = getc(fp)) != '\n') {
+ if (c == EOF) {
+ putchar('\n');
+ return;
+ }
+ putchar(c);
+ }
+ putchar('\n');
+ current_lineno++;
+ }
+ }
+ state = START;
+ }
+ else {
+ fputs(".TS", stdout);
+ putchar(c);
+ state = MIDDLE;
+ }
+ break;
+ case HAD_l:
+ if (c == 'f')
+ state = HAD_lf;
+ else {
+ putchar('.');
+ putchar('l');
+ putchar(c);
+ if (c == '\n') {
+ current_lineno++;
+ state = START;
+ }
+ else
+ state = MIDDLE;
+ }
+ break;
+ case HAD_lf:
+ if (c == ' ' || c == '\n' || compatible_flag) {
+ string line;
+ while (c != EOF) {
+ line += c;
+ if (c == '\n') {
+ current_lineno++;
+ break;
+ }
+ c = getc(fp);
+ }
+ line += '\0';
+ interpret_lf_args(line.contents());
+ printf(".lf%s", line.contents());
+ state = START;
+ }
+ else {
+ fputs(".lf", stdout);
+ putchar(c);
+ state = MIDDLE;
+ }
+ break;
+ default:
+ assert(0);
+ }
+ switch(state) {
+ case START:
+ break;
+ case MIDDLE:
+ putchar('\n');
+ break;
+ case HAD_DOT:
+ fputs(".\n", stdout);
+ break;
+ case HAD_l:
+ fputs(".l\n", stdout);
+ break;
+ case HAD_T:
+ fputs(".T\n", stdout);
+ break;
+ case HAD_lf:
+ fputs(".lf\n", stdout);
+ break;
+ case HAD_TS:
+ fputs(".TS\n", stdout);
+ break;
+ }
+ if (fp != stdin)
+ fclose(fp);
+}
+
+struct options {
+ unsigned flags;
+ int linesize;
+ char delim[2];
+ char tab_char;
+ char decimal_point_char;
+
+ options();
+};
+
+options::options()
+: flags(0), tab_char('\t'), decimal_point_char('.'), linesize(0)
+{
+ delim[0] = delim[1] = '\0';
+}
+
+// Return non-zero if p and q are the same ignoring case.
+
+int strieq(const char *p, const char *q)
+{
+ for (; cmlower(*p) == cmlower(*q); p++, q++)
+ if (*p == '\0')
+ return 1;
+ return 0;
+}
+
+// return 0 if we should give up in this table
+
+options *process_options(table_input &in)
+{
+ options *opt = new options;
+ string line;
+ int level = 0;
+ for (;;) {
+ int c = in.get();
+ if (c == EOF) {
+ int i = line.length();
+ while (--i >= 0)
+ in.unget(line[i]);
+ return opt;
+ }
+ if (c == '\n') {
+ in.unget(c);
+ int i = line.length();
+ while (--i >= 0)
+ in.unget(line[i]);
+ return opt;
+ }
+ else if (c == '(')
+ level++;
+ else if (c == ')')
+ level--;
+ else if (c == ';' && level == 0) {
+ line += '\0';
+ break;
+ }
+ line += c;
+ }
+ if (line.empty())
+ return opt;
+ char *p = &line[0];
+ for (;;) {
+ while (csspace(*p) || *p == ',')
+ p++;
+ if (*p == '\0')
+ break;
+ char *q = p;
+ while (*q != ' ' && *q != '\0' && *q != '\t' && *q != ',' && *q != '(')
+ q++;
+ char *arg = 0;
+ if (*q != '(' && *q != '\0')
+ *q++ = '\0';
+ while (csspace(*q))
+ q++;
+ if (*q == '(') {
+ *q++ = '\0';
+ arg = q;
+ while (*q != ')' && *q != '\0')
+ q++;
+ if (*q == '\0')
+ error("missing `)'");
+ else
+ *q++ = '\0';
+ }
+ if (*p == '\0') {
+ if (arg)
+ error("argument without option");
+ }
+ else if (strieq(p, "tab")) {
+ if (!arg)
+ error("`tab' option requires argument in parentheses");
+ else {
+ if (arg[0] == '\0' || arg[1] != '\0')
+ error("argument to `tab' option must be a single character");
+ else
+ opt->tab_char = arg[0];
+ }
+ }
+ else if (strieq(p, "linesize")) {
+ if (!arg)
+ error("`linesize' option requires argument in parentheses");
+ else {
+ if (sscanf(arg, "%d", &opt->linesize) != 1)
+ error("bad linesize `%s'", arg);
+ else if (opt->linesize <= 0) {
+ error("linesize must be positive");
+ opt->linesize = 0;
+ }
+ }
+ }
+ else if (strieq(p, "delim")) {
+ if (!arg)
+ error("`delim' option requires argument in parentheses");
+ else if (arg[0] == '\0' || arg[1] == '\0' || arg[2] != '\0')
+ error("argument to `delim' option must be two characters");
+ else {
+ opt->delim[0] = arg[0];
+ opt->delim[1] = arg[1];
+ }
+ }
+ else if (strieq(p, "center") || strieq(p, "centre")) {
+ if (arg)
+ error("`center' option does not take a argument");
+ opt->flags |= table::CENTER;
+ }
+ else if (strieq(p, "expand")) {
+ if (arg)
+ error("`expand' option does not take a argument");
+ opt->flags |= table::EXPAND;
+ }
+ else if (strieq(p, "box") || strieq(p, "frame")) {
+ if (arg)
+ error("`box' option does not take a argument");
+ opt->flags |= table::BOX;
+ }
+ else if (strieq(p, "doublebox") || strieq(p, "doubleframe")) {
+ if (arg)
+ error("`doublebox' option does not take a argument");
+ opt->flags |= table::DOUBLEBOX;
+ }
+ else if (strieq(p, "allbox")) {
+ if (arg)
+ error("`allbox' option does not take a argument");
+ opt->flags |= table::ALLBOX;
+ }
+ else if (strieq(p, "nokeep")) {
+ if (arg)
+ error("`nokeep' option does not take a argument");
+ opt->flags |= table::NOKEEP;
+ }
+ else if (strieq(p, "decimalpoint")) {
+ if (!arg)
+ error("`decimalpoint' option requires argument in parentheses");
+ else {
+ if (arg[0] == '\0' || arg[1] != '\0')
+ error("argument to `decimalpoint' option must be a single character");
+ else
+ opt->decimal_point_char = arg[0];
+ }
+ }
+ else {
+ error("unrecognised global option `%1'", p);
+ // delete opt;
+ // return 0;
+ }
+ p = q;
+ }
+ return opt;
+}
+
+entry_modifier::entry_modifier()
+: vertical_alignment(CENTER), zero_width(0), stagger(0)
+{
+ vertical_spacing.inc = vertical_spacing.val = 0;
+ point_size.inc = point_size.val = 0;
+}
+
+entry_modifier::~entry_modifier()
+{
+}
+
+entry_format::entry_format() : type(FORMAT_LEFT)
+{
+}
+
+entry_format::entry_format(format_type t) : type(t)
+{
+}
+
+void entry_format::debug_print() const
+{
+ switch (type) {
+ case FORMAT_LEFT:
+ putc('l', stderr);
+ break;
+ case FORMAT_CENTER:
+ putc('c', stderr);
+ break;
+ case FORMAT_RIGHT:
+ putc('r', stderr);
+ break;
+ case FORMAT_NUMERIC:
+ putc('n', stderr);
+ break;
+ case FORMAT_ALPHABETIC:
+ putc('a', stderr);
+ break;
+ case FORMAT_SPAN:
+ putc('s', stderr);
+ break;
+ case FORMAT_VSPAN:
+ putc('^', stderr);
+ break;
+ case FORMAT_HLINE:
+ putc('_', stderr);
+ break;
+ case FORMAT_DOUBLE_HLINE:
+ putc('=', stderr);
+ break;
+ default:
+ assert(0);
+ break;
+ }
+ if (point_size.val != 0) {
+ putc('p', stderr);
+ if (point_size.inc > 0)
+ putc('+', stderr);
+ else if (point_size.inc < 0)
+ putc('-', stderr);
+ fprintf(stderr, "%d ", point_size.val);
+ }
+ if (vertical_spacing.val != 0) {
+ putc('v', stderr);
+ if (vertical_spacing.inc > 0)
+ putc('+', stderr);
+ else if (vertical_spacing.inc < 0)
+ putc('-', stderr);
+ fprintf(stderr, "%d ", vertical_spacing.val);
+ }
+ if (!font.empty()) {
+ putc('f', stderr);
+ put_string(font, stderr);
+ putc(' ', stderr);
+ }
+ switch (vertical_alignment) {
+ case entry_modifier::CENTER:
+ break;
+ case entry_modifier::TOP:
+ putc('t', stderr);
+ break;
+ case entry_modifier::BOTTOM:
+ putc('d', stderr);
+ break;
+ }
+ if (zero_width)
+ putc('z', stderr);
+ if (stagger)
+ putc('u', stderr);
+}
+
+struct format {
+ int nrows;
+ int ncolumns;
+ int *separation;
+ string *width;
+ char *equal;
+ entry_format **entry;
+ char **vline;
+
+ format(int nr, int nc);
+ ~format();
+ void add_rows(int n);
+};
+
+format::format(int nr, int nc) : nrows(nr), ncolumns(nc)
+{
+ int i;
+ separation = ncolumns > 1 ? new int[ncolumns - 1] : 0;
+ for (i = 0; i < ncolumns-1; i++)
+ separation[i] = -1;
+ width = new string[ncolumns];
+ equal = new char[ncolumns];
+ for (i = 0; i < ncolumns; i++)
+ equal[i] = 0;
+ entry = new entry_format *[nrows];
+ for (i = 0; i < nrows; i++)
+ entry[i] = new entry_format[ncolumns];
+ vline = new char*[nrows];
+ for (i = 0; i < nrows; i++) {
+ vline[i] = new char[ncolumns+1];
+ for (int j = 0; j < ncolumns+1; j++)
+ vline[i][j] = 0;
+ }
+}
+
+void format::add_rows(int n)
+{
+ int i;
+ char **old_vline = vline;
+ vline = new char*[nrows + n];
+ for (i = 0; i < nrows; i++)
+ vline[i] = old_vline[i];
+ a_delete old_vline;
+ for (i = 0; i < n; i++) {
+ vline[nrows + i] = new char[ncolumns + 1];
+ for (int j = 0; j < ncolumns + 1; j++)
+ vline[nrows + i][j] = 0;
+ }
+ entry_format **old_entry = entry;
+ entry = new entry_format *[nrows + n];
+ for (i = 0; i < nrows; i++)
+ entry[i] = old_entry[i];
+ a_delete old_entry;
+ for (i = 0; i < n; i++)
+ entry[nrows + i] = new entry_format[ncolumns];
+ nrows += n;
+}
+
+format::~format()
+{
+ a_delete separation;
+ ad_delete(ncolumns) width;
+ a_delete equal;
+ for (int i = 0; i < nrows; i++) {
+ a_delete vline[i];
+ ad_delete(ncolumns) entry[i];
+ }
+ a_delete vline;
+ a_delete entry;
+}
+
+struct input_entry_format : public entry_format {
+ input_entry_format *next;
+ string width;
+ int separation;
+ int vline;
+ int pre_vline;
+ int last_column;
+ int equal;
+ input_entry_format(format_type, input_entry_format * = 0);
+ ~input_entry_format();
+ void debug_print();
+};
+
+input_entry_format::input_entry_format(format_type t, input_entry_format *p)
+: entry_format(t), next(p)
+{
+ separation = -1;
+ last_column = 0;
+ vline = 0;
+ pre_vline = 0;
+ equal = 0;
+}
+
+input_entry_format::~input_entry_format()
+{
+}
+
+void free_input_entry_format_list(input_entry_format *list)
+{
+ while (list) {
+ input_entry_format *tem = list;
+ list = list->next;
+ delete tem;
+ }
+}
+
+void input_entry_format::debug_print()
+{
+ for (int i = 0; i < pre_vline; i++)
+ putc('|', stderr);
+ entry_format::debug_print();
+ if (!width.empty()) {
+ putc('w', stderr);
+ putc('(', stderr);
+ put_string(width, stderr);
+ putc(')', stderr);
+ }
+ if (equal)
+ putc('e', stderr);
+ if (separation >= 0)
+ fprintf(stderr, "%d", separation);
+ for (i = 0; i < vline; i++)
+ putc('|', stderr);
+ if (last_column)
+ putc(',', stderr);
+}
+
+// Return zero if we should give up on this table.
+// If this is a continuation format line, current_format will be the current
+// format line.
+
+format *process_format(table_input &in, options *opt,
+ format *current_format = 0)
+{
+ input_entry_format *list = 0;
+ int c = in.get();
+ for (;;) {
+ int pre_vline = 0;
+ int got_format = 0;
+ int got_period = 0;
+ format_type t;
+ for (;;) {
+ if (c == EOF) {
+ error("end of input while processing format");
+ free_input_entry_format_list(list);
+ return 0;
+ }
+ switch (c) {
+ case 'n':
+ case 'N':
+ t = FORMAT_NUMERIC;
+ got_format = 1;
+ break;
+ case 'a':
+ case 'A':
+ got_format = 1;
+ t = FORMAT_ALPHABETIC;
+ break;
+ case 'c':
+ case 'C':
+ got_format = 1;
+ t = FORMAT_CENTER;
+ break;
+ case 'l':
+ case 'L':
+ got_format = 1;
+ t = FORMAT_LEFT;
+ break;
+ case 'r':
+ case 'R':
+ got_format = 1;
+ t = FORMAT_RIGHT;
+ break;
+ case 's':
+ case 'S':
+ got_format = 1;
+ t = FORMAT_SPAN;
+ break;
+ case '^':
+ got_format = 1;
+ t = FORMAT_VSPAN;
+ break;
+ case '_':
+ got_format = 1;
+ t = FORMAT_HLINE;
+ break;
+ case '=':
+ got_format = 1;
+ t = FORMAT_DOUBLE_HLINE;
+ break;
+ case '.':
+ got_period = 1;
+ break;
+ case '|':
+ pre_vline++;
+ break;
+ case ' ':
+ case '\t':
+ case '\n':
+ break;
+ default:
+ if (c == opt->tab_char)
+ break;
+ error("unrecognised format `%1'", char(c));
+ free_input_entry_format_list(list);
+ return 0;
+ }
+ if (got_period)
+ break;
+ c = in.get();
+ if (got_format)
+ break;
+ }
+ if (got_period)
+ break;
+ list = new input_entry_format(t, list);
+ if (pre_vline)
+ list->pre_vline = pre_vline;
+ int success = 1;
+ do {
+ switch (c) {
+ case 't':
+ case 'T':
+ c = in.get();
+ list->vertical_alignment = entry_modifier::TOP;
+ break;
+ case 'd':
+ case 'D':
+ c = in.get();
+ list->vertical_alignment = entry_modifier::BOTTOM;
+ break;
+ case 'u':
+ case 'U':
+ c = in.get();
+ list->stagger = 1;
+ break;
+ case 'z':
+ case 'Z':
+ c = in.get();
+ list->zero_width = 1;
+ break;
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ {
+ int w = 0;
+ do {
+ w = w*10 + (c - '0');
+ c = in.get();
+ } while (c != EOF && csdigit(c));
+ list->separation = w;
+ }
+ break;
+ case 'f':
+ case 'F':
+ do {
+ c = in.get();
+ } while (c == ' ' || c == '\t');
+ if (c == EOF) {
+ error("missing font name");
+ break;
+ }
+ if (c == '(') {
+ for (;;) {
+ c = in.get();
+ if (c == EOF || c == ' ' || c == '\t') {
+ error("missing `)'");
+ break;
+ }
+ if (c == ')') {
+ c = in.get();
+ break;
+ }
+ list->font += char(c);
+ }
+ }
+ else {
+ list->font = c;
+ char cc = c;
+ c = in.get();
+ if (!csdigit(cc)
+ && c != EOF && c != ' ' && c != '\t' && c != '.' && c != '\n') {
+ list->font += char(c);
+ c = in.get();
+ }
+ }
+ break;
+ case 'v':
+ case 'V':
+ c = in.get();
+ list->vertical_spacing.val = 0;
+ list->vertical_spacing.inc = 0;
+ if (c == '+' || c == '-') {
+ list->vertical_spacing.inc = (c == '+' ? 1 : -1);
+ c = in.get();
+ }
+ if (c == EOF || !csdigit(c)) {
+ error("`v' modifier must be followed by number");
+ list->vertical_spacing.inc = 0;
+ }
+ else {
+ do {
+ list->vertical_spacing.val *= 10;
+ list->vertical_spacing.val += c - '0';
+ c = in.get();
+ } while (c != EOF && csdigit(c));
+ }
+ if (list->vertical_spacing.val > MAX_VERTICAL_SPACING
+ || list->vertical_spacing.val < -MAX_VERTICAL_SPACING) {
+ error("unreasonable point size");
+ list->vertical_spacing.val = 0;
+ list->vertical_spacing.inc = 0;
+ }
+ break;
+ case 'p':
+ case 'P':
+ c = in.get();
+ list->point_size.val = 0;
+ list->point_size.inc = 0;
+ if (c == '+' || c == '-') {
+ list->point_size.inc = (c == '+' ? 1 : -1);
+ c = in.get();
+ }
+ if (c == EOF || !csdigit(c)) {
+ error("`p' modifier must be followed by number");
+ list->point_size.inc = 0;
+ }
+ else {
+ do {
+ list->point_size.val *= 10;
+ list->point_size.val += c - '0';
+ c = in.get();
+ } while (c != EOF && csdigit(c));
+ }
+ if (list->point_size.val > MAX_POINT_SIZE
+ || list->point_size.val < -MAX_POINT_SIZE) {
+ error("unreasonable point size");
+ list->point_size.val = 0;
+ list->point_size.inc = 0;
+ }
+ break;
+ case 'w':
+ case 'W':
+ c = in.get();
+ while (c == ' ' || c == '\t')
+ c = in.get();
+ if (c == '(') {
+ list->width = "";
+ c = in.get();
+ while (c != ')') {
+ if (c == EOF || c == '\n') {
+ error("missing `)'");
+ free_input_entry_format_list(list);
+ return 0;
+ }
+ list->width += c;
+ c = in.get();
+ }
+ c = in.get();
+ }
+ else {
+ if (c == '+' || c == '-') {
+ list->width = char(c);
+ c = in.get();
+ }
+ else
+ list->width = "";
+ if (c == EOF || !csdigit(c))
+ error("bad argument for `w' modifier");
+ else {
+ do {
+ list->width += char(c);
+ c = in.get();
+ } while (c != EOF && csdigit(c));
+ }
+ }
+ break;
+ case 'e':
+ case 'E':
+ c = in.get();
+ list->equal++;
+ break;
+ case '|':
+ c = in.get();
+ list->vline++;
+ break;
+ case 'B':
+ case 'b':
+ c = in.get();
+ list->font = "B";
+ break;
+ case 'I':
+ case 'i':
+ c = in.get();
+ list->font = "I";
+ break;
+ case ' ':
+ case '\t':
+ c = in.get();
+ break;
+ default:
+ if (c == opt->tab_char)
+ c = in.get();
+ else
+ success = 0;
+ break;
+ }
+ } while (success);
+ if (list->vline > 2) {
+ list->vline = 2;
+ error("more than 2 vertical bars between key letters");
+ }
+ if (c == '\n' || c == ',') {
+ c = in.get();
+ list->last_column = 1;
+ }
+ }
+ if (c == '.') {
+ do {
+ c = in.get();
+ } while (c == ' ' || c == '\t');
+ if (c != '\n') {
+ error("`.' not last character on line");
+ free_input_entry_format_list(list);
+ return 0;
+ }
+ }
+ if (!list) {
+ error("no format");
+ free_input_entry_format_list(list);
+ return 0;
+ }
+ list->last_column = 1;
+ // now reverse the list so that the first row is at the beginning
+ input_entry_format *rev = 0;
+ while (list != 0) {
+ input_entry_format *tem = list->next;
+ list->next = rev;
+ rev = list;
+ list = tem;
+ }
+ list = rev;
+ input_entry_format *tem;
+
+#if 0
+ for (tem = list; tem; tem = tem->next)
+ tem->debug_print();
+ putc('\n', stderr);
+#endif
+ // compute number of columns and rows
+ int ncolumns = 0;
+ int nrows = 0;
+ int col = 0;
+ for (tem = list; tem; tem = tem->next) {
+ if (tem->last_column) {
+ if (col >= ncolumns)
+ ncolumns = col + 1;
+ col = 0;
+ nrows++;
+ }
+ else
+ col++;
+ }
+ int row;
+ format *f;
+ if (current_format) {
+ if (ncolumns > current_format->ncolumns) {
+ error("cannot increase the number of columns in a continued format");
+ free_input_entry_format_list(list);
+ return 0;
+ }
+ f = current_format;
+ row = f->nrows;
+ f->add_rows(nrows);
+ }
+ else {
+ f = new format(nrows, ncolumns);
+ row = 0;
+ }
+ col = 0;
+ for (tem = list; tem; tem = tem->next) {
+ f->entry[row][col] = *tem;
+ if (col < ncolumns-1) {
+ // use the greatest separation
+ if (tem->separation > f->separation[col]) {
+ if (current_format)
+ error("cannot change column separation in continued format");
+ else
+ f->separation[col] = tem->separation;
+ }
+ }
+ else if (tem->separation >= 0)
+ error("column separation specified for last column");
+ if (tem->equal && !f->equal[col]) {
+ if (current_format)
+ error("cannot change which columns are equal in continued format");
+ else
+ f->equal[col] = 1;
+ }
+ if (!tem->width.empty()) {
+ // use the last width
+ if (!f->width[col].empty() && f->width[col] != tem->width)
+ error("multiple widths for column %1", col+1);
+ f->width[col] = tem->width;
+ }
+ if (tem->pre_vline) {
+ assert(col == 0);
+ f->vline[row][col] = tem->pre_vline;
+ }
+ f->vline[row][col+1] = tem->vline;
+ if (tem->last_column) {
+ row++;
+ col = 0;
+ }
+ else
+ col++;
+ }
+ free_input_entry_format_list(list);
+ for (col = 0; col < ncolumns; col++) {
+ entry_format *e = f->entry[f->nrows-1] + col;
+ if (e->type != FORMAT_HLINE
+ && e->type != FORMAT_DOUBLE_HLINE
+ && e->type != FORMAT_SPAN)
+ break;
+ }
+ if (col >= ncolumns) {
+ error("last row of format is all lines");
+ delete f;
+ return 0;
+ }
+ return f;
+}
+
+table *process_data(table_input &in, format *f, options *opt)
+{
+ char tab_char = opt->tab_char;
+ int ncolumns = f->ncolumns;
+ int current_row = 0;
+ int format_index = 0;
+ int give_up = 0;
+ enum { DATA_INPUT_LINE, TROFF_INPUT_LINE, SINGLE_HLINE, DOUBLE_HLINE } type;
+ table *tbl = new table(ncolumns, opt->flags, opt->linesize,
+ opt->decimal_point_char);
+ if (opt->delim[0] != '\0')
+ tbl->set_delim(opt->delim[0], opt->delim[1]);
+ for (;;) {
+ // first determine what type of line this is
+ int c = in.get();
+ if (c == EOF)
+ break;
+ if (c == '.') {
+ int d = in.get();
+ if (d != EOF && csdigit(d)) {
+ in.unget(d);
+ type = DATA_INPUT_LINE;
+ }
+ else {
+ in.unget(d);
+ type = TROFF_INPUT_LINE;
+ }
+ }
+ else if (c == '_' || c == '=') {
+ int d = in.get();
+ if (d == '\n') {
+ if (c == '_')
+ type = SINGLE_HLINE;
+ else
+ type = DOUBLE_HLINE;
+ }
+ else {
+ in.unget(d);
+ type = DATA_INPUT_LINE;
+ }
+ }
+ else {
+ type = DATA_INPUT_LINE;
+ }
+ switch (type) {
+ case DATA_INPUT_LINE:
+ {
+ string input_entry;
+ if (format_index >= f->nrows)
+ format_index = f->nrows - 1;
+ // A format row that is all lines doesn't use up a data line.
+ while (format_index < f->nrows - 1) {
+ for (int c = 0; c < ncolumns; c++) {
+ entry_format *e = f->entry[format_index] + c;
+ if (e->type != FORMAT_HLINE
+ && e->type != FORMAT_DOUBLE_HLINE
+ // Unfortunately tbl treats a span as needing data.
+ // && e->type != FORMAT_SPAN
+ )
+ break;
+ }
+ if (c < ncolumns)
+ break;
+ for (c = 0; c < ncolumns; c++)
+ tbl->add_entry(current_row, c, input_entry,
+ f->entry[format_index] + c, current_filename,
+ current_lineno);
+ tbl->add_vlines(current_row, f->vline[format_index]);
+ format_index++;
+ current_row++;
+ }
+ entry_format *line_format = f->entry[format_index];
+ int col = 0;
+ for (;;) {
+ if (c == tab_char || c == '\n') {
+ int ln = current_lineno;
+ if (c == '\n')
+ --ln;
+ while (col < ncolumns
+ && line_format[col].type == FORMAT_SPAN) {
+ tbl->add_entry(current_row, col, "", &line_format[col],
+ current_filename, ln);
+ col++;
+ }
+ if (c == '\n' && input_entry.length() == 2
+ && input_entry[0] == 'T' && input_entry[1] == '{') {
+ input_entry = "";
+ ln++;
+ enum {
+ START, MIDDLE, GOT_T, GOT_RIGHT_BRACE, GOT_DOT,
+ GOT_l, GOT_lf, END
+ } state = START;
+ while (state != END) {
+ c = in.get();
+ if (c == EOF)
+ break;
+ switch (state) {
+ case START:
+ if (c == 'T')
+ state = GOT_T;
+ else if (c == '.')
+ state = GOT_DOT;
+ else {
+ input_entry += c;
+ if (c != '\n')
+ state = MIDDLE;
+ }
+ break;
+ case GOT_T:
+ if (c == '}')
+ state = GOT_RIGHT_BRACE;
+ else {
+ input_entry += 'T';
+ input_entry += c;
+ state = c == '\n' ? START : MIDDLE;
+ }
+ break;
+ case GOT_DOT:
+ if (c == 'l')
+ state = GOT_l;
+ else {
+ input_entry += '.';
+ input_entry += c;
+ state = c == '\n' ? START : MIDDLE;
+ }
+ break;
+ case GOT_l:
+ if (c == 'f')
+ state = GOT_lf;
+ else {
+ input_entry += ".l";
+ input_entry += c;
+ state = c == '\n' ? START : MIDDLE;
+ }
+ break;
+ case GOT_lf:
+ if (c == ' ' || c == '\n' || compatible_flag) {
+ string args;
+ input_entry += ".lf";
+ while (c != EOF) {
+ args += c;
+ if (c == '\n')
+ break;
+ c = in.get();
+ }
+ args += '\0';
+ interpret_lf_args(args.contents());
+ // remove the '\0'
+ args.set_length(args.length() - 1);
+ input_entry += args;
+ state = START;
+ }
+ else {
+ input_entry += ".lf";
+ input_entry += c;
+ state = MIDDLE;
+ }
+ break;
+ case GOT_RIGHT_BRACE:
+ if (c == '\n' || c == tab_char)
+ state = END;
+ else {
+ input_entry += 'T';
+ input_entry += '}';
+ input_entry += c;
+ state = c == '\n' ? START : MIDDLE;
+ }
+ break;
+ case MIDDLE:
+ if (c == '\n')
+ state = START;
+ input_entry += c;
+ break;
+ case END:
+ default:
+ assert(0);
+ }
+ }
+ if (c == EOF) {
+ error("end of data in middle of text block");
+ give_up = 1;
+ break;
+ }
+ }
+ if (col >= ncolumns) {
+ if (!input_entry.empty()) {
+ if (c == '\n')
+ in.unget(c);
+ input_entry += '\0';
+ error("excess data entry `%1' discarded",
+ input_entry.contents());
+ if (c == '\n')
+ (void)in.get();
+ }
+ }
+ else
+ tbl->add_entry(current_row, col, input_entry,
+ &line_format[col], current_filename, ln);
+ col++;
+ if (c == '\n')
+ break;
+ input_entry = "";
+ }
+ else
+ input_entry += c;
+ c = in.get();
+ if (c == EOF)
+ break;
+ }
+ if (give_up)
+ break;
+ input_entry = "";
+ for (; col < ncolumns; col++)
+ tbl->add_entry(current_row, col, input_entry, &line_format[col],
+ current_filename, current_lineno - 1);
+ tbl->add_vlines(current_row, f->vline[format_index]);
+ current_row++;
+ format_index++;
+ }
+ break;
+ case TROFF_INPUT_LINE:
+ {
+ string line;
+ int ln = current_lineno;
+ for (;;) {
+ line += c;
+ if (c == '\n')
+ break;
+ c = in.get();
+ if (c == EOF) {
+ break;
+ }
+ }
+ tbl->add_text_line(current_row, line, current_filename, ln);
+ if (line.length() >= 4
+ && line[0] == '.' && line[1] == 'T' && line[2] == '&') {
+ format *newf = process_format(in, opt, f);
+ if (newf == 0)
+ give_up = 1;
+ else
+ f = newf;
+ }
+ if (line.length() >= 3
+ && line[0] == '.' && line[1] == 'f' && line[2] == 'f') {
+ line += '\0';
+ interpret_lf_args(line.contents() + 3);
+ }
+ }
+ break;
+ case SINGLE_HLINE:
+ tbl->add_single_hline(current_row);
+ break;
+ case DOUBLE_HLINE:
+ tbl->add_double_hline(current_row);
+ break;
+ default:
+ assert(0);
+ }
+ if (give_up)
+ break;
+ }
+ if (!give_up && current_row == 0) {
+ error("no real data");
+ give_up = 1;
+ }
+ if (give_up) {
+ delete tbl;
+ return 0;
+ }
+ // Do this here rather than at the beginning in case continued formats
+ // change it.
+ for (int i = 0; i < ncolumns - 1; i++)
+ if (f->separation[i] >= 0)
+ tbl->set_column_separation(i, f->separation[i]);
+ for (i = 0; i < ncolumns; i++)
+ if (!f->width[i].empty())
+ tbl->set_minimum_width(i, f->width[i]);
+ for (i = 0; i < ncolumns; i++)
+ if (f->equal[i])
+ tbl->set_equal_column(i);
+ return tbl;
+}
+
+void process_table(table_input &in)
+{
+ int c;
+ options *opt = 0;
+ format *form = 0;
+ table *tbl = 0;
+ if ((opt = process_options(in)) != 0
+ && (form = process_format(in, opt)) != 0
+ && (tbl = process_data(in, form, opt)) != 0) {
+ tbl->print();
+ delete tbl;
+ }
+ else {
+ error("giving up on this table");
+ while ((c = in.get()) != EOF)
+ ;
+ }
+ delete opt;
+ delete form;
+ if (!in.ended())
+ error("premature end of file");
+}
+
+static void usage()
+{
+ fprintf(stderr, "usage: %s [ -vC ] [ files... ]\n", program_name);
+ exit(1);
+}
+
+int main(int argc, char **argv)
+{
+ program_name = argv[0];
+ static char stderr_buf[BUFSIZ];
+ setbuf(stderr, stderr_buf);
+ int opt;
+ while ((opt = getopt(argc, argv, "vC")) != EOF)
+ switch (opt) {
+ case 'C':
+ compatible_flag = 1;
+ break;
+ case 'v':
+ {
+ extern const char *version_string;
+ fprintf(stderr, "GNU tbl version %s\n", version_string);
+ fflush(stderr);
+ break;
+ }
+ case '?':
+ usage();
+ break;
+ default:
+ assert(0);
+ }
+ printf(".if !\\n(.g .ab GNU tbl requires GNU troff.\n"
+ ".if !dTS .ds TS\n"
+ ".if !dTE .ds TE\n");
+ if (argc > optind) {
+ for (int i = optind; i < argc; i++)
+ if (argv[i][0] == '-' && argv[i][1] == '\0') {
+ current_filename = "-";
+ current_lineno = 1;
+ printf(".lf 1 -\n");
+ process_input_file(stdin);
+ }
+ else {
+ errno = 0;
+ FILE *fp = fopen(argv[i], "r");
+ if (fp == 0) {
+ current_lineno = -1;
+ error("can't open `%1': %2", argv[i], strerror(errno));
+ }
+ else {
+ current_lineno = 1;
+ current_filename = argv[i];
+ printf(".lf 1 %s\n", current_filename);
+ process_input_file(fp);
+ }
+ }
+ }
+ else {
+ current_filename = "-";
+ current_lineno = 1;
+ printf(".lf 1 -\n");
+ process_input_file(stdin);
+ }
+ if (ferror(stdout) || fflush(stdout) < 0)
+ fatal("output error");
+ return 0;
+}
+
diff --git a/gnu/usr.bin/groff/tbl/table.cc b/gnu/usr.bin/groff/tbl/table.cc
new file mode 100644
index 0000000..1daa497
--- /dev/null
+++ b/gnu/usr.bin/groff/tbl/table.cc
@@ -0,0 +1,2764 @@
+// -*- C++ -*-
+/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
+ Written by James Clark (jjc@jclark.com)
+
+This file is part of groff.
+
+groff is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
+
+groff is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License along
+with groff; see the file COPYING. If not, write to the Free Software
+Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "table.h"
+
+#define BAR_HEIGHT ".25m"
+#define DOUBLE_LINE_SEP "2p"
+#define HALF_DOUBLE_LINE_SEP "1p"
+#define LINE_SEP "2p"
+#define BODY_DEPTH ".25m"
+
+const int DEFAULT_COLUMN_SEPARATION = 3;
+
+#define DELIMITER_CHAR "\\[tbl]"
+#define PREFIX "3"
+#define SEPARATION_FACTOR_REG PREFIX "sep"
+#define BOTTOM_REG PREFIX "bot"
+#define RESET_MACRO_NAME PREFIX "init"
+#define LINESIZE_REG PREFIX "lps"
+#define TOP_REG PREFIX "top"
+#define CURRENT_ROW_REG PREFIX "crow"
+#define LAST_PASSED_ROW_REG PREFIX "passed"
+#define TRANSPARENT_STRING_NAME PREFIX "trans"
+#define QUOTE_STRING_NAME PREFIX "quote"
+#define SECTION_DIVERSION_NAME PREFIX "section"
+#define SECTION_DIVERSION_FLAG_REG PREFIX "sflag"
+#define SAVED_VERTICAL_POS_REG PREFIX "vert"
+#define NEED_BOTTOM_RULE_REG PREFIX "brule"
+#define KEEP_MACRO_NAME PREFIX "keep"
+#define RELEASE_MACRO_NAME PREFIX "release"
+#define SAVED_FONT_REG PREFIX "fnt"
+#define SAVED_SIZE_REG PREFIX "sz"
+#define SAVED_FILL_REG PREFIX "fll"
+#define SAVED_INDENT_REG PREFIX "ind"
+#define SAVED_CENTER_REG PREFIX "cent"
+#define TABLE_DIVERSION_NAME PREFIX "table"
+#define TABLE_DIVERSION_FLAG_REG PREFIX "tflag"
+#define TABLE_KEEP_MACRO_NAME PREFIX "tkeep"
+#define TABLE_RELEASE_MACRO_NAME PREFIX "trelease"
+#define NEEDED_REG PREFIX "needed"
+#define REPEATED_MARK_MACRO PREFIX "rmk"
+#define REPEATED_VPT_MACRO PREFIX "rvpt"
+#define SUPPRESS_BOTTOM_REG PREFIX "supbot"
+#define SAVED_DN_REG PREFIX "dn"
+
+// this must be one character
+#define COMPATIBLE_REG PREFIX "c"
+
+#define BLOCK_WIDTH_PREFIX PREFIX "tbw"
+#define BLOCK_DIVERSION_PREFIX PREFIX "tbd"
+#define BLOCK_HEIGHT_PREFIX PREFIX "tbh"
+#define SPAN_WIDTH_PREFIX PREFIX "w"
+#define SPAN_LEFT_NUMERIC_WIDTH_PREFIX PREFIX "lnw"
+#define SPAN_RIGHT_NUMERIC_WIDTH_PREFIX PREFIX "rnw"
+#define SPAN_ALPHABETIC_WIDTH_PREFIX PREFIX "aw"
+#define COLUMN_SEPARATION_PREFIX PREFIX "cs"
+#define ROW_START_PREFIX PREFIX "rs"
+#define COLUMN_START_PREFIX PREFIX "cl"
+#define COLUMN_END_PREFIX PREFIX "ce"
+#define COLUMN_DIVIDE_PREFIX PREFIX "cd"
+#define ROW_TOP_PREFIX PREFIX "rt"
+
+string block_width_reg(int r, int c);
+string block_diversion_name(int r, int c);
+string block_height_reg(int r, int c);
+string span_width_reg(int start_col, int end_col);
+string span_left_numeric_width_reg(int start_col, int end_col);
+string span_right_numeric_width_reg(int start_col, int end_col);
+string span_alphabetic_width_reg(int start_col, int end_col);
+string column_separation_reg(int col);
+string row_start_reg(int r);
+string column_start_reg(int c);
+string column_end_reg(int c);
+string column_divide_reg(int c);
+string row_top_reg(int r);
+
+void set_inline_modifier(const entry_modifier *);
+void restore_inline_modifier(const entry_modifier *m);
+void set_modifier(const entry_modifier *);
+int find_decimal_point(const char *s, char decimal_point_char,
+ const char *delim);
+
+string an_empty_string;
+int location_force_filename = 0;
+
+void printfs(const char *,
+ const string &arg1 = an_empty_string,
+ const string &arg2 = an_empty_string,
+ const string &arg3 = an_empty_string,
+ const string &arg4 = an_empty_string,
+ const string &arg5 = an_empty_string);
+
+void prints(const string &);
+
+inline void prints(char c)
+{
+ putchar(c);
+}
+
+inline void prints(const char *s)
+{
+ fputs(s, stdout);
+}
+
+void prints(const string &s)
+{
+ if (!s.empty())
+ fwrite(s.contents(), 1, s.length(), stdout);
+}
+
+struct horizontal_span {
+ horizontal_span *next;
+ short start_col;
+ short end_col;
+ horizontal_span(int, int, horizontal_span *);
+};
+
+struct single_line_entry;
+struct double_line_entry;
+struct simple_entry;
+
+class table_entry {
+friend class table;
+ table_entry *next;
+ int input_lineno;
+ const char *input_filename;
+protected:
+ short start_row;
+ short start_col;
+ short end_row;
+ short end_col;
+ const entry_modifier *mod;
+public:
+ void set_location();
+ table_entry(const entry_modifier *);
+ virtual ~table_entry();
+ virtual int divert(int ncols, const string *mw, int *sep);
+ virtual void do_width();
+ virtual void do_depth();
+ virtual void print() = 0;
+ virtual void position_vertically() = 0;
+ virtual single_line_entry *to_single_line_entry();
+ virtual double_line_entry *to_double_line_entry();
+ virtual simple_entry *to_simple_entry();
+ virtual int line_type();
+ virtual void note_double_vrule_on_right(int);
+ virtual void note_double_vrule_on_left(int);
+};
+
+class simple_entry : public table_entry {
+public:
+ simple_entry(const entry_modifier *);
+ void print();
+ void position_vertically();
+ simple_entry *to_simple_entry();
+ virtual void add_tab();
+ virtual void simple_print(int);
+};
+
+class empty_entry : public simple_entry {
+public:
+ empty_entry(const entry_modifier *);
+ int line_type();
+};
+
+class text_entry : public simple_entry {
+protected:
+ char *contents;
+ void print_contents();
+public:
+ text_entry(char *, const entry_modifier *);
+ ~text_entry();
+};
+
+void text_entry::print_contents()
+{
+ set_inline_modifier(mod);
+ prints(contents);
+ restore_inline_modifier(mod);
+}
+
+class repeated_char_entry : public text_entry {
+public:
+ repeated_char_entry(char *s, const entry_modifier *m);
+ void simple_print(int);
+};
+
+class simple_text_entry : public text_entry {
+public:
+ simple_text_entry(char *s, const entry_modifier *m);
+ void do_width();
+};
+
+class left_text_entry : public simple_text_entry {
+public:
+ left_text_entry(char *s, const entry_modifier *m);
+ void simple_print(int);
+ void add_tab();
+};
+
+class right_text_entry : public simple_text_entry {
+public:
+ right_text_entry(char *s, const entry_modifier *m);
+ void simple_print(int);
+ void add_tab();
+};
+
+class center_text_entry : public simple_text_entry {
+public:
+ center_text_entry(char *s, const entry_modifier *m);
+ void simple_print(int);
+ void add_tab();
+};
+
+class numeric_text_entry : public text_entry {
+ int dot_pos;
+public:
+ numeric_text_entry(char *s, const entry_modifier *m, int pos);
+ void do_width();
+ void simple_print(int);
+};
+
+class alphabetic_text_entry : public text_entry {
+public:
+ alphabetic_text_entry(char *s, const entry_modifier *m);
+ void do_width();
+ void simple_print(int);
+ void add_tab();
+};
+
+class line_entry : public simple_entry {
+protected:
+ char double_vrule_on_right;
+ char double_vrule_on_left;
+public:
+ line_entry(const entry_modifier *);
+ void note_double_vrule_on_right(int);
+ void note_double_vrule_on_left(int);
+ void simple_print(int) = 0;
+};
+
+class single_line_entry : public line_entry {
+public:
+ single_line_entry(const entry_modifier *m);
+ void simple_print(int);
+ single_line_entry *to_single_line_entry();
+ int line_type();
+};
+
+class double_line_entry : public line_entry {
+public:
+ double_line_entry(const entry_modifier *m);
+ void simple_print(int);
+ double_line_entry *to_double_line_entry();
+ int line_type();
+};
+
+class short_line_entry : public simple_entry {
+public:
+ short_line_entry(const entry_modifier *m);
+ void simple_print(int);
+ int line_type();
+};
+
+class short_double_line_entry : public simple_entry {
+public:
+ short_double_line_entry(const entry_modifier *m);
+ void simple_print(int);
+ int line_type();
+};
+
+class block_entry : public table_entry {
+ char *contents;
+protected:
+ void do_divert(int alphabetic, int ncols, const string *mw, int *sep);
+public:
+ block_entry(char *s, const entry_modifier *m);
+ ~block_entry();
+ int divert(int ncols, const string *mw, int *sep);
+ void do_width();
+ void do_depth();
+ void position_vertically();
+ void print() = 0;
+};
+
+class left_block_entry : public block_entry {
+public:
+ left_block_entry(char *s, const entry_modifier *m);
+ void print();
+};
+
+class right_block_entry : public block_entry {
+public:
+ right_block_entry(char *s, const entry_modifier *m);
+ void print();
+};
+
+class center_block_entry : public block_entry {
+public:
+ center_block_entry(char *s, const entry_modifier *m);
+ void print();
+};
+
+class alphabetic_block_entry : public block_entry {
+public:
+ alphabetic_block_entry(char *s, const entry_modifier *m);
+ void print();
+ int divert(int ncols, const string *mw, int *sep);
+};
+
+table_entry::table_entry(const entry_modifier *m)
+: next(0), start_row(-1), end_row(-1), start_col(-1), end_col(-1), mod(m),
+ input_lineno(-1), input_filename(0)
+{
+}
+
+table_entry::~table_entry()
+{
+}
+
+int table_entry::divert(int, const string *, int *)
+{
+ return 0;
+}
+
+void table_entry::do_width()
+{
+}
+
+single_line_entry *table_entry::to_single_line_entry()
+{
+ return 0;
+}
+
+double_line_entry *table_entry::to_double_line_entry()
+{
+ return 0;
+}
+
+simple_entry *table_entry::to_simple_entry()
+{
+ return 0;
+}
+
+void table_entry::do_depth()
+{
+}
+
+void table_entry::set_location()
+{
+ set_troff_location(input_filename, input_lineno);
+}
+
+int table_entry::line_type()
+{
+ return -1;
+}
+
+void table_entry::note_double_vrule_on_right(int)
+{
+}
+
+void table_entry::note_double_vrule_on_left(int)
+{
+}
+
+simple_entry::simple_entry(const entry_modifier *m) : table_entry(m)
+{
+}
+
+void simple_entry::add_tab()
+{
+ // do nothing
+}
+
+void simple_entry::simple_print(int)
+{
+ // do nothing
+}
+
+void simple_entry::position_vertically()
+{
+ if (start_row != end_row)
+ switch (mod->vertical_alignment) {
+ case entry_modifier::TOP:
+ printfs(".sp |\\n[%1]u\n", row_start_reg(start_row));
+ break;
+ case entry_modifier::CENTER:
+ // Peform the motion in two stages so that the center is rounded
+ // vertically upwards even if net vertical motion is upwards.
+ printfs(".sp |\\n[%1]u\n", row_start_reg(start_row));
+ printfs(".sp \\n[" BOTTOM_REG "]u-\\n[%1]u-1v/2u\n",
+ row_start_reg(start_row));
+ break;
+ case entry_modifier::BOTTOM:
+ printfs(".sp |\\n[%1]u+\\n[" BOTTOM_REG "]u-\\n[%1]u-1v\n",
+ row_start_reg(start_row));
+ break;
+ default:
+ assert(0);
+ }
+}
+
+void simple_entry::print()
+{
+ prints(".ta");
+ add_tab();
+ prints('\n');
+ set_location();
+ prints("\\&");
+ simple_print(0);
+ prints('\n');
+}
+
+simple_entry *simple_entry::to_simple_entry()
+{
+ return this;
+}
+
+empty_entry::empty_entry(const entry_modifier *m)
+: simple_entry(m)
+{
+}
+
+int empty_entry::line_type()
+{
+ return 0;
+}
+
+text_entry::text_entry(char *s, const entry_modifier *m)
+: contents(s), simple_entry(m)
+{
+}
+
+text_entry::~text_entry()
+{
+ a_delete contents;
+}
+
+
+repeated_char_entry::repeated_char_entry(char *s, const entry_modifier *m)
+: text_entry(s, m)
+{
+}
+
+void repeated_char_entry::simple_print(int)
+{
+ printfs("\\h'|\\n[%1]u'", column_start_reg(start_col));
+ set_inline_modifier(mod);
+ printfs("\\l" DELIMITER_CHAR "\\n[%1]u\\&",
+ span_width_reg(start_col, end_col));
+ prints(contents);
+ prints(DELIMITER_CHAR);
+ restore_inline_modifier(mod);
+}
+
+simple_text_entry::simple_text_entry(char *s, const entry_modifier *m)
+: text_entry(s, m)
+{
+}
+
+void simple_text_entry::do_width()
+{
+ set_location();
+ printfs(".nr %1 \\n[%1]>?\\w" DELIMITER_CHAR,
+ span_width_reg(start_col, end_col));
+ print_contents();
+ prints(DELIMITER_CHAR "\n");
+}
+
+left_text_entry::left_text_entry(char *s, const entry_modifier *m)
+: simple_text_entry(s, m)
+{
+}
+
+void left_text_entry::simple_print(int)
+{
+ printfs("\\h'|\\n[%1]u'", column_start_reg(start_col));
+ print_contents();
+}
+
+// The only point of this is to make `\a' ``work'' as in Unix tbl. Grrr.
+
+void left_text_entry::add_tab()
+{
+ printfs(" \\n[%1]u", column_end_reg(end_col));
+}
+
+right_text_entry::right_text_entry(char *s, const entry_modifier *m)
+: simple_text_entry(s, m)
+{
+}
+
+void right_text_entry::simple_print(int)
+{
+ printfs("\\h'|\\n[%1]u'", column_start_reg(start_col));
+ prints("\002\003");
+ print_contents();
+ prints("\002");
+}
+
+void right_text_entry::add_tab()
+{
+ printfs(" \\n[%1]u", column_end_reg(end_col));
+}
+
+center_text_entry::center_text_entry(char *s, const entry_modifier *m)
+: simple_text_entry(s, m)
+{
+}
+
+void center_text_entry::simple_print(int)
+{
+ printfs("\\h'|\\n[%1]u'", column_start_reg(start_col));
+ prints("\002\003");
+ print_contents();
+ prints("\003\002");
+}
+
+void center_text_entry::add_tab()
+{
+ printfs(" \\n[%1]u", column_end_reg(end_col));
+}
+
+numeric_text_entry::numeric_text_entry(char *s, const entry_modifier *m, int pos)
+: text_entry(s, m), dot_pos(pos)
+{
+}
+
+void numeric_text_entry::do_width()
+{
+ if (dot_pos != 0) {
+ set_location();
+ printfs(".nr %1 0\\w" DELIMITER_CHAR,
+ block_width_reg(start_row, start_col));
+ set_inline_modifier(mod);
+ for (int i = 0; i < dot_pos; i++)
+ prints(contents[i]);
+ restore_inline_modifier(mod);
+ prints(DELIMITER_CHAR "\n");
+ printfs(".nr %1 \\n[%1]>?\\n[%2]\n",
+ span_left_numeric_width_reg(start_col, end_col),
+ block_width_reg(start_row, start_col));
+ }
+ else
+ printfs(".nr %1 0\n", block_width_reg(start_row, start_col));
+ if (contents[dot_pos] != '\0') {
+ set_location();
+ printfs(".nr %1 \\n[%1]>?\\w" DELIMITER_CHAR,
+ span_right_numeric_width_reg(start_col, end_col));
+ set_inline_modifier(mod);
+ prints(contents + dot_pos);
+ restore_inline_modifier(mod);
+ prints(DELIMITER_CHAR "\n");
+ }
+}
+
+void numeric_text_entry::simple_print(int)
+{
+ printfs("\\h'|(\\n[%1]u-\\n[%2]u-\\n[%3]u/2u+\\n[%2]u+\\n[%4]u-\\n[%5]u)'",
+ span_width_reg(start_col, end_col),
+ span_left_numeric_width_reg(start_col, end_col),
+ span_right_numeric_width_reg(start_col, end_col),
+ column_start_reg(start_col),
+ block_width_reg(start_row, start_col));
+ print_contents();
+}
+
+alphabetic_text_entry::alphabetic_text_entry(char *s, const entry_modifier *m)
+: text_entry(s, m)
+{
+}
+
+void alphabetic_text_entry::do_width()
+{
+ set_location();
+ printfs(".nr %1 \\n[%1]>?\\w" DELIMITER_CHAR,
+ span_alphabetic_width_reg(start_col, end_col));
+ print_contents();
+ prints(DELIMITER_CHAR "\n");
+}
+
+void alphabetic_text_entry::simple_print(int)
+{
+ printfs("\\h'|\\n[%1]u'", column_start_reg(start_col));
+ printfs("\\h'\\n[%1]u-\\n[%2]u/2u'",
+ span_width_reg(start_col, end_col),
+ span_alphabetic_width_reg(start_col, end_col));
+ print_contents();
+}
+
+// The only point of this is to make `\a' ``work'' as in Unix tbl. Grrr.
+
+void alphabetic_text_entry::add_tab()
+{
+ printfs(" \\n[%1]u", column_end_reg(end_col));
+}
+
+block_entry::block_entry(char *s, const entry_modifier *m)
+: table_entry(m), contents(s)
+{
+}
+
+block_entry::~block_entry()
+{
+ a_delete contents;
+}
+
+void block_entry::position_vertically()
+{
+ if (start_row != end_row)
+ switch(mod->vertical_alignment) {
+ case entry_modifier::TOP:
+ printfs(".sp |\\n[%1]u\n", row_start_reg(start_row));
+ break;
+ case entry_modifier::CENTER:
+ // Peform the motion in two stages so that the center is rounded
+ // vertically upwards even if net vertical motion is upwards.
+ printfs(".sp |\\n[%1]u\n", row_start_reg(start_row));
+ printfs(".sp \\n[" BOTTOM_REG "]u-\\n[%1]u-\\n[%2]u/2u\n",
+ row_start_reg(start_row),
+ block_height_reg(start_row, start_col));
+ break;
+ case entry_modifier::BOTTOM:
+ printfs(".sp |\\n[%1]u+\\n[" BOTTOM_REG "]u-\\n[%1]u-\\n[%2]u\n",
+ row_start_reg(start_row),
+ block_height_reg(start_row, start_col));
+ break;
+ default:
+ assert(0);
+ }
+ if (mod->stagger)
+ prints(".sp -.5v\n");
+}
+
+int block_entry::divert(int ncols, const string *mw, int *sep)
+{
+ do_divert(0, ncols, mw, sep);
+ return 1;
+}
+
+void block_entry::do_divert(int alphabetic, int ncols, const string *mw,
+ int *sep)
+{
+ printfs(".di %1\n", block_diversion_name(start_row, start_col));
+ prints(".if \\n[" SAVED_FILL_REG "] .fi\n"
+ ".in 0\n");
+ prints(".ll ");
+ for (int i = start_col; i <= end_col; i++)
+ if (mw[i].empty())
+ break;
+ if (i > end_col) {
+ // Every column spanned by this entry has a minimum width.
+ for (int i = start_col; i <= end_col; i++) {
+ if (i > start_col) {
+ if (sep)
+ printfs("+%1n", as_string(sep[i - 1]));
+ prints('+');
+ }
+ printfs("(n;%1)", mw[i]);
+ }
+ printfs(">?\\n[%1]u", span_width_reg(start_col, end_col));
+ }
+ else
+ printfs("(u;\\n[%1]>?(\\n[.l]*%2/%3))",
+ span_width_reg(start_col, end_col),
+ as_string(end_col - start_col + 1),
+ as_string(ncols + 1));
+ if (alphabetic)
+ prints("-2n");
+ prints("\n");
+ set_modifier(mod);
+ prints(".cp \\n(" COMPATIBLE_REG "\n");
+ set_location();
+ prints(contents);
+ prints(".br\n.di\n.cp 0\n");
+ if (!mod->zero_width) {
+ if (alphabetic) {
+ printfs(".nr %1 \\n[%1]>?(\\n[dl]+2n)\n",
+ span_width_reg(start_col, end_col));
+ printfs(".nr %1 \\n[%1]>?\\n[dl]\n",
+ span_alphabetic_width_reg(start_col, end_col));
+ }
+ else
+ printfs(".nr %1 \\n[%1]>?\\n[dl]\n", span_width_reg(start_col, end_col));
+ }
+ printfs(".nr %1 \\n[dn]\n", block_height_reg(start_row, start_col));
+ printfs(".nr %1 \\n[dl]\n", block_width_reg(start_row, start_col));
+ prints("." RESET_MACRO_NAME "\n"
+ ".in \\n[" SAVED_INDENT_REG "]u\n"
+ ".nf\n");
+ // the block might have contained .lf commands
+ location_force_filename = 1;
+}
+
+void block_entry::do_width()
+{
+ // do nothing; the action happens in divert
+}
+
+void block_entry::do_depth()
+{
+ printfs(".nr " BOTTOM_REG " \\n[" BOTTOM_REG "]>?(\\n[%1]+\\n[%2])\n",
+ row_start_reg(start_row),
+ block_height_reg(start_row, start_col));
+}
+
+left_block_entry::left_block_entry(char *s, const entry_modifier *m)
+: block_entry(s, m)
+{
+}
+
+void left_block_entry::print()
+{
+ printfs(".in +\\n[%1]u\n", column_start_reg(start_col));
+ printfs(".%1\n", block_diversion_name(start_row, start_col));
+ prints(".in\n");
+}
+
+
+
+right_block_entry::right_block_entry(char *s, const entry_modifier *m)
+: block_entry(s, m)
+{
+}
+
+void right_block_entry::print()
+{
+ printfs(".in +\\n[%1]u+\\n[%2]u-\\n[%3]u\n",
+ column_start_reg(start_col),
+ span_width_reg(start_col, end_col),
+ block_width_reg(start_row, start_col));
+ printfs(".%1\n", block_diversion_name(start_row, start_col));
+ prints(".in\n");
+}
+
+center_block_entry::center_block_entry(char *s, const entry_modifier *m)
+: block_entry(s, m)
+{
+}
+
+void center_block_entry::print()
+{
+ printfs(".in +\\n[%1]u+(\\n[%2]u-\\n[%3]u/2u)\n",
+ column_start_reg(start_col),
+ span_width_reg(start_col, end_col),
+ block_width_reg(start_row, start_col));
+ printfs(".%1\n", block_diversion_name(start_row, start_col));
+ prints(".in\n");
+}
+
+alphabetic_block_entry::alphabetic_block_entry(char *s,
+ const entry_modifier *m)
+: block_entry(s, m)
+{
+}
+
+int alphabetic_block_entry::divert(int ncols, const string *mw, int *sep)
+{
+ do_divert(1, ncols, mw, sep);
+ return 1;
+}
+
+void alphabetic_block_entry::print()
+{
+ printfs(".in +\\n[%1]u+(\\n[%2]u-\\n[%3]u/2u)\n",
+ column_start_reg(start_col),
+ span_width_reg(start_col, end_col),
+ span_alphabetic_width_reg(start_col, end_col));
+ printfs(".%1\n", block_diversion_name(start_row, start_col));
+ prints(".in\n");
+}
+
+line_entry::line_entry(const entry_modifier *m)
+: simple_entry(m), double_vrule_on_right(0), double_vrule_on_left(0)
+{
+}
+
+void line_entry::note_double_vrule_on_right(int is_corner)
+{
+ double_vrule_on_right = is_corner ? 1 : 2;
+}
+
+void line_entry::note_double_vrule_on_left(int is_corner)
+{
+ double_vrule_on_left = is_corner ? 1 : 2;
+}
+
+
+single_line_entry::single_line_entry(const entry_modifier *m)
+: line_entry(m)
+{
+}
+
+int single_line_entry::line_type()
+{
+ return 1;
+}
+
+void single_line_entry::simple_print(int dont_move)
+{
+ printfs("\\h'|\\n[%1]u",
+ column_divide_reg(start_col));
+ if (double_vrule_on_left) {
+ prints(double_vrule_on_left == 1 ? "-" : "+");
+ prints(HALF_DOUBLE_LINE_SEP);
+ }
+ prints("'");
+ if (!dont_move)
+ prints("\\v'-" BAR_HEIGHT "'");
+ printfs("\\s[\\n[" LINESIZE_REG "]]" "\\D'l |\\n[%1]u",
+ column_divide_reg(end_col+1));
+ if (double_vrule_on_right) {
+ prints(double_vrule_on_left == 1 ? "+" : "-");
+ prints(HALF_DOUBLE_LINE_SEP);
+ }
+ prints("0'\\s0");
+ if (!dont_move)
+ prints("\\v'" BAR_HEIGHT "'");
+}
+
+single_line_entry *single_line_entry::to_single_line_entry()
+{
+ return this;
+}
+
+double_line_entry::double_line_entry(const entry_modifier *m)
+: line_entry(m)
+{
+}
+
+int double_line_entry::line_type()
+{
+ return 2;
+}
+
+void double_line_entry::simple_print(int dont_move)
+{
+ if (!dont_move)
+ prints("\\v'-" BAR_HEIGHT "'");
+ printfs("\\h'|\\n[%1]u",
+ column_divide_reg(start_col));
+ if (double_vrule_on_left) {
+ prints(double_vrule_on_left == 1 ? "-" : "+");
+ prints(HALF_DOUBLE_LINE_SEP);
+ }
+ prints("'");
+ printfs("\\v'-" HALF_DOUBLE_LINE_SEP "'"
+ "\\s[\\n[" LINESIZE_REG "]]"
+ "\\D'l |\\n[%1]u",
+ column_divide_reg(end_col+1));
+ if (double_vrule_on_right)
+ prints("-" HALF_DOUBLE_LINE_SEP);
+ prints(" 0'");
+ printfs("\\v'" DOUBLE_LINE_SEP "'"
+ "\\D'l |\\n[%1]u",
+ column_divide_reg(start_col));
+ if (double_vrule_on_right) {
+ prints(double_vrule_on_left == 1 ? "+" : "-");
+ prints(HALF_DOUBLE_LINE_SEP);
+ }
+ prints(" 0'");
+ prints("\\s0"
+ "\\v'-" HALF_DOUBLE_LINE_SEP "'");
+ if (!dont_move)
+ prints("\\v'" BAR_HEIGHT "'");
+}
+
+double_line_entry *double_line_entry::to_double_line_entry()
+{
+ return this;
+}
+
+short_line_entry::short_line_entry(const entry_modifier *m)
+: simple_entry(m)
+{
+}
+
+int short_line_entry::line_type()
+{
+ return 1;
+}
+
+void short_line_entry::simple_print(int dont_move)
+{
+ if (mod->stagger)
+ prints("\\v'-.5v'");
+ if (!dont_move)
+ prints("\\v'-" BAR_HEIGHT "'");
+ printfs("\\h'|\\n[%1]u'", column_start_reg(start_col));
+ printfs("\\s[\\n[" LINESIZE_REG "]]"
+ "\\D'l \\n[%1]u 0'"
+ "\\s0",
+ span_width_reg(start_col, end_col));
+ if (!dont_move)
+ prints("\\v'" BAR_HEIGHT "'");
+ if (mod->stagger)
+ prints("\\v'.5v'");
+}
+
+short_double_line_entry::short_double_line_entry(const entry_modifier *m)
+: simple_entry(m)
+{
+}
+
+int short_double_line_entry::line_type()
+{
+ return 2;
+}
+
+void short_double_line_entry::simple_print(int dont_move)
+{
+ if (mod->stagger)
+ prints("\\v'-.5v'");
+ if (!dont_move)
+ prints("\\v'-" BAR_HEIGHT "'");
+ printfs("\\h'|\\n[%2]u'"
+ "\\v'-" HALF_DOUBLE_LINE_SEP "'"
+ "\\s[\\n[" LINESIZE_REG "]]"
+ "\\D'l \\n[%1]u 0'"
+ "\\v'" DOUBLE_LINE_SEP "'"
+ "\\D'l |\\n[%2]u 0'"
+ "\\s0"
+ "\\v'-" HALF_DOUBLE_LINE_SEP "'",
+ span_width_reg(start_col, end_col),
+ column_start_reg(start_col));
+ if (!dont_move)
+ prints("\\v'" BAR_HEIGHT "'");
+ if (mod->stagger)
+ prints("\\v'.5v'");
+}
+
+void set_modifier(const entry_modifier *m)
+{
+ if (!m->font.empty())
+ printfs(".ft %1\n", m->font);
+ if (m->point_size.val != 0) {
+ prints(".ps ");
+ if (m->point_size.inc > 0)
+ prints('+');
+ else if (m->point_size.inc < 0)
+ prints('-');
+ printfs("%1\n", as_string(m->point_size.val));
+ }
+ if (m->vertical_spacing.val != 0) {
+ prints(".vs ");
+ if (m->vertical_spacing.inc > 0)
+ prints('+');
+ else if (m->vertical_spacing.inc < 0)
+ prints('-');
+ printfs("%1\n", as_string(m->vertical_spacing.val));
+ }
+}
+
+void set_inline_modifier(const entry_modifier *m)
+{
+ if (!m->font.empty())
+ printfs("\\f[%1]", m->font);
+ if (m->point_size.val != 0) {
+ prints("\\s[");
+ if (m->point_size.inc > 0)
+ prints('+');
+ else if (m->point_size.inc < 0)
+ prints('-');
+ printfs("%1]", as_string(m->point_size.val));
+ }
+ if (m->stagger)
+ prints("\\v'-.5v'");
+}
+
+void restore_inline_modifier(const entry_modifier *m)
+{
+ if (!m->font.empty())
+ prints("\\f[\\n[" SAVED_FONT_REG "]]");
+ if (m->point_size.val != 0)
+ prints("\\s[\\n[" SAVED_SIZE_REG "]]");
+ if (m->stagger)
+ prints("\\v'.5v'");
+}
+
+
+struct stuff {
+ stuff *next;
+ int row; // occurs before row `row'
+ char printed; // has it been printed?
+
+ stuff(int);
+ virtual void print(table *) = 0;
+ virtual ~stuff();
+ virtual int is_single_line() { return 0; };
+ virtual int is_double_line() { return 0; };
+};
+
+stuff::stuff(int r) : row(r), next(0), printed(0)
+{
+}
+
+stuff::~stuff()
+{
+}
+
+struct text_stuff : public stuff {
+ string contents;
+ const char *filename;
+ int lineno;
+
+ text_stuff(const string &, int r, const char *fn, int ln);
+ ~text_stuff();
+ void print(table *);
+};
+
+
+text_stuff::text_stuff(const string &s, int r, const char *fn, int ln)
+: contents(s), stuff(r), filename(fn), lineno(ln)
+{
+}
+
+text_stuff::~text_stuff()
+{
+}
+
+void text_stuff::print(table *)
+{
+ printed = 1;
+ prints(".cp \\n(" COMPATIBLE_REG "\n");
+ set_troff_location(filename, lineno);
+ prints(contents);
+ prints(".cp 0\n");
+ location_force_filename = 1; // it might have been a .lf command
+}
+
+struct single_hline_stuff : public stuff {
+ single_hline_stuff(int r);
+ void print(table *);
+ int is_single_line();
+};
+
+single_hline_stuff::single_hline_stuff(int r) : stuff(r)
+{
+}
+
+void single_hline_stuff::print(table *tbl)
+{
+ printed = 1;
+ tbl->print_single_hline(row);
+}
+
+int single_hline_stuff::is_single_line()
+{
+ return 1;
+}
+
+struct double_hline_stuff : stuff {
+ double_hline_stuff(int r);
+ void print(table *);
+ int is_double_line();
+};
+
+double_hline_stuff::double_hline_stuff(int r) : stuff(r)
+{
+}
+
+void double_hline_stuff::print(table *tbl)
+{
+ printed = 1;
+ tbl->print_double_hline(row);
+}
+
+int double_hline_stuff::is_double_line()
+{
+ return 1;
+}
+
+struct vertical_rule {
+ vertical_rule *next;
+ short start_row;
+ short end_row;
+ short col;
+ char is_double;
+ string top_adjust;
+ string bot_adjust;
+
+ vertical_rule(int sr, int er, int c, int dbl, vertical_rule *);
+ ~vertical_rule();
+ void contribute_to_bottom_macro(table *);
+ void print();
+};
+
+vertical_rule::vertical_rule(int sr, int er, int c, int dbl, vertical_rule *p)
+: start_row(sr), end_row(er), col(c), is_double(dbl), next(p)
+{
+}
+
+vertical_rule::~vertical_rule()
+{
+}
+
+void vertical_rule::contribute_to_bottom_macro(table *tbl)
+{
+ printfs(".if \\n[" CURRENT_ROW_REG "]>=%1",
+ as_string(start_row));
+ if (end_row != tbl->get_nrows() - 1)
+ printfs("&(\\n[" CURRENT_ROW_REG "]<%1)",
+ as_string(end_row));
+ prints(" \\{");
+ printfs(".if %1<=\\n[" LAST_PASSED_ROW_REG "] .nr %2 \\n[#T]\n",
+ as_string(start_row),
+ row_top_reg(start_row));
+ const char *offset_table[3];
+ if (is_double) {
+ offset_table[0] = "-" HALF_DOUBLE_LINE_SEP;
+ offset_table[1] = "+" HALF_DOUBLE_LINE_SEP;
+ offset_table[2] = 0;
+ }
+ else {
+ offset_table[0] = "";
+ offset_table[1] = 0;
+ }
+ for (const char **offsetp = offset_table; *offsetp; offsetp++) {
+ prints(".sp -1\n"
+ "\\v'" BODY_DEPTH);
+ if (!bot_adjust.empty())
+ printfs("+%1", bot_adjust);
+ prints("'");
+ printfs("\\h'\\n[%1]u%3'\\s[\\n[" LINESIZE_REG "]]\\D'l 0 |\\n[%2]u-1v",
+ column_divide_reg(col),
+ row_top_reg(start_row),
+ *offsetp);
+ if (!bot_adjust.empty())
+ printfs("-(%1)", bot_adjust);
+ // don't perform the top adjustment if the top is actually #T
+ if (!top_adjust.empty())
+ printfs("+((%1)*(%2>\\n[" LAST_PASSED_ROW_REG "]))",
+ top_adjust,
+ as_string(start_row));
+ prints("'\\s0\n");
+ }
+ prints(".\\}\n");
+}
+
+void vertical_rule::print()
+{
+ printfs("\\*[" TRANSPARENT_STRING_NAME "]"
+ ".if %1<=\\*[" QUOTE_STRING_NAME "]\\n[" LAST_PASSED_ROW_REG "] "
+ ".nr %2 \\*[" QUOTE_STRING_NAME "]\\n[#T]\n",
+ as_string(start_row),
+ row_top_reg(start_row));
+ const char *offset_table[3];
+ if (is_double) {
+ offset_table[0] = "-" HALF_DOUBLE_LINE_SEP;
+ offset_table[1] = "+" HALF_DOUBLE_LINE_SEP;
+ offset_table[2] = 0;
+ }
+ else {
+ offset_table[0] = "";
+ offset_table[1] = 0;
+ }
+ for (const char **offsetp = offset_table; *offsetp; offsetp++) {
+ prints("\\*[" TRANSPARENT_STRING_NAME "].sp -1\n"
+ "\\*[" TRANSPARENT_STRING_NAME "]\\v'" BODY_DEPTH);
+ if (!bot_adjust.empty())
+ printfs("+%1", bot_adjust);
+ prints("'");
+ printfs("\\h'\\n[%1]u%3'"
+ "\\s[\\n[" LINESIZE_REG "]]"
+ "\\D'l 0 |\\*[" QUOTE_STRING_NAME "]\\n[%2]u-1v",
+ column_divide_reg(col),
+ row_top_reg(start_row),
+ *offsetp);
+ if (!bot_adjust.empty())
+ printfs("-(%1)", bot_adjust);
+ // don't perform the top adjustment if the top is actually #T
+ if (!top_adjust.empty())
+ printfs("+((%1)*(%2>\\*[" QUOTE_STRING_NAME "]\\n["
+ LAST_PASSED_ROW_REG "]))",
+ top_adjust,
+ as_string(start_row));
+ prints("'"
+ "\\s0\n");
+ }
+}
+
+table::table(int nc, unsigned f, int ls, char dpc)
+: ncolumns(nc), flags(f), linesize(ls), decimal_point_char(dpc),
+ nrows(0), allocated_rows(0), entry(0), entry_list(0),
+ entry_list_tailp(&entry_list),
+ left_separation(0), right_separation(0), stuff_list(0), vline(0),
+ vrule_list(0), row_is_all_lines(0), span_list(0)
+{
+ minimum_width = new string[ncolumns];
+ column_separation = ncolumns > 1 ? new int[ncolumns - 1] : 0;
+ equal = new char[ncolumns];
+ int i;
+ for (i = 0; i < ncolumns; i++)
+ equal[i] = 0;
+ for (i = 0; i < ncolumns-1; i++)
+ column_separation[i] = DEFAULT_COLUMN_SEPARATION;
+ delim[0] = delim[1] = '\0';
+}
+
+table::~table()
+{
+ for (int i = 0; i < nrows; i++) {
+ a_delete entry[i];
+ a_delete vline[i];
+ }
+ a_delete entry;
+ a_delete vline;
+ while (entry_list) {
+ table_entry *tem = entry_list;
+ entry_list = entry_list->next;
+ delete tem;
+ }
+ ad_delete(ncolumns) minimum_width;
+ a_delete column_separation;
+ a_delete equal;
+ while (stuff_list) {
+ stuff *tem = stuff_list;
+ stuff_list = stuff_list->next;
+ delete tem;
+ }
+ while (vrule_list) {
+ vertical_rule *tem = vrule_list;
+ vrule_list = vrule_list->next;
+ delete tem;
+ }
+ a_delete row_is_all_lines;
+ while (span_list) {
+ horizontal_span *tem = span_list;
+ span_list = span_list->next;
+ delete tem;
+ }
+}
+
+void table::set_delim(char c1, char c2)
+{
+ delim[0] = c1;
+ delim[1] = c2;
+}
+
+void table::set_minimum_width(int c, const string &w)
+{
+ assert(c >= 0 && c < ncolumns);
+ minimum_width[c] = w;
+}
+
+void table::set_column_separation(int c, int n)
+{
+ assert(c >= 0 && c < ncolumns - 1);
+ column_separation[c] = n;
+}
+
+void table::set_equal_column(int c)
+{
+ assert(c >= 0 && c < ncolumns);
+ equal[c] = 1;
+}
+
+void table::add_stuff(stuff *p)
+{
+ for (stuff **pp = &stuff_list; *pp; pp = &(*pp)->next)
+ ;
+ *pp = p;
+}
+
+void table::add_text_line(int r, const string &s, const char *filename, int lineno)
+{
+ add_stuff(new text_stuff(s, r, filename, lineno));
+}
+
+void table::add_single_hline(int r)
+{
+ add_stuff(new single_hline_stuff(r));
+}
+
+void table::add_double_hline(int r)
+{
+ add_stuff(new double_hline_stuff(r));
+}
+
+void table::allocate(int r)
+{
+ if (r >= nrows) {
+ typedef table_entry **PPtable_entry; // work around g++ 1.36.1 bug
+ if (r >= allocated_rows) {
+ if (allocated_rows == 0) {
+ allocated_rows = 16;
+ if (allocated_rows <= r)
+ allocated_rows = r + 1;
+ entry = new PPtable_entry[allocated_rows];
+ vline = new char*[allocated_rows];
+ }
+ else {
+ table_entry ***old_entry = entry;
+ int old_allocated_rows = allocated_rows;
+ allocated_rows *= 2;
+ if (allocated_rows <= r)
+ allocated_rows = r + 1;
+ entry = new PPtable_entry[allocated_rows];
+ memcpy(entry, old_entry, sizeof(table_entry**)*old_allocated_rows);
+ a_delete old_entry;
+ char **old_vline = vline;
+ vline = new char*[allocated_rows];
+ memcpy(vline, old_vline, sizeof(char*)*old_allocated_rows);
+ a_delete old_vline;
+ }
+ }
+ assert(allocated_rows > r);
+ while (nrows <= r) {
+ entry[nrows] = new table_entry*[ncolumns];
+ for (int i = 0; i < ncolumns; i++)
+ entry[nrows][i] = 0;
+ vline[nrows] = new char[ncolumns+1];
+ for (i = 0; i < ncolumns+1; i++)
+ vline[nrows][i] = 0;
+ nrows++;
+ }
+ }
+}
+
+void table::do_hspan(int r, int c)
+{
+ assert(r >= 0 && c >= 0 && r < nrows && c < ncolumns);
+ if (c == 0) {
+ error("first column cannot be horizontally spanned");
+ return;
+ }
+ table_entry *e = entry[r][c];
+ if (e) {
+ assert(e->start_row <= r && r <= e->end_row
+ && e->start_col <= c && c <= e->end_col
+ && e->end_row - e->start_row > 0
+ && e->end_col - e->start_col > 0);
+ return;
+ }
+ e = entry[r][c-1];
+ // e can be 0 if we had an empty entry or an error
+ if (e == 0)
+ return;
+ if (e->start_row != r) {
+ /*
+ l l
+ ^ s */
+ error("impossible horizontal span at row %1, column %2", r + 1, c + 1);
+ }
+ else {
+ e->end_col = c;
+ entry[r][c] = e;
+ }
+}
+
+void table::do_vspan(int r, int c)
+{
+ assert(r >= 0 && c >= 0 && r < nrows && c < ncolumns);
+ if (r == 0) {
+ error("first row cannot be vertically spanned");
+ return;
+ }
+ table_entry *e = entry[r][c];
+ if (e) {
+ assert(e->start_row <= r && r <= e->end_row
+ && e->start_col <= c && c <= e->end_col
+ && e->end_row - e->start_row > 0
+ && e->end_col - e->start_col > 0);
+ return;
+ }
+ e = entry[r-1][c];
+ // e can be 0 if we had an empty entry or an error
+ if (e == 0)
+ return;
+ if (e->start_col != c) {
+ /* l s
+ l ^ */
+ error("impossible vertical span at row %1, column %2", r + 1, c + 1);
+ }
+ else {
+ for (int i = c; i <= e->end_col; i++) {
+ assert(entry[r][i] == 0);
+ entry[r][i] = e;
+ }
+ e->end_row = r;
+ }
+}
+
+int find_decimal_point(const char *s, char decimal_point_char,
+ const char *delim)
+{
+ if (s == 0 || *s == '\0')
+ return -1;
+ const char *p;
+ int in_delim = 0; // is p within eqn delimiters?
+ // tbl recognises \& even within eqn delimiters; I don't
+ for (p = s; *p; p++)
+ if (in_delim) {
+ if (*p == delim[1])
+ in_delim = 0;
+ }
+ else if (*p == delim[0])
+ in_delim = 1;
+ else if (p[0] == '\\' && p[1] == '&')
+ return p - s;
+ int possible_pos = -1;
+ in_delim = 0;
+ for (p = s; *p; p++)
+ if (in_delim) {
+ if (*p == delim[1])
+ in_delim = 0;
+ }
+ else if (*p == delim[0])
+ in_delim = 1;
+ else if (p[0] == decimal_point_char && csdigit(p[1]))
+ possible_pos = p - s;
+ if (possible_pos >= 0)
+ return possible_pos;
+ in_delim = 0;
+ for (p = s; *p; p++)
+ if (in_delim) {
+ if (*p == delim[1])
+ in_delim = 0;
+ }
+ else if (*p == delim[0])
+ in_delim = 1;
+ else if (csdigit(*p))
+ possible_pos = p + 1 - s;
+ return possible_pos;
+}
+
+void table::add_entry(int r, int c, const string &str, const entry_format *f,
+ const char *fn, int ln)
+{
+ allocate(r);
+ table_entry *e = 0;
+ if (str == "\\_") {
+ e = new short_line_entry(f);
+ }
+ else if (str == "\\=") {
+ e = new short_double_line_entry(f);
+ }
+ else if (str == "_") {
+ single_line_entry *lefte;
+ if (c > 0 && entry[r][c-1] != 0 &&
+ (lefte = entry[r][c-1]->to_single_line_entry()) != 0
+ && lefte->start_row == r
+ && lefte->mod->stagger == f->stagger) {
+ lefte->end_col = c;
+ entry[r][c] = lefte;
+ }
+ else
+ e = new single_line_entry(f);
+ }
+ else if (str == "=") {
+ double_line_entry *lefte;
+ if (c > 0 && entry[r][c-1] != 0 &&
+ (lefte = entry[r][c-1]->to_double_line_entry()) != 0
+ && lefte->start_row == r
+ && lefte->mod->stagger == f->stagger) {
+ lefte->end_col = c;
+ entry[r][c] = lefte;
+ }
+ else
+ e = new double_line_entry(f);
+ }
+ else if (str == "\\^") {
+ do_vspan(r, c);
+ }
+ else if (str.length() > 2 && str[0] == '\\' && str[1] == 'R') {
+ if (str.search('\n') >= 0)
+ error_with_file_and_line(fn, ln, "bad repeated character");
+ else {
+ char *s = str.substring(2, str.length() - 2).extract();
+ e = new repeated_char_entry(s, f);
+ }
+ }
+ else {
+ int is_block = str.search('\n') >= 0;
+ char *s;
+ switch (f->type) {
+ case FORMAT_SPAN:
+ assert(str.empty());
+ do_hspan(r, c);
+ break;
+ case FORMAT_LEFT:
+ if (!str.empty()) {
+ s = str.extract();
+ if (is_block)
+ e = new left_block_entry(s, f);
+ else
+ e = new left_text_entry(s, f);
+ }
+ else
+ e = new empty_entry(f);
+ break;
+ case FORMAT_CENTER:
+ if (!str.empty()) {
+ s = str.extract();
+ if (is_block)
+ e = new center_block_entry(s, f);
+ else
+ e = new center_text_entry(s, f);
+ }
+ else
+ e = new empty_entry(f);
+ break;
+ case FORMAT_RIGHT:
+ if (!str.empty()) {
+ s = str.extract();
+ if (is_block)
+ e = new right_block_entry(s, f);
+ else
+ e = new right_text_entry(s, f);
+ }
+ else
+ e = new empty_entry(f);
+ break;
+ case FORMAT_NUMERIC:
+ if (!str.empty()) {
+ s = str.extract();
+ if (is_block) {
+ error_with_file_and_line(fn, ln, "can't have numeric text block");
+ e = new left_block_entry(s, f);
+ }
+ else {
+ int pos = find_decimal_point(s, decimal_point_char, delim);
+ if (pos < 0)
+ e = new center_text_entry(s, f);
+ else
+ e = new numeric_text_entry(s, f, pos);
+ }
+ }
+ else
+ e = new empty_entry(f);
+ break;
+ case FORMAT_ALPHABETIC:
+ if (!str.empty()) {
+ s = str.extract();
+ if (is_block)
+ e = new alphabetic_block_entry(s, f);
+ else
+ e = new alphabetic_text_entry(s, f);
+ }
+ else
+ e = new empty_entry(f);
+ break;
+ case FORMAT_VSPAN:
+ do_vspan(r, c);
+ break;
+ case FORMAT_HLINE:
+ if (str.length() != 0)
+ error_with_file_and_line(fn, ln,
+ "non-empty data entry for `_' format ignored");
+ e = new single_line_entry(f);
+ break;
+ case FORMAT_DOUBLE_HLINE:
+ if (str.length() != 0)
+ error_with_file_and_line(fn, ln,
+ "non-empty data entry for `=' format ignored");
+ e = new double_line_entry(f);
+ break;
+ default:
+ assert(0);
+ }
+ }
+ if (e) {
+ table_entry *preve = entry[r][c];
+ if (preve) {
+ /* c s
+ ^ l */
+ error_with_file_and_line(fn, ln, "row %1, column %2 already spanned",
+ r + 1, c + 1);
+ delete e;
+ }
+ else {
+ e->input_lineno = ln;
+ e->input_filename = fn;
+ e->start_row = e->end_row = r;
+ e->start_col = e->end_col = c;
+ *entry_list_tailp = e;
+ entry_list_tailp = &e->next;
+ entry[r][c] = e;
+ }
+ }
+}
+
+// add vertical lines for row r
+
+void table::add_vlines(int r, const char *v)
+{
+ allocate(r);
+ for (int i = 0; i < ncolumns+1; i++)
+ vline[r][i] = v[i];
+}
+
+void table::check()
+{
+ table_entry *p = entry_list;
+ int i, j;
+ while (p) {
+ for (i = p->start_row; i <= p->end_row; i++)
+ for (j = p->start_col; j <= p->end_col; j++)
+ assert(entry[i][j] == p);
+ p = p->next;
+ }
+}
+
+void table::print()
+{
+ location_force_filename = 1;
+ check();
+ init_output();
+ determine_row_type();
+ compute_widths();
+ if (!(flags & CENTER))
+ prints(".if \\n[" SAVED_CENTER_REG "] \\{");
+ prints(".in +(u;\\n[.l]-\\n[.i]-\\n[TW]/2)\n"
+ ".nr " SAVED_INDENT_REG " \\n[.i]\n");
+ if (!(flags & CENTER))
+ prints(".\\}\n");
+ build_vrule_list();
+ define_bottom_macro();
+ do_top();
+ for (int i = 0; i < nrows; i++)
+ do_row(i);
+ do_bottom();
+}
+
+void table::determine_row_type()
+{
+ row_is_all_lines = new char[nrows];
+ for (int i = 0; i < nrows; i++) {
+ int had_single = 0;
+ int had_double = 0;
+ int had_non_line = 0;
+ for (int c = 0; c < ncolumns; c++) {
+ table_entry *e = entry[i][c];
+ if (e != 0) {
+ if (e->start_row == e->end_row) {
+ int t = e->line_type();
+ switch (t) {
+ case -1:
+ had_non_line = 1;
+ break;
+ case 0:
+ // empty
+ break;
+ case 1:
+ had_single = 1;
+ break;
+ case 2:
+ had_double = 1;
+ break;
+ default:
+ assert(0);
+ }
+ if (had_non_line)
+ break;
+ }
+ c = e->end_col;
+ }
+ }
+ if (had_non_line)
+ row_is_all_lines[i] = 0;
+ else if (had_double)
+ row_is_all_lines[i] = 2;
+ else if (had_single)
+ row_is_all_lines[i] = 1;
+ else
+ row_is_all_lines[i] = 0;
+ }
+}
+
+
+void table::init_output()
+{
+ prints(".nr " COMPATIBLE_REG " \\n(.C\n"
+ ".cp 0\n");
+ if (linesize > 0)
+ printfs(".nr " LINESIZE_REG " %1\n", as_string(linesize));
+ else
+ prints(".nr " LINESIZE_REG " \\n[.s]\n");
+ if (!(flags & CENTER))
+ prints(".nr " SAVED_CENTER_REG " \\n[.ce]\n");
+ prints(".de " RESET_MACRO_NAME "\n"
+ ".ft \\n[.f]\n"
+ ".ps \\n[.s]\n"
+ ".vs \\n[.v]u\n"
+ ".in \\n[.i]u\n"
+ ".ll \\n[.l]u\n"
+ ".ls \\n[.L]\n"
+ ".ad \\n[.j]\n"
+ ".ie \\n[.u] .fi\n"
+ ".el .nf\n"
+ ".ce \\n[.ce]\n"
+ "..\n"
+ ".nr " SAVED_INDENT_REG " \\n[.i]\n"
+ ".nr " SAVED_FONT_REG " \\n[.f]\n"
+ ".nr " SAVED_SIZE_REG " \\n[.s]\n"
+ ".nr " SAVED_FILL_REG " \\n[.u]\n"
+ ".nr T. 0\n"
+ ".nr " CURRENT_ROW_REG " 0-1\n"
+ ".nr " LAST_PASSED_ROW_REG " 0-1\n"
+ ".nr " SECTION_DIVERSION_FLAG_REG " 0\n"
+ ".ds " TRANSPARENT_STRING_NAME "\n"
+ ".ds " QUOTE_STRING_NAME "\n"
+ ".nr " NEED_BOTTOM_RULE_REG " 1\n"
+ ".nr " SUPPRESS_BOTTOM_REG " 0\n"
+ ".eo\n"
+ ".de " REPEATED_MARK_MACRO "\n"
+ ".mk \\$1\n"
+ ".if !'\\n(.z'' \\!." REPEATED_MARK_MACRO " \"\\$1\"\n"
+ "..\n"
+ ".de " REPEATED_VPT_MACRO "\n"
+ ".vpt \\$1\n"
+ ".if !'\\n(.z'' \\!." REPEATED_VPT_MACRO " \"\\$1\"\n"
+ "..\n");
+ if (!(flags & NOKEEP))
+ prints(".de " KEEP_MACRO_NAME "\n"
+ ".if '\\n[.z]'' \\{.ds " QUOTE_STRING_NAME " \\\\\n"
+ ".ds " TRANSPARENT_STRING_NAME " \\!\n"
+ ".di " SECTION_DIVERSION_NAME "\n"
+ ".nr " SECTION_DIVERSION_FLAG_REG " 1\n"
+ ".in 0\n"
+ ".\\}\n"
+ "..\n"
+ ".de " RELEASE_MACRO_NAME "\n"
+ ".if \\n[" SECTION_DIVERSION_FLAG_REG "] \\{"
+ ".di\n"
+ ".in \\n[" SAVED_INDENT_REG "]u\n"
+ ".nr " SAVED_DN_REG " \\n[dn]\n"
+ ".ds " QUOTE_STRING_NAME "\n"
+ ".ds " TRANSPARENT_STRING_NAME "\n"
+ ".nr " SECTION_DIVERSION_FLAG_REG " 0\n"
+ ".if \\n[.t]<=\\n[dn] \\{"
+ ".nr T. 1\n"
+ ".T#\n"
+ ".nr " SUPPRESS_BOTTOM_REG " 1\n"
+ ".sp \\n[.t]u\n"
+ ".nr " SUPPRESS_BOTTOM_REG " 0\n"
+ ".mk #T\n"
+ ".\\}\n"
+ ".if \\n[.t]<=\\n[" SAVED_DN_REG "] "
+ /* Since we turn off traps, it won't get into an infinite loop
+ when we try and print it; it will just go off the bottom of the
+ page. */
+ ".tm warning: page \\n%: table text block will not fit on one page\n"
+ ".nf\n"
+ ".ls 1\n"
+ "." SECTION_DIVERSION_NAME "\n"
+ ".ls\n"
+ ".rm " SECTION_DIVERSION_NAME "\n"
+ ".\\}\n"
+ "..\n"
+ ".nr " TABLE_DIVERSION_FLAG_REG " 0\n"
+ ".de " TABLE_KEEP_MACRO_NAME "\n"
+ ".if '\\n[.z]'' \\{"
+ ".di " TABLE_DIVERSION_NAME "\n"
+ ".nr " TABLE_DIVERSION_FLAG_REG " 1\n"
+ ".\\}\n"
+ "..\n"
+ ".de " TABLE_RELEASE_MACRO_NAME "\n"
+ ".if \\n[" TABLE_DIVERSION_FLAG_REG "] \\{.br\n"
+ ".di\n"
+ ".nr " SAVED_DN_REG " \\n[dn]\n"
+ ".ne \\n[dn]u+\\n[.V]u\n"
+ ".ie \\n[.t]<=\\n[" SAVED_DN_REG "] "
+ ".tm error: page \\n%: table will not fit on one page; use .TS H/.TH with a supporting macro package\n"
+ ".el \\{"
+ ".in 0\n"
+ ".ls 1\n"
+ ".nf\n"
+ "." TABLE_DIVERSION_NAME "\n"
+ ".\\}\n"
+ ".rm " TABLE_DIVERSION_NAME "\n"
+ ".\\}\n"
+ "..\n");
+ prints(".ec\n"
+ ".ce 0\n"
+ ".nf\n");
+}
+
+string block_width_reg(int r, int c)
+{
+ static char name[sizeof(BLOCK_WIDTH_PREFIX)+INT_DIGITS+1+INT_DIGITS];
+ sprintf(name, BLOCK_WIDTH_PREFIX "%d,%d", r, c);
+ return string(name);
+}
+
+string block_diversion_name(int r, int c)
+{
+ static char name[sizeof(BLOCK_DIVERSION_PREFIX)+INT_DIGITS+1+INT_DIGITS];
+ sprintf(name, BLOCK_DIVERSION_PREFIX "%d,%d", r, c);
+ return string(name);
+}
+
+string block_height_reg(int r, int c)
+{
+ static char name[sizeof(BLOCK_HEIGHT_PREFIX)+INT_DIGITS+1+INT_DIGITS];
+ sprintf(name, BLOCK_HEIGHT_PREFIX "%d,%d", r, c);
+ return string(name);
+}
+
+string span_width_reg(int start_col, int end_col)
+{
+ static char name[sizeof(SPAN_WIDTH_PREFIX)+INT_DIGITS+1+INT_DIGITS];
+ sprintf(name, SPAN_WIDTH_PREFIX "%d", start_col);
+ if (end_col != start_col)
+ sprintf(strchr(name, '\0'), ",%d", end_col);
+ return string(name);
+}
+
+string span_left_numeric_width_reg(int start_col, int end_col)
+{
+ static char name[sizeof(SPAN_LEFT_NUMERIC_WIDTH_PREFIX)+INT_DIGITS+1+INT_DIGITS];
+ sprintf(name, SPAN_LEFT_NUMERIC_WIDTH_PREFIX "%d", start_col);
+ if (end_col != start_col)
+ sprintf(strchr(name, '\0'), ",%d", end_col);
+ return string(name);
+}
+
+string span_right_numeric_width_reg(int start_col, int end_col)
+{
+ static char name[sizeof(SPAN_RIGHT_NUMERIC_WIDTH_PREFIX)+INT_DIGITS+1+INT_DIGITS];
+ sprintf(name, SPAN_RIGHT_NUMERIC_WIDTH_PREFIX "%d", start_col);
+ if (end_col != start_col)
+ sprintf(strchr(name, '\0'), ",%d", end_col);
+ return string(name);
+}
+
+string span_alphabetic_width_reg(int start_col, int end_col)
+{
+ static char name[sizeof(SPAN_ALPHABETIC_WIDTH_PREFIX)+INT_DIGITS+1+INT_DIGITS];
+ sprintf(name, SPAN_ALPHABETIC_WIDTH_PREFIX "%d", start_col);
+ if (end_col != start_col)
+ sprintf(strchr(name, '\0'), ",%d", end_col);
+ return string(name);
+}
+
+
+string column_separation_reg(int col)
+{
+ static char name[sizeof(COLUMN_SEPARATION_PREFIX)+INT_DIGITS];
+ sprintf(name, COLUMN_SEPARATION_PREFIX "%d", col);
+ return string(name);
+}
+
+string row_start_reg(int row)
+{
+ static char name[sizeof(ROW_START_PREFIX)+INT_DIGITS];
+ sprintf(name, ROW_START_PREFIX "%d", row);
+ return string(name);
+}
+
+string column_start_reg(int col)
+{
+ static char name[sizeof(COLUMN_START_PREFIX)+INT_DIGITS];
+ sprintf(name, COLUMN_START_PREFIX "%d", col);
+ return string(name);
+}
+
+string column_end_reg(int col)
+{
+ static char name[sizeof(COLUMN_END_PREFIX)+INT_DIGITS];
+ sprintf(name, COLUMN_END_PREFIX "%d", col);
+ return string(name);
+}
+
+string column_divide_reg(int col)
+{
+ static char name[sizeof(COLUMN_DIVIDE_PREFIX)+INT_DIGITS];
+ sprintf(name, COLUMN_DIVIDE_PREFIX "%d", col);
+ return string(name);
+}
+
+string row_top_reg(int row)
+{
+ static char name[sizeof(ROW_TOP_PREFIX)+INT_DIGITS];
+ sprintf(name, ROW_TOP_PREFIX "%d", row);
+ return string(name);
+}
+
+void init_span_reg(int start_col, int end_col)
+{
+ printfs(".nr %1 \\n(.H\n.nr %2 0\n.nr %3 0\n.nr %4 0\n",
+ span_width_reg(start_col, end_col),
+ span_alphabetic_width_reg(start_col, end_col),
+ span_left_numeric_width_reg(start_col, end_col),
+ span_right_numeric_width_reg(start_col, end_col));
+}
+
+void compute_span_width(int start_col, int end_col)
+{
+ printfs(".nr %1 \\n[%1]>?(\\n[%2]+\\n[%3])\n"
+ ".if \\n[%4] .nr %1 \\n[%1]>?(\\n[%4]+2n)\n",
+ span_width_reg(start_col, end_col),
+ span_left_numeric_width_reg(start_col, end_col),
+ span_right_numeric_width_reg(start_col, end_col),
+ span_alphabetic_width_reg(start_col, end_col));
+
+}
+
+// Increase the widths of columns so that the width of any spanning entry
+// is no greater than the sum of the widths of the columns that it spans.
+// Ensure that the widths of columns remain equal.
+
+void table::divide_span(int start_col, int end_col)
+{
+ assert(end_col > start_col);
+ printfs(".nr " NEEDED_REG " \\n[%1]-(\\n[%2]",
+ span_width_reg(start_col, end_col),
+ span_width_reg(start_col, start_col));
+ for (int i = start_col + 1; i <= end_col; i++) {
+ // The column separation may shrink with the expand option.
+ if (!(flags & EXPAND))
+ printfs("+%1n", as_string(column_separation[i - 1]));
+ printfs("+\\n[%1]", span_width_reg(i, i));
+ }
+ prints(")\n");
+ printfs(".nr " NEEDED_REG " \\n[" NEEDED_REG "]/%1\n",
+ as_string(end_col - start_col + 1));
+ prints(".if \\n[" NEEDED_REG "] \\{");
+ for (i = start_col; i <= end_col; i++)
+ printfs(".nr %1 +\\n[" NEEDED_REG "]\n",
+ span_width_reg(i, i));
+ int equal_flag = 0;
+ for (i = start_col; i <= end_col && !equal_flag; i++)
+ if (equal[i])
+ equal_flag = 1;
+ if (equal_flag) {
+ for (i = 0; i < ncolumns; i++)
+ if (i < start_col || i > end_col)
+ printfs(".nr %1 +\\n[" NEEDED_REG "]\n",
+ span_width_reg(i, i));
+ }
+ prints(".\\}\n");
+}
+
+
+void table::sum_columns(int start_col, int end_col)
+{
+ assert(end_col > start_col);
+ printfs(".nr %1 \\n[%2]",
+ span_width_reg(start_col, end_col),
+ span_width_reg(start_col, start_col));
+ for (int i = start_col + 1; i <= end_col; i++)
+ printfs("+(%1*\\n[" SEPARATION_FACTOR_REG "])+\\n[%2]",
+ as_string(column_separation[i - 1]),
+ span_width_reg(i, i));
+ prints('\n');
+}
+
+horizontal_span::horizontal_span(int sc, int ec, horizontal_span *p)
+: start_col(sc), end_col(ec), next(p)
+{
+}
+
+void table::build_span_list()
+{
+ span_list = 0;
+ table_entry *p = entry_list;
+ while (p) {
+ if (p->end_col != p->start_col) {
+ for (horizontal_span *q = span_list; q; q = q->next)
+ if (q->start_col == p->start_col
+ && q->end_col == p->end_col)
+ break;
+ if (!q)
+ span_list = new horizontal_span(p->start_col, p->end_col, span_list);
+ }
+ p = p->next;
+ }
+ // Now sort span_list primarily by order of end_row, and secondarily
+ // by reverse order of start_row. This ensures that if we divide
+ // spans using the order in span_list, we will get reasonable results.
+ horizontal_span *unsorted = span_list;
+ span_list = 0;
+ while (unsorted) {
+ for (horizontal_span **pp = &span_list; *pp; pp = &(*pp)->next)
+ if (unsorted->end_col < (*pp)->end_col
+ || (unsorted->end_col == (*pp)->end_col
+ && (unsorted->start_col > (*pp)->start_col)))
+ break;
+ horizontal_span *tem = unsorted->next;
+ unsorted->next = *pp;
+ *pp = unsorted;
+ unsorted = tem;
+ }
+}
+
+
+void table::compute_separation_factor()
+{
+ if (flags & (ALLBOX|BOX|DOUBLEBOX))
+ left_separation = right_separation = 1;
+ else {
+ for (int i = 0; i < nrows; i++) {
+ if (vline[i][0] > 0)
+ left_separation = 1;
+ if (vline[i][ncolumns] > 0)
+ right_separation = 1;
+ }
+ }
+ if (flags & EXPAND) {
+ int total_sep = left_separation + right_separation;
+ for (int i = 0; i < ncolumns - 1; i++)
+ total_sep += column_separation[i];
+ if (total_sep != 0) {
+ // Don't let the separation factor be negative.
+ prints(".nr " SEPARATION_FACTOR_REG " \\n[.l]-\\n[.i]");
+ for (i = 0; i < ncolumns; i++)
+ printfs("-\\n[%1]", span_width_reg(i, i));
+ printfs("/%1>?0\n", as_string(total_sep));
+ }
+ }
+}
+
+void table::compute_column_positions()
+{
+ printfs(".nr %1 0\n", column_divide_reg(0));
+ printfs(".nr %1 %2*\\n[" SEPARATION_FACTOR_REG "]\n",
+ column_start_reg(0),
+ as_string(left_separation));
+ for (int i = 1;; i++) {
+ printfs(".nr %1 \\n[%2]+\\n[%3]\n",
+ column_end_reg(i-1),
+ column_start_reg(i-1),
+ span_width_reg(i-1, i-1));
+ if (i >= ncolumns)
+ break;
+ printfs(".nr %1 \\n[%2]+(%3*\\n[" SEPARATION_FACTOR_REG "])\n",
+ column_start_reg(i),
+ column_end_reg(i-1),
+ as_string(column_separation[i-1]));
+ printfs(".nr %1 \\n[%2]+\\n[%3]/2\n",
+ column_divide_reg(i),
+ column_end_reg(i-1),
+ column_start_reg(i));
+ }
+ printfs(".nr %1 \\n[%2]+(%3*\\n[" SEPARATION_FACTOR_REG "])\n",
+ column_divide_reg(ncolumns),
+ column_end_reg(i-1),
+ as_string(right_separation));
+ printfs(".nr TW \\n[%1]\n",
+ column_divide_reg(ncolumns));
+ if (flags & DOUBLEBOX) {
+ printfs(".nr %1 +" DOUBLE_LINE_SEP "\n", column_divide_reg(0));
+ printfs(".nr %1 -" DOUBLE_LINE_SEP "\n", column_divide_reg(ncolumns));
+ }
+}
+
+void table::make_columns_equal()
+{
+ int first = -1; // index of first equal column
+ for (int i = 0; i < ncolumns; i++)
+ if (equal[i]) {
+ if (first < 0) {
+ printfs(".nr %1 \\n[%1]", span_width_reg(i, i));
+ first = i;
+ }
+ else
+ printfs(">?\\n[%1]", span_width_reg(i, i));
+ }
+ if (first >= 0) {
+ prints('\n');
+ for (i = first + 1; i < ncolumns; i++)
+ if (equal[i])
+ printfs(".nr %1 \\n[%2]\n",
+ span_width_reg(i, i),
+ span_width_reg(first, first));
+ }
+}
+
+void table::compute_widths()
+{
+ build_span_list();
+ int i;
+ horizontal_span *p;
+ prints(".nr " SEPARATION_FACTOR_REG " 1n\n");
+ for (i = 0; i < ncolumns; i++) {
+ init_span_reg(i, i);
+ if (!minimum_width[i].empty())
+ printfs(".nr %1 %2\n", span_width_reg(i, i), minimum_width[i]);
+ }
+ for (p = span_list; p; p = p->next)
+ init_span_reg(p->start_col, p->end_col);
+ table_entry *q;
+ for (q = entry_list; q; q = q->next)
+ if (!q->mod->zero_width)
+ q->do_width();
+ for (i = 0; i < ncolumns; i++)
+ compute_span_width(i, i);
+ for (p = span_list; p; p = p->next)
+ compute_span_width(p->start_col, p->end_col);
+ make_columns_equal();
+ // Note that divide_span keeps equal width columns equal.
+ for (p = span_list; p; p = p->next)
+ divide_span(p->start_col, p->end_col);
+ for (p = span_list; p; p = p->next)
+ sum_columns(p->start_col, p->end_col);
+ int had_spanning_block = 0;
+ int had_equal_block = 0;
+ for (q = entry_list; q; q = q->next)
+ if (q->divert(ncolumns, minimum_width,
+ (flags & EXPAND) ? column_separation : 0)) {
+ if (q->end_col > q->start_col)
+ had_spanning_block = 1;
+ for (i = q->start_col; i <= q->end_col && !had_equal_block; i++)
+ if (equal[i])
+ had_equal_block = 1;
+ }
+ if (had_equal_block)
+ make_columns_equal();
+ if (had_spanning_block)
+ for (p = span_list; p; p = p->next)
+ divide_span(p->start_col, p->end_col);
+ compute_separation_factor();
+ for (p = span_list; p; p = p->next)
+ sum_columns(p->start_col, p->end_col);
+ compute_column_positions();
+}
+
+void table::print_single_hline(int r)
+{
+ prints(".vs " LINE_SEP ">?\\n[.V]u\n"
+ ".ls 1\n"
+ "\\v'" BODY_DEPTH "'"
+ "\\s[\\n[" LINESIZE_REG "]]");
+ if (r > nrows - 1)
+ prints("\\D'l |\\n[TW]u 0'");
+ else {
+ int start_col = 0;
+ for (;;) {
+ while (start_col < ncolumns
+ && entry[r][start_col] != 0
+ && entry[r][start_col]->start_row != r)
+ start_col++;
+ for (int end_col = start_col;
+ end_col < ncolumns
+ && (entry[r][end_col] == 0
+ || entry[r][end_col]->start_row == r);
+ end_col++)
+ ;
+ if (end_col <= start_col)
+ break;
+ printfs("\\h'|\\n[%1]u",
+ column_divide_reg(start_col));
+ if ((r > 0 && vline[r-1][start_col] == 2)
+ || (r < nrows && vline[r][start_col] == 2))
+ prints("-" HALF_DOUBLE_LINE_SEP);
+ prints("'");
+ printfs("\\D'l |\\n[%1]u",
+ column_divide_reg(end_col));
+ if ((r > 0 && vline[r-1][end_col] == 2)
+ || (r < nrows && vline[r][end_col] == 2))
+ prints("+" HALF_DOUBLE_LINE_SEP);
+ prints(" 0'");
+ start_col = end_col;
+ }
+ }
+ prints("\\s0\n");
+ prints(".ls\n"
+ ".vs\n");
+}
+
+void table::print_double_hline(int r)
+{
+ prints(".vs " LINE_SEP "+" DOUBLE_LINE_SEP
+ ">?\\n[.V]u\n"
+ ".ls 1\n"
+ "\\v'" BODY_DEPTH "'"
+ "\\s[\\n[" LINESIZE_REG "]]");
+ if (r > nrows - 1)
+ prints("\\v'-" DOUBLE_LINE_SEP "'"
+ "\\D'l |\\n[TW]u 0'"
+ "\\v'" DOUBLE_LINE_SEP "'"
+ "\\h'|0'"
+ "\\D'l |\\n[TW]u 0'");
+ else {
+ int start_col = 0;
+ for (;;) {
+ while (start_col < ncolumns
+ && entry[r][start_col] != 0
+ && entry[r][start_col]->start_row != r)
+ start_col++;
+ for (int end_col = start_col;
+ end_col < ncolumns
+ && (entry[r][end_col] == 0
+ || entry[r][end_col]->start_row == r);
+ end_col++)
+ ;
+ if (end_col <= start_col)
+ break;
+ const char *left_adjust = 0;
+ if ((r > 0 && vline[r-1][start_col] == 2)
+ || (r < nrows && vline[r][start_col] == 2))
+ left_adjust = "-" HALF_DOUBLE_LINE_SEP;
+ const char *right_adjust = 0;
+ if ((r > 0 && vline[r-1][end_col] == 2)
+ || (r < nrows && vline[r][end_col] == 2))
+ right_adjust = "+" HALF_DOUBLE_LINE_SEP;
+ printfs("\\v'-" DOUBLE_LINE_SEP "'"
+ "\\h'|\\n[%1]u",
+ column_divide_reg(start_col));
+ if (left_adjust)
+ prints(left_adjust);
+ prints("'");
+ printfs("\\D'l |\\n[%1]u",
+ column_divide_reg(end_col));
+ if (right_adjust)
+ prints(right_adjust);
+ prints(" 0'");
+ printfs("\\v'" DOUBLE_LINE_SEP "'"
+ "\\h'|\\n[%1]u",
+ column_divide_reg(start_col));
+ if (left_adjust)
+ prints(left_adjust);
+ prints("'");
+ printfs("\\D'l |\\n[%1]u",
+ column_divide_reg(end_col));
+ if (right_adjust)
+ prints(right_adjust);
+ prints(" 0'");
+ start_col = end_col;
+ }
+ }
+ prints("\\s0\n"
+ ".ls\n"
+ ".vs\n");
+}
+
+void table::compute_vrule_top_adjust(int start_row, int col, string &result)
+{
+ if (row_is_all_lines[start_row] && start_row < nrows - 1) {
+ if (row_is_all_lines[start_row] == 2)
+ result = LINE_SEP ">?\\n[.V]u" "+" DOUBLE_LINE_SEP;
+ else
+ result = LINE_SEP ">?\\n[.V]u";
+ start_row++;
+ }
+ else {
+ result = "";
+ if (start_row == 0)
+ return;
+ for (stuff *p = stuff_list; p && p->row <= start_row; p = p->next)
+ if (p->row == start_row
+ && (p->is_single_line() || p->is_double_line()))
+ return;
+ }
+ int left = 0;
+ if (col > 0) {
+ table_entry *e = entry[start_row-1][col-1];
+ if (e && e->start_row == e->end_row) {
+ if (e->to_double_line_entry() != 0)
+ left = 2;
+ else if (e->to_single_line_entry() != 0)
+ left = 1;
+ }
+ }
+ int right = 0;
+ if (col < ncolumns) {
+ table_entry *e = entry[start_row-1][col];
+ if (e && e->start_row == e->end_row) {
+ if (e->to_double_line_entry() != 0)
+ right = 2;
+ else if (e->to_single_line_entry() != 0)
+ right = 1;
+ }
+ }
+ if (row_is_all_lines[start_row-1] == 0) {
+ if (left > 0 || right > 0) {
+ result += "-" BODY_DEPTH "-" BAR_HEIGHT;
+ if ((left == 2 && right != 2) || (right == 2 && left != 2))
+ result += "-" HALF_DOUBLE_LINE_SEP;
+ else if (left == 2 && right == 2)
+ result += "+" HALF_DOUBLE_LINE_SEP;
+ }
+ }
+ else if (row_is_all_lines[start_row-1] == 2) {
+ if ((left == 2 && right != 2) || (right == 2 && left != 2))
+ result += "-" DOUBLE_LINE_SEP;
+ else if (left == 1 || right == 1)
+ result += "-" HALF_DOUBLE_LINE_SEP;
+ }
+}
+
+void table::compute_vrule_bot_adjust(int end_row, int col, string &result)
+{
+ if (row_is_all_lines[end_row] && end_row > 0) {
+ end_row--;
+ result = "";
+ }
+ else {
+ for (stuff *p = stuff_list; p && p->row < end_row + 1; p = p->next)
+ ;
+ if (p && p->row == end_row + 1 && p->is_double_line()) {
+ result = "-" DOUBLE_LINE_SEP;
+ return;
+ }
+ if ((p != 0 && p->row == end_row + 1)
+ || end_row == nrows - 1) {
+ result = "";
+ return;
+ }
+ if (row_is_all_lines[end_row+1] == 1)
+ result = LINE_SEP;
+ else if (row_is_all_lines[end_row+1] == 2)
+ result = LINE_SEP "+" DOUBLE_LINE_SEP;
+ else
+ result = "";
+ }
+ int left = 0;
+ if (col > 0) {
+ table_entry *e = entry[end_row+1][col-1];
+ if (e && e->start_row == e->end_row) {
+ if (e->to_double_line_entry() != 0)
+ left = 2;
+ else if (e->to_single_line_entry() != 0)
+ left = 1;
+ }
+ }
+ int right = 0;
+ if (col < ncolumns) {
+ table_entry *e = entry[end_row+1][col];
+ if (e && e->start_row == e->end_row) {
+ if (e->to_double_line_entry() != 0)
+ right = 2;
+ else if (e->to_single_line_entry() != 0)
+ right = 1;
+ }
+ }
+ if (row_is_all_lines[end_row+1] == 0) {
+ if (left > 0 || right > 0) {
+ result = "1v-" BODY_DEPTH "-" BAR_HEIGHT;
+ if ((left == 2 && right != 2) || (right == 2 && left != 2))
+ result += "+" HALF_DOUBLE_LINE_SEP;
+ else if (left == 2 && right == 2)
+ result += "-" HALF_DOUBLE_LINE_SEP;
+ }
+ }
+ else if (row_is_all_lines[end_row+1] == 2) {
+ if (left == 2 && right == 2)
+ result += "-" DOUBLE_LINE_SEP;
+ else if (left != 2 && right != 2 && (left == 1 || right == 1))
+ result += "-" HALF_DOUBLE_LINE_SEP;
+ }
+}
+
+void table::add_vertical_rule(int start_row, int end_row, int col, int is_double)
+{
+ vrule_list = new vertical_rule(start_row, end_row, col, is_double,
+ vrule_list);
+ compute_vrule_top_adjust(start_row, col, vrule_list->top_adjust);
+ compute_vrule_bot_adjust(end_row, col, vrule_list->bot_adjust);
+}
+
+void table::build_vrule_list()
+{
+ int col;
+ if (flags & ALLBOX) {
+ for (col = 1; col < ncolumns; col++) {
+ int start_row = 0;
+ for (;;) {
+ while (start_row < nrows && vline_spanned(start_row, col))
+ start_row++;
+ if (start_row >= nrows)
+ break;
+ int end_row = start_row;
+ while (end_row < nrows && !vline_spanned(end_row, col))
+ end_row++;
+ end_row--;
+ add_vertical_rule(start_row, end_row, col, 0);
+ start_row = end_row + 1;
+ }
+ }
+ }
+ if (flags & (BOX|ALLBOX|DOUBLEBOX)) {
+ add_vertical_rule(0, nrows - 1, 0, 0);
+ add_vertical_rule(0, nrows - 1, ncolumns, 0);
+ }
+ for (int end_row = 0; end_row < nrows; end_row++)
+ for (col = 0; col < ncolumns+1; col++)
+ if (vline[end_row][col] > 0
+ && !vline_spanned(end_row, col)
+ && (end_row == nrows - 1
+ || vline[end_row+1][col] != vline[end_row][col]
+ || vline_spanned(end_row+1, col))) {
+ for (int start_row = end_row - 1;
+ start_row >= 0
+ && vline[start_row][col] == vline[end_row][col]
+ && !vline_spanned(start_row, col);
+ start_row--)
+ ;
+ start_row++;
+ add_vertical_rule(start_row, end_row, col, vline[end_row][col] > 1);
+ }
+ for (vertical_rule *p = vrule_list; p; p = p->next)
+ if (p->is_double)
+ for (int r = p->start_row; r <= p->end_row; r++) {
+ if (p->col > 0 && entry[r][p->col-1] != 0
+ && entry[r][p->col-1]->end_col == p->col-1) {
+ int is_corner = r == p->start_row || r == p->end_row;
+ entry[r][p->col-1]->note_double_vrule_on_right(is_corner);
+ }
+ if (p->col < ncolumns && entry[r][p->col] != 0
+ && entry[r][p->col]->start_col == p->col) {
+ int is_corner = r == p->start_row || r == p->end_row;
+ entry[r][p->col]->note_double_vrule_on_left(is_corner);
+ }
+ }
+}
+
+void table::define_bottom_macro()
+{
+ prints(".eo\n"
+ ".de T#\n"
+ ".if !\\n[" SUPPRESS_BOTTOM_REG "] \\{"
+ "." REPEATED_VPT_MACRO " 0\n"
+ ".mk " SAVED_VERTICAL_POS_REG "\n");
+ if (flags & (BOX|ALLBOX|DOUBLEBOX)) {
+ prints(".if \\n[T.]&\\n[" NEED_BOTTOM_RULE_REG "] \\{");
+ print_single_hline(0);
+ prints(".\\}\n");
+ }
+ prints(".ls 1\n");
+ for (vertical_rule *p = vrule_list; p; p = p->next)
+ p->contribute_to_bottom_macro(this);
+ if (flags & DOUBLEBOX)
+ prints(".if \\n[T.] \\{.vs " DOUBLE_LINE_SEP ">?\\n[.V]u\n"
+ "\\v'" BODY_DEPTH "'\\s[\\n[" LINESIZE_REG "]]"
+ "\\D'l \\n[TW]u 0'\\s0\n"
+ ".vs\n"
+ ".\\}\n"
+ ".if \\n[" LAST_PASSED_ROW_REG "]>=0 "
+ ".nr " TOP_REG " \\n[#T]-" DOUBLE_LINE_SEP "\n"
+ ".sp -1\n"
+ "\\v'" BODY_DEPTH "'\\s[\\n[" LINESIZE_REG "]]"
+ "\\D'l 0 |\\n[" TOP_REG "]u-1v'\\s0\n"
+ ".sp -1\n"
+ "\\v'" BODY_DEPTH "'\\h'|\\n[TW]u'\\s[\\n[" LINESIZE_REG "]]"
+ "\\D'l 0 |\\n[" TOP_REG "]u-1v'\\s0\n");
+ prints(".ls\n");
+ prints(".nr " LAST_PASSED_ROW_REG " \\n[" CURRENT_ROW_REG "]\n"
+ ".sp |\\n[" SAVED_VERTICAL_POS_REG "]u\n"
+ "." REPEATED_VPT_MACRO " 1\n"
+ ".\\}\n"
+ "..\n"
+ ".ec\n");
+}
+
+
+// is the vertical line before column c in row r horizontally spanned?
+
+int table::vline_spanned(int r, int c)
+{
+ assert(r >= 0 && r < nrows && c >= 0 && c < ncolumns + 1);
+ return (c != 0 && c != ncolumns && entry[r][c] != 0
+ && entry[r][c]->start_col != c
+ // horizontally spanning lines don't count
+ && entry[r][c]->to_double_line_entry() == 0
+ && entry[r][c]->to_single_line_entry() == 0);
+}
+
+int table::row_begins_section(int r)
+{
+ assert(r >= 0 && r < nrows);
+ for (int i = 0; i < ncolumns; i++)
+ if (entry[r][i] && entry[r][i]->start_row != r)
+ return 0;
+ return 1;
+}
+
+int table::row_ends_section(int r)
+{
+ assert(r >= 0 && r < nrows);
+ for (int i = 0; i < ncolumns; i++)
+ if (entry[r][i] && entry[r][i]->end_row != r)
+ return 0;
+ return 1;
+}
+
+void table::do_row(int r)
+{
+ if (!(flags & NOKEEP) && row_begins_section(r))
+ prints("." KEEP_MACRO_NAME "\n");
+ int had_line = 0;
+ for (stuff *p = stuff_list; p && p->row < r; p = p->next)
+ ;
+ for (stuff *p1 = p; p1 && p1->row == r; p1 = p1->next)
+ if (!p1->printed && (p1->is_single_line() || p1->is_double_line())) {
+ had_line = 1;
+ break;
+ }
+ if (!had_line && !row_is_all_lines[r])
+ printfs("." REPEATED_MARK_MACRO " %1\n", row_top_reg(r));
+ had_line = 0;
+ for (; p && p->row == r; p = p->next)
+ if (!p->printed) {
+ p->print(this);
+ if (!had_line && (p->is_single_line() || p->is_double_line())) {
+ printfs("." REPEATED_MARK_MACRO " %1\n", row_top_reg(r));
+ had_line = 1;
+ }
+ }
+ // Change the row *after* printing the stuff list (which might contain .TH).
+ printfs("\\*[" TRANSPARENT_STRING_NAME "].nr " CURRENT_ROW_REG " %1\n",
+ as_string(r));
+ if (!had_line && row_is_all_lines[r])
+ printfs("." REPEATED_MARK_MACRO " %1\n", row_top_reg(r));
+ // we might have had a .TH, for example, since we last tried
+ if (!(flags & NOKEEP) && row_begins_section(r))
+ prints("." KEEP_MACRO_NAME "\n");
+ printfs(".mk %1\n", row_start_reg(r));
+ prints(".mk " BOTTOM_REG "\n"
+ "." REPEATED_VPT_MACRO " 0\n");
+ int c;
+ int row_is_blank = 1;
+ int first_start_row = r;
+ for (c = 0; c < ncolumns; c++) {
+ table_entry *e = entry[r][c];
+ if (e) {
+ if (e->end_row == r) {
+ e->do_depth();
+ if (e->start_row < first_start_row)
+ first_start_row = e->start_row;
+ row_is_blank = 0;
+ }
+ c = e->end_col;
+ }
+ }
+ if (row_is_blank)
+ prints(".nr " BOTTOM_REG " +1v\n");
+ if (row_is_all_lines[r]) {
+ prints(".vs " LINE_SEP);
+ if (row_is_all_lines[r] == 2)
+ prints("+" DOUBLE_LINE_SEP);
+ prints(">?\\n[.V]u\n.ls 1\n");
+ prints("\\&");
+ prints("\\v'" BODY_DEPTH);
+ if (row_is_all_lines[r] == 2)
+ prints("-" HALF_DOUBLE_LINE_SEP);
+ prints("'");
+ for (c = 0; c < ncolumns; c++) {
+ table_entry *e = entry[r][c];
+ if (e) {
+ if (e->end_row == e->start_row)
+ e->to_simple_entry()->simple_print(1);
+ c = e->end_col;
+ }
+ }
+ prints("\n");
+ prints(".ls\n"
+ ".vs\n");
+ prints(".nr " BOTTOM_REG " \\n[" BOTTOM_REG "]>?\\n[.d]\n");
+ printfs(".sp |\\n[%1]u\n", row_start_reg(r));
+ }
+ for (int i = row_is_all_lines[r] ? r - 1 : r;
+ i >= first_start_row;
+ i--) {
+ simple_entry *first = 0;
+ for (c = 0; c < ncolumns; c++) {
+ table_entry *e = entry[r][c];
+ if (e) {
+ if (e->end_row == r && e->start_row == i) {
+ simple_entry *simple = e->to_simple_entry();
+ if (simple) {
+ if (!first) {
+ prints(".ta");
+ first = simple;
+ }
+ simple->add_tab();
+ }
+ }
+ c = e->end_col;
+ }
+ }
+ if (first) {
+ prints('\n');
+ first->position_vertically();
+ first->set_location();
+ prints("\\&");
+ first->simple_print(0);
+ for (c = first->end_col + 1; c < ncolumns; c++) {
+ table_entry *e = entry[r][c];
+ if (e) {
+ if (e->end_row == r && e->start_row == i) {
+ simple_entry *simple = e->to_simple_entry();
+ if (simple)
+ simple->simple_print(0);
+ }
+ c = e->end_col;
+ }
+ }
+ prints('\n');
+ prints(".nr " BOTTOM_REG " \\n[" BOTTOM_REG "]>?\\n[.d]\n");
+ printfs(".sp |\\n[%1]u\n", row_start_reg(r));
+ }
+ }
+ for (c = 0; c < ncolumns; c++) {
+ table_entry *e = entry[r][c];
+ if (e) {
+ if (e->end_row == r && e->to_simple_entry() == 0) {
+ e->position_vertically();
+ e->print();
+ prints(".nr " BOTTOM_REG " \\n[" BOTTOM_REG "]>?\\n[.d]\n");
+ printfs(".sp |\\n[%1]u\n", row_start_reg(r));
+ }
+ c = e->end_col;
+ }
+ }
+ prints("." REPEATED_VPT_MACRO " 1\n"
+ ".sp |\\n[" BOTTOM_REG "]u\n"
+ "\\*[" TRANSPARENT_STRING_NAME "].nr " NEED_BOTTOM_RULE_REG " 1\n");
+ if (r != nrows - 1 && (flags & ALLBOX)) {
+ print_single_hline(r + 1);
+ prints("\\*[" TRANSPARENT_STRING_NAME "].nr " NEED_BOTTOM_RULE_REG " 0\n");
+ }
+ if (r != nrows - 1) {
+ if (p && p->row == r + 1
+ && (p->is_single_line() || p->is_double_line())) {
+ p->print(this);
+ prints("\\*[" TRANSPARENT_STRING_NAME "].nr " NEED_BOTTOM_RULE_REG
+ " 0\n");
+ }
+ int printed_one = 0;
+ for (vertical_rule *p = vrule_list; p; p = p->next)
+ if (p->end_row == r) {
+ if (!printed_one) {
+ prints("." REPEATED_VPT_MACRO " 0\n");
+ printed_one = 1;
+ }
+ p->print();
+ }
+ if (printed_one)
+ prints("." REPEATED_VPT_MACRO " 1\n");
+ if (!(flags & NOKEEP) && row_ends_section(r))
+ prints("." RELEASE_MACRO_NAME "\n");
+ }
+}
+
+void table::do_top()
+{
+ prints(".fc \002\003\n");
+ if (!(flags & NOKEEP) && (flags & (BOX|DOUBLEBOX|ALLBOX)))
+ prints("." TABLE_KEEP_MACRO_NAME "\n");
+ if (flags & DOUBLEBOX) {
+ prints(".ls 1\n"
+ ".vs " LINE_SEP ">?\\n[.V]u\n"
+ "\\v'" BODY_DEPTH "'\\s[\\n[" LINESIZE_REG "]]\\D'l \\n[TW]u 0'\\s0\n"
+ ".vs\n"
+ "." REPEATED_MARK_MACRO " " TOP_REG "\n"
+ ".vs " DOUBLE_LINE_SEP ">?\\n[.V]u\n");
+ printfs("\\v'" BODY_DEPTH "'"
+ "\\s[\\n[" LINESIZE_REG "]]"
+ "\\h'\\n[%1]u'"
+ "\\D'l |\\n[%2]u 0'"
+ "\\s0"
+ "\n",
+ column_divide_reg(0),
+ column_divide_reg(ncolumns));
+ prints(".ls\n"
+ ".vs\n");
+ }
+ else if (flags & (ALLBOX|BOX)) {
+ print_single_hline(0);
+ }
+ //printfs(".mk %1\n", row_top_reg(0));
+}
+
+void table::do_bottom()
+{
+ // print stuff after last row
+ for (stuff *p = stuff_list; p; p = p->next)
+ if (p->row > nrows - 1)
+ p->print(this);
+ if (!(flags & NOKEEP))
+ prints("." RELEASE_MACRO_NAME "\n");
+ printfs(".mk %1\n", row_top_reg(nrows));
+ prints(".nr " NEED_BOTTOM_RULE_REG " 1\n"
+ ".nr T. 1\n"
+ ".T#\n");
+ if (!(flags & NOKEEP) && (flags & (BOX|DOUBLEBOX|ALLBOX)))
+ prints("." TABLE_RELEASE_MACRO_NAME "\n");
+ if (flags & DOUBLEBOX)
+ prints(".sp " DOUBLE_LINE_SEP "\n");
+ prints("." RESET_MACRO_NAME "\n"
+ ".fc\n"
+ ".cp \\n(" COMPATIBLE_REG "\n");
+}
+
+int table::get_nrows()
+{
+ return nrows;
+}
+
+const char *last_filename = 0;
+
+void set_troff_location(const char *fn, int ln)
+{
+ if (!location_force_filename && last_filename != 0
+ && strcmp(fn, last_filename) == 0)
+ printfs(".lf %1\n", as_string(ln));
+ else {
+ printfs(".lf %1 %2\n", as_string(ln), fn);
+ last_filename = fn;
+ location_force_filename = 0;
+ }
+}
+
+void printfs(const char *s, const string &arg1, const string &arg2,
+ const string &arg3, const string &arg4, const string &arg5)
+{
+ if (s) {
+ char c;
+ while ((c = *s++) != '\0') {
+ if (c == '%') {
+ switch (*s++) {
+ case '1':
+ prints(arg1);
+ break;
+ case '2':
+ prints(arg2);
+ break;
+ case '3':
+ prints(arg3);
+ break;
+ case '4':
+ prints(arg4);
+ break;
+ case '5':
+ prints(arg5);
+ break;
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ break;
+ case '%':
+ prints('%');
+ break;
+ default:
+ assert(0);
+ }
+ }
+ else
+ prints(c);
+ }
+ }
+}
+
diff --git a/gnu/usr.bin/groff/tbl/table.h b/gnu/usr.bin/groff/tbl/table.h
new file mode 100644
index 0000000..3912d9a
--- /dev/null
+++ b/gnu/usr.bin/groff/tbl/table.h
@@ -0,0 +1,152 @@
+// -*- C++ -*-
+/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
+ Written by James Clark (jjc@jclark.com)
+
+This file is part of groff.
+
+groff is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
+
+groff is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License along
+with groff; see the file COPYING. If not, write to the Free Software
+Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <ctype.h>
+#include <errno.h>
+
+#include "cset.h"
+#include "cmap.h"
+#include "stringclass.h"
+#include "errarg.h"
+#include "error.h"
+#include "lib.h"
+
+struct inc_number {
+ short inc;
+ short val;
+};
+
+struct entry_modifier {
+ inc_number point_size;
+ inc_number vertical_spacing;
+ string font;
+ enum { CENTER, TOP, BOTTOM } vertical_alignment;
+ char zero_width;
+ char stagger;
+
+ entry_modifier();
+ ~entry_modifier();
+};
+
+enum format_type {
+ FORMAT_LEFT,
+ FORMAT_CENTER,
+ FORMAT_RIGHT,
+ FORMAT_NUMERIC,
+ FORMAT_ALPHABETIC,
+ FORMAT_SPAN,
+ FORMAT_VSPAN,
+ FORMAT_HLINE,
+ FORMAT_DOUBLE_HLINE
+};
+
+struct entry_format : public entry_modifier {
+ format_type type;
+
+ entry_format(format_type);
+ entry_format();
+ void debug_print() const;
+};
+
+struct table_entry;
+struct horizontal_span;
+struct stuff;
+struct vertical_rule;
+
+class table {
+ unsigned flags;
+ int nrows;
+ int ncolumns;
+ int linesize;
+ char delim[2];
+ char decimal_point_char;
+ vertical_rule *vrule_list;
+ stuff *stuff_list;
+ horizontal_span *span_list;
+ table_entry *entry_list;
+ table_entry **entry_list_tailp;
+ table_entry ***entry;
+ char **vline;
+ char *row_is_all_lines;
+ string *minimum_width;
+ int *column_separation;
+ char *equal;
+ int left_separation;
+ int right_separation;
+ int allocated_rows;
+ void build_span_list();
+ void do_hspan(int r, int c);
+ void do_vspan(int r, int c);
+ void allocate(int r);
+ void compute_widths();
+ void divide_span(int, int);
+ void sum_columns(int, int);
+ void compute_separation_factor();
+ void compute_column_positions();
+ void do_row(int);
+ void init_output();
+ void add_stuff(stuff *);
+ void do_top();
+ void do_bottom();
+ void do_vertical_rules();
+ void build_vrule_list();
+ void add_vertical_rule(int, int, int, int);
+ void define_bottom_macro();
+ int vline_spanned(int r, int c);
+ int row_begins_section(int);
+ int row_ends_section(int);
+ void make_columns_equal();
+ void compute_vrule_top_adjust(int, int, string &);
+ void compute_vrule_bot_adjust(int, int, string &);
+ void determine_row_type();
+public:
+ /* used by flags */
+ enum {
+ CENTER = 01,
+ EXPAND = 02,
+ BOX = 04,
+ ALLBOX = 010,
+ DOUBLEBOX = 020,
+ NOKEEP = 040
+ };
+ table(int nc, unsigned flags, int linesize, char decimal_point_char);
+ ~table();
+
+ void add_text_line(int r, const string &, const char *, int);
+ void add_single_hline(int r);
+ void add_double_hline(int r);
+ void add_entry(int r, int c, const string &, const entry_format *,
+ const char *, int lineno);
+ void add_vlines(int r, const char *);
+ void check();
+ void print();
+ void set_minimum_width(int c, const string &w);
+ void set_column_separation(int c, int n);
+ void set_equal_column(int c);
+ void set_delim(char c1, char c2);
+ void print_single_hline(int r);
+ void print_double_hline(int r);
+ int get_nrows();
+};
+
+void set_troff_location(const char *, int);
diff --git a/gnu/usr.bin/groff/tbl/tbl.man b/gnu/usr.bin/groff/tbl/tbl.man
new file mode 100644
index 0000000..3fd6881
--- /dev/null
+++ b/gnu/usr.bin/groff/tbl/tbl.man
@@ -0,0 +1,143 @@
+.\" -*- nroff -*-
+.TH @G@TBL @MAN1EXT@ "@MDATE@" "Groff Version @VERSION@"
+.SH NAME
+@g@tbl \- format tables for troff
+.SH SYNOPSIS
+.B @g@tbl
+[
+.B \-Cv
+]
+[
+.IR files \|.\|.\|.
+]
+.SH DESCRIPTION
+This manual page describes the GNU version of
+.BR tbl ,
+which is part of the groff document formatting system.
+.B tbl
+compiles descriptions of tables embedded within
+.B troff
+input files into commands that are understood by
+.BR troff .
+Normally, it should be invoked using the
+.B \-t
+option of
+.B groff.
+It is highly compatible with Unix
+.BR tbl .
+The output generated by GNU
+.B tbl
+cannot be processed with Unix
+.BR troff ;
+it must be processed with GNU
+.BR troff .
+If no files are given on the command line, the standard input
+will be read.
+A filename of
+.B \-
+will cause the standard input to be read.
+.SH OPTIONS
+.TP
+.B \-C
+Recognize
+.B .TS
+and
+.B .TE
+even when followed by a character other than space or newline.
+.TP
+.B \-v
+Print the version number.
+.SH USAGE
+Only the differences between GNU
+.B tbl
+and Unix
+.B tbl
+are described here.
+.LP
+Normally
+.B tbl
+attempts to prevent undesirable breaks in the table by using diversions.
+This can sometimes interact badly with macro packages' own use of diversions,
+when footnotes, for example, are used.
+The
+.B nokeep
+option tells
+.B tbl
+not to try and prevent breaks in this way.
+.LP
+The
+.B decimalpoint
+option specifies the character to be recognized as the decimal
+point character in place of the default period.
+It takes an argument in parentheses, which must be a single
+character, as for the
+.B tab
+option.
+.LP
+The
+.B f
+format modifier can be followed by an arbitrary length
+font name in parentheses.
+.LP
+There is a
+.B d
+format modifier which means that a vertically spanning entry
+should be aligned at the bottom of its range.
+.LP
+There is no limit on the number of columns in a table, nor any limit
+on the number of text blocks.
+All the lines of a table are considered in deciding column
+widths, not just the first 200.
+Table continuation
+.RB ( .T& )
+lines are not restricted to the first 200 lines.
+.LP
+Numeric and alphabetic items may appear in the same column.
+.LP
+Numeric and alphabetic items may span horizontally.
+.LP
+.B tbl
+uses register, string, macro and diversion names beginning with
+.BR 3 .
+When using
+.B tbl
+you should avoid using any names beginning with a
+.BR 3 .
+.SH BUGS
+You should use
+.BR .TS\ H / .TH
+in conjunction with a supporting macro package for
+.I all
+multi-page boxed tables.
+If there is no header that you wish to appear at the top of each page
+of the table, place the
+.B .TH
+line immediately after the format section.
+Do not enclose a multi-page table within keep/release macros,
+or divert it in any other way.
+.LP
+A text block within a table must be able to fit on one page.
+.LP
+The
+.B bp
+request cannot be used to force a page-break in a multi-page table.
+Instead, define
+.B BP
+as follows
+.IP
+.B .de BP
+.br
+.B .ie '\e\en(.z'' .bp \e\e$1
+.br
+.B .el \e!.BP \e\e$1
+.br
+.B ..
+.br
+.LP
+and use
+.B BP
+instead of
+.BR bp .
+.SH "SEE ALSO"
+.BR groff (@MAN1EXT@),
+.BR @g@troff (@MAN1EXT@)
diff --git a/gnu/usr.bin/groff/test-groff b/gnu/usr.bin/groff/test-groff
new file mode 100755
index 0000000..35fd0e0
--- /dev/null
+++ b/gnu/usr.bin/groff/test-groff
@@ -0,0 +1,26 @@
+#! /bin/sh
+# This script runs groff without requiring that it be installed.
+# The current directory must be the build directory.
+
+builddir=.
+srcdir=`echo $0 | sed -e 's;/[^/]*$;;'`
+
+if test ! -d groff || test ! -r groff/groff
+then
+ echo $0 must be run with the build directory as the current directory 2>&1
+ exit 1
+fi
+
+PATH=$builddir/troff:$builddir/pic:$builddir/eqn:$builddir/tbl:$builddir/refer:$builddir/soelim:$builddir/grops:$builddir/grodvi:$builddir/grotty:$srcdir/$builddir/xditview:$PATH
+
+test -n "$srcdir" || srcdir=.
+
+XENVIRONMENT=`cd $srcdir; pwd`/xditview/GXditview.ad
+export XENVIRONMENT
+
+GROFF_COMMAND_PREFIX=
+GROFF_FONT_PATH=$builddir:$srcdir
+GROFF_TMAC_PATH=$srcdir/tmac:$srcdir/troff
+export PATH GROFF_COMMAND_PREFIX GROFF_FONT_PATH GROFF_TMAC_PATH
+
+exec $builddir/groff/groff ${1+"$@"}
diff --git a/gnu/usr.bin/groff/tfmtodit/Makefile b/gnu/usr.bin/groff/tfmtodit/Makefile
new file mode 100644
index 0000000..5413986
--- /dev/null
+++ b/gnu/usr.bin/groff/tfmtodit/Makefile
@@ -0,0 +1,13 @@
+# Makefile for tfmtodit
+
+PROG= tfmtodit
+SRCS= tfmtodit.cc
+CFLAGS+= -I${.CURDIR}/../include
+LDADD+= ${LIBGROFF} -lm
+DPADD+= ${LIBGROFF} ${LIBM}
+
+MANDEPEND= tfmtodit.1
+CLEANFILES+= ${MANDEPEND}
+
+.include "../Makefile.cfg"
+.include <bsd.prog.mk>
diff --git a/gnu/usr.bin/groff/tfmtodit/Makefile.dep b/gnu/usr.bin/groff/tfmtodit/Makefile.dep
new file mode 100644
index 0000000..9e1b9f5
--- /dev/null
+++ b/gnu/usr.bin/groff/tfmtodit/Makefile.dep
@@ -0,0 +1,2 @@
+tfmtodit.o : tfmtodit.cc ../include/lib.h ../include/errarg.h \
+ ../include/error.h ../include/assert.h ../include/cset.h
diff --git a/gnu/usr.bin/groff/tfmtodit/Makefile.sub b/gnu/usr.bin/groff/tfmtodit/Makefile.sub
new file mode 100644
index 0000000..aa430e2
--- /dev/null
+++ b/gnu/usr.bin/groff/tfmtodit/Makefile.sub
@@ -0,0 +1,6 @@
+PROG=tfmtodit
+MAN1=tfmtodit.n
+XLIBS=$(LIBGROFF)
+MLIB=$(LIBM)
+OBJS=tfmtodit.o
+CCSRCS=tfmtodit.cc
diff --git a/gnu/usr.bin/groff/tfmtodit/tfmtodit.cc b/gnu/usr.bin/groff/tfmtodit/tfmtodit.cc
new file mode 100644
index 0000000..407c199
--- /dev/null
+++ b/gnu/usr.bin/groff/tfmtodit/tfmtodit.cc
@@ -0,0 +1,850 @@
+// -*- C++ -*-
+/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
+ Written by James Clark (jjc@jclark.com)
+
+This file is part of groff.
+
+groff is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
+
+groff is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License along
+with groff; see the file COPYING. If not, write to the Free Software
+Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* I have tried to incorporate the changes needed for TeX 3.0 tfm files,
+but I haven't tested them. */
+
+/* Groff requires more font metric information than TeX. The reason
+for this is that TeX has separate Math Italic fonts, whereas groff
+uses normal italic fonts for math. The two additional pieces of
+information required by groff correspond to the two arguments to the
+math_fit() macro in the Metafont programs for the CM fonts. In the
+case of a font for which math_fitting is false, these two arguments
+are normally ignored by Metafont. We need to get hold of these two
+parameters and put them in the groff font file.
+
+We do this by loading this definition after cmbase when creating cm.base.
+
+def ignore_math_fit(expr left_adjustment,right_adjustment) =
+ special "adjustment";
+ numspecial left_adjustment*16/designsize;
+ numspecial right_adjustment*16/designsize;
+ enddef;
+
+This puts the two arguments to the math_fit macro into the gf file.
+(They will appear in the gf file immediately before the character to
+which they apply.) We then create a gf file using this cm.base. Then
+we run tfmtodit and specify this gf file with the -g option.
+
+This need only be done for a font for which math_fitting is false;
+When it's true, the left_correction and subscript_correction should
+both be zero. */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <string.h>
+#include <errno.h>
+#include "lib.h"
+#include "errarg.h"
+#include "error.h"
+#include "assert.h"
+#include "cset.h"
+
+/* Values in the tfm file should be multiplied by this. */
+
+#define MULTIPLIER 1
+
+struct char_info_word {
+ unsigned char width_index;
+ char height_index;
+ char depth_index;
+ char italic_index;
+ char tag;
+ unsigned char remainder;
+};
+
+struct lig_kern_command {
+ unsigned char skip_byte;
+ unsigned char next_char;
+ unsigned char op_byte;
+ unsigned char remainder;
+};
+
+class tfm {
+ int bc;
+ int ec;
+ int nw;
+ int nh;
+ int nd;
+ int ni;
+ int nl;
+ int nk;
+ int np;
+ int cs;
+ int ds;
+ char_info_word *char_info;
+ int *width;
+ int *height;
+ int *depth;
+ int *italic;
+ lig_kern_command *lig_kern;
+ int *kern;
+ int *param;
+public:
+ tfm();
+ ~tfm();
+ int load(const char *);
+ int contains(int);
+ int get_width(int);
+ int get_height(int);
+ int get_depth(int);
+ int get_italic(int);
+ int get_param(int, int *);
+ int get_checksum();
+ int get_design_size();
+ int get_lig(unsigned char, unsigned char, unsigned char *);
+ friend class kern_iterator;
+};
+
+class kern_iterator {
+ tfm *t;
+ int c;
+ int i;
+public:
+ kern_iterator(tfm *);
+ int next(unsigned char *c1, unsigned char *c2, int *k);
+};
+
+
+kern_iterator::kern_iterator(tfm *p)
+: t(p), i(-1), c(t->bc)
+{
+}
+
+int kern_iterator::next(unsigned char *c1, unsigned char *c2, int *k)
+{
+ for (; c <= t->ec; c++)
+ if (t->char_info[c - t->bc].tag == 1) {
+ if (i < 0) {
+ i = t->char_info[c - t->bc].remainder;
+ if (t->lig_kern[i].skip_byte > 128)
+ i = (256*t->lig_kern[i].op_byte
+ + t->lig_kern[i].remainder);
+ }
+ for (;;) {
+ int skip = t->lig_kern[i].skip_byte;
+ if (skip <= 128 && t->lig_kern[i].op_byte >= 128) {
+ *c1 = c;
+ *c2 = t->lig_kern[i].next_char;
+ *k = t->kern[256*(t->lig_kern[i].op_byte - 128)
+ + t->lig_kern[i].remainder];
+ if (skip == 128) {
+ c++;
+ i = -1;
+ }
+ else
+ i += skip + 1;
+ return 1;
+ }
+ if (skip >= 128)
+ break;
+ i += skip + 1;
+ }
+ i = -1;
+ }
+ return 0;
+}
+
+tfm::tfm()
+: char_info(0), width(0), height(0), depth(0), italic(0), lig_kern(0),
+ kern(0), param(0)
+{
+}
+
+int tfm::get_lig(unsigned char c1, unsigned char c2, unsigned char *cp)
+{
+ if (contains(c1) && char_info[c1 - bc].tag == 1) {
+ int i = char_info[c1 - bc].remainder;
+ if (lig_kern[i].skip_byte > 128)
+ i = 256*lig_kern[i].op_byte + lig_kern[i].remainder;
+ for (;;) {
+ int skip = lig_kern[i].skip_byte;
+ if (skip > 128)
+ break;
+ // We are only interested in normal ligatures, for which
+ // op_byte == 0.
+ if (lig_kern[i].op_byte == 0
+ && lig_kern[i].next_char == c2) {
+ *cp = lig_kern[i].remainder;
+ return 1;
+ }
+ if (skip == 128)
+ break;
+ i += skip + 1;
+ }
+ }
+ return 0;
+}
+
+int tfm::contains(int i)
+{
+ return i >= bc && i <= ec && char_info[i - bc].width_index != 0;
+}
+
+int tfm::get_width(int i)
+{
+ return width[char_info[i - bc].width_index];
+}
+
+int tfm::get_height(int i)
+{
+ return height[char_info[i - bc].height_index];
+}
+
+int tfm::get_depth(int i)
+{
+ return depth[char_info[i - bc].depth_index];
+}
+
+int tfm::get_italic(int i)
+{
+ return italic[char_info[i - bc].italic_index];
+}
+
+int tfm::get_param(int i, int *p)
+{
+ if (i <= 0 || i > np)
+ return 0;
+ else {
+ *p = param[i - 1];
+ return 1;
+ }
+}
+
+int tfm::get_checksum()
+{
+ return cs;
+}
+
+int tfm::get_design_size()
+{
+ return ds;
+}
+
+tfm::~tfm()
+{
+ a_delete char_info;
+ a_delete width;
+ a_delete height;
+ a_delete depth;
+ a_delete italic;
+ a_delete lig_kern;
+ a_delete kern;
+ a_delete param;
+}
+
+int read2(unsigned char *&s)
+{
+ int n;
+ n = *s++ << 8;
+ n |= *s++;
+ return n;
+}
+
+int read4(unsigned char *&s)
+{
+ int n;
+ n = *s++ << 24;
+ n |= *s++ << 16;
+ n |= *s++ << 8;
+ n |= *s++;
+ return n;
+}
+
+
+int tfm::load(const char *file)
+{
+ errno = 0;
+ FILE *fp = fopen(file, "r");
+ if (!fp) {
+ error("can't open `%1': %2", file, strerror(errno));
+ return 0;
+ }
+ int c1 = getc(fp);
+ int c2 = getc(fp);
+ if (c1 == EOF || c2 == EOF) {
+ fclose(fp);
+ error("unexpected end of file on `%1'", file);
+ return 0;
+ }
+ int lf = (c1 << 8) + c2;
+ int toread = lf*4 - 2;
+ unsigned char *buf = new unsigned char[toread];
+ if (fread(buf, 1, toread, fp) != toread) {
+ if (feof(fp))
+ error("unexpected end of file on `%1'", file);
+ else
+ error("error on file `%1'", file);
+ a_delete buf;
+ fclose(fp);
+ return 0;
+ }
+ fclose(fp);
+ if (lf < 6) {
+ error("bad tfm file `%1': impossibly short", file);
+ a_delete buf;
+ return 0;
+ }
+ unsigned char *ptr = buf;
+ int lh = read2(ptr);
+ bc = read2(ptr);
+ ec = read2(ptr);
+ nw = read2(ptr);
+ nh = read2(ptr);
+ nd = read2(ptr);
+ ni = read2(ptr);
+ nl = read2(ptr);
+ nk = read2(ptr);
+ int ne = read2(ptr);
+ np = read2(ptr);
+ if (6 + lh + (ec - bc + 1) + nw + nh + nd + ni + nl + nk + ne + np != lf) {
+ error("bad tfm file `%1': lengths do not sum", file);
+ a_delete buf;
+ return 0;
+ }
+ if (lh < 2) {
+ error("bad tfm file `%1': header too short", file);
+ a_delete buf;
+ return 0;
+ }
+ char_info = new char_info_word[ec - bc + 1];
+ width = new int[nw];
+ height = new int[nh];
+ depth = new int[nd];
+ italic = new int[ni];
+ lig_kern = new lig_kern_command[nl];
+ kern = new int[nk];
+ param = new int[np];
+ int i;
+ cs = read4(ptr);
+ ds = read4(ptr);
+ ptr += (lh-2)*4;
+ for (i = 0; i < ec - bc + 1; i++) {
+ char_info[i].width_index = *ptr++;
+ unsigned char tem = *ptr++;
+ char_info[i].depth_index = tem & 0xf;
+ char_info[i].height_index = tem >> 4;
+ tem = *ptr++;
+ char_info[i].italic_index = tem >> 2;
+ char_info[i].tag = tem & 3;
+ char_info[i].remainder = *ptr++;
+ }
+ for (i = 0; i < nw; i++)
+ width[i] = read4(ptr);
+ for (i = 0; i < nh; i++)
+ height[i] = read4(ptr);
+ for (i = 0; i < nd; i++)
+ depth[i] = read4(ptr);
+ for (i = 0; i < ni; i++)
+ italic[i] = read4(ptr);
+ for (i = 0; i < nl; i++) {
+ lig_kern[i].skip_byte = *ptr++;
+ lig_kern[i].next_char = *ptr++;
+ lig_kern[i].op_byte = *ptr++;
+ lig_kern[i].remainder = *ptr++;
+ }
+ for (i = 0; i < nk; i++)
+ kern[i] = read4(ptr);
+ ptr += ne*4;
+ for (i = 0; i < np; i++)
+ param[i] = read4(ptr);
+ assert(ptr == buf + lf*4 - 2);
+ a_delete buf;
+ return 1;
+}
+
+class gf {
+ int left[256];
+ int right[256];
+ static int sread4(int *p, FILE *fp);
+ static int uread3(int *p, FILE *fp);
+ static int uread2(int *p, FILE *fp);
+ static int skip(int n, FILE *fp);
+public:
+ gf();
+ int load(const char *file);
+ int get_left_adjustment(int i) { return left[i]; }
+ int get_right_adjustment(int i) { return right[i]; }
+};
+
+gf::gf()
+{
+ for (int i = 0; i < 256; i++)
+ left[i] = right[i] = 0;
+}
+
+int gf::load(const char *file)
+{
+ enum {
+ paint_0 = 0,
+ paint1 = 64,
+ boc = 67,
+ boc1 = 68,
+ eoc = 69,
+ skip0 = 70,
+ skip1 = 71,
+ new_row_0 = 74,
+ xxx1 = 239,
+ yyy = 243,
+ no_op = 244,
+ pre = 247,
+ post = 248
+ };
+ int got_an_adjustment = 0;
+ int pending_adjustment = 0;
+ int left_adj, right_adj;
+ const int gf_id_byte = 131;
+ errno = 0;
+ FILE *fp = fopen(file, "r");
+ if (!fp) {
+ error("can't open `%1': %2", file, strerror(errno));
+ return 0;
+ }
+ if (getc(fp) != pre || getc(fp) != gf_id_byte) {
+ error("bad gf file");
+ return 0;
+ }
+ int n = getc(fp);
+ if (n == EOF)
+ goto eof;
+ if (!skip(n, fp))
+ goto eof;
+ for (;;) {
+ int op = getc(fp);
+ if (op == EOF)
+ goto eof;
+ if (op == post)
+ break;
+ if ((op >= paint_0 && op <= paint_0 + 63)
+ || (op >= new_row_0 && op <= new_row_0 + 164))
+ continue;
+ switch (op) {
+ case no_op:
+ case eoc:
+ case skip0:
+ break;
+ case paint1:
+ case skip1:
+ if (!skip(1, fp))
+ goto eof;
+ break;
+ case paint1 + 1:
+ case skip1 + 1:
+ if (!skip(2, fp))
+ goto eof;
+ break;
+ case paint1 + 2:
+ case skip1 + 2:
+ if (!skip(3, fp))
+ goto eof;
+ break;
+ case boc:
+ {
+ int code;
+ if (!sread4(&code, fp))
+ goto eof;
+ if (pending_adjustment) {
+ pending_adjustment = 0;
+ left[code & 0377] = left_adj;
+ right[code & 0377] = right_adj;
+ }
+ if (!skip(20, fp))
+ goto eof;
+ break;
+ }
+ case boc1:
+ {
+ int code = getc(fp);
+ if (code == EOF)
+ goto eof;
+ if (pending_adjustment) {
+ pending_adjustment = 0;
+ left[code] = left_adj;
+ right[code] = right_adj;
+ }
+ if (!skip(4, fp))
+ goto eof;
+ break;
+ }
+ case xxx1:
+ {
+ int len = getc(fp);
+ if (len == EOF)
+ goto eof;
+ char buf[256];
+ if (fread(buf, 1, len, fp) != len)
+ goto eof;
+ if (len == 10 /* strlen("adjustment") */
+ && memcmp(buf, "adjustment", len) == 0) {
+ int c = getc(fp);
+ if (c != yyy) {
+ if (c != EOF)
+ ungetc(c, fp);
+ break;
+ }
+ if (!sread4(&left_adj, fp))
+ goto eof;
+ c = getc(fp);
+ if (c != yyy) {
+ if (c != EOF)
+ ungetc(c, fp);
+ break;
+ }
+ if (!sread4(&right_adj, fp))
+ goto eof;
+ got_an_adjustment = 1;
+ pending_adjustment = 1;
+ }
+ break;
+ }
+ case xxx1 + 1:
+ if (!uread2(&n, fp) || !skip(n, fp))
+ goto eof;
+ break;
+ case xxx1 + 2:
+ if (!uread3(&n, fp) || !skip(n, fp))
+ goto eof;
+ break;
+ case xxx1 + 3:
+ if (!sread4(&n, fp) || !skip(n, fp))
+ goto eof;
+ break;
+ case yyy:
+ if (!skip(4, fp))
+ goto eof;
+ break;
+ default:
+ fatal("unrecognized opcode `%1'", op);
+ break;
+ }
+ }
+ if (!got_an_adjustment)
+ warning("no adjustment specials found in gf file");
+ return 1;
+ eof:
+ error("unexpected end of file");
+ return 0;
+}
+
+int gf::sread4(int *p, FILE *fp)
+{
+ *p = getc(fp);
+ if (*p >= 128)
+ *p -= 256;
+ *p <<= 8;
+ *p |= getc(fp);
+ *p <<= 8;
+ *p |= getc(fp);
+ *p <<= 8;
+ *p |= getc(fp);
+ return !ferror(fp) && !feof(fp);
+}
+
+int gf::uread3(int *p, FILE *fp)
+{
+ *p = getc(fp);
+ *p <<= 8;
+ *p |= getc(fp);
+ *p <<= 8;
+ *p |= getc(fp);
+ return !ferror(fp) && !feof(fp);
+}
+
+int gf::uread2(int *p, FILE *fp)
+{
+ *p = getc(fp);
+ *p <<= 8;
+ *p |= getc(fp);
+ return !ferror(fp) && !feof(fp);
+}
+
+int gf::skip(int n, FILE *fp)
+{
+ while (--n >= 0)
+ if (getc(fp) == EOF)
+ return 0;
+ return 1;
+}
+
+
+struct char_list {
+ char *ch;
+ char_list *next;
+ char_list(const char *, char_list * = 0);
+};
+
+char_list::char_list(const char *s, char_list *p) : ch(strsave(s)), next(p)
+{
+}
+
+
+int read_map(const char *file, char_list **table)
+{
+ errno = 0;
+ FILE *fp = fopen(file, "r");
+ if (!fp) {
+ error("can't open `%1': %2", file, strerror(errno));
+ return 0;
+ }
+ for (int i = 0; i < 256; i++)
+ table[i] = 0;
+ char buf[512];
+ int lineno = 0;
+ while (fgets(buf, int(sizeof(buf)), fp)) {
+ lineno++;
+ char *ptr = buf;
+ while (csspace(*ptr))
+ ptr++;
+ if (*ptr == '\0' || *ptr == '#')
+ continue;
+ ptr = strtok(ptr, " \n\t");
+ if (!ptr)
+ continue;
+ int n;
+ if (sscanf(ptr, "%d", &n) != 1) {
+ error("%1:%2: bad map file", file, lineno);
+ fclose(fp);
+ return 0;
+ }
+ if (n < 0 || n > 255) {
+ error("%1:%2: code out of range", file, lineno);
+ fclose(fp);
+ return 0;
+ }
+ ptr = strtok(0, " \n\t");
+ if (!ptr) {
+ error("%1:%2: missing names", file, lineno);
+ fclose(fp);
+ return 0;
+ }
+ for (; ptr; ptr = strtok(0, " \n\t"))
+ table[n] = new char_list(ptr, table[n]);
+ }
+ fclose(fp);
+ return 1;
+}
+
+
+/* Every character that can participate in a ligature appears in the
+lig_chars table. `ch' gives the full-name of the character, `name'
+gives the groff name of the character, `i' gives its index in
+the encoding, which is filled in later (-1 if it does not appear). */
+
+struct {
+ const char *ch;
+ int i;
+} lig_chars[] = {
+ { "f", -1 },
+ { "i", -1 },
+ { "l", -1 },
+ { "ff", -1 },
+ { "fi", -1 },
+ { "fl", -1 },
+ { "Fi", -1 },
+ { "Fl", -1 },
+};
+
+// Indices into lig_chars[].
+
+enum { CH_f, CH_i, CH_l, CH_ff, CH_fi, CH_fl, CH_ffi, CH_ffl };
+
+// Each possible ligature appears in this table.
+
+struct {
+ unsigned char c1, c2, res;
+ const char *ch;
+} lig_table[] = {
+ { CH_f, CH_f, CH_ff, "ff" },
+ { CH_f, CH_i, CH_fi, "fi" },
+ { CH_f, CH_l, CH_fl, "fl" },
+ { CH_ff, CH_i, CH_ffi, "ffi" },
+ { CH_ff, CH_l, CH_ffl, "ffl" },
+ };
+
+static void usage();
+
+int main(int argc, char **argv)
+{
+ program_name = argv[0];
+ int special_flag = 0;
+ int skewchar = -1;
+ int opt;
+ const char *gf_file = 0;
+ while ((opt = getopt(argc, argv, "svg:k:")) != EOF)
+ switch (opt) {
+ case 'g':
+ gf_file = optarg;
+ break;
+ case 's':
+ special_flag = 1;
+ break;
+ case 'k':
+ {
+ char *ptr;
+ long n = strtol(optarg, &ptr, 0);
+ if ((n == 0 && ptr == optarg)
+ || *ptr != '\0'
+ || n < 0
+ || n > UCHAR_MAX)
+ error("invalid skewchar");
+ else
+ skewchar = (int)n;
+ break;
+ }
+ case 'v':
+ {
+ extern const char *version_string;
+ fprintf(stderr, "tfmtodit version %s\n", version_string);
+ fflush(stderr);
+ break;
+ }
+ case '?':
+ usage();
+ break;
+ case EOF:
+ assert(0);
+ }
+ if (argc - optind != 3)
+ usage();
+ gf g;
+ if (gf_file) {
+ if (!g.load(gf_file))
+ return 1;
+ }
+ const char *tfm_file = argv[optind];
+ const char *map_file = argv[optind + 1];
+ const char *font_file = argv[optind + 2];
+ tfm t;
+ if (!t.load(tfm_file))
+ return 1;
+ char_list *table[256];
+ if (!read_map(map_file, table))
+ return 1;
+ errno = 0;
+ if (!freopen(font_file, "w", stdout)) {
+ error("can't open `%1' for writing: %2", font_file, strerror(errno));
+ return 1;
+ }
+ printf("name %s\n", font_file);
+ if (special_flag)
+ fputs("special\n", stdout);
+ char *internal_name = strsave(argv[optind]);
+ int len = strlen(internal_name);
+ if (len > 4 && strcmp(internal_name + len - 4, ".tfm") == 0)
+ internal_name[len - 4] = '\0';
+ char *s = strrchr(internal_name, '/');
+ printf("internalname %s\n", s ? s + 1 : internal_name);
+ int n;
+ if (t.get_param(2, &n)) {
+ if (n > 0)
+ printf("spacewidth %d\n", n*MULTIPLIER);
+ }
+ if (t.get_param(1, &n) && n != 0)
+ printf("slant %f\n", atan2(n/double(1<<20), 1.0)*180.0/PI);
+ int xheight;
+ if (!t.get_param(5, &xheight))
+ xheight = 0;
+ int i;
+ // Print the list of ligatures.
+ // First find the indices of each character that can participate in
+ // a ligature.
+ for (i = 0; i < 256; i++)
+ for (int j = 0; j < sizeof(lig_chars)/sizeof(lig_chars[0]); j++)
+ for (char_list *p = table[i]; p; p = p->next)
+ if (strcmp(lig_chars[j].ch, p->ch) == 0)
+ lig_chars[j].i = i;
+ // For each possible ligature, if its participants all exist,
+ // and it appears as a ligature in the tfm file, include in
+ // the list of ligatures.
+ int started = 0;
+ for (i = 0; i < sizeof(lig_table)/sizeof(lig_table[0]); i++) {
+ int i1 = lig_chars[lig_table[i].c1].i;
+ int i2 = lig_chars[lig_table[i].c2].i;
+ int r = lig_chars[lig_table[i].res].i;
+ if (i1 >= 0 && i2 >= 0 && r >= 0) {
+ unsigned char c;
+ if (t.get_lig(i1, i2, &c) && c == r) {
+ if (!started) {
+ started = 1;
+ fputs("ligatures", stdout);
+ }
+ printf(" %s", lig_table[i].ch);
+ }
+ }
+ }
+ if (started)
+ fputs(" 0\n", stdout);
+ printf("checksum %d\n", t.get_checksum());
+ printf("designsize %d\n", t.get_design_size());
+ // Now print out the kerning information.
+ int had_kern = 0;
+ kern_iterator iter(&t);
+ unsigned char c1, c2;
+ int k;
+ while (iter.next(&c1, &c2, &k))
+ if (c2 != skewchar) {
+ k *= MULTIPLIER;
+ char_list *q = table[c2];
+ for (char_list *p1 = table[c1]; p1; p1 = p1->next)
+ for (char_list *p2 = q; p2; p2 = p2->next) {
+ if (!had_kern) {
+ printf("kernpairs\n");
+ had_kern = 1;
+ }
+ printf("%s %s %d\n", p1->ch, p2->ch, k);
+ }
+ }
+ printf("charset\n");
+ char_list unnamed("---");
+ for (i = 0; i < 256; i++)
+ if (t.contains(i)) {
+ char_list *p = table[i] ? table[i] : &unnamed;
+ int m[6];
+ m[0] = t.get_width(i);
+ m[1] = t.get_height(i);
+ m[2] = t.get_depth(i);
+ m[3] = t.get_italic(i);
+ m[4] = g.get_left_adjustment(i);
+ m[5] = g.get_right_adjustment(i);
+ printf("%s\t%d", p->ch, m[0]*MULTIPLIER);
+ for (int j = int(sizeof(m)/sizeof(m[0])) - 1; j > 0; j--)
+ if (m[j] != 0)
+ break;
+ for (int k = 1; k <= j; k++)
+ printf(",%d", m[k]*MULTIPLIER);
+ int type = 0;
+ if (m[2] > 0)
+ type = 1;
+ if (m[1] > xheight)
+ type += 2;
+ printf("\t%d\t%04o\n", type, i);
+ for (p = p->next; p; p = p->next)
+ printf("%s\t\"\n", p->ch);
+ }
+ return 0;
+}
+
+static void usage()
+{
+ fprintf(stderr, "usage: %s [-sv] [-g gf_file] [-k skewchar] tfm_file map_file font\n",
+ program_name);
+ exit(1);
+}
diff --git a/gnu/usr.bin/groff/tfmtodit/tfmtodit.man b/gnu/usr.bin/groff/tfmtodit/tfmtodit.man
new file mode 100644
index 0000000..1b07668
--- /dev/null
+++ b/gnu/usr.bin/groff/tfmtodit/tfmtodit.man
@@ -0,0 +1,150 @@
+.\" -*- nroff -*-
+.ie t .ds tx T\h'-.1667m'\v'.224m'E\v'-.224m'\h'-.125m'X
+.el .ds tx TeX
+.\" Like TP, but if specified indent is more than half
+.\" the current line-length - indent, use the default indent.
+.de Tp
+.ie \\n(.$=0:((0\\$1)*2u>(\\n(.lu-\\n(.iu)) .TP
+.el .TP "\\$1"
+..
+.TH TFMTODIT @MAN1EXT@ "@MDATE@" "Groff Version @VERSION@"
+.SH NAME
+tfmtodit \- create font files for use with groff \-Tdvi
+.SH SYNOPSIS
+.B tfmtodit
+[
+.B \-sv
+]
+[
+.BI \-g gf_file
+]
+[
+.BI \-k skewchar
+]
+.I tfm_file
+.I map_file
+.I font
+.SH DESCRIPTION
+.B tfmtodit
+creates a font file for use with
+.B
+groff \-Tdvi\fR.
+.I tfm_file
+is the name of the \*(tx font metric file for the font.
+.I map_file
+is a file giving the groff names for characters in the font;
+this file should consist of a sequence of lines of the form:
+.IP
+.I
+n c1 c2 \fR.\|.\|.
+.LP
+where
+.I n
+is a decimal integer giving the position of the character in the font,
+and
+.IR c1 ,
+.IR c2 ,.\|.\|.
+are the groff names of the character.
+If a character has no groff names but exists in the tfm file,
+then it will be put in the groff font file as an unnamed character.
+.I font
+is the name of the groff font file.
+The groff font file is written to
+.IR font .
+.LP
+The
+.B \-s
+option should be given if the font is special
+(a font is
+.I special
+if
+.B troff
+should search it whenever
+a character is not found in the current font.)
+If the font is special,
+it should be listed in the
+.B fonts
+command in the DESC file;
+if it is not special, there is no need to list it, since
+.B troff
+can automatically mount it when it's first used.
+.LP
+To do a good job of math typesetting, groff requires
+font metric information not present in the tfm file.
+The reason for this is that \*(tx has separate math italic fonts
+whereas groff uses normal italic fonts for math.
+The additional information required by groff is given by the
+two arguments to the
+.B math_fit
+macro in the Metafont programs for the Computer Modern fonts.
+In a text font (a font for which
+.B math_fitting
+is false), Metafont normally ignores these two arguments.
+Metafont can be made to put this information in the gf file
+by loading the following definition after
+.B cmbase
+when creating
+.BR cm.base :
+.IP
+.nf
+.ft B
+def ignore_math_fit(expr left_adjustment,right_adjustment) =
+ special "adjustment";
+ numspecial left_adjustment*16/designsize;
+ numspecial right_adjustment*16/designsize;
+ enddef;
+.fi
+.ft R
+.LP
+The gf file created using this modified
+.B cm.base
+should be specified with the
+.B \-g
+option.
+The
+.B \-g
+option should not be given for a font for which
+.B math_fitting
+is true.
+.SH OPTIONS
+.TP
+.B \-v
+Print the version number.
+.TP
+.B \-s
+The font is special.
+The effect of this option is to add the
+.B special
+command to the font file.
+.TP
+.BI \-k n
+The skewchar of this font is at position
+.IR n .
+.I n
+should be an integer;
+it may be given in decimal,
+or with a leading
+.B 0
+in octal,
+or with a leading
+.B 0x
+in hexadecimal.
+The effect of this option is to ignore any kerns whose second component
+is the specified character.
+.TP
+.BI \-g gf_file
+.I gf_file
+is a gf file produced by Metafont containing special and numspecial
+commands giving additional font metric information.
+.SH FILES
+.Tp \w'\fB@FONTDIR@/devdvi/DESC'u+2n
+.B @FONTDIR@/devdvi/DESC
+Device description file.
+.TP
+.BI @FONTDIR@/devdvi/ F
+Font description file for font
+.IR F .
+.SH "SEE ALSO"
+.BR groff (@MAN1EXT@),
+.BR grodvi (@MAN1EXT@),
+.BR groff_font (@MAN5EXT@)
diff --git a/gnu/usr.bin/groff/tmac/Makefile b/gnu/usr.bin/groff/tmac/Makefile
new file mode 100644
index 0000000..c4b310e
--- /dev/null
+++ b/gnu/usr.bin/groff/tmac/Makefile
@@ -0,0 +1,48 @@
+# Makefile for groff macros
+
+TMACOWN?= bin
+TMACGRP?= bin
+TMACMODE?= 444
+TMACDIR?= /usr/share/tmac
+MDOCDIR?= ${TMACDIR}/mdoc
+
+MAN7= groff_ms.7 me.7
+MLINKS= groff_ms.7 ms.7 me.7 groff_me.7
+LINKS= ${TMACDIR}/tmac.andoc ${TMACDIR}/tmac.an
+
+MANDEPEND= ${MAN7}
+CLEANFILES+= temp ${MANDEPEND} tmac.groff_an
+
+FILES= tmac.andoc tmac.pic tmac.ps tmac.psnew tmac.psold\
+ tmac.pspic tmac.psatk tmac.dvi tmac.tty tmac.tty-char tmac.X\
+ tmac.Xps tmac.latin1 eqnrc troffrc
+STRIPFILES= tmac.e tmac.s tmac.doc tmac.doc.old
+MDOCFILES= doc-common doc-ditroff doc-nroff doc-syms
+
+
+beforeinstall:
+ for f in ${FILES}; do \
+ ${INSTALL} -c -o ${TMACOWN} -g ${TMACGRP} -m ${TMACMODE} \
+ ${.CURDIR}/$$f ${DESTDIR}${TMACDIR}; \
+ done
+ sed -f ${.CURDIR}/strip.sed ${.CURDIR}/tmac.an >tmac.groff_an
+ ${INSTALL} -c -o ${TMACOWN} -g ${TMACGRP} -m ${TMACMODE} \
+ tmac.groff_an ${DESTDIR}${TMACDIR}
+ for f in ${STRIPFILES}; do \
+ rm -f temp; \
+ sed -f ${.CURDIR}/strip.sed ${.CURDIR}/$$f >temp; \
+ ${INSTALL} -c -o ${TMACOWN} -g ${TMACGRP} -m ${TMACMODE} \
+ temp ${DESTDIR}${TMACDIR}/$$f; \
+ done
+ for f in ${MDOCFILES}; do \
+ rm -f temp; \
+ sed -f ${.CURDIR}/strip.sed ${.CURDIR}/$$f >temp; \
+ ${INSTALL} -c -o ${TMACOWN} -g ${TMACGRP} -m ${TMACMODE} \
+ temp ${DESTDIR}${MDOCDIR}/$$f; \
+ done
+ test -f ${DESTDIR}${TMACDIR}/man.local || \
+ ${INSTALL} -c -o ${TMACOWN} -g ${TMACGRP} -m ${TMACMODE} \
+ ${.CURDIR}/man.local ${DESTDIR}${TMACDIR}
+
+.include "../Makefile.cfg"
+.include <bsd.prog.mk>
diff --git a/gnu/usr.bin/groff/tmac/Makefile.sub b/gnu/usr.bin/groff/tmac/Makefile.sub
new file mode 100644
index 0000000..673a7f2
--- /dev/null
+++ b/gnu/usr.bin/groff/tmac/Makefile.sub
@@ -0,0 +1,43 @@
+MAN7=groff_ms.n me.n
+
+FILES=tmac.an tmac.andoc tmac.pic tmac.ps tmac.psnew tmac.psold tmac.pspic \
+ tmac.psatk tmac.dvi tmac.tty tmac.tty-char tmac.X tmac.Xps tmac.latin1 \
+ eqnrc troffrc
+STRIPFILES=tmac.e tmac.doc tmac.doc.old
+MDOCFILES=doc-common doc-ditroff doc-nroff doc-syms
+mdocdir=$(tmacdir)/mdoc
+CLEANADD=temp
+
+install_data: $(FILES) $(STRIPFILES) $(MDOCFILES) man.local
+ -test -d $(tmacdir) || mkdir $(tmacdir)
+ for f in $(FILES); do \
+ rm -f $(tmacdir)/$$f; \
+ $(INSTALL_DATA) $(srcdir)/$$f $(tmacdir)/$$f; \
+ done
+ -rm -f $(tmacdir)/tmac.$(tmac_s)
+ cp $(srcdir)/tmac.s $(tmacdir)/tmac.$(tmac_s)
+ for f in $(STRIPFILES); do \
+ rm -f temp; \
+ sed -f $(srcdir)/strip.sed $(srcdir)/$$f >temp; \
+ rm -f $(tmacdir)/$$f; \
+ $(INSTALL_DATA) temp $(tmacdir)/$$f; \
+ done
+ -test -d $(mdocdir) || mkdir $(mdocdir)
+ for f in $(MDOCFILES); do \
+ rm -f temp; \
+ sed -f $(srcdir)/strip.sed $(srcdir)/$$f >temp; \
+ rm -f $(mdocdir)/$$f; \
+ $(INSTALL_DATA) temp $(mdocdir)/$$f; \
+ done
+ -test -f $(tmacdir)/man.local || \
+ $(INSTALL_DATA) $(srcdir)/man.local $(tmacdir)/man.local
+ -rm -f temp
+
+uninstall_sub:
+ -for f in $(FILES) $(STRIPFILES); do rm -f $(tmacdir)/$$f; done
+ -rm -f $(tmacdir)/tmac.$(tmac_s)
+ -if cmp -s $(tmacdir)/man.local $(srcdir)/man.local; then \
+ rm -f $(tmacdir)/man.local; \
+ fi
+ -for f in $(MDOCFILES); do rm -f $(mdocdir)/$$f; done
+ -rmdir $(mdocdir)
diff --git a/gnu/usr.bin/groff/tmac/TODO b/gnu/usr.bin/groff/tmac/TODO
new file mode 100644
index 0000000..5213fc2
--- /dev/null
+++ b/gnu/usr.bin/groff/tmac/TODO
@@ -0,0 +1,38 @@
+Support multiple line-spacing.
+
+Improve the device independence of the character definitions.
+
+If we have footnotes in the abstract in RP format, then the footnote
+will appear on the cover sheet, which it should, but also on the first
+page, which it should not.
+
+Should we allow multi-page cover-sheets?
+
+Warn about automatically numbered footnotes in floating keeps.
+
+When we bring back the footnote overflow at the top of page, it would
+be more efficient to avoid diverting it again. (Need to keep track of
+footnote height.)
+
+Possibly have a place above which the footnote trap must not be
+placed.
+
+Improved indexing, not using tm, controlled by string variable (eg
+-dIDX=file.idx).
+
+When changing from multi-column to narrower columns, we could avoid
+doing a @super-eject. (This might not be a good idea.)
+
+Think about cutmarks. Possibly implement CM.
+
+Implement thesis Mode (TM, CT).
+
+Implement more V10 features.
+
+Should this
+
+.LP
+.rs
+.sp \n(.tu
+
+print two pages?
diff --git a/gnu/usr.bin/groff/tmac/doc-common b/gnu/usr.bin/groff/tmac/doc-common
new file mode 100644
index 0000000..3c1aca4
--- /dev/null
+++ b/gnu/usr.bin/groff/tmac/doc-common
@@ -0,0 +1,456 @@
+.\" Copyright (c) 1991 The Regents of the University of California.
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)doc-common 5.7 (Berkeley) 8/5/91
+.\"
+.\" %beginstrip%
+.nr %A 1
+.nr %J 1
+.nr %N 1
+.nr %O 1
+.nr %R 1
+.nr %T 1
+.nr %V 1
+.nr Ad 12n
+.nr Ac 3
+.nr Ao 12n
+.nr Ap 2
+.nr An 12n
+.nr Aq 12n
+.nr Ar 12n
+.nr Bc 3
+.nr Bl 1
+.nr Bo 12n
+.nr Bq 12n
+.nr Bx 12n
+.nr Cd 12n
+.nr Cm 10n
+.nr Co 15n
+.nr Cx 20n
+.nr Dc 3
+.nr Do 10n
+.nr Dq 12n
+.nr Ds 6n
+.nr Dq 12n
+.nr Dv 12n
+.nr tI \n(Dsu
+.nr Ec 3
+.nr El 1
+.nr Eo 12n
+.nr Eq 12n
+.nr Em 10n
+.nr Er 12n
+.nr Ev 15n
+.nr Ex 10n
+.nr Fa 12n
+.nr Fl 10n
+.nr Fc 3
+.nr Fo 16n
+.nr Fn 16n
+.nr Hl 1
+.nr I1 6n
+.nr I2 12n
+.nr I3 18n
+.nr Ic 10n
+.nr Li 16n
+.nr Ms 6n
+.nr Nm 10n
+.nr No 12n
+.nr Ns 2
+.nr Oo 10n
+.nr Oc 3
+.nr Op 14n
+.nr Pa 32n
+.nr Pf 12n
+.nr Pc 3
+.nr Po 12n
+.nr Pq 12n
+.nr Ql 16n
+.nr Qc 3
+.nr Qo 12n
+.nr Qq 12n
+.nr Sc 3
+.nr So 12n
+.nr Sq 12n
+.nr Sy 6n
+.nr Sx 16n
+.nr Ra 1
+.nr Rj 1
+.nr Rn 1
+.nr Ro 1
+.nr Rr 1
+.nr Rt 1
+.nr Rv 1
+.nr Tn 10n
+.nr Ta 1
+.nr Tv 1
+.nr Tx 22n
+.nr Ux 10n
+.nr Va 12n
+.nr Xc 3
+.nr Xo 1
+.nr Xr 10n
+.ds sV \& \&
+.ds hV \&\ \&
+.ds iV \& \&
+.ds tV \&\\t\&
+.\" Punctuation values (3 = closing punctuation, 4 = opening)
+.nr z. 3
+.nr z, 3
+.nr z: 3
+.nr z; 3
+.nr z( 4
+.nr z) 3
+.nr z[ 4
+.nr z] 3
+.\" Matching pairs
+.ds z( z)
+.ds z[ z]
+.ds z< z>
+.\" This is disgusting, troff not parse ``if'' stmt properly
+.nr z0 0
+.nr z1 0
+.nr z2 0
+.nr z3 0
+.nr z4 0
+.nr z5 0
+.nr z6 0
+.nr z7 0
+.nr z8 0
+.nr z9 0
+.nr z# 0
+.\" Header assembly macros
+.de Dt
+.ds dT UNTITLED
+.ds vT LOCAL
+.ds cH Null
+.if !"\\$1"" .ds dT \\$1
+.if !"\\$2"" \{\
+. ds cH \\$2
+.\" . if "\\$3"" \{\
+. if \\$2>=1 .if \\$2<=8 \{\
+. ds vT FreeBSD Reference Manual
+. if \\$2>1 .if \\$2<6 .ds vT FreeBSD Programmer's Manual
+. if "\\$2"8" .ds vT FreeBSD System Manager's Manual
+. nr sN \\$2
+. \}
+. if "\\$2"unass" .ds vT DRAFT
+. if "\\$2"draft" .ds vT DRAFT
+. if "\\$2"paper" .ds vT UNTITLED
+.\" . \}
+.\}
+.if !"\\$3"" \{\
+. if "\\$3"USD" .ds vT FreeBSD User's Supplementary Documents
+. if "\\$3"PS1" .ds vT FreeBSD Programmers's Supplementary Documents
+. if "\\$3"AMD" .ds vT FreeBSD Ancestral Manual Documents
+. if "\\$3"SMM" .ds vT FreeBSD System Manager's Manual
+. if "\\$3"URM" .ds vT FreeBSD Reference Manual
+. if "\\$3"PRM" .ds vT FreeBSD Programmers's Manual
+. if "\\$3"IND" .ds vT FreeBSD Manual Master Index
+.\" . if "\\$3"CON" .ds vT FreeBSD Contributed Software Manual
+.\" . if "\\$3"IMP" .ds vT FreeBSD Implementation Notes
+.\" . if "\\$3"HOW" .ds vT FreeBSD How Pocket Manual
+. if "\\$3"LOCAL" .ds vT FreeBSD Local Manual
+. if "\\$3"tahoe" .as vT \ (Tahoe Architecture)
+. if "\\$3"vax" .as vT \ (VAX Architecture)
+. if "\\$3"hp300" .as vT \ (HP300 Architecture)
+. if "\\*(vT"LOCAL" .ds vT \\$3
+.\}
+..
+.\" NS Os macro - Operating System (behaviour changes after first call)
+.\" . ds vT \f(CODRAFT\fP\ \ \-\-\ \ \\*(vT\ \ \-\-\ \ \f(CODRAFT
+.\" . ds dD \f(CODRAFT\fP\ \ \-\-\ \ \\*(dD\ \ \-\-\ \ \f(CODRAFT
+.\" .ds vT \s+4\f(CODRAFT\fP\s-4\ \ \-\-\ \ \\*(vT\ \ \-\-\ \ \s+4\f(CODRAFT\s-4
+.\" .ds dD \s+4\f(CODRAFT\fP\s-4\ \ \-\-\ \ \\*(dD\ \ \-\-\ \ \s+4\f(CODRAFT\s-4
+.de Os
+.ds oS Null
+.if "\\$1"" \{\
+. ds oS BSD
+.\}
+.if "\\$2"" \{\
+. ds aa Non-Null
+.\}
+.if "\\$1"ATT" \{\
+. ds oS AT&T
+. if "\\$2"" .as oS \0UNIX
+. if "\\$2"7th" .as oS \07th Edition
+. if "\\$2"7" .as oS \07th Edition
+. if "\\$2"III" .as oS \0System III
+. if "\\$2"3" .as oS \0System III
+. if "\\$2"V" .as oS \0System V
+. if "\\$2"V.2" .as oS \0System V Release 2
+. if "\\$2"V.3" .as oS \0System V Release 3
+. if "\\$2"V.4" .as oS \0System V Release 4
+.\}
+.if "\\$1"BSD" \{\
+. if "\\$2"3" .ds oS 3rd Berkeley Distribution
+. if "\\$2"4" .ds oS 4th Berkeley Distribution
+. if "\\$2"4.1" .ds oS 4.1 Berkeley Distribution
+. if "\\$2"4.2" .ds oS 4.2 Berkeley Distribution
+. if "\\$2"4.3" .ds oS 4.3 Berkeley Distribution
+. if "\\$2"4.3T" .ds oS 4.3-Tahoe Berkeley Distribution
+. if "\\$2"4.3R" .ds oS 4.3-Reno Berkeley Distribution
+. if "\\$2"4.3t" .ds oS 4.3-Tahoe Berkeley Distribution
+. if "\\$2"4.3r" .ds oS 4.3-Reno Berkeley Distribution
+. if "\\$2"4.4" .ds oS 4.4BSD
+.\}
+.if "\\$1"FreeBSD" \{\
+. if "\\$2"2" .ds oS FreeBSD 2.0
+. if "\\$2"2.0" .ds oS FreeBSD 2.0
+. if "\\$2"2.0.5" .ds oS FreeBSD 2.0.5
+. if "\\$2"2.1" .ds oS FreeBSD 2.1
+. if "\\$2"2.2" .ds oS FreeBSD 2.2
+.\}
+.if "\\*(oS"Null" .ds oS \0\\$1
+.if "\\*(aa"Non-Null" .as oS \0\\$2
+.rm aa
+..
+.de Dd
+.if !"\\*(dD"" .nr gX 1
+.ie \\n(.$>0 \{\
+. ie \\n(.$==3 \{\
+. ds dD \\$1 \\$2 \\$3
+. \}
+. el \{\
+. if "\\n(mo"1" .ds dD January
+. if "\\n(mo"2" .ds dD February
+. if "\\n(mo"3" .ds dD March
+. if "\\n(mo"4" .ds dD April
+. if "\\n(mo"5" .ds dD May
+. if "\\n(mo"6" .ds dD June
+. if "\\n(mo"7" .ds dD July
+. if "\\n(mo"8" .ds dD August
+. if "\\n(mo"9" .ds dD September
+. if "\\n(mo"10" .ds dD October
+. if "\\n(mo"11" .ds dD November
+. if "\\n(mo"12" .ds dD December
+. as dD \&\ \\n(dy, 19\\n(yr
+. \}
+.\}
+.el \{\
+. ds dD Epoch
+.\}
+..
+.de hM
+.ev 1
+.pL
+.if !\\n(cR 'sp \\n(Hmu
+.tl @\\*(Hs\\*(hT\fP@\\*(Vs\\*(vT\fP@\\*(Hs\\*(hT\fP@
+'sp \\n(Hmu
+.ev
+..
+.de fM
+.ie \\n(cR 'br
+.el \{\
+. ev 1
+. pL
+. if !\\n(cR \{\
+' sp \\n(Fmu
+. tl @\\*(Hs\\*(oS\fP@\\*(Vs\\*(dD\fP@%@
+' bp
+. \}
+. ev
+.\}
+.\" .tm IN 444 fM .k == \\n(.k and nl == \\n(nl
+..
+.de lM
+.fl
+.if \\n(cR \{\
+' sp
+. tl @\\*(Hs\\*(oS\fP@\\*(Vs\\*(dD\fP@%@
+. pl \\n(nlu
+.\}
+..
+.de Pp
+.sp \\n(Ppu
+.ne 2
+.ns
+..
+.de Lp
+.Pp
+..
+.de LP
+.tm Not a \-mdoc command: .LP
+..
+.de PP
+.tm Not a \-mdoc command: .PP
+..
+.de pp
+.tm Not a \-mdoc command: .pp
+..
+.de Nd
+\&\-\& \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
+..
+.de Ss
+.sp
+.ne 2
+.ti -.25i
+\&\\*(sH\\$1 \|\\$2 \|\\$3 \|\\$4 \|\\$5 \|\\$6 \|\\$7 \|\\$8 \|\\$9
+\&\fP\s0
+.ta .5i 1i 1.5i 2i 2.5i 3i 3.5i 4i 4.5i 5i 5.5i 6i 6.5i
+.if !\\n(cR .ne 2
+.br
+..
+.de Rd
+.tm MDOC REGISTER DUMP
+.tm Db==\\n(Db register DEBUG MODE
+.tm L[0-9] registers - stack of list types
+.tm L0==\\n(L0
+.tm L1==\\n(L1
+.tm L2==\\n(L2
+.tm L3==\\n(L3
+.tm L4==\\n(L4
+.tm L5==\\n(L5
+.tm L6==\\n(L6
+.tm L7==\\n(L7
+.tm L8==\\n(L8
+.tm L9==\\n(L9
+.tm O[0-9] registers - stack of indent
+.tm O0==\\n(O0
+.tm O1==\\n(O1
+.tm O2==\\n(O2
+.tm O3==\\n(O3
+.tm O4==\\n(O4
+.tm O5==\\n(O5
+.tm O6==\\n(O6
+.tm O7==\\n(O7
+.tm O8==\\n(O8
+.tm O9==\\n(O9
+.tm aC==\\n(aC register argument counter (aV/fV)
+.tm aJ==\\n(aJ register (for vR)
+.tm aN==\\n(aN register
+.tm aP==\\n(aP register argument pointer (aV)
+.tm aT==\\n(aT register argument type
+.tm aa==\\n(aa local register
+.tm bK==\\n(bK register - Book Name flag
+.tm cF==\\n(cF register save current font
+.tm cI==\\n(cI register - column indent width
+.tm cZ==\\n(cZ register save current font size
+.tm dK==\\n(dK register - Date flag
+.tm d[0-9] registers - display-type stack
+.tm d0==\\n(d0
+.tm d1==\\n(d1
+.tm d2==\\n(d2
+.tm d3==\\n(d3
+.tm d4==\\n(d4
+.tm d5==\\n(d5
+.tm d6==\\n(d6
+.tm d7==\\n(d7
+.tm d8==\\n(d8
+.tm d9==\\n(d9
+.tm dZ==\\n(dZ register diversion count
+.tm fD==\\n(fD register subroutine test (in synopsis only)
+.tm fV==\\n(fV register argument counter (must set to \\n(.$ prior to
+.tm fY==\\n(fY register - dick with old style function declarations (fortran)
+.tm fZ==\\n(fZ register also subroutine count (in synopsis only)
+.tm h[0-9] register horizontal tag stack (continuous if 1, break if
+.tm h0==\\n(h0
+.tm h1==\\n(h1
+.tm h2==\\n(h2
+.tm h3==\\n(h3
+.tm h4==\\n(h4
+.tm h5==\\n(h5
+.tm h6==\\n(h6
+.tm h7==\\n(h7
+.tm h8==\\n(h8
+.tm h9==\\n(h9
+.tm iD==\\n(iD local register
+.tm iI==\\n(iI local register (indent for inline debug mode)
+.tm iN==\\n(iN register DEBUG MODE (inline if 1, to stderr if
+.tm iS==\\n(iS register - indent second command line in a synopsis
+.tm jK==\\n(jK register - [reference] Journal Name flag
+.tm jM==\\n(jM local register
+.tm jN==\\n(jN local register
+.tm lC==\\n(lC register - list type stack counter
+.tm lK==\\n(lK register count of lines read from input file
+.tm nK==\\n(nK register - [reference] issue number flag
+.tm nU==\\n(nU register count
+.tm oK==\\n(oK register - [reference] optional information flag
+.tm oM==\\n(oM register (extension possible)
+.tm o[0-9] register offset stack (nested tags)
+.tm o0==\\n(o0
+.tm o1==\\n(o1
+.tm o2==\\n(o2
+.tm o3==\\n(o3
+.tm o4==\\n(o4
+.tm o5==\\n(o5
+.tm o6==\\n(o6
+.tm o7==\\n(o7
+.tm o8==\\n(o8
+.tm o9==\\n(o9
+.tm oM==\\n(oM register open ended line flag
+.tm pK==\\n(pK register - [reference] page number flag
+.tm qK==\\n(qK register - Corporate or Foreign Author flag
+.tm rK==\\n(rK register - [reference] report flag
+.tm rS==\\n(rS register - Reference Start flag
+.tm sM==\\n(sM register - default is one (space mode on)
+.tm tK==\\n(tK register - reference title flag
+.tm tP==\\n(tP register tag flag (for diversions)
+.tm tX==\\n(tX register (initial class)
+.tm tY==\\n(tY register (next possible lC value)
+.tm t[0-9] register tag string stack (nested tags)
+.tm t0==\\n(t0
+.tm t1==\\n(t1
+.tm t2==\\n(t2
+.tm t3==\\n(t3
+.tm t4==\\n(t4
+.tm t5==\\n(t5
+.tm t6==\\n(t6
+.tm t7==\\n(t7
+.tm t8==\\n(t8
+.tm t9==\\n(t9
+.tm uK==\\n(uK register - reference author(s) counter
+.tm vK==\\n(vK register - reference volume flag
+.tm v[0-9] register vertical tag break stack
+.tm v0==\\n(v0
+.tm v1==\\n(v1
+.tm v2==\\n(v2
+.tm v3==\\n(v3
+.tm v4==\\n(v4
+.tm v5==\\n(v5
+.tm v6==\\n(v6
+.tm v7==\\n(v7
+.tm v8==\\n(v8
+.tm v9==\\n(v9
+.tm w[0-9] register tag stack (nested tags)
+.tm w0==\\n(w0
+.tm w1==\\n(w1
+.tm w2==\\n(w2
+.tm w3==\\n(w3
+.tm w4==\\n(w4
+.tm w5==\\n(w5
+.tm w6==\\n(w6
+.tm w7==\\n(w7
+.tm w8==\\n(w8
+.tm w9==\\n(w9
+.tm xX==\\n(xX local register
+.tm END OF REGISTER DUMP
+..
diff --git a/gnu/usr.bin/groff/tmac/doc-ditroff b/gnu/usr.bin/groff/tmac/doc-ditroff
new file mode 100644
index 0000000..039db7d
--- /dev/null
+++ b/gnu/usr.bin/groff/tmac/doc-ditroff
@@ -0,0 +1,281 @@
+.\" Copyright (c) 1991 The Regents of the University of California.
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)doc-ditroff 5.8 (Berkeley) 8/5/91
+.\"
+.\" tmac.mdoc-ditroff
+.\" %beginstrip%
+.\"
+.\" -rC1 numbers pages continuously; initialize to avoid warnings
+.if \n(.g .if !rC .nr C 0
+.ds aD \fI\s10
+.ds aR \f(CO\s10
+.ds cM \f(CB\s10
+.ds dF \fR\s10
+.ds eM \fI\s10
+.ds eR \fC\s10
+.ds eV \fC\s10
+.ds fA \f(CO\s10
+.ds fD \f(CB\s10
+.ds fL \f(CB\s10
+.ds fN \f(CB\s10
+.ds fP \fP\s0
+.ds fS \s0
+.ds fT \f(CO\s10
+.ds Hs \fR\s10
+.ds iC \f(CB\s10
+.ds lI \fC
+.ds lP \fR\|(\|\fP\s10
+.ds lp \fR(\fP\s10
+.ds rP \fR\|)\|\fP\s10
+.ds rp \fR)\fP\s10
+.ds lB \fR\^[\^\fP\s10
+.ds rB \fR\^]\fP\s10
+.ds mL \fB\s10
+.ds nM \f(CB\s10
+.ds nO \fR\s10
+.ds nT \s0
+.ds pA \fC\s10
+.ds Pu \fR{\ .\ ,\ :\ ;\ (\ )\ [\ ]\ \fR}
+.ds rA \fR\s10
+.ds rT \f(CO\s10
+.ds sH \fB\s10
+.ds sP \s0
+.ds sY \fB\s10
+.ds sX \fR\s10
+.ds tF \fR
+.ds tN \s9
+.ds vA \fI\s10
+.ds Vs \fR\s10
+.ds vT \f(CB\s10
+.ds xR \fC\s10
+.tr *\(**
+.nr sI \w\fC,u*5
+.nr Ti \n(sIu
+.nr Pp .5v
+.ds lS \0
+.nr lS \w'\0'u
+.nr dI 6n
+.de pL
+.nr Hm .5i
+.nr Fm .5i
+.nr ll 6.5i
+.ll 6.5i
+.nr lt 6.5i
+.lt 6.5i
+.nr po 1i
+.po 1.i
+.nr dV .5v
+..
+.ds <= \(<=
+.ds >= \(>=
+.ie \n(.g \{\
+. ds Lq \(lq
+. ds Rq \(rq
+.\}
+.el \{\
+. ds Lq \&``
+. ds Rq \&''
+.\}
+.ds ua \(ua
+.ds aa \(aa
+.ds ga \(ga
+.ds sR \&'
+.ds sL \&`
+.ds q \&"
+.\" Math stuff
+.ds Pi \(*p
+.ds Ne \(!=
+.ds Le \(<=
+.ds Ge \(>=
+.ds Lt <
+.ds Gt >
+.ds Pm \(+-
+.ds If \(if
+.ds Na \fINaN\fP
+.ds Ba \fR\&|\fP
+.\"
+.nr gX 0
+.de hK
+.ds hT \\*(dT
+.if !"\\*(cH"Null" \{\
+. ie !"\\*(gP"Null" .as hT \|(\|\\*(cH\\*(gP\|)
+. el .as hT \\|(\\|\\*(cH\\|)
+.\}
+.if "\\*(cH"Null" \{\
+. if !"\\*(gP"Null" .as hT \&\|(\|\\*(gP\|)
+.\}
+.wh 0 hM
+.wh -1.25i fM
+.nr nL \\n(nl
+.ie \\n(gX==1 \{\
+. rm n1
+. bp
+.\}
+.el \{\
+' bp
+.\}
+.\" Don't set the page number if this is the first page,
+.\" in case the user has used -n.
+.if \\n(nL>0 \{\
+. if !\\nC \{\
+. nr % 1
+. \}
+.\}
+.nr gX 0
+.em lM
+..
+.\"
+.nr fW \w\fC0
+.de sW
+.nr sW \w\fC\\$1
+.ie \\n(sW>=\\n(fW \{\
+. ie \\n(sW%\\n(fW .nr sW (\\n(sW/\\n(fW)+1
+. el .nr sW \\n(sW/\\n(fW
+.\}
+.el \{\
+. ie \\n(sW>0 .nr sW 1
+. el .nr sW 0
+.\}
+..
+.\"
+.de aW
+.nr sW \w\fC\\*(A\\$1
+.ie \\n(sW>=\\n(fW \{\
+. ie \\n(sW%\\n(fW .nr sW (\\n(sW/\\n(fW)+1
+. el .nr sW \\n(sW/\\n(fW
+.\}
+.el \{\
+. ie \\n(sW>0 .nr sW 1
+. el .nr sW 0
+.\}
+..
+.\" NS Ql macro - Quoted literal define
+.de Ql
+.if \\n(aC==0 \{\
+. ds mN Ql
+. ds A1 \\$1
+. ds A2 \\$2
+. ds A3 \\$3
+. ds A4 \\$4
+. ds A5 \\$5
+. ds A6 \\$6
+. ds A7 \\$7
+. ds A8 \\$8
+. nr fV \\n(.$
+. fV
+.\}
+.nr aP \\n(aP+1
+.aW \\n(aP
+.nr aP \\n(aP-1
+.if \\n(sW>2 .Li
+.if \\n(sW<=2 \{\
+.\" Db on
+. if (\\n(aP>0) \{\
+. ds A\\n(aP Li
+. nr aP \\n(aP -1
+. \}
+. if (\\n(aP==0) \{\
+. rm C0 C1 C2 C3 C4 C5 C6 C7 C8 C9
+. rm S1 S2 S3 S4 S5 S6 S7 S8 S9
+. rn A8 A9
+. rn A7 A8
+. rn A6 A7
+. rn A5 A6
+. rn A4 A5
+. rn A3 A4
+. rn A2 A3
+. rn A1 A2
+. ds A1 Li
+. nr fV \\n(aC+1
+. nr aC 0
+. fV
+. \}
+. ds qL \&\\*(sL
+. ds qR \&\\*(sR
+. En
+.\" Db off
+.\}
+..
+.\" NS Sh macro - Section Headers
+.\" NS nS register - Section Header SYNOPSIS flag
+.\" NS nF register - Section Header FILES flag
+.\" NS nA register - Section Header SEE ALSO flag
+.\" NS nT register - Section Header STANDARDS flag
+.de Sh
+.nr nS 0
+.nr sE 0
+.nr iS 0
+'ad
+.ie "\\$1"NAME" \{\
+. hK
+' in 0
+.\}
+.el \{\
+. nr nS 0
+. nr nA 0
+. nr nF 0
+. nr nT 0
+. nr nY 0
+. nr oT 0
+. if "\\$1"SYNOPSIS" \{\
+. na
+. nr nS 1
+. \}
+. if "\\$1"DESCRIPTION" \{\
+. nr fY 0
+. nr fZ 0
+. nr fB 0
+. nr Fb 0
+. ds Fb
+. \}
+. if "\\$1"SEE" \{\
+. nr nA 1
+. na
+. \}
+. if "\\$1"FILES" .nr nF 1
+. if "\\$1"STANDARDS" .nr nT 1
+. if "\\$1"AUTHORS" .nr nY 1
+. if "\\$1"SEE" .nr sE 1
+. in 0
+. nr aN 0
+.\}
+.pL
+'sp
+.ns
+.ta .5i 1i 1.5i 2i 2.5i 3i 3.5i 4i 4.5i 5i 5.5i 6i 6.5i
+.if !\\n(cR .ne 3
+'fi
+\&\\*(sH\\$1 \|\\$2 \|\\$3 \|\\$4 \|\\$5 \|\\$6 \|\\$7 \|\\$8 \|\\$9
+\&\fP\s0\&
+.in \\n(.iu+\\n(Tiu
+.ns
+..
diff --git a/gnu/usr.bin/groff/tmac/doc-nroff b/gnu/usr.bin/groff/tmac/doc-nroff
new file mode 100644
index 0000000..c036f21
--- /dev/null
+++ b/gnu/usr.bin/groff/tmac/doc-nroff
@@ -0,0 +1,225 @@
+.\" Copyright (c) 1991 The Regents of the University of California.
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)doc-nroff 5.6 (Berkeley) 8/5/91
+.\"
+.\" tmac.mdoc-nroff
+.\" %beginstrip%
+.\"
+.ds aD \fI
+.ds aR \fI
+.ds cM \fB
+.ds dF \fR
+.ds eM \fI
+.ds eR \fR
+.ds eV \fR
+.ds fA \fI
+.ds fD \fB
+.ds fL \fB
+.ds fN \fB
+.ds fP \fP
+.ds fS
+.ds fT \fI
+.ds Hs \fR
+.ds iC \fB
+.ds lI \fR
+.ds lP \fR\|(\fP
+.ds rP \fR\|)\fP
+.ds lp \fR\|(\fP
+.ds rp \fR\|)\fP
+.ds lB \fR\|[\|\fP
+.ds rB \fR\|]\fP
+.ds mL \fB
+.ds nM \fB
+.ds nO \fR
+.ds pA \fI
+.ds Pu {\ .\ ,\ ;\ :\ (\ )\ [\ ]}
+.ds rA \fR
+.ds rT \fI
+.ds sH \fB
+.ds sP
+.ds sY \fB
+.ds sX \fI
+.ds tF \fR
+.ds tN
+.ds vA \fI
+.ds Vs \fR
+.ds vT \fB
+.ds xR \fR
+.\" MISCELLANEOUS
+.nr sI .5i
+.nr Ti .5i
+.nr cR 1
+.nr Pp 1v
+.ds lS \0\0
+.nr lS \w'\0\0'u
+.nr dI 6n
+.\"
+.de pL
+.ie \\n(cR .nr Hm 0
+.el .nr Hm .5i
+.nr Fm .5i
+.nr ll 78n
+.ll 78n
+.nr lt 78n
+.lt 78n
+.nr po 0i
+.po 0i
+.nr dV 1v
+.ad l
+.na
+..
+.ds <= \&<\&=
+.ds >= \&>\&=
+.ds Rq ''
+.ds Lq ``
+.ds ua ^
+.ds aa \'
+.ds ga \`
+.ds sL `
+.ds sR '
+.ds q \&"
+.\" Math stuff
+.ds Pi pi
+.ds Ne !=
+.ds Le <=
+.ds Ge >=
+.ds Lt <
+.ds Gt >
+.ds Pm +-
+.ds If infinity
+.ds Na \fINaN\fP
+.ds Ba \fR\&|\fP
+
+.\"
+.de hK
+.nr % 1
+.ds hT \\*(dT
+.if !"\\*(cH"Null" \{\
+. ie !"\\*(gP"Null" .as hT \|(\|\\*(cH\\*(gP\|)
+. el .as hT \\|(\\|\\*(cH\\|)
+.\}
+.if "\\*(cH"Null" .if !"\\*(gP"Null" .as hT \&\|(\|\\*(gP\|)
+.ie \\n(cR \{\
+. hM
+. wh -1v fM
+.\}
+.el \{\
+. wh 0 hM
+. wh -1.167i fM
+.\}
+.if \\n(nl==0:\\n(nl==-1 'bp
+.em lM
+..
+.nr fW \w'0'
+.de sW
+.nr sW \w\\$1
+.ie \\n(sW>=\\n(fW \{\
+. ie \\n(sW%\\n(fW .nr sW (\\n(sW/\\n(fW)+1
+. el .nr sW \\n(sW/\\n(fW
+.\}
+.el .nr sW 0
+..
+.de aW
+.nr sW \w\\*(A\\$1
+.ie \\n(sW>=\\n(fW \{\
+. ie \\n(sW%\\n(fW .nr sW (\\n(sW/\\n(fW)+1
+. el .nr sW \\n(sW/\\n(fW
+.\}
+.el .nr sW 0
+..
+.\" NS Ql macro - Quoted literal define
+.de Ql
+.if \\n(aC==0 \{\
+. ds mN Ql
+. ds A1 \\$1
+. ds A2 \\$2
+. ds A3 \\$3
+. ds A4 \\$4
+. ds A5 \\$5
+. ds A6 \\$6
+. ds A7 \\$7
+. ds A8 \\$8
+. ds A9 \\$9
+. nr fV \\n(.$
+. fV
+.\}
+.ds qL \&\\*(sL
+.ds qR \&\\*(sR
+.En \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
+..
+.\" NS Sh macro - Section Headers
+.\" NS nS register - Section Header SYNOPSIS flag
+.\" NS nF register - Section Header FILES flag
+.\" NS nA register - Section Header SEE ALSO flag
+.\" NS nT register - Section Header STANDARDS flag
+.de Sh
+.nr nS 0
+.nr sE 0
+.nr iS 0
+.ie "\\$1"NAME" \{\
+. hK
+' in 0
+.\}
+.el \{\
+. nr nS 0
+. nr nA 0
+. nr nF 0
+. nr nT 0
+. nr nY 0
+. nr aN 0
+. nr oT 0
+. if "\\$1"SEE" .nr nA 1
+. if "\\$1"FILES" .nr nF 1
+. if "\\$1"STANDARDS" .nr nT 1
+. if "\\$1"SYNOPSIS" .nr nS 1
+. if "\\$1"DESCRIPTION" \{\
+. rr fB
+. rr Fb
+. ds Fb
+. nr fY 0
+. nr fZ 0
+. \}
+. if "\\$1"AUTHORS" .nr nY 1
+. in 0
+.\}
+.pL
+'sp
+.ns
+.ta .5i 1i 1.5i 2i 2.5i 3i 3.5i 4i 4.5i 5i 5.5i 6i 6.5i
+.if !\\n(cR .ne 3
+'fi
+\&\\*(sH\\$1 \|\\$2 \|\\$3 \|\\$4 \|\\$5 \|\\$6 \|\\$7 \|\\$8 \|\\$9
+\&\fP\s0\&
+.in \\n(.iu+\\n(Tiu
+.if "\\$1"SEE" .nr sE 1
+.ns
+..
diff --git a/gnu/usr.bin/groff/tmac/doc-syms b/gnu/usr.bin/groff/tmac/doc-syms
new file mode 100644
index 0000000..06ddf80
--- /dev/null
+++ b/gnu/usr.bin/groff/tmac/doc-syms
@@ -0,0 +1,314 @@
+.\" Copyright (c) 1991 The Regents of the University of California.
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)doc-syms 5.6 (Berkeley) 8/5/91
+.\"
+.\" %beginstrip%
+.\" NS Ux macro - UNIX
+.de Ux
+.nr cF \\n(.f
+.nr cZ \\n(.s
+.ds aa \&\f\\n(cF\s\\n(cZ
+.as b1 \&\\*(tNUNIX\\*(aa
+.rm aa
+.if \\n(aC==0 \{\
+. if \\n(.$>0 .aV \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
+.\}
+.ie \\n(aC>\\n(aP \{\
+. nr aP \\n(aP+1
+. ie \\n(C\\n(aP==1 \{\
+. \\*(A\\n(aP
+. \}
+. el .nR
+.\}
+.el .aZ
+..
+.\" NS Bx macro -BSD UNIX (fix smaller nroff version)
+.de Bx
+.nr cF \\n(.f
+.nr cZ \\n(.s
+.ds aa \&\f\\n(cF\s\\n(cZ
+.if \\n(aC==0 \{\
+. ie \\n(.$==0 \&\\*(tNBSD\\*(aa \\*(tNUNIX\\*(aa
+. el .aV \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
+.\}
+.if "\\$1"-alpha" \{\
+\&currently in alpha test.
+. aY
+.\}
+.if "\\$1"-beta" \{\
+\&currently in beta test.
+. aY
+.\}
+.if "\\$1"-devel" \{\
+\&currently under development.
+. aY
+.\}
+.if \\n(aC>\\n(aP \{\
+. nr aP \\n(aP+1
+. ie \\n(C\\n(aP==2 \{\
+. as b1 \&\\*(A\\n(aP\&\\*(tNBSD\\*(aa
+. ie \\n(aC>\\n(aP \{\
+. nr jj \\n(aP+1
+. ie \\n(C\\n(jj==2 \{\
+. if "\\*(A\\n(jj"Reno" \{\
+. nr aP \\n(aP+1
+. as b1 \&\-\\*(A\\n(jj
+. \}
+. if "\\*(A\\n(jj"reno" \{\
+. nr aP \\n(aP+1
+. as b1 \&\-Reno
+. \}
+. if "\\*(A\\n(jj"Tahoe" \{\
+. nr aP \\n(aP+1
+. as b1 \&\-\\*(A\\n(jj
+. \}
+. if "\\*(A\\n(jj"tahoe" \{\
+. nr aP \\n(aP+1
+. as b1 \&\-Tahoe
+. \}
+. ie \\n(aC>\\n(aP \{\
+. nr aP \\n(aP+1
+. nR
+. \}
+. el .aZ
+. \}
+. el \{\
+. nr aP \\n(aP+1
+. nR
+. \}
+. rr jj
+. \}
+. el .aZ
+. \}
+. el \{\
+. as b1 \&\\*(tNBSD\\*(aa U\\*(tNNIX\\*(aa
+. nR
+. \}
+.\}
+..
+.\" Ns Ud macro - prints "currently under development" (HISTORY section)
+.de Ud
+\&currently under development.
+..
+.\" Ns At macro - AT&T UNIX
+.de At
+.nr cF \\n(.f
+.nr cZ \\n(.s
+.ds aa \&\f\\n(cF\s\\n(cZ
+.if \\n(.$==2 \{\
+. if "\\$1"32v" \&Version 32V \\*(tNAT&T UNIX\\*(aa\\$2
+. if "\\$1"v6" \&Version 6 \\*(tNAT&T UNIX\\*(aa\\$2
+. if "\\$1"v7" \&Version 7 \\*(tNAT&T UNIX\\*(aa\\$2
+. if "\\$1"V" \&\\*(tNAT&T\\*(aa System V \\*(tNUNIX\\*(aa\\$2
+. if "\\$1"V.1" \&\\*(tNAT&T\\*(aa System V.1 \\*(tNUNIX\\*(aa\\$2
+. if "\\$1"V.2" \&\\*(tNAT&T\\*(aa System V.2 \\*(tNUNIX\\*(aa\\$2
+. if "\\$1"V.4" \&\\*(tNAT&T\\*(aa System V.4 \\*(tNUNIX\\*(aa\\$2
+.\}
+.if \\n(.$==1 \{\
+. if "\\$1"32v" \&Version 32V \\*(tNAT&T UNIX\\*(aa
+. if "\\$1"v6" \&Version 6 \\*(tNAT&T UNIX\\*(aa
+. if "\\$1"v7" \&Version 7 \\*(tNAT&T UNIX\\*(aa
+. if "\\$1"V" \&\\*(tNAT&T\\*(aa System V \\*(tNUNIX\\*(aa
+. if "\\$1"V.1" \&\\*(tNAT&T\\*(aa System V.1 \\*(tNUNIX\\*(aa
+. if "\\$1"V.2" \&\\*(tNAT&T\\*(aa System V.2 \\*(tNUNIX\\*(aa
+. if "\\$1"V.4" \&\\*(tNAT&T\\*(aa System V.4 \\*(tNUNIX\\*(aa
+.\}
+..
+.\" The Bt macro should go away now
+.\" Ns Bt macro - prints "is currently in beta test." (HISTORY section)
+.de Bt
+\&is currently in beta test.
+..
+.\" NS St macro - standards (posix, ansi - formal standard names)
+.ds Px \\*(tNPOSIX
+.ds Ai \\*(tNANSI
+.de St
+.if \\n(aC==0 \{\
+. ie \\n(.$==0 \{\
+.tm Usage: .St [-p1003.1-90 | -p1003.2 | -ansiC-89 | -iso ] \\*(Pu ... (#\\n(.c)
+. \}
+. el \{\
+. ds mN St
+. nr aP 0
+. ds A1 \\$1
+. ds A2 \\$2
+. ds A3 \\$3
+. ds A4 \\$4
+. ds A5 \\$5
+. ds A6 \\$6
+. ds A7 \\$7
+. ds A8 \\$8
+. ds A9 \\$9
+. nr fV \\n(.$
+. fV
+. \}
+.\}
+.if \\n(aC>\\n(aP \{\
+. nr cF \\n(.f
+. nr cZ \\n(.s
+. ds aa \&\f\\n(cF\s\\n(cZ
+. nr aP \\n(aP+1
+. if "\\*(A\\n(aP"-p1003.1-90" \{\
+. ie \\n(sT==1 \{\
+. ds b1 \&\\*(tNIEEE Std\\*(aa1003.1-1990\\*(sV
+. as b1 (``\\*(tN\\*(Px\\*(aa'')
+. \}
+. el \{\
+. ds b1 \&\\*(tNIEEE Std\\*(aa1003.1-1990\\*(sV
+. as b1 (``\\*(tN\\*(Px\\*(aa'')
+. \}
+. \}
+. if "\\*(A\\n(aP"-p1003.1-88" \{\
+. ie \\n(sT==1 \{\
+. ds b1 \&\\*(tNIEEE Std\\*(aa1003.1-1988\\*(sV
+. as b1 (``\\*(tN\\*(Px\\*(aa'')
+. \}
+. el \{\
+. ds b1 \&\\*(tNIEEE Std\\*(aa1003.1-1988\\*(sV
+. as b1 (``\\*(tN\\*(Px\\*(aa'')
+. \}
+. \}
+. if "\\*(A\\n(aP"-p1003.1" \{\
+. ie \\n(sT==1 \{\
+. ds b1 \&\\*(tNIEEE Std\\*(aa1003.1\\*(sV
+. as b1 (``\\*(tN\\*(Px\\*(aa'')
+. \}
+. el \{\
+. ds b1 \&\\*(tNIEEE Std\\*(aa1003.1\\*(sV
+. as b1 (``\\*(tN\\*(Px\\*(aa'')
+. \}
+. \}
+. if "\\*(A\\n(aP"-p1003.2-92" \{\
+. ie \\n(sT==1 \{\
+. ds b1 \&\\*(tNIEEE Std\\*(aa1003.2-1992\\*(sV
+. as b1 (``\\*(tN\\*(Px.2\\*(aa'')
+. \}
+. el \{\
+. ds b1 \&\\*(tNIEEE Std\\*(aa1003.2-1992\\*(sV
+. as b1 (``\\*(tN\\*(Px.2\\*(aa'')
+. \}
+. \}
+. if "\\*(A\\n(aP"-p1003.2" \{\
+. ie \\n(sT==1 \{\
+. ds b1 \&\\*(tNIEEE Std\\*(aa1003.2\\*(sV
+. as b1 (``\\*(tN\\*(Px.2\\*(aa'')
+. \}
+. el \{\
+. ds b1 \&\\*(tNIEEE Std\\*(aa1003.2\\*(sV
+. as b1 (``\\*(tN\\*(Px.2\\*(aa'')
+. \}
+. \}
+. if "\\*(A\\n(aP"-ansiC" \{\
+. ie \\n(sT==1 \{\
+. ds b1 \&\\*(tNISO \\*(aa9899:\ 1990\\*(sV
+. as b1 (``\\*(tNISO C\\*(aa'')
+. \}
+. el \{\
+. ds b1 \&\\*(tNISO \\*(aa9899:\ 1990\\*(sV
+. as b1 (``\\*(tNISO C\\*(aa'')
+. \}
+. \}
+. if "\\*(A\\n(aP"-isoC" \{\
+. ie \\n(sT==1 \{\
+. ds b1 \&\\*(tNISO \\*(aa9899:\ 1990\\*(sV
+. as b1 (``\\*(tNISO C\\*(aa'')
+. \}
+. el \{\
+. ds b1 \&\\*(tNISO \\*(aa9899:\ 1990\\*(sV
+. as b1 (``\\*(tNISO C\\*(aa'')
+. \}
+. \}
+. if "\\*(A\\n(aP"-iso9899" \{\
+. ie \\n(sT==1 \{\
+. ds b1 \&\\*(tNISO \\*(aa9899: 1990\\*(sV
+. as b1 (``\\*(tNISO C\\*(aa'')
+. \}
+. el \{\
+. ds b1 \&\\*(tNISO \\*(aa9899: 1990\\*(sV
+. as b1 (``\\*(tNISO C\\*(aa'')
+. \}
+. \}
+. if "\\*(A\\n(aP"-ansiC-89" \{\
+. ie \\n(sT==1 \{\
+. ds b1 \&\\*(tNANSI \\*(aaX3.159-1989\\*(sV
+. as b1 (``\\*(tNANSI C\\*(aa'')
+. \}
+. el \{\
+. ds b1 \&\\*(tNANSI \\*(aaX3.159-1989\\*(sV
+. as b1 (``\\*(tNANSI C\\*(aa'')
+. \}
+. \}
+. if "\\*(A\\n(aP"-ieee754" \{\
+. ie \\n(sT==1 \{\
+. ds b1 \&\\*(tNIEEE Std\\*(aa754-1985
+. \}
+. el \{\
+. ds b1 \&\\*(tNIEEE Std\\*(aa754-1985
+. \}
+. \}
+. if "\\*(A\\n(aP"-iso8802-3" \{\
+. ie \\n(sT==1 \{\
+. ds b1 \&\\*(tNISO \\*(aa8802-3: 1989\\*(sV
+.\" . as b1 (``\\*(tNANSI C\\*(aa'')
+. \}
+. el \{\
+. ds b1 \&\\*(tNISO \\*(aa8802-3: 1989\\*(sV
+.\" . as b1 (``\\*(tNANSI C\\*(aa'')
+. \}
+. \}
+. if "\\*(A\\n(aP"-xpg3" \{\
+. ie \\n(sT==1 \{\
+. ds b1 \&\\*(tNX/Open Portability Guide Issue 3\\*(aa\\*(sV
+. as b1 (``\\*(tNXPG3\\*(aa'')
+. \}
+. el \{\
+. ds b1 \&\\*(tNX/Open Portability Guide Issue 3\\*(aa\\*(sV
+. as b1 (``\\*(tNXPG3\\*(aa'')
+. \}
+. \}
+. if "\\*(A\\n(aP"-xpg4" \{\
+. ie \\n(sT==1 \{\
+. ds b1 \&\\*(tNX/Open Portability Guide Issue 4\\*(aa\\*(sV
+. as b1 (``\\*(tNXPG4\\*(aa'')
+. \}
+. el \{\
+. ds b1 \&\\*(tNX/Open Portability Guide Issue 4\\*(aa\\*(sV
+. as b1 (``\\*(tNXPG4\\*(aa'')
+. \}
+. \}
+. ie \\n(aC>\\n(aP \{\
+. nr aP \\n(aP+1
+. nR
+. \}
+. el .aZ
+.\}
+..
diff --git a/gnu/usr.bin/groff/tmac/eqnrc b/gnu/usr.bin/groff/tmac/eqnrc
new file mode 100644
index 0000000..fd064d1
--- /dev/null
+++ b/gnu/usr.bin/groff/tmac/eqnrc
@@ -0,0 +1,61 @@
+.\" Startup file for eqn.
+.EQ
+sdefine << %{ < back 20 < }%
+sdefine >> %{ > back 20 > }%
+
+sdefine dot %accent "\fR\(a.\fP"%
+sdefine dotdot %accent "\fR\(ad\fP"%
+sdefine vec %accent {up 52 "\s[\En[.s]/2u]\(->\s0"}%
+sdefine dyad %accent {up 52 "\s[\En[.s]/2u]\(<>\s0"}%
+
+sdefine cdot %type "binary" \(md%
+
+ifdef X75 ! define X %1% !
+ifdef X100 ! define X %1% !
+ifdef X75-12 ! define X %1% !
+ifdef X100-12 ! define X %1% !
+
+ifdef ps ! define ps|X %1% !
+ifdef X ! define ps|X %1% !
+
+ifdef ps|X ! sdefine inf %"\s[\En[.s]*13u/10u]\v'12M'\(if\v'-12M'\s0"% !
+
+ifdef dvi !
+sdefine int %{type "operator" vcenter \(is}%
+sdefine sum %{type "operator" vcenter \[sum]}%
+sdefine prod %{type "operator" vcenter \[product]}%
+sdefine coprod %{type "operator" vcenter \[coproduct]}%
+set num1 68
+set num2 39
+set denom1 69
+set denom2 34
+set sup1 41
+set sup2 36
+set sup3 29
+set sup_drop 39
+set sub_drop 5
+set axis_height 25
+set x_height 43
+set default_rule_thickness 4
+set big_op_spacing1 11
+set big_op_spacing2 16
+set big_op_spacing3 20
+set big_op_spacing4 60
+set big_op_spacing5 10
+!
+
+ifdef X ! set axis_height 32 !
+
+ifdef ps|X ! set draw_lines 1 !
+
+ifdef ascii ! define n %1% !
+ifdef latin1 ! define n %1% !
+ifdef koi8-r ! define n %1% !
+ifdef n !
+set nroff 1
+!
+
+undef X
+undef ps|X
+undef n
+.EN
diff --git a/gnu/usr.bin/groff/tmac/fixmacros.sed b/gnu/usr.bin/groff/tmac/fixmacros.sed
new file mode 100644
index 0000000..63cce22
--- /dev/null
+++ b/gnu/usr.bin/groff/tmac/fixmacros.sed
@@ -0,0 +1,6 @@
+s/^\([.'][ ]*[^\\ ][^ \\]\)\([^ ]\)/\1 \2/
+s/^\(\\![.'][ ]*[^\\ ][^ \\]\)\([^ ]\)/\1 \2/
+s/\([.'][ ]*i[ef] *[^ ]* [.'][ ]*[^\\0-9 ][^ \\]\)\([^ ]\)/\1 \2/
+s/\([.'][ ]*i[ef] *[^ ]* \\{[.'][ ]*[^\\0-9 ][^ \\]\)\([^ ]\)/\1 \2/
+s/\([.'][ ]*[da]s *[^ \\][^ \\]\)\([^ ]\)/\1 \2/
+s/\\\*\[/\\*[[]/
diff --git a/gnu/usr.bin/groff/tmac/groff_ms.man b/gnu/usr.bin/groff/tmac/groff_ms.man
new file mode 100644
index 0000000..d54e5b0
--- /dev/null
+++ b/gnu/usr.bin/groff/tmac/groff_ms.man
@@ -0,0 +1,218 @@
+.\" -*- nroff -*-
+.TH GROFF_MS @MAN7EXT@ "@MDATE@" "Groff Version @VERSION@"
+.SH NAME
+groff_ms \- groff ms macros
+.SH SYNOPSIS
+.B groff
+.B \-m@TMAC_S@
+[
+.IR options .\|.\|.
+]
+[
+.IR files .\|.\|.
+]
+.SH DESCRIPTION
+This manual page describes the GNU version of the ms macros,
+which is part of the groff document formatting system.
+The groff ms macros are intended to be compatible with the
+documented behaviour of the 4.3
+.SM BSD
+Unix ms macros subject to the following limitations:
+.IP \(bu
+the internals of groff ms are not similar to the internals of Unix ms
+and so documents that depend upon implementation details of Unix ms
+may well not work with groff ms;
+.IP \(bu
+there is no support for typewriter-like devices;
+.IP \(bu
+Berkeley localisms, in particular the
+.B TM
+and
+.B CT
+macros, are not implemented;
+.IP \(bu
+groff ms
+does not provide cut marks;
+.IP \(bu
+multiple line spacing is not allowed
+(use a larger vertical spacing instead);
+.IP \(bu
+groff ms does not work in compatibility mode (eg with the
+.B \-C
+option);
+.IP \(bu
+the error-handling policy of groff ms
+is to detect and report errors,
+rather than silently to ignore them.
+.LP
+The groff ms macros make use of many features of GNU troff
+and therefore cannot be used with any other troff.
+.LP
+Bell Labs localisms are not implemented in either the
+.SM BSD
+ms macros or in the groff ms macros.
+.LP
+Some Unix ms documentation says that the
+.B CW
+and
+.B GW
+number registers can be used to control the column width and
+gutter width respectively.
+This is not the case.
+These number registers are not used in groff ms.
+.LP
+Macros that cause a reset set the indent.
+Macros that change the indent do not increment or decrement
+the indent, but rather set it absolutely.
+This can cause problems for documents that define
+additional macros of their own.
+The solution is to use not the
+.B in
+request but instead the
+.B RS
+and
+.B RE
+macros.
+.LP
+The number register
+.B GS
+is set to 1 by the groff ms macros,
+but is not used by the Unix ms macros.
+It is intended that documents that need to determine whether
+they are being formatted with Unix ms or groff ms make use of this
+number register.
+.LP
+Footnotes are implemented so that they can safely be used within
+keeps and displays.
+Automatically numbered footnotes within floating keeps are
+not recommended.
+It is safe to have another
+.B \e**
+between a
+.B \e**
+and the corresponding
+.BR .FS ;
+it is required only that each
+.B .FS
+occur after the corresponding
+.B \e**
+and that the occurrences of
+.B .FS
+are in the same order as the corresponding occurrences of
+.BR \e** .
+.LP
+The strings
+.B \e*{
+and
+.B \e*}
+can be used to begin and end a superscript.
+.LP
+Some Unix V10 ms features are implemented.
+The
+.BR B ,
+.BR I
+and
+.B BI
+macros can have an optional third argument which will be printed
+in the current font before the first argument.
+There is a macro
+.B CW
+like
+.B B
+that changes to a constant-width font.
+.LP
+The following strings can be redefined to adapt the groff ms macros
+to languages other than English:
+.LP
+.nf
+.ta \w'REFERENCES'u+2n
+String Default Value
+.sp .3v
+REFERENCES References
+ABSTRACT ABSTRACT
+TOC Table of Contents
+MONTH1 January
+MONTH2 February
+MONTH3 March
+MONTH4 April
+MONTH5 May
+MONTH6 June
+MONTH7 July
+MONTH8 August
+MONTH9 September
+MONTH10 October
+MONTH11 November
+MONTH12 December
+.fi
+.LP
+The font family is reset from the string
+.BR FAM ;
+at initialization if this string is undefined it is set to the current
+font family.
+The point size, vertical spacing, and inter-paragraph spacing for footnotes
+are taken from the number registers
+.BR FPS ,
+.BR FVS ,
+and
+.BR FPD ;
+at initialization these are set to
+.BR \en(PS-2 ,
+.BR \en[FPS]+2 ,
+and
+.B \en(PD/2
+respectively; however, if any of these registers has been defined
+before initialization, it will not be set.
+The hyphenation flags (as set by the
+.B .hy
+request) are set from the
+.B HY
+register;
+if this has not been defined at initialization,
+it will be set to 14.
+.LP
+Right-aligned displays are available with
+.B ".DS R"
+and
+.BR .RD .
+.LP
+The following conventions are used for names of macros, strings and
+number registers.
+External names available to documents that use the groff ms
+macros contain only uppercase letters and digits.
+Internally the macros are divided into modules.
+Names used only within one module are of the form
+.IB module * name\fR.
+Names used outside the module in which they are defined are of the form
+.IB module @ name\fR.
+Names associated with a particular environment are of the form
+.IB environment : name;
+these are used only within the
+.B par
+module,
+and
+.I name
+does not have a module prefix.
+Constructed names used to implement arrays are of the form
+.IB array ! index\fR.
+Thus the groff ms macros reserve the following names:
+.IP \(bu
+names containing
+.BR * ;
+.IP \(bu
+names containing
+.BR @ ;
+.IP \(bu
+names containing
+.BR : ;
+.IP \(bu
+names containing only uppercase letters and digits.
+.SH FILES
+.B @MACRODIR@/tmac.@TMAC_S@
+.SH "SEE ALSO"
+.BR groff (@MAN1EXT@),
+.BR @g@troff (@MAN1EXT@),
+.BR @g@tbl (@MAN1EXT@),
+.BR @g@pic (@MAN1EXT@),
+.BR @g@eqn (@MAN1EXT@)
+.br
+.BR ms (@MAN7EXT@)
diff --git a/gnu/usr.bin/groff/tmac/man.local b/gnu/usr.bin/groff/tmac/man.local
new file mode 100644
index 0000000..7bb8f50
--- /dev/null
+++ b/gnu/usr.bin/groff/tmac/man.local
@@ -0,0 +1,2 @@
+.\" This file is loaded after tmac.an.
+.\" Put any local modifications to tmac.an here.
diff --git a/gnu/usr.bin/groff/tmac/man.ultrix b/gnu/usr.bin/groff/tmac/man.ultrix
new file mode 100644
index 0000000..49d7b25
--- /dev/null
+++ b/gnu/usr.bin/groff/tmac/man.ultrix
@@ -0,0 +1,103 @@
+.\" Install this as man.local if you're using Ultrix.
+.\" Ultrix specific additions to groff -man macros.
+.\" Written by James Clark from a specification by Martyn.Johnson@cl.cam.ac.uk.
+.\"
+.\" I1 and I2 are unimplemented.
+.de CT
+<CTRL/\\$1>
+..
+.de CW
+.ft CR
+..
+.de Ds
+.br
+.nf
+.ft R
+..
+.de De
+.ce 0
+.fi
+..
+.de EX
+.br
+.if \\n[.$] .in +(n;\\$1)
+.ft CR
+.nf
+..
+.de EE
+.fi
+.ft R
+.in \\n[an-margin]u
+..
+.de G
+.it 1 an-trap
+.ft H
+.if \\n[.$] \&\\$*
+..
+.de GL
+.it 1 an-trap
+.ft HI
+.if \\n[.$] \&\\$*
+..
+.if n .ig
+.de HB
+.ie \\n[.$] .ft HB
+.el \f[HB]\\$*\fP
+..
+.if t .ig
+.de HB
+.ie \\n[.$] .ul 999
+.el .ul
+\\$*
+..
+.als TB HB
+.de MS
+\&\f[CR]\\$1\fR(\\$2)\\$3
+..
+.de NT
+.br
+.ds an-note Note
+.ce 1
+.if \\n[.$] \{\
+. ie '\\$1'C' \{\
+. ce 99
+. if \\n[.$]>1 .ds an-note \\$2
+. \}
+. el \{\
+. ds an-note \\$1
+. if '\\$2'C' .ce 99
+. \}
+.\}
+.in \\n[an-margin]u+5n
+.ll \\n[LL]u-5n
+.sp .5v>?\n[.V]u
+\&\\*[an-note]
+.sp .5v>?\n[.V]u
+.
+..
+.de NE
+.ll \\n[LL]u
+.in \\n[an-margin]u
+.ce 0
+.sp .5v>?\n[.V]u
+..
+.de PN
+\&\f[CR]\\$1\fP\\$2
+..
+.de Pn
+.ie \\n(.$>1 \&\\$1\f[CR]\\$2\fP\\$3
+.el \&\f[CR]\\$1\fP\\$2
+..
+.de R
+.ft R
+.ul 0
+..
+.de RN
+<RETURN>
+..
+.de VS
+.if '\\$1'4' .mc \[br]
+..
+.de VE
+.mc
+..
diff --git a/gnu/usr.bin/groff/tmac/me.man b/gnu/usr.bin/groff/tmac/me.man
new file mode 100644
index 0000000..4919621
--- /dev/null
+++ b/gnu/usr.bin/groff/tmac/me.man
@@ -0,0 +1,274 @@
+.\" Copyright (c) 1980 The Regents of the University of California.
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms are permitted
+.\" provided that the above copyright notice and this paragraph are
+.\" duplicated in all such forms and that any documentation,
+.\" advertising materials, and other materials related to such
+.\" distribution and use acknowledge that the software was developed
+.\" by the University of California, Berkeley. The name of the
+.\" University may not be used to endorse or promote products derived
+.\" from this software without specific prior written permission.
+.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+.\" IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+.\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+.\"
+.\" @(#)me.7 6.4 (Berkeley) 4/13/90
+.\"
+.\" Modified for groff by jjc@jclark.com
+.hc %
+.TH GROFF_ME @MAN7EXT@ "@MDATE@" "Groff Version @VERSION@"
+.UC 3
+.SH NAME
+groff_me \- troff macros for formatting papers
+.SH SYNOPSIS
+.B "groff \-me"
+[ options ]
+file ...
+.br
+.B "troff \-me"
+[ options ]
+file ...
+.SH DESCRIPTION
+This manual page describes the GNU version of the \-me macros,
+which is part of the groff document formatting system.
+This version can be used with both GNU troff and Unix troff.
+This package of
+.I troff
+macro definitions provides a canned formatting
+facility for tech%nical papers in various formats.
+.PP
+The macro requests are defined below.
+Many
+.I troff
+requests are unsafe in conjunction with
+this package, however, these requests may be used with
+impunity after the first .pp:
+.nf
+.IP
+.ta \w'.sz +n 'u
+\&.bp begin new page
+\&.br break output line here
+\&.sp n insert n spacing lines
+\&.ls n (line spacing) n=1 single, n=2 double space
+\&.na no alignment of right margin
+\&.ce n center next n lines
+\&.ul n underline next n lines
+.fi
+.PP
+Output of the
+.I pic,
+.I eqn,
+.I refer,
+and
+.I tbl
+preprocessors
+is acceptable as input.
+.SH FILES
+@MACRODIR@/tmac.e
+.SH "SEE ALSO"
+.BR groff (@MAN1EXT@),
+.BR @g@troff (@MAN1EXT@)
+.br
+\-me Reference Manual, Eric P. Allman
+.br
+Writing Papers with Groff Using \-me
+.tr &.
+.SH REQUESTS
+This list is incomplete;
+see
+.I "The \-me Reference Manual"
+for interesting details.
+.PP
+.ta \w'.eh \'x\'y\'z\' 'u +\w'Initial 'u +\w'Cause 'u
+.br
+.di x
+ \ka
+.br
+.di
+.in \nau
+.ti 0
+Request Initial Cause Explanation
+.ti 0
+ Value Break
+.br
+.in \nau
+.ti 0
+\&.(c - yes Begin centered block
+.ti 0
+\&.(d - no Begin delayed text
+.ti 0
+\&.(f - no Begin footnote
+.ti 0
+\&.(l - yes Begin list
+.ti 0
+\&.(q - yes Begin major quote
+.ti 0
+\&.(x \fIx\fR - no Begin indexed item in index
+.I x
+.ti 0
+\&.(z - no Begin floating keep
+.ti 0
+\&.)c - yes End centered block
+.ti 0
+\&.)d - yes End delayed text
+.ti 0
+\&.)f - yes End footnote
+.ti 0
+\&.)l - yes End list
+.ti 0
+\&.)q - yes End major quote
+.ti 0
+\&.)x - yes End index item
+.ti 0
+\&.)z - yes End floating keep
+.ti 0
+\&.++ \fIm H\fR - no Define paper section.
+.I m
+defines the part of the paper, and can be
+.B C
+(chapter),
+.B A
+(appendix),
+.B P
+(preliminary, e.g., abstract, table of contents, etc.),
+.B B
+(bibliography),
+.B RC
+(chapters renumbered from page one each chapter),
+or
+.B RA
+(appendix renumbered from page one).
+.ti 0
+\&.+c \fIT\fR - yes Begin chapter (or appendix, etc., as
+set by .++).
+.I T
+is the chapter title.
+.ti 0
+\&.1c 1 yes One column format on a new page.
+.ti 0
+\&.2c 1 yes Two column format.
+.ti 0
+\&.EN - yes Space after equation
+produced by
+.I eqn
+or
+.IR neqn .
+.ti 0
+\&.EQ \fIx y\fR - yes Precede equation; break out and
+add space.
+Equation number is
+.IR y .
+The optional argument \fIx\fR
+may be
+.I I
+to indent equation (default),
+.I L
+to left-adjust the equation, or
+.I C
+to center the equation.
+.ti 0
+\&.GE - yes End \fIgremlin\fP picture.
+.ti 0
+\&.GS - yes Begin \fIgremlin\fP picture.
+.ti 0
+\&.PE - yes End \fIpic\fP picture.
+.ti 0
+\&.PS - yes Begin \fIpic\fP picture.
+.ti 0
+\&.TE - yes End table.
+.ti 0
+\&.TH - yes End heading section of table.
+.ti 0
+\&.TS \fIx\fR - yes Begin table; if \fIx\fR is
+.I H
+table has repeated heading.
+.ti 0
+\&.b \fIx\fR no no Print
+.I x
+in boldface; if no argument switch to boldface.
+.ti 0
+\&.ba \fI+n\fR 0 yes Augments the base indent by
+.I n.
+This indent is used to set the indent on regular text
+(like paragraphs).
+.ti 0
+\&.bc no yes Begin new column
+.ti 0
+\&.bi \fIx\fR no no Print
+.I x
+in bold italics (nofill only)
+.ti 0
+\&.bu - yes Begin bulleted paragraph
+.ti 0
+\&.bx \fIx\fR no no Print \fIx\fR in a box (nofill only).
+.ti 0
+\&.ef \fI\'x\'y\'z\'\fR \'\'\'\' no Set even footer to x y z
+.ti 0
+\&.eh \fI\'x\'y\'z\'\fR \'\'\'\' no Set even header to x y z
+.ti 0
+\&.fo \fI\'x\'y\'z\'\fR \'\'\'\' no Set footer to x y z
+.ti 0
+\&.hx - no Suppress headers and footers on next page.
+.ti 0
+\&.he \fI\'x\'y\'z\'\fR \'\'\'\' no Set header to x y z
+.ti 0
+\&.hl - yes Draw a horizontal line
+.ti 0
+\&.i \fIx\fR no no Italicize
+.I x;
+if
+.I x
+missing, italic text follows.
+.ti 0
+\&.ip \fIx y\fR no yes Start indented paragraph,
+with hanging tag
+.IR x .
+Indentation is
+.I y
+ens (default 5).
+.ti 0
+\&.lp yes yes Start left-blocked paragraph.
+.ti 0
+\&.np 1 yes Start numbered paragraph.
+.ti 0
+\&.of \fI\'x\'y\'z\'\fR \'\'\'\' no Set odd footer to x y z
+.ti 0
+\&.oh \fI\'x\'y\'z\'\fR \'\'\'\' no Set odd header to x y z
+.ti 0
+\&.pd - yes Print delayed text.
+.ti 0
+\&.pp no yes Begin paragraph.
+First line indented.
+.ti 0
+\&.r yes no Roman text follows.
+.ti 0
+\&.re - no Reset tabs to default values.
+.ti 0
+\&.sh \fIn x\fR - yes Section head follows,
+font automatically bold.
+.I n
+is level of section,
+.I x
+is title of section.
+.ti 0
+\&.sk no no Leave the next page blank.
+Only one page is remembered ahead.
+.ti 0
+\&.sm \fIx\fR - no Set
+.I x
+in a smaller pointsize.
+.ti 0
+\&.sz \fI+n\fR 10p no Augment the point size by
+.I n
+points.
+.ti 0
+\&.tp no yes Begin title page.
+.ti 0
+\&.u \fIx\fR - no Underline argument (even in \fItroff\fR).
+(Nofill only).
+.ti 0
+\&.uh - yes Like .sh but unnumbered.
+.ti 0
+\&.xp \fIx\fR - no Print index
+.I x.
diff --git a/gnu/usr.bin/groff/tmac/strip.sed b/gnu/usr.bin/groff/tmac/strip.sed
new file mode 100644
index 0000000..b309e86
--- /dev/null
+++ b/gnu/usr.bin/groff/tmac/strip.sed
@@ -0,0 +1,2 @@
+/%beginstrip%/,$s/[ ]*\\".*//
+/^\.$/d
diff --git a/gnu/usr.bin/groff/tmac/tmac.X b/gnu/usr.bin/groff/tmac/tmac.X
new file mode 100644
index 0000000..53dd596
--- /dev/null
+++ b/gnu/usr.bin/groff/tmac/tmac.X
@@ -0,0 +1,46 @@
+.nr _C \n(.C
+.cp 0
+.ftr CW CR
+.ftr C CR
+.ftr CO CI
+.ftr CX CBI
+.ftr H HR
+.ftr HO HI
+.ftr HX HBI
+.ftr NX NBI
+.char \(ru \D'l .5m 0'
+.char \(ul \v'.25m'\D'l .5m 0'\v'-.25m'
+.char \(br \v'.25m'\D'l 0 -1m'\v'.75m'
+.char \(rn \v'-.75m'\D'l .5m 0'\v'.75m'
+.char ~ \v'-.55m'\\s[\\n(.s/2u]\v'.2m'\(ti\v'-.2m'\s0\v'.55m'
+.char ^ \v'-.55m'\\s[\\n(.s/2u]\v'.3m'\(ha\v'-.3m'\s0\v'.55m'
+.if !c\(va .char \(va \o'\(ua\(da'
+.if !c\(em .char \(em --
+.if !c\(en .char \(en \-
+.if !c\(fi .char \(fi fi
+.if !c\(fl .char \(fl fl
+.if !c\(ff .char \(ff ff
+.if !c\(Fi .char \(Fi ffi
+.if !c\(Fl .char \(Fl ffl
+.if !c\(ci .char \(ci \v'-.25m'\h'.05m'\D'c .5m'\h'.05m'\v'.25m'
+.if !c\(sq .char \(sq \h'.05m'\D'l .5m 0'\D'l 0 -.5m'\D'l -.5m 0'\D'l 0 .5m'\h'.55m'
+.if !c\(ga .char \(ga \Z'\v'-.7m'\D'l .22m .18m''\h'.33m'
+.if !c\(dg .char \(dg \Z'\h'.25m'\v'.15m'\D'l 0 -.8m'\v'.2m'\h'-.195m'\
+\D'l .39m 0''\h'.5m'
+.if !c\(dd .char \(dd \Z'\h'.25m'\v'.15m'\D'l 0 -.8m'\v'.2m'\h'-.195m'\
+\D'l .39m 0'\v'.4m'\D'l -.39m 0''\h'.5m'
+.if !c\(lq .char \(lq ``
+.if !c\(rq .char \(rq ''
+.if !c\(Bq .char \(bq ,,
+.if !c\(OE .char \(OE O\h'-.25m'E
+.if !c\(oe .char \(oe o\h'-.14m'e
+.if !c\(ah .char \(ah \v'-.55m'\s[\En[.s]/2u]v\s0\v'.55m'
+.if !c\(ao .char \(ao \v'-.55m'\s[\En[.s]*6u/10u]\D'c .25m'\s0\v'.55m'
+.if !c\(ho .char \(ho \s[\En[.s]/2u]\v'.4m'c\v'-.4m'\s0
+.if !c\(lh .tr \(lh\(lA
+.if !c\(rh .tr \(rh\(rA
+.if !c\(bq .tr \(bq,
+.if !c\(aq .tr \(aq'
+.if '\*(.T'X100' .char \[radicalex] \h'-\w'\(sr'u'\[radicalex]\h'\w'\(sr'u'
+.if !\n(_C .mso tmac.pspic
+.cp \n(_C
diff --git a/gnu/usr.bin/groff/tmac/tmac.Xps b/gnu/usr.bin/groff/tmac/tmac.Xps
new file mode 100644
index 0000000..92471ab
--- /dev/null
+++ b/gnu/usr.bin/groff/tmac/tmac.Xps
@@ -0,0 +1,44 @@
+.do mso tmac.ps
+.nr _C \n(.C
+.cp 0
+.de Xps-char
+.char \\$1 \Z"\X'ps: invis'\\$2\X'ps: endinvis'"\\$1
+..
+.Xps-char \(bu \fS\(bu\fP
+.Xps-char \(em "\v'-.25m'\h'.05m'\D'l .9m 0'\h'.05m'"
+.Xps-char \(aq '
+.Xps-char \(bq ,
+.Xps-char \(Bq ,,
+.Xps-char \(lq ``
+.Xps-char \(rq ''
+.Xps-char \(OE OE
+.Xps-char \(oe oe
+.Xps-char \(Fn \fS\(Fn\fP
+.Xps-char \(vS \o'\(ahS'
+.Xps-char \(vs \o'\(ahs'
+.Xps-char \(vZ \o'\(ahZ'
+.Xps-char \(vz \o'\(ahz'
+.Xps-char \(/L \o'/L'
+.Xps-char \(/l \o'/l'
+.Xps-char \(:Y \o'\(adY'
+.Xps-char \(a" \(sd
+.Xps-char \(a. \v'-.6m'.
+.Xps-char \(ga "\Z'\v'-.7m'\D'l .22m .18m''\h'.33m'"
+.Xps-char \(ab \v'-.55m'\s'\\\\n(.s*6u/10u'u\s0
+.Xps-char \(ah \v'-.55m'\s[\En[.s]/2u]v\s0\v'.55m'
+.Xps-char \(ao "\v'-.55m'\s[\En[.s]*6u/10u]\D'c .25m'\s0\v'.55m'"
+.Xps-char \(ho \s[\En[.s]/2u]\v'.4m'c\v'-.4m'\s0
+.Xps-char \(.i i
+.Xps-char \(fo <
+.Xps-char \(fc >
+.Xps-char \(OK \s'\\\\n(.s*6u/10u'\e\s0/
+.Xps-char \(tm \v'-.3m'\s'\\\\n(.s*6u/10u'TM\s0\v'.3m'
+.Xps-char \(dd "\Z'\h'.25m'\v'.15m'\D'l 0 -.8m'\v'.2m'\h'-.195m'\
+\D'l .39m 0'\v'.4m'\D'l -.39m 0''\h'.5m'"
+.Xps-char \(dg "\Z'\h'.25m'\v'.15m'\D'l 0 -.8m'\v'.2m'\h'-.195m'\
+\D'l .39m 0''\h'.5m'"
+.Xps-char \(en \-
+.Xps-char \(%0 %\s'\\\\n(.s*6u/10u'\fI0\fP\s0
+.Xps-char \(lh \(->
+.Xps-char \(rh \(<-
+.cp \n(_C
diff --git a/gnu/usr.bin/groff/tmac/tmac.an b/gnu/usr.bin/groff/tmac/tmac.an
new file mode 100644
index 0000000..017a6a8
--- /dev/null
+++ b/gnu/usr.bin/groff/tmac/tmac.an
@@ -0,0 +1,326 @@
+.\"Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
+.\" Written by James Clark (jjc@jclark.com)
+.\"
+.\"This file is part of groff.
+.\"
+.\"groff is free software; you can redistribute it and/or modify it under
+.\"the terms of the GNU General Public License as published by the Free
+.\"Software Foundation; either version 2, or (at your option) any later
+.\"version.
+.\"
+.\"groff is distributed in the hope that it will be useful, but WITHOUT ANY
+.\"WARRANTY; without even the implied warranty of MERCHANTABILITY or
+.\"FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+.\"for more details.
+.\"
+.\"You should have received a copy of the GNU General Public License along
+.\"with groff; see the file COPYING. If not, write to the Free Software
+.\"Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+.\"
+.\" -rC1 => number pages continuously, rather than start each at 1
+.\" -rD1 => double-sided printing, ie different odd and even page footers
+.\" -rPnnn => number first page nnn
+.\" -rXnnn => number pages after nnn as nnna, nnnb, nnnc, ...
+.\"
+.\" The file man.local is loaded at the end. Put local additions there.
+.\" If you need to add things to TH, use `.am TH'.
+.\"
+.if !\n(.g .ab These man macros work only with groff.
+.nr _C \n(.C
+.cp 0
+.if !rD .nr D 0
+.if !rC .nr C 0
+.if rP .pn 0\nP
+.\" .TH title section extra1 extra2 extra3
+.de TH
+.cp 0
+.de an-init \" We have to do it like this to get multiple man pages right.
+.ds an-title "\\$1
+.ds an-section "\\$2
+.ds an-extra1 "\\$3
+.ie \\n[.$]>3 .ds an-extra2 "\\$4
+.el .ds an-extra2 \"Sun Release 4.0
+.ie \\n[.$]>4 .ds an-extra3 "\\$5
+.el .ds an-extra3 \"UNIX Programmer's Manual
+.ds an-init
+\\..
+.DT
+.nr IN 7.2n
+.nr LL 6.5i
+.PD
+.nr PS 10 \" normal point-size
+.nr SN 3n \" the indentation of sub-sub-headings relative to sub-headings
+.nr an-level 1
+.nr an-margin \\n[IN]
+.nr an-prevailing-indent \\n[IN]
+.nr an-tag-sep 1n
+.nr an-no-space-flag 0
+.nr an-break-flag 0
+.nr an-div? 0
+.wh 0 an-header
+.wh -1i an-footer
+.wh -.5i an-p-footer
+.if \\n[nl]>0 \{\
+. ie \\nC .bp \\n%+1
+. el .bp 1
+.\}
+..
+.de DT
+.ta T .5i \" This sets tabs every .5 inches
+..
+.de PD
+.ie \\n[.$] .nr PD (v;\\$1)
+.el .nr PD .4v>?\n[.V]
+..
+.de an-header
+.an-init
+.ev 1
+.sp .5i
+.tl '\\*[an-title](\\*[an-section])'\\*[an-extra3]'\\*[an-title](\\*[an-section])'
+.sp |1i
+.ev
+.ns
+..
+.de an-footer
+'bp
+..
+.af an-page-letter a
+.de an-p-footer
+.ev 1
+.ds an-page-string \\n%
+.if rX \{\
+. if \\n%>\\nX \{\
+. nr an-page-letter \\n%-\\nX
+. ds an-page-string \\nX\\n[an-page-letter]
+.\}\}
+.ie \\nD \{\
+. if o .tl '\\*[an-extra2]'\\*[an-extra1]'\\*[an-page-string]'
+. if e .tl '\\*[an-page-string]'\\*[an-extra1]'\\*[an-extra2]'
+.\}
+.el .tl '\\*[an-extra2]'\\*[an-extra1]'\\*[an-page-string]'
+.ev
+..
+.de SH
+.sp \\n[PD]u
+.nr an-level 1
+.nr an-margin \\n[IN]
+.nr an-prevailing-indent \\n[IN]
+.fi
+.in \\n[IN]u
+.ti 0
+.it 1 an-trap
+.nr an-no-space-flag 1
+.nr an-break-flag 1
+.ps \\n[PS]-1
+.ft B
+.ne 2v+1u
+.if \\n[.$] \&\\$*
+..
+.de SS
+.sp \\n[PD]u
+.nr an-level 1
+.nr an-margin \\n[IN]
+.nr an-prevailing-indent \\n[IN]
+.fi
+.in \\n[IN]u
+.ti \\n[SN]u
+.it 1 an-trap
+.nr an-no-space-flag 1
+.nr an-break-flag 1
+.ps \\n[PS]
+.ft B
+.ne 2v+1u
+.if \\n[.$] \&\\$*
+..
+.de B
+.it 1 an-trap
+.ft B
+.if \\n[.$] \&\\$*
+..
+.de I
+.it 1 an-trap
+.ft I
+.if \\n[.$] \&\\$*
+..
+.de SM
+.it 1 an-trap
+.ps -1
+.if \\n[.$] \&\\$*
+..
+.de SB
+.it 1 an-trap
+.ps -1
+.ft B
+.if \\n[.$] \&\\$*
+..
+.de TP
+.sp \\n[PD]u
+.if \\n[.$] .nr an-prevailing-indent (n;\\$1)
+.it 1 an-trap
+.if !\\n[an-div?] .di an-div
+.in 0
+.nr an-div? 1
+..
+.de an-trap
+.ft R
+.ps \\n[PS]
+.if \\n[an-break-flag] \{\
+. br
+. nr an-break-flag 0
+.\}
+.if \\n[an-no-space-flag] \{\
+. ns
+. nr an-no-space-flag 0
+.\}
+.if \\n[an-div?] .an-do-tag
+..
+.de an-do-tag
+.nr an-div? 0
+.br
+.di
+.in \\n[an-margin]u+\\n[an-prevailing-indent]u
+.ti -\\n[an-prevailing-indent]u
+.ie \\n[dl]+\\n[an-tag-sep]>\\n[an-prevailing-indent] \{\
+. ne 2v+1u
+. an-div
+. br
+.\}
+.el \{\
+. chop an-div
+. ne 1v+1u
+\\*[an-div]\\h'|\\n[an-prevailing-indent]u'\c
+.\}
+..
+.de LP
+.br
+.sp \\n[PD]u
+.ps \\n[PS]
+.ft R
+.in \\n[an-margin]u
+.nr an-prevailing-indent \\n[IN]
+..
+.als PP LP
+.als P LP
+.de IP
+.ie !\\n[.$] \{\
+. ps \\n[PS]
+. ft R
+. sp \\n[PD]u
+. ne 1v+1u
+. in \\n[an-margin]u+\\n[an-prevailing-indent]u
+.\}
+.el \{\
+. ie \\n[.$]-1 .TP "\\$2"
+. el .TP
+\&\\$1
+.\}
+..
+.de HP
+.ps \\n[PS]
+.ft R
+.sp \\n[PD]u
+.ne 1v+1u
+.if \\n[.$] .nr an-prevailing-indent (n;\\$1)
+.in \\n[an-margin]u+\\n[an-prevailing-indent]u
+.ti \\n[an-margin]u
+..
+.de RI
+.if \\n[.$] \{\
+. ds an-result \&\\$1
+. shift
+. while \\n[.$]>=2 \{\
+. as an-result \,\fI\\$1\fR\/\\$2
+. shift 2
+. \}
+. if \\n[.$] .as an-result \,\fI\\$1\fR
+\\*[an-result]
+.\}
+..
+.de IR
+.if \\n[.$] \{\
+. ds an-result \&\fI\\$1\fR
+. shift
+. while \\n[.$]>=2 \{\
+. as an-result \/\\$1\fI\,\\$2\fR
+. shift 2
+. \}
+. if \\n[.$] .as an-result \/\\$1
+\\*[an-result]
+.\}
+..
+.de IB
+.if \\n[.$] \{\
+. ds an-result \&\fI\\$1
+. shift
+. while \\n[.$]>=2 \{\
+. as an-result \/\\fB\\$1\fI\,\\$2
+. shift 2
+. \}
+. if \\n[.$] .as an-result \/\\fB\\$1
+\\*[an-result]
+. ft R
+.\}
+..
+.de BI
+.if \\n[.$] \{\
+. ds an-result \&\fB\\$1
+. shift
+. while \\n[.$]>=2 \{\
+. as an-result \,\fI\\$1\fB\/\\$2
+. shift 2
+. \}
+. if \\n[.$] .as an-result \,\fI\\$1
+\\*[an-result]
+. ft R
+.\}
+..
+.de RB
+.ds an-result \&
+.while \\n[.$]>=2 \{\
+. as an-result \fR\\$1\fB\\$2
+. shift 2
+.\}
+.if \\n[.$] .as an-result \fR\\$1
+\\*[an-result]
+.ft R
+..
+.de BR
+.ds an-result \&
+.while \\n[.$]>=2 \{\
+. as an-result \fB\\$1\fR\\$2
+. shift 2
+.\}
+.if \\n[.$] .as an-result \fB\\$1
+\\*[an-result]
+.ft R
+..
+.de RS
+.br
+.nr an-saved-margin\\n[an-level] \\n[an-margin]
+.nr an-saved-prevailing-indent\\n[an-level] \\n[an-prevailing-indent]
+.ie \\n[.$] .nr an-margin +(n;\\$1)
+.el .nr an-margin +\\n[an-prevailing-indent]
+.in \\n[an-margin]u
+.nr an-prevailing-indent \\n[IN]
+.nr an-level +1
+..
+.de RE
+.br
+.ie \\n[.$] .nr an-level (;\\$1)<?\\n[an-level]
+.el .nr an-level -1
+.nr an-level 1>?\\n[an-level]
+.nr an-margin \\n[an-saved-margin\\n[an-level]]
+.nr an-prevailing-indent \\n[an-saved-prevailing-indent\\n[an-level]]
+.in \\n[an-margin]u
+..
+.ds S \s[\\n[PS]]
+.ie c\[rg] .ds R \[rg]
+.el .ds R (Reg.)
+.ie c\[tm] .ds Tm \[tm]
+.el .ds Tm (TM)
+.ds lq \(lq
+.ds rq \(rq
+.hy 14
+.\" Load local modifications.
+.mso man.local
+.cp \n(_C
diff --git a/gnu/usr.bin/groff/tmac/tmac.andoc b/gnu/usr.bin/groff/tmac/tmac.andoc
new file mode 100644
index 0000000..e9dcea7
--- /dev/null
+++ b/gnu/usr.bin/groff/tmac/tmac.andoc
@@ -0,0 +1,12 @@
+.\" Load either tmac.an or tmac.doc.
+.if !\n(.g .ab These macros require groff.
+.de Dd
+.rm Dd
+.mso tmac.doc
+\\*(Dd\\
+..
+.de TH
+.rm TH
+.mso tmac.groff_an
+\\*(TH\\
+..
diff --git a/gnu/usr.bin/groff/tmac/tmac.doc b/gnu/usr.bin/groff/tmac/tmac.doc
new file mode 100644
index 0000000..e575df7
--- /dev/null
+++ b/gnu/usr.bin/groff/tmac/tmac.doc
@@ -0,0 +1,3427 @@
+.\" Copyright (c) 1991 The Regents of the University of California.
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)doc 5.8 (Berkeley) 8/5/91
+.\" Modified by jjc@jclark.com as follows: the doc-* files are assumed to be
+.\" installed as mdoc/doc-* rather than tmac.doc-* (the filename
+.\" `tmac.doc-common' would be too long); when using groff, the doc-* files
+.\" are loaded using the `mso' request.
+.\"
+.\" .mdoc-parse - attempt to parse troff request arguments
+.\" %beginstrip%
+.if \n(.g \{\
+.cp 0
+.ftr C CR
+.\}
+.if \n(.g .ig
+.de sO
+.so /usr/share/tmac/\\$1
+..
+.if !\n(.g .ig
+.de sO
+.mso mdoc/\\$1
+..
+.if t \{\
+. sO doc-ditroff
+.\}
+.if n \{\
+. sO doc-nroff
+.\}
+.sO doc-common
+.sO doc-syms
+.\" NS Db macro - start/stop DEBUG MODE
+.\" NS Db register DEBUG MODE
+.\" NS iN register DEBUG MODE (inline if 1, to stderr if 0 (default))
+.nr Db 0
+.de Db
+.ie \\n(.$==0 \{\
+. ie \\n(Db==0 \{\
+.tm DEBUGGING ON
+. nr Db 1
+. \}
+. el \{\
+.tm DEBUGGING OFF
+. nr Db 0
+. \}
+.\}
+.el \{\
+. if "\\$1"on" \{\
+.tm DEBUGGING ON
+. nr Db 1
+. \}
+. if "\\$1"off" \{\
+.tm DEBUGGING OFF
+. nr Db 0
+. \}
+.\}
+..
+.\" NS aV macro - parse argument vector (recursive) (.aV arg ... )
+.\" NS fV macro - parse argument vector (recursive) (.fV)
+.\" NS aC register argument counter (aV/fV)
+.\" NS fV register argument counter (must set to \\n(.$ prior to reuqest) (fV)
+.\" NS A[0-9] argument vector (aV/fV)
+.\" NS C[0-9] reg. arg type(1=macro, 2=arg, 3=punct-suf, 4=punct-pre) (aV/fV)
+.\" NS S[0-9] space vector (sV)
+.\" NS aP register argument pointer (aV)
+.\" NS yU local string used for debugging
+.\" NS iI local register (indent for inline debug mode)
+.\" NS mN name of calling request (set in each user requestable macro)
+.de aV
+.nr aC \\n(aC+1
+.ie "\\$1"|" \{\
+. if "\\*(mN"Op" .ds A\\n(aC \fR\\$1\fP
+. if "\\*(mN"Ar" .ds A\\n(aC \fR\\$1\fP
+. if "\\*(mN"Fl" .ds A\\n(aC \fR\\$1\fP
+. if "\\*(mN"Cm" .ds A\\n(aC \fR\\$1\fP
+. if "\\*(mN"It" .ds A\\n(aC \fR\\$1\fP
+.\}
+.el .ds A\\n(aC \\$1
+.aU \\n(aC
+.nr C\\n(aC \\n(aT
+.s\\n(aT
+.if \\n(Db \{\
+. if \\n(aT==1 .ds yU Executable
+. if \\n(aT==2 .ds yU String
+. if \\n(aT==3 .ds yU Closing Punctuation or suffix
+. if \\n(aT==4 .ds yU Opening Punctuation or prefix
+. if \\n(iN==1 \{\
+. br
+. nr iI \\n(.iu
+. in -\\n(iIu
+. if \\n(aC==1 \{\
+\&\fBDEBUG(argv) MACRO:\fP `.\\*(mN' \fBLine #:\fP \\n(.c
+. \}
+\&\t\fBArgc:\fP \\n(aC \fBArgv:\fP `\\*(A\\n(aC' \fBLength:\fP \\n(sW
+\&\t\fBSpace:\fP `\\*(S\\n(aC' \fBClass:\fP \\*(yU
+. \}
+. if \\n(iN==0 \{\
+. if \\n(aC==1 \{\
+. tm DEBUG(argv) MACRO: `.\\*(mN' Line #: \\n(.c
+. \}
+. tm \tArgc: \\n(aC Argv: `\\*(A\\n(aC' Length: \\n(sW
+. tm \tSpace: `\\*(S\\n(aC' Class: \\*(yU
+. \}
+.\}
+.ie \\n(.$==1 \{\
+. nr aP 0
+. ie \\n(dZ==1 \{\
+. if \\n(oM>1 .as b1 \\*(S0
+. \}
+. el \{\
+. if \\n(oM>0 \{\
+. if \\n(fC==0 .as b1 \\*(S0
+. \}
+. \}
+. ds S0 \\*(S\\n(aC
+. if \\n(Db \{\
+. if \\n(iN==1 \{\
+\&MACRO REQUEST: \t.\\*(mN \\*(A1 \\*(A2 \\*(A3 \\*(A4 \\*(A5 \\*(A6 \\*(A7 \\*(A8 \\*(A9
+. br
+. in \\n(iIu
+. \}
+. if \\n(iN==0 \{\
+.tm \tMACRO REQUEST: .\\*(mN \\*(A1 \\*(A2 \\*(A3 \\*(A4 \\*(A5 \\*(A6 \\*(A7 \\*(A8 \\*(A9
+. \}
+. \}
+.\}
+.el .aV \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
+..
+.de fV
+.nr aC \\n(aC+1
+.if "\\*(A\\n(aC"|" \{\
+. if "\\*(mN"Op" .ds A\\n(aC \fR\\*(A\\n(aC\fP
+. if "\\*(mN"Ar" .ds A\\n(aC \fR\\*(A\\n(aC\fP
+. if "\\*(mN"Fl" .ds A\\n(aC \fR\&\\*(A\\n(aC\fP
+. if "\\*(mN"Cm" .ds A\\n(aC \fR\\*(A\\n(aC\fP
+. if "\\*(mN"It" .ds A\\n(aC \fR\\*(A\\n(aC\fP
+.\}
+.aU \\n(aC
+.nr C\\n(aC \\n(aT
+.s\\n(aT
+.if \\n(Db \{\
+. if \\n(aT==1 .ds yU Executable
+. if \\n(aT==2 .ds yU String
+. if \\n(aT==3 .ds yU Closing Punctuation or suffix
+. if \\n(aT==4 .ds yU Opening Punctuation or prefix
+. if \\n(iN==1 \{\
+. br
+. nr iI \\n(.iu
+. in -\\n(iIu
+. if \\n(aC==1 \{\
+\&\fBDEBUG(fargv) MACRO:\fP `.\\*(mN' \fBLine #:\fP \\n(.c
+. \}
+\&\t\fBArgc:\fP \\n(aC \fBArgv:\fP `\\*(A\\n(aC' \fBLength:\fP \\n(sW
+\&\t\fBSpace:\fP `\\*(S\\n(aC' \fBClass:\fP \\*(yU
+. \}
+. if \\n(iN==0 \{\
+. if \\n(aC==1 \{\
+. tm DEBUG(fargv) MACRO: `.\\*(mN' Line #: \\n(.c
+. \}
+. tm \tArgc: \\n(aC Argv: `\\*(A\\n(aC' Length: \\n(sW
+. tm \tSpace: `\\*(S\\n(aC' Class: \\*(yU
+. \}
+.\}
+.ie \\n(fV==1 \{\
+. nr aP 0
+. ie \\n(dZ==1 \{\
+. if \\n(oM>1 .as b1 \\*(S0
+. \}
+. el \{\
+. if \\n(oM>0 \{\
+. if \\n(fC==0 .as b1 \\*(S0
+. \}
+. \}
+. ds S0 \\*(S\\n(aC
+. nr fV 0
+. if \\n(Db \{\
+. ie \\n(iN \{\
+\&\tMACRO REQUEST: .\\*(mN \\*(A1 \\*(A2 \\*(A3 \\*(A4 \\*(A5 \\*(A6 \\*(A7 \\*(A8 \\*(A9
+. br
+. in \\n(iIu
+. \}
+. el \{\
+.tm \tMACRO REQUEST: .\\*(mN \\*(A1 \\*(A2 \\*(A3 \\*(A4 \\*(A5 \\*(A6 \\*(A7 \\*(A8 \\*(A9
+. \}
+. \}
+.\}
+.el \{\
+. nr fV \\n(fV-1
+. fV
+.\}
+..
+.\" NS aX macro - stuff saved strings into `b1' (used by -diag list)
+.de aX
+.nr aP \\n(aP+1
+.as b1 \&\\*(A\\n(aP
+.ie \\n(fV==1 \{\
+. nr aP 0
+. nr fV 0
+.\}
+.el \{\
+. as b1 \&\\*(sV
+. nr fV \\n(fV-1
+. aX
+.\}
+..
+.\" NS aI macro - append arg to arg vector: .aI [arg] [type] (used by .En only)
+.de aI
+.ie \\n(aC<9 \{\
+. nr aC \\n(aC+1
+. ds A\\n(aC \\$1
+. nr C\\n(aC \\$2
+. s\\$2
+. ds xV S\\n(aC
+.\}
+.el \{\
+. tm Usage: Too many arguments (maximum of 8 accepted) (#\\n(.c)
+. tm \\*(A1 \\*(A2 \\*(A3 \\*(A4 \\*(A5 \\*(A6 \\*(A7 \\*(A8 \\*(A9
+.\}
+..
+.\"
+.\" NS aZ macro - print buffer (pB) and clean up arg vectors (aY)
+.de aZ
+.pB
+.aY
+..
+.\" NS aY macro - clean up arg vector
+.de aY
+.rm C0 C1 C2 C3 C4 C5 C6 C7 C8 C9
+.rm A0 A1 A2 A3 A4 A5 A6 A7 A8 A9
+.rm S1 S2 S3 S4 S5 S6 S7 S8 S9
+.nr aC 0
+.nr aP 0
+..
+.\" NS pB macro - test for end of vector (eol) (print b1 buffer or divert)
+.de pB
+.ie \\n(dZ==1 \{\
+. if \\n(oM==1 \{\&\\*(b1
+. rm S0
+. ds b1
+. \}
+. if \\n(oM==0 \{\
+. x2
+. \}
+.\}
+.el \{\
+. ie \\n(oM==0 \{\&\\*(b1
+. rm S0
+. ds b1
+. \}
+. el \{\
+. if ((\\n(sM==1)&(\\n(tP==0)) \{\
+. x1
+. \}
+. \}
+.\}
+.hy
+..
+.\" NS x1 macro - save buffer and divert if tP flag set
+.\" NS eB diversion string
+.\" NS b2 string save of buffer
+.\" NS lK register count of lines read from input file
+.de x1
+.nr dZ \\n(dZ+1
+.ds b2 \\*(b1
+.ds b1
+.nr lK \\n(.c
+.ev 2
+.fi
+.di eB
+..
+.\"
+.\" NS x2 macro - end diversion and print
+.\" NS b0 string local temporary
+.de x2
+.br
+.di
+.ev
+.ie (\\n(.c-\\n(lK>1) \{\
+. ds b0 \&\\*(eB\\
+. ds b1 \\*(b2\\*(b0\\*(b1
+.\}
+.el .ds b1 \\*(b2\\*(b1
+\&\\*(b1
+.rm eB b2 b0 b1
+.nr dZ \\n(dZ-1
+..
+.\" NS Fl macro - flags (appends - and prints flags)
+.\" NS cF register save current font
+.\" NS cZ register save current font size
+.de Fl
+.as b1 \&\\*(fL
+.if \\n(aC==0 \{\
+. ie \\n(.$==0 \{\
+. as b1 \&\|\-\|\fP\s0
+. pB
+. \}
+. el \{\
+. ds mN Fl
+. aV \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
+. \}
+.\}
+.if \\n(aC>0 \{\
+. ie (\\n(aC-\\n(aP)==0 \{\
+. as b1 \&\|\-\fP\s0
+. aZ
+. \}
+. el \{\
+. nr aP \\n(aP+1
+. ie \\n(C\\n(aP==1 \{\
+. as b1 \&\|\-\fP\s0
+. \\*(A\\n(aP
+. \}
+. el \{\
+. nr cF \\n(.f
+. nr cZ \\n(.s
+. if \\n(C\\n(aP==3 \{\
+. as b1 \&\|\-\|
+. \}
+. fR
+. \}
+. \}
+.\}
+..
+.\"
+.\" NS fR macro - Fl flag recursion routine (special handling)
+.\" NS jM local register
+.\" NS jN local register
+.\"
+.de fR
+.hy 0
+.nr jM \\n(C\\n(aP
+.ie \\n(jM==1 \{\
+. as b1 \&\fP\s0
+. \\*(A\\n(aP
+.\}
+.el \{\
+. nr jN \\n(aP
+. ie \\n(jM==2 \{\
+. ie !"\\*(A\\n(aP"\\*(Ba" \{\
+. ie !"\\*(A\\n(aP"\fR|\fP" \{\
+. ie "\\*(A\\n(aP"-" .as b1 \&\|\-\^\-\|
+. el .as b1 \&\|\-\\*(A\\n(aP
+. \}
+. el .as b1 \&\\*(A\\n(aP
+. \}
+. el .as b1 \&\\*(A\\n(aP
+. \}
+. el .as b1 \&\f\\n(cF\s\\n(cZ\\*(A\\n(aP\fP\s0
+. ie \\n(aC==\\n(aP \{\
+. if \\n(jM==4 .as b1 \&\|\-
+. as b1 \&\fP\s0
+. aZ
+. \}
+. el \{\
+. nr aP \\n(aP+1
+. ie ((\\n(C\\n(aP==3)&(\\n(C\\n(jN==4)) .as b1 \&\|\-
+. el .as b1 \&\\*(S\\n(jN
+. fR \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
+. \}
+.\}
+.rr jM jN
+..
+.\"
+.\" NS nR macro - general name recursion routine
+.\" NS jM local register
+.\" NS jN local register
+.de nR
+.hy 0
+.nr jM \\n(C\\n(aP
+.ie \\n(jM==1 \{\
+. as b1 \&\f\\n(cF\s\\n(cZ
+. \\*(A\\n(aP
+.\}
+.el \{\
+. nr jN \\n(aP
+. ie \\n(jM==2 .as b1 \&\\*(A\\n(aP
+. el .as b1 \&\f\\n(cF\s\\n(cZ\\*(A\\n(aP\fP\s0
+. ie \\n(aC==\\n(aP \{\
+. as b1 \&\f\\n(cF\s\\n(cZ
+. aZ
+. \}
+. el \{\
+. nr aP \\n(aP+1
+. as b1 \&\\*(S\\n(jN
+. nR
+. \}
+.\}
+.rr jM jN
+..
+.\" NS Ar macro - command line `argument' macro
+.\"
+.de Ar
+.as b1 \\*(aR
+.if \\n(aC==0 \{\
+. ie \\n(.$==0 \{\
+. as b1 file\ ...\fP\s0
+. pB
+. \}
+. el \{\
+. ds mN Ar
+. aV \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
+. \}
+.\}
+.if \\n(aC>0 \{\
+. ie (\\n(aC-\\n(aP)==0 \{\
+. as b1 \&file\ ...\fP\s0
+. aZ
+. \}
+. el \{\
+. nr aP \\n(aP+1
+. ie \\n(C\\n(aP==1 \{\
+. as b1 \&file\ ...\fP\s0
+. \\*(A\\n(aP
+. \}
+. el \{\
+. nr cF \\n(.f
+. nr cZ \\n(.s
+. if \\n(C\\n(aP==3 \{\
+. as b1 \&file\ ...
+. \}
+. nR
+. \}
+. \}
+.\}
+..
+.\" NS Ad macro - Addresses
+.de Ad
+.if \\n(aC==0 \{\
+. ie \\n(.$==0 .tm Usage: .Ad address ... \\*(Pu (#\\n(.c)
+. el \{\
+. ds mN Ad
+. aV \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
+. \}
+.\}
+.if \\n(aC>\\n(aP \{\
+. as b1 \\*(aD
+. nr aP \\n(aP+1
+. nr cF \\n(.f
+. nr cZ \\n(.s
+. nR
+.\}
+..
+.\" NS Cd macro - Config declaration (for section 4 SYNOPSIS) (not callable)
+.\" needs work - not very translatable
+.de Cd
+.if \\n(aC==0 \{\
+. ie \\n(.$==0 .tm Usage: .Cd Configuration file declaration (#\\n(.c)
+. el \{\
+. ds mN Cd
+. ds A1 \\$1
+. ds A2 \\$2
+. ds A3 \\$3
+. ds A4 \\$4
+. ds A5 \\$5
+. ds A6 \\$6
+. ds A7 \\$7
+. ds A8 \\$8
+. ds A9 \\$9
+. nr fV \\n(.$
+. fV
+. \}
+.\}
+.br
+.if \\n(aC>\\n(aP \{\
+. as b1 \\*(nM
+. nr aP \\n(aP+1
+. nr cF \\n(.f
+. nr cZ \\n(.s
+. ie \\n(nS \{\
+. if "\\*(mN"Cd" \{\
+. rs
+. ie \\n(nS>1 .br
+. el \{\
+. if \\n(iS==0 .nr iS \\n(Dsu
+. \}
+. in +\\n(iSu
+. ti -\\n(iSu
+. nr nS \\n(nS+1
+. \}
+. nR
+. in -\\n(iSu
+. \}
+. el .nR
+.\}
+..
+.\" NS Cm macro - Interactive command modifier (flag)
+.de Cm
+.if \\n(aC==0 \{\
+. ie \\n(.$==0 .tm Usage: .Cm Interactive command modifier ... \\*(Pu (#\\n(.c)
+. el \{\
+. ds mN Cm
+. ds A1 \\$1
+. ds A2 \\$2
+. ds A3 \\$3
+. ds A4 \\$4
+. ds A5 \\$5
+. ds A6 \\$6
+. ds A7 \\$7
+. ds A8 \\$8
+. ds A9 \\$9
+. nr fV \\n(.$
+. fV
+. \}
+.\}
+.if \\n(aC>\\n(aP \{\
+. as b1 \\*(cM
+. nr aP \\n(aP+1
+. nr cF \\n(.f
+. nr cZ \\n(.s
+. nR
+.\}
+..
+.\" NS Dv macro - define variable
+.de Dv
+.if \\n(aC==0 \{\
+. ie \\n(.$==0 .tm Usage: .Dv define_variable ... \\*(Pu (#\\n(.c)
+. el \{\
+. ds mN Dv
+. aV \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
+. \}
+.\}
+.if \\n(aC>\\n(aP \{\
+. as b1 \\*(eR
+. nr aP \\n(aP+1
+. nr cF \\n(.f
+. nr cZ \\n(.s
+. nR
+.\}
+..
+.\" NS Em macro - Emphasis
+.de Em
+.if \\n(aC==0 \{\
+. ie \\n(.$==0 \{\
+. tm Usage: .Em text ... \\*(Pu (#\\n(.c)
+. \}
+. el \{\
+. ds mN Em
+. ds A1 \\$1
+. ds A2 \\$2
+. ds A3 \\$3
+. ds A4 \\$4
+. ds A5 \\$5
+. ds A6 \\$6
+. ds A7 \\$7
+. ds A8 \\$8
+. ds A9 \\$9
+. nr fV \\n(.$
+. fV
+. \}
+.\}
+.if \\n(aC>\\n(aP \{\
+. as b1 \\*(eM
+. nr aP \\n(aP+1
+. nr cF \\n(.f
+. nr cZ \\n(.s
+. nR
+.\}
+..
+.\" NS Er macro - Errnotype
+.de Er
+.if \\n(aC==0 \{\
+. ie \\n(.$==0 .tm Usage: .Er ERRNOTYPE ... \\*(Pu (#\\n(.c)
+. el \{\
+. ds mN Er
+. aV \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
+. \}
+.\}
+.if \\n(aC>\\n(aP \{\
+. as b1 \\*(eR
+. nr aP \\n(aP+1
+. nr cF \\n(.f
+. nr cZ \\n(.s
+. nR
+.\}
+..
+.\" NS Ev macro - Environment variable
+.de Ev
+.if \\n(aC==0 \{\
+. ie \\n(.$==0 .tm Usage: .Ev ENVIRONMENT_VARIABLE ... \\*(Pu (#\\n(.c)
+. el \{\
+. ds mN Ev
+. aV \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
+. \}
+.\}
+.if \\n(aC>\\n(aP \{\
+. as b1 \\*(eV
+. nr aP \\n(aP+1
+. nr cF \\n(.f
+. nr cZ \\n(.s
+. nR
+.\}
+..
+.\" NS Fd macro - function declaration - not callable (& no err check)
+.\" NS fD register subroutine test (in synopsis only)
+.\" NS fY register subroutine count (in synopsis only) (fortran only)
+.\" NS fZ register also subroutine count (in synopsis only)
+.de Fd
+.ds mN Fd
+.if \\n(nS>0 \{\
+.\" if a variable type was the last thing given, want vertical space
+. if \\n(fX>0 \{\
+. Pp
+. nr fX 0
+. \}
+.\" if a subroutine was the last thing given, want vertical space
+. if \\n(fZ>0 \{\
+. ie \\n(fD==0 \{\
+. Pp
+. rs
+. \}
+. el .br
+. \}
+. nr fD \\n(fD+1
+.\}
+.nr cF \\n(.f
+.nr cZ \\n(.s
+\&\\*(fD\\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
+.br
+.ft \\n(cF
+.fs \\n(cZ
+..
+.\" NS Fr macro - function return value - not callable (at the moment)
+.de Fr
+.if \\n(aC==0 \{\
+. ie \\n(.$==0 .tm Usage: .Fr Function_return_value... \\*(Pu (#\\n(.c)
+. el \{\
+. ds mN Fr
+. aV \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
+. \}
+.\}
+.if \\n(aC>\\n(aP \{\
+. as b1 \\*(aR
+. nr aP \\n(aP+1
+. nr cF \\n(.f
+. nr cZ \\n(.s
+. nR
+.\}
+..
+.\" NS Ic macro - Interactive command
+.de Ic
+.if \\n(aC==0 \{\
+. ie \\n(.$==0 .tm Usage: .Ic Interactive command ... \\*(Pu (#\\n(.c)
+. el \{\
+. ds mN Ic
+. aV \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
+. \}
+.\}
+.if \\n(aC>\\n(aP \{\
+. as b1 \\*(iC
+. nr aP \\n(aP+1
+. nr cF \\n(.f
+. nr cZ \\n(.s
+. nR
+.\}
+..
+.\" NS Li macro - literals
+.de Li
+.if \\n(aC==0 \{\
+. ie \\n(.$==0 .tm Usage .Li argument ... \\*(Pu (#\\n(.c)
+. el \{\
+. ds mN Li
+. ds A1 \\$1
+. ds A2 \\$2
+. ds A3 \\$3
+. ds A4 \\$4
+. ds A5 \\$5
+. ds A6 \\$6
+. ds A7 \\$7
+. ds A8 \\$8
+. ds A9 \\$9
+. nr fV \\n(.$
+. fV
+. \}
+.\}
+.if \\n(aC>\\n(aP \{\
+. as b1 \\*(lI
+. nr aP \\n(aP+1
+. nr cF \\n(.f
+. nr cZ \\n(.s
+. nR
+.\}
+..
+.\" NS Or macro - Pipe symbol (OR)
+.de Or
+.if \\n(aC==0 \{\
+. ie \\n(.$==0 .tm Usage: .Or ... \\*(Pu (#\\n(.c)
+. el \{\
+. ds mN Or
+. aV \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
+. \}
+.\}
+.if \\n(aC>\\n(aP \{\
+. as b1 \\*(iC
+. nr aP \\n(aP+1
+. nr cF \\n(.f
+. nr cZ \\n(.s
+. nR
+.\}
+..
+.\" NS Ms macro - Math symbol
+.de Ms
+.if \\n(aC==0 \{\
+. ie \\n(.$==0 .tm Usage: .Ms Math symbol ... \\*(Pu (#\\n(.c)
+. el \{\
+. ds mN Ms
+. aV \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
+. \}
+.\}
+.if \\n(aC>\\n(aP \{\
+. as b1 \\*(sY
+. nr aP \\n(aP+1
+. nr cF \\n(.f
+. nr cZ \\n(.s
+. nR
+.\}
+..
+.\" NS Nm macro - Name of command or page topic
+.\" NS n1 string - save first invocation of .Nm
+.\" NS iS register - indent second command line in a synopsis
+.de Nm
+.if \\n(aC==0 \{\
+. ie \\n(.$==0 \{\
+. ie "\\*(n1"" .tm Usage: .Nm Name(s) ... \\*(Pu (#\\n(.c)
+. el \&\\*(nM\\*(n1\fP\s0
+. \}
+. el \{\
+. ds mN Nm
+. ds A1 \\$1
+. ds A2 \\$2
+. ds A3 \\$3
+. ds A4 \\$4
+. ds A5 \\$5
+. ds A6 \\$6
+. ds A7 \\$7
+. ds A8 \\$8
+. ds A9 \\$9
+. nr fV \\n(.$
+. fV
+. \}
+.\}
+.if \\n(aC>0 \{\
+. ie \\n(aC==\\n(aP \{\
+. as b1 \&\\*(nM\\*(n1\fP\s0
+. aZ
+. \}
+. el \{\
+. as b1 \\*(nM
+. nr aP \\n(aP+1
+. ie \\n(C\\n(aP==1 \{\
+. as b1 \&\\*(n1\fP\s0
+. \\*(A\\n(aP
+. \}
+. el \{\
+. nr cF \\n(.f
+. nr cZ \\n(.s
+. if \\n(nS \{\
+. if "\\*(mN"Nm" \{\
+. rs
+. in -\\n(iSu
+. ie \\n(nS>1 .br
+. el \{\
+. if \\n(iS==0 \{\
+. sw \\$1
+. nr iS ((\\n(sWu+1)*\\n(fW)u
+. \}
+. \}
+. in +\\n(iSu
+. ti -\\n(iSu
+. nr nS \\n(nS+1
+. \}
+. \}
+. if "\\*(n1"" .ds n1 \\*(A\\n(aP
+. nR
+. \}
+. \}
+.\}
+..
+.\" NS Pa macro - Pathname
+.de Pa
+.if \\n(aC==0 \{\
+. ie \\n(.$==0 \&\\*(pA~\fP\s0
+. el \{\
+. ds mN Pa
+. aV \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
+. \}
+.\}
+.if \\n(aC>\\n(aP \{\
+. as b1 \\*(pA
+. nr aP \\n(aP+1
+. nr cF \\n(.f
+. nr cZ \\n(.s
+. nR
+.\}
+..
+.\" NS Sy macro - Symbolics
+.de Sy
+.if \\n(aC==0 \{\
+. ie \\n(.$==0 .tm Usage: .Sy symbolic_text ... \\*(Pu (#\\n(.c)
+. el \{\
+. ds mN Sy
+. ds A1 \\$1
+. ds A2 \\$2
+. ds A3 \\$3
+. ds A4 \\$4
+. ds A5 \\$5
+. ds A6 \\$6
+. ds A7 \\$7
+. ds A8 \\$8
+. ds A9 \\$9
+. nr fV \\n(.$
+. fV
+. \}
+.\}
+.if \\n(aC>\\n(aP \{\
+. as b1 \\*(sY
+. nr aP \\n(aP+1
+. nr cF \\n(.f
+. nr cZ \\n(.s
+. nR
+.\}
+..
+.\" NS Tn macro - Trade Name Macro
+.de Tn
+.if \\n(aC==0 \{\
+. ie \\n(.$==0 .tm Usage: .Tn Trade_name(s) ... \\*(Pu (#\\n(.c)
+. el \{\
+. ds mN Tn
+. aV \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
+. \}
+.\}
+.if \\n(aC>\\n(aP \{\
+. as b1 \\*(tN\\*(tF
+. nr aP \\n(aP+1
+. nr cF \\n(.f
+. nr cZ \\n(.s
+. nR
+.\}
+..
+.\" NS nN macro - Trade Name Macro for inside of reference
+.de nN
+.if \\n(aC==0 \{\
+. ie \\n(.$==0 .tm Usage: .Tn Trade_name(s) ... \\*(Pu (#\\n(.c)
+. el \{\
+. ds mN Tn
+. aV \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
+. \}
+.\}
+.if \\n(aC>\\n(aP \{\
+. as b1 \\*(tN
+. nr aP \\n(aP+1
+. nr cF \\n(.f
+. nr cZ \\n(.s
+. rR
+.\}
+..
+.\" NS Va macro - variable name macro
+.de Va
+.if \\n(aC==0 \{\
+. ie \\n(.$==0 .tm Usage: .Va variable_name(s) ... \\*(Pu (#\\n(.c)
+. el \{\
+. ds mN Va
+. aV \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
+. \}
+.\}
+.if \\n(aC>\\n(aP \{\
+. as b1 \\*(vA
+. nr aP \\n(aP+1
+. nr cF \\n(.f
+. nr cZ \\n(.s
+. nR
+.\}
+..
+.\"
+.\" NS No macro - Normal text macro (default text style if mess up)
+.de No
+.as b1 \\*(nO
+.if \\n(aC==0 \{\
+. ie \\n(.$==0 .tm Usage: .No must be called with arguments (#\\n(.c)
+. el \{\
+. ds mN No
+. aV \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
+. \}
+.\}
+.if \\n(aC>\\n(aP \{\
+. nr aP \\n(aP+1
+. ie \\n(C\\n(aP==1 \{\
+. \\*(A\\n(aP
+. \}
+. el \{\
+. nr cF \\n(.f
+. nr cZ \\n(.s
+. nR
+. \}
+.\}
+..
+.\"------------------------------------------------------------------------
+.\" NS Op macro - Option Expression
+.de Op
+.if \\n(aC==0 \{\
+. ds mN Op
+.\}
+.\" .ds qL \&\\*(lO
+.\" .ds qR \&\\*(rO
+.ds qL \&\\*(lB
+.ds qR \&\\*(rB
+.En \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8
+..
+.\" NS Aq macro - Enclose string in angle brackets
+.de Aq
+.if \\n(aC==0 .ds mN Aq
+.ds qL \&<
+.ds qR \&>
+.En \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
+..
+.\" NS Bq macro - Enclose string in square brackets
+.de Bq
+.if \\n(aC==0 .ds mN Bq
+.ds qL \&\\*(lB
+.ds qR \&\\*(rB
+.En \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
+..
+.\" NS Dq macro - Enclose string in double quotes
+.de Dq
+.if \\n(aC==0 .ds mN Dq
+.ds qL \&\\*(Lq
+.ds qR \&\\*(Rq
+.En \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
+..
+.\" NS Eq macro - Enclose string in double quotes
+.de Eq
+.if \\n(aC==0 .ds mN Eq
+.ds qL \\$1
+.ds qR \\$2
+.En \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
+..
+.\" NS Pq macro - Enclose string in parenthesis
+.de Pq
+.if \\n(aC==0 .ds mN Pq
+.ds qL \&\\*(lP
+.ds qR \&\\*(rP
+.En \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
+..
+.\" NS Ql macro - Quoted literal is in file mdoc-[dit|n|g]roff (too large
+.\" an if-else to carry along recursively for `if n ...')
+.\"
+.\" NS Sq macro - Enclose string in single quotes
+.de Qq
+.if \\n(aC==0 .ds mN Qq
+.ds qL \&\\*q
+.ds qR \&\\*q
+.En \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
+..
+.\" NS Sq macro - Enclose string in single quotes
+.de Sq
+.if \\n(aC==0 .ds mN Sq
+.ds qL \&\\*(sL
+.ds qR \&\\*(sR
+.En \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
+..
+.\"
+.\" NS Es macro - Set up strings for .En call
+.de Es
+.if \\n(aC==0 \{\
+. ie \\n(.$>2 .aV \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
+. el \{\
+. ds qL \\$1
+. ds qR \\$2
+. \}
+.\}
+.if \\n(aC>\\n(aP \{\
+. nr aP \\n(aP+1
+. ds qL \\*(A\\n(aP
+. nr aP \\n(aP+1
+. ds qR \\*(A\\n(aP
+. ie \\n(aC>\\n(aP .c\\n(C\\n(aP
+. el .aZ
+.\}
+..
+.\" .tm En beg arg(A[\\n(aP])==\\*(A\\n(aP;
+.\" .tm En oM==\\n(oM; dZ==\\n(dZ; Xt==\\n(Xt; aC==\\n(aC
+.\" NS En macro - Enclose string with given args (eg [ and ] etc)
+.\" NS qL string variable set by calling macro
+.\" NS qR string variable set by calling macro
+.\" NS aJ register (for vR)
+.de En
+.ie \\n(aC==0 \{\
+. ie \\n(.$==0 \{\
+. as b1 \&\\*(qL\\*(qR
+. pB
+. \}
+. el \{\
+.\". as mN (En)
+. aV \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
+. as b1 \&\\*(qL
+. \}
+.\}
+.el \{\
+. as b1 \&\\*(qL
+.\}
+.if \\n(aC>0 \{\
+. ie (\\n(aC-\\n(aP)==0 \{\
+. as b1 \&\\*(qR
+. aZ
+. \}
+. el \{\
+. ie \\n(C\\n(aC==3 \{\
+. nr aJ \\n(aC-1
+. vR
+. nr aJ \\n(aJ+1
+. ds A\\n(aJ \&\\*(qR\\*(A\\n(aJ
+. nr aJ 0
+. \}
+. el .aI \&\\*(qR 3
+. nr aP \\n(aP+1
+. if \\n(C\\n(aP==1 .\\*(A\\n(aP
+. if \\n(C\\n(aP>1 \{\
+. nr aP \\n(aP-1
+. No
+. \}
+. \}
+.\}
+..
+.\" NS vR macro - vector routine (for En, trace backwards past trail punct)
+.de vR
+.if \\n(C\\n(aJ==3 \{\
+. nr aJ \\n(aJ-1
+. vR
+.\}
+..
+.\"------------------------------------------------------------------------
+.\" NS Ao macro - Angle open
+.de Ao
+.if \\n(aC==0 .ds mN Ao
+.ds qL \&<
+.eO \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
+..
+.\" NS Ac macro - Angle close
+.de Ac
+.if \\n(aC==0 .ds mN Ac
+.ds qR \&>
+.eC \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
+..
+.\" NS Bo macro - Bracket open
+.de Bo
+.if \\n(aC==0 .ds mN Bo
+.ds qL \&[
+.eO \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
+..
+.\" NS Bc macro - Bracket close
+.de Bc
+.if \\n(aC==0 .ds mN Bc
+.ds qR \&]
+.eC \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
+..
+.\" NS Do macro - Double Quote open
+.de Do
+.if \\n(aC==0 .ds mN Do
+.ds qL \&\\*(Lq
+.eO \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
+..
+.\" NS Dc macro - Double Quote close
+.de Dc
+.if \\n(aC==0 .ds mN Dc
+.ds qR \&\\*(Rq
+.eC \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
+..
+.\" NS Eo macro - Enclose open
+.de Eo
+.if \\n(aC==0 .ds mN Eo
+.ds qL \\$1
+.eO \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
+..
+.\" NS Ec macro - Enclose close
+.de Ec
+.if \\n(aC==0 .ds mN Ec
+.ds qR \\$1
+.eC \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
+..
+.\" NS Oo macro - Option open
+.de Oo
+.if \\n(aC==0 .ds mN Oo
+.ds qL \&[
+.eO \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
+..
+.\" NS Oc macro - Option close
+.de Oc
+.if \\n(aC==0 .ds mN Oc
+.ds qR \&]
+.eC \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
+..
+.\" NS Po macro - Parenthesis open
+.de Po
+.if \\n(aC==0 .ds mN Po
+.ds qL \&(
+.eO \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
+..
+.\" NS Pc macro - Parenthesis close
+.de Pc
+.if \\n(aC==0 .ds mN Pc
+.ds qR \&)
+.eC \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
+..
+.\" NS Qo macro - Straight Double Quote open
+.de Qo
+.if \\n(aC==0 .ds mN Qo
+.ds qL \&\\*q
+.eO \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
+..
+.\" NS Qc macro - Straight Double Quote close
+.de Qc
+.if \\n(aC==0 .ds mN Qc
+.ds qR \&\\*q
+.eC \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
+..
+.\" NS So macro - Single Quote open
+.de So
+.if \\n(aC==0 .ds mN So
+.ds qL \&\\*(sL
+.eO \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
+..
+.\" NS Sc macro - Single Quote close
+.de Sc
+.if \\n(aC==0 .ds mN Sc
+.ds qR \&\\*(sR
+.eC \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
+..
+.\" NS Xo macro - Extend open (continue)
+.de Xo
+.if \\n(aC==0 .ds mN Xo
+.\" .nr mN 1
+.ds qL
+.eO \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
+..
+.\" NS Xe macro - Extend close (end)
+.de Xc
+.\" .nr mN 0
+.if \\n(aC==0 .ds mN Xc
+.ds qR
+.eC \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
+..
+.\" NS eO macro - enclose string open
+.\" NS oM register (extension possible)
+.de eO
+.nr oM \\n(oM+1
+.\" .tm eO last arg==A[\\n(aC]==\\*(A\\n(aC; aP==\\n(aP; oM==\\n(oM; dZ==\\n(dZ;
+.ie \\n(aC==0 \{\
+. ie \\n(.$>0 \{\
+. aV \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
+. as b1 \\*(qL
+. \}
+. el \{\
+. as b1 \\*(qL
+. if (\\n(dZ==0)&(\\n(sM==1) \{\
+. nr dZ \\n(dZ+1
+. ds b2 \\*(b1
+. ds b1
+. nr lK \\n(.c
+. ev 2
+. fi
+. di eB
+. \}
+. \}
+.\}
+.el \{\
+. as b1 \\*(qL
+.\}
+.ie \\n(aC>0 \{\
+. if \\n(aC>\\n(aP \{\
+. nr aP \\n(aP+1
+. ie \\n(C\\n(aP==1 .\\*(A\\n(aP
+. el \{\
+. nr aP \\n(aP-1
+. No
+. \}
+. \}
+. if \\n(aC==\\n(aP \{\
+. if \\n(tP==1 \{\
+.\" .tm SETTING Xt!!!
+. nr Xt 1
+. \}
+.\".\" . ds S0
+.\"CHANGED ds S0 \\*(iV
+. aY
+. \}
+.\}
+.el \{\
+. if \\n(oM>1 .as b1 \\*(sV
+.\}
+..
+.\"
+.\" NS eC macro - enclose string close
+.\" NS aa local register
+.de eC
+.nr oM \\n(oM-1
+.\" tm eC last arg==A[\\n(aC]==\\*(A\\n(aC; aP==\\n(aP; oM==\\n(oM; dZ==\\n(dZ;
+.as b1 \\*(qR
+.if \\n(aC==0 \{\
+. ie \\n(.$>0 \{\
+. aV \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
+. \}
+. el \{\
+. ie "\\*(xB"" \{\
+. pB
+. \}
+. el \{\
+. pB
+.\\*(L\\n(lC
+. nr Xt 0
+. ds xB
+. \}
+. \}
+.\}
+.if \\n(aC>0 \{\
+. ie \\n(aC==\\n(aP \{\
+. ie \\n(oM==0 \{\
+. aZ
+. \}
+. el .aY
+. \}
+. el \{\
+. nr aa \\n(aP+1
+. if \\n(C\\n(aa==2 .as b1 \\*(S\\n(aC
+.\" tm CURRENT arg (aP==\\*(A\\n(aP and ap+1==\\*(A\\n(aa) tP==\\n(tP Xt==\\n(Xt
+. rr aa
+. if \\n(tP>0 \{\
+.\" tm UNSETTING Xt==\\n(Xt!!!!
+. if \\n(Xt>0 .nr Xt \\n(Xt-1
+.\" tm NOW Xt==\\n(Xt!!!!
+. \}
+. No
+. \}
+.\}
+..
+.\"------------------------------------------------------------------------
+.\" NS Pf macro - Prefix (calls .pF)
+.de Pf
+.if \\n(aC==0 .ds mN Pf
+.ds qL \&\\$1
+.pF \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
+..
+.\" NS pF macro - Prefix (for prefixing open quotes, brackets etc)
+.de pF
+.ie \\n(aC==0 \{\
+. as b1 \&\\*(qL
+. ie \\n(.$<2 \{\
+. tm Warning: Missing arguments - prefix .Pf)
+. pB
+. \}
+. el .aV \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
+.\}
+.el \{\
+. ie (\\n(aC-\\n(aP)>1 \{\
+. nr aP \\n(aP+1
+. as b1 \&\\*(A\\n(aP
+. \}
+. el .tm Warning: .Pf: trailing prefix (#\\n(.c)
+.\}
+.if \\n(aC>0 \{\
+. ie (\\n(aC-\\n(aP)==0 .aZ
+. el \{\
+. nr aP \\n(aP+1
+. c\\n(C\\n(aP
+. \}
+.\}
+..
+.\" NS Ns macro - remove space (space remove done by .aV or .fV)
+.de Ns
+.if \\n(aC==0 \{\
+. ds mN Ns
+. ie \\n(.$>0 .aV \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
+. el .tm Usage: .Ns must be called with arguments (#\\n(.c)
+.\}
+.No
+..
+.de Ap
+.if \\n(aC==0 \{\
+. ds mN Ap
+. tm Usage: Ap "cannot be first request on a line (no .Ap)" (#\\n(.c)
+.\}
+.as b1 \&'
+.No
+..
+.\" NS Hv macro - Hard (unpaddable) Space vector
+.\" NS iV string inter-vector space
+.\" NS sV string inter-argument space
+.de Hv
+.ds iV \\*(sV
+.ds sV \\*(hV
+..
+.\" NS Sv macro - Soft Space vector (troff limitation)
+.de Sv
+.ds sV \\*(iV
+..
+.\" NS Tv macro - Tab Space vector
+.de Tv
+.ds sV \\*(tV
+..
+.\" NS Sm macro - Space mode
+.\" NS sM register - default is one (space mode on)
+.nr sM 1
+.de Sm
+.if \\n(aC==0 \{\
+. ie \\n(.$==0 .tm "Usage: .Sm [off | on]" (#\\n(.c)
+. el \{\
+. ds mN Sm
+. aV \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
+. \}
+.\}
+.if \\n(aC>0 \{\
+. nr aP \\n(aP+1
+. if "\\*(A\\n(aP"on" \{\
+. ds sV \\*(iV
+. nr sM 1
+. \}
+. if "\\*(A\\n(aP"off" \{\
+. ds sV
+. rm S0 S1 S2 S3 S4 S5 S6 S7 S8 S9
+. nr sM 0
+. \}
+. ie \\n(aC>\\n(aP \{\
+. No
+. \}
+. el .aY
+.\}
+..
+.\"------------------------------------------------------------------------
+.\" Size and Argument type macros
+.\" NS aT macro - argument type
+.\" NS aU macro - argument type (same as .aT but uses A[1-9] strings
+.\" NS aT register argument type
+.if \n(.g \{\
+.de aT
+.nr aT 0
+.ie \\n(sW>2:(\A'\\$1'==0) \{\
+. nr aT 2
+.\}
+.el \{\
+. if \\n(sW==1 \{\
+. ie \\n(z\\$1>2 \{\
+. nr aT \\n(z\\$1
+. \}
+. el .nr aT 2
+. \}
+. if \\n(sW==2 \{\
+. ie \\n(\\$1 \{\
+. nr aT 1
+. \}
+. el .nr aT 2
+. \}
+.\}
+..
+.de aU
+.nr aT 0
+.aW \\$1
+.ie \\n(sW>2:(\A'\\*(A\\$1'==0) .nr aT 2
+.el \{\
+. if \\n(sW==1 \{\
+. ie \\n(z\\*(A\\$1>2 \{\
+. nr aT \\n(z\\*(A\\$1
+. \}
+. el .nr aT 2
+. \}
+. if \\n(sW==2 \{\
+. ie (\\n(\\*(A\\$1) \{\
+. nr aT 1
+. \}
+. el .nr aT 2
+. \}
+.\}
+..
+.\}
+.if !\n(.g \{\
+.de aT
+.nr aT 0
+.ie \\n(sW>2 \{\
+. nr aT 2
+.\}
+.el \{\
+. if \\n(sW==1 \{\
+. ie \\n(z\\$1>2 \{\
+. nr aT \\n(z\\$1
+. \}
+. el .nr aT 2
+. \}
+. if \\n(sW==2 \{\
+. ie \\n(\\$1 \{\
+. nr aT 1
+. \}
+. el .nr aT 2
+. \}
+.\}
+..
+.de aU
+.nr aT 0
+.aW \\$1
+.ie \\n(sW>2 .nr aT 2
+.el \{\
+. if \\n(sW==1 \{\
+. ie \\n(z\\*(A\\$1>2 \{\
+. nr aT \\n(z\\*(A\\$1
+. \}
+. el .nr aT 2
+. \}
+. if \\n(sW==2 \{\
+. ie (\\n(\\*(A\\$1) \{\
+. nr aT 1
+. \}
+. el .nr aT 2
+. \}
+.\}
+..
+.\}
+.\" NS s1 macro - set spacing for class type 1
+.\" NS s2 macro - set spacing for class type 2
+.\" NS s3 macro - set spacing for class type 3
+.\" NS s1 macro - set spacing for class type 1
+.\" NS s2 macro - set spacing for class type 2
+.\" NS s3 macro - set spacing for class type 3
+.\" NS s4 macro - set spacing for class type 4
+.\" NS S[0-9] string spacing
+.\" NS xX local register
+.\" NS aa local register
+.de s0
+.tm MDOC-ERROR: bogus type 0 (can't set space '\\*(A\\n(aC') (#\\n(.c)
+..
+.de s1
+.if \\n(\\*(A\\n(aC==3 \{\
+. nr xX \\n(aC-1
+. rm S\\n(xX
+. ds S\\n(aC \\*(sV
+.\}
+.if \\n(\\*(A\\n(aC==2 \{\
+. nr xX \\n(aC-1
+.\" this kludge can probably go away, but need to double check first
+. ie "\\*(A\\n(aC"Nb" .ds S\\n(xX \\*(hV
+. el .rm S\\n(xX
+.\}
+..
+.de s2
+.ds S\\n(aC \\*(sV
+..
+.de s3
+.if \\n(aC>1 \{\
+. nr xX \\n(aC-1
+. rm S\\n(xX
+.\}
+.ds S\\n(aC \\*(sV
+..
+.de s4
+.nr aa 0
+..
+.\" Class switches (on current argument aP)
+.\" NS c0 macro - catch errors (non-existent class type 0)
+.\" NS c1 macro - call request if type 1
+.\" NS c2 macro - call .No if type 2
+.\" NS c3 macro - call .No if type 3
+.\" NS c4 macro - call .No if type 4
+.de c0
+.tm MDOC-ERROR: bogus class 0 (can't determine '\\*(A\\n(aC') (#\\n(.c)
+..
+.de c1
+.\\*(A\\n(aP
+..
+.de c2
+.nr aP \\n(aP-1
+.No
+..
+.de c3
+.nr aP \\n(aP-1
+.No
+..
+.de c4
+.nr aP \\n(aP-1
+.No
+..
+.\" NS y1 macro - ignore if class 1
+.\" NS y2 macro - ignore if class 2
+.\" NS y3 macro - append if type 3
+.\" NS y4 macro - append if type 4
+.de y1
+.nr aa 1
+..
+.de y2
+.nr aa 1
+..
+.de y3
+.as b1 \\*(A\\n(aP
+.nr aP \\n(aP+1
+.n\\C\\n(aP
+..
+.de y4
+.as b1 \\*(A\\n(aP
+.nr aP \\n(aP+1
+.n\\C\\n(aP
+..
+.\"--------------------------------------------------------------------------
+.\" Ns Bf macro - Begin Font Mode (will be begin-mode/end-mode in groff & TeX)
+.\" Ns Ef macro - End Font Mode
+.de Bf
+.ds mN Bf
+.ie \\n(.$>0 \{\
+. nr bF \\n(.f
+. nr bZ \\n(.s
+. if "\\$1"Em" \&\\*(eM\c
+. if "\\$1"Li" \&\\*(lI\c
+. if "\\$1"Sy" \&\\*(sY\c
+. if "\\$1"-emphasis" \&\\*(eM\c
+. if "\\$1"-literal" \&\\*(lI\c
+. if "\\$1"-symbolic" \&\\*(sY\c
+.\}
+.el .tm Usage .Bf [Em | emphasis | Li | literal | Sy | symbolic] (#\\n(.c)
+..
+.de Ef
+.ds mN Ef
+.ie \\n(.$>0 .tm Usage .Ef (does not take arguments) (#\\n(.c)
+.el \&\f\\n(bF\s\\n(bZ
+..
+.\" Ns Bk macro - Begin Keep
+.\" Ns Ek macro - End Keep
+.\" Ns kS string - keep type
+.de Bk
+.ds mN Bk
+.ie \\n(.$==0 \{\
+.tm Usage: .Bk [-lines | -words] (#\\n(.c)
+.\}
+.el \{\
+. if !"\\*(kS"" .tm .Bk: nesting keeps not implemented yet. (#\\n(.c)
+. if "\\$1"-lines" .tm .Bd -lines: Not implemented yet. (#\\n(.c)
+. if "\\$1"-words" .Hv
+. ds kS \\$1
+.\}
+..
+.de Ek
+.ds mN Ek
+.ie \\n(.$>0 .tm Usage .Ek (does not take arguments) (#\\n(.c)
+.el \{\
+. if "\\*(kS"-lines" .tm .Bd -lines: Not implemented yet. (#\\n(.c)
+. if "\\*(kS"-words" .Sv
+. rm kS
+.\}
+..
+.\" NS Bd macro - Begin Display display-type [offset string]
+.\" NS Ed macro - end Display
+.\" NS O[0-9] registers - stack of indent
+.\" NS d[0-9] registers - display-type stack
+.de Bd
+.ds mN Bd
+.ie \\n(.$==0 \{\
+.tm Usage: .Bd [-literal | -filled | -ragged | -unfilled] [-offset [string]] [-compact] (#\\n(.c)
+.\}
+.el \{\
+. ds aa
+. nr bV 0
+. nr iD 0
+. nr dP \\n(dP+1
+. if "\\$1"-literal" \{\
+. nr iD \\n(iD+1
+. ds d\\n(dP dL
+. nr cF \\n(.f
+. nr cZ \\n(.s
+. ie t \{\&\\*(lI
+' ta 9n 18n 27n 36n 45n 54n 63n 72n
+. \}
+. el \{\
+' ta 8n 16n 24n 32n 40n 48n 56n 64n 72n
+. \}
+. nf
+. \}
+. if "\\$1"-filled" \{\
+. nr iD \\n(iD+1
+. ds d\\n(dP dF
+. br
+. \}
+. if "\\$1"-ragged" \{\
+. nr iD \\n(iD+1
+. ds d\\n(dP dR
+. na
+. \}
+. if "\\$1"-unfilled" \{\
+. nr iD \\n(iD+1
+. ds d\\n(dP dU
+. nf
+. \}
+.\" .tm Here is argc: \\n(.$ and here is iD \\n(iD
+. if ((\\n(iD>=1)&(\\n(.$>\\n(iD)) \{\
+. bV \\$2 \\$3 \\$4
+. \}
+. if \\n(O\\n(dP>0 'in \\n(.iu+\\n(O\\n(dPu
+. if (\\n(bV==0) \{\
+. if (\\n(nS==0) \{\
+. ie "\\*(d\\n(dP"dR" .sp \\n(dVu
+. el 'sp \\n(dVu
+. \}
+. \}
+. if \\n(cR==0 .ne 2v
+. nr bV 0
+. nr iD 0
+.\}
+..
+.\" NS bV macro - resolve remaining .Bd arguments
+.de bV
+.\" .tm in bV with args: \\$1 \\$2 \\$3
+.nr iD 1
+.ds bY
+.if "\\$1"-offset" \{\
+. ds bY \\$2
+. if "\\*(bY"left" \{\
+. nr iD \\n(iD+1
+. nr O\\n(dP 0
+. \}
+. if "\\*(bY"right" \{\
+. nr iD \\n(iD+1
+. nr O\\n(dP (\\n(.l/3)u
+. \}
+. if "\\*(bY"center" \{\
+. nr iD \\n(iD+1
+. nr O\\n(dP (\\n(.l-\\n(.i)/4u
+. \}
+. if "\\*(bY"indent" \{\
+. nr iD \\n(iD+1
+. nr O\\n(dP \\n(dIu
+. \}
+. if "\\*(bY"indent-two" \{\
+. nr iD \\n(iD+1
+. nr O\\n(dP \\n(dIu+\\n(dIu
+. \}
+. if \\n(iD==1 \{\
+. nr iD \\n(iD+1
+. sW "\\*(bY"
+. ie \\n(sW>2 \{\
+. ie ((\\*(bY>9n)&(\\*(bY<100n)) \{\
+. nr O\\n(dP \\*(bY
+. \}
+. el .nr O\\n(dP (\\n(sW)*\\n(fWu
+. \}
+. el \{\
+. if \\n(sW==2 .aT \\*(bY
+. ie \\n(aT==1 \{\
+. nr O\\n(dP \\n(\\*(bY
+. \}
+. el .nr O\\n(dP \\*(bY
+. \}
+. \}
+.\}
+.if "\\$1"-compact" \{\
+. nr bV 1
+.\}
+.if \\n(iD<\\n(.$ \{\
+. ie "\\*(bY"" \{\
+. bV \\$2 \\$3
+. \}
+. el \{\
+. bV \\$3
+. \}
+.\}
+..
+.\" NS Ed macro - end display
+.de Ed
+.ds mN Ed
+.br
+.if \\n(dP==0 .tm mdoc: Extraneous .Ed
+.if "\\*(d\\n(dP"dL" \{\
+. ft \\n(cF
+. fz \\n(cZ
+.\}
+.in \\n(.iu-\\n(O\\n(dPu
+.rr O\\n(dP
+.rm d\\n(dP
+.nr dP \\n(dP-1
+.fi
+.if t .ad
+..
+.\"--------------------------------------------------------------------------
+.\" NS Bl macro - begin list (.Bl list-type)
+.\" NS L[0-9] registers - stack of list types
+.de Bl
+.ie \\n(.$==0 \{\
+.tm Usage: .Bl [[-hang | -tag] [-width]] [ -item | -enum | -bullet | -diag] (#\\n(.c)
+.\}
+.el \{\
+. ds mN Bl
+. nr aP 0
+. nr lC \\n(lC+1
+. ds A1 \\$2
+. ds A2 \\$3
+. ds A3 \\$4
+. ds A4 \\$5
+. ds A5 \\$6
+. ds A6 \\$7
+. ds A7 \\$8
+. ds A8 \\$9
+. nr fV \\n(.$-1
+. if "\\$1"-hang" \{\
+. nr aP \\n(aP+1
+. ds L\\n(lC hL
+. nr w\\n(lC 6n
+. nr tC 1
+. \}
+. if "\\$1"-tag" \{\
+. nr aP \\n(aP+1
+. ds L\\n(lC tL
+. nr tC 1
+. \}
+. if "\\$1"-item" \{\
+. nr aP \\n(aP+1
+. ds L\\n(lC iT
+. nr tC 1
+. \}
+. if "\\$1"-enum" \{\
+. nr aP \\n(aP+1
+. ds L\\n(lC nU
+. nr w\\n(lC 3n
+. nr tC 1
+. \}
+. if "\\$1"-bullet" \{\
+. nr aP \\n(aP+1
+. ds L\\n(lC bU
+. nr w\\n(lC 2n
+. nr tC 1
+. \}
+. if "\\$1"-dash" \{\
+. nr aP \\n(aP+1
+. ds L\\n(lC hU
+. nr w\\n(lC 2n
+. nr tC 1
+. \}
+. if "\\$1"-hyphen" \{\
+. nr aP \\n(aP+1
+. ds L\\n(lC hU
+. nr w\\n(lC 2n
+. nr tC 1
+. \}
+. if "\\$1"-inset" \{\
+. nr aP \\n(aP+1
+. ds L\\n(lC lL
+. nr tC 1
+. \}
+. if "\\$1"-diag" \{\
+. nr aP \\n(aP+1
+. ds L\\n(lC mL
+. nr mL 1
+. \}
+. if "\\$1"-ohang" \{\
+. nr aP \\n(aP+1
+. ds L\\n(lC oL
+. nr tC 1
+. \}
+. if "\\$1"-column" \{\
+. nr aP \\n(aP+1
+. ds L\\n(lC cL
+. \}
+. ie \\n(aP==0 \{\
+. tm \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
+. tm Usage: .Bl [[-inset|-tag] -width] [-item|-enum|-bullet|-diag] (#\\n(.c)
+. \}
+. el \{\
+. tY
+. if (\\n(aP==1)&(\\n(aP<\\n(.$) \{\
+. nr aP 0
+. lV
+. if "\\*(L\\n(lC"cL" \{\
+. W\\n(wV
+. nr w\\n(lC 0
+' in -\\n(eWu
+. ie \\n(v\\n(lC==1 \{\
+. nr aa 0
+. \}
+. el \{\
+. sp \\n(dVu
+. \}
+. nf
+. nr wV 0
+. \}
+. \}
+. \}
+. nr aP 0
+.\" . ds b1
+. aY
+.\" .tm Here is L[\\n(lC]==\\*(L\\n(lC
+.\}
+..
+.if \n(.g \{\
+. nr i 10
+. while \ni<100 \{\
+. nr num!\nin 1
+. nr i +1
+. \}
+.\}
+.\" NS lV macro - resolve remaining .Bl arguments
+.de lV
+.nr aP \\n(aP+1
+.if \\n(fV>=\\n(aP \{\
+. nr iD 0
+. if "\\*(A\\n(aP"-compact" \{\
+. nr iD 1
+. nr v\\n(lC 1
+. \}
+. if "\\*(A\\n(aP"-width" \{\
+. nr iD 1
+. nr aP \\n(aP+1
+. nr tW 1
+. ds t\\n(lC TagwidtH
+. ds tS \\*(A\\n(aP
+. aW \\n(aP
+. ie \\n(sW>2 \{\
+. nr w\\n(lC (\\n(sW)*\\n(fWu
+. if \\n(sW==3 \{\
+. ie \\n(.g \{\
+. if \A'\\*(tS' .if r num!\\*(tS \{\
+. nr w\\n(lC \\*(tS
+. \}
+. \}
+. el \{\
+. if (\\*(tS>9n)&(\\*(tS<99n) \{\
+. nr w\\n(lC \\*(tSu
+. \}
+. \}
+. \}
+. \}
+. el \{\
+. aT \\*(tS
+. ie \\n(aT==1 \{\
+. nr w\\n(lC \\n(\\*(tS
+. \}
+. el \{\
+. nr w\\n(lC \\*(tSu
+. \}
+. \}
+. \}
+. if "\\*(A\\n(aP"-offset" \{\
+. nr iD 1
+. nr aP \\n(aP+1
+. ie "\\*(A\\n(aP"indent" \{\
+. nr o\\n(lC \\n(Dsu
+. \}
+. el \{\
+. ds tS \\*(A\\n(aP
+. aW \\n(aP
+. ie \\n(sW>2 \{\
+. nr o\\n(lC (\\n(sW)*\\n(fWu
+. ie \\n(.g \{\
+. if \A'\\*(tS' .if r num!\\*(tS \{\
+. nr o\\n(lC \\*(tS
+. \}
+. \}
+. el \{\
+. if (\\*(tS>9n)&(\\*(tS<100n) \{\
+. nr o\\n(lC \\*(tS
+. \}
+. \}
+. \}
+. el \{\
+. ie \\n(C\\n(aP==1 .nr o\\n(lC \\n(\\*(tS
+. el .nr o\\n(lC \\*(tS
+. \}
+. \}
+. \}
+. if \\n(iD==0 \{\
+. if "\\*(L\\n(lC"cL" \{\
+. nr wV \\n(wV+1
+. ds A\\n(wV \\*(A\\n(aP
+. \}
+. \}
+. if \\n(fV>\\n(aP .lV
+.\}
+..
+.\" NS El macro - end list
+.\" NS iD local register
+.de El
+.ie \\n(.$>0 \{\
+. tm Usage: .El (#\\n(.c)
+.\}
+.el \{\
+. ds mN El
+. nr iD 0
+. if "\\*(L\\n(lC"cL" \{\
+. nr iD 1
+. cC
+. \}
+. if "\\*(L\\n(lC"nU" \{\
+. nr nU 0
+. \}
+. if \\n(mL>0 \{\
+. nr iD 1
+. nr mL 0
+. tZ
+. nr lC \\n(lC-1
+. tY
+. \}
+. if "\\*(L\\n(lC"iT" \{\
+' in \\n(.iu-\\n(o\\n(lCu
+. tZ
+. nr lC \\n(lC-1
+. tY
+. nr iD 1
+. \}
+. if "\\*(L\\n(lC"oL" \{\
+' in \\n(.iu-\\n(o\\n(lCu
+. tZ
+. nr lC \\n(lC-1
+. tY
+. nr iD 1
+. \}
+. if "\\*(L\\n(lC"lL" \{\
+' in \\n(.iu-\\n(o\\n(lCu
+. tZ
+. nr lC \\n(lC-1
+. tY
+. nr iD 1
+. \}
+. if \\n(iD==0 \{\
+. lE
+. \}
+. br
+. nr iD 0
+.\}
+..
+.\" NS It macro - list item
+.\" NS iD local register
+.\" NS aA save pA font string for section FILES (no underline if nroff)
+.de It
+.if "\\*(L\\n(lC"" \{\
+. tm Usage .Bl -list-type [-width [string] | -compact | -offset [string]] (#\\n(.c)
+. tm .It \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8
+.\}
+.\" .tm Here is L[\\n(lC]==\\*(L\\n(lC
+.ne 3v
+.ie \\n(.$>0 \{\
+. ds mN It
+. ds b1
+. nr iD 0
+. ds A1 \\$1
+. ds A2 \\$2
+. ds A3 \\$3
+. ds A4 \\$4
+. ds A5 \\$5
+. ds A6 \\$6
+. ds A7 \\$7
+. ds A8 \\$8
+. ds A9 \\$9
+. nr fV \\n(.$
+. if "\\*(L\\n(lC"mL" \{\
+. nr iD 1
+. nr aP 0
+. aX
+. \\*(L\\n(lC
+. \}
+. if "\\*(L\\n(lC"cL" \{\
+. ds b1
+. nr aP 0
+. nr iD 1
+. \\*(L\\n(lC
+. \}
+. if "\\*(L\\n(lC"iT" \{\
+. nr aP 0
+. nr iD 1
+. \\*(L\\n(lC
+. \}
+. if \\n(iD==0 \{\
+. fV
+.\" tm ------------------------------------------------------------------------
+.\" tm It list-type==\\*(L\\n(lC, aP==\\n(aP
+.\" tm It beg arg(A[1])==\\*(A1; oM==\\n(oM; dZ==\\n(dZ; Xt==\\n(Xt; aC==\\n(aC
+. nr oM \\n(oM+1
+. nr tP 1
+. nr aP \\n(aP+1
+. nr tX \\n(C\\n(aP
+. ds tX \\*(A\\n(aP
+. if \\n(nF==1 \{\
+. ds aA \\*(pA
+. if n .ds pA \\*(nO
+. \}
+. ie \\n(C\\n(aP==1 \{\
+. \\*(A\\n(aP
+. \}
+. el \{\
+. nr aP \\n(aP-1
+. No
+. \}
+.\" tm in It here is b1==\\*(b1
+.\" tm It mid arg(A[1])==\\*(A1; oM==\\n(oM; dZ==\\n(dZ; Xt==\\n(Xt; aC==\\n(aC
+. ie \\n(Xt==1 .ds xB \&\\*(L\\n(lC
+. el .\\*(L\\n(lC
+. \}
+. nr iD 0
+.\}
+.el .\\*(L\\n(lC
+..
+.\" NS lL macro - .It item of list-type inset
+.de lL
+.lY
+.br
+\&\\*(b1
+.nr oM \\n(oM-1
+.nr tP 0
+.ds b1
+.aY
+'fi
+..
+.\" NS hL macro - .It item of list-type hanging label (as opposed to tagged)
+.de hL
+.lX
+.nr bb \\n(w\\n(lCu+\\n(lSu
+.ti -\\n(bbu
+.ie \w\\*(b1u>=(\\n(w\\n(lCu) \&\\*(b1
+.el \&\\*(b1\h'|\\n(bbu'\c
+.nr oM \\n(oM-1
+.ds b1
+.nr tP 0
+.aY
+'fi
+..
+.\" NS oL macro - .It item of list-type overhanging label
+.de oL
+.lY
+\&\\*(b1
+.br
+.nr oM \\n(oM-1
+.ds b1
+.nr tP 0
+.aY
+'fi
+..
+.\" NS iT macro - .It item of list-type [empty label]
+.de iT
+.lY
+.br
+.\" .ds b1
+.aY
+'fi
+..
+.\" NS nU macro - Enumerated list
+.\" NS nU register count
+.\" NS hU macro - Hyphen paragraph list (sub bullet list)
+.\" NS bU macro - Bullet paragraph list
+.de nU
+.nr oM \\n(oM+1
+.nr nU \\n(nU+1
+.ds b1 \&\\n(nU.
+.uL
+..
+.de bU
+.nr oM \\n(oM+1
+.nr bU \\n(bU+1
+.ds b1 \&\\*(sY\&\(bu\fP
+.uL
+..
+.de hU
+.nr oM \\n(oM+1
+.nr bU \\n(bU+1
+.ds b1 \&\\*(sY\&\-\fP
+.uL
+..
+.\" NS uL macro - .It item of list-type enum/bullet/hyphen
+.de uL
+.lX
+.nr bb \\n(w\\n(lCu+\\n(lSu
+.ti -\\n(bbu
+.ie \w\\*(b1u>=(\\n(w\\n(lCu) \&\\*(b1
+.el \&\\*(b1\h'|\\n(bbu'\c
+.nr oM \\n(oM-1
+.\" .nr dZ \\n(dZ+1
+.ds b1
+.nr tP 0
+.aY
+'fi
+..
+.\" NS mL macro - .It item of list-type diagnostic-message
+.de mL
+.nr cF \\n(.f
+.nr cZ \\n(.s
+.ie \\n(mL==1 \{\
+. nr zB \\n(.c
+. ie (\\n(zB-\\n(zA)>1 .Pp
+. el .br
+. nr zA \\n(zB
+. nr zB 0
+.\}
+.el \{\
+. nr zA \\n(.c
+. br
+.\}
+\&\\*(sY\\*(b1\f\\n(cF\s\\n(cZ\\*(lS\c
+.aY
+.ds b1
+'fi
+..
+.\" NS tL macro - .It item of list-type "tag"
+.de tL
+.\" tm in tL here is b1==\\*(b1
+.if \\n(tW==0 .lW
+.lX
+.nr bb \\n(w\\n(lCu+\\n(lSu
+.ti -\\n(bbu
+.ie (\w\\*(b1u)>(\\n(w\\n(lCu) \{\&\\*(b1
+. br
+.\}
+.el \&\\*(b1\h'|\\n(bbu'\c
+.if \\n(nF==1 \{\
+. if n .ds pA \\*(aA
+.\}
+.nr oM \\n(oM-1
+.nr tP 0
+.\" .nr dZ \\n(dZ+1
+.ds b1
+.aY
+'fi
+..
+.\" NS lW macro - resolve unknown label/tag width (if .Bl [inset | tag] only)
+.de lW
+.if !"TagwidtH"\\*(t\\n(lC" \{\
+. ie \\n(tX==1 \{\
+. ds t\\n(lN \\*(tX
+. nr w\\n(lN \\n(\\*(tX
+. \}
+. el \{\
+. ds t\\n(lN No
+. nr w\\n(lN \\n(No
+. \}
+. if !"\\*(t\\n(lC"\\*(t\\n(lN" .nr tC 1
+.\}
+..
+.\" NS lX macro - set up vertical spacing (if compact) and offset+indent (all)
+.de lX
+.ie \\n(tC \{\
+. nr tC 0
+. nr tW 0
+. if \\n(v\\n(lC==0 .sp \\n(dVu
+. in \\n(.iu+\\n(w\\n(lCu+\\n(o\\n(lCu+\\n(lSu
+.\}
+.el \{\
+. ie \\n(v\\n(lC==1 \{\
+. nr aa 0
+. \}
+. el \{\
+. sp \\n(dVu
+. \}
+.\}
+.if !\\n(cR .ne 2v
+..
+.\" NS lY macro - set up vertical spacing (if compact) and offset+indent (all)
+.de lY
+.ie \\n(tC \{\
+. nr tC 0
+. nr tW 0
+. if \\n(v\\n(lC==0 .sp \\n(dVu
+. in \\n(.iu+\\n(o\\n(lCu
+.\}
+.el \{\
+. ie \\n(v\\n(lC==1 \{\
+. nr aa 0
+. \}
+. el \{\
+. sp \\n(dVu
+. \}
+.\}
+.if !\\n(cR .ne 2v
+..
+.\" NS tS temporary string
+.\" NS hL macro - hanging list function
+.\" NS tS temporary string
+.\" NS hL macro - hanging list function
+.\" NS lT macro - tagged list function
+.\" NS lE macro - list end function
+.\" NS tX string (initial string)
+.\" NS tX register (initial class)
+.\" NS tC parameter change flag
+.\" NS Xt save current list-type flag
+.\" NS lC register - list type stack counter
+.\" NS tP register tag flag (for diversions)
+.\" NS w[0-9] register tag stack (nested tags)
+.\" NS t[0-9] register tag string stack (nested tags)
+.\" NS o[0-9] register offset stack (nested tags)
+.\" NS v[0-9] register vertical tag break stack
+.\" NS h[0-9] register horizontal tag stack (continuous if 1, break if 0)
+.nr lC 0
+.nr wV 0
+.nr w1 0
+.nr o1 0
+.nr v1 0
+.nr h1 0
+.ds t\n(lC
+.de lE
+.\" IN lC o[\\n(lC]==\\n(o\\n(lC, w[\\n(lC]==\\n(w\\n(lC,
+.ie \\n(o\\n(lC>0 \{\
+' in \\n(.iu-(\\n(w\\n(lCu)-(\\n(o\\n(lCu)-\\n(lSu
+. rr o\\n(lC
+.\}
+.el 'in \\n(.iu-\\n(w\\n(lCu-\\n(lSu
+.if \\n(lC<=0 .tm Extraneous .El call (#\\n(.c)
+.tZ
+.nr lC \\n(lC-1
+.tY
+..
+.\" NS tY macro - set up next block for list
+.\" NS tZ macro - decrement stack
+.\" NS tY register (next possible lC value)
+.de tY
+.nr tY (\\n(lC+1)
+.nr w\\n(tY 0
+.nr h\\n(tY 0
+.nr o\\n(tY 0
+.ds t\\n(tY \\*(t\\n(lC
+.ds L\\n(tY
+.nr v\\n(tY 0
+..
+.de tZ
+.rm L\\n(tY
+.rr w\\n(tY
+.rr h\\n(tY
+.rr o\\n(tY
+.rm t\\n(tY
+.rr v\\n(tY
+.nr tY \\n(tY-1
+..
+.\" initial values
+.nr w1 0
+.nr o1 0
+.nr h1 0
+.ds t1
+.nr v1 0
+.nr tY 1
+.\" NS Xr macro - cross reference (man page only)
+.de Xr
+.if \\n(aC==0 \{\
+. ie \\n(.$==0 .tm Usage: .Xr manpage_name [section#] \\*(Pu (#\\n(.c)
+. el \{\
+. ds mN Xr
+. aV \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
+. \}
+.\}
+.if \\n(aC>\\n(aP \{\
+. nr aP \\n(aP+1
+. ie \\n(C\\n(aP==1 .tm Usage: .Xr manpage_name [section#] \\*(Pu (#\\n(.c)
+. el \{\
+. ie \\n(C\\n(aP>2 .y\\n(C\\n(aP
+. el \{\
+. as b1 \&\\*(xR\\*(A\\n(aP\fP\s0
+. if \\n(aC>\\n(aP \{\
+. nr aP \\n(aP+1
+. if \\n(C\\n(aP==2 \{\
+. as b1 \&(\\*(A\\n(aP)
+. nr aP \\n(aP+1
+. \}
+. if \\n(aC>=\\n(aP \{\
+. c\\n(C\\n(aP
+. \}
+. \}
+. \}
+. aZ
+. \}
+.\}
+..
+.\" NS Sx macro - cross section reference
+.de Sx
+.if \\n(aC==0 \{\
+. ie \\n(.$==0 .tm Sx Usage: .Sx Section Header \\*(Pu (#\\n(.c)
+. el \{\
+. ds mN Sx
+. aV \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
+. \}
+.\}
+.\}
+.if \\n(aC>\\n(aP \{\
+. nr aP \\n(aP+1
+. as b1 \\*(sX
+. nr cF \\n(.f
+. nr cZ \\n(.s
+. nR
+.\}
+..
+.\" NS cC macro - column-list end-list
+.\" NS eW macro - column indent width
+.\" NS cI register - column indent width
+.\" NS W[1-5] macro - establish tabs for list-type column
+.de cC
+'in \\n(.iu-\\n(o\\n(lCu-\\n(w\\n(lCu
+.ta .5i 1i 1.5i 2i 2.5i 3i 3.5i 4i 4.5i 5i 5.5i 6i 6.5i
+.fi
+.tZ
+.nr lC \\n(lC-1
+.tY
+..
+.de W1
+.ta \w\\*(A1 u
+.nr eW \w\\*(A1 u
+'in \\n(.iu+\\n(eWu+\\n(o\\n(lCu
+..
+.de W2
+.ta \w\\*(A1 u +\w\\*(A2 u
+.nr eW \w\\*(A1 u+\w\\*(A2 u
+'in \\n(.iu+\\n(eWu+\\n(o\\n(lCu
+..
+.de W3
+.ta \w\\*(A1 u +\w\\*(A2 u +\w\\*(A3 u
+.nr eW \w\\*(A1 u+\w\\*(A2 u+\w\\*(A3 u
+'in \\n(.iu+\\n(eWu+\\n(o\\n(lCu
+..
+.de W4
+.ta \w\\*(A1 u +\w\\*(A2 u +\w\\*(A3 u +\w\\*(A4 u
+.nr eW \w\\*(A1 u+\w\\*(A2 u +\w\\*(A3 u +\w\\*(A4 u
+'in \\n(.iu+\\n(eWu+\\n(o\\n(lCu
+..
+.de W5
+.ta \w\\*(A1 u +\w\\*(A2 u +\w\\*(A3 u +\w\\*(A4 u +\w\\*(A5 u
+.nr eW \w\\*(A1 u +\w\\*(A2 u +\w\\*(A3 u +\w\\*(A4 u +\w\\*(A5 u
+' in \\n(.iu+\\n(eWu+\\n(o\\n(lCu
+..
+.\" This is packed abnormally close, intercol width should be an option
+.de W6
+.ta \w\\*(A1 u +\w\\*(A2 u +\w\\*(A3 u +\w\\*(A4 u +\w\\*(A5 u +\w\\*(A6
+.nr eW \w\\*(A1 u +\w\\*(A2 u +\w\\*(A3 u +\w\\*(A4 u +\w\\*(A5 u +\w\\*(A6
+' in \\n(.iu+\\n(eWu+\\n(o\\n(lCu
+..
+.\" NS cL macro - column items
+.de cL
+.if \\n(w\\n(lC==0 .nr w\\n(lC \\n(eWu
+.if \\n(.u==0 \{\
+. fi
+' in \\n(.iu+\\n(eWu
+.\}
+.ti -\\n(eWu
+.fV
+.nr aP \\n(aP+1
+.ie \\n(aC>=\\n(aP \{\
+. if "\\*(A\\n(aP"Ta" \{\
+. nr jJ \\n(aP-1
+. rm S\\n(jJ
+. rr jJ
+. \}
+. c\\n(C\\n(aP
+.\}
+.el .tm Usage: .It column_string [Ta [column_string ...] ] (#\\n(.c)
+..
+.\" NS Ta macro - append tab (\t)
+.de Ta
+.ie \\n(aC>0 \{\
+. nr aP \\n(aP+1
+. ie \\n(aC>=\\n(aP \{\
+. if "\\*(A\\n(aP"Ta" \{\
+. nr jJ \\n(aP-1
+. rm S\\n(jJ
+. rr jJ
+. \}
+. as b1 \\t
+. c\\n(C\\n(aP
+. \}
+. el \{\
+. as b1 \\t\\c
+. rm S\\n(aP
+. pB
+. aY
+.\" . ds b1
+. \}
+.\}
+.el \{\
+. tm Usage: Ta must follow column entry: e.g. (#\\n(.c)
+. tm .It column_string [Ta [column_string ...] ]
+.\}
+..
+.\"
+.\" NS Dl macro - display (one line) literal
+.de Dl
+'ta .5i 1i 1.5i 2i 2.5i 3i 3.5i 4i 4.5i 5i 5.5i 6i 6.5i
+.in \\n(.iu+\\n(Dsu
+.ie \\n(aC==0 \{\
+. ie \\n(.$==0 \{\
+. tm Usage: .Dl argument ... (#\\n(.c)
+. \}
+. el \{\
+. ds mN Dl
+. ds A1 \\$1
+. ds A2 \\$2
+. ds A3 \\$3
+. ds A4 \\$4
+. ds A5 \\$5
+. ds A6 \\$6
+. ds A7 \\$7
+. ds A8 \\$8
+. ds A9 \\$9
+. nr fV \\n(.$
+. fV
+. Li
+. \}
+.\}
+.el \{\
+. tm Usage: .Dl not callable by other macros (#\\n(.c)
+.\}
+.in \\n(.iu-\\n(Dsu
+..
+.\"
+.\" NS D1 macro - display (one line)
+.de D1
+'ta .5i 1i 1.5i 2i 2.5i 3i 3.5i 4i 4.5i 5i 5.5i 6i 6.5i
+.in \\n(.iu+\\n(Dsu
+.ie \\n(aC==0 \{\
+. ie \\n(.$==0 \{\
+. tm Usage: .D1 argument ... (#\\n(.c)
+. \}
+. el \{\
+. ds mN D1
+. ds A1 \\$1
+. ds A2 \\$2
+. ds A3 \\$3
+. ds A4 \\$4
+. ds A5 \\$5
+. ds A6 \\$6
+. ds A7 \\$7
+. ds A8 \\$8
+. ds A9 \\$9
+. nr fV \\n(.$
+. fV
+. nr aP \\n(aP+1
+. ie \\n(C\\n(aP==1 .\\*(A\\n(aP
+. el .No
+. \}
+.\}
+.el \{\
+. tm Usage: .D1 not callable by other macros (#\\n(.c)
+.\}
+.in \\n(.iu-\\n(Dsu
+..
+.\" NS Ex macro - DEFUNCT
+.de Ex
+.tm Ex defunct, Use .D1: \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
+..
+.\"
+.\" NS Ex macro - DEFUNCT
+.de Ex
+.tm Ex defunct, Use .D1: \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
+..
+.\"
+.\" NS Vt macro - Variable type (for forcing old style variable declarations)
+.\" this is not done in the same manner as .Ot for fortrash - clean up later
+.de Vt
+.\" if a function declaration was the last thing given, want vertical space
+.if \\n(fD>0 \{\
+. Pp
+. nr fD 0
+.\}
+.\" if a subroutine was the last thing given, want vertical space
+.if \\n(fZ>0 \{\
+. ie \\n(fX==0 \{\
+. Pp
+. rs
+. \}
+. el .br
+.\}
+.nr fX \\n(fX+1
+.nr cF \\n(.f
+.nr cZ \\n(.s
+\\*(fT\&\\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
+.ie \\n(oT==0 .br
+.el \&\ \&
+.ft \\n(cF
+.fs \\n(cZ
+..
+.\"
+.\" NS Ft macro - Function type
+.nr fZ 0
+.de Ft
+.if \\n(nS>0 \{\
+. if \\n(fZ>0 \{\
+. Pp
+. nr fD 0
+. nr fX 0
+. \}
+. if \\n(fD>0 \{\
+. Pp
+. nr fD 0
+. nr fX 0
+. \}
+. if \\n(fX>0 \{\
+. Pp
+. nr fX 0
+. \}
+. nr fY 1
+.\}
+.nr cF \\n(.f
+.nr cZ \\n(.s
+\&\\*(fT\\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
+.ft \\n(cF
+.fs \\n(cZ
+.\" .br
+..
+.\"
+.\" NS Ot macro - Old Function type (fortran - no newline)
+.\" Ns oT register
+.nr oT 0
+.de Ot
+.nr oT 1
+.if \\n(nS>0 \{\
+. if \\n(fZ>0 \{\
+. Pp
+. nr fD 0
+. nr fX 0
+. \}
+. if \\n(fD>0 \{\
+. Pp
+. nr fD 0
+. nr fX 0
+. \}
+. if \\n(fX>0 \{\
+. Pp
+. nr fX 0
+. \}
+. nr fY 1
+.\}
+.if \\n(.$==4 .as b1 \&\\*(fT\&\\$1 \\$2 \\$3 \\$4
+.if \\n(.$==3 .as b1 \&\\*(fT\&\\$1 \\$2 \\$3
+.if \\n(.$==2 .as b1 \&\\*(fT\&\\$1 \\$2
+.if \\n(.$==1 .as b1 \&\\*(fT\&\\$1
+.as b1 \&\ \fP
+..
+.\"
+.\" NS Fa macro - Function arguments
+.de Fa
+.if \\n(aC==0 \{\
+. ie \\n(.$==0 .tm Usage: .Fa Function Arguments ... \\*(Pu (#\\n(.c)
+. el \{\
+. ds mN Fa
+. ds A1 \\$1
+. ds A2 \\$2
+. ds A3 \\$3
+. ds A4 \\$4
+. ds A5 \\$5
+. ds A6 \\$6
+. ds A7 \\$7
+. ds A8 \\$8
+. ds A9 \\$9
+. nr fV \\n(.$
+. fV
+. \}
+.\}
+.ie \\n(fC>0 \{\
+. fC
+.\}
+.el \{\
+. if \\n(aC>\\n(aP \{\
+. as b1 \\*(fA
+. nr aP \\n(aP+1
+. nr cF \\n(.f
+. nr cZ \\n(.s
+. nR
+. if \\n(nS>0 \{\
+. if \\n(fZ>0 .br
+. \}
+. \}
+.\}
+..
+.\" NS fC macro - interal .Fa for .FO and .Fc
+.de fC
+.ie \\n(aC>\\n(aP \{\
+. nr aP \\n(aP+1
+.\" . nr aa \\n(aP
+.\" . if \\n(nS>0 \{\
+. ds Fb
+. nr fB 0
+. nr Fb 0
+. fB \\*(A\\n(aP
+. if \\n(fB>1 \{\
+. rm A\\n(aP
+. rn Fb A\\n(aP
+. \}
+.\" . \}
+. if \\n(fC>1 \{\
+. as b1 \&\f\\n(cF\s\\n(cZ,\\*(S\\n(aP\\*(fA\\*(A\\n(aP\fP\s0
+.\" . as b1 \&\\,\\*(S\\n(aP\fP\s0\\*(fA\\*(A\\n(aP\fP\s0
+. \}
+. if \\n(fC==1 \{\
+. as b1 \&\|\\*(fA\\*(A\\n(aP\fP\s0
+. \}
+. nr fC \\n(fC+1
+. fC
+.\}
+.el \{\
+. aY
+.\}
+..
+.\" NS Fn macro - functions
+.\" NS fY register - dick with old style function declarations (fortran)
+.\" NS fZ register - break a line when more than one function in a synopsis
+.\"
+.de Fn
+.if \\n(aC==0 \{\
+. ie \\n(.$==0 .tm Usage: .Fn function_name function_arg(s) ... \\*(Pu (#\\n(.c)
+. el \{\
+. ds mN Fn
+. ds A1 \\$1
+. ds A2 \\$2
+. ds A3 \\$3
+. ds A4 \\$4
+. ds A5 \\$5
+. ds A6 \\$6
+. ds A7 \\$7
+. ds A8 \\$8
+. ds A9 \\$9
+. nr fV \\n(.$
+. fV
+. \}
+.\}
+.if \\n(nS>0 \{\
+.\" if there is/has been more than one subroutine declaration
+. if \\n(fY==0 \{\
+. if \\n(fZ>0 \{\
+. Pp
+. nr fX 0
+. nr fD 0
+. \}
+. \}
+. if \\n(fY==1 \{\
+. br
+. nr fX 0
+. nr fD 0
+. nr fY 0
+. \}
+. if \\n(fD>0 \{\
+. Pp
+. nr fX 0
+. \}
+. if \\n(fX>0 \{\
+. Pp
+. nr fD 0
+. \}
+. nr fZ \\n(fZ+1
+. nr fY 0
+. rs
+. ie \\n(nS>1 .br
+. el \{\
+. if \\n(iS==0 \{\
+. nr iS ((8)*\\n(fW)u
+. \}
+. \}
+. in +\\n(iSu
+. ti -\\n(iSu
+. nr nS \\n(nS+1
+.\}
+.if \\n(aC>\\n(aP \{\
+. nr aP \\n(aP+1
+. nr cF \\n(.f
+. nr cZ \\n(.s
+. as b1 \\*(fN\\*(A\\n(aP\fP\s0\\*(lp
+. ie \\n(aC>\\n(aP \{\
+. as b1 \\*(fA
+. nr aP \\n(aP+1
+. f\\n(C\\n(aP
+. \}
+. el \{\
+. as b1 \|\\*(rp
+. aZ
+. \}
+. if \\n(nS>0 \{\
+. in -\\n(iSu
+. \}
+.\}
+..
+.\"
+.\" NS f1 macro - class switch
+.\" NS f2 macro - handle function arguments
+.\" NS f3 macro - punctuation
+.\" NS f4 macro - write out function
+.de f1
+.as b1 \\*(rp\f\\n(cF\s\\n(cZ
+.\\*(A\\n(aP
+..
+.de f2
+.if \\n(nS>0 \{\
+. ds Fb
+. nr fB 0
+. nr Fb 0
+. fB \\*(A\\n(aP
+. if \\n(fB>1 \{\
+. rm A\\n(aP
+. rn Fb A\\n(aP
+. \}
+.\}
+.as b1 \\*(A\\n(aP
+.ie \\n(aC>\\n(aP \{\
+. nr aa \\n(aP
+. nr aP \\n(aP+1
+. if \\n(C\\n(aP==2 \{\
+. as b1 \&\|\f\\n(cF\s\\n(cZ,\\*(S\\n(aa\fP\s0\|
+. \}
+. f\\n(C\\n(aP
+.\}
+.el \{\
+. as b1 \\*(rp\f\\n(cF\s\\n(cZ
+. aZ
+.\}
+..
+.de f3
+.as b1 \\*(rp\f\\n(cF\s\\n(cZ\\*(A\\n(aP
+.ie \\n(aC>\\n(aP \{\
+. No
+.\}
+.el .aZ
+..
+.de f4
+.as b1 \\*(rp\f\\n(cF\s\\n(cZ\\*(S\\n(aP\\*(A\\n(aP
+.ie \\n(aC>\\n(aP \{\
+. nr aP \\n(aP+1
+. No
+.\}
+.el .aZ
+..
+.de Fo
+.hy 0
+.if \\n(aC==0 \{\
+. ie \\n(.$==0 .tm Usage: .Fo function_name
+. el \{\
+. ds mN Fo
+. ds A1 \\$1
+. ds A2 \\$2
+. ds A3 \\$3
+. ds A4 \\$4
+. ds A5 \\$5
+. ds A6 \\$6
+. ds A7 \\$7
+. ds A8 \\$8
+. ds A9 \\$9
+. nr fV \\n(.$
+. fV
+. \}
+.\}
+.if \\n(nS>0 \{\
+.\" if there is/has been more than one subroutine declaration
+. if \\n(fY==0 \{\
+. if \\n(fZ>0 \{\
+. Pp
+. nr fX 0
+. nr fD 0
+. \}
+. \}
+. if \\n(fY==1 \{\
+. br
+. nr fX 0
+. nr fD 0
+. nr fY 0
+. \}
+. if \\n(fD>0 \{\
+. Pp
+. nr fX 0
+. \}
+. if \\n(fX>0 \{\
+. Pp
+. nr fD 0
+. \}
+. nr fZ \\n(fZ+1
+. nr fY 0
+. rs
+. ie \\n(nS>1 .br
+. el \{\
+. if \\n(iS==0 \{\
+. nr iS ((8)*\\n(fW)u
+. \}
+. \}
+. in +\\n(iSu
+. ti -\\n(iSu
+. nr nS \\n(nS+1
+.\}
+.if \\n(aC>\\n(aP \{\
+. nr oM \\n(oM+1
+. nr fC 1
+. nr aP \\n(aP+1
+. nr cF \\n(.f
+. nr cZ \\n(.s
+. as b1 \\*(fN\\*(A\\n(aP\fP\s0\\*(lp
+. aY
+.\}
+..
+.de Fc
+.if \\n(aC==0 \{\
+. if \\n(.$>0 \{\
+. ds mN Fo
+. ds A1 \\$1
+. ds A2 \\$2
+. ds A3 \\$3
+. ds A4 \\$4
+. ds A5 \\$5
+. ds A6 \\$6
+. ds A7 \\$7
+. ds A8 \\$8
+. ds A9 \\$9
+. nr fV \\n(.$
+. fV
+. \}
+.\}
+.nr fC 0
+.nr oM \\n(oM-1
+.as b1 \|\\*(rp
+.ie \\n(aC>\\n(aP \{\
+. nr aP \\n(aP+1
+. \\*(A\\n(aP
+.\}
+.el \{\
+. aZ
+.\}
+.if \\n(nS>0 \{\
+. in -\\n(iSu
+.\}
+.hy
+..
+.\" NS fb macro - if SYNOPSIS, set hard space inbetween function args
+.\" NS fb register - count of words in a function argument
+.\" NS Fb register - counter
+.\" NS Fb string - temporary string
+.de fB
+.\" .tm fB==\\n(fB, Fb==\\n(Fb, 1==\\$1 2==\\$2 3==\\$3 4==\\$4 5==\\$5 6==\\$6
+.if \\n(fB==0 \{\
+. nr fB \\n(.$
+. nr Fb 0
+. ds Fb
+.\}
+.nr Fb \\n(Fb+1
+.as Fb \&\\$1
+.if \\n(Fb<\\n(fB \{\
+. as Fb \&\\*(hV
+. fB \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
+.\}
+..
+.\" NS Fc - Function close - not implemented yet
+.\" NS Fo - Function open - not implemented yet
+.\"
+.\" Very crude references, stash all reference info into strings (usual
+.\" use of b1 buffer, then b1 contents copied to string of retrievable
+.\" naming convention), print out reference on .Re request and clean up.
+.\" Ordering very limited, no fancy citations, but can do articles, journals
+.\" and books - need to add several missing options (like city etc).
+.\" should be able to grab a refer entry, massage it a wee bit (prefix
+.\" a `.' to the %[A-Z]) and not worry (ha!)
+.\"
+.\" NS Rs macro - Reference Start
+.\" NS rS register - Reference Start flag
+.\" NS rS string - Reference Start buffer name for next save (of b1 buffer)
+.de Rs
+.nr rS 1
+.rC
+.if \\n(nA==1 .Pp
+.nr Kl 0
+..
+.\" NS Re macro - Reference End
+.de Re
+.rZ
+.rC
+.nr rS 0
+..
+.\" NS rC macro - reference cleanup
+.de rC
+.nr uK 0
+.nr jK 0
+.nr nK 0
+.nr oK 0
+.nr qK 0
+.nr rK 0
+.nr tK 0
+.nr vK 0
+.nr dK 0
+.nr pK 0
+.nr bK 0
+.ds rS
+.rm U1 U2 U3 U4 U5 U6 U7 U8
+.rm uK jK nK oK rK qK tK vK dK pK bK
+..
+.\" NS rZ macro - reference print
+.de rZ
+.if \\n(uK \{\&\\*(U1,
+. nr aK 1
+. if (\\n(uK>1 \{\
+. aK
+. \}
+. nr Kl -\\n(uK
+.\}
+.if \\n(tK \{\
+. nr Kl \\n(Kl-1
+. if \\n(Kl==0 \{\
+. ie (\\n(jK==1):(\\n(bK==1) \{\&\\*q\\*(tK\\*q.
+. \}
+. el \{\&\\*(eM\\*(tK\\*(nO.
+. \}
+. \}
+. if \\n(Kl>0 \{\
+. ie (\\n(jK==1):(\\n(bK==1) \{\&\\*q\\*(tK\\*q,
+. \}
+. el \{\&\\*(eM\\*(tK\\*(nO,
+. \}
+. \}
+.\}
+.if \\n(bK \{\
+. nr Kl \\n(Kl-1
+. if \\n(Kl==0 \&\\*(eM\\*(bK\\*(nO.
+. if \\n(Kl>0 \&\\*(eM\\*(bK\\*(nO,
+.\}
+.if \\n(jK \{\
+. nr Kl \\n(Kl-1
+. if \\n(Kl==0 \&\\*(eM\\*(jK\\*(nO.
+. if \\n(Kl>0 \&\\*(eM\\*(jK\\*(nO,
+.\}
+.if \\n(rK \{\
+. nr Kl \\n(Kl-1
+. if \\n(Kl==0 \&\\*(rK.
+. if \\n(Kl>0 \&\\*(rK,
+.\}
+.if \\n(nK \{\
+. nr Kl \\n(Kl-1
+. if \\n(Kl==0 \&\\*(nK.
+. if \\n(Kl>0 \&\\*(nK,
+.\}
+.if \\n(vK \{\
+. nr Kl \\n(Kl-1
+. if \\n(Kl==0 \&\\*(vK.
+. if \\n(Kl>0 \&\\*(vK,
+.\}
+.if \\n(pK \{\
+. nr Kl \\n(Kl-1
+. if \\n(Kl==0 \&\\*(pK.
+. if \\n(Kl>0 \&\\*(pK,
+.\}
+.if \\n(qK \{\
+. nr Kl \\n(Kl-1
+. if \\n(Kl==0 \&\\*(qK.
+. if \\n(Kl>0 \&\\*(qK,
+.\}
+.if \\n(dK \{\
+. nr Kl \\n(Kl-1
+. if \\n(Kl==0 \&\\*(dK.
+. if \\n(Kl>0 \&\\*(dK,
+.\}
+.if \\n(oK \{\
+. nr Kl \\n(Kl-1
+. if \\n(Kl==0 \&\\*(oK.
+. if \\n(Kl>0 \&\\*(oK,
+.\}
+.if \\n(Kl>0 .tm unresolved reference problem
+..
+.\" NS aK macro - print out reference authors
+.de aK
+.nr aK \\n(aK+1
+.ie (\\n(uK-\\n(aK)==0 \{\&and \\*(U\\n(aK,
+.\}
+.el \{\&\\*(U\\n(aK,
+. aK
+.\}
+..
+.\" NS %A macro - reference author(s)
+.\" NS uK register - reference author(s) counter
+.\" NS U[1-9] strings - reference author(s) names
+.de %A
+.if \\n(aC==0 \{\
+. ie \\n(.$==0 .tm Usage: .%A Author_name (#\\n(.c)
+. el \{\
+. nr uK \\n(uK+1
+. nr Kl \\n(Kl+1
+. ds rS U\\n(uK
+. ds mN %A
+. aV \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
+. \}
+.\}
+.if \\n(aC>\\n(aP \{\
+. nr aP \\n(aP+1
+. nr cF \\n(.f
+. nr cZ \\n(.s
+. rR
+.\}
+..
+.\" NS %B macro - [reference] Book Name
+.\" NS bK string - Book Name
+.\" NS bK register - Book Name flag
+.de %B
+.if \\n(aC==0 \{\
+. ie \\n(.$==0 .tm Usage: .%B Book Name (#\\n(.c)
+. el \{\
+. ds mN %B
+. if \\n(rS>0 \{\
+. nr bK \\n(bK+1
+. nr Kl \\n(Kl+1
+. ds rS bK
+. \}
+. ds A1 \\$1
+. ds A2 \\$2
+. ds A3 \\$3
+. ds A4 \\$4
+. ds A5 \\$5
+. ds A6 \\$6
+. ds A7 \\$7
+. ds A8 \\$8
+. ds A9 \\$9
+. nr fV \\n(.$
+. fV
+. \}
+.\}
+.if \\n(aC>\\n(aP \{\
+. nr aP \\n(aP+1
+. nr cF \\n(.f
+. nr cZ \\n(.s
+. ie \\n(rS==0 \{\
+. as b1 \&\\*(eM
+. nR
+. \}
+. el .rR
+.\}
+..
+.\" NS %D macro - [reference] Date
+.\" NS dK string - Date String
+.\" NS dK register - Date flag
+.de %D
+.if \\n(aC==0 \{\
+. ie \\n(.$==0 .tm Usage: .%D Date (#\\n(.c)
+. el \{\
+. ds mN %D
+. nr dK \\n(dK+1
+. nr Kl \\n(Kl+1
+. ds rS dK
+. ds A1 \\$1
+. ds A2 \\$2
+. ds A3 \\$3
+. ds A4 \\$4
+. ds A5 \\$5
+. ds A6 \\$6
+. ds A7 \\$7
+. ds A8 \\$8
+. ds A9 \\$9
+. nr fV \\n(.$
+. fV
+. \}
+.\}
+.if \\n(aC>\\n(aP \{\
+. nr aP \\n(aP+1
+. nr cF \\n(.f
+. nr cZ \\n(.s
+. rR
+.\}
+..
+.\" NS %J macro - [reference] Journal Name
+.\" NS jK register - [reference] Journal Name flag
+.\" NS jK string - [reference] Journal Name
+.de %J
+.if \\n(aC==0 \{\
+. ie \\n(.$==0 .tm Usage: .%J Journal Name (#\\n(.c)
+. el \{\
+. ds mN %J
+. nr jK \\n(jK+1
+. ds rS jK
+. nr Kl \\n(Kl+1
+. ds A1 \\$1
+. ds A2 \\$2
+. ds A3 \\$3
+. ds A4 \\$4
+. ds A5 \\$5
+. ds A6 \\$6
+. ds A7 \\$7
+. ds A8 \\$8
+. ds A9 \\$9
+. nr fV \\n(.$
+. fV
+. \}
+.\}
+.if \\n(aC>\\n(aP \{\
+. nr aP \\n(aP+1
+. nr cF \\n(.f
+. nr cZ \\n(.s
+. rR
+.\}
+..
+.\" NS %N macro - [reference] issue number
+.\" NS nK register - [reference] issue number flag
+.\" NS nK string - [reference] issue number
+.de %N
+.if \\n(aC==0 \{\
+. ie \\n(.$==0 .tm Usage: .%N issue number (#\\n(.c)
+. el \{\
+. nr nK \\n(nK+1
+. nr Kl \\n(Kl+1
+. ds rS nK
+. ds mN %N
+. aV \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
+. \}
+.\}
+.if \\n(aC>\\n(aP \{\
+. nr aP \\n(aP+1
+. nr cF \\n(.f
+. nr cZ \\n(.s
+. rR
+.\}
+..
+.\" NS %O macro - [reference] optional information
+.\" NS oK register - [reference] optional information flag
+.\" NS oK string - [reference] optional information
+.de %O
+.if \\n(aC==0 \{\
+. ie \\n(.$==0 .tm Usage: .%O optional information ... \\*(Pu (#\\n(.c)
+. el \{\
+. ds mN %O
+. nr oK \\n(oK+1
+. nr Kl \\n(Kl+1
+. ds rS oK
+. ds A1 \\$1
+. ds A2 \\$2
+. ds A3 \\$3
+. ds A4 \\$4
+. ds A5 \\$5
+. ds A6 \\$6
+. ds A7 \\$7
+. ds A8 \\$8
+. ds A9 \\$9
+. nr fV \\n(.$
+. fV
+. \}
+.\}
+.if \\n(aC>\\n(aP \{\
+. nr aP \\n(aP+1
+. nr cF \\n(.f
+. nr cZ \\n(.s
+. rR
+.\}
+..
+.\" NS %P macro - [reference] page numbers
+.\" NS pK register - [reference] page number flag
+.\" NS pK string - [reference] page number
+.de %P
+.if \\n(aC==0 \{\
+. ie \\n(.$==0 .tm Usage: .%P page numbers ... \\*(Pu (#\\n(.c)
+. el \{\
+. ds mN %P
+. nr pK \\n(pK+1
+. nr Kl \\n(Kl+1
+. ds rS pK
+. ds A1 \\$1
+. ds A2 \\$2
+. ds A3 \\$3
+. ds A4 \\$4
+. ds A5 \\$5
+. ds A6 \\$6
+. ds A7 \\$7
+. ds A8 \\$8
+. ds A9 \\$9
+. nr fV \\n(.$
+. fV
+. \}
+.\}
+.if \\n(aC>\\n(aP \{\
+. nr aP \\n(aP+1
+. nr cF \\n(.f
+. nr cZ \\n(.s
+. rR
+.\}
+..
+.\" NS %Q macro - Corporate or Foreign Author
+.\" NS qK string - Corporate or Foreign Author
+.\" NS qK register - Corporate or Foreign Author flag
+.de %Q
+.if \\n(aC==0 \{\
+. ie \\n(.$==0 .tm Usage: .%Q Corporate or Foreign Author (#\\n(.c)
+. el \{\
+. ds mN %Q
+. nr qK \\n(qK+1
+. nr Kl \\n(Kl+1
+. ds rS qK
+. ds A1 \\$1
+. ds A2 \\$2
+. ds A3 \\$3
+. ds A4 \\$4
+. ds A5 \\$5
+. ds A6 \\$6
+. ds A7 \\$7
+. ds A8 \\$8
+. ds A9 \\$9
+. nr fV \\n(.$
+. fV
+. \}
+.\}
+.if \\n(aC>\\n(aP \{\
+. nr aP \\n(aP+1
+. nr cF \\n(.f
+. nr cZ \\n(.s
+. rR
+.\}
+..
+.\" NS %R macro - [reference] report name
+.\" NS rK string - [reference] report name
+.\" NS rK register - [reference] report flag
+.de %R
+.if \\n(aC==0 \{\
+. ie \\n(.$==0 .tm Usage: .%R reference report (#\\n(.c)
+. el \{\
+. ds mN %R
+. nr rK \\n(rK+1
+. nr Kl \\n(Kl+1
+. ds rS rK
+. ds A1 \\$1
+. ds A2 \\$2
+. ds A3 \\$3
+. ds A4 \\$4
+. ds A5 \\$5
+. ds A6 \\$6
+. ds A7 \\$7
+. ds A8 \\$8
+. ds A9 \\$9
+. nr fV \\n(.$
+. fV
+. \}
+.\}
+.if \\n(aC>\\n(aP \{\
+. nr aP \\n(aP+1
+. nr cF \\n(.f
+. nr cZ \\n(.s
+. rR
+.\}
+..
+.\" NS %T macro - reference title
+.\" NS tK string - reference title
+.\" NS tK register - reference title flag
+.de %T
+.if \\n(aC==0 \{\
+. ie \\n(.$==0 .tm Usage: .%T (#\\n(.c)
+. el \{\
+. ds mN %T
+. if \\n(rS>0 \{\
+. nr tK \\n(tK+1
+. nr Kl \\n(Kl+1
+. ds rS tK
+. \}
+. ds A1 \\$1
+. ds A2 \\$2
+. ds A3 \\$3
+. ds A4 \\$4
+. ds A5 \\$5
+. ds A6 \\$6
+. ds A7 \\$7
+. ds A8 \\$8
+. ds A9 \\$9
+. nr fV \\n(.$
+. fV
+. \}
+.\}
+.if \\n(aC>\\n(aP \{\
+.\" . ie \\n(jS==1 \{\
+.\" . nr cF \\n(.f
+.\" . nr cZ \\n(.s
+.\" . ds qL \&\\*(Lq\\*(rA
+.\" . ds qR \&\\*(Rq\f\\n(cF\s\\n(cZ
+.\" . En \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
+.\" . \}
+.\" . el \{\
+. nr aP \\n(aP+1
+. nr cF \\n(.f
+. nr cZ \\n(.s
+. ie \\n(rS==0 \{\
+. as b1 \&\\*(eM
+. nR
+. \}
+. el .rR
+.\" . \}
+.\}
+..
+.\" NS %V macro - reference volume
+.\" NS vK string - reference volume
+.\" NS vK register - reference volume flag
+.de %V
+.if \\n(aC==0 \{\
+. ie \\n(.$==0 .tm Usage: .%V Volume , ... \\*(Pu (#\\n(.c)
+. el \{\
+. ds mN %V
+. nr vK \\n(vK+1
+. nr Kl \\n(Kl+1
+. ds rS vK
+. aV \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
+. \}
+.\}
+.if \\n(aC>\\n(aP \{\
+. nr aP \\n(aP+1
+. nr cF \\n(.f
+. nr cZ \\n(.s
+. rR
+.\}
+..
+.\" NS rR macro - reference recursion routine
+.\" NS jM local register
+.\" NS jN local register
+.de rR
+.hy 0
+.nr jM \\n(C\\n(aP
+.ie \\n(jM==1 \{\
+.\" . as b1 \&\f\\n(cF\s\\n(cZ
+. ie "\\*(A\\n(aP"Tn" \{\
+. nN
+. \}
+. el \{\
+. if \\n(aC>8 .tm Usage: \\*(mN - maximum 8 arguments (#\\n(.c)
+. aI rR 1
+. \\*(A\\n(aP
+. \}
+.\}
+.el \{\
+. nr jN \\n(aP
+. ie \\n(jM==2 .as b1 \&\\*(A\\n(aP
+. el .as b1 \&\\*(A\\n(aP
+.\" . el .as b1 \&\f\\n(cF\s\\n(cZ\\*(A\\n(aP\fP\s0
+. ie \\n(aC==\\n(aP \{\
+.\" . as b1 \&\f\\n(cF\s\\n(cZ
+. rD
+. \}
+. el \{\
+. nr aP \\n(aP+1
+. as b1 \&\\*(S\\n(jN
+. rR
+. \}
+.\}
+.rr jM jN
+..
+.\" NS rD macro - save b1 buffer in to appropriate name
+.de rD
+.as \\*(rS \\*(b1
+.ds b1
+.ds rS
+.aY
+..
+.\" NS Hf macro - source include header files.
+.de Hf
+.Pp
+File:
+.Pa \\$1
+.Pp
+.nr cF \\n(.f
+.nr cZ \\n(.s
+.ie t \{\
+\&\\*(lI
+.br
+.ta +9n 18n 27n 36n 45n 54n 63n 72n
+.\}
+.el \{\
+.ta +8n 16n 24n 32n 40n 48n 56n 64n 72n
+.\}
+.nf
+.so \\$1
+.fi
+.ft \\n(cF
+.fz \\n(cZ
+.Pp
+..
+.\" NS An macro - author name
+.\" NS aN register
+.nr aN 0
+.de An
+.if \\n(nY==1 \{\
+. ie \\n(aN==1 \{\
+. br
+. \}
+. el \{\
+. nr aN 1
+. \}
+.\}
+.if \\n(aC==0 \{\
+. ie \\n(.$==0 .tm Usage: .An author_name ... \\*(Pu (#\\n(.c)
+. el \{\
+. ds mN An
+. aV \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
+. \}
+.\}
+.if \\n(aC>\\n(aP \{\
+. nr aP \\n(aP+1
+. nr cF \\n(.f
+. nr cZ \\n(.s
+. nR
+.\}
+..
+.\" NS Sf macro -defunct
+.de Sf
+.tm .Sf defunct, use prefix or Ns
+..
+.ds rV "function returns the value 0 if successful; otherwise the value -1 is returned and the global variable \\*(vAerrno\fP is set to indicate the error.
+.\" Ns Rv macro - return values
+.\" Ns rV string - standard return message
+.de Rv
+.ie \\n(.$==0 \{\
+.tm Usage: .Rv [-std] (#\\n(.c)
+.\}
+.el \{\
+. ds mN Rv
+.\" . nr aP 0
+.\" . nr lR \\n(lR+1
+.\" . ds A1 \\$2
+.\" . ds A2 \\$3
+.\" . ds A3 \\$4
+.\" . ds A4 \\$5
+.\" . ds A5 \\$6
+.\" . ds A6 \\$7
+.\" . ds A7 \\$8
+.\" . ds A8 \\$9
+.\" . nr fV \\n(.$-1
+. if "\\$1"-std" \{\
+. nr cH \\*(cH
+. if (\\n(cH<2):(\\n(cH>3) .tm Usage: .Rv -std sections 2 and 3 only
+. br
+\&The
+.Fn \\$2
+\&\\*(rV
+. \}
+.\}
+..
diff --git a/gnu/usr.bin/groff/tmac/tmac.doc.old b/gnu/usr.bin/groff/tmac/tmac.doc.old
new file mode 100644
index 0000000..df44cc3
--- /dev/null
+++ b/gnu/usr.bin/groff/tmac/tmac.doc.old
@@ -0,0 +1,1858 @@
+.\"
+.\" Copyright (c) 1990 The Regents of the University of California.
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)tmac.doc.old 5.2 (Berkeley) 3/13/91
+.\" Slightly modified by jjc@jclark.com to work with groff as well.
+.\"
+.\" Assume nroff on crt's only if cR==1
+.if n .nr cR 1
+.\" STRING CONSTANTS
+.\" DITROFF
+.if t \{\
+.\" Address Style
+.ds aD \fI
+.\" Argument Reference Style
+.ds aR \f(CO
+.\" Interactive Comand Modifier (flag)
+.ds cM \f(CB
+.\" Emphasis (in the English sense - usually italics)
+.ds eM \fI
+.\" Errno Style
+.ds eR \fC
+.\" Environment Variable Style
+.ds eV \fC
+.\" Command Line Flag Style
+.ds fL \f(CB
+.\" Header String Style
+.ds Hs \fR
+.\" Interactive Command Style
+.ds iC \f(CB
+.\" Literal Style
+.ds lI \fC
+.\" Left Parenthesis Style
+.ds lP \fR\|(\|\fP
+.\" Right Parenthesis Style
+.ds rP \fR\|)\|\fP
+.\" Options Open Bracket Style
+.ds lB \fR\^[\^\fP
+.\" Options Open Bracket Style
+.ds rB \fR\^]\fP
+.\" Name (subject of manpage) Style
+.ds nM \f(CB
+.\" Pathname Style
+.ds pA \fC
+.\" Accepted punctuation string for -mdoc syntax
+.ds Pu \fR[.,:;(\^)[\^]\fR]
+.\" Section Header Style
+.ds Sp \s12\fB
+.\" .ds sT \s-2\fR
+.\" Symbolic Emphasis (boldface)
+.ds sY \f(CB
+.\" Generic Variable Style
+.ds vA \fI
+.\" Volume Title Style
+.ds Vs \fR
+.\" Cross Reference STyle (man page only)
+.ds xR \fC
+.\" Math *
+.tr *\(**
+.\}
+.\" NROFF
+.if n \{\
+.\" Address Style
+.ds aD \fI
+.\" Argument Reference Style
+.ds aR \fI
+.\" Interactive Command Modifier (flag)
+.ds cM \fB
+.\" Emphasis (in the English sense - usually italics)
+.ds eM \fI
+.\" Errno Style
+.ds eR \fR
+.\" Environment Variable Style
+.ds eV \fR
+.\" Command Line Flag Style
+.ds fL \fB
+.\" Header String Style
+.ds Hs \fR
+.\" Interactive Command Style
+.ds iC \fB
+.\" Literal Style
+.ds lI \fR
+.\" Left Parenthesis Style
+.ds lP \fR\|(\fP
+.\" Right Parenthesis Style
+.ds rP \fR\|)\fP
+.\" Options Open Bracket Style
+.ds lB \fR\|[\|\fP
+.\" Options Open Bracket Style
+.ds rB \fR\|]\fP
+.\" Name (subject of manpage) Style
+.ds nM \fB
+.\" Pathname Style
+.ds pA \fI
+.\" Accepted punctuation string for -mdoc syntax
+.ds Pu [.,;:()[]]
+.\" Section Header Style
+.ds Sp \s12\fB
+.\" .ds sT \s-2\fR
+.\" .ds sT \s-2\fR
+.\" Symbol, Mode or Mask Style
+.ds sY \fB
+.\" Generic Variable Style
+.ds vA \fI
+.\" Volume Title Style
+.ds Vs \fR
+.\" Cross Reference Style (man page only)
+.ds xR \fR
+.\}
+.\" INDENTS - Subheaders(sI), Text(Ti) between Section Headers and Subsects
+.if t \{\
+. nr sI \w'\fC,'u*5
+. nr Ti \n(sIu
+.\}
+.if n \{\
+. nr sI .5i
+. nr Ti .5i
+.\}
+.\" Flags for macros names which are used only for .Ds
+.nr dI 6n
+.nr dC 1
+.nr dL 1
+.nr dR 1
+.\" INDENT WIDTHS (for Lists)
+.\" Width Needed for Address Tag (indented amount)
+.nr Ad 12n
+.\" Angle Quote Width
+.nr Aq 12n
+.\" Width Needed for Argument
+.nr Ar 12n
+.\" Width Needed for Column offset
+.nr Cl 15n
+.\" Width neeeded for Interactive Command Modifier
+.nr Cm 10n
+.\" Width Needed for Complex Expressions
+.nr Cx 20n
+.\" Indent Width Needed for Display (right and left margins)
+.nr Ds 6n
+.\" Double Quote Width
+.nr Dq 12n
+.\" tI is dependent on Ds and used by .Dp
+.nr tI \n(Dsu
+.\" Width Needed for Display
+.nr Em 10n
+.\" Width Needed for Errno Types
+.nr Er 15n
+.\" Width Needed for Environment Variables
+.nr Ev 15n
+.\" Width Needed for Example Indent
+.nr Ex 10n
+.\" Width Needed for Flag
+.nr Fl 10n
+.\" Width Needed for Function
+.nr Fn 16n
+.\" Width neeeded for Interactive Command Name
+.nr Ic 10n
+.\" Width Needed for Constant
+.nr Li 16n
+.\" Width Needed for Math Symbol ? not sure if needed
+.nr Ms 6n
+.\" Width Needed for Name
+.nr Nm 10n
+.\" Width Needed for Option Begin
+.nr Ob 14n
+.\" Width Needed for Option End
+.nr Oe 14n
+.\" Width Needed for Option (one line)
+.nr Op 14n
+.\" Width Needed for Pathname
+.nr Pa 32n
+.\" Parenthesis Quote Width
+.nr Pq 12n
+.\" Single Quote Width
+.nr Sq 12n
+.\" Width Needed for Symbols, Modes or Masks
+.nr Sy 6n
+.\" Width needed for default or unknown text width
+.nr Tx 22n
+.\" Width Needed for Generic Variable
+.nr Va 12n
+.\" Width Needed for Cross Reference, should the cross ref be annotated.
+.nr Xr 10n
+.\" PARAGRAPH SPACE
+.if t \{\
+. nr Pp .5v
+.\}
+.if n \{\
+. nr Pp 1v
+.\}
+.\" PAGE LAYOUT
+.\" .Li Tagged Paragraph Style - zero if break on oversized tag
+.\" one if add em space and continue filling line.
+.nr tP 0
+.\" Page Layout Macro
+.de pL
+.\" DITROFF
+.ie t \{\
+.\" Header Margin
+. nr Hm .5i
+.\" Footer Margin
+. nr Fm .5i
+.\" Line length
+. nr ll 5.5i
+.\" Line length
+. ll 5.5i
+.\" Title length
+. nr lt 5.5i
+.\" Title length
+. lt 5.5i
+.\" Page offset
+. nr po 1.56i
+.\" Page offset
+. po 1.56i
+.\" Vertical space distance (from Section headers/Lists/Subsections)
+. nr vV .5v
+.\" em space
+. ds tP \|\|\|\|\|\|
+.\}
+.el \{\
+.\" Line length
+. nr ll 78n
+. ll 78n
+.\" Title length
+. nr lt 78n
+.\" Title length
+. lt 78n
+.\" Page offset
+. nr po 0i
+.\" Page offset
+. po 0i
+.\" Vertical space distance (from Section headers/Lists/Subsections)
+. nr vV 1v
+.\" em space
+. ds tP \0\0
+.\" Test for crt
+. ie \\n(cR .nr Hm 0
+. el .nr Hm .5i
+.\" Footer Margin
+. nr Fm .5i
+.\}
+..
+.\" Adjustment mode
+.if n \{\
+.ad l
+.na
+..
+.\}
+.\" PREDEFINED STRINGS
+.if t \{\
+. ds <= \(<=
+. ds >= \(>=
+. ds Lq \&``
+. ds Rq \&''
+. ds ua \(ua
+. ds aa \(aa
+. ds ga \(ga
+. ds sR \(aa
+. ds sL \(ga
+.\}
+.if n \{\
+. ds <= \&<\&=
+. ds >= \&>\&=
+. ds Rq ''
+. ds Lq ``
+. ds ua ^
+. ds aa '
+. ds ga `
+. ds sL `
+. ds sR '
+.\}
+.\" Note: The distances from the bottom or top of the page are set
+.\" in headers (macro .hK): to -1.25 for troff, and -1.167 for nroff
+.\" bottoms, and top is 0.
+.\"
+.\" .Dt Document/manpage_title section/chapter volume
+.\" The \{ and \} is necessary as roff doesn't nest if-elses
+.\" properly, especially with .ds.
+.\" TODO: separate Dt into Dt, Ch and Vt for supp docs.
+.de Dt
+.ds dT UNTITLED
+.ds vT Local
+.ds cH Null
+.\" Volume and Section Number or Chapter Number
+.if !"\\$1"" .ds dT \\$1
+.if !"\\$2"" \{\
+. ds cH \\$2
+. if "\\$3"" \{\
+. \" Volume Title if none given
+. if \\$2>=1 .if \\$2<=8 \{\
+. ds vT FreeBSD Reference Manual
+. if \\$2>1 .if \\$2<6 .ds vT FreeBSD Programmer's Manual
+. if "\\$2"8" .ds vT FreeBSD System Manager's Manual
+. \}
+. if "\\$2"unass" .ds vT DRAFT
+. if "\\$2"draft" .ds vT DRAFT
+. if "\\$2"paper" .ds vT Null
+. \}
+.\}
+.if !"\\$3"" \{\
+. \" Volume Title if given
+. if "\\$3"USD" .ds vT UNIX User's Supplementary Documents
+. if "\\$3"PS1" .ds vT UNIX Programmers's Supplementary Documents
+. if "\\$3"AMD" .ds vT UNIX Ancestral Manual Documents
+. if "\\$3"SMM" .ds vT UNIX System Manager's Manual
+. if "\\$3"URM" .ds vT UNIX Reference Manual
+. if "\\$3"PRM" .ds vT UNIX Programmers's Manual
+. if "\\$3"IND" .ds vT UNIX Manual Master Index
+. if "\\$3"CON" .ds vT UNIX Contributed Software Manual
+. if "\\$3"IMP" .ds vT UNIX Implementation Notes
+. if "\\$3"HOW" .ds vT UNIX How Pocket Manual
+. if "\\$3"LOCAL" .ds vT UNIX Local Manual
+. if "\\*(vT"Local" .ds vT \\$3
+.\}
+..
+.\"
+.\" .Os Operating System/Standard and Release or Version Number
+.\"
+.de Os
+.ds oS Null
+.if "\\$1"" \{\
+. ds oS \fIBSD Experimental\fP
+.\" . ds oS (\fIBag o' Bits\fP)
+.\}
+.if "\\$2"" \{\
+. ds o1 Non-Null
+.\}
+.if "\\$1"ATT" \{\
+. ds oS AT&T
+. if "\\$2"" .as oS \0UNIX
+. if "\\$2"7th" .as oS \07th Edition
+. if "\\$2"7" .as oS \07th Edition
+. if "\\$2"III" .as oS \0System III
+. if "\\$2"3" .as oS \0System III
+. if "\\$2"V" .as oS \0System V
+. if "\\$2"V.2" .as oS \0System V Release 2
+. if "\\$2"V.3" .as oS \0System V Release 3
+. if "\\$2"V.4" .as oS \0System V Release 4
+.\}
+.if "\\$1"BSD" \{\
+. if "\\$2"3" .ds oS 3rd Berkeley Distribution
+. if "\\$2"4" .ds oS 4th Berkeley Distribution
+. if "\\$2"4.1" .ds oS 4.1 Berkeley Distribution
+. if "\\$2"4.2" .ds oS 4.2 Berkeley Distribution
+. if "\\$2"4.3" .ds oS 4.3 Berkeley Distribution
+. if "\\$2"4.3+" .ds oS 4.3+tahoe Berkeley Distribution
+.\}
+.if "\\*(oS"Null" .ds oS \\$1
+.if "\\*(o1"Non-Null" .as oS \0\\$2
+.rm o1
+..
+.\"
+.\" Standards
+.\"
+.\" .de St
+.\" .ds sT Null
+.\" .if "\\$1"POSIX" \{\
+.\" . ds sT IEEE Standard POSIX
+.\" . if \\$2 .as sT \0\\$2
+.\" .\}
+.\" .if "\\$1"ANSI" \{\
+.\" . ds sT ANSI Standard
+.\" . if \\$2 .as sT \0\\$2
+.\" .\}
+.\" .if "\\$1"ISO" \{\
+.\" . ds sT ISO Standard
+.\" . if \\$2 .as sT \0\\$2
+.\" .\}
+.\" .if "\\*(sT"Null" .ds sR \\$3
+.\" ..
+.\"
+.\" .de Gp
+.\" .ie !"\\$1"" .ds gP \&\\$1 \\$2 \\$3 \\$4 \\$5
+.\" .el .ds gP Null
+.\" ..
+.\"
+.\"
+.de Dd
+.nr aa 0
+.ie \\n(.$>0 \{\
+. ie \\n(.$<4 \{\
+. ds dD \\$1 \\$2 \\$3
+. \}
+. el .tm Usage: .Dd Month Day, Year (e.g July 4, 1977).
+.\}
+.el \{\
+. ds dD Epoch
+.\}
+..
+.\"
+.\" House Keeping Macro - Make sense of dT, cH, vT, sT, gP and dS
+.\" TODO: Try to get else's for efficiency
+.\" TODO: GET RID OF .wh -1.167i (its in v7)
+.\"
+.\"
+.de hK
+.nr % 1
+.ds hT \\*(dT
+.if !"\\*(cH"Null" \{\
+. ie !"\\*(gP"Null" .as hT \|(\|\\*(cH\\*(gP\|)
+. el .as hT \\|(\\|\\*(cH\\|)
+.\}
+.if "\\*(cH"Null" .if !"\\*(gP"Null" .as hT \&\|(\|\\*(gP\|)
+.if t \{\
+. wh 0 hM
+. wh -1.25i fM
+.\}
+.if n \{\
+. ie \\n(cR \{\
+. hM
+. wh -0v fM
+. \}
+. el \{\
+. wh 0 hM
+. wh -1.167i fM
+. \}
+.\}
+.if n \{\
+. if \\n(nl==0:\\n(nl==-1 'bp
+.\}
+.if t 'bp
+.em lM
+..
+.\" Header Macro
+.\"
+.de hM
+.ev 1
+.pL
+.if !\\n(cR 'sp \\n(Hmu
+.tl @\\*(Hs\\*(hT\fP@\\*(Vs\\*(vT\fP@\\*(Hs\\*(hT\fP@
+'sp \\n(Hmu
+.ev
+..
+.\"
+.de fM
+.ev 1
+.pL
+.if !\\n(cR \{\
+' sp \\n(Fmu
+. tl @\\*(Hs\\*(oS\fP@\\*(Vs\\*(dD\fP@%@
+' bp
+.\}
+.if \\n(cR \{\
+.\" . tl @\\*(Hs\\*(oS\fP@\\*(Vs\\*(dD\fP@%@
+.\" ' bp
+.\}
+.ev
+..
+.de lM
+.fl
+.if \\n(cR \{\
+. fM
+. pl \\n(nlu
+.\}
+..
+.de Pp
+.sp \\n(Ppu
+.ne 2
+.ns
+..
+.de Lp
+.Pp
+..
+.de LP
+.tm Not a \-mdoc command: .LP
+..
+.de PP
+.tm Not a \-mdoc command: .PP
+..
+.de pp
+.tm Not a \-mdoc command: .pp
+..
+.de Co
+.tm Not a \-mdoc command: .Co
+..
+.nr z. 1
+.nr z, 1
+.nr z: 1
+.nr z; 1
+.nr z) 1
+.nr z( 1
+.nr z[ 1
+.nr z] 1
+.\" This is disgusting, troff not parse if stmt properly
+.nr z1 0
+.nr z2 0
+.nr z3 0
+.nr z4 0
+.nr z5 0
+.nr z6 0
+.nr z7 0
+.nr z8 0
+.nr z9 0
+.nr z0 0
+.nr z# 0
+.\"
+.de Ad
+.ie \\n(.$==0 \{\
+. tm Usage: .Ad address [...] \\*(Pu
+.\}
+.el \{\
+. ds sV \\*(aD
+. nr cF \\n(.f
+. ie "\\*(iM"" .ds f1 \&\\*(sV
+. el .as f1 \&\\*(sV
+. nB \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
+. ft \\n(cF
+.\}
+..
+.\"
+.\" Command Line Argument Macro
+.\"
+.de Ar
+.ie \\n(.$==0 \{\
+. ie !"\\*(iM"" .as f1 \&[\|\\*(aRfile\ ...\fP\|]
+. el \&[\|\\*(aRfile\ ...\fP\|]
+.\}
+.el \{\
+. ds sV \\*(aR
+. nr cF \\n(.f
+. ie "\\*(iM"" .ds f1 \&\\*(sV
+. el .as f1 \&\\*(sV
+. nB \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
+. ft \\n(cF
+.\}
+..
+.\"
+.de Em
+.ie \\n(.$==0 \{\
+. tm Usage: .Em text ... \\*(Pu
+.\}
+.el \{\
+. ds sV \\*(eM
+. nr cF \\n(.f
+. ie "\\*(iM"" .ds f1 \&\\*(sV
+. el .as f1 \&\\*(sV
+. nB \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
+. ft \\n(cF
+.\}
+..
+.\"
+.de Er
+.ie \\n(.$==0 \{\
+. tm Usage: .Er ERRNOTYPE ... \\*(Pu
+. \}
+.el \{\
+. ds sV \\*(eR
+. nr cF \\n(.f
+. ie "\\*(iM"" .ds f1 \&\\*(sV
+. el .as f1 \&\\*(sV
+. nB \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
+. ft \\n(cF
+.\}
+..
+.\"
+.de Ev
+.ie \\n(.$==0 \{\
+. tm Usage: .Ev ENVIRONMENT_VARIABLE(s) ... \\*(Pu
+. \}
+.el \{\
+. ds sV \\*(eV
+. nr cF \\n(.f
+. ie "\\*(iM"" .ds f1 \&\\*(sV
+. el .as f1 \&\\*(sV
+. nB \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
+. ft \\n(cF
+.\}
+..
+.\"
+.\" Flag Name Macro
+.\"
+.de Fl
+.ie \\n(.$==0 \{\
+. ie !"\\*(iM"" .as f1 \&\\*(fL\-\fP
+. el \&\\*(fL\-\fP
+.\}
+.el \{\
+. nr rZ 0
+. sW \\$1
+. if (\\n(sW==1&\\n(.$==1) .rZ \\$1
+. ds sV \\*(fL
+. nr cF \\n(.f
+. ie \\n(rZ \{\
+. ie "\\*(iM"" .ds f1 \&\\*(sV\-\f\\n(cF\\$1
+. el \&\\*(sV\-\f\\n(cF\\$1
+. \}
+. el \{\
+. ie "\\*(iM"" .ds f1 \&\\*(sV
+. el .as f1 \&\\*(sV
+. fB \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
+. ft \\n(cF
+. \}
+.\}
+..
+.\" Interactive Commands Macro
+.\"
+.de Ic
+.ie \\n(.$==0 \{\
+. tm Usage: .Ic Interactive Commands(s) ... \\*(Pu
+.\}
+.el \{\
+. ds sV \\*(iC
+. nr cF \\n(.f
+. ie "\\*(iM"" .ds f1 \&\\*(sV
+. el .as f1 \&\\*(sV
+. nB \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
+. ft \\n(cF
+.\}
+..
+.\"
+.\" Interactive Command Modifiers (flags)
+.\"
+.de Cm
+.ie \\n(.$==0 \{\
+. tm Usage: .Cm Interactive Command Modifier(s) ... \\*(Pu
+.\}
+.el \{\
+. ds sV \\*(cM
+. nr cF \\n(.f
+. ie "\\*(iM"" .ds f1 \&\\*(sV
+. el .as f1 \&\\*(sV
+. nB \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
+. ft \\n(cF
+.\}
+..
+.\"
+.de Li
+.ie \\n(.$==0 \{\
+. tm Usage: .Li literal ... \\*(Pu
+. \}
+.el \{\
+. ds sV \\*(lI
+. nr cF \\n(.f
+. ie "\\*(iM"" .ds f1 \&\\*(sV
+. el .as f1 \&\\*(sV
+. nB \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
+. ft \\n(cF
+.\}
+..
+.\" If in nroff or any other case where the default font
+.\" is constant width, and literal means zilch, single quote instead.
+.ie n \{\
+.de Ql
+. ie \\n(.$==0 \{\
+. tm Usage: .Ql literal ... \\*(Pu
+. \}
+. el \{\
+. Sq \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
+. \}
+..
+.\}
+.el \{\
+.de Ql
+. ie \\n(.$==0 \{\
+. tm Usage: .Ql literal ... \\*(Pu
+. \}
+. el \{\
+. Li \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
+. \}
+..
+.\}
+.\"
+.de Nm
+.ie \\n(.$==0 \{\
+. if "\\*(n1"" .tm Usage: .Nm Name(s) ... \\*(Pu
+. ie !"\\*(iM"" .as f1 \&\\*(nM\\*(n1\\$1\fP
+. el \&\\*(nM\\*(n1\\$1\fP
+.\}
+.el \{\
+. ds sV \\*(nM
+. nr cF \\n(.f
+. if \\n(nS \{\
+. rs
+. in -\\n(iSu
+. ie \\n(nS>1 .br
+. el \{\
+. sW \\$1
+. nr iS ((\\n(sW+1)*\\n(fW)u
+. \}
+. in +\\n(iSu
+. ti -\\n(iSu
+. nr nS \\n(nS+1
+. \}
+. if "\\*(n1"" .ds n1 \\$1
+. ie "\\*(iM"" .ds f1 \&\\*(sV
+. el .as f1 \&\\*(sV
+. nB \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
+. ft \\n(cF
+.\}
+..
+.\"
+.de Pa
+.ie \\n(.$==0 \{\
+\&\\*(pA~\fP
+.\}
+.el \{\
+. ds sV \\*(pA
+. nr cF \\n(.f
+. ie "\\*(iM"" .ds f1 \&\\*(sV
+. el .as f1 \&\\*(sV
+. nB \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
+. ft \\n(cF
+.\}
+..
+.\"
+.de Sy
+.ie \\n(.$==0 \{\
+. tm Usage: .Sy Symbolic Text ... \\*(Pu
+. \}
+.el \{\
+. ds sV \\*(sY
+. nr cF \\n(.f
+. ie "\\*(iM"" .ds f1 \&\\*(sV
+. el .as f1 \&\\*(sV
+. nB \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
+. ft \\n(cF
+.\}
+..
+.\"
+.de Ms
+.ie \\n(.$==0 \{\
+. tm Usage: .Ms Math Symbol ... \\*(Pu
+. \}
+.el \{\
+. ds sV \\*(sY
+. nr cF \\n(.f
+. ie "\\*(iM"" .ds f1 \&\\*(sV
+. el .as f1 \&\\*(sV
+. nB \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
+. ft \\n(cF
+.\}
+..
+.\"
+.de Va
+.ie \\n(.$==0 \{\
+. tm Usage: .Va variable_name(s) ... \\*(Pu
+.\}
+.el \{\
+. ds sV \\*(vA
+. nr cF \\n(.f
+. ie "\\*(iM"" .ds f1 \&\\*(sV
+. el .as f1 \&\\*(sV
+. nB \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
+. ft \\n(cF
+.\}
+..
+.\"
+.de nB
+.hy 0
+.if \\n(.$==0 .tm Usage error: called with empty arguments (empty quotes)?
+.ie \\n(.$>1 \{\
+. rZ \\$1
+. ie \\n(rZ .as f1 \&\f\\n(cF\\$1\fP
+. el .as f1 \&\\$1
+. rZ \\$2
+. if !\\n(rZ \{\
+. ie !"\\*(iM""\{\
+.\" I surrender
+. if "\\*(iM"Tp" .as f1 \&\ \&
+. if "\\*(iM"Dp" .as f1 \&\ \&
+. if "\\*(iM"Op" .as f1 \&\ \&
+. if "\\*(iM"Cx" .as f1 \&\ \&
+. if "\\*(iM"Dq" .as f1 \& \&
+. if "\\*(iM"Sq" .as f1 \& \&
+. if "\\*(iM"Pq" .as f1 \& \&
+. if "\\*(iM"Aq" .as f1 \& \&
+. \}
+. el .as f1 \& \&
+. \}
+. nB \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
+.\}
+.el \{\
+. rZ \\$1
+. ie \\n(rZ .as f1 \&\f\\n(cF\\$1
+. el .as f1 \&\\$1\f\\n(cF
+. if "\\*(iM"" \{\&\\*(f1
+. ds f1
+. \}
+. hy
+.\}
+..
+.de fB
+.hy 0
+.if \\n(.$==0 .tm Usage error: called with empty arguments (empty quotes)?
+.ie \\n(.$>1 \{\
+. rZ \\$1
+. ie \\n(rZ .as f1 \&\f\\n(cF\\$1\fP
+. el \{\
+. ie "\\$1"-" .as f1 \&\-\-
+. el .as f1 \&\-\\$1
+. \}
+. rZ \\$2
+. if !\\n(rZ \{\
+. ie !"\\*(iM""\{\
+.\" I surrender
+. if "\\*(iM"Tp" .as f1 \&\ \&
+. if "\\*(iM"Dp" .as f1 \&\ \&
+. if "\\*(iM"Op" .as f1 \&\ \&
+. if "\\*(iM"Cx" .as f1 \&\ \&
+. if "\\*(iM"Dq" .as f1 \& \&
+. if "\\*(iM"Sq" .as f1 \& \&
+. if "\\*(iM"Pq" .as f1 \& \&
+. if "\\*(iM"Aq" .as f1 \& \&
+. \}
+. el .as f1 \& \&
+. \}
+. fB \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
+.\}
+.el \{\
+. rZ \\$1
+. ie \\n(rZ .as f1 \&\f\\n(cF\\$1
+. el \{\
+. ie "\\$1"-" .as f1 \&\-\-\f\\n(cF
+. el .as f1 \&\-\\$1\f\\n(cF
+. \}
+. if "\\*(iM"" \{\&\\*(f1
+. ds f1
+. \}
+. hy
+.\}
+..
+.\"
+.\" Single quoted Items
+.\" eF, sB g[0-9] and f2
+.de Sq
+.nr eF 0
+.ie \\n(.$==0 \{\
+. ie "\\*(iM"" \&\\*(sL\&\\*sR
+. el .as f1 \&\\*(sL\&\\*(sR
+.\}
+.el \{\
+. ie "\\*(iM"" \{\
+. ds f1 \&\\*(sL
+. ds iM Sq
+. \}
+. el .as f1 \&\\*(sL
+. sB \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
+. ie \\n(eF>0 .\\*(g1 \\*(g2 \\*(g3 \\*(g4 \\*(g5 \\*(g6 \\*(g7 \\*(g8
+. el .as f1 \\*(g0
+. as f1 \\*(sR
+. if !"\\*(f2"" .as f1 \\*(f2
+. if "\\*(iM"Sq" \{\
+\&\\*(f1
+. ds f1
+. ds iM
+. \}
+. ds f2
+. rm g0 g1 g2 g3 g4 g5 g6 g7 g8 g9
+. nr eF 0
+.\}
+..
+.\"
+.\" Double quoted Items
+.de Dq
+.nr Ef 0
+.ie \\n(.$==0 \{\
+. ie "\\*(iM"" \&\\*(Lq\&\\*(Rq
+. el .as f1 \&\\*(Lq\&\\*(Rq
+.\}
+.el \{\
+. ie "\\*(iM"" \{\
+. ds f1 \&\\*(Lq
+. ds iM Dq
+. \}
+. el .as f1 \&\\*(Lq
+. Sb \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
+. ie \\n(Ef>0 .\\*(k1 \\*(k2 \\*(k3 \\*(k4 \\*(k5 \\*(k6 \\*(k7 \\*(k8
+. el .as f1 \\*(k0
+. as f1 \\*(Rq
+. if !"\\*(f4"" .as f1 \\*(f4
+. if "\\*(iM"Dq" \{\
+\&\\*(f1
+. ds f1
+. ds iM
+. \}
+. ds f4
+. rm k0 k1 k2 k3 k4 k5 k6 k7 k8 k9
+. nr Ef 0
+.\}
+..
+.\"
+.\" Parenthesis quoted Items
+.de Pq
+.nr pQ 0
+.ie \\n(.$==0 \{\
+. ie "\\*(iM"" \&(\&)
+. el .as f1 \&(\&)
+.\}
+.el \{\
+. ie "\\*(iM"" \{\
+. ds f1 \&(
+. ds iM Pq
+. \}
+. el .as f1 \&(
+. pB \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
+. ie \\n(pQ>0 .\\*(y1 \\*(y2 \\*(y3 \\*(y4 \\*(y5 \\*(y6 \\*(y7 \\*(y8
+. el .as f1 \\*(y0
+. as f1 \&)
+. if !"\\*(f3"" .as f1 \\*(f3
+. if "\\*(iM"Pq" \{\
+\&\\*(f1
+. ds f1
+. ds iM
+. \}
+. ds f3
+. rm y0 y1 y2 y3 y4 y5 y6 y7 y8 y9
+. nr pQ 0
+.\}
+..
+.\" eF, sB g[0-9] and f2
+.de sB
+.hy 0
+.ie \\n(.$==0 .tm Sick Logic: macro sB
+.el \{\
+. ie \\n(eF>=1 .nr eF \\n(eF+1
+. el \{\
+. mN \\$1
+. if \\n(mN .nr eF \\n(eF+1
+. \}
+. rZ \\$1
+. ie \\n(rZ .as f2 \\$1
+. el \{\
+. ie \\n(eF<1 .as g\\n(eF \\$1
+. el .as g\\n(eF \\$1
+. \}
+. if \\n(.$>1 \{\
+. rZ \\$2
+. if \\n(rZ==0 \{\
+. if \\n(eF<1 \{\
+. as g\\n(eF \& \&
+. \}
+. \}
+. sB \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
+. \}
+.\}
+..
+.de Sb
+.hy 0
+.ie \\n(.$==0 .tm Sick Logic: macro Sb
+.el \{\
+. ie \\n(Ef>=1 .nr Ef \\n(Ef+1
+. el \{\
+. mN \\$1
+. if \\n(mN .nr Ef \\n(Ef+1
+. \}
+. rZ \\$1
+. ie \\n(rZ .as f4 \\$1
+. el \{\
+. ie \\n(Ef<1 .as k\\n(Ef \\$1
+. el .as k\\n(Ef \\$1
+. \}
+. if \\n(.$>1 \{\
+. rZ \\$2
+. if \\n(rZ==0 \{\
+. if \\n(Ef<1 \{\
+. as k\\n(Ef \& \&
+. \}
+. \}
+. Sb \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
+. \}
+.\}
+..
+.de pB
+.hy 0
+.ie \\n(.$==0 .tm Sick Logic: macro pB
+.el \{\
+. ie \\n(pQ>=1 .nr pQ \\n(pQ+1
+. el \{\
+. mN \\$1
+. if \\n(mN .nr pQ \\n(pQ+1
+. \}
+. rZ \\$1
+. ie \\n(rZ .as f3 \\$1
+. el \{\
+. ie \\n(pQ<1 .as y\\n(pQ \\$1
+. el .as y\\n(pQ \\$1
+. \}
+. if \\n(.$>1 \{\
+. rZ \\$2
+. if \\n(rZ==0 \{\
+. if \\n(pQ<1 \{\
+. as y\\n(pQ \& \&
+. \}
+. \}
+. pB \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
+. \}
+.\}
+..
+.de aQ
+.hy 0
+.ie \\n(.$==0 .tm Bad Syntax: .Aq
+.el \{\
+. ie \\n(aQ>=1 .nr aQ \\n(aQ+1
+. el \{\
+. mN \\$1
+. if \\n(mN .nr aQ \\n(aQ+1
+. \}
+. rZ \\$1
+. ie \\n(rZ .as aZ \\$1
+. el \{\
+. ie \\n(aQ<1 .as a\\n(aQ \\$1
+. el .as a\\n(aQ \\$1
+. \}
+. if \\n(.$>1 \{\
+. rZ \\$2
+. if \\n(rZ==0 \{\
+. if \\n(aQ<1 \{\
+. as a\\n(aQ \& \&
+. \}
+. \}
+. aQ \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
+. \}
+.\}
+..
+.\" Angle Bracket Quoted Items
+.de Aq
+.nr aQ 0
+.ie \\n(.$==0 \{\
+. ie "\\*(iM"" \&<\&>
+. el .as f1 \&<\&>
+.\}
+.el \{\
+. ie "\\*(iM"" \{\
+. ds f1 \&<
+. ds iM Aq
+. \}
+. el .as f1 \&<
+. aQ \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8
+. ie \\n(aQ>0 .\\*(a1 \\*(a2 \\*(a3 \\*(a4 \\*(a5 \\*(a6 \\*(a7 \\*(a8
+. el .as f1 \\*(a0
+. as f1 \&>
+. if !"\\*(aZ"" .as f1 \\*(aZ
+. if "\\*(iM"Aq" \{\
+\&\\*(f1
+. ds f1
+. ds iM
+. \}
+. ds aZ
+. rm a0 a1 a2 a3 a4 a5 a6 a7 a8
+. nr aQ 0
+.\}
+..
+.\" macro Name test, return macro register value if true
+.if \n(.g .ig
+.de mN
+.nr mN 0
+.sW \\$1
+.if \\n(sW==2 \{\
+. if \\n(\\$1 .nr mN \\n(\\$1
+.\}
+..
+.if !\n(.g .ig
+.de mN
+.nr mN 0
+.if \A'\\$1' \{\
+. sW \\$1
+. if \\n(sW==2 \{\
+. if \\n(\\$1 .nr mN \\n(\\$1
+. \}
+.\}
+..
+.\" Punctuation test (using z registers), return 1 if true
+.if \n(.g .ig
+.de rZ
+.nr rZ 0
+.sW \\$1
+.if \\n(sW==1 \{\
+. if \\n(z\\$1==1 \{\
+. nr rZ 1
+. \}
+.\}
+..
+.if !\n(.g .ig
+.de rZ
+.nr rZ 0
+.if \A'\\$1' \{\
+. sW \\$1
+. if \\n(sW==1 \{\
+. if \\n(z\\$1==1 \{\
+. nr rZ 1
+. \}
+. \}
+.\}
+..
+.\"
+.\" sW returns number of characters in a string
+.if t \{\
+.nr fW \w'\fC,'
+.de sW
+.nr sW \w'\fC\\$1'
+.\}
+.if n \{\
+.nr fW \w'0'
+.de sW
+.nr sW \w'\\$1'
+.\}
+.ie \\n(sW>=\\n(fW \{\
+. ie \\n(sW%\\n(fW .nr sW (\\n(sW/\\n(fW)+1
+. el .nr sW \\n(sW/\\n(fW
+.\}
+.el .nr sW 0
+..
+.\" Option Expression -
+.\" TODO - add line overflow check (right!)
+.nr eP 0
+.ds e1
+.nr oE 0
+.nr hP 0
+.ds hP
+.nr Ep 0
+.de Op
+.hy 0
+.if "\\*(iM"" \{\
+. ds iM Op
+. ds f1 \&
+.\}
+.as f1 \&\\*(lB
+.\" .tm Op: \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
+.dO \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
+.ie !"\\$1"Cx" .oE
+.el .nr oE \\n(oE+1
+..
+.\"
+.\" just for mike, with every bite of garlic in mind (oops, i mean burp).
+.\" dO: go dOwn an argument vector and test each argument to see if
+.\" a macro name or punctuation. stash in respective place along
+.\" with its arguments.
+.nr oO 0
+.nr oP 0
+.nr aO 0
+.de dO
+.mN \\$1
+.ie \\n(mN \{\
+. if \\n(oP \{\
+. if \\n(hP \{\
+. nr oZ 1
+. oZ
+. Oz
+. \}
+. if \\n(e1==1 \{\
+.\\*(e1 \\*(e2 \\*(e3 \\*(e4 \\*(e5 \\*(e6 \\*(e7 \\*(e8 \\*(e9
+. \}
+. uO
+. if !(\\n(oO:\\n(aO) .as f1 \& \&
+. \}
+. ie "\\$1"Op" \{\
+. as f1 \&\\*(lB
+. nr aO \\n(aO+1
+. \}
+. el \{\
+. nr eP \\n(eP+1
+. ds e\\n(eP \\$1
+. nr e\\n(eP 1
+. \}
+.\}
+.el \{\
+.\" .tm dO: $1: \\$1: eP \\n(eP e[\\n(eP]: \\*(e\\n(ePEE
+. rZ \\$1
+. ie \\n(rZ \{\
+.\" .tm dO:rZ: $1: \\$1: eP \\n(eP e[\\n(eP]: \\*(e\\n(eP
+. nr hP \\n(hP+1
+. ds h\\n(hP \\$1
+. \}
+. el \{\
+.\" .tm dO:word $1: \\$1: eP \\n(eP e[\\n(eP]: \\*(e\\n(ePEE
+. if \\n(eP==0:\\n(e\\n(eP==1 .nr eP \\n(eP+1
+. if \\n(eZ .as e\\n(eP \& \&
+. as e\\n(eP " \&\\$1
+.\" . ds e\\n(eP \&\\$1
+. nr eZ \\n(eZ+1
+. \}
+.\}
+.nr oP 1
+.ie \\n(.$>1 \{\
+. dO \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
+.\}
+.el \{\
+. ie \\n(e1 \{\
+.\\*(e1 \\*(e2 \\*(e3 \\*(e4 \\*(e5 \\*(e6 \\*(e7 \\*(e8 \\*(e9
+. \}
+. el \{\
+. as f1 \\*(e1
+. \}
+.\}
+..
+.\" handle old style arguments such as the arg -Idir
+.\" in adb, .Oo is a toggle.
+.de Oo
+.ie \\n(oO .nr oO 0
+.el .nr oO 1
+..
+.\" stash punctuation
+.de oZ
+.if \\n(hP>=\\n(oZ \{\
+. nr eP \\n(eP+1
+. ds e\\n(eP \\*(h\\n(oZ
+. nr oZ \\n(oZ+1
+. oZ
+.\}
+..
+.\" clean up punctuation vector
+.de Oz
+.if \\n(hP>0 \{\
+. rm h\\n(hP
+. nr hP \\n(hP-1
+. Oz
+.\}
+..
+.\" uO: go back up created vector cleaning it up along the way
+.de uO
+.if \\n(eP>0 \{\
+. rm e\\n(eP
+. rr e\\n(eP
+. nr eP \\n(eP-1
+. nr oP 0
+. nr eZ 0
+. uO
+.\}
+..
+.\" option end
+.de oE
+.uO
+.ie \\n(hP \{\
+. as f1 \\*(rB\\*(h1\\*(h2\\*(h3
+. Oz
+. nr oZ 0
+.\}
+.el \{\
+. as f1 \\*(rB
+.\}
+.ie "\\*(iM"Op" \{\
+. if \\n(aO .aO
+.if t \{\
+. if (\\n(.lu-\\n(.ku-\\n(.ou-(2*\\n(fWu))<\w'\fC\\*(f1'u .br
+.\}
+.if n \{\
+. nr aa \w'\\*(f1'u
+.\" . nr qq \\n(.lu-\\n(.ku-\\n(.ou
+.\" \&aa == \\n(aa, f1==\\*(f1, qq==\\n(qq
+. if (\\n(.lu-\\n(.ku-\\n(.ou-\\n(aau)<=(8*\\n(fWu) .br
+.\}
+\&\\*(f1
+. ds iM
+. ds f1
+. hy
+.\}
+.el .nr oE \\n(oE-1
+..
+.de aO
+.as f1 \\*(rB
+.nr aO \\n(aO-1
+.if \\n(aO >0 .aO
+..
+.\"
+.de Xr
+.if \\n(.$<=1 \{\
+. ie \\n(.$==1 \{\
+. if !"\\*(iM"" .as f1 \&\\*(xR\\$1\fP
+. if "\\*(iM"" \&\\*(xR\\$1\fP
+. \}
+. el .tm Xr Usage: .Xr manpage_name [section#] \\*(Pu
+.\}
+.if \\n(.$==2 \{\
+. rZ \\$2
+. ie "\\*(iM"" \{\
+. ie \\n(rZ \&\\*(xR\\$1\fP\\$2
+. el \&\\*(xR\\$1\fP(\\$2)
+. \}
+. el \{\
+. ie \\n(rZ .as f1 \&\\*(xR\\$1\fP\\$2
+. el .as f1 \&\\*(xR\\$1\fP(\\$2)
+. \}
+.\}
+.if \\n(.$>=3 \{\
+. rZ \\$2
+. ie \\n(rZ \{\
+. ie !"\\*(iM"" .as f1 \&\\*(xR\\$1\fP\\$2\\$3\\$4\\$5\\$6\\$7\\$8
+. el \&\\*(xR\\$1\fP\\$2\\$3\\$4\\$5\\$6\\$7\\$8
+. \}
+. el \{\
+. rZ \\$3
+. ie \\n(rZ \{\
+. if !"\\*(iM"" \{\
+. as f1 \&\\*(xR\\$1\fP(\\$2)\\$3\\$4\\$5\\$6\\$7\\$8
+. \}
+. if "\\*(iM"" \{\
+\&\\*(xR\\$1\fP(\\$2)\\$3\\$4\\$5\\$6\\$7\\$8
+. \}
+. \}
+. el \{\
+. tm rZ = \\n(rZ the arg is \\$3
+. tm Xr-XX Usage: .Xr manpage_name [section#] \\*(Pu
+. \}
+. \}
+.\}
+..
+.\"
+.\"
+.de Ex
+.tm Ex defunct, Use .Dl: \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
+..
+.\" Display (one) Line of text.
+.de Dl
+.ie "\\*(iM"" \{\
+' ta .5i 1i 1.5i 2i 2.5i 3i 3.5i 4i 4.5i 5i 5.5i 6i 6.5i
+. in \\n(.iu+\\n(Dsu
+. mN \\$1
+. ie \\n(mN .\\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
+. el \{\
+. nr cF \\n(.f
+.\" Literal font is none specified
+\&\\*(lI\\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
+. ft \\n(cF
+. \}
+. in \\n(.iu-\\n(Dsu
+.\}
+.el \{\
+. mN \\$1
+. ie \\n(mN .\\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8
+. el \{\
+. nr cF \\n(.f
+. ds f1 \&\\*(lI\\&\\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8
+. as f1 \&\f\\n(cF
+. \}
+.\}
+..
+.\"
+.\"
+.\" user set Tagged Paragraph Width (used in both Dp and Tp)
+.de Tw
+.ie \\n(.$==0 \{\
+. nr aa 0
+.\}
+.el \{\
+. mN \\$1
+. ie \\n(sW>2 \{\
+. nr tW (\\n(sW+3)*\\n(fWu)
+. \}
+. el \{\
+. ie \\n(mN .nr tW \\n(mN
+. el .nr tW \\$1
+. \}
+. nr tF 1
+.\}
+..
+.\"
+.de Dw
+.Tw \\$1
+..
+.\"
+.de Di
+.ie \\n(.$==0 \{\
+. nr tI \\n(Dsu
+.\}
+.el \{\
+. sW \\$1
+. if \\n(sW>=2 \{\
+. nr tI \\$1u
+. \}
+. if \\n(sW<2 \{\
+. if "\\$1"L" \{\
+. nr tI 0
+. \}
+. \}
+.\}
+..
+.\" tagged paragraph
+.\" initialize baby stack variables
+.nr np 0
+.nr p1 0
+.ds s\n(np
+.\"
+.de Tp
+.ie "\\$1"" .pE p s np
+.el \{\
+. ds iM Tp
+. mN \\$1
+. ie \\n(tF \{\
+. ds tC Tw
+. nr tC 1
+. nr tF 0
+. \}
+. el \{\
+. if !"Tw"\\*(s\\n(np" \{\
+. ie \\n(mN \{\
+. ds tC \\$1
+. nr tW \\n(mN
+. \}
+. el \{\
+. ds tC Tx
+. nr tW \\n(Tx
+. \}
+. if !"\\*(tC"\\*(s\\n(np" .nr tC 1
+. \}
+. \}
+. sp \\n(vVu
+. if !\\n(cR .ne 2
+. if \\n(tC \{\
+. nr np \\n(np+1
+. nr p\\n(np \\n(tW
+. ds s\\n(np \\*(tC
+. nr tC 0
+. ds tC
+. in \\n(.iu+\\n(p\\n(npu
+. \}
+. ie \\n(mN \{\
+. ds f1
+. \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
+. if !"\\$1"Cx" .pT st p np
+. \}
+. el \{\
+. br
+. ev 1
+. fi
+. di Td
+\&\\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
+. br
+. di
+. ev
+. na
+. ds tD \\*(Td\\
+. pT di p np
+. \}
+.\}
+..
+.\"
+.\"
+.\" Complex Expression Macro
+.\"
+.\" TODO: add length across line boundary check (like Li)
+.de Cx
+.hy 0
+.ie \\n(.$==0 \{\
+. if "\\*(iM"Cx" \{\
+. ds iM
+. if \\n(oE .oE
+\&\\*(f1
+. ds f1
+. \}
+. if "\\*(iM"Tp" .pT st p np
+. if "\\*(iM"Dp" .pT st q mp
+.\}
+.el \{\
+. if "\\*(iM"" \{\
+. ds iM Cx
+. ds f1 \&
+. \}
+. mN \\$1
+.\" Here are the args: `\\$1' `\\$2' `\\$3' `\\$4'
+. ie \\n(mN .\\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
+. el \{\
+. as f1 \&\\$1
+. if \\n(.$>1 .Cx \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
+. \}
+.\}
+..
+.\" Prefix string in default font to content specified string
+.de Pf
+.Cx \\$1
+.\\$2 \\$3 \\$4 \\$5
+.Cx
+..
+.\" Suffix string in default font to content specified string
+.de Sf
+.Cx \\$1 \\$2
+.Cx \\$3
+.Cx
+..
+.\" Simple Option Begin
+.de Ob
+.hy 0
+.ie "\\*(iM"" \{\
+. ev 2
+. fi
+. di oB
+.\}
+.el \{\
+.tm shouldn't be here
+. as f1 \&[
+. mN \\$1
+. ie \\n(mN .\\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
+. el \{\
+. as f1 \&\\$1
+. if \\n(.$>1 .Oc \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
+. \}
+.\}
+..
+.de Oc
+.as f1 \&\\$1
+.if \\n(.$>1 .Oc \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
+..
+.de Oe
+.hy 0
+.ie "\\*(iM"" \{\
+. br
+. di
+. ev
+. ds bO \\*(oB\\
+\&[\\*(bO\&]
+.\}
+.el \{\
+. as f1 \&]
+.\}
+..
+.\" White space for Cx
+.de Ws
+.Cx \&\ \&
+..
+.\" tagged paragraph
+.\" initialize baby stack variables
+.nr mp 0
+.nr q1 0
+.ds r\n(np
+.\"
+.\" Complex Dp tag
+.de Dc
+.Dp Cx \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8
+..
+.\" Complex Tp tag
+.de Tc
+.Tp Cx \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8
+..
+.\" Tag with a flag and an argument with a space
+.de Ta
+.if "\\$2"" \{\
+. Tp Fl \\$1
+.\}
+.el \{\
+. Tp Fl \\$1
+. Cx \&\ \&
+. Ar \\$2 \\$3
+. Cx
+.\}
+..
+.de Da
+.Dp Cx Fl \\$1
+.Ws
+.Ar \\$2 \\$3
+.Cx
+..
+.de To
+.Tp Cx Fl \\$1
+.Ar \\$2 \\$3
+.Cx
+..
+.de Do
+.Dp Cx Fl \\$1
+.Ar \\$2 \\$3
+.Cx
+..
+.\" Blended tag toggle
+.de Bt
+.ie \\n(tP==0 .nr tP 1
+.el .nr tP 0
+..
+.\" Bullet paragraph
+.de Bu
+.Tp Sy \&\(bu
+..
+.\" Display tagged paragraph
+.de Dp
+.ie "\\$1"" \{\
+. pE q r mp
+. sp \\n(vVu
+.\}
+.el \{\
+. ds iM Dp
+. mN \\$1
+. ie \\n(tF \{\
+. ds tC Tw
+. nr tC 1
+. nr tF 0
+. \}
+. el \{\
+. if !"Tw"\\*(r\\n(mp" \{\
+. ie \\n(mN \{\
+. ds tC \\$1
+. nr tW \\n(mN
+. \}
+. el \{\
+. ds tC Tx
+. nr tW \\n(Tx
+. \}
+. if !"\\*(tC"\\*(r\\n(mp" .nr tC 1
+. \}
+. \}
+. if !\\n(cR .ne 2
+. if \\n(tC \{\
+. nr mp \\n(mp+1
+. nr q\\n(mp \\n(tW
+. ds r\\n(mp \\*(tC
+. nr tC 0
+. ds tC
+. ie \\n(tIu==\\n(Dsu .nr i\\n(mp \\n(Dsu
+. el \{\
+. nr i\\n(mp \\n(tIu
+. nr tI \\n(Dsu
+. \}
+. in \\n(.iu+\\n(i\\n(mpu
+. sp \\n(vVu
+. in \\n(.iu+\\n(\\q\\n(mpu
+. \}
+. ie \\n(mN \{\
+. \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
+. if !"\\$1"Cx" .pT st q mp
+. \}
+. el \{\
+. br
+. ev 1
+. fi
+. di Td
+\&\\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
+. br
+. di
+. ev
+. na
+. ds tD \\*(Td\\
+. pT di q mp
+. \}
+.\}
+..
+.\"
+.\" .pE number_stack string_stack counter
+.de pE
+.ie "\\$3"mp" \{\
+. in \\n(.iu-(\\n(\\$1\\n(\\$3u)-(\\n(i\\n(mpu)
+. rr i\\n(mp
+.\}
+.el .in \\n(.iu-\\n(\\$1\\n(\\$3u
+.\" .in \\n(.iu-\\n(\\$1\\n(\\$3u
+.if \\n(\\$3<=0 .tm Extraneous call .Tp or .Dp
+.rr \\$1\\n(\\$3
+.rm \\$2\\n(\\$3
+.nr \\$3 \\n(\\$3-1
+.ds iM
+..
+.\"
+.\" .pT [st or di] number_stack counter
+.de pT
+.ie "\\$1"st" \{\
+. nr bb \\n(\\$2\\n(\\$3u
+. ti -\\n(bbu
+. ie (\\n(\\$2\\n(\\$3u-2n)<=\w'\\*(f1'u \{\&\\*(f1\\*(tP
+. if \\n(tP==0 .br
+. \}
+. el \\*(f1\h'|\\n(\\$2\\n(\\$3u'\c
+.\}
+.el \{\
+. ti -\\n(\\$2\\n(\\$3u
+. ie (\\n(\\$2\\n(\\$3u-2n)<=\\n(dlu \{\&\\*(tD\\*(tP
+. if !\\n(tP .br
+. \}
+. el \\*(tD\h'|\\n(\\$2\\n(\\$3u'\c
+. if t 'ad
+.\}
+. ds iM
+. ds f1
+'fi
+..
+.\"
+.\" The new SH
+.\"
+.de Sh
+.\" set Sh state off, check for list state before calling indent (.In)
+.nr nS 0
+.nr sE 0
+.ie "\\$1"NAME" \{\
+.\" name state on, housekeep (headers & footers)
+. hK
+' in 0
+.\}
+.el \{\
+. if "\\$1"SYNOPSIS" .nr nS 1
+. in 0
+.\}
+.pL
+'sp
+.ns
+.ta .5i 1i 1.5i 2i 2.5i 3i 3.5i 4i 4.5i 5i 5.5i 6i 6.5i
+.if !\\n(cR .ne 3
+'fi
+\&\fB\\$1 \|\\$2 \|\\$3 \|\\$4 \|\\$5 \|\\$6 \|\\$7 \|\\$8 \|\\$9
+\&\fP\&
+.in \\n(.iu+\\n(Tiu
+.if "\\$1"SEE" .nr sE 1
+.ns
+..
+.\"
+.\" Nd minus sign for an en dash used in .Sh Name
+.de Nd
+\&\-\& \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
+..
+.de Ss
+.sp
+.ti -.25i
+\&\fB\\$1 \|\\$2 \|\\$3 \|\\$4 \|\\$5 \|\\$6 \|\\$7 \|\\$8 \|\\$9
+\&\fP\&
+.ta .5i 1i 1.5i 2i 2.5i 3i 3.5i 4i 4.5i 5i 5.5i 6i 6.5i
+.if !\\n(cR .ne 2
+.br
+..
+.\" .if "\\$1"Ss" .in \\n(.iu+\\n(sIu
+.\"..
+.\"
+.\"
+.\" Column Macro
+.\"
+.hy 0
+.de Cw
+.ie \\n(.$==0 \{\
+. br
+. in \\n(.iu-\\n(eWu
+. ta .5i 1i 1.5i 2i 2.5i 3i 3.5i 4i 4.5i 5i 5.5i 6i 6.5i
+.\}
+.el \{\
+. Pp
+. if \\n(.$==1 \{\
+. ta \w'\\$1 'u
+. nr eW \w'\\$1 'u
+' in \\n(.iu+\\n(eWu
+. \}
+. if \\n(.$==2 \{\
+. ta \w'\\$1 'u +\w'\\$2 'u
+. nr eW \w'\\$1 'u+\w'\\$2 'u
+' in \\n(.iu+\\n(eWu
+. \}
+. if \\n(.$==3 \{\
+. ta \w'\\$1 'u +\w'\\$2 'u +\w'\\$3 'u
+. nr eW \w'\\$1 'u+\w'\\$2 'u+\w'\\$3 'u
+' in \\n(.iu+\\n(eWu
+. \}
+. if \\n(.$==4 \{\
+. ta \w'\\$1 'u +\w'\\$2 'u +\w'\\$3 'u +\w'\\$4 'u
+. nr eW \w'\\$1 'u+\w'\\$2 'u+\w'\\$3 'u +\w'\\$4 'u
+' in \\n(.iu+\\n(eWu
+. \}
+. if \\n(.$==5 \{\
+.ta \w'\\$1 'u +\w'\\$2 'u +\w'\\$3 'u +\w'\\$4 'u +\w'\\$5 'u
+.nr eW \w'\\$1 'u +\w'\\$2 'u +\w'\\$3 'u +\w'\\$4 'u +\w'\\$5 'u
+' in \\n(.iu+\\n(eWu
+. \}
+.\}
+..
+.de Cl
+.ti -\\n(eWu
+.mN \\$1
+.ie \\n(mN .\\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
+.el \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
+..
+.nr dQ 0
+.de Ds
+.ie !"\\$1"" \{\
+. mN d\\$1
+. if \\n(mN \{\
+. nr dQ \\n(dQ+1
+. d\\$1
+. \}
+.\}
+.el .br
+.nf
+..
+.de Df
+.ie !"\\$1"" \{\
+. mN d\\$1
+. if \\n(mN \{\
+. nr dQ \\n(dQ+1
+. d\\$1
+. \}
+.\}
+.el .br
+..
+.de Dn
+\\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
+.nf
+..
+.de dI
+.nr d\\n(dQ \\n(dIu
+.in \\n(.iu+\\n(dIu
+..
+.de dC
+.nr d\\n(dQ (\\n(.l-\\n(.i)/4u
+.in \\n(.iu+\\n(d\\n(dQu
+..
+.de dR
+.nr d\\n(dQ (\\n(.l/3)u
+.in \\n(.iu+\\n(d\\n(dQu
+..
+.de dL
+.nr aa 0
+..
+.de De
+.br
+.if \\n(d\\n(dQ \{\
+. in \\n(.iu-\\n(d\\n(dQu
+. rr d\\n(dQ
+. nr dQ \\n(dQ-1
+.\}
+.fi
+..
+.\"
+.de Fn
+.ie \\n(.$==0 \{\
+. tm Usage: .Fn function_name function_arg(s) ... \\*(Pu
+.\}
+.el \{\
+. nr cF \\n(.f
+. ie \\n(.$==1 .ds f1 \&\\*(nM\\$1\fP\\*(lP\fP\\*(rP\fP
+. el \{\
+. ds f1 \\*(nM\\$1\fP\\*(lP
+. nr aa 0
+. rC \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
+. \}
+. if "\\*(iM"" \{\\&\\*(f1
+. ds f1
+. \}
+.\}
+..
+.\"
+.de rC
+.rZ \\$1
+.ie \\n(rZ \{\
+. as f1 \f\\n(cF\\*(rP\f\\n(cF\\$1\\$2\\$3\\$4\\$5\\$6\\$7
+.\}
+.el \{\
+. ie \\n(aa .as f1 \fP, \\*(aR\\$1
+. el .as f1 \\*(aR\\$1
+. nr aa 1
+. ie \\n(.$>1 .rC \\$2 \\$3 \\$4 \\$5 \\$6 \\$7
+. el .as f1 \fP\\*(rP\fP
+.\}
+..
diff --git a/gnu/usr.bin/groff/tmac/tmac.dvi b/gnu/usr.bin/groff/tmac/tmac.dvi
new file mode 100644
index 0000000..73412ac
--- /dev/null
+++ b/gnu/usr.bin/groff/tmac/tmac.dvi
@@ -0,0 +1,134 @@
+.nr _C \n(.C
+.cp 0
+.ftr CR CW
+.ftr C CW
+.ftr TT CW
+.ftr HR H
+.\" This uses the dvi-char_1 string in font CW, dvi-char_0 otherwise.
+.char _ \R'dvi-char_ \\n(.f=\f(CW\\n(.f\fP'\\*[dvi-char_\\n[dvi-char_]]
+.char \[ul] \R'dvi-char_ \w'M'=\w'i''\\*[dvi-char_\\n[dvi-char_]]
+.\" Normally use a rule.
+.\" This is designed so that \(ul, \(rn and \(br form corners.
+.ds dvi-char_0 \Z'\v'.23m'\D'R .54m .04m''\h'.5m'
+.\" In font CW use a real _ character.
+.ds dvi-char_1 _
+.if !c\[radicalex] .char \[radicalex] \D'R .5m -.04m'\v'.04m'
+.if !c\[br] .char \[br] \Z'\v'.25m'\D'R .04m -1m''
+.if !c\[ru] .char \[ru] \Z'\v'-.02m'\D'R .54m .04m''\h'.5m'
+.if !c\[rn] .char \[rn] \Z'\v'-.77m'\D'R .54m .04m''\h'.5m'
+.if !c\[co] .char \[co] \z\(ci\h'\w'\(ci'u-\w'c'u/2u'c\h'\w'\(ci'u-\w'c'u/2u'
+.if !c\[rg] .char \[rg] \z\(ci\h'\w'\(ci'u-\w'r'u/2u'r\h'\w'\(ci'u-\w'r'u/2u'
+.if !c\[fm] .char \[fm] \v'-.35m'\s[\\n(.s*7u/10u]\[prime]\s0\v'.35m'
+.if !c\[de] .char \[de] \h'.05m'\v'-.54m'\D'c .3m'\v'.54m'\h'.05m'
+.if !c\[ct] .char \[ct] \o'c/'
+.if !c\[sq] .char \[sq] \Z'\h'.05m'\D'R .4m -.04m'\v'.04m'\h'-.04m'\
+\D'R .04m -.4m'\v'.04m'\D'R -.4m -.04m'\D'R .04m .4m''\h'.5m'
+.\"char \[sq] \h'.05m'\D'l .4m 0'\D'l 0 -.4m'\D'l -.4m 0'\D'l 0 .4m'\h'.45m'
+.if !c\[!=] .char \[!=] \[slashnot]\(eq
+.if !c\[tm] .char \[tm] \v'-.3m'\s[\\n(.s/2u]TM\s0\v'.3m'
+.if !c\[aq] .char \[aq] '
+.if !c\[bq] .char \[bq] ,
+.if !c\[Bq] .char \[Bq] ,\h'\w'\(rq'u-(2u*\w"'"u)',
+.if !c\[ho] .char \[ho] \s[\En[.s]/2u]\v'.4m'c\v'-.4m'\s0
+.if !c\[-D] .char \[-D] \Z'\v'-.1m'\h'.05m'-'D
+.if !c\[Sd] .char \[Sd] \Z'\v'-.3m'\h'.35m'-'\(pd
+.if !c\[TP] .char \[TP] I\h'-.25m'\v'-.33m'\s[\En[.s]*6u/10u]\v'.33m'D\
+\v'-.33m'\s0\v'.33m'
+.if !c\[Tp] .char \[Tp] \zlp
+.cflags 8 \(an
+.if !c\[an] .char \[an] \h'-.167m'\(mi\h'-.167m'
+.\" Define some fractions.
+.de dvi-frac
+.if !c\[\\$1\\$2] .char \[\\$1\\$2] \
+\v'-.25m'\s[\\\\n(.s*7u/10u]\\$1\s0\v'.25m'\h'-.2m'\
+/\h'-.2m'\v'.25m'\s[\\\\n(.s*7u/10u]\\$2\s0\v'-.25m'
+..
+.dvi-frac 1 2
+.dvi-frac 3 4
+.dvi-frac 1 4
+.dvi-frac 1 8
+.dvi-frac 3 8
+.dvi-frac 5 8
+.dvi-frac 7 8
+.\" support for ISO Latin-1
+.if !c\[S1] .char \[S1] \v'-.2m'\s-31\s+3\v'+.2m'
+.if !c\[S2] .char \[S2] \v'-.2m'\s-32\s+3\v'+.2m'
+.if !c\[S3] .char \[S3] \v'-.2m'\s-33\s+3\v'+.2m'
+.if !c\[Of] .char \[Of] \v'-.2m'\s'\En(.s*6u/10u'\o'_a'\s0\v'.2m'
+.if !c\[Om] .char \[Om] \v'-.2m'\s'\En(.s*6u/10u'\o'_o'\s0\v'.2m'
+.if !c\[Fo] .char \[Fo] <<
+.if !c\[Fc] .char \[Fc] >>
+.if !c\[bb] .char \[bb] |
+.if !c\[Ye] .char \[Ye] \o'-Y'
+.if !c\[Cs] .char \[Cs] \o'\[mu]o'
+.de dvi-achar
+.\" Note that character definitions are always interpreted with
+.\" compatibility mode off.
+.if !c\\$1 \{\
+.char \\$1 \\$3\
+\k[acc]\
+\h'(u;-\w'\\$2'-\w'\\$3'/2+\\\\n[skw]+(\w'x'*0)-\\\\n[skw])'\
+\v'(u;\w'x'*0+\\\\n[rst]+(\w'\\$3'*0)-\\\\n[rst])'\
+\\$2\
+\v'(u;\w'x'*0-\\\\n[rst]+(\w'\\$3'*0)+\\\\n[rst])'\
+\h'|\\\\n[acc]u'
+.\}
+.hcode \\$1\\$4
+..
+.dvi-achar \(`A \` A a
+.dvi-achar \('A \' A a
+.dvi-achar \(^A ^ A a
+.dvi-achar \(~A ~ A a
+.dvi-achar \(:A \(ad A a
+.dvi-achar \(oA \(ao A a
+.dvi-achar \(`E \` E e
+.dvi-achar \('E \' E e
+.dvi-achar \(^E ^ E e
+.dvi-achar \(:E \(ad E e
+.dvi-achar \(`I \` I i
+.dvi-achar \('I \' I i
+.dvi-achar \(^I ^ I i
+.dvi-achar \(:I \(ad I i
+.dvi-achar \(~N ~ N n
+.dvi-achar \(`O \` O o
+.dvi-achar \('O \' O o
+.dvi-achar \(^O ^ O o
+.dvi-achar \(~O ~ O o
+.dvi-achar \(:O \(ad O o
+.dvi-achar \(`U \` U u
+.dvi-achar \('U \' U u
+.dvi-achar \(^U ^ U u
+.dvi-achar \(:U \(ad U u
+.dvi-achar \('Y \' Y y
+.dvi-achar \(`a \` a a
+.dvi-achar \('a \' a a
+.dvi-achar \(^a ^ a a
+.dvi-achar \(~a ~ a a
+.dvi-achar \(:a \(ad a a
+.dvi-achar \(oa \(ao a a
+.dvi-achar \(`e \` e e
+.dvi-achar \('e \' e e
+.dvi-achar \(^e ^ e e
+.dvi-achar \(:e \(ad e e
+.dvi-achar \(`i \` \(.i i
+.dvi-achar \('i \' \(.i i
+.dvi-achar \(^i ^ \(.i i
+.dvi-achar \(:i \(ad \(.i i
+.dvi-achar \(~n ~ n n
+.dvi-achar \(`o \` o o
+.dvi-achar \('o \' o o
+.dvi-achar \(^o ^ o o
+.dvi-achar \(~o ~ o o
+.dvi-achar \(:o \(ad o o
+.dvi-achar \(`u \` u u
+.dvi-achar \('u \' u u
+.dvi-achar \(^u ^ u u
+.dvi-achar \(:u \(ad u u
+.dvi-achar \('y \' y y
+.dvi-achar \(:y \(ad y y
+.if !c\(,C .char \(,C \o'\(acC'
+.hcode \(,Cc
+.if !c\(,c .char \(,c \o'\(acc'
+.hcode \(,cc
+.cp \n(_C
+.do mso tmac.latin1
diff --git a/gnu/usr.bin/groff/tmac/tmac.e b/gnu/usr.bin/groff/tmac/tmac.e
new file mode 100644
index 0000000..92fb264
--- /dev/null
+++ b/gnu/usr.bin/groff/tmac/tmac.e
@@ -0,0 +1,1649 @@
+.\" @(#)tmac.e 2.31 (Berkeley) 5/21/88
+.\" Modified by James Clark for use with groff.
+.\"
+.\" Copyright (c) 1988 Regents of the University of California.
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms are permitted
+.\" provided that this notice is preserved and that due credit is given
+.\" to the University of California at Berkeley. The name of the University
+.\" may not be used to endorse or promote products derived from this
+.\" software without specific prior written permission. This software
+.\" is provided ``as is'' without express or implied warranty.
+.\" %beginstrip%
+.\"
+.\"**********************************************************************
+.\"* *
+.\"* ****** - M E N R O F F / T R O F F M A C R O S ****** *
+.\"* *
+.\"* Produced for your edification and enjoyment by: *
+.\"* Eric Allman *
+.\"* Electronics Research Laboratory *
+.\"* U.C. Berkeley. *
+.\"* current address: *
+.\"* Britton-Lee, Inc. *
+.\"* 1919 Addison Street Suite 105 *
+.\"* Berkeley, California 94704 *
+.\"* *
+.\"* VERSION 2.31 First Release: 11 Sept 1978 *
+.\"* *
+.\"* Documentation is available. *
+.\"* *
+.\"**********************************************************************
+.\"
+.\" Code on .de commands:
+.\" *** a user interface macro.
+.\" &&& a user interface macro which is redefined
+.\" when used to be the real thing.
+.\" $$$ a macro which may be redefined by the user
+.\" to provide variant functions.
+.\" --- an internal macro.
+.\"
+.if !\n(.g .ig
+.de @R \" --- initialize number register to 0, if undefined
+.if !r\\$1 .nr \\$1 0
+..
+.@R pf
+.if \n(pf .nx
+.if !\n(.g .ig
+.de @S \" --- initialize string/macro to empty, if undefined
+.if !d\\$1 .ds \\$1 \" empty
+..
+.@R @\" \" debugging level
+.\" *** INTERNAL GP MACROS ***
+.de @C \" --- change ev's, taking info with us
+.nr _S \\n(.s
+.nr _V \\n(.v
+.nr _F \\n(.f
+.do ds _A \\n[.fam]
+.nr _I \\n(.i
+.ev \\$1
+.ps \\n(_S
+.vs \\n(_Vu
+.ft \\n(_F
+.do @fam \\*(_A
+'in \\n(_Iu
+.xl \\n($lu
+.lt \\n($lu
+.rr _S
+.rr _V
+.rr _F
+.rr _I
+.ls 1
+'ce 0
+..
+.de @D \" --- determine display type (Indent, Left, Center)
+.ds |p "\\$3
+.nr _d 0
+.if "\\$2"C" \
+. nr _d 1
+.if "\\$2"L" \
+. nr _d 2
+.if "\\$2"I" \
+. nr _d 3
+.if "\\$2"M" \
+. nr _d 4
+.if !\\n(_d \{\
+. nr _d \\$1
+. ds |p "\\$2
+.\}
+..
+.de @z \" --- end macro
+.if \n@>1 .tm >> @z, .z=\\n(.z ?a=\\n(?a
+.if !"\\n(.z"" \
+\{\
+. tm Line \\n(c. -- Unclosed block, footnote, or other diversion (\\n(.z)
+. di
+. ex
+.\}
+.if \\n(?a \
+. bp \" force out final table
+.ds bp
+.ds @b\" \" don't start another page
+.br
+.if \n@>1 .tm << @z
+..
+.\" *** STANDARD HEADERS AND FOOTERS ***
+.ie \n(.g .ds $* \\\\$*
+.el .ds $* \\\\$1 \\\\$2 \\\\$3 \\\\$4 \\\\$5 \\\\$6 \\\\$7 \\\\$8 \\\\$9
+.de he \" *** define header
+.ie !\\n(.$ \
+\{\
+. rm |4
+. rm |5
+.\}
+.el \
+\{\
+. ds |4 "\*($*
+. ds |5 "\*($*
+.\}
+..
+.de eh \" *** define even header
+.ie !\\n(.$ \
+. rm |4
+.el \
+. ds |4 "\*($*
+..
+.de oh \" *** define odd header
+.ie !\\n(.$ \
+. rm |5
+.el \
+. ds |5 "\*($*
+..
+.de fo \" *** define footer
+.ie !\\n(.$ \
+\{\
+. rm |6
+. rm |7
+.\}
+.el \
+\{\
+. ds |6 "\*($*
+. ds |7 "\*($*
+.\}
+..
+.de ef \" *** define even foot
+.ie !\\n(.$ \
+. rm |6
+.el \
+. ds |6 "\*($*
+..
+.de of \" *** define odd footer
+.ie !\\n(.$ \
+. rm |7
+.el \
+. ds |7 "\*($*
+..
+.de ep \" *** end page (must always be followed by a .bp)
+.if \\n(nl>0 \
+\{\
+. wh 0
+. rs
+. @b
+.\}
+..
+.\" *** INTERNAL HEADER AND FOOTER MACROS ***
+.de @h \" --- header
+.if \n@>1 .tm >> @h %=\\n% ?a=\\n(?a ?b=\\n(?b ?w=\\n(?w
+.if (\\n(.i+\\n(.o)>=\\n(.l \
+. tm Line \\n(c. -- Offset + indent exceeds line length
+.\" initialize a pile of junk
+.nr ?h \\n(?H \" transfer "next page" to "this page"
+.nr ?H 0
+.nr ?c \\n(?C
+.nr ?C 0
+.rn |4 |0
+.rn |5 |1
+.rn |6 |2
+.rn |7 |3
+.nr _w 0 \" reset max footnote width
+.nr ?W 0 \" no wide floats this page (yet)
+.nr ?I 1
+.\" begin actual header stuff
+.ev 2
+.rs
+.if \\n(hm>0 \
+. sp |\\n(hmu \" move to header position
+.@t $h \" output header title
+.if \\n(tm<=0 \
+. nr tm \n(.Vu
+.sp |\\n(tmu \" move to top of text
+.ev
+.mk _k \" for columned output
+.if \\n(?n .nm 1 \" restore line numbering if n1 mode
+.nr $c 1 \" set first column
+.if \n@>4 .tm -- @h >> .ns nl=\\n(nl %=\\n% _k=\\n(_k tm=\\n(tm
+.ie \\n(?s \
+\{\
+. nr ?s 0
+. rs
+' @b
+.\}
+.el \
+. @n \" begin the column
+.if \n@>2 .tm << @h
+..
+.de @n \" --- new column or page
+.if \n@>3 .tm >> @n nl=\\n(nl %=\\n% ?f=\\n(?f ?o=\\n(?o
+.if \\n(bm<=0 \
+. nr bm \\n(.Vu
+.if (\\n(_w<=\\n($l)&(\\n(?W=0) \
+\{\
+. nr _b (\\n(ppp*\\n($vu)/200u \" compute fudge factor (must be < 1P)
+. if \\n(_bu>((\\n(bmu-\\n(fmu-((\\n(tpp*\\n($vu)/100u))/2u) \
+. nr _b (\\n(ppp*\\n($vu)/100u-\n(.Vu
+. nr _b +\\n(bmu
+.\}
+.nr _B \\n(_bu
+.ch @f
+.wh -\\n(_bu @f
+.nr _b +(\\n(ppp*\\n($vu)/100u \" add 1 paragraph v in case of sweep past
+.if \n@>2 .tm @n .p=\\n(.p bm=\\n(bm _b=\\n(_b _B=\\n(_B
+.nr ?f 0 \" reset footnote flag
+.if \\n(?o \
+\{\
+. (f _ \" reprocess footnotes which run off page
+. nf
+. |o
+. fi
+. )f
+. rm |o
+.\}
+.nr ?o 0
+.if \\n(?T \
+\{\
+. nr _i \\n(.i
+. in \\n($iu
+. |h \" output the table header
+. in \\n(_iu
+. rr _i
+. mk #T \" for tbl commands
+. ns
+.\}
+.if (\\n(?a)&((\\n($c<2):(\\n(?w=0)) \
+\{\
+. nr ?a 0 \" output floating keep
+. @k |t
+. if \\n(?w \
+. mk _k \" don't overstrike wide keeps
+. nr ?w 0
+.\}
+.os
+.$H \" special column header macro
+.ns
+..
+.de @f \" --- footer
+.if \n@>1 .tm >> @f %=\\n% nl=\\n(nl ?a=\\n(?a ?b=\\n(?b ?f=\\n(?f
+.if \n@>2 .nr VL \\n(.pu-\\n(nlu
+.if \n@>2 .tm @f bm=\\n(bm _B=\\n(_B _b=\\n(_b .p-nl=\\n(VL
+.ec
+.if \\n(?T \
+\{\
+. nr T. 1 \" for tbl commands (to output bottom line)
+. T# 1 \" output the sides and bottom lines
+. br
+.\}
+.ev 2
+.ce 0
+.if \\n(?b \
+\{\
+. nr ?b 0
+. @k |b\" \" output bottom of page tables
+.\}
+.if \\n(?f \
+. @o \" output footnote if present
+.ie \\n($c<\\n($m \
+. @c \" handle new column
+.el \
+. @e \" new page
+.ev
+.if \n@>2 .tm << @f
+..
+.de @o \" --- output footnote
+.nf
+.ls 1
+.in 0
+.if \n@>2 .tm @o last printed text = \\n(nl placing @r trap at -\\n(_B
+.wh -\\n(_Bu @r
+.|f
+.fi
+.if \n@>2 .tm @o triggered @r (?o) = \\n(?o
+.if \\n(?o \
+\{\
+. di \" just in case triggered @r
+. if \\n(dn=0 \
+\{\
+. rm |o
+. nr ?o 0
+. \}
+. nr dn \\n(_D
+. rr _D
+.\}
+.rm |f
+.ch @r
+..
+.de @c \" --- new column
+.if \n@>2 .tm >> @c %=\\n%
+.rs
+.sp |\\n(_ku
+.@O +\\n($lu+\\n($su
+.nr $c +1
+.@n
+..
+.de @e \" --- end page
+.if \n@>2 .tm >> @e
+.@O \\n(_ou
+.rs
+.sp |\\n(.pu-\\n(fmu-((\\n(tpp*\\n($vu)/100u) \" move to footer position
+.@t $f \" output footer title
+.nr ?h 0
+.bp
+..
+.de @t \" --- output header or footer title
+.if !\\n(?h \
+\{\
+. sz \\n(tp \" set header/footer type fonts, etc.
+. @F \\n(tf
+. lt \\n(_Lu \" make title span entire page
+. nf
+. \\$1
+. br
+.\}
+..
+.de $h \" $$$ print header
+.ds |z
+.if !\\n(?c \
+\{\
+. if e .ds |z "\\*(|0
+. if o .ds |z "\\*(|1
+.\}
+.if !\(ts\\*(|z\(ts\(ts \
+' tl \\*(|z
+.rm |z
+..
+.de $f \" $$$ print footer
+.ds |z
+.if \\n(?c \
+\{\
+. if e .ds |z "\\*(|0
+. if o .ds |z "\\*(|1
+.\}
+.if \(ts\\*(|z\(ts\(ts \
+\{\
+. if e .ds |z "\\*(|2
+. if o .ds |z "\\*(|3
+.\}
+.if !\(ts\\*(|z\(ts\(ts \
+' tl \\*(|z
+.rm |z
+..
+.de @r \" --- reprocess overflow footnotes
+.if \n@>3 .tm >> @r .z=\\n(.z ?f=\\n(?f ?a=\\n(?a ?b=\\n(?b _b=\\n(_b
+.di |o \" save overflow footnote
+.nr ?o 1
+.nr _D \\n(dn
+.ns
+..
+.\" *** COMMANDS WITH VARIANT DEFINITIONS ***
+.rn bp @b \" --- begin page
+.de bp \" *** begin new page (overrides columns)
+.nr $c \\n($m \" force new page, not new column
+.ie \\n(nl>0 \
+. @b \\$1
+.el \
+\{\
+. if \\n(.$>0 \
+. pn \\$1
+. if \\n(?I \
+. @h \" 'spring' the header trap
+.\}
+.br
+.wh 0 @h \" reset header
+..
+.rn ll xl \" *** special line length (local)
+.de ll \" *** line length (global to environments)
+.xl \\$1
+.lt \\$1
+.nr $l \\n(.l
+.if (\\n($m<=1):(\\n($l>\\n(_L) \
+. nr _L \\n(.l
+..
+.rn po @O \" --- local page offset
+.de po \" *** page offset
+.@O \\$1
+.nr _o \\n(.o
+..
+.\" Redefine the fam request to set the family in
+.\" environment 2 as well as the current environment.
+.if !\n(.g .ig
+.do rn fam @fam \" --- set family in current environment
+.do de fam \" *** set font family in ev 2 and current ev
+.do @fam \\$1
+.ev 2
+.do @fam \\$1
+.ev
+..
+.\" *** MISCELLANEOUS ROFF COMMANDS ***
+.de hx \" *** suppress headers and footers next page
+.nr ?H 1
+..
+.de ix \" *** indent, no break
+'in \\$1
+..
+.de bl \" *** contiguous blank lines
+.br
+.ne \\$1
+.rs
+.sp \\$1
+..
+.de n1 \" *** line numbering 1
+.nm 1
+.xl -\w'0000'u
+.nr ?n 1
+..
+.de n2 \" *** line numbering 2
+.nm \\$1
+.ie \\n(.$ \
+. xl -\w'0000'u
+.el \
+. xl \\n($lu
+..
+.de pa \" *** new page
+.bp \\$1
+..
+.de ro \" *** roman page numbers
+.af % i
+..
+.de ar \" *** arabic page numbers
+.af % 1
+..
+.de m1 \" *** position one space
+.nr _0 \\n(hmu
+.nr hm \\$1v
+.nr tm +\\n(hmu-\\n(_0u
+.rr _0
+..
+.de m2 \" *** position two space
+.nr tm \\n(hmu+\\n(tpp+\\$1v
+..
+.de m3 \" *** position three space
+.nr bm \\n(fmu+\\n(tpp+\\$1v
+..
+.de m4 \" *** position four space
+.nr _0 \\n(fmu
+.nr fm \\$1v
+.nr bm +\\n(fmu-\\n(_0u
+..
+.de sk \" *** leave a blank page (next page)
+.if \\n(.$>0 \
+. tm Line \\n(c. -- I cannot skip multiple pages
+.nr ?s 1
+..
+.\" *** MISCELLANEOUS USER SUPPORT COMMANDS ***
+.if !\n(.g .ig
+.de re \" *** reset tabs (TROFF defines 15 stops default)
+.ta T 0.5i
+..
+.if \n(.g .ig
+.de re
+.ta 0.5i +0.5i +0.5i +0.5i +0.5i +0.5i +0.5i +0.5i +0.5i +0.5i +0.5i +0.5i +0.5i +0.5i +0.5i
+..
+.de ba \" *** set base indent
+.ie \\n(.$ \
+. nr $i \\$1n
+.el \
+. nr $i \\n(siu*\\n($0u
+..
+.de hl \" *** draw horizontal line
+.br
+.ie \n(.g .do nr _I \\n[.in]
+.el .nr _I \\n(.i
+\l'\\n(.lu-\\n(_Iu'
+.sp
+..
+.\" *** PARAGRAPHING ***
+.de pp \" *** paragraph
+.lp \\n(piu
+..
+.de lp \" *** left aligned paragraph
+.@p
+.if \\n(.$ \
+. ti +\\$1
+.nr $p 0 1
+..
+.de ip \" *** indented paragraph w/ optional tag
+.if (\\n(ii>0)&(\\n(ii<1n) \
+. nr ii \\n(iin
+.nr _0 \\n(ii
+.if \\n(.$>1 \
+. nr _0 \\$2n
+.@p \\n(_0u
+.if \\w"\\$1" \
+\{\
+. ti -\\n(_0u
+. ie \\w"\\$1">=\\n(_0 \
+\{\
+\&\\$1
+. br
+. \}
+. el \&\\$1\h'|\\n(_0u'\c
+.\}
+.rr _0
+..
+.de np \" *** numbered paragraph
+.\" use string comparison in case user has changed format of $p
+.if '\\n($p'-1' \
+. nr $p 0 \" reset number after .bu
+.nr $p +1 \" increment paragraph number
+.@p \w'\0(000)\0'u
+.ti -\w'\0(000)\0'u
+\0(\\n($p)\h'|\w'\0(000)\0'u'\c
+..
+.de bu \" *** bulleted paragraph
+.br
+.\" use string comparison in case user has changed format of $p
+.if '\\n($p'-1' \
+. ns \" don't space between .bu paragraphs
+.nr $p 0-1 \" mark "bulleted paragraph" mode
+.@p \w'\0\(bu\0'u
+.ti -\w'\0\(bu\0'u
+\0\(bu\0\c
+..
+.de @p \" --- initialize for paragraph
+.if "\\n(.z"|e" .tm Line \\n(c. -- Unmatched continued equation
+.in \\n($iu+\\n(pou
+.if \\n(.$ \
+. in +\\$1n
+.ce 0
+.fi
+.@F \\n(pf
+.sz \\n(pp
+.sp \\n(psu
+.ne \\n(.Lv+\\n(.Vu
+.ns
+..
+.\" *** SECTION HEADINGS ***
+.de sh \" *** section heading
+.fi
+.if (\\n(si>0)&(\\n(si<1n) \
+. nr si \\n(sin
+.ce 0
+.@d "\\$1" +1 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8
+.if !"\\$2"_" \
+\{\
+. ds |n \&\\$2
+. $p "\\*(|n" "\\*($n" \\n($0
+. $0 "\\*(|n" "\\*($n" \\n($0
+. rm |n
+.\}
+.nr $p 0 1 \" reset .np count
+..
+.de @d \" --- change section depth
+.if !""\\$1" \
+. nr $0 \\$1
+.if \\n($0&(\\n(.$>1) \
+. nr $\\n($0 \\$2
+.ds $n \&\"
+.ie \\n($0>=1 \
+\{\
+. if '\\n($1'0' \
+. nr $1 1
+. if (\\n(.$>=3) .if !"\\$3"-" \
+. nr $1 \\$3
+. as $n \\n($1
+.\}
+.el \
+. nr $1 0
+.ie \\n($0>=2 \
+\{\
+. if '\\n($2'0' \
+. nr $2 1
+. if (\\n(.$>=4) .if !"\\$4"-" \
+. nr $2 \\$4
+. as $n .\\n($2
+.\}
+.el \
+. nr $2 0
+.ie \\n($0>=3 \
+\{\
+. if '\\n($3'0' \
+. nr $3 1
+. if (\\n(.$>=5) .if !"\\$5"-" \
+. nr $3 \\$5
+. as $n .\\n($3
+.\}
+.el \
+. nr $3 0
+.ie \\n($0>=4 \
+\{\
+. if '\\n($4'0' \
+. nr $4 1
+. if (\\n(.$>=6) .if !"\\$6"-" \
+. nr $4 \\$6
+. as $n .\\n($4
+.\}
+.el \
+. nr $4 0
+.ie \\n($0>=5 \
+\{\
+. if '\\n($5'0' \
+. nr $5 1
+. if (\\n(.$>=7) .if !"\\$7"-" \
+. nr $5 \\$7
+. as $n .\\n($5
+.\}
+.el \
+. nr $5 0
+.ie \\n($0>=6 \
+\{\
+. if '\\n($6'0' \
+. nr $6 1
+. if (\\n(.$>=8) .if !"\\$8"-" \
+. nr $6 \\$8
+. as $n .\\n($6
+.\}
+.el \
+. nr $6 0
+..
+.de sx \" *** heading up, no increment (2.1.1 -> 2.1)
+.ce 0
+.ul 0
+.nr _0 \\n($0-1
+.if \\n(.$ .nr _0 +1
+.if \\n(.$ .nr _0 \\$1
+.@d \\n(_0
+.rr _0
+.$p "" "" \\n($0
+.nr $p 0 1 \" reset .np count
+..
+.de uh \" *** unnumbered section heading
+.$p "\\$1"
+.$0 "\\$1"
+..
+.de $p \" $$$ print section heading
+.if (\\n(si>0)&(\\n(.$>2) \
+. nr $i \\$3*\\n(si
+.in \\n($iu
+.ie !"\\$1\\$2"" \
+\{\
+. sp \\n(ssu \" one of them is non-null
+. ne \\n(.Lv+\\n(.Vu+\\n(psu+((\\n(spp*\\n($vu*\\n(.Lu)/100u)
+. \" exdent if \\$3 > 0
+. ie 0\\$3 \
+. ti -(\\n(siu-\\n(sou)
+. el \
+. ti +\\n(sou
+. @F \\n(sf
+. sz \\n(sp
+. if 0\\$3 \
+. $\\$3
+. if \w"\\$2">0 \\$2.
+. if \w"\\$1">0 \\$1\f1\ \ \&
+.\}
+.el \
+. sp \\n(psu
+.@F \\n(pf
+.sz \\n(pp
+..
+.\" *** COLUMNNED OUTPUT ***
+.de 2c \" *** double columned output
+.br
+.if \\n($m>1 \
+. 1c \" revert to 1c if already 2c
+.nr $c 1
+.nr $m 2
+.if \\n(.$>1 \
+. nr $m \\$2
+.if \\n(.$>0 \
+. nr $s \\$1n \" param 1: column seperation
+.nr $l (\\n(.l-((\\n($m-1)*\\n($s))/\\n($m
+.xl \\n($lu
+.mk _k
+.ns
+..
+.de 1c \" *** single columned output
+.br
+.nr $c 1
+.nr $m 1
+.ll \\n(_Lu \" return to normal output
+.sp |\\n(.hu
+.@O \\n(_ou
+..
+.de bc \" *** begin column
+.sp 24i
+..
+.\" *** FLOATING TABLES AND NONFLOATING BLOCKS ***
+.de (z \" *** begin floating keep
+.if \n@>4 .tm >> (z, .z=\n(.z
+.@D 4 \\$1 \\$2
+.@(
+..
+.de )z \" *** end floating keep
+.if \n@>4 .tm >> )z, .z=\n(.z
+.sp \\n(zsu
+.@)
+.if \n@>4 .tm -- )z << @), .z=\n(.z
+.rr _0
+.if !\\n(?b \
+. nr dn +(\\n(ppp*\\n($vu)/200u+\\n(zsu
+.nr dl -\n(.H \" fudge factor necessary to make it work
+.ie ((\\n(dn+\n(.V)>=\\n(.t):(\\n(?a):((\\n(dl>\\n($l)&(\\n($c>1)) \
+\{\
+. nr ?a 1
+. if (\\n(dl>\\n($l)&(\\n($m>1) \
+. nr ?w 1 \" mark wider than one column (top)
+. ds |x |t
+.\}
+.el \
+\{\
+. nr ?b 1
+. if (\\n(dl>\\n($l)&(\\n($m>1) \
+. nr ?W 1 \" mark wider than one column (bottom)
+. nr _b +\\n(dnu
+. \" avoid moving @f back past the current position
+. if \\n(.p-\\n(nl-\n(.V<\\n(_b \
+. nr _b \\n(.p-\\n(nl-\n(.V
+. ch @f -\\n(_bu
+. ds |x |b
+.\}
+.da \\*(|x \" copy to save macro
+.nf
+.ls 1
+.nr ?k 1
+.if \n@>4 .tm -- )z >> \\*(|x
+\!.if \\\\n(nl>(\\\\n(tm+2v) .ne \\n(dnu-\\n(zsu
+.|k\" \" and the body
+.ec
+.if \n@>4 .tm -- )z << \\*(|x, .z=\\n(.z
+.nr ?k 0
+.rm |k\" \" remove the temp macro
+.da
+.in 0
+.ls 1
+.xl \\n($lu
+.ev
+.if \n@>4 .tm << )z, .z=\\n(.z
+..
+.de @k \" --- output floating keep
+.if \n@>4 .tm >> @k, $1=\\$1, .z=\\n(.z
+.ev 1
+.nf
+.ls 1
+.in 0
+.sp \\n(zsu
+.\\$1
+.ec
+.br
+.rm \\$1
+.ev
+..
+.de (t \" XXX temp ref to (z
+.(z \\$1 \\$2
+..
+.de )t \" XXX temp ref to )t
+.)z \\$1 \\$2
+..
+.de (b \" *** begin block
+.br
+.@D 3 \\$1 \\$2
+.sp \\n(bsu
+.@(
+..
+.de )b \" *** end block
+.br
+.@)
+.if (\\n(bt=0):(\\n(.t<\\n(bt) \
+. ne \\n(dnu \" make it all on one page
+.ls 1
+.nf
+.|k
+.ec
+.fi
+.in 0
+.xl \\n($lu
+.ev
+.rm |k
+.sp \\n(bsu+\\n(.Lv-1v
+..
+.de @( \" --- begin keep
+.if !"\\n(.z"" .tm Line \\n(c. -- Illegal nested keep \\n(.z
+.@M
+.di |k
+\!'rs
+..
+.de @M \" --- set modes for display
+.nr ?k 1
+.@C 1
+.@F \\n(df
+.if \\n($R .@V
+.vs \\n(.sp*\\n($Vu/100u
+.nf
+.if "\\*(|p"F" \
+. fi \" set fill mode if "F" parameter
+.if \\n(_d=4 \
+. in 0
+.if \\n(_d=3 \
+\{\
+. in +\\n(biu
+. xl -\\n(biu
+.\}
+.if \\n(_d=1 \
+. ce 10000
+..
+.de @) \" --- end keep
+.br
+.if !"\\n(.z"|k" .tm Line \\n(c. -- Close of a keep which has never been opened
+.nr ?k 0
+.di
+.in 0
+.ce 0
+..
+.de (c \" *** begin block centered text
+.if "\\n(.z"|c" .tm Line \\n(c. -- Nested .(c requests
+.di |c
+..
+.de )c \" *** end block centered text
+.if !"\\n(.z"|c" .tm Line \\n(c. -- Unmatched .)c
+.br \" force out final line
+.di
+.if \n@>4 .tm >> .)c .l=\\n(.l .i=\\n(.i $i=\\n($i dl=\\n(dl
+.ev 1
+.ls 1
+.in (\\n(.lu-\\n(.iu-\\n(dlu)/2u
+.if \n@>4 .tm -- .)c << .in .l=\\n(.l .i=\\n(.i dl=\\n(dl
+.nf
+.|c
+.ec
+.in
+.ls
+.ev
+.rm |c
+..
+.\" *** BLOCK QUOTES (OR WHATEVER) AND LISTS ***
+.de (q \" *** begin block quote
+.br
+.@C 1
+.fi
+.sp \\n(qsu
+.in +\\n(qiu
+.xl -\\n(qiu
+.sz \\n(qp
+..
+.de )q \" *** end block quote
+.br
+.ev
+.sp \\n(qsu+\\n(.Lv-1v
+.nr ?k 0
+..
+.de (l \" *** begin list
+.br
+.sp \\n(bsu
+.@D 3 \\$1 \\$2
+.@M
+..
+.de )l \" *** end list
+.br
+.ev
+.sp \\n(bsu+\\n(.Lv-1v
+.nr ?k 0
+..
+.\" *** PREPROCESSOR SUPPORT ***
+.\"
+.\" EQN
+.\"
+.de EQ \" *** equation start
+.ec
+.if !\\n(?e \
+\{\
+. if "\\n(.z"|e" .tm Line \\n(c. -- Nested .EQ request
+. @D 1 "\\$1" "\\$2"
+. @C 2
+. di |e
+.\}
+.ls 1
+.in 0
+.nf
+..
+.de EN \" *** equation end
+.br
+.ie "\\$1"C" \
+\{\
+. nr ?e 1
+. sp \\n(esu
+.\}
+.el \
+\{\
+. nr ?e 0
+. di
+. if \\n(dn \
+. @q \" actual equation output
+. rm |e
+. ev
+.\}
+..
+.de @q \" --- equation output
+.nr _Q \\n(dnu
+.ev
+.sp \\n(esu \" output rest of preceeding text
+.if !"\\n(.z"" \!.ne \\n(_Qu
+.ne \\n(_Qu+\n(.Vu \" keep it on one page
+.@C 2 \" .ev 2 may be jumbled from header
+.if \\n(_d=1 \
+. in (\\n(.lu+\\n($iu-\\n(dlu)/2u
+.if \\n(_d=2 \
+. in \\n($iu
+.if \\n(_d=3 \
+. in \\n(biu+\\n($iu
+.if \\n(_d=4 \
+. in 0
+.mk _q
+.if \n@>1 .tm --@e: _Q=\\n(_Q _q=\\n(_q nl=\\n(nl |p=\\*(|p
+.if !"\\*(|p"" \
+\{\
+. rs
+. sp (\\n(_Qu-\\n(.vu)/2u
+. tl """\\*(|p"
+. rt \\n(_qu
+.\}
+.|e
+.sp |\\n(_qu+\\n(_Qu
+.sp \\n(esu+\\n(.Lv-1v
+.rr _q
+.rr _Q
+..
+.\"
+.\" TBL
+.\"
+.de TS \" *** table start
+.sp \\n(bsu
+.@C 1
+.fi \" drop into fill mode for text boxes
+.if "\\$1"H" \
+\{\
+. di |h \" save header part
+. nr ?T 1
+.\}
+.ls 1
+.ch @f -(\\n(_bu+1v) \" set pseudo-trap for bottom line
+.if \\n(.p-\\n(_b-1v<=\\n(nl \
+. ch @f \\n(nlu+\n(.Vu
+..
+.de TH \" *** end header part of table
+.nr T. 0
+.T# 0
+.di
+.nr _T \\n(?T
+.nr ?T 0
+.ne \\n(dnu+1v
+.nr ?T \\n(_T
+.nr _i \\n(.i
+.in 0
+.|h \" put in the initial header
+.in \\n(_iu
+.rr _i
+.mk #T
+..
+.de TE \" *** table end
+.nr ?T 0
+.ch @f -\\n(_bu \" reset pseudo-trap
+.if \\n(.p-\\n(_b<=\\n(nl \
+. ch @f \\n(nlu+\n(.Vu
+.ev
+.sp \\n(bsu+\\n(.Lv-1v
+.re
+..
+.\"
+.\" REFER
+.\"
+.de ][ \" *** refer output
+.if \\$1>5 .tm Bad arg to []
+.[\\$1
+..
+.de [0 \" --- other
+.(f
+.ip "\\*([F.\0"
+.if !"\\*([A"" \\*([A,
+.if !"\\*([T"" \\f2\\*([T\\f1\c
+.if !"\\*([T"" .if !"\\*([O"" ,\
+.ie !"\\*([O"" \\*([O
+.el .if !"\\*([T"" \&.
+.if !"\\*([D"" \\*([D.
+.@p
+.)f
+..
+.de [1 \" --- journal article
+.(f
+.ip "\\*([F.\0"
+\\*([A,
+.if !"\\*([T"" \\*(lq\\*([T,\\*(rq
+.if "\\*([V"" \\f2\\*([J\\f1,
+.if !"\\*([V"" \\f2\\*([J\\f1
+.if !"\\*([V"" \\f3\\*([V\\f1\c
+.if !"\\*([N"" (\\*([N)\c
+.if !"\\*([P"" \
+\{\
+. ie \\n([P>0 \ pp.\&
+. el \ p.\&
+\\*([P
+.\}
+.if !"\\*([I"" .if "\\*([R"" \\*([I,
+(\\*([D).
+.if !"\\*([O"" \\*([O
+.)f
+..
+.de [2 \" --- book
+.(f
+.ip "\\*([F.\0"
+\\*([A, \\f2\\*([T,\\f1
+\\*([I\c
+.if !"\\*([C"" , \\*([C\c
+ (\\*([D).
+.if !"\\*([G"" Gov't. ordering no. \\*([G
+.if !"\\*([O"" \\*([O
+.)f
+..
+.de [3 \" --- article in book
+.(f
+.ip "\\*([F.\0"
+\\*([A, \\*(lq\\*([T,\\*(rq
+.if !"\\*([P"" pp. \\*([P
+in \\f2\\*([B\\f1, \c
+.if !"\\*([E"" ed. \\*([E, \c
+.if !"\\*([I"" \\*([I\c
+.if !"\\*([C"" , \\*([C\c
+ (\\*([D).
+.if !"\\*([O"" \\*([O
+.)f
+..
+.de [4 \" --- report
+.(f
+.ip "\\*([F.\0"
+\\*([A, \\*(lq\\*([T,\\*(rq
+\\*([R\c
+.if !"\\*([G"" \& (\\*([G)\c
+.if !"\\*([I"" , \\*([I\c
+.if !"\\*([C"" , \\*([C\c
+ (\\*([D).
+.if !"\\*([O"" \\*([O
+.)f
+..
+.de [5 \" --- tm style
+.(f
+.ip "\\*([F.\0"
+\\*([A, \\f2\\*([T\\f1,
+.ie \\n(TN \\*([M.
+.el Bell Laboratories internal memorandum (\\*([D).
+.)f
+..
+.de ]<
+.$p References
+.lp
+.rm (f )f
+..
+.de ]>
+.sp
+..
+.de ]-
+.rm [V [P [A [T [N [C [B [O [R [I [E [D
+..
+.ie \n(.V<1v \
+\{\
+. ds [. \s-2\v'-.4m'\f1
+. ds .] \v'.4m'\s+2\fP
+.\}
+.el \
+\{\
+. ds [. " [
+. ds .] ]
+.\}
+.\"
+.\" IDEAL
+.\"
+.de IS \" *** start ideal picture
+.nr g7 \\n(.u
+.ls 1
+..
+.de IF
+.if \\n(g7 .fi
+.ls
+..
+.de IE \" *** end ideal picture
+.if \\n(g7 .fi
+.ls
+..
+.\"
+.\" PIC
+.\"
+.de PS \" *** start picture: $1=height, $2=width in units or inches
+.sp 0.3
+.nr g7 \\$2
+.in (\\n(.lu-\\n(g7u)/2u
+.ne \\$1u
+.nr g7 \\n(.u
+.ls 1
+..
+.de PE \" *** end picture
+.ls
+.in
+.if \\n(g7 .fi
+.sp .6
+..
+.\"
+.\" GREMLIN
+.\"
+.de GS \" *** start gremlin picture
+.nr g7 (\\n(.lu-\\n(g1u)/2u
+.if "\\$1"L" .nr g7 \\n(.iu
+.if "\\$1"R" .nr g7 \\n(.lu-\\n(g1u
+.in \\n(g7u
+.nr g7 \\n(.u
+.ls 1
+.nf
+.ne \\n(g2u
+..
+.de GE \" *** end gremlin picture
+.GF
+.sp .6
+..
+.de GF \" *** finish gremlin picture; stay at top
+.ls
+.in
+.if \\n(g7 .fi
+..
+.\" *** FONT AIDS ***
+.de sz \" *** set point size and vertical spacing
+.ps \\$1
+.if \\n($r .@v
+.vs \\n(.sp*\\n($vu/100u \" default vs at pointsize + 20%
+..
+.de @v \" --- possibly set $v from $r
+.if (1i>=240u)&(1p<=\\n($r)&(\\n($r<=4p) .nr $v \\n($r00/1p
+..
+.de @V \" --- possibly set $V from $R
+.if (1i>=240u)&(1p<=\\n($R)&(\\n($R<=4p) .nr $V \\n($R00/1p
+..
+.de @E \" --- store in _F argument to \f for restoring font
+.ie \\n(.f<10 \
+. ds _F \\n(.f
+.el \
+\{\
+. ie \\n(.f<100&\n(.g \
+. ds _F (\\n(.f
+. el \
+. ds _F P
+.\}
+..
+.de r \" *** enter roman font
+.@E
+.ft 1
+.if \\n(.$ \&\\$1\f\\*(_F\\$2
+..
+.de i \" *** enter italic
+.@E
+.ft 2
+.if \\n(.$ \&\\$1\f\\*(_F\\$2
+..
+.de b \" *** enter boldface
+.@E
+.ft 3
+.if \\n(.$ \&\\$1\f\\*(_F\\$2
+..
+.de rb \" *** enter real boldface
+.@E
+.ft 3
+.if \\n(.$ \&\\$1\f\\*(_F\\$2
+..
+.de bi \" *** enter bold italic
+.@E
+.ft 4
+.if \\n(.$ \&\\$1\f\\*(_F\\$2
+..
+.de u \" *** enter underlined word
+\&\\$1\l'|0\(ul'\\$2
+..
+.\" a better version of u
+.if !\n(.g .ig
+.de u
+\Z'\\$1'\v'.25m'\D'l \w'\\$1'u 0'\v'-.25m'\\$2
+..
+.de q \" *** enter quoted word
+\&\\*(lq\\$1\\*(rq\\$2
+..
+.de bx \" *** enter boxed word
+\k~\(br\|\\$1\|\(br\l'|\\n~u\(rn'\l'|\\n~u\(ul'\^\\$2
+..
+.de sm \" *** print in smaller font
+\s-1\\$1\\s0\\$2
+..
+.de @F \" --- change font (0 -> no change)
+.nr ~ \\$1
+.if \\n~>0 \
+. ft \\n~
+.rr ~
+..
+.\" *** FOOTNOTING ***
+.de (f \" *** begin footnote
+.ec
+.if "\\n(.z"|f" .tm Line \\n(c. -- Illegal footnote nesting
+.ie "\\n(.z"" \
+\{\
+. nr _D \\n(dn
+. nr _0 1v+\\n(nlu
+. ev 2
+. da |f
+. in 0
+. xl \\n($lu-\\n(fuu
+. @F \\n(ff
+. sz \\n(fp
+. vs \\n(.sp*\\n($Vu/100u
+. if !\\n(?f \
+\{\
+. nr _b +1v \" allow space for $s
+. $s
+. \}
+. br
+. if \\n(.p-\\n(_b-\\n(_0-\\n(.h-1v-\\n(fs<0 \
+\{\
+. da\" \" won't fit on page at all
+. bc
+. if !\\n(?f \
+. rm |f
+. da |f
+.\" next five lines could be dropped if headers had their own environment
+. in 0 \" reset everything from .bc
+. xl \\n($lu-\\n(fuu
+. @F \\n(ff
+. sz \\n(fp
+. vs \\n(.sp*\\n($Vu/100u
+. if !\\n(?f \
+. $s
+. br
+. \}
+. rr _0
+. sp \\n(fsu
+. nr ?f 1
+. fi
+. if !"\\$1"_" \
+. ti \\n(fiu
+. if \n@>2 .tm << (f $f=\\n($f
+.\}
+.el \
+\{\
+. ev 2
+. in 0
+. xl \\n($lu-\\n(fuu
+. @F \\n(ff
+. sz \\n(fp
+. vs \\n(.sp*\\n($Vu/100u
+. fi
+\!.(f \\$1
+\!.@N
+.\}
+..
+.de @N \" --- set no fill mode in the top-level diversion
+.ie "\\n(.z"" .nf
+.el \!.@N
+..
+.de )f \" *** end footnote
+.ie "\\n(.z"|f" \
+\{\
+. if \\n* \
+. nr $f +1
+. ds * \\*{\\n($f\\*}\k*
+. nr * 0
+. in 0
+. da
+. ev
+. if \\n(_w<\\n(dl \
+. nr _w \\n(dl \" compute maximum fn width
+. nr _b +\\n(dn
+. ch @f -\\n(_bu
+. if \\n(.p-\\n(_b<=\\n(nl \
+. ch @f \\n(nlu+\n(.Vu
+. nr dn \\n(_D
+. rr _D
+.\}
+.el \
+\{\
+. br
+\!.)f
+. ev
+.\}
+..
+.@R ff
+.if \n(ff<=0 \
+. nr ff 1 \" footnote font: Times Roman
+.@R fp
+.if \n(fp<=0 \
+. nr fp 8 \" footnote pointsize
+.de $s \" $$$ footnote separator
+\l'2i'
+..
+.\" *** DELAYED TEXT ***
+.de (d \" *** begin delayed text
+.am |d )d
+.sp \\n(bsu
+..
+.de )d \" *** end delayed text
+.if \\n# \
+. nr $d +1
+.ds # [\\n($d]\k#
+.rr #
+..
+.de pd \" *** print delayed text
+.|d
+.rm |d
+.nr $d 1 1
+.ds # [1]\k#
+..
+.\" *** INDEXES (TABLE OF CONTENTS) ***
+.nr _x 0 1
+.af _x a
+.de (x \" *** begin index entry
+.if \n@>4 .tm >> (x, .z=\\n(.z
+.ds |X x
+.if \\n(.$>0 \
+. ds |X \\$1
+.ie "\\n(.z"" \
+. nr _z 0
+.el \
+. nr _z 1
+.@\\n(_z
+..
+.de @0 \" --- finish (x if no current diversion
+.am %\\*(|X )x
+.sp \\n(xsu
+.ti -\\n(piu
+..
+.de @1 \" --- finish (x if current diversion
+.if "\\n(_x"z" .nr _x 0
+.de =\\n+(_x )x
+..
+.de )x \" *** end index entry
+.if \n@>4 .tm >> )x, .z=\\n(.z
+.ie "\\n(.z"" \
+\{\
+. ds |x \\n%
+. if \\n(.$>0 \
+. ds |x \\$1
+. if "\\*(|x"_" \
+. ig ..
+. am %\\*(|X ..
+. if \w"\\$2">(\\n(.l-\\n(.i-\\n(.k) \
+. ti +\\n(xuu
+\\\\a\\\\t\\$2\\*(|x
+...
+. rm |x
+. rm |X
+.\}
+.el \
+\{\
+\!.(x \\*(|X
+\!\\\\*(=\\n(_x\\\\
+\!.)x \\$1 \\$2
+\!.rm =\\n(_x
+.\}
+..
+.de xp \" *** print the index
+.br
+.@C 2
+.ls 1
+.vs \\n(.sp*\\n($Vu/100u
+.fi
+.in +\\n(piu
+.ds |X x
+.if \\n(.$>0 \
+. ds |X \\$1
+.xl -(\\n(xuu+\w'...'u)
+.di |x
+.%\\*(|X
+.br
+.di
+.rm %\\*(|X
+.xl \\n($lu
+.rm |X
+.ev
+.nf
+.in 0
+.ta \\n(.lu-\\n(xuuR \\n(.luR
+.|x
+.fi
+.in
+.rm |x
+..
+.de +c \" *** begin chapter
+.ep \" force out footnotes
+.if \\n(?o:\\n(?a \
+\{\
+. bp \" force out a table or more footnote
+. rs
+. ep
+.\}
+.nr ?C 1
+.nr $f 1 1
+.ds * \\*{1\\*}\k*
+.if \\n(?R \
+. pn 1
+.bp
+.in \\n($iu \" reset the indent
+.rs
+.ie \\n(.$ \
+. $c "\\$1"
+.el \
+. sp 3
+..
+.de ++ \" *** declare chapter type
+.nr _0 0
+.if "\\$1"C" \
+. nr _0 1 \" chapter
+.if "\\$1"RC" \
+. nr _0 11 \" renumbered chapter
+.if "\\$1"A" \
+. nr _0 2 \" appendix
+.if "\\$1"RA" \
+. nr _0 12 \" renumbered appendix
+.if "\\$1"P" \
+. nr _0 3 \" preliminary material
+.if "\\$1"B" \
+. nr _0 4 \" bibliographic material
+.if "\\$1"AB" \
+. nr _0 5 \" abstract
+.if \\n(_0=0 \
+. tm Line \\n(c. -- Bad mode to .++
+.nr ?R 0
+.if \\n(_0>10 \
+.\{
+. nr ?R 1
+. nr _0 -10
+.\}
+.nr ch 0 1
+.if (\\n(_0=3):(\\n(_0=5) \
+. pn 1 \" must do before .ep
+.if !\\n(_0=\\n(_M .if \\n(_M=3 \
+. pn 1 \" must do before .ep
+.ep \" end page for correct page number types
+.if \\n(_0=1 \
+\{\
+. af ch 1
+. af % 1
+.\}
+.if \\n(_0=2 \
+\{\
+. af ch A
+. af % 1
+.\}
+.if \\n(_0=3 \
+. af % i
+.if \\n(_0=4 \
+. af % 1
+.if \\n(_0=5 \
+. af % 1
+.if \\n(.$>1 \
+. he \\$2
+.nr _M \\n(_0
+.rr _0
+..
+.de $c \" $$$ print chapter title
+.sz 12
+.ft 3
+.ce 1000
+.if \\n(_M<3 \
+. nr ch +1
+.ie \\n(_M=1 CHAPTER\ \ \\n(ch
+.el .if \\n(_M=2 APPENDIX\ \ \\n(ch
+.if \w"\\$1" .sp 3-\\n(.L
+.if \w"\\$1" \\$1
+.if (\\n(_M<3):(\w"\\$1") \
+. sp 4-\\n(.L
+.ce 0
+.ft
+.sz
+.ie \\n(_M=1 \
+. $C Chapter \\n(ch "\\$1"
+.el .if \\n(_M=2 \
+. $C Appendix \\n(ch "\\$1"
+..
+.de tp \" *** title page
+.hx
+.bp
+.br
+.rs
+.pn \\n%
+..
+.\" *** DATES ***
+.if \n(mo=1 .ds mo January
+.if \n(mo=2 .ds mo February
+.if \n(mo=3 .ds mo March
+.if \n(mo=4 .ds mo April
+.if \n(mo=5 .ds mo May
+.if \n(mo=6 .ds mo June
+.if \n(mo=7 .ds mo July
+.if \n(mo=8 .ds mo August
+.if \n(mo=9 .ds mo September
+.if \n(mo=10 .ds mo October
+.if \n(mo=11 .ds mo November
+.if \n(mo=12 .ds mo December
+.if \n(dw=1 .ds dw Sunday
+.if \n(dw=2 .ds dw Monday
+.if \n(dw=3 .ds dw Tuesday
+.if \n(dw=4 .ds dw Wednesday
+.if \n(dw=5 .ds dw Thursday
+.if \n(dw=6 .ds dw Friday
+.if \n(dw=7 .ds dw Saturday
+.ds td \*(mo \n(dy, 19\n(yr
+.\" *** PARAMETRIC INITIALIZATIONS ***
+.rr x
+.nr $v \n(.v00+\n(.sp-1/\n(.sp \" vs as percentage of ps for .sz request
+.nr $V \n($v \" same for displays & footnotes
+.nr hm 4v \" header margin
+.nr tm 7v \" top margin
+.nr bm 6v \" bottom margin
+.nr fm 3v \" footer margin
+.nr tf 3 \" title font: (real) Times Bold
+.nr tp 10 \" title point size
+.hy 14
+.nr bi 4m \" indent for blocks
+.nr pi 5n \" indent for paragraphs
+.nr pf 1 \" normal text font
+.nr pp 10 \" normal text point size
+.nr qi 4n \" indent for quotes
+.nr qp -1 \" down one point
+.nr ii 5n \" indent for .ip's and .np's
+.nr $m 1 \" max number of columns
+.nr $s 4n \" column separation
+.nr sf 3 \" section font -- Times Bold
+.nr sp 10 \" section title pointsize
+.nr ss 12p \" section prespacing
+.nr si 0 \" section indent
+.\" *** OTHER INITIALIZATION ***
+.\" GNU pic sets this register to 1, to indicate that \x should not be used.
+.@R 0x
+.ds { \v'-0.4m'\x'\\n(0x=0*-0.2m'\s-3
+.ds } \s0\v'0.4m'
+.\" for compatibility with traditional -me
+.\" (the first will work only in compatibility mode)
+.ds [ \*{
+.ds ] \*}
+.ds < \v'0.4m'\x'\\n(0x=0*0.2m'\s-3
+.ds > \s0\v'-0.4m'
+.ds - \(em
+.\" Avoid warnings from groff -ww.
+.@S |0
+.@S |1
+.@S |2
+.@S |3
+.@S $H
+.@S $0
+.@S $1
+.@S $2
+.@S $3
+.@S $4
+.@S $5
+.@S $6
+.@S $7
+.@S $8
+.@S $9
+.@S ..
+.@R po\" \" simulated page offset
+.@R $0\" \" section depth
+.@R $i\" \" paragraph base indent
+.@R $p\" \" numbered paragraph number
+.@R $r\" \" ratio of vs to ps (may override $v)
+.@R $R\" \" same for displays (may override $V)
+.@R df\" \" display font: same as surrounding text
+.@R so\" \" additional section title offset
+.@R fu\" \" footnote undent
+.@R bt\" \" block keep threshold
+.@R *\" \" has \** been referenced?
+.@R ?a\" \" pending floating keep at page top?
+.@R ?b\" \" pending floating keep at page bottom?
+.@R ?C\" \" at chapter header?
+.@R ?e\" \" in equation?
+.@R ?H\" \" suppress headers and footers next page?
+.@R ?I\" \" has the header trap been sprung?
+.@R ?n\" \" n1 mode?
+.@R ?o\" \" footnote overflow?
+.@R ?R\" \" renumbered chapter?
+.@R ?s\" \" skip next page?
+.@R ?T\" \" inside .TS H?
+.@R ?W\" \" wide floating keep at page bottom?
+.@R ?w\" \" wide floating keep at page top?
+.nr fi 0.3i
+.nr _o \n(.o
+.nr $b 3 \" bold
+.nr ps 0.35v
+.if \n(ps<\n(.V .nr ps \n(.V
+.nr bs \n(ps \" block pre/post spacing
+.nr qs \n(ps \" quote pre/post spacing
+.nr zs 1v \" float-block pre/postspacing
+.nr xs 0.2v \" index prespacing
+.nr xu 0.5i \" index undent
+.nr fs 0.2v \" footnote prespacing
+.nr es 0.5v \" equation pre/postspacing
+.if \n(es<\n(.V .nr es \n(.V
+.wh 0 @h \" set header
+.nr $l \n(.lu \" line length
+.nr _L \n(.lu \" line length of page
+.nr $c 1 \" current column number
+.nr $f 1 1 \" footnote number
+.ds * \*{1\*}\k*\" \" footnote "name"
+.nr $d 1 1 \" delayed text number
+.ds # [1]\k#\" \" delayed text "name"
+.nr _M 1 \" chapter mode is chapter
+.ds lq \(lq\" \" left quote
+.ds rq \(rq\" \" right quote
+.em @z
+.\" *** FOREIGN LETTERS AND SPECIAL CHARACTERS ***
+.ds #h ((1u-(\\\\n(.fu%2u))*0.13m)
+.ds #v 0.6m
+.\" \" accents
+.ds ' \k_\h'-(\\n(.wu*8/10-\*(#h)'\(aa\h'|\\n_u'
+.ds ` \k_\h'-(\\n(.wu*7/10-\*(#h)'\(ga\h'|\\n_u'
+.\" \" umlaut
+.ds : \k_\h'-(\\n(.wu*8/10-\*(#h+0.1m)'\v'-\*(#v'\z.\h'0.2m'.\h'|\\n_u'\v'\*(#v'
+.\" \" circumflex and tilde
+.ds ^ \k_\h'-(\\n(.wu-\*(#h-0.05m)'^\h'|\\n_u'
+.ds ~ \k_\h'-(\\n(.wu-\*(#h-0.05m)'~\h'|\\n_u'
+.\" \" cedilla and czech
+.ds , \k_\h'-(\\n(.wu)',\h'|\\n_u'
+.ds v \k_\h'-(\\n(.wu*9/10-\*(#h)'\v'-\*(#v'\s-4v\s0\v'\*(#v'\h'|\\n_u'
+.\" \" Norwegian A or angstrom
+.ds o \k_\h'-(\\n(.wu+\w'\(de'u-\*(#h)/2u'\v'-0.4n'\z\(de\v'0.4n'\h'|\\n_u'
+.\" \" there exists, for all
+.ds qe \s-2\v'0.45m'\z\(em\v'-0.625m'\z\(em\v'-0.625m'\(em\v'0.8m'\s0\h'-0.1m'\v'-0.05m'\(br\v'0.05m'\h'0.1m'
+.ds qa \z\e\h'0.35m'\z\(sl\h'-0.33m'\v'-0.3m'\s-4\(em\s0\v'0.3m'\h'0.15m'
+.rm #h #v
+.ll 6.0i
+.lt 6.0i
+.de @U
+.tm The \\$1 macro has been removed from this version of the -me macros.
+..
+.de lo
+.@U lo
+..
+.de th
+.@U th
+..
+.de ac
+.@U ac
+..
diff --git a/gnu/usr.bin/groff/tmac/tmac.latin1 b/gnu/usr.bin/groff/tmac/tmac.latin1
new file mode 100644
index 0000000..f33ea21
--- /dev/null
+++ b/gnu/usr.bin/groff/tmac/tmac.latin1
@@ -0,0 +1,101 @@
+.nr _C \n(.C
+.cp 0
+.de latin1-tr
+.if c\\$2 .if !c\\$1 .tr \\$1\\$2
+..
+.latin1-tr \[char161] \(r!
+.latin1-tr \[char162] \(ct
+.latin1-tr \[char163] \(Po
+.latin1-tr \[char164] \(Cs
+.latin1-tr \[char165] \(Ye
+.latin1-tr \[char166] \(bb
+.latin1-tr \[char167] \(sc
+.latin1-tr \[char168] \(ad
+.latin1-tr \[char169] \(co
+.latin1-tr \[char170] \(Of
+.latin1-tr \[char171] \(Fo
+.latin1-tr \[char172] \(no
+.latin1-tr \[char173] \(hy
+.latin1-tr \[char174] \(rg
+.latin1-tr \[char175] \(a-
+.latin1-tr \[char176] \(de
+.latin1-tr \[char177] \(+-
+.latin1-tr \[char178] \(S2
+.latin1-tr \[char179] \(S3
+.latin1-tr \[char180] \(aa
+.latin1-tr \[char181] \(*m
+.latin1-tr \[char182] \(ps
+.latin1-tr \[char183] \(md
+.latin1-tr \[char184] \(ac
+.latin1-tr \[char185] \(S1
+.latin1-tr \[char186] \(Om
+.latin1-tr \[char187] \(Fc
+.latin1-tr \[char188] \(14
+.latin1-tr \[char189] \(12
+.latin1-tr \[char190] \(34
+.latin1-tr \[char191] \(r?
+.latin1-tr \[char192] \(`A
+.latin1-tr \[char193] \('A
+.latin1-tr \[char194] \(^A
+.latin1-tr \[char195] \(~A
+.latin1-tr \[char196] \(:A
+.latin1-tr \[char197] \(oA
+.latin1-tr \[char198] \(AE
+.latin1-tr \[char199] \(,C
+.latin1-tr \[char200] \(`E
+.latin1-tr \[char201] \('E
+.latin1-tr \[char202] \(^E
+.latin1-tr \[char203] \(:E
+.latin1-tr \[char204] \(`I
+.latin1-tr \[char205] \('I
+.latin1-tr \[char206] \(^I
+.latin1-tr \[char207] \(:I
+.latin1-tr \[char208] \(-D
+.latin1-tr \[char209] \(~N
+.latin1-tr \[char210] \(`O
+.latin1-tr \[char211] \('O
+.latin1-tr \[char212] \(^O
+.latin1-tr \[char213] \(~O
+.latin1-tr \[char214] \(:O
+.latin1-tr \[char215] \(mu
+.latin1-tr \[char216] \(/O
+.latin1-tr \[char217] \(`U
+.latin1-tr \[char218] \('U
+.latin1-tr \[char219] \(^U
+.latin1-tr \[char220] \(:U
+.latin1-tr \[char221] \('Y
+.latin1-tr \[char222] \(TP
+.latin1-tr \[char223] \(ss
+.latin1-tr \[char224] \(`a
+.latin1-tr \[char225] \('a
+.latin1-tr \[char226] \(^a
+.latin1-tr \[char227] \(~a
+.latin1-tr \[char228] \(:a
+.latin1-tr \[char229] \(oa
+.latin1-tr \[char230] \(ae
+.latin1-tr \[char231] \(,c
+.latin1-tr \[char232] \(`e
+.latin1-tr \[char233] \('e
+.latin1-tr \[char234] \(^e
+.latin1-tr \[char235] \(:e
+.latin1-tr \[char236] \(`i
+.latin1-tr \[char237] \('i
+.latin1-tr \[char238] \(^i
+.latin1-tr \[char239] \(:i
+.latin1-tr \[char240] \(Sd
+.latin1-tr \[char241] \(~n
+.latin1-tr \[char242] \(`o
+.latin1-tr \[char243] \('o
+.latin1-tr \[char244] \(^o
+.latin1-tr \[char245] \(~o
+.latin1-tr \[char246] \(:o
+.latin1-tr \[char247] \(di
+.latin1-tr \[char248] \(/o
+.latin1-tr \[char249] \(`u
+.latin1-tr \[char250] \('u
+.latin1-tr \[char251] \(^u
+.latin1-tr \[char252] \(:u
+.latin1-tr \[char253] \('y
+.latin1-tr \[char254] \(Tp
+.latin1-tr \[char255] \(:y
+.cp \n(_C
diff --git a/gnu/usr.bin/groff/tmac/tmac.pic b/gnu/usr.bin/groff/tmac/tmac.pic
new file mode 100644
index 0000000..1177fc0
--- /dev/null
+++ b/gnu/usr.bin/groff/tmac/tmac.pic
@@ -0,0 +1,10 @@
+.de PS
+.br
+.sp .3v
+.ne 0\\$1+1v+\n(.Vu
+.in \\n(.lu-\\n(.iu-0\\$2/2u>?0
+..
+.de PE
+.in
+.sp .3v+.5m
+..
diff --git a/gnu/usr.bin/groff/tmac/tmac.ps b/gnu/usr.bin/groff/tmac/tmac.ps
new file mode 100644
index 0000000..4d954f4
--- /dev/null
+++ b/gnu/usr.bin/groff/tmac/tmac.ps
@@ -0,0 +1,53 @@
+.nr _C \n(.C
+.cp 0
+.ftr AX ABI
+.ftr KR BMR
+.ftr KI BMI
+.ftr KB BMB
+.ftr KX BMBI
+.ftr CW CR
+.ftr CO CI
+.ftr CX CBI
+.ftr H HR
+.ftr HO HI
+.ftr HX HBI
+.ftr Hr HNR
+.ftr Hi HNI
+.ftr Hb HNB
+.ftr Hx HNBI
+.ftr NX NBI
+.ftr PA PR
+.ftr PX PBI
+.ftr ZI ZCMI
+.ftr C CR
+.cflags 8 \(an
+.char \[radicalex] \h'-\w'\(sr'u'\[radicalex]\h'\w'\(sr'u'
+.char \(mo \h'.08m'\(mo\h'-.08m'
+.char \(nm \h'.08m'\(nm\h'-.08m'
+.char \[parenlefttp] \[parenlefttp]\h'.016m'
+.char \[parenleftbt] \[parenleftbt]\h'.016m'
+.char \[parenleftex] \[parenleftex]\h'.016m'
+.char \[parenrighttp] \[parenrighttp]\h'.016m'
+.char \[parenrightbt] \[parenrightbt]\h'.016m'
+.char \[parenrightex] \[parenrightex]\h'.016m'
+.if !c\[va] .char \[va] \o'\[ua]\[da]'
+.if !c\[ci] \
+.char \[ci] \v'-.25m'\h'.05m'\D'c .5m'\h'.05m'\v'.25m'
+.if !c\[sq] \
+.char \[sq] \h'.05m'\D'l .5m 0'\D'l 0 -.5m'\D'l -.5m 0'\D'l 0 .5m'\h'.55m'
+.if !c\[ru] .char \[ru] \D'l .5m 0'
+.if !c\[ul] .char \[ul] \v'.25m'\D'l .5m 0'\v'-.25m'
+.if !c\[br] .char \[br] \Z'\v'.25m'\D'l 0 -1m''
+.if !c\[rn] .char \[rn] \v'-.75m'\D'l .5m 0'\v'.75m'
+.if !c\[or] .char \[or] \h'.1m'\Z'\D'l 0 -.675m''\h'.1m'
+.if !c\[Fi] .char \[Fi] ffi
+.if !c\[Fl] .char \[Fl] ffl
+.if !c\[ff] .char \[ff] ff
+.if !c\[ij] .char \[ij] ij
+.if !c\[IJ] .char \[IJ] IJ
+.if !c\[tm] .char \[tm] \s-3\v'-.3m'TM\v'+.3m'\s+3
+.\" pic tests this register to see whether it should use \X'ps:...'
+.nr 0p 1
+.cp \n(_C
+.if !\n(.C .mso tmac.pspic
+.do mso tmac.psold
diff --git a/gnu/usr.bin/groff/tmac/tmac.psatk b/gnu/usr.bin/groff/tmac/tmac.psatk
new file mode 100644
index 0000000..b59d23a
--- /dev/null
+++ b/gnu/usr.bin/groff/tmac/tmac.psatk
@@ -0,0 +1,61 @@
+.\" Implementation of the ATK PB and PE macros for use with groff and grops.
+.\" Load this after tmac.atk.
+.nr zT 0
+.if '\*(.T'ps' .nr zT 1
+.nr psatk-unit 1p
+.de psatk-defs
+ps: mdef 5
+/PB {
+ /saved save def
+ currentpoint translate
+ \n[psatk-unit] u -\n[psatk-unit] u scale
+ userdict begin
+ /showpage {} def
+} bind def
+/PE {
+ end
+ saved restore
+} bind def
+/troffadjust {
+ pop 0
+} bind def
+..
+.de PB
+.ne \\$1p
+.nr zT \\n(zT>0
+\\*[PB\\n(zT]\\
+..
+.de PE
+\\*[PE\\n(zT]\\
+..
+.ds PB0
+.\" The last line before the "'PE" is "\}" rather than ".\}". This
+.\" would cause a spurious space to be introduced before any picture
+.\" that was the first thing on a line. So we have to catch that and
+.\" remove it.
+.de PB1
+.ev psatk
+.fi
+.di psatk-mac
+\!ps: exec PB
+..
+.de PE0
+\v'-.75m'\
+\D'l \\$1p 0'\D'l 0 \\$2p'\D'l -\\$1p 0'\D'l 0 -\\$2p'\
+\h'\\$1p'\v'.75m'\x'\\$2p-1m>?0'\c
+..
+.ds psatk-init \Y[psatk-defs]
+.de PE1
+\!PE
+.di
+.di null
+.br
+.di
+.rm null
+.ev
+\v'-.75m'\
+\\*[psatk-init]\Y[psatk-mac]\
+\h'\\$1p'\v'.75m'\x'\\$2p-1m>?0'\c
+.rm psatk-mac
+.if \\n(.P .ds psatk-init
+..
diff --git a/gnu/usr.bin/groff/tmac/tmac.psfig b/gnu/usr.bin/groff/tmac/tmac.psfig
new file mode 100644
index 0000000..5f4111c
--- /dev/null
+++ b/gnu/usr.bin/groff/tmac/tmac.psfig
@@ -0,0 +1,87 @@
+.\" These are macros to make psfig work with groff.
+.\" They require that psfig be patched as described in ../grops/psfig.diff.
+.de psfig-defs
+ps: mdef 100
+
+% wid ht llx lly urx ury psfigstart -
+
+/psfigstart {
+ /level1 save def
+ /ury exch def
+ /urx exch def
+ /lly exch def
+ /llx exch def
+ /ht exch u def
+ /wid exch u def
+ currentpoint ht add translate
+ wid urx llx sub div ht ury lly sub div neg scale
+ llx neg lly neg translate
+
+ % set the graphics state to default values
+ 0 setgray
+ 0 setlinecap
+ 1 setlinewidth
+ 0 setlinejoin
+ 10 setmiterlimit
+ [] 0 setdash
+ newpath
+ /showpage {} def
+} bind def
+
+% psfigclip -
+
+/psfigclip {
+ currentpoint newpath
+ llx lly moveto
+ urx lly lineto
+ urx ury lineto
+ llx ury lineto
+ closepath clip
+ newpath moveto
+} bind def
+
+% psfigend -
+
+/psfigend {
+ level1 restore
+} bind def
+
+% globalstart -
+
+/globalstart {
+ % save the current space code on the stack
+ SC
+ level0 restore
+} bind def
+
+% globalend -
+
+/globalend {
+ end
+ BP
+ /SC exch def
+ DEFS begin
+} bind def
+..
+.de psfig-init
+.if \\n[.P] \{\
+\Y[psfig-defs]
+. br
+. sp -1
+. ds psfig-init\" empty
+. rm psfig-defs
+.\}
+..
+.de F+
+.br
+.psfig-init
+.nr psfig-fill \\n[.u]
+.nf
+.sp -.5
+.if !\\n[.$] .ce 9999
+..
+.de F-
+.br
+.ce 0
+.if \\n[psfig-fill] .fi
+..
diff --git a/gnu/usr.bin/groff/tmac/tmac.psnew b/gnu/usr.bin/groff/tmac/tmac.psnew
new file mode 100644
index 0000000..e13bdb8
--- /dev/null
+++ b/gnu/usr.bin/groff/tmac/tmac.psnew
@@ -0,0 +1,26 @@
+.\" Undo the effect of tmac.psold. This gives access to the additional
+.\" characters that are present in the text fonts of newer PostScript
+.\" printers. It is a bad idea to use this if you are going to
+.\" distribute the resulting PostScript output to others.
+.nr _C \n(.C
+.cp 0
+.rchar \('y\('Y\(12\(14\(34\(S1\(S2\(S3\(bb\(de\(Tp\(TP\(-D\(Sd
+.tr \[char166]\[char166]
+.tr \[char176]\[char176]
+.tr \[char177]\[char177]
+.tr \[char178]\[char178]
+.tr \[char179]\[char179]
+.tr \[char181]\[char181]
+.tr \[char185]\[char185]
+.tr \[char188]\[char188]
+.tr \[char189]\[char189]
+.tr \[char190]\[char190]
+.tr \[char208]\[char208]
+.tr \[char215]\[char215]
+.tr \[char221]\[char221]
+.tr \[char222]\[char222]
+.tr \[char240]\[char240]
+.tr \[char247]\[char247]
+.tr \[char253]\[char253]
+.tr \[char254]\[char254]
+.cp \n(_C
diff --git a/gnu/usr.bin/groff/tmac/tmac.psold b/gnu/usr.bin/groff/tmac/tmac.psold
new file mode 100644
index 0000000..04a5f6d
--- /dev/null
+++ b/gnu/usr.bin/groff/tmac/tmac.psold
@@ -0,0 +1,60 @@
+.\" In the newer PostScript printers, the text fonts contain all ISO Latin-1
+.\" characters. The font description files that comes with groff match
+.\" these fonts. The text fonts in older PostScript printers are missing
+.\" some of these characters. This file prevents those characters from
+.\" being used. This will allow the PostScript output to be printed on both
+.\" old and new printers. The effect of this file can be undone by
+.\" tmac.psnew.
+.nr _C \n(.C
+.cp 0
+.\" Define an accented character.
+.de ps-achar
+.\" Note that character definitions are always interpreted with
+.\" compatibility mode off.
+.char \\$1 \\$3\
+\k[acc]\
+\h'(u;-\w'\\$2'-\w'\\$3'/2+\\\\n[skw]+(\w'x'*0)-\\\\n[skw])'\
+\v'(u;\w'x'*0+\\\\n[rst]+(\w'\\$3'*0)-\\\\n[rst])'\
+\\$2\
+\v'(u;\w'x'*0-\\\\n[rst]+(\w'\\$3'*0)+\\\\n[rst])'\
+\h'|\\\\n[acc]u'
+.ie '\\$3'\(.i' .hcode \\$1i
+.el .hcode \\$1\\$3
+..
+.ps-achar \['y] \(aa y
+.ps-achar \['Y] \(aa Y
+.char \[12] \v'-.7m\s[\\n(.s*6u/10u]+.7m'1\v'-.7m\s0+.7m'\
+\(f/\s[\\n(.s*6u/10u]2\s0
+.char \[14] \v'-.7m\s[\\n(.s*6u/10u]+.7m'1\v'-.7m\s0+.7m'\
+\(f/\s[\\n(.s*6u/10u]4\s0
+.char \[34] \v'-.7m\s[\\n(.s*6u/10u]+.7m'3\v'-.7m\s0+.7m'\
+\(f/\s[\\n(.s*6u/10u]4\s0
+.char \[S1] \v'-.2m'\s-31\s+3\v'+.2m'
+.char \[S2] \v'-.2m'\s-32\s+3\v'+.2m'
+.char \[S3] \v'-.2m'\s-33\s+3\v'+.2m'
+.char \[bb] |
+.char \[de] \fS\(de
+.char \[-D] \Z'\v'-.1m'-'D
+.char \[TP] \
+I\h'-.25m'\v'-.33m'\s'\En(.s*6u/10u'\v'.33m'D\v'-.33m'\s0\v'.33m'
+.char \[Sd] \Z'\v'-.3m'\h'.2m'-'\(pd
+.char \[Tp] \zlp
+.tr \[char166]\[bb]
+.tr \[char176]\[de]
+.tr \[char177]\[+-]
+.tr \[char178]\[S2]
+.tr \[char179]\[S3]
+.tr \[char181]\[*m]
+.tr \[char185]\[S1]
+.tr \[char188]\[14]
+.tr \[char189]\[12]
+.tr \[char190]\[34]
+.tr \[char208]\[-D]
+.tr \[char215]\[mu]
+.tr \[char221]\['Y]
+.tr \[char222]\[TP]
+.tr \[char240]\[Sd]
+.tr \[char247]\[di]
+.tr \[char253]\['y]
+.tr \[char254]\[Tp]
+.cp \n(_C
diff --git a/gnu/usr.bin/groff/tmac/tmac.pspic b/gnu/usr.bin/groff/tmac/tmac.pspic
new file mode 100644
index 0000000..a9f53b6
--- /dev/null
+++ b/gnu/usr.bin/groff/tmac/tmac.pspic
@@ -0,0 +1,57 @@
+.\" Define the PSPIC macro.
+.\" When used other than with -Tps, it will draw a box around where
+.\" the picture would go.
+.de ps-bb
+.nr ps-nargs \\n[.$]
+.if \\n[ps-nargs]=4 \{\
+. nr ps-llx 0\\$1
+. nr ps-lly 0\\$2
+. nr ps-urx 0\\$3
+. nr ps-ury 0\\$4
+.\}
+..
+.de PSPIC
+.nr ps-offset-mode 0
+.if '\\$1'-L' \{\
+. nr ps-offset-mode 1
+. shift
+.\}
+.if '\\$1'-R' \{\
+. nr ps-offset-mode 2
+. shift
+.\}
+.if '\\$1'-I' \{\
+. nr ps-offset-mode 3
+. nr ps-offset (m;\\$2)
+. shift 2
+.\}
+.br
+.sy echo .ps-bb `psbb \\$1` >/tmp/psbb\\n[$$]
+.so /tmp/psbb\\n[$$]
+.if \\n[ps-nargs]=4 \{\
+. nr ps-wid (\\n[ps-urx]-\\n[ps-llx])
+. nr ps-ht (\\n[ps-ury]-\\n[ps-lly])
+. if \\n[ps-wid]<0 .nr ps-wid 0-\\n[ps-wid]
+. if \\n[ps-ht]<0 .nr ps-ht 0-\\n[ps-ht]
+. ie \\n[.$]>=2 .nr ps-deswid (i;\\$2)
+. el .nr ps-deswid \\n[.l]-\\n[.i]<?\\n[ps-wid]p
+. ie \\n[.$]>=3 .nr ps-desht (i;\\$3)
+. el .nr ps-desht \\n[ps-deswid]*1000+(\\n[ps-wid]/2)/\\n[ps-wid]\
+*\\n[ps-ht]+500/1000
+. ne \\n[ps-desht]u+1v
+. if \\n[ps-offset-mode]=0 .nr ps-offset \\n[.l]-\\n[.i]-\\n[ps-deswid]/2
+. if \\n[ps-offset-mode]=1 .nr ps-offset 0
+. if \\n[ps-offset-mode]=2 .nr ps-offset \\n[.l]-\\n[.i]-\\n[ps-deswid]
+. ie \\n[.$]>=3 .ds ps-desht \\n[ps-desht]
+. el .ds ps-desht \" empty
+\h'\\n[ps-offset]u'\
+\X'ps: invis'\
+\Z'\D'p 0 \\n[ps-desht]u \\n[ps-deswid]u 0 0 -\\n[ps-desht]u''\
+\X'ps: endinvis'\
+\v'\\n[ps-desht]u'\X'ps: import \\$1 \
+\\n[ps-llx] \\n[ps-lly] \\n[ps-urx] \\n[ps-ury] \\n[ps-deswid] \\*[ps-desht]'
+. br
+. sp \\n[ps-desht]u
+.\}
+.sy rm /tmp/psbb\\n[$$]
+..
diff --git a/gnu/usr.bin/groff/tmac/tmac.s b/gnu/usr.bin/groff/tmac/tmac.s
new file mode 100644
index 0000000..8807a23
--- /dev/null
+++ b/gnu/usr.bin/groff/tmac/tmac.s
@@ -0,0 +1,1844 @@
+.\" -*- nroff -*-
+.ig
+Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
+ Written by James Clark (jjc@jclark.com)
+
+This file is part of groff.
+
+groff is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
+
+groff is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License along
+with groff; see the file COPYING. If not, write to the Free Software
+Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+..
+.if !\n(.g .ab These ms macros require groff.
+.if \n(.C \
+. ab The groff ms macros do not work in compatibility mode.
+.\" Enable warnings. You can delete this if you want.
+.warn
+.\" See if already loaded.
+.if r GS .nx
+.nr GS 1
+.de @error
+.tm \\n(.F:\\n(.c: macro error: \\$*
+..
+.de @warning
+.tm \\n(.F:\\n(.c: macro warning: \\$*
+..
+.de @fatal
+.ab \\n(.F:\\n(.c: fatal macro error: \\$*
+..
+.de @not-implemented
+.@error sorry, \\$0 not implemented
+.als \\$0 @nop
+..
+.als TM @not-implemented
+.als CT @not-implemented
+.de @nop
+..
+.de @init
+.nr PO \\n(.o
+.\" a non-empty environment
+.ev ne
+\c
+.ev
+.ev nf
+'nf
+.ev
+..
+.ds REFERENCES References
+.ds ABSTRACT ABSTRACT
+.ds TOC Table of Contents
+.ds MONTH1 January
+.ds MONTH2 February
+.ds MONTH3 March
+.ds MONTH4 April
+.ds MONTH5 May
+.ds MONTH6 June
+.ds MONTH7 July
+.ds MONTH8 August
+.ds MONTH9 September
+.ds MONTH10 October
+.ds MONTH11 November
+.ds MONTH12 December
+.ds MO \\*[MONTH\n[mo]]
+.nr *year \n[yr]+1900
+.ds DY \n[dy] \*[MO] \n[*year]
+.de ND
+.if \\n[.$] .ds DY "\\$*
+..
+.de DA
+.if \\n[.$] .ds DY "\\$*
+.ds CF \\*[DY]
+..
+.\" indexing
+.de IX
+.tm \\$1\t\\$2\t\\$3\t\\$4 ... \\n[PN]
+..
+.\" print an error message and then try to recover
+.de @error-recover
+.@error \\$@ (recovering)
+.nr *pop-count 0
+.while !'\\n(.z'' \{\
+. \"@warning automatically terminating diversion \\n(.z
+. ie d @div-end!\\n(.z .@div-end!\\n(.z
+. el .*div-end-default
+. nr *pop-count +1
+. \" ensure that we don't loop forever
+. if \\n[*pop-count]>20 .@fatal recovery failed
+.\}
+.while !'\\n[.ev]'0' .ev
+.par@reset-env
+.par@reset
+..
+.de *div-end-default
+.ds *last-div \\n(.z
+.br
+.di
+.ev nf
+.\\*[*last-div]
+.ev
+..
+.\" ****************************
+.\" ******** module cov ********
+.\" ****************************
+.\" Cover sheet and first page.
+.de cov*err-not-after-first-page
+.@error \\$0 is not allowed after the first page has started
+..
+.de cov*err-not-before-tl
+.@error \\$0 is not allowed before TL
+..
+.de cov*err-not-again
+.@error \\$0 is not allowed more than once
+..
+.de cov*err-not-after-ab
+.@error \\$0 is not allowed after first AB, LP, PP, IP, SH or NH
+..
+.als AU cov*err-not-before-tl
+.als AI cov*err-not-before-tl
+.als AB cov*err-not-before-tl
+.de cov*first-page-init
+.rm cov*first-page-init
+.par@init
+.als RP cov*err-not-after-first-page
+.@init
+.ie \\n[cov*rp-format] \{\
+. pg@cs-top
+. als FS cov*FS
+. als FE cov*FE
+.\}
+.el \{\
+. pg@top
+. als FS @FS
+. als FE @FE
+.\}
+.wh 0 pg@top
+..
+.wh 0 cov*first-page-init
+.\" This handles the case where FS occurs before TL or LP.
+.de FS
+.br
+\\*[FS]\\
+..
+.nr cov*rp-format 0
+.nr cov*rp-no 0
+.\" released paper format
+.de RP
+.nr cov*rp-format 1
+.if \\n[.$] .if '\\$1'no' .nr cov*rp-no 1
+.pn 0
+..
+.de TL
+.br
+.als TL cov*err-not-again
+.rn @AB AB
+.rn @AU AU
+.rn @AI AI
+.di cov*tl-div
+.par@reset
+.ft B
+.ps +2
+.vs +3p
+.ll (u;\\n[LL]*5/6)
+.nr cov*n-au 0
+..
+.de @AU
+.par@reset
+.if !'\\n(.z'' \{\
+. br
+. di
+.\}
+.nr cov*n-au +1
+.di cov*au-div!\\n[cov*n-au]
+.nf
+.ft I
+.ps \\n[PS]
+..
+.de @AI
+.par@reset
+.if !'\\n(.z'' \{\
+. br
+. di
+.\}
+.ie !\\n[cov*n-au] .@error AI before AU
+.el \{\
+. di cov*ai-div!\\n[cov*n-au]
+. nf
+. ft R
+. ps \\n[PS]
+.\}
+..
+.de LP
+.if !'\\n[.z]'' \{\
+. br
+. di
+.\}
+.br
+.cov*ab-init
+.cov*print
+\\*[\\$0]\\
+..
+.als IP LP
+.als PP LP
+.als XP LP
+.als NH LP
+.als SH LP
+.als MC LP
+.als RT LP
+.als XS LP
+.de cov*ab-init
+.als cov*ab-init @nop
+.als LP @LP
+.als IP @IP
+.als PP @PP
+.als XP @XP
+.als RT @RT
+.als XS @XS
+.als SH @SH
+.als NH @NH
+.als QP @QP
+.als RS @RS
+.als RE @RE
+.als QS @QS
+.als QE @QE
+.als MC @MC
+.als EQ @EQ
+.als EN @EN
+.als AB cov*err-not-after-ab
+.als AU par@AU
+.als AI par@AI
+.als TL par@TL
+..
+.de @AB
+.if !'\\n(.z'' \{\
+. br
+. di
+.\}
+.cov*ab-init
+.di cov*ab-div
+.par@ab-indent
+.par@reset
+.if !'\\$1'no' \{\
+. ft I
+. ce 1
+\\*[ABSTRACT]
+. sp
+. ft R
+.\}
+.ns
+.@PP
+..
+.de AE
+.ie '\\n(.z'cov*ab-div' \{\
+. als AE cov*err-not-again
+. br
+. di
+.\" nr cov*ab-height \\n[dn]
+. par@reset-env
+. par@reset
+. cov*print
+.\}
+.el .@error AE without AB
+..
+.de @div-end!cov*ab-div
+.AE
+..
+.de cov*print
+.als cov*print @nop
+.ie d cov*tl-div \{\
+. ie \\n[cov*rp-format] .cov*rp-print
+. el .cov*draft-print
+.\}
+.el \{\
+. if \\n[cov*rp-format] \{\
+. @warning RP format but no TL
+. bp 1
+. als FS @FS
+. als FE @FE
+. \}
+. br
+.\}
+..
+.de cov*rp-print
+.nr cov*page-length \\n[.p]
+.pl 1000i
+.cov*tl-au-print
+.sp 3
+.if d cov*ab-div \{\
+. nf
+. cov*ab-div
+.\}
+.sp 3
+.par@reset
+\\*[DY]
+.br
+.if \\n[cov*fn-height] \{\
+. sp |(u;\\n[cov*page-length]-\\n[FM]\
+-\\n[cov*fn-height]-\\n[fn@sep-dist]>?\\n[nl])
+. fn@print-sep
+. ev nf
+. cov*fn-div
+. ev
+. ie \\n[cov*rp-no] .rm cov*fn-div
+. el \{\
+. rn cov*fn-div fn@overflow-div
+. nr fn@have-overflow 1
+. \}
+.\}
+.als FS @FS
+.als FE @FE
+.\" If anything was printed below where the footer line is normally printed,
+.\" then that's an overflow.
+.if -\\n[FM]/2+1v+\\n[cov*page-length]<\\n[nl] .@error cover sheet overflow
+.pl \\n[cov*page-length]u
+.bp 1
+.if !\\n[cov*rp-no] .cov*tl-au-print
+.rs
+.sp 1
+..
+.de cov*draft-print
+.cov*tl-au-print
+.if d cov*ab-div \{\
+. nf
+. sp 2
+. cov*ab-div
+.\}
+.sp 1
+..
+.de cov*tl-au-print
+.par@reset
+.nf
+.rs
+.sp 3
+.ce 9999
+.cov*tl-div
+.nr cov*i 1
+.nr cov*sp 1v
+.while \\n[cov*i]<=\\n[cov*n-au] \{\
+. sp \\n[cov*sp]u
+. cov*au-div!\\n[cov*i]
+. ie d cov*ai-div!\\n[cov*i] \{\
+. sp .5v
+. cov*ai-div!\\n[cov*i]
+. nr cov*sp 1v
+. \}
+. el .nr cov*sp .5v
+. nr cov*i +1
+.\}
+.ce 0
+..
+.nr cov*fn-height 0
+.nr cov*in-fn 0
+.\" start of footnote on cover
+.de cov*FS
+.if \\n[cov*in-fn] \{\
+. @error nested FS
+. FE
+.\}
+.nr cov*in-fn 1
+.ev fn
+.par@reset-env
+.da cov*fn-div
+.if !\\n[cov*fn-height] .ns
+.ie \\n[.$] .FP "\\$1" no
+.el .@LP
+..
+.de @div-end!cov*fn-div
+.cov*FE
+..
+.\" end of footnote on cover
+.de cov*FE
+.ie '\\n(.z'cov*fn-div' \{\
+. br
+. ev
+. di
+. nr cov*in-fn 0
+. nr cov*fn-height +\\n[dn]
+.\}
+.el .@error FE without matching FS
+..
+.\" ***************************
+.\" ******** module pg ********
+.\" ***************************
+.\" Page-level formatting.
+.\" > 0 if we have a footnote on the current page
+.nr pg@fn-flag 0
+.nr pg@colw 0
+.nr pg@fn-colw 0
+.nr HM 1i
+.nr FM 1i
+.ds LF
+.ds CF
+.ds RF
+.ds LH
+.ds CH -\\n[PN]-
+.ds RH
+.ds pg*OH '\\*[LH]'\\*[CH]'\\*[RH]'
+.ds pg*EH '\\*[LH]'\\*[CH]'\\*[RH]'
+.ds pg*OF '\\*[LF]'\\*[CF]'\\*[RF]'
+.ds pg*EF '\\*[LF]'\\*[CF]'\\*[RF]'
+.de OH
+.ds pg*\\$0 "\\$*
+..
+.als EH OH
+.als OF OH
+.als EF OH
+.de PT
+.ie \\n%=1 .if \\n[pg*P1] .tl \\*[pg*OH]
+.el \{\
+. ie o .tl \\*[pg*OH]
+. el .tl \\*[pg*EH]
+.\}
+..
+.de BT
+.ie o .tl \\*[pg*OF]
+.el .tl \\*[pg*EF]
+..
+.nr pg*P1 0
+.de P1
+.nr pg*P1 1
+..
+.wh -\n[FM]u pg@bottom
+.wh -\n[FM]u/2u pg*footer
+.nr MINGW 2n
+.nr pg@ncols 1
+.de @MC
+.if !'\\n(.z'' .error-recover MC while diversion open
+.br
+.ie \\n[pg@ncols]>1 .pg@super-eject
+.el \{\
+. \" flush out any floating keeps
+. while \\n[kp@tail]>\\n[kp@head] \{\
+. rs
+. bp
+. \}
+.\}
+.ie !\\n(.$ \{\
+. nr pg@colw \\n[LL]*7/15
+. nr pg*gutw \\n[LL]-(2*\\n[pg@colw])
+. nr pg@ncols 2
+.\}
+.el \{\
+. nr pg@colw (n;\\$1)<?\\n[LL]
+. ie \\n[.$]<2 .nr pg*gutw \\n[MINGW]
+. el .nr pg*gutw (n;\\$2)
+. nr pg@ncols \\n[LL]-\\n[pg@colw]/(\\n[pg@colw]+\\n[pg*gutw])+1
+. ie \\n[pg@ncols]>1 \
+. nr pg*gutw \\n[LL]-(\\n[pg@ncols]*\\n[pg@colw])/(\\n[pg@ncols]-1)
+. el .nr pg*gutw 0
+.\}
+.mk pg*col-top
+.ns
+.nr pg*col-num 0
+.nr pg@fn-colw \\n[pg@colw]*5/6
+.par@reset
+..
+.de 2C
+.MC
+..
+.de 1C
+.MC \\n[LL]u
+..
+.\" top of page macro
+.de pg@top
+.ch pg*footer -\\n[FM]u/2u
+.nr PN \\n%
+.nr pg*col-num 0
+.nr pg@fn-bottom-margin 0
+.nr pg*saved-po \\n[PO]
+.po \\n[PO]u
+.ev h
+.par@reset
+.sp (u;\\n[HM]/2)
+.PT
+.sp |\\n[HM]u
+.if d HD .HD
+.mk pg@header-bottom
+.ev
+.mk pg*col-top
+.pg*start-col
+..
+.de pg*start-col
+.\" Handle footnote overflow before floating keeps, because the keep
+.\" might contain an embedded footnote.
+.fn@top-hook
+.kp@top-hook
+.tbl@top-hook
+.ns
+..
+.de pg@cs-top
+.sp \\n[HM]u
+.\" move pg@bottom and pg*footer out of the way
+.ch pg@bottom \\n[.p]u*2u
+.ch pg*footer \\n[.p]u*2u
+.ns
+..
+.de pg@bottom
+.tbl@bottom-hook
+.if \\n[pg@fn-flag] .fn@bottom-hook
+.nr pg*col-num +1
+.ie \\n[pg*col-num]<\\n[pg@ncols] .pg*end-col
+.el .pg*end-page
+..
+.de pg*end-col
+'sp |\\n[pg*col-top]u
+.po (u;\\n[pg*saved-po]+(\\n[pg@colw]+\\n[pg*gutw]*\\n[pg*col-num]))
+.\"po +(u;\\n[pg@colw]+\\n[pg*gutw])
+.pg*start-col
+..
+.de pg*end-page
+.po \\n[pg*saved-po]u
+.\" Make sure we don't exit if there are still floats or footnotes left-over.
+.ie \\n[kp@head]<\\n[kp@tail]:\\n[fn@have-overflow] \{\
+. \" Switching environments ensures that we don't get an unnecessary
+. \" blank line at the top of the page.
+. ev ne
+' bp
+. ev
+.\}
+.el \{\
+. \" If the text has ended and there are no more footnotes or keeps, exit.
+. if \\n[pg@text-ended] .ex
+. if r pg*next-number \{\
+. pn \\n[pg*next-number]
+. rr pg*next-number
+. if d pg*next-format \{\
+. af PN \\*[pg*next-format]
+. rm pg*next-format
+. \}
+. \}
+' bp
+.\}
+..
+.\" pg@begin number format
+.de pg@begin
+.ie \\n[.$]>0 \{\
+. nr pg*next-number (;\\$1)
+. ie \\n[.$]>1 .ds pg*next-format \\$2
+. el .rm pg*next-format
+.\}
+.el .rr pg*next-number
+.pg@super-eject
+..
+.\" print the footer line
+.de pg*footer
+.ev h
+.par@reset
+.BT
+.ev
+..
+.\" flush out any keeps or footnotes
+.de pg@super-eject
+.br
+.if !'\\n(.z'' .@error-recover diversion open while ejecting page
+.\" Make sure we stay in the end macro while there is still footnote overflow
+.\" left, or floating keeps.
+.while \\n[kp@tail]>\\n[kp@head]:\\n[pg@fn-flag] \{\
+. rs
+. bp
+.\}
+.bp
+..
+.nr pg@text-ended 0
+.de pg@end-text
+.br
+.nr pg@text-ended 1
+.pg@super-eject
+..
+.em pg@end-text
+.\" ***************************
+.\" ******** module fn ********
+.\" ***************************
+.\" Footnotes.
+.nr fn@sep-dist 8p
+.ev fn
+.\" Round it vertically
+.vs \n[fn@sep-dist]u
+.nr fn@sep-dist \n[.v]
+.ev
+.nr fn*text-num 0 1
+.nr fn*note-num 0 1
+.ds * \\*[par@sup-start]\En+[fn*text-num]\\*[par@sup-end]
+.nr fn*open 0
+.\" normal FS
+.de @FS
+.ie \\n[.$] .fn*do-FS "\\$1" no
+.el \{\
+. ie \\n[fn*text-num]>\\n[fn*note-num] .fn*do-FS \\n+[fn*note-num]
+. el .fn*do-FS
+.\}
+..
+.\" Second argument of `no' means don't embellish the first argument.
+.de fn*do-FS
+.if \\n[fn*open] .@error-recover nested FS
+.nr fn*open 1
+.if \\n[.u] \{\
+. \" Ensure that the first line of the footnote is on the same page
+. \" as the reference. I think this is minimal.
+. ev fn
+. nr fn*need 1v
+. ev
+. ie \\n[pg@fn-flag] .nr fn*need +\\n[fn:PD]
+. el .nr fn*need +\\n[fn@sep-dist]
+. ne \\n[fn*need]u+\\n[.V]u>?0
+.\}
+.ev fn
+.par@reset-env
+.fn*start-div
+.par@reset
+.ie \\n[.$] .FP \\$@
+.el .@LP
+..
+.de @FE
+.ie !\\n[fn*open] .@error FE without FS
+.el \{\
+. nr fn*open 0
+. br
+. ev
+. fn*end-div
+.\}
+..
+.nr fn@have-overflow 0
+.\" called at the top of each column
+.de fn@top-hook
+.nr fn*max-width 0
+.nr fn*page-bottom-pos 0-\\n[FM]-\\n[pg@fn-bottom-margin]
+.ch pg@bottom \\n[fn*page-bottom-pos]u
+.if \\n[fn@have-overflow] \{\
+. nr fn@have-overflow 0
+. fn*start-div
+. ev nf
+. fn@overflow-div
+. ev
+. fn*end-div
+.\}
+..
+.\" This is called at the bottom of the column if pg@fn-flag is set.
+.de fn@bottom-hook
+.nr pg@fn-flag 0
+.nr fn@have-overflow 0
+.nr fn@bottom-pos \\n[.p]-\\n[FM]-\\n[pg@fn-bottom-margin]+\\n[.v]
+.ev fn
+.nr fn@bottom-pos -\\n[.v]
+.ev
+.ie \\n[nl]+\\n[fn@sep-dist]+\n[.V]>\\n[fn@bottom-pos] \{\
+. rn fn@div fn@overflow-div
+. nr fn@have-overflow 1
+.\}
+.el \{\
+. if \\n[pg@ncols]>1 \
+. if \\n[fn*max-width]>\\n[pg@fn-colw] \
+. nr pg@fn-bottom-margin \\n[.p]-\\n[FM]-\\n[nl]+1v
+. wh \\n[fn@bottom-pos]u fn*catch-overflow
+. fn@print-sep
+. ev nf
+. fn@div
+. rm fn@div
+. ev
+. if '\\n(.z'fn@overflow-div' \{\
+. di
+. nr fn@have-overflow \\n[dn]>0
+. \}
+. ch fn*catch-overflow
+.\}
+..
+.de fn*catch-overflow
+.di fn@overflow-div
+..
+.nr fn*embed-count 0
+.de @div-end!fn@div
+.br
+.if '\\n[.ev]'fn' .ev
+.fn*end-div
+.nr fn*open 0
+..
+.als @div-end!fn*embed-div @div-end!fn@div
+.de fn*start-div
+.ie '\\n(.z'' \{\
+. da fn@div
+. if !\\n[pg@fn-flag] .ns
+.\}
+.el .di fn*embed-div
+..
+.de fn*end-div
+.ie '\\n(.z'fn@div' \{\
+. di
+. nr fn*page-bottom-pos -\\n[dn]
+. nr fn*max-width \\n[fn*max-width]>?\\n[dl]
+. if !\\n[pg@fn-flag] .nr fn*page-bottom-pos -\\n[fn@sep-dist]
+. nr pg@fn-flag 1
+. nr fn*page-bottom-pos \\n[nl]-\\n[.p]+\n[.V]>?\\n[fn*page-bottom-pos]
+. ch pg@bottom \\n[fn*page-bottom-pos]u
+.\}
+.el \{\
+. ie '\\n(.z'fn*embed-div' \{\
+. di
+. rn fn*embed-div fn*embed-div!\\n[fn*embed-count]
+\!. fn*embed-start \\n[fn*embed-count]
+. rs
+' sp (u;\\n[dn]+\\n[fn@sep-dist]+\\n[.V])
+\!. fn*embed-end
+. nr fn*embed-count +1
+. \}
+. el \{\
+. ev fn
+. @error-recover unclosed diversion within footnote
+. \}
+.\}
+..
+.de fn*embed-start
+.ie '\\n(.z'' \{\
+. fn*start-div
+. ev nf
+. fn*embed-div!\\$1
+. rm fn*embed-div!\\$1
+. ev
+. fn*end-div
+. di fn*null
+.\}
+.el \{\
+\!. fn*embed-start \\$1
+. rs
+.\}
+..
+.de fn*embed-end
+.ie '\\n(.z'fn*null' \{\
+. di
+. rm fn*null
+.\}
+.el \!.fn*embed-end
+..
+.\" It's important that fn@print-sep use up exactly fn@sep-dist vertical space.
+.de fn@print-sep
+.ev fn
+.in 0
+.vs \\n[fn@sep-dist]u
+\D'l 1i 0'
+.br
+.ev
+..
+.\" ***************************
+.\" ******** module kp ********
+.\" ***************************
+.\" Keeps.
+.de KS
+.br
+.di kp*div
+..
+.de KF
+.if !'\\n(.z'' .@error-recover KF while open diversion
+.di kp*fdiv
+.ev k
+.par@reset-env
+.par@reset
+..
+.de KE
+.ie '\\n(.z'kp*div' .kp*end
+.el \{\
+. ie '\\n(.z'kp*fdiv' .kp*fend
+. el .@error KE without KS or KF
+.\}
+..
+.de @div-end!kp*div
+.kp*end
+..
+.de @div-end!kp*fdiv
+.kp*fend
+..
+.de kp*need
+.ie '\\n(.z'' .ds@need \\$1
+.el \!.kp*need \\$1
+..
+.\" end non-floating keep
+.de kp*end
+.br
+.di
+.kp*need \\n[dn]
+.ev nf
+.kp*div
+.ev
+.rm kp*div
+..
+.\" Floating keeps.
+.nr kp@head 0
+.nr kp@tail 0
+.\" end floating keep
+.de kp*fend
+.br
+.ev
+.di
+.ie \\n[.t]-(\\n[.k]>0*1v)>\\n[dn] \{\
+. br
+. ev nf
+. kp*fdiv
+. rm kp*fdiv
+. ev
+.\}
+.el \{\
+. rn kp*fdiv kp*div!\\n[kp@tail]
+. nr kp*ht!\\n[kp@tail] 0\\n[dn]
+. nr kp@tail +1
+.\}
+..
+.\" top of page processing for KF
+.nr kp*doing-top 0
+.de kp@top-hook
+.if !\\n[kp*doing-top] \{\
+. nr kp*doing-top 1
+. kp*do-top
+. nr kp*doing-top 0
+.\}
+..
+.de kp*do-top
+.\" If the first keep won't fit, only force it out if we haven't had a footnote
+.\" and we're at the top of the page.
+.nr kp*force \\n[pg@fn-flag]=0&(\\n[nl]<=\\n[pg@header-bottom])
+.nr kp*fits 1
+.while \\n[kp@tail]>\\n[kp@head]&\\n[kp*fits] \{\
+. ie \\n[.t]>\\n[kp*ht!\\n[kp@head]]:\\n[kp*force] \{\
+. nr kp*force 0
+. \" It's important to advance kp@head before bringing
+. \" back the keep, so that if the last line of the
+. \" last keep springs the bottom of page trap, a new
+. \" page will not be started unnecessarily.
+. rn kp*div!\\n[kp@head] kp*temp
+. nr kp@head +1
+. ev nf
+. kp*temp
+. ev
+. rm kp*temp
+. \}
+. el .nr kp*fits 0
+.\}
+..
+.\" ***************************
+.\" ******** module ds ********
+.\" ***************************
+.\" Displays and non-floating keeps.
+.de DE
+.ds*end!\\n[\\n[.ev]:ds-type]
+.nr \\n[.ev]:ds-type 0
+..
+.de ds@auto-end
+.if \\n[\\n[.ev]:ds-type] \{\
+. @error automatically terminating display
+. DE
+.\}
+..
+.de @div-end!ds*div
+.ie \\n[\\n[.ev]:ds-type] .DE
+.el .ds*end!2
+..
+.de ds*end!0
+.@error DE without DS, ID, CD, LD or BD
+..
+.de LD
+.br
+.nr \\n[.ev]:ds-type 1
+.par@reset
+.nf
+.sp \\n[DD]u
+..
+.de ID
+.LD
+.ie \\n[.$] .in +(n;\\$1)
+.el .in +\\n[DI]u
+..
+.de CD
+.LD
+.ce 9999
+..
+.de RD
+.LD
+.rj 9999
+..
+.de ds*common-end
+.par@reset
+.sp \\n[DD]u
+..
+.als ds*end!1 ds*common-end
+.de BD
+.LD
+.nr \\n[.ev]:ds-type 2
+.di ds*div
+..
+.de ds*end!2
+.br
+.ie '\\n(.z'ds*div' \{\
+. di
+. nf
+. in (u;\\n[.l]-\\n[dl]/2)
+. ds*div
+. rm ds*div
+. ds*common-end
+.\}
+.el .@error-recover mismatched DE
+..
+.de DS
+.br
+.di ds*div
+.ie '\\$1'B' \{\
+. LD
+. nr \\n[.ev]:ds-type 4
+.\}
+.el \{\
+. ie '\\$1'L' .LD
+. el \{\
+. ie '\\$1'C' .CD
+. el \{\
+. ie '\\$1'R' .RD
+. el \{\
+. ie '\\$1'I' .ID \\$2
+. el .ID \\$1
+. \}
+. \}
+. \}
+. nr \\n[.ev]:ds-type 3
+.\}
+..
+.de ds@need
+.if '\\n(.z'' \{\
+. while \\n[.t]<=(\\$1)&(\\n[nl]>\\n[pg@header-bottom]) \{\
+. rs
+' sp \\n[.t]u
+. \}
+.\}
+..
+.de ds*end!3
+.br
+.ie '\\n(.z'ds*div' \{\
+. di
+. ds@need \\n[dn]
+. ev nf
+. ds*div
+. ev
+. rm ds*div
+. ds*common-end
+.\}
+.el .@error-recover mismatched DE
+..
+.de ds*end!4
+.ie '\\n(.z'ds*div' \{\
+. br
+. di
+. nf
+. in (u;\\n[.l]-\\n[dl]/2)
+. ds@need \\n[dn]
+. ds*div
+. rm ds*div
+. ds*common-end
+.\}
+.el .@error-recover mismatched DE
+..
+.\" ****************************
+.\" ******** module par ********
+.\" ****************************
+.\" Paragraph-level formatting.
+.nr PS 10
+.nr LL 6i
+.de par*vs
+.\" If it's too big to be in points, treat it as units.
+.ie (p;\\$1)>=40p .vs (u;\\$1)
+.el .vs (p;\\$1)
+..
+.de par@ab-indent
+.nr 0:li (u;\\n[LL]/12)
+.nr 0:ri \\n[0:li]
+..
+.de par*env-init
+.aln \\n[.ev]:PS PS
+.aln \\n[.ev]:VS VS
+.aln \\n[.ev]:LL LL
+.aln \\n[.ev]:MCLL LL
+.aln \\n[.ev]:LT LT
+.aln \\n[.ev]:MCLT LT
+.aln \\n[.ev]:PI PI
+.aln \\n[.ev]:PD PD
+.ad \\n[par*adj]
+.par@reset-env
+.par@reset
+..
+.\" happens when the first page begins
+.de par@init
+.if !rLT .nr LT \\n[LL]
+.if !rFL .nr FL \\n[LL]*5/6
+.if !rVS .nr VS \\n[PS]+2
+.ps \\n[PS]
+.if !rDI .nr DI .5i
+.if !rQI .nr QI 5n
+.if !rPI .nr PI 5n
+.par*vs \\n[VS]
+.if !rPD .nr PD .3v>?\n(.V
+.if !rDD .nr DD .5v>?\n(.V
+.if !rHY .nr HY 14
+.if !dFAM .ds FAM \\n[.fam]
+.nr par*adj \\n[.j]
+.par*env-init
+.ev h
+.par*env-init
+.ev
+.ev fn
+.par*env-init
+.ev
+.ev k
+.par*env-init
+.ev
+.aln 0:MCLL pg@colw
+.aln 0:MCLT pg@colw
+.aln k:MCLL pg@colw
+.aln k:MCLT pg@colw
+.if !rFPS .nr FPS \\n[PS]-2
+.if !rFVS .nr FVS \\n[FPS]+2
+.if !rFI .nr FI 2n
+.if !rFPD .nr FPD \\n[PD]/2
+.aln fn:PS FPS
+.aln fn:VS FVS
+.aln fn:LL FL
+.aln fn:LT FL
+.aln fn:PI FI
+.aln fn:PD FPD
+.aln fn:MCLL pg@fn-colw
+.aln fn:MCLT pg@fn-colw
+..
+.de par@reset-env
+.nr \\n[.ev]:il 0
+.nr \\n[.ev]:li 0
+.nr \\n[.ev]:ri 0
+.nr \\n[.ev]:ai \\n[\\n[.ev]:PI]
+.nr \\n[.ev]:pli 0
+.nr \\n[.ev]:pri 0
+.nr \\n[.ev]:ds-type 0
+..
+.\" par@reset
+.de par@reset
+.br
+.ce 0
+.rj 0
+.ul 0
+.fi
+.ie \\n[pg@ncols]>1 \{\
+. ll (u;\\n[\\n[.ev]:MCLL]-\\n[\\n[.ev]:ri]-\\n[\\n[.ev]:pri])
+. lt \\n[\\n[.ev]:MCLT]u
+.\}
+.el \{\
+. ll (u;\\n[\\n[.ev]:LL]-\\n[\\n[.ev]:ri]-\\n[\\n[.ev]:pri])
+. lt \\n[\\n[.ev]:LT]u
+.\}
+.in (u;\\n[\\n[.ev]:li]+\\n[\\n[.ev]:pli])
+.ft 1
+.fam \\*[FAM]
+.ps \\n[\\n[.ev]:PS]
+.par*vs \\n[\\n[.ev]:VS]
+.ls 1
+.TA
+.hy \\n[HY]
+..
+.de @RT
+.nr \\n[.ev]:pli 0
+.nr \\n[.ev]:pri 0
+.par@reset
+..
+.\" This can be redefined by the user.
+.de TA
+.ta T 5n
+..
+.de par*start
+.ds@auto-end
+.nr \\n[.ev]:pli \\$1
+.nr \\n[.ev]:pri \\$2
+.par@reset
+.sp \\n[\\n[.ev]:PD]u
+.ne 1v+\\n(.Vu
+..
+.de par@finish
+.nr \\n[.ev]:pli 0
+.nr \\n[.ev]:pri 0
+.par@reset
+..
+.\" normal LP
+.de @LP
+.par*start 0 0
+.nr \\n[.ev]:ai \\n[\\n[.ev]:PI]
+..
+.de @PP
+.par*start 0 0
+.nr \\n[.ev]:ai \\n[\\n[.ev]:PI]
+.ti +\\n[\\n[.ev]:ai]u
+..
+.de @QP
+.nr \\n[.ev]:ai \\n[\\n[.ev]:PI]
+.par*start \\n[QI] \\n[QI]
+..
+.de @XP
+.par*start \\n[\\n[.ev]:PI] 0
+.ti -\\n[\\n[.ev]:PI]u
+..
+.de @IP
+.if \\n[.$]>1 .nr \\n[.ev]:ai (n;\\$2)
+.par*start \\n[\\n[.ev]:ai] 0
+.if !'\\$1'' \{\
+. \" Divert the label so as to freeze any spaces.
+. di par*label
+. par*push-tag-env
+\&\\$1
+. par*pop-tag-env
+. di
+. chop par*label
+. ti -\\n[\\n[.ev]:ai]u
+. ie \\n[dl]+1n<=\\n[\\n[.ev]:ai] \\*[par*label]\h'|\\n[\\n[.ev]:ai]u'\c
+. el \{\
+\\*[par*label]
+. br
+. \}
+. rm par*label
+.\}
+..
+.\" We don't want margin characters to be attached when we divert
+.\" the tag. Since there's no way to save and restore the current
+.\" margin character, we have to switch to a new environment, taking
+.\" what we need of the old environment with us.
+.de par*push-tag-env
+.nr par*saved-font \\n[.f]
+.nr par*saved-size \\n[.s]z
+.nr par*saved-ss \\n[.ss]
+.ds par*saved-fam \\n[.fam]
+.ev par
+.nf
+.TA
+.ft \\n[par*saved-font]
+.ps \\n[par*saved-size]u
+.ss \\n[par*saved-ss]
+.fam \\*[par*saved-fam]
+..
+.de par*pop-tag-env
+.ev
+..
+.de @RS
+.br
+.nr \\n[.ev]:li!\\n[\\n[.ev]:il] \\n[\\n[.ev]:li]
+.nr \\n[.ev]:ri!\\n[\\n[.ev]:il] \\n[\\n[.ev]:ri]
+.nr \\n[.ev]:ai!\\n[\\n[.ev]:il] \\n[\\n[.ev]:ai]
+.nr \\n[.ev]:pli!\\n[\\n[.ev]:il] \\n[\\n[.ev]:pli]
+.nr \\n[.ev]:pri!\\n[\\n[.ev]:il] \\n[\\n[.ev]:pri]
+.nr \\n[.ev]:il +1
+.nr \\n[.ev]:li +\\n[\\n[.ev]:ai]
+.nr \\n[.ev]:ai \\n[\\n[.ev]:PI]
+.par@reset
+..
+.de @RE
+.br
+.ie \\n[\\n[.ev]:il] \{\
+. nr \\n[.ev]:il -1
+. nr \\n[.ev]:ai \\n[\\n[.ev]:ai!\\n[\\n[.ev]:il]]
+. nr \\n[.ev]:li \\n[\\n[.ev]:li!\\n[\\n[.ev]:il]]
+. nr \\n[.ev]:ri \\n[\\n[.ev]:ri!\\n[\\n[.ev]:il]]
+. nr \\n[.ev]:pli \\n[\\n[.ev]:pli!\\n[\\n[.ev]:il]]
+. nr \\n[.ev]:pri \\n[\\n[.ev]:pri!\\n[\\n[.ev]:il]]
+.\}
+.el .@error unbalanced \\$0
+.par@reset
+..
+.de @QS
+.br
+.nr \\n[.ev]:li!\\n[\\n[.ev]:il] \\n[\\n[.ev]:li]
+.nr \\n[.ev]:ri!\\n[\\n[.ev]:il] \\n[\\n[.ev]:ri]
+.nr \\n[.ev]:ai!\\n[\\n[.ev]:il] \\n[\\n[.ev]:ai]
+.nr \\n[.ev]:pli!\\n[\\n[.ev]:il] \\n[\\n[.ev]:pli]
+.nr \\n[.ev]:pri!\\n[\\n[.ev]:il] \\n[\\n[.ev]:pri]
+.nr \\n[.ev]:il +1
+.nr \\n[.ev]:li +\\n[QI]
+.nr \\n[.ev]:ri +\\n[QI]
+.nr \\n[.ev]:ai \\n[\\n[.ev]:PI]
+.par@reset
+..
+.als @QE @RE
+.\" start boxed text
+.de B1
+.br
+.di par*box-div
+.nr \\n[.ev]:li +1n
+.nr \\n[.ev]:ri +1n
+.nr par*box-in \\n[.in]
+.\" remember what 1n is, just in case the point size changes
+.nr par*box-n 1n
+.in +1n
+.ll -1n
+.lt -1n
+.ti \\n[par*box-in]u+1n
+..
+.de @div-end!par*box-div
+.B2
+..
+.\" end boxed text
+.\" Postpone the drawing of the box until we're in the top-level diversion,
+.\" in case there's a footnote inside the box.
+.de B2
+.ie '\\n(.z'par*box-div' \{\
+. br
+. if \n[.V]>.25m .sp
+. di
+. if \n[.V]>.25m .sp
+. ds@need \\n[dn]
+. par*box-mark-top
+. ev nf
+. par*box-div
+. ev
+. nr \\n[.ev]:ri -\\n[par*box-n]
+. nr \\n[.ev]:li -\\n[par*box-n]
+. in -\\n[par*box-n]u
+. ll +\\n[par*box-n]u
+. lt +\\n[par*box-n]u
+. par*box-draw \\n[.i]u \\n[.l]u-(\\n[.H]u==1n*1n)
+.\}
+.el .@error B2 without B1
+..
+.de par*box-mark-top
+.ie '\\n[.z]'' \{\
+. rs
+. mk par*box-top
+.\}
+.el \!.par*box-mark-top
+..
+.de par*box-draw
+.ie '\\n[.z]'' \{\
+. nr par*box-in \\n[.i]
+. nr par*box-ll \\n[.l]
+. nr par*box-vpt \\n[.vpt]
+. nr par*box-ad \\n[.j]
+. ad l
+. vpt 0
+. in \\$1
+. ll \\$2
+\v'-1v+.25m'\
+\D'l (u;\\n[.l]-\\n[.i]) 0'\
+\D'l 0 |\\n[par*box-top]u'\
+\D'l -(u;\\n[.l]-\\n[.i]) 0'\
+\D'l 0 -|\\n[par*box-top]u'
+. br
+. sp -1
+. in \\n[par*box-in]u
+. ll \\n[par*box-ll]u
+. vpt \\n[par*box-vpt]
+. ad \\n[par*box-ad]
+.\}
+.el \!.par*box-draw \\$1 \\$2
+..
+.de @SH
+.par@finish
+.\" Keep together the heading and the first two lines of the next paragraph.
+.ne 3v+\\n[\\n[.ev]:PD]u+\\n(.Vu
+.sp 1
+.ft B
+..
+.\" TL, AU, and AI are aliased to these in cov*ab-init.
+.de par@TL
+.par@finish
+.sp 1
+.ft B
+.ps +2
+.vs +3p
+.ce 9999
+..
+.de par@AU
+.par@finish
+.sp 1
+.ft I
+.ce 9999
+..
+.de par@AI
+.par@finish
+.sp .5
+.ce 9999
+..
+.\" In paragraph macros.
+.de NL
+.ps \\n[\\n[.ev]:PS]
+..
+.de SM
+.ps -2
+..
+.de LG
+.ps +2
+..
+.de R
+.ft R
+..
+.\" par*define-font-macro macro font
+.de par*define-font-macro
+.de \\$1
+.ie \\\\n[.$] \{\
+. nr par*prev-font \\\\n[.f]
+\&\\\\$3\f[\\$2]\\\\$1\f[\\\\n[par*prev-font]]\\\\$2
+.\}
+.el .ft \\$2
+\\..
+..
+.par*define-font-macro B B
+.par*define-font-macro I I
+.par*define-font-macro BI BI
+.par*define-font-macro CW CR
+.\" underline a word
+.de UL
+\Z'\\$1'\v'.25m'\D'l \w'\\$1'u 0'\v'-.25m'\\$2
+..
+.\" box a word
+.de BX
+.nr par*bxw \w'\\$1'+.4m
+\Z'\v'.25m'\D'l 0 -1m'\D'l \\n[par*bxw]u 0'\D'l 0 1m'\D'l -\\n[par*bxw]u 0''\
+\Z'\h'.2m'\\$1'\
+\h'\\n[par*bxw]u'
+..
+.\" The first time UX is used, put a registered mark after it.
+.ds par*ux-rg \(rg
+.de UX
+\s[\\n[.s]*8u/10u]UNIX\s0\\$1\\*[par*ux-rg]
+.ds par*ux-rg
+..
+.ds par@sup-start \v'-.9m\s'\En[.s]*7u/10u'+.7m'
+.als { par@sup-start
+.ds par@sup-end \v'-.7m\s0+.9m'
+.als } par@sup-end
+.\" footnote paragraphs
+.\" FF is the footnote format
+.nr FF 0
+.\" This can be redefined. It gets a second argument of `no' if the first
+.\" argument was supplied by the user, rather than automatically.
+.de FP
+.br
+.if !d par*fp!\\n[FF] \{\
+. @error unknown footnote format `\\n[FF]'
+. nr FF 0
+.\}
+.ie '\\$2'no' .par*fp!\\n[FF]-no "\\$1"
+.el .par*fp!\\n[FF] "\\$1"
+..
+.de par*fp!0
+.@PP
+\&\\*[par@sup-start]\\$1\\*[par@sup-end]\ \c
+..
+.de par*fp!0-no
+.@PP
+\&\\$1\ \c
+..
+.de par*fp!1
+.@PP
+\&\\$1.\ \c
+..
+.de par*fp!1-no
+.@PP
+\&\\$1\ \c
+..
+.de par*fp!2
+.@LP
+\&\\$1.\ \c
+..
+.de par*fp!2-no
+.@LP
+\&\\$1\ \c
+..
+.de par*fp!3
+.@IP "\\$1." (u;\\n[\\n[.ev]:PI]*2)
+..
+.de par*fp!3-no
+.@IP "\\$1" (u;\\n[\\n[.ev]:PI]*2)
+..
+.\" ***************************
+.\" ******** module nh ********
+.\" ***************************
+.\" Numbered headings.
+.\" nh*hl is the level of the last heading
+.nr nh*hl 0
+.\" numbered heading
+.de @NH
+.ie '\\$1'S' \{\
+. shift
+. nr nh*hl 0
+. while \\n[.$] \{\
+. nr nh*hl +1
+. nr H\\n[nh*hl] 0\\$1
+. shift
+. \}
+. if !\\n[nh*hl] \{\
+. nr H1 1
+. nr nh*hl 1
+. @error missing arguments to .NH S
+. \}
+.\}
+.el \{\
+. nr nh*ohl \\n[nh*hl]
+. ie \\n[.$] \{\
+. nr nh*hl 0\\$1
+. ie \\n[nh*hl]<=0 \{\
+. nr nh*ohl 0
+. nr nh*hl 1
+. \}
+. el \{\
+. if \\n[nh*hl]-\\n[nh*ohl]>1 \
+. @warning .NH \\n[nh*ohl] followed by .NH \\n[nh*hl]
+. \}
+. \}
+. el .nr nh*hl 1
+. while \\n[nh*hl]>\\n[nh*ohl] \{\
+. nr nh*ohl +1
+. nr H\\n[nh*ohl] 0
+. \}
+. nr H\\n[nh*hl] +1
+.\}
+.ds SN
+.nr nh*i 0
+.while \\n[nh*i]<\\n[nh*hl] \{\
+. nr nh*i +1
+. as SN \\n[H\\n[nh*i]].
+.\}
+.SH
+\\*[SN]
+..
+.\" ****************************
+.\" ******** module toc ********
+.\" ****************************
+.\" Table of contents generation.
+.de @XS
+.da toc*div
+.ev h
+.ie \\n[.$] .XA "\\$1"
+.el .XA
+..
+.de @div-end!toc*div
+.XE
+..
+.de XA
+.ie '\\n(.z'toc*div' \{\
+. if d toc*num .toc*end-entry
+. ie \\n[.$] \{\
+. ie '\\$1'no' .ds toc*num
+. el .ds toc*num "\\$1
+. \}
+. el .ds toc*num \\n[PN]
+. LP
+. na
+. ll -8n
+. in (n;0\\$2)
+.\}
+.el .@error XA without XS
+..
+.de XE
+.ie '\\n(.z'toc*div' \{\
+. if d toc*num .toc*end-entry
+. ev
+. di
+.\}
+.el .@error XS without XE
+..
+.de toc*end-entry
+\\a\\t\\*[toc*num]
+.br
+.rm toc*num
+..
+.de PX
+.1C
+.if !'\\$1'no' \{\
+. ce 1
+. ps \\n[PS]+2
+. ft B
+\\*[TOC]
+. ft
+. ps
+.\}
+.nf
+.char \[toc*leader-char] .\h'1m'
+.lc \[toc*leader-char]
+.ta (u;\\n[.l]-\\n[.i]-\w'000') (u;\\n[.l]-\\n[.i])R
+.sp 2
+.toc*div
+.par@reset
+..
+.\" print the table of contents on page i
+.de TC
+.P1
+.pg@begin 1 i
+.PX \\$1
+..
+.\" ****************************
+.\" ******** module eqn ********
+.\" ****************************
+.\" Eqn support.
+.de EQ
+..
+.de EN
+..
+.de @EQ
+.br
+.ds eqn*num "\\$2
+.ie '\\$1'L' .nr eqn*type 0
+.el \{\
+. ie '\\$1'I' .nr eqn*type 1
+. el \{\
+. nr eqn*type 2
+. if !'\\$1'C' .ds eqn*num "\\$1
+. \}
+.\}
+.di eqn*div
+.in 0
+.nf
+..
+.de @div-end!eqn*div
+.@EN
+..
+.\" Note that geqn mark and lineup work correctly in centered equations.
+.de @EN
+.ie !'\\n(.z'eqn*div' .@error-recover mismatched EN
+.el \{\
+. br
+. di
+. nr eqn*have-num 0
+. if !'\\*[eqn*num]'' .nr eqn*have-num 1
+. if \\n[dl]:\\n[eqn*have-num] \{\
+. sp \\n[DD]u
+. par@reset
+. ds eqn*tabs \\n[.tabs]
+. nf
+. ie \\n[dl] \{\
+. ds@need \\n[dn]u-1v+\n[.V]u
+. chop eqn*div
+. ie \\n[eqn*type]=0 \{\
+. ta (u;\\n[.l]-\\n[.i])R
+\\*[eqn*div]\t\\*[eqn*num]
+. \}
+. el \{\
+. ie \\n[eqn*type]=1 .ta \\n[DI]u \
+(u;\\n[.l]-\\n[.i])R
+. el .ta (u;\\n[.l]-\\n[.i]/2)C \
+(u;\\n[.l]-\\n[.i])R
+\t\\*[eqn*div]\t\\*[eqn*num]
+. \}
+. \}
+. el \{\
+. ta (u;\\n[.l]-\\n[.i])R
+\t\\*[eqn*num]
+. \}
+. sp \\n[DD]u
+. fi
+. ta \\*[eqn*tabs]
+. \}
+.\}
+..
+.\" ****************************
+.\" ******** module tbl ********
+.\" ****************************
+.\" Tbl support.
+.nr tbl*have-header 0
+.de TS
+.\" The break is necessary in the case where the first page has not yet begun.
+.br
+.sp \\n[DD]u
+.if '\\$1'H' .di tbl*header-div
+..
+.de tbl@top-hook
+.if \\n[tbl*have-header] \{\
+. ie \\n[.t]-\\n[tbl*header-ht]-1v .tbl*print-header
+. el .sp \\n[.t]u
+.\}
+..
+.de tbl*print-header
+.ev nf
+.tbl*header-div
+.ev
+.mk #T
+..
+.de TH
+.ie '\\n[.z]'tbl*header-div' \{\
+. nr T. 0
+. T#
+. br
+. di
+. ie \\n[dn]+\\n[FM]+\\n[HM]+2v>=\\n[.p] \{\
+. @error ridiculously long table header
+. ds@need \\n[dn]
+. tbl*print-header
+. \}
+. el \{\
+. nr tbl*header-ht \\n[dn]
+. ds@need \\n[dn]u+1v
+. tbl*print-header
+. nr tbl*have-header 1
+. \}
+.\}
+.el .@error-recover .TH without .TS H
+..
+.de @div-end!tbl*header-div
+.TH
+.TE
+..
+.de TE
+.ie '\\n(.z'tbl*header-div' .@error-recover .TS H but no .TH before .TE
+.el \{\
+. nr tbl*have-header 0
+. sp \\n[DD]u
+.\}
+.\" reset tabs
+.TA
+..
+.de tbl@bottom-hook
+.if \\n[tbl*have-header] \{\
+. nr T. 1
+. T#
+.\}
+..
+.de T&
+..
+.\" ****************************
+.\" ******** module pic ********
+.\" ****************************
+.\" Pic support.
+.\" PS height width
+.de PS
+.br
+.sp \\n[DD]u
+.ie \\n[.$]<2 .@error bad arguments to PS (not preprocessed with pic?)
+.el \{\
+. ds@need (u;\\$1)+1v
+. in +(u;\\n[.l]-\\n[.i]-\\$2/2>?0)
+.\}
+..
+.de PE
+.par@reset
+.sp \\n[DD]u+.5m
+..
+.\" ****************************
+.\" ******** module ref ********
+.\" ****************************
+.\" Refer support.
+.de ]-
+.rm [A [B [C [D [E [G [I [J [N [O [P [Q [R [S [T [V
+.rm ref*string
+..
+.\" Other
+.ds ref*spec!0 Q A T1 S V N P I C D O
+.\" Journal article
+.ds ref*spec!1 Q A T2 J S V N P I C D O
+.\" Book
+.ds ref*spec!2 Q A T1 S V P I C D O
+.\" Article within book
+.ds ref*spec!3 Q A T2 B E S V P I C D O
+.\" Tech report
+.ds ref*spec!4 Q A T2 R G P I C D O
+.\" ][ type
+.de ][
+.if r [T \{\
+. als [T1 [T
+. als [T2 [T
+.\}
+.ie d ref*spec!\\$1 .ref*build \\*[ref*spec!\\$1]
+.el \{\
+. @error unknown reference type `\\$1'
+. ref*build \\*[ref*spec!0]
+.\}
+.ref*print
+.rm ref*string
+.rm [F [T1 [T2
+..
+.\" start of reference number
+.ds [. \\*[par@sup-start]
+.\" end of reference number
+.ds .] \\*[par@sup-end]
+.\" period before reference
+.ds <. .
+.\" period after reference
+.ds >. \" empty
+.\" comma before reference
+.ds <, ,
+.\" comma after reference
+.ds >, \" empty
+.\" start collected references
+.de ]<
+.als ref*print ref*end-print
+.SH
+\&\\*[REFERENCES]
+.par@reset
+..
+.\" end collected references
+.de ]>
+.par@finish
+.als ref*print ref*normal-print
+..
+.de ref*normal-print
+.ie d [F .FS "\\*([.\\*([F\\*(.]"
+.el .FS \&
+\\*[ref*string]
+.FE
+..
+.de ref*end-print
+.ie d [F .IP "\\*([F."
+.el .XP
+\\*[ref*string]
+..
+.als ref*print ref*normal-print
+.de ref*build
+.rm ref*string ref*post-punct
+.nr ref*suppress-period 1
+.while \\n[.$] \{\
+. if d [\\$1 \{\
+. ie d ref*add-\\$1 .ref*add-\\$1
+. el .ref*add-dflt \\$1
+. \}
+. shift
+.\}
+.\" now add a final period
+.ie d ref*string \{\
+. if !\\n[ref*suppress-period] .as ref*string .
+. if d ref*post-punct \{\
+. as ref*string "\\*[ref*post-punct]
+. rm ref*post-punct
+. \}
+.\}
+.el .ds ref*string
+..
+.de ref*add-T1
+.ref*field T , "\fI" "" "\fP"
+.if r [T .nr ref*suppress-period \\n([T
+..
+.de ref*add-T2
+.ref*field T , "\\*Q" "" "\\*U"
+.if r [T .nr ref*suppress-period \\n([T
+..
+.de ref*add-P
+.ie \\n([P>0 .ref*field P , "pp. "
+.el .ref*field P , "p. "
+..
+.de ref*add-J
+.ref*field J , \fI "" \fP
+..
+.de ref*add-D
+.ref*field D "" ( )
+..
+.de ref*add-E
+.ref*field E , "ed. "
+..
+.de ref*add-G
+.ref*field G "" ( )
+..
+.de ref*add-B
+.ref*field B "" "in \fI" "" \fP
+..
+.de ref*add-O
+.ref*field O .
+.ie r [O .nr ref*suppress-period \\n([O
+.el .nr ref*suppress-period 1
+..
+.de ref*add-A
+.ref*field A ,
+.if r [A .nr ref*suppress-period \\n([A
+..
+.de ref*add-dflt
+.ref*field \\$1 ,
+..
+.\" First argument is the field letter.
+.\" Second argument is the punctuation character to use to separate this field
+.\" from the previous field.
+.\" Third argument is a string with which to prefix this field.
+.\" Fourth argument is a string with which to postfix this field.
+.\" Fifth argument is a string to add after the punctuation character supplied
+.\" by the next field.
+.de ref*field
+.if d ref*string \{\
+. ie d ref*post-punct \{\
+. as ref*string "\\$2\\*[ref*post-punct] \"
+. rm ref*post-punct
+. \}
+. el .as ref*string "\\$2 \"
+.\}
+.as ref*string "\\$3\\*([\\$1\\$4
+.if \\n[.$]>4 .ds ref*post-punct "\\$5
+.nr ref*suppress-period 0
+..
+.\" ****************************
+.\" ******** module acc ********
+.\" ****************************
+.\" Accents and special characters.
+.ds Q \(lq
+.ds U \(rq
+.ds - \(em
+.\" Characters
+.\" The idea of this definition is for the top of the 3 to be at the x-height.
+.if !c\[yogh] .char \[yogh] \Z'\v'\w'x'*0-\En[rst]u'\s[\En[.s]*8u/10u]\
+\v'\w'3'*0+\En[rst]u'3\s0'\h'\w'\s[\En[.s]*8u/10u]3'u'
+.\" Accents
+.de acc*over-def
+.ds \\$1 \Z'\v'(u;\w'x'*0+\En[rst]-\En[.cht])'\
+\h'(u;-\En[skw]+(-\En[.w]-\w'\\$2'/2)+\En[.csk])'\\$2'
+..
+.de acc*under-def
+.ds \\$1 \Z'\v'\En[.cdp]u'\h'(u;-\En[.w]-\w'\\$2'/2)'\\$2'
+..
+.de acc*slash-def
+.ds \\$1 \Z'\h'(u;-\En[.w]-\w'\\$2'/2)'\
+\v'(u;\En[.cdp]-\En[.cht]+\En[rst]+\En[rsb]/2)'\\$2'
+..
+.de acc*prefix-def
+.ds \\$1 \Z'\h'(u;\w'x'-\w'\\$2'/2)'\\$2'
+..
+.acc*prefix-def ' \'
+.acc*prefix-def ` \`
+.acc*prefix-def ^ ^
+.acc*prefix-def , \(ac
+.acc*prefix-def : \(ad
+.acc*prefix-def ~ ~
+.\" improved accent marks
+.de AM
+.acc*over-def ' \'
+.acc*over-def ` \`
+.acc*over-def ^ ^
+.acc*over-def ~ ~
+.acc*over-def : \(ad
+.acc*over-def v \(ah
+.acc*over-def _ \(a-
+.acc*over-def o \(ao
+.acc*under-def , \(ac
+.acc*under-def . \s[\En[.s]*8u/10u]\v'.2m'.\v'-.2m'\s0
+.acc*under-def hook \(ho
+.acc*slash-def / /
+.char \[hooko] o\\\\*[hook]
+.ds q \[hooko]
+.ds 3 \[yogh]
+.ds D- \(-D\" Icelandic uppercase eth
+.ds d- \(Sd\" Icelandic lowercase eth
+.ds Th \(TP\" Icelandic uppercase thorn
+.ds th \(Tp\" Icelandic lowercase thorn
+.ds 8 \(ss\" German double s
+.ds Ae \(AE\" AE ligature
+.ds ae \(ae\" ae ligature
+.ds Oe \(OE\" OE ligature
+.ds oe \(oe\" oe ligature
+.ds ? \(r?\" upside down ?
+.ds ! \(r!\" upside down !
+..
+.\" Make sure that no blank lines creep in at the end of this file.
diff --git a/gnu/usr.bin/groff/tmac/tmac.tty b/gnu/usr.bin/groff/tmac/tmac.tty
new file mode 100644
index 0000000..b35a59e
--- /dev/null
+++ b/gnu/usr.bin/groff/tmac/tmac.tty
@@ -0,0 +1,48 @@
+.nr _C \n(.C
+.cp 0
+.nroff
+.ftr CW B
+.ftr C B
+.ftr CR B
+.po 0
+.if c\[char173] .shc \[char173]
+.de tty-char
+.if !c\\$1 .char \\$1 "\\$2
+..
+.if c\(md .tr \(bu\(md
+.tty-char \(bu \z+o
+.tty-char \(14 1/4
+.tty-char \(12 1/2
+.tty-char \(34 3/4
+.tty-char \(ff ff
+.tty-char \(fi fi
+.tty-char \(fl fl
+.tty-char \(Fi ffi
+.tty-char \(Fl ffl
+.tty-char \(<- <-
+.tty-char \(-> ->
+.tty-char \(<> <->
+.tty-char \(em --
+.tty-char \(+- +-
+.tty-char \(co (C)
+.tty-char \(<= <=
+.tty-char \(>= >=
+.tty-char \(!= !=
+.tty-char \(== ==
+.tty-char \(~= ~=
+.tty-char \(sq []
+.tty-char \(lh <=
+.tty-char \(rh =>
+.tty-char \(lA <=
+.tty-char \(rA =>
+.tty-char \(hA <=>
+.tty-char \(rg (R)
+.tty-char \(OE OE
+.tty-char \(oe oe
+.tty-char \(AE AE
+.tty-char \(ae ae
+.tty-char \(an -
+.cp \n(_C
+.\" If you want the character definitions in tmac.tty-char to be loaded
+.\" automatically, remove the `\"' from the next line.
+.\" do mso tmac.tty-char
diff --git a/gnu/usr.bin/groff/tmac/tmac.tty-char b/gnu/usr.bin/groff/tmac/tmac.tty-char
new file mode 100644
index 0000000..9815e6c
--- /dev/null
+++ b/gnu/usr.bin/groff/tmac/tmac.tty-char
@@ -0,0 +1,196 @@
+.\" This file defines standard troff characters and some groff characters for
+.\" use with -Tascii and -Tlatin1.
+.\"
+.\" These definitions are chosen so that, as far as possible, they:
+.\" - work with both -Tascii and -Tlatin1.
+.\" - work on devices that display only the last overstruck character
+.\" as well as on devices that support overstriking
+.\" - represent the character's graphical shape (not its meaning)
+.\"
+.nr _C \n(.C
+.cp 0
+.de tty-char
+.if !c\\$1 .char \\$1 "\\$2
+..
+.ie c\(a- .ds tty-rn \(a-
+.el .ds tty-rn \v'-1m'_\v'+1m'
+.tty-char \(tm tm
+.tty-char \(rn \*[tty-rn]
+.tty-char \(ua \z|^
+.tty-char \(da \z|v
+.tty-char \(sc S
+.tty-char \(ct \z/c
+.tty-char \(dg \z|-
+.tty-char \(dd \z|=
+.tty-char \(ib (\z=_
+.tty-char \(ip \z=_)
+.tty-char \(sb (=
+.tty-char \(sp =)
+.tty-char \(if oo
+.tty-char \(pt oc
+.tty-char \(es {}
+.tty-char \(ca (^)
+.tty-char \(cu U
+.tty-char \(de o
+.tty-char \(di -:-
+.tty-char \(no ~
+.tty-char \(gr \Z'\*[tty-rn]'V
+.tty-char \(is \z'\z,I
+.tty-char \(mo E
+.tty-char \(pd a
+.tty-char \(sr \e/
+.tty-char \(*C \z_H
+.tty-char \(*D \z_/\z_\e
+.tty-char \(*F \zIO
+.tty-char \(*G |\*[tty-rn]
+.tty-char \(*H \z-O
+.tty-char \(*L /\e
+.tty-char \(*P TT
+.tty-char \(*Q \zIY
+.tty-char \(*S \z_\Z'\*[tty-rn]'>
+.tty-char \(*W \z_O
+.if c\(ss .tty-char \(*b \(ss
+.tty-char \(*b B
+.tty-char \(*a a
+.tty-char \(*c \z,E
+.tty-char \(*d d
+.tty-char \(*e e
+.tty-char \(*f \z|o
+.tty-char \(+f \z|o
+.tty-char \(*g y
+.tty-char \(*h \z-0
+.tty-char \(+h \z-0
+.tty-char \(*i i
+.tty-char \(*k k
+.tty-char \(*l \z>\e
+.tty-char \(*m \z,u
+.tty-char \(*n v
+.tty-char \(*p \z-n
+.tty-char \(+p \z-w
+.tty-char \(*q \z|u
+.tty-char \(*r p
+.tty-char \(*s \z-o
+.tty-char \(*t \z~t
+.tty-char \(*u u
+.tty-char \(*w w
+.tty-char \(*x x
+.tty-char \(*y n
+.tty-char \(*z \z,C
+.tty-char \(ts s
+.\" Definition of \(ss should follow that of \(*b.
+.tty-char \(ss B
+.tty-char \(c* \zO\(mu
+.tty-char \(c+ \zO+
+.tty-char \(AN ^
+.tty-char \(OR v
+.tty-char \(uA \z=^
+.tty-char \(dA \z=v
+.if c\(md .tty-char \(a. \(md
+.tty-char \(Im I
+.tty-char \(Re R
+.tty-char \(/L \z/L
+.tty-char \(/l \z/l
+.tty-char \(%0 %o
+.tty-char \(ao o
+.tty-char \(a" """"
+.tty-char \(ah v
+.tty-char \(ho \(ac
+.tty-char \(/_ \z_/
+.tty-char \(=~ =~
+.tty-char \(Ah N
+.tty-char \(CR _|
+.tty-char \(fa \z-V
+.tty-char \(nm \z/E
+.tty-char \(pp \z_|
+.tty-char \(sd ''
+.tty-char \(st -)
+.tty-char \(te 3
+.if c\(md .tty-char \(tf .\(md.
+.tty-char \(tf .:.
+.tty-char \(wp p
+.tty-char \(~~ ~~
+.tty-char \(Fn \z,f
+.tty-char \(Bq ,,
+.tty-char \(bq ,
+.tty-char \(lz <>
+.\" Latin-1 characters
+.tty-char \(r! \z,i
+.tty-char \(Po \z-L
+.tty-char \(Cs \zox
+.tty-char \(Ye \z=Y
+.tty-char \(bb |
+.tty-char \(ad """"
+.tty-char \(Of \z_a
+.tty-char \(Fo <<
+.tty-char \(a- \*[tty-rn]
+.tty-char \(S2 2
+.tty-char \(S3 3
+.tty-char \(ps 9|
+.tty-char \(md .
+.tty-char \(ac ,
+.tty-char \(S1 1
+.tty-char \(Om \z_o
+.tty-char \(Fc >>
+.tty-char \(r? \z'c
+.tty-char \(`A \z`A
+.tty-char \('A \z'A
+.tty-char \(^A \z^A
+.tty-char \(~A \z~A
+.tty-char \(:A \z"A
+.tty-char \(oA \zoA
+.tty-char \(,C \z,C
+.tty-char \(`E \z`E
+.tty-char \('E \z'E
+.tty-char \(^E \z^E
+.tty-char \(:E \z"E
+.tty-char \(`I \z`I
+.tty-char \('I \z'I
+.tty-char \(^I \z^I
+.tty-char \(:I \z"I
+.tty-char \(-D \z-D
+.tty-char \(~N \z~N
+.tty-char \(`O \z`O
+.tty-char \('O \z'O
+.tty-char \(^O \z^O
+.tty-char \(~O \z~O
+.tty-char \(:O \z"O
+.tty-char \(/O \z/O
+.tty-char \(`U \z`U
+.tty-char \('U \z'U
+.tty-char \(^U \z^U
+.tty-char \(:U \z"U
+.tty-char \('Y \z'Y
+.tty-char \(TP \zIb
+.tty-char \(`a \z`a
+.tty-char \('a \z'a
+.tty-char \(^a \z^a
+.tty-char \(~a \z~a
+.tty-char \(:a \z"a
+.tty-char \(oa \zoa
+.tty-char \(,c \z,c
+.tty-char \(`e \z`e
+.tty-char \('e \z'e
+.tty-char \(^e \z^e
+.tty-char \(:e \z"e
+.tty-char \(`i \z`i
+.tty-char \('i \z'i
+.tty-char \(^i \z^i
+.tty-char \(:i \z"i
+.tty-char \(Sd \z`\z'o
+.tty-char \(~n \z~n
+.tty-char \(`o \z`o
+.tty-char \('o \z'o
+.tty-char \(^o \z^o
+.tty-char \(~o \z~o
+.tty-char \(:o \z"o
+.tty-char \(/o \z/o
+.tty-char \(`u \z`u
+.tty-char \('u \z'u
+.tty-char \(^u \z^u
+.tty-char \(:u \z"u
+.tty-char \('y \z'y
+.tty-char \(Tp \zpb
+.tty-char \(:y \z"y
+.\"tty-char \(:y \ij
+.cp \n(_C
+.do mso tmac.latin1
diff --git a/gnu/usr.bin/groff/tmac/troffrc b/gnu/usr.bin/groff/tmac/troffrc
new file mode 100644
index 0000000..6390c0b
--- /dev/null
+++ b/gnu/usr.bin/groff/tmac/troffrc
@@ -0,0 +1,31 @@
+.\" Startup file for troff.
+.\" This is tested by pic.
+.nr 0p 0
+.\" Use .do here, so that it works with -C.
+.\" The groff command defines the .X string if the -X option was given.
+.ie r.X .do ds troffrc!ps tmac.Xps
+.el .do ds troffrc!ps tmac.ps
+.do ds troffrc!dvi tmac.dvi
+.do ds troffrc!X75 tmac.X
+.do ds troffrc!X75-12 tmac.X
+.do ds troffrc!X100 tmac.X
+.do ds troffrc!X100-12 tmac.X
+.do ds troffrc!ascii tmac.tty
+.do ds troffrc!latin1 tmac.tty
+.do ds troffrc!koi8-r tmac.tty
+.do if d troffrc!\*[.T] \
+. do mso \*[troffrc!\*[.T]]
+.do rm troffrc!ps troffrc!Xps troffrc!dvi troffrc!X75 troffrc!X75-12 \
+troffrc!X100 troffrc!X100-12
+.do tr \[char160]
+.\" Set the hyphenation language to `us'.
+.\" Load hyphenation patterns from `hyphen.us' (in the tmac directory).
+.ie "\*[.T]"koi8-r" \{\
+.do hla us-ru
+.do hpf hyphen.us-ru
+. \}
+.el \{\
+.do hla us
+.do hpf hyphen.us
+. \}
+.\" Don't let blank lines creep in here.
diff --git a/gnu/usr.bin/groff/troff/Makefile b/gnu/usr.bin/groff/troff/Makefile
new file mode 100644
index 0000000..f51d93a
--- /dev/null
+++ b/gnu/usr.bin/groff/troff/Makefile
@@ -0,0 +1,26 @@
+PROG= troff
+SRCS= env.cc node.cc input.cc div.cc symbol.cc dictionary.cc reg.cc \
+ number.cc majorminor.cc
+CFLAGS+= -I${.CURDIR}/../include
+LDADD+= ${LIBGROFF} -lm
+DPADD+= ${LIBGROFF} ${LIBM}
+MANDEPEND= troff.1
+
+CLEANFILES+= majorminor.cc ${MANDEPEND}
+
+majorminor.cc: ${.CURDIR}/../VERSION
+ @${ECHO} Making $@
+ @-rm -f $@
+ @echo const char \*major_version = \
+ \"`sed -e 's/^\([^.]*\)\..*$$/\1/' ${.CURDIR}/../VERSION`\"\; >$@
+ @echo const char \*minor_version = \
+ \"`sed -e 's/^[^.]*\.\([0-9]*\).*$$/\1/' ${.CURDIR}/../VERSION`\"\; >>$@
+
+afterinstall:
+ ${INSTALL} -c -o bin -g bin -m 444 ${.CURDIR}/hyphen.us \
+ ${DESTDIR}${tmacdir}/hyphen.us
+ ${INSTALL} -c -o bin -g bin -m 444 ${.CURDIR}/hyphen.us-ru \
+ ${DESTDIR}${tmacdir}/hyphen.us-ru
+
+.include "../Makefile.cfg"
+.include <bsd.prog.mk>
diff --git a/gnu/usr.bin/groff/troff/Makefile.dep b/gnu/usr.bin/groff/troff/Makefile.dep
new file mode 100644
index 0000000..b1fd779
--- /dev/null
+++ b/gnu/usr.bin/groff/troff/Makefile.dep
@@ -0,0 +1,34 @@
+env.o : env.cc troff.h ../include/lib.h ../include/assert.h \
+ ../include/device.h ../include/cset.h ../include/cmap.h \
+ ../include/errarg.h ../include/error.h symbol.h dictionary.h hvunits.h \
+ env.h request.h node.h token.h div.h reg.h charinfo.h \
+ ../include/searchpath.h ../include/macropath.h
+node.o : node.cc troff.h ../include/lib.h ../include/assert.h \
+ ../include/device.h ../include/cset.h ../include/cmap.h \
+ ../include/errarg.h ../include/error.h symbol.h dictionary.h hvunits.h \
+ env.h request.h node.h token.h charinfo.h ../include/font.h reg.h
+input.o : input.cc troff.h ../include/lib.h ../include/assert.h \
+ ../include/device.h ../include/cset.h ../include/cmap.h \
+ ../include/errarg.h ../include/error.h symbol.h dictionary.h hvunits.h \
+ env.h request.h node.h reg.h token.h div.h charinfo.h ../include/font.h \
+ ../include/searchpath.h ../include/macropath.h ../include/defs.h \
+ ../include/posix.h
+div.o : div.cc troff.h ../include/lib.h ../include/assert.h \
+ ../include/device.h ../include/cset.h ../include/cmap.h \
+ ../include/errarg.h ../include/error.h symbol.h dictionary.h hvunits.h \
+ env.h request.h node.h token.h div.h reg.h
+symbol.o : symbol.cc troff.h ../include/lib.h ../include/assert.h \
+ ../include/device.h ../include/cset.h ../include/cmap.h \
+ ../include/errarg.h ../include/error.h symbol.h
+dictionary.o : dictionary.cc troff.h ../include/lib.h ../include/assert.h \
+ ../include/device.h ../include/cset.h ../include/cmap.h \
+ ../include/errarg.h ../include/error.h symbol.h dictionary.h
+reg.o : reg.cc troff.h ../include/lib.h ../include/assert.h \
+ ../include/device.h ../include/cset.h ../include/cmap.h \
+ ../include/errarg.h ../include/error.h symbol.h dictionary.h token.h \
+ request.h reg.h
+number.o : number.cc troff.h ../include/lib.h ../include/assert.h \
+ ../include/device.h ../include/cset.h ../include/cmap.h \
+ ../include/errarg.h ../include/error.h symbol.h hvunits.h env.h token.h \
+ div.h
+majorminor.o : majorminor.cc
diff --git a/gnu/usr.bin/groff/troff/Makefile.sub b/gnu/usr.bin/groff/troff/Makefile.sub
new file mode 100644
index 0000000..dc67031
--- /dev/null
+++ b/gnu/usr.bin/groff/troff/Makefile.sub
@@ -0,0 +1,30 @@
+PROG=troff
+MAN1=troff.n
+XLIBS=$(LIBGROFF)
+MLIB=$(LIBM)
+OBJS=env.o node.o input.o div.o symbol.o dictionary.o reg.o \
+ number.o majorminor.o
+CCSRCS=env.cc node.cc input.cc div.cc symbol.cc dictionary.cc reg.cc \
+ number.cc majorminor.cc
+HDRS=charinfo.h dictionary.h div.h env.h hvunits.h node.h reg.h request.h \
+ symbol.h token.h troff.h
+GENSRCS=majorminor.cc
+NAMEPREFIX=$(g)
+
+majorminor.cc: ../VERSION
+ @echo Making $@
+ @-rm -f $@
+ @echo const char \*major_version = \
+ \"`sed -e 's/^\([^.]*\)\..*$$/\1/' $(srcdir)/../VERSION`\"\; >$@
+ @echo const char \*minor_version = \
+ \"`sed -e 's/^[^.]*\.\([0-9]*\).*$$/\1/' $(srcdir)/../VERSION`\"\; >>$@
+
+install_data: hyphen.us
+ -test -d $(datadir) || mkdir $(datadir)
+ -test -d $(datasubdir) || mkdir $(datasubdir)
+ -test -d $(tmacdir) || mkdir $(tmacdir)
+ -rm -f $(tmacdir)/hyphen.us
+ $(INSTALL_DATA) $(srcdir)/hyphen.us $(tmacdir)/hyphen.us
+
+uninstall_sub:
+ -rm -f $(tmacdir)/hyphen.us
diff --git a/gnu/usr.bin/groff/troff/TODO b/gnu/usr.bin/groff/troff/TODO
new file mode 100644
index 0000000..c8ee6bc
--- /dev/null
+++ b/gnu/usr.bin/groff/troff/TODO
@@ -0,0 +1,136 @@
+Give a more helpful error message when the indent is set to a value
+greater than the line-length.
+
+Tracing. This is a pain to implement because requests are responsible
+for reading their own arguments.
+
+Possibly implement -s option (stop every N pages). This functionality
+would be more appropriate in a postprocessor.
+
+Line breaking should be smarter. In particular, it should be possible
+to shrink spaces. Also avoid having a line that's been shrunk a lot
+next to a line that's been stretched a lot. The difficulty is to
+design a mechanism that allows the user complete control over the
+decision of where to break the line.
+
+Provide a mechanism to control the shape of the rag in non-justified
+text.
+
+Add a discretionary break escape sequence. \B'...'...'...' like TeX.
+
+Think about kerning between characters and spaces. (Need to implement
+get_breakpoints and split methods for kern_pair_node class.)
+
+In troff, if .L > 1 when a diversion is reread in no-fill mode, then
+extra line-spacing is added on. Groff at the moment treats line-spacing
+like vertical spacing and doesn't do this.
+
+Suppose \(ch comes from a special font S, and that the current font is
+R. Suppose that R contains a hyphen character and that S does not.
+Suppose that the current font is R. Suppose that \(ch is in a word
+and has a non-zero hyphen-type. Then we ought to be able to hyphenate,
+but we won't be able to because we will look for the hyphen only in
+font S and not in font R.
+
+Variant of tm which doesn't write a newline.
+
+Perhaps the current input level should be accessible in a number register.
+
+Should \w deal with a newline like \X?
+
+Have another look at uses of token::delimiter. Perhaps we need to
+distinguish the case where we want to see if a token could start a
+number, from the case where we want to see if it could occur somewhere
+in a number expression.
+
+Provide a facility like copy thru in pic.
+
+Fancier implementation of font families which doesn't group fonts into
+families purely on the basis of their names.
+
+In the DESC file make the number of fonts optional if they are all on
+one line.
+
+Number register to give the diversion level.
+
+Time various alternative implementations of scale (both in font.c and
+number.c). On a sparc it's faster to always do it in floating point.
+
+Devise a more compact representation for the hyphenation patterns trie.
+
+Have a per-environment parameter to increase letter-spacing.
+
+Number register to return character height.
+
+Number register to return character slant.
+
+Request to set character height.
+
+Request to set character slant.
+
+Provide some way to upcase or downcase strings.
+
+Support non-uniformly scalable fonts. Perhaps associate a suffix with
+a particular range of sizes. eg
+ sizesuffix .display 14-512
+Then is you ask for R at pointsize 16, groff will first look for
+R.display and then R. Probably necessary to be able to specify a
+separate unitwidth for each sizesuffix (eg. for X).
+
+Request to copy an environment into the current environment.
+
+Variant of `.it' for which a line interrupted with \c counts as one
+input line.
+
+Make it possible to suppress hyphenation on a word-by-word basis.
+(Perhaps store hyphenation flags in tfont.)
+
+Possibly allow multiple simultaneous input line traps.
+
+Unpaddable, breakable space escape sequence.
+
+Support hanging punctuation.
+
+In justified text, if the last line of a paragraph is only a little
+bit short it might be desirable to justify the line. Allow the user
+control over this.
+
+Have a blank line macro like the end macro. When a blank line macro
+has been set, then a blank line causes the blank line macro to be
+called rather than doing the equivalent of .sp.
+
+The pm request could print where the macro was defined. Also could
+optionally print the contents of a macro.
+
+Provide some way to round numbers to multiples of the current
+horizontal or vertical resolution.
+
+Better string-processing support (substring, length, search).
+
+Generalized ligatures.
+
+Provide some way for a macro to tell whether it was called with `'' or
+`.'. This would be useful for implementing a tracing macro package.
+
+Request to remove an environment. (Maintain a count of the references
+to the environment from the environment table, environment dictionary
+or environment stack.)
+
+Perhaps in the nr request a leading `-' should only be recognized as a
+decrement when it's at the same input level as the request.
+
+Don't ever change a charinfo. Create new variants instead and chain
+them together.
+
+Make it possible to tr characters onto \~.
+
+Unix troff appears to read the first character of a request name in
+copy mode. Should we do the same?
+
+Number register giving name of end macro.
+
+More thorough range checking.
+
+Provide syntax for octal and hexadecimal numeric constants. Perhaps
+o#100 and x#7f as per Scheme. Or perhaps PostScript 16#7f. Ambiguity
+between whether `c' is treated as digit or scaling indicator.
diff --git a/gnu/usr.bin/groff/troff/charinfo.h b/gnu/usr.bin/groff/troff/charinfo.h
new file mode 100644
index 0000000..3dc131b
--- /dev/null
+++ b/gnu/usr.bin/groff/troff/charinfo.h
@@ -0,0 +1,165 @@
+// -*- C++ -*-
+/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
+ Written by James Clark (jjc@jclark.com)
+
+This file is part of groff.
+
+groff is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
+
+groff is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License along
+with groff; see the file COPYING. If not, write to the Free Software
+Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+class macro;
+
+class charinfo {
+ static int next_index;
+ charinfo *translation;
+ int index;
+ int number;
+ macro *mac;
+ unsigned char special_translation;
+ unsigned char hyphenation_code;
+ unsigned char flags;
+ unsigned char ascii_code;
+ char not_found;
+ char transparent_translate; // non-zero means translation applies to
+ // to transparent throughput
+public:
+ enum {
+ ENDS_SENTENCE = 1,
+ BREAK_BEFORE = 2,
+ BREAK_AFTER = 4,
+ OVERLAPS_HORIZONTALLY = 8,
+ OVERLAPS_VERTICALLY = 16,
+ TRANSPARENT = 32,
+ NUMBERED = 64
+ };
+ enum {
+ TRANSLATE_NONE,
+ TRANSLATE_SPACE,
+ TRANSLATE_DUMMY,
+ TRANSLATE_STRETCHABLE_SPACE,
+ TRANSLATE_HYPHEN_INDICATOR
+ };
+ symbol nm;
+ charinfo(symbol s);
+ int get_index();
+ int ends_sentence();
+ int overlaps_vertically();
+ int overlaps_horizontally();
+ int can_break_before();
+ int can_break_after();
+ int transparent();
+ unsigned char get_hyphenation_code();
+ unsigned char get_ascii_code();
+ void set_hyphenation_code(unsigned char);
+ void set_ascii_code(unsigned char);
+ charinfo *get_translation(int = 0);
+ void set_translation(charinfo *, int);
+ void set_flags(unsigned char);
+ void set_special_translation(int, int);
+ int get_special_translation(int = 0);
+ macro *set_macro(macro *);
+ macro *get_macro();
+ int first_time_not_found();
+ void set_number(int);
+ int get_number();
+ int numbered();
+};
+
+charinfo *get_charinfo(symbol);
+extern charinfo *charset_table[];
+charinfo *get_charinfo_by_number(int);
+
+inline int charinfo::overlaps_horizontally()
+{
+ return flags & OVERLAPS_HORIZONTALLY;
+}
+
+inline int charinfo::overlaps_vertically()
+{
+ return flags & OVERLAPS_VERTICALLY;
+}
+
+inline int charinfo::can_break_before()
+{
+ return flags & BREAK_BEFORE;
+}
+
+inline int charinfo::can_break_after()
+{
+ return flags & BREAK_AFTER;
+}
+
+inline int charinfo::ends_sentence()
+{
+ return flags & ENDS_SENTENCE;
+}
+
+inline int charinfo::transparent()
+{
+ return flags & TRANSPARENT;
+}
+
+inline int charinfo::numbered()
+{
+ return flags & NUMBERED;
+}
+
+inline charinfo *charinfo::get_translation(int transparent_throughput)
+{
+ return (transparent_throughput && !transparent_translate
+ ? 0
+ : translation);
+}
+
+inline unsigned char charinfo::get_hyphenation_code()
+{
+ return hyphenation_code;
+}
+
+inline unsigned char charinfo::get_ascii_code()
+{
+ return ascii_code;
+}
+
+inline void charinfo::set_flags(unsigned char c)
+{
+ flags = c;
+}
+
+inline int charinfo::get_index()
+{
+ return index;
+}
+
+inline int charinfo::get_special_translation(int transparent_throughput)
+{
+ return (transparent_throughput && !transparent_translate
+ ? int(TRANSLATE_NONE)
+ : special_translation);
+}
+
+inline macro *charinfo::get_macro()
+{
+ return mac;
+}
+
+inline int charinfo::first_time_not_found()
+{
+ if (not_found)
+ return 0;
+ else {
+ not_found = 1;
+ return 1;
+ }
+}
diff --git a/gnu/usr.bin/groff/troff/column.cc b/gnu/usr.bin/groff/troff/column.cc
new file mode 100644
index 0000000..230e544
--- /dev/null
+++ b/gnu/usr.bin/groff/troff/column.cc
@@ -0,0 +1,732 @@
+// -*- C++ -*-
+/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
+ Written by James Clark (jjc@jclark.com)
+
+This file is part of groff.
+
+groff is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
+
+groff is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License along
+with groff; see the file COPYING. If not, write to the Free Software
+Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#ifdef COLUMN
+
+#include "troff.h"
+#include "symbol.h"
+#include "dictionary.h"
+#include "hvunits.h"
+#include "env.h"
+#include "request.h"
+#include "node.h"
+#include "token.h"
+#include "div.h"
+#include "reg.h"
+#include "stringclass.h"
+
+void output_file::vjustify(vunits, symbol)
+{
+ // do nothing
+}
+
+struct justification_spec;
+struct output_line;
+
+class column : public output_file {
+private:
+ output_file *out;
+ vunits bottom;
+ output_line *col;
+ output_line **tail;
+ void add_output_line(output_line *);
+ void begin_page(int pageno, vunits page_length);
+ void flush();
+ void print_line(hunits, vunits, node *, vunits, vunits);
+ void vjustify(vunits, symbol);
+ void transparent_char(unsigned char c);
+ void copy_file(hunits, vunits, const char *);
+ int is_printing();
+ void check_bottom();
+public:
+ column();
+ ~column();
+ void start();
+ void output();
+ void justify(const justification_spec &);
+ void trim();
+ void reset();
+ vunits get_bottom();
+ vunits get_last_extra_space();
+ int is_active() { return out != 0; }
+};
+
+column *the_column = 0;
+
+struct transparent_output_line;
+struct vjustify_output_line;
+
+class output_line {
+ output_line *next;
+public:
+ output_line();
+ virtual ~output_line();
+ virtual void output(output_file *, vunits);
+ virtual transparent_output_line *as_transparent_output_line();
+ virtual vjustify_output_line *as_vjustify_output_line();
+ virtual vunits distance();
+ virtual vunits height();
+ virtual void reset();
+ virtual vunits extra_space(); // post line
+ friend class column;
+ friend class justification_spec;
+};
+
+class position_output_line : public output_line {
+ vunits dist;
+public:
+ position_output_line(vunits);
+ vunits distance();
+};
+
+class node_output_line : public position_output_line {
+ node *nd;
+ hunits page_offset;
+ vunits before;
+ vunits after;
+public:
+ node_output_line(vunits, node *, hunits, vunits, vunits);
+ ~node_output_line();
+ void output(output_file *, vunits);
+ vunits height();
+ vunits extra_space();
+};
+
+class vjustify_output_line : public position_output_line {
+ vunits current;
+ symbol typ;
+public:
+ vjustify_output_line(vunits dist, symbol);
+ vunits height();
+ vjustify_output_line *as_vjustify_output_line();
+ void vary(vunits amount);
+ void reset();
+ symbol type();
+};
+
+inline symbol vjustify_output_line::type()
+{
+ return typ;
+}
+
+class copy_file_output_line : public position_output_line {
+ symbol filename;
+ hunits hpos;
+public:
+ copy_file_output_line(vunits, const char *, hunits);
+ void output(output_file *, vunits);
+};
+
+class transparent_output_line : public output_line {
+ string buf;
+public:
+ transparent_output_line();
+ void output(output_file *, vunits);
+ void append_char(unsigned char c);
+ transparent_output_line *as_transparent_output_line();
+};
+
+output_line::output_line() : next(0)
+{
+}
+
+output_line::~output_line()
+{
+}
+
+void output_line::reset()
+{
+}
+
+transparent_output_line *output_line::as_transparent_output_line()
+{
+ return 0;
+}
+
+vjustify_output_line *output_line::as_vjustify_output_line()
+{
+ return 0;
+}
+
+void output_line::output(output_file *, vunits)
+{
+}
+
+vunits output_line::distance()
+{
+ return V0;
+}
+
+vunits output_line::height()
+{
+ return V0;
+}
+
+vunits output_line::extra_space()
+{
+ return V0;
+}
+
+position_output_line::position_output_line(vunits d)
+: dist(d)
+{
+}
+
+vunits position_output_line::distance()
+{
+ return dist;
+}
+
+node_output_line::node_output_line(vunits d, node *n, hunits po, vunits b, vunits a)
+: position_output_line(d), nd(n), page_offset(po), before(b), after(a)
+{
+}
+
+node_output_line::~node_output_line()
+{
+ delete_node_list(nd);
+}
+
+void node_output_line::output(output_file *out, vunits pos)
+{
+ out->print_line(page_offset, pos, nd, before, after);
+ nd = 0;
+}
+
+vunits node_output_line::height()
+{
+ return after;
+}
+
+vunits node_output_line::extra_space()
+{
+ return after;
+}
+
+vjustify_output_line::vjustify_output_line(vunits d, symbol t)
+: position_output_line(d), typ(t)
+{
+}
+
+void vjustify_output_line::reset()
+{
+ current = V0;
+}
+
+vunits vjustify_output_line::height()
+{
+ return current;
+}
+
+vjustify_output_line *vjustify_output_line::as_vjustify_output_line()
+{
+ return this;
+}
+
+inline void vjustify_output_line::vary(vunits amount)
+{
+ current += amount;
+}
+
+transparent_output_line::transparent_output_line()
+{
+}
+
+transparent_output_line *transparent_output_line::as_transparent_output_line()
+{
+ return this;
+}
+
+void transparent_output_line::append_char(unsigned char c)
+{
+ assert(c != 0);
+ buf += c;
+}
+
+void transparent_output_line::output(output_file *out, vunits)
+{
+ int len = buf.length();
+ for (int i = 0; i < len; i++)
+ out->transparent_char(buf[i]);
+}
+
+copy_file_output_line::copy_file_output_line(vunits d, const char *f, hunits h)
+: position_output_line(d), hpos(h), filename(f)
+{
+}
+
+void copy_file_output_line::output(output_file *out, vunits pos)
+{
+ out->copy_file(hpos, pos, filename.contents());
+}
+
+column::column()
+: bottom(V0), col(0), tail(&col), out(0)
+{
+}
+
+column::~column()
+{
+ assert(out != 0);
+ error("automatically outputting column before exiting");
+ output();
+ delete the_output;
+}
+
+void column::start()
+{
+ assert(out == 0);
+ if (!the_output)
+ init_output();
+ assert(the_output != 0);
+ out = the_output;
+ the_output = this;
+}
+
+void column::begin_page(int pageno, vunits page_length)
+{
+ assert(out != 0);
+ if (col) {
+ error("automatically outputting column before beginning next page");
+ output();
+ the_output->begin_page(pageno, page_length);
+ }
+ else
+ out->begin_page(pageno, page_length);
+
+}
+
+void column::flush()
+{
+ assert(out != 0);
+ out->flush();
+}
+
+int column::is_printing()
+{
+ assert(out != 0);
+ return out->is_printing();
+}
+
+vunits column::get_bottom()
+{
+ return bottom;
+}
+
+void column::add_output_line(output_line *ln)
+{
+ *tail = ln;
+ bottom += ln->distance();
+ bottom += ln->height();
+ ln->next = 0;
+ tail = &(*tail)->next;
+}
+
+void column::print_line(hunits page_offset, vunits pos, node *nd,
+ vunits before, vunits after)
+{
+ assert(out != 0);
+ add_output_line(new node_output_line(pos - bottom, nd, page_offset, before, after));
+}
+
+void column::vjustify(vunits pos, symbol typ)
+{
+ assert(out != 0);
+ add_output_line(new vjustify_output_line(pos - bottom, typ));
+}
+
+void column::transparent_char(unsigned char c)
+{
+ assert(out != 0);
+ transparent_output_line *tl = 0;
+ if (*tail)
+ tl = (*tail)->as_transparent_output_line();
+ if (!tl) {
+ tl = new transparent_output_line;
+ add_output_line(tl);
+ }
+ tl->append_char(c);
+}
+
+void column::copy_file(hunits page_offset, vunits pos, const char *filename)
+{
+ assert(out != 0);
+ add_output_line(new copy_file_output_line(pos - bottom, filename, page_offset));
+}
+
+void column::trim()
+{
+ output_line **spp = 0;
+ for (output_line **pp = &col; *pp; pp = &(*pp)->next)
+ if ((*pp)->as_vjustify_output_line() == 0)
+ spp = 0;
+ else if (!spp)
+ spp = pp;
+ if (spp) {
+ output_line *ln = *spp;
+ *spp = 0;
+ tail = spp;
+ while (ln) {
+ output_line *tem = ln->next;
+ bottom -= ln->distance();
+ bottom -= ln->height();
+ delete ln;
+ ln = tem;
+ }
+ }
+}
+
+void column::reset()
+{
+ bottom = V0;
+ for (output_line *ln = col; ln; ln = ln->next) {
+ bottom += ln->distance();
+ ln->reset();
+ bottom += ln->height();
+ }
+}
+
+void column::check_bottom()
+{
+ vunits b;
+ for (output_line *ln = col; ln; ln = ln->next) {
+ b += ln->distance();
+ b += ln->height();
+ }
+ assert(b == bottom);
+}
+
+void column::output()
+{
+ assert(out != 0);
+ vunits vpos(V0);
+ output_line *ln = col;
+ while (ln) {
+ vpos += ln->distance();
+ ln->output(out, vpos);
+ vpos += ln->height();
+ output_line *tem = ln->next;
+ delete ln;
+ ln = tem;
+ }
+ tail = &col;
+ bottom = V0;
+ col = 0;
+ the_output = out;
+ out = 0;
+}
+
+vunits column::get_last_extra_space()
+{
+ if (!col)
+ return V0;
+ for (output_line *p = col; p->next; p = p->next)
+ ;
+ return p->extra_space();
+}
+
+class justification_spec {
+ vunits height;
+ symbol *type;
+ vunits *amount;
+ int n;
+ int maxn;
+public:
+ justification_spec(vunits);
+ ~justification_spec();
+ void append(symbol t, vunits v);
+ void justify(output_line *, vunits *bottomp) const;
+};
+
+justification_spec::justification_spec(vunits h)
+: height(h), n(0), maxn(10)
+{
+ type = new symbol[maxn];
+ amount = new vunits[maxn];
+}
+
+justification_spec::~justification_spec()
+{
+ a_delete type;
+ a_delete amount;
+}
+
+void justification_spec::append(symbol t, vunits v)
+{
+ if (v <= V0) {
+ if (v < V0)
+ warning(WARN_RANGE,
+ "maximum space for vertical justification must not be negative");
+ else
+ warning(WARN_RANGE,
+ "maximum space for vertical justification must not be zero");
+ return;
+ }
+ if (n >= maxn) {
+ maxn *= 2;
+ symbol *old_type = type;
+ type = new symbol[maxn];
+ int i;
+ for (i = 0; i < n; i++)
+ type[i] = old_type[i];
+ a_delete old_type;
+ vunits *old_amount = amount;
+ amount = new vunits[maxn];
+ for (i = 0; i < n; i++)
+ amount[i] = old_amount[i];
+ a_delete old_amount;
+ }
+ assert(n < maxn);
+ type[n] = t;
+ amount[n] = v;
+ n++;
+}
+
+void justification_spec::justify(output_line *col, vunits *bottomp) const
+{
+ if (*bottomp >= height)
+ return;
+ vunits total;
+ output_line *p;
+ for (p = col; p; p = p->next) {
+ vjustify_output_line *sp = p->as_vjustify_output_line();
+ if (sp) {
+ symbol t = sp->type();
+ for (int i = 0; i < n; i++) {
+ if (t == type[i])
+ total += amount[i];
+ }
+ }
+ }
+ vunits gap = height - *bottomp;
+ for (p = col; p; p = p->next) {
+ vjustify_output_line *sp = p->as_vjustify_output_line();
+ if (sp) {
+ symbol t = sp->type();
+ for (int i = 0; i < n; i++) {
+ if (t == type[i]) {
+ if (total <= gap) {
+ sp->vary(amount[i]);
+ gap -= amount[i];
+ }
+ else {
+ // gap < total
+ vunits v = scale(amount[i], gap, total);
+ sp->vary(v);
+ gap -= v;
+ }
+ total -= amount[i];
+ }
+ }
+ }
+ }
+ assert(total == V0);
+ *bottomp = height - gap;
+}
+
+void column::justify(const justification_spec &js)
+{
+ check_bottom();
+ js.justify(col, &bottom);
+ check_bottom();
+}
+
+void column_justify()
+{
+ vunits height;
+ if (!the_column->is_active())
+ error("can't justify column - column not active");
+ else if (get_vunits(&height, 'v')) {
+ justification_spec js(height);
+ symbol nm = get_long_name(1);
+ if (!nm.is_null()) {
+ vunits v;
+ if (get_vunits(&v, 'v')) {
+ js.append(nm, v);
+ int err = 0;
+ while (has_arg()) {
+ nm = get_long_name(1);
+ if (nm.is_null()) {
+ err = 1;
+ break;
+ }
+ if (!get_vunits(&v, 'v')) {
+ err = 1;
+ break;
+ }
+ js.append(nm, v);
+ }
+ if (!err)
+ the_column->justify(js);
+ }
+ }
+ }
+ skip_line();
+}
+
+void column_start()
+{
+ if (the_column->is_active())
+ error("can't start column - column already active");
+ else
+ the_column->start();
+ skip_line();
+}
+
+void column_output()
+{
+ if (!the_column->is_active())
+ error("can't output column - column not active");
+ else
+ the_column->output();
+ skip_line();
+}
+
+void column_trim()
+{
+ if (!the_column->is_active())
+ error("can't trim column - column not active");
+ else
+ the_column->trim();
+ skip_line();
+}
+
+void column_reset()
+{
+ if (!the_column->is_active())
+ error("can't reset column - column not active");
+ else
+ the_column->reset();
+ skip_line();
+}
+
+class column_bottom_reg : public reg {
+public:
+ const char *get_string();
+};
+
+const char *column_bottom_reg::get_string()
+{
+ return itoa(the_column->get_bottom().to_units());
+}
+
+class column_extra_space_reg : public reg {
+public:
+ const char *get_string();
+};
+
+const char *column_extra_space_reg::get_string()
+{
+ return itoa(the_column->get_last_extra_space().to_units());
+}
+
+class column_active_reg : public reg {
+public:
+ const char *get_string();
+};
+
+const char *column_active_reg::get_string()
+{
+ return the_column->is_active() ? "1" : "0";
+}
+
+static int no_vjustify_mode = 0;
+
+class vjustify_node : public node {
+ symbol typ;
+public:
+ vjustify_node(symbol);
+ int reread(int *);
+ const char *type();
+ int same(node *);
+ node *copy();
+};
+
+vjustify_node::vjustify_node(symbol t)
+: typ(t)
+{
+}
+
+node *vjustify_node::copy()
+{
+ return new vjustify_node(typ);
+}
+
+const char *vjustify_node::type()
+{
+ return "vjustify_node";
+}
+
+int vjustify_node::same(node *nd)
+{
+ return typ == ((vjustify_node *)nd)->typ;
+}
+
+int vjustify_node::reread(int *bolp)
+{
+ curdiv->vjustify(typ);
+ *bolp = 1;
+ return 1;
+}
+
+void macro_diversion::vjustify(symbol type)
+{
+ if (!no_vjustify_mode)
+ mac->append(new vjustify_node(type));
+}
+
+void top_level_diversion::vjustify(symbol type)
+{
+ if (no_space_mode || no_vjustify_mode)
+ return;
+ assert(first_page_begun); // I'm not sure about this.
+ the_output->vjustify(vertical_position, type);
+}
+
+void no_vjustify()
+{
+ skip_line();
+ no_vjustify_mode = 1;
+}
+
+void restore_vjustify()
+{
+ skip_line();
+ no_vjustify_mode = 0;
+}
+
+void init_column_requests()
+{
+ the_column = new column;
+ init_request("cols", column_start);
+ init_request("colo", column_output);
+ init_request("colj", column_justify);
+ init_request("colr", column_reset);
+ init_request("colt", column_trim);
+ init_request("nvj", no_vjustify);
+ init_request("rvj", restore_vjustify);
+ number_reg_dictionary.define(".colb", new column_bottom_reg);
+ number_reg_dictionary.define(".colx", new column_extra_space_reg);
+ number_reg_dictionary.define(".cola", new column_active_reg);
+ number_reg_dictionary.define(".nvj",
+ new constant_int_reg(&no_vjustify_mode));
+}
+
+#endif /* COLUMN */
diff --git a/gnu/usr.bin/groff/troff/dictionary.cc b/gnu/usr.bin/groff/troff/dictionary.cc
new file mode 100644
index 0000000..2e6e32d
--- /dev/null
+++ b/gnu/usr.bin/groff/troff/dictionary.cc
@@ -0,0 +1,211 @@
+// -*- C++ -*-
+/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
+ Written by James Clark (jjc@jclark.com)
+
+This file is part of groff.
+
+groff is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
+
+groff is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License along
+with groff; see the file COPYING. If not, write to the Free Software
+Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+
+#include "troff.h"
+#include "symbol.h"
+#include "dictionary.h"
+
+// is `p' a good size for a hash table
+
+static int is_good_size(int p)
+{
+ const int SMALL = 10;
+ for (unsigned i = 2; i <= p/2; i++)
+ if (p % i == 0)
+ return 0;
+ for (i = 0x100; i != 0; i <<= 8)
+ if (i % p <= SMALL || i % p > p - SMALL)
+ return 0;
+ return 1;
+}
+
+dictionary::dictionary(int n) : threshold(0.5), factor(1.5), used(0), size(n)
+{
+ table = new association[n];
+ for (int i = 0; i < n; i++)
+ table[i].v = 0;
+}
+
+// see Knuth, Sorting and Searching, p518, Algorithm L
+// we can't use double-hashing because we want a remove function
+
+void *dictionary::lookup(symbol s, void *v)
+{
+ for (int i = int(s.hash() % size);
+ table[i].v != 0;
+ i == 0 ? i = size - 1: --i)
+ if (s == table[i].s) {
+ if (v != 0) {
+ void *temp = table[i].v;
+ table[i].v = v;
+ return temp;
+ }
+ else
+ return table[i].v;
+ }
+ if (v == 0)
+ return 0;
+ ++used;
+ table[i].v = v;
+ table[i].s = s;
+ if ((double)used/(double)size >= threshold || used + 1 >= size) {
+ int old_size = size;
+ size = int(size*factor);
+ while (!is_good_size(size))
+ ++size;
+ association *old_table = table;
+ table = new association[size];
+ used = 0;
+ for (i = 0; i < old_size; i++)
+ if (old_table[i].v != 0)
+ (void)lookup(old_table[i].s, old_table[i].v);
+ a_delete old_table;
+ }
+ return 0;
+}
+
+void *dictionary::lookup(const char *p)
+{
+ symbol s(p, MUST_ALREADY_EXIST);
+ if (s.is_null())
+ return 0;
+ else
+ return lookup(s);
+}
+
+// see Knuth, Sorting and Searching, p527, Algorithm R
+
+void *dictionary::remove(symbol s)
+{
+ // this relies on the fact that we are using linear probing
+ for (int i = int(s.hash() % size);
+ table[i].v != 0 && s != table[i].s;
+ i == 0 ? i = size - 1: --i)
+ ;
+ void *p = table[i].v;
+ while (table[i].v != 0) {
+ table[i].v = 0;
+ int j = i;
+ int r;
+ do {
+ --i;
+ if (i < 0)
+ i = size - 1;
+ if (table[i].v == 0)
+ break;
+ r = int(table[i].s.hash() % size);
+ } while ((i <= r && r < j) || (r < j && j < i) || (j < i && i <= r));
+ table[j] = table[i];
+ }
+ if (p != 0)
+ --used;
+ return p;
+}
+
+dictionary_iterator::dictionary_iterator(dictionary &d) : dict(&d), i(0)
+{
+}
+
+int dictionary_iterator::get(symbol *sp, void **vp)
+{
+ for (; i < dict->size; i++)
+ if (dict->table[i].v) {
+ *sp = dict->table[i].s;
+ *vp = dict->table[i].v;
+ i++;
+ return 1;
+ }
+ return 0;
+}
+
+object_dictionary_iterator::object_dictionary_iterator(object_dictionary &od)
+ : di(od.d)
+{
+}
+
+object::object() : rcount(0)
+{
+}
+
+object::~object()
+{
+}
+
+void object::add_reference()
+{
+ rcount += 1;
+}
+
+void object::remove_reference()
+{
+ if (--rcount == 0)
+ delete this;
+}
+
+object_dictionary::object_dictionary(int n) : d(n)
+{
+}
+
+object *object_dictionary::lookup(symbol nm)
+{
+ return (object *)d.lookup(nm);
+}
+
+void object_dictionary::define(symbol nm, object *obj)
+{
+ obj->add_reference();
+ obj = (object *)d.lookup(nm, obj);
+ if (obj)
+ obj->remove_reference();
+}
+
+void object_dictionary::rename(symbol oldnm, symbol newnm)
+{
+ object *obj = (object *)d.remove(oldnm);
+ if (obj) {
+ obj = (object *)d.lookup(newnm, obj);
+ if (obj)
+ obj->remove_reference();
+ }
+}
+
+void object_dictionary::remove(symbol nm)
+{
+ object *obj = (object *)d.remove(nm);
+ if (obj)
+ obj->remove_reference();
+}
+
+// Return non-zero if oldnm was defined.
+
+int object_dictionary::alias(symbol newnm, symbol oldnm)
+{
+ object *obj = (object *)d.lookup(oldnm);
+ if (obj) {
+ obj->add_reference();
+ obj = (object *)d.lookup(newnm, obj);
+ if (obj)
+ obj->remove_reference();
+ return 1;
+ }
+ return 0;
+}
+
diff --git a/gnu/usr.bin/groff/troff/dictionary.h b/gnu/usr.bin/groff/troff/dictionary.h
new file mode 100644
index 0000000..47d6d59
--- /dev/null
+++ b/gnu/usr.bin/groff/troff/dictionary.h
@@ -0,0 +1,92 @@
+// -*- C++ -*-
+/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
+ Written by James Clark (jjc@jclark.com)
+
+This file is part of groff.
+
+groff is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
+
+groff is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License along
+with groff; see the file COPYING. If not, write to the Free Software
+Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+
+
+// there is no distinction between name with no value and name with NULL value
+// null names are not permitted (they will be ignored).
+
+struct association {
+ symbol s;
+ void *v;
+ association() : v(0) {}
+};
+
+class dictionary;
+
+class dictionary_iterator {
+ dictionary *dict;
+ int i;
+public:
+ dictionary_iterator(dictionary &);
+ int get(symbol *, void **);
+};
+
+class dictionary {
+ int size;
+ int used;
+ double threshold;
+ double factor;
+ association *table;
+ void rehash(int);
+public:
+ dictionary(int);
+ void *lookup(symbol s, void *v=0); // returns value associated with key
+ void *lookup(const char *);
+ // if second parameter not NULL, value will be replaced
+ void *remove(symbol);
+ friend class dictionary_iterator;
+};
+
+class object {
+ int rcount;
+ public:
+ object();
+ virtual ~object();
+ void add_reference();
+ void remove_reference();
+};
+
+class object_dictionary;
+
+class object_dictionary_iterator {
+ dictionary_iterator di;
+public:
+ object_dictionary_iterator(object_dictionary &);
+ int get(symbol *, object **);
+};
+
+class object_dictionary {
+ dictionary d;
+public:
+ object_dictionary(int);
+ object *lookup(symbol nm);
+ void define(symbol nm, object *obj);
+ void rename(symbol oldnm, symbol newnm);
+ void remove(symbol nm);
+ int alias(symbol newnm, symbol oldnm);
+ friend class object_dictionary_iterator;
+};
+
+
+inline int object_dictionary_iterator::get(symbol *sp, object **op)
+{
+ return di.get(sp, (void **)op);
+}
diff --git a/gnu/usr.bin/groff/troff/div.cc b/gnu/usr.bin/groff/troff/div.cc
new file mode 100644
index 0000000..f82d838
--- /dev/null
+++ b/gnu/usr.bin/groff/troff/div.cc
@@ -0,0 +1,1131 @@
+// -*- C++ -*-
+/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
+ Written by James Clark (jjc@jclark.com)
+
+This file is part of groff.
+
+groff is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
+
+groff is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License along
+with groff; see the file COPYING. If not, write to the Free Software
+Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+
+// diversions
+
+#include "troff.h"
+#include "symbol.h"
+#include "dictionary.h"
+#include "hvunits.h"
+#include "env.h"
+#include "request.h"
+#include "node.h"
+#include "token.h"
+#include "div.h"
+#include "reg.h"
+
+int exit_started = 0; // the exit process has started
+int done_end_macro = 0; // the end macro (if any) has finished
+int seen_last_page_ejector = 0; // seen the LAST_PAGE_EJECTOR cookie
+int last_page_number = 0; // if > 0, the number of the last page
+ // specified with -o
+static int began_page_in_end_macro = 0; // a new page was begun during the end macro
+
+static int last_post_line_extra_space = 0; // needed for \n(.a
+static int nl_reg_contents = -1;
+static int dl_reg_contents = 0;
+static int dn_reg_contents = 0;
+static int vertical_position_traps_flag = 1;
+static vunits truncated_space;
+static vunits needed_space;
+
+diversion::diversion(symbol s)
+: nm(s), prev(0), vertical_position(V0), marked_place(V0), high_water_mark(V0)
+{
+}
+
+struct vertical_size {
+ vunits pre_extra, post_extra, pre, post;
+ vertical_size(vunits vs, int ls);
+};
+
+vertical_size::vertical_size(vunits vs, int ls)
+: pre_extra(V0), post_extra(V0), pre(vs)
+{
+ if (ls > 1)
+ post = vs*(ls - 1);
+ else
+ post = V0;
+}
+
+void node::set_vertical_size(vertical_size *)
+{
+}
+
+void extra_size_node::set_vertical_size(vertical_size *v)
+{
+ if (n < V0) {
+ if (-n > v->pre_extra)
+ v->pre_extra = -n;
+ }
+ else if (n > v->post_extra)
+ v->post_extra = n;
+}
+
+void vertical_size_node::set_vertical_size(vertical_size *v)
+{
+ if (n < V0)
+ v->pre = -n;
+ else
+ v->post = n;
+}
+
+top_level_diversion *topdiv;
+
+diversion *curdiv;
+
+void do_divert(int append)
+{
+ tok.skip();
+ symbol nm = get_name();
+ if (nm.is_null()) {
+ if (curdiv->prev) {
+ diversion *temp = curdiv;
+ curdiv = curdiv->prev;
+ delete temp;
+ }
+ else
+ warning(WARN_DI, "diversion stack underflow");
+ }
+ else {
+ macro_diversion *md = new macro_diversion(nm, append);
+ md->prev = curdiv;
+ curdiv = md;
+ }
+ skip_line();
+}
+
+void divert()
+{
+ do_divert(0);
+}
+
+void divert_append()
+{
+ do_divert(1);
+}
+
+void diversion::need(vunits n)
+{
+ vunits d = distance_to_next_trap();
+ if (d < n) {
+ space(d, 1);
+ truncated_space = -d;
+ needed_space = n;
+ }
+}
+
+macro_diversion::macro_diversion(symbol s, int append)
+: diversion(s), max_width(H0)
+{
+#if 0
+ if (append) {
+ /* We don't allow recursive appends eg:
+
+ .da a
+ .a
+ .di
+
+ This causes an infinite loop in troff anyway.
+ This is because the user could do
+
+ .as a foo
+
+ in the diversion, and this would mess things up royally,
+ since there would be two things appending to the same
+ macro_header.
+ To make it work, we would have to copy the _contents_
+ of the macro into which we were diverting; this doesn't
+ strike me as worthwhile.
+ However,
+
+ .di a
+ .a
+ .a
+ .di
+
+ will work and will make `a' contain two copies of what it contained
+ before; in troff, `a' would contain nothing. */
+ request_or_macro *rm
+ = (request_or_macro *)request_dictionary.remove(s);
+ if (!rm || (mac = rm->to_macro()) == 0)
+ mac = new macro;
+ }
+ else
+ mac = new macro;
+#endif
+ // We can now catch the situation described above by comparing
+ // the length of the charlist in the macro_header with the length
+ // stored in the macro. When we detect this, we copy the contents.
+ mac = new macro;
+ if (append) {
+ request_or_macro *rm
+ = (request_or_macro *)request_dictionary.lookup(s);
+ if (rm) {
+ macro *m = rm->to_macro();
+ if (m)
+ *mac = *m;
+ }
+ }
+}
+
+macro_diversion::~macro_diversion()
+{
+ request_or_macro *rm = (request_or_macro *)request_dictionary.lookup(nm);
+ macro *m = rm ? rm->to_macro() : 0;
+ if (m) {
+ *m = *mac;
+ delete mac;
+ }
+ else
+ request_dictionary.define(nm, mac);
+ mac = 0;
+ dl_reg_contents = max_width.to_units();
+ dn_reg_contents = vertical_position.to_units();
+}
+
+vunits macro_diversion::distance_to_next_trap()
+{
+ if (!diversion_trap.is_null() && diversion_trap_pos > vertical_position)
+ return diversion_trap_pos - vertical_position;
+ else
+ // Substract vresolution so that vunits::vunits does not overflow.
+ return vunits(INT_MAX - vresolution);
+}
+
+void macro_diversion::transparent_output(unsigned char c)
+{
+ mac->append(c);
+}
+
+void macro_diversion::transparent_output(node *n)
+{
+ mac->append(n);
+}
+
+void macro_diversion::output(node *nd, int retain_size,
+ vunits vs, int ls, hunits width)
+{
+ vertical_size v(vs, ls);
+ while (nd != 0) {
+ nd->set_vertical_size(&v);
+ node *temp = nd;
+ nd = nd->next;
+ if (temp->interpret(mac)) {
+ delete temp;
+ }
+ else {
+#if 1
+ temp->freeze_space();
+#endif
+ mac->append(temp);
+ }
+ }
+ if (!v.post_extra.is_zero())
+ last_post_line_extra_space = v.post_extra.to_units();
+ if (!retain_size) {
+ v.pre = vs;
+ v.post = (ls > 1) ? vs*(ls - 1) : V0;
+ }
+ if (width > max_width)
+ max_width = width;
+ vunits x = v.pre + v.pre_extra + v.post + v.post_extra;
+ if (vertical_position_traps_flag
+ && !diversion_trap.is_null() && diversion_trap_pos > vertical_position
+ && diversion_trap_pos <= vertical_position + x) {
+ vunits trunc = vertical_position + x - diversion_trap_pos;
+ if (trunc > v.post)
+ trunc = v.post;
+ v.post -= trunc;
+ x -= trunc;
+ truncated_space = trunc;
+ spring_trap(diversion_trap);
+ }
+ mac->append(new vertical_size_node(-v.pre));
+ mac->append(new vertical_size_node(v.post));
+ mac->append('\n');
+ vertical_position += x;
+ if (vertical_position - v.post > high_water_mark)
+ high_water_mark = vertical_position - v.post;
+}
+
+void macro_diversion::space(vunits n, int)
+{
+ if (vertical_position_traps_flag
+ && !diversion_trap.is_null() && diversion_trap_pos > vertical_position
+ && diversion_trap_pos <= vertical_position + n) {
+ truncated_space = vertical_position + n - diversion_trap_pos;
+ n = diversion_trap_pos - vertical_position;
+ spring_trap(diversion_trap);
+ }
+ else if (n + vertical_position < V0)
+ n = -vertical_position;
+ mac->append(new diverted_space_node(n));
+ vertical_position += n;
+}
+
+void macro_diversion::copy_file(const char *filename)
+{
+ mac->append(new diverted_copy_file_node(filename));
+}
+
+top_level_diversion::top_level_diversion()
+: page_count(0), have_next_page_number(0), page_length(units_per_inch*11),
+ page_offset(units_per_inch), prev_page_offset(units_per_inch),
+ ejecting_page(0), page_trap_list(0), before_first_page(1), no_space_mode(0),
+ page_number(0), last_page_count(-1)
+{
+}
+
+// find the next trap after pos
+
+trap *top_level_diversion::find_next_trap(vunits *next_trap_pos)
+{
+ trap *next_trap = 0;
+ for (trap *pt = page_trap_list; pt != 0; pt = pt->next)
+ if (!pt->nm.is_null()) {
+ if (pt->position >= V0) {
+ if (pt->position > vertical_position
+ && pt->position < page_length
+ && (next_trap == 0 || pt->position < *next_trap_pos)) {
+ next_trap = pt;
+ *next_trap_pos = pt->position;
+ }
+ }
+ else {
+ vunits pos = pt->position;
+ pos += page_length;
+ if (pos > 0 && pos > vertical_position && (next_trap == 0 || pos < *next_trap_pos)) {
+ next_trap = pt;
+ *next_trap_pos = pos;
+ }
+ }
+ }
+ return next_trap;
+}
+
+vunits top_level_diversion::distance_to_next_trap()
+{
+ vunits d;
+ if (!find_next_trap(&d))
+ return page_length - vertical_position;
+ else
+ return d - vertical_position;
+}
+
+void top_level_diversion::output(node *nd, int retain_size,
+ vunits vs, int ls, hunits /*width*/)
+{
+ no_space_mode = 0;
+ vunits next_trap_pos;
+ trap *next_trap = find_next_trap(&next_trap_pos);
+ if (before_first_page && begin_page())
+ fatal("sorry, I didn't manage to begin the first page in time: use an explicit .br request");
+ vertical_size v(vs, ls);
+ for (node *tem = nd; tem != 0; tem = tem->next)
+ tem->set_vertical_size(&v);
+ if (!v.post_extra.is_zero())
+ last_post_line_extra_space = v.post_extra.to_units();
+ if (!retain_size) {
+ v.pre = vs;
+ v.post = (ls > 1) ? vs*(ls - 1) : V0;
+ }
+ vertical_position += v.pre;
+ vertical_position += v.pre_extra;
+ the_output->print_line(page_offset, vertical_position, nd,
+ v.pre + v.pre_extra, v.post_extra);
+ vertical_position += v.post_extra;
+ if (vertical_position > high_water_mark)
+ high_water_mark = vertical_position;
+ if (vertical_position_traps_flag && vertical_position >= page_length)
+ begin_page();
+ else if (vertical_position_traps_flag
+ && next_trap != 0 && vertical_position >= next_trap_pos) {
+ nl_reg_contents = vertical_position.to_units();
+ truncated_space = v.post;
+ spring_trap(next_trap->nm);
+ }
+ else if (v.post > V0) {
+ vertical_position += v.post;
+ if (vertical_position_traps_flag
+ && next_trap != 0 && vertical_position >= next_trap_pos) {
+ truncated_space = vertical_position - next_trap_pos;
+ vertical_position = next_trap_pos;
+ nl_reg_contents = vertical_position.to_units();
+ spring_trap(next_trap->nm);
+ }
+ else if (vertical_position_traps_flag && vertical_position >= page_length)
+ begin_page();
+ else
+ nl_reg_contents = vertical_position.to_units();
+ }
+ else
+ nl_reg_contents = vertical_position.to_units();
+}
+
+void top_level_diversion::transparent_output(unsigned char c)
+{
+ if (before_first_page && begin_page())
+ // This can only happen with the transparent() request.
+ fatal("sorry, I didn't manage to begin the first page in time: use an explicit .br request");
+ const char *s = asciify(c);
+ while (*s)
+ the_output->transparent_char(*s++);
+}
+
+void top_level_diversion::transparent_output(node * /*n*/)
+{
+ error("can't transparently output node at top level");
+}
+
+void top_level_diversion::copy_file(const char *filename)
+{
+ if (before_first_page && begin_page())
+ fatal("sorry, I didn't manage to begin the first page in time: use an explicit .br request");
+ the_output->copy_file(page_offset, vertical_position, filename);
+}
+
+void top_level_diversion::space(vunits n, int forced)
+{
+ if (no_space_mode) {
+ if (!forced)
+ return;
+ else
+ no_space_mode = 0;
+ }
+ if (before_first_page) {
+ if (begin_page()) {
+ // This happens if there's a top of page trap, and the first-page
+ // transition is caused by `'sp'.
+ truncated_space = n > V0 ? n : V0;
+ return;
+ }
+ }
+ vunits next_trap_pos;
+ trap *next_trap = find_next_trap(&next_trap_pos);
+ vunits y = vertical_position + n;
+ if (vertical_position_traps_flag && next_trap != 0 && y >= next_trap_pos) {
+ vertical_position = next_trap_pos;
+ nl_reg_contents = vertical_position.to_units();
+ truncated_space = y - vertical_position;
+ spring_trap(next_trap->nm);
+ }
+ else if (y < V0) {
+ vertical_position = V0;
+ nl_reg_contents = vertical_position.to_units();
+ }
+ else if (vertical_position_traps_flag && y >= page_length && n >= V0)
+ begin_page();
+ else {
+ vertical_position = y;
+ nl_reg_contents = vertical_position.to_units();
+ }
+}
+
+trap::trap(symbol s, vunits n, trap *p)
+ : nm(s), next(p), position(n)
+{
+}
+
+void top_level_diversion::add_trap(symbol nm, vunits pos)
+{
+ trap *first_free_slot = 0;
+ for (trap **p = &page_trap_list; *p; p = &(*p)->next) {
+ if ((*p)->nm.is_null()) {
+ if (first_free_slot == 0)
+ first_free_slot = *p;
+ }
+ else if ((*p)->position == pos) {
+ (*p)->nm = nm;
+ return;
+ }
+ }
+ if (first_free_slot) {
+ first_free_slot->nm = nm;
+ first_free_slot->position = pos;
+ }
+ else
+ *p = new trap(nm, pos, 0);
+}
+
+void top_level_diversion::remove_trap(symbol nm)
+{
+ for (trap *p = page_trap_list; p; p = p->next)
+ if (p->nm == nm) {
+ p->nm = NULL_SYMBOL;
+ return;
+ }
+}
+
+void top_level_diversion::remove_trap_at(vunits pos)
+{
+ for (trap *p = page_trap_list; p; p = p->next)
+ if (p->position == pos) {
+ p->nm = NULL_SYMBOL;
+ return;
+ }
+}
+
+void top_level_diversion::change_trap(symbol nm, vunits pos)
+{
+ for (trap *p = page_trap_list; p; p = p->next)
+ if (p->nm == nm) {
+ p->position = pos;
+ return;
+ }
+}
+
+void top_level_diversion::print_traps()
+{
+ for (trap *p = page_trap_list; p; p = p->next)
+ if (p->nm.is_null())
+ fprintf(stderr, " empty\n");
+ else
+ fprintf(stderr, "%s\t%d\n", p->nm.contents(), p->position.to_units());
+ fflush(stderr);
+}
+
+void end_diversions()
+{
+ while (curdiv != topdiv) {
+ error("automatically ending diversion `%1' on exit",
+ curdiv->nm.contents());
+ diversion *tem = curdiv;
+ curdiv = curdiv->prev;
+ delete tem;
+ }
+}
+
+void cleanup_and_exit(int exit_code)
+{
+ if (the_output) {
+ the_output->trailer(topdiv->get_page_length());
+ delete the_output;
+ }
+ exit(exit_code);
+}
+
+// returns non-zero if it sprung a top of page trap
+
+int top_level_diversion::begin_page()
+{
+ if (exit_started) {
+ if (page_count == last_page_count
+ ? curenv->is_empty()
+ : (done_end_macro && (seen_last_page_ejector || began_page_in_end_macro)))
+ cleanup_and_exit(0);
+ if (!done_end_macro)
+ began_page_in_end_macro = 1;
+ }
+ if (last_page_number > 0 && page_number == last_page_number)
+ cleanup_and_exit(0);
+ if (!the_output)
+ init_output();
+ ++page_count;
+ if (have_next_page_number) {
+ page_number = next_page_number;
+ have_next_page_number = 0;
+ }
+ else if (before_first_page == 1)
+ page_number = 1;
+ else
+ page_number++;
+ // spring the top of page trap if there is one
+ vunits next_trap_pos;
+ vertical_position = -vresolution;
+ trap *next_trap = find_next_trap(&next_trap_pos);
+ vertical_position = V0;
+ high_water_mark = V0;
+ ejecting_page = 0;
+ // If before_first_page was 2, then the top of page transition was undone
+ // using eg .nr nl 0-1. See nl_reg::set_value.
+ if (before_first_page != 2)
+ the_output->begin_page(page_number, page_length);
+ before_first_page = 0;
+ nl_reg_contents = vertical_position.to_units();
+ if (vertical_position_traps_flag && next_trap != 0 && next_trap_pos == V0) {
+ truncated_space = V0;
+ spring_trap(next_trap->nm);
+ return 1;
+ }
+ else
+ return 0;
+}
+
+void continue_page_eject()
+{
+ if (topdiv->get_ejecting()) {
+ if (curdiv != topdiv)
+ error("can't continue page ejection because of current diversion");
+ else if (!vertical_position_traps_flag)
+ error("can't continue page ejection because vertical position traps disabled");
+ else {
+ push_page_ejector();
+ topdiv->space(topdiv->get_page_length(), 1);
+ }
+ }
+}
+
+void top_level_diversion::set_next_page_number(int n)
+{
+ next_page_number= n;
+ have_next_page_number = 1;
+}
+
+int top_level_diversion::get_next_page_number()
+{
+ return have_next_page_number ? next_page_number : page_number + 1;
+}
+
+void top_level_diversion::set_page_length(vunits n)
+{
+ page_length = n;
+}
+
+diversion::~diversion()
+{
+}
+
+void page_offset()
+{
+ hunits n;
+ // The troff manual says that the default scaling indicator is v,
+ // but it is in fact m: v wouldn't make sense for a horizontally
+ // oriented request.
+ if (!has_arg() || !get_hunits(&n, 'm', topdiv->page_offset))
+ n = topdiv->prev_page_offset;
+ topdiv->prev_page_offset = topdiv->page_offset;
+ topdiv->page_offset = n;
+ skip_line();
+}
+
+void page_length()
+{
+ vunits n;
+ if (has_arg() && get_vunits(&n, 'v', topdiv->get_page_length()))
+ topdiv->set_page_length(n);
+ else
+ topdiv->set_page_length(11*units_per_inch);
+ skip_line();
+}
+
+void when_request()
+{
+ vunits n;
+ if (get_vunits(&n, 'v')) {
+ symbol s = get_name();
+ if (s.is_null())
+ topdiv->remove_trap_at(n);
+ else
+ topdiv->add_trap(s, n);
+ }
+ skip_line();
+}
+
+void begin_page()
+{
+ int got_arg = 0;
+ int n;
+ if (has_arg() && get_integer(&n, topdiv->get_page_number()))
+ got_arg = 1;
+ while (!tok.newline() && !tok.eof())
+ tok.next();
+ if (curdiv == topdiv) {
+ if (topdiv->before_first_page) {
+ if (!break_flag) {
+ if (got_arg)
+ topdiv->set_next_page_number(n);
+ if (got_arg || !topdiv->no_space_mode)
+ topdiv->begin_page();
+ }
+ else if (topdiv->no_space_mode && !got_arg)
+ topdiv->begin_page();
+ else {
+ /* Given this
+
+ .wh 0 x
+ .de x
+ .tm \\n%
+ ..
+ .bp 3
+
+ troff prints
+
+ 1
+ 3
+
+ This code makes groff do the same. */
+
+ push_page_ejector();
+ topdiv->begin_page();
+ if (got_arg)
+ topdiv->set_next_page_number(n);
+ topdiv->set_ejecting();
+ }
+ }
+ else {
+ push_page_ejector();
+ if (break_flag)
+ curenv->do_break();
+ if (got_arg)
+ topdiv->set_next_page_number(n);
+ if (!(topdiv->no_space_mode && !got_arg))
+ topdiv->set_ejecting();
+ }
+ }
+ tok.next();
+}
+
+void no_space()
+{
+ if (curdiv == topdiv)
+ topdiv->no_space_mode = 1;
+ skip_line();
+}
+
+void restore_spacing()
+{
+ if (curdiv == topdiv)
+ topdiv->no_space_mode = 0;
+ skip_line();
+}
+
+/* It is necessary to generate a break before before reading the argument,
+because otherwise arguments using | will be wrong. But if we just
+generate a break as usual, then the line forced out may spring a trap
+and thus push a macro onto the input stack before we have had a chance
+to read the argument to the sp request. We resolve this dilemma by
+setting, before generating the break, a flag which will postpone the
+actual pushing of the macro associated with the trap sprung by the
+outputting of the line forced out by the break till after we have read
+the argument to the request. If the break did cause a trap to be
+sprung, then we don't actually do the space. */
+
+void space_request()
+{
+ postpone_traps();
+ if (break_flag)
+ curenv->do_break();
+ vunits n;
+ if (!has_arg() || !get_vunits(&n, 'v'))
+ n = curenv->get_vertical_spacing();
+ while (!tok.newline() && !tok.eof())
+ tok.next();
+ if (!unpostpone_traps())
+ curdiv->space(n);
+ else
+ // The line might have had line spacing that was truncated.
+ truncated_space += n;
+ tok.next();
+}
+
+void blank_line()
+{
+ curenv->do_break();
+ if (!trap_sprung_flag)
+ curdiv->space(curenv->get_vertical_spacing());
+ else
+ truncated_space += curenv->get_vertical_spacing();
+}
+
+/* need_space might spring a trap and so we must be careful that the
+BEGIN_TRAP token is not skipped over. */
+
+void need_space()
+{
+ vunits n;
+ if (!has_arg() || !get_vunits(&n, 'v'))
+ n = curenv->get_vertical_spacing();
+ while (!tok.newline() && !tok.eof())
+ tok.next();
+ curdiv->need(n);
+ tok.next();
+}
+
+void page_number()
+{
+ int n;
+ if (has_arg() && get_integer(&n, topdiv->get_page_number()))
+ topdiv->set_next_page_number(n);
+ skip_line();
+}
+
+vunits saved_space;
+
+void save_vertical_space()
+{
+ vunits x;
+ if (get_vunits(&x, 'v')) {
+ if (curdiv->distance_to_next_trap() > x)
+ curdiv->space(x, 1);
+ else
+ saved_space = x;
+ }
+ skip_line();
+}
+
+void output_saved_vertical_space()
+{
+ while (!tok.newline() && !tok.eof())
+ tok.next();
+ if (saved_space > V0)
+ curdiv->space(saved_space, 1);
+ saved_space = V0;
+ tok.next();
+}
+
+void flush_output()
+{
+ while (!tok.newline() && !tok.eof())
+ tok.next();
+ if (break_flag)
+ curenv->do_break();
+ if (the_output)
+ the_output->flush();
+ tok.next();
+}
+
+void macro_diversion::set_diversion_trap(symbol s, vunits n)
+{
+ diversion_trap = s;
+ diversion_trap_pos = n;
+}
+
+void macro_diversion::clear_diversion_trap()
+{
+ diversion_trap = NULL_SYMBOL;
+}
+
+void top_level_diversion::set_diversion_trap(symbol, vunits)
+{
+ error("can't set diversion trap when no current diversion");
+}
+
+void top_level_diversion::clear_diversion_trap()
+{
+ error("can't set diversion trap when no current diversion");
+}
+
+void diversion_trap()
+{
+ vunits n;
+ if (has_arg() && get_vunits(&n, 'v')) {
+ symbol s = get_name();
+ if (!s.is_null())
+ curdiv->set_diversion_trap(s, n);
+ else
+ curdiv->clear_diversion_trap();
+ }
+ else
+ curdiv->clear_diversion_trap();
+ skip_line();
+}
+
+void change_trap()
+{
+ symbol s = get_name(1);
+ if (!s.is_null()) {
+ vunits x;
+ if (has_arg() && get_vunits(&x, 'v'))
+ topdiv->change_trap(s, x);
+ else
+ topdiv->remove_trap(s);
+ }
+ skip_line();
+}
+
+void print_traps()
+{
+ topdiv->print_traps();
+ skip_line();
+}
+
+void mark()
+{
+ symbol s = get_name();
+ if (s.is_null())
+ curdiv->marked_place = curdiv->get_vertical_position();
+ else if (curdiv == topdiv)
+ set_number_reg(s, nl_reg_contents);
+ else
+ set_number_reg(s, curdiv->get_vertical_position().to_units());
+ skip_line();
+}
+
+// This is truly bizarre. It is documented in the SQ manual.
+
+void return_request()
+{
+ vunits dist = curdiv->marked_place - curdiv->get_vertical_position();
+ if (has_arg()) {
+ if (tok.ch() == '-') {
+ tok.next();
+ vunits x;
+ if (get_vunits(&x, 'v'))
+ dist = -x;
+ }
+ else {
+ vunits x;
+ if (get_vunits(&x, 'v'))
+ dist = x >= V0 ? x - curdiv->get_vertical_position() : V0;
+ }
+ }
+ if (dist < V0)
+ curdiv->space(dist);
+ skip_line();
+}
+
+void vertical_position_traps()
+{
+ int n;
+ if (has_arg() && get_integer(&n))
+ vertical_position_traps_flag = (n != 0);
+ else
+ vertical_position_traps_flag = 1;
+ skip_line();
+}
+
+class page_offset_reg : public reg {
+public:
+ int get_value(units *);
+ const char *get_string();
+};
+
+int page_offset_reg::get_value(units *res)
+{
+ *res = topdiv->get_page_offset().to_units();
+ return 1;
+}
+
+const char *page_offset_reg::get_string()
+{
+ return itoa(topdiv->get_page_offset().to_units());
+}
+
+class page_length_reg : public reg {
+public:
+ int get_value(units *);
+ const char *get_string();
+};
+
+int page_length_reg::get_value(units *res)
+{
+ *res = topdiv->get_page_length().to_units();
+ return 1;
+}
+
+const char *page_length_reg::get_string()
+{
+ return itoa(topdiv->get_page_length().to_units());
+}
+
+class vertical_position_reg : public reg {
+public:
+ int get_value(units *);
+ const char *get_string();
+};
+
+int vertical_position_reg::get_value(units *res)
+{
+ if (curdiv == topdiv && topdiv->before_first_page)
+ *res = -1;
+ else
+ *res = curdiv->get_vertical_position().to_units();
+ return 1;
+}
+
+const char *vertical_position_reg::get_string()
+{
+ if (curdiv == topdiv && topdiv->before_first_page)
+ return "-1";
+ else
+ return itoa(curdiv->get_vertical_position().to_units());
+}
+
+class high_water_mark_reg : public reg {
+public:
+ int get_value(units *);
+ const char *get_string();
+};
+
+int high_water_mark_reg::get_value(units *res)
+{
+ *res = curdiv->get_high_water_mark().to_units();
+ return 1;
+}
+
+const char *high_water_mark_reg::get_string()
+{
+ return itoa(curdiv->get_high_water_mark().to_units());
+}
+
+class distance_to_next_trap_reg : public reg {
+public:
+ int get_value(units *);
+ const char *get_string();
+};
+
+int distance_to_next_trap_reg::get_value(units *res)
+{
+ *res = curdiv->distance_to_next_trap().to_units();
+ return 1;
+}
+
+const char *distance_to_next_trap_reg::get_string()
+{
+ return itoa(curdiv->distance_to_next_trap().to_units());
+}
+
+class diversion_name_reg : public reg {
+public:
+ const char *get_string();
+};
+
+const char *diversion_name_reg::get_string()
+{
+ return curdiv->get_diversion_name();
+}
+
+class page_number_reg : public general_reg {
+public:
+ page_number_reg();
+ int get_value(units *);
+ void set_value(units);
+};
+
+page_number_reg::page_number_reg()
+{
+}
+
+void page_number_reg::set_value(units n)
+{
+ topdiv->set_page_number(n);
+}
+
+int page_number_reg::get_value(units *res)
+{
+ *res = topdiv->get_page_number();
+ return 1;
+}
+
+class next_page_number_reg : public reg {
+public:
+ const char *get_string();
+};
+
+const char *next_page_number_reg::get_string()
+{
+ return itoa(topdiv->get_next_page_number());
+}
+
+class page_ejecting_reg : public reg {
+public:
+ const char *get_string();
+};
+
+const char *page_ejecting_reg::get_string()
+{
+ return itoa(topdiv->get_ejecting());
+}
+
+class constant_vunits_reg : public reg {
+ vunits *p;
+public:
+ constant_vunits_reg(vunits *);
+ const char *get_string();
+};
+
+constant_vunits_reg::constant_vunits_reg(vunits *q) : p(q)
+{
+}
+
+const char *constant_vunits_reg::get_string()
+{
+ return itoa(p->to_units());
+}
+
+class nl_reg : public variable_reg {
+public:
+ nl_reg();
+ void set_value(units);
+};
+
+nl_reg::nl_reg() : variable_reg(&nl_reg_contents)
+{
+}
+
+void nl_reg::set_value(units n)
+{
+ variable_reg::set_value(n);
+ // Setting nl to a negative value when the vertical position in
+ // the top-level diversion is 0 undoes the top of page transition,
+ // so that the header macro will be called as if the top of page
+ // transition hasn't happened. This is used by Larry Wall's
+ // wrapman program. Setting before_first_page to 2 rather than 1,
+ // tells top_level_diversion::begin_page not to call
+ // output_file::begin_page again.
+ if (n < 0 && topdiv->get_vertical_position() == V0)
+ topdiv->before_first_page = 2;
+}
+
+void init_div_requests()
+{
+ init_request("wh", when_request);
+ init_request("ch", change_trap);
+ init_request("pl", page_length);
+ init_request("po", page_offset);
+ init_request("rs", restore_spacing);
+ init_request("ns", no_space);
+ init_request("sp", space_request);
+ init_request("di", divert);
+ init_request("da", divert_append);
+ init_request("bp", begin_page);
+ init_request("ne", need_space);
+ init_request("pn", page_number);
+ init_request("dt", diversion_trap);
+ init_request("rt", return_request);
+ init_request("mk", mark);
+ init_request("sv", save_vertical_space);
+ init_request("os", output_saved_vertical_space);
+ init_request("fl", flush_output);
+ init_request("vpt", vertical_position_traps);
+ init_request("ptr", print_traps);
+ number_reg_dictionary.define(".a",
+ new constant_int_reg(&last_post_line_extra_space));
+ number_reg_dictionary.define(".z", new diversion_name_reg);
+ number_reg_dictionary.define(".o", new page_offset_reg);
+ number_reg_dictionary.define(".p", new page_length_reg);
+ number_reg_dictionary.define(".d", new vertical_position_reg);
+ number_reg_dictionary.define(".h", new high_water_mark_reg);
+ number_reg_dictionary.define(".t", new distance_to_next_trap_reg);
+ number_reg_dictionary.define("dl", new variable_reg(&dl_reg_contents));
+ number_reg_dictionary.define("dn", new variable_reg(&dn_reg_contents));
+ number_reg_dictionary.define("nl", new nl_reg);
+ number_reg_dictionary.define(".vpt",
+ new constant_int_reg(&vertical_position_traps_flag));
+ number_reg_dictionary.define("%", new page_number_reg);
+ number_reg_dictionary.define(".pn", new next_page_number_reg);
+ number_reg_dictionary.define(".trunc",
+ new constant_vunits_reg(&truncated_space));
+ number_reg_dictionary.define(".ne",
+ new constant_vunits_reg(&needed_space));
+ number_reg_dictionary.define(".pe", new page_ejecting_reg);
+}
diff --git a/gnu/usr.bin/groff/troff/div.h b/gnu/usr.bin/groff/troff/div.h
new file mode 100644
index 0000000..ca5924f
--- /dev/null
+++ b/gnu/usr.bin/groff/troff/div.h
@@ -0,0 +1,147 @@
+// -*- C++ -*-
+/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
+ Written by James Clark (jjc@jclark.com)
+
+This file is part of groff.
+
+groff is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
+
+groff is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License along
+with groff; see the file COPYING. If not, write to the Free Software
+Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+class diversion {
+ friend void do_divert(int append);
+ friend void end_diversions();
+ diversion *prev;
+protected:
+ symbol nm;
+ vunits vertical_position;
+ vunits high_water_mark;
+public:
+ vunits marked_place;
+ diversion(symbol s = NULL_SYMBOL);
+ virtual ~diversion();
+ virtual void output(node *nd, int retain_size, vunits vs, int ls, hunits width) = 0;
+ virtual void transparent_output(unsigned char) = 0;
+ virtual void transparent_output(node *) = 0;
+ virtual void space(vunits distance, int forced = 0) = 0;
+#ifdef COLUMN
+ virtual void vjustify(symbol) = 0;
+#endif /* COLUMN */
+ vunits get_vertical_position() { return vertical_position; }
+ vunits get_high_water_mark() { return high_water_mark; }
+ virtual vunits distance_to_next_trap() = 0;
+ void need(vunits);
+ const char *get_diversion_name() { return nm.contents(); }
+ virtual void set_diversion_trap(symbol, vunits) = 0;
+ virtual void clear_diversion_trap() = 0;
+ virtual void copy_file(const char *filename) = 0;
+};
+
+class macro;
+
+class macro_diversion : public diversion {
+ macro *mac;
+ hunits max_width;
+ symbol diversion_trap;
+ vunits diversion_trap_pos;
+public:
+ macro_diversion(symbol, int);
+ ~macro_diversion();
+ void output(node *nd, int retain_size, vunits vs, int ls, hunits width);
+ void transparent_output(unsigned char);
+ void transparent_output(node *);
+ void space(vunits distance, int forced = 0);
+#ifdef COLUMN
+ void vjustify(symbol);
+#endif /* COLUMN */
+ vunits distance_to_next_trap();
+ void set_diversion_trap(symbol, vunits);
+ void clear_diversion_trap();
+ void copy_file(const char *filename);
+};
+
+struct trap {
+ trap *next;
+ vunits position;
+ symbol nm;
+ trap(symbol, vunits, trap *);
+};
+
+struct output_file;
+
+class top_level_diversion : public diversion {
+ int page_number;
+ int page_count;
+ int last_page_count;
+ vunits page_length;
+ hunits prev_page_offset;
+ hunits page_offset;
+ trap *page_trap_list;
+ trap *find_next_trap(vunits *);
+ int have_next_page_number;
+ int next_page_number;
+ int ejecting_page; // Is the current page being ejected?
+public:
+ int before_first_page;
+ int no_space_mode;
+ top_level_diversion();
+ void output(node *nd, int retain_size, vunits vs, int ls, hunits width);
+ void transparent_output(unsigned char);
+ void transparent_output(node *);
+ void space(vunits distance, int forced = 0);
+#ifdef COLUMN
+ void vjustify(symbol);
+#endif /* COLUMN */
+ hunits get_page_offset() { return page_offset; }
+ vunits get_page_length() { return page_length; }
+ vunits distance_to_next_trap();
+ void add_trap(symbol nm, vunits pos);
+ void change_trap(symbol nm, vunits pos);
+ void remove_trap(symbol);
+ void remove_trap_at(vunits pos);
+ void print_traps();
+ int get_page_count() { return page_count; }
+ int get_page_number() { return page_number; }
+ int get_next_page_number();
+ void set_page_number(int n) { page_number = n; }
+ int begin_page();
+ void set_next_page_number(int);
+ void set_page_length(vunits);
+ void copy_file(const char *filename);
+ int get_ejecting() { return ejecting_page; }
+ void set_ejecting() { ejecting_page = 1; }
+ friend void page_offset();
+ void set_diversion_trap(symbol, vunits);
+ void clear_diversion_trap();
+ void set_last_page() { last_page_count = page_count; }
+};
+
+extern top_level_diversion *topdiv;
+extern diversion *curdiv;
+
+extern int exit_started;
+extern int done_end_macro;
+extern int last_page_number;
+extern int seen_last_page_ejector;
+
+void spring_trap(symbol); // implemented by input.c
+extern int trap_sprung_flag;
+void postpone_traps();
+int unpostpone_traps();
+
+void push_page_ejector();
+void continue_page_eject();
+void handle_first_page_transition();
+void blank_line();
+
+extern void cleanup_and_exit(int);
diff --git a/gnu/usr.bin/groff/troff/env.cc b/gnu/usr.bin/groff/troff/env.cc
new file mode 100644
index 0000000..0d343ff
--- /dev/null
+++ b/gnu/usr.bin/groff/troff/env.cc
@@ -0,0 +1,3052 @@
+// -*- C++ -*-
+/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
+ Written by James Clark (jjc@jclark.com)
+
+This file is part of groff.
+
+groff is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
+
+groff is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License along
+with groff; see the file COPYING. If not, write to the Free Software
+Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "troff.h"
+#include "symbol.h"
+#include "dictionary.h"
+#include "hvunits.h"
+#include "env.h"
+#include "request.h"
+#include "node.h"
+#include "token.h"
+#include "div.h"
+#include "reg.h"
+#include "charinfo.h"
+#include "searchpath.h"
+#include "macropath.h"
+#include <math.h>
+
+symbol default_family("T");
+
+enum { ADJUST_LEFT = 0, ADJUST_BOTH = 1, ADJUST_CENTER = 3, ADJUST_RIGHT = 5 };
+
+enum { HYPHEN_LAST_LINE = 2, HYPHEN_LAST_CHARS = 4, HYPHEN_FIRST_CHARS = 8 };
+
+struct env_list {
+ environment *env;
+ env_list *next;
+ env_list(environment *e, env_list *p) : env(e), next(p) {}
+};
+
+env_list *env_stack;
+const int NENVIRONMENTS = 10;
+environment *env_table[NENVIRONMENTS];
+dictionary env_dictionary(10);
+environment *curenv;
+static int next_line_number = 0;
+
+charinfo *field_delimiter_char;
+charinfo *padding_indicator_char;
+
+int translate_space_to_dummy = 0;
+
+class pending_output_line {
+ node *nd;
+ int no_fill;
+ vunits vs;
+ int ls;
+ hunits width;
+#ifdef WIDOW_CONTROL
+ int last_line; // Is it the last line of the paragraph?
+#endif /* WIDOW_CONTROL */
+public:
+ pending_output_line *next;
+
+ pending_output_line(node *, int, vunits, int, hunits,
+ pending_output_line * = 0);
+ ~pending_output_line();
+ int output();
+
+#ifdef WIDOW_CONTROL
+ friend void environment::mark_last_line();
+ friend void environment::output(node *, int, vunits, int, hunits);
+#endif /* WIDOW_CONTROL */
+};
+
+pending_output_line::pending_output_line(node *n, int nf, vunits v, int l,
+ hunits w, pending_output_line *p)
+: nd(n), no_fill(nf), vs(v), ls(l), width(w),
+#ifdef WIDOW_CONTROL
+ last_line(0),
+#endif /* WIDOW_CONTROL */
+ next(p)
+{
+}
+
+pending_output_line::~pending_output_line()
+{
+ delete_node_list(nd);
+}
+
+int pending_output_line::output()
+{
+ if (trap_sprung_flag)
+ return 0;
+#ifdef WIDOW_CONTROL
+ if (next && next->last_line && !no_fill) {
+ curdiv->need(vs*ls + vunits(vresolution));
+ if (trap_sprung_flag) {
+ next->last_line = 0; // Try to avoid infinite loops.
+ return 0;
+ }
+ }
+#endif
+ curdiv->output(nd, no_fill, vs, ls, width);
+ nd = 0;
+ return 1;
+}
+
+void environment::output(node *nd, int no_fill, vunits vs, int ls,
+ hunits width)
+{
+#ifdef WIDOW_CONTROL
+ while (pending_lines) {
+ if (widow_control && !pending_lines->no_fill && !pending_lines->next)
+ break;
+ if (!pending_lines->output())
+ break;
+ pending_output_line *tem = pending_lines;
+ pending_lines = pending_lines->next;
+ delete tem;
+ }
+#else /* WIDOW_CONTROL */
+ output_pending_lines();
+#endif /* WIDOW_CONTROL */
+ if (!trap_sprung_flag && !pending_lines
+#ifdef WIDOW_CONTROL
+ && (!widow_control || no_fill)
+#endif /* WIDOW_CONTROL */
+ )
+ curdiv->output(nd, no_fill, vs, ls, width);
+ else {
+ for (pending_output_line **p = &pending_lines; *p; p = &(*p)->next)
+ ;
+ *p = new pending_output_line(nd, no_fill, vs, ls, width);
+ }
+}
+
+// a line from .tl goes at the head of the queue
+
+void environment::output_title(node *nd, int no_fill, vunits vs, int ls,
+ hunits width)
+{
+ if (!trap_sprung_flag)
+ curdiv->output(nd, no_fill, vs, ls, width);
+ else
+ pending_lines = new pending_output_line(nd, no_fill, vs, ls, width,
+ pending_lines);
+}
+
+void environment::output_pending_lines()
+{
+ while (pending_lines && pending_lines->output()) {
+ pending_output_line *tem = pending_lines;
+ pending_lines = pending_lines->next;
+ delete tem;
+ }
+}
+
+#ifdef WIDOW_CONTROL
+
+void environment::mark_last_line()
+{
+ if (!widow_control || !pending_lines)
+ return;
+ for (pending_output_line *p = pending_lines; p->next; p = p->next)
+ ;
+ if (!p->no_fill)
+ p->last_line = 1;
+}
+
+void widow_control_request()
+{
+ int n;
+ if (has_arg() && get_integer(&n))
+ curenv->widow_control = n != 0;
+ else
+ curenv->widow_control = 1;
+ skip_line();
+}
+
+#endif /* WIDOW_CONTROL */
+
+/* font_size functions */
+
+size_range *font_size::size_table = 0;
+int font_size::nranges = 0;
+
+extern "C" {
+
+static int compare_ranges(const void *p1, const void *p2)
+{
+ return ((size_range *)p1)->min - ((size_range *)p2)->min;
+}
+
+}
+
+void font_size::init_size_table(int *sizes)
+{
+ nranges = 0;
+ while (sizes[nranges*2] != 0)
+ nranges++;
+ assert(nranges > 0);
+ size_table = new size_range[nranges];
+ for (int i = 0; i < nranges; i++) {
+ size_table[i].min = sizes[i*2];
+ size_table[i].max = sizes[i*2 + 1];
+ }
+ qsort(size_table, nranges, sizeof(size_range), compare_ranges);
+}
+
+font_size::font_size(int sp)
+{
+ for (int i = 0; i < nranges; i++) {
+ if (sp < size_table[i].min) {
+ if (i > 0 && size_table[i].min - sp >= sp - size_table[i - 1].max)
+ p = size_table[i - 1].max;
+ else
+ p = size_table[i].min;
+ return;
+ }
+ if (sp <= size_table[i].max) {
+ p = sp;
+ return;
+ }
+ }
+ p = size_table[nranges - 1].max;
+}
+
+int font_size::to_units()
+{
+ return scale(p, units_per_inch, sizescale*72);
+}
+
+// we can't do this in a static constructor because various dictionaries
+// have to get initialized first
+
+void init_environments()
+{
+ curenv = env_table[0] = new environment("0");
+}
+
+void tab_character()
+{
+ curenv->tab_char = get_optional_char();
+ skip_line();
+}
+
+void leader_character()
+{
+ curenv->leader_char = get_optional_char();
+ skip_line();
+}
+
+void environment::add_char(charinfo *ci)
+{
+ if (interrupted)
+ ;
+ // don't allow fields in dummy environments
+ else if (ci == field_delimiter_char && !dummy) {
+ if (current_field)
+ wrap_up_field();
+ else
+ start_field();
+ }
+ else if (current_field && ci == padding_indicator_char)
+ add_padding();
+ else if (current_tab) {
+ if (tab_contents == 0)
+ tab_contents = new line_start_node;
+ if (ci != hyphen_indicator_char)
+ tab_contents = tab_contents->add_char(ci, this, &tab_width);
+ else
+ tab_contents = tab_contents->add_discretionary_hyphen();
+ }
+ else {
+ if (line == 0)
+ start_line();
+ if (ci != hyphen_indicator_char)
+ line = line->add_char(ci, this, &width_total);
+ else
+ line = line->add_discretionary_hyphen();
+ }
+}
+
+node *environment::make_char_node(charinfo *ci)
+{
+ return make_node(ci, this);
+}
+
+void environment::add_node(node *n)
+{
+ assert(n != 0);
+ if (current_tab || current_field)
+ n->freeze_space();
+ if (interrupted) {
+ delete n;
+ }
+ else if (current_tab) {
+ n->next = tab_contents;
+ tab_contents = n;
+ tab_width += n->width();
+ }
+ else {
+ if (line == 0) {
+ if (discarding && n->discardable()) {
+ // XXX possibly: input_line_start -= n->width();
+ delete n;
+ return;
+ }
+ start_line();
+ }
+ width_total += n->width();
+ space_total += n->nspaces();
+ n->next = line;
+ line = n;
+ }
+}
+
+
+void environment::add_hyphen_indicator()
+{
+ if (current_tab || interrupted || current_field
+ || hyphen_indicator_char != 0)
+ return;
+ if (line == 0)
+ start_line();
+ line = line->add_discretionary_hyphen();
+}
+
+int environment::get_hyphenation_flags()
+{
+ return hyphenation_flags;
+}
+
+int environment::get_hyphen_line_max()
+{
+ return hyphen_line_max;
+}
+
+int environment::get_hyphen_line_count()
+{
+ return hyphen_line_count;
+}
+
+int environment::get_center_lines()
+{
+ return center_lines;
+}
+
+int environment::get_right_justify_lines()
+{
+ return right_justify_lines;
+}
+
+void environment::add_italic_correction()
+{
+ if (current_tab) {
+ if (tab_contents)
+ tab_contents = tab_contents->add_italic_correction(&tab_width);
+ }
+ else if (line)
+ line = line->add_italic_correction(&width_total);
+}
+
+void environment::space_newline()
+{
+ assert(!current_tab && !current_field);
+ if (interrupted)
+ return;
+ hunits x = H0;
+ if (!translate_space_to_dummy) {
+ x = env_space_width(this);
+ if (node_list_ends_sentence(line) == 1)
+ x += env_sentence_space_width(this);
+ }
+ if (line != 0 && line->merge_space(x)) {
+ width_total += x;
+ return;
+ }
+ add_node(new word_space_node(x));
+ possibly_break_line(spread_flag);
+ spread_flag = 0;
+}
+
+void environment::space()
+{
+ if (interrupted)
+ return;
+ if (current_field && padding_indicator_char == 0) {
+ add_padding();
+ return;
+ }
+ hunits x = translate_space_to_dummy ? H0 : env_space_width(this);
+ node *p = current_tab ? tab_contents : line;
+ hunits *tp = current_tab ? &tab_width : &width_total;
+ if (p && p->nspaces() == 1 && p->width() == x
+ && node_list_ends_sentence(p->next) == 1) {
+ hunits xx = translate_space_to_dummy ? H0 : env_sentence_space_width(this);
+ if (p->merge_space(xx)) {
+ *tp += xx;
+ return;
+ }
+ }
+ if (p && p->merge_space(x)) {
+ *tp += x;
+ return;
+ }
+ add_node(new word_space_node(x));
+ possibly_break_line(spread_flag);
+ spread_flag = 0;
+}
+
+void environment::set_font(symbol nm)
+{
+ if (interrupted)
+ return;
+ if (nm == symbol("P")) {
+ if (family->make_definite(prev_fontno) < 0)
+ return;
+ int tem = fontno;
+ fontno = prev_fontno;
+ prev_fontno = tem;
+ }
+ else {
+ int n = symbol_fontno(nm);
+ if (n < 0) {
+ n = next_available_font_position();
+ if (!mount_font(n, nm))
+ return;
+ }
+ if (family->make_definite(n) < 0)
+ return;
+ prev_fontno = fontno;
+ fontno = n;
+ }
+}
+
+void environment::set_font(int n)
+{
+ if (interrupted)
+ return;
+ if (is_good_fontno(n)) {
+ prev_fontno = fontno;
+ fontno = n;
+ }
+ else
+ error("bad font number");
+}
+
+void environment::set_family(symbol fam)
+{
+ if (fam.is_null()) {
+ if (prev_family->make_definite(fontno) < 0)
+ return;
+ font_family *tem = family;
+ family = prev_family;
+ prev_family = tem;
+ }
+ else {
+ font_family *f = lookup_family(fam);
+ if (f->make_definite(fontno) < 0)
+ return;
+ prev_family = family;
+ family = f;
+ }
+}
+
+void environment::set_size(int n)
+{
+ if (interrupted)
+ return;
+ if (n == 0) {
+ font_size temp = prev_size;
+ prev_size = size;
+ size = temp;
+ int temp2 = prev_requested_size;
+ prev_requested_size = requested_size;
+ requested_size = temp2;
+ }
+ else {
+ prev_size = size;
+ size = font_size(n);
+ prev_requested_size = requested_size;
+ requested_size = n;
+ }
+}
+
+void environment::set_char_height(int n)
+{
+ if (interrupted)
+ return;
+ if (n == requested_size || n <= 0)
+ char_height = 0;
+ else
+ char_height = n;
+}
+
+void environment::set_char_slant(int n)
+{
+ if (interrupted)
+ return;
+ char_slant = n;
+}
+
+environment::environment(symbol nm)
+: name(nm),
+ prev_line_length((units_per_inch*13)/2),
+ line_length((units_per_inch*13)/2),
+ prev_title_length((units_per_inch*13)/2),
+ title_length((units_per_inch*13)/2),
+ prev_size(sizescale*10),
+ size(sizescale*10),
+ requested_size(sizescale*10),
+ prev_requested_size(sizescale*10),
+ char_height(0),
+ char_slant(0),
+ space_size(12),
+ sentence_space_size(12),
+ adjust_mode(ADJUST_BOTH),
+ fill(1),
+ interrupted(0),
+ prev_line_interrupted(0),
+ center_lines(0),
+ right_justify_lines(0),
+ prev_vertical_spacing(points_to_units(12)),
+ vertical_spacing(points_to_units(12)),
+ prev_line_spacing(1),
+ line_spacing(1),
+ prev_indent(0),
+ indent(0),
+ have_temporary_indent(0),
+ temporary_indent(0),
+ underline_lines(0),
+ input_trap_count(0),
+ prev_text_length(0),
+ width_total(0),
+ space_total(0),
+ input_line_start(0),
+ control_char('.'),
+ no_break_control_char('\''),
+ hyphen_indicator_char(0),
+ spread_flag(0),
+ line(0),
+ pending_lines(0),
+ discarding(0),
+ tabs(units_per_inch/2, TAB_LEFT),
+ current_tab(TAB_NONE),
+ current_field(0),
+ margin_character_flags(0),
+ margin_character_node(0),
+ margin_character_distance(points_to_units(10)),
+ numbering_nodes(0),
+ number_text_separation(1),
+ line_number_multiple(1),
+ line_number_indent(0),
+ no_number_count(0),
+ tab_char(0),
+ leader_char(charset_table['.']),
+ hyphenation_flags(1),
+ dummy(0),
+ leader_node(0),
+#ifdef WIDOW_CONTROL
+ widow_control(0),
+#endif /* WIDOW_CONTROL */
+ hyphen_line_count(0),
+ hyphen_line_max(-1),
+ hyphenation_space(H0),
+ hyphenation_margin(H0),
+ composite(0)
+{
+ prev_family = family = lookup_family(default_family);
+ prev_fontno = fontno = 1;
+ if (!is_good_fontno(1))
+ fatal("font number 1 not a valid font");
+ if (family->make_definite(1) < 0)
+ fatal("invalid default family `%1'", default_family.contents());
+ prev_fontno = fontno;
+}
+
+environment::environment(const environment *e)
+: name(e->name), // so that eg `.if "\n[.ev]"0"' works
+ prev_line_length(e->prev_line_length),
+ line_length(e->line_length),
+ prev_title_length(e->prev_title_length),
+ title_length(e->title_length),
+ prev_size(e->prev_size),
+ size(e->size),
+ prev_requested_size(e->prev_requested_size),
+ requested_size(e->requested_size),
+ char_height(e->char_height),
+ char_slant(e->char_slant),
+ space_size(e->space_size),
+ sentence_space_size(e->sentence_space_size),
+ adjust_mode(e->adjust_mode),
+ fill(e->fill),
+ interrupted(0),
+ prev_line_interrupted(0),
+ center_lines(0),
+ right_justify_lines(0),
+ prev_vertical_spacing(e->prev_vertical_spacing),
+ vertical_spacing(e->vertical_spacing),
+ prev_line_spacing(e->prev_line_spacing),
+ line_spacing(e->line_spacing),
+ prev_indent(e->prev_indent),
+ indent(e->indent),
+ have_temporary_indent(0),
+ temporary_indent(0),
+ underline_lines(0),
+ input_trap_count(0),
+ prev_text_length(e->prev_text_length),
+ width_total(0),
+ space_total(0),
+ input_line_start(0),
+ control_char(e->control_char),
+ no_break_control_char(e->no_break_control_char),
+ hyphen_indicator_char(e->hyphen_indicator_char),
+ spread_flag(0),
+ line(0),
+ pending_lines(0),
+ discarding(0),
+ tabs(e->tabs),
+ current_tab(TAB_NONE),
+ current_field(0),
+ margin_character_flags(e->margin_character_flags),
+ margin_character_node(e->margin_character_node),
+ margin_character_distance(e->margin_character_distance),
+ numbering_nodes(0),
+ number_text_separation(e->number_text_separation),
+ line_number_multiple(e->line_number_multiple),
+ line_number_indent(e->line_number_indent),
+ no_number_count(e->no_number_count),
+ tab_char(e->tab_char),
+ leader_char(e->leader_char),
+ hyphenation_flags(e->hyphenation_flags),
+ fontno(e->fontno),
+ prev_fontno(e->prev_fontno),
+ dummy(1),
+ family(e->family),
+ prev_family(e->prev_family),
+ leader_node(0),
+#ifdef WIDOW_CONTROL
+ widow_control(e->widow_control),
+#endif /* WIDOW_CONTROL */
+ hyphen_line_max(e->hyphen_line_max),
+ hyphen_line_count(0),
+ hyphenation_space(e->hyphenation_space),
+ hyphenation_margin(e->hyphenation_margin),
+ composite(0)
+{
+}
+
+environment::~environment()
+{
+ delete leader_node;
+ delete_node_list(line);
+ delete_node_list(numbering_nodes);
+}
+
+hunits environment::get_input_line_position()
+{
+ hunits n;
+ if (line == 0)
+ n = -input_line_start;
+ else
+ n = width_total - input_line_start;
+ if (current_tab)
+ n += tab_width;
+ return n;
+}
+
+void environment::set_input_line_position(hunits n)
+{
+ input_line_start = line == 0 ? -n : width_total - n;
+ if (current_tab)
+ input_line_start += tab_width;
+}
+
+hunits environment::get_line_length()
+{
+ return line_length;
+}
+
+hunits environment::get_saved_line_length()
+{
+ if (line)
+ return target_text_length + saved_indent;
+ else
+ return line_length;
+}
+
+vunits environment::get_vertical_spacing()
+{
+ return vertical_spacing;
+}
+
+int environment::get_line_spacing()
+{
+ return line_spacing;
+}
+
+int environment::get_bold()
+{
+ return get_bold_fontno(fontno);
+}
+
+hunits environment::get_digit_width()
+{
+ return env_digit_width(this);
+}
+
+int environment::get_adjust_mode()
+{
+ return adjust_mode;
+}
+
+int environment::get_fill()
+{
+ return fill;
+}
+
+hunits environment::get_indent()
+{
+ return indent;
+}
+
+hunits environment::get_saved_indent()
+{
+ if (line)
+ return saved_indent;
+ else if (have_temporary_indent)
+ return temporary_indent;
+ else
+ return indent;
+}
+
+hunits environment::get_temporary_indent()
+{
+ return temporary_indent;
+}
+
+hunits environment::get_title_length()
+{
+ return title_length;
+}
+
+node *environment::get_prev_char()
+{
+ for (node *n = current_tab ? tab_contents : line; n; n = n->next) {
+ node *last = n->last_char_node();
+ if (last)
+ return last;
+ }
+ return 0;
+}
+
+hunits environment::get_prev_char_width()
+{
+ node *last = get_prev_char();
+ if (!last)
+ return H0;
+ return last->width();
+}
+
+hunits environment::get_prev_char_skew()
+{
+ node *last = get_prev_char();
+ if (!last)
+ return H0;
+ return last->skew();
+}
+
+vunits environment::get_prev_char_height()
+{
+ node *last = get_prev_char();
+ if (!last)
+ return V0;
+ vunits min, max;
+ last->vertical_extent(&min, &max);
+ return -min;
+}
+
+vunits environment::get_prev_char_depth()
+{
+ node *last = get_prev_char();
+ if (!last)
+ return V0;
+ vunits min, max;
+ last->vertical_extent(&min, &max);
+ return max;
+}
+
+hunits environment::get_text_length()
+{
+ hunits n = line == 0 ? H0 : width_total;
+ if (current_tab)
+ n += tab_width;
+ return n;
+}
+
+hunits environment::get_prev_text_length()
+{
+ return prev_text_length;
+}
+
+
+static int sb_reg_contents = 0;
+static int st_reg_contents = 0;
+static int ct_reg_contents = 0;
+static int rsb_reg_contents = 0;
+static int rst_reg_contents = 0;
+static int skw_reg_contents = 0;
+static int ssc_reg_contents = 0;
+
+void environment::width_registers()
+{
+ // this is used to implement \w; it sets the st, sb, ct registers
+ vunits min = 0, max = 0, cur = 0;
+ int character_type = 0;
+ ssc_reg_contents = line ? line->subscript_correction().to_units() : 0;
+ skw_reg_contents = line ? line->skew().to_units() : 0;
+ line = reverse_node_list(line);
+ vunits real_min = V0;
+ vunits real_max = V0;
+ vunits v1, v2;
+ for (node *tem = line; tem; tem = tem->next) {
+ tem->vertical_extent(&v1, &v2);
+ v1 += cur;
+ if (v1 < real_min)
+ real_min = v1;
+ v2 += cur;
+ if (v2 > real_max)
+ real_max = v2;
+ if ((cur += tem->vertical_width()) < min)
+ min = cur;
+ else if (cur > max)
+ max = cur;
+ character_type |= tem->character_type();
+ }
+ line = reverse_node_list(line);
+ st_reg_contents = -min.to_units();
+ sb_reg_contents = -max.to_units();
+ rst_reg_contents = -real_min.to_units();
+ rsb_reg_contents = -real_max.to_units();
+ ct_reg_contents = character_type;
+}
+
+node *environment::extract_output_line()
+{
+ if (current_tab)
+ wrap_up_tab();
+ node *n = line;
+ line = 0;
+ return n;
+}
+
+/* environment related requests */
+
+void environment_switch()
+{
+ int pop = 0; // 1 means pop, 2 means pop but no error message on underflow
+ if (curenv->is_dummy())
+ error("can't switch environments when current environment is dummy");
+ else if (!has_arg())
+ pop = 1;
+ else {
+ symbol nm;
+ if (!tok.delimiter()) {
+ // It looks like a number.
+ int n;
+ if (get_integer(&n)) {
+ if (n >= 0 && n < NENVIRONMENTS) {
+ env_stack = new env_list(curenv, env_stack);
+ if (env_table[n] == 0)
+ env_table[n] = new environment(itoa(n));
+ curenv = env_table[n];
+ }
+ else
+ nm = itoa(n);
+ }
+ else
+ pop = 2;
+ }
+ else {
+ nm = get_long_name(1);
+ if (nm.is_null())
+ pop = 2;
+ }
+ if (!nm.is_null()) {
+ environment *e = (environment *)env_dictionary.lookup(nm);
+ if (!e) {
+ e = new environment(nm);
+ (void)env_dictionary.lookup(nm, e);
+ }
+ env_stack = new env_list(curenv, env_stack);
+ curenv = e;
+ }
+ }
+ if (pop) {
+ if (env_stack == 0) {
+ if (pop == 1)
+ error("environment stack underflow");
+ }
+ else {
+ curenv = env_stack->env;
+ env_list *tem = env_stack;
+ env_stack = env_stack->next;
+ delete tem;
+ }
+ }
+ skip_line();
+}
+
+
+static symbol P_symbol("P");
+
+void font_change()
+{
+ symbol s = get_name();
+ int is_number = 1;
+ if (s.is_null() || s == P_symbol) {
+ s = P_symbol;
+ is_number = 0;
+ }
+ else {
+ for (const char *p = s.contents(); p != 0 && *p != 0; p++)
+ if (!csdigit(*p)) {
+ is_number = 0;
+ break;
+ }
+ }
+ if (is_number)
+ curenv->set_font(atoi(s.contents()));
+ else
+ curenv->set_font(s);
+ skip_line();
+}
+
+void family_change()
+{
+ symbol s = get_name(1);
+ if (!s.is_null())
+ curenv->set_family(s);
+ skip_line();
+}
+
+void point_size()
+{
+ int n;
+ if (has_arg() && get_number(&n, 'z', curenv->get_requested_point_size())) {
+ if (n <= 0)
+ n = 1;
+ curenv->set_size(n);
+ }
+ else
+ curenv->set_size(0);
+ skip_line();
+}
+
+void space_size()
+{
+ int n;
+ if (get_integer(&n)) {
+ curenv->space_size = n;
+ if (has_arg() && get_integer(&n))
+ curenv->sentence_space_size = n;
+ else
+ curenv->sentence_space_size = curenv->space_size;
+ }
+ skip_line();
+}
+
+void fill()
+{
+ while (!tok.newline() && !tok.eof())
+ tok.next();
+ if (break_flag)
+ curenv->do_break();
+ curenv->fill = 1;
+ tok.next();
+}
+
+void no_fill()
+{
+ while (!tok.newline() && !tok.eof())
+ tok.next();
+ if (break_flag)
+ curenv->do_break();
+ curenv->fill = 0;
+ tok.next();
+}
+
+void center()
+{
+ int n;
+ if (!has_arg() || !get_integer(&n))
+ n = 1;
+ else if (n < 0)
+ n = 0;
+ while (!tok.newline() && !tok.eof())
+ tok.next();
+ if (break_flag)
+ curenv->do_break();
+ curenv->right_justify_lines = 0;
+ curenv->center_lines = n;
+ tok.next();
+}
+
+void right_justify()
+{
+ int n;
+ if (!has_arg() || !get_integer(&n))
+ n = 1;
+ else if (n < 0)
+ n = 0;
+ while (!tok.newline() && !tok.eof())
+ tok.next();
+ if (break_flag)
+ curenv->do_break();
+ curenv->center_lines = 0;
+ curenv->right_justify_lines = n;
+ tok.next();
+}
+
+void line_length()
+{
+ hunits temp;
+ if (has_arg() && get_hunits(&temp, 'm', curenv->line_length)) {
+ if (temp < H0) {
+ warning(WARN_RANGE, "bad line length %1u", temp.to_units());
+ temp = H0;
+ }
+ }
+ else
+ temp = curenv->prev_line_length;
+ curenv->prev_line_length = curenv->line_length;
+ curenv->line_length = temp;
+ skip_line();
+}
+
+void title_length()
+{
+ hunits temp;
+ if (has_arg() && get_hunits(&temp, 'm', curenv->title_length)) {
+ if (temp < H0) {
+ warning(WARN_RANGE, "bad title length %1u", temp.to_units());
+ temp = H0;
+ }
+ }
+ else
+ temp = curenv->prev_title_length;
+ curenv->prev_title_length = curenv->title_length;
+ curenv->title_length = temp;
+ skip_line();
+}
+
+void vertical_spacing()
+{
+ vunits temp;
+ if (has_arg() && get_vunits(&temp, 'p', curenv->vertical_spacing)) {
+ if (temp <= V0) {
+ warning(WARN_RANGE, "vertical spacing must be greater than 0");
+ temp = vresolution;
+ }
+ }
+ else
+ temp = curenv->prev_vertical_spacing;
+ curenv->prev_vertical_spacing = curenv->vertical_spacing;
+ curenv->vertical_spacing = temp;
+ skip_line();
+}
+
+void line_spacing()
+{
+ int temp;
+ if (has_arg() && get_integer(&temp)) {
+ if (temp < 1) {
+ warning(WARN_RANGE, "value %1 out of range: interpreted as 1", temp);
+ temp = 1;
+ }
+ }
+ else
+ temp = curenv->prev_line_spacing;
+ curenv->prev_line_spacing = curenv->line_spacing;
+ curenv->line_spacing = temp;
+ skip_line();
+}
+
+void indent()
+{
+ hunits temp;
+ if (has_arg() && get_hunits(&temp, 'm', curenv->indent)) {
+ if (temp < H0) {
+ warning(WARN_RANGE, "indent cannot be negative");
+ temp = H0;
+ }
+ }
+ else
+ temp = curenv->prev_indent;
+ while (!tok.newline() && !tok.eof())
+ tok.next();
+ if (break_flag)
+ curenv->do_break();
+ curenv->have_temporary_indent = 0;
+ curenv->prev_indent = curenv->indent;
+ curenv->indent = temp;
+ tok.next();
+}
+
+void temporary_indent()
+{
+ int err = 0;
+ hunits temp;
+ if (!get_hunits(&temp, 'm', curenv->get_indent()))
+ err = 1;
+ while (!tok.newline() && !tok.eof())
+ tok.next();
+ if (break_flag)
+ curenv->do_break();
+ if (temp < H0) {
+ warning(WARN_RANGE, "total indent cannot be negative");
+ temp = H0;
+ }
+ if (!err) {
+ curenv->temporary_indent = temp;
+ curenv->have_temporary_indent = 1;
+ }
+ tok.next();
+}
+
+void underline()
+{
+ int n;
+ if (!has_arg() || !get_integer(&n))
+ n = 1;
+ if (n <= 0) {
+ if (curenv->underline_lines > 0) {
+ curenv->prev_fontno = curenv->fontno;
+ curenv->fontno = curenv->pre_underline_fontno;
+ }
+ curenv->underline_lines = 0;
+ }
+ else {
+ curenv->underline_lines = n;
+ curenv->pre_underline_fontno = curenv->fontno;
+ curenv->fontno = get_underline_fontno();
+ }
+ skip_line();
+}
+
+void control_char()
+{
+ curenv->control_char = '.';
+ if (has_arg()) {
+ if (tok.ch() == 0)
+ error("bad control character");
+ else
+ curenv->control_char = tok.ch();
+ }
+ skip_line();
+}
+
+void no_break_control_char()
+{
+ curenv->no_break_control_char = '\'';
+ if (has_arg()) {
+ if (tok.ch() == 0)
+ error("bad control character");
+ else
+ curenv->no_break_control_char = tok.ch();
+ }
+ skip_line();
+}
+
+void margin_character()
+{
+ charinfo *ci = get_optional_char();
+ if (ci) {
+ node *nd = curenv->make_char_node(ci);
+ if (nd) {
+ delete curenv->margin_character_node;
+ curenv->margin_character_node = nd;
+ curenv->margin_character_flags = (MARGIN_CHARACTER_ON
+ |MARGIN_CHARACTER_NEXT);
+ hunits d;
+ if (has_arg() && get_hunits(&d, 'm'))
+ curenv->margin_character_distance = d;
+ }
+ }
+ else {
+ curenv->margin_character_flags &= ~MARGIN_CHARACTER_ON;
+ if (curenv->margin_character_flags == 0) {
+ delete curenv->margin_character_node;
+ curenv->margin_character_node = 0;
+ }
+ }
+ skip_line();
+}
+
+void number_lines()
+{
+ delete_node_list(curenv->numbering_nodes);
+ curenv->numbering_nodes = 0;
+ if (has_arg()) {
+ node *nd = 0;
+ for (int i = '9'; i >= '0'; i--) {
+ node *tem = make_node(charset_table[i], curenv);
+ if (!tem) {
+ skip_line();
+ return;
+ }
+ tem->next = nd;
+ nd = tem;
+ }
+ curenv->numbering_nodes = nd;
+ curenv->line_number_digit_width = env_digit_width(curenv);
+ int n;
+ if (!tok.delimiter()) {
+ if (get_integer(&n, next_line_number)) {
+ next_line_number = n;
+ if (next_line_number < 0) {
+ warning(WARN_RANGE, "negative line number");
+ next_line_number = 0;
+ }
+ }
+ }
+ else
+ while (!tok.space() && !tok.newline() && !tok.eof())
+ tok.next();
+ if (has_arg()) {
+ if (!tok.delimiter()) {
+ if (get_integer(&n)) {
+ if (n <= 0) {
+ warning(WARN_RANGE, "negative or zero line number multiple");
+ }
+ else
+ curenv->line_number_multiple = n;
+ }
+ }
+ else
+ while (!tok.space() && !tok.newline() && !tok.eof())
+ tok.next();
+ if (has_arg()) {
+ if (!tok.delimiter()) {
+ if (get_integer(&n))
+ curenv->number_text_separation = n;
+ }
+ else
+ while (!tok.space() && !tok.newline() && !tok.eof())
+ tok.next();
+ if (has_arg() && !tok.delimiter() && get_integer(&n))
+ curenv->line_number_indent = n;
+ }
+ }
+ }
+ skip_line();
+}
+
+void no_number()
+{
+ int n;
+ if (has_arg() && get_integer(&n))
+ curenv->no_number_count = n > 0 ? n : 0;
+ else
+ curenv->no_number_count = 1;
+ skip_line();
+}
+
+void no_hyphenate()
+{
+ curenv->hyphenation_flags = 0;
+ skip_line();
+}
+
+void hyphenate_request()
+{
+ int n;
+ if (has_arg() && get_integer(&n))
+ curenv->hyphenation_flags = n;
+ else
+ curenv->hyphenation_flags = 1;
+ skip_line();
+}
+
+void hyphen_char()
+{
+ curenv->hyphen_indicator_char = get_optional_char();
+ skip_line();
+}
+
+void hyphen_line_max_request()
+{
+ int n;
+ if (has_arg() && get_integer(&n))
+ curenv->hyphen_line_max = n;
+ else
+ curenv->hyphen_line_max = -1;
+ skip_line();
+}
+
+void environment::interrupt()
+{
+ if (!dummy) {
+ add_node(new transparent_dummy_node);
+ interrupted = 1;
+ }
+}
+
+void environment::newline()
+{
+ if (underline_lines > 0) {
+ if (--underline_lines == 0) {
+ prev_fontno = fontno;
+ fontno = pre_underline_fontno;
+ }
+ }
+ if (current_field)
+ wrap_up_field();
+ if (current_tab)
+ wrap_up_tab();
+ // strip trailing spaces
+ while (line != 0 && line->discardable()) {
+ width_total -= line->width();
+ space_total -= line->nspaces();
+ node *tem = line;
+ line = line->next;
+ delete tem;
+ }
+ node *to_be_output = 0;
+ hunits to_be_output_width;
+ prev_line_interrupted = 0;
+ if (dummy)
+ space_newline();
+ else if (interrupted) {
+ interrupted = 0;
+ // see environment::final_break
+ prev_line_interrupted = exit_started ? 2 : 1;
+ }
+ else if (center_lines > 0) {
+ --center_lines;
+ hunits x = target_text_length - width_total;
+ if (x > H0)
+ saved_indent += x/2;
+ to_be_output = line;
+ to_be_output_width = width_total;
+ line = 0;
+ }
+ else if (right_justify_lines > 0) {
+ --right_justify_lines;
+ hunits x = target_text_length - width_total;
+ if (x > H0)
+ saved_indent += x;
+ to_be_output = line;
+ to_be_output_width = width_total;
+ line = 0;
+ }
+ else if (fill)
+ space_newline();
+ else {
+ to_be_output = line;
+ to_be_output_width = width_total;
+ line = 0;
+ }
+ input_line_start = line == 0 ? H0 : width_total;
+ if (to_be_output) {
+ output_line(to_be_output, to_be_output_width);
+ hyphen_line_count = 0;
+ }
+ if (input_trap_count > 0) {
+ if (--input_trap_count == 0)
+ spring_trap(input_trap);
+ }
+}
+
+void environment::output_line(node *n, hunits width)
+{
+ prev_text_length = width;
+ if (margin_character_flags) {
+ hunits d = line_length + margin_character_distance - saved_indent - width;
+ if (d > 0) {
+ n = new hmotion_node(d, n);
+ width += d;
+ }
+ margin_character_flags &= ~MARGIN_CHARACTER_NEXT;
+ node *tem;
+ if (!margin_character_flags) {
+ tem = margin_character_node;
+ margin_character_node = 0;
+ }
+ else
+ tem = margin_character_node->copy();
+ tem->next = n;
+ n = tem;
+ width += tem->width();
+ }
+ node *nn = 0;
+ while (n != 0) {
+ node *tem = n->next;
+ n->next = nn;
+ nn = n;
+ n = tem;
+ }
+ if (!saved_indent.is_zero())
+ nn = new hmotion_node(saved_indent, nn);
+ width += saved_indent;
+ if (no_number_count > 0)
+ --no_number_count;
+ else if (numbering_nodes) {
+ hunits w = (line_number_digit_width
+ *(3+line_number_indent+number_text_separation));
+ if (next_line_number % line_number_multiple != 0)
+ nn = new hmotion_node(w, nn);
+ else {
+ hunits x = w;
+ nn = new hmotion_node(number_text_separation*line_number_digit_width,
+ nn);
+ x -= number_text_separation*line_number_digit_width;
+ char buf[30];
+ sprintf(buf, "%3d", next_line_number);
+ for (char *p = strchr(buf, '\0') - 1; p >= buf && *p != ' '; --p) {
+ node *gn = numbering_nodes;
+ for (int count = *p - '0'; count > 0; count--)
+ gn = gn->next;
+ gn = gn->copy();
+ x -= gn->width();
+ gn->next = nn;
+ nn = gn;
+ }
+ nn = new hmotion_node(x, nn);
+ }
+ width += w;
+ ++next_line_number;
+ }
+ output(nn, !fill, vertical_spacing, line_spacing, width);
+}
+
+void environment::start_line()
+{
+ assert(line == 0);
+ discarding = 0;
+ line = new line_start_node;
+ if (have_temporary_indent) {
+ saved_indent = temporary_indent;
+ have_temporary_indent = 0;
+ }
+ else
+ saved_indent = indent;
+ target_text_length = line_length - saved_indent;
+ width_total = H0;
+ space_total = 0;
+}
+
+hunits environment::get_hyphenation_space()
+{
+ return hyphenation_space;
+}
+
+void hyphenation_space_request()
+{
+ hunits n;
+ if (get_hunits(&n, 'm')) {
+ if (n < H0) {
+ warning(WARN_RANGE, "hyphenation space cannot be negative");
+ n = H0;
+ }
+ curenv->hyphenation_space = n;
+ }
+ skip_line();
+}
+
+hunits environment::get_hyphenation_margin()
+{
+ return hyphenation_margin;
+}
+
+void hyphenation_margin_request()
+{
+ hunits n;
+ if (get_hunits(&n, 'm')) {
+ if (n < H0) {
+ warning(WARN_RANGE, "hyphenation margin cannot be negative");
+ n = H0;
+ }
+ curenv->hyphenation_margin = n;
+ }
+ skip_line();
+}
+
+breakpoint *environment::choose_breakpoint()
+{
+ hunits x = width_total;
+ int s = space_total;
+ node *n = line;
+ breakpoint *best_bp = 0; // the best breakpoint so far
+ int best_bp_fits = 0;
+ while (n != 0) {
+ x -= n->width();
+ s -= n->nspaces();
+ breakpoint *bp = n->get_breakpoints(x, s);
+ while (bp != 0) {
+ if (bp->width <= target_text_length) {
+ if (!bp->hyphenated) {
+ breakpoint *tem = bp->next;
+ bp->next = 0;
+ while (tem != 0) {
+ breakpoint *tem1 = tem;
+ tem = tem->next;
+ delete tem1;
+ }
+ if (best_bp_fits
+ // Decide whether to use the hyphenated breakpoint.
+ && (hyphen_line_max < 0
+ // Only choose the hyphenated breakpoint if it would not
+ // exceed the maximum number of consecutive hyphenated
+ // lines.
+ || hyphen_line_count + 1 <= hyphen_line_max)
+ && !(adjust_mode == ADJUST_BOTH
+ // Don't choose the hyphenated breakpoint if the line
+ // can be justified by adding no more than
+ // hyphenation_space to any word space.
+ ? (bp->nspaces > 0
+ && (((target_text_length - bp->width
+ + (bp->nspaces - 1)*hresolution)/bp->nspaces)
+ <= hyphenation_space))
+ // Don't choose the hyphenated breakpoint if the line
+ // is no more than hyphenation_margin short.
+ : target_text_length - bp->width <= hyphenation_margin)) {
+ delete bp;
+ return best_bp;
+ }
+ if (best_bp)
+ delete best_bp;
+ return bp;
+ }
+ else {
+ if ((adjust_mode == ADJUST_BOTH
+ ? hyphenation_space == H0
+ : hyphenation_margin == H0)
+ && (hyphen_line_max < 0
+ || hyphen_line_count + 1 <= hyphen_line_max)) {
+ // No need to consider a non-hyphenated breakpoint.
+ if (best_bp)
+ delete best_bp;
+ return bp;
+ }
+ // It fits but it's hyphenated.
+ if (!best_bp_fits) {
+ if (best_bp)
+ delete best_bp;
+ best_bp = bp;
+ bp = bp->next;
+ best_bp_fits = 1;
+ }
+ else {
+ breakpoint *tem = bp;
+ bp = bp->next;
+ delete tem;
+ }
+ }
+ }
+ else {
+ if (best_bp)
+ delete best_bp;
+ best_bp = bp;
+ bp = bp->next;
+ }
+ }
+ n = n->next;
+ }
+ if (best_bp) {
+ if (!best_bp_fits)
+ warning(WARN_BREAK, "can't break line");
+ return best_bp;
+ }
+ return 0;
+}
+
+void environment::hyphenate_line()
+{
+ if (line == 0)
+ return;
+ hyphenation_type prev_type = line->get_hyphenation_type();
+ for (node **startp = &line->next; *startp != 0; startp = &(*startp)->next) {
+ hyphenation_type this_type = (*startp)->get_hyphenation_type();
+ if (prev_type == HYPHEN_BOUNDARY && this_type == HYPHEN_MIDDLE)
+ break;
+ prev_type = this_type;
+ }
+ if (*startp == 0)
+ return;
+ node *tem = *startp;
+ int i = 0;
+ do {
+ ++i;
+ tem = tem->next;
+ } while (tem != 0 && tem->get_hyphenation_type() == HYPHEN_MIDDLE);
+ int inhibit = (tem != 0 && tem->get_hyphenation_type() == HYPHEN_INHIBIT);
+ node *end = tem;
+ hyphen_list *sl = 0;
+ tem = *startp;
+ node *forward = 0;
+ while (tem != end) {
+ sl = tem->get_hyphen_list(sl);
+ node *tem1 = tem;
+ tem = tem->next;
+ tem1->next = forward;
+ forward = tem1;
+ }
+ if (!inhibit) {
+ // this is for characters like hyphen and emdash
+ int prev_code = 0;
+ for (hyphen_list *h = sl; h; h = h->next) {
+ h->breakable = (prev_code != 0
+ && h->next != 0
+ && h->next->hyphenation_code != 0);
+ prev_code = h->hyphenation_code;
+ }
+ }
+ if (hyphenation_flags != 0
+ && !inhibit
+ // this may not be right if we have extra space on this line
+ && !((hyphenation_flags & HYPHEN_LAST_LINE)
+ && curdiv->distance_to_next_trap() <= line_spacing*vertical_spacing)
+ && i >= 4)
+ hyphenate(sl, hyphenation_flags);
+ while (forward != 0) {
+ node *tem1 = forward;
+ forward = forward->next;
+ tem1->next = 0;
+ tem = tem1->add_self(tem, &sl);
+ }
+ *startp = tem;
+}
+
+static node *node_list_reverse(node *n)
+{
+ node *res = 0;
+ while (n) {
+ node *tem = n;
+ n = n->next;
+ tem->next = res;
+ res = tem;
+ }
+ return res;
+}
+
+static void distribute_space(node *n, int nspaces, hunits desired_space,
+ int force_reverse = 0)
+{
+ static int reverse = 0;
+ if (force_reverse || reverse)
+ n = node_list_reverse(n);
+ for (node *tem = n; tem; tem = tem->next)
+ tem->spread_space(&nspaces, &desired_space);
+ if (force_reverse || reverse)
+ (void)node_list_reverse(n);
+ if (!force_reverse)
+ reverse = !reverse;
+ assert(desired_space.is_zero() && nspaces == 0);
+}
+
+void environment::possibly_break_line(int forced)
+{
+ if (!fill || current_tab || current_field || dummy)
+ return;
+ while (line != 0 && (forced || width_total > target_text_length)) {
+ hyphenate_line();
+ breakpoint *bp = choose_breakpoint();
+ if (bp == 0)
+ // we'll find one eventually
+ return;
+ node *pre, *post;
+ node **ndp = &line;
+ while (*ndp != bp->nd)
+ ndp = &(*ndp)->next;
+ bp->nd->split(bp->index, &pre, &post);
+ *ndp = post;
+ hunits extra_space_width = H0;
+ switch(adjust_mode) {
+ case ADJUST_BOTH:
+ if (bp->nspaces != 0)
+ extra_space_width = target_text_length - bp->width;
+ break;
+ case ADJUST_CENTER:
+ saved_indent += (target_text_length - bp->width)/2;
+ break;
+ case ADJUST_RIGHT:
+ saved_indent += target_text_length - bp->width;
+ break;
+ }
+ distribute_space(pre, bp->nspaces, extra_space_width);
+ hunits output_width = bp->width + extra_space_width;
+ input_line_start -= output_width;
+ if (bp->hyphenated)
+ hyphen_line_count++;
+ else
+ hyphen_line_count = 0;
+ delete bp;
+ space_total = 0;
+ width_total = 0;
+ node *first_non_discardable = 0;
+ for (node *tem = line; tem != 0; tem = tem->next)
+ if (!tem->discardable())
+ first_non_discardable = tem;
+ node *to_be_discarded;
+ if (first_non_discardable) {
+ to_be_discarded = first_non_discardable->next;
+ first_non_discardable->next = 0;
+ for (tem = line; tem != 0; tem = tem->next) {
+ width_total += tem->width();
+ space_total += tem->nspaces();
+ }
+ discarding = 0;
+ }
+ else {
+ discarding = 1;
+ to_be_discarded = line;
+ line = 0;
+ }
+ // Do output_line() here so that line will be 0 iff the
+ // the environment will be empty.
+ output_line(pre, output_width);
+ while (to_be_discarded != 0) {
+ tem = to_be_discarded;
+ to_be_discarded = to_be_discarded->next;
+ input_line_start -= tem->width();
+ delete tem;
+ }
+ if (line != 0) {
+ if (have_temporary_indent) {
+ saved_indent = temporary_indent;
+ have_temporary_indent = 0;
+ }
+ else
+ saved_indent = indent;
+ target_text_length = line_length - saved_indent;
+ }
+ }
+}
+
+/*
+Do the break at the end of input after the end macro (if any).
+
+Unix troff behaves as follows: if the last line is
+
+foo bar\c
+
+it will output foo on the current page, and bar on the next page;
+if the last line is
+
+foo\c
+
+or
+
+foo bar
+
+everything will be output on the current page. This behaviour must be
+considered a bug.
+
+The problem is that some macro packages rely on this. For example,
+the ATK macros have an end macro that emits \c if it needs to print a
+table of contents but doesn't do a 'bp in the end macro; instead the
+'bp is done in the bottom of page trap. This works with Unix troff,
+provided that the current environment is not empty at the end of the
+input file.
+
+The following will make macro packages that do that sort of thing work
+even if the current environment is empty at the end of the input file.
+If the last input line used \c and this line occurred in the end macro,
+then we'll force everything out on the current page, but we'll make
+sure that the environment isn't empty so that we won't exit at the
+bottom of this page.
+*/
+
+void environment::final_break()
+{
+ if (prev_line_interrupted == 2) {
+ do_break();
+ add_node(new transparent_dummy_node);
+ }
+ else
+ do_break();
+}
+
+void environment::do_break()
+{
+ if (curdiv == topdiv && topdiv->before_first_page) {
+ topdiv->begin_page();
+ return;
+ }
+ if (current_tab)
+ wrap_up_tab();
+ if (line) {
+ line = new space_node(H0, line); // this is so that hyphenation works
+ space_total++;
+ possibly_break_line();
+ }
+ while (line != 0 && line->discardable()) {
+ width_total -= line->width();
+ space_total -= line->nspaces();
+ node *tem = line;
+ line = line->next;
+ delete tem;
+ }
+ discarding = 0;
+ input_line_start = H0;
+ if (line != 0) {
+ if (fill) {
+ switch (adjust_mode) {
+ case ADJUST_CENTER:
+ saved_indent += (target_text_length - width_total)/2;
+ break;
+ case ADJUST_RIGHT:
+ saved_indent += target_text_length - width_total;
+ break;
+ }
+ }
+ node *tem = line;
+ line = 0;
+ output_line(tem, width_total);
+ hyphen_line_count = 0;
+ }
+ prev_line_interrupted = 0;
+#ifdef WIDOW_CONTROL
+ mark_last_line();
+ output_pending_lines();
+#endif /* WIDOW_CONTROL */
+}
+
+int environment::is_empty()
+{
+ return !current_tab && line == 0 && pending_lines == 0;
+}
+
+void break_request()
+{
+ while (!tok.newline() && !tok.eof())
+ tok.next();
+ if (break_flag)
+ curenv->do_break();
+ tok.next();
+}
+
+void title()
+{
+ if (curdiv == topdiv && topdiv->before_first_page) {
+ handle_initial_title();
+ return;
+ }
+ node *part[3];
+ hunits part_width[3];
+ part[0] = part[1] = part[2] = 0;
+ environment env(curenv);
+ environment *oldenv = curenv;
+ curenv = &env;
+ read_title_parts(part, part_width);
+ curenv = oldenv;
+ curenv->size = env.size;
+ curenv->prev_size = env.prev_size;
+ curenv->requested_size = env.requested_size;
+ curenv->prev_requested_size = env.prev_requested_size;
+ curenv->char_height = env.char_height;
+ curenv->char_slant = env.char_slant;
+ curenv->fontno = env.fontno;
+ curenv->prev_fontno = env.prev_fontno;
+ node *n = 0;
+ node *p = part[2];
+ while (p != 0) {
+ node *tem = p;
+ p = p->next;
+ tem->next = n;
+ n = tem;
+ }
+ hunits title_length(curenv->title_length);
+ hunits f = title_length - part_width[1];
+ hunits f2 = f/2;
+ n = new hmotion_node(f2 - part_width[2], n);
+ p = part[1];
+ while (p != 0) {
+ node *tem = p;
+ p = p->next;
+ tem->next = n;
+ n = tem;
+ }
+ n = new hmotion_node(f - f2 - part_width[0], n);
+ p = part[0];
+ while (p != 0) {
+ node *tem = p;
+ p = p->next;
+ tem->next = n;
+ n = tem;
+ }
+ curenv->output_title(n, !curenv->fill, curenv->vertical_spacing,
+ curenv->line_spacing, title_length);
+ curenv->hyphen_line_count = 0;
+ tok.next();
+}
+
+void adjust()
+{
+ curenv->adjust_mode |= 1;
+ if (has_arg()) {
+ switch (tok.ch()) {
+ case 'l':
+ curenv->adjust_mode = ADJUST_LEFT;
+ break;
+ case 'r':
+ curenv->adjust_mode = ADJUST_RIGHT;
+ break;
+ case 'c':
+ curenv->adjust_mode = ADJUST_CENTER;
+ break;
+ case 'b':
+ case 'n':
+ curenv->adjust_mode = ADJUST_BOTH;
+ break;
+ default:
+ int n;
+ if (get_integer(&n)) {
+ if (n < 0)
+ warning(WARN_RANGE, "negative adjustment mode");
+ else if (n > 5) {
+ curenv->adjust_mode = 5;
+ warning(WARN_RANGE, "adjustment mode `%1' out of range", n);
+ }
+ else
+ curenv->adjust_mode = n;
+ }
+ }
+ }
+ skip_line();
+}
+
+void no_adjust()
+{
+ curenv->adjust_mode &= ~1;
+ skip_line();
+}
+
+void input_trap()
+{
+ curenv->input_trap_count = 0;
+ int n;
+ if (has_arg() && get_integer(&n)) {
+ if (n <= 0)
+ warning(WARN_RANGE,
+ "number of lines for input trap must be greater than zero");
+ else {
+ symbol s = get_name(1);
+ if (!s.is_null()) {
+ curenv->input_trap_count = n;
+ curenv->input_trap = s;
+ }
+ }
+ }
+ skip_line();
+}
+
+/* tabs */
+
+// must not be R or C or L or a legitimate part of a number expression
+const char TAB_REPEAT_CHAR = 'T';
+
+struct tab {
+ tab *next;
+ hunits pos;
+ tab_type type;
+ tab(hunits, tab_type);
+ enum { BLOCK = 1024 };
+ static tab *free_list;
+ void *operator new(size_t);
+ void operator delete(void *);
+};
+
+tab *tab::free_list = 0;
+
+void *tab::operator new(size_t n)
+{
+ assert(n == sizeof(tab));
+ if (!free_list) {
+ free_list = (tab *)new char[sizeof(tab)*BLOCK];
+ for (int i = 0; i < BLOCK - 1; i++)
+ free_list[i].next = free_list + i + 1;
+ free_list[BLOCK-1].next = 0;
+ }
+ tab *p = free_list;
+ free_list = (tab *)(free_list->next);
+ p->next = 0;
+ return p;
+}
+
+#ifdef __GNUG__
+/* cfront can't cope with this. */
+inline
+#endif
+void tab::operator delete(void *p)
+{
+ if (p) {
+ ((tab *)p)->next = free_list;
+ free_list = (tab *)p;
+ }
+}
+
+tab::tab(hunits x, tab_type t) : next(0), pos(x), type(t)
+{
+}
+
+tab_stops::tab_stops(hunits distance, tab_type type)
+ : initial_list(0)
+{
+ repeated_list = new tab(distance, type);
+}
+
+tab_stops::~tab_stops()
+{
+ clear();
+}
+
+tab_type tab_stops::distance_to_next_tab(hunits curpos, hunits *distance)
+{
+ hunits lastpos = 0;
+ for (tab *tem = initial_list; tem && tem->pos <= curpos; tem = tem->next)
+ lastpos = tem->pos;
+ if (tem) {
+ *distance = tem->pos - curpos;
+ return tem->type;
+ }
+ if (repeated_list == 0)
+ return TAB_NONE;
+ hunits base = lastpos;
+ for (;;) {
+ for (tem = repeated_list; tem && tem->pos + base <= curpos; tem = tem->next)
+ lastpos = tem->pos;
+ if (tem) {
+ *distance = tem->pos + base - curpos;
+ return tem->type;
+ }
+ assert(lastpos > 0);
+ base += lastpos;
+ }
+ return TAB_NONE;
+}
+
+const char *tab_stops::to_string()
+{
+ static char *buf = 0;
+ static int buf_size = 0;
+ // figure out a maximum on the amount of space we can need
+ int count = 0;
+ for (tab *p = initial_list; p; p = p->next)
+ ++count;
+ for (p = repeated_list; p; p = p->next)
+ ++count;
+ // (10 for digits + 1 for u + 1 for 'C' or 'R') + 2 for ' &' + 1 for '\0'
+ int need = count*12 + 3;
+ if (buf == 0 || need > buf_size) {
+ if (buf)
+ a_delete buf;
+ buf_size = need;
+ buf = new char[buf_size];
+ }
+ char *ptr = buf;
+ for (p = initial_list; p; p = p->next) {
+ strcpy(ptr, itoa(p->pos.to_units()));
+ ptr = strchr(ptr, '\0');
+ *ptr++ = 'u';
+ *ptr = '\0';
+ switch (p->type) {
+ case TAB_LEFT:
+ break;
+ case TAB_RIGHT:
+ *ptr++ = 'R';
+ break;
+ case TAB_CENTER:
+ *ptr++ = 'C';
+ break;
+ case TAB_NONE:
+ default:
+ assert(0);
+ }
+ }
+ if (repeated_list)
+ *ptr++ = TAB_REPEAT_CHAR;
+ for (p = repeated_list; p; p = p->next) {
+ strcpy(ptr, itoa(p->pos.to_units()));
+ ptr = strchr(ptr, '\0');
+ *ptr++ = 'u';
+ *ptr = '\0';
+ switch (p->type) {
+ case TAB_LEFT:
+ break;
+ case TAB_RIGHT:
+ *ptr++ = 'R';
+ break;
+ case TAB_CENTER:
+ *ptr++ = 'C';
+ break;
+ case TAB_NONE:
+ default:
+ assert(0);
+ }
+ }
+ *ptr++ = '\0';
+ return buf;
+}
+
+tab_stops::tab_stops() : initial_list(0), repeated_list(0)
+{
+}
+
+tab_stops::tab_stops(const tab_stops &ts)
+ : initial_list(0), repeated_list(0)
+{
+ tab **p = &initial_list;
+ tab *t = ts.initial_list;
+ while (t) {
+ *p = new tab(t->pos, t->type);
+ t = t->next;
+ p = &(*p)->next;
+ }
+ p = &repeated_list;
+ t = ts.repeated_list;
+ while (t) {
+ *p = new tab(t->pos, t->type);
+ t = t->next;
+ p = &(*p)->next;
+ }
+}
+
+void tab_stops::clear()
+{
+ while (initial_list) {
+ tab *tem = initial_list;
+ initial_list = initial_list->next;
+ delete tem;
+ }
+ while (repeated_list) {
+ tab *tem = repeated_list;
+ repeated_list = repeated_list->next;
+ delete tem;
+ }
+}
+
+void tab_stops::add_tab(hunits pos, tab_type type, int repeated)
+{
+ for (tab **p = repeated ? &repeated_list : &initial_list; *p; p = &(*p)->next)
+ ;
+ *p = new tab(pos, type);
+}
+
+
+void tab_stops::operator=(const tab_stops &ts)
+{
+ clear();
+ tab **p = &initial_list;
+ tab *t = ts.initial_list;
+ while (t) {
+ *p = new tab(t->pos, t->type);
+ t = t->next;
+ p = &(*p)->next;
+ }
+ p = &repeated_list;
+ t = ts.repeated_list;
+ while (t) {
+ *p = new tab(t->pos, t->type);
+ t = t->next;
+ p = &(*p)->next;
+ }
+}
+
+void set_tabs()
+{
+ hunits pos;
+ hunits prev_pos = 0;
+ int first = 1;
+ int repeated = 0;
+ tab_stops tabs;
+ while (has_arg()) {
+ if (tok.ch() == TAB_REPEAT_CHAR) {
+ tok.next();
+ repeated = 1;
+ prev_pos = 0;
+ }
+ if (!get_hunits(&pos, 'm', prev_pos))
+ break;
+ tab_type type = TAB_LEFT;
+ if (tok.ch() == 'C') {
+ tok.next();
+ type = TAB_CENTER;
+ }
+ else if (tok.ch() == 'R') {
+ tok.next();
+ type = TAB_RIGHT;
+ }
+ else if (tok.ch() == 'L') {
+ tok.next();
+ }
+ if (pos <= prev_pos && !first)
+ warning(WARN_RANGE,
+ "positions of tab stops must be strictly increasing");
+ else {
+ tabs.add_tab(pos, type, repeated);
+ prev_pos = pos;
+ first = 0;
+ }
+ }
+ curenv->tabs = tabs;
+ skip_line();
+}
+
+const char *environment::get_tabs()
+{
+ return tabs.to_string();
+}
+
+#if 0
+tab_stops saved_tabs;
+
+void tabs_save()
+{
+ saved_tabs = curenv->tabs;
+ skip_line();
+}
+
+void tabs_restore()
+{
+ curenv->tabs = saved_tabs;
+ skip_line();
+}
+#endif
+
+tab_type environment::distance_to_next_tab(hunits *distance)
+{
+ return curenv->tabs.distance_to_next_tab(get_input_line_position(), distance);
+}
+
+void field_characters()
+{
+ field_delimiter_char = get_optional_char();
+ if (field_delimiter_char)
+ padding_indicator_char = get_optional_char();
+ else
+ padding_indicator_char = 0;
+ skip_line();
+}
+
+void environment::wrap_up_tab()
+{
+ if (!current_tab)
+ return;
+ if (line == 0)
+ start_line();
+ hunits tab_amount;
+ switch (current_tab) {
+ case TAB_RIGHT:
+ tab_amount = tab_distance - tab_width;
+ line = make_tab_node(tab_amount, line);
+ break;
+ case TAB_CENTER:
+ tab_amount = tab_distance - tab_width/2;
+ line = make_tab_node(tab_amount, line);
+ break;
+ case TAB_NONE:
+ case TAB_LEFT:
+ default:
+ assert(0);
+ }
+ width_total += tab_amount;
+ width_total += tab_width;
+ if (current_field) {
+ if (tab_precedes_field) {
+ pre_field_width += tab_amount;
+ tab_precedes_field = 0;
+ }
+ field_distance -= tab_amount;
+ field_spaces += tab_field_spaces;
+ }
+ if (tab_contents != 0) {
+ for (node *tem = tab_contents; tem->next != 0; tem = tem->next)
+ ;
+ tem->next = line;
+ line = tab_contents;
+ }
+ tab_field_spaces = 0;
+ tab_contents = 0;
+ tab_width = H0;
+ tab_distance = H0;
+ current_tab = TAB_NONE;
+}
+
+node *environment::make_tab_node(hunits d, node *next)
+{
+ if (leader_node != 0 && d < 0) {
+ error("motion generated by leader cannot be negative");
+ delete leader_node;
+ leader_node = 0;
+ }
+ if (!leader_node)
+ return new hmotion_node(d, next);
+ node *n = new hline_node(d, leader_node, next);
+ leader_node = 0;
+ return n;
+}
+
+void environment::handle_tab(int is_leader)
+{
+ hunits d;
+ if (current_tab)
+ wrap_up_tab();
+ charinfo *ci = is_leader ? leader_char : tab_char;
+ delete leader_node;
+ leader_node = ci ? make_char_node(ci) : 0;
+ tab_type t = distance_to_next_tab(&d);
+ switch (t) {
+ case TAB_NONE:
+ return;
+ case TAB_LEFT:
+ add_node(make_tab_node(d));
+ return;
+ case TAB_RIGHT:
+ case TAB_CENTER:
+ tab_width = 0;
+ tab_distance = d;
+ tab_contents = 0;
+ current_tab = t;
+ tab_field_spaces = 0;
+ return;
+ default:
+ assert(0);
+ }
+}
+
+void environment::start_field()
+{
+ assert(!current_field);
+ hunits d;
+ if (distance_to_next_tab(&d) != TAB_NONE) {
+ pre_field_width = get_text_length();
+ field_distance = d;
+ current_field = 1;
+ field_spaces = 0;
+ tab_field_spaces = 0;
+ for (node *p = line; p; p = p->next)
+ if (p->nspaces()) {
+ p->freeze_space();
+ space_total--;
+ }
+ tab_precedes_field = current_tab != TAB_NONE;
+ }
+ else
+ error("zero field width");
+}
+
+void environment::wrap_up_field()
+{
+ if (!current_tab && field_spaces == 0)
+ add_padding();
+ hunits padding = field_distance - (get_text_length() - pre_field_width);
+ if (current_tab && tab_field_spaces != 0) {
+ hunits tab_padding = scale(padding,
+ tab_field_spaces,
+ field_spaces + tab_field_spaces);
+ padding -= tab_padding;
+ distribute_space(tab_contents, tab_field_spaces, tab_padding, 1);
+ tab_field_spaces = 0;
+ tab_width += tab_padding;
+ }
+ if (field_spaces != 0) {
+ distribute_space(line, field_spaces, padding, 1);
+ width_total += padding;
+ if (current_tab) {
+ // the start of the tab has been moved to the right by padding, so
+ tab_distance -= padding;
+ if (tab_distance <= H0) {
+ // use the next tab stop instead
+ current_tab = tabs.distance_to_next_tab(get_input_line_position()
+ - tab_width,
+ &tab_distance);
+ if (current_tab == TAB_NONE || current_tab == TAB_LEFT) {
+ width_total += tab_width;
+ if (current_tab == TAB_LEFT) {
+ line = make_tab_node(tab_distance, line);
+ width_total += tab_distance;
+ current_tab = TAB_NONE;
+ }
+ if (tab_contents != 0) {
+ for (node *tem = tab_contents; tem->next != 0; tem = tem->next)
+ ;
+ tem->next = line;
+ line = tab_contents;
+ tab_contents = 0;
+ }
+ tab_width = H0;
+ tab_distance = H0;
+ }
+ }
+ }
+ }
+ current_field = 0;
+}
+
+void environment::add_padding()
+{
+ if (current_tab) {
+ tab_contents = new space_node(H0, tab_contents);
+ tab_field_spaces++;
+ }
+ else {
+ if (line == 0)
+ start_line();
+ line = new space_node(H0, line);
+ field_spaces++;
+ }
+}
+
+typedef int (environment::*INT_FUNCP)();
+typedef vunits (environment::*VUNITS_FUNCP)();
+typedef hunits (environment::*HUNITS_FUNCP)();
+typedef const char *(environment::*STRING_FUNCP)();
+
+class int_env_reg : public reg {
+ INT_FUNCP func;
+ public:
+ int_env_reg(INT_FUNCP);
+ const char *get_string();
+ int get_value(units *val);
+};
+
+class vunits_env_reg : public reg {
+ VUNITS_FUNCP func;
+ public:
+ vunits_env_reg(VUNITS_FUNCP f);
+ const char *get_string();
+ int get_value(units *val);
+};
+
+
+class hunits_env_reg : public reg {
+ HUNITS_FUNCP func;
+ public:
+ hunits_env_reg(HUNITS_FUNCP f);
+ const char *get_string();
+ int get_value(units *val);
+};
+
+class string_env_reg : public reg {
+ STRING_FUNCP func;
+public:
+ string_env_reg(STRING_FUNCP);
+ const char *get_string();
+};
+
+int_env_reg::int_env_reg(INT_FUNCP f) : func(f)
+{
+}
+
+int int_env_reg::get_value(units *val)
+{
+ *val = (curenv->*func)();
+ return 1;
+}
+
+const char *int_env_reg::get_string()
+{
+ return itoa((curenv->*func)());
+}
+
+vunits_env_reg::vunits_env_reg(VUNITS_FUNCP f) : func(f)
+{
+}
+
+int vunits_env_reg::get_value(units *val)
+{
+ *val = (curenv->*func)().to_units();
+ return 1;
+}
+
+const char *vunits_env_reg::get_string()
+{
+ return itoa((curenv->*func)().to_units());
+}
+
+hunits_env_reg::hunits_env_reg(HUNITS_FUNCP f) : func(f)
+{
+}
+
+int hunits_env_reg::get_value(units *val)
+{
+ *val = (curenv->*func)().to_units();
+ return 1;
+}
+
+const char *hunits_env_reg::get_string()
+{
+ return itoa((curenv->*func)().to_units());
+}
+
+string_env_reg::string_env_reg(STRING_FUNCP f) : func(f)
+{
+}
+
+const char *string_env_reg::get_string()
+{
+ return (curenv->*func)();
+}
+
+class horizontal_place_reg : public general_reg {
+public:
+ horizontal_place_reg();
+ int get_value(units *);
+ void set_value(units);
+};
+
+horizontal_place_reg::horizontal_place_reg()
+{
+}
+
+int horizontal_place_reg::get_value(units *res)
+{
+ *res = curenv->get_input_line_position().to_units();
+ return 1;
+}
+
+void horizontal_place_reg::set_value(units n)
+{
+ curenv->set_input_line_position(hunits(n));
+}
+
+const char *environment::get_font_family_string()
+{
+ return family->nm.contents();
+}
+
+const char *environment::get_name_string()
+{
+ return name.contents();
+}
+
+// Convert a quantity in scaled points to ascii decimal fraction.
+
+const char *sptoa(int sp)
+{
+ assert(sp > 0);
+ assert(sizescale > 0);
+ if (sizescale == 1)
+ return itoa(sp);
+ if (sp % sizescale == 0)
+ return itoa(sp/sizescale);
+ // See if 1/sizescale is exactly representable as a decimal fraction,
+ // ie its only prime factors are 2 and 5.
+ int n = sizescale;
+ int power2 = 0;
+ while ((n & 1) == 0) {
+ n >>= 1;
+ power2++;
+ }
+ int power5 = 0;
+ while ((n % 5) == 0) {
+ n /= 5;
+ power5++;
+ }
+ if (n == 1) {
+ int decimal_point = power5 > power2 ? power5 : power2;
+ if (decimal_point <= 10) {
+ int factor = 1;
+ int t;
+ for (t = decimal_point - power2; --t >= 0;)
+ factor *= 2;
+ for (t = decimal_point - power5; --t >= 0;)
+ factor *= 5;
+ if (factor == 1 || sp <= INT_MAX/factor)
+ return iftoa(sp*factor, decimal_point);
+ }
+ }
+ double s = double(sp)/double(sizescale);
+ double factor = 10.0;
+ double val = s;
+ int decimal_point = 0;
+ do {
+ double v = ceil(s*factor);
+ if (v > INT_MAX)
+ break;
+ val = v;
+ factor *= 10.0;
+ } while (++decimal_point < 10);
+ return iftoa(int(val), decimal_point);
+}
+
+const char *environment::get_point_size_string()
+{
+ return sptoa(curenv->get_point_size());
+}
+
+const char *environment::get_requested_point_size_string()
+{
+ return sptoa(curenv->get_requested_point_size());
+}
+
+#define init_int_env_reg(name, func) \
+ number_reg_dictionary.define(name, new int_env_reg(&environment::func))
+
+#define init_vunits_env_reg(name, func) \
+ number_reg_dictionary.define(name, new vunits_env_reg(&environment::func))
+
+#define init_hunits_env_reg(name, func) \
+ number_reg_dictionary.define(name, new hunits_env_reg(&environment::func))
+
+#define init_string_env_reg(name, func) \
+ number_reg_dictionary.define(name, new string_env_reg(&environment::func))
+
+void init_env_requests()
+{
+ init_request("it", input_trap);
+ init_request("ad", adjust);
+ init_request("na", no_adjust);
+ init_request("ev", environment_switch);
+ init_request("lt", title_length);
+ init_request("ps", point_size);
+ init_request("ft", font_change);
+ init_request("fam", family_change);
+ init_request("ss", space_size);
+ init_request("fi", fill);
+ init_request("nf", no_fill);
+ init_request("ce", center);
+ init_request("rj", right_justify);
+ init_request("vs", vertical_spacing);
+ init_request("ls", line_spacing);
+ init_request("ll", line_length);
+ init_request("in", indent);
+ init_request("ti", temporary_indent);
+ init_request("ul", underline);
+ init_request("cu", underline);
+ init_request("cc", control_char);
+ init_request("c2", no_break_control_char);
+ init_request("br", break_request);
+ init_request("tl", title);
+ init_request("ta", set_tabs);
+ init_request("fc", field_characters);
+ init_request("mc", margin_character);
+ init_request("nn", no_number);
+ init_request("nm", number_lines);
+ init_request("tc", tab_character);
+ init_request("lc", leader_character);
+ init_request("hy", hyphenate_request);
+ init_request("hc", hyphen_char);
+ init_request("nh", no_hyphenate);
+ init_request("hlm", hyphen_line_max_request);
+#ifdef WIDOW_CONTROL
+ init_request("wdc", widow_control_request);
+#endif /* WIDOW_CONTROL */
+#if 0
+ init_request("tas", tabs_save);
+ init_request("tar", tabs_restore);
+#endif
+ init_request("hys", hyphenation_space_request);
+ init_request("hym", hyphenation_margin_request);
+ init_int_env_reg(".f", get_font);
+ init_int_env_reg(".b", get_bold);
+ init_hunits_env_reg(".i", get_indent);
+ init_hunits_env_reg(".in", get_saved_indent);
+ init_int_env_reg(".j", get_adjust_mode);
+ init_hunits_env_reg(".k", get_text_length);
+ init_hunits_env_reg(".l", get_line_length);
+ init_hunits_env_reg(".ll", get_saved_line_length);
+ init_int_env_reg(".L", get_line_spacing);
+ init_hunits_env_reg(".n", get_prev_text_length);
+ init_string_env_reg(".s", get_point_size_string);
+ init_string_env_reg(".sr", get_requested_point_size_string);
+ init_int_env_reg(".ps", get_point_size);
+ init_int_env_reg(".psr", get_requested_point_size);
+ init_int_env_reg(".u", get_fill);
+ init_vunits_env_reg(".v", get_vertical_spacing);
+ init_hunits_env_reg(".w", get_prev_char_width);
+ init_int_env_reg(".ss", get_space_size);
+ init_int_env_reg(".sss", get_sentence_space_size);
+ init_string_env_reg(".fam", get_font_family_string);
+ init_string_env_reg(".ev", get_name_string);
+ init_int_env_reg(".hy", get_hyphenation_flags);
+ init_int_env_reg(".hlm", get_hyphen_line_max);
+ init_int_env_reg(".hlc", get_hyphen_line_count);
+ init_hunits_env_reg(".lt", get_title_length);
+ init_string_env_reg(".tabs", get_tabs);
+ init_hunits_env_reg(".csk", get_prev_char_skew);
+ init_vunits_env_reg(".cht", get_prev_char_height);
+ init_vunits_env_reg(".cdp", get_prev_char_depth);
+ init_int_env_reg(".ce", get_center_lines);
+ init_int_env_reg(".rj", get_right_justify_lines);
+ init_hunits_env_reg(".hys", get_hyphenation_space);
+ init_hunits_env_reg(".hym", get_hyphenation_margin);
+ number_reg_dictionary.define("ln", new variable_reg(&next_line_number));
+ number_reg_dictionary.define("ct", new variable_reg(&ct_reg_contents));
+ number_reg_dictionary.define("sb", new variable_reg(&sb_reg_contents));
+ number_reg_dictionary.define("st", new variable_reg(&st_reg_contents));
+ number_reg_dictionary.define("rsb", new variable_reg(&rsb_reg_contents));
+ number_reg_dictionary.define("rst", new variable_reg(&rst_reg_contents));
+ number_reg_dictionary.define("ssc", new variable_reg(&ssc_reg_contents));
+ number_reg_dictionary.define("skw", new variable_reg(&skw_reg_contents));
+ number_reg_dictionary.define("hp", new horizontal_place_reg);
+}
+
+// Hyphenation - TeX's hyphenation algorithm with a less fancy implementation.
+
+struct trie_node;
+
+class trie {
+ trie_node *tp;
+ virtual void do_match(int len, void *val) = 0;
+ virtual void do_delete(void *) = 0;
+ void delete_trie_node(trie_node *);
+public:
+ trie() : tp(0) {}
+ virtual ~trie(); // virtual to shut up g++
+ void insert(const char *, int, void *);
+ // find calls do_match for each match it finds
+ void find(const char *pat, int patlen);
+ void clear();
+};
+
+class hyphen_trie : private trie {
+ int *h;
+ void do_match(int i, void *v);
+ void do_delete(void *v);
+ void insert_pattern(const char *pat, int patlen, int *num);
+public:
+ hyphen_trie() {}
+ ~hyphen_trie() {}
+ void hyphenate(const char *word, int len, int *hyphens);
+ void read_patterns_file(const char *name);
+};
+
+
+struct hyphenation_language {
+ symbol name;
+ dictionary exceptions;
+ hyphen_trie patterns;
+ hyphenation_language(symbol nm) : name(nm), exceptions(501) {}
+ ~hyphenation_language() { }
+};
+
+dictionary language_dictionary(5);
+hyphenation_language *current_language = 0;
+
+static void set_hyphenation_language()
+{
+ symbol nm = get_name(1);
+ if (!nm.is_null()) {
+ current_language = (hyphenation_language *)language_dictionary.lookup(nm);
+ if (!current_language) {
+ current_language = new hyphenation_language(nm);
+ (void)language_dictionary.lookup(nm, (void *)current_language);
+ }
+ }
+ skip_line();
+}
+
+const int WORD_MAX = 1024;
+
+static void hyphen_word()
+{
+ if (!current_language) {
+ error("no current hyphenation language");
+ skip_line();
+ return;
+ }
+ char buf[WORD_MAX + 1];
+ unsigned char pos[WORD_MAX + 2];
+ for (;;) {
+ tok.skip();
+ if (tok.newline() || tok.eof())
+ break;
+ int i = 0;
+ int npos = 0;
+ while (i < WORD_MAX && !tok.space() && !tok.newline() && !tok.eof()) {
+ charinfo *ci = tok.get_char(1);
+ if (ci == 0) {
+ skip_line();
+ return;
+ }
+ tok.next();
+ if (ci->get_ascii_code() == '-') {
+ if (i > 0 && (npos == 0 || pos[npos - 1] != i))
+ pos[npos++] = i;
+ }
+ else {
+ int c = ci->get_hyphenation_code();
+ if (c == 0)
+ break;
+ buf[i++] = c;
+ }
+ }
+ if (i > 0) {
+ pos[npos] = 0;
+ buf[i] = 0;
+ unsigned char *tem = new unsigned char[npos + 1];
+ memcpy(tem, pos, npos+1);
+ tem = (unsigned char *)current_language->exceptions.lookup(symbol(buf),
+ tem);
+ if (tem)
+ a_delete tem;
+ }
+ }
+ skip_line();
+}
+
+struct trie_node {
+ char c;
+ trie_node *down;
+ trie_node *right;
+ void *val;
+ trie_node(char, trie_node *);
+};
+
+trie_node::trie_node(char ch, trie_node *p)
+: c(ch), right(p), down(0), val(0)
+{
+}
+
+trie::~trie()
+{
+ clear();
+}
+
+void trie::clear()
+{
+ delete_trie_node(tp);
+ tp = 0;
+}
+
+
+void trie::delete_trie_node(trie_node *p)
+{
+ if (p) {
+ delete_trie_node(p->down);
+ delete_trie_node(p->right);
+ if (p->val)
+ do_delete(p->val);
+ delete p;
+ }
+}
+
+void trie::insert(const char *pat, int patlen, void *val)
+{
+ trie_node **p = &tp;
+ assert(patlen > 0 && pat != 0);
+ for (;;) {
+ while (*p != 0 && (*p)->c < pat[0])
+ p = &((*p)->right);
+ if (*p == 0 || (*p)->c != pat[0])
+ *p = new trie_node(pat[0], *p);
+ if (--patlen == 0) {
+ (*p)->val = val;
+ break;
+ }
+ ++pat;
+ p = &((*p)->down);
+ }
+}
+
+void trie::find(const char *pat, int patlen)
+{
+ trie_node *p = tp;
+ for (int i = 0; p != 0 && i < patlen; i++) {
+ while (p != 0 && p->c < pat[i])
+ p = p->right;
+ if (p != 0 && p->c == pat[i]) {
+ if (p->val != 0)
+ do_match(i+1, p->val);
+ p = p->down;
+ }
+ else
+ break;
+ }
+}
+
+struct operation {
+ operation *next;
+ short distance;
+ short num;
+ operation(int, int, operation *);
+};
+
+operation::operation(int i, int j, operation *op)
+: num(i), distance(j), next(op)
+{
+}
+
+void hyphen_trie::insert_pattern(const char *pat, int patlen, int *num)
+{
+ operation *op = 0;
+ for (int i = 0; i < patlen+1; i++)
+ if (num[i] != 0)
+ op = new operation(num[i], patlen - i, op);
+ insert(pat, patlen, op);
+}
+
+void hyphen_trie::hyphenate(const char *word, int len, int *hyphens)
+{
+ for (int j = 0; j < len+1; j++)
+ hyphens[j] = 0;
+ for (j = 0; j < len - 1; j++) {
+ h = hyphens + j;
+ find(word + j, len - j);
+ }
+}
+
+inline int max(int m, int n)
+{
+ return m > n ? m : n;
+}
+
+void hyphen_trie::do_match(int i, void *v)
+{
+ operation *op = (operation *)v;
+ while (op != 0) {
+ h[i - op->distance] = max(h[i - op->distance], op->num);
+ op = op->next;
+ }
+}
+
+void hyphen_trie::do_delete(void *v)
+{
+ operation *op = (operation *)v;
+ while (op) {
+ operation *tem = op;
+ op = tem->next;
+ delete tem;
+ }
+}
+
+void hyphen_trie::read_patterns_file(const char *name)
+{
+ clear();
+ char buf[WORD_MAX];
+ int num[WORD_MAX+1];
+ errno = 0;
+ char *path = 0;
+ FILE *fp = macro_path.open_file(name, &path);
+ if (fp == 0) {
+ error("can't find hyphenation patterns file `%1'", name);
+ return;
+ }
+ int c = getc(fp);
+ for (;;) {
+ for (;;) {
+ if (c == '%') {
+ do {
+ c = getc(fp);
+ } while (c != EOF && c != '\n');
+ }
+ if (c == EOF || !csspace(c))
+ break;
+ c = getc(fp);
+ }
+ if (c == EOF)
+ break;
+ int i = 0;
+ num[0] = 0;
+ do {
+ if (csdigit(c))
+ num[i] = c - '0';
+ else {
+ buf[i++] = c;
+ num[i] = 0;
+ }
+ c = getc(fp);
+ } while (i < WORD_MAX && c != EOF && !csspace(c) && c != '%');
+ insert_pattern(buf, i, num);
+ }
+ fclose(fp);
+ a_delete path;
+ return;
+}
+
+void hyphenate(hyphen_list *h, unsigned flags)
+{
+ if (!current_language)
+ return;
+ while (h && h->hyphenation_code == 0)
+ h = h->next;
+ int len = 0;
+ char hbuf[WORD_MAX+2];
+ char *buf = hbuf + 1;
+ for (hyphen_list *tem = h; tem && len < WORD_MAX; tem = tem->next) {
+ if (tem->hyphenation_code != 0)
+ buf[len++] = tem->hyphenation_code;
+ else
+ break;
+ }
+ if (len > 2) {
+ buf[len] = 0;
+ unsigned char *pos = (unsigned char *)current_language->exceptions.lookup(buf);
+ if (pos != 0) {
+ int j = 0;
+ int i = 1;
+ for (tem = h; tem != 0; tem = tem->next, i++)
+ if (pos[j] == i) {
+ tem->hyphen = 1;
+ j++;
+ }
+ }
+ else {
+ hbuf[0] = hbuf[len+1] = '.';
+ int num[WORD_MAX+3];
+ current_language->patterns.hyphenate(hbuf, len+2, num);
+ int i;
+ num[2] = 0;
+ if (flags & 8)
+ num[3] = 0;
+ if (flags & 4)
+ --len;
+ for (i = 2, tem = h; i < len && tem; tem = tem->next, i++)
+ if (num[i] & 1)
+ tem->hyphen = 1;
+ }
+ }
+}
+
+static void hyphenation_patterns_file()
+{
+ symbol name = get_long_name(1);
+ if (!name.is_null()) {
+ if (!current_language)
+ error("no current hyphenation language");
+ else
+ current_language->patterns.read_patterns_file(name.contents());
+ }
+ skip_line();
+}
+
+class hyphenation_language_reg : public reg {
+public:
+ const char *get_string();
+};
+
+const char *hyphenation_language_reg::get_string()
+{
+ return current_language ? current_language->name.contents() : "";
+}
+
+void init_hyphen_requests()
+{
+ init_request("hw", hyphen_word);
+ init_request("hla", set_hyphenation_language);
+ init_request("hpf", hyphenation_patterns_file);
+ number_reg_dictionary.define(".hla", new hyphenation_language_reg);
+}
diff --git a/gnu/usr.bin/groff/troff/env.h b/gnu/usr.bin/groff/troff/env.h
new file mode 100644
index 0000000..40ce6b8
--- /dev/null
+++ b/gnu/usr.bin/groff/troff/env.h
@@ -0,0 +1,327 @@
+// -*- C++ -*-
+/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
+ Written by James Clark (jjc@jclark.com)
+
+This file is part of groff.
+
+groff is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
+
+groff is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License along
+with groff; see the file COPYING. If not, write to the Free Software
+Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+struct size_range {
+ int min;
+ int max;
+};
+
+class font_size {
+ static size_range *size_table;
+ static int nranges;
+ int p;
+public:
+ font_size();
+ font_size(int points);
+ int to_points();
+ int to_scaled_points();
+ int to_units();
+ int operator==(font_size);
+ int operator!=(font_size);
+ static void init_size_table(int *sizes);
+};
+
+inline font_size::font_size() : p(0)
+{
+}
+
+inline int font_size::operator==(font_size fs)
+{
+ return p == fs.p;
+}
+
+inline int font_size::operator!=(font_size fs)
+{
+ return p != fs.p;
+}
+
+inline int font_size::to_scaled_points()
+{
+ return p;
+}
+
+inline int font_size::to_points()
+{
+ return p/sizescale;
+}
+
+struct environment;
+
+hunits env_digit_width(environment *);
+hunits env_space_width(environment *);
+hunits env_sentence_space_width(environment *);
+hunits env_narrow_space_width(environment *);
+hunits env_half_narrow_space_width(environment *);
+
+struct tab;
+
+enum tab_type { TAB_NONE, TAB_LEFT, TAB_CENTER, TAB_RIGHT };
+
+class tab_stops {
+ tab *initial_list;
+ tab *repeated_list;
+public:
+ tab_stops();
+ tab_stops(hunits distance, tab_type type);
+ tab_stops(const tab_stops &);
+ ~tab_stops();
+ void operator=(const tab_stops &);
+ tab_type distance_to_next_tab(hunits pos, hunits *distance);
+ void clear();
+ void add_tab(hunits pos, tab_type type, int repeated);
+ const char *to_string();
+};
+
+const unsigned MARGIN_CHARACTER_ON = 1;
+const unsigned MARGIN_CHARACTER_NEXT = 2;
+
+struct charinfo;
+struct node;
+struct breakpoint;
+struct font_family;
+struct pending_output_line;
+
+class environment {
+ int dummy; // dummy environment used for \w
+ hunits prev_line_length;
+ hunits line_length;
+ hunits prev_title_length;
+ hunits title_length;
+ font_size prev_size;
+ font_size size;
+ int requested_size;
+ int prev_requested_size;
+ int char_height;
+ int char_slant;
+ int prev_fontno;
+ int fontno;
+ font_family *prev_family;
+ font_family *family;
+ int space_size; // in 36ths of an em
+ int sentence_space_size; // same but for spaces at the end of sentences
+ int adjust_mode;
+ int fill;
+ int interrupted;
+ int prev_line_interrupted;
+ int center_lines;
+ int right_justify_lines;
+ vunits prev_vertical_spacing;
+ vunits vertical_spacing;
+ int prev_line_spacing;
+ int line_spacing;
+ hunits prev_indent;
+ hunits indent;
+ hunits temporary_indent;
+ int have_temporary_indent;
+ hunits saved_indent;
+ hunits target_text_length;
+ int pre_underline_fontno;
+ int underline_lines;
+ symbol input_trap;
+ int input_trap_count;
+ node *line; // in reverse order
+ hunits prev_text_length;
+ hunits width_total;
+ int space_total;
+ hunits input_line_start;
+ tab_stops tabs;
+ node *tab_contents;
+ hunits tab_width;
+ hunits tab_distance;
+ tab_type current_tab;
+ node *leader_node;
+ charinfo *tab_char;
+ charinfo *leader_char;
+ int current_field; // is there a current field?
+ hunits field_distance;
+ hunits pre_field_width;
+ int field_spaces;
+ int tab_field_spaces;
+ int tab_precedes_field;
+ int discarding;
+ int spread_flag; // set by \p
+ unsigned margin_character_flags;
+ node *margin_character_node;
+ hunits margin_character_distance;
+ node *numbering_nodes;
+ hunits line_number_digit_width;
+ int number_text_separation; // in digit spaces
+ int line_number_indent; // in digit spaces
+ int line_number_multiple;
+ int no_number_count;
+ unsigned hyphenation_flags;
+ int hyphen_line_count;
+ int hyphen_line_max;
+ hunits hyphenation_space;
+ hunits hyphenation_margin;
+ int composite; // used for construction of composite char?
+ pending_output_line *pending_lines;
+#ifdef WIDOW_CONTROL
+ int widow_control;
+#endif /* WIDOW_CONTROL */
+
+ tab_type distance_to_next_tab(hunits *);
+ void start_line();
+ void output_line(node *, hunits);
+ void output(node *nd, int retain_size, vunits vs, int ls, hunits width);
+ void output_title(node *nd, int retain_size, vunits vs, int ls,
+ hunits width);
+#ifdef WIDOW_CONTROL
+ void mark_last_line();
+#endif /* WIDOW_CONTROL */
+ void possibly_break_line(int forced = 0);
+ breakpoint *choose_breakpoint();
+ void hyphenate_line();
+ void start_field();
+ void wrap_up_field();
+ void add_padding();
+ node *make_tab_node(hunits d, node *next = 0);
+ node *get_prev_char();
+public:
+ const symbol name;
+ unsigned char control_char;
+ unsigned char no_break_control_char;
+ charinfo *hyphen_indicator_char;
+
+ environment(symbol);
+ environment(const environment *); // for temporary environment
+ ~environment();
+ int is_dummy() { return dummy; }
+ int is_empty();
+ int is_composite() { return composite; }
+ void set_composite() { composite = 1; }
+ vunits get_vertical_spacing(); // .v
+ int get_line_spacing(); // .L
+ int get_point_size() { return size.to_scaled_points(); }
+ font_size get_font_size() { return size; }
+ int get_size() { return size.to_units(); }
+ int get_requested_point_size() { return requested_size; }
+ int get_char_height() { return char_height; }
+ int get_char_slant() { return char_slant; }
+ hunits get_digit_width();
+ int get_font() { return fontno; }; // .f
+ font_family *get_family() { return family; }
+ int get_bold(); // .b
+ int get_adjust_mode(); // .j
+ int get_fill(); // .u
+ hunits get_indent(); // .i
+ hunits get_temporary_indent();
+ hunits get_line_length(); // .l
+ hunits get_saved_line_length(); // .ll
+ hunits get_saved_indent(); // .in
+ hunits get_title_length();
+ hunits get_prev_char_width(); // .w
+ hunits get_prev_char_skew();
+ vunits get_prev_char_height();
+ vunits get_prev_char_depth();
+ hunits get_text_length(); // .k
+ hunits get_prev_text_length(); // .n
+ hunits get_space_width() { return env_space_width(this); }
+ int get_space_size() { return space_size; } // in ems/36
+ int get_sentence_space_size() { return sentence_space_size; }
+ hunits get_narrow_space_width() { return env_narrow_space_width(this); }
+ hunits get_half_narrow_space_width()
+ { return env_half_narrow_space_width(this); }
+ hunits get_input_line_position();
+ const char *get_tabs();
+ int get_hyphenation_flags();
+ int get_hyphen_line_max();
+ int get_hyphen_line_count();
+ hunits get_hyphenation_space();
+ hunits get_hyphenation_margin();
+ int get_center_lines();
+ int get_right_justify_lines();
+ int get_prev_line_interrupted() { return prev_line_interrupted; }
+ node *make_char_node(charinfo *);
+ node *extract_output_line();
+ void width_registers();
+ void wrap_up_tab();
+ void set_font(int);
+ void set_font(symbol);
+ void set_family(symbol);
+ void set_size(int);
+ void set_char_height(int);
+ void set_char_slant(int);
+ void set_input_line_position(hunits); // used by \n(hp
+ void interrupt();
+ void spread() { spread_flag = 1; }
+ void do_break(); // .br
+ void final_break();
+ void newline();
+ void handle_tab(int is_leader = 0); // do a tab or leader
+ void add_node(node *);
+ void add_char(charinfo *);
+ void add_hyphen_indicator();
+ void add_italic_correction();
+ void space();
+ void space_newline();
+ const char *get_font_family_string();
+ const char *get_name_string();
+ const char *get_point_size_string();
+ const char *get_requested_point_size_string();
+ void output_pending_lines();
+
+ friend void title_length();
+ friend void space_size();
+ friend void fill();
+ friend void no_fill();
+ friend void adjust();
+ friend void no_adjust();
+ friend void center();
+ friend void right_justify();
+ friend void vertical_spacing();
+ friend void line_spacing();
+ friend void line_length();
+ friend void indent();
+ friend void temporary_indent();
+ friend void underline();
+ friend void input_trap();
+ friend void set_tabs();
+ friend void margin_character();
+ friend void no_number();
+ friend void number_lines();
+ friend void leader_character();
+ friend void tab_character();
+ friend void hyphenate_request();
+ friend void no_hyphenate();
+ friend void hyphen_line_max_request();
+ friend void hyphenation_space_request();
+ friend void hyphenation_margin_request();
+ friend void line_width();
+#if 0
+ friend void tabs_save();
+ friend void tabs_restore();
+#endif
+ friend void title();
+#ifdef WIDOW_CONTROL
+ friend void widow_control_request();
+#endif /* WIDOW_CONTROL */
+};
+
+extern environment *curenv;
+extern void pop_env();
+extern void push_env(int);
+
+void init_environments();
+void read_hyphen_file(const char *name);
+
+extern int break_flag;
+extern symbol default_family;
+extern int translate_space_to_dummy;
diff --git a/gnu/usr.bin/groff/troff/hvunits.h b/gnu/usr.bin/groff/troff/hvunits.h
new file mode 100644
index 0000000..4a1c5fd
--- /dev/null
+++ b/gnu/usr.bin/groff/troff/hvunits.h
@@ -0,0 +1,340 @@
+// -*- C++ -*-
+/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
+ Written by James Clark (jjc@jclark.com)
+
+This file is part of groff.
+
+groff is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
+
+groff is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License along
+with groff; see the file COPYING. If not, write to the Free Software
+Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+
+class vunits {
+ int n;
+public:
+ vunits();
+ vunits(units);
+ units to_units();
+ int is_zero();
+ vunits& operator+=(const vunits&);
+ vunits& operator-=(const vunits&);
+ friend inline vunits scale(vunits n, units x, units y); // scale n by x/y
+ friend inline vunits scale(vunits n, vunits x, vunits y);
+ friend inline vunits operator +(const vunits&, const vunits&);
+ friend inline vunits operator -(const vunits&, const vunits&);
+ friend inline vunits operator -(const vunits&);
+ friend inline int operator /(const vunits&, const vunits&);
+ friend inline vunits operator /(const vunits&, int);
+ friend inline vunits operator *(const vunits&, int);
+ friend inline vunits operator *(int, const vunits&);
+ friend inline int operator <(const vunits&, const vunits&);
+ friend inline int operator >(const vunits&, const vunits&);
+ friend inline int operator <=(const vunits&, const vunits&);
+ friend inline int operator >=(const vunits&, const vunits&);
+ friend inline int operator ==(const vunits&, const vunits&);
+ friend inline int operator !=(const vunits&, const vunits&);
+};
+
+extern vunits V0;
+
+
+class hunits {
+ int n;
+public:
+ hunits();
+ hunits(units);
+ units to_units();
+ int is_zero();
+ hunits& operator+=(const hunits&);
+ hunits& operator-=(const hunits&);
+ friend inline hunits scale(hunits n, units x, units y); // scale n by x/y
+ friend inline hunits scale(hunits n, double x);
+ friend inline hunits operator +(const hunits&, const hunits&);
+ friend inline hunits operator -(const hunits&, const hunits&);
+ friend inline hunits operator -(const hunits&);
+ friend inline int operator /(const hunits&, const hunits&);
+ friend inline hunits operator /(const hunits&, int);
+ friend inline hunits operator *(const hunits&, int);
+ friend inline hunits operator *(int, const hunits&);
+ friend inline int operator <(const hunits&, const hunits&);
+ friend inline int operator >(const hunits&, const hunits&);
+ friend inline int operator <=(const hunits&, const hunits&);
+ friend inline int operator >=(const hunits&, const hunits&);
+ friend inline int operator ==(const hunits&, const hunits&);
+ friend inline int operator !=(const hunits&, const hunits&);
+};
+
+extern hunits H0;
+
+extern int get_vunits(vunits *, unsigned char si);
+extern int get_hunits(hunits *, unsigned char si);
+extern int get_vunits(vunits *, unsigned char si, vunits prev_value);
+extern int get_hunits(hunits *, unsigned char si, hunits prev_value);
+
+inline vunits:: vunits() : n(0)
+{
+}
+
+inline units vunits::to_units()
+{
+ return n*vresolution;
+}
+
+inline int vunits::is_zero()
+{
+ return n == 0;
+}
+
+inline vunits operator +(const vunits & x, const vunits & y)
+{
+ vunits r;
+ r = x;
+ r.n += y.n;
+ return r;
+}
+
+inline vunits operator -(const vunits & x, const vunits & y)
+{
+ vunits r;
+ r = x;
+ r.n -= y.n;
+ return r;
+}
+
+inline vunits operator -(const vunits & x)
+{
+ vunits r;
+ r.n = -x.n;
+ return r;
+}
+
+inline int operator /(const vunits & x, const vunits & y)
+{
+ return x.n/y.n;
+}
+
+inline vunits operator /(const vunits & x, int n)
+{
+ vunits r;
+ r = x;
+ r.n /= n;
+ return r;
+}
+
+inline vunits operator *(const vunits & x, int n)
+{
+ vunits r;
+ r = x;
+ r.n *= n;
+ return r;
+}
+
+inline vunits operator *(int n, const vunits & x)
+{
+ vunits r;
+ r = x;
+ r.n *= n;
+ return r;
+}
+
+inline int operator <(const vunits & x, const vunits & y)
+{
+ return x.n < y.n;
+}
+
+inline int operator >(const vunits & x, const vunits & y)
+{
+ return x.n > y.n;
+}
+
+inline int operator <=(const vunits & x, const vunits & y)
+{
+ return x.n <= y.n;
+}
+
+inline int operator >=(const vunits & x, const vunits & y)
+{
+ return x.n >= y.n;
+}
+
+inline int operator ==(const vunits & x, const vunits & y)
+{
+ return x.n == y.n;
+}
+
+inline int operator !=(const vunits & x, const vunits & y)
+{
+ return x.n != y.n;
+}
+
+
+inline vunits& vunits::operator+=(const vunits & x)
+{
+ n += x.n;
+ return *this;
+}
+
+inline vunits& vunits::operator-=(const vunits & x)
+{
+ n -= x.n;
+ return *this;
+}
+
+inline hunits:: hunits() : n(0)
+{
+}
+
+inline units hunits::to_units()
+{
+ return n*hresolution;
+}
+
+inline int hunits::is_zero()
+{
+ return n == 0;
+}
+
+inline hunits operator +(const hunits & x, const hunits & y)
+{
+ hunits r;
+ r = x;
+ r.n += y.n;
+ return r;
+}
+
+inline hunits operator -(const hunits & x, const hunits & y)
+{
+ hunits r;
+ r = x;
+ r.n -= y.n;
+ return r;
+}
+
+inline hunits operator -(const hunits & x)
+{
+ hunits r;
+ r = x;
+ r.n = -x.n;
+ return r;
+}
+
+inline int operator /(const hunits & x, const hunits & y)
+{
+ return x.n/y.n;
+}
+
+inline hunits operator /(const hunits & x, int n)
+{
+ hunits r;
+ r = x;
+ r.n /= n;
+ return r;
+}
+
+inline hunits operator *(const hunits & x, int n)
+{
+ hunits r;
+ r = x;
+ r.n *= n;
+ return r;
+}
+
+inline hunits operator *(int n, const hunits & x)
+{
+ hunits r;
+ r = x;
+ r.n *= n;
+ return r;
+}
+
+inline int operator <(const hunits & x, const hunits & y)
+{
+ return x.n < y.n;
+}
+
+inline int operator >(const hunits & x, const hunits & y)
+{
+ return x.n > y.n;
+}
+
+inline int operator <=(const hunits & x, const hunits & y)
+{
+ return x.n <= y.n;
+}
+
+inline int operator >=(const hunits & x, const hunits & y)
+{
+ return x.n >= y.n;
+}
+
+inline int operator ==(const hunits & x, const hunits & y)
+{
+ return x.n == y.n;
+}
+
+inline int operator !=(const hunits & x, const hunits & y)
+{
+ return x.n != y.n;
+}
+
+
+inline hunits& hunits::operator+=(const hunits & x)
+{
+ n += x.n;
+ return *this;
+}
+
+inline hunits& hunits::operator-=(const hunits & x)
+{
+ n -= x.n;
+ return *this;
+}
+
+inline hunits scale(hunits n, units x, units y)
+{
+ hunits r;
+ r.n = scale(n.n, x, y);
+ return r;
+}
+
+inline vunits scale(vunits n, units x, units y)
+{
+ vunits r;
+ r.n = scale(n.n, x, y);
+ return r;
+}
+
+inline vunits scale(vunits n, vunits x, vunits y)
+{
+ vunits r;
+ r.n = scale(n.n, x.n, y.n);
+ return r;
+}
+
+inline hunits scale(hunits n, double x)
+{
+ hunits r;
+ r.n = int(n.n*x);
+ return r;
+}
+
+inline units scale(units n, double x)
+{
+ return int(n*x);
+}
+
+inline units points_to_units(units n)
+{
+ return scale(n, units_per_inch, 72);
+}
+
diff --git a/gnu/usr.bin/groff/troff/hyphen.us b/gnu/usr.bin/groff/troff/hyphen.us
new file mode 100644
index 0000000..d86c3d5
--- /dev/null
+++ b/gnu/usr.bin/groff/troff/hyphen.us
@@ -0,0 +1,4449 @@
+% Hyphenation patterns for US English.
+% These are the standard Plain TeX hyphenation patterns (in hyphen.tex).
+.ach4
+.ad4der
+.af1t
+.al3t
+.am5at
+.an5c
+.ang4
+.ani5m
+.ant4
+.an3te
+.anti5s
+.ar5s
+.ar4tie
+.ar4ty
+.as3c
+.as1p
+.as1s
+.aster5
+.atom5
+.au1d
+.av4i
+.awn4
+.ba4g
+.ba5na
+.bas4e
+.ber4
+.be5ra
+.be3sm
+.be5sto
+.bri2
+.but4ti
+.cam4pe
+.can5c
+.capa5b
+.car5ol
+.ca4t
+.ce4la
+.ch4
+.chill5i
+.ci2
+.cit5r
+.co3e
+.co4r
+.cor5ner
+.de4moi
+.de3o
+.de3ra
+.de3ri
+.des4c
+.dictio5
+.do4t
+.du4c
+.dumb5
+.earth5
+.eas3i
+.eb4
+.eer4
+.eg2
+.el5d
+.el3em
+.enam3
+.en3g
+.en3s
+.eq5ui5t
+.er4ri
+.es3
+.eu3
+.eye5
+.fes3
+.for5mer
+.ga2
+.ge2
+.gen3t4
+.ge5og
+.gi5a
+.gi4b
+.go4r
+.hand5i
+.han5k
+.he2
+.hero5i
+.hes3
+.het3
+.hi3b
+.hi3er
+.hon5ey
+.hon3o
+.hov5
+.id4l
+.idol3
+.im3m
+.im5pin
+.in1
+.in3ci
+.ine2
+.in2k
+.in3s
+.ir5r
+.is4i
+.ju3r
+.la4cy
+.la4m
+.lat5er
+.lath5
+.le2
+.leg5e
+.len4
+.lep5
+.lev1
+.li4g
+.lig5a
+.li2n
+.li3o
+.li4t
+.mag5a5
+.mal5o
+.man5a
+.mar5ti
+.me2
+.mer3c
+.me5ter
+.mis1
+.mist5i
+.mon3e
+.mo3ro
+.mu5ta
+.muta5b
+.ni4c
+.od2
+.odd5
+.of5te
+.or5ato
+.or3c
+.or1d
+.or3t
+.os3
+.os4tl
+.oth3
+.out3
+.ped5al
+.pe5te
+.pe5tit
+.pi4e
+.pio5n
+.pi2t
+.pre3m
+.ra4c
+.ran4t
+.ratio5na
+.ree2
+.re5mit
+.res2
+.re5stat
+.ri4g
+.rit5u
+.ro4q
+.ros5t
+.row5d
+.ru4d
+.sci3e
+.self5
+.sell5
+.se2n
+.se5rie
+.sh2
+.si2
+.sing4
+.st4
+.sta5bl
+.sy2
+.ta4
+.te4
+.ten5an
+.th2
+.ti2
+.til4
+.tim5o5
+.ting4
+.tin5k
+.ton4a
+.to4p
+.top5i
+.tou5s
+.trib5ut
+.un1a
+.un3ce
+.under5
+.un1e
+.un5k
+.un5o
+.un3u
+.up3
+.ure3
+.us5a
+.ven4de
+.ve5ra
+.wil5i
+.ye4
+4ab.
+a5bal
+a5ban
+abe2
+ab5erd
+abi5a
+ab5it5ab
+ab5lat
+ab5o5liz
+4abr
+ab5rog
+ab3ul
+a4car
+ac5ard
+ac5aro
+a5ceou
+ac1er
+a5chet
+4a2ci
+a3cie
+ac1in
+a3cio
+ac5rob
+act5if
+ac3ul
+ac4um
+a2d
+ad4din
+ad5er.
+2adi
+a3dia
+ad3ica
+adi4er
+a3dio
+a3dit
+a5diu
+ad4le
+ad3ow
+ad5ran
+ad4su
+4adu
+a3duc
+ad5um
+ae4r
+aeri4e
+a2f
+aff4
+a4gab
+aga4n
+ag5ell
+age4o
+4ageu
+ag1i
+4ag4l
+ag1n
+a2go
+3agog
+ag3oni
+a5guer
+ag5ul
+a4gy
+a3ha
+a3he
+ah4l
+a3ho
+ai2
+a5ia
+a3ic.
+ai5ly
+a4i4n
+ain5in
+ain5o
+ait5en
+a1j
+ak1en
+al5ab
+al3ad
+a4lar
+4aldi
+2ale
+al3end
+a4lenti
+a5le5o
+al1i
+al4ia.
+ali4e
+al5lev
+4allic
+4alm
+a5log.
+a4ly.
+4alys
+5a5lyst
+5alyt
+3alyz
+4ama
+am5ab
+am3ag
+ama5ra
+am5asc
+a4matis
+a4m5ato
+am5era
+am3ic
+am5if
+am5ily
+am1in
+ami4no
+a2mo
+a5mon
+amor5i
+amp5en
+a2n
+an3age
+3analy
+a3nar
+an3arc
+anar4i
+a3nati
+4and
+ande4s
+an3dis
+an1dl
+an4dow
+a5nee
+a3nen
+an5est.
+a3neu
+2ang
+ang5ie
+an1gl
+a4n1ic
+a3nies
+an3i3f
+an4ime
+a5nimi
+a5nine
+an3io
+a3nip
+an3ish
+an3it
+a3niu
+an4kli
+5anniz
+ano4
+an5ot
+anoth5
+an2sa
+an4sco
+an4sn
+an2sp
+ans3po
+an4st
+an4sur
+antal4
+an4tie
+4anto
+an2tr
+an4tw
+an3ua
+an3ul
+a5nur
+4ao
+apar4
+ap5at
+ap5ero
+a3pher
+4aphi
+a4pilla
+ap5illar
+ap3in
+ap3ita
+a3pitu
+a2pl
+apoc5
+ap5ola
+apor5i
+apos3t
+aps5es
+a3pu
+aque5
+2a2r
+ar3act
+a5rade
+ar5adis
+ar3al
+a5ramete
+aran4g
+ara3p
+ar4at
+a5ratio
+ar5ativ
+a5rau
+ar5av4
+araw4
+arbal4
+ar4chan
+ar5dine
+ar4dr
+ar5eas
+a3ree
+ar3ent
+a5ress
+ar4fi
+ar4fl
+ar1i
+ar5ial
+ar3ian
+a3riet
+ar4im
+ar5inat
+ar3io
+ar2iz
+ar2mi
+ar5o5d
+a5roni
+a3roo
+ar2p
+ar3q
+arre4
+ar4sa
+ar2sh
+4as.
+as4ab
+as3ant
+ashi4
+a5sia.
+a3sib
+a3sic
+5a5si4t
+ask3i
+as4l
+a4soc
+as5ph
+as4sh
+as3ten
+as1tr
+asur5a
+a2ta
+at3abl
+at5ac
+at3alo
+at5ap
+ate5c
+at5ech
+at3ego
+at3en.
+at3era
+ater5n
+a5terna
+at3est
+at5ev
+4ath
+ath5em
+a5then
+at4ho
+ath5om
+4ati.
+a5tia
+at5i5b
+at1ic
+at3if
+ation5ar
+at3itu
+a4tog
+a2tom
+at5omiz
+a4top
+a4tos
+a1tr
+at5rop
+at4sk
+at4tag
+at5te
+at4th
+a2tu
+at5ua
+at5ue
+at3ul
+at3ura
+a2ty
+au4b
+augh3
+au3gu
+au4l2
+aun5d
+au3r
+au5sib
+aut5en
+au1th
+a2va
+av3ag
+a5van
+ave4no
+av3era
+av5ern
+av5ery
+av1i
+avi4er
+av3ig
+av5oc
+a1vor
+3away
+aw3i
+aw4ly
+aws4
+ax4ic
+ax4id
+ay5al
+aye4
+ays4
+azi4er
+azz5i
+5ba.
+bad5ger
+ba4ge
+bal1a
+ban5dag
+ban4e
+ban3i
+barbi5
+bari4a
+bas4si
+1bat
+ba4z
+2b1b
+b2be
+b3ber
+bbi4na
+4b1d
+4be.
+beak4
+beat3
+4be2d
+be3da
+be3de
+be3di
+be3gi
+be5gu
+1bel
+be1li
+be3lo
+4be5m
+be5nig
+be5nu
+4bes4
+be3sp
+be5str
+3bet
+bet5iz
+be5tr
+be3tw
+be3w
+be5yo
+2bf
+4b3h
+bi2b
+bi4d
+3bie
+bi5en
+bi4er
+2b3if
+1bil
+bi3liz
+bina5r4
+bin4d
+bi5net
+bi3ogr
+bi5ou
+bi2t
+3bi3tio
+bi3tr
+3bit5ua
+b5itz
+b1j
+bk4
+b2l2
+blath5
+b4le.
+blen4
+5blesp
+b3lis
+b4lo
+blun4t
+4b1m
+4b3n
+bne5g
+3bod
+bod3i
+bo4e
+bol3ic
+bom4bi
+bon4a
+bon5at
+3boo
+5bor.
+4b1ora
+bor5d
+5bore
+5bori
+5bos4
+b5ota
+both5
+bo4to
+bound3
+4bp
+4brit
+broth3
+2b5s2
+bsor4
+2bt
+bt4l
+b4to
+b3tr
+buf4fer
+bu4ga
+bu3li
+bumi4
+bu4n
+bunt4i
+bu3re
+bus5ie
+buss4e
+5bust
+4buta
+3butio
+b5uto
+b1v
+4b5w
+5by.
+bys4
+1ca
+cab3in
+ca1bl
+cach4
+ca5den
+4cag4
+2c5ah
+ca3lat
+cal4la
+call5in
+4calo
+can5d
+can4e
+can4ic
+can5is
+can3iz
+can4ty
+cany4
+ca5per
+car5om
+cast5er
+cas5tig
+4casy
+ca4th
+4cativ
+cav5al
+c3c
+ccha5
+cci4a
+ccompa5
+ccon4
+ccou3t
+2ce.
+4ced.
+4ceden
+3cei
+5cel.
+3cell
+1cen
+3cenc
+2cen4e
+4ceni
+3cent
+3cep
+ce5ram
+4cesa
+3cessi
+ces5si5b
+ces5t
+cet4
+c5e4ta
+cew4
+2ch
+4ch.
+4ch3ab
+5chanic
+ch5a5nis
+che2
+cheap3
+4ched
+che5lo
+3chemi
+ch5ene
+ch3er.
+ch3ers
+4ch1in
+5chine.
+ch5iness
+5chini
+5chio
+3chit
+chi2z
+3cho2
+ch4ti
+1ci
+3cia
+ci2a5b
+cia5r
+ci5c
+4cier
+5cific.
+4cii
+ci4la
+3cili
+2cim
+2cin
+c4ina
+3cinat
+cin3em
+c1ing
+c5ing.
+5cino
+cion4
+4cipe
+ci3ph
+4cipic
+4cista
+4cisti
+2c1it
+cit3iz
+5ciz
+ck1
+ck3i
+1c4l4
+4clar
+c5laratio
+5clare
+cle4m
+4clic
+clim4
+cly4
+c5n
+1co
+co5ag
+coe2
+2cog
+co4gr
+coi4
+co3inc
+col5i
+5colo
+col3or
+com5er
+con4a
+c4one
+con3g
+con5t
+co3pa
+cop3ic
+co4pl
+4corb
+coro3n
+cos4e
+cov1
+cove4
+cow5a
+coz5e
+co5zi
+c1q
+cras5t
+5crat.
+5cratic
+cre3at
+5cred
+4c3reta
+cre4v
+cri2
+cri5f
+c4rin
+cris4
+5criti
+cro4pl
+crop5o
+cros4e
+cru4d
+4c3s2
+2c1t
+cta4b
+ct5ang
+c5tant
+c2te
+c3ter
+c4ticu
+ctim3i
+ctu4r
+c4tw
+cud5
+c4uf
+c4ui
+cu5ity
+5culi
+cul4tis
+3cultu
+cu2ma
+c3ume
+cu4mi
+3cun
+cu3pi
+cu5py
+cur5a4b
+cu5ria
+1cus
+cuss4i
+3c4ut
+cu4tie
+4c5utiv
+4cutr
+1cy
+cze4
+1d2a
+5da.
+2d3a4b
+dach4
+4daf
+2dag
+da2m2
+dan3g
+dard5
+dark5
+4dary
+3dat
+4dativ
+4dato
+5dav4
+dav5e
+5day
+d1b
+d5c
+d1d4
+2de.
+deaf5
+deb5it
+de4bon
+decan4
+de4cil
+de5com
+2d1ed
+4dee.
+de5if
+deli4e
+del5i5q
+de5lo
+d4em
+5dem.
+3demic
+dem5ic.
+de5mil
+de4mons
+demor5
+1den
+de4nar
+de3no
+denti5f
+de3nu
+de1p
+de3pa
+depi4
+de2pu
+d3eq
+d4erh
+5derm
+dern5iz
+der5s
+des2
+d2es.
+de1sc
+de2s5o
+des3ti
+de3str
+de4su
+de1t
+de2to
+de1v
+dev3il
+4dey
+4d1f
+d4ga
+d3ge4t
+dg1i
+d2gy
+d1h2
+5di.
+1d4i3a
+dia5b
+di4cam
+d4ice
+3dict
+3did
+5di3en
+d1if
+di3ge
+di4lato
+d1in
+1dina
+3dine.
+5dini
+di5niz
+1dio
+dio5g
+di4pl
+dir2
+di1re
+dirt5i
+dis1
+5disi
+d4is3t
+d2iti
+1di1v
+d1j
+d5k2
+4d5la
+3dle.
+3dled
+3dles.
+4dless
+2d3lo
+4d5lu
+2dly
+d1m
+4d1n4
+1do
+3do.
+do5de
+5doe
+2d5of
+d4og
+do4la
+doli4
+do5lor
+dom5iz
+do3nat
+doni4
+doo3d
+dop4p
+d4or
+3dos
+4d5out
+do4v
+3dox
+d1p
+1dr
+drag5on
+4drai
+dre4
+drea5r
+5dren
+dri4b
+dril4
+dro4p
+4drow
+5drupli
+4dry
+2d1s2
+ds4p
+d4sw
+d4sy
+d2th
+1du
+d1u1a
+du2c
+d1uca
+duc5er
+4duct.
+4ducts
+du5el
+du4g
+d3ule
+dum4be
+du4n
+4dup
+du4pe
+d1v
+d1w
+d2y
+5dyn
+dy4se
+dys5p
+e1a4b
+e3act
+ead1
+ead5ie
+ea4ge
+ea5ger
+ea4l
+eal5er
+eal3ou
+eam3er
+e5and
+ear3a
+ear4c
+ear5es
+ear4ic
+ear4il
+ear5k
+ear2t
+eart3e
+ea5sp
+e3ass
+east3
+ea2t
+eat5en
+eath3i
+e5atif
+e4a3tu
+ea2v
+eav3en
+eav5i
+eav5o
+2e1b
+e4bel.
+e4bels
+e4ben
+e4bit
+e3br
+e4cad
+ecan5c
+ecca5
+e1ce
+ec5essa
+ec2i
+e4cib
+ec5ificat
+ec5ifie
+ec5ify
+ec3im
+eci4t
+e5cite
+e4clam
+e4clus
+e2col
+e4comm
+e4compe
+e4conc
+e2cor
+ec3ora
+eco5ro
+e1cr
+e4crem
+ec4tan
+ec4te
+e1cu
+e4cul
+ec3ula
+2e2da
+4ed3d
+e4d1er
+ede4s
+4edi
+e3dia
+ed3ib
+ed3ica
+ed3im
+ed1it
+edi5z
+4edo
+e4dol
+edon2
+e4dri
+e4dul
+ed5ulo
+ee2c
+eed3i
+ee2f
+eel3i
+ee4ly
+ee2m
+ee4na
+ee4p1
+ee2s4
+eest4
+ee4ty
+e5ex
+e1f
+e4f3ere
+1eff
+e4fic
+5efici
+efil4
+e3fine
+ef5i5nite
+3efit
+efor5es
+e4fuse.
+4egal
+eger4
+eg5ib
+eg4ic
+eg5ing
+e5git5
+eg5n
+e4go.
+e4gos
+eg1ul
+e5gur
+5egy
+e1h4
+eher4
+ei2
+e5ic
+ei5d
+eig2
+ei5gl
+e3imb
+e3inf
+e1ing
+e5inst
+eir4d
+eit3e
+ei3th
+e5ity
+e1j
+e4jud
+ej5udi
+eki4n
+ek4la
+e1la
+e4la.
+e4lac
+elan4d
+el5ativ
+e4law
+elaxa4
+e3lea
+el5ebra
+5elec
+e4led
+el3ega
+e5len
+e4l1er
+e1les
+el2f
+el2i
+e3libe
+e4l5ic.
+el3ica
+e3lier
+el5igib
+e5lim
+e4l3ing
+e3lio
+e2lis
+el5ish
+e3liv3
+4ella
+el4lab
+ello4
+e5loc
+el5og
+el3op.
+el2sh
+el4ta
+e5lud
+el5ug
+e4mac
+e4mag
+e5man
+em5ana
+em5b
+e1me
+e2mel
+e4met
+em3ica
+emi4e
+em5igra
+em1in2
+em5ine
+em3i3ni
+e4mis
+em5ish
+e5miss
+em3iz
+5emniz
+emo4g
+emoni5o
+em3pi
+e4mul
+em5ula
+emu3n
+e3my
+en5amo
+e4nant
+ench4er
+en3dic
+e5nea
+e5nee
+en3em
+en5ero
+en5esi
+en5est
+en3etr
+e3new
+en5ics
+e5nie
+e5nil
+e3nio
+en3ish
+en3it
+e5niu
+5eniz
+4enn
+4eno
+eno4g
+e4nos
+en3ov
+en4sw
+ent5age
+4enthes
+en3ua
+en5uf
+e3ny.
+4en3z
+e5of
+eo2g
+e4oi4
+e3ol
+eop3ar
+e1or
+eo3re
+eo5rol
+eos4
+e4ot
+eo4to
+e5out
+e5ow
+e2pa
+e3pai
+ep5anc
+e5pel
+e3pent
+ep5etitio
+ephe4
+e4pli
+e1po
+e4prec
+ep5reca
+e4pred
+ep3reh
+e3pro
+e4prob
+ep4sh
+ep5ti5b
+e4put
+ep5uta
+e1q
+equi3l
+e4q3ui3s
+er1a
+era4b
+4erand
+er3ar
+4erati.
+2erb
+er4bl
+er3ch
+er4che
+2ere.
+e3real
+ere5co
+ere3in
+er5el.
+er3emo
+er5ena
+er5ence
+4erene
+er3ent
+ere4q
+er5ess
+er3est
+eret4
+er1h
+er1i
+e1ria4
+5erick
+e3rien
+eri4er
+er3ine
+e1rio
+4erit
+er4iu
+eri4v
+e4riva
+er3m4
+er4nis
+4ernit
+5erniz
+er3no
+2ero
+er5ob
+e5roc
+ero4r
+er1ou
+er1s
+er3set
+ert3er
+4ertl
+er3tw
+4eru
+eru4t
+5erwau
+e1s4a
+e4sage.
+e4sages
+es2c
+e2sca
+es5can
+e3scr
+es5cu
+e1s2e
+e2sec
+es5ecr
+es5enc
+e4sert.
+e4serts
+e4serva
+4esh
+e3sha
+esh5en
+e1si
+e2sic
+e2sid
+es5iden
+es5igna
+e2s5im
+es4i4n
+esis4te
+esi4u
+e5skin
+es4mi
+e2sol
+es3olu
+e2son
+es5ona
+e1sp
+es3per
+es5pira
+es4pre
+2ess
+es4si4b
+estan4
+es3tig
+es5tim
+4es2to
+e3ston
+2estr
+e5stro
+estruc5
+e2sur
+es5urr
+es4w
+eta4b
+eten4d
+e3teo
+ethod3
+et1ic
+e5tide
+etin4
+eti4no
+e5tir
+e5titio
+et5itiv
+4etn
+et5ona
+e3tra
+e3tre
+et3ric
+et5rif
+et3rog
+et5ros
+et3ua
+et5ym
+et5z
+4eu
+e5un
+e3up
+eu3ro
+eus4
+eute4
+euti5l
+eu5tr
+eva2p5
+e2vas
+ev5ast
+e5vea
+ev3ell
+evel3o
+e5veng
+even4i
+ev1er
+e5verb
+e1vi
+ev3id
+evi4l
+e4vin
+evi4v
+e5voc
+e5vu
+e1wa
+e4wag
+e5wee
+e3wh
+ewil5
+ew3ing
+e3wit
+1exp
+5eyc
+5eye.
+eys4
+1fa
+fa3bl
+fab3r
+fa4ce
+4fag
+fain4
+fall5e
+4fa4ma
+fam5is
+5far
+far5th
+fa3ta
+fa3the
+4fato
+fault5
+4f5b
+4fd
+4fe.
+feas4
+feath3
+fe4b
+4feca
+5fect
+2fed
+fe3li
+fe4mo
+fen2d
+fend5e
+fer1
+5ferr
+fev4
+4f1f
+f4fes
+f4fie
+f5fin.
+f2f5is
+f4fly
+f2fy
+4fh
+1fi
+fi3a
+2f3ic.
+4f3ical
+f3ican
+4ficate
+f3icen
+fi3cer
+fic4i
+5ficia
+5ficie
+4fics
+fi3cu
+fi5del
+fight5
+fil5i
+fill5in
+4fily
+2fin
+5fina
+fin2d5
+fi2ne
+f1in3g
+fin4n
+fis4ti
+f4l2
+f5less
+flin4
+flo3re
+f2ly5
+4fm
+4fn
+1fo
+5fon
+fon4de
+fon4t
+fo2r
+fo5rat
+for5ay
+fore5t
+for4i
+fort5a
+fos5
+4f5p
+fra4t
+f5rea
+fres5c
+fri2
+fril4
+frol5
+2f3s
+2ft
+f4to
+f2ty
+3fu
+fu5el
+4fug
+fu4min
+fu5ne
+fu3ri
+fusi4
+fus4s
+4futa
+1fy
+1ga
+gaf4
+5gal.
+3gali
+ga3lo
+2gam
+ga5met
+g5amo
+gan5is
+ga3niz
+gani5za
+4gano
+gar5n4
+gass4
+gath3
+4gativ
+4gaz
+g3b
+gd4
+2ge.
+2ged
+geez4
+gel4in
+ge5lis
+ge5liz
+4gely
+1gen
+ge4nat
+ge5niz
+4geno
+4geny
+1geo
+ge3om
+g4ery
+5gesi
+geth5
+4geto
+ge4ty
+ge4v
+4g1g2
+g2ge
+g3ger
+gglu5
+ggo4
+gh3in
+gh5out
+gh4to
+5gi.
+1gi4a
+gia5r
+g1ic
+5gicia
+g4ico
+gien5
+5gies.
+gil4
+g3imen
+3g4in.
+gin5ge
+5g4ins
+5gio
+3gir
+gir4l
+g3isl
+gi4u
+5giv
+3giz
+gl2
+gla4
+glad5i
+5glas
+1gle
+gli4b
+g3lig
+3glo
+glo3r
+g1m
+g4my
+gn4a
+g4na.
+gnet4t
+g1ni
+g2nin
+g4nio
+g1no
+g4non
+1go
+3go.
+gob5
+5goe
+3g4o4g
+go3is
+gon2
+4g3o3na
+gondo5
+go3ni
+5goo
+go5riz
+gor5ou
+5gos.
+gov1
+g3p
+1gr
+4grada
+g4rai
+gran2
+5graph.
+g5rapher
+5graphic
+4graphy
+4gray
+gre4n
+4gress.
+4grit
+g4ro
+gruf4
+gs2
+g5ste
+gth3
+gu4a
+3guard
+2gue
+5gui5t
+3gun
+3gus
+4gu4t
+g3w
+1gy
+2g5y3n
+gy5ra
+h3ab4l
+hach4
+hae4m
+hae4t
+h5agu
+ha3la
+hala3m
+ha4m
+han4ci
+han4cy
+5hand.
+han4g
+hang5er
+hang5o
+h5a5niz
+han4k
+han4te
+hap3l
+hap5t
+ha3ran
+ha5ras
+har2d
+hard3e
+har4le
+harp5en
+har5ter
+has5s
+haun4
+5haz
+haz3a
+h1b
+1head
+3hear
+he4can
+h5ecat
+h4ed
+he5do5
+he3l4i
+hel4lis
+hel4ly
+h5elo
+hem4p
+he2n
+hena4
+hen5at
+heo5r
+hep5
+h4era
+hera3p
+her4ba
+here5a
+h3ern
+h5erou
+h3ery
+h1es
+he2s5p
+he4t
+het4ed
+heu4
+h1f
+h1h
+hi5an
+hi4co
+high5
+h4il2
+himer4
+h4ina
+hion4e
+hi4p
+hir4l
+hi3ro
+hir4p
+hir4r
+his3el
+his4s
+hith5er
+hi2v
+4hk
+4h1l4
+hlan4
+h2lo
+hlo3ri
+4h1m
+hmet4
+2h1n
+h5odiz
+h5ods
+ho4g
+hoge4
+hol5ar
+3hol4e
+ho4ma
+home3
+hon4a
+ho5ny
+3hood
+hoon4
+hor5at
+ho5ris
+hort3e
+ho5ru
+hos4e
+ho5sen
+hos1p
+1hous
+house3
+hov5el
+4h5p
+4hr4
+hree5
+hro5niz
+hro3po
+4h1s2
+h4sh
+h4tar
+ht1en
+ht5es
+h4ty
+hu4g
+hu4min
+hun5ke
+hun4t
+hus3t4
+hu4t
+h1w
+h4wart
+hy3pe
+hy3ph
+hy2s
+2i1a
+i2al
+iam4
+iam5ete
+i2an
+4ianc
+ian3i
+4ian4t
+ia5pe
+iass4
+i4ativ
+ia4tric
+i4atu
+ibe4
+ib3era
+ib5ert
+ib5ia
+ib3in
+ib5it.
+ib5ite
+i1bl
+ib3li
+i5bo
+i1br
+i2b5ri
+i5bun
+4icam
+5icap
+4icar
+i4car.
+i4cara
+icas5
+i4cay
+iccu4
+4iceo
+4ich
+2ici
+i5cid
+ic5ina
+i2cip
+ic3ipa
+i4cly
+i2c5oc
+4i1cr
+5icra
+i4cry
+ic4te
+ictu2
+ic4t3ua
+ic3ula
+ic4um
+ic5uo
+i3cur
+2id
+i4dai
+id5anc
+id5d
+ide3al
+ide4s
+i2di
+id5ian
+idi4ar
+i5die
+id3io
+idi5ou
+id1it
+id5iu
+i3dle
+i4dom
+id3ow
+i4dr
+i2du
+id5uo
+2ie4
+ied4e
+5ie5ga
+ield3
+ien5a4
+ien4e
+i5enn
+i3enti
+i1er.
+i3esc
+i1est
+i3et
+4if.
+if5ero
+iff5en
+if4fr
+4ific.
+i3fie
+i3fl
+4ift
+2ig
+iga5b
+ig3era
+ight3i
+4igi
+i3gib
+ig3il
+ig3in
+ig3it
+i4g4l
+i2go
+ig3or
+ig5ot
+i5gre
+igu5i
+ig1ur
+i3h
+4i5i4
+i3j
+4ik
+i1la
+il3a4b
+i4lade
+i2l5am
+ila5ra
+i3leg
+il1er
+ilev4
+il5f
+il1i
+il3ia
+il2ib
+il3io
+il4ist
+2ilit
+il2iz
+ill5ab
+4iln
+il3oq
+il4ty
+il5ur
+il3v
+i4mag
+im3age
+ima5ry
+imenta5r
+4imet
+im1i
+im5ida
+imi5le
+i5mini
+4imit
+im4ni
+i3mon
+i2mu
+im3ula
+2in.
+i4n3au
+4inav
+incel4
+in3cer
+4ind
+in5dling
+2ine
+i3nee
+iner4ar
+i5ness
+4inga
+4inge
+in5gen
+4ingi
+in5gling
+4ingo
+4ingu
+2ini
+i5ni.
+i4nia
+in3io
+in1is
+i5nite.
+5initio
+in3ity
+4ink
+4inl
+2inn
+2i1no
+i4no4c
+ino4s
+i4not
+2ins
+in3se
+insur5a
+2int.
+2in4th
+in1u
+i5nus
+4iny
+2io
+4io.
+ioge4
+io2gr
+i1ol
+io4m
+ion3at
+ion4ery
+ion3i
+io5ph
+ior3i
+i4os
+io5th
+i5oti
+io4to
+i4our
+2ip
+ipe4
+iphras4
+ip3i
+ip4ic
+ip4re4
+ip3ul
+i3qua
+iq5uef
+iq3uid
+iq3ui3t
+4ir
+i1ra
+ira4b
+i4rac
+ird5e
+ire4de
+i4ref
+i4rel4
+i4res
+ir5gi
+ir1i
+iri5de
+ir4is
+iri3tu
+5i5r2iz
+ir4min
+iro4g
+5iron.
+ir5ul
+2is.
+is5ag
+is3ar
+isas5
+2is1c
+is3ch
+4ise
+is3er
+3isf
+is5han
+is3hon
+ish5op
+is3ib
+isi4d
+i5sis
+is5itiv
+4is4k
+islan4
+4isms
+i2so
+iso5mer
+is1p
+is2pi
+is4py
+4is1s
+is4sal
+issen4
+is4ses
+is4ta.
+is1te
+is1ti
+ist4ly
+4istral
+i2su
+is5us
+4ita.
+ita4bi
+i4tag
+4ita5m
+i3tan
+i3tat
+2ite
+it3era
+i5teri
+it4es
+2ith
+i1ti
+4itia
+4i2tic
+it3ica
+5i5tick
+it3ig
+it5ill
+i2tim
+2itio
+4itis
+i4tism
+i2t5o5m
+4iton
+i4tram
+it5ry
+4itt
+it3uat
+i5tud
+it3ul
+4itz.
+i1u
+2iv
+iv3ell
+iv3en.
+i4v3er.
+i4vers.
+iv5il.
+iv5io
+iv1it
+i5vore
+iv3o3ro
+i4v3ot
+4i5w
+ix4o
+4iy
+4izar
+izi4
+5izont
+5ja
+jac4q
+ja4p
+1je
+jer5s
+4jestie
+4jesty
+jew3
+jo4p
+5judg
+3ka.
+k3ab
+k5ag
+kais4
+kal4
+k1b
+k2ed
+1kee
+ke4g
+ke5li
+k3en4d
+k1er
+kes4
+k3est.
+ke4ty
+k3f
+kh4
+k1i
+5ki.
+5k2ic
+k4ill
+kilo5
+k4im
+k4in.
+kin4de
+k5iness
+kin4g
+ki4p
+kis4
+k5ish
+kk4
+k1l
+4kley
+4kly
+k1m
+k5nes
+1k2no
+ko5r
+kosh4
+k3ou
+kro5n
+4k1s2
+k4sc
+ks4l
+k4sy
+k5t
+k1w
+lab3ic
+l4abo
+laci4
+l4ade
+la3dy
+lag4n
+lam3o
+3land
+lan4dl
+lan5et
+lan4te
+lar4g
+lar3i
+las4e
+la5tan
+4lateli
+4lativ
+4lav
+la4v4a
+2l1b
+lbin4
+4l1c2
+lce4
+l3ci
+2ld
+l2de
+ld4ere
+ld4eri
+ldi4
+ld5is
+l3dr
+l4dri
+le2a
+le4bi
+left5
+5leg.
+5legg
+le4mat
+lem5atic
+4len.
+3lenc
+5lene.
+1lent
+le3ph
+le4pr
+lera5b
+ler4e
+3lerg
+3l4eri
+l4ero
+les2
+le5sco
+5lesq
+3less
+5less.
+l3eva
+lev4er.
+lev4era
+lev4ers
+3ley
+4leye
+2lf
+l5fr
+4l1g4
+l5ga
+lgar3
+l4ges
+lgo3
+2l3h
+li4ag
+li2am
+liar5iz
+li4as
+li4ato
+li5bi
+5licio
+li4cor
+4lics
+4lict.
+l4icu
+l3icy
+l3ida
+lid5er
+3lidi
+lif3er
+l4iff
+li4fl
+5ligate
+3ligh
+li4gra
+3lik
+4l4i4l
+lim4bl
+lim3i
+li4mo
+l4im4p
+l4ina
+1l4ine
+lin3ea
+lin3i
+link5er
+li5og
+4l4iq
+lis4p
+l1it
+l2it.
+5litica
+l5i5tics
+liv3er
+l1iz
+4lj
+lka3
+l3kal
+lka4t
+l1l
+l4law
+l2le
+l5lea
+l3lec
+l3leg
+l3lel
+l3le4n
+l3le4t
+ll2i
+l2lin4
+l5lina
+ll4o
+lloqui5
+ll5out
+l5low
+2lm
+l5met
+lm3ing
+l4mod
+lmon4
+2l1n2
+3lo.
+lob5al
+lo4ci
+4lof
+3logic
+l5ogo
+3logu
+lom3er
+5long
+lon4i
+l3o3niz
+lood5
+5lope.
+lop3i
+l3opm
+lora4
+lo4rato
+lo5rie
+lor5ou
+5los.
+los5et
+5losophiz
+5losophy
+los4t
+lo4ta
+loun5d
+2lout
+4lov
+2lp
+lpa5b
+l3pha
+l5phi
+lp5ing
+l3pit
+l4pl
+l5pr
+4l1r
+2l1s2
+l4sc
+l2se
+l4sie
+4lt
+lt5ag
+ltane5
+l1te
+lten4
+ltera4
+lth3i
+l5ties.
+ltis4
+l1tr
+ltu2
+ltur3a
+lu5a
+lu3br
+luch4
+lu3ci
+lu3en
+luf4
+lu5id
+lu4ma
+5lumi
+l5umn.
+5lumnia
+lu3o
+luo3r
+4lup
+luss4
+lus3te
+1lut
+l5ven
+l5vet4
+2l1w
+1ly
+4lya
+4lyb
+ly5me
+ly3no
+2lys4
+l5yse
+1ma
+2mab
+ma2ca
+ma5chine
+ma4cl
+mag5in
+5magn
+2mah
+maid5
+4mald
+ma3lig
+ma5lin
+mal4li
+mal4ty
+5mania
+man5is
+man3iz
+4map
+ma5rine.
+ma5riz
+mar4ly
+mar3v
+ma5sce
+mas4e
+mas1t
+5mate
+math3
+ma3tis
+4matiza
+4m1b
+mba4t5
+m5bil
+m4b3ing
+mbi4v
+4m5c
+4me.
+2med
+4med.
+5media
+me3die
+m5e5dy
+me2g
+mel5on
+mel4t
+me2m
+mem1o3
+1men
+men4a
+men5ac
+men4de
+4mene
+men4i
+mens4
+mensu5
+3ment
+men4te
+me5on
+m5ersa
+2mes
+3mesti
+me4ta
+met3al
+me1te
+me5thi
+m4etr
+5metric
+me5trie
+me3try
+me4v
+4m1f
+2mh
+5mi.
+mi3a
+mid4a
+mid4g
+mig4
+3milia
+m5i5lie
+m4ill
+min4a
+3mind
+m5inee
+m4ingl
+min5gli
+m5ingly
+min4t
+m4inu
+miot4
+m2is
+mis4er.
+mis5l
+mis4ti
+m5istry
+4mith
+m2iz
+4mk
+4m1l
+m1m
+mma5ry
+4m1n
+mn4a
+m4nin
+mn4o
+1mo
+4mocr
+5mocratiz
+mo2d1
+mo4go
+mois2
+moi5se
+4mok
+mo5lest
+mo3me
+mon5et
+mon5ge
+moni3a
+mon4ism
+mon4ist
+mo3niz
+monol4
+mo3ny.
+mo2r
+4mora.
+mos2
+mo5sey
+mo3sp
+moth3
+m5ouf
+3mous
+mo2v
+4m1p
+mpara5
+mpa5rab
+mpar5i
+m3pet
+mphas4
+m2pi
+mpi4a
+mp5ies
+m4p1in
+m5pir
+mp5is
+mpo3ri
+mpos5ite
+m4pous
+mpov5
+mp4tr
+m2py
+4m3r
+4m1s2
+m4sh
+m5si
+4mt
+1mu
+mula5r4
+5mult
+multi3
+3mum
+mun2
+4mup
+mu4u
+4mw
+1na
+2n1a2b
+n4abu
+4nac.
+na4ca
+n5act
+nag5er.
+nak4
+na4li
+na5lia
+4nalt
+na5mit
+n2an
+nanci4
+nan4it
+nank4
+nar3c
+4nare
+nar3i
+nar4l
+n5arm
+n4as
+nas4c
+nas5ti
+n2at
+na3tal
+nato5miz
+n2au
+nau3se
+3naut
+nav4e
+4n1b4
+ncar5
+n4ces.
+n3cha
+n5cheo
+n5chil
+n3chis
+nc1in
+nc4it
+ncour5a
+n1cr
+n1cu
+n4dai
+n5dan
+n1de
+nd5est.
+ndi4b
+n5d2if
+n1dit
+n3diz
+n5duc
+ndu4r
+nd2we
+2ne.
+n3ear
+ne2b
+neb3u
+ne2c
+5neck
+2ned
+ne4gat
+neg5ativ
+5nege
+ne4la
+nel5iz
+ne5mi
+ne4mo
+1nen
+4nene
+3neo
+ne4po
+ne2q
+n1er
+nera5b
+n4erar
+n2ere
+n4er5i
+ner4r
+1nes
+2nes.
+4nesp
+2nest
+4nesw
+3netic
+ne4v
+n5eve
+ne4w
+n3f
+n4gab
+n3gel
+nge4n4e
+n5gere
+n3geri
+ng5ha
+n3gib
+ng1in
+n5git
+n4gla
+ngov4
+ng5sh
+n1gu
+n4gum
+n2gy
+4n1h4
+nha4
+nhab3
+nhe4
+3n4ia
+ni3an
+ni4ap
+ni3ba
+ni4bl
+ni4d
+ni5di
+ni4er
+ni2fi
+ni5ficat
+n5igr
+nik4
+n1im
+ni3miz
+n1in
+5nine.
+nin4g
+ni4o
+5nis.
+nis4ta
+n2it
+n4ith
+3nitio
+n3itor
+ni3tr
+n1j
+4nk2
+n5kero
+n3ket
+nk3in
+n1kl
+4n1l
+n5m
+nme4
+nmet4
+4n1n2
+nne4
+nni3al
+nni4v
+nob4l
+no3ble
+n5ocl
+4n3o2d
+3noe
+4nog
+noge4
+nois5i
+no5l4i
+5nologis
+3nomic
+n5o5miz
+no4mo
+no3my
+no4n
+non4ag
+non5i
+n5oniz
+4nop
+5nop5o5li
+nor5ab
+no4rary
+4nosc
+nos4e
+nos5t
+no5ta
+1nou
+3noun
+nov3el3
+nowl3
+n1p4
+npi4
+npre4c
+n1q
+n1r
+nru4
+2n1s2
+ns5ab
+nsati4
+ns4c
+n2se
+n4s3es
+nsid1
+nsig4
+n2sl
+ns3m
+n4soc
+ns4pe
+n5spi
+nsta5bl
+n1t
+nta4b
+nter3s
+nt2i
+n5tib
+nti4er
+nti2f
+n3tine
+n4t3ing
+nti4p
+ntrol5li
+nt4s
+ntu3me
+nu1a
+nu4d
+nu5en
+nuf4fe
+n3uin
+3nu3it
+n4um
+nu1me
+n5umi
+3nu4n
+n3uo
+nu3tr
+n1v2
+n1w4
+nym4
+nyp4
+4nz
+n3za
+4oa
+oad3
+o5a5les
+oard3
+oas4e
+oast5e
+oat5i
+ob3a3b
+o5bar
+obe4l
+o1bi
+o2bin
+ob5ing
+o3br
+ob3ul
+o1ce
+och4
+o3chet
+ocif3
+o4cil
+o4clam
+o4cod
+oc3rac
+oc5ratiz
+ocre3
+5ocrit
+octor5a
+oc3ula
+o5cure
+od5ded
+od3ic
+odi3o
+o2do4
+odor3
+od5uct.
+od5ucts
+o4el
+o5eng
+o3er
+oe4ta
+o3ev
+o2fi
+of5ite
+ofit4t
+o2g5a5r
+og5ativ
+o4gato
+o1ge
+o5gene
+o5geo
+o4ger
+o3gie
+1o1gis
+og3it
+o4gl
+o5g2ly
+3ogniz
+o4gro
+ogu5i
+1ogy
+2ogyn
+o1h2
+ohab5
+oi2
+oic3es
+oi3der
+oiff4
+oig4
+oi5let
+o3ing
+oint5er
+o5ism
+oi5son
+oist5en
+oi3ter
+o5j
+2ok
+o3ken
+ok5ie
+o1la
+o4lan
+olass4
+ol2d
+old1e
+ol3er
+o3lesc
+o3let
+ol4fi
+ol2i
+o3lia
+o3lice
+ol5id.
+o3li4f
+o5lil
+ol3ing
+o5lio
+o5lis.
+ol3ish
+o5lite
+o5litio
+o5liv
+olli4e
+ol5ogiz
+olo4r
+ol5pl
+ol2t
+ol3ub
+ol3ume
+ol3un
+o5lus
+ol2v
+o2ly
+om5ah
+oma5l
+om5atiz
+om2be
+om4bl
+o2me
+om3ena
+om5erse
+o4met
+om5etry
+o3mia
+om3ic.
+om3ica
+o5mid
+om1in
+o5mini
+5ommend
+omo4ge
+o4mon
+om3pi
+ompro5
+o2n
+on1a
+on4ac
+o3nan
+on1c
+3oncil
+2ond
+on5do
+o3nen
+on5est
+on4gu
+on1ic
+o3nio
+on1is
+o5niu
+on3key
+on4odi
+on3omy
+on3s
+onspi4
+onspir5a
+onsu4
+onten4
+on3t4i
+ontif5
+on5um
+onva5
+oo2
+ood5e
+ood5i
+oo4k
+oop3i
+o3ord
+oost5
+o2pa
+ope5d
+op1er
+3opera
+4operag
+2oph
+o5phan
+o5pher
+op3ing
+o3pit
+o5pon
+o4posi
+o1pr
+op1u
+opy5
+o1q
+o1ra
+o5ra.
+o4r3ag
+or5aliz
+or5ange
+ore5a
+o5real
+or3ei
+ore5sh
+or5est.
+orew4
+or4gu
+4o5ria
+or3ica
+o5ril
+or1in
+o1rio
+or3ity
+o3riu
+or2mi
+orn2e
+o5rof
+or3oug
+or5pe
+3orrh
+or4se
+ors5en
+orst4
+or3thi
+or3thy
+or4ty
+o5rum
+o1ry
+os3al
+os2c
+os4ce
+o3scop
+4oscopi
+o5scr
+os4i4e
+os5itiv
+os3ito
+os3ity
+osi4u
+os4l
+o2so
+os4pa
+os4po
+os2ta
+o5stati
+os5til
+os5tit
+o4tan
+otele4g
+ot3er.
+ot5ers
+o4tes
+4oth
+oth5esi
+oth3i4
+ot3ic.
+ot5ica
+o3tice
+o3tif
+o3tis
+oto5s
+ou2
+ou3bl
+ouch5i
+ou5et
+ou4l
+ounc5er
+oun2d
+ou5v
+ov4en
+over4ne
+over3s
+ov4ert
+o3vis
+oviti4
+o5v4ol
+ow3der
+ow3el
+ow5est
+ow1i
+own5i
+o4wo
+oy1a
+1pa
+pa4ca
+pa4ce
+pac4t
+p4ad
+5pagan
+p3agat
+p4ai
+pain4
+p4al
+pan4a
+pan3el
+pan4ty
+pa3ny
+pa1p
+pa4pu
+para5bl
+par5age
+par5di
+3pare
+par5el
+p4a4ri
+par4is
+pa2te
+pa5ter
+5pathic
+pa5thy
+pa4tric
+pav4
+3pay
+4p1b
+pd4
+4pe.
+3pe4a
+pear4l
+pe2c
+2p2ed
+3pede
+3pedi
+pedia4
+ped4ic
+p4ee
+pee4d
+pek4
+pe4la
+peli4e
+pe4nan
+p4enc
+pen4th
+pe5on
+p4era.
+pera5bl
+p4erag
+p4eri
+peri5st
+per4mal
+perme5
+p4ern
+per3o
+per3ti
+pe5ru
+per1v
+pe2t
+pe5ten
+pe5tiz
+4pf
+4pg
+4ph.
+phar5i
+phe3no
+ph4er
+ph4es.
+ph1ic
+5phie
+ph5ing
+5phisti
+3phiz
+ph2l
+3phob
+3phone
+5phoni
+pho4r
+4phs
+ph3t
+5phu
+1phy
+pi3a
+pian4
+pi4cie
+pi4cy
+p4id
+p5ida
+pi3de
+5pidi
+3piec
+pi3en
+pi4grap
+pi3lo
+pi2n
+p4in.
+pind4
+p4ino
+3pi1o
+pion4
+p3ith
+pi5tha
+pi2tu
+2p3k2
+1p2l2
+3plan
+plas5t
+pli3a
+pli5er
+4plig
+pli4n
+ploi4
+plu4m
+plum4b
+4p1m
+2p3n
+po4c
+5pod.
+po5em
+po3et5
+5po4g
+poin2
+5point
+poly5t
+po4ni
+po4p
+1p4or
+po4ry
+1pos
+pos1s
+p4ot
+po4ta
+5poun
+4p1p
+ppa5ra
+p2pe
+p4ped
+p5pel
+p3pen
+p3per
+p3pet
+ppo5site
+pr2
+pray4e
+5preci
+pre5co
+pre3em
+pref5ac
+pre4la
+pre3r
+p3rese
+3press
+pre5ten
+pre3v
+5pri4e
+prin4t3
+pri4s
+pris3o
+p3roca
+prof5it
+pro3l
+pros3e
+pro1t
+2p1s2
+p2se
+ps4h
+p4sib
+2p1t
+pt5a4b
+p2te
+p2th
+pti3m
+ptu4r
+p4tw
+pub3
+pue4
+puf4
+pul3c
+pu4m
+pu2n
+pur4r
+5pus
+pu2t
+5pute
+put3er
+pu3tr
+put4ted
+put4tin
+p3w
+qu2
+qua5v
+2que.
+3quer
+3quet
+2rab
+ra3bi
+rach4e
+r5acl
+raf5fi
+raf4t
+r2ai
+ra4lo
+ram3et
+r2ami
+rane5o
+ran4ge
+r4ani
+ra5no
+rap3er
+3raphy
+rar5c
+rare4
+rar5ef
+4raril
+r2as
+ration4
+rau4t
+ra5vai
+rav3el
+ra5zie
+r1b
+r4bab
+r4bag
+rbi2
+rbi4f
+r2bin
+r5bine
+rb5ing.
+rb4o
+r1c
+r2ce
+rcen4
+r3cha
+rch4er
+r4ci4b
+rc4it
+rcum3
+r4dal
+rd2i
+rdi4a
+rdi4er
+rdin4
+rd3ing
+2re.
+re1al
+re3an
+re5arr
+5reav
+re4aw
+r5ebrat
+rec5oll
+rec5ompe
+re4cre
+2r2ed
+re1de
+re3dis
+red5it
+re4fac
+re2fe
+re5fer.
+re3fi
+re4fy
+reg3is
+re5it
+re1li
+re5lu
+r4en4ta
+ren4te
+re1o
+re5pin
+re4posi
+re1pu
+r1er4
+r4eri
+rero4
+re5ru
+r4es.
+re4spi
+ress5ib
+res2t
+re5stal
+re3str
+re4ter
+re4ti4z
+re3tri
+reu2
+re5uti
+rev2
+re4val
+rev3el
+r5ev5er.
+re5vers
+re5vert
+re5vil
+rev5olu
+re4wh
+r1f
+rfu4
+r4fy
+rg2
+rg3er
+r3get
+r3gic
+rgi4n
+rg3ing
+r5gis
+r5git
+r1gl
+rgo4n
+r3gu
+rh4
+4rh.
+4rhal
+ri3a
+ria4b
+ri4ag
+r4ib
+rib3a
+ric5as
+r4ice
+4rici
+5ricid
+ri4cie
+r4ico
+rid5er
+ri3enc
+ri3ent
+ri1er
+ri5et
+rig5an
+5rigi
+ril3iz
+5riman
+rim5i
+3rimo
+rim4pe
+r2ina
+5rina.
+rin4d
+rin4e
+rin4g
+ri1o
+5riph
+riph5e
+ri2pl
+rip5lic
+r4iq
+r2is
+r4is.
+ris4c
+r3ish
+ris4p
+ri3ta3b
+r5ited.
+rit5er.
+rit5ers
+rit3ic
+ri2tu
+rit5ur
+riv5el
+riv3et
+riv3i
+r3j
+r3ket
+rk4le
+rk4lin
+r1l
+rle4
+r2led
+r4lig
+r4lis
+rl5ish
+r3lo4
+r1m
+rma5c
+r2me
+r3men
+rm5ers
+rm3ing
+r4ming.
+r4mio
+r3mit
+r4my
+r4nar
+r3nel
+r4ner
+r5net
+r3ney
+r5nic
+r1nis4
+r3nit
+r3niv
+rno4
+r4nou
+r3nu
+rob3l
+r2oc
+ro3cr
+ro4e
+ro1fe
+ro5fil
+rok2
+ro5ker
+5role.
+rom5ete
+rom4i
+rom4p
+ron4al
+ron4e
+ro5n4is
+ron4ta
+1room
+5root
+ro3pel
+rop3ic
+ror3i
+ro5ro
+ros5per
+ros4s
+ro4the
+ro4ty
+ro4va
+rov5el
+rox5
+r1p
+r4pea
+r5pent
+rp5er.
+r3pet
+rp4h4
+rp3ing
+r3po
+r1r4
+rre4c
+rre4f
+r4reo
+rre4st
+rri4o
+rri4v
+rron4
+rros4
+rrys4
+4rs2
+r1sa
+rsa5ti
+rs4c
+r2se
+r3sec
+rse4cr
+rs5er.
+rs3es
+rse5v2
+r1sh
+r5sha
+r1si
+r4si4b
+rson3
+r1sp
+r5sw
+rtach4
+r4tag
+r3teb
+rten4d
+rte5o
+r1ti
+rt5ib
+rti4d
+r4tier
+r3tig
+rtil3i
+rtil4l
+r4tily
+r4tist
+r4tiv
+r3tri
+rtroph4
+rt4sh
+ru3a
+ru3e4l
+ru3en
+ru4gl
+ru3in
+rum3pl
+ru2n
+runk5
+run4ty
+r5usc
+ruti5n
+rv4e
+rvel4i
+r3ven
+rv5er.
+r5vest
+r3vey
+r3vic
+rvi4v
+r3vo
+r1w
+ry4c
+5rynge
+ry3t
+sa2
+2s1ab
+5sack
+sac3ri
+s3act
+5sai
+salar4
+sal4m
+sa5lo
+sal4t
+3sanc
+san4de
+s1ap
+sa5ta
+5sa3tio
+sat3u
+sau4
+sa5vor
+5saw
+4s5b
+scan4t5
+sca4p
+scav5
+s4ced
+4scei
+s4ces
+sch2
+s4cho
+3s4cie
+5scin4d
+scle5
+s4cli
+scof4
+4scopy
+scour5a
+s1cu
+4s5d
+4se.
+se4a
+seas4
+sea5w
+se2c3o
+3sect
+4s4ed
+se4d4e
+s5edl
+se2g
+seg3r
+5sei
+se1le
+5self
+5selv
+4seme
+se4mol
+sen5at
+4senc
+sen4d
+s5ened
+sen5g
+s5enin
+4sentd
+4sentl
+sep3a3
+4s1er.
+s4erl
+ser4o
+4servo
+s1e4s
+se5sh
+ses5t
+5se5um
+5sev
+sev3en
+sew4i
+5sex
+4s3f
+2s3g
+s2h
+2sh.
+sh1er
+5shev
+sh1in
+sh3io
+3ship
+shiv5
+sho4
+sh5old
+shon3
+shor4
+short5
+4shw
+si1b
+s5icc
+3side.
+5sides
+5sidi
+si5diz
+4signa
+sil4e
+4sily
+2s1in
+s2ina
+5sine.
+s3ing
+1sio
+5sion
+sion5a
+si2r
+sir5a
+1sis
+3sitio
+5siu
+1siv
+5siz
+sk2
+4ske
+s3ket
+sk5ine
+sk5ing
+s1l2
+s3lat
+s2le
+slith5
+2s1m
+s3ma
+small3
+sman3
+smel4
+s5men
+5smith
+smol5d4
+s1n4
+1so
+so4ce
+soft3
+so4lab
+sol3d2
+so3lic
+5solv
+3som
+3s4on.
+sona4
+son4g
+s4op
+5sophic
+s5ophiz
+s5ophy
+sor5c
+sor5d
+4sov
+so5vi
+2spa
+5spai
+spa4n
+spen4d
+2s5peo
+2sper
+s2phe
+3spher
+spho5
+spil4
+sp5ing
+4spio
+s4ply
+s4pon
+spor4
+4spot
+squal4l
+s1r
+2ss
+s1sa
+ssas3
+s2s5c
+s3sel
+s5seng
+s4ses.
+s5set
+s1si
+s4sie
+ssi4er
+ss5ily
+s4sl
+ss4li
+s4sn
+sspend4
+ss2t
+ssur5a
+ss5w
+2st.
+s2tag
+s2tal
+stam4i
+5stand
+s4ta4p
+5stat.
+s4ted
+stern5i
+s5tero
+ste2w
+stew5a
+s3the
+st2i
+s4ti.
+s5tia
+s1tic
+5stick
+s4tie
+s3tif
+st3ing
+5stir
+s1tle
+5stock
+stom3a
+5stone
+s4top
+3store
+st4r
+s4trad
+5stratu
+s4tray
+s4trid
+4stry
+4st3w
+s2ty
+1su
+su1al
+su4b3
+su2g3
+su5is
+suit3
+s4ul
+su2m
+sum3i
+su2n
+su2r
+4sv
+sw2
+4swo
+s4y
+4syc
+3syl
+syn5o
+sy5rin
+1ta
+3ta.
+2tab
+ta5bles
+5taboliz
+4taci
+ta5do
+4taf4
+tai5lo
+ta2l
+ta5la
+tal5en
+tal3i
+4talk
+tal4lis
+ta5log
+ta5mo
+tan4de
+tanta3
+ta5per
+ta5pl
+tar4a
+4tarc
+4tare
+ta3riz
+tas4e
+ta5sy
+4tatic
+ta4tur
+taun4
+tav4
+2taw
+tax4is
+2t1b
+4tc
+t4ch
+tch5et
+4t1d
+4te.
+tead4i
+4teat
+tece4
+5tect
+2t1ed
+te5di
+1tee
+teg4
+te5ger
+te5gi
+3tel.
+teli4
+5tels
+te2ma2
+tem3at
+3tenan
+3tenc
+3tend
+4tenes
+1tent
+ten4tag
+1teo
+te4p
+te5pe
+ter3c
+5ter3d
+1teri
+ter5ies
+ter3is
+teri5za
+5ternit
+ter5v
+4tes.
+4tess
+t3ess.
+teth5e
+3teu
+3tex
+4tey
+2t1f
+4t1g
+2th.
+than4
+th2e
+4thea
+th3eas
+the5at
+the3is
+3thet
+th5ic.
+th5ica
+4thil
+5think
+4thl
+th5ode
+5thodic
+4thoo
+thor5it
+tho5riz
+2ths
+1tia
+ti4ab
+ti4ato
+2ti2b
+4tick
+t4ico
+t4ic1u
+5tidi
+3tien
+tif2
+ti5fy
+2tig
+5tigu
+till5in
+1tim
+4timp
+tim5ul
+2t1in
+t2ina
+3tine.
+3tini
+1tio
+ti5oc
+tion5ee
+5tiq
+ti3sa
+3tise
+tis4m
+ti5so
+tis4p
+5tistica
+ti3tl
+ti4u
+1tiv
+tiv4a
+1tiz
+ti3za
+ti3zen
+2tl
+t5la
+tlan4
+3tle.
+3tled
+3tles.
+t5let.
+t5lo
+4t1m
+tme4
+2t1n2
+1to
+to3b
+to5crat
+4todo
+2tof
+to2gr
+to5ic
+to2ma
+tom4b
+to3my
+ton4ali
+to3nat
+4tono
+4tony
+to2ra
+to3rie
+tor5iz
+tos2
+5tour
+4tout
+to3war
+4t1p
+1tra
+tra3b
+tra5ch
+traci4
+trac4it
+trac4te
+tras4
+tra5ven
+trav5es5
+tre5f
+tre4m
+trem5i
+5tria
+tri5ces
+5tricia
+4trics
+2trim
+tri4v
+tro5mi
+tron5i
+4trony
+tro5phe
+tro3sp
+tro3v
+tru5i
+trus4
+4t1s2
+t4sc
+tsh4
+t4sw
+4t3t2
+t4tes
+t5to
+ttu4
+1tu
+tu1a
+tu3ar
+tu4bi
+tud2
+4tue
+4tuf4
+5tu3i
+3tum
+tu4nis
+2t3up.
+3ture
+5turi
+tur3is
+tur5o
+tu5ry
+3tus
+4tv
+tw4
+4t1wa
+twis4
+4two
+1ty
+4tya
+2tyl
+type3
+ty5ph
+4tz
+tz4e
+4uab
+uac4
+ua5na
+uan4i
+uar5ant
+uar2d
+uar3i
+uar3t
+u1at
+uav4
+ub4e
+u4bel
+u3ber
+u4bero
+u1b4i
+u4b5ing
+u3ble.
+u3ca
+uci4b
+uc4it
+ucle3
+u3cr
+u3cu
+u4cy
+ud5d
+ud3er
+ud5est
+udev4
+u1dic
+ud3ied
+ud3ies
+ud5is
+u5dit
+u4don
+ud4si
+u4du
+u4ene
+uens4
+uen4te
+uer4il
+3ufa
+u3fl
+ugh3en
+ug5in
+2ui2
+uil5iz
+ui4n
+u1ing
+uir4m
+uita4
+uiv3
+uiv4er.
+u5j
+4uk
+u1la
+ula5b
+u5lati
+ulch4
+5ulche
+ul3der
+ul4e
+u1len
+ul4gi
+ul2i
+u5lia
+ul3ing
+ul5ish
+ul4lar
+ul4li4b
+ul4lis
+4ul3m
+u1l4o
+4uls
+uls5es
+ul1ti
+ultra3
+4ultu
+u3lu
+ul5ul
+ul5v
+um5ab
+um4bi
+um4bly
+u1mi
+u4m3ing
+umor5o
+um2p
+unat4
+u2ne
+un4er
+u1ni
+un4im
+u2nin
+un5ish
+uni3v
+un3s4
+un4sw
+unt3ab
+un4ter.
+un4tes
+unu4
+un5y
+un5z
+u4ors
+u5os
+u1ou
+u1pe
+uper5s
+u5pia
+up3ing
+u3pl
+up3p
+upport5
+upt5ib
+uptu4
+u1ra
+4ura.
+u4rag
+u4ras
+ur4be
+urc4
+ur1d
+ure5at
+ur4fer
+ur4fr
+u3rif
+uri4fic
+ur1in
+u3rio
+u1rit
+ur3iz
+ur2l
+url5ing.
+ur4no
+uros4
+ur4pe
+ur4pi
+urs5er
+ur5tes
+ur3the
+urti4
+ur4tie
+u3ru
+2us
+u5sad
+u5san
+us4ap
+usc2
+us3ci
+use5a
+u5sia
+u3sic
+us4lin
+us1p
+us5sl
+us5tere
+us1tr
+u2su
+usur4
+uta4b
+u3tat
+4ute.
+4utel
+4uten
+uten4i
+4u1t2i
+uti5liz
+u3tine
+ut3ing
+ution5a
+u4tis
+5u5tiz
+u4t1l
+ut5of
+uto5g
+uto5matic
+u5ton
+u4tou
+uts4
+u3u
+uu4m
+u1v2
+uxu3
+uz4e
+1va
+5va.
+2v1a4b
+vac5il
+vac3u
+vag4
+va4ge
+va5lie
+val5o
+val1u
+va5mo
+va5niz
+va5pi
+var5ied
+3vat
+4ve.
+4ved
+veg3
+v3el.
+vel3li
+ve4lo
+v4ely
+ven3om
+v5enue
+v4erd
+5vere.
+v4erel
+v3eren
+ver5enc
+v4eres
+ver3ie
+vermi4n
+3verse
+ver3th
+v4e2s
+4ves.
+ves4te
+ve4te
+vet3er
+ve4ty
+vi5ali
+5vian
+5vide.
+5vided
+4v3iden
+5vides
+5vidi
+v3if
+vi5gn
+vik4
+2vil
+5vilit
+v3i3liz
+v1in
+4vi4na
+v2inc
+vin5d
+4ving
+vio3l
+v3io4r
+vi1ou
+vi4p
+vi5ro
+vis3it
+vi3so
+vi3su
+4viti
+vit3r
+4vity
+3viv
+5vo.
+voi4
+3vok
+vo4la
+v5ole
+5volt
+3volv
+vom5i
+vor5ab
+vori4
+vo4ry
+vo4ta
+4votee
+4vv4
+v4y
+w5abl
+2wac
+wa5ger
+wag5o
+wait5
+w5al.
+wam4
+war4t
+was4t
+wa1te
+wa5ver
+w1b
+wea5rie
+weath3
+wed4n
+weet3
+wee5v
+wel4l
+w1er
+west3
+w3ev
+whi4
+wi2
+wil2
+will5in
+win4de
+win4g
+wir4
+3wise
+with3
+wiz5
+w4k
+wl4es
+wl3in
+w4no
+1wo2
+wom1
+wo5ven
+w5p
+wra4
+wri4
+writa4
+w3sh
+ws4l
+ws4pe
+w5s4t
+4wt
+wy4
+x1a
+xac5e
+x4ago
+xam3
+x4ap
+xas5
+x3c2
+x1e
+xe4cuto
+x2ed
+xer4i
+xe5ro
+x1h
+xhi2
+xhil5
+xhu4
+x3i
+xi5a
+xi5c
+xi5di
+x4ime
+xi5miz
+x3o
+x4ob
+x3p
+xpan4d
+xpecto5
+xpe3d
+x1t2
+x3ti
+x1u
+xu3a
+xx4
+y5ac
+3yar4
+y5at
+y1b
+y1c
+y2ce
+yc5er
+y3ch
+ych4e
+ycom4
+ycot4
+y1d
+y5ee
+y1er
+y4erf
+yes4
+ye4t
+y5gi
+4y3h
+y1i
+y3la
+ylla5bl
+y3lo
+y5lu
+ymbol5
+yme4
+ympa3
+yn3chr
+yn5d
+yn5g
+yn5ic
+5ynx
+y1o4
+yo5d
+y4o5g
+yom4
+yo5net
+y4ons
+y4os
+y4ped
+yper5
+yp3i
+y3po
+y4poc
+yp2ta
+y5pu
+yra5m
+yr5ia
+y3ro
+yr4r
+ys4c
+y3s2e
+ys3ica
+ys3io
+3ysis
+y4so
+yss4
+ys1t
+ys3ta
+ysur4
+y3thin
+yt3ic
+y1w
+za1
+z5a2b
+zar2
+4zb
+2ze
+ze4n
+ze4p
+z1er
+ze3ro
+zet4
+2z1i
+z4il
+z4is
+5zl
+4zm
+1zo
+zo4m
+zo5ol
+zte4
+4z1z2
+z4zy
diff --git a/gnu/usr.bin/groff/troff/hyphen.us-ru b/gnu/usr.bin/groff/troff/hyphen.us-ru
new file mode 100644
index 0000000..3ccef48
--- /dev/null
+++ b/gnu/usr.bin/groff/troff/hyphen.us-ru
@@ -0,0 +1,4833 @@
+% Hyphenation patterns for US English and Russian (koi8-r).
+% These are the standard Plain TeX hyphenation patterns (in hyphen.tex).
+.ach4
+.ad4der
+.af1t
+.al3t
+.am5at
+.an5c
+.ang4
+.ani5m
+.ant4
+.an3te
+.anti5s
+.ar5s
+.ar4tie
+.ar4ty
+.as3c
+.as1p
+.as1s
+.aster5
+.atom5
+.au1d
+.av4i
+.awn4
+.ba4g
+.ba5na
+.bas4e
+.ber4
+.be5ra
+.be3sm
+.be5sto
+.bri2
+.but4ti
+.cam4pe
+.can5c
+.capa5b
+.car5ol
+.ca4t
+.ce4la
+.ch4
+.chill5i
+.ci2
+.cit5r
+.co3e
+.co4r
+.cor5ner
+.de4moi
+.de3o
+.de3ra
+.de3ri
+.des4c
+.dictio5
+.do4t
+.du4c
+.dumb5
+.earth5
+.eas3i
+.eb4
+.eer4
+.eg2
+.el5d
+.el3em
+.enam3
+.en3g
+.en3s
+.eq5ui5t
+.er4ri
+.es3
+.eu3
+.eye5
+.fes3
+.for5mer
+.ga2
+.ge2
+.gen3t4
+.ge5og
+.gi5a
+.gi4b
+.go4r
+.hand5i
+.han5k
+.he2
+.hero5i
+.hes3
+.het3
+.hi3b
+.hi3er
+.hon5ey
+.hon3o
+.hov5
+.id4l
+.idol3
+.im3m
+.im5pin
+.in1
+.in3ci
+.ine2
+.in2k
+.in3s
+.ir5r
+.is4i
+.ju3r
+.la4cy
+.la4m
+.lat5er
+.lath5
+.le2
+.leg5e
+.len4
+.lep5
+.lev1
+.li4g
+.lig5a
+.li2n
+.li3o
+.li4t
+.mag5a5
+.mal5o
+.man5a
+.mar5ti
+.me2
+.mer3c
+.me5ter
+.mis1
+.mist5i
+.mon3e
+.mo3ro
+.mu5ta
+.muta5b
+.ni4c
+.od2
+.odd5
+.of5te
+.or5ato
+.or3c
+.or1d
+.or3t
+.os3
+.os4tl
+.oth3
+.out3
+.ped5al
+.pe5te
+.pe5tit
+.pi4e
+.pio5n
+.pi2t
+.pre3m
+.ra4c
+.ran4t
+.ratio5na
+.ree2
+.re5mit
+.res2
+.re5stat
+.ri4g
+.rit5u
+.ro4q
+.ros5t
+.row5d
+.ru4d
+.sci3e
+.self5
+.sell5
+.se2n
+.se5rie
+.sh2
+.si2
+.sing4
+.st4
+.sta5bl
+.sy2
+.ta4
+.te4
+.ten5an
+.th2
+.ti2
+.til4
+.tim5o5
+.ting4
+.tin5k
+.ton4a
+.to4p
+.top5i
+.tou5s
+.trib5ut
+.un1a
+.un3ce
+.under5
+.un1e
+.un5k
+.un5o
+.un3u
+.up3
+.ure3
+.us5a
+.ven4de
+.ve5ra
+.wil5i
+.ye4
+4ab.
+a5bal
+a5ban
+abe2
+ab5erd
+abi5a
+ab5it5ab
+ab5lat
+ab5o5liz
+4abr
+ab5rog
+ab3ul
+a4car
+ac5ard
+ac5aro
+a5ceou
+ac1er
+a5chet
+4a2ci
+a3cie
+ac1in
+a3cio
+ac5rob
+act5if
+ac3ul
+ac4um
+a2d
+ad4din
+ad5er.
+2adi
+a3dia
+ad3ica
+adi4er
+a3dio
+a3dit
+a5diu
+ad4le
+ad3ow
+ad5ran
+ad4su
+4adu
+a3duc
+ad5um
+ae4r
+aeri4e
+a2f
+aff4
+a4gab
+aga4n
+ag5ell
+age4o
+4ageu
+ag1i
+4ag4l
+ag1n
+a2go
+3agog
+ag3oni
+a5guer
+ag5ul
+a4gy
+a3ha
+a3he
+ah4l
+a3ho
+ai2
+a5ia
+a3ic.
+ai5ly
+a4i4n
+ain5in
+ain5o
+ait5en
+a1j
+ak1en
+al5ab
+al3ad
+a4lar
+4aldi
+2ale
+al3end
+a4lenti
+a5le5o
+al1i
+al4ia.
+ali4e
+al5lev
+4allic
+4alm
+a5log.
+a4ly.
+4alys
+5a5lyst
+5alyt
+3alyz
+4ama
+am5ab
+am3ag
+ama5ra
+am5asc
+a4matis
+a4m5ato
+am5era
+am3ic
+am5if
+am5ily
+am1in
+ami4no
+a2mo
+a5mon
+amor5i
+amp5en
+a2n
+an3age
+3analy
+a3nar
+an3arc
+anar4i
+a3nati
+4and
+ande4s
+an3dis
+an1dl
+an4dow
+a5nee
+a3nen
+an5est.
+a3neu
+2ang
+ang5ie
+an1gl
+a4n1ic
+a3nies
+an3i3f
+an4ime
+a5nimi
+a5nine
+an3io
+a3nip
+an3ish
+an3it
+a3niu
+an4kli
+5anniz
+ano4
+an5ot
+anoth5
+an2sa
+an4sco
+an4sn
+an2sp
+ans3po
+an4st
+an4sur
+antal4
+an4tie
+4anto
+an2tr
+an4tw
+an3ua
+an3ul
+a5nur
+4ao
+apar4
+ap5at
+ap5ero
+a3pher
+4aphi
+a4pilla
+ap5illar
+ap3in
+ap3ita
+a3pitu
+a2pl
+apoc5
+ap5ola
+apor5i
+apos3t
+aps5es
+a3pu
+aque5
+2a2r
+ar3act
+a5rade
+ar5adis
+ar3al
+a5ramete
+aran4g
+ara3p
+ar4at
+a5ratio
+ar5ativ
+a5rau
+ar5av4
+araw4
+arbal4
+ar4chan
+ar5dine
+ar4dr
+ar5eas
+a3ree
+ar3ent
+a5ress
+ar4fi
+ar4fl
+ar1i
+ar5ial
+ar3ian
+a3riet
+ar4im
+ar5inat
+ar3io
+ar2iz
+ar2mi
+ar5o5d
+a5roni
+a3roo
+ar2p
+ar3q
+arre4
+ar4sa
+ar2sh
+4as.
+as4ab
+as3ant
+ashi4
+a5sia.
+a3sib
+a3sic
+5a5si4t
+ask3i
+as4l
+a4soc
+as5ph
+as4sh
+as3ten
+as1tr
+asur5a
+a2ta
+at3abl
+at5ac
+at3alo
+at5ap
+ate5c
+at5ech
+at3ego
+at3en.
+at3era
+ater5n
+a5terna
+at3est
+at5ev
+4ath
+ath5em
+a5then
+at4ho
+ath5om
+4ati.
+a5tia
+at5i5b
+at1ic
+at3if
+ation5ar
+at3itu
+a4tog
+a2tom
+at5omiz
+a4top
+a4tos
+a1tr
+at5rop
+at4sk
+at4tag
+at5te
+at4th
+a2tu
+at5ua
+at5ue
+at3ul
+at3ura
+a2ty
+au4b
+augh3
+au3gu
+au4l2
+aun5d
+au3r
+au5sib
+aut5en
+au1th
+a2va
+av3ag
+a5van
+ave4no
+av3era
+av5ern
+av5ery
+av1i
+avi4er
+av3ig
+av5oc
+a1vor
+3away
+aw3i
+aw4ly
+aws4
+ax4ic
+ax4id
+ay5al
+aye4
+ays4
+azi4er
+azz5i
+5ba.
+bad5ger
+ba4ge
+bal1a
+ban5dag
+ban4e
+ban3i
+barbi5
+bari4a
+bas4si
+1bat
+ba4z
+2b1b
+b2be
+b3ber
+bbi4na
+4b1d
+4be.
+beak4
+beat3
+4be2d
+be3da
+be3de
+be3di
+be3gi
+be5gu
+1bel
+be1li
+be3lo
+4be5m
+be5nig
+be5nu
+4bes4
+be3sp
+be5str
+3bet
+bet5iz
+be5tr
+be3tw
+be3w
+be5yo
+2bf
+4b3h
+bi2b
+bi4d
+3bie
+bi5en
+bi4er
+2b3if
+1bil
+bi3liz
+bina5r4
+bin4d
+bi5net
+bi3ogr
+bi5ou
+bi2t
+3bi3tio
+bi3tr
+3bit5ua
+b5itz
+b1j
+bk4
+b2l2
+blath5
+b4le.
+blen4
+5blesp
+b3lis
+b4lo
+blun4t
+4b1m
+4b3n
+bne5g
+3bod
+bod3i
+bo4e
+bol3ic
+bom4bi
+bon4a
+bon5at
+3boo
+5bor.
+4b1ora
+bor5d
+5bore
+5bori
+5bos4
+b5ota
+both5
+bo4to
+bound3
+4bp
+4brit
+broth3
+2b5s2
+bsor4
+2bt
+bt4l
+b4to
+b3tr
+buf4fer
+bu4ga
+bu3li
+bumi4
+bu4n
+bunt4i
+bu3re
+bus5ie
+buss4e
+5bust
+4buta
+3butio
+b5uto
+b1v
+4b5w
+5by.
+bys4
+1ca
+cab3in
+ca1bl
+cach4
+ca5den
+4cag4
+2c5ah
+ca3lat
+cal4la
+call5in
+4calo
+can5d
+can4e
+can4ic
+can5is
+can3iz
+can4ty
+cany4
+ca5per
+car5om
+cast5er
+cas5tig
+4casy
+ca4th
+4cativ
+cav5al
+c3c
+ccha5
+cci4a
+ccompa5
+ccon4
+ccou3t
+2ce.
+4ced.
+4ceden
+3cei
+5cel.
+3cell
+1cen
+3cenc
+2cen4e
+4ceni
+3cent
+3cep
+ce5ram
+4cesa
+3cessi
+ces5si5b
+ces5t
+cet4
+c5e4ta
+cew4
+2ch
+4ch.
+4ch3ab
+5chanic
+ch5a5nis
+che2
+cheap3
+4ched
+che5lo
+3chemi
+ch5ene
+ch3er.
+ch3ers
+4ch1in
+5chine.
+ch5iness
+5chini
+5chio
+3chit
+chi2z
+3cho2
+ch4ti
+1ci
+3cia
+ci2a5b
+cia5r
+ci5c
+4cier
+5cific.
+4cii
+ci4la
+3cili
+2cim
+2cin
+c4ina
+3cinat
+cin3em
+c1ing
+c5ing.
+5cino
+cion4
+4cipe
+ci3ph
+4cipic
+4cista
+4cisti
+2c1it
+cit3iz
+5ciz
+ck1
+ck3i
+1c4l4
+4clar
+c5laratio
+5clare
+cle4m
+4clic
+clim4
+cly4
+c5n
+1co
+co5ag
+coe2
+2cog
+co4gr
+coi4
+co3inc
+col5i
+5colo
+col3or
+com5er
+con4a
+c4one
+con3g
+con5t
+co3pa
+cop3ic
+co4pl
+4corb
+coro3n
+cos4e
+cov1
+cove4
+cow5a
+coz5e
+co5zi
+c1q
+cras5t
+5crat.
+5cratic
+cre3at
+5cred
+4c3reta
+cre4v
+cri2
+cri5f
+c4rin
+cris4
+5criti
+cro4pl
+crop5o
+cros4e
+cru4d
+4c3s2
+2c1t
+cta4b
+ct5ang
+c5tant
+c2te
+c3ter
+c4ticu
+ctim3i
+ctu4r
+c4tw
+cud5
+c4uf
+c4ui
+cu5ity
+5culi
+cul4tis
+3cultu
+cu2ma
+c3ume
+cu4mi
+3cun
+cu3pi
+cu5py
+cur5a4b
+cu5ria
+1cus
+cuss4i
+3c4ut
+cu4tie
+4c5utiv
+4cutr
+1cy
+cze4
+1d2a
+5da.
+2d3a4b
+dach4
+4daf
+2dag
+da2m2
+dan3g
+dard5
+dark5
+4dary
+3dat
+4dativ
+4dato
+5dav4
+dav5e
+5day
+d1b
+d5c
+d1d4
+2de.
+deaf5
+deb5it
+de4bon
+decan4
+de4cil
+de5com
+2d1ed
+4dee.
+de5if
+deli4e
+del5i5q
+de5lo
+d4em
+5dem.
+3demic
+dem5ic.
+de5mil
+de4mons
+demor5
+1den
+de4nar
+de3no
+denti5f
+de3nu
+de1p
+de3pa
+depi4
+de2pu
+d3eq
+d4erh
+5derm
+dern5iz
+der5s
+des2
+d2es.
+de1sc
+de2s5o
+des3ti
+de3str
+de4su
+de1t
+de2to
+de1v
+dev3il
+4dey
+4d1f
+d4ga
+d3ge4t
+dg1i
+d2gy
+d1h2
+5di.
+1d4i3a
+dia5b
+di4cam
+d4ice
+3dict
+3did
+5di3en
+d1if
+di3ge
+di4lato
+d1in
+1dina
+3dine.
+5dini
+di5niz
+1dio
+dio5g
+di4pl
+dir2
+di1re
+dirt5i
+dis1
+5disi
+d4is3t
+d2iti
+1di1v
+d1j
+d5k2
+4d5la
+3dle.
+3dled
+3dles.
+4dless
+2d3lo
+4d5lu
+2dly
+d1m
+4d1n4
+1do
+3do.
+do5de
+5doe
+2d5of
+d4og
+do4la
+doli4
+do5lor
+dom5iz
+do3nat
+doni4
+doo3d
+dop4p
+d4or
+3dos
+4d5out
+do4v
+3dox
+d1p
+1dr
+drag5on
+4drai
+dre4
+drea5r
+5dren
+dri4b
+dril4
+dro4p
+4drow
+5drupli
+4dry
+2d1s2
+ds4p
+d4sw
+d4sy
+d2th
+1du
+d1u1a
+du2c
+d1uca
+duc5er
+4duct.
+4ducts
+du5el
+du4g
+d3ule
+dum4be
+du4n
+4dup
+du4pe
+d1v
+d1w
+d2y
+5dyn
+dy4se
+dys5p
+e1a4b
+e3act
+ead1
+ead5ie
+ea4ge
+ea5ger
+ea4l
+eal5er
+eal3ou
+eam3er
+e5and
+ear3a
+ear4c
+ear5es
+ear4ic
+ear4il
+ear5k
+ear2t
+eart3e
+ea5sp
+e3ass
+east3
+ea2t
+eat5en
+eath3i
+e5atif
+e4a3tu
+ea2v
+eav3en
+eav5i
+eav5o
+2e1b
+e4bel.
+e4bels
+e4ben
+e4bit
+e3br
+e4cad
+ecan5c
+ecca5
+e1ce
+ec5essa
+ec2i
+e4cib
+ec5ificat
+ec5ifie
+ec5ify
+ec3im
+eci4t
+e5cite
+e4clam
+e4clus
+e2col
+e4comm
+e4compe
+e4conc
+e2cor
+ec3ora
+eco5ro
+e1cr
+e4crem
+ec4tan
+ec4te
+e1cu
+e4cul
+ec3ula
+2e2da
+4ed3d
+e4d1er
+ede4s
+4edi
+e3dia
+ed3ib
+ed3ica
+ed3im
+ed1it
+edi5z
+4edo
+e4dol
+edon2
+e4dri
+e4dul
+ed5ulo
+ee2c
+eed3i
+ee2f
+eel3i
+ee4ly
+ee2m
+ee4na
+ee4p1
+ee2s4
+eest4
+ee4ty
+e5ex
+e1f
+e4f3ere
+1eff
+e4fic
+5efici
+efil4
+e3fine
+ef5i5nite
+3efit
+efor5es
+e4fuse.
+4egal
+eger4
+eg5ib
+eg4ic
+eg5ing
+e5git5
+eg5n
+e4go.
+e4gos
+eg1ul
+e5gur
+5egy
+e1h4
+eher4
+ei2
+e5ic
+ei5d
+eig2
+ei5gl
+e3imb
+e3inf
+e1ing
+e5inst
+eir4d
+eit3e
+ei3th
+e5ity
+e1j
+e4jud
+ej5udi
+eki4n
+ek4la
+e1la
+e4la.
+e4lac
+elan4d
+el5ativ
+e4law
+elaxa4
+e3lea
+el5ebra
+5elec
+e4led
+el3ega
+e5len
+e4l1er
+e1les
+el2f
+el2i
+e3libe
+e4l5ic.
+el3ica
+e3lier
+el5igib
+e5lim
+e4l3ing
+e3lio
+e2lis
+el5ish
+e3liv3
+4ella
+el4lab
+ello4
+e5loc
+el5og
+el3op.
+el2sh
+el4ta
+e5lud
+el5ug
+e4mac
+e4mag
+e5man
+em5ana
+em5b
+e1me
+e2mel
+e4met
+em3ica
+emi4e
+em5igra
+em1in2
+em5ine
+em3i3ni
+e4mis
+em5ish
+e5miss
+em3iz
+5emniz
+emo4g
+emoni5o
+em3pi
+e4mul
+em5ula
+emu3n
+e3my
+en5amo
+e4nant
+ench4er
+en3dic
+e5nea
+e5nee
+en3em
+en5ero
+en5esi
+en5est
+en3etr
+e3new
+en5ics
+e5nie
+e5nil
+e3nio
+en3ish
+en3it
+e5niu
+5eniz
+4enn
+4eno
+eno4g
+e4nos
+en3ov
+en4sw
+ent5age
+4enthes
+en3ua
+en5uf
+e3ny.
+4en3z
+e5of
+eo2g
+e4oi4
+e3ol
+eop3ar
+e1or
+eo3re
+eo5rol
+eos4
+e4ot
+eo4to
+e5out
+e5ow
+e2pa
+e3pai
+ep5anc
+e5pel
+e3pent
+ep5etitio
+ephe4
+e4pli
+e1po
+e4prec
+ep5reca
+e4pred
+ep3reh
+e3pro
+e4prob
+ep4sh
+ep5ti5b
+e4put
+ep5uta
+e1q
+equi3l
+e4q3ui3s
+er1a
+era4b
+4erand
+er3ar
+4erati.
+2erb
+er4bl
+er3ch
+er4che
+2ere.
+e3real
+ere5co
+ere3in
+er5el.
+er3emo
+er5ena
+er5ence
+4erene
+er3ent
+ere4q
+er5ess
+er3est
+eret4
+er1h
+er1i
+e1ria4
+5erick
+e3rien
+eri4er
+er3ine
+e1rio
+4erit
+er4iu
+eri4v
+e4riva
+er3m4
+er4nis
+4ernit
+5erniz
+er3no
+2ero
+er5ob
+e5roc
+ero4r
+er1ou
+er1s
+er3set
+ert3er
+4ertl
+er3tw
+4eru
+eru4t
+5erwau
+e1s4a
+e4sage.
+e4sages
+es2c
+e2sca
+es5can
+e3scr
+es5cu
+e1s2e
+e2sec
+es5ecr
+es5enc
+e4sert.
+e4serts
+e4serva
+4esh
+e3sha
+esh5en
+e1si
+e2sic
+e2sid
+es5iden
+es5igna
+e2s5im
+es4i4n
+esis4te
+esi4u
+e5skin
+es4mi
+e2sol
+es3olu
+e2son
+es5ona
+e1sp
+es3per
+es5pira
+es4pre
+2ess
+es4si4b
+estan4
+es3tig
+es5tim
+4es2to
+e3ston
+2estr
+e5stro
+estruc5
+e2sur
+es5urr
+es4w
+eta4b
+eten4d
+e3teo
+ethod3
+et1ic
+e5tide
+etin4
+eti4no
+e5tir
+e5titio
+et5itiv
+4etn
+et5ona
+e3tra
+e3tre
+et3ric
+et5rif
+et3rog
+et5ros
+et3ua
+et5ym
+et5z
+4eu
+e5un
+e3up
+eu3ro
+eus4
+eute4
+euti5l
+eu5tr
+eva2p5
+e2vas
+ev5ast
+e5vea
+ev3ell
+evel3o
+e5veng
+even4i
+ev1er
+e5verb
+e1vi
+ev3id
+evi4l
+e4vin
+evi4v
+e5voc
+e5vu
+e1wa
+e4wag
+e5wee
+e3wh
+ewil5
+ew3ing
+e3wit
+1exp
+5eyc
+5eye.
+eys4
+1fa
+fa3bl
+fab3r
+fa4ce
+4fag
+fain4
+fall5e
+4fa4ma
+fam5is
+5far
+far5th
+fa3ta
+fa3the
+4fato
+fault5
+4f5b
+4fd
+4fe.
+feas4
+feath3
+fe4b
+4feca
+5fect
+2fed
+fe3li
+fe4mo
+fen2d
+fend5e
+fer1
+5ferr
+fev4
+4f1f
+f4fes
+f4fie
+f5fin.
+f2f5is
+f4fly
+f2fy
+4fh
+1fi
+fi3a
+2f3ic.
+4f3ical
+f3ican
+4ficate
+f3icen
+fi3cer
+fic4i
+5ficia
+5ficie
+4fics
+fi3cu
+fi5del
+fight5
+fil5i
+fill5in
+4fily
+2fin
+5fina
+fin2d5
+fi2ne
+f1in3g
+fin4n
+fis4ti
+f4l2
+f5less
+flin4
+flo3re
+f2ly5
+4fm
+4fn
+1fo
+5fon
+fon4de
+fon4t
+fo2r
+fo5rat
+for5ay
+fore5t
+for4i
+fort5a
+fos5
+4f5p
+fra4t
+f5rea
+fres5c
+fri2
+fril4
+frol5
+2f3s
+2ft
+f4to
+f2ty
+3fu
+fu5el
+4fug
+fu4min
+fu5ne
+fu3ri
+fusi4
+fus4s
+4futa
+1fy
+1ga
+gaf4
+5gal.
+3gali
+ga3lo
+2gam
+ga5met
+g5amo
+gan5is
+ga3niz
+gani5za
+4gano
+gar5n4
+gass4
+gath3
+4gativ
+4gaz
+g3b
+gd4
+2ge.
+2ged
+geez4
+gel4in
+ge5lis
+ge5liz
+4gely
+1gen
+ge4nat
+ge5niz
+4geno
+4geny
+1geo
+ge3om
+g4ery
+5gesi
+geth5
+4geto
+ge4ty
+ge4v
+4g1g2
+g2ge
+g3ger
+gglu5
+ggo4
+gh3in
+gh5out
+gh4to
+5gi.
+1gi4a
+gia5r
+g1ic
+5gicia
+g4ico
+gien5
+5gies.
+gil4
+g3imen
+3g4in.
+gin5ge
+5g4ins
+5gio
+3gir
+gir4l
+g3isl
+gi4u
+5giv
+3giz
+gl2
+gla4
+glad5i
+5glas
+1gle
+gli4b
+g3lig
+3glo
+glo3r
+g1m
+g4my
+gn4a
+g4na.
+gnet4t
+g1ni
+g2nin
+g4nio
+g1no
+g4non
+1go
+3go.
+gob5
+5goe
+3g4o4g
+go3is
+gon2
+4g3o3na
+gondo5
+go3ni
+5goo
+go5riz
+gor5ou
+5gos.
+gov1
+g3p
+1gr
+4grada
+g4rai
+gran2
+5graph.
+g5rapher
+5graphic
+4graphy
+4gray
+gre4n
+4gress.
+4grit
+g4ro
+gruf4
+gs2
+g5ste
+gth3
+gu4a
+3guard
+2gue
+5gui5t
+3gun
+3gus
+4gu4t
+g3w
+1gy
+2g5y3n
+gy5ra
+h3ab4l
+hach4
+hae4m
+hae4t
+h5agu
+ha3la
+hala3m
+ha4m
+han4ci
+han4cy
+5hand.
+han4g
+hang5er
+hang5o
+h5a5niz
+han4k
+han4te
+hap3l
+hap5t
+ha3ran
+ha5ras
+har2d
+hard3e
+har4le
+harp5en
+har5ter
+has5s
+haun4
+5haz
+haz3a
+h1b
+1head
+3hear
+he4can
+h5ecat
+h4ed
+he5do5
+he3l4i
+hel4lis
+hel4ly
+h5elo
+hem4p
+he2n
+hena4
+hen5at
+heo5r
+hep5
+h4era
+hera3p
+her4ba
+here5a
+h3ern
+h5erou
+h3ery
+h1es
+he2s5p
+he4t
+het4ed
+heu4
+h1f
+h1h
+hi5an
+hi4co
+high5
+h4il2
+himer4
+h4ina
+hion4e
+hi4p
+hir4l
+hi3ro
+hir4p
+hir4r
+his3el
+his4s
+hith5er
+hi2v
+4hk
+4h1l4
+hlan4
+h2lo
+hlo3ri
+4h1m
+hmet4
+2h1n
+h5odiz
+h5ods
+ho4g
+hoge4
+hol5ar
+3hol4e
+ho4ma
+home3
+hon4a
+ho5ny
+3hood
+hoon4
+hor5at
+ho5ris
+hort3e
+ho5ru
+hos4e
+ho5sen
+hos1p
+1hous
+house3
+hov5el
+4h5p
+4hr4
+hree5
+hro5niz
+hro3po
+4h1s2
+h4sh
+h4tar
+ht1en
+ht5es
+h4ty
+hu4g
+hu4min
+hun5ke
+hun4t
+hus3t4
+hu4t
+h1w
+h4wart
+hy3pe
+hy3ph
+hy2s
+2i1a
+i2al
+iam4
+iam5ete
+i2an
+4ianc
+ian3i
+4ian4t
+ia5pe
+iass4
+i4ativ
+ia4tric
+i4atu
+ibe4
+ib3era
+ib5ert
+ib5ia
+ib3in
+ib5it.
+ib5ite
+i1bl
+ib3li
+i5bo
+i1br
+i2b5ri
+i5bun
+4icam
+5icap
+4icar
+i4car.
+i4cara
+icas5
+i4cay
+iccu4
+4iceo
+4ich
+2ici
+i5cid
+ic5ina
+i2cip
+ic3ipa
+i4cly
+i2c5oc
+4i1cr
+5icra
+i4cry
+ic4te
+ictu2
+ic4t3ua
+ic3ula
+ic4um
+ic5uo
+i3cur
+2id
+i4dai
+id5anc
+id5d
+ide3al
+ide4s
+i2di
+id5ian
+idi4ar
+i5die
+id3io
+idi5ou
+id1it
+id5iu
+i3dle
+i4dom
+id3ow
+i4dr
+i2du
+id5uo
+2ie4
+ied4e
+5ie5ga
+ield3
+ien5a4
+ien4e
+i5enn
+i3enti
+i1er.
+i3esc
+i1est
+i3et
+4if.
+if5ero
+iff5en
+if4fr
+4ific.
+i3fie
+i3fl
+4ift
+2ig
+iga5b
+ig3era
+ight3i
+4igi
+i3gib
+ig3il
+ig3in
+ig3it
+i4g4l
+i2go
+ig3or
+ig5ot
+i5gre
+igu5i
+ig1ur
+i3h
+4i5i4
+i3j
+4ik
+i1la
+il3a4b
+i4lade
+i2l5am
+ila5ra
+i3leg
+il1er
+ilev4
+il5f
+il1i
+il3ia
+il2ib
+il3io
+il4ist
+2ilit
+il2iz
+ill5ab
+4iln
+il3oq
+il4ty
+il5ur
+il3v
+i4mag
+im3age
+ima5ry
+imenta5r
+4imet
+im1i
+im5ida
+imi5le
+i5mini
+4imit
+im4ni
+i3mon
+i2mu
+im3ula
+2in.
+i4n3au
+4inav
+incel4
+in3cer
+4ind
+in5dling
+2ine
+i3nee
+iner4ar
+i5ness
+4inga
+4inge
+in5gen
+4ingi
+in5gling
+4ingo
+4ingu
+2ini
+i5ni.
+i4nia
+in3io
+in1is
+i5nite.
+5initio
+in3ity
+4ink
+4inl
+2inn
+2i1no
+i4no4c
+ino4s
+i4not
+2ins
+in3se
+insur5a
+2int.
+2in4th
+in1u
+i5nus
+4iny
+2io
+4io.
+ioge4
+io2gr
+i1ol
+io4m
+ion3at
+ion4ery
+ion3i
+io5ph
+ior3i
+i4os
+io5th
+i5oti
+io4to
+i4our
+2ip
+ipe4
+iphras4
+ip3i
+ip4ic
+ip4re4
+ip3ul
+i3qua
+iq5uef
+iq3uid
+iq3ui3t
+4ir
+i1ra
+ira4b
+i4rac
+ird5e
+ire4de
+i4ref
+i4rel4
+i4res
+ir5gi
+ir1i
+iri5de
+ir4is
+iri3tu
+5i5r2iz
+ir4min
+iro4g
+5iron.
+ir5ul
+2is.
+is5ag
+is3ar
+isas5
+2is1c
+is3ch
+4ise
+is3er
+3isf
+is5han
+is3hon
+ish5op
+is3ib
+isi4d
+i5sis
+is5itiv
+4is4k
+islan4
+4isms
+i2so
+iso5mer
+is1p
+is2pi
+is4py
+4is1s
+is4sal
+issen4
+is4ses
+is4ta.
+is1te
+is1ti
+ist4ly
+4istral
+i2su
+is5us
+4ita.
+ita4bi
+i4tag
+4ita5m
+i3tan
+i3tat
+2ite
+it3era
+i5teri
+it4es
+2ith
+i1ti
+4itia
+4i2tic
+it3ica
+5i5tick
+it3ig
+it5ill
+i2tim
+2itio
+4itis
+i4tism
+i2t5o5m
+4iton
+i4tram
+it5ry
+4itt
+it3uat
+i5tud
+it3ul
+4itz.
+i1u
+2iv
+iv3ell
+iv3en.
+i4v3er.
+i4vers.
+iv5il.
+iv5io
+iv1it
+i5vore
+iv3o3ro
+i4v3ot
+4i5w
+ix4o
+4iy
+4izar
+izi4
+5izont
+5ja
+jac4q
+ja4p
+1je
+jer5s
+4jestie
+4jesty
+jew3
+jo4p
+5judg
+3ka.
+k3ab
+k5ag
+kais4
+kal4
+k1b
+k2ed
+1kee
+ke4g
+ke5li
+k3en4d
+k1er
+kes4
+k3est.
+ke4ty
+k3f
+kh4
+k1i
+5ki.
+5k2ic
+k4ill
+kilo5
+k4im
+k4in.
+kin4de
+k5iness
+kin4g
+ki4p
+kis4
+k5ish
+kk4
+k1l
+4kley
+4kly
+k1m
+k5nes
+1k2no
+ko5r
+kosh4
+k3ou
+kro5n
+4k1s2
+k4sc
+ks4l
+k4sy
+k5t
+k1w
+lab3ic
+l4abo
+laci4
+l4ade
+la3dy
+lag4n
+lam3o
+3land
+lan4dl
+lan5et
+lan4te
+lar4g
+lar3i
+las4e
+la5tan
+4lateli
+4lativ
+4lav
+la4v4a
+2l1b
+lbin4
+4l1c2
+lce4
+l3ci
+2ld
+l2de
+ld4ere
+ld4eri
+ldi4
+ld5is
+l3dr
+l4dri
+le2a
+le4bi
+left5
+5leg.
+5legg
+le4mat
+lem5atic
+4len.
+3lenc
+5lene.
+1lent
+le3ph
+le4pr
+lera5b
+ler4e
+3lerg
+3l4eri
+l4ero
+les2
+le5sco
+5lesq
+3less
+5less.
+l3eva
+lev4er.
+lev4era
+lev4ers
+3ley
+4leye
+2lf
+l5fr
+4l1g4
+l5ga
+lgar3
+l4ges
+lgo3
+2l3h
+li4ag
+li2am
+liar5iz
+li4as
+li4ato
+li5bi
+5licio
+li4cor
+4lics
+4lict.
+l4icu
+l3icy
+l3ida
+lid5er
+3lidi
+lif3er
+l4iff
+li4fl
+5ligate
+3ligh
+li4gra
+3lik
+4l4i4l
+lim4bl
+lim3i
+li4mo
+l4im4p
+l4ina
+1l4ine
+lin3ea
+lin3i
+link5er
+li5og
+4l4iq
+lis4p
+l1it
+l2it.
+5litica
+l5i5tics
+liv3er
+l1iz
+4lj
+lka3
+l3kal
+lka4t
+l1l
+l4law
+l2le
+l5lea
+l3lec
+l3leg
+l3lel
+l3le4n
+l3le4t
+ll2i
+l2lin4
+l5lina
+ll4o
+lloqui5
+ll5out
+l5low
+2lm
+l5met
+lm3ing
+l4mod
+lmon4
+2l1n2
+3lo.
+lob5al
+lo4ci
+4lof
+3logic
+l5ogo
+3logu
+lom3er
+5long
+lon4i
+l3o3niz
+lood5
+5lope.
+lop3i
+l3opm
+lora4
+lo4rato
+lo5rie
+lor5ou
+5los.
+los5et
+5losophiz
+5losophy
+los4t
+lo4ta
+loun5d
+2lout
+4lov
+2lp
+lpa5b
+l3pha
+l5phi
+lp5ing
+l3pit
+l4pl
+l5pr
+4l1r
+2l1s2
+l4sc
+l2se
+l4sie
+4lt
+lt5ag
+ltane5
+l1te
+lten4
+ltera4
+lth3i
+l5ties.
+ltis4
+l1tr
+ltu2
+ltur3a
+lu5a
+lu3br
+luch4
+lu3ci
+lu3en
+luf4
+lu5id
+lu4ma
+5lumi
+l5umn.
+5lumnia
+lu3o
+luo3r
+4lup
+luss4
+lus3te
+1lut
+l5ven
+l5vet4
+2l1w
+1ly
+4lya
+4lyb
+ly5me
+ly3no
+2lys4
+l5yse
+1ma
+2mab
+ma2ca
+ma5chine
+ma4cl
+mag5in
+5magn
+2mah
+maid5
+4mald
+ma3lig
+ma5lin
+mal4li
+mal4ty
+5mania
+man5is
+man3iz
+4map
+ma5rine.
+ma5riz
+mar4ly
+mar3v
+ma5sce
+mas4e
+mas1t
+5mate
+math3
+ma3tis
+4matiza
+4m1b
+mba4t5
+m5bil
+m4b3ing
+mbi4v
+4m5c
+4me.
+2med
+4med.
+5media
+me3die
+m5e5dy
+me2g
+mel5on
+mel4t
+me2m
+mem1o3
+1men
+men4a
+men5ac
+men4de
+4mene
+men4i
+mens4
+mensu5
+3ment
+men4te
+me5on
+m5ersa
+2mes
+3mesti
+me4ta
+met3al
+me1te
+me5thi
+m4etr
+5metric
+me5trie
+me3try
+me4v
+4m1f
+2mh
+5mi.
+mi3a
+mid4a
+mid4g
+mig4
+3milia
+m5i5lie
+m4ill
+min4a
+3mind
+m5inee
+m4ingl
+min5gli
+m5ingly
+min4t
+m4inu
+miot4
+m2is
+mis4er.
+mis5l
+mis4ti
+m5istry
+4mith
+m2iz
+4mk
+4m1l
+m1m
+mma5ry
+4m1n
+mn4a
+m4nin
+mn4o
+1mo
+4mocr
+5mocratiz
+mo2d1
+mo4go
+mois2
+moi5se
+4mok
+mo5lest
+mo3me
+mon5et
+mon5ge
+moni3a
+mon4ism
+mon4ist
+mo3niz
+monol4
+mo3ny.
+mo2r
+4mora.
+mos2
+mo5sey
+mo3sp
+moth3
+m5ouf
+3mous
+mo2v
+4m1p
+mpara5
+mpa5rab
+mpar5i
+m3pet
+mphas4
+m2pi
+mpi4a
+mp5ies
+m4p1in
+m5pir
+mp5is
+mpo3ri
+mpos5ite
+m4pous
+mpov5
+mp4tr
+m2py
+4m3r
+4m1s2
+m4sh
+m5si
+4mt
+1mu
+mula5r4
+5mult
+multi3
+3mum
+mun2
+4mup
+mu4u
+4mw
+1na
+2n1a2b
+n4abu
+4nac.
+na4ca
+n5act
+nag5er.
+nak4
+na4li
+na5lia
+4nalt
+na5mit
+n2an
+nanci4
+nan4it
+nank4
+nar3c
+4nare
+nar3i
+nar4l
+n5arm
+n4as
+nas4c
+nas5ti
+n2at
+na3tal
+nato5miz
+n2au
+nau3se
+3naut
+nav4e
+4n1b4
+ncar5
+n4ces.
+n3cha
+n5cheo
+n5chil
+n3chis
+nc1in
+nc4it
+ncour5a
+n1cr
+n1cu
+n4dai
+n5dan
+n1de
+nd5est.
+ndi4b
+n5d2if
+n1dit
+n3diz
+n5duc
+ndu4r
+nd2we
+2ne.
+n3ear
+ne2b
+neb3u
+ne2c
+5neck
+2ned
+ne4gat
+neg5ativ
+5nege
+ne4la
+nel5iz
+ne5mi
+ne4mo
+1nen
+4nene
+3neo
+ne4po
+ne2q
+n1er
+nera5b
+n4erar
+n2ere
+n4er5i
+ner4r
+1nes
+2nes.
+4nesp
+2nest
+4nesw
+3netic
+ne4v
+n5eve
+ne4w
+n3f
+n4gab
+n3gel
+nge4n4e
+n5gere
+n3geri
+ng5ha
+n3gib
+ng1in
+n5git
+n4gla
+ngov4
+ng5sh
+n1gu
+n4gum
+n2gy
+4n1h4
+nha4
+nhab3
+nhe4
+3n4ia
+ni3an
+ni4ap
+ni3ba
+ni4bl
+ni4d
+ni5di
+ni4er
+ni2fi
+ni5ficat
+n5igr
+nik4
+n1im
+ni3miz
+n1in
+5nine.
+nin4g
+ni4o
+5nis.
+nis4ta
+n2it
+n4ith
+3nitio
+n3itor
+ni3tr
+n1j
+4nk2
+n5kero
+n3ket
+nk3in
+n1kl
+4n1l
+n5m
+nme4
+nmet4
+4n1n2
+nne4
+nni3al
+nni4v
+nob4l
+no3ble
+n5ocl
+4n3o2d
+3noe
+4nog
+noge4
+nois5i
+no5l4i
+5nologis
+3nomic
+n5o5miz
+no4mo
+no3my
+no4n
+non4ag
+non5i
+n5oniz
+4nop
+5nop5o5li
+nor5ab
+no4rary
+4nosc
+nos4e
+nos5t
+no5ta
+1nou
+3noun
+nov3el3
+nowl3
+n1p4
+npi4
+npre4c
+n1q
+n1r
+nru4
+2n1s2
+ns5ab
+nsati4
+ns4c
+n2se
+n4s3es
+nsid1
+nsig4
+n2sl
+ns3m
+n4soc
+ns4pe
+n5spi
+nsta5bl
+n1t
+nta4b
+nter3s
+nt2i
+n5tib
+nti4er
+nti2f
+n3tine
+n4t3ing
+nti4p
+ntrol5li
+nt4s
+ntu3me
+nu1a
+nu4d
+nu5en
+nuf4fe
+n3uin
+3nu3it
+n4um
+nu1me
+n5umi
+3nu4n
+n3uo
+nu3tr
+n1v2
+n1w4
+nym4
+nyp4
+4nz
+n3za
+4oa
+oad3
+o5a5les
+oard3
+oas4e
+oast5e
+oat5i
+ob3a3b
+o5bar
+obe4l
+o1bi
+o2bin
+ob5ing
+o3br
+ob3ul
+o1ce
+och4
+o3chet
+ocif3
+o4cil
+o4clam
+o4cod
+oc3rac
+oc5ratiz
+ocre3
+5ocrit
+octor5a
+oc3ula
+o5cure
+od5ded
+od3ic
+odi3o
+o2do4
+odor3
+od5uct.
+od5ucts
+o4el
+o5eng
+o3er
+oe4ta
+o3ev
+o2fi
+of5ite
+ofit4t
+o2g5a5r
+og5ativ
+o4gato
+o1ge
+o5gene
+o5geo
+o4ger
+o3gie
+1o1gis
+og3it
+o4gl
+o5g2ly
+3ogniz
+o4gro
+ogu5i
+1ogy
+2ogyn
+o1h2
+ohab5
+oi2
+oic3es
+oi3der
+oiff4
+oig4
+oi5let
+o3ing
+oint5er
+o5ism
+oi5son
+oist5en
+oi3ter
+o5j
+2ok
+o3ken
+ok5ie
+o1la
+o4lan
+olass4
+ol2d
+old1e
+ol3er
+o3lesc
+o3let
+ol4fi
+ol2i
+o3lia
+o3lice
+ol5id.
+o3li4f
+o5lil
+ol3ing
+o5lio
+o5lis.
+ol3ish
+o5lite
+o5litio
+o5liv
+olli4e
+ol5ogiz
+olo4r
+ol5pl
+ol2t
+ol3ub
+ol3ume
+ol3un
+o5lus
+ol2v
+o2ly
+om5ah
+oma5l
+om5atiz
+om2be
+om4bl
+o2me
+om3ena
+om5erse
+o4met
+om5etry
+o3mia
+om3ic.
+om3ica
+o5mid
+om1in
+o5mini
+5ommend
+omo4ge
+o4mon
+om3pi
+ompro5
+o2n
+on1a
+on4ac
+o3nan
+on1c
+3oncil
+2ond
+on5do
+o3nen
+on5est
+on4gu
+on1ic
+o3nio
+on1is
+o5niu
+on3key
+on4odi
+on3omy
+on3s
+onspi4
+onspir5a
+onsu4
+onten4
+on3t4i
+ontif5
+on5um
+onva5
+oo2
+ood5e
+ood5i
+oo4k
+oop3i
+o3ord
+oost5
+o2pa
+ope5d
+op1er
+3opera
+4operag
+2oph
+o5phan
+o5pher
+op3ing
+o3pit
+o5pon
+o4posi
+o1pr
+op1u
+opy5
+o1q
+o1ra
+o5ra.
+o4r3ag
+or5aliz
+or5ange
+ore5a
+o5real
+or3ei
+ore5sh
+or5est.
+orew4
+or4gu
+4o5ria
+or3ica
+o5ril
+or1in
+o1rio
+or3ity
+o3riu
+or2mi
+orn2e
+o5rof
+or3oug
+or5pe
+3orrh
+or4se
+ors5en
+orst4
+or3thi
+or3thy
+or4ty
+o5rum
+o1ry
+os3al
+os2c
+os4ce
+o3scop
+4oscopi
+o5scr
+os4i4e
+os5itiv
+os3ito
+os3ity
+osi4u
+os4l
+o2so
+os4pa
+os4po
+os2ta
+o5stati
+os5til
+os5tit
+o4tan
+otele4g
+ot3er.
+ot5ers
+o4tes
+4oth
+oth5esi
+oth3i4
+ot3ic.
+ot5ica
+o3tice
+o3tif
+o3tis
+oto5s
+ou2
+ou3bl
+ouch5i
+ou5et
+ou4l
+ounc5er
+oun2d
+ou5v
+ov4en
+over4ne
+over3s
+ov4ert
+o3vis
+oviti4
+o5v4ol
+ow3der
+ow3el
+ow5est
+ow1i
+own5i
+o4wo
+oy1a
+1pa
+pa4ca
+pa4ce
+pac4t
+p4ad
+5pagan
+p3agat
+p4ai
+pain4
+p4al
+pan4a
+pan3el
+pan4ty
+pa3ny
+pa1p
+pa4pu
+para5bl
+par5age
+par5di
+3pare
+par5el
+p4a4ri
+par4is
+pa2te
+pa5ter
+5pathic
+pa5thy
+pa4tric
+pav4
+3pay
+4p1b
+pd4
+4pe.
+3pe4a
+pear4l
+pe2c
+2p2ed
+3pede
+3pedi
+pedia4
+ped4ic
+p4ee
+pee4d
+pek4
+pe4la
+peli4e
+pe4nan
+p4enc
+pen4th
+pe5on
+p4era.
+pera5bl
+p4erag
+p4eri
+peri5st
+per4mal
+perme5
+p4ern
+per3o
+per3ti
+pe5ru
+per1v
+pe2t
+pe5ten
+pe5tiz
+4pf
+4pg
+4ph.
+phar5i
+phe3no
+ph4er
+ph4es.
+ph1ic
+5phie
+ph5ing
+5phisti
+3phiz
+ph2l
+3phob
+3phone
+5phoni
+pho4r
+4phs
+ph3t
+5phu
+1phy
+pi3a
+pian4
+pi4cie
+pi4cy
+p4id
+p5ida
+pi3de
+5pidi
+3piec
+pi3en
+pi4grap
+pi3lo
+pi2n
+p4in.
+pind4
+p4ino
+3pi1o
+pion4
+p3ith
+pi5tha
+pi2tu
+2p3k2
+1p2l2
+3plan
+plas5t
+pli3a
+pli5er
+4plig
+pli4n
+ploi4
+plu4m
+plum4b
+4p1m
+2p3n
+po4c
+5pod.
+po5em
+po3et5
+5po4g
+poin2
+5point
+poly5t
+po4ni
+po4p
+1p4or
+po4ry
+1pos
+pos1s
+p4ot
+po4ta
+5poun
+4p1p
+ppa5ra
+p2pe
+p4ped
+p5pel
+p3pen
+p3per
+p3pet
+ppo5site
+pr2
+pray4e
+5preci
+pre5co
+pre3em
+pref5ac
+pre4la
+pre3r
+p3rese
+3press
+pre5ten
+pre3v
+5pri4e
+prin4t3
+pri4s
+pris3o
+p3roca
+prof5it
+pro3l
+pros3e
+pro1t
+2p1s2
+p2se
+ps4h
+p4sib
+2p1t
+pt5a4b
+p2te
+p2th
+pti3m
+ptu4r
+p4tw
+pub3
+pue4
+puf4
+pul3c
+pu4m
+pu2n
+pur4r
+5pus
+pu2t
+5pute
+put3er
+pu3tr
+put4ted
+put4tin
+p3w
+qu2
+qua5v
+2que.
+3quer
+3quet
+2rab
+ra3bi
+rach4e
+r5acl
+raf5fi
+raf4t
+r2ai
+ra4lo
+ram3et
+r2ami
+rane5o
+ran4ge
+r4ani
+ra5no
+rap3er
+3raphy
+rar5c
+rare4
+rar5ef
+4raril
+r2as
+ration4
+rau4t
+ra5vai
+rav3el
+ra5zie
+r1b
+r4bab
+r4bag
+rbi2
+rbi4f
+r2bin
+r5bine
+rb5ing.
+rb4o
+r1c
+r2ce
+rcen4
+r3cha
+rch4er
+r4ci4b
+rc4it
+rcum3
+r4dal
+rd2i
+rdi4a
+rdi4er
+rdin4
+rd3ing
+2re.
+re1al
+re3an
+re5arr
+5reav
+re4aw
+r5ebrat
+rec5oll
+rec5ompe
+re4cre
+2r2ed
+re1de
+re3dis
+red5it
+re4fac
+re2fe
+re5fer.
+re3fi
+re4fy
+reg3is
+re5it
+re1li
+re5lu
+r4en4ta
+ren4te
+re1o
+re5pin
+re4posi
+re1pu
+r1er4
+r4eri
+rero4
+re5ru
+r4es.
+re4spi
+ress5ib
+res2t
+re5stal
+re3str
+re4ter
+re4ti4z
+re3tri
+reu2
+re5uti
+rev2
+re4val
+rev3el
+r5ev5er.
+re5vers
+re5vert
+re5vil
+rev5olu
+re4wh
+r1f
+rfu4
+r4fy
+rg2
+rg3er
+r3get
+r3gic
+rgi4n
+rg3ing
+r5gis
+r5git
+r1gl
+rgo4n
+r3gu
+rh4
+4rh.
+4rhal
+ri3a
+ria4b
+ri4ag
+r4ib
+rib3a
+ric5as
+r4ice
+4rici
+5ricid
+ri4cie
+r4ico
+rid5er
+ri3enc
+ri3ent
+ri1er
+ri5et
+rig5an
+5rigi
+ril3iz
+5riman
+rim5i
+3rimo
+rim4pe
+r2ina
+5rina.
+rin4d
+rin4e
+rin4g
+ri1o
+5riph
+riph5e
+ri2pl
+rip5lic
+r4iq
+r2is
+r4is.
+ris4c
+r3ish
+ris4p
+ri3ta3b
+r5ited.
+rit5er.
+rit5ers
+rit3ic
+ri2tu
+rit5ur
+riv5el
+riv3et
+riv3i
+r3j
+r3ket
+rk4le
+rk4lin
+r1l
+rle4
+r2led
+r4lig
+r4lis
+rl5ish
+r3lo4
+r1m
+rma5c
+r2me
+r3men
+rm5ers
+rm3ing
+r4ming.
+r4mio
+r3mit
+r4my
+r4nar
+r3nel
+r4ner
+r5net
+r3ney
+r5nic
+r1nis4
+r3nit
+r3niv
+rno4
+r4nou
+r3nu
+rob3l
+r2oc
+ro3cr
+ro4e
+ro1fe
+ro5fil
+rok2
+ro5ker
+5role.
+rom5ete
+rom4i
+rom4p
+ron4al
+ron4e
+ro5n4is
+ron4ta
+1room
+5root
+ro3pel
+rop3ic
+ror3i
+ro5ro
+ros5per
+ros4s
+ro4the
+ro4ty
+ro4va
+rov5el
+rox5
+r1p
+r4pea
+r5pent
+rp5er.
+r3pet
+rp4h4
+rp3ing
+r3po
+r1r4
+rre4c
+rre4f
+r4reo
+rre4st
+rri4o
+rri4v
+rron4
+rros4
+rrys4
+4rs2
+r1sa
+rsa5ti
+rs4c
+r2se
+r3sec
+rse4cr
+rs5er.
+rs3es
+rse5v2
+r1sh
+r5sha
+r1si
+r4si4b
+rson3
+r1sp
+r5sw
+rtach4
+r4tag
+r3teb
+rten4d
+rte5o
+r1ti
+rt5ib
+rti4d
+r4tier
+r3tig
+rtil3i
+rtil4l
+r4tily
+r4tist
+r4tiv
+r3tri
+rtroph4
+rt4sh
+ru3a
+ru3e4l
+ru3en
+ru4gl
+ru3in
+rum3pl
+ru2n
+runk5
+run4ty
+r5usc
+ruti5n
+rv4e
+rvel4i
+r3ven
+rv5er.
+r5vest
+r3vey
+r3vic
+rvi4v
+r3vo
+r1w
+ry4c
+5rynge
+ry3t
+sa2
+2s1ab
+5sack
+sac3ri
+s3act
+5sai
+salar4
+sal4m
+sa5lo
+sal4t
+3sanc
+san4de
+s1ap
+sa5ta
+5sa3tio
+sat3u
+sau4
+sa5vor
+5saw
+4s5b
+scan4t5
+sca4p
+scav5
+s4ced
+4scei
+s4ces
+sch2
+s4cho
+3s4cie
+5scin4d
+scle5
+s4cli
+scof4
+4scopy
+scour5a
+s1cu
+4s5d
+4se.
+se4a
+seas4
+sea5w
+se2c3o
+3sect
+4s4ed
+se4d4e
+s5edl
+se2g
+seg3r
+5sei
+se1le
+5self
+5selv
+4seme
+se4mol
+sen5at
+4senc
+sen4d
+s5ened
+sen5g
+s5enin
+4sentd
+4sentl
+sep3a3
+4s1er.
+s4erl
+ser4o
+4servo
+s1e4s
+se5sh
+ses5t
+5se5um
+5sev
+sev3en
+sew4i
+5sex
+4s3f
+2s3g
+s2h
+2sh.
+sh1er
+5shev
+sh1in
+sh3io
+3ship
+shiv5
+sho4
+sh5old
+shon3
+shor4
+short5
+4shw
+si1b
+s5icc
+3side.
+5sides
+5sidi
+si5diz
+4signa
+sil4e
+4sily
+2s1in
+s2ina
+5sine.
+s3ing
+1sio
+5sion
+sion5a
+si2r
+sir5a
+1sis
+3sitio
+5siu
+1siv
+5siz
+sk2
+4ske
+s3ket
+sk5ine
+sk5ing
+s1l2
+s3lat
+s2le
+slith5
+2s1m
+s3ma
+small3
+sman3
+smel4
+s5men
+5smith
+smol5d4
+s1n4
+1so
+so4ce
+soft3
+so4lab
+sol3d2
+so3lic
+5solv
+3som
+3s4on.
+sona4
+son4g
+s4op
+5sophic
+s5ophiz
+s5ophy
+sor5c
+sor5d
+4sov
+so5vi
+2spa
+5spai
+spa4n
+spen4d
+2s5peo
+2sper
+s2phe
+3spher
+spho5
+spil4
+sp5ing
+4spio
+s4ply
+s4pon
+spor4
+4spot
+squal4l
+s1r
+2ss
+s1sa
+ssas3
+s2s5c
+s3sel
+s5seng
+s4ses.
+s5set
+s1si
+s4sie
+ssi4er
+ss5ily
+s4sl
+ss4li
+s4sn
+sspend4
+ss2t
+ssur5a
+ss5w
+2st.
+s2tag
+s2tal
+stam4i
+5stand
+s4ta4p
+5stat.
+s4ted
+stern5i
+s5tero
+ste2w
+stew5a
+s3the
+st2i
+s4ti.
+s5tia
+s1tic
+5stick
+s4tie
+s3tif
+st3ing
+5stir
+s1tle
+5stock
+stom3a
+5stone
+s4top
+3store
+st4r
+s4trad
+5stratu
+s4tray
+s4trid
+4stry
+4st3w
+s2ty
+1su
+su1al
+su4b3
+su2g3
+su5is
+suit3
+s4ul
+su2m
+sum3i
+su2n
+su2r
+4sv
+sw2
+4swo
+s4y
+4syc
+3syl
+syn5o
+sy5rin
+1ta
+3ta.
+2tab
+ta5bles
+5taboliz
+4taci
+ta5do
+4taf4
+tai5lo
+ta2l
+ta5la
+tal5en
+tal3i
+4talk
+tal4lis
+ta5log
+ta5mo
+tan4de
+tanta3
+ta5per
+ta5pl
+tar4a
+4tarc
+4tare
+ta3riz
+tas4e
+ta5sy
+4tatic
+ta4tur
+taun4
+tav4
+2taw
+tax4is
+2t1b
+4tc
+t4ch
+tch5et
+4t1d
+4te.
+tead4i
+4teat
+tece4
+5tect
+2t1ed
+te5di
+1tee
+teg4
+te5ger
+te5gi
+3tel.
+teli4
+5tels
+te2ma2
+tem3at
+3tenan
+3tenc
+3tend
+4tenes
+1tent
+ten4tag
+1teo
+te4p
+te5pe
+ter3c
+5ter3d
+1teri
+ter5ies
+ter3is
+teri5za
+5ternit
+ter5v
+4tes.
+4tess
+t3ess.
+teth5e
+3teu
+3tex
+4tey
+2t1f
+4t1g
+2th.
+than4
+th2e
+4thea
+th3eas
+the5at
+the3is
+3thet
+th5ic.
+th5ica
+4thil
+5think
+4thl
+th5ode
+5thodic
+4thoo
+thor5it
+tho5riz
+2ths
+1tia
+ti4ab
+ti4ato
+2ti2b
+4tick
+t4ico
+t4ic1u
+5tidi
+3tien
+tif2
+ti5fy
+2tig
+5tigu
+till5in
+1tim
+4timp
+tim5ul
+2t1in
+t2ina
+3tine.
+3tini
+1tio
+ti5oc
+tion5ee
+5tiq
+ti3sa
+3tise
+tis4m
+ti5so
+tis4p
+5tistica
+ti3tl
+ti4u
+1tiv
+tiv4a
+1tiz
+ti3za
+ti3zen
+2tl
+t5la
+tlan4
+3tle.
+3tled
+3tles.
+t5let.
+t5lo
+4t1m
+tme4
+2t1n2
+1to
+to3b
+to5crat
+4todo
+2tof
+to2gr
+to5ic
+to2ma
+tom4b
+to3my
+ton4ali
+to3nat
+4tono
+4tony
+to2ra
+to3rie
+tor5iz
+tos2
+5tour
+4tout
+to3war
+4t1p
+1tra
+tra3b
+tra5ch
+traci4
+trac4it
+trac4te
+tras4
+tra5ven
+trav5es5
+tre5f
+tre4m
+trem5i
+5tria
+tri5ces
+5tricia
+4trics
+2trim
+tri4v
+tro5mi
+tron5i
+4trony
+tro5phe
+tro3sp
+tro3v
+tru5i
+trus4
+4t1s2
+t4sc
+tsh4
+t4sw
+4t3t2
+t4tes
+t5to
+ttu4
+1tu
+tu1a
+tu3ar
+tu4bi
+tud2
+4tue
+4tuf4
+5tu3i
+3tum
+tu4nis
+2t3up.
+3ture
+5turi
+tur3is
+tur5o
+tu5ry
+3tus
+4tv
+tw4
+4t1wa
+twis4
+4two
+1ty
+4tya
+2tyl
+type3
+ty5ph
+4tz
+tz4e
+4uab
+uac4
+ua5na
+uan4i
+uar5ant
+uar2d
+uar3i
+uar3t
+u1at
+uav4
+ub4e
+u4bel
+u3ber
+u4bero
+u1b4i
+u4b5ing
+u3ble.
+u3ca
+uci4b
+uc4it
+ucle3
+u3cr
+u3cu
+u4cy
+ud5d
+ud3er
+ud5est
+udev4
+u1dic
+ud3ied
+ud3ies
+ud5is
+u5dit
+u4don
+ud4si
+u4du
+u4ene
+uens4
+uen4te
+uer4il
+3ufa
+u3fl
+ugh3en
+ug5in
+2ui2
+uil5iz
+ui4n
+u1ing
+uir4m
+uita4
+uiv3
+uiv4er.
+u5j
+4uk
+u1la
+ula5b
+u5lati
+ulch4
+5ulche
+ul3der
+ul4e
+u1len
+ul4gi
+ul2i
+u5lia
+ul3ing
+ul5ish
+ul4lar
+ul4li4b
+ul4lis
+4ul3m
+u1l4o
+4uls
+uls5es
+ul1ti
+ultra3
+4ultu
+u3lu
+ul5ul
+ul5v
+um5ab
+um4bi
+um4bly
+u1mi
+u4m3ing
+umor5o
+um2p
+unat4
+u2ne
+un4er
+u1ni
+un4im
+u2nin
+un5ish
+uni3v
+un3s4
+un4sw
+unt3ab
+un4ter.
+un4tes
+unu4
+un5y
+un5z
+u4ors
+u5os
+u1ou
+u1pe
+uper5s
+u5pia
+up3ing
+u3pl
+up3p
+upport5
+upt5ib
+uptu4
+u1ra
+4ura.
+u4rag
+u4ras
+ur4be
+urc4
+ur1d
+ure5at
+ur4fer
+ur4fr
+u3rif
+uri4fic
+ur1in
+u3rio
+u1rit
+ur3iz
+ur2l
+url5ing.
+ur4no
+uros4
+ur4pe
+ur4pi
+urs5er
+ur5tes
+ur3the
+urti4
+ur4tie
+u3ru
+2us
+u5sad
+u5san
+us4ap
+usc2
+us3ci
+use5a
+u5sia
+u3sic
+us4lin
+us1p
+us5sl
+us5tere
+us1tr
+u2su
+usur4
+uta4b
+u3tat
+4ute.
+4utel
+4uten
+uten4i
+4u1t2i
+uti5liz
+u3tine
+ut3ing
+ution5a
+u4tis
+5u5tiz
+u4t1l
+ut5of
+uto5g
+uto5matic
+u5ton
+u4tou
+uts4
+u3u
+uu4m
+u1v2
+uxu3
+uz4e
+1va
+5va.
+2v1a4b
+vac5il
+vac3u
+vag4
+va4ge
+va5lie
+val5o
+val1u
+va5mo
+va5niz
+va5pi
+var5ied
+3vat
+4ve.
+4ved
+veg3
+v3el.
+vel3li
+ve4lo
+v4ely
+ven3om
+v5enue
+v4erd
+5vere.
+v4erel
+v3eren
+ver5enc
+v4eres
+ver3ie
+vermi4n
+3verse
+ver3th
+v4e2s
+4ves.
+ves4te
+ve4te
+vet3er
+ve4ty
+vi5ali
+5vian
+5vide.
+5vided
+4v3iden
+5vides
+5vidi
+v3if
+vi5gn
+vik4
+2vil
+5vilit
+v3i3liz
+v1in
+4vi4na
+v2inc
+vin5d
+4ving
+vio3l
+v3io4r
+vi1ou
+vi4p
+vi5ro
+vis3it
+vi3so
+vi3su
+4viti
+vit3r
+4vity
+3viv
+5vo.
+voi4
+3vok
+vo4la
+v5ole
+5volt
+3volv
+vom5i
+vor5ab
+vori4
+vo4ry
+vo4ta
+4votee
+4vv4
+v4y
+w5abl
+2wac
+wa5ger
+wag5o
+wait5
+w5al.
+wam4
+war4t
+was4t
+wa1te
+wa5ver
+w1b
+wea5rie
+weath3
+wed4n
+weet3
+wee5v
+wel4l
+w1er
+west3
+w3ev
+whi4
+wi2
+wil2
+will5in
+win4de
+win4g
+wir4
+3wise
+with3
+wiz5
+w4k
+wl4es
+wl3in
+w4no
+1wo2
+wom1
+wo5ven
+w5p
+wra4
+wri4
+writa4
+w3sh
+ws4l
+ws4pe
+w5s4t
+4wt
+wy4
+x1a
+xac5e
+x4ago
+xam3
+x4ap
+xas5
+x3c2
+x1e
+xe4cuto
+x2ed
+xer4i
+xe5ro
+x1h
+xhi2
+xhil5
+xhu4
+x3i
+xi5a
+xi5c
+xi5di
+x4ime
+xi5miz
+x3o
+x4ob
+x3p
+xpan4d
+xpecto5
+xpe3d
+x1t2
+x3ti
+x1u
+xu3a
+xx4
+y5ac
+3yar4
+y5at
+y1b
+y1c
+y2ce
+yc5er
+y3ch
+ych4e
+ycom4
+ycot4
+y1d
+y5ee
+y1er
+y4erf
+yes4
+ye4t
+y5gi
+4y3h
+y1i
+y3la
+ylla5bl
+y3lo
+y5lu
+ymbol5
+yme4
+ympa3
+yn3chr
+yn5d
+yn5g
+yn5ic
+5ynx
+y1o4
+yo5d
+y4o5g
+yom4
+yo5net
+y4ons
+y4os
+y4ped
+yper5
+yp3i
+y3po
+y4poc
+yp2ta
+y5pu
+yra5m
+yr5ia
+y3ro
+yr4r
+ys4c
+y3s2e
+ys3ica
+ys3io
+3ysis
+y4so
+yss4
+ys1t
+ys3ta
+ysur4
+y3thin
+yt3ic
+y1w
+za1
+z5a2b
+zar2
+4zb
+2ze
+ze4n
+ze4p
+z1er
+ze3ro
+zet4
+2z1i
+z4il
+z4is
+5zl
+4zm
+1zo
+zo4m
+zo5ol
+zte4
+4z1z2
+z4zy
+Á1Á
+Á1Å
+Á1É
+Á1Ï
+Á1Õ
+Á1Ù
+Á1Ü
+Á1À
+Á1Ñ
+Å1Á
+Å1Å
+Å1É
+Å1Ï
+Å1Õ
+Å1Ù
+Å1Ü
+Å1À
+Å1Ñ
+É1Á
+É1Å
+É1É
+É1Ï
+É1Õ
+É1Ù
+É1Ü
+É1À
+É1Ñ
+Ï1Á
+Ï1Å
+Ï1É
+Ï1Ï
+Ï1Õ
+Ï1Ù
+Ï1Ü
+Ï1À
+Ï1Ñ
+Õ1Á
+Õ1Å
+Õ1É
+Õ1Ï
+Õ1Õ
+Õ1Ù
+Õ1Ü
+Õ1À
+Õ1Ñ
+Ù1Á
+Ù1Å
+Ù1É
+Ù1Ï
+Ù1Õ
+Ù1Ù
+Ù1Ü
+Ù1À
+Ù1Ñ
+Ü1Á
+Ü1Å
+Ü1É
+Ü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
+.Ä×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
+.ÓÇÒ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
+1ÂÁ
+1ÂÅ
+1ÂÉ
+1ÂÏ
+1ÂÕ
+1ÂÙ
+1ÂÑ
+1×Á
+1×Å
+1×É
+1×Ï
+1×Õ
+1×Ù
+1×Ñ
+1ÇÁ
+1ÇÅ
+1ÇÉ
+1ÇÏ
+1ÇÕ
+1ÄÁ
+1ÄÅ
+1ÄÉ
+1ÄÏ
+1ÄÕ
+1ÄÙ
+1ÄÀ
+1ÄÑ
+1ÖÁ
+1ÖÅ
+1ÖÉ
+1ÖÏ
+1ÖÕ
+1ÖÙ
+1ÚÁ
+1ÚÅ
+1ÚÉ
+1ÚÏ
+1ÚÕ
+1ÚÙ
+1ÚÑ
+1ËÁ
+1ËÅ
+1ËÉ
+1ËÏ
+1ËÕ
+1ÌÁ
+1ÌÅ
+1ÌÉ
+1ÌÏ
+1ÌÕ
+1ÌÙ
+1ÌÀ
+1ÌÑ
+1ÍÁ
+1ÍÅ
+1ÍÉ
+1ÍÏ
+1ÍÕ
+1ÍÙ
+1ÍÑ
+1ÎÁ
+1ÎÅ
+1ÎÉ
+1ÎÏ
+1ÎÕ
+1ÎÙ
+1ÎÀ
+1ÎÑ
+1ÐÁ
+1ÐÅ
+1ÐÉ
+1ÐÏ
+1ÐÕ
+1ÐÙ
+1ÐÑ
+1ÒÁ
+1ÒÅ
+1ÒÉ
+1ÒÏ
+1ÒÕ
+1ÒÙ
+1ÒÀ
+1ÒÑ
+1ÓÁ
+1ÓÅ
+1ÓÉ
+1ÓÏ
+1ÓÕ
+1ÓÙ
+1ÓÑ
+1ÔÁ
+1ÔÅ
+1ÔÉ
+1ÔÏ
+1ÔÕ
+1ÔÙ
+1ÔÀ
+1ÔÑ
+1ÆÁ
+1ÆÅ
+1ÆÉ
+1ÆÏ
+1ÆÕ
+1ÆÙ
+1ÈÁ
+1ÈÅ
+1ÈÉ
+1ÈÏ
+1ÈÕ
+1ÃÁ
+1ÃÅ
+1ÃÉ
+1ÃÏ
+1ÃÕ
+1ÃÙ
+1ÞÁ
+1ÞÅ
+1ÞÉ
+1ÞÏ
+1ÞÕ
+1ÛÁ
+1ÛÅ
+1ÛÉ
+1ÛÏ
+1ÛÕ
+1ÝÁ
+1ÝÅ
+1ÝÉ
+1ÝÏ
diff --git a/gnu/usr.bin/groff/troff/input.cc b/gnu/usr.bin/groff/troff/input.cc
new file mode 100644
index 0000000..632a8fb
--- /dev/null
+++ b/gnu/usr.bin/groff/troff/input.cc
@@ -0,0 +1,5951 @@
+// -*- C++ -*-
+/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
+ Written by James Clark (jjc@jclark.com)
+
+This file is part of groff.
+
+groff is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
+
+groff is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License along
+with groff; see the file COPYING. If not, write to the Free Software
+Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "troff.h"
+#include "symbol.h"
+#include "dictionary.h"
+#include "hvunits.h"
+#include "env.h"
+#include "request.h"
+#include "node.h"
+#include "reg.h"
+#include "token.h"
+#include "div.h"
+#include "charinfo.h"
+#include "font.h"
+#include "searchpath.h"
+#include "macropath.h"
+#include "defs.h"
+
+// Needed for getpid().
+#include "posix.h"
+
+#ifdef ISATTY_MISSING
+#undef isatty
+#define isatty(n) (1)
+#else /* not ISATTY_MISSING */
+#ifndef isatty
+extern "C" {
+ int isatty(int);
+}
+#endif /* not isatty */
+#endif /* not ISATTY_MISSING */
+
+#define USAGE_EXIT_CODE 1
+#define MACRO_PREFIX "tmac."
+#define STARTUP_FILE "troffrc"
+#define DEFAULT_INPUT_STACK_LIMIT 1000
+
+#ifndef DEFAULT_WARNING_MASK
+// warnings that are enabled by default
+#define DEFAULT_WARNING_MASK \
+ (WARN_CHAR|WARN_NUMBER|WARN_BREAK|WARN_SPACE|WARN_FONT)
+#endif
+
+// initial size of buffer for reading names; expanded as necessary
+#define ABUF_SIZE 16
+
+#ifdef COLUMN
+void init_column_requests();
+#endif /* COLUMN */
+
+static node *read_draw_node();
+void handle_first_page_transition();
+static void push_token(const token &);
+void copy_file();
+#ifdef COLUMN
+void vjustify();
+#endif /* COLUMN */
+void transparent();
+void transparent_file();
+
+const char *program_name = 0;
+token tok;
+int break_flag = 0;
+static int backtrace_flag = 0;
+#ifndef POPEN_MISSING
+char *pipe_command = 0;
+#endif
+charinfo *charset_table[256];
+
+static int warning_mask = DEFAULT_WARNING_MASK;
+static int inhibit_errors = 0;
+static int ignoring = 0;
+
+static void enable_warning(const char *);
+static void disable_warning(const char *);
+
+static int escape_char = '\\';
+static symbol end_macro_name;
+static int compatible_flag = 0;
+int ascii_output_flag = 0;
+int suppress_output_flag = 0;
+
+int tcommand_flag = 0;
+
+static int get_copy(node**, int = 0);
+static void copy_mode_error(const char *,
+ const errarg & = empty_errarg,
+ const errarg & = empty_errarg,
+ const errarg & = empty_errarg);
+
+static symbol read_escape_name();
+static void interpolate_string(symbol);
+static void interpolate_macro(symbol);
+static void interpolate_number_format(symbol);
+static void interpolate_environment_variable(symbol);
+
+static void interpolate_arg(symbol);
+static request_or_macro *lookup_request(symbol);
+static int get_delim_number(units *, int);
+static int get_delim_number(units *, int, units);
+static int get_line_arg(units *res, int si, charinfo **cp);
+static int read_size(int *);
+static symbol get_delim_name();
+static void init_registers();
+
+struct input_iterator;
+input_iterator *make_temp_iterator(const char *);
+const char *input_char_description(int);
+
+const int ESCAPE_QUESTION = 015;
+const int BEGIN_TRAP = 016;
+const int END_TRAP = 017;
+const int PAGE_EJECTOR = 020;
+const int ESCAPE_NEWLINE = 021;
+const int ESCAPE_AMPERSAND = 022;
+const int ESCAPE_UNDERSCORE = 023;
+const int ESCAPE_BAR = 024;
+const int ESCAPE_CIRCUMFLEX = 025;
+const int ESCAPE_LEFT_BRACE = 026;
+const int ESCAPE_RIGHT_BRACE = 027;
+const int ESCAPE_LEFT_QUOTE = 030;
+const int ESCAPE_RIGHT_QUOTE = 031;
+const int ESCAPE_HYPHEN = 032;
+const int ESCAPE_BANG = 033;
+const int ESCAPE_c = 034;
+const int ESCAPE_e = 035;
+const int ESCAPE_PERCENT = 036;
+const int ESCAPE_SPACE = 037;
+
+const int TITLE_REQUEST = 0200;
+const int COPY_FILE_REQUEST = 0201;
+const int TRANSPARENT_FILE_REQUEST = 0202;
+#ifdef COLUMN
+const int VJUSTIFY_REQUEST = 0203;
+#endif /* COLUMN */
+const int ESCAPE_E = 0204;
+const int LAST_PAGE_EJECTOR = 0205;
+const int ESCAPE_RIGHT_PARENTHESIS = 0206;
+
+void set_escape_char()
+{
+ if (has_arg()) {
+ if (tok.ch() == 0) {
+ error("bad escape character");
+ escape_char = '\\';
+ }
+ else
+ escape_char = tok.ch();
+ }
+ else
+ escape_char = '\\';
+ skip_line();
+}
+
+void escape_off()
+{
+ escape_char = 0;
+ skip_line();
+}
+
+class input_iterator {
+public:
+ input_iterator();
+ virtual ~input_iterator();
+ int get(node **);
+ friend class input_stack;
+protected:
+ const unsigned char *ptr;
+ const unsigned char *eptr;
+ input_iterator *next;
+private:
+ virtual int fill(node **);
+ virtual int peek();
+ virtual int has_args() { return 0; }
+ virtual int nargs() { return 0; }
+ virtual input_iterator *get_arg(int) { return NULL; }
+ virtual int get_location(int, const char **, int *)
+ { return 0; }
+ virtual void backtrace() {}
+ virtual int set_location(const char *, int)
+ { return 0; }
+ virtual int next_file(FILE *, const char *) { return 0; }
+ virtual void shift(int) {}
+ virtual int is_boundary();
+ virtual int internal_level() { return 0; }
+ virtual int is_file() { return 0; }
+};
+
+input_iterator::input_iterator()
+: ptr(0), eptr(0)
+{
+}
+
+input_iterator::~input_iterator()
+{
+}
+
+int input_iterator::fill(node **)
+{
+ return EOF;
+}
+
+int input_iterator::peek()
+{
+ return EOF;
+}
+
+int input_iterator::is_boundary()
+{
+ return 0;
+}
+
+inline int input_iterator::get(node **p)
+{
+ return ptr < eptr ? *ptr++ : fill(p);
+}
+
+
+class input_boundary : public input_iterator {
+public:
+ int is_boundary() { return 1; }
+};
+
+class file_iterator : public input_iterator {
+ FILE *fp;
+ int lineno;
+ const char *filename;
+ int popened;
+ int newline_flag;
+ enum { BUF_SIZE = 512 };
+ unsigned char buf[BUF_SIZE];
+ void close();
+public:
+ file_iterator(FILE *, const char *, int = 0);
+ ~file_iterator();
+ int fill(node **);
+ int peek();
+ int get_location(int, const char **, int *);
+ void backtrace();
+ int set_location(const char *, int);
+ int next_file(FILE *, const char *);
+ int is_file();
+};
+
+file_iterator::file_iterator(FILE *f, const char *fn, int po)
+: fp(f), filename(fn), lineno(1), newline_flag(0), popened(po)
+{
+}
+
+file_iterator::~file_iterator()
+{
+ close();
+}
+
+void file_iterator::close()
+{
+ if (fp == stdin)
+ clearerr(stdin);
+#ifndef POPEN_MISSING
+ else if (popened)
+ pclose(fp);
+#endif /* not POPEN_MISSING */
+ else
+ fclose(fp);
+}
+
+int file_iterator::is_file()
+{
+ return 1;
+}
+
+int file_iterator::next_file(FILE *f, const char *s)
+{
+ close();
+ filename = s;
+ fp = f;
+ lineno = 1;
+ newline_flag = 0;
+ popened = 0;
+ ptr = 0;
+ eptr = 0;
+ return 1;
+}
+
+int file_iterator::fill(node **)
+{
+ if (newline_flag)
+ lineno++;
+ newline_flag = 0;
+ unsigned char *p = buf;
+ ptr = p;
+ unsigned char *e = p + BUF_SIZE;
+ while (p < e) {
+ int c = getc(fp);
+ if (c == EOF)
+ break;
+ if (illegal_input_char(c))
+ warning(WARN_INPUT, "illegal input character code %1", int(c));
+ else {
+ *p++ = c;
+ if (c == '\n') {
+ newline_flag = 1;
+ break;
+ }
+ }
+ }
+ if (p > buf) {
+ eptr = p;
+ return *ptr++;
+ }
+ else {
+ eptr = p;
+ return EOF;
+ }
+}
+
+int file_iterator::peek()
+{
+ int c = getc(fp);
+ while (illegal_input_char(c)) {
+ warning(WARN_INPUT, "illegal input character code %1", int(c));
+ c = getc(fp);
+ }
+ if (c != EOF)
+ ungetc(c, fp);
+ return c;
+}
+
+int file_iterator::get_location(int /*allow_macro*/,
+ const char **filenamep, int *linenop)
+{
+ *linenop = lineno;
+ if (filename != 0 && strcmp(filename, "-") == 0)
+ *filenamep = "<standard input>";
+ else
+ *filenamep = filename;
+ return 1;
+}
+
+void file_iterator::backtrace()
+{
+ errprint("%1:%2: backtrace: %3 `%1'\n", filename, lineno,
+ popened ? "process" : "file");
+}
+
+int file_iterator::set_location(const char *f, int ln)
+{
+ if (f)
+ filename = f;
+ lineno = ln;
+ return 1;
+}
+
+input_iterator nil_iterator;
+
+class input_stack {
+public:
+ static int get(node **);
+ static int peek();
+ static void push(input_iterator *);
+ static input_iterator *get_arg(int);
+ static int nargs();
+ static int get_location(int, const char **, int *);
+ static int set_location(const char *, int);
+ static void backtrace();
+ static void backtrace_all();
+ static void next_file(FILE *, const char *);
+ static void end_file();
+ static void shift(int n);
+ static void add_boundary();
+ static void remove_boundary();
+ static int get_level();
+ static void clear();
+
+ static int limit;
+private:
+ static input_iterator *top;
+ static int level;
+
+ static int finish_get(node **);
+ static int finish_peek();
+};
+
+input_iterator *input_stack::top = &nil_iterator;
+int input_stack::level = 0;
+int input_stack::limit = DEFAULT_INPUT_STACK_LIMIT;
+
+inline int input_stack::get_level()
+{
+ return level + top->internal_level();
+}
+
+inline int input_stack::get(node **np)
+{
+ return (top->ptr < top->eptr) ? *top->ptr++ : finish_get(np);
+}
+
+int input_stack::finish_get(node **np)
+{
+ for (;;) {
+ int c = top->fill(np);
+ if (c != EOF || top->is_boundary())
+ return c;
+ if (top == &nil_iterator)
+ break;
+ input_iterator *tem = top;
+ top = top->next;
+ level--;
+ delete tem;
+ if (top->ptr < top->eptr)
+ return *top->ptr++;
+ }
+ assert(level == 0);
+ return EOF;
+}
+
+inline int input_stack::peek()
+{
+ return (top->ptr < top->eptr) ? *top->ptr : finish_peek();
+}
+
+int input_stack::finish_peek()
+{
+ for (;;) {
+ int c = top->peek();
+ if (c != EOF || top->is_boundary())
+ return c;
+ if (top == &nil_iterator)
+ break;
+ input_iterator *tem = top;
+ top = top->next;
+ level--;
+ delete tem;
+ if (top->ptr < top->eptr)
+ return *top->ptr;
+ }
+ assert(level == 0);
+ return EOF;
+}
+
+void input_stack::add_boundary()
+{
+ push(new input_boundary);
+}
+
+void input_stack::remove_boundary()
+{
+ assert(top->is_boundary());
+ input_iterator *temp = top->next;
+ delete top;
+ top = temp;
+ level--;
+}
+
+void input_stack::push(input_iterator *in)
+{
+ if (in == 0)
+ return;
+ if (++level > limit && limit > 0)
+ fatal("input stack limit exceeded (probable infinite loop)");
+ in->next = top;
+ top = in;
+}
+
+input_iterator *input_stack::get_arg(int i)
+{
+ input_iterator *p;
+ for (p = top; p != NULL; p = p->next)
+ if (p->has_args())
+ return p->get_arg(i);
+ return 0;
+}
+
+void input_stack::shift(int n)
+{
+ for (input_iterator *p = top; p; p = p->next)
+ if (p->has_args()) {
+ p->shift(n);
+ return;
+ }
+}
+
+int input_stack::nargs()
+{
+ for (input_iterator *p =top; p != 0; p = p->next)
+ if (p->has_args())
+ return p->nargs();
+ return 0;
+}
+
+int input_stack::get_location(int allow_macro, const char **filenamep, int *linenop)
+{
+ for (input_iterator *p = top; p; p = p->next)
+ if (p->get_location(allow_macro, filenamep, linenop))
+ return 1;
+ return 0;
+}
+
+void input_stack::backtrace()
+{
+ const char *f;
+ int n;
+ // only backtrace down to (not including) the topmost file
+ for (input_iterator *p = top;
+ p && !p->get_location(0, &f, &n);
+ p = p->next)
+ p->backtrace();
+}
+
+void input_stack::backtrace_all()
+{
+ for (input_iterator *p = top; p; p = p->next)
+ p->backtrace();
+}
+
+int input_stack::set_location(const char *filename, int lineno)
+{
+ for (input_iterator *p = top; p; p = p->next)
+ if (p->set_location(filename, lineno))
+ return 1;
+ return 0;
+}
+
+void input_stack::next_file(FILE *fp, const char *s)
+{
+ for (input_iterator **pp = &top; *pp != &nil_iterator; pp = &(*pp)->next)
+ if ((*pp)->next_file(fp, s))
+ return;
+ if (++level > limit && limit > 0)
+ fatal("input stack limit exceeded");
+ *pp = new file_iterator(fp, s);
+ (*pp)->next = &nil_iterator;
+}
+
+void input_stack::end_file()
+{
+ for (input_iterator **pp = &top; *pp != &nil_iterator; pp = &(*pp)->next)
+ if ((*pp)->is_file()) {
+ input_iterator *tem = *pp;
+ *pp = (*pp)->next;
+ delete tem;
+ level--;
+ return;
+ }
+}
+
+void input_stack::clear()
+{
+ int nboundaries = 0;
+ while (top != &nil_iterator) {
+ if (top->is_boundary())
+ nboundaries++;
+ input_iterator *tem = top;
+ top = top->next;
+ level--;
+ delete tem;
+ }
+ // Keep while_request happy.
+ for (; nboundaries > 0; --nboundaries)
+ add_boundary();
+}
+
+void backtrace_request()
+{
+ input_stack::backtrace_all();
+ fflush(stderr);
+ skip_line();
+}
+
+void next_file()
+{
+ symbol nm = get_long_name(0);
+ while (!tok.newline() && !tok.eof())
+ tok.next();
+ if (nm.is_null())
+ input_stack::end_file();
+ else {
+ errno = 0;
+ FILE *fp = fopen(nm.contents(), "r");
+ if (!fp)
+ error("can't open `%1': %2", nm.contents(), strerror(errno));
+ else
+ input_stack::next_file(fp, nm.contents());
+ }
+ tok.next();
+}
+
+void shift()
+{
+ int n;
+ if (!has_arg() || !get_integer(&n))
+ n = 1;
+ input_stack::shift(n);
+ skip_line();
+}
+
+static int get_char_for_escape_name()
+{
+ int c = get_copy(NULL);
+ switch (c) {
+ case EOF:
+ copy_mode_error("end of input in escape name");
+ return '\0';
+ default:
+ if (!illegal_input_char(c))
+ break;
+ // fall through
+ case ' ':
+ case '\n':
+ case '\t':
+ case '\001':
+ case '\b':
+ copy_mode_error("%1 is not allowed in an escape name",
+ input_char_description(c));
+ return '\0';
+ }
+ return c;
+}
+
+static symbol read_two_char_escape_name()
+{
+ char buf[3];
+ buf[0] = get_char_for_escape_name();
+ if (buf[0] != '\0') {
+ buf[1] = get_char_for_escape_name();
+ if (buf[1] == '\0')
+ buf[0] = 0;
+ else
+ buf[2] = 0;
+ }
+ return symbol(buf);
+}
+
+static symbol read_long_escape_name()
+{
+ int start_level = input_stack::get_level();
+ char abuf[ABUF_SIZE];
+ char *buf = abuf;
+ int buf_size = ABUF_SIZE;
+ int i = 0;
+ for (;;) {
+ int c = get_char_for_escape_name();
+ if (c == 0) {
+ if (buf != abuf)
+ a_delete buf;
+ return NULL_SYMBOL;
+ }
+ if (i + 2 > buf_size) {
+ if (buf == abuf) {
+ buf = new char [ABUF_SIZE*2];
+ memcpy(buf, abuf, buf_size);
+ buf_size = ABUF_SIZE*2;
+ }
+ else {
+ char *old_buf = buf;
+ buf = new char[buf_size*2];
+ memcpy(buf, old_buf, buf_size);
+ buf_size *= 2;
+ a_delete old_buf;
+ }
+ }
+ if (c == ']' && input_stack::get_level() == start_level)
+ break;
+ buf[i++] = c;
+ }
+ buf[i] = 0;
+ if (buf == abuf) {
+ if (i == 0) {
+ copy_mode_error("empty escape name");
+ return NULL_SYMBOL;
+ }
+ return symbol(abuf);
+ }
+ else {
+ symbol s(buf);
+ a_delete buf;
+ return s;
+ }
+}
+
+static symbol read_escape_name()
+{
+ int c = get_char_for_escape_name();
+ if (c == 0)
+ return NULL_SYMBOL;
+ if (c == '(')
+ return read_two_char_escape_name();
+ if (c == '[' && !compatible_flag)
+ return read_long_escape_name();
+ char buf[2];
+ buf[0] = c;
+ buf[1] = '\0';
+ return symbol(buf);
+}
+
+static symbol read_increment_and_escape_name(int *incp)
+{
+ int c = get_char_for_escape_name();
+ switch (c) {
+ case 0:
+ *incp = 0;
+ return NULL_SYMBOL;
+ case '(':
+ *incp = 0;
+ return read_two_char_escape_name();
+ case '+':
+ *incp = 1;
+ return read_escape_name();
+ case '-':
+ *incp = -1;
+ return read_escape_name();
+ case '[':
+ if (!compatible_flag) {
+ *incp = 0;
+ return read_long_escape_name();
+ }
+ break;
+ }
+ *incp = 0;
+ char buf[2];
+ buf[0] = c;
+ buf[1] = '\0';
+ return symbol(buf);
+}
+
+static int get_copy(node **nd, int defining)
+{
+ for (;;) {
+ int c = input_stack::get(nd);
+ if (c == ESCAPE_NEWLINE) {
+ if (defining)
+ return c;
+ do {
+ c = input_stack::get(nd);
+ } while (c == ESCAPE_NEWLINE);
+ }
+ if (c != escape_char || escape_char <= 0)
+ return c;
+ c = input_stack::peek();
+ switch(c) {
+ case 0:
+ return escape_char;
+ case '"':
+ (void)input_stack::get(NULL);
+ while ((c = input_stack::get(NULL)) != '\n' && c != EOF)
+ ;
+ return c;
+ case '#': // Like \" but newline is ignored.
+ (void)input_stack::get(NULL);
+ while ((c = input_stack::get(NULL)) != '\n')
+ if (c == EOF)
+ return EOF;
+ break;
+ case '$':
+ {
+ (void)input_stack::get(NULL);
+ symbol s = read_escape_name();
+ if (!s.is_null())
+ interpolate_arg(s);
+ break;
+ }
+ case '*':
+ {
+ (void)input_stack::get(NULL);
+ symbol s = read_escape_name();
+ if (!s.is_null())
+ interpolate_string(s);
+ break;
+ }
+ case 'a':
+ (void)input_stack::get(NULL);
+ return '\001';
+ case 'e':
+ (void)input_stack::get(NULL);
+ return ESCAPE_e;
+ case 'E':
+ (void)input_stack::get(NULL);
+ return ESCAPE_E;
+ case 'n':
+ {
+ (void)input_stack::get(NULL);
+ int inc;
+ symbol s = read_increment_and_escape_name(&inc);
+ if (!s.is_null())
+ interpolate_number_reg(s, inc);
+ break;
+ }
+ case 'g':
+ {
+ (void)input_stack::get(NULL);
+ symbol s = read_escape_name();
+ if (!s.is_null())
+ interpolate_number_format(s);
+ break;
+ }
+ case 't':
+ (void)input_stack::get(NULL);
+ return '\t';
+ case 'V':
+ {
+ (void)input_stack::get(NULL);
+ symbol s = read_escape_name();
+ if (!s.is_null())
+ interpolate_environment_variable(s);
+ break;
+ }
+ case '\n':
+ (void)input_stack::get(NULL);
+ if (defining)
+ return ESCAPE_NEWLINE;
+ break;
+ case ' ':
+ (void)input_stack::get(NULL);
+ return ESCAPE_SPACE;
+ case '|':
+ (void)input_stack::get(NULL);
+ return ESCAPE_BAR;
+ case '^':
+ (void)input_stack::get(NULL);
+ return ESCAPE_CIRCUMFLEX;
+ case '{':
+ (void)input_stack::get(NULL);
+ return ESCAPE_LEFT_BRACE;
+ case '}':
+ (void)input_stack::get(NULL);
+ return ESCAPE_RIGHT_BRACE;
+ case '`':
+ (void)input_stack::get(NULL);
+ return ESCAPE_LEFT_QUOTE;
+ case '\'':
+ (void)input_stack::get(NULL);
+ return ESCAPE_RIGHT_QUOTE;
+ case '-':
+ (void)input_stack::get(NULL);
+ return ESCAPE_HYPHEN;
+ case '_':
+ (void)input_stack::get(NULL);
+ return ESCAPE_UNDERSCORE;
+ case 'c':
+ (void)input_stack::get(NULL);
+ return ESCAPE_c;
+ case '!':
+ (void)input_stack::get(NULL);
+ return ESCAPE_BANG;
+ case '?':
+ (void)input_stack::get(NULL);
+ return ESCAPE_QUESTION;
+ case '&':
+ (void)input_stack::get(NULL);
+ return ESCAPE_AMPERSAND;
+ case ')':
+ (void)input_stack::get(NULL);
+ return ESCAPE_RIGHT_PARENTHESIS;
+ case '.':
+ (void)input_stack::get(NULL);
+ return c;
+ case '%':
+ (void)input_stack::get(NULL);
+ return ESCAPE_PERCENT;
+ default:
+ if (c == escape_char) {
+ (void)input_stack::get(NULL);
+ return c;
+ }
+ else
+ return escape_char;
+ }
+ }
+}
+
+class non_interpreted_char_node : public node {
+ unsigned char c;
+public:
+ non_interpreted_char_node(unsigned char);
+ node *copy();
+ int interpret(macro *);
+ int same(node *);
+ const char *type();
+};
+
+int non_interpreted_char_node::same(node *nd)
+{
+ return c == ((non_interpreted_char_node *)nd)->c;
+}
+
+const char *non_interpreted_char_node::type()
+{
+ return "non_interpreted_char_node";
+}
+
+non_interpreted_char_node::non_interpreted_char_node(unsigned char n) : c(n)
+{
+ assert(n != 0);
+}
+
+node *non_interpreted_char_node::copy()
+{
+ return new non_interpreted_char_node(c);
+}
+
+int non_interpreted_char_node::interpret(macro *mac)
+{
+ mac->append(c);
+ return 1;
+}
+
+static void do_width();
+static node *do_non_interpreted();
+static node *do_special();
+static void do_register();
+
+static node *do_overstrike()
+{
+ token start;
+ overstrike_node *on = new overstrike_node;
+ start.next();
+ tok.next();
+ while (tok != start) {
+ if (tok.newline() || tok.eof()) {
+ warning(WARN_DELIM, "missing closing delimiter");
+ break;
+ }
+ charinfo *ci = tok.get_char(1);
+ if (ci) {
+ node *n = curenv->make_char_node(ci);
+ if (n)
+ on->overstrike(n);
+ }
+ tok.next();
+ }
+ return on;
+}
+
+static node *do_bracket()
+{
+ token start;
+ bracket_node *bn = new bracket_node;
+ start.next();
+ tok.next();
+ while (tok != start) {
+ if (tok.eof()) {
+ warning(WARN_DELIM, "missing closing delimiter");
+ break;
+ }
+ if (tok.newline()) {
+ warning(WARN_DELIM, "missing closing delimiter");
+ input_stack::push(make_temp_iterator("\n"));
+ break;
+ }
+ charinfo *ci = tok.get_char(1);
+ if (ci) {
+ node *n = curenv->make_char_node(ci);
+ if (n)
+ bn->bracket(n);
+ }
+ tok.next();
+ }
+ return bn;
+}
+
+static int do_name_test()
+{
+ token start;
+ start.next();
+ int start_level = input_stack::get_level();
+ int bad_char = 0;
+ int some_char = 0;
+ for (;;) {
+ tok.next();
+ if (tok.newline() || tok.eof()) {
+ warning(WARN_DELIM, "missing closing delimiter");
+ break;
+ }
+ if (tok == start
+ && (compatible_flag || input_stack::get_level() == start_level))
+ break;
+ if (!tok.ch())
+ bad_char = 1;
+ some_char = 1;
+ }
+ return some_char && !bad_char;
+}
+
+#if 0
+static node *do_zero_width()
+{
+ token start;
+ start.next();
+ int start_level = input_stack::get_level();
+ environment env(curenv);
+ environment *oldenv = curenv;
+ curenv = &env;
+ for (;;) {
+ tok.next();
+ if (tok.newline() || tok.eof()) {
+ error("missing closing delimiter");
+ break;
+ }
+ if (tok == start
+ && (compatible_flag || input_stack::get_level() == start_level))
+ break;
+ tok.process();
+ }
+ curenv = oldenv;
+ node *rev = env.extract_output_line();
+ node *n = 0;
+ while (rev) {
+ node *tem = rev;
+ rev = rev->next;
+ tem->next = n;
+ n = tem;
+ }
+ return new zero_width_node(n);
+}
+
+#else
+
+// It's undesirable for \Z to change environments, because then
+// \n(.w won't work as expected.
+
+static node *do_zero_width()
+{
+ node *rev = new dummy_node;
+ token start;
+ start.next();
+ int start_level = input_stack::get_level();
+ for (;;) {
+ tok.next();
+ if (tok.newline() || tok.eof()) {
+ warning(WARN_DELIM, "missing closing delimiter");
+ break;
+ }
+ if (tok == start
+ && (compatible_flag || input_stack::get_level() == start_level))
+ break;
+ if (!tok.add_to_node_list(&rev))
+ error("illegal token in argument to \\Z");
+ }
+ node *n = 0;
+ while (rev) {
+ node *tem = rev;
+ rev = rev->next;
+ tem->next = n;
+ n = tem;
+ }
+ return new zero_width_node(n);
+}
+
+#endif
+
+token_node *node::get_token_node()
+{
+ return 0;
+}
+
+class token_node : public node {
+public:
+ token tk;
+ token_node(const token &t);
+ node *copy();
+ token_node *get_token_node();
+ int same(node *);
+ const char *type();
+};
+
+token_node::token_node(const token &t) : tk(t)
+{
+}
+
+node *token_node::copy()
+{
+ return new token_node(tk);
+}
+
+token_node *token_node::get_token_node()
+{
+ return this;
+}
+
+int token_node::same(node *nd)
+{
+ return tk == ((token_node *)nd)->tk;
+}
+
+const char *token_node::type()
+{
+ return "token_node";
+}
+
+token::token() : nd(0), type(TOKEN_EMPTY)
+{
+}
+
+token::~token()
+{
+ delete nd;
+}
+
+token::token(const token &t)
+: nm(t.nm), c(t.c), val(t.val), dim(t.dim), type(t.type)
+{
+ // Use two statements to work around bug in SGI C++.
+ node *tem = t.nd;
+ nd = tem ? tem->copy() : 0;
+}
+
+void token::operator=(const token &t)
+{
+ delete nd;
+ nm = t.nm;
+ // Use two statements to work around bug in SGI C++.
+ node *tem = t.nd;
+ nd = tem ? tem->copy() : 0;
+ c = t.c;
+ val = t.val;
+ dim = t.dim;
+ type = t.type;
+}
+
+void token::skip()
+{
+ while (space())
+ next();
+}
+
+int has_arg()
+{
+ while (tok.space())
+ tok.next();
+ return !tok.newline();
+}
+
+void token::make_space()
+{
+ type = TOKEN_SPACE;
+}
+
+void token::make_newline()
+{
+ type = TOKEN_NEWLINE;
+}
+
+void token::next()
+{
+ if (nd) {
+ delete nd;
+ nd = 0;
+ }
+ units x;
+ for (;;) {
+ node *n;
+ int cc = input_stack::get(&n);
+ if (cc != escape_char || escape_char == 0) {
+ handle_normal_char:
+ switch(cc) {
+ case EOF:
+ type = TOKEN_EOF;
+ return;
+ case TRANSPARENT_FILE_REQUEST:
+ case TITLE_REQUEST:
+ case COPY_FILE_REQUEST:
+#ifdef COLUMN
+ case VJUSTIFY_REQUEST:
+#endif /* COLUMN */
+ type = TOKEN_REQUEST;
+ c = cc;
+ return;
+ case BEGIN_TRAP:
+ type = TOKEN_BEGIN_TRAP;
+ return;
+ case END_TRAP:
+ type = TOKEN_END_TRAP;
+ return;
+ case LAST_PAGE_EJECTOR:
+ seen_last_page_ejector = 1;
+ // fall through
+ case PAGE_EJECTOR:
+ type = TOKEN_PAGE_EJECTOR;
+ return;
+ case ESCAPE_PERCENT:
+ ESCAPE_PERCENT:
+ type = TOKEN_HYPHEN_INDICATOR;
+ return;
+ case ESCAPE_SPACE:
+ ESCAPE_SPACE:
+ type = TOKEN_NODE;
+ nd = new space_char_hmotion_node(curenv->get_space_width());
+ return;
+ case ESCAPE_e:
+ ESCAPE_e:
+ type = TOKEN_ESCAPE;
+ return;
+ case ESCAPE_E:
+ goto handle_escape_char;
+ case ESCAPE_BAR:
+ ESCAPE_BAR:
+ type = TOKEN_NODE;
+ nd = new hmotion_node(curenv->get_narrow_space_width());
+ return;
+ case ESCAPE_CIRCUMFLEX:
+ ESCAPE_CIRCUMFLEX:
+ type = TOKEN_NODE;
+ nd = new hmotion_node(curenv->get_half_narrow_space_width());
+ return;
+ case ESCAPE_NEWLINE:
+ break;
+ case ESCAPE_LEFT_BRACE:
+ ESCAPE_LEFT_BRACE:
+ type = TOKEN_LEFT_BRACE;
+ return;
+ case ESCAPE_RIGHT_BRACE:
+ ESCAPE_RIGHT_BRACE:
+ type = TOKEN_RIGHT_BRACE;
+ return;
+ case ESCAPE_LEFT_QUOTE:
+ ESCAPE_LEFT_QUOTE:
+ type = TOKEN_SPECIAL;
+ nm = symbol("ga");
+ return;
+ case ESCAPE_RIGHT_QUOTE:
+ ESCAPE_RIGHT_QUOTE:
+ type = TOKEN_SPECIAL;
+ nm = symbol("aa");
+ return;
+ case ESCAPE_HYPHEN:
+ ESCAPE_HYPHEN:
+ type = TOKEN_SPECIAL;
+ nm = symbol("-");
+ return;
+ case ESCAPE_UNDERSCORE:
+ ESCAPE_UNDERSCORE:
+ type = TOKEN_SPECIAL;
+ nm = symbol("ul");
+ return;
+ case ESCAPE_c:
+ ESCAPE_c:
+ type = TOKEN_INTERRUPT;
+ return;
+ case ESCAPE_BANG:
+ ESCAPE_BANG:
+ type = TOKEN_TRANSPARENT;
+ return;
+ case ESCAPE_QUESTION:
+ ESCAPE_QUESTION:
+ nd = do_non_interpreted();
+ if (nd) {
+ type = TOKEN_NODE;
+ return;
+ }
+ break;
+ case ESCAPE_AMPERSAND:
+ ESCAPE_AMPERSAND:
+ type = TOKEN_DUMMY;
+ return;
+ case ESCAPE_RIGHT_PARENTHESIS:
+ ESCAPE_RIGHT_PARENTHESIS:
+ type = TOKEN_NODE;
+ nd = new transparent_dummy_node;
+ return;
+ case '\b':
+ type = TOKEN_BACKSPACE;
+ return;
+ case ' ':
+ type = TOKEN_SPACE;
+ return;
+ case '\t':
+ type = TOKEN_TAB;
+ return;
+ case '\n':
+ type = TOKEN_NEWLINE;
+ return;
+ case '\001':
+ type = TOKEN_LEADER;
+ return;
+ case 0:
+ {
+ assert(n != 0);
+ token_node *tn = n->get_token_node();
+ if (tn) {
+ *this = tn->tk;
+ delete tn;
+ }
+ else {
+ nd = n;
+ type = TOKEN_NODE;
+ }
+ }
+ return;
+ default:
+ type = TOKEN_CHAR;
+ c = cc;
+ return;
+ }
+ }
+ else {
+ handle_escape_char:
+ cc = input_stack::get(NULL);
+ switch(cc) {
+ case '(':
+ nm = read_two_char_escape_name();
+ type = TOKEN_SPECIAL;
+ return;
+ case EOF:
+ type = TOKEN_EOF;
+ error("end of input after escape character");
+ return;
+ case '`':
+ goto ESCAPE_LEFT_QUOTE;
+ case '\'':
+ goto ESCAPE_RIGHT_QUOTE;
+ case '-':
+ goto ESCAPE_HYPHEN;
+ case '_':
+ goto ESCAPE_UNDERSCORE;
+ case '%':
+ goto ESCAPE_PERCENT;
+ case ' ':
+ goto ESCAPE_SPACE;
+ case '0':
+ nd = new hmotion_node(curenv->get_digit_width());
+ type = TOKEN_NODE;
+ return;
+ case '|':
+ goto ESCAPE_BAR;
+ case '^':
+ goto ESCAPE_CIRCUMFLEX;
+ case '/':
+ type = TOKEN_ITALIC_CORRECTION;
+ return;
+ case ',':
+ type = TOKEN_NODE;
+ nd = new left_italic_corrected_node;
+ return;
+ case '&':
+ goto ESCAPE_AMPERSAND;
+ case ')':
+ goto ESCAPE_RIGHT_PARENTHESIS;
+ case '!':
+ goto ESCAPE_BANG;
+ case '?':
+ goto ESCAPE_QUESTION;
+ case '~':
+ nd = new unbreakable_space_node(curenv->get_space_width());
+ type = TOKEN_NODE;
+ return;
+ case '"':
+ while ((cc = input_stack::get(NULL)) != '\n' && cc != EOF)
+ ;
+ if (cc == '\n')
+ type = TOKEN_NEWLINE;
+ else
+ type = TOKEN_EOF;
+ return;
+ case '#': // Like \" but newline is ignored.
+ while ((cc = input_stack::get(NULL)) != '\n')
+ if (cc == EOF) {
+ type = TOKEN_EOF;
+ return;
+ }
+ break;
+ case '$':
+ {
+ symbol nm = read_escape_name();
+ if (!nm.is_null())
+ interpolate_arg(nm);
+ break;
+ }
+ case '*':
+ {
+ symbol nm = read_escape_name();
+ if (!nm.is_null())
+ interpolate_string(nm);
+ break;
+ }
+ case 'a':
+ nd = new non_interpreted_char_node('\001');
+ type = TOKEN_NODE;
+ return;
+ case 'A':
+ c = '0' + do_name_test();
+ type = TOKEN_CHAR;
+ return;
+ case 'b':
+ nd = do_bracket();
+ type = TOKEN_NODE;
+ return;
+ case 'c':
+ goto ESCAPE_c;
+ case 'C':
+ nm = get_delim_name();
+ if (nm.is_null())
+ break;
+ type = TOKEN_SPECIAL;
+ return;
+ case 'd':
+ type = TOKEN_NODE;
+ nd = new vmotion_node(curenv->get_size()/2);
+ return;
+ case 'D':
+ nd = read_draw_node();
+ if (!nd)
+ break;
+ type = TOKEN_NODE;
+ return;
+ case 'e':
+ goto ESCAPE_e;
+ case 'E':
+ goto handle_escape_char;
+ case 'f':
+ {
+ symbol s = read_escape_name();
+ if (s.is_null())
+ break;
+ for (const char *p = s.contents(); *p != '\0'; p++)
+ if (!csdigit(*p))
+ break;
+ if (*p)
+ curenv->set_font(s);
+ else
+ curenv->set_font(atoi(s.contents()));
+ break;
+ }
+ case 'g':
+ {
+ symbol s = read_escape_name();
+ if (!s.is_null())
+ interpolate_number_format(s);
+ break;
+ }
+ case 'h':
+ if (!get_delim_number(&x, 'm'))
+ break;
+ type = TOKEN_NODE;
+ nd = new hmotion_node(x);
+ return;
+ case 'H':
+ if (get_delim_number(&x, 'z', curenv->get_requested_point_size()))
+ curenv->set_char_height(x);
+ break;
+ case 'k':
+ nm = read_escape_name();
+ if (nm.is_null())
+ break;
+ type = TOKEN_MARK_INPUT;
+ return;
+ case 'l':
+ case 'L':
+ {
+ charinfo *s = 0;
+ if (!get_line_arg(&x, (cc == 'l' ? 'm': 'v'), &s))
+ break;
+ if (s == 0)
+ s = get_charinfo(cc == 'l' ? "ru" : "br");
+ type = TOKEN_NODE;
+ node *n = curenv->make_char_node(s);
+ if (cc == 'l')
+ nd = new hline_node(x, n);
+ else
+ nd = new vline_node(x, n);
+ return;
+ }
+ case 'n':
+ {
+ int inc;
+ symbol nm = read_increment_and_escape_name(&inc);
+ if (!nm.is_null())
+ interpolate_number_reg(nm, inc);
+ break;
+ }
+ case 'N':
+ if (!get_delim_number(&val, 0))
+ break;
+ type = TOKEN_NUMBERED_CHAR;
+ return;
+ case 'o':
+ nd = do_overstrike();
+ type = TOKEN_NODE;
+ return;
+ case 'p':
+ type = TOKEN_SPREAD;
+ return;
+ case 'r':
+ type = TOKEN_NODE;
+ nd = new vmotion_node(-curenv->get_size());
+ return;
+ case 'R':
+ do_register();
+ break;
+ case 's':
+ if (read_size(&x))
+ curenv->set_size(x);
+ break;
+ case 'S':
+ if (get_delim_number(&x, 0))
+ curenv->set_char_slant(x);
+ break;
+ case 't':
+ type = TOKEN_NODE;
+ nd = new non_interpreted_char_node('\t');
+ return;
+ case 'u':
+ type = TOKEN_NODE;
+ nd = new vmotion_node(-curenv->get_size()/2);
+ return;
+ case 'v':
+ if (!get_delim_number(&x, 'v'))
+ break;
+ type = TOKEN_NODE;
+ nd = new vmotion_node(x);
+ return;
+ case 'V':
+ {
+ symbol nm = read_escape_name();
+ if (!nm.is_null())
+ interpolate_environment_variable(nm);
+ break;
+ }
+ case 'w':
+ do_width();
+ break;
+ case 'x':
+ if (!get_delim_number(&x, 'v'))
+ break;
+ type = TOKEN_NODE;
+ nd = new extra_size_node(x);
+ return;
+ case 'X':
+ nd = do_special();
+ if (!nd)
+ break;
+ type = TOKEN_NODE;
+ return;
+ case 'Y':
+ {
+ symbol s = read_escape_name();
+ if (s.is_null())
+ break;
+ request_or_macro *p = lookup_request(s);
+ macro *m = p->to_macro();
+ if (!m) {
+ error("can't transparently throughput a request");
+ break;
+ }
+ nd = new special_node(*m);
+ type = TOKEN_NODE;
+ return;
+ }
+ case 'z':
+ {
+ next();
+ if (type == TOKEN_NODE)
+ nd = new zero_width_node(nd);
+ else {
+ charinfo *ci = get_char(1);
+ if (ci == 0)
+ break;
+ node *gn = curenv->make_char_node(ci);
+ if (gn == 0)
+ break;
+ nd = new zero_width_node(gn);
+ type = TOKEN_NODE;
+ }
+ return;
+ }
+ case 'Z':
+ nd = do_zero_width();
+ if (nd == 0)
+ break;
+ type = TOKEN_NODE;
+ return;
+ case '{':
+ goto ESCAPE_LEFT_BRACE;
+ case '}':
+ goto ESCAPE_RIGHT_BRACE;
+ case '\n':
+ break;
+ case '[':
+ if (!compatible_flag) {
+ nm = read_long_escape_name();
+ if (nm.is_null())
+ break;
+ type = TOKEN_SPECIAL;
+ return;
+ }
+ goto handle_normal_char;
+ default:
+ if (cc != escape_char && cc != '.')
+ warning(WARN_ESCAPE, "escape character ignored before %1",
+ input_char_description(cc));
+ goto handle_normal_char;
+ }
+ }
+ }
+}
+
+int token::operator==(const token &t)
+{
+ if (type != t.type)
+ return 0;
+ switch(type) {
+ case TOKEN_CHAR:
+ return c == t.c;
+ case TOKEN_SPECIAL:
+ return nm == t.nm;
+ case TOKEN_NUMBERED_CHAR:
+ return val == t.val;
+ default:
+ return 1;
+ }
+}
+
+int token::operator!=(const token &t)
+{
+ return !(*this == t);
+}
+
+// is token a suitable delimiter (like ')?
+
+int token::delimiter(int err)
+{
+ switch(type) {
+ case TOKEN_CHAR:
+ switch(c) {
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ case '+':
+ case '-':
+ case '/':
+ case '*':
+ case '%':
+ case '<':
+ case '>':
+ case '=':
+ case '&':
+ case ':':
+ case '(':
+ case ')':
+ case '.':
+ if (err)
+ error("cannot use character `%1' as a starting delimiter", char(c));
+ return 0;
+ default:
+ return 1;
+ }
+ case TOKEN_NODE:
+ case TOKEN_SPACE:
+ case TOKEN_TAB:
+ case TOKEN_NEWLINE:
+ if (err)
+ error("cannot use %1 as a starting delimiter", description());
+ return 0;
+ default:
+ return 1;
+ }
+}
+
+const char *token::description()
+{
+ static char buf[4];
+ switch (type) {
+ case TOKEN_BACKSPACE:
+ return "a backspace character";
+ case TOKEN_CHAR:
+ buf[0] = '`';
+ buf[1] = c;
+ buf[2] = '\'';
+ buf[3] = '\0';
+ return buf;
+ case TOKEN_DUMMY:
+ return "`\\&'";
+ case TOKEN_ESCAPE:
+ return "`\\e'";
+ case TOKEN_HYPHEN_INDICATOR:
+ return "`\\%'";
+ case TOKEN_INTERRUPT:
+ return "`\\c'";
+ case TOKEN_ITALIC_CORRECTION:
+ return "`\\/'";
+ case TOKEN_LEADER:
+ return "a leader character";
+ case TOKEN_LEFT_BRACE:
+ return "`\\{'";
+ case TOKEN_MARK_INPUT:
+ return "`\\k'";
+ case TOKEN_NEWLINE:
+ return "newline";
+ case TOKEN_NODE:
+ return "a node";
+ case TOKEN_NUMBERED_CHAR:
+ return "`\\N'";
+ case TOKEN_RIGHT_BRACE:
+ return "`\\}'";
+ case TOKEN_SPACE:
+ return "a space";
+ case TOKEN_SPECIAL:
+ return "a special character";
+ case TOKEN_SPREAD:
+ return "`\\p'";
+ case TOKEN_TAB:
+ return "a tab character";
+ case TOKEN_TRANSPARENT:
+ return "`\\!'";
+ case TOKEN_EOF:
+ return "end of input";
+ default:
+ break;
+ }
+ return "a magic token";
+}
+
+void skip_line()
+{
+ while (!tok.newline())
+ if (tok.eof())
+ return;
+ else
+ tok.next();
+ tok.next();
+}
+
+void compatible()
+{
+ int n;
+ if (has_arg() && get_integer(&n))
+ compatible_flag = n != 0;
+ else
+ compatible_flag = 1;
+ skip_line();
+}
+
+static void empty_name_warning(int required)
+{
+ if (tok.newline() || tok.eof()) {
+ if (required)
+ warning(WARN_MISSING, "missing name");
+ }
+ else if (tok.right_brace() || tok.tab()) {
+ const char *start = tok.description();
+ do {
+ tok.next();
+ } while (tok.space() || tok.right_brace() || tok.tab());
+ if (!tok.newline() && !tok.eof())
+ error("%1 is not allowed before an argument", start);
+ else if (required)
+ warning(WARN_MISSING, "missing name");
+ }
+ else if (required)
+ error("name expected (got %1)", tok.description());
+ else
+ error("name expected (got %1): treated as missing", tok.description());
+}
+
+static void non_empty_name_warning()
+{
+ if (!tok.newline() && !tok.eof() && !tok.space() && !tok.tab()
+ && !tok.right_brace()
+ // We don't want to give a warning for .el\{
+ && !tok.left_brace())
+ error("%1 is not allowed in a name", tok.description());
+}
+
+symbol get_name(int required)
+{
+ if (compatible_flag) {
+ char buf[3];
+ tok.skip();
+ if ((buf[0] = tok.ch()) != 0) {
+ tok.next();
+ if ((buf[1] = tok.ch()) != 0) {
+ buf[2] = 0;
+ tok.make_space();
+ }
+ else
+ non_empty_name_warning();
+ return symbol(buf);
+ }
+ else {
+ empty_name_warning(required);
+ return NULL_SYMBOL;
+ }
+ }
+ else
+ return get_long_name(required);
+}
+
+symbol get_long_name(int required)
+{
+ while (tok.space())
+ tok.next();
+ char abuf[ABUF_SIZE];
+ char *buf = abuf;
+ int buf_size = ABUF_SIZE;
+ int i = 0;
+ for (;;) {
+ if (i + 1 > buf_size) {
+ if (buf == abuf) {
+ buf = new char [ABUF_SIZE*2];
+ memcpy(buf, abuf, buf_size);
+ buf_size = ABUF_SIZE*2;
+ }
+ else {
+ char *old_buf = buf;
+ buf = new char[buf_size*2];
+ memcpy(buf, old_buf, buf_size);
+ buf_size *= 2;
+ a_delete old_buf;
+ }
+ }
+ if ((buf[i] = tok.ch()) == 0)
+ break;
+ i++;
+ tok.next();
+ }
+ if (i == 0) {
+ empty_name_warning(required);
+ return NULL_SYMBOL;
+ }
+ non_empty_name_warning();
+ if (buf == abuf)
+ return symbol(buf);
+ else {
+ symbol s(buf);
+ a_delete buf;
+ return s;
+ }
+}
+
+void exit_troff()
+{
+ exit_started = 1;
+ topdiv->set_last_page();
+ if (!end_macro_name.is_null()) {
+ spring_trap(end_macro_name);
+ tok.next();
+ process_input_stack();
+ }
+ curenv->final_break();
+ tok.next();
+ process_input_stack();
+ end_diversions();
+ done_end_macro = 1;
+ topdiv->set_ejecting();
+ static unsigned char buf[2] = { LAST_PAGE_EJECTOR, '\0' };
+ input_stack::push(make_temp_iterator((char *)buf));
+ topdiv->space(topdiv->get_page_length(), 1);
+ tok.next();
+ process_input_stack();
+ seen_last_page_ejector = 1; // should be set already
+ topdiv->set_ejecting();
+ push_page_ejector();
+ topdiv->space(topdiv->get_page_length(), 1);
+ tok.next();
+ process_input_stack();
+ // This will only happen if a trap-invoked macro starts a diversion,
+ // or if vertical position traps have been disabled.
+ cleanup_and_exit(0);
+}
+
+// This implements .ex. The input stack must be cleared before calling
+// exit_troff().
+
+void exit_request()
+{
+ input_stack::clear();
+ if (exit_started)
+ tok.next();
+ else
+ exit_troff();
+}
+
+void end_macro()
+{
+ end_macro_name = get_name();
+ skip_line();
+}
+
+void do_request()
+{
+ int saved_compatible_flag = compatible_flag;
+ compatible_flag = 0;
+ symbol nm = get_name();
+ if (nm.is_null())
+ skip_line();
+ else
+ interpolate_macro(nm);
+ compatible_flag = saved_compatible_flag;
+}
+
+inline int possibly_handle_first_page_transition()
+{
+ if (topdiv->before_first_page && curdiv == topdiv && !curenv->is_dummy()) {
+ handle_first_page_transition();
+ return 1;
+ }
+ else
+ return 0;
+}
+
+static int transparent_translate(int cc)
+{
+ if (!illegal_input_char(cc)) {
+ charinfo *ci = charset_table[cc];
+ switch (ci->get_special_translation(1)) {
+ case charinfo::TRANSLATE_SPACE:
+ return ' ';
+ case charinfo::TRANSLATE_DUMMY:
+ return ESCAPE_AMPERSAND;
+ case charinfo::TRANSLATE_HYPHEN_INDICATOR:
+ return ESCAPE_PERCENT;
+ }
+ // This is realy ugly.
+ ci = ci->get_translation(1);
+ if (ci) {
+ int c = ci->get_ascii_code();
+ if (c != '\0')
+ return c;
+ error("can't translate %1 to special character `%2'"
+ " in transparent throughput",
+ input_char_description(cc),
+ ci->nm.contents());
+ }
+ }
+ return cc;
+}
+
+class int_stack {
+ struct int_stack_element {
+ int n;
+ int_stack_element *next;
+ } *top;
+public:
+ int_stack();
+ ~int_stack();
+ void push(int);
+ int is_empty();
+ int pop();
+};
+
+int_stack::int_stack()
+{
+ top = 0;
+}
+
+int_stack::~int_stack()
+{
+ while (top != 0) {
+ int_stack_element *temp = top;
+ top = top->next;
+ delete temp;
+ }
+
+}
+
+int int_stack::is_empty()
+{
+ return top == 0;
+}
+
+void int_stack::push(int n)
+{
+ int_stack_element *p = new int_stack_element;
+ p->next = top;
+ p->n = n;
+ top = p;
+}
+
+
+int int_stack::pop()
+{
+ assert(top != 0);
+ int_stack_element *p = top;
+ top = top->next;
+ int n = p->n;
+ delete p;
+ return n;
+}
+
+int node::reread(int *)
+{
+ return 0;
+}
+
+int diverted_space_node::reread(int *bolp)
+{
+ if (curenv->get_fill())
+ blank_line();
+ else
+ curdiv->space(n);
+ *bolp = 1;
+ return 1;
+}
+
+int diverted_copy_file_node::reread(int *bolp)
+{
+ curdiv->copy_file(filename.contents());
+ *bolp = 1;
+ return 1;
+}
+
+void process_input_stack()
+{
+ int_stack trap_bol_stack;
+ int bol = 1;
+ for (;;) {
+ int suppress_next = 0;
+ switch (tok.type) {
+ case token::TOKEN_CHAR:
+ {
+ unsigned char ch = tok.c;
+ if (bol &&
+ (ch == curenv->control_char
+ || ch == curenv->no_break_control_char)) {
+ break_flag = ch == curenv->control_char;
+ // skip tabs as well as spaces here
+ do {
+ tok.next();
+ } while (tok.white_space());
+ symbol nm = get_name();
+ if (nm.is_null())
+ skip_line();
+ else
+ interpolate_macro(nm);
+ suppress_next = 1;
+ }
+ else {
+ if (possibly_handle_first_page_transition())
+ ;
+ else {
+ for (;;) {
+ curenv->add_char(charset_table[ch]);
+ tok.next();
+ if (tok.type != token::TOKEN_CHAR)
+ break;
+ ch = tok.c;
+ }
+ suppress_next = 1;
+ bol = 0;
+ }
+ }
+ break;
+ }
+ case token::TOKEN_TRANSPARENT:
+ {
+ if (bol) {
+ if (possibly_handle_first_page_transition())
+ ;
+ else {
+ int cc;
+ do {
+ node *n;
+ cc = get_copy(&n);
+ if (cc != EOF)
+ if (cc != '\0')
+ curdiv->transparent_output(transparent_translate(cc));
+ else
+ curdiv->transparent_output(n);
+ } while (cc != '\n' && cc != EOF);
+ if (cc == EOF)
+ curdiv->transparent_output('\n');
+ }
+ }
+ break;
+ }
+ case token::TOKEN_NEWLINE:
+ {
+ if (bol && !curenv->get_prev_line_interrupted())
+ blank_line();
+ else {
+ curenv->newline();
+ bol = 1;
+ }
+ break;
+ }
+ case token::TOKEN_REQUEST:
+ {
+ int request_code = tok.c;
+ tok.next();
+ switch (request_code) {
+ case TITLE_REQUEST:
+ title();
+ break;
+ case COPY_FILE_REQUEST:
+ copy_file();
+ break;
+ case TRANSPARENT_FILE_REQUEST:
+ transparent_file();
+ break;
+#ifdef COLUMN
+ case VJUSTIFY_REQUEST:
+ vjustify();
+ break;
+#endif /* COLUMN */
+ default:
+ assert(0);
+ break;
+ }
+ suppress_next = 1;
+ break;
+ }
+ case token::TOKEN_SPACE:
+ {
+ if (possibly_handle_first_page_transition())
+ ;
+ else if (bol && !curenv->get_prev_line_interrupted()) {
+ int nspaces = 0;
+ do {
+ nspaces += tok.nspaces();
+ tok.next();
+ } while (tok.space());
+ if (tok.newline())
+ blank_line();
+ else {
+ push_token(tok);
+ curenv->do_break();
+ curenv->add_node(new hmotion_node(curenv->get_space_width()*nspaces));
+ bol = 0;
+ }
+ }
+ else {
+ curenv->space();
+ bol = 0;
+ }
+ break;
+ }
+ case token::TOKEN_EOF:
+ return;
+ case token::TOKEN_NODE:
+ {
+ if (possibly_handle_first_page_transition())
+ ;
+ else if (tok.nd->reread(&bol)) {
+ delete tok.nd;
+ tok.nd = 0;
+ }
+ else {
+ curenv->add_node(tok.nd);
+ tok.nd = 0;
+ bol = 0;
+ }
+ break;
+ }
+ case token::TOKEN_PAGE_EJECTOR:
+ {
+ continue_page_eject();
+ // I think we just want to preserve bol.
+ // bol = 1;
+ break;
+ }
+ case token::TOKEN_BEGIN_TRAP:
+ {
+ trap_bol_stack.push(bol);
+ bol = 1;
+ break;
+ }
+ case token::TOKEN_END_TRAP:
+ {
+ if (trap_bol_stack.is_empty())
+ error("spurious end trap token detected!");
+ else
+ bol = trap_bol_stack.pop();
+
+ /* I'm not totally happy about this. But I can't think of any other
+ way to do it. Doing an output_pending_lines() whenever a
+ TOKEN_END_TRAP is detected doesn't work: for example,
+
+ .wh -1i x
+ .de x
+ 'bp
+ ..
+ .wh -.5i y
+ .de y
+ .tl ''-%-''
+ ..
+ .br
+ .ll .5i
+ .sp |\n(.pu-1i-.5v
+ a\%very\%very\%long\%word
+
+ will print all but the first lines from the word immediately
+ after the footer, rather than on the next page. */
+
+ if (trap_bol_stack.is_empty())
+ curenv->output_pending_lines();
+ break;
+ }
+ default:
+ {
+ bol = 0;
+ tok.process();
+ break;
+ }
+ }
+ if (!suppress_next)
+ tok.next();
+ trap_sprung_flag = 0;
+ }
+}
+
+#ifdef WIDOW_CONTROL
+
+void flush_pending_lines()
+{
+ while (!tok.newline() && !tok.eof())
+ tok.next();
+ curenv->output_pending_lines();
+ tok.next();
+}
+
+#endif /* WIDOW_CONTROL */
+
+request_or_macro::request_or_macro()
+{
+}
+
+macro *request_or_macro::to_macro()
+{
+ return 0;
+}
+
+request::request(REQUEST_FUNCP pp) : p(pp)
+{
+}
+
+void request::invoke(symbol)
+{
+ (*p)();
+}
+
+struct char_block {
+ enum { SIZE = 128 };
+ unsigned char s[SIZE];
+ char_block *next;
+ char_block();
+};
+
+char_block::char_block()
+: next(0)
+{
+}
+
+class char_list {
+public:
+ char_list();
+ ~char_list();
+ void append(unsigned char);
+ int length();
+private:
+ unsigned char *ptr;
+ int len;
+ char_block *head;
+ char_block *tail;
+ friend class macro_header;
+ friend class string_iterator;
+};
+
+char_list::char_list()
+: head(0), tail(0), ptr(0), len(0)
+{
+}
+
+char_list::~char_list()
+{
+ while (head != 0) {
+ char_block *tem = head;
+ head = head->next;
+ delete tem;
+ }
+}
+
+int char_list::length()
+{
+ return len;
+}
+
+void char_list::append(unsigned char c)
+{
+ if (tail == 0) {
+ head = tail = new char_block;
+ ptr = tail->s;
+ }
+ else {
+ if (ptr >= tail->s + char_block::SIZE) {
+ tail->next = new char_block;
+ tail = tail->next;
+ ptr = tail->s;
+ }
+ }
+ *ptr++ = c;
+ len++;
+}
+
+class node_list {
+ node *head;
+ node *tail;
+public:
+ node_list();
+ ~node_list();
+ void append(node *);
+ int length();
+ node *extract();
+
+ friend class macro_header;
+ friend class string_iterator;
+};
+
+void node_list::append(node *n)
+{
+ if (head == 0) {
+ n->next = 0;
+ head = tail = n;
+ }
+ else {
+ n->next = 0;
+ tail = tail->next = n;
+ }
+}
+
+int node_list::length()
+{
+ int total = 0;
+ for (node *n = head; n != 0; n = n->next)
+ ++total;
+ return total;
+}
+
+node_list::node_list()
+{
+ head = tail = 0;
+}
+
+node *node_list::extract()
+{
+ node *temp = head;
+ head = tail = 0;
+ return temp;
+}
+
+
+node_list::~node_list()
+{
+ delete_node_list(head);
+}
+
+struct macro_header {
+ int count;
+ char_list cl;
+ node_list nl;
+ macro_header() { count = 1; }
+ macro_header *copy(int);
+};
+
+
+macro::~macro()
+{
+ if (p != 0 && --(p->count) <= 0)
+ delete p;
+}
+
+macro::macro()
+{
+ if (!input_stack::get_location(1, &filename, &lineno)) {
+ filename = 0;
+ lineno = 0;
+ }
+ length = 0;
+ p = 0;
+}
+
+macro::macro(const macro &m)
+: filename(m.filename), lineno(m.lineno), p(m.p), length(m.length)
+{
+ if (p != 0)
+ p->count++;
+}
+
+macro &macro::operator=(const macro &m)
+{
+ // don't assign object
+ if (m.p != 0)
+ m.p->count++;
+ if (p != 0 && --(p->count) <= 0)
+ delete p;
+ p = m.p;
+ filename = m.filename;
+ lineno = m.lineno;
+ length = m.length;
+ return *this;
+}
+
+void macro::append(unsigned char c)
+{
+ assert(c != 0);
+ if (p == 0)
+ p = new macro_header;
+ if (p->cl.length() != length) {
+ macro_header *tem = p->copy(length);
+ if (--(p->count) <= 0)
+ delete p;
+ p = tem;
+ }
+ p->cl.append(c);
+ ++length;
+}
+
+void macro::append(node *n)
+{
+ assert(n != 0);
+ if (p == 0)
+ p = new macro_header;
+ if (p->cl.length() != length) {
+ macro_header *tem = p->copy(length);
+ if (--(p->count) <= 0)
+ delete p;
+ p = tem;
+ }
+ p->cl.append(0);
+ p->nl.append(n);
+ ++length;
+}
+
+void macro::print_size()
+{
+ errprint("%1", length);
+}
+
+// make a copy of the first n bytes
+
+macro_header *macro_header::copy(int n)
+{
+ macro_header *p = new macro_header;
+ char_block *bp = cl.head;
+ unsigned char *ptr = bp->s;
+ node *nd = nl.head;
+ while (--n >= 0) {
+ if (ptr >= bp->s + char_block::SIZE) {
+ bp = bp->next;
+ ptr = bp->s;
+ }
+ int c = *ptr++;
+ p->cl.append(c);
+ if (c == 0) {
+ p->nl.append(nd->copy());
+ nd = nd->next;
+ }
+ }
+ return p;
+}
+
+void print_macros()
+{
+ object_dictionary_iterator iter(request_dictionary);
+ request_or_macro *rm;
+ symbol s;
+ while (iter.get(&s, (object **)&rm)) {
+ assert(!s.is_null());
+ macro *m = rm->to_macro();
+ if (m) {
+ errprint("%1\t", s.contents());
+ m->print_size();
+ errprint("\n");
+ }
+ }
+ fflush(stderr);
+ skip_line();
+}
+
+class string_iterator : public input_iterator {
+ macro mac;
+ const char *how_invoked;
+ int newline_flag;
+ int lineno;
+ char_block *bp;
+ int count; // of characters remaining
+ node *nd;
+protected:
+ symbol nm;
+ string_iterator();
+public:
+ string_iterator(const macro &m, const char *p = 0, symbol s = NULL_SYMBOL);
+ int fill(node **);
+ int peek();
+ int get_location(int, const char **, int *);
+ void backtrace();
+};
+
+string_iterator::string_iterator(const macro &m, const char *p, symbol s)
+: lineno(1), mac(m), newline_flag(0), how_invoked(p), nm(s)
+{
+ count = mac.length;
+ if (count != 0) {
+ bp = mac.p->cl.head;
+ nd = mac.p->nl.head;
+ ptr = eptr = bp->s;
+ }
+ else {
+ bp = 0;
+ nd = 0;
+ ptr = eptr = 0;
+ }
+}
+
+string_iterator::string_iterator()
+{
+ bp = 0;
+ nd = 0;
+ ptr = eptr = 0;
+ newline_flag = 0;
+ how_invoked = 0;
+ lineno = 1;
+ count = 0;
+}
+
+int string_iterator::fill(node **np)
+{
+ if (newline_flag)
+ lineno++;
+ newline_flag = 0;
+ if (count <= 0)
+ return EOF;
+ const unsigned char *p = eptr;
+ if (p >= bp->s + char_block::SIZE) {
+ bp = bp->next;
+ p = bp->s;
+ }
+ if (*p == '\0') {
+ if (np)
+ *np = nd->copy();
+ nd = nd->next;
+ eptr = ptr = p + 1;
+ count--;
+ return 0;
+ }
+ const unsigned char *e = bp->s + char_block::SIZE;
+ if (e - p > count)
+ e = p + count;
+ ptr = p;
+ while (p < e) {
+ unsigned char c = *p;
+ if (c == '\n' || c == ESCAPE_NEWLINE) {
+ newline_flag = 1;
+ p++;
+ break;
+ }
+ if (c == '\0')
+ break;
+ p++;
+ }
+ eptr = p;
+ count -= p - ptr;
+ return *ptr++;
+}
+
+int string_iterator::peek()
+{
+ if (count <= 0)
+ return EOF;
+ const unsigned char *p = eptr;
+ if (count <= 0)
+ return EOF;
+ if (p >= bp->s + char_block::SIZE) {
+ p = bp->next->s;
+ }
+ return *p;
+}
+
+int string_iterator::get_location(int allow_macro,
+ const char **filep, int *linep)
+{
+ if (!allow_macro)
+ return 0;
+ if (mac.filename == 0)
+ return 0;
+ *filep = mac.filename;
+ *linep = mac.lineno + lineno - 1;
+ return 1;
+}
+
+void string_iterator::backtrace()
+{
+ if (mac.filename) {
+ errprint("%1:%2: backtrace", mac.filename, mac.lineno + lineno - 1);
+ if (how_invoked) {
+ if (!nm.is_null())
+ errprint(": %1 `%2'\n", how_invoked, nm.contents());
+ else
+ errprint(": %1\n", how_invoked);
+ }
+ else
+ errprint("\n");
+ }
+}
+
+class temp_iterator : public input_iterator {
+ unsigned char *base;
+ temp_iterator(const char *, int len);
+public:
+ ~temp_iterator();
+ friend input_iterator *make_temp_iterator(const char *);
+};
+
+#ifdef __GNUG__
+inline
+#endif
+temp_iterator::temp_iterator(const char *s, int len)
+{
+ base = new unsigned char[len];
+ memcpy(base, s, len);
+ ptr = base;
+ eptr = base + len;
+}
+
+temp_iterator::~temp_iterator()
+{
+ a_delete base;
+}
+
+class small_temp_iterator : public input_iterator {
+private:
+ small_temp_iterator(const char *, int);
+ ~small_temp_iterator();
+ enum { BLOCK = 16 };
+ static small_temp_iterator *free_list;
+ void *operator new(size_t);
+ void operator delete(void *);
+ enum { SIZE = 12 };
+ unsigned char buf[SIZE];
+ friend input_iterator *make_temp_iterator(const char *);
+};
+
+small_temp_iterator *small_temp_iterator::free_list = 0;
+
+void *small_temp_iterator::operator new(size_t n)
+{
+ assert(n == sizeof(small_temp_iterator));
+ if (!free_list) {
+ free_list = (small_temp_iterator *)new char[sizeof(small_temp_iterator)*BLOCK];
+ for (int i = 0; i < BLOCK - 1; i++)
+ free_list[i].next = free_list + i + 1;
+ free_list[BLOCK-1].next = 0;
+ }
+ small_temp_iterator *p = free_list;
+ free_list = (small_temp_iterator *)(free_list->next);
+ p->next = 0;
+ return p;
+}
+
+#ifdef __GNUG__
+inline
+#endif
+void small_temp_iterator::operator delete(void *p)
+{
+ if (p) {
+ ((small_temp_iterator *)p)->next = free_list;
+ free_list = (small_temp_iterator *)p;
+ }
+}
+
+small_temp_iterator::~small_temp_iterator()
+{
+}
+
+
+#ifdef __GNUG__
+inline
+#endif
+small_temp_iterator::small_temp_iterator(const char *s, int len)
+{
+ for (int i = 0; i < len; i++)
+ buf[i] = s[i];
+ ptr = buf;
+ eptr = buf + len;
+}
+
+input_iterator *make_temp_iterator(const char *s)
+{
+ if (s == 0)
+ return new small_temp_iterator(s, 0);
+ else {
+ int n = strlen(s);
+ if (n <= small_temp_iterator::SIZE)
+ return new small_temp_iterator(s, n);
+ else
+ return new temp_iterator(s, n);
+ }
+}
+
+// this is used when macros are interpolated using the .macro_name notation
+
+struct arg_list {
+ macro mac;
+ arg_list *next;
+ arg_list(const macro &);
+ ~arg_list();
+};
+
+arg_list::arg_list(const macro &m) : mac(m), next(0)
+{
+}
+
+arg_list::~arg_list()
+{
+}
+
+class macro_iterator : public string_iterator {
+ arg_list *args;
+ int argc;
+public:
+ macro_iterator(symbol, macro &);
+ macro_iterator();
+ ~macro_iterator();
+ int has_args() { return 1; }
+ input_iterator *get_arg(int i);
+ int nargs() { return argc; }
+ void add_arg(const macro &m);
+ void shift(int n);
+};
+
+input_iterator *macro_iterator::get_arg(int i)
+{
+ if (i == 0)
+ return make_temp_iterator(nm.contents());
+ if (i > 0 && i <= argc) {
+ arg_list *p = args;
+ for (int j = 1; j < i; j++) {
+ assert(p != 0);
+ p = p->next;
+ }
+ return new string_iterator(p->mac);
+ }
+ else
+ return 0;
+}
+
+void macro_iterator::add_arg(const macro &m)
+{
+ for (arg_list **p = &args; *p; p = &((*p)->next))
+ ;
+ *p = new arg_list(m);
+ ++argc;
+}
+
+void macro_iterator::shift(int n)
+{
+ while (n > 0 && argc > 0) {
+ arg_list *tem = args;
+ args = args->next;
+ delete tem;
+ --argc;
+ --n;
+ }
+}
+
+// This gets used by eg .if '\?xxx\?''.
+
+int operator==(const macro &m1, const macro &m2)
+{
+ if (m1.length != m2.length)
+ return 0;
+ string_iterator iter1(m1);
+ string_iterator iter2(m2);
+ int n = m1.length;
+ while (--n >= 0) {
+ node *nd1 = 0;
+ int c1 = iter1.get(&nd1);
+ assert(c1 != EOF);
+ node *nd2 = 0;
+ int c2 = iter2.get(&nd2);
+ assert(c2 != EOF);
+ if (c1 != c2) {
+ if (c1 == 0)
+ delete nd1;
+ else if (c2 == 0)
+ delete nd2;
+ return 0;
+ }
+ if (c1 == 0) {
+ assert(nd1 != 0);
+ assert(nd2 != 0);
+ int are_same = nd1->type() == nd2->type() && nd1->same(nd2);
+ delete nd1;
+ delete nd2;
+ if (!are_same)
+ return 0;
+ }
+ }
+ return 1;
+}
+
+static void interpolate_macro(symbol nm)
+{
+ request_or_macro *p = (request_or_macro *)request_dictionary.lookup(nm);
+ if (p == 0) {
+ int warned = 0;
+ const char *s = nm.contents();
+ if (strlen(s) > 2) {
+ request_or_macro *r;
+ char buf[3];
+ buf[0] = s[0];
+ buf[1] = s[1];
+ buf[2] = '\0';
+ r = (request_or_macro *)request_dictionary.lookup(symbol(buf));
+ if (r) {
+ macro *m = r->to_macro();
+ if (!m || !m->empty())
+ warned = warning(WARN_SPACE,
+ "space required between `%1' and argument", buf);
+ }
+ }
+ if (!warned) {
+ warning(WARN_MAC, "`%1' not defined", nm.contents());
+ p = new macro;
+ request_dictionary.define(nm, p);
+ }
+ }
+ if (p)
+ p->invoke(nm);
+ else {
+ skip_line();
+ return;
+ }
+}
+
+static void decode_args(macro_iterator *mi)
+{
+ if (!tok.newline() && !tok.eof()) {
+ node *n;
+ int c = get_copy(&n);
+ for (;;) {
+ while (c == ' ')
+ c = get_copy(&n);
+ if (c == '\n' || c == EOF)
+ break;
+ macro arg;
+ int quote_input_level = 0;
+ int done_tab_warning = 0;
+ if (c == '\"') {
+ quote_input_level = input_stack::get_level();
+ c = get_copy(&n);
+ }
+ while (c != EOF && c != '\n' && !(c == ' ' && quote_input_level == 0)) {
+ if (quote_input_level > 0 && c == '\"'
+ && (compatible_flag
+ || input_stack::get_level() == quote_input_level)) {
+ c = get_copy(&n);
+ if (c == '"') {
+ arg.append(c);
+ c = get_copy(&n);
+ }
+ else
+ break;
+ }
+ else {
+ if (c == 0)
+ arg.append(n);
+ else {
+ if (c == '\t' && quote_input_level == 0 && !done_tab_warning) {
+ warning(WARN_TAB, "tab character in unquoted macro argument");
+ done_tab_warning = 1;
+ }
+ arg.append(c);
+ }
+ c = get_copy(&n);
+ }
+ }
+ mi->add_arg(arg);
+ }
+ }
+}
+
+void macro::invoke(symbol nm)
+{
+ macro_iterator *mi = new macro_iterator(nm, *this);
+ decode_args(mi);
+ input_stack::push(mi);
+ tok.next();
+}
+
+macro *macro::to_macro()
+{
+ return this;
+}
+
+int macro::empty()
+{
+ return length == 0;
+}
+
+macro_iterator::macro_iterator(symbol s, macro &m)
+: string_iterator(m, "macro", s), args(0), argc(0)
+{
+}
+
+macro_iterator::macro_iterator() : args(0), argc(0)
+{
+}
+
+macro_iterator::~macro_iterator()
+{
+ while (args != 0) {
+ arg_list *tem = args;
+ args = args->next;
+ delete tem;
+ }
+}
+
+void read_request()
+{
+ macro_iterator *mi = new macro_iterator;
+ int reading_from_terminal = isatty(fileno(stdin));
+ int had_prompt = 0;
+ if (!tok.newline() && !tok.eof()) {
+ int c = get_copy(NULL);
+ while (c == ' ')
+ c = get_copy(NULL);
+ while (c != EOF && c != '\n' && c != ' ') {
+ if (!illegal_input_char(c)) {
+ if (reading_from_terminal)
+ fputc(c, stderr);
+ had_prompt = 1;
+ }
+ c = get_copy(NULL);
+ }
+ if (c == ' ') {
+ tok.make_space();
+ decode_args(mi);
+ }
+ }
+ if (reading_from_terminal) {
+ fputc(had_prompt ? ':' : '\007', stderr);
+ fflush(stderr);
+ }
+ input_stack::push(mi);
+ macro mac;
+ int nl = 0;
+ int c;
+ while ((c = getchar()) != EOF) {
+ if (illegal_input_char(c))
+ warning(WARN_INPUT, "illegal input character code %1", int(c));
+ else {
+ if (c == '\n') {
+ if (nl)
+ break;
+ else
+ nl = 1;
+ }
+ else
+ nl = 0;
+ mac.append(c);
+ }
+ }
+ if (reading_from_terminal)
+ clearerr(stdin);
+ input_stack::push(new string_iterator(mac));
+ tok.next();
+}
+
+void do_define_string(int append)
+{
+ symbol nm;
+ node *n;
+ int c;
+ nm = get_name(1);
+ if (nm.is_null()) {
+ skip_line();
+ return;
+ }
+ if (tok.newline())
+ c = '\n';
+ else if (tok.tab())
+ c = '\t';
+ else if (!tok.space()) {
+ error("bad string definition");
+ skip_line();
+ return;
+ }
+ else
+ c = get_copy(&n);
+ while (c == ' ')
+ c = get_copy(&n);
+ if (c == '"')
+ c = get_copy(&n);
+ macro mac;
+ request_or_macro *rm = (request_or_macro *)request_dictionary.lookup(nm);
+ macro *mm = rm ? rm->to_macro() : 0;
+ if (append && mm)
+ mac = *mm;
+ while (c != '\n' && c != EOF) {
+ if (c == 0)
+ mac.append(n);
+ else
+ mac.append((unsigned char)c);
+ c = get_copy(&n);
+ }
+ if (!mm) {
+ mm = new macro;
+ request_dictionary.define(nm, mm);
+ }
+ *mm = mac;
+ tok.next();
+}
+
+void define_string()
+{
+ do_define_string(0);
+}
+
+void append_string()
+{
+ do_define_string(1);
+}
+
+void define_character()
+{
+ node *n;
+ int c;
+ tok.skip();
+ charinfo *ci = tok.get_char(1);
+ if (ci == 0) {
+ skip_line();
+ return;
+ }
+ tok.next();
+ if (tok.newline())
+ c = '\n';
+ else if (tok.tab())
+ c = '\t';
+ else if (!tok.space()) {
+ error("bad character definition");
+ skip_line();
+ return;
+ }
+ else
+ c = get_copy(&n);
+ while (c == ' ' || c == '\t')
+ c = get_copy(&n);
+ if (c == '"')
+ c = get_copy(&n);
+ macro *m = new macro;
+ while (c != '\n' && c != EOF) {
+ if (c == 0)
+ m->append(n);
+ else
+ m->append((unsigned char)c);
+ c = get_copy(&n);
+ }
+ m = ci->set_macro(m);
+ if (m)
+ delete m;
+ tok.next();
+}
+
+
+static void remove_character()
+{
+ tok.skip();
+ while (!tok.newline() && !tok.eof()) {
+ if (!tok.space() && !tok.tab()) {
+ charinfo *ci = tok.get_char(1);
+ if (!ci)
+ break;
+ macro *m = ci->set_macro(0);
+ if (m)
+ delete m;
+ }
+ tok.next();
+ }
+ skip_line();
+}
+
+static void interpolate_string(symbol nm)
+{
+ request_or_macro *p = lookup_request(nm);
+ macro *m = p->to_macro();
+ if (!m)
+ error("you can only invoke a string using \\*");
+ else {
+ string_iterator *si = new string_iterator(*m, "string", nm);
+ input_stack::push(si);
+ }
+}
+
+/* This class is used for the implementation of \$@. It is used for
+each of the closing double quotes. It artificially increases the
+input level by 2, so that the closing double quote will appear to have
+the same input level as the opening quote. */
+
+class end_quote_iterator : public input_iterator {
+ unsigned char buf[1];
+public:
+ end_quote_iterator();
+ ~end_quote_iterator() { }
+ int internal_level() { return 2; }
+};
+
+end_quote_iterator::end_quote_iterator()
+{
+ buf[0] = '"';
+ ptr = buf;
+ eptr = buf + 1;
+}
+
+static void interpolate_arg(symbol nm)
+{
+ const char *s = nm.contents();
+ if (!s || *s == '\0')
+ copy_mode_error("missing argument name");
+ else if (s[1] == 0 && csdigit(s[0]))
+ input_stack::push(input_stack::get_arg(s[0] - '0'));
+ else if (s[0] == '*' && s[1] == '\0') {
+ for (int i = input_stack::nargs(); i > 0; i--) {
+ input_stack::push(input_stack::get_arg(i));
+ if (i != 1)
+ input_stack::push(make_temp_iterator(" "));
+ }
+ }
+ else if (s[0] == '@' && s[1] == '\0') {
+ for (int i = input_stack::nargs(); i > 0; i--) {
+ input_stack::push(new end_quote_iterator);
+ input_stack::push(input_stack::get_arg(i));
+ input_stack::push(make_temp_iterator(i == 1 ? "\"" : " \""));
+ }
+ }
+ else {
+ for (const char *p = s; *p && csdigit(*p); p++)
+ ;
+ if (*p)
+ copy_mode_error("bad argument name `%1'", s);
+ else
+ input_stack::push(input_stack::get_arg(atoi(s)));
+ }
+}
+
+void handle_first_page_transition()
+{
+ push_token(tok);
+ topdiv->begin_page();
+}
+
+// We push back a token by wrapping it up in a token_node, and
+// wrapping that up in a string_iterator.
+
+static void push_token(const token &t)
+{
+ macro m;
+ m.append(new token_node(t));
+ input_stack::push(new string_iterator(m));
+}
+
+void push_page_ejector()
+{
+ static char buf[2] = { PAGE_EJECTOR, '\0' };
+ input_stack::push(make_temp_iterator(buf));
+}
+
+void handle_initial_request(unsigned char code)
+{
+ char buf[2];
+ buf[0] = code;
+ buf[1] = '\0';
+ macro mac;
+ mac.append(new token_node(tok));
+ input_stack::push(new string_iterator(mac));
+ input_stack::push(make_temp_iterator(buf));
+ topdiv->begin_page();
+ tok.next();
+}
+
+void handle_initial_title()
+{
+ handle_initial_request(TITLE_REQUEST);
+}
+
+int trap_sprung_flag = 0;
+int postpone_traps_flag = 0;
+symbol postponed_trap;
+
+void spring_trap(symbol nm)
+{
+ assert(!nm.is_null());
+ trap_sprung_flag = 1;
+ if (postpone_traps_flag) {
+ postponed_trap = nm;
+ return;
+ }
+ static char buf[2] = { BEGIN_TRAP, 0 };
+ static char buf2[2] = { END_TRAP, '\0' };
+ input_stack::push(make_temp_iterator(buf2));
+ request_or_macro *p = lookup_request(nm);
+ macro *m = p->to_macro();
+ if (m)
+ input_stack::push(new string_iterator(*m, "trap-invoked macro", nm));
+ else
+ error("you can't invoke a request with a trap");
+ input_stack::push(make_temp_iterator(buf));
+}
+
+void postpone_traps()
+{
+ postpone_traps_flag = 1;
+}
+
+int unpostpone_traps()
+{
+ postpone_traps_flag = 0;
+ if (!postponed_trap.is_null()) {
+ spring_trap(postponed_trap);
+ postponed_trap = NULL_SYMBOL;
+ return 1;
+ }
+ else
+ return 0;
+}
+
+// this should be local to define_macro, but cfront 1.2 doesn't support that
+static symbol dot_symbol(".");
+
+enum define_mode { DEFINE_NORMAL, DEFINE_APPEND, DEFINE_IGNORE };
+
+void do_define_macro(define_mode mode)
+{
+ symbol nm;
+ if (mode == DEFINE_NORMAL || mode == DEFINE_APPEND) {
+ nm = get_name(1);
+ if (nm.is_null()) {
+ skip_line();
+ return;
+ }
+ }
+ symbol term = get_name(); // the request that terminates the definition
+ if (term.is_null())
+ term = dot_symbol;
+ while (!tok.newline() && !tok.eof())
+ tok.next();
+ const char *start_filename;
+ int start_lineno;
+ int have_start_location = input_stack::get_location(0, &start_filename,
+ &start_lineno);
+ node *n;
+ // doing this here makes the line numbers come out right
+ int c = get_copy(&n, 1);
+ macro mac;
+ macro *mm = 0;
+ if (mode == DEFINE_NORMAL || mode == DEFINE_APPEND) {
+ request_or_macro *rm =
+ (request_or_macro *)request_dictionary.lookup(nm);
+ if (rm)
+ mm = rm->to_macro();
+ if (mm && mode == DEFINE_APPEND)
+ mac = *mm;
+ }
+ int bol = 1;
+ for (;;) {
+ while (c == ESCAPE_NEWLINE) {
+ if (mode == DEFINE_NORMAL || mode == DEFINE_APPEND)
+ mac.append(c);
+ c = get_copy(&n, 1);
+ }
+ if (bol && c == '.') {
+ const char *s = term.contents();
+ int d;
+ // see if it matches term
+ for (int i = 0; s[i] != 0; i++) {
+ d = get_copy(&n);
+ if ((unsigned char)s[i] != d)
+ break;
+ }
+ if (s[i] == 0
+ && ((i == 2 && compatible_flag)
+ || (d = get_copy(&n)) == ' '
+ || d == '\n')) { // we found it
+ if (d == '\n')
+ tok.make_newline();
+ else
+ tok.make_space();
+ if (mode == DEFINE_APPEND || mode == DEFINE_NORMAL) {
+ if (!mm) {
+ mm = new macro;
+ request_dictionary.define(nm, mm);
+ }
+ *mm = mac;
+ }
+ if (term != dot_symbol) {
+ ignoring = 0;
+ interpolate_macro(term);
+ }
+ else
+ skip_line();
+ return;
+ }
+ if (mode == DEFINE_APPEND || mode == DEFINE_NORMAL) {
+ mac.append(c);
+ for (int j = 0; j < i; j++)
+ mac.append(s[j]);
+ }
+ c = d;
+ }
+ if (c == EOF) {
+ if (mode == DEFINE_NORMAL || mode == DEFINE_APPEND) {
+ if (have_start_location)
+ error_with_file_and_line(start_filename, start_lineno,
+ "end of file while defining macro `%1'",
+ nm.contents());
+ else
+ error("end of file while defining macro `%1'", nm.contents());
+ }
+ else {
+ if (have_start_location)
+ error_with_file_and_line(start_filename, start_lineno,
+ "end of file while ignoring input lines");
+ else
+ error("end of file while ignoring input lines");
+ }
+ tok.next();
+ return;
+ }
+ if (mode == DEFINE_NORMAL || mode == DEFINE_APPEND) {
+ if (c == 0)
+ mac.append(n);
+ else
+ mac.append(c);
+ }
+ bol = (c == '\n');
+ c = get_copy(&n, 1);
+ }
+}
+
+void define_macro()
+{
+ do_define_macro(DEFINE_NORMAL);
+}
+
+void append_macro()
+{
+ do_define_macro(DEFINE_APPEND);
+}
+
+void ignore()
+{
+ ignoring = 1;
+ do_define_macro(DEFINE_IGNORE);
+ ignoring = 0;
+}
+
+void remove_macro()
+{
+ for (;;) {
+ symbol s = get_name();
+ if (s.is_null())
+ break;
+ request_dictionary.remove(s);
+ }
+ skip_line();
+}
+
+void rename_macro()
+{
+ symbol s1 = get_name(1);
+ if (!s1.is_null()) {
+ symbol s2 = get_name(1);
+ if (!s2.is_null())
+ request_dictionary.rename(s1, s2);
+ }
+ skip_line();
+}
+
+void alias_macro()
+{
+ symbol s1 = get_name(1);
+ if (!s1.is_null()) {
+ symbol s2 = get_name(1);
+ if (!s2.is_null()) {
+ if (!request_dictionary.alias(s1, s2))
+ warning(WARN_MAC, "`%1' not defined", s2.contents());
+ }
+ }
+ skip_line();
+}
+
+void chop_macro()
+{
+ symbol s = get_name(1);
+ if (!s.is_null()) {
+ request_or_macro *p = lookup_request(s);
+ macro *m = p->to_macro();
+ if (!m)
+ error("cannot chop request");
+ else if (m->length == 0)
+ error("cannot chop empty macro");
+ else
+ m->length -= 1;
+ }
+ skip_line();
+}
+
+void asciify_macro()
+{
+ symbol s = get_name(1);
+ if (!s.is_null()) {
+ request_or_macro *p = lookup_request(s);
+ macro *m = p->to_macro();
+ if (!m)
+ error("cannot asciify request");
+ else {
+ macro am;
+ string_iterator iter(*m);
+ for (;;) {
+ node *nd;
+ int c = iter.get(&nd);
+ if (c == EOF)
+ break;
+ if (c != 0)
+ am.append(c);
+ else
+ nd->asciify(&am);
+ }
+ *m = am;
+ }
+ }
+ skip_line();
+}
+
+static void interpolate_environment_variable(symbol nm)
+{
+ const char *s = getenv(nm.contents());
+ if (s && *s)
+ input_stack::push(make_temp_iterator(s));
+}
+
+void interpolate_number_reg(symbol nm, int inc)
+{
+ reg *r = lookup_number_reg(nm);
+ if (inc < 0)
+ r->decrement();
+ else if (inc > 0)
+ r->increment();
+ input_stack::push(make_temp_iterator(r->get_string()));
+}
+
+static void interpolate_number_format(symbol nm)
+{
+ reg *r = (reg *)number_reg_dictionary.lookup(nm);
+ if (r)
+ input_stack::push(make_temp_iterator(r->get_format()));
+}
+
+static int get_delim_number(units *n, int si, int prev_value)
+{
+ token start;
+ start.next();
+ if (start.delimiter(1)) {
+ tok.next();
+ if (get_number(n, si, prev_value)) {
+ if (start != tok)
+ warning(WARN_DELIM, "closing delimiter does not match");
+ return 1;
+ }
+ }
+ return 0;
+}
+
+static int get_delim_number(units *n, int si)
+{
+ token start;
+ start.next();
+ if (start.delimiter(1)) {
+ tok.next();
+ if (get_number(n, si)) {
+ if (start != tok)
+ warning(WARN_DELIM, "closing delimiter does not match");
+ return 1;
+ }
+ }
+ return 0;
+}
+
+static int get_line_arg(units *n, int si, charinfo **cp)
+{
+ token start;
+ start.next();
+ if (start.delimiter(1)) {
+ tok.next();
+ if (get_number(n, si)) {
+ if (tok.dummy())
+ tok.next();
+ if (start != tok) {
+ *cp = tok.get_char(1);
+ tok.next();
+ }
+ if (start != tok)
+ warning(WARN_DELIM, "closing delimiter does not match");
+ return 1;
+ }
+ }
+ return 0;
+}
+
+static int read_size(int *x)
+{
+ tok.next();
+ int c = tok.ch();
+ int inc = 0;
+ if (c == '-') {
+ inc = -1;
+ tok.next();
+ c = tok.ch();
+ }
+ else if (c == '+') {
+ inc = 1;
+ tok.next();
+ c = tok.ch();
+ }
+ int val;
+ int bad = 0;
+ if (c == '(') {
+ tok.next();
+ c = tok.ch();
+ if (!inc) {
+ // allow an increment either before or after the left parenthesis
+ if (c == '-') {
+ inc = -1;
+ tok.next();
+ c = tok.ch();
+ }
+ else if (c == '+') {
+ inc = 1;
+ tok.next();
+ c = tok.ch();
+ }
+ }
+ if (!csdigit(c))
+ bad = 1;
+ else {
+ val = c - '0';
+ tok.next();
+ c = tok.ch();
+ if (!csdigit(c))
+ bad = 1;
+ else {
+ val = val*10 + (c - '0');
+ val *= sizescale;
+ }
+ }
+ }
+ else if (csdigit(c)) {
+ val = c - '0';
+ if (!inc && c != '0' && c < '4') {
+ tok.next();
+ c = tok.ch();
+ if (!csdigit(c))
+ bad = 1;
+ else
+ val = val*10 + (c - '0');
+ }
+ val *= sizescale;
+ }
+ else if (!tok.delimiter(1))
+ return 0;
+ else {
+ token start(tok);
+ tok.next();
+ if (!(inc
+ ? get_number(&val, 'z')
+ : get_number(&val, 'z', curenv->get_requested_point_size())))
+ return 0;
+ if (!(start.ch() == '[' && tok.ch() == ']') && start != tok) {
+ if (start.ch() == '[')
+ error("missing `]'");
+ else
+ error("missing closing delimiter");
+ return 0;
+ }
+ }
+ if (!bad) {
+ switch (inc) {
+ case 0:
+ *x = val;
+ break;
+ case 1:
+ *x = curenv->get_requested_point_size() + val;
+ break;
+ case -1:
+ *x = curenv->get_requested_point_size() - val;
+ break;
+ default:
+ assert(0);
+ }
+ return 1;
+ }
+ else {
+ error("bad digit in point size");
+ return 0;
+ }
+}
+
+static symbol get_delim_name()
+{
+ token start;
+ start.next();
+ if (start.eof()) {
+ error("end of input at start of delimited name");
+ return NULL_SYMBOL;
+ }
+ if (start.newline()) {
+ error("can't delimit name with a newline");
+ return NULL_SYMBOL;
+ }
+ int start_level = input_stack::get_level();
+ char abuf[ABUF_SIZE];
+ char *buf = abuf;
+ int buf_size = ABUF_SIZE;
+ int i = 0;
+ for (;;) {
+ if (i + 1 > buf_size) {
+ if (buf == abuf) {
+ buf = new char [ABUF_SIZE*2];
+ memcpy(buf, abuf, buf_size);
+ buf_size = ABUF_SIZE*2;
+ }
+ else {
+ char *old_buf = buf;
+ buf = new char[buf_size*2];
+ memcpy(buf, old_buf, buf_size);
+ buf_size *= 2;
+ a_delete old_buf;
+ }
+ }
+ tok.next();
+ if (tok == start
+ && (compatible_flag || input_stack::get_level() == start_level))
+ break;
+ if ((buf[i] = tok.ch()) == 0) {
+ error("missing delimiter (got %1)", tok.description());
+ if (buf != abuf)
+ a_delete buf;
+ return NULL_SYMBOL;
+ }
+ i++;
+ }
+ buf[i] = '\0';
+ if (buf == abuf) {
+ if (i == 0) {
+ error("empty delimited name");
+ return NULL_SYMBOL;
+ }
+ else
+ return symbol(buf);
+ }
+ else {
+ symbol s(buf);
+ a_delete buf;
+ return s;
+ }
+}
+
+
+// Implement \R
+
+static void do_register()
+{
+ token start;
+ start.next();
+ if (!start.delimiter(1))
+ return;
+ tok.next();
+ symbol nm = get_long_name(1);
+ if (nm.is_null())
+ return;
+ while (tok.space())
+ tok.next();
+ reg *r = (reg *)number_reg_dictionary.lookup(nm);
+ int prev_value;
+ if (!r || !r->get_value(&prev_value))
+ prev_value = 0;
+ int val;
+ if (!get_number(&val, 'u', prev_value))
+ return;
+ if (start != tok)
+ warning(WARN_DELIM, "closing delimiter does not match");
+ if (r)
+ r->set_value(val);
+ else
+ set_number_reg(nm, val);
+}
+
+// this implements the \w escape sequence
+
+static void do_width()
+{
+ token start;
+ start.next();
+ int start_level = input_stack::get_level();
+ environment env(curenv);
+ environment *oldenv = curenv;
+ curenv = &env;
+ for (;;) {
+ tok.next();
+ if (tok.eof()) {
+ warning(WARN_DELIM, "missing closing delimiter");
+ break;
+ }
+ if (tok.newline()) {
+ warning(WARN_DELIM, "missing closing delimiter");
+ input_stack::push(make_temp_iterator("\n"));
+ break;
+ }
+ if (tok == start
+ && (compatible_flag || input_stack::get_level() == start_level))
+ break;
+ tok.process();
+ }
+ env.wrap_up_tab();
+ units x = env.get_input_line_position().to_units();
+ input_stack::push(make_temp_iterator(itoa(x)));
+ env.width_registers();
+ curenv = oldenv;
+}
+
+charinfo *page_character;
+
+void set_page_character()
+{
+ page_character = get_optional_char();
+ skip_line();
+}
+
+static const symbol percent_symbol("%");
+
+void read_title_parts(node **part, hunits *part_width)
+{
+ tok.skip();
+ if (tok.newline() || tok.eof())
+ return;
+ token start(tok);
+ int start_level = input_stack::get_level();
+ tok.next();
+ for (int i = 0; i < 3; i++) {
+ while (!tok.newline() && !tok.eof()) {
+ if (tok == start
+ && (compatible_flag || input_stack::get_level() == start_level)) {
+ tok.next();
+ break;
+ }
+ if (page_character != 0 && tok.get_char() == page_character)
+ interpolate_number_reg(percent_symbol, 0);
+ else
+ tok.process();
+ tok.next();
+ }
+ curenv->wrap_up_tab();
+ part_width[i] = curenv->get_input_line_position();
+ part[i] = curenv->extract_output_line();
+ }
+ while (!tok.newline() && !tok.eof())
+ tok.next();
+}
+
+class non_interpreted_node : public node {
+ macro mac;
+public:
+ non_interpreted_node(const macro &);
+ int interpret(macro *);
+ node *copy();
+ int same(node *);
+ const char *type();
+};
+
+non_interpreted_node::non_interpreted_node(const macro &m) : mac(m)
+{
+}
+
+int non_interpreted_node::same(node *nd)
+{
+ return mac == ((non_interpreted_node *)nd)->mac;
+}
+
+const char *non_interpreted_node::type()
+{
+ return "non_interpreted_node";
+}
+
+node *non_interpreted_node::copy()
+{
+ return new non_interpreted_node(mac);
+}
+
+int non_interpreted_node::interpret(macro *m)
+{
+ string_iterator si(mac);
+ node *n;
+ for (;;) {
+ int c = si.get(&n);
+ if (c == EOF)
+ break;
+ if (c == 0)
+ m->append(n);
+ else
+ m->append(c);
+ }
+ return 1;
+}
+
+static node *do_non_interpreted()
+{
+ node *n;
+ int c;
+ macro mac;
+ while ((c = get_copy(&n)) != ESCAPE_QUESTION && c != EOF && c != '\n')
+ if (c == 0)
+ mac.append(n);
+ else
+ mac.append(c);
+ if (c == EOF || c == '\n') {
+ error("missing \\?");
+ return 0;
+ }
+ return new non_interpreted_node(mac);
+}
+
+node *do_special()
+{
+ token start;
+ start.next();
+ int start_level = input_stack::get_level();
+ macro mac;
+ for (tok.next();
+ tok != start || input_stack::get_level() != start_level;
+ tok.next()) {
+ if (tok.eof()) {
+ warning(WARN_DELIM, "missing closing delimiter");
+ return 0;
+ }
+ if (tok.newline()) {
+ input_stack::push(make_temp_iterator("\n"));
+ warning(WARN_DELIM, "missing closing delimiter");
+ break;
+ }
+ unsigned char c;
+ if (tok.space())
+ c = ' ';
+ else if (tok.tab())
+ c = '\t';
+ else if (tok.leader())
+ c = '\001';
+ else if (tok.backspace())
+ c = '\b';
+ else
+ c = tok.ch();
+ if (c == '\0')
+ error("%1 is illegal within \\X", tok.description());
+ else
+ mac.append(c);
+ }
+ return new special_node(mac);
+}
+
+void special_node::tprint(troff_output_file *out)
+{
+ tprint_start(out);
+ string_iterator iter(mac);
+ for (;;) {
+ int c = iter.get(NULL);
+ if (c == EOF)
+ break;
+ for (const char *s = ::asciify(c); *s; s++)
+ tprint_char(out, *s);
+ }
+ tprint_end(out);
+}
+
+int get_file_line(const char **filename, int *lineno)
+{
+ return input_stack::get_location(0, filename, lineno);
+}
+
+void line_file()
+{
+ int n;
+ if (get_integer(&n)) {
+ const char *filename = 0;
+ if (has_arg()) {
+ symbol s = get_long_name();
+ filename = s.contents();
+ }
+ (void)input_stack::set_location(filename, n-1);
+ }
+ skip_line();
+}
+
+static int nroff_mode = 0;
+
+static void nroff_request()
+{
+ nroff_mode = 1;
+ skip_line();
+}
+
+static void troff_request()
+{
+ nroff_mode = 0;
+ skip_line();
+}
+
+static void skip_alternative()
+{
+ int level = 0;
+ // ensure that ``.if 0\{'' works as expected
+ if (tok.left_brace())
+ level++;
+ int c;
+ for (;;) {
+ c = input_stack::get(NULL);
+ if (c == EOF)
+ break;
+ if (c == ESCAPE_LEFT_BRACE)
+ ++level;
+ else if (c == ESCAPE_RIGHT_BRACE)
+ --level;
+ else if (c == escape_char && escape_char > 0)
+ switch(input_stack::get(NULL)) {
+ case '{':
+ ++level;
+ break;
+ case '}':
+ --level;
+ break;
+ case '"':
+ while ((c = input_stack::get(NULL)) != '\n' && c != EOF)
+ ;
+ }
+ /*
+ Note that the level can properly be < 0, eg
+
+ .if 1 \{\
+ .if 0 \{\
+ .\}\}
+
+ So don't give an error message in this case.
+ */
+ if (level <= 0 && c == '\n')
+ break;
+ }
+ tok.next();
+}
+
+static void begin_alternative()
+{
+ while (tok.space() || tok.left_brace())
+ tok.next();
+}
+
+
+static int_stack if_else_stack;
+
+int do_if_request()
+{
+ int invert = 0;
+ while (tok.space())
+ tok.next();
+ while (tok.ch() == '!') {
+ tok.next();
+ invert = !invert;
+ }
+ int result;
+ unsigned char c = tok.ch();
+ if (c == 't') {
+ tok.next();
+ result = !nroff_mode;
+ }
+ else if (c == 'n') {
+ tok.next();
+ result = nroff_mode;
+ }
+ else if (c == 'v') {
+ tok.next();
+ result = 0;
+ }
+ else if (c == 'o') {
+ result = (topdiv->get_page_number() & 1);
+ tok.next();
+ }
+ else if (c == 'e') {
+ result = !(topdiv->get_page_number() & 1);
+ tok.next();
+ }
+ else if (c == 'd' || c == 'r') {
+ tok.next();
+ symbol nm = get_name(1);
+ if (nm.is_null()) {
+ skip_alternative();
+ return 0;
+ }
+ result = (c == 'd'
+ ? request_dictionary.lookup(nm) != 0
+ : number_reg_dictionary.lookup(nm) != 0);
+ }
+ else if (c == 'c') {
+ tok.next();
+ tok.skip();
+ charinfo *ci = tok.get_char(1);
+ if (ci == 0) {
+ skip_alternative();
+ return 0;
+ }
+ result = character_exists(ci, curenv);
+ tok.next();
+ }
+ else if (tok.space())
+ result = 0;
+ else if (tok.delimiter()) {
+ token delim = tok;
+ int delim_level = input_stack::get_level();
+ environment env1(curenv);
+ environment env2(curenv);
+ environment *oldenv = curenv;
+ curenv = &env1;
+ for (int i = 0; i < 2; i++) {
+ for (;;) {
+ tok.next();
+ if (tok.newline() || tok.eof()) {
+ warning(WARN_DELIM, "missing closing delimiter");
+ tok.next();
+ curenv = oldenv;
+ return 0;
+ }
+ if (tok == delim
+ && (compatible_flag || input_stack::get_level() == delim_level))
+ break;
+ tok.process();
+ }
+ curenv = &env2;
+ }
+ node *n1 = env1.extract_output_line();
+ node *n2 = env2.extract_output_line();
+ result = same_node_list(n1, n2);
+ delete_node_list(n1);
+ delete_node_list(n2);
+ tok.next();
+ curenv = oldenv;
+ }
+ else {
+ units n;
+ if (!get_number(&n, 'u')) {
+ skip_alternative();
+ return 0;
+ }
+ else
+ result = n > 0;
+ }
+ if (invert)
+ result = !result;
+ if (result)
+ begin_alternative();
+ else
+ skip_alternative();
+ return result;
+}
+
+void if_else_request()
+{
+ if_else_stack.push(do_if_request());
+}
+
+void if_request()
+{
+ do_if_request();
+}
+
+void else_request()
+{
+ if (if_else_stack.is_empty()) {
+ warning(WARN_EL, "unbalanced .el request");
+ skip_alternative();
+ }
+ else {
+ if (if_else_stack.pop())
+ skip_alternative();
+ else
+ begin_alternative();
+ }
+}
+
+static int while_depth = 0;
+static int while_break_flag = 0;
+
+void while_request()
+{
+ macro mac;
+ int escaped = 0;
+ int level = 0;
+ mac.append(new token_node(tok));
+ for (;;) {
+ node *n;
+ int c = input_stack::get(&n);
+ if (c == EOF)
+ break;
+ if (c == 0) {
+ escaped = 0;
+ mac.append(n);
+ }
+ else if (escaped) {
+ if (c == '{')
+ level += 1;
+ else if (c == '}')
+ level -= 1;
+ escaped = 0;
+ mac.append(c);
+ }
+ else {
+ if (c == ESCAPE_LEFT_BRACE)
+ level += 1;
+ else if (c == ESCAPE_RIGHT_BRACE)
+ level -= 1;
+ else if (c == escape_char)
+ escaped = 1;
+ mac.append(c);
+ if (c == '\n' && level <= 0)
+ break;
+ }
+ }
+ if (level != 0)
+ error("unbalanced \\{ \\}");
+ else {
+ while_depth++;
+ input_stack::add_boundary();
+ for (;;) {
+ input_stack::push(new string_iterator(mac, "while loop"));
+ tok.next();
+ if (!do_if_request()) {
+ while (input_stack::get(NULL) != EOF)
+ ;
+ break;
+ }
+ process_input_stack();
+ if (while_break_flag) {
+ while_break_flag = 0;
+ break;
+ }
+ }
+ input_stack::remove_boundary();
+ while_depth--;
+ }
+ tok.next();
+}
+
+void while_break_request()
+{
+ if (!while_depth) {
+ error("no while loop");
+ skip_line();
+ }
+ else {
+ while_break_flag = 1;
+ while (input_stack::get(NULL) != EOF)
+ ;
+ tok.next();
+ }
+}
+
+void while_continue_request()
+{
+ if (!while_depth) {
+ error("no while loop");
+ skip_line();
+ }
+ else {
+ while (input_stack::get(NULL) != EOF)
+ ;
+ tok.next();
+ }
+}
+
+// .so
+
+void source()
+{
+ symbol nm = get_long_name(1);
+ if (nm.is_null())
+ skip_line();
+ else {
+ while (!tok.newline() && !tok.eof())
+ tok.next();
+ errno = 0;
+ FILE *fp = fopen(nm.contents(), "r");
+ if (fp)
+ input_stack::push(new file_iterator(fp, nm.contents()));
+ else
+ error("can't open `%1': %2", nm.contents(), strerror(errno));
+ tok.next();
+ }
+}
+
+// like .so but use popen()
+
+void pipe_source()
+{
+#ifdef POPEN_MISSING
+ error("pipes not available on this system");
+ skip_line();
+#else /* not POPEN_MISSING */
+ if (tok.newline() || tok.eof())
+ error("missing command");
+ else {
+ int c;
+ while ((c = get_copy(NULL)) == ' ' || c == '\t')
+ ;
+ int buf_size = 24;
+ char *buf = new char[buf_size];
+ int buf_used = 0;
+ for (; c != '\n' && c != EOF; c = get_copy(NULL)) {
+ const char *s = asciify(c);
+ int slen = strlen(s);
+ if (buf_used + slen + 1> buf_size) {
+ char *old_buf = buf;
+ int old_buf_size = buf_size;
+ buf_size *= 2;
+ buf = new char[buf_size];
+ memcpy(buf, old_buf, old_buf_size);
+ a_delete old_buf;
+ }
+ strcpy(buf + buf_used, s);
+ buf_used += slen;
+ }
+ buf[buf_used] = '\0';
+ errno = 0;
+ FILE *fp = popen(buf, "r");
+ if (fp)
+ input_stack::push(new file_iterator(fp, symbol(buf).contents(), 1));
+ else
+ error("can't open pipe to process `%1': %2", buf, strerror(errno));
+ a_delete buf;
+ }
+ tok.next();
+#endif /* not POPEN_MISSING */
+}
+
+const char *asciify(int c)
+{
+ static char buf[3];
+ buf[0] = escape_char == '\0' ? '\\' : escape_char;
+ buf[1] = buf[2] = '\0';
+ switch (c) {
+ case ESCAPE_QUESTION:
+ buf[1] = '?';
+ break;
+ case ESCAPE_AMPERSAND:
+ buf[1] = '&';
+ break;
+ case ESCAPE_UNDERSCORE:
+ buf[1] = '_';
+ break;
+ case ESCAPE_BAR:
+ buf[1] = '|';
+ break;
+ case ESCAPE_CIRCUMFLEX:
+ buf[1] = '^';
+ break;
+ case ESCAPE_LEFT_BRACE:
+ buf[1] = '{';
+ break;
+ case ESCAPE_RIGHT_BRACE:
+ buf[1] = '}';
+ break;
+ case ESCAPE_LEFT_QUOTE:
+ buf[1] = '`';
+ break;
+ case ESCAPE_RIGHT_QUOTE:
+ buf[1] = '\'';
+ break;
+ case ESCAPE_HYPHEN:
+ buf[1] = '-';
+ break;
+ case ESCAPE_BANG:
+ buf[1] = '!';
+ break;
+ case ESCAPE_c:
+ buf[1] = 'c';
+ break;
+ case ESCAPE_e:
+ buf[1] = 'e';
+ break;
+ case ESCAPE_E:
+ buf[1] = 'E';
+ break;
+ case ESCAPE_PERCENT:
+ buf[1] = '%';
+ break;
+ case ESCAPE_SPACE:
+ buf[1] = ' ';
+ break;
+ default:
+ if (illegal_input_char(c))
+ buf[0] = '\0';
+ else
+ buf[0] = c;
+ break;
+ }
+ return buf;
+}
+
+
+const char *input_char_description(int c)
+{
+ switch (c) {
+ case '\n':
+ return "a newline character";
+ case '\b':
+ return "a backspace character";
+ case '\001':
+ return "a leader character";
+ case '\t':
+ return "a tab character ";
+ case ' ':
+ return "a space character";
+ case '\0':
+ return "a node";
+ }
+ static char buf[sizeof("magic character code ") + 1 + INT_DIGITS];
+ if (illegal_input_char(c)) {
+ const char *s = asciify(c);
+ if (*s) {
+ buf[0] = '`';
+ strcpy(buf + 1, s);
+ strcat(buf, "'");
+ return buf;
+ }
+ sprintf(buf, "magic character code %d", c);
+ return buf;
+ }
+ if (csprint(c)) {
+ buf[0] = '`';
+ buf[1] = c;
+ buf[2] = '\'';
+ return buf;
+ }
+ sprintf(buf, "character code %d", c);
+ return buf;
+}
+
+// .tm
+
+void terminal()
+{
+ if (!tok.newline() && !tok.eof()) {
+ int c;
+ while ((c = get_copy(NULL)) == ' ' || c == '\t')
+ ;
+ for (; c != '\n' && c != EOF; c = get_copy(NULL))
+ fputs(asciify(c), stderr);
+ }
+ fputc('\n', stderr);
+ fflush(stderr);
+ tok.next();
+}
+
+dictionary stream_dictionary(20);
+
+void do_open(int append)
+{
+ symbol stream = get_name(1);
+ if (!stream.is_null()) {
+ symbol filename = get_long_name(1);
+ if (!filename.is_null()) {
+ errno = 0;
+ FILE *fp = fopen(filename.contents(), append ? "a" : "w");
+ if (!fp) {
+ error("can't open `%1' for %2: %3",
+ filename.contents(),
+ append ? "appending" : "writing",
+ strerror(errno));
+ fp = (FILE *)stream_dictionary.remove(stream);
+ }
+ else
+ fp = (FILE *)stream_dictionary.lookup(stream, fp);
+ if (fp)
+ fclose(fp);
+ }
+ }
+ skip_line();
+}
+
+void open_request()
+{
+ do_open(0);
+}
+
+void opena_request()
+{
+ do_open(1);
+}
+
+void close_request()
+{
+ symbol stream = get_name(1);
+ if (!stream.is_null()) {
+ FILE *fp = (FILE *)stream_dictionary.remove(stream);
+ if (!fp)
+ error("no stream named `%1'", stream.contents());
+ else
+ fclose(fp);
+ }
+ skip_line();
+}
+
+void write_request()
+{
+ symbol stream = get_name(1);
+ if (stream.is_null()) {
+ skip_line();
+ return;
+ }
+ FILE *fp = (FILE *)stream_dictionary.lookup(stream);
+ if (!fp) {
+ error("no stream named `%1'", stream.contents());
+ skip_line();
+ return;
+ }
+ int c;
+ while ((c = get_copy(NULL)) == ' ')
+ ;
+ if (c == '"')
+ c = get_copy(NULL);
+ for (; c != '\n' && c != EOF; c = get_copy(NULL))
+ fputs(asciify(c), fp);
+ fputc('\n', fp);
+ fflush(fp);
+ tok.next();
+}
+
+static void init_charset_table()
+{
+ char buf[16];
+ strcpy(buf, "char");
+ for (int i = 0; i < 256; i++) {
+ strcpy(buf + 4, itoa(i));
+ charset_table[i] = get_charinfo(symbol(buf));
+ charset_table[i]->set_ascii_code(i);
+ if (csalpha(i))
+ charset_table[i]->set_hyphenation_code(cmlower(i));
+ }
+ charset_table['.']->set_flags(charinfo::ENDS_SENTENCE);
+ charset_table['?']->set_flags(charinfo::ENDS_SENTENCE);
+ charset_table['!']->set_flags(charinfo::ENDS_SENTENCE);
+ charset_table['-']->set_flags(charinfo::BREAK_AFTER);
+ charset_table['"']->set_flags(charinfo::TRANSPARENT);
+ charset_table['\'']->set_flags(charinfo::TRANSPARENT);
+ charset_table[')']->set_flags(charinfo::TRANSPARENT);
+ charset_table[']']->set_flags(charinfo::TRANSPARENT);
+ charset_table['*']->set_flags(charinfo::TRANSPARENT);
+ get_charinfo(symbol("dg"))->set_flags(charinfo::TRANSPARENT);
+ get_charinfo(symbol("rq"))->set_flags(charinfo::TRANSPARENT);
+ get_charinfo(symbol("em"))->set_flags(charinfo::BREAK_AFTER);
+ get_charinfo(symbol("ul"))->set_flags(charinfo::OVERLAPS_HORIZONTALLY);
+ get_charinfo(symbol("rn"))->set_flags(charinfo::OVERLAPS_HORIZONTALLY);
+ get_charinfo(symbol("radicalex"))->set_flags(charinfo::OVERLAPS_HORIZONTALLY);
+ get_charinfo(symbol("ru"))->set_flags(charinfo::OVERLAPS_HORIZONTALLY);
+ get_charinfo(symbol("br"))->set_flags(charinfo::OVERLAPS_VERTICALLY);
+ page_character = charset_table['%'];
+}
+
+static
+void do_translate(int translate_transparent)
+{
+ tok.skip();
+ while (!tok.newline() && !tok.eof()) {
+ if (tok.space()) {
+ // This is a really bizarre troff feature.
+ tok.next();
+ translate_space_to_dummy = tok.dummy();
+ if (tok.newline() || tok.eof())
+ break;
+ tok.next();
+ continue;
+ }
+ charinfo *ci1 = tok.get_char(1);
+ if (ci1 == 0)
+ break;
+ tok.next();
+ if (tok.newline() || tok.eof()) {
+ ci1->set_special_translation(charinfo::TRANSLATE_SPACE,
+ translate_transparent);
+ break;
+ }
+ if (tok.space())
+ ci1->set_special_translation(charinfo::TRANSLATE_SPACE,
+ translate_transparent);
+ else if (tok.dummy())
+ ci1->set_special_translation(charinfo::TRANSLATE_DUMMY,
+ translate_transparent);
+ else if (tok.hyphen_indicator())
+ ci1->set_special_translation(charinfo::TRANSLATE_HYPHEN_INDICATOR,
+ translate_transparent);
+ else {
+ charinfo *ci2 = tok.get_char(1);
+ if (ci2 == 0)
+ break;
+ if (ci1 == ci2)
+ ci1->set_translation(0, translate_transparent);
+ else
+ ci1->set_translation(ci2, translate_transparent);
+ }
+ tok.next();
+ }
+ skip_line();
+}
+
+void translate()
+{
+ do_translate(1);
+}
+
+void translate_no_transparent()
+{
+ do_translate(0);
+}
+
+void char_flags()
+{
+ int flags;
+ if (get_integer(&flags))
+ while (has_arg()) {
+ charinfo *ci = tok.get_char(1);
+ if (ci) {
+ charinfo *tem = ci->get_translation();
+ if (tem)
+ ci = tem;
+ ci->set_flags(flags);
+ }
+ tok.next();
+ }
+ skip_line();
+}
+
+void hyphenation_code()
+{
+ tok.skip();
+ while (!tok.newline() && !tok.eof()) {
+ charinfo *ci = tok.get_char(1);
+ if (ci == 0)
+ break;
+ tok.next();
+ tok.skip();
+ unsigned char c = tok.ch();
+ if (c == 0) {
+ error("hyphenation code must be ordinary character");
+ break;
+ }
+ if (csdigit(c)) {
+ error("hyphenation code cannot be digit");
+ break;
+ }
+ ci->set_hyphenation_code(c);
+ tok.next();
+ tok.skip();
+ }
+ skip_line();
+}
+
+charinfo *token::get_char(int required)
+{
+ if (type == TOKEN_CHAR)
+ return charset_table[c];
+ if (type == TOKEN_SPECIAL)
+ return get_charinfo(nm);
+ if (type == TOKEN_NUMBERED_CHAR)
+ return get_charinfo_by_number(val);
+ if (type == TOKEN_ESCAPE) {
+ if (escape_char != 0)
+ return charset_table[escape_char];
+ else {
+ error("`\\e' used while no current escape character");
+ return 0;
+ }
+ }
+ if (required) {
+ if (type == TOKEN_EOF || type == TOKEN_NEWLINE)
+ warning(WARN_MISSING, "missing normal or special character");
+ else
+ error("normal or special character expected (got %1)", description());
+ }
+ return 0;
+}
+
+charinfo *get_optional_char()
+{
+ while (tok.space())
+ tok.next();
+ charinfo *ci = tok.get_char();
+ if (!ci) {
+ if (!tok.newline() && !tok.eof() && !tok.right_brace() && !tok.tab())
+ error("normal or special character expected (got %1): "
+ "treated as missing",
+ tok.description());
+ }
+ else
+ tok.next();
+ return ci;
+}
+
+int token::add_to_node_list(node **pp)
+{
+ hunits w;
+ node *n = 0;
+ switch (type) {
+ case TOKEN_CHAR:
+ *pp = (*pp)->add_char(charset_table[c], curenv, &w);
+ break;
+ case TOKEN_DUMMY:
+ n = new dummy_node;
+ break;
+ case TOKEN_ESCAPE:
+ if (escape_char != 0)
+ *pp = (*pp)->add_char(charset_table[escape_char], curenv, &w);
+ break;
+ case TOKEN_HYPHEN_INDICATOR:
+ *pp = (*pp)->add_discretionary_hyphen();
+ break;
+ case TOKEN_ITALIC_CORRECTION:
+ *pp = (*pp)->add_italic_correction(&w);
+ break;
+ case TOKEN_LEFT_BRACE:
+ break;
+ case TOKEN_MARK_INPUT:
+ set_number_reg(nm, curenv->get_input_line_position().to_units());
+ break;
+ case TOKEN_NODE:
+ n = nd;
+ nd = 0;
+ break;
+ case TOKEN_NUMBERED_CHAR:
+ *pp = (*pp)->add_char(get_charinfo_by_number(val), curenv, &w);
+ break;
+ case TOKEN_RIGHT_BRACE:
+ break;
+ case TOKEN_SPACE:
+ n = new hmotion_node(curenv->get_space_width());
+ break;
+ case TOKEN_SPECIAL:
+ *pp = (*pp)->add_char(get_charinfo(nm), curenv, &w);
+ break;
+ default:
+ return 0;
+ }
+ if (n) {
+ n->next = *pp;
+ *pp = n;
+ }
+ return 1;
+}
+
+void token::process()
+{
+ if (possibly_handle_first_page_transition())
+ return;
+ switch (type) {
+ case TOKEN_BACKSPACE:
+ curenv->add_node(new hmotion_node(-curenv->get_space_width()));
+ break;
+ case TOKEN_CHAR:
+ curenv->add_char(charset_table[c]);
+ break;
+ case TOKEN_DUMMY:
+ curenv->add_node(new dummy_node);
+ break;
+ case TOKEN_EOF:
+ assert(0);
+ break;
+ case TOKEN_EMPTY:
+ assert(0);
+ break;
+ case TOKEN_ESCAPE:
+ if (escape_char != 0)
+ curenv->add_char(charset_table[escape_char]);
+ break;
+ case TOKEN_BEGIN_TRAP:
+ case TOKEN_END_TRAP:
+ case TOKEN_PAGE_EJECTOR:
+ // these are all handled in process_input_stack()
+ break;
+ case TOKEN_HYPHEN_INDICATOR:
+ curenv->add_hyphen_indicator();
+ break;
+ case TOKEN_INTERRUPT:
+ curenv->interrupt();
+ break;
+ case TOKEN_ITALIC_CORRECTION:
+ curenv->add_italic_correction();
+ break;
+ case TOKEN_LEADER:
+ curenv->handle_tab(1);
+ break;
+ case TOKEN_LEFT_BRACE:
+ break;
+ case TOKEN_MARK_INPUT:
+ set_number_reg(nm, curenv->get_input_line_position().to_units());
+ break;
+ case TOKEN_NEWLINE:
+ curenv->newline();
+ break;
+ case TOKEN_NODE:
+ curenv->add_node(nd);
+ nd = 0;
+ break;
+ case TOKEN_NUMBERED_CHAR:
+ curenv->add_char(get_charinfo_by_number(val));
+ break;
+ case TOKEN_REQUEST:
+ // handled in process_input_stack
+ break;
+ case TOKEN_RIGHT_BRACE:
+ break;
+ case TOKEN_SPACE:
+ curenv->space();
+ break;
+ case TOKEN_SPECIAL:
+ curenv->add_char(get_charinfo(nm));
+ break;
+ case TOKEN_SPREAD:
+ curenv->spread();
+ break;
+ case TOKEN_TAB:
+ curenv->handle_tab(0);
+ break;
+ case TOKEN_TRANSPARENT:
+ break;
+ default:
+ assert(0);
+ }
+}
+
+class nargs_reg : public reg {
+public:
+ const char *get_string();
+};
+
+const char *nargs_reg::get_string()
+{
+ return itoa(input_stack::nargs());
+}
+
+class lineno_reg : public reg {
+public:
+ const char *get_string();
+};
+
+const char *lineno_reg::get_string()
+{
+ int line;
+ const char *file;
+ if (!input_stack::get_location(0, &file, &line))
+ line = 0;
+ return itoa(line);
+}
+
+
+class writable_lineno_reg : public general_reg {
+public:
+ writable_lineno_reg();
+ void set_value(units);
+ int get_value(units *);
+};
+
+writable_lineno_reg::writable_lineno_reg()
+{
+}
+
+int writable_lineno_reg::get_value(units *res)
+{
+ int line;
+ const char *file;
+ if (!input_stack::get_location(0, &file, &line))
+ return 0;
+ *res = line;
+ return 1;
+}
+
+void writable_lineno_reg::set_value(units n)
+{
+ input_stack::set_location(0, n);
+}
+
+class filename_reg : public reg {
+public:
+ const char *get_string();
+};
+
+const char *filename_reg::get_string()
+{
+ int line;
+ const char *file;
+ if (input_stack::get_location(0, &file, &line))
+ return file;
+ else
+ return 0;
+}
+
+
+class constant_reg : public reg {
+ const char *s;
+public:
+ constant_reg(const char *);
+ const char *get_string();
+};
+
+constant_reg::constant_reg(const char *p) : s(p)
+{
+}
+
+const char *constant_reg::get_string()
+{
+ return s;
+}
+
+constant_int_reg::constant_int_reg(int *q) : p(q)
+{
+}
+
+const char *constant_int_reg::get_string()
+{
+ return itoa(*p);
+}
+
+void abort_request()
+{
+ int c;
+ if (tok.eof())
+ c = EOF;
+ else if (tok.newline())
+ c = '\n';
+ else {
+ while ((c = get_copy(0)) == ' ')
+ ;
+ }
+ if (c == EOF || c == '\n')
+ fputs("User Abort.", stderr);
+ else {
+ for (; c != '\n' && c != EOF; c = get_copy(NULL))
+ fputs(asciify(c), stderr);
+ }
+ fputc('\n', stderr);
+ cleanup_and_exit(1);
+}
+
+char *read_string()
+{
+ int len = 256;
+ char *s = new char[len];
+ int c;
+ while ((c = get_copy(0)) == ' ')
+ ;
+ int i = 0;
+ while (c != '\n' && c != EOF) {
+ if (!illegal_input_char(c)) {
+ if (i + 2 > len) {
+ char *tem = s;
+ s = new char[len*2];
+ memcpy(s, tem, len);
+ len *= 2;
+ a_delete tem;
+ }
+ s[i++] = c;
+ }
+ c = get_copy(0);
+ }
+ s[i] = '\0';
+ tok.next();
+ if (i == 0) {
+ a_delete s;
+ return 0;
+ }
+ return s;
+}
+
+void pipe_output()
+{
+#ifdef POPEN_MISSING
+ error("pipes not available on this system");
+ skip_line();
+#else /* not POPEN_MISSING */
+ if (the_output) {
+ error("can't pipe: output already started");
+ skip_line();
+ }
+ else {
+ if ((pipe_command = read_string()) == 0)
+ error("can't pipe to empty command");
+ }
+#endif /* not POPEN_MISSING */
+}
+
+static int system_status;
+
+void system_request()
+{
+ char *command = read_string();
+ if (!command)
+ error("empty command");
+ else {
+ system_status = system(command);
+ a_delete command;
+ }
+}
+
+void copy_file()
+{
+ if (curdiv == topdiv && topdiv->before_first_page) {
+ handle_initial_request(COPY_FILE_REQUEST);
+ return;
+ }
+ symbol filename = get_long_name(1);
+ while (!tok.newline() && !tok.eof())
+ tok.next();
+ if (break_flag)
+ curenv->do_break();
+ if (!filename.is_null())
+ curdiv->copy_file(filename.contents());
+ tok.next();
+}
+
+#ifdef COLUMN
+
+void vjustify()
+{
+ if (curdiv == topdiv && topdiv->before_first_page) {
+ handle_initial_request(VJUSTIFY_REQUEST);
+ return;
+ }
+ symbol type = get_long_name(1);
+ if (!type.is_null())
+ curdiv->vjustify(type);
+ skip_line();
+}
+
+#endif /* COLUMN */
+
+void transparent_file()
+{
+ if (curdiv == topdiv && topdiv->before_first_page) {
+ handle_initial_request(TRANSPARENT_FILE_REQUEST);
+ return;
+ }
+ symbol filename = get_long_name(1);
+ while (!tok.newline() && !tok.eof())
+ tok.next();
+ if (break_flag)
+ curenv->do_break();
+ if (!filename.is_null()) {
+ errno = 0;
+ FILE *fp = fopen(filename.contents(), "r");
+ if (!fp)
+ error("can't open `%1': %2", filename.contents(), strerror(errno));
+ else {
+ int bol = 1;
+ for (;;) {
+ int c = getc(fp);
+ if (c == EOF)
+ break;
+ if (illegal_input_char(c))
+ warning(WARN_INPUT, "illegal input character code %1", int(c));
+ else {
+ curdiv->transparent_output(c);
+ bol = c == '\n';
+ }
+ }
+ if (!bol)
+ curdiv->transparent_output('\n');
+ fclose(fp);
+ }
+ }
+ tok.next();
+}
+
+class page_range {
+ int first;
+ int last;
+public:
+ page_range *next;
+ page_range(int, int, page_range *);
+ int contains(int n);
+};
+
+page_range::page_range(int i, int j, page_range *p)
+: first(i), last(j), next(p)
+{
+}
+
+int page_range::contains(int n)
+{
+ return n >= first && (last <= 0 || n <= last);
+}
+
+page_range *output_page_list = 0;
+
+int in_output_page_list(int n)
+{
+ if (!output_page_list)
+ return 1;
+ for (page_range *p = output_page_list; p; p = p->next)
+ if (p->contains(n))
+ return 1;
+ return 0;
+}
+
+static void parse_output_page_list(char *p)
+{
+ for (;;) {
+ int i;
+ if (*p == '-')
+ i = 1;
+ else if (csdigit(*p)) {
+ i = 0;
+ do
+ i = i*10 + *p++ - '0';
+ while (csdigit(*p));
+ }
+ else
+ break;
+ int j;
+ if (*p == '-') {
+ p++;
+ j = 0;
+ if (csdigit(*p)) {
+ do
+ j = j*10 + *p++ - '0';
+ while (csdigit(*p));
+ }
+ }
+ else
+ j = i;
+ if (j == 0)
+ last_page_number = -1;
+ else if (last_page_number >= 0 && j > last_page_number)
+ last_page_number = j;
+ output_page_list = new page_range(i, j, output_page_list);
+ if (*p != ',')
+ break;
+ ++p;
+ }
+ if (*p != '\0') {
+ error("bad output page list");
+ output_page_list = 0;
+ }
+}
+
+static FILE *open_mac_file(const char *mac, char **path)
+{
+ char *s = new char[strlen(mac)+strlen(MACRO_PREFIX)+1];
+ strcpy(s, MACRO_PREFIX);
+ strcat(s, mac);
+ FILE *fp = macro_path.open_file(s, path);
+ a_delete s;
+ return fp;
+}
+
+static void process_macro_file(const char *mac)
+{
+ char *path;
+ FILE *fp = open_mac_file(mac, &path);
+ if (!fp)
+ fatal("can't find macro file %1", mac);
+ const char *s = symbol(path).contents();
+ a_delete path;
+ input_stack::push(new file_iterator(fp, s));
+ tok.next();
+ process_input_stack();
+}
+
+static void process_startup_file()
+{
+ char *path;
+ FILE *fp = macro_path.open_file(STARTUP_FILE, &path);
+ if (fp) {
+ input_stack::push(new file_iterator(fp, symbol(path).contents()));
+ a_delete path;
+ tok.next();
+ process_input_stack();
+ }
+}
+
+void macro_source()
+{
+ symbol nm = get_long_name(1);
+ if (nm.is_null())
+ skip_line();
+ else {
+ while (!tok.newline() && !tok.eof())
+ tok.next();
+ char *path;
+ FILE *fp = macro_path.open_file(nm.contents(), &path);
+ if (fp) {
+ input_stack::push(new file_iterator(fp, symbol(path).contents()));
+ a_delete path;
+ }
+ else
+ error("can't find macro file `%1'", nm.contents());
+ tok.next();
+ }
+}
+
+static void process_input_file(const char *name)
+{
+ FILE *fp;
+ if (strcmp(name, "-") == 0) {
+ clearerr(stdin);
+ fp = stdin;
+ }
+ else {
+ errno = 0;
+ fp = fopen(name, "r");
+ if (!fp)
+ fatal("can't open `%1': %2", name, strerror(errno));
+ }
+ input_stack::push(new file_iterator(fp, name));
+ tok.next();
+ process_input_stack();
+}
+
+// make sure the_input is empty before calling this
+
+static int evaluate_expression(const char *expr, units *res)
+{
+ input_stack::push(make_temp_iterator(expr));
+ tok.next();
+ int success = get_number(res, 'u');
+ while (input_stack::get(NULL) != EOF)
+ ;
+ return success;
+}
+
+static void do_register_assignment(const char *s)
+{
+ const char *p = strchr(s, '=');
+ if (!p) {
+ char buf[2];
+ buf[0] = s[0];
+ buf[1] = 0;
+ units n;
+ if (evaluate_expression(s + 1, &n))
+ set_number_reg(buf, n);
+ }
+ else {
+ char *buf = new char[p - s + 1];
+ memcpy(buf, s, p - s);
+ buf[p - s] = 0;
+ units n;
+ if (evaluate_expression(p + 1, &n))
+ set_number_reg(buf, n);
+ a_delete buf;
+ }
+}
+
+static void set_string(const char *name, const char *value)
+{
+ macro *m = new macro;
+ for (const char *p = value; *p; p++)
+ if (!illegal_input_char((unsigned char)*p))
+ m->append(*p);
+ request_dictionary.define(name, m);
+}
+
+
+static void do_string_assignment(const char *s)
+{
+ const char *p = strchr(s, '=');
+ if (!p) {
+ char buf[2];
+ buf[0] = s[0];
+ buf[1] = 0;
+ set_string(buf, s + 1);
+ }
+ else {
+ char *buf = new char[p - s + 1];
+ memcpy(buf, s, p - s);
+ buf[p - s] = 0;
+ set_string(buf, p + 1);
+ a_delete buf;
+ }
+}
+
+struct string_list {
+ const char *s;
+ string_list *next;
+ string_list(const char *ss) : s(ss), next(0) {}
+};
+
+static void add_string(const char *s, string_list **p)
+{
+ while (*p)
+ p = &((*p)->next);
+ *p = new string_list(s);
+}
+
+void usage(const char *prog)
+{
+ errprint(
+"usage: %1 -abivzCER -wname -Wname -dcstring -mname -nN -olist -rcN\n"
+" -Tname -Fdir -Mdir [ files ]\n",
+ prog);
+ exit(USAGE_EXIT_CODE);
+}
+
+int main(int argc, char **argv)
+{
+ program_name = argv[0];
+ static char stderr_buf[BUFSIZ];
+ setbuf(stderr, stderr_buf);
+ int c;
+ string_list *macros = 0;
+ string_list *register_assignments = 0;
+ string_list *string_assignments = 0;
+ int iflag = 0;
+ int tflag = 0;
+ int fflag = 0;
+ int nflag = 0;
+ int no_rc = 0; // don't process troffrc
+ int next_page_number;
+ opterr = 0;
+ hresolution = vresolution = 1;
+ while ((c = getopt(argc, argv, "abivw:W:zCEf:m:n:o:r:d:F:M:T:tqs:R"))
+ != EOF)
+ switch(c) {
+ case 'v':
+ {
+ extern const char *version_string;
+ fprintf(stderr, "GNU troff version %s\n", version_string);
+ fflush(stderr);
+ break;
+ }
+ case 'T':
+ device = optarg;
+ tflag = 1;
+ break;
+ case 'C':
+ compatible_flag = 1;
+ break;
+ case 'M':
+ macro_path.command_line_dir(optarg);
+ break;
+ case 'F':
+ font::command_line_font_dir(optarg);
+ break;
+ case 'm':
+ add_string(optarg, &macros);
+ break;
+ case 'E':
+ inhibit_errors = 1;
+ break;
+ case 'R':
+ no_rc = 1;
+ break;
+ case 'w':
+ enable_warning(optarg);
+ break;
+ case 'W':
+ disable_warning(optarg);
+ break;
+ case 'i':
+ iflag = 1;
+ break;
+ case 'b':
+ backtrace_flag = 1;
+ break;
+ case 'a':
+ ascii_output_flag = 1;
+ break;
+ case 'z':
+ suppress_output_flag = 1;
+ break;
+ case 'n':
+ if (sscanf(optarg, "%d", &next_page_number) == 1)
+ nflag++;
+ else
+ error("bad page number");
+ break;
+ case 'o':
+ parse_output_page_list(optarg);
+ break;
+ case 'd':
+ if (*optarg == '\0')
+ error("`-d' requires non-empty argument");
+ else
+ add_string(optarg, &string_assignments);
+ break;
+ case 'r':
+ if (*optarg == '\0')
+ error("`-r' requires non-empty argument");
+ else
+ add_string(optarg, &register_assignments);
+ break;
+ case 'f':
+ default_family = symbol(optarg);
+ fflag = 1;
+ break;
+ case 'q':
+ case 's':
+ case 't':
+ // silently ignore these
+ break;
+ case '?':
+ usage(argv[0]);
+ default:
+ assert(0);
+ }
+ set_string(".T", device);
+ init_charset_table();
+ if (!font::load_desc())
+ fatal("sorry, I can't continue");
+ units_per_inch = font::res;
+ hresolution = font::hor;
+ vresolution = font::vert;
+ sizescale = font::sizescale;
+ tcommand_flag = font::tcommand;
+ if (!fflag && font::family != 0 && *font::family != '\0')
+ default_family = symbol(font::family);
+ font_size::init_size_table(font::sizes);
+ int i;
+ int j = 1;
+ if (font::style_table) {
+ for (i = 0; font::style_table[i]; i++)
+ mount_style(j++, symbol(font::style_table[i]));
+ }
+ for (i = 0; font::font_name_table[i]; i++, j++)
+ // In the DESC file a font name of 0 (zero) means leave this
+ // position empty.
+ if (strcmp(font::font_name_table[i], "0") != 0)
+ mount_font(j, symbol(font::font_name_table[i]));
+ curdiv = topdiv = new top_level_diversion;
+ if (nflag)
+ topdiv->set_next_page_number(next_page_number);
+ init_input_requests();
+ init_env_requests();
+ init_div_requests();
+#ifdef COLUMN
+ init_column_requests();
+#endif /* COLUMN */
+ init_node_requests();
+ number_reg_dictionary.define(".T", new constant_reg(tflag ? "1" : "0"));
+ init_registers();
+ init_reg_requests();
+ init_hyphen_requests();
+ init_environments();
+ while (string_assignments) {
+ do_string_assignment(string_assignments->s);
+ string_list *tem = string_assignments;
+ string_assignments = string_assignments->next;
+ delete tem;
+ }
+ while (register_assignments) {
+ do_register_assignment(register_assignments->s);
+ string_list *tem = register_assignments;
+ register_assignments = register_assignments->next;
+ delete tem;
+ }
+ if (!no_rc)
+ process_startup_file();
+ while (macros) {
+ process_macro_file(macros->s);
+ string_list *tem = macros;
+ macros = macros->next;
+ delete tem;
+ }
+ for (i = optind; i < argc; i++)
+ process_input_file(argv[i]);
+ if (optind >= argc || iflag)
+ process_input_file("-");
+ exit_troff();
+ return 0; // not reached
+}
+
+void warn_request()
+{
+ int n;
+ if (has_arg() && get_integer(&n)) {
+ if (n & ~WARN_TOTAL) {
+ warning(WARN_RANGE, "warning mask must be between 0 and %1", WARN_TOTAL);
+ n &= WARN_TOTAL;
+ }
+ warning_mask = n;
+ }
+ else
+ warning_mask = WARN_TOTAL;
+ skip_line();
+}
+
+static void init_registers()
+{
+#ifdef LONG_FOR_TIME_T
+ long
+#else /* not LONG_FOR_TIME_T */
+ time_t
+#endif /* not LONG_FOR_TIME_T */
+ t = time(0);
+ // Use struct here to work around misfeature in old versions of g++.
+ struct tm *tt = localtime(&t);
+ set_number_reg("dw", int(tt->tm_wday + 1));
+ set_number_reg("dy", int(tt->tm_mday));
+ set_number_reg("mo", int(tt->tm_mon + 1));
+ set_number_reg("yr", int(tt->tm_year));
+ set_number_reg("$$", getpid());
+ number_reg_dictionary.define(".A",
+ new constant_reg(ascii_output_flag
+ ? "1"
+ : "0"));
+}
+
+void init_input_requests()
+{
+ init_request("ds", define_string);
+ init_request("as", append_string);
+ init_request("de", define_macro);
+ init_request("am", append_macro);
+ init_request("ig", ignore);
+ init_request("rm", remove_macro);
+ init_request("rn", rename_macro);
+ init_request("if", if_request);
+ init_request("ie", if_else_request);
+ init_request("el", else_request);
+ init_request("so", source);
+ init_request("nx", next_file);
+ init_request("pm", print_macros);
+ init_request("eo", escape_off);
+ init_request("ec", set_escape_char);
+ init_request("pc", set_page_character);
+ init_request("tm", terminal);
+ init_request("ex", exit_request);
+ init_request("em", end_macro);
+ init_request("tr", translate);
+ init_request("trnt", translate_no_transparent);
+ init_request("ab", abort_request);
+ init_request("pi", pipe_output);
+ init_request("cf", copy_file);
+ init_request("sy", system_request);
+ init_request("lf", line_file);
+ init_request("cflags", char_flags);
+ init_request("shift", shift);
+ init_request("rd", read_request);
+ init_request("cp", compatible);
+ init_request("char", define_character);
+ init_request("rchar", remove_character);
+ init_request("hcode", hyphenation_code);
+ init_request("while", while_request);
+ init_request("break", while_break_request);
+ init_request("continue", while_continue_request);
+ init_request("als", alias_macro);
+ init_request("backtrace", backtrace_request);
+ init_request("chop", chop_macro);
+ init_request("asciify", asciify_macro);
+ init_request("warn", warn_request);
+ init_request("open", open_request);
+ init_request("opena", opena_request);
+ init_request("close", close_request);
+ init_request("write", write_request);
+ init_request("trf", transparent_file);
+#ifdef WIDOW_CONTROL
+ init_request("fpl", flush_pending_lines);
+#endif /* WIDOW_CONTROL */
+ init_request("nroff", nroff_request);
+ init_request("troff", troff_request);
+#ifdef COLUMN
+ init_request("vj", vjustify);
+#endif /* COLUMN */
+ init_request("mso", macro_source);
+ init_request("do", do_request);
+#ifndef POPEN_MISSING
+ init_request("pso", pipe_source);
+#endif /* not POPEN_MISSING */
+ number_reg_dictionary.define("systat", new variable_reg(&system_status));
+ number_reg_dictionary.define("slimit",
+ new variable_reg(&input_stack::limit));
+ number_reg_dictionary.define(".$", new nargs_reg);
+ number_reg_dictionary.define(".c", new lineno_reg);
+ number_reg_dictionary.define("c.", new writable_lineno_reg);
+ number_reg_dictionary.define(".F", new filename_reg);
+ number_reg_dictionary.define(".C", new constant_int_reg(&compatible_flag));
+ number_reg_dictionary.define(".H", new constant_int_reg(&hresolution));
+ number_reg_dictionary.define(".V", new constant_int_reg(&vresolution));
+ number_reg_dictionary.define(".R", new constant_reg("10000"));
+ extern const char *major_version;
+ number_reg_dictionary.define(".x", new constant_reg(major_version));
+ extern const char *minor_version;
+ number_reg_dictionary.define(".y", new constant_reg(minor_version));
+ number_reg_dictionary.define(".g", new constant_reg("1"));
+ number_reg_dictionary.define(".warn", new constant_int_reg(&warning_mask));
+}
+
+object_dictionary request_dictionary(501);
+
+void init_request(const char *s, REQUEST_FUNCP f)
+{
+ request_dictionary.define(s, new request(f));
+}
+
+static request_or_macro *lookup_request(symbol nm)
+{
+ assert(!nm.is_null());
+ request_or_macro *p = (request_or_macro *)request_dictionary.lookup(nm);
+ if (p == 0) {
+ warning(WARN_MAC, "`%1' not defined", nm.contents());
+ p = new macro;
+ request_dictionary.define(nm, p);
+ }
+ return p;
+}
+
+
+node *charinfo_to_node_list(charinfo *ci, const environment *envp)
+{
+ // Don't interpret character definitions in compatible mode.
+ int old_compatible_flag = compatible_flag;
+ compatible_flag = 0;
+ int old_escape_char = escape_char;
+ escape_char = '\\';
+ macro *mac = ci->set_macro(0);
+ assert(mac != 0);
+ environment *oldenv = curenv;
+ environment env(envp);
+ curenv = &env;
+ curenv->set_composite();
+ token old_tok = tok;
+ input_stack::add_boundary();
+ string_iterator *si = new string_iterator(*mac, "composite character", ci->nm);
+ input_stack::push(si);
+ // we don't use process_input_stack, because we don't want to recognise
+ // requests
+ for (;;) {
+ tok.next();
+ if (tok.eof())
+ break;
+ if (tok.newline()) {
+ error("composite character mustn't contain newline");
+ while (!tok.eof())
+ tok.next();
+ break;
+ }
+ else
+ tok.process();
+ }
+ node *n = curenv->extract_output_line();
+ input_stack::remove_boundary();
+ ci->set_macro(mac);
+ tok = old_tok;
+ curenv = oldenv;
+ compatible_flag = old_compatible_flag;
+ escape_char = old_escape_char;
+ return n;
+}
+
+static node *read_draw_node()
+{
+ token start;
+ start.next();
+ if (!start.delimiter(1)){
+ do {
+ tok.next();
+ } while (tok != start && !tok.newline() && !tok.eof());
+ }
+ else {
+ tok.next();
+ if (tok == start)
+ error("missing argument");
+ else {
+ unsigned char type = tok.ch();
+ tok.next();
+ int maxpoints = 10;
+ hvpair *point = new hvpair[maxpoints];
+ int npoints = 0;
+ int no_last_v = 0;
+ int err = 0;
+ int i;
+ for (i = 0; tok != start; i++) {
+ if (i == maxpoints) {
+ hvpair *oldpoint = point;
+ point = new hvpair[maxpoints*2];
+ for (int j = 0; j < maxpoints; j++)
+ point[j] = oldpoint[j];
+ maxpoints *= 2;
+ a_delete oldpoint;
+ }
+ if (!get_hunits(&point[i].h, 'm')) {
+ err = 1;
+ break;
+ }
+ ++npoints;
+ tok.skip();
+ point[i].v = V0;
+ if (tok == start) {
+ no_last_v = 1;
+ break;
+ }
+ if (!get_vunits(&point[i].v, 'v')) {
+ err = 1;
+ break;
+ }
+ tok.skip();
+ }
+ while (tok != start && !tok.newline() && !tok.eof())
+ tok.next();
+ if (!err) {
+ switch (type) {
+ case 'l':
+ if (npoints != 1 || no_last_v) {
+ error("two arguments needed for line");
+ npoints = 1;
+ }
+ break;
+ case 'c':
+ if (npoints != 1 || !no_last_v) {
+ error("one argument needed for circle");
+ npoints = 1;
+ point[0].v = V0;
+ }
+ break;
+ case 'e':
+ if (npoints != 1 || no_last_v) {
+ error("two arguments needed for ellipse");
+ npoints = 1;
+ }
+ break;
+ case 'a':
+ if (npoints != 2 || no_last_v) {
+ error("four arguments needed for arc");
+ npoints = 2;
+ }
+ break;
+ case '~':
+ if (no_last_v)
+ error("even number of arguments needed for spline");
+ break;
+ default:
+ // silently pass it through
+ break;
+ }
+ draw_node *dn = new draw_node(type, point, npoints,
+ curenv->get_font_size());
+ a_delete point;
+ return dn;
+ }
+ else {
+ a_delete point;
+ }
+ }
+ }
+ return 0;
+}
+
+static struct {
+ const char *name;
+ int mask;
+} warning_table[] = {
+ { "char", WARN_CHAR },
+ { "range", WARN_RANGE },
+ { "break", WARN_BREAK },
+ { "delim", WARN_DELIM },
+ { "el", WARN_EL },
+ { "scale", WARN_SCALE },
+ { "number", WARN_NUMBER },
+ { "syntax", WARN_SYNTAX },
+ { "tab", WARN_TAB },
+ { "right-brace", WARN_RIGHT_BRACE },
+ { "missing", WARN_MISSING },
+ { "input", WARN_INPUT },
+ { "escape", WARN_ESCAPE },
+ { "space", WARN_SPACE },
+ { "font", WARN_FONT },
+ { "di", WARN_DI },
+ { "mac", WARN_MAC },
+ { "reg", WARN_REG },
+ { "ig", WARN_IG },
+ { "all", WARN_TOTAL & ~(WARN_DI | WARN_MAC | WARN_REG) },
+ { "w", WARN_TOTAL },
+ { "default", DEFAULT_WARNING_MASK },
+};
+
+static int lookup_warning(const char *name)
+{
+ for (int i = 0;
+ i < sizeof(warning_table)/sizeof(warning_table[0]);
+ i++)
+ if (strcmp(name, warning_table[i].name) == 0)
+ return warning_table[i].mask;
+ return 0;
+}
+
+static void enable_warning(const char *name)
+{
+ int mask = lookup_warning(name);
+ if (mask)
+ warning_mask |= mask;
+ else
+ error("unknown warning `%1'", name);
+}
+
+static void disable_warning(const char *name)
+{
+ int mask = lookup_warning(name);
+ if (mask)
+ warning_mask &= ~mask;
+ else
+ error("unknown warning `%1'", name);
+}
+
+static void copy_mode_error(const char *format,
+ const errarg &arg1,
+ const errarg &arg2,
+ const errarg &arg3)
+{
+ if (ignoring) {
+ static const char prefix[] = "(in ignored input) ";
+ char *s = new char[sizeof(prefix) + strlen(format)];
+ strcpy(s, prefix);
+ strcat(s, format);
+ warning(WARN_IG, s, arg1, arg2, arg3);
+ a_delete s;
+ }
+ else
+ error(format, arg1, arg2, arg3);
+}
+
+enum error_type { WARNING, ERROR, FATAL };
+
+static void do_error(error_type type,
+ const char *format,
+ const errarg &arg1,
+ const errarg &arg2,
+ const errarg &arg3)
+{
+ const char *filename;
+ int lineno;
+ if (inhibit_errors && type < FATAL)
+ return;
+ if (backtrace_flag)
+ input_stack::backtrace();
+ if (!get_file_line(&filename, &lineno))
+ filename = 0;
+ if (filename)
+ errprint("%1:%2: ", filename, lineno);
+ else if (program_name)
+ fprintf(stderr, "%s: ", program_name);
+ switch (type) {
+ case FATAL:
+ fputs("fatal error: ", stderr);
+ break;
+ case ERROR:
+ break;
+ case WARNING:
+ fputs("warning: ", stderr);
+ break;
+ }
+ errprint(format, arg1, arg2, arg3);
+ fputc('\n', stderr);
+ fflush(stderr);
+ if (type == FATAL)
+ cleanup_and_exit(1);
+}
+
+int warning(warning_type t,
+ const char *format,
+ const errarg &arg1,
+ const errarg &arg2,
+ const errarg &arg3)
+{
+ if ((t & warning_mask) != 0) {
+ do_error(WARNING, format, arg1, arg2, arg3);
+ return 1;
+ }
+ else
+ return 0;
+}
+
+void error(const char *format,
+ const errarg &arg1,
+ const errarg &arg2,
+ const errarg &arg3)
+{
+ do_error(ERROR, format, arg1, arg2, arg3);
+}
+
+void fatal(const char *format,
+ const errarg &arg1,
+ const errarg &arg2,
+ const errarg &arg3)
+{
+ do_error(FATAL, format, arg1, arg2, arg3);
+}
+
+void fatal_with_file_and_line(const char *filename, int lineno,
+ const char *format,
+ const errarg &arg1,
+ const errarg &arg2,
+ const errarg &arg3)
+{
+ fprintf(stderr, "%s:%d: fatal error: ", filename, lineno);
+ errprint(format, arg1, arg2, arg3);
+ fputc('\n', stderr);
+ fflush(stderr);
+ cleanup_and_exit(1);
+}
+
+void error_with_file_and_line(const char *filename, int lineno,
+ const char *format,
+ const errarg &arg1,
+ const errarg &arg2,
+ const errarg &arg3)
+{
+ fprintf(stderr, "%s:%d: error: ", filename, lineno);
+ errprint(format, arg1, arg2, arg3);
+ fputc('\n', stderr);
+ fflush(stderr);
+}
+
+dictionary charinfo_dictionary(501);
+
+charinfo *get_charinfo(symbol nm)
+{
+ void *p = charinfo_dictionary.lookup(nm);
+ if (p != 0)
+ return (charinfo *)p;
+ charinfo *cp = new charinfo(nm);
+ (void)charinfo_dictionary.lookup(nm, cp);
+ return cp;
+}
+
+int charinfo::next_index = 0;
+
+charinfo::charinfo(symbol s)
+: nm(s), hyphenation_code(0), translation(0), flags(0), ascii_code(0),
+ special_translation(TRANSLATE_NONE), mac(0), not_found(0),
+ transparent_translate(1)
+{
+ index = next_index++;
+}
+
+void charinfo::set_hyphenation_code(unsigned char c)
+{
+ hyphenation_code = c;
+}
+
+void charinfo::set_translation(charinfo *ci, int tt)
+{
+ translation = ci;
+ special_translation = TRANSLATE_NONE;
+ transparent_translate = tt;
+}
+
+void charinfo::set_special_translation(int c, int tt)
+{
+ special_translation = c;
+ translation = 0;
+ transparent_translate = tt;
+}
+
+void charinfo::set_ascii_code(unsigned char c)
+{
+ ascii_code = c;
+}
+
+macro *charinfo::set_macro(macro *m)
+{
+ macro *tem = mac;
+ mac = m;
+ return tem;
+}
+
+void charinfo::set_number(int n)
+{
+ number = n;
+ flags |= NUMBERED;
+}
+
+int charinfo::get_number()
+{
+ assert(flags & NUMBERED);
+ return number;
+}
+
+symbol UNNAMED_SYMBOL("---");
+
+// For numbered characters not between 0 and 255, we make a symbol out
+// of the number and store them in this dictionary.
+
+dictionary numbered_charinfo_dictionary(11);
+
+charinfo *get_charinfo_by_number(int n)
+{
+ static charinfo *number_table[256];
+
+ if (n >= 0 && n < 256) {
+ charinfo *ci = number_table[n];
+ if (!ci) {
+ ci = new charinfo(UNNAMED_SYMBOL);
+ ci->set_number(n);
+ number_table[n] = ci;
+ }
+ return ci;
+ }
+ else {
+ symbol ns(itoa(n));
+ charinfo *ci = (charinfo *)numbered_charinfo_dictionary.lookup(ns);
+ if (!ci) {
+ ci = new charinfo(UNNAMED_SYMBOL);
+ ci->set_number(n);
+ numbered_charinfo_dictionary.lookup(ns, ci);
+ }
+ return ci;
+ }
+}
+
+int font::name_to_index(const char *nm)
+{
+ charinfo *ci;
+ if (nm[1] == 0)
+ ci = charset_table[nm[0] & 0xff];
+ else if (nm[0] == '\\' && nm[2] == 0)
+ ci = get_charinfo(symbol(nm + 1));
+ else
+ ci = get_charinfo(symbol(nm));
+ if (ci == 0)
+ return -1;
+ else
+ return ci->get_index();
+}
+
+int font::number_to_index(int n)
+{
+ return get_charinfo_by_number(n)->get_index();
+}
diff --git a/gnu/usr.bin/groff/troff/node.cc b/gnu/usr.bin/groff/troff/node.cc
new file mode 100644
index 0000000..6fad470
--- /dev/null
+++ b/gnu/usr.bin/groff/troff/node.cc
@@ -0,0 +1,4851 @@
+// -*- C++ -*-
+/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
+ Written by James Clark (jjc@jclark.com)
+
+This file is part of groff.
+
+groff is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
+
+groff is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License along
+with groff; see the file COPYING. If not, write to the Free Software
+Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "troff.h"
+#include "symbol.h"
+#include "dictionary.h"
+#include "hvunits.h"
+#include "env.h"
+#include "request.h"
+#include "node.h"
+#include "token.h"
+#include "charinfo.h"
+#include "font.h"
+#include "reg.h"
+
+#define STORE_WIDTH 1
+
+symbol HYPHEN_SYMBOL("hy");
+
+// Character used when a hyphen is inserted at a line break.
+static charinfo *soft_hyphen_char;
+
+enum constant_space_type {
+ CONSTANT_SPACE_NONE,
+ CONSTANT_SPACE_RELATIVE,
+ CONSTANT_SPACE_ABSOLUTE
+ };
+
+struct special_font_list {
+ int n;
+ special_font_list *next;
+};
+
+special_font_list *global_special_fonts;
+static int global_ligature_mode = 1;
+static int global_kern_mode = 1;
+
+class track_kerning_function {
+ int non_zero;
+ units min_size;
+ hunits min_amount;
+ units max_size;
+ hunits max_amount;
+public:
+ track_kerning_function();
+ track_kerning_function(units, hunits, units, hunits);
+ int operator==(const track_kerning_function &);
+ int operator!=(const track_kerning_function &);
+ hunits compute(int point_size);
+};
+
+// embolden fontno when this is the current font
+
+struct conditional_bold {
+ conditional_bold *next;
+ int fontno;
+ hunits offset;
+ conditional_bold(int, hunits, conditional_bold * = 0);
+};
+
+struct tfont;
+
+class font_info {
+ tfont *last_tfont;
+ int number;
+ font_size last_size;
+ int last_height;
+ int last_slant;
+ symbol internal_name;
+ symbol external_name;
+ font *fm;
+ char is_bold;
+ hunits bold_offset;
+ track_kerning_function track_kern;
+ constant_space_type is_constant_spaced;
+ units constant_space;
+ int last_ligature_mode;
+ int last_kern_mode;
+ conditional_bold *cond_bold_list;
+ void flush();
+public:
+ special_font_list *sf;
+
+ font_info(symbol nm, int n, symbol enm, font *f);
+ int contains(charinfo *);
+ void set_bold(hunits);
+ void unbold();
+ void set_conditional_bold(int, hunits);
+ void conditional_unbold(int);
+ void set_track_kern(track_kerning_function &);
+ void set_constant_space(constant_space_type, units = 0);
+ int is_named(symbol);
+ symbol get_name();
+ tfont *get_tfont(font_size, int, int, int);
+ hunits get_space_width(font_size, int);
+ hunits get_narrow_space_width(font_size);
+ hunits get_half_narrow_space_width(font_size);
+ int get_bold(hunits *);
+ int is_special();
+ int is_style();
+};
+
+class tfont_spec {
+protected:
+ symbol name;
+ int input_position;
+ font *fm;
+ font_size size;
+ char is_bold;
+ char is_constant_spaced;
+ int ligature_mode;
+ int kern_mode;
+ hunits bold_offset;
+ hunits track_kern; // add this to the width
+ hunits constant_space_width;
+ int height;
+ int slant;
+public:
+ tfont_spec(symbol nm, int pos, font *, font_size, int, int);
+ tfont_spec(const tfont_spec &spec) { *this = spec; }
+ tfont_spec plain();
+ int operator==(const tfont_spec &);
+ friend tfont *font_info::get_tfont(font_size fs, int, int, int);
+};
+
+class tfont : public tfont_spec {
+ static tfont *tfont_list;
+ tfont *next;
+ tfont *plain_version;
+public:
+ tfont(tfont_spec &);
+ int contains(charinfo *);
+ hunits get_width(charinfo *c);
+ int get_bold(hunits *);
+ int get_constant_space(hunits *);
+ hunits get_track_kern();
+ tfont *get_plain();
+ font_size get_size();
+ symbol get_name();
+ charinfo *get_lig(charinfo *c1, charinfo *c2);
+ int get_kern(charinfo *c1, charinfo *c2, hunits *res);
+ int get_input_position();
+ int get_character_type(charinfo *);
+ int get_height();
+ int get_slant();
+ vunits get_char_height(charinfo *);
+ vunits get_char_depth(charinfo *);
+ hunits get_char_skew(charinfo *);
+ hunits get_italic_correction(charinfo *);
+ hunits get_left_italic_correction(charinfo *);
+ hunits get_subscript_correction(charinfo *);
+ friend tfont *make_tfont(tfont_spec &);
+};
+
+inline int env_definite_font(environment *env)
+{
+ return env->get_family()->make_definite(env->get_font());
+}
+
+/* font_info functions */
+
+static font_info **font_table = 0;
+static int font_table_size = 0;
+
+font_info::font_info(symbol nm, int n, symbol enm, font *f)
+: internal_name(nm), external_name(enm), fm(f), number(n),
+ is_constant_spaced(CONSTANT_SPACE_NONE),
+ sf(0), is_bold(0), cond_bold_list(0),
+ last_ligature_mode(1), last_kern_mode(1),
+ last_tfont(0), last_size(0)
+{
+}
+
+inline int font_info::contains(charinfo *ci)
+{
+ return fm != 0 && fm->contains(ci->get_index());
+}
+
+inline int font_info::is_special()
+{
+ return fm != 0 && fm->is_special();
+}
+
+inline int font_info::is_style()
+{
+ return fm == 0;
+}
+
+// this is the current_font, fontno is where we found the character,
+// presumably a special font
+
+tfont *font_info::get_tfont(font_size fs, int height, int slant, int fontno)
+{
+ if (last_tfont == 0 || fs != last_size
+ || height != last_height || slant != last_slant
+ || global_ligature_mode != last_ligature_mode
+ || global_kern_mode != last_kern_mode
+ || fontno != number) {
+ font_info *f = font_table[fontno];
+ tfont_spec spec(f->external_name, f->number, f->fm, fs, height, slant);
+ for (conditional_bold *p = cond_bold_list; p; p = p->next)
+ if (p->fontno == fontno) {
+ spec.is_bold = 1;
+ spec.bold_offset = p->offset;
+ break;
+ }
+ if (!spec.is_bold && is_bold) {
+ spec.is_bold = 1;
+ spec.bold_offset = bold_offset;
+ }
+ spec.track_kern = track_kern.compute(fs.to_scaled_points());
+ spec.ligature_mode = global_ligature_mode;
+ spec.kern_mode = global_kern_mode;
+ switch (is_constant_spaced) {
+ case CONSTANT_SPACE_NONE:
+ break;
+ case CONSTANT_SPACE_ABSOLUTE:
+ spec.is_constant_spaced = 1;
+ spec.constant_space_width = constant_space;
+ break;
+ case CONSTANT_SPACE_RELATIVE:
+ spec.is_constant_spaced = 1;
+ spec.constant_space_width
+ = scale(constant_space*fs.to_scaled_points(),
+ units_per_inch,
+ 36*72*sizescale);
+ break;
+ default:
+ assert(0);
+ }
+ if (fontno != number)
+ return make_tfont(spec);
+ last_tfont = make_tfont(spec);
+ last_size = fs;
+ last_height = height;
+ last_slant = slant;
+ last_ligature_mode = global_ligature_mode;
+ last_kern_mode = global_kern_mode;
+ }
+ return last_tfont;
+}
+
+int font_info::get_bold(hunits *res)
+{
+ if (is_bold) {
+ *res = bold_offset;
+ return 1;
+ }
+ else
+ return 0;
+}
+
+void font_info::unbold()
+{
+ if (is_bold) {
+ is_bold = 0;
+ flush();
+ }
+}
+
+void font_info::set_bold(hunits offset)
+{
+ if (!is_bold || offset != bold_offset) {
+ is_bold = 1;
+ bold_offset = offset;
+ flush();
+ }
+}
+
+void font_info::set_conditional_bold(int fontno, hunits offset)
+{
+ for (conditional_bold *p = cond_bold_list; p; p = p->next)
+ if (p->fontno == fontno) {
+ if (offset != p->offset) {
+ p->offset = offset;
+ flush();
+ }
+ return;
+ }
+ cond_bold_list = new conditional_bold(fontno, offset, cond_bold_list);
+}
+
+conditional_bold::conditional_bold(int f, hunits h, conditional_bold *x)
+ : fontno(f), offset(h), next(x)
+{
+}
+
+void font_info::conditional_unbold(int fontno)
+{
+ for (conditional_bold **p = &cond_bold_list; *p; p = &(*p)->next)
+ if ((*p)->fontno == fontno) {
+ conditional_bold *tem = *p;
+ *p = (*p)->next;
+ delete tem;
+ flush();
+ return;
+ }
+}
+
+void font_info::set_constant_space(constant_space_type type, units x)
+{
+ if (type != is_constant_spaced
+ || (type != CONSTANT_SPACE_NONE && x != constant_space)) {
+ flush();
+ is_constant_spaced = type;
+ constant_space = x;
+ }
+}
+
+void font_info::set_track_kern(track_kerning_function &tk)
+{
+ if (track_kern != tk) {
+ track_kern = tk;
+ flush();
+ }
+}
+
+void font_info::flush()
+{
+ last_tfont = 0;
+}
+
+int font_info::is_named(symbol s)
+{
+ return internal_name == s;
+}
+
+symbol font_info::get_name()
+{
+ return internal_name;
+}
+
+hunits font_info::get_space_width(font_size fs, int space_size)
+{
+ if (is_constant_spaced == CONSTANT_SPACE_NONE)
+ return scale(hunits(fm->get_space_width(fs.to_scaled_points())),
+ space_size, 12);
+ else if (is_constant_spaced == CONSTANT_SPACE_ABSOLUTE)
+ return constant_space;
+ else
+ return scale(constant_space*fs.to_scaled_points(),
+ units_per_inch, 36*72*sizescale);
+}
+
+hunits font_info::get_narrow_space_width(font_size fs)
+{
+ charinfo *ci = get_charinfo(symbol("|"));
+ if (fm->contains(ci->get_index()))
+ return hunits(fm->get_width(ci->get_index(), fs.to_scaled_points()));
+ else
+ return hunits(fs.to_units()/6);
+}
+
+hunits font_info::get_half_narrow_space_width(font_size fs)
+{
+ charinfo *ci = get_charinfo(symbol("^"));
+ if (fm->contains(ci->get_index()))
+ return hunits(fm->get_width(ci->get_index(), fs.to_scaled_points()));
+ else
+ return hunits(fs.to_units()/12);
+}
+
+/* tfont */
+
+tfont_spec::tfont_spec(symbol nm, int n, font *f,
+ font_size s, int h, int sl)
+ : name(nm), input_position(n), fm(f), size(s),
+ is_bold(0), is_constant_spaced(0), ligature_mode(1), kern_mode(1),
+ height(h), slant(sl)
+{
+ if (height == size.to_scaled_points())
+ height = 0;
+}
+
+int tfont_spec::operator==(const tfont_spec &spec)
+{
+ if (fm == spec.fm
+ && size == spec.size
+ && input_position == spec.input_position
+ && name == spec.name
+ && height == spec.height
+ && slant == spec.slant
+ && (is_bold
+ ? (spec.is_bold && bold_offset == spec.bold_offset)
+ : !spec.is_bold)
+ && track_kern == spec.track_kern
+ && (is_constant_spaced
+ ? (spec.is_constant_spaced
+ && constant_space_width == spec.constant_space_width)
+ : !spec.is_constant_spaced)
+ && ligature_mode == spec.ligature_mode
+ && kern_mode == spec.kern_mode)
+ return 1;
+ else
+ return 0;
+}
+
+tfont_spec tfont_spec::plain()
+{
+ return tfont_spec(name, input_position, fm, size, height, slant);
+}
+
+hunits tfont::get_width(charinfo *c)
+{
+ if (is_constant_spaced)
+ return constant_space_width;
+ else if (is_bold)
+ return (hunits(fm->get_width(c->get_index(), size.to_scaled_points()))
+ + track_kern + bold_offset);
+ else
+ return (hunits(fm->get_width(c->get_index(), size.to_scaled_points())) + track_kern);
+}
+
+vunits tfont::get_char_height(charinfo *c)
+{
+ vunits v = fm->get_height(c->get_index(), size.to_scaled_points());
+ if (height != 0 && height != size.to_scaled_points())
+ return scale(v, height, size.to_scaled_points());
+ else
+ return v;
+}
+
+vunits tfont::get_char_depth(charinfo *c)
+{
+ vunits v = fm->get_depth(c->get_index(), size.to_scaled_points());
+ if (height != 0 && height != size.to_scaled_points())
+ return scale(v, height, size.to_scaled_points());
+ else
+ return v;
+}
+
+hunits tfont::get_char_skew(charinfo *c)
+{
+ return hunits(fm->get_skew(c->get_index(), size.to_scaled_points(), slant));
+}
+
+hunits tfont::get_italic_correction(charinfo *c)
+{
+ return hunits(fm->get_italic_correction(c->get_index(), size.to_scaled_points()));
+}
+
+hunits tfont::get_left_italic_correction(charinfo *c)
+{
+ return hunits(fm->get_left_italic_correction(c->get_index(),
+ size.to_scaled_points()));
+}
+
+hunits tfont::get_subscript_correction(charinfo *c)
+{
+ return hunits(fm->get_subscript_correction(c->get_index(),
+ size.to_scaled_points()));
+}
+
+inline int tfont::get_input_position()
+{
+ return input_position;
+}
+
+inline int tfont::contains(charinfo *ci)
+{
+ return fm->contains(ci->get_index());
+}
+
+inline int tfont::get_character_type(charinfo *ci)
+{
+ return fm->get_character_type(ci->get_index());
+}
+
+inline int tfont::get_bold(hunits *res)
+{
+ if (is_bold) {
+ *res = bold_offset;
+ return 1;
+ }
+ else
+ return 0;
+}
+
+inline int tfont::get_constant_space(hunits *res)
+{
+ if (is_constant_spaced) {
+ *res = constant_space_width;
+ return 1;
+ }
+ else
+ return 0;
+}
+
+inline hunits tfont::get_track_kern()
+{
+ return track_kern;
+}
+
+inline tfont *tfont::get_plain()
+{
+ return plain_version;
+}
+
+inline font_size tfont::get_size()
+{
+ return size;
+}
+
+inline symbol tfont::get_name()
+{
+ return name;
+}
+
+inline int tfont::get_height()
+{
+ return height;
+}
+
+inline int tfont::get_slant()
+{
+ return slant;
+}
+
+symbol SYMBOL_ff("ff");
+symbol SYMBOL_fi("fi");
+symbol SYMBOL_fl("fl");
+symbol SYMBOL_Fi("Fi");
+symbol SYMBOL_Fl("Fl");
+
+charinfo *tfont::get_lig(charinfo *c1, charinfo *c2)
+{
+ if (ligature_mode == 0)
+ return 0;
+ charinfo *ci = 0;
+ if (c1->get_ascii_code() == 'f') {
+ switch (c2->get_ascii_code()) {
+ case 'f':
+ if (fm->has_ligature(font::LIG_ff))
+ ci = get_charinfo(SYMBOL_ff);
+ break;
+ case 'i':
+ if (fm->has_ligature(font::LIG_fi))
+ ci = get_charinfo(SYMBOL_fi);
+ break;
+ case 'l':
+ if (fm->has_ligature(font::LIG_fl))
+ ci = get_charinfo(SYMBOL_fl);
+ break;
+ }
+ }
+ else if (ligature_mode != 2 && c1->nm == SYMBOL_ff) {
+ switch (c2->get_ascii_code()) {
+ case 'i':
+ if (fm->has_ligature(font::LIG_ffi))
+ ci = get_charinfo(SYMBOL_Fi);
+ break;
+ case 'l':
+ if (fm->has_ligature(font::LIG_ffl))
+ ci = get_charinfo(SYMBOL_Fl);
+ break;
+ }
+ }
+ if (ci != 0 && fm->contains(ci->get_index()))
+ return ci;
+ return 0;
+}
+
+inline int tfont::get_kern(charinfo *c1, charinfo *c2, hunits *res)
+{
+ if (kern_mode == 0)
+ return 0;
+ else {
+ int n = fm->get_kern(c1->get_index(),
+ c2->get_index(),
+ size.to_scaled_points());
+ if (n) {
+ *res = hunits(n);
+ return 1;
+ }
+ else
+ return 0;
+ }
+}
+
+tfont *make_tfont(tfont_spec &spec)
+{
+ for (tfont *p = tfont::tfont_list; p; p = p->next)
+ if (*p == spec)
+ return p;
+ return new tfont(spec);
+}
+
+tfont *tfont::tfont_list = 0;
+
+tfont::tfont(tfont_spec &spec) : tfont_spec(spec)
+{
+ next = tfont_list;
+ tfont_list = this;
+ tfont_spec plain_spec = plain();
+ for (tfont *p = tfont_list; p; p = p->next)
+ if (*p == plain_spec) {
+ plain_version = p;
+ break;
+ }
+ if (!p)
+ plain_version = new tfont(plain_spec);
+}
+
+/* output_file */
+
+class real_output_file : public output_file {
+#ifndef POPEN_MISSING
+ int piped;
+#endif
+ int printing;
+ virtual void really_transparent_char(unsigned char) = 0;
+ virtual void really_print_line(hunits x, vunits y, node *n,
+ vunits before, vunits after) = 0;
+ virtual void really_begin_page(int pageno, vunits page_length) = 0;
+ virtual void really_copy_file(hunits x, vunits y, const char *filename);
+protected:
+ FILE *fp;
+public:
+ real_output_file();
+ ~real_output_file();
+ void flush();
+ void transparent_char(unsigned char);
+ void print_line(hunits x, vunits y, node *n, vunits before, vunits after);
+ void begin_page(int pageno, vunits page_length);
+ int is_printing();
+ void copy_file(hunits x, vunits y, const char *filename);
+};
+
+class suppress_output_file : public real_output_file {
+public:
+ suppress_output_file();
+ void really_transparent_char(unsigned char);
+ void really_print_line(hunits x, vunits y, node *n, vunits, vunits);
+ void really_begin_page(int pageno, vunits page_length);
+};
+
+class ascii_output_file : public real_output_file {
+public:
+ ascii_output_file();
+ void really_transparent_char(unsigned char);
+ void really_print_line(hunits x, vunits y, node *n, vunits, vunits);
+ void really_begin_page(int pageno, vunits page_length);
+ void outc(unsigned char c);
+ void outs(const char *s);
+};
+
+void ascii_output_file::outc(unsigned char c)
+{
+ fputc(c, fp);
+}
+
+void ascii_output_file::outs(const char *s)
+{
+ fputc('<', fp);
+ if (s)
+ fputs(s, fp);
+ fputc('>', fp);
+}
+
+struct hvpair;
+
+class troff_output_file : public real_output_file {
+ units hpos;
+ units vpos;
+ units output_vpos;
+ units output_hpos;
+ int force_motion;
+ int current_size;
+ int current_slant;
+ int current_height;
+ tfont *current_tfont;
+ int current_font_number;
+ symbol *font_position;
+ int nfont_positions;
+ enum { TBUF_SIZE = 256 };
+ char tbuf[TBUF_SIZE];
+ int tbuf_len;
+ int tbuf_kern;
+ int begun_page;
+ void do_motion();
+ void put(char c);
+ void put(unsigned char c);
+ void put(int i);
+ void put(const char *s);
+ void set_font(tfont *tf);
+ void flush_tbuf();
+public:
+ troff_output_file();
+ ~troff_output_file();
+ void trailer(vunits page_length);
+ void put_char(charinfo *ci, tfont *tf);
+ void put_char_width(charinfo *ci, tfont *tf, hunits w, hunits k);
+ void right(hunits);
+ void down(vunits);
+ void moveto(hunits, vunits);
+ void start_special();
+ void special_char(unsigned char c);
+ void end_special();
+ void word_marker();
+ void really_transparent_char(unsigned char c);
+ void really_print_line(hunits x, vunits y, node *n, vunits before, vunits after);
+ void really_begin_page(int pageno, vunits page_length);
+ void really_copy_file(hunits x, vunits y, const char *filename);
+ void draw(char, hvpair *, int, font_size);
+ int get_hpos() { return hpos; }
+ int get_vpos() { return vpos; }
+};
+
+static void put_string(const char *s, FILE *fp)
+{
+ for (; *s != '\0'; ++s)
+ putc(*s, fp);
+}
+
+inline void troff_output_file::put(char c)
+{
+ putc(c, fp);
+}
+
+inline void troff_output_file::put(unsigned char c)
+{
+ putc(c, fp);
+}
+
+inline void troff_output_file::put(const char *s)
+{
+ put_string(s, fp);
+}
+
+inline void troff_output_file::put(int i)
+{
+ put_string(itoa(i), fp);
+}
+
+void troff_output_file::start_special()
+{
+ flush_tbuf();
+ do_motion();
+ put("x X ");
+}
+
+void troff_output_file::special_char(unsigned char c)
+{
+ put(c);
+ if (c == '\n')
+ put('+');
+}
+
+void troff_output_file::end_special()
+{
+ put('\n');
+}
+
+inline void troff_output_file::moveto(hunits h, vunits v)
+{
+ hpos = h.to_units();
+ vpos = v.to_units();
+}
+
+void troff_output_file::really_print_line(hunits x, vunits y, node *n,
+ vunits before, vunits after)
+{
+ moveto(x, y);
+ while (n != 0) {
+ n->tprint(this);
+ n = n->next;
+ }
+ flush_tbuf();
+ // This ensures that transparent throughput will have a more predictable
+ // position.
+ do_motion();
+ force_motion = 1;
+ hpos = 0;
+ put('n');
+ put(before.to_units());
+ put(' ');
+ put(after.to_units());
+ put('\n');
+}
+
+inline void troff_output_file::word_marker()
+{
+ flush_tbuf();
+ put('w');
+}
+
+inline void troff_output_file::right(hunits n)
+{
+ hpos += n.to_units();
+}
+
+inline void troff_output_file::down(vunits n)
+{
+ vpos += n.to_units();
+}
+
+void troff_output_file::do_motion()
+{
+ if (force_motion) {
+ put('V');
+ put(vpos);
+ put('\n');
+ put('H');
+ put(hpos);
+ put('\n');
+ }
+ else {
+ if (hpos != output_hpos) {
+ units n = hpos - output_hpos;
+ if (n > 0 && n < hpos) {
+ put('h');
+ put(n);
+ }
+ else {
+ put('H');
+ put(hpos);
+ }
+ put('\n');
+ }
+ if (vpos != output_vpos) {
+ units n = vpos - output_vpos;
+ if (n > 0 && n < vpos) {
+ put('v');
+ put(n);
+ }
+ else {
+ put('V');
+ put(vpos);
+ }
+ put('\n');
+ }
+ }
+ output_vpos = vpos;
+ output_hpos = hpos;
+ force_motion = 0;
+}
+
+void troff_output_file::flush_tbuf()
+{
+ if (tbuf_len == 0)
+ return;
+ if (tbuf_kern == 0)
+ put('t');
+ else {
+ put('u');
+ put(tbuf_kern);
+ put(' ');
+ }
+ for (int i = 0; i < tbuf_len; i++)
+ put(tbuf[i]);
+ put('\n');
+ tbuf_len = 0;
+}
+
+void troff_output_file::put_char_width(charinfo *ci, tfont *tf, hunits w,
+ hunits k)
+{
+ if (tf != current_tfont) {
+ flush_tbuf();
+ set_font(tf);
+ }
+ char c = ci->get_ascii_code();
+ int kk = k.to_units();
+ if (c == '\0') {
+ flush_tbuf();
+ do_motion();
+ if (ci->numbered()) {
+ put('N');
+ put(ci->get_number());
+ }
+ else {
+ put('C');
+ const char *s = ci->nm.contents();
+ if (s[1] == 0) {
+ put('\\');
+ put(s[0]);
+ }
+ else
+ put(s);
+ }
+ put('\n');
+ hpos += w.to_units() + kk;
+ }
+ else if (tcommand_flag) {
+ if (tbuf_len > 0 && hpos == output_hpos && vpos == output_vpos
+ && kk == tbuf_kern
+ && tbuf_len < TBUF_SIZE) {
+ tbuf[tbuf_len++] = c;
+ output_hpos += w.to_units() + kk;
+ hpos = output_hpos;
+ return;
+ }
+ flush_tbuf();
+ do_motion();
+ tbuf[tbuf_len++] = c;
+ output_hpos += w.to_units() + kk;
+ tbuf_kern = kk;
+ hpos = output_hpos;
+ }
+ else {
+ // flush_tbuf();
+ int n = hpos - output_hpos;
+ if (vpos == output_vpos && n > 0 && n < 100 && !force_motion) {
+ put(char(n/10 + '0'));
+ put(char(n%10 + '0'));
+ put(c);
+ output_hpos = hpos;
+ }
+ else {
+ do_motion();
+ put('c');
+ put(c);
+ }
+ hpos += w.to_units() + kk;
+ }
+}
+
+void troff_output_file::put_char(charinfo *ci, tfont *tf)
+{
+ flush_tbuf();
+ if (tf != current_tfont)
+ set_font(tf);
+ char c = ci->get_ascii_code();
+ if (c == '\0') {
+ do_motion();
+ if (ci->numbered()) {
+ put('N');
+ put(ci->get_number());
+ }
+ else {
+ put('C');
+ const char *s = ci->nm.contents();
+ if (s[1] == 0) {
+ put('\\');
+ put(s[0]);
+ }
+ else
+ put(s);
+ }
+ put('\n');
+ }
+ else {
+ int n = hpos - output_hpos;
+ if (vpos == output_vpos && n > 0 && n < 100) {
+ put(char(n/10 + '0'));
+ put(char(n%10 + '0'));
+ put(c);
+ output_hpos = hpos;
+ }
+ else {
+ do_motion();
+ put('c');
+ put(c);
+ }
+ }
+}
+
+void troff_output_file::set_font(tfont *tf)
+{
+ if (current_tfont == tf)
+ return;
+ int n = tf->get_input_position();
+ symbol nm = tf->get_name();
+ if (n >= nfont_positions || font_position[n] != nm) {
+ put("x font ");
+ put(n);
+ put(' ');
+ put(nm.contents());
+ put('\n');
+ if (n >= nfont_positions) {
+ int old_nfont_positions = nfont_positions;
+ symbol *old_font_position = font_position;
+ nfont_positions *= 3;
+ nfont_positions /= 2;
+ if (nfont_positions <= n)
+ nfont_positions = n + 10;
+ font_position = new symbol[nfont_positions];
+ memcpy(font_position, old_font_position,
+ old_nfont_positions*sizeof(symbol));
+ a_delete old_font_position;
+ }
+ font_position[n] = nm;
+ }
+ if (current_font_number != n) {
+ put('f');
+ put(n);
+ put('\n');
+ current_font_number = n;
+ }
+ int size = tf->get_size().to_scaled_points();
+ if (current_size != size) {
+ put('s');
+ put(size);
+ put('\n');
+ current_size = size;
+ }
+ int slant = tf->get_slant();
+ if (current_slant != slant) {
+ put("x Slant ");
+ put(slant);
+ put('\n');
+ current_slant = slant;
+ }
+ int height = tf->get_height();
+ if (current_height != height) {
+ put("x Height ");
+ put(height == 0 ? current_size : height);
+ put('\n');
+ current_height = height;
+ }
+ current_tfont = tf;
+}
+
+void troff_output_file::draw(char code, hvpair *point, int npoints,
+ font_size fsize)
+{
+ flush_tbuf();
+ do_motion();
+ int size = fsize.to_scaled_points();
+ if (current_size != size) {
+ put('s');
+ put(size);
+ put('\n');
+ current_size = size;
+ current_tfont = 0;
+ }
+ put('D');
+ put(code);
+ int i;
+ if (code == 'c') {
+ put(' ');
+ put(point[0].h.to_units());
+ }
+ else
+ for (i = 0; i < npoints; i++) {
+ put(' ');
+ put(point[i].h.to_units());
+ put(' ');
+ put(point[i].v.to_units());
+ }
+ for (i = 0; i < npoints; i++)
+ output_hpos += point[i].h.to_units();
+ hpos = output_hpos;
+ if (code != 'e') {
+ for (i = 0; i < npoints; i++)
+ output_vpos += point[i].v.to_units();
+ vpos = output_vpos;
+ }
+ put('\n');
+}
+
+void troff_output_file::really_begin_page(int pageno, vunits page_length)
+{
+ flush_tbuf();
+ if (begun_page) {
+ if (page_length > V0) {
+ put('V');
+ put(page_length.to_units());
+ put('\n');
+ }
+ }
+ else
+ begun_page = 1;
+ current_tfont = 0;
+ current_font_number = -1;
+ current_size = 0;
+ // current_height = 0;
+ // current_slant = 0;
+ hpos = 0;
+ vpos = 0;
+ output_hpos = 0;
+ output_vpos = 0;
+ force_motion = 1;
+ for (int i = 0; i < nfont_positions; i++)
+ font_position[i] = NULL_SYMBOL;
+ put('p');
+ put(pageno);
+ put('\n');
+}
+
+void troff_output_file::really_copy_file(hunits x, vunits y, const char *filename)
+{
+ moveto(x, y);
+ flush_tbuf();
+ do_motion();
+ errno = 0;
+ FILE *ifp = fopen(filename, "r");
+ if (ifp == 0)
+ error("can't open `%1': %2", filename, strerror(errno));
+ else {
+ int c;
+ while ((c = getc(ifp)) != EOF)
+ put(char(c));
+ fclose(ifp);
+ }
+ force_motion = 1;
+ current_size = 0;
+ current_tfont = 0;
+ current_font_number = -1;
+ for (int i = 0; i < nfont_positions; i++)
+ font_position[i] = NULL_SYMBOL;
+}
+
+void troff_output_file::really_transparent_char(unsigned char c)
+{
+ put(c);
+}
+
+troff_output_file::~troff_output_file()
+{
+ a_delete font_position;
+}
+
+void troff_output_file::trailer(vunits page_length)
+{
+ flush_tbuf();
+ if (page_length > V0) {
+ put("x trailer\n");
+ put('V');
+ put(page_length.to_units());
+ put('\n');
+ }
+ put("x stop\n");
+}
+
+troff_output_file::troff_output_file()
+: current_height(0), current_slant(0), tbuf_len(0), nfont_positions(10),
+ begun_page(0)
+{
+ font_position = new symbol[nfont_positions];
+ put("x T ");
+ put(device);
+ put('\n');
+ put("x res ");
+ put(units_per_inch);
+ put(' ');
+ put(hresolution);
+ put(' ');
+ put(vresolution);
+ put('\n');
+ put("x init\n");
+}
+
+/* output_file */
+
+output_file *the_output = 0;
+
+output_file::output_file()
+{
+}
+
+output_file::~output_file()
+{
+}
+
+void output_file::trailer(vunits)
+{
+}
+
+real_output_file::real_output_file()
+: printing(0)
+{
+#ifndef POPEN_MISSING
+ if (pipe_command) {
+ if ((fp = popen(pipe_command, "w")) != 0) {
+ piped = 1;
+ return;
+ }
+ error("pipe open failed: %1", strerror(errno));
+ }
+ piped = 0;
+#endif /* not POPEN_MISSING */
+ fp = stdout;
+}
+
+real_output_file::~real_output_file()
+{
+ if (!fp)
+ return;
+ // To avoid looping, set fp to 0 before calling fatal().
+ if (ferror(fp) || fflush(fp) < 0) {
+ fp = 0;
+ fatal("error writing output file");
+ }
+#ifndef POPEN_MISSING
+ if (piped) {
+ int result = pclose(fp);
+ fp = 0;
+ if (result < 0)
+ fatal("pclose failed");
+ if ((result & 0x7f) != 0)
+ error("output process `%1' got fatal signal %2",
+ pipe_command, result & 0x7f);
+ else {
+ int exit_status = (result >> 8) & 0xff;
+ if (exit_status != 0)
+ error("output process `%1' exited with status %2",
+ pipe_command, exit_status);
+ }
+ }
+ else
+#endif /* not POPEN MISSING */
+ if (fclose(fp) < 0) {
+ fp = 0;
+ fatal("error closing output file");
+ }
+}
+
+void real_output_file::flush()
+{
+ if (fflush(fp) < 0)
+ fatal("error writing output file");
+}
+
+int real_output_file::is_printing()
+{
+ return printing;
+}
+
+void real_output_file::begin_page(int pageno, vunits page_length)
+{
+ printing = in_output_page_list(pageno);
+ if (printing)
+ really_begin_page(pageno, page_length);
+}
+
+void real_output_file::copy_file(hunits x, vunits y, const char *filename)
+{
+ if (printing)
+ really_copy_file(x, y, filename);
+}
+
+void real_output_file::transparent_char(unsigned char c)
+{
+ if (printing)
+ really_transparent_char(c);
+}
+
+void real_output_file::print_line(hunits x, vunits y, node *n,
+ vunits before, vunits after)
+{
+ if (printing)
+ really_print_line(x, y, n, before, after);
+ delete_node_list(n);
+}
+
+void real_output_file::really_copy_file(hunits, vunits, const char *)
+{
+ // do nothing
+}
+
+
+/* ascii_output_file */
+
+void ascii_output_file::really_transparent_char(unsigned char c)
+{
+ putc(c, fp);
+}
+
+void ascii_output_file::really_print_line(hunits, vunits, node *n, vunits, vunits)
+{
+ while (n != 0) {
+ n->ascii_print(this);
+ n = n->next;
+ }
+ fputc('\n', fp);
+}
+
+void ascii_output_file::really_begin_page(int /*pageno*/, vunits /*page_length*/)
+{
+ fputs("<beginning of page>\n", fp);
+}
+
+ascii_output_file::ascii_output_file()
+{
+}
+
+/* suppress_output_file */
+
+suppress_output_file::suppress_output_file()
+{
+}
+
+void suppress_output_file::really_print_line(hunits, vunits, node *, vunits, vunits)
+{
+}
+
+void suppress_output_file::really_begin_page(int, vunits)
+{
+}
+
+void suppress_output_file::really_transparent_char(unsigned char)
+{
+}
+
+/* glyphs, ligatures, kerns, discretionary breaks */
+
+class glyph_node : public node {
+ static glyph_node *free_list;
+protected:
+ charinfo *ci;
+ tfont *tf;
+#ifdef STORE_WIDTH
+ hunits wid;
+ glyph_node(charinfo *, tfont *, hunits, node * = 0);
+#endif
+public:
+ void *operator new(size_t);
+ void operator delete(void *);
+ glyph_node(charinfo *, tfont *, node * = 0);
+ ~glyph_node() {}
+ node *copy();
+ node *merge_glyph_node(glyph_node *);
+ node *merge_self(node *);
+ hunits width();
+ node *last_char_node();
+ units size();
+ void vertical_extent(vunits *, vunits *);
+ hunits subscript_correction();
+ hunits italic_correction();
+ hunits left_italic_correction();
+ hunits skew();
+ hyphenation_type get_hyphenation_type();
+ tfont *get_tfont();
+ void tprint(troff_output_file *);
+ void zero_width_tprint(troff_output_file *);
+ hyphen_list *get_hyphen_list(hyphen_list *ss = 0);
+ node *add_self(node *, hyphen_list **);
+ int ends_sentence();
+ int overlaps_vertically();
+ int overlaps_horizontally();
+ void ascii_print(ascii_output_file *);
+ void asciify(macro *);
+ int character_type();
+ int same(node *);
+ const char *type();
+};
+
+glyph_node *glyph_node::free_list = 0;
+
+class ligature_node : public glyph_node {
+ node *n1;
+ node *n2;
+#ifdef STORE_WIDTH
+ ligature_node(charinfo *, tfont *, hunits, node *gn1, node *gn2, node *x = 0);
+#endif
+public:
+ void *operator new(size_t);
+ void operator delete(void *);
+ ligature_node(charinfo *, tfont *, node *gn1, node *gn2, node *x = 0);
+ ~ligature_node();
+ node *copy();
+ node *add_self(node *, hyphen_list **);
+ hyphen_list *get_hyphen_list(hyphen_list *ss = 0);
+ void ascii_print(ascii_output_file *);
+ void asciify(macro *);
+ int same(node *);
+ const char *type();
+};
+
+class kern_pair_node : public node {
+ hunits amount;
+ node *n1;
+ node *n2;
+public:
+ kern_pair_node(hunits n, node *first, node *second, node *x = 0);
+ ~kern_pair_node();
+ node *copy();
+ node *merge_glyph_node(glyph_node *);
+ node *add_self(node *, hyphen_list **);
+ hyphen_list *get_hyphen_list(hyphen_list *ss = 0);
+ node *add_discretionary_hyphen();
+ hunits width();
+ node *last_char_node();
+ hunits italic_correction();
+ hunits subscript_correction();
+ void tprint(troff_output_file *);
+ hyphenation_type get_hyphenation_type();
+ int ends_sentence();
+ void ascii_print(ascii_output_file *);
+ void asciify(macro *);
+ int same(node *);
+ const char *type();
+};
+
+class dbreak_node : public node {
+ node *none;
+ node *pre;
+ node *post;
+public:
+ dbreak_node(node *n, node *p, node *x = 0);
+ ~dbreak_node();
+ node *copy();
+ node *merge_glyph_node(glyph_node *);
+ node *add_discretionary_hyphen();
+ hunits width();
+ node *last_char_node();
+ hunits italic_correction();
+ hunits subscript_correction();
+ void tprint(troff_output_file *);
+ breakpoint *get_breakpoints(hunits width, int ns, breakpoint *rest = 0,
+ int is_inner = 0);
+ int nbreaks();
+ int ends_sentence();
+ void split(int, node **, node **);
+ hyphenation_type get_hyphenation_type();
+ void ascii_print(ascii_output_file *);
+ void asciify(macro *);
+ int same(node *);
+ const char *type();
+};
+
+void *glyph_node::operator new(size_t n)
+{
+ assert(n == sizeof(glyph_node));
+ if (!free_list) {
+ const int BLOCK = 1024;
+ free_list = (glyph_node *)new char[sizeof(glyph_node)*BLOCK];
+ for (int i = 0; i < BLOCK - 1; i++)
+ free_list[i].next = free_list + i + 1;
+ free_list[BLOCK-1].next = 0;
+ }
+ glyph_node *p = free_list;
+ free_list = (glyph_node *)(free_list->next);
+ p->next = 0;
+ return p;
+}
+
+void *ligature_node::operator new(size_t n)
+{
+ return new char[n];
+}
+
+void glyph_node::operator delete(void *p)
+{
+ if (p) {
+ ((glyph_node *)p)->next = free_list;
+ free_list = (glyph_node *)p;
+ }
+}
+
+void ligature_node::operator delete(void *p)
+{
+ delete p;
+}
+
+glyph_node::glyph_node(charinfo *c, tfont *t, node *x)
+ : ci(c), tf(t), node(x)
+{
+#ifdef STORE_WIDTH
+ wid = tf->get_width(ci);
+#endif
+}
+
+#ifdef STORE_WIDTH
+glyph_node::glyph_node(charinfo *c, tfont *t, hunits w, node *x)
+ : ci(c), tf(t), wid(w), node(x)
+{
+}
+#endif
+
+node *glyph_node::copy()
+{
+#ifdef STORE_WIDTH
+ return new glyph_node(ci, tf, wid);
+#else
+ return new glyph_node(ci, tf);
+#endif
+}
+
+node *glyph_node::merge_self(node *nd)
+{
+ return nd->merge_glyph_node(this);
+}
+
+int glyph_node::character_type()
+{
+ return tf->get_character_type(ci);
+}
+
+node *glyph_node::add_self(node *n, hyphen_list **p)
+{
+ assert(ci->get_hyphenation_code() == (*p)->hyphenation_code);
+ next = 0;
+ node *nn;
+ if (n == 0 || (nn = n->merge_glyph_node(this)) == 0) {
+ next = n;
+ nn = this;
+ }
+ if ((*p)->hyphen)
+ nn = nn->add_discretionary_hyphen();
+ hyphen_list *pp = *p;
+ *p = (*p)->next;
+ delete pp;
+ return nn;
+}
+
+int glyph_node::overlaps_horizontally()
+{
+ return ci->overlaps_horizontally();
+}
+
+int glyph_node::overlaps_vertically()
+{
+ return ci->overlaps_vertically();
+}
+
+units glyph_node::size()
+{
+ return tf->get_size().to_units();
+}
+
+hyphen_list *glyph_node::get_hyphen_list(hyphen_list *tail)
+{
+ return new hyphen_list(ci->get_hyphenation_code(), tail);
+}
+
+
+tfont *node::get_tfont()
+{
+ return 0;
+}
+
+tfont *glyph_node::get_tfont()
+{
+ return tf;
+}
+
+node *node::merge_glyph_node(glyph_node * /*gn*/)
+{
+ return 0;
+}
+
+node *glyph_node::merge_glyph_node(glyph_node *gn)
+{
+ if (tf == gn->tf) {
+ charinfo *lig;
+ if ((lig = tf->get_lig(ci, gn->ci)) != 0) {
+ node *next1 = next;
+ next = 0;
+ return new ligature_node(lig, tf, this, gn, next1);
+ }
+ hunits kern;
+ if (tf->get_kern(ci, gn->ci, &kern)) {
+ node *next1 = next;
+ next = 0;
+ return new kern_pair_node(kern, this, gn, next1);
+ }
+ }
+ return 0;
+}
+
+#ifdef STORE_WIDTH
+inline
+#endif
+hunits glyph_node::width()
+{
+#ifdef STORE_WIDTH
+ return wid;
+#else
+ return tf->get_width(ci);
+#endif
+}
+
+node *glyph_node::last_char_node()
+{
+ return this;
+}
+
+void glyph_node::vertical_extent(vunits *min, vunits *max)
+{
+ *min = -tf->get_char_height(ci);
+ *max = tf->get_char_depth(ci);
+}
+
+hunits glyph_node::skew()
+{
+ return tf->get_char_skew(ci);
+}
+
+hunits glyph_node::subscript_correction()
+{
+ return tf->get_subscript_correction(ci);
+}
+
+hunits glyph_node::italic_correction()
+{
+ return tf->get_italic_correction(ci);
+}
+
+hunits glyph_node::left_italic_correction()
+{
+ return tf->get_left_italic_correction(ci);
+}
+
+hyphenation_type glyph_node::get_hyphenation_type()
+{
+ return HYPHEN_MIDDLE;
+}
+
+int glyph_node::ends_sentence()
+{
+ if (ci->ends_sentence())
+ return 1;
+ else if (ci->transparent())
+ return 2;
+ else
+ return 0;
+}
+
+void glyph_node::ascii_print(ascii_output_file *ascii)
+{
+ unsigned char c = ci->get_ascii_code();
+ if (c != 0)
+ ascii->outc(c);
+ else
+ ascii->outs(ci->nm.contents());
+}
+
+ligature_node::ligature_node(charinfo *c, tfont *t,
+ node *gn1, node *gn2, node *x)
+ : glyph_node(c, t, x), n1(gn1), n2(gn2)
+{
+}
+
+#ifdef STORE_WIDTH
+ligature_node::ligature_node(charinfo *c, tfont *t, hunits w,
+ node *gn1, node *gn2, node *x)
+ : glyph_node(c, t, w, x), n1(gn1), n2(gn2)
+{
+}
+#endif
+
+ligature_node::~ligature_node()
+{
+ delete n1;
+ delete n2;
+}
+
+node *ligature_node::copy()
+{
+#ifdef STORE_WIDTH
+ return new ligature_node(ci, tf, wid, n1->copy(), n2->copy());
+#else
+ return new ligature_node(ci, tf, n1->copy(), n2->copy());
+#endif
+}
+
+void ligature_node::ascii_print(ascii_output_file *ascii)
+{
+ n1->ascii_print(ascii);
+ n2->ascii_print(ascii);
+}
+
+hyphen_list *ligature_node::get_hyphen_list(hyphen_list *tail)
+{
+ return n1->get_hyphen_list(n2->get_hyphen_list(tail));
+}
+
+node *ligature_node::add_self(node *n, hyphen_list **p)
+{
+ n = n1->add_self(n, p);
+ n = n2->add_self(n, p);
+ n1 = n2 = 0;
+ delete this;
+ return n;
+}
+
+kern_pair_node::kern_pair_node(hunits n, node *first, node *second, node *x)
+ : node(x), n1(first), n2(second), amount(n)
+{
+}
+
+dbreak_node::dbreak_node(node *n, node *p, node *x)
+ : node(x), none(n), pre(p), post(0)
+{
+}
+
+node *dbreak_node::merge_glyph_node(glyph_node *gn)
+{
+ glyph_node *gn2 = (glyph_node *)gn->copy();
+ node *new_none = none ? none->merge_glyph_node(gn) : 0;
+ node *new_post = post ? post->merge_glyph_node(gn2) : 0;
+ if (new_none == 0 && new_post == 0) {
+ delete gn2;
+ return 0;
+ }
+ if (new_none != 0)
+ none = new_none;
+ else {
+ gn->next = none;
+ none = gn;
+ }
+ if (new_post != 0)
+ post = new_post;
+ else {
+ gn2->next = post;
+ post = gn2;
+ }
+ return this;
+}
+
+node *kern_pair_node::merge_glyph_node(glyph_node *gn)
+{
+ node *nd = n2->merge_glyph_node(gn);
+ if (nd == 0)
+ return 0;
+ n2 = nd;
+ nd = n2->merge_self(n1);
+ if (nd) {
+ nd->next = next;
+ n1 = 0;
+ n2 = 0;
+ delete this;
+ return nd;
+ }
+ return this;
+}
+
+
+hunits kern_pair_node::italic_correction()
+{
+ return n2->italic_correction();
+}
+
+hunits kern_pair_node::subscript_correction()
+{
+ return n2->subscript_correction();
+}
+
+node *kern_pair_node::add_discretionary_hyphen()
+{
+ tfont *tf = n2->get_tfont();
+ if (tf) {
+ if (tf->contains(soft_hyphen_char)) {
+ node *next1 = next;
+ next = 0;
+ node *n = copy();
+ glyph_node *gn = new glyph_node(soft_hyphen_char, tf);
+ node *nn = n->merge_glyph_node(gn);
+ if (nn == 0) {
+ gn->next = n;
+ nn = gn;
+ }
+ return new dbreak_node(this, nn, next1);
+ }
+ }
+ return this;
+}
+
+
+kern_pair_node::~kern_pair_node()
+{
+ if (n1 != 0)
+ delete n1;
+ if (n2 != 0)
+ delete n2;
+}
+
+dbreak_node::~dbreak_node()
+{
+ delete_node_list(pre);
+ delete_node_list(post);
+ delete_node_list(none);
+}
+
+node *kern_pair_node::copy()
+{
+ return new kern_pair_node(amount, n1->copy(), n2->copy());
+}
+
+node *copy_node_list(node *n)
+{
+ node *p = 0;
+ while (n != 0) {
+ node *nn = n->copy();
+ nn->next = p;
+ p = nn;
+ n = n->next;
+ }
+ while (p != 0) {
+ node *pp = p->next;
+ p->next = n;
+ n = p;
+ p = pp;
+ }
+ return n;
+}
+
+void delete_node_list(node *n)
+{
+ while (n != 0) {
+ node *tem = n;
+ n = n->next;
+ delete tem;
+ }
+}
+
+node *dbreak_node::copy()
+{
+ dbreak_node *p = new dbreak_node(copy_node_list(none), copy_node_list(pre));
+ p->post = copy_node_list(post);
+ return p;
+}
+
+hyphen_list *node::get_hyphen_list(hyphen_list *tail)
+{
+ return tail;
+}
+
+
+hyphen_list *kern_pair_node::get_hyphen_list(hyphen_list *tail)
+{
+ return n1->get_hyphen_list(n2->get_hyphen_list(tail));
+}
+
+class hyphen_inhibitor_node : public node {
+public:
+ hyphen_inhibitor_node(node *nd = 0);
+ node *copy();
+ int same(node *);
+ const char *type();
+ hyphenation_type get_hyphenation_type();
+};
+
+hyphen_inhibitor_node::hyphen_inhibitor_node(node *nd) : node(nd)
+{
+}
+
+node *hyphen_inhibitor_node::copy()
+{
+ return new hyphen_inhibitor_node;
+}
+
+int hyphen_inhibitor_node::same(node *)
+{
+ return 1;
+}
+
+const char *hyphen_inhibitor_node::type()
+{
+ return "hyphen_inhibitor_node";
+}
+
+hyphenation_type hyphen_inhibitor_node::get_hyphenation_type()
+{
+ return HYPHEN_INHIBIT;
+}
+
+/* add_discretionary_hyphen methods */
+
+node *dbreak_node::add_discretionary_hyphen()
+{
+ if (post)
+ post = post->add_discretionary_hyphen();
+ if (none)
+ none = none->add_discretionary_hyphen();
+ return this;
+}
+
+
+node *node::add_discretionary_hyphen()
+{
+ tfont *tf = get_tfont();
+ if (!tf)
+ return new hyphen_inhibitor_node(this);
+ if (tf->contains(soft_hyphen_char)) {
+ node *next1 = next;
+ next = 0;
+ node *n = copy();
+ glyph_node *gn = new glyph_node(soft_hyphen_char, tf);
+ node *n1 = n->merge_glyph_node(gn);
+ if (n1 == 0) {
+ gn->next = n;
+ n1 = gn;
+ }
+ return new dbreak_node(this, n1, next1);
+ }
+ return this;
+}
+
+
+node *node::merge_self(node *)
+{
+ return 0;
+}
+
+node *node::add_self(node *n, hyphen_list ** /*p*/)
+{
+ next = n;
+ return this;
+}
+
+node *kern_pair_node::add_self(node *n, hyphen_list **p)
+{
+ n = n1->add_self(n, p);
+ n = n2->add_self(n, p);
+ n1 = n2 = 0;
+ delete this;
+ return n;
+}
+
+
+hunits node::width()
+{
+ return H0;
+}
+
+node *node::last_char_node()
+{
+ return 0;
+}
+
+hunits hmotion_node::width()
+{
+ return n;
+}
+
+units node::size()
+{
+ return points_to_units(10);
+}
+
+hunits kern_pair_node::width()
+{
+ return n1->width() + n2->width() + amount;
+}
+
+node *kern_pair_node::last_char_node()
+{
+ node *nd = n2->last_char_node();
+ if (nd)
+ return nd;
+ return n1->last_char_node();
+}
+
+hunits dbreak_node::width()
+{
+ hunits x = H0;
+ for (node *n = none; n != 0; n = n->next)
+ x += n->width();
+ return x;
+}
+
+node *dbreak_node::last_char_node()
+{
+ for (node *n = none; n; n = n->next) {
+ node *last = n->last_char_node();
+ if (last)
+ return last;
+ }
+ return 0;
+}
+
+hunits dbreak_node::italic_correction()
+{
+ return none ? none->italic_correction() : H0;
+}
+
+hunits dbreak_node::subscript_correction()
+{
+ return none ? none->subscript_correction() : H0;
+}
+
+class italic_corrected_node : public node {
+ node *n;
+ hunits x;
+public:
+ italic_corrected_node(node *, hunits, node * = 0);
+ ~italic_corrected_node();
+ node *copy();
+ void ascii_print(ascii_output_file *);
+ void asciify(macro *m);
+ hunits width();
+ node *last_char_node();
+ void vertical_extent(vunits *, vunits *);
+ int ends_sentence();
+ int overlaps_horizontally();
+ int overlaps_vertically();
+ int same(node *);
+ hyphenation_type get_hyphenation_type();
+ tfont *get_tfont();
+ hyphen_list *get_hyphen_list(hyphen_list *ss = 0);
+ int character_type();
+ void tprint(troff_output_file *);
+ hunits subscript_correction();
+ hunits skew();
+ node *add_self(node *, hyphen_list **);
+ const char *type();
+};
+
+node *node::add_italic_correction(hunits *width)
+{
+ hunits ic = italic_correction();
+ if (ic.is_zero())
+ return this;
+ else {
+ node *next1 = next;
+ next = 0;
+ *width += ic;
+ return new italic_corrected_node(this, ic, next1);
+ }
+}
+
+italic_corrected_node::italic_corrected_node(node *nn, hunits xx, node *p)
+: n(nn), x(xx), node(p)
+{
+ assert(n != 0);
+}
+
+italic_corrected_node::~italic_corrected_node()
+{
+ delete n;
+}
+
+node *italic_corrected_node::copy()
+{
+ return new italic_corrected_node(n->copy(), x);
+}
+
+hunits italic_corrected_node::width()
+{
+ return n->width() + x;
+}
+
+void italic_corrected_node::vertical_extent(vunits *min, vunits *max)
+{
+ n->vertical_extent(min, max);
+}
+
+void italic_corrected_node::tprint(troff_output_file *out)
+{
+ n->tprint(out);
+ out->right(x);
+}
+
+hunits italic_corrected_node::skew()
+{
+ return n->skew() - x/2;
+}
+
+hunits italic_corrected_node::subscript_correction()
+{
+ return n->subscript_correction() - x;
+}
+
+void italic_corrected_node::ascii_print(ascii_output_file *out)
+{
+ n->ascii_print(out);
+}
+
+int italic_corrected_node::ends_sentence()
+{
+ return n->ends_sentence();
+}
+
+int italic_corrected_node::overlaps_horizontally()
+{
+ return n->overlaps_horizontally();
+}
+
+int italic_corrected_node::overlaps_vertically()
+{
+ return n->overlaps_vertically();
+}
+
+node *italic_corrected_node::last_char_node()
+{
+ return n->last_char_node();
+}
+
+tfont *italic_corrected_node::get_tfont()
+{
+ return n->get_tfont();
+}
+
+hyphenation_type italic_corrected_node::get_hyphenation_type()
+{
+ return n->get_hyphenation_type();
+}
+
+node *italic_corrected_node::add_self(node *nd, hyphen_list **p)
+{
+ nd = n->add_self(nd, p);
+ hunits not_interested;
+ nd = nd->add_italic_correction(&not_interested);
+ n = 0;
+ delete this;
+ return nd;
+}
+
+hyphen_list *italic_corrected_node::get_hyphen_list(hyphen_list *tail)
+{
+ return n->get_hyphen_list(tail);
+}
+
+int italic_corrected_node::character_type()
+{
+ return n->character_type();
+}
+
+class break_char_node : public node {
+ node *ch;
+ char break_code;
+public:
+ break_char_node(node *, int, node * = 0);
+ ~break_char_node();
+ node *copy();
+ hunits width();
+ vunits vertical_width();
+ node *last_char_node();
+ int character_type();
+ int ends_sentence();
+ node *add_self(node *, hyphen_list **);
+ hyphen_list *get_hyphen_list(hyphen_list *s = 0);
+ void tprint(troff_output_file *);
+ void zero_width_tprint(troff_output_file *);
+ void ascii_print(ascii_output_file *);
+ void asciify(macro *m);
+ hyphenation_type get_hyphenation_type();
+ int overlaps_vertically();
+ int overlaps_horizontally();
+ units size();
+ tfont *get_tfont();
+ int same(node *);
+ const char *type();
+};
+
+break_char_node::break_char_node(node *n, int c, node *x)
+: node(x), ch(n), break_code(c)
+{
+}
+
+break_char_node::~break_char_node()
+{
+ delete ch;
+}
+
+node *break_char_node::copy()
+{
+ return new break_char_node(ch->copy(), break_code);
+}
+
+hunits break_char_node::width()
+{
+ return ch->width();
+}
+
+vunits break_char_node::vertical_width()
+{
+ return ch->vertical_width();
+}
+
+node *break_char_node::last_char_node()
+{
+ return ch->last_char_node();
+}
+
+int break_char_node::character_type()
+{
+ return ch->character_type();
+}
+
+int break_char_node::ends_sentence()
+{
+ return ch->ends_sentence();
+}
+
+node *break_char_node::add_self(node *n, hyphen_list **p)
+{
+ assert((*p)->hyphenation_code == 0);
+ if ((*p)->breakable && (break_code & 1)) {
+ n = new space_node(H0, n);
+ n->freeze_space();
+ }
+ next = n;
+ n = this;
+ if ((*p)->breakable && (break_code & 2)) {
+ n = new space_node(H0, n);
+ n->freeze_space();
+ }
+ hyphen_list *pp = *p;
+ *p = (*p)->next;
+ delete pp;
+ return n;
+}
+
+hyphen_list *break_char_node::get_hyphen_list(hyphen_list *tail)
+{
+ return new hyphen_list(0, tail);
+}
+
+hyphenation_type break_char_node::get_hyphenation_type()
+{
+ return HYPHEN_MIDDLE;
+}
+
+void break_char_node::ascii_print(ascii_output_file *ascii)
+{
+ ch->ascii_print(ascii);
+}
+
+int break_char_node::overlaps_vertically()
+{
+ return ch->overlaps_vertically();
+}
+
+int break_char_node::overlaps_horizontally()
+{
+ return ch->overlaps_horizontally();
+}
+
+units break_char_node::size()
+{
+ return ch->size();
+}
+
+tfont *break_char_node::get_tfont()
+{
+ return ch->get_tfont();
+}
+
+node *extra_size_node::copy()
+{
+ return new extra_size_node(n);
+}
+
+node *vertical_size_node::copy()
+{
+ return new vertical_size_node(n);
+}
+
+node *hmotion_node::copy()
+{
+ return new hmotion_node(n);
+}
+
+node *space_char_hmotion_node::copy()
+{
+ return new space_char_hmotion_node(n);
+}
+
+node *vmotion_node::copy()
+{
+ return new vmotion_node(n);
+}
+
+node *dummy_node::copy()
+{
+ return new dummy_node;
+}
+
+node *transparent_dummy_node::copy()
+{
+ return new transparent_dummy_node;
+}
+
+hline_node::~hline_node()
+{
+ if (n)
+ delete n;
+}
+
+node *hline_node::copy()
+{
+ return new hline_node(x, n ? n->copy() : 0);
+}
+
+hunits hline_node::width()
+{
+ return x < H0 ? H0 : x;
+}
+
+
+vline_node::~vline_node()
+{
+ if (n)
+ delete n;
+}
+
+node *vline_node::copy()
+{
+ return new vline_node(x, n ? n->copy() : 0);
+}
+
+hunits vline_node::width()
+{
+ return n == 0 ? H0 : n->width();
+}
+
+
+zero_width_node::zero_width_node(node *nd) : n(nd)
+{
+}
+
+zero_width_node::~zero_width_node()
+{
+ delete_node_list(n);
+}
+
+node *zero_width_node::copy()
+{
+ return new zero_width_node(copy_node_list(n));
+}
+
+int node_list_character_type(node *p)
+{
+ int t = 0;
+ for (; p; p = p->next)
+ t |= p->character_type();
+ return t;
+}
+
+int zero_width_node::character_type()
+{
+ return node_list_character_type(n);
+}
+
+void node_list_vertical_extent(node *p, vunits *min, vunits *max)
+{
+ *min = V0;
+ *max = V0;
+ vunits cur_vpos = V0;
+ vunits v1, v2;
+ for (; p; p = p->next) {
+ p->vertical_extent(&v1, &v2);
+ v1 += cur_vpos;
+ if (v1 < *min)
+ *min = v1;
+ v2 += cur_vpos;
+ if (v2 > *max)
+ *max = v2;
+ cur_vpos += p->vertical_width();
+ }
+}
+
+void zero_width_node::vertical_extent(vunits *min, vunits *max)
+{
+ node_list_vertical_extent(n, min, max);
+}
+
+overstrike_node::overstrike_node() : max_width(H0), list(0)
+{
+}
+
+overstrike_node::~overstrike_node()
+{
+ delete_node_list(list);
+}
+
+node *overstrike_node::copy()
+{
+ overstrike_node *on = new overstrike_node;
+ for (node *tem = list; tem; tem = tem->next)
+ on->overstrike(tem->copy());
+ return on;
+}
+
+void overstrike_node::overstrike(node *n)
+{
+ if (n == 0)
+ return;
+ hunits w = n->width();
+ if (w > max_width)
+ max_width = w;
+ for (node **p = &list; *p; p = &(*p)->next)
+ ;
+ n->next = 0;
+ *p = n;
+}
+
+hunits overstrike_node::width()
+{
+ return max_width;
+}
+
+bracket_node::bracket_node() : max_width(H0), list(0)
+{
+}
+
+bracket_node::~bracket_node()
+{
+ delete_node_list(list);
+}
+
+node *bracket_node::copy()
+{
+ bracket_node *on = new bracket_node;
+ for (node *tem = list; tem; tem = tem->next)
+ on->bracket(tem->copy());
+ return on;
+}
+
+
+void bracket_node::bracket(node *n)
+{
+ if (n == 0)
+ return;
+ hunits w = n->width();
+ if (w > max_width)
+ max_width = w;
+ n->next = list;
+ list = n;
+}
+
+hunits bracket_node::width()
+{
+ return max_width;
+}
+
+int node::nspaces()
+{
+ return 0;
+}
+
+int node::merge_space(hunits)
+{
+ return 0;
+}
+
+#if 0
+space_node *space_node::free_list = 0;
+
+void *space_node::operator new(size_t n)
+{
+ assert(n == sizeof(space_node));
+ if (!free_list) {
+ free_list = (space_node *)new char[sizeof(space_node)*BLOCK];
+ for (int i = 0; i < BLOCK - 1; i++)
+ free_list[i].next = free_list + i + 1;
+ free_list[BLOCK-1].next = 0;
+ }
+ space_node *p = free_list;
+ free_list = (space_node *)(free_list->next);
+ p->next = 0;
+ return p;
+}
+
+inline void space_node::operator delete(void *p)
+{
+ if (p) {
+ ((space_node *)p)->next = free_list;
+ free_list = (space_node *)p;
+ }
+}
+#endif
+
+space_node::space_node(hunits nn, node *p) : node(p), n(nn), set(0)
+{
+}
+
+space_node::space_node(hunits nn, int s, node *p) : node(p), n(nn), set(s)
+{
+}
+
+#if 0
+space_node::~space_node()
+{
+}
+#endif
+
+node *space_node::copy()
+{
+ return new space_node(n, set);
+}
+
+int space_node::nspaces()
+{
+ return set ? 0 : 1;
+}
+
+int space_node::merge_space(hunits h)
+{
+ n += h;
+ return 1;
+}
+
+hunits space_node::width()
+{
+ return n;
+}
+
+void node::spread_space(int*, hunits*)
+{
+}
+
+void space_node::spread_space(int *nspaces, hunits *desired_space)
+{
+ if (!set) {
+ assert(*nspaces > 0);
+ if (*nspaces == 1) {
+ n += *desired_space;
+ *desired_space = H0;
+ }
+ else {
+ hunits extra = *desired_space / *nspaces;
+ *desired_space -= extra;
+ n += extra;
+ }
+ *nspaces -= 1;
+ set = 1;
+ }
+}
+
+void node::freeze_space()
+{
+}
+
+void space_node::freeze_space()
+{
+ set = 1;
+}
+
+diverted_space_node::diverted_space_node(vunits d, node *p)
+: node(p), n(d)
+{
+}
+
+node *diverted_space_node::copy()
+{
+ return new diverted_space_node(n);
+}
+
+diverted_copy_file_node::diverted_copy_file_node(symbol s, node *p)
+: node(p), filename(s)
+{
+}
+
+node *diverted_copy_file_node::copy()
+{
+ return new diverted_copy_file_node(filename);
+}
+
+int node::ends_sentence()
+{
+ return 0;
+}
+
+int kern_pair_node::ends_sentence()
+{
+ switch (n2->ends_sentence()) {
+ case 0:
+ return 0;
+ case 1:
+ return 1;
+ case 2:
+ break;
+ default:
+ assert(0);
+ }
+ return n1->ends_sentence();
+}
+
+int node_list_ends_sentence(node *n)
+{
+ for (; n != 0; n = n->next)
+ switch (n->ends_sentence()) {
+ case 0:
+ return 0;
+ case 1:
+ return 1;
+ case 2:
+ break;
+ default:
+ assert(0);
+ }
+ return 2;
+}
+
+
+int dbreak_node::ends_sentence()
+{
+ return node_list_ends_sentence(none);
+}
+
+
+int node::overlaps_horizontally()
+{
+ return 0;
+}
+
+int node::overlaps_vertically()
+{
+ return 0;
+}
+
+int node::discardable()
+{
+ return 0;
+}
+
+int space_node::discardable()
+{
+ return set ? 0 : 1;
+}
+
+
+vunits node::vertical_width()
+{
+ return V0;
+}
+
+vunits vline_node::vertical_width()
+{
+ return x;
+}
+
+vunits vmotion_node::vertical_width()
+{
+ return n;
+}
+
+int node::character_type()
+{
+ return 0;
+}
+
+hunits node::subscript_correction()
+{
+ return H0;
+}
+
+hunits node::italic_correction()
+{
+ return H0;
+}
+
+hunits node::left_italic_correction()
+{
+ return H0;
+}
+
+hunits node::skew()
+{
+ return H0;
+}
+
+
+/* vertical_extent methods */
+
+void node::vertical_extent(vunits *min, vunits *max)
+{
+ vunits v = vertical_width();
+ if (v < V0) {
+ *min = v;
+ *max = V0;
+ }
+ else {
+ *max = v;
+ *min = V0;
+ }
+}
+
+void vline_node::vertical_extent(vunits *min, vunits *max)
+{
+ if (n == 0)
+ node::vertical_extent(min, max);
+ else {
+ vunits cmin, cmax;
+ n->vertical_extent(&cmin, &cmax);
+ vunits h = n->size();
+ if (x < V0) {
+ if (-x < h) {
+ *min = x;
+ *max = V0;
+ }
+ else {
+ // we print the first character and then move up, so
+ *max = cmax;
+ // we print the last character and then move up h
+ *min = cmin + h;
+ if (*min > V0)
+ *min = V0;
+ *min += x;
+ }
+ }
+ else {
+ if (x < h) {
+ *max = x;
+ *min = V0;
+ }
+ else {
+ // we move down by h and then print the first character, so
+ *min = cmin + h;
+ if (*min > V0)
+ *min = V0;
+ *max = x + cmax;
+ }
+ }
+ }
+}
+
+/* ascii_print methods */
+
+
+static void ascii_print_reverse_node_list(ascii_output_file *ascii, node *n)
+{
+ if (n == 0)
+ return;
+ ascii_print_reverse_node_list(ascii, n->next);
+ n->ascii_print(ascii);
+}
+
+void dbreak_node::ascii_print(ascii_output_file *ascii)
+{
+ ascii_print_reverse_node_list(ascii, none);
+}
+
+void kern_pair_node::ascii_print(ascii_output_file *ascii)
+{
+ n1->ascii_print(ascii);
+ n2->ascii_print(ascii);
+}
+
+
+void node::ascii_print(ascii_output_file *)
+{
+}
+
+void space_node::ascii_print(ascii_output_file *ascii)
+{
+ if (!n.is_zero())
+ ascii->outc(' ');
+}
+
+void hmotion_node::ascii_print(ascii_output_file *ascii)
+{
+ // this is pretty arbitrary
+ if (n >= points_to_units(2))
+ ascii->outc(' ');
+}
+
+void space_char_hmotion_node::ascii_print(ascii_output_file *ascii)
+{
+ ascii->outc(' ');
+}
+
+/* asciify methods */
+
+void node::asciify(macro *m)
+{
+ m->append(this);
+}
+
+void glyph_node::asciify(macro *m)
+{
+ unsigned char c = ci->get_ascii_code();
+ if (c != 0) {
+ m->append(c);
+ delete this;
+ }
+ else
+ m->append(this);
+}
+
+void kern_pair_node::asciify(macro *m)
+{
+ n1->asciify(m);
+ n2->asciify(m);
+ n1 = n2 = 0;
+ delete this;
+}
+
+static void asciify_reverse_node_list(macro *m, node *n)
+{
+ if (n == 0)
+ return;
+ asciify_reverse_node_list(m, n->next);
+ n->asciify(m);
+}
+
+void dbreak_node::asciify(macro *m)
+{
+ asciify_reverse_node_list(m, none);
+ none = 0;
+ delete this;
+}
+
+void ligature_node::asciify(macro *m)
+{
+ n1->asciify(m);
+ n2->asciify(m);
+ n1 = n2 = 0;
+ delete this;
+}
+
+void break_char_node::asciify(macro *m)
+{
+ ch->asciify(m);
+ ch = 0;
+ delete this;
+}
+
+void italic_corrected_node::asciify(macro *m)
+{
+ n->asciify(m);
+ n = 0;
+ delete this;
+}
+
+void left_italic_corrected_node::asciify(macro *m)
+{
+ if (n) {
+ n->asciify(m);
+ n = 0;
+ }
+ delete this;
+}
+
+space_char_hmotion_node::space_char_hmotion_node(hunits i, node *next)
+: hmotion_node(i, next)
+{
+}
+
+void space_char_hmotion_node::asciify(macro *m)
+{
+ m->append(' ');
+ delete this;
+}
+
+void line_start_node::asciify(macro *)
+{
+ delete this;
+}
+
+void vertical_size_node::asciify(macro *)
+{
+ delete this;
+}
+
+breakpoint *node::get_breakpoints(hunits /*width*/, int /*nspaces*/,
+ breakpoint *rest, int /*is_inner*/)
+{
+ return rest;
+}
+
+int node::nbreaks()
+{
+ return 0;
+}
+
+breakpoint *space_node::get_breakpoints(hunits width, int ns, breakpoint *rest,
+ int is_inner)
+{
+ if (next->discardable())
+ return rest;
+ breakpoint *bp = new breakpoint;
+ bp->next = rest;
+ bp->width = width;
+ bp->nspaces = ns;
+ bp->hyphenated = 0;
+ if (is_inner) {
+ assert(rest != 0);
+ bp->index = rest->index + 1;
+ bp->nd = rest->nd;
+ }
+ else {
+ bp->nd = this;
+ bp->index = 0;
+ }
+ return bp;
+}
+
+int space_node::nbreaks()
+{
+ if (next->discardable())
+ return 0;
+ else
+ return 1;
+}
+
+static breakpoint *node_list_get_breakpoints(node *p, hunits *widthp,
+ int ns, breakpoint *rest)
+{
+ if (p != 0) {
+ rest = p->get_breakpoints(*widthp,
+ ns,
+ node_list_get_breakpoints(p->next, widthp, ns,
+ rest),
+ 1);
+ *widthp += p->width();
+ }
+ return rest;
+}
+
+
+breakpoint *dbreak_node::get_breakpoints(hunits width, int ns,
+ breakpoint *rest, int is_inner)
+{
+ breakpoint *bp = new breakpoint;
+ bp->next = rest;
+ bp->width = width;
+ for (node *tem = pre; tem != 0; tem = tem->next)
+ bp->width += tem->width();
+ bp->nspaces = ns;
+ bp->hyphenated = 1;
+ if (is_inner) {
+ assert(rest != 0);
+ bp->index = rest->index + 1;
+ bp->nd = rest->nd;
+ }
+ else {
+ bp->nd = this;
+ bp->index = 0;
+ }
+ return node_list_get_breakpoints(none, &width, ns, bp);
+}
+
+int dbreak_node::nbreaks()
+{
+ int i = 1;
+ for (node *tem = none; tem != 0; tem = tem->next)
+ i += tem->nbreaks();
+ return i;
+}
+
+void node::split(int /*where*/, node ** /*prep*/, node ** /*postp*/)
+{
+ assert(0);
+}
+
+void space_node::split(int where, node **pre, node **post)
+{
+ assert(where == 0);
+ *pre = next;
+ *post = 0;
+ delete this;
+}
+
+static void node_list_split(node *p, int *wherep, node **prep, node **postp)
+{
+ if (p == 0)
+ return;
+ int nb = p->nbreaks();
+ node_list_split(p->next, wherep, prep, postp);
+ if (*wherep < 0) {
+ p->next = *postp;
+ *postp = p;
+ }
+ else if (*wherep < nb) {
+ p->next = *prep;
+ p->split(*wherep, prep, postp);
+ }
+ else {
+ p->next = *prep;
+ *prep = p;
+ }
+ *wherep -= nb;
+}
+
+void dbreak_node::split(int where, node **prep, node **postp)
+{
+ assert(where >= 0);
+ if (where == 0) {
+ *postp = post;
+ post = 0;
+ if (pre == 0)
+ *prep = next;
+ else {
+ for (node *tem = pre; tem->next != 0; tem = tem->next)
+ ;
+ tem->next = next;
+ *prep = pre;
+ }
+ pre = 0;
+ delete this;
+ }
+ else {
+ *prep = next;
+ where -= 1;
+ node_list_split(none, &where, prep, postp);
+ none = 0;
+ delete this;
+ }
+}
+
+
+hyphenation_type node::get_hyphenation_type()
+{
+ return HYPHEN_BOUNDARY;
+}
+
+
+hyphenation_type dbreak_node::get_hyphenation_type()
+{
+ return HYPHEN_INHIBIT;
+}
+
+hyphenation_type kern_pair_node::get_hyphenation_type()
+{
+ return HYPHEN_MIDDLE;
+}
+
+hyphenation_type dummy_node::get_hyphenation_type()
+{
+ return HYPHEN_MIDDLE;
+}
+
+hyphenation_type transparent_dummy_node::get_hyphenation_type()
+{
+ return HYPHEN_MIDDLE;
+}
+
+int node::interpret(macro *)
+{
+ return 0;
+}
+
+special_node::special_node(const macro &m)
+: mac(m)
+{
+}
+
+int special_node::same(node *n)
+{
+ return mac == ((special_node *)n)->mac;
+}
+
+const char *special_node::type()
+{
+ return "special_node";
+}
+
+node *special_node::copy()
+{
+ return new special_node(mac);
+}
+
+void special_node::tprint_start(troff_output_file *out)
+{
+ out->start_special();
+}
+
+void special_node::tprint_char(troff_output_file *out, unsigned char c)
+{
+ out->special_char(c);
+}
+
+void special_node::tprint_end(troff_output_file *out)
+{
+ out->end_special();
+}
+
+/* composite_node */
+
+class composite_node : public node {
+ charinfo *ci;
+ node *n;
+ tfont *tf;
+public:
+ composite_node(node *, charinfo *, tfont *, node * = 0);
+ ~composite_node();
+ node *copy();
+ hunits width();
+ node *last_char_node();
+ units size();
+ void tprint(troff_output_file *);
+ hyphenation_type get_hyphenation_type();
+ int overlaps_horizontally();
+ int overlaps_vertically();
+ void ascii_print(ascii_output_file *);
+ void asciify(macro *);
+ hyphen_list *get_hyphen_list(hyphen_list *tail);
+ node *add_self(node *, hyphen_list **);
+ tfont *get_tfont();
+ int same(node *);
+ const char *type();
+ void vertical_extent(vunits *, vunits *);
+ vunits vertical_width();
+};
+
+composite_node::composite_node(node *p, charinfo *c, tfont *t, node *x)
+: node(x), n(p), ci(c), tf(t)
+{
+}
+
+composite_node::~composite_node()
+{
+ delete_node_list(n);
+}
+
+node *composite_node::copy()
+{
+ return new composite_node(copy_node_list(n), ci, tf);
+}
+
+hunits composite_node::width()
+{
+ hunits x;
+ if (tf->get_constant_space(&x))
+ return x;
+ x = H0;
+ for (node *tem = n; tem; tem = tem->next)
+ x += tem->width();
+ hunits offset;
+ if (tf->get_bold(&offset))
+ x += offset;
+ x += tf->get_track_kern();
+ return x;
+}
+
+node *composite_node::last_char_node()
+{
+ return this;
+}
+
+vunits composite_node::vertical_width()
+{
+ vunits v = V0;
+ for (node *tem = n; tem; tem = tem->next)
+ v += tem->vertical_width();
+ return v;
+}
+
+units composite_node::size()
+{
+ return tf->get_size().to_units();
+}
+
+hyphenation_type composite_node::get_hyphenation_type()
+{
+ return HYPHEN_MIDDLE;
+}
+
+int composite_node::overlaps_horizontally()
+{
+ return ci->overlaps_horizontally();
+}
+
+int composite_node::overlaps_vertically()
+{
+ return ci->overlaps_vertically();
+}
+
+void composite_node::asciify(macro *m)
+{
+ unsigned char c = ci->get_ascii_code();
+ if (c != 0) {
+ m->append(c);
+ delete this;
+ }
+ else
+ m->append(this);
+}
+
+void composite_node::ascii_print(ascii_output_file *ascii)
+{
+ unsigned char c = ci->get_ascii_code();
+ if (c != 0)
+ ascii->outc(c);
+ else
+ ascii->outs(ci->nm.contents());
+
+}
+
+hyphen_list *composite_node::get_hyphen_list(hyphen_list *tail)
+{
+ return new hyphen_list(ci->get_hyphenation_code(), tail);
+
+}
+
+node *composite_node::add_self(node *nn, hyphen_list **p)
+{
+ assert(ci->get_hyphenation_code() == (*p)->hyphenation_code);
+ next = nn;
+ nn = this;
+ if ((*p)->hyphen)
+ nn = nn->add_discretionary_hyphen();
+ hyphen_list *pp = *p;
+ *p = (*p)->next;
+ delete pp;
+ return nn;
+}
+
+tfont *composite_node::get_tfont()
+{
+ return tf;
+}
+
+node *reverse_node_list(node *n)
+{
+ node *r = 0;
+ while (n) {
+ node *tem = n;
+ n = n->next;
+ tem->next = r;
+ r = tem;
+ }
+ return r;
+}
+
+void composite_node::vertical_extent(vunits *min, vunits *max)
+{
+ n = reverse_node_list(n);
+ node_list_vertical_extent(n, min, max);
+ n = reverse_node_list(n);
+}
+
+word_space_node::word_space_node(hunits d, node *x) : space_node(d, x)
+{
+}
+
+word_space_node::word_space_node(hunits d, int s, node *x)
+: space_node(d, s, x)
+{
+}
+
+node *word_space_node::copy()
+{
+ return new word_space_node(n, set);
+}
+
+void word_space_node::tprint(troff_output_file *out)
+{
+ out->word_marker();
+ space_node::tprint(out);
+}
+
+unbreakable_space_node::unbreakable_space_node(hunits d, node *x)
+: word_space_node(d, x)
+{
+}
+
+unbreakable_space_node::unbreakable_space_node(hunits d, int s, node *x)
+: word_space_node(d, s, x)
+{
+}
+
+node *unbreakable_space_node::copy()
+{
+ return new unbreakable_space_node(n, set);
+}
+
+breakpoint *unbreakable_space_node::get_breakpoints(hunits, int,
+ breakpoint *rest, int)
+{
+ return rest;
+}
+
+int unbreakable_space_node::nbreaks()
+{
+ return 0;
+}
+
+void unbreakable_space_node::split(int, node **, node **)
+{
+ assert(0);
+}
+
+int unbreakable_space_node::merge_space(hunits)
+{
+ return 0;
+}
+
+hvpair::hvpair()
+{
+}
+
+draw_node::draw_node(char c, hvpair *p, int np, font_size s)
+ : code(c), npoints(np), sz(s)
+{
+ point = new hvpair[npoints];
+ for (int i = 0; i < npoints; i++)
+ point[i] = p[i];
+}
+
+int draw_node::same(node *n)
+{
+ draw_node *nd = (draw_node *)n;
+ if (code != nd->code || npoints != nd->npoints || sz != nd->sz)
+ return 0;
+ for (int i = 0; i < npoints; i++)
+ if (point[i].h != nd->point[i].h || point[i].v != nd->point[i].v)
+ return 0;
+ return 1;
+}
+
+const char *draw_node::type()
+{
+ return "draw_node";
+}
+
+draw_node::~draw_node()
+{
+ if (point)
+ a_delete point;
+}
+
+hunits draw_node::width()
+{
+ hunits x = H0;
+ for (int i = 0; i < npoints; i++)
+ x += point[i].h;
+ return x;
+}
+
+vunits draw_node::vertical_width()
+{
+ if (code == 'e')
+ return V0;
+ vunits x = V0;
+ for (int i = 0; i < npoints; i++)
+ x += point[i].v;
+ return x;
+}
+
+node *draw_node::copy()
+{
+ return new draw_node(code, point, npoints, sz);
+}
+
+void draw_node::tprint(troff_output_file *out)
+{
+ out->draw(code, point, npoints, sz);
+}
+
+/* tprint methods */
+
+void glyph_node::tprint(troff_output_file *out)
+{
+ tfont *ptf = tf->get_plain();
+ if (ptf == tf)
+ out->put_char_width(ci, ptf, width(), H0);
+ else {
+ hunits offset;
+ int bold = tf->get_bold(&offset);
+ hunits w = ptf->get_width(ci);
+ hunits k = H0;
+ hunits x;
+ int cs = tf->get_constant_space(&x);
+ if (cs) {
+ x -= w;
+ if (bold)
+ x -= offset;
+ hunits x2 = x/2;
+ out->right(x2);
+ k = x - x2;
+ }
+ else
+ k = tf->get_track_kern();
+ if (bold) {
+ out->put_char(ci, ptf);
+ out->right(offset);
+ }
+ out->put_char_width(ci, ptf, w, k);
+ }
+}
+
+void glyph_node::zero_width_tprint(troff_output_file *out)
+{
+ tfont *ptf = tf->get_plain();
+ hunits offset;
+ int bold = tf->get_bold(&offset);
+ hunits x;
+ int cs = tf->get_constant_space(&x);
+ if (cs) {
+ x -= ptf->get_width(ci);
+ if (bold)
+ x -= offset;
+ x = x/2;
+ out->right(x);
+ }
+ out->put_char(ci, ptf);
+ if (bold) {
+ out->right(offset);
+ out->put_char(ci, ptf);
+ out->right(-offset);
+ }
+ if (cs)
+ out->right(-x);
+}
+
+void break_char_node::tprint(troff_output_file *t)
+{
+ ch->tprint(t);
+}
+
+void break_char_node::zero_width_tprint(troff_output_file *t)
+{
+ ch->zero_width_tprint(t);
+}
+
+void hline_node::tprint(troff_output_file *out)
+{
+ if (x < H0) {
+ out->right(x);
+ x = -x;
+ }
+ if (n == 0) {
+ out->right(x);
+ return;
+ }
+ hunits w = n->width();
+ if (w <= H0) {
+ error("horizontal line drawing character must have positive width");
+ out->right(x);
+ return;
+ }
+ int i = int(x/w);
+ if (i == 0) {
+ hunits xx = x - w;
+ hunits xx2 = xx/2;
+ out->right(xx2);
+ n->tprint(out);
+ out->right(xx - xx2);
+ }
+ else {
+ hunits rem = x - w*i;
+ if (rem > H0)
+ if (n->overlaps_horizontally()) {
+ n->tprint(out);
+ out->right(rem - w);
+ }
+ else
+ out->right(rem);
+ while (--i >= 0)
+ n->tprint(out);
+ }
+}
+
+void vline_node::tprint(troff_output_file *out)
+{
+ if (n == 0) {
+ out->down(x);
+ return;
+ }
+ vunits h = n->size();
+ int overlaps = n->overlaps_vertically();
+ vunits y = x;
+ if (y < V0) {
+ y = -y;
+ int i = y / h;
+ vunits rem = y - i*h;
+ if (i == 0) {
+ out->right(n->width());
+ out->down(-rem);
+ }
+ else {
+ while (--i > 0) {
+ n->zero_width_tprint(out);
+ out->down(-h);
+ }
+ if (overlaps) {
+ n->zero_width_tprint(out);
+ out->down(-rem);
+ n->tprint(out);
+ out->down(-h);
+ }
+ else {
+ n->tprint(out);
+ out->down(-h - rem);
+ }
+ }
+ }
+ else {
+ int i = y / h;
+ vunits rem = y - i*h;
+ if (i == 0) {
+ out->down(rem);
+ out->right(n->width());
+ }
+ else {
+ out->down(h);
+ if (overlaps)
+ n->zero_width_tprint(out);
+ out->down(rem);
+ while (--i > 0) {
+ n->zero_width_tprint(out);
+ out->down(h);
+ }
+ n->tprint(out);
+ }
+ }
+}
+
+void zero_width_node::tprint(troff_output_file *out)
+{
+ if (!n)
+ return;
+ if (!n->next) {
+ n->zero_width_tprint(out);
+ return;
+ }
+ int hpos = out->get_hpos();
+ int vpos = out->get_vpos();
+ node *tem = n;
+ while (tem) {
+ tem->tprint(out);
+ tem = tem->next;
+ }
+ out->moveto(hpos, vpos);
+}
+
+void overstrike_node::tprint(troff_output_file *out)
+{
+ hunits pos = H0;
+ for (node *tem = list; tem; tem = tem->next) {
+ hunits x = (max_width - tem->width())/2;
+ out->right(x - pos);
+ pos = x;
+ tem->zero_width_tprint(out);
+ }
+ out->right(max_width - pos);
+}
+
+void bracket_node::tprint(troff_output_file *out)
+{
+ if (list == 0)
+ return;
+ int npieces = 0;
+ for (node *tem = list; tem; tem = tem->next)
+ ++npieces;
+ vunits h = list->size();
+ vunits totalh = h*npieces;
+ vunits y = (totalh - h)/2;
+ out->down(y);
+ for (tem = list; tem; tem = tem->next) {
+ tem->zero_width_tprint(out);
+ out->down(-h);
+ }
+ out->right(max_width);
+ out->down(totalh - y);
+}
+
+void node::tprint(troff_output_file *)
+{
+}
+
+void node::zero_width_tprint(troff_output_file *out)
+{
+ int hpos = out->get_hpos();
+ int vpos = out->get_vpos();
+ tprint(out);
+ out->moveto(hpos, vpos);
+}
+
+void space_node::tprint(troff_output_file *out)
+{
+ out->right(n);
+}
+
+void hmotion_node::tprint(troff_output_file *out)
+{
+ out->right(n);
+}
+
+void vmotion_node::tprint(troff_output_file *out)
+{
+ out->down(n);
+}
+
+void kern_pair_node::tprint(troff_output_file *out)
+{
+ n1->tprint(out);
+ out->right(amount);
+ n2->tprint(out);
+}
+
+static void tprint_reverse_node_list(troff_output_file *out, node *n)
+{
+ if (n == 0)
+ return;
+ tprint_reverse_node_list(out, n->next);
+ n->tprint(out);
+}
+
+void dbreak_node::tprint(troff_output_file *out)
+{
+ tprint_reverse_node_list(out, none);
+}
+
+void composite_node::tprint(troff_output_file *out)
+{
+ hunits bold_offset;
+ int is_bold = tf->get_bold(&bold_offset);
+ hunits track_kern = tf->get_track_kern();
+ hunits constant_space;
+ int is_constant_spaced = tf->get_constant_space(&constant_space);
+ hunits x = H0;
+ if (is_constant_spaced) {
+ x = constant_space;
+ for (node *tem = n; tem; tem = tem->next)
+ x -= tem->width();
+ if (is_bold)
+ x -= bold_offset;
+ hunits x2 = x/2;
+ out->right(x2);
+ x -= x2;
+ }
+ if (is_bold) {
+ int hpos = out->get_hpos();
+ int vpos = out->get_vpos();
+ tprint_reverse_node_list(out, n);
+ out->moveto(hpos, vpos);
+ out->right(bold_offset);
+ }
+ tprint_reverse_node_list(out, n);
+ if (is_constant_spaced)
+ out->right(x);
+ else
+ out->right(track_kern);
+}
+
+node *make_composite_node(charinfo *s, environment *env)
+{
+ int fontno = env_definite_font(env);
+ if (fontno < 0) {
+ error("no current font");
+ return 0;
+ }
+ assert(fontno < font_table_size && font_table[fontno] != 0);
+ node *n = charinfo_to_node_list(s, env);
+ font_size fs = env->get_font_size();
+ int char_height = env->get_char_height();
+ int char_slant = env->get_char_slant();
+ tfont *tf = font_table[fontno]->get_tfont(fs, char_height, char_slant,
+ fontno);
+ if (env->is_composite())
+ tf = tf->get_plain();
+ return new composite_node(n, s, tf);
+}
+
+node *make_glyph_node(charinfo *s, environment *env, int no_error_message = 0)
+{
+ int fontno = env_definite_font(env);
+ if (fontno < 0) {
+ error("no current font");
+ return 0;
+ }
+ assert(fontno < font_table_size && font_table[fontno] != 0);
+ int fn = fontno;
+ int found = font_table[fontno]->contains(s);
+ if (!found) {
+ if (s->numbered()) {
+ if (!no_error_message)
+ warning(WARN_CHAR, "can't find numbered character %1",
+ s->get_number());
+ return 0;
+ }
+ special_font_list *sf = font_table[fontno]->sf;
+ while (sf != 0 && !found) {
+ fn = sf->n;
+ if (font_table[fn])
+ found = font_table[fn]->contains(s);
+ sf = sf->next;
+ }
+ if (!found) {
+ sf = global_special_fonts;
+ while (sf != 0 && !found) {
+ fn = sf->n;
+ if (font_table[fn])
+ found = font_table[fn]->contains(s);
+ sf = sf->next;
+ }
+ }
+ if (!found
+#if 0
+ && global_special_fonts == 0 && font_table[fontno]->sf == 0
+#endif
+ ) {
+ for (fn = 0; fn < font_table_size; fn++)
+ if (font_table[fn]
+ && font_table[fn]->is_special()
+ && font_table[fn]->contains(s)) {
+ found = 1;
+ break;
+ }
+ }
+ if (!found) {
+ if (!no_error_message && s->first_time_not_found()) {
+ unsigned char input_code = s->get_ascii_code();
+ if (input_code != 0) {
+ if (csgraph(input_code))
+ warning(WARN_CHAR, "can't find character `%1'", input_code);
+ else
+ warning(WARN_CHAR, "can't find character with input code %1",
+ int(input_code));
+ }
+ else
+ warning(WARN_CHAR, "can't find special character `%1'",
+ s->nm.contents());
+ }
+ return 0;
+ }
+ }
+ font_size fs = env->get_font_size();
+ int char_height = env->get_char_height();
+ int char_slant = env->get_char_slant();
+ tfont *tf = font_table[fontno]->get_tfont(fs, char_height, char_slant, fn);
+ if (env->is_composite())
+ tf = tf->get_plain();
+ return new glyph_node(s, tf);
+}
+
+node *make_node(charinfo *ci, environment *env)
+{
+ switch (ci->get_special_translation()) {
+ case charinfo::TRANSLATE_SPACE:
+ return new space_char_hmotion_node(env->get_space_width());
+ case charinfo::TRANSLATE_DUMMY:
+ return new dummy_node;
+ case charinfo::TRANSLATE_HYPHEN_INDICATOR:
+ error("translation to \\% ignored in this context");
+ break;
+ }
+ charinfo *tem = ci->get_translation();
+ if (tem)
+ ci = tem;
+ macro *mac = ci->get_macro();
+ if (mac)
+ return make_composite_node(ci, env);
+ else
+ return make_glyph_node(ci, env);
+}
+
+int character_exists(charinfo *ci, environment *env)
+{
+ if (ci->get_special_translation() != charinfo::TRANSLATE_NONE)
+ return 1;
+ charinfo *tem = ci->get_translation();
+ if (tem)
+ ci = tem;
+ if (ci->get_macro())
+ return 1;
+ node *nd = make_glyph_node(ci, env, 1);
+ if (nd) {
+ delete nd;
+ return 1;
+ }
+ return 0;
+}
+
+node *node::add_char(charinfo *ci, environment *env, hunits *widthp)
+{
+ node *res;
+ switch (ci->get_special_translation()) {
+ case charinfo::TRANSLATE_SPACE:
+ res = new space_char_hmotion_node(env->get_space_width(), this);
+ *widthp += res->width();
+ return res;
+ case charinfo::TRANSLATE_DUMMY:
+ return new dummy_node(this);
+ case charinfo::TRANSLATE_HYPHEN_INDICATOR:
+ return add_discretionary_hyphen();
+ }
+ charinfo *tem = ci->get_translation();
+ if (tem)
+ ci = tem;
+ macro *mac = ci->get_macro();
+ if (mac) {
+ res = make_composite_node(ci, env);
+ if (res) {
+ res->next = this;
+ *widthp += res->width();
+ }
+ else
+ return this;
+ }
+ else {
+ node *gn = make_glyph_node(ci, env);
+ if (gn == 0)
+ return this;
+ else {
+ hunits old_width = width();
+ node *p = gn->merge_self(this);
+ if (p == 0) {
+ *widthp += gn->width();
+ gn->next = this;
+ res = gn;
+ }
+ else {
+ *widthp += p->width() - old_width;
+ res = p;
+ }
+ }
+ }
+ int break_code = 0;
+ if (ci->can_break_before())
+ break_code = 1;
+ if (ci->can_break_after())
+ break_code |= 2;
+ if (break_code) {
+ node *next1 = res->next;
+ res->next = 0;
+ res = new break_char_node(res, break_code, next1);
+ }
+ return res;
+}
+
+
+#ifdef __GNUG__
+inline
+#endif
+int same_node(node *n1, node *n2)
+{
+ if (n1 != 0) {
+ if (n2 != 0)
+ return n1->type() == n2->type() && n1->same(n2);
+ else
+ return 0;
+ }
+ else
+ return n2 == 0;
+}
+
+int same_node_list(node *n1, node *n2)
+{
+ while (n1 && n2) {
+ if (n1->type() != n2->type() || !n1->same(n2))
+ return 0;
+ n1 = n1->next;
+ n2 = n2->next;
+ }
+ return !n1 && !n2;
+}
+
+int extra_size_node::same(node *nd)
+{
+ return n == ((extra_size_node *)nd)->n;
+}
+
+const char *extra_size_node::type()
+{
+ return "extra_size_node";
+}
+
+int vertical_size_node::same(node *nd)
+{
+ return n == ((vertical_size_node *)nd)->n;
+}
+
+const char *vertical_size_node::type()
+{
+ return "vertical_size_node";
+}
+
+int hmotion_node::same(node *nd)
+{
+ return n == ((hmotion_node *)nd)->n;
+}
+
+const char *hmotion_node::type()
+{
+ return "hmotion_node";
+}
+
+int space_char_hmotion_node::same(node *nd)
+{
+ return n == ((space_char_hmotion_node *)nd)->n;
+}
+
+const char *space_char_hmotion_node::type()
+{
+ return "space_char_hmotion_node";
+}
+
+int vmotion_node::same(node *nd)
+{
+ return n == ((vmotion_node *)nd)->n;
+}
+
+const char *vmotion_node::type()
+{
+ return "vmotion_node";
+}
+
+int hline_node::same(node *nd)
+{
+ return x == ((hline_node *)nd)->x && same_node(n, ((hline_node *)nd)->n);
+}
+
+const char *hline_node::type()
+{
+ return "hline_node";
+}
+
+int vline_node::same(node *nd)
+{
+ return x == ((vline_node *)nd)->x && same_node(n, ((vline_node *)nd)->n);
+}
+
+const char *vline_node::type()
+{
+ return "vline_node";
+}
+
+int dummy_node::same(node * /*nd*/)
+{
+ return 1;
+}
+
+const char *dummy_node::type()
+{
+ return "dummy_node";
+}
+
+int transparent_dummy_node::same(node * /*nd*/)
+{
+ return 1;
+}
+
+const char *transparent_dummy_node::type()
+{
+ return "transparent_dummy_node";
+}
+
+int transparent_dummy_node::ends_sentence()
+{
+ return 2;
+}
+
+int zero_width_node::same(node *nd)
+{
+ return same_node_list(n, ((zero_width_node *)nd)->n);
+}
+
+const char *zero_width_node::type()
+{
+ return "zero_width_node";
+}
+
+int italic_corrected_node::same(node *nd)
+{
+ return (x == ((italic_corrected_node *)nd)->x
+ && same_node(n, ((italic_corrected_node *)nd)->n));
+}
+
+const char *italic_corrected_node::type()
+{
+ return "italic_corrected_node";
+}
+
+
+left_italic_corrected_node::left_italic_corrected_node(node *x)
+: n(0), node(x)
+{
+}
+
+left_italic_corrected_node::~left_italic_corrected_node()
+{
+ delete n;
+}
+
+node *left_italic_corrected_node::merge_glyph_node(glyph_node *gn)
+{
+ if (n == 0) {
+ hunits lic = gn->left_italic_correction();
+ if (!lic.is_zero()) {
+ x = lic;
+ n = gn;
+ return this;
+ }
+ }
+ else {
+ node *nd = n->merge_glyph_node(gn);
+ if (nd) {
+ n = nd;
+ x = n->left_italic_correction();
+ return this;
+ }
+ }
+ return 0;
+}
+
+node *left_italic_corrected_node::copy()
+{
+ left_italic_corrected_node *nd = new left_italic_corrected_node;
+ if (n) {
+ nd->n = n->copy();
+ nd->x = x;
+ }
+ return nd;
+}
+
+void left_italic_corrected_node::tprint(troff_output_file *out)
+{
+ if (n) {
+ out->right(x);
+ n->tprint(out);
+ }
+}
+
+const char *left_italic_corrected_node::type()
+{
+ return "left_italic_corrected_node";
+}
+
+int left_italic_corrected_node::same(node *nd)
+{
+ return (x == ((left_italic_corrected_node *)nd)->x
+ && same_node(n, ((left_italic_corrected_node *)nd)->n));
+}
+
+void left_italic_corrected_node::ascii_print(ascii_output_file *out)
+{
+ if (n)
+ n->ascii_print(out);
+}
+
+hunits left_italic_corrected_node::width()
+{
+ return n ? n->width() + x : H0;
+}
+
+void left_italic_corrected_node::vertical_extent(vunits *min, vunits *max)
+{
+ if (n)
+ n->vertical_extent(min, max);
+ else
+ node::vertical_extent(min, max);
+}
+
+hunits left_italic_corrected_node::skew()
+{
+ return n ? n->skew() + x/2 : H0;
+}
+
+hunits left_italic_corrected_node::subscript_correction()
+{
+ return n ? n->subscript_correction() : H0;
+}
+
+hunits left_italic_corrected_node::italic_correction()
+{
+ return n ? n->italic_correction() : H0;
+}
+
+int left_italic_corrected_node::ends_sentence()
+{
+ return n ? n->ends_sentence() : 0;
+}
+
+int left_italic_corrected_node::overlaps_horizontally()
+{
+ return n ? n->overlaps_horizontally() : 0;
+}
+
+int left_italic_corrected_node::overlaps_vertically()
+{
+ return n ? n->overlaps_vertically() : 0;
+}
+
+node *left_italic_corrected_node::last_char_node()
+{
+ return n ? n->last_char_node() : 0;
+}
+
+tfont *left_italic_corrected_node::get_tfont()
+{
+ return n ? n->get_tfont() : 0;
+}
+
+hyphenation_type left_italic_corrected_node::get_hyphenation_type()
+{
+ if (n)
+ return n->get_hyphenation_type();
+ else
+ return HYPHEN_MIDDLE;
+}
+
+hyphen_list *left_italic_corrected_node::get_hyphen_list(hyphen_list *tail)
+{
+ return n ? n->get_hyphen_list(tail) : tail;
+}
+
+node *left_italic_corrected_node::add_self(node *nd, hyphen_list **p)
+{
+ if (n) {
+ nd = new left_italic_corrected_node(nd);
+ nd = n->add_self(nd, p);
+ n = 0;
+ delete this;
+ }
+ return nd;
+}
+
+int left_italic_corrected_node::character_type()
+{
+ return n ? n->character_type() : 0;
+}
+
+int overstrike_node::same(node *nd)
+{
+ return same_node_list(list, ((overstrike_node *)nd)->list);
+}
+
+const char *overstrike_node::type()
+{
+ return "overstrike_node";
+}
+
+int bracket_node::same(node *nd)
+{
+ return same_node_list(list, ((bracket_node *)nd)->list);
+}
+
+const char *bracket_node::type()
+{
+ return "bracket_node";
+}
+
+int composite_node::same(node *nd)
+{
+ return ci == ((composite_node *)nd)->ci
+ && same_node_list(n, ((composite_node *)nd)->n);
+}
+
+const char *composite_node::type()
+{
+ return "composite_node";
+}
+
+int glyph_node::same(node *nd)
+{
+ return ci == ((glyph_node *)nd)->ci && tf == ((glyph_node *)nd)->tf;
+}
+
+const char *glyph_node::type()
+{
+ return "glyph_node";
+}
+
+int ligature_node::same(node *nd)
+{
+ return (same_node(n1, ((ligature_node *)nd)->n1)
+ && same_node(n2, ((ligature_node *)nd)->n2)
+ && glyph_node::same(nd));
+}
+
+const char *ligature_node::type()
+{
+ return "ligature_node";
+}
+
+int kern_pair_node::same(node *nd)
+{
+ return (amount == ((kern_pair_node *)nd)->amount
+ && same_node(n1, ((kern_pair_node *)nd)->n1)
+ && same_node(n2, ((kern_pair_node *)nd)->n2));
+}
+
+const char *kern_pair_node::type()
+{
+ return "kern_pair_node";
+}
+
+int dbreak_node::same(node *nd)
+{
+ return (same_node_list(none, ((dbreak_node *)nd)->none)
+ && same_node_list(pre, ((dbreak_node *)nd)->pre)
+ && same_node_list(post, ((dbreak_node *)nd)->post));
+}
+
+const char *dbreak_node::type()
+{
+ return "dbreak_node";
+}
+
+int break_char_node::same(node *nd)
+{
+ return (break_code == ((break_char_node *)nd)->break_code
+ && same_node(ch, ((break_char_node *)nd)->ch));
+}
+
+const char *break_char_node::type()
+{
+ return "break_char_node";
+}
+
+int line_start_node::same(node * /*nd*/)
+{
+ return 1;
+}
+
+const char *line_start_node::type()
+{
+ return "line_start_node";
+}
+
+int space_node::same(node *nd)
+{
+ return n == ((space_node *)nd)->n && set == ((space_node *)nd)->set;
+}
+
+const char *space_node::type()
+{
+ return "space_node";
+}
+
+int word_space_node::same(node *nd)
+{
+ return (n == ((word_space_node *)nd)->n
+ && set == ((word_space_node *)nd)->set);
+}
+
+const char *word_space_node::type()
+{
+ return "word_space_node";
+}
+
+int unbreakable_space_node::same(node *nd)
+{
+ return (n == ((unbreakable_space_node *)nd)->n
+ && set == ((unbreakable_space_node *)nd)->set);
+}
+
+const char *unbreakable_space_node::type()
+{
+ return "unbreakable_space_node";
+}
+
+int diverted_space_node::same(node *nd)
+{
+ return n == ((diverted_space_node *)nd)->n;
+}
+
+const char *diverted_space_node::type()
+{
+ return "diverted_space_node";
+}
+
+int diverted_copy_file_node::same(node *nd)
+{
+ return filename == ((diverted_copy_file_node *)nd)->filename;
+}
+
+const char *diverted_copy_file_node::type()
+{
+ return "diverted_copy_file_node";
+}
+
+// Grow the font_table so that its size is > n.
+
+static void grow_font_table(int n)
+{
+ assert(n >= font_table_size);
+ font_info **old_font_table = font_table;
+ int old_font_table_size = font_table_size;
+ font_table_size = font_table_size ? (font_table_size*3)/2 : 10;
+ if (font_table_size <= n)
+ font_table_size = n + 10;
+ font_table = new font_info *[font_table_size];
+ if (old_font_table_size)
+ memcpy(font_table, old_font_table,
+ old_font_table_size*sizeof(font_info *));
+ a_delete old_font_table;
+ for (int i = old_font_table_size; i < font_table_size; i++)
+ font_table[i] = 0;
+}
+
+dictionary font_translation_dictionary(17);
+
+static symbol get_font_translation(symbol nm)
+{
+ void *p = font_translation_dictionary.lookup(nm);
+ return p ? symbol((char *)p) : nm;
+}
+
+dictionary font_dictionary(50);
+
+static int mount_font_no_translate(int n, symbol name, symbol external_name)
+{
+ assert(n >= 0);
+ // We store the address of this char in font_dictionary to indicate
+ // that we've previously tried to mount the font and failed.
+ static char a_char;
+ font *fm = 0;
+ void *p = font_dictionary.lookup(external_name);
+ if (p == 0) {
+ int not_found;
+ fm = font::load_font(external_name.contents(), &not_found);
+ if (!fm) {
+ if (not_found)
+ warning(WARN_FONT, "can't find font `%1'", external_name.contents());
+ font_dictionary.lookup(external_name, &a_char);
+ return 0;
+ }
+ font_dictionary.lookup(name, fm);
+ }
+ else if (p == &a_char) {
+#if 0
+ error("invalid font `%1'", external_name.contents());
+#endif
+ return 0;
+ }
+ else
+ fm = (font*)p;
+ if (n >= font_table_size) {
+ if (n - font_table_size > 1000) {
+ error("font position too much larger than first unused position");
+ return 0;
+ }
+ grow_font_table(n);
+ }
+ else if (font_table[n] != 0)
+ delete font_table[n];
+ font_table[n] = new font_info(name, n, external_name, fm);
+ font_family::invalidate_fontno(n);
+ return 1;
+}
+
+int mount_font(int n, symbol name, symbol external_name)
+{
+ assert(n >= 0);
+ name = get_font_translation(name);
+ if (external_name.is_null())
+ external_name = name;
+ else
+ external_name = get_font_translation(external_name);
+ return mount_font_no_translate(n, name, external_name);
+}
+
+void mount_style(int n, symbol name)
+{
+ assert(n >= 0);
+ if (n >= font_table_size) {
+ if (n - font_table_size > 1000) {
+ error("font position too much larger than first unused position");
+ return;
+ }
+ grow_font_table(n);
+ }
+ else if (font_table[n] != 0)
+ delete font_table[n];
+ font_table[n] = new font_info(get_font_translation(name), n, NULL_SYMBOL, 0);
+ font_family::invalidate_fontno(n);
+}
+
+/* global functions */
+
+void font_translate()
+{
+ symbol from = get_name(1);
+ if (!from.is_null()) {
+ symbol to = get_name();
+ if (to.is_null() || from == to)
+ font_translation_dictionary.remove(from);
+ else
+ font_translation_dictionary.lookup(from, (void *)to.contents());
+ }
+ skip_line();
+}
+
+void font_position()
+{
+ int n;
+ if (get_integer(&n)) {
+ if (n < 0)
+ error("negative font position");
+ else {
+ symbol internal_name = get_name(1);
+ if (!internal_name.is_null()) {
+ symbol external_name = get_long_name(0);
+ mount_font(n, internal_name, external_name); // ignore error
+ }
+ }
+ }
+ skip_line();
+}
+
+font_family::font_family(symbol s)
+: nm(s), map_size(10)
+{
+ map = new int[map_size];
+ for (int i = 0; i < map_size; i++)
+ map[i] = -1;
+}
+
+font_family::~font_family()
+{
+ a_delete map;
+}
+
+int font_family::make_definite(int i)
+{
+ if (i >= 0) {
+ if (i < map_size && map[i] >= 0)
+ return map[i];
+ else {
+ if (i < font_table_size && font_table[i] != 0) {
+ if (i >= map_size) {
+ int old_map_size = map_size;
+ int *old_map = map;
+ map_size *= 3;
+ map_size /= 2;
+ if (i >= map_size)
+ map_size = i + 10;
+ map = new int[map_size];
+ memcpy(map, old_map, old_map_size*sizeof(int));
+ a_delete old_map;
+ for (int j = old_map_size; j < map_size; j++)
+ map[j] = -1;
+ }
+ if (font_table[i]->is_style()) {
+ symbol sty = font_table[i]->get_name();
+ symbol f = concat(nm, sty);
+ int n;
+ // don't use symbol_fontno, because that might return a style
+ // and because we don't want to translate the name
+ for (n = 0; n < font_table_size; n++)
+ if (font_table[n] != 0 && font_table[n]->is_named(f)
+ && !font_table[n]->is_style())
+ break;
+ if (n >= font_table_size) {
+ n = next_available_font_position();
+ if (!mount_font_no_translate(n, f, f))
+ return -1;
+ }
+ return map[i] = n;
+ }
+ else
+ return map[i] = i;
+ }
+ else
+ return -1;
+ }
+ }
+ else
+ return -1;
+}
+
+dictionary family_dictionary(5);
+
+font_family *lookup_family(symbol nm)
+{
+ font_family *f = (font_family *)family_dictionary.lookup(nm);
+ if (!f) {
+ f = new font_family(nm);
+ (void)family_dictionary.lookup(nm, f);
+ }
+ return f;
+}
+
+void font_family::invalidate_fontno(int n)
+{
+ assert(n >= 0 && n < font_table_size);
+ dictionary_iterator iter(family_dictionary);
+ symbol nm;
+ font_family *fam;
+ while (iter.get(&nm, (void **)&fam)) {
+ int map_size = fam->map_size;
+ if (n < map_size)
+ fam->map[n] = -1;
+ for (int i = 0; i < map_size; i++)
+ if (fam->map[i] == n)
+ fam->map[i] = -1;
+ }
+}
+
+void style()
+{
+ int n;
+ if (get_integer(&n)) {
+ if (n < 0)
+ error("negative font position");
+ else {
+ symbol internal_name = get_name(1);
+ if (!internal_name.is_null())
+ mount_style(n, internal_name);
+ }
+ }
+ skip_line();
+}
+
+static int get_fontno()
+{
+ int n;
+ tok.skip();
+ if (tok.delimiter()) {
+ symbol s = get_name(1);
+ if (!s.is_null()) {
+ n = symbol_fontno(s);
+ if (n < 0) {
+ n = next_available_font_position();
+ if (!mount_font(n, s))
+ return -1;
+ }
+ return curenv->get_family()->make_definite(n);
+ }
+ }
+ else if (get_integer(&n)) {
+ if (n < 0 || n >= font_table_size || font_table[n] == 0)
+ error("bad font number");
+ else
+ return curenv->get_family()->make_definite(n);
+ }
+ return -1;
+}
+
+static int underline_fontno = 2;
+
+void underline_font()
+{
+ int n = get_fontno();
+ if (n >= 0)
+ underline_fontno = n;
+ skip_line();
+}
+
+int get_underline_fontno()
+{
+ return underline_fontno;
+}
+
+static void read_special_fonts(special_font_list **sp)
+{
+ special_font_list *s = *sp;
+ *sp = 0;
+ while (s != 0) {
+ special_font_list *tem = s;
+ s = s->next;
+ delete tem;
+ }
+ special_font_list **p = sp;
+ while (has_arg()) {
+ int i = get_fontno();
+ if (i >= 0) {
+ special_font_list *tem = new special_font_list;
+ tem->n = i;
+ tem->next = 0;
+ *p = tem;
+ p = &(tem->next);
+ }
+ }
+}
+
+void font_special_request()
+{
+ int n = get_fontno();
+ if (n >= 0)
+ read_special_fonts(&font_table[n]->sf);
+ skip_line();
+}
+
+
+void special_request()
+{
+ read_special_fonts(&global_special_fonts);
+ skip_line();
+}
+
+int next_available_font_position()
+{
+ for (int i = 1; i < font_table_size && font_table[i] != 0; i++)
+ ;
+ return i;
+}
+
+int symbol_fontno(symbol s)
+{
+ s = get_font_translation(s);
+ for (int i = 0; i < font_table_size; i++)
+ if (font_table[i] != 0 && font_table[i]->is_named(s))
+ return i;
+ return -1;
+}
+
+int is_good_fontno(int n)
+{
+ return n >= 0 && n < font_table_size && font_table[n] != NULL;
+}
+
+int get_bold_fontno(int n)
+{
+ if (n >= 0 && n < font_table_size && font_table[n] != 0) {
+ hunits offset;
+ if (font_table[n]->get_bold(&offset))
+ return offset.to_units() + 1;
+ else
+ return 0;
+ }
+ else
+ return 0;
+}
+
+hunits env_digit_width(environment *env)
+{
+ node *n = make_glyph_node(charset_table['0'], env);
+ if (n) {
+ hunits x = n->width();
+ delete n;
+ return x;
+ }
+ else
+ return H0;
+}
+
+hunits env_space_width(environment *env)
+{
+ int fn = env_definite_font(env);
+ font_size fs = env->get_font_size();
+ if (fn < 0 || fn >= font_table_size || font_table[fn] == 0)
+ return scale(fs.to_units()/3, env->get_space_size(), 12);
+ else
+ return font_table[fn]->get_space_width(fs, env->get_space_size());
+}
+
+hunits env_sentence_space_width(environment *env)
+{
+ int fn = env_definite_font(env);
+ font_size fs = env->get_font_size();
+ if (fn < 0 || fn >= font_table_size || font_table[fn] == 0)
+ return scale(fs.to_units()/3, env->get_sentence_space_size(), 12);
+ else
+ return font_table[fn]->get_space_width(fs, env->get_sentence_space_size());
+}
+
+hunits env_half_narrow_space_width(environment *env)
+{
+ int fn = env_definite_font(env);
+ font_size fs = env->get_font_size();
+ if (fn < 0 || fn >= font_table_size || font_table[fn] == 0)
+ return 0;
+ else
+ return font_table[fn]->get_half_narrow_space_width(fs);
+}
+
+hunits env_narrow_space_width(environment *env)
+{
+ int fn = env_definite_font(env);
+ font_size fs = env->get_font_size();
+ if (fn < 0 || fn >= font_table_size || font_table[fn] == 0)
+ return 0;
+ else
+ return font_table[fn]->get_narrow_space_width(fs);
+}
+
+void bold_font()
+{
+ int n = get_fontno();
+ if (n >= 0) {
+ if (has_arg()) {
+ if (tok.delimiter()) {
+ int f = get_fontno();
+ if (f >= 0) {
+ units offset;
+ if (has_arg() && get_number(&offset, 'u') && offset >= 1)
+ font_table[f]->set_conditional_bold(n, hunits(offset - 1));
+ else
+ font_table[f]->conditional_unbold(n);
+ }
+ }
+ else {
+ units offset;
+ if (get_number(&offset, 'u') && offset >= 1)
+ font_table[n]->set_bold(hunits(offset - 1));
+ else
+ font_table[n]->unbold();
+ }
+ }
+ else
+ font_table[n]->unbold();
+ }
+ skip_line();
+}
+
+track_kerning_function::track_kerning_function() : non_zero(0)
+{
+}
+
+track_kerning_function::track_kerning_function(int min_s, hunits min_a,
+ int max_s, hunits max_a)
+ : non_zero(1),
+ min_size(min_s), min_amount(min_a),
+ max_size(max_s), max_amount(max_a)
+{
+}
+
+int track_kerning_function::operator==(const track_kerning_function &tk)
+{
+ if (non_zero)
+ return (tk.non_zero
+ && min_size == tk.min_size
+ && min_amount == tk.min_amount
+ && max_size == tk.max_size
+ && max_amount == tk.max_amount);
+ else
+ return !tk.non_zero;
+}
+
+int track_kerning_function::operator!=(const track_kerning_function &tk)
+{
+ if (non_zero)
+ return (!tk.non_zero
+ || min_size != tk.min_size
+ || min_amount != tk.min_amount
+ || max_size != tk.max_size
+ || max_amount != tk.max_amount);
+ else
+ return tk.non_zero;
+}
+
+hunits track_kerning_function::compute(int size)
+{
+ if (non_zero) {
+ if (max_size <= min_size)
+ return min_amount;
+ else if (size <= min_size)
+ return min_amount;
+ else if (size >= max_size)
+ return max_amount;
+ else
+ return (scale(max_amount, size - min_size, max_size - min_size)
+ + scale(min_amount, max_size - size, max_size - min_size));
+ }
+ else
+ return H0;
+}
+
+void track_kern()
+{
+ int n = get_fontno();
+ if (n >= 0) {
+ int min_s, max_s;
+ hunits min_a, max_a;
+ if (has_arg()
+ && get_number(&min_s, 'z')
+ && get_hunits(&min_a, 'p')
+ && get_number(&max_s, 'z')
+ && get_hunits(&max_a, 'p')) {
+ track_kerning_function tk(min_s, min_a, max_s, max_a);
+ font_table[n]->set_track_kern(tk);
+ }
+ else {
+ track_kerning_function tk;
+ font_table[n]->set_track_kern(tk);
+ }
+ }
+ skip_line();
+}
+
+void constant_space()
+{
+ int n = get_fontno();
+ if (n >= 0) {
+ int x, y;
+ if (!has_arg() || !get_integer(&x))
+ font_table[n]->set_constant_space(CONSTANT_SPACE_NONE);
+ else {
+ if (!has_arg() || !get_number(&y, 'z'))
+ font_table[n]->set_constant_space(CONSTANT_SPACE_RELATIVE, x);
+ else
+ font_table[n]->set_constant_space(CONSTANT_SPACE_ABSOLUTE,
+ scale(y*x,
+ units_per_inch,
+ 36*72*sizescale));
+ }
+ }
+ skip_line();
+}
+
+void ligature()
+{
+ int lig;
+ if (has_arg() && get_integer(&lig) && lig >= 0 && lig <= 2)
+ global_ligature_mode = lig;
+ else
+ global_ligature_mode = 1;
+ skip_line();
+}
+
+void kern_request()
+{
+ int k;
+ if (has_arg() && get_integer(&k))
+ global_kern_mode = k != 0;
+ else
+ global_kern_mode = 1;
+ skip_line();
+}
+
+void set_soft_hyphen_char()
+{
+ soft_hyphen_char = get_optional_char();
+ if (!soft_hyphen_char)
+ soft_hyphen_char = get_charinfo(HYPHEN_SYMBOL);
+ skip_line();
+}
+
+void init_output()
+{
+ if (suppress_output_flag)
+ the_output = new suppress_output_file;
+ else if (ascii_output_flag)
+ the_output = new ascii_output_file;
+ else
+ the_output = new troff_output_file;
+}
+
+class next_available_font_position_reg : public reg {
+public:
+ const char *get_string();
+};
+
+const char *next_available_font_position_reg::get_string()
+{
+ return itoa(next_available_font_position());
+}
+
+class printing_reg : public reg {
+public:
+ const char *get_string();
+};
+
+const char *printing_reg::get_string()
+{
+ if (the_output)
+ return the_output->is_printing() ? "1" : "0";
+ else
+ return "0";
+}
+
+void init_node_requests()
+{
+ init_request("fp", font_position);
+ init_request("sty", style);
+ init_request("cs", constant_space);
+ init_request("bd", bold_font);
+ init_request("uf", underline_font);
+ init_request("lg", ligature);
+ init_request("kern", kern_request);
+ init_request("tkf", track_kern);
+ init_request("special", special_request);
+ init_request("fspecial", font_special_request);
+ init_request("ftr", font_translate);
+ init_request("shc", set_soft_hyphen_char);
+ number_reg_dictionary.define(".fp", new next_available_font_position_reg);
+ number_reg_dictionary.define(".kern",
+ new constant_int_reg(&global_kern_mode));
+ number_reg_dictionary.define(".lg",
+ new constant_int_reg(&global_ligature_mode));
+ number_reg_dictionary.define(".P", new printing_reg);
+ soft_hyphen_char = get_charinfo(HYPHEN_SYMBOL);
+}
diff --git a/gnu/usr.bin/groff/troff/node.h b/gnu/usr.bin/groff/troff/node.h
new file mode 100644
index 0000000..0ab9c9f
--- /dev/null
+++ b/gnu/usr.bin/groff/troff/node.h
@@ -0,0 +1,493 @@
+// -*- C++ -*-
+/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
+ Written by James Clark (jjc@jclark.com)
+
+This file is part of groff.
+
+groff is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
+
+groff is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License along
+with groff; see the file COPYING. If not, write to the Free Software
+Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+
+struct hyphen_list {
+ unsigned char hyphen;
+ unsigned char breakable;
+ unsigned char hyphenation_code;
+ hyphen_list *next;
+ hyphen_list(unsigned char code, hyphen_list *p = 0);
+};
+
+void hyphenate(hyphen_list *, unsigned);
+
+enum hyphenation_type { HYPHEN_MIDDLE, HYPHEN_BOUNDARY, HYPHEN_INHIBIT };
+
+class ascii_output_file;
+
+struct breakpoint;
+struct vertical_size;
+struct charinfo;
+
+class macro;
+
+class troff_output_file;
+class tfont;
+class environment;
+
+class glyph_node;
+class diverted_space_node;
+class token_node;
+
+struct node {
+ node *next;
+ node();
+ node(node *n);
+ node *add_char(charinfo *c, environment *, hunits *widthp);
+
+ virtual ~node();
+ virtual node *copy() = 0;
+ virtual hunits width();
+ virtual hunits subscript_correction();
+ virtual hunits italic_correction();
+ virtual hunits left_italic_correction();
+ virtual hunits skew();
+ virtual int nspaces();
+ virtual int merge_space(hunits);
+ virtual vunits vertical_width();
+ virtual node *last_char_node();
+ virtual void vertical_extent(vunits *min, vunits *max);
+ virtual int character_type();
+ virtual void set_vertical_size(vertical_size *);
+ virtual int ends_sentence();
+ virtual node *merge_self(node *);
+ virtual node *add_discretionary_hyphen();
+ virtual node *add_self(node *, hyphen_list **);
+ virtual hyphen_list *get_hyphen_list(hyphen_list *s = 0);
+ virtual void ascii_print(ascii_output_file *);
+ virtual void asciify(macro *);
+ virtual int discardable();
+ virtual void spread_space(int *, hunits *);
+ virtual void freeze_space();
+ virtual breakpoint *get_breakpoints(hunits width, int nspaces,
+ breakpoint *rest = 0,
+ int is_inner = 0);
+ virtual int nbreaks();
+ virtual void split(int, node **, node **);
+ virtual hyphenation_type get_hyphenation_type();
+ virtual int reread(int *);
+ virtual token_node *get_token_node();
+ virtual int overlaps_vertically();
+ virtual int overlaps_horizontally();
+ virtual units size();
+ virtual int interpret(macro *);
+
+ virtual node *merge_glyph_node(glyph_node *);
+ virtual tfont *get_tfont();
+ virtual void tprint(troff_output_file *);
+ virtual void zero_width_tprint(troff_output_file *);
+
+ node *add_italic_correction(hunits *);
+
+ virtual int same(node *) = 0;
+ virtual const char *type() = 0;
+};
+
+inline node::node() : next(0)
+{
+}
+
+inline node::node(node *n) : next(n)
+{
+}
+
+inline node::~node()
+{
+}
+
+// 0 means it doesn't, 1 means it does, 2 means it's transparent
+
+int node_list_ends_sentence(node *);
+
+struct breakpoint {
+ breakpoint *next;
+ hunits width;
+ int nspaces;
+ node *nd;
+ int index;
+ char hyphenated;
+};
+
+class line_start_node : public node {
+public:
+ line_start_node() {}
+ node *copy() { return new line_start_node; }
+ int same(node *);
+ const char *type();
+ void asciify(macro *);
+};
+
+class space_node : public node {
+private:
+#if 0
+ enum { BLOCK = 1024 };
+ static space_node *free_list;
+ void operator delete(void *);
+#endif
+protected:
+ hunits n;
+ char set;
+ space_node(hunits, int, node * = 0);
+public:
+ space_node(hunits d, node *p = 0);
+#if 0
+ ~space_node();
+ void *operator new(size_t);
+#endif
+ node *copy();
+ int nspaces();
+ hunits width();
+ int discardable();
+ int merge_space(hunits);
+ void freeze_space();
+ void spread_space(int*, hunits*);
+ void tprint(troff_output_file *);
+ breakpoint *get_breakpoints(hunits width, int nspaces, breakpoint *rest = 0,
+ int is_inner = 0);
+ int nbreaks();
+ void split(int, node **, node **);
+ void ascii_print(ascii_output_file *);
+ int same(node *);
+ const char *type();
+};
+
+class word_space_node : public space_node {
+protected:
+ word_space_node(hunits, int, node * = 0);
+public:
+ word_space_node(hunits, node * = 0);
+ node *copy();
+ void tprint(troff_output_file *);
+ int same(node *);
+ const char *type();
+};
+
+class unbreakable_space_node : public word_space_node {
+ unbreakable_space_node(hunits, int, node * = 0);
+public:
+ unbreakable_space_node(hunits, node * = 0);
+ node *copy();
+ int same(node *);
+ const char *type();
+ breakpoint *get_breakpoints(hunits width, int nspaces, breakpoint *rest = 0,
+ int is_inner = 0);
+ int nbreaks();
+ void split(int, node **, node **);
+ int merge_space(hunits);
+};
+
+class diverted_space_node : public node {
+public:
+ vunits n;
+ diverted_space_node(vunits d, node *p = 0);
+ node *copy();
+ int reread(int *);
+ int same(node *);
+ const char *type();
+};
+
+class diverted_copy_file_node : public node {
+ symbol filename;
+public:
+ vunits n;
+ diverted_copy_file_node(symbol s, node *p = 0);
+ node *copy();
+ int reread(int *);
+ int same(node *);
+ const char *type();
+};
+
+class extra_size_node : public node {
+ vunits n;
+ public:
+ extra_size_node(vunits i) : n(i) {}
+ void set_vertical_size(vertical_size *);
+ node *copy();
+ int same(node *);
+ const char *type();
+};
+
+class vertical_size_node : public node {
+ vunits n;
+ public:
+ vertical_size_node(vunits i) : n(i) {}
+ void set_vertical_size(vertical_size *);
+ void asciify(macro *);
+ node *copy();
+ int same(node *);
+ const char *type();
+};
+
+class hmotion_node : public node {
+protected:
+ hunits n;
+public:
+ hmotion_node(hunits i, node *next = 0) : node(next), n(i) {}
+ node *copy();
+ void tprint(troff_output_file *);
+ hunits width();
+ void ascii_print(ascii_output_file *);
+ int same(node *);
+ const char *type();
+};
+
+class space_char_hmotion_node : public hmotion_node {
+public:
+ space_char_hmotion_node(hunits i, node *next = 0);
+ node *copy();
+ void ascii_print(ascii_output_file *);
+ void asciify(macro *);
+ int same(node *);
+ const char *type();
+};
+
+class vmotion_node : public node {
+ vunits n;
+ public:
+ vmotion_node(vunits i) : n(i) {}
+ void tprint(troff_output_file *);
+ node *copy();
+ vunits vertical_width();
+ int same(node *);
+ const char *type();
+};
+
+
+class hline_node : public node {
+ hunits x;
+ node *n;
+ public:
+ hline_node(hunits i, node *c, node *next = 0) : node(next), x(i), n(c) {}
+ ~hline_node();
+ node *copy();
+ hunits width();
+ void tprint(troff_output_file *);
+ int same(node *);
+ const char *type();
+};
+
+class vline_node : public node {
+ vunits x;
+ node *n;
+ public:
+ vline_node(vunits i, node *c, node *next= 0) : node(next), x(i), n(c) {}
+ ~vline_node();
+ node *copy();
+ void tprint(troff_output_file *);
+ hunits width();
+ vunits vertical_width();
+ void vertical_extent(vunits *, vunits *);
+ int same(node *);
+ const char *type();
+};
+
+
+class dummy_node : public node {
+ public:
+ dummy_node(node *nd = 0) : node(nd) {}
+ node *copy();
+ int same(node *);
+ const char *type();
+ hyphenation_type get_hyphenation_type();
+};
+
+class transparent_dummy_node : public node {
+public:
+ transparent_dummy_node() {}
+ node *copy();
+ int same(node *);
+ const char *type();
+ int ends_sentence();
+ hyphenation_type get_hyphenation_type();
+};
+
+class zero_width_node : public node {
+ node *n;
+ public:
+ zero_width_node(node *gn);
+ ~zero_width_node();
+ node *copy();
+ void tprint(troff_output_file *);
+ int same(node *);
+ const char *type();
+ void append(node *);
+ int character_type();
+ void vertical_extent(vunits *min, vunits *max);
+};
+
+class left_italic_corrected_node : public node {
+ node *n;
+ hunits x;
+public:
+ left_italic_corrected_node(node * = 0);
+ ~left_italic_corrected_node();
+ void tprint(troff_output_file *);
+ void ascii_print(ascii_output_file *);
+ void asciify(macro *);
+ node *copy();
+ int same(node *);
+ const char *type();
+ hunits width();
+ node *last_char_node();
+ void vertical_extent(vunits *, vunits *);
+ int ends_sentence();
+ int overlaps_horizontally();
+ int overlaps_vertically();
+ hyphenation_type get_hyphenation_type();
+ tfont *get_tfont();
+ int character_type();
+ hunits skew();
+ hunits italic_correction();
+ hunits subscript_correction();
+ hyphen_list *get_hyphen_list(hyphen_list *ss = 0);
+ node *add_self(node *, hyphen_list **);
+ node *merge_glyph_node(glyph_node *);
+};
+
+class overstrike_node : public node {
+ node *list;
+ hunits max_width;
+public:
+ overstrike_node();
+ ~overstrike_node();
+ node *copy();
+ void tprint(troff_output_file *);
+ void overstrike(node *); // add another node to be overstruck
+ hunits width();
+ int same(node *);
+ const char *type();
+};
+
+class bracket_node : public node {
+ node *list;
+ hunits max_width;
+public:
+ bracket_node();
+ ~bracket_node();
+ node *copy();
+ void tprint(troff_output_file *);
+ void bracket(node *); // add another node to be overstruck
+ hunits width();
+ int same(node *);
+ const char *type();
+};
+
+class special_node : public node {
+ macro mac;
+ void tprint_start(troff_output_file *);
+ void tprint_char(troff_output_file *, unsigned char);
+ void tprint_end(troff_output_file *);
+public:
+ special_node(const macro &);
+ node *copy();
+ void tprint(troff_output_file *);
+ int same(node *);
+ const char *type();
+};
+
+
+struct hvpair {
+ hunits h;
+ vunits v;
+
+ hvpair();
+};
+
+class draw_node : public node {
+ int npoints;
+ font_size sz;
+ char code;
+ hvpair *point;
+public:
+ draw_node(char, hvpair *, int, font_size);
+ ~draw_node();
+ hunits width();
+ vunits vertical_width();
+ node *copy();
+ void tprint(troff_output_file *);
+ int same(node *);
+ const char *type();
+};
+
+class charinfo;
+node *make_node(charinfo *ci, environment *);
+int character_exists(charinfo *, environment *);
+
+int same_node_list(node *n1, node *n2);
+node *reverse_node_list(node *n);
+void delete_node_list(node *);
+node *copy_node_list(node *);
+
+int get_bold_fontno(int f);
+
+inline hyphen_list::hyphen_list(unsigned char code, hyphen_list *p)
+: hyphenation_code(code), next(p), hyphen(0), breakable(0)
+{
+}
+
+extern void read_desc();
+extern int mount_font(int n, symbol, symbol = NULL_SYMBOL);
+extern void mount_style(int n, symbol);
+extern int is_good_fontno(int n);
+extern int symbol_fontno(symbol);
+extern int next_available_font_position();
+extern void init_size_table(int *);
+extern int get_underline_fontno();
+
+class output_file {
+ char make_g_plus_plus_shut_up;
+public:
+ output_file();
+ virtual ~output_file();
+ virtual void trailer(vunits page_length);
+ virtual void flush() = 0;
+ virtual void transparent_char(unsigned char) = 0;
+ virtual void print_line(hunits x, vunits y, node *n,
+ vunits before, vunits after) = 0;
+ virtual void begin_page(int pageno, vunits page_length) = 0;
+ virtual void copy_file(hunits x, vunits y, const char *filename) = 0;
+ virtual int is_printing() = 0;
+#ifdef COLUMN
+ virtual void vjustify(vunits, symbol);
+#endif /* COLUMN */
+};
+
+#ifndef POPEN_MISSING
+extern char *pipe_command;
+#endif
+
+extern output_file *the_output;
+extern void init_output();
+int in_output_page_list(int n);
+
+class font_family {
+ int *map;
+ int map_size;
+public:
+ const symbol nm;
+
+ font_family(symbol);
+ ~font_family();
+ make_definite(int);
+ static void invalidate_fontno(int);
+};
+
+font_family *lookup_family(symbol);
diff --git a/gnu/usr.bin/groff/troff/number.cc b/gnu/usr.bin/groff/troff/number.cc
new file mode 100644
index 0000000..3e695b5
--- /dev/null
+++ b/gnu/usr.bin/groff/troff/number.cc
@@ -0,0 +1,669 @@
+// -*- C++ -*-
+/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
+ Written by James Clark (jjc@jclark.com)
+
+This file is part of groff.
+
+groff is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
+
+groff is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License along
+with groff; see the file COPYING. If not, write to the Free Software
+Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+
+#include "troff.h"
+#include "symbol.h"
+#include "hvunits.h"
+#include "env.h"
+#include "token.h"
+#include "div.h"
+
+vunits V0;
+hunits H0;
+
+int hresolution = 1;
+int vresolution = 1;
+int units_per_inch;
+int sizescale;
+
+static int parse_expr(units *v, int scale_indicator, int parenthesised);
+static int start_number();
+
+int get_vunits(vunits *res, unsigned char si)
+{
+ if (!start_number())
+ return 0;
+ units x;
+ if (parse_expr(&x, si, 0)) {
+ *res = vunits(x);
+ return 1;
+ }
+ else
+ return 0;
+}
+
+int get_hunits(hunits *res, unsigned char si)
+{
+ if (!start_number())
+ return 0;
+ units x;
+ if (parse_expr(&x, si, 0)) {
+ *res = hunits(x);
+ return 1;
+ }
+ else
+ return 0;
+}
+
+int get_number(units *res, unsigned char si)
+{
+ if (!start_number())
+ return 0;
+ units x;
+ if (parse_expr(&x, si, 0)) {
+ *res = x;
+ return 1;
+ }
+ else
+ return 0;
+}
+
+int get_integer(int *res)
+{
+ if (!start_number())
+ return 0;
+ units x;
+ if (parse_expr(&x, 0, 0)) {
+ *res = x;
+ return 1;
+ }
+ else
+ return 0;
+}
+
+enum incr_number_result { BAD, ABSOLUTE, INCREMENT, DECREMENT };
+
+static incr_number_result get_incr_number(units *res, unsigned char);
+
+int get_vunits(vunits *res, unsigned char si, vunits prev_value)
+{
+ units v;
+ switch (get_incr_number(&v, si)) {
+ case BAD:
+ return 0;
+ case ABSOLUTE:
+ *res = v;
+ break;
+ case INCREMENT:
+ *res = prev_value + v;
+ break;
+ case DECREMENT:
+ *res = prev_value - v;
+ break;
+ default:
+ assert(0);
+ }
+ return 1;
+}
+
+int get_hunits(hunits *res, unsigned char si, hunits prev_value)
+{
+ units v;
+ switch (get_incr_number(&v, si)) {
+ case BAD:
+ return 0;
+ case ABSOLUTE:
+ *res = v;
+ break;
+ case INCREMENT:
+ *res = prev_value + v;
+ break;
+ case DECREMENT:
+ *res = prev_value - v;
+ break;
+ default:
+ assert(0);
+ }
+ return 1;
+}
+
+int get_number(units *res, unsigned char si, units prev_value)
+{
+ units v;
+ switch (get_incr_number(&v, si)) {
+ case BAD:
+ return 0;
+ case ABSOLUTE:
+ *res = v;
+ break;
+ case INCREMENT:
+ *res = prev_value + v;
+ break;
+ case DECREMENT:
+ *res = prev_value - v;
+ break;
+ default:
+ assert(0);
+ }
+ return 1;
+}
+
+int get_integer(int *res, int prev_value)
+{
+ units v;
+ switch (get_incr_number(&v, 0)) {
+ case BAD:
+ return 0;
+ case ABSOLUTE:
+ *res = v;
+ break;
+ case INCREMENT:
+ *res = prev_value + int(v);
+ break;
+ case DECREMENT:
+ *res = prev_value - int(v);
+ break;
+ default:
+ assert(0);
+ }
+ return 1;
+}
+
+
+static incr_number_result get_incr_number(units *res, unsigned char si)
+{
+ if (!start_number())
+ return BAD;
+ incr_number_result result = ABSOLUTE;
+ if (tok.ch() == '+') {
+ tok.next();
+ result = INCREMENT;
+ }
+ else if (tok.ch() == '-') {
+ tok.next();
+ result = DECREMENT;
+ }
+ if (parse_expr(res, si, 0))
+ return result;
+ else
+ return BAD;
+}
+
+static int start_number()
+{
+ while (tok.space())
+ tok.next();
+ if (tok.newline()) {
+ warning(WARN_MISSING, "missing number");
+ return 0;
+ }
+ if (tok.tab()) {
+ warning(WARN_TAB, "tab character where number expected");
+ return 0;
+ }
+ if (tok.right_brace()) {
+ warning(WARN_RIGHT_BRACE, "`\\}' where number expected");
+ return 0;
+ }
+ return 1;
+}
+
+enum { OP_LEQ = 'L', OP_GEQ = 'G', OP_MAX = 'X', OP_MIN = 'N' };
+
+#define SCALE_INDICATOR_CHARS "icPmnpuvMsz"
+
+static int parse_term(units *v, int scale_indicator, int parenthesised);
+
+static int parse_expr(units *v, int scale_indicator, int parenthesised)
+{
+ int result = parse_term(v, scale_indicator, parenthesised);
+ while (result) {
+ if (parenthesised)
+ tok.skip();
+ int op = tok.ch();
+ switch (op) {
+ case '+':
+ case '-':
+ case '/':
+ case '*':
+ case '%':
+ case ':':
+ case '&':
+ tok.next();
+ break;
+ case '>':
+ tok.next();
+ if (tok.ch() == '=') {
+ tok.next();
+ op = OP_GEQ;
+ }
+ else if (tok.ch() == '?') {
+ tok.next();
+ op = OP_MAX;
+ }
+ break;
+ case '<':
+ tok.next();
+ if (tok.ch() == '=') {
+ tok.next();
+ op = OP_LEQ;
+ }
+ else if (tok.ch() == '?') {
+ tok.next();
+ op = OP_MIN;
+ }
+ break;
+ case '=':
+ tok.next();
+ if (tok.ch() == '=')
+ tok.next();
+ break;
+ default:
+ return result;
+ }
+ units v2;
+ if (!parse_term(&v2, scale_indicator, parenthesised))
+ return 0;
+ int overflow = 0;
+ switch (op) {
+ case '<':
+ *v = *v < v2;
+ break;
+ case '>':
+ *v = *v > v2;
+ break;
+ case OP_LEQ:
+ *v = *v <= v2;
+ break;
+ case OP_GEQ:
+ *v = *v >= v2;
+ break;
+ case OP_MIN:
+ if (*v > v2)
+ *v = v2;
+ break;
+ case OP_MAX:
+ if (*v < v2)
+ *v = v2;
+ break;
+ case '=':
+ *v = *v == v2;
+ break;
+ case '&':
+ *v = *v > 0 && v2 > 0;
+ break;
+ case ':':
+ *v = *v > 0 || v2 > 0;
+ case '+':
+ if (v2 < 0) {
+ if (*v < INT_MIN - v2)
+ overflow = 1;
+ }
+ else if (v2 > 0) {
+ if (*v > INT_MAX - v2)
+ overflow = 1;
+ }
+ if (overflow) {
+ error("addition overflow");
+ return 0;
+ }
+ *v += v2;
+ break;
+ case '-':
+ if (v2 < 0) {
+ if (*v > INT_MAX + v2)
+ overflow = 1;
+ }
+ else if (v2 > 0) {
+ if (*v < INT_MIN + v2)
+ overflow = 1;
+ }
+ if (overflow) {
+ error("subtraction overflow");
+ return 0;
+ }
+ *v -= v2;
+ break;
+ case '*':
+ if (v2 < 0) {
+ if (*v > 0) {
+ if (*v > -(unsigned)INT_MIN / -(unsigned)v2)
+ overflow = 1;
+ }
+ else if (-(unsigned)*v > INT_MAX / -(unsigned)v2)
+ overflow = 1;
+ }
+ else if (v2 > 0) {
+ if (*v > 0) {
+ if (*v > INT_MAX / v2)
+ overflow = 1;
+ }
+ else if (-(unsigned)*v > -(unsigned)INT_MIN / v2)
+ overflow = 1;
+ }
+ if (overflow) {
+ error("multiplication overflow");
+ return 0;
+ }
+ *v *= v2;
+ break;
+ case '/':
+ if (v2 == 0) {
+ error("division by zero");
+ return 0;
+ }
+ *v /= v2;
+ break;
+ case '%':
+ if (v2 == 0) {
+ error("modulus by zero");
+ return 0;
+ }
+ *v %= v2;
+ break;
+ default:
+ assert(0);
+ }
+ }
+ return result;
+}
+
+static int parse_term(units *v, int scale_indicator, int parenthesised)
+{
+ int negative = 0;
+ for (;;)
+ if (parenthesised && tok.space())
+ tok.next();
+ else if (tok.ch() == '+')
+ tok.next();
+ else if (tok.ch() == '-') {
+ tok.next();
+ negative = !negative;
+ }
+ else
+ break;
+ unsigned char c = tok.ch();
+ switch (c) {
+ case '|':
+ // | is not restricted to the outermost level
+ // tbl uses this
+ tok.next();
+ if (!parse_term(v, scale_indicator, parenthesised))
+ return 0;
+ int tem;
+ tem = (scale_indicator == 'v'
+ ? curdiv->get_vertical_position().to_units()
+ : curenv->get_input_line_position().to_units());
+ if (tem >= 0) {
+ if (*v < INT_MIN + tem) {
+ error("numeric overflow");
+ return 0;
+ }
+ }
+ else {
+ if (*v > INT_MAX + tem) {
+ error("numeric overflow");
+ return 0;
+ }
+ }
+ *v -= tem;
+ if (negative) {
+ if (*v == INT_MIN) {
+ error("numeric overflow");
+ return 0;
+ }
+ *v = -*v;
+ }
+ return 1;
+ case '(':
+ tok.next();
+ c = tok.ch();
+ if (c == ')') {
+ warning(WARN_SYNTAX, "empty parentheses");
+ tok.next();
+ *v = 0;
+ return 1;
+ }
+ else if (c != 0 && strchr(SCALE_INDICATOR_CHARS, c) != 0) {
+ tok.next();
+ if (tok.ch() == ';') {
+ tok.next();
+ scale_indicator = c;
+ }
+ else {
+ error("expected `;' after scale-indicator (got %1)",
+ tok.description());
+ return 0;
+ }
+ }
+ else if (c == ';') {
+ scale_indicator = 0;
+ tok.next();
+ }
+ if (!parse_expr(v, scale_indicator, 1))
+ return 0;
+ tok.skip();
+ if (tok.ch() != ')') {
+ warning(WARN_SYNTAX, "missing `)' (got %1)", tok.description());
+ }
+ else
+ tok.next();
+ if (negative) {
+ if (*v == INT_MIN) {
+ error("numeric overflow");
+ return 0;
+ }
+ *v = -*v;
+ }
+ return 1;
+ case '.':
+ *v = 0;
+ break;
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ *v = 0;
+ do {
+ if (*v > INT_MAX/10) {
+ error("numeric overflow");
+ return 0;
+ }
+ *v *= 10;
+ if (*v > INT_MAX - (int(c) - '0')) {
+ error("numeric overflow");
+ return 0;
+ }
+ *v += c - '0';
+ tok.next();
+ c = tok.ch();
+ } while (csdigit(c));
+ break;
+ case '/':
+ case '*':
+ case '%':
+ case ':':
+ case '&':
+ case '>':
+ case '<':
+ case '=':
+ warning(WARN_SYNTAX, "empty left operand");
+ *v = 0;
+ return 1;
+ default:
+ warning(WARN_NUMBER, "numeric expression expected (got %1)",
+ tok.description());
+ return 0;
+ }
+ int divisor = 1;
+ if (tok.ch() == '.') {
+ tok.next();
+ for (;;) {
+ c = tok.ch();
+ if (!csdigit(c))
+ break;
+ // we may multiply the divisor by 254 later on
+ if (divisor <= INT_MAX/2540 && *v <= (INT_MAX - 9)/10) {
+ *v *= 10;
+ *v += c - '0';
+ divisor *= 10;
+ }
+ tok.next();
+ }
+ }
+ int si = scale_indicator;
+ int do_next = 0;
+ if ((c = tok.ch()) != 0 && strchr(SCALE_INDICATOR_CHARS, c) != 0) {
+ switch (scale_indicator) {
+ case 'z':
+ if (c != 'u' && c != 'z') {
+ warning(WARN_SCALE,
+ "only `z' and `u' scale indicators valid in this context");
+ break;
+ }
+ si = c;
+ break;
+ case 0:
+ warning(WARN_SCALE, "scale indicator invalid in this context");
+ break;
+ case 'u':
+ si = c;
+ break;
+ default:
+ if (c == 'z') {
+ warning(WARN_SCALE, "`z' scale indicator invalid in this context");
+ break;
+ }
+ si = c;
+ break;
+ }
+ // Don't do tok.next() here because the next token might be \s, which
+ // would affect the interpretation of m.
+ do_next = 1;
+ }
+ switch (si) {
+ case 'i':
+ *v = scale(*v, units_per_inch, divisor);
+ break;
+ case 'c':
+ *v = scale(*v, units_per_inch*100, divisor*254);
+ break;
+ case 0:
+ case 'u':
+ if (divisor != 1)
+ *v /= divisor;
+ break;
+ case 'p':
+ *v = scale(*v, units_per_inch, divisor*72);
+ break;
+ case 'P':
+ *v = scale(*v, units_per_inch, divisor*6);
+ break;
+ case 'm':
+ {
+ // Convert to hunits so that with -Tascii `m' behaves as in nroff.
+ hunits em = curenv->get_size();
+ *v = scale(*v, em.is_zero() ? hresolution : em.to_units(), divisor);
+ }
+ break;
+ case 'M':
+ {
+ hunits em = curenv->get_size();
+ *v = scale(*v, em.is_zero() ? hresolution : em.to_units(), divisor*100);
+ }
+ break;
+ case 'n':
+ {
+ // Convert to hunits so that with -Tascii `n' behaves as in nroff.
+ hunits en = curenv->get_size()/2;
+ *v = scale(*v, en.is_zero() ? hresolution : en.to_units(), divisor);
+ }
+ break;
+ case 'v':
+ *v = scale(*v, curenv->get_vertical_spacing().to_units(), divisor);
+ break;
+ case 's':
+ while (divisor > INT_MAX/(sizescale*72)) {
+ divisor /= 10;
+ *v /= 10;
+ }
+ *v = scale(*v, units_per_inch, divisor*sizescale*72);
+ break;
+ case 'z':
+ *v = scale(*v, sizescale, divisor);
+ break;
+ default:
+ assert(0);
+ }
+ if (do_next)
+ tok.next();
+ if (negative) {
+ if (*v == INT_MIN) {
+ error("numeric overflow");
+ return 0;
+ }
+ *v = -*v;
+ }
+ return 1;
+}
+
+units scale(units n, units x, units y)
+{
+ assert(x >= 0 && y > 0);
+ if (x == 0)
+ return 0;
+ if (n >= 0) {
+ if (n <= INT_MAX/x)
+ return (n*x)/y;
+ }
+ else {
+ if (-(unsigned)n <= -(unsigned)INT_MIN/x)
+ return (n*x)/y;
+ }
+ double res = n*double(x)/double(y);
+ if (res > INT_MAX) {
+ error("numeric overflow");
+ return INT_MAX;
+ }
+ else if (res < INT_MIN) {
+ error("numeric overflow");
+ return INT_MIN;
+ }
+ return int(res);
+}
+
+vunits::vunits(units x)
+{
+ // don't depend on the rounding direction for division of negative integers
+ if (vresolution == 1)
+ n = x;
+ else
+ n = (x < 0
+ ? -((-x + vresolution/2 - 1)/vresolution)
+ : (x + vresolution/2 - 1)/vresolution);
+}
+
+hunits::hunits(units x)
+{
+ // don't depend on the rounding direction for division of negative integers
+ if (hresolution == 1)
+ n = x;
+ else
+ n = (x < 0
+ ? -((-x + hresolution/2 - 1)/hresolution)
+ : (x + hresolution/2 - 1)/hresolution);
+}
diff --git a/gnu/usr.bin/groff/troff/reg.cc b/gnu/usr.bin/groff/troff/reg.cc
new file mode 100644
index 0000000..cefeb87
--- /dev/null
+++ b/gnu/usr.bin/groff/troff/reg.cc
@@ -0,0 +1,458 @@
+// -*- C++ -*-
+/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
+ Written by James Clark (jjc@jclark.com)
+
+This file is part of groff.
+
+groff is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
+
+groff is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License along
+with groff; see the file COPYING. If not, write to the Free Software
+Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "troff.h"
+#include "symbol.h"
+#include "dictionary.h"
+#include "token.h"
+#include "request.h"
+#include "reg.h"
+
+object_dictionary number_reg_dictionary(101);
+
+int reg::get_value(units * /*d*/)
+{
+ return 0;
+}
+
+void reg::increment()
+{
+ error("can't increment read-only register");
+}
+
+void reg::decrement()
+{
+ error("can't decrement read-only register");
+}
+
+void reg::set_increment(units /*n*/)
+{
+ error("can't auto increment read-only register");
+}
+
+void reg::alter_format(char /*f*/, int /*w*/)
+{
+ error("can't alter format of read-only register");
+}
+
+const char *reg::get_format()
+{
+ return "0";
+}
+
+void reg::set_value(units /*n*/)
+{
+ error("can't write read-only register");
+}
+
+general_reg::general_reg() : format('1'), width(0), inc(0)
+{
+}
+
+static const char *number_value_to_ascii(int value, char format, int width)
+{
+ static char buf[128]; // must be at least 21
+ switch(format) {
+ case '1':
+ if (width <= 0)
+ return itoa(value);
+ else if (width > sizeof(buf) - 2)
+ sprintf(buf, "%.*d", sizeof(buf) - 2, int(value));
+ else
+ sprintf(buf, "%.*d", width, int(value));
+ break;
+ case 'i':
+ case 'I':
+ {
+ char *p = buf;
+ // troff uses z and w to represent 10000 and 5000 in Roman
+ // numerals; I can find no historical basis for this usage
+ const char *s = format == 'i' ? "zwmdclxvi" : "ZWMDCLXVI";
+ int n = int(value);
+ if (n >= 40000 || n <= -40000) {
+ error("magnitude of `%1' too big for i or I format", n);
+ return itoa(n);
+ }
+ if (n == 0) {
+ *p++ = '0';
+ *p = 0;
+ break;
+ }
+ if (n < 0) {
+ *p++ = '-';
+ n = -n;
+ }
+ while (n >= 10000) {
+ *p++ = s[0];
+ n -= 10000;
+ }
+ for (int i = 1000; i > 0; i /= 10, s += 2) {
+ int m = n/i;
+ n -= m*i;
+ switch (m) {
+ case 3:
+ *p++ = s[2];
+ /* falls through */
+ case 2:
+ *p++ = s[2];
+ /* falls through */
+ case 1:
+ *p++ = s[2];
+ break;
+ case 4:
+ *p++ = s[2];
+ *p++ = s[1];
+ break;
+ case 8:
+ *p++ = s[1];
+ *p++ = s[2];
+ *p++ = s[2];
+ *p++ = s[2];
+ break;
+ case 7:
+ *p++ = s[1];
+ *p++ = s[2];
+ *p++ = s[2];
+ break;
+ case 6:
+ *p++ = s[1];
+ *p++ = s[2];
+ break;
+ case 5:
+ *p++ = s[1];
+ break;
+ case 9:
+ *p++ = s[2];
+ *p++ = s[0];
+ }
+ }
+ *p = 0;
+ break;
+ }
+ case 'a':
+ case 'A':
+ {
+ int n = value;
+ char *p = buf;
+ if (n == 0) {
+ *p++ = '0';
+ *p = 0;
+ }
+ else {
+ if (n < 0) {
+ n = -n;
+ *p++ = '-';
+ }
+ // this is a bit tricky
+ while (n > 0) {
+ int d = n % 26;
+ if (d == 0)
+ d = 26;
+ n -= d;
+ n /= 26;
+ *p++ = format + d - 1;
+ }
+ *p-- = 0;
+ char *q = buf[0] == '-' ? buf+1 : buf;
+ while (q < p) {
+ char temp = *q;
+ *q = *p;
+ *p = temp;
+ --p;
+ ++q;
+ }
+ }
+ break;
+ }
+ default:
+ assert(0);
+ break;
+ }
+ return buf;
+}
+
+const char *general_reg::get_string()
+{
+ units n;
+ if (!get_value(&n))
+ return "";
+ return number_value_to_ascii(n, format, width);
+}
+
+
+void general_reg::increment()
+{
+ int n;
+ if (get_value(&n))
+ set_value(n + inc);
+}
+
+void general_reg::decrement()
+{
+ int n;
+ if (get_value(&n))
+ set_value(n - inc);
+}
+
+void general_reg::set_increment(units n)
+{
+ inc = n;
+}
+
+void general_reg::alter_format(char f, int w)
+{
+ format = f;
+ width = w;
+}
+
+static const char *number_format_to_ascii(char format, int width)
+{
+ static char buf[24];
+ if (format == '1') {
+ if (width > 0) {
+ int n = width;
+ if (n > int(sizeof(buf)) - 1)
+ n = int(sizeof(buf)) - 1;
+ sprintf(buf, "%.*d", n, 0);
+ return buf;
+ }
+ else
+ return "0";
+ }
+ else {
+ buf[0] = format;
+ buf[1] = '\0';
+ return buf;
+ }
+}
+
+const char *general_reg::get_format()
+{
+ return number_format_to_ascii(format, width);
+}
+
+class number_reg : public general_reg {
+ units value;
+public:
+ number_reg();
+ int get_value(units *);
+ void set_value(units);
+};
+
+number_reg::number_reg() : value(0)
+{
+}
+
+int number_reg::get_value(units *res)
+{
+ *res = value;
+ return 1;
+}
+
+void number_reg::set_value(units n)
+{
+ value = n;
+}
+
+variable_reg::variable_reg(units *p) : ptr(p)
+{
+}
+
+void variable_reg::set_value(units n)
+{
+ *ptr = n;
+}
+
+int variable_reg::get_value(units *res)
+{
+ *res = *ptr;
+ return 1;
+}
+
+void define_number_reg()
+{
+ symbol nm = get_name(1);
+ if (nm.is_null()) {
+ skip_line();
+ return;
+ }
+ reg *r = (reg *)number_reg_dictionary.lookup(nm);
+ units v;
+ units prev_value;
+ if (!r || !r->get_value(&prev_value))
+ prev_value = 0;
+ if (get_number(&v, 'u', prev_value)) {
+ if (r == 0) {
+ r = new number_reg;
+ number_reg_dictionary.define(nm, r);
+ }
+ r->set_value(v);
+ if (tok.space() && has_arg() && get_number(&v, 'u'))
+ r->set_increment(v);
+ }
+ skip_line();
+}
+
+#if 0
+void inline_define_reg()
+{
+ token start;
+ start.next();
+ if (!start.delimiter(1))
+ return;
+ tok.next();
+ symbol nm = get_name(1);
+ if (nm.is_null())
+ return;
+ reg *r = (reg *)number_reg_dictionary.lookup(nm);
+ if (r == 0) {
+ r = new number_reg;
+ number_reg_dictionary.define(nm, r);
+ }
+ units v;
+ units prev_value;
+ if (!r->get_value(&prev_value))
+ prev_value = 0;
+ if (get_number(&v, 'u', prev_value)) {
+ r->set_value(v);
+ if (start != tok) {
+ if (get_number(&v, 'u')) {
+ r->set_increment(v);
+ if (start != tok)
+ warning(WARN_DELIM, "closing delimiter does not match");
+ }
+ }
+ }
+}
+#endif
+
+void set_number_reg(symbol nm, units n)
+{
+ reg *r = (reg *)number_reg_dictionary.lookup(nm);
+ if (r == 0) {
+ r = new number_reg;
+ number_reg_dictionary.define(nm, r);
+ }
+ r->set_value(n);
+}
+
+reg *lookup_number_reg(symbol nm)
+{
+ reg *r = (reg *)number_reg_dictionary.lookup(nm);
+ if (r == 0) {
+ warning(WARN_REG, "number register `%1' not defined", nm.contents());
+ r = new number_reg;
+ number_reg_dictionary.define(nm, r);
+ }
+ return r;
+}
+
+void alter_format()
+{
+ symbol nm = get_name(1);
+ if (nm.is_null()) {
+ skip_line();
+ return;
+ }
+ reg *r = (reg *)number_reg_dictionary.lookup(nm);
+ if (r == 0) {
+ r = new number_reg;
+ number_reg_dictionary.define(nm, r);
+ }
+ tok.skip();
+ char c = tok.ch();
+ if (csdigit(c)) {
+ int n = 0;
+ do {
+ ++n;
+ tok.next();
+ } while (csdigit(tok.ch()));
+ r->alter_format('1', n);
+ }
+ else if (c == 'i' || c == 'I' || c == 'a' || c == 'A')
+ r->alter_format(c);
+ else if (tok.newline() || tok.eof())
+ warning(WARN_MISSING, "missing number register format");
+ else
+ error("bad number register format (got %1)", tok.description());
+ skip_line();
+}
+
+void remove_reg()
+{
+ for (;;) {
+ symbol s = get_name();
+ if (s.is_null())
+ break;
+ number_reg_dictionary.remove(s);
+ }
+ skip_line();
+}
+
+void alias_reg()
+{
+ symbol s1 = get_name(1);
+ if (!s1.is_null()) {
+ symbol s2 = get_name(1);
+ if (!s2.is_null()) {
+ if (!number_reg_dictionary.alias(s1, s2))
+ warning(WARN_REG, "number register `%1' not defined", s2.contents());
+ }
+ }
+ skip_line();
+}
+
+void rename_reg()
+{
+ symbol s1 = get_name(1);
+ if (!s1.is_null()) {
+ symbol s2 = get_name(1);
+ if (!s2.is_null())
+ number_reg_dictionary.rename(s1, s2);
+ }
+ skip_line();
+}
+
+void print_number_regs()
+{
+ object_dictionary_iterator iter(number_reg_dictionary);
+ reg *r;
+ symbol s;
+ while (iter.get(&s, (object **)&r)) {
+ assert(!s.is_null());
+ errprint("%1\t", s.contents());
+ const char *p = r->get_string();
+ if (p)
+ errprint(p);
+ errprint("\n");
+ }
+ fflush(stderr);
+ skip_line();
+}
+
+void init_reg_requests()
+{
+ init_request("rr", remove_reg);
+ init_request("nr", define_number_reg);
+ init_request("af", alter_format);
+ init_request("aln", alias_reg);
+ init_request("rnn", rename_reg);
+ init_request("pnr", print_number_regs);
+}
diff --git a/gnu/usr.bin/groff/troff/reg.h b/gnu/usr.bin/groff/troff/reg.h
new file mode 100644
index 0000000..4ecbc97
--- /dev/null
+++ b/gnu/usr.bin/groff/troff/reg.h
@@ -0,0 +1,73 @@
+// -*- C++ -*-
+/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
+ Written by James Clark (jjc@jclark.com)
+
+This file is part of groff.
+
+groff is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
+
+groff is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License along
+with groff; see the file COPYING. If not, write to the Free Software
+Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+
+class reg : public object {
+public:
+ virtual const char *get_string() = 0;
+ virtual int get_value(units *);
+ virtual void increment();
+ virtual void decrement();
+ virtual void set_increment(units);
+ virtual void alter_format(char f, int w = 0);
+ virtual const char *get_format();
+ virtual void set_value(units);
+};
+
+class constant_int_reg : public reg {
+ int *p;
+public:
+ constant_int_reg(int *);
+ const char *get_string();
+};
+
+class general_reg : public reg {
+ char format;
+ int width;
+ int inc;
+public:
+ general_reg();
+ const char *get_string();
+ void increment();
+ void decrement();
+ void alter_format(char f, int w = 0);
+ void set_increment(units);
+ const char *get_format();
+ void add_value(units);
+
+ void set_value(units) = 0;
+ int get_value(units *) = 0;
+};
+
+class variable_reg : public general_reg {
+ units *ptr;
+public:
+ variable_reg(int *);
+ void set_value(units);
+ int get_value(units *);
+};
+
+extern object_dictionary number_reg_dictionary;
+extern void set_number_reg(symbol nm, units n);
+
+reg *lookup_number_reg(symbol);
+#if 0
+void inline_define_reg();
+#endif
diff --git a/gnu/usr.bin/groff/troff/request.h b/gnu/usr.bin/groff/troff/request.h
new file mode 100644
index 0000000..2de9fb7
--- /dev/null
+++ b/gnu/usr.bin/groff/troff/request.h
@@ -0,0 +1,80 @@
+// -*- C++ -*-
+/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
+ Written by James Clark (jjc@jclark.com)
+
+This file is part of groff.
+
+groff is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
+
+groff is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License along
+with groff; see the file COPYING. If not, write to the Free Software
+Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+typedef void (*REQUEST_FUNCP)();
+
+class macro;
+
+class request_or_macro : public object {
+public:
+ request_or_macro();
+ virtual void invoke(symbol s) = 0;
+ virtual macro *to_macro();
+};
+
+class request : public request_or_macro {
+ REQUEST_FUNCP p;
+public:
+ void invoke(symbol);
+ request(REQUEST_FUNCP);
+};
+
+void delete_request_or_macro(request_or_macro *);
+
+extern object_dictionary request_dictionary;
+
+struct macro_header;
+struct node;
+
+class macro : public request_or_macro {
+ macro_header *p;
+ const char *filename; // where was it defined?
+ int lineno;
+ int length;
+public:
+ macro();
+ ~macro();
+ macro(const macro &);
+ macro &operator=(const macro &);
+ void append(unsigned char);
+ void append(node *);
+ void invoke(symbol);
+ macro *to_macro();
+ void print_size();
+ int empty();
+ friend class string_iterator;
+ friend void chop_macro();
+ friend int operator==(const macro &, const macro &);
+};
+
+extern void init_input_requests();
+extern void init_div_requests();
+extern void init_node_requests();
+extern void init_reg_requests();
+extern void init_env_requests();
+extern void init_hyphen_requests();
+extern void init_request(const char *s, REQUEST_FUNCP f);
+
+extern int no_break_flag; // indicates whether request was invoked with . or '
+
+class charinfo;
+class environment;
+
+node *charinfo_to_node_list(charinfo *, const environment *);
diff --git a/gnu/usr.bin/groff/troff/symbol.cc b/gnu/usr.bin/groff/troff/symbol.cc
new file mode 100644
index 0000000..933e5d9
--- /dev/null
+++ b/gnu/usr.bin/groff/troff/symbol.cc
@@ -0,0 +1,148 @@
+// -*- C++ -*-
+/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
+ Written by James Clark (jjc@jclark.com)
+
+This file is part of groff.
+
+groff is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
+
+groff is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License along
+with groff; see the file COPYING. If not, write to the Free Software
+Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+
+#include "troff.h"
+#include "symbol.h"
+
+const char **symbol::table = 0;
+int symbol::table_used = 0;
+int symbol::table_size = 0;
+char *symbol::block = 0;
+int symbol::block_size = 0;
+
+const symbol NULL_SYMBOL;
+
+#ifdef BLOCK_SIZE
+#undef BLOCK_SIZE
+#endif
+
+const int BLOCK_SIZE = 1024;
+// the table will increase in size as necessary
+// the size will be chosen from the following array
+// add some more if you want
+// I think it unlikely that we'll need more than a million symbols
+static const unsigned int table_sizes[] = {
+101, 503, 1009, 2003, 3001, 4001, 5003, 10007, 20011, 40009, 80021, 160001, 500009, 1000003, 0
+};
+const double FULL_MAX = 0.3; // don't let the table get more than this full
+
+static unsigned int hash_string(const char *p)
+{
+ // compute a hash code; this assumes 32-bit unsigned ints
+ // see p436 of Compilers by Aho, Sethi & Ullman
+ // give special treatment to two-character names
+ unsigned int hc = 0, g;
+ if (*p != 0) {
+ hc = *p++;
+ if (*p != 0) {
+ hc <<= 7;
+ hc += *p++;
+ for (; *p != 0; p++) {
+ hc <<= 4;
+ hc += *p;
+ if ((g = (hc & 0xf0000000)) == 0) {
+ hc ^= g >> 24;
+ hc ^= g;
+ }
+ }
+ }
+ }
+ return hc;
+}
+
+// Tell compiler that a variable is intentionally unused.
+inline void unused(void *) { }
+
+symbol::symbol(const char *p, int how)
+{
+ if (p == 0 || *p == 0) {
+ s = 0;
+ return;
+ }
+ if (table == 0) {
+ table_size = table_sizes[0];
+ table = (const char **)new char*[table_size];
+ for (int i = 0; i < table_size; i++)
+ table[i] = 0;
+ table_used = 0;
+ }
+ unsigned int hc = hash_string(p);
+ for (const char **pp = table + hc % table_size;
+ *pp != 0;
+ (pp == table ? pp = table + table_size - 1 : --pp))
+ if (strcmp(p, *pp) == 0) {
+ s = *pp;
+ return;
+ }
+ if (how == MUST_ALREADY_EXIST) {
+ s = 0;
+ return;
+ }
+ if (table_used >= table_size - 1 || table_used >= table_size*FULL_MAX) {
+ const char **old_table = table;
+ unsigned int old_table_size = table_size;
+ for (int i = 1; table_sizes[i] <= old_table_size; i++)
+ if (table_sizes[i] == 0)
+ fatal("too many symbols");
+ table_size = table_sizes[i];
+ table_used = 0;
+ table = (const char **)new char*[table_size];
+ for (i = 0; i < table_size; i++)
+ table[i] = 0;
+ for (pp = old_table + old_table_size - 1;
+ pp >= old_table;
+ --pp) {
+ symbol temp(*pp, 1); /* insert it into the new table */
+ unused(&temp);
+ }
+ a_delete old_table;
+ for (pp = table + hc % table_size;
+ *pp != 0;
+ (pp == table ? pp = table + table_size - 1 : --pp))
+ ;
+ }
+ ++table_used;
+ if (how == DONT_STORE) {
+ s = *pp = p;
+ }
+ else {
+ int len = strlen(p)+1;
+ if (block == 0 || block_size < len) {
+ block_size = len > BLOCK_SIZE ? len : BLOCK_SIZE;
+ block = new char [block_size];
+ }
+ (void)strcpy(block, p);
+ s = *pp = block;
+ block += len;
+ block_size -= len;
+ }
+}
+
+symbol concat(symbol s1, symbol s2)
+{
+ char *buf = new char [strlen(s1.contents()) + strlen(s2.contents()) + 1];
+ strcpy(buf, s1.contents());
+ strcat(buf, s2.contents());
+ symbol res(buf);
+ a_delete buf;
+ return res;
+}
+
diff --git a/gnu/usr.bin/groff/troff/symbol.h b/gnu/usr.bin/groff/troff/symbol.h
new file mode 100644
index 0000000..3791674
--- /dev/null
+++ b/gnu/usr.bin/groff/troff/symbol.h
@@ -0,0 +1,73 @@
+// -*- C++ -*-
+/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
+ Written by James Clark (jjc@jclark.com)
+
+This file is part of groff.
+
+groff is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
+
+groff is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License along
+with groff; see the file COPYING. If not, write to the Free Software
+Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#define DONT_STORE 1
+#define MUST_ALREADY_EXIST 2
+
+class symbol {
+ static const char **table;
+ static int table_used;
+ static int table_size;
+ static char *block;
+ static int block_size;
+ const char *s;
+public:
+ symbol(const char *p, int how = 0);
+ symbol();
+ unsigned long hash() const;
+ operator ==(symbol) const;
+ operator !=(symbol) const;
+ const char *contents() const;
+ int is_null() const;
+};
+
+
+extern const symbol NULL_SYMBOL;
+
+inline symbol::symbol() : s(0)
+{
+}
+
+inline int symbol::operator==(symbol p) const
+{
+ return s == p.s;
+}
+
+inline int symbol::operator!=(symbol p) const
+{
+ return s != p.s;
+}
+
+inline unsigned long symbol::hash() const
+{
+ return (unsigned long)s;
+}
+
+inline const char *symbol::contents() const
+{
+ return s;
+}
+
+inline int symbol::is_null() const
+{
+ return s == 0;
+}
+
+symbol concat(symbol, symbol);
diff --git a/gnu/usr.bin/groff/troff/token.h b/gnu/usr.bin/groff/troff/token.h
new file mode 100644
index 0000000..2c160e5
--- /dev/null
+++ b/gnu/usr.bin/groff/troff/token.h
@@ -0,0 +1,194 @@
+// -*- C++ -*-
+/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
+ Written by James Clark (jjc@jclark.com)
+
+This file is part of groff.
+
+groff is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
+
+groff is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License along
+with groff; see the file COPYING. If not, write to the Free Software
+Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+
+struct charinfo;
+struct node;
+struct vunits;
+
+class token {
+ symbol nm;
+ node *nd;
+ unsigned char c;
+ int val;
+ units dim;
+ enum token_type {
+ TOKEN_BACKSPACE,
+ TOKEN_BEGIN_TRAP,
+ TOKEN_CHAR, // a normal printing character
+ TOKEN_DUMMY,
+ TOKEN_EMPTY, // this is the initial value
+ TOKEN_END_TRAP,
+ TOKEN_ESCAPE, // \e
+ TOKEN_HYPHEN_INDICATOR,
+ TOKEN_INTERRUPT, // \c
+ TOKEN_ITALIC_CORRECTION, // \/
+ TOKEN_LEADER, // ^A
+ TOKEN_LEFT_BRACE,
+ TOKEN_MARK_INPUT, // \k -- `nm' is the name of the register
+ TOKEN_NEWLINE, // newline
+ TOKEN_NODE,
+ TOKEN_NUMBERED_CHAR,
+ TOKEN_PAGE_EJECTOR,
+ TOKEN_REQUEST,
+ TOKEN_RIGHT_BRACE,
+ TOKEN_SPACE, // ` ' -- ordinary space
+ TOKEN_SPECIAL, // a special character -- \' \` \- \(xx
+ TOKEN_SPREAD, // \p -- break and spread output line
+ TOKEN_TAB, // tab
+ TOKEN_TRANSPARENT, // \!
+ TOKEN_EOF // end of file
+ } type;
+public:
+ token();
+ ~token();
+ token(const token &);
+ void operator=(const token &);
+ void next();
+ void process();
+ void skip();
+ int eof();
+ int nspaces(); // 1 if space, 2 if double space, 0 otherwise
+ int space(); // is it a space or double space?
+ int white_space(); // is the current token space or tab?
+ int newline(); // is the current token a newline?
+ int tab(); // is the current token a tab?
+ int leader();
+ int backspace();
+ int delimiter(int warn = 0); // is it suitable for use as a delimiter?
+ int dummy();
+ int transparent();
+ int left_brace();
+ int right_brace();
+ int page_ejector();
+ int hyphen_indicator();
+ int operator==(const token &); // need this for delimiters, and for conditions
+ int operator!=(const token &); // ditto
+ unsigned char ch();
+ charinfo *get_char(int required = 0);
+ int add_to_node_list(node **);
+ int title();
+ void make_space();
+ void make_newline();
+ const char *description();
+
+ friend void process_input_stack();
+};
+
+extern token tok; // the current token
+
+extern symbol get_name(int required = 0);
+extern symbol get_long_name(int required = 0);
+extern charinfo *get_optional_char();
+extern void skip_line();
+extern void handle_initial_title();
+
+struct hunits;
+extern void read_title_parts(node **part, hunits *part_width);
+
+extern int get_number(units *result, unsigned char si);
+extern int get_integer(int *result);
+
+extern int get_number(units *result, unsigned char si, units prev_value);
+extern int get_integer(int *result, int prev_value);
+
+void interpolate_number_reg(symbol, int);
+
+const char *asciify(int c);
+
+inline int token::newline()
+{
+ return type == TOKEN_NEWLINE;
+}
+
+inline int token::space()
+{
+ return type == TOKEN_SPACE;
+}
+
+inline int token::nspaces()
+{
+ if (type == TOKEN_SPACE)
+ return 1;
+ else
+ return 0;
+}
+
+inline int token::white_space()
+{
+ return type == TOKEN_SPACE || type == TOKEN_TAB;
+}
+
+inline int token::transparent()
+{
+ return type == TOKEN_TRANSPARENT;
+}
+
+inline int token::page_ejector()
+{
+ return type == TOKEN_PAGE_EJECTOR;
+}
+
+inline unsigned char token::ch()
+{
+ return type == TOKEN_CHAR ? c : 0;
+}
+
+inline int token::eof()
+{
+ return type == TOKEN_EOF;
+}
+
+inline int token::dummy()
+{
+ return type == TOKEN_DUMMY;
+}
+
+inline int token::left_brace()
+{
+ return type == TOKEN_LEFT_BRACE;
+}
+
+inline int token::right_brace()
+{
+ return type == TOKEN_RIGHT_BRACE;
+}
+
+inline int token::tab()
+{
+ return type == TOKEN_TAB;
+}
+
+inline int token::leader()
+{
+ return type == TOKEN_LEADER;
+}
+
+inline int token::backspace()
+{
+ return type == TOKEN_BACKSPACE;
+}
+
+inline int token::hyphen_indicator()
+{
+ return type == TOKEN_HYPHEN_INDICATOR;
+}
+
+int has_arg();
diff --git a/gnu/usr.bin/groff/troff/troff.h b/gnu/usr.bin/groff/troff/troff.h
new file mode 100644
index 0000000..03bd383
--- /dev/null
+++ b/gnu/usr.bin/groff/troff/troff.h
@@ -0,0 +1,83 @@
+// -*- C++ -*-
+/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
+ Written by James Clark (jjc@jclark.com)
+
+This file is part of groff.
+
+groff is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
+
+groff is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License along
+with groff; see the file COPYING. If not, write to the Free Software
+Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+#include <time.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <errno.h>
+
+#include "lib.h"
+#include "assert.h"
+#include "device.h"
+
+void cleanup_and_exit(int n);
+
+typedef int units;
+
+extern units scale(units n, units x, units y); // scale n by x/y
+
+extern units units_per_inch;
+
+extern int ascii_output_flag;
+extern int suppress_output_flag;
+
+extern int tcommand_flag;
+extern int vresolution;
+extern int hresolution;
+extern int sizescale;
+
+#include "cset.h"
+#include "cmap.h"
+#include "errarg.h"
+#include "error.h"
+
+enum warning_type {
+ WARN_CHAR = 01,
+ WARN_NUMBER = 02,
+ WARN_BREAK = 04,
+ WARN_DELIM = 010,
+ WARN_EL = 020,
+ WARN_SCALE = 040,
+ WARN_RANGE = 0100,
+ WARN_SYNTAX = 0200,
+ WARN_DI = 0400,
+ WARN_MAC = 01000,
+ WARN_REG = 02000,
+ WARN_TAB = 04000,
+ WARN_RIGHT_BRACE = 010000,
+ WARN_MISSING = 020000,
+ WARN_INPUT = 040000,
+ WARN_ESCAPE = 0100000,
+ WARN_SPACE = 0200000,
+ WARN_FONT = 0400000,
+ WARN_IG = 01000000
+ // change WARN_TOTAL if you add more warning types
+};
+
+const int WARN_TOTAL = 01777777;
+
+int warning(warning_type, const char *,
+ const errarg & = empty_errarg,
+ const errarg & = empty_errarg,
+ const errarg & = empty_errarg);
diff --git a/gnu/usr.bin/groff/troff/troff.man b/gnu/usr.bin/groff/troff/troff.man
new file mode 100644
index 0000000..25a7cc6
--- /dev/null
+++ b/gnu/usr.bin/groff/troff/troff.man
@@ -0,0 +1,2027 @@
+.\" -*- nroff -*-
+.\" define a string tx for the TeX logo
+.ie t .ds tx T\h'-.1667m'\v'.224m'E\v'-.224m'\h'-.125m'X
+.el .ds tx TeX
+.de TQ
+.br
+.ns
+.TP \\$1
+..
+.\" Like TP, but if specified indent is more than half
+.\" the current line-length - indent, use the default indent.
+.de Tp
+.ie \\n(.$=0:((0\\$1)*2u>(\\n(.lu-\\n(.iu)) .TP
+.el .TP "\\$1"
+..
+.\" The BSD man macros can't handle " in arguments to font change macros,
+.\" so use \(ts instead of ".
+.tr \(ts"
+.TH @G@TROFF 1 "@MDATE@" "Groff Version @VERSION@"
+.SH NAME
+@g@troff \- format documents
+.SH SYNOPSIS
+.nr a \n(.j
+.ad l
+.nr i \n(.i
+.in +\w'\fB@g@troff 'u
+.ti \niu
+.B @g@troff
+.de OP
+.ie \\n(.$-1 .RI "[\ \fB\\$1\fP" "\\$2" "\ ]"
+.el .RB "[\ " "\\$1" "\ ]"
+..
+.OP \-abivzCER
+.OP \-w name
+.OP \-W name
+.OP \-d cs
+.OP \-f fam
+.OP \-m name
+.OP \-n num
+.OP \-o list
+.OP \-r cn
+.OP \-T name
+.OP \-F dir
+.OP \-M dir
+.RI "[\ " files\|.\|.\|. "\ ]"
+.br
+.ad \na
+.SH DESCRIPTION
+This manual page describes the GNU version of
+.BR troff ,
+which is part of the groff document formatting system.
+It is highly compatible with Unix troff.
+Usually it should be invoked using the groff command, which will
+also run preprocessors and postprocessors in the appropriate
+order and with the appropriate options.
+.SH OPTIONS
+.TP \w'\-dname=s'u+2n
+.B \-a
+Generate an
+.SM ASCII
+approximation of the typeset output.
+.TP
+.B \-b
+Print a backtrace with each warning or error message. This backtrace
+should help track down the cause of the error. The line numbers given
+in the backtrace may not always correct: troff's idea of line numbers
+gets confused by
+.B as
+or
+.B am
+requests.
+.TP
+.B \-i
+Read the standard input after all the named input files have been
+processed.
+.TP
+.B \-v
+Print the version number.
+.TP
+.BI \-w name
+Enable warning
+.IR name .
+Available warnings are described in
+the Warnings subsection below.
+Multiple
+.B \-w
+options are allowed.
+.TP
+.BI \-W name
+Inhibit warning
+.IR name .
+Multiple
+.B \-W
+options are allowed.
+.TP
+.B \-E
+Inhibit all error messages.
+.TP
+.B \-z
+Suppress formatted output.
+.TP
+.B \-C
+Enable compatibility mode.
+.TP
+.BI \-d cs
+.TQ
+.BI \-d name = s
+Define
+.I c
+or
+.I name
+to be a string
+.IR s ;
+.I c
+must be a one letter name.
+.TP
+.BI \-f fam
+Use
+.I fam
+as the default font family.
+.TP
+.BI \-m name
+Read in the file
+.BI tmac. name\fR.
+Normally this will be searched for in @MACRODIR@.
+.TP
+.B \-R
+Don't load
+.BR troffrc .
+.TP
+.BI \-n num
+Number the first page
+.IR num .
+.TP
+.BI \-o list
+Output only pages in
+.IR list ,
+which is a comma-separated list of page ranges;
+.I n
+means print page
+.IR n ,
+.IB m \- n
+means print every page between
+.I m
+and
+.IR n ,
+.BI \- n
+means print every page up to
+.IR n ,
+.IB n \-
+means print every page from
+.IR n .
+.B Troff
+will exit after printing the last page in the list.
+.TP
+.BI \-r cn
+.TQ
+.BI \-r name = n
+Set number register
+.I c
+or
+.I name
+to
+.IR n ;
+.I c
+must be a one character name;
+.I n
+can be any troff numeric expression.
+.TP
+.BI \-T name
+Prepare output for device
+.IR name ,
+rather than the default
+.BR @DEVICE@ .
+.TP
+.BI \-F dir
+Search
+.I dir
+for subdirectories
+.BI dev name
+.RI ( name
+is the name of the device)
+for the
+.B DESC
+file and font files before the normal
+.BR @FONTDIR@ .
+.TP
+.BI \-M dir
+Search directory
+.I dir
+for macro files before the normal
+.BR @MACRODIR@ .
+.SH USAGE
+Only the features not in Unix troff are described here.
+.SS Long names
+The names of number registers, fonts, strings/macros/diversions,
+special characters can be of any length. In escape sequences, where
+you can use
+.BI ( xx
+for a two character name, you can use
+.BI [ xxx ]
+for a name of arbitrary length:
+.TP
+.BI \e[ xxx ]
+Print the special character called
+.IR xxx .
+.TP
+.BI \ef[ xxx ]
+Set font
+.IR xxx .
+.TP
+.BI \e*[ xxx ]
+Interpolate string
+.IR xxx .
+.TP
+.BI \en[ xxx ]
+Interpolate number register
+.IR xxx .
+.SS Fractional pointsizes
+A
+.I
+scaled point
+is equal to 1/sizescale
+points, where
+sizescale is specified in the
+.B DESC
+file (1 by default.)
+There is a new scale indicator
+.B z
+which has the effect of multiplying by sizescale.
+Requests and escape sequences in troff
+interpret arguments that represent a pointsize as being in units
+of scaled points, but they evaluate each such argument
+using a default scale indicator of
+.BR z .
+Arguments treated in this way are
+the argument to the
+.B ps
+request,
+the third argument to the
+.B cs
+request,
+the second and fourth arguments to the
+.B tkf
+request,
+the argument to the
+.B \eH
+escape sequence,
+and those variants of the
+.B \es
+escape sequence that take a numeric expression as their argument.
+.LP
+For example, suppose sizescale is 1000;
+then a scaled point will be equivalent to a millipoint;
+the request
+.B .ps 10.25
+is equivalent to
+.B .ps 10.25z
+and so sets the pointsize to 10250 scaled points,
+which is equal to 10.25 points.
+.LP
+The number register
+.B \en(.s
+returns the pointsize in points as decimal fraction.
+There is also a new number register
+.B \en[.ps]
+that returns the pointsize in scaled points.
+.LP
+It would make no sense to use the
+.B z
+scale indicator in a numeric expression
+whose default scale indicator was neither
+.B u
+nor
+.BR z ,
+and so
+.B troff
+disallows this.
+Similarly it would make no sense to use a scaling indicator
+other than
+.B z
+or
+.B u
+in a numeric expression whose default scale indicator was
+.BR z ,
+and so
+.B troff
+disallows this as well.
+.LP
+There is also new scale indicator
+.B s
+which multiplies by the number of units in a scaled point.
+So, for example,
+.B \en[.ps]s
+is equal to
+.BR 1m .
+Be sure not to confuse the
+.B s
+and
+.B z
+scale indicators.
+.SS Numeric expressions
+.LP
+Spaces are permitted in a number expression within parentheses.
+.LP
+.B M
+indicates a scale of 100ths of an em.
+.TP
+.IB e1 >? e2
+The maximum of
+.I e1
+and
+.IR e2 .
+.TP
+.IB e1 <? e2
+The minimum of
+.I e1
+and
+.IR e2 .
+.TP
+.BI ( c ; e )
+Evaluate
+.I e
+using
+.I c
+as the default scaling indicator.
+If
+.I c
+is missing, ignore scaling indicators in the evaluation of
+.IR e .
+.SS New escape sequences
+.TP
+.BI \eA' anything '
+This expands to
+.B 1
+or
+.B 0
+according as
+.I anything
+is or is not acceptable as the name of a string, macro, diversion,
+number register, environment or font.
+It will return
+.B 0
+if
+.I anything
+is empty.
+This is useful if you want to lookup user input in some sort of
+associative table.
+.TP
+.BI \eC' xxx '
+Typeset character named
+.IR xxx .
+Normally it is more convenient to use
+.BI \e[ xxx ]\fR.
+But
+.B \eC
+has the advantage that it is compatible with recent versions of
+.SM UNIX
+and is available in compatibility mode.
+.TP
+.B \eE
+This is equivalent to an escape character,
+but it's not interpreted in copy-mode.
+For example, strings to start and end superscripting could be defined
+like this:
+.RS
+.IP
+\&.ds { \ev'\-.3m'\es'\eEn[.s]*6u/10u'
+.br
+\&.ds } \es0\ev'.3m'
+.LP
+The use of
+.B \eE
+ensures that these definitions will work even if
+.B \e*{
+gets interpreted in copy-mode
+(for example, by being used in a macro argument.)
+.RE
+.TP
+.BI \eN' n '
+Typeset the character with code
+.I n
+in the current font.
+.I n
+can be any integer.
+Most devices only have characters with codes between 0 and 255.
+If the current font does not contain a character with that code,
+special fonts will
+.I not
+be searched.
+The
+.B \eN
+escape sequence can be conveniently used on conjunction with the
+.B char
+request:
+.RS
+.IP
+.B
+\&.char \e[phone] \ef(ZD\eN'37'
+.RE
+.IP
+The code of each character is given in the fourth column in the font
+description file after the
+.B charset
+command.
+It is possible to include unnamed characters in the font description
+file by using a name of
+.BR \-\-\- ;
+the
+.B \eN
+escape sequence is the only way to use these.
+.TP
+.BI \eR' name\ \(+-n '
+This has the same effect as
+.RS
+.IP
+.BI .nr\ name\ \(+-n
+.RE
+.TP
+.BI \es( nn
+.TQ
+.BI \es\(+-( nn
+Set the point size to
+.I nn
+points;
+.I nn
+must be exactly two digits.
+.TP
+.BI \es[\(+- n ]
+.TQ
+.BI \es\(+-[ n ]
+.TQ
+.BI \es'\(+- n '
+.TQ
+.BI \es\(+-' n '
+Set the point size to
+.I n
+scaled points;
+.I n
+is a numeric expression with a default scale indicator of
+.BR z .
+.TP
+.BI \eV x
+.TQ
+.BI \eV( xx
+.TQ
+.BI \eV[ xxx ]
+Interpolate the contents of the environment variable
+.I xxx ,
+as returned by
+.BR getenv (3).
+.B \eV
+is interpreted in copy-mode.
+.TP
+.BI \eY x
+.TQ
+.BI \eY( xx
+.TQ
+.BI \eY[ xxx ]
+This is approximately equivalent to
+.BI \eX'\e*[ xxx ]'\fR.
+However the contents of the string or macro
+.I xxx
+are not interpreted;
+also it is permitted for
+.I xxx
+to have been defined as a macro and thus contain newlines
+(it is not permitted for the argument to
+.B \eX
+to contain newlines).
+The inclusion of newlines requires an extension to the Unix troff output
+format, and will confuse drivers that do not know about this
+extension.
+.TP
+.BI \eZ' anything '
+Print anything and then restore the horizontal and vertical
+position;
+.I anything
+may not contain tabs or leaders.
+.TP
+.B \e$0
+The name by which the current macro was invoked.
+The
+.B als
+request can make a macro have more than one name.
+.TP
+.B \e$*
+In a macro, the concatenation of all the arguments separated by spaces.
+.TP
+.B \e$@
+In a macro, the concatenation of all the arguments with each surrounded by
+double quotes, and separated by spaces.
+.TP
+.BI \e$( nn
+.TQ
+.BI \e$[ nnn ]
+In a macro, this gives the
+.IR nn -th
+or
+.IR nnn -th
+argument.
+Macros can have a unlimited number of arguments.
+.TP
+.BI \e? anything \e?
+When used in a diversion, this will transparently embed
+.I anything
+in the diversion.
+.I anything
+is read in copy mode.
+When the diversion is reread,
+.I anything
+will be interpreted.
+.I anything
+may not contain newlines; use
+.B \e!
+if you want to embed newlines in a diversion.
+The escape sequence
+.B \e?
+is also recognised in copy mode and turned into a single internal
+code; it is this code that terminates
+.IR anything .
+Thus
+.RS
+.RS
+.ft B
+.nf
+.ne 15
+\&.nr x 1
+\&.nf
+\&.di d
+\e?\e\e?\e\e\e\e?\e\e\e\e\e\e\e\enx\e\e\e\e?\e\e?\e?
+\&.di
+\&.nr x 2
+\&.di e
+\&.d
+\&.di
+\&.nr x 3
+\&.di f
+\&.e
+\&.di
+\&.nr x 4
+\&.f
+.fi
+.ft
+.RE
+.RE
+.IP
+will print
+.BR 4 .
+.TP
+.B \e/
+This increases the width of the preceding character so that
+the spacing between that character and the following character
+will be correct if the following character is a roman character.
+For example, if an italic f is immediately followed by a roman
+right parenthesis, then in many fonts the top right portion of the f
+will overlap the top left of the right parenthesis producing \fIf\fR)\fR,
+which is ugly.
+Inserting
+.B \e/
+produces
+.ie \n(.g \fIf\/\fR)\fR
+.el \fIf\|\fR)\fR
+and avoids this problem.
+It is a good idea to use this escape sequence whenever an
+italic character is immediately followed by a roman character without any
+intervening space.
+.TP
+.B \e,
+This modifies the spacing of the following character so that the spacing
+between that character and the preceding character will correct if
+the preceding character is a roman character.
+For example, inserting
+.B \e,
+between the parenthesis and the f changes
+\fR(\fIf\fR to
+.ie \n(.g \fR(\,\fIf\fR.
+.el \fR(\^\fIf\fR.
+It is a good idea to use this escape sequence whenever a
+roman character is immediately followed by an italic character without any
+intervening space.
+.TP
+.B \e)
+Like
+.B \e&
+except that it behaves like a character declared with the
+.B cflags
+request to be transparent for the purposes of end of sentence recognition.
+.TP
+.B \e~
+This produces an unbreakable space that stretches like a normal inter-word
+space when a line is adjusted.
+.TP
+.B \e#
+Everything up to and including the next newline is ignored.
+This is interpreted in copy mode.
+This is like
+.B \e%
+except that
+.B \e%
+does not ignore the terminating newline.
+.SS New requests
+.TP
+.BI .aln\ xx\ yy
+Create an alias
+.I xx
+for number register object named
+.IR yy .
+The new name and the old name will be exactly equivalent.
+If
+.I yy
+is undefined, a warning of type
+.B reg
+will be generated, and the request will be ignored.
+.TP
+.BI .als\ xx\ yy
+Create an alias
+.I xx
+for request, string, macro, or diversion object named
+.IR yy .
+The new name and the old name will be exactly equivalent (it is similar to a
+hard rather than a soft link).
+If
+.I yy
+is undefined, a warning of type
+.B mac
+will be generated, and the request will be ignored.
+The
+.BR de ,
+.BR am ,
+.BR di ,
+.BR da ,
+.BR ds ,
+and
+.B as
+requests only create a new object if the name of the macro, diversion
+or string diversion is currently undefined or if it is defined to be a
+request; normally they modify the value of an existing object.
+.TP
+.BI .asciify\ xx
+This request only exists in order to make it possible
+to make certain gross hacks work with GNU troff.
+It `unformats' the diversion
+.I xx
+in such a way that
+.SM ASCII
+characters that were formatted and diverted into
+.I xx
+will be treated like ordinary input characters when
+.I xx
+is reread.
+For example, this
+.RS
+.IP
+.ne 7v+\n(.Vu
+.ft B
+.nf
+.ss 24
+\&.tr @.
+\&.di x
+\&@nr\e n\e 1
+\&.br
+\&.di
+\&.tr @@
+\&.asciify x
+\&.x
+.ss 12
+.fi
+.RE
+.IP
+will set register
+.B n
+to 1.
+.TP
+.B .backtrace
+Print a backtrace of the input stack on stderr.
+.TP
+.B .break
+Break out of a while loop.
+See also the
+.B while
+and
+.B continue
+requests.
+Be sure not to confuse this with the
+.B br
+request.
+.TP
+.BI .cflags\ n\ c1\ c2\|.\|.\|.
+Characters
+.IR c1 ,
+.IR c2 ,\|.\|.\|.
+have properties determined by
+.IR n ,
+which is ORed from the following:
+.RS
+.TP
+1
+the character ends sentences
+(initially characters
+.B .?!
+have this property);
+.TP
+2
+lines can be broken before the character
+(initially no characters have this property);
+a line will not be broken at a character with this property
+unless the characters on each side both have non-zero
+hyphenation codes.
+.TP
+4
+lines can be broken after the character
+(initially characters
+.B \-\e(hy\e(em
+have this property);
+a line will not be broken at a character with this property
+unless the characters on each side both have non-zero
+hyphenation codes.
+.TP
+8
+the character overlaps horizontally
+(initially characters
+.B \e(ul\e(rn\e(ru
+have this property);
+.TP
+16
+the character overlaps vertically
+(initially character
+.B \e(br
+has this property);
+.TP
+32
+an end of sentence character followed by any number of characters
+with this property will be treated
+as the end of a sentence if followed by a newline or two spaces;
+in other words
+the character is transparent for the purposes of end of sentence
+recognition;
+this is the same as having a zero space factor in \*(tx
+(initially characters
+.B \(ts')]*\e(dg\e(rq
+have this property).
+.RE
+.TP
+.BI .char\ c\ string
+Define character
+.I c
+to be
+.IR string .
+Every time character
+.I c
+needs to be printed,
+.I string
+will be processed in a temporary environment and the result
+will be wrapped up into a single object.
+Compatibility mode will be turned off
+and the escape character will be set to
+.B \e
+while
+.I string
+is being processed.
+Any emboldening, constant spacing or track kerning will be applied
+to this object rather than to individual characters in
+.IR string .
+A character defined by this request can be used just like
+a normal character provided by the output device.
+In particular other characters can be translated to it
+with the
+.B tr
+request;
+it can be made the leader character by the
+.B lc
+request;
+repeated patterns can be drawn with the character using the
+.B \el
+and
+.B \eL
+escape sequences;
+words containing the character can be hyphenated
+correctly, if the
+.B hcode
+request is used to give the character a hyphenation code.
+There is a special anti-recursion feature:
+use of character within the character's definition
+will be handled like normal characters not defined with
+.BR char .
+A character definition can be removed with the
+.B rchar
+request.
+.TP
+.BI .chop\ xx
+Chop the last character off macro, string, or diversion
+.IR xx .
+This is useful for removing the newline from the end of diversions
+that are to be interpolated as strings.
+.TP
+.BI .close\ stream
+Close the stream named
+.IR stream ;
+.I stream
+will no longer be an acceptable argument to the
+.B write
+request.
+See the
+.B open
+request.
+.TP
+.B .continue
+Finish the current iteration of a while loop.
+See also the
+.B while
+and
+.B break
+requests.
+.TP
+.BI .cp\ n
+If
+.I n
+is non-zero or missing, enable compatibility mode, otherwise
+disable it.
+In compatibility mode, long names are not recognised, and the
+incompatibilities caused by long names do not arise.
+.TP
+.BI .do\ xxx
+Interpret
+.I .xxx
+with compatibility mode disabled.
+For example,
+.RS
+.IP
+.B
+\&.do fam T
+.LP
+would have the same effect as
+.IP
+.B
+\&.fam T
+.LP
+except that it would work even if compatibility mode had been enabled.
+Note that the previous compatibility mode is restored before any files
+sourced by
+.I xxx
+are interpreted.
+.RE
+.TP
+.BI .fam\ xx
+Set the current font family to
+.IR xx .
+The current font family is part of the current environment.
+See the description of the
+.B sty
+request for more information on font families.
+.TP
+.BI .fspecial\ f\ s1\ s2\|.\|.\|.
+When the current font is
+.IR f ,
+fonts
+.IR s1 ,
+.IR s2 ,\|.\|.\|.
+will be special, that is, they will searched for characters not in
+the current font.
+Any fonts specified in the
+.B special
+request will be searched after fonts specified in the
+.B fspecial
+request.
+.TP
+.BI .ftr\ f\ g
+Translate font
+.I f
+to
+.IR g .
+Whenever a font named
+.I f
+is referred to in
+.B \ef
+escape sequence,
+or in the
+.BR ft ,
+.BR ul ,
+.BR bd ,
+.BR cs ,
+.BR tkf ,
+.BR special ,
+.BR fspecial ,
+.BR fp ,
+or
+.BR sty
+requests,
+font
+.I g
+will be used.
+If
+.I g
+is missing,
+or equal to
+.I f
+then font
+.I f
+will not be translated.
+.TP
+.BI .hcode \ c1\ code1\ c2\ code2\|.\|.\|.
+Set the hyphenation code of character
+.I c1
+to
+.I code1
+and that of
+.I c2
+to
+.IR code2 .
+A hyphenation code must be a single input
+character (not a special character) other than a digit or a space.
+Initially each lower-case letter has a hyphenation code, which
+is itself, and each upper-case letter has a hyphenation code
+which is the lower case version of itself.
+See also the
+.B hpf
+request.
+.TP
+.BI .hla\ lang
+Set the current hyphenation language to
+.IR lang .
+Hyphenation exceptions specified with the
+.B hw
+request and hyphenation patterns specified with the
+.B hpf
+request are both associated with the current hyphenation language.
+The
+.B hla
+request is usually invoked by the
+.B troffrc
+file.
+.TP
+.BI .hlm\ n
+Set the maximum number of consecutive hyphenated lines to
+.IR n .
+If
+.I n
+is negative, there is no maximum.
+The default value is \-1.
+This value is associated with the current environment.
+Only lines output from an environment count towards the maximum associated
+with that environment.
+Hyphens resulting from
+.B \e%
+are counted; explicit hyphens are not.
+.TP
+.BI .hpf\ file
+Read hyphenation patterns from
+.IR file ;
+this will be searched for in the same way that
+.BI tmac. name
+is searched for when the
+.BI \-m name
+option is specified.
+It should have the same format as the argument to
+the \epatterns primitive in \*(tx;
+the letters appearing in this file are interpreted as hyphenation
+codes.
+A
+.B %
+character in the patterns file introduces a comment that continues
+to the end of the line.
+The set of hyphenation patterns is associated with the current language
+set by the
+.B hla
+request.
+The
+.B hpf
+request
+is usually invoked by the
+.B troffrc
+file.
+.TP
+.BI .hym\ n
+Set the
+.I hyphenation margin
+to
+.IR n :
+when the current adjustment mode is not
+.BR b ,
+the line will not be hyphenated if the line is no more than
+.I n
+short.
+The default hyphenation margin is 0.
+The default scaling indicator for this request is
+.IR m .
+The hyphenation margin is associated with the current environment.
+The current hyphenation margin is available in the
+.B \en[.hym]
+register.
+.TP
+.BI .hys\ n
+Set the
+.I hyphenation space
+to
+.IR n :
+when the current adjustment mode is
+.B b
+don't hyphenate the line if the line can be justified by adding no more than
+.I n
+extra space to each word space.
+The default hyphenation space is 0.
+The default scaling indicator for this request is
+.BR m .
+The hyphenation space is associated with the current environment.
+The current hyphenation space is available in the
+.B \en[.hys]
+register.
+.TP
+.BI .kern\ n
+If
+.I n
+is non-zero or missing, enable pairwise kerning, otherwise disable it.
+.TP
+.BI .mso\ file
+The same as the
+.B so
+request except that
+.I file
+is searched for in the same way that
+.BI tmac. name
+is searched for when the
+.BI \-m name
+option is specified.
+.TP
+.B .nroff
+Make the
+.B n
+built-in condition true
+and the
+.B t
+built-in condition false.
+This can be reversed using the
+.B troff
+request.
+.TP
+.BI .open\ stream\ filename
+Open
+.I filename
+for writing and associate the stream named
+.I stream
+with it.
+See also the
+.B close
+and
+.B write
+requests.
+.TP
+.BI .opena\ stream\ filename
+Like
+.BR open ,
+but if
+.I filename
+exists, append to it instead of truncating it.
+.TP
+.B .pnr
+Print the names and contents of all currently defined number registers
+on stderr.
+.TP
+.BI .pso \ command
+This is behaves like the
+.B so
+request except that input comes from the standard output of
+.IR command .
+.TP
+.B .ptr
+Print the names and positions of all traps (not including input line
+traps and diversion traps) on stderr. Empty slots in the page trap
+list are printed as well, because they can affect the priority of
+subsequently planted traps.
+.TP
+.BI .rchar\ c1\ c2\|.\|.\|.
+Remove the definitions of characters
+.IR c1 ,
+.IR c2 ,\|.\|.\|.
+This undoes the effect of a
+.B char
+request.
+.TP
+.B .rj
+.TQ
+.BI .rj\ n
+Right justify the next
+.I n
+input lines.
+Without an argument right justify the next input line.
+The number of lines to be right justified is available in the
+.B \en[.rj]
+register.
+This implicitly does
+.BR .ce\ 0 .
+The
+.B ce
+request implicitly does
+.BR .rj\ 0 .
+.TP
+.BI .rnn \ xx\ yy
+Rename number register
+.I xx
+to
+.IR yy .
+.TP
+.BI .shc\ c
+Set the soft hyphen character to
+.IR c .
+If
+.I c
+is omitted,
+the soft hyphen character will be set to the default
+.BR \e(hy .
+The soft hyphen character is the character which will be inserted
+when a word is hyphenated at a line break.
+If the soft hyphen character does not exist in the font of the character
+immediately preceding a potential break point,
+then the line will not be broken at that point.
+Neither definitions (specified with the
+.B char
+request)
+nor translations (specified with the
+.B tr
+request)
+are considered when finding the soft hyphen character.
+.TP
+.BI .shift\ n
+In a macro, shift the arguments by
+.I n
+positions:
+argument
+.I i
+becomes argument
+.IR i \- n ;
+arguments 1 to
+.I n
+will no longer be available.
+If
+.I n
+is missing,
+arguments will be shifted by 1.
+Shifting by negative amounts is currently undefined.
+.TP
+.BI .special\ s1\ s2\|.\|.\|.
+Fonts
+.IR s1 ,
+.IR s2 ,
+are special and will be searched for characters not in the
+current font.
+.TP
+.BI .sty\ n\ f
+Associate style
+.I f
+with font position
+.IR n .
+A font position can be associated either with a font or
+with a style.
+The current font is the index of a font position and so is also
+either a font or a style.
+When it is a style, the font that is actually used is the font the
+name of which is the concatenation of the name of the current family
+and the name of the current style.
+For example, if the current font is 1 and font position 1 is
+associated with style
+.B R
+and the current
+font family is
+.BR T ,
+then font
+.BR TR
+will be used.
+If the current font is not a style, then the current family is ignored.
+When the requests
+.BR cs ,
+.BR bd ,
+.BR tkf ,
+.BR uf ,
+or
+.B fspecial
+are applied to a style,
+then they will instead be applied to the member of the
+current family corresponding to that style.
+The default family can be set with the
+.B \-f
+option.
+The styles command in the
+.SM DESC
+file controls which font positions
+(if any) are initially associated with styles rather than fonts.
+.TP
+.BI .tkf\ f\ s1\ n1\ s2\ n2
+Enable track kerning for font
+.IR f .
+When the current font is
+.I f
+the width of every character will be increased by an amount
+between
+.I n1
+and
+.IR n2 ;
+when the current point size is less than or equal to
+.I s1
+the width will be increased by
+.IR n1 ;
+when it is greater than or equal to
+.I s2
+the width will be increased by
+.IR n2 ;
+when the point size is greater than or equal to
+.I s1
+and less than or equal to
+.I s2
+the increase in width is a linear function of the point size.
+.TP
+.BI .trf\ filename
+Transparently output the contents of file
+.IR filename .
+Each line is output as it would be were it preceded by
+.BR \e! ;
+however, the lines are not subject to copy-mode interpretation.
+If the file does not end with a newline, then a newline will
+be added.
+For example, you can define a macro
+.I x
+containing the contents of file
+.IR f ,
+using
+.RS
+.IP
+.BI .di\ x
+.br
+.BI .trf\ f
+.br
+.B .di
+.LP
+Unlike with the
+.B cf
+request,
+the file cannot contain characters such as
+.SM NUL
+that are not legal troff input characters.
+.RE
+.TP
+.B .trnt abcd
+This is the same as the
+.B tr
+request except that the translations do not apply to text that is
+transparently throughput into a diversion with
+.BR \e! .
+For example,
+.RS
+.LP
+.nf
+.ft B
+\&.tr ab
+\&.di x
+\e!.tm a
+\&.di
+\&.x
+.fi
+.ft
+.LP
+will print
+.BR b ;
+if
+.B trnt
+is used instead of
+.B tr
+it will print
+.BR a .
+.RE
+.TP
+.B .troff
+Make the
+.B n
+built-in condition false,
+and the
+.B t
+built-in condition true.
+This undoes the effect of the
+.B nroff
+request.
+.TP
+.BI .vpt\ n
+Enable vertical position traps if
+.I n
+is non-zero, disable them otherwise.
+Vertical position traps are traps set by the
+.B wh
+or
+.B dt
+requests.
+Traps set by the
+.B it
+request are not vertical position traps.
+The parameter that controls whether vertical position traps are enabled
+is global.
+Initially vertical position traps are enabled.
+.TP
+.BI .warn\ n
+Control warnings.
+.I n
+is the sum of the numbers associated with each warning that is to be enabled;
+all other warnings will be disabled.
+The number associated with each warning is listed in the `Warnings' section.
+For example,
+.B .warn 0
+will disable all warnings, and
+.B .warn 1
+will disable all warnings except that about missing characters.
+If
+.I n
+is not given,
+all warnings will be enabled.
+.TP
+.BI .while \ c\ anything
+While condition
+.I c
+is true, accept
+.I anything
+as input;
+.I c
+can be any condition acceptable to an
+.B if
+request;
+.I anything
+can comprise multiple lines if the first line starts with
+.B \e{
+and the last line ends with
+.BR \e} .
+See also the
+.B break
+and
+.B continue
+requests.
+.TP
+.BI .write\ stream\ anything
+Write
+.I anything
+to the stream named
+.IR stream .
+.I stream
+must previously have been the subject of an
+.B open
+request.
+.I anything
+is read in copy mode;
+a leading
+.B \(ts
+will be stripped.
+.SS Extended requests
+.TP
+.BI .cf\ filename
+When used in a diversion, this will embed in the diversion an object which,
+when reread, will cause the contents of
+.I filename
+to be transparently copied through to the output.
+In Unix troff, the
+contents of
+.I filename
+is immediately copied through to the output regardless of whether
+there is a current diversion; this behavior is so anomalous that it
+must be considered a bug.
+.TP
+.BI .ev\ xx
+If
+.I xx
+is not a number, this will switch to a named environment called
+.IR xx .
+The environment should be popped with a matching
+.B ev
+request without any arguments, just as for numbered environments.
+There is no limit on the number of named environments; they will be
+created the first time that they are referenced.
+.TP
+.BI .fp\ n\ f1\ f2
+The
+.B fp
+request has an optional third argument.
+This argument gives the external name of the font,
+which is used for finding the font description file.
+The second argument gives the internal name of the font
+which is used to refer to the font in troff after it has been mounted.
+If there is no third argument then the internal name will be used
+as the external name.
+This feature allows you to use fonts with long names in compatibility mode.
+.TP
+.BI .ss\ m\ n
+When two arguments are given to the
+.B ss
+request, the second argument gives the
+.IR "sentence space size" .
+If the second argument is not given, the sentence space size
+will be the same as the word space size.
+Like the word space size, the sentence space is in units of
+one twelfth of the spacewidth parameter for the current font.
+Initially both the word space size and the sentence
+space size are 12.
+The sentence space size is used in two circumstances:
+if the end of a sentence occurs at the end of a line in fill mode, then
+both an inter-word space and a sentence space will be added;
+if two spaces follow the end of a sentence in the middle of a line,
+then the second space will be a sentence space.
+Note that the behavior of Unix troff will be exactly
+that exhibited by GNU troff if a second argument is never given to the
+.B ss
+request.
+In GNU troff, as in Unix troff, you should always
+follow a sentence with either a newline or two spaces.
+.TP
+.BI .ta\ n1\ n2\|.\|.\|.nn \ T\ r1\ r2\|.\|.\|.\|rn
+Set tabs at positions
+.IR n1 ,
+.IR n2 ,\|.\|.\|.\|,
+.I nn
+and then set tabs at
+.IR nn + r1 ,
+.IR nn + r2 ,\|.\|.\|.\|.\|,
+.IR nn + rn
+and then at
+.IR nn + rn + r1 ,
+.IR nn + rn + r2 ,\|.\|.\|.\|,
+.IR nn + rn + rn ,
+and so on.
+For example,
+.RS
+.IP
+.B
+\&.ta T .5i
+.LP
+will set tabs every half an inch.
+.RE
+.SS New number registers
+The following read-only registers are available:
+.TP
+.B \en[.C]
+1 if compatibility mode is in effect, 0 otherwise.
+.TP
+.B \en[.cdp]
+The depth of the last character added to the current environment.
+It is positive if the character extends below the baseline.
+.TP
+.B \en[.ce]
+The number of lines remaining to be centered, as set by the
+.B ce
+request.
+.TP
+.B \en[.cht]
+The height of the last character added to the current environment.
+It is positive if the character extends above the baseline.
+.TP
+.B \en[.csk]
+The skew of the last character added to the current environment.
+The
+.I skew
+of a character is how far to the right of the center of a character
+the center of an accent over that character should be placed.
+.TP
+.B \en[.ev]
+The name or number of the current environment.
+This is a string-valued register.
+.TP
+.B \en[.fam]
+The current font family.
+This is a string-valued register.
+.TP
+.B \en[.fp]
+The number of the next free font position.
+.TP
+.B \en[.g]
+Always 1.
+Macros should use this to determine whether they are running
+under GNU troff.
+.TP
+.B \en[.hla]
+The current hyphenation language as set by the
+.B hla
+request.
+.TP
+.B \en[.hlc]
+The number of immediately preceding consecutive hyphenated lines.
+.TP
+.B \en[.hlm]
+The maximum allowed number of consecutive hyphenated lines, as set by the
+.B hlm
+request.
+.TP
+.B \en[.hy]
+The current hyphenation flags (as set by the
+.B hy
+request.)
+.TP
+.B \en[.hym]
+The current hyphenation margin (as set by the
+.B hym
+request.)
+.TP
+.B \en[.hys]
+The current hyphenation space (as set by the
+.B hys
+request.)
+.TP
+.B \en[.in]
+The indent that applies to the current output line.
+.TP
+.B \en[.kern]
+.B 1
+if pairwise kerning is enabled,
+.B 0
+otherwise.
+.TP
+.B \en[.lg]
+The current ligature mode (as set by the
+.B lg
+request.)
+.TP
+.B \en[.ll]
+The line length that applies to the current output line.
+.TP
+.B \en[.lt]
+The title length as set by the
+.B lt
+request.
+.TP
+.B \en[.ne]
+The amount of space that was needed in the last
+.B ne
+request that caused a trap to be sprung.
+Useful in conjunction with the
+.B \en[.trunc]
+register.
+.TP
+.B \en[.pn]
+The number of the next page:
+either the value set by a
+.B pn
+request, or the number of the current page plus 1.
+.TP
+.B \en[.ps]
+The current pointsize in scaled points.
+.TP
+.B \en[.psr]
+The last-requested pointsize in scaled points.
+.TP
+.B \en[.rj]
+The number of lines to be right-justified as set by the
+.B rj
+request.
+.TP
+.B \en[.sr]
+The last requested pointsize in points as a decimal fraction.
+This is a string-valued register.
+.TP
+.B \en[.tabs]
+A string representation of the current tab settings suitable for use as
+an argument to the
+.B ta
+request.
+.TP
+.B \en[.trunc]
+The amount of vertical space truncated by the most recently sprung
+vertical position trap, or,
+if the trap was sprung by a
+.B ne
+request,
+minus the amount of vertical motion produced by the
+.B ne
+request.
+In other words, at the point a trap is sprung, it represents the difference
+of what the vertical position would have been but for the trap,
+and what the vertical position actually is.
+Useful in conjunction with the
+.B \en[.ne]
+register.
+.TP
+.B \en[.ss]
+.TQ
+.B \en[.sss]
+These give the values of the parameters set by the
+first and second arguments of the
+.B ss
+request.
+.TP
+.B \en[.vpt]
+1 if vertical position traps are enabled, 0 otherwise.
+.TP
+.B \en[.warn]
+The sum of the numbers associated with each of the currently enabled
+warnings.
+The number associated with each warning is listed in the `Warnings'
+subsection.
+.TP
+.B \en(.x
+The major version number.
+For example, if the version number is
+.B 1.03
+then
+.B \en(.x
+will contain
+.BR 1 .
+.TP
+.B \en(.y
+The minor version number.
+For example, if the version number is
+.B 1.03
+then
+.B \en(.y
+will contain
+.BR 03 .
+.LP
+The following registers are set by the
+.B \ew
+escape sequence:
+.TP
+.B \en[rst]
+.TQ
+.B \en[rsb]
+Like the
+.B st
+and
+.B sb
+registers, but takes account of the heights and depths of characters.
+.TP
+.B \en[ssc]
+The amount of horizontal space (possibly negative) that should
+be added to the last character before a subscript.
+.TP
+.B \en[skw]
+How far to right of the center of the last character
+in the
+.B \ew
+argument,
+the center of an accent from a roman font should be placed over that character.
+.LP
+The following read/write number registers are available:
+.TP
+.B \en[systat]
+The return value of the system() function executed by the last
+.B sy
+request.
+.TP
+.B \en[slimit]
+If greater than 0, the maximum number of objects on the input stack.
+If less than or equal to 0, there is no limit on the number of objects
+on the input stack. With no limit, recursion can continue until
+virtual memory is exhausted.
+.SS Miscellaneous
+.LP
+Fonts not listed in the
+.SM DESC
+file are automatically mounted on the next available font position
+when they are referenced.
+If a font is to be mounted explicitly with the
+.B fp
+request on an unused font position,
+it should be mounted on the first unused font position,
+which can be found in the
+.B \en[.fp]
+register;
+although
+.B troff
+does not enforce this strictly,
+it will not allow a font to be mounted at a position whose number is much
+greater than that of any currently used position.
+.LP
+Interpolating a string does not hide existing macro arguments.
+Thus in a macro, a more efficient way of doing
+.IP
+.BI . xx\ \e\e$@
+.LP
+is
+.IP
+.BI \e\e*[ xx ]\e\e
+.LP
+If the font description file contains pairwise kerning information,
+characters from that font will be kerned.
+Kerning between two characters can be inhibited by placing a
+.B \e&
+between them.
+.LP
+In a string comparison in a condition,
+characters that appear at different input levels
+to the first delimiter character will not be recognised
+as the second or third delimiters.
+This applies also to the
+.B tl
+request.
+In a
+.B \ew
+escape sequence,
+a character that appears at a different input level to
+the starting delimiter character will not be recognised
+as the closing delimiter character.
+When decoding a macro argument that is delimited
+by double quotes, a character that appears at a different
+input level to the starting delimiter character will not
+be recognised as the closing delimiter character.
+The implementation of
+.B \e$@
+ensures that the double quotes surrounding an argument
+will appear the same input level, which will be different
+to the input level of the argument itself.
+In a long escape name
+.B ]
+will not be recognized as a closing delimiter except
+when it occurs at the same input level as the opening
+.BR ] .
+In compatibility mode, no attention is paid to the input-level.
+.LP
+There are some new types of condition:
+.TP
+.BI .if\ r xxx
+True if there is a number register named
+.IR xxx .
+.TP
+.BI .if\ d xxx
+True if there is a string, macro, diversion, or request named
+.IR xxx .
+.TP
+.BI .if\ c ch
+True if there is a character
+.IR ch
+available;
+.I ch
+is either an
+.SM ASCII
+character
+or a special character
+.BI \e( xx
+or
+.BI \e[ xxx ]\fR;
+the condition will also be true if
+.I ch
+has been defined by the
+.B char
+request.
+.SS Warnings
+The warnings that can be given by
+.B troff
+are divided into the following categories.
+The name associated with each warning is used by the
+.B \-w
+and
+.B \-W
+options;
+the number is used by the
+.B warn
+request, and by the
+.B .warn
+register.
+.nr x \w'\fBright-brace'+1n+\w'0000'u
+.ta \nxuR
+.TP \nxu+3n
+.BR char \t1
+Non-existent characters.
+This is enabled by default.
+.TP
+.BR number \t2
+Invalid numeric expressions.
+This is enabled by default.
+.TP
+.BR break \t4
+In fill mode, lines which could not be broken so that their length was
+less than the line length.
+This is enabled by default.
+.TP
+.BR delim \t8
+Missing or mismatched closing delimiters.
+.TP
+.BR el \t16
+Use of the
+.B el
+request with no matching
+.B ie
+request.
+.TP
+.BR scale \t32
+Meaningless scaling indicators.
+.TP
+.BR range \t64
+Out of range arguments.
+.TP
+.BR syntax \t128
+Dubious syntax in numeric expressions.
+.TP
+.BR di \t256
+Use of
+.B di
+or
+.B da
+without an argument when there is no current diversion.
+.TP
+.BR mac \t512
+Use of undefined strings, macros and diversions.
+When an undefined string, macro or diversion is used,
+that string is automatically defined as empty.
+So, in most cases, at most one warning will be given for
+each name.
+.TP
+.BR reg \t1024
+Use of undefined number registers.
+When an undefined number register is used,
+that register is automatically defined to have a value of 0.
+a definition is automatically made with a value of 0.
+So, in most cases, at most one warning will be given for
+use of a particular name.
+.TP
+.BR tab \t2048
+Inappropriate use of a tab character.
+Either use of a tab character where a number was expected,
+or use of tab character in an unquoted macro argument.
+.TP
+.BR right-brace \t4096
+Use of
+.B \e}
+where a number was expected.
+.TP
+.BR missing \t8192
+Requests that are missing non-optional arguments.
+.TP
+.BR input \t16384
+Illegal input characters.
+.TP
+.BR escape \t32768
+Unrecognized escape sequences.
+When an unrecognized escape sequence is encountered,
+the escape character is ignored.
+.TP
+.BR space \t65536
+Missing space between a request or macro and its argument.
+This warning will be given
+when an undefined name longer than two characters is encountered,
+and the first two characters of the name make a defined name.
+The request or macro will not be invoked.
+When this warning is given, no macro is automatically defined.
+This is enabled by default.
+This warning will never occur in compatibility mode.
+.TP
+.BR font \t131072
+Non-existent fonts.
+This is enabled by default.
+.TP
+.BR ig \t262144
+Illegal escapes in text ignored with the
+.B ig
+request.
+These are conditions that are errors when they do not occur
+in ignored text.
+.LP
+There are also names that can be used to refer to groups of warnings:
+.TP
+.B all
+All warnings except
+.BR di ,
+.B mac
+and
+.BR reg .
+It is intended that this covers all warnings
+that are useful with traditional macro packages.
+.TP
+.B w
+All warnings.
+.SS Incompatibilities
+.LP
+Long names cause some incompatibilities.
+Unix troff will interpret
+.IP
+.B
+\&.dsabcd
+.LP
+as defining a string
+.B ab
+with contents
+.BR cd .
+Normally, GNU troff will interpret this as a call of a macro named
+.BR dsabcd .
+Also Unix troff will interpret
+.B \e*[
+or
+.B \en[
+as references to a string or number register called
+.BR [ .
+In GNU troff, however, this will normally be interpreted as the start
+of a long name.
+In
+.I compatibility mode
+GNU troff will interpret these things in the traditional way.
+In compatibility mode, however, long names are not recognised.
+Compatibility mode can be turned on with the
+.B \-C
+command line option, and turned on or off with the
+.B cp
+request.
+The number register
+.B \en(.C
+is 1 if compatibility mode is on, 0 otherwise.
+.LP
+GNU troff
+does not allow the use of the escape sequences
+.BR \\e\e|\e^\e&\e}\e{\e (space) \e'\e`\e-\e_\e!\e%\ec
+in names of strings, macros, diversions, number registers,
+fonts or environments; Unix troff does.
+The
+.B \eA
+escape sequence may be helpful in avoiding use of these
+escape sequences in names.
+.LP
+Fractional pointsizes cause one noteworthy incompatibility.
+In Unix troff the
+.B ps
+request ignores scale indicators and so
+.IP
+.B .ps\ 10u
+.LP
+will set the pointsize to 10 points, whereas in
+GNU troff it will set the pointsize to 10 scaled points.
+.LP
+In GNU troff there is a fundamental difference between unformatted,
+input characters, and formatted, output characters.
+Everything that affects how an output character
+will be output is stored with the character; once an output
+character has been constructed it is unaffected by any subsequent
+requests that are executed, including
+.BR bd ,
+.BR cs ,
+.BR tkf ,
+.BR tr ,
+or
+.B fp
+requests.
+Normally output characters are constructed from input
+characters at the moment immediately before the character
+is added to the current output line.
+Macros, diversions and strings are all, in fact, the same type
+of object; they contain lists of input characters and output
+characters in any combination.
+An output character does not behave like an input character
+for the purposes of macro processing; it does not inherit any
+of the special properties that the input character from which it
+was constructed might have had.
+For example,
+.IP
+.nf
+.ft B
+\&.di x
+\e\e\e\e
+\&.br
+\&.di
+\&.x
+.ft
+.fi
+.LP
+will print
+.B \e\e
+in GNU troff;
+each pair of input
+.BR \e s
+is turned into one output
+.B \e
+and the resulting output
+.BR \e s
+are not interpreted as escape characters when they are reread.
+Unix troff would interpret them as escape characters
+when they were reread and would end up printing one
+.BR \e .
+The correct way to obtain a printable
+.B \e
+is to use the
+.B \ee
+escape sequence: this will always print a single instance of the
+current escape character, regardless of whether or not it is used in a
+diversion; it will also work in both GNU troff and Unix troff.
+If you wish for some reason to store in a diversion an escape
+sequence that will be interpreted when the diversion is reread,
+you can either use the traditional
+.B \e!
+transparent output facility, or, if this is unsuitable, the new
+.B \e?
+escape sequence.
+.SH ENVIRONMENT
+.TP
+.SM
+.B GROFF_TMAC_PATH
+A colon separated list of directories in which to search for
+macro files.
+.TP
+.SM
+.B GROFF_TYPESETTER
+Default device.
+.TP
+.SM
+.B GROFF_FONT_PATH
+A colon separated list of directories in which to search for the
+.BI dev name
+directory.
+.B troff
+will search in directories given in the
+.B \-F
+option before these, and in standard directories
+.RB ( @FONTPATH@ )
+after these.
+.SH FILES
+.Tp \w'@FONTDIR@/devname/DESC'u+3n
+.B @MACRODIR@/troffrc
+Initialization file
+.TP
+.BI @MACRODIR@/tmac. name
+Macro files
+.TP
+.BI @FONTDIR@/dev name /DESC
+Device description file for device
+.IR name .
+.TP
+.BI @FONTDIR@/dev name / F
+Font file for font
+.I F
+of device
+.IR name .
+.SH "SEE ALSO"
+.BR groff (@MAN1EXT@)
+.BR @g@tbl (@MAN1EXT@),
+.BR @g@pic (@MAN1EXT@),
+.BR @g@eqn (@MAN1EXT@),
+.BR grops (@MAN1EXT@),
+.BR grodvi (@MAN1EXT@),
+.BR grotty (@MAN1EXT@),
+.BR groff_font (@MAN5EXT@),
+.BR groff_out (@MAN5EXT@),
+.BR groff_char (@MAN7EXT@)
diff --git a/gnu/usr.bin/groff/xditview/ChangeLog b/gnu/usr.bin/groff/xditview/ChangeLog
new file mode 100644
index 0000000..df19a85
--- /dev/null
+++ b/gnu/usr.bin/groff/xditview/ChangeLog
@@ -0,0 +1,274 @@
+Sat Feb 12 10:38:47 1994 James Clark (jjc@jclark.com)
+
+ * DviChar.c (Adobe_Symbol_map): Rename radicalex to rn.
+
+Thu May 27 20:30:12 1993 James Clark (jjc@jclark.com)
+
+ * device.c (isascii): Define if necessary.
+ (canonicalize_name): Cast argument to isdigit() to unsigned char.
+
+Thu Apr 29 18:36:57 1993 James Clark (jjc at jclark.com)
+
+ * xditview.c: Include <X11/Xos.h>.
+ (NewFile): Don't declare rindex(). Use strrchr() rather than
+ rindex().
+
+Tue Mar 30 15:12:09 1993 James Clark (jjc at jclark)
+
+ * draw.c (charExists): Check that fi->per_char is not NULL.
+
+Sat Dec 12 17:42:40 1992 James Clark (jjc at jclark)
+
+ * Dvi.c (SetGeometry): Cast XtMakeGeometryRequest arguments.
+
+ * draw.c (DrawPolygon, DrawFilledPolygon): Cast Xtfree argument.
+
+ * font.c (DisposeFontSizes): Add declaration.
+
+ * draw.c (FakeCharacter): Add declaration.
+
+Wed Oct 28 13:24:00 1992 James Clark (jjc at jclark)
+
+ * Imakefile (install.dev): Deleted.
+ (fonts): New target.
+
+Mon Oct 12 10:50:44 1992 James Clark (jjc at jclark)
+
+ * Imakefile (install.dev): Say when we're installing devX*-12.
+
+ * Imakefile (install.dev): Depends on DESC and FontMap.
+
+Thu Oct 1 20:03:45 1992 James Clark (jjc at jclark)
+
+ * xditview.c (Syntax): Mention -filename option.
+
+Sat Aug 15 12:56:39 1992 James Clark (jjc at jclark)
+
+ * GXditview.ad: Bind space and return to NextPage. Bind backspace
+ and delete to previous page.
+
+ * DviChar.c (Adobe_Symbol_map): Add `an'.
+
+ * DviChar.c (Adobe_Symbol_map): Add arrowvertex, arrowverttp, and
+ arrowvertbt.
+
+Mon Aug 10 11:54:27 1992 James Clark (jjc at jclark)
+
+ * FontMap: Add m/p fields to the fonts names.
+
+Sat Aug 8 12:00:28 1992 James Clark (jjc at jclark)
+
+ * DESC: Leave font positions 5-9 blank.
+
+Tue Jul 28 11:37:05 1992 James Clark (jjc at jclark)
+
+ * Imakefile: Don't use gendef. Pass definition of FONTPATH using
+ DEFINES.
+ (path.h): Deleted.
+ (device.c): Don't include path.h. Provide default definition of
+ FONTPATH.
+
+Mon Jul 6 14:06:53 1992 James Clark (jjc at jclark)
+
+ * Imakefile: Don't install tmac.X and tmac.Xps.
+ * tmac.X, tmac.Xps: Moved to ../macros.
+
+ * Imakefile: Don't install eqnchar.
+ * eqnchar: Deleted.
+
+Sun Jun 14 12:55:02 1992 James Clark (jjc@jclark)
+
+ * tmac.Xps: Handle OE, oe, lq, rq.
+ * draw.c (FakeCharacter): Don't handle these.
+
+ * draw.c (FakeCharacter): Don't handle f/.
+
+Mon Jun 8 11:46:37 1992 James Clark (jjc@jclark)
+
+ * tmac.X: Translate char160 to space.
+
+Sun Jun 7 14:39:53 1992 James Clark (jjc@jclark)
+
+ * tmac.X: Do `mso tmac.psic' before restoring compatibility mode.
+
+ * tmac.X: Add \(OE, \(oe, \(ah, \(ao, \(ho.
+
+ * tmac.Xps: Make it work in compatibility mode.
+ Redo existing character definitions with .Xps-char.
+ Add more character definitions.
+ (Xps-char): New macro.
+
+Sat Jun 6 21:46:03 1992 James Clark (jjc@jclark)
+
+ * DviChar.c (Adobe_Symbol_map): Add +h, +f, +p, Fn, lz.
+ * tmac.X: Add \(bq, \(Bq, \(aq.
+ * tmac.Xps: Handle \(aq, \(bq, \(Bq, \(Fn.
+
+Wed Jun 3 11:11:15 1992 James Clark (jjc@jclark)
+
+ * DviChar.c (Adobe_Symbol_map): Add wp.
+
+Tue Apr 21 09:21:59 1992 James Clark (jjc at jclark)
+
+ * GXditview.ad: Bind n, p, q keys to NextPage, PreviousPage and
+ Quit actions.
+
+ * xditview.c (RerasterizeAction): New function.
+ (xditview_actions): Add RerasterizeAction.
+ * GXditview.ad: Bind r key to Rerasterize action.
+
+Fri Apr 17 08:25:36 1992 James Clark (jjc at jclark)
+
+ * xditview.c: Add -filename option.
+ (main): Copy any -filename argument into current_file_name.
+
+Mon Mar 16 10:21:58 1992 James Clark (jjc at jclark)
+
+ * tmac.X: Load tmac.pspic.
+
+Sun Mar 8 11:27:19 1992 James Clark (jjc at jclark)
+
+ * Lex.c (GetLine, GetWord, GetNumber): Rewrite.
+
+Sat Oct 12 22:58:52 1991 James Clark (jjc at jclark)
+
+ * Dvi.c (SetDevice): If the size change request is refused but a
+ larger geometry is offered, request that.
+
+Wed Oct 9 12:27:48 1991 James Clark (jjc at jclark)
+
+ * font.c (InstallFontSizes): Ignore FontNameAverageWidth component.
+
+ * Dvi.c (default_font_map): Add `adobe' to font names to avoid
+ ambiguity.
+
+ * FontMap: New file.
+ * FontMap.X100, FontMap.X75: Deleted.
+ * xtotroff.c (main, usage): Add -s and -r options.
+ (MapFont): Change the font pattern to have the selected resolution and
+ size.
+ * Imakefile (install.dev): Use FontMap and supply appropriate -s
+ and -r options.
+
+ * xtotroff.c (MapFont): Check for ambiguity by comparing canonicalized
+ font names.
+
+ * DviP.h (DviFontList): Add initialized and scalable members.
+ (font.c): Add support for scalable fonts based on R5 xditview.
+
+ * DviChar.c: Use xmalloc rather than malloc.
+ * xditview.c (xmalloc): New function.
+ * xtotroff.c (xmalloc): New function.
+ * other files: Use XtMalloc and XtFree instead of malloc and free.
+
+Thu Aug 29 20:15:31 1991 James Clark (jjc at jclark)
+
+ * draw.c (setGC): Do multiplication in floating point to avoid
+ overflow.
+
+Tue Aug 13 12:04:41 1991 James Clark (jjc at jclark)
+
+ * draw.c (FakeCharacter): Remove casts in defintion of pack2.
+
+Tue Jul 30 11:42:39 1991 James Clark (jjc at jclark)
+
+ * tmac.Xps: New file.
+ * Imakefile (install): Install tmac.Xps.
+
+Tue Jul 2 09:31:37 1991 James Clark (jjc at jclark)
+
+ * xtotroff.c (main): Pass argv[0] to usage().
+
+Sun Jun 30 12:34:06 1991 James Clark (jjc at jclark)
+
+ * xtotroff.c (MapFont): Handle the case where XLoadQueryFont
+ returns NULL.
+
+Sat Jun 29 12:32:52 1991 James Clark (jjc at jclark)
+
+ * Imakefile: Use ../gendef to generate path.h.
+
+Sun Jun 16 13:26:34 1991 James Clark (jjc at jclark)
+
+ * Imakefile (depend.o): Change to device.o.
+
+Sun Jun 2 12:17:56 1991 James Clark (jjc at jclark)
+
+ * Imakefile: Remove spaces from the beginning of variable
+ assignment lines.
+
+Sun May 26 14:14:01 1991 James Clark (jjc at jclark)
+
+ * xditview.c (Syntax): Update.
+
+ * Dvi.c (DviSaveToFile, SaveToFile): New functions.
+ (FindPage): Check that we're not readingTmp before checking for
+ end of file of normal input file.
+ (ClassPartInitialize): New function.
+ * Dvi.h: Add declaration of DviSaveToFile.
+ * DviP.h: Add save method to DviClassPart. Declare
+ InheritSaveToFile.
+ * xditview.c (DoPrint, Print, PrintAction): New functions.
+ * xditview.c: Add print menu entry.
+ * xditview.c: Provide printCommand application resource.
+ * lex.c: Don't output EOF to temporary file.
+
+ * Dvi.c (QueryGeometry): Check request->request_mode.
+
+ * Dvi.c (SetDevice): New function.
+ (SetDeviceResolution): Deleted.
+
+ * Dvi.c: Add resolution resource.
+ * DviP.h: Add definitions of XtNResolution and XtCResolution.
+ * xditview.c: Add -resolution argument.
+ * GXditview.ad: Add default for GXditview.height.
+ * Dvi.c (Initialize, SetDevice): Use default_resolution.
+
+ * Dvi.c: Make MY_HEIGHT and MY_WIDTH use the paperlength and
+ paperwidth commands in the DESC file.
+
+ * Dvi.c: Add SS font to default font map.
+
+ * draw.c: Rewritten so as not to assume device and display
+ resolution is the same.
+ * DviP.h: Include device.h. Add device_font member to DviFontList.
+ Add adjustable arrary to DviCharCache. Add text_x_width,
+ text_device_width, word_flag, device_font, device_font_number,
+ device, native, device_resolution, display_resolution,
+ paperlength, paperwidth, scale_factor, sizescale members.
+ * Dvi.c (Initialize): Initialize new variable used by draw.c
+ (Destroy): Call device_destroy.
+ * font.c (MaxFontPosition): New function.
+ (LookupFontSizeBySize): Handle sizescale.
+ (InstallFont): Load the device font.
+ (ForgetFonts): New function.
+ (QueryDeviceFont): New function.
+ * parse.c (ParseInput): Handle t and u commands. Split off
+ character output into draw.c.
+ (ParseDeviceControl): Ignore res command. Use the device argument
+ to the T command.
+
+ * font.c (MapXNameToDviName): Ifdefed out.
+
+ * path.h: New file.
+ * device.c, device.h: New files.
+
+ * DviChar.c: Add entries for lB, rB, oq, lC, rC, md.
+
+ * INSTALL: New file.
+
+ * libxdvi: Merged into main directory.
+ * xtotroff.c, xditview.c: Change includes accordingly.
+
+ * devX75, devX100: Merged into main directory.
+ * xditview.man: Renamed to gxditview.man.
+
+ * Xditview.ad: Renamed to GXditview.ad.
+ * xditview.c (main): Use class of GXditview rather than xditview.
+
+ * Imakefile: New file.
+ * Makefile: Deleted.
+
+ * xtotroff.c (MapFont): Unlink output file before opening it.
+
+ * Started separate ChangeLog.
diff --git a/gnu/usr.bin/groff/xditview/DESC b/gnu/usr.bin/groff/xditview/DESC
new file mode 100644
index 0000000..172170c
--- /dev/null
+++ b/gnu/usr.bin/groff/xditview/DESC
@@ -0,0 +1,9 @@
+styles R I B BI
+fonts 6 0 0 0 0 0 S
+sizes 8 10 12 14 18 24 0
+res 75
+X11
+hor 1
+vert 1
+unitwidth 10
+postpro gxditview
diff --git a/gnu/usr.bin/groff/xditview/Dvi.c b/gnu/usr.bin/groff/xditview/Dvi.c
new file mode 100644
index 0000000..86bb511
--- /dev/null
+++ b/gnu/usr.bin/groff/xditview/Dvi.c
@@ -0,0 +1,544 @@
+#ifndef SABER
+#ifndef lint
+static char Xrcsid[] = "$XConsortium: Dvi.c,v 1.9 89/12/10 16:12:25 rws Exp $";
+#endif /* lint */
+#endif /* SABER */
+
+/*
+ * Dvi.c - Dvi display widget
+ *
+ */
+
+#define XtStrlen(s) ((s) ? strlen(s) : 0)
+
+ /* The following are defined for the reader's convenience. Any
+ Xt..Field macro in this code just refers to some field in
+ one of the substructures of the WidgetRec. */
+
+#include <X11/IntrinsicP.h>
+#include <X11/StringDefs.h>
+#include <X11/Xmu/Converters.h>
+#include <stdio.h>
+#include <ctype.h>
+#include "DviP.h"
+
+/****************************************************************
+ *
+ * Full class record constant
+ *
+ ****************************************************************/
+
+/* Private Data */
+
+static char default_font_map[] = "\
+TR -adobe-times-medium-r-normal--*-100-*-*-*-*-iso8859-1\n\
+TI -adobe-times-medium-i-normal--*-100-*-*-*-*-iso8859-1\n\
+TB -adobe-times-bold-r-normal--*-100-*-*-*-*-iso8859-1\n\
+TBI -adobe-times-bold-i-normal--*-100-*-*-*-*-iso8859-1\n\
+CR -adobe-courier-medium-r-normal--*-100-*-*-*-*-iso8859-1\n\
+CI -adobe-courier-medium-o-normal--*-100-*-*-*-*-iso8859-1\n\
+CB -adobe-courier-bold-r-normal--*-100-*-*-*-*-iso8859-1\n\
+CBI -adobe-courier-bold-o-normal--*-100-*-*-*-*-iso8859-1\n\
+HR -adobe-helvetica-medium-r-normal--*-100-*-*-*-*-iso8859-1\n\
+HI -adobe-helvetica-medium-o-normal--*-100-*-*-*-*-iso8859-1\n\
+HB -adobe-helvetica-bold-r-normal--*-100-*-*-*-*-iso8859-1\n\
+HBI -adobe-helvetica-bold-o-normal--*-100-*-*-*-*-iso8859-1\n\
+NR -adobe-new century schoolbook-medium-r-normal--*-100-*-*-*-*-iso8859-1\n\
+NI -adobe-new century schoolbook-medium-i-normal--*-100-*-*-*-*-iso8859-1\n\
+NB -adobe-new century schoolbook-bold-r-normal--*-100-*-*-*-*-iso8859-1\n\
+NBI -adobe-new century schoolbook-bold-i-normal--*-100-*-*-*-*-iso8859-1\n\
+S -adobe-symbol-medium-r-normal--*-100-*-*-*-*-adobe-fontspecific\n\
+SS -adobe-symbol-medium-r-normal--*-100-*-*-*-*-adobe-fontspecific\n\
+";
+
+#define offset(field) XtOffset(DviWidget, field)
+
+#define MY_WIDTH(dw) ((int)(dw->dvi.paperwidth * dw->dvi.scale_factor + .5))
+#define MY_HEIGHT(dw) ((int)(dw->dvi.paperlength * dw->dvi.scale_factor + .5))
+
+static XtResource resources[] = {
+ {XtNfontMap, XtCFontMap, XtRString, sizeof (char *),
+ offset(dvi.font_map_string), XtRString, default_font_map},
+ {XtNforeground, XtCForeground, XtRPixel, sizeof (unsigned long),
+ offset(dvi.foreground), XtRString, "black"},
+ {XtNbackground, XtCBackground, XtRPixel, sizeof (unsigned long),
+ offset(dvi.background), XtRString, "white"},
+ {XtNpageNumber, XtCPageNumber, XtRInt, sizeof (int),
+ offset(dvi.requested_page), XtRString, "1"},
+ {XtNlastPageNumber, XtCLastPageNumber, XtRInt, sizeof (int),
+ offset (dvi.last_page), XtRString, "0"},
+ {XtNfile, XtCFile, XtRFile, sizeof (FILE *),
+ offset (dvi.file), XtRFile, (char *) 0},
+ {XtNseek, XtCSeek, XtRBoolean, sizeof (Boolean),
+ offset(dvi.seek), XtRString, "false"},
+ {XtNfont, XtCFont, XtRFontStruct, sizeof (XFontStruct *),
+ offset(dvi.default_font), XtRString, "xtdefaultfont"},
+ {XtNbackingStore, XtCBackingStore, XtRBackingStore, sizeof (int),
+ offset(dvi.backing_store), XtRString, "default"},
+ {XtNnoPolyText, XtCNoPolyText, XtRBoolean, sizeof (Boolean),
+ offset(dvi.noPolyText), XtRString, "false"},
+ {XtNresolution, XtCResolution, XtRInt, sizeof(int),
+ offset(dvi.default_resolution), XtRString, "75"},
+};
+
+#undef offset
+
+static void ClassInitialize ();
+static void ClassPartInitialize();
+static void Initialize(), Realize (), Destroy (), Redisplay ();
+static Boolean SetValues (), SetValuesHook ();
+static XtGeometryResult QueryGeometry ();
+static void ShowDvi ();
+static void CloseFile (), OpenFile ();
+static void FindPage ();
+
+static void SaveToFile ();
+
+DviClassRec dviClassRec = {
+{
+ &widgetClassRec, /* superclass */
+ "Dvi", /* class_name */
+ sizeof(DviRec), /* size */
+ ClassInitialize, /* class_initialize */
+ ClassPartInitialize, /* class_part_initialize */
+ FALSE, /* class_inited */
+ Initialize, /* initialize */
+ NULL, /* initialize_hook */
+ Realize, /* realize */
+ NULL, /* actions */
+ 0, /* num_actions */
+ resources, /* resources */
+ XtNumber(resources), /* resource_count */
+ NULLQUARK, /* xrm_class */
+ FALSE, /* compress_motion */
+ TRUE, /* compress_exposure */
+ TRUE, /* compress_enterleave */
+ FALSE, /* visible_interest */
+ Destroy, /* destroy */
+ NULL, /* resize */
+ Redisplay, /* expose */
+ SetValues, /* set_values */
+ SetValuesHook, /* set_values_hook */
+ NULL, /* set_values_almost */
+ NULL, /* get_values_hook */
+ NULL, /* accept_focus */
+ XtVersion, /* version */
+ NULL, /* callback_private */
+ 0, /* tm_table */
+ QueryGeometry, /* query_geometry */
+ NULL, /* display_accelerator */
+ NULL /* extension */
+},{
+ SaveToFile, /* save */
+},
+};
+
+WidgetClass dviWidgetClass = (WidgetClass) &dviClassRec;
+
+static void ClassInitialize ()
+{
+ XtAddConverter( XtRString, XtRBackingStore, XmuCvtStringToBackingStore,
+ NULL, 0 );
+}
+
+/****************************************************************
+ *
+ * Private Procedures
+ *
+ ****************************************************************/
+
+/* ARGSUSED */
+static void Initialize(request, new)
+ Widget request, new;
+{
+ DviWidget dw = (DviWidget) new;
+
+ dw->dvi.current_page = 0;
+ dw->dvi.font_map = 0;
+ dw->dvi.cache.index = 0;
+ dw->dvi.text_x_width = 0;
+ dw->dvi.text_device_width = 0;
+ dw->dvi.word_flag = 0;
+ dw->dvi.file = 0;
+ dw->dvi.tmpFile = 0;
+ dw->dvi.state = 0;
+ dw->dvi.readingTmp = 0;
+ dw->dvi.cache.char_index = 0;
+ dw->dvi.cache.font_size = -1;
+ dw->dvi.cache.font_number = -1;
+ dw->dvi.cache.adjustable[0] = 0;
+ dw->dvi.file_map = 0;
+ dw->dvi.fonts = 0;
+ dw->dvi.seek = False;
+ dw->dvi.device_resolution = dw->dvi.default_resolution;
+ dw->dvi.display_resolution = dw->dvi.default_resolution;
+ dw->dvi.paperlength = dw->dvi.default_resolution*11;
+ dw->dvi.paperwidth = (dw->dvi.default_resolution*8
+ + dw->dvi.default_resolution/2);
+ dw->dvi.scale_factor = 1.0;
+ dw->dvi.sizescale = 1;
+ dw->dvi.line_thickness = -1;
+ dw->dvi.line_width = 1;
+ dw->dvi.fill = DVI_FILL_MAX;
+ dw->dvi.device_font = 0;
+ dw->dvi.device_font_number = -1;
+ dw->dvi.device = 0;
+ dw->dvi.native = 0;
+}
+
+#include <X11/bitmaps/gray>
+
+static void
+Realize (w, valueMask, attrs)
+ Widget w;
+ XtValueMask *valueMask;
+ XSetWindowAttributes *attrs;
+{
+ DviWidget dw = (DviWidget) w;
+ XGCValues values;
+
+ if (dw->dvi.backing_store != Always + WhenMapped + NotUseful) {
+ attrs->backing_store = dw->dvi.backing_store;
+ *valueMask |= CWBackingStore;
+ }
+ XtCreateWindow (w, (unsigned)InputOutput, (Visual *) CopyFromParent,
+ *valueMask, attrs);
+ values.foreground = dw->dvi.foreground;
+ values.cap_style = CapRound;
+ values.join_style = JoinRound;
+ values.line_width = dw->dvi.line_width;
+ dw->dvi.normal_GC = XCreateGC (XtDisplay (w), XtWindow (w),
+ GCForeground|GCCapStyle|GCJoinStyle
+ |GCLineWidth,
+ &values);
+ dw->dvi.gray = XCreateBitmapFromData(XtDisplay (w), XtWindow (w),
+ gray_bits,
+ gray_width, gray_height);
+ values.background = dw->dvi.background;
+ values.stipple = dw->dvi.gray;
+ dw->dvi.fill_GC = XCreateGC (XtDisplay (w), XtWindow (w),
+ GCForeground|GCBackground|GCStipple,
+ &values);
+
+ dw->dvi.fill_type = DVI_FILL_BLACK;
+
+ if (dw->dvi.file)
+ OpenFile (dw);
+ ParseFontMap (dw);
+}
+
+static void
+Destroy(w)
+ Widget w;
+{
+ DviWidget dw = (DviWidget) w;
+
+ XFreeGC (XtDisplay (w), dw->dvi.normal_GC);
+ XFreeGC (XtDisplay (w), dw->dvi.fill_GC);
+ XFreePixmap (XtDisplay (w), dw->dvi.gray);
+ DestroyFontMap (dw->dvi.font_map);
+ DestroyFileMap (dw->dvi.file_map);
+ device_destroy (dw->dvi.device);
+}
+
+/*
+ * Repaint the widget window
+ */
+
+/* ARGSUSED */
+static void
+Redisplay(w, event, region)
+ Widget w;
+ XEvent *event;
+ Region region;
+{
+ DviWidget dw = (DviWidget) w;
+ XRectangle extents;
+
+ XClipBox (region, &extents);
+ dw->dvi.extents.x1 = extents.x;
+ dw->dvi.extents.y1 = extents.y;
+ dw->dvi.extents.x2 = extents.x + extents.width;
+ dw->dvi.extents.y2 = extents.y + extents.height;
+ ShowDvi (dw);
+}
+
+/*
+ * Set specified arguments into widget
+ */
+/* ARGSUSED */
+static Boolean
+SetValues (current, request, new)
+ DviWidget current, request, new;
+{
+ Boolean redisplay = FALSE;
+ char *new_map;
+ int cur, req;
+
+ if (current->dvi.font_map_string != request->dvi.font_map_string) {
+ new_map = XtMalloc (strlen (request->dvi.font_map_string) + 1);
+ if (new_map) {
+ redisplay = TRUE;
+ strcpy (new_map, request->dvi.font_map_string);
+ new->dvi.font_map_string = new_map;
+ if (current->dvi.font_map_string)
+ XtFree (current->dvi.font_map_string);
+ current->dvi.font_map_string = 0;
+ ParseFontMap (new);
+ }
+ }
+
+ req = request->dvi.requested_page;
+ cur = current->dvi.requested_page;
+ if (cur != req) {
+ if (!request->dvi.file)
+ req = 0;
+ else {
+ if (req < 1)
+ req = 1;
+ if (current->dvi.last_page != 0 &&
+ req > current->dvi.last_page)
+ req = current->dvi.last_page;
+ }
+ if (cur != req)
+ redisplay = TRUE;
+ new->dvi.requested_page = req;
+ if (current->dvi.last_page == 0 && req > cur)
+ FindPage (new);
+ }
+
+ return redisplay;
+}
+
+/*
+ * use the set_values_hook entry to check when
+ * the file is set
+ */
+
+static Boolean
+SetValuesHook (dw, args, num_argsp)
+ DviWidget dw;
+ ArgList args;
+ Cardinal *num_argsp;
+{
+ Cardinal i;
+
+ for (i = 0; i < *num_argsp; i++) {
+ if (!strcmp (args[i].name, XtNfile)) {
+ CloseFile (dw);
+ OpenFile (dw);
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+static void CloseFile (dw)
+ DviWidget dw;
+{
+ if (dw->dvi.tmpFile)
+ fclose (dw->dvi.tmpFile);
+ ForgetPagePositions (dw);
+}
+
+static void OpenFile (dw)
+ DviWidget dw;
+{
+ char tmpName[sizeof ("/tmp/dviXXXXXX")];
+
+ dw->dvi.tmpFile = 0;
+ if (!dw->dvi.seek) {
+ strcpy (tmpName, "/tmp/dviXXXXXX");
+ mktemp (tmpName);
+ dw->dvi.tmpFile = fopen (tmpName, "w+");
+ unlink (tmpName);
+ }
+ dw->dvi.requested_page = 1;
+ dw->dvi.last_page = 0;
+}
+
+static XtGeometryResult
+QueryGeometry (w, request, geometry_return)
+ Widget w;
+ XtWidgetGeometry *request, *geometry_return;
+{
+ XtGeometryResult ret;
+ DviWidget dw = (DviWidget) w;
+
+ ret = XtGeometryYes;
+ if (((request->request_mode & CWWidth)
+ && request->width < MY_WIDTH(dw))
+ || ((request->request_mode & CWHeight)
+ && request->height < MY_HEIGHT(dw)))
+ ret = XtGeometryAlmost;
+ geometry_return->width = MY_WIDTH(dw);
+ geometry_return->height = MY_HEIGHT(dw);
+ geometry_return->request_mode = CWWidth|CWHeight;
+ return ret;
+}
+
+SetDevice (dw, name)
+ DviWidget dw;
+ char *name;
+{
+ XtWidgetGeometry request, reply;
+ XtGeometryResult ret;
+
+ ForgetFonts (dw);
+ dw->dvi.device = device_load (name);
+ if (!dw->dvi.device)
+ return;
+ dw->dvi.sizescale = dw->dvi.device->sizescale;
+ dw->dvi.device_resolution = dw->dvi.device->res;
+ dw->dvi.native = dw->dvi.device->X11;
+ dw->dvi.paperlength = dw->dvi.device->paperlength;
+ dw->dvi.paperwidth = dw->dvi.device->paperwidth;
+ if (dw->dvi.native) {
+ dw->dvi.display_resolution = dw->dvi.device_resolution;
+ dw->dvi.scale_factor = 1.0;
+ }
+ else {
+ dw->dvi.display_resolution = dw->dvi.default_resolution;
+ dw->dvi.scale_factor = ((double)dw->dvi.display_resolution
+ / dw->dvi.device_resolution);
+ }
+ request.request_mode = CWWidth|CWHeight;
+ request.width = MY_WIDTH(dw);
+ request.height = MY_HEIGHT(dw);
+ ret = XtMakeGeometryRequest ((Widget)dw, &request, &reply);
+ if (ret == XtGeometryAlmost
+ && reply.height >= request.height
+ && reply.width >= request.width) {
+ request.width = reply.width;
+ request.height = reply.height;
+ XtMakeGeometryRequest ((Widget)dw, &request, &reply);
+ }
+}
+
+static void
+ShowDvi (dw)
+ DviWidget dw;
+{
+ if (!dw->dvi.file) {
+ static char Error[] = "No file selected";
+
+ XSetFont (XtDisplay(dw), dw->dvi.normal_GC,
+ dw->dvi.default_font->fid);
+ XDrawString (XtDisplay (dw), XtWindow (dw), dw->dvi.normal_GC,
+ 20, 20, Error, strlen (Error));
+ return;
+ }
+
+ FindPage (dw);
+
+ dw->dvi.display_enable = 1;
+ ParseInput (dw);
+ if (dw->dvi.last_page && dw->dvi.requested_page > dw->dvi.last_page)
+ dw->dvi.requested_page = dw->dvi.last_page;
+}
+
+static void
+FindPage (dw)
+ DviWidget dw;
+{
+ int i;
+ long file_position;
+
+ if (dw->dvi.requested_page < 1)
+ dw->dvi.requested_page = 1;
+
+ if (dw->dvi.last_page != 0 && dw->dvi.requested_page > dw->dvi.last_page)
+ dw->dvi.requested_page = dw->dvi.last_page;
+
+ file_position = SearchPagePosition (dw, dw->dvi.requested_page);
+ if (file_position != -1) {
+ FileSeek(dw, file_position);
+ dw->dvi.current_page = dw->dvi.requested_page;
+ } else {
+ for (i=dw->dvi.requested_page; i > 0; i--) {
+ file_position = SearchPagePosition (dw, i);
+ if (file_position != -1)
+ break;
+ }
+ if (file_position == -1)
+ file_position = 0;
+ FileSeek (dw, file_position);
+
+ dw->dvi.current_page = i;
+
+ dw->dvi.display_enable = 0;
+ while (dw->dvi.current_page != dw->dvi.requested_page) {
+ dw->dvi.current_page = ParseInput (dw);
+ /*
+ * at EOF, seek back to the beginning of this page.
+ */
+ if (!dw->dvi.readingTmp && feof (dw->dvi.file)) {
+ file_position = SearchPagePosition (dw,
+ dw->dvi.current_page);
+ if (file_position != -1)
+ FileSeek (dw, file_position);
+ dw->dvi.requested_page = dw->dvi.current_page;
+ break;
+ }
+ }
+ }
+}
+
+void DviSaveToFile(w, fp)
+ Widget w;
+ FILE *fp;
+{
+ XtCheckSubclass(w, dviWidgetClass, NULL);
+ (*((DviWidgetClass) XtClass(w))->command_class.save)(w, fp);
+}
+
+static
+void SaveToFile(w, fp)
+ Widget w;
+ FILE *fp;
+{
+ DviWidget dw = (DviWidget)w;
+ long pos;
+ int c;
+
+ if (dw->dvi.tmpFile) {
+ pos = ftell(dw->dvi.tmpFile);
+ if (dw->dvi.ungot) {
+ pos--;
+ dw->dvi.ungot = 0;
+ /* The ungot character is in the tmpFile, so we don't
+ want to read it from file. */
+ (void)getc(dw->dvi.file);
+ }
+ }
+ else
+ pos = ftell(dw->dvi.file);
+ FileSeek(dw, 0L);
+ while (DviGetC(dw, &c) != EOF)
+ if (putc(c, fp) == EOF) {
+ /* XXX print error message */
+ break;
+ }
+ FileSeek(dw, pos);
+}
+
+static
+void ClassPartInitialize(widget_class)
+ WidgetClass widget_class;
+{
+ DviWidgetClass wc = (DviWidgetClass)widget_class;
+ DviWidgetClass super = (DviWidgetClass) wc->core_class.superclass;
+ if (wc->command_class.save == InheritSaveToFile)
+ wc->command_class.save = super->command_class.save;
+}
+
+/*
+Local Variables:
+c-indent-level: 8
+c-continued-statement-offset: 8
+c-brace-offset: -8
+c-argdecl-indent: 8
+c-label-offset: -8
+c-tab-always-indent: nil
+End:
+*/
diff --git a/gnu/usr.bin/groff/xditview/Dvi.h b/gnu/usr.bin/groff/xditview/Dvi.h
new file mode 100644
index 0000000..5aab7d8
--- /dev/null
+++ b/gnu/usr.bin/groff/xditview/Dvi.h
@@ -0,0 +1,46 @@
+/*
+* $XConsortium: Dvi.h,v 1.4 89/07/21 14:22:06 jim Exp $
+*/
+
+#ifndef _XtDvi_h
+#define _XtDvi_h
+
+/***********************************************************************
+ *
+ * Dvi Widget
+ *
+ ***********************************************************************/
+
+/* Parameters:
+
+ Name Class RepType Default Value
+ ---- ----- ------- -------------
+ background Background pixel White
+ foreground Foreground Pixel Black
+ fontMap FontMap char * ...
+ pageNumber PageNumber int 1
+*/
+
+#define XtNfontMap "fontMap"
+#define XtNpageNumber "pageNumber"
+#define XtNlastPageNumber "lastPageNumber"
+#define XtNnoPolyText "noPolyText"
+#define XtNseek "seek"
+#define XtNresolution "resolution"
+
+#define XtCFontMap "FontMap"
+#define XtCPageNumber "PageNumber"
+#define XtCLastPageNumber "LastPageNumber"
+#define XtCNoPolyText "NoPolyText"
+#define XtCSeek "Seek"
+#define XtCResolution "Resolution"
+
+typedef struct _DviRec *DviWidget; /* completely defined in DviPrivate.h */
+typedef struct _DviClassRec *DviWidgetClass; /* completely defined in DviPrivate.h */
+
+extern WidgetClass dviWidgetClass;
+
+extern void DviSaveToFile();
+
+#endif /* _XtDvi_h */
+/* DON'T ADD STUFF AFTER THIS #endif */
diff --git a/gnu/usr.bin/groff/xditview/DviChar.c b/gnu/usr.bin/groff/xditview/DviChar.c
new file mode 100644
index 0000000..f6d2569
--- /dev/null
+++ b/gnu/usr.bin/groff/xditview/DviChar.c
@@ -0,0 +1,664 @@
+/*
+ * DviChar.c
+ *
+ * Map DVI (ditroff output) character names to
+ * font indexes and back
+ */
+
+#include "DviChar.h"
+
+extern char *xmalloc();
+
+#define allocHash() ((DviCharNameHash *) xmalloc (sizeof (DviCharNameHash)))
+
+struct map_list {
+ struct map_list *next;
+ DviCharNameMap *map;
+};
+
+static struct map_list *world;
+
+static int standard_maps_loaded = 0;
+static void load_standard_maps ();
+static int hash_name ();
+static dispose_hash(), compute_hash();
+
+DviCharNameMap *
+DviFindMap (encoding)
+ char *encoding;
+{
+ struct map_list *m;
+
+ if (!standard_maps_loaded)
+ load_standard_maps ();
+ for (m = world; m; m=m->next)
+ if (!strcmp (m->map->encoding, encoding))
+ return m->map;
+ return 0;
+}
+
+void
+DviRegisterMap (map)
+ DviCharNameMap *map;
+{
+ struct map_list *m;
+
+ if (!standard_maps_loaded)
+ load_standard_maps ();
+ for (m = world; m; m = m->next)
+ if (!strcmp (m->map->encoding, map->encoding))
+ break;
+ if (!m) {
+ m = (struct map_list *) xmalloc (sizeof *m);
+ m->next = world;
+ world = m;
+ }
+ dispose_hash (map);
+ m->map = map;
+ compute_hash (map);
+}
+
+static
+dispose_hash (map)
+ DviCharNameMap *map;
+{
+ DviCharNameHash **buckets;
+ DviCharNameHash *h, *next;
+ int i;
+
+ buckets = map->buckets;
+ for (i = 0; i < DVI_HASH_SIZE; i++) {
+ for (h = buckets[i]; h; h=next) {
+ next = h->next;
+ free (h);
+ }
+ }
+}
+
+static int
+hash_name (name)
+ char *name;
+{
+ int i = 0;
+
+ while (*name)
+ i = (i << 1) ^ *name++;
+ if (i < 0)
+ i = -i;
+ return i;
+}
+
+static
+compute_hash (map)
+ DviCharNameMap *map;
+{
+ DviCharNameHash **buckets;
+ int c, s, i;
+ DviCharNameHash *h;
+
+ buckets = map->buckets;
+ for (i = 0; i < DVI_HASH_SIZE; i++)
+ buckets[i] = 0;
+ for (c = 0; c < DVI_MAP_SIZE; c++)
+ for (s = 0; s < DVI_MAX_SYNONYMS; s++) {
+ if (!map->dvi_names[c][s])
+ break;
+ i = hash_name (map->dvi_names[c][s]) % DVI_HASH_SIZE;
+ h = allocHash ();
+ h->next = buckets[i];
+ buckets[i] = h;
+ h->name = map->dvi_names[c][s];
+ h->position = c;
+ }
+
+}
+
+int
+DviCharIndex (map, name)
+ DviCharNameMap *map;
+ char *name;
+{
+ int i;
+ DviCharNameHash *h;
+
+ i = hash_name (name) % DVI_HASH_SIZE;
+ for (h = map->buckets[i]; h; h=h->next)
+ if (!strcmp (h->name, name))
+ return h->position;
+ return -1;
+}
+
+static DviCharNameMap ISO8859_1_map = {
+ "iso8859-1",
+ 0,
+{
+{ 0, /* 0 */},
+{ 0, /* 1 */},
+{ 0, /* 2 */},
+{ 0, /* 3 */},
+{ 0, /* 4 */},
+{ 0, /* 5 */},
+{ 0, /* 6 */},
+{ 0, /* 7 */},
+{ 0, /* 8 */},
+{ 0, /* 9 */},
+{ 0, /* 10 */},
+{ 0, /* 11 */},
+{ 0, /* 12 */},
+{ 0, /* 13 */},
+{ 0, /* 14 */},
+{ 0, /* 15 */},
+{ 0, /* 16 */},
+{ 0, /* 17 */},
+{ 0, /* 18 */},
+{ 0, /* 19 */},
+{ 0, /* 20 */},
+{ 0, /* 21 */},
+{ 0, /* 22 */},
+{ 0, /* 23 */},
+{ 0, /* 24 */},
+{ 0, /* 25 */},
+{ 0, /* 26 */},
+{ 0, /* 27 */},
+{ 0, /* 28 */},
+{ 0, /* 29 */},
+{ 0, /* 30 */},
+{ 0, /* 31 */},
+{ 0, /* 32 */},
+{ "!", /* 33 */},
+{ "\"", /* 34 */},
+{ "#","sh", /* 35 */},
+{ "$","Do", /* 36 */},
+{ "%", /* 37 */},
+{ "&", /* 38 */},
+{ "'", /* 39 */},
+{ "(", /* 40 */},
+{ ")", /* 41 */},
+{ "*", /* 42 */},
+{ "+", /* 43 */},
+{ ",", /* 44 */},
+{ "\\-", /* 45 */},
+{ ".", /* 46 */},
+{ "/","sl", /* 47 */},
+{ "0", /* 48 */},
+{ "1", /* 49 */},
+{ "2", /* 50 */},
+{ "3", /* 51 */},
+{ "4", /* 52 */},
+{ "5", /* 53 */},
+{ "6", /* 54 */},
+{ "7", /* 55 */},
+{ "8", /* 56 */},
+{ "9", /* 57 */},
+{ ":", /* 58 */},
+{ ";", /* 59 */},
+{ "<", /* 60 */},
+{ "=","eq", /* 61 */},
+{ ">", /* 62 */},
+{ "?", /* 63 */},
+{ "@","at", /* 64 */},
+{ "A", /* 65 */},
+{ "B", /* 66 */},
+{ "C", /* 67 */},
+{ "D", /* 68 */},
+{ "E", /* 69 */},
+{ "F", /* 70 */},
+{ "G", /* 71 */},
+{ "H", /* 72 */},
+{ "I", /* 73 */},
+{ "J", /* 74 */},
+{ "K", /* 75 */},
+{ "L", /* 76 */},
+{ "M", /* 77 */},
+{ "N", /* 78 */},
+{ "O", /* 79 */},
+{ "P", /* 80 */},
+{ "Q", /* 81 */},
+{ "R", /* 82 */},
+{ "S", /* 83 */},
+{ "T", /* 84 */},
+{ "U", /* 85 */},
+{ "V", /* 86 */},
+{ "W", /* 87 */},
+{ "X", /* 88 */},
+{ "Y", /* 89 */},
+{ "Z", /* 90 */},
+{ "[","lB", /* 91 */},
+{ "\\","rs", /* 92 */},
+{ "]","rB", /* 93 */},
+{ "^","a^","ha" /* 94 */},
+{ "_", /* 95 */},
+{ "`","oq", /* 96 */},
+{ "a", /* 97 */},
+{ "b", /* 98 */},
+{ "c", /* 99 */},
+{ "d", /* 100 */},
+{ "e", /* 101 */},
+{ "f", /* 102 */},
+{ "g", /* 103 */},
+{ "h", /* 104 */},
+{ "i", /* 105 */},
+{ "j", /* 106 */},
+{ "k", /* 107 */},
+{ "l", /* 108 */},
+{ "m", /* 109 */},
+{ "n", /* 110 */},
+{ "o", /* 111 */},
+{ "p", /* 112 */},
+{ "q", /* 113 */},
+{ "r", /* 114 */},
+{ "s", /* 115 */},
+{ "t", /* 116 */},
+{ "u", /* 117 */},
+{ "v", /* 118 */},
+{ "w", /* 119 */},
+{ "x", /* 120 */},
+{ "y", /* 121 */},
+{ "z", /* 122 */},
+{ "{","lC", /* 123 */},
+{ "|","or","ba" /* 124 */},
+{ "}","rC", /* 125 */},
+{ "~","a~","ap","ti" /* 126 */},
+{ 0, /* 127 */},
+{ 0, /* 128 */},
+{ 0, /* 129 */},
+{ 0, /* 130 */},
+{ 0, /* 131 */},
+{ 0, /* 132 */},
+{ 0, /* 133 */},
+{ 0, /* 134 */},
+{ 0, /* 135 */},
+{ 0, /* 136 */},
+{ 0, /* 137 */},
+{ 0, /* 138 */},
+{ 0, /* 139 */},
+{ 0, /* 140 */},
+{ 0, /* 141 */},
+{ 0, /* 142 */},
+{ 0, /* 143 */},
+{ 0, /* 144 */},
+{ 0, /* 145 */},
+{ 0, /* 146 */},
+{ 0, /* 147 */},
+{ 0, /* 148 */},
+{ 0, /* 149 */},
+{ 0, /* 150 */},
+{ 0, /* 151 */},
+{ 0, /* 152 */},
+{ 0, /* 153 */},
+{ 0, /* 154 */},
+{ 0, /* 155 */},
+{ 0, /* 156 */},
+{ 0, /* 157 */},
+{ 0, /* 158 */},
+{ 0, /* 159 */},
+{ 0, /* 160 */},
+{ "r!", "\241", /* 161 */},
+{ "ct", "\242", /* 162 */},
+{ "Po", "\243", /* 163 */},
+{ "Cs", "\244", /* 164 */},
+{ "Ye", "\245", /* 165 */},
+{ "bb", "\246", /* 166 */},
+{ "sc", "\247", /* 167 */},
+{ "ad", "\250", /* 168 */},
+{ "co", "\251", /* 169 */},
+{ "Of", "\252", /* 170 */},
+{ "Fo", "\253", /* 171 */},
+{ "no", "\254", /* 172 */},
+{ "-", "hy", "\255" /* 173 */},
+{ "rg", "\256", /* 174 */},
+{ "a-", "\257", /* 175 */},
+{ "de", "\260", /* 176 */},
+{ "+-", "\261", /* 177 */},
+{ "S2", "\262", /* 178 */},
+{ "S3", "\263", /* 179 */},
+{ "aa", "\264", /* 180 */},
+/* Omit *m here; we want *m to match the other greek letters in the
+ symbol font. */
+{ "\265", /* 181 */},
+{ "ps", "\266", /* 182 */},
+{ "md", "\267", /* 183 */},
+{ "ac", "\270", /* 184 */},
+{ "S1", "\271", /* 185 */},
+{ "Om", "\272", /* 186 */},
+{ "Fc", "\273", /* 187 */},
+{ "14", "\274", /* 188 */},
+{ "12", "\275", /* 189 */},
+{ "34", "\276", /* 190 */},
+{ "r?", "\277", /* 191 */},
+{ "`A", "\300", /* 192 */},
+{ "'A", "\301", /* 193 */},
+{ "^A", "\302", /* 194 */},
+{ "~A", "\303", /* 195 */},
+{ ":A", "\304", /* 196 */},
+{ "oA", "\305", /* 197 */},
+{ "AE", "\306", /* 198 */},
+{ ",C", "\307", /* 199 */},
+{ "`E", "\310", /* 200 */},
+{ "'E", "\311", /* 201 */},
+{ "^E", "\312", /* 202 */},
+{ ":E", "\313", /* 203 */},
+{ "`I", "\314", /* 204 */},
+{ "'I", "\315", /* 205 */},
+{ "^I", "\316", /* 206 */},
+{ ":I", "\317", /* 207 */},
+{ "-D", "\320", /* 208 */},
+{ "~N", "\321", /* 209 */},
+{ "`O", "\322", /* 210 */},
+{ "'O", "\323", /* 211 */},
+{ "^O", "\324", /* 212 */},
+{ "~O", "\325", /* 213 */},
+{ ":O", "\326", /* 214 */},
+{ "mu", "\327", /* 215 */},
+{ "/O", "\330", /* 216 */},
+{ "`U", "\331", /* 217 */},
+{ "'U", "\332", /* 218 */},
+{ "^U", "\333", /* 219 */},
+{ ":U", "\334", /* 220 */},
+{ "'Y", "\335", /* 221 */},
+{ "TP", "\336", /* 222 */},
+{ "ss", "\337", /* 223 */},
+{ "`a", "\340", /* 224 */},
+{ "'a", "\341", /* 225 */},
+{ "^a", "\342", /* 226 */},
+{ "~a", "\343", /* 227 */},
+{ ":a", "\344", /* 228 */},
+{ "oa", "\345", /* 229 */},
+{ "ae", "\346", /* 230 */},
+{ ",c", "\347", /* 231 */},
+{ "`e", "\350", /* 232 */},
+{ "'e", "\351", /* 233 */},
+{ "^e", "\352", /* 234 */},
+{ ":e", "\353", /* 235 */},
+{ "`i", "\354", /* 236 */},
+{ "'i", "\355", /* 237 */},
+{ "^i", "\356", /* 238 */},
+{ ":i", "\357", /* 239 */},
+{ "Sd", "\360", /* 240 */},
+{ "~n", "\361", /* 241 */},
+{ "`o", "\362", /* 242 */},
+{ "'o", "\363", /* 243 */},
+{ "^o", "\364", /* 244 */},
+{ "~o", "\365", /* 245 */},
+{ ":o", "\366", /* 246 */},
+{ "di", "\367", /* 247 */},
+{ "/o", "\370", /* 248 */},
+{ "`u", "\371", /* 249 */},
+{ "'u", "\372", /* 250 */},
+{ "^u", "\373", /* 251 */},
+{ ":u", "\374", /* 252 */},
+{ "'y", "\375", /* 253 */},
+{ "Tp", "\376", /* 254 */},
+{ ":y", "\377", /* 255 */},
+}};
+
+static DviCharNameMap Adobe_Symbol_map = {
+ "adobe-fontspecific",
+ 1,
+{
+{ 0, /* 0 */},
+{ 0, /* 1 */},
+{ 0, /* 2 */},
+{ 0, /* 3 */},
+{ 0, /* 4 */},
+{ 0, /* 5 */},
+{ 0, /* 6 */},
+{ 0, /* 7 */},
+{ 0, /* 8 */},
+{ 0, /* 9 */},
+{ 0, /* 10 */},
+{ 0, /* 11 */},
+{ 0, /* 12 */},
+{ 0, /* 13 */},
+{ 0, /* 14 */},
+{ 0, /* 15 */},
+{ 0, /* 16 */},
+{ 0, /* 17 */},
+{ 0, /* 18 */},
+{ 0, /* 19 */},
+{ 0, /* 20 */},
+{ 0, /* 21 */},
+{ 0, /* 22 */},
+{ 0, /* 23 */},
+{ 0, /* 24 */},
+{ 0, /* 25 */},
+{ 0, /* 26 */},
+{ 0, /* 27 */},
+{ 0, /* 28 */},
+{ 0, /* 29 */},
+{ 0, /* 30 */},
+{ 0, /* 31 */},
+{ 0, /* 32 */},
+{ "!", /* 33 */},
+{ "fa", /* 34 */},
+{ "#", "sh", /* 35 */},
+{ "te", /* 36 */},
+{ "%", /* 37 */},
+{ "&", /* 38 */},
+{ "st", /* 39 */},
+{ "(", /* 40 */},
+{ ")", /* 41 */},
+{ "**", /* 42 */},
+{ "+", "pl", /* 43 */},
+{ ",", /* 44 */},
+{ "\\-", "mi", /* 45 */},
+{ ".", /* 46 */},
+{ "/", "sl", /* 47 */},
+{ "0", /* 48 */},
+{ "1", /* 49 */},
+{ "2", /* 50 */},
+{ "3", /* 51 */},
+{ "4", /* 52 */},
+{ "5", /* 53 */},
+{ "6", /* 54 */},
+{ "7", /* 55 */},
+{ "8", /* 56 */},
+{ "9", /* 57 */},
+{ ":", /* 58 */},
+{ ";", /* 59 */},
+{ "<", /* 60 */},
+{ "=", "eq", /* 61 */},
+{ ">", /* 62 */},
+{ "?", /* 63 */},
+{ "=~", /* 64 */},
+{ "*A", /* 65 */},
+{ "*B", /* 66 */},
+{ "*X", /* 67 */},
+{ "*D", /* 68 */},
+{ "*E", /* 69 */},
+{ "*F", /* 70 */},
+{ "*G", /* 71 */},
+{ "*Y", /* 72 */},
+{ "*I", /* 73 */},
+{ "+h", /* 74 */},
+{ "*K", /* 75 */},
+{ "*L", /* 76 */},
+{ "*M", /* 77 */},
+{ "*N", /* 78 */},
+{ "*O", /* 79 */},
+{ "*P", /* 80 */},
+{ "*H", /* 81 */},
+{ "*R", /* 82 */},
+{ "*S", /* 83 */},
+{ "*T", /* 84 */},
+{ 0, /* 85 */},
+{ "ts", /* 86 */},
+{ "*W", /* 87 */},
+{ "*C", /* 88 */},
+{ "*Q", /* 89 */},
+{ "*Z", /* 90 */},
+{ "[", "lB", /* 91 */},
+{ "tf", "3d", /* 92 */},
+{ "]", "rB", /* 93 */},
+{ "pp", /* 94 */},
+{ "_", /* 95 */},
+{ "radicalex", /* 96 */},
+{ "*a", /* 97 */},
+{ "*b", /* 98 */},
+{ "*x", /* 99 */},
+{ "*d", /* 100 */},
+{ "*e", /* 101 */},
+{ "*f", /* 102 */},
+{ "*g", /* 103 */},
+{ "*y", /* 104 */},
+{ "*i", /* 105 */},
+{ "+f", /* 106 */},
+{ "*k", /* 107 */},
+{ "*l", /* 108 */},
+{ "*m", "\265", /* 109 */},
+{ "*n", /* 110 */},
+{ "*o", /* 111 */},
+{ "*p", /* 112 */},
+{ "*h", /* 113 */},
+{ "*r", /* 114 */},
+{ "*s", /* 115 */},
+{ "*t", /* 116 */},
+{ "*u", /* 117 */},
+{ "+p", /* 118 */},
+{ "*w", /* 119 */},
+{ "*c", /* 120 */},
+{ "*q", /* 121 */},
+{ "*z", /* 122 */},
+{ "lC", "{", /* 123 */},
+{ "ba", "or", "|", /* 124 */},
+{ "rC", "}", /* 125 */},
+{ "ap", /* 126 */},
+{ 0, /* 127 */},
+{ 0, /* 128 */},
+{ 0, /* 129 */},
+{ 0, /* 130 */},
+{ 0, /* 131 */},
+{ 0, /* 132 */},
+{ 0, /* 133 */},
+{ 0, /* 134 */},
+{ 0, /* 135 */},
+{ 0, /* 136 */},
+{ 0, /* 137 */},
+{ 0, /* 138 */},
+{ 0, /* 139 */},
+{ 0, /* 140 */},
+{ 0, /* 141 */},
+{ 0, /* 142 */},
+{ 0, /* 143 */},
+{ 0, /* 144 */},
+{ 0, /* 145 */},
+{ 0, /* 146 */},
+{ 0, /* 147 */},
+{ 0, /* 148 */},
+{ 0, /* 149 */},
+{ 0, /* 150 */},
+{ 0, /* 151 */},
+{ 0, /* 152 */},
+{ 0, /* 153 */},
+{ 0, /* 154 */},
+{ 0, /* 155 */},
+{ 0, /* 156 */},
+{ 0, /* 157 */},
+{ 0, /* 158 */},
+{ 0, /* 159 */},
+{ 0, /* 160 */},
+{ "*U", /* 161 */},
+{ "fm", /* 162 */},
+{ "<=", /* 163 */},
+{ "f/", /* 164 */},
+{ "if", /* 165 */},
+{ "Fn", /* 166 */},
+{ "CL", /* 167 */},
+{ "DI", /* 168 */},
+{ "HE", /* 169 */},
+{ "SP", /* 170 */},
+{ "<>", /* 171 */},
+{ "<-", /* 172 */},
+{ "ua", "arrowverttp" /* 173 */},
+{ "->", /* 174 */},
+{ "da", "arrowvertbt" /* 175 */},
+{ "de", "\260", /* 176 */},
+{ "+-", "\261", /* 177 */},
+{ "sd", /* 178 */},
+{ ">=", /* 179 */},
+{ "mu", "\327", /* 180 */},
+{ "pt", /* 181 */},
+{ "pd", /* 182 */},
+{ "bu", /* 183 */},
+{ "di", "\367", /* 184 */},
+{ "!=", /* 185 */},
+{ "==", /* 186 */},
+{ "~=", "~~", /* 187 */},
+{ 0, /* 188 */},
+{ "arrowvertex", /* 189 */},
+{ "an", /* 190 */},
+{ "CR", /* 191 */},
+{ "Ah", /* 192 */},
+{ "Im", /* 193 */},
+{ "Re", /* 194 */},
+{ "wp", /* 195 */},
+{ "c*", /* 196 */},
+{ "c+", /* 197 */},
+{ "es", /* 198 */},
+{ "ca", /* 199 */},
+{ "cu", /* 200 */},
+{ "sp", /* 201 */},
+{ "ip", /* 202 */},
+{ 0, /* 203 */},
+{ "sb", /* 204 */},
+{ "ib", /* 205 */},
+{ "mo", /* 206 */},
+{ "nm", /* 207 */},
+{ "/_", /* 208 */},
+{ "gr", /* 209 */},
+{ "rg", /* 210 */},
+{ "co", /* 211 */},
+{ "tm", /* 212 */},
+{ 0, /* 213 */},
+{ "sr", /* 214 */},
+{ "md", /* 215 */},
+{ "no", "\254", /* 216 */},
+{ "AN", /* 217 */},
+{ "OR", /* 218 */},
+{ "hA", /* 219 */},
+{ "lA", /* 220 */},
+{ "uA", /* 221 */},
+{ "rA", /* 222 */},
+{ "dA", /* 223 */},
+{ "lz", /* 224 */},
+{ "la", /* 225 */},
+{ 0, /* 226 */},
+{ 0, /* 227 */},
+{ 0, /* 228 */},
+{ 0, /* 229 */},
+{ "parenlefttp", /* 230 */},
+{ "parenleftex", /* 231 */},
+{ "parenleftbt", /* 232 */},
+{ "bracketlefttp", "lc", /* 233 */},
+{ "bracketleftex", /* 234 */},
+{ "bracketleftbt", "lf", /* 235 */},
+{ "bracelefttp", "lt", /* 236 */},
+{ "braceleftmid", "lk", /* 237 */},
+{ "braceleftbt", "lb", /* 238 */},
+{ "bracerightex", "braceleftex", "bv", /* 239 */},
+{ 0, /* 240 */},
+{ "ra", /* 241 */},
+{ "is", /* 242 */},
+{ 0, /* 243 */},
+{ 0, /* 244 */},
+{ 0, /* 245 */},
+{ "parenrighttp", /* 246 */},
+{ "parenrightex", /* 247 */},
+{ "parenrightbt", /* 248 */},
+{ "bracketrighttp", "rc", /* 249 */},
+{ "bracketrightex", /* 250 */},
+{ "bracketrightbt", "rf", /* 251 */},
+{ "bracerighttp", "rt" /* 252 */},
+{ "bracerightmid", "rk" /* 253 */},
+{ "bracerightbt", "rb" /* 254 */},
+{ 0, /* 255 */},
+}};
+
+
+static void
+load_standard_maps ()
+{
+ standard_maps_loaded = 1;
+ DviRegisterMap (&ISO8859_1_map);
+ DviRegisterMap (&Adobe_Symbol_map);
+}
diff --git a/gnu/usr.bin/groff/xditview/DviChar.h b/gnu/usr.bin/groff/xditview/DviChar.h
new file mode 100644
index 0000000..b075240
--- /dev/null
+++ b/gnu/usr.bin/groff/xditview/DviChar.h
@@ -0,0 +1,37 @@
+/*
+ * DviChar.h
+ *
+ * descriptions for mapping dvi names to
+ * font indexes and back. Dvi fonts are all
+ * 256 elements (actually only 256-32 are usable).
+ *
+ * The encoding names are taken from X -
+ * case insensitive, a dash separating the
+ * CharSetRegistry from the CharSetEncoding
+ */
+
+# define DVI_MAX_SYNONYMS 10
+# define DVI_MAP_SIZE 256
+# define DVI_HASH_SIZE 256
+
+typedef struct _dviCharNameHash {
+ struct _dviCharNameHash *next;
+ char *name;
+ int position;
+} DviCharNameHash;
+
+typedef struct _dviCharNameMap {
+ char *encoding;
+ int special;
+ char *dvi_names[DVI_MAP_SIZE][DVI_MAX_SYNONYMS];
+ DviCharNameHash *buckets[DVI_HASH_SIZE];
+} DviCharNameMap;
+
+extern DviCharNameMap *DviFindMap ( /* char *encoding */ );
+extern void DviRegisterMap ( /* DviCharNameMap *map */ );
+#ifdef NOTDEF
+extern char *DviCharName ( /* DviCharNameMap *map, int index, int synonym */ );
+#else
+#define DviCharName(map,index,synonym) ((map)->dvi_names[index][synonym])
+#endif
+extern int DviCharIndex ( /* DviCharNameMap *map, char *name */ );
diff --git a/gnu/usr.bin/groff/xditview/DviP.h b/gnu/usr.bin/groff/xditview/DviP.h
new file mode 100644
index 0000000..a1c3495
--- /dev/null
+++ b/gnu/usr.bin/groff/xditview/DviP.h
@@ -0,0 +1,233 @@
+/*
+ * $XConsortium: DviP.h,v 1.5 89/07/22 19:44:08 keith Exp $
+ */
+
+/*
+ * DviP.h - Private definitions for Dvi widget
+ */
+
+#ifndef _XtDviP_h
+#define _XtDviP_h
+
+#include "Dvi.h"
+#include "DviChar.h"
+#include "device.h"
+
+/***********************************************************************
+ *
+ * Dvi Widget Private Data
+ *
+ ***********************************************************************/
+
+/************************************
+ *
+ * Class structure
+ *
+ ***********************************/
+
+/* Type for save method. */
+
+typedef void (*DviSaveProc)();
+
+/*
+ * New fields for the Dvi widget class record
+ */
+
+
+typedef struct _DviClass {
+ DviSaveProc save;
+} DviClassPart;
+
+/*
+ * Full class record declaration
+ */
+
+typedef struct _DviClassRec {
+ CoreClassPart core_class;
+ DviClassPart command_class;
+} DviClassRec;
+
+extern DviClassRec dviClassRec;
+
+/***************************************
+ *
+ * Instance (widget) structure
+ *
+ **************************************/
+
+/*
+ * a list of fonts we've used for this widget
+ */
+
+typedef struct _dviFontSizeList {
+ struct _dviFontSizeList *next;
+ int size;
+ char *x_name;
+ XFontStruct *font;
+ int doesnt_exist;
+} DviFontSizeList;
+
+typedef struct _dviFontList {
+ struct _dviFontList *next;
+ char *dvi_name;
+ char *x_name;
+ int dvi_number;
+ Boolean initialized;
+ Boolean scalable;
+ DviFontSizeList *sizes;
+ DviCharNameMap *char_map;
+ DeviceFont *device_font;
+} DviFontList;
+
+typedef struct _dviFontMap {
+ struct _dviFontMap *next;
+ char *dvi_name;
+ char *x_name;
+} DviFontMap;
+
+#define DVI_TEXT_CACHE_SIZE 256
+#define DVI_CHAR_CACHE_SIZE 1024
+
+typedef struct _dviCharCache {
+ XTextItem cache[DVI_TEXT_CACHE_SIZE];
+ char adjustable[DVI_TEXT_CACHE_SIZE];
+ char char_cache[DVI_CHAR_CACHE_SIZE];
+ int index;
+ int max;
+ int char_index;
+ int font_size;
+ int font_number;
+ XFontStruct *font;
+ int start_x, start_y;
+ int x, y;
+} DviCharCache;
+
+typedef struct _dviState {
+ struct _dviState *next;
+ int font_size;
+ int font_number;
+ int x;
+ int y;
+} DviState;
+
+typedef struct _dviFileMap {
+ struct _dviFileMap *next;
+ long position;
+ int page_number;
+} DviFileMap;
+
+/*
+ * New fields for the Dvi widget record
+ */
+
+typedef struct {
+ /*
+ * resource specifiable items
+ */
+ char *font_map_string;
+ unsigned long foreground;
+ unsigned long background;
+ int requested_page;
+ int last_page;
+ XFontStruct *default_font;
+ FILE *file;
+ Boolean noPolyText;
+ Boolean seek; /* file is "seekable" */
+ int default_resolution;
+ /*
+ * private state
+ */
+ FILE *tmpFile; /* used when reading stdin */
+ char readingTmp; /* reading now from tmp */
+ char ungot; /* have ungetc'd a char */
+ GC normal_GC;
+ GC fill_GC;
+ DviFileMap *file_map;
+ DviFontList *fonts;
+ DviFontMap *font_map;
+ int current_page;
+ int font_size;
+ int font_number;
+ DeviceFont *device_font;
+ int device_font_number;
+ Device *device;
+ int native;
+ int device_resolution;
+ int display_resolution;
+ int paperlength;
+ int paperwidth;
+ double scale_factor; /* display res / device res */
+ int sizescale;
+ int line_thickness;
+ int line_width;
+
+#define DVI_FILL_MAX 1000
+
+ int fill;
+#define DVI_FILL_WHITE 0
+#define DVI_FILL_GRAY 1
+#define DVI_FILL_BLACK 2
+ int fill_type;
+ Pixmap gray;
+ int backing_store;
+ XFontStruct *font;
+ int display_enable;
+ struct ExposedExtents {
+ int x1, y1, x2, y2;
+ } extents;
+ DviState *state;
+ DviCharCache cache;
+ int text_x_width;
+ int text_device_width;
+ int word_flag;
+} DviPart;
+
+#define DviGetIn(dw,cp)\
+ (dw->dvi.tmpFile ? (\
+ DviGetAndPut (dw, cp) \
+ ) :\
+ (*cp = getc (dw->dvi.file))\
+)
+
+#define DviGetC(dw, cp)\
+ (dw->dvi.readingTmp ? (\
+ ((*cp = getc (dw->dvi.tmpFile)) == EOF) ? (\
+ fseek (dw->dvi.tmpFile, 0l, 2),\
+ (dw->dvi.readingTmp = 0),\
+ DviGetIn (dw,cp)\
+ ) : (\
+ *cp\
+ )\
+ ) : (\
+ DviGetIn(dw,cp)\
+ )\
+)
+
+#define DviUngetC(dw, c)\
+ (dw->dvi.readingTmp ? (\
+ ungetc (c, dw->dvi.tmpFile)\
+ ) : ( \
+ (dw->dvi.ungot = 1),\
+ ungetc (c, dw->dvi.file)))
+
+/*
+ * Full widget declaration
+ */
+
+typedef struct _DviRec {
+ CorePart core;
+ DviPart dvi;
+} DviRec;
+
+#define InheritSaveToFile ((DviSaveProc)_XtInherit)
+
+extern XFontStruct *QueryFont ();
+
+extern DviCharNameMap *QueryFontMap ();
+
+extern DeviceFont *QueryDeviceFont ();
+
+extern char *GetWord(), *GetLine();
+#endif /* _XtDviP_h */
+
+
diff --git a/gnu/usr.bin/groff/xditview/FontMap b/gnu/usr.bin/groff/xditview/FontMap
new file mode 100644
index 0000000..90911f0
--- /dev/null
+++ b/gnu/usr.bin/groff/xditview/FontMap
@@ -0,0 +1,17 @@
+TR -adobe-times-medium-r-normal--*-*-*-*-p-*-iso8859-1
+TI -adobe-times-medium-i-normal--*-*-*-*-p-*-iso8859-1
+TB -adobe-times-bold-r-normal--*-*-*-*-p-*-iso8859-1
+TBI -adobe-times-bold-i-normal--*-*-*-*-p-*-iso8859-1
+CR -adobe-courier-medium-r-normal--*-*-*-*-m-*-iso8859-1
+CI -adobe-courier-medium-o-normal--*-*-*-*-m-*-iso8859-1
+CB -adobe-courier-bold-r-normal--*-*-*-*-m-*-iso8859-1
+CBI -adobe-courier-bold-o-normal--*-*-*-*-m-*-iso8859-1
+HR -adobe-helvetica-medium-r-normal--*-*-*-*-p-*-iso8859-1
+HI -adobe-helvetica-medium-o-normal--*-*-*-*-p-*-iso8859-1
+HB -adobe-helvetica-bold-r-normal--*-*-*-*-p-*-iso8859-1
+HBI -adobe-helvetica-bold-o-normal--*-*-*-*-p-*-iso8859-1
+NR -adobe-new century schoolbook-medium-r-normal--*-*-*-*-p-*-iso8859-1
+NI -adobe-new century schoolbook-medium-i-normal--*-*-*-*-p-*-iso8859-1
+NB -adobe-new century schoolbook-bold-r-normal--*-*-*-*-p-*-iso8859-1
+NBI -adobe-new century schoolbook-bold-i-normal--*-*-*-*-p-*-iso8859-1
+S -adobe-symbol-medium-r-normal--*-*-*-*-p-*-adobe-fontspecific
diff --git a/gnu/usr.bin/groff/xditview/GXditview.ad b/gnu/usr.bin/groff/xditview/GXditview.ad
new file mode 100644
index 0000000..e99ff5e
--- /dev/null
+++ b/gnu/usr.bin/groff/xditview/GXditview.ad
@@ -0,0 +1,57 @@
+GXditview.height: 840
+
+GXditview.paned.allowResize: true
+GXditview.paned.viewport.allowVert: true
+GXditview.paned.viewport.allowHoriz: true
+GXditview.paned.viewport.skipAdjust: false
+GXditview.paned.viewport.width: 600
+GXditview.paned.viewport.height: 800
+GXditview.paned.viewport.showGrip: false
+GXditview.paned.label.skipAdjust: true
+
+GXditview.paned.viewport.dvi.translations: #augment \
+ <Btn1Down>: XawPositionSimpleMenu(menu) MenuPopup(menu)\n\
+ <Key>Next: NextPage()\n\
+ <Key>n: NextPage()\n\
+ <Key>space: NextPage()\n\
+ <Key>Return: NextPage()\n\
+ <Key>Prior: PreviousPage()\n\
+ <Key>p: PreviousPage()\n\
+ <Key>BackSpace: PreviousPage()\n\
+ <Key>Delete: PreviousPage()\n\
+ <Key>Select: SelectPage()\n\
+ <Key>Find: OpenFile()\n\
+ <Key>r: Rerasterize()\n\
+ <Key>q: Quit()
+GXditview.paned.label.translations: #augment \
+ <Btn1Down>: XawPositionSimpleMenu(menu) MenuPopup(menu)\n\
+ <Key>Next: NextPage()\n\
+ <Key>n: NextPage()\n\
+ <Key>space: NextPage()\n\
+ <Key>Return: NextPage()\n\
+ <Key>Prior: PreviousPage()\n\
+ <Key>p: PreviousPage()\n\
+ <Key>BackSpace: PreviousPage()\n\
+ <Key>Delete: PreviousPage()\n\
+ <Key>Select: SelectPage()\n\
+ <Key>Find: OpenFile()\n\
+ <Key>r: Rerasterize()\n\
+ <Key>q: Quit()
+GXditview.menu.nextPage.label: Next Page
+GXditview.menu.previousPage.label: Previous Page
+GXditview.menu.selectPage.label: Select Page
+GXditview.menu.print.label: Print
+GXditview.menu.openFile.label: Open
+GXditview.menu.quit.label: Quit
+
+GXditview.promptShell.allowShellResize: true
+GXditview.promptShell.promptDialog.value.translations: #override \
+ <Key>Return: Accept()
+
+GXditview.promptShell.promptDialog.accept.label: Accept
+GXditview.promptShell.promptDialog.accept.translations: #override \
+ <BtnUp>: Accept() unset()
+
+GXditview.promptShell.promptDialog.cancel.label: Cancel
+GXditview.promptShell.promptDialog.cancel.translations: #override \
+ <BtnUp>: Cancel() unset()
diff --git a/gnu/usr.bin/groff/xditview/INSTALL b/gnu/usr.bin/groff/xditview/INSTALL
new file mode 100644
index 0000000..144118f
--- /dev/null
+++ b/gnu/usr.bin/groff/xditview/INSTALL
@@ -0,0 +1,20 @@
+This version of gxditview uses imake.
+
+Here are the steps needed to install gxditview:
+
+- edit the Imakefile if necessary
+
+- xmkmf
+
+- make depend
+
+- make
+
+- make install
+
+- make install.man (installs the man page)
+
+The gxditview binary will be installed in the usual place for X
+binaries (eg /usr/bin/X11). Previous versions of gxditview were
+installed along with the other groff binaries (eg in /usr/local/bin);
+you will need to remove these by hand.
diff --git a/gnu/usr.bin/groff/xditview/Imakefile b/gnu/usr.bin/groff/xditview/Imakefile
new file mode 100644
index 0000000..62ac707
--- /dev/null
+++ b/gnu/usr.bin/groff/xditview/Imakefile
@@ -0,0 +1,52 @@
+GROFF_LIBDIR = /usr/local/lib/groff
+GROFF_FONTDIR = $(GROFF_LIBDIR)/font
+GROFF_FONTPATH = .:$(GROFF_FONTDIR):/usr/local/lib/font:/usr/lib/font
+DPIS = 75 100
+
+PROGRAMS = gxditview xtotroff
+DEPLIBS = XawClientDepLibs
+LOCAL_LIBRARIES = XawClientLibs
+SRCS1 = xditview.c Dvi.c draw.c font.c lex.c page.c \
+ parse.c XFontName.c DviChar.c device.c
+OBJS1 = xditview.o Dvi.o draw.o font.o lex.o page.o \
+ parse.o XFontName.o DviChar.o device.o
+SRCS2 = xtotroff.c XFontName.c DviChar.c
+OBJS2 = xtotroff.o XFontName.o DviChar.o
+INCLUDES = -I$(TOOLKITSRC) -I$(TOP)
+MATHLIB = -lm
+DEFINES = $(SIGNAL_DEFINES) -DFONTPATH=\"$(GROFF_FONTPATH)\" # -DX_NOT_STDC_ENV
+
+ComplexProgramTarget_1(gxditview,$(LOCAL_LIBRARIES),$(MATHLIB))
+NormalProgramTarget(xtotroff,$(OBJS2),$(DEPXLIB),$(XLIB), /**/)
+
+InstallAppDefaults(GXditview)
+
+fonts: xtotroff DESC FontMap
+ @dir=`pwd`; \
+ fonts=`sed -e 's/[ ].*//' FontMap`; \
+ for dpi in $(DPIS); do \
+ echo Making devX$$dpi; \
+ test -d ../devX$$dpi || mkdir ../devX$$dpi; \
+ rm -f ../devX$$dpi/DESC; \
+ sed -e "s/res 75/res $$dpi/" DESC >../devX$$dpi/DESC; \
+ (cd ../devX$$dpi; \
+ rm -f Makefile.sub; \
+ echo DEV=X$$dpi >Makefile.sub; \
+ echo DEVFILES=DESC $$fonts >>Makefile.sub; \
+ $$dir/xtotroff -g -r $$dpi -s 10 $$dir/FontMap); \
+ echo Making devX$$dpi-12; \
+ test -d ../devX$$dpi-12 || mkdir ../devX$$dpi-12; \
+ rm -f ../devX$$dpi-12/DESC; \
+ sed -e "s/res 75/res $$dpi/" -e 's/unitwidth 10/unitwidth 12/' DESC \
+ >../devX$$dpi-12/DESC; \
+ (cd ../devX$$dpi-12; \
+ rm -f Makefile.sub; \
+ echo DEV=X$$dpi-12 >Makefile.sub; \
+ echo DEVFILES=DESC $$fonts >>Makefile.sub; \
+ $$dir/xtotroff -g -r $$dpi -s 12 $$dir/FontMap); \
+ done
+
+extraclean: clean
+ -rm -f junk tmp grot old
+
+FORCE:
diff --git a/gnu/usr.bin/groff/xditview/Makefile b/gnu/usr.bin/groff/xditview/Makefile
new file mode 100644
index 0000000..9aa11dc
--- /dev/null
+++ b/gnu/usr.bin/groff/xditview/Makefile
@@ -0,0 +1,34 @@
+.if exists(${X11BASE}/include/X11/Xlib.h)
+.if exists(${X11BASE}/lib)
+.if exists(${DESTDIR}${X11BASE}/bin)
+.if exists(${DESTDIR}${X11BASE}/man/man1)
+.if exists(${DESTDIR}${X11BASE}/lib/X11/app-defaults)
+
+BINDIR= ${X11BASE}/bin
+MANDIR= ${X11BASE}/man/man
+
+MANDEPEND= gxditview.1
+CLEANFILES+= ${MANDEPEND}
+
+PROG= gxditview
+CFLAGS+= -I${X11BASE}/include -DFONTPATH=\"$(fontpath)\"
+SRCS+= xditview.c Dvi.c draw.c font.c lex.c page.c parse.c \
+ XFontName.c DviChar.c device.c
+LDDESTDIR+= -L${X11BASE}/lib
+LDADD+= -lXaw -lXmu -lXt -lXext -lX11 -lm
+DPADD+= ${X11BASE}/lib/libXaw.a ${X11BASE}/lib/libXmu.a \
+ ${X11BASE}/lib/libXt.a ${X11BASE}/lib/libXext.a \
+ ${X11BASE}/lib/libX11.a
+
+afterinstall:
+ ${INSTALL} -c -o ${BINOWN} -g ${BINGRP} -m 444 \
+ ${.CURDIR}/GXditview.ad \
+ ${DESTDIR}${X11BASE}/lib/X11/app-defaults/GXditview
+.endif
+.endif
+.endif
+.endif
+.endif
+
+.include "../Makefile.cfg"
+.include <bsd.prog.mk>
diff --git a/gnu/usr.bin/groff/xditview/Menu.h b/gnu/usr.bin/groff/xditview/Menu.h
new file mode 100644
index 0000000..c306b27
--- /dev/null
+++ b/gnu/usr.bin/groff/xditview/Menu.h
@@ -0,0 +1,46 @@
+/*
+ * $XConsortium: Menu.h,v 1.2 89/07/21 14:22:10 jim Exp $
+ */
+
+#ifndef _XtMenu_h
+#define _XtMenu_h
+
+/***********************************************************************
+ *
+ * Menu Widget
+ *
+ ***********************************************************************/
+
+/* Parameters:
+
+ Name Class RepType Default Value
+ ---- ----- ------- -------------
+ background Background pixel White
+ border BorderColor pixel Black
+ borderWidth BorderWidth int 1
+ height Height int 120
+ mappedWhenManaged MappedWhenManaged Boolean True
+ reverseVideo ReverseVideo Boolean False
+ width Width int 120
+ x Position int 0
+ y Position int 0
+
+*/
+
+#define XtNmenuEntries "menuEntries"
+#define XtNhorizontalPadding "horizontalPadding"
+#define XtNverticalPadding "verticalPadding"
+#define XtNselection "Selection"
+
+#define XtCMenuEntries "MenuEntries"
+#define XtCPadding "Padding"
+#define XtCSelection "Selection"
+
+typedef struct _MenuRec *MenuWidget; /* completely defined in MenuPrivate.h */
+typedef struct _MenuClassRec *MenuWidgetClass; /* completely defined in MenuPrivate.h */
+
+extern WidgetClass menuWidgetClass;
+
+extern Widget XawMenuCreate ();
+#endif /* _XtMenu_h */
+/* DON'T ADD STUFF AFTER THIS #endif */
diff --git a/gnu/usr.bin/groff/xditview/README b/gnu/usr.bin/groff/xditview/README
new file mode 100644
index 0000000..b99a991
--- /dev/null
+++ b/gnu/usr.bin/groff/xditview/README
@@ -0,0 +1,14 @@
+This is gxditview, a X11 previewer for groff based on MIT's xditview.
+This version can be used with the output of gtroff -Tps as well as
+with -TX75 and -TX100. You will need X11R5 to install it (it might
+work on X11R4, but I haven't tested it.)
+
+See the file INSTALL in this directory for installation instructions.
+
+xditview is copyrighted by MIT under the usual X terms (see
+gxditview.man); my changes to it are in the public domain.
+
+Please report bugs to bug-groff@prep.ai.mit.edu.
+
+James Clark
+jjc@jclark.com
diff --git a/gnu/usr.bin/groff/xditview/TODO b/gnu/usr.bin/groff/xditview/TODO
new file mode 100644
index 0000000..83a3ca1
--- /dev/null
+++ b/gnu/usr.bin/groff/xditview/TODO
@@ -0,0 +1,15 @@
+Better error handling.
+
+Resource and command-line option to specify font path.
+
+Resource to specify name of environment variable from which to get the
+font path.
+
+Have character substitutions (currently done in draw.c:FakeCharacter)
+specified in a resource (similar format to FontMap).
+
+The initial width of the dialog box should expand to accommodate the
+default value.
+
+Option in Print dialog to specify that only the current page should be
+printed.
diff --git a/gnu/usr.bin/groff/xditview/XFontName.c b/gnu/usr.bin/groff/xditview/XFontName.c
new file mode 100644
index 0000000..0aa7618
--- /dev/null
+++ b/gnu/usr.bin/groff/xditview/XFontName.c
@@ -0,0 +1,256 @@
+/*
+ * XFontName.c
+ *
+ * build/parse X Font name strings
+ */
+
+#include <X11/Xlib.h>
+#include <X11/Xos.h>
+#include "XFontName.h"
+#include <ctype.h>
+
+static char *
+extractStringField (name, buffer, size, attrp, bit)
+ char *name;
+ char *buffer;
+ int size;
+ unsigned int *attrp;
+ unsigned int bit;
+{
+ char *buf = buffer;
+
+ if (!*name)
+ return 0;
+ while (*name && *name != '-' && size > 0) {
+ *buf++ = *name++;
+ --size;
+ }
+ if (size <= 0)
+ return 0;
+ *buf = '\0';
+ if (buffer[0] != '*' || buffer[1] != '\0')
+ *attrp |= bit;
+ if (*name == '-')
+ return name+1;
+ return name;
+}
+
+static char *
+extractUnsignedField (name, result, attrp, bit)
+ char *name;
+ unsigned int *result;
+ unsigned int *attrp;
+ unsigned int bit;
+{
+ char buf[256];
+ char *c;
+ unsigned int i;
+
+ name = extractStringField (name, buf, sizeof (buf), attrp, bit);
+ if (!name)
+ return 0;
+ if (!(*attrp & bit))
+ return name;
+ i = 0;
+ for (c = buf; *c; c++) {
+ if (!isdigit (*c))
+ return 0;
+ i = i * 10 + (*c - '0');
+ }
+ *result = i;
+ return name;
+}
+
+Bool
+XParseFontName (fontNameString, fontName, fontNameAttributes)
+ XFontNameString fontNameString;
+ XFontName *fontName;
+ unsigned int *fontNameAttributes;
+{
+ char *name = fontNameString;
+ XFontName temp;
+ unsigned int attributes = 0;
+
+#define GetString(field,bit)\
+ if (!(name = extractStringField \
+ (name, temp.field, sizeof (temp.field),\
+ &attributes, bit))) \
+ return False;
+
+#define GetUnsigned(field,bit)\
+ if (!(name = extractUnsignedField \
+ (name, &temp.field, \
+ &attributes, bit))) \
+ return False;
+
+ GetString (Registry, FontNameRegistry)
+ GetString (Foundry, FontNameFoundry)
+ GetString (FamilyName, FontNameFamilyName)
+ GetString (WeightName, FontNameWeightName)
+ GetString (Slant, FontNameSlant)
+ GetString (SetwidthName, FontNameSetwidthName)
+ GetString (AddStyleName, FontNameAddStyleName)
+ GetUnsigned (PixelSize, FontNamePixelSize)
+ GetUnsigned (PointSize, FontNamePointSize)
+ GetUnsigned (ResolutionX, FontNameResolutionX)
+ GetUnsigned (ResolutionY, FontNameResolutionY)
+ GetString (Spacing, FontNameSpacing)
+ GetUnsigned (AverageWidth, FontNameAverageWidth)
+ GetString (CharSetRegistry, FontNameCharSetRegistry)
+ if (!*name) {
+ temp.CharSetEncoding[0] = '\0';
+ attributes |= FontNameCharSetEncoding;
+ } else {
+ GetString (CharSetEncoding, FontNameCharSetEncoding)
+ }
+ *fontName = temp;
+ *fontNameAttributes = attributes;
+ return True;
+}
+
+static char *
+utoa (u, s, size)
+ unsigned int u;
+ char *s;
+ int size;
+{
+ char *t;
+
+ t = s + size;
+ *--t = '\0';
+ do
+ *--t = (u % 10) + '0';
+ while (u /= 10);
+ return t;
+}
+
+Bool
+XFormatFontName (fontName, fontNameAttributes, fontNameString)
+ XFontName *fontName;
+ unsigned int fontNameAttributes;
+ XFontNameString fontNameString;
+{
+ XFontNameString tmp;
+ char *name = tmp, *f;
+ int left = sizeof (tmp) - 1;
+ char number[32];
+
+#define PutString(field, bit)\
+ f = (fontNameAttributes & bit) ? \
+ fontName->field \
+ : "*"; \
+ if ((left -= strlen (f)) < 0) \
+ return False; \
+ while (*f) \
+ if ((*name++ = *f++) == '-') \
+ return False;
+#define PutHyphen()\
+ if (--left < 0) \
+ return False; \
+ *name++ = '-';
+
+#define PutUnsigned(field, bit) \
+ f = (fontNameAttributes & bit) ? \
+ utoa (fontName->field, number, sizeof (number)) \
+ : "*"; \
+ if ((left -= strlen (f)) < 0) \
+ return False; \
+ while (*f) \
+ *name++ = *f++;
+
+ PutString (Registry, FontNameRegistry)
+ PutHyphen ();
+ PutString (Foundry, FontNameFoundry)
+ PutHyphen ();
+ PutString (FamilyName, FontNameFamilyName)
+ PutHyphen ();
+ PutString (WeightName, FontNameWeightName)
+ PutHyphen ();
+ PutString (Slant, FontNameSlant)
+ PutHyphen ();
+ PutString (SetwidthName, FontNameSetwidthName)
+ PutHyphen ();
+ PutString (AddStyleName, FontNameAddStyleName)
+ PutHyphen ();
+ PutUnsigned (PixelSize, FontNamePixelSize)
+ PutHyphen ();
+ PutUnsigned (PointSize, FontNamePointSize)
+ PutHyphen ();
+ PutUnsigned (ResolutionX, FontNameResolutionX)
+ PutHyphen ();
+ PutUnsigned (ResolutionY, FontNameResolutionY)
+ PutHyphen ();
+ PutString (Spacing, FontNameSpacing)
+ PutHyphen ();
+ PutUnsigned (AverageWidth, FontNameAverageWidth)
+ PutHyphen ();
+ PutString (CharSetRegistry, FontNameCharSetRegistry)
+ PutHyphen ();
+ PutString (CharSetEncoding, FontNameCharSetEncoding)
+ *name = '\0';
+ strcpy (fontNameString, tmp);
+ return True;
+}
+
+Bool
+XCompareFontName (name1, name2, fontNameAttributes)
+ XFontName *name1, *name2;
+ unsigned int fontNameAttributes;
+{
+#define CompareString(field,bit) \
+ if (fontNameAttributes & bit) \
+ if (strcmp (name1->field, name2->field)) \
+ return False;
+
+#define CompareUnsigned(field,bit) \
+ if (fontNameAttributes & bit) \
+ if (name1->field != name2->field) \
+ return False;
+
+ CompareString (Registry, FontNameRegistry)
+ CompareString (Foundry, FontNameFoundry)
+ CompareString (FamilyName, FontNameFamilyName)
+ CompareString (WeightName, FontNameWeightName)
+ CompareString (Slant, FontNameSlant)
+ CompareString (SetwidthName, FontNameSetwidthName)
+ CompareString (AddStyleName, FontNameAddStyleName)
+ CompareUnsigned (PixelSize, FontNamePixelSize)
+ CompareUnsigned (PointSize, FontNamePointSize)
+ CompareUnsigned (ResolutionX, FontNameResolutionX)
+ CompareUnsigned (ResolutionY, FontNameResolutionY)
+ CompareString (Spacing, FontNameSpacing)
+ CompareUnsigned (AverageWidth, FontNameAverageWidth)
+ CompareString (CharSetRegistry, FontNameCharSetRegistry)
+ CompareString (CharSetEncoding, FontNameCharSetEncoding)
+ return True;
+}
+
+XCopyFontName (name1, name2, fontNameAttributes)
+ XFontName *name1, *name2;
+ unsigned int fontNameAttributes;
+{
+#define CopyString(field,bit) \
+ if (fontNameAttributes & bit) \
+ strcpy (name2->field, name1->field);
+
+#define CopyUnsigned(field,bit) \
+ if (fontNameAttributes & bit) \
+ name2->field = name1->field;
+
+ CopyString (Registry, FontNameRegistry)
+ CopyString (Foundry, FontNameFoundry)
+ CopyString (FamilyName, FontNameFamilyName)
+ CopyString (WeightName, FontNameWeightName)
+ CopyString (Slant, FontNameSlant)
+ CopyString (SetwidthName, FontNameSetwidthName)
+ CopyString (AddStyleName, FontNameAddStyleName)
+ CopyUnsigned (PixelSize, FontNamePixelSize)
+ CopyUnsigned (PointSize, FontNamePointSize)
+ CopyUnsigned (ResolutionX, FontNameResolutionX)
+ CopyUnsigned (ResolutionY, FontNameResolutionY)
+ CopyString (Spacing, FontNameSpacing)
+ CopyUnsigned (AverageWidth, FontNameAverageWidth)
+ CopyString (CharSetRegistry, FontNameCharSetRegistry)
+ CopyString (CharSetEncoding, FontNameCharSetEncoding)
+ return True;
+}
diff --git a/gnu/usr.bin/groff/xditview/XFontName.h b/gnu/usr.bin/groff/xditview/XFontName.h
new file mode 100644
index 0000000..efe9eb1
--- /dev/null
+++ b/gnu/usr.bin/groff/xditview/XFontName.h
@@ -0,0 +1,45 @@
+typedef struct _xFontName {
+ char Registry[256];
+ char Foundry[256];
+ char FamilyName[256];
+ char WeightName[256];
+ char Slant[3];
+ char SetwidthName[256];
+ char AddStyleName[256];
+ unsigned int PixelSize;
+ unsigned int PointSize;
+ unsigned int ResolutionX;
+ unsigned int ResolutionY;
+ char Spacing[2];
+ unsigned int AverageWidth;
+ char CharSetRegistry[256];
+ char CharSetEncoding[256];
+} XFontName;
+
+#define FontNameRegistry (1<<0)
+#define FontNameFoundry (1<<1)
+#define FontNameFamilyName (1<<2)
+#define FontNameWeightName (1<<3)
+#define FontNameSlant (1<<4)
+#define FontNameSetwidthName (1<<5)
+#define FontNameAddStyleName (1<<6)
+#define FontNamePixelSize (1<<7)
+#define FontNamePointSize (1<<8)
+#define FontNameResolutionX (1<<9)
+#define FontNameResolutionY (1<<10)
+#define FontNameSpacing (1<<11)
+#define FontNameAverageWidth (1<<12)
+#define FontNameCharSetRegistry (1<<13)
+#define FontNameCharSetEncoding (1<<14)
+
+#define SlantRoman "R"
+#define SlantItalic "I"
+#define SlantOblique "O"
+#define SlantReverseItalic "RI"
+#define SlantReverseOblique "RO"
+
+#define SpacingMonoSpaced "M"
+#define SpacingProportional "P"
+#define SpacingCharacterCell "C"
+
+typedef char XFontNameString[256];
diff --git a/gnu/usr.bin/groff/xditview/device.c b/gnu/usr.bin/groff/xditview/device.c
new file mode 100644
index 0000000..6410472
--- /dev/null
+++ b/gnu/usr.bin/groff/xditview/device.c
@@ -0,0 +1,589 @@
+/* device.c */
+
+#include <stdio.h>
+#include <ctype.h>
+
+#include <X11/Xos.h>
+#include <X11/Intrinsic.h>
+
+#include "device.h"
+
+#ifndef FONTPATH
+#define FONTPATH "/usr/local/lib/groff/font:/usr/local/lib/font:/usr/lib/font"
+#endif
+
+#ifndef isascii
+#define isascii(c) (1)
+#endif
+
+extern void exit();
+extern char *strtok(), *strchr();
+extern char *getenv();
+
+/* Name of environment variable containing path to be used for
+searching for device and font description files. */
+#define FONTPATH_ENV_VAR "GROFF_FONT_PATH"
+
+#define WS " \t\r\n"
+
+/* Minimum and maximum values a `signed int' can hold. */
+#ifndef INT_MIN
+#define INT_MIN (-INT_MAX-1)
+#endif
+#ifndef INT_MAX
+#define INT_MAX 2147483647
+#endif
+
+#define CHAR_TABLE_SIZE 307
+
+struct _DeviceFont {
+ char *name;
+ int special;
+ DeviceFont *next;
+ Device *dev;
+ struct charinfo *char_table[CHAR_TABLE_SIZE];
+ struct charinfo *code_table[256];
+};
+
+struct charinfo {
+ int width;
+ int code;
+ struct charinfo *next;
+ struct charinfo *code_next;
+ char name[1];
+};
+
+static char *current_filename = 0;
+static int current_lineno = -1;
+
+static void error();
+static FILE *open_device_file();
+static DeviceFont *load_font();
+static Device *new_device();
+static DeviceFont *new_font();
+static void delete_font();
+static unsigned hash_name();
+static struct charinfo *add_char();
+static int read_charset_section();
+static char *canonicalize_name();
+
+static
+Device *new_device(name)
+ char *name;
+{
+ Device *dev;
+
+ dev = XtNew(Device);
+ dev->sizescale = 1;
+ dev->res = 0;
+ dev->unitwidth = 0;
+ dev->fonts = 0;
+ dev->X11 = 0;
+ dev->paperlength = 0;
+ dev->paperwidth = 0;
+ dev->name = XtNewString(name);
+ return dev;
+}
+
+void device_destroy(dev)
+ Device *dev;
+{
+ DeviceFont *f;
+
+ if (!dev)
+ return;
+ f = dev->fonts;
+ while (f) {
+ DeviceFont *tem = f;
+ f = f->next;
+ delete_font(tem);
+ }
+
+ XtFree(dev->name);
+ XtFree((char *)dev);
+}
+
+Device *device_load(name)
+ char *name;
+{
+ Device *dev;
+ FILE *fp;
+ int err = 0;
+ char buf[256];
+
+ fp = open_device_file(name, "DESC", &current_filename);
+ if (!fp)
+ return 0;
+ dev = new_device(name);
+ current_lineno = 0;
+ while (fgets(buf, sizeof(buf), fp)) {
+ char *p;
+ current_lineno++;
+ p = strtok(buf, WS);
+ if (p) {
+ int *np = 0;
+ char *q;
+
+ if (strcmp(p, "charset") == 0)
+ break;
+ if (strcmp(p, "X11") == 0)
+ dev->X11 = 1;
+ else if (strcmp(p, "sizescale") == 0)
+ np = &dev->sizescale;
+ else if (strcmp(p, "res") == 0)
+ np = &dev->res;
+ else if (strcmp(p, "unitwidth") == 0)
+ np = &dev->unitwidth;
+ else if (strcmp(p, "paperwidth") == 0)
+ np = &dev->paperwidth;
+ else if (strcmp(p, "paperlength") == 0)
+ np = &dev->paperlength;
+
+ if (np) {
+ q = strtok((char *)0, WS);
+ if (!q || sscanf(q, "%d", np) != 1 || *np <= 0) {
+ error("bad argument");
+ err = 1;
+ break;
+ }
+ }
+ }
+ }
+ fclose(fp);
+ current_lineno = -1;
+ if (!err) {
+ if (dev->res == 0) {
+ error("missing res line");
+ err = 1;
+ }
+ else if (dev->unitwidth == 0) {
+ error("missing unitwidth line");
+ err = 1;
+ }
+ }
+ if (dev->paperlength == 0)
+ dev->paperlength = dev->res*11;
+ if (dev->paperwidth == 0)
+ dev->paperwidth = dev->res*8 + dev->res/2;
+ if (err) {
+ device_destroy(dev);
+ dev = 0;
+ }
+ XtFree(current_filename);
+ current_filename = 0;
+ return dev;
+}
+
+
+DeviceFont *device_find_font(dev, name)
+ Device *dev;
+ char *name;
+{
+ DeviceFont *f;
+
+ if (!dev)
+ return 0;
+ for (f = dev->fonts; f; f = f->next)
+ if (strcmp(f->name, name) == 0)
+ return f;
+ return load_font(dev, name);
+}
+
+static
+DeviceFont *load_font(dev, name)
+ Device *dev;
+ char *name;
+{
+ FILE *fp;
+ char buf[256];
+ DeviceFont *f;
+ int special = 0;
+
+ fp = open_device_file(dev->name, name, &current_filename);
+ if (!fp)
+ return 0;
+ current_lineno = 0;
+ for (;;) {
+ char *p;
+
+ if (!fgets(buf, sizeof(buf), fp)) {
+ error("no charset line");
+ return 0;
+ }
+ current_lineno++;
+ p = strtok(buf, WS);
+ /* charset must be on a line by itself */
+ if (p && strcmp(p, "charset") == 0 && strtok((char *)0, WS) == 0)
+ break;
+ if (p && strcmp(p, "special") == 0)
+ special = 1;
+ }
+ f = new_font(name, dev);
+ f->special = special;
+ if (!read_charset_section(f, fp)) {
+ delete_font(f);
+ f = 0;
+ }
+ else {
+ f->next = dev->fonts;
+ dev->fonts = f;
+ }
+ fclose(fp);
+ XtFree(current_filename);
+ current_filename = 0;
+ return f;
+}
+
+static
+DeviceFont *new_font(name, dev)
+ char *name;
+ Device *dev;
+{
+ int i;
+ DeviceFont *f;
+
+ f = XtNew(DeviceFont);
+ f->name = XtNewString(name);
+ f->dev = dev;
+ f->special = 0;
+ f->next = 0;
+ for (i = 0; i < CHAR_TABLE_SIZE; i++)
+ f->char_table[i] = 0;
+ for (i = 0; i < 256; i++)
+ f->code_table[i] = 0;
+ return f;
+}
+
+static
+void delete_font(f)
+ DeviceFont *f;
+{
+ int i;
+
+ if (!f)
+ return;
+ XtFree(f->name);
+ for (i = 0; i < CHAR_TABLE_SIZE; i++) {
+ struct charinfo *ptr = f->char_table[i];
+ while (ptr) {
+ struct charinfo *tem = ptr;
+ ptr = ptr->next;
+ XtFree((char *)tem);
+ }
+ }
+ XtFree((char *)f);
+}
+
+
+static
+unsigned hash_name(name)
+ char *name;
+{
+ unsigned n = 0;
+ /* XXX do better than this */
+ while (*name)
+ n = (n << 1) ^ *name++;
+
+ return n;
+}
+
+static
+int scale_round(n, x, y)
+ int n, x, y;
+{
+ int y2;
+
+ if (x == 0)
+ return 0;
+ y2 = y/2;
+ if (n >= 0) {
+ if (n <= (INT_MAX - y2)/x)
+ return (n*x + y2)/y;
+ }
+ else if (-(unsigned)n <= (-(unsigned)INT_MIN - y2)/x)
+ return (n*x - y2)/y;
+ return (int)(n*(double)x/(double)y + .5);
+}
+
+static
+char *canonicalize_name(s)
+ char *s;
+{
+ static char ch[2];
+ if (s[0] == 'c' && s[1] == 'h' && s[2] == 'a' && s[3] == 'r') {
+ char *p;
+ int n;
+
+ for (p = s + 4; *p; p++)
+ if (!isascii(*p) || !isdigit((unsigned char)*p))
+ return s;
+ n = atoi(s + 4);
+ if (n >= 0 && n <= 0xff) {
+ ch[0] = (char)n;
+ return ch;
+ }
+ }
+ return s;
+}
+
+/* Return 1 if the character is present in the font; widthp gets the
+width if non-null. */
+
+int device_char_width(f, ps, name, widthp)
+ DeviceFont *f;
+ int ps;
+ char *name;
+ int *widthp;
+{
+ struct charinfo *p;
+
+ name = canonicalize_name(name);
+ for (p = f->char_table[hash_name(name) % CHAR_TABLE_SIZE];; p = p->next) {
+ if (!p)
+ return 0;
+ if (strcmp(p->name, name) == 0)
+ break;
+ }
+ *widthp = scale_round(p->width, ps, f->dev->unitwidth);
+ return 1;
+}
+
+int device_code_width(f, ps, code, widthp)
+ DeviceFont *f;
+ int ps;
+ int code;
+ int *widthp;
+{
+ struct charinfo *p;
+
+ for (p = f->code_table[code & 0xff];; p = p->code_next) {
+ if (!p)
+ return 0;
+ if (p->code == code)
+ break;
+ }
+ *widthp = scale_round(p->width, ps, f->dev->unitwidth);
+ return 1;
+}
+
+char *device_name_for_code(f, code)
+ DeviceFont *f;
+ int code;
+{
+ static struct charinfo *state = 0;
+ if (f)
+ state = f->code_table[code & 0xff];
+ for (; state; state = state->code_next)
+ if (state->code == code && state->name[0] != '\0') {
+ char *name = state->name;
+ state = state->code_next;
+ return name;
+ }
+ return 0;
+}
+
+int device_font_special(f)
+ DeviceFont *f;
+{
+ return f->special;
+}
+
+static
+struct charinfo *add_char(f, name, width, code)
+ DeviceFont *f;
+ char *name;
+ int width, code;
+{
+ struct charinfo **pp;
+ struct charinfo *ci;
+
+ name = canonicalize_name(name);
+ if (strcmp(name, "---") == 0)
+ name = "";
+
+ ci = (struct charinfo *)XtMalloc(XtOffsetOf(struct charinfo, name[0])
+ + strlen(name) + 1);
+
+ strcpy(ci->name, name);
+ ci->width = width;
+ ci->code = code;
+
+ if (*name != '\0') {
+ pp = &f->char_table[hash_name(name) % CHAR_TABLE_SIZE];
+ ci->next = *pp;
+ *pp = ci;
+ }
+ pp = &f->code_table[code & 0xff];
+ ci->code_next = *pp;
+ *pp = ci;
+ return ci;
+}
+
+/* Return non-zero for success. */
+
+static
+int read_charset_section(f, fp)
+ DeviceFont *f;
+ FILE *fp;
+{
+ struct charinfo *last_charinfo = 0;
+ char buf[256];
+
+ while (fgets(buf, sizeof(buf), fp)) {
+ char *name;
+ int width;
+ int code;
+ char *p;
+
+ current_lineno++;
+ name = strtok(buf, WS);
+ if (!name)
+ continue; /* ignore blank lines */
+ p = strtok((char *)0, WS);
+ if (!p) /* end of charset section */
+ break;
+ if (strcmp(p, "\"") == 0) {
+ if (!last_charinfo) {
+ error("first line of charset section cannot use `\"'");
+ return 0;
+ }
+ else
+ (void)add_char(f, name,
+ last_charinfo->width, last_charinfo->code);
+ }
+ else {
+ char *q;
+ if (sscanf(p, "%d", &width) != 1) {
+ error("bad width field");
+ return 0;
+ }
+ p = strtok((char *)0, WS);
+ if (!p) {
+ error("missing type field");
+ return 0;
+ }
+ p = strtok((char *)0, WS);
+ if (!p) {
+ error("missing code field");
+ return 0;
+ }
+ code = (int)strtol(p, &q, 0);
+ if (q == p) {
+ error("bad code field");
+ return 0;
+ }
+ last_charinfo = add_char(f, name, width, code);
+ }
+ }
+ return 1;
+}
+
+static
+FILE *find_file(file, path, result)
+ char *file, *path, **result;
+{
+ char *buf = NULL;
+ int bufsiz = 0;
+ int flen;
+ FILE *fp;
+
+ *result = NULL;
+
+ if (file == NULL)
+ return NULL;
+ if (*file == '\0')
+ return NULL;
+
+ if (*file == '/') {
+ fp = fopen(file, "r");
+ if (fp)
+ *result = XtNewString(file);
+ return fp;
+ }
+
+ flen = strlen(file);
+
+ if (!path)
+ return NULL;
+
+ while (*path) {
+ int len;
+ char *start, *end;
+
+ start = path;
+ end = strchr(path, ':');
+ if (end)
+ path = end + 1;
+ else
+ path = end = strchr(path, '\0');
+ if (start >= end)
+ continue;
+ if (end[-1] == '/')
+ --end;
+ len = (end - start) + 1 + flen + 1;
+ if (len > bufsiz) {
+ if (buf)
+ buf = XtRealloc(buf, len);
+ else
+ buf = XtMalloc(len);
+ bufsiz = len;
+ }
+ memcpy(buf, start, end - start);
+ buf[end - start] = '/';
+ strcpy(buf + (end - start) + 1, file);
+ fp = fopen(buf, "r");
+ if (fp) {
+ *result = buf;
+ return fp;
+ }
+ }
+ XtFree(buf);
+ return NULL;
+}
+
+static
+FILE *open_device_file(device_name, file_name, result)
+ char *device_name, *file_name, **result;
+{
+ char *buf, *path;
+ FILE *fp;
+
+ buf = XtMalloc(3 + strlen(device_name) + 1 + strlen(file_name) + 1);
+ sprintf(buf, "dev%s/%s", device_name, file_name);
+ path = getenv(FONTPATH_ENV_VAR);
+ if (!path)
+ path = FONTPATH;
+ fp = find_file(buf, path, result);
+ if (!fp) {
+ fprintf(stderr, "can't find device file `%s'\n", file_name);
+ fflush(stderr);
+ }
+ XtFree(buf);
+ return fp;
+}
+
+static
+void error(s)
+ char *s;
+{
+ if (current_filename) {
+ fprintf(stderr, "%s:", current_filename);
+ if (current_lineno > 0)
+ fprintf(stderr, "%d:", current_lineno);
+ putc(' ', stderr);
+ }
+ fputs(s, stderr);
+ putc('\n', stderr);
+ fflush(stderr);
+}
+
+/*
+Local Variables:
+c-indent-level: 4
+c-continued-statement-offset: 4
+c-brace-offset: -4
+c-argdecl-indent: 4
+c-label-offset: -4
+c-tab-always-indent: nil
+End:
+*/
diff --git a/gnu/usr.bin/groff/xditview/device.h b/gnu/usr.bin/groff/xditview/device.h
new file mode 100644
index 0000000..2b9a64b
--- /dev/null
+++ b/gnu/usr.bin/groff/xditview/device.h
@@ -0,0 +1,21 @@
+
+typedef struct _DeviceFont DeviceFont;
+
+typedef struct _Device {
+ char *name;
+ int sizescale;
+ int res;
+ int unitwidth;
+ int paperlength;
+ int paperwidth;
+ int X11;
+ DeviceFont *fonts;
+} Device;
+
+extern void device_destroy();
+extern Device *device_load();
+extern DeviceFont *device_find_font();
+extern int device_char_width();
+extern char *device_name_for_code();
+extern int device_code_width();
+extern int device_font_special();
diff --git a/gnu/usr.bin/groff/xditview/draw.c b/gnu/usr.bin/groff/xditview/draw.c
new file mode 100644
index 0000000..04f76c8
--- /dev/null
+++ b/gnu/usr.bin/groff/xditview/draw.c
@@ -0,0 +1,721 @@
+/*
+ * draw.c
+ *
+ * accept dvi function calls and translate to X
+ */
+
+#include <X11/Xos.h>
+#include <X11/IntrinsicP.h>
+#include <X11/StringDefs.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <math.h>
+
+/* math.h on a Sequent doesn't define M_PI, apparently */
+#ifndef M_PI
+#define M_PI 3.14159265358979323846
+#endif
+
+#include "DviP.h"
+
+#define DeviceToX(dw, n) ((int)((n) * (dw)->dvi.scale_factor + .5))
+#define XPos(dw) (DeviceToX((dw), (dw)->dvi.state->x - \
+ (dw)->dvi.text_device_width) + (dw)->dvi.text_x_width)
+#define YPos(dw) (DeviceToX((dw), (dw)->dvi.state->y))
+
+static int FakeCharacter();
+
+HorizontalMove(dw, delta)
+ DviWidget dw;
+ int delta;
+{
+ dw->dvi.state->x += delta;
+}
+
+HorizontalGoto(dw, NewPosition)
+ DviWidget dw;
+ int NewPosition;
+{
+ dw->dvi.state->x = NewPosition;
+}
+
+VerticalMove(dw, delta)
+ DviWidget dw;
+ int delta;
+{
+ dw->dvi.state->y += delta;
+}
+
+VerticalGoto(dw, NewPosition)
+ DviWidget dw;
+ int NewPosition;
+{
+ dw->dvi.state->y = NewPosition;
+}
+
+AdjustCacheDeltas (dw)
+ DviWidget dw;
+{
+ int extra;
+ int nadj;
+ int i;
+
+ nadj = 0;
+ extra = DeviceToX(dw, dw->dvi.text_device_width)
+ - dw->dvi.text_x_width;
+ if (extra == 0)
+ return;
+ for (i = 0; i <= dw->dvi.cache.index; i++)
+ if (dw->dvi.cache.adjustable[i])
+ ++nadj;
+ if (nadj == 0)
+ return;
+ dw->dvi.text_x_width += extra;
+ for (i = 0; i <= dw->dvi.cache.index; i++)
+ if (dw->dvi.cache.adjustable[i]) {
+ int x;
+ int *deltap;
+
+ x = extra/nadj;
+ deltap = &dw->dvi.cache.cache[i].delta;
+#define MIN_DELTA 2
+ if (*deltap > 0 && x + *deltap < MIN_DELTA) {
+ x = MIN_DELTA - *deltap;
+ if (x <= 0)
+ *deltap = MIN_DELTA;
+ else
+ x = 0;
+ }
+ else
+ *deltap += x;
+ extra -= x;
+ --nadj;
+ dw->dvi.cache.adjustable[i] = 0;
+ }
+}
+
+FlushCharCache (dw)
+ DviWidget dw;
+{
+ if (dw->dvi.cache.char_index != 0) {
+ AdjustCacheDeltas (dw);
+ XDrawText (XtDisplay (dw), XtWindow (dw), dw->dvi.normal_GC,
+ dw->dvi.cache.start_x, dw->dvi.cache.start_y,
+ dw->dvi.cache.cache, dw->dvi.cache.index + 1);
+ }
+ dw->dvi.cache.index = 0;
+ dw->dvi.cache.max = DVI_TEXT_CACHE_SIZE;
+#if 0
+ if (dw->dvi.noPolyText)
+ dw->dvi.cache.max = 1;
+#endif
+ dw->dvi.cache.char_index = 0;
+ dw->dvi.cache.cache[0].nchars = 0;
+ dw->dvi.cache.start_x = dw->dvi.cache.x = XPos (dw);
+ dw->dvi.cache.start_y = dw->dvi.cache.y = YPos (dw);
+}
+
+Newline (dw)
+ DviWidget dw;
+{
+ FlushCharCache (dw);
+ dw->dvi.text_x_width = dw->dvi.text_device_width = 0;
+ dw->dvi.word_flag = 0;
+}
+
+Word (dw)
+ DviWidget dw;
+{
+ dw->dvi.word_flag = 1;
+}
+
+#define charWidth(fi,c) (\
+ (fi)->per_char ?\
+ (fi)->per_char[(c) - (fi)->min_char_or_byte2].width\
+ :\
+ (fi)->max_bounds.width\
+)
+
+
+static
+int charExists (fi, c)
+ XFontStruct *fi;
+ int c;
+{
+ XCharStruct *p;
+
+ if (fi->per_char == NULL ||
+ c < fi->min_char_or_byte2 || c > fi->max_char_or_byte2)
+ return 0;
+ p = fi->per_char + (c - fi->min_char_or_byte2);
+ return (p->lbearing != 0 || p->rbearing != 0 || p->width != 0
+ || p->ascent != 0 || p->descent != 0 || p->attributes != 0);
+}
+
+static
+DoCharacter (dw, c, wid)
+ DviWidget dw;
+ int c;
+ int wid; /* width in device units */
+{
+ register XFontStruct *font;
+ register XTextItem *text;
+ int x, y;
+
+ x = XPos(dw);
+ y = YPos(dw);
+
+ /*
+ * quick and dirty extents calculation:
+ */
+ if (!(y + 24 >= dw->dvi.extents.y1
+ && y - 24 <= dw->dvi.extents.y2
+#if 0
+ && x + 24 >= dw->dvi.extents.x1
+ && x - 24 <= dw->dvi.extents.x2
+#endif
+ ))
+ return;
+
+ if (y != dw->dvi.cache.y
+ || dw->dvi.cache.char_index >= DVI_CHAR_CACHE_SIZE) {
+ FlushCharCache (dw);
+ x = dw->dvi.cache.x;
+ }
+ /*
+ * load a new font, if the current block is not empty,
+ * step to the next.
+ */
+ if (dw->dvi.cache.font_size != dw->dvi.state->font_size ||
+ dw->dvi.cache.font_number != dw->dvi.state->font_number)
+ {
+ dw->dvi.cache.font_size = dw->dvi.state->font_size;
+ dw->dvi.cache.font_number = dw->dvi.state->font_number;
+ dw->dvi.cache.font = QueryFont (dw,
+ dw->dvi.cache.font_number,
+ dw->dvi.cache.font_size);
+ if (dw->dvi.cache.cache[dw->dvi.cache.index].nchars != 0) {
+ ++dw->dvi.cache.index;
+ if (dw->dvi.cache.index >= dw->dvi.cache.max)
+ FlushCharCache (dw);
+ dw->dvi.cache.cache[dw->dvi.cache.index].nchars = 0;
+ dw->dvi.cache.adjustable[dw->dvi.cache.index] = 0;
+ }
+ }
+ if (x != dw->dvi.cache.x || dw->dvi.word_flag) {
+ if (dw->dvi.cache.cache[dw->dvi.cache.index].nchars != 0) {
+ ++dw->dvi.cache.index;
+ if (dw->dvi.cache.index >= dw->dvi.cache.max)
+ FlushCharCache (dw);
+ dw->dvi.cache.cache[dw->dvi.cache.index].nchars = 0;
+ }
+ dw->dvi.cache.adjustable[dw->dvi.cache.index]
+ = dw->dvi.word_flag;
+ dw->dvi.word_flag = 0;
+ }
+ font = dw->dvi.cache.font;
+ text = &dw->dvi.cache.cache[dw->dvi.cache.index];
+ if (text->nchars == 0) {
+ text->chars = &dw->dvi.cache.char_cache[dw->dvi.cache.char_index];
+ text->delta = x - dw->dvi.cache.x;
+ if (font != dw->dvi.font) {
+ text->font = font->fid;
+ dw->dvi.font = font;
+ } else
+ text->font = None;
+ dw->dvi.cache.x += text->delta;
+ }
+ if (charExists(font, c)) {
+ int w;
+ dw->dvi.cache.char_cache[dw->dvi.cache.char_index++] = (char) c;
+ ++text->nchars;
+ w = charWidth(font, c);
+ dw->dvi.cache.x += w;
+ if (wid != 0) {
+ dw->dvi.text_x_width += w;
+ dw->dvi.text_device_width += wid;
+ }
+ }
+}
+
+static
+int FindCharWidth (dw, buf, widp)
+ DviWidget dw;
+ char *buf;
+ int *widp;
+{
+ int maxpos;
+ int i;
+
+ if (dw->dvi.device_font == 0
+ || dw->dvi.state->font_number != dw->dvi.device_font_number) {
+ dw->dvi.device_font_number = dw->dvi.state->font_number;
+ dw->dvi.device_font
+ = QueryDeviceFont (dw, dw->dvi.device_font_number);
+ }
+ if (dw->dvi.device_font
+ && device_char_width (dw->dvi.device_font,
+ dw->dvi.state->font_size, buf, widp))
+ return 1;
+
+ maxpos = MaxFontPosition (dw);
+ for (i = 1; i <= maxpos; i++) {
+ DeviceFont *f = QueryDeviceFont (dw, i);
+ if (f && device_font_special (f)
+ && device_char_width (f, dw->dvi.state->font_size,
+ buf, widp)) {
+ dw->dvi.state->font_number = i;
+ return 1;
+ }
+ }
+ return 0;
+}
+
+/* Return the width of the character in device units. */
+
+int PutCharacter (dw, buf)
+ DviWidget dw;
+ char *buf;
+{
+ int prevFont;
+ int c = -1;
+ int wid = 0;
+ DviCharNameMap *map;
+
+ if (!dw->dvi.display_enable)
+ return 0; /* The width doesn't matter in this case. */
+ prevFont = dw->dvi.state->font_number;
+ if (!FindCharWidth (dw, buf, &wid))
+ return 0;
+ map = QueryFontMap (dw, dw->dvi.state->font_number);
+ if (map)
+ c = DviCharIndex (map, buf);
+ if (c >= 0)
+ DoCharacter (dw, c, wid);
+ else
+ (void) FakeCharacter (dw, buf, wid);
+ dw->dvi.state->font_number = prevFont;
+ return wid;
+}
+
+/* Return 1 if we can fake it; 0 otherwise. */
+
+static
+int FakeCharacter (dw, buf, wid)
+ DviWidget dw;
+ char *buf;
+ int wid;
+{
+ int oldx, oldw;
+ char ch[2];
+ char *chars = 0;
+
+ if (buf[0] == '\0' || buf[1] == '\0' || buf[2] != '\0')
+ return 0;
+#define pack2(c1, c2) (((c1) << 8) | (c2))
+
+ switch (pack2(buf[0], buf[1])) {
+ case pack2('f', 'i'):
+ chars = "fi";
+ break;
+ case pack2('f', 'l'):
+ chars = "fl";
+ break;
+ case pack2('f', 'f'):
+ chars = "ff";
+ break;
+ case pack2('F', 'i'):
+ chars = "ffi";
+ break;
+ case pack2('F', 'l'):
+ chars = "ffl";
+ break;
+ }
+ if (!chars)
+ return 0;
+ oldx = dw->dvi.state->x;
+ oldw = dw->dvi.text_device_width;
+ ch[1] = '\0';
+ for (; *chars; chars++) {
+ ch[0] = *chars;
+ dw->dvi.state->x += PutCharacter (dw, ch);
+ }
+ dw->dvi.state->x = oldx;
+ dw->dvi.text_device_width = oldw + wid;
+ return 1;
+}
+
+PutNumberedCharacter (dw, c)
+ DviWidget dw;
+ int c;
+{
+ char *name;
+ int wid;
+ DviCharNameMap *map;
+
+ if (!dw->dvi.display_enable)
+ return;
+
+ if (dw->dvi.device_font == 0
+ || dw->dvi.state->font_number != dw->dvi.device_font_number) {
+ dw->dvi.device_font_number = dw->dvi.state->font_number;
+ dw->dvi.device_font
+ = QueryDeviceFont (dw, dw->dvi.device_font_number);
+ }
+
+ if (dw->dvi.device_font == 0
+ || !device_code_width (dw->dvi.device_font,
+ dw->dvi.state->font_size, c, &wid))
+ return;
+ if (dw->dvi.native) {
+ DoCharacter (dw, c, wid);
+ return;
+ }
+ map = QueryFontMap (dw, dw->dvi.state->font_number);
+ if (!map)
+ return;
+ for (name = device_name_for_code (dw->dvi.device_font, c);
+ name;
+ name = device_name_for_code ((DeviceFont *)0, c)) {
+ int code = DviCharIndex (map, name);
+ if (code >= 0) {
+ DoCharacter (dw, code, wid);
+ break;
+ }
+ if (FakeCharacter (dw, name, wid))
+ break;
+ }
+}
+
+ClearPage (dw)
+ DviWidget dw;
+{
+ XClearWindow (XtDisplay (dw), XtWindow (dw));
+}
+
+static
+setGC (dw)
+ DviWidget dw;
+{
+ int desired_line_width;
+
+ if (dw->dvi.line_thickness < 0)
+ desired_line_width = (int)(((double)dw->dvi.device_resolution
+ * dw->dvi.state->font_size)
+ / (10.0*72.0*dw->dvi.sizescale));
+ else
+ desired_line_width = dw->dvi.line_thickness;
+
+ if (desired_line_width != dw->dvi.line_width) {
+ XGCValues values;
+ values.line_width = DeviceToX(dw, desired_line_width);
+ if (values.line_width == 0)
+ values.line_width = 1;
+ XChangeGC(XtDisplay (dw), dw->dvi.normal_GC,
+ GCLineWidth, &values);
+ dw->dvi.line_width = desired_line_width;
+ }
+}
+
+static
+setFillGC (dw)
+ DviWidget dw;
+{
+ int fill_type;
+
+ if (dw->dvi.fill == DVI_FILL_MAX)
+ fill_type = DVI_FILL_BLACK;
+ else if (dw->dvi.fill == 0)
+ fill_type = DVI_FILL_WHITE;
+ else
+ fill_type = DVI_FILL_GRAY;
+ if (dw->dvi.fill_type != fill_type) {
+ XGCValues values;
+ switch (fill_type) {
+ case DVI_FILL_WHITE:
+ values.foreground = dw->dvi.background;
+ values.fill_style = FillSolid;
+ break;
+ case DVI_FILL_BLACK:
+ values.foreground = dw->dvi.foreground;
+ values.fill_style = FillSolid;
+ break;
+ case DVI_FILL_GRAY:
+ values.foreground = dw->dvi.foreground;
+ values.fill_style = FillOpaqueStippled;
+ break;
+ }
+ XChangeGC(XtDisplay (dw), dw->dvi.fill_GC,
+ GCFillStyle|GCForeground,
+ &values);
+ dw->dvi.fill_type = fill_type;
+ }
+}
+
+DrawLine (dw, x, y)
+ DviWidget dw;
+ int x, y;
+{
+ int xp, yp;
+
+ AdjustCacheDeltas (dw);
+ setGC (dw);
+ xp = XPos (dw);
+ yp = YPos (dw);
+ XDrawLine (XtDisplay (dw), XtWindow (dw), dw->dvi.normal_GC,
+ xp, yp,
+ xp + DeviceToX (dw, x), yp + DeviceToX (dw, y));
+}
+
+DrawCircle (dw, diam)
+ DviWidget dw;
+ int diam;
+{
+ int d;
+
+ AdjustCacheDeltas (dw);
+ setGC (dw);
+ d = DeviceToX (dw, diam);
+ XDrawArc (XtDisplay (dw), XtWindow (dw), dw->dvi.normal_GC,
+ XPos (dw), YPos (dw) - d/2,
+ d, d, 0, 64*360);
+}
+
+DrawFilledCircle (dw, diam)
+ DviWidget dw;
+ int diam;
+{
+ int d;
+
+ AdjustCacheDeltas (dw);
+ setFillGC (dw);
+ d = DeviceToX (dw, diam);
+ XFillArc (XtDisplay (dw), XtWindow (dw), dw->dvi.fill_GC,
+ XPos (dw), YPos (dw) - d/2,
+ d, d, 0, 64*360);
+}
+
+DrawEllipse (dw, a, b)
+ DviWidget dw;
+ int a, b;
+{
+ AdjustCacheDeltas (dw);
+ setGC (dw);
+ XDrawArc (XtDisplay (dw), XtWindow (dw), dw->dvi.normal_GC,
+ XPos (dw), YPos (dw) - DeviceToX (dw, b/2),
+ DeviceToX (dw, a), DeviceToX (dw, b), 0, 64*360);
+}
+
+DrawFilledEllipse (dw, a, b)
+ DviWidget dw;
+ int a, b;
+{
+ AdjustCacheDeltas (dw);
+ setFillGC (dw);
+ XFillArc (XtDisplay (dw), XtWindow (dw), dw->dvi.fill_GC,
+ XPos (dw), YPos (dw) - DeviceToX (dw, b/2),
+ DeviceToX (dw, a), DeviceToX (dw, b), 0, 64*360);
+}
+
+DrawArc (dw, x0, y0, x1, y1)
+ DviWidget dw;
+ int x0, y0, x1, y1;
+{
+ int angle1, angle2;
+ int rad = (int)((sqrt ((double)x0*x0 + (double)y0*y0)
+ + sqrt ((double)x1*x1 + (double)y1*y1) + 1.0)/2.0);
+ if ((x0 == 0 && y0 == 0) || (x1 == 0 && y1 == 0))
+ return;
+ angle1 = (int)(atan2 ((double)y0, (double)-x0)*180.0*64.0/M_PI);
+ angle2 = (int)(atan2 ((double)-y1, (double)x1)*180.0*64.0/M_PI);
+
+ angle2 -= angle1;
+ if (angle2 < 0)
+ angle2 += 64*360;
+
+ AdjustCacheDeltas (dw);
+ setGC (dw);
+
+ rad = DeviceToX (dw, rad);
+ XDrawArc (XtDisplay (dw), XtWindow (dw), dw->dvi.normal_GC,
+ XPos (dw) + DeviceToX (dw, x0) - rad,
+ YPos (dw) + DeviceToX (dw, y0) - rad,
+ rad*2, rad*2, angle1, angle2);
+}
+
+DrawPolygon (dw, v, n)
+ DviWidget dw;
+ int *v;
+ int n;
+{
+ XPoint *p;
+ int i;
+ int dx, dy;
+
+ n /= 2;
+
+ AdjustCacheDeltas (dw);
+ setGC (dw);
+ p = (XPoint *)XtMalloc((n + 2)*sizeof(XPoint));
+ p[0].x = XPos (dw);
+ p[0].y = YPos (dw);
+ dx = 0;
+ dy = 0;
+ for (i = 0; i < n; i++) {
+ dx += v[2*i];
+ p[i + 1].x = DeviceToX (dw, dx) + p[0].x;
+ dy += v[2*i + 1];
+ p[i + 1].y = DeviceToX (dw, dy) + p[0].y;
+ }
+ p[n+1].x = p[0].x;
+ p[n+1].y = p[0].y;
+ XDrawLines (XtDisplay (dw), XtWindow (dw), dw->dvi.normal_GC,
+ p, n + 2, CoordModeOrigin);
+ XtFree((char *)p);
+}
+
+
+DrawFilledPolygon (dw, v, n)
+ DviWidget dw;
+ int *v;
+ int n;
+{
+ XPoint *p;
+ int i;
+ int dx, dy;
+
+ n /= 2;
+ if (n < 2)
+ return;
+
+ AdjustCacheDeltas (dw);
+ setFillGC (dw);
+ p = (XPoint *)XtMalloc((n + 1)*sizeof(XPoint));
+ p[0].x = XPos (dw);
+ p[0].y = YPos (dw);
+ dx = 0;
+ dy = 0;
+ for (i = 0; i < n; i++) {
+ dx += v[2*i];
+ p[i + 1].x = DeviceToX (dw, dx) + p[0].x;
+ dy += v[2*i + 1];
+ p[i + 1].y = DeviceToX (dw, dy) + p[0].y;
+ }
+ XFillPolygon (XtDisplay (dw), XtWindow (dw), dw->dvi.fill_GC,
+ p, n + 1, Complex, CoordModeOrigin);
+ XtFree((char *)p);
+}
+
+#define POINTS_MAX 10000
+
+static
+appendPoint(points, pointi, x, y)
+ XPoint *points;
+ int *pointi;
+ int x, y;
+{
+ if (*pointi < POINTS_MAX) {
+ points[*pointi].x = x;
+ points[*pointi].y = y;
+ *pointi += 1;
+ }
+}
+
+#define FLATNESS 1
+
+static
+flattenCurve(points, pointi, x2, y2, x3, y3, x4, y4)
+ XPoint *points;
+ int *pointi;
+ int x2, y2, x3, y3, x4, y4;
+{
+ int x1, y1, dx, dy, n1, n2, n;
+
+ x1 = points[*pointi - 1].x;
+ y1 = points[*pointi - 1].y;
+
+ dx = x4 - x1;
+ dy = y4 - y1;
+
+ n1 = dy*(x2 - x1) - dx*(y2 - y1);
+ n2 = dy*(x3 - x1) - dx*(y3 - y1);
+ if (n1 < 0)
+ n1 = -n1;
+ if (n2 < 0)
+ n2 = -n2;
+ n = n1 > n2 ? n1 : n2;
+
+ if (n*n / (dy*dy + dx*dx) <= FLATNESS*FLATNESS)
+ appendPoint (points, pointi, x4, y4);
+ else {
+ flattenCurve (points, pointi,
+ (x1 + x2)/2, (y1 + y2)/2,
+ (x1 + x2*2 + x3)/4, (y1 + y2*2 + y3)/4,
+ (x1 +3*x2 + 3*x3 + x4)/8, (y1 +3*y2 + 3*y3 + y4)/8);
+ flattenCurve (points, pointi,
+ (x2 + x3*2 + x4)/4, (y2 + y3*2 + y4)/4,
+ (x3 + x4)/2, (y3 + y4)/2,
+ x4, y4);
+ }
+}
+
+
+DrawSpline (dw, v, n)
+ DviWidget dw;
+ int *v;
+ int n;
+{
+ int sx, sy, tx, ty;
+ int ox, oy, dx, dy;
+ int i;
+ int pointi;
+ XPoint points[POINTS_MAX];
+
+ if (n == 0 || (n & 1) != 0)
+ return;
+ AdjustCacheDeltas (dw);
+ setGC (dw);
+ ox = XPos (dw);
+ oy = YPos (dw);
+ dx = v[0];
+ dy = v[1];
+ sx = ox;
+ sy = oy;
+ tx = sx + DeviceToX (dw, dx);
+ ty = sy + DeviceToX (dw, dy);
+
+ pointi = 0;
+
+ appendPoint (points, &pointi, sx, sy);
+ appendPoint (points, &pointi, (sx + tx)/2, (sy + ty)/2);
+
+ for (i = 2; i < n; i += 2) {
+ int ux = ox + DeviceToX (dw, dx += v[i]);
+ int uy = oy + DeviceToX (dw, dy += v[i+1]);
+ flattenCurve (points, &pointi,
+ (sx + tx*5)/6, (sy + ty*5)/6,
+ (tx*5 + ux)/6, (ty*5 + uy)/6,
+ (tx + ux)/2, (ty + uy)/2);
+ sx = tx;
+ sy = ty;
+ tx = ux;
+ ty = uy;
+ }
+
+ appendPoint (points, &pointi, tx, ty);
+
+ XDrawLines (XtDisplay (dw), XtWindow (dw), dw->dvi.normal_GC,
+ points, pointi, CoordModeOrigin);
+}
+
+
+/*
+Local Variables:
+c-indent-level: 8
+c-continued-statement-offset: 8
+c-brace-offset: -8
+c-argdecl-indent: 8
+c-label-offset: -8
+c-tab-always-indent: nil
+End:
+*/
diff --git a/gnu/usr.bin/groff/xditview/font.c b/gnu/usr.bin/groff/xditview/font.c
new file mode 100644
index 0000000..3778eec
--- /dev/null
+++ b/gnu/usr.bin/groff/xditview/font.c
@@ -0,0 +1,471 @@
+/*
+ * font.c
+ *
+ * map dvi fonts to X fonts
+ */
+
+#include <X11/Xos.h>
+#include <X11/IntrinsicP.h>
+#include <X11/StringDefs.h>
+#include <stdio.h>
+#include <ctype.h>
+#include "DviP.h"
+#include "XFontName.h"
+
+static DisposeFontSizes();
+
+static char *
+savestr (s)
+ char *s;
+{
+ char *n;
+
+ if (!s)
+ return 0;
+ n = XtMalloc (strlen (s) + 1);
+ if (n)
+ strcpy (n, s);
+ return n;
+}
+
+static DviFontList *
+LookupFontByPosition (dw, position)
+ DviWidget dw;
+ int position;
+{
+ DviFontList *f;
+
+ for (f = dw->dvi.fonts; f; f = f->next)
+ if (f->dvi_number == position)
+ break;
+ return f;
+}
+
+int
+MaxFontPosition (dw)
+ DviWidget dw;
+{
+ DviFontList *f;
+ int n = -1;
+
+ for (f = dw->dvi.fonts; f; f = f->next)
+ if (f->dvi_number > n)
+ n = f->dvi_number;
+ return n;
+}
+
+static DviFontSizeList *
+LookupFontSizeBySize (dw, f, size)
+ DviWidget dw;
+ DviFontList *f;
+ int size;
+{
+ DviFontSizeList *fs, *best = 0, *smallest = 0;
+ int bestsize = 0;
+ XFontName fontName;
+ unsigned int fontNameAttributes;
+ char fontNameString[2048];
+ int decipointsize;
+
+ if (f->scalable) {
+ decipointsize = (10*size)/dw->dvi.sizescale;
+ for (best = f->sizes; best; best = best->next)
+ if (best->size == decipointsize)
+ return best;
+ best = (DviFontSizeList *) XtMalloc(sizeof *best);
+ best->next = f->sizes;
+ best->size = decipointsize;
+ f->sizes = best;
+ XParseFontName (f->x_name, &fontName, &fontNameAttributes);
+ fontNameAttributes &= ~(FontNamePixelSize|FontNameAverageWidth);
+ fontNameAttributes |= FontNameResolutionX;
+ fontNameAttributes |= FontNameResolutionY;
+ fontNameAttributes |= FontNamePointSize;
+ fontName.ResolutionX = dw->dvi.display_resolution;
+ fontName.ResolutionY = dw->dvi.display_resolution;
+ fontName.PointSize = decipointsize;
+ XFormatFontName (&fontName, fontNameAttributes, fontNameString);
+ best->x_name = savestr (fontNameString);
+ best->doesnt_exist = 0;
+ best->font = 0;
+ return best;
+ }
+ for (fs = f->sizes; fs; fs=fs->next) {
+ if (dw->dvi.sizescale*fs->size <= 10*size
+ && fs->size >= bestsize) {
+ best = fs;
+ bestsize = fs->size;
+ }
+ if (smallest == 0 || fs->size < smallest->size)
+ smallest = fs;
+ }
+ return best ? best : smallest;
+}
+
+static char *
+SkipFontNameElement (n)
+ char *n;
+{
+ while (*n != '-')
+ if (!*++n)
+ return 0;
+ return n+1;
+}
+
+# define SizePosition 8
+# define EncodingPosition 13
+
+static
+ConvertFontNameToSize (n)
+ char *n;
+{
+ int i, size;
+
+ for (i = 0; i < SizePosition; i++) {
+ n = SkipFontNameElement (n);
+ if (!n)
+ return -1;
+ }
+ size = atoi (n);
+ return size;
+}
+
+static char *
+ConvertFontNameToEncoding (n)
+ char *n;
+{
+ int i;
+ for (i = 0; i < EncodingPosition; i++) {
+ n = SkipFontNameElement (n);
+ if (!n)
+ return 0;
+ }
+ return n;
+}
+
+DviFontSizeList *
+InstallFontSizes (dw, x_name, scalablep)
+ DviWidget dw;
+ char *x_name;
+ Boolean *scalablep;
+{
+ char fontNameString[2048];
+ char **fonts;
+ int i, count;
+ int size;
+ DviFontSizeList *sizes, *new;
+ XFontName fontName;
+ unsigned int fontNameAttributes;
+
+ *scalablep = FALSE;
+ if (!XParseFontName (x_name, &fontName, &fontNameAttributes))
+ return 0;
+ fontNameAttributes &= ~(FontNamePixelSize|FontNamePointSize
+ |FontNameAverageWidth);
+ fontNameAttributes |= FontNameResolutionX;
+ fontNameAttributes |= FontNameResolutionY;
+ fontName.ResolutionX = dw->dvi.display_resolution;
+ fontName.ResolutionY = dw->dvi.display_resolution;
+ XFormatFontName (&fontName, fontNameAttributes, fontNameString);
+ fonts = XListFonts (XtDisplay (dw), fontNameString, 10000000, &count);
+ sizes = 0;
+ for (i = 0; i < count; i++) {
+ size = ConvertFontNameToSize (fonts[i]);
+ if (size == 0) {
+ DisposeFontSizes (dw, sizes);
+ sizes = 0;
+ *scalablep = TRUE;
+ break;
+ }
+ if (size != -1) {
+ new = (DviFontSizeList *) XtMalloc (sizeof *new);
+ new->next = sizes;
+ new->size = size;
+ new->x_name = savestr (fonts[i]);
+ new->doesnt_exist = 0;
+ new->font = 0;
+ sizes = new;
+ }
+ }
+ XFreeFontNames (fonts);
+ return sizes;
+}
+
+static
+DisposeFontSizes (dw, fs)
+ DviWidget dw;
+ DviFontSizeList *fs;
+{
+ DviFontSizeList *next;
+
+ for (; fs; fs=next) {
+ next = fs->next;
+ if (fs->x_name)
+ XtFree (fs->x_name);
+ if (fs->font) {
+ XUnloadFont (XtDisplay (dw), fs->font->fid);
+ XFree ((char *)fs->font);
+ }
+ XtFree ((char *) fs);
+ }
+}
+
+static DviFontList *
+InstallFont (dw, position, dvi_name, x_name)
+ DviWidget dw;
+ int position;
+ char *dvi_name;
+ char *x_name;
+{
+ DviFontList *f;
+ char *encoding;
+
+ if ((f = LookupFontByPosition (dw, position)) != NULL) {
+ /*
+ * ignore gratuitous font loading
+ */
+ if (!strcmp (f->dvi_name, dvi_name) &&
+ !strcmp (f->x_name, x_name))
+ return f;
+
+ DisposeFontSizes (dw, f->sizes);
+ if (f->dvi_name)
+ XtFree (f->dvi_name);
+ if (f->x_name)
+ XtFree (f->x_name);
+ f->device_font = 0;
+ } else {
+ f = (DviFontList *) XtMalloc (sizeof (*f));
+ f->next = dw->dvi.fonts;
+ dw->dvi.fonts = f;
+ }
+ f->initialized = FALSE;
+ f->dvi_name = savestr (dvi_name);
+ f->device_font = device_find_font (dw->dvi.device, dvi_name);
+ f->x_name = savestr (x_name);
+ f->dvi_number = position;
+ f->sizes = 0;
+ f->scalable = FALSE;
+ if (f->x_name) {
+ encoding = ConvertFontNameToEncoding (f->x_name);
+ f->char_map = DviFindMap (encoding);
+ } else
+ f->char_map = 0;
+ /*
+ * force requery of fonts
+ */
+ dw->dvi.font = 0;
+ dw->dvi.font_number = -1;
+ dw->dvi.cache.font = 0;
+ dw->dvi.cache.font_number = -1;
+ dw->dvi.device_font = 0;
+ dw->dvi.device_font_number = -1;
+ return f;
+}
+
+ForgetFonts (dw)
+ DviWidget dw;
+{
+ DviFontList *f = dw->dvi.fonts;
+
+ while (f) {
+ DviFontList *tem = f;
+
+ if (f->sizes)
+ DisposeFontSizes (dw, f->sizes);
+ if (f->dvi_name)
+ XtFree (f->dvi_name);
+ if (f->x_name)
+ XtFree (f->x_name);
+ f = f->next;
+ XtFree ((char *) tem);
+ }
+
+ /*
+ * force requery of fonts
+ */
+ dw->dvi.font = 0;
+ dw->dvi.font_number = -1;
+ dw->dvi.cache.font = 0;
+ dw->dvi.cache.font_number = -1;
+ dw->dvi.device_font = 0;
+ dw->dvi.device_font_number = -1;
+ dw->dvi.fonts = 0;
+}
+
+
+static char *
+MapDviNameToXName (dw, dvi_name)
+ DviWidget dw;
+ char *dvi_name;
+{
+ DviFontMap *fm;
+
+ for (fm = dw->dvi.font_map; fm; fm=fm->next)
+ if (!strcmp (fm->dvi_name, dvi_name))
+ return fm->x_name;
+ return 0;
+}
+
+#if 0
+static char *
+MapXNameToDviName (dw, x_name)
+ DviWidget dw;
+ char *x_name;
+{
+ DviFontMap *fm;
+
+ for (fm = dw->dvi.font_map; fm; fm=fm->next)
+ if (!strcmp (fm->x_name, x_name))
+ return fm->dvi_name;
+ return 0;
+}
+#endif
+
+ParseFontMap (dw)
+ DviWidget dw;
+{
+ char dvi_name[1024];
+ char x_name[2048];
+ char *m, *s;
+ DviFontMap *fm, *new;
+
+ if (dw->dvi.font_map)
+ DestroyFontMap (dw->dvi.font_map);
+ fm = 0;
+ m = dw->dvi.font_map_string;
+ while (*m) {
+ s = m;
+ while (*m && !isspace (*m))
+ ++m;
+ strncpy (dvi_name, s, m-s);
+ dvi_name[m-s] = '\0';
+ while (isspace (*m))
+ ++m;
+ s = m;
+ while (*m && *m != '\n')
+ ++m;
+ strncpy (x_name, s, m-s);
+ x_name[m-s] = '\0';
+ new = (DviFontMap *) XtMalloc (sizeof *new);
+ new->x_name = savestr (x_name);
+ new->dvi_name = savestr (dvi_name);
+ new->next = fm;
+ fm = new;
+ ++m;
+ }
+ dw->dvi.font_map = fm;
+}
+
+DestroyFontMap (font_map)
+ DviFontMap *font_map;
+{
+ DviFontMap *next;
+
+ for (; font_map; font_map = next) {
+ next = font_map->next;
+ if (font_map->x_name)
+ XtFree (font_map->x_name);
+ if (font_map->dvi_name)
+ XtFree (font_map->dvi_name);
+ XtFree ((char *) font_map);
+ }
+}
+
+/* ARGSUSED */
+
+SetFontPosition (dw, position, dvi_name, extra)
+ DviWidget dw;
+ int position;
+ char *dvi_name;
+ char *extra; /* unused */
+{
+ char *x_name;
+
+ x_name = MapDviNameToXName (dw, dvi_name);
+ if (x_name)
+ (void) InstallFont (dw, position, dvi_name, x_name);
+}
+
+XFontStruct *
+QueryFont (dw, position, size)
+ DviWidget dw;
+ int position;
+ int size;
+{
+ DviFontList *f;
+ DviFontSizeList *fs;
+
+ f = LookupFontByPosition (dw, position);
+ if (!f)
+ return dw->dvi.default_font;
+ if (!f->initialized) {
+ f->sizes = InstallFontSizes (dw, f->x_name, &f->scalable);
+ f->initialized = TRUE;
+ }
+ fs = LookupFontSizeBySize (dw, f, size);
+ if (!fs)
+ return dw->dvi.default_font;
+ if (!fs->font) {
+ if (fs->x_name)
+ fs->font = XLoadQueryFont (XtDisplay (dw), fs->x_name);
+ if (!fs->font)
+ fs->font = dw->dvi.default_font;
+ }
+ return fs->font;
+}
+
+DeviceFont *
+QueryDeviceFont (dw, position)
+ DviWidget dw;
+ int position;
+{
+ DviFontList *f;
+
+ f = LookupFontByPosition (dw, position);
+ if (!f)
+ return 0;
+ return f->device_font;
+}
+
+DviCharNameMap *
+QueryFontMap (dw, position)
+ DviWidget dw;
+ int position;
+{
+ DviFontList *f;
+
+ f = LookupFontByPosition (dw, position);
+ if (f)
+ return f->char_map;
+ else
+ return 0;
+}
+
+#if 0
+LoadFont (dw, position, size)
+ DviWidget dw;
+ int position;
+ int size;
+{
+ XFontStruct *font;
+
+ font = QueryFont (dw, position, size);
+ dw->dvi.font_number = position;
+ dw->dvi.font_size = size;
+ dw->dvi.font = font;
+ XSetFont (XtDisplay (dw), dw->dvi.normal_GC, font->fid);
+ return;
+}
+#endif
+
+/*
+Local Variables:
+c-indent-level: 8
+c-continued-statement-offset: 8
+c-brace-offset: -8
+c-argdecl-indent: 8
+c-label-offset: -8
+c-tab-always-indent: nil
+End:
+*/
diff --git a/gnu/usr.bin/groff/xditview/gxditview.man b/gnu/usr.bin/groff/xditview/gxditview.man
new file mode 100644
index 0000000..04cd446
--- /dev/null
+++ b/gnu/usr.bin/groff/xditview/gxditview.man
@@ -0,0 +1,246 @@
+.\" -*- nroff -*-
+.TH GXDITVIEW 1 "Release 5" "X Version 11"
+.SH NAME
+gxditview \- display gtroff output files
+.SH SYNOPSIS
+.B gxditview
+.RI [\fB\- toolkitoption\ .\|.\|.\|]
+.RI [\fB\- option\ .\|.\|.\|]
+.RI [ filename ]
+.SH DESCRIPTION
+The
+.I gxditview
+program displays gtroff output on an X display.
+It uses the standard X11 fonts,
+so it does not require access to the server machine for font loading.
+.PP
+If
+.I filename
+is
+.BR \- ,
+.I gxditview
+will read the standard input.
+.PP
+The left mouse button brings up a menu with the following entries:
+.TP 8
+.B "Next Page"
+Display the next page.
+.TP
+.B "Previous Page"
+Display the previous page.
+.TP
+.B "Select Page"
+Select a particular numbered page specified by a dialog box.
+.TP
+.B Print
+Print the gtroff output using a command specified by a dialog box.
+The default command initially displayed is controlled by the
+.B printCommand
+application resource, and by the
+.B \-printCommand
+option.
+.TP
+.B Open
+Open for display a new file specified by a dialog box.
+The file should contain gtroff output.
+If the filename starts with
+.B |
+it will be taken to be a command to read from.
+.TP
+.B Quit
+Exit from
+.IR gxditview .
+.PP
+The
+.BR n ,
+Space
+and Return keys are bound to the
+.B Next\ Page
+action.
+The
+.BR p ,
+BackSpace
+and
+Delete
+keys are bound to the
+.B Previous\ Page
+action.
+The
+.B q
+key is bound to the
+.B Quit
+action.
+The
+.B r
+key is bound to the
+.B Rerasterize
+action which rereads the current file, and redisplays the current page;
+if the current file is a command, the command will be reexecuted.
+.PP
+The
+.B paperlength
+and
+.B paperwidth
+commands in the DESC file specify the length and width in machine units
+of the virtual page displayed by
+.IR gxditview .
+.SH OPTIONS
+.I Gxditview
+accepts all of the standard X Toolkit command line options along with the
+additional options listed below:
+.TP 8
+.B \-help
+This option indicates that a brief summary of the allowed options should be
+printed.
+.TP
+.B \-page
+This option specifies the page number of the document to be displayed.
+.TP
+.BI \-backingStore\ backing-store-type
+Redisplay of the gtroff output window can take upto a second or so,
+this option causes the server to save the window contents so that when
+it is scrolled around the viewport, the window is painted from
+contents saved in backing store.
+.I backing-store-type
+can be one of
+.BR Always ,
+.B WhenMapped
+or
+.BR NotUseful .
+.TP
+.BI \-printCommand\ command
+The default command displayed in the dialog box for the
+.B Print
+menu entry will be
+.IR command .
+.TP
+.BI \-resolution\ res
+The gtroff output file will be displayed at a resolution of
+.I res
+dpi,
+unless the DESC file contains the
+.B X11
+command, in which case the device resolution will be used.
+This corresponds the
+.I Dvi
+widget's
+.B resolution
+resource.
+The default is 75.
+.TP
+.BI \-filename\ string
+The default filename displayed in the dialog box for the
+.B Open
+menu entry will be
+.IR string .
+This can be either a filename, or a command starting with
+.BR | .
+.PP
+The following standard X Toolkit command line arguments are commonly used with
+.IR gxditview :
+.TP 8
+.BI \-bg\ color
+This option specifies the color to use for the background of the window.
+The default is \fIwhite\fP.
+.TP
+.BI \-bd\ color
+This option specifies the color to use for the border of the window.
+The default is \fIblack\fP.
+.TP
+.BI \-bw\ number
+This option specifies the width in pixels of the border surrounding the window.
+.TP
+.BI \-fg\ color
+This option specifies the color to use for displaying text. The default is
+\fIblack\fP.
+.TP
+.BI \-fn\ font
+This option specifies the font to be used for displaying widget text. The
+default is \fIfixed\fP.
+.TP
+.B \-rv
+This option indicates that reverse video should be simulated by swapping
+the foreground and background colors.
+.TP
+.BI \-geometry\ geometry
+This option specifies the preferred size and position of the window.
+.TP
+.BI \-display\ host : display
+This option specifies the X server to contact.
+.TP
+.BI \-xrm\ resourcestring
+This option specifies a resource string to be used.
+.SH X DEFAULTS
+This program uses the
+.I Dvi
+widget in the X Toolkit. It understands all of the core resource names and
+classes as well as:
+.PP
+.TP 8
+.BR width\ (class\ Width )
+Specifies the width of the window.
+.TP
+.BR height\ (class\ Height )
+Specifies the height of the window.
+.TP
+.BR foreground\ (class\ Foreground )
+Specifies the default foreground color.
+.TP
+.BR font\ (class\ Font )
+Specifies the font to be used for error messages.
+.TP
+.BR fontMap\ (class\ FontMap )
+Specifies the mapping from groff font names to X font names. This
+must be a string containing a sequence of lines. Each line contains
+two whitespace separated fields: first the groff font name, and
+secondly the X font name. The default is
+.nf
+"\e
+TR -adobe-times-medium-r-normal--*-100-*-*-*-*-iso8859-1\en\e
+TI -adobe-times-medium-i-normal--*-100-*-*-*-*-iso8859-1\en\e
+TB -adobe-times-bold-r-normal--*-100-*-*-*-*-iso8859-1\en\e
+TBI -adobe-times-bold-i-normal--*-100-*-*-*-*-iso8859-1\en\e
+CR -adobe-courier-medium-r-normal--*-100-*-*-*-*-iso8859-1\en\e
+CI -adobe-courier-medium-o-normal--*-100-*-*-*-*-iso8859-1\en\e
+CB -adobe-courier-bold-r-normal--*-100-*-*-*-*-iso8859-1\en\e
+CBI -adobe-courier-bold-o-normal--*-100-*-*-*-*-iso8859-1\en\e
+HR -adobe-helvetica-medium-r-normal--*-100-*-*-*-*-iso8859-1\en\e
+HI -adobe-helvetica-medium-o-normal--*-100-*-*-*-*-iso8859-1\en\e
+HB -adobe-helvetica-bold-r-normal--*-100-*-*-*-*-iso8859-1\en\e
+HBI -adobe-helvetica-bold-o-normal--*-100-*-*-*-*-iso8859-1\en\e
+NR -adobe-new century schoolbook-medium-r-normal--*-100-*-*-*-*-iso8859-1\en\e
+NI -adobe-new century schoolbook-medium-i-normal--*-100-*-*-*-*-iso8859-1\en\e
+NB -adobe-new century schoolbook-bold-r-normal--*-100-*-*-*-*-iso8859-1\en\e
+NBI -adobe-new century schoolbook-bold-i-normal--*-100-*-*-*-*-iso8859-1\en\e
+S -adobe-symbol-medium-r-normal--*-100-*-*-*-*-adobe-fontspecific\en\e
+SS -adobe-symbol-medium-r-normal--*-100-*-*-*-*-adobe-fontspecific\en\e
+"
+.fi
+
+.SH "SEE ALSO"
+.IR X (1),
+.IR xrdb (1),
+.IR gtroff (1),
+.IR groff (1)
+.SH ORIGIN
+This program is derived from xditview;
+portions of xditview originated in xtroff which was derived
+from suntroff.
+.SH COPYRIGHT
+Copyright 1989, Massachusetts Institute of Technology.
+.br
+See
+.IR X (1)
+for a full statement of rights and permissions.
+.SH AUTHORS
+Keith Packard (MIT X Consortium)
+.br
+Richard L. Hyde (Purdue)
+.br
+David Slattengren (Berkeley)
+.br
+Malcolm Slaney (Schlumberger Palo Alto Research)
+.br
+Mark Moraes (University of Toronto)
+.br
+James Clark
diff --git a/gnu/usr.bin/groff/xditview/lex.c b/gnu/usr.bin/groff/xditview/lex.c
new file mode 100644
index 0000000..854f7cb
--- /dev/null
+++ b/gnu/usr.bin/groff/xditview/lex.c
@@ -0,0 +1,103 @@
+#include <X11/Xos.h>
+#include <X11/IntrinsicP.h>
+#include <X11/StringDefs.h>
+#include <stdio.h>
+#include "DviP.h"
+
+DviGetAndPut(dw, cp)
+ DviWidget dw;
+ int *cp;
+{
+ if (dw->dvi.ungot) {
+ dw->dvi.ungot = 0;
+ *cp = getc (dw->dvi.file);
+ }
+ else {
+ *cp = getc (dw->dvi.file);
+ if (*cp != EOF)
+ putc (*cp, dw->dvi.tmpFile);
+ }
+ return *cp;
+}
+
+char *
+GetLine(dw, Buffer, Length)
+ DviWidget dw;
+ char *Buffer;
+ int Length;
+{
+ int i = 0, c;
+
+ Length--; /* Save room for final '\0' */
+
+ while (DviGetC (dw, &c) != EOF) {
+ if (Buffer && i < Length)
+ Buffer[i++] = c;
+ if (c == '\n') {
+ DviUngetC(dw, c);
+ break;
+ }
+ }
+ if (Buffer)
+ Buffer[i] = '\0';
+ return Buffer;
+}
+
+char *
+GetWord(dw, Buffer, Length)
+ DviWidget dw;
+ char *Buffer;
+ int Length;
+{
+ int i = 0, c;
+
+ Length--; /* Save room for final '\0' */
+ while (DviGetC(dw, &c) == ' ' || c == '\n')
+ ;
+ while (c != EOF) {
+ if (Buffer && i < Length)
+ Buffer[i++] = c;
+ if (DviGetC(dw, &c) == ' ' || c == '\n') {
+ DviUngetC(dw, c);
+ break;
+ }
+ }
+ if (Buffer)
+ Buffer[i] = '\0';
+ return Buffer;
+}
+
+GetNumber(dw)
+ DviWidget dw;
+{
+ int i = 0, c;
+ int negative = 0;
+
+ while (DviGetC(dw, &c) == ' ' || c == '\n')
+ ;
+ if (c == '-') {
+ negative = 1;
+ DviGetC(dw, &c);
+ }
+
+ for (; c >= '0' && c <= '9'; DviGetC(dw, &c)) {
+ if (negative)
+ i = i*10 - (c - '0');
+ else
+ i = i*10 + c - '0';
+ }
+ if (c != EOF)
+ DviUngetC(dw, c);
+ return i;
+}
+
+/*
+Local Variables:
+c-indent-level: 8
+c-continued-statement-offset: 8
+c-brace-offset: -8
+c-argdecl-indent: 8
+c-label-offset: -8
+c-tab-always-indent: nil
+End:
+*/
diff --git a/gnu/usr.bin/groff/xditview/page.c b/gnu/usr.bin/groff/xditview/page.c
new file mode 100644
index 0000000..9284199
--- /dev/null
+++ b/gnu/usr.bin/groff/xditview/page.c
@@ -0,0 +1,88 @@
+/*
+ * page.c
+ *
+ * map page numbers to file position
+ */
+
+#include <X11/Xos.h>
+#include <X11/IntrinsicP.h>
+#include <X11/StringDefs.h>
+#include <stdio.h>
+#include <ctype.h>
+#include "DviP.h"
+
+#ifdef X_NOT_STDC_ENV
+extern long ftell();
+#endif
+
+static DviFileMap *
+MapPageNumberToFileMap (dw, number)
+ DviWidget dw;
+ int number;
+{
+ DviFileMap *m;
+
+ for (m = dw->dvi.file_map; m; m=m->next)
+ if (m->page_number == number)
+ break;
+ return m;
+}
+
+DestroyFileMap (m)
+ DviFileMap *m;
+{
+ DviFileMap *next;
+
+ for (; m; m = next) {
+ next = m->next;
+ XtFree ((char *) m);
+ }
+}
+
+ForgetPagePositions (dw)
+ DviWidget dw;
+{
+ DestroyFileMap (dw->dvi.file_map);
+ dw->dvi.file_map = 0;
+}
+
+RememberPagePosition(dw, number)
+ DviWidget dw;
+ int number;
+{
+ DviFileMap *m;
+
+ if (!(m = MapPageNumberToFileMap (dw, number))) {
+ m = (DviFileMap *) XtMalloc (sizeof *m);
+ m->page_number = number;
+ m->next = dw->dvi.file_map;
+ dw->dvi.file_map = m;
+ }
+ if (dw->dvi.tmpFile)
+ m->position = ftell (dw->dvi.tmpFile);
+ else
+ m->position = ftell (dw->dvi.file);
+}
+
+SearchPagePosition (dw, number)
+ DviWidget dw;
+ int number;
+{
+ DviFileMap *m;
+
+ if (!(m = MapPageNumberToFileMap (dw, number)))
+ return -1;
+ return m->position;
+}
+
+FileSeek(dw, position)
+DviWidget dw;
+long position;
+{
+ if (dw->dvi.tmpFile) {
+ dw->dvi.readingTmp = 1;
+ fseek (dw->dvi.tmpFile, position, 0);
+ } else
+ fseek (dw->dvi.file, position, 0);
+}
+
diff --git a/gnu/usr.bin/groff/xditview/parse.c b/gnu/usr.bin/groff/xditview/parse.c
new file mode 100644
index 0000000..58928f0
--- /dev/null
+++ b/gnu/usr.bin/groff/xditview/parse.c
@@ -0,0 +1,334 @@
+/*
+ * parse.c
+ *
+ * parse dvi input
+ */
+
+#include <X11/Xos.h>
+#include <X11/IntrinsicP.h>
+#include <X11/StringDefs.h>
+#include <stdio.h>
+#include <ctype.h>
+#include "DviP.h"
+
+static int StopSeen = 0;
+static ParseDrawFunction(), ParseDeviceControl();
+static push_env(), pop_env();
+
+#define HorizontalMove(dw, delta) ((dw)->dvi.state->x += (delta))
+
+
+ParseInput(dw)
+ register DviWidget dw;
+{
+ int n, k;
+ int c;
+ char Buffer[BUFSIZ];
+ int NextPage;
+ int otherc;
+
+ StopSeen = 0;
+
+ /*
+ * make sure some state exists
+ */
+
+ if (!dw->dvi.state)
+ push_env (dw);
+ for (;;) {
+ switch (DviGetC(dw, &c)) {
+ case '\n':
+ break;
+ case ' ': /* when input is text */
+ case 0: /* occasional noise creeps in */
+ break;
+ case '{': /* push down current environment */
+ push_env(dw);
+ break;
+ case '}':
+ pop_env(dw);
+ break;
+ /*
+ * two motion digits plus a character
+ */
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ HorizontalMove(dw, (c-'0')*10 +
+ DviGetC(dw,&otherc)-'0');
+ /* fall through */
+ case 'c': /* single ascii character */
+ DviGetC(dw,&c);
+ if (c == ' ')
+ break;
+ Buffer[0] = c;
+ Buffer[1] = '\0';
+ (void) PutCharacter (dw, Buffer);
+ break;
+ case 'C':
+ GetWord (dw, Buffer, BUFSIZ);
+ (void) PutCharacter (dw, Buffer);
+ break;
+ case 't':
+ Buffer[1] = '\0';
+ while (DviGetC (dw, &c) != EOF
+ && c != ' ' && c != '\n') {
+ Buffer[0] = c;
+ HorizontalMove (dw, PutCharacter (dw, Buffer));
+ }
+ break;
+ case 'u':
+ n = GetNumber(dw);
+ Buffer[1] = '\0';
+ while (DviGetC (dw, &c) == ' ')
+ ;
+ while (c != EOF && c != ' ' && c != '\n') {
+ Buffer[0] = c;
+ HorizontalMove (dw,
+ PutCharacter (dw, Buffer) + n);
+ DviGetC (dw, &c);
+ }
+ break;
+
+ case 'D': /* draw function */
+ (void) GetLine(dw, Buffer, BUFSIZ);
+ if (dw->dvi.display_enable)
+ ParseDrawFunction(dw, Buffer);
+ break;
+ case 's': /* ignore fractional sizes */
+ n = GetNumber(dw);
+ dw->dvi.state->font_size = n;
+ break;
+ case 'f':
+ n = GetNumber(dw);
+ dw->dvi.state->font_number = n;
+ break;
+ case 'H': /* absolute horizontal motion */
+ k = GetNumber(dw);
+ HorizontalGoto(dw, k);
+ break;
+ case 'h': /* relative horizontal motion */
+ k = GetNumber(dw);
+ HorizontalMove(dw, k);
+ break;
+ case 'w': /* word space */
+ Word (dw);
+ break;
+ case 'V':
+ n = GetNumber(dw);
+ VerticalGoto(dw, n);
+ break;
+ case 'v':
+ n = GetNumber(dw);
+ VerticalMove(dw, n);
+ break;
+ case 'P': /* new spread */
+ break;
+ case 'p': /* new page */
+ (void) GetNumber(dw);
+ NextPage = dw->dvi.current_page + 1;
+ RememberPagePosition(dw, NextPage);
+ FlushCharCache (dw);
+ return(NextPage);
+ case 'N':
+ n = GetNumber(dw);
+ PutNumberedCharacter (dw, n);
+ break;
+ case 'n': /* end of line */
+ GetNumber(dw);
+ GetNumber(dw);
+ Newline (dw);
+ HorizontalGoto(dw, 0);
+ break;
+ case '+': /* continuation of X device control */
+ case '#': /* comment */
+ GetLine(dw, NULL, 0);
+ break;
+ case 'x': /* device control */
+ ParseDeviceControl(dw);
+ break;
+ case EOF:
+ dw->dvi.last_page = dw->dvi.current_page;
+ FlushCharCache (dw);
+ return dw->dvi.current_page;
+ default:
+ break;
+ }
+ }
+}
+
+static
+push_env(dw)
+ DviWidget dw;
+{
+ DviState *new;
+
+ new = (DviState *) XtMalloc (sizeof (*new));
+ if (dw->dvi.state)
+ *new = *(dw->dvi.state);
+ else {
+ new->font_size = 10;
+ new->font_number = 1;
+ new->x = 0;
+ new->y = 0;
+ }
+ new->next = dw->dvi.state;
+ dw->dvi.state = new;
+}
+
+static
+pop_env(dw)
+ DviWidget dw;
+{
+ DviState *old;
+
+ old = dw->dvi.state;
+ dw->dvi.state = old->next;
+ XtFree ((char *) old);
+}
+
+static
+InitTypesetter (dw)
+ DviWidget dw;
+{
+ while (dw->dvi.state)
+ pop_env (dw);
+ push_env (dw);
+ FlushCharCache (dw);
+}
+
+#define DRAW_ARGS_MAX 128
+
+static
+ParseDrawFunction(dw, buf)
+DviWidget dw;
+char *buf;
+{
+ int v[DRAW_ARGS_MAX];
+ int i;
+ char *ptr;
+
+ v[0] = v[1] = v[2] = v[3] = 0;
+
+ if (buf[0] == '\0')
+ return;
+ ptr = buf+1;
+
+ for (i = 0; i < DRAW_ARGS_MAX; i++) {
+ if (sscanf(ptr, "%d", v + i) != 1)
+ break;
+ while (*ptr == ' ')
+ ptr++;
+ while (*ptr != '\0' && *ptr != ' ')
+ ptr++;
+ }
+
+ switch (buf[0]) {
+ case 'l': /* draw a line */
+ DrawLine(dw, v[0], v[1]);
+ break;
+ case 'c': /* circle */
+ DrawCircle(dw, v[0]);
+ break;
+ case 'C':
+ DrawFilledCircle(dw, v[0]);
+ break;
+ case 'e': /* ellipse */
+ DrawEllipse(dw, v[0], v[1]);
+ break;
+ case 'E':
+ DrawFilledEllipse(dw, v[0], v[1]);
+ break;
+ case 'a': /* arc */
+ DrawArc(dw, v[0], v[1], v[2], v[3]);
+ break;
+ case 'p':
+ DrawPolygon(dw, v, i);
+ break;
+ case 'P':
+ DrawFilledPolygon(dw, v, i);
+ break;
+ case '~': /* wiggly line */
+ DrawSpline(dw, v, i);
+ break;
+ case 't':
+ dw->dvi.line_thickness = v[0];
+ break;
+ case 'f':
+ if (i > 0 && v[0] >= 0 && v[0] <= DVI_FILL_MAX)
+ dw->dvi.fill = v[0];
+ break;
+ default:
+#if 0
+ warning("unknown drawing function %s", buf);
+#endif
+ break;
+ }
+
+ if (buf[0] == 'e') {
+ if (i > 0)
+ dw->dvi.state->x += v[0];
+ }
+ else {
+ while (--i >= 0) {
+ if (i & 1)
+ dw->dvi.state->y += v[i];
+ else
+ dw->dvi.state->x += v[i];
+ }
+ }
+}
+
+static
+ParseDeviceControl(dw) /* Parse the x commands */
+ DviWidget dw;
+{
+ char str[20], str1[50];
+ int c, n;
+ extern int LastPage, CurrentPage;
+
+ GetWord (dw, str, 20);
+ switch (str[0]) { /* crude for now */
+ case 'T': /* output device */
+ GetWord (dw, str, 20);
+ SetDevice (dw, str);
+ break;
+ case 'i': /* initialize */
+ InitTypesetter (dw);
+ break;
+ case 't': /* trailer */
+ break;
+ case 'p': /* pause -- can restart */
+ break;
+ case 's': /* stop */
+ StopSeen = 1;
+ return;
+ case 'r': /* resolution when prepared */
+ break;
+ case 'f': /* font used */
+ n = GetNumber (dw);
+ GetWord (dw, str, 20);
+ GetLine (dw, str1, 50);
+ SetFontPosition (dw, n, str, str1);
+ break;
+ case 'H': /* char height */
+ break;
+ case 'S': /* slant */
+ break;
+ }
+ while (DviGetC (dw, &c) != '\n') /* skip rest of input line */
+ if (c == EOF)
+ return;
+ return;
+}
+
+
+/*
+Local Variables:
+c-indent-level: 8
+c-continued-statement-offset: 8
+c-brace-offset: -8
+c-argdecl-indent: 8
+c-label-offset: -8
+c-tab-always-indent: nil
+End:
+*/
diff --git a/gnu/usr.bin/groff/xditview/xdit.bm b/gnu/usr.bin/groff/xditview/xdit.bm
new file mode 100644
index 0000000..67b9c8a
--- /dev/null
+++ b/gnu/usr.bin/groff/xditview/xdit.bm
@@ -0,0 +1,14 @@
+#define xdit_width 32
+#define xdit_height 32
+static char xdit_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0xff, 0x03, 0x02, 0x00, 0x00, 0x02,
+ 0x8a, 0xa2, 0xfc, 0x03, 0x52, 0x14, 0x03, 0x04, 0x02, 0x80, 0x00, 0x08,
+ 0x52, 0x54, 0x00, 0x10, 0x8a, 0x22, 0x8f, 0x23, 0x02, 0x20, 0x06, 0x21,
+ 0x8a, 0x12, 0x8c, 0x40, 0x52, 0x14, 0x8c, 0x40, 0x02, 0x10, 0x58, 0x40,
+ 0x52, 0x14, 0x30, 0x40, 0x8a, 0x12, 0x30, 0x40, 0x02, 0x10, 0x70, 0x40,
+ 0x8a, 0x12, 0xc8, 0x40, 0x52, 0x24, 0xc4, 0xe0, 0x02, 0x20, 0x84, 0xe1,
+ 0x52, 0x54, 0xce, 0xf3, 0x8a, 0xa2, 0x00, 0xf8, 0x02, 0x00, 0x03, 0xfc,
+ 0x8a, 0x22, 0xfc, 0xf3, 0x52, 0x14, 0x00, 0xc2, 0x02, 0x00, 0x00, 0x02,
+ 0x52, 0x14, 0x45, 0x02, 0x8a, 0xa2, 0x28, 0x02, 0x02, 0x00, 0x00, 0x02,
+ 0x02, 0x00, 0x00, 0x02, 0xfe, 0xff, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
diff --git a/gnu/usr.bin/groff/xditview/xdit_mask.bm b/gnu/usr.bin/groff/xditview/xdit_mask.bm
new file mode 100644
index 0000000..f34a4f8
--- /dev/null
+++ b/gnu/usr.bin/groff/xditview/xdit_mask.bm
@@ -0,0 +1,14 @@
+#define xdit_mask_width 32
+#define xdit_mask_height 32
+static char xdit_mask_bits[] = {
+ 0xff, 0xff, 0xff, 0x07, 0xff, 0xff, 0xff, 0x07, 0xff, 0xff, 0xff, 0x07,
+ 0xff, 0xff, 0xff, 0x07, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x1f,
+ 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0x7f,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf7, 0xff, 0xff, 0xff, 0xc7,
+ 0xff, 0xff, 0xff, 0x07, 0xff, 0xff, 0xff, 0x07, 0xff, 0xff, 0xff, 0x07,
+ 0xff, 0xff, 0xff, 0x07, 0xff, 0xff, 0xff, 0x07, 0xff, 0xff, 0xff, 0x07,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
diff --git a/gnu/usr.bin/groff/xditview/xditview.c b/gnu/usr.bin/groff/xditview/xditview.c
new file mode 100644
index 0000000..f800d09
--- /dev/null
+++ b/gnu/usr.bin/groff/xditview/xditview.c
@@ -0,0 +1,588 @@
+/*
+ * Copyright 1991 Massachusetts Institute of Technology
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of 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.
+ *
+ * M.I.T. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL M.I.T.
+ * 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.
+ *
+ */
+/*
+ * xditview --
+ *
+ * Display ditroff output in an X window
+ */
+
+#ifndef SABER
+#ifndef lint
+static char rcsid[] = "$XConsortium: xditview.c,v 1.17 89/12/10 17:05:08 rws Exp $";
+#endif /* lint */
+#endif /* SABER */
+
+#include <X11/Xatom.h>
+#include <X11/Xlib.h>
+#include <X11/Xos.h>
+#include <X11/Intrinsic.h>
+#include <X11/StringDefs.h>
+#include <X11/Shell.h>
+#include <X11/Xaw/Paned.h>
+#include <X11/Xaw/Viewport.h>
+#include <X11/Xaw/Box.h>
+#include <X11/Xaw/Command.h>
+#include <X11/Xaw/Dialog.h>
+#include <X11/Xaw/Label.h>
+#include <X11/Xaw/SimpleMenu.h>
+#include <X11/Xaw/SmeBSB.h>
+
+#include <signal.h>
+
+#include "Dvi.h"
+
+#include "xdit.bm"
+#include "xdit_mask.bm"
+#include "stdio.h"
+
+extern FILE *popen();
+extern void exit();
+
+static struct app_resources {
+ char *print_command;
+ char *filename;
+} app_resources;
+
+#define offset(field) XtOffset(struct app_resources *, field)
+
+/* Application resources. */
+
+static XtResource resources[] = {
+ {"printCommand", "PrintCommand", XtRString, sizeof(char*),
+ offset(print_command), XtRString, NULL},
+ {"filename", "Filename", XtRString, sizeof(char*),
+ offset(filename), XtRString, NULL},
+};
+
+#undef offset
+
+/* Command line options table. Only resources are entered here...there is a
+ pass over the remaining options after XtParseCommand is let loose. */
+
+static XrmOptionDescRec options[] = {
+{"-page", "*dvi.pageNumber", XrmoptionSepArg, NULL},
+{"-backingStore", "*dvi.backingStore", XrmoptionSepArg, NULL},
+{"-resolution", "*dvi.resolution", XrmoptionSepArg, NULL},
+{"-printCommand", ".printCommand", XrmoptionSepArg, NULL},
+{"-filename", ".filename", XrmoptionSepArg, NULL},
+{"-noPolyText", "*dvi.noPolyText", XrmoptionNoArg, "TRUE"},
+};
+
+static char current_print_command[1024];
+
+static char current_file_name[1024];
+static FILE *current_file;
+
+/*
+ * Report the syntax for calling xditview.
+ */
+
+static
+Syntax(call)
+ char *call;
+{
+ (void) printf ("Usage: %s [-fg <color>] [-bg <color>]\n", call);
+ (void) printf (" [-bd <color>] [-bw <pixels>] [-help]\n");
+ (void) printf (" [-display displayname] [-geometry geom]\n");
+ (void) printf (" [-page <page-number>] [-backing <backing-store>]\n");
+ (void) printf (" [-resolution <res>] [-print <command>]\n");
+ (void) printf (" [-filename <file>] [filename]\n\n");
+ exit(1);
+}
+
+static void NewFile (), SetPageNumber ();
+static Widget toplevel, paned, viewport, dvi;
+static Widget page;
+static Widget simpleMenu;
+
+static void NextPage(), PreviousPage(), SelectPage(), OpenFile(), Quit();
+static void Print();
+
+static struct menuEntry {
+ char *name;
+ void (*function)();
+} menuEntries[] = {
+ "nextPage", NextPage,
+ "previousPage", PreviousPage,
+ "selectPage", SelectPage,
+ "print", Print,
+ "openFile", OpenFile,
+ "quit", Quit,
+};
+
+static void NextPageAction(), PreviousPageAction(), SelectPageAction();
+static void OpenFileAction(), QuitAction();
+static void AcceptAction(), CancelAction();
+static void PrintAction();
+static void RerasterizeAction();
+
+XtActionsRec xditview_actions[] = {
+ "NextPage", NextPageAction,
+ "PreviousPage", PreviousPageAction,
+ "SelectPage", SelectPageAction,
+ "Print", PrintAction,
+ "OpenFile", OpenFileAction,
+ "Rerasterize", RerasterizeAction,
+ "Quit", QuitAction,
+ "Accept", AcceptAction,
+ "Cancel", CancelAction,
+};
+
+#define MenuNextPage 0
+#define MenuPreviousPage 1
+#define MenuSelectPage 2
+#define MenuPrint 3
+#define MenuOpenFile 4
+#define MenuQuit 5
+
+static char pageLabel[256] = "Page <none>";
+
+void main(argc, argv)
+ int argc;
+ char **argv;
+{
+ char *file_name = 0;
+ int i;
+ static Arg labelArgs[] = {
+ {XtNlabel, (XtArgVal) pageLabel},
+ };
+ Arg topLevelArgs[2];
+ Widget entry;
+ Arg pageNumberArgs[1];
+ int page_number;
+
+ toplevel = XtInitialize("main", "GXditview",
+ options, XtNumber (options),
+ &argc, argv);
+ if (argc > 2)
+ Syntax(argv[0]);
+
+ XtGetApplicationResources(toplevel, (XtPointer)&app_resources,
+ resources, XtNumber(resources),
+ NULL, (Cardinal) 0);
+ if (app_resources.print_command)
+ strcpy(current_print_command, app_resources.print_command);
+
+ XtAppAddActions(XtWidgetToApplicationContext(toplevel),
+ xditview_actions, XtNumber (xditview_actions));
+
+ XtSetArg (topLevelArgs[0], XtNiconPixmap,
+ XCreateBitmapFromData (XtDisplay (toplevel),
+ XtScreen(toplevel)->root,
+ xdit_bits, xdit_width, xdit_height));
+
+ XtSetArg (topLevelArgs[1], XtNiconMask,
+ XCreateBitmapFromData (XtDisplay (toplevel),
+ XtScreen(toplevel)->root,
+ xdit_mask_bits,
+ xdit_mask_width, xdit_mask_height));
+ XtSetValues (toplevel, topLevelArgs, 2);
+ if (argc > 1)
+ file_name = argv[1];
+
+ /*
+ * create the menu and insert the entries
+ */
+ simpleMenu = XtCreatePopupShell ("menu", simpleMenuWidgetClass, toplevel,
+ NULL, 0);
+ for (i = 0; i < XtNumber (menuEntries); i++) {
+ entry = XtCreateManagedWidget(menuEntries[i].name,
+ smeBSBObjectClass, simpleMenu,
+ NULL, (Cardinal) 0);
+ XtAddCallback(entry, XtNcallback, menuEntries[i].function, NULL);
+ }
+
+ paned = XtCreateManagedWidget("paned", panedWidgetClass, toplevel,
+ NULL, (Cardinal) 0);
+ viewport = XtCreateManagedWidget("viewport", viewportWidgetClass, paned,
+ NULL, (Cardinal) 0);
+ dvi = XtCreateManagedWidget ("dvi", dviWidgetClass, viewport, NULL, 0);
+ page = XtCreateManagedWidget ("label", labelWidgetClass, paned,
+ labelArgs, XtNumber (labelArgs));
+ XtSetArg (pageNumberArgs[0], XtNpageNumber, &page_number);
+ XtGetValues (dvi, pageNumberArgs, 1);
+ if (file_name)
+ NewFile (file_name);
+ /* NewFile modifies current_file_name, so do this here. */
+ if (app_resources.filename)
+ strcpy(current_file_name, app_resources.filename);
+ XtRealizeWidget (toplevel);
+ if (file_name)
+ SetPageNumber (page_number);
+ XtMainLoop();
+}
+
+static void
+SetPageNumber (number)
+{
+ Arg arg[2];
+ int actual_number, last_page;
+
+ XtSetArg (arg[0], XtNpageNumber, number);
+ XtSetValues (dvi, arg, 1);
+ XtSetArg (arg[0], XtNpageNumber, &actual_number);
+ XtSetArg (arg[1], XtNlastPageNumber, &last_page);
+ XtGetValues (dvi, arg, 2);
+ if (actual_number == 0)
+ sprintf (pageLabel, "Page <none>");
+ else if (last_page > 0)
+ sprintf (pageLabel, "Page %d of %d", actual_number, last_page);
+ else
+ sprintf (pageLabel, "Page %d", actual_number);
+ XtSetArg (arg[0], XtNlabel, pageLabel);
+ XtSetValues (page, arg, 1);
+}
+
+static void
+SelectPageNumber (number_string)
+char *number_string;
+{
+ SetPageNumber (atoi(number_string));
+}
+
+static int hadFile = 0;
+
+static void
+NewFile (name)
+char *name;
+{
+ Arg arg[2];
+ char *n;
+ FILE *new_file;
+ Boolean seek = 0;
+
+ if (current_file) {
+ if (!strcmp (current_file_name, "-"))
+ ;
+ else if (current_file_name[0] == '|')
+ pclose (current_file);
+ else
+ fclose (current_file);
+ }
+ if (!strcmp (name, "-"))
+ new_file = stdin;
+ else if (name[0] == '|')
+ new_file = popen (name+1, "r");
+ else {
+ new_file = fopen (name, "r");
+ seek = 1;
+ }
+ if (!new_file) {
+ /* XXX display error message */
+ return;
+ }
+ XtSetArg (arg[0], XtNfile, new_file);
+ XtSetArg (arg[1], XtNseek, seek);
+ XtSetValues (dvi, arg, 2);
+ if (hadFile || name[0] != '-' || name[1] != '\0') {
+ XtSetArg (arg[0], XtNtitle, name);
+ if (name[0] != '/' && (n = strrchr (name, '/')))
+ n = n + 1;
+ else
+ n = name;
+ XtSetArg (arg[1], XtNiconName, n);
+ XtSetValues (toplevel, arg, 2);
+ }
+ hadFile = 1;
+ SelectPageNumber ("1");
+ strcpy (current_file_name, name);
+ current_file = new_file;
+}
+
+static char fileBuf[1024];
+
+ResetMenuEntry (entry)
+ Widget entry;
+{
+ Arg arg[1];
+
+ XtSetArg (arg[0], XtNpopupOnEntry, entry);
+ XtSetValues (XtParent(entry) , arg, (Cardinal) 1);
+}
+
+/*ARGSUSED*/
+
+static void
+NextPage (entry, name, data)
+ Widget entry;
+ caddr_t name, data;
+{
+ NextPageAction();
+ ResetMenuEntry (entry);
+}
+
+static void
+NextPageAction ()
+{
+ Arg args[1];
+ int number;
+
+ XtSetArg (args[0], XtNpageNumber, &number);
+ XtGetValues (dvi, args, 1);
+ SetPageNumber (number+1);
+}
+
+/*ARGSUSED*/
+
+static void
+PreviousPage (entry, name, data)
+ Widget entry;
+ caddr_t name, data;
+{
+ PreviousPageAction ();
+ ResetMenuEntry (entry);
+}
+
+static void
+PreviousPageAction ()
+{
+ Arg args[1];
+ int number;
+
+ XtSetArg (args[0], XtNpageNumber, &number);
+ XtGetValues (dvi, args, 1);
+ SetPageNumber (number-1);
+}
+
+/* ARGSUSED */
+
+static void
+SelectPage (entry, name, data)
+ Widget entry;
+ caddr_t name, data;
+{
+ SelectPageAction ();
+ ResetMenuEntry (entry);
+}
+
+static void
+SelectPageAction ()
+{
+ MakePrompt (toplevel, "Page number", SelectPageNumber, "");
+}
+
+
+static void
+DoPrint (name)
+ char *name;
+{
+ FILE *print_file;
+#ifdef SIGNALRETURNSINT
+ int (*handler)();
+#else
+ void (*handler)();
+#endif
+ /* Avoid dieing because of an invalid command. */
+ handler = signal(SIGPIPE, SIG_IGN);
+
+ print_file = popen(name, "w");
+ if (!print_file)
+ /* XXX print error message */
+ return;
+ DviSaveToFile(dvi, print_file);
+ pclose(print_file);
+ signal(SIGPIPE, handler);
+ strcpy(current_print_command, name);
+}
+
+static void
+RerasterizeAction()
+{
+ Arg args[1];
+ int number;
+
+ if (current_file_name[0] == 0) {
+ /* XXX display an error message */
+ return;
+ }
+ XtSetArg (args[0], XtNpageNumber, &number);
+ XtGetValues (dvi, args, 1);
+ NewFile(current_file_name);
+ SetPageNumber (number);
+}
+
+/* ARGSUSED */
+
+static void
+Print (entry, name, data)
+ Widget entry;
+ caddr_t name, data;
+{
+ PrintAction ();
+ ResetMenuEntry (entry);
+}
+
+static void
+PrintAction ()
+{
+ if (current_print_command[0])
+ strcpy (fileBuf, current_print_command);
+ else
+ fileBuf[0] = '\0';
+ MakePrompt (toplevel, "Print command:", DoPrint, fileBuf);
+}
+
+
+/* ARGSUSED */
+
+static void
+OpenFile (entry, name, data)
+ Widget entry;
+ caddr_t name, data;
+{
+ OpenFileAction ();
+ ResetMenuEntry (entry);
+}
+
+static void
+OpenFileAction ()
+{
+ if (current_file_name[0])
+ strcpy (fileBuf, current_file_name);
+ else
+ fileBuf[0] = '\0';
+ MakePrompt (toplevel, "File to open:", NewFile, fileBuf);
+}
+
+/* ARGSUSED */
+
+static void
+Quit (entry, closure, data)
+ Widget entry;
+ caddr_t closure, data;
+{
+ QuitAction ();
+}
+
+static void
+QuitAction ()
+{
+ exit (0);
+}
+
+Widget promptShell, promptDialog;
+void (*promptfunction)();
+
+/* ARGSUSED */
+static
+void CancelAction (widget, event, params, num_params)
+ Widget widget;
+ XEvent *event;
+ String *params;
+ Cardinal *num_params;
+{
+ if (promptShell) {
+ XtSetKeyboardFocus(toplevel, (Widget) None);
+ XtDestroyWidget(promptShell);
+ promptShell = (Widget) 0;
+ }
+}
+
+static
+void AcceptAction (widget, event, params, num_params)
+ Widget widget;
+ XEvent *event;
+ String *params;
+ Cardinal *num_params;
+{
+ (*promptfunction)(XawDialogGetValueString(promptDialog));
+ CancelAction (widget, event, params, num_params);
+}
+
+MakePrompt(centerw, prompt, func, def)
+Widget centerw;
+char *prompt;
+void (*func)();
+char *def;
+{
+ static Arg dialogArgs[] = {
+ {XtNlabel, NULL},
+ {XtNvalue, NULL},
+ };
+ Arg valueArgs[1];
+ Arg centerArgs[2];
+ Position source_x, source_y;
+ Position dest_x, dest_y;
+ Dimension center_width, center_height;
+ Dimension prompt_width, prompt_height;
+ Widget valueWidget;
+
+ CancelAction ((Widget)NULL, (XEvent *) 0, (String *) 0, (Cardinal *) 0);
+ promptShell = XtCreatePopupShell ("promptShell", transientShellWidgetClass,
+ toplevel, NULL, (Cardinal) 0);
+ dialogArgs[0].value = (XtArgVal)prompt;
+ dialogArgs[1].value = (XtArgVal)def;
+ promptDialog = XtCreateManagedWidget( "promptDialog", dialogWidgetClass,
+ promptShell, dialogArgs, XtNumber (dialogArgs));
+ XawDialogAddButton(promptDialog, "accept", NULL, (caddr_t) 0);
+ XawDialogAddButton(promptDialog, "cancel", NULL, (caddr_t) 0);
+ valueWidget = XtNameToWidget (promptDialog, "value");
+ if (valueWidget) {
+ XtSetArg (valueArgs[0], XtNresizable, TRUE);
+ XtSetValues (valueWidget, valueArgs, 1);
+ /*
+ * as resizable isn't set until just above, the
+ * default value will be displayed incorrectly.
+ * rectify the situation by resetting the values
+ */
+ XtSetValues (promptDialog, dialogArgs, XtNumber (dialogArgs));
+ }
+ XtSetKeyboardFocus (promptDialog, valueWidget);
+ XtSetKeyboardFocus (toplevel, valueWidget);
+ XtRealizeWidget (promptShell);
+ /*
+ * place the widget in the center of the "parent"
+ */
+ XtSetArg (centerArgs[0], XtNwidth, &center_width);
+ XtSetArg (centerArgs[1], XtNheight, &center_height);
+ XtGetValues (centerw, centerArgs, 2);
+ XtSetArg (centerArgs[0], XtNwidth, &prompt_width);
+ XtSetArg (centerArgs[1], XtNheight, &prompt_height);
+ XtGetValues (promptShell, centerArgs, 2);
+ source_x = (center_width - prompt_width) / 2;
+ source_y = (center_height - prompt_height) / 3;
+ XtTranslateCoords (centerw, source_x, source_y, &dest_x, &dest_y);
+ XtSetArg (centerArgs[0], XtNx, dest_x);
+ XtSetArg (centerArgs[1], XtNy, dest_y);
+ XtSetValues (promptShell, centerArgs, 2);
+ XtMapWidget(promptShell);
+ promptfunction = func;
+}
+
+/* For DviChar.c */
+
+char *xmalloc(n)
+ int n;
+{
+ return XtMalloc(n);
+}
+
+/*
+Local Variables:
+c-indent-level: 4
+c-continued-statement-offset: 4
+c-brace-offset: -4
+c-argdecl-indent: 4
+c-label-offset: -4
+c-tab-always-indent: nil
+End:
+*/
diff --git a/gnu/usr.bin/groff/xditview/xtotroff.c b/gnu/usr.bin/groff/xditview/xtotroff.c
new file mode 100644
index 0000000..15841f8
--- /dev/null
+++ b/gnu/usr.bin/groff/xditview/xtotroff.c
@@ -0,0 +1,303 @@
+/*
+ * xtotroff
+ *
+ * convert X font metrics into troff font metrics
+ */
+
+#include <X11/Xlib.h>
+#include <stdio.h>
+#include <ctype.h>
+#include "XFontName.h"
+#include "DviChar.h"
+
+#ifdef X_NOT_STDC_ENV
+char *malloc();
+#else
+#include <stdlib.h>
+#endif
+
+#define charWidth(fi,c) ((fi)->per_char[(c) - (fi)->min_char_or_byte2].width)
+#define charHeight(fi,c) ((fi)->per_char[(c) - (fi)->min_char_or_byte2].ascent)
+#define charDepth(fi,c) ((fi)->per_char[(c) - (fi)->min_char_or_byte2].descent)
+#define charLBearing(fi,c) ((fi)->per_char[(c) - (fi)->min_char_or_byte2].lbearing)
+#define charRBearing(fi,c) ((fi)->per_char[(c) - (fi)->min_char_or_byte2].rbearing)
+
+Display *dpy;
+int groff_flag = 0;
+unsigned resolution = 75;
+unsigned point_size = 10;
+
+int charExists (fi, c)
+ XFontStruct *fi;
+ int c;
+{
+ XCharStruct *p;
+
+ if (c < fi->min_char_or_byte2 || c > fi->max_char_or_byte2)
+ return 0;
+ p = fi->per_char + (c - fi->min_char_or_byte2);
+ return (p->lbearing != 0 || p->rbearing != 0 || p->width != 0
+ || p->ascent != 0 || p->descent != 0 || p->attributes != 0);
+}
+
+/* Canonicalize the font name by replacing scalable parts by *s. */
+
+CanonicalizeFontName (font_name, canon_font_name)
+ char *font_name, *canon_font_name;
+{
+ unsigned int attributes;
+ XFontName parsed;
+
+ if (!XParseFontName(font_name, &parsed, &attributes)) {
+ fprintf (stderr, "not a standard name: %s\n", font_name);
+ return 0;
+ }
+
+ attributes &= ~(FontNamePixelSize|FontNameAverageWidth
+ |FontNamePointSize
+ |FontNameResolutionX|FontNameResolutionY);
+ XFormatFontName(&parsed, attributes, canon_font_name);
+ return 1;
+}
+
+int FontNamesAmbiguous(font_name, names, count)
+char *font_name;
+char **names;
+int count;
+{
+ char name1[2048], name2[2048];
+ int i;
+
+ if (count == 1)
+ return 0;
+
+ for (i = 0; i < count; i++) {
+ if (!CanonicalizeFontName(names[i], i == 0 ? name1 : name2)) {
+ fprintf(stderr, "bad font name: %s\n", names[i]);
+ return 1;
+ }
+ if (i > 0 && strcmp(name1, name2) != 0) {
+ fprintf(stderr, "ambiguous font name: %s\n", font_name);
+ fprintf(stderr, " matches %s\n", names[0]);
+ fprintf(stderr, " and %s\n", names[i]);
+ return 1;
+ }
+
+ }
+ return 0;
+}
+
+MapFont (font_name, troff_name)
+ char *font_name;
+ char *troff_name;
+{
+ XFontStruct *fi;
+ int count;
+ char **names;
+ FILE *out;
+ int c;
+ unsigned int attributes;
+ XFontName parsed;
+ int j, k;
+ DviCharNameMap *char_map;
+ char encoding[256];
+ char *s;
+ int wid;
+ char name_string[2048];
+
+ if (!XParseFontName(font_name, &parsed, &attributes)) {
+ fprintf (stderr, "not a standard name: %s\n", font_name);
+ return 0;
+ }
+
+ attributes &= ~(FontNamePixelSize|FontNameAverageWidth);
+ attributes |= FontNameResolutionX;
+ attributes |= FontNameResolutionY;
+ attributes |= FontNamePointSize;
+ parsed.ResolutionX = resolution;
+ parsed.ResolutionY = resolution;
+ parsed.PointSize = point_size*10;
+ XFormatFontName(&parsed, attributes, name_string);
+
+ names = XListFonts (dpy, name_string, 100000, &count);
+ if (count < 1) {
+ fprintf (stderr, "bad font name: %s\n", font_name);
+ return 0;
+ }
+
+ if (FontNamesAmbiguous(font_name, names, count))
+ return 0;
+
+ XParseFontName(names[0], &parsed, &attributes);
+ sprintf (encoding, "%s-%s", parsed.CharSetRegistry,
+ parsed.CharSetEncoding);
+ for (s = encoding; *s; s++)
+ if (isupper (*s))
+ *s = tolower (*s);
+ char_map = DviFindMap (encoding);
+ if (!char_map) {
+ fprintf (stderr, "not a standard encoding: %s\n", encoding);
+ return 0;
+ }
+
+ fi = XLoadQueryFont (dpy, names[0]);
+ if (!fi) {
+ fprintf (stderr, "font does not exist: %s\n", names[0]);
+ return 0;
+ }
+
+ printf ("%s -> %s\n", names[0], troff_name);
+
+ (void) unlink (troff_name);
+ out = fopen (troff_name, "w");
+ if (!out) {
+ perror (troff_name);
+ return 0;
+ }
+ fprintf (out, "name %s\n", troff_name);
+ if (!strcmp (char_map->encoding, "adobe-fontspecific"))
+ fprintf (out, "special\n");
+ if (charExists (fi, ' ')) {
+ int w = charWidth (fi, ' ');
+ if (w > 0)
+ fprintf (out, "spacewidth %d\n", w);
+ }
+ fprintf (out, "charset\n");
+ for (c = fi->min_char_or_byte2; c <= fi->max_char_or_byte2; c++) {
+ char *name = DviCharName (char_map,c,0);
+ if (charExists (fi, c) && (groff_flag || name)) {
+
+ wid = charWidth (fi, c);
+
+ fprintf (out, "%s\t%d",
+ name ? name : "---",
+ wid);
+ if (groff_flag) {
+ int param[5];
+ param[0] = charHeight (fi, c);
+ param[1] = charDepth (fi, c);
+ param[2] = 0 /* charRBearing (fi, c) - wid */;
+ param[3] = 0 /* charLBearing (fi, c) */;
+ param[4] = 0; /* XXX */
+ for (j = 0; j < 5; j++)
+ if (param[j] < 0)
+ param[j] = 0;
+ for (j = 4; j >= 0; j--)
+ if (param[j] != 0)
+ break;
+ for (k = 0; k <= j; k++)
+ fprintf (out, ",%d", param[k]);
+ }
+ fprintf (out, "\t0\t0%o\n", c);
+
+ if (name) {
+ for (k = 1; DviCharName(char_map,c,k); k++) {
+ fprintf (out, "%s\t\"\n",
+ DviCharName (char_map,c,k));
+ }
+ }
+ }
+ }
+ XUnloadFont (dpy, fi->fid);
+ fclose (out);
+ return 1;
+}
+
+static usage(prog)
+ char *prog;
+{
+ fprintf (stderr,
+ "usage: %s [-g] [-r resolution] [-s pointsize FontMap\n",
+ prog);
+ exit (1);
+}
+
+
+/* For use by DviChar.c */
+
+char *xmalloc(n)
+int n;
+{
+ char *p = malloc(n);
+ if (!p) {
+ fprintf(stderr, "Out of memory\n");
+ exit(1);
+ }
+ return p;
+}
+
+main (argc, argv)
+ char **argv;
+{
+ char troff_name[1024];
+ char font_name[1024];
+ char line[1024];
+ char *a, *b, c;
+ int position;
+ FILE *map;
+ int opt;
+ extern int optind;
+ extern char *optarg;
+
+ while ((opt = getopt(argc, argv, "gr:s:")) != EOF) {
+ switch (opt) {
+ case 'g':
+ groff_flag = 1;
+ break;
+ case 'r':
+ sscanf(optarg, "%u", &resolution);
+ break;
+ case 's':
+ sscanf(optarg, "%u", &point_size);
+ break;
+ default:
+ usage(argv[0]);
+ }
+ }
+ if (argc - optind != 1)
+ usage(argv[0]);
+
+ dpy = XOpenDisplay (0);
+ if (!dpy) {
+ fprintf (stderr, "Can't connect to the X server.\n");
+ fprintf (stderr, "Make sure the DISPLAY environment variable is set correctly.\n");
+ exit (1);
+ }
+ position = 1;
+
+ map = fopen (argv[optind], "r");
+ if (map == NULL) {
+ perror (argv[optind]);
+ exit (1);
+ }
+
+ while (fgets (line, sizeof (line), map)) {
+ for (a=line,b=troff_name; *a; a++,b++) {
+ c = (*b = *a);
+ if (c == ' ' || c == '\t')
+ break;
+ }
+ *b = '\0';
+ while (*a && (*a == ' ' || *a == '\t'))
+ ++a;
+ for (b=font_name; *a; a++,b++)
+ if ((*b = *a) == '\n')
+ break;
+ *b = '\0';
+ if (!MapFont (font_name, troff_name))
+ exit (1);
+ ++position;
+ }
+ exit (0);
+}
+
+/*
+Local Variables:
+c-indent-level: 8
+c-continued-statement-offset: 8
+c-brace-offset: -8
+c-argdecl-indent: 8
+c-label-offset: -8
+c-tab-always-indent: nil
+End:
+*/
diff --git a/gnu/usr.bin/gzip/COPYING b/gnu/usr.bin/gzip/COPYING
new file mode 100644
index 0000000..a43ea21
--- /dev/null
+++ b/gnu/usr.bin/gzip/COPYING
@@ -0,0 +1,339 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 675 Mass Ave, Cambridge, MA 02139, USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ Appendix: How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) 19yy <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) 19yy name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/gnu/usr.bin/gzip/ChangeLog b/gnu/usr.bin/gzip/ChangeLog
new file mode 100644
index 0000000..7dd0f86
--- /dev/null
+++ b/gnu/usr.bin/gzip/ChangeLog
@@ -0,0 +1,587 @@
+Wed Aug 18 09:34:23 1993 Jean-loup Gailly (jloup@chorus.fr)
+
+ * version 1.2.4
+ By default, do not restore file name and timestamp from those saved
+ inside the .gz file (behave as 'compress'). Added the --name option
+ to force name and timestamp restoration.
+ Accept - as synonym for stdin.
+ Use manlinks=so or ln to support either hard links or .so in man pages
+ Accept foo.gz~ in zdiff.
+ Added support for Windows NT
+ Handle ENAMETOOLONG for strict Posix systems
+ Use --recursive instead of --recurse to comply with Webster and
+ the GNU stdandard.
+ Allow installation of shell scripts with a g prefix: make G=g install
+ Install by default zcat as gzcat if gzcat already exists in path.
+ Let zmore behave as more when invoked without parameters (give help)
+ Let gzip --list reject files not in gzip format even with --force.
+ Don't complain about non gzip files for options -rt or -rl.
+ Added advice in INSTALL for several systems.
+ Added makefile entries for NeXTstep 3.1 (if configure fails)
+ Avoid problem with memcpy on Pyramid (gave crc error on some files)
+ Support the -r option when compiled with Borland C++ on msdos.
+ Force lower case file names only for FAT file systems (not HPFS)
+ Rewrite one expression in inflate.c to avoid cc bug on Solaris x86.
+ In the msdos makefiles, get match.asm from the msdos subdirectory.
+ Catch SIGTERM and SIGHUP only if they are not ignored.
+ getopt.c: on Amiga, "#if !defined(const)" does not compile.
+ Use register parameters on Amiga.
+ Do not force names to lower case on Amiga.
+ Fix support of Atari TOS (Makefile.st and tailor.h)
+ In unlzw.c, do not suggest using zcat if zcat already used.
+ In INSTALL, suggest using bsdinst for HPUX.
+ Document Turbo C++ 1.0 bug in INSTALL.
+ Improved the documentation relative to the --no-name option.
+ Avoid signed/unsigned warnings in several files.
+ Added pointer to jka-compr19.el in README.
+ Added pointer to OS/2 executables in README.
+ Added --block-compress in tar -z example (gzip.1 and gzip.texi).
+ Don't keep rcsid in executable (avoid compilation warnings).
+ Check also the correctness of the first byte of an .Z file.
+ Return non zero status for an invalid option.
+ Remove "NEWFILES" from os2/gzip.def for Borland C++ on OS/2.
+ Remove "time stamp restored" message (just obey the -N request).
+
+Thu Jun 24 10:27:57 1993 Jean-loup Gailly (jloup@chorus.fr)
+
+ * version 1.2.3
+ Don't display the output name when decompressing except with --verbose.
+ Remove usage of alloca in getopt.c and all makefiles.
+ Use ASCPP instead of CPP to avoid breaking AC_HEADER_CHECK on RiscOS.
+ Added the zfile shell script in subdirectory sample.
+ Moved the list of compiler bugs from README to INSTALL.
+ Added vms/Readme.vms.
+ Fix DIST_BUFSIZE check in unlzh.c for 16 bit machines.
+ Fix REGSIGTYP macro in configure.in.
+ Use 'define' instead of == in vms/gzip.hlp.
+ Avoid warnings in unlzh.c
+ Allow separate installation of binaries and man pages.
+ Simplified handling of file names with spaces in zgrep and znew.
+ Fix dependencies and remove rule for trees.c in amiga/Makefile.sasc
+ Add missing quote in gzexe.
+
+Thu Jun 17 13:47:05 1993 Jean-loup Gailly (jloup@chorus.fr)
+
+ * version 1.2.2
+ Fix a compilation error in gzip.c on Sun with cc (worked with gcc).
+
+Wed Jun 16 11:20:27 1993 Jean-loup Gailly (jloup@chorus.fr)
+
+ * version 1.2.1
+ Let zmore act as more if the data is not gzipped.
+ By default, display output name only when name was actually truncated.
+ Use absolute path names in gzexe'd programs for better security.
+ In gzexe, use chmod 700 instead of 755 and don't gzexe tail,rm,etc...
+ Update vms/gzip.hlp.
+ Added a note about the fast options (-1 to -3) in algorithm.doc.
+ Improved man page for zgrep.
+ Minor fixes to gzip.texi.
+ Always set LC_ALL and LANG in configure (for tr on HPUX)
+
+Mon Jun 14 10:03:24 1993 Jean-loup Gailly (jloup@chorus.fr)
+
+ * version 1.2
+ Added the --list option to display the file characteristics.
+ Added the --no-name option: do not save or restore original filename
+ Save the original name by default.
+ Allow gunzip --suffix "" to attempt decompression on any file
+ regardless of its extension if an original name is present.
+ Add support for the SCO compress -H format.
+ gzip --fast now compresses faster (speed close to that of compress)
+ with degraded compression ratio (but still better than compress).
+ Default level changed to -6 (acts exactly as previous level -5) to
+ be a better indication of its placement in the speed/ratio range.
+ Use smart name truncation: 123456789012.c -> 123456789.c.gz
+ instead of 12345678901.gz
+ With --force, let zcat pass non gzip'ed data unchanged (zcat == cat)
+ Added the zgrep shell script.
+ Made sub.c useful for 16 bit sound, 24 bit images, etc..
+ Supress warnings about suffix for gunzip -r, except with --verbose.
+ Moved the sample programs to a subdirectory sample.
+ On MSDOS, use .gz extension when possible (files without extension)
+ Added a "Special targets" section in INSTALL.
+ Use stty -g correctly in zmore.in.
+ Use cheaper test for gzipness in zforce.in.
+ Remove space before $ in match.S (no longer accepted by gas 2.x)
+ For the shell scripts, do not assume that gzip is in the path.
+ Fix syntax error and define lnk$library in vms/Makefile.mms
+ REGSIGTYPE is void on the Amiga.
+ Do not write empty line when decompressing stdin with --verbose.
+ Fix the 1.1.2 fix for VMS (bug in get_suffix)
+ Added warning in README about compiler bug on Solaris 2.1 for x86.
+ Added warning about 'rehash' in INSTALL.
+ Removed default value of read_buf in bits.c (supermax doesn't like).
+ In tailor.h, added support for Borland C and Zortech C on OS/2.
+ Added warning in gzexe about Ultrix buggy sh (use /bin/sh5 instead).
+ Added warning in zdiff about AIX buggy sh (use /bin/ksh instead).
+ In configure.in, do not try the asm code if DEFS contains NO_ASM
+
+Fri Jun 4 09:49:33 1993 Jean-loup Gailly (jloup@chorus.fr)
+
+ * version 1.1.2
+ Fix serious bug for VMS (-gz not removed when decompressing).
+ Allow suffix other than .gz in znew.
+ Do not display compression ratio when decompressing stdin.
+ In zmore.in, work around brain damaged stty -g (Ultrix).
+ Display a correct compression ratio for .Z files.
+ Added .z to .gz renaming script in INTALL.
+ Allow setting CFLAGS in configure.
+ Add warning in README about bug in Concentrix cc compiler.
+ Avoid || in Makefile.in (at least one make doesn't support this).
+ Disable useless --ascii option for the Amiga.
+ Add a pointer to the Primos executable in README.
+ Added description of extra field in algorithm.doc.
+ Do not redefine NULL in alloca.c.
+ Added check for unsupported compression methods.
+ Avoid getopt redeclaration on OSF/1.
+
+Tue Jun 1 09:07:15 1993 Jean-loup Gailly (jloup@chorus.fr)
+
+ * version 1.1.1
+ Fix serious bug in vms.c (== instead of =).
+ Added --ascii option.
+ Add workaround in configure.in for Ultrix (quote eval argument)
+ Do not use unset in znew (not supported on Ultrix)
+ Use tar.gz instead of tar.z for the distribution of gzip.
+ Add missing menu item in gzip.texi.
+ Use size_t instead of unsigned, add AC_SIZE_T in configure.in.
+
+Fri May 28 11:40:01 1993 Jean-loup Gailly (jloup@chorus.fr)
+
+ * version 1.1
+ Use .gz suffix by default, add --suffix option.
+ Let gunzip accept a "_z" suffix (used by one 'compress' on Vax/VMS).
+ Quit when reading garbage from stdin instead of reporting an error.
+ Added sub.c and add.c for compression of 8 bit images.
+ Added makefile for VAX/MMS and support for wildcards on VMS.
+ Added support for MSC under OS/2.
+ Added support for Prime/PRIMOS.
+ Display compression ratio also when decompressing.
+ Quit after --version (GNU standard)
+ Use --force to bypass isatty() check.
+ Accept --silent as synonym for --quiet (see longopts.table)
+ Accept --to-stdout as synonym for --stdout (see longopts.table)
+ Accept -H and -? in addition to -h and --help.
+ Added comparison of zip and gzip in the readme file.
+ Return an error code in all main compression/decompression functions.
+ Continue processing other files in case of recoverable error.
+ Add description of -f in znew.1.
+ Do not keep uncompressed version for znew -t if .gz already exists.
+ On Unix, use only st_ino and st_dev in same_file().
+ Use S_IRUSR and S_IWUSR if they exist.
+ "test $1 = -d" -> "test x$1 = x-d" in gzexe.
+ In match.S, use symbol sysV68 to detect the Motorola Delta.
+ Do not include memory.h with gcc (conflicting declarations on Sun).
+ Fix more typos.
+ On VMS, define unlink as delete also for gcc.
+ In "make check", unset LANG because "wc -c" fails on Kanji.
+ Renamed shdir as scriptdir.
+ Use the 68020 code instead of 68000 code on the NeXT.
+ Documented --uncompress as synonym for --decompress.
+ Include the standard header files before gzip.h (needed on Bull).
+ Do not assume that _POSIX_VERSION implies dirent.h present.
+ Removed gzip-tar.patch since tar 1.11.2 handles gzip directly.
+ Use less memory when compiled with -DSMALL_MEM (for MSDOS).
+ Optimized updcrc().
+ Don't complain if cc -E does not work correctly.
+ Do not attempt reading 64K bytes on 16 bit Unix systems.
+ Do not use the variable name 'overhead' which is reserved on Lynx!
+ One BULL compiler does not like *p++ in inflate.c => *p, p++.
+ Use casts on free and memcmp to avoid warnings.
+ Remove the "off by more than one minute" time stamp kludge, but
+ document how to avoid saving the time stamp on pipes if desired.
+ Include crypt.h in inflate.c (one system predefines the CRYPT symbol).
+ Add links to gunzip and (g)zcat in the default make rule.
+ Create installation directories if they do not exist.
+ Clarified --prefix option in INSTALL.
+ Use symbol mc68k in match.S for the DIAB DS90.
+ Guard against zero length _match.s in configure.in.
+ In zmore, restore all tty options using stty -g.
+ Added support for MacOS
+ Simplified makecrc.c.
+ Avoid warnings in getopt.c, util.c, unlzw.c.
+ Use autoconf 1.4, in particular for INSTALL and AC_HAVE_POUNDBANG
+ Use .so instead of hard links for zcat.1, gunzip.1 and zcmp.1.
+ Fixed declration of sig_type.
+ Make consistency check in fcfree.
+ Added ztouch.
+ Do not complain if utime fails on a directory (for OS/2).
+
+Thu Mar 18 18:56:43 1993 Jean-loup Gailly (jloup@chorus.fr)
+
+ * version 1.0.7
+ Allow zmore to read from standard input (like more).
+ Support the 68000 (Atari ST) in match.S.
+ Retry partial writes (required on Linux when gzip is suspended in
+ a pipe).
+ Allow full pathnames and renamings in gzexe.
+ Don't let gzexe compress setuid executables or gzip itself.
+ Added vms/Makefile.gcc for gcc on the Vax.
+ Give a pointer to Solaris and VMS executables of gzip in README.
+ Allow installation of binaries and shell scripts in different dirs.
+ Do not use alloca on the Cray.
+ Provide strspn and strcspn if string.h does not exist.
+ Define O_CREAT and O_EXCL from FCREAT and FEXCL if necessary.
+ Remove gzip.doc in make realclean.
+ Fixed many typos. (Corrections to my English are welcome.)
+ Put "make manext=l install" at the correct place in INSTALL.
+ Fix incorrect examples in INSTALL and give more examples.
+ Include zdiff.1 for install and uninstall.
+ Allows complex PAGER variable in zmore (e.g.: PAGER="col -x | more")
+ Avoid warning on unused indfound in getopt.c.
+ Cast memset arg to void* (required by some buggy compilers).
+ Include sys/types.h before dirent.h in acgeneral.m4.
+ Fix acgeneral.m4 AC_COMPILE_CHECK to avoid warnings.
+ Don't use alloca.c with gcc. (One NeXT user did not have alloca.h).
+ Change all error messages according to GNU standards.
+ Restore time stamp only if off by more than one minute.
+ Allow installation of zcat as gzcat.
+ Suppress help message and send compressed data to the terminal when
+ gzip is invoked without parameters and without redirection.
+ (Explicit request from Noah Friedman.)
+ Add compile option GNU_STANDARD to respect the GNU coding standards:
+ with -DGNU_STANDARD, behave as gzip even if invoked under the
+ name gunzip. (Complaints to /dev/null or the FSF, not to me!)
+
+Fri Mar 10 13:27:18 1993 Jean-loup Gailly (jloup@chorus.fr)
+
+ * version 1.0.6
+ Let gzexe detect executables that are already gzexe'd.
+ Don't try restoring record format on VMS (the simple 1.0.5 code
+ worked correctly only on fixed-512 files). Suppress text_mode.
+ Added asm version for 68000 in amiga/match.a.
+ Use asm version for Atari TT.
+ Fix "make clean" in vms/Makefile.vms.
+ For OS/2, assume HPFS by default, add flag OS2FAT if necessary.
+ Fixed some bugs in zdiff and define zcmp as a link to zdiff.
+ Added zdiff.1
+ Remove configure hack for NeXT; add general fix to autoconf instead
+ Do not strip a ".z" extension if this results in an empty name.
+ Avoid array overflow in get_prefix() for extensions > 10 chars.
+ Accept either q or e to quit zmore.
+ In zmore, try restoring tty mode in all cases.
+ Use Motorola style for match.S on the NeXT.
+ configure.in: unsetenv *hangs* with the Siemens csh...
+ Update vms/gzip.hlp.
+
+Thu Mar 4 14:13:34 1993 Jean-loup Gailly (jloup@chorus.fr)
+
+ * version 1.0.5
+ For VMS, restore the file type for variable record format, otherwise
+ extract in fixed length format (not perfect, but better than
+ forcing all files to be in stream_LF format).
+ Use "-z" suffix for VMS.
+ Use only .z, .*-z, .tgz, .taz as valid gzip extensions; update
+ zforce accordingly.
+ Allow a version number in input file names for VMS.
+ Added sample program zread.c.
+ Fix "make check" for some implementations of /bin/sh.
+ Don't rely on stat() for filenames with extension > 3 chars
+ on MSDOS, OS2 and Atari.
+ Garbage collect files in /tmp created by gzexe.
+ Quote $opt in znew.
+ Use TOUCH env variable in znew if it exists.
+ Better error message for gunzip on empty or truncated file.
+ Allow prototypes in getopt.h when __STDC__ defined but 0.
+ Added "make clean" in vms/Makefile.vms.
+ Removed -g from default CFLAGS (with Noah's permission!)
+ Avoid too many HAVE_xxx_H for most systems; use common defaults.
+ Moved default Atari flags into tailor.h for consistency.
+ Use memzero() to clear the hash table.
+ Update vms/gzip.hlp to reflect the VMS behavior.
+ Fix OS_CODE (to fit in a byte).
+ Add utime.h for the Amiga.
+ Add gcc support for the Amiga.
+ Work around incorrect dirent.h for NeXT 2.0.
+ Added Makefile entry for Coherent.
+
+Fri Feb 22 11:20:49 1993 Jean-loup Gailly (jloup@chorus.fr)
+
+ * version 1.0.4
+ Added optimized asm version for 68020.
+ Add support for DJGPP.
+ Add support for the Atari ST.
+ Added zforce to rename gzip'ed files with truncated names.
+ Do not install with name uncompress (some systems rely on the
+ absence of any check in the old uncompress).
+ Added missing function (fcfree) in msdos/tailor.c
+ Let gunzip handle .tgz files, and let gzip skip them.
+ Added 'stty min 1' in zmore for SysV and fixed trap code.
+ Suppress .PHONY in Makefile.in, which breaks old makes.
+ Added documentation about pcat and unpack in INSTALL.
+ Add cast to getenv for systems without stdlib.h.
+ Use VAXC instead of VMS to avoid confusion for gcc.
+ Add -K to znew.1.
+ Add gzexe.1.
+ Try preserving file permissions in gzexe.
+ Added -d option for gzexe.
+ Guard against spaces in file names in gzexe.
+ Use CMP env. variable in zcmp.
+ Return a warning exit status for gzip of file with .z suffix.
+ Suppress usage of d_ino which is not portable to all systems.
+ Use #ifdef instead of #if for consistency.
+ For VMS, use "cc util.c" instead of "cc util" (pb with logical names)
+ Added utime() for Amiga.
+ Renamed gzcat.1 as zcat.1.
+ Include fcntl.h for Amiga (for read and write).
+ For VMS, add definition of symbols and links in the makefiles.
+ Give a VMS look to vms/gzip.hlp.
+ Save the original name only when necessary.
+ Add a mode parameter for open in read mode (required by VMS).
+ For VMS, remove the version suffix from the original name.
+ Accept both / and \ as path separator for MSDOS.
+ Let gunzip extract stored .zip files correctly.
+ Added warning about VFC format in vms/gzip.hlp.
+ In znew, skip a bad file but process the others.
+ Cleanup tailor.h.
+ Use GZIP_OPT for VMS to avoid conflict with program name.
+ Added description of GZIP variable in gzip.texi.
+
+Thu Feb 11 17:21:32 1993 Jean-loup Gailly (jloup@chorus.fr)
+
+ * version 1.0.3
+ Add -K option for znew to keep old .Z files if smaller.
+ Add -q option (quiet) to cancel -v in GZIP env variable.
+ For Turbo C, normalize pointers before freeing them.
+ Add more safety checks in add_envopt().
+ Add do_exit() for uniform exit path (always free memory).
+ Reduce MAX_PATH_LEN for MSDOS.
+ Include sys/types.h before signal.h
+ Avoid strdup, the NeXT does not have it.
+ Made gzexe safer on systems with filename limitation to 14 chars.
+
+Fri Feb 10 09:45:49 1993 Jean-loup Gailly (jloup@chorus.fr)
+
+ * version 1.0.2
+ Added env variable GZIP for default options.
+ Added support for the Amiga.
+ znew now keeps the old .Z if it is smaller than the .z file.
+ Added gzexe to compress rarely used executables.
+ Reduce memory usage when using static allocation (no DYN_ALLOC).
+ Better separation of warning and error return codes.
+ Fix unlzw.c to make DYN_ALLOC and MAXSEG_64K independent options.
+ Allow INBUFSIZ to be >= 32K in unlzw (don't use sign of rsize)
+ Generate tar file in old format to avoid problems with old systems.
+ Preserve time stamp in znew -P if touch -r works.
+ Use ${PAGER-more} instead of ${PAGER:-more} in zmore.
+ Do not use unsigned instead of mode_t.
+ Better error message for trailing garbage in .z file; ignore this
+ garbage on VMS.
+ In zmore, use icanon instead of -cbreak on SYSV.
+ Add trap handler in zmore.
+ Use char* instead of void* for non STDC compilers.
+ Added makefile entry for Xenix on 286.
+ Return an error code when existing file was not overwritten.
+ Use prototype of lzw.h for lzw.c.
+ Fix znew with -P option alone.
+ Give warning for directories even without -v.
+ Close output file before unlink() in case of error.
+ Suppress all target dependent ifdef from the portable files.
+ Free all dynamically allocated variables upon exit.
+
+Thu Feb 4 18:23:56 1993 Jean-loup Gailly (jloup@chorus.fr)
+
+ * version 1.0.1
+ Fixed some trivial errors in msdos/Makefile.bor
+
+Thu Feb 4 10:00:59 1993 Jean-loup Gailly (jloup@chorus.fr)
+
+ * version 1.0
+ gzip now runs on Vax/VMS (Amiga support will come in next version).
+ Do not overwrite files without -f when using /bin/sh.
+ Support the test option -t for compressed (.Z) files.
+ Flush output for bad compressed files. Add warning in README.
+ Added makefiles for MSDOS.
+ Don't rely on presence of csh in configure
+ Added gunzip.1 and gzcat.1.
+ Updated znew.1.
+ Check reserved flags in unlzw().
+ Return dummy value in main to avoid lint warning.
+ Define OF in lzw.h for lint.
+ Allow both "znew -v -t" and "znew -vt".
+ Don't overwrite the output file name for multiple parts.
+ Echo just a warning if configure is out of date.
+ Use ; instead of , in trees.c (confuses the SAS Amiga compiler).
+ In INSTALL, document "DEFS='-DM_XENIX' ./configure".
+ Use OTHER_PATH_SEP for more portability (DOS, OS2, VMS, AMIGA).
+ Make all directories world writable for broken versions of tar.
+ Use gzip -cd instead of zcat in zmore, zcmp, zdiff.
+ Don't use GNU tar for distributions, some systems can't untar.
+ Do not exit() for gzip --version.
+
+Mon Jan 26 10:26:42 1993 Jean-loup Gailly (jloup@chorus.fr)
+
+ * Beta version 0.8.2
+ Avoid 'far' declarations for MSDOS.
+ Use test -f instead of test -x in configure.in (for Ultrix)
+ Add empty else part to if in Makefile.in for broken shells.
+ Use NO_UNDERLINE instead of UNDERLINE (pb with Linux cpp)
+ Accept continuation files with -ff (for damage recovery)
+ Small patch to Makefile.os2
+ Use memzero instead of bzero to avoid potential conflicts
+ Document restriction on extraction of zip files.
+ Fix quoting in ACL_HAVE_SHELL_HACK.
+ Do not check file size on MSDOS because of bug in DIET.
+ Allow zcat on a file with multiple links.
+ Add fix in inflate.c for compatibility with pkzip 2.04c.
+ Release gzip in tar.z and tar format. (No tar.Z).
+
+Fri Jan 22 10:04:13 1993 Jean-loup Gailly (jloup@chorus.fr)
+
+ * Beta version 0.8.1
+ Fixed Makefile.os2
+ Fixed #if directives that TurboC does not like.
+ Don't rely on uncompress in znew, use gzip -d.
+ Add the pipe option -P in znew.
+ Add some more ideas in TODO.
+ Support both NDIR and SYSNDIR.
+
+Sat Jan 21 15:46:38 1993 Jean-loup Gailly (jloup@chorus.fr)
+
+ * Beta version 0.8
+ Support unpack.
+ Check for _match.o in configure.in in addition to return status.
+ Include <sys/types.h> in zip.c
+ Define local variables and functions as local.
+ Accept more alternative names for the program (pcat, gzcat, ...).
+ Accept .exe as well as .EXE.
+ Uncompress files with multiple links only with -f.
+ Better error message for gunzip of non-existent file.z.
+ Fix the entry for /etc/magic in INSTALL.
+ Use AC_HAVE_HEADERS uniformly instead of special macros.
+ Install the man pages as .1 by default instead of .l.
+ Document crypt++.el in README.
+ Fix for unlzw() on 16-bit machines (bitmask must be unsigned).
+ Complain if input and output files are identical.
+ Create a correct output name for files of exactly 13 chars.
+ Do not overwrite CPP if set
+ Check for i386 before trying to assemble match.s
+ Check for underline in external name before assembling
+ Add patch for tar 1.11.1.
+
+Mon Jan 5 10:16:24 1993 Jean-loup Gailly (jloup@chorus.fr)
+
+ * Beta version 0.7
+ Use "make check" instead of "make test".
+ Do not rely on dirname in znew.
+ Keep time stamp and pass options to gzip in znew.
+ Rename .l files back to .1 to avoid conflict with lex
+ Do not create .z.z files with gzip -r.
+ Use nice_match in match.asm
+ Unroll loops in deflate.c
+ Do not attempt matches beyond the window end
+ Allow again gunzip .zip files (was working in 0.5)
+ Allow again compilation with TurboC 2.0 (was working in 0.4)
+
+Tue Dec 30 20:00:19 1992 Jean-loup Gailly (jloup@chorus.fr)
+
+ * Beta version 0.6
+ The .z extension is used by pack, not compact (README, gzip.1)
+ Accept gzcat in addition to zcat.
+ Use PAGER in zmore if defined.
+ Man pages for /usr/local/man/manl should have extension .l.
+ Don't redefine bzero on the NeXT
+ Allow incomplete Huffman table if there is only one code.
+ Don't lookahead more than 7 bits (caused premature EOF).
+ Added "make test" to check for compiler bugs.
+ Don't rely on `i386`; try to assemble directly
+ Change magic header to avoid conflict with freeze 1.x.
+ Added entry for /etc/magic in INSTALL.
+ Do not destroy an input .zip file with more than one member.
+ Display "untested" instead of "OK" for gzip -t foo.Z
+ With -t, skip stdin in .Z format
+ Allow multiple compressed members in an input file.
+ Ignore a zero time stamp.
+ Made znew safer.
+
+Tue Dec 29 10:00:19 1992 Noah Friedman (friedman@gnu.ai.mit.edu)
+
+ Added test for #!/bin/sh in configure.in.
+ Fix some references to $srcdir in Makefile.in
+
+Mon Dec 21 17:33:35 1992 Jean-Loup Gailly (jloup@chorus.fr)
+
+ * Beta version 0.5
+ Put RCS ids in all files.
+ Added znew to recompress old .Z files with gzip.
+ Avoid "already .z suffix" messages for -r and no -v.
+ Put back check for d_ino in treat_dir().
+ Use HAVE_STRING_H instead of USG.
+ Added os2/Makefile.os2
+ Use SYSUTIME on OS/2.
+ Info dir is $(prefix)/info, not $(prefix)/lib/info.
+ Support long options, added getopt and alloca
+ Support -V and -t
+ Reorder configure.in according to suggestions in autoconf.info
+ Allow links when not removing original file
+ Allow either .z or .Z in zdiff
+
+Wed Nov 25 11:40:04 1992 Jean-loup Gailly (jloup@chorus.fr)
+
+ * Beta version 0.4.1
+ Save only the original base name, don't include any directory prefix.
+ Don't use HAVE_LONG_FILE_NAMES (support multiple file system types).
+ Fix declaration of abort_gzip in gzip.h.
+ Include unistd.h when it exists to avoid warnings with gcc -Wall.
+
+Mon Nov 23 12:39:01 1992 Jean-loup Gailly (jloup@chorus.fr)
+
+ * Beta version 0.4
+ Lots of cleanup
+ Use autoconf generated 'configure'
+ Fixed the NO_MULTIPLE_DOTS code
+ Fixed the save_orig_name code
+ Support for MSDOS (Turbo C)
+
+Thu Nov 19 15:18:22 1992 Jean-loup Gailly (jloup@chorus.fr)
+
+ * Beta version 0.3
+ Added auto configuration. Just type "make" now.
+ Don't overwrite compress by default in "make install". Use
+ "make install_compress" to overwrite.
+ Add match.s for 386 boxes.
+ Added documentation in texinfo format.
+ Provide help for "gunzip" invoked without redirected input.
+ Save original file name when necessary.
+ Support OS/2 (Kai-Uwe Rommel).
+
+Tue Nov 17 14:32:53 1992 Jean-loup Gailly (jloup@chorus.fr)
+
+ * Alpha version 0.2.4
+ Return 0 in get_istat() when ok (caused error with zcat).
+ Don't update crc on compressed data (caused crc errors on
+ large files).
+
+Fri Nov 13 15:04:12 1992 Jean-loup Gailly (jloup@chorus.fr)
+
+ * Alpha version 0.2.3
+ Initialize rsize in unlzw.c
+ Initialize ofd for zcat.
+ Do not use volatile ifname as argument of treat_dir.
+ Add -1 to -9 in gzip.1.
+
+Sat Oct 31 18:30:00 1992 Jean-loup Gailly (jloup@chorus.fr)
+
+ * Alpha version 0.2.2.
+ Fix error messages.
+ Accept gunzip on zip files.
+
+Sat Oct 31 17:15:00 1992 Jean-loup Gailly (jloup@chorus.fr)
+
+ * Alpha version 0.2.1
+ Use ctype.h in util.c (problem on SysV).
+ Create BINDIR if it does not exist.
+ Use cc by default.
+ Added zcmp, zmore, zdiff.
+ Fixed the man page gzip.1.
+
+Sat Oct 31 17:00:00 1992 Jean-loup Gailly (jloup@chorus.fr)
+
+ * Alpha version 0.2
+ Fixed compilation problems with gcc
+
+Sat Oct 31 12:46:00 1992 Jean-loup Gailly (jloup@chorus.fr)
+
+ * Alpha version 0.1 released (under time pressure), so it's not
+ much tested, sorry.
+
diff --git a/gnu/usr.bin/gzip/Makefile b/gnu/usr.bin/gzip/Makefile
new file mode 100644
index 0000000..736698d
--- /dev/null
+++ b/gnu/usr.bin/gzip/Makefile
@@ -0,0 +1,31 @@
+# @(#)Makefile 5.3 (Berkeley) 5/12/90
+
+PROG= gzip
+SRCS= gzip.c zip.c deflate.c trees.c bits.c unzip.c inflate.c util.c \
+ crypt.c lzw.c unlzw.c unlzh.c unpack.c getopt.c match.S
+MAN1= gzexe.1 gzip.1 zdiff.1 zforce.1 zmore.1 znew.1 zgrep.1
+CFLAGS+=-DASMV -DSTDC_HEADERS=1 -DHAVE_UNISTD_H=1 -DDIRENT=1
+MLINKS= gzip.1 gunzip.1 gzip.1 zcat.1 gzip.1 gzcat.1
+MLINKS+= zgrep.1 zfgrep.1 zgrep.1 zegrep.1
+MLINKS+= zdiff.1 zcmp.1
+LINKS+= ${BINDIR}/gzip ${BINDIR}/gunzip
+LINKS+= ${BINDIR}/gzip ${BINDIR}/gzcat
+LINKS+= ${BINDIR}/gzip ${BINDIR}/zcat
+LINKS+= ${BINDIR}/zgrep ${BINDIR}/zegrep
+LINKS+= ${BINDIR}/zgrep ${BINDIR}/zfgrep
+LINKS+= ${BINDIR}/zdiff ${BINDIR}/zcmp
+NOSHARED=yes
+
+beforeinstall:
+ ${INSTALL} -c -o ${BINOWN} -g ${BINGRP} -m ${BINMODE} \
+ ${.CURDIR}/zforce ${.CURDIR}/gzexe ${.CURDIR}/znew \
+ ${.CURDIR}/zmore ${.CURDIR}/zdiff ${.CURDIR}/zgrep \
+ ${DESTDIR}${BINDIR}
+
+match.o: ${.CURDIR}/match.S
+ $(CPP) ${.CURDIR}/match.S >_match.s
+ $(CC) -c _match.s
+ mv _match.o match.o
+ rm -f _match.s
+
+.include <bsd.prog.mk>
diff --git a/gnu/usr.bin/gzip/NEWS b/gnu/usr.bin/gzip/NEWS
new file mode 100644
index 0000000..ef5f833
--- /dev/null
+++ b/gnu/usr.bin/gzip/NEWS
@@ -0,0 +1,221 @@
+Current Version: 1.2.4.
+See the file ChangeLog for the details of all changes.
+
+Major changes from 1.2.3 to 1.2.4
+* By default, do not restore file name and timestamp from those saved
+ inside the .gz file (behave as 'compress'). Added the --name option
+ to force name and timestamp restoration.
+* Accept - as synonym for stdin.
+* Use manlinks=so or ln to support either hard links or .so in man pages
+* Accept foo.gz~ in zdiff.
+* Added support for Windows NT
+* Handle ENAMETOOLONG for strict Posix systems
+* Use --recursive instead of --recurse to comply with Webster and
+ the GNU stdandard.
+* Allow installation of shell scripts with a g prefix: make G=g install
+* Install by default zcat as gzcat if gzcat already exists in path.
+* Let zmore behave as more when invoked without parameters (give help)
+* Let gzip --list reject files not in gzip format even with --force.
+* Don't complain about non gzip files for options -rt or -rl.
+* Added advice in INSTALL for several systems.
+
+Major changes from 1.2.2 to 1.2.3
+* Don't display the output name when decompressing except with --verbose.
+* Remove usage of alloca in getopt.c and all makefiles.
+* Added the zfile shell script in subdirectory sample.
+* Moved the list of compiler bugs from README to INSTALL.
+* Added vms/Readme.vms.
+
+Major changes from 1.2.1 to 1.2.2
+* Fix a compilation error on Sun with cc (worked with gcc).
+
+Major changes from 1.2 to 1.2.1
+* Let zmore act as more if the data is not gzipped.
+* made gzexe more secure (don't rely on PATH).
+* By default, display output name only when the name was actually truncated.
+
+Major changes from 1.1.2 to 1.2
+* Added the --list option to display the file characteristics.
+* Added the --no-name option: do not save or restore original filename
+ Save the original name by default.
+* Allow gunzip --suffix "" to attempt decompression on any file
+ regardless of its extension if an original name is present.
+* Add support for the SCO compress -H format.
+* gzip --fast now compresses faster (speed close to that of compress)
+ with degraded compression ratio (but still better than compress).
+ Default level changed to -6 (acts exactly as previous level -5) to
+ be a better indication of its placement in the speed/ratio range.
+* Use smart name truncation: 123456789012.c -> 123456789.c.gz
+ instead of 12345678901.gz
+* With --force, let zcat pass non gzip'ed data unchanged (zcat == cat)
+* Added the zgrep shell script.
+* Made sub.c useful for 16 bit sound, 24 bit images, etc..
+* Supress warnings about suffix for gunzip -r, except with --verbose.
+* On MSDOS, use .gz extension when possible (files without extension)
+* Moved the sample programs to a subdirectory sample.
+* Added a "Special targets" section in INSTALL.
+
+Major changes from 1.1.1 to 1.1.2.
+* Fix serious bug for VMS (-gz not removed when decompressing).
+* Allow suffix other than .gz in znew.
+* Do not display compression ratio when decompressing stdin.
+* In zmore.in, work around brain damaged stty -g (Ultrix).
+* Display a correct compression ratio for .Z files.
+* Added .z to .gz renaming script in INTALL.
+* Allow setting CFLAGS in configure.
+
+Major changes from 1.1 to 1.1.1.
+* Fix serious bug in vms.c (affects Vax/VMS only).
+* Added --ascii option.
+* Add workaround in configure.in for Ultrix (quote eval argument)
+
+Major changes from 1.0.7 to 1.1.
+* Use .gz suffix by default, add --suffix option.
+* Let gunzip accept a "_z" suffix (used by one 'compress' on Vax/VMS).
+* Quit when reading garbage from stdin instead of reporting an error.
+* Added makefile for VAX/MMS and support for wildcards on VMS.
+* Added support for MSC under OS/2.
+* Added support for Prime/PRIMOS.
+* Display compression ratio also when decompressing (with --verbose).
+* Quit after --version (GNU standard)
+* Use --force to bypass isatty() check
+* Continue processing other files in case of recoverable error.
+* Added comparison of zip and gzip in the readme file.
+* Added small sample programs (ztouch, sub, add)
+* Use less memory when compiled with -DSMALL_MEM (for MSDOS).
+* Remove the "off by more than one minute" time stamp kludge
+
+Major changes from 1.0.6 to 1.0.7.
+* Allow zmore to read from standard input (like more).
+* Support the 68000 (Atari ST) in match.S.
+* Retry partial writes (required on Linux when gzip is suspended in a pipe).
+* Allow full pathnames and renamings in gzexe.
+* Don't let gzexe compress setuid executables or gzip itself.
+* Added vms/Makefile.gcc for gcc on the Vax.
+* Allow installation of binaries and shell scripts in different dirs.
+* Allows complex PAGER variable in zmore (e.g.: PAGER="col -x | more")
+* Allow installation of zcat as gzcat.
+* Several small changes for portability to old or weird systems.
+* Suppress help message and send compressed data to the terminal when
+ gzip is invoked without parameters and without redirection.
+* Add compile option GNU_STANDARD to respect the GNU coding standards:
+ with -DGNU_STANDARD, behave as gzip even if invoked under the name gunzip.
+(I don't like the last two changes, which were requested by the FSF.)
+
+Major changes from 1.0.5 to 1.0.6.
+* Let gzexe detect executables that are already gzexe'd.
+* Keep file attributes in znew and gzexe if cpmod is available.
+* Don't try restoring record format on VMS (1.0.5 did not work correctly)
+* Added asm version for 68000 in amiga/match.a.
+ Use asm version for Atari TT and NeXT.
+* For OS/2, assume HPFS by default, add flag OS2FAT if necessary.
+* Fixed some bugs in zdiff and define zcmp as a link to zdiff.
+
+
+Major changes from 1.0.4 to 1.0.5.
+* For VMS, restore the file type for variable record format, otherwise
+ extract in fixed length format (not perfect, but better than
+ forcing all files to be in stream_LF format).
+* For VMS, use "-z" default suffix and accept a version number in file names.
+* For Unix, allow compression of files with name ending in 'z'. Use only
+ .z, .*-z, .tgz, .taz as valid gzip extensions. In the last two cases,
+ extract to .tar by default.
+* On some versions of MSDOS, files with a 3 character extension could not
+ be compressed.
+* Garbage collect files in /tmp created by gzexe.
+* Fix the 'OS code' byte in the gzip header.
+* For the Amiga, add the missing utime.h and add support for gcc.
+
+
+Major changes from 1.0.3 to 1.0.4.
+* Added optimized asm version for 68020.
+* Add support for DJGPP.
+
+* Add support for the Atari ST.
+* Added zforce to rename gzip'ed files with truncated names.
+* Do not install with name uncompress (some systems rely on the
+ absence of any check in the old uncompress).
+* Added missing function (fcfree) in msdos/tailor.c
+* Let gunzip handle .tgz files, and let gzip skip them.
+* Added -d option (decompress) for gzexe and try preserving file permissions.
+* Suppress all warnings with -q.
+* Use GZIP_OPT for VMS to avoid conflict with program name.
+* ... and many other small changes (see ChangeLog)
+
+
+Major changes from 1.0.2 to 1.0.3
+* Added -K option for znew to keep old .Z files if smaller
+* Added -q option (quiet) to cancel -v in GZIP env variable.
+* Made gzexe safer on systems with filename limitation to 14 chars.
+* Fixed bugs in handling of GZIP env variable and incorrect free with Turbo C.
+
+
+Major changes from 1.0.1 to 1.0.2
+* Added env variable GZIP for default options. Example:
+ for sh: GZIP="-8 -v"; export GZIP
+ for csh: setenv GZIP "-8 -v"
+* Added support for the Amiga.
+* znew now keeps the old .Z if it is smaller than the .z file.
+ This can happen for some large and very redundant files.
+* Do not complain about trailing garbage for record oriented IO (Vax/VMS).
+ This implies however that multi-part gzip files are not supported
+ on such systems.
+* Added gzexe to compress rarely used executables.
+* Reduce memory usage (required for MSDOS and useful on all systems).
+* Preserve time stamp in znew -P (pipe option) if touch -r works.
+
+
+Major changes from 1.0 to 1.0.1
+* fix trivial errors in the Borland makefile (msdos/Makefile.bor)
+
+
+Major changes from 0.8.2 to 1.0
+* gzip now runs on Vax/VMS
+* gzip will not not overwrite files without -f when using /bin/sh in
+ background.
+* Support the test option -t for compressed (.Z) files.
+ Allow some data recovery for bad .Z files.
+* Added makefiles for MSDOS (Only tested for MSC, not Borland).
+* still more changes to configure for several systems
+
+
+Major changes from 0.8.1 to 0.8.2:
+* yet more changes to configure for Linux and other systems
+* Allow zcat on a file with multiple links.
+
+
+Major changes from 0.8 to 0.8.1:
+* znew has now a pipe option -P to reduce the disk space requirements,
+ but this option does not preserve timestamps.
+* Fixed some #if directives for compilation with TurboC.
+
+
+Major changes from 0.7 to 0.8:
+* gzip can now extract .z files created by 'pack'.
+* configure should no longer believe that every machine is a 386
+* Fix the entry for /etc/magic in INSTALL.
+* Add patch for GNU tar 1.11.1 and a pointer to crypt++.el
+* Uncompress files with multiple links only with -f.
+* Fix for uncompress of .Z files on 16-bit machines
+* Create a correct output name for file names of exactly N-1 chars when
+ the system has a limit of N chars.
+
+
+Major changes from 0.6 to 0.7:
+* Use "make check" instead of "make test".
+* Keep time stamp and pass options to gzip in znew.
+* Do not create .z.z files with gzip -r.
+* Allow again gunzip .zip files (was working in 0.5)
+* Allow again compilation with TurboC 2.0 (was working in 0.4)
+
+
+Major changes form 0.5 to 0.6:
+* gunzip reported an error when extracting certain .z files. The .z files
+ produced by gzip 0.5 are correct and can be read by gunzip 0.6.
+* gunzip now supports multiple compressed members within a single .z file.
+* Fix the check for i386 in configure.
+* Added "make test" to check for compiler bugs. (gcc -finline-functions
+ is broken at least on the NeXT.)
+* Use environment variable PAGER in zmore if it is defined.
+* Accept gzcat in addition to zcat for people having /usr/bin before
+ /usr/local/bin in their path.
diff --git a/gnu/usr.bin/gzip/README b/gnu/usr.bin/gzip/README
new file mode 100644
index 0000000..fdd7311
--- /dev/null
+++ b/gnu/usr.bin/gzip/README
@@ -0,0 +1,144 @@
+This is the file README for the gzip distribution, version 1.2.4.
+
+gzip (GNU zip) is a compression utility designed to be a replacement
+for 'compress'. Its main advantages over compress are much better
+compression and freedom from patented algorithms. The GNU Project
+uses it as the standard compression program for its system.
+
+gzip currently uses by default the LZ77 algorithm used in zip 1.9 (the
+portable pkzip compatible archiver). The gzip format was however
+designed to accommodate several compression algorithms. See below
+for a comparison of zip and gzip.
+
+gunzip can currently decompress files created by gzip, compress or
+pack. The detection of the input format is automatic. For the
+gzip format, gunzip checks a 32 bit CRC. For pack, gunzip checks the
+uncompressed length. The 'compress' format was not designed to allow
+consistency checks. However gunzip is sometimes able to detect a bad
+.Z file because there is some redundancy in the .Z compression format.
+If you get an error when uncompressing a .Z file, do not assume that
+the .Z file is correct simply because the standard uncompress does not
+complain. This generally means that the standard uncompress does not
+check its input, and happily generates garbage output.
+
+gzip produces files with a .gz extension. Previous versions of gzip
+used the .z extension, which was already used by the 'pack'
+Huffman encoder. gunzip is able to decompress .z files (packed
+or gzip'ed).
+
+Several planned features are not yet supported (see the file TODO).
+See the file NEWS for a summary of changes since 0.5. See the file
+INSTALL for installation instructions. Some answers to frequently
+asked questions are given in the file INSTALL, please read it. (In
+particular, please don't ask me once more for an /etc/magic entry.)
+
+WARNING: on several systems, compiler bugs cause gzip to fail, in
+particular when optimization options are on. See the section "Special
+targets" at the end of the INSTALL file for a list of known problems.
+For all machines, use "make check" to check that gzip was compiled
+correctly. Try compiling gzip without any optimization if you have a
+problem.
+
+Please send all comments and bug reports by electronic mail to:
+ Jean-loup Gailly <jloup@chorus.fr>
+
+or, if this fails, to bug-gnu-utils@prep.ai.mit.edu.
+Bug reports should ideally include:
+
+ * The complete output of "gzip -V" (or the contents of revision.h
+ if you can't get gzip to compile)
+ * The hardware and operating system (try "uname -a")
+ * The compiler used to compile (if it is gcc, use "gcc -v")
+ * A description of the bug behavior
+ * The input to gzip, that triggered the bug
+
+If you send me patches for machines I don't have access to, please test them
+very carefully. gzip is used for backups, it must be extremely reliable.
+
+The package crypt++.el is highly recommended to manipulate gzip'ed
+file from emacs. It recognizes automatically encrypted and compressed
+files when they are first visited or written. It is available via
+anonymous ftp to roebling.poly.edu [128.238.5.31] in /pub/crypt++.el.
+The same directory contains also patches to dired, ange-ftp and info.
+GNU tar 1.11.2 has a -z option to invoke directly gzip, so you don't have to
+patch it. The package ftp.uu.net:/languages/emacs-lisp/misc/jka-compr19.el.Z
+also supports gzip'ed files.
+
+The znew and gzexe shell scripts provided with gzip benefit from
+(but do not require) the cpmod utility to transfer file attributes.
+It is available by anonymous ftp on gatekeeper.dec.com in
+/.0/usenet/comp.sources.unix/volume11/cpmod.Z.
+
+The sample programs zread.c, sub.c and add.c in subdirectory sample
+are provided as examples of useful complements to gzip. Read the
+comments inside each source file. The perl script ztouch is also
+provided as example (not installed by default since it relies on perl).
+
+
+gzip is free software, you can redistribute it and/or modify it under
+the terms of the GNU General Public License, a copy of which is
+provided under the name COPYING. The latest version of gzip are always
+available by ftp in prep.ai.mit.edu:/pub/gnu, or in any of the prep
+mirror sites:
+
+- sources in gzip-*.tar (or .shar or .tar.gz).
+- Solaris 2 executables in sparc-sun-solaris2/gzip-binaries-*.tar
+- MSDOS lha self-extracting exe in gzip-msdos-*.exe. Once extracted,
+ copy gzip.exe to gunzip.exe and zcat.exe, or use "gzip -d" to decompress.
+ gzip386.exe runs much faster but only on 386 and above; it is compiled with
+ djgpp 1.10 available in directory omnigate.clarkson.edu:/pub/msdos/djgpp.
+
+A VMS executable is available in ftp.spc.edu:[.macro32.savesets]gzip-1-*.zip
+(use [.macro32]unzip.exe to extract). A PRIMOS executable is available
+in ftp.lysator.liu.se:/pub/primos/run/gzip.run.
+OS/2 executables (16 and 32 bits versions) are available in
+ftp.tu-muenchen.de:/pub/comp/os/os2/archiver/gz*-[16,32].zip
+
+Some ftp servers can automatically make a tar.Z from a tar file. If
+you are getting gzip for the first time, you can ask for a tar.Z file
+instead of the much larger tar file.
+
+Many thanks to those who provided me with bug reports and feedback.
+See the files THANKS and ChangeLog for more details.
+
+
+ Note about zip vs. gzip:
+
+The name 'gzip' was a very unfortunate choice, because zip and gzip
+are two really different programs, although the actual compression and
+decompression sources were written by the same persons. A different
+name should have been used for gzip, but it is too late to change now.
+
+zip is an archiver: it compresses several files into a single archive
+file. gzip is a simple compressor: each file is compressed separately.
+Both share the same compression and decompression code for the
+'deflate' method. unzip can also decompress old zip archives
+(implode, shrink and reduce methods). gunzip can also decompress files
+created by compress and pack. zip 1.9 and gzip do not support
+compression methods other than deflation. (zip 1.0 supports shrink and
+implode). Better compression methods may be added in future versions
+of gzip. zip will always stick to absolute compatibility with pkzip,
+it is thus constrained by PKWare, which is a commercial company. The
+gzip header format is deliberately different from that of pkzip to
+avoid such a constraint.
+
+On Unix, gzip is mostly useful in combination with tar. GNU tar
+1.11.2 has a -z option to invoke gzip automatically. "tar -z"
+compresses better than zip, since gzip can then take advantage of
+redundancy between distinct files. The drawback is that you must
+scan the whole tar.gz file in order to extract a single file near
+the end; unzip can directly seek to the end of the zip file. There
+is no overhead when you extract the whole archive anyway.
+If a member of a .zip archive is damaged, other files can still
+be recovered. If a .tar.gz file is damaged, files beyond the failure
+point cannot be recovered. (Future versions of gzip will have
+error recovery features.)
+
+gzip and gunzip are distributed as a single program. zip and unzip
+are, for historical reasons, two separate programs, although the
+authors of these two programs work closely together in the info-zip
+team. zip and unzip are not associated with the GNU project.
+The sources are available by ftp in
+
+ oak.oakland.edu:/pub/misc/unix/zip19p1.zip
+ oak.oakland.edu:/pub/misc/unix/unz50p1.tar-z
diff --git a/gnu/usr.bin/gzip/THANKS b/gnu/usr.bin/gzip/THANKS
new file mode 100644
index 0000000..6a545cb
--- /dev/null
+++ b/gnu/usr.bin/gzip/THANKS
@@ -0,0 +1,276 @@
+gzip was written by Jean-loup Gailly <jloup@chorus.fr>, with portions
+written by Mark Adler (inflate.c), Peter Jannesen (unlzw.c) and
+Haruhiko Okumura (unlzh.c). The zip deflate format was defined by Phil Katz.
+Thanks to those who reported problems and suggested various
+improvements. Here is a partial list of them:
+
+Robert Abramovitz bromo@cougar.tandem.com
+Jay Adams jka@ece.cmu.edu
+Mark Adler madler@cco.caltech.edu
+Edwin Allum edwin@csri.toronto.edu
+Joseph Arceneaux jla@gnu.ai.mit.edu
+Tim Auckland tda10@cus.cam.ac.uk
+Ken-ichiro Aoki aoki@madonna.physics.ucla.edu
+David Ascher da@marlowe.cog.brown.edu
+Eric Backus ericb@lsid.hp.com
+Becky A. Badgett badgett@cs.utexas.edu
+Bo Nygaard Bai bai@iesd.auc.dk
+Dave Barber dbarber@apocalypse.bbn.com
+Rene Beaulieu reneb@distri.hydro.qc.ca
+Neal Becker neal@ctd.comsat.com
+Dieter Becker becker@med-in.uni-sb.de
+Nelson H. F. Beebe beebe@geronimo.math.utah.edu
+Jeff Beadles jeff@onion.rain.com
+David J. N. Begley dbegley@st.nepean.uws.edu.au
+Bob Beresh rberesh@rd.hydro.on.ca
+Jim Bernard jbernard@iola.mines.colorado.edu
+Karl Berry karl@cs.umb.edu
+James W. Birdsall jwbirdsa@picarefy.picarefy.com
+Scott Bolte scott@craycos.com
+Wayne E. Bouchard web@paladine.hacks.arizona.edu
+Marc Boucher marc@cam.org
+Ola Brahammar pt90ob@pt.hk-r.se
+Dave Brennan brennan@hal.com
+Alan Brown dogbowl@dogbox.acme.gen.nz
+Michael L. Brown brown@wi.extrel.com
+Rodney Brown rdb@mel.cocam.oz.au
+Bruce bde@runx.oz.au
+Bill Bumgarner bbum@stone.com
+Leila Burrell-Davis leilabd@syma.sussex.ac.uk
+Roger Butenuth butenuth@ira.uka.de
+Jon Cargille jcargill@cs.wisc.edu
+Bud Carlson bud@isle.pegasus.com
+Lim Fung Chai fclim@i1sin.daq.semi.harris.com
+Wes Chalfant wes@kofax.com
+Andrew A. Chernov ache@astral.msk.su
+Paul Close pdc@lunch.wpd.sgi.com
+Jeff Coffler coffler@jac.enet.dec.com
+Will Colley wcc3@occs.cs.oberlin.edu
+Roger Cornelius sherpa!rac@uunet.uu.net
+Kevin Cosgrove kevinc@tekig6.pen.tek.com
+Stephen J Cowley s.j.cowley@amtp.cam.ac.uk
+Ron Cox roncox@indirect.com
+Frank Crawford frank@photon.ansto.gov.au
+James R. Crawford qralston@cislabs.pitt.edu
+Lawrence Crowl crowl@research.cs.orst.edu
+Klaus Dahlenburg kdburg@incoahe.hanse.de
+William E Davidsen davidsen@ariel.crd.ge.com
+John M. DeDourek dedourek@aixive2.cs.unb.ca
+Jeff Deifik jdeifik@isi.edu
+Vince DeMarco vince@whatnxt.cuc.ab.ca
+Michael De La Rue p91152@cplab.physics.edinburgh.ac.uk
+Jeff Delinck delinck@pa621a.inland.com
+John DeRoo deroo@grout.adv.shr.dec.com
+Jim Diamond zsd@axe.drea.dnd.ca
+Stefano Diomedi sd@teculx.tecsiel.it
+Lawrence R. Dodd dodd@roebling.poly.edu
+Matthew Donadio donadio@mxd120.rh.psu.edu
+Andy Dougherty andy@crystal.phys.lafayette.edu
+Darrell Duane dduane@mason1.gmu.edu
+John Eaton jwe@che.utexas.edu
+Will Edgington wedgingt@ptolemy.arc.nasa.gov
+Brian Edmonds edmonds@edmonds.home.cs.ubc.ca
+Paul Eggert eggert@twinsun.com
+Enami enami@sys.ptg.sony.co.jp
+Kristoffer Eriksson ske@pkmab.se
+Daniel Eriksson m91der@bellatrix.tdb.uu.se
+Rik Faith faith@cs.unc.edu
+Larry Fahnoe fahnoe@c1mpls.mn.org
+Cristian Ferretti cfs@poincare.mat.puc.cl
+Karl-Jose Filler pla_jfi@pki-nbg.philips.de
+Valery Fine fine@vxcern.cern.ch
+Bob Fischer bobf@milne.geology.yale.edu
+Per Foreby perf@efd.lth.se
+Alexander Fraser alex@cs.umb.edu
+Noah Friedman friedman@gnu.ai.mit.edu
+Bob Friesenhahn bfriesen@iphase.com
+Gerhard Friesland-Koepke frieslan@rzdspc3.informatik.uni-hamburg.de
+Andy Fyfe andy@scp.caltech.edu
+Geoff geoff@frs.faxon.com
+Arnd Gerns gerns@informatik.uni-hildesheim.de
+Kaveh R. Ghazi ghazi@staccato.rutgers.edu
+Torbjorn Granlund tege@sics.se
+Carl Greco cgreco@parrot.creighton.edu
+Bruno Haible haible@ma2s2.mathematik.uni-karlsruhe.de
+Junio Hamano junio@shadow.twinsun.com
+Harald Hanche-Olsen hanche@ams.sunysb.edu
+Darrel R. Hankerson hankedr@mail.auburn.edu
+Mark Hanning-Lee markhl@romeo.caltech.edu
+Lars Hecking st000002@hrz1.hrz.th-darmstadt.de
+Ruediger Helsch ruediger@ramz.ing.tu-bs.de
+Mark C. Henderson mch@sqwest.wimsey.bc.ca
+Karl Heuer karl@kelp.boston.ma.us
+Jarkko Hietaniemi jhi@dol-guldur.hut.fi
+Thomas Hiller hiller@fzi.de
+Eiji Hirai hirai@cc.swarthmore.edu
+Kjetil Torgrim Homme kjetilho@ifi.uio.no
+Robert D. Houk rdh@sli.com
+Jim Howard jim_howard@mentorg.com
+Preston Hunt gt5708a@prism.gatech.edu
+Shane C Hutchins sch@nymph.msel.unh.edu
+Hutch hutchinson@wrair-emh1.army.mil
+Lester Ingber ingber@alumni.caltech.edu
+Ken Ishii ishii@sni-usa.com
+Per Steinar Iversen iversen@vsfys1.fi.uib.no
+Chris Jacobsen jacobsen@xray1.physics.sunysb.edu
+Michal Jaegermann ntomczak@vm.ucs.ualberta.ca
+Brian Jones brianj@skat.usc.edu
+Denny de Jonge witaddj@dutrex.tudelft.nl
+Arne H. Juul arnej@lise.unit.no
+Dana Jacobsen jacobsd@solar.cor2.epa.gov
+Peter Jannesen peter@ncs.nl
+Brian D. Johnston johnstonb@med.ge.com
+Walter W. Jones wwj@candela.cfr.nist.gov
+Tom Judson judson@scf.usc.edu
+Henry G. Juengst juengst@saph2.physik.uni-bonn.de
+Sarantos Kapidakis sarantos%manteion@ics.forth.gr
+Amir J. Katz amir@matis.ingr.com
+Steve Kelem kelem@castor.xilinx.com
+Steven Kimball kimball@shrew.sanders.lockheed.com
+Randy Kirchhof rkk@posms.aus.tx.us
+Ned Kittlitz kittlitz@seagoon.sw.stratus.com
+Sakai Kiyotaka ksakai@mtl.t.u-tokyo.ac.jp
+Philip C Kizer pckizer@gonzo.tamu.edu
+Pete Klammer pklammer@ouray.denver.colorado.edu
+Fritz Kleemann kleemann@informatik.uni-wuerzburg.dbp.de
+Wilhelm B. Kloke wb@ifado.arb-phys.uni-dortmund.de
+Tom Kloos tk@sequent.com
+Carsten Koch carsten.koch@icem.de
+Winfried Koenig win@in.rhein-main.de
+Mathias Koerber mathias@solomon.technet.sg
+Steph Konigsdorfer s.konigsdorfer@frmy.bull.fr
+Leif Kornstaedt leif@rumtifsl.ruessel.sub.org
+Michael D. Lawler mdlawler@bsu-cs.bsu.edu
+Kevin Layer layer@franz.com
+Howard D. Leadmon howardl@wb3ffv.ampr.org
+Alexander Lehmann alex@hal.rhein-main.de
+Simon Leinen simon@lia.di.epfl.ch
+Burt Leland burt@molecular.com
+Tony Leneis tony@plaza.adp.ds.com
+Hugues Leroy hugues.leroy@irisa.fr
+Marty Leisner leisner@eso.mc.xerox.com
+Charles Levert charles@aramis.comm.polymtl.ca
+Richard Levitte levitte@e.kth.se
+Torbj|rn Lindh toobii@elixir.e.kth.se
+David R. Linn drl@vuse.vanderbilt.edu
+Antonio Lioy cat@athena.polito.it
+Jamie Lokier u90jl@ecs.oxford.ac.uk
+Richard Lloyd R.K.Lloyd@csc.liv.ac.uk
+David J. MacKenzie djm@eng.umd.edu
+John R MacMillan john@chance.gts.org
+Ron Male male@eso.mc.xerox.com
+Don R. Maszle maze@bea.lbl.gov
+Jaye Mathisen osyjm@cs.montana.edu
+Telly Mavroidis mavroidi@acf2.nyu.edu
+Imed Eddine Mbarki mbarki@pacific.cmpe.psu.edu
+Steeve McCauley steeve@pooh.geophys.mcgill.ca
+Tom McConnell tmcconne@sedona.intel.com
+Tod McQuillin mcquill@ccit05.duq.edu
+Tye McQueen tye@spillman.com
+Bernd Melchers melchers@chemie.fu-berlin.de
+Jason Merrill jason@jarthur.claremont.edu
+Dean S. Messing deanm@medulla.labs.tek.com
+M. Mesturino mesturino@cselt.stet.it
+Luke Mewburn zak@rmit.edu.au
+Jim Meyering meyering@cs.utexas.edu
+Dragan Milicic milicic@math.utah.edu
+Frederic Miserey none.fred@applelink.apple.com
+Marcel J.E. Mol marcel@duteca.et.tudelft.nl
+Soren Juul Moller sjm@dde.dk
+Chris Moore moore@src.bae.co.uk
+Dan Mosedale mosedale@genome.stanford.edu
+Helmut Muelner hmuelner@fiicmds04.tu-graz.ac.at
+Urban D Mueller umueller@amiga.physik.unizh.ch
+Ulrich Mueller ulm@vsnhdb.cern.ch
+Timothy Murphy tim@maths.tcd.ie
+Greg Naber greg@squally.halcyon.com
+Jay Nayegandhi jayng@bbiv02.enet.dec.com
+Paul K. Neville II pkn2@idsi.com
+Karl L. Noell noell@informatik.fh-wiesbaden.dbp.de
+Demizu Noritoshi nori-d@is.aist-nara.ac.jp
+Todd Ogasawara todd@protege.pegasus.com
+Helge Oldach helge.oldach@stollmann.de
+Arthur David Olson ado@elsie.nci.nih.gov
+Piet van Oostrum piet@cs.ruu.nl
+Rafael R. Pappalardo rafapa@obelix.cica.es
+Mike Pearlman canuck@masc38.rice.edu
+Yves Perrenoud pyves@nuga.alphanet.ch
+Hal Peterson hrp@pecan.cray.com
+Pascal Petit petit@cadillac.ibp.fr
+Bruno Pillard bp@chorus.fr
+Franc,ois Pinard pinard@iro.umontreal.ca
+Jay Pinkos pinkos@butyng.bu.edu
+Thomas Plass thomas@cogsci.ed.ac.uk
+Mike Polo mikep@cfsmo.honeywell.com
+Francesco Potorti pot@fly.cnuce.cnr.it
+Will Priest bpriest@lobby.ti.com
+David Purves purves@apogee.com
+Andreas Raab ar@nvmr.robin.de
+Eric S. Raymond esr@snark.thyrsus.com
+Klaus Reimann kr@cip.physik.uni-stuttgart.de
+Michael Rendell michael@mercury.cs.mun.ca
+Hal Render render@massive.uccs.edu
+Julian F. Reschke julian@math.uni-muenster.de
+Phil Richards Phil.Richards@prg.oxford.ac.uk
+Roland B Roberts roberts@nsrl31.nsrl.rochester.edu
+Arnold Robbins arnold@cc.gatech.edu
+Kevin Rodgers kevin@rolling-stone.den.mmc.com
+Kai Uwe Rommel rommel@informatik.tu-muenchen.de
+Paul Rubin phr@america.telebit.com
+Wolfgang Rupprecht wolfgang@wsrcc.com
+Jonathan Ryshpan jon@amito.hitachi.com
+Paul A Sand pas@unh.edu
+Tony Sanders sanders@bsdi.com
+Mike Sangrey mike@sojurn.lns.pa.us
+Niimi Satoshi a01309@cfi.waseda.ac.jp
+Marc Schaefer sysadm@alphanet.ch
+Andreas Schwab schwab@lamothe.informatik.uni-dortmund.de
+Eric Schenk schenk@cs.toronto.edu
+Eric P. Scott eps@cs.sfsu.edu
+Olaf Seibert rhialto@mbfys.kun.nl
+Sunando Sen sens@fasecon.econ.nyu.edu
+Harry Shamansky hts@hertz.eng.ohio-state.edu
+Amos Shapira amoss@cs.huji.ac.il
+Rick Sladkey jrs@world.std.com
+Daniel L Smith dls@autodesk.com
+Fred Smith fredex%fcshome@merk.merk.com
+Stephen Soliday soliday@ncat.edu
+Paul Southworth pauls@css.itd.umich.edu
+Rob Spencer robbie@winkle.bhpese.oz.au
+Richard Stallman rms@gnu.ai.mit.edu
+Carsten Steger carsten.steger@informatik.tu-muenchen.de
+David Sundstrom sunds@anon.asic.sc.ti.com
+Ed Sznyter ews@babel.babel.com
+Hideaki Tanabe arctanx@iyeyasu.ynl.t.u-tokyo.ac.jp
+Andrew Telford ajt@peregrin.resmel.bhp.com.au
+Glenn E. Thobe thobe@getunx.info.com
+Kei Thomsen kt@keihh.hanse.de
+Karsten Thygesen karthy@dannug.dk
+Mark Towfiq towfiq@microdyne.com
+Jeff Treece treece@sabbagh.com
+Oliver Trepte oliver@ikaros.fysik4.kth.se
+Stephane Tsacas slt@is21.isoft.fr
+Stephen Tweedie sct@dcs.ed.ac.uk
+John R. Vanderpool fish@daacdev1.stx.com
+Sotiris Vassilopoulos vassilopoulos@virginia.edu
+Pedro A. M. Vazquez vazquez@iqm.unicamp.br
+Arjan de Vet devet@win.tue.nl
+Larry W. Virden lvirden@cas.org
+Vadim V. Vlasov vvlasov@inucres.msk.su
+Eduard Vopicka eduard.vopicka@vse.cs
+Theo Vosse vosse@ruls41.leidenuniv.nl
+Darin Wayrynen darin@pcg.uucp
+Marcel Waldvogel marcel@nice.usergroup.ethz.ch
+Stephen J. Walick steve@nshore.org
+Gray Watson gray@antaire.com
+David Watt dmwatt@smersh.cambridge.ma.us
+Scott Weikart scott@igc.apc.org
+Ivo Welch iwelch@agsm.ucla.edu
+Jochen Wiedmann zrawi01@zmcipdec1.zdv.uni-tuebingen.de
+Gijsb. Wiesenekker wiesenecker@sara.nl
+Wietze van Winden wietze@swi.psy.uva.nl
+Frank Wuebbeling wuebbel@math.uni-muenster.de
+Larry W. Virden lwv26@cas.org
+Bill Wohler wohler@sap-ag.de
+Jamie Zawinski jwz@lucid.com
+Christos Zoulas christos@deshaw.com
diff --git a/gnu/usr.bin/gzip/TODO b/gnu/usr.bin/gzip/TODO
new file mode 100644
index 0000000..865be92
--- /dev/null
+++ b/gnu/usr.bin/gzip/TODO
@@ -0,0 +1,58 @@
+TODO file for gzip.
+
+Some of the planned features include:
+
+- Structure the sources so that the compression and decompression code
+ form a library usable by any program, and write both gzip and zip on
+ top of this library. This would ideally be a reentrant (thread safe)
+ library, but this would degrade performance. In the meantime, you can
+ look at the sample program zread.c.
+
+ The library should have one mode in which compressed data is sent
+ as soon as input is available, instead of waiting for complete
+ blocks. This can be useful for sending compressed data to/from interactive
+ programs.
+
+- Make it convenient to define alternative user interfaces (in
+ particular for windowing environments).
+
+- Support in-memory compression for arbitrarily large amounts of data
+ (zip currently supports in-memory compression only for a single buffer.)
+
+- Map files in memory when possible, this is generally much faster
+ than read/write. (zip currently maps entire files at once, this
+ should be done in chunks to reduce memory usage.)
+
+- Add a super-fast compression method, suitable for implementing
+ file systems with transparent compression. One problem is that the
+ best candidate (lzrw1) is patented twice (Waterworth 4,701,745
+ and Gibson & Graybill 5,049,881). The lzrw series of algorithms
+ are available by ftp in ftp.adelaide.edu.au:/pub/compression/lzrw*.
+
+- Add a super-tight (but slow) compression method, suitable for long
+ term archives. One problem is that the best versions of arithmetic
+ coding are patented (4,286,256 4,295,125 4,463,342 4,467,317
+ 4,633,490 4,652,856 4,891,643 4,905,297 4,935,882 4,973,961
+ 5,023,611 5,025,258).
+
+ Note: I will introduce new compression methods only if they are
+ significantly better in either speed or compression ratio than the
+ existing method(s). So the total number of different methods should
+ reasonably not exceed 3. (The current 9 compression levels are just
+ tuning parameters for a single method, deflation.)
+
+- Add optional error correction. One problem is that the current version
+ of ecc cannot recover from inserted or missing bytes. It would be
+ nice to recover from the most common error (transfer of a binary
+ file in ascii mode).
+
+- Add a block size (-b) option to improve error recovery in case of
+ failure of a complete sector. Each block could be extracted
+ independently, but this reduces the compression ratio.
+
+- Use a larger window size to deal with some large redundant files that
+ 'compress' currently handles better than gzip.
+
+- Implement the -e (encrypt) option.
+
+Send comments to Jean-loup Gailly <jloup@chorus.fr>.
diff --git a/gnu/usr.bin/gzip/algorithm.doc b/gnu/usr.bin/gzip/algorithm.doc
new file mode 100644
index 0000000..24f7619
--- /dev/null
+++ b/gnu/usr.bin/gzip/algorithm.doc
@@ -0,0 +1,164 @@
+1. Algorithm
+
+The deflation algorithm used by zip and gzip is a variation of LZ77
+(Lempel-Ziv 1977, see reference below). It finds duplicated strings in
+the input data. The second occurrence of a string is replaced by a
+pointer to the previous string, in the form of a pair (distance,
+length). Distances are limited to 32K bytes, and lengths are limited
+to 258 bytes. When a string does not occur anywhere in the previous
+32K bytes, it is emitted as a sequence of literal bytes. (In this
+description, 'string' must be taken as an arbitrary sequence of bytes,
+and is not restricted to printable characters.)
+
+Literals or match lengths are compressed with one Huffman tree, and
+match distances are compressed with another tree. The trees are stored
+in a compact form at the start of each block. The blocks can have any
+size (except that the compressed data for one block must fit in
+available memory). A block is terminated when zip determines that it
+would be useful to start another block with fresh trees. (This is
+somewhat similar to compress.)
+
+Duplicated strings are found using a hash table. All input strings of
+length 3 are inserted in the hash table. A hash index is computed for
+the next 3 bytes. If the hash chain for this index is not empty, all
+strings in the chain are compared with the current input string, and
+the longest match is selected.
+
+The hash chains are searched starting with the most recent strings, to
+favor small distances and thus take advantage of the Huffman encoding.
+The hash chains are singly linked. There are no deletions from the
+hash chains, the algorithm simply discards matches that are too old.
+
+To avoid a worst-case situation, very long hash chains are arbitrarily
+truncated at a certain length, determined by a runtime option (zip -1
+to -9). So zip does not always find the longest possible match but
+generally finds a match which is long enough.
+
+zip also defers the selection of matches with a lazy evaluation
+mechanism. After a match of length N has been found, zip searches for a
+longer match at the next input byte. If a longer match is found, the
+previous match is truncated to a length of one (thus producing a single
+literal byte) and the longer match is emitted afterwards. Otherwise,
+the original match is kept, and the next match search is attempted only
+N steps later.
+
+The lazy match evaluation is also subject to a runtime parameter. If
+the current match is long enough, zip reduces the search for a longer
+match, thus speeding up the whole process. If compression ratio is more
+important than speed, zip attempts a complete second search even if
+the first match is already long enough.
+
+The lazy match evaluation is no performed for the fastest compression
+modes (speed options -1 to -3). For these fast modes, new strings
+are inserted in the hash table only when no match was found, or
+when the match is not too long. This degrades the compression ratio
+but saves time since there are both fewer insertions and fewer searches.
+
+
+2. gzip file format
+
+The pkzip format imposes a lot of overhead in various headers, which
+are useful for an archiver but not necessary when only one file is
+compressed. gzip uses a much simpler structure. Numbers are in little
+endian format, and bit 0 is the least significant bit.
+A gzip file is a sequence of compressed members. Each member has the
+following structure:
+
+2 bytes magic header 0x1f, 0x8b (\037 \213)
+1 byte compression method (0..7 reserved, 8 = deflate)
+1 byte flags
+ bit 0 set: file probably ascii text
+ bit 1 set: continuation of multi-part gzip file
+ bit 2 set: extra field present
+ bit 3 set: original file name present
+ bit 4 set: file comment present
+ bit 5 set: file is encrypted
+ bit 6,7: reserved
+4 bytes file modification time in Unix format
+1 byte extra flags (depend on compression method)
+1 byte operating system on which compression took place
+
+2 bytes optional part number (second part=1)
+2 bytes optional extra field length
+? bytes optional extra field
+? bytes optional original file name, zero terminated
+? bytes optional file comment, zero terminated
+12 bytes optional encryption header
+? bytes compressed data
+4 bytes crc32
+4 bytes uncompressed input size modulo 2^32
+
+The format was designed to allow single pass compression without any
+backwards seek, and without a priori knowledge of the uncompressed
+input size or the available size on the output media. If input does
+not come from a regular disk file, the file modification time is set
+to the time at which compression started.
+
+The time stamp is useful mainly when one gzip file is transferred over
+a network. In this case it would not help to keep ownership
+attributes. In the local case, the ownership attributes are preserved
+by gzip when compressing/decompressing the file. A time stamp of zero
+is ignored.
+
+Bit 0 in the flags is only an optional indication, which can be set by
+a small lookahead in the input data. In case of doubt, the flag is
+cleared indicating binary data. For systems which have different
+file formats for ascii text and binary data, the decompressor can
+use the flag to choose the appropriate format.
+
+The extra field, if present, must consist of one or more subfields,
+each with the following format:
+
+ subfield id : 2 bytes
+ subfield size : 2 bytes (little-endian format)
+ subfield data
+
+The subfield id can consist of two letters with some mnemonic value.
+Please send any such id to jloup@chorus.fr. Ids with a zero second
+byte are reserved for future use. The following ids are defined:
+
+ Ap (0x41, 0x70) : Apollo file type information
+
+The subfield size is the size of the subfield data and does not
+include the id and the size itself. The field 'extra field length' is
+the total size of the extra field, including subfield ids and sizes.
+
+It must be possible to detect the end of the compressed data with any
+compression format, regardless of the actual size of the compressed
+data. If the compressed data cannot fit in one file (in particular for
+diskettes), each part starts with a header as described above, but
+only the last part has the crc32 and uncompressed size. A decompressor
+may prompt for additional data for multipart compressed files. It is
+desirable but not mandatory that multiple parts be extractable
+independently so that partial data can be recovered if one of the
+parts is damaged. This is possible only if no compression state is
+kept from one part to the other. The compression-type dependent flags
+can indicate this.
+
+If the file being compressed is on a file system with case insensitive
+names, the original name field must be forced to lower case. There is
+no original file name if the data was compressed from standard input.
+
+Compression is always performed, even if the compressed file is
+slightly larger than the original. The worst case expansion is
+a few bytes for the gzip file header, plus 5 bytes every 32K block,
+or an expansion ratio of 0.015% for large files. Note that the actual
+number of used disk blocks almost never increases.
+
+The encryption is that of zip 1.9. For the encryption check, the
+last byte of the decoded encryption header must be zero. The time
+stamp of an encrypted file might be set to zero to avoid giving a clue
+about the construction of the random header.
+
+Jean-loup Gailly
+jloup@chorus.fr
+
+References:
+
+[LZ77] Ziv J., Lempel A., "A Universal Algorithm for Sequential Data
+Compression", IEEE Transactions on Information Theory", Vol. 23, No. 3,
+pp. 337-343.
+
+APPNOTE.TXT documentation file in PKZIP 1.93a. It is available by
+ftp in ftp.cso.uiuc.edu:/pc/exec-pc/pkz193a.exe [128.174.5.59]
+Use "unzip pkz193a.exe APPNOTE.TXT" to extract.
diff --git a/gnu/usr.bin/gzip/bits.c b/gnu/usr.bin/gzip/bits.c
new file mode 100644
index 0000000..fae1780
--- /dev/null
+++ b/gnu/usr.bin/gzip/bits.c
@@ -0,0 +1,205 @@
+/* bits.c -- output variable-length bit strings
+ * Copyright (C) 1992-1993 Jean-loup Gailly
+ * This is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License, see the file COPYING.
+ */
+
+
+/*
+ * PURPOSE
+ *
+ * Output variable-length bit strings. Compression can be done
+ * to a file or to memory. (The latter is not supported in this version.)
+ *
+ * DISCUSSION
+ *
+ * The PKZIP "deflate" file format interprets compressed file data
+ * as a sequence of bits. Multi-bit strings in the file may cross
+ * byte boundaries without restriction.
+ *
+ * The first bit of each byte is the low-order bit.
+ *
+ * The routines in this file allow a variable-length bit value to
+ * be output right-to-left (useful for literal values). For
+ * left-to-right output (useful for code strings from the tree routines),
+ * the bits must have been reversed first with bi_reverse().
+ *
+ * For in-memory compression, the compressed bit stream goes directly
+ * into the requested output buffer. The input data is read in blocks
+ * by the mem_read() function. The buffer is limited to 64K on 16 bit
+ * machines.
+ *
+ * INTERFACE
+ *
+ * void bi_init (FILE *zipfile)
+ * Initialize the bit string routines.
+ *
+ * void send_bits (int value, int length)
+ * Write out a bit string, taking the source bits right to
+ * left.
+ *
+ * int bi_reverse (int value, int length)
+ * Reverse the bits of a bit string, taking the source bits left to
+ * right and emitting them right to left.
+ *
+ * void bi_windup (void)
+ * Write out any remaining bits in an incomplete byte.
+ *
+ * void copy_block(char *buf, unsigned len, int header)
+ * Copy a stored block to the zip file, storing first the length and
+ * its one's complement if requested.
+ *
+ */
+
+#include "tailor.h"
+#include "gzip.h"
+#include "crypt.h"
+
+#ifdef DEBUG
+# include <stdio.h>
+#endif
+
+#ifdef RCSID
+static char rcsid[] = "$Id: bits.c,v 1.3 1993/10/14 00:32:24 nate Exp $";
+#endif
+
+/* ===========================================================================
+ * Local data used by the "bit string" routines.
+ */
+
+local file_t zfile; /* output gzip file */
+
+local unsigned short bi_buf;
+/* Output buffer. bits are inserted starting at the bottom (least significant
+ * bits).
+ */
+
+#define Buf_size (8 * 2*sizeof(char))
+/* Number of bits used within bi_buf. (bi_buf might be implemented on
+ * more than 16 bits on some systems.)
+ */
+
+local int bi_valid;
+/* Number of valid bits in bi_buf. All bits above the last valid bit
+ * are always zero.
+ */
+
+int (*read_buf) OF((char *buf, unsigned size));
+/* Current input function. Set to mem_read for in-memory compression */
+
+#ifdef DEBUG
+ ulg bits_sent; /* bit length of the compressed data */
+#endif
+
+/* ===========================================================================
+ * Initialize the bit string routines.
+ */
+void bi_init (zipfile)
+ file_t zipfile; /* output zip file, NO_FILE for in-memory compression */
+{
+ zfile = zipfile;
+ bi_buf = 0;
+ bi_valid = 0;
+#ifdef DEBUG
+ bits_sent = 0L;
+#endif
+
+ /* Set the defaults for file compression. They are set by memcompress
+ * for in-memory compression.
+ */
+ if (zfile != NO_FILE) {
+ read_buf = file_read;
+ }
+}
+
+/* ===========================================================================
+ * Send a value on a given number of bits.
+ * IN assertion: length <= 16 and value fits in length bits.
+ */
+void send_bits(value, length)
+ int value; /* value to send */
+ int length; /* number of bits */
+{
+#ifdef DEBUG
+ Tracev((stderr," l %2d v %4x ", length, value));
+ Assert(length > 0 && length <= 15, "invalid length");
+ bits_sent += (ulg)length;
+#endif
+ /* If not enough room in bi_buf, use (valid) bits from bi_buf and
+ * (16 - bi_valid) bits from value, leaving (width - (16-bi_valid))
+ * unused bits in value.
+ */
+ if (bi_valid > (int)Buf_size - length) {
+ bi_buf |= (value << bi_valid);
+ put_short(bi_buf);
+ bi_buf = (ush)value >> (Buf_size - bi_valid);
+ bi_valid += length - Buf_size;
+ } else {
+ bi_buf |= value << bi_valid;
+ bi_valid += length;
+ }
+}
+
+/* ===========================================================================
+ * Reverse the first len bits of a code, using straightforward code (a faster
+ * method would use a table)
+ * IN assertion: 1 <= len <= 15
+ */
+unsigned bi_reverse(code, len)
+ unsigned code; /* the value to invert */
+ int len; /* its bit length */
+{
+ register unsigned res = 0;
+ do {
+ res |= code & 1;
+ code >>= 1, res <<= 1;
+ } while (--len > 0);
+ return res >> 1;
+}
+
+/* ===========================================================================
+ * Write out any remaining bits in an incomplete byte.
+ */
+void bi_windup()
+{
+ if (bi_valid > 8) {
+ put_short(bi_buf);
+ } else if (bi_valid > 0) {
+ put_byte(bi_buf);
+ }
+ bi_buf = 0;
+ bi_valid = 0;
+#ifdef DEBUG
+ bits_sent = (bits_sent+7) & ~7;
+#endif
+}
+
+/* ===========================================================================
+ * Copy a stored block to the zip file, storing first the length and its
+ * one's complement if requested.
+ */
+void copy_block(buf, len, header)
+ char *buf; /* the input data */
+ unsigned len; /* its length */
+ int header; /* true if block header must be written */
+{
+ bi_windup(); /* align on byte boundary */
+
+ if (header) {
+ put_short((ush)len);
+ put_short((ush)~len);
+#ifdef DEBUG
+ bits_sent += 2*16;
+#endif
+ }
+#ifdef DEBUG
+ bits_sent += (ulg)len<<3;
+#endif
+ while (len--) {
+#ifdef CRYPT
+ int t;
+ if (key) zencode(*buf, t);
+#endif
+ put_byte(*buf++);
+ }
+}
diff --git a/gnu/usr.bin/gzip/crypt.c b/gnu/usr.bin/gzip/crypt.c
new file mode 100644
index 0000000..cbce024
--- /dev/null
+++ b/gnu/usr.bin/gzip/crypt.c
@@ -0,0 +1,6 @@
+/* crypt.c (dummy version) -- do not perform encryption
+ * Hardly worth copyrighting :-)
+ */
+#ifdef RCSID
+static char rcsid[] = "$Id: crypt.c,v 0.6 1993/03/22 09:48:47 jloup Exp $";
+#endif
diff --git a/gnu/usr.bin/gzip/crypt.h b/gnu/usr.bin/gzip/crypt.h
new file mode 100644
index 0000000..2a4c203
--- /dev/null
+++ b/gnu/usr.bin/gzip/crypt.h
@@ -0,0 +1,12 @@
+/* crypt.h (dummy version) -- do not perform encryption
+ * Hardly worth copyrighting :-)
+ */
+
+#ifdef CRYPT
+# undef CRYPT /* dummy version */
+#endif
+
+#define RAND_HEAD_LEN 12 /* length of encryption random header */
+
+#define zencode
+#define zdecode
diff --git a/gnu/usr.bin/gzip/deflate.c b/gnu/usr.bin/gzip/deflate.c
new file mode 100644
index 0000000..0bc0ed4
--- /dev/null
+++ b/gnu/usr.bin/gzip/deflate.c
@@ -0,0 +1,763 @@
+/* deflate.c -- compress data using the deflation algorithm
+ * Copyright (C) 1992-1993 Jean-loup Gailly
+ * This is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License, see the file COPYING.
+ */
+
+/*
+ * PURPOSE
+ *
+ * Identify new text as repetitions of old text within a fixed-
+ * length sliding window trailing behind the new text.
+ *
+ * DISCUSSION
+ *
+ * The "deflation" process depends on being able to identify portions
+ * of the input text which are identical to earlier input (within a
+ * sliding window trailing behind the input currently being processed).
+ *
+ * The most straightforward technique turns out to be the fastest for
+ * most input files: try all possible matches and select the longest.
+ * The key feature of this algorithm is that insertions into the string
+ * dictionary are very simple and thus fast, and deletions are avoided
+ * completely. Insertions are performed at each input character, whereas
+ * string matches are performed only when the previous match ends. So it
+ * is preferable to spend more time in matches to allow very fast string
+ * insertions and avoid deletions. The matching algorithm for small
+ * strings is inspired from that of Rabin & Karp. A brute force approach
+ * is used to find longer strings when a small match has been found.
+ * A similar algorithm is used in comic (by Jan-Mark Wams) and freeze
+ * (by Leonid Broukhis).
+ * A previous version of this file used a more sophisticated algorithm
+ * (by Fiala and Greene) which is guaranteed to run in linear amortized
+ * time, but has a larger average cost, uses more memory and is patented.
+ * However the F&G algorithm may be faster for some highly redundant
+ * files if the parameter max_chain_length (described below) is too large.
+ *
+ * ACKNOWLEDGEMENTS
+ *
+ * The idea of lazy evaluation of matches is due to Jan-Mark Wams, and
+ * I found it in 'freeze' written by Leonid Broukhis.
+ * Thanks to many info-zippers for bug reports and testing.
+ *
+ * REFERENCES
+ *
+ * APPNOTE.TXT documentation file in PKZIP 1.93a distribution.
+ *
+ * A description of the Rabin and Karp algorithm is given in the book
+ * "Algorithms" by R. Sedgewick, Addison-Wesley, p252.
+ *
+ * Fiala,E.R., and Greene,D.H.
+ * Data Compression with Finite Windows, Comm.ACM, 32,4 (1989) 490-595
+ *
+ * INTERFACE
+ *
+ * void lm_init (int pack_level, ush *flags)
+ * Initialize the "longest match" routines for a new file
+ *
+ * ulg deflate (void)
+ * Processes a new input file and return its compressed length. Sets
+ * the compressed length, crc, deflate flags and internal file
+ * attributes.
+ */
+
+#include <stdio.h>
+
+#include "tailor.h"
+#include "gzip.h"
+#include "lzw.h" /* just for consistency checking */
+
+#ifdef RCSID
+static char rcsid[] = "$Id: deflate.c,v 1.3 1993/10/14 00:32:29 nate Exp $";
+#endif
+
+/* ===========================================================================
+ * Configuration parameters
+ */
+
+/* Compile with MEDIUM_MEM to reduce the memory requirements or
+ * with SMALL_MEM to use as little memory as possible. Use BIG_MEM if the
+ * entire input file can be held in memory (not possible on 16 bit systems).
+ * Warning: defining these symbols affects HASH_BITS (see below) and thus
+ * affects the compression ratio. The compressed output
+ * is still correct, and might even be smaller in some cases.
+ */
+
+#ifdef SMALL_MEM
+# define HASH_BITS 13 /* Number of bits used to hash strings */
+#endif
+#ifdef MEDIUM_MEM
+# define HASH_BITS 14
+#endif
+#ifndef HASH_BITS
+# define HASH_BITS 15
+ /* For portability to 16 bit machines, do not use values above 15. */
+#endif
+
+/* To save space (see unlzw.c), we overlay prev+head with tab_prefix and
+ * window with tab_suffix. Check that we can do this:
+ */
+#if (WSIZE<<1) > (1<<BITS)
+ error: cannot overlay window with tab_suffix and prev with tab_prefix0
+#endif
+#if HASH_BITS > BITS-1
+ error: cannot overlay head with tab_prefix1
+#endif
+
+#define HASH_SIZE (unsigned)(1<<HASH_BITS)
+#define HASH_MASK (HASH_SIZE-1)
+#define WMASK (WSIZE-1)
+/* HASH_SIZE and WSIZE must be powers of two */
+
+#define NIL 0
+/* Tail of hash chains */
+
+#define FAST 4
+#define SLOW 2
+/* speed options for the general purpose bit flag */
+
+#ifndef TOO_FAR
+# define TOO_FAR 4096
+#endif
+/* Matches of length 3 are discarded if their distance exceeds TOO_FAR */
+
+/* ===========================================================================
+ * Local data used by the "longest match" routines.
+ */
+
+typedef ush Pos;
+typedef unsigned IPos;
+/* A Pos is an index in the character window. We use short instead of int to
+ * save space in the various tables. IPos is used only for parameter passing.
+ */
+
+/* DECLARE(uch, window, 2L*WSIZE); */
+/* Sliding window. Input bytes are read into the second half of the window,
+ * and move to the first half later to keep a dictionary of at least WSIZE
+ * bytes. With this organization, matches are limited to a distance of
+ * WSIZE-MAX_MATCH bytes, but this ensures that IO is always
+ * performed with a length multiple of the block size. Also, it limits
+ * the window size to 64K, which is quite useful on MSDOS.
+ * To do: limit the window size to WSIZE+BSZ if SMALL_MEM (the code would
+ * be less efficient).
+ */
+
+/* DECLARE(Pos, prev, WSIZE); */
+/* Link to older string with same hash index. To limit the size of this
+ * array to 64K, this link is maintained only for the last 32K strings.
+ * An index in this array is thus a window index modulo 32K.
+ */
+
+/* DECLARE(Pos, head, 1<<HASH_BITS); */
+/* Heads of the hash chains or NIL. */
+
+ulg window_size = (ulg)2*WSIZE;
+/* window size, 2*WSIZE except for MMAP or BIG_MEM, where it is the
+ * input file length plus MIN_LOOKAHEAD.
+ */
+
+long block_start;
+/* window position at the beginning of the current output block. Gets
+ * negative when the window is moved backwards.
+ */
+
+local unsigned ins_h; /* hash index of string to be inserted */
+
+#define H_SHIFT ((HASH_BITS+MIN_MATCH-1)/MIN_MATCH)
+/* Number of bits by which ins_h and del_h must be shifted at each
+ * input step. It must be such that after MIN_MATCH steps, the oldest
+ * byte no longer takes part in the hash key, that is:
+ * H_SHIFT * MIN_MATCH >= HASH_BITS
+ */
+
+unsigned int near prev_length;
+/* Length of the best match at previous step. Matches not greater than this
+ * are discarded. This is used in the lazy match evaluation.
+ */
+
+ unsigned near strstart; /* start of string to insert */
+ unsigned near match_start; /* start of matching string */
+local int eofile; /* flag set at end of input file */
+local unsigned lookahead; /* number of valid bytes ahead in window */
+
+unsigned near max_chain_length;
+/* To speed up deflation, hash chains are never searched beyond this length.
+ * A higher limit improves compression ratio but degrades the speed.
+ */
+
+local unsigned int max_lazy_match;
+/* Attempt to find a better match only when the current match is strictly
+ * smaller than this value. This mechanism is used only for compression
+ * levels >= 4.
+ */
+#define max_insert_length max_lazy_match
+/* Insert new strings in the hash table only if the match length
+ * is not greater than this length. This saves time but degrades compression.
+ * max_insert_length is used only for compression levels <= 3.
+ */
+
+local int compr_level;
+/* compression level (1..9) */
+
+unsigned near good_match;
+/* Use a faster search when the previous match is longer than this */
+
+
+/* Values for max_lazy_match, good_match and max_chain_length, depending on
+ * the desired pack level (0..9). The values given below have been tuned to
+ * exclude worst case performance for pathological files. Better values may be
+ * found for specific files.
+ */
+
+typedef struct config {
+ ush good_length; /* reduce lazy search above this match length */
+ ush max_lazy; /* do not perform lazy search above this match length */
+ ush nice_length; /* quit search above this match length */
+ ush max_chain;
+} config;
+
+#ifdef FULL_SEARCH
+# define nice_match MAX_MATCH
+#else
+ int near nice_match; /* Stop searching when current match exceeds this */
+#endif
+
+local config configuration_table[10] = {
+/* good lazy nice chain */
+/* 0 */ {0, 0, 0, 0}, /* store only */
+/* 1 */ {4, 4, 8, 4}, /* maximum speed, no lazy matches */
+/* 2 */ {4, 5, 16, 8},
+/* 3 */ {4, 6, 32, 32},
+
+/* 4 */ {4, 4, 16, 16}, /* lazy matches */
+/* 5 */ {8, 16, 32, 32},
+/* 6 */ {8, 16, 128, 128},
+/* 7 */ {8, 32, 128, 256},
+/* 8 */ {32, 128, 258, 1024},
+/* 9 */ {32, 258, 258, 4096}}; /* maximum compression */
+
+/* Note: the deflate() code requires max_lazy >= MIN_MATCH and max_chain >= 4
+ * For deflate_fast() (levels <= 3) good is ignored and lazy has a different
+ * meaning.
+ */
+
+#define EQUAL 0
+/* result of memcmp for equal strings */
+
+/* ===========================================================================
+ * Prototypes for local functions.
+ */
+local void fill_window OF((void));
+local ulg deflate_fast OF((void));
+
+ int longest_match OF((IPos cur_match));
+#ifdef ASMV
+ void match_init OF((void)); /* asm code initialization */
+#endif
+
+#ifdef DEBUG
+local void check_match OF((IPos start, IPos match, int length));
+#endif
+
+/* ===========================================================================
+ * Update a hash value with the given input byte
+ * IN assertion: all calls to to UPDATE_HASH are made with consecutive
+ * input characters, so that a running hash key can be computed from the
+ * previous key instead of complete recalculation each time.
+ */
+#define UPDATE_HASH(h,c) (h = (((h)<<H_SHIFT) ^ (c)) & HASH_MASK)
+
+/* ===========================================================================
+ * Insert string s in the dictionary and set match_head to the previous head
+ * of the hash chain (the most recent string with same hash key). Return
+ * the previous length of the hash chain.
+ * IN assertion: all calls to to INSERT_STRING are made with consecutive
+ * input characters and the first MIN_MATCH bytes of s are valid
+ * (except for the last MIN_MATCH-1 bytes of the input file).
+ */
+#define INSERT_STRING(s, match_head) \
+ (UPDATE_HASH(ins_h, window[(s) + MIN_MATCH-1]), \
+ prev[(s) & WMASK] = match_head = head[ins_h], \
+ head[ins_h] = (s))
+
+/* ===========================================================================
+ * Initialize the "longest match" routines for a new file
+ */
+void lm_init (pack_level, flags)
+ int pack_level; /* 0: store, 1: best speed, 9: best compression */
+ ush *flags; /* general purpose bit flag */
+{
+ register unsigned j;
+
+ if (pack_level < 1 || pack_level > 9) error("bad pack level");
+ compr_level = pack_level;
+
+ /* Initialize the hash table. */
+#if defined(MAXSEG_64K) && HASH_BITS == 15
+ for (j = 0; j < HASH_SIZE; j++) head[j] = NIL;
+#else
+ memzero((char*)head, HASH_SIZE*sizeof(*head));
+#endif
+ /* prev will be initialized on the fly */
+
+ /* Set the default configuration parameters:
+ */
+ max_lazy_match = configuration_table[pack_level].max_lazy;
+ good_match = configuration_table[pack_level].good_length;
+#ifndef FULL_SEARCH
+ nice_match = configuration_table[pack_level].nice_length;
+#endif
+ max_chain_length = configuration_table[pack_level].max_chain;
+ if (pack_level == 1) {
+ *flags |= FAST;
+ } else if (pack_level == 9) {
+ *flags |= SLOW;
+ }
+ /* ??? reduce max_chain_length for binary files */
+
+ strstart = 0;
+ block_start = 0L;
+#ifdef ASMV
+ match_init(); /* initialize the asm code */
+#endif
+
+ lookahead = read_buf((char*)window,
+ sizeof(int) <= 2 ? (unsigned)WSIZE : 2*WSIZE);
+
+ if (lookahead == 0 || lookahead == (unsigned)EOF) {
+ eofile = 1, lookahead = 0;
+ return;
+ }
+ eofile = 0;
+ /* Make sure that we always have enough lookahead. This is important
+ * if input comes from a device such as a tty.
+ */
+ while (lookahead < MIN_LOOKAHEAD && !eofile) fill_window();
+
+ ins_h = 0;
+ for (j=0; j<MIN_MATCH-1; j++) UPDATE_HASH(ins_h, window[j]);
+ /* If lookahead < MIN_MATCH, ins_h is garbage, but this is
+ * not important since only literal bytes will be emitted.
+ */
+}
+
+/* ===========================================================================
+ * Set match_start to the longest match starting at the given string and
+ * return its length. Matches shorter or equal to prev_length are discarded,
+ * in which case the result is equal to prev_length and match_start is
+ * garbage.
+ * IN assertions: cur_match is the head of the hash chain for the current
+ * string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1
+ */
+#ifndef ASMV
+/* For MSDOS, OS/2 and 386 Unix, an optimized version is in match.asm or
+ * match.s. The code is functionally equivalent, so you can use the C version
+ * if desired.
+ */
+int longest_match(cur_match)
+ IPos cur_match; /* current match */
+{
+ unsigned chain_length = max_chain_length; /* max hash chain length */
+ register uch *scan = window + strstart; /* current string */
+ register uch *match; /* matched string */
+ register int len; /* length of current match */
+ int best_len = prev_length; /* best match length so far */
+ IPos limit = strstart > (IPos)MAX_DIST ? strstart - (IPos)MAX_DIST : NIL;
+ /* Stop when cur_match becomes <= limit. To simplify the code,
+ * we prevent matches with the string of window index 0.
+ */
+
+/* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16.
+ * It is easy to get rid of this optimization if necessary.
+ */
+#if HASH_BITS < 8 || MAX_MATCH != 258
+ error: Code too clever
+#endif
+
+#ifdef UNALIGNED_OK
+ /* Compare two bytes at a time. Note: this is not always beneficial.
+ * Try with and without -DUNALIGNED_OK to check.
+ */
+ register uch *strend = window + strstart + MAX_MATCH - 1;
+ register ush scan_start = *(ush*)scan;
+ register ush scan_end = *(ush*)(scan+best_len-1);
+#else
+ register uch *strend = window + strstart + MAX_MATCH;
+ register uch scan_end1 = scan[best_len-1];
+ register uch scan_end = scan[best_len];
+#endif
+
+ /* Do not waste too much time if we already have a good match: */
+ if (prev_length >= good_match) {
+ chain_length >>= 2;
+ }
+ Assert(strstart <= window_size-MIN_LOOKAHEAD, "insufficient lookahead");
+
+ do {
+ Assert(cur_match < strstart, "no future");
+ match = window + cur_match;
+
+ /* Skip to next match if the match length cannot increase
+ * or if the match length is less than 2:
+ */
+#if (defined(UNALIGNED_OK) && MAX_MATCH == 258)
+ /* This code assumes sizeof(unsigned short) == 2. Do not use
+ * UNALIGNED_OK if your compiler uses a different size.
+ */
+ if (*(ush*)(match+best_len-1) != scan_end ||
+ *(ush*)match != scan_start) continue;
+
+ /* It is not necessary to compare scan[2] and match[2] since they are
+ * always equal when the other bytes match, given that the hash keys
+ * are equal and that HASH_BITS >= 8. Compare 2 bytes at a time at
+ * strstart+3, +5, ... up to strstart+257. We check for insufficient
+ * lookahead only every 4th comparison; the 128th check will be made
+ * at strstart+257. If MAX_MATCH-2 is not a multiple of 8, it is
+ * necessary to put more guard bytes at the end of the window, or
+ * to check more often for insufficient lookahead.
+ */
+ scan++, match++;
+ do {
+ } while (*(ush*)(scan+=2) == *(ush*)(match+=2) &&
+ *(ush*)(scan+=2) == *(ush*)(match+=2) &&
+ *(ush*)(scan+=2) == *(ush*)(match+=2) &&
+ *(ush*)(scan+=2) == *(ush*)(match+=2) &&
+ scan < strend);
+ /* The funny "do {}" generates better code on most compilers */
+
+ /* Here, scan <= window+strstart+257 */
+ Assert(scan <= window+(unsigned)(window_size-1), "wild scan");
+ if (*scan == *match) scan++;
+
+ len = (MAX_MATCH - 1) - (int)(strend-scan);
+ scan = strend - (MAX_MATCH-1);
+
+#else /* UNALIGNED_OK */
+
+ if (match[best_len] != scan_end ||
+ match[best_len-1] != scan_end1 ||
+ *match != *scan ||
+ *++match != scan[1]) continue;
+
+ /* The check at best_len-1 can be removed because it will be made
+ * again later. (This heuristic is not always a win.)
+ * It is not necessary to compare scan[2] and match[2] since they
+ * are always equal when the other bytes match, given that
+ * the hash keys are equal and that HASH_BITS >= 8.
+ */
+ scan += 2, match++;
+
+ /* We check for insufficient lookahead only every 8th comparison;
+ * the 256th check will be made at strstart+258.
+ */
+ do {
+ } while (*++scan == *++match && *++scan == *++match &&
+ *++scan == *++match && *++scan == *++match &&
+ *++scan == *++match && *++scan == *++match &&
+ *++scan == *++match && *++scan == *++match &&
+ scan < strend);
+
+ len = MAX_MATCH - (int)(strend - scan);
+ scan = strend - MAX_MATCH;
+
+#endif /* UNALIGNED_OK */
+
+ if (len > best_len) {
+ match_start = cur_match;
+ best_len = len;
+ if (len >= nice_match) break;
+#ifdef UNALIGNED_OK
+ scan_end = *(ush*)(scan+best_len-1);
+#else
+ scan_end1 = scan[best_len-1];
+ scan_end = scan[best_len];
+#endif
+ }
+ } while ((cur_match = prev[cur_match & WMASK]) > limit
+ && --chain_length != 0);
+
+ return best_len;
+}
+#endif /* ASMV */
+
+#ifdef DEBUG
+/* ===========================================================================
+ * Check that the match at match_start is indeed a match.
+ */
+local void check_match(start, match, length)
+ IPos start, match;
+ int length;
+{
+ /* check that the match is indeed a match */
+ if (memcmp((char*)window + match,
+ (char*)window + start, length) != EQUAL) {
+ fprintf(stderr,
+ " start %d, match %d, length %d\n",
+ start, match, length);
+ error("invalid match");
+ }
+ if (verbose > 1) {
+ fprintf(stderr,"\\[%d,%d]", start-match, length);
+ do { putc(window[start++], stderr); } while (--length != 0);
+ }
+}
+#else
+# define check_match(start, match, length)
+#endif
+
+/* ===========================================================================
+ * Fill the window when the lookahead becomes insufficient.
+ * Updates strstart and lookahead, and sets eofile if end of input file.
+ * IN assertion: lookahead < MIN_LOOKAHEAD && strstart + lookahead > 0
+ * OUT assertions: at least one byte has been read, or eofile is set;
+ * file reads are performed for at least two bytes (required for the
+ * translate_eol option).
+ */
+local void fill_window()
+{
+ register unsigned n, m;
+ unsigned more = (unsigned)(window_size - (ulg)lookahead - (ulg)strstart);
+ /* Amount of free space at the end of the window. */
+
+ /* If the window is almost full and there is insufficient lookahead,
+ * move the upper half to the lower one to make room in the upper half.
+ */
+ if (more == (unsigned)EOF) {
+ /* Very unlikely, but possible on 16 bit machine if strstart == 0
+ * and lookahead == 1 (input done one byte at time)
+ */
+ more--;
+ } else if (strstart >= WSIZE+MAX_DIST) {
+ /* By the IN assertion, the window is not empty so we can't confuse
+ * more == 0 with more == 64K on a 16 bit machine.
+ */
+ Assert(window_size == (ulg)2*WSIZE, "no sliding with BIG_MEM");
+
+ memcpy((char*)window, (char*)window+WSIZE, (unsigned)WSIZE);
+ match_start -= WSIZE;
+ strstart -= WSIZE; /* we now have strstart >= MAX_DIST: */
+
+ block_start -= (long) WSIZE;
+
+ for (n = 0; n < HASH_SIZE; n++) {
+ m = head[n];
+ head[n] = (Pos)(m >= WSIZE ? m-WSIZE : NIL);
+ }
+ for (n = 0; n < WSIZE; n++) {
+ m = prev[n];
+ prev[n] = (Pos)(m >= WSIZE ? m-WSIZE : NIL);
+ /* If n is not on any hash chain, prev[n] is garbage but
+ * its value will never be used.
+ */
+ }
+ more += WSIZE;
+ }
+ /* At this point, more >= 2 */
+ if (!eofile) {
+ n = read_buf((char*)window+strstart+lookahead, more);
+ if (n == 0 || n == (unsigned)EOF) {
+ eofile = 1;
+ } else {
+ lookahead += n;
+ }
+ }
+}
+
+/* ===========================================================================
+ * Flush the current block, with given end-of-file flag.
+ * IN assertion: strstart is set to the end of the current match.
+ */
+#define FLUSH_BLOCK(eof) \
+ flush_block(block_start >= 0L ? (char*)&window[(unsigned)block_start] : \
+ (char*)NULL, (long)strstart - block_start, (eof))
+
+/* ===========================================================================
+ * Processes a new input file and return its compressed length. This
+ * function does not perform lazy evaluationof matches and inserts
+ * new strings in the dictionary only for unmatched strings or for short
+ * matches. It is used only for the fast compression options.
+ */
+local ulg deflate_fast()
+{
+ IPos hash_head; /* head of the hash chain */
+ int flush; /* set if current block must be flushed */
+ unsigned match_length = 0; /* length of best match */
+
+ prev_length = MIN_MATCH-1;
+ while (lookahead != 0) {
+ /* Insert the string window[strstart .. strstart+2] in the
+ * dictionary, and set hash_head to the head of the hash chain:
+ */
+ INSERT_STRING(strstart, hash_head);
+
+ /* Find the longest match, discarding those <= prev_length.
+ * At this point we have always match_length < MIN_MATCH
+ */
+ if (hash_head != NIL && strstart - hash_head <= MAX_DIST) {
+ /* To simplify the code, we prevent matches with the string
+ * of window index 0 (in particular we have to avoid a match
+ * of the string with itself at the start of the input file).
+ */
+ match_length = longest_match (hash_head);
+ /* longest_match() sets match_start */
+ if (match_length > lookahead) match_length = lookahead;
+ }
+ if (match_length >= MIN_MATCH) {
+ check_match(strstart, match_start, match_length);
+
+ flush = ct_tally(strstart-match_start, match_length - MIN_MATCH);
+
+ lookahead -= match_length;
+
+ /* Insert new strings in the hash table only if the match length
+ * is not too large. This saves time but degrades compression.
+ */
+ if (match_length <= max_insert_length) {
+ match_length--; /* string at strstart already in hash table */
+ do {
+ strstart++;
+ INSERT_STRING(strstart, hash_head);
+ /* strstart never exceeds WSIZE-MAX_MATCH, so there are
+ * always MIN_MATCH bytes ahead. If lookahead < MIN_MATCH
+ * these bytes are garbage, but it does not matter since
+ * the next lookahead bytes will be emitted as literals.
+ */
+ } while (--match_length != 0);
+ strstart++;
+ } else {
+ strstart += match_length;
+ match_length = 0;
+ ins_h = window[strstart];
+ UPDATE_HASH(ins_h, window[strstart+1]);
+#if MIN_MATCH != 3
+ Call UPDATE_HASH() MIN_MATCH-3 more times
+#endif
+ }
+ } else {
+ /* No match, output a literal byte */
+ Tracevv((stderr,"%c",window[strstart]));
+ flush = ct_tally (0, window[strstart]);
+ lookahead--;
+ strstart++;
+ }
+ if (flush) FLUSH_BLOCK(0), block_start = strstart;
+
+ /* Make sure that we always have enough lookahead, except
+ * at the end of the input file. We need MAX_MATCH bytes
+ * for the next match, plus MIN_MATCH bytes to insert the
+ * string following the next match.
+ */
+ while (lookahead < MIN_LOOKAHEAD && !eofile) fill_window();
+
+ }
+ return FLUSH_BLOCK(1); /* eof */
+}
+
+/* ===========================================================================
+ * Same as above, but achieves better compression. We use a lazy
+ * evaluation for matches: a match is finally adopted only if there is
+ * no better match at the next window position.
+ */
+ulg deflate()
+{
+ IPos hash_head; /* head of hash chain */
+ IPos prev_match; /* previous match */
+ int flush; /* set if current block must be flushed */
+ int match_available = 0; /* set if previous match exists */
+ register unsigned match_length = MIN_MATCH-1; /* length of best match */
+#ifdef DEBUG
+ extern long isize; /* byte length of input file, for debug only */
+#endif
+
+ if (compr_level <= 3) return deflate_fast(); /* optimized for speed */
+
+ /* Process the input block. */
+ while (lookahead != 0) {
+ /* Insert the string window[strstart .. strstart+2] in the
+ * dictionary, and set hash_head to the head of the hash chain:
+ */
+ INSERT_STRING(strstart, hash_head);
+
+ /* Find the longest match, discarding those <= prev_length.
+ */
+ prev_length = match_length, prev_match = match_start;
+ match_length = MIN_MATCH-1;
+
+ if (hash_head != NIL && prev_length < max_lazy_match &&
+ strstart - hash_head <= MAX_DIST) {
+ /* To simplify the code, we prevent matches with the string
+ * of window index 0 (in particular we have to avoid a match
+ * of the string with itself at the start of the input file).
+ */
+ match_length = longest_match (hash_head);
+ /* longest_match() sets match_start */
+ if (match_length > lookahead) match_length = lookahead;
+
+ /* Ignore a length 3 match if it is too distant: */
+ if (match_length == MIN_MATCH && strstart-match_start > TOO_FAR){
+ /* If prev_match is also MIN_MATCH, match_start is garbage
+ * but we will ignore the current match anyway.
+ */
+ match_length--;
+ }
+ }
+ /* If there was a match at the previous step and the current
+ * match is not better, output the previous match:
+ */
+ if (prev_length >= MIN_MATCH && match_length <= prev_length) {
+
+ check_match(strstart-1, prev_match, prev_length);
+
+ flush = ct_tally(strstart-1-prev_match, prev_length - MIN_MATCH);
+
+ /* Insert in hash table all strings up to the end of the match.
+ * strstart-1 and strstart are already inserted.
+ */
+ lookahead -= prev_length-1;
+ prev_length -= 2;
+ do {
+ strstart++;
+ INSERT_STRING(strstart, hash_head);
+ /* strstart never exceeds WSIZE-MAX_MATCH, so there are
+ * always MIN_MATCH bytes ahead. If lookahead < MIN_MATCH
+ * these bytes are garbage, but it does not matter since the
+ * next lookahead bytes will always be emitted as literals.
+ */
+ } while (--prev_length != 0);
+ match_available = 0;
+ match_length = MIN_MATCH-1;
+ strstart++;
+ if (flush) FLUSH_BLOCK(0), block_start = strstart;
+
+ } else if (match_available) {
+ /* If there was no match at the previous position, output a
+ * single literal. If there was a match but the current match
+ * is longer, truncate the previous match to a single literal.
+ */
+ Tracevv((stderr,"%c",window[strstart-1]));
+ if (ct_tally (0, window[strstart-1])) {
+ FLUSH_BLOCK(0), block_start = strstart;
+ }
+ strstart++;
+ lookahead--;
+ } else {
+ /* There is no previous match to compare with, wait for
+ * the next step to decide.
+ */
+ match_available = 1;
+ strstart++;
+ lookahead--;
+ }
+ Assert (strstart <= isize && lookahead <= isize, "a bit too far");
+
+ /* Make sure that we always have enough lookahead, except
+ * at the end of the input file. We need MAX_MATCH bytes
+ * for the next match, plus MIN_MATCH bytes to insert the
+ * string following the next match.
+ */
+ while (lookahead < MIN_LOOKAHEAD && !eofile) fill_window();
+ }
+ if (match_available) ct_tally (0, window[strstart-1]);
+
+ return FLUSH_BLOCK(1); /* eof */
+}
diff --git a/gnu/usr.bin/gzip/getopt.c b/gnu/usr.bin/gzip/getopt.c
new file mode 100644
index 0000000..55fad84
--- /dev/null
+++ b/gnu/usr.bin/gzip/getopt.c
@@ -0,0 +1,755 @@
+/* Getopt for GNU.
+ NOTE: getopt is now part of the C library, so if you don't know what
+ "Keep this file name-space clean" means, talk to roland@gnu.ai.mit.edu
+ before changing it!
+
+ Copyright (C) 1987, 88, 89, 90, 91, 92, 1993
+ Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any
+ later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifndef __STDC__
+# ifndef const
+# define const
+# endif
+#endif
+
+/* This tells Alpha OSF/1 not to define a getopt prototype in <stdio.h>. */
+#ifndef _NO_PROTO
+#define _NO_PROTO
+#endif
+
+#include <stdio.h>
+#include "tailor.h"
+
+/* Comment out all this code if we are using the GNU C Library, and are not
+ actually compiling the library itself. This code is part of the GNU C
+ Library, but also included in many other GNU distributions. Compiling
+ and linking in this code is a waste when using the GNU C library
+ (especially if it is a shared library). Rather than having every GNU
+ program understand `configure --with-gnu-libc' and omit the object files,
+ it is simpler to just do this in the source for each such file. */
+
+#if defined (_LIBC) || !defined (__GNU_LIBRARY__)
+
+
+/* This needs to come after some library #include
+ to get __GNU_LIBRARY__ defined. */
+#ifdef __GNU_LIBRARY__
+/* Don't include stdlib.h for non-GNU C libraries because some of them
+ contain conflicting prototypes for getopt. */
+#include <stdlib.h>
+#endif /* GNU C library. */
+
+/* If GETOPT_COMPAT is defined, `+' as well as `--' can introduce a
+ long-named option. Because this is not POSIX.2 compliant, it is
+ being phased out. */
+/* #define GETOPT_COMPAT */
+
+/* This version of `getopt' appears to the caller like standard Unix `getopt'
+ but it behaves differently for the user, since it allows the user
+ to intersperse the options with the other arguments.
+
+ As `getopt' works, it permutes the elements of ARGV so that,
+ when it is done, all the options precede everything else. Thus
+ all application programs are extended to handle flexible argument order.
+
+ Setting the environment variable POSIXLY_CORRECT disables permutation.
+ Then the behavior is completely standard.
+
+ GNU application programs can use a third alternative mode in which
+ they can distinguish the relative order of options and other arguments. */
+
+#include "getopt.h"
+
+/* For communication from `getopt' to the caller.
+ When `getopt' finds an option that takes an argument,
+ the argument value is returned here.
+ Also, when `ordering' is RETURN_IN_ORDER,
+ each non-option ARGV-element is returned here. */
+
+char *optarg = 0;
+
+/* Index in ARGV of the next element to be scanned.
+ This is used for communication to and from the caller
+ and for communication between successive calls to `getopt'.
+
+ On entry to `getopt', zero means this is the first call; initialize.
+
+ When `getopt' returns EOF, this is the index of the first of the
+ non-option elements that the caller should itself scan.
+
+ Otherwise, `optind' communicates from one call to the next
+ how much of ARGV has been scanned so far. */
+
+/* XXX 1003.2 says this must be 1 before any call. */
+int optind = 0;
+
+/* The next char to be scanned in the option-element
+ in which the last option character we returned was found.
+ This allows us to pick up the scan where we left off.
+
+ If this is zero, or a null string, it means resume the scan
+ by advancing to the next ARGV-element. */
+
+static char *nextchar;
+
+/* Callers store zero here to inhibit the error message
+ for unrecognized options. */
+
+int opterr = 1;
+
+/* Set to an option character which was unrecognized.
+ This must be initialized on some systems to avoid linking in the
+ system's own getopt implementation. */
+
+#define BAD_OPTION '\0'
+int optopt = BAD_OPTION;
+
+/* Describe how to deal with options that follow non-option ARGV-elements.
+
+ If the caller did not specify anything,
+ the default is REQUIRE_ORDER if the environment variable
+ POSIXLY_CORRECT is defined, PERMUTE otherwise.
+
+ REQUIRE_ORDER means don't recognize them as options;
+ stop option processing when the first non-option is seen.
+ This is what Unix does.
+ This mode of operation is selected by either setting the environment
+ variable POSIXLY_CORRECT, or using `+' as the first character
+ of the list of option characters.
+
+ PERMUTE is the default. We permute the contents of ARGV as we scan,
+ so that eventually all the non-options are at the end. This allows options
+ to be given in any order, even with programs that were not written to
+ expect this.
+
+ RETURN_IN_ORDER is an option available to programs that were written
+ to expect options and other ARGV-elements in any order and that care about
+ the ordering of the two. We describe each non-option ARGV-element
+ as if it were the argument of an option with character code 1.
+ Using `-' as the first character of the list of option characters
+ selects this mode of operation.
+
+ The special argument `--' forces an end of option-scanning regardless
+ of the value of `ordering'. In the case of RETURN_IN_ORDER, only
+ `--' can cause `getopt' to return EOF with `optind' != ARGC. */
+
+static enum
+{
+ REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER
+} ordering;
+
+#ifdef __GNU_LIBRARY__
+/* We want to avoid inclusion of string.h with non-GNU libraries
+ because there are many ways it can cause trouble.
+ On some systems, it contains special magic macros that don't work
+ in GCC. */
+#include <string.h>
+#define my_index strchr
+#define my_strlen strlen
+#else
+
+/* Avoid depending on library functions or files
+ whose names are inconsistent. */
+
+#if __STDC__ || defined(PROTO)
+extern char *getenv(const char *name);
+extern int strcmp (const char *s1, const char *s2);
+extern int strncmp(const char *s1, const char *s2, int n);
+
+static int my_strlen(const char *s);
+static char *my_index (const char *str, int chr);
+#else
+extern char *getenv ();
+#endif
+
+static int
+my_strlen (str)
+ const char *str;
+{
+ int n = 0;
+ while (*str++)
+ n++;
+ return n;
+}
+
+static char *
+my_index (str, chr)
+ const char *str;
+ int chr;
+{
+ while (*str)
+ {
+ if (*str == chr)
+ return (char *) str;
+ str++;
+ }
+ return 0;
+}
+
+#endif /* GNU C library. */
+
+/* Handle permutation of arguments. */
+
+/* Describe the part of ARGV that contains non-options that have
+ been skipped. `first_nonopt' is the index in ARGV of the first of them;
+ `last_nonopt' is the index after the last of them. */
+
+static int first_nonopt;
+static int last_nonopt;
+
+/* Exchange two adjacent subsequences of ARGV.
+ One subsequence is elements [first_nonopt,last_nonopt)
+ which contains all the non-options that have been skipped so far.
+ The other is elements [last_nonopt,optind), which contains all
+ the options processed since those non-options were skipped.
+
+ `first_nonopt' and `last_nonopt' are relocated so that they describe
+ the new indices of the non-options in ARGV after they are moved.
+
+ To perform the swap, we first reverse the order of all elements. So
+ all options now come before all non options, but they are in the
+ wrong order. So we put back the options and non options in original
+ order by reversing them again. For example:
+ original input: a b c -x -y
+ reverse all: -y -x c b a
+ reverse options: -x -y c b a
+ reverse non options: -x -y a b c
+*/
+
+#if __STDC__ || defined(PROTO)
+static void exchange (char **argv);
+#endif
+
+static void
+exchange (argv)
+ char **argv;
+{
+ char *temp, **first, **last;
+
+ /* Reverse all the elements [first_nonopt, optind) */
+ first = &argv[first_nonopt];
+ last = &argv[optind-1];
+ while (first < last) {
+ temp = *first; *first = *last; *last = temp; first++; last--;
+ }
+ /* Put back the options in order */
+ first = &argv[first_nonopt];
+ first_nonopt += (optind - last_nonopt);
+ last = &argv[first_nonopt - 1];
+ while (first < last) {
+ temp = *first; *first = *last; *last = temp; first++; last--;
+ }
+
+ /* Put back the non options in order */
+ first = &argv[first_nonopt];
+ last_nonopt = optind;
+ last = &argv[last_nonopt-1];
+ while (first < last) {
+ temp = *first; *first = *last; *last = temp; first++; last--;
+ }
+}
+
+/* Scan elements of ARGV (whose length is ARGC) for option characters
+ given in OPTSTRING.
+
+ If an element of ARGV starts with '-', and is not exactly "-" or "--",
+ then it is an option element. The characters of this element
+ (aside from the initial '-') are option characters. If `getopt'
+ is called repeatedly, it returns successively each of the option characters
+ from each of the option elements.
+
+ If `getopt' finds another option character, it returns that character,
+ updating `optind' and `nextchar' so that the next call to `getopt' can
+ resume the scan with the following option character or ARGV-element.
+
+ If there are no more option characters, `getopt' returns `EOF'.
+ Then `optind' is the index in ARGV of the first ARGV-element
+ that is not an option. (The ARGV-elements have been permuted
+ so that those that are not options now come last.)
+
+ OPTSTRING is a string containing the legitimate option characters.
+ If an option character is seen that is not listed in OPTSTRING,
+ return BAD_OPTION after printing an error message. If you set `opterr' to
+ zero, the error message is suppressed but we still return BAD_OPTION.
+
+ If a char in OPTSTRING is followed by a colon, that means it wants an arg,
+ so the following text in the same ARGV-element, or the text of the following
+ ARGV-element, is returned in `optarg'. Two colons mean an option that
+ wants an optional arg; if there is text in the current ARGV-element,
+ it is returned in `optarg', otherwise `optarg' is set to zero.
+
+ If OPTSTRING starts with `-' or `+', it requests different methods of
+ handling the non-option ARGV-elements.
+ See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above.
+
+ Long-named options begin with `--' instead of `-'.
+ Their names may be abbreviated as long as the abbreviation is unique
+ or is an exact match for some defined option. If they have an
+ argument, it follows the option name in the same ARGV-element, separated
+ from the option name by a `=', or else the in next ARGV-element.
+ When `getopt' finds a long-named option, it returns 0 if that option's
+ `flag' field is nonzero, the value of the option's `val' field
+ if the `flag' field is zero.
+
+ The elements of ARGV aren't really const, because we permute them.
+ But we pretend they're const in the prototype to be compatible
+ with other systems.
+
+ LONGOPTS is a vector of `struct option' terminated by an
+ element containing a name which is zero.
+
+ LONGIND returns the index in LONGOPT of the long-named option found.
+ It is only valid when a long-named option has been found by the most
+ recent call.
+
+ If LONG_ONLY is nonzero, '-' as well as '--' can introduce
+ long-named options. */
+
+int
+_getopt_internal (argc, argv, optstring, longopts, longind, long_only)
+ int argc;
+ char *const *argv;
+ const char *optstring;
+ const struct option *longopts;
+ int *longind;
+ int long_only;
+{
+ int option_index;
+
+ optarg = 0;
+
+ /* Initialize the internal data when the first call is made.
+ Start processing options with ARGV-element 1 (since ARGV-element 0
+ is the program name); the sequence of previously skipped
+ non-option ARGV-elements is empty. */
+
+ if (optind == 0)
+ {
+ first_nonopt = last_nonopt = optind = 1;
+
+ nextchar = NULL;
+
+ /* Determine how to handle the ordering of options and nonoptions. */
+
+ if (optstring[0] == '-')
+ {
+ ordering = RETURN_IN_ORDER;
+ ++optstring;
+ }
+ else if (optstring[0] == '+')
+ {
+ ordering = REQUIRE_ORDER;
+ ++optstring;
+ }
+ else if (getenv ("POSIXLY_CORRECT") != NULL)
+ ordering = REQUIRE_ORDER;
+ else
+ ordering = PERMUTE;
+ }
+
+ if (nextchar == NULL || *nextchar == '\0')
+ {
+ if (ordering == PERMUTE)
+ {
+ /* If we have just processed some options following some non-options,
+ exchange them so that the options come first. */
+
+ if (first_nonopt != last_nonopt && last_nonopt != optind)
+ exchange ((char **) argv);
+ else if (last_nonopt != optind)
+ first_nonopt = optind;
+
+ /* Now skip any additional non-options
+ and extend the range of non-options previously skipped. */
+
+ while (optind < argc
+ && (argv[optind][0] != '-' || argv[optind][1] == '\0')
+#ifdef GETOPT_COMPAT
+ && (longopts == NULL
+ || argv[optind][0] != '+' || argv[optind][1] == '\0')
+#endif /* GETOPT_COMPAT */
+ )
+ optind++;
+ last_nonopt = optind;
+ }
+
+ /* Special ARGV-element `--' means premature end of options.
+ Skip it like a null option,
+ then exchange with previous non-options as if it were an option,
+ then skip everything else like a non-option. */
+
+ if (optind != argc && !strcmp (argv[optind], "--"))
+ {
+ optind++;
+
+ if (first_nonopt != last_nonopt && last_nonopt != optind)
+ exchange ((char **) argv);
+ else if (first_nonopt == last_nonopt)
+ first_nonopt = optind;
+ last_nonopt = argc;
+
+ optind = argc;
+ }
+
+ /* If we have done all the ARGV-elements, stop the scan
+ and back over any non-options that we skipped and permuted. */
+
+ if (optind == argc)
+ {
+ /* Set the next-arg-index to point at the non-options
+ that we previously skipped, so the caller will digest them. */
+ if (first_nonopt != last_nonopt)
+ optind = first_nonopt;
+ return EOF;
+ }
+
+ /* If we have come to a non-option and did not permute it,
+ either stop the scan or describe it to the caller and pass it by. */
+
+ if ((argv[optind][0] != '-' || argv[optind][1] == '\0')
+#ifdef GETOPT_COMPAT
+ && (longopts == NULL
+ || argv[optind][0] != '+' || argv[optind][1] == '\0')
+#endif /* GETOPT_COMPAT */
+ )
+ {
+ if (ordering == REQUIRE_ORDER)
+ return EOF;
+ optarg = argv[optind++];
+ return 1;
+ }
+
+ /* We have found another option-ARGV-element.
+ Start decoding its characters. */
+
+ nextchar = (argv[optind] + 1
+ + (longopts != NULL && argv[optind][1] == '-'));
+ }
+
+ if (longopts != NULL
+ && ((argv[optind][0] == '-'
+ && (argv[optind][1] == '-' || long_only))
+#ifdef GETOPT_COMPAT
+ || argv[optind][0] == '+'
+#endif /* GETOPT_COMPAT */
+ ))
+ {
+ const struct option *p;
+ char *s = nextchar;
+ int exact = 0;
+ int ambig = 0;
+ const struct option *pfound = NULL;
+ int indfound = 0;
+
+ while (*s && *s != '=')
+ s++;
+
+ /* Test all options for either exact match or abbreviated matches. */
+ for (p = longopts, option_index = 0; p->name;
+ p++, option_index++)
+ if (!strncmp (p->name, nextchar, s - nextchar))
+ {
+ if (s - nextchar == my_strlen (p->name))
+ {
+ /* Exact match found. */
+ pfound = p;
+ indfound = option_index;
+ exact = 1;
+ break;
+ }
+ else if (pfound == NULL)
+ {
+ /* First nonexact match found. */
+ pfound = p;
+ indfound = option_index;
+ }
+ else
+ /* Second nonexact match found. */
+ ambig = 1;
+ }
+
+ if (ambig && !exact)
+ {
+ if (opterr)
+ fprintf (stderr, "%s: option `%s' is ambiguous\n",
+ argv[0], argv[optind]);
+ nextchar += my_strlen (nextchar);
+ optind++;
+ return BAD_OPTION;
+ }
+
+ if (pfound != NULL)
+ {
+ option_index = indfound;
+ optind++;
+ if (*s)
+ {
+ /* Don't test has_arg with >, because some C compilers don't
+ allow it to be used on enums. */
+ if (pfound->has_arg)
+ optarg = s + 1;
+ else
+ {
+ if (opterr)
+ {
+ if (argv[optind - 1][1] == '-')
+ /* --option */
+ fprintf (stderr,
+ "%s: option `--%s' doesn't allow an argument\n",
+ argv[0], pfound->name);
+ else
+ /* +option or -option */
+ fprintf (stderr,
+ "%s: option `%c%s' doesn't allow an argument\n",
+ argv[0], argv[optind - 1][0], pfound->name);
+ }
+ nextchar += my_strlen (nextchar);
+ return BAD_OPTION;
+ }
+ }
+ else if (pfound->has_arg == 1)
+ {
+ if (optind < argc)
+ optarg = argv[optind++];
+ else
+ {
+ if (opterr)
+ fprintf (stderr, "%s: option `%s' requires an argument\n",
+ argv[0], argv[optind - 1]);
+ nextchar += my_strlen (nextchar);
+ return optstring[0] == ':' ? ':' : BAD_OPTION;
+ }
+ }
+ nextchar += my_strlen (nextchar);
+ if (longind != NULL)
+ *longind = option_index;
+ if (pfound->flag)
+ {
+ *(pfound->flag) = pfound->val;
+ return 0;
+ }
+ return pfound->val;
+ }
+ /* Can't find it as a long option. If this is not getopt_long_only,
+ or the option starts with '--' or is not a valid short
+ option, then it's an error.
+ Otherwise interpret it as a short option. */
+ if (!long_only || argv[optind][1] == '-'
+#ifdef GETOPT_COMPAT
+ || argv[optind][0] == '+'
+#endif /* GETOPT_COMPAT */
+ || my_index (optstring, *nextchar) == NULL)
+ {
+ if (opterr)
+ {
+ if (argv[optind][1] == '-')
+ /* --option */
+ fprintf (stderr, "%s: unrecognized option `--%s'\n",
+ argv[0], nextchar);
+ else
+ /* +option or -option */
+ fprintf (stderr, "%s: unrecognized option `%c%s'\n",
+ argv[0], argv[optind][0], nextchar);
+ }
+ nextchar = (char *) "";
+ optind++;
+ return BAD_OPTION;
+ }
+ }
+
+ /* Look at and handle the next option-character. */
+
+ {
+ char c = *nextchar++;
+ char *temp = my_index (optstring, c);
+
+ /* Increment `optind' when we start to process its last character. */
+ if (*nextchar == '\0')
+ ++optind;
+
+ if (temp == NULL || c == ':')
+ {
+ if (opterr)
+ {
+#if 0
+ if (c < 040 || c >= 0177)
+ fprintf (stderr, "%s: unrecognized option, character code 0%o\n",
+ argv[0], c);
+ else
+ fprintf (stderr, "%s: unrecognized option `-%c'\n", argv[0], c);
+#else
+ /* 1003.2 specifies the format of this message. */
+ fprintf (stderr, "%s: illegal option -- %c\n", argv[0], c);
+#endif
+ }
+ optopt = c;
+ return BAD_OPTION;
+ }
+ if (temp[1] == ':')
+ {
+ if (temp[2] == ':')
+ {
+ /* This is an option that accepts an argument optionally. */
+ if (*nextchar != '\0')
+ {
+ optarg = nextchar;
+ optind++;
+ }
+ else
+ optarg = 0;
+ nextchar = NULL;
+ }
+ else
+ {
+ /* This is an option that requires an argument. */
+ if (*nextchar != '\0')
+ {
+ optarg = nextchar;
+ /* If we end this ARGV-element by taking the rest as an arg,
+ we must advance to the next element now. */
+ optind++;
+ }
+ else if (optind == argc)
+ {
+ if (opterr)
+ {
+#if 0
+ fprintf (stderr, "%s: option `-%c' requires an argument\n",
+ argv[0], c);
+#else
+ /* 1003.2 specifies the format of this message. */
+ fprintf (stderr, "%s: option requires an argument -- %c\n",
+ argv[0], c);
+#endif
+ }
+ optopt = c;
+ if (optstring[0] == ':')
+ c = ':';
+ else
+ c = BAD_OPTION;
+ }
+ else
+ /* We already incremented `optind' once;
+ increment it again when taking next ARGV-elt as argument. */
+ optarg = argv[optind++];
+ nextchar = NULL;
+ }
+ }
+ return c;
+ }
+}
+
+int
+getopt (argc, argv, optstring)
+ int argc;
+ char *const *argv;
+ const char *optstring;
+{
+ return _getopt_internal (argc, argv, optstring,
+ (const struct option *) 0,
+ (int *) 0,
+ 0);
+}
+
+int
+getopt_long (argc, argv, options, long_options, opt_index)
+ int argc;
+ char *const *argv;
+ const char *options;
+ const struct option *long_options;
+ int *opt_index;
+{
+ return _getopt_internal (argc, argv, options, long_options, opt_index, 0);
+}
+
+#endif /* _LIBC or not __GNU_LIBRARY__. */
+
+#ifdef TEST
+
+/* Compile with -DTEST to make an executable for use in testing
+ the above definition of `getopt'. */
+
+int
+main (argc, argv)
+ int argc;
+ char **argv;
+{
+ int c;
+ int digit_optind = 0;
+
+ while (1)
+ {
+ int this_option_optind = optind ? optind : 1;
+
+ c = getopt (argc, argv, "abc:d:0123456789");
+ if (c == EOF)
+ break;
+
+ switch (c)
+ {
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ if (digit_optind != 0 && digit_optind != this_option_optind)
+ printf ("digits occur in two different argv-elements.\n");
+ digit_optind = this_option_optind;
+ printf ("option %c\n", c);
+ break;
+
+ case 'a':
+ printf ("option a\n");
+ break;
+
+ case 'b':
+ printf ("option b\n");
+ break;
+
+ case 'c':
+ printf ("option c with value `%s'\n", optarg);
+ break;
+
+ case BAD_OPTION:
+ break;
+
+ default:
+ printf ("?? getopt returned character code 0%o ??\n", c);
+ }
+ }
+
+ if (optind < argc)
+ {
+ printf ("non-option ARGV-elements: ");
+ while (optind < argc)
+ printf ("%s ", argv[optind++]);
+ printf ("\n");
+ }
+
+ exit (0);
+}
+
+#endif /* TEST */
diff --git a/gnu/usr.bin/gzip/getopt.h b/gnu/usr.bin/gzip/getopt.h
new file mode 100644
index 0000000..0abce6e
--- /dev/null
+++ b/gnu/usr.bin/gzip/getopt.h
@@ -0,0 +1,127 @@
+/* Declarations for getopt.
+ Copyright (C) 1989, 1990, 1991, 1992, 1993 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any
+ later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#ifndef _GETOPT_H
+#define _GETOPT_H 1
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* For communication from `getopt' to the caller.
+ When `getopt' finds an option that takes an argument,
+ the argument value is returned here.
+ Also, when `ordering' is RETURN_IN_ORDER,
+ each non-option ARGV-element is returned here. */
+
+extern char *optarg;
+
+/* Index in ARGV of the next element to be scanned.
+ This is used for communication to and from the caller
+ and for communication between successive calls to `getopt'.
+
+ On entry to `getopt', zero means this is the first call; initialize.
+
+ When `getopt' returns EOF, this is the index of the first of the
+ non-option elements that the caller should itself scan.
+
+ Otherwise, `optind' communicates from one call to the next
+ how much of ARGV has been scanned so far. */
+
+extern int optind;
+
+/* Callers store zero here to inhibit the error message `getopt' prints
+ for unrecognized options. */
+
+extern int opterr;
+
+/* Set to an option character which was unrecognized. */
+
+extern int optopt;
+
+/* Describe the long-named options requested by the application.
+ The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector
+ of `struct option' terminated by an element containing a name which is
+ zero.
+
+ The field `has_arg' is:
+ no_argument (or 0) if the option does not take an argument,
+ required_argument (or 1) if the option requires an argument,
+ optional_argument (or 2) if the option takes an optional argument.
+
+ If the field `flag' is not NULL, it points to a variable that is set
+ to the value given in the field `val' when the option is found, but
+ left unchanged if the option is not found.
+
+ To have a long-named option do something other than set an `int' to
+ a compiled-in constant, such as set a value from `optarg', set the
+ option's `flag' field to zero and its `val' field to a nonzero
+ value (the equivalent single-letter option character, if there is
+ one). For long options that have a zero `flag' field, `getopt'
+ returns the contents of the `val' field. */
+
+struct option
+{
+#if __STDC__
+ const char *name;
+#else
+ char *name;
+#endif
+ /* has_arg can't be an enum because some compilers complain about
+ type mismatches in all the code that assumes it is an int. */
+ int has_arg;
+ int *flag;
+ int val;
+};
+
+/* Names for the values of the `has_arg' field of `struct option'. */
+
+#define no_argument 0
+#define required_argument 1
+#define optional_argument 2
+
+#if __STDC__ || defined(PROTO)
+#if defined(__GNU_LIBRARY__)
+/* Many other libraries have conflicting prototypes for getopt, with
+ differences in the consts, in stdlib.h. To avoid compilation
+ errors, only prototype getopt for the GNU C library. */
+extern int getopt (int argc, char *const *argv, const char *shortopts);
+#endif /* not __GNU_LIBRARY__ */
+extern int getopt_long (int argc, char *const *argv, const char *shortopts,
+ const struct option *longopts, int *longind);
+extern int getopt_long_only (int argc, char *const *argv,
+ const char *shortopts,
+ const struct option *longopts, int *longind);
+
+/* Internal only. Users should not call this directly. */
+extern int _getopt_internal (int argc, char *const *argv,
+ const char *shortopts,
+ const struct option *longopts, int *longind,
+ int long_only);
+#else /* not __STDC__ */
+extern int getopt ();
+extern int getopt_long ();
+extern int getopt_long_only ();
+
+extern int _getopt_internal ();
+#endif /* not __STDC__ */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _GETOPT_H */
diff --git a/gnu/usr.bin/gzip/gzexe b/gnu/usr.bin/gzip/gzexe
new file mode 100644
index 0000000..0c248d9
--- /dev/null
+++ b/gnu/usr.bin/gzip/gzexe
@@ -0,0 +1,150 @@
+#!/bin/sh
+# gzexe: compressor for Unix executables.
+# Use this only for binaries that you do not use frequently.
+#
+# The compressed version is a shell script which decompresses itself after
+# skipping $skip lines of shell commands. We try invoking the compressed
+# executable with the original name (for programs looking at their name).
+# We also try to retain the original file permissions on the compressed file.
+# For safety reasons, gzexe will not create setuid or setgid shell scripts.
+
+# WARNING: the first line of this file must be either : or #!/bin/sh
+# The : is required for some old versions of csh.
+# On Ultrix, /bin/sh is too buggy, change the first line to: #!/bin/sh5
+
+x=`basename $0`
+if test $# = 0; then
+ echo compress executables. original file foo is renamed to foo~
+ echo usage: ${x} [-d] files...
+ echo " -d decompress the executables"
+ exit 1
+fi
+
+tmp=gz$$
+trap "rm -f $tmp; exit 1" 1 2 3 5 10 13 15
+
+decomp=0
+res=0
+test "$x" = "ungzexe" && decomp=1
+if test "x$1" = "x-d"; then
+ decomp=1
+ shift
+fi
+
+echo hi > zfoo1$$
+echo hi > zfoo2$$
+if test -z "`(${CPMOD-cpmod} zfoo1$$ zfoo2$$) 2>&1`"; then
+ cpmod=${CPMOD-cpmod}
+fi
+rm -f zfoo[12]$$
+
+tail=""
+IFS="${IFS= }"; saveifs="$IFS"; IFS="${IFS}:"
+for dir in $PATH; do
+ test -z "$dir" && dir=.
+ if test -f $dir/tail; then
+ tail="$dir/tail"
+ break
+ fi
+done
+IFS="$saveifs"
+if test -z "$tail"; then
+ echo cannot find tail
+ exit 1
+fi
+
+for i do
+ if test ! -f "$i" ; then
+ echo ${x}: $i not a file
+ res=1
+ continue
+ fi
+ if test $decomp -eq 0; then
+ if sed -e 1d -e 2q "$i" | grep "^skip=[0-9]*$" >/dev/null; then
+ echo "${x}: $i is already gzexe'd"
+ continue
+ fi
+ fi
+ if ls -l "$i" | grep '^...[sS]' > /dev/null; then
+ echo "${x}: $i has setuid permission, unchanged"
+ continue
+ fi
+ if ls -l "$i" | grep '^......[sS]' > /dev/null; then
+ echo "${x}: $i has setgid permission, unchanged"
+ continue
+ fi
+ case "`basename $i`" in
+ gzip | tail | chmod | ln | sleep | rm)
+ echo "${x}: $i would depend on itself"; continue ;;
+ esac
+ if test -z "$cpmod"; then
+ cp -p "$i" $tmp 2>/dev/null || cp "$i" $tmp
+ if test -w $tmp 2>/dev/null; then
+ writable=1
+ else
+ writable=0
+ chmod u+w $tmp 2>/dev/null
+ fi
+ fi
+ if test $decomp -eq 0; then
+ sed 1q $0 > $tmp
+ sed "s|^if tail|if $tail|" >> $tmp <<'EOF'
+skip=18
+if tail +$skip $0 | gzip -cd > /tmp/gztmp$$; then
+ chmod 700 /tmp/gztmp$$
+ prog="`echo $0 | sed 's|^.*/||'`"
+ if /bin/ln /tmp/gztmp$$ "/tmp/$prog" 2>/dev/null; then
+ trap '/bin/rm -f /tmp/gztmp$$ "/tmp/$prog"; exit $res' 0
+ (/bin/sleep 5; /bin/rm -f /tmp/gztmp$$ "/tmp/$prog") 2>/dev/null &
+ /tmp/"$prog" ${1+"$@"}; res=$?
+ else
+ trap '/bin/rm -f /tmp/gztmp$$; exit $res' 0
+ (/bin/sleep 5; /bin/rm -f /tmp/gztmp$$) 2>/dev/null &
+ /tmp/gztmp$$ ${1+"$@"}; res=$?
+ fi
+else
+ echo Cannot decompress $0; exit 1
+fi; exit $res
+EOF
+ gzip -cv9 "$i" >> $tmp || {
+ /bin/rm -f $tmp
+ echo ${x}: compression not possible for $i, file unchanged.
+ res=1
+ continue
+ }
+
+ else
+ # decompression
+ skip=18
+ if sed -e 1d -e 2q "$i" | grep "^skip=[0-9]*$" >/dev/null; then
+ eval `sed -e 1d -e 2q "$i"`
+ fi
+ if tail +$skip "$i" | gzip -cd > $tmp; then
+ :
+ else
+ echo ${x}: $i probably not in gzexe format, file unchanged.
+ res=1
+ continue
+ fi
+ fi
+ rm -f "$i~"
+ mv "$i" "$i~" || {
+ echo ${x}: cannot backup $i as $i~
+ rm -f $tmp
+ res=1
+ continue
+ }
+ mv $tmp "$i" || cp -p $tmp "$i" 2>/dev/null || cp $tmp "$i" || {
+ echo ${x}: cannot create $i
+ rm -f $tmp
+ res=1
+ continue
+ }
+ rm -f $tmp
+ if test -n "$cpmod"; then
+ $cpmod "$i~" "$i" 2>/dev/null
+ elif test $writable -eq 0; then
+ chmod u-w $i 2>/dev/null
+ fi
+done
+exit $res
diff --git a/gnu/usr.bin/gzip/gzexe.1 b/gnu/usr.bin/gzip/gzexe.1
new file mode 100644
index 0000000..8b62cd6
--- /dev/null
+++ b/gnu/usr.bin/gzip/gzexe.1
@@ -0,0 +1,43 @@
+.TH GZEXE 1
+.SH NAME
+gzexe \- compress executable files in place
+.SH SYNOPSIS
+.B gzexe
+[ name ... ]
+.SH DESCRIPTION
+The
+.I gzexe
+utility allows you to compress executables in place and have them
+automatically uncompress and execute when you run them (at a penalty
+in performance). For example if you execute ``gzexe /bin/cat'' it
+will create the following two files:
+.nf
+.br
+ -r-xr-xr-x 1 root bin 9644 Feb 11 11:16 /bin/cat
+ -r-xr-xr-x 1 bin bin 24576 Nov 23 13:21 /bin/cat~
+.fi
+/bin/cat~ is the original file and /bin/cat is the self-uncompressing
+executable file. You can remove /bin/cat~ once you are sure that
+/bin/cat works properly.
+.PP
+This utility is most useful on systems with very small disks.
+.SH OPTIONS
+.TP
+.B \-d
+Decompress the given executables instead of compressing them.
+.SH "SEE ALSO"
+gzip(1), znew(1), zmore(1), zcmp(1), zforce(1)
+.SH CAVEATS
+The compressed executable is a shell script. This may create some
+security holes. In particular, the compressed executable relies
+on the PATH environment variable to find
+.I gzip
+and some other utilities
+.I (tail, chmod, ln, sleep).
+.SH "BUGS"
+.I gzexe
+attempts to retain the original file attributes on the compressed executable,
+but you may have to fix them manually in some cases, using
+.I chmod
+or
+.I chown.
diff --git a/gnu/usr.bin/gzip/gzip.1 b/gnu/usr.bin/gzip/gzip.1
new file mode 100644
index 0000000..5304d30
--- /dev/null
+++ b/gnu/usr.bin/gzip/gzip.1
@@ -0,0 +1,477 @@
+.PU
+.TH GZIP 1
+.SH NAME
+gzip, gunzip, zcat \- compress or expand files
+.SH SYNOPSIS
+.ll +8
+.B gzip
+.RB [ " \-acdfhlLnNrtvV19 " ]
+.RB [ \-S\ suffix ]
+[
+.I "name \&..."
+]
+.ll -8
+.br
+.B gunzip
+.RB [ " \-acfhlLnNrtvV " ]
+.RB [ \-S\ suffix ]
+[
+.I "name \&..."
+]
+.br
+.B zcat
+.RB [ " \-fhLV " ]
+[
+.I "name \&..."
+]
+.SH DESCRIPTION
+.I Gzip
+reduces the size of the named files using Lempel-Ziv coding (LZ77).
+Whenever possible,
+each file is replaced by one with the extension
+.B "\&.gz,"
+while keeping the same ownership modes, access and modification times.
+(The default extension is
+.B "\-gz"
+for VMS,
+.B "z"
+for MSDOS, OS/2 FAT, Windows NT FAT and Atari.)
+If no files are specified, or if a file name is "-", the standard input is
+compressed to the standard output.
+.I Gzip
+will only attempt to compress regular files.
+In particular, it will ignore symbolic links.
+.PP
+If the compressed file name is too long for its file system,
+.I gzip
+truncates it.
+.I Gzip
+attempts to truncate only the parts of the file name longer than 3 characters.
+(A part is delimited by dots.) If the name consists of small parts only,
+the longest parts are truncated. For example, if file names are limited
+to 14 characters, gzip.msdos.exe is compressed to gzi.msd.exe.gz.
+Names are not truncated on systems which do not have a limit on file name
+length.
+.PP
+By default,
+.I gzip
+keeps the original file name and timestamp in the compressed file. These
+are used when decompressing the file with the
+.B \-N
+option. This is useful when the compressed file name was truncated or
+when the time stamp was not preserved after a file transfer.
+.PP
+Compressed files can be restored to their original form using
+.I gzip -d
+or
+.I gunzip
+or
+.I zcat.
+If the original name saved in the compressed file is not suitable for its
+file system, a new name is constructed from the original one to make it
+legal.
+.PP
+.I gunzip
+takes a list of files on its command line and replaces each
+file whose name ends with .gz, -gz, .z, -z, _z or .Z
+and which begins with the correct magic number with an uncompressed
+file without the original extension.
+.I gunzip
+also recognizes the special extensions
+.B "\&.tgz"
+and
+.B "\&.taz"
+as shorthands for
+.B "\&.tar.gz"
+and
+.B "\&.tar.Z"
+respectively.
+When compressing,
+.I gzip
+uses the
+.B "\&.tgz"
+extension if necessary instead of truncating a file with a
+.B "\&.tar"
+extension.
+.PP
+.I gunzip
+can currently decompress files created by
+.I gzip, zip, compress, compress -H
+or
+.I pack.
+The detection of the input format is automatic. When using
+the first two formats,
+.I gunzip
+checks a 32 bit CRC. For
+.I pack, gunzip
+checks the uncompressed length. The standard
+.I compress
+format was not designed to allow consistency checks. However
+.I gunzip
+is sometimes able to detect a bad .Z file. If you get an error
+when uncompressing a .Z file, do not assume that the .Z file is
+correct simply because the standard
+.I uncompress
+does not complain. This generally means that the standard
+.I uncompress
+does not check its input, and happily generates garbage output.
+The SCO compress -H format (lzh compression method) does not include a CRC
+but also allows some consistency checks.
+.PP
+Files created by
+.I zip
+can be uncompressed by gzip only if they have a single member compressed
+with the 'deflation' method. This feature is only intended to help
+conversion of tar.zip files to the tar.gz format. To extract zip files
+with several members, use
+.I unzip
+instead of
+.I gunzip.
+.PP
+.I zcat
+is identical to
+.I gunzip
+.B \-c.
+(On some systems,
+.I zcat
+may be installed as
+.I gzcat
+to preserve the original link to
+.I compress.)
+.I zcat
+uncompresses either a list of files on the command line or its
+standard input and writes the uncompressed data on standard output.
+.I zcat
+will uncompress files that have the correct magic number whether
+they have a
+.B "\&.gz"
+suffix or not.
+.PP
+.I Gzip
+uses the Lempel-Ziv algorithm used in
+.I zip
+and PKZIP.
+The amount of compression obtained depends on the size of the
+input and the distribution of common substrings.
+Typically, text such as source code or English
+is reduced by 60\-70%.
+Compression is generally much better than that achieved by
+LZW (as used in
+.IR compress ),
+Huffman coding (as used in
+.IR pack ),
+or adaptive Huffman coding
+.RI ( compact ).
+.PP
+Compression is always performed, even if the compressed file is
+slightly larger than the original. The worst case expansion is
+a few bytes for the gzip file header, plus 5 bytes every 32K block,
+or an expansion ratio of 0.015% for large files. Note that the actual
+number of used disk blocks almost never increases.
+.I gzip
+preserves the mode, ownership and timestamps of files when compressing
+or decompressing.
+
+.SH OPTIONS
+.TP
+.B \-a --ascii
+Ascii text mode: convert end-of-lines using local conventions. This option
+is supported only on some non-Unix systems. For MSDOS, CR LF is converted
+to LF when compressing, and LF is converted to CR LF when decompressing.
+.TP
+.B \-c --stdout --to-stdout
+Write output on standard output; keep original files unchanged.
+If there are several input files, the output consists of a sequence of
+independently compressed members. To obtain better compression,
+concatenate all input files before compressing them.
+.TP
+.B \-d --decompress --uncompress
+Decompress.
+.TP
+.B \-f --force
+Force compression or decompression even if the file has multiple links
+or the corresponding file already exists, or if the compressed data
+is read from or written to a terminal. If the input data is not in
+a format recognized by
+.I gzip,
+and if the option --stdout is also given, copy the input data without change
+to the standard ouput: let
+.I zcat
+behave as
+.I cat.
+If
+.B \-f
+is not given,
+and when not running in the background,
+.I gzip
+prompts to verify whether an existing file should be overwritten.
+.TP
+.B \-h --help
+Display a help screen and quit.
+.TP
+.B \-l --list
+For each compressed file, list the following fields:
+
+ compressed size: size of the compressed file
+ uncompressed size: size of the uncompressed file
+ ratio: compression ratio (0.0% if unknown)
+ uncompressed_name: name of the uncompressed file
+
+The uncompressed size is given as -1 for files not in gzip format,
+such as compressed .Z files. To get the uncompressed size for such a file,
+you can use:
+
+ zcat file.Z | wc -c
+
+In combination with the --verbose option, the following fields are also
+displayed:
+
+ method: compression method
+ crc: the 32-bit CRC of the uncompressed data
+ date & time: time stamp for the uncompressed file
+
+The compression methods currently supported are deflate, compress, lzh
+(SCO compress -H) and pack. The crc is given as ffffffff for a file
+not in gzip format.
+
+With --name, the uncompressed name, date and time are
+those stored within the compress file if present.
+
+With --verbose, the size totals and compression ratio for all files
+is also displayed, unless some sizes are unknown. With --quiet,
+the title and totals lines are not displayed.
+.TP
+.B \-L --license
+Display the
+.I gzip
+license and quit.
+.TP
+.B \-n --no-name
+When compressing, do not save the original file name and time stamp by
+default. (The original name is always saved if the name had to be
+truncated.) When decompressing, do not restore the original file name
+if present (remove only the
+.I gzip
+suffix from the compressed file name) and do not restore the original
+time stamp if present (copy it from the compressed file). This option
+is the default when decompressing.
+.TP
+.B \-N --name
+When compressing, always save the original file name and time stamp; this
+is the default. When decompressing, restore the original file name and
+time stamp if present. This option is useful on systems which have
+a limit on file name length or when the time stamp has been lost after
+a file transfer.
+.TP
+.B \-q --quiet
+Suppress all warnings.
+.TP
+.B \-r --recursive
+Travel the directory structure recursively. If any of the file names
+specified on the command line are directories,
+.I gzip
+will descend into the directory and compress all the files it finds there
+(or decompress them in the case of
+.I gunzip
+).
+.TP
+.B \-S .suf --suffix .suf
+Use suffix .suf instead of .gz. Any suffix can be given, but suffixes
+other than .z and .gz should be avoided to avoid confusion when files
+are transferred to other systems. A null suffix forces gunzip to try
+decompression on all given files regardless of suffix, as in:
+
+ gunzip -S "" * (*.* for MSDOS)
+
+Previous versions of gzip used
+the .z suffix. This was changed to avoid a conflict with
+.IR pack "(1)".
+.TP
+.B \-t --test
+Test. Check the compressed file integrity.
+.TP
+.B \-v --verbose
+Verbose. Display the name and percentage reduction for each file compressed
+or decompressed.
+.TP
+.B \-V --version
+Version. Display the version number and compilation options then quit.
+.TP
+.B \-# --fast --best
+Regulate the speed of compression using the specified digit
+.IR # ,
+where
+.B \-1
+or
+.B \-\-fast
+indicates the fastest compression method (less compression)
+and
+.B \-9
+or
+.B \-\-best
+indicates the slowest compression method (best compression).
+The default compression level is
+.BR \-6
+(that is, biased towards high compression at expense of speed).
+.SH "ADVANCED USAGE"
+Multiple compressed files can be concatenated. In this case,
+.I gunzip
+will extract all members at once. For example:
+
+ gzip -c file1 > foo.gz
+ gzip -c file2 >> foo.gz
+
+Then
+ gunzip -c foo
+
+is equivalent to
+
+ cat file1 file2
+
+In case of damage to one member of a .gz file, other members can
+still be recovered (if the damaged member is removed). However,
+you can get better compression by compressing all members at once:
+
+ cat file1 file2 | gzip > foo.gz
+
+compresses better than
+
+ gzip -c file1 file2 > foo.gz
+
+If you want to recompress concatenated files to get better compression, do:
+
+ gzip -cd old.gz | gzip > new.gz
+
+If a compressed file consists of several members, the uncompressed
+size and CRC reported by the --list option applies to the last member
+only. If you need the uncompressed size for all members, you can use:
+
+ gzip -cd file.gz | wc -c
+
+If you wish to create a single archive file with multiple members so
+that members can later be extracted independently, use an archiver
+such as tar or zip. GNU tar supports the -z option to invoke gzip
+transparently. gzip is designed as a complement to tar, not as a
+replacement.
+.SH "ENVIRONMENT"
+The environment variable
+.B GZIP
+can hold a set of default options for
+.I gzip.
+These options are interpreted first and can be overwritten by
+explicit command line parameters. For example:
+ for sh: GZIP="-8v --name"; export GZIP
+ for csh: setenv GZIP "-8v --name"
+ for MSDOS: set GZIP=-8v --name
+
+On Vax/VMS, the name of the environment variable is GZIP_OPT, to
+avoid a conflict with the symbol set for invocation of the program.
+.SH "SEE ALSO"
+znew(1), zcmp(1), zmore(1), zforce(1), gzexe(1), compress(1)
+.SH "DIAGNOSTICS"
+Exit status is normally 0;
+if an error occurs, exit status is 1. If a warning occurs, exit status is 2.
+.PP
+Usage: gzip [-cdfhlLnNrtvV19] [-S suffix] [file ...]
+.in +8
+Invalid options were specified on the command line.
+.in -8
+.IR file :
+not in gzip format
+.in +8
+The file specified to
+.I gunzip
+has not been compressed.
+.in -8
+.IR file:
+Corrupt input. Use zcat to recover some data.
+.in +8
+The compressed file has been damaged. The data up to the point of failure
+can be recovered using
+.in +8
+zcat file > recover
+.in -16
+.IR file :
+compressed with
+.I xx
+bits, can only handle
+.I yy
+bits
+.in +8
+.I File
+was compressed (using LZW) by a program that could deal with
+more
+.I bits
+than the decompress code on this machine.
+Recompress the file with gzip, which compresses better and uses
+less memory.
+.in -8
+.IR file :
+already has .gz suffix -- no change
+.in +8
+The file is assumed to be already compressed.
+Rename the file and try again.
+.in -8
+.I file
+already exists; do you wish to overwrite (y or n)?
+.in +8
+Respond "y" if you want the output file to be replaced; "n" if not.
+.in -8
+gunzip: corrupt input
+.in +8
+A SIGSEGV violation was detected which usually means that the input file has
+been corrupted.
+.in -8
+.I "xx.x%"
+.in +8
+Percentage of the input saved by compression.
+(Relevant only for
+.BR \-v
+and
+.BR \-l \.)
+.in -8
+-- not a regular file or directory: ignored
+.in +8
+When the input file is not a regular file or directory,
+(e.g. a symbolic link, socket, FIFO, device file), it is
+left unaltered.
+.in -8
+-- has
+.I xx
+other links: unchanged
+.in +8
+The input file has links; it is left unchanged. See
+.IR ln "(1)"
+for more information. Use the
+.B \-f
+flag to force compression of multiply-linked files.
+.in -8
+.SH CAVEATS
+When writing compressed data to a tape, it is generally necessary to
+pad the output with zeroes up to a block boundary. When the data is
+read and the whole block is passed to
+.I gunzip
+for decompression,
+.I gunzip
+detects that there is extra trailing garbage after the compressed data
+and emits a warning by default. You have to use the --quiet option to
+suppress the warning. This option can be set in the
+.B GZIP
+environment variable as in:
+ for sh: GZIP="-q" tar -xfz --block-compress /dev/rst0
+ for csh: (setenv GZIP -q; tar -xfz --block-compr /dev/rst0
+
+In the above example, gzip is invoked implicitly by the -z option of
+GNU tar. Make sure that the same block size (-b option of tar) is used
+for reading and writing compressed data on tapes. (This example
+assumes you are using the GNU version of tar.)
+.SH BUGS
+The --list option reports incorrect sizes if they exceed 2 gigabytes.
+The --list option reports sizes as -1 and crc as ffffffff if the
+compressed file is on a non seekable media.
+
+In some rare cases, the --best option gives worse compression than
+the default compression level (-6). On some highly redundant files,
+.I compress
+compresses better than
+.I gzip.
diff --git a/gnu/usr.bin/gzip/gzip.c b/gnu/usr.bin/gzip/gzip.c
new file mode 100644
index 0000000..846b69e
--- /dev/null
+++ b/gnu/usr.bin/gzip/gzip.c
@@ -0,0 +1,1744 @@
+/* gzip (GNU zip) -- compress files with zip algorithm and 'compress' interface
+ * Copyright (C) 1992-1993 Jean-loup Gailly
+ * The unzip code was written and put in the public domain by Mark Adler.
+ * Portions of the lzw code are derived from the public domain 'compress'
+ * written by Spencer Thomas, Joe Orost, James Woods, Jim McKie, Steve Davies,
+ * Ken Turkowski, Dave Mack and Peter Jannesen.
+ *
+ * See the license_msg below and the file COPYING for the software license.
+ * See the file algorithm.doc for the compression algorithms and file formats.
+ */
+
+static char *license_msg[] = {
+" Copyright (C) 1992-1993 Jean-loup Gailly",
+" This program is free software; you can redistribute it and/or modify",
+" it under the terms of the GNU General Public License as published by",
+" the Free Software Foundation; either version 2, or (at your option)",
+" any later version.",
+"",
+" This program is distributed in the hope that it will be useful,",
+" but WITHOUT ANY WARRANTY; without even the implied warranty of",
+" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the",
+" GNU General Public License for more details.",
+"",
+" You should have received a copy of the GNU General Public License",
+" along with this program; if not, write to the Free Software",
+" Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.",
+0};
+
+/* Compress files with zip algorithm and 'compress' interface.
+ * See usage() and help() functions below for all options.
+ * Outputs:
+ * file.gz: compressed file with same mode, owner, and utimes
+ * or stdout with -c option or if stdin used as input.
+ * If the output file name had to be truncated, the original name is kept
+ * in the compressed file.
+ * On MSDOS, file.tmp -> file.tmz. On VMS, file.tmp -> file.tmp-gz.
+ *
+ * Using gz on MSDOS would create too many file name conflicts. For
+ * example, foo.txt -> foo.tgz (.tgz must be reserved as shorthand for
+ * tar.gz). Similarly, foo.dir and foo.doc would both be mapped to foo.dgz.
+ * I also considered 12345678.txt -> 12345txt.gz but this truncates the name
+ * too heavily. There is no ideal solution given the MSDOS 8+3 limitation.
+ *
+ * For the meaning of all compilation flags, see comments in Makefile.in.
+ */
+
+#ifdef RCSID
+static char rcsid[] = "$Id: gzip.c,v 1.3 1993/10/14 00:32:48 nate Exp $";
+#endif
+
+#include <ctype.h>
+#include <sys/types.h>
+#include <signal.h>
+#include <sys/stat.h>
+#include <errno.h>
+
+#include "tailor.h"
+#include "gzip.h"
+#include "lzw.h"
+#include "revision.h"
+#include "getopt.h"
+
+ /* configuration */
+
+#ifdef NO_TIME_H
+# include <sys/time.h>
+#else
+# include <time.h>
+#endif
+
+#ifndef NO_FCNTL_H
+# include <fcntl.h>
+#endif
+
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+#if defined(STDC_HEADERS) || !defined(NO_STDLIB_H)
+# include <stdlib.h>
+#else
+ extern int errno;
+#endif
+
+#if defined(DIRENT)
+# include <dirent.h>
+ typedef struct dirent dir_type;
+# define NLENGTH(dirent) ((int)strlen((dirent)->d_name))
+# define DIR_OPT "DIRENT"
+#else
+# define NLENGTH(dirent) ((dirent)->d_namlen)
+# ifdef SYSDIR
+# include <sys/dir.h>
+ typedef struct direct dir_type;
+# define DIR_OPT "SYSDIR"
+# else
+# ifdef SYSNDIR
+# include <sys/ndir.h>
+ typedef struct direct dir_type;
+# define DIR_OPT "SYSNDIR"
+# else
+# ifdef NDIR
+# include <ndir.h>
+ typedef struct direct dir_type;
+# define DIR_OPT "NDIR"
+# else
+# define NO_DIR
+# define DIR_OPT "NO_DIR"
+# endif
+# endif
+# endif
+#endif
+
+#ifndef NO_UTIME
+# ifndef NO_UTIME_H
+# include <utime.h>
+# define TIME_OPT "UTIME"
+# else
+# ifdef HAVE_SYS_UTIME_H
+# include <sys/utime.h>
+# define TIME_OPT "SYS_UTIME"
+# else
+ struct utimbuf {
+ time_t actime;
+ time_t modtime;
+ };
+# define TIME_OPT ""
+# endif
+# endif
+#else
+# define TIME_OPT "NO_UTIME"
+#endif
+
+#if !defined(S_ISDIR) && defined(S_IFDIR)
+# define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
+#endif
+#if !defined(S_ISREG) && defined(S_IFREG)
+# define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
+#endif
+
+typedef RETSIGTYPE (*sig_type) OF((int));
+
+#ifndef O_BINARY
+# define O_BINARY 0 /* creation mode for open() */
+#endif
+
+#ifndef O_CREAT
+ /* Pure BSD system? */
+# include <sys/file.h>
+# ifndef O_CREAT
+# define O_CREAT FCREAT
+# endif
+# ifndef O_EXCL
+# define O_EXCL FEXCL
+# endif
+#endif
+
+#ifndef S_IRUSR
+# define S_IRUSR 0400
+#endif
+#ifndef S_IWUSR
+# define S_IWUSR 0200
+#endif
+#define RW_USER (S_IRUSR | S_IWUSR) /* creation mode for open() */
+
+#ifndef MAX_PATH_LEN
+# define MAX_PATH_LEN 1024 /* max pathname length */
+#endif
+
+#ifndef SEEK_END
+# define SEEK_END 2
+#endif
+
+#ifdef NO_OFF_T
+ typedef long off_t;
+ off_t lseek OF((int fd, off_t offset, int whence));
+#endif
+
+/* Separator for file name parts (see shorten_name()) */
+#ifdef NO_MULTIPLE_DOTS
+# define PART_SEP "-"
+#else
+# define PART_SEP "."
+#endif
+
+ /* global buffers */
+
+DECLARE(uch, inbuf, INBUFSIZ +INBUF_EXTRA);
+DECLARE(uch, outbuf, OUTBUFSIZ+OUTBUF_EXTRA);
+DECLARE(ush, d_buf, DIST_BUFSIZE);
+DECLARE(uch, window, 2L*WSIZE);
+#ifndef MAXSEG_64K
+ DECLARE(ush, tab_prefix, 1L<<BITS);
+#else
+ DECLARE(ush, tab_prefix0, 1L<<(BITS-1));
+ DECLARE(ush, tab_prefix1, 1L<<(BITS-1));
+#endif
+
+ /* local variables */
+
+int ascii = 0; /* convert end-of-lines to local OS conventions */
+int to_stdout = 0; /* output to stdout (-c) */
+int decompress = 0; /* decompress (-d) */
+int force = 0; /* don't ask questions, compress links (-f) */
+int no_name = -1; /* don't save or restore the original file name */
+int no_time = -1; /* don't save or restore the original file time */
+int recursive = 0; /* recurse through directories (-r) */
+int list = 0; /* list the file contents (-l) */
+int verbose = 0; /* be verbose (-v) */
+int quiet = 0; /* be very quiet (-q) */
+int do_lzw = 0; /* generate output compatible with old compress (-Z) */
+int test = 0; /* test .gz file integrity */
+int foreground; /* set if program run in foreground */
+char *progname; /* program name */
+int maxbits = BITS; /* max bits per code for LZW */
+int method = DEFLATED;/* compression method */
+int level = 6; /* compression level */
+int exit_code = OK; /* program exit code */
+int save_orig_name; /* set if original name must be saved */
+int last_member; /* set for .zip and .Z files */
+int part_nb; /* number of parts in .gz file */
+long time_stamp; /* original time stamp (modification time) */
+long ifile_size; /* input file size, -1 for devices (debug only) */
+char *env; /* contents of GZIP env variable */
+char **args = NULL; /* argv pointer if GZIP env variable defined */
+char z_suffix[MAX_SUFFIX+1]; /* default suffix (can be set with --suffix) */
+int z_len; /* strlen(z_suffix) */
+
+long bytes_in; /* number of input bytes */
+long bytes_out; /* number of output bytes */
+long total_in = 0; /* input bytes for all files */
+long total_out = 0; /* output bytes for all files */
+char ifname[MAX_PATH_LEN]; /* input file name */
+char ofname[MAX_PATH_LEN]; /* output file name */
+int remove_ofname = 0; /* remove output file on error */
+struct stat istat; /* status for input file */
+int ifd; /* input file descriptor */
+int ofd; /* output file descriptor */
+unsigned insize; /* valid bytes in inbuf */
+unsigned inptr; /* index of next byte to be processed in inbuf */
+unsigned outcnt; /* bytes in output buffer */
+
+struct option longopts[] =
+{
+ /* { name has_arg *flag val } */
+ {"ascii", 0, 0, 'a'}, /* ascii text mode */
+ {"to-stdout", 0, 0, 'c'}, /* write output on standard output */
+ {"stdout", 0, 0, 'c'}, /* write output on standard output */
+ {"decompress", 0, 0, 'd'}, /* decompress */
+ {"uncompress", 0, 0, 'd'}, /* decompress */
+ /* {"encrypt", 0, 0, 'e'}, encrypt */
+ {"force", 0, 0, 'f'}, /* force overwrite of output file */
+ {"help", 0, 0, 'h'}, /* give help */
+ /* {"pkzip", 0, 0, 'k'}, force output in pkzip format */
+ {"list", 0, 0, 'l'}, /* list .gz file contents */
+ {"license", 0, 0, 'L'}, /* display software license */
+ {"no-name", 0, 0, 'n'}, /* don't save or restore original name & time */
+ {"name", 0, 0, 'N'}, /* save or restore original name & time */
+ {"quiet", 0, 0, 'q'}, /* quiet mode */
+ {"silent", 0, 0, 'q'}, /* quiet mode */
+ {"recursive", 0, 0, 'r'}, /* recurse through directories */
+ {"suffix", 1, 0, 'S'}, /* use given suffix instead of .gz */
+ {"test", 0, 0, 't'}, /* test compressed file integrity */
+ {"no-time", 0, 0, 'T'}, /* don't save or restore the time stamp */
+ {"verbose", 0, 0, 'v'}, /* verbose mode */
+ {"version", 0, 0, 'V'}, /* display version number */
+ {"fast", 0, 0, '1'}, /* compress faster */
+ {"best", 0, 0, '9'}, /* compress better */
+ {"lzw", 0, 0, 'Z'}, /* make output compatible with old compress */
+ {"bits", 1, 0, 'b'}, /* max number of bits per code (implies -Z) */
+ { 0, 0, 0, 0 }
+};
+
+/* local functions */
+
+local void usage OF((void));
+local void help OF((void));
+local void license OF((void));
+local void version OF((void));
+local void treat_stdin OF((void));
+local void treat_file OF((char *iname));
+local int create_outfile OF((void));
+local int do_stat OF((char *name, struct stat *sbuf));
+local char *get_suffix OF((char *name));
+local int get_istat OF((char *iname, struct stat *sbuf));
+local int make_ofname OF((void));
+local int same_file OF((struct stat *stat1, struct stat *stat2));
+local int name_too_long OF((char *name, struct stat *statb));
+local void shorten_name OF((char *name));
+local int get_method OF((int in));
+local void do_list OF((int ifd, int method));
+local int check_ofname OF((void));
+local void copy_stat OF((struct stat *ifstat));
+local void do_exit OF((int exitcode));
+ int main OF((int argc, char **argv));
+int (*work) OF((int infile, int outfile)) = zip; /* function to call */
+
+#ifndef NO_DIR
+local void treat_dir OF((char *dir));
+#endif
+#ifndef NO_UTIME
+local void reset_times OF((char *name, struct stat *statb));
+#endif
+
+#define strequ(s1, s2) (strcmp((s1),(s2)) == 0)
+
+/* ======================================================================== */
+local void usage()
+{
+ fprintf(stderr, "usage: %s [-%scdfhlLnN%stvV19] [-S suffix] [file ...]\n",
+ progname,
+#if O_BINARY
+ "a",
+#else
+ "",
+#endif
+#ifdef NO_DIR
+ ""
+#else
+ "r"
+#endif
+ );
+}
+
+/* ======================================================================== */
+local void help()
+{
+ static char *help_msg[] = {
+#if O_BINARY
+ " -a --ascii ascii text; convert end-of-lines using local conventions",
+#endif
+ " -c --stdout write on standard output, keep original files unchanged",
+ " -d --decompress decompress",
+/* -e --encrypt encrypt */
+ " -f --force force overwrite of output file and compress links",
+ " -h --help give this help",
+/* -k --pkzip force output in pkzip format */
+ " -l --list list compressed file contents",
+ " -L --license display software license",
+#ifdef UNDOCUMENTED
+ " -m --no-time do not save or restore the original modification time",
+ " -M --time save or restore the original modification time",
+#endif
+ " -n --no-name do not save or restore the original name and time stamp",
+ " -N --name save or restore the original name and time stamp",
+ " -q --quiet suppress all warnings",
+#ifndef NO_DIR
+ " -r --recursive operate recursively on directories",
+#endif
+ " -S .suf --suffix .suf use suffix .suf on compressed files",
+ " -t --test test compressed file integrity",
+ " -v --verbose verbose mode",
+ " -V --version display version number",
+ " -1 --fast compress faster",
+ " -9 --best compress better",
+#ifdef LZW
+ " -Z --lzw produce output compatible with old compress",
+ " -b --bits maxbits max number of bits per code (implies -Z)",
+#endif
+ " file... files to (de)compress. If none given, use standard input.",
+ 0};
+ char **p = help_msg;
+
+ fprintf(stderr,"%s %s (%s)\n", progname, VERSION, REVDATE);
+ usage();
+ while (*p) fprintf(stderr, "%s\n", *p++);
+}
+
+/* ======================================================================== */
+local void license()
+{
+ char **p = license_msg;
+
+ fprintf(stderr,"%s %s (%s)\n", progname, VERSION, REVDATE);
+ while (*p) fprintf(stderr, "%s\n", *p++);
+}
+
+/* ======================================================================== */
+local void version()
+{
+ fprintf(stderr,"%s %s (%s)\n", progname, VERSION, REVDATE);
+
+ fprintf(stderr, "Compilation options:\n%s %s ", DIR_OPT, TIME_OPT);
+#ifdef STDC_HEADERS
+ fprintf(stderr, "STDC_HEADERS ");
+#endif
+#ifdef HAVE_UNISTD_H
+ fprintf(stderr, "HAVE_UNISTD_H ");
+#endif
+#ifdef NO_MEMORY_H
+ fprintf(stderr, "NO_MEMORY_H ");
+#endif
+#ifdef NO_STRING_H
+ fprintf(stderr, "NO_STRING_H ");
+#endif
+#ifdef NO_SYMLINK
+ fprintf(stderr, "NO_SYMLINK ");
+#endif
+#ifdef NO_MULTIPLE_DOTS
+ fprintf(stderr, "NO_MULTIPLE_DOTS ");
+#endif
+#ifdef NO_CHOWN
+ fprintf(stderr, "NO_CHOWN ");
+#endif
+#ifdef PROTO
+ fprintf(stderr, "PROTO ");
+#endif
+#ifdef ASMV
+ fprintf(stderr, "ASMV ");
+#endif
+#ifdef DEBUG
+ fprintf(stderr, "DEBUG ");
+#endif
+#ifdef DYN_ALLOC
+ fprintf(stderr, "DYN_ALLOC ");
+#endif
+#ifdef MAXSEG_64K
+ fprintf(stderr, "MAXSEG_64K");
+#endif
+ fprintf(stderr, "\n");
+}
+
+/* ======================================================================== */
+int main (argc, argv)
+ int argc;
+ char **argv;
+{
+ int file_count; /* number of files to precess */
+ int proglen; /* length of progname */
+ int optc; /* current option */
+
+ EXPAND(argc, argv); /* wild card expansion if necessary */
+
+ progname = basename(argv[0]);
+ proglen = strlen(progname);
+
+ /* Suppress .exe for MSDOS, OS/2 and VMS: */
+ if (proglen > 4 && strequ(progname+proglen-4, ".exe")) {
+ progname[proglen-4] = '\0';
+ }
+
+ /* Add options in GZIP environment variable if there is one */
+ env = add_envopt(&argc, &argv, OPTIONS_VAR);
+ if (env != NULL) args = argv;
+
+ foreground = signal(SIGINT, SIG_IGN) != SIG_IGN;
+ if (foreground) {
+ (void) signal (SIGINT, (sig_type)abort_gzip);
+ }
+#ifdef SIGTERM
+ if (signal(SIGTERM, SIG_IGN) != SIG_IGN) {
+ (void) signal(SIGTERM, (sig_type)abort_gzip);
+ }
+#endif
+#ifdef SIGHUP
+ if (signal(SIGHUP, SIG_IGN) != SIG_IGN) {
+ (void) signal(SIGHUP, (sig_type)abort_gzip);
+ }
+#endif
+
+#ifndef GNU_STANDARD
+ /* For compatibility with old compress, use program name as an option.
+ * If you compile with -DGNU_STANDARD, this program will behave as
+ * gzip even if it is invoked under the name gunzip or zcat.
+ *
+ * Systems which do not support links can still use -d or -dc.
+ * Ignore an .exe extension for MSDOS, OS/2 and VMS.
+ */
+ if ( strncmp(progname, "un", 2) == 0 /* ungzip, uncompress */
+ || strncmp(progname, "gun", 3) == 0) { /* gunzip */
+ decompress = 1;
+ } else if (strequ(progname+1, "cat") /* zcat, pcat, gcat */
+ || strequ(progname, "gzcat")) { /* gzcat */
+ decompress = to_stdout = 1;
+ }
+#endif
+
+ strncpy(z_suffix, Z_SUFFIX, sizeof(z_suffix)-1);
+ z_len = strlen(z_suffix);
+
+ while ((optc = getopt_long (argc, argv, "ab:cdfhH?lLmMnNqrS:tvVZ123456789",
+ longopts, (int *)0)) != EOF) {
+ switch (optc) {
+ case 'a':
+ ascii = 1; break;
+ case 'b':
+ maxbits = atoi(optarg);
+ break;
+ case 'c':
+ to_stdout = 1; break;
+ case 'd':
+ decompress = 1; break;
+ case 'f':
+ force++; break;
+ case 'h': case 'H': case '?':
+ help(); do_exit(OK); break;
+ case 'l':
+ list = decompress = to_stdout = 1; break;
+ case 'L':
+ license(); do_exit(OK); break;
+ case 'm': /* undocumented, may change later */
+ no_time = 1; break;
+ case 'M': /* undocumented, may change later */
+ no_time = 0; break;
+ case 'n':
+ no_name = no_time = 1; break;
+ case 'N':
+ no_name = no_time = 0; break;
+ case 'q':
+ quiet = 1; verbose = 0; break;
+ case 'r':
+#ifdef NO_DIR
+ fprintf(stderr, "%s: -r not supported on this system\n", progname);
+ usage();
+ do_exit(ERROR); break;
+#else
+ recursive = 1; break;
+#endif
+ case 'S':
+#ifdef NO_MULTIPLE_DOTS
+ if (*optarg == '.') optarg++;
+#endif
+ z_len = strlen(optarg);
+ strcpy(z_suffix, optarg);
+ break;
+ case 't':
+ test = decompress = to_stdout = 1;
+ break;
+ case 'v':
+ verbose++; quiet = 0; break;
+ case 'V':
+ version(); do_exit(OK); break;
+ case 'Z':
+#ifdef LZW
+ do_lzw = 1; break;
+#else
+ fprintf(stderr, "%s: -Z not supported in this version\n",
+ progname);
+ usage();
+ do_exit(ERROR); break;
+#endif
+ case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ level = optc - '0';
+ break;
+ default:
+ /* Error message already emitted by getopt_long. */
+ usage();
+ do_exit(ERROR);
+ }
+ } /* loop on all arguments */
+
+ /* By default, save name and timestamp on compression but do not
+ * restore them on decompression.
+ */
+ if (no_time < 0) no_time = decompress;
+ if (no_name < 0) no_name = decompress;
+
+ file_count = argc - optind;
+
+#if O_BINARY
+#else
+ if (ascii && !quiet) {
+ fprintf(stderr, "%s: option --ascii ignored on this system\n",
+ progname);
+ }
+#endif
+ if ((z_len == 0 && !decompress) || z_len > MAX_SUFFIX) {
+ fprintf(stderr, "%s: incorrect suffix '%s'\n",
+ progname, optarg);
+ do_exit(ERROR);
+ }
+ if (do_lzw && !decompress) work = lzw;
+
+ /* Allocate all global buffers (for DYN_ALLOC option) */
+ ALLOC(uch, inbuf, INBUFSIZ +INBUF_EXTRA);
+ ALLOC(uch, outbuf, OUTBUFSIZ+OUTBUF_EXTRA);
+ ALLOC(ush, d_buf, DIST_BUFSIZE);
+ ALLOC(uch, window, 2L*WSIZE);
+#ifndef MAXSEG_64K
+ ALLOC(ush, tab_prefix, 1L<<BITS);
+#else
+ ALLOC(ush, tab_prefix0, 1L<<(BITS-1));
+ ALLOC(ush, tab_prefix1, 1L<<(BITS-1));
+#endif
+
+ /* And get to work */
+ if (file_count != 0) {
+ if (to_stdout && !test && !list && (!decompress || !ascii)) {
+ SET_BINARY_MODE(fileno(stdout));
+ }
+ while (optind < argc) {
+ treat_file(argv[optind++]);
+ }
+ } else { /* Standard input */
+ treat_stdin();
+ }
+ if (list && !quiet && file_count > 1) {
+ do_list(-1, -1); /* print totals */
+ }
+ do_exit(exit_code);
+ return exit_code; /* just to avoid lint warning */
+}
+
+/* ========================================================================
+ * Compress or decompress stdin
+ */
+local void treat_stdin()
+{
+ if (!force && !list &&
+ isatty(fileno((FILE *)(decompress ? stdin : stdout)))) {
+ /* Do not send compressed data to the terminal or read it from
+ * the terminal. We get here when user invoked the program
+ * without parameters, so be helpful. According to the GNU standards:
+ *
+ * If there is one behavior you think is most useful when the output
+ * is to a terminal, and another that you think is most useful when
+ * the output is a file or a pipe, then it is usually best to make
+ * the default behavior the one that is useful with output to a
+ * terminal, and have an option for the other behavior.
+ *
+ * Here we use the --force option to get the other behavior.
+ */
+ fprintf(stderr,
+ "%s: compressed data not %s a terminal. Use -f to force %scompression.\n",
+ progname, decompress ? "read from" : "written to",
+ decompress ? "de" : "");
+ fprintf(stderr,"For help, type: %s -h\n", progname);
+ do_exit(ERROR);
+ }
+
+ if (decompress || !ascii) {
+ SET_BINARY_MODE(fileno(stdin));
+ }
+ if (!test && !list && (!decompress || !ascii)) {
+ SET_BINARY_MODE(fileno(stdout));
+ }
+ strcpy(ifname, "stdin");
+ strcpy(ofname, "stdout");
+
+ /* Get the time stamp on the input file. */
+ time_stamp = 0; /* time unknown by default */
+
+#ifndef NO_STDIN_FSTAT
+ if (list || !no_time) {
+ if (fstat(fileno(stdin), &istat) != 0) {
+ error("fstat(stdin)");
+ }
+# ifdef NO_PIPE_TIMESTAMP
+ if (S_ISREG(istat.st_mode))
+# endif
+ time_stamp = istat.st_mtime;
+#endif /* NO_STDIN_FSTAT */
+ }
+ ifile_size = -1L; /* convention for unknown size */
+
+ clear_bufs(); /* clear input and output buffers */
+ to_stdout = 1;
+ part_nb = 0;
+
+ if (decompress) {
+ method = get_method(ifd);
+ if (method < 0) {
+ do_exit(exit_code); /* error message already emitted */
+ }
+ }
+ if (list) {
+ do_list(ifd, method);
+ return;
+ }
+
+ /* Actually do the compression/decompression. Loop over zipped members.
+ */
+ for (;;) {
+ if ((*work)(fileno(stdin), fileno(stdout)) != OK) return;
+
+ if (!decompress || last_member || inptr == insize) break;
+ /* end of file */
+
+ method = get_method(ifd);
+ if (method < 0) return; /* error message already emitted */
+ bytes_out = 0; /* required for length check */
+ }
+
+ if (verbose) {
+ if (test) {
+ fprintf(stderr, " OK\n");
+
+ } else if (!decompress) {
+ display_ratio(bytes_in-(bytes_out-header_bytes), bytes_in, stderr);
+ fprintf(stderr, "\n");
+#ifdef DISPLAY_STDIN_RATIO
+ } else {
+ display_ratio(bytes_out-(bytes_in-header_bytes), bytes_out,stderr);
+ fprintf(stderr, "\n");
+#endif
+ }
+ }
+}
+
+/* ========================================================================
+ * Compress or decompress the given file
+ */
+local void treat_file(iname)
+ char *iname;
+{
+ /* Accept "-" as synonym for stdin */
+ if (strequ(iname, "-")) {
+ int cflag = to_stdout;
+ treat_stdin();
+ to_stdout = cflag;
+ return;
+ }
+
+ /* Check if the input file is present, set ifname and istat: */
+ if (get_istat(iname, &istat) != OK) return;
+
+ /* If the input name is that of a directory, recurse or ignore: */
+ if (S_ISDIR(istat.st_mode)) {
+#ifndef NO_DIR
+ if (recursive) {
+ struct stat st;
+ st = istat;
+ treat_dir(iname);
+ /* Warning: ifname is now garbage */
+# ifndef NO_UTIME
+ reset_times (iname, &st);
+# endif
+ } else
+#endif
+ WARN((stderr,"%s: %s is a directory -- ignored\n", progname, ifname));
+ return;
+ }
+ if (!S_ISREG(istat.st_mode)) {
+ WARN((stderr,
+ "%s: %s is not a directory or a regular file - ignored\n",
+ progname, ifname));
+ return;
+ }
+ if (istat.st_nlink > 1 && !to_stdout && !force) {
+ WARN((stderr, "%s: %s has %d other link%c -- unchanged\n",
+ progname, ifname,
+ (int)istat.st_nlink - 1, istat.st_nlink > 2 ? 's' : ' '));
+ return;
+ }
+
+ ifile_size = istat.st_size;
+ time_stamp = no_time && !list ? 0 : istat.st_mtime;
+
+ /* Generate output file name. For -r and (-t or -l), skip files
+ * without a valid gzip suffix (check done in make_ofname).
+ */
+ if (to_stdout && !list && !test) {
+ strcpy(ofname, "stdout");
+
+ } else if (make_ofname() != OK) {
+ return;
+ }
+
+ /* Open the input file and determine compression method. The mode
+ * parameter is ignored but required by some systems (VMS) and forbidden
+ * on other systems (MacOS).
+ */
+ ifd = OPEN(ifname, ascii && !decompress ? O_RDONLY : O_RDONLY | O_BINARY,
+ RW_USER);
+ if (ifd == -1) {
+ fprintf(stderr, "%s: ", progname);
+ perror(ifname);
+ exit_code = ERROR;
+ return;
+ }
+ clear_bufs(); /* clear input and output buffers */
+ part_nb = 0;
+
+ if (decompress) {
+ method = get_method(ifd); /* updates ofname if original given */
+ if (method < 0) {
+ close(ifd);
+ return; /* error message already emitted */
+ }
+ }
+ if (list) {
+ do_list(ifd, method);
+ close(ifd);
+ return;
+ }
+
+ /* If compressing to a file, check if ofname is not ambiguous
+ * because the operating system truncates names. Otherwise, generate
+ * a new ofname and save the original name in the compressed file.
+ */
+ if (to_stdout) {
+ ofd = fileno(stdout);
+ /* keep remove_ofname as zero */
+ } else {
+ if (create_outfile() != OK) return;
+
+ if (!decompress && save_orig_name && !verbose && !quiet) {
+ fprintf(stderr, "%s: %s compressed to %s\n",
+ progname, ifname, ofname);
+ }
+ }
+ /* Keep the name even if not truncated except with --no-name: */
+ if (!save_orig_name) save_orig_name = !no_name;
+
+ if (verbose) {
+ fprintf(stderr, "%s:\t%s", ifname, (int)strlen(ifname) >= 15 ?
+ "" : ((int)strlen(ifname) >= 7 ? "\t" : "\t\t"));
+ }
+
+ /* Actually do the compression/decompression. Loop over zipped members.
+ */
+ for (;;) {
+ if ((*work)(ifd, ofd) != OK) {
+ method = -1; /* force cleanup */
+ break;
+ }
+ if (!decompress || last_member || inptr == insize) break;
+ /* end of file */
+
+ method = get_method(ifd);
+ if (method < 0) break; /* error message already emitted */
+ bytes_out = 0; /* required for length check */
+ }
+
+ close(ifd);
+ if (!to_stdout && close(ofd)) {
+ write_error();
+ }
+ if (method == -1) {
+ if (!to_stdout) unlink (ofname);
+ return;
+ }
+ /* Display statistics */
+ if(verbose) {
+ if (test) {
+ fprintf(stderr, " OK");
+ } else if (decompress) {
+ display_ratio(bytes_out-(bytes_in-header_bytes), bytes_out,stderr);
+ } else {
+ display_ratio(bytes_in-(bytes_out-header_bytes), bytes_in, stderr);
+ }
+ if (!test && !to_stdout) {
+ fprintf(stderr, " -- replaced with %s", ofname);
+ }
+ fprintf(stderr, "\n");
+ }
+ /* Copy modes, times, ownership, and remove the input file */
+ if (!to_stdout) {
+ copy_stat(&istat);
+ }
+}
+
+/* ========================================================================
+ * Create the output file. Return OK or ERROR.
+ * Try several times if necessary to avoid truncating the z_suffix. For
+ * example, do not create a compressed file of name "1234567890123."
+ * Sets save_orig_name to true if the file name has been truncated.
+ * IN assertions: the input file has already been open (ifd is set) and
+ * ofname has already been updated if there was an original name.
+ * OUT assertions: ifd and ofd are closed in case of error.
+ */
+local int create_outfile()
+{
+ struct stat ostat; /* stat for ofname */
+ int flags = O_WRONLY | O_CREAT | O_EXCL | O_BINARY;
+
+ if (ascii && decompress) {
+ flags &= ~O_BINARY; /* force ascii text mode */
+ }
+ for (;;) {
+ /* Make sure that ofname is not an existing file */
+ if (check_ofname() != OK) {
+ close(ifd);
+ return ERROR;
+ }
+ /* Create the output file */
+ remove_ofname = 1;
+ ofd = OPEN(ofname, flags, RW_USER);
+ if (ofd == -1) {
+ perror(ofname);
+ close(ifd);
+ exit_code = ERROR;
+ return ERROR;
+ }
+
+ /* Check for name truncation on new file (1234567890123.gz) */
+#ifdef NO_FSTAT
+ if (stat(ofname, &ostat) != 0) {
+#else
+ if (fstat(ofd, &ostat) != 0) {
+#endif
+ fprintf(stderr, "%s: ", progname);
+ perror(ofname);
+ close(ifd); close(ofd);
+ unlink(ofname);
+ exit_code = ERROR;
+ return ERROR;
+ }
+ if (!name_too_long(ofname, &ostat)) return OK;
+
+ if (decompress) {
+ /* name might be too long if an original name was saved */
+ WARN((stderr, "%s: %s: warning, name truncated\n",
+ progname, ofname));
+ return OK;
+ }
+ close(ofd);
+ unlink(ofname);
+#ifdef NO_MULTIPLE_DOTS
+ /* Should never happen, see check_ofname() */
+ fprintf(stderr, "%s: %s: name too long\n", progname, ofname);
+ do_exit(ERROR);
+#endif
+ shorten_name(ofname);
+ }
+}
+
+/* ========================================================================
+ * Use lstat if available, except for -c or -f. Use stat otherwise.
+ * This allows links when not removing the original file.
+ */
+local int do_stat(name, sbuf)
+ char *name;
+ struct stat *sbuf;
+{
+ errno = 0;
+#if (defined(S_IFLNK) || defined (S_ISLNK)) && !defined(NO_SYMLINK)
+ if (!to_stdout && !force) {
+ return lstat(name, sbuf);
+ }
+#endif
+ return stat(name, sbuf);
+}
+
+/* ========================================================================
+ * Return a pointer to the 'z' suffix of a file name, or NULL. For all
+ * systems, ".gz", ".z", ".Z", ".taz", ".tgz", "-gz", "-z" and "_z" are
+ * accepted suffixes, in addition to the value of the --suffix option.
+ * ".tgz" is a useful convention for tar.z files on systems limited
+ * to 3 characters extensions. On such systems, ".?z" and ".??z" are
+ * also accepted suffixes. For Unix, we do not want to accept any
+ * .??z suffix as indicating a compressed file; some people use .xyz
+ * to denote volume data.
+ * On systems allowing multiple versions of the same file (such as VMS),
+ * this function removes any version suffix in the given name.
+ */
+local char *get_suffix(name)
+ char *name;
+{
+ int nlen, slen;
+ char suffix[MAX_SUFFIX+3]; /* last chars of name, forced to lower case */
+ static char *known_suffixes[] =
+ {z_suffix, ".gz", ".z", ".taz", ".tgz", "-gz", "-z", "_z",
+#ifdef MAX_EXT_CHARS
+ "z",
+#endif
+ NULL};
+ char **suf = known_suffixes;
+
+ if (strequ(z_suffix, "z")) suf++; /* check long suffixes first */
+
+#ifdef SUFFIX_SEP
+ /* strip a version number from the file name */
+ {
+ char *v = strrchr(name, SUFFIX_SEP);
+ if (v != NULL) *v = '\0';
+ }
+#endif
+ nlen = strlen(name);
+ if (nlen <= MAX_SUFFIX+2) {
+ strcpy(suffix, name);
+ } else {
+ strcpy(suffix, name+nlen-MAX_SUFFIX-2);
+ }
+ strlwr(suffix);
+ slen = strlen(suffix);
+ do {
+ int s = strlen(*suf);
+ if (slen > s && suffix[slen-s-1] != PATH_SEP
+ && strequ(suffix + slen - s, *suf)) {
+ return name+nlen-s;
+ }
+ } while (*++suf != NULL);
+
+ return NULL;
+}
+
+
+/* ========================================================================
+ * Set ifname to the input file name (with a suffix appended if necessary)
+ * and istat to its stats. For decompression, if no file exists with the
+ * original name, try adding successively z_suffix, .gz, .z, -z and .Z.
+ * For MSDOS, we try only z_suffix and z.
+ * Return OK or ERROR.
+ */
+local int get_istat(iname, sbuf)
+ char *iname;
+ struct stat *sbuf;
+{
+ int ilen; /* strlen(ifname) */
+ static char *suffixes[] = {z_suffix, ".gz", ".z", "-z", ".Z", NULL};
+ char **suf = suffixes;
+ char *s;
+#ifdef NO_MULTIPLE_DOTS
+ char *dot; /* pointer to ifname extension, or NULL */
+#endif
+
+ strcpy(ifname, iname);
+
+ /* If input file exists, return OK. */
+ if (do_stat(ifname, sbuf) == 0) return OK;
+
+ if (!decompress || errno != ENOENT) {
+ perror(ifname);
+ exit_code = ERROR;
+ return ERROR;
+ }
+ /* file.ext doesn't exist, try adding a suffix (after removing any
+ * version number for VMS).
+ */
+ s = get_suffix(ifname);
+ if (s != NULL) {
+ perror(ifname); /* ifname already has z suffix and does not exist */
+ exit_code = ERROR;
+ return ERROR;
+ }
+#ifdef NO_MULTIPLE_DOTS
+ dot = strrchr(ifname, '.');
+ if (dot == NULL) {
+ strcat(ifname, ".");
+ dot = strrchr(ifname, '.');
+ }
+#endif
+ ilen = strlen(ifname);
+ if (strequ(z_suffix, ".gz")) suf++;
+
+ /* Search for all suffixes */
+ do {
+ s = *suf;
+#ifdef NO_MULTIPLE_DOTS
+ if (*s == '.') s++;
+#endif
+#ifdef MAX_EXT_CHARS
+ strcpy(ifname, iname);
+ /* Needed if the suffixes are not sorted by increasing length */
+
+ if (*dot == '\0') strcpy(dot, ".");
+ dot[MAX_EXT_CHARS+1-strlen(s)] = '\0';
+#endif
+ strcat(ifname, s);
+ if (do_stat(ifname, sbuf) == 0) return OK;
+ ifname[ilen] = '\0';
+ } while (*++suf != NULL);
+
+ /* No suffix found, complain using z_suffix: */
+#ifdef MAX_EXT_CHARS
+ strcpy(ifname, iname);
+ if (*dot == '\0') strcpy(dot, ".");
+ dot[MAX_EXT_CHARS+1-z_len] = '\0';
+#endif
+ strcat(ifname, z_suffix);
+ perror(ifname);
+ exit_code = ERROR;
+ return ERROR;
+}
+
+/* ========================================================================
+ * Generate ofname given ifname. Return OK, or WARNING if file must be skipped.
+ * Sets save_orig_name to true if the file name has been truncated.
+ */
+local int make_ofname()
+{
+ char *suff; /* ofname z suffix */
+
+ strcpy(ofname, ifname);
+ /* strip a version number if any and get the gzip suffix if present: */
+ suff = get_suffix(ofname);
+
+ if (decompress) {
+ if (suff == NULL) {
+ /* Whith -t or -l, try all files (even without .gz suffix)
+ * except with -r (behave as with just -dr).
+ */
+ if (!recursive && (list || test)) return OK;
+
+ /* Avoid annoying messages with -r */
+ if (verbose || (!recursive && !quiet)) {
+ WARN((stderr,"%s: %s: unknown suffix -- ignored\n",
+ progname, ifname));
+ }
+ return WARNING;
+ }
+ /* Make a special case for .tgz and .taz: */
+ strlwr(suff);
+ if (strequ(suff, ".tgz") || strequ(suff, ".taz")) {
+ strcpy(suff, ".tar");
+ } else {
+ *suff = '\0'; /* strip the z suffix */
+ }
+ /* ofname might be changed later if infile contains an original name */
+
+ } else if (suff != NULL) {
+ /* Avoid annoying messages with -r (see treat_dir()) */
+ if (verbose || (!recursive && !quiet)) {
+ fprintf(stderr, "%s: %s already has %s suffix -- unchanged\n",
+ progname, ifname, suff);
+ }
+ if (exit_code == OK) exit_code = WARNING;
+ return WARNING;
+ } else {
+ save_orig_name = 0;
+
+#ifdef NO_MULTIPLE_DOTS
+ suff = strrchr(ofname, '.');
+ if (suff == NULL) {
+ strcat(ofname, ".");
+# ifdef MAX_EXT_CHARS
+ if (strequ(z_suffix, "z")) {
+ strcat(ofname, "gz"); /* enough room */
+ return OK;
+ }
+ /* On the Atari and some versions of MSDOS, name_too_long()
+ * does not work correctly because of a bug in stat(). So we
+ * must truncate here.
+ */
+ } else if (strlen(suff)-1 + z_len > MAX_SUFFIX) {
+ suff[MAX_SUFFIX+1-z_len] = '\0';
+ save_orig_name = 1;
+# endif
+ }
+#endif /* NO_MULTIPLE_DOTS */
+ strcat(ofname, z_suffix);
+
+ } /* decompress ? */
+ return OK;
+}
+
+
+/* ========================================================================
+ * Check the magic number of the input file and update ofname if an
+ * original name was given and to_stdout is not set.
+ * Return the compression method, -1 for error, -2 for warning.
+ * Set inptr to the offset of the next byte to be processed.
+ * Updates time_stamp if there is one and --no-time is not used.
+ * This function may be called repeatedly for an input file consisting
+ * of several contiguous gzip'ed members.
+ * IN assertions: there is at least one remaining compressed member.
+ * If the member is a zip file, it must be the only one.
+ */
+local int get_method(in)
+ int in; /* input file descriptor */
+{
+ uch flags; /* compression flags */
+ char magic[2]; /* magic header */
+ ulg stamp; /* time stamp */
+
+ /* If --force and --stdout, zcat == cat, so do not complain about
+ * premature end of file: use try_byte instead of get_byte.
+ */
+ if (force && to_stdout) {
+ magic[0] = (char)try_byte();
+ magic[1] = (char)try_byte();
+ /* If try_byte returned EOF, magic[1] == 0xff */
+ } else {
+ magic[0] = (char)get_byte();
+ magic[1] = (char)get_byte();
+ }
+ method = -1; /* unknown yet */
+ part_nb++; /* number of parts in gzip file */
+ header_bytes = 0;
+ last_member = RECORD_IO;
+ /* assume multiple members in gzip file except for record oriented I/O */
+
+ if (memcmp(magic, GZIP_MAGIC, 2) == 0
+ || memcmp(magic, OLD_GZIP_MAGIC, 2) == 0) {
+
+ method = (int)get_byte();
+ if (method != DEFLATED) {
+ fprintf(stderr,
+ "%s: %s: unknown method %d -- get newer version of gzip\n",
+ progname, ifname, method);
+ exit_code = ERROR;
+ return -1;
+ }
+ work = unzip;
+ flags = (uch)get_byte();
+
+ if ((flags & ENCRYPTED) != 0) {
+ fprintf(stderr,
+ "%s: %s is encrypted -- get newer version of gzip\n",
+ progname, ifname);
+ exit_code = ERROR;
+ return -1;
+ }
+ if ((flags & CONTINUATION) != 0) {
+ fprintf(stderr,
+ "%s: %s is a a multi-part gzip file -- get newer version of gzip\n",
+ progname, ifname);
+ exit_code = ERROR;
+ if (force <= 1) return -1;
+ }
+ if ((flags & RESERVED) != 0) {
+ fprintf(stderr,
+ "%s: %s has flags 0x%x -- get newer version of gzip\n",
+ progname, ifname, flags);
+ exit_code = ERROR;
+ if (force <= 1) return -1;
+ }
+ stamp = (ulg)get_byte();
+ stamp |= ((ulg)get_byte()) << 8;
+ stamp |= ((ulg)get_byte()) << 16;
+ stamp |= ((ulg)get_byte()) << 24;
+ if (stamp != 0 && !no_time) time_stamp = stamp;
+
+ (void)get_byte(); /* Ignore extra flags for the moment */
+ (void)get_byte(); /* Ignore OS type for the moment */
+
+ if ((flags & CONTINUATION) != 0) {
+ unsigned part = (unsigned)get_byte();
+ part |= ((unsigned)get_byte())<<8;
+ if (verbose) {
+ fprintf(stderr,"%s: %s: part number %u\n",
+ progname, ifname, part);
+ }
+ }
+ if ((flags & EXTRA_FIELD) != 0) {
+ unsigned len = (unsigned)get_byte();
+ len |= ((unsigned)get_byte())<<8;
+ if (verbose) {
+ fprintf(stderr,"%s: %s: extra field of %u bytes ignored\n",
+ progname, ifname, len);
+ }
+ while (len--) (void)get_byte();
+ }
+
+ /* Get original file name if it was truncated */
+ if ((flags & ORIG_NAME) != 0) {
+ if (no_name || (to_stdout && !list) || part_nb > 1) {
+ /* Discard the old name */
+ char c; /* dummy used for NeXTstep 3.0 cc optimizer bug */
+ do {c=get_byte();} while (c != 0);
+ } else {
+ /* Copy the base name. Keep a directory prefix intact. */
+ char *p = basename(ofname);
+ char *base = p;
+ for (;;) {
+ *p = (char)get_char();
+ if (*p++ == '\0') break;
+ if (p >= ofname+sizeof(ofname)) {
+ error("corrupted input -- file name too large");
+ }
+ }
+ /* If necessary, adapt the name to local OS conventions: */
+ if (!list) {
+ MAKE_LEGAL_NAME(base);
+ if (base) list=0; /* avoid warning about unused variable */
+ }
+ } /* no_name || to_stdout */
+ } /* ORIG_NAME */
+
+ /* Discard file comment if any */
+ if ((flags & COMMENT) != 0) {
+ while (get_char() != 0) /* null */ ;
+ }
+ if (part_nb == 1) {
+ header_bytes = inptr + 2*sizeof(long); /* include crc and size */
+ }
+
+ } else if (memcmp(magic, PKZIP_MAGIC, 2) == 0 && inptr == 2
+ && memcmp((char*)inbuf, PKZIP_MAGIC, 4) == 0) {
+ /* To simplify the code, we support a zip file when alone only.
+ * We are thus guaranteed that the entire local header fits in inbuf.
+ */
+ inptr = 0;
+ work = unzip;
+ if (check_zipfile(in) != OK) return -1;
+ /* check_zipfile may get ofname from the local header */
+ last_member = 1;
+
+ } else if (memcmp(magic, PACK_MAGIC, 2) == 0) {
+ work = unpack;
+ method = PACKED;
+
+ } else if (memcmp(magic, LZW_MAGIC, 2) == 0) {
+ work = unlzw;
+ method = COMPRESSED;
+ last_member = 1;
+
+ } else if (memcmp(magic, LZH_MAGIC, 2) == 0) {
+ work = unlzh;
+ method = LZHED;
+ last_member = 1;
+
+ } else if (force && to_stdout && !list) { /* pass input unchanged */
+ method = STORED;
+ work = copy;
+ inptr = 0;
+ last_member = 1;
+ }
+ if (method >= 0) return method;
+
+ if (part_nb == 1) {
+ fprintf(stderr, "\n%s: %s: not in gzip format\n", progname, ifname);
+ exit_code = ERROR;
+ return -1;
+ } else {
+ WARN((stderr, "\n%s: %s: decompression OK, trailing garbage ignored\n",
+ progname, ifname));
+ return -2;
+ }
+}
+
+/* ========================================================================
+ * Display the characteristics of the compressed file.
+ * If the given method is < 0, display the accumulated totals.
+ * IN assertions: time_stamp, header_bytes and ifile_size are initialized.
+ */
+local void do_list(ifd, method)
+ int ifd; /* input file descriptor */
+ int method; /* compression method */
+{
+ ulg crc; /* original crc */
+ static int first_time = 1;
+ static char* methods[MAX_METHODS] = {
+ "store", /* 0 */
+ "compr", /* 1 */
+ "pack ", /* 2 */
+ "lzh ", /* 3 */
+ "", "", "", "", /* 4 to 7 reserved */
+ "defla"}; /* 8 */
+ char *date;
+
+ if (first_time && method >= 0) {
+ first_time = 0;
+ if (verbose) {
+ printf("method crc date time ");
+ }
+ if (!quiet) {
+ printf("compressed uncompr. ratio uncompressed_name\n");
+ }
+ } else if (method < 0) {
+ if (total_in <= 0 || total_out <= 0) return;
+ if (verbose) {
+ printf(" %9lu %9lu ",
+ total_in, total_out);
+ } else if (!quiet) {
+ printf("%9ld %9ld ", total_in, total_out);
+ }
+ display_ratio(total_out-(total_in-header_bytes), total_out, stdout);
+ /* header_bytes is not meaningful but used to ensure the same
+ * ratio if there is a single file.
+ */
+ printf(" (totals)\n");
+ return;
+ }
+ crc = (ulg)~0; /* unknown */
+ bytes_out = -1L;
+ bytes_in = ifile_size;
+
+#if RECORD_IO == 0
+ if (method == DEFLATED && !last_member) {
+ /* Get the crc and uncompressed size for gzip'ed (not zip'ed) files.
+ * If the lseek fails, we could use read() to get to the end, but
+ * --list is used to get quick results.
+ * Use "gunzip < foo.gz | wc -c" to get the uncompressed size if
+ * you are not concerned about speed.
+ */
+ bytes_in = (long)lseek(ifd, (off_t)(-8), SEEK_END);
+ if (bytes_in != -1L) {
+ uch buf[8];
+ bytes_in += 8L;
+ if (read(ifd, (char*)buf, sizeof(buf)) != sizeof(buf)) {
+ read_error();
+ }
+ crc = LG(buf);
+ bytes_out = LG(buf+4);
+ }
+ }
+#endif /* RECORD_IO */
+ date = ctime((time_t*)&time_stamp) + 4; /* skip the day of the week */
+ date[12] = '\0'; /* suppress the 1/100sec and the year */
+ if (verbose) {
+ printf("%5s %08lx %11s ", methods[method], crc, date);
+ }
+ printf("%9ld %9ld ", bytes_in, bytes_out);
+ if (bytes_in == -1L) {
+ total_in = -1L;
+ bytes_in = bytes_out = header_bytes = 0;
+ } else if (total_in >= 0) {
+ total_in += bytes_in;
+ }
+ if (bytes_out == -1L) {
+ total_out = -1L;
+ bytes_in = bytes_out = header_bytes = 0;
+ } else if (total_out >= 0) {
+ total_out += bytes_out;
+ }
+ display_ratio(bytes_out-(bytes_in-header_bytes), bytes_out, stdout);
+ printf(" %s\n", ofname);
+}
+
+/* ========================================================================
+ * Return true if the two stat structures correspond to the same file.
+ */
+local int same_file(stat1, stat2)
+ struct stat *stat1;
+ struct stat *stat2;
+{
+ return stat1->st_ino == stat2->st_ino
+ && stat1->st_dev == stat2->st_dev
+#ifdef NO_ST_INO
+ /* Can't rely on st_ino and st_dev, use other fields: */
+ && stat1->st_mode == stat2->st_mode
+ && stat1->st_uid == stat2->st_uid
+ && stat1->st_gid == stat2->st_gid
+ && stat1->st_size == stat2->st_size
+ && stat1->st_atime == stat2->st_atime
+ && stat1->st_mtime == stat2->st_mtime
+ && stat1->st_ctime == stat2->st_ctime
+#endif
+ ;
+}
+
+/* ========================================================================
+ * Return true if a file name is ambiguous because the operating system
+ * truncates file names.
+ */
+local int name_too_long(name, statb)
+ char *name; /* file name to check */
+ struct stat *statb; /* stat buf for this file name */
+{
+ int s = strlen(name);
+ char c = name[s-1];
+ struct stat tstat; /* stat for truncated name */
+ int res;
+
+ tstat = *statb; /* Just in case OS does not fill all fields */
+ name[s-1] = '\0';
+ res = stat(name, &tstat) == 0 && same_file(statb, &tstat);
+ name[s-1] = c;
+ Trace((stderr, " too_long(%s) => %d\n", name, res));
+ return res;
+}
+
+/* ========================================================================
+ * Shorten the given name by one character, or replace a .tar extension
+ * with .tgz. Truncate the last part of the name which is longer than
+ * MIN_PART characters: 1234.678.012.gz -> 123.678.012.gz. If the name
+ * has only parts shorter than MIN_PART truncate the longest part.
+ * For decompression, just remove the last character of the name.
+ *
+ * IN assertion: for compression, the suffix of the given name is z_suffix.
+ */
+local void shorten_name(name)
+ char *name;
+{
+ int len; /* length of name without z_suffix */
+ char *trunc = NULL; /* character to be truncated */
+ int plen; /* current part length */
+ int min_part = MIN_PART; /* current minimum part length */
+ char *p;
+
+ len = strlen(name);
+ if (decompress) {
+ if (len <= 1) error("name too short");
+ name[len-1] = '\0';
+ return;
+ }
+ p = get_suffix(name);
+ if (p == NULL) error("can't recover suffix\n");
+ *p = '\0';
+ save_orig_name = 1;
+
+ /* compress 1234567890.tar to 1234567890.tgz */
+ if (len > 4 && strequ(p-4, ".tar")) {
+ strcpy(p-4, ".tgz");
+ return;
+ }
+ /* Try keeping short extensions intact:
+ * 1234.678.012.gz -> 123.678.012.gz
+ */
+ do {
+ p = strrchr(name, PATH_SEP);
+ p = p ? p+1 : name;
+ while (*p) {
+ plen = strcspn(p, PART_SEP);
+ p += plen;
+ if (plen > min_part) trunc = p-1;
+ if (*p) p++;
+ }
+ } while (trunc == NULL && --min_part != 0);
+
+ if (trunc != NULL) {
+ do {
+ trunc[0] = trunc[1];
+ } while (*trunc++);
+ trunc--;
+ } else {
+ trunc = strrchr(name, PART_SEP[0]);
+ if (trunc == NULL) error("internal error in shorten_name");
+ if (trunc[1] == '\0') trunc--; /* force truncation */
+ }
+ strcpy(trunc, z_suffix);
+}
+
+/* ========================================================================
+ * If compressing to a file, check if ofname is not ambiguous
+ * because the operating system truncates names. Otherwise, generate
+ * a new ofname and save the original name in the compressed file.
+ * If the compressed file already exists, ask for confirmation.
+ * The check for name truncation is made dynamically, because different
+ * file systems on the same OS might use different truncation rules (on SVR4
+ * s5 truncates to 14 chars and ufs does not truncate).
+ * This function returns -1 if the file must be skipped, and
+ * updates save_orig_name if necessary.
+ * IN assertions: save_orig_name is already set if ofname has been
+ * already truncated because of NO_MULTIPLE_DOTS. The input file has
+ * already been open and istat is set.
+ */
+local int check_ofname()
+{
+ struct stat ostat; /* stat for ofname */
+
+#ifdef ENAMETOOLONG
+ /* Check for strictly conforming Posix systems (which return ENAMETOOLONG
+ * instead of silently truncating filenames).
+ */
+ errno = 0;
+ while (stat(ofname, &ostat) != 0) {
+ if (errno != ENAMETOOLONG) return 0; /* ofname does not exist */
+ shorten_name(ofname);
+ }
+#else
+ if (stat(ofname, &ostat) != 0) return 0;
+#endif
+ /* Check for name truncation on existing file. Do this even on systems
+ * defining ENAMETOOLONG, because on most systems the strict Posix
+ * behavior is disabled by default (silent name truncation allowed).
+ */
+ if (!decompress && name_too_long(ofname, &ostat)) {
+ shorten_name(ofname);
+ if (stat(ofname, &ostat) != 0) return 0;
+ }
+
+ /* Check that the input and output files are different (could be
+ * the same by name truncation or links).
+ */
+ if (same_file(&istat, &ostat)) {
+ if (strequ(ifname, ofname)) {
+ fprintf(stderr, "%s: %s: cannot %scompress onto itself\n",
+ progname, ifname, decompress ? "de" : "");
+ } else {
+ fprintf(stderr, "%s: %s and %s are the same file\n",
+ progname, ifname, ofname);
+ }
+ exit_code = ERROR;
+ return ERROR;
+ }
+ /* Ask permission to overwrite the existing file */
+ if (!force) {
+ char response[80];
+ strcpy(response,"n");
+ fprintf(stderr, "%s: %s already exists;", progname, ofname);
+ if (foreground && isatty(fileno(stdin))) {
+ fprintf(stderr, " do you wish to overwrite (y or n)? ");
+ fflush(stderr);
+ (void)fgets(response, sizeof(response)-1, stdin);
+ }
+ if (tolow(*response) != 'y') {
+ fprintf(stderr, "\tnot overwritten\n");
+ if (exit_code == OK) exit_code = WARNING;
+ return ERROR;
+ }
+ }
+ (void) chmod(ofname, 0777);
+ if (unlink(ofname)) {
+ fprintf(stderr, "%s: ", progname);
+ perror(ofname);
+ exit_code = ERROR;
+ return ERROR;
+ }
+ return OK;
+}
+
+
+#ifndef NO_UTIME
+/* ========================================================================
+ * Set the access and modification times from the given stat buffer.
+ */
+local void reset_times (name, statb)
+ char *name;
+ struct stat *statb;
+{
+ struct utimbuf timep;
+
+ /* Copy the time stamp */
+ timep.actime = statb->st_atime;
+ timep.modtime = statb->st_mtime;
+
+ /* Some systems (at least OS/2) do not support utime on directories */
+ if (utime(name, &timep) && !S_ISDIR(statb->st_mode)) {
+ WARN((stderr, "%s: ", progname));
+ if (!quiet) perror(ofname);
+ }
+}
+#endif
+
+
+/* ========================================================================
+ * Copy modes, times, ownership from input file to output file.
+ * IN assertion: to_stdout is false.
+ */
+local void copy_stat(ifstat)
+ struct stat *ifstat;
+{
+#ifndef NO_UTIME
+ if (decompress && time_stamp != 0 && ifstat->st_mtime != time_stamp) {
+ ifstat->st_mtime = time_stamp;
+ if (verbose > 1) {
+ fprintf(stderr, "%s: time stamp restored\n", ofname);
+ }
+ }
+ reset_times(ofname, ifstat);
+#endif
+ /* Copy the protection modes */
+ if (chmod(ofname, ifstat->st_mode & 07777)) {
+ WARN((stderr, "%s: ", progname));
+ if (!quiet) perror(ofname);
+ }
+#ifndef NO_CHOWN
+ chown(ofname, ifstat->st_uid, ifstat->st_gid); /* Copy ownership */
+#endif
+ remove_ofname = 0;
+ /* It's now safe to remove the input file: */
+ (void) chmod(ifname, 0777);
+ if (unlink(ifname)) {
+ WARN((stderr, "%s: ", progname));
+ if (!quiet) perror(ifname);
+ }
+}
+
+#ifndef NO_DIR
+
+/* ========================================================================
+ * Recurse through the given directory. This code is taken from ncompress.
+ */
+local void treat_dir(dir)
+ char *dir;
+{
+ dir_type *dp;
+ DIR *dirp;
+ char nbuf[MAX_PATH_LEN];
+ int len;
+
+ dirp = opendir(dir);
+
+ if (dirp == NULL) {
+ fprintf(stderr, "%s: %s unreadable\n", progname, dir);
+ exit_code = ERROR;
+ return ;
+ }
+ /*
+ ** WARNING: the following algorithm could occasionally cause
+ ** compress to produce error warnings of the form "<filename>.gz
+ ** already has .gz suffix - ignored". This occurs when the
+ ** .gz output file is inserted into the directory below
+ ** readdir's current pointer.
+ ** These warnings are harmless but annoying, so they are suppressed
+ ** with option -r (except when -v is on). An alternative
+ ** to allowing this would be to store the entire directory
+ ** list in memory, then compress the entries in the stored
+ ** list. Given the depth-first recursive algorithm used here,
+ ** this could use up a tremendous amount of memory. I don't
+ ** think it's worth it. -- Dave Mack
+ ** (An other alternative might be two passes to avoid depth-first.)
+ */
+
+ while ((dp = readdir(dirp)) != NULL) {
+
+ if (strequ(dp->d_name,".") || strequ(dp->d_name,"..")) {
+ continue;
+ }
+ len = strlen(dir);
+ if (len + NLENGTH(dp) + 1 < MAX_PATH_LEN - 1) {
+ strcpy(nbuf,dir);
+ if (len != 0 /* dir = "" means current dir on Amiga */
+#ifdef PATH_SEP2
+ && dir[len-1] != PATH_SEP2
+#endif
+#ifdef PATH_SEP3
+ && dir[len-1] != PATH_SEP3
+#endif
+ ) {
+ nbuf[len++] = PATH_SEP;
+ }
+ strcpy(nbuf+len, dp->d_name);
+ treat_file(nbuf);
+ } else {
+ fprintf(stderr,"%s: %s/%s: pathname too long\n",
+ progname, dir, dp->d_name);
+ exit_code = ERROR;
+ }
+ }
+ closedir(dirp);
+}
+#endif /* ? NO_DIR */
+
+/* ========================================================================
+ * Free all dynamically allocated variables and exit with the given code.
+ */
+local void do_exit(exitcode)
+ int exitcode;
+{
+ static int in_exit = 0;
+
+ if (in_exit) exit(exitcode);
+ in_exit = 1;
+ if (env != NULL) free(env), env = NULL;
+ if (args != NULL) free((char*)args), args = NULL;
+ FREE(inbuf);
+ FREE(outbuf);
+ FREE(d_buf);
+ FREE(window);
+#ifndef MAXSEG_64K
+ FREE(tab_prefix);
+#else
+ FREE(tab_prefix0);
+ FREE(tab_prefix1);
+#endif
+ exit(exitcode);
+}
+
+/* ========================================================================
+ * Signal and error handler.
+ */
+RETSIGTYPE abort_gzip()
+{
+ if (remove_ofname) {
+ close(ofd);
+ unlink (ofname);
+ }
+ do_exit(ERROR);
+}
diff --git a/gnu/usr.bin/gzip/gzip.h b/gnu/usr.bin/gzip/gzip.h
new file mode 100644
index 0000000..1ec96cb
--- /dev/null
+++ b/gnu/usr.bin/gzip/gzip.h
@@ -0,0 +1,315 @@
+/* gzip.h -- common declarations for all gzip modules
+ * Copyright (C) 1992-1993 Jean-loup Gailly.
+ * This is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License, see the file COPYING.
+ */
+
+#if defined(__STDC__) || defined(PROTO)
+# define OF(args) args
+#else
+# define OF(args) ()
+#endif
+
+#ifdef __STDC__
+ typedef void *voidp;
+#else
+ typedef char *voidp;
+#endif
+
+/* I don't like nested includes, but the string and io functions are used
+ * too often
+ */
+#include <stdio.h>
+#if !defined(NO_STRING_H) || defined(STDC_HEADERS)
+# include <string.h>
+# if !defined(STDC_HEADERS) && !defined(NO_MEMORY_H) && !defined(__GNUC__)
+# include <memory.h>
+# endif
+# define memzero(s, n) memset ((voidp)(s), 0, (n))
+#else
+# include <strings.h>
+# define strchr index
+# define strrchr rindex
+# define memcpy(d, s, n) bcopy((s), (d), (n))
+# define memcmp(s1, s2, n) bcmp((s1), (s2), (n))
+# define memzero(s, n) bzero((s), (n))
+#endif
+
+#ifndef RETSIGTYPE
+# define RETSIGTYPE void
+#endif
+
+#define local static
+
+typedef unsigned char uch;
+typedef unsigned short ush;
+typedef unsigned long ulg;
+
+/* Return codes from gzip */
+#define OK 0
+#define ERROR 1
+#define WARNING 2
+
+/* Compression methods (see algorithm.doc) */
+#define STORED 0
+#define COMPRESSED 1
+#define PACKED 2
+#define LZHED 3
+/* methods 4 to 7 reserved */
+#define DEFLATED 8
+#define MAX_METHODS 9
+extern int method; /* compression method */
+
+/* To save memory for 16 bit systems, some arrays are overlaid between
+ * the various modules:
+ * deflate: prev+head window d_buf l_buf outbuf
+ * unlzw: tab_prefix tab_suffix stack inbuf outbuf
+ * inflate: window inbuf
+ * unpack: window inbuf prefix_len
+ * unlzh: left+right window c_table inbuf c_len
+ * For compression, input is done in window[]. For decompression, output
+ * is done in window except for unlzw.
+ */
+
+#ifndef INBUFSIZ
+# ifdef SMALL_MEM
+# define INBUFSIZ 0x2000 /* input buffer size */
+# else
+# define INBUFSIZ 0x8000 /* input buffer size */
+# endif
+#endif
+#define INBUF_EXTRA 64 /* required by unlzw() */
+
+#ifndef OUTBUFSIZ
+# ifdef SMALL_MEM
+# define OUTBUFSIZ 8192 /* output buffer size */
+# else
+# define OUTBUFSIZ 16384 /* output buffer size */
+# endif
+#endif
+#define OUTBUF_EXTRA 2048 /* required by unlzw() */
+
+#ifndef DIST_BUFSIZE
+# ifdef SMALL_MEM
+# define DIST_BUFSIZE 0x2000 /* buffer for distances, see trees.c */
+# else
+# define DIST_BUFSIZE 0x8000 /* buffer for distances, see trees.c */
+# endif
+#endif
+
+#ifdef DYN_ALLOC
+# define EXTERN(type, array) extern type * near array
+# define DECLARE(type, array, size) type * near array
+# define ALLOC(type, array, size) { \
+ array = (type*)fcalloc((size_t)(((size)+1L)/2), 2*sizeof(type)); \
+ if (array == NULL) error("insufficient memory"); \
+ }
+# define FREE(array) {if (array != NULL) fcfree(array), array=NULL;}
+#else
+# define EXTERN(type, array) extern type array[]
+# define DECLARE(type, array, size) type array[size]
+# define ALLOC(type, array, size)
+# define FREE(array)
+#endif
+
+EXTERN(uch, inbuf); /* input buffer */
+EXTERN(uch, outbuf); /* output buffer */
+EXTERN(ush, d_buf); /* buffer for distances, see trees.c */
+EXTERN(uch, window); /* Sliding window and suffix table (unlzw) */
+#define tab_suffix window
+#ifndef MAXSEG_64K
+# define tab_prefix prev /* hash link (see deflate.c) */
+# define head (prev+WSIZE) /* hash head (see deflate.c) */
+ EXTERN(ush, tab_prefix); /* prefix code (see unlzw.c) */
+#else
+# define tab_prefix0 prev
+# define head tab_prefix1
+ EXTERN(ush, tab_prefix0); /* prefix for even codes */
+ EXTERN(ush, tab_prefix1); /* prefix for odd codes */
+#endif
+
+extern unsigned insize; /* valid bytes in inbuf */
+extern unsigned inptr; /* index of next byte to be processed in inbuf */
+extern unsigned outcnt; /* bytes in output buffer */
+
+extern long bytes_in; /* number of input bytes */
+extern long bytes_out; /* number of output bytes */
+extern long header_bytes;/* number of bytes in gzip header */
+
+#define isize bytes_in
+/* for compatibility with old zip sources (to be cleaned) */
+
+extern int ifd; /* input file descriptor */
+extern int ofd; /* output file descriptor */
+extern char ifname[]; /* input file name or "stdin" */
+extern char ofname[]; /* output file name or "stdout" */
+extern char *progname; /* program name */
+
+extern long time_stamp; /* original time stamp (modification time) */
+extern long ifile_size; /* input file size, -1 for devices (debug only) */
+
+typedef int file_t; /* Do not use stdio */
+#define NO_FILE (-1) /* in memory compression */
+
+
+#define PACK_MAGIC "\037\036" /* Magic header for packed files */
+#define GZIP_MAGIC "\037\213" /* Magic header for gzip files, 1F 8B */
+#define OLD_GZIP_MAGIC "\037\236" /* Magic header for gzip 0.5 = freeze 1.x */
+#define LZH_MAGIC "\037\240" /* Magic header for SCO LZH Compress files*/
+#define PKZIP_MAGIC "\120\113\003\004" /* Magic header for pkzip files */
+
+/* gzip flag byte */
+#define ASCII_FLAG 0x01 /* bit 0 set: file probably ascii text */
+#define CONTINUATION 0x02 /* bit 1 set: continuation of multi-part gzip file */
+#define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */
+#define ORIG_NAME 0x08 /* bit 3 set: original file name present */
+#define COMMENT 0x10 /* bit 4 set: file comment present */
+#define ENCRYPTED 0x20 /* bit 5 set: file is encrypted */
+#define RESERVED 0xC0 /* bit 6,7: reserved */
+
+/* internal file attribute */
+#define UNKNOWN 0xffff
+#define BINARY 0
+#define ASCII 1
+
+#ifndef WSIZE
+# define WSIZE 0x8000 /* window size--must be a power of two, and */
+#endif /* at least 32K for zip's deflate method */
+
+#define MIN_MATCH 3
+#define MAX_MATCH 258
+/* The minimum and maximum match lengths */
+
+#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1)
+/* Minimum amount of lookahead, except at the end of the input file.
+ * See deflate.c for comments about the MIN_MATCH+1.
+ */
+
+#define MAX_DIST (WSIZE-MIN_LOOKAHEAD)
+/* In order to simplify the code, particularly on 16 bit machines, match
+ * distances are limited to MAX_DIST instead of WSIZE.
+ */
+
+extern int decrypt; /* flag to turn on decryption */
+extern int exit_code; /* program exit code */
+extern int verbose; /* be verbose (-v) */
+extern int quiet; /* be quiet (-q) */
+extern int level; /* compression level */
+extern int test; /* check .z file integrity */
+extern int to_stdout; /* output to stdout (-c) */
+extern int save_orig_name; /* set if original name must be saved */
+
+#define get_byte() (inptr < insize ? inbuf[inptr++] : fill_inbuf(0))
+#define try_byte() (inptr < insize ? inbuf[inptr++] : fill_inbuf(1))
+
+/* put_byte is used for the compressed output, put_ubyte for the
+ * uncompressed output. However unlzw() uses window for its
+ * suffix table instead of its output buffer, so it does not use put_ubyte
+ * (to be cleaned up).
+ */
+#define put_byte(c) {outbuf[outcnt++]=(uch)(c); if (outcnt==OUTBUFSIZ)\
+ flush_outbuf();}
+#define put_ubyte(c) {window[outcnt++]=(uch)(c); if (outcnt==WSIZE)\
+ flush_window();}
+
+/* Output a 16 bit value, lsb first */
+#define put_short(w) \
+{ if (outcnt < OUTBUFSIZ-2) { \
+ outbuf[outcnt++] = (uch) ((w) & 0xff); \
+ outbuf[outcnt++] = (uch) ((ush)(w) >> 8); \
+ } else { \
+ put_byte((uch)((w) & 0xff)); \
+ put_byte((uch)((ush)(w) >> 8)); \
+ } \
+}
+
+/* Output a 32 bit value to the bit stream, lsb first */
+#define put_long(n) { \
+ put_short((n) & 0xffff); \
+ put_short(((ulg)(n)) >> 16); \
+}
+
+#define seekable() 0 /* force sequential output */
+#define translate_eol 0 /* no option -a yet */
+
+#define tolow(c) (isupper(c) ? (c)-'A'+'a' : (c)) /* force to lower case */
+
+/* Macros for getting two-byte and four-byte header values */
+#define SH(p) ((ush)(uch)((p)[0]) | ((ush)(uch)((p)[1]) << 8))
+#define LG(p) ((ulg)(SH(p)) | ((ulg)(SH((p)+2)) << 16))
+
+/* Diagnostic functions */
+#ifdef DEBUG
+# define Assert(cond,msg) {if(!(cond)) error(msg);}
+# define Trace(x) fprintf x
+# define Tracev(x) {if (verbose) fprintf x ;}
+# define Tracevv(x) {if (verbose>1) fprintf x ;}
+# define Tracec(c,x) {if (verbose && (c)) fprintf x ;}
+# define Tracecv(c,x) {if (verbose>1 && (c)) fprintf x ;}
+#else
+# define Assert(cond,msg)
+# define Trace(x)
+# define Tracev(x)
+# define Tracevv(x)
+# define Tracec(c,x)
+# define Tracecv(c,x)
+#endif
+
+#define WARN(msg) {if (!quiet) fprintf msg ; \
+ if (exit_code == OK) exit_code = WARNING;}
+
+ /* in zip.c: */
+extern int zip OF((int in, int out));
+extern int file_read OF((char *buf, unsigned size));
+
+ /* in unzip.c */
+extern int unzip OF((int in, int out));
+extern int check_zipfile OF((int in));
+
+ /* in unpack.c */
+extern int unpack OF((int in, int out));
+
+ /* in unlzh.c */
+extern int unlzh OF((int in, int out));
+
+ /* in gzip.c */
+RETSIGTYPE abort_gzip OF((void));
+
+ /* in deflate.c */
+void lm_init OF((int pack_level, ush *flags));
+ulg deflate OF((void));
+
+ /* in trees.c */
+void ct_init OF((ush *attr, int *method));
+int ct_tally OF((int dist, int lc));
+ulg flush_block OF((char *buf, ulg stored_len, int eof));
+
+ /* in bits.c */
+void bi_init OF((file_t zipfile));
+void send_bits OF((int value, int length));
+unsigned bi_reverse OF((unsigned value, int length));
+void bi_windup OF((void));
+void copy_block OF((char *buf, unsigned len, int header));
+extern int (*read_buf) OF((char *buf, unsigned size));
+
+ /* in util.c: */
+extern int copy OF((int in, int out));
+extern ulg updcrc OF((uch *s, unsigned n));
+extern void clear_bufs OF((void));
+extern int fill_inbuf OF((int eof_ok));
+extern void flush_outbuf OF((void));
+extern void flush_window OF((void));
+extern void write_buf OF((int fd, voidp buf, unsigned cnt));
+extern char *strlwr OF((char *s));
+extern char *basename OF((char *fname));
+extern void make_simple_name OF((char *name));
+extern char *add_envopt OF((int *argcp, char ***argvp, char *env));
+extern void error OF((char *m));
+extern void warn OF((char *a, char *b));
+extern void read_error OF((void));
+extern void write_error OF((void));
+extern void display_ratio OF((long num, long den, FILE *file));
+extern voidp xmalloc OF((unsigned int size));
+
+ /* in inflate.c */
+extern int inflate OF((void));
diff --git a/gnu/usr.bin/gzip/inflate.c b/gnu/usr.bin/gzip/inflate.c
new file mode 100644
index 0000000..a53d013
--- /dev/null
+++ b/gnu/usr.bin/gzip/inflate.c
@@ -0,0 +1,954 @@
+/* inflate.c -- Not copyrighted 1992 by Mark Adler
+ version c10p1, 10 January 1993 */
+
+/* You can do whatever you like with this source file, though I would
+ prefer that if you modify it and redistribute it that you include
+ comments to that effect with your name and the date. Thank you.
+ [The history has been moved to the file ChangeLog.]
+ */
+
+/*
+ Inflate deflated (PKZIP's method 8 compressed) data. The compression
+ method searches for as much of the current string of bytes (up to a
+ length of 258) in the previous 32K bytes. If it doesn't find any
+ matches (of at least length 3), it codes the next byte. Otherwise, it
+ codes the length of the matched string and its distance backwards from
+ the current position. There is a single Huffman code that codes both
+ single bytes (called "literals") and match lengths. A second Huffman
+ code codes the distance information, which follows a length code. Each
+ length or distance code actually represents a base value and a number
+ of "extra" (sometimes zero) bits to get to add to the base value. At
+ the end of each deflated block is a special end-of-block (EOB) literal/
+ length code. The decoding process is basically: get a literal/length
+ code; if EOB then done; if a literal, emit the decoded byte; if a
+ length then get the distance and emit the referred-to bytes from the
+ sliding window of previously emitted data.
+
+ There are (currently) three kinds of inflate blocks: stored, fixed, and
+ dynamic. The compressor deals with some chunk of data at a time, and
+ decides which method to use on a chunk-by-chunk basis. A chunk might
+ typically be 32K or 64K. If the chunk is uncompressible, then the
+ "stored" method is used. In this case, the bytes are simply stored as
+ is, eight bits per byte, with none of the above coding. The bytes are
+ preceded by a count, since there is no longer an EOB code.
+
+ If the data is compressible, then either the fixed or dynamic methods
+ are used. In the dynamic method, the compressed data is preceded by
+ an encoding of the literal/length and distance Huffman codes that are
+ to be used to decode this block. The representation is itself Huffman
+ coded, and so is preceded by a description of that code. These code
+ descriptions take up a little space, and so for small blocks, there is
+ a predefined set of codes, called the fixed codes. The fixed method is
+ used if the block codes up smaller that way (usually for quite small
+ chunks), otherwise the dynamic method is used. In the latter case, the
+ codes are customized to the probabilities in the current block, and so
+ can code it much better than the pre-determined fixed codes.
+
+ The Huffman codes themselves are decoded using a mutli-level table
+ lookup, in order to maximize the speed of decoding plus the speed of
+ building the decoding tables. See the comments below that precede the
+ lbits and dbits tuning parameters.
+ */
+
+
+/*
+ Notes beyond the 1.93a appnote.txt:
+
+ 1. Distance pointers never point before the beginning of the output
+ stream.
+ 2. Distance pointers can point back across blocks, up to 32k away.
+ 3. There is an implied maximum of 7 bits for the bit length table and
+ 15 bits for the actual data.
+ 4. If only one code exists, then it is encoded using one bit. (Zero
+ would be more efficient, but perhaps a little confusing.) If two
+ codes exist, they are coded using one bit each (0 and 1).
+ 5. There is no way of sending zero distance codes--a dummy must be
+ sent if there are none. (History: a pre 2.0 version of PKZIP would
+ store blocks with no distance codes, but this was discovered to be
+ too harsh a criterion.) Valid only for 1.93a. 2.04c does allow
+ zero distance codes, which is sent as one code of zero bits in
+ length.
+ 6. There are up to 286 literal/length codes. Code 256 represents the
+ end-of-block. Note however that the static length tree defines
+ 288 codes just to fill out the Huffman codes. Codes 286 and 287
+ cannot be used though, since there is no length base or extra bits
+ defined for them. Similarly, there are up to 30 distance codes.
+ However, static trees define 32 codes (all 5 bits) to fill out the
+ Huffman codes, but the last two had better not show up in the data.
+ 7. Unzip can check dynamic Huffman blocks for complete code sets.
+ The exception is that a single code would not be complete (see #4).
+ 8. The five bits following the block type is really the number of
+ literal codes sent minus 257.
+ 9. Length codes 8,16,16 are interpreted as 13 length codes of 8 bits
+ (1+6+6). Therefore, to output three times the length, you output
+ three codes (1+1+1), whereas to output four times the same length,
+ you only need two codes (1+3). Hmm.
+ 10. In the tree reconstruction algorithm, Code = Code + Increment
+ only if BitLength(i) is not zero. (Pretty obvious.)
+ 11. Correction: 4 Bits: # of Bit Length codes - 4 (4 - 19)
+ 12. Note: length code 284 can represent 227-258, but length code 285
+ really is 258. The last length deserves its own, short code
+ since it gets used a lot in very redundant files. The length
+ 258 is special since 258 - 3 (the min match length) is 255.
+ 13. The literal/length and distance code bit lengths are read as a
+ single stream of lengths. It is possible (and advantageous) for
+ a repeat code (16, 17, or 18) to go across the boundary between
+ the two sets of lengths.
+ */
+
+#ifdef RCSID
+static char rcsid[] = "$Id: inflate.c,v 1.3 1993/10/14 00:32:55 nate Exp $";
+#endif
+
+#include <sys/types.h>
+
+#include "tailor.h"
+
+#if defined(STDC_HEADERS) || !defined(NO_STDLIB_H)
+# include <stdlib.h>
+#endif
+
+#include "gzip.h"
+#define slide window
+
+/* Huffman code lookup table entry--this entry is four bytes for machines
+ that have 16-bit pointers (e.g. PC's in the small or medium model).
+ Valid extra bits are 0..13. e == 15 is EOB (end of block), e == 16
+ means that v is a literal, 16 < e < 32 means that v is a pointer to
+ the next table, which codes e - 16 bits, and lastly e == 99 indicates
+ an unused code. If a code with e == 99 is looked up, this implies an
+ error in the data. */
+struct huft {
+ uch e; /* number of extra bits or operation */
+ uch b; /* number of bits in this code or subcode */
+ union {
+ ush n; /* literal, length base, or distance base */
+ struct huft *t; /* pointer to next level of table */
+ } v;
+};
+
+
+/* Function prototypes */
+int huft_build OF((unsigned *, unsigned, unsigned, ush *, ush *,
+ struct huft **, int *));
+int huft_free OF((struct huft *));
+int inflate_codes OF((struct huft *, struct huft *, int, int));
+int inflate_stored OF((void));
+int inflate_fixed OF((void));
+int inflate_dynamic OF((void));
+int inflate_block OF((int *));
+int inflate OF((void));
+
+
+/* The inflate algorithm uses a sliding 32K byte window on the uncompressed
+ stream to find repeated byte strings. This is implemented here as a
+ circular buffer. The index is updated simply by incrementing and then
+ and'ing with 0x7fff (32K-1). */
+/* It is left to other modules to supply the 32K area. It is assumed
+ to be usable as if it were declared "uch slide[32768];" or as just
+ "uch *slide;" and then malloc'ed in the latter case. The definition
+ must be in unzip.h, included above. */
+/* unsigned wp; current position in slide */
+#define wp outcnt
+#define flush_output(w) (wp=(w),flush_window())
+
+/* Tables for deflate from PKZIP's appnote.txt. */
+static unsigned border[] = { /* Order of the bit length code lengths */
+ 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15};
+static ush cplens[] = { /* Copy lengths for literal codes 257..285 */
+ 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,
+ 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0};
+ /* note: see note #13 above about the 258 in this list. */
+static ush cplext[] = { /* Extra bits for literal codes 257..285 */
+ 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2,
+ 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 99, 99}; /* 99==invalid */
+static ush cpdist[] = { /* Copy offsets for distance codes 0..29 */
+ 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193,
+ 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145,
+ 8193, 12289, 16385, 24577};
+static ush cpdext[] = { /* Extra bits for distance codes */
+ 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6,
+ 7, 7, 8, 8, 9, 9, 10, 10, 11, 11,
+ 12, 12, 13, 13};
+
+
+
+/* Macros for inflate() bit peeking and grabbing.
+ The usage is:
+
+ NEEDBITS(j)
+ x = b & mask_bits[j];
+ DUMPBITS(j)
+
+ where NEEDBITS makes sure that b has at least j bits in it, and
+ DUMPBITS removes the bits from b. The macros use the variable k
+ for the number of bits in b. Normally, b and k are register
+ variables for speed, and are initialized at the beginning of a
+ routine that uses these macros from a global bit buffer and count.
+
+ If we assume that EOB will be the longest code, then we will never
+ ask for bits with NEEDBITS that are beyond the end of the stream.
+ So, NEEDBITS should not read any more bytes than are needed to
+ meet the request. Then no bytes need to be "returned" to the buffer
+ at the end of the last block.
+
+ However, this assumption is not true for fixed blocks--the EOB code
+ is 7 bits, but the other literal/length codes can be 8 or 9 bits.
+ (The EOB code is shorter than other codes because fixed blocks are
+ generally short. So, while a block always has an EOB, many other
+ literal/length codes have a significantly lower probability of
+ showing up at all.) However, by making the first table have a
+ lookup of seven bits, the EOB code will be found in that first
+ lookup, and so will not require that too many bits be pulled from
+ the stream.
+ */
+
+ulg bb; /* bit buffer */
+unsigned bk; /* bits in bit buffer */
+
+ush mask_bits[] = {
+ 0x0000,
+ 0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff,
+ 0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff
+};
+
+#ifdef CRYPT
+ uch cc;
+# define NEXTBYTE() \
+ (decrypt ? (cc = get_byte(), zdecode(cc), cc) : get_byte())
+#else
+# define NEXTBYTE() (uch)get_byte()
+#endif
+#define NEEDBITS(n) {while(k<(n)){b|=((ulg)NEXTBYTE())<<k;k+=8;}}
+#define DUMPBITS(n) {b>>=(n);k-=(n);}
+
+
+/*
+ Huffman code decoding is performed using a multi-level table lookup.
+ The fastest way to decode is to simply build a lookup table whose
+ size is determined by the longest code. However, the time it takes
+ to build this table can also be a factor if the data being decoded
+ is not very long. The most common codes are necessarily the
+ shortest codes, so those codes dominate the decoding time, and hence
+ the speed. The idea is you can have a shorter table that decodes the
+ shorter, more probable codes, and then point to subsidiary tables for
+ the longer codes. The time it costs to decode the longer codes is
+ then traded against the time it takes to make longer tables.
+
+ This results of this trade are in the variables lbits and dbits
+ below. lbits is the number of bits the first level table for literal/
+ length codes can decode in one step, and dbits is the same thing for
+ the distance codes. Subsequent tables are also less than or equal to
+ those sizes. These values may be adjusted either when all of the
+ codes are shorter than that, in which case the longest code length in
+ bits is used, or when the shortest code is *longer* than the requested
+ table size, in which case the length of the shortest code in bits is
+ used.
+
+ There are two different values for the two tables, since they code a
+ different number of possibilities each. The literal/length table
+ codes 286 possible values, or in a flat code, a little over eight
+ bits. The distance table codes 30 possible values, or a little less
+ than five bits, flat. The optimum values for speed end up being
+ about one bit more than those, so lbits is 8+1 and dbits is 5+1.
+ The optimum values may differ though from machine to machine, and
+ possibly even between compilers. Your mileage may vary.
+ */
+
+
+int lbits = 9; /* bits in base literal/length lookup table */
+int dbits = 6; /* bits in base distance lookup table */
+
+
+/* If BMAX needs to be larger than 16, then h and x[] should be ulg. */
+#define BMAX 16 /* maximum bit length of any code (16 for explode) */
+#define N_MAX 288 /* maximum number of codes in any set */
+
+
+unsigned hufts; /* track memory usage */
+
+
+int huft_build(b, n, s, d, e, t, m)
+unsigned *b; /* code lengths in bits (all assumed <= BMAX) */
+unsigned n; /* number of codes (assumed <= N_MAX) */
+unsigned s; /* number of simple-valued codes (0..s-1) */
+ush *d; /* list of base values for non-simple codes */
+ush *e; /* list of extra bits for non-simple codes */
+struct huft **t; /* result: starting table */
+int *m; /* maximum lookup bits, returns actual */
+/* Given a list of code lengths and a maximum table size, make a set of
+ tables to decode that set of codes. Return zero on success, one if
+ the given code set is incomplete (the tables are still built in this
+ case), two if the input is invalid (all zero length codes or an
+ oversubscribed set of lengths), and three if not enough memory. */
+{
+ unsigned a; /* counter for codes of length k */
+ unsigned c[BMAX+1]; /* bit length count table */
+ unsigned f; /* i repeats in table every f entries */
+ int g; /* maximum code length */
+ int h; /* table level */
+ register unsigned i; /* counter, current code */
+ register unsigned j; /* counter */
+ register int k; /* number of bits in current code */
+ int l; /* bits per table (returned in m) */
+ register unsigned *p; /* pointer into c[], b[], or v[] */
+ register struct huft *q; /* points to current table */
+ struct huft r; /* table entry for structure assignment */
+ struct huft *u[BMAX]; /* table stack */
+ unsigned v[N_MAX]; /* values in order of bit length */
+ register int w; /* bits before this table == (l * h) */
+ unsigned x[BMAX+1]; /* bit offsets, then code stack */
+ unsigned *xp; /* pointer into x */
+ int y; /* number of dummy codes added */
+ unsigned z; /* number of entries in current table */
+
+
+ /* Generate counts for each bit length */
+ memzero(c, sizeof(c));
+ p = b; i = n;
+ do {
+ Tracecv(*p, (stderr, (n-i >= ' ' && n-i <= '~' ? "%c %d\n" : "0x%x %d\n"),
+ n-i, *p));
+ c[*p]++; /* assume all entries <= BMAX */
+ p++; /* Can't combine with above line (Solaris bug) */
+ } while (--i);
+ if (c[0] == n) /* null input--all zero length codes */
+ {
+ *t = (struct huft *)NULL;
+ *m = 0;
+ return 0;
+ }
+
+
+ /* Find minimum and maximum length, bound *m by those */
+ l = *m;
+ for (j = 1; j <= BMAX; j++)
+ if (c[j])
+ break;
+ k = j; /* minimum code length */
+ if ((unsigned)l < j)
+ l = j;
+ for (i = BMAX; i; i--)
+ if (c[i])
+ break;
+ g = i; /* maximum code length */
+ if ((unsigned)l > i)
+ l = i;
+ *m = l;
+
+
+ /* Adjust last length count to fill out codes, if needed */
+ for (y = 1 << j; j < i; j++, y <<= 1)
+ if ((y -= c[j]) < 0)
+ return 2; /* bad input: more codes than bits */
+ if ((y -= c[i]) < 0)
+ return 2;
+ c[i] += y;
+
+
+ /* Generate starting offsets into the value table for each length */
+ x[1] = j = 0;
+ p = c + 1; xp = x + 2;
+ while (--i) { /* note that i == g from above */
+ *xp++ = (j += *p++);
+ }
+
+
+ /* Make a table of values in order of bit lengths */
+ p = b; i = 0;
+ do {
+ if ((j = *p++) != 0)
+ v[x[j]++] = i;
+ } while (++i < n);
+
+
+ /* Generate the Huffman codes and for each, make the table entries */
+ x[0] = i = 0; /* first Huffman code is zero */
+ p = v; /* grab values in bit order */
+ h = -1; /* no tables yet--level -1 */
+ w = -l; /* bits decoded == (l * h) */
+ u[0] = (struct huft *)NULL; /* just to keep compilers happy */
+ q = (struct huft *)NULL; /* ditto */
+ z = 0; /* ditto */
+
+ /* go through the bit lengths (k already is bits in shortest code) */
+ for (; k <= g; k++)
+ {
+ a = c[k];
+ while (a--)
+ {
+ /* here i is the Huffman code of length k bits for value *p */
+ /* make tables up to required level */
+ while (k > w + l)
+ {
+ h++;
+ w += l; /* previous table always l bits */
+
+ /* compute minimum size table less than or equal to l bits */
+ z = (z = g - w) > (unsigned)l ? l : z; /* upper limit on table size */
+ if ((f = 1 << (j = k - w)) > a + 1) /* try a k-w bit table */
+ { /* too few codes for k-w bit table */
+ f -= a + 1; /* deduct codes from patterns left */
+ xp = c + k;
+ while (++j < z) /* try smaller tables up to z bits */
+ {
+ if ((f <<= 1) <= *++xp)
+ break; /* enough codes to use up j bits */
+ f -= *xp; /* else deduct codes from patterns */
+ }
+ }
+ z = 1 << j; /* table entries for j-bit table */
+
+ /* allocate and link in new table */
+ if ((q = (struct huft *)malloc((z + 1)*sizeof(struct huft))) ==
+ (struct huft *)NULL)
+ {
+ if (h)
+ huft_free(u[0]);
+ return 3; /* not enough memory */
+ }
+ hufts += z + 1; /* track memory usage */
+ *t = q + 1; /* link to list for huft_free() */
+ *(t = &(q->v.t)) = (struct huft *)NULL;
+ u[h] = ++q; /* table starts after link */
+
+ /* connect to last table, if there is one */
+ if (h)
+ {
+ x[h] = i; /* save pattern for backing up */
+ r.b = (uch)l; /* bits to dump before this table */
+ r.e = (uch)(16 + j); /* bits in this table */
+ r.v.t = q; /* pointer to this table */
+ j = i >> (w - l); /* (get around Turbo C bug) */
+ u[h-1][j] = r; /* connect to last table */
+ }
+ }
+
+ /* set up table entry in r */
+ r.b = (uch)(k - w);
+ if (p >= v + n)
+ r.e = 99; /* out of values--invalid code */
+ else if (*p < s)
+ {
+ r.e = (uch)(*p < 256 ? 16 : 15); /* 256 is end-of-block code */
+ r.v.n = (ush)(*p); /* simple code is just the value */
+ p++; /* one compiler does not like *p++ */
+ }
+ else
+ {
+ r.e = (uch)e[*p - s]; /* non-simple--look up in lists */
+ r.v.n = d[*p++ - s];
+ }
+
+ /* fill code-like entries with r */
+ f = 1 << (k - w);
+ for (j = i >> w; j < z; j += f)
+ q[j] = r;
+
+ /* backwards increment the k-bit code i */
+ for (j = 1 << (k - 1); i & j; j >>= 1)
+ i ^= j;
+ i ^= j;
+
+ /* backup over finished tables */
+ while ((i & ((1 << w) - 1)) != x[h])
+ {
+ h--; /* don't need to update q */
+ w -= l;
+ }
+ }
+ }
+
+
+ /* Return true (1) if we were given an incomplete table */
+ return y != 0 && g != 1;
+}
+
+
+
+int huft_free(t)
+struct huft *t; /* table to free */
+/* Free the malloc'ed tables built by huft_build(), which makes a linked
+ list of the tables it made, with the links in a dummy first entry of
+ each table. */
+{
+ register struct huft *p, *q;
+
+
+ /* Go through linked list, freeing from the malloced (t[-1]) address. */
+ p = t;
+ while (p != (struct huft *)NULL)
+ {
+ q = (--p)->v.t;
+ free((char*)p);
+ p = q;
+ }
+ return 0;
+}
+
+
+int inflate_codes(tl, td, bl, bd)
+struct huft *tl, *td; /* literal/length and distance decoder tables */
+int bl, bd; /* number of bits decoded by tl[] and td[] */
+/* inflate (decompress) the codes in a deflated (compressed) block.
+ Return an error code or zero if it all goes ok. */
+{
+ register unsigned e; /* table entry flag/number of extra bits */
+ unsigned n, d; /* length and index for copy */
+ unsigned w; /* current window position */
+ struct huft *t; /* pointer to table entry */
+ unsigned ml, md; /* masks for bl and bd bits */
+ register ulg b; /* bit buffer */
+ register unsigned k; /* number of bits in bit buffer */
+
+
+ /* make local copies of globals */
+ b = bb; /* initialize bit buffer */
+ k = bk;
+ w = wp; /* initialize window position */
+
+ /* inflate the coded data */
+ ml = mask_bits[bl]; /* precompute masks for speed */
+ md = mask_bits[bd];
+ for (;;) /* do until end of block */
+ {
+ NEEDBITS((unsigned)bl)
+ if ((e = (t = tl + ((unsigned)b & ml))->e) > 16)
+ do {
+ if (e == 99)
+ return 1;
+ DUMPBITS(t->b)
+ e -= 16;
+ NEEDBITS(e)
+ } while ((e = (t = t->v.t + ((unsigned)b & mask_bits[e]))->e) > 16);
+ DUMPBITS(t->b)
+ if (e == 16) /* then it's a literal */
+ {
+ slide[w++] = (uch)t->v.n;
+ Tracevv((stderr, "%c", slide[w-1]));
+ if (w == WSIZE)
+ {
+ flush_output(w);
+ w = 0;
+ }
+ }
+ else /* it's an EOB or a length */
+ {
+ /* exit if end of block */
+ if (e == 15)
+ break;
+
+ /* get length of block to copy */
+ NEEDBITS(e)
+ n = t->v.n + ((unsigned)b & mask_bits[e]);
+ DUMPBITS(e);
+
+ /* decode distance of block to copy */
+ NEEDBITS((unsigned)bd)
+ if ((e = (t = td + ((unsigned)b & md))->e) > 16)
+ do {
+ if (e == 99)
+ return 1;
+ DUMPBITS(t->b)
+ e -= 16;
+ NEEDBITS(e)
+ } while ((e = (t = t->v.t + ((unsigned)b & mask_bits[e]))->e) > 16);
+ DUMPBITS(t->b)
+ NEEDBITS(e)
+ d = w - t->v.n - ((unsigned)b & mask_bits[e]);
+ DUMPBITS(e)
+ Tracevv((stderr,"\\[%d,%d]", w-d, n));
+
+ /* do the copy */
+ do {
+ n -= (e = (e = WSIZE - ((d &= WSIZE-1) > w ? d : w)) > n ? n : e);
+#if !defined(NOMEMCPY) && !defined(DEBUG)
+ if (w - d >= e) /* (this test assumes unsigned comparison) */
+ {
+ memcpy(slide + w, slide + d, e);
+ w += e;
+ d += e;
+ }
+ else /* do it slow to avoid memcpy() overlap */
+#endif /* !NOMEMCPY */
+ do {
+ slide[w++] = slide[d++];
+ Tracevv((stderr, "%c", slide[w-1]));
+ } while (--e);
+ if (w == WSIZE)
+ {
+ flush_output(w);
+ w = 0;
+ }
+ } while (n);
+ }
+ }
+
+
+ /* restore the globals from the locals */
+ wp = w; /* restore global window pointer */
+ bb = b; /* restore global bit buffer */
+ bk = k;
+
+ /* done */
+ return 0;
+}
+
+
+
+int inflate_stored()
+/* "decompress" an inflated type 0 (stored) block. */
+{
+ unsigned n; /* number of bytes in block */
+ unsigned w; /* current window position */
+ register ulg b; /* bit buffer */
+ register unsigned k; /* number of bits in bit buffer */
+
+
+ /* make local copies of globals */
+ b = bb; /* initialize bit buffer */
+ k = bk;
+ w = wp; /* initialize window position */
+
+
+ /* go to byte boundary */
+ n = k & 7;
+ DUMPBITS(n);
+
+
+ /* get the length and its complement */
+ NEEDBITS(16)
+ n = ((unsigned)b & 0xffff);
+ DUMPBITS(16)
+ NEEDBITS(16)
+ if (n != (unsigned)((~b) & 0xffff))
+ return 1; /* error in compressed data */
+ DUMPBITS(16)
+
+
+ /* read and output the compressed data */
+ while (n--)
+ {
+ NEEDBITS(8)
+ slide[w++] = (uch)b;
+ if (w == WSIZE)
+ {
+ flush_output(w);
+ w = 0;
+ }
+ DUMPBITS(8)
+ }
+
+
+ /* restore the globals from the locals */
+ wp = w; /* restore global window pointer */
+ bb = b; /* restore global bit buffer */
+ bk = k;
+ return 0;
+}
+
+
+
+int inflate_fixed()
+/* decompress an inflated type 1 (fixed Huffman codes) block. We should
+ either replace this with a custom decoder, or at least precompute the
+ Huffman tables. */
+{
+ int i; /* temporary variable */
+ struct huft *tl; /* literal/length code table */
+ struct huft *td; /* distance code table */
+ int bl; /* lookup bits for tl */
+ int bd; /* lookup bits for td */
+ unsigned l[288]; /* length list for huft_build */
+
+
+ /* set up literal table */
+ for (i = 0; i < 144; i++)
+ l[i] = 8;
+ for (; i < 256; i++)
+ l[i] = 9;
+ for (; i < 280; i++)
+ l[i] = 7;
+ for (; i < 288; i++) /* make a complete, but wrong code set */
+ l[i] = 8;
+ bl = 7;
+ if ((i = huft_build(l, 288, 257, cplens, cplext, &tl, &bl)) != 0)
+ return i;
+
+
+ /* set up distance table */
+ for (i = 0; i < 30; i++) /* make an incomplete code set */
+ l[i] = 5;
+ bd = 5;
+ if ((i = huft_build(l, 30, 0, cpdist, cpdext, &td, &bd)) > 1)
+ {
+ huft_free(tl);
+ return i;
+ }
+
+
+ /* decompress until an end-of-block code */
+ if (inflate_codes(tl, td, bl, bd))
+ return 1;
+
+
+ /* free the decoding tables, return */
+ huft_free(tl);
+ huft_free(td);
+ return 0;
+}
+
+
+
+int inflate_dynamic()
+/* decompress an inflated type 2 (dynamic Huffman codes) block. */
+{
+ int i; /* temporary variables */
+ unsigned j;
+ unsigned l; /* last length */
+ unsigned m; /* mask for bit lengths table */
+ unsigned n; /* number of lengths to get */
+ struct huft *tl; /* literal/length code table */
+ struct huft *td; /* distance code table */
+ int bl; /* lookup bits for tl */
+ int bd; /* lookup bits for td */
+ unsigned nb; /* number of bit length codes */
+ unsigned nl; /* number of literal/length codes */
+ unsigned nd; /* number of distance codes */
+#ifdef PKZIP_BUG_WORKAROUND
+ unsigned ll[288+32]; /* literal/length and distance code lengths */
+#else
+ unsigned ll[286+30]; /* literal/length and distance code lengths */
+#endif
+ register ulg b; /* bit buffer */
+ register unsigned k; /* number of bits in bit buffer */
+
+
+ /* make local bit buffer */
+ b = bb;
+ k = bk;
+
+
+ /* read in table lengths */
+ NEEDBITS(5)
+ nl = 257 + ((unsigned)b & 0x1f); /* number of literal/length codes */
+ DUMPBITS(5)
+ NEEDBITS(5)
+ nd = 1 + ((unsigned)b & 0x1f); /* number of distance codes */
+ DUMPBITS(5)
+ NEEDBITS(4)
+ nb = 4 + ((unsigned)b & 0xf); /* number of bit length codes */
+ DUMPBITS(4)
+#ifdef PKZIP_BUG_WORKAROUND
+ if (nl > 288 || nd > 32)
+#else
+ if (nl > 286 || nd > 30)
+#endif
+ return 1; /* bad lengths */
+
+
+ /* read in bit-length-code lengths */
+ for (j = 0; j < nb; j++)
+ {
+ NEEDBITS(3)
+ ll[border[j]] = (unsigned)b & 7;
+ DUMPBITS(3)
+ }
+ for (; j < 19; j++)
+ ll[border[j]] = 0;
+
+
+ /* build decoding table for trees--single level, 7 bit lookup */
+ bl = 7;
+ if ((i = huft_build(ll, 19, 19, NULL, NULL, &tl, &bl)) != 0)
+ {
+ if (i == 1)
+ huft_free(tl);
+ return i; /* incomplete code set */
+ }
+
+
+ /* read in literal and distance code lengths */
+ n = nl + nd;
+ m = mask_bits[bl];
+ i = l = 0;
+ while ((unsigned)i < n)
+ {
+ NEEDBITS((unsigned)bl)
+ j = (td = tl + ((unsigned)b & m))->b;
+ DUMPBITS(j)
+ j = td->v.n;
+ if (j < 16) /* length of code in bits (0..15) */
+ ll[i++] = l = j; /* save last length in l */
+ else if (j == 16) /* repeat last length 3 to 6 times */
+ {
+ NEEDBITS(2)
+ j = 3 + ((unsigned)b & 3);
+ DUMPBITS(2)
+ if ((unsigned)i + j > n)
+ return 1;
+ while (j--)
+ ll[i++] = l;
+ }
+ else if (j == 17) /* 3 to 10 zero length codes */
+ {
+ NEEDBITS(3)
+ j = 3 + ((unsigned)b & 7);
+ DUMPBITS(3)
+ if ((unsigned)i + j > n)
+ return 1;
+ while (j--)
+ ll[i++] = 0;
+ l = 0;
+ }
+ else /* j == 18: 11 to 138 zero length codes */
+ {
+ NEEDBITS(7)
+ j = 11 + ((unsigned)b & 0x7f);
+ DUMPBITS(7)
+ if ((unsigned)i + j > n)
+ return 1;
+ while (j--)
+ ll[i++] = 0;
+ l = 0;
+ }
+ }
+
+
+ /* free decoding table for trees */
+ huft_free(tl);
+
+
+ /* restore the global bit buffer */
+ bb = b;
+ bk = k;
+
+
+ /* build the decoding tables for literal/length and distance codes */
+ bl = lbits;
+ if ((i = huft_build(ll, nl, 257, cplens, cplext, &tl, &bl)) != 0)
+ {
+ if (i == 1) {
+ fprintf(stderr, " incomplete literal tree\n");
+ huft_free(tl);
+ }
+ return i; /* incomplete code set */
+ }
+ bd = dbits;
+ if ((i = huft_build(ll + nl, nd, 0, cpdist, cpdext, &td, &bd)) != 0)
+ {
+ if (i == 1) {
+ fprintf(stderr, " incomplete distance tree\n");
+#ifdef PKZIP_BUG_WORKAROUND
+ i = 0;
+ }
+#else
+ huft_free(td);
+ }
+ huft_free(tl);
+ return i; /* incomplete code set */
+#endif
+ }
+
+
+ /* decompress until an end-of-block code */
+ if (inflate_codes(tl, td, bl, bd))
+ return 1;
+
+
+ /* free the decoding tables, return */
+ huft_free(tl);
+ huft_free(td);
+ return 0;
+}
+
+
+
+int inflate_block(e)
+int *e; /* last block flag */
+/* decompress an inflated block */
+{
+ unsigned t; /* block type */
+ register ulg b; /* bit buffer */
+ register unsigned k; /* number of bits in bit buffer */
+
+
+ /* make local bit buffer */
+ b = bb;
+ k = bk;
+
+
+ /* read in last block bit */
+ NEEDBITS(1)
+ *e = (int)b & 1;
+ DUMPBITS(1)
+
+
+ /* read in block type */
+ NEEDBITS(2)
+ t = (unsigned)b & 3;
+ DUMPBITS(2)
+
+
+ /* restore the global bit buffer */
+ bb = b;
+ bk = k;
+
+
+ /* inflate that block type */
+ if (t == 2)
+ return inflate_dynamic();
+ if (t == 0)
+ return inflate_stored();
+ if (t == 1)
+ return inflate_fixed();
+
+
+ /* bad block type */
+ return 2;
+}
+
+
+
+int inflate()
+/* decompress an inflated entry */
+{
+ int e; /* last block flag */
+ int r; /* result code */
+ unsigned h; /* maximum struct huft's malloc'ed */
+
+
+ /* initialize window, bit buffer */
+ wp = 0;
+ bk = 0;
+ bb = 0;
+
+
+ /* decompress until the last block */
+ h = 0;
+ do {
+ hufts = 0;
+ if ((r = inflate_block(&e)) != 0)
+ return r;
+ if (hufts > h)
+ h = hufts;
+ } while (!e);
+
+ /* Undo too much lookahead. The next read will be byte aligned so we
+ * can discard unused bits in the last meaningful byte.
+ */
+ while (bk >= 8) {
+ bk -= 8;
+ inptr--;
+ }
+
+ /* flush out slide */
+ flush_output(wp);
+
+
+ /* return success */
+#ifdef DEBUG
+ fprintf(stderr, "<%u> ", h);
+#endif /* DEBUG */
+ return 0;
+}
diff --git a/gnu/usr.bin/gzip/lzw.c b/gnu/usr.bin/gzip/lzw.c
new file mode 100644
index 0000000..12bf5c6
--- /dev/null
+++ b/gnu/usr.bin/gzip/lzw.c
@@ -0,0 +1,26 @@
+/* lzw.c -- compress files in LZW format.
+ * This is a dummy version avoiding patent problems.
+ */
+
+#ifdef RCSID
+static char rcsid[] = "$Id: lzw.c,v 0.9 1993/06/10 13:27:31 jloup Exp $";
+#endif
+
+#include "tailor.h"
+#include "gzip.h"
+#include "lzw.h"
+
+static int msg_done = 0;
+
+/* Compress in to out with lzw method. */
+int lzw(in, out)
+ int in, out;
+{
+ if (msg_done) return ERROR;
+ msg_done = 1;
+ fprintf(stderr,"output in compress .Z format not supported\n");
+ if (in != out) { /* avoid warnings on unused variables */
+ exit_code = ERROR;
+ }
+ return ERROR;
+}
diff --git a/gnu/usr.bin/gzip/lzw.h b/gnu/usr.bin/gzip/lzw.h
new file mode 100644
index 0000000..4b7ac86
--- /dev/null
+++ b/gnu/usr.bin/gzip/lzw.h
@@ -0,0 +1,42 @@
+/* lzw.h -- define the lzw functions.
+ * Copyright (C) 1992-1993 Jean-loup Gailly.
+ * This is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License, see the file COPYING.
+ */
+
+#if !defined(OF) && defined(lint)
+# include "gzip.h"
+#endif
+
+#ifndef BITS
+# define BITS 16
+#endif
+#define INIT_BITS 9 /* Initial number of bits per code */
+
+#define LZW_MAGIC "\037\235" /* Magic header for lzw files, 1F 9D */
+
+#define BIT_MASK 0x1f /* Mask for 'number of compression bits' */
+/* Mask 0x20 is reserved to mean a fourth header byte, and 0x40 is free.
+ * It's a pity that old uncompress does not check bit 0x20. That makes
+ * extension of the format actually undesirable because old compress
+ * would just crash on the new format instead of giving a meaningful
+ * error message. It does check the number of bits, but it's more
+ * helpful to say "unsupported format, get a new version" than
+ * "can only handle 16 bits".
+ */
+
+#define BLOCK_MODE 0x80
+/* Block compression: if table is full and compression rate is dropping,
+ * clear the dictionary.
+ */
+
+#define LZW_RESERVED 0x60 /* reserved bits */
+
+#define CLEAR 256 /* flush the dictionary */
+#define FIRST (CLEAR+1) /* first free entry */
+
+extern int maxbits; /* max bits per code for LZW */
+extern int block_mode; /* block compress mode -C compatible with 2.0 */
+
+extern int lzw OF((int in, int out));
+extern int unlzw OF((int in, int out));
diff --git a/gnu/usr.bin/gzip/match.S b/gnu/usr.bin/gzip/match.S
new file mode 100644
index 0000000..4a3d681
--- /dev/null
+++ b/gnu/usr.bin/gzip/match.S
@@ -0,0 +1,379 @@
+/* match.s -- optional optimized asm version of longest match in deflate.c
+ * Copyright (C) 1992-1993 Jean-loup Gailly
+ * This is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License, see the file COPYING.
+ *
+ * The 68020 version has been written by Francesco Potorti` <pot@cnuce.cnr.it>
+ * with adaptations by Carsten Steger <stegerc@informatik.tu-muenchen.de>,
+ * Andreas Schwab <schwab@lamothe.informatik.uni-dortmund.de> and
+ * Kristoffer Eriksson <ske@pkmab.se>
+ */
+
+/* $Id: match.S,v 0.14 1993/06/11 18:33:24 jloup Exp $ */
+
+/* Preprocess with -DNO_UNDERLINE if your C compiler does not prefix
+ * external symbols with an underline character '_'.
+ */
+#ifdef NO_UNDERLINE
+# define _prev prev
+# define _window window
+# define _match_start match_start
+# define _prev_length prev_length
+# define _good_match good_match
+# define _nice_match nice_match
+# define _strstart strstart
+# define _max_chain_length max_chain_length
+
+# define _match_init match_init
+# define _longest_match longest_match
+#endif
+
+#ifdef DYN_ALLOC
+ error: DYN_ALLOC not yet supported in match.s
+#endif
+
+#if defined(i386) || defined(_I386)
+
+/* This version is for 386 Unix or OS/2 in 32 bit mode.
+ * Warning: it uses the AT&T syntax: mov source,dest
+ * This file is only optional. If you want to force the C version,
+ * add -DNO_ASM to CFLAGS in Makefile and set OBJA to an empty string.
+ * If you have reduced WSIZE in gzip.h, then change its value below.
+ * This version assumes static allocation of the arrays (-DDYN_ALLOC not used).
+ */
+
+ .file "match.S"
+
+#define MAX_MATCH 258
+#define MAX_MATCH2 $128 /* MAX_MATCH/2-1 */
+#define MIN_MATCH 3
+#define WSIZE $32768
+#define MAX_DIST WSIZE - MAX_MATCH - MIN_MATCH - 1
+
+ .globl _match_init
+ .globl _longest_match
+
+ .text
+
+_match_init:
+ ret
+
+/*-----------------------------------------------------------------------
+ * Set match_start to the longest match starting at the given string and
+ * return its length. Matches shorter or equal to prev_length are discarded,
+ * in which case the result is equal to prev_length and match_start is
+ * garbage.
+ * IN assertions: cur_match is the head of the hash chain for the current
+ * string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1
+ */
+
+_longest_match: /* int longest_match(cur_match) */
+
+#define cur_match 20(%esp)
+ /* return address */ /* esp+16 */
+ push %ebp /* esp+12 */
+ push %edi /* esp+8 */
+ push %esi /* esp+4 */
+ push %ebx /* esp */
+
+/*
+ * match equ esi
+ * scan equ edi
+ * chain_length equ ebp
+ * best_len equ ebx
+ * limit equ edx
+ */
+ mov cur_match,%esi
+ mov _max_chain_length,%ebp /* chain_length = max_chain_length */
+ mov _strstart,%edi
+ mov %edi,%edx
+ sub MAX_DIST,%edx /* limit = strstart-MAX_DIST */
+ jae limit_ok
+ sub %edx,%edx /* limit = NIL */
+limit_ok:
+ add $2+_window,%edi /* edi = offset(window+strstart+2) */
+ mov _prev_length,%ebx /* best_len = prev_length */
+ movw -3(%ebx,%edi),%ax /* ax = scan[best_len-1..best_len] */
+ movw -2(%edi),%cx /* cx = scan[0..1] */
+ cmp _good_match,%ebx /* do we have a good match already? */
+ jb do_scan
+ shr $2,%ebp /* chain_length >>= 2 */
+ jmp do_scan
+
+ .align 4
+long_loop:
+/* at this point, edi == scan+2, esi == cur_match */
+ movw -3(%ebx,%edi),%ax /* ax = scan[best_len-1..best_len] */
+ movw -2(%edi),%cx /* cx = scan[0..1] */
+short_loop:
+/*
+ * at this point, di == scan+2, si == cur_match,
+ * ax = scan[best_len-1..best_len] and cx = scan[0..1]
+ */
+ and WSIZE-1, %esi
+ movw _prev(%esi,%esi),%si /* cur_match = prev[cur_match] */
+ /* top word of esi is still 0 */
+ cmp %edx,%esi /* cur_match <= limit ? */
+ jbe the_end
+ dec %ebp /* --chain_length */
+ jz the_end
+do_scan:
+ cmpw _window-1(%ebx,%esi),%ax/* check match at best_len-1 */
+ jne short_loop
+ cmpw _window(%esi),%cx /* check min_match_length match */
+ jne short_loop
+
+ lea _window+2(%esi),%esi /* si = match */
+ mov %edi,%eax /* ax = scan+2 */
+ mov MAX_MATCH2,%ecx /* scan for at most MAX_MATCH bytes */
+ rep; cmpsw /* loop until mismatch */
+ je maxmatch /* match of length MAX_MATCH? */
+mismatch:
+ movb -2(%edi),%cl /* mismatch on first or second byte? */
+ subb -2(%esi),%cl /* cl = 0 if first bytes equal */
+ xchg %edi,%eax /* edi = scan+2, eax = end of scan */
+ sub %edi,%eax /* eax = len */
+ sub %eax,%esi /* esi = cur_match + 2 + offset(window) */
+ sub $2+_window,%esi /* esi = cur_match */
+ subb $1,%cl /* set carry if cl == 0 (cannot use DEC) */
+ adc $0,%eax /* eax = carry ? len+1 : len */
+ cmp %ebx,%eax /* len > best_len ? */
+ jle long_loop
+ mov %esi,_match_start /* match_start = cur_match */
+ mov %eax,%ebx /* ebx = best_len = len */
+ cmp _nice_match,%eax /* len >= nice_match ? */
+ jl long_loop
+the_end:
+ mov %ebx,%eax /* result = eax = best_len */
+ pop %ebx
+ pop %esi
+ pop %edi
+ pop %ebp
+ ret
+maxmatch:
+ cmpsb
+ jmp mismatch
+
+#else
+
+/* ======================== 680x0 version ================================= */
+
+#if defined(m68k)||defined(mc68k)||defined(__mc68000__)||defined(__MC68000__)
+# ifndef mc68000
+# define mc68000
+# endif
+#endif
+
+#if defined(__mc68020__) || defined(__MC68020__) || defined(sysV68)
+# ifndef mc68020
+# define mc68020
+# endif
+#endif
+
+#if defined(mc68020) || defined(mc68000)
+
+#if (defined(mc68020) || defined(NeXT)) && !defined(UNALIGNED_OK)
+# define UNALIGNED_OK
+#endif
+
+#ifdef sysV68 /* Try Motorola Delta style */
+
+# define GLOBAL(symbol) global symbol
+# define TEXT text
+# define FILE(filename) file filename
+# define invert_maybe(src,dst) dst,src
+# define imm(data) &data
+# define reg(register) %register
+
+# define addl add.l
+# define addql addq.l
+# define blos blo.b
+# define bhis bhi.b
+# define bras bra.b
+# define clrl clr.l
+# define cmpmb cmpm.b
+# define cmpw cmp.w
+# define cmpl cmp.l
+# define lslw lsl.w
+# define lsrl lsr.l
+# define movel move.l
+# define movew move.w
+# define moveb move.b
+# define moveml movem.l
+# define subl sub.l
+# define subw sub.w
+# define subql subq.l
+
+# define IndBase(bd,An) (bd,An)
+# define IndBaseNdxl(bd,An,Xn) (bd,An,Xn.l)
+# define IndBaseNdxw(bd,An,Xn) (bd,An,Xn.w)
+# define predec(An) -(An)
+# define postinc(An) (An)+
+
+#else /* default style (Sun 3, NeXT, Amiga, Atari) */
+
+# define GLOBAL(symbol) .globl symbol
+# define TEXT .text
+# define FILE(filename) .even
+# define invert_maybe(src,dst) src,dst
+# if defined(sun) || defined(mc68k)
+# define imm(data) #data
+# else
+# define imm(data) \#data
+# endif
+# define reg(register) register
+
+# define blos bcss
+# if defined(sun) || defined(mc68k)
+# define movel movl
+# define movew movw
+# define moveb movb
+# endif
+# define IndBase(bd,An) An@(bd)
+# define IndBaseNdxl(bd,An,Xn) An@(bd,Xn:l)
+# define IndBaseNdxw(bd,An,Xn) An@(bd,Xn:w)
+# define predec(An) An@-
+# define postinc(An) An@+
+
+#endif /* styles */
+
+#define Best_Len reg(d0) /* unsigned */
+#define Cur_Match reg(d1) /* Ipos */
+#define Loop_Counter reg(d2) /* int */
+#define Scan_Start reg(d3) /* unsigned short */
+#define Scan_End reg(d4) /* unsigned short */
+#define Limit reg(d5) /* IPos */
+#define Chain_Length reg(d6) /* unsigned */
+#define Scan_Test reg(d7)
+#define Scan reg(a0) /* *uch */
+#define Match reg(a1) /* *uch */
+#define Prev_Address reg(a2) /* *Pos */
+#define Scan_Ini reg(a3) /* *uch */
+#define Match_Ini reg(a4) /* *uch */
+#define Stack_Pointer reg(sp)
+
+#define MAX_MATCH 258
+#define MIN_MATCH 3
+#define WSIZE 32768
+#define MAX_DIST (WSIZE - MAX_MATCH - MIN_MATCH - 1)
+
+ GLOBAL (_match_init)
+ GLOBAL (_longest_match)
+
+ TEXT
+
+ FILE ("match.S")
+
+_match_init:
+ rts
+
+/*-----------------------------------------------------------------------
+ * Set match_start to the longest match starting at the given string and
+ * return its length. Matches shorter or equal to prev_length are discarded,
+ * in which case the result is equal to prev_length and match_start is
+ * garbage.
+ * IN assertions: cur_match is the head of the hash chain for the current
+ * string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1
+ */
+
+/* int longest_match (cur_match) */
+
+#ifdef UNALIGNED_OK
+# define pushreg 15928 /* d2-d6/a2-a4 */
+# define popreg 7292
+#else
+# define pushreg 16184 /* d2-d7/a2-a4 */
+# define popreg 7420
+#endif
+
+_longest_match:
+ movel IndBase(4,Stack_Pointer),Cur_Match
+ moveml imm(pushreg),predec(Stack_Pointer)
+ movel _max_chain_length,Chain_Length
+ movel _prev_length,Best_Len
+ movel imm(_prev),Prev_Address
+ movel imm(_window+MIN_MATCH),Match_Ini
+ movel _strstart,Limit
+ movel Match_Ini,Scan_Ini
+ addl Limit,Scan_Ini
+ subw imm(MAX_DIST),Limit
+ bhis L__limit_ok
+ clrl Limit
+L__limit_ok:
+ cmpl invert_maybe(_good_match,Best_Len)
+ blos L__length_ok
+ lsrl imm(2),Chain_Length
+L__length_ok:
+ subql imm(1),Chain_Length
+#ifdef UNALIGNED_OK
+ movew IndBase(-MIN_MATCH,Scan_Ini),Scan_Start
+ movew IndBaseNdxw(-MIN_MATCH-1,Scan_Ini,Best_Len),Scan_End
+#else
+ moveb IndBase(-MIN_MATCH,Scan_Ini),Scan_Start
+ lslw imm(8),Scan_Start
+ moveb IndBase(-MIN_MATCH+1,Scan_Ini),Scan_Start
+ moveb IndBaseNdxw(-MIN_MATCH-1,Scan_Ini,Best_Len),Scan_End
+ lslw imm(8),Scan_End
+ moveb IndBaseNdxw(-MIN_MATCH,Scan_Ini,Best_Len),Scan_End
+#endif
+ bras L__do_scan
+
+L__long_loop:
+#ifdef UNALIGNED_OK
+ movew IndBaseNdxw(-MIN_MATCH-1,Scan_Ini,Best_Len),Scan_End
+#else
+ moveb IndBaseNdxw(-MIN_MATCH-1,Scan_Ini,Best_Len),Scan_End
+ lslw imm(8),Scan_End
+ moveb IndBaseNdxw(-MIN_MATCH,Scan_Ini,Best_Len),Scan_End
+#endif
+
+L__short_loop:
+ lslw imm(1),Cur_Match
+ movew IndBaseNdxl(0,Prev_Address,Cur_Match),Cur_Match
+ cmpw invert_maybe(Limit,Cur_Match)
+ dbls Chain_Length,L__do_scan
+ bras L__return
+
+L__do_scan:
+ movel Match_Ini,Match
+ addl Cur_Match,Match
+#ifdef UNALIGNED_OK
+ cmpw invert_maybe(IndBaseNdxw(-MIN_MATCH-1,Match,Best_Len),Scan_End)
+ bne L__short_loop
+ cmpw invert_maybe(IndBase(-MIN_MATCH,Match),Scan_Start)
+ bne L__short_loop
+#else
+ moveb IndBaseNdxw(-MIN_MATCH-1,Match,Best_Len),Scan_Test
+ lslw imm(8),Scan_Test
+ moveb IndBaseNdxw(-MIN_MATCH,Match,Best_Len),Scan_Test
+ cmpw invert_maybe(Scan_Test,Scan_End)
+ bne L__short_loop
+ moveb IndBase(-MIN_MATCH,Match),Scan_Test
+ lslw imm(8),Scan_Test
+ moveb IndBase(-MIN_MATCH+1,Match),Scan_Test
+ cmpw invert_maybe(Scan_Test,Scan_Start)
+ bne L__short_loop
+#endif
+
+ movew imm((MAX_MATCH-MIN_MATCH+1)-1),Loop_Counter
+ movel Scan_Ini,Scan
+L__scan_loop:
+ cmpmb postinc(Match),postinc(Scan)
+ dbne Loop_Counter,L__scan_loop
+
+ subl Scan_Ini,Scan
+ addql imm(MIN_MATCH-1),Scan
+ cmpl invert_maybe(Best_Len,Scan)
+ bls L__short_loop
+ movel Scan,Best_Len
+ movel Cur_Match,_match_start
+ cmpl invert_maybe(_nice_match,Best_Len)
+ blos L__long_loop
+L__return:
+ moveml postinc(Stack_Pointer),imm(popreg)
+ rts
+
+#else
+ error: this asm version is for 386 or 680x0 only
+#endif /* mc68000 || mc68020 */
+#endif /* i386 || _I386 */
diff --git a/gnu/usr.bin/gzip/revision.h b/gnu/usr.bin/gzip/revision.h
new file mode 100644
index 0000000..f99b65f
--- /dev/null
+++ b/gnu/usr.bin/gzip/revision.h
@@ -0,0 +1,16 @@
+/* revision.h -- define the version number
+ * Copyright (C) 1992-1993 Jean-loup Gailly.
+ * This is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License, see the file COPYING.
+ */
+
+#define VERSION "1.2.4"
+#define PATCHLEVEL 0
+#define REVDATE "18 Aug 93"
+
+/* This version does not support compression into old compress format: */
+#ifdef LZW
+# undef LZW
+#endif
+
+/* $Id: revision.h,v 0.25 1993/06/24 08:29:52 jloup Exp $ */
diff --git a/gnu/usr.bin/gzip/tailor.h b/gnu/usr.bin/gzip/tailor.h
new file mode 100644
index 0000000..840733a
--- /dev/null
+++ b/gnu/usr.bin/gzip/tailor.h
@@ -0,0 +1,328 @@
+/* tailor.h -- target dependent definitions
+ * Copyright (C) 1992-1993 Jean-loup Gailly.
+ * This is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License, see the file COPYING.
+ */
+
+/* The target dependent definitions should be defined here only.
+ * The target dependent functions should be defined in tailor.c.
+ */
+
+/* $Id: tailor.h,v 1.3 1993/10/14 00:33:08 nate Exp $ */
+
+#if defined(__MSDOS__) && !defined(MSDOS)
+# define MSDOS
+#endif
+
+#if defined(__OS2__) && !defined(OS2)
+# define OS2
+#endif
+
+#if defined(OS2) && defined(MSDOS) /* MS C under OS/2 */
+# undef MSDOS
+#endif
+
+#ifdef MSDOS
+# ifdef __GNUC__
+ /* DJGPP version 1.09+ on MS-DOS.
+ * The DJGPP 1.09 stat() function must be upgraded before gzip will
+ * fully work.
+ * No need for DIRENT, since <unistd.h> defines POSIX_SOURCE which
+ * implies DIRENT.
+ */
+# define near
+# else
+# define MAXSEG_64K
+# ifdef __TURBOC__
+# define NO_OFF_T
+# ifdef __BORLANDC__
+# define DIRENT
+# else
+# define NO_UTIME
+# endif
+# else /* MSC */
+# define HAVE_SYS_UTIME_H
+# define NO_UTIME_H
+# endif
+# endif
+# define PATH_SEP2 '\\'
+# define PATH_SEP3 ':'
+# define MAX_PATH_LEN 128
+# define NO_MULTIPLE_DOTS
+# define MAX_EXT_CHARS 3
+# define Z_SUFFIX "z"
+# define NO_CHOWN
+# define PROTO
+# define STDC_HEADERS
+# define NO_SIZE_CHECK
+# define casemap(c) tolow(c) /* Force file names to lower case */
+# include <io.h>
+# define OS_CODE 0x00
+# define SET_BINARY_MODE(fd) setmode(fd, O_BINARY)
+# if !defined(NO_ASM) && !defined(ASMV)
+# define ASMV
+# endif
+#else
+# define near
+#endif
+
+#ifdef OS2
+# define PATH_SEP2 '\\'
+# define PATH_SEP3 ':'
+# define MAX_PATH_LEN 260
+# ifdef OS2FAT
+# define NO_MULTIPLE_DOTS
+# define MAX_EXT_CHARS 3
+# define Z_SUFFIX "z"
+# define casemap(c) tolow(c)
+# endif
+# define NO_CHOWN
+# define PROTO
+# define STDC_HEADERS
+# include <io.h>
+# define OS_CODE 0x06
+# define SET_BINARY_MODE(fd) setmode(fd, O_BINARY)
+# ifdef _MSC_VER
+# define HAVE_SYS_UTIME_H
+# define NO_UTIME_H
+# define MAXSEG_64K
+# undef near
+# define near _near
+# endif
+# ifdef __EMX__
+# define HAVE_SYS_UTIME_H
+# define NO_UTIME_H
+# define DIRENT
+# define EXPAND(argc,argv) \
+ {_response(&argc, &argv); _wildcard(&argc, &argv);}
+# endif
+# ifdef __BORLANDC__
+# define DIRENT
+# endif
+# ifdef __ZTC__
+# define NO_DIR
+# define NO_UTIME_H
+# include <dos.h>
+# define EXPAND(argc,argv) \
+ {response_expand(&argc, &argv);}
+# endif
+#endif
+
+#ifdef WIN32 /* Windows NT */
+# define HAVE_SYS_UTIME_H
+# define NO_UTIME_H
+# define PATH_SEP2 '\\'
+# define PATH_SEP3 ':'
+# define MAX_PATH_LEN 260
+# define NO_CHOWN
+# define PROTO
+# define STDC_HEADERS
+# define SET_BINARY_MODE(fd) setmode(fd, O_BINARY)
+# include <io.h>
+# include <malloc.h>
+# ifdef NTFAT
+# define NO_MULTIPLE_DOTS
+# define MAX_EXT_CHARS 3
+# define Z_SUFFIX "z"
+# define casemap(c) tolow(c) /* Force file names to lower case */
+# endif
+# define OS_CODE 0x0b
+#endif
+
+#ifdef MSDOS
+# ifdef __TURBOC__
+# include <alloc.h>
+# define DYN_ALLOC
+ /* Turbo C 2.0 does not accept static allocations of large arrays */
+ void * fcalloc (unsigned items, unsigned size);
+ void fcfree (void *ptr);
+# else /* MSC */
+# include <malloc.h>
+# define fcalloc(nitems,itemsize) halloc((long)(nitems),(itemsize))
+# define fcfree(ptr) hfree(ptr)
+# endif
+#else
+# ifdef MAXSEG_64K
+# define fcalloc(items,size) calloc((items),(size))
+# else
+# define fcalloc(items,size) malloc((size_t)(items)*(size_t)(size))
+# endif
+# define fcfree(ptr) free(ptr)
+#endif
+
+#if defined(VAXC) || defined(VMS)
+# define PATH_SEP ']'
+# define PATH_SEP2 ':'
+# define SUFFIX_SEP ';'
+# define NO_MULTIPLE_DOTS
+# define Z_SUFFIX "-gz"
+# define RECORD_IO 1
+# define casemap(c) tolow(c)
+# define OS_CODE 0x02
+# define OPTIONS_VAR "GZIP_OPT"
+# define STDC_HEADERS
+# define NO_UTIME
+# define EXPAND(argc,argv) vms_expand_args(&argc,&argv);
+# include <file.h>
+# define unlink delete
+# ifdef VAXC
+# define NO_FCNTL_H
+# include <unixio.h>
+# endif
+#endif
+
+#ifdef AMIGA
+# define PATH_SEP2 ':'
+# define STDC_HEADERS
+# define OS_CODE 0x01
+# define ASMV
+# ifdef __GNUC__
+# define DIRENT
+# define HAVE_UNISTD_H
+# else /* SASC */
+# define NO_STDIN_FSTAT
+# define SYSDIR
+# define NO_SYMLINK
+# define NO_CHOWN
+# define NO_FCNTL_H
+# include <fcntl.h> /* for read() and write() */
+# define direct dirent
+ extern void _expand_args(int *argc, char ***argv);
+# define EXPAND(argc,argv) _expand_args(&argc,&argv);
+# undef O_BINARY /* disable useless --ascii option */
+# endif
+#endif
+
+#if defined(ATARI) || defined(atarist)
+# ifndef STDC_HEADERS
+# define STDC_HEADERS
+# define HAVE_UNISTD_H
+# define DIRENT
+# endif
+# define ASMV
+# define OS_CODE 0x05
+# ifdef TOSFS
+# define PATH_SEP2 '\\'
+# define PATH_SEP3 ':'
+# define MAX_PATH_LEN 128
+# define NO_MULTIPLE_DOTS
+# define MAX_EXT_CHARS 3
+# define Z_SUFFIX "z"
+# define NO_CHOWN
+# define casemap(c) tolow(c) /* Force file names to lower case */
+# define NO_SYMLINK
+# endif
+#endif
+
+#ifdef MACOS
+# define PATH_SEP ':'
+# define DYN_ALLOC
+# define PROTO
+# define NO_STDIN_FSTAT
+# define NO_CHOWN
+# define NO_UTIME
+# define chmod(file, mode) (0)
+# define OPEN(name, flags, mode) open(name, flags)
+# define OS_CODE 0x07
+# ifdef MPW
+# define isatty(fd) ((fd) <= 2)
+# endif
+#endif
+
+#ifdef __50SERIES /* Prime/PRIMOS */
+# define PATH_SEP '>'
+# define STDC_HEADERS
+# define NO_MEMORY_H
+# define NO_UTIME_H
+# define NO_UTIME
+# define NO_CHOWN
+# define NO_STDIN_FSTAT
+# define NO_SIZE_CHECK
+# define NO_SYMLINK
+# define RECORD_IO 1
+# define casemap(c) tolow(c) /* Force file names to lower case */
+# define put_char(c) put_byte((c) & 0x7F)
+# define get_char(c) ascii2pascii(get_byte())
+# define OS_CODE 0x0F /* temporary, subject to change */
+# ifdef SIGTERM
+# undef SIGTERM /* We don't want a signal handler for SIGTERM */
+# endif
+#endif
+
+#if defined(pyr) && !defined(NOMEMCPY) /* Pyramid */
+# define NOMEMCPY /* problem with overlapping copies */
+#endif
+
+#ifdef TOPS20
+# define OS_CODE 0x0a
+#endif
+
+#ifndef unix
+# define NO_ST_INO /* don't rely on inode numbers */
+#endif
+
+
+ /* Common defaults */
+
+#ifndef OS_CODE
+# define OS_CODE 0x03 /* assume Unix */
+#endif
+
+#ifndef PATH_SEP
+# define PATH_SEP '/'
+#endif
+
+#ifndef casemap
+# define casemap(c) (c)
+#endif
+
+#ifndef OPTIONS_VAR
+# define OPTIONS_VAR "GZIP"
+#endif
+
+#ifndef Z_SUFFIX
+# define Z_SUFFIX ".gz"
+#endif
+
+#ifdef MAX_EXT_CHARS
+# define MAX_SUFFIX MAX_EXT_CHARS
+#else
+# define MAX_SUFFIX 30
+#endif
+
+#ifndef MAKE_LEGAL_NAME
+# ifdef NO_MULTIPLE_DOTS
+# define MAKE_LEGAL_NAME(name) make_simple_name(name)
+# else
+# define MAKE_LEGAL_NAME(name)
+# endif
+#endif
+
+#ifndef MIN_PART
+# define MIN_PART 3
+ /* keep at least MIN_PART chars between dots in a file name. */
+#endif
+
+#ifndef EXPAND
+# define EXPAND(argc,argv)
+#endif
+
+#ifndef RECORD_IO
+# define RECORD_IO 0
+#endif
+
+#ifndef SET_BINARY_MODE
+# define SET_BINARY_MODE(fd)
+#endif
+
+#ifndef OPEN
+# define OPEN(name, flags, mode) open(name, flags, mode)
+#endif
+
+#ifndef get_char
+# define get_char() get_byte()
+#endif
+
+#ifndef put_char
+# define put_char(c) put_byte(c)
+#endif
diff --git a/gnu/usr.bin/gzip/trees.c b/gnu/usr.bin/gzip/trees.c
new file mode 100644
index 0000000..d5b41c8
--- /dev/null
+++ b/gnu/usr.bin/gzip/trees.c
@@ -0,0 +1,1075 @@
+/* trees.c -- output deflated data using Huffman coding
+ * Copyright (C) 1992-1993 Jean-loup Gailly
+ * This is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License, see the file COPYING.
+ */
+
+/*
+ * PURPOSE
+ *
+ * Encode various sets of source values using variable-length
+ * binary code trees.
+ *
+ * DISCUSSION
+ *
+ * The PKZIP "deflation" process uses several Huffman trees. The more
+ * common source values are represented by shorter bit sequences.
+ *
+ * Each code tree is stored in the ZIP file in a compressed form
+ * which is itself a Huffman encoding of the lengths of
+ * all the code strings (in ascending order by source values).
+ * The actual code strings are reconstructed from the lengths in
+ * the UNZIP process, as described in the "application note"
+ * (APPNOTE.TXT) distributed as part of PKWARE's PKZIP program.
+ *
+ * REFERENCES
+ *
+ * Lynch, Thomas J.
+ * Data Compression: Techniques and Applications, pp. 53-55.
+ * Lifetime Learning Publications, 1985. ISBN 0-534-03418-7.
+ *
+ * Storer, James A.
+ * Data Compression: Methods and Theory, pp. 49-50.
+ * Computer Science Press, 1988. ISBN 0-7167-8156-5.
+ *
+ * Sedgewick, R.
+ * Algorithms, p290.
+ * Addison-Wesley, 1983. ISBN 0-201-06672-6.
+ *
+ * INTERFACE
+ *
+ * void ct_init (ush *attr, int *methodp)
+ * Allocate the match buffer, initialize the various tables and save
+ * the location of the internal file attribute (ascii/binary) and
+ * method (DEFLATE/STORE)
+ *
+ * void ct_tally (int dist, int lc);
+ * Save the match info and tally the frequency counts.
+ *
+ * long flush_block (char *buf, ulg stored_len, int eof)
+ * Determine the best encoding for the current block: dynamic trees,
+ * static trees or store, and output the encoded block to the zip
+ * file. Returns the total compressed length for the file so far.
+ *
+ */
+
+#include <ctype.h>
+
+#include "tailor.h"
+#include "gzip.h"
+
+#ifdef RCSID
+static char rcsid[] = "$Id: trees.c,v 1.3 1993/10/14 00:33:11 nate Exp $";
+#endif
+
+/* ===========================================================================
+ * Constants
+ */
+
+#define MAX_BITS 15
+/* All codes must not exceed MAX_BITS bits */
+
+#define MAX_BL_BITS 7
+/* Bit length codes must not exceed MAX_BL_BITS bits */
+
+#define LENGTH_CODES 29
+/* number of length codes, not counting the special END_BLOCK code */
+
+#define LITERALS 256
+/* number of literal bytes 0..255 */
+
+#define END_BLOCK 256
+/* end of block literal code */
+
+#define L_CODES (LITERALS+1+LENGTH_CODES)
+/* number of Literal or Length codes, including the END_BLOCK code */
+
+#define D_CODES 30
+/* number of distance codes */
+
+#define BL_CODES 19
+/* number of codes used to transfer the bit lengths */
+
+
+local int near extra_lbits[LENGTH_CODES] /* extra bits for each length code */
+ = {0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0};
+
+local int near extra_dbits[D_CODES] /* extra bits for each distance code */
+ = {0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13};
+
+local int near extra_blbits[BL_CODES]/* extra bits for each bit length code */
+ = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7};
+
+#define STORED_BLOCK 0
+#define STATIC_TREES 1
+#define DYN_TREES 2
+/* The three kinds of block type */
+
+#ifndef LIT_BUFSIZE
+# ifdef SMALL_MEM
+# define LIT_BUFSIZE 0x2000
+# else
+# ifdef MEDIUM_MEM
+# define LIT_BUFSIZE 0x4000
+# else
+# define LIT_BUFSIZE 0x8000
+# endif
+# endif
+#endif
+#ifndef DIST_BUFSIZE
+# define DIST_BUFSIZE LIT_BUFSIZE
+#endif
+/* Sizes of match buffers for literals/lengths and distances. There are
+ * 4 reasons for limiting LIT_BUFSIZE to 64K:
+ * - frequencies can be kept in 16 bit counters
+ * - if compression is not successful for the first block, all input data is
+ * still in the window so we can still emit a stored block even when input
+ * comes from standard input. (This can also be done for all blocks if
+ * LIT_BUFSIZE is not greater than 32K.)
+ * - if compression is not successful for a file smaller than 64K, we can
+ * even emit a stored file instead of a stored block (saving 5 bytes).
+ * - creating new Huffman trees less frequently may not provide fast
+ * adaptation to changes in the input data statistics. (Take for
+ * example a binary file with poorly compressible code followed by
+ * a highly compressible string table.) Smaller buffer sizes give
+ * fast adaptation but have of course the overhead of transmitting trees
+ * more frequently.
+ * - I can't count above 4
+ * The current code is general and allows DIST_BUFSIZE < LIT_BUFSIZE (to save
+ * memory at the expense of compression). Some optimizations would be possible
+ * if we rely on DIST_BUFSIZE == LIT_BUFSIZE.
+ */
+#if LIT_BUFSIZE > INBUFSIZ
+ error cannot overlay l_buf and inbuf
+#endif
+
+#define REP_3_6 16
+/* repeat previous bit length 3-6 times (2 bits of repeat count) */
+
+#define REPZ_3_10 17
+/* repeat a zero length 3-10 times (3 bits of repeat count) */
+
+#define REPZ_11_138 18
+/* repeat a zero length 11-138 times (7 bits of repeat count) */
+
+/* ===========================================================================
+ * Local data
+ */
+
+/* Data structure describing a single value and its code string. */
+typedef struct ct_data {
+ union {
+ ush freq; /* frequency count */
+ ush code; /* bit string */
+ } fc;
+ union {
+ ush dad; /* father node in Huffman tree */
+ ush len; /* length of bit string */
+ } dl;
+} ct_data;
+
+#define Freq fc.freq
+#define Code fc.code
+#define Dad dl.dad
+#define Len dl.len
+
+#define HEAP_SIZE (2*L_CODES+1)
+/* maximum heap size */
+
+local ct_data near dyn_ltree[HEAP_SIZE]; /* literal and length tree */
+local ct_data near dyn_dtree[2*D_CODES+1]; /* distance tree */
+
+local ct_data near static_ltree[L_CODES+2];
+/* The static literal tree. Since the bit lengths are imposed, there is no
+ * need for the L_CODES extra codes used during heap construction. However
+ * The codes 286 and 287 are needed to build a canonical tree (see ct_init
+ * below).
+ */
+
+local ct_data near static_dtree[D_CODES];
+/* The static distance tree. (Actually a trivial tree since all codes use
+ * 5 bits.)
+ */
+
+local ct_data near bl_tree[2*BL_CODES+1];
+/* Huffman tree for the bit lengths */
+
+typedef struct tree_desc {
+ ct_data near *dyn_tree; /* the dynamic tree */
+ ct_data near *static_tree; /* corresponding static tree or NULL */
+ int near *extra_bits; /* extra bits for each code or NULL */
+ int extra_base; /* base index for extra_bits */
+ int elems; /* max number of elements in the tree */
+ int max_length; /* max bit length for the codes */
+ int max_code; /* largest code with non zero frequency */
+} tree_desc;
+
+local tree_desc near l_desc =
+{dyn_ltree, static_ltree, extra_lbits, LITERALS+1, L_CODES, MAX_BITS, 0};
+
+local tree_desc near d_desc =
+{dyn_dtree, static_dtree, extra_dbits, 0, D_CODES, MAX_BITS, 0};
+
+local tree_desc near bl_desc =
+{bl_tree, (ct_data near *)0, extra_blbits, 0, BL_CODES, MAX_BL_BITS, 0};
+
+
+local ush near bl_count[MAX_BITS+1];
+/* number of codes at each bit length for an optimal tree */
+
+local uch near bl_order[BL_CODES]
+ = {16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15};
+/* The lengths of the bit length codes are sent in order of decreasing
+ * probability, to avoid transmitting the lengths for unused bit length codes.
+ */
+
+local int near heap[2*L_CODES+1]; /* heap used to build the Huffman trees */
+local int heap_len; /* number of elements in the heap */
+local int heap_max; /* element of largest frequency */
+/* The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used.
+ * The same heap array is used to build all trees.
+ */
+
+local uch near depth[2*L_CODES+1];
+/* Depth of each subtree used as tie breaker for trees of equal frequency */
+
+local uch length_code[MAX_MATCH-MIN_MATCH+1];
+/* length code for each normalized match length (0 == MIN_MATCH) */
+
+local uch dist_code[512];
+/* distance codes. The first 256 values correspond to the distances
+ * 3 .. 258, the last 256 values correspond to the top 8 bits of
+ * the 15 bit distances.
+ */
+
+local int near base_length[LENGTH_CODES];
+/* First normalized length for each code (0 = MIN_MATCH) */
+
+local int near base_dist[D_CODES];
+/* First normalized distance for each code (0 = distance of 1) */
+
+#define l_buf inbuf
+/* DECLARE(uch, l_buf, LIT_BUFSIZE); buffer for literals or lengths */
+
+/* DECLARE(ush, d_buf, DIST_BUFSIZE); buffer for distances */
+
+local uch near flag_buf[(LIT_BUFSIZE/8)];
+/* flag_buf is a bit array distinguishing literals from lengths in
+ * l_buf, thus indicating the presence or absence of a distance.
+ */
+
+local unsigned last_lit; /* running index in l_buf */
+local unsigned last_dist; /* running index in d_buf */
+local unsigned last_flags; /* running index in flag_buf */
+local uch flags; /* current flags not yet saved in flag_buf */
+local uch flag_bit; /* current bit used in flags */
+/* bits are filled in flags starting at bit 0 (least significant).
+ * Note: these flags are overkill in the current code since we don't
+ * take advantage of DIST_BUFSIZE == LIT_BUFSIZE.
+ */
+
+local ulg opt_len; /* bit length of current block with optimal trees */
+local ulg static_len; /* bit length of current block with static trees */
+
+local ulg compressed_len; /* total bit length of compressed file */
+
+local ulg input_len; /* total byte length of input file */
+/* input_len is for debugging only since we can get it by other means. */
+
+ush *file_type; /* pointer to UNKNOWN, BINARY or ASCII */
+int *file_method; /* pointer to DEFLATE or STORE */
+
+#ifdef DEBUG
+extern ulg bits_sent; /* bit length of the compressed data */
+extern long isize; /* byte length of input file */
+#endif
+
+extern long block_start; /* window offset of current block */
+extern unsigned near strstart; /* window offset of current string */
+
+/* ===========================================================================
+ * Local (static) routines in this file.
+ */
+
+local void init_block OF((void));
+local void pqdownheap OF((ct_data near *tree, int k));
+local void gen_bitlen OF((tree_desc near *desc));
+local void gen_codes OF((ct_data near *tree, int max_code));
+local void build_tree OF((tree_desc near *desc));
+local void scan_tree OF((ct_data near *tree, int max_code));
+local void send_tree OF((ct_data near *tree, int max_code));
+local int build_bl_tree OF((void));
+local void send_all_trees OF((int lcodes, int dcodes, int blcodes));
+local void compress_block OF((ct_data near *ltree, ct_data near *dtree));
+local void set_file_type OF((void));
+
+
+#ifndef DEBUG
+# define send_code(c, tree) send_bits(tree[c].Code, tree[c].Len)
+ /* Send a code of the given tree. c and tree must not have side effects */
+
+#else /* DEBUG */
+# define send_code(c, tree) \
+ { if (verbose>1) fprintf(stderr,"\ncd %3d ",(c)); \
+ send_bits(tree[c].Code, tree[c].Len); }
+#endif
+
+#define d_code(dist) \
+ ((dist) < 256 ? dist_code[dist] : dist_code[256+((dist)>>7)])
+/* Mapping from a distance to a distance code. dist is the distance - 1 and
+ * must not have side effects. dist_code[256] and dist_code[257] are never
+ * used.
+ */
+
+#define MAX(a,b) (a >= b ? a : b)
+/* the arguments must not have side effects */
+
+/* ===========================================================================
+ * Allocate the match buffer, initialize the various tables and save the
+ * location of the internal file attribute (ascii/binary) and method
+ * (DEFLATE/STORE).
+ */
+void ct_init(attr, methodp)
+ ush *attr; /* pointer to internal file attribute */
+ int *methodp; /* pointer to compression method */
+{
+ int n; /* iterates over tree elements */
+ int bits; /* bit counter */
+ int length; /* length value */
+ int code; /* code value */
+ int dist; /* distance index */
+
+ file_type = attr;
+ file_method = methodp;
+ compressed_len = input_len = 0L;
+
+ if (static_dtree[0].Len != 0) return; /* ct_init already called */
+
+ /* Initialize the mapping length (0..255) -> length code (0..28) */
+ length = 0;
+ for (code = 0; code < LENGTH_CODES-1; code++) {
+ base_length[code] = length;
+ for (n = 0; n < (1<<extra_lbits[code]); n++) {
+ length_code[length++] = (uch)code;
+ }
+ }
+ Assert (length == 256, "ct_init: length != 256");
+ /* Note that the length 255 (match length 258) can be represented
+ * in two different ways: code 284 + 5 bits or code 285, so we
+ * overwrite length_code[255] to use the best encoding:
+ */
+ length_code[length-1] = (uch)code;
+
+ /* Initialize the mapping dist (0..32K) -> dist code (0..29) */
+ dist = 0;
+ for (code = 0 ; code < 16; code++) {
+ base_dist[code] = dist;
+ for (n = 0; n < (1<<extra_dbits[code]); n++) {
+ dist_code[dist++] = (uch)code;
+ }
+ }
+ Assert (dist == 256, "ct_init: dist != 256");
+ dist >>= 7; /* from now on, all distances are divided by 128 */
+ for ( ; code < D_CODES; code++) {
+ base_dist[code] = dist << 7;
+ for (n = 0; n < (1<<(extra_dbits[code]-7)); n++) {
+ dist_code[256 + dist++] = (uch)code;
+ }
+ }
+ Assert (dist == 256, "ct_init: 256+dist != 512");
+
+ /* Construct the codes of the static literal tree */
+ for (bits = 0; bits <= MAX_BITS; bits++) bl_count[bits] = 0;
+ n = 0;
+ while (n <= 143) static_ltree[n++].Len = 8, bl_count[8]++;
+ while (n <= 255) static_ltree[n++].Len = 9, bl_count[9]++;
+ while (n <= 279) static_ltree[n++].Len = 7, bl_count[7]++;
+ while (n <= 287) static_ltree[n++].Len = 8, bl_count[8]++;
+ /* Codes 286 and 287 do not exist, but we must include them in the
+ * tree construction to get a canonical Huffman tree (longest code
+ * all ones)
+ */
+ gen_codes((ct_data near *)static_ltree, L_CODES+1);
+
+ /* The static distance tree is trivial: */
+ for (n = 0; n < D_CODES; n++) {
+ static_dtree[n].Len = 5;
+ static_dtree[n].Code = bi_reverse(n, 5);
+ }
+
+ /* Initialize the first block of the first file: */
+ init_block();
+}
+
+/* ===========================================================================
+ * Initialize a new block.
+ */
+local void init_block()
+{
+ int n; /* iterates over tree elements */
+
+ /* Initialize the trees. */
+ for (n = 0; n < L_CODES; n++) dyn_ltree[n].Freq = 0;
+ for (n = 0; n < D_CODES; n++) dyn_dtree[n].Freq = 0;
+ for (n = 0; n < BL_CODES; n++) bl_tree[n].Freq = 0;
+
+ dyn_ltree[END_BLOCK].Freq = 1;
+ opt_len = static_len = 0L;
+ last_lit = last_dist = last_flags = 0;
+ flags = 0; flag_bit = 1;
+}
+
+#define SMALLEST 1
+/* Index within the heap array of least frequent node in the Huffman tree */
+
+
+/* ===========================================================================
+ * Remove the smallest element from the heap and recreate the heap with
+ * one less element. Updates heap and heap_len.
+ */
+#define pqremove(tree, top) \
+{\
+ top = heap[SMALLEST]; \
+ heap[SMALLEST] = heap[heap_len--]; \
+ pqdownheap(tree, SMALLEST); \
+}
+
+/* ===========================================================================
+ * Compares to subtrees, using the tree depth as tie breaker when
+ * the subtrees have equal frequency. This minimizes the worst case length.
+ */
+#define smaller(tree, n, m) \
+ (tree[n].Freq < tree[m].Freq || \
+ (tree[n].Freq == tree[m].Freq && depth[n] <= depth[m]))
+
+/* ===========================================================================
+ * Restore the heap property by moving down the tree starting at node k,
+ * exchanging a node with the smallest of its two sons if necessary, stopping
+ * when the heap property is re-established (each father smaller than its
+ * two sons).
+ */
+local void pqdownheap(tree, k)
+ ct_data near *tree; /* the tree to restore */
+ int k; /* node to move down */
+{
+ int v = heap[k];
+ int j = k << 1; /* left son of k */
+ while (j <= heap_len) {
+ /* Set j to the smallest of the two sons: */
+ if (j < heap_len && smaller(tree, heap[j+1], heap[j])) j++;
+
+ /* Exit if v is smaller than both sons */
+ if (smaller(tree, v, heap[j])) break;
+
+ /* Exchange v with the smallest son */
+ heap[k] = heap[j]; k = j;
+
+ /* And continue down the tree, setting j to the left son of k */
+ j <<= 1;
+ }
+ heap[k] = v;
+}
+
+/* ===========================================================================
+ * Compute the optimal bit lengths for a tree and update the total bit length
+ * for the current block.
+ * IN assertion: the fields freq and dad are set, heap[heap_max] and
+ * above are the tree nodes sorted by increasing frequency.
+ * OUT assertions: the field len is set to the optimal bit length, the
+ * array bl_count contains the frequencies for each bit length.
+ * The length opt_len is updated; static_len is also updated if stree is
+ * not null.
+ */
+local void gen_bitlen(desc)
+ tree_desc near *desc; /* the tree descriptor */
+{
+ ct_data near *tree = desc->dyn_tree;
+ int near *extra = desc->extra_bits;
+ int base = desc->extra_base;
+ int max_code = desc->max_code;
+ int max_length = desc->max_length;
+ ct_data near *stree = desc->static_tree;
+ int h; /* heap index */
+ int n, m; /* iterate over the tree elements */
+ int bits; /* bit length */
+ int xbits; /* extra bits */
+ ush f; /* frequency */
+ int overflow = 0; /* number of elements with bit length too large */
+
+ for (bits = 0; bits <= MAX_BITS; bits++) bl_count[bits] = 0;
+
+ /* In a first pass, compute the optimal bit lengths (which may
+ * overflow in the case of the bit length tree).
+ */
+ tree[heap[heap_max]].Len = 0; /* root of the heap */
+
+ for (h = heap_max+1; h < HEAP_SIZE; h++) {
+ n = heap[h];
+ bits = tree[tree[n].Dad].Len + 1;
+ if (bits > max_length) bits = max_length, overflow++;
+ tree[n].Len = (ush)bits;
+ /* We overwrite tree[n].Dad which is no longer needed */
+
+ if (n > max_code) continue; /* not a leaf node */
+
+ bl_count[bits]++;
+ xbits = 0;
+ if (n >= base) xbits = extra[n-base];
+ f = tree[n].Freq;
+ opt_len += (ulg)f * (bits + xbits);
+ if (stree) static_len += (ulg)f * (stree[n].Len + xbits);
+ }
+ if (overflow == 0) return;
+
+ Trace((stderr,"\nbit length overflow\n"));
+ /* This happens for example on obj2 and pic of the Calgary corpus */
+
+ /* Find the first bit length which could increase: */
+ do {
+ bits = max_length-1;
+ while (bl_count[bits] == 0) bits--;
+ bl_count[bits]--; /* move one leaf down the tree */
+ bl_count[bits+1] += 2; /* move one overflow item as its brother */
+ bl_count[max_length]--;
+ /* The brother of the overflow item also moves one step up,
+ * but this does not affect bl_count[max_length]
+ */
+ overflow -= 2;
+ } while (overflow > 0);
+
+ /* Now recompute all bit lengths, scanning in increasing frequency.
+ * h is still equal to HEAP_SIZE. (It is simpler to reconstruct all
+ * lengths instead of fixing only the wrong ones. This idea is taken
+ * from 'ar' written by Haruhiko Okumura.)
+ */
+ for (bits = max_length; bits != 0; bits--) {
+ n = bl_count[bits];
+ while (n != 0) {
+ m = heap[--h];
+ if (m > max_code) continue;
+ if (tree[m].Len != (unsigned) bits) {
+ Trace((stderr,"code %d bits %d->%d\n", m, tree[m].Len, bits));
+ opt_len += ((long)bits-(long)tree[m].Len)*(long)tree[m].Freq;
+ tree[m].Len = (ush)bits;
+ }
+ n--;
+ }
+ }
+}
+
+/* ===========================================================================
+ * Generate the codes for a given tree and bit counts (which need not be
+ * optimal).
+ * IN assertion: the array bl_count contains the bit length statistics for
+ * the given tree and the field len is set for all tree elements.
+ * OUT assertion: the field code is set for all tree elements of non
+ * zero code length.
+ */
+local void gen_codes (tree, max_code)
+ ct_data near *tree; /* the tree to decorate */
+ int max_code; /* largest code with non zero frequency */
+{
+ ush next_code[MAX_BITS+1]; /* next code value for each bit length */
+ ush code = 0; /* running code value */
+ int bits; /* bit index */
+ int n; /* code index */
+
+ /* The distribution counts are first used to generate the code values
+ * without bit reversal.
+ */
+ for (bits = 1; bits <= MAX_BITS; bits++) {
+ next_code[bits] = code = (code + bl_count[bits-1]) << 1;
+ }
+ /* Check that the bit counts in bl_count are consistent. The last code
+ * must be all ones.
+ */
+ Assert (code + bl_count[MAX_BITS]-1 == (1<<MAX_BITS)-1,
+ "inconsistent bit counts");
+ Tracev((stderr,"\ngen_codes: max_code %d ", max_code));
+
+ for (n = 0; n <= max_code; n++) {
+ int len = tree[n].Len;
+ if (len == 0) continue;
+ /* Now reverse the bits */
+ tree[n].Code = bi_reverse(next_code[len]++, len);
+
+ Tracec(tree != static_ltree, (stderr,"\nn %3d %c l %2d c %4x (%x) ",
+ n, (isgraph(n) ? n : ' '), len, tree[n].Code, next_code[len]-1));
+ }
+}
+
+/* ===========================================================================
+ * Construct one Huffman tree and assigns the code bit strings and lengths.
+ * Update the total bit length for the current block.
+ * IN assertion: the field freq is set for all tree elements.
+ * OUT assertions: the fields len and code are set to the optimal bit length
+ * and corresponding code. The length opt_len is updated; static_len is
+ * also updated if stree is not null. The field max_code is set.
+ */
+local void build_tree(desc)
+ tree_desc near *desc; /* the tree descriptor */
+{
+ ct_data near *tree = desc->dyn_tree;
+ ct_data near *stree = desc->static_tree;
+ int elems = desc->elems;
+ int n, m; /* iterate over heap elements */
+ int max_code = -1; /* largest code with non zero frequency */
+ int node = elems; /* next internal node of the tree */
+
+ /* Construct the initial heap, with least frequent element in
+ * heap[SMALLEST]. The sons of heap[n] are heap[2*n] and heap[2*n+1].
+ * heap[0] is not used.
+ */
+ heap_len = 0, heap_max = HEAP_SIZE;
+
+ for (n = 0; n < elems; n++) {
+ if (tree[n].Freq != 0) {
+ heap[++heap_len] = max_code = n;
+ depth[n] = 0;
+ } else {
+ tree[n].Len = 0;
+ }
+ }
+
+ /* The pkzip format requires that at least one distance code exists,
+ * and that at least one bit should be sent even if there is only one
+ * possible code. So to avoid special checks later on we force at least
+ * two codes of non zero frequency.
+ */
+ while (heap_len < 2) {
+ int new = heap[++heap_len] = (max_code < 2 ? ++max_code : 0);
+ tree[new].Freq = 1;
+ depth[new] = 0;
+ opt_len--; if (stree) static_len -= stree[new].Len;
+ /* new is 0 or 1 so it does not have extra bits */
+ }
+ desc->max_code = max_code;
+
+ /* The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree,
+ * establish sub-heaps of increasing lengths:
+ */
+ for (n = heap_len/2; n >= 1; n--) pqdownheap(tree, n);
+
+ /* Construct the Huffman tree by repeatedly combining the least two
+ * frequent nodes.
+ */
+ do {
+ pqremove(tree, n); /* n = node of least frequency */
+ m = heap[SMALLEST]; /* m = node of next least frequency */
+
+ heap[--heap_max] = n; /* keep the nodes sorted by frequency */
+ heap[--heap_max] = m;
+
+ /* Create a new node father of n and m */
+ tree[node].Freq = tree[n].Freq + tree[m].Freq;
+ depth[node] = (uch) (MAX(depth[n], depth[m]) + 1);
+ tree[n].Dad = tree[m].Dad = (ush)node;
+#ifdef DUMP_BL_TREE
+ if (tree == bl_tree) {
+ fprintf(stderr,"\nnode %d(%d), sons %d(%d) %d(%d)",
+ node, tree[node].Freq, n, tree[n].Freq, m, tree[m].Freq);
+ }
+#endif
+ /* and insert the new node in the heap */
+ heap[SMALLEST] = node++;
+ pqdownheap(tree, SMALLEST);
+
+ } while (heap_len >= 2);
+
+ heap[--heap_max] = heap[SMALLEST];
+
+ /* At this point, the fields freq and dad are set. We can now
+ * generate the bit lengths.
+ */
+ gen_bitlen((tree_desc near *)desc);
+
+ /* The field len is now set, we can generate the bit codes */
+ gen_codes ((ct_data near *)tree, max_code);
+}
+
+/* ===========================================================================
+ * Scan a literal or distance tree to determine the frequencies of the codes
+ * in the bit length tree. Updates opt_len to take into account the repeat
+ * counts. (The contribution of the bit length codes will be added later
+ * during the construction of bl_tree.)
+ */
+local void scan_tree (tree, max_code)
+ ct_data near *tree; /* the tree to be scanned */
+ int max_code; /* and its largest code of non zero frequency */
+{
+ int n; /* iterates over all tree elements */
+ int prevlen = -1; /* last emitted length */
+ int curlen; /* length of current code */
+ int nextlen = tree[0].Len; /* length of next code */
+ int count = 0; /* repeat count of the current code */
+ int max_count = 7; /* max repeat count */
+ int min_count = 4; /* min repeat count */
+
+ if (nextlen == 0) max_count = 138, min_count = 3;
+ tree[max_code+1].Len = (ush)0xffff; /* guard */
+
+ for (n = 0; n <= max_code; n++) {
+ curlen = nextlen; nextlen = tree[n+1].Len;
+ if (++count < max_count && curlen == nextlen) {
+ continue;
+ } else if (count < min_count) {
+ bl_tree[curlen].Freq += count;
+ } else if (curlen != 0) {
+ if (curlen != prevlen) bl_tree[curlen].Freq++;
+ bl_tree[REP_3_6].Freq++;
+ } else if (count <= 10) {
+ bl_tree[REPZ_3_10].Freq++;
+ } else {
+ bl_tree[REPZ_11_138].Freq++;
+ }
+ count = 0; prevlen = curlen;
+ if (nextlen == 0) {
+ max_count = 138, min_count = 3;
+ } else if (curlen == nextlen) {
+ max_count = 6, min_count = 3;
+ } else {
+ max_count = 7, min_count = 4;
+ }
+ }
+}
+
+/* ===========================================================================
+ * Send a literal or distance tree in compressed form, using the codes in
+ * bl_tree.
+ */
+local void send_tree (tree, max_code)
+ ct_data near *tree; /* the tree to be scanned */
+ int max_code; /* and its largest code of non zero frequency */
+{
+ int n; /* iterates over all tree elements */
+ int prevlen = -1; /* last emitted length */
+ int curlen; /* length of current code */
+ int nextlen = tree[0].Len; /* length of next code */
+ int count = 0; /* repeat count of the current code */
+ int max_count = 7; /* max repeat count */
+ int min_count = 4; /* min repeat count */
+
+ /* tree[max_code+1].Len = -1; */ /* guard already set */
+ if (nextlen == 0) max_count = 138, min_count = 3;
+
+ for (n = 0; n <= max_code; n++) {
+ curlen = nextlen; nextlen = tree[n+1].Len;
+ if (++count < max_count && curlen == nextlen) {
+ continue;
+ } else if (count < min_count) {
+ do { send_code(curlen, bl_tree); } while (--count != 0);
+
+ } else if (curlen != 0) {
+ if (curlen != prevlen) {
+ send_code(curlen, bl_tree); count--;
+ }
+ Assert(count >= 3 && count <= 6, " 3_6?");
+ send_code(REP_3_6, bl_tree); send_bits(count-3, 2);
+
+ } else if (count <= 10) {
+ send_code(REPZ_3_10, bl_tree); send_bits(count-3, 3);
+
+ } else {
+ send_code(REPZ_11_138, bl_tree); send_bits(count-11, 7);
+ }
+ count = 0; prevlen = curlen;
+ if (nextlen == 0) {
+ max_count = 138, min_count = 3;
+ } else if (curlen == nextlen) {
+ max_count = 6, min_count = 3;
+ } else {
+ max_count = 7, min_count = 4;
+ }
+ }
+}
+
+/* ===========================================================================
+ * Construct the Huffman tree for the bit lengths and return the index in
+ * bl_order of the last bit length code to send.
+ */
+local int build_bl_tree()
+{
+ int max_blindex; /* index of last bit length code of non zero freq */
+
+ /* Determine the bit length frequencies for literal and distance trees */
+ scan_tree((ct_data near *)dyn_ltree, l_desc.max_code);
+ scan_tree((ct_data near *)dyn_dtree, d_desc.max_code);
+
+ /* Build the bit length tree: */
+ build_tree((tree_desc near *)(&bl_desc));
+ /* opt_len now includes the length of the tree representations, except
+ * the lengths of the bit lengths codes and the 5+5+4 bits for the counts.
+ */
+
+ /* Determine the number of bit length codes to send. The pkzip format
+ * requires that at least 4 bit length codes be sent. (appnote.txt says
+ * 3 but the actual value used is 4.)
+ */
+ for (max_blindex = BL_CODES-1; max_blindex >= 3; max_blindex--) {
+ if (bl_tree[bl_order[max_blindex]].Len != 0) break;
+ }
+ /* Update opt_len to include the bit length tree and counts */
+ opt_len += 3*(max_blindex+1) + 5+5+4;
+ Tracev((stderr, "\ndyn trees: dyn %ld, stat %ld", opt_len, static_len));
+
+ return max_blindex;
+}
+
+/* ===========================================================================
+ * Send the header for a block using dynamic Huffman trees: the counts, the
+ * lengths of the bit length codes, the literal tree and the distance tree.
+ * IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4.
+ */
+local void send_all_trees(lcodes, dcodes, blcodes)
+ int lcodes, dcodes, blcodes; /* number of codes for each tree */
+{
+ int rank; /* index in bl_order */
+
+ Assert (lcodes >= 257 && dcodes >= 1 && blcodes >= 4, "not enough codes");
+ Assert (lcodes <= L_CODES && dcodes <= D_CODES && blcodes <= BL_CODES,
+ "too many codes");
+ Tracev((stderr, "\nbl counts: "));
+ send_bits(lcodes-257, 5); /* not +255 as stated in appnote.txt */
+ send_bits(dcodes-1, 5);
+ send_bits(blcodes-4, 4); /* not -3 as stated in appnote.txt */
+ for (rank = 0; rank < blcodes; rank++) {
+ Tracev((stderr, "\nbl code %2d ", bl_order[rank]));
+ send_bits(bl_tree[bl_order[rank]].Len, 3);
+ }
+ Tracev((stderr, "\nbl tree: sent %ld", bits_sent));
+
+ send_tree((ct_data near *)dyn_ltree, lcodes-1); /* send the literal tree */
+ Tracev((stderr, "\nlit tree: sent %ld", bits_sent));
+
+ send_tree((ct_data near *)dyn_dtree, dcodes-1); /* send the distance tree */
+ Tracev((stderr, "\ndist tree: sent %ld", bits_sent));
+}
+
+/* ===========================================================================
+ * Determine the best encoding for the current block: dynamic trees, static
+ * trees or store, and output the encoded block to the zip file. This function
+ * returns the total compressed length for the file so far.
+ */
+ulg flush_block(buf, stored_len, eof)
+ char *buf; /* input block, or NULL if too old */
+ ulg stored_len; /* length of input block */
+ int eof; /* true if this is the last block for a file */
+{
+ ulg opt_lenb, static_lenb; /* opt_len and static_len in bytes */
+ int max_blindex; /* index of last bit length code of non zero freq */
+
+ flag_buf[last_flags] = flags; /* Save the flags for the last 8 items */
+
+ /* Check if the file is ascii or binary */
+ if (*file_type == (ush)UNKNOWN) set_file_type();
+
+ /* Construct the literal and distance trees */
+ build_tree((tree_desc near *)(&l_desc));
+ Tracev((stderr, "\nlit data: dyn %ld, stat %ld", opt_len, static_len));
+
+ build_tree((tree_desc near *)(&d_desc));
+ Tracev((stderr, "\ndist data: dyn %ld, stat %ld", opt_len, static_len));
+ /* At this point, opt_len and static_len are the total bit lengths of
+ * the compressed block data, excluding the tree representations.
+ */
+
+ /* Build the bit length tree for the above two trees, and get the index
+ * in bl_order of the last bit length code to send.
+ */
+ max_blindex = build_bl_tree();
+
+ /* Determine the best encoding. Compute first the block length in bytes */
+ opt_lenb = (opt_len+3+7)>>3;
+ static_lenb = (static_len+3+7)>>3;
+ input_len += stored_len; /* for debugging only */
+
+ Trace((stderr, "\nopt %lu(%lu) stat %lu(%lu) stored %lu lit %u dist %u ",
+ opt_lenb, opt_len, static_lenb, static_len, stored_len,
+ last_lit, last_dist));
+
+ if (static_lenb <= opt_lenb) opt_lenb = static_lenb;
+
+ /* If compression failed and this is the first and last block,
+ * and if the zip file can be seeked (to rewrite the local header),
+ * the whole file is transformed into a stored file:
+ */
+#ifdef FORCE_METHOD
+ if (level == 1 && eof && compressed_len == 0L) { /* force stored file */
+#else
+ if (stored_len <= opt_lenb && eof && compressed_len == 0L && seekable()) {
+#endif
+ /* Since LIT_BUFSIZE <= 2*WSIZE, the input data must be there: */
+ if (buf == (char*)0) error ("block vanished");
+
+ copy_block(buf, (unsigned)stored_len, 0); /* without header */
+ compressed_len = stored_len << 3;
+ *file_method = STORED;
+
+#ifdef FORCE_METHOD
+ } else if (level == 2 && buf != (char*)0) { /* force stored block */
+#else
+ } else if (stored_len+4 <= opt_lenb && buf != (char*)0) {
+ /* 4: two words for the lengths */
+#endif
+ /* The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE.
+ * Otherwise we can't have processed more than WSIZE input bytes since
+ * the last block flush, because compression would have been
+ * successful. If LIT_BUFSIZE <= WSIZE, it is never too late to
+ * transform a block into a stored block.
+ */
+ send_bits((STORED_BLOCK<<1)+eof, 3); /* send block type */
+ compressed_len = (compressed_len + 3 + 7) & ~7L;
+ compressed_len += (stored_len + 4) << 3;
+
+ copy_block(buf, (unsigned)stored_len, 1); /* with header */
+
+#ifdef FORCE_METHOD
+ } else if (level == 3) { /* force static trees */
+#else
+ } else if (static_lenb == opt_lenb) {
+#endif
+ send_bits((STATIC_TREES<<1)+eof, 3);
+ compress_block((ct_data near *)static_ltree, (ct_data near *)static_dtree);
+ compressed_len += 3 + static_len;
+ } else {
+ send_bits((DYN_TREES<<1)+eof, 3);
+ send_all_trees(l_desc.max_code+1, d_desc.max_code+1, max_blindex+1);
+ compress_block((ct_data near *)dyn_ltree, (ct_data near *)dyn_dtree);
+ compressed_len += 3 + opt_len;
+ }
+ Assert (compressed_len == bits_sent, "bad compressed size");
+ init_block();
+
+ if (eof) {
+ Assert (input_len == isize, "bad input size");
+ bi_windup();
+ compressed_len += 7; /* align on byte boundary */
+ }
+ Tracev((stderr,"\ncomprlen %lu(%lu) ", compressed_len>>3,
+ compressed_len-7*eof));
+
+ return compressed_len >> 3;
+}
+
+/* ===========================================================================
+ * Save the match info and tally the frequency counts. Return true if
+ * the current block must be flushed.
+ */
+int ct_tally (dist, lc)
+ int dist; /* distance of matched string */
+ int lc; /* match length-MIN_MATCH or unmatched char (if dist==0) */
+{
+ l_buf[last_lit++] = (uch)lc;
+ if (dist == 0) {
+ /* lc is the unmatched char */
+ dyn_ltree[lc].Freq++;
+ } else {
+ /* Here, lc is the match length - MIN_MATCH */
+ dist--; /* dist = match distance - 1 */
+ Assert((ush)dist < (ush)MAX_DIST &&
+ (ush)lc <= (ush)(MAX_MATCH-MIN_MATCH) &&
+ (ush)d_code(dist) < (ush)D_CODES, "ct_tally: bad match");
+
+ dyn_ltree[length_code[lc]+LITERALS+1].Freq++;
+ dyn_dtree[d_code(dist)].Freq++;
+
+ d_buf[last_dist++] = (ush)dist;
+ flags |= flag_bit;
+ }
+ flag_bit <<= 1;
+
+ /* Output the flags if they fill a byte: */
+ if ((last_lit & 7) == 0) {
+ flag_buf[last_flags++] = flags;
+ flags = 0, flag_bit = 1;
+ }
+ /* Try to guess if it is profitable to stop the current block here */
+ if (level > 2 && (last_lit & 0xfff) == 0) {
+ /* Compute an upper bound for the compressed length */
+ ulg out_length = (ulg)last_lit*8L;
+ ulg in_length = (ulg)strstart-block_start;
+ int dcode;
+ for (dcode = 0; dcode < D_CODES; dcode++) {
+ out_length += (ulg)dyn_dtree[dcode].Freq*(5L+extra_dbits[dcode]);
+ }
+ out_length >>= 3;
+ Trace((stderr,"\nlast_lit %u, last_dist %u, in %ld, out ~%ld(%ld%%) ",
+ last_lit, last_dist, in_length, out_length,
+ 100L - out_length*100L/in_length));
+ if (last_dist < last_lit/2 && out_length < in_length/2) return 1;
+ }
+ return (last_lit == LIT_BUFSIZE-1 || last_dist == DIST_BUFSIZE);
+ /* We avoid equality with LIT_BUFSIZE because of wraparound at 64K
+ * on 16 bit machines and because stored blocks are restricted to
+ * 64K-1 bytes.
+ */
+}
+
+/* ===========================================================================
+ * Send the block data compressed using the given Huffman trees
+ */
+local void compress_block(ltree, dtree)
+ ct_data near *ltree; /* literal tree */
+ ct_data near *dtree; /* distance tree */
+{
+ unsigned dist; /* distance of matched string */
+ int lc; /* match length or unmatched char (if dist == 0) */
+ unsigned lx = 0; /* running index in l_buf */
+ unsigned dx = 0; /* running index in d_buf */
+ unsigned fx = 0; /* running index in flag_buf */
+ uch flag = 0; /* current flags */
+ unsigned code; /* the code to send */
+ int extra; /* number of extra bits to send */
+
+ if (last_lit != 0) do {
+ if ((lx & 7) == 0) flag = flag_buf[fx++];
+ lc = l_buf[lx++];
+ if ((flag & 1) == 0) {
+ send_code(lc, ltree); /* send a literal byte */
+ Tracecv(isgraph(lc), (stderr," '%c' ", lc));
+ } else {
+ /* Here, lc is the match length - MIN_MATCH */
+ code = length_code[lc];
+ send_code(code+LITERALS+1, ltree); /* send the length code */
+ extra = extra_lbits[code];
+ if (extra != 0) {
+ lc -= base_length[code];
+ send_bits(lc, extra); /* send the extra length bits */
+ }
+ dist = d_buf[dx++];
+ /* Here, dist is the match distance - 1 */
+ code = d_code(dist);
+ Assert (code < D_CODES, "bad d_code");
+
+ send_code(code, dtree); /* send the distance code */
+ extra = extra_dbits[code];
+ if (extra != 0) {
+ dist -= base_dist[code];
+ send_bits(dist, extra); /* send the extra distance bits */
+ }
+ } /* literal or match pair ? */
+ flag >>= 1;
+ } while (lx < last_lit);
+
+ send_code(END_BLOCK, ltree);
+}
+
+/* ===========================================================================
+ * Set the file type to ASCII or BINARY, using a crude approximation:
+ * binary if more than 20% of the bytes are <= 6 or >= 128, ascii otherwise.
+ * IN assertion: the fields freq of dyn_ltree are set and the total of all
+ * frequencies does not exceed 64K (to fit in an int on 16 bit machines).
+ */
+local void set_file_type()
+{
+ int n = 0;
+ unsigned ascii_freq = 0;
+ unsigned bin_freq = 0;
+ while (n < 7) bin_freq += dyn_ltree[n++].Freq;
+ while (n < 128) ascii_freq += dyn_ltree[n++].Freq;
+ while (n < LITERALS) bin_freq += dyn_ltree[n++].Freq;
+ *file_type = bin_freq > (ascii_freq >> 2) ? BINARY : ASCII;
+ if (*file_type == BINARY && translate_eol) {
+ warn("-l used on binary file", "");
+ }
+}
diff --git a/gnu/usr.bin/gzip/unlzh.c b/gnu/usr.bin/gzip/unlzh.c
new file mode 100644
index 0000000..e318e5e
--- /dev/null
+++ b/gnu/usr.bin/gzip/unlzh.c
@@ -0,0 +1,401 @@
+/* unlzh.c -- decompress files in SCO compress -H (LZH) format.
+ * The code in this file is directly derived from the public domain 'ar002'
+ * written by Haruhiko Okumura.
+ */
+
+#ifdef RCSID
+static char rcsid[] = "$Id: unlzh.c,v 1.2 1993/06/24 10:59:01 jloup Exp $";
+#endif
+
+#include <stdio.h>
+
+#include "tailor.h"
+#include "gzip.h"
+#include "lzw.h" /* just for consistency checking */
+
+/* decode.c */
+
+local unsigned decode OF((unsigned count, uch buffer[]));
+local void decode_start OF((void));
+
+/* huf.c */
+local void huf_decode_start OF((void));
+local unsigned decode_c OF((void));
+local unsigned decode_p OF((void));
+local void read_pt_len OF((int nn, int nbit, int i_special));
+local void read_c_len OF((void));
+
+/* io.c */
+local void fillbuf OF((int n));
+local unsigned getbits OF((int n));
+local void init_getbits OF((void));
+
+/* maketbl.c */
+
+local void make_table OF((int nchar, uch bitlen[],
+ int tablebits, ush table[]));
+
+
+#define DICBIT 13 /* 12(-lh4-) or 13(-lh5-) */
+#define DICSIZ ((unsigned) 1 << DICBIT)
+
+#ifndef CHAR_BIT
+# define CHAR_BIT 8
+#endif
+
+#ifndef UCHAR_MAX
+# define UCHAR_MAX 255
+#endif
+
+#define BITBUFSIZ (CHAR_BIT * 2 * sizeof(char))
+/* Do not use CHAR_BIT * sizeof(bitbuf), does not work on machines
+ * for which short is not on 16 bits (Cray).
+ */
+
+/* encode.c and decode.c */
+
+#define MAXMATCH 256 /* formerly F (not more than UCHAR_MAX + 1) */
+#define THRESHOLD 3 /* choose optimal value */
+
+/* huf.c */
+
+#define NC (UCHAR_MAX + MAXMATCH + 2 - THRESHOLD)
+ /* alphabet = {0, 1, 2, ..., NC - 1} */
+#define CBIT 9 /* $\lfloor \log_2 NC \rfloor + 1$ */
+#define CODE_BIT 16 /* codeword length */
+
+#define NP (DICBIT + 1)
+#define NT (CODE_BIT + 3)
+#define PBIT 4 /* smallest integer such that (1U << PBIT) > NP */
+#define TBIT 5 /* smallest integer such that (1U << TBIT) > NT */
+#if NT > NP
+# define NPT NT
+#else
+# define NPT NP
+#endif
+
+/* local ush left[2 * NC - 1]; */
+/* local ush right[2 * NC - 1]; */
+#define left prev
+#define right head
+#if NC > (1<<(BITS-2))
+ error cannot overlay left+right and prev
+#endif
+
+/* local uch c_len[NC]; */
+#define c_len outbuf
+#if NC > OUTBUFSIZ
+ error cannot overlay c_len and outbuf
+#endif
+
+local uch pt_len[NPT];
+local unsigned blocksize;
+local ush pt_table[256];
+
+/* local ush c_table[4096]; */
+#define c_table d_buf
+#if (DIST_BUFSIZE-1) < 4095
+ error cannot overlay c_table and d_buf
+#endif
+
+/***********************************************************
+ io.c -- input/output
+***********************************************************/
+
+local ush bitbuf;
+local unsigned subbitbuf;
+local int bitcount;
+
+local void fillbuf(n) /* Shift bitbuf n bits left, read n bits */
+ int n;
+{
+ bitbuf <<= n;
+ while (n > bitcount) {
+ bitbuf |= subbitbuf << (n -= bitcount);
+ subbitbuf = (unsigned)try_byte();
+ if ((int)subbitbuf == EOF) subbitbuf = 0;
+ bitcount = CHAR_BIT;
+ }
+ bitbuf |= subbitbuf >> (bitcount -= n);
+}
+
+local unsigned getbits(n)
+ int n;
+{
+ unsigned x;
+
+ x = bitbuf >> (BITBUFSIZ - n); fillbuf(n);
+ return x;
+}
+
+local void init_getbits()
+{
+ bitbuf = 0; subbitbuf = 0; bitcount = 0;
+ fillbuf(BITBUFSIZ);
+}
+
+/***********************************************************
+ maketbl.c -- make table for decoding
+***********************************************************/
+
+local void make_table(nchar, bitlen, tablebits, table)
+ int nchar;
+ uch bitlen[];
+ int tablebits;
+ ush table[];
+{
+ ush count[17], weight[17], start[18], *p;
+ unsigned i, k, len, ch, jutbits, avail, nextcode, mask;
+
+ for (i = 1; i <= 16; i++) count[i] = 0;
+ for (i = 0; i < (unsigned)nchar; i++) count[bitlen[i]]++;
+
+ start[1] = 0;
+ for (i = 1; i <= 16; i++)
+ start[i + 1] = start[i] + (count[i] << (16 - i));
+ if ((start[17] & 0xffff) != 0)
+ error("Bad table\n");
+
+ jutbits = 16 - tablebits;
+ for (i = 1; i <= (unsigned)tablebits; i++) {
+ start[i] >>= jutbits;
+ weight[i] = (unsigned) 1 << (tablebits - i);
+ }
+ while (i <= 16) {
+ weight[i] = (unsigned) 1 << (16 - i);
+ i++;
+ }
+
+ i = start[tablebits + 1] >> jutbits;
+ if (i != 0) {
+ k = 1 << tablebits;
+ while (i != k) table[i++] = 0;
+ }
+
+ avail = nchar;
+ mask = (unsigned) 1 << (15 - tablebits);
+ for (ch = 0; ch < (unsigned)nchar; ch++) {
+ if ((len = bitlen[ch]) == 0) continue;
+ nextcode = start[len] + weight[len];
+ if (len <= (unsigned)tablebits) {
+ for (i = start[len]; i < nextcode; i++) table[i] = ch;
+ } else {
+ k = start[len];
+ p = &table[k >> jutbits];
+ i = len - tablebits;
+ while (i != 0) {
+ if (*p == 0) {
+ right[avail] = left[avail] = 0;
+ *p = avail++;
+ }
+ if (k & mask) p = &right[*p];
+ else p = &left[*p];
+ k <<= 1; i--;
+ }
+ *p = ch;
+ }
+ start[len] = nextcode;
+ }
+}
+
+/***********************************************************
+ huf.c -- static Huffman
+***********************************************************/
+
+local void read_pt_len(nn, nbit, i_special)
+ int nn;
+ int nbit;
+ int i_special;
+{
+ int i, c, n;
+ unsigned mask;
+
+ n = getbits(nbit);
+ if (n == 0) {
+ c = getbits(nbit);
+ for (i = 0; i < nn; i++) pt_len[i] = 0;
+ for (i = 0; i < 256; i++) pt_table[i] = c;
+ } else {
+ i = 0;
+ while (i < n) {
+ c = bitbuf >> (BITBUFSIZ - 3);
+ if (c == 7) {
+ mask = (unsigned) 1 << (BITBUFSIZ - 1 - 3);
+ while (mask & bitbuf) { mask >>= 1; c++; }
+ }
+ fillbuf((c < 7) ? 3 : c - 3);
+ pt_len[i++] = c;
+ if (i == i_special) {
+ c = getbits(2);
+ while (--c >= 0) pt_len[i++] = 0;
+ }
+ }
+ while (i < nn) pt_len[i++] = 0;
+ make_table(nn, pt_len, 8, pt_table);
+ }
+}
+
+local void read_c_len()
+{
+ int i, c, n;
+ unsigned mask;
+
+ n = getbits(CBIT);
+ if (n == 0) {
+ c = getbits(CBIT);
+ for (i = 0; i < NC; i++) c_len[i] = 0;
+ for (i = 0; i < 4096; i++) c_table[i] = c;
+ } else {
+ i = 0;
+ while (i < n) {
+ c = pt_table[bitbuf >> (BITBUFSIZ - 8)];
+ if (c >= NT) {
+ mask = (unsigned) 1 << (BITBUFSIZ - 1 - 8);
+ do {
+ if (bitbuf & mask) c = right[c];
+ else c = left [c];
+ mask >>= 1;
+ } while (c >= NT);
+ }
+ fillbuf((int) pt_len[c]);
+ if (c <= 2) {
+ if (c == 0) c = 1;
+ else if (c == 1) c = getbits(4) + 3;
+ else c = getbits(CBIT) + 20;
+ while (--c >= 0) c_len[i++] = 0;
+ } else c_len[i++] = c - 2;
+ }
+ while (i < NC) c_len[i++] = 0;
+ make_table(NC, c_len, 12, c_table);
+ }
+}
+
+local unsigned decode_c()
+{
+ unsigned j, mask;
+
+ if (blocksize == 0) {
+ blocksize = getbits(16);
+ if (blocksize == 0) {
+ return NC; /* end of file */
+ }
+ read_pt_len(NT, TBIT, 3);
+ read_c_len();
+ read_pt_len(NP, PBIT, -1);
+ }
+ blocksize--;
+ j = c_table[bitbuf >> (BITBUFSIZ - 12)];
+ if (j >= NC) {
+ mask = (unsigned) 1 << (BITBUFSIZ - 1 - 12);
+ do {
+ if (bitbuf & mask) j = right[j];
+ else j = left [j];
+ mask >>= 1;
+ } while (j >= NC);
+ }
+ fillbuf((int) c_len[j]);
+ return j;
+}
+
+local unsigned decode_p()
+{
+ unsigned j, mask;
+
+ j = pt_table[bitbuf >> (BITBUFSIZ - 8)];
+ if (j >= NP) {
+ mask = (unsigned) 1 << (BITBUFSIZ - 1 - 8);
+ do {
+ if (bitbuf & mask) j = right[j];
+ else j = left [j];
+ mask >>= 1;
+ } while (j >= NP);
+ }
+ fillbuf((int) pt_len[j]);
+ if (j != 0) j = ((unsigned) 1 << (j - 1)) + getbits((int) (j - 1));
+ return j;
+}
+
+local void huf_decode_start()
+{
+ init_getbits(); blocksize = 0;
+}
+
+/***********************************************************
+ decode.c
+***********************************************************/
+
+local int j; /* remaining bytes to copy */
+local int done; /* set at end of input */
+
+local void decode_start()
+{
+ huf_decode_start();
+ j = 0;
+ done = 0;
+}
+
+/* Decode the input and return the number of decoded bytes put in buffer
+ */
+local unsigned decode(count, buffer)
+ unsigned count;
+ uch buffer[];
+ /* The calling function must keep the number of
+ bytes to be processed. This function decodes
+ either 'count' bytes or 'DICSIZ' bytes, whichever
+ is smaller, into the array 'buffer[]' of size
+ 'DICSIZ' or more.
+ Call decode_start() once for each new file
+ before calling this function.
+ */
+{
+ local unsigned i;
+ unsigned r, c;
+
+ r = 0;
+ while (--j >= 0) {
+ buffer[r] = buffer[i];
+ i = (i + 1) & (DICSIZ - 1);
+ if (++r == count) return r;
+ }
+ for ( ; ; ) {
+ c = decode_c();
+ if (c == NC) {
+ done = 1;
+ return r;
+ }
+ if (c <= UCHAR_MAX) {
+ buffer[r] = c;
+ if (++r == count) return r;
+ } else {
+ j = c - (UCHAR_MAX + 1 - THRESHOLD);
+ i = (r - decode_p() - 1) & (DICSIZ - 1);
+ while (--j >= 0) {
+ buffer[r] = buffer[i];
+ i = (i + 1) & (DICSIZ - 1);
+ if (++r == count) return r;
+ }
+ }
+ }
+}
+
+
+/* ===========================================================================
+ * Unlzh in to out. Return OK or ERROR.
+ */
+int unlzh(in, out)
+ int in;
+ int out;
+{
+ unsigned n;
+ ifd = in;
+ ofd = out;
+
+ decode_start();
+ while (!done) {
+ n = decode((unsigned) DICSIZ, window);
+ if (!test && n > 0) {
+ write_buf(out, (char*)window, n);
+ }
+ }
+ return OK;
+}
diff --git a/gnu/usr.bin/gzip/unlzw.c b/gnu/usr.bin/gzip/unlzw.c
new file mode 100644
index 0000000..fe2110f
--- /dev/null
+++ b/gnu/usr.bin/gzip/unlzw.c
@@ -0,0 +1,377 @@
+/* unlzw.c -- decompress files in LZW format.
+ * The code in this file is directly derived from the public domain 'compress'
+ * written by Spencer Thomas, Joe Orost, James Woods, Jim McKie, Steve Davies,
+ * Ken Turkowski, Dave Mack and Peter Jannesen.
+ *
+ * This is a temporary version which will be rewritten in some future version
+ * to accommodate in-memory decompression.
+ */
+
+#ifdef RCSID
+static char rcsid[] = "$Id: unlzw.c,v 1.3 1993/10/14 00:33:17 nate Exp $";
+#endif
+
+#include <sys/types.h>
+
+#include "tailor.h"
+
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+#ifndef NO_FCNTL_H
+# include <fcntl.h>
+#endif
+
+#include "gzip.h"
+#include "lzw.h"
+
+typedef unsigned char char_type;
+typedef long code_int;
+typedef unsigned long count_int;
+typedef unsigned short count_short;
+typedef unsigned long cmp_code_int;
+
+#define MAXCODE(n) (1L << (n))
+
+#ifndef REGISTERS
+# define REGISTERS 2
+#endif
+#define REG1
+#define REG2
+#define REG3
+#define REG4
+#define REG5
+#define REG6
+#define REG7
+#define REG8
+#define REG9
+#define REG10
+#define REG11
+#define REG12
+#define REG13
+#define REG14
+#define REG15
+#define REG16
+#if REGISTERS >= 1
+# undef REG1
+# define REG1 register
+#endif
+#if REGISTERS >= 2
+# undef REG2
+# define REG2 register
+#endif
+#if REGISTERS >= 3
+# undef REG3
+# define REG3 register
+#endif
+#if REGISTERS >= 4
+# undef REG4
+# define REG4 register
+#endif
+#if REGISTERS >= 5
+# undef REG5
+# define REG5 register
+#endif
+#if REGISTERS >= 6
+# undef REG6
+# define REG6 register
+#endif
+#if REGISTERS >= 7
+# undef REG7
+# define REG7 register
+#endif
+#if REGISTERS >= 8
+# undef REG8
+# define REG8 register
+#endif
+#if REGISTERS >= 9
+# undef REG9
+# define REG9 register
+#endif
+#if REGISTERS >= 10
+# undef REG10
+# define REG10 register
+#endif
+#if REGISTERS >= 11
+# undef REG11
+# define REG11 register
+#endif
+#if REGISTERS >= 12
+# undef REG12
+# define REG12 register
+#endif
+#if REGISTERS >= 13
+# undef REG13
+# define REG13 register
+#endif
+#if REGISTERS >= 14
+# undef REG14
+# define REG14 register
+#endif
+#if REGISTERS >= 15
+# undef REG15
+# define REG15 register
+#endif
+#if REGISTERS >= 16
+# undef REG16
+# define REG16 register
+#endif
+
+#ifndef BYTEORDER
+# define BYTEORDER 0000
+#endif
+
+#ifndef NOALLIGN
+# define NOALLIGN 0
+#endif
+
+
+union bytes {
+ long word;
+ struct {
+#if BYTEORDER == 4321
+ char_type b1;
+ char_type b2;
+ char_type b3;
+ char_type b4;
+#else
+#if BYTEORDER == 1234
+ char_type b4;
+ char_type b3;
+ char_type b2;
+ char_type b1;
+#else
+# undef BYTEORDER
+ int dummy;
+#endif
+#endif
+ } bytes;
+};
+
+#if BYTEORDER == 4321 && NOALLIGN == 1
+# define input(b,o,c,n,m){ \
+ (c) = (*(long *)(&(b)[(o)>>3])>>((o)&0x7))&(m); \
+ (o) += (n); \
+ }
+#else
+# define input(b,o,c,n,m){ \
+ REG1 char_type *p = &(b)[(o)>>3]; \
+ (c) = ((((long)(p[0]))|((long)(p[1])<<8)| \
+ ((long)(p[2])<<16))>>((o)&0x7))&(m); \
+ (o) += (n); \
+ }
+#endif
+
+#ifndef MAXSEG_64K
+ /* DECLARE(ush, tab_prefix, (1<<BITS)); -- prefix code */
+# define tab_prefixof(i) tab_prefix[i]
+# define clear_tab_prefixof() memzero(tab_prefix, 256);
+#else
+ /* DECLARE(ush, tab_prefix0, (1<<(BITS-1)); -- prefix for even codes */
+ /* DECLARE(ush, tab_prefix1, (1<<(BITS-1)); -- prefix for odd codes */
+ ush *tab_prefix[2];
+# define tab_prefixof(i) tab_prefix[(i)&1][(i)>>1]
+# define clear_tab_prefixof() \
+ memzero(tab_prefix0, 128), \
+ memzero(tab_prefix1, 128);
+#endif
+#define de_stack ((char_type *)(&d_buf[DIST_BUFSIZE-1]))
+#define tab_suffixof(i) tab_suffix[i]
+
+int block_mode = BLOCK_MODE; /* block compress mode -C compatible with 2.0 */
+
+/* ============================================================================
+ * Decompress in to out. This routine adapts to the codes in the
+ * file building the "string" table on-the-fly; requiring no table to
+ * be stored in the compressed file.
+ * IN assertions: the buffer inbuf contains already the beginning of
+ * the compressed data, from offsets iptr to insize-1 included.
+ * The magic header has already been checked and skipped.
+ * bytes_in and bytes_out have been initialized.
+ */
+int unlzw(in, out)
+ int in, out; /* input and output file descriptors */
+{
+ REG2 char_type *stackp;
+ REG3 code_int code;
+ REG4 int finchar;
+ REG5 code_int oldcode;
+ REG6 code_int incode;
+ REG7 long inbits;
+ REG8 long posbits;
+ REG9 int outpos;
+/* REG10 int insize; (global) */
+ REG11 unsigned bitmask;
+ REG12 code_int free_ent;
+ REG13 code_int maxcode;
+ REG14 code_int maxmaxcode;
+ REG15 int n_bits;
+ REG16 int rsize;
+
+#ifdef MAXSEG_64K
+ tab_prefix[0] = tab_prefix0;
+ tab_prefix[1] = tab_prefix1;
+#endif
+ maxbits = get_byte();
+ block_mode = maxbits & BLOCK_MODE;
+ if ((maxbits & LZW_RESERVED) != 0) {
+ WARN((stderr, "\n%s: %s: warning, unknown flags 0x%x\n",
+ progname, ifname, maxbits & LZW_RESERVED));
+ }
+ maxbits &= BIT_MASK;
+ maxmaxcode = MAXCODE(maxbits);
+
+ if (maxbits > BITS) {
+ fprintf(stderr,
+ "\n%s: %s: compressed with %d bits, can only handle %d bits\n",
+ progname, ifname, maxbits, BITS);
+ exit_code = ERROR;
+ return ERROR;
+ }
+ rsize = insize;
+ maxcode = MAXCODE(n_bits = INIT_BITS)-1;
+ bitmask = (1<<n_bits)-1;
+ oldcode = -1;
+ finchar = 0;
+ outpos = 0;
+ posbits = inptr<<3;
+
+ free_ent = ((block_mode) ? FIRST : 256);
+
+ clear_tab_prefixof(); /* Initialize the first 256 entries in the table. */
+
+ for (code = 255 ; code >= 0 ; --code) {
+ tab_suffixof(code) = (char_type)code;
+ }
+ do {
+ REG1 int i;
+ int e;
+ int o;
+
+ resetbuf:
+ e = insize-(o = (posbits>>3));
+
+ for (i = 0 ; i < e ; ++i) {
+ inbuf[i] = inbuf[i+o];
+ }
+ insize = e;
+ posbits = 0;
+
+ if (insize < INBUF_EXTRA) {
+ if ((rsize = read(in, (char*)inbuf+insize, INBUFSIZ)) == EOF) {
+ read_error();
+ }
+ insize += rsize;
+ bytes_in += (ulg)rsize;
+ }
+ inbits = ((rsize != 0) ? ((long)insize - insize%n_bits)<<3 :
+ ((long)insize<<3)-(n_bits-1));
+
+ while (inbits > posbits) {
+ if (free_ent > maxcode) {
+ posbits = ((posbits-1) +
+ ((n_bits<<3)-(posbits-1+(n_bits<<3))%(n_bits<<3)));
+ ++n_bits;
+ if (n_bits == maxbits) {
+ maxcode = maxmaxcode;
+ } else {
+ maxcode = MAXCODE(n_bits)-1;
+ }
+ bitmask = (1<<n_bits)-1;
+ goto resetbuf;
+ }
+ input(inbuf,posbits,code,n_bits,bitmask);
+ Tracev((stderr, "%d ", code));
+
+ if (oldcode == -1) {
+ if (code >= 256) error("corrupt input.");
+ outbuf[outpos++] = (char_type)(finchar = (int)(oldcode=code));
+ continue;
+ }
+ if (code == CLEAR && block_mode) {
+ clear_tab_prefixof();
+ free_ent = FIRST - 1;
+ posbits = ((posbits-1) +
+ ((n_bits<<3)-(posbits-1+(n_bits<<3))%(n_bits<<3)));
+ maxcode = MAXCODE(n_bits = INIT_BITS)-1;
+ bitmask = (1<<n_bits)-1;
+ goto resetbuf;
+ }
+ incode = code;
+ stackp = de_stack;
+
+ if (code >= free_ent) { /* Special case for KwKwK string. */
+ if (code > free_ent) {
+#ifdef DEBUG
+ char_type *p;
+
+ posbits -= n_bits;
+ p = &inbuf[posbits>>3];
+ fprintf(stderr,
+ "code:%ld free_ent:%ld n_bits:%d insize:%u\n",
+ code, free_ent, n_bits, insize);
+ fprintf(stderr,
+ "posbits:%ld inbuf:%02X %02X %02X %02X %02X\n",
+ posbits, p[-1],p[0],p[1],p[2],p[3]);
+#endif
+ if (!test && outpos > 0) {
+ write_buf(out, (char*)outbuf, outpos);
+ bytes_out += (ulg)outpos;
+ }
+ error(to_stdout ? "corrupt input." :
+ "corrupt input. Use zcat to recover some data.");
+ }
+ *--stackp = (char_type)finchar;
+ code = oldcode;
+ }
+
+ while ((cmp_code_int)code >= (cmp_code_int)256) {
+ /* Generate output characters in reverse order */
+ *--stackp = tab_suffixof(code);
+ code = tab_prefixof(code);
+ }
+ *--stackp = (char_type)(finchar = tab_suffixof(code));
+
+ /* And put them out in forward order */
+ {
+ REG1 int i;
+
+ if (outpos+(i = (de_stack-stackp)) >= OUTBUFSIZ) {
+ do {
+ if (i > OUTBUFSIZ-outpos) i = OUTBUFSIZ-outpos;
+
+ if (i > 0) {
+ memcpy(outbuf+outpos, stackp, i);
+ outpos += i;
+ }
+ if (outpos >= OUTBUFSIZ) {
+ if (!test) {
+ write_buf(out, (char*)outbuf, outpos);
+ bytes_out += (ulg)outpos;
+ }
+ outpos = 0;
+ }
+ stackp+= i;
+ } while ((i = (de_stack-stackp)) > 0);
+ } else {
+ memcpy(outbuf+outpos, stackp, i);
+ outpos += i;
+ }
+ }
+
+ if ((code = free_ent) < maxmaxcode) { /* Generate the new entry. */
+
+ tab_prefixof(code) = (unsigned short)oldcode;
+ tab_suffixof(code) = (char_type)finchar;
+ free_ent = code+1;
+ }
+ oldcode = incode; /* Remember previous code. */
+ }
+ } while (rsize != 0);
+
+ if (!test && outpos > 0) {
+ write_buf(out, (char*)outbuf, outpos);
+ bytes_out += (ulg)outpos;
+ }
+ return OK;
+}
diff --git a/gnu/usr.bin/gzip/unpack.c b/gnu/usr.bin/gzip/unpack.c
new file mode 100644
index 0000000..a00fdae
--- /dev/null
+++ b/gnu/usr.bin/gzip/unpack.c
@@ -0,0 +1,239 @@
+/* unpack.c -- decompress files in pack format.
+ * Copyright (C) 1992-1993 Jean-loup Gailly
+ * This is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License, see the file COPYING.
+ */
+
+#ifdef RCSID
+static char rcsid[] = "$Id: unpack.c,v 1.4 1993/06/11 19:25:36 jloup Exp $";
+#endif
+
+#include "tailor.h"
+#include "gzip.h"
+#include "crypt.h"
+
+#define MIN(a,b) ((a) <= (b) ? (a) : (b))
+/* The arguments must not have side effects. */
+
+#define MAX_BITLEN 25
+/* Maximum length of Huffman codes. (Minor modifications to the code
+ * would be needed to support 32 bits codes, but pack never generates
+ * more than 24 bits anyway.)
+ */
+
+#define LITERALS 256
+/* Number of literals, excluding the End of Block (EOB) code */
+
+#define MAX_PEEK 12
+/* Maximum number of 'peek' bits used to optimize traversal of the
+ * Huffman tree.
+ */
+
+local ulg orig_len; /* original uncompressed length */
+local int max_len; /* maximum bit length of Huffman codes */
+
+local uch literal[LITERALS];
+/* The literal bytes present in the Huffman tree. The EOB code is not
+ * represented.
+ */
+
+local int lit_base[MAX_BITLEN+1];
+/* All literals of a given bit length are contiguous in literal[] and
+ * have contiguous codes. literal[code+lit_base[len]] is the literal
+ * for a code of len bits.
+ */
+
+local int leaves [MAX_BITLEN+1]; /* Number of leaves for each bit length */
+local int parents[MAX_BITLEN+1]; /* Number of parents for each bit length */
+
+local int peek_bits; /* Number of peek bits currently used */
+
+/* local uch prefix_len[1 << MAX_PEEK]; */
+#define prefix_len outbuf
+/* For each bit pattern b of peek_bits bits, prefix_len[b] is the length
+ * of the Huffman code starting with a prefix of b (upper bits), or 0
+ * if all codes of prefix b have more than peek_bits bits. It is not
+ * necessary to have a huge table (large MAX_PEEK) because most of the
+ * codes encountered in the input stream are short codes (by construction).
+ * So for most codes a single lookup will be necessary.
+ */
+#if (1<<MAX_PEEK) > OUTBUFSIZ
+ error cannot overlay prefix_len and outbuf
+#endif
+
+local ulg bitbuf;
+/* Bits are added on the low part of bitbuf and read from the high part. */
+
+local int valid; /* number of valid bits in bitbuf */
+/* all bits above the last valid bit are always zero */
+
+/* Set code to the next 'bits' input bits without skipping them. code
+ * must be the name of a simple variable and bits must not have side effects.
+ * IN assertions: bits <= 25 (so that we still have room for an extra byte
+ * when valid is only 24), and mask = (1<<bits)-1.
+ */
+#define look_bits(code,bits,mask) \
+{ \
+ while (valid < (bits)) bitbuf = (bitbuf<<8) | (ulg)get_byte(), valid += 8; \
+ code = (bitbuf >> (valid-(bits))) & (mask); \
+}
+
+/* Skip the given number of bits (after having peeked at them): */
+#define skip_bits(bits) (valid -= (bits))
+
+#define clear_bitbuf() (valid = 0, bitbuf = 0)
+
+/* Local functions */
+
+local void read_tree OF((void));
+local void build_tree OF((void));
+
+/* ===========================================================================
+ * Read the Huffman tree.
+ */
+local void read_tree()
+{
+ int len; /* bit length */
+ int base; /* base offset for a sequence of leaves */
+ int n;
+
+ /* Read the original input size, MSB first */
+ orig_len = 0;
+ for (n = 1; n <= 4; n++) orig_len = (orig_len << 8) | (ulg)get_byte();
+
+ max_len = (int)get_byte(); /* maximum bit length of Huffman codes */
+ if (max_len > MAX_BITLEN) {
+ error("invalid compressed data -- Huffman code > 32 bits");
+ }
+
+ /* Get the number of leaves at each bit length */
+ n = 0;
+ for (len = 1; len <= max_len; len++) {
+ leaves[len] = (int)get_byte();
+ n += leaves[len];
+ }
+ if (n > LITERALS) {
+ error("too many leaves in Huffman tree");
+ }
+ Trace((stderr, "orig_len %ld, max_len %d, leaves %d\n",
+ orig_len, max_len, n));
+ /* There are at least 2 and at most 256 leaves of length max_len.
+ * (Pack arbitrarily rejects empty files and files consisting of
+ * a single byte even repeated.) To fit the last leaf count in a
+ * byte, it is offset by 2. However, the last literal is the EOB
+ * code, and is not transmitted explicitly in the tree, so we must
+ * adjust here by one only.
+ */
+ leaves[max_len]++;
+
+ /* Now read the leaves themselves */
+ base = 0;
+ for (len = 1; len <= max_len; len++) {
+ /* Remember where the literals of this length start in literal[] : */
+ lit_base[len] = base;
+ /* And read the literals: */
+ for (n = leaves[len]; n > 0; n--) {
+ literal[base++] = (uch)get_byte();
+ }
+ }
+ leaves[max_len]++; /* Now include the EOB code in the Huffman tree */
+}
+
+/* ===========================================================================
+ * Build the Huffman tree and the prefix table.
+ */
+local void build_tree()
+{
+ int nodes = 0; /* number of nodes (parents+leaves) at current bit length */
+ int len; /* current bit length */
+ uch *prefixp; /* pointer in prefix_len */
+
+ for (len = max_len; len >= 1; len--) {
+ /* The number of parent nodes at this level is half the total
+ * number of nodes at parent level:
+ */
+ nodes >>= 1;
+ parents[len] = nodes;
+ /* Update lit_base by the appropriate bias to skip the parent nodes
+ * (which are not represented in the literal array):
+ */
+ lit_base[len] -= nodes;
+ /* Restore nodes to be parents+leaves: */
+ nodes += leaves[len];
+ }
+ /* Construct the prefix table, from shortest leaves to longest ones.
+ * The shortest code is all ones, so we start at the end of the table.
+ */
+ peek_bits = MIN(max_len, MAX_PEEK);
+ prefixp = &prefix_len[1<<peek_bits];
+ for (len = 1; len <= peek_bits; len++) {
+ int prefixes = leaves[len] << (peek_bits-len); /* may be 0 */
+ while (prefixes--) *--prefixp = (uch)len;
+ }
+ /* The length of all other codes is unknown: */
+ while (prefixp > prefix_len) *--prefixp = 0;
+}
+
+/* ===========================================================================
+ * Unpack in to out. This routine does not support the old pack format
+ * with magic header \037\037.
+ *
+ * IN assertions: the buffer inbuf contains already the beginning of
+ * the compressed data, from offsets inptr to insize-1 included.
+ * The magic header has already been checked. The output buffer is cleared.
+ */
+int unpack(in, out)
+ int in, out; /* input and output file descriptors */
+{
+ int len; /* Bit length of current code */
+ unsigned eob; /* End Of Block code */
+ register unsigned peek; /* lookahead bits */
+ unsigned peek_mask; /* Mask for peek_bits bits */
+
+ ifd = in;
+ ofd = out;
+
+ read_tree(); /* Read the Huffman tree */
+ build_tree(); /* Build the prefix table */
+ clear_bitbuf(); /* Initialize bit input */
+ peek_mask = (1<<peek_bits)-1;
+
+ /* The eob code is the largest code among all leaves of maximal length: */
+ eob = leaves[max_len]-1;
+ Trace((stderr, "eob %d %x\n", max_len, eob));
+
+ /* Decode the input data: */
+ for (;;) {
+ /* Since eob is the longest code and not shorter than max_len,
+ * we can peek at max_len bits without having the risk of reading
+ * beyond the end of file.
+ */
+ look_bits(peek, peek_bits, peek_mask);
+ len = prefix_len[peek];
+ if (len > 0) {
+ peek >>= peek_bits - len; /* discard the extra bits */
+ } else {
+ /* Code of more than peek_bits bits, we must traverse the tree */
+ ulg mask = peek_mask;
+ len = peek_bits;
+ do {
+ len++, mask = (mask<<1)+1;
+ look_bits(peek, len, mask);
+ } while (peek < (unsigned)parents[len]);
+ /* loop as long as peek is a parent node */
+ }
+ /* At this point, peek is the next complete code, of len bits */
+ if (peek == eob && len == max_len) break; /* end of file? */
+ put_ubyte(literal[peek+lit_base[len]]);
+ Tracev((stderr,"%02d %04x %c\n", len, peek,
+ literal[peek+lit_base[len]]));
+ skip_bits(len);
+ } /* for (;;) */
+
+ flush_window();
+ Trace((stderr, "bytes_out %ld\n", bytes_out));
+ if (orig_len != (ulg)bytes_out) {
+ error("invalid compressed data--length error");
+ }
+ return OK;
+}
diff --git a/gnu/usr.bin/gzip/unzip.c b/gnu/usr.bin/gzip/unzip.c
new file mode 100644
index 0000000..7e287a1
--- /dev/null
+++ b/gnu/usr.bin/gzip/unzip.c
@@ -0,0 +1,199 @@
+/* unzip.c -- decompress files in gzip or pkzip format.
+ * Copyright (C) 1992-1993 Jean-loup Gailly
+ * This is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License, see the file COPYING.
+ *
+ * The code in this file is derived from the file funzip.c written
+ * and put in the public domain by Mark Adler.
+ */
+
+/*
+ This version can extract files in gzip or pkzip format.
+ For the latter, only the first entry is extracted, and it has to be
+ either deflated or stored.
+ */
+
+#ifdef RCSID
+static char rcsid[] = "$Id: unzip.c,v 0.13 1993/06/10 13:29:00 jloup Exp $";
+#endif
+
+#include "tailor.h"
+#include "gzip.h"
+#include "crypt.h"
+
+/* PKZIP header definitions */
+#define LOCSIG 0x04034b50L /* four-byte lead-in (lsb first) */
+#define LOCFLG 6 /* offset of bit flag */
+#define CRPFLG 1 /* bit for encrypted entry */
+#define EXTFLG 8 /* bit for extended local header */
+#define LOCHOW 8 /* offset of compression method */
+#define LOCTIM 10 /* file mod time (for decryption) */
+#define LOCCRC 14 /* offset of crc */
+#define LOCSIZ 18 /* offset of compressed size */
+#define LOCLEN 22 /* offset of uncompressed length */
+#define LOCFIL 26 /* offset of file name field length */
+#define LOCEXT 28 /* offset of extra field length */
+#define LOCHDR 30 /* size of local header, including sig */
+#define EXTHDR 16 /* size of extended local header, inc sig */
+
+
+/* Globals */
+
+int decrypt; /* flag to turn on decryption */
+char *key; /* not used--needed to link crypt.c */
+int pkzip = 0; /* set for a pkzip file */
+int ext_header = 0; /* set if extended local header */
+
+/* ===========================================================================
+ * Check zip file and advance inptr to the start of the compressed data.
+ * Get ofname from the local header if necessary.
+ */
+int check_zipfile(in)
+ int in; /* input file descriptors */
+{
+ uch *h = inbuf + inptr; /* first local header */
+
+ ifd = in;
+
+ /* Check validity of local header, and skip name and extra fields */
+ inptr += LOCHDR + SH(h + LOCFIL) + SH(h + LOCEXT);
+
+ if (inptr > insize || LG(h) != LOCSIG) {
+ fprintf(stderr, "\n%s: %s: not a valid zip file\n",
+ progname, ifname);
+ exit_code = ERROR;
+ return ERROR;
+ }
+ method = h[LOCHOW];
+ if (method != STORED && method != DEFLATED) {
+ fprintf(stderr,
+ "\n%s: %s: first entry not deflated or stored -- use unzip\n",
+ progname, ifname);
+ exit_code = ERROR;
+ return ERROR;
+ }
+
+ /* If entry encrypted, decrypt and validate encryption header */
+ if ((decrypt = h[LOCFLG] & CRPFLG) != 0) {
+ fprintf(stderr, "\n%s: %s: encrypted file -- use unzip\n",
+ progname, ifname);
+ exit_code = ERROR;
+ return ERROR;
+ }
+
+ /* Save flags for unzip() */
+ ext_header = (h[LOCFLG] & EXTFLG) != 0;
+ pkzip = 1;
+
+ /* Get ofname and time stamp from local header (to be done) */
+ return OK;
+}
+
+/* ===========================================================================
+ * Unzip in to out. This routine works on both gzip and pkzip files.
+ *
+ * IN assertions: the buffer inbuf contains already the beginning of
+ * the compressed data, from offsets inptr to insize-1 included.
+ * The magic header has already been checked. The output buffer is cleared.
+ */
+int unzip(in, out)
+ int in, out; /* input and output file descriptors */
+{
+ ulg orig_crc = 0; /* original crc */
+ ulg orig_len = 0; /* original uncompressed length */
+ int n;
+ uch buf[EXTHDR]; /* extended local header */
+
+ ifd = in;
+ ofd = out;
+
+ updcrc(NULL, 0); /* initialize crc */
+
+ if (pkzip && !ext_header) { /* crc and length at the end otherwise */
+ orig_crc = LG(inbuf + LOCCRC);
+ orig_len = LG(inbuf + LOCLEN);
+ }
+
+ /* Decompress */
+ if (method == DEFLATED) {
+
+ int res = inflate();
+
+ if (res == 3) {
+ error("out of memory");
+ } else if (res != 0) {
+ error("invalid compressed data--format violated");
+ }
+
+ } else if (pkzip && method == STORED) {
+
+ register ulg n = LG(inbuf + LOCLEN);
+
+ if (n != LG(inbuf + LOCSIZ) - (decrypt ? RAND_HEAD_LEN : 0)) {
+
+ fprintf(stderr, "len %ld, siz %ld\n", n, LG(inbuf + LOCSIZ));
+ error("invalid compressed data--length mismatch");
+ }
+ while (n--) {
+ uch c = (uch)get_byte();
+#ifdef CRYPT
+ if (decrypt) zdecode(c);
+#endif
+ put_ubyte(c);
+ }
+ flush_window();
+ } else {
+ error("internal error, invalid method");
+ }
+
+ /* Get the crc and original length */
+ if (!pkzip) {
+ /* crc32 (see algorithm.doc)
+ * uncompressed input size modulo 2^32
+ */
+ for (n = 0; n < 8; n++) {
+ buf[n] = (uch)get_byte(); /* may cause an error if EOF */
+ }
+ orig_crc = LG(buf);
+ orig_len = LG(buf+4);
+
+ } else if (ext_header) { /* If extended header, check it */
+ /* signature - 4bytes: 0x50 0x4b 0x07 0x08
+ * CRC-32 value
+ * compressed size 4-bytes
+ * uncompressed size 4-bytes
+ */
+ for (n = 0; n < EXTHDR; n++) {
+ buf[n] = (uch)get_byte(); /* may cause an error if EOF */
+ }
+ orig_crc = LG(buf+4);
+ orig_len = LG(buf+12);
+ }
+
+ /* Validate decompression */
+ if (orig_crc != updcrc(outbuf, 0)) {
+ error("invalid compressed data--crc error");
+ }
+ if (orig_len != (ulg)bytes_out) {
+ error("invalid compressed data--length error");
+ }
+
+ /* Check if there are more entries in a pkzip file */
+ if (pkzip && inptr + 4 < insize && LG(inbuf+inptr) == LOCSIG) {
+ if (to_stdout) {
+ WARN((stderr,
+ "%s: %s has more than one entry--rest ignored\n",
+ progname, ifname));
+ } else {
+ /* Don't destroy the input zip file */
+ fprintf(stderr,
+ "%s: %s has more than one entry -- unchanged\n",
+ progname, ifname);
+ exit_code = ERROR;
+ ext_header = pkzip = 0;
+ return ERROR;
+ }
+ }
+ ext_header = pkzip = 0; /* for next file */
+ return OK;
+}
diff --git a/gnu/usr.bin/gzip/util.c b/gnu/usr.bin/gzip/util.c
new file mode 100644
index 0000000..2cddf92
--- /dev/null
+++ b/gnu/usr.bin/gzip/util.c
@@ -0,0 +1,462 @@
+/* util.c -- utility functions for gzip support
+ * Copyright (C) 1992-1993 Jean-loup Gailly
+ * This is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License, see the file COPYING.
+ */
+
+#ifdef RCSID
+static char rcsid[] = "$Id: util.c,v 1.3 1993/10/14 00:33:26 nate Exp $";
+#endif
+
+#include <ctype.h>
+#include <errno.h>
+#include <sys/types.h>
+
+#include "tailor.h"
+
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+#ifndef NO_FCNTL_H
+# include <fcntl.h>
+#endif
+
+#if defined(STDC_HEADERS) || !defined(NO_STDLIB_H)
+# include <stdlib.h>
+#else
+ extern int errno;
+#endif
+
+#include "gzip.h"
+#include "crypt.h"
+
+extern ulg crc_32_tab[]; /* crc table, defined below */
+
+/* ===========================================================================
+ * Copy input to output unchanged: zcat == cat with --force.
+ * IN assertion: insize bytes have already been read in inbuf.
+ */
+int copy(in, out)
+ int in, out; /* input and output file descriptors */
+{
+ errno = 0;
+ while (insize != 0 && (int)insize != EOF) {
+ write_buf(out, (char*)inbuf, insize);
+ bytes_out += insize;
+ insize = read(in, (char*)inbuf, INBUFSIZ);
+ }
+ if ((int)insize == EOF && errno != 0) {
+ read_error();
+ }
+ bytes_in = bytes_out;
+ return OK;
+}
+
+/* ===========================================================================
+ * Run a set of bytes through the crc shift register. If s is a NULL
+ * pointer, then initialize the crc shift register contents instead.
+ * Return the current crc in either case.
+ */
+ulg updcrc(s, n)
+ uch *s; /* pointer to bytes to pump through */
+ unsigned n; /* number of bytes in s[] */
+{
+ register ulg c; /* temporary variable */
+
+ static ulg crc = (ulg)0xffffffffL; /* shift register contents */
+
+ if (s == NULL) {
+ c = 0xffffffffL;
+ } else {
+ c = crc;
+ if (n) do {
+ c = crc_32_tab[((int)c ^ (*s++)) & 0xff] ^ (c >> 8);
+ } while (--n);
+ }
+ crc = c;
+ return c ^ 0xffffffffL; /* (instead of ~c for 64-bit machines) */
+}
+
+/* ===========================================================================
+ * Clear input and output buffers
+ */
+void clear_bufs()
+{
+ outcnt = 0;
+ insize = inptr = 0;
+ bytes_in = bytes_out = 0L;
+}
+
+/* ===========================================================================
+ * Fill the input buffer. This is called only when the buffer is empty.
+ */
+int fill_inbuf(eof_ok)
+ int eof_ok; /* set if EOF acceptable as a result */
+{
+ int len;
+
+ /* Read as much as possible */
+ insize = 0;
+ errno = 0;
+ do {
+ len = read(ifd, (char*)inbuf+insize, INBUFSIZ-insize);
+ if (len == 0 || len == EOF) break;
+ insize += len;
+ } while (insize < INBUFSIZ);
+
+ if (insize == 0) {
+ if (eof_ok) return EOF;
+ read_error();
+ }
+ bytes_in += (ulg)insize;
+ inptr = 1;
+ return inbuf[0];
+}
+
+/* ===========================================================================
+ * Write the output buffer outbuf[0..outcnt-1] and update bytes_out.
+ * (used for the compressed data only)
+ */
+void flush_outbuf()
+{
+ if (outcnt == 0) return;
+
+ write_buf(ofd, (char *)outbuf, outcnt);
+ bytes_out += (ulg)outcnt;
+ outcnt = 0;
+}
+
+/* ===========================================================================
+ * Write the output window window[0..outcnt-1] and update crc and bytes_out.
+ * (Used for the decompressed data only.)
+ */
+void flush_window()
+{
+ if (outcnt == 0) return;
+ updcrc(window, outcnt);
+
+ if (!test) {
+ write_buf(ofd, (char *)window, outcnt);
+ }
+ bytes_out += (ulg)outcnt;
+ outcnt = 0;
+}
+
+/* ===========================================================================
+ * Does the same as write(), but also handles partial pipe writes and checks
+ * for error return.
+ */
+void write_buf(fd, buf, cnt)
+ int fd;
+ voidp buf;
+ unsigned cnt;
+{
+ unsigned n;
+
+ while ((n = write(fd, buf, cnt)) != cnt) {
+ if (n == (unsigned)(-1)) {
+ write_error();
+ }
+ cnt -= n;
+ buf = (voidp)((char*)buf+n);
+ }
+}
+
+/* ========================================================================
+ * Put string s in lower case, return s.
+ */
+char *strlwr(s)
+ char *s;
+{
+ char *t;
+ for (t = s; *t; t++) *t = tolow(*t);
+ return s;
+}
+
+/* ========================================================================
+ * Return the base name of a file (remove any directory prefix and
+ * any version suffix). For systems with file names that are not
+ * case sensitive, force the base name to lower case.
+ */
+char *basename(fname)
+ char *fname;
+{
+ char *p;
+
+ if ((p = strrchr(fname, PATH_SEP)) != NULL) fname = p+1;
+#ifdef PATH_SEP2
+ if ((p = strrchr(fname, PATH_SEP2)) != NULL) fname = p+1;
+#endif
+#ifdef PATH_SEP3
+ if ((p = strrchr(fname, PATH_SEP3)) != NULL) fname = p+1;
+#endif
+#ifdef SUFFIX_SEP
+ if ((p = strrchr(fname, SUFFIX_SEP)) != NULL) *p = '\0';
+#endif
+ if (casemap('A') == 'a') strlwr(fname);
+ return fname;
+}
+
+/* ========================================================================
+ * Make a file name legal for file systems not allowing file names with
+ * multiple dots or starting with a dot (such as MSDOS), by changing
+ * all dots except the last one into underlines. A target dependent
+ * function can be used instead of this simple function by defining the macro
+ * MAKE_LEGAL_NAME in tailor.h and providing the function in a target
+ * dependent module.
+ */
+void make_simple_name(name)
+ char *name;
+{
+ char *p = strrchr(name, '.');
+ if (p == NULL) return;
+ if (p == name) p++;
+ do {
+ if (*--p == '.') *p = '_';
+ } while (p != name);
+}
+
+
+#if defined(NO_STRING_H) && !defined(STDC_HEADERS)
+
+/* Provide missing strspn and strcspn functions. */
+
+# ifndef __STDC__
+# define const
+# endif
+
+int strspn OF((const char *s, const char *accept));
+int strcspn OF((const char *s, const char *reject));
+
+/* ========================================================================
+ * Return the length of the maximum initial segment
+ * of s which contains only characters in accept.
+ */
+int strspn(s, accept)
+ const char *s;
+ const char *accept;
+{
+ register const char *p;
+ register const char *a;
+ register int count = 0;
+
+ for (p = s; *p != '\0'; ++p) {
+ for (a = accept; *a != '\0'; ++a) {
+ if (*p == *a) break;
+ }
+ if (*a == '\0') return count;
+ ++count;
+ }
+ return count;
+}
+
+/* ========================================================================
+ * Return the length of the maximum inital segment of s
+ * which contains no characters from reject.
+ */
+int strcspn(s, reject)
+ const char *s;
+ const char *reject;
+{
+ register int count = 0;
+
+ while (*s != '\0') {
+ if (strchr(reject, *s++) != NULL) return count;
+ ++count;
+ }
+ return count;
+}
+
+#endif /* NO_STRING_H */
+
+/* ========================================================================
+ * Add an environment variable (if any) before argv, and update argc.
+ * Return the expanded environment variable to be freed later, or NULL
+ * if no options were added to argv.
+ */
+#define SEPARATOR " \t" /* separators in env variable */
+
+char *add_envopt(argcp, argvp, env)
+ int *argcp; /* pointer to argc */
+ char ***argvp; /* pointer to argv */
+ char *env; /* name of environment variable */
+{
+ char *p; /* running pointer through env variable */
+ char **oargv; /* runs through old argv array */
+ char **nargv; /* runs through new argv array */
+ int oargc = *argcp; /* old argc */
+ int nargc = 0; /* number of arguments in env variable */
+
+ env = (char*)getenv(env);
+ if (env == NULL) return NULL;
+
+ p = (char*)xmalloc(strlen(env)+1);
+ env = strcpy(p, env); /* keep env variable intact */
+
+ for (p = env; *p; nargc++ ) { /* move through env */
+ p += strspn(p, SEPARATOR); /* skip leading separators */
+ if (*p == '\0') break;
+
+ p += strcspn(p, SEPARATOR); /* find end of word */
+ if (*p) *p++ = '\0'; /* mark it */
+ }
+ if (nargc == 0) {
+ free(env);
+ return NULL;
+ }
+ *argcp += nargc;
+ /* Allocate the new argv array, with an extra element just in case
+ * the original arg list did not end with a NULL.
+ */
+ nargv = (char**)calloc(*argcp+1, sizeof(char *));
+ if (nargv == NULL) error("out of memory");
+ oargv = *argvp;
+ *argvp = nargv;
+
+ /* Copy the program name first */
+ if (oargc-- < 0) error("argc<=0");
+ *(nargv++) = *(oargv++);
+
+ /* Then copy the environment args */
+ for (p = env; nargc > 0; nargc--) {
+ p += strspn(p, SEPARATOR); /* skip separators */
+ *(nargv++) = p; /* store start */
+ while (*p++) ; /* skip over word */
+ }
+
+ /* Finally copy the old args and add a NULL (usual convention) */
+ while (oargc--) *(nargv++) = *(oargv++);
+ *nargv = NULL;
+ return env;
+}
+
+/* ========================================================================
+ * Error handlers.
+ */
+void error(m)
+ char *m;
+{
+ fprintf(stderr, "\n%s: %s: %s\n", progname, ifname, m);
+ abort_gzip();
+}
+
+void warn(a, b)
+ char *a, *b; /* message strings juxtaposed in output */
+{
+ WARN((stderr, "%s: %s: warning: %s%s\n", progname, ifname, a, b));
+}
+
+void read_error()
+{
+ fprintf(stderr, "\n%s: ", progname);
+ if (errno != 0) {
+ perror(ifname);
+ } else {
+ fprintf(stderr, "%s: unexpected end of file\n", ifname);
+ }
+ abort_gzip();
+}
+
+void write_error()
+{
+ fprintf(stderr, "\n%s: ", progname);
+ perror(ofname);
+ abort_gzip();
+}
+
+/* ========================================================================
+ * Display compression ratio on the given stream on 6 characters.
+ */
+void display_ratio(num, den, file)
+ long num;
+ long den;
+ FILE *file;
+{
+ long ratio; /* 1000 times the compression ratio */
+
+ if (den == 0) {
+ ratio = 0; /* no compression */
+ } else if (den < 2147483L) { /* (2**31 -1)/1000 */
+ ratio = 1000L*num/den;
+ } else {
+ ratio = num/(den/1000L);
+ }
+ if (ratio < 0) {
+ putc('-', file);
+ ratio = -ratio;
+ } else {
+ putc(' ', file);
+ }
+ fprintf(file, "%2ld.%1ld%%", ratio / 10L, ratio % 10L);
+}
+
+
+/* ========================================================================
+ * Semi-safe malloc -- never returns NULL.
+ */
+voidp xmalloc (size)
+ unsigned size;
+{
+ voidp cp = (voidp)malloc (size);
+
+ if (cp == NULL) error("out of memory");
+ return cp;
+}
+
+/* ========================================================================
+ * Table of CRC-32's of all single-byte values (made by makecrc.c)
+ */
+ulg crc_32_tab[] = {
+ 0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L,
+ 0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L,
+ 0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L,
+ 0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL,
+ 0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L,
+ 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L,
+ 0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L,
+ 0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL,
+ 0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L,
+ 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL,
+ 0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L,
+ 0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L,
+ 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L,
+ 0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL,
+ 0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL,
+ 0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L,
+ 0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL,
+ 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L,
+ 0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L,
+ 0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L,
+ 0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL,
+ 0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L,
+ 0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L,
+ 0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL,
+ 0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L,
+ 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L,
+ 0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L,
+ 0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L,
+ 0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L,
+ 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL,
+ 0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL,
+ 0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L,
+ 0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L,
+ 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL,
+ 0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL,
+ 0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L,
+ 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL,
+ 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L,
+ 0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL,
+ 0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L,
+ 0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL,
+ 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L,
+ 0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L,
+ 0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL,
+ 0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L,
+ 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L,
+ 0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L,
+ 0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L,
+ 0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L,
+ 0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L,
+ 0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL,
+ 0x2d02ef8dL
+};
diff --git a/gnu/usr.bin/gzip/zdiff b/gnu/usr.bin/gzip/zdiff
new file mode 100644
index 0000000..84e65d3
--- /dev/null
+++ b/gnu/usr.bin/gzip/zdiff
@@ -0,0 +1,69 @@
+#!/bin/sh
+# sh is buggy on RS/6000 AIX 3.2. Replace above line with #!/bin/ksh
+
+# Zcmp and zdiff are used to invoke the cmp or the diff pro-
+# gram on compressed files. All options specified are passed
+# directly to cmp or diff. If only 1 file is specified, then
+# the files compared are file1 and an uncompressed file1.gz.
+# If two files are specified, then they are uncompressed (if
+# necessary) and fed to cmp or diff. The exit status from cmp
+# or diff is preserved.
+
+PATH="/usr/local/bin:$PATH"; export PATH
+prog=`echo $0 | sed 's|.*/||'`
+case "$prog" in
+ *cmp) comp=${CMP-cmp} ;;
+ *) comp=${DIFF-diff} ;;
+esac
+
+OPTIONS=
+FILES=
+for ARG
+do
+ case "$ARG" in
+ -*) OPTIONS="$OPTIONS $ARG";;
+ *) if test -f "$ARG"; then
+ FILES="$FILES $ARG"
+ else
+ echo "${prog}: $ARG not found or not a regular file"
+ exit 1
+ fi ;;
+ esac
+done
+if test -z "$FILES"; then
+ echo "Usage: $prog [${comp}_options] file [file]"
+ exit 1
+fi
+set $FILES
+if test $# -eq 1; then
+ FILE=`echo "$1" | sed 's/[-.][zZtga]*$//'`
+ gzip -cd "$1" | $comp $OPTIONS - "$FILE"
+ STAT="$?"
+
+elif test $# -eq 2; then
+ case "$1" in
+ *[-.]gz* | *[-.][zZ] | *.t[ga]z)
+ case "$2" in
+ *[-.]gz* | *[-.][zZ] | *.t[ga]z)
+ F=`echo "$2" | sed 's|.*/||;s|[-.][zZtga]*||'`
+ gzip -cdfq "$2" > /tmp/"$F".$$
+ gzip -cdfq "$1" | $comp $OPTIONS - /tmp/"$F".$$
+ STAT="$?"
+ /bin/rm -f /tmp/"$F".$$;;
+
+ *) gzip -cdfq "$1" | $comp $OPTIONS - "$2"
+ STAT="$?";;
+ esac;;
+ *) case "$2" in
+ *[-.]gz* | *[-.][zZ] | *.t[ga]z)
+ gzip -cdfq "$2" | $comp $OPTIONS "$1" -
+ STAT="$?";;
+ *) $comp $OPTIONS "$1" "$2"
+ STAT="$?";;
+ esac;;
+ esac
+ exit "$STAT"
+else
+ echo "Usage: $prog [${comp}_options] file [file]"
+ exit 1
+fi
diff --git a/gnu/usr.bin/gzip/zdiff.1 b/gnu/usr.bin/gzip/zdiff.1
new file mode 100644
index 0000000..ea3bf41
--- /dev/null
+++ b/gnu/usr.bin/gzip/zdiff.1
@@ -0,0 +1,44 @@
+.TH ZDIFF 1
+.SH NAME
+zcmp, zdiff \- compare compressed files
+.SH SYNOPSIS
+.B zcmp
+[ cmp_options ] file1
+[ file2 ]
+.br
+.B zdiff
+[ diff_options ] file1
+[ file2 ]
+.SH DESCRIPTION
+.I Zcmp
+and
+.I zdiff
+are used to invoke the
+.I cmp
+or the
+.I diff
+program on compressed files. All options specified are passed directly to
+.I cmp
+or
+.IR diff "."
+If only 1 file is specified, then the files compared are
+.I file1
+and an uncompressed
+.IR file1 ".gz."
+If two files are specified, then they are uncompressed if necessary and fed to
+.I cmp
+or
+.IR diff "."
+The exit status from
+.I cmp
+or
+.I diff
+is preserved.
+.SH "SEE ALSO"
+cmp(1), diff(1), zmore(1), zgrep(1), znew(1), zforce(1), gzip(1), gzexe(1)
+.SH BUGS
+Messages from the
+.I cmp
+or
+.I diff
+programs refer to temporary filenames instead of those specified.
diff --git a/gnu/usr.bin/gzip/zforce b/gnu/usr.bin/gzip/zforce
new file mode 100644
index 0000000..17258a4
--- /dev/null
+++ b/gnu/usr.bin/gzip/zforce
@@ -0,0 +1,41 @@
+#!/bin/sh
+# zforce: force a gz extension on all gzip files so that gzip will not
+# compress them twice.
+#
+# This can be useful for files with names truncated after a file transfer.
+# 12345678901234 is renamed to 12345678901.gz
+
+PATH="/usr/local/bin:$PATH"; export PATH
+x=`basename $0`
+if test $# = 0; then
+ echo "force a '.gz' extension on all gzip files"
+ echo usage: $x files...
+ exit 1
+fi
+
+res=0
+for i do
+ if test ! -f "$i" ; then
+ echo ${x}: $i not a file
+ res=1
+ continue
+ fi
+ test `expr "$i" : '.*[.-]z$'` -eq 0 || continue
+ test `expr "$i" : '.*[.-]gz$'` -eq 0 || continue
+ test `expr "$i" : '.*[.]t[ag]z$'` -eq 0 || continue
+
+ if gzip -l < "$i" 2>/dev/null | grep '^defl' > /dev/null; then
+
+ if test `expr "$i" : '^............'` -eq 12; then
+ new=`expr "$i" : '\(.*\)...$`.gz
+ else
+ new="$i.gz"
+ fi
+ if mv "$i" "$new" 2>/dev/null; then
+ echo $i -- replaced with $new
+ continue
+ fi
+ res=1; echo ${x}: cannot rename $i to $new
+ fi
+done
+exit $res
diff --git a/gnu/usr.bin/gzip/zforce.1 b/gnu/usr.bin/gzip/zforce.1
new file mode 100644
index 0000000..37c6aba
--- /dev/null
+++ b/gnu/usr.bin/gzip/zforce.1
@@ -0,0 +1,20 @@
+.TH ZFORCE 1
+.SH NAME
+zforce \- force a '.gz' extension on all gzip files
+.SH SYNOPSIS
+.B zforce
+[ name ... ]
+.SH DESCRIPTION
+.I zforce
+forces a .gz extension on all
+.I gzip
+files so that
+.I gzip
+will not compress them twice.
+This can be useful for files with names truncated after a file transfer.
+On systems with a 14 char limitation on file names, the original name
+is truncated to make room for the .gz suffix. For example,
+12345678901234 is renamed to 12345678901.gz. A file name such as foo.tgz
+is left intact.
+.SH "SEE ALSO"
+gzip(1), znew(1), zmore(1), zgrep(1), zdiff(1), gzexe(1)
diff --git a/gnu/usr.bin/gzip/zgrep b/gnu/usr.bin/gzip/zgrep
new file mode 100644
index 0000000..bcc10cc
--- /dev/null
+++ b/gnu/usr.bin/gzip/zgrep
@@ -0,0 +1,72 @@
+#!/bin/sh
+
+# zgrep -- a wrapper around a grep program that decompresses files as needed
+# Adapted from a version sent by Charles Levert <charles@comm.polymtl.ca>
+
+PATH="/usr/local/bin:$PATH"; export PATH
+
+prog=`echo $0 | sed 's|.*/||'`
+case "$prog" in
+ *egrep) grep=${EGREP-egrep} ;;
+ *fgrep) grep=${FGREP-fgrep} ;;
+ *) grep=${GREP-grep} ;;
+esac
+A=
+fileno=0
+pat=""
+while test $# -ne 0; do
+ case "$1" in
+ -e | -f) opt="$opt $1"; shift; pat="$1"
+ if test "$grep" = grep; then # grep is buggy with -e on SVR4
+ grep=egrep
+ fi;;
+ -*) opt="$opt $1";;
+ *) if test -z "$pat"; then
+ pat="$1"
+ else
+ fileno=`expr $fileno + 1`
+ eval A$fileno=\$1
+ A="$A \"\$A$fileno\""
+ fi
+ ;;
+ esac
+ shift
+done
+
+if test -z "$pat"; then
+ echo "grep through gzip files"
+ echo "usage: $prog [grep_options] pattern [files]"
+ exit 1
+fi
+
+list=0
+silent=0
+op=`echo "$opt" | sed -e 's/ //g' -e 's/-//g'`
+case "$op" in
+ *l*) list=1
+esac
+case "$op" in
+ *h*) silent=1
+esac
+
+if test $fileno -eq 0; then
+ gzip -cdfq | $grep $opt "$pat"
+ exit $?
+fi
+eval set "$A" # files in $1, $2 ...
+
+res=0
+for i do
+ if test $list -eq 1; then
+ gzip -cdfq "$i" | $grep $opt "$pat" > /dev/null && echo $i
+ r=$?
+ elif test $# -eq 1 -o $silent -eq 1; then
+ gzip -cdfq "$i" | $grep $opt "$pat"
+ r=$?
+ else
+ gzip -cdfq "$i" | $grep $opt "$pat" | sed "s|^|${i}:|"
+ r=$?
+ fi
+ test "$r" -ne 0 && res="$r"
+done
+exit $res
diff --git a/gnu/usr.bin/gzip/zgrep.1 b/gnu/usr.bin/gzip/zgrep.1
new file mode 100644
index 0000000..a52a88a
--- /dev/null
+++ b/gnu/usr.bin/gzip/zgrep.1
@@ -0,0 +1,44 @@
+.TH ZGREP 1
+.SH NAME
+zgrep \- search possibly compressed files for a regular expression
+.SH SYNOPSIS
+.B zgrep
+[ grep_options ]
+.BI [\ -e\ ] " pattern"
+.IR filename ".\|.\|."
+.SH DESCRIPTION
+.IR Zgrep
+is used to invoke the
+.I grep
+on compress'ed or gzip'ed files. All options specified are passed directly to
+.I grep.
+If no file is specified, then the standard input is decompressed
+if necessary and fed to grep.
+Otherwise the given files are uncompressed if necessary and fed to
+.I grep.
+.PP
+If
+.I zgrep
+is invoked as
+.I zegrep
+or
+.I zfgrep
+then
+.I egrep
+or
+.I fgrep
+is used instead of
+.I grep.
+If the GREP environment variable is set,
+.I zgrep
+uses it as the
+.I grep
+program to be invoked. For example:
+
+ for sh: GREP=fgrep zgrep string files
+ for csh: (setenv GREP fgrep; zgrep string files)
+.SH AUTHOR
+Charles Levert (charles@comm.polymtl.ca)
+.SH "SEE ALSO"
+grep(1), egrep(1), fgrep(1), zdiff(1), zmore(1), znew(1), zforce(1),
+gzip(1), gzexe(1)
diff --git a/gnu/usr.bin/gzip/zip.c b/gnu/usr.bin/gzip/zip.c
new file mode 100644
index 0000000..507d161
--- /dev/null
+++ b/gnu/usr.bin/gzip/zip.c
@@ -0,0 +1,117 @@
+/* zip.c -- compress files to the gzip or pkzip format
+ * Copyright (C) 1992-1993 Jean-loup Gailly
+ * This is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License, see the file COPYING.
+ */
+
+#ifdef RCSID
+static char rcsid[] = "$Id: zip.c,v 0.17 1993/06/10 13:29:25 jloup Exp $";
+#endif
+
+#include <ctype.h>
+#include <sys/types.h>
+
+#include "tailor.h"
+#include "gzip.h"
+#include "crypt.h"
+
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+#ifndef NO_FCNTL_H
+# include <fcntl.h>
+#endif
+
+local ulg crc; /* crc on uncompressed file data */
+long header_bytes; /* number of bytes in gzip header */
+
+/* ===========================================================================
+ * Deflate in to out.
+ * IN assertions: the input and output buffers are cleared.
+ * The variables time_stamp and save_orig_name are initialized.
+ */
+int zip(in, out)
+ int in, out; /* input and output file descriptors */
+{
+ uch flags = 0; /* general purpose bit flags */
+ ush attr = 0; /* ascii/binary flag */
+ ush deflate_flags = 0; /* pkzip -es, -en or -ex equivalent */
+
+ ifd = in;
+ ofd = out;
+ outcnt = 0;
+
+ /* Write the header to the gzip file. See algorithm.doc for the format */
+
+ method = DEFLATED;
+ put_byte(GZIP_MAGIC[0]); /* magic header */
+ put_byte(GZIP_MAGIC[1]);
+ put_byte(DEFLATED); /* compression method */
+
+ if (save_orig_name) {
+ flags |= ORIG_NAME;
+ }
+ put_byte(flags); /* general flags */
+ put_long(time_stamp);
+
+ /* Write deflated file to zip file */
+ crc = updcrc(0, 0);
+
+ bi_init(out);
+ ct_init(&attr, &method);
+ lm_init(level, &deflate_flags);
+
+ put_byte((uch)deflate_flags); /* extra flags */
+ put_byte(OS_CODE); /* OS identifier */
+
+ if (save_orig_name) {
+ char *p = basename(ifname); /* Don't save the directory part. */
+ do {
+ put_char(*p);
+ } while (*p++);
+ }
+ header_bytes = (long)outcnt;
+
+ (void)deflate();
+
+#if !defined(NO_SIZE_CHECK) && !defined(RECORD_IO)
+ /* Check input size (but not in VMS -- variable record lengths mess it up)
+ * and not on MSDOS -- diet in TSR mode reports an incorrect file size)
+ */
+ if (ifile_size != -1L && isize != (ulg)ifile_size) {
+ Trace((stderr, " actual=%ld, read=%ld ", ifile_size, isize));
+ fprintf(stderr, "%s: %s: file size changed while zipping\n",
+ progname, ifname);
+ }
+#endif
+
+ /* Write the crc and uncompressed size */
+ put_long(crc);
+ put_long(isize);
+ header_bytes += 2*sizeof(long);
+
+ flush_outbuf();
+ return OK;
+}
+
+
+/* ===========================================================================
+ * Read a new buffer from the current input file, perform end-of-line
+ * translation, and update the crc and input file size.
+ * IN assertion: size >= 2 (for end-of-line translation)
+ */
+int file_read(buf, size)
+ char *buf;
+ unsigned size;
+{
+ unsigned len;
+
+ Assert(insize == 0, "inbuf not empty");
+
+ len = read(ifd, buf, size);
+ if (len == (unsigned)(-1) || len == 0) return (int)len;
+
+ crc = updcrc((uch*)buf, len);
+ isize += (ulg)len;
+ return (int)len;
+}
diff --git a/gnu/usr.bin/gzip/zmore b/gnu/usr.bin/gzip/zmore
new file mode 100644
index 0000000..ca933c7
--- /dev/null
+++ b/gnu/usr.bin/gzip/zmore
@@ -0,0 +1,51 @@
+#!/bin/sh
+
+PATH="/usr/local/bin:$PATH"; export PATH
+if test "`echo -n a`" = "-n a"; then
+ # looks like a SysV system:
+ n1=''; n2='\c'
+else
+ n1='-n'; n2=''
+fi
+oldtty=`stty -g 2>/dev/null`
+if stty -cbreak 2>/dev/null; then
+ cb='cbreak'; ncb='-cbreak'
+else
+ # 'stty min 1' resets eof to ^a on both SunOS and SysV!
+ cb='min 1 -icanon'; ncb='icanon eof ^d'
+fi
+if test $? -eq 0 -a -n "$oldtty"; then
+ trap 'stty $oldtty 2>/dev/null; exit' 0 2 3 5 10 13 15
+else
+ trap 'stty $ncb echo 2>/dev/null; exit' 0 2 3 5 10 13 15
+fi
+
+if test $# = 0; then
+ if test -t 0; then
+ echo usage: zmore files...
+ else
+ gzip -cdfq | eval ${PAGER-more}
+ fi
+else
+ FIRST=1
+ for FILE
+ do
+ if test $FIRST -eq 0; then
+ echo $n1 "--More--(Next file: $FILE)$n2"
+ stty $cb -echo 2>/dev/null
+ ANS=`dd bs=1 count=1 2>/dev/null`
+ stty $ncb echo 2>/dev/null
+ echo " "
+ if test "$ANS" = 'e' -o "$ANS" = 'q'; then
+ exit
+ fi
+ fi
+ if test "$ANS" != 's'; then
+ echo "------> $FILE <------"
+ gzip -cdfq "$FILE" | eval ${PAGER-more}
+ fi
+ if test -t; then
+ FIRST=0
+ fi
+ done
+fi
diff --git a/gnu/usr.bin/gzip/zmore.1 b/gnu/usr.bin/gzip/zmore.1
new file mode 100644
index 0000000..f7f1843
--- /dev/null
+++ b/gnu/usr.bin/gzip/zmore.1
@@ -0,0 +1,145 @@
+.TH ZMORE 1
+.SH NAME
+zmore \- file perusal filter for crt viewing of compressed text
+.SH SYNOPSIS
+.B zmore
+[ name ... ]
+.SH DESCRIPTION
+.I Zmore
+is a filter which allows examination of compressed or plain text files
+one screenful at a time on a soft-copy terminal.
+.I zmore
+works on files compressed with
+.I compress, pack
+or
+.I gzip,
+and also on uncompressed files.
+If a file does not exist,
+.I zmore
+looks for a file of the same name with the addition of a .gz, .z or .Z suffix.
+.PP
+.I Zmore
+normally pauses after each screenful, printing --More--
+at the bottom of the screen.
+If the user then types a carriage return, one more line is displayed.
+If the user hits a space,
+another screenful is displayed. Other possibilities are enumerated later.
+.PP
+.I Zmore
+looks in the file
+.I /etc/termcap
+to determine terminal characteristics,
+and to determine the default window size.
+On a terminal capable of displaying 24 lines,
+the default window size is 22 lines.
+To use a pager other than the default
+.I more,
+set environment variable PAGER to the name of the desired program, such as
+.I less.
+.PP
+Other sequences which may be typed when
+.I zmore
+pauses, and their effects, are as follows (\fIi\fP is an optional integer
+argument, defaulting to 1) :
+.PP
+.IP \fIi\|\fP<space>
+display
+.I i
+more lines, (or another screenful if no argument is given)
+.PP
+.IP ^D
+display 11 more lines (a ``scroll'').
+If
+.I i
+is given, then the scroll size is set to \fIi\|\fP.
+.PP
+.IP d
+same as ^D (control-D)
+.PP
+.IP \fIi\|\fPz
+same as typing a space except that \fIi\|\fP, if present, becomes the new
+window size. Note that the window size reverts back to the default at the
+end of the current file.
+.PP
+.IP \fIi\|\fPs
+skip \fIi\|\fP lines and print a screenful of lines
+.PP
+.IP \fIi\|\fPf
+skip \fIi\fP screenfuls and print a screenful of lines
+.PP
+.IP "q or Q"
+quit reading the current file; go on to the next (if any)
+.PP
+.IP "e or q"
+When the prompt --More--(Next file:
+.IR file )
+is printed, this command causes zmore to exit.
+.PP
+.IP s
+When the prompt --More--(Next file:
+.IR file )
+is printed, this command causes zmore to skip the next file and continue.
+.PP
+.IP =
+Display the current line number.
+.PP
+.IP \fIi\|\fP/expr
+search for the \fIi\|\fP-th occurrence of the regular expression \fIexpr.\fP
+If the pattern is not found,
+.I zmore
+goes on to the next file (if any).
+Otherwise, a screenful is displayed, starting two lines before the place
+where the expression was found.
+The user's erase and kill characters may be used to edit the regular
+expression.
+Erasing back past the first column cancels the search command.
+.PP
+.IP \fIi\|\fPn
+search for the \fIi\|\fP-th occurrence of the last regular expression entered.
+.PP
+.IP !command
+invoke a shell with \fIcommand\|\fP.
+The character `!' in "command" are replaced with the
+previous shell command. The sequence "\\!" is replaced by "!".
+.PP
+.IP ":q or :Q"
+quit reading the current file; go on to the next (if any)
+(same as q or Q).
+.PP
+.IP .
+(dot) repeat the previous command.
+.PP
+The commands take effect immediately, i.e., it is not necessary to
+type a carriage return.
+Up to the time when the command character itself is given,
+the user may hit the line kill character to cancel the numerical
+argument being formed.
+In addition, the user may hit the erase character to redisplay the
+--More-- message.
+.PP
+At any time when output is being sent to the terminal, the user can
+hit the quit key (normally control\-\\).
+.I Zmore
+will stop sending output, and will display the usual --More--
+prompt.
+The user may then enter one of the above commands in the normal manner.
+Unfortunately, some output is lost when this is done, due to the
+fact that any characters waiting in the terminal's output queue
+are flushed when the quit signal occurs.
+.PP
+The terminal is set to
+.I noecho
+mode by this program so that the output can be continuous.
+What you type will thus not show on your terminal, except for the / and !
+commands.
+.PP
+If the standard output is not a teletype, then
+.I zmore
+acts just like
+.I zcat,
+except that a header is printed before each file.
+.SH FILES
+.DT
+/etc/termcap Terminal data base
+.SH "SEE ALSO"
+more(1), gzip(1), zdiff(1), zgrep(1), znew(1), zforce(1), gzexe(1)
diff --git a/gnu/usr.bin/gzip/znew b/gnu/usr.bin/gzip/znew
new file mode 100644
index 0000000..5c832e8
--- /dev/null
+++ b/gnu/usr.bin/gzip/znew
@@ -0,0 +1,145 @@
+#!/bin/sh
+
+PATH="/usr/local/bin:$PATH"; export PATH
+check=0
+pipe=0
+opt=
+files=
+keep=0
+res=0
+old=0
+new=0
+block=1024
+# block is the disk block size (best guess, need not be exact)
+
+warn="(does not preserve modes and timestamp)"
+tmp=/tmp/zfoo.$$
+echo hi > $tmp.1
+echo hi > $tmp.2
+if test -z "`(${CPMOD-cpmod} $tmp.1 $tmp.2) 2>&1`"; then
+ cpmod=${CPMOD-cpmod}
+ warn=""
+fi
+
+if test -z "$cpmod" && ${TOUCH-touch} -r $tmp.1 $tmp.2 2>/dev/null; then
+ cpmod="${TOUCH-touch}"
+ cpmodarg="-r"
+ warn="(does not preserve file modes)"
+fi
+
+# check if GZIP env. variable uses -S or --suffix
+gzip -q $tmp.1
+ext=`echo $tmp.1* | sed "s|$tmp.1||"`
+rm -f $tmp.[12]*
+if test -z "$ext"; then
+ echo znew: error determining gzip extension
+ exit 1
+fi
+if test "$ext" = ".Z"; then
+ echo znew: cannot use .Z as gzip extension.
+ exit 1
+fi
+
+for arg
+do
+ case "$arg" in
+ -*) opt="$opt $arg"; shift;;
+ *) break;;
+ esac
+done
+
+if test $# -eq 0; then
+ echo "recompress .Z files into $ext (gzip) files"
+ echo usage: `echo $0 | sed 's,^.*/,,'` "[-tv9KP]" file.Z...
+ echo " -t tests the new files before deleting originals"
+ echo " -v be verbose"
+ echo " -9 use the slowest compression method (optimal compression)"
+ echo " -K keep a .Z file when it is smaller than the $ext file"
+ echo " -P use pipes for the conversion $warn"
+ exit 1
+fi
+
+opt=`echo "$opt" | sed -e 's/ //g' -e 's/-//g'`
+case "$opt" in
+ *t*) check=1; opt=`echo "$opt" | sed 's/t//g'`
+esac
+case "$opt" in
+ *K*) keep=1; opt=`echo "$opt" | sed 's/K//g'`
+esac
+case "$opt" in
+ *P*) pipe=1; opt=`echo "$opt" | sed 's/P//g'`
+esac
+if test -n "$opt"; then
+ opt="-$opt"
+fi
+
+for i do
+ n=`echo $i | sed 's/.Z$//'`
+ if test ! -f "$n.Z" ; then
+ echo $n.Z not found
+ res=1; continue
+ fi
+ test $keep -eq 1 && old=`wc -c < "$n.Z"`
+ if test $pipe -eq 1; then
+ if gzip -d < "$n.Z" | gzip $opt > "$n$ext"; then
+ # Copy file attributes from old file to new one, if possible.
+ test -n "$cpmod" && $cpmod $cpmodarg "$n.Z" "$n$ext" 2> /dev/null
+ else
+ echo error while recompressing $n.Z
+ res=1; continue
+ fi
+ else
+ if test $check -eq 1; then
+ if cp -p "$n.Z" "$n.$$" 2> /dev/null || cp "$n.Z" "$n.$$"; then
+ :
+ else
+ echo cannot backup "$n.Z"
+ res=1; continue
+ fi
+ fi
+ if gzip -d "$n.Z"; then
+ :
+ else
+ test $check -eq 1 && mv "$n.$$" "$n.Z"
+ echo error while uncompressing $n.Z
+ res=1; continue
+ fi
+ if gzip $opt "$n"; then
+ :
+ else
+ if test $check -eq 1; then
+ mv "$n.$$" "$n.Z" && rm -f "$n"
+ echo error while recompressing $n
+ else
+ # compress $n (might be dangerous if disk full)
+ echo error while recompressing $n, left uncompressed
+ fi
+ res=1; continue
+ fi
+ fi
+ test $keep -eq 1 && new=`wc -c < "$n$ext"`
+ if test $keep -eq 1 -a `expr \( $old + $block - 1 \) / $block` -lt \
+ `expr \( $new + $block - 1 \) / $block`; then
+ if test $pipe -eq 1; then
+ rm -f "$n$ext"
+ elif test $check -eq 1; then
+ mv "$n.$$" "$n.Z" && rm -f "$n$ext"
+ else
+ gzip -d "$n$ext" && compress "$n" && rm -f "$n$ext"
+ fi
+ echo "$n.Z smaller than $n$ext -- unchanged"
+
+ elif test $check -eq 1; then
+ if gzip -t "$n$ext" ; then
+ rm -f "$n.$$" "$n.Z"
+ else
+ test $pipe -eq 0 && mv "$n.$$" "$n.Z"
+ rm -f "$n$ext"
+ echo error while testing $n$ext, $n.Z unchanged
+ res=1; continue
+ fi
+ elif test $pipe -eq 1; then
+ rm -f "$n.Z"
+ fi
+done
+exit $res
diff --git a/gnu/usr.bin/gzip/znew.1 b/gnu/usr.bin/gzip/znew.1
new file mode 100644
index 0000000..5cfb472
--- /dev/null
+++ b/gnu/usr.bin/gzip/znew.1
@@ -0,0 +1,39 @@
+.TH ZNEW 1
+.SH NAME
+znew \- recompress .Z files to .gz files
+.SH SYNOPSIS
+.B znew
+[ -ftv9PK] [ name.Z ... ]
+.SH DESCRIPTION
+.I Znew
+recompresses files from .Z (compress) format to .gz (gzip) format.
+If you want to recompress a file already in gzip format, rename the file
+to force a .Z extension then apply znew.
+.SH OPTIONS
+.TP
+.B \-f
+Force recompression from .Z to .gz format even if a .gz file already exists.
+.TP
+.B \-t
+Tests the new files before deleting originals.
+.TP
+.B \-v
+Verbose. Display the name and percentage reduction for each file compressed.
+.TP
+.B \-9
+Use the slowest compression method (optimal compression).
+.TP
+.B \-P
+Use pipes for the conversion to reduce disk space usage.
+.TP
+.B \-K
+Keep a .Z file when it is smaller than the .gz file
+.SH "SEE ALSO"
+gzip(1), zmore(1), zdiff(1), zgrep(1), zforce(1), gzexe(1), compress(1)
+.SH BUGS
+.I Znew
+does not maintain the time stamp with the -P option if
+.I cpmod(1)
+is not available and
+.I touch(1)
+does not support the -r option.
diff --git a/gnu/usr.bin/ld/Makefile b/gnu/usr.bin/ld/Makefile
new file mode 100644
index 0000000..132c675
--- /dev/null
+++ b/gnu/usr.bin/ld/Makefile
@@ -0,0 +1,16 @@
+# $Id: Makefile,v 1.16 1994/12/23 22:30:29 nate Exp $
+#
+
+PROG= ld
+SRCS= ld.c symbol.c lib.c shlib.c warnings.c etc.c rrs.c xbits.c md.c
+CFLAGS += -I$(.CURDIR) -I$(.CURDIR)/$(MACHINE)
+LDFLAGS+= -Xlinker -Bstatic
+
+SUBDIR= ldconfig ldd
+.if !defined(NOPIC)
+SUBDIR+= rtld
+.endif
+
+.PATH: $(.CURDIR)/$(MACHINE)
+
+.include <bsd.prog.mk>
diff --git a/gnu/usr.bin/ld/PORTING b/gnu/usr.bin/ld/PORTING
new file mode 100644
index 0000000..fc6f918
--- /dev/null
+++ b/gnu/usr.bin/ld/PORTING
@@ -0,0 +1,192 @@
+$Id$
+
+This document describes some of the machine dependent parts in ld(1) and rtld(?)
+Most of the machine dependencies are a result of different ways in which
+relocation information is conveyed in an architecture's object files.
+Especially RISC architectures are likely candidates to have deviated from the
+traditional relocation record structure due a tendency to use odd sized
+"bitfields" to denote immediate operands within their fixed size instructions.
+
+Also, there may be slight differences in the model used for Position
+Independent Code generation by the compiler.
+
+Lastly, both ld and rtld must fiddle with actual machine instructions to setup
+a transfer vector to accommodate PIC code and dynamic linking.
+
+
+Machine dependent macros and data structures.
+
+typedef struct jmpslot { ... } jmpslot_t;
+
+ The Procedure Linkage Table (PLT) is an array of these structures.
+ The structure contains room for a control transfer instruction
+ and a relocation index. md_make_jmpslot() and md_fix_jmpslot()
+ are responsible for filling these in.
+
+JMPSLOT_NEEDS_RELOC()
+
+ Macro indicating whether or not a jmpslot entry needs a run-time
+ relocation when ld has already resolved the symbolic reference
+ (eg. when `-Bsymbolic' was given). Usually the case if the control
+ transfer instruction is PC relative or something.
+
+RELOC_STATICS_THROUGH_GOT_P(r)
+
+ Predicate taking a `struct relocation_info *' as an argument. It
+ decides whether variables with file scope are addressed relative to
+ the start Global Offset Table (1) or an entry in GOT must be
+ allocated (0). The compiler has a say in this.
+
+
+Some other random macros:
+
+BAD_MID(ex)
+
+ Tells whether the machine ID in an input file header is acceptable.
+
+N_SET_FLAG(ex,f)
+
+ Set flags F in a.out header. Must account for possible non-NetBSD
+ headers; QMAGIC is still a documented ld output format.
+
+N_IS_DYNAMIC(ex)
+
+ Return true if this appears to be a dynamically linked object.
+
+#define relocation_info reloc_info_<machine>
+
+ Define (possibly machine dependent) relocation record format.
+ Should convert to a typedef someday for greater opacity.
+
+md_got_reloc(r)
+
+ Adjustment to be applied to the relocation value of references
+ to "_GLOBAL_OFFSET_TABLE". It's here because of Sun's sparc as(1),
+ (it's is a *bug*), and could have been `#ifdef SUN_COMPAT' if I
+ had not let it slip into NetBSD's gas for compatibility.
+
+md_get_rt_segment_addend(r,a)
+
+ Another SunOS bug workaround.
+
+
+The macros below have defaults defined in ld.h for the traditional relocation
+structure format; each takes a `struct relocation_info *' argument (see
+ld.h for more detailed comments):
+
+RELOC_ADDRESS(r) - the address at which to relocate
+RELOC_EXTERN_P(r) - relocation for external symbol
+RELOC_TYPE(r) - segment (text/data/bss), non-external relocs
+RELOC_SYMBOL(r) - symbol index, external relocs
+RELOC_MEMORY_SUB_P(r) - relocation involves something to subtract
+RELOC_MEMORY_ADD_P(r) - relocation involves something to add
+RELOC_ADD_EXTRA(r) - <disused> (moved into MD files)
+RELOC_PCREL_P(r) - relocation is PC relative
+RELOC_VALUE_RIGHTSHIFT(r) - <disused>
+RELOC_TARGET_SIZE(r) - size (in bytes) of relocated value
+RELOC_TARGET_BITPOS(r) - <disused> (moved into MD files)
+RELOC_TARGET_BITSIZE(r) - <disused> (moved into MD files)
+RELOC_JMPTAB_P(r) - relocation is for a PLT entry
+RELOC_BASEREL_P(r) - relocation is for a GOT entry
+RELOC_RELATIVE_P(r) - relocation is load address relative
+RELOC_COPY_P(r) - relocation involves an initialization
+RELOC_LAZY_P(r) - (run-time) resolution can be lazy.
+CHECK_GOT_RELOC(r) - consistency check on relocations involving
+ the "_GLOBAL_OFFSET_TABLE" symbol
+
+
+
+Things which are currently defined as routines in <machine>/md.c:
+
+
+md_init_header(struct exec *hp, int magic, int flags)
+
+ Initializes the output file header. Straightforward, unless
+ multiple OS'es are supported.
+
+
+md_swap*_exec_hdr(struct exec *)
+
+ Input/output a.out header in target byte-order.
+
+
+md_swap*_reloc(struct relocation_info *, n)
+
+ Input/output N relocation records in target byte-order.
+
+
+md_get_addend(struct relocation_info *rp, char *addr)
+
+ Return a relocation addend. Traditionally found in the object file
+ at address ADDR. The relocation record determines the data width
+ in bytes (using RELOC_TARGET_SIZE()).
+
+md_relocate(struct relocation_info *rp, long reloc, char *addr,
+ int relocatable_output)
+
+ Perform a relocation at the given address, usually by entering
+ the specified value RELOC into the object file. Some architectures
+ may store the relocation in RP when RELOCATABLE_OUTPUT is set.
+ Again, the byte size of the relocation value is determined from
+ RP through RELOC_TARGET_SIZE().
+
+md_make_reloc(struct relocation_info *rp, int type)
+
+ Construct the machine dependent part of a relocation record used
+ for run-time relocation. Sets RP's type field or one or more
+ bitfields according to TYPE which is ld's internal relocation
+ representation of the type of (run-time) relocation. TYPE is a
+ combination of the following bits:
+
+ RELTYPE_EXTERN - relocation is for unresolved symbol
+ RELTYPE_JMPSLOT - relocation is for a PLT entry
+ RELTYPE_BASEREL - <not used>
+ RELTYPE_RELATIVE - relocation is load address relative
+ RELTYPE_COPY - relocation is an initalization
+
+md_make_jmpreloc(struct relocation_info *rp, *r, int type)
+
+ Set up a run-time relocation record pertaining to a jmpslot.
+ This usually sets a bit or a relocation type dedicated to jmpslot
+ relocations. R is the relocation record to be updated (ie. the
+ run-time relocation record), while RP points at the relocation
+ record from the object file on behalf of which we allocated a
+ PLT entry. RP may not be needed.
+
+md_make_gotreloc(struct relocation_info *rp, *r, int type)
+
+ Set up a run-time relocation record pertaining to a GOT entry.
+ This usually sets a bit or a relocation type dedicated to GOT
+ relocations. R is the relocation record to be updated (ie. the
+ run-time relocation record), while RP points at the relocation
+ record from the object file on behalf of which we allocated a
+ GOT entry.
+
+md_make_cpyreloc(struct relocation_info *rp, *r)
+
+ Mark the relocation record as pertaining to a location that needs
+ run-time initializing from some shared object source.
+ R and RP same as above.
+
+md_make_jmpslot(jmpslot_t *sp, long offset, long index)
+
+ Construct a jmpslot, ie. fill in the machine opcodes that comprise
+ a transfer to slot 0 of the PLT. OFFSET is the location of SP
+ relative to the start of the PLT (ie. (int)sp - (int)&PLT[0] ).
+ INDEX is the entry in the run-time relocation record table which
+ determines what symbol this jmpslot is supposed to resolve.
+
+md_fix_jmpslot(jmpslot_t *sp, long offset, long addr)
+
+ Fix up a jmpslot so that it will transfer directly to ADDR
+ in stead of to PLT[0]. OFFSET has the same meaning as in
+ md_make_jmpslot(). This function is called by binder() after
+ it has resolved a symbol into a (run-time) address.
+
+md_set_breakpoint(long where, long *savep)
+
+ Set a breakpoint. Used when run under a debugger. The breakpoint
+ instruction is to be set at location WHERE. The original contents
+ of *WHERE is to be saved in *SAVEP.
+
+
diff --git a/gnu/usr.bin/ld/cplus-dem.c b/gnu/usr.bin/ld/cplus-dem.c
new file mode 100644
index 0000000..27f56ef
--- /dev/null
+++ b/gnu/usr.bin/ld/cplus-dem.c
@@ -0,0 +1,975 @@
+/*-
+ * This code is derived from software copyrighted by the Free Software
+ * Foundation.
+ */
+
+#ifndef lint
+/*static char sccsid[] = "from: @(#)cplus-dem.c 5.4 (Berkeley) 4/30/91";*/
+static char rcsid[] = "$Id: cplus-dem.c,v 1.3 1993/11/09 04:18:51 paul Exp $";
+#endif /* not lint */
+
+/* Demangler for GNU C++
+ Copyright (C) 1989 Free Software Foundation, Inc.
+ written by James Clark (jjc@jclark.uucp)
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 1, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* This is for g++ 1.36.1 (November 6 version). It will probably
+ require changes for any other version.
+
+ Modified for g++ 1.36.2 (November 18 version). */
+
+/* This file exports one function
+
+ char *cplus_demangle (const char *name)
+
+ If `name' is a mangled function name produced by g++, then
+ a pointer to a malloced string giving a C++ representation
+ of the name will be returned; otherwise NULL will be returned.
+ It is the caller's responsibility to free the string which
+ is returned.
+
+ For example,
+
+ cplus_demangle ("_foo__1Ai")
+
+ returns
+
+ "A::foo(int)"
+
+ This file imports xmalloc and xrealloc, which are like malloc and
+ realloc except that they generate a fatal error if there is no
+ available memory. */
+
+/* #define nounderscore 1 /* define this is names don't start with _ */
+
+#include <stdio.h>
+#include <ctype.h>
+
+#ifdef USG
+#include <memory.h>
+#include <string.h>
+#else
+#include <strings.h>
+#define memcpy(s1, s2, n) bcopy ((s2), (s1), (n))
+#define memcmp(s1, s2, n) bcmp ((s2), (s1), (n))
+#define strchr index
+#define strrchr rindex
+#endif
+
+#ifndef __STDC__
+#define const
+#endif
+
+#ifdef __STDC__
+extern char *cplus_demangle (const char *type);
+#else
+extern char *cplus_demangle ();
+#endif
+
+#ifdef __STDC__
+extern char *xmalloc (int);
+extern char *xrealloc (char *, int);
+#else
+extern char *xmalloc ();
+extern char *xrealloc ();
+#endif
+
+static char **typevec = 0;
+static int ntypes = 0;
+static int typevec_size = 0;
+
+static struct {
+ const char *in;
+ const char *out;
+} optable[] = {
+ "new", " new",
+ "delete", " delete",
+ "ne", "!=",
+ "eq", "==",
+ "ge", ">=",
+ "gt", ">",
+ "le", "<=",
+ "lt", "<",
+ "plus", "+",
+ "minus", "-",
+ "mult", "*",
+ "convert", "+", /* unary + */
+ "negate", "-", /* unary - */
+ "trunc_mod", "%",
+ "trunc_div", "/",
+ "truth_andif", "&&",
+ "truth_orif", "||",
+ "truth_not", "!",
+ "postincrement", "++",
+ "postdecrement", "--",
+ "bit_ior", "|",
+ "bit_xor", "^",
+ "bit_and", "&",
+ "bit_not", "~",
+ "call", "()",
+ "cond", "?:",
+ "alshift", "<<",
+ "arshift", ">>",
+ "component", "->",
+ "indirect", "*",
+ "method_call", "->()",
+ "addr", "&", /* unary & */
+ "array", "[]",
+ "nop", "", /* for operator= */
+};
+
+/* Beware: these aren't '\0' terminated. */
+
+typedef struct {
+ char *b; /* pointer to start of string */
+ char *p; /* pointer after last character */
+ char *e; /* pointer after end of allocated space */
+} string;
+
+#ifdef __STDC__
+static void string_need (string *s, int n);
+static void string_delete (string *s);
+static void string_init (string *s);
+static void string_clear (string *s);
+static int string_empty (string *s);
+static void string_append (string *p, const char *s);
+static void string_appends (string *p, string *s);
+static void string_appendn (string *p, const char *s, int n);
+static void string_prepend (string *p, const char *s);
+#if 0
+static void string_prepends (string *p, string *s);
+#endif
+static void string_prependn (string *p, const char *s, int n);
+static int get_count (const char **type, int *count);
+static int do_args (const char **type, string *decl);
+static int do_type (const char **type, string *result);
+static int do_arg (const char **type, string *result);
+static int do_args (const char **type, string *decl);
+static void munge_function_name (string *name);
+static void remember_type (const char *type, int len);
+#else
+static void string_need ();
+static void string_delete ();
+static void string_init ();
+static void string_clear ();
+static int string_empty ();
+static void string_append ();
+static void string_appends ();
+static void string_appendn ();
+static void string_prepend ();
+static void string_prepends ();
+static void string_prependn ();
+static int get_count ();
+static int do_args ();
+static int do_type ();
+static int do_arg ();
+static int do_args ();
+static void munge_function_name ();
+static void remember_type ();
+#endif
+
+char *
+cplus_demangle (type)
+ const char *type;
+{
+ string decl;
+ int n;
+ int success = 0;
+ int constructor = 0;
+ int const_flag = 0;
+ int i;
+ const char *p;
+#ifndef LONGERNAMES
+ const char *premangle;
+#endif
+
+ if (type == NULL || *type == '\0')
+ return NULL;
+#ifndef nounderscore
+ if (*type++ != '_')
+ return NULL;
+#endif
+ p = type;
+ while (*p != '\0' && !(*p == '_' && p[1] == '_'))
+ p++;
+ if (*p == '\0')
+ {
+ /* destructor */
+ if (type[0] == '_' && type[1] == '$' && type[2] == '_')
+ {
+ int n = (strlen (type) - 3)*2 + 3 + 2 + 1;
+ char *tem = (char *) xmalloc (n);
+ strcpy (tem, type + 3);
+ strcat (tem, "::~");
+ strcat (tem, type + 3);
+ strcat (tem, "()");
+ return tem;
+ }
+ /* static data member */
+ if (*type != '_' && (p = strchr (type, '$')) != NULL)
+ {
+ int n = strlen (type) + 2;
+ char *tem = (char *) xmalloc (n);
+ memcpy (tem, type, p - type);
+ strcpy (tem + (p - type), "::");
+ strcpy (tem + (p - type) + 2, p + 1);
+ return tem;
+ }
+ /* virtual table */
+ if (type[0] == '_' && type[1] == 'v' && type[2] == 't' && type[3] == '$')
+ {
+ int n = strlen (type + 4) + 14 + 1;
+ char *tem = (char *) xmalloc (n);
+ strcpy (tem, type + 4);
+ strcat (tem, " virtual table");
+ return tem;
+ }
+ return NULL;
+ }
+
+ string_init (&decl);
+
+ if (p == type)
+ {
+ if (!isdigit (p[2]))
+ {
+ string_delete (&decl);
+ return NULL;
+ }
+ constructor = 1;
+ }
+ else
+ {
+ string_appendn (&decl, type, p - type);
+ munge_function_name (&decl);
+ }
+ p += 2;
+
+#ifndef LONGERNAMES
+ premangle = p;
+#endif
+ switch (*p)
+ {
+ case 'C':
+ /* a const member function */
+ if (!isdigit (p[1]))
+ {
+ string_delete (&decl);
+ return NULL;
+ }
+ p += 1;
+ const_flag = 1;
+ /* fall through */
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ n = 0;
+ do
+ {
+ n *= 10;
+ n += *p - '0';
+ p += 1;
+ }
+ while (isdigit (*p));
+ if (strlen (p) < n)
+ {
+ string_delete (&decl);
+ return NULL;
+ }
+ if (constructor)
+ {
+ string_appendn (&decl, p, n);
+ string_append (&decl, "::");
+ string_appendn (&decl, p, n);
+ }
+ else
+ {
+ string_prepend (&decl, "::");
+ string_prependn (&decl, p, n);
+ }
+ p += n;
+#ifndef LONGERNAMES
+ remember_type (premangle, p - premangle);
+#endif
+ success = do_args (&p, &decl);
+ if (const_flag)
+ string_append (&decl, " const");
+ break;
+ case 'F':
+ p += 1;
+ success = do_args (&p, &decl);
+ break;
+ }
+
+ for (i = 0; i < ntypes; i++)
+ if (typevec[i] != NULL)
+ free (typevec[i]);
+ ntypes = 0;
+ if (typevec != NULL)
+ {
+ free ((char *)typevec);
+ typevec = NULL;
+ typevec_size = 0;
+ }
+
+ if (success)
+ {
+ string_appendn (&decl, "", 1);
+ return decl.b;
+ }
+ else
+ {
+ string_delete (&decl);
+ return NULL;
+ }
+}
+
+static int
+get_count (type, count)
+ const char **type;
+ int *count;
+{
+ if (!isdigit (**type))
+ return 0;
+ *count = **type - '0';
+ *type += 1;
+ /* see flush_repeats in cplus-method.c */
+ if (isdigit (**type))
+ {
+ const char *p = *type;
+ int n = *count;
+ do
+ {
+ n *= 10;
+ n += *p - '0';
+ p += 1;
+ }
+ while (isdigit (*p));
+ if (*p == '_')
+ {
+ *type = p + 1;
+ *count = n;
+ }
+ }
+ return 1;
+}
+
+/* result will be initialised here; it will be freed on failure */
+
+static int
+do_type (type, result)
+ const char **type;
+ string *result;
+{
+ int n;
+ int done;
+ int non_empty = 0;
+ int success;
+ string decl;
+ const char *remembered_type;
+
+ string_init (&decl);
+ string_init (result);
+
+ done = 0;
+ success = 1;
+ while (success && !done)
+ {
+ int member;
+ switch (**type)
+ {
+ case 'P':
+ *type += 1;
+ string_prepend (&decl, "*");
+ break;
+
+ case 'R':
+ *type += 1;
+ string_prepend (&decl, "&");
+ break;
+
+ case 'T':
+ *type += 1;
+ if (!get_count (type, &n) || n >= ntypes)
+ success = 0;
+ else
+ {
+ remembered_type = typevec[n];
+ type = &remembered_type;
+ }
+ break;
+
+ case 'F':
+ *type += 1;
+ if (!string_empty (&decl) && decl.b[0] == '*')
+ {
+ string_prepend (&decl, "(");
+ string_append (&decl, ")");
+ }
+ if (!do_args (type, &decl) || **type != '_')
+ success = 0;
+ else
+ *type += 1;
+ break;
+
+ case 'M':
+ case 'O':
+ {
+ int constp = 0;
+ int volatilep = 0;
+
+ member = **type == 'M';
+ *type += 1;
+ if (!isdigit (**type))
+ {
+ success = 0;
+ break;
+ }
+ n = 0;
+ do
+ {
+ n *= 10;
+ n += **type - '0';
+ *type += 1;
+ }
+ while (isdigit (**type));
+ if (strlen (*type) < n)
+ {
+ success = 0;
+ break;
+ }
+ string_append (&decl, ")");
+ string_prepend (&decl, "::");
+ string_prependn (&decl, *type, n);
+ string_prepend (&decl, "(");
+ *type += n;
+ if (member)
+ {
+ if (**type == 'C')
+ {
+ *type += 1;
+ constp = 1;
+ }
+ if (**type == 'V')
+ {
+ *type += 1;
+ volatilep = 1;
+ }
+ if (*(*type)++ != 'F')
+ {
+ success = 0;
+ break;
+ }
+ }
+ if ((member && !do_args (type, &decl)) || **type != '_')
+ {
+ success = 0;
+ break;
+ }
+ *type += 1;
+ if (constp)
+ {
+ if (non_empty)
+ string_append (&decl, " ");
+ else
+ non_empty = 1;
+ string_append (&decl, "const");
+ }
+ if (volatilep)
+ {
+ if (non_empty)
+ string_append (&decl, " ");
+ else
+ non_empty = 1;
+ string_append (&decl, "volatilep");
+ }
+ break;
+ }
+
+ case 'C':
+ if ((*type)[1] == 'P')
+ {
+ *type += 1;
+ if (!string_empty (&decl))
+ string_prepend (&decl, " ");
+ string_prepend (&decl, "const");
+ break;
+ }
+
+ /* fall through */
+ default:
+ done = 1;
+ break;
+ }
+ }
+
+ done = 0;
+ non_empty = 0;
+ while (success && !done)
+ {
+ switch (**type)
+ {
+ case 'C':
+ *type += 1;
+ if (non_empty)
+ string_append (result, " ");
+ else
+ non_empty = 1;
+ string_append (result, "const");
+ break;
+ case 'U':
+ *type += 1;
+ if (non_empty)
+ string_append (result, " ");
+ else
+ non_empty = 1;
+ string_append (result, "unsigned");
+ break;
+ case 'V':
+ *type += 1;
+ if (non_empty)
+ string_append (result, " ");
+ else
+ non_empty = 1;
+ string_append (result, "volatile");
+ break;
+ default:
+ done = 1;
+ break;
+ }
+ }
+
+ if (success)
+ switch (**type)
+ {
+ case '\0':
+ case '_':
+ break;
+ case 'v':
+ *type += 1;
+ if (non_empty)
+ string_append (result, " ");
+ string_append (result, "void");
+ break;
+ case 'x':
+ *type += 1;
+ if (non_empty)
+ string_append (result, " ");
+ string_append (result, "long long");
+ break;
+ case 'l':
+ *type += 1;
+ if (non_empty)
+ string_append (result, " ");
+ string_append (result, "long");
+ break;
+ case 'i':
+ *type += 1;
+ if (non_empty)
+ string_append (result, " ");
+ string_append (result, "int");
+ break;
+ case 's':
+ *type += 1;
+ if (non_empty)
+ string_append (result, " ");
+ string_append (result, "short");
+ break;
+ case 'c':
+ *type += 1;
+ if (non_empty)
+ string_append (result, " ");
+ string_append (result, "char");
+ break;
+ case 'r':
+ *type += 1;
+ if (non_empty)
+ string_append (result, " ");
+ string_append (result, "long double");
+ break;
+ case 'd':
+ *type += 1;
+ if (non_empty)
+ string_append (result, " ");
+ string_append (result, "double");
+ break;
+ case 'f':
+ *type += 1;
+ if (non_empty)
+ string_append (result, " ");
+ string_append (result, "float");
+ break;
+ case 'G':
+ *type += 1;
+ if (!isdigit (**type))
+ {
+ success = 0;
+ break;
+ }
+ /* fall through */
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ n = 0;
+ do
+ {
+ n *= 10;
+ n += **type - '0';
+ *type += 1;
+ }
+ while (isdigit (**type));
+ if (strlen (*type) < n)
+ {
+ success = 0;
+ break;
+ }
+ if (non_empty)
+ string_append (result, " ");
+ string_appendn (result, *type, n);
+ *type += n;
+ break;
+ default:
+ success = 0;
+ break;
+ }
+
+ if (success)
+ {
+ if (!string_empty (&decl))
+ {
+ string_append (result, " ");
+ string_appends (result, &decl);
+ }
+ string_delete (&decl);
+ return 1;
+ }
+ else
+ {
+ string_delete (&decl);
+ string_delete (result);
+ return 0;
+ }
+}
+
+/* `result' will be initialised in do_type; it will be freed on failure */
+
+static int
+do_arg (type, result)
+ const char **type;
+ string *result;
+{
+ const char *start = *type;
+
+ if (!do_type (type, result))
+ return 0;
+ remember_type (start, *type - start);
+ return 1;
+}
+
+static void
+remember_type (start, len)
+ const char *start;
+ int len;
+{
+ char *tem;
+
+ if (ntypes >= typevec_size)
+ {
+ if (typevec_size == 0)
+ {
+ typevec_size = 3;
+ typevec = (char **) xmalloc (sizeof (char*)*typevec_size);
+ }
+ else
+ {
+ typevec_size *= 2;
+ typevec = (char **) xrealloc ((char *)typevec, sizeof (char*)*typevec_size);
+ }
+ }
+ tem = (char *) xmalloc (len + 1);
+ memcpy (tem, start, len);
+ tem[len] = '\0';
+ typevec[ntypes++] = tem;
+}
+
+/* `decl' must be already initialised, usually non-empty;
+ it won't be freed on failure */
+
+static int
+do_args (type, decl)
+ const char **type;
+ string *decl;
+{
+ string arg;
+ int need_comma = 0;
+
+ string_append (decl, "(");
+
+ while (**type != '_' && **type != '\0' && **type != 'e' && **type != 'v')
+ {
+ if (**type == 'N')
+ {
+ int r;
+ int t;
+ *type += 1;
+ if (!get_count (type, &r) || !get_count (type, &t) || t >= ntypes)
+ return 0;
+ while (--r >= 0)
+ {
+ const char *tem = typevec[t];
+ if (need_comma)
+ string_append (decl, ", ");
+ if (!do_arg (&tem, &arg))
+ return 0;
+ string_appends (decl, &arg);
+ string_delete (&arg);
+ need_comma = 1;
+ }
+ }
+ else
+ {
+ if (need_comma)
+ string_append (decl, ", ");
+ if (!do_arg (type, &arg))
+ return 0;
+ string_appends (decl, &arg);
+ string_delete (&arg);
+ need_comma = 1;
+ }
+ }
+
+ if (**type == 'v')
+ *type += 1;
+ else if (**type == 'e')
+ {
+ *type += 1;
+ if (need_comma)
+ string_append (decl, ",");
+ string_append (decl, "...");
+ }
+
+ string_append (decl, ")");
+ return 1;
+}
+
+static void
+munge_function_name (name)
+ string *name;
+{
+ if (!string_empty (name) && name->p - name->b >= 3
+ && name->b[0] == 'o' && name->b[1] == 'p' && name->b[2] == '$')
+ {
+ int i;
+ /* see if it's an assignment expression */
+ if (name->p - name->b >= 10 /* op$assign_ */
+ && memcmp (name->b + 3, "assign_", 7) == 0)
+ {
+ for (i = 0; i < sizeof (optable)/sizeof (optable[0]); i++)
+ {
+ int len = name->p - name->b - 10;
+ if (strlen (optable[i].in) == len
+ && memcmp (optable[i].in, name->b + 10, len) == 0)
+ {
+ string_clear (name);
+ string_append (name, "operator");
+ string_append (name, optable[i].out);
+ string_append (name, "=");
+ return;
+ }
+ }
+ }
+ else
+ {
+ for (i = 0; i < sizeof (optable)/sizeof (optable[0]); i++)
+ {
+ int len = name->p - name->b - 3;
+ if (strlen (optable[i].in) == len
+ && memcmp (optable[i].in, name->b + 3, len) == 0)
+ {
+ string_clear (name);
+ string_append (name, "operator");
+ string_append (name, optable[i].out);
+ return;
+ }
+ }
+ }
+ return;
+ }
+ else if (!string_empty (name) && name->p - name->b >= 5
+ && memcmp (name->b, "type$", 5) == 0)
+ {
+ /* type conversion operator */
+ string type;
+ const char *tem = name->b + 5;
+ if (do_type (&tem, &type))
+ {
+ string_clear (name);
+ string_append (name, "operator ");
+ string_appends (name, &type);
+ string_delete (&type);
+ return;
+ }
+ }
+}
+
+/* a mini string-handling package */
+
+static void
+string_need (s, n)
+ string *s;
+ int n;
+{
+ if (s->b == NULL)
+ {
+ if (n < 32)
+ n = 32;
+ s->p = s->b = (char *) xmalloc (n);
+ s->e = s->b + n;
+ }
+ else if (s->e - s->p < n)
+ {
+ int tem = s->p - s->b;
+ n += tem;
+ n *= 2;
+ s->b = (char *) xrealloc (s->b, n);
+ s->p = s->b + tem;
+ s->e = s->b + n;
+ }
+}
+
+static void
+string_delete (s)
+ string *s;
+{
+ if (s->b != NULL)
+ {
+ free (s->b);
+ s->b = s->e = s->p = NULL;
+ }
+}
+
+static void
+string_init (s)
+ string *s;
+{
+ s->b = s->p = s->e = NULL;
+}
+
+static void
+string_clear (s)
+ string *s;
+{
+ s->p = s->b;
+}
+
+static int
+string_empty (s)
+ string *s;
+{
+ return s->b == s->p;
+}
+
+static void
+string_append (p, s)
+ string *p;
+ const char *s;
+{
+ int n;
+ if (s == NULL || *s == '\0')
+ return;
+ n = strlen (s);
+ string_need (p, n);
+ memcpy (p->p, s, n);
+ p->p += n;
+}
+
+static void
+string_appends (p, s)
+ string *p, *s;
+{
+ int n;
+ if (s->b == s->p)
+ return;
+ n = s->p - s->b;
+ string_need (p, n);
+ memcpy (p->p, s->b, n);
+ p->p += n;
+}
+
+static void
+string_appendn (p, s, n)
+ string *p;
+ const char *s;
+ int n;
+{
+ if (n == 0)
+ return;
+ string_need (p, n);
+ memcpy (p->p, s, n);
+ p->p += n;
+}
+
+static void
+string_prepend (p, s)
+ string *p;
+ const char *s;
+{
+ if (s == NULL || *s == '\0')
+ return;
+ string_prependn (p, s, strlen (s));
+}
+
+#if 0
+static void
+string_prepends (p, s)
+ string *p, *s;
+{
+ if (s->b == s->p)
+ return;
+ string_prependn (p, s->b, s->p - s->b);
+}
+#endif
+
+static void
+string_prependn (p, s, n)
+ string *p;
+ const char *s;
+ int n;
+{
+ char *q;
+
+ if (n == 0)
+ return;
+ string_need (p, n);
+ for (q = p->p - 1; q >= p->b; q--)
+ q[n] = q[0];
+ memcpy (p->b, s, n);
+ p->p += n;
+}
diff --git a/gnu/usr.bin/ld/etc.c b/gnu/usr.bin/ld/etc.c
new file mode 100644
index 0000000..59e0a18
--- /dev/null
+++ b/gnu/usr.bin/ld/etc.c
@@ -0,0 +1,66 @@
+/*
+ * $Id: etc.c,v 1.7 1994/02/13 20:41:05 jkh Exp $
+ */
+
+#include <err.h>
+#include <stdlib.h>
+#include <string.h>
+
+/*
+ * Like malloc but get fatal error if memory is exhausted.
+ */
+void *
+xmalloc(size)
+ size_t size;
+{
+ register void *result = (void *)malloc(size);
+
+ if (!result)
+ errx(1, "virtual memory exhausted");
+
+ return result;
+}
+
+/*
+ * Like realloc but get fatal error if memory is exhausted.
+ */
+void *
+xrealloc(ptr, size)
+ void *ptr;
+ size_t size;
+{
+ register void *result;
+
+ if (ptr == NULL)
+ result = (void *)malloc(size);
+ else
+ result = (void *)realloc(ptr, size);
+
+ if (!result)
+ errx(1, "virtual memory exhausted");
+
+ return result;
+}
+
+/*
+ * Return a newly-allocated string whose contents concatenate
+ * the strings S1, S2, S3.
+ */
+char *
+concat(s1, s2, s3)
+ const char *s1, *s2, *s3;
+{
+ register int len1 = strlen(s1),
+ len2 = strlen(s2),
+ len3 = strlen(s3);
+
+ register char *result = (char *)xmalloc(len1 + len2 + len3 + 1);
+
+ strcpy(result, s1);
+ strcpy(result + len1, s2);
+ strcpy(result + len1 + len2, s3);
+ result[len1 + len2 + len3] = 0;
+
+ return result;
+}
+
diff --git a/gnu/usr.bin/ld/i386/md-static-funcs.c b/gnu/usr.bin/ld/i386/md-static-funcs.c
new file mode 100644
index 0000000..64491e3
--- /dev/null
+++ b/gnu/usr.bin/ld/i386/md-static-funcs.c
@@ -0,0 +1,16 @@
+/*
+ * $Id: md-static-funcs.c,v 1.2 1994/02/13 20:42:06 jkh Exp $
+ *
+ * Called by ld.so when onanating.
+ * This *must* be a static function, so it is not called through a jmpslot.
+ */
+
+static inline void
+md_relocate_simple(r, relocation, addr)
+struct relocation_info *r;
+long relocation;
+char *addr;
+{
+ *(long *)addr += relocation;
+}
+
diff --git a/gnu/usr.bin/ld/i386/md.c b/gnu/usr.bin/ld/i386/md.c
new file mode 100644
index 0000000..07271fc
--- /dev/null
+++ b/gnu/usr.bin/ld/i386/md.c
@@ -0,0 +1,360 @@
+/*
+ * 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: md.c,v 1.11 1994/12/23 22:31:12 nate Exp $
+ */
+
+#include <sys/param.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <err.h>
+#include <fcntl.h>
+#include <a.out.h>
+#include <stab.h>
+#include <string.h>
+
+#include "ld.h"
+
+/*
+ * Get relocation addend corresponding to relocation record RP
+ * from address ADDR
+ */
+long
+md_get_addend(rp, addr)
+struct relocation_info *rp;
+unsigned char *addr;
+{
+ switch (RELOC_TARGET_SIZE(rp)) {
+ case 0:
+ return get_byte(addr);
+ case 1:
+ return get_short(addr);
+ case 2:
+ return get_long(addr);
+ default:
+ errx(1, "Unsupported relocation size: %x",
+ RELOC_TARGET_SIZE(rp));
+ }
+}
+
+/*
+ * Put RELOCATION at ADDR according to relocation record RP.
+ */
+void
+md_relocate(rp, relocation, addr, relocatable_output)
+struct relocation_info *rp;
+long relocation;
+unsigned char *addr;
+int relocatable_output;
+{
+ switch (RELOC_TARGET_SIZE(rp)) {
+ case 0:
+ put_byte(addr, relocation);
+ break;
+ case 1:
+ put_short(addr, relocation);
+ break;
+ case 2:
+ put_long(addr, relocation);
+ break;
+ default:
+ errx(1, "Unsupported relocation size: %x",
+ RELOC_TARGET_SIZE(rp));
+ }
+}
+
+/*
+ * Machine dependent part of claim_rrs_reloc().
+ * Set RRS relocation type.
+ */
+int
+md_make_reloc(rp, r, type)
+struct relocation_info *rp, *r;
+int type;
+{
+ /* Relocation size */
+ r->r_length = rp->r_length;
+
+ if (RELOC_PCREL_P(rp))
+ r->r_pcrel = 1;
+
+ if (type & RELTYPE_RELATIVE)
+ r->r_relative = 1;
+
+ if (type & RELTYPE_COPY)
+ r->r_copy = 1;
+
+ return 0;
+}
+
+/*
+ * Set up a transfer from jmpslot at OFFSET (relative to the PLT table)
+ * to the binder slot (which is at offset 0 of the PLT).
+ */
+void
+md_make_jmpslot(sp, offset, index)
+jmpslot_t *sp;
+long offset;
+long index;
+{
+ /*
+ * i386 PC-relative "fixed point" is located right after the
+ * instruction it pertains to.
+ */
+ u_long fudge = - (sizeof(sp->opcode) + sizeof(sp->addr) + offset);
+
+ sp->opcode = CALL;
+#if 0
+ sp->addr = fudge;
+#else
+ sp->addr[0] = fudge & 0xffff;
+ sp->addr[1] = fudge >> 16;
+#endif
+ sp->reloc_index = index;
+}
+
+/*
+ * Set up a "direct" transfer (ie. not through the run-time binder) from
+ * jmpslot at OFFSET to ADDR. Used by `ld' when the SYMBOLIC flag is on,
+ * and by `ld.so' after resolving the symbol.
+ * On the i386, we use the JMP instruction which is PC relative, so no
+ * further RRS relocations will be necessary for such a jmpslot.
+ */
+void
+md_fix_jmpslot(sp, offset, addr)
+jmpslot_t *sp;
+long offset;
+u_long addr;
+{
+ u_long fudge = addr - (sizeof(sp->opcode) + sizeof(sp->addr) + offset);
+
+ sp->opcode = JUMP;
+#if 0
+ sp->addr = fudge;
+#else
+ sp->addr[0] = fudge & 0xffff;
+ sp->addr[1] = fudge >> 16;
+#endif
+ sp->reloc_index = 0;
+}
+
+/*
+ * Update the relocation record for a RRS jmpslot.
+ */
+void
+md_make_jmpreloc(rp, r, type)
+struct relocation_info *rp, *r;
+int type;
+{
+ jmpslot_t *sp;
+
+ /*
+ * Fix relocation address to point to the correct
+ * location within this jmpslot.
+ */
+ r->r_address += sizeof(sp->opcode);
+
+ /* Relocation size */
+ r->r_length = 2;
+
+ /* Set relocation type */
+ r->r_jmptable = 1;
+ if (type & RELTYPE_RELATIVE)
+ r->r_relative = 1;
+
+}
+
+/*
+ * Set relocation type for a RRS GOT relocation.
+ */
+void
+md_make_gotreloc(rp, r, type)
+struct relocation_info *rp, *r;
+int type;
+{
+ r->r_baserel = 1;
+ if (type & RELTYPE_RELATIVE)
+ r->r_relative = 1;
+
+ /* Relocation size */
+ r->r_length = 2;
+}
+
+/*
+ * Set relocation type for a RRS copy operation.
+ */
+void
+md_make_cpyreloc(rp, r)
+struct relocation_info *rp, *r;
+{
+ /* Relocation size */
+ r->r_length = 2;
+
+ r->r_copy = 1;
+}
+
+void
+md_set_breakpoint(where, savep)
+long where;
+long *savep;
+{
+ *savep = *(long *)where;
+ *(char *)where = TRAP;
+}
+
+#ifndef RTLD
+
+#ifdef __FreeBSD__
+int netzmagic;
+#endif
+
+/*
+ * Initialize (output) exec header such that useful values are
+ * obtained from subsequent N_*() macro evaluations.
+ */
+void
+md_init_header(hp, magic, flags)
+struct exec *hp;
+int magic, flags;
+{
+#ifdef NetBSD
+ if (oldmagic || magic == QMAGIC)
+ hp->a_midmag = magic;
+ else
+ N_SETMAGIC((*hp), magic, MID_I386, flags);
+#endif
+#ifdef __FreeBSD__
+ if (oldmagic)
+ hp->a_midmag = magic;
+ else if (netzmagic)
+ N_SETMAGIC_NET((*hp), magic, MID_I386, flags);
+ else
+ N_SETMAGIC((*hp), magic, MID_I386, flags);
+#endif
+
+ /* TEXT_START depends on the value of outheader.a_entry. */
+ if (!(link_mode & SHAREABLE))
+ hp->a_entry = PAGSIZ;
+}
+#endif /* RTLD */
+
+
+#ifdef NEED_SWAP
+/*
+ * Byte swap routines for cross-linking.
+ */
+
+void
+md_swapin_exec_hdr(h)
+struct exec *h;
+{
+ int skip = 0;
+
+ if (!N_BADMAG(*h))
+ skip = 1;
+
+ swap_longs((long *)h + skip, sizeof(*h)/sizeof(long) - skip);
+}
+
+void
+md_swapout_exec_hdr(h)
+struct exec *h;
+{
+ /* NetBSD: Always leave magic alone */
+ int skip = 1;
+#if 0
+ if (N_GETMAGIC(*h) == OMAGIC)
+ skip = 0;
+#endif
+
+ swap_longs((long *)h + skip, sizeof(*h)/sizeof(long) - skip);
+}
+
+
+void
+md_swapin_reloc(r, n)
+struct relocation_info *r;
+int n;
+{
+ int bits;
+
+ for (; n; n--, r++) {
+ r->r_address = md_swap_long(r->r_address);
+ bits = ((int *)r)[1];
+ r->r_symbolnum = md_swap_long(bits) & 0x00ffffff;
+ r->r_pcrel = (bits & 1);
+ r->r_length = (bits >> 1) & 3;
+ r->r_extern = (bits >> 3) & 1;
+ r->r_baserel = (bits >> 4) & 1;
+ r->r_jmptable = (bits >> 5) & 1;
+ r->r_relative = (bits >> 6) & 1;
+#ifdef N_SIZE
+ r->r_copy = (bits >> 7) & 1;
+#endif
+ }
+}
+
+void
+md_swapout_reloc(r, n)
+struct relocation_info *r;
+int n;
+{
+ int bits;
+
+ for (; n; n--, r++) {
+ r->r_address = md_swap_long(r->r_address);
+ bits = md_swap_long(r->r_symbolnum) & 0xffffff00;
+ bits |= (r->r_pcrel & 1);
+ bits |= (r->r_length & 3) << 1;
+ bits |= (r->r_extern & 1) << 3;
+ bits |= (r->r_baserel & 1) << 4;
+ bits |= (r->r_jmptable & 1) << 5;
+ bits |= (r->r_relative & 1) << 6;
+#ifdef N_SIZE
+ bits |= (r->r_copy & 1) << 7;
+#endif
+ ((int *)r)[1] = bits;
+ }
+}
+
+void
+md_swapout_jmpslot(j, n)
+jmpslot_t *j;
+int n;
+{
+ for (; n; n--, j++) {
+ j->opcode = md_swap_short(j->opcode);
+ j->addr[0] = md_swap_short(j->addr[0]);
+ j->addr[1] = md_swap_short(j->addr[1]);
+ j->reloc_index = md_swap_short(j->reloc_index);
+ }
+}
+
+#endif /* NEED_SWAP */
diff --git a/gnu/usr.bin/ld/i386/md.h b/gnu/usr.bin/ld/i386/md.h
new file mode 100644
index 0000000..da5283d
--- /dev/null
+++ b/gnu/usr.bin/ld/i386/md.h
@@ -0,0 +1,226 @@
+/*
+ * 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: md.h,v 1.11 1994/12/23 22:31:14 nate Exp $
+ */
+
+
+#if defined(CROSS_LINKER) && defined(XHOST) && XHOST==sparc
+#define NEED_SWAP
+#endif
+
+#define MAX_ALIGNMENT (sizeof (long))
+
+#ifdef NetBSD
+#define PAGSIZ __LDPGSZ
+#else
+#define PAGSIZ 4096
+#endif
+
+#if defined(NetBSD) || defined(CROSS_LINKER)
+
+#define N_SET_FLAG(ex,f) (oldmagic || N_GETMAGIC(ex)==QMAGIC ? (0) : \
+ N_SETMAGIC(ex, \
+ N_GETMAGIC(ex), \
+ MID_MACHINE, \
+ N_GETFLAG(ex)|(f)))
+
+#define N_IS_DYNAMIC(ex) ((N_GETFLAG(ex) & EX_DYNAMIC))
+
+#define N_BADMID(ex) \
+ (N_GETMID(ex) != 0 && N_GETMID(ex) != MID_MACHINE)
+
+#endif
+
+/*
+ * FreeBSD does it differently
+ */
+#ifdef __FreeBSD__
+#define N_SET_FLAG(ex,f) (oldmagic ? (0) : \
+ (netzmagic == 0 ? \
+ N_SETMAGIC(ex, \
+ N_GETMAGIC(ex), \
+ MID_MACHINE, \
+ N_GETFLAG(ex)|(f)) : \
+ N_SETMAGIC_NET(ex, \
+ N_GETMAGIC_NET(ex), \
+ MID_MACHINE, \
+ N_GETFLAG_NET(ex)|(f)) ))
+
+#define N_IS_DYNAMIC(ex) ((N_GETMAGIC_NET(ex) == ZMAGIC) ? \
+ ((N_GETFLAG_NET(ex) & EX_DYNAMIC)) : \
+ ((N_GETFLAG(ex) & EX_DYNAMIC) ))
+#define N_BADMID(ex) 0
+#endif
+
+/*
+ * Should be handled by a.out.h ?
+ */
+#define N_ADJUST(ex) (((ex).a_entry < PAGSIZ) ? -PAGSIZ : 0)
+#define TEXT_START(ex) (N_TXTADDR(ex) + N_ADJUST(ex))
+#define DATA_START(ex) (N_DATADDR(ex) + N_ADJUST(ex))
+
+#define RELOC_STATICS_THROUGH_GOT_P(r) (0)
+#define JMPSLOT_NEEDS_RELOC (0)
+
+#define md_got_reloc(r) (0)
+
+#define md_get_rt_segment_addend(r,a) md_get_addend(r,a)
+
+/* Width of a Global Offset Table entry */
+#define GOT_ENTRY_SIZE 4
+typedef long got_t;
+
+typedef struct jmpslot {
+ u_short opcode;
+ u_short addr[2];
+ u_short reloc_index;
+#define JMPSLOT_RELOC_MASK 0xffff
+} jmpslot_t;
+
+#define NOP 0x90
+#define CALL 0xe890 /* NOP + CALL opcode */
+#define JUMP 0xe990 /* NOP + JMP opcode */
+#define TRAP 0xcc /* INT 3 */
+
+/*
+ * Byte swap defs for cross linking
+ */
+
+#if !defined(NEED_SWAP)
+
+#define md_swapin_exec_hdr(h)
+#define md_swapout_exec_hdr(h)
+#define md_swapin_symbols(s,n)
+#define md_swapout_symbols(s,n)
+#define md_swapin_zsymbols(s,n)
+#define md_swapout_zsymbols(s,n)
+#define md_swapin_reloc(r,n)
+#define md_swapout_reloc(r,n)
+#define md_swapin__dynamic(l)
+#define md_swapout__dynamic(l)
+#define md_swapin_section_dispatch_table(l)
+#define md_swapout_section_dispatch_table(l)
+#define md_swapin_so_debug(d)
+#define md_swapout_so_debug(d)
+#define md_swapin_rrs_hash(f,n)
+#define md_swapout_rrs_hash(f,n)
+#define md_swapin_sod(l,n)
+#define md_swapout_sod(l,n)
+#define md_swapout_jmpslot(j,n)
+#define md_swapout_got(g,n)
+#define md_swapin_ranlib_hdr(h,n)
+#define md_swapout_ranlib_hdr(h,n)
+
+#endif /* NEED_SWAP */
+
+#ifdef CROSS_LINKER
+
+#define get_byte(p) ( ((unsigned char *)(p))[0] )
+
+#define get_short(p) ( ( ((unsigned char *)(p))[0] << 8) | \
+ ( ((unsigned char *)(p))[1] ) \
+ )
+
+#define get_long(p) ( ( ((unsigned char *)(p))[0] << 24) | \
+ ( ((unsigned char *)(p))[1] << 16) | \
+ ( ((unsigned char *)(p))[2] << 8 ) | \
+ ( ((unsigned char *)(p))[3] ) \
+ )
+
+#define put_byte(p, v) { ((unsigned char *)(p))[0] = ((unsigned long)(v)); }
+
+#define put_short(p, v) { ((unsigned char *)(p))[0] = \
+ ((((unsigned long)(v)) >> 8) & 0xff); \
+ ((unsigned char *)(p))[1] = \
+ ((((unsigned long)(v)) ) & 0xff); }
+
+#define put_long(p, v) { ((unsigned char *)(p))[0] = \
+ ((((unsigned long)(v)) >> 24) & 0xff); \
+ ((unsigned char *)(p))[1] = \
+ ((((unsigned long)(v)) >> 16) & 0xff); \
+ ((unsigned char *)(p))[2] = \
+ ((((unsigned long)(v)) >> 8) & 0xff); \
+ ((unsigned char *)(p))[3] = \
+ ((((unsigned long)(v)) ) & 0xff); }
+
+#ifdef NEED_SWAP
+
+/* Define IO byte swapping routines */
+
+void md_swapin_exec_hdr __P((struct exec *));
+void md_swapout_exec_hdr __P((struct exec *));
+void md_swapin_reloc __P((struct relocation_info *, int));
+void md_swapout_reloc __P((struct relocation_info *, int));
+void md_swapout_jmpslot __P((jmpslot_t *, int));
+
+#define md_swapin_symbols(s,n) swap_symbols(s,n)
+#define md_swapout_symbols(s,n) swap_symbols(s,n)
+#define md_swapin_zsymbols(s,n) swap_zsymbols(s,n)
+#define md_swapout_zsymbols(s,n) swap_zsymbols(s,n)
+#define md_swapin__dynamic(l) swap__dynamic(l)
+#define md_swapout__dynamic(l) swap__dynamic(l)
+#define md_swapin_section_dispatch_table(l) swap_section_dispatch_table(l)
+#define md_swapout_section_dispatch_table(l) swap_section_dispatch_table(l)
+#define md_swapin_so_debug(d) swap_so_debug(d)
+#define md_swapout_so_debug(d) swap_so_debug(d)
+#define md_swapin_rrs_hash(f,n) swap_rrs_hash(f,n)
+#define md_swapout_rrs_hash(f,n) swap_rrs_hash(f,n)
+#define md_swapin_sod(l,n) swapin_sod(l,n)
+#define md_swapout_sod(l,n) swapout_sod(l,n)
+#define md_swapout_got(g,n) swap_longs((long*)(g),n)
+#define md_swapin_ranlib_hdr(h,n) swap_ranlib_hdr(h,n)
+#define md_swapout_ranlib_hdr(h,n) swap_ranlib_hdr(h,n)
+
+#define md_swap_short(x) ( (((x) >> 8) & 0xff) | (((x) & 0xff) << 8) )
+
+#define md_swap_long(x) ( (((x) >> 24) & 0xff ) | (((x) >> 8 ) & 0xff00 ) | \
+ (((x) << 8 ) & 0xff0000) | (((x) << 24) & 0xff000000))
+
+#else /* We need not swap, but must pay attention to alignment: */
+
+#define md_swap_short(x) (x)
+#define md_swap_long(x) (x)
+
+#endif /* NEED_SWAP */
+
+#else /* Not a cross linker: use native */
+
+#define md_swap_short(x) (x)
+#define md_swap_long(x) (x)
+
+#define get_byte(where) (*(char *)(where))
+#define get_short(where) (*(short *)(where))
+#define get_long(where) (*(long *)(where))
+
+#define put_byte(where,what) (*(char *)(where) = (what))
+#define put_short(where,what) (*(short *)(where) = (what))
+#define put_long(where,what) (*(long *)(where) = (what))
+
+#endif /* CROSS_LINKER */
diff --git a/gnu/usr.bin/ld/i386/mdprologue.S b/gnu/usr.bin/ld/i386/mdprologue.S
new file mode 100644
index 0000000..1de0f72
--- /dev/null
+++ b/gnu/usr.bin/ld/i386/mdprologue.S
@@ -0,0 +1,93 @@
+/*
+ * 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: mdprologue.S,v 1.7 1994/12/04 07:42:44 mycroft Exp $
+ */
+
+/*
+ * i386 run-time link editor entry points.
+ */
+
+#include <sys/syscall.h>
+
+ .text
+ .globl _binder, _binder_entry
+
+/*
+ * _rtl(int version, struct crt_ldso *crtp)
+ */
+
+_rtl: # crt0 calls us here
+ pushl %ebp # Allocate stack frame
+ movl %esp,%ebp
+ pushl %ebx
+
+ call 1f # PIC function prologue
+1:
+ popl %ebx
+ addl $_GLOBAL_OFFSET_TABLE_+[.-1b],%ebx
+
+ movl 12(%ebp),%eax # Extract data from interface structure
+ movl (%eax),%eax # base address of ld.so (first field)
+ # setup arguments for rtld()
+ movl (%ebx),%ecx # 1st entry in GOT is our __DYNAMIC
+ addl %eax,%ecx # add load address
+ pushl %ecx # 3rd arg
+ pushl 12(%ebp) # 2nd arg == &crt.
+ pushl 8(%ebp) # 1st arg == version
+ addl _rtld@GOT(%ebx),%eax # relocate address of function
+ call %eax # _rtld(version, crtp, DYNAMIC)
+ addl $12,%esp # pop arguments
+
+ popl %ebx
+ leave # remove stack frame
+ ret
+
+ # First call to a procedure generally comes through here for
+ # binding.
+
+_binder_entry:
+ pushl %ebp # setup a stack frame
+ movl %esp,%ebp
+ pusha # save all regs
+
+ xorl %eax,%eax # clear
+ movl 4(%ebp),%esi # return address in PLT
+ movw (%esi),%ax # get hold of relocation number
+ subl $6,%esi # make it point to the jmpslot
+
+ pushl %eax # pushd arguments
+ pushl %esi #
+ call _binder@PLT # _binder(rpc, index)
+ addl $8,%esp # pop arguments
+ movl %eax,4(%ebp) # return value from _binder() == actual
+ # address of function
+ popa # restore regs
+ leave # remove our stack frame
+ ret
diff --git a/gnu/usr.bin/ld/ld.1 b/gnu/usr.bin/ld/ld.1
new file mode 100644
index 0000000..f3a12c4
--- /dev/null
+++ b/gnu/usr.bin/ld/ld.1
@@ -0,0 +1,217 @@
+.\"
+.\" 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.
+.\" 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: ld.1,v 1.8 1994/12/11 21:39:31 ats Exp $
+.\"
+.Dd October 14, 1993
+.Dt LD 1
+.Os FreeBSD
+.Sh NAME
+.Nm ld
+.Nd link editor
+.Sh SYNOPSIS
+.Nm ld
+.Op Fl MNnrSstXxz
+.Bk -words
+.Op Fl A Ar symbol-file
+.Op Fl assert Ar keyword
+.Op Fl B Ar linkmode
+.Op Fl D Ar datasize
+.Op Fl d Ar c
+.Op Fl d Ar p
+.Op Fl e Ar entry
+.Op Fl l Ar library-specifier
+.Op Fl L Ar library-search-path
+.Op Fl nostdlib
+.Op Fl o Ar filename
+.Op Fl T Ar address
+.Op Fl u Ar symbol
+.Op Fl V Ar shlib-version
+.Op Fl y Ar symbol
+.Ek
+.Sh DESCRIPTION
+.Nm
+combines the object and archive files given on the command line into a new
+object file. The output object file is either an executable program, a
+shared object suitable for loading at run-time, or an object file that can
+once again be processed by
+.Nm ld.
+Object files and archives are processed in the order given on the command line.
+.Pp
+The options are as follows:
+.Pp
+.Bl -tag -width indent
+.It Fl A Ar symbol-file
+The the symbol-file is taken as a base for link-editing the object files
+on the command line.
+.It Fl a\&ssert Ar keyword
+This option has currently no effect. It is here for compatibility with
+SunOS ld. All conditions which would cause a Sun assertion to fail will
+currently always cause error or warning messages from
+.Nm ld\&.
+.It Fl B Ar dynamic
+Specifies that linking against dynamic libraries can take place. If a library
+specifier of the form -lx appears on the command line,
+.Nm ld
+searches for a library of the from libx.so.n.m (see the
+.Ar l
+option) according to the search rules in effect. If such a file can not be
+found a traditional archive is looked for.
+This options can appear anywhere on the command line and is complementary
+to -Bstatic.
+.It Fl B Ar static
+The counterpart of -Bdynamic. This option turns off dynamic linking for
+all library specifiers until a -Bdynamic is once again given. Any explicitly
+mentioned shared object encountered on the command line while this option is
+in effect is flagged as an error.
+.It Fl B Ar shareable
+Instructs the linker to build a shared object from the object files rather
+than a normal executable image.
+.It Fl B Ar symbolic
+This option causes all symbolic references in the output to be resolved in
+this link-edit session. The only remaining run-time relocation requirements are
+.Em base-relative
+relocations, ie. translation with respect to the load address. Failure to
+resolve any symbolic reference causes an error to be reported.
+.It Fl B Ar forcearchive
+Force all members of archives to be loaded, whether or not such members
+contribute a definition to any plain object files. Useful for making a
+shared library from an archive of PIC objects without having to unpack
+the archive.
+.It Fl B Ar silly
+Search for
+.Em \.sa
+silly archive companions of shared objects. Useful for compatibility with
+version 3 shared objects.
+.It Fl D Ar data-size
+Set the size of the data segment. For sanity's sake, this should be larger
+than the cumulative data sizes of the input files.
+.It Fl d Ar c
+Force allocation of commons even producing relocatable output.
+.It Fl d Ar p
+Force alias definitions of procedure calls in non-PIC code. Useful to
+obtain shareable code in the presence of run-time relocations as such
+calls will be re-directed through the Procedure Linkage Table (see
+.Xr link 5)
+.It Fl e Ar entry-symbol
+Specifies the entry symbol for an executable.
+.It Fl L Ar path
+Add
+.Ar path
+to the list of directories to search for libraries specified with the
+.Ar -l
+option.
+.It Fl l Ar lib-spec
+This option specifies a library to be considered for inclusion in the
+output. If the -Bdynamic option is in effect, a shared library of the
+form lib<spec>.so.m.n (where
+.Em m
+is the major, and
+.Em n
+is the minor version number, respectively) is searched for first. The
+library with the highest version found in the search path is selected.
+If no shared library is found or the -Bstatic options is in effect,
+an archive of the form lib<spec>.a is looked for in the library seach path.
+.It Fl M
+Produce output about the mapping of segments of the input files and the
+values assigned to (global) symbols in the output file.
+.It Fl N
+Produce a OMAGIC output file.
+.It Fl n
+Produce a NMAGIC output file.
+.It Fl nostdlib
+Do not search the built-in path
+.Po
+usually
+.Dq /usr/lib
+.Pc
+for
+.Ar -l
+specified libraries.
+.It Fl o Ar filename
+Specifies the name of the output file. Defaults to
+.Dq a.out.
+.It Fl Q
+Produce a QMAGIC (FreeBSD/BSDi-i386) output file. This is the default.
+.It Fl r
+Produce relocatable object file, suitable for another pass through
+.Nm ld.
+.It Fl S
+Strip all debugger symbols from the output.
+.It Fl s
+Strip all symbols from the output.
+.It Fl T
+Specifies the start address of the text segment, with respect to which
+all input files will be relocated.
+.It Fl t
+Leave a trace of the input files as they are processed.
+.It Fl u Ar symbol
+Force
+.Ar symbol
+to be marked as undefined. Useful to force loading of an archive member
+in the absence of any other references to that member.
+.It Fl V Ar version
+Put the given version number into the output shared library (if one is
+created). Useful to make shared libaries compatible with other operating
+systems. Eg. SunOS 4.x libraries use version number 3. Defaults to 8.
+.It Fl X
+Discard local symbols in the input files that start with the letter
+.Dq L
+.It Fl x
+Discard all local symbols in the input files.
+.It Fl y Ar symbol
+Trace the manipulations inflicted on
+.Ar symbol
+.It Fl Z
+Make a 386BSD ZMAGIC output file.
+.It Fl z
+Make a NetBSD ZMAGIC output file.
+.Sh FILES
+.Sh SEE ALSO
+.Xr ldconfig 8 ,
+.Xr link 5
+.Sh CAVEATS
+An entry point must now explicitly be given if the output is intended to be
+a normal executable program. This was not the case for the previous version of
+.Nm ld\&.
+.Sh BUGS
+Shared objects are not properly checked for undefined symbols.
+.Pp
+Cascading of shared object defeats the
+.Dq -Bstatic
+option.
+.Pp
+All shared objects presented to
+.Nm ld
+are marked for run-time loading in the output file, even if no symbols
+are needed from them.
+.Sh HISTORY
+The shared library model employed by
+.Nm ld
+appeared first in SunOS 4.0
diff --git a/gnu/usr.bin/ld/ld.1aout b/gnu/usr.bin/ld/ld.1aout
new file mode 100644
index 0000000..f3a12c4
--- /dev/null
+++ b/gnu/usr.bin/ld/ld.1aout
@@ -0,0 +1,217 @@
+.\"
+.\" 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.
+.\" 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: ld.1,v 1.8 1994/12/11 21:39:31 ats Exp $
+.\"
+.Dd October 14, 1993
+.Dt LD 1
+.Os FreeBSD
+.Sh NAME
+.Nm ld
+.Nd link editor
+.Sh SYNOPSIS
+.Nm ld
+.Op Fl MNnrSstXxz
+.Bk -words
+.Op Fl A Ar symbol-file
+.Op Fl assert Ar keyword
+.Op Fl B Ar linkmode
+.Op Fl D Ar datasize
+.Op Fl d Ar c
+.Op Fl d Ar p
+.Op Fl e Ar entry
+.Op Fl l Ar library-specifier
+.Op Fl L Ar library-search-path
+.Op Fl nostdlib
+.Op Fl o Ar filename
+.Op Fl T Ar address
+.Op Fl u Ar symbol
+.Op Fl V Ar shlib-version
+.Op Fl y Ar symbol
+.Ek
+.Sh DESCRIPTION
+.Nm
+combines the object and archive files given on the command line into a new
+object file. The output object file is either an executable program, a
+shared object suitable for loading at run-time, or an object file that can
+once again be processed by
+.Nm ld.
+Object files and archives are processed in the order given on the command line.
+.Pp
+The options are as follows:
+.Pp
+.Bl -tag -width indent
+.It Fl A Ar symbol-file
+The the symbol-file is taken as a base for link-editing the object files
+on the command line.
+.It Fl a\&ssert Ar keyword
+This option has currently no effect. It is here for compatibility with
+SunOS ld. All conditions which would cause a Sun assertion to fail will
+currently always cause error or warning messages from
+.Nm ld\&.
+.It Fl B Ar dynamic
+Specifies that linking against dynamic libraries can take place. If a library
+specifier of the form -lx appears on the command line,
+.Nm ld
+searches for a library of the from libx.so.n.m (see the
+.Ar l
+option) according to the search rules in effect. If such a file can not be
+found a traditional archive is looked for.
+This options can appear anywhere on the command line and is complementary
+to -Bstatic.
+.It Fl B Ar static
+The counterpart of -Bdynamic. This option turns off dynamic linking for
+all library specifiers until a -Bdynamic is once again given. Any explicitly
+mentioned shared object encountered on the command line while this option is
+in effect is flagged as an error.
+.It Fl B Ar shareable
+Instructs the linker to build a shared object from the object files rather
+than a normal executable image.
+.It Fl B Ar symbolic
+This option causes all symbolic references in the output to be resolved in
+this link-edit session. The only remaining run-time relocation requirements are
+.Em base-relative
+relocations, ie. translation with respect to the load address. Failure to
+resolve any symbolic reference causes an error to be reported.
+.It Fl B Ar forcearchive
+Force all members of archives to be loaded, whether or not such members
+contribute a definition to any plain object files. Useful for making a
+shared library from an archive of PIC objects without having to unpack
+the archive.
+.It Fl B Ar silly
+Search for
+.Em \.sa
+silly archive companions of shared objects. Useful for compatibility with
+version 3 shared objects.
+.It Fl D Ar data-size
+Set the size of the data segment. For sanity's sake, this should be larger
+than the cumulative data sizes of the input files.
+.It Fl d Ar c
+Force allocation of commons even producing relocatable output.
+.It Fl d Ar p
+Force alias definitions of procedure calls in non-PIC code. Useful to
+obtain shareable code in the presence of run-time relocations as such
+calls will be re-directed through the Procedure Linkage Table (see
+.Xr link 5)
+.It Fl e Ar entry-symbol
+Specifies the entry symbol for an executable.
+.It Fl L Ar path
+Add
+.Ar path
+to the list of directories to search for libraries specified with the
+.Ar -l
+option.
+.It Fl l Ar lib-spec
+This option specifies a library to be considered for inclusion in the
+output. If the -Bdynamic option is in effect, a shared library of the
+form lib<spec>.so.m.n (where
+.Em m
+is the major, and
+.Em n
+is the minor version number, respectively) is searched for first. The
+library with the highest version found in the search path is selected.
+If no shared library is found or the -Bstatic options is in effect,
+an archive of the form lib<spec>.a is looked for in the library seach path.
+.It Fl M
+Produce output about the mapping of segments of the input files and the
+values assigned to (global) symbols in the output file.
+.It Fl N
+Produce a OMAGIC output file.
+.It Fl n
+Produce a NMAGIC output file.
+.It Fl nostdlib
+Do not search the built-in path
+.Po
+usually
+.Dq /usr/lib
+.Pc
+for
+.Ar -l
+specified libraries.
+.It Fl o Ar filename
+Specifies the name of the output file. Defaults to
+.Dq a.out.
+.It Fl Q
+Produce a QMAGIC (FreeBSD/BSDi-i386) output file. This is the default.
+.It Fl r
+Produce relocatable object file, suitable for another pass through
+.Nm ld.
+.It Fl S
+Strip all debugger symbols from the output.
+.It Fl s
+Strip all symbols from the output.
+.It Fl T
+Specifies the start address of the text segment, with respect to which
+all input files will be relocated.
+.It Fl t
+Leave a trace of the input files as they are processed.
+.It Fl u Ar symbol
+Force
+.Ar symbol
+to be marked as undefined. Useful to force loading of an archive member
+in the absence of any other references to that member.
+.It Fl V Ar version
+Put the given version number into the output shared library (if one is
+created). Useful to make shared libaries compatible with other operating
+systems. Eg. SunOS 4.x libraries use version number 3. Defaults to 8.
+.It Fl X
+Discard local symbols in the input files that start with the letter
+.Dq L
+.It Fl x
+Discard all local symbols in the input files.
+.It Fl y Ar symbol
+Trace the manipulations inflicted on
+.Ar symbol
+.It Fl Z
+Make a 386BSD ZMAGIC output file.
+.It Fl z
+Make a NetBSD ZMAGIC output file.
+.Sh FILES
+.Sh SEE ALSO
+.Xr ldconfig 8 ,
+.Xr link 5
+.Sh CAVEATS
+An entry point must now explicitly be given if the output is intended to be
+a normal executable program. This was not the case for the previous version of
+.Nm ld\&.
+.Sh BUGS
+Shared objects are not properly checked for undefined symbols.
+.Pp
+Cascading of shared object defeats the
+.Dq -Bstatic
+option.
+.Pp
+All shared objects presented to
+.Nm ld
+are marked for run-time loading in the output file, even if no symbols
+are needed from them.
+.Sh HISTORY
+The shared library model employed by
+.Nm ld
+appeared first in SunOS 4.0
diff --git a/gnu/usr.bin/ld/ld.c b/gnu/usr.bin/ld/ld.c
new file mode 100644
index 0000000..cb59660
--- /dev/null
+++ b/gnu/usr.bin/ld/ld.c
@@ -0,0 +1,3701 @@
+/*-
+ * This code is derived from software copyrighted by the Free Software
+ * Foundation.
+ *
+ * Modified 1991 by Donn Seeley at UUNET Technologies, Inc.
+ *
+ * Modified 1993 by Paul Kranenburg, Erasmus University
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)ld.c 6.10 (Berkeley) 5/22/91";
+#endif /* not lint */
+
+/* Linker `ld' for GNU
+ Copyright (C) 1988 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 1, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* Written by Richard Stallman with some help from Eric Albert.
+ Set, indirect, and warning symbol features added by Randy Smith. */
+
+/*
+ * $Id: ld.c,v 1.30 1995/09/28 19:43:20 bde Exp $
+ */
+
+/* Define how to initialize system-dependent header fields. */
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/file.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <err.h>
+#include <fcntl.h>
+#include <ar.h>
+#include <ranlib.h>
+#include <a.out.h>
+#include <stab.h>
+#include <string.h>
+
+#include "ld.h"
+
+/* Vector of entries for input files specified by arguments.
+ These are all the input files except for members of specified libraries. */
+struct file_entry *file_table;
+int number_of_files;
+
+/* 1 => write relocation into output file so can re-input it later. */
+int relocatable_output;
+
+/* 1 => building a shared object, set by `-Bshareable'. */
+int building_shared_object;
+
+/* 1 => create the output executable. */
+int make_executable;
+
+/* Force the executable to be output, even if there are non-fatal errors */
+int force_executable;
+
+/* 1 => assign space to common symbols even if `relocatable_output'. */
+int force_common_definition;
+
+/* 1 => assign jmp slots to text symbols in shared objects even if non-PIC */
+int force_alias_definition;
+
+/* 1 => some files contain PIC code, affects relocation bits
+ if `relocatable_output'. */
+int pic_code_seen;
+
+/* 1 => segments must be page aligned (ZMAGIC, QMAGIC) */
+int page_align_segments;
+
+/* 1 => data segment must be page aligned, even if `-n' or `-N' */
+int page_align_data;
+
+/* 1 => do not use standard library search path */
+int nostdlib;
+
+/* Version number to put in __DYNAMIC (set by -V) */
+int soversion;
+
+int text_size; /* total size of text. */
+int text_start; /* start of text */
+int text_pad; /* clear space between text and data */
+int data_size; /* total size of data. */
+int data_start; /* start of data */
+int data_pad; /* part of bss segment as part of data */
+
+int bss_size; /* total size of bss. */
+int bss_start; /* start of bss */
+
+int text_reloc_size; /* total size of text relocation. */
+int data_reloc_size; /* total size of data relocation. */
+
+int rrs_section_type; /* What's in the RRS section */
+int rrs_text_size; /* Size of RRS text additions */
+int rrs_text_start; /* Location of above */
+int rrs_data_size; /* Size of RRS data additions */
+int rrs_data_start; /* Location of above */
+
+/* Specifications of start and length of the area reserved at the end
+ of the data segment for the set vectors. Computed in 'digest_symbols' */
+int set_sect_start; /* start of set element vectors */
+int set_sect_size; /* size of above */
+
+int link_mode; /* Current link mode */
+
+/*
+ * When loading the text and data, we can avoid doing a close
+ * and another open between members of the same library.
+ *
+ * These two variables remember the file that is currently open.
+ * Both are zero if no file is open.
+ *
+ * See `each_file' and `file_close'.
+ */
+struct file_entry *input_file;
+int input_desc;
+
+/* The name of the file to write; "a.out" by default. */
+char *output_filename; /* Output file name. */
+FILE *outstream; /* Output file descriptor. */
+struct exec outheader; /* Output file header. */
+int magic; /* Output file magic. */
+int oldmagic;
+int relocatable_output; /* `-r'-ed output */
+
+symbol *entry_symbol; /* specified by `-e' */
+int entry_offset; /* program entry if no `-e' given */
+
+int page_size; /* Size of a page (machine dependent) */
+
+/*
+ * Keep a list of any symbols referenced from the command line (so
+ * that error messages for these guys can be generated). This list is
+ * zero terminated.
+ */
+symbol **cmdline_references;
+int cl_refs_allocated;
+
+/*
+ * Which symbols should be stripped (omitted from the output): none, all, or
+ * debugger symbols.
+ */
+enum {
+ STRIP_NONE, STRIP_ALL, STRIP_DEBUGGER
+} strip_symbols;
+
+/*
+ * Which local symbols should be omitted: none, all, or those starting with L.
+ * This is irrelevant if STRIP_NONE.
+ */
+enum {
+ DISCARD_NONE, DISCARD_ALL, DISCARD_L
+} discard_locals;
+
+int global_sym_count; /* # of nlist entries for global symbols */
+int size_sym_count; /* # of N_SIZE nlist entries for output
+ (relocatable_output only) */
+int local_sym_count; /* # of nlist entries for local symbols. */
+int non_L_local_sym_count; /* # of nlist entries for non-L symbols */
+int debugger_sym_count; /* # of nlist entries for debugger info. */
+int undefined_global_sym_count; /* # of global symbols referenced and
+ not defined. */
+int undefined_shobj_sym_count; /* # of undefined symbols referenced
+ by shared objects */
+int multiple_def_count; /* # of multiply defined symbols. */
+int defined_global_sym_count; /* # of defined global symbols. */
+int common_defined_global_count; /* # of common symbols. */
+int undefined_weak_sym_count; /* # of weak symbols referenced and
+ not defined. */
+
+#if notused
+int special_sym_count; /* # of linker defined symbols. */
+ /* XXX - Currently, only __DYNAMIC and _G_O_T_ go here if required,
+ * perhaps _etext, _edata and _end should go here too.
+ */
+#endif
+int global_alias_count; /* # of aliased symbols */
+int set_symbol_count; /* # of N_SET* symbols. */
+int set_vector_count; /* # of set vectors in output. */
+int warn_sym_count; /* # of warning symbols encountered. */
+int list_warning_symbols; /* 1 => warning symbols referenced */
+
+struct string_list_element *set_element_prefixes;
+
+int trace_files; /* print names of input files as processed (`-t'). */
+int write_map; /* write a load map (`-M') */
+
+/*
+ * `text-start' address is normally this much plus a page boundary.
+ * This is not a user option; it is fixed for each system.
+ */
+int text_start_alignment;
+
+/*
+ * Nonzero if -T was specified in the command line.
+ * This prevents text_start from being set later to default values.
+ */
+int T_flag_specified;
+
+/*
+ * Nonzero if -Tdata was specified in the command line.
+ * This prevents data_start from being set later to default values.
+ */
+int Tdata_flag_specified;
+
+/*
+ * Size to pad data section up to.
+ * We simply increase the size of the data section, padding with zeros,
+ * and reduce the size of the bss section to match.
+ */
+int specified_data_size;
+
+long *set_vectors;
+int setv_fill_count;
+
+static void decode_option __P((char *, char *));
+static void decode_command __P((int, char **));
+static int classify_arg __P((char *));
+static void load_symbols __P((void));
+static void enter_global_ref __P((struct localsymbol *,
+ char *, struct file_entry *));
+static void digest_symbols __P((void));
+static void digest_pass1 __P((void)), digest_pass2 __P((void));
+static void consider_file_section_lengths __P((struct file_entry *));
+static void relocate_file_addresses __P((struct file_entry *));
+static void consider_relocation __P((struct file_entry *, int));
+static void consider_local_symbols __P((struct file_entry *));
+static void perform_relocation __P((char *, int,
+ struct relocation_info *, int,
+ struct file_entry *, int));
+static void copy_text __P((struct file_entry *));
+static void copy_data __P((struct file_entry *));
+static void coptxtrel __P((struct file_entry *));
+static void copdatrel __P((struct file_entry *));
+static void write_output __P((void));
+static void write_header __P((void));
+static void write_text __P((void));
+static void write_data __P((void));
+static void write_rel __P((void));
+static void write_syms __P((void));
+static void assign_symbolnums __P((struct file_entry *, int *));
+static void cleanup __P((void));
+static int parse __P((char *, char *, char *));
+
+
+int
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+
+ /* Added this to stop ld core-dumping on very large .o files. */
+#ifdef RLIMIT_STACK
+ /* Get rid of any avoidable limit on stack size. */
+ {
+ struct rlimit rlim;
+
+ /* Set the stack limit huge so that alloca does not fail. */
+ if (getrlimit(RLIMIT_STACK, &rlim) != 0)
+ warn("getrlimit");
+ else {
+ rlim.rlim_cur = rlim.rlim_max;
+ if (setrlimit(RLIMIT_STACK, &rlim) != 0)
+ warn("setrlimit");
+ }
+ }
+#endif /* RLIMIT_STACK */
+
+ page_size = PAGSIZ;
+
+ /* Clear the cumulative info on the output file. */
+
+ text_size = 0;
+ data_size = 0;
+ bss_size = 0;
+ text_reloc_size = 0;
+ data_reloc_size = 0;
+
+ data_pad = 0;
+ text_pad = 0;
+ page_align_segments = 0;
+ page_align_data = 0;
+
+ /* Initialize the data about options. */
+
+ specified_data_size = 0;
+ strip_symbols = STRIP_NONE;
+ trace_files = 0;
+ discard_locals = DISCARD_NONE;
+ entry_symbol = 0;
+ write_map = 0;
+ relocatable_output = 0;
+ force_common_definition = 0;
+ T_flag_specified = 0;
+ Tdata_flag_specified = 0;
+ magic = DEFAULT_MAGIC;
+ make_executable = 1;
+ force_executable = 0;
+ link_mode = DYNAMIC;
+#ifdef SUNOS4
+ link_mode |= SILLYARCHIVE;
+#endif
+ soversion = DEFAULT_SOVERSION;
+
+ /* Initialize the cumulative counts of symbols. */
+
+ local_sym_count = 0;
+ non_L_local_sym_count = 0;
+ debugger_sym_count = 0;
+ undefined_global_sym_count = 0;
+ warn_sym_count = 0;
+ list_warning_symbols = 0;
+ multiple_def_count = 0;
+ common_defined_global_count = 0;
+
+ /* Keep a list of symbols referenced from the command line */
+ cl_refs_allocated = 10;
+ cmdline_references = (symbol **)
+ xmalloc(cl_refs_allocated * sizeof(symbol *));
+ *cmdline_references = 0;
+
+ /* Completely decode ARGV. */
+ decode_command(argc, argv);
+
+ building_shared_object =
+ (!relocatable_output && (link_mode & SHAREABLE));
+
+ if (building_shared_object && entry_symbol) {
+ errx(1,"`-Bshareable' and `-e' options are mutually exclusive");
+ }
+
+ /* Create the symbols `etext', `edata' and `end'. */
+ symtab_init(relocatable_output);
+
+ /*
+ * Determine whether to count the header as part of the text size,
+ * and initialize the text size accordingly. This depends on the kind
+ * of system and on the output format selected.
+ */
+
+ if (magic == ZMAGIC || magic == QMAGIC)
+ page_align_segments = 1;
+
+ md_init_header(&outheader, magic, 0);
+
+ text_size = sizeof(struct exec);
+ text_size -= N_TXTOFF(outheader);
+
+ if (text_size < 0)
+ text_size = 0;
+ entry_offset = text_size;
+
+ if (!T_flag_specified && !relocatable_output)
+ text_start = TEXT_START(outheader);
+
+ /* The text-start address is normally this far past a page boundary. */
+ text_start_alignment = text_start % page_size;
+
+ /*
+ * Load symbols of all input files. Also search all libraries and
+ * decide which library members to load.
+ */
+ load_symbols();
+
+ /* Compute where each file's sections go, and relocate symbols. */
+ digest_symbols();
+
+ /*
+ * Print error messages for any missing symbols, for any warning
+ * symbols, and possibly multiple definitions
+ */
+ make_executable &= do_warnings(stderr);
+
+ /* Print a map, if requested. */
+ if (write_map)
+ print_symbols(stdout);
+
+ /* Write the output file. */
+ if (make_executable || force_executable)
+ write_output();
+
+ exit(!make_executable);
+}
+
+/*
+ * Analyze a command line argument. Return 0 if the argument is a filename.
+ * Return 1 if the argument is a option complete in itself. Return 2 if the
+ * argument is a option which uses an argument.
+ *
+ * Thus, the value is the number of consecutive arguments that are part of
+ * options.
+ */
+
+static int
+classify_arg(arg)
+ register char *arg;
+{
+ if (*arg != '-')
+ return 0;
+ switch (arg[1]) {
+ case 'a':
+ if (!strcmp(&arg[2], "ssert"))
+ return 2;
+ case 'A':
+ case 'D':
+ case 'e':
+ case 'L':
+ case 'l':
+ case 'o':
+ case 'u':
+ case 'V':
+ case 'y':
+ if (arg[2])
+ return 1;
+ return 2;
+
+ case 'B':
+ if (!strcmp(&arg[2], "static"))
+ return 1;
+ if (!strcmp(&arg[2], "dynamic"))
+ return 1;
+
+ case 'T':
+ if (arg[2] == 0)
+ return 2;
+ if (!strcmp(&arg[2], "text"))
+ return 2;
+ if (!strcmp(&arg[2], "data"))
+ return 2;
+ return 1;
+ }
+
+ return 1;
+}
+
+/*
+ * Process the command arguments, setting up file_table with an entry for
+ * each input file, and setting variables according to the options.
+ */
+
+static void
+decode_command(argc, argv)
+ int argc;
+ char **argv;
+{
+ register int i;
+ register struct file_entry *p;
+
+ number_of_files = 0;
+ output_filename = "a.out";
+
+ /*
+ * First compute number_of_files so we know how long to make
+ * file_table.
+ * Also process most options completely.
+ */
+
+ for (i = 1; i < argc; i++) {
+ register int code = classify_arg(argv[i]);
+ if (code) {
+ if (i + code > argc)
+ errx(1, "no argument following %s", argv[i]);
+
+ decode_option(argv[i], argv[i + 1]);
+
+ if (argv[i][1] == 'l' || argv[i][1] == 'A')
+ number_of_files++;
+
+ i += code - 1;
+ } else
+ number_of_files++;
+ }
+
+ if (!number_of_files)
+ errx(1, "No input files specified");
+
+ p = file_table = (struct file_entry *)
+ xmalloc(number_of_files * sizeof(struct file_entry));
+ bzero(p, number_of_files * sizeof(struct file_entry));
+
+ /* Now scan again and fill in file_table. */
+ /* All options except -A and -l are ignored here. */
+
+ for (i = 1; i < argc; i++) {
+ char *string;
+ register int code = classify_arg(argv[i]);
+
+ if (code == 0) {
+ p->filename = argv[i];
+ p->local_sym_name = argv[i];
+ p++;
+ continue;
+ }
+ if (code == 2)
+ string = argv[i + 1];
+ else
+ string = &argv[i][2];
+
+ if (argv[i][1] == 'B') {
+ if (strcmp(string, "static") == 0)
+ link_mode &= ~DYNAMIC;
+ else if (strcmp(string, "dynamic") == 0)
+ link_mode |= DYNAMIC;
+ else if (strcmp(string, "symbolic") == 0)
+ link_mode |= SYMBOLIC;
+ else if (strcmp(string, "forcearchive") == 0)
+ link_mode |= FORCEARCHIVE;
+ else if (strcmp(string, "shareable") == 0)
+ link_mode |= SHAREABLE;
+#ifdef SUN_COMPAT
+ else if (strcmp(string, "silly") == 0)
+ link_mode |= SILLYARCHIVE;
+ else if (strcmp(string, "~silly") == 0)
+ link_mode &= ~SILLYARCHIVE;
+#endif
+ }
+ if (argv[i][1] == 'A') {
+ if (p != file_table)
+ errx(1, "-A specified before an input file other than the first");
+ p->filename = string;
+ p->local_sym_name = string;
+ p->flags |= E_JUST_SYMS;
+ link_mode &= ~DYNAMIC;
+ p++;
+ }
+ if (argv[i][1] == 'l') {
+ p->filename = string;
+ p->local_sym_name = concat("-l", string, "");
+ p->flags |= E_SEARCH_DIRS;
+ if (link_mode & DYNAMIC && !relocatable_output)
+ p->flags |= E_SEARCH_DYNAMIC;
+ p++;
+ }
+ i += code - 1;
+ }
+
+ /* Now check some option settings for consistency. */
+
+ if (page_align_segments &&
+ (text_start - text_start_alignment) & (page_size - 1))
+ errx(1, "incorrect alignment of text start address");
+
+ /* Append the standard search directories to the user-specified ones. */
+ add_search_path(getenv("LD_LIBRARY_PATH"));
+ if (!nostdlib)
+ std_search_path();
+}
+
+void
+add_cmdline_ref(sp)
+ symbol *sp;
+{
+ symbol **ptr;
+
+ for (ptr = cmdline_references;
+ ptr < cmdline_references + cl_refs_allocated && *ptr;
+ ptr++);
+
+ if (ptr >= cmdline_references + cl_refs_allocated - 1) {
+ int diff = ptr - cmdline_references;
+
+ cl_refs_allocated *= 2;
+ cmdline_references = (symbol **)
+ xrealloc(cmdline_references,
+ cl_refs_allocated * sizeof(symbol *));
+ ptr = cmdline_references + diff;
+ }
+ *ptr++ = sp;
+ *ptr = (symbol *)0;
+}
+
+int
+set_element_prefixed_p(name)
+ char *name;
+{
+ struct string_list_element *p;
+ int i;
+
+ for (p = set_element_prefixes; p; p = p->next) {
+
+ for (i = 0; p->str[i] != '\0' && (p->str[i] == name[i]); i++);
+ if (p->str[i] == '\0')
+ return 1;
+ }
+ return 0;
+}
+
+/*
+ * Record an option and arrange to act on it later. ARG should be the
+ * following command argument, which may or may not be used by this option.
+ *
+ * The `l' and `A' options are ignored here since they actually specify input
+ * files.
+ */
+
+static void
+decode_option(swt, arg)
+ register char *swt, *arg;
+{
+ if (!strcmp(swt + 1, "Bstatic"))
+ return;
+ if (!strcmp(swt + 1, "Bdynamic"))
+ return;
+ if (!strcmp(swt + 1, "Bsymbolic"))
+ return;
+ if (!strcmp(swt + 1, "Bforcearchive"))
+ return;
+ if (!strcmp(swt + 1, "Bshareable"))
+ return;
+ if (!strcmp(swt + 1, "assert"))
+ return;
+#ifdef SUN_COMPAT
+ if (!strcmp(swt + 1, "Bsilly"))
+ return;
+#endif
+ if (!strcmp(swt + 1, "Ttext")) {
+ text_start = parse(arg, "%x", "invalid argument to -Ttext");
+ T_flag_specified = 1;
+ return;
+ }
+ if (!strcmp(swt + 1, "Tdata")) {
+ rrs_data_start = parse(arg, "%x", "invalid argument to -Tdata");
+ Tdata_flag_specified = 1;
+ return;
+ }
+ if (!strcmp(swt + 1, "noinhibit-exec")) {
+ force_executable = 1;
+ return;
+ }
+ if (!strcmp(swt + 1, "nostdlib")) {
+ nostdlib = 1;
+ return;
+ }
+ if (swt[2] != 0)
+ arg = &swt[2];
+
+ switch (swt[1]) {
+ case 'A':
+ return;
+
+ case 'D':
+ specified_data_size = parse(arg, "%x", "invalid argument to -D");
+ return;
+
+ case 'd':
+ if (swt[2] == 0 || *arg == 'c')
+ force_common_definition = 1;
+ else if (*arg == 'p')
+ force_alias_definition = 1;
+ else
+ errx(1, "-d option takes 'c' or 'p' argument");
+ return;
+
+ case 'e':
+ entry_symbol = getsym(arg);
+ if (!entry_symbol->defined &&
+ !(entry_symbol->flags & GS_REFERENCED))
+ undefined_global_sym_count++;
+ entry_symbol->flags |= GS_REFERENCED;
+ add_cmdline_ref(entry_symbol);
+ return;
+
+ case 'l':
+ return;
+
+ case 'L':
+ add_search_dir(arg);
+ return;
+
+ case 'M':
+ write_map = 1;
+ return;
+
+ case 'N':
+ magic = OMAGIC;
+ return;
+
+ case 'n':
+ magic = NMAGIC;
+ return;
+
+ case 'o':
+ output_filename = arg;
+ return;
+
+ case 'p':
+ page_align_data = 1;
+ return;
+
+#ifdef QMAGIC
+ case 'Q':
+ magic = QMAGIC;
+ return;
+#endif
+
+ case 'r':
+ relocatable_output = 1;
+ magic = OMAGIC;
+ text_start = 0;
+ return;
+
+ case 'S':
+ strip_symbols = STRIP_DEBUGGER;
+ return;
+
+ case 's':
+ strip_symbols = STRIP_ALL;
+ return;
+
+ case 'T':
+ text_start = parse(arg, "%x", "invalid argument to -T");
+ T_flag_specified = 1;
+ return;
+
+ case 't':
+ trace_files = 1;
+ return;
+
+ case 'u':
+ {
+ register symbol *sp = getsym(arg);
+
+ if (!sp->defined && !(sp->flags & GS_REFERENCED))
+ undefined_global_sym_count++;
+ sp->flags |= GS_REFERENCED;
+ add_cmdline_ref(sp);
+ }
+ return;
+
+#if 1
+ case 'V':
+ soversion = parse(arg, "%d", "invalid argument to -V");
+ return;
+#endif
+
+ case 'X':
+ discard_locals = DISCARD_L;
+ return;
+
+ case 'x':
+ discard_locals = DISCARD_ALL;
+ return;
+
+ case 'y':
+ {
+ register symbol *sp = getsym(&swt[2]);
+ sp->flags |= GS_TRACE;
+ }
+ return;
+
+ case 'z':
+ magic = ZMAGIC;
+ oldmagic = 0;
+#ifdef __FreeBSD__
+ netzmagic = 1;
+#endif
+ return;
+
+ case 'Z':
+ magic = oldmagic = ZMAGIC;
+#ifdef __FreeBSD__
+ netzmagic = 0;
+#endif
+ return;
+
+ default:
+ errx(1, "invalid command option `%s'", swt);
+ }
+}
+
+/* Convenient functions for operating on one or all files being loaded. */
+
+/*
+ * Call FUNCTION on each input file entry. Do not call for entries for
+ * libraries; instead, call once for each library member that is being
+ * loaded.
+ *
+ * FUNCTION receives two arguments: the entry, and ARG.
+ */
+
+void
+each_file(function, arg)
+ register void (*function)();
+ register void *arg;
+{
+ register int i;
+
+ for (i = 0; i < number_of_files; i++) {
+ register struct file_entry *entry = &file_table[i];
+ register struct file_entry *subentry;
+
+ if (entry->flags & E_SCRAPPED)
+ continue;
+
+ if (!(entry->flags & E_IS_LIBRARY))
+ (*function)(entry, arg);
+
+ subentry = entry->subfiles;
+ for (; subentry; subentry = subentry->chain) {
+ if (subentry->flags & E_SCRAPPED)
+ continue;
+ (*function)(subentry, arg);
+ }
+
+#ifdef SUN_COMPAT
+ if (entry->silly_archive) {
+
+ if (!(entry->flags & E_DYNAMIC))
+ warnx("Silly");
+
+ if (!(entry->silly_archive->flags & E_IS_LIBRARY))
+ warnx("Sillier");
+
+ subentry = entry->silly_archive->subfiles;
+ for (; subentry; subentry = subentry->chain) {
+ if (subentry->flags & E_SCRAPPED)
+ continue;
+ (*function)(subentry, arg);
+ }
+ }
+#endif
+ }
+}
+
+/*
+ * Call FUNCTION on each input file entry until it returns a non-zero value.
+ * Return this value. Do not call for entries for libraries; instead, call
+ * once for each library member that is being loaded.
+ *
+ * FUNCTION receives two arguments: the entry, and ARG. It must be a function
+ * returning unsigned long (though this can probably be fudged).
+ */
+
+unsigned long
+check_each_file(function, arg)
+ register unsigned long (*function)();
+ register void *arg;
+{
+ register int i;
+ register unsigned long return_val;
+
+ for (i = 0; i < number_of_files; i++) {
+ register struct file_entry *entry = &file_table[i];
+ if (entry->flags & E_SCRAPPED)
+ continue;
+ if (entry->flags & E_IS_LIBRARY) {
+ register struct file_entry *subentry = entry->subfiles;
+ for (; subentry; subentry = subentry->chain) {
+ if (subentry->flags & E_SCRAPPED)
+ continue;
+ if (return_val = (*function)(subentry, arg))
+ return return_val;
+ }
+ } else if (return_val = (*function)(entry, arg))
+ return return_val;
+ }
+ return 0;
+}
+
+/* Like `each_file' but ignore files that were just for symbol definitions. */
+
+void
+each_full_file(function, arg)
+ register void (*function)();
+ register void *arg;
+{
+ register int i;
+
+ for (i = 0; i < number_of_files; i++) {
+ register struct file_entry *entry = &file_table[i];
+ register struct file_entry *subentry;
+
+ if (entry->flags & (E_SCRAPPED | E_JUST_SYMS))
+ continue;
+
+#ifdef SUN_COMPAT
+ if (entry->silly_archive) {
+
+ if (!(entry->flags & E_DYNAMIC))
+ warnx("Silly");
+
+ if (!(entry->silly_archive->flags & E_IS_LIBRARY))
+ warnx("Sillier");
+
+ subentry = entry->silly_archive->subfiles;
+ for (; subentry; subentry = subentry->chain) {
+ if (subentry->flags & E_SCRAPPED)
+ continue;
+ (*function)(subentry, arg);
+ }
+ }
+#endif
+ if (entry->flags & E_DYNAMIC)
+ continue;
+
+ if (!(entry->flags & E_IS_LIBRARY))
+ (*function)(entry, arg);
+
+ subentry = entry->subfiles;
+ for (; subentry; subentry = subentry->chain) {
+ if (subentry->flags & E_SCRAPPED)
+ continue;
+ (*function)(subentry, arg);
+ }
+
+ }
+}
+
+/* Close the input file that is now open. */
+
+void
+file_close()
+{
+ close(input_desc);
+ input_desc = 0;
+ input_file = 0;
+}
+
+/*
+ * Open the input file specified by 'entry', and return a descriptor. The
+ * open file is remembered; if the same file is opened twice in a row, a new
+ * open is not actually done.
+ */
+int
+file_open(entry)
+ register struct file_entry *entry;
+{
+ register int fd;
+
+ if (entry->superfile && (entry->superfile->flags & E_IS_LIBRARY))
+ return file_open(entry->superfile);
+
+ if (entry == input_file)
+ return input_desc;
+
+ if (input_file)
+ file_close();
+
+ if (entry->flags & E_SEARCH_DIRS) {
+ fd = findlib(entry);
+ } else
+ fd = open(entry->filename, O_RDONLY, 0);
+
+ if (fd >= 0) {
+ input_file = entry;
+ input_desc = fd;
+ return fd;
+ }
+
+ if (entry->flags & E_SEARCH_DIRS)
+ errx(1, "%s: no match", entry->local_sym_name);
+ else
+ err(1, "%s", entry->filename);
+ return fd;
+}
+
+int
+text_offset(entry)
+ struct file_entry *entry;
+{
+ return entry->starting_offset + N_TXTOFF (entry->header);
+}
+
+/*---------------------------------------------------------------------------*/
+
+/*
+ * Read a file's header into the proper place in the file_entry. FD is the
+ * descriptor on which the file is open. ENTRY is the file's entry.
+ */
+void
+read_header(fd, entry)
+ int fd;
+ struct file_entry *entry;
+{
+ register int len;
+
+ if (lseek(fd, entry->starting_offset, L_SET) !=
+ entry->starting_offset)
+ err(1, "%s: read_header: lseek", get_file_name(entry));
+
+ len = read(fd, &entry->header, sizeof(struct exec));
+ if (len != sizeof (struct exec))
+ err(1, "%s: read_header: read", get_file_name(entry));
+
+ md_swapin_exec_hdr(&entry->header);
+
+ if (N_BADMAG (entry->header))
+ errx(1, "%s: bad magic", get_file_name(entry));
+
+ if (N_BADMID(entry->header))
+ errx(1, "%s: non-native input file", get_file_name(entry));
+
+ entry->flags |= E_HEADER_VALID;
+}
+
+/*
+ * Read the symbols of file ENTRY into core. Assume it is already open, on
+ * descriptor FD. Also read the length of the string table, which follows
+ * the symbol table, but don't read the contents of the string table.
+ */
+
+void
+read_entry_symbols(fd, entry)
+ struct file_entry *entry;
+ int fd;
+{
+ int str_size;
+ struct nlist *np;
+ int i;
+
+ if (!(entry->flags & E_HEADER_VALID))
+ read_header(fd, entry);
+
+ np = (struct nlist *)alloca(entry->header.a_syms);
+ entry->nsymbols = entry->header.a_syms / sizeof(struct nlist);
+ if (entry->nsymbols == 0)
+ return;
+
+ entry->symbols = (struct localsymbol *)
+ xmalloc(entry->nsymbols * sizeof(struct localsymbol));
+
+ if (lseek(fd, N_SYMOFF(entry->header) + entry->starting_offset, L_SET)
+ != N_SYMOFF(entry->header) + entry->starting_offset)
+ err(1, "%s: read_symbols: lseek(syms)", get_file_name(entry));
+
+ if (entry->header.a_syms != read(fd, np, entry->header.a_syms))
+ errx(1, "%s: read_symbols: premature end of file in symbols",
+ get_file_name(entry));
+
+ md_swapin_symbols(np, entry->header.a_syms / sizeof(struct nlist));
+
+ for (i = 0; i < entry->nsymbols; i++) {
+ entry->symbols[i].nzlist.nlist = *np++;
+ entry->symbols[i].nzlist.nz_size = 0;
+ entry->symbols[i].symbol = NULL;
+ entry->symbols[i].next = NULL;
+ entry->symbols[i].entry = entry;
+ entry->symbols[i].gotslot_offset = -1;
+ entry->symbols[i].flags = 0;
+ }
+
+ entry->strings_offset = N_STROFF(entry->header) +
+ entry->starting_offset;
+ if (lseek(fd, entry->strings_offset, 0) == (off_t)-1)
+ err(1, "%s: read_symbols: lseek(strings)",
+ get_file_name(entry));
+ if (sizeof str_size != read(fd, &str_size, sizeof str_size))
+ errx(1, "%s: read_symbols: cannot read string table size",
+ get_file_name(entry));
+
+ entry->string_size = md_swap_long(str_size);
+}
+
+/*
+ * Read the string table of file ENTRY open on descriptor FD, into core.
+ */
+void
+read_entry_strings(fd, entry)
+ struct file_entry *entry;
+ int fd;
+{
+
+ if (entry->string_size == 0)
+ return;
+
+ if (!(entry->flags & E_HEADER_VALID) || !entry->strings_offset)
+ errx(1, "%s: read_strings: string table unavailable",
+ get_file_name(entry));
+
+ if (lseek(fd, entry->strings_offset, L_SET) !=
+ entry->strings_offset)
+ err(1, "%s: read_strings: lseek",
+ get_file_name(entry));
+
+ if (read(fd, entry->strings, entry->string_size) !=
+ entry->string_size)
+ errx(1, "%s: read_strings: premature end of file in strings",
+ get_file_name(entry));
+
+ return;
+}
+
+/* Read in the relocation sections of ENTRY if necessary */
+
+void
+read_entry_relocation(fd, entry)
+ int fd;
+ struct file_entry *entry;
+{
+ register struct relocation_info *reloc;
+ off_t pos;
+
+ if (!entry->textrel) {
+
+ reloc = (struct relocation_info *)
+ xmalloc(entry->header.a_trsize);
+
+ pos = text_offset(entry) +
+ entry->header.a_text + entry->header.a_data;
+
+ if (lseek(fd, pos, L_SET) != pos)
+ err(1, "%s: read_reloc(text): lseek",
+ get_file_name(entry));
+
+ if (read(fd, reloc, entry->header.a_trsize) !=
+ entry->header.a_trsize)
+ errx(1, "%s: read_reloc(text): premature EOF",
+ get_file_name(entry));
+
+ md_swapin_reloc(reloc, entry->header.a_trsize / sizeof(*reloc));
+ entry->textrel = reloc;
+ entry->ntextrel = entry->header.a_trsize / sizeof(*reloc);
+
+ }
+
+ if (!entry->datarel) {
+
+ reloc = (struct relocation_info *)
+ xmalloc(entry->header.a_drsize);
+
+ pos = text_offset(entry) + entry->header.a_text +
+ entry->header.a_data + entry->header.a_trsize;
+
+ if (lseek(fd, pos, L_SET) != pos)
+ err(1, "%s: read_reloc(data): lseek",
+ get_file_name(entry));
+
+ if (read(fd, reloc, entry->header.a_drsize) !=
+ entry->header.a_drsize)
+ errx(1, "%s: read_reloc(data): premature EOF",
+ get_file_name(entry));
+
+ md_swapin_reloc(reloc, entry->header.a_drsize / sizeof(*reloc));
+ entry->datarel = reloc;
+ entry->ndatarel = entry->header.a_drsize / sizeof(*reloc);
+
+ }
+}
+
+/*---------------------------------------------------------------------------*/
+
+/*
+ * Read in the symbols of all input files.
+ */
+static void
+load_symbols()
+{
+ register int i;
+
+ if (trace_files)
+ fprintf(stderr, "Loading symbols:\n\n");
+
+ for (i = 0; i < number_of_files; i++)
+ read_file_symbols(&file_table[i]);
+
+ if (trace_files)
+ fprintf(stderr, "\n");
+}
+
+/*
+ * If ENTRY is a rel file, read its symbol and string sections into core. If
+ * it is a library, search it and load the appropriate members (which means
+ * calling this function recursively on those members).
+ */
+
+void
+read_file_symbols(entry)
+ register struct file_entry *entry;
+{
+ register int fd;
+ register int len;
+ struct exec hdr;
+
+ fd = file_open(entry);
+
+ len = read(fd, &hdr, sizeof hdr);
+ if (len != sizeof hdr)
+ errx(1, "%s: read_file_symbols(header): premature EOF",
+ get_file_name(entry));
+
+ md_swapin_exec_hdr(&hdr);
+
+ if (!N_BADMAG (hdr)) {
+ if (N_IS_DYNAMIC(hdr) && !(entry->flags & E_JUST_SYMS)) {
+ if (relocatable_output) {
+ errx(1,
+ "%s: -r and shared objects currently not supported",
+ get_file_name(entry));
+ return;
+ }
+#if notyet /* Compatibility */
+ if (!(N_GETFLAG(hdr) & EX_PIC))
+ warnx("%s: EX_PIC not set",
+ get_file_name(entry));
+#endif
+ entry->flags |= E_DYNAMIC;
+ if (entry->superfile || rrs_add_shobj(entry))
+ read_shared_object(fd, entry);
+ else
+ entry->flags |= E_SCRAPPED;
+ } else {
+ if (N_GETFLAG(hdr) & EX_PIC)
+ pic_code_seen = 1;
+ read_entry_symbols(fd, entry);
+ entry->strings = (char *)alloca(entry->string_size);
+ read_entry_strings(fd, entry);
+ read_entry_relocation(fd, entry);
+ enter_file_symbols(entry);
+ entry->strings = 0;
+ }
+ } else {
+ char armag[SARMAG];
+
+ lseek (fd, 0, 0);
+ if (SARMAG != read(fd, armag, SARMAG) ||
+ strncmp (armag, ARMAG, SARMAG))
+ errx(1,
+ "%s: malformed input file (not rel or archive)",
+ get_file_name(entry));
+ entry->flags |= E_IS_LIBRARY;
+ search_library(fd, entry);
+ }
+
+ file_close();
+}
+
+
+/*
+ * Enter the external symbol defs and refs of ENTRY in the hash table.
+ */
+
+void
+enter_file_symbols(entry)
+ struct file_entry *entry;
+{
+ struct localsymbol *lsp, *lspend;
+
+ if (trace_files)
+ prline_file_name(entry, stderr);
+
+ lspend = entry->symbols + entry->nsymbols;
+
+ for (lsp = entry->symbols; lsp < lspend; lsp++) {
+ register struct nlist *p = &lsp->nzlist.nlist;
+
+ if (p->n_type == (N_SETV | N_EXT))
+ continue;
+
+ /*
+ * Turn magically prefixed symbols into set symbols of
+ * a corresponding type.
+ */
+ if (set_element_prefixes &&
+ set_element_prefixed_p(entry->strings+lsp->nzlist.nz_strx))
+ lsp->nzlist.nz_type += (N_SETA - N_ABS);
+
+ if (SET_ELEMENT_P(p->n_type)) {
+ set_symbol_count++;
+ if (!relocatable_output)
+ enter_global_ref(lsp,
+ p->n_un.n_strx + entry->strings, entry);
+ } else if (p->n_type == N_WARNING) {
+ char *msg = p->n_un.n_strx + entry->strings;
+
+ /* Grab the next entry. */
+ lsp++;
+ p = &lsp->nzlist.nlist;
+ if (p->n_type != (N_UNDF | N_EXT)) {
+ warnx(
+ "%s: Warning symbol without external reference following.",
+ get_file_name(entry));
+ make_executable = 0;
+ lsp--; /* Process normally. */
+ } else {
+ symbol *sp;
+ char *name = p->n_un.n_strx + entry->strings;
+ /* Deal with the warning symbol. */
+ lsp->flags |= LS_WARNING;
+ enter_global_ref(lsp, name, entry);
+ sp = getsym(name);
+ if (sp->warning == NULL) {
+ sp->warning = (char *)
+ xmalloc(strlen(msg)+1);
+ strcpy(sp->warning, msg);
+ warn_sym_count++;
+ } else if (strcmp(sp->warning, msg))
+ warnx(
+ "%s: multiple definitions for warning symbol `%s'",
+ get_file_name(entry), sp->name);
+ }
+ } else if (p->n_type & N_EXT) {
+ enter_global_ref(lsp,
+ p->n_un.n_strx + entry->strings, entry);
+ } else if (p->n_un.n_strx &&
+ (p->n_un.n_strx + entry->strings)[0] == LPREFIX)
+ lsp->flags |= LS_L_SYMBOL;
+ }
+
+}
+
+/*
+ * Enter one global symbol in the hash table. LSP points to the `struct
+ * localsymbol' from the file that describes the global symbol. NAME is the
+ * symbol's name. ENTRY is the file entry for the file the symbol comes from.
+ *
+ * LSP is put on the chain of all such structs that refer to the same symbol.
+ * This chain starts in the `refs' for symbols from relocatable objects. A
+ * backpointer to the global symbol is kept in LSP.
+ *
+ * Symbols from shared objects are linked through `soref'. For such symbols
+ * that's all we do at this stage, with the exception of the case where the
+ * symbol is a common. The `referenced' bit is only set for references from
+ * relocatable objects.
+ *
+ */
+
+static void
+enter_global_ref(lsp, name, entry)
+ struct localsymbol *lsp;
+ char *name;
+ struct file_entry *entry;
+{
+ register struct nzlist *nzp = &lsp->nzlist;
+ register symbol *sp = getsym(name);
+ register int type = nzp->nz_type;
+ int oldref = (sp->flags & GS_REFERENCED);
+ int olddef = sp->defined;
+ int com = sp->defined && sp->common_size;
+
+ if (type == (N_INDR | N_EXT) && !olddef) {
+ sp->alias = getsym(entry->strings + (lsp + 1)->nzlist.nz_strx);
+ if (sp == sp->alias) {
+ warnx("%s: %s is alias for itself",
+ get_file_name(entry), name);
+ /* Rewrite symbol as global text symbol with value 0 */
+ lsp->nzlist.nz_type = N_TEXT|N_EXT;
+ lsp->nzlist.nz_value = 0;
+ make_executable = 0;
+ } else {
+ global_alias_count++;
+ }
+#if 0
+ if (sp->flags & GS_REFERENCED)
+ sp->alias->flags |= GS_REFERENCED;
+#endif
+ }
+
+ if (entry->flags & E_DYNAMIC) {
+ lsp->next = sp->sorefs;
+ sp->sorefs = lsp;
+ lsp->symbol = sp;
+
+ /*
+ * Handle commons from shared objects:
+ * 1) If symbol hitherto undefined, turn it into a common.
+ * 2) If symbol already common, update size if necessary.
+ */
+/*XXX - look at case where commons are only in shared objects */
+ if (type == (N_UNDF | N_EXT) && nzp->nz_value) {
+ if (!olddef) {
+ if (oldref)
+ undefined_global_sym_count--;
+ common_defined_global_count++;
+ sp->common_size = nzp->nz_value;
+ sp->defined = N_UNDF | N_EXT;
+ } else if (com && sp->common_size < nzp->nz_value) {
+ sp->common_size = nzp->nz_value;
+ }
+ } else if (type != (N_UNDF | N_EXT) && !oldref) {
+ /*
+ * This is an ex common...
+ */
+ if (com)
+ common_defined_global_count--;
+ sp->common_size = 0;
+ sp->defined = 0;
+ }
+
+ /*
+ * Handle size information in shared objects.
+ */
+ if (nzp->nz_size > sp->size)
+ sp->size = nzp->nz_size;
+
+ if ((lsp->flags & LS_WARNING) && (sp->flags & GS_REFERENCED))
+ /*
+ * Prevent warning symbols from getting
+ * gratuitously referenced.
+ */
+ list_warning_symbols = 1;
+ return;
+ }
+
+ lsp->next = sp->refs;
+ sp->refs = lsp;
+ lsp->symbol = sp;
+
+ if (lsp->flags & LS_WARNING) {
+ /*
+ * Prevent warning symbols from getting
+ * gratuitously referenced.
+ */
+ if (sp->flags & GS_REFERENCED)
+ list_warning_symbols = 1;
+ return;
+ }
+
+ if (sp->warning)
+ list_warning_symbols = 1;
+
+ sp->flags |= GS_REFERENCED;
+
+ if (sp == dynamic_symbol || sp == got_symbol) {
+ if (type != (N_UNDF | N_EXT) && !(entry->flags & E_JUST_SYMS))
+ errx(1,"Linker reserved symbol %s defined as type %x ",
+ name, type);
+ return;
+ }
+
+ if (olddef && N_ISWEAK(&nzp->nlist) && !(sp->flags & GS_WEAK)) {
+#ifdef DEBUG
+ printf("%s: not overridden by weak symbol from %s\n",
+ sp->name, get_file_name(entry));
+#endif
+ return;
+ }
+
+ if (type == (N_SIZE | N_EXT)) {
+
+ if (relocatable_output && nzp->nz_value != 0 && sp->size == 0)
+ size_sym_count++;
+ if (sp->size < nzp->nz_value)
+ sp->size = nzp->nz_value;
+
+ } else if (type != (N_UNDF | N_EXT) || nzp->nz_value) {
+
+ /*
+ * Set `->defined' here, so commons and undefined globals
+ * can be counted correctly.
+ */
+ if (!sp->defined || sp->defined == (N_UNDF | N_EXT)) {
+ sp->defined = type;
+ }
+
+ if ((sp->flags & GS_WEAK) && !N_ISWEAK(&nzp->nlist)) {
+ /*
+ * Upgrade an existing weak definition.
+ * We fake it by pretending the symbol is undefined;
+ * must undo any common fiddling, however.
+ */
+ if (!oldref)
+ errx(1, "internal error: enter_glob_ref: "
+ "weak symbol not referenced");
+ if (!olddef && !com)
+ undefined_weak_sym_count--;
+ undefined_global_sym_count++;
+ sp->defined = type;
+ sp->flags &= ~GS_WEAK;
+ olddef = 0;
+ if (com)
+ common_defined_global_count--;
+ com = 0;
+ sp->common_size = 0;
+ }
+ if (oldref && !olddef) {
+ /*
+ * It used to be undefined and we're defining it.
+ */
+ undefined_global_sym_count--;
+ if (sp->flags & GS_WEAK)
+ /* Used to be a weak reference */
+ undefined_weak_sym_count--;
+ if (undefined_global_sym_count < 0 ||
+ undefined_weak_sym_count < 0)
+ errx(1, "internal error: enter_glob_ref: "
+ "undefined_global_sym_count = %d, "
+ "undefined_weak_sym_count = %d",
+ undefined_global_sym_count,
+ undefined_weak_sym_count);
+
+ }
+
+ if (N_ISWEAK(&nzp->nlist))
+ /* The definition is weak */
+ sp->flags |= GS_WEAK;
+
+ if (!olddef && type == (N_UNDF | N_EXT) && nzp->nz_value) {
+ /*
+ * First definition and it's common.
+ */
+ common_defined_global_count++;
+ sp->common_size = nzp->nz_value;
+ } else if (com && type != (N_UNDF | N_EXT)) {
+ /*
+ * It used to be common and we're defining
+ * it as something else.
+ */
+ common_defined_global_count--;
+ sp->common_size = 0;
+ } else if (com && type == (N_UNDF | N_EXT) &&
+ sp->common_size < nzp->nz_value)
+ /*
+ * It used to be common and this is a new common entry
+ * to which we need to pay attention.
+ */
+ sp->common_size = nzp->nz_value;
+
+ if (SET_ELEMENT_P(type) && (!olddef || com))
+ set_vector_count++;
+
+ } else if (!oldref && !com) {
+ /*
+ * An unreferenced symbol can already be defined
+ * as common by shared objects.
+ */
+ undefined_global_sym_count++;
+ if (N_ISWEAK(&nzp->nlist)) {
+ /* The reference is weak */
+ sp->flags |= GS_WEAK;
+ undefined_weak_sym_count++;
+ }
+ }
+
+ if (sp == end_symbol && (entry->flags & E_JUST_SYMS) &&
+ !T_flag_specified)
+ text_start = nzp->nz_value;
+
+ if (sp->flags & GS_TRACE) {
+ register char *reftype;
+ switch (type & N_TYPE) {
+ case N_UNDF:
+ reftype = nzp->nz_value
+ ? "defined as common" : "referenced";
+ break;
+
+ case N_ABS:
+ reftype = "defined as absolute";
+ break;
+
+ case N_TEXT:
+ reftype = "defined in text section";
+ break;
+
+ case N_DATA:
+ reftype = "defined in data section";
+ break;
+
+ case N_BSS:
+ reftype = "defined in BSS section";
+ break;
+
+ case N_INDR:
+ reftype = "alias";
+ break;
+
+ case N_SIZE:
+ reftype = "size spec";
+ break;
+
+ default:
+ reftype = "I don't know this type";
+ break;
+ }
+
+ fprintf(stderr, "symbol %s %s%s in ", sp->name,
+ (N_ISWEAK(&nzp->nlist))?"weakly ":"", reftype);
+ print_file_name (entry, stderr);
+ fprintf(stderr, "\n");
+ }
+}
+
+/*
+ * This returns 0 if the given file entry's symbol table does *not* contain
+ * the nlist point entry, and it returns the files entry pointer (cast to
+ * unsigned long) if it does.
+ */
+
+unsigned long
+contains_symbol(entry, np)
+ struct file_entry *entry;
+ register struct nlist *np;
+{
+ if (np >= &entry->symbols->nzlist.nlist &&
+ np < &(entry->symbols + entry->nsymbols)->nzlist.nlist)
+ return (unsigned long) entry;
+ return 0;
+}
+
+
+/*
+ * Having entered all the global symbols and found the sizes of sections of
+ * all files to be linked, make all appropriate deductions from this data.
+ *
+ * We propagate global symbol values from definitions to references. We compute
+ * the layout of the output file and where each input file's contents fit
+ * into it.
+ *
+ * This is now done in several stages.
+ *
+ * 1) All global symbols are examined for definitions in relocatable (.o)
+ * files. The symbols' type is set according to the definition found,
+ * but its value can not yet be determined. In stead, we keep a pointer
+ * to the file entry's localsymbol that bequeathed the global symbol with
+ * its definition. Also, multiple (incompatible) definitions are checked
+ * for in this pass. If no definition comes forward, the set of local
+ * symbols originating from shared objects is searched for a definition.
+ *
+ * 2) Then the relocation information of each relocatable file is examined
+ * for possible contributions to the RRS section.
+ *
+ * 3) When this is done, the sizes and start addresses are set of all segments
+ * that will appear in the output file (including the RRS segment).
+ *
+ * 4) Finally, all symbols are relocated according according to the start
+ * of the entry they are part of. Then global symbols are assigned their
+ * final values. Also, space for commons and imported data are allocated
+ * during this pass, if the link mode in effect so demands.
+ *
+ */
+
+static void
+digest_symbols()
+{
+
+ if (trace_files)
+ fprintf(stderr, "Digesting symbol information:\n\n");
+
+ if (!relocatable_output) {
+ /*
+ * The set sector size is the number of set elements + a word
+ * for each symbol for the length word at the beginning of
+ * the vector, plus a word for each symbol for a zero at the
+ * end of the vector (for incremental linking).
+ */
+ set_sect_size = (set_symbol_count + 2 * set_vector_count) *
+ sizeof (unsigned long);
+ set_vectors = (long *)xmalloc (set_sect_size);
+ setv_fill_count = 0;
+ }
+
+ /* Pass 1: check and define symbols */
+ defined_global_sym_count = 0;
+ digest_pass1();
+
+ each_full_file(consider_relocation, (void *)0); /* Text */
+ each_full_file(consider_relocation, (void *)1); /* Data */
+
+ each_file(consider_local_symbols, (void *)0);
+
+ /*
+ * Compute total size of sections.
+ * RRS data is the first output data section, RRS text is the last
+ * text section. Thus, DATA_START is calculated from RRS_DATA_START
+ * and RRS_DATA_SIZE, while RRS_TEXT_START is derived from TEXT_START
+ * and TEXT_SIZE.
+ */
+ consider_rrs_section_lengths();
+ each_full_file(consider_file_section_lengths, 0);
+ rrs_text_start = text_start + text_size;
+ text_size += rrs_text_size;
+ data_size += rrs_data_size;
+
+ /*
+ * If necessary, pad text section to full page in the file. Include
+ * the padding in the text segment size.
+ */
+
+ if (page_align_segments || page_align_data) {
+ int text_end = text_size + N_TXTOFF(outheader);
+ text_pad = PALIGN(text_end, page_size) - text_end;
+ text_size += text_pad;
+ }
+ outheader.a_text = text_size;
+
+ /*
+ * Make the data segment address start in memory on a suitable
+ * boundary.
+ */
+
+ if (!Tdata_flag_specified)
+ rrs_data_start = text_start +
+ DATA_START(outheader) - TEXT_START(outheader);
+
+ data_start = rrs_data_start + rrs_data_size;
+ if (!relocatable_output) {
+ set_sect_start = rrs_data_start + data_size;
+ data_size += MALIGN(set_sect_size);
+ }
+ bss_start = rrs_data_start + data_size;
+
+#ifdef DEBUG
+printf("textstart = %#x, textsize = %#x, rrs_text_start = %#x, rrs_text_size %#x\n",
+ text_start, text_size, rrs_text_start, rrs_text_size);
+printf("datastart = %#x, datasize = %#x, rrs_data_start %#x, rrs_data_size %#x\n",
+ data_start, data_size, rrs_data_start, rrs_data_size);
+printf("bssstart = %#x, bsssize = %#x\n",
+ bss_start, bss_size);
+printf("set_sect_start = %#x, set_sect_size = %#x\n",
+ set_sect_start, set_sect_size);
+#endif
+
+ /* Compute start addresses of each file's sections and symbols. */
+
+ each_full_file(relocate_file_addresses, 0);
+ relocate_rrs_addresses();
+
+ /* Pass 2: assign values to symbols */
+ digest_pass2();
+
+ if (end_symbol) { /* These are null if -r. */
+ etext_symbol->value = text_start + text_size - text_pad;
+ edata_symbol->value = rrs_data_start + data_size;
+ end_symbol->value = rrs_data_start + data_size + bss_size;
+ }
+ /*
+ * Figure the data_pad now, so that it overlaps with the bss
+ * addresses.
+ */
+
+ if (specified_data_size && specified_data_size > data_size)
+ data_pad = specified_data_size - data_size;
+
+ if (page_align_segments)
+ data_pad = PALIGN(data_pad + data_size, page_size) - data_size;
+
+ bss_size -= data_pad;
+ if (bss_size < 0)
+ bss_size = 0;
+
+ data_size += data_pad;
+
+ /*
+ * Calculate total number of symbols that will go into
+ * the output symbol table (barring DISCARD_* settings).
+ */
+ global_sym_count = defined_global_sym_count +
+ undefined_global_sym_count;
+
+ if (dynamic_symbol->flags & GS_REFERENCED)
+ global_sym_count++;
+
+ if (got_symbol->flags & GS_REFERENCED)
+ global_sym_count++;
+
+ if (relocatable_output || building_shared_object) {
+ /* For each alias we write out two struct nlists */
+ global_sym_count += global_alias_count;
+ /* Propagate warning symbols; costs two extra struct nlists */
+ global_sym_count += 2 * warn_sym_count;
+ }
+
+ if (relocatable_output)
+ /* We write out the original N_SIZE symbols */
+ global_sym_count += size_sym_count;
+
+#ifdef DEBUG
+printf(
+"global symbols %d "
+"(defined %d, undefined %d, weak %d, aliases %d, warnings 2 * %d, "
+"size symbols %d)\ncommons %d, locals: %d, debug symbols: %d, set_symbols %d\n",
+ global_sym_count,
+ defined_global_sym_count, undefined_global_sym_count,
+ undefined_weak_sym_count,
+ global_alias_count, warn_sym_count, size_sym_count,
+ common_defined_global_count, local_sym_count,
+ debugger_sym_count, set_symbol_count);
+#endif
+}
+
+/*
+ * Determine the definition of each global symbol.
+ */
+static void
+digest_pass1()
+{
+
+ /*
+ * For each symbol, verify that it is defined globally at most
+ * once within relocatable files (except when building a shared lib).
+ * and set the `defined' field if there is a definition.
+ *
+ * Then check the shared object symbol chain for any remaining
+ * undefined symbols. Set the `so_defined' field for any
+ * definition find this way.
+ */
+ FOR_EACH_SYMBOL(i, sp) {
+ symbol *spsave;
+ struct localsymbol *lsp;
+ int defs = 0;
+
+ if (!(sp->flags & GS_REFERENCED)) {
+#if 0
+ /* Check for undefined symbols in shared objects */
+ int type;
+ for (lsp = sp->sorefs; lsp; lsp = lsp->next) {
+ type = lsp->nzlist.nlist.n_type;
+ if ((type & N_EXT) && type != (N_UNDF | N_EXT))
+ break;
+ }
+ if ((type & N_EXT) && type == (N_UNDF | N_EXT))
+ undefined_shobj_sym_count++;
+#endif
+
+ /* Superfluous symbol from shared object */
+ continue;
+ }
+ if (sp->so_defined)
+ /* Already examined; must have been an alias */
+ continue;
+
+ if (sp == got_symbol || sp == dynamic_symbol)
+ continue;
+
+ for (lsp = sp->refs; lsp; lsp = lsp->next) {
+ register struct nlist *p = &lsp->nzlist.nlist;
+ register int type = p->n_type;
+
+ if (SET_ELEMENT_P(type)) {
+ if (relocatable_output)
+ errx(1,
+ "internal error: global ref to set el %s with -r",
+ sp->name);
+ if (!defs++) {
+ sp->defined = N_SETV | N_EXT;
+ sp->value =
+ setv_fill_count++ * sizeof(long);
+ } else if ((sp->defined & N_TYPE) != N_SETV) {
+ sp->mult_defs = 1;
+ multiple_def_count++;
+ }
+ /* Keep count and remember symbol */
+ sp->setv_count++;
+ set_vectors[setv_fill_count++] = (long)p;
+ if (building_shared_object) {
+ struct relocation_info reloc;
+
+ /*
+ * Make sure to relocate the contents
+ * of this set vector.
+ */
+ bzero(&reloc, sizeof(reloc));
+ RELOC_INIT_SEGMENT_RELOC(&reloc);
+ RELOC_ADDRESS(&reloc) =
+ setv_fill_count * sizeof(long);
+ alloc_rrs_segment_reloc(NULL, &reloc);
+ }
+
+ } else if ((type & N_EXT) && type != (N_UNDF | N_EXT)
+ && (type & N_TYPE) != N_FN
+ && (type & N_TYPE) != N_SIZE) {
+ /* non-common definition */
+ if (!N_ISWEAK(p))
+ ++defs;
+ if (defs > 1) {
+ sp->mult_defs = 1;
+ multiple_def_count++;
+ } else if (!N_ISWEAK(p) ||
+ (!sp->def_lsp && !sp->common_size)) {
+ sp->def_lsp = lsp;
+ lsp->entry->flags |= E_SYMBOLS_USED;
+ sp->defined = type;
+ sp->aux = N_AUX(p);
+ }
+ }
+ }
+
+ if (sp->defined) {
+ if ((sp->defined & N_TYPE) == N_SETV)
+ /* Allocate zero entry in set vector */
+ setv_fill_count++;
+ /*
+ * At this stage, we do not know whether an alias
+ * is going to be defined for real here, or whether
+ * it refers to a shared object symbol. The decision
+ * is deferred until digest_pass2().
+ */
+ if (!sp->alias)
+ defined_global_sym_count++;
+ continue;
+ }
+
+ if (relocatable_output)
+ /* We're done */
+ continue;
+
+ /*
+ * Still undefined, search the shared object symbols for a
+ * definition. This symbol must go into the RRS.
+ */
+ if (building_shared_object) {
+ /* Just punt for now */
+ undefined_global_sym_count--;
+ if (undefined_global_sym_count < 0)
+ errx(1,
+ "internal error: digest_pass1,1: %s: undefined_global_sym_count = %d",
+ sp->name, undefined_global_sym_count);
+ continue;
+ }
+
+ spsave=sp;
+ again:
+ for (lsp = sp->sorefs; lsp; lsp = lsp->next) {
+ register struct nlist *p = &lsp->nzlist.nlist;
+ register int type = p->n_type;
+
+ if ((type & N_EXT) && type != (N_UNDF | N_EXT) &&
+ (type & N_TYPE) != N_FN) {
+ /* non-common definition */
+ sp->def_lsp = lsp;
+ sp->so_defined = type;
+ sp->aux = N_AUX(p);
+ if (lsp->entry->flags & E_SECONDCLASS)
+ /* Keep looking for something better */
+ continue;
+ if (N_ISWEAK(p))
+ /* Keep looking for something better */
+ continue;
+ break;
+ }
+ }
+ if (sp->def_lsp) {
+#ifdef DEBUG
+printf("pass1: SO definition for %s, type %x in %s at %#x\n",
+ sp->name, sp->so_defined, get_file_name(sp->def_lsp->entry),
+ sp->def_lsp->nzlist.nz_value);
+#endif
+ sp->def_lsp->entry->flags |= E_SYMBOLS_USED;
+ if (sp->flags & GS_REFERENCED)
+ undefined_global_sym_count--;
+ else
+ sp->flags |= GS_REFERENCED;
+ if (undefined_global_sym_count < 0)
+ errx(1, "internal error: digest_pass1,2: "
+ "%s: undefined_global_sym_count = %d",
+ sp->name, undefined_global_sym_count);
+ if (sp->alias &&
+ !(sp->alias->flags & GS_REFERENCED)) {
+ sp = sp->alias;
+ goto again;
+ }
+ }
+ sp=spsave;
+ } END_EACH_SYMBOL;
+
+ if (setv_fill_count != set_sect_size/sizeof(long))
+ errx(1, "internal error: allocated set symbol space (%d) "
+ "doesn't match actual (%d)",
+ set_sect_size/sizeof(long), setv_fill_count);
+}
+
+
+/*
+ * Scan relocation info in ENTRY for contributions to the RRS section
+ * of the output file.
+ */
+static void
+consider_relocation(entry, dataseg)
+ struct file_entry *entry;
+ int dataseg;
+{
+ struct relocation_info *reloc, *end;
+ struct localsymbol *lsp;
+ symbol *sp;
+
+ if (dataseg == 0) {
+ /* Text relocations */
+ reloc = entry->textrel;
+ end = entry->textrel + entry->ntextrel;
+ } else {
+ /* Data relocations */
+ reloc = entry->datarel;
+ end = entry->datarel + entry->ndatarel;
+ }
+
+ for (; reloc < end; reloc++) {
+
+ if (relocatable_output) {
+ lsp = &entry->symbols[reloc->r_symbolnum];
+ if (RELOC_BASEREL_P(reloc)) {
+ pic_code_seen = 1; /* Compatibility */
+ if (!RELOC_EXTERN_P(reloc))
+ lsp->flags |= LS_RENAME;
+ }
+ continue;
+ }
+
+ /*
+ * First, do the PIC specific relocs.
+ * r_relative and r_copy should not occur at this point
+ * (we do output them). The others break down to these
+ * combinations:
+ *
+ * jmptab: extern: needs jmp slot
+ * !extern: "intersegment" jump/call,
+ * should get resolved in output
+ *
+ * baserel: extern: need GOT entry
+ * !extern: may need GOT entry,
+ * machine dependent
+ *
+ * baserel's always refer to symbol through `r_symbolnum'
+ * whether extern or not. Internal baserels refer to statics
+ * that must be accessed either *through* the GOT table like
+ * global data, or by means of an offset from the GOT table.
+ * The macro RELOC_STATICS_THROUGH_GOT_P() determines which
+ * applies, since this is a machine (compiler?) dependent
+ * addressing mode.
+ */
+
+ if (RELOC_JMPTAB_P(reloc)) {
+
+ if (!RELOC_EXTERN_P(reloc))
+ continue;
+
+ lsp = &entry->symbols[reloc->r_symbolnum];
+ sp = lsp->symbol;
+ if (sp->alias)
+ sp = sp->alias;
+ if (sp->flags & GS_TRACE) {
+ fprintf(stderr, "symbol %s has jmpslot in %s\n",
+ sp->name, get_file_name(entry));
+ }
+ alloc_rrs_jmpslot(entry, sp);
+
+ } else if (RELOC_BASEREL_P(reloc)) {
+
+ lsp = &entry->symbols[reloc->r_symbolnum];
+ alloc_rrs_gotslot(entry, reloc, lsp);
+
+ } else if (RELOC_EXTERN_P(reloc)) {
+
+ /*
+ * Non-PIC relocations.
+ * If the definition comes from a shared object
+ * we need a relocation entry in RRS.
+ *
+ * If the .so definition is N_TEXT a jmpslot is
+ * allocated.
+ *
+ * If it is N_DATA we allocate an address in BSS (?)
+ * and arrange for the data to be copied at run-time.
+ * The symbol is temporarily marked with N_SIZE in
+ * the `defined' field, so we know what to do in
+ * pass2() and during actual relocation. We convert
+ * the type back to something real again when writing
+ * out the symbols.
+ *
+ */
+ lsp = &entry->symbols[reloc->r_symbolnum];
+ sp = lsp->symbol;
+ if (sp == NULL)
+ errx(1, "%s: bogus relocation record",
+ get_file_name(entry));
+
+ if (sp->alias)
+ sp = sp->alias;
+
+ /*
+ * Skip refs to _GLOBAL_OFFSET_TABLE_ and __DYNAMIC
+ */
+ if (sp == got_symbol) {
+ if (!CHECK_GOT_RELOC(reloc))
+ errx(1,
+ "%s: Unexpected relocation type for GOT symbol",
+ get_file_name(entry));
+ continue;
+ }
+
+ /*
+ * This symbol gives rise to a RRS entry
+ */
+
+ if (building_shared_object) {
+ if (sp->flags & GS_TRACE) {
+ fprintf(stderr,
+ "symbol %s RRS entry in %s\n",
+ sp->name, get_file_name(entry));
+ }
+ alloc_rrs_reloc(entry, sp);
+ continue;
+ }
+
+ if (force_alias_definition && sp->so_defined &&
+ sp->aux == AUX_FUNC) {
+
+ /* Call to shared library procedure */
+ alloc_rrs_jmpslot(entry, sp);
+
+ } else if (sp->size && sp->so_defined &&
+ sp->aux == AUX_OBJECT) {
+
+ /* Reference to shared library data */
+ alloc_rrs_cpy_reloc(entry, sp);
+ sp->defined = N_SIZE;
+
+ } else if (!sp->defined && sp->common_size == 0 &&
+ sp->so_defined)
+ alloc_rrs_reloc(entry, sp);
+
+ } else {
+ /*
+ * Segment relocation.
+ * Prepare an RRS relocation as these are load
+ * address dependent.
+ */
+ if (building_shared_object && !RELOC_PCREL_P(reloc)) {
+ alloc_rrs_segment_reloc(entry, reloc);
+ }
+ }
+ }
+}
+
+/*
+ * Determine the disposition of each local symbol.
+ */
+static void
+consider_local_symbols(entry)
+ register struct file_entry *entry;
+{
+ register struct localsymbol *lsp, *lspend;
+
+ if (entry->flags & E_DYNAMIC)
+ return;
+
+ lspend = entry->symbols + entry->nsymbols;
+
+ /*
+ * For each symbol determine whether it should go
+ * in the output symbol table.
+ */
+
+ for (lsp = entry->symbols; lsp < lspend; lsp++) {
+ register struct nlist *p = &lsp->nzlist.nlist;
+ register int type = p->n_type;
+
+ if (type == N_WARNING)
+ continue;
+
+ if (SET_ELEMENT_P (type)) {
+ /*
+ * This occurs even if global. These types of
+ * symbols are never written globally, though
+ * they are stored globally.
+ */
+ if (relocatable_output)
+ lsp->flags |= LS_WRITE;
+
+ } else if (!(type & (N_STAB | N_EXT))) {
+
+ /*
+ * Ordinary local symbol
+ */
+ if ((lsp->flags & LS_RENAME) || (
+ discard_locals != DISCARD_ALL &&
+ !(discard_locals == DISCARD_L &&
+ (lsp->flags & LS_L_SYMBOL))) ) {
+
+ lsp->flags |= LS_WRITE;
+ local_sym_count++;
+ }
+
+ } else if (!(type & N_EXT)) {
+
+ /*
+ * Debugger symbol
+ */
+ if (strip_symbols == STRIP_NONE) {
+ lsp->flags |= LS_WRITE;
+ debugger_sym_count++;
+ }
+ }
+ }
+
+ /*
+ * Count one for the local symbol that we generate,
+ * whose name is the file's name (usually) and whose address
+ * is the start of the file's text.
+ */
+ if (discard_locals != DISCARD_ALL)
+ local_sym_count++;
+}
+
+/*
+ * Accumulate the section sizes of input file ENTRY into the section sizes of
+ * the output file.
+ */
+static void
+consider_file_section_lengths(entry)
+ register struct file_entry *entry;
+{
+
+ entry->text_start_address = text_size;
+ /* If there were any vectors, we need to chop them off */
+ text_size += entry->header.a_text;
+ entry->data_start_address = data_size;
+ data_size += entry->header.a_data;
+ entry->bss_start_address = bss_size;
+ bss_size += entry->header.a_bss;
+
+ text_reloc_size += entry->header.a_trsize;
+ data_reloc_size += entry->header.a_drsize;
+}
+
+/*
+ * Determine where the sections of ENTRY go into the output file,
+ * whose total section sizes are already known.
+ * Also relocate the addresses of the file's local and debugger symbols.
+ */
+static void
+relocate_file_addresses(entry)
+ register struct file_entry *entry;
+{
+ register struct localsymbol *lsp, *lspend;
+
+ entry->text_start_address += text_start;
+ /*
+ * Note that `data_start' and `data_size' have not yet been
+ * adjusted for `data_pad'. If they had been, we would get the wrong
+ * results here.
+ */
+ entry->data_start_address += data_start;
+ entry->bss_start_address += bss_start;
+#ifdef DEBUG
+printf("%s: datastart: %#x, bss %#x\n", get_file_name(entry),
+ entry->data_start_address, entry->bss_start_address);
+#endif
+
+ lspend = entry->symbols + entry->nsymbols;
+
+ for (lsp = entry->symbols; lsp < lspend; lsp++) {
+ register struct nlist *p = &lsp->nzlist.nlist;
+ register int type = p->n_type;
+
+ /*
+ * If this belongs to a section, update it
+ * by the section's start address
+ */
+
+ switch (type & N_TYPE) {
+ case N_TEXT:
+ case N_SETT:
+ p->n_value += entry->text_start_address;
+ break;
+ case N_DATA:
+ case N_SETD:
+ case N_SETV:
+ /*
+ * A symbol whose value is in the data section is
+ * present in the input file as if the data section
+ * started at an address equal to the length of the
+ * file's text.
+ */
+ p->n_value += entry->data_start_address -
+ entry->header.a_text;
+ break;
+ case N_BSS:
+ case N_SETB:
+ /* likewise for symbols with value in BSS. */
+ p->n_value += entry->bss_start_address -
+ (entry->header.a_text +
+ entry->header.a_data);
+ break;
+ }
+
+ }
+
+}
+
+/*
+ * Assign a value to each global symbol.
+ */
+static void
+digest_pass2()
+{
+ FOR_EACH_SYMBOL(i, sp) {
+ int size;
+ int align = sizeof(int);
+
+ if (!(sp->flags & GS_REFERENCED))
+ continue;
+
+ if (sp->alias &&
+ (relocatable_output || building_shared_object ||
+ (sp->alias->defined && !sp->alias->so_defined))) {
+ /*
+ * The alias points at a defined symbol, so it
+ * must itself be counted as one too, in order to
+ * compute the correct number of symbol table entries.
+ */
+ if (!sp->defined) {
+ /*
+ * Change aliased symbol's definition too.
+ * These things happen if shared object commons
+ * or data is going into our symbol table.
+ */
+ if (sp->so_defined != (N_INDR+N_EXT))
+ warnx( "pass2: %s: alias isn't",
+ sp->name);
+ sp->defined = sp->so_defined;
+ sp->so_defined = 0;
+ }
+ defined_global_sym_count++;
+ }
+
+ if ((sp->defined & N_TYPE) == N_SETV) {
+ /*
+ * Set length word at front of vector and zero byte
+ * at end. Reverse the vector itself to put it in
+ * file order.
+ */
+ unsigned long i, *p, *q;
+ unsigned long length_word_index =
+ sp->value / sizeof(long);
+
+ /* Relocate symbol value */
+ sp->value += set_sect_start;
+
+ set_vectors[length_word_index] = sp->setv_count;
+
+ /*
+ * Relocate vector to final address.
+ */
+ for (i = 0; i < sp->setv_count; i++) {
+ struct nlist *p = (struct nlist *)
+ set_vectors[1+i+length_word_index];
+
+ set_vectors[1+i+length_word_index] = p->n_value;
+ if (building_shared_object) {
+ struct relocation_info reloc;
+
+ bzero(&reloc, sizeof(reloc));
+ RELOC_INIT_SEGMENT_RELOC(&reloc);
+ RELOC_ADDRESS(&reloc) =
+ (1 + i + length_word_index) *
+ sizeof(long)
+ + set_sect_start;
+ RELOC_TYPE(&reloc) =
+ (p->n_type - (N_SETA - N_ABS)) & N_TYPE;
+ claim_rrs_segment_reloc(NULL, &reloc);
+ }
+ }
+
+ /*
+ * Reverse the vector.
+ */
+ p = &set_vectors[length_word_index + 1];
+ q = &set_vectors[length_word_index + sp->setv_count];
+ while (p < q) {
+ unsigned long tmp = *p;
+ *p++ = *q;
+ *q-- = tmp;
+ }
+
+ /* Clear terminating entry */
+ set_vectors[length_word_index + sp->setv_count + 1] = 0;
+ continue;
+ }
+
+ if (sp->def_lsp) {
+ if (sp->defined && (sp->defined & ~N_EXT) != N_SETV)
+ sp->value = sp->def_lsp->nzlist.nz_value;
+ if (sp->so_defined &&
+ (sp->def_lsp->entry->flags & E_SECONDCLASS))
+ /* Flag second-hand definitions */
+ undefined_global_sym_count++;
+ if (sp->flags & GS_TRACE)
+ printf("symbol %s assigned to location %#x\n",
+ sp->name, sp->value);
+ }
+
+ /*
+ * If not -r'ing, allocate common symbols in the BSS section.
+ */
+ if (building_shared_object && !(link_mode & SYMBOLIC))
+ /* No common allocation in shared objects */
+ continue;
+
+ if ((size = sp->common_size) != 0) {
+ /*
+ * It's a common.
+ */
+ if (sp->defined != (N_UNDF + N_EXT))
+ errx(1, "%s: common isn't", sp->name);
+
+ } else if ((size = sp->size) != 0 && sp->defined == N_SIZE) {
+ /*
+ * It's data from shared object with size info.
+ */
+ if (!sp->so_defined)
+ errx(1, "%s: Bogus N_SIZE item", sp->name);
+
+ } else
+ /*
+ * It's neither
+ */
+ continue;
+
+
+ if (relocatable_output && !force_common_definition) {
+ sp->defined = 0;
+ undefined_global_sym_count++;
+ defined_global_sym_count--;
+ continue;
+ }
+
+ /*
+ * Round up to nearest sizeof (int). I don't know whether
+ * this is necessary or not (given that alignment is taken
+ * care of later), but it's traditional, so I'll leave it in.
+ * Note that if this size alignment is ever removed, ALIGN
+ * above will have to be initialized to 1 instead of sizeof
+ * (int).
+ */
+
+ size = PALIGN(size, sizeof(int));
+
+ while (align < MAX_ALIGNMENT && !(size & align))
+ align <<= 1;
+
+ bss_size = PALIGN(bss_size + data_size + rrs_data_start, align)
+ - (data_size + rrs_data_start);
+
+ sp->value = rrs_data_start + data_size + bss_size;
+ if (sp->defined == (N_UNDF | N_EXT))
+ sp->defined = N_BSS | N_EXT;
+ else {
+ sp->so_defined = 0;
+ defined_global_sym_count++;
+ }
+ bss_size += size;
+ if (write_map)
+ printf("Allocating %s %s: %x at %x\n",
+ sp->defined==(N_BSS|N_EXT)?"common":"data",
+ sp->name, size, sp->value);
+
+ } END_EACH_SYMBOL;
+}
+
+
+/* -------------------------------------------------------------------*/
+
+/* Write the output file */
+void
+write_output()
+{
+ struct stat statbuf;
+ int filemode;
+ mode_t u_mask;
+
+ if (lstat(output_filename, &statbuf) == 0) {
+ if (S_ISREG(statbuf.st_mode))
+ (void)unlink(output_filename);
+ }
+
+ u_mask = umask(0);
+ (void)umask(u_mask);
+
+ outstream = fopen(output_filename, "w");
+ if (outstream == NULL)
+ err(1, "fopen: %s", output_filename);
+
+ if (atexit(cleanup))
+ err(1, "atexit");
+
+ if (fstat(fileno(outstream), &statbuf) < 0)
+ err(1, "fstat: %s", output_filename);
+
+ filemode = statbuf.st_mode;
+
+ if (S_ISREG(statbuf.st_mode) &&
+ chmod(output_filename, filemode & ~0111) == -1)
+ err(1, "chmod: %s", output_filename);
+
+ /* Output the a.out header. */
+ write_header();
+
+ /* Output the text and data segments, relocating as we go. */
+ write_text();
+ write_data();
+
+ /* Output the merged relocation info, if requested with `-r'. */
+ if (relocatable_output)
+ write_rel();
+
+ /* Output the symbol table (both globals and locals). */
+ write_syms();
+
+ /* Output the RSS section */
+ write_rrs();
+
+ if (chmod (output_filename, filemode | (0111 & ~u_mask)) == -1)
+ err(1, "chmod: %s", output_filename);
+
+ fflush(outstream);
+ /* Report I/O error such as disk full. */
+ if (ferror(outstream) || fclose(outstream) != 0)
+ err(1, "write_output: %s", output_filename);
+ outstream = 0;
+}
+
+/* Total number of symbols to be written in the output file. */
+static int nsyms;
+
+void
+write_header()
+{
+ int flags;
+
+ if (link_mode & SHAREABLE)
+ /* Output is shared object */
+ flags = EX_DYNAMIC | EX_PIC;
+ else if (relocatable_output && pic_code_seen)
+ /* Output is relocatable and contains PIC code */
+ flags = EX_PIC;
+ else if (rrs_section_type == RRS_FULL)
+ /* Output is a dynamic executable */
+ flags = EX_DYNAMIC;
+ else
+ /*
+ * Output is a static executable
+ * or a non-PIC relocatable object
+ */
+ flags = 0;
+
+ if (oldmagic && (flags & EX_DPMASK))
+ warnx("Cannot set flag in old magic headers\n");
+
+ N_SET_FLAG (outheader, flags);
+
+ outheader.a_text = text_size;
+ outheader.a_data = data_size;
+ outheader.a_bss = bss_size;
+ outheader.a_entry = (entry_symbol ? entry_symbol->value
+ : text_start + entry_offset);
+
+ if (strip_symbols == STRIP_ALL)
+ nsyms = 0;
+ else
+ nsyms = global_sym_count + local_sym_count + debugger_sym_count;
+
+ if (relocatable_output)
+ nsyms += set_symbol_count;
+
+ outheader.a_syms = nsyms * sizeof (struct nlist);
+
+ if (relocatable_output) {
+ outheader.a_trsize = text_reloc_size;
+ outheader.a_drsize = data_reloc_size;
+ } else {
+ outheader.a_trsize = 0;
+ outheader.a_drsize = 0;
+ }
+
+ md_swapout_exec_hdr(&outheader);
+ mywrite(&outheader, sizeof (struct exec), 1, outstream);
+ md_swapin_exec_hdr(&outheader);
+
+ /*
+ * Output whatever padding is required in the executable file
+ * between the header and the start of the text.
+ */
+
+#ifndef COFF_ENCAPSULATE
+ padfile(N_TXTOFF(outheader) - sizeof outheader, outstream);
+#endif
+}
+
+/*
+ * Relocate the text segment of each input file
+ * and write to the output file.
+ */
+void
+write_text()
+{
+
+ if (trace_files)
+ fprintf(stderr, "Copying and relocating text:\n\n");
+
+ each_full_file(copy_text, 0);
+ file_close();
+
+ if (trace_files)
+ fprintf(stderr, "\n");
+
+ padfile(text_pad, outstream);
+}
+
+/*
+ * Read the text segment contents of ENTRY, relocate them, and write the
+ * result to the output file. If `-r', save the text relocation for later
+ * reuse.
+ */
+void
+copy_text(entry)
+ struct file_entry *entry;
+{
+ register char *bytes;
+ register int fd;
+
+ if (trace_files)
+ prline_file_name(entry, stderr);
+
+ fd = file_open(entry);
+
+ /* Allocate space for the file's text section */
+ bytes = (char *)alloca(entry->header.a_text);
+
+ /* Deal with relocation information however is appropriate */
+ if (entry->textrel == NULL)
+ errx(1, "%s: no text relocation", get_file_name(entry));
+
+ /* Read the text section into core. */
+ if (lseek(fd, text_offset(entry), L_SET) == (off_t)-1)
+ err(1, "%s: copy_text: lseek", get_file_name(entry));
+ if (entry->header.a_text != read(fd, bytes, entry->header.a_text))
+ errx(1, "%s: copy_text: premature EOF", get_file_name(entry));
+
+ /* Relocate the text according to the text relocation. */
+ perform_relocation (bytes, entry->header.a_text,
+ entry->textrel, entry->ntextrel, entry, 0);
+
+ /* Write the relocated text to the output file. */
+ mywrite(bytes, 1, entry->header.a_text, outstream);
+}
+
+/*
+ * Relocate the data segment of each input file
+ * and write to the output file.
+ */
+
+void
+write_data()
+{
+ off_t pos;
+
+ if (trace_files)
+ fprintf(stderr, "Copying and relocating data:\n\n");
+
+ pos = N_DATOFF(outheader) + data_start - rrs_data_start;
+ if (fseek(outstream, pos, SEEK_SET) != 0)
+ errx(1, "write_data: fseek");
+
+ each_full_file(copy_data, 0);
+ file_close();
+
+ /*
+ * Write out the set element vectors. See digest symbols for
+ * description of length of the set vector section.
+ */
+
+ if (set_vector_count) {
+ swap_longs(set_vectors, set_symbol_count + 2*set_vector_count);
+ mywrite(set_vectors, set_symbol_count + 2*set_vector_count,
+ sizeof (unsigned long), outstream);
+ }
+
+ if (trace_files)
+ fprintf(stderr, "\n");
+
+ padfile(data_pad, outstream);
+}
+
+/*
+ * Read the data segment contents of ENTRY, relocate them, and write the
+ * result to the output file. If `-r', save the data relocation for later
+ * reuse. See comments in `copy_text'.
+ */
+void
+copy_data(entry)
+ struct file_entry *entry;
+{
+ register char *bytes;
+ register int fd;
+
+ if (trace_files)
+ prline_file_name (entry, stderr);
+
+ fd = file_open(entry);
+
+ bytes = (char *)alloca(entry->header.a_data);
+
+ if (entry->datarel == NULL)
+ errx(1, "%s: no data relocation", get_file_name(entry));
+
+ if (lseek(fd, text_offset(entry) + entry->header.a_text, L_SET) ==
+ (off_t)-1)
+ err(1, "%s: copy_data: lseek", get_file_name(entry));
+ if (entry->header.a_data != read(fd, bytes, entry->header.a_data))
+ errx(1, "%s: copy_data: premature EOF", get_file_name(entry));
+
+ perform_relocation(bytes, entry->header.a_data,
+ entry->datarel, entry->ndatarel, entry, 1);
+
+ mywrite(bytes, 1, entry->header.a_data, outstream);
+}
+
+/*
+ * Relocate ENTRY's text or data section contents. DATA is the address of the
+ * contents, in core. DATA_SIZE is the length of the contents. PC_RELOCATION
+ * is the difference between the address of the contents in the output file
+ * and its address in the input file. RELOC is the address of the
+ * relocation info, in core. NRELOC says how many there are.
+ */
+
+/* HACK: md.c may need access to this */
+int pc_relocation;
+
+void
+perform_relocation(data, data_size, reloc, nreloc, entry, dataseg)
+ char *data;
+ int data_size;
+ struct relocation_info *reloc;
+ int nreloc;
+ struct file_entry *entry;
+ int dataseg;
+{
+
+ register struct relocation_info *r = reloc;
+ struct relocation_info *end = reloc + nreloc;
+
+ int text_relocation = entry->text_start_address;
+ int data_relocation = entry->data_start_address - entry->header.a_text;
+ int bss_relocation = entry->bss_start_address -
+ entry->header.a_text - entry->header.a_data;
+ pc_relocation = dataseg?
+ entry->data_start_address - entry->header.a_text:
+ entry->text_start_address;
+
+ for (; r < end; r++) {
+ int addr = RELOC_ADDRESS(r);
+ long addend = md_get_addend(r, data+addr);
+ long relocation;
+
+ /*
+ * Loop over the relocations again as we did in
+ * consider_relocation(), claiming the reserved RRS
+ * relocations.
+ */
+
+ if (addr >= data_size)
+ errx(1, "%s: relocation address out of range",
+ get_file_name(entry));
+
+ if (RELOC_JMPTAB_P(r)) {
+
+ int symindex = RELOC_SYMBOL(r);
+ struct localsymbol *lsp = &entry->symbols[symindex];
+ symbol *sp;
+
+ if (symindex >= entry->nsymbols)
+ errx(1, "%s: relocation symbolnum out of range",
+ get_file_name(entry));
+
+ sp = lsp->symbol;
+ if (sp == NULL)
+ errx(1, "%s: bogus relocation record",
+ get_file_name(entry));
+ if (sp->alias)
+ sp = sp->alias;
+
+ if (relocatable_output)
+ relocation = addend;
+ else if (!RELOC_EXTERN_P(r)) {
+ relocation = addend +
+ data_relocation - text_relocation;
+ } else
+ relocation = addend +
+ claim_rrs_jmpslot(entry, r, sp, addend);
+
+ } else if (RELOC_BASEREL_P(r)) {
+
+ int symindex = RELOC_SYMBOL(r);
+ struct localsymbol *lsp = &entry->symbols[symindex];
+
+ if (symindex >= entry->nsymbols)
+ errx(1, "%s: relocation symbolnum out of range",
+ get_file_name(entry));
+
+ if (relocatable_output)
+ relocation = addend;
+ else if (!RELOC_EXTERN_P(r))
+ relocation = claim_rrs_internal_gotslot(
+ entry, r, lsp, addend);
+ else
+ relocation = claim_rrs_gotslot(
+ entry, r, lsp, addend);
+
+ } else if (RELOC_EXTERN_P(r)) {
+
+ int symindex = RELOC_SYMBOL(r);
+ symbol *sp;
+
+ if (symindex >= entry->nsymbols)
+ errx(1, "%s: relocation symbolnum out of range",
+ get_file_name(entry));
+
+ sp = entry->symbols[symindex].symbol;
+ if (sp == NULL)
+ errx(1, "%s: bogus relocation record",
+ get_file_name(entry));
+ if (sp->alias)
+ sp = sp->alias;
+
+ if (relocatable_output) {
+ relocation = addend;
+ /*
+ * In PIC code, we keep the reference to the
+ * external symbol, even if defined now.
+ */
+ if (!pic_code_seen)
+ relocation += sp->value;
+ } else if (sp->defined) {
+ if (sp->flags & GS_TRACE) {
+ fprintf(stderr,
+ "symbol %s defined as %x in %s\n",
+ sp->name, sp->defined,
+ get_file_name(entry) );
+ }
+ if (sp == got_symbol) {
+ /* Handle _GOT_ refs */
+ relocation = addend + sp->value
+ + md_got_reloc(r);
+ } else if (building_shared_object) {
+ /*
+ * Normal (non-PIC) relocation needs
+ * to be converted into an RRS reloc
+ * when building a shared object.
+ */
+ r->r_address += dataseg?
+ entry->data_start_address:
+ entry->text_start_address;
+ relocation = addend;
+ if (claim_rrs_reloc(
+ entry, r, sp, &relocation))
+ continue;
+ } else if (sp->defined == N_SIZE) {
+ /*
+ * If size is known, arrange a
+ * run-time copy.
+ */
+ if (!sp->size)
+ errx(1, "Copy item isn't: %s",
+ sp->name);
+
+ relocation = addend + sp->value;
+ r->r_address = sp->value;
+ claim_rrs_cpy_reloc(entry, r, sp);
+ } else
+ /* Plain old relocation */
+ relocation = addend + sp->value;
+ } else {
+ /*
+ * If the symbol is undefined, we relocate it
+ * in a way similar to -r case. We use an
+ * RRS relocation to resolve the symbol at
+ * run-time. The r_address field is updated
+ * to reflect the changed position in the
+ * output file.
+ */
+ if (sp->flags & GS_TRACE) {
+ fprintf(stderr,
+ "symbol %s claims RRS in %s%s\n",
+ sp->name, get_file_name(entry),
+ (sp->so_defined == (N_TEXT+N_EXT) &&
+ sp->flags & GS_HASJMPSLOT)?
+ " (JMPSLOT)":"");
+ }
+ if (sp->so_defined == (N_TEXT+N_EXT) &&
+ sp->flags & GS_HASJMPSLOT) {
+ /*
+ * Claim a jmpslot if one was allocated.
+ *
+ * At this point, a jmpslot can only
+ * result from a shared object reference
+ * while `force_alias' is in effect.
+ */
+ relocation = addend +
+ claim_rrs_jmpslot(
+ entry, r, sp, addend);
+ } else {
+ r->r_address += dataseg?
+ entry->data_start_address:
+ entry->text_start_address;
+ relocation = addend;
+ if ((building_shared_object ||
+ sp->so_defined) &&
+ claim_rrs_reloc(entry, r, sp,
+ &relocation))
+ continue;
+ }
+ }
+
+ } else {
+
+ switch (RELOC_TYPE(r)) {
+ case N_TEXT:
+ case N_TEXT | N_EXT:
+ relocation = addend + text_relocation;
+ break;
+
+ case N_DATA:
+ case N_DATA | N_EXT:
+ /*
+ * A word that points to beginning of the the
+ * data section initially contains not 0 but
+ * rather the "address" of that section in
+ * the input file, which is the length of the
+ * file's text.
+ */
+ relocation = addend + data_relocation;
+ break;
+
+ case N_BSS:
+ case N_BSS | N_EXT:
+ /*
+ * Similarly, an input word pointing to the
+ * beginning of the bss initially contains
+ * the length of text plus data of the file.
+ */
+ relocation = addend + bss_relocation;
+ break;
+
+ case N_ABS:
+ case N_ABS | N_EXT:
+ /*
+ * Don't know why this code would occur, but
+ * apparently it does.
+ */
+ break;
+
+ default:
+ errx(1, "%s: nonexternal relocation invalid",
+ get_file_name(entry));
+ }
+
+ /*
+ * When building a shared object, these segment
+ * relocations need a "load address relative"
+ * RRS fixup.
+ */
+ if (building_shared_object && !RELOC_PCREL_P(r)) {
+ r->r_address += dataseg?
+ entry->data_start_address:
+ entry->text_start_address;
+ claim_rrs_segment_reloc(entry, r);
+ }
+ }
+
+ if (RELOC_PCREL_P(r))
+ relocation -= pc_relocation;
+
+ md_relocate(r, relocation, data+addr, relocatable_output);
+
+ }
+}
+
+
+/*
+ * For relocatable_output only: write out the relocation,
+ * relocating the addresses-to-be-relocated.
+ */
+void
+write_rel()
+{
+ int count = 0;
+
+ if (trace_files)
+ fprintf(stderr, "Writing text relocation:\n\n");
+
+ /*
+ * Assign each global symbol a sequence number, giving the order
+ * in which `write_syms' will write it.
+ * This is so we can store the proper symbolnum fields
+ * in relocation entries we write.
+ */
+
+ /* BLECH - Assign number 0 to __DYNAMIC (!! Sun compatibility) */
+
+ if (dynamic_symbol->flags & GS_REFERENCED)
+ dynamic_symbol->symbolnum = count++;
+ FOR_EACH_SYMBOL(i, sp) {
+ if (sp == dynamic_symbol)
+ continue;
+ if (sp->warning)
+ count += 2;
+ if (!(sp->flags & GS_REFERENCED))
+ continue;
+ sp->symbolnum = count++;
+ if (sp->size)
+ count++;
+ if (sp->alias)
+ count++;
+ } END_EACH_SYMBOL;
+
+ if (count != global_sym_count)
+ errx(1, "internal error: write_rel: count = %d", count);
+
+ each_full_file(assign_symbolnums, &count);
+
+ /* Write out the relocations of all files, remembered from copy_text. */
+ each_full_file(coptxtrel, 0);
+
+ if (trace_files)
+ fprintf(stderr, "\nWriting data relocation:\n\n");
+
+ each_full_file(copdatrel, 0);
+
+ if (trace_files)
+ fprintf(stderr, "\n");
+}
+
+
+/*
+ * Assign symbol ordinal numbers to local symbols in each entry.
+ */
+static void
+assign_symbolnums(entry, countp)
+ struct file_entry *entry;
+ int *countp;
+{
+ struct localsymbol *lsp, *lspend;
+ int n = *countp;
+
+ lspend = entry->symbols + entry->nsymbols;
+
+ if (discard_locals != DISCARD_ALL)
+ /* Count the N_FN symbol for this entry */
+ n++;
+
+ for (lsp = entry->symbols; lsp < lspend; lsp++) {
+ if (lsp->flags & LS_WRITE)
+ lsp->symbolnum = n++;
+ }
+ *countp = n;
+}
+
+static void
+coptxtrel(entry)
+ struct file_entry *entry;
+{
+ register struct relocation_info *r, *end;
+ register int reloc = entry->text_start_address;
+
+ r = entry->textrel;
+ end = r + entry->ntextrel;
+
+ for (; r < end; r++) {
+ register int symindex;
+ struct localsymbol *lsp;
+ symbol *sp;
+
+ RELOC_ADDRESS(r) += reloc;
+
+ symindex = RELOC_SYMBOL(r);
+ lsp = &entry->symbols[symindex];
+
+ if (!RELOC_EXTERN_P(r)) {
+ if (!pic_code_seen)
+ continue;
+ if (RELOC_BASEREL_P(r))
+ RELOC_SYMBOL(r) = lsp->symbolnum;
+ continue;
+ }
+
+ if (symindex >= entry->nsymbols)
+ errx(1, "%s: relocation symbolnum out of range",
+ get_file_name(entry));
+
+ sp = lsp->symbol;
+
+#ifdef N_INDR
+ /* Resolve indirection. */
+ if ((sp->defined & ~N_EXT) == N_INDR) {
+ if (sp->alias == NULL)
+ errx(1, "internal error: alias in hyperspace");
+ sp = sp->alias;
+ }
+#endif
+
+ /*
+ * If the symbol is now defined, change the external
+ * relocation to an internal one.
+ */
+
+ if (sp->defined) {
+ if (!pic_code_seen) {
+ RELOC_EXTERN_P(r) = 0;
+ RELOC_SYMBOL(r) = (sp->defined & N_TYPE);
+ } else
+ RELOC_SYMBOL(r) = sp->symbolnum;
+#ifdef RELOC_ADD_EXTRA
+ /*
+ * If we aren't going to be adding in the
+ * value in memory on the next pass of the
+ * loader, then we need to add it in from the
+ * relocation entry, unless the symbol remains
+ * external in our output. Otherwise the work we
+ * did in this pass is lost.
+ */
+ if (!RELOC_MEMORY_ADD_P(r) && !RELOC_EXTERN_P(r))
+ RELOC_ADD_EXTRA(r) += sp->value;
+#endif
+ } else
+ /*
+ * Global symbols come first.
+ */
+ RELOC_SYMBOL(r) = sp->symbolnum;
+ }
+ md_swapout_reloc(entry->textrel, entry->ntextrel);
+ mywrite(entry->textrel, entry->ntextrel,
+ sizeof(struct relocation_info), outstream);
+}
+
+static void
+copdatrel(entry)
+ struct file_entry *entry;
+{
+ register struct relocation_info *r, *end;
+ /*
+ * Relocate the address of the relocation. Old address is relative to
+ * start of the input file's data section. New address is relative to
+ * start of the output file's data section.
+ */
+ register int reloc = entry->data_start_address - text_size;
+
+ r = entry->datarel;
+ end = r + entry->ndatarel;
+
+ for (; r < end; r++) {
+ register int symindex;
+ symbol *sp;
+ int symtype;
+
+ RELOC_ADDRESS(r) += reloc;
+
+ if (!RELOC_EXTERN_P(r)) {
+ if (RELOC_BASEREL_P(r))
+ errx(1, "%s: Unsupported relocation type",
+ get_file_name(entry));
+ continue;
+ }
+
+ symindex = RELOC_SYMBOL(r);
+ sp = entry->symbols[symindex].symbol;
+
+ if (symindex >= entry->header.a_syms)
+ errx(1, "%s: relocation symbolnum out of range",
+ get_file_name(entry));
+
+#ifdef N_INDR
+ /* Resolve indirection. */
+ if ((sp->defined & ~N_EXT) == N_INDR) {
+ if (sp->alias == NULL)
+ errx(1, "internal error: alias in hyperspace");
+ sp = sp->alias;
+ }
+#endif
+
+ symtype = sp->defined & N_TYPE;
+
+ if (!pic_code_seen && ( symtype == N_BSS ||
+ symtype == N_DATA ||
+ symtype == N_TEXT ||
+ symtype == N_ABS)) {
+ RELOC_EXTERN_P(r) = 0;
+ RELOC_SYMBOL(r) = symtype;
+ } else
+ /*
+ * Global symbols come first.
+ */
+ RELOC_SYMBOL(r) =
+ entry->symbols[symindex].symbol->symbolnum;
+ }
+ md_swapout_reloc(entry->datarel, entry->ndatarel);
+ mywrite(entry->datarel, entry->ndatarel,
+ sizeof(struct relocation_info), outstream);
+}
+
+void write_file_syms __P((struct file_entry *, int *));
+void write_string_table __P((void));
+
+/* Offsets and current lengths of symbol and string tables in output file. */
+
+static int symtab_offset;
+static int symtab_len;
+
+/* Address in output file where string table starts. */
+static int strtab_offset;
+
+/* Offset within string table
+ where the strings in `strtab_vector' should be written. */
+static int strtab_len;
+
+/* Total size of string table strings allocated so far,
+ including strings in `strtab_vector'. */
+static int strtab_size;
+
+/* Vector whose elements are strings to be added to the string table. */
+static char **strtab_vector;
+
+/* Vector whose elements are the lengths of those strings. */
+static int *strtab_lens;
+
+/* Index in `strtab_vector' at which the next string will be stored. */
+static int strtab_index;
+
+/*
+ * Add the string NAME to the output file string table. Record it in
+ * `strtab_vector' to be output later. Return the index within the string
+ * table that this string will have.
+ */
+
+static int
+assign_string_table_index(name)
+ char *name;
+{
+ register int index = strtab_size;
+ register int len = strlen(name) + 1;
+
+ strtab_size += len;
+ strtab_vector[strtab_index] = name;
+ strtab_lens[strtab_index++] = len;
+
+ return index;
+}
+
+/*
+ * Write the contents of `strtab_vector' into the string table. This is done
+ * once for each file's local&debugger symbols and once for the global
+ * symbols.
+ */
+void
+write_string_table()
+{
+ register int i;
+
+ if (fseek(outstream, strtab_offset + strtab_len, SEEK_SET) != 0)
+ err(1, "write_string_table: %s: fseek", output_filename);
+
+ for (i = 0; i < strtab_index; i++) {
+ mywrite(strtab_vector[i], 1, strtab_lens[i], outstream);
+ strtab_len += strtab_lens[i];
+ }
+}
+
+/* Write the symbol table and string table of the output file. */
+
+void
+write_syms()
+{
+ /* Number of symbols written so far. */
+ int syms_written = 0;
+ struct nlist nl;
+
+ /*
+ * Buffer big enough for all the global symbols. One extra struct
+ * for each indirect symbol to hold the extra reference following.
+ */
+ struct nlist *buf = (struct nlist *)
+ alloca(global_sym_count * sizeof(struct nlist));
+ /* Pointer for storing into BUF. */
+ register struct nlist *bufp = buf;
+
+ /* Size of string table includes the bytes that store the size. */
+ strtab_size = sizeof strtab_size;
+
+ symtab_offset = N_SYMOFF(outheader);
+ symtab_len = 0;
+ strtab_offset = N_STROFF(outheader);
+ strtab_len = strtab_size;
+
+ if (strip_symbols == STRIP_ALL)
+ return;
+
+ /* First, write out the global symbols. */
+
+ /*
+ * Allocate two vectors that record the data to generate the string
+ * table from the global symbols written so far. This must include
+ * extra space for the references following indirect outputs.
+ */
+
+ strtab_vector = (char **)alloca((global_sym_count) * sizeof(char *));
+ strtab_lens = (int *)alloca((global_sym_count) * sizeof(int));
+ strtab_index = 0;
+
+ /*
+ * __DYNAMIC symbol *must* be first for Sun compatibility, as Sun's
+ * ld.so reads the shared object's first symbol. This means that
+ * (Sun's) shared libraries cannot be stripped! (We only assume
+ * that __DYNAMIC is the first item in the data segment)
+ *
+ * If defined (ie. not relocatable_output), make it look
+ * like an internal symbol.
+ */
+ if (dynamic_symbol->flags & GS_REFERENCED) {
+ nl.n_other = 0;
+ nl.n_desc = 0;
+ nl.n_type = dynamic_symbol->defined;
+ if (nl.n_type == N_UNDF)
+ nl.n_type |= N_EXT;
+ else
+ nl.n_type &= ~N_EXT;
+ nl.n_value = dynamic_symbol->value;
+ nl.n_un.n_strx = assign_string_table_index(dynamic_symbol->name);
+ *bufp++ = nl;
+ syms_written++;
+ }
+
+ /* Scan the symbol hash table, bucket by bucket. */
+
+ FOR_EACH_SYMBOL(i, sp) {
+
+ if (sp == dynamic_symbol)
+ /* Already dealt with above */
+ continue;
+
+ /*
+ * Propagate N_WARNING symbols.
+ */
+ if ((relocatable_output || building_shared_object)
+ && sp->warning) {
+ nl.n_type = N_WARNING;
+ nl.n_un.n_strx = assign_string_table_index(sp->warning);
+ nl.n_value = 0;
+ nl.n_other = 0;
+ nl.n_desc = 0;
+ *bufp++ = nl;
+ syms_written++;
+
+ nl.n_type = N_UNDF + N_EXT;
+ nl.n_un.n_strx = assign_string_table_index(sp->name);
+ nl.n_value = 0;
+ nl.n_other = 0;
+ nl.n_desc = 0;
+ *bufp++ = nl;
+ syms_written++;
+ }
+
+ if (!(sp->flags & GS_REFERENCED))
+ /* Came from shared object but was not used */
+ continue;
+
+ if (sp->so_defined || (sp->alias && sp->alias->so_defined))
+ /*
+ * Definition came from shared object,
+ * don't mention it here
+ */
+ continue;
+
+ if (!sp->defined && !relocatable_output) {
+ /*
+ * We're building a shared object and there
+ * are still undefined symbols. Don't output
+ * these, symbol was discounted in digest_pass1()
+ * (they are in the RRS symbol table).
+ */
+ if (building_shared_object)
+ continue;
+ if (!(sp->flags & GS_WEAK))
+ warnx("symbol %s remains undefined", sp->name);
+ }
+
+ if (syms_written >= global_sym_count)
+ errx(1,
+ "internal error: number of symbols exceeds alloc'd %d",
+ global_sym_count);
+
+ /*
+ * Construct a `struct nlist' for the symbol.
+ */
+ nl.n_other = 0;
+ nl.n_desc = 0;
+
+ if (sp->defined > 1) {
+ /*
+ * defined with known type
+ */
+ if (!relocatable_output && !building_shared_object &&
+ sp->alias && sp->alias->defined > 1) {
+ /*
+ * If the target of an indirect symbol has
+ * been defined and we are outputting an
+ * executable, resolve the indirection; it's
+ * no longer needed.
+ */
+ nl.n_type = sp->alias->defined;
+ nl.n_value = sp->alias->value;
+ nl.n_other = N_OTHER(0, sp->alias->aux);
+ } else {
+ int bind = 0;
+
+ if (sp->defined == N_SIZE)
+ nl.n_type = N_DATA | N_EXT;
+ else
+ nl.n_type = sp->defined;
+ if (nl.n_type == (N_INDR|N_EXT) &&
+ sp->value != 0)
+ errx(1, "%s: N_INDR has value %#x",
+ sp->name, sp->value);
+ nl.n_value = sp->value;
+ if (sp->def_lsp)
+ bind = N_BIND(&sp->def_lsp->nzlist.nlist);
+ nl.n_other = N_OTHER(bind, sp->aux);
+ }
+
+ } else if (sp->common_size) {
+ /*
+ * defined as common but not allocated,
+ * happens only with -r and not -d, write out
+ * a common definition.
+ *
+ * common condition needs to be before undefined
+ * condition because unallocated commons are set
+ * undefined in digest_symbols.
+ */
+ nl.n_type = N_UNDF | N_EXT;
+ nl.n_value = sp->common_size;
+ } else if (!sp->defined) {
+ /* undefined -- legit only if -r */
+ nl.n_type = N_UNDF | N_EXT;
+ nl.n_value = 0;
+ } else
+ errx(1,
+ "internal error: %s defined in mysterious way",
+ sp->name);
+
+ /*
+ * Allocate string table space for the symbol name.
+ */
+
+ nl.n_un.n_strx = assign_string_table_index(sp->name);
+
+ /* Output to the buffer and count it. */
+
+ *bufp++ = nl;
+ syms_written++;
+
+ /*
+ * Write second symbol of an alias pair.
+ */
+ if (nl.n_type == N_INDR + N_EXT) {
+ if (sp->alias == NULL)
+ errx(1, "internal error: alias in hyperspace");
+ nl.n_type = N_UNDF + N_EXT;
+ nl.n_un.n_strx =
+ assign_string_table_index(sp->alias->name);
+ nl.n_value = 0;
+ nl.n_other = 0;
+ nl.n_desc = 0;
+ *bufp++ = nl;
+ syms_written++;
+ }
+
+ /*
+ * Write N_SIZE symbol for a symbol with a known size.
+ */
+ if (relocatable_output && sp->size) {
+ nl.n_type = N_SIZE + N_EXT;
+ nl.n_un.n_strx = assign_string_table_index(sp->name);
+ nl.n_value = sp->size;
+ nl.n_other = 0;
+ nl.n_desc = 0;
+ *bufp++ = nl;
+ syms_written++;
+ }
+
+#ifdef DEBUG
+printf("writesym(#%d): %s, type %x\n", syms_written, sp->name, sp->defined);
+#endif
+ } END_EACH_SYMBOL;
+
+ if (syms_written != strtab_index || strtab_index != global_sym_count)
+ errx(1, "internal error: wrong number (%d) of global symbols "
+ "written into output file, should be %d",
+ syms_written, global_sym_count);
+
+ /* Output the buffer full of `struct nlist's. */
+
+ if (fseek(outstream, symtab_offset + symtab_len, SEEK_SET) != 0)
+ err(1, "write_syms: fseek");
+ md_swapout_symbols(buf, bufp - buf);
+ mywrite(buf, bufp - buf, sizeof(struct nlist), outstream);
+ symtab_len += sizeof(struct nlist) * (bufp - buf);
+
+ /* Write the strings for the global symbols. */
+ write_string_table();
+
+ /* Write the local symbols defined by the various files. */
+ each_file(write_file_syms, (void *)&syms_written);
+ file_close();
+
+ if (syms_written != nsyms)
+ errx(1, "internal error: wrong number of symbols (%d) "
+ "written into output file, should be %d",
+ syms_written, nsyms);
+
+ if (symtab_offset + symtab_len != strtab_offset)
+ errx(1,
+ "internal error: inconsistent symbol table length: %d vs %s",
+ symtab_offset + symtab_len, strtab_offset);
+
+ if (fseek(outstream, strtab_offset, SEEK_SET) != 0)
+ err(1, "write_syms: fseek");
+ strtab_size = md_swap_long(strtab_size);
+ mywrite(&strtab_size, sizeof(int), 1, outstream);
+}
+
+
+/*
+ * Write the local and debugger symbols of file ENTRY. Increment
+ * *SYMS_WRITTEN_ADDR for each symbol that is written.
+ */
+
+/*
+ * Note that we do not combine identical names of local symbols. dbx or gdb
+ * would be confused if we did that.
+ */
+void
+write_file_syms(entry, syms_written_addr)
+ struct file_entry *entry;
+ int *syms_written_addr;
+{
+ struct localsymbol *lsp, *lspend;
+
+ /* Upper bound on number of syms to be written here. */
+ int max_syms = entry->nsymbols + 1;
+
+ /*
+ * Buffer to accumulate all the syms before writing them. It has one
+ * extra slot for the local symbol we generate here.
+ */
+ struct nlist *buf = (struct nlist *)
+ alloca(max_syms * sizeof(struct nlist));
+
+ register struct nlist *bufp = buf;
+
+ if (entry->flags & E_DYNAMIC)
+ return;
+
+ /*
+ * Make tables that record, for each symbol, its name and its name's
+ * length. The elements are filled in by `assign_string_table_index'.
+ */
+
+ strtab_vector = (char **)alloca(max_syms * sizeof(char *));
+ strtab_lens = (int *)alloca(max_syms * sizeof(int));
+ strtab_index = 0;
+
+ /* Generate a local symbol for the start of this file's text. */
+
+ if (discard_locals != DISCARD_ALL) {
+ struct nlist nl;
+
+ nl.n_type = N_FN | N_EXT;
+ nl.n_un.n_strx =
+ assign_string_table_index(entry->local_sym_name);
+ nl.n_value = entry->text_start_address;
+ nl.n_desc = 0;
+ nl.n_other = 0;
+ *bufp++ = nl;
+ (*syms_written_addr)++;
+ }
+ /* Read the file's string table. */
+
+ entry->strings = (char *)alloca(entry->string_size);
+ read_entry_strings(file_open(entry), entry);
+
+ lspend = entry->symbols + entry->nsymbols;
+
+ for (lsp = entry->symbols; lsp < lspend; lsp++) {
+ register struct nlist *p = &lsp->nzlist.nlist;
+ char *name;
+
+ if (!(lsp->flags & LS_WRITE))
+ continue;
+
+ if (p->n_un.n_strx == 0)
+ name = NULL;
+ else if (!(lsp->flags & LS_RENAME))
+ name = p->n_un.n_strx + entry->strings;
+ else {
+ char *cp = p->n_un.n_strx + entry->strings;
+ name = (char *)alloca(
+ strlen(entry->local_sym_name) +
+ strlen(cp) + 2 );
+ (void)sprintf(name, "%s.%s", entry->local_sym_name, cp);
+ }
+
+ /*
+ * If this symbol has a name, allocate space for it
+ * in the output string table.
+ */
+
+ if (name)
+ p->n_un.n_strx = assign_string_table_index(name);
+
+ /* Output this symbol to the buffer and count it. */
+
+ *bufp++ = *p;
+ (*syms_written_addr)++;
+ }
+
+ /* All the symbols are now in BUF; write them. */
+
+ if (fseek(outstream, symtab_offset + symtab_len, SEEK_SET) != 0)
+ err(1, "write local symbols: fseek");
+ md_swapout_symbols(buf, bufp - buf);
+ mywrite(buf, bufp - buf, sizeof(struct nlist), outstream);
+ symtab_len += sizeof(struct nlist) * (bufp - buf);
+
+ /*
+ * Write the string-table data for the symbols just written, using
+ * the data in vectors `strtab_vector' and `strtab_lens'.
+ */
+
+ write_string_table();
+ entry->strings = 0; /* Since it will disappear anyway. */
+}
+
+/*
+ * Parse the string ARG using scanf format FORMAT, and return the result.
+ * If it does not parse, report fatal error
+ * generating the error message using format string ERROR and ARG as arg.
+ */
+
+static int
+parse(arg, format, error)
+ char *arg, *format, *error;
+{
+ int x;
+
+ if (1 != sscanf(arg, format, &x))
+ errx(1, error, arg);
+ return x;
+}
+
+/*
+ * Output COUNT*ELTSIZE bytes of data at BUF to the descriptor FD.
+ */
+void
+mywrite(buf, count, eltsize, fd)
+ void *buf;
+ int count;
+ int eltsize;
+ FILE *fd;
+{
+
+ if (fwrite(buf, eltsize, count, fd) != count)
+ err(1, "write");
+}
+
+static void
+cleanup()
+{
+ struct stat statbuf;
+
+ if (outstream == 0)
+ return;
+
+ if (fstat(fileno(outstream), &statbuf) == 0) {
+ if (S_ISREG(statbuf.st_mode))
+ (void)unlink(output_filename);
+ }
+}
+
+/*
+ * Output PADDING zero-bytes to descriptor FD.
+ * PADDING may be negative; in that case, do nothing.
+ */
+void
+padfile(padding, fd)
+ int padding;
+ FILE *fd;
+{
+ register char *buf;
+ if (padding <= 0)
+ return;
+
+ buf = (char *)alloca(padding);
+ bzero(buf, padding);
+ mywrite(buf, padding, 1, fd);
+}
diff --git a/gnu/usr.bin/ld/ld.h b/gnu/usr.bin/ld/ld.h
new file mode 100644
index 0000000..468dbff
--- /dev/null
+++ b/gnu/usr.bin/ld/ld.h
@@ -0,0 +1,702 @@
+/*
+ * $Id: ld.h,v 1.14 1995/05/30 05:01:45 rgrimes Exp $
+ */
+/*-
+ * This code is derived from software copyrighted by the Free Software
+ * Foundation.
+ *
+ * Modified 1991 by Donn Seeley at UUNET Technologies, Inc.
+ */
+
+#define SUN_COMPAT
+
+#ifndef N_SIZE
+#define N_SIZE 0xc
+#endif
+
+#ifndef min
+#define min(a,b) ((a) < (b) ? (a) : (b))
+#endif
+
+#ifndef __P
+#ifndef __STDC__
+#define __P(a) ()
+#else
+#define __P(a) a
+#endif
+#endif
+
+/* If compiled with GNU C, use the built-in alloca */
+#if defined(__GNUC__) || defined(sparc)
+#define alloca __builtin_alloca
+#endif
+
+#include "md.h"
+#include "link.h"
+
+/* Macro to control the number of undefined references printed */
+#define MAX_UREFS_PRINTED 10
+
+/* Align to power-of-two boundary */
+#define PALIGN(x,p) (((x) + (u_long)(p) - 1) & (-(u_long)(p)))
+
+/* Align to machine dependent boundary */
+#define MALIGN(x) PALIGN(x,MAX_ALIGNMENT)
+
+/* Define this to specify the default executable format. */
+#ifndef DEFAULT_MAGIC
+#ifdef __FreeBSD__
+#define DEFAULT_MAGIC QMAGIC
+extern int netzmagic;
+#else
+#define DEFAULT_MAGIC ZMAGIC
+#endif
+#endif
+
+
+/*
+ * Ok. Following are the relocation information macros. If your
+ * system should not be able to use the default set (below), you must
+ * define the following:
+
+ * relocation_info: This must be typedef'd (or #define'd) to the type
+ * of structure that is stored in the relocation info section of your
+ * a.out files. Often this is defined in the a.out.h for your system.
+ *
+ * RELOC_ADDRESS (rval): Offset into the current section of the
+ * <whatever> to be relocated. *Must be an lvalue*.
+ *
+ * RELOC_EXTERN_P (rval): Is this relocation entry based on an
+ * external symbol (1), or was it fully resolved upon entering the
+ * loader (0) in which case some combination of the value in memory
+ * (if RELOC_MEMORY_ADD_P) and the extra (if RELOC_ADD_EXTRA) contains
+ * what the value of the relocation actually was. *Must be an lvalue*.
+ *
+ * RELOC_TYPE (rval): If this entry was fully resolved upon
+ * entering the loader, what type should it be relocated as?
+ *
+ * RELOC_SYMBOL (rval): If this entry was not fully resolved upon
+ * entering the loader, what is the index of it's symbol in the symbol
+ * table? *Must be a lvalue*.
+ *
+ * RELOC_MEMORY_ADD_P (rval): This should return true if the final
+ * relocation value output here should be added to memory, or if the
+ * section of memory described should simply be set to the relocation
+ * value.
+ *
+ * RELOC_ADD_EXTRA (rval): (Optional) This macro, if defined, gives
+ * an extra value to be added to the relocation value based on the
+ * individual relocation entry. *Must be an lvalue if defined*.
+ *
+ * RELOC_PCREL_P (rval): True if the relocation value described is
+ * pc relative.
+ *
+ * RELOC_VALUE_RIGHTSHIFT (rval): Number of bits right to shift the
+ * final relocation value before putting it where it belongs.
+ *
+ * RELOC_TARGET_SIZE (rval): log to the base 2 of the number of
+ * bytes of size this relocation entry describes; 1 byte == 0; 2 bytes
+ * == 1; 4 bytes == 2, and etc. This is somewhat redundant (we could
+ * do everything in terms of the bit operators below), but having this
+ * macro could end up producing better code on machines without fancy
+ * bit twiddling. Also, it's easier to understand/code big/little
+ * endian distinctions with this macro.
+ *
+ * RELOC_TARGET_BITPOS (rval): The starting bit position within the
+ * object described in RELOC_TARGET_SIZE in which the relocation value
+ * will go.
+ *
+ * RELOC_TARGET_BITSIZE (rval): How many bits are to be replaced
+ * with the bits of the relocation value. It may be assumed by the
+ * code that the relocation value will fit into this many bits. This
+ * may be larger than RELOC_TARGET_SIZE if such be useful.
+ *
+ *
+ * Things I haven't implemented
+ * ----------------------------
+ *
+ * Values for RELOC_TARGET_SIZE other than 0, 1, or 2.
+ *
+ * Pc relative relocation for External references.
+ *
+ *
+ */
+
+
+/* Default macros */
+#ifndef RELOC_ADDRESS
+
+#define RELOC_ADDRESS(r) ((r)->r_address)
+#define RELOC_EXTERN_P(r) ((r)->r_extern)
+#define RELOC_TYPE(r) ((r)->r_symbolnum)
+#define RELOC_SYMBOL(r) ((r)->r_symbolnum)
+#define RELOC_MEMORY_SUB_P(r) 0
+#define RELOC_MEMORY_ADD_P(r) 1
+#undef RELOC_ADD_EXTRA
+#define RELOC_PCREL_P(r) ((r)->r_pcrel)
+#define RELOC_VALUE_RIGHTSHIFT(r) 0
+#if defined(RTLD) && defined(SUN_COMPAT)
+#define RELOC_TARGET_SIZE(r) (2) /* !!!!! Sun BUG compatible */
+#else
+#define RELOC_TARGET_SIZE(r) ((r)->r_length)
+#endif
+#define RELOC_TARGET_BITPOS(r) 0
+#define RELOC_TARGET_BITSIZE(r) 32
+
+#define RELOC_JMPTAB_P(r) ((r)->r_jmptable)
+#define RELOC_BASEREL_P(r) ((r)->r_baserel)
+#define RELOC_RELATIVE_P(r) ((r)->r_relative)
+#define RELOC_COPY_P(r) ((r)->r_copy)
+#define RELOC_LAZY_P(r) ((r)->r_jmptable)
+
+#define CHECK_GOT_RELOC(r) ((r)->r_pcrel)
+
+#define RELOC_INIT_SEGMENT_RELOC(r)
+
+#endif
+
+#ifndef MAX_GOTOFF
+#define MAX_GOTOFF (LONG_MAX)
+#endif
+
+#ifndef MIN_GOTOFF
+#define MIN_GOTOFF (LONG_MIN)
+#endif
+
+/*
+ * Internal representation of relocation types
+ */
+#define RELTYPE_EXTERN 1
+#define RELTYPE_JMPSLOT 2
+#define RELTYPE_BASEREL 4
+#define RELTYPE_RELATIVE 8
+#define RELTYPE_COPY 16
+
+#ifdef nounderscore
+#define LPREFIX '.'
+#else
+#define LPREFIX 'L'
+#endif
+
+#ifndef TEXT_START
+#define TEXT_START(x) N_TXTADDR(x)
+#endif
+
+#ifndef DATA_START
+#define DATA_START(x) N_DATADDR(x)
+#endif
+
+/* If a this type of symbol is encountered, its name is a warning
+ message to print each time the symbol referenced by the next symbol
+ table entry is referenced.
+
+ This feature may be used to allow backwards compatibility with
+ certain functions (eg. gets) but to discourage programmers from
+ their use.
+
+ So if, for example, you wanted to have ld print a warning whenever
+ the function "gets" was used in their C program, you would add the
+ following to the assembler file in which gets is defined:
+
+ .stabs "Obsolete function \"gets\" referenced",30,0,0,0
+ .stabs "_gets",1,0,0,0
+
+ These .stabs do not necessarily have to be in the same file as the
+ gets function, they simply must exist somewhere in the compilation. */
+
+#ifndef N_WARNING
+#define N_WARNING 0x1E /* Warning message to print if symbol
+ included */
+#endif /* This is input to ld */
+
+/* Special global symbol types understood by GNU LD. */
+
+/* The following type indicates the definition of a symbol as being
+ an indirect reference to another symbol. The other symbol
+ appears as an undefined reference, immediately following this symbol.
+
+ Indirection is asymmetrical. The other symbol's value will be used
+ to satisfy requests for the indirect symbol, but not vice versa.
+ If the other symbol does not have a definition, libraries will
+ be searched to find a definition.
+
+ So, for example, the following two lines placed in an assembler
+ input file would result in an object file which would direct gnu ld
+ to resolve all references to symbol "foo" as references to symbol
+ "bar".
+
+ .stabs "_foo",11,0,0,0
+ .stabs "_bar",1,0,0,0
+
+ Note that (11 == (N_INDR | N_EXT)) and (1 == (N_UNDF | N_EXT)). */
+
+#ifndef N_INDR
+#define N_INDR 0xa
+#endif
+
+/* The following symbols refer to set elements. These are expected
+ only in input to the loader; they should not appear in loader
+ output (unless relocatable output is requested). To be recognized
+ by the loader, the input symbols must have their N_EXT bit set.
+ All the N_SET[ATDB] symbols with the same name form one set. The
+ loader collects all of these elements at load time and outputs a
+ vector for each name.
+ Space (an array of 32 bit words) is allocated for the set in the
+ data section, and the n_value field of each set element value is
+ stored into one word of the array.
+ The first word of the array is the length of the set (number of
+ elements). The last word of the vector is set to zero for possible
+ use by incremental loaders. The array is ordered by the linkage
+ order; the first symbols which the linker encounters will be first
+ in the array.
+
+ In C syntax this looks like:
+
+ struct set_vector {
+ unsigned int length;
+ unsigned int vector[length];
+ unsigned int always_zero;
+ };
+
+ Before being placed into the array, each element is relocated
+ according to its type. This allows the loader to create an array
+ of pointers to objects automatically. N_SETA type symbols will not
+ be relocated.
+
+ The address of the set is made into an N_SETV symbol
+ whose name is the same as the name of the set.
+ This symbol acts like a N_DATA global symbol
+ in that it can satisfy undefined external references.
+
+ For the purposes of determining whether or not to load in a library
+ file, set element definitions are not considered "real
+ definitions"; they will not cause the loading of a library
+ member.
+
+ If relocatable output is requested, none of this processing is
+ done. The symbols are simply relocated and passed through to the
+ output file.
+
+ So, for example, the following three lines of assembler code
+ (whether in one file or scattered between several different ones)
+ will produce a three element vector (total length is five words;
+ see above), referenced by the symbol "_xyzzy", which will have the
+ addresses of the routines _init1, _init2, and _init3.
+
+ *NOTE*: If symbolic addresses are used in the n_value field of the
+ defining .stabs, those symbols must be defined in the same file as
+ that containing the .stabs.
+
+ .stabs "_xyzzy",23,0,0,_init1
+ .stabs "_xyzzy",23,0,0,_init2
+ .stabs "_xyzzy",23,0,0,_init3
+
+ Note that (23 == (N_SETT | N_EXT)). */
+
+#ifndef N_SETA
+#define N_SETA 0x14 /* Absolute set element symbol */
+#endif /* This is input to LD, in a .o file. */
+
+#ifndef N_SETT
+#define N_SETT 0x16 /* Text set element symbol */
+#endif /* This is input to LD, in a .o file. */
+
+#ifndef N_SETD
+#define N_SETD 0x18 /* Data set element symbol */
+#endif /* This is input to LD, in a .o file. */
+
+#ifndef N_SETB
+#define N_SETB 0x1A /* Bss set element symbol */
+#endif /* This is input to LD, in a .o file. */
+
+/* Macros dealing with the set element symbols defined in a.out.h */
+#define SET_ELEMENT_P(x) ((x) >= N_SETA && (x) <= (N_SETB|N_EXT))
+#define TYPE_OF_SET_ELEMENT(x) ((x) - N_SETA + N_ABS)
+
+#ifndef N_SETV
+#define N_SETV 0x1C /* Pointer to set vector in data area. */
+#endif /* This is output from LD. */
+
+
+#ifndef __GNU_STAB__
+/* Line number for the data section. This is to be used to describe
+ the source location of a variable declaration. */
+#ifndef N_DSLINE
+#define N_DSLINE (N_SLINE+N_DATA-N_TEXT)
+#endif
+
+/* Line number for the bss section. This is to be used to describe
+ the source location of a variable declaration. */
+#ifndef N_BSLINE
+#define N_BSLINE (N_SLINE+N_BSS-N_TEXT)
+#endif
+#endif /* not __GNU_STAB__ */
+
+#define N_ISWEAK(p) (N_BIND(p) & BIND_WEAK)
+
+
+typedef struct localsymbol {
+ struct nzlist nzlist; /* n[z]list from file */
+ struct glosym *symbol; /* Corresponding global symbol,
+ if any */
+ struct localsymbol *next; /* List of definitions */
+ struct file_entry *entry; /* Backpointer to file */
+ long gotslot_offset; /* Position in GOT, if any */
+ int symbolnum; /* Position in output nlist */
+ int flags;
+#define LS_L_SYMBOL 1 /* Local symbol starts with an `L' */
+#define LS_WRITE 2 /* Symbol goes in output symtable */
+#define LS_RENAME 4 /* xlat name to `<file>.<name>' */
+#define LS_HASGOTSLOT 8 /* This symbol has a GOT entry */
+#define LS_WARNING 16 /* Second part of a N_WARNING duo */
+} localsymbol_t;
+
+/* Symbol table */
+
+/*
+ * Global symbol data is recorded in these structures, one for each global
+ * symbol. They are found via hashing in 'symtab', which points to a vector
+ * of buckets. Each bucket is a chain of these structures through the link
+ * field.
+ */
+
+typedef struct glosym {
+ struct glosym *link; /* Next symbol hash bucket. */
+ char *name; /* Name of this symbol. */
+ long value; /* Value of this symbol */
+ localsymbol_t *refs; /* Chain of local symbols from object
+ files pertaining to this global
+ symbol */
+ localsymbol_t *sorefs;/* Same for local symbols from shared
+ object files. */
+
+ char *warning; /* message, from N_WARNING nlists */
+ int common_size; /* Common size */
+ int symbolnum; /* Symbol index in output symbol table */
+ int rrs_symbolnum; /* Symbol index in RRS symbol table */
+
+ localsymbol_t *def_lsp; /* The local symbol that gave this
+ global symbol its definition */
+
+ char defined; /* Definition of this symbol */
+ char so_defined; /* Definition of this symbol in a shared
+ object. These go into the RRS symbol table */
+ u_char undef_refs; /* Count of number of "undefined"
+ messages printed for this symbol */
+ u_char mult_defs; /* Same for "multiply defined" symbols */
+ struct glosym *alias; /* For symbols of type N_INDR, this
+ points at the real symbol. */
+ int setv_count; /* Number of elements in N_SETV symbols */
+ int size; /* Size of this symbol (either from N_SIZE
+ symbols or a from shared object's RRS */
+ int aux; /* Auxiliary type information conveyed in
+ the `n_other' field of nlists */
+
+ /* The offset into one of the RRS tables, -1 if not used */
+ long jmpslot_offset;
+ long gotslot_offset;
+
+ long flags;
+
+#define GS_DEFINED 0x1 /* Symbol has definition (notyetused)*/
+#define GS_REFERENCED 0x2 /* Symbol is referred to by something
+ interesting */
+#define GS_TRACE 0x4 /* Symbol will be traced */
+#define GS_HASJMPSLOT 0x8 /* */
+#define GS_HASGOTSLOT 0x10 /* Some state bits concerning */
+#define GS_CPYRELOCRESERVED 0x20 /* entries in GOT and PLT tables */
+#define GS_CPYRELOCCLAIMED 0x40 /* */
+#define GS_WEAK 0x80 /* Symbol is weakly defined */
+
+} symbol;
+
+/* Number of buckets in symbol hash table */
+#define SYMTABSIZE 1009
+
+/* The symbol hash table: a vector of SYMTABSIZE pointers to struct glosym. */
+extern symbol *symtab[];
+#define FOR_EACH_SYMBOL(i,sp) { \
+ int i; \
+ for (i = 0; i < SYMTABSIZE; i++) { \
+ register symbol *sp; \
+ for (sp = symtab[i]; sp; sp = sp->link)
+
+#define END_EACH_SYMBOL }}
+
+/* # of global symbols referenced and not defined. */
+extern int undefined_global_sym_count;
+
+/* # of weak symbols referenced and not defined. */
+extern int undefined_weak_sym_count;
+
+/* # of undefined symbols referenced by shared objects */
+extern int undefined_shobj_sym_count;
+
+/* # of multiply defined symbols. */
+extern int multiple_def_count;
+
+/* # of common symbols. */
+extern int common_defined_global_count;
+
+/* # of warning symbols encountered. */
+extern int warn_sym_count;
+extern int list_warning_symbols;
+
+/*
+ * Define a linked list of strings which define symbols which should be
+ * treated as set elements even though they aren't. Any symbol with a prefix
+ * matching one of these should be treated as a set element.
+ *
+ * This is to make up for deficiencies in many assemblers which aren't willing
+ * to pass any stabs through to the loader which they don't understand.
+ */
+struct string_list_element {
+ char *str;
+ struct string_list_element *next;
+};
+
+extern symbol *entry_symbol; /* the entry symbol, if any */
+extern symbol *edata_symbol; /* the symbol _edata */
+extern symbol *etext_symbol; /* the symbol _etext */
+extern symbol *end_symbol; /* the symbol _end */
+extern symbol *got_symbol; /* the symbol __GLOBAL_OFFSET_TABLE_ */
+extern symbol *dynamic_symbol; /* the symbol __DYNAMIC */
+
+/*
+ * Each input file, and each library member ("subfile") being loaded, has a
+ * `file_entry' structure for it.
+ *
+ * For files specified by command args, these are contained in the vector which
+ * `file_table' points to.
+ *
+ * For library members, they are dynamically allocated, and chained through the
+ * `chain' field. The chain is found in the `subfiles' field of the
+ * `file_entry'. The `file_entry' objects for the members have `superfile'
+ * fields pointing to the one for the library.
+ */
+
+struct file_entry {
+ char *filename; /* Name of this file. */
+ /*
+ * Name to use for the symbol giving address of text start Usually
+ * the same as filename, but for a file spec'd with -l this is the -l
+ * switch itself rather than the filename.
+ */
+ char *local_sym_name;
+ struct exec header; /* The file's a.out header. */
+ localsymbol_t *symbols; /* Symbol table of the file. */
+ int nsymbols; /* Number of symbols in above array. */
+ int string_size; /* Size in bytes of string table. */
+ char *strings; /* Pointer to the string table when
+ in core, NULL otherwise */
+ int strings_offset; /* Offset of string table,
+ (normally N_STROFF() + 4) */
+ /*
+ * Next two used only if `relocatable_output' or if needed for
+ * output of undefined reference line numbers.
+ */
+ struct relocation_info *textrel; /* Text relocations */
+ int ntextrel; /* # of text relocations */
+ struct relocation_info *datarel; /* Data relocations */
+ int ndatarel; /* # of data relocations */
+
+ /*
+ * Relation of this file's segments to the output file.
+ */
+ int text_start_address; /* Start of this file's text segment
+ in the output file core image. */
+ int data_start_address; /* Start of this file's data segment
+ in the output file core image. */
+ int bss_start_address; /* Start of this file's bss segment
+ in the output file core image. */
+ struct file_entry *subfiles; /* For a library, points to chain of
+ entries for the library members. */
+ struct file_entry *superfile; /* For library member, points to the
+ library's own entry. */
+ struct file_entry *chain; /* For library member, points to next
+ entry for next member. */
+ int starting_offset; /* For a library member, offset of the
+ member within the archive. Zero for
+ files that are not library members.*/
+ int total_size; /* Size of contents of this file,
+ if library member. */
+#ifdef SUN_COMPAT
+ struct file_entry *silly_archive;/* For shared libraries which have
+ a .sa companion */
+#endif
+ int lib_major, lib_minor; /* Version numbers of a shared object */
+
+ int flags;
+#define E_IS_LIBRARY 1 /* File is a an archive */
+#define E_HEADER_VALID 2 /* File's header has been read */
+#define E_SEARCH_DIRS 4 /* Search directories for file */
+#define E_SEARCH_DYNAMIC 8 /* Search for shared libs allowed */
+#define E_JUST_SYMS 0x10 /* File is used for incremental load */
+#define E_DYNAMIC 0x20 /* File is a shared object */
+#define E_SCRAPPED 0x40 /* Ignore this file */
+#define E_SYMBOLS_USED 0x80 /* Symbols from this entry were used */
+#define E_SECONDCLASS 0x100 /* Shared object is a subsidiary */
+};
+
+/*
+ * Section start addresses.
+ */
+extern int text_size; /* total size of text. */
+extern int text_start; /* start of text */
+extern int text_pad; /* clear space between text and data */
+extern int data_size; /* total size of data. */
+extern int data_start; /* start of data */
+extern int data_pad; /* part of bss segment within data */
+
+extern int bss_size; /* total size of bss. */
+extern int bss_start; /* start of bss */
+
+extern int text_reloc_size; /* total size of text relocation. */
+extern int data_reloc_size; /* total size of data relocation. */
+
+/*
+ * Runtime Relocation Section (RRS).
+ * This describes the data structures that go into the output text and data
+ * segments to support the run-time linker. The RRS can be empty (plain old
+ * static linking), or can just exist of GOT and PLT entries (in case of
+ * statically linked PIC code).
+ */
+extern int rrs_section_type; /* What's in the RRS section */
+#define RRS_NONE 0
+#define RRS_PARTIAL 1
+#define RRS_FULL 2
+extern int rrs_text_size; /* Size of RRS text additions */
+extern int rrs_text_start; /* Location of above */
+extern int rrs_data_size; /* Size of RRS data additions */
+extern int rrs_data_start; /* Location of above */
+
+/* Version number to put in __DYNAMIC (set by -V) */
+extern int soversion;
+#ifndef DEFAULT_SOVERSION
+#define DEFAULT_SOVERSION LD_VERSION_BSD
+#endif
+
+extern int pc_relocation; /* Current PC reloc value */
+
+extern int number_of_shobjs; /* # of shared objects linked in */
+
+/* Current link mode */
+extern int link_mode;
+#define DYNAMIC 1 /* Consider shared libraries */
+#define SYMBOLIC 2 /* Force symbolic resolution */
+#define FORCEARCHIVE 4 /* Force inclusion of all members
+ of archives */
+#define SHAREABLE 8 /* Build a shared object */
+#define SILLYARCHIVE 16 /* Process .sa companions, if any */
+
+extern FILE *outstream; /* Output file. */
+extern struct exec outheader; /* Output file header. */
+extern int magic; /* Output file magic. */
+extern int oldmagic;
+extern int relocatable_output;
+
+/* Size of a page. */
+extern int page_size;
+
+extern char **search_dirs; /* Directories to search for libraries. */
+extern int n_search_dirs; /* Length of above. */
+
+extern int write_map; /* write a load map (`-M') */
+
+void read_header __P((int, struct file_entry *));
+void read_entry_symbols __P((int, struct file_entry *));
+void read_entry_strings __P((int, struct file_entry *));
+void read_entry_relocation __P((int, struct file_entry *));
+void enter_file_symbols __P((struct file_entry *));
+void read_file_symbols __P((struct file_entry *));
+int set_element_prefixed_p __P((char *));
+int text_offset __P((struct file_entry *));
+int file_open __P((struct file_entry *));
+void each_file __P((void (*)(), void *));
+void each_full_file __P((void (*)(), void *));
+unsigned long check_each_file __P((unsigned long (*)(), void *));
+void mywrite __P((void *, int, int, FILE *));
+void padfile __P((int, FILE *));
+
+/* In warnings.c: */
+void perror_name __P((char *));
+void perror_file __P((struct file_entry *));
+void print_symbols __P((FILE *));
+char *get_file_name __P((struct file_entry *));
+void print_file_name __P((struct file_entry *, FILE *));
+void prline_file_name __P((struct file_entry *, FILE *));
+int do_warnings __P((FILE *));
+
+/* In etc.c: */
+void *xmalloc __P((size_t));
+void *xrealloc __P((void *, size_t));
+char *concat __P((const char *, const char *, const char *));
+
+/* In symbol.c: */
+void symtab_init __P((int));
+symbol *getsym __P((char *)), *getsym_soft __P((char *));
+
+/* In lib.c: */
+void search_library __P((int, struct file_entry *));
+void read_shared_object __P((int, struct file_entry *));
+int findlib __P((struct file_entry *));
+
+/* In shlib.c: */
+char *findshlib __P((char *, int *, int *, int));
+char *search_lib_dir __P((char *, char *, int *, int *, int));
+void add_search_dir __P((char *));
+void add_search_path __P((char *));
+void std_search_path __P((void));
+int getdewey __P((int[], char *));
+int cmpndewey __P((int[], int, int[], int));
+
+/* In rrs.c: */
+void init_rrs __P((void));
+int rrs_add_shobj __P((struct file_entry *));
+void alloc_rrs_reloc __P((struct file_entry *, symbol *));
+void alloc_rrs_segment_reloc __P((struct file_entry *, struct relocation_info *));
+void alloc_rrs_jmpslot __P((struct file_entry *, symbol *));
+void alloc_rrs_gotslot __P((struct file_entry *, struct relocation_info *, localsymbol_t *));
+void alloc_rrs_cpy_reloc __P((struct file_entry *, symbol *));
+
+int claim_rrs_reloc __P((struct file_entry *, struct relocation_info *, symbol *, long *));
+long claim_rrs_jmpslot __P((struct file_entry *, struct relocation_info *, symbol *, long));
+long claim_rrs_gotslot __P((struct file_entry *, struct relocation_info *, struct localsymbol *, long));
+long claim_rrs_internal_gotslot __P((struct file_entry *, struct relocation_info *, struct localsymbol *, long));
+void claim_rrs_cpy_reloc __P((struct file_entry *, struct relocation_info *, symbol *));
+void claim_rrs_segment_reloc __P((struct file_entry *, struct relocation_info *));
+void consider_rrs_section_lengths __P((void));
+void relocate_rrs_addresses __P((void));
+void write_rrs __P((void));
+
+/* In <md>.c */
+void md_init_header __P((struct exec *, int, int));
+long md_get_addend __P((struct relocation_info *, unsigned char *));
+void md_relocate __P((struct relocation_info *, long, unsigned char *, int));
+void md_make_jmpslot __P((jmpslot_t *, long, long));
+void md_fix_jmpslot __P((jmpslot_t *, long, u_long));
+int md_make_reloc __P((struct relocation_info *, struct relocation_info *, int));
+void md_make_jmpreloc __P((struct relocation_info *, struct relocation_info *, int));
+void md_make_gotreloc __P((struct relocation_info *, struct relocation_info *, int));
+void md_make_copyreloc __P((struct relocation_info *, struct relocation_info *));
+void md_set_breakpoint __P((long, long *));
+
+#ifdef NEED_SWAP
+void md_swapin_exec_hdr __P((struct exec *));
+void md_swapout_exec_hdr __P((struct exec *));
+void md_swapin_reloc __P((struct relocation_info *, int));
+void md_swapout_reloc __P((struct relocation_info *, int));
+void md_swapout_jmpslot __P((jmpslot_t *, int));
+
+/* In xbits.c: */
+void swap_longs __P((long *, int));
+void swap_symbols __P((struct nlist *, int));
+void swap_zsymbols __P((struct nzlist *, int));
+void swap_ranlib_hdr __P((struct ranlib *, int));
+void swap__dynamic __P((struct link_dynamic *));
+void swap_section_dispatch_table __P((struct section_dispatch_table *));
+void swap_so_debug __P((struct so_debug *));
+void swapin_sod __P((struct sod *, int));
+void swapout_sod __P((struct sod *, int));
+void swapout_fshash __P((struct fshash *, int));
+#endif
diff --git a/gnu/usr.bin/ld/ldconfig/Makefile b/gnu/usr.bin/ld/ldconfig/Makefile
new file mode 100644
index 0000000..28cbe51
--- /dev/null
+++ b/gnu/usr.bin/ld/ldconfig/Makefile
@@ -0,0 +1,13 @@
+# $Id: Makefile,v 1.6 1994/02/13 20:42:18 jkh Exp $
+
+PROG= ldconfig
+SRCS= ldconfig.c shlib.c etc.c
+LDDIR?= $(.CURDIR)/..
+CFLAGS+=-I$(LDDIR) -I$(.CURDIR) -I$(LDDIR)/$(MACHINE)
+LDFLAGS+=-static
+BINDIR= /sbin
+MAN8= ldconfig.8
+
+.PATH: $(LDDIR) $(LDDIR)/$(MACHINE)
+
+.include <bsd.prog.mk>
diff --git a/gnu/usr.bin/ld/ldconfig/ldconfig.8 b/gnu/usr.bin/ld/ldconfig/ldconfig.8
new file mode 100644
index 0000000..9b83224
--- /dev/null
+++ b/gnu/usr.bin/ld/ldconfig/ldconfig.8
@@ -0,0 +1,131 @@
+.\"
+.\" 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.
+.\" 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: ldconfig.8,v 1.6 1994/12/23 22:31:21 nate Exp $
+.\"
+.Dd October 3, 1993
+.Dt LDCONFIG 8
+.Os FreeBSD
+.Sh NAME
+.Nm ldconfig
+.Nd configure the shared library cache
+.Sh SYNOPSIS
+.Nm ldconfig
+.Op Fl mrsv
+.Op Ar directory Ar ...
+.Sh DESCRIPTION
+.Nm
+is used to prepare a set of
+.Dq hints
+for use by the run-time linker
+.Xr ld.so
+to facilitate quick lookup of shared libraries available in multiple
+directories. It scans a set of built-in system directories and any
+.Ar directories
+specified on the command line (in the given order) looking for shared
+libraries and stores the results in the file
+.Xr /var/run/ld.so.hints
+to forestall the overhead that would otherwise result from the
+directory search operations
+.Xr ld.so
+would have to perform to load the required shared libraries.
+.Pp
+The shared libraries so found will be automatically available for loading
+if needed by the program being prepared for execution. This obviates the need
+for storing search paths within the executable.
+.Pp
+The
+.Ev LD_LIBRARY_PATH
+environment variable can be used to override the use of
+directories (or the order thereof) from the cache or to specify additional
+directories where shared libraries might be found.
+.Ev LD_LIBRARY_PATH
+is a
+.Sq \:
+separated list of directory paths which are searched by
+.Xr ld.so
+when it needs to load a shared library. It can be viewed as the run-time
+equivalent of the
+.Fl L
+switch of
+.Xr ld.
+.Pp
+.Nm Ldconfig
+is typically run as part of the boot sequence.
+.Pp
+The following options recognized by
+.Nm ldconfig:
+.Bl -tag -width indent
+.It Fl m
+Instead of replacing the contents of
+.Xr ld.so.hints
+with those found in the directories specified,
+.Dq merge
+in new entries.
+.It Fl r
+Lists the current contents of
+.Xr ld.so.hints
+on the standard output. The hints file will not be modified.
+.It Fl s
+Do not scan the built-in system directory
+.Pq Dq /usr/lib
+for shared libraries.
+.It Fl v
+Switch on verbose mode.
+.Sh Security
+Special care must be taken when loading shared libraries into the address
+space of
+.Ev set-user-Id
+programs. Whenever such a program is run,
+.Xr ld.so
+will only load shared libraries from the
+.Ev ld.so.hints
+file. In particular, the
+.Ev LD_LIBRARY_PATH
+is not used to search for libraries. Thus, the role of ldconfig is dual. In
+addition to building a set of hints for quick lookup, it also serves to
+specify the trusted collection of directories from which shared objects can
+be safely loaded. It is presumed that the set of directories specified to
+.Nm ldconfig
+are under control of the system's administrator.
+.Xr ld.so
+further assists set-user-Id programs by erasing the
+.Ev LD_LIBRARY_PATH
+from the environment.
+
+.Sh FILES
+.Xr /var/run/ld.so.hints
+.Sh SEE ALSO
+.Xr ld 1 ,
+.Xr link 5
+.Sh HISTORY
+A
+.Nm
+utility first appeared in SunOS 4.0, it appeared in its current form
+in FreeBSD 1.1.
diff --git a/gnu/usr.bin/ld/ldconfig/ldconfig.c b/gnu/usr.bin/ld/ldconfig/ldconfig.c
new file mode 100644
index 0000000..1b3f8f2
--- /dev/null
+++ b/gnu/usr.bin/ld/ldconfig/ldconfig.c
@@ -0,0 +1,453 @@
+/*
+ * 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: ldconfig.c,v 1.10 1995/06/24 10:08:44 asami Exp $
+ */
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/file.h>
+#include <sys/time.h>
+#include <sys/mman.h>
+#include <sys/resource.h>
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <ar.h>
+#include <ranlib.h>
+#include <a.out.h>
+#include <stab.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "ld.h"
+
+#undef major
+#undef minor
+
+extern char *__progname;
+
+static int verbose;
+static int nostd;
+static int justread;
+static int merge;
+
+struct shlib_list {
+ /* Internal list of shared libraries found */
+ char *name;
+ char *path;
+ int dewey[MAXDEWEY];
+ int ndewey;
+#define major dewey[0]
+#define minor dewey[1]
+ struct shlib_list *next;
+};
+
+static struct shlib_list *shlib_head = NULL, **shlib_tail = &shlib_head;
+
+static void enter __P((char *, char *, char *, int *, int));
+static int dodir __P((char *, int));
+static int buildhints __P((void));
+static int readhints __P((void));
+static void listhints __P((void));
+
+int
+main(argc, argv)
+int argc;
+char *argv[];
+{
+ int i, c;
+ int rval = 0;
+
+ while ((c = getopt(argc, argv, "mrsv")) != EOF) {
+ switch (c) {
+ case 'm':
+ merge = 1;
+ break;
+ case 'r':
+ justread = 1;
+ break;
+ case 's':
+ nostd = 1;
+ break;
+ case 'v':
+ verbose = 1;
+ break;
+ default:
+ errx(1, "Usage: %s [-m][-r][-s][-v][dir ...]",
+ __progname);
+ break;
+ }
+ }
+
+ if (justread || merge) {
+ if ((rval = readhints()) != 0)
+ return rval;
+ if (justread) {
+ listhints();
+ return;
+ }
+ }
+
+ if (!nostd)
+ std_search_path();
+
+ for (i = 0; i < n_search_dirs; i++)
+ rval |= dodir(search_dirs[i], 1);
+
+ for (i = optind; i < argc; i++)
+ rval |= dodir(argv[i], 0);
+
+ rval |= buildhints();
+
+ return rval;
+}
+
+int
+dodir(dir, silent)
+char *dir;
+int silent;
+{
+ DIR *dd;
+ struct dirent *dp;
+ char name[MAXPATHLEN], rest[MAXPATHLEN];
+ int dewey[MAXDEWEY], ndewey;
+
+ if ((dd = opendir(dir)) == NULL) {
+ if (!silent || errno != ENOENT)
+ warn("%s", dir);
+ return -1;
+ }
+
+ while ((dp = readdir(dd)) != NULL) {
+ int n;
+
+ name[0] = rest[0] = '\0';
+
+ n = sscanf(dp->d_name, "lib%[^.].so.%s",
+ name, rest);
+
+ if (n < 2 || rest[0] == '\0')
+ continue;
+
+ ndewey = getdewey(dewey, rest);
+ enter(dir, dp->d_name, name, dewey, ndewey);
+ }
+
+ return 0;
+}
+
+static void
+enter(dir, file, name, dewey, ndewey)
+char *dir, *file, *name;
+int dewey[], ndewey;
+{
+ struct shlib_list *shp;
+
+ for (shp = shlib_head; shp; shp = shp->next) {
+ if (strcmp(name, shp->name) != 0 || major != shp->major)
+ continue;
+
+ /* Name matches existing entry */
+ if (cmpndewey(dewey, ndewey, shp->dewey, shp->ndewey) > 0) {
+
+ /* Update this entry with higher versioned lib */
+ if (verbose)
+ printf("Updating lib%s.%d.%d to %s/%s\n",
+ shp->name, shp->major, shp->minor,
+ dir, file);
+
+ free(shp->name);
+ shp->name = strdup(name);
+ free(shp->path);
+ shp->path = concat(dir, "/", file);
+ bcopy(dewey, shp->dewey, sizeof(shp->dewey));
+ shp->ndewey = ndewey;
+ }
+ break;
+ }
+
+ if (shp)
+ /* Name exists: older version or just updated */
+ return;
+
+ /* Allocate new list element */
+ if (verbose)
+ printf("Adding %s/%s\n", dir, file);
+
+ shp = (struct shlib_list *)xmalloc(sizeof *shp);
+ shp->name = strdup(name);
+ shp->path = concat(dir, "/", file);
+ bcopy(dewey, shp->dewey, MAXDEWEY);
+ shp->ndewey = ndewey;
+ shp->next = NULL;
+
+ *shlib_tail = shp;
+ shlib_tail = &shp->next;
+}
+
+
+#if DEBUG
+/* test */
+#undef _PATH_LD_HINTS
+#define _PATH_LD_HINTS "./ld.so.hints"
+#endif
+
+int
+hinthash(cp, vmajor)
+char *cp;
+int vmajor;
+{
+ int k = 0;
+
+ while (*cp)
+ k = (((k << 1) + (k >> 14)) ^ (*cp++)) & 0x3fff;
+
+ k = (((k << 1) + (k >> 14)) ^ (vmajor*257)) & 0x3fff;
+
+ return k;
+}
+
+int
+buildhints()
+{
+ struct hints_header hdr;
+ struct hints_bucket *blist;
+ struct shlib_list *shp;
+ char *strtab;
+ int i, n, str_index = 0;
+ int strtab_sz = 0; /* Total length of strings */
+ int nhints = 0; /* Total number of hints */
+ int fd;
+ char *tmpfile;
+
+ for (shp = shlib_head; shp; shp = shp->next) {
+ strtab_sz += 1 + strlen(shp->name);
+ strtab_sz += 1 + strlen(shp->path);
+ nhints++;
+ }
+
+ /* Fill hints file header */
+ hdr.hh_magic = HH_MAGIC;
+ hdr.hh_version = LD_HINTS_VERSION_1;
+ hdr.hh_nbucket = 1 * nhints;
+ n = hdr.hh_nbucket * sizeof(struct hints_bucket);
+ hdr.hh_hashtab = sizeof(struct hints_header);
+ hdr.hh_strtab = hdr.hh_hashtab + n;
+ hdr.hh_strtab_sz = strtab_sz;
+ hdr.hh_ehints = hdr.hh_strtab + hdr.hh_strtab_sz;
+
+ if (verbose)
+ printf("Totals: entries %d, buckets %d, string size %d\n",
+ nhints, hdr.hh_nbucket, strtab_sz);
+
+ /* Allocate buckets and string table */
+ blist = (struct hints_bucket *)xmalloc(n);
+ bzero((char *)blist, n);
+ for (i = 0; i < hdr.hh_nbucket; i++)
+ /* Empty all buckets */
+ blist[i].hi_next = -1;
+
+ strtab = (char *)xmalloc(strtab_sz);
+
+ /* Enter all */
+ for (shp = shlib_head; shp; shp = shp->next) {
+ struct hints_bucket *bp;
+
+ bp = blist +
+ (hinthash(shp->name, shp->major) % hdr.hh_nbucket);
+
+ if (bp->hi_pathx) {
+ int i;
+
+ for (i = 0; i < hdr.hh_nbucket; i++) {
+ if (blist[i].hi_pathx == 0)
+ break;
+ }
+ if (i == hdr.hh_nbucket) {
+ warnx("Bummer!");
+ return -1;
+ }
+ while (bp->hi_next != -1)
+ bp = &blist[bp->hi_next];
+ bp->hi_next = i;
+ bp = blist + i;
+ }
+
+ /* Insert strings in string table */
+ bp->hi_namex = str_index;
+ strcpy(strtab + str_index, shp->name);
+ str_index += 1 + strlen(shp->name);
+
+ bp->hi_pathx = str_index;
+ strcpy(strtab + str_index, shp->path);
+ str_index += 1 + strlen(shp->path);
+
+ /* Copy versions */
+ bcopy(shp->dewey, bp->hi_dewey, sizeof(bp->hi_dewey));
+ bp->hi_ndewey = shp->ndewey;
+ }
+
+ umask(022); /* ensure the file will be worl-readable */
+ tmpfile = concat(_PATH_LD_HINTS, "+", "");
+ if ((fd = open(tmpfile, O_RDWR|O_CREAT|O_TRUNC, 0444)) == -1) {
+ warn("%s", _PATH_LD_HINTS);
+ return -1;
+ }
+
+ if (write(fd, &hdr, sizeof(struct hints_header)) !=
+ sizeof(struct hints_header)) {
+ warn("%s", _PATH_LD_HINTS);
+ return -1;
+ }
+ if (write(fd, blist, hdr.hh_nbucket * sizeof(struct hints_bucket)) !=
+ hdr.hh_nbucket * sizeof(struct hints_bucket)) {
+ warn("%s", _PATH_LD_HINTS);
+ return -1;
+ }
+ if (write(fd, strtab, strtab_sz) != strtab_sz) {
+ warn("%s", _PATH_LD_HINTS);
+ return -1;
+ }
+ if (close(fd) != 0) {
+ warn("%s", _PATH_LD_HINTS);
+ return -1;
+ }
+
+ /* Install it */
+ if (unlink(_PATH_LD_HINTS) != 0 && errno != ENOENT) {
+ warn("%s", _PATH_LD_HINTS);
+ return -1;
+ }
+
+ if (rename(tmpfile, _PATH_LD_HINTS) != 0) {
+ warn("%s", _PATH_LD_HINTS);
+ return -1;
+ }
+
+ return 0;
+}
+
+static int
+readhints()
+{
+ int fd;
+ caddr_t addr;
+ long msize;
+ struct hints_header *hdr;
+ struct hints_bucket *blist;
+ char *strtab;
+ struct shlib_list *shp;
+ int i;
+
+ if ((fd = open(_PATH_LD_HINTS, O_RDONLY, 0)) == -1) {
+ warn("%s", _PATH_LD_HINTS);
+ return -1;
+ }
+
+ msize = PAGSIZ;
+ addr = mmap(0, msize, PROT_READ, MAP_COPY, fd, 0);
+
+ if (addr == (caddr_t)-1) {
+ warn("%s", _PATH_LD_HINTS);
+ return -1;
+ }
+
+ hdr = (struct hints_header *)addr;
+ if (HH_BADMAG(*hdr)) {
+ warnx("%s: Bad magic: %o",
+ _PATH_LD_HINTS, hdr->hh_magic);
+ return -1;
+ }
+
+ if (hdr->hh_version != LD_HINTS_VERSION_1) {
+ warnx("Unsupported version: %d", hdr->hh_version);
+ return -1;
+ }
+
+ if (hdr->hh_ehints > msize) {
+ if (mmap(addr+msize, hdr->hh_ehints - msize,
+ PROT_READ, MAP_COPY|MAP_FIXED,
+ fd, msize) != (caddr_t)(addr+msize)) {
+
+ warn("%s", _PATH_LD_HINTS);
+ return -1;
+ }
+ }
+ close(fd);
+
+ blist = (struct hints_bucket *)(addr + hdr->hh_hashtab);
+ strtab = (char *)(addr + hdr->hh_strtab);
+
+ for (i = 0; i < hdr->hh_nbucket; i++) {
+ struct hints_bucket *bp = &blist[i];
+
+ /* Sanity check */
+ if (bp->hi_namex >= hdr->hh_strtab_sz) {
+ warnx("Bad name index: %#x", bp->hi_namex);
+ return -1;
+ }
+ if (bp->hi_pathx >= hdr->hh_strtab_sz) {
+ warnx("Bad path index: %#x", bp->hi_pathx);
+ return -1;
+ }
+
+ /* Allocate new list element */
+ shp = (struct shlib_list *)xmalloc(sizeof *shp);
+ shp->name = strdup(strtab + bp->hi_namex);
+ shp->path = strdup(strtab + bp->hi_pathx);
+ bcopy(bp->hi_dewey, shp->dewey, sizeof(shp->dewey));
+ shp->ndewey = bp->hi_ndewey;
+ shp->next = NULL;
+
+ *shlib_tail = shp;
+ shlib_tail = &shp->next;
+ }
+
+ return 0;
+}
+
+static void
+listhints()
+{
+ struct shlib_list *shp;
+ int i;
+
+ printf("%s:\n", _PATH_LD_HINTS);
+
+ for (i = 0, shp = shlib_head; shp; i++, shp = shp->next)
+ printf("\t%d:-l%s.%d.%d => %s\n",
+ i, shp->name, shp->major, shp->minor, shp->path);
+
+ return;
+}
+
diff --git a/gnu/usr.bin/ld/ldd/Makefile b/gnu/usr.bin/ld/ldd/Makefile
new file mode 100644
index 0000000..282a8fd
--- /dev/null
+++ b/gnu/usr.bin/ld/ldd/Makefile
@@ -0,0 +1,7 @@
+# $Id: Makefile,v 1.2 1993/11/09 04:19:24 paul Exp $
+
+PROG= ldd
+SRCS= ldd.c
+BINDIR= /usr/bin
+
+.include <bsd.prog.mk>
diff --git a/gnu/usr.bin/ld/ldd/ldd.1 b/gnu/usr.bin/ld/ldd/ldd.1
new file mode 100644
index 0000000..0c3b5e4
--- /dev/null
+++ b/gnu/usr.bin/ld/ldd/ldd.1
@@ -0,0 +1,25 @@
+.Dd October 22, 1993
+.Dt LDD 1
+.Os FreeBSD
+.Sh NAME
+.Nm ldd
+.Nd list dynamic object dependencies
+.Sh SYNOPSIS
+.Nm ldd
+.Op Ar filename Ar ...
+.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.
+.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.
diff --git a/gnu/usr.bin/ld/ldd/ldd.c b/gnu/usr.bin/ld/ldd/ldd.c
new file mode 100644
index 0000000..2f54806
--- /dev/null
+++ b/gnu/usr.bin/ld/ldd/ldd.c
@@ -0,0 +1,139 @@
+/*
+ * 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: ldd.c,v 1.4 1994/06/15 22:41:03 rich Exp $
+ */
+
+#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>
+
+void
+usage()
+{
+ extern char *__progname;
+
+ fprintf(stderr, "Usage: %s <filename> ...\n", __progname);
+ exit(1);
+}
+
+int
+main(argc, argv)
+int argc;
+char *argv[];
+{
+ int rval;
+ int c;
+
+ while ((c = getopt(argc, argv, "")) != EOF) {
+ switch (c) {
+ default:
+ usage();
+ /*NOTREACHED*/
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (argc <= 0) {
+ usage();
+ /*NOTREACHED*/
+ }
+
+ /* ld.so magic */
+ setenv("LD_TRACE_LOADED_OBJECTS", "", 1);
+
+ rval = 0;
+ while (argc--) {
+ int fd;
+ struct exec hdr;
+ int status;
+
+ if ((fd = open(*argv, O_RDONLY, 0)) < 0) {
+ 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);
+
+ 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/gnu/usr.bin/ld/lib.c b/gnu/usr.bin/ld/lib.c
new file mode 100644
index 0000000..5e119ba
--- /dev/null
+++ b/gnu/usr.bin/ld/lib.c
@@ -0,0 +1,865 @@
+/*
+ * $Id: lib.c,v 1.15 1995/05/30 05:01:46 rgrimes Exp $ - library routines
+ */
+
+#include <sys/param.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/file.h>
+#include <sys/time.h>
+#include <err.h>
+#include <fcntl.h>
+#include <ar.h>
+#include <ranlib.h>
+#include <a.out.h>
+#include <stab.h>
+#include <string.h>
+#include <dirent.h>
+#include <ctype.h>
+
+#include "ld.h"
+
+static void linear_library __P((int, struct file_entry *));
+static void symdef_library __P((int, struct file_entry *, int));
+static struct file_entry *decode_library_subfile __P((int,
+ struct file_entry *,
+ int, int *));
+
+/*
+ * Search the library ENTRY, already open on descriptor FD. This means
+ * deciding which library members to load, making a chain of `struct
+ * file_entry' for those members, and entering their global symbols in the
+ * hash table.
+ */
+
+void
+search_library(fd, entry)
+ int fd;
+ struct file_entry *entry;
+{
+ int member_length;
+ register char *name;
+ register struct file_entry *subentry;
+
+ if (!(link_mode & FORCEARCHIVE) && !undefined_global_sym_count)
+ return;
+
+ /* Examine its first member, which starts SARMAG bytes in. */
+ subentry = decode_library_subfile(fd, entry, SARMAG, &member_length);
+ if (!subentry)
+ return;
+
+ name = subentry->filename;
+ free(subentry);
+
+ /* Search via __.SYMDEF if that exists, else linearly. */
+
+ if (!strcmp(name, "__.SYMDEF"))
+ symdef_library(fd, entry, member_length);
+ else
+ linear_library(fd, entry);
+}
+
+/*
+ * Construct and return a file_entry for a library member. The library's
+ * file_entry is library_entry, and the library is open on FD.
+ * SUBFILE_OFFSET is the byte index in the library of this member's header.
+ * We store the length of the member into *LENGTH_LOC.
+ */
+
+static struct file_entry *
+decode_library_subfile(fd, library_entry, subfile_offset, length_loc)
+ int fd;
+ struct file_entry *library_entry;
+ int subfile_offset;
+ int *length_loc;
+{
+ int bytes_read;
+ register int namelen;
+ int member_length, content_length;
+ int starting_offset;
+ register char *name;
+ struct ar_hdr hdr1;
+ register struct file_entry *subentry;
+
+ lseek(fd, subfile_offset, 0);
+
+ bytes_read = read(fd, &hdr1, sizeof hdr1);
+ if (!bytes_read)
+ return 0; /* end of archive */
+
+ if (sizeof hdr1 != bytes_read)
+ errx(1, "%s: malformed library archive",
+ get_file_name(library_entry));
+
+ if (sscanf(hdr1.ar_size, "%d", &member_length) != 1)
+ errx(1, "%s: malformatted header of archive member: %.*s",
+ get_file_name(library_entry),
+ sizeof(hdr1.ar_name), hdr1.ar_name);
+
+ subentry = (struct file_entry *) xmalloc(sizeof(struct file_entry));
+ bzero(subentry, sizeof(struct file_entry));
+
+ for (namelen = 0;
+ namelen < sizeof hdr1.ar_name
+ && hdr1.ar_name[namelen] != 0 && hdr1.ar_name[namelen] != ' '
+ && hdr1.ar_name[namelen] != '/';
+ namelen++);
+
+ starting_offset = subfile_offset + sizeof hdr1;
+ content_length = member_length;
+
+#ifdef AR_EFMT1
+ /*
+ * BSD 4.4 extended AR format: #1/<namelen>, with name as the
+ * first <namelen> bytes of the file
+ */
+ if (strncmp(hdr1.ar_name, AR_EFMT1, sizeof(AR_EFMT1) - 1) == 0 &&
+ isdigit(hdr1.ar_name[sizeof(AR_EFMT1) - 1])) {
+
+ namelen = atoi(&hdr1.ar_name[sizeof(AR_EFMT1) - 1]);
+ name = (char *)xmalloc(namelen + 1);
+ if (read(fd, name, namelen) != namelen)
+ errx(1, "%s: malformatted archive member: %.*s",
+ get_file_name(library_entry),
+ sizeof(hdr1.ar_name), hdr1.ar_name);
+ name[namelen] = 0;
+ content_length -= namelen;
+ starting_offset += namelen;
+ } else
+
+#endif
+ {
+ name = (char *)xmalloc(namelen + 1);
+ strncpy(name, hdr1.ar_name, namelen);
+ name[namelen] = 0;
+ }
+
+ subentry->filename = name;
+ subentry->local_sym_name = name;
+ subentry->starting_offset = starting_offset;
+ subentry->superfile = library_entry;
+ subentry->total_size = content_length;
+#if 0
+ subentry->symbols = 0;
+ subentry->strings = 0;
+ subentry->subfiles = 0;
+ subentry->chain = 0;
+ subentry->flags = 0;
+#endif
+
+ (*length_loc) = member_length;
+
+ return subentry;
+}
+
+static int subfile_wanted_p __P((struct file_entry *));
+
+/*
+ * Search a library that has a __.SYMDEF member. FD is a descriptor on
+ * which the library is open. The file pointer is assumed to point at the
+ * __.SYMDEF data. ENTRY is the library's file_entry. MEMBER_LENGTH is the
+ * length of the __.SYMDEF data.
+ */
+
+static void
+symdef_library(fd, entry, member_length)
+ int fd;
+ struct file_entry *entry;
+ int member_length;
+{
+ int *symdef_data = (int *) xmalloc(member_length);
+ register struct ranlib *symdef_base;
+ char *sym_name_base;
+ int nsymdefs;
+ int length_of_strings;
+ int not_finished;
+ int bytes_read;
+ register int i;
+ struct file_entry *prev = 0;
+ int prev_offset = 0;
+
+ bytes_read = read(fd, symdef_data, member_length);
+ if (bytes_read != member_length)
+ errx(1, "%s: malformatted __.SYMDEF",
+ get_file_name(entry));
+
+ nsymdefs = md_swap_long(*symdef_data) / sizeof(struct ranlib);
+ if (nsymdefs < 0 ||
+ nsymdefs * sizeof(struct ranlib) + 2 * sizeof(int) > member_length)
+ errx(1, "%s: malformatted __.SYMDEF",
+ get_file_name(entry));
+
+ symdef_base = (struct ranlib *) (symdef_data + 1);
+ length_of_strings = md_swap_long(*(int *) (symdef_base + nsymdefs));
+
+ if (length_of_strings < 0
+ || nsymdefs * sizeof(struct ranlib) + length_of_strings
+ + 2 * sizeof(int) > member_length)
+ errx(1, "%s: malformatted __.SYMDEF",
+ get_file_name(entry));
+
+ sym_name_base = sizeof(int) + (char *) (symdef_base + nsymdefs);
+
+ /* Check all the string indexes for validity. */
+ md_swapin_ranlib_hdr(symdef_base, nsymdefs);
+ for (i = 0; i < nsymdefs; i++) {
+ register int index = symdef_base[i].ran_un.ran_strx;
+ if (index < 0 || index >= length_of_strings
+ || (index && *(sym_name_base + index - 1)))
+ errx(1, "%s: malformatted __.SYMDEF",
+ get_file_name(entry));
+ }
+
+ /*
+ * Search the symdef data for members to load. Do this until one
+ * whole pass finds nothing to load.
+ */
+
+ not_finished = 1;
+ while (not_finished) {
+
+ not_finished = 0;
+
+ /*
+ * Scan all the symbols mentioned in the symdef for ones that
+ * we need. Load the library members that contain such
+ * symbols.
+ */
+
+ for (i = 0; (i < nsymdefs &&
+ ((link_mode & FORCEARCHIVE) ||
+ undefined_global_sym_count ||
+ common_defined_global_count)); i++) {
+
+ register symbol *sp;
+ int junk;
+ register int j;
+ register int offset = symdef_base[i].ran_off;
+ struct file_entry *subentry;
+
+
+ if (symdef_base[i].ran_un.ran_strx < 0)
+ continue;
+
+ sp = getsym_soft(sym_name_base
+ + symdef_base[i].ran_un.ran_strx);
+
+ /*
+ * If we find a symbol that appears to be needed,
+ * think carefully about the archive member that the
+ * symbol is in.
+ */
+
+ /*
+ * Per Mike Karels' recommendation, we no longer load
+ * library files if the only reference(s) that would
+ * be satisfied are 'common' references. This
+ * prevents some problems with name pollution (e.g. a
+ * global common 'utime' linked to a function).
+ *
+ * If we're not forcing the archive in then we don't
+ * need to bother if: we've never heard of the symbol,
+ * or if it is already defined. The last clause causes
+ * archive members to be searched for definitions
+ * satisfying undefined shared object symbols.
+ */
+ if (!(link_mode & FORCEARCHIVE) &&
+ (!sp || sp->defined ||
+ (!(sp->flags & GS_REFERENCED) &&
+ !sp->sorefs)))
+ continue;
+
+ /*
+ * Don't think carefully about any archive member
+ * more than once in a given pass.
+ */
+
+ if (prev_offset == offset)
+ continue;
+ prev_offset = offset;
+
+ /*
+ * Read the symbol table of the archive member.
+ */
+
+ subentry = decode_library_subfile(fd,
+ entry, offset, &junk);
+ if (subentry == 0)
+ errx(1,
+ "invalid offset for %s in symbol table of %s",
+ sym_name_base
+ + symdef_base[i].ran_un.ran_strx,
+ entry->filename);
+
+ read_entry_symbols(fd, subentry);
+ subentry->strings = (char *)
+ alloca(subentry->string_size);
+ read_entry_strings(fd, subentry);
+
+ /*
+ * Now scan the symbol table and decide whether to
+ * load.
+ */
+
+ if (!(link_mode & FORCEARCHIVE) &&
+ !subfile_wanted_p(subentry)) {
+ if (subentry->symbols)
+ free(subentry->symbols);
+ free(subentry);
+ } else {
+ /*
+ * This member is needed; load it. Since we
+ * are loading something on this pass, we
+ * must make another pass through the symdef
+ * data.
+ */
+
+ not_finished = 1;
+
+ read_entry_relocation(fd, subentry);
+ enter_file_symbols(subentry);
+
+ if (prev)
+ prev->chain = subentry;
+ else
+ entry->subfiles = subentry;
+ prev = subentry;
+
+ /*
+ * Clear out this member's symbols from the
+ * symdef data so that following passes won't
+ * waste time on them.
+ */
+
+ for (j = 0; j < nsymdefs; j++) {
+ if (symdef_base[j].ran_off == offset)
+ symdef_base[j].ran_un.ran_strx = -1;
+ }
+
+ /*
+ * We'll read the strings again
+ * if we need them.
+ */
+ subentry->strings = 0;
+ }
+ }
+ }
+
+ free(symdef_data);
+}
+
+/*
+ * Search a library that has no __.SYMDEF. ENTRY is the library's file_entry.
+ * FD is the descriptor it is open on.
+ */
+
+static void
+linear_library(fd, entry)
+ int fd;
+ struct file_entry *entry;
+{
+ register struct file_entry *prev = 0;
+ register int this_subfile_offset = SARMAG;
+
+ while ((link_mode & FORCEARCHIVE) ||
+ undefined_global_sym_count || common_defined_global_count) {
+
+ int member_length;
+ register struct file_entry *subentry;
+
+ subentry = decode_library_subfile(fd, entry,
+ this_subfile_offset, &member_length);
+
+ if (!subentry)
+ return;
+
+ read_entry_symbols(fd, subentry);
+ subentry->strings = (char *)alloca(subentry->string_size);
+ read_entry_strings(fd, subentry);
+
+ if (!(link_mode & FORCEARCHIVE) &&
+ !subfile_wanted_p(subentry)) {
+ if (subentry->symbols)
+ free(subentry->symbols);
+ free(subentry);
+ } else {
+ read_entry_relocation(fd, subentry);
+ enter_file_symbols(subentry);
+
+ if (prev)
+ prev->chain = subentry;
+ else
+ entry->subfiles = subentry;
+ prev = subentry;
+ subentry->strings = 0; /* Since space will dissapear
+ * on return */
+ }
+
+ this_subfile_offset += member_length + sizeof(struct ar_hdr);
+ if (this_subfile_offset & 1)
+ this_subfile_offset++;
+ }
+}
+
+/*
+ * ENTRY is an entry for a library member. Its symbols have been read into
+ * core, but not entered. Return nonzero if we ought to load this member.
+ */
+
+static int
+subfile_wanted_p(entry)
+ struct file_entry *entry;
+{
+ struct localsymbol *lsp, *lspend;
+#ifdef DOLLAR_KLUDGE
+ register int dollar_cond = 0;
+#endif
+
+ lspend = entry->symbols + entry->nsymbols;
+
+ for (lsp = entry->symbols; lsp < lspend; lsp++) {
+ register struct nlist *p = &lsp->nzlist.nlist;
+ register int type = p->n_type;
+ register char *name = p->n_un.n_strx + entry->strings;
+ register symbol *sp = getsym_soft(name);
+
+ /*
+ * If the symbol has an interesting definition, we could
+ * potentially want it.
+ */
+ if (! (type & N_EXT)
+ || (type == (N_UNDF | N_EXT) && p->n_value == 0
+
+#ifdef DOLLAR_KLUDGE
+ && name[1] != '$'
+#endif
+ )
+#ifdef SET_ELEMENT_P
+ || SET_ELEMENT_P(type)
+ || set_element_prefixed_p(name)
+#endif
+ )
+ continue;
+
+
+#ifdef DOLLAR_KLUDGE
+ if (name[1] == '$') {
+ sp = getsym_soft(&name[2]);
+ dollar_cond = 1;
+ if (!sp)
+ continue;
+ if (sp->flags & SP_REFERENCED) {
+ if (write_map) {
+ print_file_name(entry, stdout);
+ fprintf(stdout, " needed due to $-conditional %s\n", name);
+ }
+ return 1;
+ }
+ continue;
+ }
+#endif
+
+ /*
+ * If this symbol has not been hashed, we can't be
+ * looking for it.
+ */
+
+ if (!sp)
+ continue;
+
+ /*
+ * We don't load a file if it merely satisfies a
+ * common reference (see explanation above in
+ * symdef_library()).
+ */
+ if ((sp->flags & GS_REFERENCED) && !sp->defined) {
+ /*
+ * This is a symbol we are looking for. It
+ * is either not yet defined or defined as a
+ * common.
+ */
+#ifdef DOLLAR_KLUDGE
+ if (dollar_cond)
+ continue;
+#endif
+ if (type == (N_UNDF | N_EXT)) {
+ /*
+ * Symbol being defined as common.
+ * Remember this, but don't load
+ * subfile just for this.
+ */
+
+ /*
+ * If it didn't used to be common, up
+ * the count of common symbols.
+ */
+ if (!sp->common_size)
+ common_defined_global_count++;
+
+ if (sp->common_size < p->n_value)
+ sp->common_size = p->n_value;
+ if (!sp->defined)
+ undefined_global_sym_count--;
+ sp->defined = type;
+ continue;
+ }
+ if (sp->flags & GS_WEAK)
+ /* Weak symbols don't pull archive members */
+ continue;
+ if (write_map) {
+ print_file_name(entry, stdout);
+ fprintf(stdout, " needed due to %s\n", sp->name);
+ }
+ return 1;
+ } else {
+ /*
+ * Check for undefined symbols or commons
+ * in shared objects.
+ */
+ struct localsymbol *lsp;
+ int wascommon = sp->defined && sp->common_size;
+ int iscommon = type == (N_UNDF|N_EXT) && p->n_value;
+
+ if (wascommon) {
+ /*
+ * sp was defined as common by shared object.
+ */
+ if (iscommon && p->n_value < sp->common_size)
+ sp->common_size = p->n_value;
+ continue;
+ }
+
+ if (sp->sorefs == NULL)
+ continue;
+
+ for (lsp = sp->sorefs; lsp; lsp = lsp->next) {
+ int type = lsp->nzlist.nlist.n_type;
+ if ( (type & N_EXT) &&
+ (type & N_STAB) == 0 &&
+ type != (N_UNDF | N_EXT))
+ break; /* We don't need it */
+ }
+ if (lsp != NULL) {
+ /* There's a real definition */
+ if (iscommon)
+ /*
+ * But this member wants it to be
+ * a common; ignore it.
+ */
+ continue;
+
+ if (N_ISWEAK(&lsp->nzlist.nlist))
+ /* Weak symbols don't pull archive members */
+ continue;
+ }
+
+ /*
+ * At this point, either the new symbol is a common
+ * and the shared object reference is undefined --
+ * in which case we note the common -- or the shared
+ * object reference has a definition -- in which case
+ * the library member takes precedence.
+ */
+ if (iscommon) {
+ /*
+ * New symbol is common, just takes its
+ * size, but don't load.
+ */
+ sp->common_size = p->n_value;
+ sp->defined = type;
+ continue;
+ }
+
+ /*
+ * THIS STILL MISSES the case where one shared
+ * object defines a common and the next defines
+ * more strongly; fix this someday by making
+ * `struct glosym' and enter_global_ref() more
+ * symmetric.
+ */
+
+ if (write_map) {
+ print_file_name(entry, stdout);
+ fprintf(stdout,
+ " needed due to shared lib ref %s (%d)\n",
+ sp->name,
+ lsp ? lsp->nzlist.nlist.n_type : -1);
+ }
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * Read the symbols of dynamic entity ENTRY into core. Assume it is already
+ * open, on descriptor FD.
+ */
+void
+read_shared_object(fd, entry)
+ struct file_entry *entry;
+ int fd;
+{
+ struct _dynamic dyn;
+ struct section_dispatch_table sdt;
+ struct nlist *np;
+ struct nzlist *nzp;
+ int n, i, has_nz = 0;
+
+ if (!(entry->flags & E_HEADER_VALID))
+ read_header(fd, entry);
+
+ /* Read DYNAMIC structure (first in data segment) */
+ if (lseek(fd, text_offset(entry) + entry->header.a_text, L_SET) ==
+ (off_t)-1)
+ err(1, "%s: lseek", get_file_name(entry));
+ if (read(fd, &dyn, sizeof dyn) != sizeof dyn) {
+ errx(1, "%s: premature EOF reading _dynamic",
+ get_file_name(entry));
+ }
+ md_swapin__dynamic(&dyn);
+
+ /* Check version */
+ switch (dyn.d_version) {
+ default:
+ errx(1, "%s: unsupported _DYNAMIC version: %d",
+ get_file_name(entry), dyn.d_version);
+ break;
+ case LD_VERSION_SUN:
+ break;
+ case LD_VERSION_BSD:
+ has_nz = 1;
+ break;
+ }
+
+ /* Read Section Dispatch Table (from data segment) */
+ if (lseek(fd,
+ text_offset(entry) + (long)dyn.d_un.d_sdt -
+ (DATA_START(entry->header) - N_DATOFF(entry->header)),
+ L_SET) == (off_t)-1)
+ err(1, "%s: lseek", get_file_name(entry));
+ if (read(fd, &sdt, sizeof sdt) != sizeof sdt)
+ errx(1, "%s: premature EOF reading sdt",
+ get_file_name(entry));
+ md_swapin_section_dispatch_table(&sdt);
+
+ /* Read symbols (text segment) */
+ n = sdt.sdt_strings - sdt.sdt_nzlist;
+ entry->nsymbols = n /
+ (has_nz ? sizeof(struct nzlist) : sizeof(struct nlist));
+ nzp = (struct nzlist *)(np = (struct nlist *)alloca (n));
+ entry->symbols = (struct localsymbol *)
+ xmalloc(entry->nsymbols * sizeof(struct localsymbol));
+
+ if (lseek(fd,
+ text_offset(entry) + (long)sdt.sdt_nzlist -
+ (TEXT_START(entry->header) - N_TXTOFF(entry->header)),
+ L_SET) == (off_t)-1)
+ err(1, "%s: lseek", get_file_name(entry));
+ if (read(fd, (char *)nzp, n) != n)
+ errx(1, "%s: premature EOF reading symbols ",
+ get_file_name(entry));
+
+ if (has_nz)
+ md_swapin_zsymbols(nzp, entry->nsymbols);
+ else
+ md_swapin_symbols(np, entry->nsymbols);
+
+ /* Convert to structs localsymbol */
+ for (i = 0; i < entry->nsymbols; i++) {
+ if (has_nz) {
+ entry->symbols[i].nzlist = *nzp++;
+ } else {
+ entry->symbols[i].nzlist.nlist = *np++;
+ entry->symbols[i].nzlist.nz_size = 0;
+ }
+ entry->symbols[i].symbol = NULL;
+ entry->symbols[i].next = NULL;
+ entry->symbols[i].entry = entry;
+ entry->symbols[i].gotslot_offset = -1;
+ entry->symbols[i].flags = 0;
+ }
+
+ /* Read strings (text segment) */
+ n = entry->string_size = sdt.sdt_str_sz;
+ entry->strings = (char *)alloca(n);
+ entry->strings_offset = text_offset(entry) + sdt.sdt_strings;
+ if (lseek(fd,
+ entry->strings_offset -
+ (TEXT_START(entry->header) - N_TXTOFF(entry->header)),
+ L_SET) == (off_t)-1)
+ err(1, "%s: lseek", get_file_name(entry));
+ if (read(fd, entry->strings, n) != n)
+ errx(1, "%s: premature EOF reading strings",
+ get_file_name(entry));
+ enter_file_symbols (entry);
+ entry->strings = 0;
+
+ /*
+ * Load any subsidiary shared objects.
+ */
+ if (sdt.sdt_sods) {
+ struct sod sod;
+ off_t offset;
+ struct file_entry *prev = NULL;
+
+ offset = (off_t)sdt.sdt_sods;
+ while (1) {
+ struct file_entry *subentry;
+ char *libname, name[MAXPATHLEN]; /*XXX*/
+
+ subentry = (struct file_entry *)
+ xmalloc(sizeof(struct file_entry));
+ bzero(subentry, sizeof(struct file_entry));
+ subentry->superfile = entry;
+ subentry->flags = E_SECONDCLASS;
+
+ if (lseek(fd,
+ offset - (TEXT_START(entry->header) -
+ N_TXTOFF(entry->header)),
+ L_SET) == (off_t)-1)
+ err(1, "%s: lseek", get_file_name(entry));
+ if (read(fd, &sod, sizeof(sod)) != sizeof(sod))
+ errx(1, "%s: premature EOF reding sod",
+ get_file_name(entry));
+ md_swapin_sod(&sod, 1);
+ if (lseek(fd,
+ (off_t)sod.sod_name - (TEXT_START(entry->header) -
+ N_TXTOFF(entry->header)),
+ L_SET) == (off_t)-1)
+ err(1, "%s: lseek", get_file_name(entry));
+ (void)read(fd, name, sizeof(name)); /*XXX*/
+ if (sod.sod_library) {
+ int sod_major = sod.sod_major;
+ int sod_minor = sod.sod_minor;
+
+ libname = findshlib(name,
+ &sod_major, &sod_minor, 0);
+ if (libname == NULL)
+ errx(1,"no shared -l%s.%d.%d available",
+ name, sod.sod_major, sod.sod_minor);
+ subentry->filename = libname;
+ subentry->local_sym_name = concat("-l", name, "");
+ } else {
+ subentry->filename = strdup(name);
+ subentry->local_sym_name = strdup(name);
+ }
+ read_file_symbols(subentry);
+
+ if (prev)
+ prev->chain = subentry;
+ else
+ entry->subfiles = subentry;
+ prev = subentry;
+ fd = file_open(entry);
+ if ((offset = (off_t)sod.sod_next) == 0)
+ break;
+ }
+ }
+#ifdef SUN_COMPAT
+ if (link_mode & SILLYARCHIVE) {
+ char *cp, *sa_name;
+ char armag[SARMAG];
+ int fd;
+ struct file_entry *subentry;
+
+ sa_name = strdup(entry->filename);
+ if (sa_name == NULL)
+ goto out;
+ cp = sa_name + strlen(sa_name) - 1;
+ while (cp > sa_name) {
+ if (!isdigit(*cp) && *cp != '.')
+ break;
+ --cp;
+ }
+ if (cp <= sa_name || *cp != 'o') {
+ /* Not in `libxxx.so.n.m' form */
+ free(sa_name);
+ goto out;
+ }
+
+ *cp = 'a';
+ if ((fd = open(sa_name, O_RDONLY, 0)) < 0)
+ goto out;
+
+ /* Read archive magic */
+ bzero(armag, SARMAG);
+ (void)read(fd, armag, SARMAG);
+ (void)close(fd);
+ if (strncmp(armag, ARMAG, SARMAG) != 0) {
+ warnx("%s: malformed silly archive",
+ get_file_name(entry));
+ goto out;
+ }
+
+ subentry = (struct file_entry *)
+ xmalloc(sizeof(struct file_entry));
+ bzero(subentry, sizeof(struct file_entry));
+
+ entry->silly_archive = subentry;
+ subentry->superfile = entry;
+ subentry->filename = sa_name;
+ subentry->local_sym_name = sa_name;
+ subentry->flags |= E_IS_LIBRARY;
+ search_library(file_open(subentry), subentry);
+out:
+ ;
+ }
+#endif
+}
+
+#undef major
+#undef minor
+
+int
+findlib(p)
+struct file_entry *p;
+{
+ int i;
+ int fd = -1;
+ int major = -1, minor = -1;
+ char *cp, *fname = NULL;
+
+ if (!(p->flags & E_SEARCH_DYNAMIC))
+ goto dot_a;
+
+ fname = findshlib(p->filename, &major, &minor, 1);
+
+ if (fname && (fd = open(fname, O_RDONLY, 0)) >= 0) {
+ p->filename = fname;
+ p->lib_major = major;
+ p->lib_minor = minor;
+ p->flags &= ~E_SEARCH_DIRS;
+ return fd;
+ }
+ (void)free(fname);
+
+dot_a:
+ p->flags &= ~E_SEARCH_DYNAMIC;
+ if (cp = strrchr(p->filename, '/')) {
+ *cp++ = '\0';
+ fname = concat(concat(p->filename, "/lib", cp), ".a", "");
+ *(--cp) = '/';
+ } else
+ fname = concat("lib", p->filename, ".a");
+
+ for (i = 0; i < n_search_dirs; i++) {
+ register char *path
+ = concat(search_dirs[i], "/", fname);
+ fd = open(path, O_RDONLY, 0);
+ if (fd >= 0) {
+ p->filename = path;
+ p->flags &= ~E_SEARCH_DIRS;
+ break;
+ }
+ (void)free(path);
+ }
+ (void)free(fname);
+ return fd;
+}
+
diff --git a/gnu/usr.bin/ld/rrs.c b/gnu/usr.bin/ld/rrs.c
new file mode 100644
index 0000000..2d1b3bc
--- /dev/null
+++ b/gnu/usr.bin/ld/rrs.c
@@ -0,0 +1,1246 @@
+/*
+ * 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: rrs.c,v 1.13 1994/12/23 22:30:48 nate Exp $
+ */
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/file.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <err.h>
+#include <fcntl.h>
+#include <ar.h>
+#include <ranlib.h>
+#include <a.out.h>
+#include <stab.h>
+#include <string.h>
+
+#include "ld.h"
+
+static struct _dynamic rrs_dyn; /* defined in link.h */
+static struct so_debug rrs_so_debug; /* defined in link.h */
+static struct section_dispatch_table rrs_sdt; /* defined in link.h */
+static got_t *rrs_got;
+static jmpslot_t *rrs_plt; /* defined in md.h */
+static struct relocation_info *rrs_reloc;
+static struct nzlist *rrs_symbols; /* RRS symbol table */
+static char *rrs_strtab; /* RRS strings */
+static struct rrs_hash *rrs_hashtab; /* RT hash table */
+static struct shobj *rrs_shobjs;
+
+static int reserved_rrs_relocs;
+static int claimed_rrs_relocs;
+static int discarded_rrs_relocs;
+
+static int number_of_gotslots = 1;
+static int number_of_jmpslots = 1;
+static int number_of_rrs_hash_entries;
+static int number_of_rrs_symbols;
+static int rrs_strtab_size;
+static int rrs_symbol_size;
+
+static int current_jmpslot_offset;
+static int current_got_offset;
+static int got_origin;
+static int current_reloc_offset;
+static int current_hash_index;
+int number_of_shobjs;
+
+/* Convert a GOT offset into a table entry */
+#define GOTP(off) ((got_t *)((long)rrs_got + got_origin + (off)))
+
+struct shobj {
+ struct shobj *next;
+ struct file_entry *entry;
+};
+
+/*
+RRS text segment:
+ +-------------------+ <-- sdt_rel (rrs_text_start)
+ | |
+ | relocation |
+ | |
+ +-------------------+ <-- <sdt>.sdt_hash
+ | |
+ | hash buckets |
+ | |
+ +-------------------+ <-- <sdt>.sdt_nzlist
+ | |
+ | symbols |
+ | |
+ +-------------------+ <-- <sdt>.sdt_strings
+ | |
+ | strings |
+ | |
+ +-------------------+ <-- <sdt>.sdt_sods
+ | |
+ | shobjs |
+ | |
+ +-------------------+
+ | |
+ | shobjs strings | <-- <shobj>.sod_name
+ | |
+ +-------------------+
+
+
+RRS data segment:
+
+ +-------------------+ <-- __DYNAMIC (rrs_data_start)
+ | |
+ | _dymamic |
+ | |
+ +-------------------+ <-- __DYNAMIC.d_debug
+ | |
+ | so_debug |
+ | |
+ +-------------------+ <-- __DYNAMIC.d_un.d_sdt
+ | |
+ | sdt |
+ | |
+ +-------------------+ <-- sdt_got
+ | |
+ | _GOT_ | <-- _GLOBAL_OFFSET_TABLE_
+ | | ( == sdt_got + got_origin)
+ | |
+ +-------------------+ <-- sdt_plt
+ | |
+ | PLT |
+ | |
+ +-------------------+
+*/
+
+/*
+ * Add NAME to the list of needed run-time objects.
+ * Return 1 if ENTRY was added to the list.
+ */
+int
+rrs_add_shobj(entry)
+ struct file_entry *entry;
+{
+ struct shobj **p;
+
+ for (p = &rrs_shobjs; *p != NULL; p = &(*p)->next)
+ if (strcmp((*p)->entry->filename, entry->filename) == 0)
+ return 0;
+ *p = (struct shobj *)xmalloc(sizeof(struct shobj));
+ (*p)->next = NULL;
+ (*p)->entry = entry;
+
+ number_of_shobjs++;
+ return 1;
+}
+
+void
+alloc_rrs_reloc(entry, sp)
+ struct file_entry *entry;
+ symbol *sp;
+{
+#ifdef DEBUG
+printf("alloc_rrs_reloc: %s in %s\n", sp->name, get_file_name(entry));
+#endif
+ reserved_rrs_relocs++;
+}
+
+void
+alloc_rrs_segment_reloc(entry, r)
+ struct file_entry *entry;
+ struct relocation_info *r;
+{
+#ifdef DEBUG
+printf("alloc_rrs_segment_reloc at %#x in %s\n",
+ r->r_address, get_file_name(entry));
+#endif
+ reserved_rrs_relocs++;
+}
+
+void
+alloc_rrs_jmpslot(entry, sp)
+ struct file_entry *entry;
+ symbol *sp;
+{
+ if (sp->flags & GS_HASJMPSLOT)
+ return;
+
+ sp->flags |= GS_HASJMPSLOT;
+ number_of_jmpslots++;
+ reserved_rrs_relocs++;
+}
+
+void
+alloc_rrs_gotslot(entry, r, lsp)
+ struct file_entry *entry;
+ struct relocation_info *r;
+ struct localsymbol *lsp;
+{
+ symbol *sp = lsp->symbol;
+
+ if (!RELOC_EXTERN_P(r)) {
+
+ if (sp != NULL) {
+ warnx("%s: relocation for internal symbol "
+ "expected at %#x",
+ get_file_name(entry), RELOC_ADDRESS(r));
+ return;
+ }
+
+ if (!RELOC_STATICS_THROUGH_GOT_P(r))
+ /* No need for a GOT slot */
+ return;
+
+ if (lsp->flags & LS_HASGOTSLOT)
+ return;
+
+ lsp->flags |= LS_HASGOTSLOT;
+
+ } else {
+
+ if (sp == NULL) {
+ warnx("%s: relocation must refer "
+ "to global symbol at %#x",
+ get_file_name(entry), RELOC_ADDRESS(r));
+ return;
+ }
+
+ if (sp->alias)
+ sp = sp->alias;
+
+ if (sp->flags & GS_HASGOTSLOT)
+ return;
+
+ sp->flags |= GS_HASGOTSLOT;
+ }
+
+ number_of_gotslots++;
+ reserved_rrs_relocs++;
+}
+
+void
+alloc_rrs_cpy_reloc(entry, sp)
+ struct file_entry *entry;
+ symbol *sp;
+{
+ if (sp->flags & GS_CPYRELOCRESERVED)
+ return;
+#ifdef DEBUG
+printf("alloc_rrs_copy: %s in %s\n", sp->name, get_file_name(entry));
+#endif
+ sp->flags |= GS_CPYRELOCRESERVED;
+ reserved_rrs_relocs++;
+}
+
+static struct relocation_info *
+rrs_next_reloc()
+{
+ struct relocation_info *r;
+
+ r = rrs_reloc + claimed_rrs_relocs++;
+ if (claimed_rrs_relocs > reserved_rrs_relocs)
+ errx(1, "internal error: RRS relocs exceed allocation %d",
+ reserved_rrs_relocs);
+ return r;
+}
+
+/*
+ * Claim a RRS relocation as a result of a regular (ie. non-PIC)
+ * relocation record in a rel file.
+ *
+ * Return 1 if the output file needs no further updating.
+ * Return 0 if the relocation value pointed to by RELOCATION must
+ * written to a.out.
+ */
+int
+claim_rrs_reloc(entry, rp, sp, relocation)
+ struct file_entry *entry;
+ struct relocation_info *rp;
+ symbol *sp;
+ long *relocation;
+{
+ struct relocation_info *r = rrs_next_reloc();
+
+ if (rp->r_address < text_start + text_size)
+ warnx("%s: RRS text relocation at %#x for \"%s\"",
+ get_file_name(entry), rp->r_address, sp->name);
+
+#ifdef DEBUG
+printf("claim_rrs_reloc: %s in %s\n", sp->name, get_file_name(entry));
+#endif
+ r->r_address = rp->r_address;
+ r->r_symbolnum = sp->rrs_symbolnum;
+
+ if (link_mode & SYMBOLIC) {
+ if (!sp->defined)
+ warnx("Cannot reduce symbol \"%s\" in %s",
+ sp->name, get_file_name(entry));
+ RELOC_EXTERN_P(r) = 0;
+ *relocation += sp->value;
+ (void) md_make_reloc(rp, r, RELTYPE_RELATIVE);
+ return 0;
+ } else {
+ RELOC_EXTERN_P(r) = 1;
+ return md_make_reloc(rp, r, RELTYPE_EXTERN);
+ }
+}
+
+/*
+ * Claim a jmpslot. Setup RRS relocation if claimed for the first time.
+ */
+long
+claim_rrs_jmpslot(entry, rp, sp, addend)
+ struct file_entry *entry;
+ struct relocation_info *rp;
+ symbol *sp;
+ long addend;
+{
+ struct relocation_info *r;
+
+ if (!(sp->flags & GS_HASJMPSLOT))
+ errx(1, "internal error: "
+ "%s: claim_rrs_jmpslot: %s: no reservation",
+ get_file_name(entry),
+ sp->name);
+
+ if (sp->jmpslot_offset != -1)
+ return rrs_sdt.sdt_plt + sp->jmpslot_offset;
+
+ sp->jmpslot_offset = current_jmpslot_offset;
+ current_jmpslot_offset += sizeof(jmpslot_t);
+
+#ifdef DEBUG
+printf("claim_rrs_jmpslot: %s: %s(%d) -> offset %x\n",
+ get_file_name(entry),
+ sp->name, sp->rrs_symbolnum, sp->jmpslot_offset);
+#endif
+
+ if ((link_mode & SYMBOLIC) || rrs_section_type == RRS_PARTIAL) {
+ if (!sp->defined)
+ warnx("Cannot reduce symbol \"%s\" in %s",
+ sp->name, get_file_name(entry));
+
+ md_fix_jmpslot( rrs_plt + sp->jmpslot_offset/sizeof(jmpslot_t),
+ rrs_sdt.sdt_plt + sp->jmpslot_offset,
+ sp->value);
+ if (rrs_section_type == RRS_PARTIAL || !JMPSLOT_NEEDS_RELOC) {
+ /* PLT is self-contained */
+ discarded_rrs_relocs++;
+ return rrs_sdt.sdt_plt + sp->jmpslot_offset;
+ }
+ } else {
+ md_make_jmpslot(rrs_plt + sp->jmpslot_offset/sizeof(jmpslot_t),
+ sp->jmpslot_offset,
+ claimed_rrs_relocs);
+ }
+
+ /*
+ * Install a run-time relocation for this PLT entry.
+ */
+ r = rrs_next_reloc();
+
+ RELOC_SYMBOL(r) = sp->rrs_symbolnum;
+
+ r->r_address = (long)rrs_sdt.sdt_plt + sp->jmpslot_offset;
+
+ if (link_mode & SYMBOLIC) {
+ RELOC_EXTERN_P(r) = 0;
+ md_make_jmpreloc(rp, r, RELTYPE_RELATIVE);
+ } else {
+ RELOC_EXTERN_P(r) = 1;
+ md_make_jmpreloc(rp, r, 0);
+ }
+
+ return rrs_sdt.sdt_plt + sp->jmpslot_offset;
+}
+
+/*
+ * Claim GOT entry for a global symbol. If this is the first relocation
+ * claiming the entry, setup a RRS relocation for it.
+ * Return offset into the GOT allocated to this symbol.
+ */
+long
+claim_rrs_gotslot(entry, rp, lsp, addend)
+ struct file_entry *entry;
+ struct relocation_info *rp;
+ struct localsymbol *lsp;
+ long addend;
+{
+ struct relocation_info *r;
+ symbol *sp = lsp->symbol;
+ int reloc_type = 0;
+
+ if (sp == NULL) {
+ return 0;
+ }
+
+ if (sp->alias)
+ sp = sp->alias;
+
+ if (!(sp->flags & GS_HASGOTSLOT))
+ errx(1, "internal error: "
+ "%s: claim_rrs_gotslot: %s: no reservation",
+ get_file_name(entry), sp->name);
+
+ if (sp->gotslot_offset != -1) {
+#ifdef DIAGNOSTIC
+ if (*GOTP(sp->gotslot_offset) != addend +
+ ((!(link_mode & SHAREABLE) || (link_mode & SYMBOLIC))
+ ? sp->value : 0))
+ errx(1, "%s: %s: gotslot at %#x is multiple valued, "
+ "*got = %#x, addend = %#x, sp->value = %#x",
+ get_file_name(entry), sp->name,
+ sp->gotslot_offset,
+ *GOTP(sp->gotslot_offset), addend, sp->value);
+#endif
+ /* This symbol already passed here before. */
+ return sp->gotslot_offset;
+ }
+
+ if (current_got_offset == 0)
+ /* GOT offset 0 is reserved */
+ current_got_offset += sizeof(got_t);
+
+ if (current_got_offset > MAX_GOTOFF)
+ errx(1, "%s: GOT overflow on symbol `%s' at %#x",
+ get_file_name(entry), sp->name, RELOC_ADDRESS(rp));
+
+ sp->gotslot_offset = current_got_offset;
+ current_got_offset += sizeof(got_t);
+
+#ifdef DEBUG
+printf("claim_rrs_gotslot: %s(%d,%#x) slot offset %#x, addend %#x\n",
+ sp->name, sp->rrs_symbolnum, sp->value, sp->gotslot_offset, addend);
+#endif
+
+ if (sp->defined &&
+ (!(link_mode & SHAREABLE) || (link_mode & SYMBOLIC))) {
+
+ /*
+ * Reduce to just a base-relative translation.
+ */
+
+ *GOTP(sp->gotslot_offset) = sp->value + addend;
+ reloc_type = RELTYPE_RELATIVE;
+
+ } else if ((link_mode & SYMBOLIC) || rrs_section_type == RRS_PARTIAL) {
+ /*
+ * SYMBOLIC: all symbols must be known.
+ * RRS_PARTIAL: we don't link against shared objects,
+ * so again all symbols must be known.
+ */
+ warnx("Cannot reduce symbol \"%s\" in %s",
+ sp->name, get_file_name(entry));
+
+ } else {
+
+ /*
+ * This gotslot will be updated with symbol value at run-time.
+ */
+
+ *GOTP(sp->gotslot_offset) = addend;
+ }
+
+ if (rrs_section_type == RRS_PARTIAL) {
+ /*
+ * Base address is known, gotslot should be fully
+ * relocated by now.
+ * NOTE: RRS_PARTIAL implies !SHAREABLE.
+ */
+ if (!sp->defined)
+ warnx("Cannot reduce symbol \"%s\" in %s",
+ sp->name, get_file_name(entry));
+ discarded_rrs_relocs++;
+ return sp->gotslot_offset;
+ }
+
+ /*
+ * Claim a relocation entry.
+ * If symbol is defined and in "main" (!SHAREABLE)
+ * we still put out a relocation as we cannot easily
+ * undo the allocation.
+ * `RELTYPE_RELATIVE' relocations have the external bit off
+ * as no symbol need be looked up at run-time.
+ */
+ r = rrs_next_reloc();
+ r->r_address = got_symbol->value + sp->gotslot_offset;
+ RELOC_SYMBOL(r) = sp->rrs_symbolnum;
+ RELOC_EXTERN_P(r) = !(reloc_type == RELTYPE_RELATIVE);
+ md_make_gotreloc(rp, r, reloc_type);
+
+ return sp->gotslot_offset;
+}
+
+/*
+ * Claim a GOT entry for a static symbol. Return offset of the
+ * allocated GOT entry. If RELOC_STATICS_THROUGH_GOT_P is in effect,
+ * return the offset of the symbol with respect to the *location* of
+ * the GOT.
+ */
+long
+claim_rrs_internal_gotslot(entry, rp, lsp, addend)
+ struct file_entry *entry;
+ struct relocation_info *rp;
+ struct localsymbol *lsp;
+ long addend;
+{
+ struct relocation_info *r;
+
+ addend += lsp->nzlist.nz_value;
+
+ if (!RELOC_STATICS_THROUGH_GOT_P(r))
+ return addend - got_symbol->value;
+
+ if (!(lsp->flags & LS_HASGOTSLOT))
+ errx(1, "internal error: "
+ "%s: claim_rrs_internal_gotslot at %#x: no reservation",
+ get_file_name(entry), RELOC_ADDRESS(rp));
+
+ if (lsp->gotslot_offset != -1) {
+ /* Already claimed */
+ if (*GOTP(lsp->gotslot_offset) != addend)
+ errx(1, "%s: gotslot at %#x is multiple valued",
+ get_file_name(entry), lsp->gotslot_offset);
+ return lsp->gotslot_offset;
+ }
+
+ if (current_got_offset == 0)
+ /* GOT offset 0 is reserved */
+ current_got_offset += sizeof(got_t);
+
+ if (current_got_offset > MAX_GOTOFF)
+ errx(1, "%s: GOT overflow for relocation at %#x",
+ get_file_name(entry), RELOC_ADDRESS(rp));
+
+ lsp->gotslot_offset = current_got_offset;
+ current_got_offset += sizeof(got_t);
+
+ *GOTP(lsp->gotslot_offset) = addend;
+
+#ifdef DEBUG
+printf("claim_rrs_internal_gotslot: %s: slot offset %#x, addend = %#x\n",
+ get_file_name(entry), lsp->gotslot_offset, addend);
+#endif
+
+ if (rrs_section_type == RRS_PARTIAL) {
+ discarded_rrs_relocs++;
+ return lsp->gotslot_offset;
+ }
+
+ /*
+ * Relocation entry needed for this static GOT entry.
+ */
+ r = rrs_next_reloc();
+ r->r_address = got_symbol->value + lsp->gotslot_offset;
+ RELOC_EXTERN_P(r) = 0;
+ md_make_gotreloc(rp, r, RELTYPE_RELATIVE);
+ return lsp->gotslot_offset;
+}
+
+void
+claim_rrs_cpy_reloc(entry, rp, sp)
+ struct file_entry *entry;
+ struct relocation_info *rp;
+ symbol *sp;
+{
+ struct relocation_info *r;
+
+ if (sp->flags & GS_CPYRELOCCLAIMED)
+ return;
+
+ if (!(sp->flags & GS_CPYRELOCRESERVED))
+ errx(1, "internal error: "
+ "%s: claim_cpy_reloc: %s: no reservation",
+ get_file_name(entry), sp->name);
+
+#ifdef DEBUG
+printf("claim_rrs_copy: %s: %s -> %x\n",
+ get_file_name(entry), sp->name, sp->so_defined);
+#endif
+
+ r = rrs_next_reloc();
+ sp->flags |= GS_CPYRELOCCLAIMED;
+ r->r_address = rp->r_address;
+ RELOC_SYMBOL(r) = sp->rrs_symbolnum;
+ RELOC_EXTERN_P(r) = RELOC_EXTERN_P(rp);
+ md_make_cpyreloc(rp, r);
+}
+
+void
+claim_rrs_segment_reloc(entry, rp)
+ struct file_entry *entry;
+ struct relocation_info *rp;
+{
+ struct relocation_info *r = rrs_next_reloc();
+
+#ifdef DEBUG
+printf("claim_rrs_segment_reloc: %s at %#x\n",
+ get_file_name(entry), rp->r_address);
+#endif
+
+ r->r_address = rp->r_address;
+ RELOC_TYPE(r) = RELOC_TYPE(rp);
+ RELOC_EXTERN_P(r) = 0;
+ md_make_reloc(rp, r, RELTYPE_RELATIVE);
+
+}
+
+/*
+ * Fill the RRS hash table for the given symbol name.
+ * NOTE: the hash value computation must match the one in rtld.
+ */
+void
+rrs_insert_hash(cp, index)
+ char *cp;
+ int index;
+{
+ int hashval = 0;
+ struct rrs_hash *hp;
+
+ for (; *cp; cp++)
+ hashval = (hashval << 1) + *cp;
+
+ hashval = (hashval & 0x7fffffff) % rrs_sdt.sdt_buckets;
+
+ /* Get to the bucket */
+ hp = rrs_hashtab + hashval;
+ if (hp->rh_symbolnum == -1) {
+ /* Empty bucket, use it */
+ hp->rh_symbolnum = index;
+ hp->rh_next = 0;
+ return;
+ }
+
+ while (hp->rh_next != 0)
+ hp = rrs_hashtab + hp->rh_next;
+
+ hp->rh_next = current_hash_index++;
+ hp = rrs_hashtab + hp->rh_next;
+ hp->rh_symbolnum = index;
+ hp->rh_next = 0;
+}
+
+/*
+ * There are two interesting cases to consider here.
+ *
+ * 1) No shared objects were loaded, but there were PIC input rel files.
+ * In this case we must output a _GLOBAL_OFFSET_TABLE_ but no other
+ * RRS data. Also, the entries in the GOT must be fully resolved.
+ *
+ * 2) It's a genuine dynamically linked program, so the whole RRS scoop
+ * goes into a.out.
+ */
+void
+consider_rrs_section_lengths()
+{
+ int n;
+ struct shobj *shp, **shpp;
+
+#ifdef notyet
+/* We run into trouble with this as long as shared object symbols
+ are not checked for definitions */
+ /*
+ * First, determine the real number of shared objects we need.
+ */
+ for (shpp = &rrs_shobjs; *shpp; shpp = &(*shpp)->next) {
+ while (*shpp && !((*shpp)->entry->flags & E_SYMBOLS_USED)) {
+ if (--number_of_shobjs < 0)
+ errx(1, "internal error: number_of_shobjs < 0");
+ *shpp = (*shpp)->next;
+ }
+ if (*shpp == NULL)
+ break;
+ }
+#endif
+
+ /* First, determine what of the RRS we want */
+ if (relocatable_output)
+ rrs_section_type = RRS_NONE;
+ else if (link_mode & SHAREABLE)
+ rrs_section_type = RRS_FULL;
+ else if (number_of_shobjs == 0 /*&& !(link_mode & DYNAMIC)*/) {
+ /*
+ * First slots in both tables are reserved
+ * hence the "> 1" condition
+ */
+ if (number_of_gotslots > 1 || number_of_jmpslots > 1)
+ rrs_section_type = RRS_PARTIAL;
+ else
+ rrs_section_type = RRS_NONE;
+ } else
+ rrs_section_type = RRS_FULL;
+
+ if (rrs_section_type == RRS_NONE) {
+ got_symbol->defined = 0;
+ if (reserved_rrs_relocs > 0)
+ errx(1, "internal error: empty RRS has reservations");
+ return;
+ }
+
+ rrs_symbol_size = LD_VERSION_NZLIST_P(soversion) ?
+ sizeof(struct nzlist) : sizeof(struct nlist);
+
+ /*
+ * If there is an entry point, __DYNAMIC must be referenced (usually
+ * from crt0), as this is the method used to determine whether the
+ * run-time linker must be called.
+ */
+ if (!(link_mode & SHAREABLE) && !(dynamic_symbol->flags & GS_REFERENCED))
+ errx(1, "No reference to __DYNAMIC");
+
+ dynamic_symbol->flags |= GS_REFERENCED;
+
+ if (number_of_gotslots > 1)
+ got_symbol->flags |= GS_REFERENCED;
+
+
+ /* Next, allocate relocs, got and plt */
+ n = reserved_rrs_relocs * sizeof(struct relocation_info);
+ rrs_reloc = (struct relocation_info *)xmalloc(n);
+ bzero(rrs_reloc, n);
+
+ n = number_of_gotslots * sizeof(got_t);
+ rrs_got = (got_t *)xmalloc(n);
+ bzero(rrs_got, n);
+
+ n = number_of_jmpslots * sizeof(jmpslot_t);
+ rrs_plt = (jmpslot_t *)xmalloc(n);
+ bzero(rrs_plt, n);
+
+ /* Initialize first jmpslot */
+ md_fix_jmpslot(rrs_plt, 0, 0);
+
+ if (rrs_section_type == RRS_PARTIAL) {
+ rrs_data_size = number_of_gotslots * sizeof(got_t);
+ rrs_data_size += number_of_jmpslots * sizeof(jmpslot_t);
+ return;
+ }
+
+ /*
+ * Walk the symbol table, assign RRS symbol numbers
+ * and calculate string space.
+ * Assign number 0 to __DYNAMIC (!! Sun compatibility)
+ */
+ dynamic_symbol->rrs_symbolnum = number_of_rrs_symbols++;
+ FOR_EACH_SYMBOL(i ,sp) {
+ if ((link_mode & SHAREABLE) && sp->warning) {
+ /* Allocate N_WARNING & co */
+ rrs_strtab_size +=
+ 2 + strlen(sp->name) + strlen(sp->warning);
+ number_of_rrs_symbols += 2;
+ }
+
+ if (!(sp->flags & GS_REFERENCED))
+ continue;
+
+ rrs_strtab_size += 1 + strlen(sp->name);
+ if (sp != dynamic_symbol)
+ sp->rrs_symbolnum = number_of_rrs_symbols++;
+ if (sp->alias) {
+ /*
+ * (sigh) Always allocate space to hold the
+ * indirection. At this point there's not
+ * enough information to decide whether it's
+ * actually needed or not.
+ */
+ number_of_rrs_symbols++;
+ rrs_strtab_size += 1 + strlen(sp->alias->name);
+ }
+ } END_EACH_SYMBOL;
+
+ /*
+ * Now that we know how many RRS symbols there are going to be,
+ * allocate and initialize the RRS symbol hash table.
+ */
+ rrs_sdt.sdt_buckets = number_of_rrs_symbols/4;
+ if (rrs_sdt.sdt_buckets < 4)
+ rrs_sdt.sdt_buckets = 4;
+
+ number_of_rrs_hash_entries = rrs_sdt.sdt_buckets +
+ number_of_rrs_symbols;
+ rrs_hashtab = (struct rrs_hash *)xmalloc(
+ number_of_rrs_hash_entries * sizeof(struct rrs_hash));
+ for (n = 0; n < rrs_sdt.sdt_buckets; n++)
+ rrs_hashtab[n].rh_symbolnum = -1;
+ current_hash_index = rrs_sdt.sdt_buckets;
+
+ /*
+ * Get symbols into hash table now, so we can fine tune the size
+ * of the latter. We adjust the value of `number_of_rrs_hash_entries'
+ * to the number of hash link slots actually used.
+ */
+ FOR_EACH_SYMBOL(i ,sp) {
+ if (sp->flags & GS_REFERENCED)
+ rrs_insert_hash(sp->name, sp->rrs_symbolnum);
+ } END_EACH_SYMBOL;
+ number_of_rrs_hash_entries = current_hash_index;
+
+ /*
+ * Calculate RRS section sizes.
+ */
+ rrs_data_size = sizeof(struct _dynamic);
+ rrs_data_size += sizeof(struct so_debug);
+ rrs_data_size += sizeof(struct section_dispatch_table);
+ rrs_data_size += number_of_gotslots * sizeof(got_t);
+ rrs_data_size += number_of_jmpslots * sizeof(jmpslot_t);
+ rrs_data_size = MALIGN(rrs_data_size);
+
+ rrs_text_size = reserved_rrs_relocs * sizeof(struct relocation_info);
+ rrs_text_size += number_of_rrs_hash_entries * sizeof(struct rrs_hash);
+ rrs_text_size += number_of_rrs_symbols * rrs_symbol_size;
+
+ /* Align strings size */
+ rrs_strtab_size = MALIGN(rrs_strtab_size);
+ rrs_text_size += rrs_strtab_size;
+
+ /* Process needed shared objects */
+ for (shp = rrs_shobjs; shp; shp = shp->next) {
+ char *name = shp->entry->local_sym_name;
+
+ if (*name == '-' && *(name+1) == 'l')
+ name += 2;
+
+ rrs_text_size += sizeof(struct sod);
+ rrs_text_size += 1 + strlen(name);
+ }
+
+ /* Finally, align size */
+ rrs_text_size = MALIGN(rrs_text_size);
+}
+
+void
+relocate_rrs_addresses()
+{
+
+ dynamic_symbol->value = 0;
+
+ /*
+ * Get ready to allocate linkage table offsets.
+ * First jmpslot is reserved for the run-time binder
+ * GOT entry at offset 0 is reserved for `__DYNAMIC'.
+ */
+ current_jmpslot_offset = sizeof(jmpslot_t);
+ current_got_offset = 0;
+
+ if (1 /* Not "-fPIC" seen */) {
+ int gotsize = number_of_gotslots * sizeof(got_t);
+
+ if (gotsize + MIN_GOTOFF - (int)sizeof(got_t) > MAX_GOTOFF)
+ warnx("Global Offset Table overflow");
+ if (gotsize > MAX_GOTOFF)
+ /* Position at "two-complements" origin */
+ current_got_offset += MIN_GOTOFF;
+ }
+
+ got_origin = -current_got_offset;
+
+ if (rrs_section_type == RRS_NONE)
+ return;
+
+ if (rrs_section_type == RRS_PARTIAL) {
+ rrs_sdt.sdt_got = rrs_data_start;
+ got_symbol->value = rrs_sdt.sdt_got + got_origin;
+ rrs_sdt.sdt_plt = rrs_sdt.sdt_got +
+ number_of_gotslots * sizeof(got_t);
+ return;
+ }
+
+ /*
+ * RRS data relocations.
+ */
+ rrs_dyn.d_version = soversion;
+ rrs_dyn.d_debug = (struct so_debug *)
+ (rrs_data_start + sizeof(struct _dynamic));
+ rrs_dyn.d_un.d_sdt = (struct section_dispatch_table *)
+ ((long)rrs_dyn.d_debug + sizeof(struct so_debug));
+
+ rrs_sdt.sdt_got = (long)rrs_dyn.d_un.d_sdt +
+ sizeof(struct section_dispatch_table);
+ rrs_sdt.sdt_plt = rrs_sdt.sdt_got + number_of_gotslots*sizeof(got_t);
+
+ /*
+ * RRS text relocations.
+ */
+ rrs_sdt.sdt_rel = rrs_text_start;
+ /*
+ * Sun BUG compatibility alert.
+ * Main program's RRS text values are relative to TXTADDR? WHY??
+ */
+#ifdef SUN_COMPAT
+ if (soversion == LD_VERSION_SUN && !(link_mode & SHAREABLE))
+ rrs_sdt.sdt_rel -= N_TXTADDR(outheader);
+#endif
+
+ rrs_sdt.sdt_hash = rrs_sdt.sdt_rel +
+ reserved_rrs_relocs * sizeof(struct relocation_info);
+ rrs_sdt.sdt_nzlist = rrs_sdt.sdt_hash +
+ number_of_rrs_hash_entries * sizeof(struct rrs_hash);
+ rrs_sdt.sdt_strings = rrs_sdt.sdt_nzlist +
+ number_of_rrs_symbols * rrs_symbol_size;
+ rrs_sdt.sdt_str_sz = rrs_strtab_size;
+ rrs_sdt.sdt_text_sz = text_size;
+ rrs_sdt.sdt_plt_sz = number_of_jmpslots * sizeof(jmpslot_t);
+
+ rrs_sdt.sdt_sods = rrs_shobjs ? rrs_sdt.sdt_strings+rrs_strtab_size : 0;
+ rrs_sdt.sdt_filler1 = 0;
+ rrs_sdt.sdt_filler2 = 0;
+
+ /*
+ * Assign addresses to _GLOBAL_OFFSET_TABLE_ and __DYNAMIC.
+ * The value `&__DYNAMIC' is in the GOT table at offset 0.
+ */
+ got_symbol->value = rrs_sdt.sdt_got + got_origin;
+ *GOTP(0) = dynamic_symbol->value = rrs_data_start;
+
+}
+
+void
+write_rrs_data()
+{
+ long pos;
+
+ if (rrs_section_type == RRS_NONE)
+ return;
+
+ pos = rrs_data_start + (N_DATOFF(outheader) - DATA_START(outheader));
+ if (fseek(outstream, pos, SEEK_SET) != 0)
+ err(1, "write_rrs_data: fseek");
+
+ if (rrs_section_type == RRS_PARTIAL) {
+ /*
+ * Only a GOT and PLT are needed.
+ */
+ md_swapout_got(rrs_got, number_of_gotslots);
+ mywrite(rrs_got, number_of_gotslots, sizeof(got_t), outstream);
+
+ md_swapout_jmpslot(rrs_plt, number_of_jmpslots);
+ mywrite(rrs_plt, number_of_jmpslots,
+ sizeof(jmpslot_t), outstream);
+
+ return;
+ }
+
+ md_swapout__dynamic(&rrs_dyn);
+ mywrite(&rrs_dyn, 1, sizeof(struct _dynamic), outstream);
+
+ md_swapout_so_debug(&rrs_so_debug);
+ mywrite(&rrs_so_debug, 1, sizeof(struct so_debug), outstream);
+
+ md_swapout_section_dispatch_table(&rrs_sdt);
+ mywrite(&rrs_sdt, 1, sizeof(struct section_dispatch_table), outstream);
+
+ md_swapout_got(rrs_got, number_of_gotslots);
+ mywrite(rrs_got, number_of_gotslots, sizeof(got_t), outstream);
+
+ md_swapout_jmpslot(rrs_plt, number_of_jmpslots);
+ mywrite(rrs_plt, number_of_jmpslots, sizeof(jmpslot_t), outstream);
+}
+
+void
+write_rrs_text()
+{
+ long pos;
+ int i;
+ int symsize;
+ struct nzlist *nlp;
+ int offset = 0;
+ struct shobj *shp;
+ struct sod *sodp;
+ int bind;
+
+ if (rrs_section_type == RRS_PARTIAL)
+ return;
+
+ pos = rrs_text_start + (N_TXTOFF(outheader) - TEXT_START(outheader));
+ if (fseek(outstream, pos, SEEK_SET) != 0)
+ err(1, "write_rrs_text: fseek");
+
+ /* Write relocation records */
+ md_swapout_reloc(rrs_reloc, reserved_rrs_relocs);
+ mywrite(rrs_reloc, reserved_rrs_relocs,
+ sizeof(struct relocation_info), outstream);
+
+ /* Write the RRS symbol hash tables */
+ md_swapout_rrs_hash(rrs_hashtab, number_of_rrs_hash_entries);
+ mywrite(rrs_hashtab, number_of_rrs_hash_entries,
+ sizeof(struct rrs_hash), outstream);
+
+ /*
+ * Determine size of an RRS symbol entry, allocate space
+ * to collect them in.
+ */
+ symsize = number_of_rrs_symbols * rrs_symbol_size;
+ nlp = rrs_symbols = (struct nzlist *)alloca(symsize);
+ rrs_strtab = (char *)alloca(rrs_strtab_size);
+
+#define INCR_NLP(p) ((p) = (struct nzlist *)((long)(p) + rrs_symbol_size))
+
+ /* __DYNAMIC symbol *must* be first for Sun compatibility */
+ nlp->nz_desc = nlp->nz_other = 0;
+ if (LD_VERSION_NZLIST_P(soversion))
+ nlp->nz_size = 0;
+ nlp->nz_type = dynamic_symbol->defined;
+ nlp->nz_value = dynamic_symbol->value;
+ nlp->nz_value = dynamic_symbol->value;
+ nlp->nz_strx = offset;
+ strcpy(rrs_strtab + offset, dynamic_symbol->name);
+ offset += 1 + strlen(dynamic_symbol->name);
+ INCR_NLP(nlp);
+
+ /*
+ * Now, for each global symbol, construct a nzlist element
+ * for inclusion in the RRS symbol table.
+ */
+ FOR_EACH_SYMBOL(i, sp) {
+
+ if (sp == dynamic_symbol)
+ continue;
+
+ if ((link_mode & SHAREABLE) && sp->warning) {
+ /*
+ * Write a N_WARNING duo.
+ */
+ nlp->nz_type = N_WARNING;
+ nlp->nz_un.n_strx = offset;
+ nlp->nz_value = 0;
+ nlp->nz_other = 0;
+ nlp->nz_desc = 0;
+ nlp->nz_size = 0;
+ strcpy(rrs_strtab + offset, sp->warning);
+ offset += 1 + strlen(sp->warning);
+ INCR_NLP(nlp);
+
+ nlp->nz_type = N_UNDF + N_EXT;
+ nlp->nz_un.n_strx = offset;
+ nlp->nz_value = 0;
+ nlp->nz_other = 0;
+ nlp->nz_desc = 0;
+ nlp->nz_size = 0;
+ strcpy(rrs_strtab + offset, sp->name);
+ offset += 1 + strlen(sp->name);
+ INCR_NLP(nlp);
+ }
+
+ if (!(sp->flags & GS_REFERENCED))
+ continue;
+
+ if ((long)nlp - (long)rrs_symbols >=
+ number_of_rrs_symbols * rrs_symbol_size)
+ errx(1, "internal error: "
+ "rrs symbols exceed allocation %d",
+ number_of_rrs_symbols);
+
+ nlp->nz_desc = 0;
+ nlp->nz_other = 0;
+ if (LD_VERSION_NZLIST_P(soversion))
+ nlp->nz_size = 0;
+
+ bind = (sp->flags & GS_WEAK) ? BIND_WEAK : 0;
+
+ if (sp->defined > 1) {
+ /* defined with known type */
+ if (!(link_mode & SHAREABLE) &&
+ sp->alias && sp->alias->defined > 1) {
+ /*
+ * If the target of an indirect symbol has
+ * been defined and we are outputting an
+ * executable, resolve the indirection; it's
+ * no longer needed.
+ */
+ nlp->nz_type = sp->alias->defined;
+ nlp->nz_value = sp->alias->value;
+ nlp->nz_other = N_OTHER(bind, sp->alias->aux);
+ } else if (sp->defined == N_SIZE) {
+ /*
+ * Make sure this symbol isn't going
+ * to define anything.
+ */
+ nlp->nz_type = N_UNDF;
+ nlp->nz_value = 0;
+ } else {
+ nlp->nz_type = sp->defined;
+ nlp->nz_value = sp->value;
+ nlp->nz_other = N_OTHER(bind, sp->aux);
+ }
+ if (LD_VERSION_NZLIST_P(soversion))
+ nlp->nz_size = sp->size;
+ } else if (sp->common_size) {
+ /*
+ * A common definition.
+ */
+ nlp->nz_type = N_UNDF | N_EXT;
+ nlp->nz_value = sp->common_size;
+ nlp->nz_other = N_OTHER(bind, 0);
+ } else if (!sp->defined) {
+ /* undefined */
+ nlp->nz_type = N_UNDF | N_EXT;
+ nlp->nz_value = 0;
+ if (sp->so_defined && sp->jmpslot_offset != -1) {
+ /*
+ * A PLT entry. The auxiliary type -- which
+ * must be AUX_FUNC -- is used by the run-time
+ * linker to unambiguously resolve function
+ * address references.
+ */
+ if (sp->aux != AUX_FUNC)
+ errx(1, "%s: non-function jmpslot",
+ sp->name);
+ nlp->nz_other = N_OTHER(bind, sp->aux);
+ nlp->nz_value =
+ rrs_sdt.sdt_plt + sp->jmpslot_offset;
+ }
+ } else
+ errx(1, "internal error: %s defined in mysterious way",
+ sp->name);
+
+ /* Set symbol's name */
+ nlp->nz_strx = offset;
+ strcpy(rrs_strtab + offset, sp->name);
+ offset += 1 + strlen(sp->name);
+
+ if (sp->alias) {
+ /*
+ * Write an extra symbol for indirections (possibly
+ * just a dummy).
+ */
+ int t = (nlp->nz_type == N_INDR + N_EXT);
+
+ INCR_NLP(nlp);
+ nlp->nz_type = N_UNDF + (t ? N_EXT : 0);
+ nlp->nz_un.n_strx = offset;
+ nlp->nz_value = 0;
+ nlp->nz_other = 0;
+ nlp->nz_desc = 0;
+ nlp->nz_size = 0;
+ strcpy(rrs_strtab + offset, sp->alias->name);
+ offset += 1 + strlen(sp->alias->name);
+ }
+
+ INCR_NLP(nlp);
+
+ } END_EACH_SYMBOL;
+
+ if (MALIGN(offset) != rrs_strtab_size)
+ errx(1, "internal error: "
+ "inconsistent RRS string table length: %d, expected %d",
+ offset, rrs_strtab_size);
+
+ /* Write the symbol table */
+ if (rrs_symbol_size == sizeof(struct nlist))
+ md_swapout_symbols(rrs_symbols, number_of_rrs_symbols);
+ else
+ md_swapout_zsymbols(rrs_symbols, number_of_rrs_symbols);
+ mywrite(rrs_symbols, symsize, 1, outstream);
+
+ /* Write the strings */
+ mywrite(rrs_strtab, rrs_strtab_size, 1, outstream);
+
+ /*
+ * Write the names of the shared objects needed at run-time
+ */
+ pos = rrs_sdt.sdt_sods + number_of_shobjs * sizeof(struct sod);
+ sodp = (struct sod *)alloca( number_of_shobjs * sizeof(struct sod));
+
+ for (i = 0, shp = rrs_shobjs; shp; i++, shp = shp->next) {
+ char *name = shp->entry->local_sym_name;
+
+ if (i >= number_of_shobjs)
+ errx(1, "internal error: # of link objects exceeds %d",
+ number_of_shobjs);
+
+ sodp[i].sod_name = pos;
+ sodp[i].sod_major = shp->entry->lib_major;
+ sodp[i].sod_minor = shp->entry->lib_minor;
+
+ if (*name == '-' && *(name+1) == 'l') {
+ name += 2;
+ sodp[i].sod_library = 1;
+ } else
+ sodp[i].sod_library = 0;
+
+ pos += 1 + strlen(name);
+ sodp[i].sod_next = (i == number_of_shobjs - 1) ? 0 :
+ (rrs_sdt.sdt_sods + (i+1)*sizeof(struct sod));
+ }
+
+ if (i < number_of_shobjs)
+ errx(1, "internal error: "
+ "# of link objects less then expected %d",
+ number_of_shobjs);
+
+ md_swapout_sod(sodp, number_of_shobjs);
+ mywrite(sodp, number_of_shobjs, sizeof(struct sod), outstream);
+
+ for (i = 0, shp = rrs_shobjs; shp; i++, shp = shp->next) {
+ char *name = shp->entry->local_sym_name;
+
+ if (*name == '-' && *(name+1) == 'l') {
+ name += 2;
+ }
+
+ mywrite(name, strlen(name) + 1, 1, outstream);
+ }
+}
+
+void
+write_rrs()
+{
+
+ /*
+ * First, do some consistency checks on the RRS segment.
+ */
+ if (rrs_section_type == RRS_NONE) {
+ if (reserved_rrs_relocs > 1)
+ errx(1, "internal error: "
+ "RRS relocs in static program: %d",
+ reserved_rrs_relocs-1);
+ return;
+ }
+
+#ifdef DEBUG
+printf("rrs_relocs: reserved %d claimed %d discarded %d, gotslots %d jmpslots %d\n",
+ reserved_rrs_relocs, claimed_rrs_relocs, discarded_rrs_relocs,
+ number_of_gotslots-1, number_of_jmpslots-1);
+#endif
+
+ /* Final consistency check */
+ if (claimed_rrs_relocs + discarded_rrs_relocs != reserved_rrs_relocs) {
+ errx(1, "internal error: "
+ "reserved relocs(%d) != claimed(%d) + discarded(%d)",
+ reserved_rrs_relocs,
+ claimed_rrs_relocs,
+ discarded_rrs_relocs);
+ }
+
+ /* Write the RRS segments. */
+ write_rrs_text ();
+ write_rrs_data ();
+}
diff --git a/gnu/usr.bin/ld/rtld/Makefile b/gnu/usr.bin/ld/rtld/Makefile
new file mode 100644
index 0000000..5898649
--- /dev/null
+++ b/gnu/usr.bin/ld/rtld/Makefile
@@ -0,0 +1,33 @@
+# $Id: Makefile,v 1.17 1996/01/11 17:27:16 phk Exp $
+
+PROG= ld.so
+SRCS= mdprologue.S rtld.c malloc.c shlib.c etc.c md.c
+MAN1= rtld.1
+LDDIR?= $(.CURDIR)/..
+PICFLAG=-fpic
+CFLAGS+=-I$(LDDIR) -I$(.CURDIR) -I$(LDDIR)/$(MACHINE) $(PICFLAG) -DRTLD
+LDFLAGS+=-Bshareable -Bsymbolic -assert nosymbolic
+ASFLAGS+=-k
+DPADD+= ${LIBC:S/c.a/c_pic.a/} ${LIBC:S/c.a/gcc_pic.a/}
+LDADD+= -lc_pic -lgcc_pic
+BINDIR= /usr/libexec
+MLINKS= rtld.1 ld.so.1
+
+.PATH: $(LDDIR) $(LDDIR)/$(MACHINE)
+
+$(PROG): ${OBJS} ${DPADD}
+ $(LD) -o $(PROG) $(LDFLAGS) $(OBJS) $(LDADD)
+
+realinstall:
+ ${INSTALL} ${COPY} ${STRIP} -o ${BINOWN} -g ${BINGRP} -m ${BINMODE} \
+ ${INSTALLFLAGS} ${PROG} ${DESTDIR}${BINDIR}/${PROG}.new
+ test -f ${DESTDIR}${BINDIR}/${PROG}.old && \
+ chflags noschg ${DESTDIR}${BINDIR}/${PROG}.old || \
+ :
+ -chflags noschg ${DESTDIR}${BINDIR}/${PROG}
+ -ln -f ${DESTDIR}${BINDIR}/${PROG} ${DESTDIR}${BINDIR}/${PROG}.old
+ mv ${DESTDIR}${BINDIR}/${PROG}.new ${DESTDIR}${BINDIR}/${PROG}
+ chflags schg ${DESTDIR}${BINDIR}/${PROG}
+ -rm ${DESTDIR}${BINDIR}/${PROG}.old
+
+.include <bsd.prog.mk>
diff --git a/gnu/usr.bin/ld/rtld/malloc.c b/gnu/usr.bin/ld/rtld/malloc.c
new file mode 100644
index 0000000..60e6ec3
--- /dev/null
+++ b/gnu/usr.bin/ld/rtld/malloc.c
@@ -0,0 +1,481 @@
+/*
+ * Copyright (c) 1983 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+/*static char *sccsid = "from: @(#)malloc.c 5.11 (Berkeley) 2/23/91";*/
+static char *rcsid = "$Id: malloc.c,v 1.3 1995/03/04 17:46:24 nate Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+/*
+ * malloc.c (Caltech) 2/21/82
+ * Chris Kingsley, kingsley@cit-20.
+ *
+ * This is a very fast storage allocator. It allocates blocks of a small
+ * number of different sizes, and keeps free lists of each size. Blocks that
+ * don't exactly fit are passed up to the next larger size. In this
+ * implementation, the available sizes are 2^n-4 (or 2^n-10) bytes long.
+ * This is designed for use in a virtual memory environment.
+ */
+
+#include <sys/types.h>
+#include <err.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/param.h>
+#include <sys/mman.h>
+#ifndef BSD
+#define MAP_COPY MAP_PRIVATE
+#define MAP_FILE 0
+#define MAP_ANON 0
+#endif
+
+#ifndef BSD /* Need do better than this */
+#define NEED_DEV_ZERO 1
+#endif
+
+#define NULL 0
+
+static void morecore();
+static int findbucket();
+
+/*
+ * Pre-allocate mmap'ed pages
+ */
+#define NPOOLPAGES (32*1024/pagesz)
+static caddr_t pagepool_start, pagepool_end;
+static int morepages();
+
+/*
+ * The overhead on a block is at least 4 bytes. When free, this space
+ * contains a pointer to the next free block, and the bottom two bits must
+ * be zero. When in use, the first byte is set to MAGIC, and the second
+ * byte is the size index. The remaining bytes are for alignment.
+ * If range checking is enabled then a second word holds the size of the
+ * requested block, less 1, rounded up to a multiple of sizeof(RMAGIC).
+ * The order of elements is critical: ov_magic must overlay the low order
+ * bits of ov_next, and ov_magic can not be a valid ov_next bit pattern.
+ */
+union overhead {
+ union overhead *ov_next; /* when free */
+ struct {
+ u_char ovu_magic; /* magic number */
+ u_char ovu_index; /* bucket # */
+#ifdef RCHECK
+ u_short ovu_rmagic; /* range magic number */
+ u_int ovu_size; /* actual block size */
+#endif
+ } ovu;
+#define ov_magic ovu.ovu_magic
+#define ov_index ovu.ovu_index
+#define ov_rmagic ovu.ovu_rmagic
+#define ov_size ovu.ovu_size
+};
+
+#define MAGIC 0xef /* magic # on accounting info */
+#define RMAGIC 0x5555 /* magic # on range info */
+
+#ifdef RCHECK
+#define RSLOP sizeof (u_short)
+#else
+#define RSLOP 0
+#endif
+
+/*
+ * nextf[i] is the pointer to the next free block of size 2^(i+3). The
+ * smallest allocatable block is 8 bytes. The overhead information
+ * precedes the data area returned to the user.
+ */
+#define NBUCKETS 30
+static union overhead *nextf[NBUCKETS];
+extern char *sbrk();
+
+static int pagesz; /* page size */
+static int pagebucket; /* page size bucket */
+
+#ifdef MSTATS
+/*
+ * nmalloc[i] is the difference between the number of mallocs and frees
+ * for a given block size.
+ */
+static u_int nmalloc[NBUCKETS];
+#include <stdio.h>
+#endif
+
+#if defined(DEBUG) || defined(RCHECK)
+#define ASSERT(p) if (!(p)) botch("p")
+#include <stdio.h>
+static
+botch(s)
+ char *s;
+{
+ fprintf(stderr, "\r\nassertion botched: %s\r\n", s);
+ (void) fflush(stderr); /* just in case user buffered it */
+ abort();
+}
+#else
+#define ASSERT(p)
+#endif
+
+void *
+malloc(nbytes)
+ size_t nbytes;
+{
+ register union overhead *op;
+ register int bucket, n;
+ register unsigned amt;
+
+ /*
+ * First time malloc is called, setup page size and
+ * align break pointer so all data will be page aligned.
+ */
+ if (pagesz == 0) {
+ pagesz = n = getpagesize();
+ if (morepages(NPOOLPAGES) == 0)
+ return NULL;
+ op = (union overhead *)(pagepool_start);
+ n = n - sizeof (*op) - ((int)op & (n - 1));
+ if (n < 0)
+ n += pagesz;
+ if (n) {
+ pagepool_start += n;
+ }
+ bucket = 0;
+ amt = 8;
+ while (pagesz > amt) {
+ amt <<= 1;
+ bucket++;
+ }
+ pagebucket = bucket;
+ }
+ /*
+ * Convert amount of memory requested into closest block size
+ * stored in hash buckets which satisfies request.
+ * Account for space used per block for accounting.
+ */
+ if (nbytes <= (n = pagesz - sizeof (*op) - RSLOP)) {
+#ifndef RCHECK
+ amt = 8; /* size of first bucket */
+ bucket = 0;
+#else
+ amt = 16; /* size of first bucket */
+ bucket = 1;
+#endif
+ n = -(sizeof (*op) + RSLOP);
+ } else {
+ amt = pagesz;
+ bucket = pagebucket;
+ }
+ while (nbytes > amt + n) {
+ amt <<= 1;
+ if (amt == 0)
+ return (NULL);
+ bucket++;
+ }
+ /*
+ * If nothing in hash bucket right now,
+ * request more memory from the system.
+ */
+ if ((op = nextf[bucket]) == NULL) {
+ morecore(bucket);
+ if ((op = nextf[bucket]) == NULL)
+ return (NULL);
+ }
+ /* remove from linked list */
+ nextf[bucket] = op->ov_next;
+ op->ov_magic = MAGIC;
+ op->ov_index = bucket;
+#ifdef MSTATS
+ nmalloc[bucket]++;
+#endif
+#ifdef RCHECK
+ /*
+ * Record allocated size of block and
+ * bound space with magic numbers.
+ */
+ op->ov_size = (nbytes + RSLOP - 1) & ~(RSLOP - 1);
+ op->ov_rmagic = RMAGIC;
+ *(u_short *)((caddr_t)(op + 1) + op->ov_size) = RMAGIC;
+#endif
+ return ((char *)(op + 1));
+}
+
+/*
+ * Allocate more memory to the indicated bucket.
+ */
+static void
+morecore(bucket)
+ int bucket;
+{
+ register union overhead *op;
+ register int sz; /* size of desired block */
+ int amt; /* amount to allocate */
+ int nblks; /* how many blocks we get */
+
+ /*
+ * sbrk_size <= 0 only for big, FLUFFY, requests (about
+ * 2^30 bytes on a VAX, I think) or for a negative arg.
+ */
+ sz = 1 << (bucket + 3);
+#ifdef DEBUG
+ ASSERT(sz > 0);
+#else
+ if (sz <= 0)
+ return;
+#endif
+ if (sz < pagesz) {
+ amt = pagesz;
+ nblks = amt / sz;
+ } else {
+ amt = sz + pagesz;
+ nblks = 1;
+ }
+ if (amt > pagepool_end - pagepool_start)
+ if (morepages(amt/pagesz + NPOOLPAGES) == 0)
+ return;
+ op = (union overhead *)pagepool_start;
+ pagepool_start += amt;
+
+ /*
+ * Add new memory allocated to that on
+ * free list for this hash bucket.
+ */
+ nextf[bucket] = op;
+ while (--nblks > 0) {
+ op->ov_next = (union overhead *)((caddr_t)op + sz);
+ op = (union overhead *)((caddr_t)op + sz);
+ }
+}
+
+void
+free(cp)
+ void *cp;
+{
+ register int size;
+ register union overhead *op;
+
+ if (cp == NULL)
+ return;
+ op = (union overhead *)((caddr_t)cp - sizeof (union overhead));
+#ifdef DEBUG
+ ASSERT(op->ov_magic == MAGIC); /* make sure it was in use */
+#else
+ if (op->ov_magic != MAGIC)
+ return; /* sanity */
+#endif
+#ifdef RCHECK
+ ASSERT(op->ov_rmagic == RMAGIC);
+ ASSERT(*(u_short *)((caddr_t)(op + 1) + op->ov_size) == RMAGIC);
+#endif
+ size = op->ov_index;
+ ASSERT(size < NBUCKETS);
+ op->ov_next = nextf[size]; /* also clobbers ov_magic */
+ nextf[size] = op;
+#ifdef MSTATS
+ nmalloc[size]--;
+#endif
+}
+
+/*
+ * When a program attempts "storage compaction" as mentioned in the
+ * old malloc man page, it realloc's an already freed block. Usually
+ * this is the last block it freed; occasionally it might be farther
+ * back. We have to search all the free lists for the block in order
+ * to determine its bucket: 1st we make one pass thru the lists
+ * checking only the first block in each; if that fails we search
+ * ``realloc_srchlen'' blocks in each list for a match (the variable
+ * is extern so the caller can modify it). If that fails we just copy
+ * however many bytes was given to realloc() and hope it's not huge.
+ */
+int realloc_srchlen = 4; /* 4 should be plenty, -1 =>'s whole list */
+
+void *
+realloc(cp, nbytes)
+ void *cp;
+ size_t nbytes;
+{
+ register u_int onb;
+ register int i;
+ union overhead *op;
+ char *res;
+ int was_alloced = 0;
+
+ if (cp == NULL)
+ return (malloc(nbytes));
+ op = (union overhead *)((caddr_t)cp - sizeof (union overhead));
+ if (op->ov_magic == MAGIC) {
+ was_alloced++;
+ i = op->ov_index;
+ } else {
+ /*
+ * Already free, doing "compaction".
+ *
+ * Search for the old block of memory on the
+ * free list. First, check the most common
+ * case (last element free'd), then (this failing)
+ * the last ``realloc_srchlen'' items free'd.
+ * If all lookups fail, then assume the size of
+ * the memory block being realloc'd is the
+ * largest possible (so that all "nbytes" of new
+ * memory are copied into). Note that this could cause
+ * a memory fault if the old area was tiny, and the moon
+ * is gibbous. However, that is very unlikely.
+ */
+ if ((i = findbucket(op, 1)) < 0 &&
+ (i = findbucket(op, realloc_srchlen)) < 0)
+ i = NBUCKETS;
+ }
+ onb = 1 << (i + 3);
+ if (onb < pagesz)
+ onb -= sizeof (*op) + RSLOP;
+ else
+ onb += pagesz - sizeof (*op) - RSLOP;
+ /* avoid the copy if same size block */
+ if (was_alloced) {
+ if (i) {
+ i = 1 << (i + 2);
+ if (i < pagesz)
+ i -= sizeof (*op) + RSLOP;
+ else
+ i += pagesz - sizeof (*op) - RSLOP;
+ }
+ if (nbytes <= onb && nbytes > i) {
+#ifdef RCHECK
+ op->ov_size = (nbytes + RSLOP - 1) & ~(RSLOP - 1);
+ *(u_short *)((caddr_t)(op + 1) + op->ov_size) = RMAGIC;
+#endif
+ return(cp);
+ } else
+ free(cp);
+ }
+ if ((res = malloc(nbytes)) == NULL)
+ return (NULL);
+ if (cp != res) /* common optimization if "compacting" */
+ bcopy(cp, res, (nbytes < onb) ? nbytes : onb);
+ return (res);
+}
+
+/*
+ * Search ``srchlen'' elements of each free list for a block whose
+ * header starts at ``freep''. If srchlen is -1 search the whole list.
+ * Return bucket number, or -1 if not found.
+ */
+static
+findbucket(freep, srchlen)
+ union overhead *freep;
+ int srchlen;
+{
+ register union overhead *p;
+ register int i, j;
+
+ for (i = 0; i < NBUCKETS; i++) {
+ j = 0;
+ for (p = nextf[i]; p && j != srchlen; p = p->ov_next) {
+ if (p == freep)
+ return (i);
+ j++;
+ }
+ }
+ return (-1);
+}
+
+#ifdef MSTATS
+/*
+ * mstats - print out statistics about malloc
+ *
+ * Prints two lines of numbers, one showing the length of the free list
+ * for each size category, the second showing the number of mallocs -
+ * frees for each size category.
+ */
+mstats(s)
+ char *s;
+{
+ register int i, j;
+ register union overhead *p;
+ int totfree = 0,
+ totused = 0;
+
+ fprintf(stderr, "Memory allocation statistics %s\nfree:\t", s);
+ for (i = 0; i < NBUCKETS; i++) {
+ for (j = 0, p = nextf[i]; p; p = p->ov_next, j++)
+ ;
+ fprintf(stderr, " %d", j);
+ totfree += j * (1 << (i + 3));
+ }
+ fprintf(stderr, "\nused:\t");
+ for (i = 0; i < NBUCKETS; i++) {
+ fprintf(stderr, " %d", nmalloc[i]);
+ totused += nmalloc[i] * (1 << (i + 3));
+ }
+ fprintf(stderr, "\n\tTotal in use: %d, total free: %d\n",
+ totused, totfree);
+}
+#endif
+
+
+static int
+morepages(n)
+int n;
+{
+ int fd = -1;
+ int offset;
+
+#ifdef NEED_DEV_ZERO
+ fd = open("/dev/zero", O_RDWR, 0);
+ if (fd == -1)
+ perror("/dev/zero");
+#endif
+
+ if (pagepool_end - pagepool_start > pagesz) {
+ caddr_t addr = (caddr_t)
+ (((int)pagepool_start + pagesz - 1) & ~(pagesz - 1));
+ if (munmap(addr, pagepool_end - addr) != 0)
+ warn("morepages: munmap %p", addr);
+ }
+
+ offset = (int)pagepool_start - ((int)pagepool_start & ~(pagesz - 1));
+
+ if ((pagepool_start = mmap(0, n * pagesz,
+ PROT_READ|PROT_WRITE,
+ MAP_ANON|MAP_COPY, fd, 0)) == (caddr_t)-1) {
+ xprintf("Cannot map anonymous memory");
+ return 0;
+ }
+ pagepool_end = pagepool_start + n * pagesz;
+ pagepool_start += offset;
+
+#ifdef NEED_DEV_ZERO
+ close(fd);
+#endif
+ return n;
+}
diff --git a/gnu/usr.bin/ld/rtld/md-prologue.c b/gnu/usr.bin/ld/rtld/md-prologue.c
new file mode 100644
index 0000000..dae455e
--- /dev/null
+++ b/gnu/usr.bin/ld/rtld/md-prologue.c
@@ -0,0 +1,39 @@
+/*
+ * rtld entry pseudo code - turn into assembler and tweak it
+ */
+
+#include <sys/types.h>
+#include <sys/types.h>
+#include <a.out.h>
+#include "link.h"
+#include "md.h"
+
+extern long _GOT_[];
+extern void (*rtld)();
+extern void (*binder())();
+
+void
+rtld_entry(version, crtp)
+int version;
+struct crt *crtp;
+{
+ register struct link_dynamic *dp;
+ register void (*f)();
+
+ /* __DYNAMIC is first entry in GOT */
+ dp = (struct link_dynamic *) (_GOT_[0]+crtp->crt_ba);
+
+ f = (void (*)())((long)rtld + crtp->crt_ba);
+ (*f)(version, crtp, dp);
+}
+
+void
+binder_entry()
+{
+ extern int PC;
+ struct jmpslot *sp;
+ void (*func)();
+
+ func = binder(PC, sp->reloc_index & 0x003fffff);
+ (*func)();
+}
diff --git a/gnu/usr.bin/ld/rtld/rtld.1 b/gnu/usr.bin/ld/rtld/rtld.1
new file mode 100644
index 0000000..2b3c75a
--- /dev/null
+++ b/gnu/usr.bin/ld/rtld/rtld.1
@@ -0,0 +1,144 @@
+.\" $Id$
+.\"
+.\" Copyright (c) 1995 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.
+.\" 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.
+.\"
+.Dd June 27, 1995
+.Dt RTLD 1
+.Os FreeBSD
+.Sh NAME
+.Nm ld.so
+.Nd run-time link-editor
+.Sh DESCRIPTION
+.Nm
+is a self-contained, position independent program image providing run-time
+support for loading and link-editing shared objects into a process'
+address space. It uses the data structures
+.Po
+see
+.Xr link 5
+.Pc
+contained within dynamically linked programs to determine which shared
+libraries are needed and loads them at a convenient virtual address
+using the
+.Xr mmap 2
+system call.
+.Pp
+After all shared libraries have been succesfully loaded,
+.Nm
+proceeds to resolve external references from both the main program and
+all objects loaded. A mechanism is provided for initialisation routines
+to be called, on a per-object basis, giving a shared object an opportunity
+to perfrom any extra set-up, before execution of the program proper begins.
+This is useful for C++ libraries that contain static constrictors.
+.Pp
+.Nm
+is itself a shared object that is initially loaded by the startup module
+.Em crt0 .
+Since
+.Xr a.out 5
+formats do not provide easy access to the file header from within a running
+process,
+.Em crt0
+uses the special symbol
+.Va _DYNAMIC
+to determine whether a program is in fact dynamically linked or not. Whenever
+the linker
+.Xr ld 1
+has relocated this symbol to a location other then 0,
+.Em crt0
+assumes the services of
+.Nm
+are needed
+.Po
+see
+.Xr link 5
+for details
+.Pc \&.
+.Em crt0
+passes control to
+.Nm
+\&'s entry point before the program's
+.Fn main
+routine is called. Thus,
+.Nm
+can complete the link-editing process before the dynamic program calls upon
+services of any dynamic library.
+.Pp
+To quickly locate the required shared objects in the filesystem,
+.Nm
+may use a
+.Dq hints
+file, prepared by the
+.Xr ldconfig 8
+utility, in which the full path specification of the shared objects can be
+looked up by hashing on the 3-tuple
+.Ao
+library-name, major-version-number, minor-version-number
+.Ac \&.
+.Pp
+.Nm
+recognises a number of environment variables that can be used to modify
+its behaviour as follows:
+.Pp
+.Bl -tag -width "LD_TRACE_LOADED_OBJECTS"
+.It Ev LD_LIBRARY_PATH
+A colon separated list of directories, overriding the default search path
+for shared libraries.
+.It Ev LD_WARN_NON_PURE_CODE
+When set, issue a warning whenever a link-editing operation requires
+modification of the text segment of some loaded object. This is usually
+indicative of an incorrectly built library.
+.It Ev LD_SUPPRESS_WARNINGS
+When set, no warning messages of any kind are issued. Normally, a warning
+is given if satisfactorily versioned library could not be found.
+.It Ev LD_TRACE_LOADED_OBJECTS
+When set, causes
+.Nm
+to exit after loading the shared objects and printing a summary which includes
+the absolute pathnames of all objects, to standard output.
+.It Ev LD_NO_INTERN_SEARCH
+When set,
+.Nm
+does not process any internal search paths that were recorded in the
+executable.
+.It Ev LD_NOSTD_PATH
+When set, do not include a set of built-in standard directory paths for
+searching. This might be useful when running on a system with a completely
+non-standard filesystem layout.
+.El
+.Pp
+.Sh FILES
+/var/run/ld.so.hints
+.Pp
+.Sh SEE ALSO
+.Xr ld 1
+.Xr ldconfig 8
+.Xr link 5
+.Sh HISTORY
+The shared library model employed first appeared in SunOS 4.0
diff --git a/gnu/usr.bin/ld/rtld/rtld.c b/gnu/usr.bin/ld/rtld/rtld.c
new file mode 100644
index 0000000..3300538
--- /dev/null
+++ b/gnu/usr.bin/ld/rtld/rtld.c
@@ -0,0 +1,1704 @@
+/*
+ * 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: rtld.c,v 1.31.1.5 1995/11/28 01:15:45 jdp Exp jdp $
+ */
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/file.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <sys/errno.h>
+#include <sys/mman.h>
+#ifndef MAP_COPY
+#define MAP_COPY MAP_PRIVATE
+#endif
+#include <err.h>
+#include <fcntl.h>
+#include <a.out.h>
+#include <stab.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#if __STDC__
+#include <stdarg.h>
+#else
+#include <varargs.h>
+#endif
+
+#include "ld.h"
+
+#ifndef MAP_ANON
+#define MAP_ANON 0
+#define anon_open() do { \
+ if ((anon_fd = open("/dev/zero", O_RDWR, 0)) == -1) \
+ err("open: %s", "/dev/zero"); \
+} while (0)
+#define anon_close() do { \
+ (void)close(anon_fd); \
+ anon_fd = -1; \
+} while (0)
+#else
+#define anon_open()
+#define anon_close()
+#endif
+
+/*
+ * Structure for building a list of shared objects.
+ */
+struct so_list {
+ struct so_map *sol_map; /* Link map for shared object */
+ struct so_list *sol_next; /* Next entry in the list */
+};
+
+/*
+ * Loader private data, hung off <so_map>->som_spd
+ */
+struct somap_private {
+ int spd_version;
+ struct so_map *spd_parent;
+ struct so_list *spd_children;
+ struct so_map *spd_prev;
+ int spd_refcount;
+ int spd_flags;
+#define RTLD_MAIN 0x01
+#define RTLD_RTLD 0x02
+#define RTLD_DL 0x04
+#define RTLD_INIT 0x08
+#define RTLD_TRACED 0x10
+ unsigned long a_text; /* text size, if known */
+ unsigned long a_data; /* initialized data size */
+ unsigned long a_bss; /* uninitialized data size */
+
+#ifdef SUN_COMPAT
+ long spd_offset; /* Correction for Sun main programs */
+#endif
+};
+
+#define LM_PRIVATE(smp) ((struct somap_private *)(smp)->som_spd)
+
+#ifdef SUN_COMPAT
+#define LM_OFFSET(smp) (LM_PRIVATE(smp)->spd_offset)
+#else
+#define LM_OFFSET(smp) (0)
+#endif
+
+/* Base address for section_dispatch_table entries */
+#define LM_LDBASE(smp) (smp->som_addr + LM_OFFSET(smp))
+
+/* Start of text segment */
+#define LM_TXTADDR(smp) (smp->som_addr == (caddr_t)0 ? PAGSIZ : 0)
+
+/* Start of run-time relocation_info */
+#define LM_REL(smp) ((struct relocation_info *) \
+ (smp->som_addr + LM_OFFSET(smp) + LD_REL((smp)->som_dynamic)))
+
+/* Start of symbols */
+#define LM_SYMBOL(smp, i) ((struct nzlist *) \
+ (smp->som_addr + LM_OFFSET(smp) + LD_SYMBOL((smp)->som_dynamic) + \
+ i * (LD_VERSION_NZLIST_P(smp->som_dynamic->d_version) ? \
+ sizeof(struct nzlist) : sizeof(struct nlist))))
+
+/* Start of hash table */
+#define LM_HASH(smp) ((struct rrs_hash *) \
+ ((smp)->som_addr + LM_OFFSET(smp) + LD_HASH((smp)->som_dynamic)))
+
+/* Start of strings */
+#define LM_STRINGS(smp) ((char *) \
+ ((smp)->som_addr + LM_OFFSET(smp) + LD_STRINGS((smp)->som_dynamic)))
+
+/* End of text */
+#define LM_ETEXT(smp) ((char *) \
+ ((smp)->som_addr + LM_TXTADDR(smp) + LD_TEXTSZ((smp)->som_dynamic)))
+
+/* Needed shared objects */
+#define LM_NEED(smp) ((struct sod *) \
+ ((smp)->som_addr + LM_TXTADDR(smp) + LD_NEED((smp)->som_dynamic)))
+
+/* PLT is in data segment, so don't use LM_OFFSET here */
+#define LM_PLT(smp) ((jmpslot_t *) \
+ ((smp)->som_addr + LD_PLT((smp)->som_dynamic)))
+
+/* Parent of link map */
+#define LM_PARENT(smp) (LM_PRIVATE(smp)->spd_parent)
+
+char **environ;
+char *__progname;
+int errno;
+
+static uid_t uid, euid;
+static gid_t gid, egid;
+static int careful;
+static char __main_progname[] = "main";
+static char *main_progname = __main_progname;
+static char us[] = "/usr/libexec/ld.so";
+static int anon_fd = -1;
+static char *ld_library_path;
+static int tracing;
+
+struct so_map *link_map_head;
+struct so_map *link_map_tail;
+struct rt_symbol *rt_symbol_head;
+
+static void *__dlopen __P((char *, int));
+static int __dlclose __P((void *));
+static void *__dlsym __P((void *, char *));
+static char *__dlerror __P((void));
+static void __dlexit __P((void));
+
+static struct ld_entry ld_entry = {
+ __dlopen, __dlclose, __dlsym, __dlerror, __dlexit
+};
+
+ void xprintf __P((char *, ...));
+static struct so_map *map_object __P(( char *,
+ struct sod *,
+ struct so_map *));
+static int map_sods __P((struct so_map *));
+static int reloc_and_init __P((struct so_map *));
+static void unmap_object __P((struct so_map *, int));
+static struct so_map *alloc_link_map __P(( char *, struct sod *,
+ struct so_map *, caddr_t,
+ struct _dynamic *));
+static void free_link_map __P((struct so_map *));
+static inline int check_text_reloc __P(( struct relocation_info *,
+ struct so_map *,
+ caddr_t));
+static int reloc_map __P((struct so_map *));
+static void reloc_copy __P((struct so_map *));
+static void init_object __P((struct so_map *));
+static void init_sods __P((struct so_list *));
+static int call_map __P((struct so_map *, char *));
+static char *findhint __P((char *, int, int *));
+static char *rtfindlib __P((char *, int, int));
+void binder_entry __P((void));
+long binder __P((jmpslot_t *));
+static struct nzlist *lookup __P((char *, struct so_map **, int));
+static inline struct rt_symbol *lookup_rts __P((char *));
+static struct rt_symbol *enter_rts __P((char *, long, int, caddr_t,
+ long, struct so_map *));
+static void generror __P((char *, ...));
+static int maphints __P((void));
+static void unmaphints __P((void));
+
+static inline int
+strcmp (register const char *s1, register const char *s2)
+{
+ while (*s1 == *s2++)
+ if (*s1++ == 0)
+ return (0);
+ return (*(unsigned char *)s1 - *(unsigned char *)--s2);
+}
+
+#include "md-static-funcs.c"
+
+/*
+ * Called from assembler stub that has set up crtp (passed from crt0)
+ * and dp (our __DYNAMIC).
+ */
+int
+rtld(version, crtp, dp)
+int version;
+struct crt_ldso *crtp;
+struct _dynamic *dp;
+{
+ struct relocation_info *reloc;
+ struct relocation_info *reloc_limit; /* End+1 of relocation */
+ struct so_debug *ddp;
+ struct so_map *main_map;
+ struct so_map *smp;
+
+ /* Check version */
+ if (version != CRT_VERSION_BSD_2 &&
+ version != CRT_VERSION_BSD_3 &&
+ version != CRT_VERSION_SUN)
+ return -1;
+
+ /* Fixup __DYNAMIC structure */
+ (long)dp->d_un.d_sdt += crtp->crt_ba;
+
+ /* Relocate ourselves */
+ reloc = (struct relocation_info *) (LD_REL(dp) + crtp->crt_ba);
+ reloc_limit =
+ (struct relocation_info *) ((char *) reloc + LD_RELSZ(dp));
+ while(reloc < reloc_limit) {
+ /*
+ * Objects linked with "-Bsymbolic" (in particular, ld.so
+ * itself) can end up having unused relocation entries at
+ * the end. These can be detected by the fact that they
+ * have an address of 0.
+ */
+ if(reloc->r_address == 0) /* We're done */
+ break;
+ md_relocate_simple(reloc, crtp->crt_ba,
+ reloc->r_address + crtp->crt_ba);
+ ++reloc;
+ }
+
+ __progname = "ld.so";
+ if (version >= CRT_VERSION_BSD_3)
+ main_progname = crtp->crt_prog;
+
+ /* Setup out (private) environ variable */
+ environ = crtp->crt_ep;
+
+ /* Get user and group identifiers */
+ uid = getuid(); euid = geteuid();
+ gid = getgid(); egid = getegid();
+
+ careful = (uid != euid) || (gid != egid);
+
+ if (careful) {
+ unsetenv("LD_LIBRARY_PATH");
+ unsetenv("LD_PRELOAD");
+ } else
+ ld_library_path = getenv("LD_LIBRARY_PATH");
+
+ tracing = getenv("LD_TRACE_LOADED_OBJECTS") != NULL;
+
+ /*
+ * Setup the directory search list for findshlib. We use only
+ * the standard search path. Any extra directories from
+ * LD_LIBRARY_PATH are searched explicitly, in rtfindlib.
+ */
+ std_search_path();
+
+ anon_open();
+
+ /* Make a link map entry for the main program */
+ main_map = alloc_link_map(main_progname,
+ (struct sod *) NULL, (struct so_map *) NULL,
+ (caddr_t) 0, crtp->crt_dp);
+ LM_PRIVATE(main_map)->spd_refcount++;
+ LM_PRIVATE(main_map)->spd_flags |= RTLD_MAIN;
+
+ /* Make a link map entry for ourselves */
+ smp = alloc_link_map(us,
+ (struct sod *) NULL, (struct so_map *) NULL,
+ (caddr_t) crtp->crt_ba, dp);
+ LM_PRIVATE(smp)->spd_refcount++;
+ LM_PRIVATE(smp)->spd_flags |= RTLD_RTLD;
+
+ /* Fill in some fields in main's __DYNAMIC structure */
+ crtp->crt_dp->d_entry = &ld_entry;
+ crtp->crt_dp->d_un.d_sdt->sdt_loaded = link_map_head->som_next;
+
+ /* Map all the shared objects that the main program depends upon */
+ if(map_sods(main_map) == -1)
+ return -1;
+
+ if(tracing) /* We're done */
+ exit(0);
+
+ /* Relocate and initialize all mapped objects */
+ if(reloc_and_init(main_map) == -1) /* Failed */
+ return -1;
+
+ ddp = crtp->crt_dp->d_debug;
+ ddp->dd_cc = rt_symbol_head;
+ if (ddp->dd_in_debugger) {
+ caddr_t addr = (caddr_t)((long)crtp->crt_bp & (~(PAGSIZ - 1)));
+
+ /* Set breakpoint for the benefit of debuggers */
+ if (mprotect(addr, PAGSIZ,
+ PROT_READ|PROT_WRITE|PROT_EXEC) == -1) {
+ err(1, "Cannot set breakpoint (%s)", main_progname);
+ }
+ md_set_breakpoint((long)crtp->crt_bp, (long *)&ddp->dd_bpt_shadow);
+ if (mprotect(addr, PAGSIZ, PROT_READ|PROT_EXEC) == -1) {
+ err(1, "Cannot re-protect breakpoint (%s)",
+ main_progname);
+ }
+
+ ddp->dd_bpt_addr = crtp->crt_bp;
+ if (link_map_head)
+ ddp->dd_sym_loaded = 1;
+ }
+
+ /* Close the hints file */
+ unmaphints();
+
+ /* Close our file descriptor */
+ (void)close(crtp->crt_ldfd);
+ anon_close();
+
+ return LDSO_VERSION_HAS_DLEXIT;
+}
+
+
+/*
+ * Allocate a new link map and return a pointer to it.
+ *
+ * PATH is the pathname of the shared object.
+ *
+ * SODP is a pointer to the shared object dependency structure responsible
+ * for causing the new object to be loaded. PARENT is the shared object
+ * into which SODP points. Both can be NULL if the new object is not
+ * being loaded as a result of a shared object dependency.
+ *
+ * ADDR is the address at which the object has been mapped. DP is a pointer
+ * to its _dynamic structure.
+ */
+ static struct so_map *
+alloc_link_map(path, sodp, parent, addr, dp)
+ char *path;
+ struct sod *sodp;
+ struct so_map *parent;
+ caddr_t addr;
+ struct _dynamic *dp;
+{
+ struct so_map *smp;
+ struct somap_private *smpp;
+ size_t smp_size;
+
+#ifdef DEBUG /* { */
+ xprintf("alloc_link_map: \"%s\" at %p\n", path, addr);
+#endif /* } */
+
+ /*
+ * Allocate so_map and private area with a single malloc. Round
+ * up the size of so_map so the private area is aligned.
+ */
+ smp_size = ((((sizeof(struct so_map)) + sizeof (void *) - 1) /
+ sizeof (void *)) * sizeof (void *));
+
+ smp = (struct so_map *)xmalloc(smp_size +
+ sizeof (struct somap_private));
+ smpp = (struct somap_private *) (((caddr_t) smp) + smp_size);
+
+ /* Link the new entry into the list of link maps */
+ smp->som_next = NULL;
+ smpp->spd_prev = link_map_tail;
+ if(link_map_tail == NULL) /* First link map entered into list */
+ link_map_head = link_map_tail = smp;
+ else { /* Append to end of list */
+ link_map_tail->som_next = smp;
+ link_map_tail = smp;
+ }
+
+ smp->som_addr = addr;
+ smp->som_path = strdup(path);
+ smp->som_sod = sodp;
+ smp->som_dynamic = dp;
+ smp->som_spd = (caddr_t)smpp;
+
+ smpp->spd_refcount = 0;
+ smpp->spd_flags = 0;
+ smpp->spd_parent = parent;
+ smpp->spd_children = NULL;
+ smpp->a_text = 0;
+ smpp->a_data = 0;
+ smpp->a_bss = 0;
+#ifdef SUN_COMPAT
+ smpp->spd_offset =
+ (addr==0 && dp && dp->d_version==LD_VERSION_SUN) ? PAGSIZ : 0;
+#endif
+ return smp;
+}
+
+/*
+ * Remove the specified link map entry from the list of link maps, and free
+ * the associated storage.
+ */
+ static void
+free_link_map(smp)
+ struct so_map *smp;
+{
+ struct somap_private *smpp = LM_PRIVATE(smp);
+
+#ifdef DEBUG /* { */
+ xprintf("free_link_map: \"%s\"\n", smp->som_path);
+#endif /* } */
+
+ if(smpp->spd_prev == NULL) /* Removing first entry in list */
+ link_map_head = smp->som_next;
+ else /* Update link of previous entry */
+ smpp->spd_prev->som_next = smp->som_next;
+
+ if(smp->som_next == NULL) /* Removing last entry in list */
+ link_map_tail = smpp->spd_prev;
+ else /* Update back link of next entry */
+ LM_PRIVATE(smp->som_next)->spd_prev = smpp->spd_prev;
+
+ free(smp->som_path);
+ free(smp);
+}
+
+/*
+ * Map the shared object specified by PATH into memory, if it is not
+ * already mapped. Increment the object's reference count, and return a
+ * pointer to its link map.
+ *
+ * As a special case, if PATH is NULL, it is taken to refer to the main
+ * program.
+ *
+ * SODP is a pointer to the shared object dependency structure that caused
+ * this object to be requested. PARENT is a pointer to the link map of
+ * the shared object containing that structure. For a shared object not
+ * being mapped as a result of a shared object dependency, these pointers
+ * should be NULL. An example of this is a shared object that is explicitly
+ * loaded via dlopen().
+ *
+ * The return value is a pointer to the link map for the requested object.
+ * If the operation failed, the return value is NULL. In that case, an
+ * error message can be retrieved by calling dlerror().
+ */
+ static struct so_map *
+map_object(path, sodp, parent)
+ char *path;
+ struct sod *sodp;
+ struct so_map *parent;
+{
+ struct so_map *smp;
+
+ if(path == NULL) /* Special case for the main program itself */
+ smp = link_map_head;
+ else {
+ /* Check whether the shared object is already mapped */
+ for(smp = link_map_head; smp != NULL; smp = smp->som_next) {
+ if(!(LM_PRIVATE(smp)->spd_flags & (RTLD_MAIN|RTLD_RTLD))
+ && smp->som_path != NULL
+ && strcmp(smp->som_path, path) == 0)
+ break;
+ }
+ }
+
+ if (smp == NULL) { /* We must map the object */
+ struct _dynamic *dp;
+ int fd;
+ caddr_t addr;
+ struct exec hdr;
+ struct somap_private *smpp;
+
+ if ((fd = open(path, O_RDONLY, 0)) == -1) {
+ generror ("open failed for \"%s\" : %s",
+ path, strerror (errno));
+ return NULL;
+ }
+
+ if (read(fd, &hdr, sizeof(hdr)) != sizeof(hdr)) {
+ generror ("header read failed for \"%s\"", path);
+ (void)close(fd);
+ return NULL;
+ }
+
+ if (N_BADMAG(hdr)) {
+ generror ("bad magic number in \"%s\"", path);
+ (void)close(fd);
+ return NULL;
+ }
+
+ /*
+ * Map the entire address space of the object. It is
+ * tempting to map just the text segment at first, in
+ * order to avoid having to use mprotect to change the
+ * protections of the data segment. But that would not
+ * be correct. Mmap might find a group of free pages
+ * large enough to hold the text segment, but not large
+ * enough for the entire object. When we then mapped
+ * in the data and BSS segments, they would either be
+ * non-contiguous with the text segment (if we didn't
+ * specify MAP_FIXED), or they would map over some
+ * previously mapped region (if we did use MAP_FIXED).
+ * The only way we can be sure of getting a contigous
+ * region that is large enough is to map the entire
+ * region at once.
+ */
+ if ((addr = mmap(0, hdr.a_text + hdr.a_data + hdr.a_bss,
+ PROT_READ|PROT_EXEC,
+ MAP_COPY, fd, 0)) == (caddr_t)-1) {
+ generror ("mmap failed for \"%s\" : %s",
+ path, strerror (errno));
+ (void)close(fd);
+ return NULL;
+ }
+
+ (void)close(fd);
+
+ /* Change the data segment to writable */
+ if (mprotect(addr + hdr.a_text, hdr.a_data,
+ PROT_READ|PROT_WRITE|PROT_EXEC) != 0) {
+ generror ("mprotect failed for \"%s\" : %s",
+ path, strerror (errno));
+ (void)munmap(addr, hdr.a_text + hdr.a_data + hdr.a_bss);
+ return NULL;
+ }
+
+ /* Map in pages of zeros for the BSS segment */
+ if (mmap(addr + hdr.a_text + hdr.a_data, hdr.a_bss,
+ PROT_READ|PROT_WRITE|PROT_EXEC,
+ MAP_ANON|MAP_COPY|MAP_FIXED,
+ anon_fd, 0) == (caddr_t)-1) {
+ generror ("mmap failed for \"%s\" : %s",
+ path, strerror (errno));
+ (void)munmap(addr, hdr.a_text + hdr.a_data + hdr.a_bss);
+ return NULL;
+ }
+
+ /* Assume _DYNAMIC is the first data item */
+ dp = (struct _dynamic *)(addr+hdr.a_text);
+
+ /* Fixup __DYNAMIC structure */
+ (long)dp->d_un.d_sdt += (long)addr;
+
+ smp = alloc_link_map(path, sodp, parent, addr, dp);
+
+ /* save segment sizes for unmap. */
+ smpp = LM_PRIVATE(smp);
+ smpp->a_text = hdr.a_text;
+ smpp->a_data = hdr.a_data;
+ smpp->a_bss = hdr.a_bss;
+ }
+
+ LM_PRIVATE(smp)->spd_refcount++;
+ if(LM_PRIVATE(smp)->spd_refcount == 1) { /* First use of object */
+ /*
+ * Recursively map all of the shared objects that this
+ * one depends upon.
+ */
+ if(map_sods(smp) == -1) { /* Failed */
+ unmap_object(smp, 0); /* Clean up */
+ return NULL;
+ }
+ }
+
+ return smp;
+}
+
+/*
+ * Map all of the shared objects that a given object depends upon. PARENT is
+ * a pointer to the link map for the shared object whose dependencies are
+ * to be mapped.
+ *
+ * Returns 0 on success. Returns -1 on failure. In that case, an error
+ * message can be retrieved by calling dlerror().
+ */
+ static int
+map_sods(parent)
+ struct so_map *parent;
+{
+ struct somap_private *parpp = LM_PRIVATE(parent);
+ struct so_list **soltail = &parpp->spd_children;
+ long next = LD_NEED(parent->som_dynamic);
+
+ while(next != 0) {
+ struct sod *sodp =
+ (struct sod *) (LM_LDBASE(parent) + next);
+ char *name =
+ (char *) (LM_LDBASE(parent) + sodp->sod_name);
+ char *path = NULL;
+ struct so_map *smp = NULL;
+
+ if(sodp->sod_library) {
+ path = rtfindlib(name, sodp->sod_major,
+ sodp->sod_minor);
+ if(path == NULL) {
+ generror ("Can't find shared library"
+ " \"lib%s.so.%d.%d\"", name,
+ sodp->sod_major, sodp->sod_minor);
+ }
+ } else {
+ if(careful && name[0] != '/') {
+ generror("Shared library path must start"
+ " with \"/\" for \"%s\"", name);
+ } else
+ path = strdup(name);
+ }
+
+ if(path != NULL)
+ smp = map_object(path, sodp, parent);
+
+ if(tracing &&
+ (smp == NULL || !(LM_PRIVATE(smp)->spd_flags & RTLD_TRACED))) {
+ if(sodp->sod_library)
+ printf("\t-l%s.%d => ", name, sodp->sod_major);
+ else
+ printf("\t%s => ", name);
+
+ if(path == NULL)
+ printf("not found\n");
+ else if(smp == NULL)
+ printf("can't load\n");
+ else {
+ printf("%s (%p)\n", path, smp->som_addr);
+ LM_PRIVATE(smp)->spd_flags |= RTLD_TRACED;
+ }
+ }
+
+ if(path != NULL)
+ free(path);
+
+ if(smp != NULL) {
+ struct so_list *solp = (struct so_list *)
+ xmalloc(sizeof(struct so_list));
+ solp->sol_map = smp;
+ solp->sol_next = NULL;
+ *soltail = solp;
+ soltail = &solp->sol_next;
+ } else if(!tracing)
+ break;
+
+ next = sodp->sod_next;
+ }
+
+ if(next != 0) {
+ /*
+ * Oh drat, we have to clean up a mess.
+ *
+ * We failed to load a shared object that we depend upon.
+ * So now we have to unload any dependencies that we had
+ * already successfully loaded prior to the error.
+ *
+ * Cleaning up doesn't matter so much for the initial
+ * loading of the program, since any failure is going to
+ * terminate the program anyway. But it is very important
+ * to clean up properly when something is being loaded
+ * via dlopen().
+ */
+ struct so_list *solp;
+
+ while((solp = parpp->spd_children) != NULL) {
+ unmap_object(solp->sol_map, 0);
+ parpp->spd_children = solp->sol_next;
+ free(solp);
+ }
+
+ return -1;
+ }
+
+ return 0;
+}
+
+/*
+ * Relocate and initialize the tree of shared objects rooted at the given
+ * link map entry. Returns 0 on success, or -1 on failure. On failure,
+ * an error message can be retrieved via dlerror().
+ */
+ static int
+reloc_and_init(root)
+ struct so_map *root;
+{
+ struct so_map *smp;
+
+ /*
+ * Relocate all newly-loaded objects. We avoid recursion for this
+ * step by taking advantage of a few facts. This function is called
+ * only when there are in fact some newly-loaded objects to process.
+ * Furthermore, all newly-loaded objects will have their link map
+ * entries at the end of the link map list. And, the root of the
+ * tree of objects just loaded will have been the first to be loaded
+ * and therefore the first new object in the link map list. Finally,
+ * we take advantage of the fact that we can relocate the newly-loaded
+ * objects in any order.
+ *
+ * All these facts conspire to let us simply loop over the tail
+ * portion of the link map list, relocating each object so
+ * encountered.
+ */
+ for(smp = root; smp != NULL; smp = smp->som_next) {
+ if(!(LM_PRIVATE(smp)->spd_flags & RTLD_RTLD)) {
+ if(reloc_map(smp) < 0)
+ return -1;
+ }
+ }
+
+ /*
+ * Copy any relocated initialized data. Again, we can just loop
+ * over the appropriate portion of the link map list.
+ */
+ for(smp = root; smp != NULL; smp = smp->som_next) {
+ if(!(LM_PRIVATE(smp)->spd_flags & RTLD_RTLD))
+ reloc_copy(smp);
+ }
+
+ /*
+ * Call any object initialization routines.
+ *
+ * Here, the order is very important, and we cannot simply loop
+ * over the newly-loaded objects as we did before. Rather, we
+ * have to initialize the tree of new objects depth-first, and
+ * process the sibling objects at each level in reverse order
+ * relative to the dependency list.
+ *
+ * Here is the reason we initialize depth-first. If an object
+ * depends on one or more other objects, then the objects it
+ * depends on should be initialized first, before the parent
+ * object itself. For it is possible that the parent's
+ * initialization routine will need the services provided by the
+ * objects it depends on -- and those objects had better already
+ * be initialized.
+ *
+ * We initialize the objects at each level of the tree in reverse
+ * order for a similar reason. When an object is linked with
+ * several libraries, it is common for routines in the earlier
+ * libraries to call routines in the later libraries. So, again,
+ * the later libraries need to be initialized first.
+ *
+ * The upshot of these rules is that we have to use recursion to
+ * get the libraries initialized in the best order. But the
+ * recursion is never likely to be very deep.
+ */
+ init_object(root);
+
+ return 0;
+}
+
+/*
+ * Remove a reference to the shared object specified by SMP. If no
+ * references remain, unmap the object and, recursively, its descendents.
+ * This function also takes care of calling the finalization routines for
+ * objects that are removed.
+ *
+ * If KEEP is true, then the actual calls to munmap() are skipped,
+ * and the object is kept in memory. That is used only for finalization,
+ * from dlexit(), when the program is exiting. There are two reasons
+ * for it. First, the program is exiting and there is no point in
+ * spending the time to explicitly unmap its shared objects. Second,
+ * even after dlexit() has been called, there are still a couple of
+ * calls that are made to functions in libc. (This is really a bug
+ * in crt0.) So libc and the main program, at least, must remain
+ * mapped in that situation.
+ *
+ * Under no reasonable circumstances should this function fail. If
+ * anything goes wrong, we consider it an internal error, and report
+ * it with err().
+ */
+ static void
+unmap_object(smp, keep)
+ struct so_map *smp;
+ int keep;
+{
+ struct somap_private *smpp = LM_PRIVATE(smp);
+
+ smpp->spd_refcount--;
+ if(smpp->spd_refcount == 0) { /* Finished with this object */
+ struct so_list *solp;
+
+ if(smpp->spd_flags & RTLD_INIT) { /* Was initialized */
+ /*
+ * Call the object's finalization routine. For
+ * backward compatibility, we first try to call
+ * ".fini". If that does not exist, we call
+ * "__fini".
+ */
+ if(call_map(smp, ".fini") == -1)
+ call_map(smp, "__fini");
+ }
+
+ /* Recursively unreference the object's descendents */
+ while((solp = smpp->spd_children) != NULL) {
+ unmap_object(solp->sol_map, keep);
+ smpp->spd_children = solp->sol_next;
+ free(solp);
+ }
+
+ if(!keep) { /* Unmap the object from memory */
+ if(munmap(smp->som_addr,
+ smpp->a_text + smpp->a_data + smpp->a_bss) < 0)
+ err(1, "internal error 1: munmap failed");
+
+ /* Unlink and free the object's link map entry */
+ free_link_map(smp);
+ }
+ }
+}
+
+static inline int
+check_text_reloc(r, smp, addr)
+struct relocation_info *r;
+struct so_map *smp;
+caddr_t addr;
+{
+ char *sym;
+
+ if (addr >= LM_ETEXT(smp))
+ return 0;
+
+ if (RELOC_EXTERN_P(r))
+ sym = LM_STRINGS(smp) +
+ LM_SYMBOL(smp, RELOC_SYMBOL(r))->nz_strx;
+ else
+ sym = "";
+
+ if (getenv("LD_SUPPRESS_WARNINGS") == NULL &&
+ getenv("LD_WARN_NON_PURE_CODE") != NULL)
+ warnx("warning: non pure code in %s at %x (%s)",
+ smp->som_path, r->r_address, sym);
+
+ if (smp->som_write == 0 &&
+ mprotect(smp->som_addr + LM_TXTADDR(smp),
+ LD_TEXTSZ(smp->som_dynamic),
+ PROT_READ|PROT_WRITE|PROT_EXEC) == -1) {
+ generror ("mprotect failed for \"%s\" : %s",
+ smp->som_path, strerror (errno));
+ return -1;
+ }
+
+ smp->som_write = 1;
+ return 0;
+}
+
+static int
+reloc_map(smp)
+ struct so_map *smp;
+{
+ /*
+ * Caching structure for reducing the number of calls to
+ * lookup() during relocation.
+ *
+ * While relocating a given shared object, the dynamic linker
+ * maintains a caching vector that is directly indexed by
+ * the symbol number in the relocation entry. The first time
+ * a given symbol is looked up, the caching vector is
+ * filled in with a pointer to the symbol table entry, and
+ * a pointer to the so_map of the shared object in which the
+ * symbol was defined. On subsequent uses of the same symbol,
+ * that information is retrieved directly from the caching
+ * vector, without calling lookup() again.
+ *
+ * A symbol that is referenced in a relocation entry is
+ * typically referenced in many relocation entries, so this
+ * caching reduces the number of calls to lookup()
+ * dramatically. The overall improvement in the speed of
+ * dynamic linking is also dramatic -- as much as a factor
+ * of three for programs that use many shared libaries.
+ */
+ struct cacheent {
+ struct nzlist *np; /* Pointer to symbol entry */
+ struct so_map *src_map; /* Shared object that defined symbol */
+ };
+
+ struct _dynamic *dp = smp->som_dynamic;
+ struct relocation_info *r = LM_REL(smp);
+ struct relocation_info *rend = r + LD_RELSZ(dp)/sizeof(*r);
+ long symbolbase = (long)LM_SYMBOL(smp, 0);
+ char *stringbase = LM_STRINGS(smp);
+ int symsize = LD_VERSION_NZLIST_P(dp->d_version) ?
+ sizeof(struct nzlist) :
+ sizeof(struct nlist);
+ long numsyms = LD_STABSZ(dp) / symsize;
+ size_t cachebytes = numsyms * sizeof(struct cacheent);
+ struct cacheent *symcache =
+ (struct cacheent *) alloca(cachebytes);
+
+ if(symcache == NULL) {
+ generror("Cannot allocate symbol caching vector for %s",
+ smp->som_path);
+ return -1;
+ }
+ bzero(symcache, cachebytes);
+
+ if (LD_PLTSZ(dp))
+ md_fix_jmpslot(LM_PLT(smp),
+ (long)LM_PLT(smp), (long)binder_entry);
+
+ for (; r < rend; r++) {
+ char *sym;
+ caddr_t addr;
+
+ /*
+ * Objects linked with "-Bsymbolic" can end up having unused
+ * relocation entries at the end. These can be detected by
+ * the fact that they have an address of 0.
+ */
+ if(r->r_address == 0) /* Finished relocating this object */
+ break;
+
+ addr = smp->som_addr + r->r_address;
+ if (check_text_reloc(r, smp, addr) < 0)
+ return -1;
+
+ if (RELOC_EXTERN_P(r)) {
+ struct so_map *src_map = NULL;
+ struct nzlist *p, *np;
+ long relocation;
+
+ if (RELOC_LAZY_P(r))
+ continue;
+
+ p = (struct nzlist *)
+ (symbolbase + symsize * RELOC_SYMBOL(r));
+
+ if (p->nz_type == (N_SETV + N_EXT))
+ src_map = smp;
+
+ sym = stringbase + p->nz_strx;
+
+ /*
+ * Look up the symbol, checking the caching
+ * vector first.
+ */
+ np = symcache[RELOC_SYMBOL(r)].np;
+ if(np != NULL) /* Symbol already cached */
+ src_map = symcache[RELOC_SYMBOL(r)].src_map;
+ else { /* Symbol not cached yet */
+ np = lookup(sym, &src_map, 0/*XXX-jumpslots!*/);
+ /*
+ * Record the needed information about
+ * the symbol in the caching vector,
+ * so that we won't have to call
+ * lookup the next time we encounter
+ * the symbol.
+ */
+ symcache[RELOC_SYMBOL(r)].np = np;
+ symcache[RELOC_SYMBOL(r)].src_map = src_map;
+ }
+
+ if (np == NULL) {
+ generror ("Undefined symbol \"%s\" in %s:%s",
+ sym, main_progname, smp->som_path);
+ return -1;
+ }
+
+ /*
+ * Found symbol definition.
+ * If it's in a link map, adjust value
+ * according to the load address of that map.
+ * Otherwise it's a run-time allocated common
+ * whose value is already up-to-date.
+ */
+ relocation = md_get_addend(r, addr);
+ relocation += np->nz_value;
+ if (src_map)
+ relocation += (long)src_map->som_addr;
+
+ if (RELOC_PCREL_P(r))
+ relocation -= (long)smp->som_addr;
+
+ if (RELOC_COPY_P(r) && src_map) {
+ (void)enter_rts(sym,
+ (long)addr,
+ N_DATA + N_EXT,
+ src_map->som_addr + np->nz_value,
+ np->nz_size, src_map);
+ continue;
+ }
+ md_relocate(r, relocation, addr, 0);
+
+ } else {
+ md_relocate(r,
+#ifdef SUN_COMPAT
+ md_get_rt_segment_addend(r, addr)
+#else
+ md_get_addend(r, addr)
+#endif
+ + (long)smp->som_addr, addr, 0);
+ }
+
+ }
+
+ if (smp->som_write) {
+ if (mprotect(smp->som_addr + LM_TXTADDR(smp),
+ LD_TEXTSZ(smp->som_dynamic),
+ PROT_READ|PROT_EXEC) == -1) {
+ generror ("mprotect failed for \"%s\" : %s",
+ smp->som_path, strerror (errno));
+ return -1;
+ }
+ smp->som_write = 0;
+ }
+ return 0;
+}
+
+ static void
+reloc_copy(smp)
+ struct so_map *smp;
+{
+ struct rt_symbol *rtsp;
+
+ for (rtsp = rt_symbol_head; rtsp; rtsp = rtsp->rt_next)
+ if ((rtsp->rt_smp == NULL || rtsp->rt_smp == smp) &&
+ rtsp->rt_sp->nz_type == N_DATA + N_EXT) {
+ bcopy(rtsp->rt_srcaddr, (caddr_t)rtsp->rt_sp->nz_value,
+ rtsp->rt_sp->nz_size);
+ }
+}
+
+ static void
+init_object(smp)
+ struct so_map *smp;
+{
+ struct somap_private *smpp = LM_PRIVATE(smp);
+
+ if(!(smpp->spd_flags & RTLD_INIT)) { /* Not initialized yet */
+ smpp->spd_flags |= RTLD_INIT;
+
+ /* Make sure all the children are initialized */
+ if(smpp->spd_children != NULL)
+ init_sods(smpp->spd_children);
+
+ if(call_map(smp, ".init") == -1)
+ call_map(smp, "__init");
+ }
+}
+
+ static void
+init_sods(solp)
+ struct so_list *solp;
+{
+ /* Recursively initialize the rest of the list */
+ if(solp->sol_next != NULL)
+ init_sods(solp->sol_next);
+
+ /* Initialize the first element of the list */
+ init_object(solp->sol_map);
+}
+
+
+/*
+ * Call a function in a given shared object. SMP is the shared object, and
+ * SYM is the name of the function.
+ *
+ * Returns 0 on success, or -1 if the symbol was not found. Failure is not
+ * necessarily an error condition, so no error message is generated.
+ */
+ static int
+call_map(smp, sym)
+ struct so_map *smp;
+ char *sym;
+{
+ struct so_map *src_map = smp;
+ struct nzlist *np;
+
+ np = lookup(sym, &src_map, 1);
+ if (np) {
+ (*(void (*)())(src_map->som_addr + np->nz_value))();
+ return 0;
+ }
+
+ return -1;
+}
+
+/*
+ * Run-time common symbol table.
+ */
+
+#define RTC_TABSIZE 57
+static struct rt_symbol *rt_symtab[RTC_TABSIZE];
+
+/*
+ * Compute hash value for run-time symbol table
+ */
+ static inline int
+hash_string(key)
+ char *key;
+{
+ register char *cp;
+ register int k;
+
+ cp = key;
+ k = 0;
+ while (*cp)
+ k = (((k << 1) + (k >> 14)) ^ (*cp++)) & 0x3fff;
+
+ return k;
+}
+
+/*
+ * Lookup KEY in the run-time common symbol table.
+ */
+
+ static inline struct rt_symbol *
+lookup_rts(key)
+ char *key;
+{
+ register int hashval;
+ register struct rt_symbol *rtsp;
+
+ /* Determine which bucket. */
+
+ hashval = hash_string(key) % RTC_TABSIZE;
+
+ /* Search the bucket. */
+
+ for (rtsp = rt_symtab[hashval]; rtsp; rtsp = rtsp->rt_link)
+ if (strcmp(key, rtsp->rt_sp->nz_name) == 0)
+ return rtsp;
+
+ return NULL;
+}
+
+ static struct rt_symbol *
+enter_rts(name, value, type, srcaddr, size, smp)
+ char *name;
+ long value;
+ int type;
+ caddr_t srcaddr;
+ long size;
+ struct so_map *smp;
+{
+ register int hashval;
+ register struct rt_symbol *rtsp, **rpp;
+
+ /* Determine which bucket */
+ hashval = hash_string(name) % RTC_TABSIZE;
+
+ /* Find end of bucket */
+ for (rpp = &rt_symtab[hashval]; *rpp; rpp = &(*rpp)->rt_link)
+ continue;
+
+ /* Allocate new common symbol */
+ rtsp = (struct rt_symbol *)malloc(sizeof(struct rt_symbol));
+ rtsp->rt_sp = (struct nzlist *)malloc(sizeof(struct nzlist));
+ rtsp->rt_sp->nz_name = strdup(name);
+ rtsp->rt_sp->nz_value = value;
+ rtsp->rt_sp->nz_type = type;
+ rtsp->rt_sp->nz_size = size;
+ rtsp->rt_srcaddr = srcaddr;
+ rtsp->rt_smp = smp;
+ rtsp->rt_link = NULL;
+
+ /* Link onto linear list as well */
+ rtsp->rt_next = rt_symbol_head;
+ rt_symbol_head = rtsp;
+
+ *rpp = rtsp;
+
+ return rtsp;
+}
+
+
+/*
+ * Lookup NAME in the link maps. The link map producing a definition
+ * is returned in SRC_MAP. If SRC_MAP is not NULL on entry the search is
+ * confined to that map. If STRONG is set, the symbol returned must
+ * have a proper type (used by binder()).
+ */
+ static struct nzlist *
+lookup(name, src_map, strong)
+ char *name;
+ struct so_map **src_map; /* IN/OUT */
+ int strong;
+{
+ long common_size = 0;
+ struct so_map *smp;
+ struct rt_symbol *rtsp;
+
+ if ((rtsp = lookup_rts(name)) != NULL)
+ return rtsp->rt_sp;
+
+ /*
+ * Search all maps for a definition of NAME
+ */
+ for (smp = link_map_head; smp; smp = smp->som_next) {
+ int buckets;
+ long hashval;
+ struct rrs_hash *hp;
+ char *cp;
+ struct nzlist *np;
+
+ /* Some local caching */
+ long symbolbase;
+ struct rrs_hash *hashbase;
+ char *stringbase;
+ int symsize;
+
+ if (*src_map && smp != *src_map)
+ continue;
+
+ if ((buckets = LD_BUCKETS(smp->som_dynamic)) == 0)
+ continue;
+
+ if (LM_PRIVATE(smp)->spd_flags & RTLD_RTLD)
+ continue;
+
+restart:
+ /*
+ * Compute bucket in which the symbol might be found.
+ */
+ for (hashval = 0, cp = name; *cp; cp++)
+ hashval = (hashval << 1) + *cp;
+
+ hashval = (hashval & 0x7fffffff) % buckets;
+
+ hashbase = LM_HASH(smp);
+ hp = hashbase + hashval;
+ if (hp->rh_symbolnum == -1)
+ /* Nothing in this bucket */
+ continue;
+
+ symbolbase = (long)LM_SYMBOL(smp, 0);
+ stringbase = LM_STRINGS(smp);
+ symsize = LD_VERSION_NZLIST_P(smp->som_dynamic->d_version)?
+ sizeof(struct nzlist) :
+ sizeof(struct nlist);
+ while (hp) {
+ np = (struct nzlist *)
+ (symbolbase + hp->rh_symbolnum * symsize);
+ cp = stringbase + np->nz_strx;
+ if (strcmp(cp, name) == 0)
+ break;
+ if (hp->rh_next == 0)
+ hp = NULL;
+ else
+ hp = hashbase + hp->rh_next;
+ }
+ if (hp == NULL)
+ /* Nothing in this bucket */
+ continue;
+
+ /*
+ * We have a symbol with the name we're looking for.
+ */
+ if (np->nz_type == N_INDR+N_EXT) {
+ /*
+ * Next symbol gives the aliased name. Restart
+ * search with new name and confine to this map.
+ */
+ name = stringbase + (++np)->nz_strx;
+ *src_map = smp;
+ goto restart;
+ }
+
+ if (np->nz_value == 0)
+ /* It's not a definition */
+ continue;
+
+ if (np->nz_type == N_UNDF+N_EXT && np->nz_value != 0) {
+ if (np->nz_other == AUX_FUNC) {
+ /* It's a weak function definition */
+ if (strong)
+ continue;
+ } else {
+ /* It's a common, note value and continue search */
+ if (common_size < np->nz_value)
+ common_size = np->nz_value;
+ continue;
+ }
+ }
+
+ *src_map = smp;
+ return np;
+ }
+
+ if (common_size == 0)
+ /* Not found */
+ return NULL;
+
+ /*
+ * It's a common, enter into run-time common symbol table.
+ */
+ rtsp = enter_rts(name, (long)calloc(1, common_size),
+ N_UNDF + N_EXT, 0, common_size, NULL);
+
+#if DEBUG
+ xprintf("Allocating common: %s size %d at %#x\n", name, common_size,
+ rtsp->rt_sp->nz_value);
+#endif
+
+ return rtsp->rt_sp;
+}
+
+/*
+ * This routine is called from the jumptable to resolve
+ * procedure calls to shared objects.
+ */
+ long
+binder(jsp)
+ jmpslot_t *jsp;
+{
+ struct so_map *smp, *src_map = NULL;
+ long addr;
+ char *sym;
+ struct nzlist *np;
+ int index;
+
+ /*
+ * Find the PLT map that contains JSP.
+ */
+ for (smp = link_map_head; smp; smp = smp->som_next) {
+ if (LM_PLT(smp) < jsp &&
+ jsp < LM_PLT(smp) + LD_PLTSZ(smp->som_dynamic)/sizeof(*jsp))
+ break;
+ }
+
+ if (smp == NULL)
+ errx(1, "Call to binder from unknown location: %#x\n", jsp);
+
+ index = jsp->reloc_index & JMPSLOT_RELOC_MASK;
+
+ /* Get the local symbol this jmpslot refers to */
+ sym = LM_STRINGS(smp) +
+ LM_SYMBOL(smp,RELOC_SYMBOL(&LM_REL(smp)[index]))->nz_strx;
+
+ np = lookup(sym, &src_map, 1);
+ if (np == NULL)
+ errx(1, "Undefined symbol \"%s\" called from %s:%s at %#x",
+ sym, main_progname, smp->som_path, jsp);
+
+ /* Fixup jmpslot so future calls transfer directly to target */
+ addr = np->nz_value;
+ if (src_map)
+ addr += (long)src_map->som_addr;
+
+ md_fix_jmpslot(jsp, (long)jsp, addr);
+
+#if DEBUG
+ xprintf(" BINDER: %s located at = %#x in %s\n", sym, addr,
+ src_map->som_path);
+#endif
+ return addr;
+}
+
+static struct hints_header *hheader; /* NULL means not mapped */
+static struct hints_bucket *hbuckets;
+static char *hstrtab;
+
+/*
+ * Map the hints file into memory, if it is not already mapped. Returns
+ * 0 on success, or -1 on failure.
+ */
+ static int
+maphints __P((void))
+{
+ static int hints_bad; /* TRUE if hints are unusable */
+ int hfd;
+ struct hints_header hdr;
+ caddr_t addr;
+
+ if (hheader != NULL) /* Already mapped */
+ return 0;
+
+ if (hints_bad) /* Known to be corrupt or unavailable */
+ return -1;
+
+ if ((hfd = open(_PATH_LD_HINTS, O_RDONLY, 0)) == -1) {
+ hints_bad = 1;
+ return -1;
+ }
+
+ /* Read the header and check it */
+
+ if (read(hfd, &hdr, sizeof hdr) != sizeof hdr ||
+ HH_BADMAG(hdr) ||
+ hdr.hh_version != LD_HINTS_VERSION_1) {
+ close(hfd);
+ hints_bad = 1;
+ return -1;
+ }
+
+ /* Map the hints into memory */
+
+ addr = mmap(0, hdr.hh_ehints, PROT_READ, MAP_SHARED, hfd, 0);
+ if (addr == (caddr_t)-1) {
+ close(hfd);
+ hints_bad = 1;
+ return -1;
+ }
+
+ close(hfd);
+
+ hheader = (struct hints_header *)addr;
+ hbuckets = (struct hints_bucket *)(addr + hheader->hh_hashtab);
+ hstrtab = (char *)(addr + hheader->hh_strtab);
+
+ return 0;
+}
+
+/*
+ * Unmap the hints file, if it is currently mapped.
+ */
+ static void
+unmaphints()
+{
+ if (hheader != NULL) {
+ munmap((caddr_t)hheader, hheader->hh_ehints);
+ hheader = NULL;
+ }
+}
+
+ int
+hinthash(cp, vmajor)
+ char *cp;
+ int vmajor;
+{
+ int k = 0;
+
+ while (*cp)
+ k = (((k << 1) + (k >> 14)) ^ (*cp++)) & 0x3fff;
+
+ k = (((k << 1) + (k >> 14)) ^ (vmajor*257)) & 0x3fff;
+
+ return k;
+}
+
+#undef major
+#undef minor
+
+/*
+ * Search for a library in the hints generated by ldconfig. On success,
+ * returns the full pathname of the matching library. This string is
+ * always dynamically allocated on the heap.
+ *
+ * Returns the minor number of the matching library via the pointer
+ * argument MINORP.
+ *
+ * Returns NULL if the library cannot be found.
+ */
+ static char *
+findhint(name, major, minorp)
+ char *name;
+ int major;
+ int *minorp;
+{
+ struct hints_bucket *bp =
+ hbuckets + (hinthash(name, major) % hheader->hh_nbucket);
+
+ while (1) {
+ /* Sanity check */
+ if (bp->hi_namex >= hheader->hh_strtab_sz) {
+ warnx("Bad name index: %#x\n", bp->hi_namex);
+ break;
+ }
+ if (bp->hi_pathx >= hheader->hh_strtab_sz) {
+ warnx("Bad path index: %#x\n", bp->hi_pathx);
+ break;
+ }
+
+ /*
+ * We accept the current hints entry if its name matches
+ * and its major number matches. We don't have to search
+ * for the best minor number, because that was already
+ * done by "ldconfig" when it built the hints file.
+ */
+ if (strcmp(name, hstrtab + bp->hi_namex) == 0 &&
+ bp->hi_major == major) {
+ *minorp = bp->hi_ndewey >= 2 ? bp->hi_minor : -1;
+ return strdup(hstrtab + bp->hi_pathx);
+ }
+
+ if (bp->hi_next == -1)
+ break;
+
+ /* Move on to next in bucket */
+ bp = &hbuckets[bp->hi_next];
+ }
+
+ /* No hints available for name */
+ return NULL;
+}
+
+/*
+ * Search for the given shared library. On success, returns a string
+ * containing the full pathname for the library. This string is always
+ * dynamically allocated on the heap.
+ *
+ * Returns NULL if the library cannot be found.
+ */
+ static char *
+rtfindlib(name, major, minor)
+ char *name;
+ int major, minor;
+{
+ char *ld_path = ld_library_path;
+ char *path = NULL;
+ int realminor = -1;
+
+ if (ld_path != NULL) { /* First, search the directories in ld_path */
+ /*
+ * There is no point in trying to use the hints file for this.
+ */
+ char *dir;
+
+ while (path == NULL && (dir = strsep(&ld_path, ":")) != NULL) {
+ path = search_lib_dir(dir, name, &major, &realminor, 0);
+ if (ld_path)
+ *(ld_path-1) = ':';
+ }
+ }
+
+ if (path == NULL && maphints() == 0) /* Search the hints file */
+ path = findhint(name, major, &realminor);
+
+ if (path == NULL) /* Search the standard directories */
+ path = findshlib(name, &major, &realminor, 0);
+
+ if (path != NULL &&
+ realminor < minor &&
+ getenv("LD_SUPPRESS_WARNINGS") == NULL) {
+ warnx("warning: %s: minor version %d"
+ " older than expected %d, using it anyway",
+ path, realminor, minor);
+ }
+
+ return path;
+}
+
+/*
+ * Buffer for error messages and a pointer that is set to point to the buffer
+ * when a error occurs. It acts as a last error flag, being set to NULL
+ * after an error is returned.
+ */
+#define DLERROR_BUF_SIZE 512
+static char dlerror_buf [DLERROR_BUF_SIZE];
+static char *dlerror_msg = NULL;
+
+
+ static void *
+__dlopen(path, mode)
+ char *path;
+ int mode;
+{
+ struct so_map *old_tail = link_map_tail;
+ struct so_map *smp;
+
+ anon_open();
+
+ /* Map the object, and the objects on which it depends */
+ smp = map_object(path, (struct sod *) NULL, (struct so_map *) NULL);
+ if(smp == NULL) /* Failed */
+ return NULL;
+ LM_PRIVATE(smp)->spd_flags |= RTLD_DL;
+
+ /* Relocate and initialize all newly-mapped objects */
+ if(link_map_tail != old_tail) { /* We have mapped some new objects */
+ if(reloc_and_init(smp) == -1) /* Failed */
+ return NULL;
+ }
+
+ unmaphints();
+ anon_close();
+
+ return smp;
+}
+
+ static int
+__dlclose(fd)
+ void *fd;
+{
+ struct so_map *smp = (struct so_map *)fd;
+ struct so_map *scanp;
+
+#ifdef DEBUG
+ xprintf("dlclose(%s): refcount = %d\n", smp->som_path,
+ LM_PRIVATE(smp)->spd_refcount);
+#endif
+ /* Check the argument for validity */
+ for(scanp = link_map_head; scanp != NULL; scanp = scanp->som_next)
+ if(scanp == smp) /* We found the map in the list */
+ break;
+ if(scanp == NULL || !(LM_PRIVATE(smp)->spd_flags & RTLD_DL)) {
+ generror("Invalid argument to dlclose");
+ return -1;
+ }
+
+ unmap_object(smp, 0);
+
+ return 0;
+}
+
+ static void *
+__dlsym(fd, sym)
+ void *fd;
+ char *sym;
+{
+ struct so_map *src_map = (struct so_map *)fd;
+ struct nzlist *np;
+ long addr;
+
+ np = lookup(sym, &src_map, 1);
+ if (np == NULL) {
+ generror ("Symbol \"%s\" not found", sym);
+ return NULL;
+ }
+
+ addr = np->nz_value;
+ if (src_map)
+ addr += (long)src_map->som_addr;
+
+ return (void *)addr;
+}
+
+ static char *
+__dlerror __P((void))
+{
+ char *err;
+
+ err = dlerror_msg;
+ dlerror_msg = NULL; /* Next call will return NULL */
+
+ return err;
+}
+
+ static void
+__dlexit __P((void))
+{
+#ifdef DEBUG
+xprintf("__dlexit called\n");
+#endif
+
+ unmap_object(link_map_head, 1);
+}
+
+/*
+ * Generate an error message that can be later be retrieved via dlerror.
+ */
+static void
+#if __STDC__
+generror(char *fmt, ...)
+#else
+generror(fmt, va_alist)
+char *fmt;
+#endif
+{
+ va_list ap;
+#if __STDC__
+ va_start(ap, fmt);
+#else
+ va_start(ap);
+#endif
+ vsnprintf (dlerror_buf, DLERROR_BUF_SIZE, fmt, ap);
+ dlerror_msg = dlerror_buf;
+
+ va_end(ap);
+}
+
+void
+#if __STDC__
+xprintf(char *fmt, ...)
+#else
+xprintf(fmt, va_alist)
+char *fmt;
+#endif
+{
+ char buf[256];
+ va_list ap;
+#if __STDC__
+ va_start(ap, fmt);
+#else
+ va_start(ap);
+#endif
+
+ vsprintf(buf, fmt, ap);
+ (void)write(1, buf, strlen(buf));
+ va_end(ap);
+}
diff --git a/gnu/usr.bin/ld/rtld/sbrk.c b/gnu/usr.bin/ld/rtld/sbrk.c
new file mode 100644
index 0000000..2d2c610
--- /dev/null
+++ b/gnu/usr.bin/ld/rtld/sbrk.c
@@ -0,0 +1,101 @@
+/*
+ * 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 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$
+ */
+
+#include <machine/vmparam.h>
+#include <sys/param.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/file.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <sys/mman.h>
+#ifndef BSD
+#define MAP_COPY MAP_PRIVATE
+#define MAP_FILE 0
+#define MAP_ANON 0
+#endif
+#include <fcntl.h>
+#include <a.out.h>
+#include <stab.h>
+#include <string.h>
+#if __STDC__
+#include <stdarg.h>
+#else
+#include <varargs.h>
+#endif
+
+#include "ld.h"
+
+#ifndef BSD /* Need do better than this */
+#define NEED_DEV_ZERO 1
+#endif
+
+caddr_t
+sbrk(incr)
+int incr;
+{
+ int fd = -1;
+ caddr_t curbrk;
+
+ /* Round-up increment to page size */
+ incr = ((incr + PAGSIZ - 1) & ~(PAGSIZ - 1));
+
+#if DEBUG
+xprintf("sbrk: incr = %#x\n", incr);
+#endif
+
+#ifdef NEED_DEV_ZERO
+ fd = open("/dev/zero", O_RDWR, 0);
+ if (fd == -1)
+ perror("/dev/zero");
+#endif
+
+ if ((curbrk = mmap(0, incr,
+ PROT_READ|PROT_WRITE,
+ MAP_ANON|MAP_COPY, fd, 0)) == (caddr_t)-1) {
+ xprintf("Cannot map anonymous memory");
+ _exit(1);
+ }
+
+#ifdef DEBUG
+xprintf("sbrk: curbrk = %#x\n", curbrk);
+#endif
+
+#ifdef NEED_DEV_ZERO
+ close(fd);
+#endif
+
+ return(curbrk);
+}
+
diff --git a/gnu/usr.bin/ld/shlib.c b/gnu/usr.bin/ld/shlib.c
new file mode 100644
index 0000000..04af10a
--- /dev/null
+++ b/gnu/usr.bin/ld/shlib.c
@@ -0,0 +1,314 @@
+/*
+ * 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: shlib.c,v 1.13 1995/03/19 21:20:09 nate Exp $
+ */
+
+#include <sys/param.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/file.h>
+#include <sys/time.h>
+#include <err.h>
+#include <fcntl.h>
+#include <string.h>
+#include <ctype.h>
+#include <dirent.h>
+#include <a.out.h>
+
+#include "ld.h"
+
+#ifdef SUNOS4
+char *strsep();
+#endif
+
+/*
+ * Standard directories to search for files specified by -l.
+ */
+#ifndef STANDARD_SEARCH_DIRS
+#define STANDARD_SEARCH_DIRS "/usr/lib"
+#endif
+
+/*
+ * Actual vector of library search directories,
+ * including `-L'ed and LD_LIBARAY_PATH spec'd ones.
+ */
+char **search_dirs;
+int n_search_dirs;
+
+char *standard_search_dirs[] = {
+ STANDARD_SEARCH_DIRS
+};
+
+
+void
+add_search_dir(name)
+ char *name;
+{
+ n_search_dirs++;
+ search_dirs = (char **)
+ xrealloc(search_dirs, n_search_dirs * sizeof(char *));
+ search_dirs[n_search_dirs - 1] = strdup(name);
+}
+
+void
+add_search_path(path)
+char *path;
+{
+ register char *cp;
+
+ if (path == NULL)
+ return;
+
+ /* Add search directories from `paths' */
+ while ((cp = strsep(&path, ":")) != NULL) {
+ add_search_dir(cp);
+ if (path)
+ *(path-1) = ':';
+ }
+}
+
+void
+std_search_path()
+{
+ int i, n;
+
+ /* Append standard search directories */
+ n = sizeof standard_search_dirs / sizeof standard_search_dirs[0];
+ for (i = 0; i < n; i++)
+ add_search_dir(standard_search_dirs[i]);
+}
+
+/*
+ * Return true if CP points to a valid dewey number.
+ * Decode and leave the result in the array DEWEY.
+ * Return the number of decoded entries in DEWEY.
+ */
+
+int
+getdewey(dewey, cp)
+int dewey[];
+char *cp;
+{
+ int i, n;
+
+ for (n = 0, i = 0; i < MAXDEWEY; i++) {
+ if (*cp == '\0')
+ break;
+
+ if (*cp == '.') cp++;
+ if (!isdigit(*cp))
+ return 0;
+
+ dewey[n++] = strtol(cp, &cp, 10);
+ }
+
+ return n;
+}
+
+/*
+ * Compare two dewey arrays.
+ * Return -1 if `d1' represents a smaller value than `d2'.
+ * Return 1 if `d1' represents a greater value than `d2'.
+ * Return 0 if equal.
+ */
+int
+cmpndewey(d1, n1, d2, n2)
+int d1[], d2[];
+int n1, n2;
+{
+ register int i;
+
+ for (i = 0; i < n1 && i < n2; i++) {
+ if (d1[i] < d2[i])
+ return -1;
+ if (d1[i] > d2[i])
+ return 1;
+ }
+
+ if (n1 == n2)
+ return 0;
+
+ if (i == n1)
+ return -1;
+
+ if (i == n2)
+ return 1;
+
+ errx(1, "cmpndewey: cant happen");
+ return 0;
+}
+
+/*
+ * Search directories for a shared library matching the given
+ * major and minor version numbers. See search_lib_dir() below for
+ * the detailed matching rules.
+ *
+ * As soon as a directory with an acceptable match is found, the search
+ * terminates. Subsequent directories are not searched for a better
+ * match. This is in conformance with the SunOS searching rules. Also,
+ * it avoids a lot of directory searches that are virtually guaranteed to
+ * be fruitless.
+ *
+ * The return value is a full pathname to the matching library. The
+ * string is dynamically allocated. If no matching library is found, the
+ * function returns NULL.
+ */
+
+char *
+findshlib(name, majorp, minorp, do_dot_a)
+char *name;
+int *majorp, *minorp;
+int do_dot_a;
+{
+ int i;
+
+ for (i = 0; i < n_search_dirs; i++) {
+ char *path;
+
+ path = search_lib_dir(search_dirs[i], name, majorp, minorp,
+ do_dot_a);
+ if(path != NULL)
+ return path;
+ }
+
+ return NULL;
+}
+
+/*
+ * Search a given directory for a library (preferably shared) satisfying
+ * the given criteria.
+ *
+ * The matching rules are as follows:
+ *
+ * if(*majorp == -1)
+ * find the library with the highest major version;
+ * else
+ * insist on a major version identical to *majorp;
+ *
+ * Always find the library with the highest minor version;
+ * if(*minorp != -1)
+ * insist on a minor version >= *minorp;
+ *
+ * It is invalid to specify a specific minor number while wildcarding
+ * the major number.
+ *
+ * The actual major and minor numbers found are returned via the pointer
+ * arguments.
+ *
+ * A suitable shared library is always preferred over a static (.a) library.
+ * If do_dot_a is false, then a static library will not be accepted in
+ * any case.
+ *
+ * The return value is a full pathname to the matching library. The
+ * string is dynamically allocated. If no matching library is found, the
+ * function returns NULL.
+ */
+
+char *
+search_lib_dir(dir, name, majorp, minorp, do_dot_a)
+ char *dir;
+ char *name;
+ int *majorp;
+ int *minorp;
+ int do_dot_a;
+{
+ int namelen;
+ DIR *dd;
+ struct dirent *dp;
+ int best_dewey[MAXDEWEY];
+ int best_ndewey;
+ char dot_a_name[MAXNAMLEN+1];
+ char dot_so_name[MAXNAMLEN+1];
+
+ if((dd = opendir(dir)) == NULL)
+ return NULL;
+
+ namelen = strlen(name);
+ best_ndewey = 0;
+ dot_a_name[0] = '\0';
+ dot_so_name[0] = '\0';
+
+ while((dp = readdir(dd)) != NULL) {
+ char *extension;
+
+ if(strlen(dp->d_name) < 3 + namelen + 2 || /* lib+xxx+.a */
+ strncmp(dp->d_name, "lib", 3) != 0 ||
+ strncmp(dp->d_name + 3, name, namelen) != 0 ||
+ dp->d_name[3+namelen] != '.')
+ continue;
+
+ extension = dp->d_name + 3 + namelen + 1; /* a or so.* */
+
+ if(strncmp(extension, "so.", 3) == 0) {
+ int cur_dewey[MAXDEWEY];
+ int cur_ndewey;
+
+ cur_ndewey = getdewey(cur_dewey, extension+3);
+ if(cur_ndewey == 0) /* No version number */
+ continue;
+
+ if(*majorp != -1) { /* Need exact match on major */
+ if(cur_dewey[0] != *majorp)
+ continue;
+ if(*minorp != -1) { /* Need minor >= minimum */
+ if(cur_ndewey < 2 ||
+ cur_dewey[1] < *minorp)
+ continue;
+ }
+ }
+
+ if(cmpndewey(cur_dewey, cur_ndewey, best_dewey,
+ best_ndewey) <= 0) /* No better than prior match */
+ continue;
+
+ /* We found a better match */
+ strcpy(dot_so_name, dp->d_name);
+ bcopy(cur_dewey, best_dewey,
+ cur_ndewey * sizeof best_dewey[0]);
+ best_ndewey = cur_ndewey;
+ } else if(do_dot_a && strcmp(extension, "a") == 0)
+ strcpy(dot_a_name, dp->d_name);
+ }
+ closedir(dd);
+
+ if(dot_so_name[0] != '\0') {
+ *majorp = best_dewey[0];
+ if(best_ndewey >= 2)
+ *minorp = best_dewey[1];
+ return concat(dir, "/", dot_so_name);
+ }
+
+ if(dot_a_name[0] != '\0')
+ return concat(dir, "/", dot_a_name);
+
+ return NULL;
+}
diff --git a/gnu/usr.bin/ld/sparc/md-static-funcs.c b/gnu/usr.bin/ld/sparc/md-static-funcs.c
new file mode 100644
index 0000000..2672cb5
--- /dev/null
+++ b/gnu/usr.bin/ld/sparc/md-static-funcs.c
@@ -0,0 +1,37 @@
+
+/*
+ * $Id: md-static-funcs.c,v 1.2 1993/12/08 10:28:56 pk Exp $
+ *
+ * Simple SPARC relocations for the benefit of self-relocation of ld.so
+ * avoiding the use of global variables (ie. reloc_bitshift[] et. al.).
+ * Only types supported are RELOC_32 and RELOC_RELATIVE.
+ *
+ * This *must* be a static function, so it is not called through a jmpslot.
+ */
+static void
+md_relocate_simple(r, relocation, addr)
+struct relocation_info *r;
+long relocation;
+char *addr;
+{
+ register unsigned long mask;
+ register unsigned long shift;
+
+ switch (r->r_type) {
+ case RELOC_32:
+ mask = 0xffffffff;
+ shift = 0;
+ break;
+ case RELOC_RELATIVE:
+ mask = 0x003fffff;
+ shift = 10;
+ break;
+ }
+ relocation += (*(long *)addr & mask) << shift;
+ relocation >>= shift;
+ relocation &= mask;
+
+ *(long *) (addr) &= ~mask;
+ *(long *) (addr) |= relocation;
+}
+
diff --git a/gnu/usr.bin/ld/sparc/md.c b/gnu/usr.bin/ld/sparc/md.c
new file mode 100644
index 0000000..508d37d
--- /dev/null
+++ b/gnu/usr.bin/ld/sparc/md.c
@@ -0,0 +1,351 @@
+/*
+ * 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: md.c,v 1.7 1994/02/13 20:43:03 jkh Exp $
+ */
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <a.out.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <err.h>
+#include <fcntl.h>
+#include <stab.h>
+#include <string.h>
+
+#include "ld.h"
+
+/*
+ * Relocation masks and sizes for the Sparc architecture.
+ *
+ * Note that these are very dependent on the order of the enums in
+ * enum reloc_type (in a.out.h); if they change the following must be
+ * changed.
+ * Also, note that RELOC_RELATIVE is handled as if it were a RELOC_HI22.
+ * This should work provided that relocations values have zeroes in their
+ * least significant 10 bits. As RELOC_RELATIVE is used only to relocate
+ * with load address values - which are page aligned - this condition is
+ * fulfilled as long as the system's page size is > 1024 (and a power of 2).
+ */
+static int reloc_target_rightshift[] = {
+ 0, 0, 0, /* RELOC_8, _16, _32 */
+ 0, 0, 0, 2, 2, /* DISP8, DISP16, DISP32, WDISP30, WDISP22 */
+ 10, 0, /* HI22, _22 */
+ 0, 0, /* RELOC_13, _LO10 */
+ 0, 0, /* _SFA_BASE, _SFA_OFF13 */
+ 0, 0, 10, /* _BASE10, _BASE13, _BASE22 */
+ 0, 10, /* _PC10, _PC22 */
+ 2, 0, /* _JMP_TBL, _SEGOFF16 */
+ 0, 0, 0 /* _GLOB_DAT, JMP_SLOT, _RELATIVE */
+};
+static int reloc_target_size[] = {
+ 0, 1, 2, /* RELOC_8, _16, _32 */
+ 0, 1, 2, 2, 2, /* DISP8, DISP16, DISP32, WDISP30, WDISP22 */
+ 2, 2, /* HI22, _22 */
+ 2, 2, /* RELOC_13, _LO10 */
+ 2, 2, /* _SFA_BASE, _SFA_OFF13 */
+ 2, 2, 2, /* _BASE10, _BASE13, _BASE22 */
+ 2, 2, /* _PC10, _PC22 */
+ 2, 0, /* _JMP_TBL, _SEGOFF16 */
+ 2, 0, 2 /* _GLOB_DAT, JMP_SLOT, _RELATIVE */
+};
+static int reloc_target_bitsize[] = {
+ 8, 16, 32, /* RELOC_8, _16, _32 */
+ 8, 16, 32, 30, 22, /* DISP8, DISP16, DISP32, WDISP30, WDISP22 */
+ 22, 22, /* HI22, _22 */
+ 13, 10, /* RELOC_13, _LO10 */
+ 32, 32, /* _SFA_BASE, _SFA_OFF13 */
+ 10, 13, 22, /* _BASE10, _BASE13, _BASE22 */
+ 10, 22, /* _PC10, _PC22 */
+ 30, 0, /* _JMP_TBL, _SEGOFF16 */
+ 32, 0, 22 /* _GLOB_DAT, JMP_SLOT, _RELATIVE */
+};
+
+
+/*
+ * Get relocation addend corresponding to relocation record RP
+ * ADDR unused by SPARC impl.
+ */
+long
+md_get_addend(r, addr)
+struct relocation_info *r;
+unsigned char *addr;
+{
+ return r->r_addend;
+}
+
+void
+md_relocate(r, relocation, addr, relocatable_output)
+struct relocation_info *r;
+long relocation;
+unsigned char *addr;
+int relocatable_output;
+{
+ register unsigned long mask;
+
+#ifndef RTLD
+ if (relocatable_output) {
+ /*
+ * Non-PC relative relocations which are absolute or
+ * which have become non-external now have fixed
+ * relocations. Set the ADD_EXTRA of this relocation
+ * to be the relocation we have now determined.
+ */
+ if (!RELOC_PCREL_P(r)) {
+ if ((int) r->r_type <= RELOC_32
+ || RELOC_EXTERN_P(r) == 0)
+ RELOC_ADD_EXTRA(r) = relocation;
+ } else if (RELOC_EXTERN_P(r))
+ /*
+ * External PC-relative relocations continue
+ * to move around; update their relocations
+ * by the amount they have moved so far.
+ */
+ RELOC_ADD_EXTRA(r) -= pc_relocation;
+ return;
+ }
+#endif
+
+ relocation >>= RELOC_VALUE_RIGHTSHIFT(r);
+
+ /* Unshifted mask for relocation */
+ mask = 1 << RELOC_TARGET_BITSIZE(r) - 1;
+ mask |= mask - 1;
+ relocation &= mask;
+
+ /* Shift everything up to where it's going to be used */
+ relocation <<= RELOC_TARGET_BITPOS(r);
+ mask <<= RELOC_TARGET_BITPOS(r);
+
+ switch (RELOC_TARGET_SIZE(r)) {
+ case 0:
+ if (RELOC_MEMORY_ADD_P(r))
+ relocation += (mask & *(u_char *) (addr));
+ *(u_char *) (addr) &= ~mask;
+ *(u_char *) (addr) |= relocation;
+ break;
+
+ case 1:
+ if (RELOC_MEMORY_ADD_P(r))
+ relocation += (mask & *(u_short *) (addr));
+ *(u_short *) (addr) &= ~mask;
+ *(u_short *) (addr) |= relocation;
+ break;
+
+ case 2:
+ if (RELOC_MEMORY_ADD_P(r))
+ relocation += (mask & *(u_long *) (addr));
+ *(u_long *) (addr) &= ~mask;
+ *(u_long *) (addr) |= relocation;
+ break;
+ default:
+ errx(1, "Unimplemented relocation field length: %d",
+ RELOC_TARGET_SIZE(r));
+ }
+}
+
+#ifndef RTLD
+/*
+ * Machine dependent part of claim_rrs_reloc().
+ * On the Sparc the relocation offsets are stored in the r_addend member.
+ */
+int
+md_make_reloc(rp, r, type)
+struct relocation_info *rp, *r;
+int type;
+{
+ r->r_type = rp->r_type;
+ r->r_addend = rp->r_addend;
+
+#if 1
+ /*
+ * This wouldn't be strictly necessary - we could record the
+ * relocation value "in situ" in stead of in the r_addend field -
+ * but we are being Sun compatible here. Besides, Sun's ld.so
+ * has a bug that prevents it from handling this alternate method.
+ *
+ * IT WOULD BE REALLY NICE TO HAVE CONSISTENCY THROUGHOUT THE ENTIRE
+ * RELOCATION PROCESS, ie. using `r_addend' for storing all partially
+ * completed relocations, in stead of mixing them in both relocation
+ * records and in the segment data.
+ */
+ if (RELOC_PCREL_P(rp))
+ r->r_addend -= pc_relocation;
+#endif
+
+ return 1;
+}
+#endif
+
+/*
+ * Set up a transfer from jmpslot at OFFSET (relative to the PLT table)
+ * to the binder slot (which is at offset 0 of the PLT).
+ */
+void
+md_make_jmpslot(sp, offset, index)
+jmpslot_t *sp;
+long offset;
+long index;
+{
+ u_long fudge = (u_long) -(sizeof(sp->opcode1) + offset);
+ sp->opcode1 = SAVE;
+ /* The following is a RELOC_WDISP30 relocation */
+ sp->opcode2 = CALL | ((fudge >> 2) & 0x3fffffff);
+ sp->reloc_index = NOP | index;
+}
+
+/*
+ * Set up a "direct" transfer (ie. not through the run-time binder) from
+ * jmpslot at OFFSET to ADDR. Used by `ld' when the SYMBOLIC flag is on,
+ * and by `ld.so' after resolving the symbol.
+ * On the i386, we use the JMP instruction which is PC relative, so no
+ * further RRS relocations will be necessary for such a jmpslot.
+ *
+ * OFFSET unused on Sparc.
+ */
+void
+md_fix_jmpslot(sp, offset, addr)
+jmpslot_t *sp;
+long offset;
+u_long addr;
+{
+ /*
+ * Here comes a RELOC_{LO10,HI22} relocation pair
+ * The resulting code is:
+ * sethi %hi(addr), %g1
+ * jmp %g1+%lo(addr)
+ * nop ! delay slot
+ */
+ sp->opcode1 = SETHI | ((addr >> 10) & 0x003fffff);
+ sp->opcode2 = JMP | (addr & 0x000003ff);
+ sp->reloc_index = NOP;
+}
+
+/*
+ * Update the relocation record for a jmpslot.
+ */
+void
+md_make_jmpreloc(rp, r, type)
+struct relocation_info *rp, *r;
+int type;
+{
+ if (type & RELTYPE_RELATIVE)
+ r->r_type = RELOC_RELATIVE;
+ else
+ r->r_type = RELOC_JMP_SLOT;
+
+ r->r_addend = rp->r_addend;
+}
+
+/*
+ * Set relocation type for a GOT RRS relocation.
+ */
+void
+md_make_gotreloc(rp, r, type)
+struct relocation_info *rp, *r;
+int type;
+{
+ /*
+ * GOT value resolved (symbolic or entry point): R_32
+ * GOT not resolved: GLOB_DAT
+ *
+ * NOTE: I don't think it makes a difference.
+ */
+ if (type & RELTYPE_RELATIVE)
+ r->r_type = RELOC_32;
+ else
+ r->r_type = RELOC_GLOB_DAT;
+
+ r->r_addend = 0;
+}
+
+/*
+ * Set relocation type for a RRS copy operation.
+ */
+void
+md_make_cpyreloc(rp, r)
+struct relocation_info *rp, *r;
+{
+ r->r_type = RELOC_COPY_DAT;
+ r->r_addend = 0;
+}
+
+void
+md_set_breakpoint(where, savep)
+long where;
+long *savep;
+{
+ *savep = *(long *)where;
+ *(long *)where = TRAP;
+}
+
+#ifndef RTLD
+/*
+ * Initialize (output) exec header such that useful values are
+ * obtained from subsequent N_*() macro evaluations.
+ */
+void
+md_init_header(hp, magic, flags)
+struct exec *hp;
+int magic, flags;
+{
+#ifdef NetBSD
+ N_SETMAGIC((*hp), magic, MID_MACHINE, flags);
+
+ /* TEXT_START depends on the value of outheader.a_entry. */
+ if (!(link_mode & SHAREABLE)) /*WAS: if (entry_symbol) */
+ hp->a_entry = PAGSIZ;
+#else
+ hp->a_magic = magic;
+ hp->a_machtype = M_SPARC;
+ hp->a_toolversion = 1;
+ hp->a_dynamic = ((flags) & EX_DYNAMIC);
+
+ /* SunOS 4.1 N_TXTADDR depends on the value of outheader.a_entry. */
+ if (!(link_mode & SHAREABLE)) /*WAS: if (entry_symbol) */
+ hp->a_entry = N_PAGSIZ(*hp);
+#endif
+}
+
+/*
+ * Check for acceptable foreign machine Ids
+ */
+int
+md_midcompat(hp)
+struct exec *hp;
+{
+#ifdef NetBSD
+#define SUN_M_SPARC 3
+ return (((md_swap_long(hp->a_midmag)&0x00ff0000) >> 16) == SUN_M_SPARC);
+#else
+ return hp->a_machtype == M_SPARC;
+#endif
+}
+#endif /* RTLD */
diff --git a/gnu/usr.bin/ld/sparc/md.h b/gnu/usr.bin/ld/sparc/md.h
new file mode 100644
index 0000000..f83c1ff
--- /dev/null
+++ b/gnu/usr.bin/ld/sparc/md.h
@@ -0,0 +1,292 @@
+/*
+ * 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: md.h,v 1.6 1994/02/13 20:43:07 jkh Exp $
+ */
+
+/*
+ * SPARC machine dependent definitions
+ */
+
+
+#define MAX_ALIGNMENT (sizeof (double))
+
+#ifdef NetBSD
+#define PAGSIZ __LDPGSZ
+
+#define N_SET_FLAG(ex,f) N_SETMAGIC(ex,N_GETMAGIC(ex), \
+ MID_MACHINE, N_GETFLAG(ex)|(f))
+#define N_IS_DYNAMIC(ex) ((N_GETFLAG(ex) & EX_DYNAMIC))
+
+/*
+ * Should be handled by a.out.h ?
+ */
+#define N_ADJUST(ex) (((ex).a_entry < PAGSIZ) ? -PAGSIZ : 0)
+#define TEXT_START(ex) (N_TXTADDR(ex) + N_ADJUST(ex))
+#define DATA_START(ex) (N_DATADDR(ex) + N_ADJUST(ex))
+
+#else
+
+/* Get the SunOS a.out and relocation nomenclature */
+#define EX_DYNAMIC 1
+
+#define N_IS_DYNAMIC(ex) ((ex).a_dynamic)
+
+#define N_SET_FLAG(ex, f) { \
+ (ex).a_dynamic = ((f) & EX_DYNAMIC); \
+}
+
+#undef relocation_info
+#define relocation_info reloc_info_sparc
+#define r_symbolnum r_index
+#endif /* NetBSD */
+
+#define N_BADMID(ex) \
+ (N_GETMID(ex) != 0 && N_GETMID(ex) != MID_MACHINE && \
+ !md_midcompat(&(ex)))
+
+/* Sparc (Sun 4) macros */
+#define RELOC_ADDRESS(r) ((r)->r_address)
+#define RELOC_EXTERN_P(r) ((r)->r_extern)
+#define RELOC_TYPE(r) ((r)->r_symbolnum)
+#define RELOC_SYMBOL(r) ((r)->r_symbolnum)
+#define RELOC_MEMORY_SUB_P(r) 0
+#ifdef RTLD
+/* XXX - consider this making SUN_COMPAT --> repercussions on rrs.c */
+#define RELOC_MEMORY_ADD_P(r) 1
+#else
+#define RELOC_MEMORY_ADD_P(r) 0
+#endif
+#define RELOC_ADD_EXTRA(r) ((r)->r_addend)
+#define RELOC_PCREL_P(r) \
+ (((r)->r_type >= RELOC_DISP8 && (r)->r_type <= RELOC_WDISP22) \
+ || ((r)->r_type == RELOC_PC10 || (r)->r_type == RELOC_PC22) \
+ || (r)->r_type == RELOC_JMP_TBL)
+#define RELOC_VALUE_RIGHTSHIFT(r) (reloc_target_rightshift[(r)->r_type])
+#define RELOC_TARGET_SIZE(r) (reloc_target_size[(r)->r_type])
+#define RELOC_TARGET_BITPOS(r) 0
+#define RELOC_TARGET_BITSIZE(r) (reloc_target_bitsize[(r)->r_type])
+
+#define RELOC_JMPTAB_P(r) ((r)->r_type == RELOC_JMP_TBL)
+
+#define RELOC_BASEREL_P(r) \
+ ((r)->r_type >= RELOC_BASE10 && (r)->r_type <= RELOC_BASE22)
+
+#define RELOC_RELATIVE_P(r) ((r)->r_type == RELOC_RELATIVE)
+#define RELOC_COPY_DAT (RELOC_RELATIVE+1) /*XXX*/
+#define RELOC_COPY_P(r) ((r)->r_type == RELOC_COPY_DAT)
+#define RELOC_LAZY_P(r) ((r)->r_type == RELOC_JMP_SLOT)
+
+#define RELOC_STATICS_THROUGH_GOT_P(r) (1)
+#define JMPSLOT_NEEDS_RELOC (1)
+
+/*
+ * Define the range of usable Global Offset Table offsets
+ * when using sparc 13 bit relocation types (-4096 - 4092).
+ */
+#define MAX_GOTSIZE (8192)
+#define MAX_GOTOFF (4092)
+#define MIN_GOTOFF (-4096)
+
+#define CHECK_GOT_RELOC(r) \
+ ((r)->r_type == RELOC_PC10 || (r)->r_type == RELOC_PC22)
+
+#define md_got_reloc(r) (-(r)->r_address)
+
+#define RELOC_INIT_SEGMENT_RELOC(r) ((r)->r_type = RELOC_32)
+
+#ifdef SUN_COMPAT
+/*
+ * Sun plays games with `r_addend'
+ */
+#define md_get_rt_segment_addend(r,a) (0)
+#endif
+
+/* Width of a Global Offset Table entry */
+typedef long got_t;
+
+typedef struct jmpslot {
+ u_long opcode1;
+ u_long opcode2;
+ u_long reloc_index;
+#define JMPSLOT_RELOC_MASK (0x003fffff) /* 22 bits */
+} jmpslot_t;
+
+#define SAVE 0x9de3bfa0 /* Build stack frame (opcode1) */
+#define SETHI 0x03000000 /* %hi(addr) -> %g1 (opcode1) */
+#define CALL 0x40000000 /* Call instruction (opcode2) */
+#define JMP 0x81c06000 /* Jump %g1 instruction (opcode2) */
+#define NOP 0x01000000 /* Delay slot NOP for (reloc_index) */
+#define TRAP 0x91d02001 /* ta 0x1 */
+
+
+/*
+ * Byte swap defs for cross linking
+ */
+
+#if !defined(NEED_SWAP)
+
+#define md_swapin_exec_hdr(h)
+#define md_swapout_exec_hdr(h)
+#define md_swapin_symbols(s,n)
+#define md_swapout_symbols(s,n)
+#define md_swapin_zsymbols(s,n)
+#define md_swapout_zsymbols(s,n)
+#define md_swapin_reloc(r,n)
+#define md_swapout_reloc(r,n)
+#define md_swapin__dynamic(l)
+#define md_swapout__dynamic(l)
+#define md_swapin_section_dispatch_table(l)
+#define md_swapout_section_dispatch_table(l)
+#define md_swapin_so_debug(d)
+#define md_swapout_so_debug(d)
+#define md_swapin_rrs_hash(f,n)
+#define md_swapout_rrs_hash(f,n)
+#define md_swapin_sod(l,n)
+#define md_swapout_sod(l,n)
+#define md_swapout_jmpslot(j,n)
+#define md_swapout_got(g,n)
+#define md_swapin_ranlib_hdr(h,n)
+#define md_swapout_ranlib_hdr(h,n)
+
+#endif /* NEED_SWAP */
+
+#ifdef CROSS_LINKER
+
+#ifdef NEED_SWAP
+
+/* Define IO byte swapping routines */
+
+void md_swapin_exec_hdr __P((struct exec *));
+void md_swapout_exec_hdr __P((struct exec *));
+void md_swapin_reloc __P((struct relocation_info *, int));
+void md_swapout_reloc __P((struct relocation_info *, int));
+void md_swapout_jmpslot __P((jmpslot_t *, int));
+
+#define md_swapin_symbols(s,n) swap_symbols(s,n)
+#define md_swapout_symbols(s,n) swap_symbols(s,n)
+#define md_swapin_zsymbols(s,n) swap_zsymbols(s,n)
+#define md_swapout_zsymbols(s,n) swap_zsymbols(s,n)
+#define md_swapin__dynamic(l) swap__dynamic(l)
+#define md_swapout__dynamic(l) swap__dynamic(l)
+#define md_swapin_section_dispatch_table(l) swap_section_dispatch_table(l)
+#define md_swapout_section_dispatch_table(l) swap_section_dispatch_table(l)
+#define md_swapin_so_debug(d) swap_so_debug(d)
+#define md_swapout_so_debug(d) swap_so_debug(d)
+#define md_swapin_rrs_hash(f,n) swap_rrs_hash(f,n)
+#define md_swapout_rrs_hash(f,n) swap_rrs_hash(f,n)
+#define md_swapin_sod(l,n) swapin_sod(l,n)
+#define md_swapout_sod(l,n) swapout_sod(l,n)
+#define md_swapout_got(g,n) swap_longs((long*)(g),n)
+#define md_swapin_ranlib_hdr(h,n) swap_ranlib_hdr(h,n)
+#define md_swapout_ranlib_hdr(h,n) swap_ranlib_hdr(h,n)
+
+#define md_swap_short(x) ( (((x) >> 8) & 0xff) | (((x) & 0xff) << 8) )
+
+#define md_swap_long(x) ( (((x) >> 24) & 0xff ) | (((x) >> 8 ) & 0xff00 ) | \
+ (((x) << 8 ) & 0xff0000) | (((x) << 24) & 0xff000000))
+
+#define get_byte(p) ( ((unsigned char *)(p))[0] )
+
+#define get_short(p) ( ( ((unsigned char *)(p))[1] << 8) | \
+ ( ((unsigned char *)(p))[0] ) \
+ )
+#define get_long(p) ( ( ((unsigned char *)(p))[3] << 24) | \
+ ( ((unsigned char *)(p))[2] << 16) | \
+ ( ((unsigned char *)(p))[1] << 8 ) | \
+ ( ((unsigned char *)(p))[0] ) \
+ )
+
+#define put_byte(p, v) { ((unsigned char *)(p))[0] = ((unsigned long)(v)); }
+
+#define put_short(p, v) { ((unsigned char *)(p))[1] = \
+ ((((unsigned long)(v)) >> 8) & 0xff); \
+ ((unsigned char *)(p))[0] = \
+ ((((unsigned long)(v)) ) & 0xff); }
+
+#define put_long(p, v) { ((unsigned char *)(p))[3] = \
+ ((((unsigned long)(v)) >> 24) & 0xff); \
+ ((unsigned char *)(p))[2] = \
+ ((((unsigned long)(v)) >> 16) & 0xff); \
+ ((unsigned char *)(p))[1] = \
+ ((((unsigned long)(v)) >> 8) & 0xff); \
+ ((unsigned char *)(p))[0] = \
+ ((((unsigned long)(v)) ) & 0xff); }
+
+#else /* We need not swap, but must pay attention to alignment: */
+
+#define md_swap_short(x) (x)
+#define md_swap_long(x) (x)
+
+#define get_byte(p) ( ((unsigned char *)(p))[0] )
+
+#define get_short(p) ( ( ((unsigned char *)(p))[0] << 8) | \
+ ( ((unsigned char *)(p))[1] ) \
+ )
+
+#define get_long(p) ( ( ((unsigned char *)(p))[0] << 24) | \
+ ( ((unsigned char *)(p))[1] << 16) | \
+ ( ((unsigned char *)(p))[2] << 8 ) | \
+ ( ((unsigned char *)(p))[3] ) \
+ )
+
+
+#define put_byte(p, v) { ((unsigned char *)(p))[0] = ((unsigned long)(v)); }
+
+#define put_short(p, v) { ((unsigned char *)(p))[0] = \
+ ((((unsigned long)(v)) >> 8) & 0xff); \
+ ((unsigned char *)(p))[1] = \
+ ((((unsigned long)(v)) ) & 0xff); }
+
+#define put_long(p, v) { ((unsigned char *)(p))[0] = \
+ ((((unsigned long)(v)) >> 24) & 0xff); \
+ ((unsigned char *)(p))[1] = \
+ ((((unsigned long)(v)) >> 16) & 0xff); \
+ ((unsigned char *)(p))[2] = \
+ ((((unsigned long)(v)) >> 8) & 0xff); \
+ ((unsigned char *)(p))[3] = \
+ ((((unsigned long)(v)) ) & 0xff); }
+
+#endif /* NEED_SWAP */
+
+#else /* Not a cross linker: use native */
+
+#define md_swap_short(x) (x)
+#define md_swap_long(x) (x)
+
+#define get_byte(where) (*(char *)(where))
+#define get_short(where) (*(short *)(where))
+#define get_long(where) (*(long *)(where))
+
+#define put_byte(where,what) (*(char *)(where) = (what))
+#define put_short(where,what) (*(short *)(where) = (what))
+#define put_long(where,what) (*(long *)(where) = (what))
+
+#endif /* CROSS_LINKER */
+
diff --git a/gnu/usr.bin/ld/sparc/mdprologue.S b/gnu/usr.bin/ld/sparc/mdprologue.S
new file mode 100644
index 0000000..d3236a3
--- /dev/null
+++ b/gnu/usr.bin/ld/sparc/mdprologue.S
@@ -0,0 +1,101 @@
+/*
+ * 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: mdprologue.S,v 1.3 1994/02/13 20:43:13 jkh Exp $
+ */
+
+/*
+ * SPARC run-time link editor entry points.
+ */
+
+#define CRT_VERSION_SUN 1
+
+ .seg "text" ! [internal]
+ .proc 16
+ .global _rtld_entry
+_rtld_entry:
+!#PROLOGUE# 0
+ save %sp,-96,%sp
+L.1B:
+ call L.2B
+ sethi %hi((__GLOBAL_OFFSET_TABLE_-(L.1B-.))),%l7
+L.2B:
+!#PROLOGUE# 1
+ or %l7,%lo((__GLOBAL_OFFSET_TABLE_-(L.1B-.))),%l7
+ add %l7,%o7,%l7
+
+ cmp %i0, CRT_VERSION_SUN ! is crtp passed in Sun style,
+ bne 1f ! ie. relative to stack frame ?
+ nop
+ add %i1, %fp, %i1 ! if so, adjust to absolute address
+1:
+ ld [%i1], %o3 ! load base address (crtp->crt_ba)
+ ld [%l7], %o2 ! get __DYNAMIC address
+ ! from 1st GOT entry
+ add %o2, %o3, %o2 ! relocate and make it 3rd arg.
+
+ ld [%l7 + _rtld], %g1 ! get address of rtld()
+ add %g1, %o3, %g1 ! relocate
+
+ mov %i1, %o1 ! set up args, #2: crtp
+ call %g1 ! rtld(version, crtp, dp)
+ mov %i0, %o0 ! arg #1: version
+
+ ret
+ restore
+ .seg "data" ! [internal]
+
+ .seg "text"
+ .global _binder_entry
+_binder_entry:
+!#PROLOGUE# 0
+ save %sp,-96,%sp
+!L.1C:
+! call L.2C
+! sethi %hi((__GLOBAL_OFFSET_TABLE_-(L.1C-.))),%l7
+!L.2C:
+! or %l7,%lo((__GLOBAL_OFFSET_TABLE_-(L.1C-.))),%l7
+!#PROLOGUE# 1
+
+ sub %i7, 4, %o0 ! get to jmpslot through pc
+ ld [%i7+4], %o1 ! get relocation index
+ sethi %hi(0x3fffff), %o2 ! -> reloc_index & 0x003fffff
+ or %o2, %lo(0x3fffff), %o2 ! [internal]
+ call _binder ! and call binder(jsp, reloc_index)
+ and %o1, %o2, %o1
+
+ mov %o0, %g1 ! return value == function address
+
+ restore ! get rid of our context
+ jmp %g1 ! and go.
+ restore ! and the jmpslot context
+ nop
+
+ .seg "data" ! [internal]
+
diff --git a/gnu/usr.bin/ld/symbol.c b/gnu/usr.bin/ld/symbol.c
new file mode 100644
index 0000000..c07637e
--- /dev/null
+++ b/gnu/usr.bin/ld/symbol.c
@@ -0,0 +1,161 @@
+/*
+ * $Id: symbol.c,v 1.5 1994/06/15 22:39:56 rich Exp $ - symbol table routines
+ */
+
+/* Create the symbol table entries for `etext', `edata' and `end'. */
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <a.out.h>
+#include <stab.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "ld.h"
+
+symbol *symtab[SYMTABSIZE]; /* The symbol table. */
+int num_hash_tab_syms; /* Number of symbols in symbol hash table. */
+
+symbol *edata_symbol; /* the symbol _edata */
+symbol *etext_symbol; /* the symbol _etext */
+symbol *end_symbol; /* the symbol _end */
+symbol *got_symbol; /* the symbol __GLOBAL_OFFSET_TABLE_ */
+symbol *dynamic_symbol; /* the symbol __DYNAMIC */
+
+void
+symtab_init(relocatable_output)
+ int relocatable_output;
+{
+ /*
+ * Put linker reserved symbols into symbol table.
+ */
+#ifndef nounderscore
+#define ETEXT_SYM "_etext"
+#define EDATA_SYM "_edata"
+#define END_SYM "_end"
+#define DYN_SYM "__DYNAMIC"
+#define GOT_SYM "__GLOBAL_OFFSET_TABLE_"
+#else
+#define ETEXT_SYM "etext"
+#define EDATA_SYM "edata"
+#define END_SYM "end"
+#define DYN_SYM "_DYNAMIC"
+#define GOT_SYM "_GLOBAL_OFFSET_TABLE_"
+#endif
+
+ dynamic_symbol = getsym(DYN_SYM);
+ dynamic_symbol->defined = relocatable_output?N_UNDF:(N_DATA | N_EXT);
+
+ got_symbol = getsym(GOT_SYM);
+ got_symbol->defined = N_DATA | N_EXT;
+
+ if (relocatable_output)
+ return;
+
+ etext_symbol = getsym(ETEXT_SYM);
+ edata_symbol = getsym(EDATA_SYM);
+ end_symbol = getsym(END_SYM);
+
+ etext_symbol->defined = N_TEXT | N_EXT;
+ edata_symbol->defined = N_DATA | N_EXT;
+ end_symbol->defined = N_BSS | N_EXT;
+
+ etext_symbol->flags |= GS_REFERENCED;
+ edata_symbol->flags |= GS_REFERENCED;
+ end_symbol->flags |= GS_REFERENCED;
+}
+
+/*
+ * Compute the hash code for symbol name KEY.
+ */
+
+int
+hash_string (key)
+ char *key;
+{
+ register char *cp;
+ register int k;
+
+ cp = key;
+ k = 0;
+ while (*cp)
+ k = (((k << 1) + (k >> 14)) ^ (*cp++)) & 0x3fff;
+
+ return k;
+}
+
+/*
+ * Get the symbol table entry for the global symbol named KEY.
+ * Create one if there is none.
+ */
+
+symbol *
+getsym(key)
+ char *key;
+{
+ register int hashval;
+ register symbol *bp;
+
+ /* Determine the proper bucket. */
+ hashval = hash_string(key) % SYMTABSIZE;
+
+ /* Search the bucket. */
+ for (bp = symtab[hashval]; bp; bp = bp->link)
+ if (strcmp(key, bp->name) == 0)
+ return bp;
+
+ /* Nothing was found; create a new symbol table entry. */
+ bp = (symbol *)xmalloc(sizeof(symbol));
+ bp->name = (char *)xmalloc(strlen(key) + 1);
+ strcpy (bp->name, key);
+ bp->refs = 0;
+ bp->defined = 0;
+ bp->value = 0;
+ bp->common_size = 0;
+ bp->warning = 0;
+ bp->undef_refs = 0;
+ bp->mult_defs = 0;
+ bp->alias = 0;
+ bp->setv_count = 0;
+ bp->symbolnum = 0;
+ bp->rrs_symbolnum = 0;
+
+ bp->size = 0;
+ bp->aux = 0;
+ bp->sorefs = 0;
+ bp->so_defined = 0;
+ bp->def_lsp = 0;
+ bp->jmpslot_offset = -1;
+ bp->gotslot_offset = -1;
+ bp->flags = 0;
+
+ /* Add the entry to the bucket. */
+ bp->link = symtab[hashval];
+ symtab[hashval] = bp;
+
+ ++num_hash_tab_syms;
+
+ return bp;
+}
+
+/* Like `getsym' but return 0 if the symbol is not already known. */
+
+symbol *
+getsym_soft (key)
+ char *key;
+{
+ register int hashval;
+ register symbol *bp;
+
+ /* Determine which bucket. */
+ hashval = hash_string(key) % SYMTABSIZE;
+
+ /* Search the bucket. */
+ for (bp = symtab[hashval]; bp; bp = bp->link)
+ if (strcmp(key, bp->name) == 0)
+ return bp;
+
+ return 0;
+}
diff --git a/gnu/usr.bin/ld/symseg.h b/gnu/usr.bin/ld/symseg.h
new file mode 100644
index 0000000..112dd6f
--- /dev/null
+++ b/gnu/usr.bin/ld/symseg.h
@@ -0,0 +1,359 @@
+/*-
+ *
+ * This code is derived from software copyrighted by the Free Software
+ * Foundation.
+ *
+ * from: @(#)symseg.h 5.4 (Berkeley) 4/30/91
+ * $Id: symseg.h,v 1.3 1993/11/09 04:19:05 paul Exp $
+ */
+
+/* GDB symbol table format definitions.
+ Copyright (C) 1987, 1988 Free Software Foundation, Inc.
+
+This file is part of GNU CC.
+
+GNU CC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 1, or (at your option)
+any later version.
+
+GNU CC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* Format of GDB symbol table data.
+ There is one symbol segment for each source file or
+ independant compilation. These segments are simply concatenated
+ to form the GDB symbol table. A zero word where the beginning
+ of a segment is expected indicates there are no more segments.
+
+Format of a symbol segment:
+
+ The symbol segment begins with a word containing 1
+ if it is in the format described here. Other formats may
+ be designed, with other code numbers.
+
+ The segment contains many objects which point at each other.
+ The pointers are offsets in bytes from the beginning of the segment.
+ Thus, each segment can be loaded into core and its pointers relocated
+ to make valid in-core pointers.
+
+ All the data objects in the segment can be found indirectly from
+ one of them, the root object, of type `struct symbol_root'.
+ It appears at the beginning of the segment.
+
+ The total size of the segment, in bytes, appears as the `length'
+ field of this object. This size includes the size of the
+ root object.
+
+ All the object data types are defined here to contain pointer types
+ appropriate for in-core use on a relocated symbol segment.
+ Casts to and from type int are required for working with
+ unrelocated symbol segments such as are found in the file.
+
+ The ldsymaddr word is filled in by the loader to contain
+ the offset (in bytes) within the ld symbol table
+ of the first nonglobal symbol from this compilation.
+ This makes it possible to match those symbols
+ (which contain line number information) reliably with
+ the segment they go with.
+
+ Core addresses within the program that appear in the symbol segment
+ are not relocated by the loader. They are inserted by the assembler
+ and apply to addresses as output by the assembler, so GDB must
+ relocate them when it loads the symbol segment. It gets the information
+ on how to relocate from the textrel, datarel, bssrel, databeg and bssbeg
+ words of the root object.
+
+ The words textrel, datarel and bssrel
+ are filled in by ld with the amounts to relocate within-the-file
+ text, data and bss addresses by; databeg and bssbeg can be
+ used to tell which kind of relocation an address needs. */
+
+enum language {language_c};
+
+struct symbol_root
+{
+ int format; /* Data format version */
+ int length; /* # bytes in this symbol segment */
+ int ldsymoff; /* Offset in ld symtab of this file's syms */
+ int textrel; /* Relocation for text addresses */
+ int datarel; /* Relocation for data addresses */
+ int bssrel; /* Relocation for bss addresses */
+ char *filename; /* Name of main source file compiled */
+ char *filedir; /* Name of directory it was reached from */
+ struct blockvector *blockvector; /* Vector of all symbol-naming blocks */
+ struct typevector *typevector; /* Vector of all data types */
+ enum language language; /* Code identifying the language used */
+ char *version; /* Version info. Not fully specified */
+ char *compilation; /* Compilation info. Not fully specified */
+ int databeg; /* Address within the file of data start */
+ int bssbeg; /* Address within the file of bss start */
+ struct sourcevector *sourcevector; /* Vector of line-number info */
+};
+
+/* All data types of symbols in the compiled program
+ are represented by `struct type' objects.
+ All of these objects are pointed to by the typevector.
+ The type vector may have empty slots that contain zero. */
+
+struct typevector
+{
+ int length; /* Number of types described */
+ struct type *type[1];
+};
+
+/* Different kinds of data types are distinguished by the `code' field. */
+
+enum type_code
+{
+ TYPE_CODE_UNDEF, /* Not used; catches errors */
+ TYPE_CODE_PTR, /* Pointer type */
+ TYPE_CODE_ARRAY, /* Array type, lower bound zero */
+ TYPE_CODE_STRUCT, /* C struct or Pascal record */
+ TYPE_CODE_UNION, /* C union or Pascal variant part */
+ TYPE_CODE_ENUM, /* Enumeration type */
+ TYPE_CODE_FUNC, /* Function type */
+ TYPE_CODE_INT, /* Integer type */
+ TYPE_CODE_FLT, /* Floating type */
+ TYPE_CODE_VOID, /* Void type (values zero length) */
+ TYPE_CODE_SET, /* Pascal sets */
+ TYPE_CODE_RANGE, /* Range (integers within spec'd bounds) */
+ TYPE_CODE_PASCAL_ARRAY, /* Array with explicit type of index */
+};
+
+/* This appears in a type's flags word for an unsigned integer type. */
+#define TYPE_FLAG_UNSIGNED 1
+
+/* Other flag bits are used with GDB. */
+
+struct type
+{
+ /* Code for kind of type */
+ enum type_code code;
+ /* Name of this type, or zero if none.
+ This is used for printing only.
+ Type names specified as input are defined by symbols. */
+ char *name;
+ /* Length in bytes of storage for a value of this type */
+ int length;
+ /* For a pointer type, describes the type of object pointed to.
+ For an array type, describes the type of the elements.
+ For a function type, describes the type of the value.
+ Unused otherwise. */
+ struct type *target_type;
+ /* Type that is a pointer to this type.
+ Zero if no such pointer-to type is known yet.
+ The debugger may add the address of such a type
+ if it has to construct one later. */
+ struct type *pointer_type;
+ /* Type that is a function returning this type.
+ Zero if no such function type is known here.
+ The debugger may add the address of such a type
+ if it has to construct one later. */
+ struct type *function_type;
+ /* Flags about this type. */
+ short flags;
+ /* Number of fields described for this type */
+ short nfields;
+ /* For structure and union types, a description of each field.
+ For set and pascal array types, there is one "field",
+ whose type is the domain type of the set or array.
+ For range types, there are two "fields",
+ the minimum and maximum values (both inclusive).
+ For enum types, each possible value is described by one "field".
+ For range types, there are two "fields", that record constant values
+ (inclusive) for the minimum and maximum.
+
+ Using a pointer to a separate array of fields
+ allows all types to have the same size, which is useful
+ because we can allocate the space for a type before
+ we know what to put in it. */
+ struct field
+ {
+ /* Position of this field, counting in bits from start of
+ containing structure. For a function type, this is the
+ position in the argument list of this argument.
+ For a range bound or enum value, this is the value itself. */
+ int bitpos;
+ /* Size of this field, in bits, or zero if not packed.
+ For an unpacked field, the field's type's length
+ says how many bytes the field occupies. */
+ int bitsize;
+ /* In a struct or enum type, type of this field.
+ In a function type, type of this argument.
+ In an array type, the domain-type of the array. */
+ struct type *type;
+ /* Name of field, value or argument.
+ Zero for range bounds and array domains. */
+ char *name;
+ } *fields;
+};
+
+/* All of the name-scope contours of the program
+ are represented by `struct block' objects.
+ All of these objects are pointed to by the blockvector.
+
+ Each block represents one name scope.
+ Each lexical context has its own block.
+
+ The first two blocks in the blockvector are special.
+ The first one contains all the symbols defined in this compilation
+ whose scope is the entire program linked together.
+ The second one contains all the symbols whose scope is the
+ entire compilation excluding other separate compilations.
+ In C, these correspond to global symbols and static symbols.
+
+ Each block records a range of core addresses for the code that
+ is in the scope of the block. The first two special blocks
+ give, for the range of code, the entire range of code produced
+ by the compilation that the symbol segment belongs to.
+
+ The blocks appear in the blockvector
+ in order of increasing starting-address,
+ and, within that, in order of decreasing ending-address.
+
+ This implies that within the body of one function
+ the blocks appear in the order of a depth-first tree walk. */
+
+struct blockvector
+{
+ /* Number of blocks in the list. */
+ int nblocks;
+ /* The blocks themselves. */
+ struct block *block[1];
+};
+
+struct block
+{
+ /* Addresses in the executable code that are in this block.
+ Note: in an unrelocated symbol segment in a file,
+ these are always zero. They can be filled in from the
+ N_LBRAC and N_RBRAC symbols in the loader symbol table. */
+ int startaddr, endaddr;
+ /* The symbol that names this block,
+ if the block is the body of a function;
+ otherwise, zero.
+ Note: In an unrelocated symbol segment in an object file,
+ this field may be zero even when the block has a name.
+ That is because the block is output before the name
+ (since the name resides in a higher block).
+ Since the symbol does point to the block (as its value),
+ it is possible to find the block and set its name properly. */
+ struct symbol *function;
+ /* The `struct block' for the containing block, or 0 if none. */
+ /* Note that in an unrelocated symbol segment in an object file
+ this pointer may be zero when the correct value should be
+ the second special block (for symbols whose scope is one compilation).
+ This is because the compiler ouptuts the special blocks at the
+ very end, after the other blocks. */
+ struct block *superblock;
+ /* Number of local symbols. */
+ int nsyms;
+ /* The symbols. */
+ struct symbol *sym[1];
+};
+
+/* Represent one symbol name; a variable, constant, function or typedef. */
+
+/* Different name spaces for symbols. Looking up a symbol specifies
+ a namespace and ignores symbol definitions in other name spaces.
+
+ VAR_NAMESPACE is the usual namespace.
+ In C, this contains variables, function names, typedef names
+ and enum type values.
+
+ STRUCT_NAMESPACE is used in C to hold struct, union and enum type names.
+ Thus, if `struct foo' is used in a C program,
+ it produces a symbol named `foo' in the STRUCT_NAMESPACE.
+
+ LABEL_NAMESPACE may be used for names of labels (for gotos);
+ currently it is not used and labels are not recorded at all. */
+
+/* For a non-global symbol allocated statically,
+ the correct core address cannot be determined by the compiler.
+ The compiler puts an index number into the symbol's value field.
+ This index number can be matched with the "desc" field of
+ an entry in the loader symbol table. */
+
+enum namespace
+{
+ UNDEF_NAMESPACE, VAR_NAMESPACE, STRUCT_NAMESPACE, LABEL_NAMESPACE,
+};
+
+/* An address-class says where to find the value of the symbol in core. */
+
+enum address_class
+{
+ LOC_UNDEF, /* Not used; catches errors */
+ LOC_CONST, /* Value is constant int */
+ LOC_STATIC, /* Value is at fixed address */
+ LOC_REGISTER, /* Value is in register */
+ LOC_ARG, /* Value is at spec'd position in arglist */
+ LOC_LOCAL, /* Value is at spec'd pos in stack frame */
+ LOC_TYPEDEF, /* Value not used; definition in SYMBOL_TYPE
+ Symbols in the namespace STRUCT_NAMESPACE
+ all have this class. */
+ LOC_LABEL, /* Value is address in the code */
+ LOC_BLOCK, /* Value is address of a `struct block'.
+ Function names have this class. */
+ LOC_EXTERNAL, /* Value is at address not in this compilation.
+ This is used for .comm symbols
+ and for extern symbols within functions.
+ Inside GDB, this is changed to LOC_STATIC once the
+ real address is obtained from a loader symbol. */
+ LOC_CONST_BYTES /* Value is a constant byte-sequence. */
+};
+
+struct symbol
+{
+ /* Symbol name */
+ char *name;
+ /* Name space code. */
+ enum namespace namespace;
+ /* Address class */
+ enum address_class class;
+ /* Data type of value */
+ struct type *type;
+ /* constant value, or address if static, or register number,
+ or offset in arguments, or offset in stack frame. */
+ union
+ {
+ long value;
+ struct block *block; /* for LOC_BLOCK */
+ char *bytes; /* for LOC_CONST_BYTES */
+ }
+ value;
+};
+
+/* Source-file information.
+ This describes the relation between source files and line numbers
+ and addresses in the program text. */
+
+struct sourcevector
+{
+ int length; /* Number of source files described */
+ struct source *source[1]; /* Descriptions of the files */
+};
+
+/* Line number and address of one line. */
+
+struct line
+{
+ int linenum;
+ int address;
+};
+
+/* All the information on one source file. */
+
+struct source
+{
+ char *name; /* Name of file */
+ int nlines; /* Number of lines that follow */
+ struct line lines[1]; /* Information on each line */
+};
diff --git a/gnu/usr.bin/ld/warnings.c b/gnu/usr.bin/ld/warnings.c
new file mode 100644
index 0000000..3c65a22
--- /dev/null
+++ b/gnu/usr.bin/ld/warnings.c
@@ -0,0 +1,758 @@
+/*
+ * $Id: warnings.c,v 1.9 1994/12/23 22:30:57 nate Exp $
+ */
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/file.h>
+#include <sys/time.h>
+#include <sys/errno.h>
+#include <err.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <ar.h>
+#include <ranlib.h>
+#include <a.out.h>
+#include <stab.h>
+#include <string.h>
+#if __STDC__
+#include <stdarg.h>
+#else
+#include <varargs.h>
+#endif
+
+#include "ld.h"
+
+static int reported_undefineds;
+
+/*
+ * Print the filename of ENTRY on OUTFILE (a stdio stream),
+ * and then a newline.
+ */
+
+void
+prline_file_name (entry, outfile)
+ struct file_entry *entry;
+ FILE *outfile;
+{
+ print_file_name (entry, outfile);
+ fprintf (outfile, "\n");
+}
+
+/*
+ * Print the filename of ENTRY on OUTFILE (a stdio stream).
+ */
+
+void
+print_file_name (entry, outfile)
+ struct file_entry *entry;
+ FILE *outfile;
+{
+ if (entry == NULL) {
+ fprintf (outfile, "NULL");
+ }
+
+ if (entry->superfile) {
+ print_file_name (entry->superfile, outfile);
+ fprintf (outfile, "(%s)", entry->filename);
+ } else
+ fprintf (outfile, "%s", entry->filename);
+}
+
+/*
+ * Return the filename of entry as a string (malloc'd for the purpose)
+ */
+
+char *
+get_file_name (entry)
+ struct file_entry *entry;
+{
+ char *result, *supfile;
+
+ if (entry == NULL) {
+ return (char *)strdup("NULL");
+ }
+
+ if (entry->superfile) {
+ supfile = get_file_name(entry->superfile);
+ result = (char *)
+ xmalloc(strlen(supfile) + strlen(entry->filename) + 3);
+ (void)sprintf(result, "%s(%s)", supfile, entry->filename);
+ free(supfile);
+
+ } else {
+ result = (char *)xmalloc(strlen(entry->filename) + 1);
+ strcpy(result, entry->filename);
+ }
+ return result;
+}
+
+/* Print a complete or partial map of the output file. */
+
+static void describe_file_sections __P((struct file_entry *, FILE *));
+static void list_file_locals __P((struct file_entry *, FILE *));
+
+void
+print_symbols(outfile)
+ FILE *outfile;
+{
+ fprintf(outfile, "\nFiles:\n\n");
+ each_file(describe_file_sections, (void *)outfile);
+
+ fprintf(outfile, "\nGlobal symbols:\n\n");
+ FOR_EACH_SYMBOL(i, sp) {
+ fprintf(outfile, " %s: ", sp->name);
+ if (!(sp->flags & GS_REFERENCED))
+ fprintf(outfile, "unreferenced");
+ else if (sp->so_defined)
+ fprintf(outfile, "sodefined");
+ else if (!sp->defined)
+ fprintf(outfile, "undefined");
+ else if (sp->defined == (N_UNDF|N_EXT))
+ fprintf(outfile, "common: size %#x", sp->common_size);
+ else
+ fprintf(outfile, "type %d, value %#x, size %#x",
+ sp->defined, sp->value, sp->size);
+ if (sp->alias)
+ fprintf(outfile, ", aliased to %s", sp->alias->name);
+ fprintf(outfile, "\n");
+ } END_EACH_SYMBOL;
+
+ each_file(list_file_locals, (void *)outfile);
+}
+
+static void
+describe_file_sections(entry, outfile)
+ struct file_entry *entry;
+ FILE *outfile;
+{
+ fprintf(outfile, " ");
+ print_file_name(entry, outfile);
+ if (entry->flags & (E_JUST_SYMS | E_DYNAMIC))
+ fprintf(outfile, " symbols only\n");
+ else
+ fprintf(outfile, " text %x(%x), data %x(%x), bss %x(%x) hex\n",
+ entry->text_start_address, entry->header.a_text,
+ entry->data_start_address, entry->header.a_data,
+ entry->bss_start_address, entry->header.a_bss);
+}
+
+static void
+list_file_locals (entry, outfile)
+ struct file_entry *entry;
+ FILE *outfile;
+{
+ struct localsymbol *lsp, *lspend;
+
+ entry->strings = (char *)alloca(entry->string_size);
+ read_entry_strings (file_open(entry), entry);
+
+ fprintf (outfile, "\nLocal symbols of ");
+ print_file_name (entry, outfile);
+ fprintf (outfile, ":\n\n");
+
+ lspend = entry->symbols + entry->nsymbols;
+ for (lsp = entry->symbols; lsp < lspend; lsp++) {
+ register struct nlist *p = &lsp->nzlist.nlist;
+ /*
+ * If this is a definition,
+ * update it if necessary by this file's start address.
+ */
+ if (!(p->n_type & (N_STAB | N_EXT)))
+ fprintf(outfile, " %s: 0x%x\n",
+ entry->strings + p->n_un.n_strx, p->n_value);
+ }
+
+ entry->strings = 0; /* All done with them. */
+}
+
+
+/* Static vars for do_warnings and subroutines of it */
+static int list_unresolved_refs; /* List unresolved refs */
+static int list_multiple_defs; /* List multiple definitions */
+
+static struct line_debug_entry *init_debug_scan __P((int, struct file_entry *));
+static int next_debug_entry __P((int, struct line_debug_entry *));
+
+/*
+ * Structure for communication between do_file_warnings and it's
+ * helper routines. Will in practice be an array of three of these:
+ * 0) Current line, 1) Next line, 2) Source file info.
+ */
+struct line_debug_entry
+{
+ int line;
+ char *filename;
+ struct localsymbol *sym;
+};
+
+/*
+ * Helper routines for do_file_warnings.
+ */
+
+/*
+ * Return an integer less than, equal to, or greater than 0 as per the
+ * relation between the two relocation entries. Used by qsort.
+ */
+
+static int
+reloc_cmp(rel1, rel2)
+ struct relocation_info *rel1, *rel2;
+{
+ return RELOC_ADDRESS(rel1) - RELOC_ADDRESS(rel2);
+}
+
+/*
+ * Moves to the next debugging symbol in the file. USE_DATA_SYMBOLS
+ * determines the type of the debugging symbol to look for (DSLINE or
+ * SLINE). STATE_POINTER keeps track of the old and new locatiosn in
+ * the file. It assumes that state_pointer[1] is valid; ie
+ * that it.sym points into some entry in the symbol table. If
+ * state_pointer[1].sym == 0, this routine should not be called.
+ */
+
+static int
+next_debug_entry(use_data_symbols, state_pointer)
+ register int use_data_symbols;
+ /* Next must be passed by reference! */
+ struct line_debug_entry state_pointer[3];
+{
+ register struct line_debug_entry
+ *current = state_pointer,
+ *next = state_pointer + 1,
+ /* Used to store source file */
+ *source = state_pointer + 2;
+
+ struct file_entry *entry = (struct file_entry *)source->sym;
+ struct localsymbol *lspend = entry->symbols + entry->nsymbols;
+
+
+ current->sym = next->sym;
+ current->line = next->line;
+ current->filename = next->filename;
+
+ while (++(next->sym) < lspend) {
+
+ struct nlist *np = &next->sym->nzlist.nlist;
+
+ /*
+ * n_type is a char, and N_SOL, N_EINCL and N_BINCL are > 0x80,
+ * so may look negative...therefore, must mask to low bits
+ */
+ switch (np->n_type & 0xff) {
+ case N_SLINE:
+ if (use_data_symbols)
+ continue;
+ next->line = np->n_desc;
+ return 1;
+ case N_DSLINE:
+ if (!use_data_symbols)
+ continue;
+ next->line = np->n_desc;
+ return 1;
+#ifdef HAVE_SUN_STABS
+ case N_EINCL:
+ next->filename = source->filename;
+ continue;
+#endif
+ case N_SO:
+ source->filename = np->n_un.n_strx + entry->strings;
+ source->line++;
+#ifdef HAVE_SUN_STABS
+ case N_BINCL:
+#endif
+ case N_SOL:
+ next->filename = np->n_un.n_strx + entry->strings;
+ default:
+ continue;
+ }
+ }
+ next->sym = (struct localsymbol *)0;
+ return 0;
+}
+
+/*
+ * Create a structure to save the state of a scan through the debug symbols.
+ * USE_DATA_SYMBOLS is set if we should be scanning for DSLINE's instead of
+ * SLINE's. ENTRY is the file entry which points at the symbols to use.
+ */
+
+static struct line_debug_entry *
+init_debug_scan(use_data_symbols, entry)
+ int use_data_symbols;
+ struct file_entry *entry;
+{
+ register struct localsymbol *lsp, *lspend;
+ struct line_debug_entry *state_pointer, *current, *next, *source;
+
+ state_pointer = (struct line_debug_entry *)
+ xmalloc(3 * sizeof(*state_pointer));
+
+ current = state_pointer,
+ next = state_pointer + 1,
+ source = state_pointer + 2; /* Used to store source file */
+
+ lspend = entry->symbols+entry->nsymbols;
+
+ for (lsp = entry->symbols; lsp < lspend; lsp++)
+ if (lsp->nzlist.nlist.n_type == N_SO)
+ break;
+
+ if (lsp >= lspend) {
+ /* I believe this translates to "We lose" */
+ current->filename = next->filename = entry->filename;
+ current->line = next->line = -1;
+ current->sym = next->sym = (struct localsymbol *)0;
+ return state_pointer;
+ }
+ next->line = source->line = 0;
+ next->filename = source->filename
+ = (lsp->nzlist.nlist.n_un.n_strx + entry->strings);
+ source->sym = (struct localsymbol *)entry;
+ next->sym = lsp;
+
+ /* To setup next */
+ next_debug_entry(use_data_symbols, state_pointer);
+
+ if (!next->sym) { /* No line numbers for this section; */
+ /* setup output results as appropriate */
+ if (source->line) {
+ current->filename = source->filename = entry->filename;
+ current->line = -1; /* Don't print lineno */
+ } else {
+ current->filename = source->filename;
+ current->line = 0;
+ }
+ return state_pointer;
+ }
+ /* To setup current */
+ next_debug_entry(use_data_symbols, state_pointer);
+
+ return state_pointer;
+}
+
+/*
+ * Takes an ADDRESS (in either text or data space) and a STATE_POINTER which
+ * describes the current location in the implied scan through the debug
+ * symbols within the file which ADDRESS is within, and returns the source
+ * line number which corresponds to ADDRESS.
+ */
+
+static int
+address_to_line(address, state_pointer)
+ unsigned long address;
+/* Next must be passed by reference! */
+ struct line_debug_entry state_pointer[3];
+{
+ struct line_debug_entry *current, *next, *tmp_pointer;
+ int use_data_symbols;
+
+ current = state_pointer;
+ next = state_pointer + 1;
+
+ if (next->sym)
+ use_data_symbols =
+ (next->sym->nzlist.nlist.n_type & N_TYPE) == N_DATA;
+ else
+ return current->line;
+
+ /* Go back to the beginning if we've already passed it. */
+ if (current->sym->nzlist.nlist.n_value > address) {
+ tmp_pointer = init_debug_scan(use_data_symbols,
+ (struct file_entry *)
+ ((state_pointer + 2)->sym));
+ state_pointer[0] = tmp_pointer[0];
+ state_pointer[1] = tmp_pointer[1];
+ state_pointer[2] = tmp_pointer[2];
+ free(tmp_pointer);
+ }
+
+ /* If we're still in a bad way, return -1, meaning invalid line. */
+ if (current->sym->nzlist.nlist.n_value > address)
+ return -1;
+
+ while (next->sym
+ && next->sym->nzlist.nlist.n_value <= address
+ && next_debug_entry(use_data_symbols, state_pointer));
+
+ return current->line;
+}
+
+
+/* Macros for manipulating bitvectors. */
+#define BIT_SET_P(bv, index) ((bv)[(index) >> 3] & 1 << ((index) & 0x7))
+#define SET_BIT(bv, index) ((bv)[(index) >> 3] |= 1 << ((index) & 0x7))
+
+/*
+ * This routine will scan through the relocation data of file ENTRY, printing
+ * out references to undefined symbols and references to symbols defined in
+ * files with N_WARNING symbols. If DATA_SEGMENT is non-zero, it will scan
+ * the data relocation segment (and use N_DSLINE symbols to track line
+ * number); otherwise it will scan the text relocation segment. Warnings
+ * will be printed on the output stream OUTFILE. Eventually, every nlist
+ * symbol mapped through will be marked in the NLIST_BITVECTOR, so we don't
+ * repeat ourselves when we scan the nlists themselves.
+ */
+
+static void
+do_relocation_warnings(entry, data_segment, outfile, nlist_bitvector)
+ struct file_entry *entry;
+ int data_segment;
+ FILE *outfile;
+ unsigned char *nlist_bitvector;
+{
+ struct relocation_info *rp, *erp;
+ int start_of_segment;
+ struct localsymbol *start_of_syms;
+ struct line_debug_entry *state_pointer, *current;
+ /* Assigned to generally static values; should not be written into. */
+ char *errfmt;
+ /*
+ * Assigned to alloca'd values cand copied into; should be freed when
+ * done.
+ */
+ char *errmsg;
+ int invalidate_line_number;
+
+ rp = data_segment ? entry->datarel : entry->textrel;
+ erp = data_segment ? (rp + entry->ndatarel) : (rp + entry->ntextrel);
+ start_of_syms = entry->symbols;
+ start_of_segment = (data_segment ?
+ entry->data_start_address :
+ entry->text_start_address);
+ state_pointer = init_debug_scan(data_segment != 0, entry);
+ current = state_pointer;
+
+ /*
+ * We need to sort the relocation info here. Sheesh, so much effort
+ * for one lousy error optimization.
+ */
+ qsort(rp, erp - rp, sizeof(rp[0]), reloc_cmp);
+
+ for (; rp < erp; rp++) {
+ register struct localsymbol *lsp;
+ register symbol *g;
+
+ /*
+ * If the relocation isn't resolved through a symbol, continue.
+ */
+ if (!RELOC_EXTERN_P(rp))
+ continue;
+
+ lsp = &entry->symbols[RELOC_SYMBOL(rp)];
+
+ /*
+ * Local symbols shouldn't ever be used by relocation info,
+ * so the next should be safe. This is, of course, wrong.
+ * References to local BSS symbols can be the targets of
+ * relocation info, and they can (must) be resolved through
+ * symbols. However, these must be defined properly, (the
+ * assembler would have caught it otherwise), so we can
+ * ignore these cases.
+ */
+
+ if ((g = lsp->symbol) == NULL)
+ continue;
+
+ if (!(lsp->nzlist.nz_type & N_EXT) &&
+ !SET_ELEMENT_P(lsp->nzlist.nz_type)) {
+ warnx("internal error: `%s' N_EXT not set", g->name);
+ continue;
+ }
+
+ errmsg = 0;
+
+ if (!g->defined && !g->so_defined && list_unresolved_refs) {
+ /* Mark as being noted by relocation warning pass. */
+ SET_BIT(nlist_bitvector, lsp - start_of_syms);
+
+ if (g->undef_refs == 0)
+ reported_undefineds++;
+ if (g->undef_refs >= MAX_UREFS_PRINTED)
+ /* Listed too many */
+ continue;
+ /* Undefined symbol which we should mention */
+
+ if (++(g->undef_refs) == MAX_UREFS_PRINTED) {
+ errfmt = "More undefined symbol %s refs follow";
+ invalidate_line_number = 1;
+ } else {
+ errfmt =
+ "Undefined symbol `%s' referenced from %s segment";
+ invalidate_line_number = 0;
+ }
+ } else { /* Defined */
+ /* Potential symbol warning here */
+ if (!g->warning)
+ continue;
+
+ if (BIT_SET_P(nlist_bitvector, lsp - start_of_syms))
+ continue;
+
+ /* Mark as being noted by relocation warning pass. */
+ SET_BIT(nlist_bitvector, lsp - start_of_syms);
+
+ errfmt = 0;
+ errmsg = g->warning;
+ invalidate_line_number = 0;
+ }
+
+
+ /* If errfmt == 0, errmsg has already been defined. */
+ if (errfmt != 0) {
+ char *nm;
+
+ nm = g->name;
+ errmsg = (char *)
+ xmalloc(strlen(errfmt) + strlen(nm) + 1);
+ sprintf(errmsg, errfmt, nm, data_segment?"data":"text");
+ if (nm != g->name)
+ free(nm);
+ }
+ address_to_line(RELOC_ADDRESS(rp) + start_of_segment,
+ state_pointer);
+
+ if (current->line >= 0)
+ fprintf(outfile, "%s:%d: %s\n",
+ current->filename,
+ invalidate_line_number ? 0 : current->line,
+ errmsg);
+ else
+ fprintf(outfile, "%s: %s\n", current->filename, errmsg);
+
+ if (errfmt != 0)
+ free(errmsg);
+ }
+
+ free(state_pointer);
+}
+
+/*
+ * Print on OUTFILE a list of all warnings generated by references and/or
+ * definitions in the file ENTRY. List source file and line number if
+ * possible, just the .o file if not.
+ */
+
+void
+do_file_warnings (entry, outfile)
+ struct file_entry *entry;
+ FILE *outfile;
+{
+ int nsym;
+ int i;
+ char *errfmt, *file_name;
+ int line_number;
+ int dont_allow_symbol_name;
+ u_char *nlist_bitvector;
+ struct line_debug_entry *text_scan, *data_scan;
+
+ nsym = entry->nsymbols;
+ nlist_bitvector = (u_char *)alloca((nsym >> 3) + 1);
+ bzero(nlist_bitvector, (nsym >> 3) + 1);
+
+ /* Read in the strings */
+ entry->strings = (char *)alloca(entry->string_size);
+ read_entry_strings(file_open(entry), entry);
+
+ if (!(entry->flags & E_DYNAMIC)) {
+ /* Do text warnings based on a scan through the reloc info. */
+ do_relocation_warnings(entry, 0, outfile, nlist_bitvector);
+
+ /* Do data warnings based on a scan through the reloc info. */
+ do_relocation_warnings(entry, 1, outfile, nlist_bitvector);
+ }
+
+ /*
+ * Scan through all of the nlist entries in this file and pick up
+ * anything that the scan through the relocation stuff didn't.
+ */
+ text_scan = init_debug_scan(0, entry);
+ data_scan = init_debug_scan(1, entry);
+
+ for (i = 0; i < nsym; i++) {
+ struct nlist *np;
+ symbol *g;
+
+ g = entry->symbols[i].symbol;
+ np = &entry->symbols[i].nzlist.nlist;
+
+ if (g == NULL)
+ continue;
+
+ if (!(np->n_type & N_EXT) && !SET_ELEMENT_P(np->n_type)) {
+ warnx("internal error: `%s' N_EXT not set", g->name);
+ continue;
+ }
+
+ if (!(g->flags & GS_REFERENCED)) {
+#if 0
+ /* Check for undefined shobj symbols */
+ struct localsymbol *lsp;
+ register int type;
+
+ for (lsp = g->sorefs; lsp; lsp = lsp->next) {
+ type = lsp->nzlist.nz_type;
+ if ((type & N_EXT) &&
+ type != (N_UNDF | N_EXT)) {
+ break;
+ }
+ }
+ if (type == (N_UNDF | N_EXT)) {
+ fprintf(stderr,
+ "Undefined symbol %s referenced from %s\n",
+ g->name,
+ get_file_name(entry));
+ }
+#endif
+ continue;
+ }
+
+ dont_allow_symbol_name = 0;
+
+ if (list_multiple_defs && g->mult_defs) {
+
+ errfmt = "Definition of symbol `%s' (multiply defined)";
+ switch (np->n_type) {
+ case N_TEXT | N_EXT:
+ line_number =
+ address_to_line(np->n_value, text_scan);
+ file_name = text_scan[0].filename;
+ break;
+
+ case N_DATA | N_EXT:
+ line_number =
+ address_to_line(np->n_value, data_scan);
+ file_name = data_scan[0].filename;
+ break;
+
+ case N_SETA | N_EXT:
+ case N_SETT | N_EXT:
+ case N_SETD | N_EXT:
+ case N_SETB | N_EXT:
+ if (g->mult_defs == 2)
+ continue;
+ errfmt =
+ "First set element definition of symbol `%s' (multiply defined)";
+ line_number = -1;
+ break;
+
+ case N_SIZE | N_EXT:
+ errfmt =
+ "Size element definition of symbol `%s' (multiply defined)";
+ line_number = -1;
+ break;
+
+ case N_INDR | N_EXT:
+ errfmt =
+ "Alias definition of symbol `%s' (multiply defined)";
+ line_number = -1;
+ break;
+
+ case N_UNDF | N_EXT:
+ /* Don't print out multiple defs at references.*/
+ continue;
+
+ default:
+ warnx("%s: unexpected multiple definitions "
+ "of symbol `%s', type %#x",
+ get_file_name(entry),
+ g->name, np->n_type);
+ break;
+ }
+
+ } else if (BIT_SET_P(nlist_bitvector, i)) {
+ continue;
+ } else if (list_unresolved_refs &&
+ !g->defined && !g->so_defined) {
+
+ if (g->undef_refs == 0)
+ reported_undefineds++;
+ if (g->undef_refs >= MAX_UREFS_PRINTED)
+ continue;
+ if (++(g->undef_refs) == MAX_UREFS_PRINTED)
+ errfmt = "More undefined `%s' refs follow";
+ else
+ errfmt = "Undefined symbol `%s' referenced";
+ line_number = -1;
+ } else if (g->def_lsp && g->def_lsp->entry != entry &&
+ !(entry->flags & E_DYNAMIC) &&
+ g->def_lsp->entry->flags & E_SECONDCLASS) {
+ fprintf(outfile,
+ "%s: Undefined symbol `%s' referenced (use %s ?)\n",
+ get_file_name(entry),
+ g->name,
+ g->def_lsp->entry->local_sym_name);
+ continue;
+ } else if (g->warning) {
+ /*
+ * There are two cases in which we don't want to do
+ * this. The first is if this is a definition instead
+ * of a reference. The second is if it's the reference
+ * used by the warning stabs itself.
+ */
+ if (np->n_type != (N_EXT | N_UNDF) ||
+ (entry->symbols[i].flags & LS_WARNING))
+ continue;
+
+ errfmt = g->warning;
+ line_number = -1;
+ dont_allow_symbol_name = 1;
+ } else
+ continue;
+
+ if (line_number == -1)
+ fprintf(outfile, "%s: ", get_file_name(entry));
+ else
+ fprintf(outfile, "%s:%d: ", file_name, line_number);
+
+ if (dont_allow_symbol_name)
+ fprintf(outfile, "%s", errfmt);
+ else
+ fprintf(outfile, errfmt, g->name);
+
+ fputc('\n', outfile);
+ }
+ free(text_scan);
+ free(data_scan);
+ entry->strings = 0; /* Since it will disappear anyway. */
+}
+
+int
+do_warnings(outfile)
+ FILE *outfile;
+{
+
+ list_unresolved_refs = !relocatable_output &&
+ ( (undefined_global_sym_count - undefined_weak_sym_count) > 0
+ || undefined_shobj_sym_count
+ );
+ list_multiple_defs = multiple_def_count != 0;
+
+ if (!(list_unresolved_refs ||
+ list_warning_symbols ||
+ list_multiple_defs))
+ /* No need to run this routine */
+ return 1;
+
+ if (entry_symbol && !entry_symbol->defined)
+ fprintf(outfile, "Undefined entry symbol `%s'\n",
+ entry_symbol->name);
+
+ each_file(do_file_warnings, (void *)outfile);
+
+ if (list_unresolved_refs &&
+ reported_undefineds !=
+ (undefined_global_sym_count - undefined_weak_sym_count))
+ warnx("Spurious undefined symbols: "
+ "# undefined symbols %d, reported %d",
+ (undefined_global_sym_count - undefined_weak_sym_count),
+ reported_undefineds);
+
+ if (list_unresolved_refs || list_multiple_defs)
+ return 0;
+
+ return 1;
+}
+
diff --git a/gnu/usr.bin/ld/xbits.c b/gnu/usr.bin/ld/xbits.c
new file mode 100644
index 0000000..6374beb
--- /dev/null
+++ b/gnu/usr.bin/ld/xbits.c
@@ -0,0 +1,167 @@
+/*
+ * 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: xbits.c,v 1.2 1993/11/09 04:19:08 paul Exp $
+ */
+
+/*
+ * "Generic" byte-swap routines.
+ */
+
+#include <sys/param.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/file.h>
+#include <fcntl.h>
+#include <ar.h>
+#include <ranlib.h>
+#include <a.out.h>
+#include <stab.h>
+#include <string.h>
+
+#include "ld.h"
+
+void
+swap_longs(lp, n)
+int n;
+long *lp;
+{
+ for (; n > 0; n--, lp++)
+ *lp = md_swap_long(*lp);
+}
+
+void
+swap_symbols(s, n)
+struct nlist *s;
+int n;
+{
+ for (; n; n--, s++) {
+ s->n_un.n_strx = md_swap_long(s->n_un.n_strx);
+ s->n_desc = md_swap_short(s->n_desc);
+ s->n_value = md_swap_long(s->n_value);
+ }
+}
+
+void
+swap_zsymbols(s, n)
+struct nzlist *s;
+int n;
+{
+ for (; n; n--, s++) {
+ s->nz_strx = md_swap_long(s->nz_strx);
+ s->nz_desc = md_swap_short(s->nz_desc);
+ s->nz_value = md_swap_long(s->nz_value);
+ s->nz_size = md_swap_long(s->nz_size);
+ }
+}
+
+
+void
+swap_ranlib_hdr(rlp, n)
+struct ranlib *rlp;
+int n;
+{
+ for (; n; n--, rlp++) {
+ rlp->ran_un.ran_strx = md_swap_long(rlp->ran_un.ran_strx);
+ rlp->ran_off = md_swap_long(rlp->ran_off);
+ }
+}
+
+void
+swap__dynamic(dp)
+struct _dynamic *dp;
+{
+ dp->d_version = md_swap_long(dp->d_version);
+ dp->d_debug = (struct so_debug *)md_swap_long((long)dp->d_debug);
+ dp->d_un.d_sdt = (struct section_dispatch_table *)
+ md_swap_long((long)dp->d_un.d_sdt);
+ dp->d_entry = (struct ld_entry *)md_swap_long((long)dp->d_entry);
+}
+
+void
+swap_section_dispatch_table(sdp)
+struct section_dispatch_table *sdp;
+{
+ swap_longs((long *)sdp, sizeof(*sdp)/sizeof(long));
+}
+
+void
+swap_so_debug(ddp)
+struct so_debug *ddp;
+{
+ swap_longs((long *)ddp, sizeof(*ddp)/sizeof(long));
+}
+
+void
+swapin_sod(sodp, n)
+struct sod *sodp;
+int n;
+{
+ unsigned long bits;
+
+ for (; n; n--, sodp++) {
+ sodp->sod_name = md_swap_long(sodp->sod_name);
+ sodp->sod_major = md_swap_short(sodp->sod_major);
+ sodp->sod_minor = md_swap_short(sodp->sod_minor);
+ sodp->sod_next = md_swap_long(sodp->sod_next);
+ bits = ((unsigned long *)sodp)[1];
+ sodp->sod_library = ((bits >> 24) & 1);
+ }
+}
+
+void
+swapout_sod(sodp, n)
+struct sod *sodp;
+int n;
+{
+ unsigned long bits;
+
+ for (; n; n--, sodp++) {
+ sodp->sod_name = md_swap_long(sodp->sod_name);
+ sodp->sod_major = md_swap_short(sodp->sod_major);
+ sodp->sod_minor = md_swap_short(sodp->sod_minor);
+ sodp->sod_next = md_swap_long(sodp->sod_next);
+ bits = (unsigned long)(sodp->sod_library) << 24;
+ ((unsigned long *)sodp)[1] = bits;
+ }
+}
+
+void
+swap_rrs_hash(fsp, n)
+struct rrs_hash *fsp;
+int n;
+{
+ for (; n; n--, fsp++) {
+ fsp->rh_symbolnum = md_swap_long(fsp->rh_symbolnum);
+ fsp->rh_next = md_swap_long(fsp->rh_next);
+ }
+}
+
diff --git a/gnu/usr.bin/man/COPYING b/gnu/usr.bin/man/COPYING
new file mode 100644
index 0000000..a43ea21
--- /dev/null
+++ b/gnu/usr.bin/man/COPYING
@@ -0,0 +1,339 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 675 Mass Ave, Cambridge, MA 02139, USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ Appendix: How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) 19yy <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) 19yy name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/gnu/usr.bin/man/Makefile b/gnu/usr.bin/man/Makefile
new file mode 100644
index 0000000..9e59558
--- /dev/null
+++ b/gnu/usr.bin/man/Makefile
@@ -0,0 +1,10 @@
+# Master Makefile for man, manpath, apropos, whatis, and makewhatis
+#
+# You may distribute under the terms of the GNU General Public
+# License as specified in the README file that comes with the man 1.0
+# distribution.
+#
+
+SUBDIR = lib man manpath apropos whatis makewhatis catman
+
+.include <bsd.subdir.mk>
diff --git a/gnu/usr.bin/man/Makefile.inc b/gnu/usr.bin/man/Makefile.inc
new file mode 100644
index 0000000..802e622
--- /dev/null
+++ b/gnu/usr.bin/man/Makefile.inc
@@ -0,0 +1,23 @@
+#
+# Set a bunch of things to hardcoded paths so that we don't accidently
+# pick up a user's own version of some utility and hose ourselves.
+#
+BINDIR?= /usr/bin
+libdir= /etc
+bindir= ${BINDIR}
+pager= more -s
+manpath_config_file= /etc/manpath.config
+troff= /usr/bin/groff -Tps -man
+nroff= /usr/bin/nroff -Tascii -man
+apropos= /usr/bin/apropos
+whatis= /usr/bin/whatis
+neqn= /usr/bin/eqn -Tascii
+tbl= /usr/bin/tbl
+col= /usr/bin/col
+vgrind= /usr/bin/vgrind
+refer= /usr/bin/refer
+grap= # no grap
+pic= /usr/bin/pic
+zcat= /usr/bin/zcat
+compress= gzip -c
+compext= .gz
diff --git a/gnu/usr.bin/man/Makefile.shprog b/gnu/usr.bin/man/Makefile.shprog
new file mode 100644
index 0000000..665a194
--- /dev/null
+++ b/gnu/usr.bin/man/Makefile.shprog
@@ -0,0 +1,30 @@
+# $Id$
+
+# This may become bsd.shprog.mk. The general version would have to handle:
+# - arbitrary sed substitutions.
+# - programs without man pages.
+# - programs with man pages in sections other than section 1.
+
+MAN1= ${SHPROG:S/$/.1/g}
+
+CLEANFILES+= ${SHPROG} ${MAN1}
+
+all: ${SHPROG}
+
+.sh:
+ sed -e 's,%libdir%,${libdir},' -e 's,%bindir%,${bindir},' \
+ -e 's,%pager%,${pager},' \
+ ${.ALLSRC} > ${.TARGET}
+
+.SUFFIXES: .man .1
+.man.1:
+ sed -e 's,%libdir%,${libdir},' -e 's,%bindir%,${bindir},' \
+ -e 's,%pager%,${pager},' -e 's,%troff%,${troff},' \
+ -e 's,%manpath_config_file%,${manpath_config_file},' \
+ ${.ALLSRC} > ${.TARGET}
+
+beforeinstall:
+ ${INSTALL} ${COPY} -o ${BINOWN} -g ${BINGRP} -m ${BINMODE} \
+ ${SHPROG} ${DESTDIR}${BINDIR}
+
+.include <bsd.prog.mk>
diff --git a/gnu/usr.bin/man/README b/gnu/usr.bin/man/README
new file mode 100644
index 0000000..d8fc4d4
--- /dev/null
+++ b/gnu/usr.bin/man/README
@@ -0,0 +1,134 @@
+README file for man(1).
+
+This is a replacement for Un*x man(1), apropos(1), whatis(1), and
+manpath(1). It has all kinds of neat features that other versions of
+man don't, including support for multiple man page directory trees,
+preformatted man pages, and troff. It is provided without any
+warranty whatever. I hope you find it useful.
+
+This program is not a GNU product but it is distributed under the
+terms of the GNU copyleft which is described in the file COPYING.
+
+There is a solution written in perl which is probably superior in
+every way, but, like me, you may prefer this one anyway.
+:-)
+
+If you compile with support for preformatted man pages, man(1) will
+try to update the preformatted page if the man page source is newer.
+
+If you compile with support for troff, you can say things like
+`man -t foo | psdit > foo.ps' and have fabulous printed documentation
+as well.
+
+I have resisted the temptation to handle all the bizarre ways various
+vendors have of organizing man pages. This version of man assumes
+that directory trees have the structure:
+
+ .../man
+ /manSect
+ /foo.Sect*
+ ...
+ /catSect
+ /foo.Sect*
+ ...
+
+where Sect is some number or string and should be listed in the set of
+sections to be searched. It is not necessary to have both the cat*
+and man* subdirectories, but you must have at least one. :-)
+
+
+INSTALLATION
+
+1. Run configure. This will grope around your system a bit and then
+ ask you a number of questions. It will create a Makefile from the
+ file Makefile.in, and a config.h file from config.h.in. You may
+ have to do some fine tuning to get things to work exactly right on
+ your system. If you do, I'd like to know what changes you had to
+ make to get things working.
+
+2. Edit the manpath.config file. This determines the system-wide
+ mappings for bin directories and man page directories.
+
+3. Do a `make all', try it out, and then if you're happy with that, do
+ a `make install'. You don't need to be root to use this set of
+ programs.
+
+4. Install the whatis database(s) by running makewhatis. If you want
+ to keep things absolutely current, you'll need to run this whenever
+ you add new man pages. You might want to add an entry in your
+ crontab.
+
+BUGS
+
+If you find one of these, please tell me about it. If you have a fix,
+that's even better. If not, I can't guarantee that I'll fix it, but I
+would like to know about them.
+
+John Eaton
+jwe@che.utexas.edu
+Department of Chemical Engineering
+The University of Texas at Austin
+Austin, Texas 78712
+
+
+CHANGES
+
+Partial list of changes since version 1.0:
+
+Installation made easier (this was the intent anyway) with the
+introduction of a configure script.
+
+Commands like `man 3f intro' handled properly when the name of the
+file we want is something like .../man3/intro.3f.
+
+Man can now run set uid to a special user so formatted man pages don't
+have to be world writable.
+
+Man now works with compressed (.Z) frozen (.F) and yabba (.Y) cat
+files. Frozen files are compressed files using freeze/melt, some
+combination of LZW and tree coding. Sources for it came out on
+comp.sources.misc or alt.sources or ... a few months ago. Yabba files
+are compressed using yabba/unyabba, a data compression scheme posted
+to alt.sources by Dan Bernstein.
+
+Man now uses a more reasonable default for the search order:
+1, n, l, 6, 8, 2, 3, 4, 5, 7, p, o
+
+Man now allows for user-definable section search order via -S or
+MANSECT.
+
+Glob.c can work even if you don't have alloca, and works properly on
+Suns with the Sun C compiler.
+
+There is now a way to automatically to run preprocessors like the Sun
+man program. The first line of the man page indicates which
+preprocessors should be run:
+
+ If the first line is a string of the form:
+
+ '\" X
+
+ where X is separated from the the `"' by a single SPACE and
+ consists of any combination of characters in the following
+ list, man pipes its input to troff(1) or nroff(1) through
+ the corresponding preprocessors.
+
+ e eqn(1), or neqn for nroff
+ g grap(1)
+ p pic(1)
+ r refer(1)
+ t tbl(1), and col(1V) for nroff
+ v vgrind(1)
+
+Preprocessors may also be set on the command line with -p or from the
+environment with MANROFFSEQ.
+
+The tbl preprocessor is run by default.
+
+Manpath now stat()'s the directories in MANPATH to avoid including
+directories that don't exist.
+
+The output of apropos and whatis are now piped through PAGER.
+
+There is a new option to show where you would find a man page
+(-w option) and in what order (-w with -a).
diff --git a/gnu/usr.bin/man/TODO b/gnu/usr.bin/man/TODO
new file mode 100644
index 0000000..19060ad
--- /dev/null
+++ b/gnu/usr.bin/man/TODO
@@ -0,0 +1,123 @@
+Things that would be nice but aren't really necessary:
+
+0. Update the documentation.
+
+XX Come up with an easier way to install this thing. There are now
+ lots of options and dependent flags to set. Should I worry too
+ much about this?
+
+XX Properly handle commands like `man 3f intro' when the name of the
+ file we want is something like .../man3/intro.3f. The way this is
+ done right now seems sort of kludgey but it mostly works. See
+ man.c for details.
+
+2. Malloc everything instead of having fixed limits... Or at least
+ check the limits everywhere. If you're paranoid about this, make
+ the limits big (famous last words: really, there aren't that many
+ things that could go wrong :-).
+
+3. Try to do a little better job of memory management. There are a
+ lot of little temporary strings that are malloc'd and never freed.
+ This is probably ok for a standalone program but not so good if
+ you wanted to call man() from another program.
+
+XX Come up with a clear view of the cat directory file permissions
+ problem. What's a good solution, other than having man run setuid
+ to some special user? (Make directories writable by all, cat
+ files 666.)
+
+XX Allow a compile time option that makes man run setuid to some
+ other user that owns all the cat pages, so that they don't have to
+ be world writable.
+
+XX Allow man to deal with compressed (.Z) frozen (.F) and yabba (.Y)
+ cat files. Frozen files are compressed files using freeze/melt,
+ some combination of LZW and tree coding. Sources for it came out
+ on comp.sources.misc or alt.sources or ... a few months ago.
+ Yabba files are compressed using yabba/unyabba, a data compression
+ scheme posted to alt.sources by Dan Bernstein.
+
+XX Choose a more reasonable default for the search order. Perhaps
+ this: 1, n, l, 6, 8, 2, 3, 4, 5, 7, p, o
+
+XX Fix glob.c so it doesn't need alloca, and/or fix it so that it can
+ work on a Sun:
+
+ #ifdef __GNUC__
+ #define alloca __builtin_alloca
+ #else /* !__GNUC__ */
+ #ifdef sparc
+ #include <alloca.h>
+ #endif /* sparc */
+ #endif /* __GNUC__ */
+
+XX Add some way to automatically to run preprocessors. The Sun man
+ program has a convention that the first line of the man page can
+ indicate which preprocessors should be run. Here's an excerpt from
+ its man page:
+
+ Preprocessing Manual Pages
+ If the first line is a string of the form:
+
+ '\" X
+
+ where X is separated from the the `"' by a single SPACE and
+ consists of any combination of characters in the following
+ list, man pipes its input to troff(1) or nroff(1) through
+ the corresponding preprocessors.
+
+ e eqn(1), or neqn for nroff
+ r refer(1)
+ t tbl(1), and col(1V) for nroff
+ v vgrind(1)
+
+ If eqn or neqn is invoked, it will automatically read the
+ file /usr/pub/eqnchar (see eqnchar(7)).
+
+XX Have manpath stat() the directories in MANPATH to avoid including
+ directories that don't exist. Some versions of man and whatis
+ complain when the directories (like /usr/new/man) don't exist.
+
+XX Pipe the output of apropos and whatis through a pager.
+
+XX I've been using your man(1) package for a while now and I ran into
+ a problem with the X man pages that use tbl commands. Is it
+ possible to configure your man(1) package to use a general command
+ string. For example, a user could set an environment variable:
+
+ setenv ROFFLINE 'pic $* | tbl | nroff -man'
+
+13. Fix makewhatis so that it can handle stuff like this (from the
+ Motif 1.1 man pages):
+
+ .TH XmRowColumn 3X "" "" "" ""
+ .SH NAME
+ .mc |
+ \fBXmRowColumn \(em the RowColumn widget class.\fP
+ .mc
+ .iX "XmRowColumn"
+ .iX "widget class" "RowColumn"
+ .sp 1
+ .SH SYNOPSIS
+
+14. Consider changing the format of the awk command's printf to use
+ "%s" instead of the standard 20.20s to accomodate the extra long
+ file names used by Motif. Maybe there's a better way to handle
+ this?
+
+15. Add ability to run man on a local file
+
+16. Handle per-tree tmac macros
+
+XX Allow user-definable section search order via -S or $MANSECT.
+ Thus programmers can get stty(3) before stty(1).
+
+XX Show all the places you would find a man page (-w option) and in
+ what order.
+
+19. Support for multi-char sections like man1m/*.1m or manavs/*.avs
+ (can I have a section that doesn't start with a numeral?)
+
+20. Implement man -K for regexp apropos
+
+21. An option to grep through all the man pages in $MANPATH
diff --git a/gnu/usr.bin/man/apropos/Makefile b/gnu/usr.bin/man/apropos/Makefile
new file mode 100644
index 0000000..0e986bb
--- /dev/null
+++ b/gnu/usr.bin/man/apropos/Makefile
@@ -0,0 +1,6 @@
+# $Id: Makefile,v 1.9 1995/07/25 00:33:07 bde Exp $
+
+SHPROG= apropos
+
+.include "../../Makefile.inc"
+.include "../Makefile.shprog"
diff --git a/gnu/usr.bin/man/apropos/apropos.man b/gnu/usr.bin/man/apropos/apropos.man
new file mode 100644
index 0000000..3bb3e17
--- /dev/null
+++ b/gnu/usr.bin/man/apropos/apropos.man
@@ -0,0 +1,27 @@
+.\" Man page for apropos
+.\"
+.\" Copyright (c) 1990, 1991, John W. Eaton.
+.\"
+.\" You may distribute under the terms of the GNU General Public
+.\" License as specified in the README file that comes with the man 1.0
+.\" distribution.
+.\"
+.\" John W. Eaton
+.\" jwe@che.utexas.edu
+.\" Department of Chemical Engineering
+.\" The University of Texas at Austin
+.\" Austin, Texas 78712
+.\"
+.TH apropos 1 "Jan 15, 1991"
+.LO 1
+.SH NAME
+apropos \- search the whatis database for strings
+.SH SYNOPSIS
+.BI apropos
+keyword ...
+.SH DESCRIPTION
+apropos searches a set of database files containing short descriptions
+of system commands for keywords and displays the result on the
+standard output.
+.SH "SEE ALSO"
+whatis(1), man(1).
diff --git a/gnu/usr.bin/man/apropos/apropos.sh b/gnu/usr.bin/man/apropos/apropos.sh
new file mode 100644
index 0000000..070b848
--- /dev/null
+++ b/gnu/usr.bin/man/apropos/apropos.sh
@@ -0,0 +1,64 @@
+#!/bin/sh
+#
+# apropos -- search the whatis database for keywords.
+#
+# Copyright (c) 1990, 1991, John W. Eaton.
+#
+# You may distribute under the terms of the GNU General Public
+# License as specified in the README file that comes with the man
+# distribution.
+#
+# John W. Eaton
+# jwe@che.utexas.edu
+# Department of Chemical Engineering
+# The University of Texas at Austin
+# Austin, Texas 78712
+
+PATH=/usr/local/bin:/bin:/usr/ucb:/usr/bin
+
+libdir=%libdir%
+
+if [ $# = 0 ]
+then
+ echo "usage: `basename $0` keyword ..."
+ exit 1
+fi
+
+manpath=`%bindir%/manpath -q | tr : '\040'`
+
+if [ "$manpath" = "" ]
+then
+ echo "whatis: manpath is null"
+ exit 1
+fi
+
+if [ "$PAGER" = "" ]
+then
+ PAGER="%pager%"
+fi
+
+while [ $1 ]
+do
+ found=0
+ for d in $manpath /usr/lib
+ do
+ if [ -f $d/whatis ]
+ then
+ grep -i "$1" $d/whatis
+ status=$?
+ if [ "$status" = "0" ]
+ then
+ found=1
+ fi
+ fi
+ done
+
+ if [ "$found" = "0" ]
+ then
+ echo "$1: nothing appropriate"
+ fi
+
+ shift
+done | $PAGER
+
+exit
diff --git a/gnu/usr.bin/man/catman/Makefile b/gnu/usr.bin/man/catman/Makefile
new file mode 100644
index 0000000..3b919e1
--- /dev/null
+++ b/gnu/usr.bin/man/catman/Makefile
@@ -0,0 +1,7 @@
+MAN1= catman.1
+
+beforeinstall:
+ ${INSTALL} -c -o ${BINOWN} -g ${BINGRP} -m ${BINMODE} \
+ ${.CURDIR}/catman.perl ${DESTDIR}${BINDIR}/catman
+
+.include <bsd.prog.mk>
diff --git a/gnu/usr.bin/man/catman/catman.1 b/gnu/usr.bin/man/catman/catman.1
new file mode 100644
index 0000000..1eb6c3c
--- /dev/null
+++ b/gnu/usr.bin/man/catman/catman.1
@@ -0,0 +1,160 @@
+.\"
+.\" (c) Copyright 1995 Wolfram Schneider. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by Wolfram Schneider
+.\" 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.
+.\"
+.\" /usr/bin/catman - preformat man pages
+.\"
+.\" E-mail: Wolfram Schneider <wosch@cs.tu-berlin.de>
+.\"
+.\" $Id: catman.1,v 1.6 1996/01/23 21:09:39 joerg Exp $
+.\"
+
+.Dd Mar 12, 1995
+.Dt CATMAN 1
+.Os
+.Sh NAME
+.Nm catman
+.Nd preformat man pages
+
+.Sh SYNOPSIS
+.Nm catman
+.Op Fl f | Fl force
+.Op Fl h | Fl help
+.Op Fl p | Fl print
+.Op Fl r | Fl remove
+.Op Fl v | Fl verbose
+.Op Ar directories...
+
+.Sh DESCRIPTION
+.Nm Catman
+format man pages to ASCII. It's like typing
+.Sq man program
+for all man pages in
+.Ar directories .
+.Ar Directories
+is a list of man directories or subdirectories separated
+by spaces or colons.
+Use
+.Ar /usr/share/man
+if no
+.Ar directories
+defined.
+
+.Sh OPTIONS
+.Bl -tag -width Ds
+
+.It Fl f , Fl force
+Force overwriting old cat pages. Normally only those pages will be formatted
+which are not up to date. This option is a waste of time, CPU and RAM.
+
+.It Fl h , Fl help
+Print options and exit.
+
+.It Fl p , Fl print
+Don't actually format man pages. Show what would be done.
+
+.It Fl r , Fl remove
+Remove garbage, e.\& g. catpage without manpage, uncompressed catpage but
+a compressed catpage exist, filenames with non-alphanumeric
+characters, uncompressed manpage but a compressed manpage exist.
+
+.It Fl v , Fl verbose
+More warnings.
+
+
+.Sh EXAMPLES
+.Pp
+.Dl $ catman
+.Pp
+Format man pages in
+.Ar /usr/share/man
+if neccessary.
+
+.Pp
+.Dl $ catman $MANPATH
+.Pp
+Format all your man pages if neccessary.
+
+.Pp
+.Dl $ catman -f /usr/local/man/man1 /usr/local/man/manl
+.Pp
+Force reformatting of all man pages in
+.Pa /usr/local/man/man1
+and
+.Pa /usr/local/man/manl .
+
+.Pp
+.Dl $ catman -p /usr/X11/man
+.Pp
+Show only.
+
+.Sh FILES
+.Bl -tag -width /etc/master.passwdxx -compact
+.Pa /etc/weekly :
+start this program
+.Po
+or
+.Pa /etc/daily
+.Pc
+.El
+
+.Sh FEATURES
+Very fast if all man pages already formatted.
+
+Does not support the
+.Fl w
+option as some other systems do. Use
+.Xr makewhatis 1
+to rebuild the
+.Ql whatis
+database.
+.Sh BUGS
+.Xr man 1
+is a setuid program. Be careful that user
+.Sq man
+has write permissions to the catman directories.
+
+.Nm Catman
+does not check for any
+.Sq .so
+in man page sources. Use hard or symlinks
+to avoid redundant formatted man pages.
+
+.Sh SEE ALSO
+.Xr man 1 ,
+.Xr manpath 1 ,
+.Xr makewhatis 1 .
+
+.Sh HISTORY
+This version of
+.Nm catman
+command appeared in FreeBSD 2.1
+
+.Sh AUTHOR
+Wolfram Schneider
+.Aq wosch@cs.tu-berlin.de ,
+Germany.
diff --git a/gnu/usr.bin/man/catman/catman.perl b/gnu/usr.bin/man/catman/catman.perl
new file mode 100644
index 0000000..d21562f
--- /dev/null
+++ b/gnu/usr.bin/man/catman/catman.perl
@@ -0,0 +1,395 @@
+#!/usr/bin/perl
+#
+# Copyright (c) March 1995 Wolfram Schneider. All rights reserved.
+# Alle Rechte vorbehalten. Es gilt das kontinentaleuropäische Urheberrecht.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# 3. All advertising materials mentioning features or use of this software
+# must display the following acknowledgement:
+# This product includes software developed by Wolfram Schneider
+# 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 AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED 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.
+#
+# /usr/bin/catman - preformat man pages
+#
+# /etc/weekly: catman `manpath -q`
+#
+# Email: Wolfram Schneider <wosch@cs.tu-berlin.de>
+#
+# $Id: catman.perl,v 1.12 1995/05/19 21:07:26 w Exp w $
+
+
+sub usage {
+
+warn <<EOF;
+usage: catman [-h|-help] [-f|-force] [-p|-print] [-r|remove]
+ [-v|-verbose] [directories ...]
+EOF
+
+exit 1;
+}
+
+sub variables {
+ $force = 0; # force overwriting existing catpages
+ $verbose = 0; # more warnings
+ $print = 0; # show only, do nothing
+ $remove = 0; # unlink forgotten man/catpages
+
+ # if no argument for directories given
+ @defaultmanpath = ( '/usr/share/man' );
+
+ $exit = 0; # exit code
+ $ext = ".gz"; # extension
+ umask(022);
+
+ # Signals
+ $SIG{'INT'} = 'Exit';
+ $SIG{'HUP'} = 'Exit';
+ $SIG{'TRAP'} = 'Exit';
+ $SIG{'QUIT'} = 'Exit';
+ $SIG{'TERM'} = 'Exit';
+ $tmp = ''; # tmp file
+
+ $ENV{'PATH'} = '/bin:/usr/bin';
+}
+
+sub Exit {
+ unlink($tmp) if $tmp ne ""; # unlink if a filename
+ die "$0: die on signal SIG@_\n";
+}
+
+sub parse {
+ local(@argv) = @_;
+
+ while($_ = $argv[0], /^-/) {
+ shift @argv;
+ last if /^--$/;
+ if (/^--?(f|force)$/) { $force = 1 }
+ elsif (/^--?(p|print)$/) { $print = 1 }
+ elsif (/^--?(r|remove)$/) { $remove = 1 }
+ elsif (/^--?(v|verbose)$/) { $verbose = 1 }
+ else { &usage }
+ }
+
+ return &absolute_path(@argv) if $#argv >= 0;
+ return @defaultmanpath if $#defaultmanpath >= 0;
+
+ warn "Missing directories\n"; &usage;
+}
+
+# make relative path to absolute path
+sub absolute_path {
+ local(@dirlist) = @_;
+ local($pwd, $dir, @a);
+
+ $pwd = $ENV{'PWD'};
+
+ foreach $dir (@dirlist) {
+ if ($dir !~ "^/") {
+ chop($pwd = `pwd`) if (!$pwd || $pwd !~ /^\//);
+ push(@a, "$pwd/$dir");
+ } else {
+ push(@a, $dir);
+ }
+ }
+ return @a;
+}
+
+# strip unused '/'
+# e.g.: //usr///home// -> /usr/home
+sub stripdir {
+ local($dir) = @_;
+
+ $dir =~ s|/+|/|g; # delete double '/'
+ $dir =~ s|/$||; # delete '/' at end
+ $dir =~ s|/(\.\/)+|/|g; # delete ././././
+
+ $dir =~ s|/+|/|g; # delete double '/'
+ $dir =~ s|/$||; # delete '/' at end
+ $dir =~ s|/\.$||; # delete /. at end
+ return $dir if $dir ne "";
+ return '/';
+}
+
+# read man directory
+sub parse_dir {
+ local($dir) = @_;
+ local($subdir, $catdir);
+ local($dev,$ino) = (stat($dir))[01];
+
+ # already visit
+ if ($dir_visit{$dev,$ino}) {
+ warn "$dir already parsed: $dir_visit{$dev,$ino}\n";
+ return 1;
+ }
+ $dir_visit{$dev,$ino} = $dir;
+
+ # Manpath, /usr/local/man
+ if ($dir =~ /man$/) {
+ warn "open manpath directory ``$dir''\n" if $verbose;
+ if (!opendir(DIR, $dir)) {
+ warn "opendir ``$dir'':$!\n"; $exit = 1; return 0;
+ }
+
+ warn "chdir to: $dir\n" if $verbose;
+ chdir($dir) || do { warn "$dir: $!\n"; $exit = 1; return 0 };
+
+ foreach $subdir (sort(readdir(DIR))) {
+ if ($subdir =~ /^man\w+$/) {
+ $subdir = "$dir/$subdir";
+ &catdir_create($subdir) && &parse_subdir($subdir);
+ }
+ }
+ closedir DIR
+
+ # subdir, /usr/local/man/man1
+ } elsif ($dir =~ /man\w+$/) {
+ local($parentdir) = $dir;
+ $parentdir =~ s|/[^/]+$||;
+ warn "chdir to: $parentdir\n" if $verbose;
+ chdir($parentdir) || do {
+ warn "$parentdir: $!\n"; $exit = 1; return 0 };
+
+ &catdir_create($dir) && &parse_subdir($dir);
+ } else {
+ warn "Assume ``$dir'' is not a man directory.\n";
+ $exit = 1;
+ }
+}
+
+# create cat subdirectory if neccessary
+# e.g.: man9 exist, but cat9 not
+sub catdir_create {
+ local($subdir) = @_;
+ local($catdir) = $subdir;
+
+ $catdir = &man2cat($subdir);
+ if (-d $catdir) {
+ return 1 if -w _;
+ if (!chmod(755, $catdir)) {
+ warn "Cannot write $catdir, chmod: $!\n";
+ $exit = 1;
+ return 0;
+ }
+ return 1;
+ }
+
+ warn "mkdir ``$catdir''\n" if $verbose || $print;
+ unless ($print) {
+ unlink($catdir); # be paranoid
+ if (!mkdir($catdir, 0755)) {
+ warn "Cannot make $catdir: $!\n";
+ $exit = 1;
+ return 0;
+ }
+ return 1;
+ }
+}
+
+# I: /usr/share/man/man9
+# O: /usr/share/man/cat9
+sub man2cat {
+ local($man) = @_;
+
+ $man =~ s/man(\w+)$/cat$1/;
+ return $man;
+}
+
+sub parse_subdir {
+ local($subdir) = @_;
+ local($file, $f, $catdir, $catdir_short, $mandir, $mandir_short);
+ local($mtime_man, $mtime_cat);
+ local(%read);
+
+
+ $mandir = $subdir;
+ $catdir = &man2cat($mandir);
+
+ ($mandir_short = $mandir) =~ s|.*/(.*)|$1|;
+ ($catdir_short = $catdir) =~ s|.*/(.*)|$1|;
+
+ warn "open man directory: ``$mandir''\n" if $verbose;
+ if (!opendir(D, $mandir)) {
+ warn "opendir ``$mandir'': $!\n"; $exit = 1; return 0;
+ }
+
+ foreach $file (readdir(D)) {
+ # skip current and parent directory
+ next if $file eq "." || $file eq "..";
+
+ # fo_09-o.bar0
+ if ($file !~ /^[\w\-\[\.]+\.\w+$/) {
+ &garbage("$mandir/$file", "Assume garbage")
+ unless -d "$mandir/$file";
+ next;
+ }
+
+ if ($file !~ /\.gz$/) {
+ if (-e "$mandir/$file.gz") {
+ &garbage("$mandir/$file",
+ "Manpage unused, see compressed version");
+ next;
+ }
+ warn "$mandir/$file is uncompressed\n" if $verbose;
+ $cfile = "$file.gz";
+ } else {
+ $cfile = "$file";
+ }
+
+ if (!(($mtime_man = ((stat("$mandir_short/$file"))[9])) && -r _ && -f _)) {
+ if (! -d _) {
+ warn "Cannot read file: ``$mandir/$file''\n";
+ $exit = 1;
+ if ($remove && -l "$mandir/$file") {
+ &garbage("$mandir/$file", "Assume wrong symlink");
+ }
+ next;
+ }
+ warn "Ignore subsubdirectory: ``$mandir/$file''\n"
+ if $verbose;
+ next;
+ }
+
+ $read{$file} = 1;
+
+ # Assume catpages always compressed
+ if (($mtime_cat = ((stat("$catdir_short/$cfile"))[9]))
+ && -r _ && -f _) {
+ if ($mtime_man > $mtime_cat || $force) {
+ &nroff("$mandir/$file", "$catdir/$cfile");
+ } else {
+ warn "up to date: $mandir/$file\n" if $verbose;
+ #print STDERR "." if $verbose;
+ }
+ } else {
+ &nroff("$mandir/$file", "$catdir/$cfile");
+ }
+ }
+ closedir D;
+
+ if (!opendir(D, $catdir)) {
+ warn "opendir ``$catdir'': $!\n"; return 0;
+ }
+
+ warn "open cat directory: ``$catdir''\n" if $verbose;
+ foreach $file (readdir(D)) {
+ next if $file =~ /^(\.|\.\.)$/; # skip current and parent directory
+
+ if ($file !~ /^[\w\-\[\.]+\.\w+$/) {
+ &garbage("$catdir/$file", "Assume garbage")
+ unless -d "$catdir/$file";
+ next;
+ }
+
+ if ($file !~ /\.gz$/ && $read{"$file.gz"}) {
+ &garbage("$catdir/$file",
+ "Catpage unused, see compressed version");
+ } elsif (!$read{$file}) {
+ # maybe a bug in man(1)
+ # if both manpage and catpage are uncompressed, man reformats
+ # the manpage and puts a compressed catpage to the
+ # already existing uncompressed catpage
+ ($f = $file) =~ s/\.gz$//;
+
+ # man page is uncompressed, catpage is compressed
+ next if $read{$f};
+ &garbage("$catdir/$file", "Catpage without manpage");
+ }
+ }
+ closedir D;
+}
+
+sub garbage {
+ local($file, @text) = @_;
+
+ warn "@text: ``$file''\n";
+ if ($remove) {
+ warn "unlink $file\n";
+ unless ($print) {
+ unlink($file) || warn "unlink $file: $!\n" ;
+ }
+ }
+}
+
+sub nroff {
+ local($man,$cat) = @_;
+ local($nroff) = "nroff -Tascii -man | col";
+ local($dev, $ino) = (stat($man))[01];
+
+ # It's a link
+ if ($link{"$dev.$ino"}) {
+ warn "Link: $link{\"$dev.$ino\"} -> $cat\n" if $verbose || $print;
+
+ return if $print; # done
+ unlink($cat); # remove possible old link
+
+ unless (link($link{"$dev.$ino"}, $cat)) {
+ warn "Link $cat: $!\n";
+ $exit = 1;
+ }
+ return;
+ } else {
+ $cat = "$cat$ext" if $cat !~ /$ext$/;
+ warn "Format: $man -> $cat\n" if $verbose || $print;
+
+ unless($print) {
+ # man page is compressed
+ if ($man =~ /$ext$/) {
+ $nroff = "zcat $man | tbl | $nroff";
+ } else {
+ $nroff = "tbl $man | $nroff";
+ }
+
+ # start formatting
+ $tmp = "$cat.$tmp"; # for cleanup after signals
+ system("$nroff | gzip > $cat.tmp");
+ if ($?) {
+ # assume a fatal signal to nroff
+ &Exit("INT to system() function") if ($? == 2);
+ } else {
+ rename("$cat.tmp", $cat);
+ }
+ }
+ }
+
+ # dev/ino from manpage, path from catpage
+ $link{"$dev.$ino"} = $cat;
+}
+
+#############
+# main
+warn "Don't start this program as root, use:\n" .
+ "echo $0 @ARGV | nice -5 su -m man\n" unless $>;
+
+&variables;
+foreach $dir (&parse(split(/[ :]/, join($", @ARGV)))) { #"
+ if (-e $dir && -d _ && -r _ && -x _) {
+ warn "``$dir'' is not writable for you,\n" .
+ "can only write to existing cat subdirs (if any)\n"
+ if ! -w _ && $verbose;
+ &parse_dir(&stripdir($dir));
+ } else {
+ warn "``$dir'' is not a directory or not read-/searchable for you\n";
+ $exit = 1;
+ }
+}
+exit($exit);
diff --git a/gnu/usr.bin/man/lib/Makefile b/gnu/usr.bin/man/lib/Makefile
new file mode 100644
index 0000000..cb5fd63
--- /dev/null
+++ b/gnu/usr.bin/man/lib/Makefile
@@ -0,0 +1,33 @@
+LIB = man
+
+.if exists(${.CURDIR}/obj)
+CONFH= ${.CURDIR}/obj/config.h
+.else
+CONFH= ${.CURDIR}/config.h
+.endif
+
+NOPROFILE= YES
+
+CFLAGS+= -I${.CURDIR} -DSTDC_HEADERS -DPOSIX -DHAS_TROFF -DDO_COMPRESS -DALT_SYSTEMS
+CLEANFILES+= ${CONFH}
+SRCS = util.c gripes.c ${CONFH}
+
+libman.a:: ${CONFH}
+
+install:
+ @echo -n
+
+${CONFH}: ${.CURDIR}/config.h_dist ${.CURDIR}/../Makefile.inc
+ sed -e 's,%apropos%,${apropos},' -e 's,%whatis%,${whatis},' \
+ -e 's,%pager%,${pager},' -e 's,%troff%,${troff},' \
+ -e 's,%nroff%,${nroff},' -e 's,%tbl%,${tbl},' \
+ -e 's,%col%,${col},' -e 's,%pic%,${pic},' \
+ -e 's,%eqn%,${eqn},' -e 's,%neqn%,${neqn},' \
+ -e 's,%vgrind%,${vgrind},' -e 's,%refer%,${refer},' \
+ -e 's,%grap%,${grap},' -e 's,%zcat%,${zcat},' \
+ -e 's,%manpath_config_file%,${manpath_config_file},' \
+ -e 's,%compress%,${compress},' \
+ -e 's,%compext%,${compext},' \
+ ${.CURDIR}/config.h_dist > ${CONFH}
+
+.include <bsd.lib.mk>
diff --git a/gnu/usr.bin/man/lib/config.h_dist b/gnu/usr.bin/man/lib/config.h_dist
new file mode 100644
index 0000000..4900c4d4
--- /dev/null
+++ b/gnu/usr.bin/man/lib/config.h_dist
@@ -0,0 +1,210 @@
+/*
+ * config.h
+ *
+ * If you haven't read the README file, now might be a good time.
+ *
+ * This file is edited by configure, so you shouldn't have to.
+ * If that doesn't work, edit this file to match your site.
+ *
+ * Sorry it's so long, but there are lots of things you might want to
+ * customize for your site.
+ *
+ * Copyright (c) 1990, 1991, John W. Eaton.
+ *
+ * You may distribute under the terms of the GNU General Public
+ * License as specified in the file COPYING that comes with the man
+ * distribution.
+ *
+ * John W. Eaton
+ * jwe@che.utexas.edu
+ * Department of Chemical Engineering
+ * The University of Texas at Austin
+ * Austin, Texas 78712
+ */
+
+/*
+ * This is the size of a number of internal buffers. It should
+ * probably not be less than 512.
+ */
+#ifndef BUFSIZ
+#define BUFSIZ 1024
+#endif
+
+/*
+ * This should be at least the size of the longest path.
+ */
+#ifndef MAXPATHLEN
+#define MAXPATHLEN 1024
+#endif
+
+/*
+ * This is the maximum number of directories expected in the manpath.
+ */
+#ifndef MAXDIRS
+#define MAXDIRS 64
+#endif
+
+/*
+ * This is the name of the group that owns the preformatted man pages.
+ * If you are running man as a setgid program, you should make sure
+ * that all of the preformatted man pages and the directories that
+ * they live in are readable and writeable and owned by this group.
+ */
+#ifdef SECURE_MAN_UID
+#define MAN_USER ""
+#endif
+
+/*
+ * It's probably best to define absolute paths to all of these. If
+ * you don't, you'll be depending on the user's path to be correct
+ * when system () is called. This can result in weird behavior that's
+ * hard to track down, especially after you forget how this program
+ * works... If you don't have some of these programs, simply define
+ * them to be empty strings (i.e. ""). As a minimum, you must have
+ * nroff installed.
+ */
+#ifndef APROPOS
+#define APROPOS "%apropos%"
+#endif
+
+#ifndef WHATIS
+#define WHATIS "%whatis%"
+#endif
+
+#ifndef PAGER
+#define PAGER "%pager%"
+#endif
+
+#ifdef HAS_TROFF
+#ifndef TROFF
+#define TROFF "%troff%"
+#endif
+#endif
+
+#ifndef NROFF
+#define NROFF "%nroff%"
+#endif
+
+#ifndef EQN
+#define EQN "%eqn%"
+#endif
+
+#ifndef NEQN
+#define NEQN "%neqn%"
+#endif
+
+#ifndef TBL
+#define TBL "%tbl%"
+#endif
+
+#ifndef COL
+#define COL "%col%"
+#endif
+
+#ifndef VGRIND
+#define VGRIND "%vgrind%"
+#endif
+
+#ifndef REFER
+#define REFER "%refer%"
+#endif
+
+#ifndef GRAP
+#define GRAP "%grap%"
+#endif
+
+#ifndef PIC
+#define PIC "%pic%"
+#endif
+
+/*
+ * Define the absolute path to the configuration file.
+ */
+#ifndef MAN_MAIN
+ static char config_file[] = "%manpath_config_file%" ;
+#endif
+
+/*
+ * Define the uncompression program(s) to use for those preformatted
+ * pages that end in the given character. If you add extras here, you
+ * may need to change man.c. [I have no idea what FCAT and YCAT files
+ * are! - I will leave them in for now.. -jkh]
+ */
+/* .F files */
+#define FCAT ""
+/* .Y files */
+#define YCAT ""
+/* .Z files */
+#define ZCAT "%zcat%"
+
+/*
+ * This is the standard program to use on this system for compressing
+ * pages once they have been formatted, and the character to tack on
+ * to the end of those files. The program listed is expected to read
+ * from the standard input and write compressed output to the standard
+ * output. These won't actually be used unless compression is enabled.
+ */
+#ifdef DO_COMPRESS
+#define COMPRESSOR "%compress%"
+#define COMPRESS_EXT "%compext%"
+#endif
+
+/*
+ * Define the standard manual sections. For example, if your man
+ * directory tree has subdirectories man1, man2, man3, mann,
+ * and man3foo, std_sections[] would have "1", "2", "3", "n", and
+ * "3foo". Directories are searched in the order they appear. Having
+ * extras isn't fatal, it just slows things down a bit.
+ *
+ * Note that this is just for directories to search. If you have
+ * files like .../man3/foobar.3Xtc, you don't need to have "3Xtc" in
+ * the list below -- this is handled separately, so that `man 3Xtc foobar',
+ * `man 3 foobar', and `man foobar' should find the file .../man3/foo.3Xtc,
+ * (assuming, of course, that there isn't a .../man1/foo.1 or somesuch
+ * that we would find first).
+ *
+ * Note that this list should be in the order that you want the
+ * directories to be searched. Is there a standard for this? What is
+ * the normal order? If anyone knows, please tell me!
+ */
+#ifndef MANPATH_MAIN
+ static char *std_sections[] =
+ {
+ "1", "n", "l", "6", "8", "2", "3", "4", "5", "7", "9", "p", "o", NULL
+ };
+#endif
+
+/*
+ * Not all systems define these in stat.h.
+ */
+#ifndef S_IRUSR
+#define S_IRUSR 00400 /* read permission: owner */
+#endif
+#ifndef S_IWUSR
+#define S_IWUSR 00200 /* write permission: owner */
+#endif
+#ifndef S_IRGRP
+#define S_IRGRP 00040 /* read permission: group */
+#endif
+#ifndef S_IWGRP
+#define S_IWGRP 00020 /* write permission: group */
+#endif
+#ifndef S_IROTH
+#define S_IROTH 00004 /* read permission: other */
+#endif
+#ifndef S_IWOTH
+#define S_IWOTH 00002 /* write permission: other */
+#endif
+
+/*
+ * This is the mode used for formatted pages that we create. If you
+ * are using the setgid option, you should use 664. If you are not,
+ * you should use 666 and make the cat* directories mode 777.
+ */
+#ifndef CATMODE
+#ifdef SECURE_MAN_UID
+#define CATMODE S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH
+#else
+#define CATMODE S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH
+#endif
+#endif
diff --git a/gnu/usr.bin/man/lib/gripes.c b/gnu/usr.bin/man/lib/gripes.c
new file mode 100644
index 0000000..466f0bc
--- /dev/null
+++ b/gnu/usr.bin/man/lib/gripes.c
@@ -0,0 +1,180 @@
+/*
+ * gripes.c
+ *
+ * Copyright (c) 1990, 1991, John W. Eaton.
+ *
+ * You may distribute under the terms of the GNU General Public
+ * License as specified in the file COPYING that comes with the man
+ * distribution.
+ *
+ * John W. Eaton
+ * jwe@che.utexas.edu
+ * Department of Chemical Engineering
+ * The University of Texas at Austin
+ * Austin, Texas 78712
+ */
+
+#include <stdio.h>
+#include "gripes.h"
+
+#ifdef STDC_HEADERS
+#include <stdlib.h>
+#else
+extern int fprintf ();
+extern int fflush ();
+extern int exit ();
+#endif
+
+extern char *prognam;
+
+void
+gripe_no_name (section)
+ char *section;
+{
+ if (section)
+ fprintf (stderr, "What manual page do you want from section %s?\n",
+ section);
+ else
+ fprintf (stderr, "What manual page do you want?\n");
+
+ fflush (stderr);
+}
+
+void
+gripe_reading_man_file (name)
+ char *name;
+{
+ fprintf (stderr, "Read access denied for file %s\n", name);
+
+ fflush (stderr);
+}
+
+void
+gripe_converting_name (name, to_cat)
+ char *name;
+ int to_cat;
+{
+ if (to_cat)
+ fprintf (stderr, "Error converting %s to cat name\n", name);
+ else
+ fprintf (stderr, "Error converting %s to man name\n", name);
+
+ fflush (stderr);
+
+ exit (1);
+}
+
+void
+gripe_system_command (status)
+ int status;
+{
+ fprintf (stderr, "Error executing formatting or display command.\n");
+ fprintf (stderr, "system command exited with status %d\n", status);
+
+ fflush (stderr);
+}
+
+void
+gripe_not_found (name, section)
+ char *name, *section;
+{
+ if (section)
+ fprintf (stderr, "No entry for %s in section %s of the manual\n",
+ name, section);
+ else
+ fprintf (stderr, "No manual entry for %s\n", name);
+
+ fflush (stderr);
+}
+
+void
+gripe_incompatible (s)
+ char *s;
+{
+ fprintf (stderr, "%s: incompatible options %s\n", prognam, s);
+
+ fflush (stderr);
+
+ exit (1);
+}
+
+void
+gripe_getting_mp_config (file)
+ char *file;
+{
+ fprintf (stderr, "%s: unable to find the file %s\n", prognam, file);
+
+ fflush (stderr);
+
+ exit (1);
+}
+
+void
+gripe_reading_mp_config (file)
+ char *file;
+{
+ fprintf (stderr, "%s: unable to make sense of the file %s\n", prognam, file);
+
+ fflush (stderr);
+
+ exit (1);
+}
+
+void
+gripe_invalid_section (section)
+ char *section;
+{
+ fprintf (stderr, "%s: invalid section (%s) selected\n", prognam, section);
+
+ fflush (stderr);
+
+ exit (1);
+}
+
+void
+gripe_manpath ()
+{
+ fprintf (stderr, "%s: manpath is null\n", prognam);
+
+ fflush (stderr);
+
+ exit (1);
+}
+
+void
+gripe_alloc (bytes, object)
+ int bytes;
+ char *object;
+{
+ fprintf (stderr, "%s: can't malloc %d bytes for %s\n",
+ prognam, bytes, object);
+
+ fflush (stderr);
+
+ exit (1);
+}
+
+void
+gripe_roff_command_from_file (file)
+ char *file;
+{
+ fprintf (stderr, "Error parsing *roff command from file %s\n", file);
+
+ fflush (stderr);
+}
+
+void
+gripe_roff_command_from_env ()
+{
+ fprintf (stderr, "Error parsing MANROFFSEQ. Using system defaults.\n");
+
+ fflush (stderr);
+}
+
+void
+gripe_roff_command_from_command_line ()
+{
+ fprintf (stderr, "Error parsing *roff command from command line.\n");
+
+ fflush (stderr);
+}
diff --git a/gnu/usr.bin/man/lib/gripes.h b/gnu/usr.bin/man/lib/gripes.h
new file mode 100644
index 0000000..5fd59b2
--- /dev/null
+++ b/gnu/usr.bin/man/lib/gripes.h
@@ -0,0 +1,30 @@
+/*
+ * gripes.h
+ *
+ * Copyright (c) 1990, 1991, John W. Eaton.
+ *
+ * You may distribute under the terms of the GNU General Public
+ * License as specified in the file COPYING that comes with the man
+ * distribution.
+ *
+ * John W. Eaton
+ * jwe@che.utexas.edu
+ * Department of Chemical Engineering
+ * The University of Texas at Austin
+ * Austin, Texas 78712
+ */
+
+extern void gripe_no_name ();
+extern void gripe_converting_name ();
+extern void gripe_system_command ();
+extern void gripe_reading_man_file ();
+extern void gripe_not_found ();
+extern void gripe_invalid_section ();
+extern void gripe_manpath ();
+extern void gripe_alloc ();
+extern void gripe_incompatible ();
+extern void gripe_getting_mp_config ();
+extern void gripe_reading_mp_config ();
+extern void gripe_roff_command_from_file ();
+extern void gripe_roff_command_from_env ();
+extern void gripe_roff_command_from_command_line ();
diff --git a/gnu/usr.bin/man/lib/util.c b/gnu/usr.bin/man/lib/util.c
new file mode 100644
index 0000000..14a6cb9
--- /dev/null
+++ b/gnu/usr.bin/man/lib/util.c
@@ -0,0 +1,149 @@
+/*
+ * util.c
+ *
+ * Copyright (c) 1990, 1991, John W. Eaton.
+ *
+ * You may distribute under the terms of the GNU General Public
+ * License as specified in the file COPYING that comes with the man
+ * distribution.
+ *
+ * John W. Eaton
+ * jwe@che.utexas.edu
+ * Department of Chemical Engineering
+ * The University of Texas at Austin
+ * Austin, Texas 78712
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+
+#ifdef STDC_HEADERS
+#include <stdlib.h>
+#else
+extern int fprintf ();
+extern int tolower ();
+#endif
+
+extern char *strdup ();
+extern int system ();
+
+#include "gripes.h"
+
+/*
+ * Extract last element of a name like /foo/bar/baz.
+ */
+char *
+mkprogname (s)
+ register char *s;
+{
+ char *t;
+
+ t = strrchr (s, '/');
+ if (t == (char *)NULL)
+ t = s;
+ else
+ t++;
+
+ return strdup (t);
+}
+
+void
+downcase (s)
+ char *s;
+{
+ register char c;
+ while ((c = *s) != '\0')
+ {
+ if (isalpha (c))
+ *s++ = tolower (c);
+ }
+}
+
+/*
+ * Is file a newer than file b?
+ *
+ * case:
+ *
+ * a newer than b returns 1
+ * a older than b returns 0
+ * stat on a fails returns -1
+ * stat on b fails returns -2
+ * stat on a and b fails returns -3
+ */
+int
+is_newer (fa, fb)
+ register char *fa;
+ register char *fb;
+{
+ struct stat fa_sb;
+ struct stat fb_sb;
+ register int fa_stat;
+ register int fb_stat;
+ register int status = 0;
+
+ fa_stat = stat (fa, &fa_sb);
+ if (fa_stat != 0)
+ status = 1;
+
+ fb_stat = stat (fb, &fb_sb);
+ if (fb_stat != 0)
+ status |= 2;
+
+ if (status != 0)
+ return -status;
+
+ return (fa_sb.st_mtime > fb_sb.st_mtime);
+}
+
+/*
+ * Is path a directory?
+ */
+int
+is_directory (path)
+ char *path;
+{
+ struct stat sb;
+ register int status;
+
+ status = stat (path, &sb);
+
+ if (status != 0)
+ return -1;
+
+ return ((sb.st_mode & S_IFDIR) == S_IFDIR);
+
+}
+
+/*
+ * Attempt a system () call. Return 1 for success and 0 for failure
+ * (handy for counting successes :-).
+ */
+int
+do_system_command (command)
+ char *command;
+{
+ int status = 0;
+ extern int debug;
+
+ /*
+ * If we're debugging, don't really execute the command -- you never
+ * know what might be in that mangled string :-O.
+ */
+ if (debug)
+ fprintf (stderr, "\ntrying command: %s\n", command);
+ else
+ status = system (command);
+
+ if (WIFSIGNALED(status))
+ return -1;
+ else if (WEXITSTATUS(status)) {
+ gripe_system_command (status);
+ return 0;
+ }
+ else
+ return 1;
+}
diff --git a/gnu/usr.bin/man/makewhatis/Makefile b/gnu/usr.bin/man/makewhatis/Makefile
new file mode 100644
index 0000000..644a3a5
--- /dev/null
+++ b/gnu/usr.bin/man/makewhatis/Makefile
@@ -0,0 +1,7 @@
+MAN1= makewhatis.1
+
+beforeinstall:
+ ${INSTALL} -c -o ${BINOWN} -g ${BINGRP} -m ${BINMODE} \
+ ${.CURDIR}/makewhatis.perl ${DESTDIR}${BINDIR}/makewhatis
+
+.include <bsd.prog.mk>
diff --git a/gnu/usr.bin/man/makewhatis/makewhatis.1 b/gnu/usr.bin/man/makewhatis/makewhatis.1
new file mode 100644
index 0000000..4570b58
--- /dev/null
+++ b/gnu/usr.bin/man/makewhatis/makewhatis.1
@@ -0,0 +1,155 @@
+.\"
+.\" (c) Copyright 1995 Wolfram Schneider. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by Wolfram Schneider
+.\" 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.
+.\"
+.\" /usr/bin/makewhatis - create whatis database
+.\"
+.\" Email: Wolfram Schneider <wosch@cs.tu-berlin.de>
+.\"
+.\" $Id: makewhatis.1,v 1.1 1995/02/15 22:52:51 joerg Exp $
+.\"
+
+.Dd Jan, 12, 1995
+.Dt MAKEWHATIS 1
+.Os FreeBSD 2.1
+.Sh NAME
+.Nm makewhatis
+.Nd create whatis database
+
+.Sh SYNOPSIS
+.Nm makewhatis
+.Op Fl i | Fl indent Ar column
+.Op Fl n | Fl name Ar name
+.Op Fl o | Fl outfile Ar file
+.Op Fl v | Fl verbose
+.Op Fl h | Fl help
+.Op Ar directories ...
+
+.Sh DESCRIPTION
+.Nm Makewhatis
+extracts the name and a short description from unformatted manpages
+and creates the
+.Xr whatis 1
+database.
+.Nm Makewhatis
+can read gzip'ed manpages.
+
+.Ar Directory
+names a directory containing manpage subdirectories
+.Pq named Pa man[0-8] .
+Colons are treated as spaces, hence
+.Ic makewhatis $MANPATH
+or
+.Ic makewhatis `manpath`
+are allowed.
+
+.Sh OPTIONS
+.Bl -tag -width Ds
+.It Fl h , Fl help
+Print options and exit.
+.It Fl v, Fl verbose
+Issue more warnings
+.Pq to stderr .
+For every parsed man page write a single char:
+.Ql \&.
+for an uncompressed page,
+.Ql *
+for a compressed page, and
+.Ql +
+for a link.
+
+.It Fl i , Fl indent Ar column
+Justify description strings to
+.Ar column Pq default 24 .
+
+.It Fl o , Fl outfile Ar file
+Write all output to
+.Ar file
+instead of
+.Pa dirname/whatis Ns .
+
+.It Fl n , Fl name Ar name
+Use
+.Ar name
+instead of
+.Pa whatis Ns .
+
+.Sh EXAMPLES
+.Pp
+.Ic makewhatis $MANPATH
+.Pp
+Create whatis database for all directories in your
+.Pa $MANPATH Ns .
+.Pp
+.Ic makewhatis -outfile /tmp/mywhatis /usr/local/man $HOME/man
+.Pp
+Create whatis database
+.Pa /tmp/mywhatis
+\&.
+Traverse directories
+.Pa /usr/local/man
+and
+.Pa $HOME/man Ns .
+Don't create
+.Pa /usr/local/man/whatis
+or
+.Pa $HOME/man/whatis Ns .
+.Pp
+.Ic makewhatis -name windex $HOME/man
+.Pp
+Create whatis database
+.Pa windex
+instead of
+.Pa whatis Ns .
+May be useful for Solaris.
+
+.Sh FILES
+.Bl -tag -width /etc/master.passwdxx -compact
+.It Pa */man/whatis
+whatis database
+.It Pa /etc/weekly
+run
+.Nm
+every week
+.El
+
+.Sh SEE ALSO
+.Xr man 1 ,
+.Xr whatis 1 ,
+.Xr apropos 1 ,
+.Xr manpath 1 ,
+.Xr catman 1 .
+
+.Sh HISTORY
+This
+.Nm
+command appeared in FreeBSD 2.1.
+
+.Sh AUTHOR
+Wolfram Schneider
+.Aq wosch@cs.tu-berlin.de ,
+Germany
diff --git a/gnu/usr.bin/man/makewhatis/makewhatis.perl b/gnu/usr.bin/man/makewhatis/makewhatis.perl
new file mode 100644
index 0000000..02f11a3
--- /dev/null
+++ b/gnu/usr.bin/man/makewhatis/makewhatis.perl
@@ -0,0 +1,498 @@
+#!/usr/bin/perl
+#
+# Copyright (c) 1994, 1995 Wolfram Schneider. All rights reserved.
+# Alle Rechte vorbehalten. Es gilt das kontinentaleuropäische Urheberrecht.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# 3. All advertising materials mentioning features or use of this software
+# must display the following acknowledgement:
+# This product includes software developed by Wolfram Schneider
+# 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 AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED 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 -- update the whatis database in the man directories.
+#
+# E-Mail: Wolfram Schneider <wosch@cs.tu-berlin.de>
+#
+# $Id: makewhatis.perl,v 1.6 1995/04/01 11:43:09 joerg Exp $
+#
+
+sub usage {
+
+ warn <<EOF;
+usage: makewhatis [-v|-verbose] [-h|-help] [-i|-indent colum]
+ [-n|-name name] [-o|-outfile file] [directories ...]
+EOF
+ exit 1;
+}
+
+
+# Format output
+sub open_output {
+ local($dir) = @_;
+
+ die "Name for whatis is empty\n" if $whatis_name eq "";
+
+ if ($outfile) { # Write all Output to $outfile
+ $whatisdb = $outfile;
+ } else { # Use man/whatis
+ $whatisdb = $dir . "/$whatis_name.tmp";
+ }
+ $tmp = $whatisdb; # for signals
+
+ if (!open(A, "> $whatisdb")) {
+ die "$whatisdb: $!\n" if $outfile;
+
+ warn "$whatisdb: $!\n"; $err++; return 0;
+ }
+ @a = ();
+
+ warn "Open $whatisdb\n" if $verbose;
+ select A;
+ return 1;
+}
+
+sub close_output {
+ local($success) = @_;
+ local($w) = $whatisdb;
+ local($counter) = 0;
+ local($i, $last,@b);
+
+ $w =~ s/\.tmp$//;
+ if ($success) { # success
+
+ # uniq
+ @b = ();
+ warn "\n" if $verbose && $pointflag;
+ warn "sort -u > $whatisdb\n" if $verbose;
+ foreach $i (sort @a) {
+ if ($i ne $last) {
+ push(@b, $i);
+ $counter++;
+ }
+ $last =$i;
+ }
+ print @b; close A; select STDOUT;
+
+ if (!$outfile) {
+ rename($whatisdb, $w);
+ warn "Rename $whatisdb to $w\n" if $verbose;
+ $counter_all += $counter;
+ warn "$counter entries in $w\n" if $verbose;
+ } else {
+ $counter_all = $counter;
+ }
+ } else { # building whatisdb failed
+ unlink($whatisdb);
+ warn "building whatisdb: $whatisdb failed\n" if $verbose;
+ }
+ return 1;
+}
+
+sub parse_subdir {
+ local($dir) = @_;
+ local($file, $dev,$ino);
+
+ warn "\n" if $pointflag;
+ warn "traverse $dir\n" if $verbose;
+ $pointflag = 0;
+
+ if (!opendir(M, $dir)) {
+ warn "$dir: $!\n"; $err++; return 0;
+ }
+
+ $| = 1 if $verbose;
+ foreach $file (readdir(M)) {
+ next if $file =~ /^(\.|\.\.)$/;
+
+ ($dev, $ino) = ((stat("$dir/$file"))[01]);
+ if (-f _) {
+ if ($man_red{"$dev.$ino"}) {
+ # Link
+ print STDERR "+" if $verbose;
+ $pointflag++ if $verbose;
+ } else {
+ &manual("$dir/$file");
+ }
+ $man_red{"$dev.$ino"} = 1;
+ } elsif (! -d _) {
+ warn "Cannot find file: $dir/$file\n"; $err++;
+ }
+ }
+ closedir M;
+ return 1;
+}
+
+# read man directory
+sub parse_dir {
+ local($dir) = @_;
+ local($subdir, $file);
+
+ # clean up, in case mandir and subdirs are called simultaneously
+ # e. g.: ~/man/man1 ~/man/man2 ~/man
+ #~/man/ man1 and ~/man/man2 are a subset of ~/man
+ foreach $file (keys %man_red) {
+ delete $man_red{$file};
+ }
+
+ if ($dir =~ /man$/) {
+ warn "\n" if $verbose && $pointflag;
+ warn "open manpath directory ``$dir''\n" if $verbose;
+ $pointflag = 0;
+ if (!opendir(DIR, $dir)) {
+ warn "opendir ``$dir'':$!\n"; $err = 1; return 0;
+ }
+ foreach $subdir (sort(readdir(DIR))) {
+ if ($subdir =~ /^man\w+$/) {
+ $subdir = "$dir/$subdir";
+ &parse_subdir($subdir);
+ }
+ }
+ closedir DIR
+
+ } elsif ($dir =~ /man\w+$/) {
+ &parse_subdir($dir);
+ } else {
+ warn "Assume ``$dir'' is not a man directory.\n";
+ $err = 1; return 0;
+ }
+ return 1;
+}
+
+sub dir_redundant {
+ local($dir) = @_;
+
+ local ($dev,$ino) = (stat($dir))[0..1];
+
+ if ($dir_redundant{"$dev.$ino"}) {
+ warn "$dir is equal to: $dir_redundant{\"$dev.$ino\"}\n" if $verbose;
+ return 0;
+ }
+ $dir_redundant{"$dev.$ino"} = $dir;
+ return 1;
+}
+
+
+# ``/usr/man/man1/foo.l'' -> ``l''
+sub ext {
+ local($filename) = @_;
+ local($extension) = $filename;
+
+ $extension =~ s/$ext$//g; # strip .gz
+ $extension =~ s/.*\///g; # basename
+
+ if ($extension !~ /\./) { # no dot
+ $extension = $filename;
+ #$extension =~ s|/[^/]+$||;
+ $extension =~ s/.*(.)/$1/; # last character
+ warn "\n" if $verbose && $pointflag;
+ warn "$filename has no extension, try section ``$extension''\n"
+ if $verbose;
+ $pointflag = 0;
+ } else {
+ $extension =~ s/.*\.//g; # foo.bla.1 -> 1
+ }
+ return "$extension";
+}
+
+# ``/usr/man/man1/foo.1'' -> ``foo''
+sub name {
+ local($name) = @_;
+
+ $name =~ s=.*/==;
+ $name =~ s=$ext$==o;
+ $name =~ s=\.[^\.]+$==;
+
+ return "$name";
+}
+
+# output
+sub out {
+ local($list) = @_;
+ local($delim) = " - ";
+ $_ = $list;
+
+ # delete italic etc.
+ s/^\.[^ -]+[ -]+//;
+ s/\\\((em|mi)//;
+ s/\\f[IRBP]//g;
+ s/\\\*p//g;
+ s/\(OBSOLETED\)[ ]?//;
+ s/\\&//g;
+ s/^\@INDOT\@//;
+ s/[\"\\]//g; #"
+ s/[. \t-]+$//;
+
+ s/ / - / unless / - /;
+ ($man,$desc) = split(/ - /);
+
+ $man = $name unless $man;
+ $man =~ s/[,. ]+$//;
+ $man =~ s/,/($extension),/g;
+ $man .= "($extension)";
+
+ &manpagename;
+
+ $desc =~ s/^[ \t]+//;
+
+ for($i = length($man); $i < $indent && $desc; $i++) {
+ $man .= ' ';
+ }
+ if ($desc) {
+ push(@a, "$man$delim$desc\n");
+ } else {
+ push(@a, "$man\n");
+ }
+}
+
+# The filename of manual page is not a keyword.
+# This may be dangerous, because you don't find the manpage
+# whith: $ man <section> <keyword>
+#
+# Add filename if a) filename is not a keyword and b) no keyword(s)
+# exist as file in same mansection
+#
+sub manpagename {
+ foreach (split(/,\s+/, $man)) {
+ s/\(.+//;
+ # filename is keyword
+ return if $name eq $_;
+ }
+
+ $name =~ s=\[=\\\[=g; # shit '['
+ foreach (split(/,\s+/, $man)) {
+ s/\(.+//;
+ ($f = $file) =~ s/$name/$_/;
+ # a keyword exist as file
+ return if -e "$f";
+ }
+
+ $man .= ", $name($extension)";
+}
+
+# looking for NAME
+sub manual {
+ local($file) = @_;
+ local($list, $desc, $extension);
+ local($ofile) = $file;
+
+ # Compressed man pages
+ if ($ofile =~ /$ext$/) {
+ $ofile = "gzcat $file |";
+ print STDERR "*" if $verbose;
+ } else {
+ print STDERR "." if $verbose;
+ }
+ $pointflag++ if $verbose;
+
+ if (!open(F, "$ofile")) {
+ warn "Cannot open file: $ofile\n"; $err++;
+ return 0;
+ }
+ # extension/section
+ $extension = &ext($file);
+ $name = &name($file);
+
+ local($source) = 0;
+ local($list);
+ while(<F>) {
+ # ``man'' style pages
+ # &&: it takes you only half the user time, regexp is slow!!!
+ if (/^\.SH/ && /^\.SH[ \t]+["]?(NAME|Name|NAMN)["]?/) {
+ #while(<F>) { last unless /^\./ } # Skip
+ #chop; $list = $_;
+ while(<F>) {
+ last if /^\.SH[ \t]/;
+ chop;
+ s/^\.[A-Z]+[ ]+[0-9]+$//; # delete commands
+ s/^\.[A-Za-z]+[ \t]*//; # delete commands
+ s/^\.\\".*$//; #" delete comments
+ s/^[ \t]+//;
+ if ($_) {
+ $list .= $_;
+ $list .= ' ';
+ }
+ }
+ &out($list); close F; return 1;
+ } elsif (/^\.Sh/ && /^\.Sh[ \t]+["]?(NAME|Name)["]?/) {
+ # ``doc'' style pages
+ local($flag) = 0;
+ while(<F>) {
+ last if /^\.Sh/;
+ chop;
+ s/^\.\\".*$//; #" delete comments
+ if (/^\.Nm/) {
+ s/^\.Nm[ \t]*//;
+ s/ ,/,/g;
+ s/[ \t]+$//;
+ $list .= $_;
+ $list .= ' ';
+ } else {
+ $list .= '- ' if (!$flag && !/-/);
+ $flag++;
+ s/^\.[A-Z][a-z][ \t]*//;
+ s/[ \t]+$//;
+ $list .= $_;
+ $list .= ' ';
+ }
+ }
+ &out($list); close F; return 1;
+
+ } elsif(/^\.so/ && /^\.so[ \t]+man/) {
+ close F; return 1;
+ }
+ }
+ if (!$source && $verbose) {
+ warn "\n" if $pointflag;
+ warn "Maybe $file is not a manpage\n" ;
+ $pointflag = 0;
+ }
+ return 0;
+}
+
+# make relative path to absolute path
+sub absolute_path {
+ local(@dirlist) = @_;
+ local($pwd, $dir, @a);
+
+ $pwd = $ENV{'PWD'};
+ foreach $dir (@dirlist) {
+ if ($dir !~ "^/") {
+ chop($pwd = `pwd`) if (!$pwd || $pwd !~ /^\//);
+ push(@a, "$pwd/$dir");
+ } else {
+ push(@a, $dir);
+ }
+ }
+ return @a;
+}
+
+# strip unused '/'
+# e.g.: //usr///home// -> /usr/home
+sub stripdir {
+ local($dir) = @_;
+
+ $dir =~ s|/+|/|g; # delete double '/'
+ $dir =~ s|/$||; # delete '/' at end
+ $dir =~ s|/(\.\/)+|/|g; # delete ././././
+
+ $dir =~ s|/+|/|g; # delete double '/'
+ $dir =~ s|/$||; # delete '/' at end
+ $dir =~ s|/\.$||; # delete /. at end
+ return $dir if $dir ne "";
+ return '/';
+}
+
+sub variables {
+ $verbose = 0; # Verbose
+ $indent = 24; # indent for description
+ $outfile = 0; # Don't write to ./whatis
+ $whatis_name = "whatis"; # Default name for DB
+
+ # if no argument for directories given
+ @defaultmanpath = ( '/usr/share/man' );
+
+ $ext = '.gz'; # extension
+ umask(022);
+
+ $err = 0; # exit code
+ $whatisdb = '';
+ $counter_all = 0;
+ $dir_redundant = ''; # redundant directories
+ $man_red = ''; # redundant man pages
+ @a = (); # Array for output
+
+ # Signals
+ $SIG{'INT'} = 'Exit';
+ $SIG{'HUP'} = 'Exit';
+ $SIG{'TRAP'} = 'Exit';
+ $SIG{'QUIT'} = 'Exit';
+ $SIG{'TERM'} = 'Exit';
+ $tmp = ''; # tmp file
+
+ $ENV{'PATH'} = "/bin:/usr/bin:$ENV{'PATH'}";
+}
+
+sub Exit {
+ unlink($tmp) if $tmp ne ""; # unlink if a filename
+ die "$0: die on signal SIG@_\n";
+}
+
+sub parse {
+ local(@argv) = @_;
+ local($i);
+
+ while ($_ = $argv[0], /^-/) {
+ shift @argv;
+ last if /^--$/;
+ if (/^--?(v|verbose)$/) { $verbose = 1 }
+ elsif (/^--?(h|help|\?)$/) { &usage }
+ elsif (/^--?(o|outfile)$/) { $outfile = $argv[0]; shift @argv }
+ elsif (/^--?(f|format|i|indent)$/) { $i = $argv[0]; shift @argv }
+ elsif (/^--?(n|name)$/) { $whatis_name = $argv[0];shift @argv }
+ else { &usage }
+ }
+
+ if ($i ne "") {
+ if ($i =~ /^[0-9]+$/) {
+ $indent = $i;
+ } else {
+ warn "Ignoring wrong indent value: ``$i''\n";
+ }
+ }
+
+ return &absolute_path(@argv) if $#argv >= 0;
+ return @defaultmanpath if $#defaultmanpath >= 0;
+
+ warn "Missing directories\n"; &usage;
+}
+
+
+##
+## Main
+##
+
+&variables;
+# allow colons in dir: ``makewhatis dir1:dir2:dir3''
+@argv = &parse(split(/[: ]/, join($", @ARGV))); # "
+
+
+if ($outfile) {
+ if(&open_output($outfile)){
+ foreach $dir (@argv) {
+ $dir = &stripdir($dir);
+ &dir_redundant($dir) && &parse_dir($dir);
+ }
+ }
+ &close_output(1);
+} else {
+ foreach $dir (@argv) {
+ $dir = &stripdir($dir);
+ &dir_redundant($dir) &&
+ &close_output(&open_output($dir) && &parse_dir($dir));
+ }
+}
+
+warn "Total entries: $counter_all\n" if $verbose && ($#argv > 0 || $outfile);
+exit $err;
diff --git a/gnu/usr.bin/man/man/Makefile b/gnu/usr.bin/man/man/Makefile
new file mode 100644
index 0000000..daab3c2
--- /dev/null
+++ b/gnu/usr.bin/man/man/Makefile
@@ -0,0 +1,33 @@
+PROG= man
+SRCS= man.c manpath.c glob.c
+BINMODE=4555
+BINOWN= man
+
+.if exists(${.CURDIR}/../lib/obj)
+LDADD= -L${.CURDIR}/../lib/obj -lman
+CFLAGS+= -I${.CURDIR}/../lib/obj
+.else
+LDADD= -L${.CURDIR}/../lib/ -lman
+.endif
+
+.if exists(${.CURDIR}/obj)
+MAN1= ${.CURDIR}/obj/man.1
+.else
+MAN1= ${.CURDIR}/man.1
+.endif
+
+DPADD+= ${MAN1}
+CFLAGS+= -I${.CURDIR}/../lib -DSTDC_HEADERS -DPOSIX -DHAS_TROFF
+CFLAGS+= -DDO_COMPRESS -DALT_SYSTEMS -DSETREUID -DCATMODE=0664
+CLEANFILES+= ${MAN1}
+MANDEPEND+= ${MAN1}
+
+${MAN1}: ${.CURDIR}/man.man
+ @echo Making ${.TARGET:T} from ${.ALLSRC:T}; \
+ sed -e 's,%libdir%,${libdir},' -e 's,%bindir%,${bindir},' \
+ -e 's,%pager%,${pager},' -e 's,%troff%,${troff},' \
+ -e 's,%manpath_config_file%,${manpath_config_file},' \
+ -e 's,%compress%,${compress},' \
+ ${.CURDIR}/man.man > ${MAN1}
+
+.include <bsd.prog.mk>
diff --git a/gnu/usr.bin/man/man/glob.c b/gnu/usr.bin/man/man/glob.c
new file mode 100644
index 0000000..ba4be06
--- /dev/null
+++ b/gnu/usr.bin/man/man/glob.c
@@ -0,0 +1,689 @@
+/* File-name wildcard pattern matching for GNU.
+ Copyright (C) 1985, 1988, 1989, 1990, 1991 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 1, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* To whomever it may concern: I have never seen the code which most
+ Unix programs use to perform this function. I wrote this from scratch
+ based on specifications for the pattern matching. --RMS. */
+
+#ifdef SHELL
+#include "config.h"
+#endif /* SHELL */
+
+#include <sys/types.h>
+
+#if defined (USGr3) && !defined (DIRENT)
+#define DIRENT
+#endif /* USGr3 */
+#if defined (Xenix) && !defined (SYSNDIR)
+#define SYSNDIR
+#endif /* Xenix */
+
+#if defined (POSIX) || defined (DIRENT) || defined (__GNU_LIBRARY__)
+#include <dirent.h>
+#define direct dirent
+#define D_NAMLEN(d) strlen((d)->d_name)
+#else /* not POSIX or DIRENT or __GNU_LIBRARY__ */
+#define D_NAMLEN(d) ((d)->d_namlen)
+#ifdef USG
+#if defined (SYSNDIR)
+#include <sys/ndir.h>
+#else /* SYSNDIR */
+#include "ndir.h"
+#endif /* not SYSNDIR */
+#else /* not USG */
+#include <sys/dir.h>
+#endif /* USG */
+#endif /* POSIX or DIRENT or __GNU_LIBRARY__ */
+
+#if defined (_POSIX_SOURCE)
+/* Posix does not require that the d_ino field be present, and some
+ systems do not provide it. */
+#define REAL_DIR_ENTRY(dp) 1
+#else
+#define REAL_DIR_ENTRY(dp) (dp->d_ino != 0)
+#endif /* _POSIX_SOURCE */
+
+#if defined (STDC_HEADERS) || defined (__GNU_LIBRARY__)
+#include <stdlib.h>
+#include <string.h>
+#define STDC_STRINGS
+#else /* STDC_HEADERS or __GNU_LIBRARY__ */
+
+#if defined (USG)
+#include <string.h>
+#ifndef POSIX
+#include <memory.h>
+#endif /* POSIX */
+#define STDC_STRINGS
+#else /* not USG */
+#ifdef NeXT
+#include <string.h>
+#else /* NeXT */
+#include <strings.h>
+#endif /* NeXT */
+/* Declaring bcopy causes errors on systems whose declarations are different.
+ If the declaration is omitted, everything works fine. */
+#endif /* not USG */
+
+extern char *malloc ();
+extern char *realloc ();
+extern void free ();
+
+#ifndef NULL
+#define NULL 0
+#endif
+#endif /* Not STDC_HEADERS or __GNU_LIBRARY__. */
+
+#ifdef STDC_STRINGS
+#define bcopy(s, d, n) memcpy ((d), (s), (n))
+#define index strchr
+#define rindex strrchr
+#endif /* STDC_STRINGS */
+
+#ifndef alloca
+#ifdef __GNUC__
+#define alloca __builtin_alloca
+#else /* Not GCC. */
+#ifdef sparc
+#include <alloca.h>
+#else /* Not sparc. */
+extern char *alloca ();
+#endif /* sparc. */
+#endif /* GCC. */
+#endif
+
+/* Nonzero if '*' and '?' do not match an initial '.' for glob_filename. */
+int noglob_dot_filenames = 1;
+
+static int glob_match_after_star ();
+
+/* Return nonzero if PATTERN has any special globbing chars in it. */
+
+int
+glob_pattern_p (pattern)
+ char *pattern;
+{
+ register char *p = pattern;
+ register char c;
+ int open = 0;
+
+ while ((c = *p++) != '\0')
+ switch (c)
+ {
+ case '?':
+ case '*':
+ return 1;
+
+ case '[': /* Only accept an open brace if there is a close */
+ open++; /* brace to match it. Bracket expressions must be */
+ continue; /* complete, according to Posix.2 */
+ case ']':
+ if (open)
+ return 1;
+ continue;
+
+ case '\\':
+ if (*p++ == '\0')
+ return 0;
+ }
+
+ return 0;
+}
+
+
+/* Match the pattern PATTERN against the string TEXT;
+ return 1 if it matches, 0 otherwise.
+
+ A match means the entire string TEXT is used up in matching.
+
+ In the pattern string, `*' matches any sequence of characters,
+ `?' matches any character, [SET] matches any character in the specified set,
+ [!SET] matches any character not in the specified set.
+
+ A set is composed of characters or ranges; a range looks like
+ character hyphen character (as in 0-9 or A-Z).
+ [0-9a-zA-Z_] is the set of characters allowed in C identifiers.
+ Any other character in the pattern must be matched exactly.
+
+ To suppress the special syntactic significance of any of `[]*?!-\',
+ and match the character exactly, precede it with a `\'.
+
+ If DOT_SPECIAL is nonzero,
+ `*' and `?' do not match `.' at the beginning of TEXT. */
+
+int
+glob_match (pattern, text, dot_special)
+ char *pattern, *text;
+ int dot_special;
+{
+ register char *p = pattern, *t = text;
+ register char c;
+
+ while ((c = *p++) != '\0')
+ switch (c)
+ {
+ case '?':
+ if (*t == '\0' || (dot_special && t == text && *t == '.'))
+ return 0;
+ else
+ ++t;
+ break;
+
+ case '\\':
+ if (*p++ != *t++)
+ return 0;
+ break;
+
+ case '*':
+ if (dot_special && t == text && *t == '.')
+ return 0;
+ return glob_match_after_star (p, t);
+
+ case '[':
+ {
+ register char c1 = *t++;
+ int invert;
+ char *cp1 = p;
+
+ if (c1 == '\0')
+ return 0;
+
+ invert = (*p == '!');
+
+ if (invert)
+ p++;
+
+ c = *p++;
+ while (1)
+ {
+ register char cstart = c, cend = c;
+
+ if (c == '\\')
+ {
+ cstart = *p++;
+ cend = cstart;
+ }
+
+ if (cstart == '\0')
+ {
+ /* Missing ']'. */
+ if (c1 != '[')
+ return 0;
+ /* matched a single bracket */
+ p = cp1;
+ goto breakbracket;
+ }
+
+ c = *p++;
+
+ if (c == '-')
+ {
+ cend = *p++;
+ if (cend == '\\')
+ cend = *p++;
+ if (cend == '\0')
+ return 0;
+ c = *p++;
+ }
+ if (c1 >= cstart && c1 <= cend)
+ goto match;
+ if (c == ']')
+ break;
+ }
+ if (!invert)
+ return 0;
+ break;
+
+ match:
+ /* Skip the rest of the [...] construct that already matched. */
+ while (c != ']')
+ {
+ if (c == '\0')
+ return 0;
+ c = *p++;
+ if (c == '\0')
+ return 0;
+ if (c == '\\')
+ p++;
+ }
+ if (invert)
+ return 0;
+ breakbracket:
+ break;
+ }
+
+ default:
+ if (c != *t++)
+ return 0;
+ }
+
+ return *t == '\0';
+}
+
+/* Like glob_match, but match PATTERN against any final segment of TEXT. */
+
+static int
+glob_match_after_star (pattern, text)
+ char *pattern, *text;
+{
+ register char *p = pattern, *t = text;
+ register char c, c1;
+
+ while ((c = *p++) == '?' || c == '*')
+ if (c == '?' && *t++ == '\0')
+ return 0;
+
+ if (c == '\0')
+ return 1;
+
+ if (c == '\\')
+ c1 = *p;
+ else
+ c1 = c;
+
+ --p;
+ while (1)
+ {
+ if ((c == '[' || *t == c1) && glob_match (p, t, 0))
+ return 1;
+ if (*t++ == '\0')
+ return 0;
+ }
+}
+
+/* Return a vector of names of files in directory DIR
+ whose names match glob pattern PAT.
+ The names are not in any particular order.
+ Wildcards at the beginning of PAT do not match an initial period
+ if noglob_dot_filenames is nonzero.
+
+ The vector is terminated by an element that is a null pointer.
+
+ To free the space allocated, first free the vector's elements,
+ then free the vector.
+
+ Return NULL if cannot get enough memory to hold the pointer
+ and the names.
+
+ Return -1 if cannot access directory DIR.
+ Look in errno for more information. */
+
+char **
+glob_vector (pat, dir)
+ char *pat;
+ char *dir;
+{
+ struct globval
+ {
+ struct globval *next;
+ char *name;
+ };
+
+ DIR *d;
+ register struct direct *dp;
+ struct globval *lastlink;
+ register struct globval *nextlink;
+ register char *nextname;
+ unsigned int count;
+ int lose;
+ register char **name_vector;
+ register unsigned int i;
+#ifdef ALLOCA_MISSING
+ struct globval *templink;
+#endif
+
+ d = opendir (dir);
+ if (d == NULL)
+ return (char **) -1;
+
+ lastlink = NULL;
+ count = 0;
+ lose = 0;
+
+ /* Scan the directory, finding all names that match.
+ For each name that matches, allocate a struct globval
+ on the stack and store the name in it.
+ Chain those structs together; lastlink is the front of the chain. */
+ while (1)
+ {
+#if defined (SHELL)
+ /* Make globbing interruptible in the bash shell. */
+ extern int interrupt_state;
+
+ if (interrupt_state)
+ {
+ closedir (d);
+ lose = 1;
+ goto lost;
+ }
+#endif /* SHELL */
+
+ dp = readdir (d);
+ if (dp == NULL)
+ break;
+ if (REAL_DIR_ENTRY (dp)
+ && glob_match (pat, dp->d_name, noglob_dot_filenames))
+ {
+#ifdef ALLOCA_MISSING
+ nextlink = (struct globval *) malloc (sizeof (struct globval));
+#else
+ nextlink = (struct globval *) alloca (sizeof (struct globval));
+#endif
+ nextlink->next = lastlink;
+ i = D_NAMLEN (dp) + 1;
+ nextname = (char *) malloc (i);
+ if (nextname == NULL)
+ {
+ lose = 1;
+ break;
+ }
+ lastlink = nextlink;
+ nextlink->name = nextname;
+ bcopy (dp->d_name, nextname, i);
+ count++;
+ }
+ }
+ closedir (d);
+
+ if (!lose)
+ {
+ name_vector = (char **) malloc ((count + 1) * sizeof (char *));
+ lose |= name_vector == NULL;
+ }
+
+ /* Have we run out of memory? */
+#ifdef SHELL
+ lost:
+#endif
+ if (lose)
+ {
+ /* Here free the strings we have got. */
+ while (lastlink)
+ {
+ free (lastlink->name);
+#ifdef ALLOCA_MISSING
+ templink = lastlink->next;
+ free ((char *) lastlink);
+ lastlink = templink;
+#else
+ lastlink = lastlink->next;
+#endif
+ }
+ return NULL;
+ }
+
+ /* Copy the name pointers from the linked list into the vector. */
+ for (i = 0; i < count; ++i)
+ {
+ name_vector[i] = lastlink->name;
+#ifdef ALLOCA_MISSING
+ templink = lastlink->next;
+ free ((char *) lastlink);
+ lastlink = templink;
+#else
+ lastlink = lastlink->next;
+#endif
+ }
+
+ name_vector[count] = NULL;
+ return name_vector;
+}
+
+/* Return a new array, replacing ARRAY, which is the concatenation
+ of each string in ARRAY to DIR.
+ Return NULL if out of memory. */
+
+static char **
+glob_dir_to_array (dir, array)
+ char *dir, **array;
+{
+ register unsigned int i, l;
+ int add_slash = 0;
+ char **result;
+
+ l = strlen (dir);
+ if (l == 0)
+ return array;
+
+ if (dir[l - 1] != '/')
+ add_slash++;
+
+ for (i = 0; array[i] != NULL; i++)
+ ;
+
+ result = (char **) malloc ((i + 1) * sizeof (char *));
+ if (result == NULL)
+ return NULL;
+
+ for (i = 0; array[i] != NULL; i++)
+ {
+ result[i] = (char *) malloc (1 + l + add_slash + strlen (array[i]));
+ if (result[i] == NULL)
+ return NULL;
+ strcpy (result[i], dir);
+ if (add_slash)
+ result[i][l] = '/';
+ strcpy (result[i] + l + add_slash, array[i]);
+ }
+ result[i] = NULL;
+
+ /* Free the input array. */
+ for (i = 0; array[i] != NULL; i++)
+ free (array[i]);
+ free ((char *) array);
+ return result;
+}
+
+/* Do globbing on PATHNAME. Return an array of pathnames that match,
+ marking the end of the array with a null-pointer as an element.
+ If no pathnames match, then the array is empty (first element is null).
+ If there isn't enough memory, then return NULL.
+ If a file system error occurs, return -1; `errno' has the error code.
+
+ Wildcards at the beginning of PAT, or following a slash,
+ do not match an initial period if noglob_dot_filenames is nonzero. */
+
+char **
+glob_filename (pathname)
+ char *pathname;
+{
+ char **result;
+ unsigned int result_size;
+ char *directory_name, *filename;
+ unsigned int directory_len;
+
+ result = (char **) malloc (sizeof (char *));
+ result_size = 1;
+ if (result == NULL)
+ return NULL;
+
+ result[0] = NULL;
+
+ /* Find the filename. */
+ filename = rindex (pathname, '/');
+ if (filename == NULL)
+ {
+ filename = pathname;
+ directory_name = "";
+ directory_len = 0;
+ }
+ else
+ {
+ directory_len = (filename - pathname) + 1;
+#ifdef ALLOCA_MISSING
+ directory_name = (char *) malloc (directory_len + 1);
+#else
+ directory_name = (char *) alloca (directory_len + 1);
+#endif
+ bcopy (pathname, directory_name, directory_len);
+ directory_name[directory_len] = '\0';
+ ++filename;
+ }
+
+ /* If directory_name contains globbing characters, then we
+ have to expand the previous levels. Just recurse. */
+ if (glob_pattern_p (directory_name))
+ {
+ char **directories;
+ register unsigned int i;
+
+ if (directory_name[directory_len - 1] == '/')
+ directory_name[directory_len - 1] = '\0';
+
+ directories = glob_filename (directory_name);
+#ifdef ALLOCA_MISSING
+ free ((char *) directory_name);
+#endif
+ if (directories == NULL)
+ goto memory_error;
+ else if (directories == (char **) -1)
+ return (char **) -1;
+ else if (*directories == NULL)
+ {
+ free ((char *) directories);
+ return (char **) -1;
+ }
+
+ /* We have successfully globbed the preceding directory name.
+ For each name in DIRECTORIES, call glob_vector on it and
+ FILENAME. Concatenate the results together. */
+ for (i = 0; directories[i] != NULL; i++)
+ {
+ char **temp_results = glob_vector (filename, directories[i]);
+ if (temp_results == NULL)
+ goto memory_error;
+ else if (temp_results == (char **) -1)
+ /* This filename is probably not a directory. Ignore it. */
+ ;
+ else
+ {
+ char **array = glob_dir_to_array (directories[i], temp_results);
+ register unsigned int l;
+
+ l = 0;
+ while (array[l] != NULL)
+ ++l;
+
+ result = (char **) realloc (result,
+ (result_size + l) * sizeof (char *));
+ if (result == NULL)
+ goto memory_error;
+
+ for (l = 0; array[l] != NULL; ++l)
+ result[result_size++ - 1] = array[l];
+ result[result_size - 1] = NULL;
+ free ((char *) array);
+ }
+ }
+ /* Free the directories. */
+ for (i = 0; directories[i] != NULL; i++)
+ free (directories[i]);
+ free ((char *) directories);
+
+ return result;
+ }
+
+ /* If there is only a directory name, return it. */
+ if (*filename == '\0')
+ {
+ result = (char **) realloc ((char *) result, 2 * sizeof (char *));
+ if (result != NULL)
+ {
+ result[0] = (char *) malloc (directory_len + 1);
+ if (result[0] == NULL)
+ {
+#ifdef ALLOCA_MISSING
+ free ((char *) directory_name);
+#endif
+ goto memory_error;
+ }
+ bcopy (directory_name, result[0], directory_len + 1);
+ result[1] = NULL;
+ }
+#ifdef ALLOCA_MISSING
+ free ((char *) directory_name);
+#endif
+ return result;
+ }
+ else
+ {
+ /* Otherwise, just return what glob_vector
+ returns appended to the directory name. */
+ char **temp_results = glob_vector (filename,
+ (directory_len == 0
+ ? "." : directory_name));
+
+ if (temp_results == NULL || temp_results == (char **) -1)
+ {
+#ifdef NO_ALLOCA
+ free ((char *) directory_name);
+#endif
+ return temp_results;
+ }
+
+ temp_results = glob_dir_to_array (directory_name, temp_results);
+#ifdef NO_ALLOCA
+ free ((char *) directory_name);
+#endif
+ return temp_results;
+ }
+
+ /* We get to memory error if the program has run out of memory, or
+ if this is the shell, and we have been interrupted. */
+ memory_error:
+ if (result != NULL)
+ {
+ register unsigned int i;
+ for (i = 0; result[i] != NULL; ++i)
+ free (result[i]);
+ free ((char *) result);
+ }
+#if defined (SHELL)
+ {
+ extern int interrupt_state;
+
+ if (interrupt_state)
+ throw_to_top_level ();
+ }
+#endif /* SHELL */
+ return NULL;
+}
+
+#ifdef TEST
+
+main (argc, argv)
+ int argc;
+ char **argv;
+{
+ char **value;
+ int i, optind;
+
+ for (optind = 1; optind < argc; optind++)
+ {
+ value = glob_filename (argv[optind]);
+ if (value == NULL)
+ puts ("virtual memory exhausted");
+ else if (value == (char **) -1)
+ perror (argv[optind]);
+ else
+ for (i = 0; value[i] != NULL; i++)
+ puts (value[i]);
+ }
+ exit (0);
+}
+
+#endif /* TEST */
diff --git a/gnu/usr.bin/man/man/man.c b/gnu/usr.bin/man/man/man.c
new file mode 100644
index 0000000..2823e23
--- /dev/null
+++ b/gnu/usr.bin/man/man/man.c
@@ -0,0 +1,1432 @@
+/*
+ * man.c
+ *
+ * Copyright (c) 1990, 1991, John W. Eaton.
+ *
+ * You may distribute under the terms of the GNU General Public
+ * License as specified in the file COPYING that comes with the man
+ * distribution.
+ *
+ * John W. Eaton
+ * jwe@che.utexas.edu
+ * Department of Chemical Engineering
+ * The University of Texas at Austin
+ * Austin, Texas 78712
+ */
+
+#define MAN_MAIN
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+#include <sys/file.h>
+#include <signal.h>
+#include "config.h"
+#include "gripes.h"
+#include "version.h"
+
+#ifndef POSIX
+#include <unistd.h>
+#else
+#ifndef R_OK
+#define R_OK 4
+#endif
+#endif
+
+#ifdef SECURE_MAN_UID
+extern uid_t getuid ();
+extern int setuid ();
+#endif
+
+#ifdef STDC_HEADERS
+#include <stdlib.h>
+#else
+extern char *malloc ();
+extern char *getenv ();
+extern void free ();
+extern int system ();
+extern int strcmp ();
+extern int strncmp ();
+extern int exit ();
+extern int fflush ();
+extern int printf ();
+extern int fprintf ();
+extern FILE *fopen ();
+extern int fclose ();
+extern char *sprintf ();
+#endif
+
+extern char *strdup ();
+
+extern char **glob_vector ();
+extern char **glob_filename ();
+extern int access ();
+extern int unlink ();
+extern int system ();
+extern int chmod ();
+extern int is_newer ();
+extern int is_directory ();
+extern int do_system_command ();
+
+char *prognam;
+static char *pager;
+static char *manp;
+static char *manpathlist[MAXDIRS];
+static char *section;
+static char *colon_sep_section_list;
+static char **section_list;
+static char *roff_directive;
+static int apropos;
+static int whatis;
+static int findall;
+static int print_where;
+
+#ifdef ALT_SYSTEMS
+static int alt_system;
+static char *alt_system_name;
+#endif
+
+static int troff = 0;
+
+int debug;
+
+#ifdef HAS_TROFF
+#ifdef ALT_SYSTEMS
+static char args[] = "M:P:S:adfhkm:p:tw?";
+#else
+static char args[] = "M:P:S:adfhkp:tw?";
+#endif
+#else
+#ifdef ALT_SYSTEMS
+static char args[] = "M:P:S:adfhkm:p:w?";
+#else
+static char args[] = "M:P:S:adfhkp:w?";
+#endif
+#endif
+
+#ifdef SETREUID
+uid_t ruid;
+uid_t euid;
+uid_t rgid;
+uid_t egid;
+#endif
+
+int
+main (argc, argv)
+ int argc;
+ char **argv;
+{
+ int status = 0;
+ char *nextarg;
+ char *tmp;
+ extern int optind;
+ extern char *mkprogname ();
+ char *is_section ();
+ char **get_section_list ();
+ void man_getopt ();
+ void do_apropos ();
+ void do_whatis ();
+ int man ();
+
+ prognam = mkprogname (argv[0]);
+
+ man_getopt (argc, argv);
+
+ if (optind == argc)
+ gripe_no_name ((char *)NULL);
+
+ section_list = get_section_list ();
+
+ if (optind == argc - 1)
+ {
+ tmp = is_section (argv[optind]);
+
+ if (tmp != NULL)
+ gripe_no_name (tmp);
+ }
+
+#ifdef SETREUID
+ ruid = getuid();
+ rgid = getgid();
+ euid = geteuid();
+ egid = getegid();
+ setreuid(-1, ruid);
+ setregid(-1, rgid);
+#endif
+
+ while (optind < argc)
+ {
+ nextarg = argv[optind++];
+
+ /*
+ * See if this argument is a valid section name. If not,
+ * is_section returns NULL.
+ */
+ tmp = is_section (nextarg);
+
+ if (tmp != NULL)
+ {
+ section = tmp;
+
+ if (debug)
+ fprintf (stderr, "\nsection: %s\n", section);
+
+ continue;
+ }
+
+ if (apropos)
+ do_apropos (nextarg);
+ else if (whatis)
+ do_whatis (nextarg);
+ else
+ {
+ status = man (nextarg);
+
+ if (status == 0)
+ gripe_not_found (nextarg, section);
+ }
+ }
+ return (status==0); /* status==1 --> exit(0),
+ status==0 --> exit(1) */
+}
+
+void
+usage ()
+{
+ static char usage_string[1024] = "%s, version %s\n\n";
+
+#ifdef HAS_TROFF
+#ifdef ALT_SYSTEMS
+ static char s1[] =
+ "usage: %s [-adfhktw] [section] [-M path] [-P pager] [-S list]\n\
+ [-m system] [-p string] name ...\n\n";
+#else
+ static char s1[] =
+ "usage: %s [-adfhktw] [section] [-M path] [-P pager] [-S list]\n\
+ [-p string] name ...\n\n";
+#endif
+#else
+#ifdef ALT_SYSTEMS
+ static char s1[] =
+ "usage: %s [-adfhkw] [section] [-M path] [-P pager] [-S list]\n\
+ [-m system] [-p string] name ...\n\n";
+#else
+ static char s1[] =
+ "usage: %s [-adfhkw] [section] [-M path] [-P pager] [-S list]\n\
+ [-p string] name ...\n\n";
+#endif
+#endif
+
+static char s2[] = " a : find all matching entries\n\
+ d : print gobs of debugging information\n\
+ f : same as whatis(1)\n\
+ h : print this help message\n\
+ k : same as apropos(1)\n";
+
+#ifdef HAS_TROFF
+ static char s3[] = " t : use troff to format pages for printing\n";
+#endif
+
+ static char s4[] = " w : print location of man page(s) that would be displayed\n\n\
+ M path : set search path for manual pages to `path'\n\
+ P pager : use program `pager' to display pages\n\
+ S list : colon separated section list\n";
+
+#ifdef ALT_SYSTEMS
+ static char s5[] = " m system : search for alternate system's man pages\n";
+#endif
+
+ static char s6[] = " p string : string tells which preprocessors to run\n\
+ e - [n]eqn(1) p - pic(1) t - tbl(1)\n\
+ g - grap(1) r - refer(1) v - vgrind(1)\n";
+
+ strcat (usage_string, s1);
+ strcat (usage_string, s2);
+
+#ifdef HAS_TROFF
+ strcat (usage_string, s3);
+#endif
+
+ strcat (usage_string, s4);
+
+#ifdef ALT_SYSTEMS
+ strcat (usage_string, s5);
+#endif
+
+ strcat (usage_string, s6);
+
+ fprintf (stderr, usage_string, prognam, version, prognam);
+ exit(1);
+}
+
+char **
+add_dir_to_mpath_list (mp, p)
+ char **mp;
+ char *p;
+{
+ int status;
+
+ status = is_directory (p);
+
+ if (status < 0 && debug)
+ {
+ fprintf (stderr, "Warning: couldn't stat file %s!\n", p);
+ }
+ else if (status == 0 && debug)
+ {
+ fprintf (stderr, "Warning: %s isn't a directory!\n", p);
+ }
+ else if (status == 1)
+ {
+ if (debug)
+ fprintf (stderr, "adding %s to manpathlist\n", p);
+
+ *mp++ = strdup (p);
+ }
+ return mp;
+}
+
+/*
+ * Get options from the command line and user environment.
+ */
+void
+man_getopt (argc, argv)
+ register int argc;
+ register char **argv;
+{
+ register int c;
+ register char *p;
+ register char *end;
+ register char **mp;
+ extern char *optarg;
+ extern int getopt ();
+ extern void downcase ();
+ extern char *manpath ();
+
+ while ((c = getopt (argc, argv, args)) != EOF)
+ {
+ switch (c)
+ {
+ case 'M':
+ manp = strdup (optarg);
+ break;
+ case 'P':
+ pager = strdup (optarg);
+ break;
+ case 'S':
+ colon_sep_section_list = strdup (optarg);
+ break;
+ case 'a':
+ findall++;
+ break;
+ case 'd':
+ debug++;
+ break;
+ case 'f':
+ if (troff)
+ gripe_incompatible ("-f and -t");
+ if (apropos)
+ gripe_incompatible ("-f and -k");
+ if (print_where)
+ gripe_incompatible ("-f and -w");
+ whatis++;
+ break;
+ case 'k':
+ if (troff)
+ gripe_incompatible ("-k and -t");
+ if (whatis)
+ gripe_incompatible ("-k and -f");
+ if (print_where)
+ gripe_incompatible ("-k and -w");
+ apropos++;
+ break;
+#ifdef ALT_SYSTEMS
+ case 'm':
+ alt_system++;
+ alt_system_name = strdup (optarg);
+ break;
+#endif
+ case 'p':
+ roff_directive = strdup (optarg);
+ break;
+#ifdef HAS_TROFF
+ case 't':
+ if (apropos)
+ gripe_incompatible ("-t and -k");
+ if (whatis)
+ gripe_incompatible ("-t and -f");
+ if (print_where)
+ gripe_incompatible ("-t and -w");
+ troff++;
+ break;
+#endif
+ case 'w':
+ if (apropos)
+ gripe_incompatible ("-w and -k");
+ if (whatis)
+ gripe_incompatible ("-w and -f");
+ if (troff)
+ gripe_incompatible ("-w and -t");
+ print_where++;
+ break;
+ case 'h':
+ case '?':
+ default:
+ usage();
+ break;
+ }
+ }
+
+ if (pager == NULL || *pager == '\0')
+ if ((pager = getenv ("PAGER")) == NULL)
+ pager = strdup (PAGER);
+
+ if (debug)
+ fprintf (stderr, "\nusing %s as pager\n", pager);
+
+ if (manp == NULL)
+ {
+ if ((manp = manpath (0)) == NULL)
+ gripe_manpath ();
+
+ if (debug)
+ fprintf (stderr,
+ "\nsearch path for pages determined by manpath is\n%s\n\n",
+ manp);
+ }
+
+#ifdef ALT_SYSTEMS
+ if (alt_system_name == NULL || *alt_system_name == '\0')
+ if ((alt_system_name = getenv ("SYSTEM")) != NULL)
+ alt_system_name = strdup (alt_system_name);
+
+ if (alt_system_name != NULL && *alt_system_name != '\0')
+ downcase (alt_system_name);
+#endif
+
+ /*
+ * Expand the manpath into a list for easier handling.
+ */
+ mp = manpathlist;
+ for (p = manp; ; p = end+1)
+ {
+ if ((end = strchr (p, ':')) != NULL)
+ *end = '\0';
+
+#ifdef ALT_SYSTEMS
+ if (alt_system)
+ {
+ char buf[FILENAME_MAX];
+
+ if (debug)
+ fprintf (stderr, "Alternate system `%s' specified\n",
+ alt_system_name);
+
+ strcpy (buf, p);
+ strcat (buf, "/");
+ strcat (buf, alt_system_name);
+
+ mp = add_dir_to_mpath_list (mp, buf);
+ }
+ else
+ {
+ mp = add_dir_to_mpath_list (mp, p);
+ }
+#else
+ mp = add_dir_to_mpath_list (mp, p);
+#endif
+ if (end == NULL)
+ break;
+
+ *end = ':';
+ }
+ *mp = NULL;
+}
+
+/*
+ * Check to see if the argument is a valid section number. If the
+ * first character of name is a numeral, or the name matches one of
+ * the sections listed in section_list, we'll assume that it's a section.
+ * The list of sections in config.h simply allows us to specify oddly
+ * named directories like .../man3f. Yuk.
+ */
+char *
+is_section (name)
+ register char *name;
+{
+ register char **vs;
+
+ for (vs = section_list; *vs != NULL; vs++)
+ if ((strcmp (*vs, name) == NULL)
+ || (isdigit (name[0]) && strlen(name) == 1))
+ return strdup (name);
+
+ return NULL;
+}
+
+/*
+ * Handle the apropos option. Cheat by using another program.
+ */
+void
+do_apropos (name)
+ register char *name;
+{
+ register int len;
+ register char *command;
+
+ len = strlen (APROPOS) + strlen (name) + 2;
+
+ if ((command = (char *) malloc(len)) == NULL)
+ gripe_alloc (len, "command");
+
+ sprintf (command, "%s %s", APROPOS, name);
+
+ (void) do_system_command (command);
+
+ free (command);
+}
+
+/*
+ * Handle the whatis option. Cheat by using another program.
+ */
+void
+do_whatis (name)
+ register char *name;
+{
+ register int len;
+ register char *command;
+
+ len = strlen (WHATIS) + strlen (name) + 2;
+
+ if ((command = (char *) malloc(len)) == NULL)
+ gripe_alloc (len, "command");
+
+ sprintf (command, "%s %s", WHATIS, name);
+
+ (void) do_system_command (command);
+
+ free (command);
+}
+
+/*
+ * Change a name of the form ...man/man1/name.1 to ...man/cat1/name.1
+ * or a name of the form ...man/cat1/name.1 to ...man/man1/name.1
+ */
+char *
+convert_name (name, to_cat)
+ register char *name;
+ register int to_cat;
+{
+ register char *to_name;
+ register char *t1;
+ register char *t2 = NULL;
+
+#ifdef DO_COMPRESS
+ if (to_cat)
+ {
+ int len = strlen (name) + 3;
+ int cextlen = strlen(COMPRESS_EXT);
+
+ to_name = (char *) malloc (len);
+ if (to_name == NULL)
+ gripe_alloc (len, "to_name");
+ strcpy (to_name, name);
+ /* Avoid tacking it on twice */
+ if (strcmp(name + (len - (3 + cextlen)), COMPRESS_EXT))
+ strcat (to_name, COMPRESS_EXT);
+ }
+ else
+ to_name = strdup (name);
+#else
+ to_name = strdup (name);
+#endif
+
+ t1 = strrchr (to_name, '/');
+ if (t1 != NULL)
+ {
+ *t1 = NULL;
+ t2 = strrchr (to_name, '/');
+ *t1 = '/';
+ }
+
+ if (t2 == NULL)
+ gripe_converting_name (name, to_cat);
+
+ if (to_cat)
+ {
+ *(++t2) = 'c';
+ *(t2+2) = 't';
+ }
+ else
+ {
+ *(++t2) = 'm';
+ *(t2+2) = 'n';
+ }
+
+ if (debug)
+ fprintf (stderr, "to_name in convert_name () is: %s\n", to_name);
+
+ return to_name;
+}
+
+/*
+ * Try to find the man page corresponding to the given name. The
+ * reason we do this with globbing is because some systems have man
+ * page directories named man3 which contain files with names like
+ * XtPopup.3Xt. Rather than requiring that this program know about
+ * all those possible names, we simply try to match things like
+ * .../man[sect]/name[sect]*. This is *much* easier.
+ *
+ * Note that globbing is only done when the section is unspecified.
+ */
+char **
+glob_for_file (path, section, name, cat)
+ register char *path;
+ register char *section;
+ register char *name;
+ register int cat;
+{
+ char pathname[FILENAME_MAX];
+ char **gf;
+
+ if (cat)
+ sprintf (pathname, "%s/cat%s/%s.%s*", path, section, name, section);
+ else
+ sprintf (pathname, "%s/man%s/%s.%s*", path, section, name, section);
+
+ if (debug)
+ fprintf (stderr, "globbing %s\n", pathname);
+
+ gf = glob_filename (pathname);
+
+ if ((gf == (char **) -1 || *gf == NULL) && isdigit (*section))
+ {
+ if (cat)
+ sprintf (pathname, "%s/cat%s/%s.%c*", path, section, name, *section);
+ else
+ sprintf (pathname, "%s/man%s/%s.%c*", path, section, name, *section);
+
+ gf = glob_filename (pathname);
+ }
+ if ((gf == (char **) -1 || *gf == NULL) && isdigit (*section))
+ {
+ if (cat)
+ sprintf (pathname, "%s/cat%s/%s.0*", path, section, name);
+ else
+ sprintf (pathname, "%s/man%s/%s.0*", path, section, name);
+ if (debug)
+ fprintf (stderr, "globbing %s\n", pathname);
+ gf = glob_filename (pathname);
+ }
+ return gf;
+}
+
+/*
+ * Return an un-globbed name in the same form as if we were doing
+ * globbing.
+ */
+char **
+make_name (path, section, name, cat)
+ register char *path;
+ register char *section;
+ register char *name;
+ register int cat;
+{
+ register int i = 0;
+ static char *names[3];
+ char buf[FILENAME_MAX];
+
+ if (cat)
+ sprintf (buf, "%s/cat%s/%s.%s", path, section, name, section);
+ else
+ sprintf (buf, "%s/man%s/%s.%s", path, section, name, section);
+
+ if (access (buf, R_OK) == 0)
+ names[i++] = strdup (buf);
+
+ /*
+ * If we're given a section that looks like `3f', we may want to try
+ * file names like .../man3/foo.3f as well. This seems a bit
+ * kludgey to me, but what the hey...
+ */
+ if (section[1] != '\0')
+ {
+ if (cat)
+ sprintf (buf, "%s/cat%c/%s.%s", path, section[0], name, section);
+ else
+ sprintf (buf, "%s/man%c/%s.%s", path, section[0], name, section);
+
+ if (access (buf, R_OK) == 0)
+ names[i++] = strdup (buf);
+ }
+
+ names[i] = NULL;
+
+ return &names[0];
+}
+
+char *
+get_expander (file)
+ char *file;
+{
+ char *end = file + (strlen (file) - 1);
+
+ while (end > file && end[-1] != '.')
+ --end;
+ if (end == file)
+ return NULL;
+#ifdef FCAT
+ if (*end == 'F')
+ return FCAT;
+#endif /* FCAT */
+#ifdef YCAT
+ if (*end == 'Y')
+ return YCAT;
+#endif /* YCAT */
+#ifdef ZCAT
+ if (*end == 'Z' || !strcmp(end, "gz"))
+ return ZCAT;
+#endif /* ZCAT */
+ return NULL;
+}
+
+/*
+ * Simply display the preformatted page.
+ */
+int
+display_cat_file (file)
+ register char *file;
+{
+ register int found;
+ char command[FILENAME_MAX];
+
+ found = 0;
+
+ if (access (file, R_OK) == 0)
+ {
+ char *expander = get_expander (file);
+
+ if (expander != NULL)
+ sprintf (command, "%s %s | %s", expander, file, pager);
+ else
+ sprintf (command, "%s %s", pager, file);
+
+ found = do_system_command (command);
+ }
+ return found;
+}
+
+/*
+ * Try to find the ultimate source file. If the first line of the
+ * current file is not of the form
+ *
+ * .so man3/printf.3s
+ *
+ * the input file name is returned.
+ */
+char *
+ultimate_source (name, path)
+ char *name;
+ char *path;
+{
+ static char buf[BUFSIZ];
+ static char ult[FILENAME_MAX];
+
+ FILE *fp;
+ char *beg;
+ char *end;
+
+ strcpy (ult, name);
+ strcpy (buf, name);
+
+ next:
+
+ if ((fp = fopen (ult, "r")) == NULL)
+ return buf;
+
+ if (fgets (buf, BUFSIZ, fp) == NULL)
+ return ult;
+
+ if (strlen (buf) < 5)
+ return ult;
+
+ beg = buf;
+ if (*beg++ == '.' && *beg++ == 's' && *beg++ == 'o')
+ {
+ while ((*beg == ' ' || *beg == '\t') && *beg != '\0')
+ beg++;
+
+ end = beg;
+ while (*end != ' ' && *end != '\t' && *end != '\n' && *end != '\0')
+ end++;
+
+ *end = '\0';
+
+ strcpy (ult, path);
+ strcat (ult, "/");
+ strcat (ult, beg);
+
+ strcpy (buf, ult);
+
+ goto next;
+ }
+
+ if (debug)
+ fprintf (stderr, "found ultimate source file %s\n", ult);
+
+ return ult;
+}
+
+void
+add_directive (first, d, file, buf)
+ int *first;
+ char *d;
+ char *file;
+ char *buf;
+{
+ if (strcmp (d, "") != 0)
+ {
+ if (*first)
+ {
+ *first = 0;
+ strcpy (buf, d);
+ strcat (buf, " ");
+ strcat (buf, file);
+ }
+ else
+ {
+ strcat (buf, " | ");
+ strcat (buf, d);
+ }
+ }
+}
+
+int
+parse_roff_directive (cp, file, buf)
+ char *cp;
+ char *file;
+ char *buf;
+{
+ char c;
+ int first = 1;
+ int tbl_found = 0;
+
+ while ((c = *cp++) != '\0')
+ {
+ switch (c)
+ {
+ case 'e':
+
+ if (debug)
+ fprintf (stderr, "found eqn(1) directive\n");
+
+ if (troff)
+ add_directive (&first, EQN, file, buf);
+ else
+ add_directive (&first, NEQN, file, buf);
+
+ break;
+
+ case 'g':
+
+ if (debug)
+ fprintf (stderr, "found grap(1) directive\n");
+
+ add_directive (&first, GRAP, file, buf);
+
+ break;
+
+ case 'p':
+
+ if (debug)
+ fprintf (stderr, "found pic(1) directive\n");
+
+ add_directive (&first, PIC, file, buf);
+
+ break;
+
+ case 't':
+
+ if (debug)
+ fprintf (stderr, "found tbl(1) directive\n");
+
+ tbl_found++;
+ add_directive (&first, TBL, file, buf);
+ break;
+
+ case 'v':
+
+ if (debug)
+ fprintf (stderr, "found vgrind(1) directive\n");
+
+ add_directive (&first, VGRIND, file, buf);
+ break;
+
+ case 'r':
+
+ if (debug)
+ fprintf (stderr, "found refer(1) directive\n");
+
+ add_directive (&first, REFER, file, buf);
+ break;
+
+ case ' ':
+ case '\t':
+ case '\n':
+
+ goto done;
+
+ default:
+
+ return -1;
+ }
+ }
+
+ done:
+
+ if (first)
+ return 1;
+
+#ifdef HAS_TROFF
+ if (troff)
+ {
+ strcat (buf, " | ");
+ strcat (buf, TROFF);
+ }
+ else
+#endif
+ {
+ strcat (buf, " | ");
+ strcat (buf, NROFF);
+ }
+ if (tbl_found && !troff && strcmp (COL, "") != 0)
+ {
+ strcat (buf, " | ");
+ strcat (buf, COL);
+ }
+
+ return 0;
+}
+
+char *
+make_roff_command (file)
+ char *file;
+{
+ FILE *fp;
+ char line [BUFSIZ];
+ static char buf [BUFSIZ];
+ int status;
+ char *cp;
+
+ if (roff_directive != NULL)
+ {
+ if (debug)
+ fprintf (stderr, "parsing directive from command line\n");
+
+ status = parse_roff_directive (roff_directive, file, buf);
+
+ if (status == 0)
+ return buf;
+
+ if (status == -1)
+ gripe_roff_command_from_command_line (file);
+ }
+
+ if ((fp = fopen (file, "r")) != NULL)
+ {
+ cp = line;
+ fgets (line, 100, fp);
+ if (*cp++ == '\'' && *cp++ == '\\' && *cp++ == '"' && *cp++ == ' ')
+ {
+ if (debug)
+ fprintf (stderr, "parsing directive from file\n");
+
+ status = parse_roff_directive (cp, file, buf);
+
+ fclose (fp);
+
+ if (status == 0)
+ return buf;
+
+ if (status == -1)
+ gripe_roff_command_from_file (file);
+ }
+ }
+ else
+ {
+ /*
+ * Is there really any point in continuing to look for
+ * preprocessor options if we can't even read the man page source?
+ */
+ gripe_reading_man_file (file);
+ return NULL;
+ }
+
+ if ((cp = getenv ("MANROFFSEQ")) != NULL)
+ {
+ if (debug)
+ fprintf (stderr, "parsing directive from environment\n");
+
+ status = parse_roff_directive (cp, file, buf);
+
+ if (status == 0)
+ return buf;
+
+ if (status == -1)
+ gripe_roff_command_from_env ();
+ }
+
+ if (debug)
+ fprintf (stderr, "using default preprocessor sequence\n");
+
+ if ((cp = get_expander(file)) == NULL)
+ cp = "cat";
+ sprintf(buf, "%s %s | ", cp, file);
+#ifdef HAS_TROFF
+ if (troff)
+ {
+ if (strcmp (TBL, "") != 0)
+ {
+ strcat (buf, TBL);
+ strcat (buf, " | ");
+ strcat (buf, TROFF);
+ }
+ else
+ {
+ strcat (buf, TROFF);
+ }
+ }
+ else
+#endif
+ {
+ if (strcmp (TBL, "") != 0)
+ {
+ strcat (buf, TBL);
+ strcat (buf, " | ");
+ strcat (buf, NROFF);
+ }
+ else
+ {
+ strcpy (buf, NROFF);
+ }
+
+ if (strcmp (COL, "") != 0)
+ {
+ strcat (buf, " | ");
+ strcat (buf, COL);
+ }
+ }
+ return buf;
+}
+
+/*
+ * Try to format the man page and create a new formatted file. Return
+ * 1 for success and 0 for failure.
+ */
+int
+make_cat_file (path, man_file, cat_file)
+ register char *path;
+ register char *man_file;
+ register char *cat_file;
+{
+ int status;
+ int mode;
+ FILE *fp;
+ char *roff_command;
+ char command[FILENAME_MAX];
+ char temp[FILENAME_MAX];
+
+ sprintf(temp, "%s.tmp", cat_file);
+ if ((fp = fopen (temp, "w")) != NULL)
+ {
+ fclose (fp);
+ unlink (temp);
+
+ roff_command = make_roff_command (man_file);
+ if (roff_command == NULL)
+ return 0;
+ else
+#ifdef DO_COMPRESS
+ sprintf (command, "(cd %s ; %s | %s > %s)", path,
+ roff_command, COMPRESSOR, temp);
+#else
+ sprintf (command, "(cd %s ; %s > %s)", path,
+ roff_command, temp);
+#endif
+ /*
+ * Don't let the user interrupt the system () call and screw up
+ * the formatted man page if we're not done yet.
+ */
+ fprintf (stderr, "Formatting page, please wait...");
+ fflush(stderr);
+
+ status = do_system_command (command);
+
+ if (status <= 0) {
+ fprintf(stderr, "Failed.\n");
+ unlink(temp);
+ exit(1);
+ }
+ else {
+ if (rename(temp, cat_file) == -1) {
+ /* FS might be sticky */
+ sprintf(command, "cp %s %s", temp, cat_file);
+ if (system(command))
+ fprintf(stderr,
+ "\nHmm! Can't seem to rename %s to %s, check permissions on man dir!\n",
+ temp, cat_file);
+ unlink(temp);
+ return 0;
+ }
+ }
+ fprintf(stderr, "Done.\n");
+ if (status == 1)
+ {
+ mode = CATMODE;
+ chmod (cat_file, mode);
+
+ if (debug)
+ fprintf (stderr, "mode of %s is now %o\n", cat_file, mode);
+ }
+
+
+ return 1;
+ }
+ else
+ {
+ if (debug)
+ fprintf (stderr, "Couldn't open %s for writing.\n", cat_file);
+
+ return 0;
+ }
+}
+
+/*
+ * Try to format the man page source and save it, then display it. If
+ * that's not possible, try to format the man page source and display
+ * it directly.
+ *
+ * Note that we've already been handed the name of the ultimate source
+ * file at this point.
+ */
+int
+format_and_display (path, man_file, cat_file)
+ register char *path;
+ register char *man_file;
+ register char *cat_file;
+{
+ int status;
+ register int found;
+ char *roff_command;
+ char command[FILENAME_MAX];
+
+ found = 0;
+
+ if (access (man_file, R_OK) != 0)
+ return 0;
+
+ if (troff)
+ {
+ roff_command = make_roff_command (man_file);
+ if (roff_command == NULL)
+ return 0;
+ else
+ sprintf (command, "(cd %s ; %s)", path, roff_command);
+
+ found = do_system_command (command);
+ }
+ else
+ {
+ status = is_newer (man_file, cat_file);
+ if (debug)
+ fprintf (stderr, "status from is_newer() = %d\n");
+
+ if (status == 1 || status == -2)
+ {
+ /*
+ * Cat file is out of date. Try to format and save it.
+ */
+ if (print_where)
+ {
+ printf ("%s\n", man_file);
+ found++;
+ }
+ else
+ {
+
+#ifdef SETREUID
+ setreuid(-1, euid);
+ setregid(-1, egid);
+#endif
+
+ found = make_cat_file (path, man_file, cat_file);
+
+#ifdef SETREUID
+ setreuid(-1, ruid);
+ setregid(-1, rgid);
+
+ if (!found)
+ {
+ /* Try again as real user - see note below.
+ By running with
+ effective group (user) ID == real group (user) ID
+ except for the call above, I believe the problems
+ of reading private man pages is avoided. */
+ found = make_cat_file (path, man_file, cat_file);
+ }
+#endif
+#ifdef SECURE_MAN_UID
+ if (!found)
+ {
+ /*
+ * Try again as real user. Note that for private
+ * man pages, we won't even get this far unless the
+ * effective user can read the real user's man page
+ * source. Also, if we are trying to find all the
+ * man pages, this will probably make it impossible
+ * to make cat files in the system directories if
+ * the real user's man directories are searched
+ * first, because there's no way to undo this (is
+ * there?). Yikes, am I missing something obvious?
+ */
+ setuid (getuid ());
+
+ found = make_cat_file (path, man_file, cat_file);
+ }
+#endif
+ if (found)
+ {
+ /*
+ * Creating the cat file worked. Now just display it.
+ */
+ (void) display_cat_file (cat_file);
+ }
+ else
+ {
+ /*
+ * Couldn't create cat file. Just format it and
+ * display it through the pager.
+ */
+ roff_command = make_roff_command (man_file);
+ if (roff_command == NULL)
+ return 0;
+ else
+ sprintf (command, "(cd %s ; %s | %s)", path,
+ roff_command, pager);
+
+ found = do_system_command (command);
+ }
+ }
+ }
+ else if (access (cat_file, R_OK) == 0)
+ {
+ /*
+ * Formatting not necessary. Cat file is newer than source
+ * file, or source file is not present but cat file is.
+ */
+ if (print_where)
+ {
+ printf ("%s (source: %s)\n", cat_file, man_file);
+ found++;
+ }
+ else
+ {
+ found = display_cat_file (cat_file);
+ }
+ }
+ }
+ return found;
+}
+
+/*
+ * See if the preformatted man page or the source exists in the given
+ * section.
+ */
+int
+try_section (path, section, name, glob)
+ register char *path;
+ register char *section;
+ register char *name;
+ register int glob;
+{
+ register int found = 0;
+ register int to_cat;
+ register int cat;
+ register char **names;
+ register char **np;
+
+ if (debug)
+ {
+ if (glob)
+ fprintf (stderr, "trying section %s with globbing\n", section);
+ else
+ fprintf (stderr, "trying section %s without globbing\n", section);
+ }
+
+#ifndef NROFF_MISSING
+ /*
+ * Look for man page source files.
+ */
+ cat = 0;
+ if (glob)
+ names = glob_for_file (path, section, name, cat);
+ else
+ names = make_name (path, section, name, cat);
+
+ if (names == (char **) -1 || *names == NULL)
+ /*
+ * No files match. See if there's a preformatted page around that
+ * we can display.
+ */
+#endif /* NROFF_MISSING */
+ {
+ if (!troff)
+ {
+ cat = 1;
+ if (glob)
+ names = glob_for_file (path, section, name, cat);
+ else
+ names = make_name (path, section, name, cat);
+
+ if (names != (char **) -1 && *names != NULL)
+ {
+ for (np = names; *np != NULL; np++)
+ {
+ if (print_where)
+ {
+ printf ("%s\n", *np);
+ found++;
+ }
+ else
+ {
+ found += display_cat_file (*np);
+ }
+ }
+ }
+ }
+ }
+#ifndef NROFF_MISSING
+ else
+ {
+ for (np = names; *np != NULL; np++)
+ {
+ register char *cat_file = NULL;
+ register char *man_file;
+
+ man_file = ultimate_source (*np, path);
+
+ if (!troff)
+ {
+ to_cat = 1;
+
+ cat_file = convert_name (man_file, to_cat);
+
+ if (debug)
+ fprintf (stderr, "will try to write %s if needed\n", cat_file);
+ }
+
+ found += format_and_display (path, man_file, cat_file);
+ }
+ }
+#endif /* NROFF_MISSING */
+ return found;
+}
+
+/*
+ * Search for manual pages.
+ *
+ * If preformatted manual pages are supported, look for the formatted
+ * file first, then the man page source file. If they both exist and
+ * the man page source file is newer, or only the source file exists,
+ * try to reformat it and write the results in the cat directory. If
+ * it is not possible to write the cat file, simply format and display
+ * the man file.
+ *
+ * If preformatted pages are not supported, or the troff option is
+ * being used, only look for the man page source file.
+ *
+ */
+int
+man (name)
+ char *name;
+{
+ register int found;
+ register int glob;
+ register char **mp;
+ register char **sp;
+
+ found = 0;
+
+ fflush (stdout);
+ if (section != NULL)
+ {
+ for (mp = manpathlist; *mp != NULL; mp++)
+ {
+ if (debug)
+ fprintf (stderr, "\nsearching in %s\n", *mp);
+
+ glob = 1;
+
+ found += try_section (*mp, section, name, glob);
+
+ if (found && !findall) /* i.e. only do this section... */
+ return found;
+ }
+ }
+ else
+ {
+ for (sp = section_list; *sp != NULL; sp++)
+ {
+ for (mp = manpathlist; *mp != NULL; mp++)
+ {
+ if (debug)
+ fprintf (stderr, "\nsearching in %s\n", *mp);
+
+ glob = 1;
+
+ found += try_section (*mp, *sp, name, glob);
+
+ if (found && !findall) /* i.e. only do this section... */
+ return found;
+ }
+ }
+ }
+ return found;
+}
+
+char **
+get_section_list ()
+{
+ int i;
+ char *p;
+ char *end;
+ static char *tmp_section_list[100];
+
+ if (colon_sep_section_list == NULL)
+ {
+ if ((p = getenv ("MANSECT")) == NULL)
+ {
+ return std_sections;
+ }
+ else
+ {
+ colon_sep_section_list = strdup (p);
+ }
+ }
+
+ i = 0;
+ for (p = colon_sep_section_list; ; p = end+1)
+ {
+ if ((end = strchr (p, ':')) != NULL)
+ *end = '\0';
+
+ tmp_section_list[i++] = strdup (p);
+
+ if (end == NULL)
+ break;
+ }
+
+ tmp_section_list [i] = NULL;
+ return tmp_section_list;
+}
diff --git a/gnu/usr.bin/man/man/man.man b/gnu/usr.bin/man/man/man.man
new file mode 100644
index 0000000..7556c58
--- /dev/null
+++ b/gnu/usr.bin/man/man/man.man
@@ -0,0 +1,134 @@
+.\" Man page for man
+.\"
+.\" Copyright (c) 1990, 1991, John W. Eaton.
+.\"
+.\" You may distribute under the terms of the GNU General Public
+.\" License as specified in the README file that comes with the man 1.0
+.\" distribution.
+.\"
+.\" John W. Eaton
+.\" jwe@che.utexas.edu
+.\" Department of Chemical Engineering
+.\" The University of Texas at Austin
+.\" Austin, Texas 78712
+.\"
+.TH man 1 "Jan 5, 1991"
+.LO 1
+.SH NAME
+man \- format and display the on-line manual pages
+.SH SYNOPSIS
+man [\-adfhktw] [\-m system] [\-p string] [\-M path] [\-P pager]
+[\-S list] [section] name ...
+.SH DESCRIPTION
+man formats and displays the on-line manual pages. This version knows
+about the MANPATH and PAGER environment variables, so you can have
+your own set(s) of personal man pages and choose whatever program you
+like to display the formatted pages. If section is specified, man
+only looks in that section of the manual. You may also specify the
+order to search the sections for entries and which preprocessors to
+run on the source files via command line options or environment
+variables. If enabled by the system administrator, formatted man
+pages will also be compressed with the `%compress%' command to save
+space.
+.SH OPTIONS
+.TP
+.B \-\^M " path"
+Specify an alternate manpath. By default, man uses
+.B manpath
+to determine the path to search. This option overrides the
+.B MANPATH
+environment variable.
+.TP
+.B \-\^P " pager"
+Specify which pager to use. By default, man uses
+.B %pager%,
+This option overrides the
+.B PAGER
+environment variable.
+.TP
+.B \-\^S " list"
+List is a colon separated list of manual sections to search.
+This option overrides the
+.B MANSECT
+environment variable.
+.TP
+.B \-\^a
+By default, man will exit after displaying the first manual page it
+finds. Using this option forces man to display all the manual pages
+that match
+.B name,
+not just the first.
+.TP
+.B \-\^d
+Don't actually display the man pages, but do print gobs of debugging
+information.
+.TP
+.B \-\^f
+Equivalent to
+.B whatis.
+.TP
+.B \-\^h
+Print a one line help message and exit.
+.TP
+.B \-\^k
+Equivalent to
+.B apropos.
+.TP
+.B \-\^m " system"
+Specify an alternate set of man pages to search based on the system
+name given.
+.TP
+.B \-\^p " string"
+Specify the sequence of preprocessors to run before nroff or troff.
+Not all installations will have a full set of preprocessors.
+Some of the preprocessors and the letters used to designate them are:
+eqn (e), grap (g), pic (p), tbl (t), vgrind (v), refer (r).
+This option overrides the
+.B MANROFFSEQ
+environment variable.
+.TP
+.B \-\^t
+Use
+.B %troff%
+to format the manual page, passing the output to
+.B stdout.
+The output from
+.B %troff%
+may need to be passed through some filter or another before being
+printed.
+.TP
+.B \-\^w
+Don't actually display the man pages, but do print the location(s) of
+the files that would be formatted or displayed.
+.SH ENVIRONMENT
+.TP \w'MANROFFSEQ\ \ 'u
+.B MANPATH
+If
+.B MANPATH
+is set, its value is used as the path to search for manual pages.
+.TP
+.B MANROFFSEQ
+If
+.B MANROFFSEQ
+is set, its value is used to determine the set of preprocessors run
+before running nroff or troff. By default, pages are passed through
+the table preprocessor before nroff.
+.TP
+.B MANSEC
+If
+.B MANSEC
+is set, its value is used to determine which manual sections to search.
+.TP
+.B PAGER
+If
+.B PAGER
+is set, its value is used as the name of the program to use to display
+the man page. By default,
+.B %pager%
+is used.
+.SH "SEE ALSO"
+apropos(1), whatis(1), manpath(1), more(1), groff(1).
+.SH BUGS
+The
+.B \-t
+option only works if a troff-like program is installed.
diff --git a/gnu/usr.bin/man/man/manpath.c b/gnu/usr.bin/man/man/manpath.c
new file mode 100644
index 0000000..294ffaf
--- /dev/null
+++ b/gnu/usr.bin/man/man/manpath.c
@@ -0,0 +1,520 @@
+/*
+ * manpath.c
+ *
+ * Copyright (c) 1990, 1991, John W. Eaton.
+ *
+ * You may distribute under the terms of the GNU General Public
+ * License as specified in the file COPYING that comes with the man
+ * distribution.
+ *
+ * John W. Eaton
+ * jwe@che.utexas.edu
+ * Department of Chemical Engineering
+ * The University of Texas at Austin
+ * Austin, Texas 78712
+ */
+
+#define MANPATH_MAIN
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include "config.h"
+#include "manpath.h"
+#include "gripes.h"
+
+#ifdef STDC_HEADERS
+#include <stdlib.h>
+#else
+extern int fprintf ();
+extern int strcmp ();
+extern int strncmp ();
+extern char *memcpy ();
+extern char *getenv();
+extern char *malloc();
+extern void free ();
+extern int exit ();
+#endif
+
+extern char *strdup ();
+extern int is_directory ();
+
+#ifndef MAIN
+extern int debug;
+#endif
+
+#ifdef MAIN
+
+#ifndef STDC_HEADERS
+extern char *strcpy ();
+extern int fflush ();
+#endif
+
+char *prognam;
+int debug;
+
+/*
+ * Examine user's PATH and print a reasonable MANPATH.
+ */
+int
+main(argc, argv)
+ int argc;
+ char **argv;
+{
+ int c;
+ int quiet;
+ char *mp;
+ extern int getopt ();
+ extern char *mkprogname ();
+ void usage ();
+ char *manpath ();
+
+ quiet = 1;
+
+ prognam = mkprogname (argv[0]);
+
+ while ((c = getopt (argc, argv, "dhq?")) != EOF)
+ {
+ switch (c)
+ {
+ case 'd':
+ debug++;
+ break;
+ case 'q':
+ quiet = 0;
+ break;
+ case '?':
+ case 'h':
+ default:
+ usage();
+ break;
+ }
+ }
+
+ mp = manpath (quiet);
+
+ fprintf (stdout, "%s\n", mp);
+ fflush (stdout);
+
+ return 0;
+}
+
+void
+usage ()
+{
+ fprintf (stderr, "usage: %s [-q]\n", prognam);
+ exit (1);
+}
+#endif /* MAIN */
+
+/*
+ * If the environment variable MANPATH is set, return it.
+ * If the environment variable PATH is set and has a nonzero length,
+ * try to determine the corresponding manpath, otherwise, return the
+ * default manpath.
+ *
+ * The manpath.config file is used to map system wide /bin directories
+ * to top level man page directories.
+ *
+ * For directories which are in the user's path but not in the
+ * manpath.config file, see if there is a subdirectory `man' or `MAN'.
+ * If so, add that directory to the path. Example: user has
+ * $HOME/bin in his path and the directory $HOME/bin/man exists -- the
+ * directory $HOME/bin/man will be added to the manpath.
+ */
+char *
+manpath (perrs)
+ register int perrs;
+{
+ register int len;
+ register char *manpathlist;
+ register char *path;
+ int get_dirlist ();
+ char *def_path ();
+ char *get_manpath ();
+
+ if (get_dirlist ())
+ gripe_reading_mp_config ();
+
+ if ((manpathlist = getenv ("MANPATH")) != NULL)
+ /*
+ * This must be it.
+ */
+ {
+ if (perrs)
+ fprintf (stderr, "(Warning: MANPATH environment variable set)\n");
+ return strdup (manpathlist);
+ }
+ else if ((path = getenv ("PATH")) == NULL)
+ /*
+ * Things aren't going to work well, but hey...
+ */
+ {
+ if (perrs)
+ fprintf (stderr, "Warning: path not set\n");
+ return def_path (perrs);
+ }
+ else
+ {
+ if ((len = strlen (path)) == 0)
+ /*
+ * Things aren't going to work well here either...
+ */
+ {
+ if (perrs)
+ fprintf (stderr, "Warning: path set but has zero length\n");
+ return def_path (perrs);
+ }
+ return get_manpath (perrs, path);
+ }
+}
+
+/*
+ * Get the list of bin directories and the corresponding man
+ * directories from the manpath.config file.
+ *
+ * This is ugly.
+ */
+int
+get_dirlist ()
+{
+ int i;
+ char *bp;
+ char *p;
+ char buf[BUFSIZ];
+ DIRLIST *dlp = list;
+ FILE *config;
+
+ if ((config = fopen (config_file, "r")) == NULL)
+ gripe_getting_mp_config (config_file);
+
+ while ((bp = fgets (buf, BUFSIZ, config)) != NULL)
+ {
+ while (*bp && (*bp == ' ' || *bp == '\t'))
+ bp++;
+
+ if (*bp == '#' || *bp == '\n')
+ continue;
+
+ if (!strncmp ("MANBIN", bp, 6))
+ continue;
+
+ if (!strncmp ("MANDATORY_MANPATH", bp, 17))
+ {
+ if ((p = strchr (bp, ' ')) == NULL)
+ if ((p = strchr (bp, '\t')) == NULL)
+ return -1;
+
+ bp = p;
+
+ dlp->mandatory = 1;
+
+ while (*bp && *bp != '\n' && (*bp == ' ' || *bp == '\t'))
+ bp++;
+
+ i = 0;
+ while (*bp && *bp != '\n' && *bp != ' ' && *bp != '\t')
+ dlp->mandir[i++] = *bp++;
+ dlp->mandir[i] = '\0';
+
+ if (debug)
+ fprintf (stderr, "found mandatory man directory %s\n",
+ dlp->mandir);
+ }
+ else if (!strncmp ("MANPATH_MAP", bp, 11))
+ {
+ if ((p = strchr (bp, ' ')) == NULL)
+ if ((p = strchr (bp, '\t')) == NULL)
+ return -1;
+
+ bp = p;
+
+ dlp->mandatory = 0;
+
+ while (*bp && *bp != '\n' && (*bp == ' ' || *bp == '\t'))
+ bp++;
+
+ i = 0;
+ while (*bp && *bp != '\n' && *bp != ' ' && *bp != '\t')
+ dlp->bin[i++] = *bp++;
+ dlp->bin[i] = '\0';
+
+ while (*bp && *bp != '\n' && (*bp == ' ' || *bp == '\t'))
+ bp++;
+
+ i = 0;
+ while (*bp && *bp != '\n' && *bp != ' ' && *bp != '\t')
+ dlp->mandir[i++] = *bp++;
+ dlp->mandir[i] = '\0';
+
+ if (debug)
+ fprintf (stderr, "found manpath map %s --> %s\n",
+ dlp->bin, dlp->mandir);
+ }
+ else
+ {
+ gripe_reading_mp_config ();
+ }
+ dlp++;
+ }
+
+ dlp->bin[0] = '\0';
+ dlp->mandir[0] = '\0';
+ dlp->mandatory = 0;
+
+ return 0;
+}
+
+/*
+ * Construct the default manpath. This picks up mandatory manpaths
+ * only.
+ */
+char *
+def_path (perrs)
+ int perrs;
+{
+ register int len;
+ register char *manpathlist, *p;
+ register DIRLIST *dlp;
+
+ len = 0;
+ dlp = list;
+ while (dlp->mandatory != 0)
+ {
+ len += strlen (dlp->mandir) + 1;
+ dlp++;
+ }
+
+ manpathlist = (char *) malloc (len);
+ if (manpathlist == NULL)
+ gripe_alloc (len, "manpathlist");
+
+ *manpathlist = '\0';
+
+ dlp = list;
+ p = manpathlist;
+ while (dlp->mandatory != 0)
+ {
+ int status;
+ char *path = dlp->mandir;
+
+ status = is_directory(path);
+
+ if (status < 0 && perrs)
+ {
+ fprintf (stderr, "Warning: couldn't stat file %s!\n", path);
+ }
+ else if (status == 0 && perrs)
+ {
+ fprintf (stderr, "Warning: standard directory %s doesn't exist!\n",
+ path);
+ }
+ else if (status == 1)
+ {
+ len = strlen (path);
+ memcpy (p, path, len);
+ p += len;
+ *p++ = ':';
+ dlp++;
+ }
+ }
+
+ p[-1] = '\0';
+
+ return manpathlist;
+}
+
+/*
+ * For each directory in the user's path, see if it is one of the
+ * directories listed in the manpath.config file. If so, and it is
+ * not already in the manpath, add it. If the directory is not listed
+ * in the manpath.config file, see if there is a subdirectory `man' or
+ * `MAN'. If so, and it is not already in the manpath, add it.
+ * Example: user has $HOME/bin in his path and the directory
+ * $HOME/bin/man exists -- the directory $HOME/bin/man will be added
+ * to the manpath.
+ */
+char *
+get_manpath (perrs, path)
+ register int perrs;
+ register char *path;
+{
+ register int len;
+ register char *tmppath;
+ register char *t;
+ register char *p;
+ register char **lp;
+ register char *end;
+ register char *manpathlist;
+ register DIRLIST *dlp;
+ void add_dir_to_list ();
+ char *has_subdirs ();
+
+ tmppath = strdup (path);
+
+ for (p = tmppath; ; p = end+1)
+ {
+ if (end = strchr(p, ':'))
+ *end = '\0';
+
+ if (debug)
+ fprintf (stderr, "\npath directory %s ", p);
+
+ /*
+ * The directory we're working on is in the config file.
+ * If we haven't added it to the list yet, do.
+ */
+ for (dlp = list; dlp->mandir[0] != '\0'; dlp++)
+ if (dlp->bin[0] != '\0' && !strcmp (p, dlp->bin))
+ {
+ if (debug)
+ fprintf (stderr, "is in the config file\n");
+
+ add_dir_to_list (tmplist, dlp->mandir, perrs);
+ goto found;
+ }
+
+ /*
+ * The directory we're working on isn't in the config file. See
+ * if it has man or MAN subdirectories. If so, and it hasn't
+ * been added to the list, do.
+ */
+ if (debug)
+ fprintf (stderr, "is not in the config file\n");
+
+ t = has_subdirs (p);
+ if (t != NULL)
+ {
+ if (debug)
+ fprintf (stderr, "but it does have a man or MAN subdirectory\n");
+
+ add_dir_to_list (tmplist, t, perrs);
+ free (t);
+ }
+ else
+ {
+ if (debug)
+ fprintf (stderr, "and doesn't have man or MAN subdirectories\n");
+ }
+
+ found:
+
+ if (!end)
+ break;
+ }
+
+ if (debug)
+ fprintf (stderr, "\nadding mandatory man directories\n\n");
+
+ dlp = list;
+ while (dlp->mandatory != 0)
+ {
+ add_dir_to_list (tmplist, dlp->mandir, perrs);
+ dlp++;
+ }
+
+ len = 0;
+ lp = tmplist;
+ while (*lp != NULL)
+ {
+ len += strlen (*lp) + 1;
+ lp++;
+ }
+
+ manpathlist = (char *) malloc (len);
+ if (manpathlist == NULL)
+ gripe_alloc (len, "manpathlist");
+
+ *manpathlist = '\0';
+
+ lp = tmplist;
+ p = manpathlist;
+ while (*lp != NULL)
+ {
+ len = strlen (*lp);
+ memcpy (p, *lp, len);
+ p += len;
+ *p++ = ':';
+ lp++;
+ }
+
+ p[-1] = '\0';
+
+ return manpathlist;
+}
+
+/*
+ * Add a directory to the manpath list if it isn't already there.
+ */
+void
+add_dir_to_list (lp, dir, perrs)
+ char **lp;
+ char *dir;
+ int perrs;
+{
+ extern char *strdup ();
+ int status;
+
+ while (*lp != NULL)
+ {
+ if (!strcmp (*lp, dir))
+ {
+ if (debug)
+ fprintf (stderr, "%s is already in the manpath\n", dir);
+ return;
+ }
+ lp++;
+ }
+ /*
+ * Not found -- add it.
+ */
+ status = is_directory(dir);
+
+ if (status < 0 && perrs)
+ {
+ fprintf (stderr, "Warning: couldn't stat file %s!\n", dir);
+ }
+ else if (status == 0 && perrs)
+ {
+ fprintf (stderr, "Warning: %s isn't a directory!\n", dir);
+ }
+ else if (status == 1)
+ {
+ if (debug)
+ fprintf (stderr, "adding %s to manpath\n", dir);
+
+ *lp = strdup (dir);
+ }
+}
+
+/*
+ * Check to see if the current directory has man or MAN
+ * subdirectories.
+ */
+char *
+has_subdirs (p)
+ register char *p;
+{
+ int len;
+ register char *t;
+
+ len = strlen (p);
+
+ t = (char *) malloc ((unsigned) len + 5);
+ if (t == NULL)
+ gripe_alloc (len+5, "p\n");
+
+ memcpy (t, p, len);
+ strcpy (t + len, "/man");
+
+ if (is_directory (t) == 1)
+ return t;
+
+ strcpy (t + len, "/MAN");
+
+ if (is_directory (t) == 1)
+ return t;
+
+ return NULL;
+}
diff --git a/gnu/usr.bin/man/man/manpath.h b/gnu/usr.bin/man/man/manpath.h
new file mode 100644
index 0000000..3039bd9
--- /dev/null
+++ b/gnu/usr.bin/man/man/manpath.h
@@ -0,0 +1,26 @@
+/*
+ * manpath.h
+ *
+ * Copyright (c) 1990, 1991, John W. Eaton.
+ *
+ * You may distribute under the terms of the GNU General Public
+ * License as specified in the file COPYING that comes with the man
+ * distribution.
+ *
+ * John W. Eaton
+ * jwe@che.utexas.edu
+ * Department of Chemical Engineering
+ * The University of Texas at Austin
+ * Austin, Texas 78712
+ */
+
+typedef struct
+{
+ char mandir[MAXPATHLEN];
+ char bin[MAXPATHLEN];
+ int mandatory;
+} DIRLIST;
+
+DIRLIST list[MAXDIRS];
+
+char *tmplist[MAXDIRS];
diff --git a/gnu/usr.bin/man/man/ndir.h b/gnu/usr.bin/man/man/ndir.h
new file mode 100644
index 0000000..438d5c2
--- /dev/null
+++ b/gnu/usr.bin/man/man/ndir.h
@@ -0,0 +1,51 @@
+/*
+ <dir.h> -- definitions for 4.2BSD-compatible directory access
+
+ last edit: 09-Jul-1983 D A Gwyn
+*/
+
+#ifdef VMS
+#ifndef FAB$C_BID
+#include <fab.h>
+#endif
+#ifndef NAM$C_BID
+#include <nam.h>
+#endif
+#ifndef RMS$_SUC
+#include <rmsdef.h>
+#endif
+#include "dir.h"
+#endif /* VMS */
+
+#define DIRBLKSIZ 512 /* size of directory block */
+#ifdef VMS
+#define MAXNAMLEN (DIR$S_NAME + 7) /* 80 plus room for version #. */
+#define MAXFULLSPEC NAM$C_MAXRSS /* Maximum full spec */
+#else
+#define MAXNAMLEN 15 /* maximum filename length */
+#endif /* VMS */
+ /* NOTE: MAXNAMLEN must be one less than a multiple of 4 */
+
+struct direct /* data from readdir() */
+ {
+ long d_ino; /* inode number of entry */
+ unsigned short d_reclen; /* length of this record */
+ unsigned short d_namlen; /* length of string in d_name */
+ char d_name[MAXNAMLEN+1]; /* name of file */
+ };
+
+typedef struct
+ {
+ int dd_fd; /* file descriptor */
+ int dd_loc; /* offset in block */
+ int dd_size; /* amount of valid data */
+ char dd_buf[DIRBLKSIZ]; /* directory block */
+ } DIR; /* stream data from opendir() */
+
+extern DIR *opendir();
+extern struct direct *readdir();
+extern long telldir();
+extern void seekdir();
+extern void closedir();
+
+#define rewinddir( dirp ) seekdir( dirp, 0L )
diff --git a/gnu/usr.bin/man/man/strdup.c b/gnu/usr.bin/man/man/strdup.c
new file mode 100644
index 0000000..4e5af07
--- /dev/null
+++ b/gnu/usr.bin/man/man/strdup.c
@@ -0,0 +1,39 @@
+/* strdup.c -- return a newly allocated copy of a string
+ Copyright (C) 1990 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#ifdef STDC_HEADERS
+#include <string.h>
+#include <stdlib.h>
+#else
+char *malloc ();
+char *strcpy ();
+#endif
+
+/* Return a newly allocated copy of STR,
+ or 0 if out of memory. */
+
+char *
+strdup (str)
+ char *str;
+{
+ char *newstr;
+
+ newstr = (char *) malloc (strlen (str) + 1);
+ if (newstr)
+ strcpy (newstr, str);
+ return newstr;
+}
diff --git a/gnu/usr.bin/man/man/version.h b/gnu/usr.bin/man/man/version.h
new file mode 100644
index 0000000..2ec5c22
--- /dev/null
+++ b/gnu/usr.bin/man/man/version.h
@@ -0,0 +1,17 @@
+/*
+ * version.h
+ *
+ * Copyright (c) 1990, 1991, John W. Eaton.
+ *
+ * You may distribute under the terms of the GNU General Public
+ * License as specified in the file COPYING that comes with the man
+ * distribution.
+ *
+ * John W. Eaton
+ * jwe@che.utexas.edu
+ * Department of Chemical Engineering
+ * The University of Texas at Austin
+ * Austin, Texas 78712
+ */
+
+static char version[] = "1.1";
diff --git a/gnu/usr.bin/man/manpath/Makefile b/gnu/usr.bin/man/manpath/Makefile
new file mode 100644
index 0000000..578ae91
--- /dev/null
+++ b/gnu/usr.bin/man/manpath/Makefile
@@ -0,0 +1,33 @@
+PROG= manpath
+SRCS= manpath.c
+
+.if exists(${.CURDIR}/../lib/obj)
+LDADD= -L${.CURDIR}/../lib/obj -lman
+.else
+LDADD= -L${.CURDIR}/../lib/ -lman
+.endif
+
+.if exists(${.CURDIR}/obj)
+MAN1=${.CURDIR}/obj/manpath.1
+.else
+MAN1=${.CURDIR}/manpath.1
+.endif
+
+DPADD+= ${MAN1}
+CFLAGS+= -DMAIN -DSTDC_HEADERS -DPOSIX -DHAS_TROFF -DDO_UNCOMPRESS
+CFLAGS+= -DALT_SYSTEMS -I${.CURDIR}/../lib -I${.CURDIR}/../lib/obj
+CLEANFILES+= ${MAN1}
+MANDEPEND+= ${MAN1}
+
+${MAN1}: ${.CURDIR}/manpath.man
+ @echo Making ${.TARGET:T} from ${.ALLSRC:T}; \
+ sed -e 's,%libdir%,${libdir},' -e 's,%bindir%,${bindir},' \
+ -e 's,%pager%,${pager},' -e 's,%troff%,${troff},' \
+ -e 's,%manpath_config_file%,${manpath_config_file},' \
+ ${.CURDIR}/manpath.man > ${MAN1}
+
+afterinstall:
+ ${INSTALL} -c -o bin -g bin -m 644 ${.CURDIR}/manpath.config \
+ ${DESTDIR}${manpath_config_file}.sample
+
+.include <bsd.prog.mk>
diff --git a/gnu/usr.bin/man/manpath/manpath.c b/gnu/usr.bin/man/manpath/manpath.c
new file mode 100644
index 0000000..294ffaf
--- /dev/null
+++ b/gnu/usr.bin/man/manpath/manpath.c
@@ -0,0 +1,520 @@
+/*
+ * manpath.c
+ *
+ * Copyright (c) 1990, 1991, John W. Eaton.
+ *
+ * You may distribute under the terms of the GNU General Public
+ * License as specified in the file COPYING that comes with the man
+ * distribution.
+ *
+ * John W. Eaton
+ * jwe@che.utexas.edu
+ * Department of Chemical Engineering
+ * The University of Texas at Austin
+ * Austin, Texas 78712
+ */
+
+#define MANPATH_MAIN
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include "config.h"
+#include "manpath.h"
+#include "gripes.h"
+
+#ifdef STDC_HEADERS
+#include <stdlib.h>
+#else
+extern int fprintf ();
+extern int strcmp ();
+extern int strncmp ();
+extern char *memcpy ();
+extern char *getenv();
+extern char *malloc();
+extern void free ();
+extern int exit ();
+#endif
+
+extern char *strdup ();
+extern int is_directory ();
+
+#ifndef MAIN
+extern int debug;
+#endif
+
+#ifdef MAIN
+
+#ifndef STDC_HEADERS
+extern char *strcpy ();
+extern int fflush ();
+#endif
+
+char *prognam;
+int debug;
+
+/*
+ * Examine user's PATH and print a reasonable MANPATH.
+ */
+int
+main(argc, argv)
+ int argc;
+ char **argv;
+{
+ int c;
+ int quiet;
+ char *mp;
+ extern int getopt ();
+ extern char *mkprogname ();
+ void usage ();
+ char *manpath ();
+
+ quiet = 1;
+
+ prognam = mkprogname (argv[0]);
+
+ while ((c = getopt (argc, argv, "dhq?")) != EOF)
+ {
+ switch (c)
+ {
+ case 'd':
+ debug++;
+ break;
+ case 'q':
+ quiet = 0;
+ break;
+ case '?':
+ case 'h':
+ default:
+ usage();
+ break;
+ }
+ }
+
+ mp = manpath (quiet);
+
+ fprintf (stdout, "%s\n", mp);
+ fflush (stdout);
+
+ return 0;
+}
+
+void
+usage ()
+{
+ fprintf (stderr, "usage: %s [-q]\n", prognam);
+ exit (1);
+}
+#endif /* MAIN */
+
+/*
+ * If the environment variable MANPATH is set, return it.
+ * If the environment variable PATH is set and has a nonzero length,
+ * try to determine the corresponding manpath, otherwise, return the
+ * default manpath.
+ *
+ * The manpath.config file is used to map system wide /bin directories
+ * to top level man page directories.
+ *
+ * For directories which are in the user's path but not in the
+ * manpath.config file, see if there is a subdirectory `man' or `MAN'.
+ * If so, add that directory to the path. Example: user has
+ * $HOME/bin in his path and the directory $HOME/bin/man exists -- the
+ * directory $HOME/bin/man will be added to the manpath.
+ */
+char *
+manpath (perrs)
+ register int perrs;
+{
+ register int len;
+ register char *manpathlist;
+ register char *path;
+ int get_dirlist ();
+ char *def_path ();
+ char *get_manpath ();
+
+ if (get_dirlist ())
+ gripe_reading_mp_config ();
+
+ if ((manpathlist = getenv ("MANPATH")) != NULL)
+ /*
+ * This must be it.
+ */
+ {
+ if (perrs)
+ fprintf (stderr, "(Warning: MANPATH environment variable set)\n");
+ return strdup (manpathlist);
+ }
+ else if ((path = getenv ("PATH")) == NULL)
+ /*
+ * Things aren't going to work well, but hey...
+ */
+ {
+ if (perrs)
+ fprintf (stderr, "Warning: path not set\n");
+ return def_path (perrs);
+ }
+ else
+ {
+ if ((len = strlen (path)) == 0)
+ /*
+ * Things aren't going to work well here either...
+ */
+ {
+ if (perrs)
+ fprintf (stderr, "Warning: path set but has zero length\n");
+ return def_path (perrs);
+ }
+ return get_manpath (perrs, path);
+ }
+}
+
+/*
+ * Get the list of bin directories and the corresponding man
+ * directories from the manpath.config file.
+ *
+ * This is ugly.
+ */
+int
+get_dirlist ()
+{
+ int i;
+ char *bp;
+ char *p;
+ char buf[BUFSIZ];
+ DIRLIST *dlp = list;
+ FILE *config;
+
+ if ((config = fopen (config_file, "r")) == NULL)
+ gripe_getting_mp_config (config_file);
+
+ while ((bp = fgets (buf, BUFSIZ, config)) != NULL)
+ {
+ while (*bp && (*bp == ' ' || *bp == '\t'))
+ bp++;
+
+ if (*bp == '#' || *bp == '\n')
+ continue;
+
+ if (!strncmp ("MANBIN", bp, 6))
+ continue;
+
+ if (!strncmp ("MANDATORY_MANPATH", bp, 17))
+ {
+ if ((p = strchr (bp, ' ')) == NULL)
+ if ((p = strchr (bp, '\t')) == NULL)
+ return -1;
+
+ bp = p;
+
+ dlp->mandatory = 1;
+
+ while (*bp && *bp != '\n' && (*bp == ' ' || *bp == '\t'))
+ bp++;
+
+ i = 0;
+ while (*bp && *bp != '\n' && *bp != ' ' && *bp != '\t')
+ dlp->mandir[i++] = *bp++;
+ dlp->mandir[i] = '\0';
+
+ if (debug)
+ fprintf (stderr, "found mandatory man directory %s\n",
+ dlp->mandir);
+ }
+ else if (!strncmp ("MANPATH_MAP", bp, 11))
+ {
+ if ((p = strchr (bp, ' ')) == NULL)
+ if ((p = strchr (bp, '\t')) == NULL)
+ return -1;
+
+ bp = p;
+
+ dlp->mandatory = 0;
+
+ while (*bp && *bp != '\n' && (*bp == ' ' || *bp == '\t'))
+ bp++;
+
+ i = 0;
+ while (*bp && *bp != '\n' && *bp != ' ' && *bp != '\t')
+ dlp->bin[i++] = *bp++;
+ dlp->bin[i] = '\0';
+
+ while (*bp && *bp != '\n' && (*bp == ' ' || *bp == '\t'))
+ bp++;
+
+ i = 0;
+ while (*bp && *bp != '\n' && *bp != ' ' && *bp != '\t')
+ dlp->mandir[i++] = *bp++;
+ dlp->mandir[i] = '\0';
+
+ if (debug)
+ fprintf (stderr, "found manpath map %s --> %s\n",
+ dlp->bin, dlp->mandir);
+ }
+ else
+ {
+ gripe_reading_mp_config ();
+ }
+ dlp++;
+ }
+
+ dlp->bin[0] = '\0';
+ dlp->mandir[0] = '\0';
+ dlp->mandatory = 0;
+
+ return 0;
+}
+
+/*
+ * Construct the default manpath. This picks up mandatory manpaths
+ * only.
+ */
+char *
+def_path (perrs)
+ int perrs;
+{
+ register int len;
+ register char *manpathlist, *p;
+ register DIRLIST *dlp;
+
+ len = 0;
+ dlp = list;
+ while (dlp->mandatory != 0)
+ {
+ len += strlen (dlp->mandir) + 1;
+ dlp++;
+ }
+
+ manpathlist = (char *) malloc (len);
+ if (manpathlist == NULL)
+ gripe_alloc (len, "manpathlist");
+
+ *manpathlist = '\0';
+
+ dlp = list;
+ p = manpathlist;
+ while (dlp->mandatory != 0)
+ {
+ int status;
+ char *path = dlp->mandir;
+
+ status = is_directory(path);
+
+ if (status < 0 && perrs)
+ {
+ fprintf (stderr, "Warning: couldn't stat file %s!\n", path);
+ }
+ else if (status == 0 && perrs)
+ {
+ fprintf (stderr, "Warning: standard directory %s doesn't exist!\n",
+ path);
+ }
+ else if (status == 1)
+ {
+ len = strlen (path);
+ memcpy (p, path, len);
+ p += len;
+ *p++ = ':';
+ dlp++;
+ }
+ }
+
+ p[-1] = '\0';
+
+ return manpathlist;
+}
+
+/*
+ * For each directory in the user's path, see if it is one of the
+ * directories listed in the manpath.config file. If so, and it is
+ * not already in the manpath, add it. If the directory is not listed
+ * in the manpath.config file, see if there is a subdirectory `man' or
+ * `MAN'. If so, and it is not already in the manpath, add it.
+ * Example: user has $HOME/bin in his path and the directory
+ * $HOME/bin/man exists -- the directory $HOME/bin/man will be added
+ * to the manpath.
+ */
+char *
+get_manpath (perrs, path)
+ register int perrs;
+ register char *path;
+{
+ register int len;
+ register char *tmppath;
+ register char *t;
+ register char *p;
+ register char **lp;
+ register char *end;
+ register char *manpathlist;
+ register DIRLIST *dlp;
+ void add_dir_to_list ();
+ char *has_subdirs ();
+
+ tmppath = strdup (path);
+
+ for (p = tmppath; ; p = end+1)
+ {
+ if (end = strchr(p, ':'))
+ *end = '\0';
+
+ if (debug)
+ fprintf (stderr, "\npath directory %s ", p);
+
+ /*
+ * The directory we're working on is in the config file.
+ * If we haven't added it to the list yet, do.
+ */
+ for (dlp = list; dlp->mandir[0] != '\0'; dlp++)
+ if (dlp->bin[0] != '\0' && !strcmp (p, dlp->bin))
+ {
+ if (debug)
+ fprintf (stderr, "is in the config file\n");
+
+ add_dir_to_list (tmplist, dlp->mandir, perrs);
+ goto found;
+ }
+
+ /*
+ * The directory we're working on isn't in the config file. See
+ * if it has man or MAN subdirectories. If so, and it hasn't
+ * been added to the list, do.
+ */
+ if (debug)
+ fprintf (stderr, "is not in the config file\n");
+
+ t = has_subdirs (p);
+ if (t != NULL)
+ {
+ if (debug)
+ fprintf (stderr, "but it does have a man or MAN subdirectory\n");
+
+ add_dir_to_list (tmplist, t, perrs);
+ free (t);
+ }
+ else
+ {
+ if (debug)
+ fprintf (stderr, "and doesn't have man or MAN subdirectories\n");
+ }
+
+ found:
+
+ if (!end)
+ break;
+ }
+
+ if (debug)
+ fprintf (stderr, "\nadding mandatory man directories\n\n");
+
+ dlp = list;
+ while (dlp->mandatory != 0)
+ {
+ add_dir_to_list (tmplist, dlp->mandir, perrs);
+ dlp++;
+ }
+
+ len = 0;
+ lp = tmplist;
+ while (*lp != NULL)
+ {
+ len += strlen (*lp) + 1;
+ lp++;
+ }
+
+ manpathlist = (char *) malloc (len);
+ if (manpathlist == NULL)
+ gripe_alloc (len, "manpathlist");
+
+ *manpathlist = '\0';
+
+ lp = tmplist;
+ p = manpathlist;
+ while (*lp != NULL)
+ {
+ len = strlen (*lp);
+ memcpy (p, *lp, len);
+ p += len;
+ *p++ = ':';
+ lp++;
+ }
+
+ p[-1] = '\0';
+
+ return manpathlist;
+}
+
+/*
+ * Add a directory to the manpath list if it isn't already there.
+ */
+void
+add_dir_to_list (lp, dir, perrs)
+ char **lp;
+ char *dir;
+ int perrs;
+{
+ extern char *strdup ();
+ int status;
+
+ while (*lp != NULL)
+ {
+ if (!strcmp (*lp, dir))
+ {
+ if (debug)
+ fprintf (stderr, "%s is already in the manpath\n", dir);
+ return;
+ }
+ lp++;
+ }
+ /*
+ * Not found -- add it.
+ */
+ status = is_directory(dir);
+
+ if (status < 0 && perrs)
+ {
+ fprintf (stderr, "Warning: couldn't stat file %s!\n", dir);
+ }
+ else if (status == 0 && perrs)
+ {
+ fprintf (stderr, "Warning: %s isn't a directory!\n", dir);
+ }
+ else if (status == 1)
+ {
+ if (debug)
+ fprintf (stderr, "adding %s to manpath\n", dir);
+
+ *lp = strdup (dir);
+ }
+}
+
+/*
+ * Check to see if the current directory has man or MAN
+ * subdirectories.
+ */
+char *
+has_subdirs (p)
+ register char *p;
+{
+ int len;
+ register char *t;
+
+ len = strlen (p);
+
+ t = (char *) malloc ((unsigned) len + 5);
+ if (t == NULL)
+ gripe_alloc (len+5, "p\n");
+
+ memcpy (t, p, len);
+ strcpy (t + len, "/man");
+
+ if (is_directory (t) == 1)
+ return t;
+
+ strcpy (t + len, "/MAN");
+
+ if (is_directory (t) == 1)
+ return t;
+
+ return NULL;
+}
diff --git a/gnu/usr.bin/man/manpath/manpath.config b/gnu/usr.bin/man/manpath/manpath.config
new file mode 100644
index 0000000..91aac29
--- /dev/null
+++ b/gnu/usr.bin/man/manpath/manpath.config
@@ -0,0 +1,30 @@
+# manpath.config
+#
+# This file is read by manpath to configure the mandatory manpath, to
+# map each path element to a manpath element and to determine where the
+# "man" binary lives. The format is:
+#
+# MANBIN pathname
+# MANDATORY_MANPATH manpath_element
+# MANPATH_MAP path_element manpath_element
+#
+# MANBIN is optional
+#
+#MANBIN /usr/local/bin/man
+#
+# every automatically generated MANPATH includes these fields
+#
+MANDATORY_MANPATH /usr/share/man
+MANDATORY_MANPATH /usr/local/man
+#MANDATORY_MANPATH /usr/X386/man
+MANDATORY_MANPATH /usr/X11R6/man
+#
+# set up PATH to MANPATH mapping
+#
+MANPATH_MAP /bin /usr/share/man
+MANPATH_MAP /usr/bin /usr/share/man
+MANPATH_MAP /usr/ucb /usr/share/man
+MANPATH_MAP /usr/local/mh /usr/local/mh/man
+MANPATH_MAP /usr/local/bin /usr/local/man
+MANPATH_MAP /usr/X386/bin /usr/X386/man
+MANPATH_MAP /usr/X11R6/bin /usr/X11R6/man
diff --git a/gnu/usr.bin/man/manpath/manpath.h b/gnu/usr.bin/man/manpath/manpath.h
new file mode 100644
index 0000000..3039bd9
--- /dev/null
+++ b/gnu/usr.bin/man/manpath/manpath.h
@@ -0,0 +1,26 @@
+/*
+ * manpath.h
+ *
+ * Copyright (c) 1990, 1991, John W. Eaton.
+ *
+ * You may distribute under the terms of the GNU General Public
+ * License as specified in the file COPYING that comes with the man
+ * distribution.
+ *
+ * John W. Eaton
+ * jwe@che.utexas.edu
+ * Department of Chemical Engineering
+ * The University of Texas at Austin
+ * Austin, Texas 78712
+ */
+
+typedef struct
+{
+ char mandir[MAXPATHLEN];
+ char bin[MAXPATHLEN];
+ int mandatory;
+} DIRLIST;
+
+DIRLIST list[MAXDIRS];
+
+char *tmplist[MAXDIRS];
diff --git a/gnu/usr.bin/man/manpath/manpath.man b/gnu/usr.bin/man/manpath/manpath.man
new file mode 100644
index 0000000..9212324
--- /dev/null
+++ b/gnu/usr.bin/man/manpath/manpath.man
@@ -0,0 +1,56 @@
+.\" Man page for manpath
+.\"
+.\" Copyright (c) 1990, 1991, John W. Eaton.
+.\"
+.\" You may distribute under the terms of the GNU General Public
+.\" License as specified in the README file that comes with the man 1.0
+.\" distribution.
+.\"
+.\" John W. Eaton
+.\" jwe@che.utexas.edu
+.\" Department of Chemical Engineering
+.\" The University of Texas at Austin
+.\" Austin, Texas 78712
+.\"
+.TH manpath 1 "Jan 5, 1991"
+.LO 1
+.SH NAME
+manpath \- determine user's search path for man pages
+.SH SYNOPSIS
+manpath [\-q]
+.SH DESCRIPTION
+manpath tries to determine the user's manpath from a set of system
+defaults and the user's
+.B PATH ,
+echoing the result to the standard output. Warnings and errors are
+written to the standard error.
+If a directory in the user's path is not listed in the manpath.config
+file, manpath looks for the subdirectories man or MAN. If they exist,
+they are added to the search path.
+.PP
+manpath is used by
+.B man
+to determine the search path, so user's normally don't need to set the
+.B MANPATH
+environment variable directly.
+.SH OPTIONS
+.TP
+.B \-\^q
+Operate quietly. Only echo the final manpath.
+.SH ENVIRONMENT
+.TP \w'MANPATH\ \ 'u
+.B MANPATH
+If
+.B MANPATH
+is set,
+.B manpath
+echoes its value on the standard output and issues a warning on the
+standard error.
+.SH FILES
+.TP \w'%manpath_config_file%'u+2n
+.BI %manpath_config_file%
+System configuration file.
+.SH "SEE ALSO"
+apropos(1), whatis(1), man(1).
+.SH BUGS
+None known.
diff --git a/gnu/usr.bin/man/whatis/Makefile b/gnu/usr.bin/man/whatis/Makefile
new file mode 100644
index 0000000..6fb62a2
--- /dev/null
+++ b/gnu/usr.bin/man/whatis/Makefile
@@ -0,0 +1,6 @@
+# $Id$
+
+SHPROG= whatis
+
+.include "../../Makefile.inc"
+.include "../Makefile.shprog"
diff --git a/gnu/usr.bin/man/whatis/whatis.man b/gnu/usr.bin/man/whatis/whatis.man
new file mode 100644
index 0000000..9e5528d
--- /dev/null
+++ b/gnu/usr.bin/man/whatis/whatis.man
@@ -0,0 +1,27 @@
+.\" Man page for whatis
+.\"
+.\" Copyright (c) 1990, 1991, John W. Eaton.
+.\"
+.\" You may distribute under the terms of the GNU General Public
+.\" License as specified in the README file that comes with the man 1.0
+.\" distribution.
+.\"
+.\" John W. Eaton
+.\" jwe@che.utexas.edu
+.\" Department of Chemical Engineering
+.\" The University of Texas at Austin
+.\" Austin, Texas 78712
+.\"
+.TH whatis 1 "Jan 5, 1991"
+.LO 1
+.SH NAME
+whatis \- search the whatis database for complete words.
+.SH SYNOPSIS
+.BI whatis
+keyword ...
+.SH DESCRIPTION
+whatis searches a set of database files containing short descriptions
+of system commands for keywords and displays the result on the
+standard output. Only complete word matches are displayed.
+.SH "SEE ALSO"
+apropos(1), man(1).
diff --git a/gnu/usr.bin/man/whatis/whatis.sh b/gnu/usr.bin/man/whatis/whatis.sh
new file mode 100644
index 0000000..34abaaa
--- /dev/null
+++ b/gnu/usr.bin/man/whatis/whatis.sh
@@ -0,0 +1,66 @@
+#!/bin/sh
+#
+# whatis -- search the whatis database for keywords. Like apropos,
+# but match only commands (as whole words).
+#
+# Copyright (c) 1990, 1991, John W. Eaton.
+#
+# You may distribute under the terms of the GNU General Public
+# License as specified in the README file that comes with the man
+# distribution.
+#
+# John W. Eaton
+# jwe@che.utexas.edu
+# Department of Chemical Engineering
+# The University of Texas at Austin
+# Austin, Texas 78712
+
+PATH=/usr/local/bin:/bin:/usr/ucb:/usr/bin
+
+libdir=%libdir%
+
+if [ $# = 0 ]
+then
+ echo "usage: `basename $0` name ..."
+ exit 1
+fi
+
+manpath=`%bindir%/manpath -q | tr : '\040'`
+
+if [ "$manpath" = "" ]
+then
+ echo "whatis: manpath is null"
+ exit 1
+fi
+
+if [ "$PAGER" = "" ]
+then
+ PAGER="%pager%"
+fi
+
+while [ $1 ]
+do
+ found=0
+ for d in $manpath /usr/lib
+ do
+ if [ -f $d/whatis ]
+ then
+ grep -iw "^$1" $d/whatis
+ status=$?
+ if [ "$status" = "0" ]
+ then
+ found=1
+ export found;
+ fi
+ fi
+ done
+
+ if [ "$found" = "0" ]
+ then
+ echo "$1: nothing appropriate"
+ fi
+
+ shift
+done | $PAGER
+
+exit
diff --git a/gnu/usr.bin/mkisofs/COPYING b/gnu/usr.bin/mkisofs/COPYING
new file mode 100644
index 0000000..946cb19
--- /dev/null
+++ b/gnu/usr.bin/mkisofs/COPYING
@@ -0,0 +1,345 @@
+ The GPL below is copyrighted by the Free Software
+ Foundation, but the instance of code that it refers to (the mkisofs
+ utility is copyrighted by Yggdrasil Computing, Incorporated).
+
+----------------------------------------
+
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 675 Mass Ave, Cambridge, MA 02139, USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ Appendix: How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) 19yy <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) 19yy name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/gnu/usr.bin/mkisofs/ChangeLog b/gnu/usr.bin/mkisofs/ChangeLog
new file mode 100644
index 0000000..8dc41be
--- /dev/null
+++ b/gnu/usr.bin/mkisofs/ChangeLog
@@ -0,0 +1,695 @@
+Sun Feb 26 01:52:06 1995 Eric Youngdale (eric@largo)
+
+ * Add patches from Ross Biro to allow you to merge arbitrary
+ trees into the image. This is not compiled in by default but
+ you need to add -DADD_FILES when compiling.
+
+Fri Feb 17 02:29:03 1995 Paul Eggert <eggert@twinsun.com>
+
+ * tree.c: Port to Solaris 2.4. Prefer <sys/mkdev.h> if
+ HASMKDEV. Cast unknown integer types to unsigned long and
+ print them with %lu or %lx.
+
+Thu Jan 26 15:25:00 1995 H. Peter Anvin (hpa@yggdrasil.com)
+
+ * mkisofs.c: Substitute underscore for leading dot in non-Rock
+ Ridge filenames, since MS-DOS cannot read files whose names
+ begin with a period.
+
+Mon Jan 16 18:31:41 1995 Eric Youngdale (eric@aib.com)
+
+ * rock.c (generate_rock_ridge_attributes): Only use ROOT
+ record for symlinks if we are at the start of the symlink.
+ Otherwise just generate an empty entry.
+
+Mon Jan 16 16:19:50 1995 Eric Youngdale (eric@aib.com)
+
+ * diag/isodump.c: Use isonum_733 instead of trying to dereference
+ pointers when trying to decode 733 numbers in the iso9660 image.
+
+ * diag/isovfy.c: Likewise.
+
+ * write.c: Always assign an extent number, even for zero length
+ files. A zero length file with a NULL extent is apparently dropped
+ by many readers.
+
+Wed Jan 11 13:46:50 1995 Eric Youngdale (eric@aib.com)
+
+ * mkisofs.c: Modify extension record to conform to IEEE P1282
+ specifications. This is commented out right now, but a trivial
+ change to a #define enables this. I need to see the specs
+ to see whether anything else changed before this becomes final.
+
+ * write.c (FDECL4): Fix so that we properly determine error
+ conditions.
+
+ * mkisofs.h: Change rr_attributes to unsigned.
+
+ * tree.c(increment_nlink): Change pnt since rr_attributes is now
+ unsigned.
+
+ Ultrix patches from petav@argon.e20.physik.tu-muenchen.de (Peter Averkamp)
+
+ * rock.c: Fix for ultrix systems, we have 64 bit device numbers.
+ Type cast when generating file size. Change rr_attributes to
+ unsigned.
+
+ * mkisofs.c: For ultrix systems, define our own function
+ for strdup.
+
+ * mkisofs.c: Fix usage() since some compilers do not concatenate
+ strings properly (i.e. ultrix).
+
+ Bugs found with Sentinel II:
+
+ * write.c: Fix a couple of memory leaks.
+
+ * mkisofs.c: Bugfix - always put a zero byte at end of name
+ for ".." entry.
+
+ * tree.c: Set isorec.date from fstatbuf.st_ctime, not current_time,
+ since current_time might not be set.
+
+Sat Dec 3 14:55:42 1994 Eric Youngdale (eric@andante)
+
+ * mkisofs.c: When returning entry for ".." file, set second byte
+ to 0.
+
+ * write.c: Free name and rr_attributes fields when writing.
+
+Mon Nov 28 13:36:27 1994 Eric Youngdale (eric@andante)
+
+ * mkisofs.h: Change rr_attributes to unsigned.
+
+ * rock.c: Ditto. Work around >>32 bug in ultrix for 64 bit data types.
+
+ * mkisofs.c (usage): Fix for ultrix - use continuation lines
+ instead of assuming that strings are catenated by the compiler.
+
+Mon Jun 20 20:25:26 1994 Eric Youngdale (eric@esp22)
+
+ * mkisofs.c, mkisofs.8, Makefile (version_string): Bump to pre-1.02.
+
+ * mkisofs.h: Fix declaration of e_malloc to use DECL macros.
+
+ * tree.c: Fix bug in previous change.
+
+ * diag/*.c: Add appropriate copyright notices.
+
+Sat Apr 9 13:30:46 1994 Eric Youngdale (ericy@cais.com)
+
+ * Configure: New file - shell script that determines a bunch of
+ things to properly build mkisofs.
+
+ * Makefile.in: New file - copy of Makefile, but Configure sets a
+ few things up for it.
+
+ * tree.c: Do not depend upon opendir to return NULL if we cannot
+ open a directory - actually try and read the first entry. The
+ foibles of NFS seem to require this.
+
+ * write.c: Fix definition of xfwrite (Use FDECL4)
+
+ Add some changes to allow more configurability of some of the
+ volume header fields:
+
+ * mkisofs.8: Document new configuration options.
+
+ * mkisofs.c: Add variables to hold new fields. Add function to
+ read .mkisofsrc files.
+
+ * defaults.h: Another way of configuring the same things.
+
+ Add some changes from Leo Weppelman leo@ahwau.ahold.nl.
+
+ * mkisofs.c: Allow -A to specify application ID. Fix usage(),
+ getopt and add case switch.
+
+ * rock.c: Fix handling of device numbers (dev_t high should only
+ be used when sizeof(dev_t) > 32 bits).
+
+ Add a bunch of changes from Manuel Bouyer.
+
+ * diag/Makefile: New file.
+
+ * diag/dump.c, diag/isodump.c: Use termios if system supports it.
+
+ * (throughout): Replace all occurences of "malloc" with e_malloc.
+
+ * mkisofs.c: For NetBSD, attempt to increase the rlimit for
+ the size of the data segment to about 33 Mb.
+
+ * mkisofs.c (e_malloc): New function. Calls malloc, and prints
+ nice error message and exits if NULL is returned.
+
+Sun Jan 23 19:23:57 1994 Eric Youngdale (eric@esp22)
+
+ * mkisofs.c, mkisofs.8, Makefile (version_string): Bump to 1.01.
+
+ Add a bunch of stuff so that mkisofs will work on a VMS system.
+
+ * (ALL): Change any direct use of the "st_ino" field from
+ the statbuf to use a macro.
+
+ * mkisofs.h: Define appropriate macros for both VMS and unix.
+
+ * (ALL): Add type casts whenever we use the UNCACHED_DEV macro.
+
+ * rock.c: Wrap a #ifndef VMS around block and character device
+ stuff.
+
+ * write.c: Add prototype for strdup if VMS is defined.
+
+ * make.com: Script for building mkisofs on a VMS system.
+
+ * Makefile: Include make.com in the distribution.
+
+ * mkisofs.c: Include <sys/type.h> on VMS systems.
+
+ * tree.c: Include <sys/file.h> and "vms.h" on VMS systems.
+
+ * mkisofs.h (PATH_SEPARATOR, SPATH_SEPARATOR): New macros
+ that define the ascii character that separates the last directory
+ component from the filename.
+
+ * tree.c, mkisofs.c: Use them.
+
+ * vms.c: New file. Contains version of getopt, strdup, opendir,
+ readdir and closedir.
+
+ * vms.h: New file. Defines S_IS* macros. Define gmtime as
+ localtime, since gmtime under VMS returns NULL.
+
+Sat Jan 15 13:57:42 1994 Eric Youngdale (eric@esp22)
+
+ * mkisofs.h (transparent_compression): New prototype.
+
+ * mkisofs.c (transparent_compression): Declare, use
+ '-z' option to turn on.
+
+ * tree.c: Change TRANS.TBL;1 to TRANS.TBL (version gets
+ added later, if required).
+
+ * rock.c: If transparent compression requested, verify
+ file is really suitable (check magic numbers), and extract
+ correct file length to store in SUSP record.
+
+Sat Jan 15 01:57:42 1994 Eric Youngdale (eric@esp22)
+
+ * write.c (compare_dirs): Bugfix for patch from Jan 6.
+
+ * mkisofs.h (struct directory_entry): Add element total_rr_attr_size.
+ (struct file_hash): Add element ce_bytes.
+
+ * write.c (iso_write): Update last_extent_written, as required,
+ and check it against last_extent as a sanity check.
+ (generate_one_directory): If ce_bytes is non-zero, allocate
+ a buffer and fill it with the CE records. Also, update
+ the extent and offset entries in the CE SUSP field and
+ output after directory is written.
+ (assign_directory_addresses): Allow for CE sectors after each
+ directory.
+
+ * tree.c (sort_n_finish): Set field ce_bytes by summing
+ the sizes of all CE blocks in each files RR attributes.
+ Do not count these bytes for main directory.
+
+ * rock.c (generate_rock_ridge_attributes): Generate
+ CE entries to break up large records into manageable sizes.
+ Allow long names to be split, and allow long symlinks to be split.
+ Allow splitting before each SUSP field as well, to make
+ sure we do not screw outselves.
+
+Thu Jan 6 21:47:43 1994 Eric Youngdale (eric@esp22)
+
+ Bugfix.
+
+ * write.c (compare_dirs): Only compare directory names up to
+ the ';' for the version number.
+
+ Add four new options: (1) Full 31 character filenames,
+ (2) Omit version number, (3) Omit trailing period from filenames,
+ (4) Skip deep directory relocation.
+
+ * iso9660.h: Allow 34 characters for filename.
+
+ * mkisofs.8: Update for new options.
+
+ * mkisofs.c: Add flag variables for new options.
+ Mention new options in usage(), tell getopt about
+ new options, and set appropriate flags when
+ new options are specified.
+
+ * mkisofs.c (iso9660_file_length): Implement new options.
+
+ * mkisofs.h: Declare flag variables for new options.
+
+ * tree.c (sort_n_finish): Increase declaration of newname and
+ rootname to 34 characters. If full_iso9660_filenames in effect,
+ use different rules for making unique names.
+
+ * tree.c (scan_directory_tree): Use RR_relocation_depth instead of
+ constant for threshold for starting deep directory relocation.
+
+Wed Jan 5 01:32:34 1994 John Brezak (brezak@ch.hp.com)
+
+ * Makefile.bsd: New file. For NetBSD.
+
+ * rock.c, tree.c: Do not include sys/sysmacros.h for NetBSD.
+
+Fri Dec 31 13:22:52 1993 Eric Youngdale (eric@esp22)
+
+ * mkisofs.c, mkisofs.8, Makefile (version_string): Bump to 1.00.
+
+ * tree.c (scan_directory_tree): Handle case where we do not
+ have permissions to open a directory.
+
+ * write.c (xfwrite): New function - wrapper for fwrite,
+ except that we print message and punt if write fails.
+
+ * write.c: Move include of mkisofs.h and iso9660.h until after
+ string.h and stdlib.h is included.
+
+ * write.c: Do not attempt to use strerror on sun systems.
+
+Thu Dec 9 13:17:28 1993 R.-D. Marzusch (marzusch@odiehh.hanse.de)
+
+ * exclude.c, exclude.h: New files. Contains list of files to
+ exclude from consideration.
+
+ * Makefile: Compile exclude.c, add dependencies to other files.
+
+ * mkisofs.8: Describe -x option.
+
+ * mkisofs.c: Include exclude.h, handle -x option.
+
+
+Fri Dec 10 01:07:43 1993 Peter van der Veen (peterv@qnx.com)
+
+ * mkisofs.c, mkisofs.h: Moved declaration of root_record.
+
+ * mkisofs.h: Added prototype for get_733().
+
+ * write.c(iso_write), tree.c, rock.c(generate_rock_ridge_attributes):
+ Added defines for QNX operation system
+
+ * rock.c(generate_rock_ridge_attributes): symbolic links should
+ not have CONTINUE component flag set unless there are multiple
+ component records, and mkisofs does not generate these.
+ st_ctime was stored as the creation time, changed to attribute time.
+ QNX has a creation time, so that is stored as well under QNX.
+
+Thu Oct 28 19:54:38 1993 Eric Youngdale (eric@kafka)
+
+ * mkisofs.c, Makefile (version_string): Bump to 0.99.
+
+ * write.c(iso_write): Put hour, minute, second into date fields in
+ volume descriptor.
+
+ * write.c (iso_write): Set file_structure_version to 1, instead of
+ ' ' (Seems to screw up Macs).
+
+Sun Oct 17 01:13:36 1993 Eric Youngdale (eric@kafka)
+
+ * mkisofs.c, Makefile (version_string): Bump to 0.98.
+
+ Increment nlink in root directory when rr_moved directory is present.
+
+ * tree.c (increment_nlink): New function.
+
+ * tree.c (finish_cl_pl_entries): Call increment_nlink for all
+ references to the root directory.
+
+ * tree.c (root_statbuf): New variable.
+
+ * tree.c (scan_directory_tree): Initialize root_statbuf when we
+ stat the root directory.
+
+ * tree.c (generate_reloc_directory): Use root_statbuf when
+ generating the Rock Ridge stuff for the ".." entry in the
+ reloc_dir.
+
+ * tree.c (scan_directory_tree): Use root_statbuf when generating
+ the ".." entry in the root directory.
+
+Sat Oct 16 10:28:30 1993 Eric Youngdale (eric@kafka)
+
+ Fix path tables so that they are sorted.
+
+ * tree.c (assign_directory_addresses): Move to write.c
+
+ * write.c (generate_path_tables): Create an array of pointers to
+ the individual directories, and sort it based upon the name and
+ the parent path table index. Then update all of the indexes and
+ repeat the sort until the path table indexes no longer need to be
+ changed, and then write the path table.
+
+ Fix problem where hard links were throwing off the total extent count.
+
+ * write.c (iso_write): Call assign_file_addresses, and then
+ use last_extent to determine how big the volume is.
+
+ * write.c (generate_one_directory): Decrement n_data_extents
+ for hard links to non-directories so that the expected number
+ of extents is written correctly.
+
+ * write.c(assign_file_addresses): New function.
+
+Fri Oct 15 22:35:43 1993 Eric Youngdale (eric@kafka)
+
+ The standard says we should do these things:
+
+ * tree.c (generate_reloc_directory): Add RR attributes to
+ the rr_moved directory.
+
+ * mkisofs.c(main): Change ER text strings back to recommended
+ values.
+
+Tue Oct 12 21:07:38 1993 Eric Youngdale (eric@kafka)
+
+ * mkisofs.c, Makefile (version_string): Bump to 0.97.
+
+ * tree.c (scan_directory_tree): Do not insert PL entry into
+ root directory record (i.e. !parent)
+
+ * tree.c (finish_cl_pl_entries): Do not rely upon name
+ comparison to locate parent - use d_entry->self instead,
+ which is guaranteed to be correct.
+
+ * mkisofs.h: New variable n_data_extents.
+
+ * tree.c: Declare and initialize n_data_extents to 0.
+ (scan_directory_tree) for non-directories, add
+ ROUND_UP(statbuf.st_size) to n_data_extents.
+ (sort_n_finish): Increment n_data_extents for translation tables,
+ as appropriate.
+
+ * write.c(iso_write): Add n_data_extents to the
+ volume_space_size field.
+
+ * hash.c(add_hash): If size != 0 and extent == 0, or
+ if size == 0 and extent != 0, then complain about
+ inserting this into the hash table. Kind of a sanity check.
+
+Sat Oct 9 16:39:15 1993 Eric Youngdale (eric@kafka)
+
+ * mkisofs.c, Makefile (version_string): Bump to 0.96.
+
+ Numerous bugfixes, thanks to a one-off disc from rab@cdrom.com.
+
+ * write.c(generate_one_directory): Wait until after we have
+ filled in the starting_extent field to s_entry before calling
+ add_hash. This fixes a problem where the hash table gets an
+ extent of 0 for all regular files, and this turns up when you have
+ hard links on the disc. (The hash table allows us to have each
+ hard link point to the same extent on the cdrom, thereby saving
+ some space).
+
+ * tree.c(scan_directory_tree): Set statbuf.st_dev and
+ statbuf.st_ino to the UNCACHED numbers for symlinks that we
+ are not following. This prevents the function find_hash from
+ returning an inode that cooresponds to the file the symlink points
+ to, which in turn prevents generate_one_directory from filling in
+ a bogus file length (should be zero for symlinks).
+
+ * tree.c(scan_directory_tree): Always call lstat for the file
+ so that non-RockRidge discs get correct treatment of symlinks.
+ Improve error message when we ignore a symlink on a non-RR disc.
+
+ * write.c(generate_one_directory): Set fields for starting_extent
+ and size in the "." and ".." entries before we add them to the
+ file hash. Fixes problems with incorrect backlinks for second
+ level directories.
+
+Wed Oct 6 19:53:40 1993 Eric Youngdale (eric@kafka)
+
+ * write.c (write_one_file): Print message and punt if we are
+ unable to open the file.
+
+ * tree.c(scan_directory_tree): For regular files, use the access
+ function to verify that the file is readable in the first place.
+ If not, issue a warning and skip it. For directories, it probably
+ does not matter, since we would not be able to descend into them
+ in the first place.
+
+Wed Sep 29 00:02:47 1993 Eric Youngdale (eric@kafka)
+
+ * mkisofs.c, Makefile (version_string): Bump to 0.95.
+
+ * write.c, tree.c: Cosmetic changes to printed information.
+
+ * tree.c(scan_directory_tree): Set size to zero for
+ special stub entries that correspond to the
+ relocated directories. Hopefully last big bug.
+
+ * mkisofs.h: Change TABLE_INODE, UNCACHED_* macros
+ to be 0x7fff... to be compatible with signed datatypes.
+
+Mon Sep 27 20:14:49 1993 Eric Youngdale (eric@kafka)
+
+ * mkisofs.c, Makefile (version_string): Bump to 0.94.
+
+ * write.c (write_path_tables): Actually search the
+ directory for the matching entry in case we renamed
+ the directory because of a name conflict.
+
+ * tree.c(scan_directory_tree): Take directory_entry pointer
+ as second argument so that we can create a backpointer
+ in the directory structure that points back to the original
+ dir.
+
+ * mkisofs.c: Fix call to scan_directory_tree to use new calling
+ sequence.
+
+ * write.c(generate_one_directory): Punt if the last_extent counter
+ ever exceeds 700Mb/2048. Print name of responsible file,
+ extent counter, and starting extent. Perhaps we can catch it in
+ the act.
+
+Sun Sep 26 20:58:05 1993 Eric Youngdale (eric@kafka)
+
+ * mkisofs.c, Makefile (version_string): Bump to 0.93.
+
+ * tree.c(scan_directory_tree): Handle symlinks better. Either
+ leave them as symlinks, or erase any trace that they were a
+ symlink but do not do it 1/2 way as before. Also, watch for
+ directory loops created with symlinks.
+
+ * mkisofs.h: Add new flag follow_links.
+
+ * mkisofs.c: Add command line switch "-f" to toggle follow_links.
+
+ * mkisofs.8: Document new switch.
+
+ * tree.c: Add code to handle symlinks using new flag.
+
+ * hash.c: Add add_directory_hash, find_directory_hash functions.
+
+ * mkisofs.h: Add prototypes.
+
+Sat Sep 25 14:26:31 1993 Eric Youngdale (eric@kafka)
+
+ * mkisofs.c, Makefile (version_string): Bump to 0.92.
+
+ * mkisofs.c: Make sure path is an actual directory before trying
+ to scan it.
+
+ * mkisofs.h: Add DECL and FDECL? macros for sparc like systems.
+ Do proper define of optind and optarg under SVr4.
+
+ * tree.c: Change translation table name from YMTRANS.TBL to TRANS.TBL.
+
+ * mkisofs.c: Neaten up message in extension record when RRIP is
+ in use.
+
+ * Throughout - change all function declarations so that
+ traditional C compilers (i.e. sparc) will work.
+
+ * Makefile: Change to use system default C compiler.
+
+ * mkisofs.c: Add some stuff so that this will compile under VMS.
+ Many things missing for VMS still.
+
+ * iso9660.h: Do not use zero length array in struct definition.
+
+ * tree.c (sort_n_finish): Account for this.
+
+ * Change copyright notice.
+
+
+Wed Aug 25 08:06:51 1993 Eric Youngdale (eric@kafka)
+
+ * mkisofs.c, Makefile (version_string): Bump to 0.91.
+
+ * mkisofs.h: Only include sys/dir.h for linux. Other systems
+ will need other things.
+
+ * mkisofs.c, tree.c: Include unistd.h.
+
+ * Makefile: Use OBJS to define list of object files.
+
+Sun Aug 22 20:55:17 1993 Eric Youngdale (eric@kafka)
+
+ * mkisofs.c, Makefile (version_string): Bump to 0.9.
+
+ * write.c (iso_7*): Fix so that they work properly on Motorola
+ systems.
+
+Fri Aug 20 00:14:36 1993 Eric Youngdale (eric@kafka)
+
+ * mkisofs.c, Makefile (version_string): Bump to 0.8.
+
+ * rock.c: Do not mask off write permissions from posix file modes.
+
+Wed Aug 18 09:02:12 1993 Eric Youngdale (eric@kafka)
+
+ * mkisofs.c, Makefile (version_string): Bump to 0.7.
+
+ * rock.c: Do not write NM field for . and .. (redundant and a
+ waste of space).
+
+ * mkisofs.c: Take -P and -p options for publisher and preparer id
+ fields.
+
+ * write.c: Store publisher and preparer id in volume
+ descriptor.
+
+ * rock.c: Write optional SP field to identify SUSP. Write
+ optional CE field to point to the extension header.
+
+ * tree.c: Request SP and CE fields be added to root directory.
+
+ * tree.c: Fix bug in name conflict resolution.
+
+ * write.c: Fill in date fields in the colume descriptor.
+
+ * write.c (write_one_file): If the file is large enough, write in
+ chunks of 16 sectors to improve performance.
+
+ * hash.c (add_hash, find_hash, etc): Do not hash s_entry, instead
+ store relevant info in hash structure (we free s_entry structs as
+ we write files, and we need to have access to the hash table the
+ whole way through.
+
+ * write.c: Add a few statistics about directory sizes, RR sizes,
+ translation table sizes, etc.
+
+ * tree.c: Use major, not MAJOR. Same for minor. Define S_ISSOCK
+ and S_ISLNK if not defined.
+
+ * rock.c: Define S_ISLNK if not defined.
+
+ * mkisofs.c: Print out max memory usage. Fix bug in call to getopt.
+
+ * mkisofs.c, Makefile (version_string): Bump to 0.6.
+
+ * tree.c: Simplify the calculation of isorec.len, isorec.name_len
+ and the calculation of the path table sizes by doing it all at
+ one point after conflict resolution is done.
+
+ * tree.c: scan_directory_tree is now responsible for generating
+ the line that goes into the YMTRANS.TBL file. These lines are
+ collected later on into something that will be dumped to the
+ file. Correctly handle all of the special file types.
+
+Mon Aug 16 21:59:47 1993 Eric Youngdale (eric@kafka)
+
+ * mkisofs.c, Makefile (version_string): Bump to 0.5.
+
+ * mkisofs.c: Add -a option (to force all files to be
+ transferred). Remove find_file_hash stuff.
+
+ * write.c: Pad length even if Rock Ridge is not in use.
+
+ * hash.c: Rewrite hash_file_* stuff so that it can be used to
+ easily detect (and look up) filenames that have been accepted
+ for use in this directory. Used for name collision detection.
+
+ * tree.c (sort_n_finish): If two names collide, generate a unique
+ one (verified with the hash routines). Change the lower priority
+ name if there is a difference.
+
+
+
+Sat Aug 14 13:18:21 1993 Eric Youngdale (eric@kafka)
+
+ * mkisofs.c, Makefile (version_string): Bump to 0.4.
+
+ * tree.c (load_translation_table): New function - read
+ YMTRANS.TBL. (scan_directory_tree) Call it.
+
+ * mkisofs.c (iso9660_file_length): Call find_file_hash to see
+ if translated name is specified. If so, use it.
+
+ * hash.c (name_hash, add_file_hash, find_file_hash,
+ flush_file_hash): New functions for hashing stuff from
+ YMTRANS.TBL.
+
+ * mkisofs.h: Add a bunch of prototypes for the new functions.
+
+ * mkisofs.8: Update.
+
+ * mkisofs.c, Makefile (version_string): Bump to 0.3.
+
+ * Makefile: Add version number to tar file in dist target.
+
+ * mkisofs.c: Call finish_cl_pl_entries() after directories have
+ been generated, and extent numbers assigned.
+
+ * write.c (generate_one_directory): Update s_entry->size for
+ directories (as well as isorec.size).
+
+ * rock.c: Add code to generate CL, PL, and RE entries. The
+ extent numbers for the CL and PL entries are NULL, and these
+ are filled in later once we know where they actually belong.
+
+ * mkisofs.h: Add parent_rec to directory_entry. Used to fix CL/PL
+ stuff.
+
+ * tree.c (scan_directory_tree): Set flag to generate CL/PL/RE
+ entries as required, update sizes as well.
+
+Fri Aug 13 19:49:30 1993 Eric Youngdale (eric@kafka)
+
+ * mkisofs.c (version_string): Bump to 0.2.
+
+ * hash.c: Do not use entries with inode == 0xffffffff or dev ==
+ 0xffff.
+
+ * write.c (write_path_tables): Strip leading directory specifications.
+
+ * mkisofs.h: Add definition for reloc_dir symbol. Add prototype
+ for sort_n_finish, add third parameter to scan_directory_tree
+ (for true parent, when directories are relocated).
+
+ * mkisofs.c (main): Modify call to scan_directory_tree. Call
+ sort_n_finish for reloc_dir.
+
+ * tree.c (sort_n_finish): New function - moved code from
+ scan_directory_tree.
+
+ * tree.c (generate_reloc_directory): New function. Generate
+ directory to hold relocated directories.
+
+ * tree.c (scan_directory_tree): Strip leading directories when
+ generating this_dir->name. If depth is too great, then move
+ directory to reloc_dir (creating if it does not exist, and leave
+ a dummy (non-directory) entry in the regular directory so that
+ we can eventually add the required Rock Ridge record.
+
+ * tree.c (scan_directory_tree): Use s_entry instead of sort_dir,
+ assign to this_dir->contents sooner.
+
+Thu Aug 12 22:38:17 1993 Eric Youngdale (eric@kafka)
+
+ * mkisofs.c (usage): Fix syntax.
+
+ * mkisofs.c (main): Add new argument to scan_directory_tree
+
+ * tree.c (scan_directory_tree): If directory is at depth 8 or
+ more, create rr_moved directory in main directory.
+
+Mon Jul 26 19:45:47 1993 Eric Youngdale (eric@kafka)
+
+ * mkisofs v 0.1 released.
+
diff --git a/gnu/usr.bin/mkisofs/Configure b/gnu/usr.bin/mkisofs/Configure
new file mode 100755
index 0000000..70151ad
--- /dev/null
+++ b/gnu/usr.bin/mkisofs/Configure
@@ -0,0 +1,43 @@
+#!/bin/sh
+#
+# This script attempts to automatically configure for the host system.
+#
+MKDEV=
+MACROS=
+MALLOC=
+
+if [ -f /usr/include/sys/mkdev.h ]
+then
+MKDEV=-DHASMKDEV
+fi
+
+if [ -f /usr/include/sys/sysmacros.h ]
+then
+MACROS=-DHASSYSMACROS
+fi
+
+if [ -f /usr/include/malloc.h ]
+then
+MALLOC=-DHASMALLOC_H
+fi
+
+#
+# OK, we have all of the configuration stuff done. Now generate the Makefile.
+#
+
+echo XCFLAGS=${MKDEV} ${MACROS} ${MALLOC} > Makefrag
+
+sed -e "/XCFLAGS=/ r Makefrag" Makefile.in > Makefile
+rm -f Makefrag
+
+#
+# Now generate config.h
+#
+rm -rf config.h
+touch config.h
+if [ -f /usr/include/termios.h ]
+then
+echo "#define USE_TERMIOS" >> config.h
+fi
+
+echo "The Makefile is now properly configured for your system." \ No newline at end of file
diff --git a/gnu/usr.bin/mkisofs/Makefile b/gnu/usr.bin/mkisofs/Makefile
new file mode 100644
index 0000000..56639c7
--- /dev/null
+++ b/gnu/usr.bin/mkisofs/Makefile
@@ -0,0 +1,6 @@
+PROG= mkisofs
+MAN8= mkisofs.8
+SRCS= mkisofs.c tree.c write.c hash.c rock.c exclude.c
+CFLAGS+= -D__BSD__
+
+.include <bsd.prog.mk>
diff --git a/gnu/usr.bin/mkisofs/Makefile.in b/gnu/usr.bin/mkisofs/Makefile.in
new file mode 100644
index 0000000..dceb17c
--- /dev/null
+++ b/gnu/usr.bin/mkisofs/Makefile.in
@@ -0,0 +1,51 @@
+#CFLAGS=-g -Wall -c
+#CC=gcc
+
+#
+# XCFLAGS is automatically set by Configure.
+#
+XCFLAGS=
+CFLAGS=-g -c $(XCFLAGS)
+LDFLAGS=
+OBJS=mkisofs.o tree.o write.o hash.o rock.o exclude.o
+
+World: mkisofs
+
+Makefile: Makefile.in Configure
+ ./Configure
+ echo "Type make again to build mkisofs."
+
+mkisofs: Makefile $(OBJS)
+ $(CC) $(LDFLAGS) -o mkisofs $(OBJS)
+
+install: mkisofs mkisofs.8
+ strip mkisofs
+ cp mkisofs /usr/bin/
+ if [ -d /usr/man/man8 ]; then cp mkisofs.8 /usr/man/man8/; fi
+
+tree.o: tree.c mkisofs.h iso9660.h exclude.h
+ $(CC) $(CFLAGS) tree.c
+
+write.o: write.c mkisofs.h iso9660.h
+ $(CC) $(CFLAGS) write.c
+
+hash.o: hash.c mkisofs.h
+ $(CC) $(CFLAGS) hash.c
+
+rock.o: rock.c mkisofs.h iso9660.h
+ $(CC) $(CFLAGS) rock.c
+
+exclude.o: exclude.c exclude.h
+ $(CC) $(CFLAGS) exclude.c
+
+mkisofs.o: mkisofs.c iso9660.h mkisofs.h exclude.h
+ $(CC) $(CFLAGS) mkisofs.c
+
+clean:
+ /bin/rm -f *.o core mkisofs *~ #*#
+ (cd diag/; make clean)
+ (cd cdwrite/; make clean)
+
+dist:
+ tar -cvf - README Configure Makefile.in make.com TODO COPYING ChangeLog *.8 *.c *.h diag cdwrite.old cdwrite-1.5 | gzip > mkisofs-1.04.tar.gz
+
diff --git a/gnu/usr.bin/mkisofs/README b/gnu/usr.bin/mkisofs/README
new file mode 100644
index 0000000..f2f415f
--- /dev/null
+++ b/gnu/usr.bin/mkisofs/README
@@ -0,0 +1,84 @@
+Note:
+ There is a feature which can be optionally compiled into
+mkisofs that allows you to merge arbitrary directory trees into the
+image you are creating. You need to compile with -DADD_FILES for my
+changes to take effect. Thanks to Ross Biro biro@yggdrasil.com.
+
+ This program requires a lot of virtual memory to run since it
+builds all of the directories in memory. The exact requirements
+depend upon a lot of things, but for Rock Ridge discs 12Mb would not
+be unreasonable. Without RockRidge and without the translation
+tables, the requirements would be considerably less.
+
+ The cdwrite utility is maintained separately from mkisofs by
+yggdrasil.com. It is enclosed here as a convenience, since the two programs
+are often useful together.
+
+*****************************
+Notes for version 1.2.
+
+ Minor bugfixes here and there. Support for compiled in
+defaults for many of the text fields in the volume header are now
+present, and there is also support for a file ".mkisofsrc" that can
+also read settings for these parameters.
+
+ A short script "Configure" was added to allow us to set up special
+compile options that depend upon the system that we are running on.
+This should help stamp out the sphaghetti-isms that were starting to grow
+up in various places in the code.
+
+ You should get more meaningful error messages if you run out of
+memory.
+
+*****************************
+Notes for version 1.1.
+
+ The big news is that SUSP CE entries are now generated for
+extremely long filenames and symlink names. This virtually guarantees
+that there is no limit (OK, well, about 600Mb) for file name lengths.
+I have tested this as well as I can, and it seems to work with linux.
+This would only be used very rarely I suspect.
+
+ Also, I believe that support for VMS is done. You must be
+careful, because only Stream-LF and FIxed length record files can be
+recorded. The rest are rejected with error messages. Perhaps I am
+being too severe here.
+
+ There is a bugfix in the sorting of entries on the disc - we
+need to stop comparing once we reach the ';' character.
+
+ There are four new options -z -d -D -l -V. Some of these tell
+mkisofs to relax some of the iso9660 restrictions, and many systems
+apparently do not really seem to mind. Use these with caution.
+
+ Some diagnostic programs to scan disc images are in the diag
+directory. These are not as portable as mkisofs, and may have some
+bugs. Still they are useful because they can check for bugs that I might
+have introduced as I add new features.
+
+*****************************
+Notes for version 1.0.
+
+ In version 1.0, the date fields in the TF fields were fixed -
+previously I was storing st_ctime as the file creation time instead of
+the file attribute change time. Thanks to Peter van der Veen for
+pointing this out. I have one slight concern with this change,
+however. The Young Minds software is definitely supplying 3 dates
+(creation, modification and access), and I would strongly suspect that
+they are incorrectly putting the file attribute change time in the
+file creation slot. I would be curious to see how the different RRIP
+filesystems treat this. Anyway, this is something to keep in the back
+of your mind.
+
+ The symlink handling was not quite correct in 0.99 - this is
+now fixed. Only some systems seemed to have been affected by this bug.
+
+ A command line option is now present to allow you to
+specifically exclude certain files from the distribution.
+
+ The case where you do not have permissions to read a directory
+is now handled better by mkisofs. The directory that cannot be opened
+is converted into a zero-length file, and processing continues normally.
+
+ A few portability things have been fixed (hopefully).
+
diff --git a/gnu/usr.bin/mkisofs/TODO b/gnu/usr.bin/mkisofs/TODO
new file mode 100644
index 0000000..923f66d
--- /dev/null
+++ b/gnu/usr.bin/mkisofs/TODO
@@ -0,0 +1,15 @@
+ 1) Allow multiple input paths to be concatenated together.
+ This is a little tricky, because the directory entries need to be
+ correctly sorted as per iso9660 specifications. It would be better to
+ force the user to add hard links or copies of the files rather than do
+ the wrong thing. Leave alone for the time being, I am not sure that
+ this feature is really needed.
+
+ 2) For symlinks, we may need to strip out the leading path
+ information if the link is to an absolute file, and the absolute
+ address is in the space that we are dumping to the CDROM. Who the
+ hell knows what we should really do with this, actually. Leave it
+ for now and see if anyone squalks.
+
+ 3) Find out if output needs to be written at a particular
+ blocksize or not.
diff --git a/gnu/usr.bin/mkisofs/config.h b/gnu/usr.bin/mkisofs/config.h
new file mode 100644
index 0000000..0e0ae33
--- /dev/null
+++ b/gnu/usr.bin/mkisofs/config.h
@@ -0,0 +1 @@
+#define USE_TERMIOS
diff --git a/gnu/usr.bin/mkisofs/defaults.h b/gnu/usr.bin/mkisofs/defaults.h
new file mode 100644
index 0000000..03960d1
--- /dev/null
+++ b/gnu/usr.bin/mkisofs/defaults.h
@@ -0,0 +1,34 @@
+/*
+ * Header file defaults.h - assorted default values for character strings in
+ * the volume descriptor.
+ */
+
+#define PREPARER_DEFAULT NULL
+#define PUBLISHER_DEFAULT NULL
+#define APPID_DEFAULT NULL
+#define COPYRIGHT_DEFAULT NULL
+#define BIBLIO_DEFAULT NULL
+#define ABSTRACT_DEFAULT NULL
+#define VOLSET_ID_DEFAULT NULL
+#define VOLUME_ID_DEFAULT "CDROM"
+
+#ifdef __FreeBSD__
+#define SYSTEM_ID_DEFAULT "FreeBSD"
+#endif
+
+#ifdef __QNX__
+#define SYSTEM_ID_DEFAULT "QNX"
+#endif
+
+#ifdef __linux__
+#define SYSTEM_ID_DEFAULT "LINUX"
+#endif
+
+
+#ifdef __osf__
+#define SYSTEM_ID_DEFAULT "OSF"
+#endif
+
+#ifndef SYSTEM_ID_DEFAULT
+#define SYSTEM_ID_DEFAULT "UNKNOWNSYS"
+#endif
diff --git a/gnu/usr.bin/mkisofs/diag/Makefile b/gnu/usr.bin/mkisofs/diag/Makefile
new file mode 100644
index 0000000..e6f3a12
--- /dev/null
+++ b/gnu/usr.bin/mkisofs/diag/Makefile
@@ -0,0 +1,16 @@
+#CC = gcc
+CC = cc -traditional
+
+all: dump isodump isovfy
+
+isoinfo:isoinfo.c
+ ${CC} -g -o isoinfo isoinfo.c
+dump:dump.c
+ ${CC} -o dump dump.c
+isodump:isodump.c
+ ${CC} -o isodump isodump.c
+isovfy:isovfy.c
+ ${CC} -o isovfy isovfy.c
+
+clean:
+ rm -f dump isodump isovfy isoinfo
diff --git a/gnu/usr.bin/mkisofs/diag/README b/gnu/usr.bin/mkisofs/diag/README
new file mode 100644
index 0000000..59b4069
--- /dev/null
+++ b/gnu/usr.bin/mkisofs/diag/README
@@ -0,0 +1,74 @@
+ I am enclosing 3 test programs that I use to verify the
+integrity of an iso9660 disc. The first one (isodump) is pretty
+simple - it dumps to the screen the contents of the various
+directories. The second one (isovfy) goes through and looks for
+problems of one kind or another.
+
+ To use, type something like "./isodump /dev/ramdisk" or
+"./isodump /dev/scd0", depending upon where the iso9660 disc is. It
+starts by displaying the files in the first sector of the root
+directory. It has some pretty simple one letter commands that you
+can use to traverse the directory tree.
+
+ a - move back one sector.
+ b - move forward one sector.
+ g - go to new logical sector.
+ q - quit
+
+The a and b commands do not try and stop you from going past the
+beginning or end of a sector, and the g command does not have any way
+of knowing whether the sector you request is actually a directory or
+not.
+
+ The output is displayed in several columns. The first column
+is the total length of the directory record for the file. The second
+column (in [] brackets) is the volume number. Next comes the starting
+extent number (in hex), and then comes the file size in bytes. Then
+cones the filename (not the Rock Ridge version), and this is preceeded
+by an "*" if the file is a directory. After this is a summary of the
+Rock Ridge fields present along with a display of the translation of
+the symbolic link name if the SL Rock Ridge record is present.
+
+ I tailored this program for debugging some of the problems
+that I was having earlier. The idea is that you can tailor it
+to test for problems that you might be having, so it is not intended
+as a be-all and end-all dump program.
+
+ If you move to a sector that does not contain directory
+information, the results are unpredictable.
+
+ The second program, isovfy, is run in the same way as isodump,
+except that you do not have to do much except let it run. I have it
+written to verify all kinds of different things, and as people find
+other sorts of problems other tests could be added.
+
+ The third program, dump.c, basically does a hexdump of the cd.
+This is screen oriented, and there are some simple commands:
+
+ a - move back one sector.
+ b - move forward one sector.
+ f - enter new search string.
+ + - search forward for search string.
+ g - go to new logical sector.
+ q - quit
+
+
+ Note that with the 'g' command, sectors are always given in
+hex, and represent 2048 byte sectors (as on the cdrom). If you know
+how to decode a raw iso9660 directory, you can pick out the starting
+extent number from the hexdump and know where to go from there. The
+starting extent appears something like 30 bytes prior to the start of
+the iso9660 (not Rock Ridge) filename, and it appears in a 7.3.3
+format (meaning that it occupies 8 bytes, 4 in little endian format,
+and 4 in big endian format). Thus you should see a mirror image of
+the bytes when looking at the extent number.
+
+ The isovfy program can also dump the contents of the path
+tables, but this capability is commented out right now. Feel free
+to enable this to see what is in the tables. Ultimately I may fix
+it so that this checks the integrity of the tables as well.
+
+ The isovfy program gives warnings about things like files that
+have a size of 0 but have an extent number assigned. The mkisofs program
+should never do this, but the YM software does leave these around.
+I think it is probably harmless in the YM case.~
diff --git a/gnu/usr.bin/mkisofs/diag/dump.c b/gnu/usr.bin/mkisofs/diag/dump.c
new file mode 100644
index 0000000..3c28481
--- /dev/null
+++ b/gnu/usr.bin/mkisofs/diag/dump.c
@@ -0,0 +1,201 @@
+/*
+ * File dump.c - dump a file/device both in hex and in ASCII.
+
+ Written by Eric Youngdale (1993).
+
+ Copyright 1993 Yggdrasil Computing, Incorporated
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "../config.h"
+
+#include <stdio.h>
+#ifdef USE_TERMIOS
+#include <termios.h>
+#include <sys/ioctl.h>
+#else
+#include <termio.h>
+#endif
+#include <signal.h>
+
+FILE * infile;
+int file_addr;
+unsigned char buffer[256];
+unsigned char search[64];
+
+#define PAGE 256
+
+#ifdef USE_TERMIOS
+struct termios savetty;
+struct termios newtty;
+#else
+struct termio savetty;
+struct termio newtty;
+#endif
+
+reset_tty(){
+#ifdef USE_TERMIOS
+ if(tcsetattr(0, TCSANOW, &savetty) == -1)
+#else
+ if(ioctl(0, TCSETAF, &savetty)==-1)
+#endif
+ {
+ printf("cannot put tty into normal mode\n");
+ exit(1);
+ }
+}
+
+set_tty(){
+#ifdef USE_TERMIOS
+ if(tcsetattr(0, TCSANOW, &newtty) == -1)
+#else
+ if(ioctl(0, TCSETAF, &newtty)==-1)
+#endif
+ {
+ printf("cannot put tty into raw mode\n");
+ exit(1);
+ }
+}
+
+
+/* Come here when we get a suspend signal from the terminal */
+
+onsusp ()
+{
+ /* ignore SIGTTOU so we don't get stopped if csh grabs the tty */
+ signal(SIGTTOU, SIG_IGN);
+ reset_tty ();
+ fflush (stdout);
+ signal(SIGTTOU, SIG_DFL);
+ /* Send the TSTP signal to suspend our process group */
+ signal(SIGTSTP, SIG_DFL);
+/* sigsetmask(0);*/
+ kill (0, SIGTSTP);
+ /* Pause for station break */
+
+ /* We're back */
+ signal (SIGTSTP, onsusp);
+ set_tty ();
+}
+
+
+
+crsr2(int row, int col){
+ printf("\033[%d;%dH",row,col);
+}
+
+showblock(int flag){
+ unsigned int k;
+ int i, j;
+ lseek(fileno(infile), file_addr, 0);
+ read(fileno(infile), buffer, sizeof(buffer));
+ if(flag) {
+ for(i=0;i<16;i++){
+ crsr2(i+3,1);
+ printf("%8.8x ",file_addr+(i<<4));
+ for(j=15;j>=0;j--){
+ printf("%2.2x",buffer[(i<<4)+j]);
+ if(!(j & 0x3)) printf(" ");
+ };
+ for(j=0;j< 16;j++){
+ k = buffer[(i << 4) + j];
+ if(k >= ' ' && k < 0x80) printf("%c",k);
+ else printf(".");
+ };
+ }
+ };
+ crsr2(20,1);
+ printf(" Zone, zone offset: %6x %4.4x ",file_addr>>11, file_addr & 0x7ff);
+ fflush(stdout);
+}
+
+getbyte()
+{
+ char c1;
+ c1 = buffer[file_addr & (PAGE-1)];
+ file_addr++;
+ if ((file_addr & (PAGE-1)) == 0) showblock(0);
+ return c1;
+}
+
+main(int argc, char * argv[]){
+ char c;
+ int nbyte;
+ int i,j;
+ if(argc < 2) return 0;
+ infile = fopen(argv[1],"rb");
+ for(i=0;i<30;i++) printf("\n");
+ file_addr = 0;
+/* Now setup the keyboard for single character input. */
+#ifdef USE_TERMIOS
+ if(tcgetattr(0, &savetty) == -1)
+#else
+ if(ioctl(0, TCGETA, &savetty) == -1)
+#endif
+ {
+ printf("stdin must be a tty\n");
+ exit(1);
+ }
+ newtty=savetty;
+ newtty.c_lflag&=~ICANON;
+ newtty.c_lflag&=~ECHO;
+ newtty.c_cc[VMIN]=1;
+ set_tty();
+ signal(SIGTSTP, onsusp);
+
+ do{
+ if(file_addr < 0) file_addr = 0;
+ showblock(1);
+ read (0, &c, 1);
+ if (c == 'a') file_addr -= PAGE;
+ if (c == 'b') file_addr += PAGE;
+ if (c == 'g') {
+ crsr2(20,1);
+ printf("Enter new starting block (in hex):");
+ scanf("%x",&file_addr);
+ file_addr = file_addr << 11;
+ crsr2(20,1);
+ printf(" ");
+ };
+ if (c == 'f') {
+ crsr2(20,1);
+ printf("Enter new search string:");
+ fgets(search,sizeof(search),stdin);
+ while(search[strlen(search)-1] == '\n') search[strlen(search)-1] = 0;
+ crsr2(20,1);
+ printf(" ");
+ };
+ if (c == '+') {
+ while(1==1){
+ while(1==1){
+ c = getbyte(&file_addr);
+ if (c == search[0]) break;
+ };
+ for (j=1;j<strlen(search);j++)
+ if(search[j] != getbyte()) break;
+ if(j==strlen(search)) break;
+ };
+ file_addr &= ~(PAGE-1);
+ showblock(1);
+ };
+ if (c == 'q') break;
+ } while(1==1);
+ reset_tty();
+ fclose(infile);
+}
+
+
+
+
diff --git a/gnu/usr.bin/mkisofs/diag/isodump.c b/gnu/usr.bin/mkisofs/diag/isodump.c
new file mode 100644
index 0000000..442c6ed
--- /dev/null
+++ b/gnu/usr.bin/mkisofs/diag/isodump.c
@@ -0,0 +1,436 @@
+/*
+ * File isodump.c - dump iso9660 directory information.
+ *
+
+ Written by Eric Youngdale (1993).
+
+ Copyright 1993 Yggdrasil Computing, Incorporated
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "../config.h"
+
+#include <stdio.h>
+#ifdef USE_TERMIOS
+#include <termios.h>
+#include <sys/ioctl.h>
+#else
+#include <termio.h>
+#endif
+#include <signal.h>
+
+FILE * infile;
+int file_addr;
+unsigned char buffer[2048];
+unsigned char search[64];
+
+#define PAGE sizeof(buffer)
+
+#define ISODCL(from, to) (to - from + 1)
+
+
+int
+isonum_731 (char * p)
+{
+ return ((p[0] & 0xff)
+ | ((p[1] & 0xff) << 8)
+ | ((p[2] & 0xff) << 16)
+ | ((p[3] & 0xff) << 24));
+}
+
+
+int
+isonum_733 (unsigned char * p)
+{
+ return (isonum_731 (p));
+}
+
+struct iso_primary_descriptor {
+ unsigned char type [ISODCL ( 1, 1)]; /* 711 */
+ unsigned char id [ISODCL ( 2, 6)];
+ unsigned char version [ISODCL ( 7, 7)]; /* 711 */
+ unsigned char unused1 [ISODCL ( 8, 8)];
+ unsigned char system_id [ISODCL ( 9, 40)]; /* aunsigned chars */
+ unsigned char volume_id [ISODCL ( 41, 72)]; /* dunsigned chars */
+ unsigned char unused2 [ISODCL ( 73, 80)];
+ unsigned char volume_space_size [ISODCL ( 81, 88)]; /* 733 */
+ unsigned char unused3 [ISODCL ( 89, 120)];
+ unsigned char volume_set_size [ISODCL (121, 124)]; /* 723 */
+ unsigned char volume_sequence_number [ISODCL (125, 128)]; /* 723 */
+ unsigned char logical_block_size [ISODCL (129, 132)]; /* 723 */
+ unsigned char path_table_size [ISODCL (133, 140)]; /* 733 */
+ unsigned char type_l_path_table [ISODCL (141, 144)]; /* 731 */
+ unsigned char opt_type_l_path_table [ISODCL (145, 148)]; /* 731 */
+ unsigned char type_m_path_table [ISODCL (149, 152)]; /* 732 */
+ unsigned char opt_type_m_path_table [ISODCL (153, 156)]; /* 732 */
+ unsigned char root_directory_record [ISODCL (157, 190)]; /* 9.1 */
+ unsigned char volume_set_id [ISODCL (191, 318)]; /* dunsigned chars */
+ unsigned char publisher_id [ISODCL (319, 446)]; /* achars */
+ unsigned char preparer_id [ISODCL (447, 574)]; /* achars */
+ unsigned char application_id [ISODCL (575, 702)]; /* achars */
+ unsigned char copyright_file_id [ISODCL (703, 739)]; /* 7.5 dchars */
+ unsigned char abstract_file_id [ISODCL (740, 776)]; /* 7.5 dchars */
+ unsigned char bibliographic_file_id [ISODCL (777, 813)]; /* 7.5 dchars */
+ unsigned char creation_date [ISODCL (814, 830)]; /* 8.4.26.1 */
+ unsigned char modification_date [ISODCL (831, 847)]; /* 8.4.26.1 */
+ unsigned char expiration_date [ISODCL (848, 864)]; /* 8.4.26.1 */
+ unsigned char effective_date [ISODCL (865, 881)]; /* 8.4.26.1 */
+ unsigned char file_structure_version [ISODCL (882, 882)]; /* 711 */
+ unsigned char unused4 [ISODCL (883, 883)];
+ unsigned char application_data [ISODCL (884, 1395)];
+ unsigned char unused5 [ISODCL (1396, 2048)];
+};
+
+struct iso_directory_record {
+ unsigned char length [ISODCL (1, 1)]; /* 711 */
+ unsigned char ext_attr_length [ISODCL (2, 2)]; /* 711 */
+ unsigned char extent [ISODCL (3, 10)]; /* 733 */
+ unsigned char size [ISODCL (11, 18)]; /* 733 */
+ unsigned char date [ISODCL (19, 25)]; /* 7 by 711 */
+ unsigned char flags [ISODCL (26, 26)];
+ unsigned char file_unit_size [ISODCL (27, 27)]; /* 711 */
+ unsigned char interleave [ISODCL (28, 28)]; /* 711 */
+ unsigned char volume_sequence_number [ISODCL (29, 32)]; /* 723 */
+ unsigned char name_len [ISODCL (33, 33)]; /* 711 */
+ unsigned char name [1];
+};
+
+#ifdef USE_TERMIOS
+struct termios savetty;
+struct termios newtty;
+#else
+struct termio savetty;
+struct termio newtty;
+#endif
+
+reset_tty(){
+#ifdef USE_TERMIOS
+ if(tcsetattr(0, TCSANOW, &savetty) == -1)
+#else
+ if(ioctl(0, TCSETAF, &savetty)==-1)
+#endif
+ {
+ printf("cannot put tty into normal mode\n");
+ exit(1);
+ }
+}
+
+set_tty(){
+#ifdef USE_TERMIOS
+ if(tcsetattr(0, TCSANOW, &newtty) == -1)
+#else
+ if(ioctl(0, TCSETAF, &newtty)==-1)
+#endif
+ {
+ printf("cannot put tty into raw mode\n");
+ exit(1);
+ }
+}
+
+/* Come here when we get a suspend signal from the terminal */
+
+onsusp ()
+{
+ /* ignore SIGTTOU so we don't get stopped if csh grabs the tty */
+ signal(SIGTTOU, SIG_IGN);
+ reset_tty ();
+ fflush (stdout);
+ signal(SIGTTOU, SIG_DFL);
+ /* Send the TSTP signal to suspend our process group */
+ signal(SIGTSTP, SIG_DFL);
+/* sigsetmask(0);*/
+ kill (0, SIGTSTP);
+ /* Pause for station break */
+
+ /* We're back */
+ signal (SIGTSTP, onsusp);
+ set_tty ();
+}
+
+
+
+crsr2(int row, int col){
+ printf("\033[%d;%dH",row,col);
+}
+
+int parse_rr(unsigned char * pnt, int len, int cont_flag)
+{
+ int slen;
+ int ncount;
+ int extent;
+ int cont_extent, cont_offset, cont_size;
+ int flag1, flag2;
+ unsigned char *pnts;
+ char symlink[1024];
+ int goof;
+/* printf(" RRlen=%d ", len); */
+
+ symlink[0] = 0;
+
+ cont_extent = cont_offset = cont_size = 0;
+
+ ncount = 0;
+ flag1 = flag2 = 0;
+ while(len >= 4){
+ if(ncount) printf(",");
+ else printf("[");
+ printf("%c%c", pnt[0], pnt[1]);
+ if(pnt[3] != 1) {
+ printf("**BAD RRVERSION");
+ return;
+ };
+ ncount++;
+ if(pnt[0] == 'R' && pnt[1] == 'R') flag1 = pnt[4] & 0xff;
+ if(strncmp(pnt, "PX", 2) == 0) flag2 |= 1;
+ if(strncmp(pnt, "PN", 2) == 0) flag2 |= 2;
+ if(strncmp(pnt, "SL", 2) == 0) flag2 |= 4;
+ if(strncmp(pnt, "NM", 2) == 0) flag2 |= 8;
+ if(strncmp(pnt, "CL", 2) == 0) flag2 |= 16;
+ if(strncmp(pnt, "PL", 2) == 0) flag2 |= 32;
+ if(strncmp(pnt, "RE", 2) == 0) flag2 |= 64;
+ if(strncmp(pnt, "TF", 2) == 0) flag2 |= 128;
+
+ if(strncmp(pnt, "PX", 2) == 0) {
+ extent = isonum_733(pnt+12);
+ printf("=%x", extent);
+ };
+
+ if(strncmp(pnt, "CE", 2) == 0) {
+ cont_extent = isonum_733(pnt+4);
+ cont_offset = isonum_733(pnt+12);
+ cont_size = isonum_733(pnt+20);
+ printf("=[%x,%x,%d]", cont_extent, cont_offset,
+ cont_size);
+ };
+
+ if(strncmp(pnt, "PL", 2) == 0 || strncmp(pnt, "CL", 2) == 0) {
+ extent = isonum_733(pnt+4);
+ printf("=%x", extent);
+ };
+
+ if(strncmp(pnt, "SL", 2) == 0) {
+ int cflag;
+
+ cflag = pnt[4];
+ pnts = pnt+5;
+ slen = pnt[2] - 5;
+ while(slen >= 1){
+ switch(pnts[0] & 0xfe){
+ case 0:
+ strncat(symlink, pnts+2, pnts[1]);
+ break;
+ case 2:
+ strcat (symlink, ".");
+ break;
+ case 4:
+ strcat (symlink, "..");
+ break;
+ case 8:
+ if((pnts[0] & 1) == 0)strcat (symlink, "/");
+ break;
+ case 16:
+ strcat(symlink,"/mnt");
+ printf("Warning - mount point requested");
+ break;
+ case 32:
+ strcat(symlink,"kafka");
+ printf("Warning - host_name requested");
+ break;
+ default:
+ printf("Reserved bit setting in symlink", goof++);
+ break;
+ };
+ if((pnts[0] & 0xfe) && pnts[1] != 0) {
+ printf("Incorrect length in symlink component");
+ };
+ if((pnts[0] & 1) == 0) strcat(symlink,"/");
+
+ slen -= (pnts[1] + 2);
+ pnts += (pnts[1] + 2);
+
+ };
+ if(cflag) printf("+");
+ printf("=%s", symlink);
+ symlink[0] = 0;
+ };
+
+ len -= pnt[2];
+ pnt += pnt[2];
+ if(len <= 3 && cont_extent) {
+ unsigned char sector[2048];
+ lseek(fileno(infile), cont_extent << 11, 0);
+ read(fileno(infile), sector, sizeof(sector));
+ flag2 |= parse_rr(&sector[cont_offset], cont_size, 1);
+ };
+ };
+ if(ncount) printf("]");
+ if (!cont_flag && flag1 != flag2)
+ printf("Flag %x != %x", flag1, flag2, goof++);
+ return flag2;
+}
+
+int
+dump_rr(struct iso_directory_record * idr)
+{
+ int len;
+ unsigned char * pnt;
+
+ len = idr->length[0] & 0xff;
+ len -= sizeof(struct iso_directory_record);
+ len += sizeof(idr->name);
+ len -= idr->name_len[0];
+ pnt = (unsigned char *) idr;
+ pnt += sizeof(struct iso_directory_record);
+ pnt -= sizeof(idr->name);
+ pnt += idr->name_len[0];
+ if((idr->name_len[0] & 1) == 0){
+ pnt++;
+ len--;
+ };
+ parse_rr(pnt, len, 0);
+}
+
+
+showblock(int flag){
+ unsigned int k;
+ int i, j;
+ int line;
+ struct iso_directory_record * idr;
+ lseek(fileno(infile), file_addr, 0);
+ read(fileno(infile), buffer, sizeof(buffer));
+ for(i=0;i<60;i++) printf("\n");
+ fflush(stdout);
+ i = line = 0;
+ if(flag) {
+ while(1==1){
+ crsr2(line+3,1);
+ idr = (struct iso_directory_record *) &buffer[i];
+ if(idr->length[0] == 0) break;
+ printf("%3d ", idr->length[0]);
+ printf("[%2d] ", idr->volume_sequence_number[0]);
+ printf("%5x ", isonum_733(idr->extent));
+ printf("%8d ", isonum_733(idr->size));
+ printf ((idr->flags[0] & 2) ? "*" : " ");
+ if(idr->name_len[0] == 1 && idr->name[0] == 0)
+ printf(". ");
+ else if(idr->name_len[0] == 1 && idr->name[0] == 1)
+ printf(".. ");
+ else {
+ for(j=0; j<idr->name_len[0]; j++) printf("%c", idr->name[j]);
+ for(j=0; j<14 -idr->name_len[0]; j++) printf(" ");
+ };
+ dump_rr(idr);
+ printf("\n");
+ i += buffer[i];
+ if (i > 2048 - sizeof(struct iso_directory_record)) break;
+ line++;
+ };
+ };
+ printf("\n");
+ printf(" Zone, zone offset: %6x %4.4x ",file_addr>>11, file_addr & 0x7ff);
+ fflush(stdout);
+}
+
+getbyte()
+{
+ char c1;
+ c1 = buffer[file_addr & (PAGE-1)];
+ file_addr++;
+ if ((file_addr & (PAGE-1)) == 0) showblock(0);
+ return c1;
+}
+
+main(int argc, char * argv[]){
+ char c;
+ char buffer[2048];
+ int nbyte;
+ int i,j;
+ struct iso_primary_descriptor ipd;
+ struct iso_directory_record * idr;
+
+ if(argc < 2) return 0;
+ infile = fopen(argv[1],"rb");
+
+ file_addr = 16 << 11;
+ lseek(fileno(infile), file_addr, 0);
+ read(fileno(infile), &ipd, sizeof(ipd));
+
+ idr = (struct iso_directory_record *) &ipd.root_directory_record;
+
+ file_addr = isonum_733(idr->extent);
+
+ file_addr = file_addr << 11;
+
+/* Now setup the keyboard for single character input. */
+#ifdef USE_TERMIOS
+ if(tcgetattr(0, &savetty) == -1)
+#else
+ if(ioctl(0, TCGETA, &savetty) == -1)
+#endif
+ {
+ printf("stdin must be a tty\n");
+ exit(1);
+ }
+ newtty=savetty;
+ newtty.c_lflag&=~ICANON;
+ newtty.c_lflag&=~ECHO;
+ newtty.c_cc[VMIN]=1;
+ set_tty();
+ signal(SIGTSTP, onsusp);
+
+ do{
+ if(file_addr < 0) file_addr = 0;
+ showblock(1);
+ read (0, &c, 1);
+ if (c == 'a') file_addr -= PAGE;
+ if (c == 'b') file_addr += PAGE;
+ if (c == 'g') {
+ crsr2(20,1);
+ printf("Enter new starting block (in hex):");
+ scanf("%x",&file_addr);
+ file_addr = file_addr << 11;
+ crsr2(20,1);
+ printf(" ");
+ };
+ if (c == 'f') {
+ crsr2(20,1);
+ printf("Enter new search string:");
+ fgets(search,sizeof(search),stdin);
+ while(search[strlen(search)-1] == '\n') search[strlen(search)-1] = 0;
+ crsr2(20,1);
+ printf(" ");
+ };
+ if (c == '+') {
+ while(1==1){
+ while(1==1){
+ c = getbyte(&file_addr);
+ if (c == search[0]) break;
+ };
+ for (j=1;j<strlen(search);j++)
+ if(search[j] != getbyte()) break;
+ if(j==strlen(search)) break;
+ };
+ file_addr &= ~(PAGE-1);
+ showblock(1);
+ };
+ if (c == 'q') break;
+ } while(1==1);
+ reset_tty();
+ fclose(infile);
+}
+
+
+
+
diff --git a/gnu/usr.bin/mkisofs/diag/isoinfo.c b/gnu/usr.bin/mkisofs/diag/isoinfo.c
new file mode 100644
index 0000000..3f3b472
--- /dev/null
+++ b/gnu/usr.bin/mkisofs/diag/isoinfo.c
@@ -0,0 +1,522 @@
+/*
+ * File isodump.c - dump iso9660 directory information.
+ *
+
+ Written by Eric Youngdale (1993).
+
+ Copyright 1993 Yggdrasil Computing, Incorporated
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/*
+ * Simple program to dump contents of iso9660 image in more usable format.
+ *
+ * Usage:
+ * To list contents of image (with or without RR):
+ * isoinfo -l [-R] -i imagefile
+ * To extract file from image:
+ * isoinfo -i imagefile -x xtractfile > outfile
+ * To generate a "find" like list of files:
+ * isoinfo -f -i imagefile
+ */
+
+#include "../config.h"
+
+#include <stdio.h>
+#include <signal.h>
+#include <sys/stat.h>
+
+#ifdef __svr4__
+#include <stdlib.h>
+#else
+extern int optind;
+extern char *optarg;
+/* extern int getopt (int __argc, char **__argv, char *__optstring); */
+#endif
+
+FILE * infile;
+int use_rock = 0;
+int do_listing = 0;
+int do_find = 0;
+char * xtract = 0;
+
+struct stat fstat_buf;
+char name_buf[256];
+char xname[256];
+unsigned char date_buf[9];
+
+unsigned char buffer[2048];
+
+#define PAGE sizeof(buffer)
+
+#define ISODCL(from, to) (to - from + 1)
+
+
+int
+isonum_731 (char * p)
+{
+ return ((p[0] & 0xff)
+ | ((p[1] & 0xff) << 8)
+ | ((p[2] & 0xff) << 16)
+ | ((p[3] & 0xff) << 24));
+}
+
+
+int
+isonum_733 (unsigned char * p)
+{
+ return (isonum_731 (p));
+}
+
+struct iso_primary_descriptor {
+ unsigned char type [ISODCL ( 1, 1)]; /* 711 */
+ unsigned char id [ISODCL ( 2, 6)];
+ unsigned char version [ISODCL ( 7, 7)]; /* 711 */
+ unsigned char unused1 [ISODCL ( 8, 8)];
+ unsigned char system_id [ISODCL ( 9, 40)]; /* aunsigned chars */
+ unsigned char volume_id [ISODCL ( 41, 72)]; /* dunsigned chars */
+ unsigned char unused2 [ISODCL ( 73, 80)];
+ unsigned char volume_space_size [ISODCL ( 81, 88)]; /* 733 */
+ unsigned char unused3 [ISODCL ( 89, 120)];
+ unsigned char volume_set_size [ISODCL (121, 124)]; /* 723 */
+ unsigned char volume_sequence_number [ISODCL (125, 128)]; /* 723 */
+ unsigned char logical_block_size [ISODCL (129, 132)]; /* 723 */
+ unsigned char path_table_size [ISODCL (133, 140)]; /* 733 */
+ unsigned char type_l_path_table [ISODCL (141, 144)]; /* 731 */
+ unsigned char opt_type_l_path_table [ISODCL (145, 148)]; /* 731 */
+ unsigned char type_m_path_table [ISODCL (149, 152)]; /* 732 */
+ unsigned char opt_type_m_path_table [ISODCL (153, 156)]; /* 732 */
+ unsigned char root_directory_record [ISODCL (157, 190)]; /* 9.1 */
+ unsigned char volume_set_id [ISODCL (191, 318)]; /* dunsigned chars */
+ unsigned char publisher_id [ISODCL (319, 446)]; /* achars */
+ unsigned char preparer_id [ISODCL (447, 574)]; /* achars */
+ unsigned char application_id [ISODCL (575, 702)]; /* achars */
+ unsigned char copyright_file_id [ISODCL (703, 739)]; /* 7.5 dchars */
+ unsigned char abstract_file_id [ISODCL (740, 776)]; /* 7.5 dchars */
+ unsigned char bibliographic_file_id [ISODCL (777, 813)]; /* 7.5 dchars */
+ unsigned char creation_date [ISODCL (814, 830)]; /* 8.4.26.1 */
+ unsigned char modification_date [ISODCL (831, 847)]; /* 8.4.26.1 */
+ unsigned char expiration_date [ISODCL (848, 864)]; /* 8.4.26.1 */
+ unsigned char effective_date [ISODCL (865, 881)]; /* 8.4.26.1 */
+ unsigned char file_structure_version [ISODCL (882, 882)]; /* 711 */
+ unsigned char unused4 [ISODCL (883, 883)];
+ unsigned char application_data [ISODCL (884, 1395)];
+ unsigned char unused5 [ISODCL (1396, 2048)];
+};
+
+struct iso_directory_record {
+ unsigned char length [ISODCL (1, 1)]; /* 711 */
+ unsigned char ext_attr_length [ISODCL (2, 2)]; /* 711 */
+ unsigned char extent [ISODCL (3, 10)]; /* 733 */
+ unsigned char size [ISODCL (11, 18)]; /* 733 */
+ unsigned char date [ISODCL (19, 25)]; /* 7 by 711 */
+ unsigned char flags [ISODCL (26, 26)];
+ unsigned char file_unit_size [ISODCL (27, 27)]; /* 711 */
+ unsigned char interleave [ISODCL (28, 28)]; /* 711 */
+ unsigned char volume_sequence_number [ISODCL (29, 32)]; /* 723 */
+ unsigned char name_len [ISODCL (33, 33)]; /* 711 */
+ unsigned char name [1];
+};
+
+
+int parse_rr(unsigned char * pnt, int len, int cont_flag)
+{
+ int slen;
+ int ncount;
+ int extent;
+ int cont_extent, cont_offset, cont_size;
+ int flag1, flag2;
+ unsigned char *pnts;
+ char symlink[1024];
+ int goof;
+
+ symlink[0] = 0;
+
+ cont_extent = cont_offset = cont_size = 0;
+
+ ncount = 0;
+ flag1 = flag2 = 0;
+ while(len >= 4){
+ if(pnt[3] != 1) {
+ printf("**BAD RRVERSION");
+ return;
+ };
+ ncount++;
+ if(pnt[0] == 'R' && pnt[1] == 'R') flag1 = pnt[4] & 0xff;
+ if(strncmp(pnt, "PX", 2) == 0) flag2 |= 1;
+ if(strncmp(pnt, "PN", 2) == 0) flag2 |= 2;
+ if(strncmp(pnt, "SL", 2) == 0) flag2 |= 4;
+ if(strncmp(pnt, "NM", 2) == 0) flag2 |= 8;
+ if(strncmp(pnt, "CL", 2) == 0) flag2 |= 16;
+ if(strncmp(pnt, "PL", 2) == 0) flag2 |= 32;
+ if(strncmp(pnt, "RE", 2) == 0) flag2 |= 64;
+ if(strncmp(pnt, "TF", 2) == 0) flag2 |= 128;
+
+ if(strncmp(pnt, "PX", 2) == 0) {
+ fstat_buf.st_mode = isonum_733(pnt+4);
+ fstat_buf.st_nlink = isonum_733(pnt+12);
+ fstat_buf.st_uid = isonum_733(pnt+20);
+ fstat_buf.st_gid = isonum_733(pnt+28);
+ };
+
+ if(strncmp(pnt, "NM", 2) == 0) {
+ strncpy(name_buf, pnt+5, pnt[2] - 5);
+ name_buf[pnt[2] - 5] = 0;
+ }
+
+ if(strncmp(pnt, "CE", 2) == 0) {
+ cont_extent = isonum_733(pnt+4);
+ cont_offset = isonum_733(pnt+12);
+ cont_size = isonum_733(pnt+20);
+ };
+
+ if(strncmp(pnt, "PL", 2) == 0 || strncmp(pnt, "CL", 2) == 0) {
+ extent = isonum_733(pnt+4);
+ };
+
+ if(strncmp(pnt, "SL", 2) == 0) {
+ int cflag;
+
+ cflag = pnt[4];
+ pnts = pnt+5;
+ slen = pnt[2] - 5;
+ while(slen >= 1){
+ switch(pnts[0] & 0xfe){
+ case 0:
+ strncat(symlink, pnts+2, pnts[1]);
+ break;
+ case 2:
+ strcat (symlink, ".");
+ break;
+ case 4:
+ strcat (symlink, "..");
+ break;
+ case 8:
+ if((pnts[0] & 1) == 0)strcat (symlink, "/");
+ break;
+ case 16:
+ strcat(symlink,"/mnt");
+ printf("Warning - mount point requested");
+ break;
+ case 32:
+ strcat(symlink,"kafka");
+ printf("Warning - host_name requested");
+ break;
+ default:
+ printf("Reserved bit setting in symlink", goof++);
+ break;
+ };
+ if((pnts[0] & 0xfe) && pnts[1] != 0) {
+ printf("Incorrect length in symlink component");
+ };
+ if((pnts[0] & 1) == 0) strcat(symlink,"/");
+
+ slen -= (pnts[1] + 2);
+ pnts += (pnts[1] + 2);
+ if(xname[0] == 0) strcpy(xname, "-> ");
+ strcat(xname, symlink);
+ };
+ symlink[0] = 0;
+ };
+
+ len -= pnt[2];
+ pnt += pnt[2];
+ if(len <= 3 && cont_extent) {
+ unsigned char sector[2048];
+ lseek(fileno(infile), cont_extent << 11, 0);
+ read(fileno(infile), sector, sizeof(sector));
+ flag2 |= parse_rr(&sector[cont_offset], cont_size, 1);
+ };
+ };
+ return flag2;
+}
+
+int
+dump_rr(struct iso_directory_record * idr)
+{
+ int len;
+ unsigned char * pnt;
+
+ len = idr->length[0] & 0xff;
+ len -= sizeof(struct iso_directory_record);
+ len += sizeof(idr->name);
+ len -= idr->name_len[0];
+ pnt = (unsigned char *) idr;
+ pnt += sizeof(struct iso_directory_record);
+ pnt -= sizeof(idr->name);
+ pnt += idr->name_len[0];
+ if((idr->name_len[0] & 1) == 0){
+ pnt++;
+ len--;
+ };
+ parse_rr(pnt, len, 0);
+}
+
+struct todo
+{
+ struct todo * next;
+ char * name;
+ int extent;
+ int length;
+};
+
+struct todo * todo_idr = NULL;
+
+char * months[12] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul",
+ "Aug", "Sep", "Oct", "Nov", "Dec"};
+
+dump_stat()
+{
+ int i;
+ char outline[80];
+
+ memset(outline, ' ', sizeof(outline));
+
+ if(S_ISREG(fstat_buf.st_mode))
+ outline[0] = '-';
+ else if(S_ISDIR(fstat_buf.st_mode))
+ outline[0] = 'd';
+ else if(S_ISLNK(fstat_buf.st_mode))
+ outline[0] = 'l';
+ else if(S_ISCHR(fstat_buf.st_mode))
+ outline[0] = 'c';
+ else if(S_ISBLK(fstat_buf.st_mode))
+ outline[0] = 'b';
+ else if(S_ISFIFO(fstat_buf.st_mode))
+ outline[0] = 'f';
+ else if(S_ISSOCK(fstat_buf.st_mode))
+ outline[0] = 's';
+ else
+ outline[0] = '?';
+
+ memset(outline+1, '-', 9);
+ if( fstat_buf.st_mode & S_IRUSR )
+ outline[1] = 'r';
+ if( fstat_buf.st_mode & S_IWUSR )
+ outline[2] = 'w';
+ if( fstat_buf.st_mode & S_IXUSR )
+ outline[3] = 'x';
+
+ if( fstat_buf.st_mode & S_IRGRP )
+ outline[4] = 'r';
+ if( fstat_buf.st_mode & S_IWGRP )
+ outline[5] = 'w';
+ if( fstat_buf.st_mode & S_IXGRP )
+ outline[6] = 'x';
+
+ if( fstat_buf.st_mode & S_IROTH )
+ outline[7] = 'r';
+ if( fstat_buf.st_mode & S_IWOTH )
+ outline[8] = 'w';
+ if( fstat_buf.st_mode & S_IXOTH )
+ outline[9] = 'x';
+
+ sprintf(outline+11, "%3d", fstat_buf.st_nlink);
+ sprintf(outline+15, "%4o", fstat_buf.st_uid);
+ sprintf(outline+20, "%4o", fstat_buf.st_gid);
+ sprintf(outline+33, "%8d", fstat_buf.st_size);
+
+ memcpy(outline+42, months[date_buf[1]-1], 3);
+ sprintf(outline+46, "%2d", date_buf[2]);
+ sprintf(outline+49, "%4d", date_buf[0]+1900);
+
+ for(i=0; i<54; i++)
+ if(outline[i] == 0) outline[i] = ' ';
+ outline[54] = 0;
+
+ printf("%s %s %s\n", outline, name_buf, xname);
+}
+
+extract_file(struct iso_directory_record * idr)
+{
+ int extent, len, tlen;
+ unsigned char buff[2048];
+
+ extent = isonum_733(idr->extent);
+ len = isonum_733(idr->size);
+
+ while(len > 0)
+ {
+ lseek(fileno(infile), extent << 11, 0);
+ tlen = (len > sizeof(buff) ? sizeof(buff) : len);
+ read(fileno(infile), buff, tlen);
+ len -= tlen;
+ extent++;
+ write(1, buff, tlen);
+ }
+}
+
+parse_dir(char * rootname, int extent, int len){
+ unsigned int k;
+ char testname[256];
+ struct todo * td;
+ int i, j;
+ struct iso_directory_record * idr;
+
+
+ if( do_listing)
+ printf("\nDirectory listing of %s\n", rootname);
+
+ while(len > 0 )
+ {
+ lseek(fileno(infile), extent << 11, 0);
+ read(fileno(infile), buffer, sizeof(buffer));
+ len -= sizeof(buffer);
+ extent++;
+ i = 0;
+ while(1==1){
+ idr = (struct iso_directory_record *) &buffer[i];
+ if(idr->length[0] == 0) break;
+ memset(&fstat_buf, 0, sizeof(fstat_buf));
+ name_buf[0] = xname[0] = 0;
+ fstat_buf.st_size = isonum_733(idr->size);
+ if( idr->flags[0] & 2)
+ fstat_buf.st_mode |= S_IFDIR;
+ else
+ fstat_buf.st_mode |= S_IFREG;
+ if(idr->name_len[0] == 1 && idr->name[0] == 0)
+ strcpy(name_buf, ".");
+ else if(idr->name_len[0] == 1 && idr->name[0] == 1)
+ strcpy(name_buf, "..");
+ else {
+ strncpy(name_buf, idr->name, idr->name_len[0]);
+ name_buf[idr->name_len[0]] = 0;
+ };
+ memcpy(date_buf, idr->date, 9);
+ if(use_rock) dump_rr(idr);
+ if( (idr->flags[0] & 2) != 0
+ && (idr->name_len[0] != 1
+ || (idr->name[0] != 0 && idr->name[0] != 1)))
+ {
+ /*
+ * Add this directory to the todo list.
+ */
+ td = todo_idr;
+ if( td != NULL )
+ {
+ while(td->next != NULL) td = td->next;
+ td->next = (struct todo *) malloc(sizeof(*td));
+ td = td->next;
+ }
+ else
+ {
+ todo_idr = td = (struct todo *) malloc(sizeof(*td));
+ }
+ td->next = NULL;
+ td->extent = isonum_733(idr->extent);
+ td->length = isonum_733(idr->size);
+ td->name = (char *) malloc(strlen(rootname)
+ + strlen(name_buf) + 2);
+ strcpy(td->name, rootname);
+ strcat(td->name, name_buf);
+ strcat(td->name, "/");
+ }
+ else
+ {
+ strcpy(testname, rootname);
+ strcat(testname, name_buf);
+ if(xtract && strcmp(xtract, testname) == 0)
+ {
+ extract_file(idr);
+ }
+ }
+ if( do_find
+ && (idr->name_len[0] != 1
+ || (idr->name[0] != 0 && idr->name[0] != 1)))
+ {
+ strcpy(testname, rootname);
+ strcat(testname, name_buf);
+ printf("%s\n", testname);
+ }
+ if(do_listing)
+ dump_stat();
+ i += buffer[i];
+ if (i > 2048 - sizeof(struct iso_directory_record)) break;
+ }
+ }
+}
+
+usage()
+{
+ fprintf(stderr, "isoinfo -i filename [-l] [-R] [-x filename] [-f]\n");
+}
+
+main(int argc, char * argv[]){
+ char c;
+ char buffer[2048];
+ int nbyte;
+ char * filename = NULL;
+ int i,j;
+ struct todo * td;
+ struct iso_primary_descriptor ipd;
+ struct iso_directory_record * idr;
+
+ if(argc < 2) return 0;
+ while ((c = getopt(argc, argv, "i:Rlx:f")) != EOF)
+ switch (c)
+ {
+ case 'f':
+ do_find++;
+ break;
+ case 'R':
+ use_rock++;
+ break;
+ case 'l':
+ do_listing++;
+ break;
+ case 'i':
+ filename = optarg;
+ break;
+ case 'x':
+ xtract = optarg;
+ break;
+ default:
+ usage();
+ exit(1);
+ }
+
+ if( filename == NULL )
+ {
+ fprintf(stderr, "Error - file not specified\n");
+ exit(1);
+ }
+
+ infile = fopen(filename,"rb");
+
+ if( infile == NULL )
+ {
+ fprintf(stderr,"Unable to open file %s\n", filename);
+ exit(1);
+ }
+
+ lseek(fileno(infile), 16<<11, 0);
+ read(fileno(infile), &ipd, sizeof(ipd));
+
+ idr = (struct iso_directory_record *) &ipd.root_directory_record;
+
+ parse_dir("/", isonum_733(idr->extent), isonum_733(idr->size));
+ td = todo_idr;
+ while(td)
+ {
+ parse_dir(td->name, td->extent, td->length);
+ td = td->next;
+ }
+
+ fclose(infile);
+}
+
+
+
+
diff --git a/gnu/usr.bin/mkisofs/diag/isovfy.c b/gnu/usr.bin/mkisofs/diag/isovfy.c
new file mode 100644
index 0000000..eb52c91
--- /dev/null
+++ b/gnu/usr.bin/mkisofs/diag/isovfy.c
@@ -0,0 +1,490 @@
+/*
+ * File isovfy.c - verify consistency of iso9660 filesystem.
+ *
+
+ Written by Eric Youngdale (1993).
+
+ Copyright 1993 Yggdrasil Computing, Incorporated
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <stdio.h>
+#include <signal.h>
+
+FILE * infile;
+
+#define PAGE sizeof(buffer)
+
+#define ISODCL(from, to) (to - from + 1)
+
+struct iso_primary_descriptor {
+ unsigned char type [ISODCL ( 1, 1)]; /* 711 */
+ unsigned char id [ISODCL ( 2, 6)];
+ unsigned char version [ISODCL ( 7, 7)]; /* 711 */
+ unsigned char unused1 [ISODCL ( 8, 8)];
+ unsigned char system_id [ISODCL ( 9, 40)]; /* aunsigned chars */
+ unsigned char volume_id [ISODCL ( 41, 72)]; /* dunsigned chars */
+ unsigned char unused2 [ISODCL ( 73, 80)];
+ unsigned char volume_space_size [ISODCL ( 81, 88)]; /* 733 */
+ unsigned char unused3 [ISODCL ( 89, 120)];
+ unsigned char volume_set_size [ISODCL (121, 124)]; /* 723 */
+ unsigned char volume_sequence_number [ISODCL (125, 128)]; /* 723 */
+ unsigned char logical_block_size [ISODCL (129, 132)]; /* 723 */
+ unsigned char path_table_size [ISODCL (133, 140)]; /* 733 */
+ unsigned char type_l_path_table [ISODCL (141, 144)]; /* 731 */
+ unsigned char opt_type_l_path_table [ISODCL (145, 148)]; /* 731 */
+ unsigned char type_m_path_table [ISODCL (149, 152)]; /* 732 */
+ unsigned char opt_type_m_path_table [ISODCL (153, 156)]; /* 732 */
+ unsigned char root_directory_record [ISODCL (157, 190)]; /* 9.1 */
+ unsigned char volume_set_id [ISODCL (191, 318)]; /* dunsigned chars */
+ unsigned char publisher_id [ISODCL (319, 446)]; /* achars */
+ unsigned char preparer_id [ISODCL (447, 574)]; /* achars */
+ unsigned char application_id [ISODCL (575, 702)]; /* achars */
+ unsigned char copyright_file_id [ISODCL (703, 739)]; /* 7.5 dchars */
+ unsigned char abstract_file_id [ISODCL (740, 776)]; /* 7.5 dchars */
+ unsigned char bibliographic_file_id [ISODCL (777, 813)]; /* 7.5 dchars */
+ unsigned char creation_date [ISODCL (814, 830)]; /* 8.4.26.1 */
+ unsigned char modification_date [ISODCL (831, 847)]; /* 8.4.26.1 */
+ unsigned char expiration_date [ISODCL (848, 864)]; /* 8.4.26.1 */
+ unsigned char effective_date [ISODCL (865, 881)]; /* 8.4.26.1 */
+ unsigned char file_structure_version [ISODCL (882, 882)]; /* 711 */
+ unsigned char unused4 [ISODCL (883, 883)];
+ unsigned char application_data [ISODCL (884, 1395)];
+ unsigned char unused5 [ISODCL (1396, 2048)];
+};
+
+struct iso_directory_record {
+ unsigned char length [ISODCL (1, 1)]; /* 711 */
+ unsigned char ext_attr_length [ISODCL (2, 2)]; /* 711 */
+ unsigned char extent [ISODCL (3, 10)]; /* 733 */
+ unsigned char size [ISODCL (11, 18)]; /* 733 */
+ unsigned char date [ISODCL (19, 25)]; /* 7 by 711 */
+ unsigned char flags [ISODCL (26, 26)];
+ unsigned char file_unit_size [ISODCL (27, 27)]; /* 711 */
+ unsigned char interleave [ISODCL (28, 28)]; /* 711 */
+ unsigned char volume_sequence_number [ISODCL (29, 32)]; /* 723 */
+ unsigned char name_len [ISODCL (33, 33)]; /* 711 */
+ unsigned char name [38];
+};
+
+int
+isonum_721 (char * p)
+{
+ return ((p[0] & 0xff)
+ | ((p[1] & 0xff) << 8));
+}
+
+int
+isonum_731 (char * p)
+{
+ return ((p[0] & 0xff)
+ | ((p[1] & 0xff) << 8)
+ | ((p[2] & 0xff) << 16)
+ | ((p[3] & 0xff) << 24));
+}
+
+int
+isonum_722 (char * p)
+{
+ return ((p[1] & 0xff)
+ | ((p[0] & 0xff) << 8));
+}
+
+int
+isonum_732 (char * p)
+{
+ return ((p[3] & 0xff)
+ | ((p[2] & 0xff) << 8)
+ | ((p[1] & 0xff) << 16)
+ | ((p[0] & 0xff) << 24));
+}
+
+int
+isonum_733 (unsigned char * p)
+{
+ return (isonum_731 (p));
+}
+
+char lbuffer[1024];
+int iline;
+int rr_goof;
+
+
+int
+dump_rr(struct iso_directory_record * idr){
+ int len;
+ char * pnt;
+
+ len = idr->length[0] & 0xff;
+ len -= (sizeof(struct iso_directory_record) - sizeof(idr->name));
+ len -= idr->name_len[0];
+ pnt = (char *) idr;
+ pnt += (sizeof(struct iso_directory_record) - sizeof(idr->name));
+ pnt += idr->name_len[0];
+
+ if((idr->name_len[0] & 1) == 0){
+ pnt++;
+ len--;
+ };
+
+ rr_goof = 0;
+ parse_rr(pnt, len, 0);
+ return rr_goof;
+}
+
+int parse_rr(unsigned char * pnt, int len, int cont_flag)
+{
+ int slen;
+ int ncount;
+ int flag1, flag2;
+ int extent;
+ unsigned char *pnts;
+ int cont_extent, cont_offset, cont_size;
+ char symlink[1024];
+ iline += sprintf(lbuffer+iline," RRlen=%d ", len);
+
+ cont_extent = cont_offset = cont_size = 0;
+
+ symlink[0] = 0;
+
+ ncount = 0;
+ flag1 = flag2 = 0;
+ while(len >= 4){
+ if(ncount) iline += sprintf(lbuffer+iline,",");
+ else iline += sprintf(lbuffer+iline,"[");
+ iline += sprintf(lbuffer+iline,"%c%c", pnt[0], pnt[1]);
+
+ if(pnt[0] < 'A' || pnt[0] > 'Z' || pnt[1] < 'A' ||
+ pnt[1] > 'Z') {
+ iline += sprintf(lbuffer+iline,"**BAD SUSP %d %d]",
+ pnt[0], pnt[1], rr_goof++);
+ return flag2;
+ };
+
+ if(pnt[3] != 1) {
+ iline += sprintf(lbuffer+iline,"**BAD RRVERSION", rr_goof++);
+ return flag2;
+ };
+ ncount++;
+ if(pnt[0] == 'R' && pnt[1] == 'R') flag1 = pnt[4] & 0xff;
+ if(strncmp(pnt, "PX", 2) == 0) flag2 |= 1;
+ if(strncmp(pnt, "PN", 2) == 0) flag2 |= 2;
+ if(strncmp(pnt, "SL", 2) == 0) flag2 |= 4;
+ if(strncmp(pnt, "NM", 2) == 0) flag2 |= 8;
+ if(strncmp(pnt, "CL", 2) == 0) flag2 |= 16;
+ if(strncmp(pnt, "PL", 2) == 0) flag2 |= 32;
+ if(strncmp(pnt, "RE", 2) == 0) flag2 |= 64;
+ if(strncmp(pnt, "TF", 2) == 0) flag2 |= 128;
+
+ if(strncmp(pnt, "CE", 2) == 0) {
+ cont_extent = isonum_733(pnt+4);
+ cont_offset = isonum_733(pnt+12);
+ cont_size = isonum_733(pnt+20);
+ iline += sprintf(lbuffer+iline, "=[%x,%x,%d]",
+ cont_extent, cont_offset, cont_size);
+ };
+
+ if(strncmp(pnt, "PL", 2) == 0 || strncmp(pnt, "CL", 2) == 0) {
+ extent = isonum_733(pnt+4);
+ iline += sprintf(lbuffer+iline,"=%x", extent);
+ if(extent == 0) rr_goof++;
+ };
+ if(strncmp(pnt, "SL", 2) == 0) {
+ pnts = pnt+5;
+ slen = pnt[2] - 5;
+ while(slen >= 1){
+ switch(pnts[0] & 0xfe){
+ case 0:
+ strncat(symlink, pnts+2, pnts[1]);
+ break;
+ case 2:
+ strcat (symlink, ".");
+ break;
+ case 4:
+ strcat (symlink, "..");
+ break;
+ case 8:
+ strcat (symlink, "/");
+ break;
+ case 16:
+ strcat(symlink,"/mnt");
+ iline += sprintf(lbuffer+iline,"Warning - mount point requested");
+ break;
+ case 32:
+ strcat(symlink,"kafka");
+ iline += sprintf(lbuffer+iline,"Warning - host_name requested");
+ break;
+ default:
+ iline += sprintf(lbuffer+iline,"Reserved bit setting in symlink", rr_goof++);
+ break;
+ };
+ if((pnts[0] & 0xfe) && pnts[1] != 0) {
+ iline += sprintf(lbuffer+iline,"Incorrect length in symlink component");
+ };
+ if((pnts[0] & 1) == 0)
+ strcat(symlink,"/");
+ slen -= (pnts[1] + 2);
+ pnts += (pnts[1] + 2);
+
+ };
+ if(symlink[0] != 0) {
+ iline += sprintf(lbuffer+iline,"=%s", symlink);
+ symlink[0] = 0;
+ }
+ };
+
+ len -= pnt[2];
+ pnt += pnt[2];
+ if(len <= 3 && cont_extent) {
+ unsigned char sector[2048];
+ lseek(fileno(infile), cont_extent << 11, 0);
+ read(fileno(infile), sector, sizeof(sector));
+ flag2 |= parse_rr(&sector[cont_offset], cont_size, 1);
+ };
+ };
+ if(ncount) iline += sprintf(lbuffer+iline,"]");
+ if (!cont_flag && flag1 && flag1 != flag2)
+ iline += sprintf(lbuffer+iline,"Flag %x != %x", flag1, flag2, rr_goof++);
+ return flag2;
+}
+
+
+int dir_count = 0;
+int dir_size_count = 0;
+int ngoof = 0;
+
+
+check_tree(int file_addr, int file_size, int parent_addr){
+ unsigned char buffer[2048];
+ unsigned int k;
+ int rflag;
+ int i, i1, j, goof;
+ int extent, size;
+ int line;
+ int orig_file_addr, parent_file_addr;
+ struct iso_directory_record * idr;
+
+ i1 = 0;
+
+ orig_file_addr = file_addr >> 11; /* Actual extent of this directory */
+ parent_file_addr = parent_addr >> 11;
+
+ if((dir_count % 100) == 0) printf("[%d %d]\n", dir_count, dir_size_count);
+#if 0
+ printf("Starting directory %d %d %d\n", file_addr, file_size, parent_addr);
+#endif
+
+ dir_count++;
+ dir_size_count += file_size >> 11;
+
+ if(file_size & 0x3ff) printf("********Directory has unusual size\n");
+
+ for(k=0; k < (file_size >> 11); k++){
+ lseek(fileno(infile), file_addr, 0);
+ read(fileno(infile), buffer, sizeof(buffer));
+ i = 0;
+ while(1==1){
+ goof = iline=0;
+ idr = (struct iso_directory_record *) &buffer[i];
+ if(idr->length[0] == 0) break;
+ iline += sprintf(&lbuffer[iline],"%3d ", idr->length[0]);
+ extent = isonum_733(idr->extent);
+ size = isonum_733(idr->size);
+ iline += sprintf(&lbuffer[iline],"%5x ", extent);
+ iline += sprintf(&lbuffer[iline],"%8d ", size);
+ iline += sprintf (&lbuffer[iline], "%c", (idr->flags[0] & 2) ? '*' : ' ');
+
+ if(idr->name_len[0] > 33 || idr->name_len[0] < 0)
+ iline += sprintf(&lbuffer[iline],"File name length=(%d)",
+ idr->name_len[0], goof++);
+ else if(idr->name_len[0] == 1 && idr->name[0] == 0) {
+ iline += sprintf(&lbuffer[iline],". ");
+ rflag = 0;
+ if(orig_file_addr !=isonum_733(idr->extent))
+ iline += sprintf(&lbuffer[iline],"***** Directory has null extent.", goof++);
+ if(i1)
+ iline += sprintf(&lbuffer[iline],"***** . not first entry.", rr_goof++);
+ } else if(idr->name_len[0] == 1 && idr->name[0] == 1) {
+ iline += sprintf(&lbuffer[iline],".. ");
+ rflag = 0;
+ if(parent_file_addr !=isonum_733(idr->extent))
+ iline += sprintf(&lbuffer[iline],"***** Directory has null extent.", goof++);
+ if(i1 != 1)
+ iline += sprintf(&lbuffer[iline],"***** .. not second entry.", rr_goof++);
+
+ } else {
+ if(i1 < 2) iline += sprintf(&lbuffer[iline]," Improper sorting.", rr_goof++);
+ for(j=0; j<idr->name_len[0]; j++) iline += sprintf(&lbuffer[iline],"%c", idr->name[j]);
+ for(j=0; j<14 -idr->name_len[0]; j++) iline += sprintf(&lbuffer[iline]," ");
+ rflag = 1;
+ };
+
+ if(size && extent == 0) iline += sprintf(&lbuffer[iline],"****Extent==0, size != 0", goof++);
+#if 0
+ /* This is apparently legal. */
+ if(size == 0 && extent) iline += sprintf(&lbuffer[iline],"****Extent!=0, size == 0", goof++);
+#endif
+
+ if(idr->flags[0] & 0xfd)
+ iline += sprintf(&lbuffer[iline],"Flags=(%x) ", idr->flags[0], goof++);
+
+ if(idr->flags[0] & 0xfd)
+ iline += sprintf(&lbuffer[iline],"Flags=(%x) ", idr->flags[0], goof++);
+
+ if(idr->interleave[0])
+ iline += sprintf(&lbuffer[iline],"Interleave=(%d) ", idr->interleave[0], goof++);
+
+ if(idr->file_unit_size[0])
+ iline += sprintf(&lbuffer[iline],"File unit size=(%d) ", idr->file_unit_size[0], goof++);
+
+ if(idr->volume_sequence_number[0] != 1)
+ iline += sprintf(&lbuffer[iline],"Volume sequence number=(%d) ", idr->volume_sequence_number[0], goof++);
+
+ goof += dump_rr(idr);
+ iline += sprintf(&lbuffer[iline],"\n");
+
+
+ if(goof){
+ ngoof++;
+ lbuffer[iline++] = 0;
+ printf("%x: %s", orig_file_addr, lbuffer);
+ };
+
+
+
+ if(rflag && (idr->flags[0] & 2)) check_tree((isonum_733(idr->extent)) << 11,
+ isonum_733(idr->size),
+ orig_file_addr << 11);
+ i += buffer[i];
+ i1++;
+ if (i > 2048 - sizeof(struct iso_directory_record)) break;
+ };
+ file_addr += sizeof(buffer);
+ };
+ fflush(stdout);
+}
+
+
+/* This function simply dumps the contents of the path tables. No
+ consistency checking takes place, although this would proably be a good
+ idea. */
+
+struct path_table_info{
+ char * name;
+ unsigned int extent;
+ unsigned short index;
+ unsigned short parent;
+};
+
+
+check_path_tables(int typel_extent, int typem_extent, int path_table_size){
+ int file_addr;
+ int count;
+ int j;
+ char * pnt;
+ char * typel, *typem;
+
+ /* Now read in the path tables */
+
+ typel = (char *) malloc(path_table_size);
+ lseek(fileno(infile), typel_extent << 11, 0);
+ read(fileno(infile), typel, path_table_size);
+
+ typem = (char *) malloc(path_table_size);
+ lseek(fileno(infile), typem_extent << 11, 0);
+ read(fileno(infile), typem, path_table_size);
+
+ j = path_table_size;
+ pnt = typel;
+ count = 1;
+ while(j){
+ int namelen, extent, index;
+ char name[32];
+ namelen = *pnt++; pnt++;
+ extent = isonum_731(pnt); pnt += 4;
+ index = isonum_721(pnt); pnt+= 2;
+ j -= 8+namelen;
+ memset(name, 0, sizeof(name));
+
+ strncpy(name, pnt, namelen);
+ pnt += namelen;
+ if(j & 1) { j--; pnt++;};
+ printf("%4.4d %4.4d %8.8x %s\n",count++, index, extent, name);
+ };
+
+ j = path_table_size;
+ pnt = typem;
+ count = 1;
+ while(j){
+ int namelen, extent, index;
+ char name[32];
+ namelen = *pnt++; pnt++;
+ extent = isonum_732(pnt); pnt += 4;
+ index = isonum_722(pnt); pnt+= 2;
+ j -= 8+namelen;
+ memset(name, 0, sizeof(name));
+
+ strncpy(name, pnt, namelen);
+ pnt += namelen;
+ if(j & 1) { j--; pnt++;};
+ printf("%4.4d %4.4d %8.8x %s\n", count++, index, extent, name);
+ };
+
+}
+
+main(int argc, char * argv[]){
+ int file_addr, file_size;
+ char c;
+ int nbyte;
+ struct iso_primary_descriptor ipd;
+ struct iso_directory_record * idr;
+ int typel_extent, typem_extent;
+ int path_table_size;
+ int i,j;
+ if(argc < 2) return 0;
+ infile = fopen(argv[1],"rb");
+
+
+ file_addr = 16 << 11;
+ lseek(fileno(infile), file_addr, 0);
+ read(fileno(infile), &ipd, sizeof(ipd));
+
+ idr = (struct iso_directory_record *) &ipd.root_directory_record;
+
+ file_addr = isonum_733(idr->extent);
+ file_size = isonum_733(idr->size);
+
+ printf("Root at extent %x, %d bytes\n", file_addr, file_size);
+ file_addr = file_addr << 11;
+
+ check_tree(file_addr, file_size, file_addr);
+
+ typel_extent = isonum_731(ipd.type_l_path_table);
+ typem_extent = isonum_732(ipd.type_m_path_table);
+ path_table_size = isonum_733(ipd.path_table_size);
+
+ /* Enable this to get the dump of the path tables */
+#if 0
+ check_path_tables(typel_extent, typem_extent, path_table_size);
+#endif
+
+ fclose(infile);
+
+ if(!ngoof) printf("No errors found\n");
+}
+
+
+
+
diff --git a/gnu/usr.bin/mkisofs/exclude.c b/gnu/usr.bin/mkisofs/exclude.c
new file mode 100644
index 0000000..c20ea28
--- /dev/null
+++ b/gnu/usr.bin/mkisofs/exclude.c
@@ -0,0 +1,53 @@
+/*
+ * 9-Dec-93 R.-D. Marzusch, marzusch@odiehh.hanse.de:
+ * added 'exclude' option (-x) to specify pathnames NOT to be included in
+ * CD image.
+ */
+
+#include <stdio.h>
+#ifndef VMS
+#ifdef HASMALLOC_H
+#include <malloc.h>
+#else
+#include <stdlib.h>
+#endif
+#endif
+#include <string.h>
+
+/* this allows for 1000 entries to be excluded ... */
+#define MAXEXCL 1000
+static char * excl[MAXEXCL];
+
+void exclude(fn)
+char * fn;
+{
+ register int i;
+
+ for (i=0; excl[i] && i<MAXEXCL; i++);
+ if (i == MAXEXCL) {
+ fprintf(stderr,"Can't exclude '%s' - too many entries in table\n",fn);
+ return;
+ }
+
+ excl[i] = (char *) malloc(strlen(fn)+1);
+ if (! excl[i]) {
+ fprintf(stderr,"Can't allocate memory for excluded filename\n");
+ return;
+ }
+
+ strcpy(excl[i],fn);
+}
+
+int is_excluded(fn)
+char * fn;
+{
+ /* very dumb search method ... */
+ register int i;
+
+ for (i=0; excl[i] && i<MAXEXCL; i++) {
+ if (strcmp(excl[i],fn) == 0) {
+ return 1; /* found -> excluded filenmae */
+ }
+ }
+ return 0; /* not found -> not excluded */
+}
diff --git a/gnu/usr.bin/mkisofs/exclude.h b/gnu/usr.bin/mkisofs/exclude.h
new file mode 100644
index 0000000..d22fda2
--- /dev/null
+++ b/gnu/usr.bin/mkisofs/exclude.h
@@ -0,0 +1,8 @@
+/*
+ * 9-Dec-93 R.-D. Marzusch, marzusch@odiehh.hanse.de:
+ * added 'exclude' option (-x) to specify pathnames NOT to be included in
+ * CD image.
+ */
+
+void exclude();
+int is_excluded();
diff --git a/gnu/usr.bin/mkisofs/hash.c b/gnu/usr.bin/mkisofs/hash.c
new file mode 100644
index 0000000..d21d84f
--- /dev/null
+++ b/gnu/usr.bin/mkisofs/hash.c
@@ -0,0 +1,177 @@
+/*
+ * File hash.c - generate hash tables for iso9660 filesystem.
+
+ Written by Eric Youngdale (1993).
+
+ Copyright 1993 Yggdrasil Computing, Incorporated
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <stdlib.h>
+#include "mkisofs.h"
+
+#define NR_HASH 1024
+
+#define HASH_FN(DEV, INO) ((DEV + INO + (INO >> 2) + (INO << 8)) % NR_HASH)
+
+static struct file_hash * hash_table[NR_HASH] = {0,};
+
+void FDECL1(add_hash, struct directory_entry *, spnt){
+ struct file_hash * s_hash;
+ unsigned int hash_number;
+
+ if(spnt->size == 0 || spnt->starting_block == 0)
+ if(spnt->size != 0 || spnt->starting_block != 0) {
+ fprintf(stderr,"Non zero-length file assigned zero extent.\n");
+ exit(1);
+ };
+
+ if (spnt->dev == (dev_t) UNCACHED_DEVICE || spnt->inode == UNCACHED_INODE) return;
+ hash_number = HASH_FN((unsigned int) spnt->dev, (unsigned int) spnt->inode);
+
+#if 0
+ if (verbose) fprintf(stderr,"%s ",spnt->name);
+#endif
+ s_hash = (struct file_hash *) e_malloc(sizeof(struct file_hash));
+ s_hash->next = hash_table[hash_number];
+ s_hash->inode = spnt->inode;
+ s_hash->dev = spnt->dev;
+ s_hash->starting_block = spnt->starting_block;
+ s_hash->size = spnt->size;
+ hash_table[hash_number] = s_hash;
+}
+
+struct file_hash * FDECL2(find_hash, dev_t, dev, ino_t, inode){
+ unsigned int hash_number;
+ struct file_hash * spnt;
+ hash_number = HASH_FN((unsigned int) dev, (unsigned int) inode);
+ if (dev == (dev_t) UNCACHED_DEVICE || inode == UNCACHED_INODE) return NULL;
+
+ spnt = hash_table[hash_number];
+ while(spnt){
+ if(spnt->inode == inode && spnt->dev == dev) return spnt;
+ spnt = spnt->next;
+ };
+ return NULL;
+}
+
+
+static struct file_hash * directory_hash_table[NR_HASH] = {0,};
+
+void FDECL2(add_directory_hash, dev_t, dev, ino_t, inode){
+ struct file_hash * s_hash;
+ unsigned int hash_number;
+
+ if (dev == (dev_t) UNCACHED_DEVICE || inode == UNCACHED_INODE) return;
+ hash_number = HASH_FN((unsigned int) dev, (unsigned int) inode);
+
+ s_hash = (struct file_hash *) e_malloc(sizeof(struct file_hash));
+ s_hash->next = directory_hash_table[hash_number];
+ s_hash->inode = inode;
+ s_hash->dev = dev;
+ directory_hash_table[hash_number] = s_hash;
+}
+
+struct file_hash * FDECL2(find_directory_hash, dev_t, dev, ino_t, inode){
+ unsigned int hash_number;
+ struct file_hash * spnt;
+ hash_number = HASH_FN((unsigned int) dev, (unsigned int) inode);
+ if (dev == (dev_t) UNCACHED_DEVICE || inode == UNCACHED_INODE) return NULL;
+
+ spnt = directory_hash_table[hash_number];
+ while(spnt){
+ if(spnt->inode == inode && spnt->dev == dev) return spnt;
+ spnt = spnt->next;
+ };
+ return NULL;
+}
+
+struct name_hash{
+ struct name_hash * next;
+ struct directory_entry * de;
+};
+
+#define NR_NAME_HASH 128
+
+static struct name_hash * name_hash_table[NR_NAME_HASH] = {0,};
+
+static unsigned int FDECL1(name_hash, const char *, name){
+ unsigned int hash = 0;
+ const char * p;
+
+ p = name;
+
+ while (*p) hash = (hash << 15) + (hash << 3) + (hash >> 3) + *p++;
+ return hash % NR_NAME_HASH;
+
+}
+
+
+void FDECL1(add_file_hash, struct directory_entry *, de){
+ struct name_hash * new;
+ int hash;
+
+ new = (struct name_hash *) e_malloc(sizeof(struct name_hash));
+ new->de = de;
+ new->next = NULL;
+ hash = name_hash(de->isorec.name);
+
+ /* Now insert into the hash table */
+ new->next = name_hash_table[hash];
+ name_hash_table[hash] = new;
+}
+
+struct directory_entry * FDECL1(find_file_hash, char *, name){
+ struct name_hash * nh;
+
+ for(nh = name_hash_table[name_hash(name)]; nh; nh = nh->next)
+ if(strcmp(nh->de->isorec.name, name) == 0) return nh->de;
+ return NULL;
+}
+
+int FDECL1(delete_file_hash, struct directory_entry *, de){
+ struct name_hash * nh, *prev;
+ int hash;
+
+ prev = NULL;
+ hash = name_hash(de->isorec.name);
+ for(nh = name_hash_table[hash]; nh; nh = nh->next) {
+ if(nh->de == de) break;
+ prev = nh;
+ };
+ if(!nh) return 1;
+ if(!prev)
+ name_hash_table[hash] = nh->next;
+ else
+ prev->next = nh->next;
+ free(nh);
+ return 0;
+}
+
+void flush_file_hash(){
+ struct name_hash * nh, *nh1;
+ int i;
+
+ for(i=0; i<NR_NAME_HASH; i++) {
+ nh = name_hash_table[i];
+ while(nh) {
+ nh1 = nh->next;
+ free(nh);
+ nh = nh1;
+ };
+ name_hash_table[i] = NULL;
+
+ };
+}
diff --git a/gnu/usr.bin/mkisofs/iso9660.h b/gnu/usr.bin/mkisofs/iso9660.h
new file mode 100644
index 0000000..2c202da
--- /dev/null
+++ b/gnu/usr.bin/mkisofs/iso9660.h
@@ -0,0 +1,107 @@
+/*
+ * Header file iso9660.h - assorted structure definitions and typecasts.
+ * specific to iso9660 filesystem.
+
+ Written by Eric Youngdale (1993).
+
+ Copyright 1993 Yggdrasil Computing, Incorporated
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#ifndef _ISOFS_FS_H
+#define _ISOFS_FS_H
+
+/*
+ * The isofs filesystem constants/structures
+ */
+
+/* This part borrowed from the bsd386 isofs */
+#define ISODCL(from, to) (to - from + 1)
+
+struct iso_volume_descriptor {
+ char type[ISODCL(1,1)]; /* 711 */
+ char id[ISODCL(2,6)];
+ char version[ISODCL(7,7)];
+ char data[ISODCL(8,2048)];
+};
+
+/* volume descriptor types */
+#define ISO_VD_PRIMARY 1
+#define ISO_VD_END 255
+
+#define ISO_STANDARD_ID "CD001"
+
+struct iso_primary_descriptor {
+ char type [ISODCL ( 1, 1)]; /* 711 */
+ char id [ISODCL ( 2, 6)];
+ char version [ISODCL ( 7, 7)]; /* 711 */
+ char unused1 [ISODCL ( 8, 8)];
+ char system_id [ISODCL ( 9, 40)]; /* achars */
+ char volume_id [ISODCL ( 41, 72)]; /* dchars */
+ char unused2 [ISODCL ( 73, 80)];
+ char volume_space_size [ISODCL ( 81, 88)]; /* 733 */
+ char unused3 [ISODCL ( 89, 120)];
+ char volume_set_size [ISODCL (121, 124)]; /* 723 */
+ char volume_sequence_number [ISODCL (125, 128)]; /* 723 */
+ char logical_block_size [ISODCL (129, 132)]; /* 723 */
+ char path_table_size [ISODCL (133, 140)]; /* 733 */
+ char type_l_path_table [ISODCL (141, 144)]; /* 731 */
+ char opt_type_l_path_table [ISODCL (145, 148)]; /* 731 */
+ char type_m_path_table [ISODCL (149, 152)]; /* 732 */
+ char opt_type_m_path_table [ISODCL (153, 156)]; /* 732 */
+ char root_directory_record [ISODCL (157, 190)]; /* 9.1 */
+ char volume_set_id [ISODCL (191, 318)]; /* dchars */
+ char publisher_id [ISODCL (319, 446)]; /* achars */
+ char preparer_id [ISODCL (447, 574)]; /* achars */
+ char application_id [ISODCL (575, 702)]; /* achars */
+ char copyright_file_id [ISODCL (703, 739)]; /* 7.5 dchars */
+ char abstract_file_id [ISODCL (740, 776)]; /* 7.5 dchars */
+ char bibliographic_file_id [ISODCL (777, 813)]; /* 7.5 dchars */
+ char creation_date [ISODCL (814, 830)]; /* 8.4.26.1 */
+ char modification_date [ISODCL (831, 847)]; /* 8.4.26.1 */
+ char expiration_date [ISODCL (848, 864)]; /* 8.4.26.1 */
+ char effective_date [ISODCL (865, 881)]; /* 8.4.26.1 */
+ char file_structure_version [ISODCL (882, 882)]; /* 711 */
+ char unused4 [ISODCL (883, 883)];
+ char application_data [ISODCL (884, 1395)];
+ char unused5 [ISODCL (1396, 2048)];
+};
+
+/* We use this to help us look up the parent inode numbers. */
+
+struct iso_path_table{
+ unsigned char name_len[2]; /* 721 */
+ char extent[4]; /* 731 */
+ char parent[2]; /* 721 */
+ char name[1];
+};
+
+struct iso_directory_record {
+ unsigned char length [ISODCL (1, 1)]; /* 711 */
+ char ext_attr_length [ISODCL (2, 2)]; /* 711 */
+ char extent [ISODCL (3, 10)]; /* 733 */
+ char size [ISODCL (11, 18)]; /* 733 */
+ char date [ISODCL (19, 25)]; /* 7 by 711 */
+ char flags [ISODCL (26, 26)];
+ char file_unit_size [ISODCL (27, 27)]; /* 711 */
+ char interleave [ISODCL (28, 28)]; /* 711 */
+ char volume_sequence_number [ISODCL (29, 32)]; /* 723 */
+ unsigned char name_len [ISODCL (33, 33)]; /* 711 */
+ char name [34]; /* Not really, but we need something here */
+};
+#endif
+
+
+
diff --git a/gnu/usr.bin/mkisofs/make.com b/gnu/usr.bin/mkisofs/make.com
new file mode 100644
index 0000000..752ea4d
--- /dev/null
+++ b/gnu/usr.bin/mkisofs/make.com
@@ -0,0 +1,16 @@
+$! Set the def dir to proper place for use in batch. Works for interactive too.
+$flnm = f$enviroment("PROCEDURE") ! get current procedure name
+$set default 'f$parse(flnm,,,"DEVICE")''f$parse(flnm,,,"DIRECTORY")'
+$!
+$!
+$if "''p1'".eqs."LINK" then goto link
+$gcc/debug mkisofs.c
+$gcc/debug write.c
+$gcc/debug tree.c
+$gcc/debug hash.c
+$gcc/debug rock.c
+$gcc/debug vms.c
+$gcc/debug exclude.c
+$link:
+$link mkisofs.obj+write.obj+tree.obj+hash.obj+rock.obj+vms.obj+exclude.obj+ -
+ gnu_cc:[000000]gcclib/lib+sys$library:vaxcrtl/lib
diff --git a/gnu/usr.bin/mkisofs/mkisofs.8 b/gnu/usr.bin/mkisofs/mkisofs.8
new file mode 100644
index 0000000..d05909b
--- /dev/null
+++ b/gnu/usr.bin/mkisofs/mkisofs.8
@@ -0,0 +1,274 @@
+.\" -*- nroff -*-
+.TH MKISOFS 8 "January 1995" "Version 1.04"
+.SH NAME
+mkisofs \- create a iso9660 filesystem with optional Rock Ridge attributes.
+.SH SYNOPSIS
+.B mkisofs
+[
+.B \-R
+]
+[
+.B \-T
+]
+[
+.B \-v
+]
+[
+.B \-z
+]
+[
+.B \-a
+]
+[
+.B \-f
+]
+[
+.B \-d
+]
+[
+.B \-D
+]
+[
+.B \-l
+]
+[
+.B \-L
+]
+[
+.B \-L
+]
+[
+.B \-V
+]
+[
+.B \-V
+.I volid
+]
+[
+.B \-i
+.I include-list
+]
+[
+.B \-p
+.I preparer
+]
+[
+.B \-P
+.I publisher
+]
+[
+.B \-A
+.I application_id
+]
+[
+.B \-x
+.I path
+]
+.B \-o
+.I filename
+.I path
+.SH DESCRIPTION
+.B mkisofs
+is effectively a pre-mastering program to generate the iso9660 filesystem - it
+takes a snapshot of a given directory tree, and generates a binary image which
+will correspond to an iso9660 filesystem when written to a block device.
+.PP
+.B mkisofs
+is also capable of generating the System Use Sharing Protocol records specified
+by the Rock Ridge Interchange Protocol. This is used to further describe the
+files in the iso9660 filesystem to a unix host, and provides information such
+as longer filenames, uid/gid, posix permissions, and block and character
+devices.
+.PP
+Each file written to the iso9660 filesystem must have a filename in the 8.3
+format (8 characters, period, 3 characters, all upper case), even if Rock Ridge
+is in use. This filename is used on systems that are not able to make use of
+the Rock Ridge extensions (such as MS-DOS), and each filename in each directory
+must be different from the other filenames in the same directory.
+.B mkisofs
+generally tries to form correct names by forcing the unix filename to upper
+case and truncating as required, but often times this yields unsatisfactory
+results when there are cases where the
+truncated names are not all unique.
+.B mkisofs
+assigns weightings to each filename, and if two names that are otherwise the
+same are found the name with the lower priority is renamed to have a 3 digit
+number as an extension (where the number is guaranteed to be unique). An
+example of this would be the files foo.bar and
+foo.bar.~1~ - the file foo.bar.~1~ would be written as FOO.000;1 and the file
+foo.bar would be written as FOO.BAR;1
+.PP
+Note that
+.B mkisofs
+is not designed to communicate with the writer directly. Most writers
+have proprietary command sets which vary from one manufacturer to
+another, and you need a specialized tool to actually burn the disk.
+The cdwrite utility that comes with mkisofs is capable of communicating
+with Phillips drives (newer versions of cdwrite should be available from
+Yggdrasil). Most writers come with some version of DOS software
+that allows a direct image copy of an iso9660 image to the writer.
+.PP
+Also you should know that most cd writers are very particular about timing.
+Once you start to burn a disc, you cannot let their buffer empty before you
+are done, or you will end up with a corrupt disc. Thus it is critical
+that you be able to maintain an uninterupted data stream to the writer
+for the entire time that the disc is being written.
+.PP
+.br
+.B path
+is the path of the directory tree to be copied into the iso9660 filesystem.
+.SH OPTIONS
+.TP
+.I \-a
+Include all files on the iso9660 filesystem. Normally files that contain the
+characters '~' or '#' will not be included (these are typically backup files
+for editors under unix).
+.TP
+.I \-A application_id
+Specifies a text string that will be written into the volume header.
+This should describe the application that will be on the disc. There
+is space on the disc for 128 characters of information. This parameter can
+also be set in the file .mkisofsrc with APPL=id. If specified in both
+places, the command line version is used.
+.TP
+.I \-d
+Omit trailing period from files that do not have a period. This violates the
+ISO9660 standard, but it happens to work on many systems. Use with caution.
+.TP
+.I \-D
+Do not use deep directory relocation, and instead just pack them in the
+way we see them. This violates the ISO9660 standard, but it works on many
+systems. Use with caution.
+.TP
+.I \-f
+Follow symbolic links when generating the filesystem. When this option is not
+in use, symbolic links will be entered using Rock Ridge if enabled, otherwise
+the file will be ignored.
+.TP
+.I \-i include-list
+Use the specified file as a list of files to add to the directory tree.
+This is useful for quickly repacking a CD while adding files to it.
+The format of this file is path1/file=path2 where path1 is the directory
+in the ISO9660 file system where file should appear and path2 is the
+where to find the file.
+.TP
+.I \-l
+Allow full 32 character filenames. Normally the ISO9660 filename will be in an
+8.3 format which is compatible with MS-DOS, even though the ISO9660 standard
+allows filenames of up to 32 characters. If you use this option, the disc may
+be difficult to use on a MS-DOS system, but this comes in handy on some other
+systems (such as the Amiga). Use with caution.
+.TP
+.I \-L
+Allow filenames to begin with a period. Ususally, a leading dot is
+replaced with an underscore in order to maintain MS-DOS compatibility.
+.TP
+.I \-N
+Omit version numbers from ISO9660 file names. This may violate the ISO9660
+standard, but no one really uses the version numbers anyway. Use with caution.
+.TP
+.I \-o filename
+is the name of the file to which the iso9660 filesystem image should be
+written. This can be a disk file, a tape drive, or it can correspond directly
+to the device name of the optical disc writer. If not specified, stdout is
+]used. Note that the output can also be a block special device for a regular
+disk drive, in which case the disk partition can be mounted and examined to
+ensure that the premastering was done correctly.
+.TP
+.I \-P publisher_id
+Specifies a text string that will be written into the volume header.
+This should describe the publisher of the CDROM, usually with a
+mailing address and phone number. There is space on the disc for 128
+characters of information. This parameter can also be set in the file
+.mkisofsrc with PUBL=. If specified in both places, the command line
+version is used.
+.TP
+.I \-p preparer_id
+Specifies a text string that will be written into the volume header.
+This should describe the preparer of the CDROM, usually with a mailing
+address and phone number. There is space on the disc for 128
+characters of information. This parameter can also be set in the file
+.mkisofsrc with PREP=. If specified in both places, the command
+line version is used.
+.TP
+.I \-R
+Generate SUSP and RR records using the Rock Ridge protocol to further describe
+the files on the iso9660 filesystem.
+.TP
+.I \-T
+Generate a file TRANS.TBL in each directory on the CDROM, which can be used
+on non-Rock Ridge capable systems to help establish the correct file names.
+There is also information present in the file that indicates the major and
+minor numbers for block and character devices, and each symlink has the name of
+the link file given.
+.TP
+.I \-V volid
+Specifies the volume ID to be written into the master block. This
+parameter can also be set in the file .mkisofsrc with VOLI=id. If
+specified in both places, the command line version is used.
+.TP
+.I \-v
+Verbose execution.
+.TP
+.I \-x path
+Exclude
+.I path
+from being written to CDROM.
+.I path
+must be the complete pathname that results from concatenating the pathname
+given as command line argument and the path relative to this directory.
+Multiple paths may be excluded (up to 1000).
+Example:
+
+mkisofs \-o cd \-x /local/dir1 \-x /local/dir2 /local
+.TP
+.I \-z
+Generate special SUSP records for transparently compressed files. This is
+only of use and interest for hosts that support transparent decompression.
+This is an experimental feature, and no hosts yet support this, but there
+are ALPHA patches for linux that can make use of this feature.
+.SH CONFIGURATION
+.B mkisofs
+looks for a file .mkisofsrc, first in the current working directory, and if not
+found there then in the directory in which the
+.B mkisofs
+binary is stored. This file is assumed to contain a series of lines
+of the form "TAG=value", and in this way you can specify certain
+options. Only the first four characters of the tag are used, and the
+case of the tag is not significant. Some fields in the volume header
+are not settable on the command line, but can be altered through this
+facility. These are the copyright information (COPY), the
+bibliographic information (BIBL), the abstract (ABST), the volume set
+ID (VOLS) and the system ID (SYSI).
+.PP
+.B mkisofs
+can also be configured at compile time with defaults for many of these fields.
+See the file defaults.h.
+.SH AUTHOR
+.B mkisofs
+is not based on the standard mk*fs tools for unix, because we must generate
+a complete copy of an existing filesystem on a disk in the iso9660
+filesystem. The name mkisofs is probably a bit of a misnomer, since it
+not only creates the filesystem, but it also populates it as well.
+.PP
+.br
+Eric Youngdale <eric@aib.com> wrote both the linux isofs9660 filesystem
+and the mkisofs utility, and is currently maintaining them. The copyright for
+the mkisofs utility is held by Yggdrasil Computing, Incorporated.
+.SH BUGS
+Any files that have hard links to files not in the tree being copied to the
+iso9660 filessytem will have an incorrect file reference count.
+.PP
+There may be some other ones. Please, report them to the author.
+.SH FUTURE IMPROVEMENTS
+Allow specfication of multiple paths on the command line to be included in
+iso9660 filesystem. Can be tricky - directory entries in the root directory
+need to be properly sorted.
+.SH AVAILABILITY
+.B mkisofs
+is available for anonymous ftp from tsx-11.mit.edu in
+/pub/linux/BETA/cdrom/mkisofs and many other mirror sites. With the 1.0
+release, it is no longer considered to be in beta testing. Most of the bugs
+that are being discovered now are very minor (and interestingly enough also
+seem to be present in the YM software). Reports indicate that people are
+gearing up for production runs using version 1.00.
diff --git a/gnu/usr.bin/mkisofs/mkisofs.c b/gnu/usr.bin/mkisofs/mkisofs.c
new file mode 100644
index 0000000..e1948ca
--- /dev/null
+++ b/gnu/usr.bin/mkisofs/mkisofs.c
@@ -0,0 +1,760 @@
+/*
+ * Program mkisofs.c - generate iso9660 filesystem based upon directory
+ * tree on hard disk.
+
+ Written by Eric Youngdale (1993).
+
+ Copyright 1993 Yggdrasil Computing, Incorporated
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* ADD_FILES changes made by Ross Biro biro@yggdrasil.com 2/23/95 */
+
+#include "mkisofs.h"
+
+#include <assert.h>
+
+#ifdef linux
+#include <getopt.h>
+#endif
+
+#include "iso9660.h"
+#include <ctype.h>
+
+#ifndef VMS
+#include <time.h>
+#else
+#include <sys/time.h>
+#include "vms.h"
+#endif
+
+#include <stdlib.h>
+#include <sys/stat.h>
+
+#ifndef VMS
+#include <unistd.h>
+#endif
+
+#include "exclude.h"
+
+#ifdef __NetBSD__
+#include <sys/time.h>
+#include <sys/resource.h>
+#endif
+
+struct directory * root = NULL;
+
+static char version_string[] = "mkisofs v1.04";
+
+FILE * discimage;
+unsigned int next_extent = 0;
+unsigned int last_extent = 0;
+unsigned int path_table_size = 0;
+unsigned int path_table[4] = {0,};
+unsigned int path_blocks = 0;
+struct iso_directory_record root_record;
+static int timezone_offset;
+char * extension_record = NULL;
+int extension_record_extent = 0;
+static int extension_record_size = 0;
+
+/* These variables are associated with command line options */
+int use_RockRidge = 0;
+int verbose = 0;
+int all_files = 0;
+int follow_links = 0;
+int generate_tables = 0;
+char * preparer = PREPARER_DEFAULT;
+char * publisher = PUBLISHER_DEFAULT;
+char * appid = APPID_DEFAULT;
+char * copyright = COPYRIGHT_DEFAULT;
+char * biblio = BIBLIO_DEFAULT;
+char * abstract = ABSTRACT_DEFAULT;
+char * volset_id = VOLSET_ID_DEFAULT;
+char * volume_id = VOLUME_ID_DEFAULT;
+char * system_id = SYSTEM_ID_DEFAULT;
+
+int omit_period = 0; /* Violates iso9660, but these are a pain */
+int transparent_compression = 0; /* So far only works with linux */
+int omit_version_number = 0; /* May violate iso9660, but noone uses vers*/
+int RR_relocation_depth = 6; /* Violates iso9660, but most systems work */
+int full_iso9660_filenames = 0; /* Used with Amiga. Disc will not work with
+ DOS */
+int allow_leading_dots = 0; /* DOS cannot read names with leading dots */
+
+struct rcopts{
+ char * tag;
+ char ** variable;
+};
+
+struct rcopts rcopt[] = {
+ {"PREP", &preparer},
+ {"PUBL", &publisher},
+ {"APPI", &appid},
+ {"COPY", &copyright},
+ {"BIBL", &biblio},
+ {"ABST", &abstract},
+ {"VOLS", &volset_id},
+ {"VOLI", &volume_id},
+ {"SYSI", &system_id},
+ {NULL, NULL}
+};
+
+#ifdef ultrix
+char *strdup(s)
+char *s;{char *c;if(c=(char *)malloc(strlen(s)+1))strcpy(c,s);return c;}
+#endif
+
+void FDECL1(read_rcfile, char *, appname)
+{
+ FILE * rcfile;
+ struct rcopts * rco;
+ char * pnt, *pnt1;
+ char linebuffer[256];
+ rcfile = fopen(".mkisofsrc","r");
+
+ if(!rcfile) {
+ if(strlen(appname)+sizeof(".mkisofsrc") > sizeof(linebuffer)) return;
+ strcpy(linebuffer, appname);
+ pnt = strrchr(linebuffer,'/');
+ if(!pnt) return;
+ pnt++;
+ strcpy(pnt, ".mkisofsrc");
+ rcfile = fopen(linebuffer,"r");
+ fprintf(stderr, "Using %s.\n", linebuffer);
+ } else {
+ fprintf(stderr, "Using ./.mkisofsrc.\n");
+ }
+
+ if(!rcfile) return;
+
+ /* OK, we got it. Now read in the lines and parse them */
+ while(!feof(rcfile))
+ {
+ fgets(linebuffer, sizeof(linebuffer), rcfile);
+ pnt = linebuffer;
+ while(1==1) {
+ if(*pnt == ' ' || *pnt == '\t' || *pnt == '\n' || *pnt == 0) break;
+ if(islower(*pnt)) *pnt = toupper(*pnt);
+ pnt++;
+ }
+ /* OK, now find the '=' sign */
+ while(*pnt && *pnt != '=' && *pnt != '#') pnt++;
+
+ if(*pnt == '#') continue; /* SKip comment */
+ if(*pnt != '=') continue; /* Skip to next line */
+ pnt++; /* Skip past '=' sign */
+
+ while(*pnt == ' ' || *pnt == '\t') pnt++; /* And skip past whitespace */
+
+ /* Now get rid of trailing newline */
+ pnt1 = pnt;
+ while(*pnt1) {
+ if(*pnt1 == '\n') *pnt1 = 0;
+ else
+ pnt1++;
+ };
+ pnt1 = linebuffer;
+ while(*pnt1 == ' ' || *pnt1 == '\t') pnt1++;
+ /* OK, now figure out which option we have */
+ for(rco = rcopt; rco->tag; rco++) {
+ if(strncmp(rco->tag, pnt1, 4) == 0)
+ {
+ *rco->variable = strdup(pnt);
+ break;
+ };
+ }
+ }
+ fclose(rcfile);
+}
+
+char * path_table_l = NULL;
+char * path_table_m = NULL;
+int goof = 0;
+
+void usage(){
+ fprintf(stderr,"Usage:\n");
+ fprintf(stderr,
+"mkisofs [-o outfile] [-R] [-V volid] [-v] [-a] \
+[-T]\n [-l] [-d] [-V] [-D] [-L] [-p preparer] \
+[-P publisher] [ -A app_id ] [-z] \
+[-x path -x path ...] path\n");
+ exit(1);
+}
+
+int get_iso9660_timezone_offset(){
+ struct tm gm;
+ struct tm * pt;
+ time_t ctime;
+ int local_min, gmt_min;
+
+ time(&ctime);
+ pt = gmtime(&ctime);
+ gm = *pt;
+ pt = localtime(&ctime);
+
+ if(gm.tm_year < pt->tm_year)
+ gm.tm_yday = -1;
+
+ if(gm.tm_year > pt->tm_year)
+ pt->tm_yday = -1;
+
+ gmt_min = gm.tm_min + 60*(gm.tm_hour + 24*gm.tm_yday);
+ local_min = pt->tm_min + 60*(pt->tm_hour + 24*pt->tm_yday);
+ return (gmt_min - local_min)/15;
+}
+
+
+/* Fill in date in the iso9660 format */
+int FDECL2(iso9660_date,char *, result, time_t, ctime){
+ struct tm *local;
+ local = localtime(&ctime);
+ result[0] = local->tm_year;
+ result[1] = local->tm_mon + 1;
+ result[2] = local->tm_mday;
+ result[3] = local->tm_hour;
+ result[4] = local->tm_min;
+ result[5] = local->tm_sec;
+ result[6] = timezone_offset;
+ return 0;
+}
+
+int FDECL3(iso9660_file_length,const char*, name, struct directory_entry *, sresult,
+ int, dirflag){
+ int seen_dot = 0;
+ int seen_semic = 0;
+ char * result;
+ int priority = 32767;
+ int tildes = 0;
+ int ignore = 0;
+ int extra = 0;
+ int current_length = 0;
+ int chars_after_dot = 0;
+ int chars_before_dot = 0;
+ const char * pnt;
+ result = sresult->isorec.name;
+
+ if(strcmp(name,".") == 0){
+ if(result) *result = 0;
+ return 1;
+ };
+
+ if(strcmp(name,"..") == 0){
+ if(result) {
+ *result++ = 1;
+ *result++ = 0;
+ }
+ return 1;
+ };
+
+ pnt = name;
+ while(*pnt){
+#ifdef VMS
+ if(strcmp(pnt,".DIR;1") == 0) break;
+#endif
+ if(*pnt == '#') {priority = 1; pnt++; continue; };
+ if(*pnt == '~') {priority = 1; tildes++; pnt++; continue;};
+ if(*pnt == ';') {seen_semic = 1; *result++ = *pnt++; continue; };
+ if(ignore) {pnt++; continue;};
+ if(seen_semic){
+ if(*pnt >= '0' && *pnt <= '9') *result++ = *pnt;
+ extra++;
+ pnt++;
+ continue;
+ };
+ if(full_iso9660_filenames) {
+ /* Here we allow a more relaxed syntax. */
+ if(*pnt == '.') {
+ if (seen_dot) {ignore++; continue;}
+ seen_dot++;
+ }
+ if(current_length < 30) *result++ = (islower(*pnt) ? toupper(*pnt) : *pnt);
+ } else { /* Dos style filenames */
+ if(*pnt == '.') {
+ if (!chars_before_dot && !allow_leading_dots) {
+ /* DOS can't read files with dot first */
+ chars_before_dot++;
+ if (result) *result++ = '_'; /* Substitute underscore */
+ } else {
+ if (seen_dot) {ignore++; continue;}
+ if(result) *result++ = '.';
+ seen_dot++;
+ }
+ } else if (seen_dot) {
+ if(chars_after_dot < 3) {
+ chars_after_dot++;
+ if(result) *result++ = (islower(*pnt) ? toupper(*pnt) : *pnt);
+ }
+ } else {
+ if(chars_before_dot < 8) {
+ chars_before_dot++;
+ if(result) *result++ = (islower(*pnt) ? toupper(*pnt) : *pnt);
+ };
+ };
+ };
+ current_length++;
+ pnt++;
+ };
+
+ if(tildes == 2){
+ int prio1 = 0;
+ pnt = name;
+ while (*pnt && *pnt != '~') pnt++;
+ if (*pnt) pnt++;
+ while(*pnt && *pnt != '~'){
+ prio1 = 10*prio1 + *pnt - '0';
+ pnt++;
+ };
+ priority = prio1;
+ };
+
+ if (!dirflag){
+ if (!seen_dot && !omit_period) {
+ if (result) *result++ = '.';
+ extra++;
+ };
+ if(!omit_version_number && !seen_semic) {
+ if(result){
+ *result++ = ';';
+ *result++ = '1';
+ };
+ extra += 2;
+ }
+ };
+ if(result) *result++ = 0;
+
+#if 1 /* WALNUT CREEK HACKS -- rab 950126 */
+{
+ int i, c, len;
+ char *r;
+
+ assert(result);
+ assert(omit_version_number);
+ assert(omit_period);
+ assert(extra == 0);
+ r = sresult->isorec.name;
+ len = strlen(r);
+ if (r[len - 1] == '.') {
+ assert(seen_dot && chars_after_dot == 0);
+ r[--len] = '\0';
+ seen_dot = 0;
+ }
+ for (i = 0; i < len; ++i) {
+ c = r[i];
+ if (c == '.') {
+ if (dirflag) {
+ fprintf(stderr, "changing DIR %s to ", r);
+ r[i] = '\0';
+ fprintf(stderr, "%s\n", r);
+ chars_after_dot = 0;
+ seen_dot = 0;
+ extra = 0;
+ break;
+ }
+ } else if (!isalnum(c) && c != '_') {
+ fprintf(stderr, "changing %s to ", r);
+ r[i] = '_';
+ fprintf(stderr, "%s\n", r);
+ }
+ }
+}
+#endif
+
+ sresult->priority = priority;
+ return chars_before_dot + chars_after_dot + seen_dot + extra;
+}
+
+#ifdef ADD_FILES
+
+struct file_adds *root_file_adds = NULL;
+
+void
+FDECL2(add_one_file, char *, addpath, char *, path )
+{
+ char *cp;
+ char *name;
+ struct file_adds *f;
+ struct file_adds *tmp;
+
+ f = root_file_adds;
+ tmp = NULL;
+
+ name = rindex (addpath, PATH_SEPARATOR);
+ if (name == NULL) {
+ name = addpath;
+ } else {
+ name++;
+ }
+
+ cp = strtok (addpath, SPATH_SEPARATOR);
+
+ while (cp != NULL && strcmp (name, cp)) {
+ if (f == NULL) {
+ root_file_adds = e_malloc (sizeof *root_file_adds);
+ f=root_file_adds;
+ f->name = NULL;
+ f->child = NULL;
+ f->next = NULL;
+ f->add_count = 0;
+ f->adds = NULL;
+ f->used = 0;
+ }
+ if (f->child) {
+ for (tmp = f->child; tmp->next != NULL; tmp =tmp->next) {
+ if (strcmp (tmp->name, cp) == 0) {
+ f = tmp;
+ goto next;
+ }
+ }
+ if (strcmp (tmp->name, cp) == 0) {
+ f=tmp;
+ goto next;
+ }
+ /* add a new node. */
+ tmp->next = e_malloc (sizeof (*tmp->next));
+ f=tmp->next;
+ f->name = strdup (cp);
+ f->child = NULL;
+ f->next = NULL;
+ f->add_count = 0;
+ f->adds = NULL;
+ f->used = 0;
+ } else {
+ /* no children. */
+ f->child = e_malloc (sizeof (*f->child));
+ f = f->child;
+ f->name = strdup (cp);
+ f->child = NULL;
+ f->next = NULL;
+ f->add_count = 0;
+ f->adds = NULL;
+ f->used = 0;
+
+ }
+ next:
+ cp = strtok (NULL, SPATH_SEPARATOR);
+ }
+ /* Now f if non-null points to where we should add things */
+ if (f == NULL) {
+ root_file_adds = e_malloc (sizeof *root_file_adds);
+ f=root_file_adds;
+ f->name = NULL;
+ f->child = NULL;
+ f->next = NULL;
+ f->add_count = 0;
+ f->adds = NULL;
+ }
+
+ /* Now f really points to where we should add this name. */
+ f->add_count++;
+ f->adds = realloc (f->adds, sizeof (*f->adds)*f->add_count);
+ f->adds[f->add_count-1].path = strdup (path);
+ f->adds[f->add_count-1].name = strdup (name);
+}
+
+void
+FDECL3(add_file_list, int, argc, char **,argv, int, ind)
+{
+ char *ptr;
+ char *dup_arg;
+
+ while (ind < argc) {
+ dup_arg = strdup (argv[ind]);
+ ptr = index (dup_arg,'=');
+ if (ptr == NULL) {
+ free (dup_arg);
+ return;
+ }
+ *ptr = 0;
+ ptr++;
+ add_one_file (dup_arg, ptr);
+ free (dup_arg);
+ ind++;
+ }
+}
+void
+FDECL1(add_file, char *, filename)
+{
+ char buff[1024];
+ FILE *f;
+ char *ptr;
+ char *p2;
+ int count=0;
+
+ if (strcmp (filename, "-") == 0) {
+ f = stdin;
+ } else {
+ f = fopen (filename, "r");
+ if (f == NULL) {
+ perror ("fopen");
+ exit (1);
+ }
+ }
+ while (fgets (buff, 1024, f)) {
+ count++;
+ ptr = buff;
+ while (isspace (*ptr)) ptr++;
+ if (*ptr==0) continue;
+ if (*ptr=='#') continue;
+
+ if (ptr[strlen(ptr)-1]== '\n') ptr[strlen(ptr)-1]=0;
+ p2 = index (ptr, '=');
+ if (p2 == NULL) {
+ fprintf (stderr, "Error in line %d: %s\n", count, buff);
+ exit (1);
+ }
+ *p2 = 0;
+ p2++;
+ add_one_file (ptr, p2);
+ }
+ if (f != stdin) fclose (f);
+}
+
+#endif
+
+int FDECL2(main, int, argc, char **, argv){
+ char * outfile;
+ struct directory_entry de;
+ unsigned int mem_start;
+ struct stat statbuf;
+ char * scan_tree;
+ int c;
+#ifdef ADD_FILES
+ char *add_file_file = NULL;
+#endif
+
+ if (argc < 2)
+ usage();
+
+ /* Get the defaults from the .mkisofsrc file */
+ read_rcfile(argv[0]);
+
+ outfile = NULL;
+ while ((c = getopt(argc, argv, "i:o:V:RfvaTp:P:x:dDlLNzA:")) != EOF)
+ switch (c)
+ {
+ case 'p':
+ preparer = optarg;
+ if(strlen(preparer) > 128) {
+ fprintf(stderr,"Preparer string too long\n");
+ exit(1);
+ };
+ break;
+ case 'P':
+ publisher = optarg;
+ if(strlen(publisher) > 128) {
+ fprintf(stderr,"Publisher string too long\n");
+ exit(1);
+ };
+ break;
+ case 'A':
+ appid = optarg;
+ if(strlen(appid) > 128) {
+ fprintf(stderr,"Application-id string too long\n");
+ exit(1);
+ };
+ break;
+ case 'd':
+ omit_period++;
+ break;
+ case 'D':
+ RR_relocation_depth = 32767;
+ break;
+ case 'l':
+ full_iso9660_filenames++;
+ break;
+ case 'L':
+ allow_leading_dots++;
+ break;
+ case 'N':
+ omit_version_number++;
+ break;
+ case 'o':
+ outfile = optarg;
+ break;
+ case 'f':
+ follow_links++;
+ break;
+ case 'R':
+ use_RockRidge++;
+ break;
+ case 'V':
+ volume_id = optarg;
+ break;
+ case 'v':
+ verbose++;
+ break;
+ case 'a':
+ all_files++;
+ break;
+ case 'T':
+ generate_tables++;
+ break;
+ case 'z':
+#ifdef VMS
+ fprintf(stderr,"Transparent compression not supported with VMS\n");
+ exit(1);
+#else
+ transparent_compression++;
+#endif
+ break;
+ case 'x':
+ exclude(optarg);
+ break;
+ case 'i':
+#ifdef ADD_FILES
+ add_file_file = optarg;
+ break;
+#endif
+ default:
+ usage();
+ exit(1);
+ }
+#ifdef __NetBSD__
+ {
+ int resource;
+ struct rlimit rlp;
+ if (getrlimit(RLIMIT_DATA,&rlp) == -1)
+ perror("Warning: getrlimit");
+ else {
+ rlp.rlim_cur=33554432;
+ if (setrlimit(RLIMIT_DATA,&rlp) == -1)
+ perror("Warning: setrlimit");
+ }
+ }
+#endif
+ mem_start = (unsigned int) sbrk(0);
+
+ if(verbose) fprintf(stderr,"%s\n", version_string);
+ /* Now find the timezone offset */
+
+ timezone_offset = get_iso9660_timezone_offset();
+
+ /* The first step is to scan the directory tree, and take some notes */
+
+ scan_tree = argv[optind];
+
+#ifdef ADD_FILES
+ if (add_file_file) {
+ add_file(add_file_file);
+ }
+ add_file_list (argc, argv, optind+1);
+#endif
+
+ if(!scan_tree){
+ usage();
+ exit(1);
+ };
+
+#ifndef VMS
+ if(scan_tree[strlen(scan_tree)-1] != '/') {
+ scan_tree = (char *) e_malloc(strlen(argv[optind])+2);
+ strcpy(scan_tree, argv[optind]);
+ strcat(scan_tree, "/");
+ };
+#endif
+
+ if(use_RockRidge){
+#if 1
+ extension_record = generate_rr_extension_record("RRIP_1991A",
+ "THE ROCK RIDGE INTERCHANGE PROTOCOL PROVIDES SUPPORT FOR POSIX FILE SYSTEM SEMANTICS",
+ "PLEASE CONTACT DISC PUBLISHER FOR SPECIFICATION SOURCE. SEE PUBLISHER IDENTIFIER IN PRIMARY VOLUME DESCRIPTOR FOR CONTACT INFORMATION.", &extension_record_size);
+#else
+ extension_record = generate_rr_extension_record("IEEE_P1282",
+ "THE IEEE P1282 PROTOCOL PROVIDES SUPPORT FOR POSIX FILE SYSTEM SEMANTICS",
+ "PLEASE CONTACT THE IEEE STANDARDS DEPARTMENT, PISCATAWAY, NJ, USA FOR THE P1282 SPECIFICATION.", &extension_record_size);
+#endif
+ };
+
+ stat(argv[optind], &statbuf);
+ add_directory_hash(statbuf.st_dev, STAT_INODE(statbuf));
+
+ de.filedir = root; /* We need this to bootstrap */
+ scan_directory_tree(argv[optind], &de);
+ root->self = root->contents; /* Fix this up so that the path tables get done right */
+
+ if(reloc_dir) sort_n_finish(reloc_dir);
+
+ if (goof) exit(1);
+
+ if (outfile){
+ discimage = fopen(outfile, "w");
+ if (!discimage){
+ fprintf(stderr,"Unable to open disc image file\n");
+ exit(1);
+
+ };
+ } else
+ discimage = stdout;
+
+ /* Now assign addresses on the disc for the path table. */
+
+ path_blocks = (path_table_size + (SECTOR_SIZE - 1)) >> 11;
+ if (path_blocks & 1) path_blocks++;
+ path_table[0] = 0x14;
+ path_table[1] = path_table[0] + path_blocks;
+ path_table[2] = path_table[1] + path_blocks;
+ path_table[3] = path_table[2] + path_blocks;
+
+ last_extent = path_table[3] + path_blocks; /* The next free block */
+
+ /* The next step is to go through the directory tree and assign extent
+ numbers for all of the directories */
+
+ assign_directory_addresses(root);
+
+ if(extension_record) {
+ struct directory_entry * s_entry;
+ extension_record_extent = last_extent++;
+ s_entry = root->contents;
+ set_733(s_entry->rr_attributes + s_entry->rr_attr_size - 24,
+ extension_record_extent);
+ set_733(s_entry->rr_attributes + s_entry->rr_attr_size - 8,
+ extension_record_size);
+ };
+
+ if (use_RockRidge && reloc_dir)
+ finish_cl_pl_entries();
+
+ /* Now we generate the path tables that are used by DOS to improve directory
+ access times. */
+ generate_path_tables();
+
+ /* Generate root record for volume descriptor. */
+ generate_root_record();
+
+ dump_tree(root);
+
+ iso_write(discimage);
+
+ fprintf(stderr,"Max brk space used %x\n",
+ ((unsigned int)sbrk(0)) - mem_start);
+ fprintf(stderr,"%d extents written (%d Mb)\n", last_extent, last_extent >> 9);
+#ifdef VMS
+ return 1;
+#else
+ return 0;
+#endif
+}
+
+void *e_malloc(size_t size)
+{
+void* pt;
+ if((pt=malloc(size))==NULL) {
+ printf("Not enougth memory\n");
+ exit (1);
+ }
+return pt;
+}
diff --git a/gnu/usr.bin/mkisofs/mkisofs.h b/gnu/usr.bin/mkisofs/mkisofs.h
new file mode 100644
index 0000000..f7c43ca
--- /dev/null
+++ b/gnu/usr.bin/mkisofs/mkisofs.h
@@ -0,0 +1,263 @@
+/*
+ * Header file mkisofs.h - assorted structure definitions and typecasts.
+
+ Written by Eric Youngdale (1993).
+
+ Copyright 1993 Yggdrasil Computing, Incorporated
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* ADD_FILES changes made by Ross Biro biro@yggdrasil.com 2/23/95 */
+
+#include <stdio.h>
+
+/* This symbol is used to indicate that we do not have things like
+ symlinks, devices, and so forth available. Just files and dirs */
+
+#ifdef VMS
+#define NON_UNIXFS
+#endif
+
+#ifdef DJGPP
+#define NON_UNIXFS
+#endif
+
+#ifdef VMS
+#include <sys/dir.h>
+#define dirent direct
+#else
+#include <dirent.h>
+#endif
+
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#ifdef linux
+#include <sys/dir.h>
+#endif
+
+#ifdef ultrix
+extern char *strdup();
+#endif
+
+#ifdef __STDC__
+#define DECL(NAME,ARGS) NAME ARGS
+#define FDECL1(NAME,TYPE0, ARG0) \
+ NAME(TYPE0 ARG0)
+#define FDECL2(NAME,TYPE0, ARG0,TYPE1, ARG1) \
+ NAME(TYPE0 ARG0, TYPE1 ARG1)
+#define FDECL3(NAME,TYPE0, ARG0,TYPE1, ARG1, TYPE2, ARG2) \
+ NAME(TYPE0 ARG0, TYPE1 ARG1, TYPE2 ARG2)
+#define FDECL4(NAME,TYPE0, ARG0,TYPE1, ARG1, TYPE2, ARG2, TYPE3, ARG3) \
+ NAME(TYPE0 ARG0, TYPE1 ARG1, TYPE2 ARG2, TYPE3 ARG3)
+#define FDECL5(NAME,TYPE0, ARG0,TYPE1, ARG1, TYPE2, ARG2, TYPE3, ARG3, TYPE4, ARG4) \
+ NAME(TYPE0 ARG0, TYPE1 ARG1, TYPE2 ARG2, TYPE3 ARG3, TYPE4 ARG4)
+#define FDECL6(NAME,TYPE0, ARG0,TYPE1, ARG1, TYPE2, ARG2, TYPE3, ARG3, TYPE4, ARG4, TYPE5, ARG5) \
+ NAME(TYPE0 ARG0, TYPE1 ARG1, TYPE2 ARG2, TYPE3 ARG3, TYPE4 ARG4, TYPE5 ARG5)
+#else
+#define DECL(NAME,ARGS) NAME()
+#define FDECL1(NAME,TYPE0, ARG0) NAME(ARG0) TYPE0 ARG0;
+#define FDECL2(NAME,TYPE0, ARG0,TYPE1, ARG1) NAME(ARG0, ARG1) TYPE0 ARG0; TYPE1 ARG1;
+#define FDECL3(NAME,TYPE0, ARG0,TYPE1, ARG1, TYPE2, ARG2) \
+ NAME(ARG0, ARG1, ARG2) TYPE0 ARG0; TYPE1 ARG1; TYPE2 ARG2;
+#define FDECL4(NAME,TYPE0, ARG0,TYPE1, ARG1, TYPE2, ARG2, TYPE3, ARG3) \
+ NAME(ARG0, ARG1, ARG2, ARG3, ARG4) TYPE0 ARG0; TYPE1 ARG1; TYPE2 ARG2; TYPE3 ARG3;
+#define FDECL5(NAME,TYPE0, ARG0,TYPE1, ARG1, TYPE2, ARG2, TYPE3, ARG3, TYPE4, ARG4) \
+ NAME(ARG0, ARG1, ARG2, ARG3, ARG4) TYPE0 ARG0; TYPE1 ARG1; TYPE2 ARG2; TYPE3 ARG3; TYPE4 ARG4;
+#define FDECL6(NAME,TYPE0, ARG0,TYPE1, ARG1, TYPE2, ARG2, TYPE3, ARG3, TYPE4, ARG4, TYPE5, ARG5) \
+ NAME(ARG0, ARG1, ARG2, ARG3, ARG4, ARG5) TYPE0 ARG0; TYPE1 ARG1; TYPE2 ARG2; TYPE3 ARG3; TYPE4 ARG4; TYPE5 ARG5;
+#define const
+#endif
+
+
+#ifdef __svr4__
+#include <stdlib.h>
+#else
+extern int optind;
+extern char *optarg;
+/* extern int getopt (int __argc, char **__argv, char *__optstring); */
+#endif
+
+#include "iso9660.h"
+#include "defaults.h"
+
+struct directory_entry{
+ struct directory_entry * next;
+ struct iso_directory_record isorec;
+ unsigned int starting_block;
+ unsigned int size;
+ unsigned int priority;
+ char * name;
+ char * table;
+ char * whole_name;
+ struct directory * filedir;
+ struct directory_entry * parent_rec;
+ unsigned int flags;
+ ino_t inode; /* Used in the hash table */
+ dev_t dev; /* Used in the hash table */
+ unsigned char * rr_attributes;
+ unsigned int rr_attr_size;
+ unsigned int total_rr_attr_size;
+};
+
+struct file_hash{
+ struct file_hash * next;
+ ino_t inode; /* Used in the hash table */
+ dev_t dev; /* Used in the hash table */
+ unsigned int starting_block;
+ unsigned int size;
+};
+
+struct directory{
+ struct directory * next; /* Next directory at same level as this one */
+ struct directory * subdir; /* First subdirectory in this directory */
+ struct directory * parent;
+ struct directory_entry * contents;
+ struct directory_entry * self;
+ char * whole_name; /* Entire path */
+ char * de_name; /* Entire path */
+ unsigned int ce_bytes; /* Number of bytes of CE entries reqd for this dir */
+ unsigned int depth;
+ unsigned int size;
+ unsigned int extent;
+ unsigned short path_index;
+};
+
+struct deferred{
+ struct deferred * next;
+ unsigned int starting_block;
+ char * name;
+ struct directory * filedir;
+ unsigned int flags;
+};
+
+#ifdef ADD_FILES
+struct file_adds {
+ char *name;
+ struct file_adds *child;
+ struct file_adds *next;
+ int add_count;
+ int used;
+ struct dirent de;
+ struct {
+ char *path;
+ char *name;
+ } *adds;
+};
+extern struct file_adds *root_file_adds;
+
+#endif
+
+extern void DECL(sort_n_finish,(struct directory *));
+extern int goof;
+extern struct directory * root;
+extern struct directory * reloc_dir;
+extern unsigned int next_extent;
+extern unsigned int last_extent;
+extern unsigned int path_table_size;
+extern unsigned int path_table[4];
+extern unsigned int path_blocks;
+extern char * path_table_l;
+extern char * path_table_m;
+extern struct iso_directory_record root_record;
+
+extern int use_RockRidge;
+extern int follow_links;
+extern int verbose;
+extern int all_files;
+extern int generate_tables;
+extern int omit_period;
+extern int omit_version_number;
+extern int transparent_compression;
+extern int RR_relocation_depth;
+extern int full_iso9660_filenames;
+
+extern int DECL(scan_directory_tree,(char * path, struct directory_entry * self));
+extern void DECL(dump_tree,(struct directory * node));
+extern void DECL(assign_directory_addresses,(struct directory * root));
+
+extern int DECL(iso9660_file_length,(const char* name,
+ struct directory_entry * sresult, int flag));
+extern int DECL(iso_write,(FILE * outfile));
+extern void generate_path_tables();
+extern void DECL(generate_iso9660_directories,(struct directory *, FILE*));
+extern void DECL(generate_one_directory,(struct directory *, FILE*));
+extern void generate_root_record();
+extern int DECL(iso9660_date,(char *, time_t));
+extern void DECL(add_hash,(struct directory_entry *));
+extern struct file_hash * DECL(find_hash,(dev_t, ino_t));
+extern void DECL(add_directory_hash,(dev_t, ino_t));
+extern struct file_hash * DECL(find_directory_hash,(dev_t, ino_t));
+extern void flush_file_hash();
+extern int DECL(delete_file_hash,(struct directory_entry *));
+extern struct directory_entry * DECL(find_file_hash,(char *));
+extern void DECL(add_file_hash,(struct directory_entry *));
+extern void finish_cl_pl_entries();
+extern int DECL(get_733,(char *));
+
+extern void DECL(set_723,(char *, unsigned int));
+extern void DECL(set_733,(char *, unsigned int));
+extern void DECL(sort_directory,(struct directory_entry **));
+extern int DECL(generate_rock_ridge_attributes,(char *, char *,
+ struct directory_entry *,
+ struct stat *, struct stat *,
+ int deep_flag));
+extern char * DECL(generate_rr_extension_record,(char * id, char * descriptor,
+ char * source, int * size));
+
+extern char * extension_record;
+extern int extension_record_extent;
+extern int n_data_extents;
+
+/* These are a few goodies that can be specified on the command line, and are
+ filled into the root record */
+
+extern char * preparer;
+extern char * publisher;
+extern char * copyright;
+extern char * biblio;
+extern char * abstract;
+extern char * appid;
+extern char * volset_id;
+extern char * system_id;
+extern char * volume_id;
+
+extern void * DECL(e_malloc,(size_t));
+
+
+#define SECTOR_SIZE (2048)
+#define ROUND_UP(X) ((X + (SECTOR_SIZE - 1)) & ~(SECTOR_SIZE - 1))
+
+#define NEED_RE 1
+#define NEED_PL 2
+#define NEED_CL 4
+#define NEED_CE 8
+#define NEED_SP 16
+
+#define TABLE_INODE (sizeof(ino_t) >= 4 ? 0x7ffffffe : 0x7ffe)
+#define UNCACHED_INODE (sizeof(ino_t) >= 4 ? 0x7fffffff : 0x7fff)
+#define UNCACHED_DEVICE (sizeof(dev_t) >= 4 ? 0x7fffffff : 0x7fff)
+
+#ifdef VMS
+#define STAT_INODE(X) (X.st_ino[0])
+#define PATH_SEPARATOR ']'
+#define SPATH_SEPARATOR ""
+#else
+#define STAT_INODE(X) (X.st_ino)
+#define PATH_SEPARATOR '/'
+#define SPATH_SEPARATOR "/"
+#endif
+
diff --git a/gnu/usr.bin/mkisofs/rock.c b/gnu/usr.bin/mkisofs/rock.c
new file mode 100644
index 0000000..f3361ce
--- /dev/null
+++ b/gnu/usr.bin/mkisofs/rock.c
@@ -0,0 +1,530 @@
+/*
+ * File rock.c - generate RRIP records for iso9660 filesystems.
+
+ Written by Eric Youngdale (1993).
+
+ Copyright 1993 Yggdrasil Computing, Incorporated
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <stdlib.h>
+
+#ifndef VMS
+#if defined(HASSYSMACROS) && !defined(HASMKDEV)
+#include <sys/sysmacros.h>
+#endif
+#include <unistd.h>
+#endif
+#ifdef HASMKDEV
+#include <sys/types.h>
+#include <sys/mkdev.h>
+#endif
+
+#include "mkisofs.h"
+#include "iso9660.h"
+#include <string.h>
+
+#ifdef NON_UNIXFS
+#define S_ISLNK(m) (0)
+#else
+#ifndef S_ISLNK
+#define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK)
+#endif
+#endif
+
+#define SU_VERSION 1
+
+#define SL_ROOT 8
+#define SL_PARENT 4
+#define SL_CURRENT 2
+#define SL_CONTINUE 1
+
+#define CE_SIZE 28
+#define CL_SIZE 12
+#define ER_SIZE 8
+#define NM_SIZE 5
+#define PL_SIZE 12
+#define PN_SIZE 20
+#define PX_SIZE 36
+#define RE_SIZE 4
+#define SL_SIZE 20
+#define ZZ_SIZE 15
+#ifdef __QNX__
+#define TF_SIZE (5 + 4 * 7)
+#else
+#define TF_SIZE (5 + 3 * 7)
+#endif
+
+/* If we need to store this number of bytes, make sure we
+ do not box ourselves in so that we do not have room for
+ a CE entry for the continuation record */
+
+#define MAYBE_ADD_CE_ENTRY(BYTES) \
+ (BYTES + CE_SIZE + currlen + (ipnt - recstart) > reclimit ? 1 : 0)
+
+/*
+ * Buffer to build RR attributes
+ */
+
+static unsigned char Rock[16384];
+static unsigned char symlink_buff[256];
+static int ipnt = 0;
+static int recstart = 0;
+static int currlen = 0;
+static int mainrec = 0;
+static int reclimit;
+
+static add_CE_entry(){
+ if(recstart)
+ set_733((char*)Rock + recstart - 8, ipnt + 28 - recstart);
+ Rock[ipnt++] ='C';
+ Rock[ipnt++] ='E';
+ Rock[ipnt++] = CE_SIZE;
+ Rock[ipnt++] = SU_VERSION;
+ set_733((char*)Rock + ipnt, 0);
+ ipnt += 8;
+ set_733((char*)Rock + ipnt, 0);
+ ipnt += 8;
+ set_733((char*)Rock + ipnt, 0);
+ ipnt += 8;
+ recstart = ipnt;
+ currlen = 0;
+ if(!mainrec) mainrec = ipnt;
+ reclimit = SECTOR_SIZE - 8; /* Limit to one sector */
+}
+
+#ifdef __STDC__
+int generate_rock_ridge_attributes (char * whole_name, char * name,
+ struct directory_entry * s_entry,
+ struct stat * statbuf,
+ struct stat * lstatbuf,
+ int deep_opt)
+#else
+int generate_rock_ridge_attributes (whole_name, name,
+ s_entry,
+ statbuf,
+ lstatbuf,
+ deep_opt)
+char * whole_name; char * name; struct directory_entry * s_entry;
+struct stat * statbuf, *lstatbuf;
+int deep_opt;
+#endif
+{
+ int flagpos, flagval;
+ int need_ce;
+
+ statbuf = statbuf; /* this shuts up unreferenced compiler warnings */
+ mainrec = recstart = ipnt = 0;
+ reclimit = 0xf8;
+
+ /* Obtain the amount of space that is currently used for the directory
+ record. Assume max for name, since name conflicts may cause us
+ to rename the file later on */
+ currlen = sizeof(s_entry->isorec);
+
+ /* Identify that we are using the SUSP protocol */
+ if(deep_opt & NEED_SP){
+ Rock[ipnt++] ='S';
+ Rock[ipnt++] ='P';
+ Rock[ipnt++] = 7;
+ Rock[ipnt++] = SU_VERSION;
+ Rock[ipnt++] = 0xbe;
+ Rock[ipnt++] = 0xef;
+ Rock[ipnt++] = 0;
+ };
+
+ /* First build the posix name field */
+ Rock[ipnt++] ='R';
+ Rock[ipnt++] ='R';
+ Rock[ipnt++] = 5;
+ Rock[ipnt++] = SU_VERSION;
+ flagpos = ipnt;
+ flagval = 0;
+ Rock[ipnt++] = 0; /* We go back and fix this later */
+
+ if(strcmp(name,".") && strcmp(name,"..")){
+ char * npnt;
+ int remain, use;
+
+ remain = strlen(name);
+ npnt = name;
+
+ while(remain){
+ use = remain;
+ need_ce = 0;
+ /* Can we fit this SUSP and a CE entry? */
+ if(use + currlen + CE_SIZE + (ipnt - recstart) > reclimit) {
+ use = reclimit - currlen - CE_SIZE - (ipnt - recstart);
+ need_ce++;
+ }
+
+ /* Only room for 256 per SUSP field */
+ if(use > 0xf8) use = 0xf8;
+
+ /* First build the posix name field */
+ Rock[ipnt++] ='N';
+ Rock[ipnt++] ='M';
+ Rock[ipnt++] = NM_SIZE + use;
+ Rock[ipnt++] = SU_VERSION;
+ Rock[ipnt++] = (remain != use ? 1 : 0);
+ flagval |= (1<<3);
+ strncpy((char *)&Rock[ipnt], npnt, use);
+ npnt += use;
+ ipnt += use;
+ remain -= use;
+ if(remain && need_ce) add_CE_entry();
+ };
+ };
+
+ /*
+ * Add the posix modes
+ */
+ if(MAYBE_ADD_CE_ENTRY(PX_SIZE)) add_CE_entry();
+ Rock[ipnt++] ='P';
+ Rock[ipnt++] ='X';
+ Rock[ipnt++] = PX_SIZE;
+ Rock[ipnt++] = SU_VERSION;
+ flagval |= (1<<0);
+ set_733((char*)Rock + ipnt, lstatbuf->st_mode);
+ ipnt += 8;
+ set_733((char*)Rock + ipnt, lstatbuf->st_nlink);
+ ipnt += 8;
+ set_733((char*)Rock + ipnt, lstatbuf->st_uid);
+ ipnt += 8;
+ set_733((char*)Rock + ipnt, lstatbuf->st_gid);
+ ipnt += 8;
+
+ /*
+ * Check for special devices
+ */
+#ifndef NON_UNIXFS
+ if (S_ISCHR(lstatbuf->st_mode) || S_ISBLK(lstatbuf->st_mode)) {
+ if(MAYBE_ADD_CE_ENTRY(PN_SIZE)) add_CE_entry();
+ Rock[ipnt++] ='P';
+ Rock[ipnt++] ='N';
+ Rock[ipnt++] = PN_SIZE;
+ Rock[ipnt++] = SU_VERSION;
+ flagval |= (1<<1);
+ if(sizeof(dev_t) <= 4) {
+ set_733((char*)Rock + ipnt, 0);
+ ipnt += 8;
+ set_733((char*)Rock + ipnt, lstatbuf->st_rdev);
+ ipnt += 8;
+ }
+ else {
+#if defined(__BSD__)
+ set_733((char*)Rock + ipnt, (lstatbuf->st_rdev >> 16) >> 16);
+#else
+ set_733((char*)Rock + ipnt, lstatbuf->st_rdev >> 32);
+#endif
+ ipnt += 8;
+ set_733((char*)Rock + ipnt, lstatbuf->st_rdev);
+ ipnt += 8;
+ }
+ };
+#endif
+ /*
+ * Check for and symbolic links. VMS does not have these.
+ */
+ if (S_ISLNK(lstatbuf->st_mode)){
+ int lenpos, lenval, j0, j1;
+ int cflag, nchar;
+ unsigned char * cpnt, *cpnt1;
+ nchar = readlink(whole_name, symlink_buff, sizeof(symlink_buff));
+ symlink_buff[nchar] = 0;
+ set_733(s_entry->isorec.size, 0);
+ cpnt = &symlink_buff[0];
+ flagval |= (1<<2);
+
+ while(nchar){
+ if(MAYBE_ADD_CE_ENTRY(SL_SIZE)) add_CE_entry();
+ Rock[ipnt++] ='S';
+ Rock[ipnt++] ='L';
+ lenpos = ipnt;
+ Rock[ipnt++] = SL_SIZE;
+ Rock[ipnt++] = SU_VERSION;
+ Rock[ipnt++] = 0; /* Flags */
+ lenval = 5;
+ while(*cpnt){
+ cpnt1 = (unsigned char *) strchr((char *) cpnt, '/');
+ if(cpnt1) {
+ nchar--;
+ *cpnt1 = 0;
+ };
+
+ /* We treat certain components in a special way. */
+ if(cpnt[0] == '.' && cpnt[1] == '.' && cpnt[2] == 0){
+ if(MAYBE_ADD_CE_ENTRY(2)) add_CE_entry();
+ Rock[ipnt++] = SL_PARENT;
+ Rock[ipnt++] = 0; /* length is zero */
+ lenval += 2;
+ nchar -= 2;
+ } else if(cpnt[0] == '.' && cpnt[1] == 0){
+ if(MAYBE_ADD_CE_ENTRY(2)) add_CE_entry();
+ Rock[ipnt++] = SL_CURRENT;
+ Rock[ipnt++] = 0; /* length is zero */
+ lenval += 2;
+ nchar -= 1;
+ } else if(cpnt[0] == 0){
+ if(MAYBE_ADD_CE_ENTRY(2)) add_CE_entry();
+ Rock[ipnt++] = (cpnt == &symlink_buff[0] ? SL_ROOT : 0);
+ Rock[ipnt++] = 0; /* length is zero */
+ lenval += 2;
+ } else {
+ /* If we do not have enough room for a component, start
+ a new continuations segment now */
+ if(MAYBE_ADD_CE_ENTRY(6)) {
+ add_CE_entry();
+ if(cpnt1){
+ *cpnt1 = '/';
+ cpnt1 = NULL; /* A kluge so that we can restart properly */
+ }
+ break;
+ }
+ j0 = strlen((char *) cpnt);
+ while(j0) {
+ j1 = j0;
+ if(j1 > 0xf8) j1 = 0xf8;
+ need_ce = 0;
+ if(j1 + currlen + CE_SIZE + (ipnt - recstart) > reclimit) {
+ j1 = reclimit - currlen - CE_SIZE - (ipnt - recstart);
+ need_ce++;
+ }
+ Rock[ipnt++] = (j1 != j0 ? SL_CONTINUE : 0);
+ Rock[ipnt++] = j1;
+ strncpy((char *) Rock + ipnt, (char *) cpnt, j1);
+ ipnt += j1;
+ lenval += j1 + 2;
+ cpnt += j1;
+ nchar -= j1; /* Number we processed this time */
+ j0 -= j1;
+ if(need_ce) {
+ add_CE_entry();
+ if(cpnt1) {
+ *cpnt1 = '/';
+ cpnt1 = NULL; /* A kluge so that we can restart properly */
+ }
+ break;
+ }
+ }
+ };
+ if(cpnt1) {
+ cpnt = cpnt1 + 1;
+ } else
+ break;
+ };
+ Rock[lenpos] = lenval;
+ if(nchar) Rock[lenpos + 2] = SL_CONTINUE; /* We need another SL entry */
+ } /* while nchar */
+ } /* Is a symbolic link */
+ /*
+ * Add in the Rock Ridge TF time field
+ */
+ if(MAYBE_ADD_CE_ENTRY(TF_SIZE)) add_CE_entry();
+ Rock[ipnt++] ='T';
+ Rock[ipnt++] ='F';
+ Rock[ipnt++] = TF_SIZE;
+ Rock[ipnt++] = SU_VERSION;
+#ifdef __QNX__
+ Rock[ipnt++] = 0x0f;
+#else
+ Rock[ipnt++] = 0x0e;
+#endif
+ flagval |= (1<<7);
+#ifdef __QNX__
+ iso9660_date((char *) &Rock[ipnt], lstatbuf->st_ftime);
+ ipnt += 7;
+#endif
+ iso9660_date((char *) &Rock[ipnt], lstatbuf->st_mtime);
+ ipnt += 7;
+ iso9660_date((char *) &Rock[ipnt], lstatbuf->st_atime);
+ ipnt += 7;
+ iso9660_date((char *) &Rock[ipnt], lstatbuf->st_ctime);
+ ipnt += 7;
+
+ /*
+ * Add in the Rock Ridge RE time field
+ */
+ if(deep_opt & NEED_RE){
+ if(MAYBE_ADD_CE_ENTRY(RE_SIZE)) add_CE_entry();
+ Rock[ipnt++] ='R';
+ Rock[ipnt++] ='E';
+ Rock[ipnt++] = RE_SIZE;
+ Rock[ipnt++] = SU_VERSION;
+ flagval |= (1<<6);
+ };
+ /*
+ * Add in the Rock Ridge PL record, if required.
+ */
+ if(deep_opt & NEED_PL){
+ if(MAYBE_ADD_CE_ENTRY(PL_SIZE)) add_CE_entry();
+ Rock[ipnt++] ='P';
+ Rock[ipnt++] ='L';
+ Rock[ipnt++] = PL_SIZE;
+ Rock[ipnt++] = SU_VERSION;
+ set_733((char*)Rock + ipnt, 0);
+ ipnt += 8;
+ flagval |= (1<<5);
+ };
+
+ /*
+ * Add in the Rock Ridge CL field, if required.
+ */
+ if(deep_opt & NEED_CL){
+ if(MAYBE_ADD_CE_ENTRY(CL_SIZE)) add_CE_entry();
+ Rock[ipnt++] ='C';
+ Rock[ipnt++] ='L';
+ Rock[ipnt++] = CL_SIZE;
+ Rock[ipnt++] = SU_VERSION;
+ set_733((char*)Rock + ipnt, 0);
+ ipnt += 8;
+ flagval |= (1<<4);
+ };
+
+#ifndef VMS
+ /* If transparent compression was requested, fill in the correct
+ field for this file */
+ if(transparent_compression &&
+ S_ISREG(lstatbuf->st_mode) &&
+ strlen(name) > 3 &&
+ strcmp(name + strlen(name) - 3,".gZ") == 0){
+ FILE * zipfile;
+ char * checkname;
+ unsigned int file_size;
+ unsigned char header[8];
+ int OK_flag;
+
+ /* First open file and verify that the correct algorithm was used */
+ file_size = 0;
+ OK_flag = 1;
+
+ zipfile = fopen(whole_name, "r");
+ fread(header, 1, sizeof(header), zipfile);
+
+ /* Check some magic numbers from gzip. */
+ if(header[0] != 0x1f || header[1] != 0x8b || header[2] != 8) OK_flag = 0;
+ /* Make sure file was blocksized. */
+ if((header[3] & 0x40 == 0)) OK_flag = 0;
+ /* OK, now go to the end of the file and get some more info */
+ if(OK_flag){
+ int status;
+ status = (long)lseek(fileno(zipfile), (off_t)(-8), SEEK_END);
+ if(status == -1) OK_flag = 0;
+ }
+ if(OK_flag){
+ if(read(fileno(zipfile), (char*)header, sizeof(header)) != sizeof(header))
+ OK_flag = 0;
+ else {
+ int blocksize;
+ blocksize = (header[3] << 8) | header[2];
+ file_size = ((unsigned int)header[7] << 24) |
+ ((unsigned int)header[6] << 16) |
+ ((unsigned int)header[5] << 8) | header[4];
+#if 0
+ fprintf(stderr,"Blocksize = %d %d\n", blocksize, file_size);
+#endif
+ if(blocksize != SECTOR_SIZE) OK_flag = 0;
+ }
+ }
+ fclose(zipfile);
+
+ checkname = strdup(whole_name);
+ checkname[strlen(whole_name)-3] = 0;
+ zipfile = fopen(checkname, "r");
+ if(zipfile) {
+ OK_flag = 0;
+ fprintf(stderr,"Unable to insert transparent compressed file - name conflict\n");
+ fclose(zipfile);
+ }
+
+ free(checkname);
+
+ if(OK_flag){
+ if(MAYBE_ADD_CE_ENTRY(ZZ_SIZE)) add_CE_entry();
+ Rock[ipnt++] ='Z';
+ Rock[ipnt++] ='Z';
+ Rock[ipnt++] = ZZ_SIZE;
+ Rock[ipnt++] = SU_VERSION;
+ Rock[ipnt++] = 'g'; /* Identify compression technique used */
+ Rock[ipnt++] = 'z';
+ Rock[ipnt++] = 3;
+ set_733((char*)Rock + ipnt, file_size); /* Real file size */
+ ipnt += 8;
+ };
+ }
+#endif
+ /*
+ * Add in the Rock Ridge CE field, if required. We use this for the
+ * extension record that is stored in the root directory.
+ */
+ if(deep_opt & NEED_CE) add_CE_entry();
+ /*
+ * Done filling in all of the fields. Now copy it back to a buffer for the
+ * file in question.
+ */
+
+ /* Now copy this back to the buffer for the file */
+ Rock[flagpos] = flagval;
+
+ /* If there was a CE, fill in the size field */
+ if(recstart)
+ set_733((char*)Rock + recstart - 8, ipnt - recstart);
+
+ s_entry->rr_attributes = (unsigned char *) e_malloc(ipnt);
+ s_entry->total_rr_attr_size = ipnt;
+ s_entry->rr_attr_size = (mainrec ? mainrec : ipnt);
+ memcpy(s_entry->rr_attributes, Rock, ipnt);
+ return ipnt;
+}
+
+/* Guaranteed to return a single sector with the relevant info */
+
+char * FDECL4(generate_rr_extension_record, char *, id, char *, descriptor,
+ char *, source, int *, size){
+ int ipnt = 0;
+ char * pnt;
+ int len_id, len_des, len_src;
+
+ len_id = strlen(id);
+ len_des = strlen(descriptor);
+ len_src = strlen(source);
+ Rock[ipnt++] ='E';
+ Rock[ipnt++] ='R';
+ Rock[ipnt++] = ER_SIZE + len_id + len_des + len_src;
+ Rock[ipnt++] = 1;
+ Rock[ipnt++] = len_id;
+ Rock[ipnt++] = len_des;
+ Rock[ipnt++] = len_src;
+ Rock[ipnt++] = 1;
+
+ memcpy(Rock + ipnt, id, len_id);
+ ipnt += len_id;
+
+ memcpy(Rock + ipnt, descriptor, len_des);
+ ipnt += len_des;
+
+ memcpy(Rock + ipnt, source, len_src);
+ ipnt += len_src;
+
+ if(ipnt > SECTOR_SIZE) {
+ fprintf(stderr,"Extension record too long\n");
+ exit(1);
+ };
+ pnt = (char *) e_malloc(SECTOR_SIZE);
+ memset(pnt, 0, SECTOR_SIZE);
+ memcpy(pnt, Rock, ipnt);
+ *size = ipnt;
+ return pnt;
+}
diff --git a/gnu/usr.bin/mkisofs/tree.c b/gnu/usr.bin/mkisofs/tree.c
new file mode 100644
index 0000000..5060c41
--- /dev/null
+++ b/gnu/usr.bin/mkisofs/tree.c
@@ -0,0 +1,1011 @@
+/*
+ * File tree.c - scan directory tree and build memory structures for iso9660
+ * filesystem
+
+ Written by Eric Youngdale (1993).
+
+ Copyright 1993 Yggdrasil Computing, Incorporated
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* ADD_FILES changes made by Ross Biro biro@yggdrasil.com 2/23/95 */
+
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <errno.h>
+
+#ifndef VMS
+#if defined(HASSYSMACROS) && !defined(HASMKDEV)
+#include <sys/sysmacros.h>
+#endif
+#include <unistd.h>
+#ifdef HASMKDEV
+#include <sys/types.h>
+#include <sys/mkdev.h>
+#endif
+#else
+#include <sys/file.h>
+#include <vms/fabdef.h>
+#include "vms.h"
+extern char * strdup(const char *);
+#endif
+
+#include "mkisofs.h"
+#include "iso9660.h"
+
+#include <sys/stat.h>
+
+#include "exclude.h"
+
+#ifdef NON_UNIXFS
+#define S_ISLNK(m) (0)
+#define S_ISSOCK(m) (0)
+#define S_ISFIFO(m) (0)
+#else
+#ifndef S_ISLNK
+#define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK)
+#endif
+#ifndef S_ISSOCK
+#define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK)
+#endif
+#endif
+
+#ifdef __svr4__
+extern char * strdup(const char *);
+#endif
+
+/* WALNUT CREEK CDROM HACK -- rab 950126 */
+static char trans_tbl[] = "00_TRANS.TBL";
+
+static unsigned char symlink_buff[256];
+
+extern int verbose;
+
+struct stat fstatbuf = {0,}; /* We use this for the artificial entries we create */
+
+struct stat root_statbuf = {0, }; /* Stat buffer for root directory */
+
+struct directory * reloc_dir = NULL;
+
+
+void FDECL1(sort_n_finish, struct directory *, this_dir)
+{
+ struct directory_entry *s_entry, *s_entry1;
+ time_t current_time;
+ struct directory_entry * table;
+ int count;
+ int new_reclen;
+ char * c;
+ int tablesize = 0;
+ char newname[34], rootname[34];
+
+ /* Here we can take the opportunity to toss duplicate entries from the
+ directory. */
+
+ table = NULL;
+
+ if(fstatbuf.st_ctime == 0){
+ time (&current_time);
+ fstatbuf.st_uid = 0;
+ fstatbuf.st_gid = 0;
+ fstatbuf.st_ctime = current_time;
+ fstatbuf.st_mtime = current_time;
+ fstatbuf.st_atime = current_time;
+ };
+
+ flush_file_hash();
+ s_entry = this_dir->contents;
+ while(s_entry){
+
+ /* First assume no conflict, and handle this case */
+
+ if(!(s_entry1 = find_file_hash(s_entry->isorec.name))){
+ add_file_hash(s_entry);
+ s_entry = s_entry->next;
+ continue;
+ };
+
+ if(s_entry1 == s_entry){
+ fprintf(stderr,"Fatal goof\n");
+ exit(1);
+ };
+ /* OK, handle the conflicts. Try substitute names until we come
+ up with a winner */
+ strcpy(rootname, s_entry->isorec.name);
+ if(full_iso9660_filenames) {
+ if(strlen(rootname) > 27) rootname[27] = 0;
+ }
+ c = strchr(rootname, '.');
+ if (c) *c = 0;
+ count = 0;
+ while(count < 1000){
+ sprintf(newname,"%s.%3.3d%s", rootname, count,
+ (s_entry->isorec.flags[0] == 2 ||
+ omit_version_number ? "" : ";1"));
+
+#ifdef VMS
+ /* Sigh. VAXCRTL seems to be broken here */
+ { int ijk = 0;
+ while(newname[ijk]) {
+ if(newname[ijk] == ' ') newname[ijk] = '0';
+ ijk++;
+ };
+ }
+#endif
+
+ if(!find_file_hash(newname)) break;
+ count++;
+ };
+ if(count >= 1000){
+ fprintf(stderr,"Unable to generate unique name for file %s\n", s_entry->name);
+ exit(1);
+ };
+
+ /* OK, now we have a good replacement name. Now decide which one
+ of these two beasts should get the name changed */
+
+ if(s_entry->priority < s_entry1->priority) {
+ fprintf(stderr,"Using %s for %s%s%s (%s)\n", newname, this_dir->whole_name, SPATH_SEPARATOR, s_entry->name, s_entry1->name);
+ s_entry->isorec.name_len[0] = strlen(newname);
+ new_reclen = sizeof(struct iso_directory_record) -
+ sizeof(s_entry->isorec.name) +
+ strlen(newname);
+ if(use_RockRidge) {
+ if (new_reclen & 1) new_reclen++; /* Pad to an even byte */
+ new_reclen += s_entry->rr_attr_size;
+ };
+ if (new_reclen & 1) new_reclen++; /* Pad to an even byte */
+ s_entry->isorec.length[0] = new_reclen;
+ strcpy(s_entry->isorec.name, newname);
+ } else {
+ delete_file_hash(s_entry1);
+ fprintf(stderr,"Using %s for %s%s%s (%s)\n", newname, this_dir->whole_name, SPATH_SEPARATOR, s_entry1->name, s_entry->name);
+ s_entry1->isorec.name_len[0] = strlen(newname);
+ new_reclen = sizeof(struct iso_directory_record) -
+ sizeof(s_entry1->isorec.name) +
+ strlen(newname);
+ if(use_RockRidge) {
+ if (new_reclen & 1) new_reclen++; /* Pad to an even byte */
+ new_reclen += s_entry1->rr_attr_size;
+ };
+ if (new_reclen & 1) new_reclen++; /* Pad to an even byte */
+ s_entry1->isorec.length[0] = new_reclen;
+ strcpy(s_entry1->isorec.name, newname);
+ add_file_hash(s_entry1);
+ };
+ add_file_hash(s_entry);
+ s_entry = s_entry->next;
+ };
+
+ if(generate_tables && !find_file_hash(trans_tbl) && (reloc_dir != this_dir)){
+ /* First we need to figure out how big this table is */
+ for (s_entry = this_dir->contents; s_entry; s_entry = s_entry->next){
+ if(strcmp(s_entry->name, ".") == 0 ||
+ strcmp(s_entry->name, "..") == 0) continue;
+ if(s_entry->table) tablesize += 35 + strlen(s_entry->table);
+ };
+ table = (struct directory_entry *)
+ e_malloc(sizeof (struct directory_entry));
+ memset(table, 0, sizeof(struct directory_entry));
+ table->table = NULL;
+ table->next = this_dir->contents;
+ this_dir->contents = table;
+
+ table->filedir = root;
+ table->isorec.flags[0] = 0;
+ table->priority = 32768;
+ iso9660_date(table->isorec.date, fstatbuf.st_ctime);
+ table->inode = TABLE_INODE;
+ table->dev = (dev_t) UNCACHED_DEVICE;
+ set_723(table->isorec.volume_sequence_number, 1);
+ set_733(table->isorec.size, tablesize);
+ table->size = tablesize;
+ table->filedir = this_dir;
+ table->name = strdup("<translation table>");
+ table->table = (char *) e_malloc(ROUND_UP(tablesize));
+ memset(table->table, 0, ROUND_UP(tablesize));
+#if 1 /* WALNUT CREEK -- 950126 */
+ iso9660_file_length (trans_tbl, table, 0);
+#else
+ iso9660_file_length (trans_tbl, table, 1);
+#endif
+
+ if(use_RockRidge){
+ fstatbuf.st_mode = 0444 | S_IFREG;
+ fstatbuf.st_nlink = 1;
+ generate_rock_ridge_attributes("",
+ trans_tbl, table,
+ &fstatbuf, &fstatbuf, 0);
+ };
+ };
+
+ for(s_entry = this_dir->contents; s_entry; s_entry = s_entry->next){
+ new_reclen = strlen(s_entry->isorec.name);
+
+ if(s_entry->isorec.flags[0] == 2){
+ if (strcmp(s_entry->name,".") && strcmp(s_entry->name,"..")) {
+ path_table_size += new_reclen + sizeof(struct iso_path_table) - 1;
+ if (new_reclen & 1) path_table_size++;
+ } else {
+ new_reclen = 1;
+ if (this_dir == root && strlen(s_entry->name) == 1)
+ path_table_size += sizeof(struct iso_path_table);
+ }
+ };
+ if(path_table_size & 1) path_table_size++; /* For odd lengths we pad */
+ s_entry->isorec.name_len[0] = new_reclen;
+
+ new_reclen +=
+ sizeof(struct iso_directory_record) -
+ sizeof(s_entry->isorec.name);
+
+ if (new_reclen & 1)
+ new_reclen++;
+ if(use_RockRidge){
+ new_reclen += s_entry->rr_attr_size;
+
+ if (new_reclen & 1)
+ new_reclen++;
+ };
+ if(new_reclen > 0xff) {
+ fprintf(stderr,"Fatal error - RR overflow for file %s\n",
+ s_entry->name);
+ exit(1);
+ };
+ s_entry->isorec.length[0] = new_reclen;
+ };
+
+ sort_directory(&this_dir->contents);
+
+ if(table){
+ char buffer[1024];
+ count = 0;
+ for (s_entry = this_dir->contents; s_entry; s_entry = s_entry->next){
+ if(s_entry == table) continue;
+ if(!s_entry->table) continue;
+ if(strcmp(s_entry->name, ".") == 0 ||
+ strcmp(s_entry->name, "..") == 0) continue;
+
+ sprintf(buffer,"%c %-34s%s",s_entry->table[0],
+ s_entry->isorec.name, s_entry->table+1);
+ memcpy(table->table + count, buffer, strlen(buffer));
+ count += strlen(buffer);
+ free(s_entry->table);
+ s_entry->table = NULL;
+ };
+ if(count != tablesize) {
+ fprintf(stderr,"Translation table size mismatch %d %d\n",
+ count, tablesize);
+ exit(1);
+ };
+ };
+
+ /* Now go through the directory and figure out how large this one will be.
+ Do not split a directory entry across a sector boundary */
+
+ s_entry = this_dir->contents;
+ this_dir->ce_bytes = 0;
+ while(s_entry){
+ new_reclen = s_entry->isorec.length[0];
+ if ((this_dir->size & (SECTOR_SIZE - 1)) + new_reclen >= SECTOR_SIZE)
+ this_dir->size = (this_dir->size + (SECTOR_SIZE - 1)) &
+ ~(SECTOR_SIZE - 1);
+ this_dir->size += new_reclen;
+
+ /* See if continuation entries were used on disc */
+ if(use_RockRidge &&
+ s_entry->rr_attr_size != s_entry->total_rr_attr_size) {
+ unsigned char * pnt;
+ int len;
+ int nbytes;
+
+ pnt = s_entry->rr_attributes;
+ len = s_entry->total_rr_attr_size;
+
+ /* We make sure that each continuation entry record is not
+ split across sectors, but each file could in theory have more
+ than one CE, so we scan through and figure out what we need. */
+
+ while(len > 3){
+ if(pnt[0] == 'C' && pnt[1] == 'E') {
+ nbytes = get_733(pnt+20);
+
+ if((this_dir->ce_bytes & (SECTOR_SIZE - 1)) + nbytes >=
+ SECTOR_SIZE) this_dir->ce_bytes =
+ ROUND_UP(this_dir->ce_bytes);
+ /* Now store the block in the ce buffer */
+ this_dir->ce_bytes += nbytes;
+ if(this_dir->ce_bytes & 1) this_dir->ce_bytes++;
+ };
+ len -= pnt[2];
+ pnt += pnt[2];
+ }
+ }
+ s_entry = s_entry->next;
+ }
+}
+
+static void generate_reloc_directory()
+{
+ int new_reclen;
+ time_t current_time;
+ struct directory_entry *s_entry;
+
+ /* Create an entry for our internal tree */
+ time (&current_time);
+ reloc_dir = (struct directory *)
+ e_malloc(sizeof(struct directory));
+ memset(reloc_dir, 0, sizeof(struct directory));
+ reloc_dir->parent = root;
+ reloc_dir->next = root->subdir;
+ root->subdir = reloc_dir;
+ reloc_dir->depth = 1;
+ reloc_dir->whole_name = strdup("./rr_moved");
+ reloc_dir->de_name = strdup("rr_moved");
+ reloc_dir->extent = 0;
+
+ new_reclen = strlen(reloc_dir->de_name);
+
+ /* Now create an actual directory entry */
+ s_entry = (struct directory_entry *)
+ e_malloc(sizeof (struct directory_entry));
+ memset(s_entry, 0, sizeof(struct directory_entry));
+ s_entry->next = root->contents;
+ reloc_dir->self = s_entry;
+
+ root->contents = s_entry;
+ root->contents->name = strdup(reloc_dir->de_name);
+ root->contents->filedir = root;
+ root->contents->isorec.flags[0] = 2;
+ root->contents->priority = 32768;
+ iso9660_date(root->contents->isorec.date, current_time);
+ root->contents->inode = UNCACHED_INODE;
+ root->contents->dev = (dev_t) UNCACHED_DEVICE;
+ set_723(root->contents->isorec.volume_sequence_number, 1);
+ iso9660_file_length (reloc_dir->de_name, root->contents, 1);
+
+ if(use_RockRidge){
+ fstatbuf.st_mode = 0555 | S_IFDIR;
+ fstatbuf.st_nlink = 2;
+ generate_rock_ridge_attributes("",
+ "rr_moved", s_entry,
+ &fstatbuf, &fstatbuf, 0);
+ };
+
+ /* Now create the . and .. entries in rr_moved */
+ /* Now create an actual directory entry */
+ s_entry = (struct directory_entry *)
+ e_malloc(sizeof (struct directory_entry));
+ memcpy(s_entry, root->contents,
+ sizeof(struct directory_entry));
+ s_entry->name = strdup(".");
+ iso9660_file_length (".", s_entry, 1);
+
+ s_entry->filedir = reloc_dir;
+ reloc_dir->contents = s_entry;
+
+ if(use_RockRidge){
+ fstatbuf.st_mode = 0555 | S_IFDIR;
+ fstatbuf.st_nlink = 2;
+ generate_rock_ridge_attributes("",
+ ".", s_entry,
+ &fstatbuf, &fstatbuf, 0);
+ };
+
+ s_entry = (struct directory_entry *)
+ e_malloc(sizeof (struct directory_entry));
+ memcpy(s_entry, root->contents,
+ sizeof(struct directory_entry));
+ s_entry->name = strdup("..");
+ iso9660_file_length ("..", s_entry, 1);
+ s_entry->filedir = root;
+ reloc_dir->contents->next = s_entry;
+ reloc_dir->contents->next->next = NULL;
+ if(use_RockRidge){
+ fstatbuf.st_mode = 0555 | S_IFDIR;
+ fstatbuf.st_nlink = 2;
+ generate_rock_ridge_attributes("",
+ "..", s_entry,
+ &root_statbuf, &root_statbuf, 0);
+ };
+}
+
+static void FDECL1(increment_nlink, struct directory_entry *, s_entry){
+ unsigned char * pnt;
+ int len, nlink;
+
+ pnt = s_entry->rr_attributes;
+ len = s_entry->total_rr_attr_size;
+ while(len){
+ if(pnt[0] == 'P' && pnt[1] == 'X') {
+ nlink = get_733(pnt+12);
+ set_733(pnt+12, nlink+1);
+ break;
+ };
+ len -= pnt[2];
+ pnt += pnt[2];
+ };
+}
+
+void finish_cl_pl_entries(){
+ struct directory_entry *s_entry, *s_entry1;
+ struct directory * d_entry;
+
+ s_entry = reloc_dir->contents;
+ s_entry = s_entry->next->next; /* Skip past . and .. */
+ for(; s_entry; s_entry = s_entry->next){
+ d_entry = reloc_dir->subdir;
+ while(d_entry){
+ if(d_entry->self == s_entry) break;
+ d_entry = d_entry->next;
+ };
+ if(!d_entry){
+ fprintf(stderr,"Unable to locate directory parent\n");
+ exit(1);
+ };
+
+ /* First fix the PL pointer in the directory in the rr_reloc dir */
+ s_entry1 = d_entry->contents->next;
+ set_733(s_entry1->rr_attributes + s_entry1->total_rr_attr_size - 8,
+ s_entry->filedir->extent);
+
+ /* Now fix the CL pointer */
+ s_entry1 = s_entry->parent_rec;
+
+ set_733(s_entry1->rr_attributes + s_entry1->total_rr_attr_size - 8,
+ d_entry->extent);
+
+ s_entry->filedir = reloc_dir; /* Now we can fix this */
+ }
+ /* Next we need to modify the NLINK terms in the assorted root directory records
+ to account for the presence of the RR_MOVED directory */
+
+ increment_nlink(root->self);
+ increment_nlink(root->self->next);
+ d_entry = root->subdir;
+ while(d_entry){
+ increment_nlink(d_entry->contents->next);
+ d_entry = d_entry->next;
+ };
+}
+
+#ifdef ADD_FILES
+/* This function looks up additions. */
+char *
+FDECL3(look_up_addition,char **, newpath, char *,path, struct dirent **,de) {
+ char *dup_path;
+ char *cp;
+ struct file_adds *f;
+ struct file_adds *tmp;
+
+ f=root_file_adds;
+ if (!f) return NULL;
+
+ /* I don't trust strtok */
+ dup_path = strdup (path);
+
+ cp = strtok (dup_path, SPATH_SEPARATOR);
+ while (cp != NULL) {
+ for (tmp = f->child; tmp != NULL; tmp=tmp->next) {
+ if (strcmp (tmp->name, cp) == 0) break;
+ }
+ if (tmp == NULL) {
+ /* no match */
+ free (dup_path);
+ return (NULL);
+ }
+ f = tmp;
+ cp = strtok(NULL, SPATH_SEPARATOR);
+ }
+ free (dup_path);
+
+ /* looks like we found something. */
+ if (tmp->used >= tmp->add_count) return (NULL);
+
+ *newpath = tmp->adds[tmp->used].path;
+ tmp->used++;
+ *de = &(tmp->de);
+ return (tmp->adds[tmp->used-1].name);
+
+}
+
+/* This function lets us add files from outside the standard file tree.
+ It is useful if we want to duplicate a cd, but add/replace things.
+ We should note that the real path will be used for exclusions. */
+
+struct dirent *
+FDECL3(readdir_add_files, char **, pathp, char *,path, DIR *, dir){
+ struct dirent *de;
+
+ char *addpath;
+ char *name;
+
+ de = readdir (dir);
+ if (de) {
+ return (de);
+ }
+
+ name=look_up_addition (&addpath, path, &de);
+
+ if (!name) {
+ return;
+ }
+
+ *pathp=addpath;
+
+ /* Now we must create the directory entry. */
+ /* fortuneately only the name seems to matter. */
+ /*
+ de->d_ino = -1;
+ de->d_off = 0;
+ de->d_reclen = strlen (name);
+ */
+ strncpy (de->d_name, name, NAME_MAX);
+ de->d_name[NAME_MAX]=0;
+ return (de);
+
+}
+#else
+struct dirent *
+FDECL3(readdir_add_files, char **, pathp, char *,path, DIR *, dir){
+ return (readdir (dir));
+}
+#endif
+/*
+ * This function scans the directory tree, looking for files, and it makes
+ * note of everything that is found. We also begin to construct the ISO9660
+ * directory entries, so that we can determine how large each directory is.
+ */
+
+int
+FDECL2(scan_directory_tree,char *, path, struct directory_entry *, de){
+ DIR * current_dir;
+ char whole_path[1024];
+ struct dirent * d_entry;
+ struct directory_entry *s_entry, *s_entry1;
+ struct directory * this_dir, *next_brother, *parent;
+ struct stat statbuf, lstatbuf;
+ int status, dflag;
+ char * cpnt;
+ int new_reclen;
+ int deep_flag;
+ char *old_path;
+
+ current_dir = opendir(path);
+ d_entry = NULL;
+
+ /* Apparently NFS sometimes allows you to open the directory, but
+ then refuses to allow you to read the contents. Allow for this */
+
+ old_path = path;
+
+ if(current_dir) d_entry = readdir_add_files(&path, old_path, current_dir);
+
+ if(!current_dir || !d_entry) {
+ fprintf(stderr,"Unable to open directory %s\n", path);
+ de->isorec.flags[0] &= ~2; /* Mark as not a directory */
+ if(current_dir) closedir(current_dir);
+ return 0;
+ };
+
+ parent = de->filedir;
+ /* Set up the struct for the current directory, and insert it into the
+ tree */
+
+#ifdef VMS
+ vms_path_fixup(path);
+#endif
+
+ this_dir = (struct directory *) e_malloc(sizeof(struct directory));
+ this_dir->next = NULL;
+ new_reclen = 0;
+ this_dir->subdir = NULL;
+ this_dir->self = de;
+ this_dir->contents = NULL;
+ this_dir->whole_name = strdup(path);
+ cpnt = strrchr(path, PATH_SEPARATOR);
+ if(cpnt)
+ cpnt++;
+ else
+ cpnt = path;
+ this_dir->de_name = strdup(cpnt);
+ this_dir->size = 0;
+ this_dir->extent = 0;
+
+ if(!parent || parent == root){
+ if (!root) {
+ root = this_dir; /* First time through for root directory only */
+ root->depth = 0;
+ root->parent = root;
+ } else {
+ this_dir->depth = 1;
+ if(!root->subdir)
+ root->subdir = this_dir;
+ else {
+ next_brother = root->subdir;
+ while(next_brother->next) next_brother = next_brother->next;
+ next_brother->next = this_dir;
+ };
+ this_dir->parent = parent;
+ };
+ } else {
+ /* Come through here for normal traversal of tree */
+#ifdef DEBUG
+ fprintf(stderr,"%s(%d) ", path, this_dir->depth);
+#endif
+ if(parent->depth > RR_relocation_depth) {
+ fprintf(stderr,"Directories too deep %s\n", path);
+ exit(1);
+ };
+
+ this_dir->parent = parent;
+ this_dir->depth = parent->depth + 1;
+
+ if(!parent->subdir)
+ parent->subdir = this_dir;
+ else {
+ next_brother = parent->subdir;
+ while(next_brother->next) next_brother = next_brother->next;
+ next_brother->next = this_dir;
+ };
+ };
+
+/* Now we scan the directory itself, and look at what is inside of it. */
+
+ dflag = 0;
+ while(1==1){
+
+ /* The first time through, skip this, since we already asked for
+ the first entry when we opened the directory. */
+ if(dflag) d_entry = readdir_add_files(&path, old_path, current_dir);
+ dflag++;
+
+ if(!d_entry) break;
+
+ /* OK, got a valid entry */
+
+ /* If we do not want all files, then pitch the backups. */
+ if(!all_files){
+ if(strchr(d_entry->d_name,'~')) continue;
+ if(strchr(d_entry->d_name,'#')) continue;
+ };
+
+ if(strlen(path)+strlen(d_entry->d_name) + 2 > sizeof(whole_path)){
+ fprintf(stderr, "Overflow of stat buffer\n");
+ exit(1);
+ };
+
+ /* Generate the complete ASCII path for this file */
+ strcpy(whole_path, path);
+#ifndef VMS
+ if(whole_path[strlen(whole_path)-1] != '/')
+ strcat(whole_path, "/");
+#endif
+ strcat(whole_path, d_entry->d_name);
+
+ /* Should we exclude this file? */
+ if (is_excluded(whole_path)) {
+ if (verbose) {
+ fprintf(stderr, "Excluded: %s\n",whole_path);
+ }
+ continue;
+ }
+#if 0
+ if (verbose) fprintf(stderr, "%s\n",whole_path);
+#endif
+ status = stat(whole_path, &statbuf);
+
+ lstat(whole_path, &lstatbuf);
+
+ if(this_dir == root && strcmp(d_entry->d_name, ".") == 0)
+ root_statbuf = statbuf; /* Save this for later on */
+
+ /* We do this to make sure that the root entries are consistent */
+ if(this_dir == root && strcmp(d_entry->d_name, "..") == 0) {
+ statbuf = root_statbuf;
+ lstatbuf = root_statbuf;
+ };
+
+ if(S_ISLNK(lstatbuf.st_mode)){
+
+ /* Here we decide how to handle the symbolic links. Here
+ we handle the general case - if we are not following
+ links or there is an error, then we must change
+ something. If RR is in use, it is easy, we let RR
+ describe the file. If not, then we punt the file. */
+
+ if((status || !follow_links)){
+ if(use_RockRidge){
+ status = 0;
+ statbuf.st_size = 0;
+ STAT_INODE(statbuf) = UNCACHED_INODE;
+ statbuf.st_dev = (dev_t) UNCACHED_DEVICE;
+ statbuf.st_mode = (statbuf.st_mode & ~S_IFMT) | S_IFREG;
+ } else {
+ if(follow_links) fprintf(stderr,
+ "Unable to stat file %s - ignoring and continuing.\n",
+ whole_path);
+ else fprintf(stderr,
+ "Symlink %s ignored - continuing.\n",
+ whole_path);
+ continue; /* Non Rock Ridge discs - ignore all symlinks */
+ };
+ }
+
+ if( follow_links
+ && S_ISDIR(statbuf.st_mode) )
+ {
+ if( strcmp(d_entry->d_name, ".")
+ && strcmp(d_entry->d_name, "..") )
+ {
+ if(find_directory_hash(statbuf.st_dev, STAT_INODE(statbuf)))
+ {
+ if(!use_RockRidge)
+ {
+ fprintf(stderr, "Already cached directory seen (%s)\n",
+ whole_path);
+ continue;
+ }
+ statbuf.st_size = 0;
+ STAT_INODE(statbuf) = UNCACHED_INODE;
+ statbuf.st_dev = (dev_t) UNCACHED_DEVICE;
+ statbuf.st_mode = (statbuf.st_mode & ~S_IFMT) | S_IFREG;
+ } else {
+ lstatbuf = statbuf;
+ add_directory_hash(statbuf.st_dev, STAT_INODE(statbuf));
+ }
+ }
+ }
+ }
+
+ /*
+ * Add directories to the cache so that we don't waste space even
+ * if we are supposed to be following symlinks.
+ */
+ if( follow_links
+ && strcmp(d_entry->d_name, ".")
+ && strcmp(d_entry->d_name, "..")
+ && S_ISDIR(statbuf.st_mode) )
+ {
+ add_directory_hash(statbuf.st_dev, STAT_INODE(statbuf));
+ }
+#ifdef VMS
+ if(!S_ISDIR(lstatbuf.st_mode) && (statbuf.st_fab_rfm != FAB$C_FIX &&
+ statbuf.st_fab_rfm != FAB$C_STMLF)) {
+ fprintf(stderr,"Warning - file %s has an unsupported VMS record"
+ " format (%d)\n",
+ whole_path, statbuf.st_fab_rfm);
+ }
+#endif
+
+ if(S_ISREG(lstatbuf.st_mode) && (status = access(whole_path, R_OK))){
+ fprintf(stderr, "File %s is not readable (errno = %d) - ignoring\n",
+ whole_path, errno);
+ continue;
+ }
+
+ /* Add this so that we can detect directory loops with hard links.
+ If we are set up to follow symlinks, then we skip this checking. */
+ if( !follow_links
+ && S_ISDIR(lstatbuf.st_mode)
+ && strcmp(d_entry->d_name, ".")
+ && strcmp(d_entry->d_name, "..") )
+ {
+ if(find_directory_hash(statbuf.st_dev, STAT_INODE(statbuf))) {
+ fprintf(stderr,"Directory loop - fatal goof (%s %lx %lu).\n",
+ whole_path, (unsigned long) statbuf.st_dev,
+ (unsigned long) STAT_INODE(statbuf));
+ exit(1);
+ };
+ add_directory_hash(statbuf.st_dev, STAT_INODE(statbuf));
+ };
+
+ if (!S_ISCHR(lstatbuf.st_mode) && !S_ISBLK(lstatbuf.st_mode) &&
+ !S_ISFIFO(lstatbuf.st_mode) && !S_ISSOCK(lstatbuf.st_mode)
+ && !S_ISLNK(lstatbuf.st_mode) && !S_ISREG(lstatbuf.st_mode) &&
+ !S_ISDIR(lstatbuf.st_mode)) {
+ fprintf(stderr,"Unknown file type %s - ignoring and continuing.\n",
+ whole_path);
+ continue;
+ };
+
+ /* Who knows what trash this is - ignore and continue */
+
+ if(status) {
+ fprintf(stderr,
+ "Unable to stat file %s - ignoring and continuing.\n",
+ whole_path);
+ continue;
+ };
+
+ s_entry = (struct directory_entry *)
+ e_malloc(sizeof (struct directory_entry));
+ s_entry->next = this_dir->contents;
+ this_dir->contents = s_entry;
+ deep_flag = 0;
+ s_entry->table = NULL;
+
+ s_entry->name = strdup(d_entry->d_name);
+ s_entry->whole_name = strdup (whole_path);
+
+ s_entry->filedir = this_dir;
+ s_entry->isorec.flags[0] = 0;
+ s_entry->isorec.ext_attr_length[0] = 0;
+ iso9660_date(s_entry->isorec.date, statbuf.st_ctime);
+ s_entry->isorec.file_unit_size[0] = 0;
+ s_entry->isorec.interleave[0] = 0;
+ if(parent && parent == reloc_dir && strcmp(d_entry->d_name, "..") == 0){
+ s_entry->inode = UNCACHED_INODE;
+ s_entry->dev = (dev_t) UNCACHED_DEVICE;
+ deep_flag = NEED_PL;
+ } else {
+ s_entry->inode = STAT_INODE(statbuf);
+ s_entry->dev = statbuf.st_dev;
+ };
+ set_723(s_entry->isorec.volume_sequence_number, 1);
+ iso9660_file_length(d_entry->d_name, s_entry, S_ISDIR(statbuf.st_mode));
+ s_entry->rr_attr_size = 0;
+ s_entry->total_rr_attr_size = 0;
+ s_entry->rr_attributes = NULL;
+
+ /* Directories are assigned sizes later on */
+ if (!S_ISDIR(statbuf.st_mode)) {
+ set_733(s_entry->isorec.size, statbuf.st_size);
+
+ if (S_ISCHR(lstatbuf.st_mode) || S_ISBLK(lstatbuf.st_mode) ||
+ S_ISFIFO(lstatbuf.st_mode) || S_ISSOCK(lstatbuf.st_mode)
+ || S_ISLNK(lstatbuf.st_mode))
+ s_entry->size = 0;
+ else
+ s_entry->size = statbuf.st_size;
+ } else
+ s_entry->isorec.flags[0] = 2;
+
+ if (strcmp(d_entry->d_name,".") && strcmp(d_entry->d_name,"..") &&
+ S_ISDIR(statbuf.st_mode) && this_dir->depth > RR_relocation_depth){
+ if(!reloc_dir) generate_reloc_directory();
+
+ s_entry1 = (struct directory_entry *)
+ e_malloc(sizeof (struct directory_entry));
+ memcpy(s_entry1, this_dir->contents,
+ sizeof(struct directory_entry));
+ s_entry1->table = NULL;
+ s_entry1->name = strdup(this_dir->contents->name);
+ s_entry1->next = reloc_dir->contents;
+ reloc_dir->contents = s_entry1;
+ s_entry1->priority = 32768;
+ s_entry1->parent_rec = this_dir->contents;
+
+ deep_flag = NEED_RE;
+
+ if(use_RockRidge) {
+ generate_rock_ridge_attributes(whole_path,
+ d_entry->d_name, s_entry1,
+ &statbuf, &lstatbuf, deep_flag);
+ };
+
+ deep_flag = 0;
+
+ /* We need to set this temporarily so that the parent to this is correctly
+ determined. */
+ s_entry1->filedir = reloc_dir;
+ scan_directory_tree(whole_path, s_entry1);
+ s_entry1->filedir = this_dir;
+
+ statbuf.st_size = 0;
+ statbuf.st_mode &= 0777;
+ set_733(s_entry->isorec.size, 0);
+ s_entry->size = 0;
+ s_entry->isorec.flags[0] = 0;
+ s_entry->inode = UNCACHED_INODE;
+ deep_flag = NEED_CL;
+ };
+
+ if(generate_tables && strcmp(s_entry->name, ".") && strcmp(s_entry->name, "..")) {
+ char buffer[2048];
+ switch(lstatbuf.st_mode & S_IFMT){
+ case S_IFDIR:
+ sprintf(buffer,"D\t%s\n",
+ s_entry->name);
+ break;
+#ifndef NON_UNIXFS
+ case S_IFBLK:
+ sprintf(buffer,"B\t%s\t%lu %lu\n",
+ s_entry->name,
+ (unsigned long) major(statbuf.st_rdev),
+ (unsigned long) minor(statbuf.st_rdev));
+ break;
+ case S_IFIFO:
+ sprintf(buffer,"P\t%s\n",
+ s_entry->name);
+ break;
+ case S_IFCHR:
+ sprintf(buffer,"C\t%s\t%lu %lu\n",
+ s_entry->name,
+ (unsigned long) major(statbuf.st_rdev),
+ (unsigned long) minor(statbuf.st_rdev));
+ break;
+ case S_IFLNK:
+ readlink(whole_path, symlink_buff, sizeof(symlink_buff));
+ sprintf(buffer,"L\t%s\t%s\n",
+ s_entry->name, symlink_buff);
+ break;
+ case S_IFSOCK:
+ sprintf(buffer,"S\t%s\n",
+ s_entry->name);
+ break;
+#endif /* NON_UNIXFS */
+ case S_IFREG:
+ default:
+ sprintf(buffer,"F\t%s\n",
+ s_entry->name);
+ break;
+ };
+ s_entry->table = strdup(buffer);
+ };
+
+ if(S_ISDIR(statbuf.st_mode)){
+ int dflag;
+ if (strcmp(d_entry->d_name,".") && strcmp(d_entry->d_name,"..")) {
+ dflag = scan_directory_tree(whole_path, s_entry);
+ /* If unable to scan directory, mark this as a non-directory */
+ if(!dflag)
+ lstatbuf.st_mode = (lstatbuf.st_mode & ~S_IFMT) | S_IFREG;
+ }
+ };
+
+ if(use_RockRidge && this_dir == root && strcmp(s_entry->name, ".") == 0)
+ deep_flag |= NEED_CE | NEED_SP; /* For extension record */
+
+ /* Now figure out how much room this file will take in the directory */
+
+ if(use_RockRidge) {
+ generate_rock_ridge_attributes(whole_path,
+ d_entry->d_name, s_entry,
+ &statbuf, &lstatbuf, deep_flag);
+
+ }
+ }
+ closedir(current_dir);
+ sort_n_finish(this_dir);
+ return 1;
+}
+
+
+void FDECL2(generate_iso9660_directories, struct directory *, node, FILE*, outfile){
+ struct directory * dpnt;
+
+ dpnt = node;
+
+ while (dpnt){
+ generate_one_directory(dpnt, outfile);
+ if(dpnt->subdir) generate_iso9660_directories(dpnt->subdir, outfile);
+ dpnt = dpnt->next;
+ };
+}
+
+void FDECL1(dump_tree, struct directory *, node){
+ struct directory * dpnt;
+
+ dpnt = node;
+
+ while (dpnt){
+ fprintf(stderr,"%4d %5d %s\n",dpnt->extent, dpnt->size, dpnt->de_name);
+ if(dpnt->subdir) dump_tree(dpnt->subdir);
+ dpnt = dpnt->next;
+ };
+}
+
diff --git a/gnu/usr.bin/mkisofs/vms.c b/gnu/usr.bin/mkisofs/vms.c
new file mode 100644
index 0000000..19dc516
--- /dev/null
+++ b/gnu/usr.bin/mkisofs/vms.c
@@ -0,0 +1,269 @@
+/*
+ * File vms.c - assorted bletcherous hacks for VMS.
+
+ Written by Eric Youngdale (1993).
+
+ */
+
+#ifdef VMS
+#include <rms.h>
+#include <descrip.h>
+#include <ssdef.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#define opendir fake_opendir
+#include "mkisofs.h"
+#undef opendir
+#include <stdio.h>
+
+static struct RAB *rab; /* used for external mailfiles */
+static int rms_status;
+
+static error_exit(char * text){
+ fprintf(stderr,"%s\n", text);
+ exit(33);
+}
+
+
+char * strrchr(const char *, char);
+
+char * strdup(char * source){
+ char * pnt;
+ pnt = (char *) e_malloc(strlen(source) + 1);
+ strcpy(pnt, source);
+ return pnt;
+}
+
+int VMS_stat(char * path, struct stat * spnt){
+ char * spath;
+ char sbuffer[255];
+ char * pnt, *ppnt;
+ char * pnt1;
+
+ ppnt = strrchr(path,']');
+ if(ppnt) ppnt++;
+ else ppnt = path;
+
+ spath = path;
+
+ if(strcmp(ppnt,".") == 0 || strcmp(ppnt,"..") == 0){
+ strcpy(sbuffer, path);
+
+ /* Find end of actual name */
+ pnt = strrchr(sbuffer,']');
+ if(!pnt) return 0;
+
+ pnt1 = pnt;
+ while(*pnt1 != '[' && *pnt1 != '.') pnt1--;
+
+ if(*pnt1 != '[' && strcmp(ppnt,"..") == 0) {
+ pnt1--;
+ while(*pnt1 != '[' && *pnt1 != '.') pnt1--;
+ };
+
+ if(*pnt1 == '.') {
+ *pnt1 = ']';
+ pnt = pnt1;
+ while(*pnt != '.' && *pnt != ']') pnt++;
+ *pnt++ = ']';
+ while(*pnt != '.' && *pnt != ']') pnt++;
+ *pnt = 0;
+ strcat(sbuffer,".DIR;1");
+ };
+
+ if(*pnt1 == '[') {
+ pnt1++;
+ *pnt1 = 0;
+ strcat(pnt1,"000000]");
+ pnt1 = strrchr(path,'[') + 1;
+ pnt = sbuffer + strlen(sbuffer);
+ while(*pnt1 && *pnt1 != '.' && *pnt1 != ']') *pnt++ = *pnt1++;
+ *pnt = 0;
+ strcat(sbuffer,".DIR;1");
+ };
+
+ spath = sbuffer;
+ };
+ return stat(spath, spnt);
+}
+
+static int dircontext[32] = {0,};
+static char * searchpath[32];
+static struct direct d_entry[32];
+
+int optind = 0;
+char * optarg;
+
+int getopt(int argc, char *argv[], char * flags){
+ char * pnt;
+ char c;
+ optind++;
+ if(*argv[optind] != '-') return EOF;
+ optarg = 0;
+
+ c = *(argv[optind]+1);
+ pnt = (char *) strchr(flags, c);
+ if(!pnt) return c; /* Not found */
+ if(pnt[1] == ':') {
+ optind++;
+ optarg = argv[optind];
+ };
+ return c;
+}
+
+void vms_path_fixup(char * name){
+ char * pnt1;
+ pnt1 = name + strlen(name) - 6;
+
+ /* First strip the .DIR;1 */
+ if(strcmp(pnt1, ".DIR;1") == 0) *pnt1 = 0;
+
+ pnt1 = (char*) strrchr(name, ']');
+ if(pnt1) {
+ if(pnt1[1] == 0) return;
+ *pnt1 = '.';
+ strcat(name,"]");
+ return;
+ };
+ pnt1 = (char*) strrchr(name, '>');
+ if(pnt1) {
+ if(pnt1[1] == 0) return;
+ *pnt1 = '.';
+ strcat(name,">");
+ return;
+ };
+}
+
+int opendir(char * path){
+ int i;
+ for(i=1; i<32; i++) {
+ if(dircontext[i] == 0){
+ dircontext[i] = -1;
+ searchpath[i] = (char *) e_malloc(strlen(path) + 6);
+ strcpy(searchpath[i], path);
+ vms_path_fixup(searchpath[i]);
+ strcat(searchpath[i],"*.*.*");
+ return i;
+ };
+ };
+ exit(0);
+}
+
+struct direct * readdir(int context){
+ int i;
+ char cresult[100];
+ char * pnt;
+ int status;
+ $DESCRIPTOR(dpath,searchpath[context]);
+ $DESCRIPTOR(result,cresult);
+
+ if(dircontext[context] == -1) {
+ dircontext[context] = -2;
+ strcpy(d_entry[context].d_name, ".");
+ return &d_entry[context];
+ };
+
+ if(dircontext[context] == -2) {
+ dircontext[context] = -3;
+ strcpy(d_entry[context].d_name, "..");
+ return &d_entry[context];
+ };
+
+ if(dircontext[context] == -3) dircontext[context] = 0;
+
+ dpath.dsc$w_length = strlen(searchpath[context]);
+ lib$find_file(&dpath, &result, &dircontext[context],
+ 0, 0, &status, 0);
+
+ if(status == SS$_NOMOREFILES) return 0;
+
+ /* Now trim trailing spaces from the name */
+ i = result.dsc$w_length - 1;
+ while(i && cresult[i] == ' ') i--;
+ cresult[i+1] = 0;
+
+ /* Now locate the actual portion of the file we want */
+
+ pnt = (char *) strrchr(cresult,']');
+ if(pnt) pnt++;
+ else
+ pnt = cresult;
+
+ strcpy(d_entry[context].d_name, pnt);
+ return &d_entry[context];
+}
+
+void closedir(int context){
+ lib$find_file_end(&dircontext[context]);
+ free(searchpath[context]);
+ searchpath[context] = (char *) 0;
+ dircontext[context] = 0;
+}
+
+static open_file(char* fn){
+/* this routine initializes a rab and fab required to get the
+ correct definition of the external data file used by mail */
+ struct FAB * fab;
+
+ rab = (struct RAB*) e_malloc(sizeof(struct RAB));
+ fab = (struct FAB*) e_malloc(sizeof(struct FAB));
+
+ *rab = cc$rms_rab; /* initialize RAB*/
+ rab->rab$l_fab = fab;
+
+ *fab = cc$rms_fab; /* initialize FAB*/
+ fab->fab$l_fna = fn;
+ fab->fab$b_fns = strlen(fn);
+ fab->fab$w_mrs = 512;
+ fab->fab$b_fac = FAB$M_BIO | FAB$M_GET;
+ fab->fab$b_org = FAB$C_SEQ;
+ fab->fab$b_rfm = FAB$C_FIX;
+ fab->fab$l_xab = (char*) 0;
+
+ rms_status = sys$open(rab->rab$l_fab);
+ if(rms_status != RMS$_NORMAL && rms_status != RMS$_CREATED)
+ error_exit("$OPEN");
+ rms_status = sys$connect(rab);
+ if(rms_status != RMS$_NORMAL)
+ error_exit("$CONNECT");
+ return 1;
+}
+
+static close_file(struct RAB * prab){
+ rms_status = sys$close(prab->rab$l_fab);
+ free(prab->rab$l_fab);
+ free(prab);
+ if(rms_status != RMS$_NORMAL)
+ error_exit("$CLOSE");
+}
+
+#define NSECT 16
+extern unsigned int last_extent_written;
+
+int vms_write_one_file(char * filename, int size, FILE * outfile){
+ int status, i;
+ char buffer[SECTOR_SIZE * NSECT];
+ int count;
+ int use;
+ int remain;
+
+ open_file(filename);
+
+ remain = size;
+
+ while(remain > 0){
+ use = (remain > SECTOR_SIZE * NSECT - 1 ? NSECT*SECTOR_SIZE : remain);
+ use = ROUND_UP(use); /* Round up to nearest sector boundary */
+ memset(buffer, 0, use);
+ rab->rab$l_ubf = buffer;
+ rab->rab$w_usz = sizeof(buffer);
+ status = sys$read(rab);
+ fwrite(buffer, 1, use, outfile);
+ last_extent_written += use/SECTOR_SIZE;
+ if((last_extent_written % 1000) < use/SECTOR_SIZE) fprintf(stderr,"%d..", last_extent_written);
+ remain -= use;
+ };
+
+ close_file(rab);
+}
+#endif
diff --git a/gnu/usr.bin/mkisofs/vms.h b/gnu/usr.bin/mkisofs/vms.h
new file mode 100644
index 0000000..b57a677
--- /dev/null
+++ b/gnu/usr.bin/mkisofs/vms.h
@@ -0,0 +1,19 @@
+/*
+ * Header file mkisofs.h - assorted structure definitions and typecasts.
+
+ Written by Eric Youngdale (1993).
+
+ */
+
+#ifdef VMS
+#define stat(X,Y) VMS_stat(X,Y)
+#define lstat VMS_stat
+
+/* gmtime not available under VMS - make it look like we are in Greenwich */
+#define gmtime localtime
+
+#define S_ISBLK(X) (0)
+#define S_ISCHR(X) (0)
+#define S_ISREG(X) (((X) & S_IFMT) == S_IFREG)
+#define S_ISDIR(X) (((X) & S_IFMT) == S_IFDIR)
+#endif
diff --git a/gnu/usr.bin/mkisofs/write.c b/gnu/usr.bin/mkisofs/write.c
new file mode 100644
index 0000000..64b4a3c
--- /dev/null
+++ b/gnu/usr.bin/mkisofs/write.c
@@ -0,0 +1,785 @@
+/*
+ * Program write.c - dump memory structures to file for iso9660 filesystem.
+
+ Written by Eric Youngdale (1993).
+
+ Copyright 1993 Yggdrasil Computing, Incorporated
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <string.h>
+#include <stdlib.h>
+#include "mkisofs.h"
+#include "iso9660.h"
+#include <time.h>
+#include <errno.h>
+
+#ifdef __svr4__
+extern char * strdup(const char *);
+#endif
+
+#ifdef VMS
+extern char * strdup(const char *);
+#endif
+
+
+/* Max number of sectors we will write at one time */
+#define NSECT 16
+
+/* Counters for statistics */
+
+static int table_size = 0;
+static int total_dir_size = 0;
+static int rockridge_size = 0;
+static struct directory ** pathlist;
+static next_path_index = 1;
+
+/* Used to fill in some of the information in the volume descriptor. */
+static struct tm *local;
+
+/* Routines to actually write the disc. We write sequentially so that
+ we could write a tape, or write the disc directly */
+
+
+#define FILL_SPACE(X) memset(vol_desc.X, ' ', sizeof(vol_desc.X))
+
+void FDECL2(set_721, char *, pnt, unsigned int, i){
+ pnt[0] = i & 0xff;
+ pnt[1] = (i >> 8) & 0xff;
+}
+
+void FDECL2(set_722, char *, pnt, unsigned int, i){
+ pnt[0] = (i >> 8) & 0xff;
+ pnt[1] = i & 0xff;
+}
+
+void FDECL2(set_723, char *, pnt, unsigned int, i){
+ pnt[3] = pnt[0] = i & 0xff;
+ pnt[2] = pnt[1] = (i >> 8) & 0xff;
+}
+
+void FDECL2(set_731, char *, pnt, unsigned int, i){
+ pnt[0] = i & 0xff;
+ pnt[1] = (i >> 8) & 0xff;
+ pnt[2] = (i >> 16) & 0xff;
+ pnt[3] = (i >> 24) & 0xff;
+}
+
+void FDECL2(set_732, char *, pnt, unsigned int, i){
+ pnt[3] = i & 0xff;
+ pnt[2] = (i >> 8) & 0xff;
+ pnt[1] = (i >> 16) & 0xff;
+ pnt[0] = (i >> 24) & 0xff;
+}
+
+int FDECL1(get_733, char *, p){
+ return ((p[0] & 0xff)
+ | ((p[1] & 0xff) << 8)
+ | ((p[2] & 0xff) << 16)
+ | ((p[3] & 0xff) << 24));
+}
+
+void FDECL2(set_733, char *, pnt, unsigned int, i){
+ pnt[7] = pnt[0] = i & 0xff;
+ pnt[6] = pnt[1] = (i >> 8) & 0xff;
+ pnt[5] = pnt[2] = (i >> 16) & 0xff;
+ pnt[4] = pnt[3] = (i >> 24) & 0xff;
+}
+
+static FDECL4(xfwrite, void *, buffer, int, count, int, size, FILE *, file)
+{
+ while(count) {
+ int got=fwrite(buffer,size,count,file);
+ if(got<=0) fprintf(stderr,"cannot fwrite %d*%d\n",size,count),exit(1);
+ count-=got,*(char**)&buffer+=size*got;
+ }
+}
+
+struct deferred_write{
+ struct deferred_write * next;
+ char * table;
+ unsigned int extent;
+ unsigned int size;
+ char * name;
+};
+
+static struct deferred_write * dw_head = NULL, * dw_tail = NULL;
+
+static struct directory_entry * sort_dir;
+
+unsigned int last_extent_written =0;
+static struct iso_primary_descriptor vol_desc;
+static path_table_index;
+
+/* We recursively walk through all of the directories and assign extent
+ numbers to them. We have already assigned extent numbers to everything that
+ goes in front of them */
+
+void FDECL1(assign_directory_addresses, struct directory *, node){
+ struct directory * dpnt;
+ int dir_size;
+
+ dpnt = node;
+
+ while (dpnt){
+ dpnt->extent = last_extent;
+ dpnt->path_index = next_path_index++;
+ dir_size = (dpnt->size + (SECTOR_SIZE - 1)) >> 11;
+
+ last_extent += dir_size;
+
+ /* Leave room for the CE entries for this directory. Keep them
+ close to the reference directory so that access will be quick. */
+ if(dpnt->ce_bytes)
+ last_extent += ROUND_UP(dpnt->ce_bytes) >> 11;
+
+ if(dpnt->subdir) assign_directory_addresses(dpnt->subdir);
+ dpnt = dpnt->next;
+ };
+}
+
+static void FDECL3(write_one_file, char *, filename, unsigned int, size, FILE *, outfile){
+ FILE * infile;
+ char buffer[SECTOR_SIZE * NSECT];
+ int use;
+ int remain;
+ if ((infile = fopen(filename, "rb")) == NULL) {
+#ifdef sun
+ fprintf(stderr, "cannot open %s: (%d)\n", filename, errno);
+#else
+ fprintf(stderr, "cannot open %s: %s\n", filename, strerror(errno));
+#endif
+ exit(1);
+ }
+ remain = size;
+
+ while(remain > 0){
+ use = (remain > SECTOR_SIZE * NSECT - 1 ? NSECT*SECTOR_SIZE : remain);
+ use = ROUND_UP(use); /* Round up to nearest sector boundary */
+ memset(buffer, 0, use);
+ if (fread(buffer, 1, use, infile) == 0) {
+ fprintf(stderr,"cannot read from %s\n",filename);
+ exit(1);
+ }
+ xfwrite(buffer, 1, use, outfile);
+ last_extent_written += use/SECTOR_SIZE;
+ if((last_extent_written % 1000) < use/SECTOR_SIZE) fprintf(stderr,"%d..", last_extent_written);
+ remain -= use;
+ };
+ fclose(infile);
+}
+
+static void FDECL1(write_files, FILE *, outfile){
+ struct deferred_write * dwpnt, *dwnext;
+ dwpnt = dw_head;
+ while(dwpnt){
+ if(dwpnt->table) {
+ xfwrite(dwpnt->table, 1, ROUND_UP(dwpnt->size), outfile);
+ last_extent_written += ROUND_UP(dwpnt->size) / SECTOR_SIZE;
+ table_size += dwpnt->size;
+/* fprintf(stderr,"Size %d ", dwpnt->size); */
+ free(dwpnt->table);
+ } else {
+
+#ifdef VMS
+ vms_write_one_file(dwpnt->name, dwpnt->size, outfile);
+#else
+ write_one_file(dwpnt->name, dwpnt->size, outfile);
+#endif
+ free(dwpnt->name);
+ };
+
+ dwnext = dwpnt;
+ dwpnt = dwpnt->next;
+ free(dwnext);
+ };
+}
+
+#if 0
+static void dump_filelist(){
+ struct deferred_write * dwpnt;
+ dwpnt = dw_head;
+ while(dwpnt){
+ fprintf(stderr, "File %s\n",dwpnt->name);
+ dwpnt = dwpnt->next;
+ };
+ fprintf(stderr,"\n");
+};
+#endif
+
+int FDECL2(compare_dirs, struct directory_entry **, r, struct directory_entry **, l) {
+ char * rpnt, *lpnt;
+
+ rpnt = (*r)->isorec.name;
+ lpnt = (*l)->isorec.name;
+
+ while(*rpnt && *lpnt) {
+ if(*rpnt == ';' && *lpnt != ';') return -1;
+ if(*rpnt != ';' && *lpnt == ';') return 1;
+ if(*rpnt == ';' && *lpnt == ';') return 0;
+ if(*rpnt < *lpnt) return -1;
+ if(*rpnt > *lpnt) return 1;
+ rpnt++; lpnt++;
+ }
+ if(*rpnt) return 1;
+ if(*lpnt) return -1;
+ return 0;
+}
+
+void FDECL1(sort_directory, struct directory_entry **, sort_dir){
+ int dcount = 0;
+ int i, len;
+ struct directory_entry * s_entry;
+ struct directory_entry ** sortlist;
+
+ s_entry = *sort_dir;
+ while(s_entry){
+ dcount++;
+ s_entry = s_entry->next;
+ };
+ /* OK, now we know how many there are. Build a vector for sorting. */
+
+ sortlist = (struct directory_entry **)
+ e_malloc(sizeof(struct directory_entry *) * dcount);
+
+ dcount = 0;
+ s_entry = *sort_dir;
+ while(s_entry){
+ sortlist[dcount] = s_entry;
+ len = s_entry->isorec.name_len[0];
+ s_entry->isorec.name[len] = 0;
+ dcount++;
+ s_entry = s_entry->next;
+ };
+
+ qsort(sortlist, dcount, sizeof(struct directory_entry *),
+ (void *)compare_dirs);
+
+ /* Now reassemble the linked list in the proper sorted order */
+ for(i=0; i<dcount-1; i++)
+ sortlist[i]->next = sortlist[i+1];
+
+ sortlist[dcount-1]->next = NULL;
+ *sort_dir = sortlist[0];
+
+ free(sortlist);
+
+}
+
+void generate_root_record(){
+ time_t ctime;
+
+ time (&ctime);
+ local = localtime(&ctime);
+
+ root_record.length[0] = 1 + sizeof(struct iso_directory_record);
+ root_record.ext_attr_length[0] = 0;
+ set_733(root_record.extent, root->extent);
+ set_733(root_record.size, ROUND_UP(root->size));
+ iso9660_date(root_record.date, ctime);
+ root_record.flags[0] = 2;
+ root_record.file_unit_size[0] = 0;
+ root_record.interleave[0] = 0;
+ set_723(root_record.volume_sequence_number, 1);
+ root_record.name_len[0] = 1;
+}
+
+static void FDECL1(assign_file_addresses, struct directory *, dpnt){
+ struct directory * finddir;
+ struct directory_entry * s_entry;
+ struct file_hash *s_hash;
+ struct deferred_write * dwpnt;
+ char whole_path[1024];
+
+ while (dpnt){
+ s_entry = dpnt->contents;
+ for(s_entry = dpnt->contents; s_entry; s_entry = s_entry->next){
+
+ /* This saves some space if there are symlinks present */
+ s_hash = find_hash(s_entry->dev, s_entry->inode);
+ if(s_hash){
+ if(verbose)
+ fprintf(stderr, "Cache hit for %s%s%s\n",s_entry->filedir->de_name,
+ SPATH_SEPARATOR, s_entry->name);
+ set_733(s_entry->isorec.extent, s_hash->starting_block);
+ set_733(s_entry->isorec.size, s_hash->size);
+ continue;
+ };
+ if (strcmp(s_entry->name,".") && strcmp(s_entry->name,"..") &&
+ s_entry->isorec.flags[0] == 2){
+ finddir = dpnt->subdir;
+ while(1==1){
+ if(finddir->self == s_entry) break;
+ finddir = finddir->next;
+ if(!finddir) {fprintf(stderr,"Fatal goof\n"); exit(1);};
+ };
+ set_733(s_entry->isorec.extent, finddir->extent);
+ s_entry->starting_block = finddir->extent;
+ s_entry->size = ROUND_UP(finddir->size);
+ total_dir_size += s_entry->size;
+ add_hash(s_entry);
+ set_733(s_entry->isorec.size, ROUND_UP(finddir->size));
+ } else {
+ if(strcmp(s_entry->name,".") ==0 || strcmp(s_entry->name,"..") == 0) {
+ if(strcmp(s_entry->name,".") == 0) {
+ set_733(s_entry->isorec.extent, dpnt->extent);
+
+ /* Set these so that the hash table has the correct information */
+ s_entry->starting_block = dpnt->extent;
+ s_entry->size = ROUND_UP(dpnt->size);
+
+ add_hash(s_entry);
+ s_entry->starting_block = dpnt->extent;
+ set_733(s_entry->isorec.size, ROUND_UP(dpnt->size));
+ } else {
+ if(dpnt == root) total_dir_size += root->size;
+ set_733(s_entry->isorec.extent, dpnt->parent->extent);
+
+ /* Set these so that the hash table has the correct information */
+ s_entry->starting_block = dpnt->parent->extent;
+ s_entry->size = ROUND_UP(dpnt->parent->size);
+
+ add_hash(s_entry);
+ s_entry->starting_block = dpnt->parent->extent;
+ set_733(s_entry->isorec.size, ROUND_UP(dpnt->parent->size));
+ };
+ } else {
+ /* Now we schedule the file to be written. This is all quite
+ straightforward, just make a list and assign extents as we go.
+ Once we get through writing all of the directories, we should
+ be ready write out these files */
+
+ if(s_entry->size) {
+ dwpnt = (struct deferred_write *)
+ e_malloc(sizeof(struct deferred_write));
+ if(dw_tail){
+ dw_tail->next = dwpnt;
+ dw_tail = dwpnt;
+ } else {
+ dw_head = dwpnt;
+ dw_tail = dwpnt;
+ };
+ if(s_entry->inode == TABLE_INODE) {
+ dwpnt->table = s_entry->table;
+ dwpnt->name = NULL;
+ } else {
+ dwpnt->table = NULL;
+ strcpy(whole_path, s_entry->whole_name);
+ dwpnt->name = strdup(whole_path);
+ };
+ dwpnt->next = NULL;
+ dwpnt->size = s_entry->size;
+ dwpnt->extent = last_extent;
+ set_733(s_entry->isorec.extent, last_extent);
+ s_entry->starting_block = last_extent;
+ add_hash(s_entry);
+ last_extent += ROUND_UP(s_entry->size) >> 11;
+ if(verbose)
+ fprintf(stderr,"%d %d %s\n", s_entry->starting_block,
+ last_extent-1, whole_path);
+#ifdef DBG_ISO
+ if((ROUND_UP(s_entry->size) >> 11) > 500){
+ fprintf(stderr,"Warning: large file %s\n", whole_path);
+ fprintf(stderr,"Starting block is %d\n", s_entry->starting_block);
+ fprintf(stderr,"Reported file size is %d extents\n", s_entry->size);
+
+ };
+#endif
+ if(last_extent > (700000000 >> 11)) { /* More than 700Mb? Punt */
+ fprintf(stderr,"Extent overflow processing file %s\n", whole_path);
+ fprintf(stderr,"Starting block is %d\n", s_entry->starting_block);
+ fprintf(stderr,"Reported file size is %d extents\n", s_entry->size);
+ exit(1);
+ };
+ } else {
+ /*
+ * This is for zero-length files. If we leave the extent 0,
+ * then we get screwed, because many readers simply drop files
+ * that have an extent of zero. Thus we leave the size 0,
+ * and just assign the extent number.
+ */
+ set_733(s_entry->isorec.extent, last_extent);
+ }
+ };
+ };
+ };
+ if(dpnt->subdir) assign_file_addresses(dpnt->subdir);
+ dpnt = dpnt->next;
+ };
+}
+
+void FDECL2(generate_one_directory, struct directory *, dpnt, FILE *, outfile){
+ unsigned int total_size, ce_size;
+ char * directory_buffer;
+ char * ce_buffer;
+ unsigned int ce_address;
+ struct directory_entry * s_entry, *s_entry_d;
+ int new_reclen;
+ unsigned int dir_index, ce_index;
+
+ total_size = (dpnt->size + (SECTOR_SIZE - 1)) & ~(SECTOR_SIZE - 1);
+ directory_buffer = (char *) e_malloc(total_size);
+ memset(directory_buffer, 0, total_size);
+ dir_index = 0;
+
+ ce_size = (dpnt->ce_bytes + (SECTOR_SIZE - 1)) & ~(SECTOR_SIZE - 1);
+ ce_buffer = NULL;
+
+ if(ce_size) {
+ ce_buffer = (char *) e_malloc(ce_size);
+ memset(ce_buffer, 0, ce_size);
+
+ ce_index = 0;
+
+ /* Absolute byte address of CE entries for this directory */
+ ce_address = last_extent_written + (total_size >> 11);
+ ce_address = ce_address << 11;
+ }
+
+ s_entry = dpnt->contents;
+ while(s_entry) {
+
+ /* We do not allow directory entries to cross sector boundaries. Simply
+ pad, and then start the next entry at the next sector */
+ new_reclen = s_entry->isorec.length[0];
+ if ((dir_index & (SECTOR_SIZE - 1)) + new_reclen >= SECTOR_SIZE)
+ dir_index = (dir_index + (SECTOR_SIZE - 1)) &
+ ~(SECTOR_SIZE - 1);
+
+ memcpy(directory_buffer + dir_index, &s_entry->isorec,
+ sizeof(struct iso_directory_record) -
+ sizeof(s_entry->isorec.name) + s_entry->isorec.name_len[0]);
+ dir_index += sizeof(struct iso_directory_record) -
+ sizeof (s_entry->isorec.name)+ s_entry->isorec.name_len[0];
+
+ /* Add the Rock Ridge attributes, if present */
+ if(s_entry->rr_attr_size){
+ if(dir_index & 1)
+ directory_buffer[dir_index++] = 0;
+
+ /* If the RR attributes were too long, then write the CE records,
+ as required. */
+ if(s_entry->rr_attr_size != s_entry->total_rr_attr_size) {
+ unsigned char * pnt;
+ int len, nbytes;
+
+ /* Go through the entire record and fix up the CE entries
+ so that the extent and offset are correct */
+
+ pnt = s_entry->rr_attributes;
+ len = s_entry->total_rr_attr_size;
+ while(len > 3){
+ if(pnt[0] == 'C' && pnt[1] == 'E') {
+ nbytes = get_733(pnt+20);
+
+ if((ce_index & (SECTOR_SIZE - 1)) + nbytes >=
+ SECTOR_SIZE) ce_index = ROUND_UP(ce_index);
+
+ set_733(pnt+4, (ce_address + ce_index) >> 11);
+ set_733(pnt+12, (ce_address + ce_index) & (SECTOR_SIZE - 1));
+
+
+ /* Now store the block in the ce buffer */
+ memcpy(ce_buffer + ce_index,
+ pnt + pnt[2], nbytes);
+ ce_index += nbytes;
+ if(ce_index & 1) ce_index++;
+ };
+ len -= pnt[2];
+ pnt += pnt[2];
+ };
+
+ }
+
+ rockridge_size += s_entry->total_rr_attr_size;
+ memcpy(directory_buffer + dir_index, s_entry->rr_attributes,
+ s_entry->rr_attr_size);
+ dir_index += s_entry->rr_attr_size;
+ };
+ if(dir_index & 1)
+ directory_buffer[dir_index++] = 0;
+
+ s_entry_d = s_entry;
+ s_entry = s_entry->next;
+
+ if (s_entry_d->rr_attributes) free(s_entry_d->rr_attributes);
+ free (s_entry_d->name);
+ free (s_entry_d);
+ };
+ sort_dir = NULL;
+
+ if(dpnt->size != dir_index)
+ fprintf(stderr,"Unexpected directory length %d %d %s\n",dpnt->size,
+ dir_index, dpnt->de_name);
+ xfwrite(directory_buffer, 1, total_size, outfile);
+ last_extent_written += total_size >> 11;
+ free(directory_buffer);
+
+ if(ce_size){
+ if(ce_index != dpnt->ce_bytes)
+ fprintf(stderr,"Continuation entry record length mismatch (%d %d).\n",
+ ce_index, dpnt->ce_bytes);
+ xfwrite(ce_buffer, 1, ce_size, outfile);
+ last_extent_written += ce_size >> 11;
+ free(ce_buffer);
+ }
+
+}
+
+static void FDECL1(build_pathlist, struct directory *, node){
+ struct directory * dpnt;
+
+ dpnt = node;
+
+ while (dpnt){
+ pathlist[dpnt->path_index] = dpnt;
+ if(dpnt->subdir) build_pathlist(dpnt->subdir);
+ dpnt = dpnt->next;
+ };
+}
+
+int FDECL2(compare_paths, const struct directory **, r, const struct directory **, l) {
+ if((*r)->parent->path_index < (*l)->parent->path_index) return -1;
+ if((*r)->parent->path_index > (*l)->parent->path_index) return 1;
+ return strcmp((*r)->self->isorec.name, (*l)->self->isorec.name);
+
+}
+
+void generate_path_tables(){
+ struct directory * dpnt;
+ char * npnt, *npnt1;
+ int namelen;
+ struct directory_entry * de;
+ int fix;
+ int tablesize;
+ int i,j;
+ /* First allocate memory for the tables and initialize the memory */
+
+ tablesize = path_blocks << 11;
+ path_table_m = (char *) e_malloc(tablesize);
+ path_table_l = (char *) e_malloc(tablesize);
+ memset(path_table_l, 0, tablesize);
+ memset(path_table_m, 0, tablesize);
+
+ /* Now start filling in the path tables. Start with root directory */
+ path_table_index = 0;
+ pathlist = (struct directory **) e_malloc(sizeof(struct directory *) * next_path_index);
+ memset(pathlist, 0, sizeof(struct directory *) * next_path_index);
+ build_pathlist(root);
+
+ do{
+ fix = 0;
+ qsort(&pathlist[1], next_path_index-1, sizeof(struct directory *), (void *)compare_paths);
+
+ for(j=1; j<next_path_index; j++)
+ if(pathlist[j]->path_index != j){
+ pathlist[j]->path_index = j;
+ fix++;
+ };
+ } while(fix);
+
+ for(j=1; j<next_path_index; j++){
+ dpnt = pathlist[j];
+ if(!dpnt){
+ fprintf(stderr,"Entry %d not in path tables\n", j);
+ exit(1);
+ };
+ npnt = dpnt->de_name;
+ if(*npnt == 0 || dpnt == root) npnt = "."; /* So the root comes out OK */
+ npnt1 = strrchr(npnt, PATH_SEPARATOR);
+ if(npnt1) npnt = npnt1 + 1;
+
+ de = dpnt->self;
+ if(!de) {fprintf(stderr,"Fatal goof\n"); exit(1);};
+
+
+ namelen = de->isorec.name_len[0];
+
+ path_table_l[path_table_index] = namelen;
+ path_table_m[path_table_index] = namelen;
+ path_table_index += 2;
+ set_731(path_table_l + path_table_index, dpnt->extent);
+ set_732(path_table_m + path_table_index, dpnt->extent);
+ path_table_index += 4;
+ set_721(path_table_l + path_table_index, dpnt->parent->path_index);
+ set_722(path_table_m + path_table_index, dpnt->parent->path_index);
+ path_table_index += 2;
+ for(i =0; i<namelen; i++){
+ path_table_l[path_table_index] = de->isorec.name[i];
+ path_table_m[path_table_index] = de->isorec.name[i];
+ path_table_index++;
+ };
+ if(path_table_index & 1) path_table_index++; /* For odd lengths we pad */
+ };
+ free(pathlist);
+ if(path_table_index != path_table_size)
+ fprintf(stderr,"Path table lengths do not match %d %d\n",path_table_index,
+ path_table_size);
+}
+
+int FDECL1(iso_write, FILE *, outfile){
+ char buffer[2048];
+ char iso_time[17];
+ int should_write;
+ int i;
+
+ assign_file_addresses(root);
+
+ memset(buffer, 0, sizeof(buffer));
+
+ /* This will break in the year 2000, I supose, but there is no good way
+ to get the top two digits of the year. */
+ sprintf(iso_time, "%4.4d%2.2d%2.2d%2.2d%2.2d%2.2d00", 1900 + local->tm_year,
+ local->tm_mon+1, local->tm_mday,
+ local->tm_hour, local->tm_min, local->tm_sec);
+
+ /* First, we output 16 sectors of all zero */
+
+ for(i=0; i<16; i++)
+ xfwrite(buffer, 1, sizeof(buffer), outfile);
+
+ last_extent_written += 16;
+
+ /* Next we write out the primary descriptor for the disc */
+ memset(&vol_desc, 0, sizeof(vol_desc));
+ vol_desc.type[0] = ISO_VD_PRIMARY;
+ memcpy(vol_desc.id, ISO_STANDARD_ID, sizeof(ISO_STANDARD_ID));
+ vol_desc.version[0] = 1;
+
+ memset(vol_desc.system_id, ' ', sizeof(vol_desc.system_id));
+ memcpy(vol_desc.system_id, system_id, strlen(system_id));
+
+ memset(vol_desc.volume_id, ' ', sizeof(vol_desc.volume_id));
+ memcpy(vol_desc.volume_id, volume_id, strlen(volume_id));
+
+ should_write = last_extent;
+ set_733(vol_desc.volume_space_size, last_extent);
+ set_723(vol_desc.volume_set_size, 1);
+ set_723(vol_desc.volume_sequence_number, 1);
+ set_723(vol_desc.logical_block_size, 2048);
+
+ /* The path tables are used by DOS based machines to cache directory
+ locations */
+
+ set_733(vol_desc.path_table_size, path_table_size);
+ set_731(vol_desc.type_l_path_table, path_table[0]);
+ set_731(vol_desc.opt_type_l_path_table, path_table[1]);
+ set_732(vol_desc.type_m_path_table, path_table[2]);
+ set_732(vol_desc.opt_type_m_path_table, path_table[3]);
+
+ /* Now we copy the actual root directory record */
+
+ memcpy(vol_desc.root_directory_record, &root_record,
+ sizeof(struct iso_directory_record) + 1);
+
+ /* The rest is just fluff. It looks nice to fill in many of these fields,
+ though */
+
+ FILL_SPACE(volume_set_id);
+ if(volset_id) memcpy(vol_desc.volume_set_id, volset_id, strlen(volset_id));
+
+ FILL_SPACE(publisher_id);
+ if(publisher) memcpy(vol_desc.publisher_id, publisher, strlen(publisher));
+
+ FILL_SPACE(preparer_id);
+ if(preparer) memcpy(vol_desc.preparer_id, preparer, strlen(preparer));
+
+ FILL_SPACE(application_id);
+ if(appid) memcpy(vol_desc.application_id, appid, strlen(appid));
+
+ FILL_SPACE(copyright_file_id);
+ if(appid) memcpy(vol_desc.copyright_file_id, appid, strlen(appid));
+
+ FILL_SPACE(abstract_file_id);
+ if(appid) memcpy(vol_desc.abstract_file_id, appid, strlen(appid));
+
+ FILL_SPACE(bibliographic_file_id);
+ if(appid) memcpy(vol_desc.bibliographic_file_id, appid, strlen(appid));
+
+ FILL_SPACE(creation_date);
+ FILL_SPACE(modification_date);
+ FILL_SPACE(expiration_date);
+ FILL_SPACE(effective_date);
+ vol_desc.file_structure_version[0] = 1;
+ FILL_SPACE(application_data);
+
+ memcpy(vol_desc.creation_date, iso_time, 16);
+ memcpy(vol_desc.modification_date, iso_time, 16);
+ memcpy(vol_desc.expiration_date, "0000000000000000", 16);
+ memcpy(vol_desc.effective_date, iso_time, 16);
+
+ /* For some reason, Young Minds writes this twice. Aw, what the heck */
+ xfwrite(&vol_desc, 1, 2048, outfile);
+ xfwrite(&vol_desc, 1, 2048, outfile);
+ last_extent_written += 2;
+
+ /* Now write the end volume descriptor. Much simpler than the other one */
+ memset(&vol_desc, 0, sizeof(vol_desc));
+ vol_desc.type[0] = ISO_VD_END;
+ memcpy(vol_desc.id, ISO_STANDARD_ID, sizeof(ISO_STANDARD_ID));
+ vol_desc.version[0] = 1;
+ xfwrite(&vol_desc, 1, 2048, outfile);
+ xfwrite(&vol_desc, 1, 2048, outfile);
+ last_extent_written += 2;
+
+ /* Next we write the path tables */
+ xfwrite(path_table_l, 1, path_blocks << 11, outfile);
+ xfwrite(path_table_l, 1, path_blocks << 11, outfile);
+ xfwrite(path_table_m, 1, path_blocks << 11, outfile);
+ xfwrite(path_table_m, 1, path_blocks << 11, outfile);
+ last_extent_written += 4*path_blocks;
+ free(path_table_l);
+ free(path_table_m);
+ path_table_l = NULL;
+ path_table_m = NULL;
+
+ /* OK, all done with that crap. Now write out the directories.
+ This is where the fur starts to fly, because we need to keep track of
+ each file as we find it and keep track of where we put it. */
+
+#ifdef DBG_ISO
+ fprintf(stderr,"Total directory extents being written = %d\n", last_extent);
+#endif
+#if 0
+ generate_one_directory(root, outfile);
+#endif
+ generate_iso9660_directories(root, outfile);
+
+ if(extension_record) {
+ xfwrite(extension_record, 1, SECTOR_SIZE, outfile);
+ last_extent_written++;
+ }
+
+ /* Now write all of the files that we need. */
+ fprintf(stderr,"Total extents scheduled to be written = %d\n", last_extent);
+ write_files(outfile);
+
+ fprintf(stderr,"Total extents actually written = %d\n", last_extent_written);
+ /* Hard links throw us off here */
+ if(should_write != last_extent){
+ fprintf(stderr,"Number of extents written not what was predicted. Please fix.\n");
+ fprintf(stderr,"Predicted = %d, written = %d\n", should_write, last_extent);
+ };
+
+ fprintf(stderr,"Total translation table size: %d\n", table_size);
+ fprintf(stderr,"Total rockridge attributes bytes: %d\n", rockridge_size);
+ fprintf(stderr,"Total directory bytes: %d\n", total_dir_size);
+ fprintf(stderr,"Path table size(bytes): %d\n", path_table_size);
+#ifdef DEBUG
+ fprintf(stderr, "next extent, last_extent, last_extent_written %d %d %d\n",
+ next_extent, last_extent, last_extent_written);
+#endif
+ return 0;
+}
diff --git a/gnu/usr.bin/patch/EXTERN.h b/gnu/usr.bin/patch/EXTERN.h
new file mode 100644
index 0000000..96dd888
--- /dev/null
+++ b/gnu/usr.bin/patch/EXTERN.h
@@ -0,0 +1,24 @@
+/* $Header: /home/ncvs/src/gnu/usr.bin/patch/EXTERN.h,v 1.1.1.1 1993/06/19 14:21:52 paul Exp $
+ *
+ * $Log: EXTERN.h,v $
+ * Revision 1.1.1.1 1993/06/19 14:21:52 paul
+ * b-maked patch-2.10
+ *
+ * Revision 2.0 86/09/17 15:35:37 lwall
+ * Baseline for netwide release.
+ *
+ */
+
+#ifdef EXT
+#undef EXT
+#endif
+#define EXT extern
+
+#ifdef INIT
+#undef INIT
+#endif
+#define INIT(x)
+
+#ifdef DOINIT
+#undef DOINIT
+#endif
diff --git a/gnu/usr.bin/patch/INTERN.h b/gnu/usr.bin/patch/INTERN.h
new file mode 100644
index 0000000..b718b1d
--- /dev/null
+++ b/gnu/usr.bin/patch/INTERN.h
@@ -0,0 +1,22 @@
+/* $Header: /home/ncvs/src/gnu/usr.bin/patch/INTERN.h,v 1.1.1.1 1993/06/19 14:21:52 paul Exp $
+ *
+ * $Log: INTERN.h,v $
+ * Revision 1.1.1.1 1993/06/19 14:21:52 paul
+ * b-maked patch-2.10
+ *
+ * Revision 2.0 86/09/17 15:35:58 lwall
+ * Baseline for netwide release.
+ *
+ */
+
+#ifdef EXT
+#undef EXT
+#endif
+#define EXT
+
+#ifdef INIT
+#undef INIT
+#endif
+#define INIT(x) = x
+
+#define DOINIT
diff --git a/gnu/usr.bin/patch/Makefile b/gnu/usr.bin/patch/Makefile
new file mode 100644
index 0000000..4d5fad2
--- /dev/null
+++ b/gnu/usr.bin/patch/Makefile
@@ -0,0 +1,6 @@
+PROG= patch
+SRCS = backupfile.c getopt.c getopt1.c inp.c patch.c pch.c util.c \
+ version.c
+CFLAGS += -DHAVE_CONFIG_H
+MAN= patch.1
+.include <bsd.prog.mk>
diff --git a/gnu/usr.bin/patch/backupfile.c b/gnu/usr.bin/patch/backupfile.c
new file mode 100644
index 0000000..7779056
--- /dev/null
+++ b/gnu/usr.bin/patch/backupfile.c
@@ -0,0 +1,402 @@
+/* backupfile.c -- make Emacs style backup file names
+ Copyright (C) 1990, 1991, 1992 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* Written by David MacKenzie <djm@gnu.ai.mit.edu>.
+ Some algorithms adapted from GNU Emacs. */
+
+#include "config.h"
+#include <stdio.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include "backupfile.h"
+#ifdef STDC_HEADERS
+#include <string.h>
+#include <stdlib.h>
+#else
+char *malloc ();
+#endif
+
+#if defined (HAVE_UNISTD_H)
+#include <unistd.h>
+#endif
+
+#if defined(DIRENT) || defined(_POSIX_VERSION)
+#include <dirent.h>
+#define NLENGTH(direct) (strlen((direct)->d_name))
+#else /* not (DIRENT or _POSIX_VERSION) */
+#define dirent direct
+#define NLENGTH(direct) ((direct)->d_namlen)
+#ifdef SYSNDIR
+#include <sys/ndir.h>
+#endif /* SYSNDIR */
+#ifdef SYSDIR
+#include <sys/dir.h>
+#endif /* SYSDIR */
+#ifdef NDIR
+#include <ndir.h>
+#endif /* NDIR */
+#endif /* DIRENT or _POSIX_VERSION */
+
+#ifndef isascii
+#define ISDIGIT(c) (isdigit ((unsigned char) (c)))
+#else
+#define ISDIGIT(c) (isascii (c) && isdigit (c))
+#endif
+
+#if defined (_POSIX_VERSION)
+/* POSIX does not require that the d_ino field be present, and some
+ systems do not provide it. */
+#define REAL_DIR_ENTRY(dp) 1
+#else
+#define REAL_DIR_ENTRY(dp) ((dp)->d_ino != 0)
+#endif
+
+/* Which type of backup file names are generated. */
+enum backup_type backup_type = none;
+
+/* The extension added to file names to produce a simple (as opposed
+ to numbered) backup file name. */
+char *simple_backup_suffix = "~";
+
+char *basename ();
+char *dirname ();
+static char *concat ();
+char *find_backup_file_name ();
+static char *make_version_name ();
+static int max_backup_version ();
+static int version_number ();
+
+/* Return NAME with any leading path stripped off. */
+
+char *
+basename (name)
+ char *name;
+{
+ char *r = name, *p = name;
+
+ while (*p)
+ if (*p++ == '/')
+ r = p;
+ return r;
+}
+
+#ifndef NODIR
+/* Return the name of the new backup file for file FILE,
+ allocated with malloc. Return 0 if out of memory.
+ FILE must not end with a '/' unless it is the root directory.
+ Do not call this function if backup_type == none. */
+
+char *
+find_backup_file_name (file)
+ char *file;
+{
+ char *dir;
+ char *base_versions;
+ int highest_backup;
+
+ if (backup_type == simple)
+ {
+ char *s = malloc (strlen (file) + strlen (simple_backup_suffix) + 1);
+ strcpy (s, file);
+ addext (s, simple_backup_suffix, '~');
+ return s;
+ }
+ base_versions = concat (basename (file), ".~");
+ if (base_versions == 0)
+ return 0;
+ dir = dirname (file);
+ if (dir == 0)
+ {
+ free (base_versions);
+ return 0;
+ }
+ highest_backup = max_backup_version (base_versions, dir);
+ free (base_versions);
+ free (dir);
+ if (backup_type == numbered_existing && highest_backup == 0)
+ return concat (file, simple_backup_suffix);
+ return make_version_name (file, highest_backup + 1);
+}
+
+/* Return the number of the highest-numbered backup file for file
+ FILE in directory DIR. If there are no numbered backups
+ of FILE in DIR, or an error occurs reading DIR, return 0.
+ FILE should already have ".~" appended to it. */
+
+static int
+max_backup_version (file, dir)
+ char *file, *dir;
+{
+ DIR *dirp;
+ struct dirent *dp;
+ int highest_version;
+ int this_version;
+ int file_name_length;
+
+ dirp = opendir (dir);
+ if (!dirp)
+ return 0;
+
+ highest_version = 0;
+ file_name_length = strlen (file);
+
+ while ((dp = readdir (dirp)) != 0)
+ {
+ if (!REAL_DIR_ENTRY (dp) || NLENGTH (dp) <= file_name_length)
+ continue;
+
+ this_version = version_number (file, dp->d_name, file_name_length);
+ if (this_version > highest_version)
+ highest_version = this_version;
+ }
+ closedir (dirp);
+ return highest_version;
+}
+
+/* Return a string, allocated with malloc, containing
+ "FILE.~VERSION~". Return 0 if out of memory. */
+
+static char *
+make_version_name (file, version)
+ char *file;
+ int version;
+{
+ char *backup_name;
+
+ backup_name = malloc (strlen (file) + 16);
+ if (backup_name == 0)
+ return 0;
+ sprintf (backup_name, "%s.~%d~", file, version);
+ return backup_name;
+}
+
+/* If BACKUP is a numbered backup of BASE, return its version number;
+ otherwise return 0. BASE_LENGTH is the length of BASE.
+ BASE should already have ".~" appended to it. */
+
+static int
+version_number (base, backup, base_length)
+ char *base;
+ char *backup;
+ int base_length;
+{
+ int version;
+ char *p;
+
+ version = 0;
+ if (!strncmp (base, backup, base_length) && ISDIGIT (backup[base_length]))
+ {
+ for (p = &backup[base_length]; ISDIGIT (*p); ++p)
+ version = version * 10 + *p - '0';
+ if (p[0] != '~' || p[1])
+ version = 0;
+ }
+ return version;
+}
+
+/* Return the newly-allocated concatenation of STR1 and STR2.
+ If out of memory, return 0. */
+
+static char *
+concat (str1, str2)
+ char *str1, *str2;
+{
+ char *newstr;
+ char str1_length = strlen (str1);
+
+ newstr = malloc (str1_length + strlen (str2) + 1);
+ if (newstr == 0)
+ return 0;
+ strcpy (newstr, str1);
+ strcpy (newstr + str1_length, str2);
+ return newstr;
+}
+
+/* Return the leading directories part of PATH,
+ allocated with malloc. If out of memory, return 0.
+ Assumes that trailing slashes have already been
+ removed. */
+
+char *
+dirname (path)
+ char *path;
+{
+ char *newpath;
+ char *slash;
+ int length; /* Length of result, not including NUL. */
+
+ slash = basename (path);
+ if (slash == path)
+ {
+ /* File is in the current directory. */
+ path = ".";
+ length = 1;
+ }
+ else
+ {
+ /* Remove any trailing slashes from result. */
+ while (*--slash == '/' && slash > path)
+ ;
+
+ length = slash - path + 1;
+ }
+ newpath = malloc (length + 1);
+ if (newpath == 0)
+ return 0;
+ strncpy (newpath, path, length);
+ newpath[length] = 0;
+ return newpath;
+}
+
+/* If ARG is an unambiguous match for an element of the
+ null-terminated array OPTLIST, return the index in OPTLIST
+ of the matched element, else -1 if it does not match any element
+ or -2 if it is ambiguous (is a prefix of more than one element). */
+
+int
+argmatch (arg, optlist)
+ char *arg;
+ char **optlist;
+{
+ int i; /* Temporary index in OPTLIST. */
+ int arglen; /* Length of ARG. */
+ int matchind = -1; /* Index of first nonexact match. */
+ int ambiguous = 0; /* If nonzero, multiple nonexact match(es). */
+
+ arglen = strlen (arg);
+
+ /* Test all elements for either exact match or abbreviated matches. */
+ for (i = 0; optlist[i]; i++)
+ {
+ if (!strncmp (optlist[i], arg, arglen))
+ {
+ if (strlen (optlist[i]) == arglen)
+ /* Exact match found. */
+ return i;
+ else if (matchind == -1)
+ /* First nonexact match found. */
+ matchind = i;
+ else
+ /* Second nonexact match found. */
+ ambiguous = 1;
+ }
+ }
+ if (ambiguous)
+ return -2;
+ else
+ return matchind;
+}
+
+/* Error reporting for argmatch.
+ KIND is a description of the type of entity that was being matched.
+ VALUE is the invalid value that was given.
+ PROBLEM is the return value from argmatch. */
+
+void
+invalid_arg (kind, value, problem)
+ char *kind;
+ char *value;
+ int problem;
+{
+ fprintf (stderr, "patch: ");
+ if (problem == -1)
+ fprintf (stderr, "invalid");
+ else /* Assume -2. */
+ fprintf (stderr, "ambiguous");
+ fprintf (stderr, " %s `%s'\n", kind, value);
+}
+
+static char *backup_args[] =
+{
+ "never", "simple", "nil", "existing", "t", "numbered", 0
+};
+
+static enum backup_type backup_types[] =
+{
+ simple, simple, numbered_existing, numbered_existing, numbered, numbered
+};
+
+/* Return the type of backup indicated by VERSION.
+ Unique abbreviations are accepted. */
+
+enum backup_type
+get_version (version)
+ char *version;
+{
+ int i;
+
+ if (version == 0 || *version == 0)
+ return numbered_existing;
+ i = argmatch (version, backup_args);
+ if (i >= 0)
+ return backup_types[i];
+ invalid_arg ("version control type", version, i);
+ exit (1);
+}
+#endif /* NODIR */
+
+/* Append to FILENAME the extension EXT, unless the result would be too long,
+ in which case just append the character E. */
+
+void
+addext (filename, ext, e)
+ char *filename, *ext;
+ int e;
+{
+ char *s = basename (filename);
+ int slen = strlen (s), extlen = strlen (ext);
+ long slen_max = -1;
+
+#if HAVE_PATHCONF && defined (_PC_NAME_MAX)
+#ifndef _POSIX_NAME_MAX
+#define _POSIX_NAME_MAX 14
+#endif
+ if (slen + extlen <= _POSIX_NAME_MAX)
+ /* The file name is so short there's no need to call pathconf. */
+ slen_max = _POSIX_NAME_MAX;
+ else if (s == filename)
+ slen_max = pathconf (".", _PC_NAME_MAX);
+ else
+ {
+ char c = *s;
+ *s = 0;
+ slen_max = pathconf (filename, _PC_NAME_MAX);
+ *s = c;
+ }
+#endif
+ if (slen_max == -1) {
+#ifdef HAVE_LONG_FILE_NAMES
+ slen_max = 255;
+#else
+ slen_max = 14;
+#endif
+ }
+ if (slen + extlen <= slen_max)
+ strcpy (s + slen, ext);
+ else
+ {
+ if (slen_max <= slen) {
+ /* Try to preserve difference between .h .c etc. */
+ if (slen == slen_max && s[slen - 2] == '.')
+ s[slen - 2] = s[slen - 1];
+
+ slen = slen_max - 1;
+ }
+ s[slen] = e;
+ s[slen + 1] = 0;
+ }
+}
diff --git a/gnu/usr.bin/patch/backupfile.h b/gnu/usr.bin/patch/backupfile.h
new file mode 100644
index 0000000..dfd1fc4
--- /dev/null
+++ b/gnu/usr.bin/patch/backupfile.h
@@ -0,0 +1,46 @@
+/* backupfile.h -- declarations for making Emacs style backup file names
+ Copyright (C) 1990, 1991, 1992 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* When to make backup files. */
+enum backup_type
+{
+ /* Never make backups. */
+ none,
+
+ /* Make simple backups of every file. */
+ simple,
+
+ /* Make numbered backups of files that already have numbered backups,
+ and simple backups of the others. */
+ numbered_existing,
+
+ /* Make numbered backups of every file. */
+ numbered
+};
+
+extern enum backup_type backup_type;
+extern char *simple_backup_suffix;
+
+#ifdef __STDC__
+char *find_backup_file_name (char *file);
+enum backup_type get_version (char *version);
+void addext (char *, char *, int);
+#else
+char *find_backup_file_name ();
+enum backup_type get_version ();
+void addext ();
+#endif
diff --git a/gnu/usr.bin/patch/common.h b/gnu/usr.bin/patch/common.h
new file mode 100644
index 0000000..4bb99e0
--- /dev/null
+++ b/gnu/usr.bin/patch/common.h
@@ -0,0 +1,197 @@
+/* $Header: /home/ncvs/src/gnu/usr.bin/patch/common.h,v 1.2 1993/09/22 16:51:03 rich Exp $
+ *
+ * $Log: common.h,v $
+ * Revision 1.2 1993/09/22 16:51:03 rich
+ * Increaed the fixed static buffer sizes and maximum hunk size that
+ * otherwise causes the XFree86 1.3 patch set to fail.
+ *
+ * Revision 1.1.1.1 1993/06/19 14:21:52 paul
+ * b-maked patch-2.10
+ *
+ * Revision 2.0.1.2 88/06/22 20:44:53 lwall
+ * patch12: sprintf was declared wrong
+ *
+ * Revision 2.0.1.1 88/06/03 15:01:56 lwall
+ * patch10: support for shorter extensions.
+ *
+ * Revision 2.0 86/09/17 15:36:39 lwall
+ * Baseline for netwide release.
+ *
+ */
+
+#define DEBUGGING
+
+#define VOIDUSED 7
+#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
+
+/* NeXT declares malloc and realloc incompatibly from us in some of
+ these files. Temporarily redefine them to prevent errors. */
+#define malloc system_malloc
+#define realloc system_realloc
+#include <stdio.h>
+#include <assert.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <ctype.h>
+#include <signal.h>
+#undef malloc
+#undef realloc
+
+/* constants */
+
+/* AIX predefines these. */
+#ifdef TRUE
+#undef TRUE
+#endif
+#ifdef FALSE
+#undef FALSE
+#endif
+#define TRUE (1)
+#define FALSE (0)
+
+#define MAXHUNKSIZE 200000 /* is this enough lines? */
+#define INITHUNKMAX 125 /* initial dynamic allocation size */
+#define MAXLINELEN 4096
+#define BUFFERSIZE 4096
+
+#define SCCSPREFIX "s."
+#define GET "get %s"
+#define GET_LOCKED "get -e %s"
+#define SCCSDIFF "get -p %s | diff - %s >/dev/null"
+
+#define RCSSUFFIX ",v"
+#define CHECKOUT "co %s"
+#define CHECKOUT_LOCKED "co -l %s"
+#define RCSDIFF "rcsdiff %s > /dev/null"
+
+/* 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 optind_last; /* for restarting plan_b */
+
+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 int myuid; /* cache getuid return value */
+
+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 *origprae INIT(Nullch);
+
+EXT char *TMPOUTNAME;
+EXT char *TMPINNAME;
+EXT char *TMPREJNAME;
+EXT char *TMPPATNAME;
+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 batch 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
+#define UNI_DIFF 5
+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 */
+
+#include <errno.h>
+#ifdef STDC_HEADERS
+#include <stdlib.h>
+#include <string.h>
+#else
+extern int errno;
+FILE *popen();
+char *malloc();
+char *realloc();
+long atol();
+char *getenv();
+char *strcpy();
+char *strcat();
+#endif
+char *mktemp();
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#else
+long lseek();
+#endif
+#if defined(_POSIX_VERSION) || defined(HAVE_FCNTL_H)
+#include <fcntl.h>
+#endif
+
+#if !defined(S_ISDIR) && defined(S_IFDIR)
+#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
+#endif
+#if !defined(S_ISREG) && defined(S_IFREG)
+#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
+#endif
diff --git a/gnu/usr.bin/patch/config.h b/gnu/usr.bin/patch/config.h
new file mode 100644
index 0000000..177a8c5
--- /dev/null
+++ b/gnu/usr.bin/patch/config.h
@@ -0,0 +1,81 @@
+/* config.h. Generated automatically by configure. */
+/* Portability variables. -*- C -*- */
+
+/* Define if the system does not support the `const' keyword. */
+/* #undef const */
+
+/* Define if the system supports file names longer than 14 characters. */
+#define HAVE_LONG_FILE_NAMES
+
+/* Define if the system has pathconf(). */
+/* #undef HAVE_PATHCONF */
+
+/* Define if the system has strerror(). */
+#define HAVE_STRERROR 1
+
+/* Define if the system has ANSI C header files and library functions. */
+#define STDC_HEADERS
+
+/* Define if the system uses strchr instead of index
+ and strrchr instead of rindex. */
+#define HAVE_STRING_H 1
+
+#if defined(STDC_HEADERS) || defined(HAVE_STRING_H)
+#define index strchr
+#define rindex strrchr
+#endif
+
+/* Define if the system has unistd.h. */
+#define HAVE_UNISTD_H 1
+
+/* Define if the system has fcntl.h. */
+#define HAVE_FCNTL_H 1
+
+/* Define as either int or void -- the type that signal handlers return. */
+#define RETSIGTYPE void
+
+#ifndef RETSIGTYPE
+#define RETSIGTYPE void
+#endif
+
+/* Which directory library header to use. */
+#define DIRENT 1 /* dirent.h */
+/* #undef SYSNDIR */ /* sys/ndir.h */
+/* #undef SYSDIR */ /* sys/dir.h */
+/* #undef NDIR */ /* ndir.h */
+/* #undef NODIR */ /* none -- don't make numbered backup files */
+
+/* Define if the system lets you pass fewer arguments to a function
+ than the function actually accepts (in the absence of a prototype).
+ Defining it makes I/O calls slightly more efficient.
+ You need not bother defining it unless your C preprocessor chokes on
+ multi-line arguments to macros. */
+/* #undef CANVARARG */
+
+/* Define Reg* as either `register' or nothing, depending on whether
+ the C compiler pays attention to this many register declarations.
+ The intent is that you don't have to order your register declarations
+ in the order of importance, so you can freely declare register variables
+ in sub-blocks of code and as function parameters.
+ Do not use Reg<n> more than once per routine.
+
+ These don't really matter a lot, since most modern C compilers ignore
+ register declarations and often do a better job of allocating
+ registers than people do. */
+
+#define Reg1 register
+#define Reg2 register
+#define Reg3 register
+#define Reg4 register
+#define Reg5 register
+#define Reg6 register
+#define Reg7
+#define Reg8
+#define Reg9
+#define Reg10
+#define Reg11
+#define Reg12
+#define Reg13
+#define Reg14
+#define Reg15
+#define Reg16
diff --git a/gnu/usr.bin/patch/getopt.c b/gnu/usr.bin/patch/getopt.c
new file mode 100644
index 0000000..a59a013
--- /dev/null
+++ b/gnu/usr.bin/patch/getopt.c
@@ -0,0 +1,731 @@
+/* Getopt for GNU.
+ NOTE: getopt is now part of the C library, so if you don't know what
+ "Keep this file name-space clean" means, talk to roland@gnu.ai.mit.edu
+ before changing it!
+
+ Copyright (C) 1987, 88, 89, 90, 91, 92, 1993
+ Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any
+ later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* NOTE!!! AIX requires this to be the first thing in the file.
+ Do not put ANYTHING before it! */
+#if !defined (__GNUC__) && defined (_AIX)
+ #pragma alloca
+#endif
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef __GNUC__
+#define alloca __builtin_alloca
+#else /* not __GNUC__ */
+#if defined (HAVE_ALLOCA_H) || (defined(sparc) && (defined(sun) || (!defined(USG) && !defined(SVR4) && !defined(__svr4__))))
+#include <alloca.h>
+#else
+#ifndef _AIX
+char *alloca ();
+#endif
+#endif /* alloca.h */
+#endif /* not __GNUC__ */
+
+#if !__STDC__ && !defined(const) && IN_GCC
+#define const
+#endif
+
+/* This tells Alpha OSF/1 not to define a getopt prototype in <stdio.h>. */
+#ifndef _NO_PROTO
+#define _NO_PROTO
+#endif
+
+#include <stdio.h>
+
+/* Comment out all this code if we are using the GNU C Library, and are not
+ actually compiling the library itself. This code is part of the GNU C
+ Library, but also included in many other GNU distributions. Compiling
+ and linking in this code is a waste when using the GNU C library
+ (especially if it is a shared library). Rather than having every GNU
+ program understand `configure --with-gnu-libc' and omit the object files,
+ it is simpler to just do this in the source for each such file. */
+
+#if defined (_LIBC) || !defined (__GNU_LIBRARY__)
+
+
+/* This needs to come after some library #include
+ to get __GNU_LIBRARY__ defined. */
+#ifdef __GNU_LIBRARY__
+#undef alloca
+/* Don't include stdlib.h for non-GNU C libraries because some of them
+ contain conflicting prototypes for getopt. */
+#include <stdlib.h>
+#else /* Not GNU C library. */
+#define __alloca alloca
+#endif /* GNU C library. */
+
+/* If GETOPT_COMPAT is defined, `+' as well as `--' can introduce a
+ long-named option. Because this is not POSIX.2 compliant, it is
+ being phased out. */
+/* #define GETOPT_COMPAT */
+
+/* This version of `getopt' appears to the caller like standard Unix `getopt'
+ but it behaves differently for the user, since it allows the user
+ to intersperse the options with the other arguments.
+
+ As `getopt' works, it permutes the elements of ARGV so that,
+ when it is done, all the options precede everything else. Thus
+ all application programs are extended to handle flexible argument order.
+
+ Setting the environment variable POSIXLY_CORRECT disables permutation.
+ Then the behavior is completely standard.
+
+ GNU application programs can use a third alternative mode in which
+ they can distinguish the relative order of options and other arguments. */
+
+#include "getopt.h"
+
+/* For communication from `getopt' to the caller.
+ When `getopt' finds an option that takes an argument,
+ the argument value is returned here.
+ Also, when `ordering' is RETURN_IN_ORDER,
+ each non-option ARGV-element is returned here. */
+
+char *optarg = 0;
+
+/* Index in ARGV of the next element to be scanned.
+ This is used for communication to and from the caller
+ and for communication between successive calls to `getopt'.
+
+ On entry to `getopt', zero means this is the first call; initialize.
+
+ When `getopt' returns EOF, this is the index of the first of the
+ non-option elements that the caller should itself scan.
+
+ Otherwise, `optind' communicates from one call to the next
+ how much of ARGV has been scanned so far. */
+
+/* XXX 1003.2 says this must be 1 before any call. */
+int optind = 0;
+
+/* The next char to be scanned in the option-element
+ in which the last option character we returned was found.
+ This allows us to pick up the scan where we left off.
+
+ If this is zero, or a null string, it means resume the scan
+ by advancing to the next ARGV-element. */
+
+static char *nextchar;
+
+/* Callers store zero here to inhibit the error message
+ for unrecognized options. */
+
+int opterr = 1;
+
+/* Set to an option character which was unrecognized.
+ This must be initialized on some systems to avoid linking in the
+ system's own getopt implementation. */
+
+int optopt = '?';
+
+/* Describe how to deal with options that follow non-option ARGV-elements.
+
+ If the caller did not specify anything,
+ the default is REQUIRE_ORDER if the environment variable
+ POSIXLY_CORRECT is defined, PERMUTE otherwise.
+
+ REQUIRE_ORDER means don't recognize them as options;
+ stop option processing when the first non-option is seen.
+ This is what Unix does.
+ This mode of operation is selected by either setting the environment
+ variable POSIXLY_CORRECT, or using `+' as the first character
+ of the list of option characters.
+
+ PERMUTE is the default. We permute the contents of ARGV as we scan,
+ so that eventually all the non-options are at the end. This allows options
+ to be given in any order, even with programs that were not written to
+ expect this.
+
+ RETURN_IN_ORDER is an option available to programs that were written
+ to expect options and other ARGV-elements in any order and that care about
+ the ordering of the two. We describe each non-option ARGV-element
+ as if it were the argument of an option with character code 1.
+ Using `-' as the first character of the list of option characters
+ selects this mode of operation.
+
+ The special argument `--' forces an end of option-scanning regardless
+ of the value of `ordering'. In the case of RETURN_IN_ORDER, only
+ `--' can cause `getopt' to return EOF with `optind' != ARGC. */
+
+static enum
+{
+ REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER
+} ordering;
+
+#ifdef __GNU_LIBRARY__
+/* We want to avoid inclusion of string.h with non-GNU libraries
+ because there are many ways it can cause trouble.
+ On some systems, it contains special magic macros that don't work
+ in GCC. */
+#include <string.h>
+#define my_index strchr
+#define my_bcopy(src, dst, n) memcpy ((dst), (src), (n))
+#else
+
+/* Avoid depending on library functions or files
+ whose names are inconsistent. */
+
+char *getenv ();
+
+static char *
+my_index (str, chr)
+ const char *str;
+ int chr;
+{
+ while (*str)
+ {
+ if (*str == chr)
+ return (char *) str;
+ str++;
+ }
+ return 0;
+}
+
+static void
+my_bcopy (from, to, size)
+ const char *from;
+ char *to;
+ int size;
+{
+ int i;
+ for (i = 0; i < size; i++)
+ to[i] = from[i];
+}
+#endif /* GNU C library. */
+
+/* Handle permutation of arguments. */
+
+/* Describe the part of ARGV that contains non-options that have
+ been skipped. `first_nonopt' is the index in ARGV of the first of them;
+ `last_nonopt' is the index after the last of them. */
+
+static int first_nonopt;
+static int last_nonopt;
+
+/* Exchange two adjacent subsequences of ARGV.
+ One subsequence is elements [first_nonopt,last_nonopt)
+ which contains all the non-options that have been skipped so far.
+ The other is elements [last_nonopt,optind), which contains all
+ the options processed since those non-options were skipped.
+
+ `first_nonopt' and `last_nonopt' are relocated so that they describe
+ the new indices of the non-options in ARGV after they are moved. */
+
+static void
+exchange (argv)
+ char **argv;
+{
+ int nonopts_size = (last_nonopt - first_nonopt) * sizeof (char *);
+ char **temp = (char **) __alloca (nonopts_size);
+
+ /* Interchange the two blocks of data in ARGV. */
+
+ my_bcopy ((char *) &argv[first_nonopt], (char *) temp, nonopts_size);
+ my_bcopy ((char *) &argv[last_nonopt], (char *) &argv[first_nonopt],
+ (optind - last_nonopt) * sizeof (char *));
+ my_bcopy ((char *) temp,
+ (char *) &argv[first_nonopt + optind - last_nonopt],
+ nonopts_size);
+
+ /* Update records for the slots the non-options now occupy. */
+
+ first_nonopt += (optind - last_nonopt);
+ last_nonopt = optind;
+}
+
+/* Scan elements of ARGV (whose length is ARGC) for option characters
+ given in OPTSTRING.
+
+ If an element of ARGV starts with '-', and is not exactly "-" or "--",
+ then it is an option element. The characters of this element
+ (aside from the initial '-') are option characters. If `getopt'
+ is called repeatedly, it returns successively each of the option characters
+ from each of the option elements.
+
+ If `getopt' finds another option character, it returns that character,
+ updating `optind' and `nextchar' so that the next call to `getopt' can
+ resume the scan with the following option character or ARGV-element.
+
+ If there are no more option characters, `getopt' returns `EOF'.
+ Then `optind' is the index in ARGV of the first ARGV-element
+ that is not an option. (The ARGV-elements have been permuted
+ so that those that are not options now come last.)
+
+ OPTSTRING is a string containing the legitimate option characters.
+ If an option character is seen that is not listed in OPTSTRING,
+ return '?' after printing an error message. If you set `opterr' to
+ zero, the error message is suppressed but we still return '?'.
+
+ If a char in OPTSTRING is followed by a colon, that means it wants an arg,
+ so the following text in the same ARGV-element, or the text of the following
+ ARGV-element, is returned in `optarg'. Two colons mean an option that
+ wants an optional arg; if there is text in the current ARGV-element,
+ it is returned in `optarg', otherwise `optarg' is set to zero.
+
+ If OPTSTRING starts with `-' or `+', it requests different methods of
+ handling the non-option ARGV-elements.
+ See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above.
+
+ Long-named options begin with `--' instead of `-'.
+ Their names may be abbreviated as long as the abbreviation is unique
+ or is an exact match for some defined option. If they have an
+ argument, it follows the option name in the same ARGV-element, separated
+ from the option name by a `=', or else the in next ARGV-element.
+ When `getopt' finds a long-named option, it returns 0 if that option's
+ `flag' field is nonzero, the value of the option's `val' field
+ if the `flag' field is zero.
+
+ The elements of ARGV aren't really const, because we permute them.
+ But we pretend they're const in the prototype to be compatible
+ with other systems.
+
+ LONGOPTS is a vector of `struct option' terminated by an
+ element containing a name which is zero.
+
+ LONGIND returns the index in LONGOPT of the long-named option found.
+ It is only valid when a long-named option has been found by the most
+ recent call.
+
+ If LONG_ONLY is nonzero, '-' as well as '--' can introduce
+ long-named options. */
+
+int
+_getopt_internal (argc, argv, optstring, longopts, longind, long_only)
+ int argc;
+ char *const *argv;
+ const char *optstring;
+ const struct option *longopts;
+ int *longind;
+ int long_only;
+{
+ int option_index;
+
+ optarg = 0;
+
+ /* Initialize the internal data when the first call is made.
+ Start processing options with ARGV-element 1 (since ARGV-element 0
+ is the program name); the sequence of previously skipped
+ non-option ARGV-elements is empty. */
+
+ if (optind == 0)
+ {
+ first_nonopt = last_nonopt = optind = 1;
+
+ nextchar = NULL;
+
+ /* Determine how to handle the ordering of options and nonoptions. */
+
+ if (optstring[0] == '-')
+ {
+ ordering = RETURN_IN_ORDER;
+ ++optstring;
+ }
+ else if (optstring[0] == '+')
+ {
+ ordering = REQUIRE_ORDER;
+ ++optstring;
+ }
+ else if (getenv ("POSIXLY_CORRECT") != NULL)
+ ordering = REQUIRE_ORDER;
+ else
+ ordering = PERMUTE;
+ }
+
+ if (nextchar == NULL || *nextchar == '\0')
+ {
+ if (ordering == PERMUTE)
+ {
+ /* If we have just processed some options following some non-options,
+ exchange them so that the options come first. */
+
+ if (first_nonopt != last_nonopt && last_nonopt != optind)
+ exchange ((char **) argv);
+ else if (last_nonopt != optind)
+ first_nonopt = optind;
+
+ /* Now skip any additional non-options
+ and extend the range of non-options previously skipped. */
+
+ while (optind < argc
+ && (argv[optind][0] != '-' || argv[optind][1] == '\0')
+#ifdef GETOPT_COMPAT
+ && (longopts == NULL
+ || argv[optind][0] != '+' || argv[optind][1] == '\0')
+#endif /* GETOPT_COMPAT */
+ )
+ optind++;
+ last_nonopt = optind;
+ }
+
+ /* Special ARGV-element `--' means premature end of options.
+ Skip it like a null option,
+ then exchange with previous non-options as if it were an option,
+ then skip everything else like a non-option. */
+
+ if (optind != argc && !strcmp (argv[optind], "--"))
+ {
+ optind++;
+
+ if (first_nonopt != last_nonopt && last_nonopt != optind)
+ exchange ((char **) argv);
+ else if (first_nonopt == last_nonopt)
+ first_nonopt = optind;
+ last_nonopt = argc;
+
+ optind = argc;
+ }
+
+ /* If we have done all the ARGV-elements, stop the scan
+ and back over any non-options that we skipped and permuted. */
+
+ if (optind == argc)
+ {
+ /* Set the next-arg-index to point at the non-options
+ that we previously skipped, so the caller will digest them. */
+ if (first_nonopt != last_nonopt)
+ optind = first_nonopt;
+ return EOF;
+ }
+
+ /* If we have come to a non-option and did not permute it,
+ either stop the scan or describe it to the caller and pass it by. */
+
+ if ((argv[optind][0] != '-' || argv[optind][1] == '\0')
+#ifdef GETOPT_COMPAT
+ && (longopts == NULL
+ || argv[optind][0] != '+' || argv[optind][1] == '\0')
+#endif /* GETOPT_COMPAT */
+ )
+ {
+ if (ordering == REQUIRE_ORDER)
+ return EOF;
+ optarg = argv[optind++];
+ return 1;
+ }
+
+ /* We have found another option-ARGV-element.
+ Start decoding its characters. */
+
+ nextchar = (argv[optind] + 1
+ + (longopts != NULL && argv[optind][1] == '-'));
+ }
+
+ if (longopts != NULL
+ && ((argv[optind][0] == '-'
+ && (argv[optind][1] == '-' || long_only))
+#ifdef GETOPT_COMPAT
+ || argv[optind][0] == '+'
+#endif /* GETOPT_COMPAT */
+ ))
+ {
+ const struct option *p;
+ char *s = nextchar;
+ int exact = 0;
+ int ambig = 0;
+ const struct option *pfound = NULL;
+ int indfound;
+
+ while (*s && *s != '=')
+ s++;
+
+ /* Test all options for either exact match or abbreviated matches. */
+ for (p = longopts, option_index = 0; p->name;
+ p++, option_index++)
+ if (!strncmp (p->name, nextchar, s - nextchar))
+ {
+ if (s - nextchar == strlen (p->name))
+ {
+ /* Exact match found. */
+ pfound = p;
+ indfound = option_index;
+ exact = 1;
+ break;
+ }
+ else if (pfound == NULL)
+ {
+ /* First nonexact match found. */
+ pfound = p;
+ indfound = option_index;
+ }
+ else
+ /* Second nonexact match found. */
+ ambig = 1;
+ }
+
+ if (ambig && !exact)
+ {
+ if (opterr)
+ fprintf (stderr, "%s: option `%s' is ambiguous\n",
+ argv[0], argv[optind]);
+ nextchar += strlen (nextchar);
+ optind++;
+ return '?';
+ }
+
+ if (pfound != NULL)
+ {
+ option_index = indfound;
+ optind++;
+ if (*s)
+ {
+ /* Don't test has_arg with >, because some C compilers don't
+ allow it to be used on enums. */
+ if (pfound->has_arg)
+ optarg = s + 1;
+ else
+ {
+ if (opterr)
+ {
+ if (argv[optind - 1][1] == '-')
+ /* --option */
+ fprintf (stderr,
+ "%s: option `--%s' doesn't allow an argument\n",
+ argv[0], pfound->name);
+ else
+ /* +option or -option */
+ fprintf (stderr,
+ "%s: option `%c%s' doesn't allow an argument\n",
+ argv[0], argv[optind - 1][0], pfound->name);
+ }
+ nextchar += strlen (nextchar);
+ return '?';
+ }
+ }
+ else if (pfound->has_arg == 1)
+ {
+ if (optind < argc)
+ optarg = argv[optind++];
+ else
+ {
+ if (opterr)
+ fprintf (stderr, "%s: option `%s' requires an argument\n",
+ argv[0], argv[optind - 1]);
+ nextchar += strlen (nextchar);
+ return optstring[0] == ':' ? ':' : '?';
+ }
+ }
+ nextchar += strlen (nextchar);
+ if (longind != NULL)
+ *longind = option_index;
+ if (pfound->flag)
+ {
+ *(pfound->flag) = pfound->val;
+ return 0;
+ }
+ return pfound->val;
+ }
+ /* Can't find it as a long option. If this is not getopt_long_only,
+ or the option starts with '--' or is not a valid short
+ option, then it's an error.
+ Otherwise interpret it as a short option. */
+ if (!long_only || argv[optind][1] == '-'
+#ifdef GETOPT_COMPAT
+ || argv[optind][0] == '+'
+#endif /* GETOPT_COMPAT */
+ || my_index (optstring, *nextchar) == NULL)
+ {
+ if (opterr)
+ {
+ if (argv[optind][1] == '-')
+ /* --option */
+ fprintf (stderr, "%s: unrecognized option `--%s'\n",
+ argv[0], nextchar);
+ else
+ /* +option or -option */
+ fprintf (stderr, "%s: unrecognized option `%c%s'\n",
+ argv[0], argv[optind][0], nextchar);
+ }
+ nextchar = (char *) "";
+ optind++;
+ return '?';
+ }
+ }
+
+ /* Look at and handle the next option-character. */
+
+ {
+ char c = *nextchar++;
+ char *temp = my_index (optstring, c);
+
+ /* Increment `optind' when we start to process its last character. */
+ if (*nextchar == '\0')
+ ++optind;
+
+ if (temp == NULL || c == ':')
+ {
+ if (opterr)
+ {
+#if 0
+ if (c < 040 || c >= 0177)
+ fprintf (stderr, "%s: unrecognized option, character code 0%o\n",
+ argv[0], c);
+ else
+ fprintf (stderr, "%s: unrecognized option `-%c'\n", argv[0], c);
+#else
+ /* 1003.2 specifies the format of this message. */
+ fprintf (stderr, "%s: illegal option -- %c\n", argv[0], c);
+#endif
+ }
+ optopt = c;
+ return '?';
+ }
+ if (temp[1] == ':')
+ {
+ if (temp[2] == ':')
+ {
+ /* This is an option that accepts an argument optionally. */
+ if (*nextchar != '\0')
+ {
+ optarg = nextchar;
+ optind++;
+ }
+ else
+ optarg = 0;
+ nextchar = NULL;
+ }
+ else
+ {
+ /* This is an option that requires an argument. */
+ if (*nextchar != '\0')
+ {
+ optarg = nextchar;
+ /* If we end this ARGV-element by taking the rest as an arg,
+ we must advance to the next element now. */
+ optind++;
+ }
+ else if (optind == argc)
+ {
+ if (opterr)
+ {
+#if 0
+ fprintf (stderr, "%s: option `-%c' requires an argument\n",
+ argv[0], c);
+#else
+ /* 1003.2 specifies the format of this message. */
+ fprintf (stderr, "%s: option requires an argument -- %c\n",
+ argv[0], c);
+#endif
+ }
+ optopt = c;
+ if (optstring[0] == ':')
+ c = ':';
+ else
+ c = '?';
+ }
+ else
+ /* We already incremented `optind' once;
+ increment it again when taking next ARGV-elt as argument. */
+ optarg = argv[optind++];
+ nextchar = NULL;
+ }
+ }
+ return c;
+ }
+}
+
+int
+getopt (argc, argv, optstring)
+ int argc;
+ char *const *argv;
+ const char *optstring;
+{
+ return _getopt_internal (argc, argv, optstring,
+ (const struct option *) 0,
+ (int *) 0,
+ 0);
+}
+
+#endif /* _LIBC or not __GNU_LIBRARY__. */
+
+#ifdef TEST
+
+/* Compile with -DTEST to make an executable for use in testing
+ the above definition of `getopt'. */
+
+int
+main (argc, argv)
+ int argc;
+ char **argv;
+{
+ int c;
+ int digit_optind = 0;
+
+ while (1)
+ {
+ int this_option_optind = optind ? optind : 1;
+
+ c = getopt (argc, argv, "abc:d:0123456789");
+ if (c == EOF)
+ break;
+
+ switch (c)
+ {
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ if (digit_optind != 0 && digit_optind != this_option_optind)
+ printf ("digits occur in two different argv-elements.\n");
+ digit_optind = this_option_optind;
+ printf ("option %c\n", c);
+ break;
+
+ case 'a':
+ printf ("option a\n");
+ break;
+
+ case 'b':
+ printf ("option b\n");
+ break;
+
+ case 'c':
+ printf ("option c with value `%s'\n", optarg);
+ break;
+
+ case '?':
+ break;
+
+ default:
+ printf ("?? getopt returned character code 0%o ??\n", c);
+ }
+ }
+
+ if (optind < argc)
+ {
+ printf ("non-option ARGV-elements: ");
+ while (optind < argc)
+ printf ("%s ", argv[optind++]);
+ printf ("\n");
+ }
+
+ exit (0);
+}
+
+#endif /* TEST */
diff --git a/gnu/usr.bin/patch/getopt.h b/gnu/usr.bin/patch/getopt.h
new file mode 100644
index 0000000..45541f5
--- /dev/null
+++ b/gnu/usr.bin/patch/getopt.h
@@ -0,0 +1,129 @@
+/* Declarations for getopt.
+ Copyright (C) 1989, 1990, 1991, 1992, 1993 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any
+ later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#ifndef _GETOPT_H
+#define _GETOPT_H 1
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* For communication from `getopt' to the caller.
+ When `getopt' finds an option that takes an argument,
+ the argument value is returned here.
+ Also, when `ordering' is RETURN_IN_ORDER,
+ each non-option ARGV-element is returned here. */
+
+extern char *optarg;
+
+/* Index in ARGV of the next element to be scanned.
+ This is used for communication to and from the caller
+ and for communication between successive calls to `getopt'.
+
+ On entry to `getopt', zero means this is the first call; initialize.
+
+ When `getopt' returns EOF, this is the index of the first of the
+ non-option elements that the caller should itself scan.
+
+ Otherwise, `optind' communicates from one call to the next
+ how much of ARGV has been scanned so far. */
+
+extern int optind;
+
+/* Callers store zero here to inhibit the error message `getopt' prints
+ for unrecognized options. */
+
+extern int opterr;
+
+/* Set to an option character which was unrecognized. */
+
+extern int optopt;
+
+/* Describe the long-named options requested by the application.
+ The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector
+ of `struct option' terminated by an element containing a name which is
+ zero.
+
+ The field `has_arg' is:
+ no_argument (or 0) if the option does not take an argument,
+ required_argument (or 1) if the option requires an argument,
+ optional_argument (or 2) if the option takes an optional argument.
+
+ If the field `flag' is not NULL, it points to a variable that is set
+ to the value given in the field `val' when the option is found, but
+ left unchanged if the option is not found.
+
+ To have a long-named option do something other than set an `int' to
+ a compiled-in constant, such as set a value from `optarg', set the
+ option's `flag' field to zero and its `val' field to a nonzero
+ value (the equivalent single-letter option character, if there is
+ one). For long options that have a zero `flag' field, `getopt'
+ returns the contents of the `val' field. */
+
+struct option
+{
+#if __STDC__
+ const char *name;
+#else
+ char *name;
+#endif
+ /* has_arg can't be an enum because some compilers complain about
+ type mismatches in all the code that assumes it is an int. */
+ int has_arg;
+ int *flag;
+ int val;
+};
+
+/* Names for the values of the `has_arg' field of `struct option'. */
+
+#define no_argument 0
+#define required_argument 1
+#define optional_argument 2
+
+#if __STDC__
+#if defined(__GNU_LIBRARY__)
+/* Many other libraries have conflicting prototypes for getopt, with
+ differences in the consts, in stdlib.h. To avoid compilation
+ errors, only prototype getopt for the GNU C library. */
+extern int getopt (int argc, char *const *argv, const char *shortopts);
+#else /* not __GNU_LIBRARY__ */
+extern int getopt ();
+#endif /* not __GNU_LIBRARY__ */
+extern int getopt_long (int argc, char *const *argv, const char *shortopts,
+ const struct option *longopts, int *longind);
+extern int getopt_long_only (int argc, char *const *argv,
+ const char *shortopts,
+ const struct option *longopts, int *longind);
+
+/* Internal only. Users should not call this directly. */
+extern int _getopt_internal (int argc, char *const *argv,
+ const char *shortopts,
+ const struct option *longopts, int *longind,
+ int long_only);
+#else /* not __STDC__ */
+extern int getopt ();
+extern int getopt_long ();
+extern int getopt_long_only ();
+
+extern int _getopt_internal ();
+#endif /* not __STDC__ */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _GETOPT_H */
diff --git a/gnu/usr.bin/patch/getopt1.c b/gnu/usr.bin/patch/getopt1.c
new file mode 100644
index 0000000..a32615c
--- /dev/null
+++ b/gnu/usr.bin/patch/getopt1.c
@@ -0,0 +1,176 @@
+/* getopt_long and getopt_long_only entry points for GNU getopt.
+ Copyright (C) 1987, 88, 89, 90, 91, 92, 1993
+ Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any
+ later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "getopt.h"
+
+#if !__STDC__ && !defined(const) && IN_GCC
+#define const
+#endif
+
+#include <stdio.h>
+
+/* Comment out all this code if we are using the GNU C Library, and are not
+ actually compiling the library itself. This code is part of the GNU C
+ Library, but also included in many other GNU distributions. Compiling
+ and linking in this code is a waste when using the GNU C library
+ (especially if it is a shared library). Rather than having every GNU
+ program understand `configure --with-gnu-libc' and omit the object files,
+ it is simpler to just do this in the source for each such file. */
+
+#if defined (_LIBC) || !defined (__GNU_LIBRARY__)
+
+
+/* This needs to come after some library #include
+ to get __GNU_LIBRARY__ defined. */
+#ifdef __GNU_LIBRARY__
+#include <stdlib.h>
+#else
+char *getenv ();
+#endif
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+int
+getopt_long (argc, argv, options, long_options, opt_index)
+ int argc;
+ char *const *argv;
+ const char *options;
+ const struct option *long_options;
+ int *opt_index;
+{
+ return _getopt_internal (argc, argv, options, long_options, opt_index, 0);
+}
+
+/* Like getopt_long, but '-' as well as '--' can indicate a long option.
+ If an option that starts with '-' (not '--') doesn't match a long option,
+ but does match a short option, it is parsed as a short option
+ instead. */
+
+int
+getopt_long_only (argc, argv, options, long_options, opt_index)
+ int argc;
+ char *const *argv;
+ const char *options;
+ const struct option *long_options;
+ int *opt_index;
+{
+ return _getopt_internal (argc, argv, options, long_options, opt_index, 1);
+}
+
+
+#endif /* _LIBC or not __GNU_LIBRARY__. */
+
+#ifdef TEST
+
+#include <stdio.h>
+
+int
+main (argc, argv)
+ int argc;
+ char **argv;
+{
+ int c;
+ int digit_optind = 0;
+
+ while (1)
+ {
+ int this_option_optind = optind ? optind : 1;
+ int option_index = 0;
+ static struct option long_options[] =
+ {
+ {"add", 1, 0, 0},
+ {"append", 0, 0, 0},
+ {"delete", 1, 0, 0},
+ {"verbose", 0, 0, 0},
+ {"create", 0, 0, 0},
+ {"file", 1, 0, 0},
+ {0, 0, 0, 0}
+ };
+
+ c = getopt_long (argc, argv, "abc:d:0123456789",
+ long_options, &option_index);
+ if (c == EOF)
+ break;
+
+ switch (c)
+ {
+ case 0:
+ printf ("option %s", long_options[option_index].name);
+ if (optarg)
+ printf (" with arg %s", optarg);
+ printf ("\n");
+ break;
+
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ if (digit_optind != 0 && digit_optind != this_option_optind)
+ printf ("digits occur in two different argv-elements.\n");
+ digit_optind = this_option_optind;
+ printf ("option %c\n", c);
+ break;
+
+ case 'a':
+ printf ("option a\n");
+ break;
+
+ case 'b':
+ printf ("option b\n");
+ break;
+
+ case 'c':
+ printf ("option c with value `%s'\n", optarg);
+ break;
+
+ case 'd':
+ printf ("option d with value `%s'\n", optarg);
+ break;
+
+ case '?':
+ break;
+
+ default:
+ printf ("?? getopt returned character code 0%o ??\n", c);
+ }
+ }
+
+ if (optind < argc)
+ {
+ printf ("non-option ARGV-elements: ");
+ while (optind < argc)
+ printf ("%s ", argv[optind++]);
+ printf ("\n");
+ }
+
+ exit (0);
+}
+
+#endif /* TEST */
diff --git a/gnu/usr.bin/patch/inp.c b/gnu/usr.bin/patch/inp.c
new file mode 100644
index 0000000..e8e1531
--- /dev/null
+++ b/gnu/usr.bin/patch/inp.c
@@ -0,0 +1,382 @@
+/* $Header: /home/ncvs/src/gnu/usr.bin/patch/inp.c,v 1.2 1995/01/12 22:09:39 hsu Exp $
+ *
+ * $Log: inp.c,v $
+ * Revision 1.2 1995/01/12 22:09:39 hsu
+ * Fix bug that created new files even when running in -C check mode.
+ * Reviewed by: phk
+ *
+ * Revision 1.1.1.1 1993/06/19 14:21:52 paul
+ * b-maked patch-2.10
+ *
+ * Revision 2.0.1.1 88/06/03 15:06:13 lwall
+ * patch10: made a little smarter about sccs files
+ *
+ * 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, statfailed;
+ Reg1 char *s;
+ Reg2 LINENUM iline;
+ char lbuf[MAXLINELEN];
+ int output_elsewhere = strcmp(filename, outname);
+ extern int check_patch;
+
+ statfailed = stat(filename, &filestat);
+ if (statfailed && ok_to_create_file) {
+ if (verbose)
+ say2("(Creating file %s...)\n",filename);
+ if (check_patch)
+ return TRUE;
+ makedirs(filename, TRUE);
+ close(creat(filename, 0666));
+ statfailed = stat(filename, &filestat);
+ }
+ if (statfailed && check_patch) {
+ fatal2("%s not found and in check_patch mode.", filename);
+ }
+ /* For nonexistent or read-only files, look for RCS or SCCS versions. */
+ if (statfailed
+ || (! output_elsewhere
+ && (/* No one can write to it. */
+ (filestat.st_mode & 0222) == 0
+ /* I can't write to it. */
+ || ((filestat.st_mode & 0022) == 0
+ && filestat.st_uid != myuid)))) {
+ struct stat cstat;
+ char *cs = Nullch;
+ char *filebase;
+ int pathlen;
+
+ filebase = basename(filename);
+ pathlen = filebase - filename;
+
+ /* Put any leading path into `s'.
+ Leave room in lbuf for the diff command. */
+ s = lbuf + 20;
+ strncpy(s, filename, pathlen);
+
+#define try(f,a1,a2) (Sprintf(s + pathlen, f, a1, a2), stat(s, &cstat) == 0)
+ if (( try("RCS/%s%s", filebase, RCSSUFFIX)
+ || try("RCS/%s" , filebase, 0)
+ || try( "%s%s", filebase, RCSSUFFIX))
+ &&
+ /* Check that RCS file is not working file.
+ Some hosts don't report file name length errors. */
+ (statfailed
+ || ( (filestat.st_dev ^ cstat.st_dev)
+ | (filestat.st_ino ^ cstat.st_ino)))) {
+ Sprintf(buf, output_elsewhere?CHECKOUT:CHECKOUT_LOCKED, filename);
+ Sprintf(lbuf, RCSDIFF, filename);
+ cs = "RCS";
+ } else if ( try("SCCS/%s%s", SCCSPREFIX, filebase)
+ || try( "%s%s", SCCSPREFIX, filebase)) {
+ Sprintf(buf, output_elsewhere?GET:GET_LOCKED, s);
+ Sprintf(lbuf, SCCSDIFF, s, filename);
+ cs = "SCCS";
+ } else if (statfailed)
+ fatal2("can't find %s\n", filename);
+ /* else we can't write to it but it's not under a version
+ control system, so just proceed. */
+ if (cs) {
+ if (!statfailed) {
+ if ((filestat.st_mode & 0222) != 0)
+ /* The owner can write to it. */
+ fatal3("file %s seems to be locked by somebody else under %s\n",
+ filename, cs);
+ /* It might be checked out unlocked. See if it's safe to
+ check out the default version locked. */
+ if (verbose)
+ say3("Comparing file %s to default %s version...\n",
+ filename, cs);
+ if (system(lbuf))
+ fatal3("can't check out file %s: differs from default %s version\n",
+ filename, cs);
+ }
+ if (verbose)
+ say3("Checking out file %s from %s...\n", filename, cs);
+ if (system(buf) || stat(filename, &filestat))
+ fatal3("can't check out file %s from %s\n", filename, cs);
+ }
+ }
+ filemode = filestat.st_mode;
+ if (!S_ISREG(filemode))
+ 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)
+ pfatal2("can't open file %s", 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 if (batch) {
+ fatal2(
+"this file doesn't appear to be the %s version--aborting.\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)
+ pfatal2("can't open file %s", filename);
+ if ((tifd = creat(TMPINNAME, 0666)) < 0)
+ pfatal2("can't open file %s", 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 if (batch) {
+ fatal2(
+"this file doesn't appear to be the %s version--aborting.\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("out of memory\n");
+ for (i=1; ; i++) {
+ if (! (i % lines_per_buf)) /* new block */
+ if (write(tifd, tibuf[0], BUFFERSIZE) < BUFFERSIZE)
+ pfatal1("can't write temp file");
+ 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)
+ pfatal1("can't write temp file");
+ break;
+ }
+ }
+ Fclose(ifp);
+ Close(tifd);
+ if ((tifd = open(TMPINNAME, 0)) < 0) {
+ pfatal2("can't reopen file %s", 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, (long)baseline / lines_per_buf * BUFFERSIZE, 0);
+#endif
+ if (read(tifd, tibuf[whichbuf], BUFFERSIZE) < 0)
+ pfatal2("error reading tmp file %s", 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);
+ if (strnEQ(string,revision,patlen) && isspace(string[patlen]))
+ return TRUE;
+ for (s = string; *s; s++) {
+ if (isspace(*s) && strnEQ(s+1, revision, patlen) &&
+ isspace(s[patlen+1] )) {
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
diff --git a/gnu/usr.bin/patch/inp.h b/gnu/usr.bin/patch/inp.h
new file mode 100644
index 0000000..ea07ee8
--- /dev/null
+++ b/gnu/usr.bin/patch/inp.h
@@ -0,0 +1,21 @@
+/* $Header: /home/ncvs/src/gnu/usr.bin/patch/inp.h,v 1.1.1.1 1993/06/19 14:21:52 paul Exp $
+ *
+ * $Log: inp.h,v $
+ * Revision 1.1.1.1 1993/06/19 14:21:52 paul
+ * b-maked patch-2.10
+ *
+ * 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/gnu/usr.bin/patch/patch.1 b/gnu/usr.bin/patch/patch.1
new file mode 100644
index 0000000..6eec2b4
--- /dev/null
+++ b/gnu/usr.bin/patch/patch.1
@@ -0,0 +1,587 @@
+.\" -*- nroff -*-
+.rn '' }`
+'\" $Header: /home/ncvs/src/gnu/usr.bin/patch/patch.1,v 1.4 1994/02/25 21:45:59 phk Exp $
+'\"
+'\" $Log: patch.1,v $
+'\" Revision 1.4 1994/02/25 21:45:59 phk
+'\" added the -C/-check again.
+'\"
+.\" Revision 1.3 1994/02/17 22:20:33 jkh
+.\" Put this back - I was somehow under the erroneous impression that patch was in
+.\" ports, until I saw the the commit messages, that is! :-) All changed backed out.
+.\"
+.\" Revision 1.2 1994/02/17 22:16:02 jkh
+.\" From Poul-Henning Kamp - Implement a -C option to verify the integrity of
+.\" a patch before actually applying it.
+.\"
+.\" Revision 1.1.1.1 1993/06/19 14:21:51 paul
+.\" b-maked patch-2.10
+.\"
+'\" Revision 2.0.1.2 88/06/22 20:47:18 lwall
+'\" patch12: now avoids Bell System Logo
+'\"
+'\" Revision 2.0.1.1 88/06/03 15:12:51 lwall
+'\" patch10: -B switch was contributed.
+'\"
+'\" 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 \(*W-\*(Tr
+.ds -- \(*W-
+.if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch
+.if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\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 LOCAL
+.SH NAME
+patch - apply a diff file to an original
+.SH SYNOPSIS
+.B patch
+[options] [origfile [patchfile]] [+ [options] [origfile]]...
+.sp
+but usually just
+.sp
+.B patch
+<patchfile
+.SH DESCRIPTION
+.I Patch
+will take a patch file containing any of the four 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" (\*(L"~\*(R" on systems that do not
+support long file names), or as specified by the
+\fB\-b\fP (\fB\-\-suffix\fP),
+\fB\-B\fP (\fB\-\-prefix\fP),
+or
+\fB\-V\fP (\fB\-\-version\-control\fP)
+options.
+The extension used for making backup files may also be specified in the
+.B SIMPLE_BACKUP_SUFFIX
+environment variable, which is overridden by the above options.
+.PP
+If the backup file already exists,
+.B patch
+creates a new backup file name by changing the first lowercase letter
+in the last component of the file's name into uppercase. If there are
+no more lowercase letters in the name, it removes the first character
+from the name. It repeats this process until it comes up with a
+backup file that does not already exist.
+.PP
+You may also specify where you want the output to go with a
+\fB\-o\fP (\fB\-\-output\fP)
+option; if that file already exists, it is backed up first.
+.PP
+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
+\fB\-c\fP (\fB\-\-context\fP),
+\fB\-e\fP (\fB\-\-ed\fP),
+\fB\-n\fP (\fB\-\-normal\fP),
+or
+\fB\-u\fP (\fB\-\-unified\fP)
+option.
+Context diffs (old-style, new-style, and unified) and
+normal diffs are applied by the
+.I patch
+program itself, while
+.I 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" (\*(L"#\*(R" on systems that do not support
+long file names).
+(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 file name 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 file name from that line.
+The Index line, if present, takes precedence over the context diff header.
+If no file name 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 or is read-only, 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 file names and revision level, as
+mentioned previously.
+You can give options (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 options:
+.TP 5
+.B "\-b suff, \-\-suffix=suff"
+causes
+.B suff
+to be interpreted as the backup extension, to be
+used in place of \*(L".orig\*(R" or \*(L"~\*(R".
+.TP 5
+.B "\-B pref, \-\-prefix=pref"
+causes
+.B pref
+to be interpreted as a prefix to the backup file
+name. If this argument is specified, any argument from
+.B \-b
+will be ignored.
+.TP 5
+.B "\-c, \-\-context"
+forces
+.I patch
+to interpret the patch file as a context diff.
+.TP 5
+.B "\-C, \-\-check"
+see what would happen, but don't do it.
+.TP 5
+.B "\-d dir, \-\-directory=dir"
+causes
+.I patch
+to interpret
+.B dir
+as a directory, and cd to it before doing
+anything else.
+.TP 5
+.B "\-D sym, \-\-ifdef=sym"
+causes
+.I patch
+to use the "#ifdef...#endif" construct to mark changes.
+.B sym
+will be used as the differentiating symbol.
+.TP 5
+.B "\-e, \-\-ed"
+forces
+.I patch
+to interpret the patch file as an
+.I ed
+script.
+.TP 5
+.B "\-E, \-\-remove\-empty\-files"
+causes
+.I patch
+to remove output files that are empty after the patches have been applied.
+.TP 5
+.B "\-f, \-\-force"
+forces
+.I patch
+to assume that the user knows exactly what he or she is doing, and to not
+ask any questions. It assumes the following: skip patches for which a
+file to patch can't be found; patch files even though they have the
+wrong version for the ``Prereq:'' line in the patch; and assume that
+patches are not reversed even if they look like they are.
+This option does not suppress commentary; use
+.B \-s
+for that.
+.TP 5
+.B "\-t, \-\-batch"
+similar to
+.BR \-f ,
+in that it suppresses questions, but makes some different assumptions:
+skip patches for which a file to patch can't be found (the same as \fB\-f\fP);
+skip patches for which the file has the wrong version for the ``Prereq:'' line
+in the patch; and assume that patches are reversed if they look like
+they are.
+.TP 5
+.B "\-F number, \-\-fuzz=number"
+sets the maximum fuzz factor.
+This option only applies 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, \-\-ignore\-whitespace"
+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, \-\-normal"
+forces
+.I patch
+to interpret the patch file as a normal diff.
+.TP 5
+.B "\-N, \-\-forward"
+causes
+.I patch
+to ignore patches that it thinks are reversed or already applied.
+See also
+.B \-R .
+.TP 5
+.B "\-o file, \-\-output=file"
+causes
+.B file
+to be interpreted as the output file name.
+.TP 5
+.B "\-p[number], \-\-strip[=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 slashes are to be stripped from
+the front of the pathname.
+(Any intervening directory names also go away.)
+For example, supposing the file name 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", unless all of the directories in the
+leading path (u/howard/src/blurfl) exist and that path is relative,
+in which case you get the entire pathname unmodified.
+Whatever you end up with is looked for either in the current directory,
+or the directory specified by the
+.B \-d
+option.
+.TP 5
+.B "\-r file, \-\-reject\-file=file"
+causes
+.B file
+to be interpreted as the reject file name.
+.TP 5
+.B "\-R, \-\-reverse"
+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
+option will not work with
+.I 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
+option 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, \-\-silent, \-\-quiet"
+makes
+.I patch
+do its work silently, unless an error occurs.
+.TP 5
+.B "\-S, \-\-skip"
+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 "\-u, \-\-unified"
+forces
+.I patch
+to interpret the patch file as a unified context diff (a unidiff).
+.TP 5
+.B "\-v, \-\-version"
+causes
+.I patch
+to print out its revision header and patch level.
+.TP 5
+.B "\-V method, \-\-version\-\-control=method"
+causes
+.B method
+to be interpreted as a method for creating
+backup file names. The type of backups made can also be given in the
+.B VERSION_CONTROL
+environment variable, which is overridden by this option.
+The
+.B -B
+option overrides this option, causing the prefix to always be used for
+making backup file names.
+The value of the
+.B VERSION_CONTROL
+environment variable and the argument to the
+.B -V
+option are like the GNU
+Emacs `version-control' variable; they also recognize synonyms that
+are more descriptive. The valid values are (unique abbreviations are
+accepted):
+.RS
+.TP
+`t' or `numbered'
+Always make numbered backups.
+.TP
+`nil' or `existing'
+Make numbered backups of files that already
+have them, simple backups of the others.
+This is the default.
+.TP
+`never' or `simple'
+Always make simple backups.
+.RE
+.TP 5
+.B "\-x number, \-\-debug=number"
+sets internal debugging flags, and is of interest only to
+.I patch
+patchers.
+.SH AUTHOR
+Larry Wall <lwall@netlabs.com>
+.br
+with many other contributors.
+.SH ENVIRONMENT
+.TP
+.B TMPDIR
+Directory to put temporary files in; default is /tmp.
+.TP
+.B SIMPLE_BACKUP_SUFFIX
+Extension to use for backup file names instead of \*(L".orig\*(R" or
+\*(L"~\*(R".
+.TP
+.B VERSION_CONTROL
+Selects when numbered backup files are made.
+.SH FILES
+$TMPDIR/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 file names 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
+option 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.
+.PP
+.I Patch
+will exit with a non-zero status if any reject files were created.
+When applying a set of patches in a loop it behooves you to check this
+exit status so you don't apply a later patch to a partially patched file.
+.SH CAVEATS
+.I Patch
+cannot tell if the line numbers are off in an
+.I 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.
+.rn }` ''
diff --git a/gnu/usr.bin/patch/patch.c b/gnu/usr.bin/patch/patch.c
new file mode 100644
index 0000000..b03d065
--- /dev/null
+++ b/gnu/usr.bin/patch/patch.c
@@ -0,0 +1,974 @@
+char rcsid[] =
+ "$Header: /home/ncvs/src/gnu/usr.bin/patch/patch.c,v 1.5 1995/01/12 22:09:40 hsu 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 1.5 1995/01/12 22:09:40 hsu
+ * Fix bug that created new files even when running in -C check mode.
+ * Reviewed by: phk
+ *
+ * Revision 1.4 1994/02/25 21:46:04 phk
+ * added the -C/-check again.
+ *
+ * Revision 1.3 1994/02/17 22:20:34 jkh
+ * Put this back - I was somehow under the erroneous impression that patch was in
+ * ports, until I saw the the commit messages, that is! :-) All changed backed out.
+ *
+ * Revision 1.2 1994/02/17 22:16:03 jkh
+ * From Poul-Henning Kamp - Implement a -C option to verify the integrity of
+ * a patch before actually applying it.
+ *
+ * Revision 1.1.1.1 1993/06/19 14:21:52 paul
+ * b-maked patch-2.10
+ *
+ * Revision 2.0.2.0 90/05/01 22:17:50 davison
+ * patch12u: unidiff support added
+ *
+ * Revision 2.0.1.6 88/06/22 20:46:39 lwall
+ * patch12: rindex() wasn't declared
+ *
+ * Revision 2.0.1.5 88/06/03 15:09:37 lwall
+ * patch10: exit code improved.
+ * patch10: better support for non-flexfilenames.
+ *
+ * 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"
+#include "backupfile.h"
+#include "getopt.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();
+
+/* TRUE if -E was specified on command line. */
+static int remove_empty_files = FALSE;
+
+/* TRUE if -R was specified on command line. */
+static int reverse_flag_specified = FALSE;
+
+/* TRUE if -C was specified on command line. */
+int check_patch = FALSE;
+
+/* Apply a set of diffs as appropriate. */
+
+int
+main(argc,argv)
+int argc;
+char **argv;
+{
+ LINENUM where;
+ LINENUM newwhere;
+ LINENUM fuzz;
+ LINENUM mymaxfuzz;
+ int hunk = 0;
+ int failed = 0;
+ int failtotal = 0;
+ bool rev_okayed = 0;
+ int i;
+
+ setbuf(stderr, serrbuf);
+ for (i = 0; i<MAXFILEC; i++)
+ filearg[i] = Nullch;
+
+ myuid = getuid();
+
+ /* Cons up the names of the temporary files. */
+ {
+ /* Directory for temporary files. */
+ char *tmpdir;
+ int tmpname_len;
+
+ tmpdir = getenv ("TMPDIR");
+ if (tmpdir == NULL) {
+ tmpdir = "/tmp";
+ }
+ tmpname_len = strlen (tmpdir) + 20;
+
+ TMPOUTNAME = (char *) malloc (tmpname_len);
+ strcpy (TMPOUTNAME, tmpdir);
+ strcat (TMPOUTNAME, "/patchoXXXXXX");
+ Mktemp(TMPOUTNAME);
+
+ TMPINNAME = (char *) malloc (tmpname_len);
+ strcpy (TMPINNAME, tmpdir);
+ strcat (TMPINNAME, "/patchiXXXXXX");
+ Mktemp(TMPINNAME);
+
+ TMPREJNAME = (char *) malloc (tmpname_len);
+ strcpy (TMPREJNAME, tmpdir);
+ strcat (TMPREJNAME, "/patchrXXXXXX");
+ Mktemp(TMPREJNAME);
+
+ TMPPATNAME = (char *) malloc (tmpname_len);
+ strcpy (TMPPATNAME, tmpdir);
+ strcat (TMPPATNAME, "/patchpXXXXXX");
+ Mktemp(TMPPATNAME);
+ }
+
+ {
+ char *v;
+
+ v = getenv ("SIMPLE_BACKUP_SUFFIX");
+ if (v)
+ simple_backup_suffix = v;
+ else
+ simple_backup_suffix = ".orig";
+#ifndef NODIR
+ v = getenv ("VERSION_CONTROL");
+ backup_type = get_version (v); /* OK to pass NULL. */
+#endif
+ }
+
+ /* parse switches */
+ Argc = argc;
+ Argv = argv;
+ get_some_switches();
+
+ /* make sure we clean up /tmp in case of disaster */
+ set_signals(0);
+
+ 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]);
+
+ /* for ed script just up and do it and exit */
+ if (diff_type == ED_DIFF) {
+ do_ed_script();
+ continue;
+ }
+
+ /* initialize the patched file */
+ if (!skip_rest_of_patch)
+ init_output(TMPOUTNAME);
+
+ /* 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;
+ rev_okayed = FALSE;
+ 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|rev_okayed)) {
+ /* 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 if (batch) {
+ if (verbose)
+ say3(
+"%seversed (or previously applied) patch detected! %s -R.",
+ reverse ? "R" : "Unr",
+ reverse ? "Assuming" : "Ignoring");
+ }
+ 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')
+ rev_okayed = TRUE;
+ else
+ 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) {
+ optind = optind_last;
+ say1("\n\nRan out of memory using Plan A--trying again...\n\n");
+ if (ofp)
+ Fclose(ofp);
+ ofp = Nullfp;
+ if (rejfp)
+ Fclose(rejfp);
+ rejfp = Nullfp;
+ 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) {
+ struct stat statbuf;
+ char *realout = outname;
+
+ if (check_patch) {
+ ;
+ } else if (move_file(TMPOUTNAME, outname) < 0) {
+ toutkeep = TRUE;
+ realout = TMPOUTNAME;
+ chmod(TMPOUTNAME, filemode);
+ }
+ else
+ chmod(outname, filemode);
+
+ if (remove_empty_files && stat(realout, &statbuf) == 0
+ && statbuf.st_size == 0) {
+ if (verbose)
+ say2("Removing %s (empty after patching).\n", realout);
+ while (unlink(realout) >= 0) ; /* while is for Eunice. */
+ }
+ }
+ Fclose(rejfp);
+ rejfp = Nullfp;
+ if (failed) {
+ failtotal += failed;
+ if (!*rejname) {
+ Strcpy(rejname, outname);
+ addext(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 (check_patch) {
+ ;
+ } else if (move_file(TMPREJNAME, rejname) < 0)
+ trejkeep = TRUE;
+ }
+ set_signals(1);
+ }
+ my_exit(failtotal);
+}
+
+/* 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 = reverse_flag_specified;
+ skip_rest_of_patch = FALSE;
+
+ get_some_switches();
+
+ if (filec >= 2)
+ fatal1("you may not change to a different patch file\n");
+}
+
+static char *shortopts = "-b:B:cCd:D:eEfF:lnNo:p::r:RsStuvV:x:";
+static struct option longopts[] =
+{
+ {"suffix", 1, NULL, 'b'},
+ {"prefix", 1, NULL, 'B'},
+ {"check", 0, NULL, 'C'},
+ {"context", 0, NULL, 'c'},
+ {"directory", 1, NULL, 'd'},
+ {"ifdef", 1, NULL, 'D'},
+ {"ed", 0, NULL, 'e'},
+ {"remove-empty-files", 0, NULL, 'E'},
+ {"force", 0, NULL, 'f'},
+ {"fuzz", 1, NULL, 'F'},
+ {"ignore-whitespace", 0, NULL, 'l'},
+ {"normal", 0, NULL, 'n'},
+ {"forward", 0, NULL, 'N'},
+ {"output", 1, NULL, 'o'},
+ {"strip", 2, NULL, 'p'},
+ {"reject-file", 1, NULL, 'r'},
+ {"reverse", 0, NULL, 'R'},
+ {"quiet", 0, NULL, 's'},
+ {"silent", 0, NULL, 's'},
+ {"skip", 0, NULL, 'S'},
+ {"batch", 0, NULL, 't'},
+ {"unified", 0, NULL, 'u'},
+ {"version", 0, NULL, 'v'},
+ {"version-control", 1, NULL, 'V'},
+ {"debug", 1, NULL, 'x'},
+ {0, 0, 0, 0}
+};
+
+/* Process switches and filenames up to next '+' or end of list. */
+
+void
+get_some_switches()
+{
+ Reg1 int optc;
+
+ rejname[0] = '\0';
+ optind_last = optind;
+ if (optind == Argc)
+ return;
+ while ((optc = getopt_long (Argc, Argv, shortopts, longopts, (int *) 0))
+ != -1) {
+ if (optc == 1) {
+ if (strEQ(optarg, "+"))
+ return;
+ if (filec == MAXFILEC)
+ fatal1("too many file arguments\n");
+ filearg[filec++] = savestr(optarg);
+ }
+ else {
+ switch (optc) {
+ case 'b':
+ simple_backup_suffix = savestr(optarg);
+ break;
+ case 'B':
+ origprae = savestr(optarg);
+ break;
+ case 'c':
+ diff_type = CONTEXT_DIFF;
+ break;
+ case 'C':
+ check_patch = TRUE;
+ break;
+ case 'd':
+ if (chdir(optarg) < 0)
+ pfatal2("can't cd to %s", optarg);
+ break;
+ case 'D':
+ do_defines = TRUE;
+ if (!isalpha(*optarg) && '_' != *optarg)
+ fatal1("argument to -D is not an identifier\n");
+ Sprintf(if_defined, "#ifdef %s\n", optarg);
+ Sprintf(not_defined, "#ifndef %s\n", optarg);
+ Sprintf(end_defined, "#endif /* %s */\n", optarg);
+ break;
+ case 'e':
+ diff_type = ED_DIFF;
+ break;
+ case 'E':
+ remove_empty_files = TRUE;
+ break;
+ case 'f':
+ force = TRUE;
+ break;
+ case 'F':
+ maxfuzz = atoi(optarg);
+ break;
+ case 'l':
+ canonicalize = TRUE;
+ break;
+ case 'n':
+ diff_type = NORMAL_DIFF;
+ break;
+ case 'N':
+ noreverse = TRUE;
+ break;
+ case 'o':
+ outname = savestr(optarg);
+ break;
+ case 'p':
+ if (optarg)
+ strippath = atoi(optarg);
+ else
+ strippath = 0;
+ break;
+ case 'r':
+ Strcpy(rejname, optarg);
+ break;
+ case 'R':
+ reverse = TRUE;
+ reverse_flag_specified = TRUE;
+ break;
+ case 's':
+ verbose = FALSE;
+ break;
+ case 'S':
+ skip_rest_of_patch = TRUE;
+ break;
+ case 't':
+ batch = TRUE;
+ break;
+ case 'u':
+ diff_type = UNI_DIFF;
+ break;
+ case 'v':
+ version();
+ break;
+ case 'V':
+#ifndef NODIR
+ backup_type = get_version (optarg);
+#endif
+ break;
+#ifdef DEBUGGING
+ case 'x':
+ debug = atoi(optarg);
+ break;
+#endif
+ default:
+ fprintf(stderr, "\
+Usage: %s [options] [origfile [patchfile]] [+ [options] [origfile]]...\n",
+ Argv[0]);
+ fprintf(stderr, "\
+Options:\n\
+ [-cCeEflnNRsStuv] [-b backup-ext] [-B backup-prefix] [-d directory]\n\
+ [-D symbol] [-F max-fuzz] [-o out-file] [-p[strip-count]]\n\
+ [-r rej-name] [-V {numbered,existing,simple}] [--check] [--context]\n\
+ [--prefix=backup-prefix] [--suffix=backup-ext] [--ifdef=symbol]\n\
+ [--directory=directory] [--ed] [--fuzz=max-fuzz] [--force] [--batch]\n\
+ [--ignore-whitespace] [--forward] [--reverse] [--output=out-file]\n");
+ fprintf(stderr, "\
+ [--strip[=strip-count]] [--normal] [--reject-file=rej-name] [--skip]\n\
+ [--remove-empty-files] [--quiet] [--silent] [--unified] [--version]\n\
+ [--version-control={numbered,existing,simple}]\n");
+ my_exit(1);
+ }
+ }
+ }
+
+ /* Process any filename args given after "--". */
+ for (; optind < Argc; ++optind) {
+ if (filec == MAXFILEC)
+ fatal1("too many file arguments\n");
+ filearg[filec++] = savestr(Argv[optind]);
+ }
+}
+
+/* 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:
+ fatal1("fatal internal error in abort_hunk\n");
+ }
+ }
+}
+
+/* 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);
+ }
+ else 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++;
+ }
+ }
+ else {
+ assert(pch_char(new) == ' ');
+ old++;
+ new++;
+ if (R_do_defines && def_state != OUTSIDE) {
+ fputs(end_defined, ofp);
+ def_state = OUTSIDE;
+ }
+ }
+ }
+ 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)
+ pfatal2("can't create %s", name);
+}
+
+/* Open a file to put hunks we can't locate. */
+
+void
+init_reject(name)
+char *name;
+{
+ rejfp = fopen(name, "w");
+ if (rejfp == Nullfp)
+ pfatal2("can't create %s", 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)
+ fatal1("misordered hunks! output would 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/gnu/usr.bin/patch/patchlevel.h b/gnu/usr.bin/patch/patchlevel.h
new file mode 100644
index 0000000..d5de3a9
--- /dev/null
+++ b/gnu/usr.bin/patch/patchlevel.h
@@ -0,0 +1 @@
+#define PATCH_VERSION "2.1"
diff --git a/gnu/usr.bin/patch/pch.c b/gnu/usr.bin/patch/pch.c
new file mode 100644
index 0000000..0a40bfa
--- /dev/null
+++ b/gnu/usr.bin/patch/pch.c
@@ -0,0 +1,1323 @@
+/* $Header: /home/ncvs/src/gnu/usr.bin/patch/pch.c,v 1.5 1995/05/30 05:02:35 rgrimes Exp $
+ *
+ * $Log: pch.c,v $
+ * Revision 1.5 1995/05/30 05:02:35 rgrimes
+ * Remove trailing whitespace.
+ *
+ * Revision 1.4 1994/02/25 21:46:07 phk
+ * added the -C/-check again.
+ *
+ * Revision 1.3 1994/02/17 22:20:36 jkh
+ * Put this back - I was somehow under the erroneous impression that patch was in
+ * ports, until I saw the the commit messages, that is! :-) All changed backed out.
+ *
+ * Revision 1.2 1994/02/17 22:16:05 jkh
+ * From Poul-Henning Kamp - Implement a -C option to verify the integrity of
+ * a patch before actually applying it.
+ *
+ * Revision 1.1.1.1 1993/06/19 14:21:52 paul
+ * b-maked patch-2.10
+ *
+ * Revision 2.0.2.0 90/05/01 22:17:51 davison
+ * patch12u: unidiff support added
+ *
+ * Revision 2.0.1.7 88/06/03 15:13:28 lwall
+ * patch10: Can now find patches in shar scripts.
+ * patch10: Hunks that swapped and then swapped back could core dump.
+ *
+ * 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)
+ pfatal2("can't create %s", TMPPATNAME);
+ while (fgets(buf, sizeof buf, stdin) != Nullch)
+ fputs(buf, pfp);
+ Fclose(pfp);
+ filename = TMPPATNAME;
+ }
+ pfp = fopen(filename, "r");
+ if (pfp == Nullfp)
+ pfatal2("patch file %s not found", 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("out of memory\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 == UNI_DIFF ? "a unified diff" :
+ 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 || batch) {
+ say1("No file to patch. Skipping...\n");
+ filearg[0] = savestr(bestguess);
+ skip_rest_of_patch = TRUE;
+ 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 == 'X'; 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, "+++ ", 4))
+ oldtmp = savestr(s+4); /* pretend it is the old name */
+ 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;
+ }
+ if ((!diff_type || diff_type == UNI_DIFF) && strnEQ(s, "@@ -", 4)) {
+ if (!atol(s+3))
+ ok_to_create_file = TRUE;
+ p_indent = indent;
+ p_start = this_line;
+ p_sline = p_input_line;
+ retval = UNI_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 (indname)
+ filearg[0] = savestr(indname);
+ else if (oldname)
+ filearg[0] = savestr(oldname);
+ else if (newname)
+ filearg[0] = savestr(newname);
+ }
+ 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;
+}
+
+/* Make this a function for better debugging. */
+static void
+malformed ()
+{
+ fatal3("malformed patch at line %ld: %s", p_input_line, buf);
+ /* about as informative as "Syntax error" in C */
+}
+
+/* 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;
+#ifdef zilog
+ p_line[(short)p_end] = Nullch;
+#else
+ p_line[p_end] = Nullch;
+#endif
+ 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)
+ malformed ();
+ if (strnEQ(s,"0,0",3))
+ strcpy(s,s+2);
+ p_first = (LINENUM) atol(s);
+ while (isdigit(*s)) s++;
+ if (*s == ',') {
+ for (; *s && !isdigit(*s); s++) ;
+ if (!*s)
+ 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)
+ malformed ();
+ p_newfirst = (LINENUM) atol(s);
+ while (isdigit(*s)) s++;
+ if (*s == ',') {
+ for (; *s && !isdigit(*s); s++) ;
+ if (!*s)
+ 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
+ && (p_context != 0 || p_repl_lines != 1))
+ repl_could_be_missing = FALSE;
+ break;
+ }
+ goto change_line;
+ case '+': case '!':
+ repl_could_be_missing = FALSE;
+ change_line:
+ if (buf[1] == '\n' && canonicalize)
+ strcpy(buf+1," \n");
+ 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;
+ }
+ 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 */
+ if (!p_context && p_repl_lines == 1) {
+ p_repl_lines = 0;
+ p_max--;
+ }
+ fillsrc = 1;
+ filldst = repl_beginning+1;
+ fillcnt = p_repl_lines;
+ p_end = p_max;
+ }
+ else if (!p_context && fillcnt == 1) {
+ /* the first hunk was a null hunk with no context */
+ /* and we were expecting one line -- fix it up. */
+ while (filldst < p_end) {
+ p_line[filldst] = p_line[filldst+1];
+ p_Char[filldst] = p_Char[filldst+1];
+ p_len[filldst] = p_len[filldst+1];
+ filldst++;
+ }
+#if 0
+ repl_beginning--; /* this doesn't need to be fixed */
+#endif
+ p_end--;
+ p_first++; /* do append rather than insert */
+ fillcnt = 0;
+ p_ptrn_lines = 0;
+ }
+
+ if (diff_type == CONTEXT_DIFF &&
+ (fillcnt || (p_first > 1 && ptrn_copiable > 2*p_context)) ) {
+ if (verbose)
+ say4("%s\n%s\n%s\n",
+"(Fascinating--this is really a new-style context diff but without",
+"the telltale extra asterisks on the *** line that usually indicate",
+"the new style...)");
+ 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 if (diff_type == UNI_DIFF) {
+ long line_beginning = ftell(pfp);
+ /* file pos of the current line */
+ Reg4 LINENUM fillsrc; /* index of old lines */
+ Reg5 LINENUM filldst; /* index of new lines */
+ char ch;
+
+ ret = pgets(buf, sizeof buf, pfp);
+ p_input_line++;
+ if (ret == Nullch || strnNE(buf, "@@ -", 4)) {
+ next_intuit_at(line_beginning,p_input_line);
+ return FALSE;
+ }
+ s = buf+4;
+ if (!*s)
+ malformed ();
+ p_first = (LINENUM) atol(s);
+ while (isdigit(*s)) s++;
+ if (*s == ',') {
+ p_ptrn_lines = (LINENUM) atol(++s);
+ while (isdigit(*s)) s++;
+ } else
+ p_ptrn_lines = 1;
+ if (*s == ' ') s++;
+ if (*s != '+' || !*++s)
+ malformed ();
+ p_newfirst = (LINENUM) atol(s);
+ while (isdigit(*s)) s++;
+ if (*s == ',') {
+ p_repl_lines = (LINENUM) atol(++s);
+ while (isdigit(*s)) s++;
+ } else
+ p_repl_lines = 1;
+ if (*s == ' ') s++;
+ if (*s != '@')
+ malformed ();
+ if (!p_ptrn_lines)
+ p_first++; /* do append rather than insert */
+ p_max = p_ptrn_lines + p_repl_lines + 1;
+ while (p_max >= hunkmax)
+ grow_hunkmax();
+ fillsrc = 1;
+ filldst = fillsrc + p_ptrn_lines;
+ p_end = filldst + p_repl_lines;
+ 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] = '*';
+ Sprintf(buf,"--- %ld,%ld ----\n",p_newfirst,p_newfirst+p_repl_lines-1);
+ p_line[filldst] = savestr(buf);
+ if (out_of_mem) {
+ p_end = 0;
+ return FALSE;
+ }
+ p_Char[filldst++] = '=';
+ p_context = 100;
+ context = 0;
+ p_hunk_beg = p_input_line + 1;
+ while (fillsrc <= p_ptrn_lines || filldst <= p_end) {
+ line_beginning = ftell(pfp);
+ ret = pgets(buf, sizeof buf, pfp);
+ p_input_line++;
+ if (ret == Nullch) {
+ if (p_max - filldst < 3)
+ Strcpy(buf, " \n"); /* assume blank lines got chopped */
+ else {
+ fatal1("unexpected end of file in patch\n");
+ }
+ }
+ if (*buf == '\t' || *buf == '\n') {
+ ch = ' '; /* assume the space got eaten */
+ s = savestr(buf);
+ }
+ else {
+ ch = *buf;
+ s = savestr(buf+1);
+ }
+ if (out_of_mem) {
+ while (--filldst > p_ptrn_lines)
+ free(p_line[filldst]);
+ p_end = fillsrc-1;
+ return FALSE;
+ }
+ switch (ch) {
+ case '-':
+ if (fillsrc > p_ptrn_lines) {
+ free(s);
+ p_end = filldst-1;
+ malformed ();
+ }
+ p_Char[fillsrc] = ch;
+ p_line[fillsrc] = s;
+ p_len[fillsrc++] = strlen(s);
+ break;
+ case '=':
+ ch = ' ';
+ /* FALL THROUGH */
+ case ' ':
+ if (fillsrc > p_ptrn_lines) {
+ free(s);
+ while (--filldst > p_ptrn_lines)
+ free(p_line[filldst]);
+ p_end = fillsrc-1;
+ malformed ();
+ }
+ context++;
+ p_Char[fillsrc] = ch;
+ p_line[fillsrc] = s;
+ p_len[fillsrc++] = strlen(s);
+ s = savestr(s);
+ if (out_of_mem) {
+ while (--filldst > p_ptrn_lines)
+ free(p_line[filldst]);
+ p_end = fillsrc-1;
+ return FALSE;
+ }
+ /* FALL THROUGH */
+ case '+':
+ if (filldst > p_end) {
+ free(s);
+ while (--filldst > p_ptrn_lines)
+ free(p_line[filldst]);
+ p_end = fillsrc-1;
+ malformed ();
+ }
+ p_Char[filldst] = ch;
+ p_line[filldst] = s;
+ p_len[filldst++] = strlen(s);
+ break;
+ default:
+ p_end = filldst;
+ malformed ();
+ }
+ if (ch != ' ' && context > 0) {
+ if (context < p_context)
+ p_context = context;
+ context = -1000;
+ }
+ }/* while */
+ }
+ 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;
+}
+
+/* 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 == 'X'); 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 */
+ if (p_efake <= i)
+ n = p_end - i + 1;
+ else
+ n = -i;
+ 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;
+
+ 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(1);
+}
diff --git a/gnu/usr.bin/patch/pch.h b/gnu/usr.bin/patch/pch.h
new file mode 100644
index 0000000..4967081
--- /dev/null
+++ b/gnu/usr.bin/patch/pch.h
@@ -0,0 +1,39 @@
+/* $Header: /home/ncvs/src/gnu/usr.bin/patch/pch.h,v 1.1.1.1 1993/06/19 14:21:52 paul Exp $
+ *
+ * $Log: pch.h,v $
+ * Revision 1.1.1.1 1993/06/19 14:21:52 paul
+ * b-maked patch-2.10
+ *
+ * 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/gnu/usr.bin/patch/util.c b/gnu/usr.bin/patch/util.c
new file mode 100644
index 0000000..56ce12e
--- /dev/null
+++ b/gnu/usr.bin/patch/util.c
@@ -0,0 +1,433 @@
+#include "EXTERN.h"
+#include "common.h"
+#include "INTERN.h"
+#include "util.h"
+#include "backupfile.h"
+
+void my_exit();
+
+#ifndef HAVE_STRERROR
+static char *
+private_strerror (errnum)
+ int errnum;
+{
+ extern char *sys_errlist[];
+ extern int sys_nerr;
+
+ if (errnum > 0 && errnum <= sys_nerr)
+ return sys_errlist[errnum];
+ return "Unknown system error";
+}
+#define strerror private_strerror
+#endif /* !HAVE_STRERROR */
+
+/* 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)
+ pfatal2("internal error, can't reopen %s", from);
+ while ((i=read(fromfd, buf, sizeof buf)) > 0)
+ if (write(1, buf, i) != 1)
+ pfatal1("write failed");
+ Close(fromfd);
+ return 0;
+ }
+
+ if (origprae) {
+ Strcpy(bakname, origprae);
+ Strcat(bakname, to);
+ } else {
+#ifndef NODIR
+ char *backupname = find_backup_file_name(to);
+ if (backupname == (char *) 0)
+ fatal1("out of memory\n");
+ Strcpy(bakname, backupname);
+ free(backupname);
+#else /* NODIR */
+ Strcpy(bakname, to);
+ Strcat(bakname, simple_backup_suffix);
+#endif /* NODIR */
+ }
+
+ 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.
+ Change the first lowercase char into uppercase;
+ if that isn't sufficient, chop off the first char and try again. */
+ while (stat(bakname, &filestat) == 0 &&
+ to_device == filestat.st_dev && to_inode == filestat.st_ino) {
+ /* Skip initial non-lowercase chars. */
+ 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 (rename(to, bakname) < 0) {
+ say4("Can't backup %s, output is in %s: %s\n", to, from,
+ strerror(errno));
+ return -1;
+ }
+ while (unlink(to) >= 0) ;
+ }
+#ifdef DEBUGGING
+ if (debug & 4)
+ say3("Moving %s to %s.\n", from, to);
+#endif
+ if (rename(from, to) < 0) { /* different file system? */
+ Reg4 int tofd;
+
+ tofd = creat(to, 0666);
+ if (tofd < 0) {
+ say4("Can't create %s, output is in %s: %s\n",
+ to, from, strerror(errno));
+ return -1;
+ }
+ fromfd = open(from, 0);
+ if (fromfd < 0)
+ pfatal2("internal error, can't reopen %s", from);
+ while ((i=read(fromfd, buf, sizeof buf)) > 0)
+ if (write(tofd, buf, i) != i)
+ pfatal1("write failed");
+ 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)
+ pfatal2("can't create %s", to);
+ fromfd = open(from, 0);
+ if (fromfd < 0)
+ pfatal2("internal error, can't reopen %s", from);
+ while ((i=read(fromfd, buf, sizeof buf)) > 0)
+ if (write(tofd, buf, i) != i)
+ pfatal2("write to %s failed", 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("out of memory\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*/
+pfatal(pat) char *pat; { ; }
+/*VARARGS ARGSUSED*/
+ask(pat) char *pat; { ; }
+
+#else
+
+/* Vanilla terminal output (buffered). */
+
+void
+say(pat,arg1,arg2,arg3)
+char *pat;
+long 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;
+long arg1,arg2,arg3;
+{
+ fprintf(stderr, "patch: **** ");
+ fprintf(stderr, pat, arg1, arg2, arg3);
+ my_exit(1);
+}
+
+/* Say something from patch, something from the system, then silence . . . */
+
+void /* very void */
+pfatal(pat,arg1,arg2,arg3)
+char *pat;
+long arg1,arg2,arg3;
+{
+ int errnum = errno;
+
+ fprintf(stderr, "patch: **** ");
+ fprintf(stderr, pat, arg1, arg2, arg3);
+ fprintf(stderr, ": %s\n", strerror(errnum));
+ my_exit(1);
+}
+
+/* Get a response from the user, somehow or other. */
+
+void
+ask(pat,arg1,arg2,arg3)
+char *pat;
+long 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(reset)
+int reset;
+{
+#ifndef lint
+ static RETSIGTYPE (*hupval)(),(*intval)();
+
+ if (!reset) {
+ hupval = signal(SIGHUP, SIG_IGN);
+ if (hupval != SIG_IGN)
+ hupval = (RETSIGTYPE(*)())my_exit;
+ intval = signal(SIGINT, SIG_IGN);
+ if (intval != SIG_IGN)
+ intval = (RETSIGTYPE(*)())my_exit;
+ }
+ Signal(SIGHUP, hupval);
+ Signal(SIGINT, intval);
+#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.
+ If `striplast' is TRUE, ignore the last element of `filename'. */
+
+void
+makedirs(filename,striplast)
+Reg1 char *filename;
+bool striplast;
+{
+ char tmpbuf[256];
+ Reg2 char *s = tmpbuf;
+ char *dirv[20]; /* Point to the NULs between elements. */
+ Reg3 int i;
+ Reg4 int dirvp = 0; /* Number of finished entries in dirv. */
+
+ /* Copy `filename' into `tmpbuf' with a NUL instead of a slash
+ between the directories. */
+ 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++) {
+ struct stat sbuf;
+
+ if (stat(tmpbuf, &sbuf) && errno == ENOENT) {
+ while (*s) s++;
+ *s++ = ' ';
+ strcpy(s, tmpbuf);
+ }
+ *dirv[i] = '/';
+ }
+ if (s != buf)
+ system(buf);
+}
+
+/* Make filenames more reasonable. */
+
+char *
+fetchname(at,strip_leading,assume_exists)
+char *at;
+int strip_leading;
+int assume_exists;
+{
+ char *fullname;
+ char *name;
+ Reg1 char *t;
+ char tmpbuf[200];
+ int sleading = strip_leading;
+
+ if (!at)
+ return Nullch;
+ while (isspace(*at))
+ at++;
+#ifdef DEBUGGING
+ if (debug & 128)
+ say4("fetchname %s %d %d\n",at,strip_leading,assume_exists);
+#endif
+ if (strnEQ(at, "/dev/null", 9)) /* so files can be created by diffing */
+ return Nullch; /* against /dev/null. */
+ name = fullname = t = savestr(at);
+
+ /* Strip off up to `sleading' leading slashes and null terminate. */
+ for (; *t && !isspace(*t); t++)
+ if (*t == '/')
+ if (--sleading >= 0)
+ name = t+1;
+ *t = '\0';
+
+ /* If no -p option was given (957 is the default value!),
+ we were given a relative pathname,
+ and the leading directories that we just stripped off all exist,
+ put them back on. */
+ if (strip_leading == 957 && name != fullname && *fullname != '/') {
+ name[-1] = '\0';
+ if (stat(fullname, &filestat) == 0 && S_ISDIR (filestat.st_mode)) {
+ name[-1] = '/';
+ name=fullname;
+ }
+ }
+
+ name = savestr(name);
+ free(fullname);
+
+ if (stat(name, &filestat) && !assume_exists) {
+ char *filebase = basename(name);
+ int pathlen = filebase - name;
+
+ /* Put any leading path into `tmpbuf'. */
+ strncpy(tmpbuf, name, pathlen);
+
+#define try(f, a1, a2) (Sprintf(tmpbuf + pathlen, f, a1, a2), stat(tmpbuf, &filestat) == 0)
+ if ( try("RCS/%s%s", filebase, RCSSUFFIX)
+ || try("RCS/%s" , filebase, 0)
+ || try( "%s%s", filebase, RCSSUFFIX)
+ || try("SCCS/%s%s", SCCSPREFIX, filebase)
+ || try( "%s%s", SCCSPREFIX, filebase))
+ return name;
+ free(name);
+ name = Nullch;
+ }
+
+ return name;
+}
+
+char *
+xmalloc (size)
+ unsigned size;
+{
+ register char *p = (char *) malloc (size);
+ if (!p)
+ fatal("out of memory");
+ return p;
+}
diff --git a/gnu/usr.bin/patch/util.h b/gnu/usr.bin/patch/util.h
new file mode 100644
index 0000000..c56b4c3
--- /dev/null
+++ b/gnu/usr.bin/patch/util.h
@@ -0,0 +1,91 @@
+/* $Header: /home/ncvs/src/gnu/usr.bin/patch/util.h,v 1.1.1.1 1993/06/19 14:21:52 paul Exp $
+ *
+ * $Log: util.h,v $
+ * Revision 1.1.1.1 1993/06/19 14:21:52 paul
+ * b-maked patch-2.10
+ *
+ * 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
+#define pfatal1 pfatal
+#define pfatal2 pfatal
+#define pfatal3 pfatal
+#define pfatal4 pfatal
+
+#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))
+#define pfatal1(a) pfatal(a, 0, 0, 0)
+#define pfatal2(a,b) pfatal(a, (b)==(b), 0, 0)
+#define pfatal3(a,b,c) pfatal(a, (b)==(b), (c)==(c), 0)
+#define pfatal4(a,b,c,d) pfatal(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
+#define pfatal1(a) pfatal(a, Nullch, Nullch, Nullch)
+#define pfatal2(a,b) pfatal(a, b, Nullch, Nullch)
+#define pfatal3(a,b,c) pfatal(a, b, c, Nullch)
+#define pfatal4 pfatal
+
+#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 pfatal();
+void ask();
+char *savestr();
+void set_signals();
+void ignore_signals();
+void makedirs();
+char *basename();
diff --git a/gnu/usr.bin/patch/version.c b/gnu/usr.bin/patch/version.c
new file mode 100644
index 0000000..dfd2e9a
--- /dev/null
+++ b/gnu/usr.bin/patch/version.c
@@ -0,0 +1,28 @@
+/* $Header: /home/ncvs/src/gnu/usr.bin/patch/version.c,v 1.1.1.1 1993/06/19 14:21:52 paul Exp $
+ *
+ * $Log: version.c,v $
+ * Revision 1.1.1.1 1993/06/19 14:21:52 paul
+ * b-maked patch-2.10
+ *
+ * Revision 2.0 86/09/17 15:40:11 lwall
+ * Baseline for netwide release.
+ *
+ */
+
+#include "EXTERN.h"
+#include "common.h"
+#include "util.h"
+#include "INTERN.h"
+#include "patchlevel.h"
+#include "version.h"
+
+void my_exit();
+
+/* Print out the version number and die. */
+
+void
+version()
+{
+ fprintf(stderr, "Patch version %s\n", PATCH_VERSION);
+ my_exit(0);
+}
diff --git a/gnu/usr.bin/patch/version.h b/gnu/usr.bin/patch/version.h
new file mode 100644
index 0000000..f59ee26
--- /dev/null
+++ b/gnu/usr.bin/patch/version.h
@@ -0,0 +1,12 @@
+/* $Header: /home/ncvs/src/gnu/usr.bin/patch/version.h,v 1.1.1.1 1993/06/19 14:21:52 paul Exp $
+ *
+ * $Log: version.h,v $
+ * Revision 1.1.1.1 1993/06/19 14:21:52 paul
+ * b-maked patch-2.10
+ *
+ * Revision 2.0 86/09/17 15:40:14 lwall
+ * Baseline for netwide release.
+ *
+ */
+
+void version();
diff --git a/gnu/usr.bin/perl/Artistic b/gnu/usr.bin/perl/Artistic
new file mode 100644
index 0000000..fbf7989
--- /dev/null
+++ b/gnu/usr.bin/perl/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/gnu/usr.bin/perl/Copying b/gnu/usr.bin/perl/Copying
new file mode 100644
index 0000000..3c68f02
--- /dev/null
+++ b/gnu/usr.bin/perl/Copying
@@ -0,0 +1,248 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 1, February 1989
+
+ Copyright (C) 1989 Free Software Foundation, Inc.
+ 675 Mass Ave, Cambridge, MA 02139, USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The license agreements of most software companies try to keep users
+at the mercy of those companies. By contrast, our General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. The
+General Public License applies to the Free Software Foundation's
+software and to any other program whose authors commit to using it.
+You can use it for your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Specifically, the General Public License is designed to make
+sure that you have the freedom to give away or sell copies of free
+software, that you receive source code or can get it if you want it,
+that you can change the software or use pieces of it in new free
+programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of a such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must tell them their rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License Agreement applies to any program or other work which
+contains a notice placed by the copyright holder saying it may be
+distributed under the terms of this General Public License. The
+"Program", below, refers to any such program or work, and a "work based
+on the Program" means either the Program or any work containing the
+Program or a portion of it, either verbatim or with modifications. Each
+licensee is addressed as "you".
+
+ 1. You may copy and distribute verbatim copies of the Program's source
+code as you receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice and
+disclaimer of warranty; keep intact all the notices that refer to this
+General Public License and to the absence of any warranty; and give any
+other recipients of the Program a copy of this General Public License
+along with the Program. You may charge a fee for the physical act of
+transferring a copy.
+
+ 2. You may modify your copy or copies of the Program or any portion of
+it, and copy and distribute such modifications under the terms of Paragraph
+1 above, provided that you also do the following:
+
+ a) cause the modified files to carry prominent notices stating that
+ you changed the files and the date of any change; and
+
+ b) cause the whole of any work that you distribute or publish, that
+ in whole or in part contains the Program or any part thereof, either
+ with or without modifications, to be licensed at no charge to all
+ third parties under the terms of this General Public License (except
+ that you may choose to grant warranty protection to some or all
+ third parties, at your option).
+
+ c) If the modified program normally reads commands interactively when
+ run, you must cause it, when started running for such interactive use
+ in the simplest and most usual way, to print or display an
+ announcement including an appropriate copyright notice and a notice
+ that there is no warranty (or else, saying that you provide a
+ warranty) and that users may redistribute the program under these
+ conditions, and telling the user how to view a copy of this General
+ Public License.
+
+ d) You may charge a fee for the physical act of transferring a
+ copy, and you may at your option offer warranty protection in
+ exchange for a fee.
+
+Mere aggregation of another independent work with the Program (or its
+derivative) on a volume of a storage or distribution medium does not bring
+the other work under the scope of these terms.
+
+ 3. You may copy and distribute the Program (or a portion or derivative of
+it, under Paragraph 2) in object code or executable form under the terms of
+Paragraphs 1 and 2 above provided that you also do one of the following:
+
+ a) accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of
+ Paragraphs 1 and 2 above; or,
+
+ b) accompany it with a written offer, valid for at least three
+ years, to give any third party free (except for a nominal charge
+ for the cost of distribution) a complete machine-readable copy of the
+ corresponding source code, to be distributed under the terms of
+ Paragraphs 1 and 2 above; or,
+
+ c) accompany it with the information you received as to where the
+ corresponding source code may be obtained. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form alone.)
+
+Source code for a work means the preferred form of the work for making
+modifications to it. For an executable file, complete source code means
+all the source code for all modules it contains; but, as a special
+exception, it need not include source code for modules which are standard
+libraries that accompany the operating system on which the executable
+file runs, or for standard header files or definitions files that
+accompany that operating system.
+
+ 4. You may not copy, modify, sublicense, distribute or transfer the
+Program except as expressly provided under this General Public License.
+Any attempt otherwise to copy, modify, sublicense, distribute or transfer
+the Program is void, and will automatically terminate your rights to use
+the Program under this License. However, parties who have received
+copies, or rights to use copies, from you under this General Public
+License will not have their licenses terminated so long as such parties
+remain in full compliance.
+
+ 5. By copying, distributing or modifying the Program (or any work based
+on the Program) you indicate your acceptance of this license to do so,
+and all its terms and conditions.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the original
+licensor to copy, distribute or modify the Program subject to these
+terms and conditions. You may not impose any further restrictions on the
+recipients' exercise of the rights granted herein.
+
+ 7. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of the license which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+the license, you may choose any version ever published by the Free Software
+Foundation.
+
+ 8. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 9. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 10. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ Appendix: How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to humanity, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these
+terms.
+
+ To do so, attach the following notices to the program. It is safest to
+attach them to the start of each source file to most effectively convey
+the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) 19yy <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 1, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) 19xx name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the
+appropriate parts of the General Public License. Of course, the
+commands you use may be called something other than `show w' and `show
+c'; they could even be mouse-clicks or menu items--whatever suits your
+program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the
+ program `Gnomovision' (a program to direct compilers to make passes
+ at assemblers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+That's all there is to it!
diff --git a/gnu/usr.bin/perl/Makefile b/gnu/usr.bin/perl/Makefile
new file mode 100644
index 0000000..385033a
--- /dev/null
+++ b/gnu/usr.bin/perl/Makefile
@@ -0,0 +1,10 @@
+#
+# Bmake file for perl 4.036
+#
+# Note: I'm not sure what to do with c2ph located in misc...
+#
+
+SUBDIR= perl tperl sperl usub lib x2p
+
+.include <bsd.subdir.mk>
+
diff --git a/gnu/usr.bin/perl/README b/gnu/usr.bin/perl/README
new file mode 100644
index 0000000..c52c7f4
--- /dev/null
+++ b/gnu/usr.bin/perl/README
@@ -0,0 +1,195 @@
+
+ Perl Kit, Version 4.0
+
+ Copyright (c) 1989,1990,1991, Larry Wall
+ All rights reserved.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of either:
+
+ a) the GNU General Public License as published by the Free
+ Software Foundation; either version 1, or (at your option) any
+ later version, or
+
+ b) the "Artistic License" which comes with this Kit.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See either
+ the GNU General Public License or the Artistic License for more details.
+
+ You should have received a copy of the Artistic License with this
+ Kit, in the file named "Artistic". If not, I'll be glad to provide one.
+
+ You should also have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ For those of you that choose to use the GNU General Public License,
+ my interpretation of the GNU General Public License is that no Perl
+ script falls under the terms of the GPL unless you explicitly put
+ said script under the terms of the GPL yourself. Furthermore, any
+ object code linked with uperl.o does not automatically fall under the
+ terms of the GPL, provided such object code only adds definitions
+ of subroutines and variables, and does not otherwise impair the
+ resulting interpreter from executing any standard Perl script. I
+ consider linking in C subroutines in this manner to be the moral
+ equivalent of defining subroutines in the Perl language itself. You
+ may sell such an object file as proprietary provided that you provide
+ or offer to provide the Perl source, as specified by the GNU General
+ Public License. (This is merely an alternate way of specifying input
+ to the program.) You may also sell a binary produced by the dumping of
+ a running Perl script that belongs to you, provided that you provide or
+ offer to provide the Perl source as specified by the GPL. (The
+ fact that a Perl interpreter and your code are in the same binary file
+ is, in this case, a form of mere aggregation.) This is my interpretation
+ of the GPL. If you still have concerns or difficulties understanding
+ my intent, feel free to contact me. Of course, the Artistic License
+ spells all this out for your protection, so you may prefer to use that.
+
+--------------------------------------------------------------------------
+
+Perl is a language that combines some of the features of C, sed, awk and shell.
+See the manual page for more hype. There's also a Nutshell Handbook published
+by O'Reilly & Assoc. Their U.S. number is 1-800-338-6887 (dev-nuts) and
+their international number is 1-707-829-0515. E-mail to nuts@ora.com.
+
+Perl will probably not run on machines with a small address space.
+
+Please read all the directions below before you proceed any further, and
+then follow them carefully.
+
+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. If you're a hotshot, run Configure -d to take all the
+ defaults and then edit config.sh to patch up any flaws.
+
+ You might possibly have to trim # comments from the front of Configure
+ if your sh doesn't handle them, but all other # comments will be taken
+ care of.
+
+ (If you don't have sh, you'll have to copy the sample file config.H to
+ config.h and edit the config.h to reflect your system's peculiarities.)
+
+2) Glance through config.h to make sure system dependencies are correct.
+ Most of them should have been taken care of by running the Configure script.
+
+ If you have any additional changes to make to the C definitions, they
+ can be done in cflags.SH. For instance, to turn off the optimizer
+ on eval.c, find the line in the switch structure for eval.c and
+ put the command $optimize='-g' before the ;;. You will probably
+ want to change the entry for teval.c too. To change the C flags
+ for all the files, edit config.sh and change either $ccflags or $optimize.
+
+3) make depend
+
+ This will look for all the includes and modify Makefile accordingly.
+ Configure will offer to do this for you.
+
+4) make
+
+ This will attempt to make perl in the current directory.
+
+ If you can't compile successfully, try adding a -DCRIPPLED_CC flag.
+ (Just because you get no errors doesn't mean it compiled right!)
+ This simplifies some complicated expressions for compilers that
+ get indigestion easily. If that has no effect, try turning off
+ optimization. If you have missing routines, you probably need to
+ add some library or other, or you need to undefine some feature that
+ Configure thought was there but is defective or incomplete.
+
+ Some compilers will not compile or optimize the larger files without
+ some extra switches to use larger jump offsets or allocate larger
+ internal tables. You can customize the switches for each file in
+ cflags.SH. It's okay to insert rules for specific files into
+ Makefile.SH, since a default rule only takes effect in the
+ absence of a specific rule.
+
+ Most of the following hints are now done automatically by Configure.
+
+ The 3b2 needs to turn off -O.
+ Compilers with limited switch tables may have to define -DSMALLSWITCHES
+ Domain/OS 10.3 (at least) native C 6.7 may need -opt 2 for eval.c
+ AIX/RT may need a -a switch and -DCRIPPLED_CC.
+ AIX RS/6000 needs to use system malloc and avoid -O on eval.c and toke.c.
+ AIX RS/6000 needs -D_NO_PROTO.
+ SUNOS 4.0.[12] needs -DFPUTS_BOTCH.
+ SUNOS 3.[45] should use the system malloc.
+ SGI machines may need -Ddouble="long float" and -O1.
+ Vax-based systems may need to hand assemble teval.s with a -J switch.
+ Ultrix on MIPS machines may need -DLANGUAGE_C.
+ Ultrix 4.0 on MIPS machines may need -Olimit 2900 or so.
+ Ultrix 3.[01] on MIPS needs to undefine WAITPID--the system call is busted.
+ MIPS machines need /bin before /bsd43/bin in PATH.
+ MIPS machines may need to undef d_volatile.
+ MIPS machines may need to turn off -O on cmd.c, perl.c and tperl.c.
+ Some MIPS machines may need to undefine CASTNEGFLOAT.
+ Xenix 386 needs -Sm11000 for yacc, and may need -UM_I86.
+ SCO Xenix may need -m25000 for yacc. See also README.xenix.
+ Genix needs to use libc rather than libc_s, or #undef VARARGS.
+ NCR Tower 32 (OS 2.01.01) may need -W2,-Sl,2000 and #undef MKDIR.
+ A/UX may appears to work with -O -B/usr/lib/big/ optimizer flags.
+ A/UX needs -lposix to find rewinddir.
+ A/UX may need -ZP -DPOSIX, and -g if big cc is used.
+ FPS machines may need -J and -DBADSWITCH.
+ UTS may need one or more of -DCRIPPLED_CC, -K or -g, and undef LSTAT.
+ dynix may need to undefine CASTNEGFLOAT (d_castneg='undef' in config.sh).
+ Dnix (not dynix) may need to remove -O.
+ IRIX 3.3 may need to undefine VFORK.
+ HP/UX may need to pull cerror.o and syscall.o out of libc.a and link
+ them in explicitly.
+ If you get syntax errors on '(', try -DCRIPPLED_CC or -DBADSWITCH or both.
+ Machines with half-implemented dbm routines will need to #undef ODBM & NDBM.
+ If you have GDBM available and want it instead of NDBM, say -DHAS_GDBM.
+ C's that don't try to restore registers on longjmp() may need -DJMPCLOBBER.
+ (Try this if you get random glitches.)
+ If you get duplicates upon linking for malloc et al, say -DHIDEMYMALLOC.
+ Turn on support for 64-bit integers (long longs) with -DQUAD.
+
+5) make test
+
+ This will run the regression tests on the perl you just made.
+ If it doesn't say "All tests successful" then something went wrong.
+ See the README in the t subdirectory. Note that you can't run it
+ in background if this disables opening of /dev/tty. If "make test"
+ bombs out, just cd to the t directory and run TEST by hand to see if
+ it makes any difference. If individual tests bomb, you can run
+ them by hand, e.g., ./perl op/groups.t
+
+6) make install
+
+ This will put perl into a public directory (such as /usr/local/bin).
+ It will also try to put the man pages in a reasonable place. It will not
+ nroff the man page, however. You may need to be root to do this. If
+ you are not root, you must own the directories in question and you should
+ ignore any messages about chown not working.
+
+7) Read the manual entry before running perl.
+
+8) IMPORTANT! Help save the world! Communicate any problems and suggested
+ patches to me, lwall@netlabs.com (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. It's also
+ helpful if you send the output of "uname -a".
+
+ Watch for perl patches in comp.lang.perl. Patches will generally be
+ in a form usable by the patch program. If you are just now bringing up
+ perl 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.
+
+
+Just a personal note: I want you to know that I create nice things like this
+because it pleases the Author of my story. If this bothers you, then your
+notion of Authorship needs some revision. But you can use perl anyway. :-)
+
+ The author.
diff --git a/gnu/usr.bin/perl/VERSION b/gnu/usr.bin/perl/VERSION
new file mode 100644
index 0000000..2b80880
--- /dev/null
+++ b/gnu/usr.bin/perl/VERSION
@@ -0,0 +1 @@
+Perl 4.0 patchlevel 36
diff --git a/gnu/usr.bin/perl/Wishlist b/gnu/usr.bin/perl/Wishlist
new file mode 100644
index 0000000..3290834
--- /dev/null
+++ b/gnu/usr.bin/perl/Wishlist
@@ -0,0 +1,9 @@
+built-in cpp
+perl to C translator
+multi-threading
+make more easily embeddable
+built-in globbing
+compile to threaded code
+rewrite regexp parser for better integrated optimization
+add structured types and objects
+allow for lexical scoping
diff --git a/gnu/usr.bin/perl/eg/ADB b/gnu/usr.bin/perl/eg/ADB
new file mode 100644
index 0000000..09b93c3
--- /dev/null
+++ b/gnu/usr.bin/perl/eg/ADB
@@ -0,0 +1,8 @@
+#!/usr/bin/perl
+
+# $Header: /home/cvs/386BSD/ports/lang/perl/eg/ADB,v 1.1.1.1 1993/08/23 21:29:43 nate Exp $
+
+# This script is only useful when used in your crash directory.
+
+$num = shift;
+exec 'adb', '-k', "vmunix.$num", "vmcore.$num";
diff --git a/gnu/usr.bin/perl/eg/README b/gnu/usr.bin/perl/eg/README
new file mode 100644
index 0000000..87cfc33
--- /dev/null
+++ b/gnu/usr.bin/perl/eg/README
@@ -0,0 +1,22 @@
+Although supplied with the perl package, the perl scripts in this eg
+directory and its subdirectories are placed in the public domain, and
+you may do anything with them that you wish.
+
+This stuff is supplied on an as-is basis--little attempt has been made to make
+any of it portable. It's mostly here to give you an idea of what perl code
+looks like, and what tricks and idioms are used.
+
+System administrators responsible for many computers will enjoy the items
+down in the g directory very much. The scan directory contains the beginnings
+of a system to check on and report various kinds of anomalies.
+
+If you machine doesn't support #!, the first thing you'll want to do is
+replace the #! with a couple of lines that look like this:
+
+ eval "exec /usr/bin/perl -S $0 $*"
+ if $running_under_some_shell;
+
+being sure to include any flags that were on the #! line. A supplied script
+called "nih" will translate perl scripts in place for you:
+
+ nih g/g??
diff --git a/gnu/usr.bin/perl/eg/changes b/gnu/usr.bin/perl/eg/changes
new file mode 100644
index 0000000..9835e1b
--- /dev/null
+++ b/gnu/usr.bin/perl/eg/changes
@@ -0,0 +1,34 @@
+#!/usr/bin/perl -P
+
+# $Header: /home/cvs/386BSD/ports/lang/perl/eg/changes,v 1.1.1.1 1993/08/23 21:29:43 nate Exp $
+
+($dir, $days) = @ARGV;
+$dir = '/' if $dir eq '';
+$days = '14' if $days eq '';
+
+# Masscomps do things differently from Suns
+
+#if defined(mc300) || defined(mc500) || defined(mc700)
+open(Find, "find $dir -mtime -$days -print |") ||
+ die "changes: can't run find";
+#else
+open(Find, "find $dir \\( -fstype nfs -prune \\) -o -mtime -$days -ls |") ||
+ die "changes: can't run find";
+#endif
+
+while (<Find>) {
+
+#if defined(mc300) || defined(mc500) || defined(mc700)
+ $x = `/bin/ls -ild $_`;
+ $_ = $x;
+ ($inode,$perm,$links,$owner,$group,$size,$month,$day,$time,$name)
+ = split(' ');
+#else
+ ($inode,$blocks,$perm,$links,$owner,$group,$size,$month,$day,$time,$name)
+ = split(' ');
+#endif
+
+ printf("%10s%3s %-8s %-8s%9s %3s %2s %s\n",
+ $perm,$links,$owner,$group,$size,$month,$day,$name);
+}
+
diff --git a/gnu/usr.bin/perl/eg/client b/gnu/usr.bin/perl/eg/client
new file mode 100644
index 0000000..5900c90
--- /dev/null
+++ b/gnu/usr.bin/perl/eg/client
@@ -0,0 +1,34 @@
+#!./perl
+
+$pat = 'S n C4 x8';
+$inet = 2;
+$echo = 7;
+$smtp = 25;
+$nntp = 119;
+$test = 2345;
+
+$SIG{'INT'} = 'dokill';
+
+$this = pack($pat,$inet,0, 128,149,13,43);
+$that = pack($pat,$inet,$test,127,0,0,1);
+
+if (socket(S,2,1,6)) { print "socket ok\n"; } else { die $!; }
+if (bind(S,$this)) { print "bind ok\n"; } else { die $!; }
+if (connect(S,$that)) { print "connect ok\n"; } else { die $!; }
+
+select(S); $| = 1; select(stdout);
+
+if ($child = fork) {
+ while (<STDIN>) {
+ print S;
+ }
+ sleep 3;
+ do dokill();
+}
+else {
+ while (<S>) {
+ print;
+ }
+}
+
+sub dokill { kill 9,$child if $child; }
diff --git a/gnu/usr.bin/perl/eg/down b/gnu/usr.bin/perl/eg/down
new file mode 100644
index 0000000..bbb0d06
--- /dev/null
+++ b/gnu/usr.bin/perl/eg/down
@@ -0,0 +1,30 @@
+#!/usr/bin/perl
+
+$| = 1;
+if ($#ARGV >= 0) {
+ $cmd = join(' ',@ARGV);
+}
+else {
+ print "Command: ";
+ $cmd = <stdin>;
+ chop($cmd);
+ while ($cmd =~ s/\\$//) {
+ print "+ ";
+ $cmd .= <stdin>;
+ chop($cmd);
+ }
+}
+$cwd = `pwd`; chop($cwd);
+
+open(FIND,'find . -type d -print|') || die "Can't run find";
+
+while (<FIND>) {
+ chop;
+ unless (chdir $_) {
+ print stderr "Can't cd to $_\n";
+ next;
+ }
+ print "\t--> ",$_,"\n";
+ system $cmd;
+ chdir $cwd;
+}
diff --git a/gnu/usr.bin/perl/eg/dus b/gnu/usr.bin/perl/eg/dus
new file mode 100644
index 0000000..94c648b
--- /dev/null
+++ b/gnu/usr.bin/perl/eg/dus
@@ -0,0 +1,22 @@
+#!/usr/bin/perl
+
+# $Header: /home/cvs/386BSD/ports/lang/perl/eg/dus,v 1.1.1.1 1993/08/23 21:29:43 nate Exp $
+
+# This script does a du -s on any directories in the current directory that
+# are not mount points for another filesystem.
+
+($mydev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,$atime,$mtime,$ctime,
+ $blksize,$blocks) = stat('.');
+
+open(ls,'ls -F1|');
+
+while (<ls>) {
+ chop;
+ next unless s|/$||;
+ ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,$atime,$mtime,$ctime,
+ $blksize,$blocks) = stat($_);
+ next unless $dev == $mydev;
+ push(@ary,$_);
+}
+
+exec 'du', '-s', @ary;
diff --git a/gnu/usr.bin/perl/eg/findcp b/gnu/usr.bin/perl/eg/findcp
new file mode 100644
index 0000000..47e4438
--- /dev/null
+++ b/gnu/usr.bin/perl/eg/findcp
@@ -0,0 +1,53 @@
+#!/usr/bin/perl
+
+# $Header: /home/cvs/386BSD/ports/lang/perl/eg/findcp,v 1.1.1.1 1993/08/23 21:29:43 nate Exp $
+
+# This is a wrapper around the find command that pretends find has a switch
+# of the form -cp host:destination. It presumes your find implements -ls.
+# It uses tar to do the actual copy. If your tar knows about the I switch
+# you may prefer to use findtar, since this one has to do the tar in batches.
+
+sub copy {
+ `tar cf - $list | rsh $desthost cd $destdir '&&' tar xBpf -`;
+}
+
+$sourcedir = $ARGV[0];
+if ($sourcedir =~ /^\//) {
+ $ARGV[0] = '.';
+ unless (chdir($sourcedir)) { die "Can't find directory $sourcedir: $!"; }
+}
+
+$args = join(' ',@ARGV);
+if ($args =~ s/-cp *([^ ]+)/-ls/) {
+ $dest = $1;
+ if ($dest =~ /(.*):(.*)/) {
+ $desthost = $1;
+ $destdir = $2;
+ }
+ else {
+ die "Malformed destination--should be host:directory";
+ }
+}
+else {
+ die("No destination specified");
+}
+
+open(find,"find $args |") || die "Can't run find for you: $!";
+
+while (<find>) {
+ @x = split(' ');
+ if ($x[2] =~ /^d/) { next;}
+ chop($filename = $x[10]);
+ if (length($list) > 5000) {
+ do copy();
+ $list = '';
+ }
+ else {
+ $list .= ' ';
+ }
+ $list .= $filename;
+}
+
+if ($list) {
+ do copy();
+}
diff --git a/gnu/usr.bin/perl/eg/findtar b/gnu/usr.bin/perl/eg/findtar
new file mode 100644
index 0000000..a60f10f
--- /dev/null
+++ b/gnu/usr.bin/perl/eg/findtar
@@ -0,0 +1,17 @@
+#!/usr/bin/perl
+
+# $Header: /home/cvs/386BSD/ports/lang/perl/eg/findtar,v 1.1.1.1 1993/08/23 21:29:43 nate Exp $
+
+# findtar takes find-style arguments and spits out a tarfile on stdout.
+# It won't work unless your find supports -ls and your tar the I flag.
+
+$args = join(' ',@ARGV);
+open(find,"/usr/bin/find $args -ls |") || die "Can't run find for you.";
+
+open(tar,"| /bin/tar cIf - -") || die "Can't run tar for you: $!";
+
+while (<find>) {
+ @x = split(' ');
+ if ($x[2] =~ /^d/) { print tar '-d ';}
+ print tar $x[10],"\n";
+}
diff --git a/gnu/usr.bin/perl/eg/g/gcp b/gnu/usr.bin/perl/eg/g/gcp
new file mode 100644
index 0000000..3e44a9c
--- /dev/null
+++ b/gnu/usr.bin/perl/eg/g/gcp
@@ -0,0 +1,114 @@
+#!/usr/bin/perl
+
+# $Header: /home/cvs/386BSD/ports/lang/perl/eg/g/gcp,v 1.1.1.1 1993/08/23 21:29:44 nate Exp $
+
+# Here is a script to do global rcps. See man page.
+
+$#ARGV >= 1 || die "Not enough arguments.\n";
+
+if ($ARGV[0] eq '-r') {
+ $rcp = 'rcp -r';
+ shift;
+} else {
+ $rcp = 'rcp';
+}
+$args = $rcp;
+$dest = $ARGV[$#ARGV];
+
+$SIG{'QUIT'} = 'CLEANUP';
+$SIG{'INT'} = 'CONT';
+
+while ($arg = shift) {
+ if ($arg =~ /^([-a-zA-Z0-9_+]+):/) {
+ if ($systype && $systype ne $1) {
+ die "Can't mix system type specifers ($systype vs $1).\n";
+ }
+ $#ARGV < 0 || $arg !~ /:$/ || die "No source file specified.\n";
+ $systype = $1;
+ $args .= " $arg";
+ } else {
+ if ($#ARGV >= 0) {
+ if ($arg =~ /^[\/~]/) {
+ $arg =~ /^(.*)\// && ($dir = $1);
+ } else {
+ if (!$pwd) {
+ chop($pwd = `pwd`);
+ }
+ $dir = $pwd;
+ }
+ }
+ if ($olddir && $dir ne $olddir && $dest =~ /:$/) {
+ $args .= " $dest$olddir; $rcp";
+ }
+ $olddir = $dir;
+ $args .= " $arg";
+ }
+}
+
+die "No system type specified.\n" unless $systype;
+
+$args =~ s/:$/:$olddir/;
+
+chop($thishost = `hostname`);
+
+$one_of_these = ":$systype:";
+if ($systype =~ s/\+/[+]/g) {
+ $one_of_these =~ s/\+/:/g;
+}
+$one_of_these =~ s/-/:-/g;
+
+@ARGV = ();
+push(@ARGV,'.grem') if -f '.grem';
+push(@ARGV,'.ghosts') if -f '.ghosts';
+push(@ARGV,'/etc/ghosts');
+
+$remainder = '';
+
+line: while (<>) {
+ s/[ \t]*\n//;
+ if (!$_ || /^#/) {
+ next line;
+ }
+ if (/^([a-zA-Z_0-9]+)=(.+)/) {
+ $name = $1; $repl = $2;
+ $repl =~ s/\+/:/g;
+ $repl =~ s/-/:-/g;
+ $one_of_these =~ s/:$name:/:$repl:/;
+ $repl =~ s/:/:-/g;
+ $one_of_these =~ s/:-$name:/:-$repl:/g;
+ next line;
+ }
+ @gh = split(' ');
+ $host = $gh[0];
+ next line if $host eq $thishost; # should handle aliases too
+ $wanted = 0;
+ foreach $class (@gh) {
+ $wanted++ if index($one_of_these,":$class:") >= 0;
+ $wanted = -9999 if index($one_of_these,":-$class:") >= 0;
+ }
+ if ($wanted > 0) {
+ ($cmd = $args) =~ s/[ \t]$systype:/ $host:/g;
+ print "$cmd\n";
+ $result = `$cmd 2>&1`;
+ $remainder .= "$host+" if
+ $result =~ /Connection timed out|Permission denied/;
+ print $result;
+ }
+}
+
+if ($remainder) {
+ chop($remainder);
+ open(grem,">.grem") || (printf stderr "Can't create .grem: $!\n");
+ print grem 'rem=', $remainder, "\n";
+ close(grem);
+ print 'rem=', $remainder, "\n";
+}
+
+sub CLEANUP {
+ exit;
+}
+
+sub CONT {
+ print "Continuing...\n"; # Just ignore the signal that kills rcp
+ $remainder .= "$host+";
+}
diff --git a/gnu/usr.bin/perl/eg/g/gcp.man b/gnu/usr.bin/perl/eg/g/gcp.man
new file mode 100644
index 0000000..8985742
--- /dev/null
+++ b/gnu/usr.bin/perl/eg/g/gcp.man
@@ -0,0 +1,77 @@
+.\" $Header: /home/cvs/386BSD/ports/lang/perl/eg/g/gcp.man,v 1.1.1.1 1993/08/23 21:29:44 nate Exp $
+.TH GCP 1C "13 May 1988"
+.SH NAME
+gcp \- global file copy
+.SH SYNOPSIS
+.B gcp
+file1 file2
+.br
+.B gcp
+[
+.B \-r
+] file ... directory
+.SH DESCRIPTION
+.I gcp
+works just like rcp(1C) except that you may specify a set of hosts to copy files
+from or to.
+The host sets are defined in the file /etc/ghosts.
+(An individual host name can be used as a set containing one member.)
+You can give a command like
+
+ gcp /etc/motd sun:
+
+to copy your /etc/motd file to /etc/motd on all the Suns.
+If, on the other hand, you say
+
+ gcp /a/foo /b/bar sun:/tmp
+
+then your files will be copied to /tmp on all the Suns.
+The general rule is that if you don't specify the destination directory,
+files go to the same directory they are in currently.
+.P
+You may specify the union of two or more sets by using + as follows:
+
+ gcp /a/foo /b/bar 750+mc:
+
+which will copy /a/foo to /a/foo on all 750's and Masscomps, and then copy
+/b/bar to /b/bar on all 750's and Masscomps.
+.P
+Commonly used sets should be defined in /etc/ghosts.
+For example, you could add a line that says
+
+ pep=manny+moe+jack
+
+Another way to do that would be to add the word "pep" after each of the host
+entries:
+
+ manny sun3 pep
+.br
+ moe sun3 pep
+.br
+ jack sun3 pep
+
+Hosts and sets of host can also be excluded:
+
+ foo=sun-sun2
+
+Any host so excluded will never be included, even if a subsequent set on the
+line includes it:
+
+ foo=abc+def
+.br
+ bar=xyz-abc+foo
+
+comes out to xyz+def.
+
+You can define private host sets by creating .ghosts in your current directory
+with entries just like /etc/ghosts.
+Also, if there is a file .grem, it defines "rem" to be the remaining hosts
+from the last gsh or gcp that didn't succeed everywhere.
+.PP
+Interrupting with a SIGINT will cause the rcp to the current host to be skipped
+and execution resumed with the next host.
+To stop completely, send a SIGQUIT.
+.SH SEE ALSO
+rcp(1C)
+.SH BUGS
+All the bugs of rcp, since it calls rcp.
diff --git a/gnu/usr.bin/perl/eg/g/ged b/gnu/usr.bin/perl/eg/g/ged
new file mode 100644
index 0000000..d296a84
--- /dev/null
+++ b/gnu/usr.bin/perl/eg/g/ged
@@ -0,0 +1,21 @@
+#!/usr/bin/perl
+
+# $Header: /home/cvs/386BSD/ports/lang/perl/eg/g/ged,v 1.1.1.1 1993/08/23 21:29:44 nate Exp $
+
+# Does inplace edits on a set of files on a set of machines.
+#
+# Typical invokation:
+#
+# ged vax+sun /etc/passwd
+# s/Freddy/Freddie/;
+# ^D
+#
+
+$class = shift;
+$files = join(' ',@ARGV);
+
+die "Usage: ged class files <perlcmds\n" unless $files;
+
+exec "gsh", $class, "-d", "perl -pi.bak - $files";
+
+die "Couldn't execute gsh for some reason, stopped";
diff --git a/gnu/usr.bin/perl/eg/g/ghosts b/gnu/usr.bin/perl/eg/g/ghosts
new file mode 100644
index 0000000..96ec771
--- /dev/null
+++ b/gnu/usr.bin/perl/eg/g/ghosts
@@ -0,0 +1,33 @@
+# This first section gives alternate sets defined in terms of the sets given
+# by the second section. The order is important--all references must be
+# forward references.
+
+Nnd=sun-nd
+all=sun+mc+vax
+baseline=sun+mc
+sun=sun2+sun3
+vax=750+8600
+pep=manny+moe+jack
+
+# This second section defines the basic sets. Each host should have a line
+# that specifies which sets it is a member of. Extra sets should be separated
+# by white space. (The first section isn't strictly necessary, since all sets
+# could be defined in the second section, but then it wouldn't be so readable.)
+
+basvax 8600 src
+cdb0 sun3 sys
+cdb1 sun3 sys
+cdb2 sun3 sys
+chief sun3 src
+tis0 sun3
+manny sun3 sys
+moe sun3 sys
+jack sun3 sys
+disney sun3 sys
+huey sun3 nd
+dewey sun3 nd
+louie sun3 nd
+bizet sun2 src sys
+gif0 mc src
+mc0 mc
+dtv0 mc
diff --git a/gnu/usr.bin/perl/eg/g/gsh b/gnu/usr.bin/perl/eg/g/gsh
new file mode 100644
index 0000000..3322a02
--- /dev/null
+++ b/gnu/usr.bin/perl/eg/g/gsh
@@ -0,0 +1,117 @@
+#! /usr/bin/perl
+
+# $Header: /home/cvs/386BSD/ports/lang/perl/eg/g/gsh,v 1.1.1.1 1993/08/23 21:29:44 nate Exp $
+
+# Do rsh globally--see man page
+
+$SIG{'QUIT'} = 'quit'; # install signal handler for SIGQUIT
+
+sub getswitches {
+ while ($ARGV[0] =~ /^-/) { # parse switches
+ $ARGV[0] =~ /^-h/ && ($showhost++,$silent++,shift(@ARGV),next);
+ $ARGV[0] =~ /^-s/ && ($silent++,shift(@ARGV),next);
+ $ARGV[0] =~ /^-d/ && ($dodist++,shift(@ARGV),next);
+ $ARGV[0] =~ /^-n/ && ($n=' -n',shift(@ARGV),next);
+ $ARGV[0] =~ /^-l/ && ($l=' -l ' . $ARGV[1],shift(@ARGV),shift(@ARGV),
+ next);
+ last;
+ }
+}
+
+do getswitches(); # get any switches before class
+$systype = shift; # get name representing set of hosts
+do getswitches(); # same switches allowed after class
+
+if ($dodist) { # distribute input over all rshes?
+ `cat >/tmp/gsh$$`; # get input into a handy place
+ $dist = " </tmp/gsh$$"; # each rsh takes input from there
+}
+
+$cmd = join(' ',@ARGV); # remaining args constitute the command
+$cmd =~ s/'/'"'"'/g; # quote any embedded single quotes
+
+$one_of_these = ":$systype:"; # prepare to expand "macros"
+$one_of_these =~ s/\+/:/g; # we hope to end up with list of
+$one_of_these =~ s/-/:-/g; # colon separated attributes
+
+@ARGV = ();
+push(@ARGV,'.grem') if -f '.grem';
+push(@ARGV,'.ghosts') if -f '.ghosts';
+push(@ARGV,'/etc/ghosts');
+
+$remainder = '';
+
+line: while (<>) { # for each line of ghosts
+
+ s/[ \t]*\n//; # trim trailing whitespace
+ if (!$_ || /^#/) { # skip blank line or comment
+ next line;
+ }
+
+ if (/^(\w+)=(.+)/) { # a macro line?
+ $name = $1; $repl = $2;
+ $repl =~ s/\+/:/g;
+ $repl =~ s/-/:-/g;
+ $one_of_these =~ s/:$name:/:$repl:/; # do expansion in "wanted" list
+ $repl =~ s/:/:-/g;
+ $one_of_these =~ s/:-$name:/:-$repl:/;
+ next line;
+ }
+
+ # we have a normal line
+
+ @attr = split(' '); # a list of attributes to match against
+ # which we put into an array
+ $host = $attr[0]; # the first attribute is the host name
+ if ($showhost) {
+ $showhost = "$host:\t";
+ }
+
+ $wanted = 0;
+ foreach $attr (@attr) { # iterate over attribute array
+ $wanted++ if index($one_of_these,":$attr:") >= 0;
+ $wanted = -9999 if index($one_of_these,":-$attr:") >= 0;
+ }
+ if ($wanted > 0) {
+ print "rsh $host$l$n '$cmd'\n" unless $silent;
+ $SIG{'INT'} = 'DEFAULT';
+ if (open(PIPE,"rsh $host$l$n '$cmd'$dist 2>&1|")) { # start an rsh
+ $SIG{'INT'} = 'cont';
+ for ($iter=0; <PIPE>; $iter++) {
+ unless ($iter) {
+ $remainder .= "$host+"
+ if /Connection timed out|Permission denied/;
+ }
+ print $showhost,$_;
+ }
+ close(PIPE);
+ } else {
+ print "(Can't execute rsh: $!)\n";
+ $SIG{'INT'} = 'cont';
+ }
+ }
+}
+
+unlink "/tmp/gsh$$" if $dodist;
+
+if ($remainder) {
+ chop($remainder);
+ open(grem,">.grem") || (printf stderr "Can't make a .grem file: $!\n");
+ print grem 'rem=', $remainder, "\n";
+ close(grem);
+ print 'rem=', $remainder, "\n";
+}
+
+# here are a couple of subroutines that serve as signal handlers
+
+sub cont {
+ print "\rContinuing...\n";
+ $remainder .= "$host+";
+}
+
+sub quit {
+ $| = 1;
+ print "\r";
+ $SIG{'INT'} = '';
+ kill 2, $$;
+}
diff --git a/gnu/usr.bin/perl/eg/g/gsh.man b/gnu/usr.bin/perl/eg/g/gsh.man
new file mode 100644
index 0000000..00eafb6
--- /dev/null
+++ b/gnu/usr.bin/perl/eg/g/gsh.man
@@ -0,0 +1,80 @@
+.\" $Header: /home/cvs/386BSD/ports/lang/perl/eg/g/gsh.man,v 1.1.1.1 1993/08/23 21:29:44 nate Exp $
+.TH GSH 8 "13 May 1988"
+.SH NAME
+gsh \- global shell
+.SH SYNOPSIS
+.B gsh
+[options]
+.I host
+[options]
+.I command
+.SH DESCRIPTION
+.I gsh
+works just like rsh(1C) except that you may specify a set of hosts to execute
+the command on.
+The host sets are defined in the file /etc/ghosts.
+(An individual host name can be used as a set containing one member.)
+You can give a command like
+
+ gsh sun /etc/mungmotd
+
+to run /etc/mungmotd on all your Suns.
+.P
+You may specify the union of two or more sets by using + as follows:
+
+ gsh 750+mc /etc/mungmotd
+
+which will run mungmotd on all 750's and Masscomps.
+.P
+Commonly used sets should be defined in /etc/ghosts.
+For example, you could add a line that says
+
+ pep=manny+moe+jack
+
+Another way to do that would be to add the word "pep" after each of the host
+entries:
+
+ manny sun3 pep
+.br
+ moe sun3 pep
+.br
+ jack sun3 pep
+
+Hosts and sets of host can also be excluded:
+
+ foo=sun-sun2
+
+Any host so excluded will never be included, even if a subsequent set on the
+line includes it:
+
+ foo=abc+def
+ bar=xyz-abc+foo
+
+comes out to xyz+def.
+
+You can define private host sets by creating .ghosts in your current directory
+with entries just like /etc/ghosts.
+Also, if there is a file .grem, it defines "rem" to be the remaining hosts
+from the last gsh or gcp that didn't succeed everywhere.
+
+Options include all those defined by rsh, as well as
+
+.IP "\-d" 8
+Causes gsh to collect input till end of file, and then distribute that input
+to each invokation of rsh.
+.IP "\-h" 8
+Rather than print out the command followed by the output, merely prepends the
+host name to each line of output.
+.IP "\-s" 8
+Do work silently.
+.PP
+Interrupting with a SIGINT will cause the rsh to the current host to be skipped
+and execution resumed with the next host.
+To stop completely, send a SIGQUIT.
+.SH SEE ALSO
+rsh(1C)
+.SH BUGS
+All the bugs of rsh, since it calls rsh.
+
+Also, will not properly return data from the remote execution that contains
+null characters.
diff --git a/gnu/usr.bin/perl/eg/muck b/gnu/usr.bin/perl/eg/muck
new file mode 100644
index 0000000..873539b
--- /dev/null
+++ b/gnu/usr.bin/perl/eg/muck
@@ -0,0 +1,141 @@
+#!../perl
+
+$M = '-M';
+$M = '-m' if -d '/usr/uts' && -f '/etc/master';
+
+do 'getopt.pl';
+do Getopt('f');
+
+if ($opt_f) {
+ $makefile = $opt_f;
+}
+elsif (-f 'makefile') {
+ $makefile = 'makefile';
+}
+elsif (-f 'Makefile') {
+ $makefile = 'Makefile';
+}
+else {
+ die "No makefile\n";
+}
+
+$MF = 'mf00';
+
+while(($key,$val) = each(ENV)) {
+ $mac{$key} = $val;
+}
+
+do scan($makefile);
+
+$co = $action{'.c.o'};
+$co = ' ' unless $co;
+
+$missing = "Missing dependencies:\n";
+foreach $key (sort keys(o)) {
+ if ($oc{$key}) {
+ $src = $oc{$key};
+ $action = $action{$key};
+ }
+ else {
+ $action = '';
+ }
+ if (!$action) {
+ if ($co && ($c = $key) =~ s/\.o$/.c/ && -f $c) {
+ $src = $c;
+ $action = $co;
+ }
+ else {
+ print "No source found for $key $c\n";
+ next;
+ }
+ }
+ $I = '';
+ $D = '';
+ $I .= $1 while $action =~ s/(-I\S+\s*)//;
+ $D .= $1 . ' ' while $action =~ s/(-D\w+)//;
+ if ($opt_v) {
+ $cmd = "Checking $key: cc $M $D $I $src";
+ $cmd =~ s/\s\s+/ /g;
+ print stderr $cmd,"\n";
+ }
+ open(CPP,"cc $M $D $I $src|") || die "Can't run C preprocessor: $!";
+ while (<CPP>) {
+ ($name,$dep) = split;
+ $dep =~ s|^\./||;
+ (print $missing,"$key: $dep\n"),($missing='')
+ unless ($dep{"$key: $dep"} += 2) > 2;
+ }
+}
+
+$extra = "\nExtraneous dependencies:\n";
+foreach $key (sort keys(dep)) {
+ if ($key =~ /\.o: .*\.h$/ && $dep{$key} == 1) {
+ print $extra,$key,"\n";
+ $extra = '';
+ }
+}
+
+sub scan {
+ local($makefile) = @_;
+ local($MF) = $MF;
+ print stderr "Analyzing $makefile.\n" if $opt_v;
+ $MF++;
+ open($MF,$makefile) || die "Can't open $makefile: $!";
+ while (<$MF>) {
+ chop;
+ chop($_ = $_ . <$MF>) while s/\\$//;
+ next if /^#/;
+ next if /^$/;
+ s/\$\((\w+):([^=)]*)=([^)]*)\)/do subst("$1","$2","$3")/eg;
+ s/\$\((\w+)\)/$mac{$1}/eg;
+ $mac{$1} = $2, next if /^(\w+)\s*=\s*(.*)/;
+ if (/^include\s+(.*)/) {
+ do scan($1);
+ print stderr "Continuing $makefile.\n" if $opt_v;
+ next;
+ }
+ if (/^([^:]+):\s*(.*)/) {
+ $left = $1;
+ $right = $2;
+ if ($right =~ /^([^;]*);(.*)/) {
+ $right = $1;
+ $action = $2;
+ }
+ else {
+ $action = '';
+ }
+ while (<$MF>) {
+ last unless /^\t/;
+ chop;
+ chop($_ = $_ . <$MF>) while s/\\$//;
+ next if /^#/;
+ last if /^$/;
+ s/\$\((\w+):([^=)]*)=([^)]*)\)/do subst("$1","$2","$3")/eg;
+ s/\$\((\w+)\)/$mac{$1}/eg;
+ $action .= $_;
+ }
+ foreach $targ (split(' ',$left)) {
+ $targ =~ s|^\./||;
+ foreach $src (split(' ',$right)) {
+ $src =~ s|^\./||;
+ $deplist{$targ} .= ' ' . $src;
+ $dep{"$targ: $src"} = 1;
+ $o{$src} = 1 if $src =~ /\.o$/;
+ $oc{$targ} = $src if $targ =~ /\.o$/ && $src =~ /\.[yc]$/;
+ }
+ $action{$targ} .= $action;
+ }
+ redo if $_;
+ }
+ }
+ close($MF);
+}
+
+sub subst {
+ local($foo,$from,$to) = @_;
+ $foo = $mac{$foo};
+ $from =~ s/\./[.]/;
+ y/a/a/;
+ $foo =~ s/\b$from\b/$to/g;
+ $foo;
+}
diff --git a/gnu/usr.bin/perl/eg/muck.man b/gnu/usr.bin/perl/eg/muck.man
new file mode 100644
index 0000000..1b45ee0
--- /dev/null
+++ b/gnu/usr.bin/perl/eg/muck.man
@@ -0,0 +1,21 @@
+.\" $Header: /home/cvs/386BSD/ports/lang/perl/eg/muck.man,v 1.1.1.1 1993/08/23 21:29:43 nate Exp $
+.TH MUCK 1 "10 Jan 1989"
+.SH NAME
+muck \- make usage checker
+.SH SYNOPSIS
+.B muck
+[options]
+.SH DESCRIPTION
+.I muck
+looks at your current makefile and complains if you've left out any dependencies
+between .o and .h files.
+It also complains about extraneous dependencies.
+.PP
+You can use the -f FILENAME option to specify an alternate name for your
+makefile.
+The -v option is a little more verbose about what muck is mucking around
+with at the moment.
+.SH SEE ALSO
+make(1)
+.SH BUGS
+Only knows about .h, .c and .o files.
diff --git a/gnu/usr.bin/perl/eg/myrup b/gnu/usr.bin/perl/eg/myrup
new file mode 100644
index 0000000..b318589
--- /dev/null
+++ b/gnu/usr.bin/perl/eg/myrup
@@ -0,0 +1,29 @@
+#!/usr/bin/perl
+
+# $Header: /home/cvs/386BSD/ports/lang/perl/eg/myrup,v 1.1.1.1 1993/08/23 21:29:43 nate Exp $
+
+# This was a customization of ruptime requested by someone here who wanted
+# to be able to find the least loaded machine easily. It uses the
+# /etc/ghosts file that's defined for gsh and gcp to prune down the
+# number of entries to those hosts we have administrative control over.
+
+print "node load (u)\n------- --------\n";
+
+open(ghosts,'/etc/ghosts') || die "Can't open /etc/ghosts: $!";
+line: while (<ghosts>) {
+ next line if /^#/;
+ next line if /^$/;
+ next line if /=/;
+ ($host) = split;
+ $wanted{$host} = 1;
+}
+
+open(ruptime,'ruptime|') || die "Can't run ruptime: $!";
+open(sort,'|sort +1n');
+
+while (<ruptime>) {
+ ($host,$upness,$foo,$users,$foo,$foo,$load) = split(/[\s,]+/);
+ if ($wanted{$host} && $upness eq 'up') {
+ printf sort "%s\t%s (%d)\n", $host, $load, $users;
+ }
+}
diff --git a/gnu/usr.bin/perl/eg/nih b/gnu/usr.bin/perl/eg/nih
new file mode 100644
index 0000000..a376142
--- /dev/null
+++ b/gnu/usr.bin/perl/eg/nih
@@ -0,0 +1,10 @@
+eval "exec /usr/bin/perl -Spi.bak $0 $*"
+ if $running_under_some_shell;
+
+# $Header: /home/cvs/386BSD/ports/lang/perl/eg/nih,v 1.1.1.1 1993/08/23 21:29:43 nate Exp $
+
+# This script makes #! scripts directly executable on machines that don't
+# support #!. It edits in place any scripts mentioned on the command line.
+
+s|^#!(.*)|#!$1\neval "exec $1 -S \$0 \$*"\n\tif \$running_under_some_shell;|
+ if $. == 1;
diff --git a/gnu/usr.bin/perl/eg/perlsh b/gnu/usr.bin/perl/eg/perlsh
new file mode 100644
index 0000000..2b2cccd
--- /dev/null
+++ b/gnu/usr.bin/perl/eg/perlsh
@@ -0,0 +1,15 @@
+#!/usr/bin/perl
+
+# Poor man's perl shell.
+
+# Simply type two carriage returns every time you want to evaluate.
+# Note that it must be a complete perl statement--don't type double
+# carriage return in the middle of a loop.
+
+$/ = "\n\n"; # set paragraph mode
+$SHlinesep = "\n";
+while ($SHcmd = <>) {
+ $/ = $SHlinesep;
+ eval $SHcmd; print $@ || "\n";
+ $SHlinesep = $/; $/ = '';
+}
diff --git a/gnu/usr.bin/perl/eg/relink b/gnu/usr.bin/perl/eg/relink
new file mode 100644
index 0000000..69956c9
--- /dev/null
+++ b/gnu/usr.bin/perl/eg/relink
@@ -0,0 +1,91 @@
+#!/usr/bin/perl
+'di';
+'ig00';
+#
+# $Header: /home/cvs/386BSD/ports/lang/perl/eg/relink,v 1.1.1.1 1993/08/23 21:29:43 nate Exp $
+#
+# $Log: relink,v $
+# Revision 1.1.1.1 1993/08/23 21:29:43 nate
+# PERL!
+#
+# Revision 4.0 91/03/20 01:11:40 lwall
+# 4.0 baseline.
+#
+# Revision 3.0.1.2 90/08/09 03:17:44 lwall
+# patch19: added man page for relink and rename
+#
+
+($op = shift) || die "Usage: relink perlexpr [filenames]\n";
+if (!@ARGV) {
+ @ARGV = <STDIN>;
+ chop(@ARGV);
+}
+for (@ARGV) {
+ next unless -l; # symbolic link?
+ $name = $_;
+ $_ = readlink($_);
+ $was = $_;
+ eval $op;
+ die $@ if $@;
+ if ($was ne $_) {
+ unlink($name);
+ symlink($_, $name);
+ }
+}
+##############################################################################
+
+ # These next few lines are legal in both Perl and nroff.
+
+.00; # finish .ig
+
+'di \" finish diversion--previous line must be blank
+.nr nl 0-1 \" fake up transition to first page again
+.nr % 0 \" start at page 1
+';<<'.ex'; #__END__ ############# From here on it's a standard manual page ############
+.TH RELINK 1 "July 30, 1990"
+.AT 3
+.SH LINK
+relink \- relinks multiple symbolic links
+.SH SYNOPSIS
+.B relink perlexpr [symlinknames]
+.SH DESCRIPTION
+.I Relink
+relinks the symbolic links given according to the rule specified as the
+first argument.
+The argument is a Perl expression which is expected to modify the $_
+string in Perl for at least some of the names specified.
+For each symbolic link named on the command line, the Perl expression
+will be executed on the contents of the symbolic link with that name.
+If a given symbolic link's contents is not modified by the expression,
+it will not be changed.
+If a name given on the command line is not a symbolic link, it will be ignored.
+If no names are given on the command line, names will be read
+via standard input.
+.PP
+For example, to relink all symbolic links in the current directory
+pointing to somewhere in X11R3 so that they point to X11R4, you might say
+.nf
+
+ relink 's/X11R3/X11R4/' *
+
+.fi
+To change all occurences of links in the system from /usr/spool to /var/spool,
+you'd say
+.nf
+
+ find / -type l -print | relink 's#/usr/spool#/var/spool#'
+
+.fi
+.SH ENVIRONMENT
+No environment variables are used.
+.SH FILES
+.SH AUTHOR
+Larry Wall
+.SH "SEE ALSO"
+ln(1)
+.br
+perl(1)
+.SH DIAGNOSTICS
+If you give an invalid Perl expression you'll get a syntax error.
+.SH BUGS
+.ex
diff --git a/gnu/usr.bin/perl/eg/rename b/gnu/usr.bin/perl/eg/rename
new file mode 100644
index 0000000..b568406
--- /dev/null
+++ b/gnu/usr.bin/perl/eg/rename
@@ -0,0 +1,83 @@
+#!/usr/bin/perl
+'di';
+'ig00';
+#
+# $Header: /home/cvs/386BSD/ports/lang/perl/eg/rename,v 1.1.1.1 1993/08/23 21:29:43 nate Exp $
+#
+# $Log: rename,v $
+# Revision 1.1.1.1 1993/08/23 21:29:43 nate
+# PERL!
+#
+# Revision 4.0 91/03/20 01:11:53 lwall
+# 4.0 baseline.
+#
+# Revision 3.0.1.2 90/08/09 03:17:57 lwall
+# patch19: added man page for relink and rename
+#
+
+($op = shift) || die "Usage: rename perlexpr [filenames]\n";
+if (!@ARGV) {
+ @ARGV = <STDIN>;
+ chop(@ARGV);
+}
+for (@ARGV) {
+ $was = $_;
+ eval $op;
+ die $@ if $@;
+ rename($was,$_) unless $was eq $_;
+}
+##############################################################################
+
+ # These next few lines are legal in both Perl and nroff.
+
+.00; # finish .ig
+
+'di \" finish diversion--previous line must be blank
+.nr nl 0-1 \" fake up transition to first page again
+.nr % 0 \" start at page 1
+';<<'.ex'; #__END__ ############# From here on it's a standard manual page ############
+.TH RENAME 1 "July 30, 1990"
+.AT 3
+.SH NAME
+rename \- renames multiple files
+.SH SYNOPSIS
+.B rename perlexpr [files]
+.SH DESCRIPTION
+.I Rename
+renames the filenames supplied according to the rule specified as the
+first argument.
+The argument is a Perl expression which is expected to modify the $_
+string in Perl for at least some of the filenames specified.
+If a given filename is not modified by the expression, it will not be
+renamed.
+If no filenames are given on the command line, filenames will be read
+via standard input.
+.PP
+For example, to rename all files matching *.bak to strip the extension,
+you might say
+.nf
+
+ rename 's/\e.bak$//' *.bak
+
+.fi
+To translate uppercase names to lower, you'd use
+.nf
+
+ rename 'y/A-Z/a-z/' *
+
+.fi
+.SH ENVIRONMENT
+No environment variables are used.
+.SH FILES
+.SH AUTHOR
+Larry Wall
+.SH "SEE ALSO"
+mv(1)
+.br
+perl(1)
+.SH DIAGNOSTICS
+If you give an invalid Perl expression you'll get a syntax error.
+.SH BUGS
+.I Rename
+does not check for the existence of target filenames, so use with care.
+.ex
diff --git a/gnu/usr.bin/perl/eg/rmfrom b/gnu/usr.bin/perl/eg/rmfrom
new file mode 100644
index 0000000..0c8fa2c
--- /dev/null
+++ b/gnu/usr.bin/perl/eg/rmfrom
@@ -0,0 +1,7 @@
+#!/usr/bin/perl -n
+
+# $Header: /home/cvs/386BSD/ports/lang/perl/eg/rmfrom,v 1.1.1.1 1993/08/23 21:29:43 nate Exp $
+
+# A handy (but dangerous) script to put after a find ... -print.
+
+chop; unlink;
diff --git a/gnu/usr.bin/perl/eg/scan/scan_df b/gnu/usr.bin/perl/eg/scan/scan_df
new file mode 100644
index 0000000..6887387
--- /dev/null
+++ b/gnu/usr.bin/perl/eg/scan/scan_df
@@ -0,0 +1,51 @@
+#!/usr/bin/perl -P
+
+# $Header: /home/cvs/386BSD/ports/lang/perl/eg/scan/scan_df,v 1.1.1.1 1993/08/23 21:29:44 nate Exp $
+
+# This report points out filesystems that are in danger of overflowing.
+
+(chdir '/usr/adm/private/memories') || die "Can't cd to memories: $!\n";
+`df >newdf`;
+open(Df, 'olddf');
+
+while (<Df>) {
+ ($fs,$kbytes,$used,$avail,$capacity,$mounted_on) = split;
+ next if $fs =~ /:/;
+ next if $fs eq '';
+ $oldused{$fs} = $used;
+}
+
+open(Df, 'newdf') || die "scan_df: can't open newdf";
+
+while (<Df>) {
+ ($fs,$kbytes,$used,$avail,$capacity,$mounted_on) = split;
+ next if $fs =~ /:/;
+ next if $fs eq '';
+ $oldused = $oldused{$fs};
+ next if ($oldused == $used && $capacity < 99); # inactive filesystem
+ if ($capacity >= 90) {
+#if defined(mc300) || defined(mc500) || defined(mc700)
+ $_ = substr($_,0,13) . ' ' . substr($_,13,1000);
+ $kbytes /= 2; # translate blocks to K
+ $used /= 2;
+ $oldused /= 2;
+ $avail /= 2;
+#endif
+ $diff = int($used - $oldused);
+ if ($avail < $diff * 2) { # mark specially if in danger
+ $mounted_on .= ' *';
+ }
+ next if $diff < 50 && $mounted_on eq '/';
+ $fs =~ s|/dev/||;
+ if ($diff >= 0) {
+ $diff = '(+' . $diff . ')';
+ }
+ else {
+ $diff = '(' . $diff . ')';
+ }
+ printf "%-8s%8d%8d %-8s%8d%7s %s\n",
+ $fs,$kbytes,$used,$diff,$avail,$capacity,$mounted_on;
+ }
+}
+
+rename('newdf','olddf');
diff --git a/gnu/usr.bin/perl/eg/scan/scan_last b/gnu/usr.bin/perl/eg/scan/scan_last
new file mode 100644
index 0000000..6621120
--- /dev/null
+++ b/gnu/usr.bin/perl/eg/scan/scan_last
@@ -0,0 +1,57 @@
+#!/usr/bin/perl -P
+
+# $Header: /home/cvs/386BSD/ports/lang/perl/eg/scan/scan_last,v 1.1.1.1 1993/08/23 21:29:45 nate Exp $
+
+# This reports who was logged on at weird hours
+
+($dy, $mo, $lastdt) = split(/ +/,`date`);
+
+open(Last, 'exec last 2>&1 |') || die "scan_last: can't run last";
+
+while (<Last>) {
+#if defined(mc300) || defined(mc500) || defined(mc700)
+ $_ = substr($_,0,19) . substr($_,23,100);
+#endif
+ next if /^$/;
+ (print),next if m|^/|;
+ $login = substr($_,0,8);
+ $tty = substr($_,10,7);
+ $from = substr($_,19,15);
+ $day = substr($_,36,3);
+ $mo = substr($_,40,3);
+ $dt = substr($_,44,2);
+ $hr = substr($_,47,2);
+ $min = substr($_,50,2);
+ $dash = substr($_,53,1);
+ $tohr = substr($_,55,2);
+ $tomin = substr($_,58,2);
+ $durhr = substr($_,63,2);
+ $durmin = substr($_,66,2);
+
+ next unless $hr;
+ next if $login eq 'reboot ';
+ next if $login eq 'shutdown';
+
+ if ($dt != $lastdt) {
+ if ($lastdt < $dt) {
+ $seen += $dt - $lastdt;
+ }
+ else {
+ $seen++;
+ }
+ $lastdt = $dt;
+ }
+
+ $inat = $hr + $min / 60;
+ if ($tohr =~ /^[a-z]/) {
+ $outat = 12; # something innocuous
+ } else {
+ $outat = $tohr + $tomin / 60;
+ }
+
+ last if $seen + ($inat < 8) > 1;
+
+ if ($inat < 5 || $inat > 21 || $outat < 6 || $outat > 23) {
+ print;
+ }
+}
diff --git a/gnu/usr.bin/perl/eg/scan/scan_messages b/gnu/usr.bin/perl/eg/scan/scan_messages
new file mode 100644
index 0000000..a28cda8
--- /dev/null
+++ b/gnu/usr.bin/perl/eg/scan/scan_messages
@@ -0,0 +1,222 @@
+#!/usr/bin/perl -P
+
+# $Header: /home/cvs/386BSD/ports/lang/perl/eg/scan/scan_messages,v 1.1.1.1 1993/08/23 21:29:44 nate Exp $
+
+# This prints out extraordinary console messages. You'll need to customize.
+
+chdir('/usr/adm/private/memories') || die "Can't cd to memories: $!\n";
+
+$maxpos = `cat oldmsgs 2>&1`;
+
+#if defined(mc300) || defined(mc500) || defined(mc700)
+open(Msgs, '/dev/null') || die "scan_messages: can't open messages";
+#else
+open(Msgs, '/usr/adm/messages') || die "scan_messages: can't open messages";
+#endif
+
+($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,$atime,$mtime,$ctime,
+ $blksize,$blocks) = stat(Msgs);
+
+if ($size < $maxpos) { # Did somebody truncate messages file?
+ $maxpos = 0;
+}
+
+seek(Msgs,$maxpos,0); # Start where we left off last time.
+
+while (<Msgs>) {
+ s/\[(\d+)\]/#/ && s/$1/#/g;
+#ifdef vax
+ $_ =~ s/[A-Z][a-z][a-z] +\w+ +[0-9:]+ +\w+ +//;
+ next if /root@.*:/;
+ next if /^vmunix: 4.3 BSD UNIX/;
+ next if /^vmunix: Copyright/;
+ next if /^vmunix: avail mem =/;
+ next if /^vmunix: SBIA0 at /;
+ next if /^vmunix: disk ra81 is/;
+ next if /^vmunix: dmf. at uba/;
+ next if /^vmunix: dmf.:.*asynch/;
+ next if /^vmunix: ex. at uba/;
+ next if /^vmunix: ex.: HW/;
+ next if /^vmunix: il. at uba/;
+ next if /^vmunix: il.: hardware/;
+ next if /^vmunix: ra. at uba/;
+ next if /^vmunix: ra.: media/;
+ next if /^vmunix: real mem/;
+ next if /^vmunix: syncing disks/;
+ next if /^vmunix: tms/;
+ next if /^vmunix: tmscp. at uba/;
+ next if /^vmunix: uba. at /;
+ next if /^vmunix: uda. at /;
+ next if /^vmunix: uda.: unit . ONLIN/;
+ next if /^vmunix: .*buffers containing/;
+ next if /^syslogd: .*newslog/;
+#endif
+ next if /unknown service/;
+ next if /^\.\.\.$/;
+ if (/^[A-Z][a-z][a-z] [ 0-9][0-9] [ 0-9][0-9]:[0-9][0-9]/) {
+ $pfx = '';
+ next;
+ }
+ next if /^[ \t]*$/;
+ next if /^[ 0-9]*done$/;
+ if (/^A/) {
+ next if /^Accounting [sr]/;
+ }
+ elsif (/^C/) {
+ next if /^Called from/;
+ next if /^Copyright/;
+ }
+ elsif (/^E/) {
+ next if /^End traceback/;
+ next if /^Ethernet address =/;
+ }
+ elsif (/^K/) {
+ next if /^KERNEL MODE/;
+ }
+ elsif (/^R/) {
+ next if /^Rebooting Unix/;
+ }
+ elsif (/^S/) {
+ next if /^Sun UNIX 4\.2 Release/;
+ }
+ elsif (/^W/) {
+ next if /^WARNING: clock gained/;
+ }
+ elsif (/^a/) {
+ next if /^arg /;
+ next if /^avail mem =/;
+ }
+ elsif (/^b/) {
+ next if /^bwtwo[0-9] at /;
+ }
+ elsif (/^c/) {
+ next if /^cgone[0-9] at /;
+ next if /^cdp[0-9] at /;
+ next if /^csr /;
+ }
+ elsif (/^d/) {
+ next if /^dcpa: init/;
+ next if /^done$/;
+ next if /^dts/;
+ next if /^dump i\/o error/;
+ next if /^dumping to dev/;
+ next if /^dump succeeded/;
+ $pfx = '*' if /^dev = /;
+ }
+ elsif (/^e/) {
+ next if /^end \*\*/;
+ next if /^error in copy/;
+ }
+ elsif (/^f/) {
+ next if /^found /;
+ }
+ elsif (/^i/) {
+ next if /^ib[0-9] at /;
+ next if /^ie[0-9] at /;
+ }
+ elsif (/^l/) {
+ next if /^le[0-9] at /;
+ }
+ elsif (/^m/) {
+ next if /^mem = /;
+ next if /^mt[0-9] at /;
+ next if /^mti[0-9] at /;
+ $pfx = '*' if /^mode = /;
+ }
+ elsif (/^n/) {
+ next if /^not found /;
+ }
+ elsif (/^p/) {
+ next if /^page map /;
+ next if /^pi[0-9] at /;
+ $pfx = '*' if /^panic/;
+ }
+ elsif (/^q/) {
+ next if /^qqq /;
+ }
+ elsif (/^r/) {
+ next if /^read /;
+ next if /^revarp: Requesting/;
+ next if /^root [od]/;
+ }
+ elsif (/^s/) {
+ next if /^sc[0-9] at /;
+ next if /^sd[0-9] at /;
+ next if /^sd[0-9]: </;
+ next if /^si[0-9] at /;
+ next if /^si_getstatus/;
+ next if /^sk[0-9] at /;
+ next if /^skioctl/;
+ next if /^skopen/;
+ next if /^skprobe/;
+ next if /^skread/;
+ next if /^skwrite/;
+ next if /^sky[0-9] at /;
+ next if /^st[0-9] at /;
+ next if /^st0:.*load/;
+ next if /^stat1 = /;
+ next if /^syncing disks/;
+ next if /^syslogd: going down on signal 15/;
+ }
+ elsif (/^t/) {
+ next if /^timeout [0-9]/;
+ next if /^tm[0-9] at /;
+ next if /^tod[0-9] at /;
+ next if /^tv [0-9]/;
+ $pfx = '*' if /^trap address/;
+ }
+ elsif (/^u/) {
+ next if /^unit nsk/;
+ next if /^use one of/;
+ $pfx = '' if /^using/;
+ next if /^using [0-9]+ buffers/;
+ }
+ elsif (/^x/) {
+ next if /^xy[0-9] at /;
+ next if /^write [0-9]/;
+ next if /^xy[0-9]: </;
+ next if /^xyc[0-9] at /;
+ }
+ elsif (/^y/) {
+ next if /^yyy [0-9]/;
+ }
+ elsif (/^z/) {
+ next if /^zs[0-9] at /;
+ }
+ $pfx = '*' if /^[a-z]+:$/;
+ s/pid [0-9]+: //;
+ if (/last message repeated ([0-9]+) time/) {
+ $seen{$last} += $1;
+ next;
+ }
+ s/^/$pfx/ if $pfx;
+ unless ($seen{$_}++) {
+ push(@seen,$_);
+ }
+ $last = $_;
+}
+$max = tell(Msgs);
+
+open(tmp,'|sort >oldmsgs.tmp') || die "Can't create tmp file: $!\n";
+while ($_ = pop(@seen)) {
+ print tmp $_;
+}
+close(tmp);
+open(tmp,'oldmsgs.tmp') || die "Can't reopen tmp file: $!\n";
+while (<tmp>) {
+ if (/^nd:/) {
+ next if $seen{$_} < 20;
+ }
+ if (/NFS/) {
+ next if $seen{$_} < 20;
+ }
+ if (/no carrier/) {
+ next if $seen{$_} < 20;
+ }
+ if (/silo overflow/) {
+ next if $seen{$_} < 20;
+ }
+ print $seen{$_},":\t",$_;
+}
+
+print `rm -f oldmsgs.tmp 2>&1; echo $max > oldmsgs 2>&1`;
diff --git a/gnu/usr.bin/perl/eg/scan/scan_passwd b/gnu/usr.bin/perl/eg/scan/scan_passwd
new file mode 100644
index 0000000..f9c53c7d
--- /dev/null
+++ b/gnu/usr.bin/perl/eg/scan/scan_passwd
@@ -0,0 +1,30 @@
+#!/usr/bin/perl
+
+# $Header: /home/cvs/386BSD/ports/lang/perl/eg/scan/scan_passwd,v 1.1.1.1 1993/08/23 21:29:45 nate Exp $
+
+# This scans passwd file for security holes.
+
+open(Pass,'/etc/passwd') || die "Can't open passwd file: $!\n";
+# $dotriv = (`date` =~ /^Mon/);
+$dotriv = 1;
+
+while (<Pass>) {
+ ($login,$pass,$uid,$gid,$gcos,$home,$shell) = split(/:/);
+ if ($shell eq '') {
+ print "Short: $_";
+ }
+ next if /^[+]/;
+ if ($pass eq '') {
+ if (index(":sync:lpq:+:", ":$login:") < 0) {
+ print "No pass: $login\t$gcos\n";
+ }
+ }
+ elsif ($dotriv && crypt($login,substr($pass,0,2)) eq $pass) {
+ print "Trivial: $login\t$gcos\n";
+ }
+ if ($uid == 0) {
+ if ($login !~ /^.?root$/ && $pass ne '*') {
+ print "Extra root: $_";
+ }
+ }
+}
diff --git a/gnu/usr.bin/perl/eg/scan/scan_ps b/gnu/usr.bin/perl/eg/scan/scan_ps
new file mode 100644
index 0000000..b0480d5
--- /dev/null
+++ b/gnu/usr.bin/perl/eg/scan/scan_ps
@@ -0,0 +1,32 @@
+#!/usr/bin/perl -P
+
+# $Header: /home/cvs/386BSD/ports/lang/perl/eg/scan/scan_ps,v 1.1.1.1 1993/08/23 21:29:45 nate Exp $
+
+# This looks for looping processes.
+
+#if defined(mc300) || defined(mc500) || defined(mc700)
+open(Ps, '/bin/ps -el|') || die "scan_ps: can't run ps";
+
+while (<Ps>) {
+ next if /rwhod/;
+ print if index(' T', substr($_,62,1)) < 0;
+}
+#else
+open(Ps, '/bin/ps auxww|') || die "scan_ps: can't run ps";
+
+while (<Ps>) {
+ next if /dataserver/;
+ next if /nfsd/;
+ next if /update/;
+ next if /ypserv/;
+ next if /rwhod/;
+ next if /routed/;
+ next if /pagedaemon/;
+#ifdef vax
+ ($user,$pid,$cpu,$mem,$sz,$rss,$tt,$stat,$start,$time) = split;
+#else
+ ($user,$pid,$cpu,$mem,$sz,$rss,$tt,$stat,$time) = split;
+#endif
+ print if length($time) > 4;
+}
+#endif
diff --git a/gnu/usr.bin/perl/eg/scan/scan_sudo b/gnu/usr.bin/perl/eg/scan/scan_sudo
new file mode 100644
index 0000000..a95a609
--- /dev/null
+++ b/gnu/usr.bin/perl/eg/scan/scan_sudo
@@ -0,0 +1,54 @@
+#!/usr/bin/perl -P
+
+# $Header: /home/cvs/386BSD/ports/lang/perl/eg/scan/scan_sudo,v 1.1.1.1 1993/08/23 21:29:45 nate Exp $
+
+# Analyze the sudo log.
+
+chdir('/usr/adm/private/memories') || die "Can't cd to memories: $!\n";
+
+if (open(Oldsudo,'oldsudo')) {
+ $maxpos = <Oldsudo>;
+ close Oldsudo;
+}
+else {
+ $maxpos = 0;
+ `echo 0 >oldsudo`;
+}
+
+unless (open(Sudo, '/usr/adm/sudo.log')) {
+ print "Somebody removed sudo.log!!!\n" if $maxpos;
+ exit 0;
+}
+
+($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,$atime,$mtime,$ctime,
+ $blksize,$blocks) = stat(Sudo);
+
+if ($size < $maxpos) {
+ $maxpos = 0;
+ print "Somebody reset sudo.log!!!\n";
+}
+
+seek(Sudo,$maxpos,0);
+
+while (<Sudo>) {
+ s/^.* :[ \t]+//;
+ s/ipcrm.*/ipcrm/;
+ s/kill.*/kill/;
+ unless ($seen{$_}++) {
+ push(@seen,$_);
+ }
+ $last = $_;
+}
+$max = tell(Sudo);
+
+open(tmp,'|sort >oldsudo.tmp') || die "Can't create tmp file: $!\n";
+while ($_ = pop(@seen)) {
+ print tmp $_;
+}
+close(tmp);
+open(tmp,'oldsudo.tmp') || die "Can't reopen tmp file: $!\n";
+while (<tmp>) {
+ print $seen{$_},":\t",$_;
+}
+
+print `(rm -f oldsudo.tmp; echo $max > oldsudo) 2>&1`;
diff --git a/gnu/usr.bin/perl/eg/scan/scan_suid b/gnu/usr.bin/perl/eg/scan/scan_suid
new file mode 100644
index 0000000..a730e0a
--- /dev/null
+++ b/gnu/usr.bin/perl/eg/scan/scan_suid
@@ -0,0 +1,84 @@
+#!/usr/bin/perl -P
+
+# $Header: /home/cvs/386BSD/ports/lang/perl/eg/scan/scan_suid,v 1.1.1.1 1993/08/23 21:29:44 nate Exp $
+
+# Look for new setuid root files.
+
+chdir '/usr/adm/private/memories' || die "Can't cd to memories: $!\n";
+
+($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,$atime,$mtime,$ctime,
+ $blksize,$blocks) = stat('oldsuid');
+if ($nlink) {
+ $lasttime = $mtime;
+ $tmp = $ctime - $atime;
+ if ($tmp <= 0 || $tmp >= 10) {
+ print "WARNING: somebody has read oldsuid!\n";
+ }
+ $tmp = $ctime - $mtime;
+ if ($tmp <= 0 || $tmp >= 10) {
+ print "WARNING: somebody has modified oldsuid!!!\n";
+ }
+} else {
+ $lasttime = time - 60 * 60 * 24; # one day ago
+}
+$thistime = time;
+
+#if defined(mc300) || defined(mc500) || defined(mc700)
+open(Find, 'find / -perm -04000 -print |') ||
+ die "scan_find: can't run find";
+#else
+open(Find, 'find / \( -fstype nfs -prune \) -o -perm -04000 -ls |') ||
+ die "scan_find: can't run find";
+#endif
+
+open(suid, '>newsuid.tmp');
+
+while (<Find>) {
+
+#if defined(mc300) || defined(mc500) || defined(mc700)
+ $x = `/bin/ls -il $_`;
+ $_ = $x;
+ s/^ *//;
+ ($inode,$perm,$links,$owner,$group,$size,$month,$day,$time,$name)
+ = split;
+#else
+ s/^ *//;
+ ($inode,$blocks,$perm,$links,$owner,$group,$size,$month,$day,$time,$name)
+ = split;
+#endif
+
+ if ($perm =~ /[sS]/ && $owner eq 'root') {
+ ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,$atime,$mtime,$ctime,
+ $blksize,$blocks) = stat($name);
+ $foo = sprintf("%10s%3s %-8s %-8s%9s %3s %2s %s %s\n",
+ $perm,$links,$owner,$group,$size,$month,$day,$name,$inode);
+ print suid $foo;
+ if ($ctime > $lasttime) {
+ if ($ctime > $thistime) {
+ print "Future file: $foo";
+ }
+ else {
+ $ct .= $foo;
+ }
+ }
+ }
+}
+close(suid);
+
+print `sort +7 -8 newsuid.tmp >newsuid 2>&1`;
+$foo = `/bin/diff oldsuid newsuid 2>&1`;
+print "Differences in suid info:\n",$foo if $foo;
+print `mv oldsuid oldoldsuid 2>&1; mv newsuid oldsuid 2>&1`;
+print `touch oldsuid 2>&1;sleep 2 2>&1;chmod o+w oldsuid 2>&1`;
+print `rm -f newsuid.tmp 2>&1`;
+
+@ct = split(/\n/,$ct);
+$ct = '';
+$* = 1;
+while ($#ct >= 0) {
+ $tmp = shift(@ct);
+ unless ($foo =~ "^>.*$tmp\n") { $ct .= "$tmp\n"; }
+}
+
+print "Inode changed since last time:\n",$ct if $ct;
+
diff --git a/gnu/usr.bin/perl/eg/scan/scanner b/gnu/usr.bin/perl/eg/scan/scanner
new file mode 100644
index 0000000..f773e87
--- /dev/null
+++ b/gnu/usr.bin/perl/eg/scan/scanner
@@ -0,0 +1,87 @@
+#!/usr/bin/perl
+
+# $Header: /home/cvs/386BSD/ports/lang/perl/eg/scan/scanner,v 1.1.1.1 1993/08/23 21:29:44 nate Exp $
+
+# This runs all the scan_* routines on all the machines in /etc/ghosts.
+# We run this every morning at about 6 am:
+
+# !/bin/sh
+# cd /usr/adm/private
+# decrypt scanner | perl >scan.out 2>&1
+# mail admin <scan.out
+
+# Note that the scan_* files should be encrypted with the key "-inquire", and
+# scanner should be encrypted somehow so that people can't find that key.
+# I leave it up to you to figure out how to unencrypt it before executing.
+
+$ENV{'PATH'} = '/bin:/usr/bin:/usr/local/bin:/usr/ucb:.';
+
+$| = 1; # command buffering on stdout
+
+print "Subject: bizarre happenings\n\n";
+
+(chdir '/usr/adm/private') || die "Can't cd to /usr/adm/private: $!\n";
+
+if ($#ARGV >= 0) {
+ @scanlist = @ARGV;
+} else {
+ @scanlist = split(/[ \t\n]+/,`echo scan_*`);
+}
+
+scan: while ($scan = shift(@scanlist)) {
+ print "\n********** $scan **********\n";
+ $showhost++;
+
+ $systype = 'all';
+
+ open(ghosts, '/etc/ghosts') || die 'No /etc/ghosts file';
+
+ $one_of_these = ":$systype:";
+ if ($systype =~ s/\+/[+]/g) {
+ $one_of_these =~ s/\+/:/g;
+ }
+
+ line: while (<ghosts>) {
+ s/[ \t]*\n//;
+ if (!$_ || /^#/) {
+ next line;
+ }
+ if (/^([a-zA-Z_0-9]+)=(.+)/) {
+ $name = $1; $repl = $2;
+ $repl =~ s/\+/:/g;
+ $one_of_these =~ s/:$name:/:$repl:/;
+ next line;
+ }
+ @gh = split;
+ $host = $gh[0];
+ if ($showhost) { $showhost = "$host:\t"; }
+ class: while ($class = pop(gh)) {
+ if (index($one_of_these,":$class:") >=0) {
+ $iter = 0;
+ `exec crypt -inquire <$scan >.x 2>/dev/null`;
+ unless (open(scan,'.x')) {
+ print "Can't run $scan: $!\n";
+ next scan;
+ }
+ $cmd = <scan>;
+ unless ($cmd =~ s/#!(.*)\n/$1/) {
+ $cmd = '/usr/bin/perl';
+ }
+ close(scan);
+ if (open(PIPE,"exec rsh $host '$cmd' <.x|")) {
+ sleep(5);
+ unlink '.x';
+ while (<PIPE>) {
+ last if $iter++ > 1000; # must be looping
+ next if /^[0-9.]+u [0-9.]+s/;
+ print $showhost,$_;
+ }
+ close(PIPE);
+ } else {
+ print "(Can't execute rsh: $!)\n";
+ }
+ last class;
+ }
+ }
+ }
+}
diff --git a/gnu/usr.bin/perl/eg/server b/gnu/usr.bin/perl/eg/server
new file mode 100644
index 0000000..49a140a
--- /dev/null
+++ b/gnu/usr.bin/perl/eg/server
@@ -0,0 +1,27 @@
+#!./perl
+
+$pat = 'S n C4 x8';
+$inet = 2;
+$echo = 7;
+$smtp = 25;
+$nntp = 119;
+
+$this = pack($pat,$inet,2345, 0,0,0,0);
+select(NS); $| = 1; select(stdout);
+
+if (socket(S,2,1,6)) { print "socket ok\n"; } else { die $!; }
+if (bind(S,$this)) { print "bind ok\n"; } else { die $!; }
+if (listen(S,5)) { print "listen ok\n"; } else { die $!; }
+for (;;) {
+ print "Listening again\n";
+ if ($addr = accept(NS,S)) { print "accept ok\n"; } else { die $!; }
+
+ @ary = unpack($pat,$addr);
+ $, = ' ';
+ print @ary; print "\n";
+
+ while (<NS>) {
+ print;
+ print NS;
+ }
+}
diff --git a/gnu/usr.bin/perl/eg/shmkill b/gnu/usr.bin/perl/eg/shmkill
new file mode 100644
index 0000000..e8d1b11
--- /dev/null
+++ b/gnu/usr.bin/perl/eg/shmkill
@@ -0,0 +1,24 @@
+#!/usr/bin/perl
+
+# $Header: /home/cvs/386BSD/ports/lang/perl/eg/shmkill,v 1.1.1.1 1993/08/23 21:29:43 nate Exp $
+
+# A script to call from crontab periodically when people are leaving shared
+# memory sitting around unattached.
+
+open(ipcs,'ipcs -m -o|') || die "Can't run ipcs: $!";
+
+while (<ipcs>) {
+ $tmp = index($_,'NATTCH');
+ $pos = $tmp if $tmp >= 0;
+ if (/^m/) {
+ ($m,$id,$key,$mode,$owner,$group,$attach) = split;
+ if ($attach != substr($_,$pos,6)) {
+ die "Different ipcs format--can't parse!\n";
+ }
+ if ($attach == 0) {
+ push(@goners,'-m',$id);
+ }
+ }
+}
+
+exec 'ipcrm', @goners if $#goners >= 0;
diff --git a/gnu/usr.bin/perl/eg/sysvipc/README b/gnu/usr.bin/perl/eg/sysvipc/README
new file mode 100644
index 0000000..54094f1
--- /dev/null
+++ b/gnu/usr.bin/perl/eg/sysvipc/README
@@ -0,0 +1,9 @@
+FYEnjoyment, here are the test scripts I used while implementing SysV
+IPC in Perl. Each of them must be run with the parameter "s" for
+"send" or "r" for "receive"; in each case, the receiver is the server
+and the sender is the client.
+
+--
+Chip Salzenberg at ComDev/TCT <chip@tct.uucp>, <uunet!ateng!tct!chip>
+
+
diff --git a/gnu/usr.bin/perl/eg/sysvipc/ipcmsg b/gnu/usr.bin/perl/eg/sysvipc/ipcmsg
new file mode 100644
index 0000000..317e027
--- /dev/null
+++ b/gnu/usr.bin/perl/eg/sysvipc/ipcmsg
@@ -0,0 +1,47 @@
+#!/usr/bin/perl
+eval 'exec /usr/bin/perl -S $0 ${1+"$@"}'
+ if 0;
+
+require 'sys/ipc.ph';
+require 'sys/msg.ph';
+
+$| = 1;
+
+$mode = shift;
+die "usage: ipcmsg {r|s}\n" unless $mode =~ /^[rs]$/;
+$send = ($mode eq "s");
+
+$id = msgget(0x1234, ($send ? 0 : &IPC_CREAT) | 0644);
+die "Can't get message queue: $!\n" unless defined($id);
+print "message queue id: $id\n";
+
+if ($send) {
+ while (<STDIN>) {
+ chop;
+ unless (msgsnd($id, pack("LA*", $., $_), 0)) {
+ die "Can't send message: $!\n";
+ }
+ }
+}
+else {
+ $SIG{'INT'} = $SIG{'QUIT'} = "leave";
+ for (;;) {
+ unless (msgrcv($id, $_, 512, 0, 0)) {
+ die "Can't receive message: $!\n";
+ }
+ ($type, $message) = unpack("La*", $_);
+ printf "[%d] %s\n", $type, $message;
+ }
+}
+
+&leave;
+
+sub leave {
+ if (!$send) {
+ $x = msgctl($id, &IPC_RMID, 0);
+ if (!defined($x) || $x < 0) {
+ die "Can't remove message queue: $!\n";
+ }
+ }
+ exit;
+}
diff --git a/gnu/usr.bin/perl/eg/sysvipc/ipcsem b/gnu/usr.bin/perl/eg/sysvipc/ipcsem
new file mode 100644
index 0000000..d72a2dd
--- /dev/null
+++ b/gnu/usr.bin/perl/eg/sysvipc/ipcsem
@@ -0,0 +1,46 @@
+#!/usr/bin/perl
+eval 'exec /usr/bin/perl -S $0 ${1+"$@"}'
+ if 0;
+
+require 'sys/ipc.ph';
+require 'sys/msg.ph';
+
+$| = 1;
+
+$mode = shift;
+die "usage: ipcmsg {r|s}\n" unless $mode =~ /^[rs]$/;
+$signal = ($mode eq "s");
+
+$id = semget(0x1234, 1, ($signal ? 0 : &IPC_CREAT) | 0644);
+die "Can't get semaphore: $!\n" unless defined($id);
+print "semaphore id: $id\n";
+
+if ($signal) {
+ while (<STDIN>) {
+ print "Signalling\n";
+ unless (semop($id, 0, pack("sss", 0, 1, 0))) {
+ die "Can't signal semaphore: $!\n";
+ }
+ }
+}
+else {
+ $SIG{'INT'} = $SIG{'QUIT'} = "leave";
+ for (;;) {
+ unless (semop($id, 0, pack("sss", 0, -1, 0))) {
+ die "Can't wait for semaphore: $!\n";
+ }
+ print "Unblocked\n";
+ }
+}
+
+&leave;
+
+sub leave {
+ if (!$signal) {
+ $x = semctl($id, 0, &IPC_RMID, 0);
+ if (!defined($x) || $x < 0) {
+ die "Can't remove semaphore: $!\n";
+ }
+ }
+ exit;
+}
diff --git a/gnu/usr.bin/perl/eg/sysvipc/ipcshm b/gnu/usr.bin/perl/eg/sysvipc/ipcshm
new file mode 100644
index 0000000..d40e46b
--- /dev/null
+++ b/gnu/usr.bin/perl/eg/sysvipc/ipcshm
@@ -0,0 +1,50 @@
+#!/usr/bin/perl
+eval 'exec /usr/bin/perl -S $0 ${1+"$@"}'
+ if 0;
+
+require 'sys/ipc.ph';
+require 'sys/shm.ph';
+
+$| = 1;
+
+$mode = shift;
+die "usage: ipcshm {r|s}\n" unless $mode =~ /^[rs]$/;
+$send = ($mode eq "s");
+
+$SIZE = 32;
+$id = shmget(0x1234, $SIZE, ($send ? 0 : &IPC_CREAT) | 0644);
+die "Can't get shared memory: $!\n" unless defined($id);
+print "shared memory id: $id\n";
+
+if ($send) {
+ while (<STDIN>) {
+ chop;
+ unless (shmwrite($id, pack("La*", length($_), $_), 0, $SIZE)) {
+ die "Can't write to shared memory: $!\n";
+ }
+ }
+}
+else {
+ $SIG{'INT'} = $SIG{'QUIT'} = "leave";
+ for (;;) {
+ $_ = <STDIN>;
+ unless (shmread($id, $_, 0, $SIZE)) {
+ die "Can't read shared memory: $!\n";
+ }
+ $len = unpack("L", $_);
+ $message = substr($_, length(pack("L",0)), $len);
+ printf "[%d] %s\n", $len, $message;
+ }
+}
+
+&leave;
+
+sub leave {
+ if (!$send) {
+ $x = shmctl($id, &IPC_RMID, 0);
+ if (!defined($x) || $x < 0) {
+ die "Can't remove shared memory: $!\n";
+ }
+ }
+ exit;
+}
diff --git a/gnu/usr.bin/perl/eg/travesty b/gnu/usr.bin/perl/eg/travesty
new file mode 100644
index 0000000..7e6f983
--- /dev/null
+++ b/gnu/usr.bin/perl/eg/travesty
@@ -0,0 +1,46 @@
+#!/usr/bin/perl
+
+while (<>) {
+ next if /^\./;
+ next if /^From / .. /^$/;
+ next if /^Path: / .. /^$/;
+ s/^\W+//;
+ push(@ary,split(' '));
+ while ($#ary > 1) {
+ $a = $p;
+ $p = $n;
+ $w = shift(@ary);
+ $n = $num{$w};
+ if ($n eq '') {
+ push(@word,$w);
+ $n = pack('S',$#word);
+ $num{$w} = $n;
+ }
+ $lookup{$a . $p} .= $n;
+ }
+}
+
+for (;;) {
+ $n = $lookup{$a . $p};
+ ($foo,$n) = each(lookup) if $n eq '';
+ $n = substr($n,int(rand(length($n))) & 0177776,2);
+ $a = $p;
+ $p = $n;
+ ($w) = unpack('S',$n);
+ $w = $word[$w];
+ $col += length($w) + 1;
+ if ($col >= 65) {
+ $col = 0;
+ print "\n";
+ }
+ else {
+ print ' ';
+ }
+ print $w;
+ if ($w =~ /\.$/) {
+ if (rand() < .1) {
+ print "\n";
+ $col = 80;
+ }
+ }
+}
diff --git a/gnu/usr.bin/perl/eg/van/empty b/gnu/usr.bin/perl/eg/van/empty
new file mode 100644
index 0000000..ee656e6
--- /dev/null
+++ b/gnu/usr.bin/perl/eg/van/empty
@@ -0,0 +1,45 @@
+#!/usr/bin/perl
+
+# $Header: /home/cvs/386BSD/ports/lang/perl/eg/van/empty,v 1.1.1.1 1993/08/23 21:29:45 nate Exp $
+
+# This script empties a trashcan.
+
+$recursive = shift if $ARGV[0] eq '-r';
+
+@ARGV = '.' if $#ARGV < 0;
+
+chop($pwd = `pwd`);
+
+dir: foreach $dir (@ARGV) {
+ unless (chdir $dir) {
+ print stderr "Can't find directory $dir: $!\n";
+ next dir;
+ }
+ if ($recursive) {
+ do cmd('find . -name .deleted -exec /bin/rm -rf {} ;');
+ }
+ else {
+ if (-d '.deleted') {
+ do cmd('rm -rf .deleted');
+ }
+ else {
+ if ($dir eq '.' && $pwd =~ m|/\.deleted$|) {
+ chdir '..';
+ do cmd('rm -rf .deleted');
+ }
+ else {
+ print stderr "No trashcan found in directory $dir\n";
+ }
+ }
+ }
+}
+continue {
+ chdir $pwd;
+}
+
+# force direct execution with no shell
+
+sub cmd {
+ system split(' ',join(' ',@_));
+}
+
diff --git a/gnu/usr.bin/perl/eg/van/unvanish b/gnu/usr.bin/perl/eg/van/unvanish
new file mode 100644
index 0000000..5045982
--- /dev/null
+++ b/gnu/usr.bin/perl/eg/van/unvanish
@@ -0,0 +1,66 @@
+#!/usr/bin/perl
+
+# $Header: /home/cvs/386BSD/ports/lang/perl/eg/van/unvanish,v 1.1.1.1 1993/08/23 21:29:45 nate Exp $
+
+sub it {
+ if ($olddir ne '.') {
+ chop($pwd = `pwd`) if $pwd eq '';
+ (chdir $olddir) || die "Directory $olddir is not accesible";
+ }
+ unless ($olddir eq '.deleted') {
+ if (-d '.deleted') {
+ chdir '.deleted' || die "Directory .deleted is not accesible";
+ }
+ else {
+ chop($pwd = `pwd`) if $pwd eq '';
+ die "Directory .deleted does not exist" unless $pwd =~ /\.deleted$/;
+ }
+ }
+ print `mv $startfiles$filelist..$force`;
+ if ($olddir ne '.') {
+ (chdir $pwd) || die "Can't get back to original directory $pwd: $!\n";
+ }
+}
+
+if ($#ARGV < 0) {
+ open(lastcmd,'.deleted/.lastcmd') ||
+ open(lastcmd,'.lastcmd') ||
+ die "No previous vanish in this dir";
+ $ARGV = <lastcmd>;
+ close(lastcmd);
+ @ARGV = split(/[\n ]+/,$ARGV);
+}
+
+while ($ARGV[0] =~ /^-/) {
+ $_ = shift;
+ /^-f/ && ($force = ' >/dev/null 2>&1');
+ /^-i/ && ($interactive = 1);
+ if (/^-+$/) {
+ $startfiles = '- ';
+ last;
+ }
+}
+
+while ($file = shift) {
+ if ($file =~ s|^(.*)/||) {
+ $dir = $1;
+ }
+ else {
+ $dir = '.';
+ }
+
+ if ($dir ne $olddir) {
+ do it() if $olddir;
+ $olddir = $dir;
+ }
+
+ if ($interactive) {
+ print "unvanish: restore $dir/$file? ";
+ next unless <stdin> =~ /^y/i;
+ }
+
+ $filelist .= $file; $filelist .= ' ';
+
+}
+
+do it() if $olddir;
diff --git a/gnu/usr.bin/perl/eg/van/vanexp b/gnu/usr.bin/perl/eg/van/vanexp
new file mode 100644
index 0000000..79b7885
--- /dev/null
+++ b/gnu/usr.bin/perl/eg/van/vanexp
@@ -0,0 +1,21 @@
+#!/usr/bin/perl
+
+# $Header: /home/cvs/386BSD/ports/lang/perl/eg/van/vanexp,v 1.1.1.1 1993/08/23 21:29:45 nate Exp $
+
+# This is for running from a find at night to expire old .deleteds
+
+$can = $ARGV[0];
+
+exit 1 unless $can =~ /.deleted$/;
+
+($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,$atime,$mtime,$ctime,
+ $blksize,$blocks) = stat($can);
+
+exit 0 unless $size;
+
+if (time - $mtime > 2 * 24 * 60 * 60) {
+ `/bin/rm -rf $can`;
+}
+else {
+ `find $can -ctime +2 -exec rm -f {} \;`;
+}
diff --git a/gnu/usr.bin/perl/eg/van/vanish b/gnu/usr.bin/perl/eg/van/vanish
new file mode 100644
index 0000000..b79776a
--- /dev/null
+++ b/gnu/usr.bin/perl/eg/van/vanish
@@ -0,0 +1,65 @@
+#!/usr/bin/perl
+
+# $Header: /home/cvs/386BSD/ports/lang/perl/eg/van/vanish,v 1.1.1.1 1993/08/23 21:29:45 nate Exp $
+
+sub it {
+ if ($olddir ne '.') {
+ chop($pwd = `pwd`) if $pwd eq '';
+ (chdir $olddir) || die "Directory $olddir is not accesible";
+ }
+ if (!-d .deleted) {
+ print `mkdir .deleted; chmod 775 .deleted`;
+ die "You can't remove files from $olddir" if $?;
+ }
+ $filelist =~ s/ $//;
+ $filelist =~ s/#/\\#/g;
+ if ($filelist !~ /^[ \t]*$/) {
+ open(lastcmd,'>.deleted/.lastcmd');
+ print lastcmd $filelist,"\n";
+ close(lastcmd);
+ print `/bin/mv $startfiles$filelist .deleted$force`;
+ }
+ if ($olddir ne '.') {
+ (chdir $pwd) || die "Can't get back to original directory $pwd: $!\n";
+ }
+}
+
+while ($ARGV[0] =~ /^-/) {
+ $_ = shift;
+ /^-f/ && ($force = ' >/dev/null 2>&1');
+ /^-i/ && ($interactive = 1);
+ if (/^-+$/) {
+ $startfiles = '- ';
+ last;
+ }
+}
+
+chop($pwd = `pwd`);
+
+while ($file = shift) {
+ if ($file =~ s|^(.*)/||) {
+ $dir = $1;
+ }
+ else {
+ $dir = '.';
+ }
+
+ if ($interactive) {
+ print "vanish: remove $dir/$file? ";
+ next unless <stdin> =~ /^y/i;
+ }
+
+ if ($file eq '.deleted') {
+ print stderr "To delete .deleted (the trashcan) use the 'empty' command.\n";
+ next;
+ }
+
+ if ($dir ne $olddir) {
+ do it() if $olddir;
+ $olddir = $dir;
+ }
+
+ $filelist .= $file; $filelist .= ' ';
+}
+
+do it() if $olddir;
diff --git a/gnu/usr.bin/perl/eg/who b/gnu/usr.bin/perl/eg/who
new file mode 100644
index 0000000..ac15246
--- /dev/null
+++ b/gnu/usr.bin/perl/eg/who
@@ -0,0 +1,13 @@
+#!/usr/bin/perl
+# This assumes your /etc/utmp file looks like ours
+open(UTMP,'/etc/utmp');
+@mo = (Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec);
+while (read(UTMP,$utmp,36)) {
+ ($line,$name,$host,$time) = unpack('A8A8A16l',$utmp);
+ if ($name) {
+ $host = "($host)" if ord($host);
+ ($sec,$min,$hour,$mday,$mon) = localtime($time);
+ printf "%-9s%-8s%s %2d %02d:%02d %s\n",
+ $name,$line,$mo[$mon],$mday,$hour,$min,$host;
+ }
+}
diff --git a/gnu/usr.bin/perl/emacs/perl-mode.el b/gnu/usr.bin/perl/emacs/perl-mode.el
new file mode 100644
index 0000000..cb6195d
--- /dev/null
+++ b/gnu/usr.bin/perl/emacs/perl-mode.el
@@ -0,0 +1,631 @@
+;; Perl code editing commands for GNU Emacs
+;; Copyright (C) 1990 William F. Mann
+;; Adapted from C code editing commands 'c-mode.el', Copyright 1987 by the
+;; Free Software Foundation, under terms of its General Public License.
+
+;; This file may be made part of GNU Emacs at the option of the FSF, or
+;; of the perl distribution at the option of Larry Wall.
+
+;; This code is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY. No author or distributor
+;; accepts responsibility to anyone for the consequences of using it
+;; or for whether it serves any particular purpose or works at all,
+;; unless he says so in writing. Refer to the GNU Emacs General Public
+;; License for full details.
+
+;; Everyone is granted permission to copy, modify and redistribute
+;; this code, but only under the conditions described in the
+;; GNU Emacs General Public License. A copy of this license is
+;; supposed to have been given to you along with GNU Emacs so you
+;; can know your rights and responsibilities. It should be in a
+;; file named COPYING. Among other things, the copyright notice
+;; and this notice must be preserved on all copies.
+
+;; To enter perl-mode automatically, add (autoload 'perl-mode "perl-mode")
+;; to your .emacs file and change the first line of your perl script to:
+;; #!/usr/bin/perl -- # -*-Perl-*-
+;; With argments to perl:
+;; #!/usr/bin/perl -P- # -*-Perl-*-
+;; To handle files included with do 'filename.pl';, add something like
+;; (setq auto-mode-alist (append (list (cons "\\.pl$" 'perl-mode))
+;; auto-mode-alist))
+;; to your .emacs file; otherwise the .pl suffix defaults to prolog-mode.
+
+;; This code is based on the 18.53 version c-mode.el, with extensive
+;; rewriting. Most of the features of c-mode survived intact.
+
+;; I added a new feature which adds functionality to TAB; it is controlled
+;; by the variable perl-tab-to-comment. With it enabled, TAB does the
+;; first thing it can from the following list: change the indentation;
+;; move past leading white space; delete an empty comment; reindent a
+;; comment; move to end of line; create an empty comment; tell you that
+;; the line ends in a quoted string, or has a # which should be a \#.
+
+;; If your machine is slow, you may want to remove some of the bindings
+;; to electric-perl-terminator. I changed the indenting defaults to be
+;; what Larry Wall uses in perl/lib, but left in all the options.
+
+;; I also tuned a few things: comments and labels starting in column
+;; zero are left there by indent-perl-exp; perl-beginning-of-function
+;; goes back to the first open brace/paren in column zero, the open brace
+;; in 'sub ... {', or the equal sign in 'format ... ='; indent-perl-exp
+;; (meta-^q) indents from the current line through the close of the next
+;; brace/paren, so you don't need to start exactly at a brace or paren.
+
+;; It may be good style to put a set of redundant braces around your
+;; main program. This will let you reindent it with meta-^q.
+
+;; Known problems (these are all caused by limitations in the elisp
+;; parsing routine (parse-partial-sexp), which was not designed for such
+;; a rich language; writing a more suitable parser would be a big job):
+;; 1) Regular expression delimitors do not act as quotes, so special
+;; characters such as `'"#:;[](){} may need to be backslashed
+;; in regular expressions and in both parts of s/// and tr///.
+;; 2) The globbing syntax <pattern> is not recognized, so special
+;; characters in the pattern string must be backslashed.
+;; 3) The q, qq, and << quoting operators are not recognized; see below.
+;; 4) \ (backslash) always quotes the next character, so '\' is
+;; treated as the start of a string. Use "\\" as a work-around.
+;; 5) To make variables such a $' and $#array work, perl-mode treats
+;; $ just like backslash, so '$' is the same as problem 5.
+;; 6) Unfortunately, treating $ like \ makes ${var} be treated as an
+;; unmatched }. See below.
+;; 7) When ' (quote) is used as a package name separator, perl-mode
+;; doesn't understand, and thinks it is seeing a quoted string.
+
+;; Here are some ugly tricks to bypass some of these problems: the perl
+;; expression /`/ (that's a back-tick) usually evaluates harmlessly,
+;; but will trick perl-mode into starting a quoted string, which
+;; can be ended with another /`/. Assuming you have no embedded
+;; back-ticks, this can used to help solve problem 3:
+;;
+;; /`/; $ugly = q?"'$?; /`/;
+;;
+;; To solve problem 6, add a /{/; before each use of ${var}:
+;; /{/; while (<${glob_me}>) ...
+;;
+;; Problem 7 is even worse, but this 'fix' does work :-(
+;; $DB'stop#'
+;; [$DB'line#'
+;; ] =~ s/;9$//;
+
+
+(defvar perl-mode-abbrev-table nil
+ "Abbrev table in use in perl-mode buffers.")
+(define-abbrev-table 'perl-mode-abbrev-table ())
+
+(defvar perl-mode-map ()
+ "Keymap used in Perl mode.")
+(if perl-mode-map
+ ()
+ (setq perl-mode-map (make-sparse-keymap))
+ (define-key perl-mode-map "{" 'electric-perl-terminator)
+ (define-key perl-mode-map "}" 'electric-perl-terminator)
+ (define-key perl-mode-map ";" 'electric-perl-terminator)
+ (define-key perl-mode-map ":" 'electric-perl-terminator)
+ (define-key perl-mode-map "\e\C-a" 'perl-beginning-of-function)
+ (define-key perl-mode-map "\e\C-e" 'perl-end-of-function)
+ (define-key perl-mode-map "\e\C-h" 'mark-perl-function)
+ (define-key perl-mode-map "\e\C-q" 'indent-perl-exp)
+ (define-key perl-mode-map "\177" 'backward-delete-char-untabify)
+ (define-key perl-mode-map "\t" 'perl-indent-command))
+
+(autoload 'c-macro-expand "cmacexp"
+ "Display the result of expanding all C macros occurring in the region.
+The expansion is entirely correct because it uses the C preprocessor."
+ t)
+
+(defvar perl-mode-syntax-table nil
+ "Syntax table in use in perl-mode buffers.")
+
+(if perl-mode-syntax-table
+ ()
+ (setq perl-mode-syntax-table (make-syntax-table (standard-syntax-table)))
+ (modify-syntax-entry ?\n ">" perl-mode-syntax-table)
+ (modify-syntax-entry ?# "<" perl-mode-syntax-table)
+ (modify-syntax-entry ?$ "/" perl-mode-syntax-table)
+ (modify-syntax-entry ?% "." perl-mode-syntax-table)
+ (modify-syntax-entry ?& "." perl-mode-syntax-table)
+ (modify-syntax-entry ?\' "\"" perl-mode-syntax-table)
+ (modify-syntax-entry ?* "." perl-mode-syntax-table)
+ (modify-syntax-entry ?+ "." perl-mode-syntax-table)
+ (modify-syntax-entry ?- "." perl-mode-syntax-table)
+ (modify-syntax-entry ?/ "." perl-mode-syntax-table)
+ (modify-syntax-entry ?< "." perl-mode-syntax-table)
+ (modify-syntax-entry ?= "." perl-mode-syntax-table)
+ (modify-syntax-entry ?> "." perl-mode-syntax-table)
+ (modify-syntax-entry ?\\ "\\" perl-mode-syntax-table)
+ (modify-syntax-entry ?` "\"" perl-mode-syntax-table)
+ (modify-syntax-entry ?| "." perl-mode-syntax-table)
+)
+
+(defconst perl-indent-level 4
+ "*Indentation of Perl statements with respect to containing block.")
+(defconst perl-continued-statement-offset 4
+ "*Extra indent for lines not starting new statements.")
+(defconst perl-continued-brace-offset -4
+ "*Extra indent for substatements that start with open-braces.
+This is in addition to perl-continued-statement-offset.")
+(defconst perl-brace-offset 0
+ "*Extra indentation for braces, compared with other text in same context.")
+(defconst perl-brace-imaginary-offset 0
+ "*Imagined indentation of an open brace that actually follows a statement.")
+(defconst perl-label-offset -2
+ "*Offset of Perl label lines relative to usual indentation.")
+
+(defconst perl-tab-always-indent t
+ "*Non-nil means TAB in Perl mode should always indent the current line,
+regardless of where in the line point is when the TAB command is used.")
+
+(defconst perl-tab-to-comment t
+ "*Non-nil means that for lines which don't need indenting, TAB will
+either indent an existing comment, move to end-of-line, or if at end-of-line
+already, create a new comment.")
+
+(defconst perl-nochange ";?#\\|\f\\|\\s(\\|\\(\\w\\|\\s_\\)+:"
+ "*Lines starting with this regular expression will not be auto-indented.")
+
+(defun perl-mode ()
+ "Major mode for editing Perl code.
+Expression and list commands understand all Perl brackets.
+Tab indents for Perl code.
+Comments are delimited with # ... \\n.
+Paragraphs are separated by blank lines only.
+Delete converts tabs to spaces as it moves back.
+\\{perl-mode-map}
+Variables controlling indentation style:
+ perl-tab-always-indent
+ Non-nil means TAB in Perl mode should always indent the current line,
+ regardless of where in the line point is when the TAB command is used.
+ perl-tab-to-comment
+ Non-nil means that for lines which don't need indenting, TAB will
+ either delete an empty comment, indent an existing comment, move
+ to end-of-line, or if at end-of-line already, create a new comment.
+ perl-nochange
+ Lines starting with this regular expression will not be auto-indented.
+ perl-indent-level
+ Indentation of Perl statements within surrounding block.
+ The surrounding block's indentation is the indentation
+ of the line on which the open-brace appears.
+ perl-continued-statement-offset
+ Extra indentation given to a substatement, such as the
+ then-clause of an if or body of a while.
+ perl-continued-brace-offset
+ Extra indentation given to a brace that starts a substatement.
+ This is in addition to perl-continued-statement-offset.
+ perl-brace-offset
+ Extra indentation for line if it starts with an open brace.
+ perl-brace-imaginary-offset
+ An open brace following other text is treated as if it were
+ this far to the right of the start of its line.
+ perl-label-offset
+ Extra indentation for line that is a label.
+
+Various indentation styles: K&R BSD BLK GNU LW
+ perl-indent-level 5 8 0 2 4
+ perl-continued-statement-offset 5 8 4 2 4
+ perl-continued-brace-offset 0 0 0 0 -4
+ perl-brace-offset -5 -8 0 0 0
+ perl-brace-imaginary-offset 0 0 4 0 0
+ perl-label-offset -5 -8 -2 -2 -2
+
+Turning on Perl mode calls the value of the variable perl-mode-hook with no
+args, if that value is non-nil."
+ (interactive)
+ (kill-all-local-variables)
+ (use-local-map perl-mode-map)
+ (setq major-mode 'perl-mode)
+ (setq mode-name "Perl")
+ (setq local-abbrev-table perl-mode-abbrev-table)
+ (set-syntax-table perl-mode-syntax-table)
+ (make-local-variable 'paragraph-start)
+ (setq paragraph-start (concat "^$\\|" page-delimiter))
+ (make-local-variable 'paragraph-separate)
+ (setq paragraph-separate paragraph-start)
+ (make-local-variable 'paragraph-ignore-fill-prefix)
+ (setq paragraph-ignore-fill-prefix t)
+ (make-local-variable 'indent-line-function)
+ (setq indent-line-function 'perl-indent-line)
+ (make-local-variable 'require-final-newline)
+ (setq require-final-newline t)
+ (make-local-variable 'comment-start)
+ (setq comment-start "# ")
+ (make-local-variable 'comment-end)
+ (setq comment-end "")
+ (make-local-variable 'comment-column)
+ (setq comment-column 32)
+ (make-local-variable 'comment-start-skip)
+ (setq comment-start-skip "\\(^\\|\\s-\\);?#+ *")
+ (make-local-variable 'comment-indent-hook)
+ (setq comment-indent-hook 'perl-comment-indent)
+ (make-local-variable 'parse-sexp-ignore-comments)
+ (setq parse-sexp-ignore-comments nil)
+ (run-hooks 'perl-mode-hook))
+
+;; This is used by indent-for-comment
+;; to decide how much to indent a comment in Perl code
+;; based on its context.
+(defun perl-comment-indent ()
+ (if (and (bolp) (not (eolp)))
+ 0 ;Existing comment at bol stays there.
+ (save-excursion
+ (skip-chars-backward " \t")
+ (max (1+ (current-column)) ;Else indent at comment column
+ comment-column)))) ; except leave at least one space.
+
+(defun electric-perl-terminator (arg)
+ "Insert character. If at end-of-line, and not in a comment or a quote,
+correct the line's indentation."
+ (interactive "P")
+ (let ((insertpos (point)))
+ (and (not arg) ; decide whether to indent
+ (eolp)
+ (save-excursion
+ (beginning-of-line)
+ (and (not ; eliminate comments quickly
+ (re-search-forward comment-start-skip insertpos t))
+ (or (/= last-command-char ?:)
+ ;; Colon is special only after a label ....
+ (looking-at "\\s-*\\(\\w\\|\\s_\\)+$"))
+ (let ((pps (parse-partial-sexp
+ (perl-beginning-of-function) insertpos)))
+ (not (or (nth 3 pps) (nth 4 pps) (nth 5 pps))))))
+ (progn ; must insert, indent, delete
+ (insert-char last-command-char 1)
+ (perl-indent-line)
+ (delete-char -1))))
+ (self-insert-command (prefix-numeric-value arg)))
+
+;; not used anymore, but may be useful someday:
+;;(defun perl-inside-parens-p ()
+;; (condition-case ()
+;; (save-excursion
+;; (save-restriction
+;; (narrow-to-region (point)
+;; (perl-beginning-of-function))
+;; (goto-char (point-max))
+;; (= (char-after (or (scan-lists (point) -1 1) (point-min))) ?\()))
+;; (error nil)))
+
+(defun perl-indent-command (&optional arg)
+ "Indent current line as Perl code, or optionally, insert a tab character.
+
+With an argument, indent the current line, regardless of other options.
+
+If perl-tab-always-indent is nil and point is not in the indentation
+area at the beginning of the line, simply insert a tab.
+
+Otherwise, indent the current line. If point was within the indentation
+area it is moved to the end of the indentation area. If the line was
+already indented properly and point was not within the indentation area,
+and if perl-tab-to-comment is non-nil (the default), then do the first
+possible action from the following list:
+
+ 1) delete an empty comment
+ 2) move forward to start of comment, indenting if necessary
+ 3) move forward to end of line
+ 4) create an empty comment
+ 5) move backward to start of comment, indenting if necessary."
+ (interactive "P")
+ (if arg ; If arg, just indent this line
+ (perl-indent-line "\f")
+ (if (and (not perl-tab-always-indent)
+ (<= (current-column) (current-indentation)))
+ (insert-tab)
+ (let (bof lsexp delta (oldpnt (point)))
+ (beginning-of-line)
+ (setq lsexp (point))
+ (setq bof (perl-beginning-of-function))
+ (goto-char oldpnt)
+ (setq delta (perl-indent-line "\f\\|;?#" bof))
+ (and perl-tab-to-comment
+ (= oldpnt (point)) ; done if point moved
+ (if (listp delta) ; if line starts in a quoted string
+ (setq lsexp (or (nth 2 delta) bof))
+ (= delta 0)) ; done if indenting occurred
+ (let (eol state)
+ (end-of-line)
+ (setq eol (point))
+ (if (= (char-after bof) ?=)
+ (if (= oldpnt eol)
+ (message "In a format statement"))
+ (setq state (parse-partial-sexp lsexp eol))
+ (if (nth 3 state)
+ (if (= oldpnt eol) ; already at eol in a string
+ (message "In a string which starts with a %c."
+ (nth 3 state)))
+ (if (not (nth 4 state))
+ (if (= oldpnt eol) ; no comment, create one?
+ (indent-for-comment))
+ (beginning-of-line)
+ (if (re-search-forward comment-start-skip eol 'move)
+ (if (eolp)
+ (progn ; kill existing comment
+ (goto-char (match-beginning 0))
+ (skip-chars-backward " \t")
+ (kill-region (point) eol))
+ (if (or (< oldpnt (point)) (= oldpnt eol))
+ (indent-for-comment) ; indent existing comment
+ (end-of-line)))
+ (if (/= oldpnt eol)
+ (end-of-line)
+ (message "Use backslash to quote # characters.")
+ (ding t))))))))))))
+
+(defun perl-indent-line (&optional nochange parse-start)
+ "Indent current line as Perl code. Return the amount the indentation
+changed by, or (parse-state) if line starts in a quoted string."
+ (let ((case-fold-search nil)
+ (pos (- (point-max) (point)))
+ (bof (or parse-start (save-excursion (perl-beginning-of-function))))
+ beg indent shift-amt)
+ (beginning-of-line)
+ (setq beg (point))
+ (setq shift-amt
+ (cond ((= (char-after bof) ?=) 0)
+ ((listp (setq indent (calculate-perl-indent bof))) indent)
+ ((looking-at (or nochange perl-nochange)) 0)
+ (t
+ (skip-chars-forward " \t\f")
+ (cond ((looking-at "\\(\\w\\|\\s_\\)+:")
+ (setq indent (max 1 (+ indent perl-label-offset))))
+ ((= (following-char) ?})
+ (setq indent (- indent perl-indent-level)))
+ ((= (following-char) ?{)
+ (setq indent (+ indent perl-brace-offset))))
+ (- indent (current-column)))))
+ (skip-chars-forward " \t\f")
+ (if (and (numberp shift-amt) (/= 0 shift-amt))
+ (progn (delete-region beg (point))
+ (indent-to indent)))
+ ;; If initial point was within line's indentation,
+ ;; position after the indentation. Else stay at same point in text.
+ (if (> (- (point-max) pos) (point))
+ (goto-char (- (point-max) pos)))
+ shift-amt))
+
+(defun calculate-perl-indent (&optional parse-start)
+ "Return appropriate indentation for current line as Perl code.
+In usual case returns an integer: the column to indent to.
+Returns (parse-state) if line starts inside a string."
+ (save-excursion
+ (beginning-of-line)
+ (let ((indent-point (point))
+ (case-fold-search nil)
+ (colon-line-end 0)
+ state containing-sexp)
+ (if parse-start ;used to avoid searching
+ (goto-char parse-start)
+ (perl-beginning-of-function))
+ (while (< (point) indent-point) ;repeat until right sexp
+ (setq parse-start (point))
+ (setq state (parse-partial-sexp (point) indent-point 0))
+; state = (depth_in_parens innermost_containing_list last_complete_sexp
+; string_terminator_or_nil inside_commentp following_quotep
+; minimum_paren-depth_this_scan)
+; Parsing stops if depth in parentheses becomes equal to third arg.
+ (setq containing-sexp (nth 1 state)))
+ (cond ((nth 3 state) state) ; In a quoted string?
+ ((null containing-sexp) ; Line is at top level.
+ (skip-chars-forward " \t\f")
+ (if (= (following-char) ?{)
+ 0 ; move to beginning of line if it starts a function body
+ ;; indent a little if this is a continuation line
+ (perl-backward-to-noncomment)
+ (if (or (bobp)
+ (memq (preceding-char) '(?\; ?\})))
+ 0 perl-continued-statement-offset)))
+ ((/= (char-after containing-sexp) ?{)
+ ;; line is expression, not statement:
+ ;; indent to just after the surrounding open.
+ (goto-char (1+ containing-sexp))
+ (current-column))
+ (t
+ ;; Statement level. Is it a continuation or a new statement?
+ ;; Find previous non-comment character.
+ (perl-backward-to-noncomment)
+ ;; Back up over label lines, since they don't
+ ;; affect whether our line is a continuation.
+ (while (or (eq (preceding-char) ?\,)
+ (and (eq (preceding-char) ?:)
+ (memq (char-syntax (char-after (- (point) 2)))
+ '(?w ?_))))
+ (if (eq (preceding-char) ?\,)
+ (perl-backward-to-start-of-continued-exp containing-sexp))
+ (beginning-of-line)
+ (perl-backward-to-noncomment))
+ ;; Now we get the answer.
+ (if (not (memq (preceding-char) '(?\; ?\} ?\{)))
+ ;; This line is continuation of preceding line's statement;
+ ;; indent perl-continued-statement-offset more than the
+ ;; previous line of the statement.
+ (progn
+ (perl-backward-to-start-of-continued-exp containing-sexp)
+ (+ perl-continued-statement-offset (current-column)
+ (if (save-excursion (goto-char indent-point)
+ (looking-at "[ \t]*{"))
+ perl-continued-brace-offset 0)))
+ ;; This line starts a new statement.
+ ;; Position at last unclosed open.
+ (goto-char containing-sexp)
+ (or
+ ;; If open paren is in col 0, close brace is special
+ (and (bolp)
+ (save-excursion (goto-char indent-point)
+ (looking-at "[ \t]*}"))
+ perl-indent-level)
+ ;; Is line first statement after an open-brace?
+ ;; If no, find that first statement and indent like it.
+ (save-excursion
+ (forward-char 1)
+ ;; Skip over comments and labels following openbrace.
+ (while (progn
+ (skip-chars-forward " \t\f\n")
+ (cond ((looking-at ";?#")
+ (forward-line 1) t)
+ ((looking-at "\\(\\w\\|\\s_\\)+:")
+ (save-excursion
+ (end-of-line)
+ (setq colon-line-end (point)))
+ (search-forward ":")))))
+ ;; The first following code counts
+ ;; if it is before the line we want to indent.
+ (and (< (point) indent-point)
+ (if (> colon-line-end (point))
+ (- (current-indentation) perl-label-offset)
+ (current-column))))
+ ;; If no previous statement,
+ ;; indent it relative to line brace is on.
+ ;; For open paren in column zero, don't let statement
+ ;; start there too. If perl-indent-level is zero,
+ ;; use perl-brace-offset + perl-continued-statement-offset
+ ;; For open-braces not the first thing in a line,
+ ;; add in perl-brace-imaginary-offset.
+ (+ (if (and (bolp) (zerop perl-indent-level))
+ (+ perl-brace-offset perl-continued-statement-offset)
+ perl-indent-level)
+ ;; Move back over whitespace before the openbrace.
+ ;; If openbrace is not first nonwhite thing on the line,
+ ;; add the perl-brace-imaginary-offset.
+ (progn (skip-chars-backward " \t")
+ (if (bolp) 0 perl-brace-imaginary-offset))
+ ;; If the openbrace is preceded by a parenthesized exp,
+ ;; move to the beginning of that;
+ ;; possibly a different line
+ (progn
+ (if (eq (preceding-char) ?\))
+ (forward-sexp -1))
+ ;; Get initial indentation of the line we are on.
+ (current-indentation))))))))))
+
+(defun perl-backward-to-noncomment ()
+ "Move point backward to after the first non-white-space, skipping comments."
+ (interactive)
+ (let (opoint stop)
+ (while (not stop)
+ (setq opoint (point))
+ (beginning-of-line)
+ (if (re-search-forward comment-start-skip opoint 'move 1)
+ (progn (goto-char (match-end 1))
+ (skip-chars-forward ";")))
+ (skip-chars-backward " \t\f")
+ (setq stop (or (bobp)
+ (not (bolp))
+ (forward-char -1))))))
+
+(defun perl-backward-to-start-of-continued-exp (lim)
+ (if (= (preceding-char) ?\))
+ (forward-sexp -1))
+ (beginning-of-line)
+ (if (<= (point) lim)
+ (goto-char (1+ lim)))
+ (skip-chars-forward " \t\f"))
+
+;; note: this may be slower than the c-mode version, but I can understand it.
+(defun indent-perl-exp ()
+ "Indent each line of the Perl grouping following point."
+ (interactive)
+ (let* ((case-fold-search nil)
+ (oldpnt (point-marker))
+ (bof-mark (save-excursion
+ (end-of-line 2)
+ (perl-beginning-of-function)
+ (point-marker)))
+ eol last-mark lsexp-mark delta)
+ (if (= (char-after (marker-position bof-mark)) ?=)
+ (message "Can't indent a format statement")
+ (message "Indenting Perl expression...")
+ (save-excursion (end-of-line) (setq eol (point)))
+ (save-excursion ; locate matching close paren
+ (while (and (not (eobp)) (<= (point) eol))
+ (parse-partial-sexp (point) (point-max) 0))
+ (setq last-mark (point-marker)))
+ (setq lsexp-mark bof-mark)
+ (beginning-of-line)
+ (while (< (point) (marker-position last-mark))
+ (setq delta (perl-indent-line nil (marker-position bof-mark)))
+ (if (numberp delta) ; unquoted start-of-line?
+ (progn
+ (if (eolp)
+ (delete-horizontal-space))
+ (setq lsexp-mark (point-marker))))
+ (end-of-line)
+ (setq eol (point))
+ (if (nth 4 (parse-partial-sexp (marker-position lsexp-mark) eol))
+ (progn ; line ends in a comment
+ (beginning-of-line)
+ (if (or (not (looking-at "\\s-*;?#"))
+ (listp delta)
+ (and (/= 0 delta)
+ (= (- (current-indentation) delta) comment-column)))
+ (if (re-search-forward comment-start-skip eol t)
+ (indent-for-comment))))) ; indent existing comment
+ (forward-line 1))
+ (goto-char (marker-position oldpnt))
+ (message "Indenting Perl expression...done"))))
+
+(defun perl-beginning-of-function (&optional arg)
+ "Move backward to next beginning-of-function, or as far as possible.
+With argument, repeat that many times; negative args move forward.
+Returns new value of point in all cases."
+ (interactive "p")
+ (or arg (setq arg 1))
+ (if (< arg 0) (forward-char 1))
+ (and (/= arg 0)
+ (re-search-backward "^\\s(\\|^\\s-*sub\\b[^{]+{\\|^\\s-*format\\b[^=]*=\\|^\\."
+ nil 'move arg)
+ (goto-char (1- (match-end 0))))
+ (point))
+
+;; note: this routine is adapted directly from emacs lisp.el, end-of-defun;
+;; no bugs have been removed :-)
+(defun perl-end-of-function (&optional arg)
+ "Move forward to next end-of-function.
+The end of a function is found by moving forward from the beginning of one.
+With argument, repeat that many times; negative args move backward."
+ (interactive "p")
+ (or arg (setq arg 1))
+ (let ((first t))
+ (while (and (> arg 0) (< (point) (point-max)))
+ (let ((pos (point)) npos)
+ (while (progn
+ (if (and first
+ (progn
+ (forward-char 1)
+ (perl-beginning-of-function 1)
+ (not (bobp))))
+ nil
+ (or (bobp) (forward-char -1))
+ (perl-beginning-of-function -1))
+ (setq first nil)
+ (forward-list 1)
+ (skip-chars-forward " \t")
+ (if (looking-at "[#\n]")
+ (forward-line 1))
+ (<= (point) pos))))
+ (setq arg (1- arg)))
+ (while (< arg 0)
+ (let ((pos (point)))
+ (perl-beginning-of-function 1)
+ (forward-sexp 1)
+ (forward-line 1)
+ (if (>= (point) pos)
+ (if (progn (perl-beginning-of-function 2) (not (bobp)))
+ (progn
+ (forward-list 1)
+ (skip-chars-forward " \t")
+ (if (looking-at "[#\n]")
+ (forward-line 1)))
+ (goto-char (point-min)))))
+ (setq arg (1+ arg)))))
+
+(defun mark-perl-function ()
+ "Put mark at end of Perl function, point at beginning."
+ (interactive)
+ (push-mark (point))
+ (perl-end-of-function)
+ (push-mark (point))
+ (perl-beginning-of-function)
+ (backward-paragraph))
+
+;;;;;;;; That's all, folks! ;;;;;;;;;
diff --git a/gnu/usr.bin/perl/emacs/perldb.el b/gnu/usr.bin/perl/emacs/perldb.el
new file mode 100644
index 0000000..66951be
--- /dev/null
+++ b/gnu/usr.bin/perl/emacs/perldb.el
@@ -0,0 +1,423 @@
+;; Run perl -d under Emacs
+;; Based on gdb.el, as written by W. Schelter, and modified by rms.
+;; Modified for Perl by Ray Lischner (uunet!mntgfx!lisch), Nov 1990.
+
+;; This file is part of GNU Emacs.
+;; Copyright (C) 1988,1990 Free Software Foundation, Inc.
+
+;; GNU Emacs is distributed in the hope that it will be useful, but
+;; WITHOUT ANY WARRANTY. No author or distributor accepts responsibility
+;; to anyone for the consequences of using it or for whether it serves
+;; any particular purpose or works at all, unless he says so in writing.
+;; Refer to the GNU Emacs General Public License for full details.
+
+;; Everyone is granted permission to copy, modify and redistribute GNU
+;; Emacs, but only under the conditions described in the GNU Emacs
+;; General Public License. A copy of this license is supposed to have
+;; been given to you along with GNU Emacs so you can know your rights and
+;; responsibilities. It should be in a file named COPYING. Among other
+;; things, the copyright notice and this notice must be preserved on all
+;; copies.
+
+;; Description of perl -d interface:
+
+;; A facility is provided for the simultaneous display of the source code
+;; in one window, while using perldb to step through a function in the
+;; other. A small arrow in the source window, indicates the current
+;; line.
+
+;; Starting up:
+
+;; In order to use this facility, invoke the command PERLDB to obtain a
+;; shell window with the appropriate command bindings. You will be asked
+;; for the name of a file to run and additional command line arguments.
+;; Perldb will be invoked on this file, in a window named *perldb-foo*
+;; if the file is foo.
+
+;; M-s steps by one line, and redisplays the source file and line.
+
+;; You may easily create additional commands and bindings to interact
+;; with the display. For example to put the perl debugger command n on \M-n
+;; (def-perldb n "\M-n")
+
+;; This causes the emacs command perldb-next to be defined, and runs
+;; perldb-display-frame after the command.
+
+;; perldb-display-frame is the basic display function. It tries to display
+;; in the other window, the file and line corresponding to the current
+;; position in the perldb window. For example after a perldb-step, it would
+;; display the line corresponding to the position for the last step. Or
+;; if you have done a backtrace in the perldb buffer, and move the cursor
+;; into one of the frames, it would display the position corresponding to
+;; that frame.
+
+;; perldb-display-frame is invoked automatically when a filename-and-line-number
+;; appears in the output.
+
+
+(require 'shell)
+
+(defvar perldb-prompt-pattern "^ DB<[0-9]+> "
+ "A regexp to recognize the prompt for perldb.")
+
+(defvar perldb-mode-map nil
+ "Keymap for perldb-mode.")
+
+(if perldb-mode-map
+ nil
+ (setq perldb-mode-map (copy-keymap shell-mode-map))
+ (define-key perldb-mode-map "\C-l" 'perldb-refresh))
+
+(define-key ctl-x-map " " 'perldb-break)
+(define-key ctl-x-map "&" 'send-perldb-command)
+
+;;Of course you may use `def-perldb' with any other perldb command, including
+;;user defined ones.
+
+(defmacro def-perldb (name key &optional doc)
+ (let* ((fun (intern (concat "perldb-" name))))
+ (` (progn
+ (defun (, fun) (arg)
+ (, (or doc ""))
+ (interactive "p")
+ (perldb-call (if (not (= 1 arg))
+ (concat (, name) arg)
+ (, name))))
+ (define-key perldb-mode-map (, key) (quote (, fun)))))))
+
+(def-perldb "s" "\M-s" "Step one source line with display")
+(def-perldb "n" "\M-n" "Step one source line (skip functions)")
+(def-perldb "c" "\M-c" "Continue with display")
+(def-perldb "r" "\C-c\C-r" "Return from current subroutine")
+(def-perldb "A" "\C-c\C-a" "Delete all actions")
+
+(defun perldb-mode ()
+ "Major mode for interacting with an inferior Perl debugger process.
+The following commands are available:
+
+\\{perldb-mode-map}
+
+\\[perldb-display-frame] displays in the other window
+the last line referred to in the perldb buffer.
+
+\\[perldb-s],\\[perldb-n], and \\[perldb-n] in the perldb window,
+call perldb to step, next or continue and then update the other window
+with the current file and position.
+
+If you are in a source file, you may select a point to break
+at, by doing \\[perldb-break].
+
+Commands:
+Many commands are inherited from shell mode.
+Additionally we have:
+
+\\[perldb-display-frame] display frames file in other window
+\\[perldb-s] advance one line in program
+\\[perldb-n] advance one line in program (skip over calls).
+\\[send-perldb-command] used for special printing of an arg at the current point.
+C-x SPACE sets break point at current line."
+ (interactive)
+ (kill-all-local-variables)
+ (setq major-mode 'perldb-mode)
+ (setq mode-name "Inferior Perl")
+ (setq mode-line-process '(": %s"))
+ (use-local-map perldb-mode-map)
+ (make-local-variable 'last-input-start)
+ (setq last-input-start (make-marker))
+ (make-local-variable 'last-input-end)
+ (setq last-input-end (make-marker))
+ (make-local-variable 'perldb-last-frame)
+ (setq perldb-last-frame nil)
+ (make-local-variable 'perldb-last-frame-displayed-p)
+ (setq perldb-last-frame-displayed-p t)
+ (make-local-variable 'perldb-delete-prompt-marker)
+ (setq perldb-delete-prompt-marker nil)
+ (make-local-variable 'perldb-filter-accumulator)
+ (setq perldb-filter-accumulator nil)
+ (make-local-variable 'shell-prompt-pattern)
+ (setq shell-prompt-pattern perldb-prompt-pattern)
+ (run-hooks 'shell-mode-hook 'perldb-mode-hook))
+
+(defvar current-perldb-buffer nil)
+
+(defvar perldb-command-name "perl"
+ "Pathname for executing perl -d.")
+
+(defun end-of-quoted-arg (argstr start end)
+ (let* ((chr (substring argstr start (1+ start)))
+ (idx (string-match (concat "[^\\]" chr) argstr (1+ start))))
+ (and idx (1+ idx))
+ )
+)
+
+(defun parse-args-helper (arglist argstr start end)
+ (while (and (< start end) (string-match "[ \t\n\f\r\b]"
+ (substring argstr start (1+ start))))
+ (setq start (1+ start)))
+ (cond
+ ((= start end) arglist)
+ ((string-match "[\"']" (substring argstr start (1+ start)))
+ (let ((next (end-of-quoted-arg argstr start end)))
+ (parse-args-helper (cons (substring argstr (1+ start) next) arglist)
+ argstr (1+ next) end)))
+ (t (let ((next (string-match "[ \t\n\f\b\r]" argstr start)))
+ (if next
+ (parse-args-helper (cons (substring argstr start next) arglist)
+ argstr (1+ next) end)
+ (cons (substring argstr start) arglist))))
+ )
+ )
+
+(defun parse-args (args)
+ "Extract arguments from a string ARGS.
+White space separates arguments, with single or double quotes
+used to protect spaces. A list of strings is returned, e.g.,
+(parse-args \"foo bar 'two args'\") => (\"foo\" \"bar\" \"two args\")."
+ (nreverse (parse-args-helper '() args 0 (length args)))
+)
+
+(defun perldb (path args)
+ "Run perldb on program FILE in buffer *perldb-FILE*.
+The default directory for the current buffer becomes the initial
+working directory, by analogy with gdb . If you wish to change this, use
+the Perl command `chdir(DIR)'."
+ (interactive "FRun perl -d on file: \nsCommand line arguments: ")
+ (setq path (expand-file-name path))
+ (let ((file (file-name-nondirectory path))
+ (dir default-directory))
+ (switch-to-buffer (concat "*perldb-" file "*"))
+ (setq default-directory dir)
+ (or (bolp) (newline))
+ (insert "Current directory is " default-directory "\n")
+ (apply 'make-shell
+ (concat "perldb-" file) perldb-command-name nil "-d" path "-emacs"
+ (parse-args args))
+ (perldb-mode)
+ (set-process-filter (get-buffer-process (current-buffer)) 'perldb-filter)
+ (set-process-sentinel (get-buffer-process (current-buffer)) 'perldb-sentinel)
+ (perldb-set-buffer)))
+
+(defun perldb-set-buffer ()
+ (cond ((eq major-mode 'perldb-mode)
+ (setq current-perldb-buffer (current-buffer)))))
+
+;; This function is responsible for inserting output from Perl
+;; into the buffer.
+;; Aside from inserting the text, it notices and deletes
+;; each filename-and-line-number;
+;; that Perl prints to identify the selected frame.
+;; It records the filename and line number, and maybe displays that file.
+(defun perldb-filter (proc string)
+ (let ((inhibit-quit t))
+ (if perldb-filter-accumulator
+ (perldb-filter-accumulate-marker proc
+ (concat perldb-filter-accumulator string))
+ (perldb-filter-scan-input proc string))))
+
+(defun perldb-filter-accumulate-marker (proc string)
+ (setq perldb-filter-accumulator nil)
+ (if (> (length string) 1)
+ (if (= (aref string 1) ?\032)
+ (let ((end (string-match "\n" string)))
+ (if end
+ (progn
+ (let* ((first-colon (string-match ":" string 2))
+ (second-colon
+ (string-match ":" string (1+ first-colon))))
+ (setq perldb-last-frame
+ (cons (substring string 2 first-colon)
+ (string-to-int
+ (substring string (1+ first-colon)
+ second-colon)))))
+ (setq perldb-last-frame-displayed-p nil)
+ (perldb-filter-scan-input proc
+ (substring string (1+ end))))
+ (setq perldb-filter-accumulator string)))
+ (perldb-filter-insert proc "\032")
+ (perldb-filter-scan-input proc (substring string 1)))
+ (setq perldb-filter-accumulator string)))
+
+(defun perldb-filter-scan-input (proc string)
+ (if (equal string "")
+ (setq perldb-filter-accumulator nil)
+ (let ((start (string-match "\032" string)))
+ (if start
+ (progn (perldb-filter-insert proc (substring string 0 start))
+ (perldb-filter-accumulate-marker proc
+ (substring string start)))
+ (perldb-filter-insert proc string)))))
+
+(defun perldb-filter-insert (proc string)
+ (let ((moving (= (point) (process-mark proc)))
+ (output-after-point (< (point) (process-mark proc)))
+ (old-buffer (current-buffer))
+ start)
+ (set-buffer (process-buffer proc))
+ (unwind-protect
+ (save-excursion
+ ;; Insert the text, moving the process-marker.
+ (goto-char (process-mark proc))
+ (setq start (point))
+ (insert string)
+ (set-marker (process-mark proc) (point))
+ (perldb-maybe-delete-prompt)
+ ;; Check for a filename-and-line number.
+ (perldb-display-frame
+ ;; Don't display the specified file
+ ;; unless (1) point is at or after the position where output appears
+ ;; and (2) this buffer is on the screen.
+ (or output-after-point
+ (not (get-buffer-window (current-buffer))))
+ ;; Display a file only when a new filename-and-line-number appears.
+ t))
+ (set-buffer old-buffer))
+ (if moving (goto-char (process-mark proc)))))
+
+(defun perldb-sentinel (proc msg)
+ (cond ((null (buffer-name (process-buffer proc)))
+ ;; buffer killed
+ ;; Stop displaying an arrow in a source file.
+ (setq overlay-arrow-position nil)
+ (set-process-buffer proc nil))
+ ((memq (process-status proc) '(signal exit))
+ ;; Stop displaying an arrow in a source file.
+ (setq overlay-arrow-position nil)
+ ;; Fix the mode line.
+ (setq mode-line-process
+ (concat ": "
+ (symbol-name (process-status proc))))
+ (let* ((obuf (current-buffer)))
+ ;; save-excursion isn't the right thing if
+ ;; process-buffer is current-buffer
+ (unwind-protect
+ (progn
+ ;; Write something in *compilation* and hack its mode line,
+ (set-buffer (process-buffer proc))
+ ;; Force mode line redisplay soon
+ (set-buffer-modified-p (buffer-modified-p))
+ (if (eobp)
+ (insert ?\n mode-name " " msg)
+ (save-excursion
+ (goto-char (point-max))
+ (insert ?\n mode-name " " msg)))
+ ;; If buffer and mode line will show that the process
+ ;; is dead, we can delete it now. Otherwise it
+ ;; will stay around until M-x list-processes.
+ (delete-process proc))
+ ;; Restore old buffer, but don't restore old point
+ ;; if obuf is the perldb buffer.
+ (set-buffer obuf))))))
+
+
+(defun perldb-refresh ()
+ "Fix up a possibly garbled display, and redraw the arrow."
+ (interactive)
+ (redraw-display)
+ (perldb-display-frame))
+
+(defun perldb-display-frame (&optional nodisplay noauto)
+ "Find, obey and delete the last filename-and-line marker from PERLDB.
+The marker looks like \\032\\032FILENAME:LINE:CHARPOS\\n.
+Obeying it means displaying in another window the specified file and line."
+ (interactive)
+ (perldb-set-buffer)
+ (and perldb-last-frame (not nodisplay)
+ (or (not perldb-last-frame-displayed-p) (not noauto))
+ (progn (perldb-display-line (car perldb-last-frame) (cdr perldb-last-frame))
+ (setq perldb-last-frame-displayed-p t))))
+
+;; Make sure the file named TRUE-FILE is in a buffer that appears on the screen
+;; and that its line LINE is visible.
+;; Put the overlay-arrow on the line LINE in that buffer.
+
+(defun perldb-display-line (true-file line)
+ (let* ((buffer (find-file-noselect true-file))
+ (window (display-buffer buffer t))
+ (pos))
+ (save-excursion
+ (set-buffer buffer)
+ (save-restriction
+ (widen)
+ (goto-line line)
+ (setq pos (point))
+ (setq overlay-arrow-string "=>")
+ (or overlay-arrow-position
+ (setq overlay-arrow-position (make-marker)))
+ (set-marker overlay-arrow-position (point) (current-buffer)))
+ (cond ((or (< pos (point-min)) (> pos (point-max)))
+ (widen)
+ (goto-char pos))))
+ (set-window-point window overlay-arrow-position)))
+
+(defun perldb-call (command)
+ "Invoke perldb COMMAND displaying source in other window."
+ (interactive)
+ (goto-char (point-max))
+ (setq perldb-delete-prompt-marker (point-marker))
+ (perldb-set-buffer)
+ (send-string (get-buffer-process current-perldb-buffer)
+ (concat command "\n")))
+
+(defun perldb-maybe-delete-prompt ()
+ (if (and perldb-delete-prompt-marker
+ (> (point-max) (marker-position perldb-delete-prompt-marker)))
+ (let (start)
+ (goto-char perldb-delete-prompt-marker)
+ (setq start (point))
+ (beginning-of-line)
+ (delete-region (point) start)
+ (setq perldb-delete-prompt-marker nil))))
+
+(defun perldb-break ()
+ "Set PERLDB breakpoint at this source line."
+ (interactive)
+ (let ((line (save-restriction
+ (widen)
+ (1+ (count-lines 1 (point))))))
+ (send-string (get-buffer-process current-perldb-buffer)
+ (concat "b " line "\n"))))
+
+(defun perldb-read-token()
+ "Return a string containing the token found in the buffer at point.
+A token can be a number or an identifier. If the token is a name prefaced
+by `$', `@', or `%', the leading character is included in the token."
+ (save-excursion
+ (let (begin)
+ (or (looking-at "[$@%]")
+ (re-search-backward "[^a-zA-Z_0-9]" (point-min) 'move))
+ (setq begin (point))
+ (or (looking-at "[$@%]") (setq begin (+ begin 1)))
+ (forward-char 1)
+ (buffer-substring begin
+ (if (re-search-forward "[^a-zA-Z_0-9]"
+ (point-max) 'move)
+ (- (point) 1)
+ (point)))
+)))
+
+(defvar perldb-commands nil
+ "List of strings or functions used by send-perldb-command.
+It is for customization by the user.")
+
+(defun send-perldb-command (arg)
+ "Issue a Perl debugger command selected by the prefix arg. A numeric
+arg selects the ARG'th member COMMAND of the list perldb-commands.
+The token under the cursor is passed to the command. If COMMAND is a
+string, (format COMMAND TOKEN) is inserted at the end of the perldb
+buffer, otherwise (funcall COMMAND TOKEN) is inserted. If there is
+no such COMMAND, then the token itself is inserted. For example,
+\"p %s\" is a possible string to be a member of perldb-commands,
+or \"p $ENV{%s}\"."
+ (interactive "P")
+ (let (comm token)
+ (if arg (setq comm (nth arg perldb-commands)))
+ (setq token (perldb-read-token))
+ (if (eq (current-buffer) current-perldb-buffer)
+ (set-mark (point)))
+ (cond (comm
+ (setq comm
+ (if (stringp comm) (format comm token) (funcall comm token))))
+ (t (setq comm token)))
+ (switch-to-buffer-other-window current-perldb-buffer)
+ (goto-char (dot-max))
+ (insert-string comm)))
diff --git a/gnu/usr.bin/perl/emacs/perldb.pl b/gnu/usr.bin/perl/emacs/perldb.pl
new file mode 100644
index 0000000..7c9e651
--- /dev/null
+++ b/gnu/usr.bin/perl/emacs/perldb.pl
@@ -0,0 +1,568 @@
+package DB;
+
+# modified Perl debugger, to be run from Emacs in perldb-mode
+# Ray Lischner (uunet!mntgfx!lisch) as of 5 Nov 1990
+
+$header = '$Header: /home/cvs/386BSD/ports/lang/perl/emacs/perldb.pl,v 1.1.1.1 1993/08/23 21:29:46 nate Exp $';
+#
+# This file is automatically included if you do perl -d.
+# It's probably not useful to include this yourself.
+#
+# Perl supplies the values for @line and %sub. It effectively inserts
+# a do DB'DB(<linenum>); in front of every place that can
+# have a breakpoint. It also inserts a do 'perldb.pl' before the first line.
+#
+# $Log: perldb.pl,v $
+# Revision 1.1.1.1 1993/08/23 21:29:46 nate
+# PERL!
+#
+# Revision 4.0 91/03/20 01:18:58 lwall
+# 4.0 baseline.
+#
+# Revision 3.0.1.6 91/01/11 18:08:58 lwall
+# patch42: @_ couldn't be accessed from debugger
+#
+# Revision 3.0.1.5 90/11/10 01:40:26 lwall
+# patch38: the debugger wouldn't stop correctly or do action routines
+#
+# Revision 3.0.1.4 90/10/15 17:40:38 lwall
+# patch29: added caller
+# patch29: the debugger now understands packages and evals
+# patch29: scripts now run at almost full speed under the debugger
+# patch29: more variables are settable from debugger
+#
+# Revision 3.0.1.3 90/08/09 04:00:58 lwall
+# patch19: debugger now allows continuation lines
+# patch19: debugger can now dump lists of variables
+# patch19: debugger can now add aliases easily from prompt
+#
+# Revision 3.0.1.2 90/03/12 16:39:39 lwall
+# patch13: perl -d didn't format stack traces of *foo right
+# patch13: perl -d wiped out scalar return values of subroutines
+#
+# Revision 3.0.1.1 89/10/26 23:14:02 lwall
+# patch1: RCS expanded an unintended $Header in lib/perldb.pl
+#
+# Revision 3.0 89/10/18 15:19:46 lwall
+# 3.0 baseline
+#
+# Revision 2.0 88/06/05 00:09:45 root
+# Baseline version 2.0.
+#
+#
+
+open(IN, "</dev/tty") || open(IN, "<&STDIN"); # so we don't dingle stdin
+open(OUT,">/dev/tty") || open(OUT, ">&STDOUT"); # so we don't dongle stdout
+select(OUT);
+$| = 1; # for DB'OUT
+select(STDOUT);
+$| = 1; # for real STDOUT
+$sub = '';
+
+# Is Perl being run from Emacs?
+$emacs = $main'ARGV[$[] eq '-emacs';
+shift(@main'ARGV) if $emacs;
+
+$header =~ s/.Header: ([^,]+),v(\s+\S+\s+\S+).*$/$1$2/;
+print OUT "\nLoading DB routines from $header\n\nEnter h for help.\n\n";
+
+sub DB {
+ &save;
+ ($package, $filename, $line) = caller;
+ $usercontext = '($@, $!, $[, $,, $/, $\) = @saved;' .
+ "package $package;"; # this won't let them modify, alas
+ local(*dbline) = "_<$filename";
+ $max = $#dbline;
+ if (($stop,$action) = split(/\0/,$dbline{$line})) {
+ if ($stop eq '1') {
+ $signal |= 1;
+ }
+ else {
+ $evalarg = "\$DB'signal |= do {$stop;}"; &eval;
+ $dbline{$line} =~ s/;9($|\0)/$1/;
+ }
+ }
+ if ($single || $trace || $signal) {
+ if ($emacs) {
+ print OUT "\032\032$filename:$line:0\n";
+ } else {
+ print OUT "$package'" unless $sub =~ /'/;
+ print OUT "$sub($filename:$line):\t",$dbline[$line];
+ for ($i = $line + 1; $i <= $max && $dbline[$i] == 0; ++$i) {
+ last if $dbline[$i] =~ /^\s*(}|#|\n)/;
+ print OUT "$sub($filename:$i):\t",$dbline[$i];
+ }
+ }
+ }
+ $evalarg = $action, &eval if $action;
+ if ($single || $signal) {
+ $evalarg = $pre, &eval if $pre;
+ print OUT $#stack . " levels deep in subroutine calls!\n"
+ if $single & 4;
+ $start = $line;
+ while ((print OUT " DB<", $#hist+1, "> "), $cmd=&gets) {
+ $single = 0;
+ $signal = 0;
+ $cmd eq '' && exit 0;
+ chop($cmd);
+ $cmd =~ s/\\$// && do {
+ print OUT " cont: ";
+ $cmd .= &gets;
+ redo;
+ };
+ $cmd =~ /^q$/ && exit 0;
+ $cmd =~ /^$/ && ($cmd = $laststep);
+ push(@hist,$cmd) if length($cmd) > 1;
+ ($i) = split(/\s+/,$cmd);
+ eval "\$cmd =~ $alias{$i}", print OUT $@ if $alias{$i};
+ $cmd =~ /^h$/ && do {
+ print OUT "
+T Stack trace.
+s Single step.
+n Next, steps over subroutine calls.
+r Return from current subroutine.
+c [line] Continue; optionally inserts a one-time-only breakpoint
+ at the specified line.
+<CR> Repeat last n or s.
+l min+incr List incr+1 lines starting at min.
+l min-max List lines.
+l line List line;
+l List next window.
+- List previous window.
+w line List window around line.
+l subname List subroutine.
+f filename Switch to filename.
+/pattern/ Search forwards for pattern; final / is optional.
+?pattern? Search backwards for pattern.
+L List breakpoints and actions.
+S List subroutine names.
+t Toggle trace mode.
+b [line] [condition]
+ Set breakpoint; line defaults to the current execution line;
+ condition breaks if it evaluates to true, defaults to \'1\'.
+b subname [condition]
+ Set breakpoint at first line of subroutine.
+d [line] Delete breakpoint.
+D Delete all breakpoints.
+a [line] command
+ Set an action to be done before the line is executed.
+ Sequence is: check for breakpoint, print line if necessary,
+ do action, prompt user if breakpoint or step, evaluate line.
+A Delete all actions.
+V [pkg [vars]] List some (default all) variables in package (default current).
+X [vars] Same as \"V currentpackage [vars]\".
+< command Define command before prompt.
+| command Define command after prompt.
+! number Redo command (default previous command).
+! -number Redo number\'th to last command.
+H -number Display last number commands (default all).
+q or ^D Quit.
+p expr Same as \"print DB'OUT expr\" in current package.
+= [alias value] Define a command alias, or list current aliases.
+command Execute as a perl statement in current package.
+
+";
+ next; };
+ $cmd =~ /^t$/ && do {
+ $trace = !$trace;
+ print OUT "Trace = ".($trace?"on":"off")."\n";
+ next; };
+ $cmd =~ /^S$/ && do {
+ foreach $subname (sort(keys %sub)) {
+ print OUT $subname,"\n";
+ }
+ next; };
+ $cmd =~ s/^X\b/V $package/;
+ $cmd =~ /^V$/ && do {
+ $cmd = 'V $package'; };
+ $cmd =~ /^V\s*(\S+)\s*(.*)/ && do {
+ $packname = $1;
+ @vars = split(' ',$2);
+ do 'dumpvar.pl' unless defined &main'dumpvar;
+ if (defined &main'dumpvar) {
+ &main'dumpvar($packname,@vars);
+ }
+ else {
+ print DB'OUT "dumpvar.pl not available.\n";
+ }
+ next; };
+ $cmd =~ /^f\s*(.*)/ && do {
+ $file = $1;
+ if (!$file) {
+ print OUT "The old f command is now the r command.\n";
+ print OUT "The new f command switches filenames.\n";
+ next;
+ }
+ if (!defined $_main{'_<' . $file}) {
+ if (($try) = grep(m#^_<.*$file#, keys %_main)) {
+ $file = substr($try,2);
+ print "\n$file:\n";
+ }
+ }
+ if (!defined $_main{'_<' . $file}) {
+ print OUT "There's no code here anything matching $file.\n";
+ next;
+ }
+ elsif ($file ne $filename) {
+ *dbline = "_<$file";
+ $max = $#dbline;
+ $filename = $file;
+ $start = 1;
+ $cmd = "l";
+ } };
+ $cmd =~ /^l\s*(['A-Za-z_]['\w]*)/ && do {
+ $subname = $1;
+ $subname = "main'" . $subname unless $subname =~ /'/;
+ $subname = "main" . $subname if substr($subname,0,1) eq "'";
+ ($file,$subrange) = split(/:/,$sub{$subname});
+ if ($file ne $filename) {
+ *dbline = "_<$file";
+ $max = $#dbline;
+ $filename = $file;
+ }
+ if ($subrange) {
+ if (eval($subrange) < -$window) {
+ $subrange =~ s/-.*/+/;
+ }
+ $cmd = "l $subrange";
+ } else {
+ print OUT "Subroutine $1 not found.\n";
+ next;
+ } };
+ $cmd =~ /^w\s*(\d*)$/ && do {
+ $incr = $window - 1;
+ $start = $1 if $1;
+ $start -= $preview;
+ $cmd = 'l ' . $start . '-' . ($start + $incr); };
+ $cmd =~ /^-$/ && do {
+ $incr = $window - 1;
+ $cmd = 'l ' . ($start-$window*2) . '+'; };
+ $cmd =~ /^l$/ && do {
+ $incr = $window - 1;
+ $cmd = 'l ' . $start . '-' . ($start + $incr); };
+ $cmd =~ /^l\s*(\d*)\+(\d*)$/ && do {
+ $start = $1 if $1;
+ $incr = $2;
+ $incr = $window - 1 unless $incr;
+ $cmd = 'l ' . $start . '-' . ($start + $incr); };
+ $cmd =~ /^l\s*(([\d\$\.]+)([-,]([\d\$\.]+))?)?/ && do {
+ $end = (!$2) ? $max : ($4 ? $4 : $2);
+ $end = $max if $end > $max;
+ $i = $2;
+ $i = $line if $i eq '.';
+ $i = 1 if $i < 1;
+ if ($emacs) {
+ print OUT "\032\032$filename:$i:0\n";
+ $i = $end;
+ } else {
+ for (; $i <= $end; $i++) {
+ print OUT "$i:\t", $dbline[$i];
+ last if $signal;
+ }
+ }
+ $start = $i; # remember in case they want more
+ $start = $max if $start > $max;
+ next; };
+ $cmd =~ /^D$/ && do {
+ print OUT "Deleting all breakpoints...\n";
+ for ($i = 1; $i <= $max ; $i++) {
+ if (defined $dbline{$i}) {
+ $dbline{$i} =~ s/^[^\0]+//;
+ if ($dbline{$i} =~ s/^\0?$//) {
+ delete $dbline{$i};
+ }
+ }
+ }
+ next; };
+ $cmd =~ /^L$/ && do {
+ for ($i = 1; $i <= $max; $i++) {
+ if (defined $dbline{$i}) {
+ print OUT "$i:\t", $dbline[$i];
+ ($stop,$action) = split(/\0/, $dbline{$i});
+ print OUT " break if (", $stop, ")\n"
+ if $stop;
+ print OUT " action: ", $action, "\n"
+ if $action;
+ last if $signal;
+ }
+ }
+ next; };
+ $cmd =~ /^b\s*(['A-Za-z_]['\w]*)\s*(.*)/ && do {
+ $subname = $1;
+ $cond = $2 || '1';
+ $subname = "$package'" . $subname unless $subname =~ /'/;
+ $subname = "main" . $subname if substr($subname,0,1) eq "'";
+ ($filename,$i) = split(/[:-]/, $sub{$subname});
+ if ($i) {
+ *dbline = "_<$filename";
+ ++$i while $dbline[$i] == 0 && $i < $#dbline;
+ $dbline{$i} =~ s/^[^\0]*/$cond/;
+ } else {
+ print OUT "Subroutine $subname not found.\n";
+ }
+ next; };
+ $cmd =~ /^b\s*(\d*)\s*(.*)/ && do {
+ $i = ($1?$1:$line);
+ $cond = $2 || '1';
+ if ($dbline[$i] == 0) {
+ print OUT "Line $i not breakable.\n";
+ } else {
+ $dbline{$i} =~ s/^[^\0]*/$cond/;
+ }
+ next; };
+ $cmd =~ /^d\s*(\d+)?/ && do {
+ $i = ($1?$1:$line);
+ $dbline{$i} =~ s/^[^\0]*//;
+ delete $dbline{$i} if $dbline{$i} eq '';
+ next; };
+ $cmd =~ /^A$/ && do {
+ for ($i = 1; $i <= $max ; $i++) {
+ if (defined $dbline{$i}) {
+ $dbline{$i} =~ s/\0[^\0]*//;
+ delete $dbline{$i} if $dbline{$i} eq '';
+ }
+ }
+ next; };
+ $cmd =~ /^<\s*(.*)/ && do {
+ $pre = do action($1);
+ next; };
+ $cmd =~ /^>\s*(.*)/ && do {
+ $post = do action($1);
+ next; };
+ $cmd =~ /^a\s*(\d+)(\s+(.*))?/ && do {
+ $i = $1;
+ if ($dbline[$i] == 0) {
+ print OUT "Line $i may not have an action.\n";
+ } else {
+ $dbline{$i} =~ s/\0[^\0]*//;
+ $dbline{$i} .= "\0" . do action($3);
+ }
+ next; };
+ $cmd =~ /^n$/ && do {
+ $single = 2;
+ $laststep = $cmd;
+ last; };
+ $cmd =~ /^s$/ && do {
+ $single = 1;
+ $laststep = $cmd;
+ last; };
+ $cmd =~ /^c\s*(\d*)\s*$/ && do {
+ $i = $1;
+ if ($i) {
+ if ($dbline[$i] == 0) {
+ print OUT "Line $i not breakable.\n";
+ next;
+ }
+ $dbline{$i} =~ s/(\0|$)/;9$1/; # add one-time-only b.p.
+ }
+ for ($i=0; $i <= $#stack; ) {
+ $stack[$i++] &= ~1;
+ }
+ last; };
+ $cmd =~ /^r$/ && do {
+ $stack[$#stack] |= 2;
+ last; };
+ $cmd =~ /^T$/ && do {
+ local($p,$f,$l,$s,$h,$a,@a,@sub);
+ for ($i = 1; ($p,$f,$l,$s,$h,$w) = caller($i); $i++) {
+ @a = @args;
+ for (@a) {
+ if (/^StB\000/ && length($_) == length($_main{'_main'})) {
+ $_ = sprintf("%s",$_);
+ }
+ else {
+ s/'/\\'/g;
+ s/([^\0]*)/'$1'/ unless /^-?[\d.]+$/;
+ s/([\200-\377])/sprintf("M-%c",ord($1)&0177)/eg;
+ s/([\0-\37\177])/sprintf("^%c",ord($1)^64)/eg;
+ }
+ }
+ $w = $w ? '@ = ' : '$ = ';
+ $a = $h ? '(' . join(', ', @a) . ')' : '';
+ push(@sub, "$w&$s$a from file $f line $l\n");
+ last if $signal;
+ }
+ for ($i=0; $i <= $#sub; $i++) {
+ last if $signal;
+ print OUT $sub[$i];
+ }
+ next; };
+ $cmd =~ /^\/(.*)$/ && do {
+ $inpat = $1;
+ $inpat =~ s:([^\\])/$:$1:;
+ if ($inpat ne "") {
+ eval '$inpat =~ m'."\n$inpat\n";
+ if ($@ ne "") {
+ print OUT "$@";
+ next;
+ }
+ $pat = $inpat;
+ }
+ $end = $start;
+ eval '
+ for (;;) {
+ ++$start;
+ $start = 1 if ($start > $max);
+ last if ($start == $end);
+ if ($dbline[$start] =~ m'."\n$pat\n".'i) {
+ if ($emacs) {
+ print OUT "\032\032$filename:$start:0\n";
+ } else {
+ print OUT "$start:\t", $dbline[$start], "\n";
+ }
+ last;
+ }
+ } ';
+ print OUT "/$pat/: not found\n" if ($start == $end);
+ next; };
+ $cmd =~ /^\?(.*)$/ && do {
+ $inpat = $1;
+ $inpat =~ s:([^\\])\?$:$1:;
+ if ($inpat ne "") {
+ eval '$inpat =~ m'."\n$inpat\n";
+ if ($@ ne "") {
+ print OUT "$@";
+ next;
+ }
+ $pat = $inpat;
+ }
+ $end = $start;
+ eval '
+ for (;;) {
+ --$start;
+ $start = $max if ($start <= 0);
+ last if ($start == $end);
+ if ($dbline[$start] =~ m'."\n$pat\n".'i) {
+ if ($emacs) {
+ print OUT "\032\032$filename:$start:0\n";
+ } else {
+ print OUT "$start:\t", $dbline[$start], "\n";
+ }
+ last;
+ }
+ } ';
+ print OUT "?$pat?: not found\n" if ($start == $end);
+ next; };
+ $cmd =~ /^!+\s*(-)?(\d+)?$/ && do {
+ pop(@hist) if length($cmd) > 1;
+ $i = ($1?($#hist-($2?$2:1)):($2?$2:$#hist));
+ $cmd = $hist[$i] . "\n";
+ print OUT $cmd;
+ redo; };
+ $cmd =~ /^!(.+)$/ && do {
+ $pat = "^$1";
+ pop(@hist) if length($cmd) > 1;
+ for ($i = $#hist; $i; --$i) {
+ last if $hist[$i] =~ $pat;
+ }
+ if (!$i) {
+ print OUT "No such command!\n\n";
+ next;
+ }
+ $cmd = $hist[$i] . "\n";
+ print OUT $cmd;
+ redo; };
+ $cmd =~ /^H\s*(-(\d+))?/ && do {
+ $end = $2?($#hist-$2):0;
+ $hist = 0 if $hist < 0;
+ for ($i=$#hist; $i>$end; $i--) {
+ print OUT "$i: ",$hist[$i],"\n"
+ unless $hist[$i] =~ /^.?$/;
+ };
+ next; };
+ $cmd =~ s/^p( .*)?$/print DB'OUT$1/;
+ $cmd =~ /^=/ && do {
+ if (local($k,$v) = ($cmd =~ /^=\s*(\S+)\s+(.*)/)) {
+ $alias{$k}="s~$k~$v~";
+ print OUT "$k = $v\n";
+ } elsif ($cmd =~ /^=\s*$/) {
+ foreach $k (sort keys(%alias)) {
+ if (($v = $alias{$k}) =~ s~^s\~$k\~(.*)\~$~$1~) {
+ print OUT "$k = $v\n";
+ } else {
+ print OUT "$k\t$alias{$k}\n";
+ };
+ };
+ };
+ next; };
+ $evalarg = $cmd; &eval;
+ print OUT "\n";
+ }
+ if ($post) {
+ $evalarg = $post; &eval;
+ }
+ }
+ ($@, $!, $[, $,, $/, $\) = @saved;
+}
+
+sub save {
+ @saved = ($@, $!, $[, $,, $/, $\);
+ $[ = 0; $, = ""; $/ = "\n"; $\ = "";
+}
+
+# The following takes its argument via $evalarg to preserve current @_
+
+sub eval {
+ eval "$usercontext $evalarg; &DB'save";
+ print OUT $@;
+}
+
+sub action {
+ local($action) = @_;
+ while ($action =~ s/\\$//) {
+ print OUT "+ ";
+ $action .= &gets;
+ }
+ $action;
+}
+
+sub gets {
+ local($.);
+ <IN>;
+}
+
+sub catch {
+ $signal = 1;
+}
+
+sub sub {
+ push(@stack, $single);
+ $single &= 1;
+ $single |= 4 if $#stack == $deep;
+ if (wantarray) {
+ @i = &$sub;
+ $single |= pop(@stack);
+ @i;
+ }
+ else {
+ $i = &$sub;
+ $single |= pop(@stack);
+ $i;
+ }
+}
+
+$single = 1; # so it stops on first executable statement
+@hist = ('?');
+$SIG{'INT'} = "DB'catch";
+$deep = 100; # warning if stack gets this deep
+$window = 10;
+$preview = 3;
+
+@stack = (0);
+@ARGS = @ARGV;
+for (@args) {
+ s/'/\\'/g;
+ s/(.*)/'$1'/ unless /^-?[\d.]+$/;
+}
+
+if (-f '.perldb') {
+ do './.perldb';
+}
+elsif (-f "$ENV{'LOGDIR'}/.perldb") {
+ do "$ENV{'LOGDIR'}/.perldb";
+}
+elsif (-f "$ENV{'HOME'}/.perldb") {
+ do "$ENV{'HOME'}/.perldb";
+}
+
+1;
diff --git a/gnu/usr.bin/perl/emacs/tedstuff b/gnu/usr.bin/perl/emacs/tedstuff
new file mode 100644
index 0000000..257bbc8
--- /dev/null
+++ b/gnu/usr.bin/perl/emacs/tedstuff
@@ -0,0 +1,296 @@
+Article 4417 of comp.lang.perl:
+Path: jpl-devvax!elroy.jpl.nasa.gov!decwrl!mcnc!uvaarpa!mmdf
+From: ted@evi.com (Ted Stefanik)
+Newsgroups: comp.lang.perl
+Subject: Correction to Perl fatal error marking in GNU Emacs
+Message-ID: <1991Feb27.065853.15801@uvaarpa.Virginia.EDU>
+Date: 27 Feb 91 06:58:53 GMT
+Sender: mmdf@uvaarpa.Virginia.EDU (Uvaarpa Mail System)
+Reply-To: ted@evi.com (Ted Stefanik)
+Organization: The Internet
+Lines: 282
+
+Reading my own message, it occurred to me that I didn't quite satisfy the
+request of stef@zweig.sun (Stephane Payrard):
+
+| Does anyone has extended perdb/perdb.el to position the
+| point to the first syntax error? It would be cool.
+
+What I posted is a way to use the "M-x compile" command to test perl scripts.
+(Needless to say, the script cannot be not interactive; you can't provide input
+to a *compilation* buffer). When creating new Perl programs, I use "M-x
+compile" until I'm sure that they are syntatically correct; if syntax errors
+occur, C-x` takes me to each in sequence. After I'm sure the syntax is
+correct, I start worrying about semantics, and switch to "M-x perldb" if
+necessary.
+
+Therefore, the stuff I posted works great with "M-x compile", but not at all
+with "M-x perldb".
+
+Next, let me update what I posted. I found that perl's die() command doesn't
+print the same format error message as perl does when it dies with a syntax
+error. If you put the following in your ".emacs" file, it causes C-x` to
+recognize both kinds of errors:
+
+(load-library "compile")
+(setq compilation-error-regexp
+ "\\([^ :\n]+\\(: *\\|, line \\|(\\)[0-9]+\\)\\|\\([0-9]+ *of *[^ \n]+\\|[^ \n]+ \\(at \\)*line [0-9]+\\)")
+
+Last, so I don't look like a total fool, let me propose a way to satisfy
+Stephane Payrard's original request (repeated again):
+
+| Does anyone has extended perdb/perdb.el to position the
+| point to the first syntax error? It would be cool.
+
+I'm not satisfied with just the "first syntax error". Perl's parser is better
+than most about not getting out of sync; therefore, if it reports multiple
+errors, you can usually be assured they are all real errors.
+
+So... I hacked in the "next-error" function from "compile.el" to form
+"perldb-next-error". You can apply the patches at the end of this message
+to add "perldb-next-error" to your "perldb.el".
+
+Notes:
+ 1) The patch binds "perldb-next-error" to C-x~ (because ~ is the shift
+ of ` on my keyboard, and C-x~ is not yet taken in my version of EMACS).
+
+ 2) "next-error" is meant to work on a single *compilation* buffer; any new
+ "M-x compile" or "M-x grep" command will clear the old *compilation*
+ buffer and reset the compilation-error parser to start at the top of the
+ *compilation* buffer.
+
+ "perldb-next-error", on the other hand, has to deal with multiple
+ *perldb-<foo>* buffers, each of which keep growing. "perldb-next-error"
+ correctly handles the constantly growing *perldb-<foo>* buffers by
+ keeping track of the last reported error in the "current-perldb-buffer".
+
+ Sadly however, when you invoke a new "M-x perldb" on a different Perl
+ script, "perldb-next-error" will start parsing the new *perldb-<bar>*
+ buffer at the top (even if it was previously parsed), and will completely
+ lose the marker of the last reported error in *perldb-<foo>*.
+
+ 3) "perldb-next-error" still uses "compilation-error-regexp" to find
+ fatal errors. Therefore, both the "M-x compile"/C-x` scheme and
+ the "M-x perldb"/C-x~ scheme can be used to find fatal errors that
+ match the common "compilation-error-regexp". You *will* want to install
+ that "compilation-error-regexp" stuff into your .emacs file.
+
+ 4) The patch was developed and tested with GNU Emacs 18.55.
+
+ 5) Since the patch was ripped off from compile.el, the code is (of
+ course) subject to the GNU copyleft.
+
+*** perldb.el.orig Wed Feb 27 00:44:27 1991
+--- perldb.el Wed Feb 27 00:44:30 1991
+***************
+*** 199,205 ****
+
+ (defun perldb-set-buffer ()
+ (cond ((eq major-mode 'perldb-mode)
+! (setq current-perldb-buffer (current-buffer)))))
+
+ ;; This function is responsible for inserting output from Perl
+ ;; into the buffer.
+--- 199,211 ----
+
+ (defun perldb-set-buffer ()
+ (cond ((eq major-mode 'perldb-mode)
+! (cond ((not (eq current-perldb-buffer (current-buffer)))
+! (perldb-forget-errors)
+! (setq perldb-parsing-end 2)) ;; 2 to defeat grep defeater
+! (t
+! (if (> perldb-parsing-end (point-max))
+! (setq perldb-parsing-end (max (point-max) 2)))))
+! (setq current-perldb-buffer (current-buffer)))))
+
+ ;; This function is responsible for inserting output from Perl
+ ;; into the buffer.
+***************
+*** 291,297 ****
+ ;; process-buffer is current-buffer
+ (unwind-protect
+ (progn
+! ;; Write something in *compilation* and hack its mode line,
+ (set-buffer (process-buffer proc))
+ ;; Force mode line redisplay soon
+ (set-buffer-modified-p (buffer-modified-p))
+--- 297,303 ----
+ ;; process-buffer is current-buffer
+ (unwind-protect
+ (progn
+! ;; Write something in *perldb-<foo>* and hack its mode line,
+ (set-buffer (process-buffer proc))
+ ;; Force mode line redisplay soon
+ (set-buffer-modified-p (buffer-modified-p))
+***************
+*** 421,423 ****
+--- 427,593 ----
+ (switch-to-buffer-other-window current-perldb-buffer)
+ (goto-char (dot-max))
+ (insert-string comm)))
++
++ (defvar perldb-error-list nil
++ "List of error message descriptors for visiting erring functions.
++ Each error descriptor is a list of length two.
++ Its car is a marker pointing to an error message.
++ Its cadr is a marker pointing to the text of the line the message is about,
++ or nil if that is not interesting.
++ The value may be t instead of a list;
++ this means that the buffer of error messages should be reparsed
++ the next time the list of errors is wanted.")
++
++ (defvar perldb-parsing-end nil
++ "Position of end of buffer when last error messages parsed.")
++
++ (defvar perldb-error-message "No more fatal Perl errors"
++ "Message to print when no more matches for compilation-error-regexp are found")
++
++ (defun perldb-next-error (&optional argp)
++ "Visit next perldb error message and corresponding source code.
++ This operates on the output from the \\[perldb] command.
++ If all preparsed error messages have been processed,
++ the error message buffer is checked for new ones.
++ A non-nil argument (prefix arg, if interactive)
++ means reparse the error message buffer and start at the first error."
++ (interactive "P")
++ (if (or (eq perldb-error-list t)
++ argp)
++ (progn (perldb-forget-errors)
++ (setq perldb-parsing-end 2))) ;; 2 to defeat grep defeater
++ (if perldb-error-list
++ nil
++ (save-excursion
++ (switch-to-buffer current-perldb-buffer)
++ (perldb-parse-errors)))
++ (let ((next-error (car perldb-error-list)))
++ (if (null next-error)
++ (error (concat perldb-error-message
++ (if (and (get-buffer-process current-perldb-buffer)
++ (eq (process-status
++ (get-buffer-process
++ current-perldb-buffer))
++ 'run))
++ " yet" ""))))
++ (setq perldb-error-list (cdr perldb-error-list))
++ (if (null (car (cdr next-error)))
++ nil
++ (switch-to-buffer (marker-buffer (car (cdr next-error))))
++ (goto-char (car (cdr next-error)))
++ (set-marker (car (cdr next-error)) nil))
++ (let* ((pop-up-windows t)
++ (w (display-buffer (marker-buffer (car next-error)))))
++ (set-window-point w (car next-error))
++ (set-window-start w (car next-error)))
++ (set-marker (car next-error) nil)))
++
++ ;; Set perldb-error-list to nil, and
++ ;; unchain the markers that point to the error messages and their text,
++ ;; so that they no longer slow down gap motion.
++ ;; This would happen anyway at the next garbage collection,
++ ;; but it is better to do it right away.
++ (defun perldb-forget-errors ()
++ (if (eq perldb-error-list t)
++ (setq perldb-error-list nil))
++ (while perldb-error-list
++ (let ((next-error (car perldb-error-list)))
++ (set-marker (car next-error) nil)
++ (if (car (cdr next-error))
++ (set-marker (car (cdr next-error)) nil)))
++ (setq perldb-error-list (cdr perldb-error-list))))
++
++ (defun perldb-parse-errors ()
++ "Parse the current buffer as error messages.
++ This makes a list of error descriptors, perldb-error-list.
++ For each source-file, line-number pair in the buffer,
++ the source file is read in, and the text location is saved in perldb-error-list.
++ The function next-error, assigned to \\[next-error], takes the next error off the list
++ and visits its location."
++ (setq perldb-error-list nil)
++ (message "Parsing error messages...")
++ (let (text-buffer
++ last-filename last-linenum)
++ ;; Don't reparse messages already seen at last parse.
++ (goto-char perldb-parsing-end)
++ ;; Don't parse the first two lines as error messages.
++ ;; This matters for grep.
++ (if (bobp)
++ (forward-line 2))
++ (while (re-search-forward compilation-error-regexp nil t)
++ (let (linenum filename
++ error-marker text-marker)
++ ;; Extract file name and line number from error message.
++ (save-restriction
++ (narrow-to-region (match-beginning 0) (match-end 0))
++ (goto-char (point-max))
++ (skip-chars-backward "[0-9]")
++ ;; If it's a lint message, use the last file(linenum) on the line.
++ ;; Normally we use the first on the line.
++ (if (= (preceding-char) ?\()
++ (progn
++ (narrow-to-region (point-min) (1+ (buffer-size)))
++ (end-of-line)
++ (re-search-backward compilation-error-regexp)
++ (skip-chars-backward "^ \t\n")
++ (narrow-to-region (point) (match-end 0))
++ (goto-char (point-max))
++ (skip-chars-backward "[0-9]")))
++ ;; Are we looking at a "filename-first" or "line-number-first" form?
++ (if (looking-at "[0-9]")
++ (progn
++ (setq linenum (read (current-buffer)))
++ (goto-char (point-min)))
++ ;; Line number at start, file name at end.
++ (progn
++ (goto-char (point-min))
++ (setq linenum (read (current-buffer)))
++ (goto-char (point-max))
++ (skip-chars-backward "^ \t\n")))
++ (setq filename (perldb-grab-filename)))
++ ;; Locate the erring file and line.
++ (if (and (equal filename last-filename)
++ (= linenum last-linenum))
++ nil
++ (beginning-of-line 1)
++ (setq error-marker (point-marker))
++ ;; text-buffer gets the buffer containing this error's file.
++ (if (not (equal filename last-filename))
++ (setq text-buffer
++ (and (file-exists-p (setq last-filename filename))
++ (find-file-noselect filename))
++ last-linenum 0))
++ (if text-buffer
++ ;; Go to that buffer and find the erring line.
++ (save-excursion
++ (set-buffer text-buffer)
++ (if (zerop last-linenum)
++ (progn
++ (goto-char 1)
++ (setq last-linenum 1)))
++ (forward-line (- linenum last-linenum))
++ (setq last-linenum linenum)
++ (setq text-marker (point-marker))
++ (setq perldb-error-list
++ (cons (list error-marker text-marker)
++ perldb-error-list)))))
++ (forward-line 1)))
++ (setq perldb-parsing-end (point-max)))
++ (message "Parsing error messages...done")
++ (setq perldb-error-list (nreverse perldb-error-list)))
++
++ (defun perldb-grab-filename ()
++ "Return a string which is a filename, starting at point.
++ Ignore quotes and parentheses around it, as well as trailing colons."
++ (if (eq (following-char) ?\")
++ (save-restriction
++ (narrow-to-region (point)
++ (progn (forward-sexp 1) (point)))
++ (goto-char (point-min))
++ (read (current-buffer)))
++ (buffer-substring (point)
++ (progn
++ (skip-chars-forward "^ :,\n\t(")
++ (point)))))
++
++ (define-key ctl-x-map "~" 'perldb-next-error)
+
+
diff --git a/gnu/usr.bin/perl/h2pl/README b/gnu/usr.bin/perl/h2pl/README
new file mode 100644
index 0000000..5fe8ae7
--- /dev/null
+++ b/gnu/usr.bin/perl/h2pl/README
@@ -0,0 +1,71 @@
+[This file of Tom Christiansen's has been edited to change makelib to h2ph
+and .h to .ph where appropriate--law.]
+
+This directory contains files to help you convert the *.ph files generated my
+h2ph out of the perl source directory into *.pl files with all the
+indirection of the subroutine calls removed. The .ph version will be more
+safely portable, because if something isn't defined on the new system, like
+&TIOCGETP, then you'll get a fatal run-time error on the system lacking that
+function. Using the .pl version means that the subsequent scripts will give
+you a 0 $TIOCGETP and God only knows what may then happen. Still, I like the
+.pl stuff because they're faster to load.
+
+FIrst, you need to run h2ph on things like sys/ioctl.h to get stuff
+into the perl library directory, often /usr/local/lib/perl. For example,
+ # h2ph sys/ioctl.h
+takes /usr/include/sys/ioctl.h as input and writes (without i/o redirection)
+the file /usr/local/lib/perl/sys/ioctl.ph, which looks like this
+
+ eval 'sub TIOCM_RTS {0004;}';
+ eval 'sub TIOCM_ST {0010;}';
+ eval 'sub TIOCM_SR {0020;}';
+ eval 'sub TIOCM_CTS {0040;}';
+ eval 'sub TIOCM_CAR {0100;}';
+
+and much worse, rather than what Larry's ioctl.pl from the perl source dir has,
+which is:
+
+ $TIOCM_RTS = 0004;
+ $TIOCM_ST = 0010;
+ $TIOCM_SR = 0020;
+ $TIOCM_CTS = 0040;
+ $TIOCM_CAR = 0100;
+
+[Workaround for fixed bug in makedir/h2ph deleted--law.]
+
+The more complicated ioctl subs look like this:
+
+ eval 'sub TIOCGSIZE {&TIOCGWINSZ;}';
+ eval 'sub TIOCGWINSZ {&_IOR("t", 104, \'struct winsize\');}';
+ eval 'sub TIOCSETD {&_IOW("t", 1, \'int\');}';
+ eval 'sub TIOCGETP {&_IOR("t", 8,\'struct sgttyb\');}';
+
+The _IO[RW] routines use a %sizeof array, which (presumably)
+is keyed on the type name with the value being the size in bytes.
+
+To build %sizeof, try running this in this directory:
+
+ % ./getioctlsizes
+
+Which will tell you which things the %sizeof array needs
+to hold. You can try to build a sizeof.ph file with:
+
+ % ./getioctlsizes | ./mksizes > sizeof.ph
+
+Note that mksizes hardcodes the #include files for all the types, so it will
+probably require customization. Once you have sizeof.ph, install it in the
+perl library directory. Run my tcbreak script to see whether you can do
+ioctls in perl now. You'll get some kind of fatal run-time error if you
+can't. That script should be included in this directory.
+
+If this works well, now you can try to convert the *.ph files into
+*.pl files. Try this:
+
+ foreach file ( sysexits.ph sys/{errno.ph,ioctl.ph} )
+ ./mkvars $file > t/$file:r.pl
+ end
+
+The last one will be the hardest. If it works, should be able to
+run tcbreak2 and have it work the same as tcbreak.
+
+Good luck.
diff --git a/gnu/usr.bin/perl/h2pl/cbreak.pl b/gnu/usr.bin/perl/h2pl/cbreak.pl
new file mode 100644
index 0000000..422185e
--- /dev/null
+++ b/gnu/usr.bin/perl/h2pl/cbreak.pl
@@ -0,0 +1,34 @@
+$sgttyb_t = 'C4 S';
+
+sub cbreak {
+ &set_cbreak(1);
+}
+
+sub cooked {
+ &set_cbreak(0);
+}
+
+sub set_cbreak {
+ local($on) = @_;
+
+ require 'sizeof.ph';
+ require 'sys/ioctl.ph';
+
+ ioctl(STDIN,&TIOCGETP,$sgttyb)
+ || die "Can't ioctl TIOCGETP: $!";
+
+ @ary = unpack($sgttyb_t,$sgttyb);
+ if ($on) {
+ $ary[4] |= &CBREAK;
+ $ary[4] &= ~&ECHO;
+ } else {
+ $ary[4] &= ~&CBREAK;
+ $ary[4] |= &ECHO;
+ }
+ $sgttyb = pack($sgttyb_t,@ary);
+ ioctl(STDIN,&TIOCSETP,$sgttyb)
+ || die "Can't ioctl TIOCSETP: $!";
+
+}
+
+1;
diff --git a/gnu/usr.bin/perl/h2pl/cbreak2.pl b/gnu/usr.bin/perl/h2pl/cbreak2.pl
new file mode 100644
index 0000000..8ac55a3
--- /dev/null
+++ b/gnu/usr.bin/perl/h2pl/cbreak2.pl
@@ -0,0 +1,33 @@
+$sgttyb_t = 'C4 S';
+
+sub cbreak {
+ &set_cbreak(1);
+}
+
+sub cooked {
+ &set_cbreak(0);
+}
+
+sub set_cbreak {
+ local($on) = @_;
+
+ require 'sys/ioctl.pl';
+
+ ioctl(STDIN,$TIOCGETP,$sgttyb)
+ || die "Can't ioctl TIOCGETP: $!";
+
+ @ary = unpack($sgttyb_t,$sgttyb);
+ if ($on) {
+ $ary[4] |= $CBREAK;
+ $ary[4] &= ~$ECHO;
+ } else {
+ $ary[4] &= ~$CBREAK;
+ $ary[4] |= $ECHO;
+ }
+ $sgttyb = pack($sgttyb_t,@ary);
+ ioctl(STDIN,$TIOCSETP,$sgttyb)
+ || die "Can't ioctl TIOCSETP: $!";
+
+}
+
+1;
diff --git a/gnu/usr.bin/perl/h2pl/eg/sizeof.ph b/gnu/usr.bin/perl/h2pl/eg/sizeof.ph
new file mode 100644
index 0000000..285bff1
--- /dev/null
+++ b/gnu/usr.bin/perl/h2pl/eg/sizeof.ph
@@ -0,0 +1,14 @@
+$sizeof{'char'} = 1;
+$sizeof{'int'} = 4;
+$sizeof{'long'} = 4;
+$sizeof{'struct arpreq'} = 36;
+$sizeof{'struct ifconf'} = 8;
+$sizeof{'struct ifreq'} = 32;
+$sizeof{'struct ltchars'} = 6;
+$sizeof{'struct pcntl'} = 116;
+$sizeof{'struct rtentry'} = 52;
+$sizeof{'struct sgttyb'} = 6;
+$sizeof{'struct tchars'} = 6;
+$sizeof{'struct ttychars'} = 14;
+$sizeof{'struct winsize'} = 8;
+$sizeof{'struct termios'} = 132;
diff --git a/gnu/usr.bin/perl/h2pl/eg/sys/errno.pl b/gnu/usr.bin/perl/h2pl/eg/sys/errno.pl
new file mode 100644
index 0000000..d9ba3be
--- /dev/null
+++ b/gnu/usr.bin/perl/h2pl/eg/sys/errno.pl
@@ -0,0 +1,92 @@
+$EPERM = 0x1;
+$ENOENT = 0x2;
+$ESRCH = 0x3;
+$EINTR = 0x4;
+$EIO = 0x5;
+$ENXIO = 0x6;
+$E2BIG = 0x7;
+$ENOEXEC = 0x8;
+$EBADF = 0x9;
+$ECHILD = 0xA;
+$EAGAIN = 0xB;
+$ENOMEM = 0xC;
+$EACCES = 0xD;
+$EFAULT = 0xE;
+$ENOTBLK = 0xF;
+$EBUSY = 0x10;
+$EEXIST = 0x11;
+$EXDEV = 0x12;
+$ENODEV = 0x13;
+$ENOTDIR = 0x14;
+$EISDIR = 0x15;
+$EINVAL = 0x16;
+$ENFILE = 0x17;
+$EMFILE = 0x18;
+$ENOTTY = 0x19;
+$ETXTBSY = 0x1A;
+$EFBIG = 0x1B;
+$ENOSPC = 0x1C;
+$ESPIPE = 0x1D;
+$EROFS = 0x1E;
+$EMLINK = 0x1F;
+$EPIPE = 0x20;
+$EDOM = 0x21;
+$ERANGE = 0x22;
+$EWOULDBLOCK = 0x23;
+$EINPROGRESS = 0x24;
+$EALREADY = 0x25;
+$ENOTSOCK = 0x26;
+$EDESTADDRREQ = 0x27;
+$EMSGSIZE = 0x28;
+$EPROTOTYPE = 0x29;
+$ENOPROTOOPT = 0x2A;
+$EPROTONOSUPPORT = 0x2B;
+$ESOCKTNOSUPPORT = 0x2C;
+$EOPNOTSUPP = 0x2D;
+$EPFNOSUPPORT = 0x2E;
+$EAFNOSUPPORT = 0x2F;
+$EADDRINUSE = 0x30;
+$EADDRNOTAVAIL = 0x31;
+$ENETDOWN = 0x32;
+$ENETUNREACH = 0x33;
+$ENETRESET = 0x34;
+$ECONNABORTED = 0x35;
+$ECONNRESET = 0x36;
+$ENOBUFS = 0x37;
+$EISCONN = 0x38;
+$ENOTCONN = 0x39;
+$ESHUTDOWN = 0x3A;
+$ETOOMANYREFS = 0x3B;
+$ETIMEDOUT = 0x3C;
+$ECONNREFUSED = 0x3D;
+$ELOOP = 0x3E;
+$ENAMETOOLONG = 0x3F;
+$EHOSTDOWN = 0x40;
+$EHOSTUNREACH = 0x41;
+$ENOTEMPTY = 0x42;
+$EPROCLIM = 0x43;
+$EUSERS = 0x44;
+$EDQUOT = 0x45;
+$ESTALE = 0x46;
+$EREMOTE = 0x47;
+$EDEADLK = 0x48;
+$ENOLCK = 0x49;
+$MTH_UNDEF_SQRT = 0x12C;
+$MTH_OVF_EXP = 0x12D;
+$MTH_UNDEF_LOG = 0x12E;
+$MTH_NEG_BASE = 0x12F;
+$MTH_ZERO_BASE = 0x130;
+$MTH_OVF_POW = 0x131;
+$MTH_LRG_SIN = 0x132;
+$MTH_LRG_COS = 0x133;
+$MTH_LRG_TAN = 0x134;
+$MTH_LRG_COT = 0x135;
+$MTH_OVF_TAN = 0x136;
+$MTH_OVF_COT = 0x137;
+$MTH_UNDEF_ASIN = 0x138;
+$MTH_UNDEF_ACOS = 0x139;
+$MTH_UNDEF_ATAN2 = 0x13A;
+$MTH_OVF_SINH = 0x13B;
+$MTH_OVF_COSH = 0x13C;
+$MTH_UNDEF_ZLOG = 0x13D;
+$MTH_UNDEF_ZDIV = 0x13E;
diff --git a/gnu/usr.bin/perl/h2pl/eg/sys/ioctl.pl b/gnu/usr.bin/perl/h2pl/eg/sys/ioctl.pl
new file mode 100644
index 0000000..0b552ca
--- /dev/null
+++ b/gnu/usr.bin/perl/h2pl/eg/sys/ioctl.pl
@@ -0,0 +1,186 @@
+$_IOCTL_ = 0x1;
+$TIOCGSIZE = 0x40087468;
+$TIOCSSIZE = 0x80087467;
+$IOCPARM_MASK = 0x7F;
+$IOC_VOID = 0x20000000;
+$IOC_OUT = 0x40000000;
+$IOC_IN = 0x80000000;
+$IOC_INOUT = 0xC0000000;
+$TIOCGETD = 0x40047400;
+$TIOCSETD = 0x80047401;
+$TIOCHPCL = 0x20007402;
+$TIOCMODG = 0x40047403;
+$TIOCMODS = 0x80047404;
+$TIOCM_LE = 0x1;
+$TIOCM_DTR = 0x2;
+$TIOCM_RTS = 0x4;
+$TIOCM_ST = 0x8;
+$TIOCM_SR = 0x10;
+$TIOCM_CTS = 0x20;
+$TIOCM_CAR = 0x40;
+$TIOCM_CD = 0x40;
+$TIOCM_RNG = 0x80;
+$TIOCM_RI = 0x80;
+$TIOCM_DSR = 0x100;
+$TIOCGETP = 0x40067408;
+$TIOCSETP = 0x80067409;
+$TIOCSETN = 0x8006740A;
+$TIOCEXCL = 0x2000740D;
+$TIOCNXCL = 0x2000740E;
+$TIOCFLUSH = 0x80047410;
+$TIOCSETC = 0x80067411;
+$TIOCGETC = 0x40067412;
+$TIOCSET = 0x80047413;
+$TIOCBIS = 0x80047414;
+$TIOCBIC = 0x80047415;
+$TIOCGET = 0x40047416;
+$TANDEM = 0x1;
+$CBREAK = 0x2;
+$LCASE = 0x4;
+$ECHO = 0x8;
+$CRMOD = 0x10;
+$RAW = 0x20;
+$ODDP = 0x40;
+$EVENP = 0x80;
+$ANYP = 0xC0;
+$NLDELAY = 0x300;
+$NL0 = 0x0;
+$NL1 = 0x100;
+$NL2 = 0x200;
+$NL3 = 0x300;
+$TBDELAY = 0xC00;
+$TAB0 = 0x0;
+$TAB1 = 0x400;
+$TAB2 = 0x800;
+$XTABS = 0xC00;
+$CRDELAY = 0x3000;
+$CR0 = 0x0;
+$CR1 = 0x1000;
+$CR2 = 0x2000;
+$CR3 = 0x3000;
+$VTDELAY = 0x4000;
+$FF0 = 0x0;
+$FF1 = 0x4000;
+$BSDELAY = 0x8000;
+$BS0 = 0x0;
+$BS1 = 0x8000;
+$ALLDELAY = 0xFF00;
+$CRTBS = 0x10000;
+$PRTERA = 0x20000;
+$CRTERA = 0x40000;
+$TILDE = 0x80000;
+$MDMBUF = 0x100000;
+$LITOUT = 0x200000;
+$TOSTOP = 0x400000;
+$FLUSHO = 0x800000;
+$NOHANG = 0x1000000;
+$L001000 = 0x2000000;
+$CRTKIL = 0x4000000;
+$L004000 = 0x8000000;
+$CTLECH = 0x10000000;
+$PENDIN = 0x20000000;
+$DECCTQ = 0x40000000;
+$NOFLSH = 0x80000000;
+$TIOCCSET = 0x800E7417;
+$TIOCCGET = 0x400E7418;
+$TIOCLBIS = 0x8004747F;
+$TIOCLBIC = 0x8004747E;
+$TIOCLSET = 0x8004747D;
+$TIOCLGET = 0x4004747C;
+$LCRTBS = 0x1;
+$LPRTERA = 0x2;
+$LCRTERA = 0x4;
+$LTILDE = 0x8;
+$LMDMBUF = 0x10;
+$LLITOUT = 0x20;
+$LTOSTOP = 0x40;
+$LFLUSHO = 0x80;
+$LNOHANG = 0x100;
+$LCRTKIL = 0x400;
+$LCTLECH = 0x1000;
+$LPENDIN = 0x2000;
+$LDECCTQ = 0x4000;
+$LNOFLSH = 0x8000;
+$TIOCSBRK = 0x2000747B;
+$TIOCCBRK = 0x2000747A;
+$TIOCSDTR = 0x20007479;
+$TIOCCDTR = 0x20007478;
+$TIOCGPGRP = 0x40047477;
+$TIOCSPGRP = 0x80047476;
+$TIOCSLTC = 0x80067475;
+$TIOCGLTC = 0x40067474;
+$TIOCOUTQ = 0x40047473;
+$TIOCSTI = 0x80017472;
+$TIOCNOTTY = 0x20007471;
+$TIOCPKT = 0x80047470;
+$TIOCPKT_DATA = 0x0;
+$TIOCPKT_FLUSHREAD = 0x1;
+$TIOCPKT_FLUSHWRITE = 0x2;
+$TIOCPKT_STOP = 0x4;
+$TIOCPKT_START = 0x8;
+$TIOCPKT_NOSTOP = 0x10;
+$TIOCPKT_DOSTOP = 0x20;
+$TIOCSTOP = 0x2000746F;
+$TIOCSTART = 0x2000746E;
+$TIOCREMOTE = 0x20007469;
+$TIOCGWINSZ = 0x40087468;
+$TIOCSWINSZ = 0x80087467;
+$TIOCRESET = 0x20007466;
+$OTTYDISC = 0x0;
+$NETLDISC = 0x1;
+$NTTYDISC = 0x2;
+$FIOCLEX = 0x20006601;
+$FIONCLEX = 0x20006602;
+$FIONREAD = 0x4004667F;
+$FIONBIO = 0x8004667E;
+$FIOASYNC = 0x8004667D;
+$FIOSETOWN = 0x8004667C;
+$FIOGETOWN = 0x4004667B;
+$STPUTTABLE = 0x8004667A;
+$STGETTABLE = 0x80046679;
+$SIOCSHIWAT = 0x80047300;
+$SIOCGHIWAT = 0x40047301;
+$SIOCSLOWAT = 0x80047302;
+$SIOCGLOWAT = 0x40047303;
+$SIOCATMARK = 0x40047307;
+$SIOCSPGRP = 0x80047308;
+$SIOCGPGRP = 0x40047309;
+$SIOCADDRT = 0x8034720A;
+$SIOCDELRT = 0x8034720B;
+$SIOCSIFADDR = 0x8020690C;
+$SIOCGIFADDR = 0xC020690D;
+$SIOCSIFDSTADDR = 0x8020690E;
+$SIOCGIFDSTADDR = 0xC020690F;
+$SIOCSIFFLAGS = 0x80206910;
+$SIOCGIFFLAGS = 0xC0206911;
+$SIOCGIFBRDADDR = 0xC0206912;
+$SIOCSIFBRDADDR = 0x80206913;
+$SIOCGIFCONF = 0xC0086914;
+$SIOCGIFNETMASK = 0xC0206915;
+$SIOCSIFNETMASK = 0x80206916;
+$SIOCGIFMETRIC = 0xC0206917;
+$SIOCSIFMETRIC = 0x80206918;
+$SIOCSARP = 0x8024691E;
+$SIOCGARP = 0xC024691F;
+$SIOCDARP = 0x80246920;
+$PIXCONTINUE = 0x80747000;
+$PIXSTEP = 0x80747001;
+$PIXTERMINATE = 0x20007002;
+$PIGETFLAGS = 0x40747003;
+$PIXINHERIT = 0x80747004;
+$PIXDETACH = 0x20007005;
+$PIXGETSUBCODE = 0xC0747006;
+$PIXRDREGS = 0xC0747007;
+$PIXWRREGS = 0xC0747008;
+$PIXRDVREGS = 0xC0747009;
+$PIXWRVREGS = 0xC074700A;
+$PIXRDVSTATE = 0xC074700B;
+$PIXWRVSTATE = 0xC074700C;
+$PIXRDCREGS = 0xC074700D;
+$PIXWRCREGS = 0xC074700E;
+$PIRDSDRS = 0xC074700F;
+$PIXGETSIGACTION = 0xC0747010;
+$PIGETU = 0xC0747011;
+$PISETRWTID = 0xC0747012;
+$PIXGETTHCOUNT = 0xC0747013;
+$PIXRUN = 0x20007014;
diff --git a/gnu/usr.bin/perl/h2pl/eg/sysexits.pl b/gnu/usr.bin/perl/h2pl/eg/sysexits.pl
new file mode 100644
index 0000000..f4cb777
--- /dev/null
+++ b/gnu/usr.bin/perl/h2pl/eg/sysexits.pl
@@ -0,0 +1,16 @@
+$EX_OK = 0x0;
+$EX__BASE = 0x40;
+$EX_USAGE = 0x40;
+$EX_DATAERR = 0x41;
+$EX_NOINPUT = 0x42;
+$EX_NOUSER = 0x43;
+$EX_NOHOST = 0x44;
+$EX_UNAVAILABLE = 0x45;
+$EX_SOFTWARE = 0x46;
+$EX_OSERR = 0x47;
+$EX_OSFILE = 0x48;
+$EX_CANTCREAT = 0x49;
+$EX_IOERR = 0x4A;
+$EX_TEMPFAIL = 0x4B;
+$EX_PROTOCOL = 0x4C;
+$EX_NOPERM = 0x4D;
diff --git a/gnu/usr.bin/perl/h2pl/getioctlsizes b/gnu/usr.bin/perl/h2pl/getioctlsizes
new file mode 100644
index 0000000..403fffa
--- /dev/null
+++ b/gnu/usr.bin/perl/h2pl/getioctlsizes
@@ -0,0 +1,13 @@
+#!/usr/bin/perl
+
+open (IOCTLS,'/usr/include/sys/ioctl.h') || die "ioctl open failed";
+
+while (<IOCTLS>) {
+ if (/^\s*#\s*define\s+\w+\s+_IO(R|W|WR)\('?\w+'?,\s*\w+,\s*([^)]+)/) {
+ $need{$2}++;
+ }
+}
+
+foreach $key ( sort keys %need ) {
+ print $key,"\n";
+}
diff --git a/gnu/usr.bin/perl/h2pl/mksizes b/gnu/usr.bin/perl/h2pl/mksizes
new file mode 100644
index 0000000..a39c83a
--- /dev/null
+++ b/gnu/usr.bin/perl/h2pl/mksizes
@@ -0,0 +1,42 @@
+#!/usr/bin/perl
+
+($iam = $0) =~ s%.*/%%;
+$tmp = "$iam.$$";
+open (CODE,">$tmp.c") || die "$iam: cannot create $tmp.c: $!\n";
+
+$mask = q/printf ("$sizeof{'%s'} = %d;\n"/;
+
+# write C program
+select(CODE);
+
+print <<EO_C_PROGRAM;
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <net/if_arp.h>
+#include <net/if.h>
+#include <net/route.h>
+#include <sys/ioctl.h>
+
+main() {
+EO_C_PROGRAM
+
+while ( <> ) {
+ chop;
+ printf "\t%s, \n\t\t\"%s\", sizeof(%s));\n", $mask, $_,$_;
+}
+
+print "\n}\n";
+
+close CODE;
+
+# compile C program
+
+select(STDOUT);
+
+system "cc $tmp.c -o $tmp";
+die "couldn't compile $tmp.c" if $?;
+system "./$tmp";
+die "couldn't run $tmp" if $?;
+
+unlink "$tmp.c", $tmp;
diff --git a/gnu/usr.bin/perl/h2pl/mkvars b/gnu/usr.bin/perl/h2pl/mkvars
new file mode 100644
index 0000000..16317aa
--- /dev/null
+++ b/gnu/usr.bin/perl/h2pl/mkvars
@@ -0,0 +1,31 @@
+#!/usr/bin/perl
+
+require 'sizeof.ph';
+
+$LIB = '/usr/share/perl';
+
+foreach $include (@ARGV) {
+ printf STDERR "including %s\n", $include;
+ do $include;
+ warn "sourcing $include: $@\n" if ($@);
+ if (!open (INCLUDE,"$LIB/$include")) {
+ warn "can't open $LIB/$include: $!\n";
+ next;
+ }
+ while (<INCLUDE>) {
+ chop;
+ if (/^\s*eval\s+'sub\s+(\w+)\s.*[^{]$/ || /^\s*sub\s+(\w+)\s.*[^{]$/) {
+ $var = $1;
+ $val = eval "&$var;";
+ if ($@) {
+ warn "$@: $_";
+ print <<EOT;
+warn "\$$var isn't correctly set" if defined \$_main{'$var'};
+EOT
+ next;
+ }
+ ( $nval = sprintf ("%x",$val ) ) =~ tr/a-z/A-Z/;
+ printf "\$%s = 0x%s;\n", $var, $nval;
+ }
+ }
+}
diff --git a/gnu/usr.bin/perl/h2pl/tcbreak b/gnu/usr.bin/perl/h2pl/tcbreak
new file mode 100644
index 0000000..2677cc9
--- /dev/null
+++ b/gnu/usr.bin/perl/h2pl/tcbreak
@@ -0,0 +1,17 @@
+#!/usr/bin/perl
+
+require 'cbreak.pl';
+
+&cbreak;
+
+$| = 1;
+
+print "gimme a char: ";
+
+$c = getc;
+
+print "$c\n";
+
+printf "you gave me `%s', which is 0x%02x\n", $c, ord($c);
+
+&cooked;
diff --git a/gnu/usr.bin/perl/h2pl/tcbreak2 b/gnu/usr.bin/perl/h2pl/tcbreak2
new file mode 100644
index 0000000..fcbf926
--- /dev/null
+++ b/gnu/usr.bin/perl/h2pl/tcbreak2
@@ -0,0 +1,17 @@
+#!/usr/bin/perl
+
+require 'cbreak2.pl';
+
+&cbreak;
+
+$| = 1;
+
+print "gimme a char: ";
+
+$c = getc;
+
+print "$c\n";
+
+printf "you gave me `%s', which is 0x%02x\n", $c, ord($c);
+
+&cooked;
diff --git a/gnu/usr.bin/perl/lib/Makefile b/gnu/usr.bin/perl/lib/Makefile
new file mode 100644
index 0000000..76398c8
--- /dev/null
+++ b/gnu/usr.bin/perl/lib/Makefile
@@ -0,0 +1,17 @@
+PLIBDIR= ${DESTDIR}/usr/share/perl
+
+PLIB+= abbrev.pl assert.pl bigfloat.pl bigint.pl bigrat.pl cacheout.pl
+PLIB+= chat2.pl complete.pl ctime.pl dumpvar.pl exceptions.pl fastcwd.pl
+PLIB+= find.pl finddepth.pl flush.pl getcwd.pl getopts.pl importenv.pl
+PLIB+= look.pl newgetopt.pl open2.pl perldb.pl pwd.pl shellwords.pl
+PLIB+= stat.pl syslog.pl termcap.pl timelocal.pl validate.pl
+
+NOOBJ=
+
+install:
+ ${INSTALL} -c -o ${BINOWN} -g ${BINGRP} -m 444 ${PLIB} ${PLIBDIR}
+
+clean:
+cleandir:
+
+.include <bsd.prog.mk>
diff --git a/gnu/usr.bin/perl/lib/abbrev.pl b/gnu/usr.bin/perl/lib/abbrev.pl
new file mode 100644
index 0000000..c233d4a
--- /dev/null
+++ b/gnu/usr.bin/perl/lib/abbrev.pl
@@ -0,0 +1,33 @@
+;# Usage:
+;# %foo = ();
+;# &abbrev(*foo,LIST);
+;# ...
+;# $long = $foo{$short};
+
+package abbrev;
+
+sub main'abbrev {
+ local(*domain) = @_;
+ shift(@_);
+ @cmp = @_;
+ local($[) = 0;
+ foreach $name (@_) {
+ @extra = split(//,$name);
+ $abbrev = shift(@extra);
+ $len = 1;
+ foreach $cmp (@cmp) {
+ next if $cmp eq $name;
+ while (substr($cmp,0,$len) eq $abbrev) {
+ $abbrev .= shift(@extra);
+ ++$len;
+ }
+ }
+ $domain{$abbrev} = $name;
+ while ($#extra >= 0) {
+ $abbrev .= shift(@extra);
+ $domain{$abbrev} = $name;
+ }
+ }
+}
+
+1;
diff --git a/gnu/usr.bin/perl/lib/assert.pl b/gnu/usr.bin/perl/lib/assert.pl
new file mode 100644
index 0000000..cfda70c
--- /dev/null
+++ b/gnu/usr.bin/perl/lib/assert.pl
@@ -0,0 +1,52 @@
+# assert.pl
+# tchrist@convex.com (Tom Christiansen)
+#
+# Usage:
+#
+# &assert('@x > @y');
+# &assert('$var > 10', $var, $othervar, @various_info);
+#
+# That is, if the first expression evals false, we blow up. The
+# rest of the args, if any, are nice to know because they will
+# be printed out by &panic, which is just the stack-backtrace
+# routine shamelessly borrowed from the perl debugger.
+
+sub assert {
+ &panic("ASSERTION BOTCHED: $_[0]",$@) unless eval $_[0];
+}
+
+sub panic {
+ select(STDERR);
+
+ print "\npanic: @_\n";
+
+ exit 1 if $] <= 4.003; # caller broken
+
+ # stack traceback gratefully borrowed from perl debugger
+
+ local($i,$_);
+ local($p,$f,$l,$s,$h,$a,@a,@sub);
+ for ($i = 0; ($p,$f,$l,$s,$h,$w) = caller($i); $i++) {
+ @a = @DB'args;
+ for (@a) {
+ if (/^StB\000/ && length($_) == length($_main{'_main'})) {
+ $_ = sprintf("%s",$_);
+ }
+ else {
+ s/'/\\'/g;
+ s/([^\0]*)/'$1'/ unless /^-?[\d.]+$/;
+ s/([\200-\377])/sprintf("M-%c",ord($1)&0177)/eg;
+ s/([\0-\37\177])/sprintf("^%c",ord($1)^64)/eg;
+ }
+ }
+ $w = $w ? '@ = ' : '$ = ';
+ $a = $h ? '(' . join(', ', @a) . ')' : '';
+ push(@sub, "$w&$s$a from file $f line $l\n");
+ }
+ for ($i=0; $i <= $#sub; $i++) {
+ print $sub[$i];
+ }
+ exit 1;
+}
+
+1;
diff --git a/gnu/usr.bin/perl/lib/bigfloat.pl b/gnu/usr.bin/perl/lib/bigfloat.pl
new file mode 100644
index 0000000..278f11d
--- /dev/null
+++ b/gnu/usr.bin/perl/lib/bigfloat.pl
@@ -0,0 +1,233 @@
+package bigfloat;
+require "bigint.pl";
+# Arbitrary length float math package
+#
+# by Mark Biggar
+#
+# number format
+# canonical strings have the form /[+-]\d+E[+-]\d+/
+# Input values can have inbedded whitespace
+# Error returns
+# 'NaN' An input parameter was "Not a Number" or
+# divide by zero or sqrt of negative number
+# Division is computed to
+# max($div_scale,length(dividend).length(divisor))
+# digits by default.
+# Also used for default sqrt scale
+
+$div_scale = 40;
+
+# Rounding modes one of 'even', 'odd', '+inf', '-inf', 'zero' or 'trunc'.
+
+$rnd_mode = 'even';
+
+# bigfloat routines
+#
+# fadd(NSTR, NSTR) return NSTR addition
+# fsub(NSTR, NSTR) return NSTR subtraction
+# fmul(NSTR, NSTR) return NSTR multiplication
+# fdiv(NSTR, NSTR[,SCALE]) returns NSTR division to SCALE places
+# fneg(NSTR) return NSTR negation
+# fabs(NSTR) return NSTR absolute value
+# fcmp(NSTR,NSTR) return CODE compare undef,<0,=0,>0
+# fround(NSTR, SCALE) return NSTR round to SCALE digits
+# ffround(NSTR, SCALE) return NSTR round at SCALEth place
+# fnorm(NSTR) return (NSTR) normalize
+# fsqrt(NSTR[, SCALE]) return NSTR sqrt to SCALE places
+
+# Convert a number to canonical string form.
+# Takes something that looks like a number and converts it to
+# the form /^[+-]\d+E[+-]\d+$/.
+sub main'fnorm { #(string) return fnum_str
+ local($_) = @_;
+ s/\s+//g; # strip white space
+ if (/^([+-]?)(\d*)(\.(\d*))?([Ee]([+-]?\d+))?$/ && "$2$4" ne '') {
+ &norm(($1 ? "$1$2$4" : "+$2$4"),(($4 ne '') ? $6-length($4) : $6));
+ } else {
+ 'NaN';
+ }
+}
+
+# normalize number -- for internal use
+sub norm { #(mantissa, exponent) return fnum_str
+ local($_, $exp) = @_;
+ if ($_ eq 'NaN') {
+ 'NaN';
+ } else {
+ s/^([+-])0+/$1/; # strip leading zeros
+ if (length($_) == 1) {
+ '+0E+0';
+ } else {
+ $exp += length($1) if (s/(0+)$//); # strip trailing zeros
+ sprintf("%sE%+ld", $_, $exp);
+ }
+ }
+}
+
+# negation
+sub main'fneg { #(fnum_str) return fnum_str
+ local($_) = &'fnorm($_[0]);
+ vec($_,0,8) ^= ord('+') ^ ord('-') unless $_ eq '+0E+0'; # flip sign
+ s/^H/N/;
+ $_;
+}
+
+# absolute value
+sub main'fabs { #(fnum_str) return fnum_str
+ local($_) = &'fnorm($_[0]);
+ s/^-/+/; # mash sign
+ $_;
+}
+
+# multiplication
+sub main'fmul { #(fnum_str, fnum_str) return fnum_str
+ local($x,$y) = (&'fnorm($_[0]),&'fnorm($_[1]));
+ if ($x eq 'NaN' || $y eq 'NaN') {
+ 'NaN';
+ } else {
+ local($xm,$xe) = split('E',$x);
+ local($ym,$ye) = split('E',$y);
+ &norm(&'bmul($xm,$ym),$xe+$ye);
+ }
+}
+
+# addition
+sub main'fadd { #(fnum_str, fnum_str) return fnum_str
+ local($x,$y) = (&'fnorm($_[0]),&'fnorm($_[1]));
+ if ($x eq 'NaN' || $y eq 'NaN') {
+ 'NaN';
+ } else {
+ local($xm,$xe) = split('E',$x);
+ local($ym,$ye) = split('E',$y);
+ ($xm,$xe,$ym,$ye) = ($ym,$ye,$xm,$xe) if ($xe < $ye);
+ &norm(&'badd($ym,$xm.('0' x ($xe-$ye))),$ye);
+ }
+}
+
+# subtraction
+sub main'fsub { #(fnum_str, fnum_str) return fnum_str
+ &'fadd($_[0],&'fneg($_[1]));
+}
+
+# division
+# args are dividend, divisor, scale (optional)
+# result has at most max(scale, length(dividend), length(divisor)) digits
+sub main'fdiv #(fnum_str, fnum_str[,scale]) return fnum_str
+{
+ local($x,$y,$scale) = (&'fnorm($_[0]),&'fnorm($_[1]),$_[2]);
+ if ($x eq 'NaN' || $y eq 'NaN' || $y eq '+0E+0') {
+ 'NaN';
+ } else {
+ local($xm,$xe) = split('E',$x);
+ local($ym,$ye) = split('E',$y);
+ $scale = $div_scale if (!$scale);
+ $scale = length($xm)-1 if (length($xm)-1 > $scale);
+ $scale = length($ym)-1 if (length($ym)-1 > $scale);
+ $scale = $scale + length($ym) - length($xm);
+ &norm(&round(&'bdiv($xm.('0' x $scale),$ym),$ym),
+ $xe-$ye-$scale);
+ }
+}
+
+# round int $q based on fraction $r/$base using $rnd_mode
+sub round { #(int_str, int_str, int_str) return int_str
+ local($q,$r,$base) = @_;
+ if ($q eq 'NaN' || $r eq 'NaN') {
+ 'NaN';
+ } elsif ($rnd_mode eq 'trunc') {
+ $q; # just truncate
+ } else {
+ local($cmp) = &'bcmp(&'bmul($r,'+2'),$base);
+ if ( $cmp < 0 ||
+ ($cmp == 0 &&
+ ( $rnd_mode eq 'zero' ||
+ ($rnd_mode eq '-inf' && (substr($q,0,1) eq '+')) ||
+ ($rnd_mode eq '+inf' && (substr($q,0,1) eq '-')) ||
+ ($rnd_mode eq 'even' && $q =~ /[24680]$/) ||
+ ($rnd_mode eq 'odd' && $q =~ /[13579]$/) )) ) {
+ $q; # round down
+ } else {
+ &'badd($q, ((substr($q,0,1) eq '-') ? '-1' : '+1'));
+ # round up
+ }
+ }
+}
+
+# round the mantissa of $x to $scale digits
+sub main'fround { #(fnum_str, scale) return fnum_str
+ local($x,$scale) = (&'fnorm($_[0]),$_[1]);
+ if ($x eq 'NaN' || $scale <= 0) {
+ $x;
+ } else {
+ local($xm,$xe) = split('E',$x);
+ if (length($xm)-1 <= $scale) {
+ $x;
+ } else {
+ &norm(&round(substr($xm,0,$scale+1),
+ "+0".substr($xm,$scale+1,1),"+10"),
+ $xe+length($xm)-$scale-1);
+ }
+ }
+}
+
+# round $x at the 10 to the $scale digit place
+sub main'ffround { #(fnum_str, scale) return fnum_str
+ local($x,$scale) = (&'fnorm($_[0]),$_[1]);
+ if ($x eq 'NaN') {
+ 'NaN';
+ } else {
+ local($xm,$xe) = split('E',$x);
+ if ($xe >= $scale) {
+ $x;
+ } else {
+ $xe = length($xm)+$xe-$scale;
+ if ($xe < 1) {
+ '+0E+0';
+ } elsif ($xe == 1) {
+ &norm(&round('+0',"+0".substr($xm,1,1),"+10"), $scale);
+ } else {
+ &norm(&round(substr($xm,0,$trunc),
+ "+0".substr($xm,$trunc,1),"+10"), $scale);
+ }
+ }
+ }
+}
+
+# compare 2 values returns one of undef, <0, =0, >0
+# returns undef if either or both input value are not numbers
+sub main'fcmp #(fnum_str, fnum_str) return cond_code
+{
+ local($x, $y) = (&'fnorm($_[0]),&'fnorm($_[1]));
+ if ($x eq "NaN" || $y eq "NaN") {
+ undef;
+ } else {
+ ord($y) <=> ord($x)
+ ||
+ ( local($xm,$xe,$ym,$ye) = split('E', $x."E$y"),
+ (($xe <=> $ye) * (substr($x,0,1).'1')
+ || &bigint'cmp($xm,$ym))
+ );
+ }
+}
+
+# square root by Newtons method.
+sub main'fsqrt { #(fnum_str[, scale]) return fnum_str
+ local($x, $scale) = (&'fnorm($_[0]), $_[1]);
+ if ($x eq 'NaN' || $x =~ /^-/) {
+ 'NaN';
+ } elsif ($x eq '+0E+0') {
+ '+0E+0';
+ } else {
+ local($xm, $xe) = split('E',$x);
+ $scale = $div_scale if (!$scale);
+ $scale = length($xm)-1 if ($scale < length($xm)-1);
+ local($gs, $guess) = (1, sprintf("1E%+d", (length($xm)+$xe-1)/2));
+ while ($gs < 2*$scale) {
+ $guess = &'fmul(&'fadd($guess,&'fdiv($x,$guess,$gs*2)),".5");
+ $gs *= 2;
+ }
+ &'fround($guess, $scale);
+ }
+}
+
+1;
diff --git a/gnu/usr.bin/perl/lib/bigint.pl b/gnu/usr.bin/perl/lib/bigint.pl
new file mode 100644
index 0000000..5c79da9
--- /dev/null
+++ b/gnu/usr.bin/perl/lib/bigint.pl
@@ -0,0 +1,271 @@
+package bigint;
+
+# arbitrary size integer math package
+#
+# by Mark Biggar
+#
+# Canonical Big integer value are strings of the form
+# /^[+-]\d+$/ with leading zeros suppressed
+# Input values to these routines may be strings of the form
+# /^\s*[+-]?[\d\s]+$/.
+# Examples:
+# '+0' canonical zero value
+# ' -123 123 123' canonical value '-123123123'
+# '1 23 456 7890' canonical value '+1234567890'
+# Output values always always in canonical form
+#
+# Actual math is done in an internal format consisting of an array
+# whose first element is the sign (/^[+-]$/) and whose remaining
+# elements are base 100000 digits with the least significant digit first.
+# The string 'NaN' is used to represent the result when input arguments
+# are not numbers, as well as the result of dividing by zero
+#
+# routines provided are:
+#
+# bneg(BINT) return BINT negation
+# babs(BINT) return BINT absolute value
+# bcmp(BINT,BINT) return CODE compare numbers (undef,<0,=0,>0)
+# badd(BINT,BINT) return BINT addition
+# bsub(BINT,BINT) return BINT subtraction
+# bmul(BINT,BINT) return BINT multiplication
+# bdiv(BINT,BINT) return (BINT,BINT) division (quo,rem) just quo if scalar
+# bmod(BINT,BINT) return BINT modulus
+# bgcd(BINT,BINT) return BINT greatest common divisor
+# bnorm(BINT) return BINT normalization
+#
+
+# normalize string form of number. Strip leading zeros. Strip any
+# white space and add a sign, if missing.
+# Strings that are not numbers result the value 'NaN'.
+sub main'bnorm { #(num_str) return num_str
+ local($_) = @_;
+ s/\s+//g; # strip white space
+ if (s/^([+-]?)0*(\d+)$/$1$2/) { # test if number
+ substr($_,0,0) = '+' unless $1; # Add missing sign
+ s/^-0/+0/;
+ $_;
+ } else {
+ 'NaN';
+ }
+}
+
+# Convert a number from string format to internal base 100000 format.
+# Assumes normalized value as input.
+sub internal { #(num_str) return int_num_array
+ local($d) = @_;
+ ($is,$il) = (substr($d,0,1),length($d)-2);
+ substr($d,0,1) = '';
+ ($is, reverse(unpack("a" . ($il%5+1) . ("a5" x ($il/5)), $d)));
+}
+
+# Convert a number from internal base 100000 format to string format.
+# This routine scribbles all over input array.
+sub external { #(int_num_array) return num_str
+ $es = shift;
+ grep($_ > 9999 || ($_ = substr('0000'.$_,-5)), @_); # zero pad
+ &'bnorm(join('', $es, reverse(@_))); # reverse concat and normalize
+}
+
+# Negate input value.
+sub main'bneg { #(num_str) return num_str
+ local($_) = &'bnorm(@_);
+ vec($_,0,8) ^= ord('+') ^ ord('-') unless $_ eq '+0';
+ s/^H/N/;
+ $_;
+}
+
+# Returns the absolute value of the input.
+sub main'babs { #(num_str) return num_str
+ &abs(&'bnorm(@_));
+}
+
+sub abs { # post-normalized abs for internal use
+ local($_) = @_;
+ s/^-/+/;
+ $_;
+}
+
+# Compares 2 values. Returns one of undef, <0, =0, >0. (suitable for sort)
+sub main'bcmp { #(num_str, num_str) return cond_code
+ local($x,$y) = (&'bnorm($_[0]),&'bnorm($_[1]));
+ if ($x eq 'NaN') {
+ undef;
+ } elsif ($y eq 'NaN') {
+ undef;
+ } else {
+ &cmp($x,$y);
+ }
+}
+
+sub cmp { # post-normalized compare for internal use
+ local($cx, $cy) = @_;
+ $cx cmp $cy
+ &&
+ (
+ ord($cy) <=> ord($cx)
+ ||
+ ($cx cmp ',') * (length($cy) <=> length($cx) || $cy cmp $cx)
+ );
+}
+
+sub main'badd { #(num_str, num_str) return num_str
+ local(*x, *y); ($x, $y) = (&'bnorm($_[0]),&'bnorm($_[1]));
+ if ($x eq 'NaN') {
+ 'NaN';
+ } elsif ($y eq 'NaN') {
+ 'NaN';
+ } else {
+ @x = &internal($x); # convert to internal form
+ @y = &internal($y);
+ local($sx, $sy) = (shift @x, shift @y); # get signs
+ if ($sx eq $sy) {
+ &external($sx, &add(*x, *y)); # if same sign add
+ } else {
+ ($x, $y) = (&abs($x),&abs($y)); # make abs
+ if (&cmp($y,$x) > 0) {
+ &external($sy, &sub(*y, *x));
+ } else {
+ &external($sx, &sub(*x, *y));
+ }
+ }
+ }
+}
+
+sub main'bsub { #(num_str, num_str) return num_str
+ &'badd($_[0],&'bneg($_[1]));
+}
+
+# GCD -- Euclids algorithm Knuth Vol 2 pg 296
+sub main'bgcd { #(num_str, num_str) return num_str
+ local($x,$y) = (&'bnorm($_[0]),&'bnorm($_[1]));
+ if ($x eq 'NaN' || $y eq 'NaN') {
+ 'NaN';
+ } else {
+ ($x, $y) = ($y,&'bmod($x,$y)) while $y ne '+0';
+ $x;
+ }
+}
+
+# routine to add two base 1e5 numbers
+# stolen from Knuth Vol 2 Algorithm A pg 231
+# there are separate routines to add and sub as per Kunth pg 233
+sub add { #(int_num_array, int_num_array) return int_num_array
+ local(*x, *y) = @_;
+ $car = 0;
+ for $x (@x) {
+ last unless @y || $car;
+ $x -= 1e5 if $car = (($x += shift(@y) + $car) >= 1e5);
+ }
+ for $y (@y) {
+ last unless $car;
+ $y -= 1e5 if $car = (($y += $car) >= 1e5);
+ }
+ (@x, @y, $car);
+}
+
+# subtract base 1e5 numbers -- stolen from Knuth Vol 2 pg 232, $x > $y
+sub sub { #(int_num_array, int_num_array) return int_num_array
+ local(*sx, *sy) = @_;
+ $bar = 0;
+ for $sx (@sx) {
+ last unless @y || $bar;
+ $sx += 1e5 if $bar = (($sx -= shift(@sy) + $bar) < 0);
+ }
+ @sx;
+}
+
+# multiply two numbers -- stolen from Knuth Vol 2 pg 233
+sub main'bmul { #(num_str, num_str) return num_str
+ local(*x, *y); ($x, $y) = (&'bnorm($_[0]), &'bnorm($_[1]));
+ if ($x eq 'NaN') {
+ 'NaN';
+ } elsif ($y eq 'NaN') {
+ 'NaN';
+ } else {
+ @x = &internal($x);
+ @y = &internal($y);
+ local($signr) = (shift @x ne shift @y) ? '-' : '+';
+ @prod = ();
+ for $x (@x) {
+ ($car, $cty) = (0, 0);
+ for $y (@y) {
+ $prod = $x * $y + $prod[$cty] + $car;
+ $prod[$cty++] =
+ $prod - ($car = int($prod * 1e-5)) * 1e5;
+ }
+ $prod[$cty] += $car if $car;
+ $x = shift @prod;
+ }
+ &external($signr, @x, @prod);
+ }
+}
+
+# modulus
+sub main'bmod { #(num_str, num_str) return num_str
+ (&'bdiv(@_))[1];
+}
+
+sub main'bdiv { #(dividend: num_str, divisor: num_str) return num_str
+ local (*x, *y); ($x, $y) = (&'bnorm($_[0]), &'bnorm($_[1]));
+ return wantarray ? ('NaN','NaN') : 'NaN'
+ if ($x eq 'NaN' || $y eq 'NaN' || $y eq '+0');
+ return wantarray ? ('+0',$x) : '+0' if (&cmp(&abs($x),&abs($y)) < 0);
+ @x = &internal($x); @y = &internal($y);
+ $srem = $y[0];
+ $sr = (shift @x ne shift @y) ? '-' : '+';
+ $car = $bar = $prd = 0;
+ if (($dd = int(1e5/($y[$#y]+1))) != 1) {
+ for $x (@x) {
+ $x = $x * $dd + $car;
+ $x -= ($car = int($x * 1e-5)) * 1e5;
+ }
+ push(@x, $car); $car = 0;
+ for $y (@y) {
+ $y = $y * $dd + $car;
+ $y -= ($car = int($y * 1e-5)) * 1e5;
+ }
+ }
+ else {
+ push(@x, 0);
+ }
+ @q = (); ($v2,$v1) = @y[$#y-1,$#y];
+ while ($#x > $#y) {
+ ($u2,$u1,$u0) = @x[($#x-2)..$#x];
+ $q = (($u0 == $v1) ? 99999 : int(($u0*1e5+$u1)/$v1));
+ --$q while ($v2*$q > ($u0*1e5+$u1-$q*$v1)*1e5+$u2);
+ if ($q) {
+ ($car, $bar) = (0,0);
+ for ($y = 0, $x = $#x-$#y-1; $y <= $#y; ++$y,++$x) {
+ $prd = $q * $y[$y] + $car;
+ $prd -= ($car = int($prd * 1e-5)) * 1e5;
+ $x[$x] += 1e5 if ($bar = (($x[$x] -= $prd + $bar) < 0));
+ }
+ if ($x[$#x] < $car + $bar) {
+ $car = 0; --$q;
+ for ($y = 0, $x = $#x-$#y-1; $y <= $#y; ++$y,++$x) {
+ $x[$x] -= 1e5
+ if ($car = (($x[$x] += $y[$y] + $car) > 1e5));
+ }
+ }
+ }
+ pop(@x); unshift(@q, $q);
+ }
+ if (wantarray) {
+ @d = ();
+ if ($dd != 1) {
+ $car = 0;
+ for $x (reverse @x) {
+ $prd = $car * 1e5 + $x;
+ $car = $prd - ($tmp = int($prd / $dd)) * $dd;
+ unshift(@d, $tmp);
+ }
+ }
+ else {
+ @d = @x;
+ }
+ (&external($sr, @q), &external($srem, @d, 0));
+ } else {
+ &external($sr, @q);
+ }
+}
+1;
diff --git a/gnu/usr.bin/perl/lib/bigrat.pl b/gnu/usr.bin/perl/lib/bigrat.pl
new file mode 100644
index 0000000..fb10cf3
--- /dev/null
+++ b/gnu/usr.bin/perl/lib/bigrat.pl
@@ -0,0 +1,148 @@
+package bigrat;
+require "bigint.pl";
+
+# Arbitrary size rational math package
+#
+# by Mark Biggar
+#
+# Input values to these routines consist of strings of the form
+# m|^\s*[+-]?[\d\s]+(/[\d\s]+)?$|.
+# Examples:
+# "+0/1" canonical zero value
+# "3" canonical value "+3/1"
+# " -123/123 123" canonical value "-1/1001"
+# "123 456/7890" canonical value "+20576/1315"
+# Output values always include a sign and no leading zeros or
+# white space.
+# This package makes use of the bigint package.
+# The string 'NaN' is used to represent the result when input arguments
+# that are not numbers, as well as the result of dividing by zero and
+# the sqrt of a negative number.
+# Extreamly naive algorthims are used.
+#
+# Routines provided are:
+#
+# rneg(RAT) return RAT negation
+# rabs(RAT) return RAT absolute value
+# rcmp(RAT,RAT) return CODE compare numbers (undef,<0,=0,>0)
+# radd(RAT,RAT) return RAT addition
+# rsub(RAT,RAT) return RAT subtraction
+# rmul(RAT,RAT) return RAT multiplication
+# rdiv(RAT,RAT) return RAT division
+# rmod(RAT) return (RAT,RAT) integer and fractional parts
+# rnorm(RAT) return RAT normalization
+# rsqrt(RAT, cycles) return RAT square root
+
+# Convert a number to the canonical string form m|^[+-]\d+/\d+|.
+sub main'rnorm { #(string) return rat_num
+ local($_) = @_;
+ s/\s+//g;
+ if (m#^([+-]?\d+)(/(\d*[1-9]0*))?$#) {
+ &norm($1, $3 ? $3 : '+1');
+ } else {
+ 'NaN';
+ }
+}
+
+# Normalize by reducing to lowest terms
+sub norm { #(bint, bint) return rat_num
+ local($num,$dom) = @_;
+ if ($num eq 'NaN') {
+ 'NaN';
+ } elsif ($dom eq 'NaN') {
+ 'NaN';
+ } elsif ($dom =~ /^[+-]?0+$/) {
+ 'NaN';
+ } else {
+ local($gcd) = &'bgcd($num,$dom);
+ if ($gcd ne '+1') {
+ $num = &'bdiv($num,$gcd);
+ $dom = &'bdiv($dom,$gcd);
+ } else {
+ $num = &'bnorm($num);
+ $dom = &'bnorm($dom);
+ }
+ substr($dom,0,1) = '';
+ "$num/$dom";
+ }
+}
+
+# negation
+sub main'rneg { #(rat_num) return rat_num
+ local($_) = &'rnorm($_[0]);
+ tr/-+/+-/ if ($_ ne '+0/1');
+ $_;
+}
+
+# absolute value
+sub main'rabs { #(rat_num) return $rat_num
+ local($_) = &'rnorm($_[0]);
+ substr($_,0,1) = '+' unless $_ eq 'NaN';
+ $_;
+}
+
+# multipication
+sub main'rmul { #(rat_num, rat_num) return rat_num
+ local($xn,$xd) = split('/',&'rnorm($_[0]));
+ local($yn,$yd) = split('/',&'rnorm($_[1]));
+ &norm(&'bmul($xn,$yn),&'bmul($xd,$yd));
+}
+
+# division
+sub main'rdiv { #(rat_num, rat_num) return rat_num
+ local($xn,$xd) = split('/',&'rnorm($_[0]));
+ local($yn,$yd) = split('/',&'rnorm($_[1]));
+ &norm(&'bmul($xn,$yd),&'bmul($xd,$yn));
+}
+
+# addition
+sub main'radd { #(rat_num, rat_num) return rat_num
+ local($xn,$xd) = split('/',&'rnorm($_[0]));
+ local($yn,$yd) = split('/',&'rnorm($_[1]));
+ &norm(&'badd(&'bmul($xn,$yd),&'bmul($yn,$xd)),&'bmul($xd,$yd));
+}
+
+# subtraction
+sub main'rsub { #(rat_num, rat_num) return rat_num
+ local($xn,$xd) = split('/',&'rnorm($_[0]));
+ local($yn,$yd) = split('/',&'rnorm($_[1]));
+ &norm(&'bsub(&'bmul($xn,$yd),&'bmul($yn,$xd)),&'bmul($xd,$yd));
+}
+
+# comparison
+sub main'rcmp { #(rat_num, rat_num) return cond_code
+ local($xn,$xd) = split('/',&'rnorm($_[0]));
+ local($yn,$yd) = split('/',&'rnorm($_[1]));
+ &bigint'cmp(&'bmul($xn,$yd),&'bmul($yn,$xd));
+}
+
+# int and frac parts
+sub main'rmod { #(rat_num) return (rat_num,rat_num)
+ local($xn,$xd) = split('/',&'rnorm($_[0]));
+ local($i,$f) = &'bdiv($xn,$xd);
+ if (wantarray) {
+ ("$i/1", "$f/$xd");
+ } else {
+ "$i/1";
+ }
+}
+
+# square root by Newtons method.
+# cycles specifies the number of iterations default: 5
+sub main'rsqrt { #(fnum_str[, cycles]) return fnum_str
+ local($x, $scale) = (&'rnorm($_[0]), $_[1]);
+ if ($x eq 'NaN') {
+ 'NaN';
+ } elsif ($x =~ /^-/) {
+ 'NaN';
+ } else {
+ local($gscale, $guess) = (0, '+1/1');
+ $scale = 5 if (!$scale);
+ while ($gscale++ < $scale) {
+ $guess = &'rmul(&'radd($guess,&'rdiv($x,$guess)),"+1/2");
+ }
+ "$guess"; # quotes necessary due to perl bug
+ }
+}
+
+1;
diff --git a/gnu/usr.bin/perl/lib/cacheout.pl b/gnu/usr.bin/perl/lib/cacheout.pl
new file mode 100644
index 0000000..513c25b
--- /dev/null
+++ b/gnu/usr.bin/perl/lib/cacheout.pl
@@ -0,0 +1,40 @@
+# Open in their package.
+
+sub cacheout'open {
+ open($_[0], $_[1]);
+}
+
+# But only this sub name is visible to them.
+
+sub cacheout {
+ package cacheout;
+
+ ($file) = @_;
+ if (!$isopen{$file}) {
+ if (++$numopen > $maxopen) {
+ local(@lru) = sort {$isopen{$a} <=> $isopen{$b};} keys(%isopen);
+ splice(@lru, $maxopen / 3);
+ $numopen -= @lru;
+ for (@lru) { close $_; delete $isopen{$_}; }
+ }
+ &open($file, ($saw{$file}++ ? '>>' : '>') . $file)
+ || die "Can't create $file: $!\n";
+ }
+ $isopen{$file} = ++$seq;
+}
+
+package cacheout;
+
+$seq = 0;
+$numopen = 0;
+
+if (open(PARAM,'/usr/include/sys/param.h')) {
+ local($.);
+ while (<PARAM>) {
+ $maxopen = $1 - 4 if /^\s*#\s*define\s+NOFILE\s+(\d+)/;
+ }
+ close PARAM;
+}
+$maxopen = 16 unless $maxopen;
+
+1;
diff --git a/gnu/usr.bin/perl/lib/chat2.pl b/gnu/usr.bin/perl/lib/chat2.pl
new file mode 100644
index 0000000..662872c
--- /dev/null
+++ b/gnu/usr.bin/perl/lib/chat2.pl
@@ -0,0 +1,339 @@
+## chat.pl: chat with a server
+## V2.01.alpha.7 91/06/16
+## Randal L. Schwartz
+
+package chat;
+
+$sockaddr = 'S n a4 x8';
+chop($thishost = `hostname`); $thisaddr = (gethostbyname($thishost))[4];
+$thisproc = pack($sockaddr, 2, 0, $thisaddr);
+
+# *S = symbol for current I/O, gets assigned *chatsymbol....
+$next = "chatsymbol000000"; # next one
+$nextpat = "^chatsymbol"; # patterns that match next++, ++, ++, ++
+
+
+## $handle = &chat'open_port("server.address",$port_number);
+## opens a named or numbered TCP server
+
+sub open_port { ## public
+ local($server, $port) = @_;
+
+ local($serveraddr,$serverproc);
+
+ *S = ++$next;
+ if ($server =~ /^(\d+)+\.(\d+)\.(\d+)\.(\d+)$/) {
+ $serveraddr = pack('C4', $1, $2, $3, $4);
+ } else {
+ local(@x) = gethostbyname($server);
+ return undef unless @x;
+ $serveraddr = $x[4];
+ }
+ $serverproc = pack($sockaddr, 2, $port, $serveraddr);
+ unless (socket(S, 2, 1, 6)) {
+ # XXX hardwired $AF_SOCKET, $SOCK_STREAM, 'tcp'
+ # but who the heck would change these anyway? (:-)
+ ($!) = ($!, close(S)); # close S while saving $!
+ return undef;
+ }
+ unless (bind(S, $thisproc)) {
+ ($!) = ($!, close(S)); # close S while saving $!
+ return undef;
+ }
+ unless (connect(S, $serverproc)) {
+ ($!) = ($!, close(S)); # close S while saving $!
+ return undef;
+ }
+ select((select(S), $| = 1)[0]);
+ $next; # return symbol for switcharound
+}
+
+## ($host, $port, $handle) = &chat'open_listen([$port_number]);
+## opens a TCP port on the current machine, ready to be listened to
+## if $port_number is absent or zero, pick a default port number
+## process must be uid 0 to listen to a low port number
+
+sub open_listen { ## public
+
+ *S = ++$next;
+ local($thisport) = shift || 0;
+ local($thisproc_local) = pack($sockaddr, 2, $thisport, $thisaddr);
+ local(*NS) = "__" . time;
+ unless (socket(NS, 2, 1, 6)) {
+ # XXX hardwired $AF_SOCKET, $SOCK_STREAM, 'tcp'
+ # but who the heck would change these anyway? (:-)
+ ($!) = ($!, close(NS));
+ return undef;
+ }
+ unless (bind(NS, $thisproc_local)) {
+ ($!) = ($!, close(NS));
+ return undef;
+ }
+ unless (listen(NS, 1)) {
+ ($!) = ($!, close(NS));
+ return undef;
+ }
+ select((select(NS), $| = 1)[0]);
+ local($family, $port, @myaddr) =
+ unpack("S n C C C C x8", getsockname(NS));
+ $S{"needs_accept"} = *NS; # so expect will open it
+ (@myaddr, $port, $next); # returning this
+}
+
+## $handle = &chat'open_proc("command","arg1","arg2",...);
+## opens a /bin/sh on a pseudo-tty
+
+sub open_proc { ## public
+ local(@cmd) = @_;
+
+ *S = ++$next;
+ local(*TTY) = "__TTY" . time;
+ local($pty,$tty) = &_getpty(S,TTY);
+ die "Cannot find a new pty" unless defined $pty;
+ local($pid) = fork;
+ die "Cannot fork: $!" unless defined $pid;
+ unless ($pid) {
+ close STDIN; close STDOUT; close STDERR;
+ setpgrp(0,$$);
+ if (open(DEVTTY, "/dev/tty")) {
+ ioctl(DEVTTY,0x20007471,0); # XXX s/b &TIOCNOTTY
+ close DEVTTY;
+ }
+ open(STDIN,"<&TTY");
+ open(STDOUT,">&TTY");
+ open(STDERR,">&STDOUT");
+ die "Oops" unless fileno(STDERR) == 2; # sanity
+ close(S);
+ exec @cmd;
+ die "Cannot exec @cmd: $!";
+ }
+ close(TTY);
+ $PID{$next} = $pid;
+ $next; # return symbol for switcharound
+}
+
+# $S is the read-ahead buffer
+
+## $return = &chat'expect([$handle,] $timeout_time,
+## $pat1, $body1, $pat2, $body2, ... )
+## $handle is from previous &chat'open_*().
+## $timeout_time is the time (either relative to the current time, or
+## absolute, ala time(2)) at which a timeout event occurs.
+## $pat1, $pat2, and so on are regexs which are matched against the input
+## stream. If a match is found, the entire matched string is consumed,
+## and the corresponding body eval string is evaled.
+##
+## Each pat is a regular-expression (probably enclosed in single-quotes
+## in the invocation). ^ and $ will work, respecting the current value of $*.
+## If pat is 'TIMEOUT', the body is executed if the timeout is exceeded.
+## If pat is 'EOF', the body is executed if the process exits before
+## the other patterns are seen.
+##
+## Pats are scanned in the order given, so later pats can contain
+## general defaults that won't be examined unless the earlier pats
+## have failed.
+##
+## The result of eval'ing body is returned as the result of
+## the invocation. Recursive invocations are not thought
+## through, and may work only accidentally. :-)
+##
+## undef is returned if either a timeout or an eof occurs and no
+## corresponding body has been defined.
+## I/O errors of any sort are treated as eof.
+
+$nextsubname = "expectloop000000"; # used for subroutines
+
+sub expect { ## public
+ if ($_[0] =~ /$nextpat/) {
+ *S = shift;
+ }
+ local($endtime) = shift;
+
+ local($timeout,$eof) = (1,1);
+ local($caller) = caller;
+ local($rmask, $nfound, $timeleft, $thisbuf);
+ local($cases, $pattern, $action, $subname);
+ $endtime += time if $endtime < 600_000_000;
+
+ if (defined $S{"needs_accept"}) { # is it a listen socket?
+ local(*NS) = $S{"needs_accept"};
+ delete $S{"needs_accept"};
+ $S{"needs_close"} = *NS;
+ unless(accept(S,NS)) {
+ ($!) = ($!, close(S), close(NS));
+ return undef;
+ }
+ select((select(S), $| = 1)[0]);
+ }
+
+ # now see whether we need to create a new sub:
+
+ unless ($subname = $expect_subname{$caller,@_}) {
+ # nope. make a new one:
+ $expect_subname{$caller,@_} = $subname = $nextsubname++;
+
+ $cases .= <<"EDQ"; # header is funny to make everything elsif's
+sub $subname {
+ LOOP: {
+ if (0) { ; }
+EDQ
+ while (@_) {
+ ($pattern,$action) = splice(@_,0,2);
+ if ($pattern =~ /^eof$/i) {
+ $cases .= <<"EDQ";
+ elsif (\$eof) {
+ package $caller;
+ $action;
+ }
+EDQ
+ $eof = 0;
+ } elsif ($pattern =~ /^timeout$/i) {
+ $cases .= <<"EDQ";
+ elsif (\$timeout) {
+ package $caller;
+ $action;
+ }
+EDQ
+ $timeout = 0;
+ } else {
+ $pattern =~ s#/#\\/#g;
+ $cases .= <<"EDQ";
+ elsif (\$S =~ /$pattern/) {
+ \$S = \$';
+ package $caller;
+ $action;
+ }
+EDQ
+ }
+ }
+ $cases .= <<"EDQ" if $eof;
+ elsif (\$eof) {
+ undef;
+ }
+EDQ
+ $cases .= <<"EDQ" if $timeout;
+ elsif (\$timeout) {
+ undef;
+ }
+EDQ
+ $cases .= <<'ESQ';
+ else {
+ $rmask = "";
+ vec($rmask,fileno(S),1) = 1;
+ ($nfound, $rmask) =
+ select($rmask, undef, undef, $endtime - time);
+ if ($nfound) {
+ $nread = sysread(S, $thisbuf, 1024);
+ if ($nread > 0) {
+ $S .= $thisbuf;
+ } else {
+ $eof++, redo LOOP; # any error is also eof
+ }
+ } else {
+ $timeout++, redo LOOP; # timeout
+ }
+ redo LOOP;
+ }
+ }
+}
+ESQ
+ eval $cases; die "$cases:\n$@" if $@;
+ }
+ $eof = $timeout = 0;
+ do $subname();
+}
+
+## &chat'print([$handle,] @data)
+## $handle is from previous &chat'open().
+## like print $handle @data
+
+sub print { ## public
+ if ($_[0] =~ /$nextpat/) {
+ *S = shift;
+ }
+ print S @_;
+}
+
+## &chat'close([$handle,])
+## $handle is from previous &chat'open().
+## like close $handle
+
+sub close { ## public
+ local($pid);
+ if ($_[0] =~ /$nextpat/) {
+ $pid = $PID{$_[0]};
+ *S = shift;
+ } else {
+ $pid = $PID{$next};
+ }
+ close(S);
+ waitpid($pid,0);
+ if (defined $S{"needs_close"}) { # is it a listen socket?
+ local(*NS) = $S{"needs_close"};
+ delete $S{"needs_close"};
+ close(NS);
+ }
+}
+
+## @ready_handles = &chat'select($timeout, @handles)
+## select()'s the handles with a timeout value of $timeout seconds.
+## Returns an array of handles that are ready for I/O.
+## Both user handles and chat handles are supported (but beware of
+## stdio's buffering for user handles).
+
+sub select { ## public
+ local($timeout) = shift;
+ local(@handles) = @_;
+ local(%handlename) = ();
+ local(%ready) = ();
+ local($caller) = caller;
+ local($rmask) = "";
+ for (@handles) {
+ if (/$nextpat/o) { # one of ours... see if ready
+ local(*SYM) = $_;
+ if (length($SYM)) {
+ $timeout = 0; # we have a winner
+ $ready{$_}++;
+ }
+ $handlename{fileno($_)} = $_;
+ } else {
+ $handlename{fileno(/'/ ? $_ : "$caller\'$_")} = $_;
+ }
+ }
+ for (sort keys %handlename) {
+ vec($rmask, $_, 1) = 1;
+ }
+ select($rmask, undef, undef, $timeout);
+ for (sort keys %handlename) {
+ $ready{$handlename{$_}}++ if vec($rmask,$_,1);
+ }
+ sort keys %ready;
+}
+
+# ($pty,$tty) = $chat'_getpty(PTY,TTY):
+# internal procedure to get the next available pty.
+# opens pty on handle PTY, and matching tty on handle TTY.
+# returns undef if can't find a pty.
+
+sub _getpty { ## private
+ local($_PTY,$_TTY) = @_;
+ $_PTY =~ s/^([^']+)$/(caller)[$[]."'".$1/e;
+ $_TTY =~ s/^([^']+)$/(caller)[$[]."'".$1/e;
+ local($pty,$tty);
+ for $bank (112..127) {
+ next unless -e sprintf("/dev/pty%c0", $bank);
+ for $unit (48..57) {
+ $pty = sprintf("/dev/pty%c%c", $bank, $unit);
+ open($_PTY,"+>$pty") || next;
+ select((select($_PTY), $| = 1)[0]);
+ ($tty = $pty) =~ s/pty/tty/;
+ open($_TTY,"+>$tty") || next;
+ select((select($_TTY), $| = 1)[0]);
+ system "stty nl>$tty";
+ return ($pty,$tty);
+ }
+ }
+ undef;
+}
+
+1;
diff --git a/gnu/usr.bin/perl/lib/complete.pl b/gnu/usr.bin/perl/lib/complete.pl
new file mode 100644
index 0000000..dabf8f6
--- /dev/null
+++ b/gnu/usr.bin/perl/lib/complete.pl
@@ -0,0 +1,110 @@
+;#
+;# @(#)complete.pl,v1.1 (me@anywhere.EBay.Sun.COM) 09/23/91
+;#
+;# Author: Wayne Thompson
+;#
+;# Description:
+;# This routine provides word completion.
+;# (TAB) attempts word completion.
+;# (^D) prints completion list.
+;# (These may be changed by setting $Complete'complete, etc.)
+;#
+;# Diagnostics:
+;# Bell when word completion fails.
+;#
+;# Dependencies:
+;# The tty driver is put into raw mode.
+;#
+;# Bugs:
+;#
+;# Usage:
+;# $input = &Complete('prompt_string', *completion_list);
+;# or
+;# $input = &Complete('prompt_string', @completion_list);
+;#
+
+CONFIG: {
+ package Complete;
+
+ $complete = "\004";
+ $kill = "\025";
+ $erase1 = "\177";
+ $erase2 = "\010";
+}
+
+sub Complete {
+ package Complete;
+
+ local($[) = 0;
+ if ($_[1] =~ /^StB\0/) {
+ ($prompt, *_) = @_;
+ }
+ else {
+ $prompt = shift(@_);
+ }
+ @cmp_lst = sort(@_);
+
+ system('stty raw -echo');
+ LOOP: {
+ print($prompt, $return);
+ while (($_ = getc(STDIN)) ne "\r") {
+ CASE: {
+ # (TAB) attempt completion
+ $_ eq "\t" && do {
+ @match = grep(/^$return/, @cmp_lst);
+ $l = length($test = shift(@match));
+ unless ($#match < 0) {
+ foreach $cmp (@match) {
+ until (substr($cmp, 0, $l) eq substr($test, 0, $l)) {
+ $l--;
+ }
+ }
+ print("\a");
+ }
+ print($test = substr($test, $r, $l - $r));
+ $r = length($return .= $test);
+ last CASE;
+ };
+
+ # (^D) completion list
+ $_ eq $complete && do {
+ print(join("\r\n", '', grep(/^$return/, @cmp_lst)), "\r\n");
+ redo LOOP;
+ };
+
+ # (^U) kill
+ $_ eq $kill && do {
+ if ($r) {
+ undef($r, $return);
+ print("\r\n");
+ redo LOOP;
+ }
+ last CASE;
+ };
+
+ # (DEL) || (BS) erase
+ ($_ eq $erase1 || $_ eq $erase2) && do {
+ if($r) {
+ print("\b \b");
+ chop($return);
+ $r--;
+ }
+ last CASE;
+ };
+
+ # printable char
+ ord >= 32 && do {
+ $return .= $_;
+ $r++;
+ print;
+ last CASE;
+ };
+ }
+ }
+ }
+ system('stty -raw echo');
+ print("\n");
+ $return;
+}
+
+1;
diff --git a/gnu/usr.bin/perl/lib/ctime.pl b/gnu/usr.bin/perl/lib/ctime.pl
new file mode 100644
index 0000000..4c59754
--- /dev/null
+++ b/gnu/usr.bin/perl/lib/ctime.pl
@@ -0,0 +1,51 @@
+;# ctime.pl is a simple Perl emulation for the well known ctime(3C) function.
+;#
+;# Waldemar Kebsch, Federal Republic of Germany, November 1988
+;# kebsch.pad@nixpbe.UUCP
+;# Modified March 1990, Feb 1991 to properly handle timezones
+;# $RCSfile: ctime.pl,v $$Revision: 1.1.1.1 $$Date: 1993/08/23 21:29:52 $
+;# Marion Hakanson (hakanson@cse.ogi.edu)
+;# Oregon Graduate Institute of Science and Technology
+;#
+;# usage:
+;#
+;# #include <ctime.pl> # see the -P and -I option in perl.man
+;# $Date = &ctime(time);
+
+CONFIG: {
+ package ctime;
+
+ @DoW = ('Sun','Mon','Tue','Wed','Thu','Fri','Sat');
+ @MoY = ('Jan','Feb','Mar','Apr','May','Jun',
+ 'Jul','Aug','Sep','Oct','Nov','Dec');
+}
+
+sub ctime {
+ package ctime;
+
+ local($time) = @_;
+ local($[) = 0;
+ local($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst);
+
+ # Determine what time zone is in effect.
+ # Use GMT if TZ is defined as null, local time if TZ undefined.
+ # There's no portable way to find the system default timezone.
+
+ $TZ = defined($ENV{'TZ'}) ? ( $ENV{'TZ'} ? $ENV{'TZ'} : 'GMT' ) : '';
+ ($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst) =
+ ($TZ eq 'GMT') ? gmtime($time) : localtime($time);
+
+ # Hack to deal with 'PST8PDT' format of TZ
+ # Note that this can't deal with all the esoteric forms, but it
+ # does recognize the most common: [:]STDoff[DST[off][,rule]]
+
+ if($TZ=~/^([^:\d+\-,]{3,})([+-]?\d{1,2}(:\d{1,2}){0,2})([^\d+\-,]{3,})?/){
+ $TZ = $isdst ? $4 : $1;
+ }
+ $TZ .= ' ' unless $TZ eq '';
+
+ $year += ($year < 70) ? 2000 : 1900;
+ sprintf("%s %s %2d %2d:%02d:%02d %s%4d\n",
+ $DoW[$wday], $MoY[$mon], $mday, $hour, $min, $sec, $TZ, $year);
+}
+1;
diff --git a/gnu/usr.bin/perl/lib/dumpvar.pl b/gnu/usr.bin/perl/lib/dumpvar.pl
new file mode 100644
index 0000000..5427494
--- /dev/null
+++ b/gnu/usr.bin/perl/lib/dumpvar.pl
@@ -0,0 +1,37 @@
+package dumpvar;
+
+# translate control chars to ^X - Randal Schwartz
+sub unctrl {
+ local($_) = @_;
+ s/([\001-\037\177])/'^'.pack('c',ord($1)^64)/eg;
+ $_;
+}
+sub main'dumpvar {
+ ($package,@vars) = @_;
+ local(*stab) = eval("*_$package");
+ while (($key,$val) = each(%stab)) {
+ {
+ next if @vars && !grep($key eq $_,@vars);
+ local(*entry) = $val;
+ if (defined $entry) {
+ print "\$$key = '",&unctrl($entry),"'\n";
+ }
+ if (defined @entry) {
+ print "\@$key = (\n";
+ foreach $num ($[ .. $#entry) {
+ print " $num\t'",&unctrl($entry[$num]),"'\n";
+ }
+ print ")\n";
+ }
+ if ($key ne "_$package" && $key ne "_DB" && defined %entry) {
+ print "\%$key = (\n";
+ foreach $key (sort keys(%entry)) {
+ print " $key\t'",&unctrl($entry{$key}),"'\n";
+ }
+ print ")\n";
+ }
+ }
+ }
+}
+
+1;
diff --git a/gnu/usr.bin/perl/lib/exceptions.pl b/gnu/usr.bin/perl/lib/exceptions.pl
new file mode 100644
index 0000000..02c4498
--- /dev/null
+++ b/gnu/usr.bin/perl/lib/exceptions.pl
@@ -0,0 +1,54 @@
+# exceptions.pl
+# tchrist@convex.com
+#
+# Here's a little code I use for exception handling. It's really just
+# glorfied eval/die. The way to use use it is when you might otherwise
+# exit, use &throw to raise an exception. The first enclosing &catch
+# handler looks at the exception and decides whether it can catch this kind
+# (catch takes a list of regexps to catch), and if so, it returns the one it
+# caught. If it *can't* catch it, then it will reraise the exception
+# for someone else to possibly see, or to die otherwise.
+#
+# I use oddly named variables in order to make darn sure I don't conflict
+# with my caller. I also hide in my own package, and eval the code in his.
+#
+# The EXCEPTION: prefix is so you can tell whether it's a user-raised
+# exception or a perl-raised one (eval error).
+#
+# --tom
+#
+# examples:
+# if (&catch('/$user_input/', 'regexp', 'syntax error') {
+# warn "oops try again";
+# redo;
+# }
+#
+# if ($error = &catch('&subroutine()')) { # catches anything
+#
+# &throw('bad input') if /^$/;
+
+sub catch {
+ package exception;
+ local($__code__, @__exceptions__) = @_;
+ local($__package__) = caller;
+ local($__exception__);
+
+ eval "package $__package__; $__code__";
+ if ($__exception__ = &'thrown) {
+ for (@__exceptions__) {
+ return $__exception__ if /$__exception__/;
+ }
+ &'throw($__exception__);
+ }
+}
+
+sub throw {
+ local($exception) = @_;
+ die "EXCEPTION: $exception\n";
+}
+
+sub thrown {
+ $@ =~ /^(EXCEPTION: )+(.+)/ && $2;
+}
+
+1;
diff --git a/gnu/usr.bin/perl/lib/fastcwd.pl b/gnu/usr.bin/perl/lib/fastcwd.pl
new file mode 100644
index 0000000..6b452e8
--- /dev/null
+++ b/gnu/usr.bin/perl/lib/fastcwd.pl
@@ -0,0 +1,35 @@
+# By John Bazik
+#
+# Usage: $cwd = &fastcwd;
+#
+# This is a faster version of getcwd. It's also more dangerous because
+# you might chdir out of a directory that you can't chdir back into.
+
+sub fastcwd {
+ local($odev, $oino, $cdev, $cino, $tdev, $tino);
+ local(@path, $path);
+ local(*DIR);
+
+ ($cdev, $cino) = stat('.');
+ for (;;) {
+ ($odev, $oino) = ($cdev, $cino);
+ chdir('..');
+ ($cdev, $cino) = stat('.');
+ last if $odev == $cdev && $oino == $cino;
+ opendir(DIR, '.');
+ for (;;) {
+ $_ = readdir(DIR);
+ next if $_ eq '.';
+ next if $_ eq '..';
+
+ last unless $_;
+ ($tdev, $tino) = lstat($_);
+ last unless $tdev != $odev || $tino != $oino;
+ }
+ closedir(DIR);
+ unshift(@path, $_);
+ }
+ chdir($path = '/' . join('/', @path));
+ $path;
+}
+1;
diff --git a/gnu/usr.bin/perl/lib/find.pl b/gnu/usr.bin/perl/lib/find.pl
new file mode 100644
index 0000000..8dab054
--- /dev/null
+++ b/gnu/usr.bin/perl/lib/find.pl
@@ -0,0 +1,106 @@
+# Usage:
+# require "find.pl";
+#
+# &find('/foo','/bar');
+#
+# sub wanted { ... }
+# where wanted does whatever you want. $dir contains the
+# current directory name, and $_ the current filename within
+# that directory. $name contains "$dir/$_". You are cd'ed
+# to $dir when the function is called. The function may
+# set $prune to prune the tree.
+#
+# This library is primarily for find2perl, which, when fed
+#
+# find2perl / -name .nfs\* -mtime +7 -exec rm -f {} \; -o -fstype nfs -prune
+#
+# spits out something like this
+#
+# sub wanted {
+# /^\.nfs.*$/ &&
+# (($dev,$ino,$mode,$nlink,$uid,$gid) = lstat($_)) &&
+# int(-M _) > 7 &&
+# unlink($_)
+# ||
+# ($nlink || (($dev,$ino,$mode,$nlink,$uid,$gid) = lstat($_))) &&
+# $dev < 0 &&
+# ($prune = 1);
+# }
+
+sub find {
+ chop($cwd = `pwd`);
+ foreach $topdir (@_) {
+ (($topdev,$topino,$topmode,$topnlink) = stat($topdir))
+ || (warn("Can't stat $topdir: $!\n"), next);
+ if (-d _) {
+ if (chdir($topdir)) {
+ ($dir,$_) = ($topdir,'.');
+ $name = $topdir;
+ &wanted;
+ $topdir =~ s,/$,, ;
+ &finddir($topdir,$topnlink);
+ }
+ else {
+ warn "Can't cd to $topdir: $!\n";
+ }
+ }
+ else {
+ unless (($dir,$_) = $topdir =~ m#^(.*/)(.*)$#) {
+ ($dir,$_) = ('.', $topdir);
+ }
+ $name = $topdir;
+ chdir $dir && &wanted;
+ }
+ chdir $cwd;
+ }
+}
+
+sub finddir {
+ local($dir,$nlink) = @_;
+ local($dev,$ino,$mode,$subcount);
+ local($name);
+
+ # Get the list of files in the current directory.
+
+ opendir(DIR,'.') || (warn "Can't open $dir: $!\n", return);
+ local(@filenames) = readdir(DIR);
+ closedir(DIR);
+
+ if ($nlink == 2) { # This dir has no subdirectories.
+ for (@filenames) {
+ next if $_ eq '.';
+ next if $_ eq '..';
+ $name = "$dir/$_";
+ $nlink = 0;
+ &wanted;
+ }
+ }
+ else { # This dir has subdirectories.
+ $subcount = $nlink - 2;
+ for (@filenames) {
+ next if $_ eq '.';
+ next if $_ eq '..';
+ $nlink = $prune = 0;
+ $name = "$dir/$_";
+ &wanted;
+ if ($subcount > 0) { # Seen all the subdirs?
+
+ # Get link count and check for directoriness.
+
+ ($dev,$ino,$mode,$nlink) = lstat($_) unless $nlink;
+
+ if (-d _) {
+
+ # It really is a directory, so do it recursively.
+
+ if (!$prune && chdir $_) {
+ &finddir($name,$nlink);
+ chdir '..';
+ }
+ --$subcount;
+ }
+ }
+ }
+ }
+}
+1;
diff --git a/gnu/usr.bin/perl/lib/finddepth.pl b/gnu/usr.bin/perl/lib/finddepth.pl
new file mode 100644
index 0000000..15e4daf
--- /dev/null
+++ b/gnu/usr.bin/perl/lib/finddepth.pl
@@ -0,0 +1,105 @@
+# Usage:
+# require "finddepth.pl";
+#
+# &finddepth('/foo','/bar');
+#
+# sub wanted { ... }
+# where wanted does whatever you want. $dir contains the
+# current directory name, and $_ the current filename within
+# that directory. $name contains "$dir/$_". You are cd'ed
+# to $dir when the function is called. The function may
+# set $prune to prune the tree.
+#
+# This library is primarily for find2perl, which, when fed
+#
+# find2perl / -name .nfs\* -mtime +7 -exec rm -f {} \; -o -fstype nfs -prune
+#
+# spits out something like this
+#
+# sub wanted {
+# /^\.nfs.*$/ &&
+# (($dev,$ino,$mode,$nlink,$uid,$gid) = lstat($_)) &&
+# int(-M _) > 7 &&
+# unlink($_)
+# ||
+# ($nlink || (($dev,$ino,$mode,$nlink,$uid,$gid) = lstat($_))) &&
+# $dev < 0 &&
+# ($prune = 1);
+# }
+
+sub finddepth {
+ chop($cwd = `pwd`);
+ foreach $topdir (@_) {
+ (($topdev,$topino,$topmode,$topnlink) = stat($topdir))
+ || (warn("Can't stat $topdir: $!\n"), next);
+ if (-d _) {
+ if (chdir($topdir)) {
+ $topdir =~ s,/$,, ;
+ &finddepthdir($topdir,$topnlink);
+ ($dir,$_) = ($topdir,'.');
+ $name = $topdir;
+ &wanted;
+ }
+ else {
+ warn "Can't cd to $topdir: $!\n";
+ }
+ }
+ else {
+ unless (($dir,$_) = $topdir =~ m#^(.*/)(.*)$#) {
+ ($dir,$_) = ('.', $topdir);
+ }
+ chdir $dir && &wanted;
+ }
+ chdir $cwd;
+ }
+}
+
+sub finddepthdir {
+ local($dir,$nlink) = @_;
+ local($dev,$ino,$mode,$subcount);
+ local($name);
+
+ # Get the list of files in the current directory.
+
+ opendir(DIR,'.') || warn "Can't open $dir: $!\n";
+ local(@filenames) = readdir(DIR);
+ closedir(DIR);
+
+ if ($nlink == 2) { # This dir has no subdirectories.
+ for (@filenames) {
+ next if $_ eq '.';
+ next if $_ eq '..';
+ $name = "$dir/$_";
+ $nlink = 0;
+ &wanted;
+ }
+ }
+ else { # This dir has subdirectories.
+ $subcount = $nlink - 2;
+ for (@filenames) {
+ next if $_ eq '.';
+ next if $_ eq '..';
+ $nlink = $prune = 0;
+ $name = "$dir/$_";
+ if ($subcount > 0) { # Seen all the subdirs?
+
+ # Get link count and check for directoriness.
+
+ ($dev,$ino,$mode,$nlink) = lstat($_) unless $nlink;
+
+ if (-d _) {
+
+ # It really is a directory, so do it recursively.
+
+ if (!$prune && chdir $_) {
+ &finddepthdir($name,$nlink);
+ chdir '..';
+ }
+ --$subcount;
+ }
+ }
+ &wanted;
+ }
+ }
+}
+1;
diff --git a/gnu/usr.bin/perl/lib/flush.pl b/gnu/usr.bin/perl/lib/flush.pl
new file mode 100644
index 0000000..55002b9
--- /dev/null
+++ b/gnu/usr.bin/perl/lib/flush.pl
@@ -0,0 +1,23 @@
+;# Usage: &flush(FILEHANDLE)
+;# flushes the named filehandle
+
+;# Usage: &printflush(FILEHANDLE, "prompt: ")
+;# prints arguments and flushes filehandle
+
+sub flush {
+ local($old) = select(shift);
+ $| = 1;
+ print "";
+ $| = 0;
+ select($old);
+}
+
+sub printflush {
+ local($old) = select(shift);
+ $| = 1;
+ print @_;
+ $| = 0;
+ select($old);
+}
+
+1;
diff --git a/gnu/usr.bin/perl/lib/getcwd.pl b/gnu/usr.bin/perl/lib/getcwd.pl
new file mode 100644
index 0000000..a3214ba
--- /dev/null
+++ b/gnu/usr.bin/perl/lib/getcwd.pl
@@ -0,0 +1,62 @@
+# By Brandon S. Allbery
+#
+# Usage: $cwd = &getcwd;
+
+sub getcwd
+{
+ local($dotdots, $cwd, @pst, @cst, $dir, @tst);
+
+ unless (@cst = stat('.'))
+ {
+ warn "stat(.): $!";
+ return '';
+ }
+ $cwd = '';
+ do
+ {
+ $dotdots .= '/' if $dotdots;
+ $dotdots .= '..';
+ @pst = @cst;
+ unless (opendir(getcwd'PARENT, $dotdots)) #'))
+ {
+ warn "opendir($dotdots): $!";
+ return '';
+ }
+ unless (@cst = stat($dotdots))
+ {
+ warn "stat($dotdots): $!";
+ closedir(getcwd'PARENT); #');
+ return '';
+ }
+ if ($pst[$[] == $cst[$[] && $pst[$[ + 1] == $cst[$[ + 1])
+ {
+ $dir = '';
+ }
+ else
+ {
+ do
+ {
+ unless ($dir = readdir(getcwd'PARENT)) #'))
+ {
+ warn "readdir($dotdots): $!";
+ closedir(getcwd'PARENT); #');
+ return '';
+ }
+ unless (@tst = lstat("$dotdots/$dir"))
+ {
+ warn "lstat($dotdots/$dir): $!";
+ closedir(getcwd'PARENT); #');
+ return '';
+ }
+ }
+ while ($dir eq '.' || $dir eq '..' || $tst[$[] != $pst[$[] ||
+ $tst[$[ + 1] != $pst[$[ + 1]);
+ }
+ $cwd = "$dir/$cwd";
+ closedir(getcwd'PARENT); #');
+ } while ($dir);
+ chop($cwd);
+ $cwd;
+}
+
+1;
diff --git a/gnu/usr.bin/perl/lib/getopt.pl b/gnu/usr.bin/perl/lib/getopt.pl
new file mode 100644
index 0000000..6772d54
--- /dev/null
+++ b/gnu/usr.bin/perl/lib/getopt.pl
@@ -0,0 +1,41 @@
+;# $RCSfile: getopt.pl,v $$Revision: 1.1.1.1 $$Date: 1993/08/23 21:29:52 $
+
+;# Process single-character switches with switch clustering. Pass one argument
+;# which is a string containing all switches that take an argument. For each
+;# switch found, sets $opt_x (where x is the switch name) to the value of the
+;# argument, or 1 if no argument. Switches which take an argument don't care
+;# whether there is a space between the switch and the argument.
+
+;# Usage:
+;# do Getopt('oDI'); # -o, -D & -I take arg. Sets opt_* as a side effect.
+
+sub Getopt {
+ local($argumentative) = @_;
+ local($_,$first,$rest);
+ local($[) = 0;
+
+ while (@ARGV && ($_ = $ARGV[0]) =~ /^-(.)(.*)/) {
+ ($first,$rest) = ($1,$2);
+ if (index($argumentative,$first) >= $[) {
+ if ($rest ne '') {
+ shift(@ARGV);
+ }
+ else {
+ shift(@ARGV);
+ $rest = shift(@ARGV);
+ }
+ eval "\$opt_$first = \$rest;";
+ }
+ else {
+ eval "\$opt_$first = 1;";
+ if ($rest ne '') {
+ $ARGV[0] = "-$rest";
+ }
+ else {
+ shift(@ARGV);
+ }
+ }
+ }
+}
+
+1;
diff --git a/gnu/usr.bin/perl/lib/getopts.pl b/gnu/usr.bin/perl/lib/getopts.pl
new file mode 100644
index 0000000..a0818d1
--- /dev/null
+++ b/gnu/usr.bin/perl/lib/getopts.pl
@@ -0,0 +1,50 @@
+;# getopts.pl - a better getopt.pl
+
+;# Usage:
+;# do Getopts('a:bc'); # -a takes arg. -b & -c not. Sets opt_* as a
+;# # side effect.
+
+sub Getopts {
+ local($argumentative) = @_;
+ local(@args,$_,$first,$rest);
+ local($errs) = 0;
+ local($[) = 0;
+
+ @args = split( / */, $argumentative );
+ while(@ARGV && ($_ = $ARGV[0]) =~ /^-(.)(.*)/) {
+ ($first,$rest) = ($1,$2);
+ $pos = index($argumentative,$first);
+ if($pos >= $[) {
+ if($args[$pos+1] eq ':') {
+ shift(@ARGV);
+ if($rest eq '') {
+ ++$errs unless @ARGV;
+ $rest = shift(@ARGV);
+ }
+ eval "\$opt_$first = \$rest;";
+ }
+ else {
+ eval "\$opt_$first = 1";
+ if($rest eq '') {
+ shift(@ARGV);
+ }
+ else {
+ $ARGV[0] = "-$rest";
+ }
+ }
+ }
+ else {
+ print STDERR "Unknown option: $first\n";
+ ++$errs;
+ if($rest ne '') {
+ $ARGV[0] = "-$rest";
+ }
+ else {
+ shift(@ARGV);
+ }
+ }
+ }
+ $errs == 0;
+}
+
+1;
diff --git a/gnu/usr.bin/perl/lib/importenv.pl b/gnu/usr.bin/perl/lib/importenv.pl
new file mode 100644
index 0000000..c9ad330
--- /dev/null
+++ b/gnu/usr.bin/perl/lib/importenv.pl
@@ -0,0 +1,16 @@
+;# $Header: /home/cvs/386BSD/ports/lang/perl/lib/importenv.pl,v 1.1.1.1 1993/08/23 21:29:53 nate Exp $
+
+;# This file, when interpreted, pulls the environment into normal variables.
+;# Usage:
+;# require 'importenv.pl';
+;# or
+;# #include <importenv.pl>
+
+local($tmp,$key) = '';
+
+foreach $key (keys(ENV)) {
+ $tmp .= "\$$key = \$ENV{'$key'};" if $key =~ /^[A-Za-z]\w*$/;
+}
+eval $tmp;
+
+1;
diff --git a/gnu/usr.bin/perl/lib/look.pl b/gnu/usr.bin/perl/lib/look.pl
new file mode 100644
index 0000000..4c14e64
--- /dev/null
+++ b/gnu/usr.bin/perl/lib/look.pl
@@ -0,0 +1,44 @@
+;# Usage: &look(*FILEHANDLE,$key,$dict,$fold)
+
+;# Sets file position in FILEHANDLE to be first line greater than or equal
+;# (stringwise) to $key. Pass flags for dictionary order and case folding.
+
+sub look {
+ local(*FH,$key,$dict,$fold) = @_;
+ local($max,$min,$mid,$_);
+ local($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,$atime,$mtime,$ctime,
+ $blksize,$blocks) = stat(FH);
+ $blksize = 8192 unless $blksize;
+ $key =~ s/[^\w\s]//g if $dict;
+ $key =~ y/A-Z/a-z/ if $fold;
+ $max = int($size / $blksize);
+ while ($max - $min > 1) {
+ $mid = int(($max + $min) / 2);
+ seek(FH,$mid * $blksize,0);
+ $_ = <FH> if $mid; # probably a partial line
+ $_ = <FH>;
+ chop;
+ s/[^\w\s]//g if $dict;
+ y/A-Z/a-z/ if $fold;
+ if ($_ lt $key) {
+ $min = $mid;
+ }
+ else {
+ $max = $mid;
+ }
+ }
+ $min *= $blksize;
+ seek(FH,$min,0);
+ <FH> if $min;
+ while (<FH>) {
+ chop;
+ s/[^\w\s]//g if $dict;
+ y/A-Z/a-z/ if $fold;
+ last if $_ ge $key;
+ $min = tell(FH);
+ }
+ seek(FH,$min,0);
+ $min;
+}
+
+1;
diff --git a/gnu/usr.bin/perl/lib/newgetopt.pl b/gnu/usr.bin/perl/lib/newgetopt.pl
new file mode 100644
index 0000000..0e4cbfd
--- /dev/null
+++ b/gnu/usr.bin/perl/lib/newgetopt.pl
@@ -0,0 +1,271 @@
+# newgetopt.pl -- new options parsing
+
+# SCCS Status : @(#)@ newgetopt.pl 1.13
+# Author : Johan Vromans
+# Created On : Tue Sep 11 15:00:12 1990
+# Last Modified By: Johan Vromans
+# Last Modified On: Tue Jun 2 11:24:03 1992
+# Update Count : 75
+# Status : Okay
+
+# This package implements a new getopt function. This function adheres
+# to the new syntax (long option names, no bundling).
+#
+# Arguments to the function are:
+#
+# - a list of possible options. These should designate valid perl
+# identifiers, optionally followed by an argument specifier ("="
+# for mandatory arguments or ":" for optional arguments) and an
+# argument type specifier: "n" or "i" for integer numbers, "f" for
+# real (fix) numbers or "s" for strings.
+# If an "@" sign is appended, the option is treated as an array.
+# Value(s) are not set, but pushed.
+#
+# - if the first option of the list consists of non-alphanumeric
+# characters only, it is interpreted as a generic option starter.
+# Everything starting with one of the characters from the starter
+# will be considered an option.
+# Likewise, a double occurrence (e.g. "--") signals end of
+# the options list.
+# The default value for the starter is "-", "--" or "+".
+#
+# Upon return, the option variables, prefixed with "opt_", are defined
+# and set to the respective option arguments, if any.
+# Options that do not take an argument are set to 1. Note that an
+# option with an optional argument will be defined, but set to '' if
+# no actual argument has been supplied.
+# A return status of 0 (false) indicates that the function detected
+# one or more errors.
+#
+# Special care is taken to give a correct treatment to optional arguments.
+#
+# E.g. if option "one:i" (i.e. takes an optional integer argument),
+# then the following situations are handled:
+#
+# -one -two -> $opt_one = '', -two is next option
+# -one -2 -> $opt_one = -2
+#
+# Also, assume "foo=s" and "bar:s" :
+#
+# -bar -xxx -> $opt_bar = '', '-xxx' is next option
+# -foo -bar -> $opt_foo = '-bar'
+# -foo -- -> $opt_foo = '--'
+#
+# HISTORY
+# 2-Jun-1992 Johan Vromans
+# Do not use //o to allow multiple NGetOpt calls with different delimeters.
+# Prevent typeless option from using previous $array state.
+# Prevent empty option from being eaten as a (negative) number.
+
+# 25-May-1992 Johan Vromans
+# Add array options. "foo=s@" will return an array @opt_foo that
+# contains all values that were supplied. E.g. "-foo one -foo -two" will
+# return @opt_foo = ("one", "-two");
+# Correct bug in handling options that allow for a argument when followed
+# by another option.
+
+# 4-May-1992 Johan Vromans
+# Add $ignorecase to match options in either case.
+# Allow '' option.
+
+# 19-Mar-1992 Johan Vromans
+# Allow require from packages.
+# NGetOpt is now defined in the package that requires it.
+# @ARGV and $opt_... are taken from the package that calls it.
+# Use standard (?) option prefixes: -, -- and +.
+
+# 20-Sep-1990 Johan Vromans
+# Set options w/o argument to 1.
+# Correct the dreadful semicolon/require bug.
+
+
+{ package newgetopt;
+ $debug = 0; # for debugging
+ $ignorecase = 1; # ignore case when matching options
+}
+
+sub NGetOpt {
+
+ @newgetopt'optionlist = @_;
+ *newgetopt'ARGV = *ARGV;
+
+ package newgetopt;
+
+ local ($[) = 0;
+ local ($genprefix) = "(--|-|\\+)";
+ local ($argend) = "--";
+ local ($error) = 0;
+ local ($opt, $optx, $arg, $type, $mand, %opctl);
+ local ($pkg) = (caller)[0];
+
+ print STDERR "NGetOpt 1.13 -- called from $pkg\n" if $debug;
+
+ # See if the first element of the optionlist contains option
+ # starter characters.
+ if ( $optionlist[0] =~ /^\W+$/ ) {
+ $genprefix = shift (@optionlist);
+ # Turn into regexp.
+ $genprefix =~ s/(\W)/\\\1/g;
+ $genprefix = "[" . $genprefix . "]";
+ undef $argend;
+ }
+
+ # Verify correctness of optionlist.
+ %opctl = ();
+ foreach $opt ( @optionlist ) {
+ $opt =~ tr/A-Z/a-z/ if $ignorecase;
+ if ( $opt !~ /^(\w*)([=:][infse]@?)?$/ ) {
+ print STDERR ("Error in option spec: \"", $opt, "\"\n");
+ $error++;
+ next;
+ }
+ $opctl{$1} = defined $2 ? $2 : "";
+ }
+
+ return 0 if $error;
+
+ if ( $debug ) {
+ local ($arrow, $k, $v);
+ $arrow = "=> ";
+ while ( ($k,$v) = each(%opctl) ) {
+ print STDERR ($arrow, "\$opctl{\"$k\"} = \"$v\"\n");
+ $arrow = " ";
+ }
+ }
+
+ # Process argument list
+
+ while ( $#ARGV >= 0 ) {
+
+ # >>> See also the continue block <<<
+
+ # Get next argument
+ $opt = shift (@ARGV);
+ print STDERR ("=> option \"", $opt, "\"\n") if $debug;
+ $arg = undef;
+
+ # Check for exhausted list.
+ if ( $opt =~ /^$genprefix/ ) {
+ # Double occurrence is terminator
+ return ($error == 0)
+ if ($opt eq "$+$+") || ((defined $argend) && $opt eq $argend);
+ $opt = $'; # option name (w/o prefix)
+ }
+ else {
+ # Apparently not an option - push back and exit.
+ unshift (@ARGV, $opt);
+ return ($error == 0);
+ }
+
+ # Look it up.
+ $opt =~ tr/A-Z/a-z/ if $ignorecase;
+ unless ( defined ( $type = $opctl{$opt} ) ) {
+ print STDERR ("Unknown option: ", $opt, "\n");
+ $error++;
+ next;
+ }
+
+ # Determine argument status.
+ print STDERR ("=> found \"$type\" for ", $opt, "\n") if $debug;
+
+ # If it is an option w/o argument, we're almost finished with it.
+ if ( $type eq "" ) {
+ $arg = 1; # supply explicit value
+ $array = 0;
+ next;
+ }
+
+ # Get mandatory status and type info.
+ ($mand, $type, $array) = $type =~ /^(.)(.)(@?)$/;
+
+ # Check if the argument list is exhausted.
+ if ( $#ARGV < 0 ) {
+
+ # Complain if this option needs an argument.
+ if ( $mand eq "=" ) {
+ print STDERR ("Option ", $opt, " requires an argument\n");
+ $error++;
+ }
+ if ( $mand eq ":" ) {
+ $arg = $type eq "s" ? "" : 0;
+ }
+ next;
+ }
+
+ # Get (possibly optional) argument.
+ $arg = shift (@ARGV);
+
+ # Check if it is a valid argument. A mandatory string takes
+ # anything.
+ if ( "$mand$type" ne "=s" && $arg =~ /^$genprefix/ ) {
+
+ # Check for option list terminator.
+ if ( $arg eq "$+$+" ||
+ ((defined $argend) && $arg eq $argend)) {
+ # Push back so the outer loop will terminate.
+ unshift (@ARGV, $arg);
+ # Complain if an argument is required.
+ if ($mand eq "=") {
+ print STDERR ("Option ", $opt, " requires an argument\n");
+ $error++;
+ undef $arg; # don't assign it
+ }
+ else {
+ # Supply empty value.
+ $arg = $type eq "s" ? "" : 0;
+ }
+ next;
+ }
+
+ # Maybe the optional argument is the next option?
+ if ( $mand eq ":" && ($' eq "" || $' =~ /[a-zA-Z_]/) ) {
+ # Yep. Push back.
+ unshift (@ARGV, $arg);
+ $arg = $type eq "s" ? "" : 0;
+ next;
+ }
+ }
+
+ if ( $type eq "n" || $type eq "i" ) { # numeric/integer
+ if ( $arg !~ /^-?[0-9]+$/ ) {
+ print STDERR ("Value \"", $arg, "\" invalid for option ",
+ $opt, " (number expected)\n");
+ $error++;
+ undef $arg; # don't assign it
+ }
+ next;
+ }
+
+ if ( $type eq "f" ) { # fixed real number, int is also ok
+ if ( $arg !~ /^-?[0-9.]+$/ ) {
+ print STDERR ("Value \"", $arg, "\" invalid for option ",
+ $opt, " (real number expected)\n");
+ $error++;
+ undef $arg; # don't assign it
+ }
+ next;
+ }
+
+ if ( $type eq "s" ) { # string
+ next;
+ }
+
+ }
+ continue {
+ if ( defined $arg ) {
+ if ( $array ) {
+ print STDERR ('=> push (@', $pkg, '\'opt_', $opt, ", \"$arg\")\n")
+ if $debug;
+ eval ('push(@' . $pkg . '\'opt_' . $opt . ", \$arg);");
+ }
+ else {
+ print STDERR ('=> $', $pkg, '\'opt_', $opt, " = \"$arg\"\n")
+ if $debug;
+ eval ('$' . $pkg . '\'opt_' . $opt . " = \$arg;");
+ }
+ }
+ }
+
+ return ($error == 0);
+}
+1;
diff --git a/gnu/usr.bin/perl/lib/open2.pl b/gnu/usr.bin/perl/lib/open2.pl
new file mode 100644
index 0000000..dcd68a8
--- /dev/null
+++ b/gnu/usr.bin/perl/lib/open2.pl
@@ -0,0 +1,54 @@
+# &open2: tom christiansen, <tchrist@convex.com>
+#
+# usage: $pid = &open2('rdr', 'wtr', 'some cmd and args');
+# or $pid = &open2('rdr', 'wtr', 'some', 'cmd', 'and', 'args');
+#
+# spawn the given $cmd and connect $rdr for
+# reading and $wtr for writing. return pid
+# of child, or 0 on failure.
+#
+# WARNING: this is dangerous, as you may block forever
+# unless you are very careful.
+#
+# $wtr is left unbuffered.
+#
+# abort program if
+# rdr or wtr are null
+# pipe or fork or exec fails
+
+package open2;
+$fh = 'FHOPEN000'; # package static in case called more than once
+
+sub main'open2 {
+ local($kidpid);
+ local($dad_rdr, $dad_wtr, @cmd) = @_;
+
+ $dad_rdr ne '' || die "open2: rdr should not be null";
+ $dad_wtr ne '' || die "open2: wtr should not be null";
+
+ # force unqualified filehandles into callers' package
+ local($package) = caller;
+ $dad_rdr =~ s/^[^']+$/$package'$&/;
+ $dad_wtr =~ s/^[^']+$/$package'$&/;
+
+ local($kid_rdr) = ++$fh;
+ local($kid_wtr) = ++$fh;
+
+ pipe($dad_rdr, $kid_wtr) || die "open2: pipe 1 failed: $!";
+ pipe($kid_rdr, $dad_wtr) || die "open2: pipe 2 failed: $!";
+
+ if (($kidpid = fork) < 0) {
+ die "open2: fork failed: $!";
+ } elsif ($kidpid == 0) {
+ close $dad_rdr; close $dad_wtr;
+ open(STDIN, "<&$kid_rdr");
+ open(STDOUT, ">&$kid_wtr");
+ warn "execing @cmd\n" if $debug;
+ exec @cmd;
+ die "open2: exec of @cmd failed";
+ }
+ close $kid_rdr; close $kid_wtr;
+ select((select($dad_wtr), $| = 1)[0]); # unbuffer pipe
+ $kidpid;
+}
+1; # so require is happy
diff --git a/gnu/usr.bin/perl/lib/perldb.pl b/gnu/usr.bin/perl/lib/perldb.pl
new file mode 100644
index 0000000..1aadb93
--- /dev/null
+++ b/gnu/usr.bin/perl/lib/perldb.pl
@@ -0,0 +1,598 @@
+package DB;
+
+# modified Perl debugger, to be run from Emacs in perldb-mode
+# Ray Lischner (uunet!mntgfx!lisch) as of 5 Nov 1990
+# Johan Vromans -- upgrade to 4.0 pl 10
+
+$header = '$RCSfile: perldb.pl,v $$Revision: 1.1.1.1 $$Date: 1993/08/23 21:29:51 $';
+#
+# This file is automatically included if you do perl -d.
+# It's probably not useful to include this yourself.
+#
+# Perl supplies the values for @line and %sub. It effectively inserts
+# a do DB'DB(<linenum>); in front of every place that can
+# have a breakpoint. It also inserts a do 'perldb.pl' before the first line.
+#
+# $Log: perldb.pl,v $
+# Revision 1.1.1.1 1993/08/23 21:29:51 nate
+# PERL!
+#
+# Revision 4.0.1.3 92/06/08 13:43:57 lwall
+# patch20: support for MSDOS folded into perldb.pl
+# patch20: perldb couldn't debug file containing '-', such as STDIN designator
+#
+# Revision 4.0.1.2 91/11/05 17:55:58 lwall
+# patch11: perldb.pl modified to run within emacs in perldb-mode
+#
+# Revision 4.0.1.1 91/06/07 11:17:44 lwall
+# patch4: added $^P variable to control calling of perldb routines
+# patch4: debugger sometimes listed wrong number of lines for a statement
+#
+# Revision 4.0 91/03/20 01:25:50 lwall
+# 4.0 baseline.
+#
+# Revision 3.0.1.6 91/01/11 18:08:58 lwall
+# patch42: @_ couldn't be accessed from debugger
+#
+# Revision 3.0.1.5 90/11/10 01:40:26 lwall
+# patch38: the debugger wouldn't stop correctly or do action routines
+#
+# Revision 3.0.1.4 90/10/15 17:40:38 lwall
+# patch29: added caller
+# patch29: the debugger now understands packages and evals
+# patch29: scripts now run at almost full speed under the debugger
+# patch29: more variables are settable from debugger
+#
+# Revision 3.0.1.3 90/08/09 04:00:58 lwall
+# patch19: debugger now allows continuation lines
+# patch19: debugger can now dump lists of variables
+# patch19: debugger can now add aliases easily from prompt
+#
+# Revision 3.0.1.2 90/03/12 16:39:39 lwall
+# patch13: perl -d didn't format stack traces of *foo right
+# patch13: perl -d wiped out scalar return values of subroutines
+#
+# Revision 3.0.1.1 89/10/26 23:14:02 lwall
+# patch1: RCS expanded an unintended $Header in lib/perldb.pl
+#
+# Revision 3.0 89/10/18 15:19:46 lwall
+# 3.0 baseline
+#
+# Revision 2.0 88/06/05 00:09:45 root
+# Baseline version 2.0.
+#
+#
+
+if (-e "/dev/tty") {
+ $console = "/dev/tty";
+ $rcfile=".perldb";
+}
+else {
+ $console = "con";
+ $rcfile="perldb.ini";
+}
+
+open(IN, "<$console") || open(IN, "<&STDIN"); # so we don't dingle stdin
+open(OUT,">$console") || open(OUT, ">&STDOUT"); # so we don't dongle stdout
+select(OUT);
+$| = 1; # for DB'OUT
+select(STDOUT);
+$| = 1; # for real STDOUT
+$sub = '';
+
+# Is Perl being run from Emacs?
+$emacs = $main'ARGV[$[] eq '-emacs';
+shift(@main'ARGV) if $emacs;
+
+$header =~ s/.Header: ([^,]+),v(\s+\S+\s+\S+).*$/$1$2/;
+print OUT "\nLoading DB routines from $header\n";
+print OUT ("Emacs support ",
+ $emacs ? "enabled" : "available",
+ ".\n");
+print OUT "\nEnter h for help.\n\n";
+
+sub DB {
+ &save;
+ ($package, $filename, $line) = caller;
+ $usercontext = '($@, $!, $[, $,, $/, $\) = @saved;' .
+ "package $package;"; # this won't let them modify, alas
+ local($^P) = 0; # don't debug our own evals
+ local(*dbline) = "_<$filename";
+ $max = $#dbline;
+ if (($stop,$action) = split(/\0/,$dbline{$line})) {
+ if ($stop eq '1') {
+ $signal |= 1;
+ }
+ else {
+ $evalarg = "\$DB'signal |= do {$stop;}"; &eval;
+ $dbline{$line} =~ s/;9($|\0)/$1/;
+ }
+ }
+ if ($single || $trace || $signal) {
+ if ($emacs) {
+ print OUT "\032\032$filename:$line:0\n";
+ } else {
+ print OUT "$package'" unless $sub =~ /'/;
+ print OUT "$sub($filename:$line):\t",$dbline[$line];
+ for ($i = $line + 1; $i <= $max && $dbline[$i] == 0; ++$i) {
+ last if $dbline[$i] =~ /^\s*(}|#|\n)/;
+ print OUT "$sub($filename:$i):\t",$dbline[$i];
+ }
+ }
+ }
+ $evalarg = $action, &eval if $action;
+ if ($single || $signal) {
+ $evalarg = $pre, &eval if $pre;
+ print OUT $#stack . " levels deep in subroutine calls!\n"
+ if $single & 4;
+ $start = $line;
+ CMD:
+ while ((print OUT " DB<", $#hist+1, "> "), $cmd=&gets) {
+ {
+ $single = 0;
+ $signal = 0;
+ $cmd eq '' && exit 0;
+ chop($cmd);
+ $cmd =~ s/\\$// && do {
+ print OUT " cont: ";
+ $cmd .= &gets;
+ redo CMD;
+ };
+ $cmd =~ /^q$/ && exit 0;
+ $cmd =~ /^$/ && ($cmd = $laststep);
+ push(@hist,$cmd) if length($cmd) > 1;
+ ($i) = split(/\s+/,$cmd);
+ eval "\$cmd =~ $alias{$i}", print OUT $@ if $alias{$i};
+ $cmd =~ /^h$/ && do {
+ print OUT "
+T Stack trace.
+s Single step.
+n Next, steps over subroutine calls.
+r Return from current subroutine.
+c [line] Continue; optionally inserts a one-time-only breakpoint
+ at the specified line.
+<CR> Repeat last n or s.
+l min+incr List incr+1 lines starting at min.
+l min-max List lines.
+l line List line;
+l List next window.
+- List previous window.
+w line List window around line.
+l subname List subroutine.
+f filename Switch to filename.
+/pattern/ Search forwards for pattern; final / is optional.
+?pattern? Search backwards for pattern.
+L List breakpoints and actions.
+S List subroutine names.
+t Toggle trace mode.
+b [line] [condition]
+ Set breakpoint; line defaults to the current execution line;
+ condition breaks if it evaluates to true, defaults to \'1\'.
+b subname [condition]
+ Set breakpoint at first line of subroutine.
+d [line] Delete breakpoint.
+D Delete all breakpoints.
+a [line] command
+ Set an action to be done before the line is executed.
+ Sequence is: check for breakpoint, print line if necessary,
+ do action, prompt user if breakpoint or step, evaluate line.
+A Delete all actions.
+V [pkg [vars]] List some (default all) variables in package (default current).
+X [vars] Same as \"V currentpackage [vars]\".
+< command Define command before prompt.
+> command Define command after prompt.
+! number Redo command (default previous command).
+! -number Redo number\'th to last command.
+H -number Display last number commands (default all).
+q or ^D Quit.
+p expr Same as \"print DB'OUT expr\" in current package.
+= [alias value] Define a command alias, or list current aliases.
+command Execute as a perl statement in current package.
+
+";
+ next CMD; };
+ $cmd =~ /^t$/ && do {
+ $trace = !$trace;
+ print OUT "Trace = ".($trace?"on":"off")."\n";
+ next CMD; };
+ $cmd =~ /^S$/ && do {
+ foreach $subname (sort(keys %sub)) {
+ print OUT $subname,"\n";
+ }
+ next CMD; };
+ $cmd =~ s/^X\b/V $package/;
+ $cmd =~ /^V$/ && do {
+ $cmd = 'V $package'; };
+ $cmd =~ /^V\b\s*(\S+)\s*(.*)/ && do {
+ $packname = $1;
+ @vars = split(' ',$2);
+ do 'dumpvar.pl' unless defined &main'dumpvar;
+ if (defined &main'dumpvar) {
+ &main'dumpvar($packname,@vars);
+ }
+ else {
+ print DB'OUT "dumpvar.pl not available.\n";
+ }
+ next CMD; };
+ $cmd =~ /^f\b\s*(.*)/ && do {
+ $file = $1;
+ if (!$file) {
+ print OUT "The old f command is now the r command.\n";
+ print OUT "The new f command switches filenames.\n";
+ next CMD;
+ }
+ if (!defined $_main{'_<' . $file}) {
+ if (($try) = grep(m#^_<.*$file#, keys %_main)) {
+ $file = substr($try,2);
+ print "\n$file:\n";
+ }
+ }
+ if (!defined $_main{'_<' . $file}) {
+ print OUT "There's no code here anything matching $file.\n";
+ next CMD;
+ }
+ elsif ($file ne $filename) {
+ *dbline = "_<$file";
+ $max = $#dbline;
+ $filename = $file;
+ $start = 1;
+ $cmd = "l";
+ } };
+ $cmd =~ /^l\b\s*(['A-Za-z_]['\w]*)/ && do {
+ $subname = $1;
+ $subname = "main'" . $subname unless $subname =~ /'/;
+ $subname = "main" . $subname if substr($subname,0,1) eq "'";
+ ($file,$subrange) = split(/:/,$sub{$subname});
+ if ($file ne $filename) {
+ *dbline = "_<$file";
+ $max = $#dbline;
+ $filename = $file;
+ }
+ if ($subrange) {
+ if (eval($subrange) < -$window) {
+ $subrange =~ s/-.*/+/;
+ }
+ $cmd = "l $subrange";
+ } else {
+ print OUT "Subroutine $1 not found.\n";
+ next CMD;
+ } };
+ $cmd =~ /^w\b\s*(\d*)$/ && do {
+ $incr = $window - 1;
+ $start = $1 if $1;
+ $start -= $preview;
+ $cmd = 'l ' . $start . '-' . ($start + $incr); };
+ $cmd =~ /^-$/ && do {
+ $incr = $window - 1;
+ $cmd = 'l ' . ($start-$window*2) . '+'; };
+ $cmd =~ /^l$/ && do {
+ $incr = $window - 1;
+ $cmd = 'l ' . $start . '-' . ($start + $incr); };
+ $cmd =~ /^l\b\s*(\d*)\+(\d*)$/ && do {
+ $start = $1 if $1;
+ $incr = $2;
+ $incr = $window - 1 unless $incr;
+ $cmd = 'l ' . $start . '-' . ($start + $incr); };
+ $cmd =~ /^l\b\s*(([\d\$\.]+)([-,]([\d\$\.]+))?)?/ && do {
+ $end = (!$2) ? $max : ($4 ? $4 : $2);
+ $end = $max if $end > $max;
+ $i = $2;
+ $i = $line if $i eq '.';
+ $i = 1 if $i < 1;
+ if ($emacs) {
+ print OUT "\032\032$filename:$i:0\n";
+ $i = $end;
+ } else {
+ for (; $i <= $end; $i++) {
+ print OUT "$i:\t", $dbline[$i];
+ last if $signal;
+ }
+ }
+ $start = $i; # remember in case they want more
+ $start = $max if $start > $max;
+ next CMD; };
+ $cmd =~ /^D$/ && do {
+ print OUT "Deleting all breakpoints...\n";
+ for ($i = 1; $i <= $max ; $i++) {
+ if (defined $dbline{$i}) {
+ $dbline{$i} =~ s/^[^\0]+//;
+ if ($dbline{$i} =~ s/^\0?$//) {
+ delete $dbline{$i};
+ }
+ }
+ }
+ next CMD; };
+ $cmd =~ /^L$/ && do {
+ for ($i = 1; $i <= $max; $i++) {
+ if (defined $dbline{$i}) {
+ print OUT "$i:\t", $dbline[$i];
+ ($stop,$action) = split(/\0/, $dbline{$i});
+ print OUT " break if (", $stop, ")\n"
+ if $stop;
+ print OUT " action: ", $action, "\n"
+ if $action;
+ last if $signal;
+ }
+ }
+ next CMD; };
+ $cmd =~ /^b\b\s*(['A-Za-z_]['\w]*)\s*(.*)/ && do {
+ $subname = $1;
+ $cond = $2 || '1';
+ $subname = "$package'" . $subname unless $subname =~ /'/;
+ $subname = "main" . $subname if substr($subname,0,1) eq "'";
+ ($filename,$i) = split(/:/, $sub{$subname});
+ $i += 0;
+ if ($i) {
+ *dbline = "_<$filename";
+ ++$i while $dbline[$i] == 0 && $i < $#dbline;
+ $dbline{$i} =~ s/^[^\0]*/$cond/;
+ } else {
+ print OUT "Subroutine $subname not found.\n";
+ }
+ next CMD; };
+ $cmd =~ /^b\b\s*(\d*)\s*(.*)/ && do {
+ $i = ($1?$1:$line);
+ $cond = $2 || '1';
+ if ($dbline[$i] == 0) {
+ print OUT "Line $i not breakable.\n";
+ } else {
+ $dbline{$i} =~ s/^[^\0]*/$cond/;
+ }
+ next CMD; };
+ $cmd =~ /^d\b\s*(\d+)?/ && do {
+ $i = ($1?$1:$line);
+ $dbline{$i} =~ s/^[^\0]*//;
+ delete $dbline{$i} if $dbline{$i} eq '';
+ next CMD; };
+ $cmd =~ /^A$/ && do {
+ for ($i = 1; $i <= $max ; $i++) {
+ if (defined $dbline{$i}) {
+ $dbline{$i} =~ s/\0[^\0]*//;
+ delete $dbline{$i} if $dbline{$i} eq '';
+ }
+ }
+ next CMD; };
+ $cmd =~ /^<\s*(.*)/ && do {
+ $pre = do action($1);
+ next CMD; };
+ $cmd =~ /^>\s*(.*)/ && do {
+ $post = do action($1);
+ next CMD; };
+ $cmd =~ /^a\b\s*(\d+)(\s+(.*))?/ && do {
+ $i = $1;
+ if ($dbline[$i] == 0) {
+ print OUT "Line $i may not have an action.\n";
+ } else {
+ $dbline{$i} =~ s/\0[^\0]*//;
+ $dbline{$i} .= "\0" . do action($3);
+ }
+ next CMD; };
+ $cmd =~ /^n$/ && do {
+ $single = 2;
+ $laststep = $cmd;
+ last CMD; };
+ $cmd =~ /^s$/ && do {
+ $single = 1;
+ $laststep = $cmd;
+ last CMD; };
+ $cmd =~ /^c\b\s*(\d*)\s*$/ && do {
+ $i = $1;
+ if ($i) {
+ if ($dbline[$i] == 0) {
+ print OUT "Line $i not breakable.\n";
+ next CMD;
+ }
+ $dbline{$i} =~ s/(\0|$)/;9$1/; # add one-time-only b.p.
+ }
+ for ($i=0; $i <= $#stack; ) {
+ $stack[$i++] &= ~1;
+ }
+ last CMD; };
+ $cmd =~ /^r$/ && do {
+ $stack[$#stack] |= 2;
+ last CMD; };
+ $cmd =~ /^T$/ && do {
+ local($p,$f,$l,$s,$h,$a,@a,@sub);
+ for ($i = 1; ($p,$f,$l,$s,$h,$w) = caller($i); $i++) {
+ @a = @args;
+ for (@a) {
+ if (/^StB\000/ && length($_) == length($_main{'_main'})) {
+ $_ = sprintf("%s",$_);
+ }
+ else {
+ s/'/\\'/g;
+ s/([^\0]*)/'$1'/ unless /^-?[\d.]+$/;
+ s/([\200-\377])/sprintf("M-%c",ord($1)&0177)/eg;
+ s/([\0-\37\177])/sprintf("^%c",ord($1)^64)/eg;
+ }
+ }
+ $w = $w ? '@ = ' : '$ = ';
+ $a = $h ? '(' . join(', ', @a) . ')' : '';
+ push(@sub, "$w&$s$a from file $f line $l\n");
+ last if $signal;
+ }
+ for ($i=0; $i <= $#sub; $i++) {
+ last if $signal;
+ print OUT $sub[$i];
+ }
+ next CMD; };
+ $cmd =~ /^\/(.*)$/ && do {
+ $inpat = $1;
+ $inpat =~ s:([^\\])/$:$1:;
+ if ($inpat ne "") {
+ eval '$inpat =~ m'."\n$inpat\n";
+ if ($@ ne "") {
+ print OUT "$@";
+ next CMD;
+ }
+ $pat = $inpat;
+ }
+ $end = $start;
+ eval '
+ for (;;) {
+ ++$start;
+ $start = 1 if ($start > $max);
+ last if ($start == $end);
+ if ($dbline[$start] =~ m'."\n$pat\n".'i) {
+ if ($emacs) {
+ print OUT "\032\032$filename:$start:0\n";
+ } else {
+ print OUT "$start:\t", $dbline[$start], "\n";
+ }
+ last;
+ }
+ } ';
+ print OUT "/$pat/: not found\n" if ($start == $end);
+ next CMD; };
+ $cmd =~ /^\?(.*)$/ && do {
+ $inpat = $1;
+ $inpat =~ s:([^\\])\?$:$1:;
+ if ($inpat ne "") {
+ eval '$inpat =~ m'."\n$inpat\n";
+ if ($@ ne "") {
+ print OUT "$@";
+ next CMD;
+ }
+ $pat = $inpat;
+ }
+ $end = $start;
+ eval '
+ for (;;) {
+ --$start;
+ $start = $max if ($start <= 0);
+ last if ($start == $end);
+ if ($dbline[$start] =~ m'."\n$pat\n".'i) {
+ if ($emacs) {
+ print OUT "\032\032$filename:$start:0\n";
+ } else {
+ print OUT "$start:\t", $dbline[$start], "\n";
+ }
+ last;
+ }
+ } ';
+ print OUT "?$pat?: not found\n" if ($start == $end);
+ next CMD; };
+ $cmd =~ /^!+\s*(-)?(\d+)?$/ && do {
+ pop(@hist) if length($cmd) > 1;
+ $i = ($1?($#hist-($2?$2:1)):($2?$2:$#hist));
+ $cmd = $hist[$i] . "\n";
+ print OUT $cmd;
+ redo CMD; };
+ $cmd =~ /^!(.+)$/ && do {
+ $pat = "^$1";
+ pop(@hist) if length($cmd) > 1;
+ for ($i = $#hist; $i; --$i) {
+ last if $hist[$i] =~ $pat;
+ }
+ if (!$i) {
+ print OUT "No such command!\n\n";
+ next CMD;
+ }
+ $cmd = $hist[$i] . "\n";
+ print OUT $cmd;
+ redo CMD; };
+ $cmd =~ /^H\b\s*(-(\d+))?/ && do {
+ $end = $2?($#hist-$2):0;
+ $hist = 0 if $hist < 0;
+ for ($i=$#hist; $i>$end; $i--) {
+ print OUT "$i: ",$hist[$i],"\n"
+ unless $hist[$i] =~ /^.?$/;
+ };
+ next CMD; };
+ $cmd =~ s/^p( .*)?$/print DB'OUT$1/;
+ $cmd =~ /^=/ && do {
+ if (local($k,$v) = ($cmd =~ /^=\s*(\S+)\s+(.*)/)) {
+ $alias{$k}="s~$k~$v~";
+ print OUT "$k = $v\n";
+ } elsif ($cmd =~ /^=\s*$/) {
+ foreach $k (sort keys(%alias)) {
+ if (($v = $alias{$k}) =~ s~^s\~$k\~(.*)\~$~$1~) {
+ print OUT "$k = $v\n";
+ } else {
+ print OUT "$k\t$alias{$k}\n";
+ };
+ };
+ };
+ next CMD; };
+ }
+ $evalarg = $cmd; &eval;
+ print OUT "\n";
+ }
+ if ($post) {
+ $evalarg = $post; &eval;
+ }
+ }
+ ($@, $!, $[, $,, $/, $\) = @saved;
+}
+
+sub save {
+ @saved = ($@, $!, $[, $,, $/, $\);
+ $[ = 0; $, = ""; $/ = "\n"; $\ = "";
+}
+
+# The following takes its argument via $evalarg to preserve current @_
+
+sub eval {
+ eval "$usercontext $evalarg; &DB'save";
+ print OUT $@;
+}
+
+sub action {
+ local($action) = @_;
+ while ($action =~ s/\\$//) {
+ print OUT "+ ";
+ $action .= &gets;
+ }
+ $action;
+}
+
+sub gets {
+ local($.);
+ <IN>;
+}
+
+sub catch {
+ $signal = 1;
+}
+
+sub sub {
+ push(@stack, $single);
+ $single &= 1;
+ $single |= 4 if $#stack == $deep;
+ if (wantarray) {
+ @i = &$sub;
+ $single |= pop(@stack);
+ @i;
+ }
+ else {
+ $i = &$sub;
+ $single |= pop(@stack);
+ $i;
+ }
+}
+
+$single = 1; # so it stops on first executable statement
+@hist = ('?');
+$SIG{'INT'} = "DB'catch";
+$deep = 100; # warning if stack gets this deep
+$window = 10;
+$preview = 3;
+
+@stack = (0);
+@ARGS = @ARGV;
+for (@args) {
+ s/'/\\'/g;
+ s/(.*)/'$1'/ unless /^-?[\d.]+$/;
+}
+
+if (-f $rcfile) {
+ do "./$rcfile";
+}
+elsif (-f "$ENV{'LOGDIR'}/$rcfile") {
+ do "$ENV{'LOGDIR'}/$rcfile";
+}
+elsif (-f "$ENV{'HOME'}/$rcfile") {
+ do "$ENV{'HOME'}/$rcfile";
+}
+
+1;
diff --git a/gnu/usr.bin/perl/lib/pwd.pl b/gnu/usr.bin/perl/lib/pwd.pl
new file mode 100644
index 0000000..16baadc
--- /dev/null
+++ b/gnu/usr.bin/perl/lib/pwd.pl
@@ -0,0 +1,72 @@
+;# pwd.pl - keeps track of current working directory in PWD environment var
+;#
+;# $RCSfile: pwd.pl,v $$Revision: 1.1.1.1 $$Date: 1993/08/23 21:29:52 $
+;#
+;# $Log: pwd.pl,v $
+# Revision 1.1.1.1 1993/08/23 21:29:52 nate
+# PERL!
+#
+;# Revision 4.0.1.1 92/06/08 13:45:22 lwall
+;# patch20: support added to pwd.pl to strip automounter crud
+;#
+;# Revision 4.0 91/03/20 01:26:03 lwall
+;# 4.0 baseline.
+;#
+;# Revision 3.0.1.2 91/01/11 18:09:24 lwall
+;# patch42: some .pl files were missing their trailing 1;
+;#
+;# Revision 3.0.1.1 90/08/09 04:01:24 lwall
+;# patch19: Initial revision
+;#
+;#
+;# Usage:
+;# require "pwd.pl";
+;# &initpwd;
+;# ...
+;# &chdir($newdir);
+
+package pwd;
+
+sub main'initpwd {
+ if ($ENV{'PWD'}) {
+ local($dd,$di) = stat('.');
+ local($pd,$pi) = stat($ENV{'PWD'});
+ if ($di != $pi || $dd != $pd) {
+ chop($ENV{'PWD'} = `pwd`);
+ }
+ }
+ else {
+ chop($ENV{'PWD'} = `pwd`);
+ }
+ if ($ENV{'PWD'} =~ m|(/[^/]+(/[^/]+/[^/]+))(.*)|) {
+ local($pd,$pi) = stat($2);
+ local($dd,$di) = stat($1);
+ if ($di == $pi && $dd == $pd) {
+ $ENV{'PWD'}="$2$3";
+ }
+ }
+}
+
+sub main'chdir {
+ local($newdir) = shift;
+ if (chdir $newdir) {
+ if ($newdir =~ m#^/#) {
+ $ENV{'PWD'} = $newdir;
+ }
+ else {
+ local(@curdir) = split(m#/#,$ENV{'PWD'});
+ @curdir = '' unless @curdir;
+ foreach $component (split(m#/#, $newdir)) {
+ next if $component eq '.';
+ pop(@curdir),next if $component eq '..';
+ push(@curdir,$component);
+ }
+ $ENV{'PWD'} = join('/',@curdir) || '/';
+ }
+ }
+ else {
+ 0;
+ }
+}
+
+1;
diff --git a/gnu/usr.bin/perl/lib/shellwords.pl b/gnu/usr.bin/perl/lib/shellwords.pl
new file mode 100644
index 0000000..5d593da
--- /dev/null
+++ b/gnu/usr.bin/perl/lib/shellwords.pl
@@ -0,0 +1,48 @@
+;# shellwords.pl
+;#
+;# Usage:
+;# require 'shellwords.pl';
+;# @words = &shellwords($line);
+;# or
+;# @words = &shellwords(@lines);
+;# or
+;# @words = &shellwords; # defaults to $_ (and clobbers it)
+
+sub shellwords {
+ package shellwords;
+ local($_) = join('', @_) if @_;
+ local(@words,$snippet,$field);
+
+ s/^\s+//;
+ while ($_ ne '') {
+ $field = '';
+ for (;;) {
+ if (s/^"(([^"\\]|\\[\\"])*)"//) {
+ ($snippet = $1) =~ s#\\(.)#$1#g;
+ }
+ elsif (/^"/) {
+ die "Unmatched double quote: $_\n";
+ }
+ elsif (s/^'(([^'\\]|\\[\\'])*)'//) {
+ ($snippet = $1) =~ s#\\(.)#$1#g;
+ }
+ elsif (/^'/) {
+ die "Unmatched single quote: $_\n";
+ }
+ elsif (s/^\\(.)//) {
+ $snippet = $1;
+ }
+ elsif (s/^([^\s\\'"]+)//) {
+ $snippet = $1;
+ }
+ else {
+ s/^\s+//;
+ last;
+ }
+ $field .= $snippet;
+ }
+ push(@words, $field);
+ }
+ @words;
+}
+1;
diff --git a/gnu/usr.bin/perl/lib/stat.pl b/gnu/usr.bin/perl/lib/stat.pl
new file mode 100644
index 0000000..6186f54
--- /dev/null
+++ b/gnu/usr.bin/perl/lib/stat.pl
@@ -0,0 +1,31 @@
+;# $Header: /home/cvs/386BSD/ports/lang/perl/lib/stat.pl,v 1.1.1.1 1993/08/23 21:29:53 nate Exp $
+
+;# Usage:
+;# require 'stat.pl';
+;# @ary = stat(foo);
+;# $st_dev = @ary[$ST_DEV];
+;#
+$ST_DEV = 0 + $[;
+$ST_INO = 1 + $[;
+$ST_MODE = 2 + $[;
+$ST_NLINK = 3 + $[;
+$ST_UID = 4 + $[;
+$ST_GID = 5 + $[;
+$ST_RDEV = 6 + $[;
+$ST_SIZE = 7 + $[;
+$ST_ATIME = 8 + $[;
+$ST_MTIME = 9 + $[;
+$ST_CTIME = 10 + $[;
+$ST_BLKSIZE = 11 + $[;
+$ST_BLOCKS = 12 + $[;
+
+;# Usage:
+;# require 'stat.pl';
+;# do Stat('foo'); # sets st_* as a side effect
+;#
+sub Stat {
+ ($st_dev,$st_ino,$st_mode,$st_nlink,$st_uid,$st_gid,$st_rdev,$st_size,
+ $st_atime,$st_mtime,$st_ctime,$st_blksize,$st_blocks) = stat(shift(@_));
+}
+
+1;
diff --git a/gnu/usr.bin/perl/lib/syslog.pl b/gnu/usr.bin/perl/lib/syslog.pl
new file mode 100644
index 0000000..94a4f6a
--- /dev/null
+++ b/gnu/usr.bin/perl/lib/syslog.pl
@@ -0,0 +1,224 @@
+#
+# syslog.pl
+#
+# $Log: syslog.pl,v $
+# Revision 1.1.1.1 1993/08/23 21:29:51 nate
+# PERL!
+#
+# Revision 4.0.1.1 92/06/08 13:48:05 lwall
+# patch20: new warning for ambiguous use of unary operators
+#
+# Revision 4.0 91/03/20 01:26:24 lwall
+# 4.0 baseline.
+#
+# Revision 3.0.1.4 90/11/10 01:41:11 lwall
+# patch38: syslog.pl was referencing an absolute path
+#
+# Revision 3.0.1.3 90/10/15 17:42:18 lwall
+# patch29: various portability fixes
+#
+# Revision 3.0.1.1 90/08/09 03:57:17 lwall
+# patch19: Initial revision
+#
+# Revision 1.2 90/06/11 18:45:30 18:45:30 root ()
+# - Changed 'warn' to 'mail|warning' in test call (to give example of
+# facility specification, and because 'warn' didn't work on HP-UX).
+# - Fixed typo in &openlog ("ncons" should be "cons").
+# - Added (package-global) $maskpri, and &setlogmask.
+# - In &syslog:
+# - put argument test ahead of &connect (why waste cycles?),
+# - allowed facility to be specified in &syslog's first arg (temporarily
+# overrides any $facility set in &openlog), just as in syslog(3C),
+# - do a return 0 when bit for $numpri not set in log mask (see syslog(3C)),
+# - changed $whoami code to use getlogin, getpwuid($<) and 'syslog'
+# (in that order) when $ident is null,
+# - made PID logging consistent with syslog(3C) and subject to $lo_pid only,
+# - fixed typo in "print CONS" statement ($<facility should be <$facility).
+# - changed \n to \r in print CONS (\r is useful, $message already has a \n).
+# - Changed &xlate to return -1 for an unknown name, instead of croaking.
+#
+#
+# tom christiansen <tchrist@convex.com>
+# modified to use sockets by Larry Wall <lwall@jpl-devvax.jpl.nasa.gov>
+# NOTE: openlog now takes three arguments, just like openlog(3)
+#
+# call syslog() with a string priority and a list of printf() args
+# like syslog(3)
+#
+# usage: require 'syslog.pl';
+#
+# then (put these all in a script to test function)
+#
+#
+# do openlog($program,'cons,pid','user');
+# do syslog('info','this is another test');
+# do syslog('mail|warning','this is a better test: %d', time);
+# do closelog();
+#
+# do syslog('debug','this is the last test');
+# do openlog("$program $$",'ndelay','user');
+# do syslog('notice','fooprogram: this is really done');
+#
+# $! = 55;
+# do syslog('info','problem was %m'); # %m == $! in syslog(3)
+
+package syslog;
+
+$host = 'localhost' unless $host; # set $syslog'host to change
+
+require 'syslog.ph';
+
+$maskpri = &LOG_UPTO(&LOG_DEBUG);
+
+sub main'openlog {
+ ($ident, $logopt, $facility) = @_; # package vars
+ $lo_pid = $logopt =~ /\bpid\b/;
+ $lo_ndelay = $logopt =~ /\bndelay\b/;
+ $lo_cons = $logopt =~ /\bcons\b/;
+ $lo_nowait = $logopt =~ /\bnowait\b/;
+ &connect if $lo_ndelay;
+}
+
+sub main'closelog {
+ $facility = $ident = '';
+ &disconnect;
+}
+
+sub main'setlogmask {
+ local($oldmask) = $maskpri;
+ $maskpri = shift;
+ $oldmask;
+}
+
+sub main'syslog {
+ local($priority) = shift;
+ local($mask) = shift;
+ local($message, $whoami);
+ local(@words, $num, $numpri, $numfac, $sum);
+ local($facility) = $facility; # may need to change temporarily.
+
+ die "syslog: expected both priority and mask" unless $mask && $priority;
+
+ @words = split(/\W+/, $priority, 2);# Allow "level" or "level|facility".
+ undef $numpri;
+ undef $numfac;
+ foreach (@words) {
+ $num = &xlate($_); # Translate word to number.
+ if (/^kern$/ || $num < 0) {
+ die "syslog: invalid level/facility: $_\n";
+ }
+ elsif ($num <= &LOG_PRIMASK) {
+ die "syslog: too many levels given: $_\n" if defined($numpri);
+ $numpri = $num;
+ return 0 unless &LOG_MASK($numpri) & $maskpri;
+ }
+ else {
+ die "syslog: too many facilities given: $_\n" if defined($numfac);
+ $facility = $_;
+ $numfac = $num;
+ }
+ }
+
+ die "syslog: level must be given\n" unless defined($numpri);
+
+ if (!defined($numfac)) { # Facility not specified in this call.
+ $facility = 'user' unless $facility;
+ $numfac = &xlate($facility);
+ }
+
+ &connect unless $connected;
+
+ $whoami = $ident;
+
+ if (!$ident && $mask =~ /^(\S.*):\s?(.*)/) {
+ $whoami = $1;
+ $mask = $2;
+ }
+
+ unless ($whoami) {
+ ($whoami = getlogin) ||
+ ($whoami = getpwuid($<)) ||
+ ($whoami = 'syslog');
+ }
+
+ $whoami .= "[$$]" if $lo_pid;
+
+ $mask =~ s/%m/$!/g;
+ $mask .= "\n" unless $mask =~ /\n$/;
+ $message = sprintf ($mask, @_);
+
+ $sum = $numpri + $numfac;
+ unless (send(SYSLOG,"<$sum>$whoami: $message",0)) {
+ if ($lo_cons) {
+ if ($pid = fork) {
+ unless ($lo_nowait) {
+ do {$died = wait;} until $died == $pid || $died < 0;
+ }
+ }
+ else {
+ open(CONS,">/dev/console");
+ print CONS "<$facility.$priority>$whoami: $message\r";
+ exit if defined $pid; # if fork failed, we're parent
+ close CONS;
+ }
+ }
+ }
+}
+
+sub xlate {
+ local($name) = @_;
+ $name =~ y/a-z/A-Z/;
+ $name = "LOG_$name" unless $name =~ /^LOG_/;
+ $name = "syslog'$name";
+ eval(&$name) || -1;
+}
+
+sub connect {
+ $pat = 'S n C4 x8';
+
+ $af_unix = 1;
+ $af_inet = 2;
+
+ $stream = 1;
+ $datagram = 2;
+
+ ($name,$aliases,$proto) = getprotobyname('udp');
+ $udp = $proto;
+
+ ($name,$aliase,$port,$proto) = getservbyname('syslog','udp');
+ $syslog = $port;
+
+ if (chop($myname = `hostname`)) {
+ ($name,$aliases,$addrtype,$length,@addrs) = gethostbyname($myname);
+ die "Can't lookup $myname\n" unless $name;
+ @bytes = unpack("C4",$addrs[0]);
+ }
+ else {
+ @bytes = (0,0,0,0);
+ }
+ $this = pack($pat, $af_inet, 0, @bytes);
+
+ if ($host =~ /^\d+\./) {
+ @bytes = split(/\./,$host);
+ }
+ else {
+ ($name,$aliases,$addrtype,$length,@addrs) = gethostbyname($host);
+ die "Can't lookup $host\n" unless $name;
+ @bytes = unpack("C4",$addrs[0]);
+ }
+ $that = pack($pat,$af_inet,$syslog,@bytes);
+
+ socket(SYSLOG,$af_inet,$datagram,$udp) || die "socket: $!\n";
+ bind(SYSLOG,$this) || die "bind: $!\n";
+ connect(SYSLOG,$that) || die "connect: $!\n";
+
+ local($old) = select(SYSLOG); $| = 1; select($old);
+ $connected = 1;
+}
+
+sub disconnect {
+ close SYSLOG;
+ $connected = 0;
+}
+
+1;
diff --git a/gnu/usr.bin/perl/lib/termcap.pl b/gnu/usr.bin/perl/lib/termcap.pl
new file mode 100644
index 0000000..81556db
--- /dev/null
+++ b/gnu/usr.bin/perl/lib/termcap.pl
@@ -0,0 +1,165 @@
+;# $RCSfile: termcap.pl,v $$Revision: 1.1.1.1 $$Date: 1993/08/23 21:29:52 $
+;#
+;# Usage:
+;# require 'ioctl.pl';
+;# ioctl(TTY,$TIOCGETP,$foo);
+;# ($ispeed,$ospeed) = unpack('cc',$foo);
+;# require 'termcap.pl';
+;# &Tgetent('vt100'); # sets $TC{'cm'}, etc.
+;# &Tputs(&Tgoto($TC{'cm'},$col,$row), 0, 'FILEHANDLE');
+;# &Tputs($TC{'dl'},$affcnt,'FILEHANDLE');
+;#
+sub Tgetent {
+ local($TERM) = @_;
+ local($TERMCAP,$_,$entry,$loop,$field);
+
+ warn "Tgetent: no ospeed set" unless $ospeed;
+ foreach $key (keys(TC)) {
+ delete $TC{$key};
+ }
+ $TERM = $ENV{'TERM'} unless $TERM;
+ $TERMCAP = $ENV{'TERMCAP'};
+ $TERMCAP = '/etc/termcap' unless $TERMCAP;
+ if ($TERMCAP !~ m:^/:) {
+ if ($TERMCAP !~ /(^|\|)$TERM[:\|]/) {
+ $TERMCAP = '/etc/termcap';
+ }
+ }
+ if ($TERMCAP =~ m:^/:) {
+ $entry = '';
+ do {
+ $loop = "
+ open(TERMCAP,'<$TERMCAP') || die \"Can't open $TERMCAP\";
+ while (<TERMCAP>) {
+ next if /^#/;
+ next if /^\t/;
+ if (/(^|\\|)$TERM[:\\|]/) {
+ chop;
+ while (chop eq '\\\\') {
+ \$_ .= <TERMCAP>;
+ chop;
+ }
+ \$_ .= ':';
+ last;
+ }
+ }
+ close TERMCAP;
+ \$entry .= \$_;
+ ";
+ eval $loop;
+ } while s/:tc=([^:]+):/:/ && ($TERM = $1);
+ $TERMCAP = $entry;
+ }
+
+ foreach $field (split(/:[\s:\\]*/,$TERMCAP)) {
+ if ($field =~ /^\w\w$/) {
+ $TC{$field} = 1;
+ }
+ elsif ($field =~ /^(\w\w)#(.*)/) {
+ $TC{$1} = $2 if $TC{$1} eq '';
+ }
+ elsif ($field =~ /^(\w\w)=(.*)/) {
+ $entry = $1;
+ $_ = $2;
+ s/\\E/\033/g;
+ s/\\(\d\d\d)/pack('c',$1 & 0177)/eg;
+ s/\\n/\n/g;
+ s/\\r/\r/g;
+ s/\\t/\t/g;
+ s/\\b/\b/g;
+ s/\\f/\f/g;
+ s/\\\^/\377/g;
+ s/\^\?/\177/g;
+ s/\^(.)/pack('c',ord($1) & 31)/eg;
+ s/\\(.)/$1/g;
+ s/\377/^/g;
+ $TC{$entry} = $_ if $TC{$entry} eq '';
+ }
+ }
+ $TC{'pc'} = "\0" if $TC{'pc'} eq '';
+ $TC{'bc'} = "\b" if $TC{'bc'} eq '';
+}
+
+@Tputs = (0,200,133.3,90.9,74.3,66.7,50,33.3,16.7,8.3,5.5,4.1,2,1,.5,.2);
+
+sub Tputs {
+ local($string,$affcnt,$FH) = @_;
+ local($ms);
+ if ($string =~ /(^[\d.]+)(\*?)(.*)$/) {
+ $ms = $1;
+ $ms *= $affcnt if $2;
+ $string = $3;
+ $decr = $Tputs[$ospeed];
+ if ($decr > .1) {
+ $ms += $decr / 2;
+ $string .= $TC{'pc'} x ($ms / $decr);
+ }
+ }
+ print $FH $string if $FH;
+ $string;
+}
+
+sub Tgoto {
+ local($string) = shift(@_);
+ local($result) = '';
+ local($after) = '';
+ local($code,$tmp) = @_;
+ local(@tmp);
+ @tmp = ($tmp,$code);
+ local($online) = 0;
+ while ($string =~ /^([^%]*)%(.)(.*)/) {
+ $result .= $1;
+ $code = $2;
+ $string = $3;
+ if ($code eq 'd') {
+ $result .= sprintf("%d",shift(@tmp));
+ }
+ elsif ($code eq '.') {
+ $tmp = shift(@tmp);
+ if ($tmp == 0 || $tmp == 4 || $tmp == 10) {
+ if ($online) {
+ ++$tmp, $after .= $TC{'up'} if $TC{'up'};
+ }
+ else {
+ ++$tmp, $after .= $TC{'bc'};
+ }
+ }
+ $result .= sprintf("%c",$tmp);
+ $online = !$online;
+ }
+ elsif ($code eq '+') {
+ $result .= sprintf("%c",shift(@tmp)+ord($string));
+ $string = substr($string,1,99);
+ $online = !$online;
+ }
+ elsif ($code eq 'r') {
+ ($code,$tmp) = @tmp;
+ @tmp = ($tmp,$code);
+ $online = !$online;
+ }
+ elsif ($code eq '>') {
+ ($code,$tmp,$string) = unpack("CCa99",$string);
+ if ($tmp[$[] > $code) {
+ $tmp[$[] += $tmp;
+ }
+ }
+ elsif ($code eq '2') {
+ $result .= sprintf("%02d",shift(@tmp));
+ $online = !$online;
+ }
+ elsif ($code eq '3') {
+ $result .= sprintf("%03d",shift(@tmp));
+ $online = !$online;
+ }
+ elsif ($code eq 'i') {
+ ($code,$tmp) = @tmp;
+ @tmp = ($code+1,$tmp+1);
+ }
+ else {
+ return "OOPS";
+ }
+ }
+ $result . $string . $after;
+}
+
+1;
diff --git a/gnu/usr.bin/perl/lib/timelocal.pl b/gnu/usr.bin/perl/lib/timelocal.pl
new file mode 100644
index 0000000..7028c8e
--- /dev/null
+++ b/gnu/usr.bin/perl/lib/timelocal.pl
@@ -0,0 +1,83 @@
+;# timelocal.pl
+;#
+;# Usage:
+;# $time = timelocal($sec,$min,$hours,$mday,$mon,$year);
+;# $time = timegm($sec,$min,$hours,$mday,$mon,$year);
+
+;# These routines are quite efficient and yet are always guaranteed to agree
+;# with localtime() and gmtime(). We manage this by caching the start times
+;# of any months we've seen before. If we know the start time of the month,
+;# we can always calculate any time within the month. The start times
+;# themselves are guessed by successive approximation starting at the
+;# current time, since most dates seen in practice are close to the
+;# current date. Unlike algorithms that do a binary search (calling gmtime
+;# once for each bit of the time value, resulting in 32 calls), this algorithm
+;# calls it at most 6 times, and usually only once or twice. If you hit
+;# the month cache, of course, it doesn't call it at all.
+
+;# timelocal is implemented using the same cache. We just assume that we're
+;# translating a GMT time, and then fudge it when we're done for the timezone
+;# and daylight savings arguments. The timezone is determined by examining
+;# the result of localtime(0) when the package is initialized. The daylight
+;# savings offset is currently assumed to be one hour.
+
+CONFIG: {
+ package timelocal;
+
+ local($[) = 0;
+ @epoch = localtime(0);
+ $tzmin = $epoch[2] * 60 + $epoch[1]; # minutes east of GMT
+ if ($tzmin > 0) {
+ $tzmin = 24 * 60 - $tzmin; # minutes west of GMT
+ $tzmin -= 24 * 60 if $epoch[5] == 70; # account for the date line
+ }
+
+ $SEC = 1;
+ $MIN = 60 * $SEC;
+ $HR = 60 * $MIN;
+ $DAYS = 24 * $HR;
+ $YearFix = ((gmtime(946684800))[5] == 100) ? 100 : 0;
+ 1;
+}
+
+sub timegm {
+ package timelocal;
+
+ local($[) = 0;
+ $ym = pack(C2, @_[5,4]);
+ $cheat = $cheat{$ym} || &cheat;
+ $cheat + $_[0] * $SEC + $_[1] * $MIN + $_[2] * $HR + ($_[3]-1) * $DAYS;
+}
+
+sub timelocal {
+ package timelocal;
+
+ local($[) = 0;
+ $time = &main'timegm + $tzmin*$MIN;
+ @test = localtime($time);
+ $time -= $HR if $test[2] != $_[2];
+ $time;
+}
+
+package timelocal;
+
+sub cheat {
+ $year = $_[5];
+ $month = $_[4];
+ die "Month out of range 0..11 in ctime.pl\n" if $month > 11;
+ $guess = $^T;
+ @g = gmtime($guess);
+ $year += $YearFix if $year < $epoch[5];
+ while ($diff = $year - $g[5]) {
+ $guess += $diff * (363 * $DAYS);
+ @g = gmtime($guess);
+ }
+ while ($diff = $month - $g[4]) {
+ $guess += $diff * (27 * $DAYS);
+ @g = gmtime($guess);
+ }
+ $g[3]--;
+ $guess -= $g[0] * $SEC + $g[1] * $MIN + $g[2] * $HR + $g[3] * $DAYS;
+ $cheat{$ym} = $guess;
+}
+1;
diff --git a/gnu/usr.bin/perl/lib/validate.pl b/gnu/usr.bin/perl/lib/validate.pl
new file mode 100644
index 0000000..4b901b6
--- /dev/null
+++ b/gnu/usr.bin/perl/lib/validate.pl
@@ -0,0 +1,104 @@
+;# $Header: /home/cvs/386BSD/ports/lang/perl/lib/validate.pl,v 1.1.1.1 1993/08/23 21:29:51 nate Exp $
+
+;# The validate routine takes a single multiline string consisting of
+;# lines containing a filename plus a file test to try on it. (The
+;# file test may also be a 'cd', causing subsequent relative filenames
+;# to be interpreted relative to that directory.) After the file test
+;# you may put '|| die' to make it a fatal error if the file test fails.
+;# The default is '|| warn'. The file test may optionally have a ! prepended
+;# to test for the opposite condition. If you do a cd and then list some
+;# relative filenames, you may want to indent them slightly for readability.
+;# If you supply your own "die" or "warn" message, you can use $file to
+;# interpolate the filename.
+
+;# Filetests may be bunched: -rwx tests for all of -r, -w and -x.
+;# Only the first failed test of the bunch will produce a warning.
+
+;# The routine returns the number of warnings issued.
+
+;# Usage:
+;# require "validate.pl";
+;# $warnings += do validate('
+;# /vmunix -e || die
+;# /boot -e || die
+;# /bin cd
+;# csh -ex
+;# csh !-ug
+;# sh -ex
+;# sh !-ug
+;# /usr -d || warn "What happened to $file?\n"
+;# ');
+
+sub validate {
+ local($file,$test,$warnings,$oldwarnings);
+ foreach $check (split(/\n/,$_[0])) {
+ next if $check =~ /^#/;
+ next if $check =~ /^$/;
+ ($file,$test) = split(' ',$check,2);
+ if ($test =~ s/^(!?-)(\w{2,}\b)/$1Z/) {
+ $testlist = $2;
+ @testlist = split(//,$testlist);
+ }
+ else {
+ @testlist = ('Z');
+ }
+ $oldwarnings = $warnings;
+ foreach $one (@testlist) {
+ $this = $test;
+ $this =~ s/(-\w\b)/$1 \$file/g;
+ $this =~ s/-Z/-$one/;
+ $this .= ' || warn' unless $this =~ /\|\|/;
+ $this =~ s/^(.*\S)\s*\|\|\s*(die|warn)$/$1 || do valmess('$2','$1')/;
+ $this =~ s/\bcd\b/chdir (\$cwd = \$file)/g;
+ eval $this;
+ last if $warnings > $oldwarnings;
+ }
+ }
+ $warnings;
+}
+
+sub valmess {
+ local($disposition,$this) = @_;
+ $file = $cwd . '/' . $file unless $file =~ m|^/|;
+ if ($this =~ /^(!?)-(\w)\s+\$file\s*$/) {
+ $neg = $1;
+ $tmp = $2;
+ $tmp eq 'r' && ($mess = "$file is not readable by uid $>.");
+ $tmp eq 'w' && ($mess = "$file is not writable by uid $>.");
+ $tmp eq 'x' && ($mess = "$file is not executable by uid $>.");
+ $tmp eq 'o' && ($mess = "$file is not owned by uid $>.");
+ $tmp eq 'R' && ($mess = "$file is not readable by you.");
+ $tmp eq 'W' && ($mess = "$file is not writable by you.");
+ $tmp eq 'X' && ($mess = "$file is not executable by you.");
+ $tmp eq 'O' && ($mess = "$file is not owned by you.");
+ $tmp eq 'e' && ($mess = "$file does not exist.");
+ $tmp eq 'z' && ($mess = "$file does not have zero size.");
+ $tmp eq 's' && ($mess = "$file does not have non-zero size.");
+ $tmp eq 'f' && ($mess = "$file is not a plain file.");
+ $tmp eq 'd' && ($mess = "$file is not a directory.");
+ $tmp eq 'l' && ($mess = "$file is not a symbolic link.");
+ $tmp eq 'p' && ($mess = "$file is not a named pipe (FIFO).");
+ $tmp eq 'S' && ($mess = "$file is not a socket.");
+ $tmp eq 'b' && ($mess = "$file is not a block special file.");
+ $tmp eq 'c' && ($mess = "$file is not a character special file.");
+ $tmp eq 'u' && ($mess = "$file does not have the setuid bit set.");
+ $tmp eq 'g' && ($mess = "$file does not have the setgid bit set.");
+ $tmp eq 'k' && ($mess = "$file does not have the sticky bit set.");
+ $tmp eq 'T' && ($mess = "$file is not a text file.");
+ $tmp eq 'B' && ($mess = "$file is not a binary file.");
+ if ($neg eq '!') {
+ $mess =~ s/ is not / should not be / ||
+ $mess =~ s/ does not / should not / ||
+ $mess =~ s/ not / /;
+ }
+ print stderr $mess,"\n";
+ }
+ else {
+ $this =~ s/\$file/'$file'/g;
+ print stderr "Can't do $this.\n";
+ }
+ if ($disposition eq 'die') { exit 1; }
+ ++$warnings;
+}
+
+1;
diff --git a/gnu/usr.bin/perl/misc/c2ph b/gnu/usr.bin/perl/misc/c2ph
new file mode 100644
index 0000000..1a2e4b8
--- /dev/null
+++ b/gnu/usr.bin/perl/misc/c2ph
@@ -0,0 +1,1071 @@
+#!/usr/bin/perl
+#
+#
+# c2ph (aka pstruct)
+# Tom Christiansen, <tchrist@convex.com>
+#
+# As pstruct, dump C structures as generated from 'cc -g -S' stabs.
+# As c2ph, do this PLUS generate perl code for getting at the structures.
+#
+# See the usage message for more. If this isn't enough, read the code.
+#
+
+$RCSID = '$RCSfile: c2ph,v $$Revision: 1.1.1.1 $$Date: 1994/09/10 06:27:31 $';
+
+
+######################################################################
+
+# some handy data definitions. many of these can be reset later.
+
+$bitorder = 'b'; # ascending; set to B for descending bit fields
+
+%intrinsics =
+%template = (
+ 'char', 'c',
+ 'unsigned char', 'C',
+ 'short', 's',
+ 'short int', 's',
+ 'unsigned short', 'S',
+ 'unsigned short int', 'S',
+ 'short unsigned int', 'S',
+ 'int', 'i',
+ 'unsigned int', 'I',
+ 'long', 'l',
+ 'long int', 'l',
+ 'unsigned long', 'L',
+ 'unsigned long', 'L',
+ 'long unsigned int', 'L',
+ 'unsigned long int', 'L',
+ 'long long', 'q',
+ 'long long int', 'q',
+ 'unsigned long long', 'Q',
+ 'unsigned long long int', 'Q',
+ 'float', 'f',
+ 'double', 'd',
+ 'pointer', 'p',
+ 'null', 'x',
+ 'neganull', 'X',
+ 'bit', $bitorder,
+);
+
+&buildscrunchlist;
+delete $intrinsics{'neganull'};
+delete $intrinsics{'bit'};
+delete $intrinsics{'null'};
+
+# use -s to recompute sizes
+%sizeof = (
+ 'char', '1',
+ 'unsigned char', '1',
+ 'short', '2',
+ 'short int', '2',
+ 'unsigned short', '2',
+ 'unsigned short int', '2',
+ 'short unsigned int', '2',
+ 'int', '4',
+ 'unsigned int', '4',
+ 'long', '4',
+ 'long int', '4',
+ 'unsigned long', '4',
+ 'unsigned long int', '4',
+ 'long unsigned int', '4',
+ 'long long', '8',
+ 'long long int', '8',
+ 'unsigned long long', '8',
+ 'unsigned long long int', '8',
+ 'float', '4',
+ 'double', '8',
+ 'pointer', '4',
+);
+
+($type_width, $member_width, $offset_width, $size_width) = (20, 20, 6, 5);
+
+($offset_fmt, $size_fmt) = ('d', 'd');
+
+$indent = 2;
+
+$CC = 'cc';
+$CFLAGS = '-g -S';
+$DEFINES = '';
+
+$perl++ if $0 =~ m#/?c2ph$#;
+
+require 'getopts.pl';
+
+eval '$'.$1.'$2;' while $ARGV[0] =~ /^([A-Za-z_]+=)(.*)/ && shift;
+
+&Getopts('aixdpvtnws:') || &usage(0);
+
+$opt_d && $debug++;
+$opt_t && $trace++;
+$opt_p && $perl++;
+$opt_v && $verbose++;
+$opt_n && ($perl = 0);
+
+if ($opt_w) {
+ ($type_width, $member_width, $offset_width) = (45, 35, 8);
+}
+if ($opt_x) {
+ ($offset_fmt, $offset_width, $size_fmt, $size_width) = ( 'x', '08', 'x', 04 );
+}
+
+eval '$'.$1.'$2;' while $ARGV[0] =~ /^([A-Za-z_]+=)(.*)/ && shift;
+
+sub PLUMBER {
+ select(STDERR);
+ print "oops, apperent pager foulup\n";
+ $isatty++;
+ &usage(1);
+}
+
+sub usage {
+ local($oops) = @_;
+ unless (-t STDOUT) {
+ select(STDERR);
+ } elsif (!$oops) {
+ $isatty++;
+ $| = 1;
+ print "hit <RETURN> for further explanation: ";
+ <STDIN>;
+ open (PIPE, "|". ($ENV{PAGER} || 'more'));
+ $SIG{PIPE} = PLUMBER;
+ select(PIPE);
+ }
+
+ print "usage: $0 [-dpnP] [var=val] [files ...]\n";
+
+ exit unless $isatty;
+
+ print <<EOF;
+
+Options:
+
+-w wide; short for: type_width=45 member_width=35 offset_width=8
+-x hex; short for: offset_fmt=x offset_width=08 size_fmt=x size_width=04
+
+-n do not generate perl code (default when invoked as pstruct)
+-p generate perl code (default when invoked as c2ph)
+-v generate perl code, with C decls as comments
+
+-i do NOT recompute sizes for intrinsic datatypes
+-a dump information on intrinsics also
+
+-t trace execution
+-d spew reams of debugging output
+
+-slist give comma-separated list a structures to dump
+
+
+Var Name Default Value Meaning
+
+EOF
+
+ &defvar('CC', 'which_compiler to call');
+ &defvar('CFLAGS', 'how to generate *.s files with stabs');
+ &defvar('DEFINES','any extra cflags or cpp defines, like -I, -D, -U');
+
+ print "\n";
+
+ &defvar('type_width', 'width of type field (column 1)');
+ &defvar('member_width', 'width of member field (column 2)');
+ &defvar('offset_width', 'width of offset field (column 3)');
+ &defvar('size_width', 'width of size field (column 4)');
+
+ print "\n";
+
+ &defvar('offset_fmt', 'sprintf format type for offset');
+ &defvar('size_fmt', 'sprintf format type for size');
+
+ print "\n";
+
+ &defvar('indent', 'how far to indent each nesting level');
+
+ print <<'EOF';
+
+ If any *.[ch] files are given, these will be catted together into
+ a temporary *.c file and sent through:
+ $CC $CFLAGS $DEFINES
+ and the resulting *.s groped for stab information. If no files are
+ supplied, then stdin is read directly with the assumption that it
+ contains stab information. All other liens will be ignored. At
+ most one *.s file should be supplied.
+
+EOF
+ close PIPE;
+ exit 1;
+}
+
+sub defvar {
+ local($var, $msg) = @_;
+ printf "%-16s%-15s %s\n", $var, eval "\$$var", $msg;
+}
+
+$recurse = 1;
+
+if (@ARGV) {
+ if (grep(!/\.[csh]$/,@ARGV)) {
+ warn "Only *.[csh] files expected!\n";
+ &usage;
+ }
+ elsif (grep(/\.s$/,@ARGV)) {
+ if (@ARGV > 1) {
+ warn "Only one *.s file allowed!\n";
+ &usage;
+ }
+ }
+ elsif (@ARGV == 1 && $ARGV[0] =~ /\.c$/) {
+ local($dir, $file) = $ARGV[0] =~ m#(.*/)?(.*)$#;
+ $chdir = "cd $dir; " if $dir;
+ &system("$chdir$CC $CFLAGS $DEFINES $file") && exit 1;
+ $ARGV[0] =~ s/\.c$/.s/;
+ }
+ else {
+ $TMP = "/tmp/c2ph.$$.c";
+ &system("cat @ARGV > $TMP") && exit 1;
+ &system("cd /tmp; $CC $CFLAGS $DEFINES $TMP") && exit 1;
+ unlink $TMP;
+ $TMP =~ s/\.c$/.s/;
+ @ARGV = ($TMP);
+ }
+}
+
+if ($opt_s) {
+ for (split(/[\s,]+/, $opt_s)) {
+ $interested{$_}++;
+ }
+}
+
+
+$| = 1 if $debug;
+
+main: {
+
+ if ($trace) {
+ if (-t && !@ARGV) {
+ print STDERR "reading from your keyboard: ";
+ } else {
+ print STDERR "reading from " . (@ARGV ? "@ARGV" : "<STDIN>").": ";
+ }
+ }
+
+STAB: while (<>) {
+ if ($trace && !($. % 10)) {
+ $lineno = $..'';
+ print STDERR $lineno, "\b" x length($lineno);
+ }
+ next unless /^\s*\.stabs\s+/;
+ $line = $_;
+ s/^\s*\.stabs\s+//;
+ &stab;
+ }
+ print STDERR "$.\n" if $trace;
+ unlink $TMP if $TMP;
+
+ &compute_intrinsics if $perl && !$opt_i;
+
+ print STDERR "resolving types\n" if $trace;
+
+ &resolve_types;
+ &adjust_start_addrs;
+
+ $sum = 2 + $type_width + $member_width;
+ $pmask1 = "%-${type_width}s %-${member_width}s";
+ $pmask2 = "%-${sum}s %${offset_width}${offset_fmt}%s %${size_width}${size_fmt}%s";
+
+ if ($perl) {
+ # resolve template -- should be in stab define order, but even this isn't enough.
+ print STDERR "\nbuilding type templates: " if $trace;
+ for $i (reverse 0..$#type) {
+ next unless defined($name = $type[$i]);
+ next unless defined $struct{$name};
+ $build_recursed = 0;
+ &build_template($name) unless defined $template{&psou($name)} ||
+ $opt_s && !$interested{$name};
+ }
+ print STDERR "\n\n" if $trace;
+ }
+
+ print STDERR "dumping structs: " if $trace;
+
+
+ foreach $name (sort keys %struct) {
+ next if $opt_s && !$interested{$name};
+ print STDERR "$name " if $trace;
+
+ undef @sizeof;
+ undef @typedef;
+ undef @offsetof;
+ undef @indices;
+ undef @typeof;
+
+ $mname = &munge($name);
+
+ $fname = &psou($name);
+
+ print "# " if $perl && $verbose;
+ $pcode = '';
+ print "$fname {\n" if !$perl || $verbose;
+ $template{$fname} = &scrunch($template{$fname}) if $perl;
+ &pstruct($name,$name,0);
+ print "# " if $perl && $verbose;
+ print "}\n" if !$perl || $verbose;
+ print "\n" if $perl && $verbose;
+
+ if ($perl) {
+ print "$pcode";
+
+ printf("\nsub %-32s { %4d; }\n\n", "${mname}'struct", $countof{$name});
+
+ print <<EOF;
+sub ${mname}'typedef {
+ local(\$${mname}'index) = shift;
+ defined \$${mname}'index
+ ? \$${mname}'typedef[\$${mname}'index]
+ : \$${mname}'typedef;
+}
+EOF
+
+ print <<EOF;
+sub ${mname}'sizeof {
+ local(\$${mname}'index) = shift;
+ defined \$${mname}'index
+ ? \$${mname}'sizeof[\$${mname}'index]
+ : \$${mname}'sizeof;
+}
+EOF
+
+ print <<EOF;
+sub ${mname}'offsetof {
+ local(\$${mname}'index) = shift;
+ defined \$${mname}index
+ ? \$${mname}'offsetof[\$${mname}'index]
+ : \$${mname}'sizeof;
+}
+EOF
+
+ print <<EOF;
+sub ${mname}'typeof {
+ local(\$${mname}'index) = shift;
+ defined \$${mname}index
+ ? \$${mname}'typeof[\$${mname}'index]
+ : '$name';
+}
+EOF
+
+
+ print "\$${mname}'typedef = '" . &scrunch($template{$fname})
+ . "';\n";
+
+ print "\$${mname}'sizeof = $sizeof{$name};\n\n";
+
+
+ print "\@${mname}'indices = (", &squishseq(@indices), ");\n";
+
+ print "\n";
+
+ print "\@${mname}'typedef[\@${mname}'indices] = (",
+ join("\n\t", '', @typedef), "\n );\n\n";
+ print "\@${mname}'sizeof[\@${mname}'indices] = (",
+ join("\n\t", '', @sizeof), "\n );\n\n";
+ print "\@${mname}'offsetof[\@${mname}'indices] = (",
+ join("\n\t", '', @offsetof), "\n );\n\n";
+ print "\@${mname}'typeof[\@${mname}'indices] = (",
+ join("\n\t", '', @typeof), "\n );\n\n";
+
+ $template_printed{$fname}++;
+ $size_printed{$fname}++;
+ }
+ print "\n";
+ }
+
+ print STDERR "\n" if $trace;
+
+ unless ($perl && $opt_a) {
+ print "\n1;\n";
+ exit;
+ }
+
+
+
+ foreach $name (sort bysizevalue keys %intrinsics) {
+ next if $size_printed{$name};
+ print '$',&munge($name),"'sizeof = ", $sizeof{$name}, ";\n";
+ }
+
+ print "\n";
+
+ sub bysizevalue { $sizeof{$a} <=> $sizeof{$b}; }
+
+
+ foreach $name (sort keys %intrinsics) {
+ print '$',&munge($name),"'typedef = '", $template{$name}, "';\n";
+ }
+
+ print "\n1;\n";
+
+ exit;
+}
+
+########################################################################################
+
+
+sub stab {
+ next unless /:[\$\w]+(\(\d+,\d+\))?=[\*\$\w]+/; # (\d+,\d+) is for sun
+ s/"// || next;
+ s/",([x\d]+),([x\d]+),([x\d]+),.*// || next;
+
+ next if /^\s*$/;
+
+ $size = $3 if $3;
+
+
+ $line = $_;
+
+ if (($name, $pdecl) = /^([\$ \w]+):[tT]((\d+)(=[rufs*](\d+))+)$/) {
+ print "$name is a typedef for some funky pointers: $pdecl\n" if $debug;
+ &pdecl($pdecl);
+ next;
+ }
+
+
+
+ if (/(([ \w]+):t(\d+|\(\d+,\d+\)))=r?(\d+|\(\d+,\d+\))(;\d+;\d+;)?/) {
+ local($ident) = $2;
+ push(@intrinsics, $ident);
+ $typeno = &typeno($3);
+ $type[$typeno] = $ident;
+ print STDERR "intrinsic $ident in new type $typeno\n" if $debug;
+ next;
+ }
+
+ if (($name, $typeordef, $typeno, $extra, $struct, $_)
+ = /^([\$ \w]+):([ustT])(\d+|\(\d+,\d+\))(=[rufs*](\d+))?(.*)$/)
+ {
+ $typeno = &typeno($typeno); # sun foolery
+ }
+ elsif (/^[\$\w]+:/) {
+ next; # variable
+ }
+ else {
+ warn "can't grok stab: <$_> in: $line " if $_;
+ next;
+ }
+
+ #warn "got size $size for $name\n";
+ $sizeof{$name} = $size if $size;
+
+ s/;[-\d]*;[-\d]*;$//; # we don't care about ranges
+
+ $typenos{$name} = $typeno;
+
+ unless (defined $type[$typeno]) {
+ &panic("type 0??") unless $typeno;
+ $type[$typeno] = $name unless defined $type[$typeno];
+ printf "new type $typeno is $name" if $debug;
+ if ($extra =~ /\*/ && defined $type[$struct]) {
+ print ", a typedef for a pointer to " , $type[$struct] if $debug;
+ }
+ } else {
+ printf "%s is type %d", $name, $typeno if $debug;
+ print ", a typedef for " , $type[$typeno] if $debug;
+ }
+ print "\n" if $debug;
+ #next unless $extra =~ /[su*]/;
+
+ #$type[$struct] = $name;
+
+ if ($extra =~ /[us*]/) {
+ &sou($name, $extra);
+ $_ = &sdecl($name, $_, 0);
+ }
+ elsif (/^=ar/) {
+ print "it's a bare array typedef -- that's pretty sick\n" if $debug;
+ $_ = "$typeno$_";
+ $scripts = '';
+ $_ = &adecl($_,1);
+
+ }
+ elsif (s/((\w+):t(\d+|\(\d+,\d+\)))?=r?(;\d+;\d+;)?//) { # the ?'s are for gcc
+ push(@intrinsics, $2);
+ $typeno = &typeno($3);
+ $type[$typeno] = $2;
+ print STDERR "intrinsic $2 in new type $typeno\n" if $debug;
+ }
+ elsif (s/^=e//) { # blessed by thy compiler; mine won't do this
+ &edecl;
+ }
+ else {
+ warn "Funny remainder for $name on line $_ left in $line " if $_;
+ }
+}
+
+sub typeno { # sun thinks types are (0,27) instead of just 27
+ local($_) = @_;
+ s/\(\d+,(\d+)\)/$1/;
+ $_;
+}
+
+sub pstruct {
+ local($what,$prefix,$base) = @_;
+ local($field, $fieldname, $typeno, $count, $offset, $entry);
+ local($fieldtype);
+ local($type, $tname);
+ local($mytype, $mycount, $entry2);
+ local($struct_count) = 0;
+ local($pad, $revpad, $length, $prepad, $lastoffset, $lastlength, $fmt);
+ local($bits,$bytes);
+ local($template);
+
+
+ local($mname) = &munge($name);
+
+ sub munge {
+ local($_) = @_;
+ s/[\s\$\.]/_/g;
+ $_;
+ }
+
+ local($sname) = &psou($what);
+
+ $nesting++;
+
+ for $field (split(/;/, $struct{$what})) {
+ $pad = $prepad = 0;
+ $entry = '';
+ ($fieldname, $typeno, $count, $offset, $length) = split(/,/, $field);
+
+ $type = $type[$typeno];
+
+ $type =~ /([^[]*)(\[.*\])?/;
+ $mytype = $1;
+ $count .= $2;
+ $fieldtype = &psou($mytype);
+
+ local($fname) = &psou($name);
+
+ if ($build_templates) {
+
+ $pad = ($offset - ($lastoffset + $lastlength))/8
+ if defined $lastoffset;
+
+ if (! $finished_template{$sname}) {
+ if ($isaunion{$what}) {
+ $template{$sname} .= 'X' x $revpad . ' ' if $revpad;
+ } else {
+ $template{$sname} .= 'x' x $pad . ' ' if $pad;
+ }
+ }
+
+ $template = &fetch_template($type) x
+ ($count ? &scripts2count($count) : 1);
+
+ if (! $finished_template{$sname}) {
+ $template{$sname} .= $template;
+ }
+
+ $revpad = $length/8 if $isaunion{$what};
+
+ ($lastoffset, $lastlength) = ($offset, $length);
+
+ } else {
+ print '# ' if $perl && $verbose;
+ $entry = sprintf($pmask1,
+ ' ' x ($nesting * $indent) . $fieldtype,
+ "$prefix.$fieldname" . $count);
+
+ $entry =~ s/(\*+)( )/$2$1/;
+
+ printf $pmask2,
+ $entry,
+ ($base+$offset)/8,
+ ($bits = ($base+$offset)%8) ? ".$bits" : " ",
+ $length/8,
+ ($bits = $length % 8) ? ".$bits": ""
+ if !$perl || $verbose;
+
+
+ if ($perl && $nesting == 1) {
+ $template = &scrunch(&fetch_template($type) x
+ ($count ? &scripts2count($count) : 1));
+ push(@sizeof, int($length/8) .",\t# $fieldname");
+ push(@offsetof, int($offset/8) .",\t# $fieldname");
+ push(@typedef, "'$template', \t# $fieldname");
+ $type =~ s/(struct|union) //;
+ push(@typeof, "'$type" . ($count ? $count : '') .
+ "',\t# $fieldname");
+ }
+
+ print ' ', ' ' x $indent x $nesting, $template
+ if $perl && $verbose;
+
+ print "\n" if !$perl || $verbose;
+
+ }
+ if ($perl) {
+ local($mycount) = defined $struct{$mytype} ? $countof{$mytype} : 1;
+ $mycount *= &scripts2count($count) if $count;
+ if ($nesting==1 && !$build_templates) {
+ $pcode .= sprintf("sub %-32s { %4d; }\n",
+ "${mname}'${fieldname}", $struct_count);
+ push(@indices, $struct_count);
+ }
+ $struct_count += $mycount;
+ }
+
+
+ &pstruct($type, "$prefix.$fieldname", $base+$offset)
+ if $recurse && defined $struct{$type};
+ }
+
+ $countof{$what} = $struct_count unless defined $countof{$whati};
+
+ $template{$sname} .= '$' if $build_templates;
+ $finished_template{$sname}++;
+
+ if ($build_templates && !defined $sizeof{$name}) {
+ local($fmt) = &scrunch($template{$sname});
+ print STDERR "no size for $name, punting with $fmt..." if $debug;
+ eval '$sizeof{$name} = length(pack($fmt, ()))';
+ if ($@) {
+ chop $@;
+ warn "couldn't get size for \$name: $@";
+ } else {
+ print STDERR $sizeof{$name}, "\n" if $debUg;
+ }
+ }
+
+ --$nesting;
+}
+
+
+sub psize {
+ local($me) = @_;
+ local($amstruct) = $struct{$me} ? 'struct ' : '';
+
+ print '$sizeof{\'', $amstruct, $me, '\'} = ';
+ printf "%d;\n", $sizeof{$me};
+}
+
+sub pdecl {
+ local($pdecl) = @_;
+ local(@pdecls);
+ local($tname);
+
+ warn "pdecl: $pdecl\n" if $debug;
+
+ $pdecl =~ s/\(\d+,(\d+)\)/$1/g;
+ $pdecl =~ s/\*//g;
+ @pdecls = split(/=/, $pdecl);
+ $typeno = $pdecls[0];
+ $tname = pop @pdecls;
+
+ if ($tname =~ s/^f//) { $tname = "$tname&"; }
+ #else { $tname = "$tname*"; }
+
+ for (reverse @pdecls) {
+ $tname .= s/^f// ? "&" : "*";
+ #$tname =~ s/^f(.*)/$1&/;
+ print "type[$_] is $tname\n" if $debug;
+ $type[$_] = $tname unless defined $type[$_];
+ }
+}
+
+
+
+sub adecl {
+ ($arraytype, $unknown, $lower, $upper) = ();
+ #local($typeno);
+ # global $typeno, @type
+ local($_, $typedef) = @_;
+
+ while (s/^((\d+)=)?ar(\d+);//) {
+ ($arraytype, $unknown) = ($2, $3);
+ if (s/^(\d+);(\d+);//) {
+ ($lower, $upper) = ($1, $2);
+ $scripts .= '[' . ($upper+1) . ']';
+ } else {
+ warn "can't find array bounds: $_";
+ }
+ }
+ if (s/^([\d*f=]*),(\d+),(\d+);//) {
+ ($start, $length) = ($2, $3);
+ local($whatis) = $1;
+ if ($whatis =~ /^(\d+)=/) {
+ $typeno = $1;
+ &pdecl($whatis);
+ } else {
+ $typeno = $whatis;
+ }
+ } elsif (s/^(\d+)(=[*suf]\d*)//) {
+ local($whatis) = $2;
+
+ if ($whatis =~ /[f*]/) {
+ &pdecl($whatis);
+ } elsif ($whatis =~ /[su]/) { #
+ print "$prefix.$fieldname is an array$scripts anon structs; disgusting\n"
+ if $debug;
+ #$type[$typeno] = $name unless defined $type[$typeno];
+ ##printf "new type $typeno is $name" if $debug;
+ $typeno = $1;
+ $type[$typeno] = "$prefix.$fieldname";
+ local($name) = $type[$typeno];
+ &sou($name, $whatis);
+ $_ = &sdecl($name, $_, $start+$offset);
+ 1;
+ $start = $start{$name};
+ $offset = $sizeof{$name};
+ $length = $offset;
+ } else {
+ warn "what's this? $whatis in $line ";
+ }
+ } elsif (/^\d+$/) {
+ $typeno = $_;
+ } else {
+ warn "bad array stab: $_ in $line ";
+ next STAB;
+ }
+ #local($wasdef) = defined($type[$typeno]) && $debug;
+ #if ($typedef) {
+ #print "redefining $type[$typeno] to " if $wasdef;
+ #$type[$typeno] = "$whatis$scripts"; # unless defined $type[$typeno];
+ #print "$type[$typeno]\n" if $wasdef;
+ #} else {
+ #$type[$arraytype] = $type[$typeno] unless defined $type[$arraytype];
+ #}
+ $type[$arraytype] = "$type[$typeno]$scripts" if defined $type[$typeno];
+ print "type[$arraytype] is $type[$arraytype]\n" if $debug;
+ print "$prefix.$fieldname is an array of $type[$arraytype]\n" if $debug;
+ $_;
+}
+
+
+
+sub sdecl {
+ local($prefix, $_, $offset) = @_;
+
+ local($fieldname, $scripts, $type, $arraytype, $unknown,
+ $whatis, $pdecl, $upper,$lower, $start,$length) = ();
+ local($typeno,$sou);
+
+
+SFIELD:
+ while (/^([^;]+);/) {
+ $scripts = '';
+ warn "sdecl $_\n" if $debug;
+ if (s/^([\$\w]+)://) {
+ $fieldname = $1;
+ } elsif (s/(\d+)=([us])(\d+|\(\d+,\d+\))//) { #
+ $typeno = &typeno($1);
+ $type[$typeno] = "$prefix.$fieldname";
+ local($name) = "$prefix.$fieldname";
+ &sou($name,$2);
+ $_ = &sdecl("$prefix.$fieldname", $_, $start+$offset);
+ $start = $start{$name};
+ $offset += $sizeof{$name};
+ #print "done with anon, start is $start, offset is $offset\n";
+ #next SFIELD;
+ } else {
+ warn "weird field $_ of $line" if $debug;
+ next STAB;
+ #$fieldname = &gensym;
+ #$_ = &sdecl("$prefix.$fieldname", $_, $start+$offset);
+ }
+
+ if (/^\d+=ar/) {
+ $_ = &adecl($_);
+ }
+ elsif (s/^(\d+|\(\d+,\d+\))?,(\d+),(\d+);//) {
+ ($start, $length) = ($2, $3);
+ &panic("no length?") unless $length;
+ $typeno = &typeno($1) if $1;
+ }
+ elsif (s/^((\d+|\(\d+,\d+\))(=[*f](\d+|\(\d+,\d+\)))+),(\d+),(\d+);//) {
+ ($pdecl, $start, $length) = ($1,$5,$6);
+ &pdecl($pdecl);
+ }
+ elsif (s/(\d+)=([us])(\d+|\(\d+,\d+\))//) { # the dratted anon struct
+ ($typeno, $sou) = ($1, $2);
+ $typeno = &typeno($typeno);
+ if (defined($type[$typeno])) {
+ warn "now how did we get type $1 in $fieldname of $line?";
+ } else {
+ print "anon type $typeno is $prefix.$fieldname\n" if $debug;
+ $type[$typeno] = "$prefix.$fieldname" unless defined $type[$typeno];
+ };
+ local($name) = "$prefix.$fieldname";
+ &sou($name,$sou);
+ print "anon ".($isastruct{$name}) ? "struct":"union"." for $prefix.$fieldname\n" if $debug;
+ $type[$typeno] = "$prefix.$fieldname";
+ $_ = &sdecl("$prefix.$fieldname", $_, $start+$offset);
+ $start = $start{$name};
+ $length = $sizeof{$name};
+ }
+ else {
+ warn "can't grok stab for $name ($_) in line $line ";
+ next STAB;
+ }
+
+ &panic("no length for $prefix.$fieldname") unless $length;
+ $struct{$name} .= join(',', $fieldname, $typeno, $scripts, $start, $length) . ';';
+ }
+ if (s/;\d*,(\d+),(\d+);//) {
+ local($start, $size) = ($1, $2);
+ $sizeof{$prefix} = $size;
+ print "start of $prefix is $start, size of $sizeof{$prefix}\n" if $debug;
+ $start{$prefix} = $start;
+ }
+ $_;
+}
+
+sub edecl {
+ s/;$//;
+ $enum{$name} = $_;
+ $_ = '';
+}
+
+sub resolve_types {
+ local($sou);
+ for $i (0 .. $#type) {
+ next unless defined $type[$i];
+ $_ = $type[$i];
+ unless (/\d/) {
+ print "type[$i] $type[$i]\n" if $debug;
+ next;
+ }
+ print "type[$i] $_ ==> " if $debug;
+ s/^(\d+)(\**)\&\*(\**)/"$2($3".&type($1) . ')()'/e;
+ s/^(\d+)\&/&type($1)/e;
+ s/^(\d+)/&type($1)/e;
+ s/(\*+)([^*]+)(\*+)/$1$3$2/;
+ s/\((\*+)(\w+)(\*+)\)/$3($1$2)/;
+ s/^(\d+)([\*\[].*)/&type($1).$2/e;
+ #s/(\d+)(\*|(\[[\[\]\d\*]+]\])+)/&type($1).$2/ge;
+ $type[$i] = $_;
+ print "$_\n" if $debug;
+ }
+}
+sub type { &psou($type[$_[0]] || "<UNDEFINED>"); }
+
+sub adjust_start_addrs {
+ for (sort keys %start) {
+ ($basename = $_) =~ s/\.[^.]+$//;
+ $start{$_} += $start{$basename};
+ print "start: $_ @ $start{$_}\n" if $debug;
+ }
+}
+
+sub sou {
+ local($what, $_) = @_;
+ /u/ && $isaunion{$what}++;
+ /s/ && $isastruct{$what}++;
+}
+
+sub psou {
+ local($what) = @_;
+ local($prefix) = '';
+ if ($isaunion{$what}) {
+ $prefix = 'union ';
+ } elsif ($isastruct{$what}) {
+ $prefix = 'struct ';
+ }
+ $prefix . $what;
+}
+
+sub scrunch {
+ local($_) = @_;
+
+ study;
+
+ s/\$//g;
+ s/ / /g;
+ 1 while s/(\w) \1/$1$1/g;
+
+ # i wanna say this, but perl resists my efforts:
+ # s/(\w)(\1+)/$2 . length($1)/ge;
+
+ &quick_scrunch;
+
+ s/ $//;
+
+ $_;
+}
+
+sub buildscrunchlist {
+ $scrunch_code = "sub quick_scrunch {\n";
+ for (values %intrinsics) {
+ $scrunch_code .= "\ts/($_{2,})/'$_' . length(\$1)/ge;\n";
+ }
+ $scrunch_code .= "}\n";
+ print "$scrunch_code" if $debug;
+ eval $scrunch_code;
+ &panic("can't eval scrunch_code $@ \nscrunch_code") if $@;
+}
+
+sub fetch_template {
+ local($mytype) = @_;
+ local($fmt);
+ local($count) = 1;
+
+ &panic("why do you care?") unless $perl;
+
+ if ($mytype =~ s/(\[\d+\])+$//) {
+ $count .= $1;
+ }
+
+ if ($mytype =~ /\*/) {
+ $fmt = $template{'pointer'};
+ }
+ elsif (defined $template{$mytype}) {
+ $fmt = $template{$mytype};
+ }
+ elsif (defined $struct{$mytype}) {
+ if (!defined $template{&psou($mytype)}) {
+ &build_template($mytype) unless $mytype eq $name;
+ }
+ elsif ($template{&psou($mytype)} !~ /\$$/) {
+ #warn "incomplete template for $mytype\n";
+ }
+ $fmt = $template{&psou($mytype)} || '?';
+ }
+ else {
+ warn "unknown fmt for $mytype\n";
+ $fmt = '?';
+ }
+
+ $fmt x $count . ' ';
+}
+
+sub compute_intrinsics {
+ local($TMP) = "/tmp/c2ph-i.$$.c";
+ open (TMP, ">$TMP") || die "can't open $TMP: $!";
+ select(TMP);
+
+ print STDERR "computing intrinsic sizes: " if $trace;
+
+ undef %intrinsics;
+
+ print <<'EOF';
+main() {
+ char *mask = "%d %s\n";
+EOF
+
+ for $type (@intrinsics) {
+ next if $type eq 'void';
+ print <<"EOF";
+ printf(mask,sizeof($type), "$type");
+EOF
+ }
+
+ print <<'EOF';
+ printf(mask,sizeof(char *), "pointer");
+ exit(0);
+}
+EOF
+ close TMP;
+
+ select(STDOUT);
+ open(PIPE, "cd /tmp && $CC $TMP && /tmp/a.out|");
+ while (<PIPE>) {
+ chop;
+ split(' ',$_,2);;
+ print "intrinsic $_[1] is size $_[0]\n" if $debug;
+ $sizeof{$_[1]} = $_[0];
+ $intrinsics{$_[1]} = $template{$_[0]};
+ }
+ close(PIPE) || die "couldn't read intrinsics!";
+ unlink($TMP, '/tmp/a.out');
+ print STDERR "done\n" if $trace;
+}
+
+sub scripts2count {
+ local($_) = @_;
+
+ s/^\[//;
+ s/\]$//;
+ s/\]\[/*/g;
+ $_ = eval;
+ &panic("$_: $@") if $@;
+ $_;
+}
+
+sub system {
+ print STDERR "@_\n" if $trace;
+ system @_;
+}
+
+sub build_template {
+ local($name) = @_;
+
+ &panic("already got a template for $name") if defined $template{$name};
+
+ local($build_templates) = 1;
+
+ local($lparen) = '(' x $build_recursed;
+ local($rparen) = ')' x $build_recursed;
+
+ print STDERR "$lparen$name$rparen " if $trace;
+ $build_recursed++;
+ &pstruct($name,$name,0);
+ print STDERR "TEMPLATE for $name is ", $template{&psou($name)}, "\n" if $debug;
+ --$build_recursed;
+}
+
+
+sub panic {
+
+ select(STDERR);
+
+ print "\npanic: @_\n";
+
+ exit 1 if $] <= 4.003; # caller broken
+
+ local($i,$_);
+ local($p,$f,$l,$s,$h,$a,@a,@sub);
+ for ($i = 0; ($p,$f,$l,$s,$h,$w) = caller($i); $i++) {
+ @a = @DB'args;
+ for (@a) {
+ if (/^StB\000/ && length($_) == length($_main{'_main'})) {
+ $_ = sprintf("%s",$_);
+ }
+ else {
+ s/'/\\'/g;
+ s/([^\0]*)/'$1'/ unless /^-?[\d.]+$/;
+ s/([\200-\377])/sprintf("M-%c",ord($1)&0177)/eg;
+ s/([\0-\37\177])/sprintf("^%c",ord($1)^64)/eg;
+ }
+ }
+ $w = $w ? '@ = ' : '$ = ';
+ $a = $h ? '(' . join(', ', @a) . ')' : '';
+ push(@sub, "$w&$s$a from file $f line $l\n");
+ last if $signal;
+ }
+ for ($i=0; $i <= $#sub; $i++) {
+ last if $signal;
+ print $sub[$i];
+ }
+ exit 1;
+}
+
+sub squishseq {
+ local($num);
+ local($last) = -1e8;
+ local($string);
+ local($seq) = '..';
+
+ while (defined($num = shift)) {
+ if ($num == ($last + 1)) {
+ $string .= $seq unless $inseq++;
+ $last = $num;
+ next;
+ } elsif ($inseq) {
+ $string .= $last unless $last == -1e8;
+ }
+
+ $string .= ',' if defined $string;
+ $string .= $num;
+ $last = $num;
+ $inseq = 0;
+ }
+ $string .= $last if $inseq && $last != -e18;
+ $string;
+}
diff --git a/gnu/usr.bin/perl/misc/c2ph.1 b/gnu/usr.bin/perl/misc/c2ph.1
new file mode 100644
index 0000000..316e775
--- /dev/null
+++ b/gnu/usr.bin/perl/misc/c2ph.1
@@ -0,0 +1,191 @@
+Article 484 of comp.lang.perl:
+Xref: netlabs comp.lang.perl:484 comp.lang.c:983 alt.sources:134
+Path: netlabs!psinntp!iggy.GW.Vitalink.COM!lll-winken!sun-barr!cronkite.Central.Sun.COM!spdev!texsun!convex!tchrist
+From: tchrist@convex.com (Tom Christiansen)
+Newsgroups: comp.lang.perl,comp.lang.c,alt.sources
+Subject: pstruct -- a C structure formatter; AKA c2ph, a C to perl header translator
+Keywords: C perl tranlator
+Message-ID: <1991Jul25.081021.8104@convex.com>
+Date: 25 Jul 91 08:10:21 GMT
+Sender: usenet@convex.com (news access account)
+Followup-To: comp.lang.perl
+Organization: CONVEX Computer Corporation, Richardson, Tx., USA
+Lines: 1208
+Nntp-Posting-Host: pixel.convex.com
+
+Once upon a time, I wrote a program called pstruct. It was a perl
+program that tried to parse out C structures and display their member
+offsets for you. This was especially useful for people looking at
+binary dumps or poking around the kernel.
+
+Pstruct was not a pretty program. Neither was it particularly robust.
+The problem, you see, was that the C compiler was much better at parsing
+C than I could ever hope to be.
+
+So I got smart: I decided to be lazy and let the C compiler parse the C,
+which would spit out debugger stabs for me to read. These were much
+easier to parse. It's still not a pretty program, but at least it's more
+robust.
+
+Pstruct takes any .c or .h files, or preferably .s ones, since that's
+the format it is going to massage them into anyway, and spits out
+listings like this:
+
+struct tty {
+ int tty.t_locker 000 4
+ int tty.t_mutex_index 004 4
+ struct tty * tty.t_tp_virt 008 4
+ struct clist tty.t_rawq 00c 20
+ int tty.t_rawq.c_cc 00c 4
+ int tty.t_rawq.c_cmax 010 4
+ int tty.t_rawq.c_cfx 014 4
+ int tty.t_rawq.c_clx 018 4
+ struct tty * tty.t_rawq.c_tp_cpu 01c 4
+ struct tty * tty.t_rawq.c_tp_iop 020 4
+ unsigned char * tty.t_rawq.c_buf_cpu 024 4
+ unsigned char * tty.t_rawq.c_buf_iop 028 4
+ struct clist tty.t_canq 02c 20
+ int tty.t_canq.c_cc 02c 4
+ int tty.t_canq.c_cmax 030 4
+ int tty.t_canq.c_cfx 034 4
+ int tty.t_canq.c_clx 038 4
+ struct tty * tty.t_canq.c_tp_cpu 03c 4
+ struct tty * tty.t_canq.c_tp_iop 040 4
+ unsigned char * tty.t_canq.c_buf_cpu 044 4
+ unsigned char * tty.t_canq.c_buf_iop 048 4
+ struct clist tty.t_outq 04c 20
+ int tty.t_outq.c_cc 04c 4
+ int tty.t_outq.c_cmax 050 4
+ int tty.t_outq.c_cfx 054 4
+ int tty.t_outq.c_clx 058 4
+ struct tty * tty.t_outq.c_tp_cpu 05c 4
+ struct tty * tty.t_outq.c_tp_iop 060 4
+ unsigned char * tty.t_outq.c_buf_cpu 064 4
+ unsigned char * tty.t_outq.c_buf_iop 068 4
+ (*int)() tty.t_oproc_cpu 06c 4
+ (*int)() tty.t_oproc_iop 070 4
+ (*int)() tty.t_stopproc_cpu 074 4
+ (*int)() tty.t_stopproc_iop 078 4
+ struct thread * tty.t_rsel 07c 4
+
+ etc.
+
+
+Actually, this was generated by a particular set of options. You can control
+the formatting of each column, whether you prefer wide or fat, hex or decimal,
+leading zeroes or whatever.
+
+All you need to be able to use this is a C compiler than generates
+BSD/GCC-style stabs. The -g option on native BSD compilers and GCC
+should get this for you.
+
+To learn more, just type a bogus option, like -\?, and a long usage message
+will be provided. There are a fair number of possibilities.
+
+If you're only a C programmer, than this is the end of the message for you.
+You can quit right now, and if you care to, save off the source and run it
+when you feel like it. Or not.
+
+
+
+But if you're a perl programmer, then for you I have something much more
+wondrous than just a structure offset printer.
+
+You see, if you call pstruct by its other incybernation, c2ph, you have a code
+generator that translates C code into perl code! Well, structure and union
+declarations at least, but that's quite a bit.
+
+Prior to this point, anyone programming in perl who wanted to interact
+with C programs, like the kernel, was forced to guess the layouts of the C
+strutures, and then hardwire these into his program. Of course, when you
+took your wonderfully to a system where the sgtty structure was laid out
+differently, you program broke. Which is a shame.
+
+We've had Larry's h2ph translator, which helped, but that only works on
+cpp symbols, not real C, which was also very much needed. What I offer
+you is a symbolic way of getting at all the C structures. I've couched
+them in terms of packages and functions. Consider the following program:
+
+ #!/usr/bin/perl
+
+ require 'syscall.ph';
+ require 'sys/time.ph';
+ require 'sys/resource.ph';
+
+ $ru = "\0" x &rusage'sizeof();
+
+ syscall(&SYS_getrusage, &RUSAGE_SELF, $ru) && die "getrusage: $!";
+
+ @ru = unpack($t = &rusage'typedef(), $ru);
+
+ $utime = $ru[ &rusage'ru_utime + &timeval'tv_sec ]
+ + ($ru[ &rusage'ru_utime + &timeval'tv_usec ]) / 1e6;
+
+ $stime = $ru[ &rusage'ru_stime + &timeval'tv_sec ]
+ + ($ru[ &rusage'ru_stime + &timeval'tv_usec ]) / 1e6;
+
+ printf "you have used %8.3fs+%8.3fu seconds.\n", $utime, $stime;
+
+
+As you see, the name of the package is the name of the structure. Regular
+fields are just their own names. Plus the follwoing accessor functions are
+provided for your convenience:
+
+ struct This takes no arguments, and is merely the number of first-level
+ elements in the structure. You would use this for indexing
+ into arrays of structures, perhaps like this
+
+
+ $usec = $u[ &user'u_utimer
+ + (&ITIMER_VIRTUAL * &itimerval'struct)
+ + &itimerval'it_value
+ + &timeval'tv_usec
+ ];
+
+ sizeof Returns the bytes in the structure, or the member if
+ you pass it an argument, such as
+
+ &rusage'sizeof(&rusage'ru_utime)
+
+ typedef This is the perl format definition for passing to pack and
+ unpack. If you ask for the typedef of a nothing, you get
+ the whole structure, otherwise you get that of the member
+ you ask for. Padding is taken care of, as is the magic to
+ guarantee that a union is unpacked into all its aliases.
+ Bitfields are not quite yet supported however.
+
+ offsetof This function is the byte offset into the array of that
+ member. You may wish to use this for indexing directly
+ into the packed structure with vec() if you're too lazy
+ to unpack it.
+
+ typeof Not to be confused with the typedef accessor function, this
+ one returns the C type of that field. This would allow
+ you to print out a nice structured pretty print of some
+ structure without knoning anything about it beforehand.
+ No args to this one is a noop. Someday I'll post such
+ a thing to dump out your u structure for you.
+
+
+The way I see this being used is like basically this:
+
+ % h2ph <some_include_file.h > /usr/lib/perl/tmp.ph
+ % c2ph some_include_file.h >> /usr/lib/perl/tmp.ph
+ % install
+
+It's a little tricker with c2ph because you have to get the includes right.
+I can't know this for your system, but it's not usually too terribly difficult.
+
+The code isn't pretty as I mentioned -- I never thought it would be a 1000-
+line program when I started, or I might not have begun. :-) But I would have
+been less cavalier in how the parts of the program communicated with each
+other, etc. It might also have helped if I didn't have to divine the makeup
+of the stabs on the fly, and then account for micro differences between my
+compiler and gcc.
+
+Anyway, here it is. Should run on perl v4 or greater. Maybe less.
+
+
+--tom
+
+
diff --git a/gnu/usr.bin/perl/misc/pstruct b/gnu/usr.bin/perl/misc/pstruct
new file mode 100644
index 0000000..5dfea04
--- /dev/null
+++ b/gnu/usr.bin/perl/misc/pstruct
@@ -0,0 +1,1071 @@
+#!/usr/bin/perl
+#
+#
+# c2ph (aka pstruct)
+# Tom Christiansen, <tchrist@convex.com>
+#
+# As pstruct, dump C structures as generated from 'cc -g -S' stabs.
+# As c2ph, do this PLUS generate perl code for getting at the structures.
+#
+# See the usage message for more. If this isn't enough, read the code.
+#
+
+$RCSID = '$RCSfile: pstruct,v $$Revision: 1.1.1.1 $$Date: 1994/09/10 06:27:31 $';
+
+
+######################################################################
+
+# some handy data definitions. many of these can be reset later.
+
+$bitorder = 'b'; # ascending; set to B for descending bit fields
+
+%intrinsics =
+%template = (
+ 'char', 'c',
+ 'unsigned char', 'C',
+ 'short', 's',
+ 'short int', 's',
+ 'unsigned short', 'S',
+ 'unsigned short int', 'S',
+ 'short unsigned int', 'S',
+ 'int', 'i',
+ 'unsigned int', 'I',
+ 'long', 'l',
+ 'long int', 'l',
+ 'unsigned long', 'L',
+ 'unsigned long', 'L',
+ 'long unsigned int', 'L',
+ 'unsigned long int', 'L',
+ 'long long', 'q',
+ 'long long int', 'q',
+ 'unsigned long long', 'Q',
+ 'unsigned long long int', 'Q',
+ 'float', 'f',
+ 'double', 'd',
+ 'pointer', 'p',
+ 'null', 'x',
+ 'neganull', 'X',
+ 'bit', $bitorder,
+);
+
+&buildscrunchlist;
+delete $intrinsics{'neganull'};
+delete $intrinsics{'bit'};
+delete $intrinsics{'null'};
+
+# use -s to recompute sizes
+%sizeof = (
+ 'char', '1',
+ 'unsigned char', '1',
+ 'short', '2',
+ 'short int', '2',
+ 'unsigned short', '2',
+ 'unsigned short int', '2',
+ 'short unsigned int', '2',
+ 'int', '4',
+ 'unsigned int', '4',
+ 'long', '4',
+ 'long int', '4',
+ 'unsigned long', '4',
+ 'unsigned long int', '4',
+ 'long unsigned int', '4',
+ 'long long', '8',
+ 'long long int', '8',
+ 'unsigned long long', '8',
+ 'unsigned long long int', '8',
+ 'float', '4',
+ 'double', '8',
+ 'pointer', '4',
+);
+
+($type_width, $member_width, $offset_width, $size_width) = (20, 20, 6, 5);
+
+($offset_fmt, $size_fmt) = ('d', 'd');
+
+$indent = 2;
+
+$CC = 'cc';
+$CFLAGS = '-g -S';
+$DEFINES = '';
+
+$perl++ if $0 =~ m#/?c2ph$#;
+
+require 'getopts.pl';
+
+eval '$'.$1.'$2;' while $ARGV[0] =~ /^([A-Za-z_]+=)(.*)/ && shift;
+
+&Getopts('aixdpvtnws:') || &usage(0);
+
+$opt_d && $debug++;
+$opt_t && $trace++;
+$opt_p && $perl++;
+$opt_v && $verbose++;
+$opt_n && ($perl = 0);
+
+if ($opt_w) {
+ ($type_width, $member_width, $offset_width) = (45, 35, 8);
+}
+if ($opt_x) {
+ ($offset_fmt, $offset_width, $size_fmt, $size_width) = ( 'x', '08', 'x', 04 );
+}
+
+eval '$'.$1.'$2;' while $ARGV[0] =~ /^([A-Za-z_]+=)(.*)/ && shift;
+
+sub PLUMBER {
+ select(STDERR);
+ print "oops, apperent pager foulup\n";
+ $isatty++;
+ &usage(1);
+}
+
+sub usage {
+ local($oops) = @_;
+ unless (-t STDOUT) {
+ select(STDERR);
+ } elsif (!$oops) {
+ $isatty++;
+ $| = 1;
+ print "hit <RETURN> for further explanation: ";
+ <STDIN>;
+ open (PIPE, "|". ($ENV{PAGER} || 'more'));
+ $SIG{PIPE} = PLUMBER;
+ select(PIPE);
+ }
+
+ print "usage: $0 [-dpnP] [var=val] [files ...]\n";
+
+ exit unless $isatty;
+
+ print <<EOF;
+
+Options:
+
+-w wide; short for: type_width=45 member_width=35 offset_width=8
+-x hex; short for: offset_fmt=x offset_width=08 size_fmt=x size_width=04
+
+-n do not generate perl code (default when invoked as pstruct)
+-p generate perl code (default when invoked as c2ph)
+-v generate perl code, with C decls as comments
+
+-i do NOT recompute sizes for intrinsic datatypes
+-a dump information on intrinsics also
+
+-t trace execution
+-d spew reams of debugging output
+
+-slist give comma-separated list a structures to dump
+
+
+Var Name Default Value Meaning
+
+EOF
+
+ &defvar('CC', 'which_compiler to call');
+ &defvar('CFLAGS', 'how to generate *.s files with stabs');
+ &defvar('DEFINES','any extra cflags or cpp defines, like -I, -D, -U');
+
+ print "\n";
+
+ &defvar('type_width', 'width of type field (column 1)');
+ &defvar('member_width', 'width of member field (column 2)');
+ &defvar('offset_width', 'width of offset field (column 3)');
+ &defvar('size_width', 'width of size field (column 4)');
+
+ print "\n";
+
+ &defvar('offset_fmt', 'sprintf format type for offset');
+ &defvar('size_fmt', 'sprintf format type for size');
+
+ print "\n";
+
+ &defvar('indent', 'how far to indent each nesting level');
+
+ print <<'EOF';
+
+ If any *.[ch] files are given, these will be catted together into
+ a temporary *.c file and sent through:
+ $CC $CFLAGS $DEFINES
+ and the resulting *.s groped for stab information. If no files are
+ supplied, then stdin is read directly with the assumption that it
+ contains stab information. All other liens will be ignored. At
+ most one *.s file should be supplied.
+
+EOF
+ close PIPE;
+ exit 1;
+}
+
+sub defvar {
+ local($var, $msg) = @_;
+ printf "%-16s%-15s %s\n", $var, eval "\$$var", $msg;
+}
+
+$recurse = 1;
+
+if (@ARGV) {
+ if (grep(!/\.[csh]$/,@ARGV)) {
+ warn "Only *.[csh] files expected!\n";
+ &usage;
+ }
+ elsif (grep(/\.s$/,@ARGV)) {
+ if (@ARGV > 1) {
+ warn "Only one *.s file allowed!\n";
+ &usage;
+ }
+ }
+ elsif (@ARGV == 1 && $ARGV[0] =~ /\.c$/) {
+ local($dir, $file) = $ARGV[0] =~ m#(.*/)?(.*)$#;
+ $chdir = "cd $dir; " if $dir;
+ &system("$chdir$CC $CFLAGS $DEFINES $file") && exit 1;
+ $ARGV[0] =~ s/\.c$/.s/;
+ }
+ else {
+ $TMP = "/tmp/c2ph.$$.c";
+ &system("cat @ARGV > $TMP") && exit 1;
+ &system("cd /tmp; $CC $CFLAGS $DEFINES $TMP") && exit 1;
+ unlink $TMP;
+ $TMP =~ s/\.c$/.s/;
+ @ARGV = ($TMP);
+ }
+}
+
+if ($opt_s) {
+ for (split(/[\s,]+/, $opt_s)) {
+ $interested{$_}++;
+ }
+}
+
+
+$| = 1 if $debug;
+
+main: {
+
+ if ($trace) {
+ if (-t && !@ARGV) {
+ print STDERR "reading from your keyboard: ";
+ } else {
+ print STDERR "reading from " . (@ARGV ? "@ARGV" : "<STDIN>").": ";
+ }
+ }
+
+STAB: while (<>) {
+ if ($trace && !($. % 10)) {
+ $lineno = $..'';
+ print STDERR $lineno, "\b" x length($lineno);
+ }
+ next unless /^\s*\.stabs\s+/;
+ $line = $_;
+ s/^\s*\.stabs\s+//;
+ &stab;
+ }
+ print STDERR "$.\n" if $trace;
+ unlink $TMP if $TMP;
+
+ &compute_intrinsics if $perl && !$opt_i;
+
+ print STDERR "resolving types\n" if $trace;
+
+ &resolve_types;
+ &adjust_start_addrs;
+
+ $sum = 2 + $type_width + $member_width;
+ $pmask1 = "%-${type_width}s %-${member_width}s";
+ $pmask2 = "%-${sum}s %${offset_width}${offset_fmt}%s %${size_width}${size_fmt}%s";
+
+ if ($perl) {
+ # resolve template -- should be in stab define order, but even this isn't enough.
+ print STDERR "\nbuilding type templates: " if $trace;
+ for $i (reverse 0..$#type) {
+ next unless defined($name = $type[$i]);
+ next unless defined $struct{$name};
+ $build_recursed = 0;
+ &build_template($name) unless defined $template{&psou($name)} ||
+ $opt_s && !$interested{$name};
+ }
+ print STDERR "\n\n" if $trace;
+ }
+
+ print STDERR "dumping structs: " if $trace;
+
+
+ foreach $name (sort keys %struct) {
+ next if $opt_s && !$interested{$name};
+ print STDERR "$name " if $trace;
+
+ undef @sizeof;
+ undef @typedef;
+ undef @offsetof;
+ undef @indices;
+ undef @typeof;
+
+ $mname = &munge($name);
+
+ $fname = &psou($name);
+
+ print "# " if $perl && $verbose;
+ $pcode = '';
+ print "$fname {\n" if !$perl || $verbose;
+ $template{$fname} = &scrunch($template{$fname}) if $perl;
+ &pstruct($name,$name,0);
+ print "# " if $perl && $verbose;
+ print "}\n" if !$perl || $verbose;
+ print "\n" if $perl && $verbose;
+
+ if ($perl) {
+ print "$pcode";
+
+ printf("\nsub %-32s { %4d; }\n\n", "${mname}'struct", $countof{$name});
+
+ print <<EOF;
+sub ${mname}'typedef {
+ local(\$${mname}'index) = shift;
+ defined \$${mname}'index
+ ? \$${mname}'typedef[\$${mname}'index]
+ : \$${mname}'typedef;
+}
+EOF
+
+ print <<EOF;
+sub ${mname}'sizeof {
+ local(\$${mname}'index) = shift;
+ defined \$${mname}'index
+ ? \$${mname}'sizeof[\$${mname}'index]
+ : \$${mname}'sizeof;
+}
+EOF
+
+ print <<EOF;
+sub ${mname}'offsetof {
+ local(\$${mname}'index) = shift;
+ defined \$${mname}index
+ ? \$${mname}'offsetof[\$${mname}'index]
+ : \$${mname}'sizeof;
+}
+EOF
+
+ print <<EOF;
+sub ${mname}'typeof {
+ local(\$${mname}'index) = shift;
+ defined \$${mname}index
+ ? \$${mname}'typeof[\$${mname}'index]
+ : '$name';
+}
+EOF
+
+
+ print "\$${mname}'typedef = '" . &scrunch($template{$fname})
+ . "';\n";
+
+ print "\$${mname}'sizeof = $sizeof{$name};\n\n";
+
+
+ print "\@${mname}'indices = (", &squishseq(@indices), ");\n";
+
+ print "\n";
+
+ print "\@${mname}'typedef[\@${mname}'indices] = (",
+ join("\n\t", '', @typedef), "\n );\n\n";
+ print "\@${mname}'sizeof[\@${mname}'indices] = (",
+ join("\n\t", '', @sizeof), "\n );\n\n";
+ print "\@${mname}'offsetof[\@${mname}'indices] = (",
+ join("\n\t", '', @offsetof), "\n );\n\n";
+ print "\@${mname}'typeof[\@${mname}'indices] = (",
+ join("\n\t", '', @typeof), "\n );\n\n";
+
+ $template_printed{$fname}++;
+ $size_printed{$fname}++;
+ }
+ print "\n";
+ }
+
+ print STDERR "\n" if $trace;
+
+ unless ($perl && $opt_a) {
+ print "\n1;\n";
+ exit;
+ }
+
+
+
+ foreach $name (sort bysizevalue keys %intrinsics) {
+ next if $size_printed{$name};
+ print '$',&munge($name),"'sizeof = ", $sizeof{$name}, ";\n";
+ }
+
+ print "\n";
+
+ sub bysizevalue { $sizeof{$a} <=> $sizeof{$b}; }
+
+
+ foreach $name (sort keys %intrinsics) {
+ print '$',&munge($name),"'typedef = '", $template{$name}, "';\n";
+ }
+
+ print "\n1;\n";
+
+ exit;
+}
+
+########################################################################################
+
+
+sub stab {
+ next unless /:[\$\w]+(\(\d+,\d+\))?=[\*\$\w]+/; # (\d+,\d+) is for sun
+ s/"// || next;
+ s/",([x\d]+),([x\d]+),([x\d]+),.*// || next;
+
+ next if /^\s*$/;
+
+ $size = $3 if $3;
+
+
+ $line = $_;
+
+ if (($name, $pdecl) = /^([\$ \w]+):[tT]((\d+)(=[rufs*](\d+))+)$/) {
+ print "$name is a typedef for some funky pointers: $pdecl\n" if $debug;
+ &pdecl($pdecl);
+ next;
+ }
+
+
+
+ if (/(([ \w]+):t(\d+|\(\d+,\d+\)))=r?(\d+|\(\d+,\d+\))(;\d+;\d+;)?/) {
+ local($ident) = $2;
+ push(@intrinsics, $ident);
+ $typeno = &typeno($3);
+ $type[$typeno] = $ident;
+ print STDERR "intrinsic $ident in new type $typeno\n" if $debug;
+ next;
+ }
+
+ if (($name, $typeordef, $typeno, $extra, $struct, $_)
+ = /^([\$ \w]+):([ustT])(\d+|\(\d+,\d+\))(=[rufs*](\d+))?(.*)$/)
+ {
+ $typeno = &typeno($typeno); # sun foolery
+ }
+ elsif (/^[\$\w]+:/) {
+ next; # variable
+ }
+ else {
+ warn "can't grok stab: <$_> in: $line " if $_;
+ next;
+ }
+
+ #warn "got size $size for $name\n";
+ $sizeof{$name} = $size if $size;
+
+ s/;[-\d]*;[-\d]*;$//; # we don't care about ranges
+
+ $typenos{$name} = $typeno;
+
+ unless (defined $type[$typeno]) {
+ &panic("type 0??") unless $typeno;
+ $type[$typeno] = $name unless defined $type[$typeno];
+ printf "new type $typeno is $name" if $debug;
+ if ($extra =~ /\*/ && defined $type[$struct]) {
+ print ", a typedef for a pointer to " , $type[$struct] if $debug;
+ }
+ } else {
+ printf "%s is type %d", $name, $typeno if $debug;
+ print ", a typedef for " , $type[$typeno] if $debug;
+ }
+ print "\n" if $debug;
+ #next unless $extra =~ /[su*]/;
+
+ #$type[$struct] = $name;
+
+ if ($extra =~ /[us*]/) {
+ &sou($name, $extra);
+ $_ = &sdecl($name, $_, 0);
+ }
+ elsif (/^=ar/) {
+ print "it's a bare array typedef -- that's pretty sick\n" if $debug;
+ $_ = "$typeno$_";
+ $scripts = '';
+ $_ = &adecl($_,1);
+
+ }
+ elsif (s/((\w+):t(\d+|\(\d+,\d+\)))?=r?(;\d+;\d+;)?//) { # the ?'s are for gcc
+ push(@intrinsics, $2);
+ $typeno = &typeno($3);
+ $type[$typeno] = $2;
+ print STDERR "intrinsic $2 in new type $typeno\n" if $debug;
+ }
+ elsif (s/^=e//) { # blessed by thy compiler; mine won't do this
+ &edecl;
+ }
+ else {
+ warn "Funny remainder for $name on line $_ left in $line " if $_;
+ }
+}
+
+sub typeno { # sun thinks types are (0,27) instead of just 27
+ local($_) = @_;
+ s/\(\d+,(\d+)\)/$1/;
+ $_;
+}
+
+sub pstruct {
+ local($what,$prefix,$base) = @_;
+ local($field, $fieldname, $typeno, $count, $offset, $entry);
+ local($fieldtype);
+ local($type, $tname);
+ local($mytype, $mycount, $entry2);
+ local($struct_count) = 0;
+ local($pad, $revpad, $length, $prepad, $lastoffset, $lastlength, $fmt);
+ local($bits,$bytes);
+ local($template);
+
+
+ local($mname) = &munge($name);
+
+ sub munge {
+ local($_) = @_;
+ s/[\s\$\.]/_/g;
+ $_;
+ }
+
+ local($sname) = &psou($what);
+
+ $nesting++;
+
+ for $field (split(/;/, $struct{$what})) {
+ $pad = $prepad = 0;
+ $entry = '';
+ ($fieldname, $typeno, $count, $offset, $length) = split(/,/, $field);
+
+ $type = $type[$typeno];
+
+ $type =~ /([^[]*)(\[.*\])?/;
+ $mytype = $1;
+ $count .= $2;
+ $fieldtype = &psou($mytype);
+
+ local($fname) = &psou($name);
+
+ if ($build_templates) {
+
+ $pad = ($offset - ($lastoffset + $lastlength))/8
+ if defined $lastoffset;
+
+ if (! $finished_template{$sname}) {
+ if ($isaunion{$what}) {
+ $template{$sname} .= 'X' x $revpad . ' ' if $revpad;
+ } else {
+ $template{$sname} .= 'x' x $pad . ' ' if $pad;
+ }
+ }
+
+ $template = &fetch_template($type) x
+ ($count ? &scripts2count($count) : 1);
+
+ if (! $finished_template{$sname}) {
+ $template{$sname} .= $template;
+ }
+
+ $revpad = $length/8 if $isaunion{$what};
+
+ ($lastoffset, $lastlength) = ($offset, $length);
+
+ } else {
+ print '# ' if $perl && $verbose;
+ $entry = sprintf($pmask1,
+ ' ' x ($nesting * $indent) . $fieldtype,
+ "$prefix.$fieldname" . $count);
+
+ $entry =~ s/(\*+)( )/$2$1/;
+
+ printf $pmask2,
+ $entry,
+ ($base+$offset)/8,
+ ($bits = ($base+$offset)%8) ? ".$bits" : " ",
+ $length/8,
+ ($bits = $length % 8) ? ".$bits": ""
+ if !$perl || $verbose;
+
+
+ if ($perl && $nesting == 1) {
+ $template = &scrunch(&fetch_template($type) x
+ ($count ? &scripts2count($count) : 1));
+ push(@sizeof, int($length/8) .",\t# $fieldname");
+ push(@offsetof, int($offset/8) .",\t# $fieldname");
+ push(@typedef, "'$template', \t# $fieldname");
+ $type =~ s/(struct|union) //;
+ push(@typeof, "'$type" . ($count ? $count : '') .
+ "',\t# $fieldname");
+ }
+
+ print ' ', ' ' x $indent x $nesting, $template
+ if $perl && $verbose;
+
+ print "\n" if !$perl || $verbose;
+
+ }
+ if ($perl) {
+ local($mycount) = defined $struct{$mytype} ? $countof{$mytype} : 1;
+ $mycount *= &scripts2count($count) if $count;
+ if ($nesting==1 && !$build_templates) {
+ $pcode .= sprintf("sub %-32s { %4d; }\n",
+ "${mname}'${fieldname}", $struct_count);
+ push(@indices, $struct_count);
+ }
+ $struct_count += $mycount;
+ }
+
+
+ &pstruct($type, "$prefix.$fieldname", $base+$offset)
+ if $recurse && defined $struct{$type};
+ }
+
+ $countof{$what} = $struct_count unless defined $countof{$whati};
+
+ $template{$sname} .= '$' if $build_templates;
+ $finished_template{$sname}++;
+
+ if ($build_templates && !defined $sizeof{$name}) {
+ local($fmt) = &scrunch($template{$sname});
+ print STDERR "no size for $name, punting with $fmt..." if $debug;
+ eval '$sizeof{$name} = length(pack($fmt, ()))';
+ if ($@) {
+ chop $@;
+ warn "couldn't get size for \$name: $@";
+ } else {
+ print STDERR $sizeof{$name}, "\n" if $debUg;
+ }
+ }
+
+ --$nesting;
+}
+
+
+sub psize {
+ local($me) = @_;
+ local($amstruct) = $struct{$me} ? 'struct ' : '';
+
+ print '$sizeof{\'', $amstruct, $me, '\'} = ';
+ printf "%d;\n", $sizeof{$me};
+}
+
+sub pdecl {
+ local($pdecl) = @_;
+ local(@pdecls);
+ local($tname);
+
+ warn "pdecl: $pdecl\n" if $debug;
+
+ $pdecl =~ s/\(\d+,(\d+)\)/$1/g;
+ $pdecl =~ s/\*//g;
+ @pdecls = split(/=/, $pdecl);
+ $typeno = $pdecls[0];
+ $tname = pop @pdecls;
+
+ if ($tname =~ s/^f//) { $tname = "$tname&"; }
+ #else { $tname = "$tname*"; }
+
+ for (reverse @pdecls) {
+ $tname .= s/^f// ? "&" : "*";
+ #$tname =~ s/^f(.*)/$1&/;
+ print "type[$_] is $tname\n" if $debug;
+ $type[$_] = $tname unless defined $type[$_];
+ }
+}
+
+
+
+sub adecl {
+ ($arraytype, $unknown, $lower, $upper) = ();
+ #local($typeno);
+ # global $typeno, @type
+ local($_, $typedef) = @_;
+
+ while (s/^((\d+)=)?ar(\d+);//) {
+ ($arraytype, $unknown) = ($2, $3);
+ if (s/^(\d+);(\d+);//) {
+ ($lower, $upper) = ($1, $2);
+ $scripts .= '[' . ($upper+1) . ']';
+ } else {
+ warn "can't find array bounds: $_";
+ }
+ }
+ if (s/^([\d*f=]*),(\d+),(\d+);//) {
+ ($start, $length) = ($2, $3);
+ local($whatis) = $1;
+ if ($whatis =~ /^(\d+)=/) {
+ $typeno = $1;
+ &pdecl($whatis);
+ } else {
+ $typeno = $whatis;
+ }
+ } elsif (s/^(\d+)(=[*suf]\d*)//) {
+ local($whatis) = $2;
+
+ if ($whatis =~ /[f*]/) {
+ &pdecl($whatis);
+ } elsif ($whatis =~ /[su]/) { #
+ print "$prefix.$fieldname is an array$scripts anon structs; disgusting\n"
+ if $debug;
+ #$type[$typeno] = $name unless defined $type[$typeno];
+ ##printf "new type $typeno is $name" if $debug;
+ $typeno = $1;
+ $type[$typeno] = "$prefix.$fieldname";
+ local($name) = $type[$typeno];
+ &sou($name, $whatis);
+ $_ = &sdecl($name, $_, $start+$offset);
+ 1;
+ $start = $start{$name};
+ $offset = $sizeof{$name};
+ $length = $offset;
+ } else {
+ warn "what's this? $whatis in $line ";
+ }
+ } elsif (/^\d+$/) {
+ $typeno = $_;
+ } else {
+ warn "bad array stab: $_ in $line ";
+ next STAB;
+ }
+ #local($wasdef) = defined($type[$typeno]) && $debug;
+ #if ($typedef) {
+ #print "redefining $type[$typeno] to " if $wasdef;
+ #$type[$typeno] = "$whatis$scripts"; # unless defined $type[$typeno];
+ #print "$type[$typeno]\n" if $wasdef;
+ #} else {
+ #$type[$arraytype] = $type[$typeno] unless defined $type[$arraytype];
+ #}
+ $type[$arraytype] = "$type[$typeno]$scripts" if defined $type[$typeno];
+ print "type[$arraytype] is $type[$arraytype]\n" if $debug;
+ print "$prefix.$fieldname is an array of $type[$arraytype]\n" if $debug;
+ $_;
+}
+
+
+
+sub sdecl {
+ local($prefix, $_, $offset) = @_;
+
+ local($fieldname, $scripts, $type, $arraytype, $unknown,
+ $whatis, $pdecl, $upper,$lower, $start,$length) = ();
+ local($typeno,$sou);
+
+
+SFIELD:
+ while (/^([^;]+);/) {
+ $scripts = '';
+ warn "sdecl $_\n" if $debug;
+ if (s/^([\$\w]+)://) {
+ $fieldname = $1;
+ } elsif (s/(\d+)=([us])(\d+|\(\d+,\d+\))//) { #
+ $typeno = &typeno($1);
+ $type[$typeno] = "$prefix.$fieldname";
+ local($name) = "$prefix.$fieldname";
+ &sou($name,$2);
+ $_ = &sdecl("$prefix.$fieldname", $_, $start+$offset);
+ $start = $start{$name};
+ $offset += $sizeof{$name};
+ #print "done with anon, start is $start, offset is $offset\n";
+ #next SFIELD;
+ } else {
+ warn "weird field $_ of $line" if $debug;
+ next STAB;
+ #$fieldname = &gensym;
+ #$_ = &sdecl("$prefix.$fieldname", $_, $start+$offset);
+ }
+
+ if (/^\d+=ar/) {
+ $_ = &adecl($_);
+ }
+ elsif (s/^(\d+|\(\d+,\d+\))?,(\d+),(\d+);//) {
+ ($start, $length) = ($2, $3);
+ &panic("no length?") unless $length;
+ $typeno = &typeno($1) if $1;
+ }
+ elsif (s/^((\d+|\(\d+,\d+\))(=[*f](\d+|\(\d+,\d+\)))+),(\d+),(\d+);//) {
+ ($pdecl, $start, $length) = ($1,$5,$6);
+ &pdecl($pdecl);
+ }
+ elsif (s/(\d+)=([us])(\d+|\(\d+,\d+\))//) { # the dratted anon struct
+ ($typeno, $sou) = ($1, $2);
+ $typeno = &typeno($typeno);
+ if (defined($type[$typeno])) {
+ warn "now how did we get type $1 in $fieldname of $line?";
+ } else {
+ print "anon type $typeno is $prefix.$fieldname\n" if $debug;
+ $type[$typeno] = "$prefix.$fieldname" unless defined $type[$typeno];
+ };
+ local($name) = "$prefix.$fieldname";
+ &sou($name,$sou);
+ print "anon ".($isastruct{$name}) ? "struct":"union"." for $prefix.$fieldname\n" if $debug;
+ $type[$typeno] = "$prefix.$fieldname";
+ $_ = &sdecl("$prefix.$fieldname", $_, $start+$offset);
+ $start = $start{$name};
+ $length = $sizeof{$name};
+ }
+ else {
+ warn "can't grok stab for $name ($_) in line $line ";
+ next STAB;
+ }
+
+ &panic("no length for $prefix.$fieldname") unless $length;
+ $struct{$name} .= join(',', $fieldname, $typeno, $scripts, $start, $length) . ';';
+ }
+ if (s/;\d*,(\d+),(\d+);//) {
+ local($start, $size) = ($1, $2);
+ $sizeof{$prefix} = $size;
+ print "start of $prefix is $start, size of $sizeof{$prefix}\n" if $debug;
+ $start{$prefix} = $start;
+ }
+ $_;
+}
+
+sub edecl {
+ s/;$//;
+ $enum{$name} = $_;
+ $_ = '';
+}
+
+sub resolve_types {
+ local($sou);
+ for $i (0 .. $#type) {
+ next unless defined $type[$i];
+ $_ = $type[$i];
+ unless (/\d/) {
+ print "type[$i] $type[$i]\n" if $debug;
+ next;
+ }
+ print "type[$i] $_ ==> " if $debug;
+ s/^(\d+)(\**)\&\*(\**)/"$2($3".&type($1) . ')()'/e;
+ s/^(\d+)\&/&type($1)/e;
+ s/^(\d+)/&type($1)/e;
+ s/(\*+)([^*]+)(\*+)/$1$3$2/;
+ s/\((\*+)(\w+)(\*+)\)/$3($1$2)/;
+ s/^(\d+)([\*\[].*)/&type($1).$2/e;
+ #s/(\d+)(\*|(\[[\[\]\d\*]+]\])+)/&type($1).$2/ge;
+ $type[$i] = $_;
+ print "$_\n" if $debug;
+ }
+}
+sub type { &psou($type[$_[0]] || "<UNDEFINED>"); }
+
+sub adjust_start_addrs {
+ for (sort keys %start) {
+ ($basename = $_) =~ s/\.[^.]+$//;
+ $start{$_} += $start{$basename};
+ print "start: $_ @ $start{$_}\n" if $debug;
+ }
+}
+
+sub sou {
+ local($what, $_) = @_;
+ /u/ && $isaunion{$what}++;
+ /s/ && $isastruct{$what}++;
+}
+
+sub psou {
+ local($what) = @_;
+ local($prefix) = '';
+ if ($isaunion{$what}) {
+ $prefix = 'union ';
+ } elsif ($isastruct{$what}) {
+ $prefix = 'struct ';
+ }
+ $prefix . $what;
+}
+
+sub scrunch {
+ local($_) = @_;
+
+ study;
+
+ s/\$//g;
+ s/ / /g;
+ 1 while s/(\w) \1/$1$1/g;
+
+ # i wanna say this, but perl resists my efforts:
+ # s/(\w)(\1+)/$2 . length($1)/ge;
+
+ &quick_scrunch;
+
+ s/ $//;
+
+ $_;
+}
+
+sub buildscrunchlist {
+ $scrunch_code = "sub quick_scrunch {\n";
+ for (values %intrinsics) {
+ $scrunch_code .= "\ts/($_{2,})/'$_' . length(\$1)/ge;\n";
+ }
+ $scrunch_code .= "}\n";
+ print "$scrunch_code" if $debug;
+ eval $scrunch_code;
+ &panic("can't eval scrunch_code $@ \nscrunch_code") if $@;
+}
+
+sub fetch_template {
+ local($mytype) = @_;
+ local($fmt);
+ local($count) = 1;
+
+ &panic("why do you care?") unless $perl;
+
+ if ($mytype =~ s/(\[\d+\])+$//) {
+ $count .= $1;
+ }
+
+ if ($mytype =~ /\*/) {
+ $fmt = $template{'pointer'};
+ }
+ elsif (defined $template{$mytype}) {
+ $fmt = $template{$mytype};
+ }
+ elsif (defined $struct{$mytype}) {
+ if (!defined $template{&psou($mytype)}) {
+ &build_template($mytype) unless $mytype eq $name;
+ }
+ elsif ($template{&psou($mytype)} !~ /\$$/) {
+ #warn "incomplete template for $mytype\n";
+ }
+ $fmt = $template{&psou($mytype)} || '?';
+ }
+ else {
+ warn "unknown fmt for $mytype\n";
+ $fmt = '?';
+ }
+
+ $fmt x $count . ' ';
+}
+
+sub compute_intrinsics {
+ local($TMP) = "/tmp/c2ph-i.$$.c";
+ open (TMP, ">$TMP") || die "can't open $TMP: $!";
+ select(TMP);
+
+ print STDERR "computing intrinsic sizes: " if $trace;
+
+ undef %intrinsics;
+
+ print <<'EOF';
+main() {
+ char *mask = "%d %s\n";
+EOF
+
+ for $type (@intrinsics) {
+ next if $type eq 'void';
+ print <<"EOF";
+ printf(mask,sizeof($type), "$type");
+EOF
+ }
+
+ print <<'EOF';
+ printf(mask,sizeof(char *), "pointer");
+ exit(0);
+}
+EOF
+ close TMP;
+
+ select(STDOUT);
+ open(PIPE, "cd /tmp && $CC $TMP && /tmp/a.out|");
+ while (<PIPE>) {
+ chop;
+ split(' ',$_,2);;
+ print "intrinsic $_[1] is size $_[0]\n" if $debug;
+ $sizeof{$_[1]} = $_[0];
+ $intrinsics{$_[1]} = $template{$_[0]};
+ }
+ close(PIPE) || die "couldn't read intrinsics!";
+ unlink($TMP, '/tmp/a.out');
+ print STDERR "done\n" if $trace;
+}
+
+sub scripts2count {
+ local($_) = @_;
+
+ s/^\[//;
+ s/\]$//;
+ s/\]\[/*/g;
+ $_ = eval;
+ &panic("$_: $@") if $@;
+ $_;
+}
+
+sub system {
+ print STDERR "@_\n" if $trace;
+ system @_;
+}
+
+sub build_template {
+ local($name) = @_;
+
+ &panic("already got a template for $name") if defined $template{$name};
+
+ local($build_templates) = 1;
+
+ local($lparen) = '(' x $build_recursed;
+ local($rparen) = ')' x $build_recursed;
+
+ print STDERR "$lparen$name$rparen " if $trace;
+ $build_recursed++;
+ &pstruct($name,$name,0);
+ print STDERR "TEMPLATE for $name is ", $template{&psou($name)}, "\n" if $debug;
+ --$build_recursed;
+}
+
+
+sub panic {
+
+ select(STDERR);
+
+ print "\npanic: @_\n";
+
+ exit 1 if $] <= 4.003; # caller broken
+
+ local($i,$_);
+ local($p,$f,$l,$s,$h,$a,@a,@sub);
+ for ($i = 0; ($p,$f,$l,$s,$h,$w) = caller($i); $i++) {
+ @a = @DB'args;
+ for (@a) {
+ if (/^StB\000/ && length($_) == length($_main{'_main'})) {
+ $_ = sprintf("%s",$_);
+ }
+ else {
+ s/'/\\'/g;
+ s/([^\0]*)/'$1'/ unless /^-?[\d.]+$/;
+ s/([\200-\377])/sprintf("M-%c",ord($1)&0177)/eg;
+ s/([\0-\37\177])/sprintf("^%c",ord($1)^64)/eg;
+ }
+ }
+ $w = $w ? '@ = ' : '$ = ';
+ $a = $h ? '(' . join(', ', @a) . ')' : '';
+ push(@sub, "$w&$s$a from file $f line $l\n");
+ last if $signal;
+ }
+ for ($i=0; $i <= $#sub; $i++) {
+ last if $signal;
+ print $sub[$i];
+ }
+ exit 1;
+}
+
+sub squishseq {
+ local($num);
+ local($last) = -1e8;
+ local($string);
+ local($seq) = '..';
+
+ while (defined($num = shift)) {
+ if ($num == ($last + 1)) {
+ $string .= $seq unless $inseq++;
+ $last = $num;
+ next;
+ } elsif ($inseq) {
+ $string .= $last unless $last == -1e8;
+ }
+
+ $string .= ',' if defined $string;
+ $string .= $num;
+ $last = $num;
+ $inseq = 0;
+ }
+ $string .= $last if $inseq && $last != -e18;
+ $string;
+}
diff --git a/gnu/usr.bin/perl/perl/EXTERN.h b/gnu/usr.bin/perl/perl/EXTERN.h
new file mode 100644
index 0000000..fec95bf
--- /dev/null
+++ b/gnu/usr.bin/perl/perl/EXTERN.h
@@ -0,0 +1,29 @@
+/* $RCSfile: EXTERN.h,v $$Revision: 1.1.1.1 $$Date: 1994/09/10 06:27:34 $
+ *
+ * Copyright (c) 1991, Larry Wall
+ *
+ * You may distribute under the terms of either the GNU General Public
+ * License or the Artistic License, as specified in the README file.
+ *
+ * $Log: EXTERN.h,v $
+ * Revision 1.1.1.1 1994/09/10 06:27:34 gclarkii
+ * Initial import of Perl 4.046 bmaked
+ *
+ * Revision 1.1.1.1 1993/08/23 21:29:33 nate
+ * PERL!
+ *
+ * Revision 4.0.1.1 91/06/07 10:10:32 lwall
+ * patch4: new copyright notice
+ *
+ * Revision 4.0 91/03/20 00:58:26 lwall
+ * 4.0 baseline.
+ *
+ */
+
+#undef EXT
+#define EXT extern
+
+#undef INIT
+#define INIT(x)
+
+#undef DOINIT
diff --git a/gnu/usr.bin/perl/perl/INTERN.h b/gnu/usr.bin/perl/perl/INTERN.h
new file mode 100644
index 0000000..d1792d8
--- /dev/null
+++ b/gnu/usr.bin/perl/perl/INTERN.h
@@ -0,0 +1,29 @@
+/* $RCSfile: INTERN.h,v $$Revision: 1.1.1.1 $$Date: 1994/09/10 06:27:34 $
+ *
+ * Copyright (c) 1991, Larry Wall
+ *
+ * You may distribute under the terms of either the GNU General Public
+ * License or the Artistic License, as specified in the README file.
+ *
+ * $Log: INTERN.h,v $
+ * Revision 1.1.1.1 1994/09/10 06:27:34 gclarkii
+ * Initial import of Perl 4.046 bmaked
+ *
+ * Revision 1.1.1.1 1993/08/23 21:29:33 nate
+ * PERL!
+ *
+ * Revision 4.0.1.1 91/06/07 10:10:42 lwall
+ * patch4: new copyright notice
+ *
+ * Revision 4.0 91/03/20 00:58:35 lwall
+ * 4.0 baseline.
+ *
+ */
+
+#undef EXT
+#define EXT
+
+#undef INIT
+#define INIT(x) = x
+
+#define DOINIT
diff --git a/gnu/usr.bin/perl/perl/Makefile b/gnu/usr.bin/perl/perl/Makefile
new file mode 100644
index 0000000..c981ac1
--- /dev/null
+++ b/gnu/usr.bin/perl/perl/Makefile
@@ -0,0 +1,17 @@
+#
+#
+
+PROG= perl
+
+SRCS+= array.c cmd.c cons.c consarg.c doarg.c doio.c dolist.c dump.c
+SRCS+= eval.c form.c hash.c malloc.c perl.c perly.c regcomp.c regexec.c
+SRCS+= stab.c str.c toke.c util.c usersub.c
+CFLAGS+= -I${.CURDIR}
+LDADD= -lm
+DPADD= ${LIBM}
+
+DPADD+= ${LIBCRYPT}
+LDADD+= -lcrypt
+
+.include "../../Makefile.inc"
+.include <bsd.prog.mk>
diff --git a/gnu/usr.bin/perl/perl/arg.h b/gnu/usr.bin/perl/perl/arg.h
new file mode 100644
index 0000000..b3f8d5a
--- /dev/null
+++ b/gnu/usr.bin/perl/perl/arg.h
@@ -0,0 +1,1001 @@
+/* $RCSfile: arg.h,v $$Revision: 1.2 $$Date: 1994/09/11 03:17:24 $
+ *
+ * Copyright (c) 1991, Larry Wall
+ *
+ * You may distribute under the terms of either the GNU General Public
+ * License or the Artistic License, as specified in the README file.
+ *
+ * $Log: arg.h,v $
+ * Revision 1.2 1994/09/11 03:17:24 gclarkii
+ * Changed AF_LOCAL to AF_LOCAL_XX so as not to conflict with 4.4 socket.h
+ * Added casts to shutup warnings in doio.c
+ *
+ * Revision 1.1.1.1 1994/09/10 06:27:34 gclarkii
+ * Initial import of Perl 4.046 bmaked
+ *
+ * Revision 1.1.1.1 1993/08/23 21:29:34 nate
+ * PERL!
+ *
+ * Revision 4.0.1.3 92/06/08 11:44:06 lwall
+ * patch20: O_PIPE conflicted with Atari
+ * patch20: clarified debugging output for literals and double-quoted strings
+ *
+ * Revision 4.0.1.2 91/11/05 15:51:05 lwall
+ * patch11: added eval {}
+ * patch11: added sort {} LIST
+ *
+ * Revision 4.0.1.1 91/06/07 10:18:30 lwall
+ * patch4: length($`), length($&), length($') now optimized to avoid string copy
+ * patch4: new copyright notice
+ * patch4: many, many itty-bitty portability fixes
+ *
+ * Revision 4.0 91/03/20 01:03:09 lwall
+ * 4.0 baseline.
+ *
+ */
+
+#define O_NULL 0
+#define O_RCAT 1
+#define O_ITEM 2
+#define O_SCALAR 3
+#define O_ITEM2 4
+#define O_ITEM3 5
+#define O_CONCAT 6
+#define O_REPEAT 7
+#define O_MATCH 8
+#define O_NMATCH 9
+#define O_SUBST 10
+#define O_NSUBST 11
+#define O_ASSIGN 12
+#define O_LOCAL 13
+#define O_AASSIGN 14
+#define O_SASSIGN 15
+#define O_CHOP 16
+#define O_DEFINED 17
+#define O_UNDEF 18
+#define O_STUDY 19
+#define O_POW 20
+#define O_MULTIPLY 21
+#define O_DIVIDE 22
+#define O_MODULO 23
+#define O_ADD 24
+#define O_SUBTRACT 25
+#define O_LEFT_SHIFT 26
+#define O_RIGHT_SHIFT 27
+#define O_LT 28
+#define O_GT 29
+#define O_LE 30
+#define O_GE 31
+#define O_EQ 32
+#define O_NE 33
+#define O_NCMP 34
+#define O_BIT_AND 35
+#define O_XOR 36
+#define O_BIT_OR 37
+#define O_AND 38
+#define O_OR 39
+#define O_COND_EXPR 40
+#define O_COMMA 41
+#define O_NEGATE 42
+#define O_NOT 43
+#define O_COMPLEMENT 44
+#define O_SELECT 45
+#define O_WRITE 46
+#define O_DBMOPEN 47
+#define O_DBMCLOSE 48
+#define O_OPEN 49
+#define O_TRANS 50
+#define O_NTRANS 51
+#define O_CLOSE 52
+#define O_EACH 53
+#define O_VALUES 54
+#define O_KEYS 55
+#define O_LARRAY 56
+#define O_ARRAY 57
+#define O_AELEM 58
+#define O_DELETE 59
+#define O_LHASH 60
+#define O_HASH 61
+#define O_HELEM 62
+#define O_LAELEM 63
+#define O_LHELEM 64
+#define O_LSLICE 65
+#define O_ASLICE 66
+#define O_HSLICE 67
+#define O_LASLICE 68
+#define O_LHSLICE 69
+#define O_SPLICE 70
+#define O_PUSH 71
+#define O_POP 72
+#define O_SHIFT 73
+#define O_UNPACK 74
+#define O_SPLIT 75
+#define O_LENGTH 76
+#define O_SPRINTF 77
+#define O_SUBSTR 78
+#define O_PACK 79
+#define O_GREP 80
+#define O_JOIN 81
+#define O_SLT 82
+#define O_SGT 83
+#define O_SLE 84
+#define O_SGE 85
+#define O_SEQ 86
+#define O_SNE 87
+#define O_SCMP 88
+#define O_SUBR 89
+#define O_DBSUBR 90
+#define O_CALLER 91
+#define O_SORT 92
+#define O_REVERSE 93
+#define O_WARN 94
+#define O_DIE 95
+#define O_PRTF 96
+#define O_PRINT 97
+#define O_CHDIR 98
+#define O_EXIT 99
+#define O_RESET 100
+#define O_LIST 101
+#define O_EOF 102
+#define O_GETC 103
+#define O_TELL 104
+#define O_RECV 105
+#define O_READ 106
+#define O_SYSREAD 107
+#define O_SYSWRITE 108
+#define O_SEND 109
+#define O_SEEK 110
+#define O_RETURN 111
+#define O_REDO 112
+#define O_NEXT 113
+#define O_LAST 114
+#define O_DUMP 115
+#define O_GOTO 116
+#define O_INDEX 117
+#define O_RINDEX 118
+#define O_TIME 119
+#define O_TMS 120
+#define O_LOCALTIME 121
+#define O_GMTIME 122
+#define O_TRUNCATE 123
+#define O_LSTAT 124
+#define O_STAT 125
+#define O_CRYPT 126
+#define O_ATAN2 127
+#define O_SIN 128
+#define O_COS 129
+#define O_RAND 130
+#define O_SRAND 131
+#define O_EXP 132
+#define O_LOG 133
+#define O_SQRT 134
+#define O_INT 135
+#define O_ORD 136
+#define O_ALARM 137
+#define O_SLEEP 138
+#define O_RANGE 139
+#define O_F_OR_R 140
+#define O_FLIP 141
+#define O_FLOP 142
+#define O_FORK 143
+#define O_WAIT 144
+#define O_WAITPID 145
+#define O_SYSTEM 146
+#define O_EXEC_OP 147
+#define O_HEX 148
+#define O_OCT 149
+#define O_CHOWN 150
+#define O_KILL 151
+#define O_UNLINK 152
+#define O_CHMOD 153
+#define O_UTIME 154
+#define O_UMASK 155
+#define O_MSGGET 156
+#define O_SHMGET 157
+#define O_SEMGET 158
+#define O_MSGCTL 159
+#define O_SHMCTL 160
+#define O_SEMCTL 161
+#define O_MSGSND 162
+#define O_MSGRCV 163
+#define O_SEMOP 164
+#define O_SHMREAD 165
+#define O_SHMWRITE 166
+#define O_RENAME 167
+#define O_LINK 168
+#define O_MKDIR 169
+#define O_RMDIR 170
+#define O_GETPPID 171
+#define O_GETPGRP 172
+#define O_SETPGRP 173
+#define O_GETPRIORITY 174
+#define O_SETPRIORITY 175
+#define O_CHROOT 176
+#define O_FCNTL 177
+#define O_IOCTL 178
+#define O_FLOCK 179
+#define O_UNSHIFT 180
+#define O_REQUIRE 181
+#define O_DOFILE 182
+#define O_EVAL 183
+#define O_FTRREAD 184
+#define O_FTRWRITE 185
+#define O_FTREXEC 186
+#define O_FTEREAD 187
+#define O_FTEWRITE 188
+#define O_FTEEXEC 189
+#define O_FTIS 190
+#define O_FTEOWNED 191
+#define O_FTROWNED 192
+#define O_FTZERO 193
+#define O_FTSIZE 194
+#define O_FTMTIME 195
+#define O_FTATIME 196
+#define O_FTCTIME 197
+#define O_FTSOCK 198
+#define O_FTCHR 199
+#define O_FTBLK 200
+#define O_FTFILE 201
+#define O_FTDIR 202
+#define O_FTPIPE 203
+#define O_FTLINK 204
+#define O_SYMLINK 205
+#define O_READLINK 206
+#define O_FTSUID 207
+#define O_FTSGID 208
+#define O_FTSVTX 209
+#define O_FTTTY 210
+#define O_FTTEXT 211
+#define O_FTBINARY 212
+#define O_SOCKET 213
+#define O_BIND 214
+#define O_CONNECT 215
+#define O_LISTEN 216
+#define O_ACCEPT 217
+#define O_GHBYNAME 218
+#define O_GHBYADDR 219
+#define O_GHOSTENT 220
+#define O_GNBYNAME 221
+#define O_GNBYADDR 222
+#define O_GNETENT 223
+#define O_GPBYNAME 224
+#define O_GPBYNUMBER 225
+#define O_GPROTOENT 226
+#define O_GSBYNAME 227
+#define O_GSBYPORT 228
+#define O_GSERVENT 229
+#define O_SHOSTENT 230
+#define O_SNETENT 231
+#define O_SPROTOENT 232
+#define O_SSERVENT 233
+#define O_EHOSTENT 234
+#define O_ENETENT 235
+#define O_EPROTOENT 236
+#define O_ESERVENT 237
+#define O_SOCKPAIR 238
+#define O_SHUTDOWN 239
+#define O_GSOCKOPT 240
+#define O_SSOCKOPT 241
+#define O_GETSOCKNAME 242
+#define O_GETPEERNAME 243
+#define O_SSELECT 244
+#define O_FILENO 245
+#define O_BINMODE 246
+#define O_VEC 247
+#define O_GPWNAM 248
+#define O_GPWUID 249
+#define O_GPWENT 250
+#define O_SPWENT 251
+#define O_EPWENT 252
+#define O_GGRNAM 253
+#define O_GGRGID 254
+#define O_GGRENT 255
+#define O_SGRENT 256
+#define O_EGRENT 257
+#define O_GETLOGIN 258
+#define O_OPEN_DIR 259
+#define O_READDIR 260
+#define O_TELLDIR 261
+#define O_SEEKDIR 262
+#define O_REWINDDIR 263
+#define O_CLOSEDIR 264
+#define O_SYSCALL 265
+#define O_PIPE_OP 266
+#define O_TRY 267
+#define O_EVALONCE 268
+#define MAXO 269
+
+#ifndef DOINIT
+extern char *opname[];
+#else
+char *opname[] = {
+ "NULL",
+ "RCAT",
+ "ITEM",
+ "SCALAR",
+ "ITEM2",
+ "ITEM3",
+ "CONCAT",
+ "REPEAT",
+ "MATCH",
+ "NMATCH",
+ "SUBST",
+ "NSUBST",
+ "ASSIGN",
+ "LOCAL",
+ "AASSIGN",
+ "SASSIGN",
+ "CHOP",
+ "DEFINED",
+ "UNDEF",
+ "STUDY",
+ "POW",
+ "MULTIPLY",
+ "DIVIDE",
+ "MODULO",
+ "ADD",
+ "SUBTRACT",
+ "LEFT_SHIFT",
+ "RIGHT_SHIFT",
+ "LT",
+ "GT",
+ "LE",
+ "GE",
+ "EQ",
+ "NE",
+ "NCMP",
+ "BIT_AND",
+ "XOR",
+ "BIT_OR",
+ "AND",
+ "OR",
+ "COND_EXPR",
+ "COMMA",
+ "NEGATE",
+ "NOT",
+ "COMPLEMENT",
+ "SELECT",
+ "WRITE",
+ "DBMOPEN",
+ "DBMCLOSE",
+ "OPEN",
+ "TRANS",
+ "NTRANS",
+ "CLOSE",
+ "EACH",
+ "VALUES",
+ "KEYS",
+ "LARRAY",
+ "ARRAY",
+ "AELEM",
+ "DELETE",
+ "LHASH",
+ "HASH",
+ "HELEM",
+ "LAELEM",
+ "LHELEM",
+ "LSLICE",
+ "ASLICE",
+ "HSLICE",
+ "LASLICE",
+ "LHSLICE",
+ "SPLICE",
+ "PUSH",
+ "POP",
+ "SHIFT",
+ "UNPACK",
+ "SPLIT",
+ "LENGTH",
+ "SPRINTF",
+ "SUBSTR",
+ "PACK",
+ "GREP",
+ "JOIN",
+ "SLT",
+ "SGT",
+ "SLE",
+ "SGE",
+ "SEQ",
+ "SNE",
+ "SCMP",
+ "SUBR",
+ "DBSUBR",
+ "CALLER",
+ "SORT",
+ "REVERSE",
+ "WARN",
+ "DIE",
+ "PRINTF",
+ "PRINT",
+ "CHDIR",
+ "EXIT",
+ "RESET",
+ "LIST",
+ "EOF",
+ "GETC",
+ "TELL",
+ "RECV",
+ "READ",
+ "SYSREAD",
+ "SYSWRITE",
+ "SEND",
+ "SEEK",
+ "RETURN",
+ "REDO",
+ "NEXT",
+ "LAST",
+ "DUMP",
+ "GOTO",/* shudder */
+ "INDEX",
+ "RINDEX",
+ "TIME",
+ "TIMES",
+ "LOCALTIME",
+ "GMTIME",
+ "TRUNCATE",
+ "LSTAT",
+ "STAT",
+ "CRYPT",
+ "ATAN2",
+ "SIN",
+ "COS",
+ "RAND",
+ "SRAND",
+ "EXP",
+ "LOG",
+ "SQRT",
+ "INT",
+ "ORD",
+ "ALARM",
+ "SLEEP",
+ "RANGE",
+ "FLIP_OR_RANGE",
+ "FLIP",
+ "FLOP",
+ "FORK",
+ "WAIT",
+ "WAITPID",
+ "SYSTEM",
+ "EXEC",
+ "HEX",
+ "OCT",
+ "CHOWN",
+ "KILL",
+ "UNLINK",
+ "CHMOD",
+ "UTIME",
+ "UMASK",
+ "MSGGET",
+ "SHMGET",
+ "SEMGET",
+ "MSGCTL",
+ "SHMCTL",
+ "SEMCTL",
+ "MSGSND",
+ "MSGRCV",
+ "SEMOP",
+ "SHMREAD",
+ "SHMWRITE",
+ "RENAME",
+ "LINK",
+ "MKDIR",
+ "RMDIR",
+ "GETPPID",
+ "GETPGRP",
+ "SETPGRP",
+ "GETPRIORITY",
+ "SETPRIORITY",
+ "CHROOT",
+ "FCNTL",
+ "SYSIOCTL",
+ "FLOCK",
+ "UNSHIFT",
+ "REQUIRE",
+ "DOFILE",
+ "EVAL",
+ "FTRREAD",
+ "FTRWRITE",
+ "FTREXEC",
+ "FTEREAD",
+ "FTEWRITE",
+ "FTEEXEC",
+ "FTIS",
+ "FTEOWNED",
+ "FTROWNED",
+ "FTZERO",
+ "FTSIZE",
+ "FTMTIME",
+ "FTATIME",
+ "FTCTIME",
+ "FTSOCK",
+ "FTCHR",
+ "FTBLK",
+ "FTFILE",
+ "FTDIR",
+ "FTPIPE",
+ "FTLINK",
+ "SYMLINK",
+ "READLINK",
+ "FTSUID",
+ "FTSGID",
+ "FTSVTX",
+ "FTTTY",
+ "FTTEXT",
+ "FTBINARY",
+ "SOCKET",
+ "BIND",
+ "CONNECT",
+ "LISTEN",
+ "ACCEPT",
+ "GHBYNAME",
+ "GHBYADDR",
+ "GHOSTENT",
+ "GNBYNAME",
+ "GNBYADDR",
+ "GNETENT",
+ "GPBYNAME",
+ "GPBYNUMBER",
+ "GPROTOENT",
+ "GSBYNAME",
+ "GSBYPORT",
+ "GSERVENT",
+ "SHOSTENT",
+ "SNETENT",
+ "SPROTOENT",
+ "SSERVENT",
+ "EHOSTENT",
+ "ENETENT",
+ "EPROTOENT",
+ "ESERVENT",
+ "SOCKPAIR",
+ "SHUTDOWN",
+ "GSOCKOPT",
+ "SSOCKOPT",
+ "GETSOCKNAME",
+ "GETPEERNAME",
+ "SSELECT",
+ "FILENO",
+ "BINMODE",
+ "VEC",
+ "GPWNAM",
+ "GPWUID",
+ "GPWENT",
+ "SPWENT",
+ "EPWENT",
+ "GGRNAM",
+ "GGRGID",
+ "GGRENT",
+ "SGRENT",
+ "EGRENT",
+ "GETLOGIN",
+ "OPENDIR",
+ "READDIR",
+ "TELLDIR",
+ "SEEKDIR",
+ "REWINDDIR",
+ "CLOSEDIR",
+ "SYSCALL",
+ "PIPE",
+ "TRY",
+ "EVALONCE",
+ "269"
+};
+#endif
+
+#define A_NULL 0
+#define A_EXPR 1
+#define A_CMD 2
+#define A_STAB 3
+#define A_LVAL 4
+#define A_SINGLE 5
+#define A_DOUBLE 6
+#define A_BACKTICK 7
+#define A_READ 8
+#define A_SPAT 9
+#define A_LEXPR 10
+#define A_ARYLEN 11
+#define A_ARYSTAB 12
+#define A_LARYLEN 13
+#define A_GLOB 14
+#define A_WORD 15
+#define A_INDREAD 16
+#define A_LARYSTAB 17
+#define A_STAR 18
+#define A_LSTAR 19
+#define A_WANTARRAY 20
+#define A_LENSTAB 21
+
+#define A_MASK 31
+#define A_DONT 32 /* or this into type to suppress evaluation */
+
+#ifndef DOINIT
+extern char *argname[];
+#else
+char *argname[] = {
+ "A_NULL",
+ "EXPR",
+ "CMD",
+ "STAB",
+ "LVAL",
+ "LITERAL",
+ "DOUBLEQUOTE",
+ "BACKTICK",
+ "READ",
+ "SPAT",
+ "LEXPR",
+ "ARYLEN",
+ "ARYSTAB",
+ "LARYLEN",
+ "GLOB",
+ "WORD",
+ "INDREAD",
+ "LARYSTAB",
+ "STAR",
+ "LSTAR",
+ "WANTARRAY",
+ "LENSTAB",
+ "22"
+};
+#endif
+
+#ifndef DOINIT
+extern bool hoistable[];
+#else
+bool hoistable[] =
+ {0, /* A_NULL */
+ 0, /* EXPR */
+ 1, /* CMD */
+ 1, /* STAB */
+ 0, /* LVAL */
+ 1, /* SINGLE */
+ 0, /* DOUBLE */
+ 0, /* BACKTICK */
+ 0, /* READ */
+ 0, /* SPAT */
+ 0, /* LEXPR */
+ 1, /* ARYLEN */
+ 1, /* ARYSTAB */
+ 0, /* LARYLEN */
+ 0, /* GLOB */
+ 1, /* WORD */
+ 0, /* INDREAD */
+ 0, /* LARYSTAB */
+ 1, /* STAR */
+ 1, /* LSTAR */
+ 1, /* WANTARRAY */
+ 0, /* LENSTAB */
+ 0, /* 21 */
+};
+#endif
+
+union argptr {
+ ARG *arg_arg;
+ char *arg_cval;
+ STAB *arg_stab;
+ SPAT *arg_spat;
+ CMD *arg_cmd;
+ STR *arg_str;
+ HASH *arg_hash;
+};
+
+struct arg {
+ union argptr arg_ptr;
+ short arg_len;
+ unsigned short arg_type;
+ unsigned short arg_flags;
+};
+
+#define AF_ARYOK 1 /* op can handle multiple values here */
+#define AF_POST 2 /* post *crement this item */
+#define AF_PRE 4 /* pre *crement this item */
+#define AF_UP 8 /* increment rather than decrement */
+#define AF_COMMON 16 /* left and right have symbols in common */
+#define AF_DEPR 32 /* an older form of the construct */
+#define AF_LISTISH 64 /* turn into list if important */
+#define AF_LOCAL_XX 128 /* list of local variables */
+
+/*
+ * Most of the ARG pointers are used as pointers to arrays of ARG. When
+ * so used, the 0th element is special, and represents the operator to
+ * use on the list of arguments following. The arg_len in the 0th element
+ * gives the maximum argument number, and the arg_str is used to store
+ * the return value in a more-or-less static location. Sorry it's not
+ * re-entrant (yet), but it sure makes it efficient. The arg_type of the
+ * 0th element is an operator (O_*) rather than an argument type (A_*).
+ */
+
+#define Nullarg Null(ARG*)
+
+#ifndef DOINIT
+EXT unsigned short opargs[MAXO+1];
+#else
+#define A(e1,e2,e3) (e1+(e2<<2)+(e3<<4))
+#define A5(e1,e2,e3,e4,e5) (e1+(e2<<2)+(e3<<4)+(e4<<6)+(e5<<8))
+unsigned short opargs[MAXO+1] = {
+ A(0,0,0), /* NULL */
+ A(1,1,0), /* RCAT */
+ A(1,0,0), /* ITEM */
+ A(1,0,0), /* SCALAR */
+ A(0,0,0), /* ITEM2 */
+ A(0,0,0), /* ITEM3 */
+ A(1,1,0), /* CONCAT */
+ A(3,1,0), /* REPEAT */
+ A(1,0,0), /* MATCH */
+ A(1,0,0), /* NMATCH */
+ A(1,0,0), /* SUBST */
+ A(1,0,0), /* NSUBST */
+ A(1,1,0), /* ASSIGN */
+ A(1,0,0), /* LOCAL */
+ A(3,3,0), /* AASSIGN */
+ A(0,0,0), /* SASSIGN */
+ A(3,0,0), /* CHOP */
+ A(1,0,0), /* DEFINED */
+ A(1,0,0), /* UNDEF */
+ A(1,0,0), /* STUDY */
+ A(1,1,0), /* POW */
+ A(1,1,0), /* MULTIPLY */
+ A(1,1,0), /* DIVIDE */
+ A(1,1,0), /* MODULO */
+ A(1,1,0), /* ADD */
+ A(1,1,0), /* SUBTRACT */
+ A(1,1,0), /* LEFT_SHIFT */
+ A(1,1,0), /* RIGHT_SHIFT */
+ A(1,1,0), /* LT */
+ A(1,1,0), /* GT */
+ A(1,1,0), /* LE */
+ A(1,1,0), /* GE */
+ A(1,1,0), /* EQ */
+ A(1,1,0), /* NE */
+ A(1,1,0), /* NCMP */
+ A(1,1,0), /* BIT_AND */
+ A(1,1,0), /* XOR */
+ A(1,1,0), /* BIT_OR */
+ A(1,0,0), /* AND */
+ A(1,0,0), /* OR */
+ A(1,0,0), /* COND_EXPR */
+ A(1,1,0), /* COMMA */
+ A(1,0,0), /* NEGATE */
+ A(1,0,0), /* NOT */
+ A(1,0,0), /* COMPLEMENT */
+ A(1,0,0), /* SELECT */
+ A(1,0,0), /* WRITE */
+ A(1,1,1), /* DBMOPEN */
+ A(1,0,0), /* DBMCLOSE */
+ A(1,1,0), /* OPEN */
+ A(1,0,0), /* TRANS */
+ A(1,0,0), /* NTRANS */
+ A(1,0,0), /* CLOSE */
+ A(0,0,0), /* EACH */
+ A(0,0,0), /* VALUES */
+ A(0,0,0), /* KEYS */
+ A(0,0,0), /* LARRAY */
+ A(0,0,0), /* ARRAY */
+ A(0,1,0), /* AELEM */
+ A(0,1,0), /* DELETE */
+ A(0,0,0), /* LHASH */
+ A(0,0,0), /* HASH */
+ A(0,1,0), /* HELEM */
+ A(0,1,0), /* LAELEM */
+ A(0,1,0), /* LHELEM */
+ A(0,3,3), /* LSLICE */
+ A(0,3,0), /* ASLICE */
+ A(0,3,0), /* HSLICE */
+ A(0,3,0), /* LASLICE */
+ A(0,3,0), /* LHSLICE */
+ A(0,3,1), /* SPLICE */
+ A(0,3,0), /* PUSH */
+ A(0,0,0), /* POP */
+ A(0,0,0), /* SHIFT */
+ A(1,1,0), /* UNPACK */
+ A(1,0,1), /* SPLIT */
+ A(1,0,0), /* LENGTH */
+ A(3,0,0), /* SPRINTF */
+ A(1,1,1), /* SUBSTR */
+ A(1,3,0), /* PACK */
+ A(0,3,0), /* GREP */
+ A(1,3,0), /* JOIN */
+ A(1,1,0), /* SLT */
+ A(1,1,0), /* SGT */
+ A(1,1,0), /* SLE */
+ A(1,1,0), /* SGE */
+ A(1,1,0), /* SEQ */
+ A(1,1,0), /* SNE */
+ A(1,1,0), /* SCMP */
+ A(0,3,0), /* SUBR */
+ A(0,3,0), /* DBSUBR */
+ A(1,0,0), /* CALLER */
+ A(1,3,0), /* SORT */
+ A(0,3,0), /* REVERSE */
+ A(0,3,0), /* WARN */
+ A(0,3,0), /* DIE */
+ A(1,3,0), /* PRINTF */
+ A(1,3,0), /* PRINT */
+ A(1,0,0), /* CHDIR */
+ A(1,0,0), /* EXIT */
+ A(1,0,0), /* RESET */
+ A(3,0,0), /* LIST */
+ A(1,0,0), /* EOF */
+ A(1,0,0), /* GETC */
+ A(1,0,0), /* TELL */
+ A5(1,1,1,1,0), /* RECV */
+ A(1,1,3), /* READ */
+ A(1,1,3), /* SYSREAD */
+ A(1,1,3), /* SYSWRITE */
+ A(1,1,3), /* SEND */
+ A(1,1,1), /* SEEK */
+ A(0,3,0), /* RETURN */
+ A(0,0,0), /* REDO */
+ A(0,0,0), /* NEXT */
+ A(0,0,0), /* LAST */
+ A(0,0,0), /* DUMP */
+ A(0,0,0), /* GOTO */
+ A(1,1,1), /* INDEX */
+ A(1,1,1), /* RINDEX */
+ A(0,0,0), /* TIME */
+ A(0,0,0), /* TIMES */
+ A(1,0,0), /* LOCALTIME */
+ A(1,0,0), /* GMTIME */
+ A(1,1,0), /* TRUNCATE */
+ A(1,0,0), /* LSTAT */
+ A(1,0,0), /* STAT */
+ A(1,1,0), /* CRYPT */
+ A(1,1,0), /* ATAN2 */
+ A(1,0,0), /* SIN */
+ A(1,0,0), /* COS */
+ A(1,0,0), /* RAND */
+ A(1,0,0), /* SRAND */
+ A(1,0,0), /* EXP */
+ A(1,0,0), /* LOG */
+ A(1,0,0), /* SQRT */
+ A(1,0,0), /* INT */
+ A(1,0,0), /* ORD */
+ A(1,0,0), /* ALARM */
+ A(1,0,0), /* SLEEP */
+ A(1,1,0), /* RANGE */
+ A(1,0,0), /* F_OR_R */
+ A(1,0,0), /* FLIP */
+ A(0,1,0), /* FLOP */
+ A(0,0,0), /* FORK */
+ A(0,0,0), /* WAIT */
+ A(1,1,0), /* WAITPID */
+ A(1,3,0), /* SYSTEM */
+ A(1,3,0), /* EXEC */
+ A(1,0,0), /* HEX */
+ A(1,0,0), /* OCT */
+ A(0,3,0), /* CHOWN */
+ A(0,3,0), /* KILL */
+ A(0,3,0), /* UNLINK */
+ A(0,3,0), /* CHMOD */
+ A(0,3,0), /* UTIME */
+ A(1,0,0), /* UMASK */
+ A(1,1,0), /* MSGGET */
+ A(1,1,1), /* SHMGET */
+ A(1,1,1), /* SEMGET */
+ A(1,1,1), /* MSGCTL */
+ A(1,1,1), /* SHMCTL */
+ A5(1,1,1,1,0), /* SEMCTL */
+ A(1,1,1), /* MSGSND */
+ A5(1,1,1,1,1), /* MSGRCV */
+ A(1,1,1), /* SEMOP */
+ A5(1,1,1,1,0), /* SHMREAD */
+ A5(1,1,1,1,0), /* SHMWRITE */
+ A(1,1,0), /* RENAME */
+ A(1,1,0), /* LINK */
+ A(1,1,0), /* MKDIR */
+ A(1,0,0), /* RMDIR */
+ A(0,0,0), /* GETPPID */
+ A(1,0,0), /* GETPGRP */
+ A(1,1,0), /* SETPGRP */
+ A(1,1,0), /* GETPRIORITY */
+ A(1,1,1), /* SETPRIORITY */
+ A(1,0,0), /* CHROOT */
+ A(1,1,1), /* FCNTL */
+ A(1,1,1), /* SYSIOCTL */
+ A(1,1,0), /* FLOCK */
+ A(0,3,0), /* UNSHIFT */
+ A(1,0,0), /* REQUIRE */
+ A(1,0,0), /* DOFILE */
+ A(1,0,0), /* EVAL */
+ A(1,0,0), /* FTRREAD */
+ A(1,0,0), /* FTRWRITE */
+ A(1,0,0), /* FTREXEC */
+ A(1,0,0), /* FTEREAD */
+ A(1,0,0), /* FTEWRITE */
+ A(1,0,0), /* FTEEXEC */
+ A(1,0,0), /* FTIS */
+ A(1,0,0), /* FTEOWNED */
+ A(1,0,0), /* FTROWNED */
+ A(1,0,0), /* FTZERO */
+ A(1,0,0), /* FTSIZE */
+ A(1,0,0), /* FTMTIME */
+ A(1,0,0), /* FTATIME */
+ A(1,0,0), /* FTCTIME */
+ A(1,0,0), /* FTSOCK */
+ A(1,0,0), /* FTCHR */
+ A(1,0,0), /* FTBLK */
+ A(1,0,0), /* FTFILE */
+ A(1,0,0), /* FTDIR */
+ A(1,0,0), /* FTPIPE */
+ A(1,0,0), /* FTLINK */
+ A(1,1,0), /* SYMLINK */
+ A(1,0,0), /* READLINK */
+ A(1,0,0), /* FTSUID */
+ A(1,0,0), /* FTSGID */
+ A(1,0,0), /* FTSVTX */
+ A(1,0,0), /* FTTTY */
+ A(1,0,0), /* FTTEXT */
+ A(1,0,0), /* FTBINARY */
+ A5(1,1,1,1,0), /* SOCKET */
+ A(1,1,0), /* BIND */
+ A(1,1,0), /* CONNECT */
+ A(1,1,0), /* LISTEN */
+ A(1,1,0), /* ACCEPT */
+ A(1,0,0), /* GHBYNAME */
+ A(1,1,0), /* GHBYADDR */
+ A(0,0,0), /* GHOSTENT */
+ A(1,0,0), /* GNBYNAME */
+ A(1,1,0), /* GNBYADDR */
+ A(0,0,0), /* GNETENT */
+ A(1,0,0), /* GPBYNAME */
+ A(1,0,0), /* GPBYNUMBER */
+ A(0,0,0), /* GPROTOENT */
+ A(1,1,0), /* GSBYNAME */
+ A(1,1,0), /* GSBYPORT */
+ A(0,0,0), /* GSERVENT */
+ A(1,0,0), /* SHOSTENT */
+ A(1,0,0), /* SNETENT */
+ A(1,0,0), /* SPROTOENT */
+ A(1,0,0), /* SSERVENT */
+ A(0,0,0), /* EHOSTENT */
+ A(0,0,0), /* ENETENT */
+ A(0,0,0), /* EPROTOENT */
+ A(0,0,0), /* ESERVENT */
+ A5(1,1,1,1,1), /* SOCKPAIR */
+ A(1,1,0), /* SHUTDOWN */
+ A(1,1,1), /* GSOCKOPT */
+ A5(1,1,1,1,0), /* SSOCKOPT */
+ A(1,0,0), /* GETSOCKNAME */
+ A(1,0,0), /* GETPEERNAME */
+ A5(1,1,1,1,0), /* SSELECT */
+ A(1,0,0), /* FILENO */
+ A(1,0,0), /* BINMODE */
+ A(1,1,1), /* VEC */
+ A(1,0,0), /* GPWNAM */
+ A(1,0,0), /* GPWUID */
+ A(0,0,0), /* GPWENT */
+ A(0,0,0), /* SPWENT */
+ A(0,0,0), /* EPWENT */
+ A(1,0,0), /* GGRNAM */
+ A(1,0,0), /* GGRGID */
+ A(0,0,0), /* GGRENT */
+ A(0,0,0), /* SGRENT */
+ A(0,0,0), /* EGRENT */
+ A(0,0,0), /* GETLOGIN */
+ A(1,1,0), /* OPENDIR */
+ A(1,0,0), /* READDIR */
+ A(1,0,0), /* TELLDIR */
+ A(1,1,0), /* SEEKDIR */
+ A(1,0,0), /* REWINDDIR */
+ A(1,0,0), /* CLOSEDIR */
+ A(1,3,0), /* SYSCALL */
+ A(1,1,0), /* PIPE */
+ A(0,0,0), /* TRY */
+ A(1,0,0), /* EVALONCE */
+ 0
+};
+#undef A
+#undef A5
+#endif
+
+int do_trans();
+int do_split();
+bool do_eof();
+long do_tell();
+bool do_seek();
+int do_tms();
+int do_time();
+int do_stat();
+STR *do_push();
+FILE *nextargv();
+STR *do_fttext();
+int do_slice();
diff --git a/gnu/usr.bin/perl/perl/array.c b/gnu/usr.bin/perl/perl/array.c
new file mode 100644
index 0000000..a413e3b
--- /dev/null
+++ b/gnu/usr.bin/perl/perl/array.c
@@ -0,0 +1,290 @@
+/* $RCSfile: array.c,v $$Revision: 1.1.1.1 $$Date: 1994/09/10 06:27:31 $
+ *
+ * Copyright (c) 1991, Larry Wall
+ *
+ * You may distribute under the terms of either the GNU General Public
+ * License or the Artistic License, as specified in the README file.
+ *
+ * $Log: array.c,v $
+ * Revision 1.1.1.1 1994/09/10 06:27:31 gclarkii
+ * Initial import of Perl 4.046 bmaked
+ *
+ * Revision 1.1.1.1 1993/08/23 21:29:34 nate
+ * PERL!
+ *
+ * Revision 4.0.1.3 92/06/08 11:45:05 lwall
+ * patch20: Perl now distinguishes overlapped copies from non-overlapped
+ *
+ * Revision 4.0.1.2 91/11/05 16:00:14 lwall
+ * patch11: random cleanup
+ * patch11: passing non-existend array elements to subrouting caused core dump
+ *
+ * Revision 4.0.1.1 91/06/07 10:19:08 lwall
+ * patch4: new copyright notice
+ *
+ * Revision 4.0 91/03/20 01:03:32 lwall
+ * 4.0 baseline.
+ *
+ */
+
+#include "EXTERN.h"
+#include "perl.h"
+
+STR *
+afetch(ar,key,lval)
+register ARRAY *ar;
+int key;
+int lval;
+{
+ STR *str;
+
+ if (key < 0 || key > ar->ary_fill) {
+ if (lval && key >= 0) {
+ if (ar->ary_flags & ARF_REAL)
+ str = Str_new(5,0);
+ else
+ str = str_mortal(&str_undef);
+ (void)astore(ar,key,str);
+ return str;
+ }
+ else
+ return &str_undef;
+ }
+ if (!ar->ary_array[key]) {
+ if (lval) {
+ str = Str_new(6,0);
+ (void)astore(ar,key,str);
+ return str;
+ }
+ return &str_undef;
+ }
+ return ar->ary_array[key];
+}
+
+bool
+astore(ar,key,val)
+register ARRAY *ar;
+int key;
+STR *val;
+{
+ int retval;
+
+ if (key < 0)
+ return FALSE;
+ if (key > ar->ary_max) {
+ int newmax;
+
+ if (ar->ary_alloc != ar->ary_array) {
+ retval = ar->ary_array - ar->ary_alloc;
+ Move(ar->ary_array, ar->ary_alloc, ar->ary_max+1, STR*);
+ Zero(ar->ary_alloc+ar->ary_max+1, retval, STR*);
+ ar->ary_max += retval;
+ ar->ary_array -= retval;
+ if (key > ar->ary_max - 10) {
+ newmax = key + ar->ary_max;
+ goto resize;
+ }
+ }
+ else {
+ if (ar->ary_alloc) {
+ newmax = key + ar->ary_max / 5;
+ resize:
+ Renew(ar->ary_alloc,newmax+1, STR*);
+ Zero(&ar->ary_alloc[ar->ary_max+1], newmax - ar->ary_max, STR*);
+ }
+ else {
+ newmax = key < 4 ? 4 : key;
+ Newz(2,ar->ary_alloc, newmax+1, STR*);
+ }
+ ar->ary_array = ar->ary_alloc;
+ ar->ary_max = newmax;
+ }
+ }
+ if (ar->ary_flags & ARF_REAL) {
+ if (ar->ary_fill < key) {
+ while (++ar->ary_fill < key) {
+ if (ar->ary_array[ar->ary_fill] != Nullstr) {
+ str_free(ar->ary_array[ar->ary_fill]);
+ ar->ary_array[ar->ary_fill] = Nullstr;
+ }
+ }
+ }
+ retval = (ar->ary_array[key] != Nullstr);
+ if (retval)
+ str_free(ar->ary_array[key]);
+ }
+ else
+ retval = 0;
+ ar->ary_array[key] = val;
+ return retval;
+}
+
+ARRAY *
+anew(stab)
+STAB *stab;
+{
+ register ARRAY *ar;
+
+ New(1,ar,1,ARRAY);
+ ar->ary_magic = Str_new(7,0);
+ ar->ary_alloc = ar->ary_array = 0;
+ str_magic(ar->ary_magic, stab, '#', Nullch, 0);
+ ar->ary_max = ar->ary_fill = -1;
+ ar->ary_flags = ARF_REAL;
+ return ar;
+}
+
+ARRAY *
+afake(stab,size,strp)
+STAB *stab;
+register int size;
+register STR **strp;
+{
+ register ARRAY *ar;
+
+ New(3,ar,1,ARRAY);
+ New(4,ar->ary_alloc,size+1,STR*);
+ Copy(strp,ar->ary_alloc,size,STR*);
+ ar->ary_array = ar->ary_alloc;
+ ar->ary_magic = Str_new(8,0);
+ str_magic(ar->ary_magic, stab, '#', Nullch, 0);
+ ar->ary_fill = size - 1;
+ ar->ary_max = size - 1;
+ ar->ary_flags = 0;
+ while (size--) {
+ if (*strp)
+ (*strp)->str_pok &= ~SP_TEMP;
+ strp++;
+ }
+ return ar;
+}
+
+void
+aclear(ar)
+register ARRAY *ar;
+{
+ register int key;
+
+ if (!ar || !(ar->ary_flags & ARF_REAL) || ar->ary_max < 0)
+ return;
+ /*SUPPRESS 560*/
+ if (key = ar->ary_array - ar->ary_alloc) {
+ ar->ary_max += key;
+ ar->ary_array -= key;
+ }
+ for (key = 0; key <= ar->ary_max; key++)
+ str_free(ar->ary_array[key]);
+ ar->ary_fill = -1;
+ Zero(ar->ary_array, ar->ary_max+1, STR*);
+}
+
+void
+afree(ar)
+register ARRAY *ar;
+{
+ register int key;
+
+ if (!ar)
+ return;
+ /*SUPPRESS 560*/
+ if (key = ar->ary_array - ar->ary_alloc) {
+ ar->ary_max += key;
+ ar->ary_array -= key;
+ }
+ if (ar->ary_flags & ARF_REAL) {
+ for (key = 0; key <= ar->ary_max; key++)
+ str_free(ar->ary_array[key]);
+ }
+ str_free(ar->ary_magic);
+ Safefree(ar->ary_alloc);
+ Safefree(ar);
+}
+
+bool
+apush(ar,val)
+register ARRAY *ar;
+STR *val;
+{
+ return astore(ar,++(ar->ary_fill),val);
+}
+
+STR *
+apop(ar)
+register ARRAY *ar;
+{
+ STR *retval;
+
+ if (ar->ary_fill < 0)
+ return Nullstr;
+ retval = ar->ary_array[ar->ary_fill];
+ ar->ary_array[ar->ary_fill--] = Nullstr;
+ return retval;
+}
+
+void
+aunshift(ar,num)
+register ARRAY *ar;
+register int num;
+{
+ register int i;
+ register STR **sstr,**dstr;
+
+ if (num <= 0)
+ return;
+ if (ar->ary_array - ar->ary_alloc >= num) {
+ ar->ary_max += num;
+ ar->ary_fill += num;
+ while (num--)
+ *--ar->ary_array = Nullstr;
+ }
+ else {
+ (void)astore(ar,ar->ary_fill+num,(STR*)0); /* maybe extend array */
+ dstr = ar->ary_array + ar->ary_fill;
+ sstr = dstr - num;
+#ifdef BUGGY_MSC5
+ # pragma loop_opt(off) /* don't loop-optimize the following code */
+#endif /* BUGGY_MSC5 */
+ for (i = ar->ary_fill - num; i >= 0; i--) {
+ *dstr-- = *sstr--;
+#ifdef BUGGY_MSC5
+ # pragma loop_opt() /* loop-optimization back to command-line setting */
+#endif /* BUGGY_MSC5 */
+ }
+ Zero(ar->ary_array, num, STR*);
+ }
+}
+
+STR *
+ashift(ar)
+register ARRAY *ar;
+{
+ STR *retval;
+
+ if (ar->ary_fill < 0)
+ return Nullstr;
+ retval = *ar->ary_array;
+ *(ar->ary_array++) = Nullstr;
+ ar->ary_max--;
+ ar->ary_fill--;
+ return retval;
+}
+
+int
+alen(ar)
+register ARRAY *ar;
+{
+ return ar->ary_fill;
+}
+
+void
+afill(ar, fill)
+register ARRAY *ar;
+int fill;
+{
+ if (fill < 0)
+ fill = -1;
+ if (fill <= ar->ary_max)
+ ar->ary_fill = fill;
+ else
+ (void)astore(ar,fill,Nullstr);
+}
diff --git a/gnu/usr.bin/perl/perl/array.h b/gnu/usr.bin/perl/perl/array.h
new file mode 100644
index 0000000..9b2207b
--- /dev/null
+++ b/gnu/usr.bin/perl/perl/array.h
@@ -0,0 +1,48 @@
+/* $RCSfile: array.h,v $$Revision: 1.1.1.1 $$Date: 1994/09/10 06:27:34 $
+ *
+ * Copyright (c) 1991, Larry Wall
+ *
+ * You may distribute under the terms of either the GNU General Public
+ * License or the Artistic License, as specified in the README file.
+ *
+ * $Log: array.h,v $
+ * Revision 1.1.1.1 1994/09/10 06:27:34 gclarkii
+ * Initial import of Perl 4.046 bmaked
+ *
+ * Revision 1.1.1.1 1993/08/23 21:29:34 nate
+ * PERL!
+ *
+ * Revision 4.0.1.2 92/06/08 11:45:57 lwall
+ * patch20: removed implicit int declarations on funcions
+ *
+ * Revision 4.0.1.1 91/06/07 10:19:20 lwall
+ * patch4: new copyright notice
+ *
+ * Revision 4.0 91/03/20 01:03:44 lwall
+ * 4.0 baseline.
+ *
+ */
+
+struct atbl {
+ STR **ary_array;
+ STR **ary_alloc;
+ STR *ary_magic;
+ int ary_max;
+ int ary_fill;
+ char ary_flags;
+};
+
+#define ARF_REAL 1 /* free old entries */
+
+STR *afetch();
+bool astore();
+STR *apop();
+STR *ashift();
+void afree();
+void aclear();
+bool apush();
+int alen();
+ARRAY *anew();
+ARRAY *afake();
+void aunshift();
+void afill();
diff --git a/gnu/usr.bin/perl/perl/cflags b/gnu/usr.bin/perl/perl/cflags
new file mode 100755
index 0000000..672dfc6
--- /dev/null
+++ b/gnu/usr.bin/perl/perl/cflags
@@ -0,0 +1,91 @@
+case "$0" in
+*/*) cd `expr X$0 : 'X\(.*\)/'` ;;
+esac
+case $CONFIG in
+'')
+ if test ! -f config.sh; then
+ ln ../config.sh . || \
+ ln ../../config.sh . || \
+ ln ../../../config.sh . || \
+ (echo "Can't find config.sh."; exit 1)
+ fi 2>/dev/null
+ . ./config.sh
+ ;;
+esac
+
+also=': '
+case $# in
+1) also='echo 1>&2 " CCCMD = "'
+esac
+
+case $# in
+0) set *.c; echo "The current C flags are:" ;;
+esac
+
+set `echo "$* " | sed 's/\.[oc] / /g'`
+
+for file do
+
+ case "$#" in
+ 1) ;;
+ *) echo $n " $file.c $c" ;;
+ esac
+
+ : allow variables like toke_cflags to be evaluated
+
+ eval 'eval ${'"${file}_cflags"'-""}'
+
+ : or customize here
+
+ case "$file" in
+ array) ;;
+ cmd) ;;
+ cons) ;;
+ consarg) ;;
+ doarg) ;;
+ doio) ;;
+ dolist) ;;
+ dump) ;;
+ eval) ;;
+ form) ;;
+ hash) ;;
+ malloc) ;;
+ perl) ;;
+ perly) ;;
+ regcomp) ;;
+ regexec) ;;
+ stab) ;;
+ str) ;;
+ toke) ;;
+ usersub) ;;
+ util) ;;
+ tarray) ;;
+ tcmd) ;;
+ tcons) ;;
+ tconsarg) ;;
+ tdoarg) ;;
+ tdoio) ;;
+ tdolist) ;;
+ tdump) ;;
+ teval) ;;
+ tform) ;;
+ thash) ;;
+ tmalloc) ;;
+ tperl) ;;
+ tperly) ;;
+ tregcomp) ;;
+ tregexec) ;;
+ tstab) ;;
+ tstr) ;;
+ ttoke) ;;
+ tusersub) ;;
+ tutil) ;;
+ *) ;;
+ esac
+
+ echo "$cc -c $ccflags $optimize $large $split"
+ eval "$also "'"$cc -c $ccflags $optimize $large $split"'
+
+ . ./config.sh
+
+done
diff --git a/gnu/usr.bin/perl/perl/cmd.c b/gnu/usr.bin/perl/perl/cmd.c
new file mode 100644
index 0000000..162926d
--- /dev/null
+++ b/gnu/usr.bin/perl/perl/cmd.c
@@ -0,0 +1,1266 @@
+/* $RCSfile: cmd.c,v $$Revision: 1.1.1.1 $$Date: 1994/09/10 06:27:32 $
+ *
+ * Copyright (c) 1991, Larry Wall
+ *
+ * You may distribute under the terms of either the GNU General Public
+ * License or the Artistic License, as specified in the README file.
+ *
+ * $Log: cmd.c,v $
+ * Revision 1.1.1.1 1994/09/10 06:27:32 gclarkii
+ * Initial import of Perl 4.046 bmaked
+ *
+ * Revision 1.1.1.1 1993/08/23 21:29:35 nate
+ * PERL!
+ *
+ * Revision 4.0.1.5 92/06/08 12:00:39 lwall
+ * patch20: the switch optimizer didn't do anything in subroutines
+ * patch20: removed implicit int declarations on funcions
+ *
+ * Revision 4.0.1.4 91/11/11 16:29:33 lwall
+ * patch19: do {$foo ne "bar";} returned wrong value
+ * patch19: some earlier patches weren't propagated to alternate 286 code
+ *
+ * Revision 4.0.1.3 91/11/05 16:07:43 lwall
+ * patch11: random cleanup
+ * patch11: "foo\0" eq "foo" was sometimes optimized to true
+ * patch11: foreach on null list could spring memory leak
+ *
+ * Revision 4.0.1.2 91/06/07 10:26:45 lwall
+ * patch4: new copyright notice
+ * patch4: made some allowances for "semi-standard" C
+ *
+ * Revision 4.0.1.1 91/04/11 17:36:16 lwall
+ * patch1: you may now use "die" and "caller" in a signal handler
+ *
+ * Revision 4.0 91/03/20 01:04:18 lwall
+ * 4.0 baseline.
+ *
+ */
+
+#include "EXTERN.h"
+#include "perl.h"
+
+#ifdef I_VARARGS
+# include <varargs.h>
+#endif
+
+static STR strchop;
+
+void grow_dlevel();
+
+/* do longjmps() clobber register variables? */
+
+#if defined(cray) || defined(STANDARD_C)
+#define JMPCLOBBER
+#endif
+
+/* This is the main command loop. We try to spend as much time in this loop
+ * as possible, so lots of optimizations do their activities in here. This
+ * means things get a little sloppy.
+ */
+
+int
+cmd_exec(cmdparm,gimme,sp)
+CMD *VOLATILE cmdparm;
+VOLATILE int gimme;
+VOLATILE int sp;
+{
+ register CMD *cmd = cmdparm;
+ SPAT *VOLATILE oldspat;
+ VOLATILE int firstsave = savestack->ary_fill;
+ VOLATILE int oldsave;
+ VOLATILE int aryoptsave;
+#ifdef DEBUGGING
+ VOLATILE int olddlevel;
+ VOLATILE int entdlevel;
+#endif
+ register STR *retstr = &str_undef;
+ register char *tmps;
+ register int cmdflags;
+ register int match;
+ register char *go_to = goto_targ;
+ register int newsp = -2;
+ register STR **st = stack->ary_array;
+ FILE *VOLATILE fp;
+ ARRAY *VOLATILE ar;
+
+ lastsize = 0;
+#ifdef DEBUGGING
+ entdlevel = dlevel;
+#endif
+tail_recursion_entry:
+#ifdef DEBUGGING
+ dlevel = entdlevel;
+ if (debug & 4)
+ deb("mortals = (%d/%d) stack, = (%d/%d)\n",
+ tmps_max, tmps_base,
+ savestack->ary_fill, firstsave);
+#endif
+#ifdef TAINT
+ tainted = 0; /* Each statement is presumed innocent */
+#endif
+ if (cmd == Nullcmd) {
+ if (gimme == G_ARRAY && newsp > -2)
+ return newsp;
+ else {
+ st[++sp] = retstr;
+ return sp;
+ }
+ }
+ cmdflags = cmd->c_flags; /* hopefully load register */
+ if (go_to) {
+ if (cmd->c_label && strEQ(go_to,cmd->c_label))
+ goto_targ = go_to = Nullch; /* here at last */
+ else {
+ switch (cmd->c_type) {
+ case C_IF:
+ oldspat = curspat;
+ oldsave = savestack->ary_fill;
+#ifdef DEBUGGING
+ olddlevel = dlevel;
+#endif
+ retstr = &str_yes;
+ newsp = -2;
+ if (cmd->ucmd.ccmd.cc_true) {
+#ifdef DEBUGGING
+ if (debug) {
+ debname[dlevel] = 't';
+ debdelim[dlevel] = '_';
+ if (++dlevel >= dlmax)
+ grow_dlevel();
+ }
+#endif
+ newsp = cmd_exec(cmd->ucmd.ccmd.cc_true,gimme && (cmdflags & CF_TERM),sp);
+ st = stack->ary_array; /* possibly reallocated */
+ retstr = st[newsp];
+ }
+ if (!goto_targ)
+ go_to = Nullch;
+ curspat = oldspat;
+ if (savestack->ary_fill > oldsave)
+ restorelist(oldsave);
+#ifdef DEBUGGING
+ dlevel = olddlevel;
+#endif
+ cmd = cmd->ucmd.ccmd.cc_alt;
+ goto tail_recursion_entry;
+ case C_ELSE:
+ oldspat = curspat;
+ oldsave = savestack->ary_fill;
+#ifdef DEBUGGING
+ olddlevel = dlevel;
+#endif
+ retstr = &str_undef;
+ newsp = -2;
+ if (cmd->ucmd.ccmd.cc_true) {
+#ifdef DEBUGGING
+ if (debug) {
+ debname[dlevel] = 'e';
+ debdelim[dlevel] = '_';
+ if (++dlevel >= dlmax)
+ grow_dlevel();
+ }
+#endif
+ newsp = cmd_exec(cmd->ucmd.ccmd.cc_true,gimme && (cmdflags & CF_TERM),sp);
+ st = stack->ary_array; /* possibly reallocated */
+ retstr = st[newsp];
+ }
+ if (!goto_targ)
+ go_to = Nullch;
+ curspat = oldspat;
+ if (savestack->ary_fill > oldsave)
+ restorelist(oldsave);
+#ifdef DEBUGGING
+ dlevel = olddlevel;
+#endif
+ break;
+ case C_BLOCK:
+ case C_WHILE:
+ if (!(cmdflags & CF_ONCE)) {
+ cmdflags |= CF_ONCE;
+ if (++loop_ptr >= loop_max) {
+ loop_max += 128;
+ Renew(loop_stack, loop_max, struct loop);
+ }
+ loop_stack[loop_ptr].loop_label = cmd->c_label;
+ loop_stack[loop_ptr].loop_sp = sp;
+#ifdef DEBUGGING
+ if (debug & 4) {
+ deb("(Pushing label #%d %s)\n",
+ loop_ptr, cmd->c_label ? cmd->c_label : "");
+ }
+#endif
+ }
+#ifdef JMPCLOBBER
+ cmdparm = cmd;
+#endif
+ match = setjmp(loop_stack[loop_ptr].loop_env);
+ if (match) {
+ st = stack->ary_array; /* possibly reallocated */
+#ifdef JMPCLOBBER
+ cmd = cmdparm;
+ cmdflags = cmd->c_flags|CF_ONCE;
+#endif
+ if (savestack->ary_fill > oldsave)
+ restorelist(oldsave);
+ switch (match) {
+ default:
+ fatal("longjmp returned bad value (%d)",match);
+ case O_LAST: /* not done unless go_to found */
+ go_to = Nullch;
+ if (lastretstr) {
+ retstr = lastretstr;
+ newsp = -2;
+ }
+ else {
+ newsp = sp + lastsize;
+ retstr = st[newsp];
+ }
+#ifdef DEBUGGING
+ olddlevel = dlevel;
+#endif
+ curspat = oldspat;
+ goto next_cmd;
+ case O_NEXT: /* not done unless go_to found */
+ go_to = Nullch;
+#ifdef JMPCLOBBER
+ newsp = -2;
+ retstr = &str_undef;
+#endif
+ goto next_iter;
+ case O_REDO: /* not done unless go_to found */
+ go_to = Nullch;
+#ifdef JMPCLOBBER
+ newsp = -2;
+ retstr = &str_undef;
+#endif
+ goto doit;
+ }
+ }
+ oldspat = curspat;
+ oldsave = savestack->ary_fill;
+#ifdef DEBUGGING
+ olddlevel = dlevel;
+#endif
+ if (cmd->ucmd.ccmd.cc_true) {
+#ifdef DEBUGGING
+ if (debug) {
+ debname[dlevel] = 't';
+ debdelim[dlevel] = '_';
+ if (++dlevel >= dlmax)
+ grow_dlevel();
+ }
+#endif
+ newsp = cmd_exec(cmd->ucmd.ccmd.cc_true,gimme && (cmdflags & CF_TERM),sp);
+ st = stack->ary_array; /* possibly reallocated */
+ if (newsp >= 0)
+ retstr = st[newsp];
+ }
+ if (!goto_targ) {
+ go_to = Nullch;
+ goto next_iter;
+ }
+#ifdef DEBUGGING
+ dlevel = olddlevel;
+#endif
+ if (cmd->ucmd.ccmd.cc_alt) {
+#ifdef DEBUGGING
+ if (debug) {
+ debname[dlevel] = 'a';
+ debdelim[dlevel] = '_';
+ if (++dlevel >= dlmax)
+ grow_dlevel();
+ }
+#endif
+ newsp = cmd_exec(cmd->ucmd.ccmd.cc_alt,gimme && (cmdflags & CF_TERM),sp);
+ st = stack->ary_array; /* possibly reallocated */
+ if (newsp >= 0)
+ retstr = st[newsp];
+ }
+ if (goto_targ)
+ break;
+ go_to = Nullch;
+ goto finish_while;
+ }
+ cmd = cmd->c_next;
+ if (cmd && cmd->c_head == cmd)
+ /* reached end of while loop */
+ return sp; /* targ isn't in this block */
+ if (cmdflags & CF_ONCE) {
+#ifdef DEBUGGING
+ if (debug & 4) {
+ tmps = loop_stack[loop_ptr].loop_label;
+ deb("(Popping label #%d %s)\n",loop_ptr,
+ tmps ? tmps : "" );
+ }
+#endif
+ loop_ptr--;
+ }
+ goto tail_recursion_entry;
+ }
+ }
+
+until_loop:
+
+ /* Set line number so run-time errors can be located */
+
+ curcmd = cmd;
+
+#ifdef DEBUGGING
+ if (debug) {
+ if (debug & 2) {
+ deb("%s (%lx) r%lx t%lx a%lx n%lx cs%lx\n",
+ cmdname[cmd->c_type],cmd,cmd->c_expr,
+ cmd->ucmd.ccmd.cc_true,cmd->ucmd.ccmd.cc_alt,cmd->c_next,
+ curspat);
+ }
+ debname[dlevel] = cmdname[cmd->c_type][0];
+ debdelim[dlevel] = '!';
+ if (++dlevel >= dlmax)
+ grow_dlevel();
+ }
+#endif
+
+ /* Here is some common optimization */
+
+ if (cmdflags & CF_COND) {
+ switch (cmdflags & CF_OPTIMIZE) {
+
+ case CFT_FALSE:
+ retstr = cmd->c_short;
+ newsp = -2;
+ match = FALSE;
+ if (cmdflags & CF_NESURE)
+ goto maybe;
+ break;
+ case CFT_TRUE:
+ retstr = cmd->c_short;
+ newsp = -2;
+ match = TRUE;
+ if (cmdflags & CF_EQSURE)
+ goto flipmaybe;
+ break;
+
+ case CFT_REG:
+ retstr = STAB_STR(cmd->c_stab);
+ newsp = -2;
+ match = str_true(retstr); /* => retstr = retstr, c2 should fix */
+ if (cmdflags & (match ? CF_EQSURE : CF_NESURE))
+ goto flipmaybe;
+ break;
+
+ case CFT_ANCHOR: /* /^pat/ optimization */
+ if (multiline) {
+ if (*cmd->c_short->str_ptr && !(cmdflags & CF_EQSURE))
+ goto scanner; /* just unanchor it */
+ else
+ break; /* must evaluate */
+ }
+ match = 0;
+ goto strop;
+
+ case CFT_STROP: /* string op optimization */
+ match = 1;
+ strop:
+ retstr = STAB_STR(cmd->c_stab);
+ newsp = -2;
+#ifndef I286
+ if (*cmd->c_short->str_ptr == *str_get(retstr) &&
+ (match ? retstr->str_cur == cmd->c_slen - 1 :
+ retstr->str_cur >= cmd->c_slen) &&
+ bcmp(cmd->c_short->str_ptr, str_get(retstr),
+ cmd->c_slen) == 0 ) {
+ if (cmdflags & CF_EQSURE) {
+ if (sawampersand && (cmdflags & CF_OPTIMIZE) != CFT_STROP) {
+ curspat = Nullspat;
+ if (leftstab)
+ str_nset(stab_val(leftstab),"",0);
+ if (amperstab)
+ str_sset(stab_val(amperstab),cmd->c_short);
+ if (rightstab)
+ str_nset(stab_val(rightstab),
+ retstr->str_ptr + cmd->c_slen,
+ retstr->str_cur - cmd->c_slen);
+ }
+ if (cmd->c_spat)
+ lastspat = cmd->c_spat;
+ match = !(cmdflags & CF_FIRSTNEG);
+ retstr = match ? &str_yes : &str_no;
+ goto flipmaybe;
+ }
+ }
+ else if (cmdflags & CF_NESURE) {
+ match = cmdflags & CF_FIRSTNEG;
+ retstr = match ? &str_yes : &str_no;
+ goto flipmaybe;
+ }
+#else
+ {
+ char *zap1, *zap2, zap1c, zap2c;
+ int zaplen;
+ int lenok;
+
+ zap1 = cmd->c_short->str_ptr;
+ zap2 = str_get(retstr);
+ zap1c = *zap1;
+ zap2c = *zap2;
+ zaplen = cmd->c_slen;
+ if (match)
+ lenok = (retstr->str_cur == cmd->c_slen - 1);
+ else
+ lenok = (retstr->str_cur >= cmd->c_slen);
+ if ((zap1c == zap2c) && lenok && (bcmp(zap1, zap2, zaplen) == 0)) {
+ if (cmdflags & CF_EQSURE) {
+ if (sawampersand &&
+ (cmdflags & CF_OPTIMIZE) != CFT_STROP) {
+ curspat = Nullspat;
+ if (leftstab)
+ str_nset(stab_val(leftstab),"",0);
+ if (amperstab)
+ str_sset(stab_val(amperstab),cmd->c_short);
+ if (rightstab)
+ str_nset(stab_val(rightstab),
+ retstr->str_ptr + cmd->c_slen,
+ retstr->str_cur - cmd->c_slen);
+ }
+ if (cmd->c_spat)
+ lastspat = cmd->c_spat;
+ match = !(cmdflags & CF_FIRSTNEG);
+ retstr = match ? &str_yes : &str_no;
+ goto flipmaybe;
+ }
+ }
+ else if (cmdflags & CF_NESURE) {
+ match = cmdflags & CF_FIRSTNEG;
+ retstr = match ? &str_yes : &str_no;
+ goto flipmaybe;
+ }
+ }
+#endif
+ break; /* must evaluate */
+
+ case CFT_SCAN: /* non-anchored search */
+ scanner:
+ retstr = STAB_STR(cmd->c_stab);
+ newsp = -2;
+ if (retstr->str_pok & SP_STUDIED)
+ if (screamfirst[cmd->c_short->str_rare] >= 0)
+ tmps = screaminstr(retstr, cmd->c_short);
+ else
+ tmps = Nullch;
+ else {
+ tmps = str_get(retstr); /* make sure it's pok */
+#ifndef lint
+ tmps = fbminstr((unsigned char*)tmps,
+ (unsigned char*)tmps + retstr->str_cur, cmd->c_short);
+#endif
+ }
+ if (tmps) {
+ if (cmdflags & CF_EQSURE) {
+ ++cmd->c_short->str_u.str_useful;
+ if (sawampersand) {
+ curspat = Nullspat;
+ if (leftstab)
+ str_nset(stab_val(leftstab),retstr->str_ptr,
+ tmps - retstr->str_ptr);
+ if (amperstab)
+ str_nset(stab_val(amperstab),
+ tmps, cmd->c_short->str_cur);
+ if (rightstab)
+ str_nset(stab_val(rightstab),
+ tmps + cmd->c_short->str_cur,
+ retstr->str_cur - (tmps - retstr->str_ptr) -
+ cmd->c_short->str_cur);
+ }
+ lastspat = cmd->c_spat;
+ match = !(cmdflags & CF_FIRSTNEG);
+ retstr = match ? &str_yes : &str_no;
+ goto flipmaybe;
+ }
+ else
+ hint = tmps;
+ }
+ else {
+ if (cmdflags & CF_NESURE) {
+ ++cmd->c_short->str_u.str_useful;
+ match = cmdflags & CF_FIRSTNEG;
+ retstr = match ? &str_yes : &str_no;
+ goto flipmaybe;
+ }
+ }
+ if (--cmd->c_short->str_u.str_useful < 0) {
+ cmdflags &= ~CF_OPTIMIZE;
+ cmdflags |= CFT_EVAL; /* never try this optimization again */
+ cmd->c_flags = (cmdflags & ~CF_ONCE);
+ }
+ break; /* must evaluate */
+
+ case CFT_NUMOP: /* numeric op optimization */
+ retstr = STAB_STR(cmd->c_stab);
+ newsp = -2;
+ switch (cmd->c_slen) {
+ case O_EQ:
+ if (dowarn) {
+ if ((!retstr->str_nok && !looks_like_number(retstr)))
+ warn("Possible use of == on string value");
+ }
+ match = (str_gnum(retstr) == cmd->c_short->str_u.str_nval);
+ break;
+ case O_NE:
+ match = (str_gnum(retstr) != cmd->c_short->str_u.str_nval);
+ break;
+ case O_LT:
+ match = (str_gnum(retstr) < cmd->c_short->str_u.str_nval);
+ break;
+ case O_LE:
+ match = (str_gnum(retstr) <= cmd->c_short->str_u.str_nval);
+ break;
+ case O_GT:
+ match = (str_gnum(retstr) > cmd->c_short->str_u.str_nval);
+ break;
+ case O_GE:
+ match = (str_gnum(retstr) >= cmd->c_short->str_u.str_nval);
+ break;
+ }
+ if (match) {
+ if (cmdflags & CF_EQSURE) {
+ retstr = &str_yes;
+ goto flipmaybe;
+ }
+ }
+ else if (cmdflags & CF_NESURE) {
+ retstr = &str_no;
+ goto flipmaybe;
+ }
+ break; /* must evaluate */
+
+ case CFT_INDGETS: /* while (<$foo>) */
+ last_in_stab = stabent(str_get(STAB_STR(cmd->c_stab)),TRUE);
+ if (!stab_io(last_in_stab))
+ stab_io(last_in_stab) = stio_new();
+ goto dogets;
+ case CFT_GETS: /* really a while (<file>) */
+ last_in_stab = cmd->c_stab;
+ dogets:
+ fp = stab_io(last_in_stab)->ifp;
+ retstr = stab_val(defstab);
+ newsp = -2;
+ keepgoing:
+ if (fp && str_gets(retstr, fp, 0)) {
+ if (*retstr->str_ptr == '0' && retstr->str_cur == 1)
+ match = FALSE;
+ else
+ match = TRUE;
+ stab_io(last_in_stab)->lines++;
+ }
+ else if (stab_io(last_in_stab)->flags & IOF_ARGV) {
+ if (!fp)
+ goto doeval; /* first time through */
+ fp = nextargv(last_in_stab);
+ if (fp)
+ goto keepgoing;
+ (void)do_close(last_in_stab,FALSE);
+ stab_io(last_in_stab)->flags |= IOF_START;
+ retstr = &str_undef;
+ match = FALSE;
+ }
+ else {
+ retstr = &str_undef;
+ match = FALSE;
+ }
+ goto flipmaybe;
+ case CFT_EVAL:
+ break;
+ case CFT_UNFLIP:
+ while (tmps_max > tmps_base) { /* clean up after last eval */
+ str_free(tmps_list[tmps_max]);
+ tmps_list[tmps_max--] = Nullstr;
+ }
+ newsp = eval(cmd->c_expr,gimme && (cmdflags & CF_TERM),sp);
+ st = stack->ary_array; /* possibly reallocated */
+ retstr = st[newsp];
+ match = str_true(retstr);
+ if (cmd->c_expr->arg_type == O_FLIP) /* undid itself? */
+ cmdflags = copyopt(cmd,cmd->c_expr[3].arg_ptr.arg_cmd);
+ goto maybe;
+ case CFT_CHOP:
+ retstr = stab_val(cmd->c_stab);
+ newsp = -2;
+ match = (retstr->str_cur != 0);
+ tmps = str_get(retstr);
+ tmps += retstr->str_cur - match;
+ str_nset(&strchop,tmps,match);
+ *tmps = '\0';
+ retstr->str_nok = 0;
+ retstr->str_cur = tmps - retstr->str_ptr;
+ STABSET(retstr);
+ retstr = &strchop;
+ goto flipmaybe;
+ case CFT_ARRAY:
+ match = cmd->c_short->str_u.str_useful; /* just to get register */
+
+ if (match < 0) { /* first time through here? */
+ ar = stab_array(cmd->c_expr[1].arg_ptr.arg_stab);
+ aryoptsave = savestack->ary_fill;
+ savesptr(&stab_val(cmd->c_stab));
+ savelong(&cmd->c_short->str_u.str_useful);
+ }
+ else {
+ ar = stab_xarray(cmd->c_expr[1].arg_ptr.arg_stab);
+ if (cmd->c_type != C_WHILE && savestack->ary_fill > firstsave)
+ restorelist(firstsave);
+ }
+
+ if (match >= ar->ary_fill) { /* we're in LAST, probably */
+ if (match < 0 && /* er, probably not... */
+ savestack->ary_fill > aryoptsave)
+ restorelist(aryoptsave);
+ retstr = &str_undef;
+ cmd->c_short->str_u.str_useful = -1; /* actually redundant */
+ match = FALSE;
+ }
+ else {
+ match++;
+ if (!(retstr = ar->ary_array[match]))
+ retstr = afetch(ar,match,TRUE);
+ stab_val(cmd->c_stab) = retstr;
+ cmd->c_short->str_u.str_useful = match;
+ match = TRUE;
+ }
+ newsp = -2;
+ goto maybe;
+ case CFT_D1:
+ break;
+ case CFT_D0:
+ if (DBsingle->str_u.str_nval != 0)
+ break;
+ if (DBsignal->str_u.str_nval != 0)
+ break;
+ if (DBtrace->str_u.str_nval != 0)
+ break;
+ goto next_cmd;
+ }
+
+ /* we have tried to make this normal case as abnormal as possible */
+
+ doeval:
+ if (gimme == G_ARRAY) {
+ lastretstr = Nullstr;
+ lastspbase = sp;
+ lastsize = newsp - sp;
+ if (lastsize < 0)
+ lastsize = 0;
+ }
+ else
+ lastretstr = retstr;
+ while (tmps_max > tmps_base) { /* clean up after last eval */
+ str_free(tmps_list[tmps_max]);
+ tmps_list[tmps_max--] = Nullstr;
+ }
+ newsp = eval(cmd->c_expr,
+ gimme && (cmdflags & CF_TERM) && cmd->c_type == C_EXPR &&
+ !cmd->ucmd.acmd.ac_expr,
+ sp);
+ st = stack->ary_array; /* possibly reallocated */
+ retstr = st[newsp];
+ if (newsp > sp && retstr)
+ match = str_true(retstr);
+ else
+ match = FALSE;
+ goto maybe;
+
+ /* if flipflop was true, flop it */
+
+ flipmaybe:
+ if (match && cmdflags & CF_FLIP) {
+ while (tmps_max > tmps_base) { /* clean up after last eval */
+ str_free(tmps_list[tmps_max]);
+ tmps_list[tmps_max--] = Nullstr;
+ }
+ if (cmd->c_expr->arg_type == O_FLOP) { /* currently toggled? */
+ newsp = eval(cmd->c_expr,G_SCALAR,sp);/*let eval undo it*/
+ cmdflags = copyopt(cmd,cmd->c_expr[3].arg_ptr.arg_cmd);
+ }
+ else {
+ newsp = eval(cmd->c_expr,G_SCALAR,sp);/* let eval do it */
+ if (cmd->c_expr->arg_type == O_FLOP) /* still toggled? */
+ cmdflags = copyopt(cmd,cmd->c_expr[4].arg_ptr.arg_cmd);
+ }
+ }
+ else if (cmdflags & CF_FLIP) {
+ if (cmd->c_expr->arg_type == O_FLOP) { /* currently toggled? */
+ match = TRUE; /* force on */
+ }
+ }
+
+ /* at this point, match says whether our expression was true */
+
+ maybe:
+ if (cmdflags & CF_INVERT)
+ match = !match;
+ if (!match)
+ goto next_cmd;
+ }
+#ifdef TAINT
+ tainted = 0; /* modifier doesn't affect regular expression */
+#endif
+
+ /* now to do the actual command, if any */
+
+ switch (cmd->c_type) {
+ case C_NULL:
+ fatal("panic: cmd_exec");
+ case C_EXPR: /* evaluated for side effects */
+ if (cmd->ucmd.acmd.ac_expr) { /* more to do? */
+ if (gimme == G_ARRAY) {
+ lastretstr = Nullstr;
+ lastspbase = sp;
+ lastsize = newsp - sp;
+ if (lastsize < 0)
+ lastsize = 0;
+ }
+ else
+ lastretstr = retstr;
+ while (tmps_max > tmps_base) { /* clean up after last eval */
+ str_free(tmps_list[tmps_max]);
+ tmps_list[tmps_max--] = Nullstr;
+ }
+ newsp = eval(cmd->ucmd.acmd.ac_expr,gimme && (cmdflags&CF_TERM),sp);
+ st = stack->ary_array; /* possibly reallocated */
+ retstr = st[newsp];
+ }
+ break;
+ case C_NSWITCH:
+ {
+ double value = str_gnum(STAB_STR(cmd->c_stab));
+
+ match = (int)value;
+ if (value < 0.0) {
+ if (((double)match) > value)
+ --match; /* was fractional--truncate other way */
+ }
+ }
+ goto doswitch;
+ case C_CSWITCH:
+ if (multiline) {
+ cmd = cmd->c_next; /* can't assume anything */
+ goto tail_recursion_entry;
+ }
+ match = *(str_get(STAB_STR(cmd->c_stab))) & 255;
+ doswitch:
+ match -= cmd->ucmd.scmd.sc_offset;
+ if (match < 0)
+ match = 0;
+ else if (match > cmd->ucmd.scmd.sc_max)
+ match = cmd->ucmd.scmd.sc_max;
+ cmd = cmd->ucmd.scmd.sc_next[match];
+ goto tail_recursion_entry;
+ case C_NEXT:
+ cmd = cmd->ucmd.ccmd.cc_alt;
+ goto tail_recursion_entry;
+ case C_ELSIF:
+ fatal("panic: ELSIF");
+ case C_IF:
+ oldspat = curspat;
+ oldsave = savestack->ary_fill;
+#ifdef DEBUGGING
+ olddlevel = dlevel;
+#endif
+ retstr = &str_yes;
+ newsp = -2;
+ if (cmd->ucmd.ccmd.cc_true) {
+#ifdef DEBUGGING
+ if (debug) {
+ debname[dlevel] = 't';
+ debdelim[dlevel] = '_';
+ if (++dlevel >= dlmax)
+ grow_dlevel();
+ }
+#endif
+ newsp = cmd_exec(cmd->ucmd.ccmd.cc_true,gimme && (cmdflags & CF_TERM),sp);
+ st = stack->ary_array; /* possibly reallocated */
+ retstr = st[newsp];
+ }
+ curspat = oldspat;
+ if (savestack->ary_fill > oldsave)
+ restorelist(oldsave);
+#ifdef DEBUGGING
+ dlevel = olddlevel;
+#endif
+ cmd = cmd->ucmd.ccmd.cc_alt;
+ goto tail_recursion_entry;
+ case C_ELSE:
+ oldspat = curspat;
+ oldsave = savestack->ary_fill;
+#ifdef DEBUGGING
+ olddlevel = dlevel;
+#endif
+ retstr = &str_undef;
+ newsp = -2;
+ if (cmd->ucmd.ccmd.cc_true) {
+#ifdef DEBUGGING
+ if (debug) {
+ debname[dlevel] = 'e';
+ debdelim[dlevel] = '_';
+ if (++dlevel >= dlmax)
+ grow_dlevel();
+ }
+#endif
+ newsp = cmd_exec(cmd->ucmd.ccmd.cc_true,gimme && (cmdflags & CF_TERM),sp);
+ st = stack->ary_array; /* possibly reallocated */
+ retstr = st[newsp];
+ }
+ curspat = oldspat;
+ if (savestack->ary_fill > oldsave)
+ restorelist(oldsave);
+#ifdef DEBUGGING
+ dlevel = olddlevel;
+#endif
+ break;
+ case C_BLOCK:
+ case C_WHILE:
+ if (!(cmdflags & CF_ONCE)) { /* first time through here? */
+ cmdflags |= CF_ONCE;
+ if (++loop_ptr >= loop_max) {
+ loop_max += 128;
+ Renew(loop_stack, loop_max, struct loop);
+ }
+ loop_stack[loop_ptr].loop_label = cmd->c_label;
+ loop_stack[loop_ptr].loop_sp = sp;
+#ifdef DEBUGGING
+ if (debug & 4) {
+ deb("(Pushing label #%d %s)\n",
+ loop_ptr, cmd->c_label ? cmd->c_label : "");
+ }
+#endif
+ }
+#ifdef JMPCLOBBER
+ cmdparm = cmd;
+#endif
+ match = setjmp(loop_stack[loop_ptr].loop_env);
+ if (match) {
+ st = stack->ary_array; /* possibly reallocated */
+#ifdef JMPCLOBBER
+ cmd = cmdparm;
+ cmdflags = cmd->c_flags|CF_ONCE;
+ go_to = goto_targ;
+#endif
+ if (savestack->ary_fill > oldsave)
+ restorelist(oldsave);
+ switch (match) {
+ default:
+ fatal("longjmp returned bad value (%d)",match);
+ case O_LAST:
+ if (lastretstr) {
+ retstr = lastretstr;
+ newsp = -2;
+ }
+ else {
+ newsp = sp + lastsize;
+ retstr = st[newsp];
+ }
+ curspat = oldspat;
+ goto next_cmd;
+ case O_NEXT:
+#ifdef JMPCLOBBER
+ newsp = -2;
+ retstr = &str_undef;
+#endif
+ goto next_iter;
+ case O_REDO:
+#ifdef DEBUGGING
+ dlevel = olddlevel;
+#endif
+#ifdef JMPCLOBBER
+ newsp = -2;
+ retstr = &str_undef;
+#endif
+ goto doit;
+ }
+ }
+ oldspat = curspat;
+ oldsave = savestack->ary_fill;
+#ifdef DEBUGGING
+ olddlevel = dlevel;
+#endif
+ doit:
+ if (cmd->ucmd.ccmd.cc_true) {
+#ifdef DEBUGGING
+ if (debug) {
+ debname[dlevel] = 't';
+ debdelim[dlevel] = '_';
+ if (++dlevel >= dlmax)
+ grow_dlevel();
+ }
+#endif
+ newsp = cmd_exec(cmd->ucmd.ccmd.cc_true,gimme && (cmdflags & CF_TERM),sp);
+ st = stack->ary_array; /* possibly reallocated */
+ retstr = st[newsp];
+ }
+ /* actually, this spot is rarely reached anymore since the above
+ * cmd_exec() returns through longjmp(). Hooray for structure.
+ */
+ next_iter:
+#ifdef DEBUGGING
+ dlevel = olddlevel;
+#endif
+ if (cmd->ucmd.ccmd.cc_alt) {
+#ifdef DEBUGGING
+ if (debug) {
+ debname[dlevel] = 'a';
+ debdelim[dlevel] = '_';
+ if (++dlevel >= dlmax)
+ grow_dlevel();
+ }
+#endif
+ newsp = cmd_exec(cmd->ucmd.ccmd.cc_alt,gimme && (cmdflags & CF_TERM),sp);
+ st = stack->ary_array; /* possibly reallocated */
+ retstr = st[newsp];
+ }
+ finish_while:
+ curspat = oldspat;
+ if (savestack->ary_fill > oldsave) {
+ if (cmdflags & CF_TERM) {
+ for (match = sp + 1; match <= newsp; match++)
+ st[match] = str_mortal(st[match]);
+ retstr = st[newsp];
+ }
+ restorelist(oldsave);
+ }
+#ifdef DEBUGGING
+ dlevel = olddlevel - 1;
+#endif
+ if (cmd->c_type != C_BLOCK)
+ goto until_loop; /* go back and evaluate conditional again */
+ }
+ if (cmdflags & CF_LOOP) {
+ cmdflags |= CF_COND; /* now test the condition */
+#ifdef DEBUGGING
+ dlevel = entdlevel;
+#endif
+ goto until_loop;
+ }
+ next_cmd:
+ if (cmdflags & CF_ONCE) {
+#ifdef DEBUGGING
+ if (debug & 4) {
+ tmps = loop_stack[loop_ptr].loop_label;
+ deb("(Popping label #%d %s)\n",loop_ptr, tmps ? tmps : "");
+ }
+#endif
+ loop_ptr--;
+ if ((cmdflags & CF_OPTIMIZE) == CFT_ARRAY &&
+ savestack->ary_fill > aryoptsave)
+ restorelist(aryoptsave);
+ }
+ cmd = cmd->c_next;
+ goto tail_recursion_entry;
+}
+
+#ifdef DEBUGGING
+# ifndef I_VARARGS
+/*VARARGS1*/
+void deb(pat,a1,a2,a3,a4,a5,a6,a7,a8)
+char *pat;
+{
+ register int i;
+
+ fprintf(stderr,"%-4ld",(long)curcmd->c_line);
+ for (i=0; i<dlevel; i++)
+ fprintf(stderr,"%c%c ",debname[i],debdelim[i]);
+ fprintf(stderr,pat,a1,a2,a3,a4,a5,a6,a7,a8);
+}
+# else
+/*VARARGS1*/
+void deb(va_alist)
+va_dcl
+{
+ va_list args;
+ char *pat;
+ register int i;
+
+ va_start(args);
+ fprintf(stderr,"%-4ld",(long)curcmd->c_line);
+ for (i=0; i<dlevel; i++)
+ fprintf(stderr,"%c%c ",debname[i],debdelim[i]);
+
+ pat = va_arg(args, char *);
+ (void) vfprintf(stderr,pat,args);
+ va_end( args );
+}
+# endif
+#endif
+
+int
+copyopt(cmd,which)
+register CMD *cmd;
+register CMD *which;
+{
+ cmd->c_flags &= CF_ONCE|CF_COND|CF_LOOP;
+ cmd->c_flags |= which->c_flags;
+ cmd->c_short = which->c_short;
+ cmd->c_slen = which->c_slen;
+ cmd->c_stab = which->c_stab;
+ return cmd->c_flags;
+}
+
+ARRAY *
+saveary(stab)
+STAB *stab;
+{
+ register STR *str;
+
+ str = Str_new(10,0);
+ str->str_state = SS_SARY;
+ str->str_u.str_stab = stab;
+ if (str->str_ptr) {
+ Safefree(str->str_ptr);
+ str->str_ptr = Nullch;
+ str->str_len = 0;
+ }
+ str->str_ptr = (char*)stab_array(stab);
+ (void)apush(savestack,str); /* save array ptr */
+ stab_xarray(stab) = Null(ARRAY*);
+ return stab_xarray(aadd(stab));
+}
+
+HASH *
+savehash(stab)
+STAB *stab;
+{
+ register STR *str;
+
+ str = Str_new(11,0);
+ str->str_state = SS_SHASH;
+ str->str_u.str_stab = stab;
+ if (str->str_ptr) {
+ Safefree(str->str_ptr);
+ str->str_ptr = Nullch;
+ str->str_len = 0;
+ }
+ str->str_ptr = (char*)stab_hash(stab);
+ (void)apush(savestack,str); /* save hash ptr */
+ stab_xhash(stab) = Null(HASH*);
+ return stab_xhash(hadd(stab));
+}
+
+void
+saveitem(item)
+register STR *item;
+{
+ register STR *str;
+
+ (void)apush(savestack,item); /* remember the pointer */
+ str = Str_new(12,0);
+ str_sset(str,item);
+ (void)apush(savestack,str); /* remember the value */
+}
+
+void
+saveint(intp)
+int *intp;
+{
+ register STR *str;
+
+ str = Str_new(13,0);
+ str->str_state = SS_SINT;
+ str->str_u.str_useful = (long)*intp; /* remember value */
+ if (str->str_ptr) {
+ Safefree(str->str_ptr);
+ str->str_len = 0;
+ }
+ str->str_ptr = (char*)intp; /* remember pointer */
+ (void)apush(savestack,str);
+}
+
+void
+savelong(longp)
+long *longp;
+{
+ register STR *str;
+
+ str = Str_new(14,0);
+ str->str_state = SS_SLONG;
+ str->str_u.str_useful = *longp; /* remember value */
+ if (str->str_ptr) {
+ Safefree(str->str_ptr);
+ str->str_len = 0;
+ }
+ str->str_ptr = (char*)longp; /* remember pointer */
+ (void)apush(savestack,str);
+}
+
+void
+savesptr(sptr)
+STR **sptr;
+{
+ register STR *str;
+
+ str = Str_new(15,0);
+ str->str_state = SS_SSTRP;
+ str->str_magic = *sptr; /* remember value */
+ if (str->str_ptr) {
+ Safefree(str->str_ptr);
+ str->str_len = 0;
+ }
+ str->str_ptr = (char*)sptr; /* remember pointer */
+ (void)apush(savestack,str);
+}
+
+void
+savenostab(stab)
+STAB *stab;
+{
+ register STR *str;
+
+ str = Str_new(16,0);
+ str->str_state = SS_SNSTAB;
+ str->str_magic = (STR*)stab; /* remember which stab to free */
+ (void)apush(savestack,str);
+}
+
+void
+savehptr(hptr)
+HASH **hptr;
+{
+ register STR *str;
+
+ str = Str_new(17,0);
+ str->str_state = SS_SHPTR;
+ str->str_u.str_hash = *hptr; /* remember value */
+ if (str->str_ptr) {
+ Safefree(str->str_ptr);
+ str->str_len = 0;
+ }
+ str->str_ptr = (char*)hptr; /* remember pointer */
+ (void)apush(savestack,str);
+}
+
+void
+saveaptr(aptr)
+ARRAY **aptr;
+{
+ register STR *str;
+
+ str = Str_new(17,0);
+ str->str_state = SS_SAPTR;
+ str->str_u.str_array = *aptr; /* remember value */
+ if (str->str_ptr) {
+ Safefree(str->str_ptr);
+ str->str_len = 0;
+ }
+ str->str_ptr = (char*)aptr; /* remember pointer */
+ (void)apush(savestack,str);
+}
+
+void
+savelist(sarg,maxsarg)
+register STR **sarg;
+int maxsarg;
+{
+ register STR *str;
+ register int i;
+
+ for (i = 1; i <= maxsarg; i++) {
+ (void)apush(savestack,sarg[i]); /* remember the pointer */
+ str = Str_new(18,0);
+ str_sset(str,sarg[i]);
+ (void)apush(savestack,str); /* remember the value */
+ sarg[i]->str_u.str_useful = -1;
+ }
+}
+
+void
+restorelist(base)
+int base;
+{
+ register STR *str;
+ register STR *value;
+ register STAB *stab;
+
+ if (base < -1)
+ fatal("panic: corrupt saved stack index");
+ while (savestack->ary_fill > base) {
+ value = apop(savestack);
+ switch (value->str_state) {
+ case SS_NORM: /* normal string */
+ case SS_INCR:
+ str = apop(savestack);
+ str_replace(str,value);
+ STABSET(str);
+ break;
+ case SS_SARY: /* array reference */
+ stab = value->str_u.str_stab;
+ afree(stab_xarray(stab));
+ stab_xarray(stab) = (ARRAY*)value->str_ptr;
+ value->str_ptr = Nullch;
+ str_free(value);
+ break;
+ case SS_SHASH: /* hash reference */
+ stab = value->str_u.str_stab;
+ (void)hfree(stab_xhash(stab), FALSE);
+ stab_xhash(stab) = (HASH*)value->str_ptr;
+ value->str_ptr = Nullch;
+ str_free(value);
+ break;
+ case SS_SINT: /* int reference */
+ *((int*)value->str_ptr) = (int)value->str_u.str_useful;
+ value->str_ptr = Nullch;
+ str_free(value);
+ break;
+ case SS_SLONG: /* long reference */
+ *((long*)value->str_ptr) = value->str_u.str_useful;
+ value->str_ptr = Nullch;
+ str_free(value);
+ break;
+ case SS_SSTRP: /* STR* reference */
+ *((STR**)value->str_ptr) = value->str_magic;
+ value->str_magic = Nullstr;
+ value->str_ptr = Nullch;
+ str_free(value);
+ break;
+ case SS_SHPTR: /* HASH* reference */
+ *((HASH**)value->str_ptr) = value->str_u.str_hash;
+ value->str_ptr = Nullch;
+ str_free(value);
+ break;
+ case SS_SAPTR: /* ARRAY* reference */
+ *((ARRAY**)value->str_ptr) = value->str_u.str_array;
+ value->str_ptr = Nullch;
+ str_free(value);
+ break;
+ case SS_SNSTAB:
+ stab = (STAB*)value->str_magic;
+ value->str_magic = Nullstr;
+ (void)stab_clear(stab);
+ str_free(value);
+ break;
+ case SS_SCSV: /* callsave structure */
+ {
+ CSV *csv = (CSV*) value->str_ptr;
+
+ curcmd = csv->curcmd;
+ curcsv = csv->curcsv;
+ csv->sub->depth = csv->depth;
+ if (csv->hasargs) { /* put back old @_ */
+ afree(csv->argarray);
+ stab_xarray(defstab) = csv->savearray;
+ }
+ str_free(value);
+ }
+ break;
+ default:
+ fatal("panic: restorelist inconsistency");
+ }
+ }
+}
+
+#ifdef DEBUGGING
+void
+grow_dlevel()
+{
+ dlmax += 128;
+ Renew(debname, dlmax, char);
+ Renew(debdelim, dlmax, char);
+}
+#endif
diff --git a/gnu/usr.bin/perl/perl/cmd.h b/gnu/usr.bin/perl/perl/cmd.h
new file mode 100644
index 0000000..da0fa8e
--- /dev/null
+++ b/gnu/usr.bin/perl/perl/cmd.h
@@ -0,0 +1,182 @@
+/* $RCSfile: cmd.h,v $$Revision: 1.1.1.1 $$Date: 1994/09/10 06:27:34 $
+ *
+ * Copyright (c) 1991, Larry Wall
+ *
+ * You may distribute under the terms of either the GNU General Public
+ * License or the Artistic License, as specified in the README file.
+ *
+ * $Log: cmd.h,v $
+ * Revision 1.1.1.1 1994/09/10 06:27:34 gclarkii
+ * Initial import of Perl 4.046 bmaked
+ *
+ * Revision 1.1.1.1 1993/08/23 21:29:35 nate
+ * PERL!
+ *
+ * Revision 4.0.1.2 92/06/08 12:01:02 lwall
+ * patch20: removed implicit int declarations on funcions
+ *
+ * Revision 4.0.1.1 91/06/07 10:28:50 lwall
+ * patch4: new copyright notice
+ * patch4: length($`), length($&), length($') now optimized to avoid string copy
+ *
+ * Revision 4.0 91/03/20 01:04:34 lwall
+ * 4.0 baseline.
+ *
+ */
+
+#define C_NULL 0
+#define C_IF 1
+#define C_ELSE 2
+#define C_WHILE 3
+#define C_BLOCK 4
+#define C_EXPR 5
+#define C_NEXT 6
+#define C_ELSIF 7 /* temporary--turns into an IF + ELSE */
+#define C_CSWITCH 8 /* created by switch optimization in block_head() */
+#define C_NSWITCH 9 /* likewise */
+
+#ifdef DEBUGGING
+#ifndef DOINIT
+extern char *cmdname[];
+#else
+char *cmdname[] = {
+ "NULL",
+ "IF",
+ "ELSE",
+ "WHILE",
+ "BLOCK",
+ "EXPR",
+ "NEXT",
+ "ELSIF",
+ "CSWITCH",
+ "NSWITCH",
+ "10"
+};
+#endif
+#endif /* DEBUGGING */
+
+#define CF_OPTIMIZE 077 /* type of optimization */
+#define CF_FIRSTNEG 0100/* conditional is ($register NE 'string') */
+#define CF_NESURE 0200 /* if short doesn't match we're sure */
+#define CF_EQSURE 0400 /* if short does match we're sure */
+#define CF_COND 01000 /* test c_expr as conditional first, if not null. */
+ /* Set for everything except do {} while currently */
+#define CF_LOOP 02000 /* loop on the c_expr conditional (loop modifiers) */
+#define CF_INVERT 04000 /* it's an "unless" or an "until" */
+#define CF_ONCE 010000 /* we've already pushed the label on the stack */
+#define CF_FLIP 020000 /* on a match do flipflop */
+#define CF_TERM 040000 /* value of this cmd might be returned */
+#define CF_DBSUB 0100000 /* this is an inserted cmd for debugging */
+
+#define CFT_FALSE 0 /* c_expr is always false */
+#define CFT_TRUE 1 /* c_expr is always true */
+#define CFT_REG 2 /* c_expr is a simple register */
+#define CFT_ANCHOR 3 /* c_expr is an anchored search /^.../ */
+#define CFT_STROP 4 /* c_expr is a string comparison */
+#define CFT_SCAN 5 /* c_expr is an unanchored search /.../ */
+#define CFT_GETS 6 /* c_expr is <filehandle> */
+#define CFT_EVAL 7 /* c_expr is not optimized, so call eval() */
+#define CFT_UNFLIP 8 /* 2nd half of range not optimized */
+#define CFT_CHOP 9 /* c_expr is a chop on a register */
+#define CFT_ARRAY 10 /* this is a foreach loop */
+#define CFT_INDGETS 11 /* c_expr is <$variable> */
+#define CFT_NUMOP 12 /* c_expr is a numeric comparison */
+#define CFT_CCLASS 13 /* c_expr must start with one of these characters */
+#define CFT_D0 14 /* no special breakpoint at this line */
+#define CFT_D1 15 /* possible special breakpoint at this line */
+
+#ifdef DEBUGGING
+#ifndef DOINIT
+extern char *cmdopt[];
+#else
+char *cmdopt[] = {
+ "FALSE",
+ "TRUE",
+ "REG",
+ "ANCHOR",
+ "STROP",
+ "SCAN",
+ "GETS",
+ "EVAL",
+ "UNFLIP",
+ "CHOP",
+ "ARRAY",
+ "INDGETS",
+ "NUMOP",
+ "CCLASS",
+ "14"
+};
+#endif
+#endif /* DEBUGGING */
+
+struct acmd {
+ STAB *ac_stab; /* a symbol table entry */
+ ARG *ac_expr; /* any associated expression */
+};
+
+struct ccmd {
+ CMD *cc_true; /* normal code to do on if and while */
+ CMD *cc_alt; /* else cmd ptr or continue code */
+};
+
+struct scmd {
+ CMD **sc_next; /* array of pointers to commands */
+ short sc_offset; /* first value - 1 */
+ short sc_max; /* last value + 1 */
+};
+
+struct cmd {
+ CMD *c_next; /* the next command at this level */
+ ARG *c_expr; /* conditional expression */
+ CMD *c_head; /* head of this command list */
+ STR *c_short; /* string to match as shortcut */
+ STAB *c_stab; /* a symbol table entry, mostly for fp */
+ SPAT *c_spat; /* pattern used by optimization */
+ char *c_label; /* label for this construct */
+ union ucmd {
+ struct acmd acmd; /* normal command */
+ struct ccmd ccmd; /* compound command */
+ struct scmd scmd; /* switch command */
+ } ucmd;
+ short c_slen; /* len of c_short, if not null */
+ VOLATILE short c_flags; /* optimization flags--see above */
+ HASH *c_stash; /* package line was compiled in */
+ STAB *c_filestab; /* file the following line # is from */
+ line_t c_line; /* line # of this command */
+ char c_type; /* what this command does */
+};
+
+#define Nullcmd Null(CMD*)
+#define Nullcsv Null(CSV*)
+
+EXT CMD * VOLATILE main_root INIT(Nullcmd);
+EXT CMD * VOLATILE eval_root INIT(Nullcmd);
+
+EXT CMD compiling;
+EXT CMD * VOLATILE curcmd INIT(&compiling);
+EXT CSV * VOLATILE curcsv INIT(Nullcsv);
+
+struct callsave {
+ SUBR *sub;
+ STAB *stab;
+ CSV *curcsv;
+ CMD *curcmd;
+ ARRAY *savearray;
+ ARRAY *argarray;
+ long depth;
+ int wantarray;
+ char hasargs;
+};
+
+struct compcmd {
+ CMD *comp_true;
+ CMD *comp_alt;
+};
+
+void opt_arg();
+ARG* evalstatic();
+int cmd_exec();
+#ifdef DEBUGGING
+void deb();
+#endif
+int copyopt();
diff --git a/gnu/usr.bin/perl/perl/config.H b/gnu/usr.bin/perl/perl/config.H
new file mode 100644
index 0000000..e3d054e
--- /dev/null
+++ b/gnu/usr.bin/perl/perl/config.H
@@ -0,0 +1,892 @@
+#ifndef config_h
+#define config_h
+/* config.h
+ * This file was produced by running the config.h.SH script, which
+ * gets its values from config.sh, which is generally produced by
+ * running Configure.
+ *
+ * Feel free to modify any of this as the need arises. Note, however,
+ * that running config.h.SH again will wipe out any changes you've made.
+ * For a more permanent change edit config.sh and rerun config.h.SH.
+ */
+ /*SUPPRESS 460*/
+
+
+/* EUNICE
+ * This symbol, if defined, indicates that the program is being compiled
+ * under the EUNICE package under VMS. The program will need to handle
+ * things like files that don't go away the first time you unlink them,
+ * due to version numbering. It will also need to compensate for lack
+ * of a respectable link() command.
+ */
+/* VMS
+ * This symbol, if defined, indicates that the program is running under
+ * VMS. It is currently only set in conjunction with the EUNICE symbol.
+ */
+/*#undef EUNICE /**/
+/*#undef VMS /**/
+
+/* LOC_SED
+ * This symbol holds the complete pathname to the sed program.
+ */
+#define LOC_SED "/bin/sed" /**/
+
+/* ALIGN_BYTES
+ * This symbol contains the number of bytes required to align a double.
+ * Usual values are 2, 4, and 8.
+ */
+#define ALIGN_BYTES 8 /**/
+
+/* BIN
+ * This symbol holds the name of the directory in which the user wants
+ * to keep publicly executable images for the package in question. It
+ * is most often a local directory such as /usr/local/bin.
+ */
+#define BIN "/usr/bin" /**/
+
+/* BYTEORDER
+ * This symbol contains an encoding of the order of bytes in a long.
+ * Usual values (in hex) are 0x1234, 0x4321, 0x2143, 0x3412...
+ */
+#define BYTEORDER 0x4321 /**/
+
+/* CPPSTDIN
+ * This symbol contains the first part of the string which will invoke
+ * the C preprocessor on the standard input and produce to standard
+ * output. Typical value of "cc -E" or "/lib/cpp".
+ */
+/* CPPMINUS
+ * This symbol contains the second part of the string which will invoke
+ * the C preprocessor on the standard input and produce to standard
+ * output. This symbol will have the value "-" if CPPSTDIN needs a minus
+ * to specify standard input, otherwise the value is "".
+ */
+#define CPPSTDIN "/usr/lib/cpp"
+#define CPPMINUS ""
+
+/* HAS_BCMP
+ * This symbol, if defined, indicates that the bcmp routine is available
+ * to compare blocks of memory. If undefined, use memcmp. If that's
+ * not available, roll your own.
+ */
+#define HAS_BCMP /**/
+
+/* HAS_BCOPY
+ * This symbol, if defined, indicates that the bcopy routine is available
+ * to copy blocks of memory. Otherwise you should probably use memcpy().
+ * If neither is defined, roll your own.
+ */
+/* SAFE_BCOPY
+ * This symbol, if defined, indicates that the bcopy routine is available
+ * to copy potentially overlapping copy blocks of bcopy. Otherwise you
+ * should probably use memmove() or memcpy(). If neither is defined,
+ * roll your own.
+ */
+#define HAS_BCOPY /**/
+#define SAFE_BCOPY /**/
+
+/* HAS_BZERO
+ * This symbol, if defined, indicates that the bzero routine is available
+ * to zero blocks of memory. Otherwise you should probably use memset()
+ * or roll your own.
+ */
+#define HAS_BZERO /**/
+
+/* CASTNEGFLOAT
+ * This symbol, if defined, indicates that this C compiler knows how to
+ * cast negative or large floating point numbers to unsigned longs, ints
+ * and shorts.
+ */
+/* CASTFLAGS
+ * This symbol contains flags that say what difficulties the compiler
+ * has casting odd floating values to unsigned long:
+ * 1 = couldn't cast < 0
+ * 2 = couldn't cast >= 0x80000000
+ */
+#define CASTNEGFLOAT /**/
+#define CASTFLAGS 0 /**/
+
+/* CHARSPRINTF
+ * This symbol is defined if this system declares "char *sprintf()" in
+ * stdio.h. The trend seems to be to declare it as "int sprintf()". It
+ * is up to the package author to declare sprintf correctly based on the
+ * symbol.
+ */
+#define CHARSPRINTF /**/
+
+/* HAS_CHSIZE
+ * This symbol, if defined, indicates that the chsize routine is available
+ * to truncate files. You might need a -lx to get this routine.
+ */
+/*#undef HAS_CHSIZE /**/
+
+/* HAS_CRYPT
+ * This symbol, if defined, indicates that the crypt routine is available
+ * to encrypt passwords and the like.
+ */
+#define HAS_CRYPT /**/
+
+/* CSH
+ * This symbol, if defined, indicates that the C-shell exists.
+ * If defined, contains the full pathname of csh.
+ */
+#define CSH "/bin/csh" /**/
+
+/* DOSUID
+ * This symbol, if defined, indicates that the C program should
+ * check the script that it is executing for setuid/setgid bits, and
+ * attempt to emulate setuid/setgid on systems that have disabled
+ * setuid #! scripts because the kernel can't do it securely.
+ * It is up to the package designer to make sure that this emulation
+ * is done securely. Among other things, it should do an fstat on
+ * the script it just opened to make sure it really is a setuid/setgid
+ * script, it should make sure the arguments passed correspond exactly
+ * to the argument on the #! line, and it should not trust any
+ * subprocesses to which it must pass the filename rather than the
+ * file descriptor of the script to be executed.
+ */
+/*#undef DOSUID /**/
+
+/* HAS_DUP2
+ * This symbol, if defined, indicates that the dup2 routine is available
+ * to dup file descriptors. Otherwise you should use dup().
+ */
+#define HAS_DUP2 /**/
+
+/* HAS_FCHMOD
+ * This symbol, if defined, indicates that the fchmod routine is available
+ * to change mode of opened files. If unavailable, use chmod().
+ */
+#define HAS_FCHMOD /**/
+
+/* HAS_FCHOWN
+ * This symbol, if defined, indicates that the fchown routine is available
+ * to change ownership of opened files. If unavailable, use chown().
+ */
+#define HAS_FCHOWN /**/
+
+/* HAS_FCNTL
+ * This symbol, if defined, indicates to the C program that
+ * the fcntl() function exists.
+ */
+#define HAS_FCNTL /**/
+
+/* FLEXFILENAMES
+ * This symbol, if defined, indicates that the system supports filenames
+ * longer than 14 characters.
+ */
+#define FLEXFILENAMES /**/
+
+/* HAS_FLOCK
+ * This symbol, if defined, indicates that the flock() routine is
+ * available to do file locking.
+ */
+#define HAS_FLOCK /**/
+
+/* HAS_GETGROUPS
+ * This symbol, if defined, indicates that the getgroups() routine is
+ * available to get the list of process groups. If unavailable, multiple
+ * groups are probably not supported.
+ */
+#define HAS_GETGROUPS /**/
+
+/* HAS_GETHOSTENT
+ * This symbol, if defined, indicates that the gethostent() routine is
+ * available to lookup host names in some data base or other.
+ */
+#define HAS_GETHOSTENT /**/
+
+/* HAS_GETPGRP
+ * This symbol, if defined, indicates that the getpgrp() routine is
+ * available to get the current process group.
+ */
+#define HAS_GETPGRP /**/
+
+/* HAS_GETPGRP2
+ * This symbol, if defined, indicates that the getpgrp2() (as in DG/UX)
+ * routine is available to get the current process group.
+ */
+/*#undef HAS_GETPGRP2 /**/
+
+/* HAS_GETPRIORITY
+ * This symbol, if defined, indicates that the getpriority() routine is
+ * available to get a process's priority.
+ */
+#define HAS_GETPRIORITY /**/
+
+/* HAS_HTONS
+ * This symbol, if defined, indicates that the htons routine (and friends)
+ * are available to do network order byte swapping.
+ */
+/* HAS_HTONL
+ * This symbol, if defined, indicates that the htonl routine (and friends)
+ * are available to do network order byte swapping.
+ */
+/* HAS_NTOHS
+ * This symbol, if defined, indicates that the ntohs routine (and friends)
+ * are available to do network order byte swapping.
+ */
+/* HAS_NTOHL
+ * This symbol, if defined, indicates that the ntohl routine (and friends)
+ * are available to do network order byte swapping.
+ */
+#define HAS_HTONS /**/
+#define HAS_HTONL /**/
+#define HAS_NTOHS /**/
+#define HAS_NTOHL /**/
+
+/* index
+ * This preprocessor symbol is defined, along with rindex, if the system
+ * uses the strchr and strrchr routines instead.
+ */
+/* rindex
+ * This preprocessor symbol is defined, along with index, if the system
+ * uses the strchr and strrchr routines instead.
+ */
+/*#undef index strchr /* cultural */
+/*#undef rindex strrchr /* differences? */
+
+/* HAS_ISASCII
+ * This symbol, if defined, indicates that the isascii routine is available
+ * to test characters for asciiness.
+ */
+#define HAS_ISASCII /**/
+
+/* HAS_KILLPG
+ * This symbol, if defined, indicates that the killpg routine is available
+ * to kill process groups. If unavailable, you probably should use kill
+ * with a negative process number.
+ */
+#define HAS_KILLPG /**/
+
+/* HAS_LSTAT
+ * This symbol, if defined, indicates that the lstat() routine is
+ * available to stat symbolic links.
+ */
+#define HAS_LSTAT /**/
+
+/* HAS_MEMCMP
+ * This symbol, if defined, indicates that the memcmp routine is available
+ * to compare blocks of memory. If undefined, roll your own.
+ */
+#define HAS_MEMCMP /**/
+
+/* HAS_MEMCPY
+ * This symbol, if defined, indicates that the memcpy routine is available
+ * to copy blocks of memory. Otherwise you should probably use bcopy().
+ * If neither is defined, roll your own.
+ */
+/* SAFE_MEMCPY
+ * This symbol, if defined, indicates that the memcpy routine is available
+ * to copy potentially overlapping copy blocks of memory. Otherwise you
+ * should probably use memmove() or bcopy(). If neither is defined,
+ * roll your own.
+ */
+#define HAS_MEMCPY /**/
+/*#undef SAFE_MEMCPY /**/
+
+/* HAS_MEMMOVE
+ * This symbol, if defined, indicates that the memmove routine is available
+ * to move potentially overlapping blocks of memory. Otherwise you
+ * should use bcopy() or roll your own.
+ */
+/*#undef HAS_MEMMOVE /**/
+
+/* HAS_MEMSET
+ * This symbol, if defined, indicates that the memset routine is available
+ * to set a block of memory to a character. If undefined, roll your own.
+ */
+#define HAS_MEMSET /**/
+
+/* HAS_MKDIR
+ * This symbol, if defined, indicates that the mkdir routine is available
+ * to create directories. Otherwise you should fork off a new process to
+ * exec /bin/mkdir.
+ */
+#define HAS_MKDIR /**/
+
+/* HAS_MSG
+ * This symbol, if defined, indicates that the entire msg*(2) library is
+ * supported.
+ */
+#define HAS_MSG /**/
+
+/* HAS_MSGCTL
+ * This symbol, if defined, indicates that the msgctl() routine is
+ * available to control message passing.
+ */
+#define HAS_MSGCTL /**/
+
+/* HAS_MSGGET
+ * This symbol, if defined, indicates that the msgget() routine is
+ * available to get messages.
+ */
+#define HAS_MSGGET /**/
+
+/* HAS_MSGRCV
+ * This symbol, if defined, indicates that the msgrcv() routine is
+ * available to receive messages.
+ */
+#define HAS_MSGRCV /**/
+
+/* HAS_MSGSND
+ * This symbol, if defined, indicates that the msgsnd() routine is
+ * available to send messages.
+ */
+#define HAS_MSGSND /**/
+
+/* HAS_NDBM
+ * This symbol, if defined, indicates that ndbm.h exists and should
+ * be included.
+ */
+#define HAS_NDBM /**/
+
+/* HAS_ODBM
+ * This symbol, if defined, indicates that dbm.h exists and should
+ * be included.
+ */
+#define HAS_ODBM /**/
+
+/* HAS_OPEN3
+ * This manifest constant lets the C program know that the three
+ * argument form of open(2) is available.
+ */
+#define HAS_OPEN3 /**/
+
+/* HAS_READDIR
+ * This symbol, if defined, indicates that the readdir routine is available
+ * from the C library to read directories.
+ */
+#define HAS_READDIR /**/
+
+/* HAS_RENAME
+ * This symbol, if defined, indicates that the rename routine is available
+ * to rename files. Otherwise you should do the unlink(), link(), unlink()
+ * trick.
+ */
+#define HAS_RENAME /**/
+
+/* HAS_REWINDDIR
+ * This symbol, if defined, indicates that the rewindir routine is
+ * available to rewind directories.
+ */
+#define HAS_REWINDDIR /**/
+
+/* HAS_RMDIR
+ * This symbol, if defined, indicates that the rmdir routine is available
+ * to remove directories. Otherwise you should fork off a new process to
+ * exec /bin/rmdir.
+ */
+#define HAS_RMDIR /**/
+
+/* HAS_SEEKDIR
+ * This symbol, if defined, indicates that the seekdir routine is
+ * available to seek into directories.
+ */
+#define HAS_SEEKDIR /**/
+
+/* HAS_SELECT
+ * This symbol, if defined, indicates that the select() subroutine
+ * exists.
+ */
+#define HAS_SELECT /**/
+
+/* HAS_SEM
+ * This symbol, if defined, indicates that the entire sem*(2) library is
+ * supported.
+ */
+#define HAS_SEM /**/
+
+/* HAS_SEMCTL
+ * This symbol, if defined, indicates that the semctl() routine is
+ * available to control semaphores.
+ */
+#define HAS_SEMCTL /**/
+
+/* HAS_SEMGET
+ * This symbol, if defined, indicates that the semget() routine is
+ * available to get semaphores ids.
+ */
+#define HAS_SEMGET /**/
+
+/* HAS_SEMOP
+ * This symbol, if defined, indicates that the semop() routine is
+ * available to perform semaphore operations.
+ */
+#define HAS_SEMOP /**/
+
+/* HAS_SETEGID
+ * This symbol, if defined, indicates that the setegid routine is available
+ * to change the effective gid of the current program.
+ */
+#define HAS_SETEGID /**/
+
+/* HAS_SETEUID
+ * This symbol, if defined, indicates that the seteuid routine is available
+ * to change the effective uid of the current program.
+ */
+#define HAS_SETEUID /**/
+
+/* HAS_SETPGRP
+ * This symbol, if defined, indicates that the setpgrp() routine is
+ * available to set the current process group.
+ */
+#define HAS_SETPGRP /**/
+
+/* HAS_SETPGRP2
+ * This symbol, if defined, indicates that the setpgrp2() (as in DG/UX)
+ * routine is available to set the current process group.
+ */
+/*#undef HAS_SETPGRP2 /**/
+
+/* HAS_SETPRIORITY
+ * This symbol, if defined, indicates that the setpriority() routine is
+ * available to set a process's priority.
+ */
+#define HAS_SETPRIORITY /**/
+
+/* HAS_SETREGID
+ * This symbol, if defined, indicates that the setregid routine is
+ * available to change the real and effective gid of the current program.
+ */
+/* HAS_SETRESGID
+ * This symbol, if defined, indicates that the setresgid routine is
+ * available to change the real, effective and saved gid of the current
+ * program.
+ */
+#define HAS_SETREGID /**/
+/*#undef HAS_SETRESGID /**/
+
+/* HAS_SETREUID
+ * This symbol, if defined, indicates that the setreuid routine is
+ * available to change the real and effective uid of the current program.
+ */
+/* HAS_SETRESUID
+ * This symbol, if defined, indicates that the setresuid routine is
+ * available to change the real, effective and saved uid of the current
+ * program.
+ */
+#define HAS_SETREUID /**/
+/*#undef HAS_SETRESUID /**/
+
+/* HAS_SETRGID
+ * This symbol, if defined, indicates that the setrgid routine is available
+ * to change the real gid of the current program.
+ */
+#define HAS_SETRGID /**/
+
+/* HAS_SETRUID
+ * This symbol, if defined, indicates that the setruid routine is available
+ * to change the real uid of the current program.
+ */
+#define HAS_SETRUID /**/
+
+/* HAS_SHM
+ * This symbol, if defined, indicates that the entire shm*(2) library is
+ * supported.
+ */
+#define HAS_SHM /**/
+
+/* HAS_SHMAT
+ * This symbol, if defined, indicates that the shmat() routine is
+ * available to attach a shared memory segment.
+ */
+/* VOID_SHMAT
+ * This symbol, if defined, indicates that the shmat() routine
+ * returns a pointer of type void*.
+ */
+#define HAS_SHMAT /**/
+
+/*#undef VOIDSHMAT /**/
+
+/* HAS_SHMCTL
+ * This symbol, if defined, indicates that the shmctl() routine is
+ * available to control a shared memory segment.
+ */
+#define HAS_SHMCTL /**/
+
+/* HAS_SHMDT
+ * This symbol, if defined, indicates that the shmdt() routine is
+ * available to detach a shared memory segment.
+ */
+#define HAS_SHMDT /**/
+
+/* HAS_SHMGET
+ * This symbol, if defined, indicates that the shmget() routine is
+ * available to get a shared memory segment id.
+ */
+#define HAS_SHMGET /**/
+
+/* HAS_SOCKET
+ * This symbol, if defined, indicates that the BSD socket interface is
+ * supported.
+ */
+/* HAS_SOCKETPAIR
+ * This symbol, if defined, indicates that the BSD socketpair call is
+ * supported.
+ */
+/* OLDSOCKET
+ * This symbol, if defined, indicates that the 4.1c BSD socket interface
+ * is supported instead of the 4.2/4.3 BSD socket interface.
+ */
+#define HAS_SOCKET /**/
+
+#define HAS_SOCKETPAIR /**/
+
+/*#undef OLDSOCKET /**/
+
+/* STATBLOCKS
+ * This symbol is defined if this system has a stat structure declaring
+ * st_blksize and st_blocks.
+ */
+#define STATBLOCKS /**/
+
+/* STDSTDIO
+ * This symbol is defined if this system has a FILE structure declaring
+ * _ptr and _cnt in stdio.h.
+ */
+#define STDSTDIO /**/
+
+/* STRUCTCOPY
+ * This symbol, if defined, indicates that this C compiler knows how
+ * to copy structures. If undefined, you'll need to use a block copy
+ * routine of some sort instead.
+ */
+#define STRUCTCOPY /**/
+
+/* HAS_STRERROR
+ * This symbol, if defined, indicates that the strerror() routine is
+ * available to translate error numbers to strings.
+ */
+/*#undef HAS_STRERROR /**/
+
+/* HAS_SYMLINK
+ * This symbol, if defined, indicates that the symlink routine is available
+ * to create symbolic links.
+ */
+#define HAS_SYMLINK /**/
+
+/* HAS_SYSCALL
+ * This symbol, if defined, indicates that the syscall routine is available
+ * to call arbitrary system calls. If undefined, that's tough.
+ */
+#define HAS_SYSCALL /**/
+
+/* HAS_TELLDIR
+ * This symbol, if defined, indicates that the telldir routine is
+ * available to tell your location in directories.
+ */
+#define HAS_TELLDIR /**/
+
+/* HAS_TRUNCATE
+ * This symbol, if defined, indicates that the truncate routine is
+ * available to truncate files.
+ */
+#define HAS_TRUNCATE /**/
+
+/* HAS_VFORK
+ * This symbol, if defined, indicates that vfork() exists.
+ */
+#define HAS_VFORK /**/
+
+/* VOIDSIG
+ * This symbol is defined if this system declares "void (*signal())()" in
+ * signal.h. The old way was to declare it as "int (*signal())()". It
+ * is up to the package author to declare things correctly based on the
+ * symbol.
+ */
+/* TO_SIGNAL
+ * This symbol's value is either "void" or "int", corresponding to the
+ * appropriate return "type" of a signal handler. Thus, one can declare
+ * a signal handler using "TO_SIGNAL (*handler())()", and define the
+ * handler using "TO_SIGNAL handler(sig)".
+ */
+#define VOIDSIG /**/
+#define TO_SIGNAL int /**/
+
+/* HASVOLATILE
+ * This symbol, if defined, indicates that this C compiler knows about
+ * the volatile declaration.
+ */
+/*#undef HASVOLATILE /**/
+
+/* HAS_VPRINTF
+ * This symbol, if defined, indicates that the vprintf routine is available
+ * to printf with a pointer to an argument list. If unavailable, you
+ * may need to write your own, probably in terms of _doprnt().
+ */
+/* CHARVSPRINTF
+ * This symbol is defined if this system has vsprintf() returning type
+ * (char*). The trend seems to be to declare it as "int vsprintf()". It
+ * is up to the package author to declare vsprintf correctly based on the
+ * symbol.
+ */
+#define HAS_VPRINTF /**/
+#define CHARVSPRINTF /**/
+
+/* HAS_WAIT4
+ * This symbol, if defined, indicates that wait4() exists.
+ */
+#define HAS_WAIT4 /**/
+
+/* HAS_WAITPID
+ * This symbol, if defined, indicates that waitpid() exists.
+ */
+#define HAS_WAITPID /**/
+
+/* GIDTYPE
+ * This symbol has a value like gid_t, int, ushort, or whatever type is
+ * used to declare group ids in the kernel.
+ */
+#define GIDTYPE gid_t /**/
+
+/* GROUPSTYPE
+ * This symbol has a value like gid_t, int, ushort, or whatever type is
+ * used in the return value of getgroups().
+ */
+#define GROUPSTYPE int /**/
+
+/* I_FCNTL
+ * This manifest constant tells the C program to include <fcntl.h>.
+ */
+/*#undef I_FCNTL /**/
+
+/* I_GDBM
+ * This symbol, if defined, indicates that gdbm.h exists and should
+ * be included.
+ */
+/*#undef I_GDBM /**/
+
+/* I_GRP
+ * This symbol, if defined, indicates to the C program that it should
+ * include grp.h.
+ */
+#define I_GRP /**/
+
+/* I_NETINET_IN
+ * This symbol, if defined, indicates to the C program that it should
+ * include netinet/in.h.
+ */
+/* I_SYS_IN
+ * This symbol, if defined, indicates to the C program that it should
+ * include sys/in.h.
+ */
+#define I_NETINET_IN /**/
+/*#undef I_SYS_IN /**/
+
+/* I_PWD
+ * This symbol, if defined, indicates to the C program that it should
+ * include pwd.h.
+ */
+/* PWQUOTA
+ * This symbol, if defined, indicates to the C program that struct passwd
+ * contains pw_quota.
+ */
+/* PWAGE
+ * This symbol, if defined, indicates to the C program that struct passwd
+ * contains pw_age.
+ */
+/* PWCHANGE
+ * This symbol, if defined, indicates to the C program that struct passwd
+ * contains pw_change.
+ */
+/* PWCLASS
+ * This symbol, if defined, indicates to the C program that struct passwd
+ * contains pw_class.
+ */
+/* PWEXPIRE
+ * This symbol, if defined, indicates to the C program that struct passwd
+ * contains pw_expire.
+ */
+/* PWCOMMENT
+ * This symbol, if defined, indicates to the C program that struct passwd
+ * contains pw_comment.
+ */
+#define I_PWD /**/
+/*#undef PWQUOTA /**/
+#define PWAGE /**/
+/*#undef PWCHANGE /**/
+/*#undef PWCLASS /**/
+/*#undef PWEXPIRE /**/
+#define PWCOMMENT /**/
+
+/* I_SYS_FILE
+ * This manifest constant tells the C program to include <sys/file.h>.
+ */
+#define I_SYS_FILE /**/
+
+/* I_SYSIOCTL
+ * This symbol, if defined, indicates that sys/ioctl.h exists and should
+ * be included.
+ */
+#define I_SYSIOCTL /**/
+
+/* I_TIME
+ * This symbol is defined if the program should include <time.h>.
+ */
+/* I_SYS_TIME
+ * This symbol is defined if the program should include <sys/time.h>.
+ */
+/* SYSTIMEKERNEL
+ * This symbol is defined if the program should include <sys/time.h>
+ * with KERNEL defined.
+ */
+/* I_SYS_SELECT
+ * This symbol is defined if the program should include <sys/select.h>.
+ */
+/*#undef I_TIME /**/
+#define I_SYS_TIME /**/
+/*#undef SYSTIMEKERNEL /**/
+/*#undef I_SYS_SELECT /**/
+
+/* I_UTIME
+ * This symbol, if defined, indicates to the C program that it should
+ * include utime.h.
+ */
+#define I_UTIME /**/
+
+/* I_VARARGS
+ * This symbol, if defined, indicates to the C program that it should
+ * include varargs.h.
+ */
+#define I_VARARGS /**/
+
+/* I_VFORK
+ * This symbol, if defined, indicates to the C program that it should
+ * include vfork.h.
+ */
+#define I_VFORK /**/
+
+/* INTSIZE
+ * This symbol contains the size of an int, so that the C preprocessor
+ * can make decisions based on it.
+ */
+#define INTSIZE 4 /**/
+
+/* I_DIRENT
+ * This symbol, if defined, indicates that the program should use the
+ * P1003-style directory routines, and include <dirent.h>.
+ */
+/* I_SYS_DIR
+ * This symbol, if defined, indicates that the program should use the
+ * directory functions by including <sys/dir.h>.
+ */
+/* I_NDIR
+ * This symbol, if defined, indicates that the program should include the
+ * system's version of ndir.h, rather than the one with this package.
+ */
+/* I_SYS_NDIR
+ * This symbol, if defined, indicates that the program should include the
+ * system's version of sys/ndir.h, rather than the one with this package.
+ */
+/* I_MY_DIR
+ * This symbol, if defined, indicates that the program should compile
+ * the ndir.c code provided with the package.
+ */
+/* DIRNAMLEN
+ * This symbol, if defined, indicates to the C program that the length
+ * of directory entry names is provided by a d_namlen field. Otherwise
+ * you need to do strlen() on the d_name field.
+ */
+#define I_DIRENT /**/
+/*#undef I_SYS_DIR /**/
+/*#undef I_NDIR /**/
+/*#undef I_SYS_NDIR /**/
+/*#undef I_MY_DIR /**/
+/*#undef DIRNAMLEN /**/
+
+/* MYMALLOC
+ * This symbol, if defined, indicates that we're using our own malloc.
+ */
+/* MALLOCPTRTYPE
+ * This symbol defines the kind of ptr returned by malloc and realloc.
+ */
+#define MYMALLOC /**/
+
+#define MALLOCPTRTYPE char /**/
+
+
+/* RANDBITS
+ * This symbol contains the number of bits of random number the rand()
+ * function produces. Usual values are 15, 16, and 31.
+ */
+#define RANDBITS 31 /**/
+
+/* SCRIPTDIR
+ * This symbol holds the name of the directory in which the user wants
+ * to keep publicly executable scripts for the package in question. It
+ * is often a directory that is mounted across diverse architectures.
+ */
+#define SCRIPTDIR "/usr/bin" /**/
+
+/* SIG_NAME
+ * This symbol contains an list of signal names in order.
+ */
+#define SIG_NAME "ZERO","HUP","INT","QUIT","ILL","TRAP","ABRT","EMT","FPE","KILL","BUS","SEGV","SYS","PIPE","ALRM","TERM","URG","STOP","TSTP","CONT","CLD","TTIN","TTOU","IO","XCPU","XFSZ","VTALRM","PROF","WINCH","LOST","USR1","USR2" /**/
+
+/* STDCHAR
+ * This symbol is defined to be the type of char used in stdio.h.
+ * It has the values "unsigned char" or "char".
+ */
+#define STDCHAR unsigned char /**/
+
+/* UIDTYPE
+ * This symbol has a value like uid_t, int, ushort, or whatever type is
+ * used to declare user ids in the kernel.
+ */
+#define UIDTYPE uid_t /**/
+
+/* VOIDHAVE
+ * This symbol indicates how much support of the void type is given by this
+ * compiler. What various bits mean:
+ *
+ * 1 = supports declaration of void
+ * 2 = supports arrays of pointers to functions returning void
+ * 4 = supports comparisons between pointers to void functions and
+ * addresses of void functions
+ *
+ * The package designer should define VOIDWANT to indicate the requirements
+ * of the package. This can be done either by #defining VOIDWANT before
+ * including config.h, or by defining voidwant in Myinit.U. If the level
+ * of void support necessary is not present, config.h defines void to "int",
+ * VOID to the empty string, and VOIDP to "char *".
+ */
+/* void
+ * This symbol is used for void casts. On implementations which support
+ * void appropriately, its value is "void". Otherwise, its value maps
+ * to "int".
+ */
+/* VOID
+ * This symbol's value is "void" if the implementation supports void
+ * appropriately. Otherwise, its value is the empty string. The primary
+ * use of this symbol is in specifying void parameter lists for function
+ * prototypes.
+ */
+/* VOIDP
+ * This symbol is used for casting generic pointers. On implementations
+ * which support void appropriately, its value is "void *". Otherwise,
+ * its value is "char *".
+ */
+#ifndef VOIDWANT
+#define VOIDWANT 7
+#endif
+#define VOIDHAVE 7
+#if (VOIDHAVE & VOIDWANT) != VOIDWANT
+#define void int /* is void to be avoided? */
+#define VOID
+#define VOIDP (char *)
+#define M_VOID /* Xenix strikes again */
+#else
+#define VOID void
+#define VOIDP (void *)
+#endif
+
+/* PRIVLIB
+ * This symbol contains the name of the private library for this package.
+ * The library is private in the sense that it needn't be in anyone's
+ * execution path, but it should be accessible by the world. The program
+ * should be prepared to do ~ expansion.
+ */
+#define PRIVLIB "/usr/share/perl" /**/
+
+#endif
diff --git a/gnu/usr.bin/perl/perl/config.h b/gnu/usr.bin/perl/perl/config.h
new file mode 100644
index 0000000..4a66712
--- /dev/null
+++ b/gnu/usr.bin/perl/perl/config.h
@@ -0,0 +1,769 @@
+#ifndef config_h
+#define config_h
+/* config.h
+ * This file was produced by running the config.h.SH script, which
+ * gets its values from config.sh, which is generally produced by
+ * running Configure.
+ *
+ * Feel free to modify any of this as the need arises. Note, however,
+ * that running config.h.SH again will wipe out any changes you've made.
+ * For a more permanent change edit config.sh and rerun config.h.SH.
+ */
+ /*SUPPRESS 460*/
+
+
+/*#undef EUNICE */
+/*#undef VMS */
+
+/* LOC_SED
+ * This symbol holds the complete pathname to the sed program.
+ */
+#define LOC_SED "/usr/bin/sed" /**/
+
+/* ALIGN_BYTES
+ * This symbol contains the number of bytes required to align a double.
+ * Usual values are 2, 4, and 8.
+ */
+#define ALIGN_BYTES 4 /**/
+
+/* BIN
+ * This symbol holds the name of the directory in which the user wants
+ * to keep publicly executable images for the package in question. It
+ * is most often a local directory such as /usr/local/bin.
+ */
+#define BIN "/usr/bin" /**/
+
+/* BYTEORDER
+ * This symbol contains an encoding of the order of bytes in a long.
+ * Usual values (in hex) are 0x1234, 0x4321, 0x2143, 0x3412...
+ */
+#define BYTEORDER 0x1234 /**/
+
+/* CPPSTDIN
+ * This symbol contains the first part of the string which will invoke
+ * the C preprocessor on the standard input and produce to standard
+ * output. Typical value of "cc -E" or "/lib/cpp".
+ */
+/* CPPMINUS
+ * This symbol contains the second part of the string which will invoke
+ * the C preprocessor on the standard input and produce to standard
+ * output. This symbol will have the value "-" if CPPSTDIN needs a minus
+ * to specify standard input, otherwise the value is "".
+ */
+#define CPPSTDIN "cc -E"
+#define CPPMINUS "-"
+
+/* HAS_BCMP
+ * This symbol, if defined, indicates that the bcmp routine is available
+ * to compare blocks of memory. If undefined, use memcmp. If that's
+ * not available, roll your own.
+ */
+#define HAS_BCMP /**/
+
+/* HAS_BCOPY
+ * This symbol, if defined, indicates that the bcopy routine is available
+ * to copy blocks of memory. Otherwise you should probably use memcpy().
+ * If neither is defined, roll your own.
+ */
+/* SAFE_BCOPY
+ * This symbol, if defined, indicates that the bcopy routine is available
+ * to copy potentially overlapping copy blocks of bcopy. Otherwise you
+ * should probably use memmove() or memcpy(). If neither is defined,
+ * roll your own.
+ */
+#define HAS_BCOPY /**/
+#define SAFE_BCOPY /**/
+
+/* HAS_BZERO
+ * This symbol, if defined, indicates that the bzero routine is available
+ * to zero blocks of memory. Otherwise you should probably use memset()
+ * or roll your own.
+ */
+#define HAS_BZERO /**/
+
+/* CASTNEGFLOAT
+ * This symbol, if defined, indicates that this C compiler knows how to
+ * cast negative or large floating point numbers to unsigned longs, ints
+ * and shorts.
+ */
+/* CASTFLAGS
+ * This symbol contains flags that say what difficulties the compiler
+ * has casting odd floating values to unsigned long:
+ * 1 = couldn't cast < 0
+ * 2 = couldn't cast >= 0x80000000
+ */
+#define CASTNEGFLOAT /**/
+#define CASTFLAGS 0 /**/
+
+/* CHARSPRINTF
+ * This symbol is defined if this system declares "char *sprintf()" in
+ * stdio.h. The trend seems to be to declare it as "int sprintf()". It
+ * is up to the package author to declare sprintf correctly based on the
+ * symbol.
+ */
+/*#undef CHARSPRINTF */
+
+/* HAS_CHSIZE
+ * This symbol, if defined, indicates that the chsize routine is available
+ * to truncate files. You might need a -lx to get this routine.
+ */
+/*#undef HAS_CHSIZE */
+
+/* HAS_CRYPT
+ * This symbol, if defined, indicates that the crypt routine is available
+ * to encrypt passwords and the like.
+ */
+#define HAS_CRYPT /**/
+
+/* CSH
+ * This symbol, if defined, indicates that the C-shell exists.
+ * If defined, contains the full pathname of csh.
+ */
+#define CSH "/bin/csh" /**/
+
+/* DOSUID
+ * This symbol, if defined, indicates that the C program should
+ * check the script that it is executing for setuid/setgid bits, and
+ * attempt to emulate setuid/setgid on systems that have disabled
+ * setuid #! scripts because the kernel can't do it securely.
+ * It is up to the package designer to make sure that this emulation
+ * is done securely. Among other things, it should do an fstat on
+ * the script it just opened to make sure it really is a setuid/setgid
+ * script, it should make sure the arguments passed correspond exactly
+ * to the argument on the #! line, and it should not trust any
+ * subprocesses to which it must pass the filename rather than the
+ * file descriptor of the script to be executed.
+ */
+/*#undef DOSUID */
+
+/* HAS_DUP2
+ * This symbol, if defined, indicates that the dup2 routine is available
+ * to dup file descriptors. Otherwise you should use dup().
+ */
+#define HAS_DUP2 /**/
+
+/* HAS_FCHMOD
+ * This symbol, if defined, indicates that the fchmod routine is available
+ * to change mode of opened files. If unavailable, use chmod().
+ */
+#define HAS_FCHMOD /**/
+
+/* HAS_FCHOWN
+ * This symbol, if defined, indicates that the fchown routine is available
+ * to change ownership of opened files. If unavailable, use chown().
+ */
+#define HAS_FCHOWN /**/
+
+/* HAS_FCNTL
+ * This symbol, if defined, indicates to the C program that
+ * the fcntl() function exists.
+ */
+#define HAS_FCNTL /**/
+
+/* FLEXFILENAMES
+ * This symbol, if defined, indicates that the system supports filenames
+ * longer than 14 characters.
+ */
+#define FLEXFILENAMES /**/
+
+/* HAS_FLOCK
+ * This symbol, if defined, indicates that the flock() routine is
+ * available to do file locking.
+ */
+#define HAS_FLOCK /**/
+
+/* HAS_GETGROUPS
+ * This symbol, if defined, indicates that the getgroups() routine is
+ * available to get the list of process groups. If unavailable, multiple
+ * groups are probably not supported.
+ */
+#define HAS_GETGROUPS /**/
+
+/* HAS_GETHOSTENT
+ * This symbol, if defined, indicates that the gethostent() routine is
+ * available to lookup host names in some data base or other.
+ */
+/*#undef HAS_GETHOSTENT */
+
+/* HAS_GETPGRP
+ * This symbol, if defined, indicates that the getpgrp() routine is
+ * available to get the current process group.
+ */
+#define HAS_GETPGRP /**/
+
+/* HAS_GETPGRP2
+ * This symbol, if defined, indicates that the getpgrp2() (as in DG/UX)
+ * routine is available to get the current process group.
+ */
+/*#undef HAS_GETPGRP2 */
+
+/* HAS_GETPRIORITY
+ * This symbol, if defined, indicates that the getpriority() routine is
+ * available to get a process's priority.
+ */
+#define HAS_GETPRIORITY /**/
+
+/* HAS_HTONS
+ * This symbol, if defined, indicates that the htons routine (and friends)
+ * are available to do network order byte swapping.
+ */
+/* HAS_HTONL
+ * This symbol, if defined, indicates that the htonl routine (and friends)
+ * are available to do network order byte swapping.
+ */
+/* HAS_NTOHS
+ * This symbol, if defined, indicates that the ntohs routine (and friends)
+ * are available to do network order byte swapping.
+ */
+/* HAS_NTOHL
+ * This symbol, if defined, indicates that the ntohl routine (and friends)
+ * are available to do network order byte swapping.
+ */
+#define HAS_HTONS /**/
+#define HAS_HTONL /**/
+#define HAS_NTOHS /**/
+#define HAS_NTOHL /**/
+
+/* index
+ * This preprocessor symbol is defined, along with rindex, if the system
+ * uses the strchr and strrchr routines instead.
+ */
+/* rindex
+ * This preprocessor symbol is defined, along with index, if the system
+ * uses the strchr and strrchr routines instead.
+ */
+
+/* HAS_ISASCII
+ * This symbol, if defined, indicates that the isascii routine is available
+ * to test characters for asciiness.
+ */
+#define HAS_ISASCII /**/
+
+/* HAS_KILLPG
+ * This symbol, if defined, indicates that the killpg routine is available
+ * to kill process groups. If unavailable, you probably should use kill
+ * with a negative process number.
+ */
+#define HAS_KILLPG /**/
+
+/* HAS_LSTAT
+ * This symbol, if defined, indicates that the lstat() routine is
+ * available to stat symbolic links.
+ */
+#define HAS_LSTAT /**/
+
+/* HAS_MEMCMP
+ * This symbol, if defined, indicates that the memcmp routine is available
+ * to compare blocks of memory. If undefined, roll your own.
+ */
+#define HAS_MEMCMP /**/
+
+/* HAS_MEMCPY
+ * This symbol, if defined, indicates that the memcpy routine is available
+ * to copy blocks of memory. Otherwise you should probably use bcopy().
+ * If neither is defined, roll your own.
+ */
+/* SAFE_MEMCPY
+ * This symbol, if defined, indicates that the memcpy routine is available
+ * to copy potentially overlapping copy blocks of memory. Otherwise you
+ * should probably use memmove() or bcopy(). If neither is defined,
+ * roll your own.
+ */
+#define HAS_MEMCPY /**/
+#define SAFE_MEMCPY /**/
+
+/* HAS_MEMMOVE
+ * This symbol, if defined, indicates that the memmove routine is available
+ * to move potentially overlapping blocks of memory. Otherwise you
+ * should use bcopy() or roll your own.
+ */
+#define HAS_MEMMOVE /**/
+
+/* HAS_MEMSET
+ * This symbol, if defined, indicates that the memset routine is available
+ * to set a block of memory to a character. If undefined, roll your own.
+ */
+#define HAS_MEMSET /**/
+
+/* HAS_MKDIR
+ * This symbol, if defined, indicates that the mkdir routine is available
+ * to create directories. Otherwise you should fork off a new process to
+ * exec /bin/mkdir.
+ */
+#define HAS_MKDIR /**/
+
+
+/* HAS_NDBM
+ * This symbol, if defined, indicates that ndbm.h exists and should
+ * be included.
+ */
+#define HAS_NDBM /**/
+
+/* HAS_ODBM
+ * This symbol, if defined, indicates that dbm.h exists and should
+ * be included.
+ */
+
+/* HAS_OPEN3
+ * This manifest constant lets the C program know that the three
+ * argument form of open(2) is available.
+ */
+#define HAS_OPEN3 /**/
+
+/* HAS_READDIR
+ * This symbol, if defined, indicates that the readdir routine is available
+ * from the C library to read directories.
+ */
+#define HAS_READDIR /**/
+
+/* HAS_RENAME
+ * This symbol, if defined, indicates that the rename routine is available
+ * to rename files. Otherwise you should do the unlink(), link(), unlink()
+ * trick.
+ */
+#define HAS_RENAME /**/
+
+/* HAS_REWINDDIR
+ * This symbol, if defined, indicates that the rewindir routine is
+ * available to rewind directories.
+ */
+#define HAS_REWINDDIR /**/
+
+/* HAS_RMDIR
+ * This symbol, if defined, indicates that the rmdir routine is available
+ * to remove directories. Otherwise you should fork off a new process to
+ * exec /bin/rmdir.
+ */
+#define HAS_RMDIR /**/
+
+/* HAS_SEEKDIR
+ * This symbol, if defined, indicates that the seekdir routine is
+ * available to seek into directories.
+ */
+#define HAS_SEEKDIR /**/
+
+/* HAS_SELECT
+ * This symbol, if defined, indicates that the select() subroutine
+ * exists.
+ */
+#define HAS_SELECT /**/
+
+/* HAS_SETEGID
+ * This symbol, if defined, indicates that the setegid routine is available
+ * to change the effective gid of the current program.
+ */
+#define HAS_SETEGID /**/
+
+/* HAS_SETEUID
+ * This symbol, if defined, indicates that the seteuid routine is available
+ * to change the effective uid of the current program.
+ */
+#define HAS_SETEUID /**/
+
+/* HAS_SETPGRP
+ * This symbol, if defined, indicates that the setpgrp() routine is
+ * available to set the current process group.
+ */
+#define HAS_SETPGRP /**/
+
+/* HAS_SETPGRP2
+ * This symbol, if defined, indicates that the setpgrp2() (as in DG/UX)
+ * routine is available to set the current process group.
+ */
+
+/* HAS_SETPRIORITY
+ * This symbol, if defined, indicates that the setpriority() routine is
+ * available to set a process's priority.
+ */
+#define HAS_SETPRIORITY /**/
+
+/* HAS_SETREGID
+ * This symbol, if defined, indicates that the setregid routine is
+ * available to change the real and effective gid of the current program.
+ */
+/* HAS_SETRESGID
+ * This symbol, if defined, indicates that the setresgid routine is
+ * available to change the real, effective and saved gid of the current
+ * program.
+ */
+#define HAS_SETREGID /**/
+
+/* HAS_SETREUID
+ * This symbol, if defined, indicates that the setreuid routine is
+ * available to change the real and effective uid of the current program.
+ */
+/* HAS_SETRESUID
+ * This symbol, if defined, indicates that the setresuid routine is
+ * available to change the real, effective and saved uid of the current
+ * program.
+ */
+#define HAS_SETREUID /**/
+
+/* HAS_SETRGID
+ * This symbol, if defined, indicates that the setrgid routine is available
+ * to change the real gid of the current program.
+ */
+#define HAS_SETRGID /**/
+
+/* HAS_SETRUID
+ * This symbol, if defined, indicates that the setruid routine is available
+ * to change the real uid of the current program.
+ */
+#define HAS_SETRUID /**/
+
+
+/* HAS_SOCKET
+ * This symbol, if defined, indicates that the BSD socket interface is
+ * supported.
+ */
+/* HAS_SOCKETPAIR
+ * This symbol, if defined, indicates that the BSD socketpair call is
+ * supported.
+ */
+/* OLDSOCKET
+ * This symbol, if defined, indicates that the 4.1c BSD socket interface
+ * is supported instead of the 4.2/4.3 BSD socket interface.
+ */
+#define HAS_SOCKET /**/
+
+#define HAS_SOCKETPAIR /**/
+
+
+/* STATBLOCKS
+ * This symbol is defined if this system has a stat structure declaring
+ * st_blksize and st_blocks.
+ */
+#define STATBLOCKS /**/
+
+/* STDSTDIO
+ * This symbol is defined if this system has a FILE structure declaring
+ * _ptr and _cnt in stdio.h.
+ */
+
+/* STRUCTCOPY
+ * This symbol, if defined, indicates that this C compiler knows how
+ * to copy structures. If undefined, you'll need to use a block copy
+ * routine of some sort instead.
+ */
+#define STRUCTCOPY /**/
+
+/* HAS_STRERROR
+ * This symbol, if defined, indicates that the strerror() routine is
+ * available to translate error numbers to strings.
+ */
+#define HAS_STRERROR /**/
+
+/* HAS_SYMLINK
+ * This symbol, if defined, indicates that the symlink routine is available
+ * to create symbolic links.
+ */
+#define HAS_SYMLINK /**/
+
+/* HAS_SYSCALL
+ * This symbol, if defined, indicates that the syscall routine is available
+ * to call arbitrary system calls. If undefined, that's tough.
+ */
+#define HAS_SYSCALL /**/
+
+/* HAS_TELLDIR
+ * This symbol, if defined, indicates that the telldir routine is
+ * available to tell your location in directories.
+ */
+#define HAS_TELLDIR /**/
+
+/* HAS_TRUNCATE
+ * This symbol, if defined, indicates that the truncate routine is
+ * available to truncate files.
+ */
+#define HAS_TRUNCATE /**/
+
+/* HAS_VFORK
+ * This symbol, if defined, indicates that vfork() exists.
+ */
+#define HAS_VFORK /**/
+
+/* VOIDSIG
+ * This symbol is defined if this system declares "void (*signal())()" in
+ * signal.h. The old way was to declare it as "int (*signal())()". It
+ * is up to the package author to declare things correctly based on the
+ * symbol.
+ */
+/* TO_SIGNAL
+ * This symbol's value is either "void" or "int", corresponding to the
+ * appropriate return "type" of a signal handler. Thus, one can declare
+ * a signal handler using "TO_SIGNAL (*handler())()", and define the
+ * handler using "TO_SIGNAL handler(sig)".
+ */
+#define VOIDSIG /**/
+#define TO_SIGNAL int /**/
+
+/* HASVOLATILE
+ * This symbol, if defined, indicates that this C compiler knows about
+ * the volatile declaration.
+ */
+#define HASVOLATILE /**/
+
+/* HAS_VPRINTF
+ * This symbol, if defined, indicates that the vprintf routine is available
+ * to printf with a pointer to an argument list. If unavailable, you
+ * may need to write your own, probably in terms of _doprnt().
+ */
+/* CHARVSPRINTF
+ * This symbol is defined if this system has vsprintf() returning type
+ * (char*). The trend seems to be to declare it as "int vsprintf()". It
+ * is up to the package author to declare vsprintf correctly based on the
+ * symbol.
+ */
+#define HAS_VPRINTF /**/
+
+/* HAS_WAIT4
+ * This symbol, if defined, indicates that wait4() exists.
+ */
+#define HAS_WAIT4 /**/
+
+/* HAS_WAITPID
+ * This symbol, if defined, indicates that waitpid() exists.
+ */
+#define HAS_WAITPID /**/
+
+/* GIDTYPE
+ * This symbol has a value like gid_t, int, ushort, or whatever type is
+ * used to declare group ids in the kernel.
+ */
+#define GIDTYPE gid_t /**/
+
+/* GROUPSTYPE
+ * This symbol has a value like gid_t, int, ushort, or whatever type is
+ * used in the return value of getgroups().
+ */
+#define GROUPSTYPE gid_t /**/
+
+/* I_FCNTL
+ * This manifest constant tells the C program to include <fcntl.h>.
+ */
+
+/* I_GDBM
+ * This symbol, if defined, indicates that gdbm.h exists and should
+ * be included.
+ */
+
+/* I_GRP
+ * This symbol, if defined, indicates to the C program that it should
+ * include grp.h.
+ */
+#define I_GRP /**/
+
+/* I_NETINET_IN
+ * This symbol, if defined, indicates to the C program that it should
+ * include netinet/in.h.
+ */
+/* I_SYS_IN
+ * This symbol, if defined, indicates to the C program that it should
+ * include sys/in.h.
+ */
+#define I_NETINET_IN /**/
+
+/* I_PWD
+ * This symbol, if defined, indicates to the C program that it should
+ * include pwd.h.
+ */
+/* PWQUOTA
+ * This symbol, if defined, indicates to the C program that struct passwd
+ * contains pw_quota.
+ */
+/* PWAGE
+ * This symbol, if defined, indicates to the C program that struct passwd
+ * contains pw_age.
+ */
+/* PWCHANGE
+ * This symbol, if defined, indicates to the C program that struct passwd
+ * contains pw_change.
+ */
+/* PWCLASS
+ * This symbol, if defined, indicates to the C program that struct passwd
+ * contains pw_class.
+ */
+/* PWEXPIRE
+ * This symbol, if defined, indicates to the C program that struct passwd
+ * contains pw_expire.
+ */
+/* PWCOMMENT
+ * This symbol, if defined, indicates to the C program that struct passwd
+ * contains pw_comment.
+ */
+#define I_PWD /**/
+#define PWCHANGE /**/
+#define PWCLASS /**/
+#define PWEXPIRE /**/
+
+/* I_SYS_FILE
+ * This manifest constant tells the C program to include <sys/file.h>.
+ */
+#define I_SYS_FILE /**/
+
+/* I_SYSIOCTL
+ * This symbol, if defined, indicates that sys/ioctl.h exists and should
+ * be included.
+ */
+#define I_SYSIOCTL /**/
+
+/* I_TIME
+ * This symbol is defined if the program should include <time.h>.
+ */
+/* I_SYS_TIME
+ * This symbol is defined if the program should include <sys/time.h>.
+ */
+/* SYSTIMEKERNEL
+ * This symbol is defined if the program should include <sys/time.h>
+ * with KERNEL defined.
+ */
+/* I_SYS_SELECT
+ * This symbol is defined if the program should include <sys/select.h>.
+ */
+#define I_SYS_TIME /**/
+
+/* I_UTIME
+ * This symbol, if defined, indicates to the C program that it should
+ * include utime.h.
+ */
+#define I_UTIME /**/
+
+/* I_VARARGS
+ * This symbol, if defined, indicates to the C program that it should
+ * include varargs.h.
+ */
+#define I_VARARGS /**/
+
+/* I_VFORK
+ * This symbol, if defined, indicates to the C program that it should
+ * include vfork.h.
+ */
+
+/* INTSIZE
+ * This symbol contains the size of an int, so that the C preprocessor
+ * can make decisions based on it.
+ */
+#define INTSIZE 4 /**/
+
+/* I_DIRENT
+ * This symbol, if defined, indicates that the program should use the
+ * P1003-style directory routines, and include <dirent.h>.
+ */
+/* I_SYS_DIR
+ * This symbol, if defined, indicates that the program should use the
+ * directory functions by including <sys/dir.h>.
+ */
+/* I_NDIR
+ * This symbol, if defined, indicates that the program should include the
+ * system's version of ndir.h, rather than the one with this package.
+ */
+/* I_SYS_NDIR
+ * This symbol, if defined, indicates that the program should include the
+ * system's version of sys/ndir.h, rather than the one with this package.
+ */
+/* I_MY_DIR
+ * This symbol, if defined, indicates that the program should compile
+ * the ndir.c code provided with the package.
+ */
+/* DIRNAMLEN
+ * This symbol, if defined, indicates to the C program that the length
+ * of directory entry names is provided by a d_namlen field. Otherwise
+ * you need to do strlen() on the d_name field.
+ */
+#define I_DIRENT /**/
+
+/* MYMALLOC
+ * This symbol, if defined, indicates that we're using our own malloc.
+ */
+/* MALLOCPTRTYPE
+ * This symbol defines the kind of ptr returned by malloc and realloc.
+ */
+#define MYMALLOC /**/
+
+#define MALLOCPTRTYPE void /**/
+
+
+/* RANDBITS
+ * This symbol contains the number of bits of random number the rand()
+ * function produces. Usual values are 15, 16, and 31.
+ */
+#define RANDBITS 31 /**/
+
+/* SCRIPTDIR
+ * This symbol holds the name of the directory in which the user wants
+ * to keep publicly executable scripts for the package in question. It
+ * is often a directory that is mounted across diverse architectures.
+ */
+#define SCRIPTDIR "/usr/bin" /**/
+
+/* SIG_NAME
+ * This symbol contains an list of signal names in order.
+ */
+#define SIG_NAME "ZERO","HUP","INT","QUIT","ILL","TRAP","ABRT","EMT","FPE","KILL","BUS","SEGV","SYS","PIPE","ALRM","TERM","URG","STOP","TSTP","CONT","CHLD","TTIN","TTOU","IO","XCPU","XFSZ","VTALRM","PROF","WINCH","INFO","USR1","USR2" /**/
+
+/* STDCHAR
+ * This symbol is defined to be the type of char used in stdio.h.
+ * It has the values "unsigned char" or "char".
+ */
+#define STDCHAR char /**/
+
+/* UIDTYPE
+ * This symbol has a value like uid_t, int, ushort, or whatever type is
+ * used to declare user ids in the kernel.
+ */
+#define UIDTYPE uid_t /**/
+
+/* VOIDHAVE
+ * This symbol indicates how much support of the void type is given by this
+ * compiler. What various bits mean:
+ *
+ * 1 = supports declaration of void
+ * 2 = supports arrays of pointers to functions returning void
+ * 4 = supports comparisons between pointers to void functions and
+ * addresses of void functions
+ *
+ * The package designer should define VOIDWANT to indicate the requirements
+ * of the package. This can be done either by #defining VOIDWANT before
+ * including config.h, or by defining voidwant in Myinit.U. If the level
+ * of void support necessary is not present, config.h defines void to "int",
+ * VOID to the empty string, and VOIDP to "char *".
+ */
+/* void
+ * This symbol is used for void casts. On implementations which support
+ * void appropriately, its value is "void". Otherwise, its value maps
+ * to "int".
+ */
+/* VOID
+ * This symbol's value is "void" if the implementation supports void
+ * appropriately. Otherwise, its value is the empty string. The primary
+ * use of this symbol is in specifying void parameter lists for function
+ * prototypes.
+ */
+/* VOIDP
+ * This symbol is used for casting generic pointers. On implementations
+ * which support void appropriately, its value is "void *". Otherwise,
+ * its value is "char *".
+ */
+#ifndef VOIDWANT
+#define VOIDWANT 7
+#endif
+#define VOIDHAVE 7
+#if (VOIDHAVE & VOIDWANT) != VOIDWANT
+#define void int /* is void to be avoided? */
+#define VOID
+#define VOIDP (char *)
+#define M_VOID /* Xenix strikes again */
+#else
+#define VOID void
+#define VOIDP (void *)
+#endif
+
+/* PRIVLIB
+ * This symbol contains the name of the private library for this package.
+ * The library is private in the sense that it needn't be in anyone's
+ * execution path, but it should be accessible by the world. The program
+ * should be prepared to do ~ expansion.
+ */
+#define PRIVLIB "/usr/share/perl" /**/
+
+#endif
diff --git a/gnu/usr.bin/perl/perl/config.sh b/gnu/usr.bin/perl/perl/config.sh
new file mode 100644
index 0000000..a4196bd
--- /dev/null
+++ b/gnu/usr.bin/perl/perl/config.sh
@@ -0,0 +1,268 @@
+#!/bin/sh
+# config.sh
+# This file was produced by running the Configure script.
+d_eunice='undef'
+define='define'
+eunicefix=':'
+loclist='
+cat
+cp
+echo
+expr
+grep
+mkdir
+mv
+rm
+sed
+sort
+tr
+uniq
+'
+expr='/bin/expr'
+sed='/usr/bin/sed'
+echo='/bin/echo'
+cat='/bin/cat'
+rm='/bin/rm'
+mv='/bin/mv'
+cp='/bin/cp'
+tail=''
+tr='/usr/bin/tr'
+mkdir='/bin/mkdir'
+sort='/usr/bin/sort'
+uniq='/usr/bin/uniq'
+grep='/usr/bin/grep'
+trylist='
+Mcc
+bison
+cpp
+csh
+egrep
+line
+nroff
+perl
+test
+uname
+yacc
+'
+test='test'
+inews=''
+egrep='/usr/bin/egrep'
+more=''
+pg=''
+Mcc='Mcc'
+vi=''
+mailx=''
+mail=''
+cpp='/usr/bin/cpp'
+perl='perl'
+emacs=''
+ls=''
+rmail=''
+sendmail=''
+shar=''
+smail=''
+tbl=''
+troff=''
+nroff='/usr/bin/nroff'
+uname='uname'
+uuname=''
+line='line'
+chgrp=''
+chmod=''
+lint=''
+sleep=''
+pr=''
+tar=''
+ln=''
+lpr=''
+lp=''
+touch=''
+make=''
+date=''
+csh='/bin/csh'
+bash=''
+ksh=''
+lex=''
+flex=''
+bison='bison'
+Log='$Log'
+Header='$Header'
+Id='$Id'
+lastuname='uname: not found'
+alignbytes='4'
+bin='/usr/bin'
+installbin='/usr/bin'
+byteorder='1234'
+contains='grep'
+cppstdin='/usr/bin/cpp'
+cppminus=''
+d_bcmp='define'
+d_bcopy='define'
+d_safebcpy='define'
+d_bzero='define'
+d_castneg='define'
+castflags='0'
+d_charsprf='undef'
+d_chsize='undef'
+d_crypt='define'
+cryptlib='-lcrypt'
+d_csh='define'
+d_dosuid='define'
+d_dup2='define'
+d_fchmod='define'
+d_fchown='define'
+d_fcntl='define'
+d_flexfnam='define'
+d_flock='define'
+d_getgrps='define'
+d_gethent='undef'
+d_getpgrp='define'
+d_getpgrp2='undef'
+d_getprior='define'
+d_htonl='define'
+d_index='undef'
+d_isascii='undef'
+d_killpg='define'
+d_lstat='define'
+d_memcmp='define'
+d_memcpy='define'
+d_safemcpy='define'
+d_memmove='define'
+d_memset='define'
+d_mkdir='define'
+d_msg='define'
+d_msgctl='define'
+d_msgget='define'
+d_msgrcv='define'
+d_msgsnd='define'
+d_ndbm='define'
+d_odbm='undef'
+d_open3='define'
+d_readdir='define'
+d_rename='define'
+d_rewindir='define'
+d_rmdir='define'
+d_seekdir='define'
+d_select='define'
+d_sem='define'
+d_semctl='define'
+d_semget='define'
+d_semop='define'
+d_setegid='define'
+d_seteuid='define'
+d_setpgrp='define'
+d_setpgrp2='undef'
+d_setprior='define'
+d_setregid='define'
+d_setresgid='undef'
+d_setreuid='define'
+d_setresuid='undef'
+d_setrgid='define'
+d_setruid='define'
+d_shm='define'
+d_shmat='define'
+d_voidshmat='define'
+d_shmctl='define'
+d_shmdt='define'
+d_shmget='define'
+d_socket='define'
+d_sockpair='define'
+d_oldsock='undef'
+socketlib=''
+d_statblks='define'
+d_stdstdio='undef'
+d_strctcpy='define'
+d_strerror='define'
+d_symlink='define'
+d_syscall='define'
+d_telldir='define'
+d_truncate='define'
+d_vfork='define'
+d_voidsig='define'
+d_tosignal='int'
+d_volatile='define'
+d_vprintf='define'
+d_charvspr='undef'
+d_wait4='define'
+d_waitpid='define'
+gidtype='gid_t'
+groupstype='int'
+i_fcntl='undef'
+i_gdbm='undef'
+i_grp='define'
+i_niin='define'
+i_sysin='undef'
+i_pwd='define'
+d_pwquota='undef'
+d_pwage='undef'
+d_pwchange='define'
+d_pwclass='define'
+d_pwexpire='define'
+d_pwcomment='undef'
+i_sys_file='define'
+i_sysioctl='define'
+i_time='undef'
+i_sys_time='define'
+i_sys_select='undef'
+d_systimekernel='undef'
+i_utime='define'
+i_varargs='define'
+i_vfork='undef'
+intsize='4'
+libc='/usr/lib/libc.so.1.0'
+nm_opts=''
+libndir=''
+i_my_dir='undef'
+i_ndir='undef'
+i_sys_ndir='undef'
+i_dirent='define'
+i_sys_dir='undef'
+d_dirnamlen='define'
+ndirc=''
+ndiro=''
+mallocsrc='malloc.c'
+mallocobj='malloc.o'
+d_mymalloc='define'
+mallocptrtype='void'
+mansrc='/usr/man/man1'
+manext='1'
+models='none'
+split=''
+small=''
+medium=''
+large=''
+huge=''
+optimize='-O'
+ccflags=''
+cppflags=''
+ldflags=''
+cc='cc'
+nativegcc=''
+libs='-lm'
+n='-n'
+c=''
+package='perl'
+randbits='31'
+scriptdir='/usr/bin'
+installscr='/usr/bin'
+sig_name='ZERO HUP INT QUIT ILL TRAP ABRT EMT FPE KILL BUS SEGV SYS PIPE ALRM TERM URG STOP TSTP CONT CHLD TTIN TTOU IO XCPU XFSZ VTALRM PROF WINCH INFO USR1 USR2'
+spitshell='cat'
+shsharp='true'
+sharpbang='#!'
+startsh='#!/bin/sh'
+stdchar='char'
+uidtype='uid_t'
+usrinclude='/usr/include'
+inclPath=''
+void=''
+voidhave='7'
+voidwant='7'
+w_localtim='1'
+w_s_timevl='1'
+w_s_tm='1'
+yacc='/usr/bin/yacc'
+lib=''
+privlib='/usr/share/perl'
+installprivlib='/usr/share/perl'
+PATCHLEVEL=36
+CONFIG=true
diff --git a/gnu/usr.bin/perl/perl/cons.c b/gnu/usr.bin/perl/perl/cons.c
new file mode 100644
index 0000000..bbf783e
--- /dev/null
+++ b/gnu/usr.bin/perl/perl/cons.c
@@ -0,0 +1,1453 @@
+/* $RCSfile: cons.c,v $$Revision: 1.1.1.1 $$Date: 1994/09/10 06:27:32 $
+ *
+ * Copyright (c) 1991, Larry Wall
+ *
+ * You may distribute under the terms of either the GNU General Public
+ * License or the Artistic License, as specified in the README file.
+ *
+ * $Log: cons.c,v $
+ * Revision 1.1.1.1 1994/09/10 06:27:32 gclarkii
+ * Initial import of Perl 4.046 bmaked
+ *
+ * Revision 1.1.1.1 1993/08/23 21:29:35 nate
+ * PERL!
+ *
+ * Revision 4.0.1.4 1993/02/05 19:30:15 lwall
+ * patch36: fixed various little coredump bugs
+ *
+ * Revision 4.0.1.3 92/06/08 12:18:35 lwall
+ * patch20: removed implicit int declarations on funcions
+ * patch20: deleted some minor memory leaks
+ * patch20: fixed double debug break in foreach with implicit array assignment
+ * patch20: fixed confusion between a *var's real name and its effective name
+ * patch20: Perl now distinguishes overlapped copies from non-overlapped
+ * patch20: debugger sometimes displayed wrong source line
+ * patch20: various error messages have been clarified
+ * patch20: an eval block containing a null block or statement could dump core
+ *
+ * Revision 4.0.1.2 91/11/05 16:15:13 lwall
+ * patch11: debugger got confused over nested subroutine definitions
+ * patch11: prepared for ctype implementations that don't define isascii()
+ *
+ * Revision 4.0.1.1 91/06/07 10:31:15 lwall
+ * patch4: new copyright notice
+ * patch4: added global modifier for pattern matches
+ *
+ * Revision 4.0 91/03/20 01:05:51 lwall
+ * 4.0 baseline.
+ *
+ */
+
+#include "EXTERN.h"
+#include "perl.h"
+#include "perly.h"
+
+extern char *tokename[];
+extern int yychar;
+
+static int cmd_tosave();
+static int arg_tosave();
+static int spat_tosave();
+static void make_cswitch();
+static void make_nswitch();
+
+static bool saw_return;
+
+SUBR *
+make_sub(name,cmd)
+char *name;
+CMD *cmd;
+{
+ register SUBR *sub;
+ STAB *stab = stabent(name,TRUE);
+
+ if (sub = stab_sub(stab)) {
+ if (dowarn) {
+ CMD *oldcurcmd = curcmd;
+
+ if (cmd)
+ curcmd = cmd;
+ warn("Subroutine %s redefined",name);
+ curcmd = oldcurcmd;
+ }
+ if (!sub->usersub && sub->cmd) {
+ cmd_free(sub->cmd);
+ sub->cmd = Nullcmd;
+ afree(sub->tosave);
+ }
+ Safefree(sub);
+ }
+ Newz(101,sub,1,SUBR);
+ stab_sub(stab) = sub;
+ sub->filestab = curcmd->c_filestab;
+ saw_return = FALSE;
+ tosave = anew(Nullstab);
+ tosave->ary_fill = 0; /* make 1 based */
+ (void)cmd_tosave(cmd,FALSE); /* this builds the tosave array */
+ sub->tosave = tosave;
+ if (saw_return) {
+ struct compcmd mycompblock;
+
+ mycompblock.comp_true = cmd;
+ mycompblock.comp_alt = Nullcmd;
+ cmd = add_label(savestr("_SUB_"),make_ccmd(C_BLOCK,0,
+ Nullarg,mycompblock));
+ saw_return = FALSE;
+ cmd->c_flags |= CF_TERM;
+ cmd->c_head = cmd;
+ }
+ sub->cmd = cmd;
+ if (perldb) {
+ STR *str;
+ STR *tmpstr = str_mortal(&str_undef);
+
+ sprintf(buf,"%s:%ld",stab_val(curcmd->c_filestab)->str_ptr, subline);
+ str = str_make(buf,0);
+ str_cat(str,"-");
+ sprintf(buf,"%ld",(long)curcmd->c_line);
+ str_cat(str,buf);
+ stab_efullname(tmpstr,stab);
+ hstore(stab_xhash(DBsub), tmpstr->str_ptr, tmpstr->str_cur, str, 0);
+ }
+ Safefree(name);
+ return sub;
+}
+
+SUBR *
+make_usub(name, ix, subaddr, filename)
+char *name;
+int ix;
+int (*subaddr)();
+char *filename;
+{
+ register SUBR *sub;
+ STAB *stab = stabent(name,allstabs);
+
+ if (!stab) /* unused function */
+ return Null(SUBR*);
+ if (sub = stab_sub(stab)) {
+ if (dowarn)
+ warn("Subroutine %s redefined",name);
+ if (!sub->usersub && sub->cmd) {
+ cmd_free(sub->cmd);
+ sub->cmd = Nullcmd;
+ afree(sub->tosave);
+ }
+ Safefree(sub);
+ }
+ Newz(101,sub,1,SUBR);
+ stab_sub(stab) = sub;
+ sub->filestab = fstab(filename);
+ sub->usersub = subaddr;
+ sub->userindex = ix;
+ return sub;
+}
+
+void
+make_form(stab,fcmd)
+STAB *stab;
+FCMD *fcmd;
+{
+ if (stab_form(stab)) {
+ FCMD *tmpfcmd;
+ FCMD *nextfcmd;
+
+ for (tmpfcmd = stab_form(stab); tmpfcmd; tmpfcmd = nextfcmd) {
+ nextfcmd = tmpfcmd->f_next;
+ if (tmpfcmd->f_expr)
+ arg_free(tmpfcmd->f_expr);
+ if (tmpfcmd->f_unparsed)
+ str_free(tmpfcmd->f_unparsed);
+ if (tmpfcmd->f_pre)
+ Safefree(tmpfcmd->f_pre);
+ Safefree(tmpfcmd);
+ }
+ }
+ stab_form(stab) = fcmd;
+}
+
+CMD *
+block_head(tail)
+register CMD *tail;
+{
+ CMD *head;
+ register int opt;
+ register int last_opt = 0;
+ register STAB *last_stab = Nullstab;
+ register int count = 0;
+ register CMD *switchbeg = Nullcmd;
+
+ if (tail == Nullcmd) {
+ return tail;
+ }
+ head = tail->c_head;
+
+ for (tail = head; tail; tail = tail->c_next) {
+
+ /* save one measly dereference at runtime */
+ if (tail->c_type == C_IF) {
+ if (!(tail->ucmd.ccmd.cc_alt = tail->ucmd.ccmd.cc_alt->c_next))
+ tail->c_flags |= CF_TERM;
+ }
+ else if (tail->c_type == C_EXPR) {
+ ARG *arg;
+
+ if (tail->ucmd.acmd.ac_expr)
+ arg = tail->ucmd.acmd.ac_expr;
+ else
+ arg = tail->c_expr;
+ if (arg) {
+ if (arg->arg_type == O_RETURN)
+ tail->c_flags |= CF_TERM;
+ else if (arg->arg_type == O_ITEM && arg[1].arg_type == A_CMD)
+ tail->c_flags |= CF_TERM;
+ }
+ }
+ if (!tail->c_next)
+ tail->c_flags |= CF_TERM;
+
+ if (tail->c_expr && (tail->c_flags & CF_OPTIMIZE) == CFT_FALSE)
+ opt_arg(tail,1, tail->c_type == C_EXPR);
+
+ /* now do a little optimization on case-ish structures */
+ switch(tail->c_flags & (CF_OPTIMIZE|CF_FIRSTNEG|CF_INVERT)) {
+ case CFT_ANCHOR:
+ case CFT_STROP:
+ opt = (tail->c_flags & CF_NESURE) ? CFT_STROP : 0;
+ break;
+ case CFT_CCLASS:
+ opt = CFT_STROP;
+ break;
+ case CFT_NUMOP:
+ opt = (tail->c_slen == O_NE ? 0 : CFT_NUMOP);
+ if ((tail->c_flags&(CF_NESURE|CF_EQSURE)) != (CF_NESURE|CF_EQSURE))
+ opt = 0;
+ break;
+ default:
+ opt = 0;
+ }
+ if (opt && opt == last_opt && tail->c_stab == last_stab)
+ count++;
+ else {
+ if (count >= 3) { /* is this the breakeven point? */
+ if (last_opt == CFT_NUMOP)
+ make_nswitch(switchbeg,count);
+ else
+ make_cswitch(switchbeg,count);
+ }
+ if (opt) {
+ count = 1;
+ switchbeg = tail;
+ }
+ else
+ count = 0;
+ }
+ last_opt = opt;
+ last_stab = tail->c_stab;
+ }
+ if (count >= 3) { /* is this the breakeven point? */
+ if (last_opt == CFT_NUMOP)
+ make_nswitch(switchbeg,count);
+ else
+ make_cswitch(switchbeg,count);
+ }
+ return head;
+}
+
+/* We've spotted a sequence of CMDs that all test the value of the same
+ * spat. Thus we can insert a SWITCH in front and jump directly
+ * to the correct one.
+ */
+static void
+make_cswitch(head,count)
+register CMD *head;
+int count;
+{
+ register CMD *cur;
+ register CMD **loc;
+ register int i;
+ register int min = 255;
+ register int max = 0;
+
+ /* make a new head in the exact same spot */
+ New(102,cur, 1, CMD);
+ StructCopy(head,cur,CMD);
+ Zero(head,1,CMD);
+ head->c_head = cur->c_head;
+ head->c_type = C_CSWITCH;
+ head->c_next = cur; /* insert new cmd at front of list */
+ head->c_stab = cur->c_stab;
+
+ Newz(103,loc,258,CMD*);
+ loc++; /* lie a little */
+ while (count--) {
+ if ((cur->c_flags & CF_OPTIMIZE) == CFT_CCLASS) {
+ for (i = 0; i <= 255; i++) {
+ if (!loc[i] && cur->c_short->str_ptr[i>>3] & (1 << (i&7))) {
+ loc[i] = cur;
+ if (i < min)
+ min = i;
+ if (i > max)
+ max = i;
+ }
+ }
+ }
+ else {
+ i = *cur->c_short->str_ptr & 255;
+ if (!loc[i]) {
+ loc[i] = cur;
+ if (i < min)
+ min = i;
+ if (i > max)
+ max = i;
+ }
+ }
+ cur = cur->c_next;
+ }
+ max++;
+ if (min > 0)
+ Move(&loc[min],&loc[0], max - min, CMD*);
+ loc--;
+ min--;
+ max -= min;
+ for (i = 0; i <= max; i++)
+ if (!loc[i])
+ loc[i] = cur;
+ Renew(loc,max+1,CMD*); /* chop it down to size */
+ head->ucmd.scmd.sc_offset = min;
+ head->ucmd.scmd.sc_max = max;
+ head->ucmd.scmd.sc_next = loc;
+}
+
+static void
+make_nswitch(head,count)
+register CMD *head;
+int count;
+{
+ register CMD *cur = head;
+ register CMD **loc;
+ register int i;
+ register int min = 32767;
+ register int max = -32768;
+ int origcount = count;
+ double value; /* or your money back! */
+ short changed; /* so triple your money back! */
+
+ while (count--) {
+ i = (int)str_gnum(cur->c_short);
+ value = (double)i;
+ if (value != cur->c_short->str_u.str_nval)
+ return; /* fractional values--just forget it */
+ changed = i;
+ if (changed != i)
+ return; /* too big for a short */
+ if (cur->c_slen == O_LE)
+ i++;
+ else if (cur->c_slen == O_GE) /* we only do < or > here */
+ i--;
+ if (i < min)
+ min = i;
+ if (i > max)
+ max = i;
+ cur = cur->c_next;
+ }
+ count = origcount;
+ if (max - min > count * 2 + 10) /* too sparse? */
+ return;
+
+ /* now make a new head in the exact same spot */
+ New(104,cur, 1, CMD);
+ StructCopy(head,cur,CMD);
+ Zero(head,1,CMD);
+ head->c_head = cur->c_head;
+ head->c_type = C_NSWITCH;
+ head->c_next = cur; /* insert new cmd at front of list */
+ head->c_stab = cur->c_stab;
+
+ Newz(105,loc, max - min + 3, CMD*);
+ loc++;
+ max -= min;
+ max++;
+ while (count--) {
+ i = (int)str_gnum(cur->c_short);
+ i -= min;
+ switch(cur->c_slen) {
+ case O_LE:
+ i++;
+ case O_LT:
+ for (i--; i >= -1; i--)
+ if (!loc[i])
+ loc[i] = cur;
+ break;
+ case O_GE:
+ i--;
+ case O_GT:
+ for (i++; i <= max; i++)
+ if (!loc[i])
+ loc[i] = cur;
+ break;
+ case O_EQ:
+ if (!loc[i])
+ loc[i] = cur;
+ break;
+ }
+ cur = cur->c_next;
+ }
+ loc--;
+ min--;
+ max++;
+ for (i = 0; i <= max; i++)
+ if (!loc[i])
+ loc[i] = cur;
+ head->ucmd.scmd.sc_offset = min;
+ head->ucmd.scmd.sc_max = max;
+ head->ucmd.scmd.sc_next = loc;
+}
+
+CMD *
+append_line(head,tail)
+register CMD *head;
+register CMD *tail;
+{
+ if (tail == Nullcmd)
+ return head;
+ if (!tail->c_head) /* make sure tail is well formed */
+ tail->c_head = tail;
+ if (head != Nullcmd) {
+ tail = tail->c_head; /* get to start of tail list */
+ if (!head->c_head)
+ head->c_head = head; /* start a new head list */
+ while (head->c_next) {
+ head->c_next->c_head = head->c_head;
+ head = head->c_next; /* get to end of head list */
+ }
+ head->c_next = tail; /* link to end of old list */
+ tail->c_head = head->c_head; /* propagate head pointer */
+ }
+ while (tail->c_next) {
+ tail->c_next->c_head = tail->c_head;
+ tail = tail->c_next;
+ }
+ return tail;
+}
+
+CMD *
+dodb(cur)
+CMD *cur;
+{
+ register CMD *cmd;
+ register CMD *head = cur->c_head;
+ STR *str;
+
+ if (!head)
+ head = cur;
+ if (!head->c_line)
+ return cur;
+ str = afetch(stab_xarray(curcmd->c_filestab),(int)head->c_line,FALSE);
+ if (str == &str_undef || str->str_nok)
+ return cur;
+ str->str_u.str_nval = (double)head->c_line;
+ str->str_nok = 1;
+ Newz(106,cmd,1,CMD);
+ str_magic(str, curcmd->c_filestab, 0, Nullch, 0);
+ str->str_magic->str_u.str_cmd = cmd;
+ cmd->c_type = C_EXPR;
+ cmd->ucmd.acmd.ac_stab = Nullstab;
+ cmd->ucmd.acmd.ac_expr = Nullarg;
+ cmd->c_expr = make_op(O_SUBR, 2,
+ stab2arg(A_WORD,DBstab),
+ Nullarg,
+ Nullarg);
+ /*SUPPRESS 53*/
+ cmd->c_flags |= CF_COND|CF_DBSUB|CFT_D0;
+ cmd->c_line = head->c_line;
+ cmd->c_label = head->c_label;
+ cmd->c_filestab = curcmd->c_filestab;
+ cmd->c_stash = curstash;
+ return append_line(cmd, cur);
+}
+
+CMD *
+make_acmd(type,stab,cond,arg)
+int type;
+STAB *stab;
+ARG *cond;
+ARG *arg;
+{
+ register CMD *cmd;
+
+ Newz(107,cmd,1,CMD);
+ cmd->c_type = type;
+ cmd->ucmd.acmd.ac_stab = stab;
+ cmd->ucmd.acmd.ac_expr = arg;
+ cmd->c_expr = cond;
+ if (cond)
+ cmd->c_flags |= CF_COND;
+ if (cmdline == NOLINE)
+ cmd->c_line = curcmd->c_line;
+ else {
+ cmd->c_line = cmdline;
+ cmdline = NOLINE;
+ }
+ cmd->c_filestab = curcmd->c_filestab;
+ cmd->c_stash = curstash;
+ if (perldb)
+ cmd = dodb(cmd);
+ return cmd;
+}
+
+CMD *
+make_ccmd(type,debuggable,arg,cblock)
+int type;
+int debuggable;
+ARG *arg;
+struct compcmd cblock;
+{
+ register CMD *cmd;
+
+ Newz(108,cmd, 1, CMD);
+ cmd->c_type = type;
+ cmd->c_expr = arg;
+ cmd->ucmd.ccmd.cc_true = cblock.comp_true;
+ cmd->ucmd.ccmd.cc_alt = cblock.comp_alt;
+ if (arg)
+ cmd->c_flags |= CF_COND;
+ if (cmdline == NOLINE)
+ cmd->c_line = curcmd->c_line;
+ else {
+ cmd->c_line = cmdline;
+ cmdline = NOLINE;
+ }
+ cmd->c_filestab = curcmd->c_filestab;
+ cmd->c_stash = curstash;
+ if (perldb && debuggable)
+ cmd = dodb(cmd);
+ return cmd;
+}
+
+CMD *
+make_icmd(type,arg,cblock)
+int type;
+ARG *arg;
+struct compcmd cblock;
+{
+ register CMD *cmd;
+ register CMD *alt;
+ register CMD *cur;
+ register CMD *head;
+ struct compcmd ncblock;
+
+ Newz(109,cmd, 1, CMD);
+ head = cmd;
+ cmd->c_type = type;
+ cmd->c_expr = arg;
+ cmd->ucmd.ccmd.cc_true = cblock.comp_true;
+ cmd->ucmd.ccmd.cc_alt = cblock.comp_alt;
+ if (arg)
+ cmd->c_flags |= CF_COND;
+ if (cmdline == NOLINE)
+ cmd->c_line = curcmd->c_line;
+ else {
+ cmd->c_line = cmdline;
+ cmdline = NOLINE;
+ }
+ cmd->c_filestab = curcmd->c_filestab;
+ cmd->c_stash = curstash;
+ cur = cmd;
+ alt = cblock.comp_alt;
+ while (alt && alt->c_type == C_ELSIF) {
+ cur = alt;
+ alt = alt->ucmd.ccmd.cc_alt;
+ }
+ if (alt) { /* a real life ELSE at the end? */
+ ncblock.comp_true = alt;
+ ncblock.comp_alt = Nullcmd;
+ alt = append_line(cur,make_ccmd(C_ELSE,1,Nullarg,ncblock));
+ cur->ucmd.ccmd.cc_alt = alt;
+ }
+ else
+ alt = cur; /* no ELSE, so cur is proxy ELSE */
+
+ cur = cmd;
+ while (cmd) { /* now point everyone at the ELSE */
+ cur = cmd;
+ cmd = cur->ucmd.ccmd.cc_alt;
+ cur->c_head = head;
+ if (cur->c_type == C_ELSIF)
+ cur->c_type = C_IF;
+ if (cur->c_type == C_IF)
+ cur->ucmd.ccmd.cc_alt = alt;
+ if (cur == alt)
+ break;
+ cur->c_next = cmd;
+ }
+ if (perldb)
+ cur = dodb(cur);
+ return cur;
+}
+
+void
+opt_arg(cmd,fliporflop,acmd)
+register CMD *cmd;
+int fliporflop;
+int acmd;
+{
+ register ARG *arg;
+ int opt = CFT_EVAL;
+ int sure = 0;
+ ARG *arg2;
+ int context = 0; /* 0 = normal, 1 = before &&, 2 = before || */
+ int flp = fliporflop;
+
+ if (!cmd)
+ return;
+ if (!(arg = cmd->c_expr)) {
+ cmd->c_flags &= ~CF_COND;
+ return;
+ }
+
+ /* Can we turn && and || into if and unless? */
+
+ if (acmd && !cmd->ucmd.acmd.ac_expr && !(cmd->c_flags & CF_TERM) &&
+ (arg->arg_type == O_AND || arg->arg_type == O_OR) ) {
+ dehoist(arg,1);
+ arg[2].arg_type &= A_MASK; /* don't suppress eval */
+ dehoist(arg,2);
+ cmd->ucmd.acmd.ac_expr = arg[2].arg_ptr.arg_arg;
+ cmd->c_expr = arg[1].arg_ptr.arg_arg;
+ if (arg->arg_type == O_OR)
+ cmd->c_flags ^= CF_INVERT; /* || is like unless */
+ arg->arg_len = 0;
+ free_arg(arg);
+ arg = cmd->c_expr;
+ }
+
+ /* Turn "if (!expr)" into "unless (expr)" */
+
+ if (!(cmd->c_flags & CF_TERM)) { /* unless return value wanted */
+ while (arg->arg_type == O_NOT) {
+ dehoist(arg,1);
+ cmd->c_flags ^= CF_INVERT; /* flip sense of cmd */
+ cmd->c_expr = arg[1].arg_ptr.arg_arg; /* hoist the rest of expr */
+ free_arg(arg);
+ arg = cmd->c_expr; /* here we go again */
+ }
+ }
+
+ if (!arg->arg_len) { /* sanity check */
+ cmd->c_flags |= opt;
+ return;
+ }
+
+ /* for "cond .. cond" we set up for the initial check */
+
+ if (arg->arg_type == O_FLIP)
+ context |= 4;
+
+ /* for "cond && expr" and "cond || expr" we can ignore expr, sort of */
+
+ morecontext:
+ if (arg->arg_type == O_AND)
+ context |= 1;
+ else if (arg->arg_type == O_OR)
+ context |= 2;
+ if (context && (arg[flp].arg_type & A_MASK) == A_EXPR) {
+ arg = arg[flp].arg_ptr.arg_arg;
+ flp = 1;
+ if (arg->arg_type == O_AND || arg->arg_type == O_OR)
+ goto morecontext;
+ }
+ if ((context & 3) == 3)
+ return;
+
+ if (arg[flp].arg_flags & (AF_PRE|AF_POST)) {
+ cmd->c_flags |= opt;
+ if (acmd && !cmd->ucmd.acmd.ac_expr && !(cmd->c_flags & CF_TERM)
+ && cmd->c_expr->arg_type == O_ITEM) {
+ arg[flp].arg_flags &= ~AF_POST; /* prefer ++$foo to $foo++ */
+ arg[flp].arg_flags |= AF_PRE; /* if value not wanted */
+ }
+ return; /* side effect, can't optimize */
+ }
+
+ if (arg->arg_type == O_ITEM || arg->arg_type == O_FLIP ||
+ arg->arg_type == O_AND || arg->arg_type == O_OR) {
+ if ((arg[flp].arg_type & A_MASK) == A_SINGLE) {
+ opt = (str_true(arg[flp].arg_ptr.arg_str) ? CFT_TRUE : CFT_FALSE);
+ cmd->c_short = str_smake(arg[flp].arg_ptr.arg_str);
+ goto literal;
+ }
+ else if ((arg[flp].arg_type & A_MASK) == A_STAB ||
+ (arg[flp].arg_type & A_MASK) == A_LVAL) {
+ cmd->c_stab = arg[flp].arg_ptr.arg_stab;
+ if (!context)
+ arg[flp].arg_ptr.arg_stab = Nullstab;
+ opt = CFT_REG;
+ literal:
+ if (!context) { /* no && or ||? */
+ arg_free(arg);
+ cmd->c_expr = Nullarg;
+ }
+ if (!(context & 1))
+ cmd->c_flags |= CF_EQSURE;
+ if (!(context & 2))
+ cmd->c_flags |= CF_NESURE;
+ }
+ }
+ else if (arg->arg_type == O_MATCH || arg->arg_type == O_SUBST ||
+ arg->arg_type == O_NMATCH || arg->arg_type == O_NSUBST) {
+ if ((arg[1].arg_type == A_STAB || arg[1].arg_type == A_LVAL) &&
+ (arg[2].arg_type & A_MASK) == A_SPAT &&
+ arg[2].arg_ptr.arg_spat->spat_short &&
+ (arg->arg_type == O_SUBST || arg->arg_type == O_NSUBST ||
+ (arg[2].arg_ptr.arg_spat->spat_flags & SPAT_GLOBAL) == 0 )) {
+ cmd->c_stab = arg[1].arg_ptr.arg_stab;
+ cmd->c_short = str_smake(arg[2].arg_ptr.arg_spat->spat_short);
+ cmd->c_slen = arg[2].arg_ptr.arg_spat->spat_slen;
+ if (arg[2].arg_ptr.arg_spat->spat_flags & SPAT_ALL &&
+ !(arg[2].arg_ptr.arg_spat->spat_flags & SPAT_ONCE) &&
+ (arg->arg_type == O_MATCH || arg->arg_type == O_NMATCH) )
+ sure |= CF_EQSURE; /* (SUBST must be forced even */
+ /* if we know it will work.) */
+ if (arg->arg_type != O_SUBST) {
+ str_free(arg[2].arg_ptr.arg_spat->spat_short);
+ arg[2].arg_ptr.arg_spat->spat_short = Nullstr;
+ arg[2].arg_ptr.arg_spat->spat_slen = 0; /* only one chk */
+ }
+ sure |= CF_NESURE; /* normally only sure if it fails */
+ if (arg->arg_type == O_NMATCH || arg->arg_type == O_NSUBST)
+ cmd->c_flags |= CF_FIRSTNEG;
+ if (context & 1) { /* only sure if thing is false */
+ if (cmd->c_flags & CF_FIRSTNEG)
+ sure &= ~CF_NESURE;
+ else
+ sure &= ~CF_EQSURE;
+ }
+ else if (context & 2) { /* only sure if thing is true */
+ if (cmd->c_flags & CF_FIRSTNEG)
+ sure &= ~CF_EQSURE;
+ else
+ sure &= ~CF_NESURE;
+ }
+ if (sure & (CF_EQSURE|CF_NESURE)) { /* if we know anything*/
+ if (arg[2].arg_ptr.arg_spat->spat_flags & SPAT_SCANFIRST)
+ opt = CFT_SCAN;
+ else
+ opt = CFT_ANCHOR;
+ if (sure == (CF_EQSURE|CF_NESURE) /* really sure? */
+ && arg->arg_type == O_MATCH
+ && context & 4
+ && fliporflop == 1) {
+ spat_free(arg[2].arg_ptr.arg_spat);
+ arg[2].arg_ptr.arg_spat = Nullspat; /* don't do twice */
+ }
+ else
+ cmd->c_spat = arg[2].arg_ptr.arg_spat;
+ cmd->c_flags |= sure;
+ }
+ }
+ }
+ else if (arg->arg_type == O_SEQ || arg->arg_type == O_SNE ||
+ arg->arg_type == O_SLT || arg->arg_type == O_SGT) {
+ if (arg[1].arg_type == A_STAB || arg[1].arg_type == A_LVAL) {
+ if (arg[2].arg_type == A_SINGLE) {
+ /*SUPPRESS 594*/
+ char *junk = str_get(arg[2].arg_ptr.arg_str);
+
+ cmd->c_stab = arg[1].arg_ptr.arg_stab;
+ cmd->c_short = str_smake(arg[2].arg_ptr.arg_str);
+ cmd->c_slen = cmd->c_short->str_cur+1;
+ switch (arg->arg_type) {
+ case O_SLT: case O_SGT:
+ sure |= CF_EQSURE;
+ cmd->c_flags |= CF_FIRSTNEG;
+ break;
+ case O_SNE:
+ cmd->c_flags |= CF_FIRSTNEG;
+ /* FALL THROUGH */
+ case O_SEQ:
+ sure |= CF_NESURE|CF_EQSURE;
+ break;
+ }
+ if (context & 1) { /* only sure if thing is false */
+ if (cmd->c_flags & CF_FIRSTNEG)
+ sure &= ~CF_NESURE;
+ else
+ sure &= ~CF_EQSURE;
+ }
+ else if (context & 2) { /* only sure if thing is true */
+ if (cmd->c_flags & CF_FIRSTNEG)
+ sure &= ~CF_EQSURE;
+ else
+ sure &= ~CF_NESURE;
+ }
+ if (sure & (CF_EQSURE|CF_NESURE)) {
+ opt = CFT_STROP;
+ cmd->c_flags |= sure;
+ }
+ }
+ }
+ }
+ else if (arg->arg_type == O_EQ || arg->arg_type == O_NE ||
+ arg->arg_type == O_LE || arg->arg_type == O_GE ||
+ arg->arg_type == O_LT || arg->arg_type == O_GT) {
+ if (arg[1].arg_type == A_STAB || arg[1].arg_type == A_LVAL) {
+ if (arg[2].arg_type == A_SINGLE) {
+ cmd->c_stab = arg[1].arg_ptr.arg_stab;
+ if (dowarn) {
+ STR *str = arg[2].arg_ptr.arg_str;
+
+ if ((!str->str_nok && !looks_like_number(str)))
+ warn("Possible use of == on string value");
+ }
+ cmd->c_short = str_nmake(str_gnum(arg[2].arg_ptr.arg_str));
+ cmd->c_slen = arg->arg_type;
+ sure |= CF_NESURE|CF_EQSURE;
+ if (context & 1) { /* only sure if thing is false */
+ sure &= ~CF_EQSURE;
+ }
+ else if (context & 2) { /* only sure if thing is true */
+ sure &= ~CF_NESURE;
+ }
+ if (sure & (CF_EQSURE|CF_NESURE)) {
+ opt = CFT_NUMOP;
+ cmd->c_flags |= sure;
+ }
+ }
+ }
+ }
+ else if (arg->arg_type == O_ASSIGN &&
+ (arg[1].arg_type == A_STAB || arg[1].arg_type == A_LVAL) &&
+ arg[1].arg_ptr.arg_stab == defstab &&
+ arg[2].arg_type == A_EXPR ) {
+ arg2 = arg[2].arg_ptr.arg_arg;
+ if (arg2->arg_type == O_ITEM && arg2[1].arg_type == A_READ) {
+ opt = CFT_GETS;
+ cmd->c_stab = arg2[1].arg_ptr.arg_stab;
+ if (!(stab_io(arg2[1].arg_ptr.arg_stab)->flags & IOF_ARGV)) {
+ free_arg(arg2);
+ arg[2].arg_ptr.arg_arg = Nullarg;
+ free_arg(arg);
+ cmd->c_expr = Nullarg;
+ }
+ }
+ }
+ else if (arg->arg_type == O_CHOP &&
+ (arg[1].arg_type == A_STAB || arg[1].arg_type == A_LVAL) ) {
+ opt = CFT_CHOP;
+ cmd->c_stab = arg[1].arg_ptr.arg_stab;
+ free_arg(arg);
+ cmd->c_expr = Nullarg;
+ }
+ if (context & 4)
+ opt |= CF_FLIP;
+ cmd->c_flags |= opt;
+
+ if (cmd->c_flags & CF_FLIP) {
+ if (fliporflop == 1) {
+ arg = cmd->c_expr; /* get back to O_FLIP arg */
+ New(110,arg[3].arg_ptr.arg_cmd, 1, CMD);
+ Copy(cmd, arg[3].arg_ptr.arg_cmd, 1, CMD);
+ New(111,arg[4].arg_ptr.arg_cmd,1,CMD);
+ Copy(cmd, arg[4].arg_ptr.arg_cmd, 1, CMD);
+ opt_arg(arg[4].arg_ptr.arg_cmd,2,acmd);
+ arg->arg_len = 2; /* this is a lie */
+ }
+ else {
+ if ((opt & CF_OPTIMIZE) == CFT_EVAL)
+ cmd->c_flags = (cmd->c_flags & ~CF_OPTIMIZE) | CFT_UNFLIP;
+ }
+ }
+}
+
+CMD *
+add_label(lbl,cmd)
+char *lbl;
+register CMD *cmd;
+{
+ if (cmd)
+ cmd->c_label = lbl;
+ return cmd;
+}
+
+CMD *
+addcond(cmd, arg)
+register CMD *cmd;
+register ARG *arg;
+{
+ cmd->c_expr = arg;
+ cmd->c_flags |= CF_COND;
+ return cmd;
+}
+
+CMD *
+addloop(cmd, arg)
+register CMD *cmd;
+register ARG *arg;
+{
+ void while_io();
+
+ cmd->c_expr = arg;
+ cmd->c_flags |= CF_COND|CF_LOOP;
+
+ if (!(cmd->c_flags & CF_INVERT))
+ while_io(cmd); /* add $_ =, if necessary */
+
+ if (cmd->c_type == C_BLOCK)
+ cmd->c_flags &= ~CF_COND;
+ else {
+ arg = cmd->ucmd.acmd.ac_expr;
+ if (arg && arg->arg_type == O_ITEM && arg[1].arg_type == A_CMD)
+ cmd->c_flags &= ~CF_COND; /* "do {} while" happens at least once */
+ if (arg && (arg->arg_flags & AF_DEPR) &&
+ (arg->arg_type == O_SUBR || arg->arg_type == O_DBSUBR) )
+ cmd->c_flags &= ~CF_COND; /* likewise for "do subr() while" */
+ }
+ return cmd;
+}
+
+CMD *
+invert(cmd)
+CMD *cmd;
+{
+ register CMD *targ = cmd;
+ if (targ->c_head)
+ targ = targ->c_head;
+ if (targ->c_flags & CF_DBSUB)
+ targ = targ->c_next;
+ targ->c_flags ^= CF_INVERT;
+ return cmd;
+}
+
+void
+cpy7bit(d,s,l)
+register char *d;
+register char *s;
+register int l;
+{
+ while (l--)
+ *d++ = *s++ & 127;
+ *d = '\0';
+}
+
+int
+yyerror(s)
+char *s;
+{
+ char tmpbuf[258];
+ char tmp2buf[258];
+ char *tname = tmpbuf;
+
+ if (bufptr > oldoldbufptr && bufptr - oldoldbufptr < 200 &&
+ oldoldbufptr != oldbufptr && oldbufptr != bufptr) {
+ while (isSPACE(*oldoldbufptr))
+ oldoldbufptr++;
+ cpy7bit(tmp2buf, oldoldbufptr, bufptr - oldoldbufptr);
+ sprintf(tname,"next 2 tokens \"%s\"",tmp2buf);
+ }
+ else if (bufptr > oldbufptr && bufptr - oldbufptr < 200 &&
+ oldbufptr != bufptr) {
+ while (isSPACE(*oldbufptr))
+ oldbufptr++;
+ cpy7bit(tmp2buf, oldbufptr, bufptr - oldbufptr);
+ sprintf(tname,"next token \"%s\"",tmp2buf);
+ }
+ else if (yychar > 256)
+ tname = "next token ???";
+ else if (!yychar)
+ (void)strcpy(tname,"at EOF");
+ else if (yychar < 32)
+ (void)sprintf(tname,"next char ^%c",yychar+64);
+ else if (yychar == 127)
+ (void)strcpy(tname,"at EOF");
+ else
+ (void)sprintf(tname,"next char %c",yychar);
+ (void)sprintf(buf, "%s in file %s at line %d, %s\n",
+ s,stab_val(curcmd->c_filestab)->str_ptr,curcmd->c_line,tname);
+ if (curcmd->c_line == multi_end && multi_start < multi_end)
+ sprintf(buf+strlen(buf),
+ " (Might be a runaway multi-line %c%c string starting on line %d)\n",
+ multi_open,multi_close,multi_start);
+ if (in_eval)
+ str_cat(stab_val(stabent("@",TRUE)),buf);
+ else
+ fputs(buf,stderr);
+ if (++error_count >= 10)
+ fatal("%s has too many errors.\n",
+ stab_val(curcmd->c_filestab)->str_ptr);
+}
+
+void
+while_io(cmd)
+register CMD *cmd;
+{
+ register ARG *arg = cmd->c_expr;
+ STAB *asgnstab;
+
+ /* hoist "while (<channel>)" up into command block */
+
+ if (arg && arg->arg_type == O_ITEM && arg[1].arg_type == A_READ) {
+ cmd->c_flags &= ~CF_OPTIMIZE; /* clear optimization type */
+ cmd->c_flags |= CFT_GETS; /* and set it to do the input */
+ cmd->c_stab = arg[1].arg_ptr.arg_stab;
+ if (stab_io(arg[1].arg_ptr.arg_stab)->flags & IOF_ARGV) {
+ cmd->c_expr = l(make_op(O_ASSIGN, 2, /* fake up "$_ =" */
+ stab2arg(A_LVAL,defstab), arg, Nullarg));
+ }
+ else {
+ free_arg(arg);
+ cmd->c_expr = Nullarg;
+ }
+ }
+ else if (arg && arg->arg_type == O_ITEM && arg[1].arg_type == A_INDREAD) {
+ cmd->c_flags &= ~CF_OPTIMIZE; /* clear optimization type */
+ cmd->c_flags |= CFT_INDGETS; /* and set it to do the input */
+ cmd->c_stab = arg[1].arg_ptr.arg_stab;
+ free_arg(arg);
+ cmd->c_expr = Nullarg;
+ }
+ else if (arg && arg->arg_type == O_ITEM && arg[1].arg_type == A_GLOB) {
+ if ((cmd->c_flags & CF_OPTIMIZE) == CFT_ARRAY)
+ asgnstab = cmd->c_stab;
+ else
+ asgnstab = defstab;
+ cmd->c_expr = l(make_op(O_ASSIGN, 2, /* fake up "$foo =" */
+ stab2arg(A_LVAL,asgnstab), arg, Nullarg));
+ cmd->c_flags &= ~CF_OPTIMIZE; /* clear optimization type */
+ }
+}
+
+CMD *
+wopt(cmd)
+register CMD *cmd;
+{
+ register CMD *tail;
+ CMD *newtail;
+ register int i;
+
+ if (cmd->c_expr && (cmd->c_flags & CF_OPTIMIZE) == CFT_FALSE)
+ opt_arg(cmd,1, cmd->c_type == C_EXPR);
+
+ while_io(cmd); /* add $_ =, if necessary */
+
+ /* First find the end of the true list */
+
+ tail = cmd->ucmd.ccmd.cc_true;
+ if (tail == Nullcmd)
+ return cmd;
+ New(112,newtail, 1, CMD); /* guaranteed continue */
+ for (;;) {
+ /* optimize "next" to point directly to continue block */
+ if (tail->c_type == C_EXPR &&
+ tail->ucmd.acmd.ac_expr &&
+ tail->ucmd.acmd.ac_expr->arg_type == O_NEXT &&
+ (tail->ucmd.acmd.ac_expr->arg_len == 0 ||
+ (cmd->c_label &&
+ strEQ(cmd->c_label,
+ tail->ucmd.acmd.ac_expr[1].arg_ptr.arg_str->str_ptr) )))
+ {
+ arg_free(tail->ucmd.acmd.ac_expr);
+ tail->ucmd.acmd.ac_expr = Nullarg;
+ tail->c_type = C_NEXT;
+ if (cmd->ucmd.ccmd.cc_alt != Nullcmd)
+ tail->ucmd.ccmd.cc_alt = cmd->ucmd.ccmd.cc_alt;
+ else
+ tail->ucmd.ccmd.cc_alt = newtail;
+ tail->ucmd.ccmd.cc_true = Nullcmd;
+ }
+ else if (tail->c_type == C_IF && !tail->ucmd.ccmd.cc_alt) {
+ if (cmd->ucmd.ccmd.cc_alt != Nullcmd)
+ tail->ucmd.ccmd.cc_alt = cmd->ucmd.ccmd.cc_alt;
+ else
+ tail->ucmd.ccmd.cc_alt = newtail;
+ }
+ else if (tail->c_type == C_CSWITCH || tail->c_type == C_NSWITCH) {
+ if (cmd->ucmd.ccmd.cc_alt != Nullcmd) {
+ for (i = tail->ucmd.scmd.sc_max; i >= 0; i--)
+ if (!tail->ucmd.scmd.sc_next[i])
+ tail->ucmd.scmd.sc_next[i] = cmd->ucmd.ccmd.cc_alt;
+ }
+ else {
+ for (i = tail->ucmd.scmd.sc_max; i >= 0; i--)
+ if (!tail->ucmd.scmd.sc_next[i])
+ tail->ucmd.scmd.sc_next[i] = newtail;
+ }
+ }
+
+ if (!tail->c_next)
+ break;
+ tail = tail->c_next;
+ }
+
+ /* if there's a continue block, link it to true block and find end */
+
+ if (cmd->ucmd.ccmd.cc_alt != Nullcmd) {
+ tail->c_next = cmd->ucmd.ccmd.cc_alt;
+ tail = tail->c_next;
+ for (;;) {
+ /* optimize "next" to point directly to continue block */
+ if (tail->c_type == C_EXPR &&
+ tail->ucmd.acmd.ac_expr &&
+ tail->ucmd.acmd.ac_expr->arg_type == O_NEXT &&
+ (tail->ucmd.acmd.ac_expr->arg_len == 0 ||
+ (cmd->c_label &&
+ strEQ(cmd->c_label,
+ tail->ucmd.acmd.ac_expr[1].arg_ptr.arg_str->str_ptr) )))
+ {
+ arg_free(tail->ucmd.acmd.ac_expr);
+ tail->ucmd.acmd.ac_expr = Nullarg;
+ tail->c_type = C_NEXT;
+ tail->ucmd.ccmd.cc_alt = newtail;
+ tail->ucmd.ccmd.cc_true = Nullcmd;
+ }
+ else if (tail->c_type == C_IF && !tail->ucmd.ccmd.cc_alt) {
+ tail->ucmd.ccmd.cc_alt = newtail;
+ }
+ else if (tail->c_type == C_CSWITCH || tail->c_type == C_NSWITCH) {
+ for (i = tail->ucmd.scmd.sc_max; i >= 0; i--)
+ if (!tail->ucmd.scmd.sc_next[i])
+ tail->ucmd.scmd.sc_next[i] = newtail;
+ }
+
+ if (!tail->c_next)
+ break;
+ tail = tail->c_next;
+ }
+ /*SUPPRESS 530*/
+ for ( ; tail->c_next; tail = tail->c_next) ;
+ }
+
+ /* Here's the real trick: link the end of the list back to the beginning,
+ * inserting a "last" block to break out of the loop. This saves one or
+ * two procedure calls every time through the loop, because of how cmd_exec
+ * does tail recursion.
+ */
+
+ tail->c_next = newtail;
+ tail = newtail;
+ if (!cmd->ucmd.ccmd.cc_alt)
+ cmd->ucmd.ccmd.cc_alt = tail; /* every loop has a continue now */
+
+#ifndef lint
+ Copy((char *)cmd, (char *)tail, 1, CMD);
+#endif
+ tail->c_type = C_EXPR;
+ tail->c_flags ^= CF_INVERT; /* turn into "last unless" */
+ tail->c_next = tail->ucmd.ccmd.cc_true; /* loop directly back to top */
+ tail->ucmd.acmd.ac_expr = make_op(O_LAST,0,Nullarg,Nullarg,Nullarg);
+ tail->ucmd.acmd.ac_stab = Nullstab;
+ return cmd;
+}
+
+CMD *
+over(eachstab,cmd)
+STAB *eachstab;
+register CMD *cmd;
+{
+ /* hoist "for $foo (@bar)" up into command block */
+
+ cmd->c_flags &= ~CF_OPTIMIZE; /* clear optimization type */
+ cmd->c_flags |= CFT_ARRAY; /* and set it to do the iteration */
+ cmd->c_stab = eachstab;
+ cmd->c_short = Str_new(23,0); /* just to save a field in struct cmd */
+ cmd->c_short->str_u.str_useful = -1;
+
+ return cmd;
+}
+
+void
+cmd_free(cmd)
+register CMD *cmd;
+{
+ register CMD *tofree;
+ register CMD *head = cmd;
+
+ if (!cmd)
+ return;
+ if (cmd->c_head != cmd)
+ warn("Malformed cmd links\n");
+ while (cmd) {
+ if (cmd->c_type != C_WHILE) { /* WHILE block is duplicated */
+ if (cmd->c_label) {
+ Safefree(cmd->c_label);
+ cmd->c_label = Nullch;
+ }
+ if (cmd->c_short) {
+ str_free(cmd->c_short);
+ cmd->c_short = Nullstr;
+ }
+ if (cmd->c_expr) {
+ arg_free(cmd->c_expr);
+ cmd->c_expr = Nullarg;
+ }
+ }
+ switch (cmd->c_type) {
+ case C_WHILE:
+ case C_BLOCK:
+ case C_ELSE:
+ case C_IF:
+ if (cmd->ucmd.ccmd.cc_true) {
+ cmd_free(cmd->ucmd.ccmd.cc_true);
+ cmd->ucmd.ccmd.cc_true = Nullcmd;
+ }
+ break;
+ case C_EXPR:
+ if (cmd->ucmd.acmd.ac_expr) {
+ arg_free(cmd->ucmd.acmd.ac_expr);
+ cmd->ucmd.acmd.ac_expr = Nullarg;
+ }
+ break;
+ }
+ tofree = cmd;
+ cmd = cmd->c_next;
+ if (tofree != head) /* to get Saber to shut up */
+ Safefree(tofree);
+ if (cmd && cmd == head) /* reached end of while loop */
+ break;
+ }
+ Safefree(head);
+}
+
+void
+arg_free(arg)
+register ARG *arg;
+{
+ register int i;
+
+ if (!arg)
+ return;
+ for (i = 1; i <= arg->arg_len; i++) {
+ switch (arg[i].arg_type & A_MASK) {
+ case A_NULL:
+ if (arg->arg_type == O_TRANS) {
+ Safefree(arg[i].arg_ptr.arg_cval);
+ arg[i].arg_ptr.arg_cval = Nullch;
+ }
+ break;
+ case A_LEXPR:
+ if (arg->arg_type == O_AASSIGN &&
+ arg[i].arg_ptr.arg_arg->arg_type == O_LARRAY) {
+ char *name =
+ stab_name(arg[i].arg_ptr.arg_arg[1].arg_ptr.arg_stab);
+
+ if (strnEQ("_GEN_",name, 5)) /* array for foreach */
+ hdelete(defstash,name,strlen(name));
+ }
+ /* FALL THROUGH */
+ case A_EXPR:
+ arg_free(arg[i].arg_ptr.arg_arg);
+ arg[i].arg_ptr.arg_arg = Nullarg;
+ break;
+ case A_CMD:
+ cmd_free(arg[i].arg_ptr.arg_cmd);
+ arg[i].arg_ptr.arg_cmd = Nullcmd;
+ break;
+ case A_WORD:
+ case A_STAB:
+ case A_LVAL:
+ case A_READ:
+ case A_GLOB:
+ case A_ARYLEN:
+ case A_LARYLEN:
+ case A_ARYSTAB:
+ case A_LARYSTAB:
+ break;
+ case A_SINGLE:
+ case A_DOUBLE:
+ case A_BACKTICK:
+ str_free(arg[i].arg_ptr.arg_str);
+ arg[i].arg_ptr.arg_str = Nullstr;
+ break;
+ case A_SPAT:
+ spat_free(arg[i].arg_ptr.arg_spat);
+ arg[i].arg_ptr.arg_spat = Nullspat;
+ break;
+ }
+ }
+ free_arg(arg);
+}
+
+void
+spat_free(spat)
+register SPAT *spat;
+{
+ register SPAT *sp;
+ HENT *entry;
+
+ if (!spat)
+ return;
+ if (spat->spat_runtime) {
+ arg_free(spat->spat_runtime);
+ spat->spat_runtime = Nullarg;
+ }
+ if (spat->spat_repl) {
+ arg_free(spat->spat_repl);
+ spat->spat_repl = Nullarg;
+ }
+ if (spat->spat_short) {
+ str_free(spat->spat_short);
+ spat->spat_short = Nullstr;
+ }
+ if (spat->spat_regexp) {
+ regfree(spat->spat_regexp);
+ spat->spat_regexp = Null(REGEXP*);
+ }
+
+ /* now unlink from spat list */
+
+ for (entry = defstash->tbl_array['_']; entry; entry = entry->hent_next) {
+ register HASH *stash;
+ STAB *stab = (STAB*)entry->hent_val;
+
+ if (!stab)
+ continue;
+ stash = stab_hash(stab);
+ if (!stash || stash->tbl_spatroot == Null(SPAT*))
+ continue;
+ if (stash->tbl_spatroot == spat)
+ stash->tbl_spatroot = spat->spat_next;
+ else {
+ for (sp = stash->tbl_spatroot;
+ sp && sp->spat_next != spat;
+ sp = sp->spat_next)
+ /*SUPPRESS 530*/
+ ;
+ if (sp)
+ sp->spat_next = spat->spat_next;
+ }
+ }
+ Safefree(spat);
+}
+
+/* Recursively descend a command sequence and push the address of any string
+ * that needs saving on recursion onto the tosave array.
+ */
+
+static int
+cmd_tosave(cmd,willsave)
+register CMD *cmd;
+int willsave; /* willsave passes down the tree */
+{
+ register CMD *head = cmd;
+ int shouldsave = FALSE; /* shouldsave passes up the tree */
+ int tmpsave;
+ register CMD *lastcmd = Nullcmd;
+
+ while (cmd) {
+ if (cmd->c_expr)
+ shouldsave |= arg_tosave(cmd->c_expr,willsave);
+ switch (cmd->c_type) {
+ case C_WHILE:
+ if (cmd->ucmd.ccmd.cc_true) {
+ tmpsave = cmd_tosave(cmd->ucmd.ccmd.cc_true,willsave);
+
+ /* Here we check to see if the temporary array generated for
+ * a foreach needs to be localized because of recursion.
+ */
+ if (tmpsave && (cmd->c_flags & CF_OPTIMIZE) == CFT_ARRAY) {
+ if (lastcmd &&
+ lastcmd->c_type == C_EXPR &&
+ lastcmd->c_expr) {
+ ARG *arg = lastcmd->c_expr;
+
+ if (arg->arg_type == O_ASSIGN &&
+ arg[1].arg_type == A_LEXPR &&
+ arg[1].arg_ptr.arg_arg->arg_type == O_LARRAY &&
+ strnEQ("_GEN_",
+ stab_name(
+ arg[1].arg_ptr.arg_arg[1].arg_ptr.arg_stab),
+ 5)) { /* array generated for foreach */
+ (void)localize(arg);
+ }
+ }
+
+ /* in any event, save the iterator */
+
+ if (cmd->c_short) /* Better safe than sorry */
+ (void)apush(tosave,cmd->c_short);
+ }
+ shouldsave |= tmpsave;
+ }
+ break;
+ case C_BLOCK:
+ case C_ELSE:
+ case C_IF:
+ if (cmd->ucmd.ccmd.cc_true)
+ shouldsave |= cmd_tosave(cmd->ucmd.ccmd.cc_true,willsave);
+ break;
+ case C_EXPR:
+ if (cmd->ucmd.acmd.ac_expr)
+ shouldsave |= arg_tosave(cmd->ucmd.acmd.ac_expr,willsave);
+ break;
+ }
+ lastcmd = cmd;
+ cmd = cmd->c_next;
+ if (cmd && cmd == head) /* reached end of while loop */
+ break;
+ }
+ return shouldsave;
+}
+
+static int
+arg_tosave(arg,willsave)
+register ARG *arg;
+int willsave;
+{
+ register int i;
+ int shouldsave = FALSE;
+
+ for (i = arg->arg_len; i >= 1; i--) {
+ switch (arg[i].arg_type & A_MASK) {
+ case A_NULL:
+ break;
+ case A_LEXPR:
+ case A_EXPR:
+ shouldsave |= arg_tosave(arg[i].arg_ptr.arg_arg,shouldsave);
+ break;
+ case A_CMD:
+ shouldsave |= cmd_tosave(arg[i].arg_ptr.arg_cmd,shouldsave);
+ break;
+ case A_WORD:
+ case A_STAB:
+ case A_LVAL:
+ case A_READ:
+ case A_GLOB:
+ case A_ARYLEN:
+ case A_SINGLE:
+ case A_DOUBLE:
+ case A_BACKTICK:
+ break;
+ case A_SPAT:
+ shouldsave |= spat_tosave(arg[i].arg_ptr.arg_spat);
+ break;
+ }
+ }
+ switch (arg->arg_type) {
+ case O_RETURN:
+ saw_return = TRUE;
+ break;
+ case O_EVAL:
+ case O_SUBR:
+ shouldsave = TRUE;
+ break;
+ }
+ if (willsave && arg->arg_ptr.arg_str)
+ (void)apush(tosave,arg->arg_ptr.arg_str);
+ return shouldsave;
+}
+
+static int
+spat_tosave(spat)
+register SPAT *spat;
+{
+ int shouldsave = FALSE;
+
+ if (spat->spat_runtime)
+ shouldsave |= arg_tosave(spat->spat_runtime,FALSE);
+ if (spat->spat_repl) {
+ shouldsave |= arg_tosave(spat->spat_repl,FALSE);
+ }
+
+ return shouldsave;
+}
+
diff --git a/gnu/usr.bin/perl/perl/consarg.c b/gnu/usr.bin/perl/perl/consarg.c
new file mode 100644
index 0000000..d0d59b7
--- /dev/null
+++ b/gnu/usr.bin/perl/perl/consarg.c
@@ -0,0 +1,1299 @@
+/* $RCSfile: consarg.c,v $$Revision: 1.2 $$Date: 1994/09/11 03:17:29 $
+ *
+ * Copyright (c) 1991, Larry Wall
+ *
+ * You may distribute under the terms of either the GNU General Public
+ * License or the Artistic License, as specified in the README file.
+ *
+ * $Log: consarg.c,v $
+ * Revision 1.2 1994/09/11 03:17:29 gclarkii
+ * Changed AF_LOCAL to AF_LOCAL_XX so as not to conflict with 4.4 socket.h
+ * Added casts to shutup warnings in doio.c
+ *
+ * Revision 1.1.1.1 1994/09/10 06:27:32 gclarkii
+ * Initial import of Perl 4.046 bmaked
+ *
+ * Revision 1.1.1.1 1993/08/23 21:29:35 nate
+ * PERL!
+ *
+ * Revision 4.0.1.4 92/06/08 12:26:27 lwall
+ * patch20: new warning for use of x with non-numeric right operand
+ * patch20: modulus with highest bit in left operand set didn't always work
+ * patch20: illegal lvalue message could be followed by core dump
+ * patch20: deleted some minor memory leaks
+ *
+ * Revision 4.0.1.3 91/11/05 16:21:16 lwall
+ * patch11: random cleanup
+ * patch11: added eval {}
+ * patch11: added sort {} LIST
+ * patch11: "foo" x -1 dumped core
+ * patch11: substr() and vec() weren't allowed in an lvalue list
+ *
+ * Revision 4.0.1.2 91/06/07 10:33:12 lwall
+ * patch4: new copyright notice
+ * patch4: length($`), length($&), length($') now optimized to avoid string copy
+ *
+ * Revision 4.0.1.1 91/04/11 17:38:34 lwall
+ * patch1: fixed "Bad free" error
+ *
+ * Revision 4.0 91/03/20 01:06:15 lwall
+ * 4.0 baseline.
+ *
+ */
+
+#include "EXTERN.h"
+#include "perl.h"
+static int nothing_in_common();
+static int arg_common();
+static int spat_common();
+
+ARG *
+make_split(stab,arg,limarg)
+register STAB *stab;
+register ARG *arg;
+ARG *limarg;
+{
+ register SPAT *spat;
+
+ if (arg->arg_type != O_MATCH) {
+ Newz(201,spat,1,SPAT);
+ spat->spat_next = curstash->tbl_spatroot; /* link into spat list */
+ curstash->tbl_spatroot = spat;
+
+ spat->spat_runtime = arg;
+ arg = make_match(O_MATCH,stab2arg(A_STAB,defstab),spat);
+ }
+ Renew(arg,4,ARG);
+ arg->arg_len = 3;
+ if (limarg) {
+ if (limarg->arg_type == O_ITEM) {
+ Copy(limarg+1,arg+3,1,ARG);
+ limarg[1].arg_type = A_NULL;
+ arg_free(limarg);
+ }
+ else {
+ arg[3].arg_flags = 0;
+ arg[3].arg_len = 0;
+ arg[3].arg_type = A_EXPR;
+ arg[3].arg_ptr.arg_arg = limarg;
+ }
+ }
+ else {
+ arg[3].arg_flags = 0;
+ arg[3].arg_len = 0;
+ arg[3].arg_type = A_NULL;
+ arg[3].arg_ptr.arg_arg = Nullarg;
+ }
+ arg->arg_type = O_SPLIT;
+ spat = arg[2].arg_ptr.arg_spat;
+ spat->spat_repl = stab2arg(A_STAB,aadd(stab));
+ if (spat->spat_short) { /* exact match can bypass regexec() */
+ if (!((spat->spat_flags & SPAT_SCANFIRST) &&
+ (spat->spat_flags & SPAT_ALL) )) {
+ str_free(spat->spat_short);
+ spat->spat_short = Nullstr;
+ }
+ }
+ return arg;
+}
+
+ARG *
+mod_match(type,left,pat)
+register ARG *left;
+register ARG *pat;
+{
+
+ register SPAT *spat;
+ register ARG *newarg;
+
+ if (!pat)
+ return Nullarg;
+
+ if ((pat->arg_type == O_MATCH ||
+ pat->arg_type == O_SUBST ||
+ pat->arg_type == O_TRANS ||
+ pat->arg_type == O_SPLIT
+ ) &&
+ pat[1].arg_ptr.arg_stab == defstab ) {
+ switch (pat->arg_type) {
+ case O_MATCH:
+ newarg = make_op(type == O_MATCH ? O_MATCH : O_NMATCH,
+ pat->arg_len,
+ left,Nullarg,Nullarg);
+ break;
+ case O_SUBST:
+ newarg = l(make_op(type == O_MATCH ? O_SUBST : O_NSUBST,
+ pat->arg_len,
+ left,Nullarg,Nullarg));
+ break;
+ case O_TRANS:
+ newarg = l(make_op(type == O_MATCH ? O_TRANS : O_NTRANS,
+ pat->arg_len,
+ left,Nullarg,Nullarg));
+ break;
+ case O_SPLIT:
+ newarg = make_op(type == O_MATCH ? O_SPLIT : O_SPLIT,
+ pat->arg_len,
+ left,Nullarg,Nullarg);
+ break;
+ }
+ if (pat->arg_len >= 2) {
+ newarg[2].arg_type = pat[2].arg_type;
+ newarg[2].arg_ptr = pat[2].arg_ptr;
+ newarg[2].arg_len = pat[2].arg_len;
+ newarg[2].arg_flags = pat[2].arg_flags;
+ if (pat->arg_len >= 3) {
+ newarg[3].arg_type = pat[3].arg_type;
+ newarg[3].arg_ptr = pat[3].arg_ptr;
+ newarg[3].arg_len = pat[3].arg_len;
+ newarg[3].arg_flags = pat[3].arg_flags;
+ }
+ }
+ free_arg(pat);
+ }
+ else {
+ Newz(202,spat,1,SPAT);
+ spat->spat_next = curstash->tbl_spatroot; /* link into spat list */
+ curstash->tbl_spatroot = spat;
+
+ spat->spat_runtime = pat;
+ newarg = make_op(type,2,left,Nullarg,Nullarg);
+ newarg[2].arg_type = A_SPAT | A_DONT;
+ newarg[2].arg_ptr.arg_spat = spat;
+ }
+
+ return newarg;
+}
+
+ARG *
+make_op(type,newlen,arg1,arg2,arg3)
+int type;
+int newlen;
+ARG *arg1;
+ARG *arg2;
+ARG *arg3;
+{
+ register ARG *arg;
+ register ARG *chld;
+ register unsigned doarg;
+ register int i;
+ extern ARG *arg4; /* should be normal arguments, really */
+ extern ARG *arg5;
+
+ arg = op_new(newlen);
+ arg->arg_type = type;
+ /*SUPPRESS 560*/
+ if (chld = arg1) {
+ if (chld->arg_type == O_ITEM &&
+ (hoistable[ i = (chld[1].arg_type&A_MASK)] || i == A_LVAL ||
+ (i == A_LEXPR &&
+ (chld[1].arg_ptr.arg_arg->arg_type == O_LIST ||
+ chld[1].arg_ptr.arg_arg->arg_type == O_ARRAY ||
+ chld[1].arg_ptr.arg_arg->arg_type == O_HASH ))))
+ {
+ arg[1].arg_type = chld[1].arg_type;
+ arg[1].arg_ptr = chld[1].arg_ptr;
+ arg[1].arg_flags |= chld[1].arg_flags;
+ arg[1].arg_len = chld[1].arg_len;
+ free_arg(chld);
+ }
+ else {
+ arg[1].arg_type = A_EXPR;
+ arg[1].arg_ptr.arg_arg = chld;
+ }
+ }
+ /*SUPPRESS 560*/
+ if (chld = arg2) {
+ if (chld->arg_type == O_ITEM &&
+ (hoistable[chld[1].arg_type&A_MASK] ||
+ (type == O_ASSIGN &&
+ ((chld[1].arg_type == A_READ && !(arg[1].arg_type & A_DONT))
+ ||
+ (chld[1].arg_type == A_INDREAD && !(arg[1].arg_type & A_DONT))
+ ||
+ (chld[1].arg_type == A_GLOB && !(arg[1].arg_type & A_DONT))
+ ) ) ) ) {
+ arg[2].arg_type = chld[1].arg_type;
+ arg[2].arg_ptr = chld[1].arg_ptr;
+ arg[2].arg_len = chld[1].arg_len;
+ free_arg(chld);
+ }
+ else {
+ arg[2].arg_type = A_EXPR;
+ arg[2].arg_ptr.arg_arg = chld;
+ }
+ }
+ /*SUPPRESS 560*/
+ if (chld = arg3) {
+ if (chld->arg_type == O_ITEM && hoistable[chld[1].arg_type&A_MASK]) {
+ arg[3].arg_type = chld[1].arg_type;
+ arg[3].arg_ptr = chld[1].arg_ptr;
+ arg[3].arg_len = chld[1].arg_len;
+ free_arg(chld);
+ }
+ else {
+ arg[3].arg_type = A_EXPR;
+ arg[3].arg_ptr.arg_arg = chld;
+ }
+ }
+ if (newlen >= 4 && (chld = arg4)) {
+ if (chld->arg_type == O_ITEM && hoistable[chld[1].arg_type&A_MASK]) {
+ arg[4].arg_type = chld[1].arg_type;
+ arg[4].arg_ptr = chld[1].arg_ptr;
+ arg[4].arg_len = chld[1].arg_len;
+ free_arg(chld);
+ }
+ else {
+ arg[4].arg_type = A_EXPR;
+ arg[4].arg_ptr.arg_arg = chld;
+ }
+ }
+ if (newlen >= 5 && (chld = arg5)) {
+ if (chld->arg_type == O_ITEM && hoistable[chld[1].arg_type&A_MASK]) {
+ arg[5].arg_type = chld[1].arg_type;
+ arg[5].arg_ptr = chld[1].arg_ptr;
+ arg[5].arg_len = chld[1].arg_len;
+ free_arg(chld);
+ }
+ else {
+ arg[5].arg_type = A_EXPR;
+ arg[5].arg_ptr.arg_arg = chld;
+ }
+ }
+ doarg = opargs[type];
+ for (i = 1; i <= newlen; ++i) {
+ if (!(doarg & 1))
+ arg[i].arg_type |= A_DONT;
+ if (doarg & 2)
+ arg[i].arg_flags |= AF_ARYOK;
+ doarg >>= 2;
+ }
+#ifdef DEBUGGING
+ if (debug & 16) {
+ fprintf(stderr,"%lx <= make_op(%s",arg,opname[arg->arg_type]);
+ if (arg1)
+ fprintf(stderr,",%s=%lx",
+ argname[arg[1].arg_type&A_MASK],arg[1].arg_ptr.arg_arg);
+ if (arg2)
+ fprintf(stderr,",%s=%lx",
+ argname[arg[2].arg_type&A_MASK],arg[2].arg_ptr.arg_arg);
+ if (arg3)
+ fprintf(stderr,",%s=%lx",
+ argname[arg[3].arg_type&A_MASK],arg[3].arg_ptr.arg_arg);
+ if (newlen >= 4)
+ fprintf(stderr,",%s=%lx",
+ argname[arg[4].arg_type&A_MASK],arg[4].arg_ptr.arg_arg);
+ if (newlen >= 5)
+ fprintf(stderr,",%s=%lx",
+ argname[arg[5].arg_type&A_MASK],arg[5].arg_ptr.arg_arg);
+ fprintf(stderr,")\n");
+ }
+#endif
+ arg = evalstatic(arg); /* see if we can consolidate anything */
+ return arg;
+}
+
+ARG *
+evalstatic(arg)
+register ARG *arg;
+{
+ static STR *str = Nullstr;
+ register STR *s1;
+ register STR *s2;
+ double value; /* must not be register */
+ register char *tmps;
+ int i;
+ unsigned long tmplong;
+ long tmp2;
+ double exp(), log(), sqrt(), modf();
+ char *crypt();
+ double sin(), cos(), atan2(), pow();
+
+ if (!arg || !arg->arg_len)
+ return arg;
+
+ if (!str)
+ str = Str_new(20,0);
+
+ if (arg[1].arg_type == A_SINGLE)
+ s1 = arg[1].arg_ptr.arg_str;
+ else
+ s1 = Nullstr;
+ if (arg->arg_len >= 2 && arg[2].arg_type == A_SINGLE)
+ s2 = arg[2].arg_ptr.arg_str;
+ else
+ s2 = Nullstr;
+
+#define CHECK1 if (!s1) return arg
+#define CHECK2 if (!s2) return arg
+#define CHECK12 if (!s1 || !s2) return arg
+
+ switch (arg->arg_type) {
+ default:
+ return arg;
+ case O_SORT:
+ if (arg[1].arg_type == A_CMD)
+ arg[1].arg_type |= A_DONT;
+ return arg;
+ case O_EVAL:
+ if (arg[1].arg_type == A_CMD) {
+ arg->arg_type = O_TRY;
+ arg[1].arg_type |= A_DONT;
+ return arg;
+ }
+ CHECK1;
+ arg->arg_type = O_EVALONCE;
+ return arg;
+ case O_AELEM:
+ CHECK2;
+ i = (int)str_gnum(s2);
+ if (i < 32767 && i >= 0) {
+ arg->arg_type = O_ITEM;
+ arg->arg_len = 1;
+ arg[1].arg_type = A_ARYSTAB; /* $abc[123] is hoistable now */
+ arg[1].arg_len = i;
+ str_free(s2);
+ Renew(arg, 2, ARG);
+ }
+ return arg;
+ case O_CONCAT:
+ CHECK12;
+ str_sset(str,s1);
+ str_scat(str,s2);
+ break;
+ case O_REPEAT:
+ CHECK2;
+ if (dowarn && !s2->str_nok && !looks_like_number(s2))
+ warn("Right operand of x is not numeric");
+ CHECK1;
+ i = (int)str_gnum(s2);
+ tmps = str_get(s1);
+ str_nset(str,"",0);
+ if (i > 0) {
+ STR_GROW(str, i * s1->str_cur + 1);
+ repeatcpy(str->str_ptr, tmps, s1->str_cur, i);
+ str->str_cur = i * s1->str_cur;
+ str->str_ptr[str->str_cur] = '\0';
+ }
+ break;
+ case O_MULTIPLY:
+ CHECK12;
+ value = str_gnum(s1);
+ str_numset(str,value * str_gnum(s2));
+ break;
+ case O_DIVIDE:
+ CHECK12;
+ value = str_gnum(s2);
+ if (value == 0.0)
+ yyerror("Illegal division by constant zero");
+ else
+#ifdef SLOPPYDIVIDE
+ /* insure that 20./5. == 4. */
+ {
+ double x;
+ int k;
+ x = str_gnum(s1);
+ if ((double)(int)x == x &&
+ (double)(int)value == value &&
+ (k = (int)x/(int)value)*(int)value == (int)x) {
+ value = k;
+ } else {
+ value = x/value;
+ }
+ str_numset(str,value);
+ }
+#else
+ str_numset(str,str_gnum(s1) / value);
+#endif
+ break;
+ case O_MODULO:
+ CHECK12;
+ tmplong = (unsigned long)str_gnum(s2);
+ if (tmplong == 0L) {
+ yyerror("Illegal modulus of constant zero");
+ return arg;
+ }
+ value = str_gnum(s1);
+#ifndef lint
+ if (value >= 0.0)
+ str_numset(str,(double)(((unsigned long)value) % tmplong));
+ else {
+ tmp2 = (long)value;
+ str_numset(str,(double)((tmplong-((-tmp2 - 1) % tmplong)) - 1));
+ }
+#else
+ tmp2 = tmp2;
+#endif
+ break;
+ case O_ADD:
+ CHECK12;
+ value = str_gnum(s1);
+ str_numset(str,value + str_gnum(s2));
+ break;
+ case O_SUBTRACT:
+ CHECK12;
+ value = str_gnum(s1);
+ str_numset(str,value - str_gnum(s2));
+ break;
+ case O_LEFT_SHIFT:
+ CHECK12;
+ value = str_gnum(s1);
+ i = (int)str_gnum(s2);
+#ifndef lint
+ str_numset(str,(double)(((long)value) << i));
+#endif
+ break;
+ case O_RIGHT_SHIFT:
+ CHECK12;
+ value = str_gnum(s1);
+ i = (int)str_gnum(s2);
+#ifndef lint
+ str_numset(str,(double)(((long)value) >> i));
+#endif
+ break;
+ case O_LT:
+ CHECK12;
+ value = str_gnum(s1);
+ str_numset(str,(value < str_gnum(s2)) ? 1.0 : 0.0);
+ break;
+ case O_GT:
+ CHECK12;
+ value = str_gnum(s1);
+ str_numset(str,(value > str_gnum(s2)) ? 1.0 : 0.0);
+ break;
+ case O_LE:
+ CHECK12;
+ value = str_gnum(s1);
+ str_numset(str,(value <= str_gnum(s2)) ? 1.0 : 0.0);
+ break;
+ case O_GE:
+ CHECK12;
+ value = str_gnum(s1);
+ str_numset(str,(value >= str_gnum(s2)) ? 1.0 : 0.0);
+ break;
+ case O_EQ:
+ CHECK12;
+ if (dowarn) {
+ if ((!s1->str_nok && !looks_like_number(s1)) ||
+ (!s2->str_nok && !looks_like_number(s2)) )
+ warn("Possible use of == on string value");
+ }
+ value = str_gnum(s1);
+ str_numset(str,(value == str_gnum(s2)) ? 1.0 : 0.0);
+ break;
+ case O_NE:
+ CHECK12;
+ value = str_gnum(s1);
+ str_numset(str,(value != str_gnum(s2)) ? 1.0 : 0.0);
+ break;
+ case O_NCMP:
+ CHECK12;
+ value = str_gnum(s1);
+ value -= str_gnum(s2);
+ if (value > 0.0)
+ value = 1.0;
+ else if (value < 0.0)
+ value = -1.0;
+ str_numset(str,value);
+ break;
+ case O_BIT_AND:
+ CHECK12;
+ value = str_gnum(s1);
+#ifndef lint
+ str_numset(str,(double)(U_L(value) & U_L(str_gnum(s2))));
+#endif
+ break;
+ case O_XOR:
+ CHECK12;
+ value = str_gnum(s1);
+#ifndef lint
+ str_numset(str,(double)(U_L(value) ^ U_L(str_gnum(s2))));
+#endif
+ break;
+ case O_BIT_OR:
+ CHECK12;
+ value = str_gnum(s1);
+#ifndef lint
+ str_numset(str,(double)(U_L(value) | U_L(str_gnum(s2))));
+#endif
+ break;
+ case O_AND:
+ CHECK12;
+ if (str_true(s1))
+ str_sset(str,s2);
+ else
+ str_sset(str,s1);
+ break;
+ case O_OR:
+ CHECK12;
+ if (str_true(s1))
+ str_sset(str,s1);
+ else
+ str_sset(str,s2);
+ break;
+ case O_COND_EXPR:
+ CHECK12;
+ if ((arg[3].arg_type & A_MASK) != A_SINGLE)
+ return arg;
+ if (str_true(s1))
+ str_sset(str,s2);
+ else
+ str_sset(str,arg[3].arg_ptr.arg_str);
+ str_free(arg[3].arg_ptr.arg_str);
+ Renew(arg, 3, ARG);
+ break;
+ case O_NEGATE:
+ CHECK1;
+ str_numset(str,(double)(-str_gnum(s1)));
+ break;
+ case O_NOT:
+ CHECK1;
+#ifdef NOTNOT
+ { char xxx = str_true(s1); str_numset(str,(double)!xxx); }
+#else
+ str_numset(str,(double)(!str_true(s1)));
+#endif
+ break;
+ case O_COMPLEMENT:
+ CHECK1;
+#ifndef lint
+ str_numset(str,(double)(~U_L(str_gnum(s1))));
+#endif
+ break;
+ case O_SIN:
+ CHECK1;
+ str_numset(str,sin(str_gnum(s1)));
+ break;
+ case O_COS:
+ CHECK1;
+ str_numset(str,cos(str_gnum(s1)));
+ break;
+ case O_ATAN2:
+ CHECK12;
+ value = str_gnum(s1);
+ str_numset(str,atan2(value, str_gnum(s2)));
+ break;
+ case O_POW:
+ CHECK12;
+ value = str_gnum(s1);
+ str_numset(str,pow(value, str_gnum(s2)));
+ break;
+ case O_LENGTH:
+ if (arg[1].arg_type == A_STAB) {
+ arg->arg_type = O_ITEM;
+ arg[1].arg_type = A_LENSTAB;
+ return arg;
+ }
+ CHECK1;
+ str_numset(str, (double)str_len(s1));
+ break;
+ case O_SLT:
+ CHECK12;
+ str_numset(str,(double)(str_cmp(s1,s2) < 0));
+ break;
+ case O_SGT:
+ CHECK12;
+ str_numset(str,(double)(str_cmp(s1,s2) > 0));
+ break;
+ case O_SLE:
+ CHECK12;
+ str_numset(str,(double)(str_cmp(s1,s2) <= 0));
+ break;
+ case O_SGE:
+ CHECK12;
+ str_numset(str,(double)(str_cmp(s1,s2) >= 0));
+ break;
+ case O_SEQ:
+ CHECK12;
+ str_numset(str,(double)(str_eq(s1,s2)));
+ break;
+ case O_SNE:
+ CHECK12;
+ str_numset(str,(double)(!str_eq(s1,s2)));
+ break;
+ case O_SCMP:
+ CHECK12;
+ str_numset(str,(double)(str_cmp(s1,s2)));
+ break;
+ case O_CRYPT:
+ CHECK12;
+#ifdef HAS_CRYPT
+ tmps = str_get(s1);
+ str_set(str,crypt(tmps,str_get(s2)));
+#else
+ yyerror(
+ "The crypt() function is unimplemented due to excessive paranoia.");
+#endif
+ break;
+ case O_EXP:
+ CHECK1;
+ str_numset(str,exp(str_gnum(s1)));
+ break;
+ case O_LOG:
+ CHECK1;
+ str_numset(str,log(str_gnum(s1)));
+ break;
+ case O_SQRT:
+ CHECK1;
+ str_numset(str,sqrt(str_gnum(s1)));
+ break;
+ case O_INT:
+ CHECK1;
+ value = str_gnum(s1);
+ if (value >= 0.0)
+ (void)modf(value,&value);
+ else {
+ (void)modf(-value,&value);
+ value = -value;
+ }
+ str_numset(str,value);
+ break;
+ case O_ORD:
+ CHECK1;
+#ifndef I286
+ str_numset(str,(double)(*str_get(s1)));
+#else
+ {
+ int zapc;
+ char *zaps;
+
+ zaps = str_get(s1);
+ zapc = (int) *zaps;
+ str_numset(str,(double)(zapc));
+ }
+#endif
+ break;
+ }
+ arg->arg_type = O_ITEM; /* note arg1 type is already SINGLE */
+ str_free(s1);
+ arg[1].arg_ptr.arg_str = str;
+ if (s2) {
+ str_free(s2);
+ arg[2].arg_ptr.arg_str = Nullstr;
+ arg[2].arg_type = A_NULL;
+ }
+ str = Nullstr;
+
+ return arg;
+}
+
+ARG *
+l(arg)
+register ARG *arg;
+{
+ register int i;
+ register ARG *arg1;
+ register ARG *arg2;
+ SPAT *spat;
+ int arghog = 0;
+
+ i = arg[1].arg_type & A_MASK;
+
+ arg->arg_flags |= AF_COMMON; /* assume something in common */
+ /* which forces us to copy things */
+
+ if (i == A_ARYLEN) {
+ arg[1].arg_type = A_LARYLEN;
+ return arg;
+ }
+ if (i == A_ARYSTAB) {
+ arg[1].arg_type = A_LARYSTAB;
+ return arg;
+ }
+
+ /* see if it's an array reference */
+
+ if (i == A_EXPR || i == A_LEXPR) {
+ arg1 = arg[1].arg_ptr.arg_arg;
+
+ if (arg1->arg_type == O_LIST || arg1->arg_type == O_ITEM) {
+ /* assign to list */
+ if (arg->arg_len > 1) {
+ dehoist(arg,2);
+ arg2 = arg[2].arg_ptr.arg_arg;
+ if (nothing_in_common(arg1,arg2))
+ arg->arg_flags &= ~AF_COMMON;
+ if (arg->arg_type == O_ASSIGN) {
+ if (arg1->arg_flags & AF_LOCAL_XX)
+ arg->arg_flags |= AF_LOCAL_XX;
+ arg[1].arg_flags |= AF_ARYOK;
+ arg[2].arg_flags |= AF_ARYOK;
+ }
+ }
+ else if (arg->arg_type != O_CHOP)
+ arg->arg_type = O_ASSIGN; /* possible local(); */
+ for (i = arg1->arg_len; i >= 1; i--) {
+ switch (arg1[i].arg_type) {
+ case A_STAR: case A_LSTAR:
+ arg1[i].arg_type = A_LSTAR;
+ break;
+ case A_STAB: case A_LVAL:
+ arg1[i].arg_type = A_LVAL;
+ break;
+ case A_ARYLEN: case A_LARYLEN:
+ arg1[i].arg_type = A_LARYLEN;
+ break;
+ case A_ARYSTAB: case A_LARYSTAB:
+ arg1[i].arg_type = A_LARYSTAB;
+ break;
+ case A_EXPR: case A_LEXPR:
+ arg1[i].arg_type = A_LEXPR;
+ switch(arg1[i].arg_ptr.arg_arg->arg_type) {
+ case O_ARRAY: case O_LARRAY:
+ arg1[i].arg_ptr.arg_arg->arg_type = O_LARRAY;
+ arghog = 1;
+ break;
+ case O_AELEM: case O_LAELEM:
+ arg1[i].arg_ptr.arg_arg->arg_type = O_LAELEM;
+ break;
+ case O_HASH: case O_LHASH:
+ arg1[i].arg_ptr.arg_arg->arg_type = O_LHASH;
+ arghog = 1;
+ break;
+ case O_HELEM: case O_LHELEM:
+ arg1[i].arg_ptr.arg_arg->arg_type = O_LHELEM;
+ break;
+ case O_ASLICE: case O_LASLICE:
+ arg1[i].arg_ptr.arg_arg->arg_type = O_LASLICE;
+ break;
+ case O_HSLICE: case O_LHSLICE:
+ arg1[i].arg_ptr.arg_arg->arg_type = O_LHSLICE;
+ break;
+ case O_SUBSTR: case O_VEC:
+ (void)l(arg1[i].arg_ptr.arg_arg);
+ Renewc(arg1[i].arg_ptr.arg_arg->arg_ptr.arg_str, 1,
+ struct lstring, STR);
+ /* grow string struct to hold an lstring struct */
+ break;
+ default:
+ goto ill_item;
+ }
+ break;
+ default:
+ ill_item:
+ (void)sprintf(tokenbuf, "Illegal item (%s) as lvalue",
+ argname[arg1[i].arg_type&A_MASK]);
+ yyerror(tokenbuf);
+ }
+ }
+ if (arg->arg_len > 1) {
+ if (arg2->arg_type == O_SPLIT && !arg2[3].arg_type && !arghog) {
+ arg2[3].arg_type = A_SINGLE;
+ arg2[3].arg_ptr.arg_str =
+ str_nmake((double)arg1->arg_len + 1); /* limit split len*/
+ }
+ }
+ }
+ else if (arg1->arg_type == O_AELEM || arg1->arg_type == O_LAELEM)
+ if (arg->arg_type == O_DEFINED)
+ arg1->arg_type = O_AELEM;
+ else
+ arg1->arg_type = O_LAELEM;
+ else if (arg1->arg_type == O_ARRAY || arg1->arg_type == O_LARRAY) {
+ arg1->arg_type = O_LARRAY;
+ if (arg->arg_len > 1) {
+ dehoist(arg,2);
+ arg2 = arg[2].arg_ptr.arg_arg;
+ if (arg2->arg_type == O_SPLIT) { /* use split's builtin =?*/
+ spat = arg2[2].arg_ptr.arg_spat;
+ if (!(spat->spat_flags & SPAT_ONCE) &&
+ nothing_in_common(arg1,spat->spat_repl)) {
+ spat->spat_repl[1].arg_ptr.arg_stab =
+ arg1[1].arg_ptr.arg_stab;
+ arg1[1].arg_ptr.arg_stab = Nullstab;
+ spat->spat_flags |= SPAT_ONCE;
+ arg_free(arg1); /* recursive */
+ arg[1].arg_ptr.arg_arg = Nullarg;
+ free_arg(arg); /* non-recursive */
+ return arg2; /* split has builtin assign */
+ }
+ }
+ else if (nothing_in_common(arg1,arg2))
+ arg->arg_flags &= ~AF_COMMON;
+ if (arg->arg_type == O_ASSIGN) {
+ arg[1].arg_flags |= AF_ARYOK;
+ arg[2].arg_flags |= AF_ARYOK;
+ }
+ }
+ else if (arg->arg_type == O_ASSIGN)
+ arg[1].arg_flags |= AF_ARYOK;
+ }
+ else if (arg1->arg_type == O_HELEM || arg1->arg_type == O_LHELEM)
+ if (arg->arg_type == O_DEFINED)
+ arg1->arg_type = O_HELEM; /* avoid creating one */
+ else
+ arg1->arg_type = O_LHELEM;
+ else if (arg1->arg_type == O_HASH || arg1->arg_type == O_LHASH) {
+ arg1->arg_type = O_LHASH;
+ if (arg->arg_len > 1) {
+ dehoist(arg,2);
+ arg2 = arg[2].arg_ptr.arg_arg;
+ if (nothing_in_common(arg1,arg2))
+ arg->arg_flags &= ~AF_COMMON;
+ if (arg->arg_type == O_ASSIGN) {
+ arg[1].arg_flags |= AF_ARYOK;
+ arg[2].arg_flags |= AF_ARYOK;
+ }
+ }
+ else if (arg->arg_type == O_ASSIGN)
+ arg[1].arg_flags |= AF_ARYOK;
+ }
+ else if (arg1->arg_type == O_ASLICE) {
+ arg1->arg_type = O_LASLICE;
+ if (arg->arg_type == O_ASSIGN) {
+ dehoist(arg,2);
+ arg[1].arg_flags |= AF_ARYOK;
+ arg[2].arg_flags |= AF_ARYOK;
+ }
+ }
+ else if (arg1->arg_type == O_HSLICE) {
+ arg1->arg_type = O_LHSLICE;
+ if (arg->arg_type == O_ASSIGN) {
+ dehoist(arg,2);
+ arg[1].arg_flags |= AF_ARYOK;
+ arg[2].arg_flags |= AF_ARYOK;
+ }
+ }
+ else if ((arg->arg_type == O_DEFINED || arg->arg_type == O_UNDEF) &&
+ (arg1->arg_type == (perldb ? O_DBSUBR : O_SUBR)) ) {
+ arg[1].arg_type |= A_DONT;
+ }
+ else if (arg1->arg_type == O_SUBSTR || arg1->arg_type == O_VEC) {
+ (void)l(arg1);
+ Renewc(arg1->arg_ptr.arg_str, 1, struct lstring, STR);
+ /* grow string struct to hold an lstring struct */
+ }
+ else if (arg1->arg_type == O_ASSIGN)
+ /*SUPPRESS 530*/
+ ;
+ else {
+ (void)sprintf(tokenbuf,
+ "Illegal expression (%s) as lvalue",opname[arg1->arg_type]);
+ yyerror(tokenbuf);
+ return arg;
+ }
+ arg[1].arg_type = A_LEXPR | (arg[1].arg_type & A_DONT);
+ if (arg->arg_type == O_ASSIGN && (arg1[1].arg_flags & AF_ARYOK)) {
+ arg[1].arg_flags |= AF_ARYOK;
+ if (arg->arg_len > 1)
+ arg[2].arg_flags |= AF_ARYOK;
+ }
+#ifdef DEBUGGING
+ if (debug & 16)
+ fprintf(stderr,"lval LEXPR\n");
+#endif
+ return arg;
+ }
+ if (i == A_STAR || i == A_LSTAR) {
+ arg[1].arg_type = A_LSTAR | (arg[1].arg_type & A_DONT);
+ return arg;
+ }
+
+ /* not an array reference, should be a register name */
+
+ if (i != A_STAB && i != A_LVAL) {
+ (void)sprintf(tokenbuf,
+ "Illegal item (%s) as lvalue",argname[arg[1].arg_type&A_MASK]);
+ yyerror(tokenbuf);
+ return arg;
+ }
+ arg[1].arg_type = A_LVAL | (arg[1].arg_type & A_DONT);
+#ifdef DEBUGGING
+ if (debug & 16)
+ fprintf(stderr,"lval LVAL\n");
+#endif
+ return arg;
+}
+
+ARG *
+fixl(type,arg)
+int type;
+ARG *arg;
+{
+ if (type == O_DEFINED || type == O_UNDEF) {
+ if (arg->arg_type != O_ITEM)
+ arg = hide_ary(arg);
+ if (arg->arg_type == O_ITEM) {
+ type = arg[1].arg_type & A_MASK;
+ if (type == A_EXPR || type == A_LEXPR)
+ arg[1].arg_type = A_LEXPR|A_DONT;
+ }
+ }
+ return arg;
+}
+
+void
+dehoist(arg,i)
+ARG *arg;
+{
+ ARG *tmparg;
+
+ if (arg[i].arg_type != A_EXPR) { /* dehoist */
+ tmparg = make_op(O_ITEM,1,Nullarg,Nullarg,Nullarg);
+ tmparg[1] = arg[i];
+ arg[i].arg_ptr.arg_arg = tmparg;
+ arg[i].arg_type = A_EXPR;
+ }
+}
+
+ARG *
+addflags(i,flags,arg)
+register ARG *arg;
+{
+ arg[i].arg_flags |= flags;
+ return arg;
+}
+
+ARG *
+hide_ary(arg)
+ARG *arg;
+{
+ if (arg->arg_type == O_ARRAY || arg->arg_type == O_HASH)
+ return make_op(O_ITEM,1,arg,Nullarg,Nullarg);
+ return arg;
+}
+
+/* maybe do a join on multiple array dimensions */
+
+ARG *
+jmaybe(arg)
+register ARG *arg;
+{
+ if (arg && arg->arg_type == O_COMMA) {
+ arg = listish(arg);
+ arg = make_op(O_JOIN, 2,
+ stab2arg(A_STAB,stabent(";",TRUE)),
+ make_list(arg),
+ Nullarg);
+ }
+ return arg;
+}
+
+ARG *
+make_list(arg)
+register ARG *arg;
+{
+ register int i;
+ register ARG *node;
+ register ARG *nxtnode;
+ register int j;
+ STR *tmpstr;
+
+ if (!arg) {
+ arg = op_new(0);
+ arg->arg_type = O_LIST;
+ }
+ if (arg->arg_type != O_COMMA) {
+ if (arg->arg_type != O_ARRAY)
+ arg->arg_flags |= AF_LISTISH; /* see listish() below */
+ arg->arg_flags |= AF_LISTISH; /* see listish() below */
+ return arg;
+ }
+ for (i = 2, node = arg; ; i++) {
+ if (node->arg_len < 2)
+ break;
+ if (node[1].arg_type != A_EXPR)
+ break;
+ node = node[1].arg_ptr.arg_arg;
+ if (node->arg_type != O_COMMA)
+ break;
+ }
+ if (i > 2) {
+ node = arg;
+ arg = op_new(i);
+ tmpstr = arg->arg_ptr.arg_str;
+ StructCopy(node, arg, ARG); /* copy everything except the STR */
+ arg->arg_ptr.arg_str = tmpstr;
+ for (j = i; ; ) {
+ StructCopy(node+2, arg+j, ARG);
+ arg[j].arg_flags |= AF_ARYOK;
+ --j; /* Bug in Xenix compiler */
+ if (j < 2) {
+ StructCopy(node+1, arg+1, ARG);
+ free_arg(node);
+ break;
+ }
+ nxtnode = node[1].arg_ptr.arg_arg;
+ free_arg(node);
+ node = nxtnode;
+ }
+ }
+ arg[1].arg_flags |= AF_ARYOK;
+ arg[2].arg_flags |= AF_ARYOK;
+ arg->arg_type = O_LIST;
+ arg->arg_len = i;
+ str_free(arg->arg_ptr.arg_str);
+ arg->arg_ptr.arg_str = Nullstr;
+ return arg;
+}
+
+/* turn a single item into a list */
+
+ARG *
+listish(arg)
+ARG *arg;
+{
+ if (arg && arg->arg_flags & AF_LISTISH)
+ arg = make_op(O_LIST,1,arg,Nullarg,Nullarg);
+ return arg;
+}
+
+ARG *
+maybelistish(optype, arg)
+int optype;
+ARG *arg;
+{
+ ARG *tmparg = arg;
+
+ if (optype == O_RETURN && arg->arg_type == O_ITEM &&
+ arg[1].arg_type == A_EXPR && (tmparg = arg[1].arg_ptr.arg_arg) &&
+ ((tmparg->arg_flags & AF_LISTISH) || (tmparg->arg_type == O_ARRAY) )) {
+ tmparg = listish(tmparg);
+ free_arg(arg);
+ arg = tmparg;
+ }
+ else if (optype == O_PRTF ||
+ (arg->arg_type == O_ASLICE || arg->arg_type == O_HSLICE ||
+ arg->arg_type == O_F_OR_R) )
+ arg = listish(arg);
+ return arg;
+}
+
+/* mark list of local variables */
+
+ARG *
+localize(arg)
+ARG *arg;
+{
+ arg->arg_flags |= AF_LOCAL_XX;
+ return arg;
+}
+
+ARG *
+rcatmaybe(arg)
+ARG *arg;
+{
+ ARG *arg2;
+
+ if (arg->arg_type == O_CONCAT && arg[2].arg_type == A_EXPR) {
+ arg2 = arg[2].arg_ptr.arg_arg;
+ if (arg2->arg_type == O_ITEM && arg2[1].arg_type == A_READ) {
+ arg->arg_type = O_RCAT;
+ arg[2].arg_type = arg2[1].arg_type;
+ arg[2].arg_ptr = arg2[1].arg_ptr;
+ free_arg(arg2);
+ }
+ }
+ return arg;
+}
+
+ARG *
+stab2arg(atype,stab)
+int atype;
+register STAB *stab;
+{
+ register ARG *arg;
+
+ arg = op_new(1);
+ arg->arg_type = O_ITEM;
+ arg[1].arg_type = atype;
+ arg[1].arg_ptr.arg_stab = stab;
+ return arg;
+}
+
+ARG *
+cval_to_arg(cval)
+register char *cval;
+{
+ register ARG *arg;
+
+ arg = op_new(1);
+ arg->arg_type = O_ITEM;
+ arg[1].arg_type = A_SINGLE;
+ arg[1].arg_ptr.arg_str = str_make(cval,0);
+ Safefree(cval);
+ return arg;
+}
+
+ARG *
+op_new(numargs)
+int numargs;
+{
+ register ARG *arg;
+
+ Newz(203,arg, numargs + 1, ARG);
+ arg->arg_ptr.arg_str = Str_new(21,0);
+ arg->arg_len = numargs;
+ return arg;
+}
+
+void
+free_arg(arg)
+ARG *arg;
+{
+ str_free(arg->arg_ptr.arg_str);
+ Safefree(arg);
+}
+
+ARG *
+make_match(type,expr,spat)
+int type;
+ARG *expr;
+SPAT *spat;
+{
+ register ARG *arg;
+
+ arg = make_op(type,2,expr,Nullarg,Nullarg);
+
+ arg[2].arg_type = A_SPAT|A_DONT;
+ arg[2].arg_ptr.arg_spat = spat;
+#ifdef DEBUGGING
+ if (debug & 16)
+ fprintf(stderr,"make_match SPAT=%lx\n",(long)spat);
+#endif
+
+ if (type == O_SUBST || type == O_NSUBST) {
+ if (arg[1].arg_type != A_STAB) {
+ yyerror("Illegal lvalue");
+ }
+ arg[1].arg_type = A_LVAL;
+ }
+ return arg;
+}
+
+ARG *
+cmd_to_arg(cmd)
+CMD *cmd;
+{
+ register ARG *arg;
+
+ arg = op_new(1);
+ arg->arg_type = O_ITEM;
+ arg[1].arg_type = A_CMD;
+ arg[1].arg_ptr.arg_cmd = cmd;
+ return arg;
+}
+
+/* Check two expressions to see if there is any identifier in common */
+
+static int
+nothing_in_common(arg1,arg2)
+ARG *arg1;
+ARG *arg2;
+{
+ static int thisexpr = 0; /* I don't care if this wraps */
+
+ thisexpr++;
+ if (arg_common(arg1,thisexpr,1))
+ return 0; /* hit eval or do {} */
+ stab_lastexpr(defstab) = thisexpr; /* pretend to hit @_ */
+ if (arg_common(arg2,thisexpr,0))
+ return 0; /* hit identifier again */
+ return 1;
+}
+
+/* Recursively descend an expression and mark any identifier or check
+ * it to see if it was marked already.
+ */
+
+static int
+arg_common(arg,exprnum,marking)
+register ARG *arg;
+int exprnum;
+int marking;
+{
+ register int i;
+
+ if (!arg)
+ return 0;
+ for (i = arg->arg_len; i >= 1; i--) {
+ switch (arg[i].arg_type & A_MASK) {
+ case A_NULL:
+ break;
+ case A_LEXPR:
+ case A_EXPR:
+ if (arg_common(arg[i].arg_ptr.arg_arg,exprnum,marking))
+ return 1;
+ break;
+ case A_CMD:
+ return 1; /* assume hanky panky */
+ case A_STAR:
+ case A_LSTAR:
+ case A_STAB:
+ case A_LVAL:
+ case A_ARYLEN:
+ case A_LARYLEN:
+ if (marking)
+ stab_lastexpr(arg[i].arg_ptr.arg_stab) = exprnum;
+ else if (stab_lastexpr(arg[i].arg_ptr.arg_stab) == exprnum)
+ return 1;
+ break;
+ case A_DOUBLE:
+ case A_BACKTICK:
+ {
+ register char *s = arg[i].arg_ptr.arg_str->str_ptr;
+ register char *send = s + arg[i].arg_ptr.arg_str->str_cur;
+ register STAB *stab;
+
+ while (*s) {
+ if (*s == '$' && s[1]) {
+ s = scanident(s,send,tokenbuf);
+ stab = stabent(tokenbuf,TRUE);
+ if (marking)
+ stab_lastexpr(stab) = exprnum;
+ else if (stab_lastexpr(stab) == exprnum)
+ return 1;
+ continue;
+ }
+ else if (*s == '\\' && s[1])
+ s++;
+ s++;
+ }
+ }
+ break;
+ case A_SPAT:
+ if (spat_common(arg[i].arg_ptr.arg_spat,exprnum,marking))
+ return 1;
+ break;
+ case A_READ:
+ case A_INDREAD:
+ case A_GLOB:
+ case A_WORD:
+ case A_SINGLE:
+ break;
+ }
+ }
+ switch (arg->arg_type) {
+ case O_ARRAY:
+ case O_LARRAY:
+ if ((arg[1].arg_type & A_MASK) == A_STAB)
+ (void)aadd(arg[1].arg_ptr.arg_stab);
+ break;
+ case O_HASH:
+ case O_LHASH:
+ if ((arg[1].arg_type & A_MASK) == A_STAB)
+ (void)hadd(arg[1].arg_ptr.arg_stab);
+ break;
+ case O_EVAL:
+ case O_SUBR:
+ case O_DBSUBR:
+ return 1;
+ }
+ return 0;
+}
+
+static int
+spat_common(spat,exprnum,marking)
+register SPAT *spat;
+int exprnum;
+int marking;
+{
+ if (spat->spat_runtime)
+ if (arg_common(spat->spat_runtime,exprnum,marking))
+ return 1;
+ if (spat->spat_repl) {
+ if (arg_common(spat->spat_repl,exprnum,marking))
+ return 1;
+ }
+ return 0;
+}
diff --git a/gnu/usr.bin/perl/perl/crypt.c b/gnu/usr.bin/perl/perl/crypt.c
new file mode 100644
index 0000000..3e95f45
--- /dev/null
+++ b/gnu/usr.bin/perl/perl/crypt.c
@@ -0,0 +1,200 @@
+/*
+ * Copyright (c) 1989 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Tom Truscott.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+/* from static char sccsid[] = "@(#)crypt.c 5.11 (Berkeley) 6/25/91"; */
+static char rcsid[] = "$Header: /home/ncvs/src/gnu/usr.bin/perl/perl/crypt.c,v 1.1.1.1 1994/09/10 06:27:37 gclarkii Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+#include <unistd.h>
+#include <stdio.h>
+
+/*
+ * UNIX password, and DES, encryption.
+ *
+ * since this is non-exportable, this is just a dummy. if you want real
+ * encryption, make sure you've got libcrypt.a around.
+ */
+
+#define SCRAMBLE /* Don't leave them in plaintext */
+
+#ifndef SCRAMBLE
+static char cryptresult[1+4+4+11+1]; /* "encrypted" result */
+
+char *
+crypt(key, setting)
+ register const char *key;
+ register const char *setting;
+{
+ fprintf(stderr, "WARNING! crypt(3) not present in the system!\n");
+ strncpy(cryptresult, key, sizeof cryptresult);
+ cryptresult[sizeof cryptresult - 1] = '\0';
+ return (cryptresult);
+}
+
+#else
+
+char *
+crypt(pw, salt)
+ register const char *pw;
+ register const char *salt;
+{
+ static char password[14];
+ long matrix[128], *m, vector[2];
+ char a, b, *p;
+ int i, value;
+ unsigned short crc;
+ unsigned long t;
+
+ /* Ugly hack, but I'm too lazy to find the real problem - NW */
+ bzero(matrix, 128 * sizeof(long));
+
+ if (salt[0]) {
+ a = salt[0];
+ if (salt[1])
+ b = salt[1];
+ else
+ b = a;
+ } else
+ a = b = '0';
+ password[0] = a;
+ password[1] = b;
+ if (a > 'Z')
+ a -= 6;
+ if (a > '9')
+ a -= 7;
+ if (b > 'Z')
+ b -= 6;
+ if (b > '9')
+ b -= 7;
+ a -= '.';
+ b -= '.';
+ value = (a | (b << 6)) & 07777;
+
+ crc = value;
+ value += 1000;
+ b = 0;
+ p = (char *)pw;
+ while (value--) {
+ if (crc & 0x8000)
+ crc = (crc << 1) ^ 0x1021;
+ else
+ crc <<= 1;
+ if (!b) {
+ b = 8;
+ if (!(i = *p++)) {
+ p = (char *)pw;
+ i = *p++;
+ }
+ }
+ if (i & 0x80)
+ crc ^= 1;
+ i <<= 1;
+ b--;
+ }
+
+ m = matrix;
+ matrix[0] = 0;
+ a = 32;
+ for (value = 07777; value >= 0; value--) {
+ *m <<= 1;
+ if (crc & 0x8000) {
+ *m |= 1;
+ crc = (crc << 1) ^ 0x1021;
+ } else
+ crc <<= 1;
+ if (!b) {
+ b = 8;
+ if (!(i = *p++)) {
+ p = (char *)pw;
+ i = *p++;
+ }
+ }
+ if (i & 0x80)
+ crc ^= 1;
+ i <<= 1;
+ b--;
+ if (!(a--)) {
+ a = 32;
+ *++m = 0;
+ }
+ }
+
+ vector[0] = 0;
+ vector[1] = 0;
+ p = (char *) vector;
+ for (i = 0; i < 7; i++)
+ if (pw[i])
+ *p++ = pw[i];
+ else
+ break;
+
+ p = password + 2;
+ a = 6;
+ m = matrix;
+ *p = 0;
+ for (i = 077; i >= 0; i--) {
+ t = *m++;
+ t = t ^ *m++;
+ t = t ^ vector[0];
+ t = t ^ vector[1];
+ b = 0;
+ while (t) {
+ if (t & 1)
+ b = 1 - b;
+ t >>= 1;
+ }
+ a--;
+ if (b)
+ *p |= 1 << a;
+ if (!a) {
+ a = 6;
+ *++p = 0;
+ }
+ }
+
+ for (i = 2; i < 13; i++) {
+ password[i] += '.';
+ if (password[i] > '9')
+ password[i] += 7;
+ if (password[i] > 'Z')
+ password[i] += 6;
+ }
+ password[13] = 0;
+
+ return password;
+}
+#endif
diff --git a/gnu/usr.bin/perl/perl/doarg.c b/gnu/usr.bin/perl/perl/doarg.c
new file mode 100644
index 0000000..2a64787
--- /dev/null
+++ b/gnu/usr.bin/perl/perl/doarg.c
@@ -0,0 +1,1856 @@
+/* $RCSfile: doarg.c,v $$Revision: 1.2 $$Date: 1994/09/11 03:17:30 $
+ *
+ * Copyright (c) 1991, Larry Wall
+ *
+ * You may distribute under the terms of either the GNU General Public
+ * License or the Artistic License, as specified in the README file.
+ *
+ * $Log: doarg.c,v $
+ * Revision 1.2 1994/09/11 03:17:30 gclarkii
+ * Changed AF_LOCAL to AF_LOCAL_XX so as not to conflict with 4.4 socket.h
+ * Added casts to shutup warnings in doio.c
+ *
+ * Revision 1.1.1.1 1994/09/10 06:27:32 gclarkii
+ * Initial import of Perl 4.046 bmaked
+ *
+ * Revision 1.1.1.1 1993/08/23 21:29:35 nate
+ * PERL!
+ *
+ * Revision 4.0.1.8 1993/02/05 19:32:27 lwall
+ * patch36: substitution didn't always invalidate numericity
+ *
+ * Revision 4.0.1.7 92/06/11 21:07:11 lwall
+ * patch34: join with null list attempted negative allocation
+ * patch34: sprintf("%6.4s", "abcdefg") didn't print "abcd "
+ *
+ * Revision 4.0.1.6 92/06/08 12:34:30 lwall
+ * patch20: removed implicit int declarations on funcions
+ * patch20: pattern modifiers i and o didn't interact right
+ * patch20: join() now pre-extends target string to avoid excessive copying
+ * patch20: fixed confusion between a *var's real name and its effective name
+ * patch20: subroutines didn't localize $`, $&, $', $1 et al correctly
+ * patch20: usersub routines didn't reclaim temp values soon enough
+ * patch20: ($<,$>) = ... didn't work on some architectures
+ * patch20: added Atari ST portability
+ *
+ * Revision 4.0.1.5 91/11/11 16:31:58 lwall
+ * patch19: added little-endian pack/unpack options
+ *
+ * Revision 4.0.1.4 91/11/05 16:35:06 lwall
+ * patch11: /$foo/o optimizer could access deallocated data
+ * patch11: minimum match length calculation in regexp is now cumulative
+ * patch11: added some support for 64-bit integers
+ * patch11: prepared for ctype implementations that don't define isascii()
+ * patch11: sprintf() now supports any length of s field
+ * patch11: indirect subroutine calls through magic vars (e.g. &$1) didn't work
+ * patch11: defined(&$foo) and undef(&$foo) didn't work
+ *
+ * Revision 4.0.1.3 91/06/10 01:18:41 lwall
+ * patch10: pack(hh,1) dumped core
+ *
+ * Revision 4.0.1.2 91/06/07 10:42:17 lwall
+ * patch4: new copyright notice
+ * patch4: // wouldn't use previous pattern if it started with a null character
+ * patch4: //o and s///o now optimize themselves fully at runtime
+ * patch4: added global modifier for pattern matches
+ * patch4: undef @array disabled "@array" interpolation
+ * patch4: chop("") was returning "\0" rather than ""
+ * patch4: vector logical operations &, | and ^ sometimes returned null string
+ * patch4: syscall couldn't pass numbers with most significant bit set on sparcs
+ *
+ * Revision 4.0.1.1 91/04/11 17:40:14 lwall
+ * patch1: fixed undefined environ problem
+ * patch1: fixed debugger coredump on subroutines
+ *
+ * Revision 4.0 91/03/20 01:06:42 lwall
+ * 4.0 baseline.
+ *
+ */
+
+#include "EXTERN.h"
+#include "perl.h"
+
+#if !defined(NSIG) || defined(M_UNIX) || defined(M_XENIX)
+#include <signal.h>
+#endif
+
+extern unsigned char fold[];
+
+#ifdef BUGGY_MSC
+ #pragma function(memcmp)
+#endif /* BUGGY_MSC */
+
+static void doencodes();
+
+int
+do_subst(str,arg,sp)
+STR *str;
+ARG *arg;
+int sp;
+{
+ register SPAT *spat;
+ SPAT *rspat;
+ register STR *dstr;
+ register char *s = str_get(str);
+ char *strend = s + str->str_cur;
+ register char *m;
+ char *c;
+ register char *d;
+ int clen;
+ int iters = 0;
+ int maxiters = (strend - s) + 10;
+ register int i;
+ bool once;
+ char *orig;
+ int safebase;
+
+ rspat = spat = arg[2].arg_ptr.arg_spat;
+ if (!spat || !s)
+ fatal("panic: do_subst");
+ else if (spat->spat_runtime) {
+ nointrp = "|)";
+ (void)eval(spat->spat_runtime,G_SCALAR,sp);
+ m = str_get(dstr = stack->ary_array[sp+1]);
+ nointrp = "";
+ if (spat->spat_regexp) {
+ regfree(spat->spat_regexp);
+ spat->spat_regexp = Null(REGEXP*); /* required if regcomp pukes */
+ }
+ spat->spat_regexp = regcomp(m,m+dstr->str_cur,
+ spat->spat_flags & SPAT_FOLD);
+ if (spat->spat_flags & SPAT_KEEP) {
+ if (!(spat->spat_flags & SPAT_FOLD))
+ scanconst(spat, m, dstr->str_cur);
+ arg_free(spat->spat_runtime); /* it won't change, so */
+ spat->spat_runtime = Nullarg; /* no point compiling again */
+ hoistmust(spat);
+ if (curcmd->c_expr && (curcmd->c_flags & CF_OPTIMIZE) == CFT_EVAL) {
+ curcmd->c_flags &= ~CF_OPTIMIZE;
+ opt_arg(curcmd, 1, curcmd->c_type == C_EXPR);
+ }
+ }
+ }
+#ifdef DEBUGGING
+ if (debug & 8) {
+ deb("2.SPAT /%s/\n",spat->spat_regexp->precomp);
+ }
+#endif
+ safebase = ((!spat->spat_regexp || !spat->spat_regexp->nparens) &&
+ !sawampersand);
+ if (!spat->spat_regexp->prelen && lastspat)
+ spat = lastspat;
+ orig = m = s;
+ if (hint) {
+ if (hint < s || hint > strend)
+ fatal("panic: hint in do_match");
+ s = hint;
+ hint = Nullch;
+ if (spat->spat_regexp->regback >= 0) {
+ s -= spat->spat_regexp->regback;
+ if (s < m)
+ s = m;
+ }
+ else
+ s = m;
+ }
+ else if (spat->spat_short) {
+ if (spat->spat_flags & SPAT_SCANFIRST) {
+ if (str->str_pok & SP_STUDIED) {
+ if (screamfirst[spat->spat_short->str_rare] < 0)
+ goto nope;
+ else if (!(s = screaminstr(str,spat->spat_short)))
+ goto nope;
+ }
+#ifndef lint
+ else if (!(s = fbminstr((unsigned char*)s, (unsigned char*)strend,
+ spat->spat_short)))
+ goto nope;
+#endif
+ if (s && spat->spat_regexp->regback >= 0) {
+ ++spat->spat_short->str_u.str_useful;
+ s -= spat->spat_regexp->regback;
+ if (s < m)
+ s = m;
+ }
+ else
+ s = m;
+ }
+ else if (!multiline && (*spat->spat_short->str_ptr != *s ||
+ bcmp(spat->spat_short->str_ptr, s, spat->spat_slen) ))
+ goto nope;
+ if (--spat->spat_short->str_u.str_useful < 0) {
+ str_free(spat->spat_short);
+ spat->spat_short = Nullstr; /* opt is being useless */
+ }
+ }
+ once = !(rspat->spat_flags & SPAT_GLOBAL);
+ if (rspat->spat_flags & SPAT_CONST) { /* known replacement string? */
+ if ((rspat->spat_repl[1].arg_type & A_MASK) == A_SINGLE)
+ dstr = rspat->spat_repl[1].arg_ptr.arg_str;
+ else { /* constant over loop, anyway */
+ (void)eval(rspat->spat_repl,G_SCALAR,sp);
+ dstr = stack->ary_array[sp+1];
+ }
+ c = str_get(dstr);
+ clen = dstr->str_cur;
+ if (clen <= spat->spat_regexp->minlen) {
+ /* can do inplace substitution */
+ if (regexec(spat->spat_regexp, s, strend, orig, 0,
+ str->str_pok & SP_STUDIED ? str : Nullstr, safebase)) {
+ if (spat->spat_regexp->subbase) /* oops, no we can't */
+ goto long_way;
+ d = s;
+ lastspat = spat;
+ str->str_pok = SP_VALID; /* disable possible screamer */
+ if (once) {
+ m = spat->spat_regexp->startp[0];
+ d = spat->spat_regexp->endp[0];
+ s = orig;
+ if (m - s > strend - d) { /* faster to shorten from end */
+ if (clen) {
+ Copy(c, m, clen, char);
+ m += clen;
+ }
+ i = strend - d;
+ if (i > 0) {
+ Move(d, m, i, char);
+ m += i;
+ }
+ *m = '\0';
+ str->str_cur = m - s;
+ STABSET(str);
+ str_numset(arg->arg_ptr.arg_str, 1.0);
+ stack->ary_array[++sp] = arg->arg_ptr.arg_str;
+ str->str_nok = 0;
+ return sp;
+ }
+ /*SUPPRESS 560*/
+ else if (i = m - s) { /* faster from front */
+ d -= clen;
+ m = d;
+ str_chop(str,d-i);
+ s += i;
+ while (i--)
+ *--d = *--s;
+ if (clen)
+ Copy(c, m, clen, char);
+ STABSET(str);
+ str_numset(arg->arg_ptr.arg_str, 1.0);
+ stack->ary_array[++sp] = arg->arg_ptr.arg_str;
+ str->str_nok = 0;
+ return sp;
+ }
+ else if (clen) {
+ d -= clen;
+ str_chop(str,d);
+ Copy(c,d,clen,char);
+ STABSET(str);
+ str_numset(arg->arg_ptr.arg_str, 1.0);
+ stack->ary_array[++sp] = arg->arg_ptr.arg_str;
+ str->str_nok = 0;
+ return sp;
+ }
+ else {
+ str_chop(str,d);
+ STABSET(str);
+ str_numset(arg->arg_ptr.arg_str, 1.0);
+ stack->ary_array[++sp] = arg->arg_ptr.arg_str;
+ str->str_nok = 0;
+ return sp;
+ }
+ /* NOTREACHED */
+ }
+ do {
+ if (iters++ > maxiters)
+ fatal("Substitution loop");
+ m = spat->spat_regexp->startp[0];
+ /*SUPPRESS 560*/
+ if (i = m - s) {
+ if (s != d)
+ Move(s,d,i,char);
+ d += i;
+ }
+ if (clen) {
+ Copy(c,d,clen,char);
+ d += clen;
+ }
+ s = spat->spat_regexp->endp[0];
+ } while (regexec(spat->spat_regexp, s, strend, orig, s == m,
+ Nullstr, TRUE)); /* (don't match same null twice) */
+ if (s != d) {
+ i = strend - s;
+ str->str_cur = d - str->str_ptr + i;
+ Move(s,d,i+1,char); /* include the Null */
+ }
+ STABSET(str);
+ str_numset(arg->arg_ptr.arg_str, (double)iters);
+ stack->ary_array[++sp] = arg->arg_ptr.arg_str;
+ str->str_nok = 0;
+ return sp;
+ }
+ str_numset(arg->arg_ptr.arg_str, 0.0);
+ stack->ary_array[++sp] = arg->arg_ptr.arg_str;
+ return sp;
+ }
+ }
+ else
+ c = Nullch;
+ if (regexec(spat->spat_regexp, s, strend, orig, 0,
+ str->str_pok & SP_STUDIED ? str : Nullstr, safebase)) {
+ long_way:
+ dstr = Str_new(25,str_len(str));
+ str_nset(dstr,m,s-m);
+ if (spat->spat_regexp->subbase)
+ curspat = spat;
+ lastspat = spat;
+ do {
+ if (iters++ > maxiters)
+ fatal("Substitution loop");
+ if (spat->spat_regexp->subbase
+ && spat->spat_regexp->subbase != orig) {
+ m = s;
+ s = orig;
+ orig = spat->spat_regexp->subbase;
+ s = orig + (m - s);
+ strend = s + (strend - m);
+ }
+ m = spat->spat_regexp->startp[0];
+ str_ncat(dstr,s,m-s);
+ s = spat->spat_regexp->endp[0];
+ if (c) {
+ if (clen)
+ str_ncat(dstr,c,clen);
+ }
+ else {
+ char *mysubbase = spat->spat_regexp->subbase;
+
+ spat->spat_regexp->subbase = Nullch; /* so recursion works */
+ (void)eval(rspat->spat_repl,G_SCALAR,sp);
+ str_scat(dstr,stack->ary_array[sp+1]);
+ if (spat->spat_regexp->subbase)
+ Safefree(spat->spat_regexp->subbase);
+ spat->spat_regexp->subbase = mysubbase;
+ }
+ if (once)
+ break;
+ } while (regexec(spat->spat_regexp, s, strend, orig, s == m, Nullstr,
+ safebase));
+ str_ncat(dstr,s,strend - s);
+ str_replace(str,dstr);
+ STABSET(str);
+ str_numset(arg->arg_ptr.arg_str, (double)iters);
+ stack->ary_array[++sp] = arg->arg_ptr.arg_str;
+ str->str_nok = 0;
+ return sp;
+ }
+ str_numset(arg->arg_ptr.arg_str, 0.0);
+ stack->ary_array[++sp] = arg->arg_ptr.arg_str;
+ return sp;
+
+nope:
+ ++spat->spat_short->str_u.str_useful;
+ str_numset(arg->arg_ptr.arg_str, 0.0);
+ stack->ary_array[++sp] = arg->arg_ptr.arg_str;
+ return sp;
+}
+#ifdef BUGGY_MSC
+ #pragma intrinsic(memcmp)
+#endif /* BUGGY_MSC */
+
+int
+do_trans(str,arg)
+STR *str;
+ARG *arg;
+{
+ register short *tbl;
+ register char *s;
+ register int matches = 0;
+ register int ch;
+ register char *send;
+ register char *d;
+ register int squash = arg[2].arg_len & 1;
+
+ tbl = (short*) arg[2].arg_ptr.arg_cval;
+ s = str_get(str);
+ send = s + str->str_cur;
+ if (!tbl || !s)
+ fatal("panic: do_trans");
+#ifdef DEBUGGING
+ if (debug & 8) {
+ deb("2.TBL\n");
+ }
+#endif
+ if (!arg[2].arg_len) {
+ while (s < send) {
+ if ((ch = tbl[*s & 0377]) >= 0) {
+ matches++;
+ *s = ch;
+ }
+ s++;
+ }
+ }
+ else {
+ d = s;
+ while (s < send) {
+ if ((ch = tbl[*s & 0377]) >= 0) {
+ *d = ch;
+ if (matches++ && squash) {
+ if (d[-1] == *d)
+ matches--;
+ else
+ d++;
+ }
+ else
+ d++;
+ }
+ else if (ch == -1) /* -1 is unmapped character */
+ *d++ = *s; /* -2 is delete character */
+ s++;
+ }
+ matches += send - d; /* account for disappeared chars */
+ *d = '\0';
+ str->str_cur = d - str->str_ptr;
+ }
+ STABSET(str);
+ return matches;
+}
+
+void
+do_join(str,arglast)
+register STR *str;
+int *arglast;
+{
+ register STR **st = stack->ary_array;
+ int sp = arglast[1];
+ register int items = arglast[2] - sp;
+ register char *delim = str_get(st[sp]);
+ register STRLEN len;
+ int delimlen = st[sp]->str_cur;
+
+ st += sp + 1;
+
+ len = (items > 0 ? (delimlen * (items - 1) ) : 0);
+ if (str->str_len < len + items) { /* current length is way too short */
+ while (items-- > 0) {
+ if (*st)
+ len += (*st)->str_cur;
+ st++;
+ }
+ STR_GROW(str, len + 1); /* so try to pre-extend */
+
+ items = arglast[2] - sp;
+ st -= items;
+ }
+
+ if (items-- > 0)
+ str_sset(str, *st++);
+ else
+ str_set(str,"");
+ len = delimlen;
+ if (len) {
+ for (; items > 0; items--,st++) {
+ str_ncat(str,delim,len);
+ str_scat(str,*st);
+ }
+ }
+ else {
+ for (; items > 0; items--,st++)
+ str_scat(str,*st);
+ }
+ STABSET(str);
+}
+
+void
+do_pack(str,arglast)
+register STR *str;
+int *arglast;
+{
+ register STR **st = stack->ary_array;
+ register int sp = arglast[1];
+ register int items;
+ register char *pat = str_get(st[sp]);
+ register char *patend = pat + st[sp]->str_cur;
+ register int len;
+ int datumtype;
+ STR *fromstr;
+ /*SUPPRESS 442*/
+ static char *null10 = "\0\0\0\0\0\0\0\0\0\0";
+ static char *space10 = " ";
+
+ /* These must not be in registers: */
+ char achar;
+ short ashort;
+ int aint;
+ unsigned int auint;
+ long along;
+ unsigned long aulong;
+#ifdef QUAD
+ quad aquad;
+ unsigned quad auquad;
+#endif
+ char *aptr;
+ float afloat;
+ double adouble;
+
+ items = arglast[2] - sp;
+ st += ++sp;
+ str_nset(str,"",0);
+ while (pat < patend) {
+#define NEXTFROM (items-- > 0 ? *st++ : &str_no)
+ datumtype = *pat++;
+ if (*pat == '*') {
+ len = index("@Xxu",datumtype) ? 0 : items;
+ pat++;
+ }
+ else if (isDIGIT(*pat)) {
+ len = *pat++ - '0';
+ while (isDIGIT(*pat))
+ len = (len * 10) + (*pat++ - '0');
+ }
+ else
+ len = 1;
+ switch(datumtype) {
+ default:
+ break;
+ case '%':
+ fatal("% may only be used in unpack");
+ case '@':
+ len -= str->str_cur;
+ if (len > 0)
+ goto grow;
+ len = -len;
+ if (len > 0)
+ goto shrink;
+ break;
+ case 'X':
+ shrink:
+ if (str->str_cur < len)
+ fatal("X outside of string");
+ str->str_cur -= len;
+ str->str_ptr[str->str_cur] = '\0';
+ break;
+ case 'x':
+ grow:
+ while (len >= 10) {
+ str_ncat(str,null10,10);
+ len -= 10;
+ }
+ str_ncat(str,null10,len);
+ break;
+ case 'A':
+ case 'a':
+ fromstr = NEXTFROM;
+ aptr = str_get(fromstr);
+ if (pat[-1] == '*')
+ len = fromstr->str_cur;
+ if (fromstr->str_cur > len)
+ str_ncat(str,aptr,len);
+ else {
+ str_ncat(str,aptr,fromstr->str_cur);
+ len -= fromstr->str_cur;
+ if (datumtype == 'A') {
+ while (len >= 10) {
+ str_ncat(str,space10,10);
+ len -= 10;
+ }
+ str_ncat(str,space10,len);
+ }
+ else {
+ while (len >= 10) {
+ str_ncat(str,null10,10);
+ len -= 10;
+ }
+ str_ncat(str,null10,len);
+ }
+ }
+ break;
+ case 'B':
+ case 'b':
+ {
+ char *savepat = pat;
+ int saveitems;
+
+ fromstr = NEXTFROM;
+ saveitems = items;
+ aptr = str_get(fromstr);
+ if (pat[-1] == '*')
+ len = fromstr->str_cur;
+ pat = aptr;
+ aint = str->str_cur;
+ str->str_cur += (len+7)/8;
+ STR_GROW(str, str->str_cur + 1);
+ aptr = str->str_ptr + aint;
+ if (len > fromstr->str_cur)
+ len = fromstr->str_cur;
+ aint = len;
+ items = 0;
+ if (datumtype == 'B') {
+ for (len = 0; len++ < aint;) {
+ items |= *pat++ & 1;
+ if (len & 7)
+ items <<= 1;
+ else {
+ *aptr++ = items & 0xff;
+ items = 0;
+ }
+ }
+ }
+ else {
+ for (len = 0; len++ < aint;) {
+ if (*pat++ & 1)
+ items |= 128;
+ if (len & 7)
+ items >>= 1;
+ else {
+ *aptr++ = items & 0xff;
+ items = 0;
+ }
+ }
+ }
+ if (aint & 7) {
+ if (datumtype == 'B')
+ items <<= 7 - (aint & 7);
+ else
+ items >>= 7 - (aint & 7);
+ *aptr++ = items & 0xff;
+ }
+ pat = str->str_ptr + str->str_cur;
+ while (aptr <= pat)
+ *aptr++ = '\0';
+
+ pat = savepat;
+ items = saveitems;
+ }
+ break;
+ case 'H':
+ case 'h':
+ {
+ char *savepat = pat;
+ int saveitems;
+
+ fromstr = NEXTFROM;
+ saveitems = items;
+ aptr = str_get(fromstr);
+ if (pat[-1] == '*')
+ len = fromstr->str_cur;
+ pat = aptr;
+ aint = str->str_cur;
+ str->str_cur += (len+1)/2;
+ STR_GROW(str, str->str_cur + 1);
+ aptr = str->str_ptr + aint;
+ if (len > fromstr->str_cur)
+ len = fromstr->str_cur;
+ aint = len;
+ items = 0;
+ if (datumtype == 'H') {
+ for (len = 0; len++ < aint;) {
+ if (isALPHA(*pat))
+ items |= ((*pat++ & 15) + 9) & 15;
+ else
+ items |= *pat++ & 15;
+ if (len & 1)
+ items <<= 4;
+ else {
+ *aptr++ = items & 0xff;
+ items = 0;
+ }
+ }
+ }
+ else {
+ for (len = 0; len++ < aint;) {
+ if (isALPHA(*pat))
+ items |= (((*pat++ & 15) + 9) & 15) << 4;
+ else
+ items |= (*pat++ & 15) << 4;
+ if (len & 1)
+ items >>= 4;
+ else {
+ *aptr++ = items & 0xff;
+ items = 0;
+ }
+ }
+ }
+ if (aint & 1)
+ *aptr++ = items & 0xff;
+ pat = str->str_ptr + str->str_cur;
+ while (aptr <= pat)
+ *aptr++ = '\0';
+
+ pat = savepat;
+ items = saveitems;
+ }
+ break;
+ case 'C':
+ case 'c':
+ while (len-- > 0) {
+ fromstr = NEXTFROM;
+ aint = (int)str_gnum(fromstr);
+ achar = aint;
+ str_ncat(str,&achar,sizeof(char));
+ }
+ break;
+ /* Float and double added by gnb@melba.bby.oz.au 22/11/89 */
+ case 'f':
+ case 'F':
+ while (len-- > 0) {
+ fromstr = NEXTFROM;
+ afloat = (float)str_gnum(fromstr);
+ str_ncat(str, (char *)&afloat, sizeof (float));
+ }
+ break;
+ case 'd':
+ case 'D':
+ while (len-- > 0) {
+ fromstr = NEXTFROM;
+ adouble = (double)str_gnum(fromstr);
+ str_ncat(str, (char *)&adouble, sizeof (double));
+ }
+ break;
+ case 'n':
+ while (len-- > 0) {
+ fromstr = NEXTFROM;
+ ashort = (short)str_gnum(fromstr);
+#ifdef HAS_HTONS
+ ashort = htons(ashort);
+#endif
+ str_ncat(str,(char*)&ashort,sizeof(short));
+ }
+ break;
+ case 'v':
+ while (len-- > 0) {
+ fromstr = NEXTFROM;
+ ashort = (short)str_gnum(fromstr);
+#ifdef HAS_HTOVS
+ ashort = htovs(ashort);
+#endif
+ str_ncat(str,(char*)&ashort,sizeof(short));
+ }
+ break;
+ case 'S':
+ case 's':
+ while (len-- > 0) {
+ fromstr = NEXTFROM;
+ ashort = (short)str_gnum(fromstr);
+ str_ncat(str,(char*)&ashort,sizeof(short));
+ }
+ break;
+ case 'I':
+ while (len-- > 0) {
+ fromstr = NEXTFROM;
+ auint = U_I(str_gnum(fromstr));
+ str_ncat(str,(char*)&auint,sizeof(unsigned int));
+ }
+ break;
+ case 'i':
+ while (len-- > 0) {
+ fromstr = NEXTFROM;
+ aint = (int)str_gnum(fromstr);
+ str_ncat(str,(char*)&aint,sizeof(int));
+ }
+ break;
+ case 'N':
+ while (len-- > 0) {
+ fromstr = NEXTFROM;
+ aulong = U_L(str_gnum(fromstr));
+#ifdef HAS_HTONL
+ aulong = htonl(aulong);
+#endif
+ str_ncat(str,(char*)&aulong,sizeof(unsigned long));
+ }
+ break;
+ case 'V':
+ while (len-- > 0) {
+ fromstr = NEXTFROM;
+ aulong = U_L(str_gnum(fromstr));
+#ifdef HAS_HTOVL
+ aulong = htovl(aulong);
+#endif
+ str_ncat(str,(char*)&aulong,sizeof(unsigned long));
+ }
+ break;
+ case 'L':
+ while (len-- > 0) {
+ fromstr = NEXTFROM;
+ aulong = U_L(str_gnum(fromstr));
+ str_ncat(str,(char*)&aulong,sizeof(unsigned long));
+ }
+ break;
+ case 'l':
+ while (len-- > 0) {
+ fromstr = NEXTFROM;
+ along = (long)str_gnum(fromstr);
+ str_ncat(str,(char*)&along,sizeof(long));
+ }
+ break;
+#ifdef QUAD
+ case 'Q':
+ while (len-- > 0) {
+ fromstr = NEXTFROM;
+ auquad = (unsigned quad)str_gnum(fromstr);
+ str_ncat(str,(char*)&auquad,sizeof(unsigned quad));
+ }
+ break;
+ case 'q':
+ while (len-- > 0) {
+ fromstr = NEXTFROM;
+ aquad = (quad)str_gnum(fromstr);
+ str_ncat(str,(char*)&aquad,sizeof(quad));
+ }
+ break;
+#endif /* QUAD */
+ case 'p':
+ while (len-- > 0) {
+ fromstr = NEXTFROM;
+ aptr = str_get(fromstr);
+ str_ncat(str,(char*)&aptr,sizeof(char*));
+ }
+ break;
+ case 'u':
+ fromstr = NEXTFROM;
+ aptr = str_get(fromstr);
+ aint = fromstr->str_cur;
+ STR_GROW(str,aint * 4 / 3);
+ if (len <= 1)
+ len = 45;
+ else
+ len = len / 3 * 3;
+ while (aint > 0) {
+ int todo;
+
+ if (aint > len)
+ todo = len;
+ else
+ todo = aint;
+ doencodes(str, aptr, todo);
+ aint -= todo;
+ aptr += todo;
+ }
+ break;
+ }
+ }
+ STABSET(str);
+}
+#undef NEXTFROM
+
+static void
+doencodes(str, s, len)
+register STR *str;
+register char *s;
+register int len;
+{
+ char hunk[5];
+
+ *hunk = len + ' ';
+ str_ncat(str, hunk, 1);
+ hunk[4] = '\0';
+ while (len > 0) {
+ hunk[0] = ' ' + (077 & (*s >> 2));
+ hunk[1] = ' ' + (077 & ((*s << 4) & 060 | (s[1] >> 4) & 017));
+ hunk[2] = ' ' + (077 & ((s[1] << 2) & 074 | (s[2] >> 6) & 03));
+ hunk[3] = ' ' + (077 & (s[2] & 077));
+ str_ncat(str, hunk, 4);
+ s += 3;
+ len -= 3;
+ }
+ for (s = str->str_ptr; *s; s++) {
+ if (*s == ' ')
+ *s = '`';
+ }
+ str_ncat(str, "\n", 1);
+}
+
+void
+do_sprintf(str,len,sarg)
+register STR *str;
+register int len;
+register STR **sarg;
+{
+ register char *s;
+ register char *t;
+ register char *f;
+ bool dolong;
+#ifdef QUAD
+ bool doquad;
+#endif /* QUAD */
+ char ch;
+ static STR *sargnull = &str_no;
+ register char *send;
+ register STR *arg;
+ char *xs;
+ int xlen;
+ int pre;
+ int post;
+ double value;
+
+ str_set(str,"");
+ len--; /* don't count pattern string */
+ t = s = str_get(*sarg);
+ send = s + (*sarg)->str_cur;
+ sarg++;
+ for ( ; ; len--) {
+
+ /*SUPPRESS 560*/
+ if (len <= 0 || !(arg = *sarg++))
+ arg = sargnull;
+
+ /*SUPPRESS 530*/
+ for ( ; t < send && *t != '%'; t++) ;
+ if (t >= send)
+ break; /* end of format string, ignore extra args */
+ f = t;
+ *buf = '\0';
+ xs = buf;
+#ifdef QUAD
+ doquad =
+#endif /* QUAD */
+ dolong = FALSE;
+ pre = post = 0;
+ for (t++; t < send; t++) {
+ switch (*t) {
+ default:
+ ch = *(++t);
+ *t = '\0';
+ (void)sprintf(xs,f);
+ len++, sarg--;
+ xlen = strlen(xs);
+ break;
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ case '.': case '#': case '-': case '+': case ' ':
+ continue;
+ case 'l':
+#ifdef QUAD
+ if (dolong) {
+ dolong = FALSE;
+ doquad = TRUE;
+ } else
+#endif
+ dolong = TRUE;
+ continue;
+ case 'c':
+ ch = *(++t);
+ *t = '\0';
+ xlen = (int)str_gnum(arg);
+ if (strEQ(f,"%c")) { /* some printfs fail on null chars */
+ *xs = xlen;
+ xs[1] = '\0';
+ xlen = 1;
+ }
+ else {
+ (void)sprintf(xs,f,xlen);
+ xlen = strlen(xs);
+ }
+ break;
+ case 'D':
+ dolong = TRUE;
+ /* FALL THROUGH */
+ case 'd':
+ ch = *(++t);
+ *t = '\0';
+#ifdef QUAD
+ if (doquad)
+ (void)sprintf(buf,s,(quad)str_gnum(arg));
+ else
+#endif
+ if (dolong)
+ (void)sprintf(xs,f,(long)str_gnum(arg));
+ else
+ (void)sprintf(xs,f,(int)str_gnum(arg));
+ xlen = strlen(xs);
+ break;
+ case 'X': case 'O':
+ dolong = TRUE;
+ /* FALL THROUGH */
+ case 'x': case 'o': case 'u':
+ ch = *(++t);
+ *t = '\0';
+ value = str_gnum(arg);
+#ifdef QUAD
+ if (doquad)
+ (void)sprintf(buf,s,(unsigned quad)value);
+ else
+#endif
+ if (dolong)
+ (void)sprintf(xs,f,U_L(value));
+ else
+ (void)sprintf(xs,f,U_I(value));
+ xlen = strlen(xs);
+ break;
+ case 'E': case 'e': case 'f': case 'G': case 'g':
+ ch = *(++t);
+ *t = '\0';
+ (void)sprintf(xs,f,str_gnum(arg));
+ xlen = strlen(xs);
+ break;
+ case 's':
+ ch = *(++t);
+ *t = '\0';
+ xs = str_get(arg);
+ xlen = arg->str_cur;
+ if (*xs == 'S' && xs[1] == 't' && xs[2] == 'B' && xs[3] == '\0'
+ && xlen == sizeof(STBP)) {
+ STR *tmpstr = Str_new(24,0);
+
+ stab_efullname(tmpstr, ((STAB*)arg)); /* a stab value! */
+ sprintf(tokenbuf,"*%s",tmpstr->str_ptr);
+ /* reformat to non-binary */
+ xs = tokenbuf;
+ xlen = strlen(tokenbuf);
+ str_free(tmpstr);
+ }
+ if (strEQ(f,"%s")) { /* some printfs fail on >128 chars */
+ break; /* so handle simple cases */
+ }
+ else if (f[1] == '-') {
+ char *mp = index(f, '.');
+ int min = atoi(f+2);
+
+ if (mp) {
+ int max = atoi(mp+1);
+
+ if (xlen > max)
+ xlen = max;
+ }
+ if (xlen < min)
+ post = min - xlen;
+ break;
+ }
+ else if (isDIGIT(f[1])) {
+ char *mp = index(f, '.');
+ int min = atoi(f+1);
+
+ if (mp) {
+ int max = atoi(mp+1);
+
+ if (xlen > max)
+ xlen = max;
+ }
+ if (xlen < min)
+ pre = min - xlen;
+ break;
+ }
+ strcpy(tokenbuf+64,f); /* sprintf($s,...$s...) */
+ *t = ch;
+ (void)sprintf(buf,tokenbuf+64,xs);
+ xs = buf;
+ xlen = strlen(xs);
+ break;
+ }
+ /* end of switch, copy results */
+ *t = ch;
+ STR_GROW(str, str->str_cur + (f - s) + xlen + 1 + pre + post);
+ str_ncat(str, s, f - s);
+ if (pre) {
+ repeatcpy(str->str_ptr + str->str_cur, " ", 1, pre);
+ str->str_cur += pre;
+ }
+ str_ncat(str, xs, xlen);
+ if (post) {
+ repeatcpy(str->str_ptr + str->str_cur, " ", 1, post);
+ str->str_cur += post;
+ }
+ s = t;
+ break; /* break from for loop */
+ }
+ }
+ str_ncat(str, s, t - s);
+ STABSET(str);
+}
+
+STR *
+do_push(ary,arglast)
+register ARRAY *ary;
+int *arglast;
+{
+ register STR **st = stack->ary_array;
+ register int sp = arglast[1];
+ register int items = arglast[2] - sp;
+ register STR *str = &str_undef;
+
+ for (st += ++sp; items > 0; items--,st++) {
+ str = Str_new(26,0);
+ if (*st)
+ str_sset(str,*st);
+ (void)apush(ary,str);
+ }
+ return str;
+}
+
+void
+do_unshift(ary,arglast)
+register ARRAY *ary;
+int *arglast;
+{
+ register STR **st = stack->ary_array;
+ register int sp = arglast[1];
+ register int items = arglast[2] - sp;
+ register STR *str;
+ register int i;
+
+ aunshift(ary,items);
+ i = 0;
+ for (st += ++sp; i < items; i++,st++) {
+ str = Str_new(27,0);
+ str_sset(str,*st);
+ (void)astore(ary,i,str);
+ }
+}
+
+int
+do_subr(arg,gimme,arglast)
+register ARG *arg;
+int gimme;
+int *arglast;
+{
+ register STR **st = stack->ary_array;
+ register int sp = arglast[1];
+ register int items = arglast[2] - sp;
+ register SUBR *sub;
+ SPAT * VOLATILE oldspat = curspat;
+ STR *str;
+ STAB *stab;
+ int oldsave = savestack->ary_fill;
+ int oldtmps_base = tmps_base;
+ int hasargs = ((arg[2].arg_type & A_MASK) != A_NULL);
+ register CSV *csv;
+
+ if ((arg[1].arg_type & A_MASK) == A_WORD)
+ stab = arg[1].arg_ptr.arg_stab;
+ else {
+ STR *tmpstr = STAB_STR(arg[1].arg_ptr.arg_stab);
+
+ if (tmpstr)
+ stab = stabent(str_get(tmpstr),TRUE);
+ else
+ stab = Nullstab;
+ }
+ if (!stab)
+ fatal("Undefined subroutine called");
+ if (!(sub = stab_sub(stab))) {
+ STR *tmpstr = arg[0].arg_ptr.arg_str;
+
+ stab_efullname(tmpstr, stab);
+ fatal("Undefined subroutine \"%s\" called",tmpstr->str_ptr);
+ }
+ if (arg->arg_type == O_DBSUBR && !sub->usersub) {
+ str = stab_val(DBsub);
+ saveitem(str);
+ stab_efullname(str,stab);
+ sub = stab_sub(DBsub);
+ if (!sub)
+ fatal("No DBsub routine");
+ }
+ str = Str_new(15, sizeof(CSV));
+ str->str_state = SS_SCSV;
+ (void)apush(savestack,str);
+ csv = (CSV*)str->str_ptr;
+ csv->sub = sub;
+ csv->stab = stab;
+ csv->curcsv = curcsv;
+ csv->curcmd = curcmd;
+ csv->depth = sub->depth;
+ csv->wantarray = gimme;
+ csv->hasargs = hasargs;
+ curcsv = csv;
+ tmps_base = tmps_max;
+ if (sub->usersub) {
+ csv->hasargs = 0;
+ csv->savearray = Null(ARRAY*);;
+ csv->argarray = Null(ARRAY*);
+ st[sp] = arg->arg_ptr.arg_str;
+ if (!hasargs)
+ items = 0;
+ sp = (*sub->usersub)(sub->userindex,sp,items);
+ }
+ else {
+ if (hasargs) {
+ csv->savearray = stab_xarray(defstab);
+ csv->argarray = afake(defstab, items, &st[sp+1]);
+ stab_xarray(defstab) = csv->argarray;
+ }
+ sub->depth++;
+ if (sub->depth >= 2) { /* save temporaries on recursion? */
+ if (sub->depth == 100 && dowarn)
+ warn("Deep recursion on subroutine \"%s\"",stab_ename(stab));
+ savelist(sub->tosave->ary_array,sub->tosave->ary_fill);
+ }
+ sp = cmd_exec(sub->cmd,gimme, --sp); /* so do it already */
+ }
+
+ st = stack->ary_array;
+ tmps_base = oldtmps_base;
+ for (items = arglast[0] + 1; items <= sp; items++)
+ st[items] = str_mortal(st[items]);
+ /* in case restore wipes old str */
+ restorelist(oldsave);
+ curspat = oldspat;
+ return sp;
+}
+
+int
+do_assign(arg,gimme,arglast)
+register ARG *arg;
+int gimme;
+int *arglast;
+{
+
+ register STR **st = stack->ary_array;
+ STR **firstrelem = st + arglast[1] + 1;
+ STR **firstlelem = st + arglast[0] + 1;
+ STR **lastrelem = st + arglast[2];
+ STR **lastlelem = st + arglast[1];
+ register STR **relem;
+ register STR **lelem;
+
+ register STR *str;
+ register ARRAY *ary;
+ register int makelocal;
+ HASH *hash;
+ int i;
+
+ makelocal = (arg->arg_flags & AF_LOCAL_XX) != 0;
+ localizing = makelocal;
+ delaymagic = DM_DELAY; /* catch simultaneous items */
+
+ /* If there's a common identifier on both sides we have to take
+ * special care that assigning the identifier on the left doesn't
+ * clobber a value on the right that's used later in the list.
+ */
+ if (arg->arg_flags & AF_COMMON) {
+ for (relem = firstrelem; relem <= lastrelem; relem++) {
+ /*SUPPRESS 560*/
+ if (str = *relem)
+ *relem = str_mortal(str);
+ }
+ }
+ relem = firstrelem;
+ lelem = firstlelem;
+ ary = Null(ARRAY*);
+ hash = Null(HASH*);
+ while (lelem <= lastlelem) {
+ str = *lelem++;
+ if (str->str_state >= SS_HASH) {
+ if (str->str_state == SS_ARY) {
+ if (makelocal)
+ ary = saveary(str->str_u.str_stab);
+ else {
+ ary = stab_array(str->str_u.str_stab);
+ ary->ary_fill = -1;
+ }
+ i = 0;
+ while (relem <= lastrelem) { /* gobble up all the rest */
+ str = Str_new(28,0);
+ if (*relem)
+ str_sset(str,*relem);
+ *(relem++) = str;
+ (void)astore(ary,i++,str);
+ }
+ }
+ else if (str->str_state == SS_HASH) {
+ char *tmps;
+ STR *tmpstr;
+ int magic = 0;
+ STAB *tmpstab = str->str_u.str_stab;
+
+ if (makelocal)
+ hash = savehash(str->str_u.str_stab);
+ else {
+ hash = stab_hash(str->str_u.str_stab);
+ if (tmpstab == envstab) {
+ magic = 'E';
+ environ[0] = Nullch;
+ }
+ else if (tmpstab == sigstab) {
+ magic = 'S';
+#ifndef NSIG
+#define NSIG 32
+#endif
+ for (i = 1; i < NSIG; i++)
+ signal(i, SIG_DFL); /* crunch, crunch, crunch */
+ }
+#ifdef SOME_DBM
+ else if (hash->tbl_dbm)
+ magic = 'D';
+#endif
+ hclear(hash, magic == 'D'); /* wipe any dbm file too */
+
+ }
+ while (relem < lastrelem) { /* gobble up all the rest */
+ if (*relem)
+ str = *(relem++);
+ else
+ str = &str_no, relem++;
+ tmps = str_get(str);
+ tmpstr = Str_new(29,0);
+ if (*relem)
+ str_sset(tmpstr,*relem); /* value */
+ *(relem++) = tmpstr;
+ (void)hstore(hash,tmps,str->str_cur,tmpstr,0);
+ if (magic) {
+ str_magic(tmpstr, tmpstab, magic, tmps, str->str_cur);
+ stabset(tmpstr->str_magic, tmpstr);
+ }
+ }
+ }
+ else
+ fatal("panic: do_assign");
+ }
+ else {
+ if (makelocal)
+ saveitem(str);
+ if (relem <= lastrelem) {
+ str_sset(str, *relem);
+ *(relem++) = str;
+ }
+ else {
+ str_sset(str, &str_undef);
+ if (gimme == G_ARRAY) {
+ i = ++lastrelem - firstrelem;
+ relem++; /* tacky, I suppose */
+ astore(stack,i,str);
+ if (st != stack->ary_array) {
+ st = stack->ary_array;
+ firstrelem = st + arglast[1] + 1;
+ firstlelem = st + arglast[0] + 1;
+ lastlelem = st + arglast[1];
+ lastrelem = st + i;
+ relem = lastrelem + 1;
+ }
+ }
+ }
+ STABSET(str);
+ }
+ }
+ if (delaymagic & ~DM_DELAY) {
+ if (delaymagic & DM_UID) {
+#ifdef HAS_SETREUID
+ (void)setreuid(uid,euid);
+#else /* not HAS_SETREUID */
+#ifdef HAS_SETRUID
+ if ((delaymagic & DM_UID) == DM_RUID) {
+ (void)setruid(uid);
+ delaymagic =~ DM_RUID;
+ }
+#endif /* HAS_SETRUID */
+#ifdef HAS_SETEUID
+ if ((delaymagic & DM_UID) == DM_EUID) {
+ (void)seteuid(uid);
+ delaymagic =~ DM_EUID;
+ }
+#endif /* HAS_SETEUID */
+ if (delaymagic & DM_UID) {
+ if (uid != euid)
+ fatal("No setreuid available");
+ (void)setuid(uid);
+ }
+#endif /* not HAS_SETREUID */
+ uid = (int)getuid();
+ euid = (int)geteuid();
+ }
+ if (delaymagic & DM_GID) {
+#ifdef HAS_SETREGID
+ (void)setregid(gid,egid);
+#else /* not HAS_SETREGID */
+#ifdef HAS_SETRGID
+ if ((delaymagic & DM_GID) == DM_RGID) {
+ (void)setrgid(gid);
+ delaymagic =~ DM_RGID;
+ }
+#endif /* HAS_SETRGID */
+#ifdef HAS_SETEGID
+ if ((delaymagic & DM_GID) == DM_EGID) {
+ (void)setegid(gid);
+ delaymagic =~ DM_EGID;
+ }
+#endif /* HAS_SETEGID */
+ if (delaymagic & DM_GID) {
+ if (gid != egid)
+ fatal("No setregid available");
+ (void)setgid(gid);
+ }
+#endif /* not HAS_SETREGID */
+ gid = (int)getgid();
+ egid = (int)getegid();
+ }
+ }
+ delaymagic = 0;
+ localizing = FALSE;
+ if (gimme == G_ARRAY) {
+ i = lastrelem - firstrelem + 1;
+ if (ary || hash)
+ Copy(firstrelem, firstlelem, i, STR*);
+ return arglast[0] + i;
+ }
+ else {
+ str_numset(arg->arg_ptr.arg_str,(double)(arglast[2] - arglast[1]));
+ *firstlelem = arg->arg_ptr.arg_str;
+ return arglast[0] + 1;
+ }
+}
+
+int /*SUPPRESS 590*/
+do_study(str,arg,gimme,arglast)
+STR *str;
+ARG *arg;
+int gimme;
+int *arglast;
+{
+ register unsigned char *s;
+ register int pos = str->str_cur;
+ register int ch;
+ register int *sfirst;
+ register int *snext;
+ static int maxscream = -1;
+ static STR *lastscream = Nullstr;
+ int retval;
+ int retarg = arglast[0] + 1;
+
+#ifndef lint
+ s = (unsigned char*)(str_get(str));
+#else
+ s = Null(unsigned char*);
+#endif
+ if (lastscream)
+ lastscream->str_pok &= ~SP_STUDIED;
+ lastscream = str;
+ if (pos <= 0) {
+ retval = 0;
+ goto ret;
+ }
+ if (pos > maxscream) {
+ if (maxscream < 0) {
+ maxscream = pos + 80;
+ New(301,screamfirst, 256, int);
+ New(302,screamnext, maxscream, int);
+ }
+ else {
+ maxscream = pos + pos / 4;
+ Renew(screamnext, maxscream, int);
+ }
+ }
+
+ sfirst = screamfirst;
+ snext = screamnext;
+
+ if (!sfirst || !snext)
+ fatal("do_study: out of memory");
+
+ for (ch = 256; ch; --ch)
+ *sfirst++ = -1;
+ sfirst -= 256;
+
+ while (--pos >= 0) {
+ ch = s[pos];
+ if (sfirst[ch] >= 0)
+ snext[pos] = sfirst[ch] - pos;
+ else
+ snext[pos] = -pos;
+ sfirst[ch] = pos;
+
+ /* If there were any case insensitive searches, we must assume they
+ * all are. This speeds up insensitive searches much more than
+ * it slows down sensitive ones.
+ */
+ if (sawi)
+ sfirst[fold[ch]] = pos;
+ }
+
+ str->str_pok |= SP_STUDIED;
+ retval = 1;
+ ret:
+ str_numset(arg->arg_ptr.arg_str,(double)retval);
+ stack->ary_array[retarg] = arg->arg_ptr.arg_str;
+ return retarg;
+}
+
+int /*SUPPRESS 590*/
+do_defined(str,arg,gimme,arglast)
+STR *str;
+register ARG *arg;
+int gimme;
+int *arglast;
+{
+ register int type;
+ register int retarg = arglast[0] + 1;
+ int retval;
+ ARRAY *ary;
+ HASH *hash;
+
+ if ((arg[1].arg_type & A_MASK) != A_LEXPR)
+ fatal("Illegal argument to defined()");
+ arg = arg[1].arg_ptr.arg_arg;
+ type = arg->arg_type;
+
+ if (type == O_SUBR || type == O_DBSUBR) {
+ if ((arg[1].arg_type & A_MASK) == A_WORD)
+ retval = stab_sub(arg[1].arg_ptr.arg_stab) != 0;
+ else {
+ STR *tmpstr = STAB_STR(arg[1].arg_ptr.arg_stab);
+
+ retval = tmpstr && stab_sub(stabent(str_get(tmpstr),TRUE)) != 0;
+ }
+ }
+ else if (type == O_ARRAY || type == O_LARRAY ||
+ type == O_ASLICE || type == O_LASLICE )
+ retval = ((ary = stab_xarray(arg[1].arg_ptr.arg_stab)) != 0
+ && ary->ary_max >= 0 );
+ else if (type == O_HASH || type == O_LHASH ||
+ type == O_HSLICE || type == O_LHSLICE )
+ retval = ((hash = stab_xhash(arg[1].arg_ptr.arg_stab)) != 0
+ && hash->tbl_array);
+ else
+ retval = FALSE;
+ str_numset(str,(double)retval);
+ stack->ary_array[retarg] = str;
+ return retarg;
+}
+
+int /*SUPPRESS 590*/
+do_undef(str,arg,gimme,arglast)
+STR *str;
+register ARG *arg;
+int gimme;
+int *arglast;
+{
+ register int type;
+ register STAB *stab;
+ int retarg = arglast[0] + 1;
+
+ if ((arg[1].arg_type & A_MASK) != A_LEXPR)
+ fatal("Illegal argument to undef()");
+ arg = arg[1].arg_ptr.arg_arg;
+ type = arg->arg_type;
+
+ if (type == O_ARRAY || type == O_LARRAY) {
+ stab = arg[1].arg_ptr.arg_stab;
+ afree(stab_xarray(stab));
+ stab_xarray(stab) = anew(stab); /* so "@array" still works */
+ }
+ else if (type == O_HASH || type == O_LHASH) {
+ stab = arg[1].arg_ptr.arg_stab;
+ if (stab == envstab)
+ environ[0] = Nullch;
+ else if (stab == sigstab) {
+ int i;
+
+ for (i = 1; i < NSIG; i++)
+ signal(i, SIG_DFL); /* munch, munch, munch */
+ }
+ (void)hfree(stab_xhash(stab), TRUE);
+ stab_xhash(stab) = Null(HASH*);
+ }
+ else if (type == O_SUBR || type == O_DBSUBR) {
+ stab = arg[1].arg_ptr.arg_stab;
+ if ((arg[1].arg_type & A_MASK) != A_WORD) {
+ STR *tmpstr = STAB_STR(arg[1].arg_ptr.arg_stab);
+
+ if (tmpstr)
+ stab = stabent(str_get(tmpstr),TRUE);
+ else
+ stab = Nullstab;
+ }
+ if (stab && stab_sub(stab)) {
+ cmd_free(stab_sub(stab)->cmd);
+ stab_sub(stab)->cmd = Nullcmd;
+ afree(stab_sub(stab)->tosave);
+ Safefree(stab_sub(stab));
+ stab_sub(stab) = Null(SUBR*);
+ }
+ }
+ else
+ fatal("Can't undefine that kind of object");
+ str_numset(str,0.0);
+ stack->ary_array[retarg] = str;
+ return retarg;
+}
+
+int
+do_vec(lvalue,astr,arglast)
+int lvalue;
+STR *astr;
+int *arglast;
+{
+ STR **st = stack->ary_array;
+ int sp = arglast[0];
+ register STR *str = st[++sp];
+ register int offset = (int)str_gnum(st[++sp]);
+ register int size = (int)str_gnum(st[++sp]);
+ unsigned char *s = (unsigned char*)str_get(str);
+ unsigned long retnum;
+ int len;
+
+ sp = arglast[1];
+ offset *= size; /* turn into bit offset */
+ len = (offset + size + 7) / 8;
+ if (offset < 0 || size < 1)
+ retnum = 0;
+ else if (!lvalue && len > str->str_cur)
+ retnum = 0;
+ else {
+ if (len > str->str_cur) {
+ STR_GROW(str,len);
+ (void)memzero(str->str_ptr + str->str_cur, len - str->str_cur);
+ str->str_cur = len;
+ }
+ s = (unsigned char*)str_get(str);
+ if (size < 8)
+ retnum = (s[offset >> 3] >> (offset & 7)) & ((1 << size) - 1);
+ else {
+ offset >>= 3;
+ if (size == 8)
+ retnum = s[offset];
+ else if (size == 16)
+ retnum = ((unsigned long) s[offset] << 8) + s[offset+1];
+ else if (size == 32)
+ retnum = ((unsigned long) s[offset] << 24) +
+ ((unsigned long) s[offset + 1] << 16) +
+ (s[offset + 2] << 8) + s[offset+3];
+ }
+
+ if (lvalue) { /* it's an lvalue! */
+ struct lstring *lstr = (struct lstring*)astr;
+
+ astr->str_magic = str;
+ st[sp]->str_rare = 'v';
+ lstr->lstr_offset = offset;
+ lstr->lstr_len = size;
+ }
+ }
+
+ str_numset(astr,(double)retnum);
+ st[sp] = astr;
+ return sp;
+}
+
+void
+do_vecset(mstr,str)
+STR *mstr;
+STR *str;
+{
+ struct lstring *lstr = (struct lstring*)str;
+ register int offset;
+ register int size;
+ register unsigned char *s = (unsigned char*)mstr->str_ptr;
+ register unsigned long lval = U_L(str_gnum(str));
+ int mask;
+
+ mstr->str_rare = 0;
+ str->str_magic = Nullstr;
+ offset = lstr->lstr_offset;
+ size = lstr->lstr_len;
+ if (size < 8) {
+ mask = (1 << size) - 1;
+ size = offset & 7;
+ lval &= mask;
+ offset >>= 3;
+ s[offset] &= ~(mask << size);
+ s[offset] |= lval << size;
+ }
+ else {
+ if (size == 8)
+ s[offset] = lval & 255;
+ else if (size == 16) {
+ s[offset] = (lval >> 8) & 255;
+ s[offset+1] = lval & 255;
+ }
+ else if (size == 32) {
+ s[offset] = (lval >> 24) & 255;
+ s[offset+1] = (lval >> 16) & 255;
+ s[offset+2] = (lval >> 8) & 255;
+ s[offset+3] = lval & 255;
+ }
+ }
+}
+
+void
+do_chop(astr,str)
+register STR *astr;
+register STR *str;
+{
+ register char *tmps;
+ register int i;
+ ARRAY *ary;
+ HASH *hash;
+ HENT *entry;
+
+ if (!str)
+ return;
+ if (str->str_state == SS_ARY) {
+ ary = stab_array(str->str_u.str_stab);
+ for (i = 0; i <= ary->ary_fill; i++)
+ do_chop(astr,ary->ary_array[i]);
+ return;
+ }
+ if (str->str_state == SS_HASH) {
+ hash = stab_hash(str->str_u.str_stab);
+ (void)hiterinit(hash);
+ /*SUPPRESS 560*/
+ while (entry = hiternext(hash))
+ do_chop(astr,hiterval(hash,entry));
+ return;
+ }
+ tmps = str_get(str);
+ if (tmps && str->str_cur) {
+ tmps += str->str_cur - 1;
+ str_nset(astr,tmps,1); /* remember last char */
+ *tmps = '\0'; /* wipe it out */
+ str->str_cur = tmps - str->str_ptr;
+ str->str_nok = 0;
+ STABSET(str);
+ }
+ else
+ str_nset(astr,"",0);
+}
+
+void
+do_vop(optype,str,left,right)
+STR *str;
+STR *left;
+STR *right;
+{
+ register char *s;
+ register char *l = str_get(left);
+ register char *r = str_get(right);
+ register int len;
+
+ len = left->str_cur;
+ if (len > right->str_cur)
+ len = right->str_cur;
+ if (str->str_cur > len)
+ str->str_cur = len;
+ else if (str->str_cur < len) {
+ STR_GROW(str,len);
+ (void)memzero(str->str_ptr + str->str_cur, len - str->str_cur);
+ str->str_cur = len;
+ }
+ str->str_pok = 1;
+ str->str_nok = 0;
+ s = str->str_ptr;
+ if (!s) {
+ str_nset(str,"",0);
+ s = str->str_ptr;
+ }
+ switch (optype) {
+ case O_BIT_AND:
+ while (len--)
+ *s++ = *l++ & *r++;
+ break;
+ case O_XOR:
+ while (len--)
+ *s++ = *l++ ^ *r++;
+ goto mop_up;
+ case O_BIT_OR:
+ while (len--)
+ *s++ = *l++ | *r++;
+ mop_up:
+ len = str->str_cur;
+ if (right->str_cur > len)
+ str_ncat(str,right->str_ptr+len,right->str_cur - len);
+ else if (left->str_cur > len)
+ str_ncat(str,left->str_ptr+len,left->str_cur - len);
+ break;
+ }
+}
+
+int
+do_syscall(arglast)
+int *arglast;
+{
+ register STR **st = stack->ary_array;
+ register int sp = arglast[1];
+ register int items = arglast[2] - sp;
+#ifdef atarist
+ unsigned long arg[14]; /* yes, we really need that many ! */
+#else
+ unsigned long arg[8];
+#endif
+ register int i = 0;
+ int retval = -1;
+
+#ifdef HAS_SYSCALL
+#ifdef TAINT
+ for (st += ++sp; items--; st++)
+ tainted |= (*st)->str_tainted;
+ st = stack->ary_array;
+ sp = arglast[1];
+ items = arglast[2] - sp;
+#endif
+#ifdef TAINT
+ taintproper("Insecure dependency in syscall");
+#endif
+ /* This probably won't work on machines where sizeof(long) != sizeof(int)
+ * or where sizeof(long) != sizeof(char*). But such machines will
+ * not likely have syscall implemented either, so who cares?
+ */
+ while (items--) {
+ if (st[++sp]->str_nok || !i)
+ arg[i++] = (unsigned long)str_gnum(st[sp]);
+#ifndef lint
+ else
+ arg[i++] = (unsigned long)st[sp]->str_ptr;
+#endif /* lint */
+ }
+ sp = arglast[1];
+ items = arglast[2] - sp;
+ switch (items) {
+ case 0:
+ fatal("Too few args to syscall");
+ case 1:
+ retval = syscall(arg[0]);
+ break;
+ case 2:
+ retval = syscall(arg[0],arg[1]);
+ break;
+ case 3:
+ retval = syscall(arg[0],arg[1],arg[2]);
+ break;
+ case 4:
+ retval = syscall(arg[0],arg[1],arg[2],arg[3]);
+ break;
+ case 5:
+ retval = syscall(arg[0],arg[1],arg[2],arg[3],arg[4]);
+ break;
+ case 6:
+ retval = syscall(arg[0],arg[1],arg[2],arg[3],arg[4],arg[5]);
+ break;
+ case 7:
+ retval = syscall(arg[0],arg[1],arg[2],arg[3],arg[4],arg[5],arg[6]);
+ break;
+ case 8:
+ retval = syscall(arg[0],arg[1],arg[2],arg[3],arg[4],arg[5],arg[6],
+ arg[7]);
+ break;
+#ifdef atarist
+ case 9:
+ retval = syscall(arg[0],arg[1],arg[2],arg[3],arg[4],arg[5],arg[6],
+ arg[7], arg[8]);
+ break;
+ case 10:
+ retval = syscall(arg[0],arg[1],arg[2],arg[3],arg[4],arg[5],arg[6],
+ arg[7], arg[8], arg[9]);
+ break;
+ case 11:
+ retval = syscall(arg[0],arg[1],arg[2],arg[3],arg[4],arg[5],arg[6],
+ arg[7], arg[8], arg[9], arg[10]);
+ break;
+ case 12:
+ retval = syscall(arg[0],arg[1],arg[2],arg[3],arg[4],arg[5],arg[6],
+ arg[7], arg[8], arg[9], arg[10], arg[11]);
+ break;
+ case 13:
+ retval = syscall(arg[0],arg[1],arg[2],arg[3],arg[4],arg[5],arg[6],
+ arg[7], arg[8], arg[9], arg[10], arg[11], arg[12]);
+ break;
+ case 14:
+ retval = syscall(arg[0],arg[1],arg[2],arg[3],arg[4],arg[5],arg[6],
+ arg[7], arg[8], arg[9], arg[10], arg[11], arg[12], arg[13]);
+ break;
+#endif /* atarist */
+ }
+ return retval;
+#else
+ fatal("syscall() unimplemented");
+#endif
+}
+
+
diff --git a/gnu/usr.bin/perl/perl/doio.c b/gnu/usr.bin/perl/perl/doio.c
new file mode 100644
index 0000000..9c0731f
--- /dev/null
+++ b/gnu/usr.bin/perl/perl/doio.c
@@ -0,0 +1,2958 @@
+/* $RCSfile: doio.c,v $$Revision: 1.2 $$Date: 1994/09/11 03:17:32 $
+ *
+ * Copyright (c) 1991, Larry Wall
+ *
+ * You may distribute under the terms of either the GNU General Public
+ * License or the Artistic License, as specified in the README file.
+ *
+ * $Log: doio.c,v $
+ * Revision 1.2 1994/09/11 03:17:32 gclarkii
+ * Changed AF_LOCAL to AF_LOCAL_XX so as not to conflict with 4.4 socket.h
+ * Added casts to shutup warnings in doio.c
+ *
+ * Revision 1.1.1.1 1994/09/10 06:27:32 gclarkii
+ * Initial import of Perl 4.046 bmaked
+ *
+ * Revision 1.2 1994/03/09 22:24:27 ache
+ * (cast) added for last argument of semctl
+ *
+ * Revision 1.1.1.1 1993/08/23 21:29:36 nate
+ * PERL!
+ *
+ * Revision 4.0.1.6 92/06/11 21:08:16 lwall
+ * patch34: some systems don't declare h_errno extern in header files
+ *
+ * Revision 4.0.1.5 92/06/08 13:00:21 lwall
+ * patch20: some machines don't define ENOTSOCK in errno.h
+ * patch20: new warnings for failed use of stat operators on filenames with \n
+ * patch20: wait failed when STDOUT or STDERR reopened to a pipe
+ * patch20: end of file latch not reset on reopen of STDIN
+ * patch20: seek(HANDLE, 0, 1) went to eof because of ancient Ultrix workaround
+ * patch20: fixed memory leak on system() for vfork() machines
+ * patch20: get*by* routines now return something useful in a scalar context
+ * patch20: h_errno now accessible via $?
+ *
+ * Revision 4.0.1.4 91/11/05 16:51:43 lwall
+ * patch11: prepared for ctype implementations that don't define isascii()
+ * patch11: perl mistook some streams for sockets because they return mode 0 too
+ * patch11: reopening STDIN, STDOUT and STDERR failed on some machines
+ * patch11: certain perl errors should set EBADF so that $! looks better
+ * patch11: truncate on a closed filehandle could dump
+ * patch11: stats of _ forgot whether prior stat was actually lstat
+ * patch11: -T returned true on NFS directory
+ *
+ * Revision 4.0.1.3 91/06/10 01:21:19 lwall
+ * patch10: read didn't work from character special files open for writing
+ * patch10: close-on-exec wrongly set on system file descriptors
+ *
+ * Revision 4.0.1.2 91/06/07 10:53:39 lwall
+ * patch4: new copyright notice
+ * patch4: system fd's are now treated specially
+ * patch4: added $^F variable to specify maximum system fd, default 2
+ * patch4: character special files now opened with bidirectional stdio buffers
+ * patch4: taintchecks could improperly modify parent in vfork()
+ * patch4: many, many itty-bitty portability fixes
+ *
+ * Revision 4.0.1.1 91/04/11 17:41:06 lwall
+ * patch1: hopefully straightened out some of the Xenix mess
+ *
+ * Revision 4.0 91/03/20 01:07:06 lwall
+ * 4.0 baseline.
+ *
+ */
+
+#include "EXTERN.h"
+#include "perl.h"
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+
+#ifdef HAS_SOCKET
+#include <sys/socket.h>
+#include <netdb.h>
+#ifndef ENOTSOCK
+#include <net/errno.h>
+#endif
+#endif
+
+#ifdef HAS_SELECT
+#ifdef I_SYS_SELECT
+#ifndef I_SYS_TIME
+#include <sys/select.h>
+#endif
+#endif
+#endif
+
+#ifdef HOST_NOT_FOUND
+extern int h_errno;
+#endif
+
+#if defined(HAS_MSG) || defined(HAS_SEM) || defined(HAS_SHM)
+#include <sys/ipc.h>
+#ifdef HAS_MSG
+#include <sys/msg.h>
+#endif
+#ifdef HAS_SEM
+#include <sys/sem.h>
+#endif
+#ifdef HAS_SHM
+#include <sys/shm.h>
+#endif
+#endif
+
+#ifdef I_PWD
+#include <pwd.h>
+#endif
+#ifdef I_GRP
+#include <grp.h>
+#endif
+#ifdef I_UTIME
+#include <utime.h>
+#endif
+#ifdef I_FCNTL
+#include <fcntl.h>
+#endif
+#ifdef I_SYS_FILE
+#include <sys/file.h>
+#endif
+
+int laststatval = -1;
+int laststype = O_STAT;
+
+static char* warn_nl = "Unsuccessful %s on filename containing newline";
+
+bool
+do_open(stab,name,len)
+STAB *stab;
+register char *name;
+int len;
+{
+ FILE *fp;
+ register STIO *stio = stab_io(stab);
+ char *myname = savestr(name);
+ int result;
+ int fd;
+ int writing = 0;
+ char mode[3]; /* stdio file mode ("r\0" or "r+\0") */
+ FILE *saveifp = Nullfp;
+ FILE *saveofp = Nullfp;
+ char savetype = ' ';
+
+ mode[0] = mode[1] = mode[2] = '\0';
+ name = myname;
+ forkprocess = 1; /* assume true if no fork */
+ while (len && isSPACE(name[len-1]))
+ name[--len] = '\0';
+ if (!stio)
+ stio = stab_io(stab) = stio_new();
+ else if (stio->ifp) {
+ fd = fileno(stio->ifp);
+ if (stio->type == '-')
+ result = 0;
+ else if (fd <= maxsysfd) {
+ saveifp = stio->ifp;
+ saveofp = stio->ofp;
+ savetype = stio->type;
+ result = 0;
+ }
+ else if (stio->type == '|')
+ result = mypclose(stio->ifp);
+ else if (stio->ifp != stio->ofp) {
+ if (stio->ofp) {
+ result = fclose(stio->ofp);
+ fclose(stio->ifp); /* clear stdio, fd already closed */
+ }
+ else
+ result = fclose(stio->ifp);
+ }
+ else
+ result = fclose(stio->ifp);
+ if (result == EOF && fd > maxsysfd)
+ fprintf(stderr,"Warning: unable to close filehandle %s properly.\n",
+ stab_ename(stab));
+ stio->ofp = stio->ifp = Nullfp;
+ }
+ if (*name == '+' && len > 1 && name[len-1] != '|') { /* scary */
+ mode[1] = *name++;
+ mode[2] = '\0';
+ --len;
+ writing = 1;
+ }
+ else {
+ mode[1] = '\0';
+ }
+ stio->type = *name;
+ if (*name == '|') {
+ /*SUPPRESS 530*/
+ for (name++; isSPACE(*name); name++) ;
+#ifdef TAINT
+ taintenv();
+ taintproper("Insecure dependency in piped open");
+#endif
+ fp = mypopen(name,"w");
+ writing = 1;
+ }
+ else if (*name == '>') {
+#ifdef TAINT
+ taintproper("Insecure dependency in open");
+#endif
+ name++;
+ if (*name == '>') {
+ mode[0] = stio->type = 'a';
+ name++;
+ }
+ else
+ mode[0] = 'w';
+ writing = 1;
+ if (*name == '&') {
+ duplicity:
+ name++;
+ while (isSPACE(*name))
+ name++;
+ if (isDIGIT(*name))
+ fd = atoi(name);
+ else {
+ stab = stabent(name,FALSE);
+ if (!stab || !stab_io(stab)) {
+#ifdef EINVAL
+ errno = EINVAL;
+#endif
+ goto say_false;
+ }
+ if (stab_io(stab) && stab_io(stab)->ifp) {
+ fd = fileno(stab_io(stab)->ifp);
+ if (stab_io(stab)->type == 's')
+ stio->type = 's';
+ }
+ else
+ fd = -1;
+ }
+ if (!(fp = fdopen(fd = dup(fd),mode))) {
+ close(fd);
+ }
+ }
+ else {
+ while (isSPACE(*name))
+ name++;
+ if (strEQ(name,"-")) {
+ fp = stdout;
+ stio->type = '-';
+ }
+ else {
+ fp = fopen(name,mode);
+ }
+ }
+ }
+ else {
+ if (*name == '<') {
+ mode[0] = 'r';
+ name++;
+ while (isSPACE(*name))
+ name++;
+ if (*name == '&')
+ goto duplicity;
+ if (strEQ(name,"-")) {
+ fp = stdin;
+ stio->type = '-';
+ }
+ else
+ fp = fopen(name,mode);
+ }
+ else if (name[len-1] == '|') {
+#ifdef TAINT
+ taintenv();
+ taintproper("Insecure dependency in piped open");
+#endif
+ name[--len] = '\0';
+ while (len && isSPACE(name[len-1]))
+ name[--len] = '\0';
+ /*SUPPRESS 530*/
+ for (; isSPACE(*name); name++) ;
+ fp = mypopen(name,"r");
+ stio->type = '|';
+ }
+ else {
+ stio->type = '<';
+ /*SUPPRESS 530*/
+ for (; isSPACE(*name); name++) ;
+ if (strEQ(name,"-")) {
+ fp = stdin;
+ stio->type = '-';
+ }
+ else
+ fp = fopen(name,"r");
+ }
+ }
+ if (!fp) {
+ if (dowarn && stio->type == '<' && index(name, '\n'))
+ warn(warn_nl, "open");
+ Safefree(myname);
+ goto say_false;
+ }
+ Safefree(myname);
+ if (stio->type &&
+ stio->type != '|' && stio->type != '-') {
+ if (fstat(fileno(fp),&statbuf) < 0) {
+ (void)fclose(fp);
+ goto say_false;
+ }
+ if (S_ISSOCK(statbuf.st_mode))
+ stio->type = 's'; /* in case a socket was passed in to us */
+#ifdef HAS_SOCKET
+ else if (
+#ifdef S_IFMT
+ !(statbuf.st_mode & S_IFMT)
+#else
+ !statbuf.st_mode
+#endif
+ ) {
+ int buflen = sizeof tokenbuf;
+ if (getsockname(fileno(fp), (struct sockaddr * )tokenbuf, &buflen) >= 0
+ || errno != ENOTSOCK)
+ stio->type = 's'; /* some OS's return 0 on fstat()ed socket */
+ /* but some return 0 for streams too, sigh */
+ }
+#endif
+ }
+ if (saveifp) { /* must use old fp? */
+ fd = fileno(saveifp);
+ if (saveofp) {
+ fflush(saveofp); /* emulate fclose() */
+ if (saveofp != saveifp) { /* was a socket? */
+ fclose(saveofp);
+ if (fd > 2)
+ Safefree(saveofp);
+ }
+ }
+ if (fd != fileno(fp)) {
+ int pid;
+ STR *str;
+
+ dup2(fileno(fp), fd);
+ str = afetch(fdpid,fileno(fp),TRUE);
+ pid = str->str_u.str_useful;
+ str->str_u.str_useful = 0;
+ str = afetch(fdpid,fd,TRUE);
+ str->str_u.str_useful = pid;
+ fclose(fp);
+
+ }
+ fp = saveifp;
+ clearerr(fp);
+ }
+#if defined(HAS_FCNTL) && defined(F_SETFD)
+ fd = fileno(fp);
+ fcntl(fd,F_SETFD,fd > maxsysfd);
+#endif
+ stio->ifp = fp;
+ if (writing) {
+ if (stio->type == 's'
+ || (stio->type == '>' && S_ISCHR(statbuf.st_mode)) ) {
+ if (!(stio->ofp = fdopen(fileno(fp),"w"))) {
+ fclose(fp);
+ stio->ifp = Nullfp;
+ goto say_false;
+ }
+ }
+ else
+ stio->ofp = fp;
+ }
+ return TRUE;
+
+say_false:
+ stio->ifp = saveifp;
+ stio->ofp = saveofp;
+ stio->type = savetype;
+ return FALSE;
+}
+
+FILE *
+nextargv(stab)
+register STAB *stab;
+{
+ register STR *str;
+#ifndef FLEXFILENAMES
+ int filedev;
+ int fileino;
+#endif
+ int fileuid;
+ int filegid;
+ static int filemode = 0;
+ static int lastfd;
+ static char *oldname;
+
+ if (!argvoutstab)
+ argvoutstab = stabent("ARGVOUT",TRUE);
+ if (filemode & (S_ISUID|S_ISGID)) {
+ fflush(stab_io(argvoutstab)->ifp); /* chmod must follow last write */
+#ifdef HAS_FCHMOD
+ (void)fchmod(lastfd,filemode);
+#else
+ (void)chmod(oldname,filemode);
+#endif
+ }
+ filemode = 0;
+ while (alen(stab_xarray(stab)) >= 0) {
+ str = ashift(stab_xarray(stab));
+ str_sset(stab_val(stab),str);
+ STABSET(stab_val(stab));
+ oldname = str_get(stab_val(stab));
+ if (do_open(stab,oldname,stab_val(stab)->str_cur)) {
+ if (inplace) {
+#ifdef TAINT
+ taintproper("Insecure dependency in inplace open");
+#endif
+ if (strEQ(oldname,"-")) {
+ str_free(str);
+ defoutstab = stabent("STDOUT",TRUE);
+ return stab_io(stab)->ifp;
+ }
+#ifndef FLEXFILENAMES
+ filedev = statbuf.st_dev;
+ fileino = statbuf.st_ino;
+#endif
+ filemode = statbuf.st_mode;
+ fileuid = statbuf.st_uid;
+ filegid = statbuf.st_gid;
+ if (!S_ISREG(filemode)) {
+ warn("Can't do inplace edit: %s is not a regular file",
+ oldname );
+ do_close(stab,FALSE);
+ str_free(str);
+ continue;
+ }
+ if (*inplace) {
+#ifdef SUFFIX
+ add_suffix(str,inplace);
+#else
+ str_cat(str,inplace);
+#endif
+#ifndef FLEXFILENAMES
+ if (stat(str->str_ptr,&statbuf) >= 0
+ && statbuf.st_dev == filedev
+ && statbuf.st_ino == fileino ) {
+ warn("Can't do inplace edit: %s > 14 characters",
+ str->str_ptr );
+ do_close(stab,FALSE);
+ str_free(str);
+ continue;
+ }
+#endif
+#ifdef HAS_RENAME
+#ifndef DOSISH
+ if (rename(oldname,str->str_ptr) < 0) {
+ warn("Can't rename %s to %s: %s, skipping file",
+ oldname, str->str_ptr, strerror(errno) );
+ do_close(stab,FALSE);
+ str_free(str);
+ continue;
+ }
+#else
+ do_close(stab,FALSE);
+ (void)unlink(str->str_ptr);
+ (void)rename(oldname,str->str_ptr);
+ do_open(stab,str->str_ptr,stab_val(stab)->str_cur);
+#endif /* MSDOS */
+#else
+ (void)UNLINK(str->str_ptr);
+ if (link(oldname,str->str_ptr) < 0) {
+ warn("Can't rename %s to %s: %s, skipping file",
+ oldname, str->str_ptr, strerror(errno) );
+ do_close(stab,FALSE);
+ str_free(str);
+ continue;
+ }
+ (void)UNLINK(oldname);
+#endif
+ }
+ else {
+#ifndef DOSISH
+ if (UNLINK(oldname) < 0) {
+ warn("Can't rename %s to %s: %s, skipping file",
+ oldname, str->str_ptr, strerror(errno) );
+ do_close(stab,FALSE);
+ str_free(str);
+ continue;
+ }
+#else
+ fatal("Can't do inplace edit without backup");
+#endif
+ }
+
+ str_nset(str,">",1);
+ str_cat(str,oldname);
+ errno = 0; /* in case sprintf set errno */
+ if (!do_open(argvoutstab,str->str_ptr,str->str_cur)) {
+ warn("Can't do inplace edit on %s: %s",
+ oldname, strerror(errno) );
+ do_close(stab,FALSE);
+ str_free(str);
+ continue;
+ }
+ defoutstab = argvoutstab;
+ lastfd = fileno(stab_io(argvoutstab)->ifp);
+ (void)fstat(lastfd,&statbuf);
+#ifdef HAS_FCHMOD
+ (void)fchmod(lastfd,filemode);
+#else
+ (void)chmod(oldname,filemode);
+#endif
+ if (fileuid != statbuf.st_uid || filegid != statbuf.st_gid) {
+#ifdef HAS_FCHOWN
+ (void)fchown(lastfd,fileuid,filegid);
+#else
+#ifdef HAS_CHOWN
+ (void)chown(oldname,fileuid,filegid);
+#endif
+#endif
+ }
+ }
+ str_free(str);
+ return stab_io(stab)->ifp;
+ }
+ else
+ fprintf(stderr,"Can't open %s: %s\n",str_get(str), strerror(errno));
+ str_free(str);
+ }
+ if (inplace) {
+ (void)do_close(argvoutstab,FALSE);
+ defoutstab = stabent("STDOUT",TRUE);
+ }
+ return Nullfp;
+}
+
+#ifdef HAS_PIPE
+void
+do_pipe(str, rstab, wstab)
+STR *str;
+STAB *rstab;
+STAB *wstab;
+{
+ register STIO *rstio;
+ register STIO *wstio;
+ int fd[2];
+
+ if (!rstab)
+ goto badexit;
+ if (!wstab)
+ goto badexit;
+
+ rstio = stab_io(rstab);
+ wstio = stab_io(wstab);
+
+ if (!rstio)
+ rstio = stab_io(rstab) = stio_new();
+ else if (rstio->ifp)
+ do_close(rstab,FALSE);
+ if (!wstio)
+ wstio = stab_io(wstab) = stio_new();
+ else if (wstio->ifp)
+ do_close(wstab,FALSE);
+
+ if (pipe(fd) < 0)
+ goto badexit;
+ rstio->ifp = fdopen(fd[0], "r");
+ wstio->ofp = fdopen(fd[1], "w");
+ wstio->ifp = wstio->ofp;
+ rstio->type = '<';
+ wstio->type = '>';
+ if (!rstio->ifp || !wstio->ofp) {
+ if (rstio->ifp) fclose(rstio->ifp);
+ else close(fd[0]);
+ if (wstio->ofp) fclose(wstio->ofp);
+ else close(fd[1]);
+ goto badexit;
+ }
+
+ str_sset(str,&str_yes);
+ return;
+
+badexit:
+ str_sset(str,&str_undef);
+ return;
+}
+#endif
+
+bool
+do_close(stab,explicit)
+STAB *stab;
+bool explicit;
+{
+ bool retval = FALSE;
+ register STIO *stio;
+ int status;
+
+ if (!stab)
+ stab = argvstab;
+ if (!stab) {
+ errno = EBADF;
+ return FALSE;
+ }
+ stio = stab_io(stab);
+ if (!stio) { /* never opened */
+ if (dowarn && explicit)
+ warn("Close on unopened file <%s>",stab_ename(stab));
+ return FALSE;
+ }
+ if (stio->ifp) {
+ if (stio->type == '|') {
+ status = mypclose(stio->ifp);
+ retval = (status == 0);
+ statusvalue = (unsigned short)status & 0xffff;
+ }
+ else if (stio->type == '-')
+ retval = TRUE;
+ else {
+ if (stio->ofp && stio->ofp != stio->ifp) { /* a socket */
+ retval = (fclose(stio->ofp) != EOF);
+ fclose(stio->ifp); /* clear stdio, fd already closed */
+ }
+ else
+ retval = (fclose(stio->ifp) != EOF);
+ }
+ stio->ofp = stio->ifp = Nullfp;
+ }
+ if (explicit)
+ stio->lines = 0;
+ stio->type = ' ';
+ return retval;
+}
+
+bool
+do_eof(stab)
+STAB *stab;
+{
+ register STIO *stio;
+ int ch;
+
+ if (!stab) { /* eof() */
+ if (argvstab)
+ stio = stab_io(argvstab);
+ else
+ return TRUE;
+ }
+ else
+ stio = stab_io(stab);
+
+ if (!stio)
+ return TRUE;
+
+ while (stio->ifp) {
+
+#ifdef STDSTDIO /* (the code works without this) */
+ if (stio->ifp->_cnt > 0) /* cheat a little, since */
+ return FALSE; /* this is the most usual case */
+#endif
+
+ ch = getc(stio->ifp);
+ if (ch != EOF) {
+ (void)ungetc(ch, stio->ifp);
+ return FALSE;
+ }
+#ifdef STDSTDIO
+ if (stio->ifp->_cnt < -1)
+ stio->ifp->_cnt = -1;
+#endif
+ if (!stab) { /* not necessarily a real EOF yet? */
+ if (!nextargv(argvstab)) /* get another fp handy */
+ return TRUE;
+ }
+ else
+ return TRUE; /* normal fp, definitely end of file */
+ }
+ return TRUE;
+}
+
+long
+do_tell(stab)
+STAB *stab;
+{
+ register STIO *stio;
+
+ if (!stab)
+ goto phooey;
+
+ stio = stab_io(stab);
+ if (!stio || !stio->ifp)
+ goto phooey;
+
+#ifdef ULTRIX_STDIO_BOTCH
+ if (feof(stio->ifp))
+ (void)fseek (stio->ifp, 0L, 2); /* ultrix 1.2 workaround */
+#endif
+
+ return ftell(stio->ifp);
+
+phooey:
+ if (dowarn)
+ warn("tell() on unopened file");
+ errno = EBADF;
+ return -1L;
+}
+
+bool
+do_seek(stab, pos, whence)
+STAB *stab;
+long pos;
+int whence;
+{
+ register STIO *stio;
+
+ if (!stab)
+ goto nuts;
+
+ stio = stab_io(stab);
+ if (!stio || !stio->ifp)
+ goto nuts;
+
+#ifdef ULTRIX_STDIO_BOTCH
+ if (feof(stio->ifp))
+ (void)fseek (stio->ifp, 0L, 2); /* ultrix 1.2 workaround */
+#endif
+
+ return fseek(stio->ifp, pos, whence) >= 0;
+
+nuts:
+ if (dowarn)
+ warn("seek() on unopened file");
+ errno = EBADF;
+ return FALSE;
+}
+
+int
+do_ctl(optype,stab,func,argstr)
+int optype;
+STAB *stab;
+int func;
+STR *argstr;
+{
+ register STIO *stio;
+ register char *s;
+ int retval;
+
+ if (!stab || !argstr || !(stio = stab_io(stab)) || !stio->ifp) {
+ errno = EBADF; /* well, sort of... */
+ return -1;
+ }
+
+ if (argstr->str_pok || !argstr->str_nok) {
+ if (!argstr->str_pok)
+ s = str_get(argstr);
+
+#ifdef IOCPARM_MASK
+#ifndef IOCPARM_LEN
+#define IOCPARM_LEN(x) (((x) >> 16) & IOCPARM_MASK)
+#endif
+#endif
+#ifdef IOCPARM_LEN
+ retval = IOCPARM_LEN(func); /* on BSDish systes we're safe */
+#else
+ retval = 256; /* otherwise guess at what's safe */
+#endif
+ if (argstr->str_cur < retval) {
+ Str_Grow(argstr,retval+1);
+ argstr->str_cur = retval;
+ }
+
+ s = argstr->str_ptr;
+ s[argstr->str_cur] = 17; /* a little sanity check here */
+ }
+ else {
+ retval = (int)str_gnum(argstr);
+#ifdef DOSISH
+ s = (char*)(long)retval; /* ouch */
+#else
+ s = (char*)retval; /* ouch */
+#endif
+ }
+
+#ifndef lint
+ if (optype == O_IOCTL)
+ retval = ioctl(fileno(stio->ifp), func, s);
+ else
+#ifdef DOSISH
+ fatal("fcntl is not implemented");
+#else
+#ifdef HAS_FCNTL
+ retval = fcntl(fileno(stio->ifp), func, s);
+#else
+ fatal("fcntl is not implemented");
+#endif
+#endif
+#else /* lint */
+ retval = 0;
+#endif /* lint */
+
+ if (argstr->str_pok) {
+ if (s[argstr->str_cur] != 17)
+ fatal("Return value overflowed string");
+ s[argstr->str_cur] = 0; /* put our null back */
+ }
+ return retval;
+}
+
+int
+do_stat(str,arg,gimme,arglast)
+STR *str;
+register ARG *arg;
+int gimme;
+int *arglast;
+{
+ register ARRAY *ary = stack;
+ register int sp = arglast[0] + 1;
+ int max = 13;
+
+ if ((arg[1].arg_type & A_MASK) == A_WORD) {
+ tmpstab = arg[1].arg_ptr.arg_stab;
+ if (tmpstab != defstab) {
+ laststype = O_STAT;
+ statstab = tmpstab;
+ str_set(statname,"");
+ if (!stab_io(tmpstab) || !stab_io(tmpstab)->ifp ||
+ fstat(fileno(stab_io(tmpstab)->ifp),&statcache) < 0) {
+ max = 0;
+ laststatval = -1;
+ }
+ }
+ else if (laststatval < 0)
+ max = 0;
+ }
+ else {
+ str_set(statname,str_get(ary->ary_array[sp]));
+ statstab = Nullstab;
+#ifdef HAS_LSTAT
+ laststype = arg->arg_type;
+ if (arg->arg_type == O_LSTAT)
+ laststatval = lstat(str_get(statname),&statcache);
+ else
+#endif
+ laststatval = stat(str_get(statname),&statcache);
+ if (laststatval < 0) {
+ if (dowarn && index(str_get(statname), '\n'))
+ warn(warn_nl, "stat");
+ max = 0;
+ }
+ }
+
+ if (gimme != G_ARRAY) {
+ if (max)
+ str_sset(str,&str_yes);
+ else
+ str_sset(str,&str_undef);
+ STABSET(str);
+ ary->ary_array[sp] = str;
+ return sp;
+ }
+ sp--;
+ if (max) {
+#ifndef lint
+ (void)astore(ary,++sp,
+ str_2mortal(str_nmake((double)statcache.st_dev)));
+ (void)astore(ary,++sp,
+ str_2mortal(str_nmake((double)statcache.st_ino)));
+ (void)astore(ary,++sp,
+ str_2mortal(str_nmake((double)statcache.st_mode)));
+ (void)astore(ary,++sp,
+ str_2mortal(str_nmake((double)statcache.st_nlink)));
+ (void)astore(ary,++sp,
+ str_2mortal(str_nmake((double)statcache.st_uid)));
+ (void)astore(ary,++sp,
+ str_2mortal(str_nmake((double)statcache.st_gid)));
+ (void)astore(ary,++sp,
+ str_2mortal(str_nmake((double)statcache.st_rdev)));
+ (void)astore(ary,++sp,
+ str_2mortal(str_nmake((double)statcache.st_size)));
+ (void)astore(ary,++sp,
+ str_2mortal(str_nmake((double)statcache.st_atime)));
+ (void)astore(ary,++sp,
+ str_2mortal(str_nmake((double)statcache.st_mtime)));
+ (void)astore(ary,++sp,
+ str_2mortal(str_nmake((double)statcache.st_ctime)));
+#ifdef STATBLOCKS
+ (void)astore(ary,++sp,
+ str_2mortal(str_nmake((double)statcache.st_blksize)));
+ (void)astore(ary,++sp,
+ str_2mortal(str_nmake((double)statcache.st_blocks)));
+#else
+ (void)astore(ary,++sp,
+ str_2mortal(str_make("",0)));
+ (void)astore(ary,++sp,
+ str_2mortal(str_make("",0)));
+#endif
+#else /* lint */
+ (void)astore(ary,++sp,str_nmake(0.0));
+#endif /* lint */
+ }
+ return sp;
+}
+
+#if !defined(HAS_TRUNCATE) && !defined(HAS_CHSIZE) && defined(F_FREESP)
+ /* code courtesy of William Kucharski */
+#define HAS_CHSIZE
+
+int chsize(fd, length)
+int fd; /* file descriptor */
+off_t length; /* length to set file to */
+{
+ extern long lseek();
+ struct flock fl;
+ struct stat filebuf;
+
+ if (fstat(fd, &filebuf) < 0)
+ return -1;
+
+ if (filebuf.st_size < length) {
+
+ /* extend file length */
+
+ if ((lseek(fd, (length - 1), 0)) < 0)
+ return -1;
+
+ /* write a "0" byte */
+
+ if ((write(fd, "", 1)) != 1)
+ return -1;
+ }
+ else {
+ /* truncate length */
+
+ fl.l_whence = 0;
+ fl.l_len = 0;
+ fl.l_start = length;
+ fl.l_type = F_WRLCK; /* write lock on file space */
+
+ /*
+ * This relies on the UNDOCUMENTED F_FREESP argument to
+ * fcntl(2), which truncates the file so that it ends at the
+ * position indicated by fl.l_start.
+ *
+ * Will minor miracles never cease?
+ */
+
+ if (fcntl(fd, F_FREESP, &fl) < 0)
+ return -1;
+
+ }
+
+ return 0;
+}
+#endif /* F_FREESP */
+
+int /*SUPPRESS 590*/
+do_truncate(str,arg,gimme,arglast)
+STR *str;
+register ARG *arg;
+int gimme;
+int *arglast;
+{
+ register ARRAY *ary = stack;
+ register int sp = arglast[0] + 1;
+ off_t len = (off_t)str_gnum(ary->ary_array[sp+1]);
+ int result = 1;
+ STAB *tmpstab;
+
+#if defined(HAS_TRUNCATE) || defined(HAS_CHSIZE)
+#ifdef HAS_TRUNCATE
+ if ((arg[1].arg_type & A_MASK) == A_WORD) {
+ tmpstab = arg[1].arg_ptr.arg_stab;
+ if (!stab_io(tmpstab) || !stab_io(tmpstab)->ifp ||
+ ftruncate(fileno(stab_io(tmpstab)->ifp), len) < 0)
+ result = 0;
+ }
+ else if (truncate(str_get(ary->ary_array[sp]), len) < 0)
+ result = 0;
+#else
+ if ((arg[1].arg_type & A_MASK) == A_WORD) {
+ tmpstab = arg[1].arg_ptr.arg_stab;
+ if (!stab_io(tmpstab) || !stab_io(tmpstab)->ifp ||
+ chsize(fileno(stab_io(tmpstab)->ifp), len) < 0)
+ result = 0;
+ }
+ else {
+ int tmpfd;
+
+ if ((tmpfd = open(str_get(ary->ary_array[sp]), 0)) < 0)
+ result = 0;
+ else {
+ if (chsize(tmpfd, len) < 0)
+ result = 0;
+ close(tmpfd);
+ }
+ }
+#endif
+
+ if (result)
+ str_sset(str,&str_yes);
+ else
+ str_sset(str,&str_undef);
+ STABSET(str);
+ ary->ary_array[sp] = str;
+ return sp;
+#else
+ fatal("truncate not implemented");
+#endif
+}
+
+int
+looks_like_number(str)
+STR *str;
+{
+ register char *s;
+ register char *send;
+
+ if (!str->str_pok)
+ return TRUE;
+ s = str->str_ptr;
+ send = s + str->str_cur;
+ while (isSPACE(*s))
+ s++;
+ if (s >= send)
+ return FALSE;
+ if (*s == '+' || *s == '-')
+ s++;
+ while (isDIGIT(*s))
+ s++;
+ if (s == send)
+ return TRUE;
+ if (*s == '.')
+ s++;
+ else if (s == str->str_ptr)
+ return FALSE;
+ while (isDIGIT(*s))
+ s++;
+ if (s == send)
+ return TRUE;
+ if (*s == 'e' || *s == 'E') {
+ s++;
+ if (*s == '+' || *s == '-')
+ s++;
+ while (isDIGIT(*s))
+ s++;
+ }
+ while (isSPACE(*s))
+ s++;
+ if (s >= send)
+ return TRUE;
+ return FALSE;
+}
+
+bool
+do_print(str,fp)
+register STR *str;
+FILE *fp;
+{
+ register char *tmps;
+
+ if (!fp) {
+ if (dowarn)
+ warn("print to unopened file");
+ errno = EBADF;
+ return FALSE;
+ }
+ if (!str)
+ return TRUE;
+ if (ofmt &&
+ ((str->str_nok && str->str_u.str_nval != 0.0)
+ || (looks_like_number(str) && str_gnum(str) != 0.0) ) ) {
+ fprintf(fp, ofmt, str->str_u.str_nval);
+ return !ferror(fp);
+ }
+ else {
+ tmps = str_get(str);
+ if (*tmps == 'S' && tmps[1] == 't' && tmps[2] == 'B' && tmps[3] == '\0'
+ && str->str_cur == sizeof(STBP) && strlen(tmps) < str->str_cur) {
+ STR *tmpstr = str_mortal(&str_undef);
+ stab_efullname(tmpstr,((STAB*)str));/* a stab value, be nice */
+ str = tmpstr;
+ tmps = str->str_ptr;
+ putc('*',fp);
+ }
+ if (str->str_cur && (fwrite(tmps,1,str->str_cur,fp) == 0 || ferror(fp)))
+ return FALSE;
+ }
+ return TRUE;
+}
+
+bool
+do_aprint(arg,fp,arglast)
+register ARG *arg;
+register FILE *fp;
+int *arglast;
+{
+ register STR **st = stack->ary_array;
+ register int sp = arglast[1];
+ register int retval;
+ register int items = arglast[2] - sp;
+
+ if (!fp) {
+ if (dowarn)
+ warn("print to unopened file");
+ errno = EBADF;
+ return FALSE;
+ }
+ st += ++sp;
+ if (arg->arg_type == O_PRTF) {
+ do_sprintf(arg->arg_ptr.arg_str,items,st);
+ retval = do_print(arg->arg_ptr.arg_str,fp);
+ }
+ else {
+ retval = (items <= 0);
+ for (; items > 0; items--,st++) {
+ if (retval && ofslen) {
+ if (fwrite(ofs, 1, ofslen, fp) == 0 || ferror(fp)) {
+ retval = FALSE;
+ break;
+ }
+ }
+ if (!(retval = do_print(*st, fp)))
+ break;
+ }
+ if (retval && orslen)
+ if (fwrite(ors, 1, orslen, fp) == 0 || ferror(fp))
+ retval = FALSE;
+ }
+ return retval;
+}
+
+int
+mystat(arg,str)
+ARG *arg;
+STR *str;
+{
+ STIO *stio;
+
+ if (arg[1].arg_type & A_DONT) {
+ stio = stab_io(arg[1].arg_ptr.arg_stab);
+ if (stio && stio->ifp) {
+ statstab = arg[1].arg_ptr.arg_stab;
+ str_set(statname,"");
+ laststype = O_STAT;
+ return (laststatval = fstat(fileno(stio->ifp), &statcache));
+ }
+ else {
+ if (arg[1].arg_ptr.arg_stab == defstab)
+ return laststatval;
+ if (dowarn)
+ warn("Stat on unopened file <%s>",
+ stab_ename(arg[1].arg_ptr.arg_stab));
+ statstab = Nullstab;
+ str_set(statname,"");
+ return (laststatval = -1);
+ }
+ }
+ else {
+ statstab = Nullstab;
+ str_set(statname,str_get(str));
+ laststype = O_STAT;
+ laststatval = stat(str_get(str),&statcache);
+ if (laststatval < 0 && dowarn && index(str_get(str), '\n'))
+ warn(warn_nl, "stat");
+ return laststatval;
+ }
+}
+
+int
+mylstat(arg,str)
+ARG *arg;
+STR *str;
+{
+ if (arg[1].arg_type & A_DONT) {
+ if (arg[1].arg_ptr.arg_stab == defstab) {
+ if (laststype != O_LSTAT)
+ fatal("The stat preceding -l _ wasn't an lstat");
+ return laststatval;
+ }
+ fatal("You can't use -l on a filehandle");
+ }
+
+ laststype = O_LSTAT;
+ statstab = Nullstab;
+ str_set(statname,str_get(str));
+#ifdef HAS_LSTAT
+ laststatval = lstat(str_get(str),&statcache);
+#else
+ laststatval = stat(str_get(str),&statcache);
+#endif
+ if (laststatval < 0 && dowarn && index(str_get(str), '\n'))
+ warn(warn_nl, "lstat");
+ return laststatval;
+}
+
+STR *
+do_fttext(arg,str)
+register ARG *arg;
+STR *str;
+{
+ int i;
+ int len;
+ int odd = 0;
+ STDCHAR tbuf[512];
+ register STDCHAR *s;
+ register STIO *stio;
+
+ if (arg[1].arg_type & A_DONT) {
+ if (arg[1].arg_ptr.arg_stab == defstab) {
+ if (statstab)
+ stio = stab_io(statstab);
+ else {
+ str = statname;
+ goto really_filename;
+ }
+ }
+ else {
+ statstab = arg[1].arg_ptr.arg_stab;
+ str_set(statname,"");
+ stio = stab_io(statstab);
+ }
+ if (stio && stio->ifp) {
+#if defined(STDSTDIO) || defined(atarist) /* this will work with atariST */
+ fstat(fileno(stio->ifp),&statcache);
+ if (S_ISDIR(statcache.st_mode)) /* handle NFS glitch */
+ return arg->arg_type == O_FTTEXT ? &str_no : &str_yes;
+ if (stio->ifp->_cnt <= 0) {
+ i = getc(stio->ifp);
+ if (i != EOF)
+ (void)ungetc(i,stio->ifp);
+ }
+ if (stio->ifp->_cnt <= 0) /* null file is anything */
+ return &str_yes;
+ len = stio->ifp->_cnt + (stio->ifp->_ptr - stio->ifp->_base);
+ s = stio->ifp->_base;
+#else
+ fatal("-T and -B not implemented on filehandles");
+#endif
+ }
+ else {
+ if (dowarn)
+ warn("Test on unopened file <%s>",
+ stab_ename(arg[1].arg_ptr.arg_stab));
+ errno = EBADF;
+ return &str_undef;
+ }
+ }
+ else {
+ statstab = Nullstab;
+ str_set(statname,str_get(str));
+ really_filename:
+ i = open(str_get(str),0);
+ if (i < 0) {
+ if (dowarn && index(str_get(str), '\n'))
+ warn(warn_nl, "open");
+ return &str_undef;
+ }
+ fstat(i,&statcache);
+ len = read(i,tbuf,512);
+ (void)close(i);
+ if (len <= 0) {
+ if (S_ISDIR(statcache.st_mode) && arg->arg_type == O_FTTEXT)
+ return &str_no; /* special case NFS directories */
+ return &str_yes; /* null file is anything */
+ }
+ s = tbuf;
+ }
+
+ /* now scan s to look for textiness */
+
+ for (i = 0; i < len; i++,s++) {
+ if (!*s) { /* null never allowed in text */
+ odd += len;
+ break;
+ }
+ else if (*s & 128)
+ odd++;
+ else if (*s < 32 &&
+ *s != '\n' && *s != '\r' && *s != '\b' &&
+ *s != '\t' && *s != '\f' && *s != 27)
+ odd++;
+ }
+
+ if ((odd * 10 > len) == (arg->arg_type == O_FTTEXT)) /* allow 10% odd */
+ return &str_no;
+ else
+ return &str_yes;
+}
+
+static char **Argv = Null(char **);
+static char *Cmd = Nullch;
+
+bool
+do_aexec(really,arglast)
+STR *really;
+int *arglast;
+{
+ register STR **st = stack->ary_array;
+ register int sp = arglast[1];
+ register int items = arglast[2] - sp;
+ register char **a;
+ char *tmps;
+
+ if (items) {
+ New(401,Argv, items+1, char*);
+ a = Argv;
+ for (st += ++sp; items > 0; items--,st++) {
+ if (*st)
+ *a++ = str_get(*st);
+ else
+ *a++ = "";
+ }
+ *a = Nullch;
+#ifdef TAINT
+ if (*Argv[0] != '/') /* will execvp use PATH? */
+ taintenv(); /* testing IFS here is overkill, probably */
+#endif
+ if (really && *(tmps = str_get(really)))
+ execvp(tmps,Argv);
+ else
+ execvp(Argv[0],Argv);
+ }
+ do_execfree();
+ return FALSE;
+}
+
+void
+do_execfree()
+{
+ if (Argv) {
+ Safefree(Argv);
+ Argv = Null(char **);
+ }
+ if (Cmd) {
+ Safefree(Cmd);
+ Cmd = Nullch;
+ }
+}
+
+bool
+do_exec(cmd)
+char *cmd;
+{
+ register char **a;
+ register char *s;
+ char flags[10];
+
+ /* save an extra exec if possible */
+
+#ifdef CSH
+ if (strnEQ(cmd,cshname,cshlen) && strnEQ(cmd+cshlen," -c",3)) {
+ strcpy(flags,"-c");
+ s = cmd+cshlen+3;
+ if (*s == 'f') {
+ s++;
+ strcat(flags,"f");
+ }
+ if (*s == ' ')
+ s++;
+ if (*s++ == '\'') {
+ char *ncmd = s;
+
+ while (*s)
+ s++;
+ if (s[-1] == '\n')
+ *--s = '\0';
+ if (s[-1] == '\'') {
+ *--s = '\0';
+ execl(cshname,"csh", flags,ncmd,(char*)0);
+ *s = '\'';
+ return FALSE;
+ }
+ }
+ }
+#endif /* CSH */
+
+ /* see if there are shell metacharacters in it */
+
+ /*SUPPRESS 530*/
+ for (s = cmd; *s && isALPHA(*s); s++) ; /* catch VAR=val gizmo */
+ if (*s == '=')
+ goto doshell;
+ for (s = cmd; *s; s++) {
+ if (*s != ' ' && !isALPHA(*s) && index("$&*(){}[]'\";\\|?<>~`\n",*s)) {
+ if (*s == '\n' && !s[1]) {
+ *s = '\0';
+ break;
+ }
+ doshell:
+ execl("/bin/sh","sh","-c",cmd,(char*)0);
+ return FALSE;
+ }
+ }
+ New(402,Argv, (s - cmd) / 2 + 2, char*);
+ Cmd = nsavestr(cmd, s-cmd);
+ a = Argv;
+ for (s = Cmd; *s;) {
+ while (*s && isSPACE(*s)) s++;
+ if (*s)
+ *(a++) = s;
+ while (*s && !isSPACE(*s)) s++;
+ if (*s)
+ *s++ = '\0';
+ }
+ *a = Nullch;
+ if (Argv[0]) {
+ execvp(Argv[0],Argv);
+ if (errno == ENOEXEC) { /* for system V NIH syndrome */
+ do_execfree();
+ goto doshell;
+ }
+ }
+ do_execfree();
+ return FALSE;
+}
+
+#ifdef HAS_SOCKET
+int
+do_socket(stab, arglast)
+STAB *stab;
+int *arglast;
+{
+ register STR **st = stack->ary_array;
+ register int sp = arglast[1];
+ register STIO *stio;
+ int domain, type, protocol, fd;
+
+ if (!stab) {
+ errno = EBADF;
+ return FALSE;
+ }
+
+ stio = stab_io(stab);
+ if (!stio)
+ stio = stab_io(stab) = stio_new();
+ else if (stio->ifp)
+ do_close(stab,FALSE);
+
+ domain = (int)str_gnum(st[++sp]);
+ type = (int)str_gnum(st[++sp]);
+ protocol = (int)str_gnum(st[++sp]);
+#ifdef TAINT
+ taintproper("Insecure dependency in socket");
+#endif
+ fd = socket(domain,type,protocol);
+ if (fd < 0)
+ return FALSE;
+ stio->ifp = fdopen(fd, "r"); /* stdio gets confused about sockets */
+ stio->ofp = fdopen(fd, "w");
+ stio->type = 's';
+ if (!stio->ifp || !stio->ofp) {
+ if (stio->ifp) fclose(stio->ifp);
+ if (stio->ofp) fclose(stio->ofp);
+ if (!stio->ifp && !stio->ofp) close(fd);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+int
+do_bind(stab, arglast)
+STAB *stab;
+int *arglast;
+{
+ register STR **st = stack->ary_array;
+ register int sp = arglast[1];
+ register STIO *stio;
+ char *addr;
+
+ if (!stab)
+ goto nuts;
+
+ stio = stab_io(stab);
+ if (!stio || !stio->ifp)
+ goto nuts;
+
+ addr = str_get(st[++sp]);
+#ifdef TAINT
+ taintproper("Insecure dependency in bind");
+#endif
+ return bind(fileno(stio->ifp), (struct sockaddr * ) addr, st[sp]->str_cur) >= 0;
+
+nuts:
+ if (dowarn)
+ warn("bind() on closed fd");
+ errno = EBADF;
+ return FALSE;
+
+}
+
+int
+do_connect(stab, arglast)
+STAB *stab;
+int *arglast;
+{
+ register STR **st = stack->ary_array;
+ register int sp = arglast[1];
+ register STIO *stio;
+ char *addr;
+
+ if (!stab)
+ goto nuts;
+
+ stio = stab_io(stab);
+ if (!stio || !stio->ifp)
+ goto nuts;
+
+ addr = str_get(st[++sp]);
+#ifdef TAINT
+ taintproper("Insecure dependency in connect");
+#endif
+ return connect(fileno(stio->ifp), (struct sockaddr *) addr, st[sp]->str_cur) >= 0;
+
+nuts:
+ if (dowarn)
+ warn("connect() on closed fd");
+ errno = EBADF;
+ return FALSE;
+
+}
+
+int
+do_listen(stab, arglast)
+STAB *stab;
+int *arglast;
+{
+ register STR **st = stack->ary_array;
+ register int sp = arglast[1];
+ register STIO *stio;
+ int backlog;
+
+ if (!stab)
+ goto nuts;
+
+ stio = stab_io(stab);
+ if (!stio || !stio->ifp)
+ goto nuts;
+
+ backlog = (int)str_gnum(st[++sp]);
+ return listen(fileno(stio->ifp), backlog) >= 0;
+
+nuts:
+ if (dowarn)
+ warn("listen() on closed fd");
+ errno = EBADF;
+ return FALSE;
+}
+
+void
+do_accept(str, nstab, gstab)
+STR *str;
+STAB *nstab;
+STAB *gstab;
+{
+ register STIO *nstio;
+ register STIO *gstio;
+ int len = sizeof buf;
+ int fd;
+
+ if (!nstab)
+ goto badexit;
+ if (!gstab)
+ goto nuts;
+
+ gstio = stab_io(gstab);
+ nstio = stab_io(nstab);
+
+ if (!gstio || !gstio->ifp)
+ goto nuts;
+ if (!nstio)
+ nstio = stab_io(nstab) = stio_new();
+ else if (nstio->ifp)
+ do_close(nstab,FALSE);
+
+ fd = accept(fileno(gstio->ifp),(struct sockaddr *)buf,&len);
+ if (fd < 0)
+ goto badexit;
+ nstio->ifp = fdopen(fd, "r");
+ nstio->ofp = fdopen(fd, "w");
+ nstio->type = 's';
+ if (!nstio->ifp || !nstio->ofp) {
+ if (nstio->ifp) fclose(nstio->ifp);
+ if (nstio->ofp) fclose(nstio->ofp);
+ if (!nstio->ifp && !nstio->ofp) close(fd);
+ goto badexit;
+ }
+
+ str_nset(str, buf, len);
+ return;
+
+nuts:
+ if (dowarn)
+ warn("accept() on closed fd");
+ errno = EBADF;
+badexit:
+ str_sset(str,&str_undef);
+ return;
+}
+
+int
+do_shutdown(stab, arglast)
+STAB *stab;
+int *arglast;
+{
+ register STR **st = stack->ary_array;
+ register int sp = arglast[1];
+ register STIO *stio;
+ int how;
+
+ if (!stab)
+ goto nuts;
+
+ stio = stab_io(stab);
+ if (!stio || !stio->ifp)
+ goto nuts;
+
+ how = (int)str_gnum(st[++sp]);
+ return shutdown(fileno(stio->ifp), how) >= 0;
+
+nuts:
+ if (dowarn)
+ warn("shutdown() on closed fd");
+ errno = EBADF;
+ return FALSE;
+
+}
+
+int
+do_sopt(optype, stab, arglast)
+int optype;
+STAB *stab;
+int *arglast;
+{
+ register STR **st = stack->ary_array;
+ register int sp = arglast[1];
+ register STIO *stio;
+ int fd;
+ unsigned int lvl;
+ unsigned int optname;
+
+ if (!stab)
+ goto nuts;
+
+ stio = stab_io(stab);
+ if (!stio || !stio->ifp)
+ goto nuts;
+
+ fd = fileno(stio->ifp);
+ lvl = (unsigned int)str_gnum(st[sp+1]);
+ optname = (unsigned int)str_gnum(st[sp+2]);
+ switch (optype) {
+ case O_GSOCKOPT:
+ st[sp] = str_2mortal(Str_new(22,257));
+ st[sp]->str_cur = 256;
+ st[sp]->str_pok = 1;
+ if (getsockopt(fd, lvl, optname, st[sp]->str_ptr,
+ (int*)&st[sp]->str_cur) < 0)
+ goto nuts;
+ break;
+ case O_SSOCKOPT:
+ st[sp] = st[sp+3];
+ if (setsockopt(fd, lvl, optname, st[sp]->str_ptr, st[sp]->str_cur) < 0)
+ goto nuts;
+ st[sp] = &str_yes;
+ break;
+ }
+
+ return sp;
+
+nuts:
+ if (dowarn)
+ warn("[gs]etsockopt() on closed fd");
+ st[sp] = &str_undef;
+ errno = EBADF;
+ return sp;
+
+}
+
+int
+do_getsockname(optype, stab, arglast)
+int optype;
+STAB *stab;
+int *arglast;
+{
+ register STR **st = stack->ary_array;
+ register int sp = arglast[1];
+ register STIO *stio;
+ int fd;
+
+ if (!stab)
+ goto nuts;
+
+ stio = stab_io(stab);
+ if (!stio || !stio->ifp)
+ goto nuts;
+
+ st[sp] = str_2mortal(Str_new(22,257));
+ st[sp]->str_cur = 256;
+ st[sp]->str_pok = 1;
+ fd = fileno(stio->ifp);
+ switch (optype) {
+ case O_GETSOCKNAME:
+ if (getsockname(fd, (struct sockaddr *) st[sp]->str_ptr, (int*)&st[sp]->str_cur) < 0)
+ goto nuts2;
+ break;
+ case O_GETPEERNAME:
+ if (getpeername(fd, (struct sockaddr *) st[sp]->str_ptr, (int*)&st[sp]->str_cur) < 0)
+ goto nuts2;
+ break;
+ }
+
+ return sp;
+
+nuts:
+ if (dowarn)
+ warn("get{sock,peer}name() on closed fd");
+ errno = EBADF;
+nuts2:
+ st[sp] = &str_undef;
+ return sp;
+
+}
+
+int
+do_ghent(which,gimme,arglast)
+int which;
+int gimme;
+int *arglast;
+{
+ register ARRAY *ary = stack;
+ register int sp = arglast[0];
+ register char **elem;
+ register STR *str;
+ struct hostent *gethostbyname();
+ struct hostent *gethostbyaddr();
+#ifdef HAS_GETHOSTENT
+ struct hostent *gethostent();
+#endif
+ struct hostent *hent;
+ unsigned long len;
+
+ if (which == O_GHBYNAME) {
+ char *name = str_get(ary->ary_array[sp+1]);
+
+ hent = gethostbyname(name);
+ }
+ else if (which == O_GHBYADDR) {
+ STR *addrstr = ary->ary_array[sp+1];
+ int addrtype = (int)str_gnum(ary->ary_array[sp+2]);
+ char *addr = str_get(addrstr);
+
+ hent = gethostbyaddr(addr,addrstr->str_cur,addrtype);
+ }
+ else
+#ifdef HAS_GETHOSTENT
+ hent = gethostent();
+#else
+ fatal("gethostent not implemented");
+#endif
+
+#ifdef HOST_NOT_FOUND
+ if (!hent)
+ statusvalue = (unsigned short)h_errno & 0xffff;
+#endif
+
+ if (gimme != G_ARRAY) {
+ astore(ary, ++sp, str = str_mortal(&str_undef));
+ if (hent) {
+ if (which == O_GHBYNAME) {
+#ifdef h_addr
+ str_nset(str, *hent->h_addr, hent->h_length);
+#else
+ str_nset(str, hent->h_addr, hent->h_length);
+#endif
+ }
+ else
+ str_set(str, hent->h_name);
+ }
+ return sp;
+ }
+
+ if (hent) {
+#ifndef lint
+ (void)astore(ary, ++sp, str = str_mortal(&str_no));
+ str_set(str, hent->h_name);
+ (void)astore(ary, ++sp, str = str_mortal(&str_no));
+ for (elem = hent->h_aliases; *elem; elem++) {
+ str_cat(str, *elem);
+ if (elem[1])
+ str_ncat(str," ",1);
+ }
+ (void)astore(ary, ++sp, str = str_mortal(&str_no));
+ str_numset(str, (double)hent->h_addrtype);
+ (void)astore(ary, ++sp, str = str_mortal(&str_no));
+ len = hent->h_length;
+ str_numset(str, (double)len);
+#ifdef h_addr
+ for (elem = hent->h_addr_list; *elem; elem++) {
+ (void)astore(ary, ++sp, str = str_mortal(&str_no));
+ str_nset(str, *elem, len);
+ }
+#else
+ (void)astore(ary, ++sp, str = str_mortal(&str_no));
+ str_nset(str, hent->h_addr, len);
+#endif /* h_addr */
+#else /* lint */
+ elem = Nullch;
+ elem = elem;
+ (void)astore(ary, ++sp, str_mortal(&str_no));
+#endif /* lint */
+ }
+
+ return sp;
+}
+
+int
+do_gnent(which,gimme,arglast)
+int which;
+int gimme;
+int *arglast;
+{
+ register ARRAY *ary = stack;
+ register int sp = arglast[0];
+ register char **elem;
+ register STR *str;
+ struct netent *getnetbyname();
+ struct netent *getnetbyaddr();
+ struct netent *getnetent();
+ struct netent *nent;
+
+ if (which == O_GNBYNAME) {
+ char *name = str_get(ary->ary_array[sp+1]);
+
+ nent = getnetbyname(name);
+ }
+ else if (which == O_GNBYADDR) {
+ unsigned long addr = U_L(str_gnum(ary->ary_array[sp+1]));
+ int addrtype = (int)str_gnum(ary->ary_array[sp+2]);
+
+ nent = getnetbyaddr((long)addr,addrtype);
+ }
+ else
+ nent = getnetent();
+
+ if (gimme != G_ARRAY) {
+ astore(ary, ++sp, str = str_mortal(&str_undef));
+ if (nent) {
+ if (which == O_GNBYNAME)
+ str_numset(str, (double)nent->n_net);
+ else
+ str_set(str, nent->n_name);
+ }
+ return sp;
+ }
+
+ if (nent) {
+#ifndef lint
+ (void)astore(ary, ++sp, str = str_mortal(&str_no));
+ str_set(str, nent->n_name);
+ (void)astore(ary, ++sp, str = str_mortal(&str_no));
+ for (elem = nent->n_aliases; *elem; elem++) {
+ str_cat(str, *elem);
+ if (elem[1])
+ str_ncat(str," ",1);
+ }
+ (void)astore(ary, ++sp, str = str_mortal(&str_no));
+ str_numset(str, (double)nent->n_addrtype);
+ (void)astore(ary, ++sp, str = str_mortal(&str_no));
+ str_numset(str, (double)nent->n_net);
+#else /* lint */
+ elem = Nullch;
+ elem = elem;
+ (void)astore(ary, ++sp, str_mortal(&str_no));
+#endif /* lint */
+ }
+
+ return sp;
+}
+
+int
+do_gpent(which,gimme,arglast)
+int which;
+int gimme;
+int *arglast;
+{
+ register ARRAY *ary = stack;
+ register int sp = arglast[0];
+ register char **elem;
+ register STR *str;
+ struct protoent *getprotobyname();
+ struct protoent *getprotobynumber();
+ struct protoent *getprotoent();
+ struct protoent *pent;
+
+ if (which == O_GPBYNAME) {
+ char *name = str_get(ary->ary_array[sp+1]);
+
+ pent = getprotobyname(name);
+ }
+ else if (which == O_GPBYNUMBER) {
+ int proto = (int)str_gnum(ary->ary_array[sp+1]);
+
+ pent = getprotobynumber(proto);
+ }
+ else
+ pent = getprotoent();
+
+ if (gimme != G_ARRAY) {
+ astore(ary, ++sp, str = str_mortal(&str_undef));
+ if (pent) {
+ if (which == O_GPBYNAME)
+ str_numset(str, (double)pent->p_proto);
+ else
+ str_set(str, pent->p_name);
+ }
+ return sp;
+ }
+
+ if (pent) {
+#ifndef lint
+ (void)astore(ary, ++sp, str = str_mortal(&str_no));
+ str_set(str, pent->p_name);
+ (void)astore(ary, ++sp, str = str_mortal(&str_no));
+ for (elem = pent->p_aliases; *elem; elem++) {
+ str_cat(str, *elem);
+ if (elem[1])
+ str_ncat(str," ",1);
+ }
+ (void)astore(ary, ++sp, str = str_mortal(&str_no));
+ str_numset(str, (double)pent->p_proto);
+#else /* lint */
+ elem = Nullch;
+ elem = elem;
+ (void)astore(ary, ++sp, str_mortal(&str_no));
+#endif /* lint */
+ }
+
+ return sp;
+}
+
+int
+do_gsent(which,gimme,arglast)
+int which;
+int gimme;
+int *arglast;
+{
+ register ARRAY *ary = stack;
+ register int sp = arglast[0];
+ register char **elem;
+ register STR *str;
+ struct servent *getservbyname();
+ struct servent *getservbynumber();
+ struct servent *getservent();
+ struct servent *sent;
+
+ if (which == O_GSBYNAME) {
+ char *name = str_get(ary->ary_array[sp+1]);
+ char *proto = str_get(ary->ary_array[sp+2]);
+
+ if (proto && !*proto)
+ proto = Nullch;
+
+ sent = getservbyname(name,proto);
+ }
+ else if (which == O_GSBYPORT) {
+ int port = (int)str_gnum(ary->ary_array[sp+1]);
+ char *proto = str_get(ary->ary_array[sp+2]);
+
+ sent = getservbyport(port,proto);
+ }
+ else
+ sent = getservent();
+
+ if (gimme != G_ARRAY) {
+ astore(ary, ++sp, str = str_mortal(&str_undef));
+ if (sent) {
+ if (which == O_GSBYNAME) {
+#ifdef HAS_NTOHS
+ str_numset(str, (double)ntohs(sent->s_port));
+#else
+ str_numset(str, (double)(sent->s_port));
+#endif
+ }
+ else
+ str_set(str, sent->s_name);
+ }
+ return sp;
+ }
+
+ if (sent) {
+#ifndef lint
+ (void)astore(ary, ++sp, str = str_mortal(&str_no));
+ str_set(str, sent->s_name);
+ (void)astore(ary, ++sp, str = str_mortal(&str_no));
+ for (elem = sent->s_aliases; *elem; elem++) {
+ str_cat(str, *elem);
+ if (elem[1])
+ str_ncat(str," ",1);
+ }
+ (void)astore(ary, ++sp, str = str_mortal(&str_no));
+#ifdef HAS_NTOHS
+ str_numset(str, (double)ntohs(sent->s_port));
+#else
+ str_numset(str, (double)(sent->s_port));
+#endif
+ (void)astore(ary, ++sp, str = str_mortal(&str_no));
+ str_set(str, sent->s_proto);
+#else /* lint */
+ elem = Nullch;
+ elem = elem;
+ (void)astore(ary, ++sp, str_mortal(&str_no));
+#endif /* lint */
+ }
+
+ return sp;
+}
+
+#endif /* HAS_SOCKET */
+
+#ifdef HAS_SELECT
+int
+do_select(gimme,arglast)
+int gimme;
+int *arglast;
+{
+ register STR **st = stack->ary_array;
+ register int sp = arglast[0];
+ register int i;
+ register int j;
+ register char *s;
+ register STR *str;
+ double value;
+ int maxlen = 0;
+ int nfound;
+ struct timeval timebuf;
+ struct timeval *tbuf = &timebuf;
+ int growsize;
+#if BYTEORDER != 0x1234 && BYTEORDER != 0x12345678
+ int masksize;
+ int offset;
+ char *fd_sets[4];
+ int k;
+
+#if BYTEORDER & 0xf0000
+#define ORDERBYTE (0x88888888 - BYTEORDER)
+#else
+#define ORDERBYTE (0x4444 - BYTEORDER)
+#endif
+
+#endif
+
+ for (i = 1; i <= 3; i++) {
+ j = st[sp+i]->str_cur;
+ if (maxlen < j)
+ maxlen = j;
+ }
+
+#if BYTEORDER == 0x1234 || BYTEORDER == 0x12345678
+ growsize = maxlen; /* little endians can use vecs directly */
+#else
+#ifdef NFDBITS
+
+#ifndef NBBY
+#define NBBY 8
+#endif
+
+ masksize = NFDBITS / NBBY;
+#else
+ masksize = sizeof(long); /* documented int, everyone seems to use long */
+#endif
+ growsize = maxlen + (masksize - (maxlen % masksize));
+ Zero(&fd_sets[0], 4, char*);
+#endif
+
+ for (i = 1; i <= 3; i++) {
+ str = st[sp+i];
+ j = str->str_len;
+ if (j < growsize) {
+ if (str->str_pok) {
+ Str_Grow(str,growsize);
+ s = str_get(str) + j;
+ while (++j <= growsize) {
+ *s++ = '\0';
+ }
+ }
+ else if (str->str_ptr) {
+ Safefree(str->str_ptr);
+ str->str_ptr = Nullch;
+ }
+ }
+#if BYTEORDER != 0x1234 && BYTEORDER != 0x12345678
+ s = str->str_ptr;
+ if (s) {
+ New(403, fd_sets[i], growsize, char);
+ for (offset = 0; offset < growsize; offset += masksize) {
+ for (j = 0, k=ORDERBYTE; j < masksize; j++, (k >>= 4))
+ fd_sets[i][j+offset] = s[(k % masksize) + offset];
+ }
+ }
+#endif
+ }
+ str = st[sp+4];
+ if (str->str_nok || str->str_pok) {
+ value = str_gnum(str);
+ if (value < 0.0)
+ value = 0.0;
+ timebuf.tv_sec = (long)value;
+ value -= (double)timebuf.tv_sec;
+ timebuf.tv_usec = (long)(value * 1000000.0);
+ }
+ else
+ tbuf = Null(struct timeval*);
+
+#if BYTEORDER == 0x1234 || BYTEORDER == 0x12345678
+ nfound = select(
+ maxlen * 8,
+ (fd_set *) st[sp+1]->str_ptr,
+ (fd_set *) st[sp+2]->str_ptr,
+ (fd_set *) st[sp+3]->str_ptr,
+ tbuf);
+#else
+ nfound = select(
+ maxlen * 8,
+ fd_sets[1],
+ fd_sets[2],
+ fd_sets[3],
+ tbuf);
+ for (i = 1; i <= 3; i++) {
+ if (fd_sets[i]) {
+ str = st[sp+i];
+ s = str->str_ptr;
+ for (offset = 0; offset < growsize; offset += masksize) {
+ for (j = 0, k=ORDERBYTE; j < masksize; j++, (k >>= 4))
+ s[(k % masksize) + offset] = fd_sets[i][j+offset];
+ }
+ Safefree(fd_sets[i]);
+ }
+ }
+#endif
+
+ st[++sp] = str_mortal(&str_no);
+ str_numset(st[sp], (double)nfound);
+ if (gimme == G_ARRAY && tbuf) {
+ value = (double)(timebuf.tv_sec) +
+ (double)(timebuf.tv_usec) / 1000000.0;
+ st[++sp] = str_mortal(&str_no);
+ str_numset(st[sp], value);
+ }
+ return sp;
+}
+#endif /* SELECT */
+
+#ifdef HAS_SOCKET
+int
+do_spair(stab1, stab2, arglast)
+STAB *stab1;
+STAB *stab2;
+int *arglast;
+{
+ register STR **st = stack->ary_array;
+ register int sp = arglast[2];
+ register STIO *stio1;
+ register STIO *stio2;
+ int domain, type, protocol, fd[2];
+
+ if (!stab1 || !stab2)
+ return FALSE;
+
+ stio1 = stab_io(stab1);
+ stio2 = stab_io(stab2);
+ if (!stio1)
+ stio1 = stab_io(stab1) = stio_new();
+ else if (stio1->ifp)
+ do_close(stab1,FALSE);
+ if (!stio2)
+ stio2 = stab_io(stab2) = stio_new();
+ else if (stio2->ifp)
+ do_close(stab2,FALSE);
+
+ domain = (int)str_gnum(st[++sp]);
+ type = (int)str_gnum(st[++sp]);
+ protocol = (int)str_gnum(st[++sp]);
+#ifdef TAINT
+ taintproper("Insecure dependency in socketpair");
+#endif
+#ifdef HAS_SOCKETPAIR
+ if (socketpair(domain,type,protocol,fd) < 0)
+ return FALSE;
+#else
+ fatal("Socketpair unimplemented");
+#endif
+ stio1->ifp = fdopen(fd[0], "r");
+ stio1->ofp = fdopen(fd[0], "w");
+ stio1->type = 's';
+ stio2->ifp = fdopen(fd[1], "r");
+ stio2->ofp = fdopen(fd[1], "w");
+ stio2->type = 's';
+ if (!stio1->ifp || !stio1->ofp || !stio2->ifp || !stio2->ofp) {
+ if (stio1->ifp) fclose(stio1->ifp);
+ if (stio1->ofp) fclose(stio1->ofp);
+ if (!stio1->ifp && !stio1->ofp) close(fd[0]);
+ if (stio2->ifp) fclose(stio2->ifp);
+ if (stio2->ofp) fclose(stio2->ofp);
+ if (!stio2->ifp && !stio2->ofp) close(fd[1]);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+#endif /* HAS_SOCKET */
+
+int
+do_gpwent(which,gimme,arglast)
+int which;
+int gimme;
+int *arglast;
+{
+#ifdef I_PWD
+ register ARRAY *ary = stack;
+ register int sp = arglast[0];
+ register STR *str;
+ struct passwd *getpwnam();
+ struct passwd *getpwuid();
+ struct passwd *getpwent();
+ struct passwd *pwent;
+
+ if (which == O_GPWNAM) {
+ char *name = str_get(ary->ary_array[sp+1]);
+
+ pwent = getpwnam(name);
+ }
+ else if (which == O_GPWUID) {
+ int uid = (int)str_gnum(ary->ary_array[sp+1]);
+
+ pwent = getpwuid(uid);
+ }
+ else
+ pwent = getpwent();
+
+ if (gimme != G_ARRAY) {
+ astore(ary, ++sp, str = str_mortal(&str_undef));
+ if (pwent) {
+ if (which == O_GPWNAM)
+ str_numset(str, (double)pwent->pw_uid);
+ else
+ str_set(str, pwent->pw_name);
+ }
+ return sp;
+ }
+
+ if (pwent) {
+ (void)astore(ary, ++sp, str = str_mortal(&str_no));
+ str_set(str, pwent->pw_name);
+ (void)astore(ary, ++sp, str = str_mortal(&str_no));
+ str_set(str, pwent->pw_passwd);
+ (void)astore(ary, ++sp, str = str_mortal(&str_no));
+ str_numset(str, (double)pwent->pw_uid);
+ (void)astore(ary, ++sp, str = str_mortal(&str_no));
+ str_numset(str, (double)pwent->pw_gid);
+ (void)astore(ary, ++sp, str = str_mortal(&str_no));
+#ifdef PWCHANGE
+ str_numset(str, (double)pwent->pw_change);
+#else
+#ifdef PWQUOTA
+ str_numset(str, (double)pwent->pw_quota);
+#else
+#ifdef PWAGE
+ str_set(str, pwent->pw_age);
+#endif
+#endif
+#endif
+ (void)astore(ary, ++sp, str = str_mortal(&str_no));
+#ifdef PWCLASS
+ str_set(str,pwent->pw_class);
+#else
+#ifdef PWCOMMENT
+ str_set(str, pwent->pw_comment);
+#endif
+#endif
+ (void)astore(ary, ++sp, str = str_mortal(&str_no));
+ str_set(str, pwent->pw_gecos);
+ (void)astore(ary, ++sp, str = str_mortal(&str_no));
+ str_set(str, pwent->pw_dir);
+ (void)astore(ary, ++sp, str = str_mortal(&str_no));
+ str_set(str, pwent->pw_shell);
+#ifdef PWEXPIRE
+ (void)astore(ary, ++sp, str = str_mortal(&str_no));
+ str_numset(str, (double)pwent->pw_expire);
+#endif
+ }
+
+ return sp;
+#else
+ fatal("password routines not implemented");
+#endif
+}
+
+int
+do_ggrent(which,gimme,arglast)
+int which;
+int gimme;
+int *arglast;
+{
+#ifdef I_GRP
+ register ARRAY *ary = stack;
+ register int sp = arglast[0];
+ register char **elem;
+ register STR *str;
+ struct group *getgrnam();
+ struct group *getgrgid();
+ struct group *getgrent();
+ struct group *grent;
+
+ if (which == O_GGRNAM) {
+ char *name = str_get(ary->ary_array[sp+1]);
+
+ grent = getgrnam(name);
+ }
+ else if (which == O_GGRGID) {
+ int gid = (int)str_gnum(ary->ary_array[sp+1]);
+
+ grent = getgrgid(gid);
+ }
+ else
+ grent = getgrent();
+
+ if (gimme != G_ARRAY) {
+ astore(ary, ++sp, str = str_mortal(&str_undef));
+ if (grent) {
+ if (which == O_GGRNAM)
+ str_numset(str, (double)grent->gr_gid);
+ else
+ str_set(str, grent->gr_name);
+ }
+ return sp;
+ }
+
+ if (grent) {
+ (void)astore(ary, ++sp, str = str_mortal(&str_no));
+ str_set(str, grent->gr_name);
+ (void)astore(ary, ++sp, str = str_mortal(&str_no));
+ str_set(str, grent->gr_passwd);
+ (void)astore(ary, ++sp, str = str_mortal(&str_no));
+ str_numset(str, (double)grent->gr_gid);
+ (void)astore(ary, ++sp, str = str_mortal(&str_no));
+ for (elem = grent->gr_mem; *elem; elem++) {
+ str_cat(str, *elem);
+ if (elem[1])
+ str_ncat(str," ",1);
+ }
+ }
+
+ return sp;
+#else
+ fatal("group routines not implemented");
+#endif
+}
+
+int
+do_dirop(optype,stab,gimme,arglast)
+int optype;
+STAB *stab;
+int gimme;
+int *arglast;
+{
+#if defined(DIRENT) && defined(HAS_READDIR)
+ register ARRAY *ary = stack;
+ register STR **st = ary->ary_array;
+ register int sp = arglast[1];
+ register STIO *stio;
+ long along;
+#ifndef apollo
+ struct DIRENT *readdir();
+#endif
+ register struct DIRENT *dp;
+
+ if (!stab)
+ goto nope;
+ if (!(stio = stab_io(stab)))
+ stio = stab_io(stab) = stio_new();
+ if (!stio->dirp && optype != O_OPEN_DIR)
+ goto nope;
+ st[sp] = &str_yes;
+ switch (optype) {
+ case O_OPEN_DIR:
+ if (stio->dirp)
+ closedir(stio->dirp);
+ if (!(stio->dirp = opendir(str_get(st[sp+1]))))
+ goto nope;
+ break;
+ case O_READDIR:
+ if (gimme == G_ARRAY) {
+ --sp;
+ /*SUPPRESS 560*/
+ while (dp = readdir(stio->dirp)) {
+#ifdef DIRNAMLEN
+ (void)astore(ary,++sp,
+ str_2mortal(str_make(dp->d_name,dp->d_namlen)));
+#else
+ (void)astore(ary,++sp,
+ str_2mortal(str_make(dp->d_name,0)));
+#endif
+ }
+ }
+ else {
+ if (!(dp = readdir(stio->dirp)))
+ goto nope;
+ st[sp] = str_mortal(&str_undef);
+#ifdef DIRNAMLEN
+ str_nset(st[sp], dp->d_name, dp->d_namlen);
+#else
+ str_set(st[sp], dp->d_name);
+#endif
+ }
+ break;
+#if defined(HAS_TELLDIR) || defined(telldir)
+ case O_TELLDIR: {
+#ifndef telldir
+ long telldir();
+#endif
+ st[sp] = str_mortal(&str_undef);
+ str_numset(st[sp], (double)telldir(stio->dirp));
+ break;
+ }
+#endif
+#if defined(HAS_SEEKDIR) || defined(seekdir)
+ case O_SEEKDIR:
+ st[sp] = str_mortal(&str_undef);
+ along = (long)str_gnum(st[sp+1]);
+ (void)seekdir(stio->dirp,along);
+ break;
+#endif
+#if defined(HAS_REWINDDIR) || defined(rewinddir)
+ case O_REWINDDIR:
+ st[sp] = str_mortal(&str_undef);
+ (void)rewinddir(stio->dirp);
+ break;
+#endif
+ case O_CLOSEDIR:
+ st[sp] = str_mortal(&str_undef);
+ (void)closedir(stio->dirp);
+ stio->dirp = 0;
+ break;
+ default:
+ goto phooey;
+ }
+ return sp;
+
+nope:
+ st[sp] = &str_undef;
+ if (!errno)
+ errno = EBADF;
+ return sp;
+
+#endif
+phooey:
+ fatal("Unimplemented directory operation");
+}
+
+int
+apply(type,arglast)
+int type;
+int *arglast;
+{
+ register STR **st = stack->ary_array;
+ register int sp = arglast[1];
+ register int items = arglast[2] - sp;
+ register int val;
+ register int val2;
+ register int tot = 0;
+ char *s;
+
+#ifdef TAINT
+ for (st += ++sp; items--; st++)
+ tainted |= (*st)->str_tainted;
+ st = stack->ary_array;
+ sp = arglast[1];
+ items = arglast[2] - sp;
+#endif
+ switch (type) {
+ case O_CHMOD:
+#ifdef TAINT
+ taintproper("Insecure dependency in chmod");
+#endif
+ if (--items > 0) {
+ tot = items;
+ val = (int)str_gnum(st[++sp]);
+ while (items--) {
+ if (chmod(str_get(st[++sp]),val))
+ tot--;
+ }
+ }
+ break;
+#ifdef HAS_CHOWN
+ case O_CHOWN:
+#ifdef TAINT
+ taintproper("Insecure dependency in chown");
+#endif
+ if (items > 2) {
+ items -= 2;
+ tot = items;
+ val = (int)str_gnum(st[++sp]);
+ val2 = (int)str_gnum(st[++sp]);
+ while (items--) {
+ if (chown(str_get(st[++sp]),val,val2))
+ tot--;
+ }
+ }
+ break;
+#endif
+#ifdef HAS_KILL
+ case O_KILL:
+#ifdef TAINT
+ taintproper("Insecure dependency in kill");
+#endif
+ if (--items > 0) {
+ tot = items;
+ s = str_get(st[++sp]);
+ if (isUPPER(*s)) {
+ if (*s == 'S' && s[1] == 'I' && s[2] == 'G')
+ s += 3;
+ if (!(val = whichsig(s)))
+ fatal("Unrecognized signal name \"%s\"",s);
+ }
+ else
+ val = (int)str_gnum(st[sp]);
+ if (val < 0) {
+ val = -val;
+ while (items--) {
+ int proc = (int)str_gnum(st[++sp]);
+#ifdef HAS_KILLPG
+ if (killpg(proc,val)) /* BSD */
+#else
+ if (kill(-proc,val)) /* SYSV */
+#endif
+ tot--;
+ }
+ }
+ else {
+ while (items--) {
+ if (kill((int)(str_gnum(st[++sp])),val))
+ tot--;
+ }
+ }
+ }
+ break;
+#endif
+ case O_UNLINK:
+#ifdef TAINT
+ taintproper("Insecure dependency in unlink");
+#endif
+ tot = items;
+ while (items--) {
+ s = str_get(st[++sp]);
+ if (euid || unsafe) {
+ if (UNLINK(s))
+ tot--;
+ }
+ else { /* don't let root wipe out directories without -U */
+#ifdef HAS_LSTAT
+ if (lstat(s,&statbuf) < 0 || S_ISDIR(statbuf.st_mode))
+#else
+ if (stat(s,&statbuf) < 0 || S_ISDIR(statbuf.st_mode))
+#endif
+ tot--;
+ else {
+ if (UNLINK(s))
+ tot--;
+ }
+ }
+ }
+ break;
+ case O_UTIME:
+#ifdef TAINT
+ taintproper("Insecure dependency in utime");
+#endif
+ if (items > 2) {
+#ifdef I_UTIME
+ struct utimbuf utbuf;
+#else
+ struct {
+ long actime;
+ long modtime;
+ } utbuf;
+#endif
+
+ Zero(&utbuf, sizeof utbuf, char);
+ utbuf.actime = (long)str_gnum(st[++sp]); /* time accessed */
+ utbuf.modtime = (long)str_gnum(st[++sp]); /* time modified */
+ items -= 2;
+#ifndef lint
+ tot = items;
+ while (items--) {
+ if (utime(str_get(st[++sp]),&utbuf))
+ tot--;
+ }
+#endif
+ }
+ else
+ items = 0;
+ break;
+ }
+ return tot;
+}
+
+/* Do the permissions allow some operation? Assumes statcache already set. */
+
+int
+cando(bit, effective, statbufp)
+int bit;
+int effective;
+register struct stat *statbufp;
+{
+#ifdef DOSISH
+ /* [Comments and code from Len Reed]
+ * MS-DOS "user" is similar to UNIX's "superuser," but can't write
+ * to write-protected files. The execute permission bit is set
+ * by the Miscrosoft C library stat() function for the following:
+ * .exe files
+ * .com files
+ * .bat files
+ * directories
+ * All files and directories are readable.
+ * Directories and special files, e.g. "CON", cannot be
+ * write-protected.
+ * [Comment by Tom Dinger -- a directory can have the write-protect
+ * bit set in the file system, but DOS permits changes to
+ * the directory anyway. In addition, all bets are off
+ * here for networked software, such as Novell and
+ * Sun's PC-NFS.]
+ */
+
+ /* Atari stat() does pretty much the same thing. we set x_bit_set_in_stat
+ * too so it will actually look into the files for magic numbers
+ */
+ return (bit & statbufp->st_mode) ? TRUE : FALSE;
+
+#else /* ! MSDOS */
+ if ((effective ? euid : uid) == 0) { /* root is special */
+ if (bit == S_IXUSR) {
+ if (statbufp->st_mode & 0111 || S_ISDIR(statbufp->st_mode))
+ return TRUE;
+ }
+ else
+ return TRUE; /* root reads and writes anything */
+ return FALSE;
+ }
+ if (statbufp->st_uid == (effective ? euid : uid) ) {
+ if (statbufp->st_mode & bit)
+ return TRUE; /* ok as "user" */
+ }
+ else if (ingroup((int)statbufp->st_gid,effective)) {
+ if (statbufp->st_mode & bit >> 3)
+ return TRUE; /* ok as "group" */
+ }
+ else if (statbufp->st_mode & bit >> 6)
+ return TRUE; /* ok as "other" */
+ return FALSE;
+#endif /* ! MSDOS */
+}
+
+int
+ingroup(testgid,effective)
+int testgid;
+int effective;
+{
+ if (testgid == (effective ? egid : gid))
+ return TRUE;
+#ifdef HAS_GETGROUPS
+#ifndef NGROUPS
+#define NGROUPS 32
+#endif
+ {
+ GROUPSTYPE gary[NGROUPS];
+ int anum;
+
+ anum = getgroups(NGROUPS,gary);
+ while (--anum >= 0)
+ if (gary[anum] == testgid)
+ return TRUE;
+ }
+#endif
+ return FALSE;
+}
+
+#if defined(HAS_MSG) || defined(HAS_SEM) || defined(HAS_SHM)
+
+int
+do_ipcget(optype, arglast)
+int optype;
+int *arglast;
+{
+ register STR **st = stack->ary_array;
+ register int sp = arglast[0];
+ key_t key;
+ int n, flags;
+
+ key = (key_t)str_gnum(st[++sp]);
+ n = (optype == O_MSGGET) ? 0 : (int)str_gnum(st[++sp]);
+ flags = (int)str_gnum(st[++sp]);
+ errno = 0;
+ switch (optype)
+ {
+#ifdef HAS_MSG
+ case O_MSGGET:
+ return msgget(key, flags);
+#endif
+#ifdef HAS_SEM
+ case O_SEMGET:
+ return semget(key, n, flags);
+#endif
+#ifdef HAS_SHM
+ case O_SHMGET:
+ return shmget(key, n, flags);
+#endif
+#if !defined(HAS_MSG) || !defined(HAS_SEM) || !defined(HAS_SHM)
+ default:
+ fatal("%s not implemented", opname[optype]);
+#endif
+ }
+ return -1; /* should never happen */
+}
+
+int
+do_ipcctl(optype, arglast)
+int optype;
+int *arglast;
+{
+ register STR **st = stack->ary_array;
+ register int sp = arglast[0];
+ STR *astr;
+ char *a;
+ int id, n, cmd, infosize, getinfo, ret;
+
+ id = (int)str_gnum(st[++sp]);
+ n = (optype == O_SEMCTL) ? (int)str_gnum(st[++sp]) : 0;
+ cmd = (int)str_gnum(st[++sp]);
+ astr = st[++sp];
+
+ infosize = 0;
+ getinfo = (cmd == IPC_STAT);
+
+ switch (optype)
+ {
+#ifdef HAS_MSG
+ case O_MSGCTL:
+ if (cmd == IPC_STAT || cmd == IPC_SET)
+ infosize = sizeof(struct msqid_ds);
+ break;
+#endif
+#ifdef HAS_SHM
+ case O_SHMCTL:
+ if (cmd == IPC_STAT || cmd == IPC_SET)
+ infosize = sizeof(struct shmid_ds);
+ break;
+#endif
+#ifdef HAS_SEM
+ case O_SEMCTL:
+ if (cmd == IPC_STAT || cmd == IPC_SET)
+ infosize = sizeof(struct semid_ds);
+ else if (cmd == GETALL || cmd == SETALL)
+ {
+ struct semid_ds semds;
+ if (semctl(id, 0, IPC_STAT, (union semun)&semds) == -1)
+ return -1;
+ getinfo = (cmd == GETALL);
+ infosize = semds.sem_nsems * sizeof(short);
+ /* "short" is technically wrong but much more portable
+ than guessing about u_?short(_t)? */
+ }
+ break;
+#endif
+#if !defined(HAS_MSG) || !defined(HAS_SEM) || !defined(HAS_SHM)
+ default:
+ fatal("%s not implemented", opname[optype]);
+#endif
+ }
+
+ if (infosize)
+ {
+ if (getinfo)
+ {
+ STR_GROW(astr, infosize+1);
+ a = str_get(astr);
+ }
+ else
+ {
+ a = str_get(astr);
+ if (astr->str_cur != infosize)
+ {
+ errno = EINVAL;
+ return -1;
+ }
+ }
+ }
+ else
+ {
+ int i = (int)str_gnum(astr);
+ a = (char *)i; /* ouch */
+ }
+ errno = 0;
+ switch (optype)
+ {
+#ifdef HAS_MSG
+ case O_MSGCTL:
+ ret = msgctl(id, cmd, (struct msqid_ds *)a);
+ break;
+#endif
+#ifdef HAS_SEM
+ case O_SEMCTL:
+ ret = semctl(id, n, cmd, (union semun)((int)a));
+ break;
+#endif
+#ifdef HAS_SHM
+ case O_SHMCTL:
+ ret = shmctl(id, cmd, (struct shmid_ds *)a);
+ break;
+#endif
+ }
+ if (getinfo && ret >= 0) {
+ astr->str_cur = infosize;
+ astr->str_ptr[infosize] = '\0';
+ }
+ return ret;
+}
+
+int
+do_msgsnd(arglast)
+int *arglast;
+{
+#ifdef HAS_MSG
+ register STR **st = stack->ary_array;
+ register int sp = arglast[0];
+ STR *mstr;
+ char *mbuf;
+ int id, msize, flags;
+
+ id = (int)str_gnum(st[++sp]);
+ mstr = st[++sp];
+ flags = (int)str_gnum(st[++sp]);
+ mbuf = str_get(mstr);
+ if ((msize = mstr->str_cur - sizeof(long)) < 0) {
+ errno = EINVAL;
+ return -1;
+ }
+ errno = 0;
+ return msgsnd(id, (struct msgbuf *)mbuf, msize, flags);
+#else
+ fatal("msgsnd not implemented");
+#endif
+}
+
+int
+do_msgrcv(arglast)
+int *arglast;
+{
+#ifdef HAS_MSG
+ register STR **st = stack->ary_array;
+ register int sp = arglast[0];
+ STR *mstr;
+ char *mbuf;
+ long mtype;
+ int id, msize, flags, ret;
+
+ id = (int)str_gnum(st[++sp]);
+ mstr = st[++sp];
+ msize = (int)str_gnum(st[++sp]);
+ mtype = (long)str_gnum(st[++sp]);
+ flags = (int)str_gnum(st[++sp]);
+ mbuf = str_get(mstr);
+ if (mstr->str_cur < sizeof(long)+msize+1) {
+ STR_GROW(mstr, sizeof(long)+msize+1);
+ mbuf = str_get(mstr);
+ }
+ errno = 0;
+ ret = msgrcv(id, (struct msgbuf *)mbuf, msize, mtype, flags);
+ if (ret >= 0) {
+ mstr->str_cur = sizeof(long)+ret;
+ mstr->str_ptr[sizeof(long)+ret] = '\0';
+ }
+ return ret;
+#else
+ fatal("msgrcv not implemented");
+#endif
+}
+
+int
+do_semop(arglast)
+int *arglast;
+{
+#ifdef HAS_SEM
+ register STR **st = stack->ary_array;
+ register int sp = arglast[0];
+ STR *opstr;
+ char *opbuf;
+ int id, opsize;
+
+ id = (int)str_gnum(st[++sp]);
+ opstr = st[++sp];
+ opbuf = str_get(opstr);
+ opsize = opstr->str_cur;
+ if (opsize < sizeof(struct sembuf)
+ || (opsize % sizeof(struct sembuf)) != 0) {
+ errno = EINVAL;
+ return -1;
+ }
+ errno = 0;
+ return semop(id, (struct sembuf *)opbuf, opsize/sizeof(struct sembuf));
+#else
+ fatal("semop not implemented");
+#endif
+}
+
+int
+do_shmio(optype, arglast)
+int optype;
+int *arglast;
+{
+#ifdef HAS_SHM
+ register STR **st = stack->ary_array;
+ register int sp = arglast[0];
+ STR *mstr;
+ char *mbuf, *shm;
+ int id, mpos, msize;
+ struct shmid_ds shmds;
+#ifndef VOIDSHMAT
+ extern char *shmat();
+#endif
+
+ id = (int)str_gnum(st[++sp]);
+ mstr = st[++sp];
+ mpos = (int)str_gnum(st[++sp]);
+ msize = (int)str_gnum(st[++sp]);
+ errno = 0;
+ if (shmctl(id, IPC_STAT, &shmds) == -1)
+ return -1;
+ if (mpos < 0 || msize < 0 || mpos + msize > shmds.shm_segsz) {
+ errno = EFAULT; /* can't do as caller requested */
+ return -1;
+ }
+ shm = (char*)shmat(id, (char*)NULL, (optype == O_SHMREAD) ? SHM_RDONLY : 0);
+ if (shm == (char *)-1) /* I hate System V IPC, I really do */
+ return -1;
+ mbuf = str_get(mstr);
+ if (optype == O_SHMREAD) {
+ if (mstr->str_cur < msize) {
+ STR_GROW(mstr, msize+1);
+ mbuf = str_get(mstr);
+ }
+ Copy(shm + mpos, mbuf, msize, char);
+ mstr->str_cur = msize;
+ mstr->str_ptr[msize] = '\0';
+ }
+ else {
+ int n;
+
+ if ((n = mstr->str_cur) > msize)
+ n = msize;
+ Copy(mbuf, shm + mpos, n, char);
+ if (n < msize)
+ memzero(shm + mpos + n, msize - n);
+ }
+ return shmdt(shm);
+#else
+ fatal("shm I/O not implemented");
+#endif
+}
+
+#endif /* SYSV IPC */
diff --git a/gnu/usr.bin/perl/perl/dolist.c b/gnu/usr.bin/perl/perl/dolist.c
new file mode 100644
index 0000000..448a260
--- /dev/null
+++ b/gnu/usr.bin/perl/perl/dolist.c
@@ -0,0 +1,1976 @@
+/* $RCSfile: dolist.c,v $$Revision: 1.1.1.1 $$Date: 1994/09/10 06:27:32 $
+ *
+ * Copyright (c) 1991, Larry Wall
+ *
+ * You may distribute under the terms of either the GNU General Public
+ * License or the Artistic License, as specified in the README file.
+ *
+ * $Log: dolist.c,v $
+ * Revision 1.1.1.1 1994/09/10 06:27:32 gclarkii
+ * Initial import of Perl 4.046 bmaked
+ *
+ * Revision 1.1.1.1 1993/08/23 21:29:36 nate
+ * PERL!
+ *
+ * Revision 4.0.1.5 92/06/08 13:13:27 lwall
+ * patch20: g pattern modifer sometimes returned extra values
+ * patch20: m/$pattern/g didn't work
+ * patch20: pattern modifiers i and o didn't interact right
+ * patch20: @ in unpack failed too often
+ * patch20: Perl now distinguishes overlapped copies from non-overlapped
+ * patch20: slice on null list in scalar context returned random value
+ * patch20: splice with negative offset didn't work with $[ = 1
+ * patch20: fixed some memory leaks in splice
+ * patch20: scalar keys %array now counts keys for you
+ *
+ * Revision 4.0.1.4 91/11/11 16:33:19 lwall
+ * patch19: added little-endian pack/unpack options
+ * patch19: sort $subname was busted by changes in 4.018
+ *
+ * Revision 4.0.1.3 91/11/05 17:07:02 lwall
+ * patch11: prepared for ctype implementations that don't define isascii()
+ * patch11: /$foo/o optimizer could access deallocated data
+ * patch11: certain optimizations of //g in array context returned too many values
+ * patch11: regexp with no parens in array context returned wacky $`, $& and $'
+ * patch11: $' not set right on some //g
+ * patch11: added some support for 64-bit integers
+ * patch11: grep of a split lost its values
+ * patch11: added sort {} LIST
+ * patch11: multiple reallocations now avoided in 1 .. 100000
+ *
+ * Revision 4.0.1.2 91/06/10 01:22:15 lwall
+ * patch10: //g only worked first time through
+ *
+ * Revision 4.0.1.1 91/06/07 10:58:28 lwall
+ * patch4: new copyright notice
+ * patch4: added global modifier for pattern matches
+ * patch4: // wouldn't use previous pattern if it started with a null character
+ * patch4: //o and s///o now optimize themselves fully at runtime
+ * patch4: $` was busted inside s///
+ * patch4: caller($arg) didn't work except under debugger
+ *
+ * Revision 4.0 91/03/20 01:08:03 lwall
+ * 4.0 baseline.
+ *
+ */
+
+#include "EXTERN.h"
+#include "perl.h"
+
+static int sortcmp();
+static int sortsub();
+
+#ifdef BUGGY_MSC
+ #pragma function(memcmp)
+#endif /* BUGGY_MSC */
+
+int
+do_match(str,arg,gimme,arglast)
+STR *str;
+register ARG *arg;
+int gimme;
+int *arglast;
+{
+ register STR **st = stack->ary_array;
+ register SPAT *spat = arg[2].arg_ptr.arg_spat;
+ register char *t;
+ register int sp = arglast[0] + 1;
+ STR *srchstr = st[sp];
+ register char *s = str_get(st[sp]);
+ char *strend = s + st[sp]->str_cur;
+ STR *tmpstr;
+ char *myhint = hint;
+ int global;
+ int safebase;
+ char *truebase = s;
+ register REGEXP *rx = spat->spat_regexp;
+
+ hint = Nullch;
+ if (!spat) {
+ if (gimme == G_ARRAY)
+ return --sp;
+ str_set(str,Yes);
+ STABSET(str);
+ st[sp] = str;
+ return sp;
+ }
+ global = spat->spat_flags & SPAT_GLOBAL;
+ safebase = (gimme == G_ARRAY) || global;
+ if (!s)
+ fatal("panic: do_match");
+ if (spat->spat_flags & SPAT_USED) {
+#ifdef DEBUGGING
+ if (debug & 8)
+ deb("2.SPAT USED\n");
+#endif
+ if (gimme == G_ARRAY)
+ return --sp;
+ str_set(str,No);
+ STABSET(str);
+ st[sp] = str;
+ return sp;
+ }
+ --sp;
+ if (spat->spat_runtime) {
+ nointrp = "|)";
+ sp = eval(spat->spat_runtime,G_SCALAR,sp);
+ st = stack->ary_array;
+ t = str_get(tmpstr = st[sp--]);
+ nointrp = "";
+#ifdef DEBUGGING
+ if (debug & 8)
+ deb("2.SPAT /%s/\n",t);
+#endif
+ if (!global && rx)
+ regfree(rx);
+ spat->spat_regexp = Null(REGEXP*); /* crucial if regcomp aborts */
+ spat->spat_regexp = regcomp(t,t+tmpstr->str_cur,
+ spat->spat_flags & SPAT_FOLD);
+ if (!spat->spat_regexp->prelen && lastspat)
+ spat = lastspat;
+ if (spat->spat_flags & SPAT_KEEP) {
+ if (!(spat->spat_flags & SPAT_FOLD))
+ scanconst(spat,spat->spat_regexp->precomp,
+ spat->spat_regexp->prelen);
+ if (spat->spat_runtime)
+ arg_free(spat->spat_runtime); /* it won't change, so */
+ spat->spat_runtime = Nullarg; /* no point compiling again */
+ hoistmust(spat);
+ if (curcmd->c_expr && (curcmd->c_flags & CF_OPTIMIZE) == CFT_EVAL) {
+ curcmd->c_flags &= ~CF_OPTIMIZE;
+ opt_arg(curcmd, 1, curcmd->c_type == C_EXPR);
+ }
+ }
+ if (global) {
+ if (rx) {
+ if (rx->startp[0]) {
+ s = rx->endp[0];
+ if (s == rx->startp[0])
+ s++;
+ if (s > strend) {
+ regfree(rx);
+ rx = spat->spat_regexp;
+ goto nope;
+ }
+ }
+ regfree(rx);
+ }
+ }
+ else if (!spat->spat_regexp->nparens)
+ gimme = G_SCALAR; /* accidental array context? */
+ rx = spat->spat_regexp;
+ if (regexec(rx, s, strend, s, 0,
+ srchstr->str_pok & SP_STUDIED ? srchstr : Nullstr,
+ safebase)) {
+ if (rx->subbase || global)
+ curspat = spat;
+ lastspat = spat;
+ goto gotcha;
+ }
+ else {
+ if (gimme == G_ARRAY)
+ return sp;
+ str_sset(str,&str_no);
+ STABSET(str);
+ st[++sp] = str;
+ return sp;
+ }
+ }
+ else {
+#ifdef DEBUGGING
+ if (debug & 8) {
+ char ch;
+
+ if (spat->spat_flags & SPAT_ONCE)
+ ch = '?';
+ else
+ ch = '/';
+ deb("2.SPAT %c%s%c\n",ch,rx->precomp,ch);
+ }
+#endif
+ if (!rx->prelen && lastspat) {
+ spat = lastspat;
+ rx = spat->spat_regexp;
+ }
+ t = s;
+ play_it_again:
+ if (global && rx->startp[0]) {
+ t = s = rx->endp[0];
+ if (s == rx->startp[0])
+ s++,t++;
+ if (s > strend)
+ goto nope;
+ }
+ if (myhint) {
+ if (myhint < s || myhint > strend)
+ fatal("panic: hint in do_match");
+ s = myhint;
+ if (rx->regback >= 0) {
+ s -= rx->regback;
+ if (s < t)
+ s = t;
+ }
+ else
+ s = t;
+ }
+ else if (spat->spat_short) {
+ if (spat->spat_flags & SPAT_SCANFIRST) {
+ if (srchstr->str_pok & SP_STUDIED) {
+ if (screamfirst[spat->spat_short->str_rare] < 0)
+ goto nope;
+ else if (!(s = screaminstr(srchstr,spat->spat_short)))
+ goto nope;
+ else if (spat->spat_flags & SPAT_ALL)
+ goto yup;
+ }
+#ifndef lint
+ else if (!(s = fbminstr((unsigned char*)s,
+ (unsigned char*)strend, spat->spat_short)))
+ goto nope;
+#endif
+ else if (spat->spat_flags & SPAT_ALL)
+ goto yup;
+ if (s && rx->regback >= 0) {
+ ++spat->spat_short->str_u.str_useful;
+ s -= rx->regback;
+ if (s < t)
+ s = t;
+ }
+ else
+ s = t;
+ }
+ else if (!multiline && (*spat->spat_short->str_ptr != *s ||
+ bcmp(spat->spat_short->str_ptr, s, spat->spat_slen) ))
+ goto nope;
+ if (--spat->spat_short->str_u.str_useful < 0) {
+ str_free(spat->spat_short);
+ spat->spat_short = Nullstr; /* opt is being useless */
+ }
+ }
+ if (!rx->nparens && !global) {
+ gimme = G_SCALAR; /* accidental array context? */
+ safebase = FALSE;
+ }
+ if (regexec(rx, s, strend, truebase, 0,
+ srchstr->str_pok & SP_STUDIED ? srchstr : Nullstr,
+ safebase)) {
+ if (rx->subbase || global)
+ curspat = spat;
+ lastspat = spat;
+ if (spat->spat_flags & SPAT_ONCE)
+ spat->spat_flags |= SPAT_USED;
+ goto gotcha;
+ }
+ else {
+ if (global)
+ rx->startp[0] = Nullch;
+ if (gimme == G_ARRAY)
+ return sp;
+ str_sset(str,&str_no);
+ STABSET(str);
+ st[++sp] = str;
+ return sp;
+ }
+ }
+ /*NOTREACHED*/
+
+ gotcha:
+ if (gimme == G_ARRAY) {
+ int iters, i, len;
+
+ iters = rx->nparens;
+ if (global && !iters)
+ i = 1;
+ else
+ i = 0;
+ if (sp + iters + i >= stack->ary_max) {
+ astore(stack,sp + iters + i, Nullstr);
+ st = stack->ary_array; /* possibly realloced */
+ }
+
+ for (i = !i; i <= iters; i++) {
+ st[++sp] = str_mortal(&str_no);
+ /*SUPPRESS 560*/
+ if (s = rx->startp[i]) {
+ len = rx->endp[i] - s;
+ if (len > 0)
+ str_nset(st[sp],s,len);
+ }
+ }
+ if (global) {
+ truebase = rx->subbeg;
+ goto play_it_again;
+ }
+ return sp;
+ }
+ else {
+ str_sset(str,&str_yes);
+ STABSET(str);
+ st[++sp] = str;
+ return sp;
+ }
+
+yup:
+ ++spat->spat_short->str_u.str_useful;
+ lastspat = spat;
+ if (spat->spat_flags & SPAT_ONCE)
+ spat->spat_flags |= SPAT_USED;
+ if (global) {
+ rx->subbeg = t;
+ rx->subend = strend;
+ rx->startp[0] = s;
+ rx->endp[0] = s + spat->spat_short->str_cur;
+ curspat = spat;
+ goto gotcha;
+ }
+ if (sawampersand) {
+ char *tmps;
+
+ if (rx->subbase)
+ Safefree(rx->subbase);
+ tmps = rx->subbase = nsavestr(t,strend-t);
+ rx->subbeg = tmps;
+ rx->subend = tmps + (strend-t);
+ tmps = rx->startp[0] = tmps + (s - t);
+ rx->endp[0] = tmps + spat->spat_short->str_cur;
+ curspat = spat;
+ }
+ str_sset(str,&str_yes);
+ STABSET(str);
+ st[++sp] = str;
+ return sp;
+
+nope:
+ rx->startp[0] = Nullch;
+ if (spat->spat_short)
+ ++spat->spat_short->str_u.str_useful;
+ if (gimme == G_ARRAY)
+ return sp;
+ str_sset(str,&str_no);
+ STABSET(str);
+ st[++sp] = str;
+ return sp;
+}
+
+#ifdef BUGGY_MSC
+ #pragma intrinsic(memcmp)
+#endif /* BUGGY_MSC */
+
+int
+do_split(str,spat,limit,gimme,arglast)
+STR *str;
+register SPAT *spat;
+register int limit;
+int gimme;
+int *arglast;
+{
+ register ARRAY *ary = stack;
+ STR **st = ary->ary_array;
+ register int sp = arglast[0] + 1;
+ register char *s = str_get(st[sp]);
+ char *strend = s + st[sp--]->str_cur;
+ register STR *dstr;
+ register char *m;
+ int iters = 0;
+ int maxiters = (strend - s) + 10;
+ int i;
+ char *orig;
+ int origlimit = limit;
+ int realarray = 0;
+
+ if (!spat || !s)
+ fatal("panic: do_split");
+ else if (spat->spat_runtime) {
+ nointrp = "|)";
+ sp = eval(spat->spat_runtime,G_SCALAR,sp);
+ st = stack->ary_array;
+ m = str_get(dstr = st[sp--]);
+ nointrp = "";
+ if (*m == ' ' && dstr->str_cur == 1) {
+ str_set(dstr,"\\s+");
+ m = dstr->str_ptr;
+ spat->spat_flags |= SPAT_SKIPWHITE;
+ }
+ if (spat->spat_regexp) {
+ regfree(spat->spat_regexp);
+ spat->spat_regexp = Null(REGEXP*); /* avoid possible double free */
+ }
+ spat->spat_regexp = regcomp(m,m+dstr->str_cur,
+ spat->spat_flags & SPAT_FOLD);
+ if (spat->spat_flags & SPAT_KEEP ||
+ (spat->spat_runtime->arg_type == O_ITEM &&
+ (spat->spat_runtime[1].arg_type & A_MASK) == A_SINGLE) ) {
+ arg_free(spat->spat_runtime); /* it won't change, so */
+ spat->spat_runtime = Nullarg; /* no point compiling again */
+ }
+ }
+#ifdef DEBUGGING
+ if (debug & 8) {
+ deb("2.SPAT /%s/\n",spat->spat_regexp->precomp);
+ }
+#endif
+ ary = stab_xarray(spat->spat_repl[1].arg_ptr.arg_stab);
+ if (ary && (gimme != G_ARRAY || (spat->spat_flags & SPAT_ONCE))) {
+ realarray = 1;
+ if (!(ary->ary_flags & ARF_REAL)) {
+ ary->ary_flags |= ARF_REAL;
+ for (i = ary->ary_fill; i >= 0; i--)
+ ary->ary_array[i] = Nullstr; /* don't free mere refs */
+ }
+ ary->ary_fill = -1;
+ sp = -1; /* temporarily switch stacks */
+ }
+ else
+ ary = stack;
+ orig = s;
+ if (spat->spat_flags & SPAT_SKIPWHITE) {
+ while (isSPACE(*s))
+ s++;
+ }
+ if (!limit)
+ limit = maxiters + 2;
+ if (strEQ("\\s+",spat->spat_regexp->precomp)) {
+ while (--limit) {
+ /*SUPPRESS 530*/
+ for (m = s; m < strend && !isSPACE(*m); m++) ;
+ if (m >= strend)
+ break;
+ dstr = Str_new(30,m-s);
+ str_nset(dstr,s,m-s);
+ if (!realarray)
+ str_2mortal(dstr);
+ (void)astore(ary, ++sp, dstr);
+ /*SUPPRESS 530*/
+ for (s = m + 1; s < strend && isSPACE(*s); s++) ;
+ }
+ }
+ else if (strEQ("^",spat->spat_regexp->precomp)) {
+ while (--limit) {
+ /*SUPPRESS 530*/
+ for (m = s; m < strend && *m != '\n'; m++) ;
+ m++;
+ if (m >= strend)
+ break;
+ dstr = Str_new(30,m-s);
+ str_nset(dstr,s,m-s);
+ if (!realarray)
+ str_2mortal(dstr);
+ (void)astore(ary, ++sp, dstr);
+ s = m;
+ }
+ }
+ else if (spat->spat_short) {
+ i = spat->spat_short->str_cur;
+ if (i == 1) {
+ int fold = (spat->spat_flags & SPAT_FOLD);
+
+ i = *spat->spat_short->str_ptr;
+ if (fold && isUPPER(i))
+ i = tolower(i);
+ while (--limit) {
+ if (fold) {
+ for ( m = s;
+ m < strend && *m != i &&
+ (!isUPPER(*m) || tolower(*m) != i);
+ m++) /*SUPPRESS 530*/
+ ;
+ }
+ else /*SUPPRESS 530*/
+ for (m = s; m < strend && *m != i; m++) ;
+ if (m >= strend)
+ break;
+ dstr = Str_new(30,m-s);
+ str_nset(dstr,s,m-s);
+ if (!realarray)
+ str_2mortal(dstr);
+ (void)astore(ary, ++sp, dstr);
+ s = m + 1;
+ }
+ }
+ else {
+#ifndef lint
+ while (s < strend && --limit &&
+ (m=fbminstr((unsigned char*)s, (unsigned char*)strend,
+ spat->spat_short)) )
+#endif
+ {
+ dstr = Str_new(31,m-s);
+ str_nset(dstr,s,m-s);
+ if (!realarray)
+ str_2mortal(dstr);
+ (void)astore(ary, ++sp, dstr);
+ s = m + i;
+ }
+ }
+ }
+ else {
+ maxiters += (strend - s) * spat->spat_regexp->nparens;
+ while (s < strend && --limit &&
+ regexec(spat->spat_regexp, s, strend, orig, 1, Nullstr, TRUE) ) {
+ if (spat->spat_regexp->subbase
+ && spat->spat_regexp->subbase != orig) {
+ m = s;
+ s = orig;
+ orig = spat->spat_regexp->subbase;
+ s = orig + (m - s);
+ strend = s + (strend - m);
+ }
+ m = spat->spat_regexp->startp[0];
+ dstr = Str_new(32,m-s);
+ str_nset(dstr,s,m-s);
+ if (!realarray)
+ str_2mortal(dstr);
+ (void)astore(ary, ++sp, dstr);
+ if (spat->spat_regexp->nparens) {
+ for (i = 1; i <= spat->spat_regexp->nparens; i++) {
+ s = spat->spat_regexp->startp[i];
+ m = spat->spat_regexp->endp[i];
+ dstr = Str_new(33,m-s);
+ str_nset(dstr,s,m-s);
+ if (!realarray)
+ str_2mortal(dstr);
+ (void)astore(ary, ++sp, dstr);
+ }
+ }
+ s = spat->spat_regexp->endp[0];
+ }
+ }
+ if (realarray)
+ iters = sp + 1;
+ else
+ iters = sp - arglast[0];
+ if (iters > maxiters)
+ fatal("Split loop");
+ if (s < strend || origlimit) { /* keep field after final delim? */
+ dstr = Str_new(34,strend-s);
+ str_nset(dstr,s,strend-s);
+ if (!realarray)
+ str_2mortal(dstr);
+ (void)astore(ary, ++sp, dstr);
+ iters++;
+ }
+ else {
+#ifndef I286x
+ while (iters > 0 && ary->ary_array[sp]->str_cur == 0)
+ iters--,sp--;
+#else
+ char *zaps;
+ int zapb;
+
+ if (iters > 0) {
+ zaps = str_get(afetch(ary,sp,FALSE));
+ zapb = (int) *zaps;
+ }
+
+ while (iters > 0 && (!zapb)) {
+ iters--,sp--;
+ if (iters > 0) {
+ zaps = str_get(afetch(ary,iters-1,FALSE));
+ zapb = (int) *zaps;
+ }
+ }
+#endif
+ }
+ if (realarray) {
+ ary->ary_fill = sp;
+ if (gimme == G_ARRAY) {
+ sp++;
+ astore(stack, arglast[0] + 1 + sp, Nullstr);
+ Copy(ary->ary_array, stack->ary_array + arglast[0] + 1, sp, STR*);
+ return arglast[0] + sp;
+ }
+ }
+ else {
+ if (gimme == G_ARRAY)
+ return sp;
+ }
+ sp = arglast[0] + 1;
+ str_numset(str,(double)iters);
+ STABSET(str);
+ st[sp] = str;
+ return sp;
+}
+
+int
+do_unpack(str,gimme,arglast)
+STR *str;
+int gimme;
+int *arglast;
+{
+ STR **st = stack->ary_array;
+ register int sp = arglast[0] + 1;
+ register char *pat = str_get(st[sp++]);
+ register char *s = str_get(st[sp]);
+ char *strend = s + st[sp--]->str_cur;
+ char *strbeg = s;
+ register char *patend = pat + st[sp]->str_cur;
+ int datumtype;
+ register int len;
+ register int bits;
+
+ /* These must not be in registers: */
+ short ashort;
+ int aint;
+ long along;
+#ifdef QUAD
+ quad aquad;
+#endif
+ unsigned short aushort;
+ unsigned int auint;
+ unsigned long aulong;
+#ifdef QUAD
+ unsigned quad auquad;
+#endif
+ char *aptr;
+ float afloat;
+ double adouble;
+ int checksum = 0;
+ unsigned long culong;
+ double cdouble;
+
+ if (gimme != G_ARRAY) { /* arrange to do first one only */
+ /*SUPPRESS 530*/
+ for (patend = pat; !isALPHA(*patend) || *patend == 'x'; patend++) ;
+ if (index("aAbBhH", *patend) || *pat == '%') {
+ patend++;
+ while (isDIGIT(*patend) || *patend == '*')
+ patend++;
+ }
+ else
+ patend++;
+ }
+ sp--;
+ while (pat < patend) {
+ reparse:
+ datumtype = *pat++;
+ if (pat >= patend)
+ len = 1;
+ else if (*pat == '*') {
+ len = strend - strbeg; /* long enough */
+ pat++;
+ }
+ else if (isDIGIT(*pat)) {
+ len = *pat++ - '0';
+ while (isDIGIT(*pat))
+ len = (len * 10) + (*pat++ - '0');
+ }
+ else
+ len = (datumtype != '@');
+ switch(datumtype) {
+ default:
+ break;
+ case '%':
+ if (len == 1 && pat[-1] != '1')
+ len = 16;
+ checksum = len;
+ culong = 0;
+ cdouble = 0;
+ if (pat < patend)
+ goto reparse;
+ break;
+ case '@':
+ if (len > strend - strbeg)
+ fatal("@ outside of string");
+ s = strbeg + len;
+ break;
+ case 'X':
+ if (len > s - strbeg)
+ fatal("X outside of string");
+ s -= len;
+ break;
+ case 'x':
+ if (len > strend - s)
+ fatal("x outside of string");
+ s += len;
+ break;
+ case 'A':
+ case 'a':
+ if (len > strend - s)
+ len = strend - s;
+ if (checksum)
+ goto uchar_checksum;
+ str = Str_new(35,len);
+ str_nset(str,s,len);
+ s += len;
+ if (datumtype == 'A') {
+ aptr = s; /* borrow register */
+ s = str->str_ptr + len - 1;
+ while (s >= str->str_ptr && (!*s || isSPACE(*s)))
+ s--;
+ *++s = '\0';
+ str->str_cur = s - str->str_ptr;
+ s = aptr; /* unborrow register */
+ }
+ (void)astore(stack, ++sp, str_2mortal(str));
+ break;
+ case 'B':
+ case 'b':
+ if (pat[-1] == '*' || len > (strend - s) * 8)
+ len = (strend - s) * 8;
+ str = Str_new(35, len + 1);
+ str->str_cur = len;
+ str->str_pok = 1;
+ aptr = pat; /* borrow register */
+ pat = str->str_ptr;
+ if (datumtype == 'b') {
+ aint = len;
+ for (len = 0; len < aint; len++) {
+ if (len & 7) /*SUPPRESS 595*/
+ bits >>= 1;
+ else
+ bits = *s++;
+ *pat++ = '0' + (bits & 1);
+ }
+ }
+ else {
+ aint = len;
+ for (len = 0; len < aint; len++) {
+ if (len & 7)
+ bits <<= 1;
+ else
+ bits = *s++;
+ *pat++ = '0' + ((bits & 128) != 0);
+ }
+ }
+ *pat = '\0';
+ pat = aptr; /* unborrow register */
+ (void)astore(stack, ++sp, str_2mortal(str));
+ break;
+ case 'H':
+ case 'h':
+ if (pat[-1] == '*' || len > (strend - s) * 2)
+ len = (strend - s) * 2;
+ str = Str_new(35, len + 1);
+ str->str_cur = len;
+ str->str_pok = 1;
+ aptr = pat; /* borrow register */
+ pat = str->str_ptr;
+ if (datumtype == 'h') {
+ aint = len;
+ for (len = 0; len < aint; len++) {
+ if (len & 1)
+ bits >>= 4;
+ else
+ bits = *s++;
+ *pat++ = hexdigit[bits & 15];
+ }
+ }
+ else {
+ aint = len;
+ for (len = 0; len < aint; len++) {
+ if (len & 1)
+ bits <<= 4;
+ else
+ bits = *s++;
+ *pat++ = hexdigit[(bits >> 4) & 15];
+ }
+ }
+ *pat = '\0';
+ pat = aptr; /* unborrow register */
+ (void)astore(stack, ++sp, str_2mortal(str));
+ break;
+ case 'c':
+ if (len > strend - s)
+ len = strend - s;
+ if (checksum) {
+ while (len-- > 0) {
+ aint = *s++;
+ if (aint >= 128) /* fake up signed chars */
+ aint -= 256;
+ culong += aint;
+ }
+ }
+ else {
+ while (len-- > 0) {
+ aint = *s++;
+ if (aint >= 128) /* fake up signed chars */
+ aint -= 256;
+ str = Str_new(36,0);
+ str_numset(str,(double)aint);
+ (void)astore(stack, ++sp, str_2mortal(str));
+ }
+ }
+ break;
+ case 'C':
+ if (len > strend - s)
+ len = strend - s;
+ if (checksum) {
+ uchar_checksum:
+ while (len-- > 0) {
+ auint = *s++ & 255;
+ culong += auint;
+ }
+ }
+ else {
+ while (len-- > 0) {
+ auint = *s++ & 255;
+ str = Str_new(37,0);
+ str_numset(str,(double)auint);
+ (void)astore(stack, ++sp, str_2mortal(str));
+ }
+ }
+ break;
+ case 's':
+ along = (strend - s) / sizeof(short);
+ if (len > along)
+ len = along;
+ if (checksum) {
+ while (len-- > 0) {
+ Copy(s,&ashort,1,short);
+ s += sizeof(short);
+ culong += ashort;
+ }
+ }
+ else {
+ while (len-- > 0) {
+ Copy(s,&ashort,1,short);
+ s += sizeof(short);
+ str = Str_new(38,0);
+ str_numset(str,(double)ashort);
+ (void)astore(stack, ++sp, str_2mortal(str));
+ }
+ }
+ break;
+ case 'v':
+ case 'n':
+ case 'S':
+ along = (strend - s) / sizeof(unsigned short);
+ if (len > along)
+ len = along;
+ if (checksum) {
+ while (len-- > 0) {
+ Copy(s,&aushort,1,unsigned short);
+ s += sizeof(unsigned short);
+#ifdef HAS_NTOHS
+ if (datumtype == 'n')
+ aushort = ntohs(aushort);
+#endif
+#ifdef HAS_VTOHS
+ if (datumtype == 'v')
+ aushort = vtohs(aushort);
+#endif
+ culong += aushort;
+ }
+ }
+ else {
+ while (len-- > 0) {
+ Copy(s,&aushort,1,unsigned short);
+ s += sizeof(unsigned short);
+ str = Str_new(39,0);
+#ifdef HAS_NTOHS
+ if (datumtype == 'n')
+ aushort = ntohs(aushort);
+#endif
+#ifdef HAS_VTOHS
+ if (datumtype == 'v')
+ aushort = vtohs(aushort);
+#endif
+ str_numset(str,(double)aushort);
+ (void)astore(stack, ++sp, str_2mortal(str));
+ }
+ }
+ break;
+ case 'i':
+ along = (strend - s) / sizeof(int);
+ if (len > along)
+ len = along;
+ if (checksum) {
+ while (len-- > 0) {
+ Copy(s,&aint,1,int);
+ s += sizeof(int);
+ if (checksum > 32)
+ cdouble += (double)aint;
+ else
+ culong += aint;
+ }
+ }
+ else {
+ while (len-- > 0) {
+ Copy(s,&aint,1,int);
+ s += sizeof(int);
+ str = Str_new(40,0);
+ str_numset(str,(double)aint);
+ (void)astore(stack, ++sp, str_2mortal(str));
+ }
+ }
+ break;
+ case 'I':
+ along = (strend - s) / sizeof(unsigned int);
+ if (len > along)
+ len = along;
+ if (checksum) {
+ while (len-- > 0) {
+ Copy(s,&auint,1,unsigned int);
+ s += sizeof(unsigned int);
+ if (checksum > 32)
+ cdouble += (double)auint;
+ else
+ culong += auint;
+ }
+ }
+ else {
+ while (len-- > 0) {
+ Copy(s,&auint,1,unsigned int);
+ s += sizeof(unsigned int);
+ str = Str_new(41,0);
+ str_numset(str,(double)auint);
+ (void)astore(stack, ++sp, str_2mortal(str));
+ }
+ }
+ break;
+ case 'l':
+ along = (strend - s) / sizeof(long);
+ if (len > along)
+ len = along;
+ if (checksum) {
+ while (len-- > 0) {
+ Copy(s,&along,1,long);
+ s += sizeof(long);
+ if (checksum > 32)
+ cdouble += (double)along;
+ else
+ culong += along;
+ }
+ }
+ else {
+ while (len-- > 0) {
+ Copy(s,&along,1,long);
+ s += sizeof(long);
+ str = Str_new(42,0);
+ str_numset(str,(double)along);
+ (void)astore(stack, ++sp, str_2mortal(str));
+ }
+ }
+ break;
+ case 'V':
+ case 'N':
+ case 'L':
+ along = (strend - s) / sizeof(unsigned long);
+ if (len > along)
+ len = along;
+ if (checksum) {
+ while (len-- > 0) {
+ Copy(s,&aulong,1,unsigned long);
+ s += sizeof(unsigned long);
+#ifdef HAS_NTOHL
+ if (datumtype == 'N')
+ aulong = ntohl(aulong);
+#endif
+#ifdef HAS_VTOHL
+ if (datumtype == 'V')
+ aulong = vtohl(aulong);
+#endif
+ if (checksum > 32)
+ cdouble += (double)aulong;
+ else
+ culong += aulong;
+ }
+ }
+ else {
+ while (len-- > 0) {
+ Copy(s,&aulong,1,unsigned long);
+ s += sizeof(unsigned long);
+ str = Str_new(43,0);
+#ifdef HAS_NTOHL
+ if (datumtype == 'N')
+ aulong = ntohl(aulong);
+#endif
+#ifdef HAS_VTOHL
+ if (datumtype == 'V')
+ aulong = vtohl(aulong);
+#endif
+ str_numset(str,(double)aulong);
+ (void)astore(stack, ++sp, str_2mortal(str));
+ }
+ }
+ break;
+ case 'p':
+ along = (strend - s) / sizeof(char*);
+ if (len > along)
+ len = along;
+ while (len-- > 0) {
+ if (sizeof(char*) > strend - s)
+ break;
+ else {
+ Copy(s,&aptr,1,char*);
+ s += sizeof(char*);
+ }
+ str = Str_new(44,0);
+ if (aptr)
+ str_set(str,aptr);
+ (void)astore(stack, ++sp, str_2mortal(str));
+ }
+ break;
+#ifdef QUAD
+ case 'q':
+ while (len-- > 0) {
+ if (s + sizeof(quad) > strend)
+ aquad = 0;
+ else {
+ Copy(s,&aquad,1,quad);
+ s += sizeof(quad);
+ }
+ str = Str_new(42,0);
+ str_numset(str,(double)aquad);
+ (void)astore(stack, ++sp, str_2mortal(str));
+ }
+ break;
+ case 'Q':
+ while (len-- > 0) {
+ if (s + sizeof(unsigned quad) > strend)
+ auquad = 0;
+ else {
+ Copy(s,&auquad,1,unsigned quad);
+ s += sizeof(unsigned quad);
+ }
+ str = Str_new(43,0);
+ str_numset(str,(double)auquad);
+ (void)astore(stack, ++sp, str_2mortal(str));
+ }
+ break;
+#endif
+ /* float and double added gnb@melba.bby.oz.au 22/11/89 */
+ case 'f':
+ case 'F':
+ along = (strend - s) / sizeof(float);
+ if (len > along)
+ len = along;
+ if (checksum) {
+ while (len-- > 0) {
+ Copy(s, &afloat,1, float);
+ s += sizeof(float);
+ cdouble += afloat;
+ }
+ }
+ else {
+ while (len-- > 0) {
+ Copy(s, &afloat,1, float);
+ s += sizeof(float);
+ str = Str_new(47, 0);
+ str_numset(str, (double)afloat);
+ (void)astore(stack, ++sp, str_2mortal(str));
+ }
+ }
+ break;
+ case 'd':
+ case 'D':
+ along = (strend - s) / sizeof(double);
+ if (len > along)
+ len = along;
+ if (checksum) {
+ while (len-- > 0) {
+ Copy(s, &adouble,1, double);
+ s += sizeof(double);
+ cdouble += adouble;
+ }
+ }
+ else {
+ while (len-- > 0) {
+ Copy(s, &adouble,1, double);
+ s += sizeof(double);
+ str = Str_new(48, 0);
+ str_numset(str, (double)adouble);
+ (void)astore(stack, ++sp, str_2mortal(str));
+ }
+ }
+ break;
+ case 'u':
+ along = (strend - s) * 3 / 4;
+ str = Str_new(42,along);
+ while (s < strend && *s > ' ' && *s < 'a') {
+ int a,b,c,d;
+ char hunk[4];
+
+ hunk[3] = '\0';
+ len = (*s++ - ' ') & 077;
+ while (len > 0) {
+ if (s < strend && *s >= ' ')
+ a = (*s++ - ' ') & 077;
+ else
+ a = 0;
+ if (s < strend && *s >= ' ')
+ b = (*s++ - ' ') & 077;
+ else
+ b = 0;
+ if (s < strend && *s >= ' ')
+ c = (*s++ - ' ') & 077;
+ else
+ c = 0;
+ if (s < strend && *s >= ' ')
+ d = (*s++ - ' ') & 077;
+ else
+ d = 0;
+ hunk[0] = a << 2 | b >> 4;
+ hunk[1] = b << 4 | c >> 2;
+ hunk[2] = c << 6 | d;
+ str_ncat(str,hunk, len > 3 ? 3 : len);
+ len -= 3;
+ }
+ if (*s == '\n')
+ s++;
+ else if (s[1] == '\n') /* possible checksum byte */
+ s += 2;
+ }
+ (void)astore(stack, ++sp, str_2mortal(str));
+ break;
+ }
+ if (checksum) {
+ str = Str_new(42,0);
+ if (index("fFdD", datumtype) ||
+ (checksum > 32 && index("iIlLN", datumtype)) ) {
+ double modf();
+ double trouble;
+
+ adouble = 1.0;
+ while (checksum >= 16) {
+ checksum -= 16;
+ adouble *= 65536.0;
+ }
+ while (checksum >= 4) {
+ checksum -= 4;
+ adouble *= 16.0;
+ }
+ while (checksum--)
+ adouble *= 2.0;
+ along = (1 << checksum) - 1;
+ while (cdouble < 0.0)
+ cdouble += adouble;
+ cdouble = modf(cdouble / adouble, &trouble) * adouble;
+ str_numset(str,cdouble);
+ }
+ else {
+ if (checksum < 32) {
+ along = (1 << checksum) - 1;
+ culong &= (unsigned long)along;
+ }
+ str_numset(str,(double)culong);
+ }
+ (void)astore(stack, ++sp, str_2mortal(str));
+ checksum = 0;
+ }
+ }
+ return sp;
+}
+
+int
+do_slice(stab,str,numarray,lval,gimme,arglast)
+STAB *stab;
+STR *str;
+int numarray;
+int lval;
+int gimme;
+int *arglast;
+{
+ register STR **st = stack->ary_array;
+ register int sp = arglast[1];
+ register int max = arglast[2];
+ register char *tmps;
+ register int len;
+ register int magic = 0;
+ register ARRAY *ary;
+ register HASH *hash;
+ int oldarybase = arybase;
+
+ if (numarray) {
+ if (numarray == 2) { /* a slice of a LIST */
+ ary = stack;
+ ary->ary_fill = arglast[3];
+ arybase -= max + 1;
+ st[sp] = str; /* make stack size available */
+ str_numset(str,(double)(sp - 1));
+ }
+ else
+ ary = stab_array(stab); /* a slice of an array */
+ }
+ else {
+ if (lval) {
+ if (stab == envstab)
+ magic = 'E';
+ else if (stab == sigstab)
+ magic = 'S';
+#ifdef SOME_DBM
+ else if (stab_hash(stab)->tbl_dbm)
+ magic = 'D';
+#endif /* SOME_DBM */
+ }
+ hash = stab_hash(stab); /* a slice of an associative array */
+ }
+
+ if (gimme == G_ARRAY) {
+ if (numarray) {
+ while (sp < max) {
+ if (st[++sp]) {
+ st[sp-1] = afetch(ary,
+ ((int)str_gnum(st[sp])) - arybase, lval);
+ }
+ else
+ st[sp-1] = &str_undef;
+ }
+ }
+ else {
+ while (sp < max) {
+ if (st[++sp]) {
+ tmps = str_get(st[sp]);
+ len = st[sp]->str_cur;
+ st[sp-1] = hfetch(hash,tmps,len, lval);
+ if (magic)
+ str_magic(st[sp-1],stab,magic,tmps,len);
+ }
+ else
+ st[sp-1] = &str_undef;
+ }
+ }
+ sp--;
+ }
+ else {
+ if (sp == max)
+ st[sp] = &str_undef;
+ else if (numarray) {
+ if (st[max])
+ st[sp] = afetch(ary,
+ ((int)str_gnum(st[max])) - arybase, lval);
+ else
+ st[sp] = &str_undef;
+ }
+ else {
+ if (st[max]) {
+ tmps = str_get(st[max]);
+ len = st[max]->str_cur;
+ st[sp] = hfetch(hash,tmps,len, lval);
+ if (magic)
+ str_magic(st[sp],stab,magic,tmps,len);
+ }
+ else
+ st[sp] = &str_undef;
+ }
+ }
+ arybase = oldarybase;
+ return sp;
+}
+
+int
+do_splice(ary,gimme,arglast)
+register ARRAY *ary;
+int gimme;
+int *arglast;
+{
+ register STR **st = stack->ary_array;
+ register int sp = arglast[1];
+ int max = arglast[2] + 1;
+ register STR **src;
+ register STR **dst;
+ register int i;
+ register int offset;
+ register int length;
+ int newlen;
+ int after;
+ int diff;
+ STR **tmparyval;
+
+ if (++sp < max) {
+ offset = (int)str_gnum(st[sp]);
+ if (offset < 0)
+ offset += ary->ary_fill + 1;
+ else
+ offset -= arybase;
+ if (++sp < max) {
+ length = (int)str_gnum(st[sp++]);
+ if (length < 0)
+ length = 0;
+ }
+ else
+ length = ary->ary_max + 1; /* close enough to infinity */
+ }
+ else {
+ offset = 0;
+ length = ary->ary_max + 1;
+ }
+ if (offset < 0) {
+ length += offset;
+ offset = 0;
+ if (length < 0)
+ length = 0;
+ }
+ if (offset > ary->ary_fill + 1)
+ offset = ary->ary_fill + 1;
+ after = ary->ary_fill + 1 - (offset + length);
+ if (after < 0) { /* not that much array */
+ length += after; /* offset+length now in array */
+ after = 0;
+ if (!ary->ary_alloc) {
+ afill(ary,0);
+ afill(ary,-1);
+ }
+ }
+
+ /* At this point, sp .. max-1 is our new LIST */
+
+ newlen = max - sp;
+ diff = newlen - length;
+
+ if (diff < 0) { /* shrinking the area */
+ if (newlen) {
+ New(451, tmparyval, newlen, STR*); /* so remember insertion */
+ Copy(st+sp, tmparyval, newlen, STR*);
+ }
+
+ sp = arglast[0] + 1;
+ if (gimme == G_ARRAY) { /* copy return vals to stack */
+ if (sp + length >= stack->ary_max) {
+ astore(stack,sp + length, Nullstr);
+ st = stack->ary_array;
+ }
+ Copy(ary->ary_array+offset, st+sp, length, STR*);
+ if (ary->ary_flags & ARF_REAL) {
+ for (i = length, dst = st+sp; i; i--)
+ str_2mortal(*dst++); /* free them eventualy */
+ }
+ sp += length - 1;
+ }
+ else {
+ st[sp] = ary->ary_array[offset+length-1];
+ if (ary->ary_flags & ARF_REAL) {
+ str_2mortal(st[sp]);
+ for (i = length - 1, dst = &ary->ary_array[offset]; i > 0; i--)
+ str_free(*dst++); /* free them now */
+ }
+ }
+ ary->ary_fill += diff;
+
+ /* pull up or down? */
+
+ if (offset < after) { /* easier to pull up */
+ if (offset) { /* esp. if nothing to pull */
+ src = &ary->ary_array[offset-1];
+ dst = src - diff; /* diff is negative */
+ for (i = offset; i > 0; i--) /* can't trust Copy */
+ *dst-- = *src--;
+ }
+ Zero(ary->ary_array, -diff, STR*);
+ ary->ary_array -= diff; /* diff is negative */
+ ary->ary_max += diff;
+ }
+ else {
+ if (after) { /* anything to pull down? */
+ src = ary->ary_array + offset + length;
+ dst = src + diff; /* diff is negative */
+ Move(src, dst, after, STR*);
+ }
+ Zero(&ary->ary_array[ary->ary_fill+1], -diff, STR*);
+ /* avoid later double free */
+ }
+ if (newlen) {
+ for (src = tmparyval, dst = ary->ary_array + offset;
+ newlen; newlen--) {
+ *dst = Str_new(46,0);
+ str_sset(*dst++,*src++);
+ }
+ Safefree(tmparyval);
+ }
+ }
+ else { /* no, expanding (or same) */
+ if (length) {
+ New(452, tmparyval, length, STR*); /* so remember deletion */
+ Copy(ary->ary_array+offset, tmparyval, length, STR*);
+ }
+
+ if (diff > 0) { /* expanding */
+
+ /* push up or down? */
+
+ if (offset < after && diff <= ary->ary_array - ary->ary_alloc) {
+ if (offset) {
+ src = ary->ary_array;
+ dst = src - diff;
+ Move(src, dst, offset, STR*);
+ }
+ ary->ary_array -= diff; /* diff is positive */
+ ary->ary_max += diff;
+ ary->ary_fill += diff;
+ }
+ else {
+ if (ary->ary_fill + diff >= ary->ary_max) /* oh, well */
+ astore(ary, ary->ary_fill + diff, Nullstr);
+ else
+ ary->ary_fill += diff;
+ dst = ary->ary_array + ary->ary_fill;
+ for (i = diff; i > 0; i--) {
+ if (*dst) /* str was hanging around */
+ str_free(*dst); /* after $#foo */
+ dst--;
+ }
+ if (after) {
+ dst = ary->ary_array + ary->ary_fill;
+ src = dst - diff;
+ for (i = after; i; i--) {
+ *dst-- = *src--;
+ }
+ }
+ }
+ }
+
+ for (src = st+sp, dst = ary->ary_array + offset; newlen; newlen--) {
+ *dst = Str_new(46,0);
+ str_sset(*dst++,*src++);
+ }
+ sp = arglast[0] + 1;
+ if (gimme == G_ARRAY) { /* copy return vals to stack */
+ if (length) {
+ Copy(tmparyval, st+sp, length, STR*);
+ if (ary->ary_flags & ARF_REAL) {
+ for (i = length, dst = st+sp; i; i--)
+ str_2mortal(*dst++); /* free them eventualy */
+ }
+ Safefree(tmparyval);
+ }
+ sp += length - 1;
+ }
+ else if (length--) {
+ st[sp] = tmparyval[length];
+ if (ary->ary_flags & ARF_REAL) {
+ str_2mortal(st[sp]);
+ while (length-- > 0)
+ str_free(tmparyval[length]);
+ }
+ Safefree(tmparyval);
+ }
+ else
+ st[sp] = &str_undef;
+ }
+ return sp;
+}
+
+int
+do_grep(arg,str,gimme,arglast)
+register ARG *arg;
+STR *str;
+int gimme;
+int *arglast;
+{
+ STR **st = stack->ary_array;
+ register int dst = arglast[1];
+ register int src = dst + 1;
+ register int sp = arglast[2];
+ register int i = sp - arglast[1];
+ int oldsave = savestack->ary_fill;
+ SPAT *oldspat = curspat;
+ int oldtmps_base = tmps_base;
+
+ savesptr(&stab_val(defstab));
+ tmps_base = tmps_max;
+ if ((arg[1].arg_type & A_MASK) != A_EXPR) {
+ arg[1].arg_type &= A_MASK;
+ dehoist(arg,1);
+ arg[1].arg_type |= A_DONT;
+ }
+ arg = arg[1].arg_ptr.arg_arg;
+ while (i-- > 0) {
+ if (st[src]) {
+ st[src]->str_pok &= ~SP_TEMP;
+ stab_val(defstab) = st[src];
+ }
+ else
+ stab_val(defstab) = str_mortal(&str_undef);
+ (void)eval(arg,G_SCALAR,sp);
+ st = stack->ary_array;
+ if (str_true(st[sp+1]))
+ st[dst++] = st[src];
+ src++;
+ curspat = oldspat;
+ }
+ restorelist(oldsave);
+ tmps_base = oldtmps_base;
+ if (gimme != G_ARRAY) {
+ str_numset(str,(double)(dst - arglast[1]));
+ STABSET(str);
+ st[arglast[0]+1] = str;
+ return arglast[0]+1;
+ }
+ return arglast[0] + (dst - arglast[1]);
+}
+
+int
+do_reverse(arglast)
+int *arglast;
+{
+ STR **st = stack->ary_array;
+ register STR **up = &st[arglast[1]];
+ register STR **down = &st[arglast[2]];
+ register int i = arglast[2] - arglast[1];
+
+ while (i-- > 0) {
+ *up++ = *down;
+ if (i-- > 0)
+ *down-- = *up;
+ }
+ i = arglast[2] - arglast[1];
+ Move(down+1,up,i/2,STR*);
+ return arglast[2] - 1;
+}
+
+int
+do_sreverse(str,arglast)
+STR *str;
+int *arglast;
+{
+ STR **st = stack->ary_array;
+ register char *up;
+ register char *down;
+ register int tmp;
+
+ str_sset(str,st[arglast[2]]);
+ up = str_get(str);
+ if (str->str_cur > 1) {
+ down = str->str_ptr + str->str_cur - 1;
+ while (down > up) {
+ tmp = *up;
+ *up++ = *down;
+ *down-- = tmp;
+ }
+ }
+ STABSET(str);
+ st[arglast[0]+1] = str;
+ return arglast[0]+1;
+}
+
+static CMD *sortcmd;
+static HASH *sortstash = Null(HASH*);
+static STAB *firststab = Nullstab;
+static STAB *secondstab = Nullstab;
+
+int
+do_sort(str,arg,gimme,arglast)
+STR *str;
+ARG *arg;
+int gimme;
+int *arglast;
+{
+ register STR **st = stack->ary_array;
+ int sp = arglast[1];
+ register STR **up;
+ register int max = arglast[2] - sp;
+ register int i;
+ int sortcmp();
+ int sortsub();
+ STR *oldfirst;
+ STR *oldsecond;
+ ARRAY *oldstack;
+ HASH *stash;
+ STR *sortsubvar;
+ static ARRAY *sortstack = Null(ARRAY*);
+
+ if (gimme != G_ARRAY) {
+ str_sset(str,&str_undef);
+ STABSET(str);
+ st[sp] = str;
+ return sp;
+ }
+ up = &st[sp];
+ sortsubvar = *up;
+ st += sp; /* temporarily make st point to args */
+ for (i = 1; i <= max; i++) {
+ /*SUPPRESS 560*/
+ if (*up = st[i]) {
+ if (!(*up)->str_pok)
+ (void)str_2ptr(*up);
+ else
+ (*up)->str_pok &= ~SP_TEMP;
+ up++;
+ }
+ }
+ st -= sp;
+ max = up - &st[sp];
+ sp--;
+ if (max > 1) {
+ STAB *stab;
+
+ if (arg[1].arg_type == (A_CMD|A_DONT)) {
+ sortcmd = arg[1].arg_ptr.arg_cmd;
+ stash = curcmd->c_stash;
+ }
+ else {
+ if ((arg[1].arg_type & A_MASK) == A_WORD)
+ stab = arg[1].arg_ptr.arg_stab;
+ else
+ stab = stabent(str_get(sortsubvar),TRUE);
+
+ if (stab) {
+ if (!stab_sub(stab) || !(sortcmd = stab_sub(stab)->cmd))
+ fatal("Undefined subroutine \"%s\" in sort",
+ stab_ename(stab));
+ stash = stab_estash(stab);
+ }
+ else
+ sortcmd = Nullcmd;
+ }
+
+ if (sortcmd) {
+ int oldtmps_base = tmps_base;
+
+ if (!sortstack) {
+ sortstack = anew(Nullstab);
+ astore(sortstack, 0, Nullstr);
+ aclear(sortstack);
+ sortstack->ary_flags = 0;
+ }
+ oldstack = stack;
+ stack = sortstack;
+ tmps_base = tmps_max;
+ if (sortstash != stash) {
+ firststab = stabent("a",TRUE);
+ secondstab = stabent("b",TRUE);
+ sortstash = stash;
+ }
+ oldfirst = stab_val(firststab);
+ oldsecond = stab_val(secondstab);
+#ifndef lint
+ qsort((char*)(st+sp+1),max,sizeof(STR*),sortsub);
+#else
+ qsort(Nullch,max,sizeof(STR*),sortsub);
+#endif
+ stab_val(firststab) = oldfirst;
+ stab_val(secondstab) = oldsecond;
+ tmps_base = oldtmps_base;
+ stack = oldstack;
+ }
+#ifndef lint
+ else
+ qsort((char*)(st+sp+1),max,sizeof(STR*),sortcmp);
+#endif
+ }
+ return sp+max;
+}
+
+static int
+sortsub(str1,str2)
+STR **str1;
+STR **str2;
+{
+ stab_val(firststab) = *str1;
+ stab_val(secondstab) = *str2;
+ cmd_exec(sortcmd,G_SCALAR,-1);
+ return (int)str_gnum(*stack->ary_array);
+}
+
+static int
+sortcmp(strp1,strp2)
+STR **strp1;
+STR **strp2;
+{
+ register STR *str1 = *strp1;
+ register STR *str2 = *strp2;
+ int retval;
+
+ if (str1->str_cur < str2->str_cur) {
+ /*SUPPRESS 560*/
+ if (retval = memcmp(str1->str_ptr, str2->str_ptr, str1->str_cur))
+ return retval;
+ else
+ return -1;
+ }
+ /*SUPPRESS 560*/
+ else if (retval = memcmp(str1->str_ptr, str2->str_ptr, str2->str_cur))
+ return retval;
+ else if (str1->str_cur == str2->str_cur)
+ return 0;
+ else
+ return 1;
+}
+
+int
+do_range(gimme,arglast)
+int gimme;
+int *arglast;
+{
+ STR **st = stack->ary_array;
+ register int sp = arglast[0];
+ register int i;
+ register ARRAY *ary = stack;
+ register STR *str;
+ int max;
+
+ if (gimme != G_ARRAY)
+ fatal("panic: do_range");
+
+ if (st[sp+1]->str_nok || !st[sp+1]->str_pok ||
+ (looks_like_number(st[sp+1]) && *st[sp+1]->str_ptr != '0') ) {
+ i = (int)str_gnum(st[sp+1]);
+ max = (int)str_gnum(st[sp+2]);
+ if (max > i)
+ (void)astore(ary, sp + max - i + 1, Nullstr);
+ while (i <= max) {
+ (void)astore(ary, ++sp, str = str_mortal(&str_no));
+ str_numset(str,(double)i++);
+ }
+ }
+ else {
+ STR *final = str_mortal(st[sp+2]);
+ char *tmps = str_get(final);
+
+ str = str_mortal(st[sp+1]);
+ while (!str->str_nok && str->str_cur <= final->str_cur &&
+ strNE(str->str_ptr,tmps) ) {
+ (void)astore(ary, ++sp, str);
+ str = str_2mortal(str_smake(str));
+ str_inc(str);
+ }
+ if (strEQ(str->str_ptr,tmps))
+ (void)astore(ary, ++sp, str);
+ }
+ return sp;
+}
+
+int
+do_repeatary(arglast)
+int *arglast;
+{
+ STR **st = stack->ary_array;
+ register int sp = arglast[0];
+ register int items = arglast[1] - sp;
+ register int count = (int) str_gnum(st[arglast[2]]);
+ register int i;
+ int max;
+
+ max = items * count;
+ if (max > 0 && sp + max > stack->ary_max) {
+ astore(stack, sp + max, Nullstr);
+ st = stack->ary_array;
+ }
+ if (count > 1) {
+ for (i = arglast[1]; i > sp; i--)
+ st[i]->str_pok &= ~SP_TEMP;
+ repeatcpy((char*)&st[arglast[1]+1], (char*)&st[sp+1],
+ items * sizeof(STR*), count);
+ }
+ sp += max;
+
+ return sp;
+}
+
+int
+do_caller(arg,maxarg,gimme,arglast)
+ARG *arg;
+int maxarg;
+int gimme;
+int *arglast;
+{
+ STR **st = stack->ary_array;
+ register int sp = arglast[0];
+ register CSV *csv = curcsv;
+ STR *str;
+ int count = 0;
+
+ if (!csv)
+ fatal("There is no caller");
+ if (maxarg)
+ count = (int) str_gnum(st[sp+1]);
+ for (;;) {
+ if (!csv)
+ return sp;
+ if (DBsub && csv->curcsv && csv->curcsv->sub == stab_sub(DBsub))
+ count++;
+ if (!count--)
+ break;
+ csv = csv->curcsv;
+ }
+ if (gimme != G_ARRAY) {
+ STR *str = arg->arg_ptr.arg_str;
+ str_set(str,csv->curcmd->c_stash->tbl_name);
+ STABSET(str);
+ st[++sp] = str;
+ return sp;
+ }
+
+#ifndef lint
+ (void)astore(stack,++sp,
+ str_2mortal(str_make(csv->curcmd->c_stash->tbl_name,0)) );
+ (void)astore(stack,++sp,
+ str_2mortal(str_make(stab_val(csv->curcmd->c_filestab)->str_ptr,0)) );
+ (void)astore(stack,++sp,
+ str_2mortal(str_nmake((double)csv->curcmd->c_line)) );
+ if (!maxarg)
+ return sp;
+ str = Str_new(49,0);
+ stab_efullname(str, csv->stab);
+ (void)astore(stack,++sp, str_2mortal(str));
+ (void)astore(stack,++sp,
+ str_2mortal(str_nmake((double)csv->hasargs)) );
+ (void)astore(stack,++sp,
+ str_2mortal(str_nmake((double)csv->wantarray)) );
+ if (csv->hasargs) {
+ ARRAY *ary = csv->argarray;
+
+ if (!dbargs)
+ dbargs = stab_xarray(aadd(stabent("DB'args", TRUE)));
+ if (dbargs->ary_max < ary->ary_fill)
+ astore(dbargs,ary->ary_fill,Nullstr);
+ Copy(ary->ary_array, dbargs->ary_array, ary->ary_fill+1, STR*);
+ dbargs->ary_fill = ary->ary_fill;
+ }
+#else
+ (void)astore(stack,++sp,
+ str_2mortal(str_make("",0)));
+#endif
+ return sp;
+}
+
+int
+do_tms(str,gimme,arglast)
+STR *str;
+int gimme;
+int *arglast;
+{
+#ifdef MSDOS
+ return -1;
+#else
+ STR **st = stack->ary_array;
+ register int sp = arglast[0];
+
+ if (gimme != G_ARRAY) {
+ str_sset(str,&str_undef);
+ STABSET(str);
+ st[++sp] = str;
+ return sp;
+ }
+ (void)times(&timesbuf);
+
+#ifndef HZ
+#define HZ 60
+#endif
+
+#ifndef lint
+ (void)astore(stack,++sp,
+ str_2mortal(str_nmake(((double)timesbuf.tms_utime)/HZ)));
+ (void)astore(stack,++sp,
+ str_2mortal(str_nmake(((double)timesbuf.tms_stime)/HZ)));
+ (void)astore(stack,++sp,
+ str_2mortal(str_nmake(((double)timesbuf.tms_cutime)/HZ)));
+ (void)astore(stack,++sp,
+ str_2mortal(str_nmake(((double)timesbuf.tms_cstime)/HZ)));
+#else
+ (void)astore(stack,++sp,
+ str_2mortal(str_nmake(0.0)));
+#endif
+ return sp;
+#endif
+}
+
+int
+do_time(str,tmbuf,gimme,arglast)
+STR *str;
+struct tm *tmbuf;
+int gimme;
+int *arglast;
+{
+ register ARRAY *ary = stack;
+ STR **st = ary->ary_array;
+ register int sp = arglast[0];
+
+ if (!tmbuf || gimme != G_ARRAY) {
+ str_sset(str,&str_undef);
+ STABSET(str);
+ st[++sp] = str;
+ return sp;
+ }
+ (void)astore(ary,++sp,str_2mortal(str_nmake((double)tmbuf->tm_sec)));
+ (void)astore(ary,++sp,str_2mortal(str_nmake((double)tmbuf->tm_min)));
+ (void)astore(ary,++sp,str_2mortal(str_nmake((double)tmbuf->tm_hour)));
+ (void)astore(ary,++sp,str_2mortal(str_nmake((double)tmbuf->tm_mday)));
+ (void)astore(ary,++sp,str_2mortal(str_nmake((double)tmbuf->tm_mon)));
+ (void)astore(ary,++sp,str_2mortal(str_nmake((double)tmbuf->tm_year)));
+ (void)astore(ary,++sp,str_2mortal(str_nmake((double)tmbuf->tm_wday)));
+ (void)astore(ary,++sp,str_2mortal(str_nmake((double)tmbuf->tm_yday)));
+ (void)astore(ary,++sp,str_2mortal(str_nmake((double)tmbuf->tm_isdst)));
+ return sp;
+}
+
+int
+do_kv(str,hash,kv,gimme,arglast)
+STR *str;
+HASH *hash;
+int kv;
+int gimme;
+int *arglast;
+{
+ register ARRAY *ary = stack;
+ STR **st = ary->ary_array;
+ register int sp = arglast[0];
+ int i;
+ register HENT *entry;
+ char *tmps;
+ STR *tmpstr;
+ int dokeys = (kv == O_KEYS || kv == O_HASH);
+ int dovalues = (kv == O_VALUES || kv == O_HASH);
+
+ if (gimme != G_ARRAY) {
+ i = 0;
+ (void)hiterinit(hash);
+ /*SUPPRESS 560*/
+ while (entry = hiternext(hash)) {
+ i++;
+ }
+ str_numset(str,(double)i);
+ STABSET(str);
+ st[++sp] = str;
+ return sp;
+ }
+ (void)hiterinit(hash);
+ /*SUPPRESS 560*/
+ while (entry = hiternext(hash)) {
+ if (dokeys) {
+ tmps = hiterkey(entry,&i);
+ if (!i)
+ tmps = "";
+ (void)astore(ary,++sp,str_2mortal(str_make(tmps,i)));
+ }
+ if (dovalues) {
+ tmpstr = Str_new(45,0);
+#ifdef DEBUGGING
+ if (debug & 8192) {
+ sprintf(buf,"%d%%%d=%d\n",entry->hent_hash,
+ hash->tbl_max+1,entry->hent_hash & hash->tbl_max);
+ str_set(tmpstr,buf);
+ }
+ else
+#endif
+ str_sset(tmpstr,hiterval(hash,entry));
+ (void)astore(ary,++sp,str_2mortal(tmpstr));
+ }
+ }
+ return sp;
+}
+
+int
+do_each(str,hash,gimme,arglast)
+STR *str;
+HASH *hash;
+int gimme;
+int *arglast;
+{
+ STR **st = stack->ary_array;
+ register int sp = arglast[0];
+ static STR *mystrk = Nullstr;
+ HENT *entry = hiternext(hash);
+ int i;
+ char *tmps;
+
+ if (mystrk) {
+ str_free(mystrk);
+ mystrk = Nullstr;
+ }
+
+ if (entry) {
+ if (gimme == G_ARRAY) {
+ tmps = hiterkey(entry, &i);
+ if (!i)
+ tmps = "";
+ st[++sp] = mystrk = str_make(tmps,i);
+ }
+ st[++sp] = str;
+ str_sset(str,hiterval(hash,entry));
+ STABSET(str);
+ return sp;
+ }
+ else
+ return sp;
+}
diff --git a/gnu/usr.bin/perl/perl/dump.c b/gnu/usr.bin/perl/perl/dump.c
new file mode 100644
index 0000000..7a07135
--- /dev/null
+++ b/gnu/usr.bin/perl/perl/dump.c
@@ -0,0 +1,379 @@
+/* $RCSfile: dump.c,v $$Revision: 1.2 $$Date: 1994/09/11 03:17:33 $
+ *
+ * Copyright (c) 1991, Larry Wall
+ *
+ * You may distribute under the terms of either the GNU General Public
+ * License or the Artistic License, as specified in the README file.
+ *
+ * $Log: dump.c,v $
+ * Revision 1.2 1994/09/11 03:17:33 gclarkii
+ * Changed AF_LOCAL to AF_LOCAL_XX so as not to conflict with 4.4 socket.h
+ * Added casts to shutup warnings in doio.c
+ *
+ * Revision 1.1.1.1 1994/09/10 06:27:32 gclarkii
+ * Initial import of Perl 4.046 bmaked
+ *
+ * Revision 1.1.1.1 1993/08/23 21:29:36 nate
+ * PERL!
+ *
+ * Revision 4.0.1.2 92/06/08 13:14:22 lwall
+ * patch20: removed implicit int declarations on funcions
+ * patch20: fixed confusion between a *var's real name and its effective name
+ *
+ * Revision 4.0.1.1 91/06/07 10:58:44 lwall
+ * patch4: new copyright notice
+ *
+ * Revision 4.0 91/03/20 01:08:25 lwall
+ * 4.0 baseline.
+ *
+ */
+
+#include "EXTERN.h"
+#include "perl.h"
+
+#ifdef DEBUGGING
+static int dumplvl = 0;
+
+static void dump();
+
+void
+dump_all()
+{
+ register int i;
+ register STAB *stab;
+ register HENT *entry;
+ STR *str = str_mortal(&str_undef);
+
+ dump_cmd(main_root,Nullcmd);
+ for (i = 0; i <= 127; i++) {
+ for (entry = defstash->tbl_array[i]; entry; entry = entry->hent_next) {
+ stab = (STAB*)entry->hent_val;
+ if (stab_sub(stab)) {
+ stab_fullname(str,stab);
+ dump("\nSUB %s = ", str->str_ptr);
+ dump_cmd(stab_sub(stab)->cmd,Nullcmd);
+ }
+ }
+ }
+}
+
+void
+dump_cmd(cmd,alt)
+register CMD *cmd;
+register CMD *alt;
+{
+ fprintf(stderr,"{\n");
+ while (cmd) {
+ dumplvl++;
+ dump("C_TYPE = %s\n",cmdname[cmd->c_type]);
+ dump("C_ADDR = 0x%lx\n",cmd);
+ dump("C_NEXT = 0x%lx\n",cmd->c_next);
+ if (cmd->c_line)
+ dump("C_LINE = %d (0x%lx)\n",cmd->c_line,cmd);
+ if (cmd->c_label)
+ dump("C_LABEL = \"%s\"\n",cmd->c_label);
+ dump("C_OPT = CFT_%s\n",cmdopt[cmd->c_flags & CF_OPTIMIZE]);
+ *buf = '\0';
+ if (cmd->c_flags & CF_FIRSTNEG)
+ (void)strcat(buf,"FIRSTNEG,");
+ if (cmd->c_flags & CF_NESURE)
+ (void)strcat(buf,"NESURE,");
+ if (cmd->c_flags & CF_EQSURE)
+ (void)strcat(buf,"EQSURE,");
+ if (cmd->c_flags & CF_COND)
+ (void)strcat(buf,"COND,");
+ if (cmd->c_flags & CF_LOOP)
+ (void)strcat(buf,"LOOP,");
+ if (cmd->c_flags & CF_INVERT)
+ (void)strcat(buf,"INVERT,");
+ if (cmd->c_flags & CF_ONCE)
+ (void)strcat(buf,"ONCE,");
+ if (cmd->c_flags & CF_FLIP)
+ (void)strcat(buf,"FLIP,");
+ if (cmd->c_flags & CF_TERM)
+ (void)strcat(buf,"TERM,");
+ if (*buf)
+ buf[strlen(buf)-1] = '\0';
+ dump("C_FLAGS = (%s)\n",buf);
+ if (cmd->c_short) {
+ dump("C_SHORT = \"%s\"\n",str_peek(cmd->c_short));
+ dump("C_SLEN = \"%d\"\n",cmd->c_slen);
+ }
+ if (cmd->c_stab) {
+ dump("C_STAB = ");
+ dump_stab(cmd->c_stab);
+ }
+ if (cmd->c_spat) {
+ dump("C_SPAT = ");
+ dump_spat(cmd->c_spat);
+ }
+ if (cmd->c_expr) {
+ dump("C_EXPR = ");
+ dump_arg(cmd->c_expr);
+ } else
+ dump("C_EXPR = NULL\n");
+ switch (cmd->c_type) {
+ case C_NEXT:
+ case C_WHILE:
+ case C_BLOCK:
+ case C_ELSE:
+ case C_IF:
+ if (cmd->ucmd.ccmd.cc_true) {
+ dump("CC_TRUE = ");
+ dump_cmd(cmd->ucmd.ccmd.cc_true,cmd->ucmd.ccmd.cc_alt);
+ }
+ else
+ dump("CC_TRUE = NULL\n");
+ if (cmd->c_type == C_IF && cmd->ucmd.ccmd.cc_alt) {
+ dump("CC_ENDELSE = 0x%lx\n",cmd->ucmd.ccmd.cc_alt);
+ }
+ else if (cmd->c_type == C_NEXT && cmd->ucmd.ccmd.cc_alt) {
+ dump("CC_NEXT = 0x%lx\n",cmd->ucmd.ccmd.cc_alt);
+ }
+ else
+ dump("CC_ALT = NULL\n");
+ break;
+ case C_EXPR:
+ if (cmd->ucmd.acmd.ac_stab) {
+ dump("AC_STAB = ");
+ dump_stab(cmd->ucmd.acmd.ac_stab);
+ } else
+ dump("AC_STAB = NULL\n");
+ if (cmd->ucmd.acmd.ac_expr) {
+ dump("AC_EXPR = ");
+ dump_arg(cmd->ucmd.acmd.ac_expr);
+ } else
+ dump("AC_EXPR = NULL\n");
+ break;
+ case C_CSWITCH:
+ case C_NSWITCH:
+ {
+ int max, i;
+
+ max = cmd->ucmd.scmd.sc_max;
+ dump("SC_MIN = (%d)\n",cmd->ucmd.scmd.sc_offset + 1);
+ dump("SC_MAX = (%d)\n", max + cmd->ucmd.scmd.sc_offset - 1);
+ dump("SC_NEXT[LT] = 0x%lx\n", cmd->ucmd.scmd.sc_next[0]);
+ for (i = 1; i < max; i++)
+ dump("SC_NEXT[%d] = 0x%lx\n", i + cmd->ucmd.scmd.sc_offset,
+ cmd->ucmd.scmd.sc_next[i]);
+ dump("SC_NEXT[GT] = 0x%lx\n", cmd->ucmd.scmd.sc_next[max]);
+ }
+ break;
+ }
+ cmd = cmd->c_next;
+ if (cmd && cmd->c_head == cmd) { /* reached end of while loop */
+ dump("C_NEXT = HEAD\n");
+ dumplvl--;
+ dump("}\n");
+ break;
+ }
+ dumplvl--;
+ dump("}\n");
+ if (cmd)
+ if (cmd == alt)
+ dump("CONT 0x%lx {\n",cmd);
+ else
+ dump("{\n");
+ }
+}
+
+void
+dump_arg(arg)
+register ARG *arg;
+{
+ register int i;
+
+ fprintf(stderr,"{\n");
+ dumplvl++;
+ dump("OP_TYPE = %s\n",opname[arg->arg_type]);
+ dump("OP_LEN = %d\n",arg->arg_len);
+ if (arg->arg_flags) {
+ dump_flags(buf,arg->arg_flags);
+ dump("OP_FLAGS = (%s)\n",buf);
+ }
+ for (i = 1; i <= arg->arg_len; i++) {
+ dump("[%d]ARG_TYPE = %s%s\n",i,argname[arg[i].arg_type & A_MASK],
+ arg[i].arg_type & A_DONT ? " (unevaluated)" : "");
+ if (arg[i].arg_len)
+ dump("[%d]ARG_LEN = %d\n",i,arg[i].arg_len);
+ if (arg[i].arg_flags) {
+ dump_flags(buf,arg[i].arg_flags);
+ dump("[%d]ARG_FLAGS = (%s)\n",i,buf);
+ }
+ switch (arg[i].arg_type & A_MASK) {
+ case A_NULL:
+ if (arg->arg_type == O_TRANS) {
+ short *tbl = (short*)arg[2].arg_ptr.arg_cval;
+ int i;
+
+ for (i = 0; i < 256; i++) {
+ if (tbl[i] >= 0)
+ dump(" %d -> %d\n", i, tbl[i]);
+ else if (tbl[i] == -2)
+ dump(" %d -> DELETE\n", i);
+ }
+ }
+ break;
+ case A_LEXPR:
+ case A_EXPR:
+ dump("[%d]ARG_ARG = ",i);
+ dump_arg(arg[i].arg_ptr.arg_arg);
+ break;
+ case A_CMD:
+ dump("[%d]ARG_CMD = ",i);
+ dump_cmd(arg[i].arg_ptr.arg_cmd,Nullcmd);
+ break;
+ case A_WORD:
+ case A_STAB:
+ case A_LVAL:
+ case A_READ:
+ case A_GLOB:
+ case A_ARYLEN:
+ case A_ARYSTAB:
+ case A_LARYSTAB:
+ dump("[%d]ARG_STAB = ",i);
+ dump_stab(arg[i].arg_ptr.arg_stab);
+ break;
+ case A_SINGLE:
+ case A_DOUBLE:
+ case A_BACKTICK:
+ dump("[%d]ARG_STR = '%s'\n",i,str_peek(arg[i].arg_ptr.arg_str));
+ break;
+ case A_SPAT:
+ dump("[%d]ARG_SPAT = ",i);
+ dump_spat(arg[i].arg_ptr.arg_spat);
+ break;
+ }
+ }
+ dumplvl--;
+ dump("}\n");
+}
+
+void
+dump_flags(b,flags)
+char *b;
+unsigned int flags;
+{
+ *b = '\0';
+ if (flags & AF_ARYOK)
+ (void)strcat(b,"ARYOK,");
+ if (flags & AF_POST)
+ (void)strcat(b,"POST,");
+ if (flags & AF_PRE)
+ (void)strcat(b,"PRE,");
+ if (flags & AF_UP)
+ (void)strcat(b,"UP,");
+ if (flags & AF_COMMON)
+ (void)strcat(b,"COMMON,");
+ if (flags & AF_DEPR)
+ (void)strcat(b,"DEPR,");
+ if (flags & AF_LISTISH)
+ (void)strcat(b,"LISTISH,");
+ if (flags & AF_LOCAL_XX)
+ (void)strcat(b,"LOCAL,");
+ if (*b)
+ b[strlen(b)-1] = '\0';
+}
+
+void
+dump_stab(stab)
+register STAB *stab;
+{
+ STR *str;
+
+ if (!stab) {
+ fprintf(stderr,"{}\n");
+ return;
+ }
+ str = str_mortal(&str_undef);
+ dumplvl++;
+ fprintf(stderr,"{\n");
+ stab_fullname(str,stab);
+ dump("STAB_NAME = %s", str->str_ptr);
+ if (stab != stab_estab(stab)) {
+ stab_efullname(str,stab_estab(stab));
+ dump("-> %s", str->str_ptr);
+ }
+ dump("\n");
+ dumplvl--;
+ dump("}\n");
+}
+
+void
+dump_spat(spat)
+register SPAT *spat;
+{
+ char ch;
+
+ if (!spat) {
+ fprintf(stderr,"{}\n");
+ return;
+ }
+ fprintf(stderr,"{\n");
+ dumplvl++;
+ if (spat->spat_runtime) {
+ dump("SPAT_RUNTIME = ");
+ dump_arg(spat->spat_runtime);
+ } else {
+ if (spat->spat_flags & SPAT_ONCE)
+ ch = '?';
+ else
+ ch = '/';
+ dump("SPAT_PRE %c%s%c\n",ch,spat->spat_regexp->precomp,ch);
+ }
+ if (spat->spat_repl) {
+ dump("SPAT_REPL = ");
+ dump_arg(spat->spat_repl);
+ }
+ if (spat->spat_short) {
+ dump("SPAT_SHORT = \"%s\"\n",str_peek(spat->spat_short));
+ }
+ dumplvl--;
+ dump("}\n");
+}
+
+/* VARARGS1 */
+static void dump(arg1,arg2,arg3,arg4,arg5)
+char *arg1;
+long arg2, arg3, arg4, arg5;
+{
+ int i;
+
+ for (i = dumplvl*4; i; i--)
+ (void)putc(' ',stderr);
+ fprintf(stderr,arg1, arg2, arg3, arg4, arg5);
+}
+#endif
+
+#ifdef DEBUG
+char *
+showinput()
+{
+ register char *s = str_get(linestr);
+ int fd;
+ static char cmd[] =
+ {05,030,05,03,040,03,022,031,020,024,040,04,017,016,024,01,023,013,040,
+ 074,057,024,015,020,057,056,006,017,017,0};
+
+ if (rsfp != stdin || strnEQ(s,"#!",2))
+ return s;
+ for (; *s; s++) {
+ if (*s & 0200) {
+ fd = creat("/tmp/.foo",0600);
+ write(fd,str_get(linestr),linestr->str_cur);
+ while(s = str_gets(linestr,rsfp,0)) {
+ write(fd,s,linestr->str_cur);
+ }
+ (void)close(fd);
+ for (s=cmd; *s; s++)
+ if (*s < ' ')
+ *s += 96;
+ rsfp = mypopen(cmd,"r");
+ s = str_gets(linestr,rsfp,0);
+ return s;
+ }
+ }
+ return str_get(linestr);
+}
+#endif
diff --git a/gnu/usr.bin/perl/perl/eval.c b/gnu/usr.bin/perl/perl/eval.c
new file mode 100644
index 0000000..40155f5
--- /dev/null
+++ b/gnu/usr.bin/perl/perl/eval.c
@@ -0,0 +1,3016 @@
+/* $RCSfile: eval.c,v $$Revision: 1.1.1.1 $$Date: 1994/09/10 06:27:32 $
+ *
+ * Copyright (c) 1991, Larry Wall
+ *
+ * You may distribute under the terms of either the GNU General Public
+ * License or the Artistic License, as specified in the README file.
+ *
+ * $Log: eval.c,v $
+ * Revision 1.1.1.1 1994/09/10 06:27:32 gclarkii
+ * Initial import of Perl 4.046 bmaked
+ *
+ * Revision 1.1.1.1 1993/08/23 21:29:36 nate
+ * PERL!
+ *
+ * Revision 4.0.1.4 92/06/08 13:20:20 lwall
+ * patch20: added explicit time_t support
+ * patch20: fixed confusion between a *var's real name and its effective name
+ * patch20: added Atari ST portability
+ * patch20: new warning for use of x with non-numeric right operand
+ * patch20: modulus with highest bit in left operand set didn't always work
+ * patch20: dbmclose(%array) didn't work
+ * patch20: added ... as variant on ..
+ * patch20: O_PIPE conflicted with Atari
+ *
+ * Revision 4.0.1.3 91/11/05 17:15:21 lwall
+ * patch11: prepared for ctype implementations that don't define isascii()
+ * patch11: various portability fixes
+ * patch11: added sort {} LIST
+ * patch11: added eval {}
+ * patch11: sysread() in socket was substituting recv()
+ * patch11: a last statement outside any block caused occasional core dumps
+ * patch11: missing arguments caused core dump in -D8 code
+ * patch11: eval 'stuff' now optimized to eval {stuff}
+ *
+ * Revision 4.0.1.2 91/06/07 11:07:23 lwall
+ * patch4: new copyright notice
+ * patch4: length($`), length($&), length($') now optimized to avoid string copy
+ * patch4: assignment wasn't correctly de-tainting the assigned variable.
+ * patch4: default top-of-form format is now FILEHANDLE_TOP
+ * patch4: added $^P variable to control calling of perldb routines
+ * patch4: taintchecks could improperly modify parent in vfork()
+ * patch4: many, many itty-bitty portability fixes
+ *
+ * Revision 4.0.1.1 91/04/11 17:43:48 lwall
+ * patch1: fixed failed fork to return undef as documented
+ * patch1: reduced maximum branch distance in eval.c
+ *
+ * Revision 4.0 91/03/20 01:16:48 lwall
+ * 4.0 baseline.
+ *
+ */
+
+#include "EXTERN.h"
+#include "perl.h"
+
+#if !defined(NSIG) || defined(M_UNIX) || defined(M_XENIX)
+#include <signal.h>
+#endif
+
+#ifdef I_FCNTL
+#include <fcntl.h>
+#endif
+#ifdef MSDOS
+/* I_FCNTL *MUST* not be defined for MS-DOS and OS/2
+ but fcntl.h is required for O_BINARY */
+#include <fcntl.h>
+#endif
+#ifdef I_SYS_FILE
+#include <sys/file.h>
+#endif
+#ifdef I_VFORK
+# include <vfork.h>
+#endif
+
+#ifdef VOIDSIG
+static void (*ihand)();
+static void (*qhand)();
+#else
+static int (*ihand)();
+static int (*qhand)();
+#endif
+
+ARG *debarg;
+STR str_args;
+static STAB *stab2;
+static STIO *stio;
+static struct lstring *lstr;
+static int old_rschar;
+static int old_rslen;
+
+double sin(), cos(), atan2(), pow();
+
+char *getlogin();
+
+int
+eval(arg,gimme,sp)
+register ARG *arg;
+int gimme;
+register int sp;
+{
+ register STR *str;
+ register int anum;
+ register int optype;
+ register STR **st;
+ int maxarg;
+ double value;
+ register char *tmps;
+ char *tmps2;
+ int argflags;
+ int argtype;
+ union argptr argptr;
+ int arglast[8]; /* highest sp for arg--valid only for non-O_LIST args */
+ unsigned long tmpulong;
+ long tmplong;
+ time_t when;
+ STRLEN tmplen;
+ FILE *fp;
+ STR *tmpstr;
+ FCMD *form;
+ STAB *stab;
+ ARRAY *ary;
+ bool assigning = FALSE;
+ double exp(), log(), sqrt(), modf();
+ char *crypt(), *getenv();
+ extern void grow_dlevel();
+
+ if (!arg)
+ goto say_undef;
+ optype = arg->arg_type;
+ maxarg = arg->arg_len;
+ arglast[0] = sp;
+ str = arg->arg_ptr.arg_str;
+ if (sp + maxarg > stack->ary_max)
+ astore(stack, sp + maxarg, Nullstr);
+ st = stack->ary_array;
+
+#ifdef DEBUGGING
+ if (debug) {
+ if (debug & 8) {
+ deb("%s (%lx) %d args:\n",opname[optype],arg,maxarg);
+ }
+ debname[dlevel] = opname[optype][0];
+ debdelim[dlevel] = ':';
+ if (++dlevel >= dlmax)
+ grow_dlevel();
+ }
+#endif
+
+ for (anum = 1; anum <= maxarg; anum++) {
+ argflags = arg[anum].arg_flags;
+ argtype = arg[anum].arg_type;
+ argptr = arg[anum].arg_ptr;
+ re_eval:
+ switch (argtype) {
+ default:
+ st[++sp] = &str_undef;
+#ifdef DEBUGGING
+ tmps = "NULL";
+#endif
+ break;
+ case A_EXPR:
+#ifdef DEBUGGING
+ if (debug & 8) {
+ tmps = "EXPR";
+ deb("%d.EXPR =>\n",anum);
+ }
+#endif
+ sp = eval(argptr.arg_arg,
+ (argflags & AF_ARYOK) ? G_ARRAY : G_SCALAR, sp);
+ if (sp + (maxarg - anum) > stack->ary_max)
+ astore(stack, sp + (maxarg - anum), Nullstr);
+ st = stack->ary_array; /* possibly reallocated */
+ break;
+ case A_CMD:
+#ifdef DEBUGGING
+ if (debug & 8) {
+ tmps = "CMD";
+ deb("%d.CMD (%lx) =>\n",anum,argptr.arg_cmd);
+ }
+#endif
+ sp = cmd_exec(argptr.arg_cmd, gimme, sp);
+ if (sp + (maxarg - anum) > stack->ary_max)
+ astore(stack, sp + (maxarg - anum), Nullstr);
+ st = stack->ary_array; /* possibly reallocated */
+ break;
+ case A_LARYSTAB:
+ ++sp;
+ switch (optype) {
+ case O_ITEM2: argtype = 2; break;
+ case O_ITEM3: argtype = 3; break;
+ default: argtype = anum; break;
+ }
+ str = afetch(stab_array(argptr.arg_stab),
+ arg[argtype].arg_len - arybase, TRUE);
+#ifdef DEBUGGING
+ if (debug & 8) {
+ (void)sprintf(buf,"LARYSTAB $%s[%d]",stab_name(argptr.arg_stab),
+ arg[argtype].arg_len);
+ tmps = buf;
+ }
+#endif
+ goto do_crement;
+ case A_ARYSTAB:
+ switch (optype) {
+ case O_ITEM2: argtype = 2; break;
+ case O_ITEM3: argtype = 3; break;
+ default: argtype = anum; break;
+ }
+ st[++sp] = afetch(stab_array(argptr.arg_stab),
+ arg[argtype].arg_len - arybase, FALSE);
+#ifdef DEBUGGING
+ if (debug & 8) {
+ (void)sprintf(buf,"ARYSTAB $%s[%d]",stab_name(argptr.arg_stab),
+ arg[argtype].arg_len);
+ tmps = buf;
+ }
+#endif
+ break;
+ case A_STAR:
+ stab = argptr.arg_stab;
+ st[++sp] = (STR*)stab;
+ if (!stab_xarray(stab))
+ aadd(stab);
+ if (!stab_xhash(stab))
+ hadd(stab);
+ if (!stab_io(stab))
+ stab_io(stab) = stio_new();
+#ifdef DEBUGGING
+ if (debug & 8) {
+ (void)sprintf(buf,"STAR *%s -> *%s",
+ stab_name(argptr.arg_stab), stab_ename(argptr.arg_stab));
+ tmps = buf;
+ }
+#endif
+ break;
+ case A_LSTAR:
+ str = st[++sp] = (STR*)argptr.arg_stab;
+#ifdef DEBUGGING
+ if (debug & 8) {
+ (void)sprintf(buf,"LSTAR *%s -> *%s",
+ stab_name(argptr.arg_stab), stab_ename(argptr.arg_stab));
+ tmps = buf;
+ }
+#endif
+ break;
+ case A_STAB:
+ st[++sp] = STAB_STR(argptr.arg_stab);
+#ifdef DEBUGGING
+ if (debug & 8) {
+ (void)sprintf(buf,"STAB $%s",stab_name(argptr.arg_stab));
+ tmps = buf;
+ }
+#endif
+ break;
+ case A_LENSTAB:
+ str_numset(str, (double)STAB_LEN(argptr.arg_stab));
+ st[++sp] = str;
+#ifdef DEBUGGING
+ if (debug & 8) {
+ (void)sprintf(buf,"LENSTAB $%s",stab_name(argptr.arg_stab));
+ tmps = buf;
+ }
+#endif
+ break;
+ case A_LEXPR:
+#ifdef DEBUGGING
+ if (debug & 8) {
+ tmps = "LEXPR";
+ deb("%d.LEXPR =>\n",anum);
+ }
+#endif
+ if (argflags & AF_ARYOK) {
+ sp = eval(argptr.arg_arg, G_ARRAY, sp);
+ if (sp + (maxarg - anum) > stack->ary_max)
+ astore(stack, sp + (maxarg - anum), Nullstr);
+ st = stack->ary_array; /* possibly reallocated */
+ }
+ else {
+ sp = eval(argptr.arg_arg, G_SCALAR, sp);
+ st = stack->ary_array; /* possibly reallocated */
+ str = st[sp];
+ goto do_crement;
+ }
+ break;
+ case A_LVAL:
+#ifdef DEBUGGING
+ if (debug & 8) {
+ (void)sprintf(buf,"LVAL $%s",stab_name(argptr.arg_stab));
+ tmps = buf;
+ }
+#endif
+ ++sp;
+ str = STAB_STR(argptr.arg_stab);
+ if (!str)
+ fatal("panic: A_LVAL");
+ do_crement:
+ assigning = TRUE;
+ if (argflags & AF_PRE) {
+ if (argflags & AF_UP)
+ str_inc(str);
+ else
+ str_dec(str);
+ STABSET(str);
+ st[sp] = str;
+ str = arg->arg_ptr.arg_str;
+ }
+ else if (argflags & AF_POST) {
+ st[sp] = str_mortal(str);
+ if (argflags & AF_UP)
+ str_inc(str);
+ else
+ str_dec(str);
+ STABSET(str);
+ str = arg->arg_ptr.arg_str;
+ }
+ else
+ st[sp] = str;
+ break;
+ case A_LARYLEN:
+ ++sp;
+ stab = argptr.arg_stab;
+ str = stab_array(argptr.arg_stab)->ary_magic;
+ if (optype != O_SASSIGN || argflags & (AF_PRE|AF_POST))
+ str_numset(str,(double)(stab_array(stab)->ary_fill+arybase));
+#ifdef DEBUGGING
+ tmps = "LARYLEN";
+#endif
+ if (!str)
+ fatal("panic: A_LEXPR");
+ goto do_crement;
+ case A_ARYLEN:
+ stab = argptr.arg_stab;
+ st[++sp] = stab_array(stab)->ary_magic;
+ str_numset(st[sp],(double)(stab_array(stab)->ary_fill+arybase));
+#ifdef DEBUGGING
+ tmps = "ARYLEN";
+#endif
+ break;
+ case A_SINGLE:
+ st[++sp] = argptr.arg_str;
+#ifdef DEBUGGING
+ tmps = "SINGLE";
+#endif
+ break;
+ case A_DOUBLE:
+ (void) interp(str,argptr.arg_str,sp);
+ st = stack->ary_array;
+ st[++sp] = str;
+#ifdef DEBUGGING
+ tmps = "DOUBLE";
+#endif
+ break;
+ case A_BACKTICK:
+ tmps = str_get(interp(str,argptr.arg_str,sp));
+ st = stack->ary_array;
+#ifdef TAINT
+ taintproper("Insecure dependency in ``");
+#endif
+ fp = mypopen(tmps,"r");
+ str_set(str,"");
+ if (fp) {
+ if (gimme == G_SCALAR) {
+ while (str_gets(str,fp,str->str_cur) != Nullch)
+ /*SUPPRESS 530*/
+ ;
+ }
+ else {
+ for (;;) {
+ if (++sp > stack->ary_max) {
+ astore(stack, sp, Nullstr);
+ st = stack->ary_array;
+ }
+ str = st[sp] = Str_new(56,80);
+ if (str_gets(str,fp,0) == Nullch) {
+ sp--;
+ break;
+ }
+ if (str->str_len - str->str_cur > 20) {
+ str->str_len = str->str_cur+1;
+ Renew(str->str_ptr, str->str_len, char);
+ }
+ str_2mortal(str);
+ }
+ }
+ statusvalue = mypclose(fp);
+ }
+ else
+ statusvalue = -1;
+
+ if (gimme == G_SCALAR)
+ st[++sp] = str;
+#ifdef DEBUGGING
+ tmps = "BACK";
+#endif
+ break;
+ case A_WANTARRAY:
+ {
+ if (curcsv->wantarray == G_ARRAY)
+ st[++sp] = &str_yes;
+ else
+ st[++sp] = &str_no;
+ }
+#ifdef DEBUGGING
+ tmps = "WANTARRAY";
+#endif
+ break;
+ case A_INDREAD:
+ last_in_stab = stabent(str_get(STAB_STR(argptr.arg_stab)),TRUE);
+ old_rschar = rschar;
+ old_rslen = rslen;
+ goto do_read;
+ case A_GLOB:
+ argflags |= AF_POST; /* enable newline chopping */
+ last_in_stab = argptr.arg_stab;
+ old_rschar = rschar;
+ old_rslen = rslen;
+ rslen = 1;
+#ifdef DOSISH
+ rschar = 0;
+#else
+#ifdef CSH
+ rschar = 0;
+#else
+ rschar = '\n';
+#endif /* !CSH */
+#endif /* !MSDOS */
+ goto do_read;
+ case A_READ:
+ last_in_stab = argptr.arg_stab;
+ old_rschar = rschar;
+ old_rslen = rslen;
+ do_read:
+ if (anum > 1) /* assign to scalar */
+ gimme = G_SCALAR; /* force context to scalar */
+ if (gimme == G_ARRAY)
+ str = Str_new(57,0);
+ ++sp;
+ fp = Nullfp;
+ if (stab_io(last_in_stab)) {
+ fp = stab_io(last_in_stab)->ifp;
+ if (!fp) {
+ if (stab_io(last_in_stab)->flags & IOF_ARGV) {
+ if (stab_io(last_in_stab)->flags & IOF_START) {
+ stab_io(last_in_stab)->flags &= ~IOF_START;
+ stab_io(last_in_stab)->lines = 0;
+ if (alen(stab_array(last_in_stab)) < 0) {
+ tmpstr = str_make("-",1); /* assume stdin */
+ (void)apush(stab_array(last_in_stab), tmpstr);
+ }
+ }
+ fp = nextargv(last_in_stab);
+ if (!fp) { /* Note: fp != stab_io(last_in_stab)->ifp */
+ (void)do_close(last_in_stab,FALSE); /* now it does*/
+ stab_io(last_in_stab)->flags |= IOF_START;
+ }
+ }
+ else if (argtype == A_GLOB) {
+ (void) interp(str,stab_val(last_in_stab),sp);
+ st = stack->ary_array;
+ tmpstr = Str_new(55,0);
+#ifdef DOSISH
+ str_set(tmpstr, "perlglob ");
+ str_scat(tmpstr,str);
+ str_cat(tmpstr," |");
+#else
+#ifdef CSH
+ str_nset(tmpstr,cshname,cshlen);
+ str_cat(tmpstr," -cf 'set nonomatch; glob ");
+ str_scat(tmpstr,str);
+ str_cat(tmpstr,"'|");
+#else
+ str_set(tmpstr, "echo ");
+ str_scat(tmpstr,str);
+ str_cat(tmpstr,
+ "|tr -s ' \t\f\r' '\\012\\012\\012\\012'|");
+#endif /* !CSH */
+#endif /* !MSDOS */
+ (void)do_open(last_in_stab,tmpstr->str_ptr,
+ tmpstr->str_cur);
+ fp = stab_io(last_in_stab)->ifp;
+ str_free(tmpstr);
+ }
+ }
+ }
+ if (!fp && dowarn)
+ warn("Read on closed filehandle <%s>",stab_ename(last_in_stab));
+ tmplen = str->str_len; /* remember if already alloced */
+ if (!tmplen)
+ Str_Grow(str,80); /* try short-buffering it */
+ keepgoing:
+ if (!fp)
+ st[sp] = &str_undef;
+ else if (!str_gets(str,fp, optype == O_RCAT ? str->str_cur : 0)) {
+ clearerr(fp);
+ if (stab_io(last_in_stab)->flags & IOF_ARGV) {
+ fp = nextargv(last_in_stab);
+ if (fp)
+ goto keepgoing;
+ (void)do_close(last_in_stab,FALSE);
+ stab_io(last_in_stab)->flags |= IOF_START;
+ }
+ else if (argflags & AF_POST) {
+ (void)do_close(last_in_stab,FALSE);
+ }
+ st[sp] = &str_undef;
+ rschar = old_rschar;
+ rslen = old_rslen;
+ if (gimme == G_ARRAY) {
+ --sp;
+ str_2mortal(str);
+ goto array_return;
+ }
+ break;
+ }
+ else {
+ stab_io(last_in_stab)->lines++;
+ st[sp] = str;
+#ifdef TAINT
+ str->str_tainted = 1; /* Anything from the outside world...*/
+#endif
+ if (argflags & AF_POST) {
+ if (str->str_cur > 0)
+ str->str_cur--;
+ if (str->str_ptr[str->str_cur] == rschar)
+ str->str_ptr[str->str_cur] = '\0';
+ else
+ str->str_cur++;
+ for (tmps = str->str_ptr; *tmps; tmps++)
+ if (!isALPHA(*tmps) && !isDIGIT(*tmps) &&
+ index("$&*(){}[]'\";\\|?<>~`",*tmps))
+ break;
+ if (*tmps && stat(str->str_ptr,&statbuf) < 0)
+ goto keepgoing; /* unmatched wildcard? */
+ }
+ if (gimme == G_ARRAY) {
+ if (str->str_len - str->str_cur > 20) {
+ str->str_len = str->str_cur+1;
+ Renew(str->str_ptr, str->str_len, char);
+ }
+ str_2mortal(str);
+ if (++sp > stack->ary_max) {
+ astore(stack, sp, Nullstr);
+ st = stack->ary_array;
+ }
+ str = Str_new(58,80);
+ goto keepgoing;
+ }
+ else if (!tmplen && str->str_len - str->str_cur > 80) {
+ /* try to reclaim a bit of scalar space on 1st alloc */
+ if (str->str_cur < 60)
+ str->str_len = 80;
+ else
+ str->str_len = str->str_cur+40; /* allow some slop */
+ Renew(str->str_ptr, str->str_len, char);
+ }
+ }
+ rschar = old_rschar;
+ rslen = old_rslen;
+#ifdef DEBUGGING
+ tmps = "READ";
+#endif
+ break;
+ }
+#ifdef DEBUGGING
+ if (debug & 8)
+ deb("%d.%s = '%s'\n",anum,tmps,str_peek(st[sp]));
+#endif
+ if (anum < 8)
+ arglast[anum] = sp;
+ }
+
+ st += arglast[0];
+#ifdef SMALLSWITCHES
+ if (optype < O_CHOWN)
+#endif
+ switch (optype) {
+ case O_RCAT:
+ STABSET(str);
+ break;
+ case O_ITEM:
+ if (gimme == G_ARRAY)
+ goto array_return;
+ /* FALL THROUGH */
+ case O_SCALAR:
+ STR_SSET(str,st[1]);
+ STABSET(str);
+ break;
+ case O_ITEM2:
+ if (gimme == G_ARRAY)
+ goto array_return;
+ --anum;
+ STR_SSET(str,st[arglast[anum]-arglast[0]]);
+ STABSET(str);
+ break;
+ case O_ITEM3:
+ if (gimme == G_ARRAY)
+ goto array_return;
+ --anum;
+ STR_SSET(str,st[arglast[anum]-arglast[0]]);
+ STABSET(str);
+ break;
+ case O_CONCAT:
+ STR_SSET(str,st[1]);
+ str_scat(str,st[2]);
+ STABSET(str);
+ break;
+ case O_REPEAT:
+ if (gimme == G_ARRAY && arg[1].arg_flags & AF_ARYOK) {
+ sp = do_repeatary(arglast);
+ goto array_return;
+ }
+ STR_SSET(str,st[1]);
+ anum = (int)str_gnum(st[2]);
+ if (anum >= 1) {
+ tmpstr = Str_new(50, 0);
+ tmps = str_get(str);
+ str_nset(tmpstr,tmps,str->str_cur);
+ tmps = str_get(tmpstr); /* force to be string */
+ STR_GROW(str, (anum * str->str_cur) + 1);
+ repeatcpy(str->str_ptr, tmps, tmpstr->str_cur, anum);
+ str->str_cur *= anum;
+ str->str_ptr[str->str_cur] = '\0';
+ str->str_nok = 0;
+ str_free(tmpstr);
+ }
+ else {
+ if (dowarn && st[2]->str_pok && !looks_like_number(st[2]))
+ warn("Right operand of x is not numeric");
+ str_sset(str,&str_no);
+ }
+ STABSET(str);
+ break;
+ case O_MATCH:
+ sp = do_match(str,arg,
+ gimme,arglast);
+ if (gimme == G_ARRAY)
+ goto array_return;
+ STABSET(str);
+ break;
+ case O_NMATCH:
+ sp = do_match(str,arg,
+ G_SCALAR,arglast);
+ str_sset(str, str_true(str) ? &str_no : &str_yes);
+ STABSET(str);
+ break;
+ case O_SUBST:
+ sp = do_subst(str,arg,arglast[0]);
+ goto array_return;
+ case O_NSUBST:
+ sp = do_subst(str,arg,arglast[0]);
+ str = arg->arg_ptr.arg_str;
+ str_set(str, str_true(str) ? No : Yes);
+ goto array_return;
+ case O_ASSIGN:
+ if (arg[1].arg_flags & AF_ARYOK) {
+ if (arg->arg_len == 1) {
+ arg->arg_type = O_LOCAL;
+ goto local;
+ }
+ else {
+ arg->arg_type = O_AASSIGN;
+ goto aassign;
+ }
+ }
+ else {
+ arg->arg_type = O_SASSIGN;
+ goto sassign;
+ }
+ case O_LOCAL:
+ local:
+ arglast[2] = arglast[1]; /* push a null array */
+ /* FALL THROUGH */
+ case O_AASSIGN:
+ aassign:
+ sp = do_assign(arg,
+ gimme,arglast);
+ goto array_return;
+ case O_SASSIGN:
+ sassign:
+#ifdef TAINT
+ if (tainted && !st[2]->str_tainted)
+ tainted = 0;
+#endif
+ STR_SSET(str, st[2]);
+ STABSET(str);
+ break;
+ case O_CHOP:
+ st -= arglast[0];
+ str = arg->arg_ptr.arg_str;
+ for (sp = arglast[0] + 1; sp <= arglast[1]; sp++)
+ do_chop(str,st[sp]);
+ st += arglast[0];
+ break;
+ case O_DEFINED:
+ if (arg[1].arg_type & A_DONT) {
+ sp = do_defined(str,arg,
+ gimme,arglast);
+ goto array_return;
+ }
+ else if (str->str_pok || str->str_nok)
+ goto say_yes;
+ goto say_no;
+ case O_UNDEF:
+ if (arg[1].arg_type & A_DONT) {
+ sp = do_undef(str,arg,
+ gimme,arglast);
+ goto array_return;
+ }
+ else if (str != stab_val(defstab)) {
+ if (str->str_len) {
+ if (str->str_state == SS_INCR)
+ Str_Grow(str,0);
+ Safefree(str->str_ptr);
+ str->str_ptr = Nullch;
+ str->str_len = 0;
+ }
+ str->str_pok = str->str_nok = 0;
+ STABSET(str);
+ }
+ goto say_undef;
+ case O_STUDY:
+ sp = do_study(str,arg,
+ gimme,arglast);
+ goto array_return;
+ case O_POW:
+ value = str_gnum(st[1]);
+ value = pow(value,str_gnum(st[2]));
+ goto donumset;
+ case O_MULTIPLY:
+ value = str_gnum(st[1]);
+ value *= str_gnum(st[2]);
+ goto donumset;
+ case O_DIVIDE:
+ if ((value = str_gnum(st[2])) == 0.0)
+ fatal("Illegal division by zero");
+#ifdef SLOPPYDIVIDE
+ /* insure that 20./5. == 4. */
+ {
+ double x;
+ int k;
+ x = str_gnum(st[1]);
+ if ((double)(int)x == x &&
+ (double)(int)value == value &&
+ (k = (int)x/(int)value)*(int)value == (int)x) {
+ value = k;
+ } else {
+ value = x/value;
+ }
+ }
+#else
+ value = str_gnum(st[1]) / value;
+#endif
+ goto donumset;
+ case O_MODULO:
+ tmpulong = (unsigned long) str_gnum(st[2]);
+ if (tmpulong == 0L)
+ fatal("Illegal modulus zero");
+#ifndef lint
+ value = str_gnum(st[1]);
+ if (value >= 0.0)
+ value = (double)(((unsigned long)value) % tmpulong);
+ else {
+ tmplong = (long)value;
+ value = (double)(tmpulong - ((-tmplong - 1) % tmpulong)) - 1;
+ }
+#endif
+ goto donumset;
+ case O_ADD:
+ value = str_gnum(st[1]);
+ value += str_gnum(st[2]);
+ goto donumset;
+ case O_SUBTRACT:
+ value = str_gnum(st[1]);
+ value -= str_gnum(st[2]);
+ goto donumset;
+ case O_LEFT_SHIFT:
+ value = str_gnum(st[1]);
+ anum = (int)str_gnum(st[2]);
+#ifndef lint
+ value = (double)(U_L(value) << anum);
+#endif
+ goto donumset;
+ case O_RIGHT_SHIFT:
+ value = str_gnum(st[1]);
+ anum = (int)str_gnum(st[2]);
+#ifndef lint
+ value = (double)(U_L(value) >> anum);
+#endif
+ goto donumset;
+ case O_LT:
+ value = str_gnum(st[1]);
+ value = (value < str_gnum(st[2])) ? 1.0 : 0.0;
+ goto donumset;
+ case O_GT:
+ value = str_gnum(st[1]);
+ value = (value > str_gnum(st[2])) ? 1.0 : 0.0;
+ goto donumset;
+ case O_LE:
+ value = str_gnum(st[1]);
+ value = (value <= str_gnum(st[2])) ? 1.0 : 0.0;
+ goto donumset;
+ case O_GE:
+ value = str_gnum(st[1]);
+ value = (value >= str_gnum(st[2])) ? 1.0 : 0.0;
+ goto donumset;
+ case O_EQ:
+ if (dowarn) {
+ if ((!st[1]->str_nok && !looks_like_number(st[1])) ||
+ (!st[2]->str_nok && !looks_like_number(st[2])) )
+ warn("Possible use of == on string value");
+ }
+ value = str_gnum(st[1]);
+ value = (value == str_gnum(st[2])) ? 1.0 : 0.0;
+ goto donumset;
+ case O_NE:
+ value = str_gnum(st[1]);
+ value = (value != str_gnum(st[2])) ? 1.0 : 0.0;
+ goto donumset;
+ case O_NCMP:
+ value = str_gnum(st[1]);
+ value -= str_gnum(st[2]);
+ if (value > 0.0)
+ value = 1.0;
+ else if (value < 0.0)
+ value = -1.0;
+ goto donumset;
+ case O_BIT_AND:
+ if (!sawvec || st[1]->str_nok || st[2]->str_nok) {
+ value = str_gnum(st[1]);
+#ifndef lint
+ value = (double)(U_L(value) & U_L(str_gnum(st[2])));
+#endif
+ goto donumset;
+ }
+ else
+ do_vop(optype,str,st[1],st[2]);
+ break;
+ case O_XOR:
+ if (!sawvec || st[1]->str_nok || st[2]->str_nok) {
+ value = str_gnum(st[1]);
+#ifndef lint
+ value = (double)(U_L(value) ^ U_L(str_gnum(st[2])));
+#endif
+ goto donumset;
+ }
+ else
+ do_vop(optype,str,st[1],st[2]);
+ break;
+ case O_BIT_OR:
+ if (!sawvec || st[1]->str_nok || st[2]->str_nok) {
+ value = str_gnum(st[1]);
+#ifndef lint
+ value = (double)(U_L(value) | U_L(str_gnum(st[2])));
+#endif
+ goto donumset;
+ }
+ else
+ do_vop(optype,str,st[1],st[2]);
+ break;
+/* use register in evaluating str_true() */
+ case O_AND:
+ if (str_true(st[1])) {
+ anum = 2;
+ optype = O_ITEM2;
+ argflags = arg[anum].arg_flags;
+ if (gimme == G_ARRAY)
+ argflags |= AF_ARYOK;
+ argtype = arg[anum].arg_type & A_MASK;
+ argptr = arg[anum].arg_ptr;
+ maxarg = anum = 1;
+ sp = arglast[0];
+ st -= sp;
+ goto re_eval;
+ }
+ else {
+ if (assigning) {
+ str_sset(str, st[1]);
+ STABSET(str);
+ }
+ else
+ str = st[1];
+ break;
+ }
+ case O_OR:
+ if (str_true(st[1])) {
+ if (assigning) {
+ str_sset(str, st[1]);
+ STABSET(str);
+ }
+ else
+ str = st[1];
+ break;
+ }
+ else {
+ anum = 2;
+ optype = O_ITEM2;
+ argflags = arg[anum].arg_flags;
+ if (gimme == G_ARRAY)
+ argflags |= AF_ARYOK;
+ argtype = arg[anum].arg_type & A_MASK;
+ argptr = arg[anum].arg_ptr;
+ maxarg = anum = 1;
+ sp = arglast[0];
+ st -= sp;
+ goto re_eval;
+ }
+ case O_COND_EXPR:
+ anum = (str_true(st[1]) ? 2 : 3);
+ optype = (anum == 2 ? O_ITEM2 : O_ITEM3);
+ argflags = arg[anum].arg_flags;
+ if (gimme == G_ARRAY)
+ argflags |= AF_ARYOK;
+ argtype = arg[anum].arg_type & A_MASK;
+ argptr = arg[anum].arg_ptr;
+ maxarg = anum = 1;
+ sp = arglast[0];
+ st -= sp;
+ goto re_eval;
+ case O_COMMA:
+ if (gimme == G_ARRAY)
+ goto array_return;
+ str = st[2];
+ break;
+ case O_NEGATE:
+ value = -str_gnum(st[1]);
+ goto donumset;
+ case O_NOT:
+#ifdef NOTNOT
+ { char xxx = str_true(st[1]); value = (double) !xxx; }
+#else
+ value = (double) !str_true(st[1]);
+#endif
+ goto donumset;
+ case O_COMPLEMENT:
+ if (!sawvec || st[1]->str_nok) {
+#ifndef lint
+ value = (double) ~U_L(str_gnum(st[1]));
+#endif
+ goto donumset;
+ }
+ else {
+ STR_SSET(str,st[1]);
+ tmps = str_get(str);
+ for (anum = str->str_cur; anum; anum--, tmps++)
+ *tmps = ~*tmps;
+ }
+ break;
+ case O_SELECT:
+ stab_efullname(str,defoutstab);
+ if (maxarg > 0) {
+ if ((arg[1].arg_type & A_MASK) == A_WORD)
+ defoutstab = arg[1].arg_ptr.arg_stab;
+ else
+ defoutstab = stabent(str_get(st[1]),TRUE);
+ if (!stab_io(defoutstab))
+ stab_io(defoutstab) = stio_new();
+ curoutstab = defoutstab;
+ }
+ STABSET(str);
+ break;
+ case O_WRITE:
+ if (maxarg == 0)
+ stab = defoutstab;
+ else if ((arg[1].arg_type & A_MASK) == A_WORD) {
+ if (!(stab = arg[1].arg_ptr.arg_stab))
+ stab = defoutstab;
+ }
+ else
+ stab = stabent(str_get(st[1]),TRUE);
+ if (!stab_io(stab)) {
+ str_set(str, No);
+ STABSET(str);
+ break;
+ }
+ curoutstab = stab;
+ fp = stab_io(stab)->ofp;
+ debarg = arg;
+ if (stab_io(stab)->fmt_stab)
+ form = stab_form(stab_io(stab)->fmt_stab);
+ else
+ form = stab_form(stab);
+ if (!form || !fp) {
+ if (dowarn) {
+ if (form)
+ warn("No format for filehandle");
+ else {
+ if (stab_io(stab)->ifp)
+ warn("Filehandle only opened for input");
+ else
+ warn("Write on closed filehandle");
+ }
+ }
+ str_set(str, No);
+ STABSET(str);
+ break;
+ }
+ format(&outrec,form,sp);
+ do_write(&outrec,stab,sp);
+ if (stab_io(stab)->flags & IOF_FLUSH)
+ (void)fflush(fp);
+ str_set(str, Yes);
+ STABSET(str);
+ break;
+ case O_DBMOPEN:
+#ifdef SOME_DBM
+ anum = arg[1].arg_type & A_MASK;
+ if (anum == A_WORD || anum == A_STAB)
+ stab = arg[1].arg_ptr.arg_stab;
+ else
+ stab = stabent(str_get(st[1]),TRUE);
+ if (st[3]->str_nok || st[3]->str_pok)
+ anum = (int)str_gnum(st[3]);
+ else
+ anum = -1;
+ value = (double)hdbmopen(stab_hash(stab),str_get(st[2]),anum);
+ goto donumset;
+#else
+ fatal("No dbm or ndbm on this machine");
+#endif
+ case O_DBMCLOSE:
+#ifdef SOME_DBM
+ anum = arg[1].arg_type & A_MASK;
+ if (anum == A_WORD || anum == A_STAB)
+ stab = arg[1].arg_ptr.arg_stab;
+ else
+ stab = stabent(str_get(st[1]),TRUE);
+ hdbmclose(stab_hash(stab));
+ goto say_yes;
+#else
+ fatal("No dbm or ndbm on this machine");
+#endif
+ case O_OPEN:
+ if ((arg[1].arg_type & A_MASK) == A_WORD)
+ stab = arg[1].arg_ptr.arg_stab;
+ else
+ stab = stabent(str_get(st[1]),TRUE);
+ tmps = str_get(st[2]);
+ if (do_open(stab,tmps,st[2]->str_cur)) {
+ value = (double)forkprocess;
+ stab_io(stab)->lines = 0;
+ goto donumset;
+ }
+ else if (forkprocess == 0) /* we are a new child */
+ goto say_zero;
+ else
+ goto say_undef;
+ /* break; */
+ case O_TRANS:
+ value = (double) do_trans(str,arg);
+ str = arg->arg_ptr.arg_str;
+ goto donumset;
+ case O_NTRANS:
+ str_set(arg->arg_ptr.arg_str, do_trans(str,arg) == 0 ? Yes : No);
+ str = arg->arg_ptr.arg_str;
+ break;
+ case O_CLOSE:
+ if (maxarg == 0)
+ stab = defoutstab;
+ else if ((arg[1].arg_type & A_MASK) == A_WORD)
+ stab = arg[1].arg_ptr.arg_stab;
+ else
+ stab = stabent(str_get(st[1]),TRUE);
+ str_set(str, do_close(stab,TRUE) ? Yes : No );
+ STABSET(str);
+ break;
+ case O_EACH:
+ sp = do_each(str,stab_hash(arg[1].arg_ptr.arg_stab),
+ gimme,arglast);
+ goto array_return;
+ case O_VALUES:
+ case O_KEYS:
+ sp = do_kv(str,stab_hash(arg[1].arg_ptr.arg_stab), optype,
+ gimme,arglast);
+ goto array_return;
+ case O_LARRAY:
+ str->str_nok = str->str_pok = 0;
+ str->str_u.str_stab = arg[1].arg_ptr.arg_stab;
+ str->str_state = SS_ARY;
+ break;
+ case O_ARRAY:
+ ary = stab_array(arg[1].arg_ptr.arg_stab);
+ maxarg = ary->ary_fill + 1;
+ if (gimme == G_ARRAY) { /* array wanted */
+ sp = arglast[0];
+ st -= sp;
+ if (maxarg > 0 && sp + maxarg > stack->ary_max) {
+ astore(stack,sp + maxarg, Nullstr);
+ st = stack->ary_array;
+ }
+ st += sp;
+ Copy(ary->ary_array, &st[1], maxarg, STR*);
+ sp += maxarg;
+ goto array_return;
+ }
+ else {
+ value = (double)maxarg;
+ goto donumset;
+ }
+ case O_AELEM:
+ anum = ((int)str_gnum(st[2])) - arybase;
+ str = afetch(stab_array(arg[1].arg_ptr.arg_stab),anum,FALSE);
+ break;
+ case O_DELETE:
+ tmpstab = arg[1].arg_ptr.arg_stab;
+ tmps = str_get(st[2]);
+ str = hdelete(stab_hash(tmpstab),tmps,st[2]->str_cur);
+ if (tmpstab == envstab)
+ my_setenv(tmps,Nullch);
+ if (!str)
+ goto say_undef;
+ break;
+ case O_LHASH:
+ str->str_nok = str->str_pok = 0;
+ str->str_u.str_stab = arg[1].arg_ptr.arg_stab;
+ str->str_state = SS_HASH;
+ break;
+ case O_HASH:
+ if (gimme == G_ARRAY) { /* array wanted */
+ sp = do_kv(str,stab_hash(arg[1].arg_ptr.arg_stab), optype,
+ gimme,arglast);
+ goto array_return;
+ }
+ else {
+ tmpstab = arg[1].arg_ptr.arg_stab;
+ if (!stab_hash(tmpstab)->tbl_fill)
+ goto say_zero;
+ sprintf(buf,"%d/%d",stab_hash(tmpstab)->tbl_fill,
+ stab_hash(tmpstab)->tbl_max+1);
+ str_set(str,buf);
+ }
+ break;
+ case O_HELEM:
+ tmpstab = arg[1].arg_ptr.arg_stab;
+ tmps = str_get(st[2]);
+ str = hfetch(stab_hash(tmpstab),tmps,st[2]->str_cur,FALSE);
+ break;
+ case O_LAELEM:
+ anum = ((int)str_gnum(st[2])) - arybase;
+ str = afetch(stab_array(arg[1].arg_ptr.arg_stab),anum,TRUE);
+ if (!str || str == &str_undef)
+ fatal("Assignment to non-creatable value, subscript %d",anum);
+ break;
+ case O_LHELEM:
+ tmpstab = arg[1].arg_ptr.arg_stab;
+ tmps = str_get(st[2]);
+ anum = st[2]->str_cur;
+ str = hfetch(stab_hash(tmpstab),tmps,anum,TRUE);
+ if (!str || str == &str_undef)
+ fatal("Assignment to non-creatable value, subscript \"%s\"",tmps);
+ if (tmpstab == envstab) /* heavy wizardry going on here */
+ str_magic(str, tmpstab, 'E', tmps, anum); /* str is now magic */
+ /* he threw the brick up into the air */
+ else if (tmpstab == sigstab)
+ str_magic(str, tmpstab, 'S', tmps, anum);
+#ifdef SOME_DBM
+ else if (stab_hash(tmpstab)->tbl_dbm)
+ str_magic(str, tmpstab, 'D', tmps, anum);
+#endif
+ else if (tmpstab == DBline)
+ str_magic(str, tmpstab, 'L', tmps, anum);
+ break;
+ case O_LSLICE:
+ anum = 2;
+ argtype = FALSE;
+ goto do_slice_already;
+ case O_ASLICE:
+ anum = 1;
+ argtype = FALSE;
+ goto do_slice_already;
+ case O_HSLICE:
+ anum = 0;
+ argtype = FALSE;
+ goto do_slice_already;
+ case O_LASLICE:
+ anum = 1;
+ argtype = TRUE;
+ goto do_slice_already;
+ case O_LHSLICE:
+ anum = 0;
+ argtype = TRUE;
+ do_slice_already:
+ sp = do_slice(arg[1].arg_ptr.arg_stab,str,anum,argtype,
+ gimme,arglast);
+ goto array_return;
+ case O_SPLICE:
+ sp = do_splice(stab_array(arg[1].arg_ptr.arg_stab),gimme,arglast);
+ goto array_return;
+ case O_PUSH:
+ if (arglast[2] - arglast[1] != 1)
+ str = do_push(stab_array(arg[1].arg_ptr.arg_stab),arglast);
+ else {
+ str = Str_new(51,0); /* must copy the STR */
+ str_sset(str,st[2]);
+ (void)apush(stab_array(arg[1].arg_ptr.arg_stab),str);
+ }
+ break;
+ case O_POP:
+ str = apop(ary = stab_array(arg[1].arg_ptr.arg_stab));
+ goto staticalization;
+ case O_SHIFT:
+ str = ashift(ary = stab_array(arg[1].arg_ptr.arg_stab));
+ staticalization:
+ if (!str)
+ goto say_undef;
+ if (ary->ary_flags & ARF_REAL)
+ (void)str_2mortal(str);
+ break;
+ case O_UNPACK:
+ sp = do_unpack(str,gimme,arglast);
+ goto array_return;
+ case O_SPLIT:
+ value = str_gnum(st[3]);
+ sp = do_split(str, arg[2].arg_ptr.arg_spat, (int)value,
+ gimme,arglast);
+ goto array_return;
+ case O_LENGTH:
+ if (maxarg < 1)
+ value = (double)str_len(stab_val(defstab));
+ else
+ value = (double)str_len(st[1]);
+ goto donumset;
+ case O_SPRINTF:
+ do_sprintf(str, sp-arglast[0], st+1);
+ break;
+ case O_SUBSTR:
+ anum = ((int)str_gnum(st[2])) - arybase; /* anum=where to start*/
+ tmps = str_get(st[1]); /* force conversion to string */
+ /*SUPPRESS 560*/
+ if (argtype = (str == st[1]))
+ str = arg->arg_ptr.arg_str;
+ if (anum < 0)
+ anum += st[1]->str_cur + arybase;
+ if (anum < 0 || anum > st[1]->str_cur)
+ str_nset(str,"",0);
+ else {
+ optype = maxarg < 3 ? st[1]->str_cur : (int)str_gnum(st[3]);
+ if (optype < 0)
+ optype = 0;
+ tmps += anum;
+ anum = st[1]->str_cur - anum; /* anum=how many bytes left*/
+ if (anum > optype)
+ anum = optype;
+ str_nset(str, tmps, anum);
+ if (argtype) { /* it's an lvalue! */
+ lstr = (struct lstring*)str;
+ str->str_magic = st[1];
+ st[1]->str_rare = 's';
+ lstr->lstr_offset = tmps - str_get(st[1]);
+ lstr->lstr_len = anum;
+ }
+ }
+ break;
+ case O_PACK:
+ /*SUPPRESS 701*/
+ (void)do_pack(str,arglast);
+ break;
+ case O_GREP:
+ sp = do_grep(arg,str,gimme,arglast);
+ goto array_return;
+ case O_JOIN:
+ do_join(str,arglast);
+ break;
+ case O_SLT:
+ tmps = str_get(st[1]);
+ value = (double) (str_cmp(st[1],st[2]) < 0);
+ goto donumset;
+ case O_SGT:
+ tmps = str_get(st[1]);
+ value = (double) (str_cmp(st[1],st[2]) > 0);
+ goto donumset;
+ case O_SLE:
+ tmps = str_get(st[1]);
+ value = (double) (str_cmp(st[1],st[2]) <= 0);
+ goto donumset;
+ case O_SGE:
+ tmps = str_get(st[1]);
+ value = (double) (str_cmp(st[1],st[2]) >= 0);
+ goto donumset;
+ case O_SEQ:
+ tmps = str_get(st[1]);
+ value = (double) str_eq(st[1],st[2]);
+ goto donumset;
+ case O_SNE:
+ tmps = str_get(st[1]);
+ value = (double) !str_eq(st[1],st[2]);
+ goto donumset;
+ case O_SCMP:
+ tmps = str_get(st[1]);
+ value = (double) str_cmp(st[1],st[2]);
+ goto donumset;
+ case O_SUBR:
+ sp = do_subr(arg,gimme,arglast);
+ st = stack->ary_array + arglast[0]; /* maybe realloced */
+ goto array_return;
+ case O_DBSUBR:
+ sp = do_subr(arg,gimme,arglast);
+ st = stack->ary_array + arglast[0]; /* maybe realloced */
+ goto array_return;
+ case O_CALLER:
+ sp = do_caller(arg,maxarg,gimme,arglast);
+ st = stack->ary_array + arglast[0]; /* maybe realloced */
+ goto array_return;
+ case O_SORT:
+ sp = do_sort(str,arg,
+ gimme,arglast);
+ goto array_return;
+ case O_REVERSE:
+ if (gimme == G_ARRAY)
+ sp = do_reverse(arglast);
+ else
+ sp = do_sreverse(str, arglast);
+ goto array_return;
+ case O_WARN:
+ if (arglast[2] - arglast[1] != 1) {
+ do_join(str,arglast);
+ tmps = str_get(str);
+ }
+ else {
+ str = st[2];
+ tmps = str_get(st[2]);
+ }
+ if (!tmps || !*tmps)
+ tmps = "Warning: something's wrong";
+ warn("%s",tmps);
+ goto say_yes;
+ case O_DIE:
+ if (arglast[2] - arglast[1] != 1) {
+ do_join(str,arglast);
+ tmps = str_get(str);
+ }
+ else {
+ str = st[2];
+ tmps = str_get(st[2]);
+ }
+ if (!tmps || !*tmps)
+ tmps = "Died";
+ fatal("%s",tmps);
+ goto say_zero;
+ case O_PRTF:
+ case O_PRINT:
+ if ((arg[1].arg_type & A_MASK) == A_WORD)
+ stab = arg[1].arg_ptr.arg_stab;
+ else
+ stab = stabent(str_get(st[1]),TRUE);
+ if (!stab)
+ stab = defoutstab;
+ if (!stab_io(stab)) {
+ if (dowarn)
+ warn("Filehandle never opened");
+ goto say_zero;
+ }
+ if (!(fp = stab_io(stab)->ofp)) {
+ if (dowarn) {
+ if (stab_io(stab)->ifp)
+ warn("Filehandle opened only for input");
+ else
+ warn("Print on closed filehandle");
+ }
+ goto say_zero;
+ }
+ else {
+ if (optype == O_PRTF || arglast[2] - arglast[1] != 1)
+ value = (double)do_aprint(arg,fp,arglast);
+ else {
+ value = (double)do_print(st[2],fp);
+ if (orslen && optype == O_PRINT)
+ if (fwrite(ors, 1, orslen, fp) == 0)
+ goto say_zero;
+ }
+ if (stab_io(stab)->flags & IOF_FLUSH)
+ if (fflush(fp) == EOF)
+ goto say_zero;
+ }
+ goto donumset;
+ case O_CHDIR:
+ if (maxarg < 1)
+ tmps = Nullch;
+ else
+ tmps = str_get(st[1]);
+ if (!tmps || !*tmps) {
+ tmpstr = hfetch(stab_hash(envstab),"HOME",4,FALSE);
+ tmps = str_get(tmpstr);
+ }
+ if (!tmps || !*tmps) {
+ tmpstr = hfetch(stab_hash(envstab),"LOGDIR",6,FALSE);
+ tmps = str_get(tmpstr);
+ }
+#ifdef TAINT
+ taintproper("Insecure dependency in chdir");
+#endif
+ value = (double)(chdir(tmps) >= 0);
+ goto donumset;
+ case O_EXIT:
+ if (maxarg < 1)
+ anum = 0;
+ else
+ anum = (int)str_gnum(st[1]);
+ exit(anum);
+ goto say_zero;
+ case O_RESET:
+ if (maxarg < 1)
+ tmps = "";
+ else
+ tmps = str_get(st[1]);
+ str_reset(tmps,curcmd->c_stash);
+ value = 1.0;
+ goto donumset;
+ case O_LIST:
+ if (gimme == G_ARRAY)
+ goto array_return;
+ if (maxarg > 0)
+ str = st[sp - arglast[0]]; /* unwanted list, return last item */
+ else
+ str = &str_undef;
+ break;
+ case O_EOF:
+ if (maxarg <= 0)
+ stab = last_in_stab;
+ else if ((arg[1].arg_type & A_MASK) == A_WORD)
+ stab = arg[1].arg_ptr.arg_stab;
+ else
+ stab = stabent(str_get(st[1]),TRUE);
+ str_set(str, do_eof(stab) ? Yes : No);
+ STABSET(str);
+ break;
+ case O_GETC:
+ if (maxarg <= 0)
+ stab = stdinstab;
+ else if ((arg[1].arg_type & A_MASK) == A_WORD)
+ stab = arg[1].arg_ptr.arg_stab;
+ else
+ stab = stabent(str_get(st[1]),TRUE);
+ if (!stab)
+ stab = argvstab;
+ if (!stab || do_eof(stab)) /* make sure we have fp with something */
+ goto say_undef;
+ else {
+#ifdef TAINT
+ tainted = 1;
+#endif
+ str_set(str," ");
+ *str->str_ptr = getc(stab_io(stab)->ifp); /* should never be EOF */
+ }
+ STABSET(str);
+ break;
+ case O_TELL:
+ if (maxarg <= 0)
+ stab = last_in_stab;
+ else if ((arg[1].arg_type & A_MASK) == A_WORD)
+ stab = arg[1].arg_ptr.arg_stab;
+ else
+ stab = stabent(str_get(st[1]),TRUE);
+#ifndef lint
+ value = (double)do_tell(stab);
+#else
+ (void)do_tell(stab);
+#endif
+ goto donumset;
+ case O_RECV:
+ case O_READ:
+ case O_SYSREAD:
+ if ((arg[1].arg_type & A_MASK) == A_WORD)
+ stab = arg[1].arg_ptr.arg_stab;
+ else
+ stab = stabent(str_get(st[1]),TRUE);
+ tmps = str_get(st[2]);
+ anum = (int)str_gnum(st[3]);
+ errno = 0;
+ maxarg = sp - arglast[0];
+ if (maxarg > 4)
+ warn("Too many args on read");
+ if (maxarg == 4)
+ maxarg = (int)str_gnum(st[4]);
+ else
+ maxarg = 0;
+ if (!stab_io(stab) || !stab_io(stab)->ifp)
+ goto say_undef;
+#ifdef HAS_SOCKET
+ if (optype == O_RECV) {
+ argtype = sizeof buf;
+ STR_GROW(st[2], anum+1), (tmps = str_get(st[2])); /* sneaky */
+ anum = recvfrom(fileno(stab_io(stab)->ifp), tmps, anum, maxarg,
+ buf, &argtype);
+ if (anum >= 0) {
+ st[2]->str_cur = anum;
+ st[2]->str_ptr[anum] = '\0';
+ str_nset(str,buf,argtype);
+ }
+ else
+ str_sset(str,&str_undef);
+ break;
+ }
+#else
+ if (optype == O_RECV)
+ goto badsock;
+#endif
+ STR_GROW(st[2], anum+maxarg+1), (tmps = str_get(st[2])); /* sneaky */
+ if (optype == O_SYSREAD) {
+ anum = read(fileno(stab_io(stab)->ifp), tmps+maxarg, anum);
+ }
+ else
+#ifdef HAS_SOCKET
+ if (stab_io(stab)->type == 's') {
+ argtype = sizeof buf;
+ anum = recvfrom(fileno(stab_io(stab)->ifp), tmps+maxarg, anum, 0,
+ buf, &argtype);
+ }
+ else
+#endif
+ anum = fread(tmps+maxarg, 1, anum, stab_io(stab)->ifp);
+ if (anum < 0)
+ goto say_undef;
+ st[2]->str_cur = anum+maxarg;
+ st[2]->str_ptr[anum+maxarg] = '\0';
+ value = (double)anum;
+ goto donumset;
+ case O_SYSWRITE:
+ case O_SEND:
+ if ((arg[1].arg_type & A_MASK) == A_WORD)
+ stab = arg[1].arg_ptr.arg_stab;
+ else
+ stab = stabent(str_get(st[1]),TRUE);
+ tmps = str_get(st[2]);
+ anum = (int)str_gnum(st[3]);
+ errno = 0;
+ stio = stab_io(stab);
+ maxarg = sp - arglast[0];
+ if (!stio || !stio->ifp) {
+ anum = -1;
+ if (dowarn) {
+ if (optype == O_SYSWRITE)
+ warn("Syswrite on closed filehandle");
+ else
+ warn("Send on closed socket");
+ }
+ }
+ else if (optype == O_SYSWRITE) {
+ if (maxarg > 4)
+ warn("Too many args on syswrite");
+ if (maxarg == 4)
+ optype = (int)str_gnum(st[4]);
+ else
+ optype = 0;
+ anum = write(fileno(stab_io(stab)->ifp), tmps+optype, anum);
+ }
+#ifdef HAS_SOCKET
+ else if (maxarg >= 4) {
+ if (maxarg > 4)
+ warn("Too many args on send");
+ tmps2 = str_get(st[4]);
+ anum = sendto(fileno(stab_io(stab)->ifp), tmps, st[2]->str_cur,
+ anum, tmps2, st[4]->str_cur);
+ }
+ else
+ anum = send(fileno(stab_io(stab)->ifp), tmps, st[2]->str_cur, anum);
+#else
+ else
+ goto badsock;
+#endif
+ if (anum < 0)
+ goto say_undef;
+ value = (double)anum;
+ goto donumset;
+ case O_SEEK:
+ if ((arg[1].arg_type & A_MASK) == A_WORD)
+ stab = arg[1].arg_ptr.arg_stab;
+ else
+ stab = stabent(str_get(st[1]),TRUE);
+ value = str_gnum(st[2]);
+ str_set(str, do_seek(stab,
+ (long)value, (int)str_gnum(st[3]) ) ? Yes : No);
+ STABSET(str);
+ break;
+ case O_RETURN:
+ tmps = "_SUB_"; /* just fake up a "last _SUB_" */
+ optype = O_LAST;
+ if (curcsv && curcsv->wantarray == G_ARRAY) {
+ lastretstr = Nullstr;
+ lastspbase = arglast[1];
+ lastsize = arglast[2] - arglast[1];
+ }
+ else
+ lastretstr = str_mortal(st[arglast[2] - arglast[0]]);
+ goto dopop;
+ case O_REDO:
+ case O_NEXT:
+ case O_LAST:
+ tmps = Nullch;
+ if (maxarg > 0) {
+ tmps = str_get(arg[1].arg_ptr.arg_str);
+ dopop:
+ while (loop_ptr >= 0 && (!loop_stack[loop_ptr].loop_label ||
+ strNE(tmps,loop_stack[loop_ptr].loop_label) )) {
+#ifdef DEBUGGING
+ if (debug & 4) {
+ deb("(Skipping label #%d %s)\n",loop_ptr,
+ loop_stack[loop_ptr].loop_label);
+ }
+#endif
+ loop_ptr--;
+ }
+#ifdef DEBUGGING
+ if (debug & 4) {
+ deb("(Found label #%d %s)\n",loop_ptr,
+ loop_stack[loop_ptr].loop_label);
+ }
+#endif
+ }
+ if (loop_ptr < 0) {
+ if (tmps && strEQ(tmps, "_SUB_"))
+ fatal("Can't return outside a subroutine");
+ fatal("Bad label: %s", maxarg > 0 ? tmps : "<null>");
+ }
+ if (!lastretstr && optype == O_LAST && lastsize) {
+ st -= arglast[0];
+ st += lastspbase + 1;
+ optype = loop_stack[loop_ptr].loop_sp - lastspbase; /* negative */
+ if (optype) {
+ for (anum = lastsize; anum > 0; anum--,st++)
+ st[optype] = str_mortal(st[0]);
+ }
+ longjmp(loop_stack[loop_ptr].loop_env, O_LAST);
+ }
+ longjmp(loop_stack[loop_ptr].loop_env, optype);
+ case O_DUMP:
+ case O_GOTO:/* shudder */
+ goto_targ = str_get(arg[1].arg_ptr.arg_str);
+ if (!*goto_targ)
+ goto_targ = Nullch; /* just restart from top */
+ if (optype == O_DUMP) {
+ do_undump = 1;
+ my_unexec();
+ }
+ longjmp(top_env, 1);
+ case O_INDEX:
+ tmps = str_get(st[1]);
+ if (maxarg < 3)
+ anum = 0;
+ else {
+ anum = (int) str_gnum(st[3]) - arybase;
+ if (anum < 0)
+ anum = 0;
+ else if (anum > st[1]->str_cur)
+ anum = st[1]->str_cur;
+ }
+#ifndef lint
+ if (!(tmps2 = fbminstr((unsigned char*)tmps + anum,
+ (unsigned char*)tmps + st[1]->str_cur, st[2])))
+#else
+ if (tmps2 = fbminstr(Null(unsigned char*),Null(unsigned char*),Nullstr))
+#endif
+ value = (double)(-1 + arybase);
+ else
+ value = (double)(tmps2 - tmps + arybase);
+ goto donumset;
+ case O_RINDEX:
+ tmps = str_get(st[1]);
+ tmps2 = str_get(st[2]);
+ if (maxarg < 3)
+ anum = st[1]->str_cur;
+ else {
+ anum = (int) str_gnum(st[3]) - arybase + st[2]->str_cur;
+ if (anum < 0)
+ anum = 0;
+ else if (anum > st[1]->str_cur)
+ anum = st[1]->str_cur;
+ }
+#ifndef lint
+ if (!(tmps2 = rninstr(tmps, tmps + anum,
+ tmps2, tmps2 + st[2]->str_cur)))
+#else
+ if (tmps2 = rninstr(Nullch,Nullch,Nullch,Nullch))
+#endif
+ value = (double)(-1 + arybase);
+ else
+ value = (double)(tmps2 - tmps + arybase);
+ goto donumset;
+ case O_TIME:
+#ifndef lint
+ value = (double) time(Null(long*));
+#endif
+ goto donumset;
+ case O_TMS:
+ sp = do_tms(str,gimme,arglast);
+ goto array_return;
+ case O_LOCALTIME:
+ if (maxarg < 1)
+ (void)time(&when);
+ else
+ when = (time_t)str_gnum(st[1]);
+ sp = do_time(str,localtime(&when),
+ gimme,arglast);
+ goto array_return;
+ case O_GMTIME:
+ if (maxarg < 1)
+ (void)time(&when);
+ else
+ when = (time_t)str_gnum(st[1]);
+ sp = do_time(str,gmtime(&when),
+ gimme,arglast);
+ goto array_return;
+ case O_TRUNCATE:
+ sp = do_truncate(str,arg,
+ gimme,arglast);
+ goto array_return;
+ case O_LSTAT:
+ case O_STAT:
+ sp = do_stat(str,arg,
+ gimme,arglast);
+ goto array_return;
+ case O_CRYPT:
+#ifdef HAS_CRYPT
+ tmps = str_get(st[1]);
+#ifdef FCRYPT
+ str_set(str,fcrypt(tmps,str_get(st[2])));
+#else
+ str_set(str,crypt(tmps,str_get(st[2])));
+#endif
+#else
+ fatal(
+ "The crypt() function is unimplemented due to excessive paranoia.");
+#endif
+ break;
+ case O_ATAN2:
+ value = str_gnum(st[1]);
+ value = atan2(value,str_gnum(st[2]));
+ goto donumset;
+ case O_SIN:
+ if (maxarg < 1)
+ value = str_gnum(stab_val(defstab));
+ else
+ value = str_gnum(st[1]);
+ value = sin(value);
+ goto donumset;
+ case O_COS:
+ if (maxarg < 1)
+ value = str_gnum(stab_val(defstab));
+ else
+ value = str_gnum(st[1]);
+ value = cos(value);
+ goto donumset;
+ case O_RAND:
+ if (maxarg < 1)
+ value = 1.0;
+ else
+ value = str_gnum(st[1]);
+ if (value == 0.0)
+ value = 1.0;
+#if RANDBITS == 31
+ value = rand() * value / 2147483648.0;
+#else
+#if RANDBITS == 16
+ value = rand() * value / 65536.0;
+#else
+#if RANDBITS == 15
+ value = rand() * value / 32768.0;
+#else
+ value = rand() * value / (double)(((unsigned long)1) << RANDBITS);
+#endif
+#endif
+#endif
+ goto donumset;
+ case O_SRAND:
+ if (maxarg < 1) {
+ (void)time(&when);
+ anum = when;
+ }
+ else
+ anum = (int)str_gnum(st[1]);
+ (void)srand(anum);
+ goto say_yes;
+ case O_EXP:
+ if (maxarg < 1)
+ value = str_gnum(stab_val(defstab));
+ else
+ value = str_gnum(st[1]);
+ value = exp(value);
+ goto donumset;
+ case O_LOG:
+ if (maxarg < 1)
+ value = str_gnum(stab_val(defstab));
+ else
+ value = str_gnum(st[1]);
+ if (value <= 0.0)
+ fatal("Can't take log of %g\n", value);
+ value = log(value);
+ goto donumset;
+ case O_SQRT:
+ if (maxarg < 1)
+ value = str_gnum(stab_val(defstab));
+ else
+ value = str_gnum(st[1]);
+ if (value < 0.0)
+ fatal("Can't take sqrt of %g\n", value);
+ value = sqrt(value);
+ goto donumset;
+ case O_INT:
+ if (maxarg < 1)
+ value = str_gnum(stab_val(defstab));
+ else
+ value = str_gnum(st[1]);
+ if (value >= 0.0)
+ (void)modf(value,&value);
+ else {
+ (void)modf(-value,&value);
+ value = -value;
+ }
+ goto donumset;
+ case O_ORD:
+ if (maxarg < 1)
+ tmps = str_get(stab_val(defstab));
+ else
+ tmps = str_get(st[1]);
+#ifndef I286
+ value = (double) (*tmps & 255);
+#else
+ anum = (int) *tmps;
+ value = (double) (anum & 255);
+#endif
+ goto donumset;
+ case O_ALARM:
+#ifdef HAS_ALARM
+ if (maxarg < 1)
+ tmps = str_get(stab_val(defstab));
+ else
+ tmps = str_get(st[1]);
+ if (!tmps)
+ tmps = "0";
+ anum = alarm((unsigned int)atoi(tmps));
+ if (anum < 0)
+ goto say_undef;
+ value = (double)anum;
+ goto donumset;
+#else
+ fatal("Unsupported function alarm");
+ break;
+#endif
+ case O_SLEEP:
+ if (maxarg < 1)
+ tmps = Nullch;
+ else
+ tmps = str_get(st[1]);
+ (void)time(&when);
+ if (!tmps || !*tmps)
+ sleep((32767<<16)+32767);
+ else
+ sleep((unsigned int)atoi(tmps));
+#ifndef lint
+ value = (double)when;
+ (void)time(&when);
+ value = ((double)when) - value;
+#endif
+ goto donumset;
+ case O_RANGE:
+ sp = do_range(gimme,arglast);
+ goto array_return;
+ case O_F_OR_R:
+ if (gimme == G_ARRAY) { /* it's a range */
+ /* can we optimize to constant array? */
+ if ((arg[1].arg_type & A_MASK) == A_SINGLE &&
+ (arg[2].arg_type & A_MASK) == A_SINGLE) {
+ st[2] = arg[2].arg_ptr.arg_str;
+ sp = do_range(gimme,arglast);
+ st = stack->ary_array;
+ maxarg = sp - arglast[0];
+ str_free(arg[1].arg_ptr.arg_str);
+ arg[1].arg_ptr.arg_str = Nullstr;
+ str_free(arg[2].arg_ptr.arg_str);
+ arg[2].arg_ptr.arg_str = Nullstr;
+ arg->arg_type = O_ARRAY;
+ arg[1].arg_type = A_STAB|A_DONT;
+ arg->arg_len = 1;
+ stab = arg[1].arg_ptr.arg_stab = aadd(genstab());
+ ary = stab_array(stab);
+ afill(ary,maxarg - 1);
+ anum = maxarg;
+ st += arglast[0]+1;
+ while (maxarg-- > 0)
+ ary->ary_array[maxarg] = str_smake(st[maxarg]);
+ st -= arglast[0]+1;
+ goto array_return;
+ }
+ arg->arg_type = optype = O_RANGE;
+ maxarg = arg->arg_len = 2;
+ anum = 2;
+ arg[anum].arg_flags &= ~AF_ARYOK;
+ argflags = arg[anum].arg_flags;
+ argtype = arg[anum].arg_type & A_MASK;
+ arg[anum].arg_type = argtype;
+ argptr = arg[anum].arg_ptr;
+ sp = arglast[0];
+ st -= sp;
+ sp++;
+ goto re_eval;
+ }
+ arg->arg_type = O_FLIP;
+ /* FALL THROUGH */
+ case O_FLIP:
+ if ((arg[1].arg_type & A_MASK) == A_SINGLE ?
+ last_in_stab && (int)str_gnum(st[1]) == stab_io(last_in_stab)->lines
+ :
+ str_true(st[1]) ) {
+ arg[2].arg_type &= ~A_DONT;
+ arg[1].arg_type |= A_DONT;
+ arg->arg_type = optype = O_FLOP;
+ if (arg->arg_flags & AF_COMMON) {
+ str_numset(str,0.0);
+ anum = 2;
+ argflags = arg[2].arg_flags;
+ argtype = arg[2].arg_type & A_MASK;
+ argptr = arg[2].arg_ptr;
+ sp = arglast[0];
+ st -= sp++;
+ goto re_eval;
+ }
+ else {
+ str_numset(str,1.0);
+ break;
+ }
+ }
+ str_set(str,"");
+ break;
+ case O_FLOP:
+ str_inc(str);
+ if ((arg[2].arg_type & A_MASK) == A_SINGLE ?
+ last_in_stab && (int)str_gnum(st[2]) == stab_io(last_in_stab)->lines
+ :
+ str_true(st[2]) ) {
+ arg->arg_type = O_FLIP;
+ arg[1].arg_type &= ~A_DONT;
+ arg[2].arg_type |= A_DONT;
+ str_cat(str,"E0");
+ }
+ break;
+ case O_FORK:
+#ifdef HAS_FORK
+ anum = fork();
+ if (anum < 0)
+ goto say_undef;
+ if (!anum) {
+ /*SUPPRESS 560*/
+ if (tmpstab = stabent("$",allstabs))
+ str_numset(STAB_STR(tmpstab),(double)getpid());
+ hclear(pidstatus, FALSE); /* no kids, so don't wait for 'em */
+ }
+ value = (double)anum;
+ goto donumset;
+#else
+ fatal("Unsupported function fork");
+ break;
+#endif
+ case O_WAIT:
+#ifdef HAS_WAIT
+#ifndef lint
+ anum = wait(&argflags);
+ if (anum > 0)
+ pidgone(anum,argflags);
+ value = (double)anum;
+#endif
+ statusvalue = (unsigned short)argflags;
+ goto donumset;
+#else
+ fatal("Unsupported function wait");
+ break;
+#endif
+ case O_WAITPID:
+#ifdef HAS_WAIT
+#ifndef lint
+ anum = (int)str_gnum(st[1]);
+ optype = (int)str_gnum(st[2]);
+ anum = wait4pid(anum, &argflags,optype);
+ value = (double)anum;
+#endif
+ statusvalue = (unsigned short)argflags;
+ goto donumset;
+#else
+ fatal("Unsupported function wait");
+ break;
+#endif
+ case O_SYSTEM:
+#ifdef HAS_FORK
+#ifdef TAINT
+ if (arglast[2] - arglast[1] == 1) {
+ taintenv();
+ tainted |= st[2]->str_tainted;
+ taintproper("Insecure dependency in system");
+ }
+#endif
+ while ((anum = vfork()) == -1) {
+ if (errno != EAGAIN) {
+ value = -1.0;
+ goto donumset;
+ }
+ sleep(5);
+ }
+ if (anum > 0) {
+#ifndef lint
+ ihand = signal(SIGINT, SIG_IGN);
+ qhand = signal(SIGQUIT, SIG_IGN);
+ argtype = wait4pid(anum, &argflags, 0);
+#else
+ ihand = qhand = 0;
+#endif
+ (void)signal(SIGINT, ihand);
+ (void)signal(SIGQUIT, qhand);
+ statusvalue = (unsigned short)argflags;
+ if (argtype < 0)
+ value = -1.0;
+ else {
+ value = (double)((unsigned int)argflags & 0xffff);
+ }
+ do_execfree(); /* free any memory child malloced on vfork */
+ goto donumset;
+ }
+ if ((arg[1].arg_type & A_MASK) == A_STAB)
+ value = (double)do_aexec(st[1],arglast);
+ else if (arglast[2] - arglast[1] != 1)
+ value = (double)do_aexec(Nullstr,arglast);
+ else {
+ value = (double)do_exec(str_get(str_mortal(st[2])));
+ }
+ _exit(-1);
+#else /* ! FORK */
+ if ((arg[1].arg_type & A_MASK) == A_STAB)
+ value = (double)do_aspawn(st[1],arglast);
+ else if (arglast[2] - arglast[1] != 1)
+ value = (double)do_aspawn(Nullstr,arglast);
+ else {
+ value = (double)do_spawn(str_get(str_mortal(st[2])));
+ }
+ goto donumset;
+#endif /* FORK */
+ case O_EXEC_OP:
+ if ((arg[1].arg_type & A_MASK) == A_STAB)
+ value = (double)do_aexec(st[1],arglast);
+ else if (arglast[2] - arglast[1] != 1)
+ value = (double)do_aexec(Nullstr,arglast);
+ else {
+#ifdef TAINT
+ taintenv();
+ tainted |= st[2]->str_tainted;
+ taintproper("Insecure dependency in exec");
+#endif
+ value = (double)do_exec(str_get(str_mortal(st[2])));
+ }
+ goto donumset;
+ case O_HEX:
+ if (maxarg < 1)
+ tmps = str_get(stab_val(defstab));
+ else
+ tmps = str_get(st[1]);
+ value = (double)scanhex(tmps, 99, &argtype);
+ goto donumset;
+
+ case O_OCT:
+ if (maxarg < 1)
+ tmps = str_get(stab_val(defstab));
+ else
+ tmps = str_get(st[1]);
+ while (*tmps && (isSPACE(*tmps) || *tmps == '0'))
+ tmps++;
+ if (*tmps == 'x')
+ value = (double)scanhex(++tmps, 99, &argtype);
+ else
+ value = (double)scanoct(tmps, 99, &argtype);
+ goto donumset;
+
+/* These common exits are hidden here in the middle of the switches for the
+ benefit of those machines with limited branch addressing. Sigh. */
+
+array_return:
+#ifdef DEBUGGING
+ if (debug) {
+ dlevel--;
+ if (debug & 8) {
+ anum = sp - arglast[0];
+ switch (anum) {
+ case 0:
+ deb("%s RETURNS ()\n",opname[optype]);
+ break;
+ case 1:
+ deb("%s RETURNS (\"%s\")\n",opname[optype],
+ st[1] ? str_get(st[1]) : "");
+ break;
+ default:
+ tmps = st[1] ? str_get(st[1]) : "";
+ deb("%s RETURNS %d ARGS (\"%s\",%s\"%s\")\n",opname[optype],
+ anum,tmps,anum==2?"":"...,",
+ st[anum] ? str_get(st[anum]) : "");
+ break;
+ }
+ }
+ }
+#endif
+ return sp;
+
+say_yes:
+ str = &str_yes;
+ goto normal_return;
+
+say_no:
+ str = &str_no;
+ goto normal_return;
+
+say_undef:
+ str = &str_undef;
+ goto normal_return;
+
+say_zero:
+ value = 0.0;
+ /* FALL THROUGH */
+
+donumset:
+ str_numset(str,value);
+ STABSET(str);
+ st[1] = str;
+#ifdef DEBUGGING
+ if (debug) {
+ dlevel--;
+ if (debug & 8)
+ deb("%s RETURNS \"%f\"\n",opname[optype],value);
+ }
+#endif
+ return arglast[0] + 1;
+#ifdef SMALLSWITCHES
+ }
+ else
+ switch (optype) {
+#endif
+ case O_CHOWN:
+#ifdef HAS_CHOWN
+ value = (double)apply(optype,arglast);
+ goto donumset;
+#else
+ fatal("Unsupported function chown");
+ break;
+#endif
+ case O_KILL:
+#ifdef HAS_KILL
+ value = (double)apply(optype,arglast);
+ goto donumset;
+#else
+ fatal("Unsupported function kill");
+ break;
+#endif
+ case O_UNLINK:
+ case O_CHMOD:
+ case O_UTIME:
+ value = (double)apply(optype,arglast);
+ goto donumset;
+ case O_UMASK:
+#ifdef HAS_UMASK
+ if (maxarg < 1) {
+ anum = umask(0);
+ (void)umask(anum);
+ }
+ else
+ anum = umask((int)str_gnum(st[1]));
+ value = (double)anum;
+#ifdef TAINT
+ taintproper("Insecure dependency in umask");
+#endif
+ goto donumset;
+#else
+ fatal("Unsupported function umask");
+ break;
+#endif
+#if defined(HAS_MSG) || defined(HAS_SEM) || defined(HAS_SHM)
+ case O_MSGGET:
+ case O_SHMGET:
+ case O_SEMGET:
+ if ((anum = do_ipcget(optype, arglast)) == -1)
+ goto say_undef;
+ value = (double)anum;
+ goto donumset;
+ case O_MSGCTL:
+ case O_SHMCTL:
+ case O_SEMCTL:
+ anum = do_ipcctl(optype, arglast);
+ if (anum == -1)
+ goto say_undef;
+ if (anum != 0) {
+ value = (double)anum;
+ goto donumset;
+ }
+ str_set(str,"0 but true");
+ STABSET(str);
+ break;
+ case O_MSGSND:
+ value = (double)(do_msgsnd(arglast) >= 0);
+ goto donumset;
+ case O_MSGRCV:
+ value = (double)(do_msgrcv(arglast) >= 0);
+ goto donumset;
+ case O_SEMOP:
+ value = (double)(do_semop(arglast) >= 0);
+ goto donumset;
+ case O_SHMREAD:
+ case O_SHMWRITE:
+ value = (double)(do_shmio(optype, arglast) >= 0);
+ goto donumset;
+#else /* not SYSVIPC */
+ case O_MSGGET:
+ case O_MSGCTL:
+ case O_MSGSND:
+ case O_MSGRCV:
+ case O_SEMGET:
+ case O_SEMCTL:
+ case O_SEMOP:
+ case O_SHMGET:
+ case O_SHMCTL:
+ case O_SHMREAD:
+ case O_SHMWRITE:
+ fatal("System V IPC is not implemented on this machine");
+#endif /* not SYSVIPC */
+ case O_RENAME:
+ tmps = str_get(st[1]);
+ tmps2 = str_get(st[2]);
+#ifdef TAINT
+ taintproper("Insecure dependency in rename");
+#endif
+#ifdef HAS_RENAME
+ value = (double)(rename(tmps,tmps2) >= 0);
+#else
+ if (same_dirent(tmps2, tmps)) /* can always rename to same name */
+ anum = 1;
+ else {
+ if (euid || stat(tmps2,&statbuf) < 0 || !S_ISDIR(statbuf.st_mode))
+ (void)UNLINK(tmps2);
+ if (!(anum = link(tmps,tmps2)))
+ anum = UNLINK(tmps);
+ }
+ value = (double)(anum >= 0);
+#endif
+ goto donumset;
+ case O_LINK:
+#ifdef HAS_LINK
+ tmps = str_get(st[1]);
+ tmps2 = str_get(st[2]);
+#ifdef TAINT
+ taintproper("Insecure dependency in link");
+#endif
+ value = (double)(link(tmps,tmps2) >= 0);
+ goto donumset;
+#else
+ fatal("Unsupported function link");
+ break;
+#endif
+ case O_MKDIR:
+ tmps = str_get(st[1]);
+ anum = (int)str_gnum(st[2]);
+#ifdef TAINT
+ taintproper("Insecure dependency in mkdir");
+#endif
+#ifdef HAS_MKDIR
+ value = (double)(mkdir(tmps,anum) >= 0);
+ goto donumset;
+#else
+ (void)strcpy(buf,"mkdir ");
+#endif
+#if !defined(HAS_MKDIR) || !defined(HAS_RMDIR)
+ one_liner:
+ for (tmps2 = buf+6; *tmps; ) {
+ *tmps2++ = '\\';
+ *tmps2++ = *tmps++;
+ }
+ (void)strcpy(tmps2," 2>&1");
+ rsfp = mypopen(buf,"r");
+ if (rsfp) {
+ *buf = '\0';
+ tmps2 = fgets(buf,sizeof buf,rsfp);
+ (void)mypclose(rsfp);
+ if (tmps2 != Nullch) {
+ for (errno = 1; errno < sys_nerr; errno++) {
+ if (instr(buf,sys_errlist[errno])) /* you don't see this */
+ goto say_zero;
+ }
+ errno = 0;
+#ifndef EACCES
+#define EACCES EPERM
+#endif
+ if (instr(buf,"cannot make"))
+ errno = EEXIST;
+ else if (instr(buf,"existing file"))
+ errno = EEXIST;
+ else if (instr(buf,"ile exists"))
+ errno = EEXIST;
+ else if (instr(buf,"non-exist"))
+ errno = ENOENT;
+ else if (instr(buf,"does not exist"))
+ errno = ENOENT;
+ else if (instr(buf,"not empty"))
+ errno = EBUSY;
+ else if (instr(buf,"cannot access"))
+ errno = EACCES;
+ else
+ errno = EPERM;
+ goto say_zero;
+ }
+ else { /* some mkdirs return no failure indication */
+ tmps = str_get(st[1]);
+ anum = (stat(tmps,&statbuf) >= 0);
+ if (optype == O_RMDIR)
+ anum = !anum;
+ if (anum)
+ errno = 0;
+ else
+ errno = EACCES; /* a guess */
+ value = (double)anum;
+ }
+ goto donumset;
+ }
+ else
+ goto say_zero;
+#endif
+ case O_RMDIR:
+ if (maxarg < 1)
+ tmps = str_get(stab_val(defstab));
+ else
+ tmps = str_get(st[1]);
+#ifdef TAINT
+ taintproper("Insecure dependency in rmdir");
+#endif
+#ifdef HAS_RMDIR
+ value = (double)(rmdir(tmps) >= 0);
+ goto donumset;
+#else
+ (void)strcpy(buf,"rmdir ");
+ goto one_liner; /* see above in HAS_MKDIR */
+#endif
+ case O_GETPPID:
+#ifdef HAS_GETPPID
+ value = (double)getppid();
+ goto donumset;
+#else
+ fatal("Unsupported function getppid");
+ break;
+#endif
+ case O_GETPGRP:
+#ifdef HAS_GETPGRP
+ if (maxarg < 1)
+ anum = 0;
+ else
+ anum = (int)str_gnum(st[1]);
+#ifdef _POSIX_SOURCE
+ if (anum != 0)
+ fatal("POSIX getpgrp can't take an argument");
+ value = (double)getpgrp();
+#else
+ value = (double)getpgrp(anum);
+#endif
+ goto donumset;
+#else
+ fatal("The getpgrp() function is unimplemented on this machine");
+ break;
+#endif
+ case O_SETPGRP:
+#ifdef HAS_SETPGRP
+ argtype = (int)str_gnum(st[1]);
+ anum = (int)str_gnum(st[2]);
+#ifdef TAINT
+ taintproper("Insecure dependency in setpgrp");
+#endif
+ value = (double)(setpgrp(argtype,anum) >= 0);
+ goto donumset;
+#else
+ fatal("The setpgrp() function is unimplemented on this machine");
+ break;
+#endif
+ case O_GETPRIORITY:
+#ifdef HAS_GETPRIORITY
+ argtype = (int)str_gnum(st[1]);
+ anum = (int)str_gnum(st[2]);
+ value = (double)getpriority(argtype,anum);
+ goto donumset;
+#else
+ fatal("The getpriority() function is unimplemented on this machine");
+ break;
+#endif
+ case O_SETPRIORITY:
+#ifdef HAS_SETPRIORITY
+ argtype = (int)str_gnum(st[1]);
+ anum = (int)str_gnum(st[2]);
+ optype = (int)str_gnum(st[3]);
+#ifdef TAINT
+ taintproper("Insecure dependency in setpriority");
+#endif
+ value = (double)(setpriority(argtype,anum,optype) >= 0);
+ goto donumset;
+#else
+ fatal("The setpriority() function is unimplemented on this machine");
+ break;
+#endif
+ case O_CHROOT:
+#ifdef HAS_CHROOT
+ if (maxarg < 1)
+ tmps = str_get(stab_val(defstab));
+ else
+ tmps = str_get(st[1]);
+#ifdef TAINT
+ taintproper("Insecure dependency in chroot");
+#endif
+ value = (double)(chroot(tmps) >= 0);
+ goto donumset;
+#else
+ fatal("Unsupported function chroot");
+ break;
+#endif
+ case O_FCNTL:
+ case O_IOCTL:
+ if (maxarg <= 0)
+ stab = last_in_stab;
+ else if ((arg[1].arg_type & A_MASK) == A_WORD)
+ stab = arg[1].arg_ptr.arg_stab;
+ else
+ stab = stabent(str_get(st[1]),TRUE);
+ argtype = U_I(str_gnum(st[2]));
+#ifdef TAINT
+ taintproper("Insecure dependency in ioctl");
+#endif
+ anum = do_ctl(optype,stab,argtype,st[3]);
+ if (anum == -1)
+ goto say_undef;
+ if (anum != 0) {
+ value = (double)anum;
+ goto donumset;
+ }
+ str_set(str,"0 but true");
+ STABSET(str);
+ break;
+ case O_FLOCK:
+#ifdef HAS_FLOCK
+ if (maxarg <= 0)
+ stab = last_in_stab;
+ else if ((arg[1].arg_type & A_MASK) == A_WORD)
+ stab = arg[1].arg_ptr.arg_stab;
+ else
+ stab = stabent(str_get(st[1]),TRUE);
+ if (stab && stab_io(stab))
+ fp = stab_io(stab)->ifp;
+ else
+ fp = Nullfp;
+ if (fp) {
+ argtype = (int)str_gnum(st[2]);
+ value = (double)(flock(fileno(fp),argtype) >= 0);
+ }
+ else
+ value = 0;
+ goto donumset;
+#else
+ fatal("The flock() function is unimplemented on this machine");
+ break;
+#endif
+ case O_UNSHIFT:
+ ary = stab_array(arg[1].arg_ptr.arg_stab);
+ if (arglast[2] - arglast[1] != 1)
+ do_unshift(ary,arglast);
+ else {
+ STR *tmpstr = Str_new(52,0); /* must copy the STR */
+ str_sset(tmpstr,st[2]);
+ aunshift(ary,1);
+ (void)astore(ary,0,tmpstr);
+ }
+ value = (double)(ary->ary_fill + 1);
+ goto donumset;
+
+ case O_TRY:
+ sp = do_try(arg[1].arg_ptr.arg_cmd,
+ gimme,arglast);
+ goto array_return;
+
+ case O_EVALONCE:
+ sp = do_eval(st[1], O_EVAL, curcmd->c_stash, TRUE,
+ gimme,arglast);
+ if (eval_root) {
+ str_free(arg[1].arg_ptr.arg_str);
+ arg[1].arg_ptr.arg_cmd = eval_root;
+ arg[1].arg_type = (A_CMD|A_DONT);
+ arg[0].arg_type = O_TRY;
+ }
+ goto array_return;
+
+ case O_REQUIRE:
+ case O_DOFILE:
+ case O_EVAL:
+ if (maxarg < 1)
+ tmpstr = stab_val(defstab);
+ else
+ tmpstr =
+ (arg[1].arg_type & A_MASK) != A_NULL ? st[1] : stab_val(defstab);
+#ifdef TAINT
+ tainted |= tmpstr->str_tainted;
+ taintproper("Insecure dependency in eval");
+#endif
+ sp = do_eval(tmpstr, optype, curcmd->c_stash, FALSE,
+ gimme,arglast);
+ goto array_return;
+
+ case O_FTRREAD:
+ argtype = 0;
+ anum = S_IRUSR;
+ goto check_perm;
+ case O_FTRWRITE:
+ argtype = 0;
+ anum = S_IWUSR;
+ goto check_perm;
+ case O_FTREXEC:
+ argtype = 0;
+ anum = S_IXUSR;
+ goto check_perm;
+ case O_FTEREAD:
+ argtype = 1;
+ anum = S_IRUSR;
+ goto check_perm;
+ case O_FTEWRITE:
+ argtype = 1;
+ anum = S_IWUSR;
+ goto check_perm;
+ case O_FTEEXEC:
+ argtype = 1;
+ anum = S_IXUSR;
+ check_perm:
+ if (mystat(arg,st[1]) < 0)
+ goto say_undef;
+ if (cando(anum,argtype,&statcache))
+ goto say_yes;
+ goto say_no;
+
+ case O_FTIS:
+ if (mystat(arg,st[1]) < 0)
+ goto say_undef;
+ goto say_yes;
+ case O_FTEOWNED:
+ case O_FTROWNED:
+ if (mystat(arg,st[1]) < 0)
+ goto say_undef;
+ if (statcache.st_uid == (optype == O_FTEOWNED ? euid : uid) )
+ goto say_yes;
+ goto say_no;
+ case O_FTZERO:
+ if (mystat(arg,st[1]) < 0)
+ goto say_undef;
+ if (!statcache.st_size)
+ goto say_yes;
+ goto say_no;
+ case O_FTSIZE:
+ if (mystat(arg,st[1]) < 0)
+ goto say_undef;
+ value = (double)statcache.st_size;
+ goto donumset;
+
+ case O_FTMTIME:
+ if (mystat(arg,st[1]) < 0)
+ goto say_undef;
+ value = (double)(basetime - statcache.st_mtime) / 86400.0;
+ goto donumset;
+ case O_FTATIME:
+ if (mystat(arg,st[1]) < 0)
+ goto say_undef;
+ value = (double)(basetime - statcache.st_atime) / 86400.0;
+ goto donumset;
+ case O_FTCTIME:
+ if (mystat(arg,st[1]) < 0)
+ goto say_undef;
+ value = (double)(basetime - statcache.st_ctime) / 86400.0;
+ goto donumset;
+
+ case O_FTSOCK:
+ if (mystat(arg,st[1]) < 0)
+ goto say_undef;
+ if (S_ISSOCK(statcache.st_mode))
+ goto say_yes;
+ goto say_no;
+ case O_FTCHR:
+ if (mystat(arg,st[1]) < 0)
+ goto say_undef;
+ if (S_ISCHR(statcache.st_mode))
+ goto say_yes;
+ goto say_no;
+ case O_FTBLK:
+ if (mystat(arg,st[1]) < 0)
+ goto say_undef;
+ if (S_ISBLK(statcache.st_mode))
+ goto say_yes;
+ goto say_no;
+ case O_FTFILE:
+ if (mystat(arg,st[1]) < 0)
+ goto say_undef;
+ if (S_ISREG(statcache.st_mode))
+ goto say_yes;
+ goto say_no;
+ case O_FTDIR:
+ if (mystat(arg,st[1]) < 0)
+ goto say_undef;
+ if (S_ISDIR(statcache.st_mode))
+ goto say_yes;
+ goto say_no;
+ case O_FTPIPE:
+ if (mystat(arg,st[1]) < 0)
+ goto say_undef;
+ if (S_ISFIFO(statcache.st_mode))
+ goto say_yes;
+ goto say_no;
+ case O_FTLINK:
+ if (mylstat(arg,st[1]) < 0)
+ goto say_undef;
+ if (S_ISLNK(statcache.st_mode))
+ goto say_yes;
+ goto say_no;
+ case O_SYMLINK:
+#ifdef HAS_SYMLINK
+ tmps = str_get(st[1]);
+ tmps2 = str_get(st[2]);
+#ifdef TAINT
+ taintproper("Insecure dependency in symlink");
+#endif
+ value = (double)(symlink(tmps,tmps2) >= 0);
+ goto donumset;
+#else
+ fatal("Unsupported function symlink");
+#endif
+ case O_READLINK:
+#ifdef HAS_SYMLINK
+ if (maxarg < 1)
+ tmps = str_get(stab_val(defstab));
+ else
+ tmps = str_get(st[1]);
+ anum = readlink(tmps,buf,sizeof buf);
+ if (anum < 0)
+ goto say_undef;
+ str_nset(str,buf,anum);
+ break;
+#else
+ goto say_undef; /* just pretend it's a normal file */
+#endif
+ case O_FTSUID:
+#ifdef S_ISUID
+ anum = S_ISUID;
+ goto check_xid;
+#else
+ goto say_no;
+#endif
+ case O_FTSGID:
+#ifdef S_ISGID
+ anum = S_ISGID;
+ goto check_xid;
+#else
+ goto say_no;
+#endif
+ case O_FTSVTX:
+#ifdef S_ISVTX
+ anum = S_ISVTX;
+#else
+ goto say_no;
+#endif
+ check_xid:
+ if (mystat(arg,st[1]) < 0)
+ goto say_undef;
+ if (statcache.st_mode & anum)
+ goto say_yes;
+ goto say_no;
+ case O_FTTTY:
+ if (arg[1].arg_type & A_DONT) {
+ stab = arg[1].arg_ptr.arg_stab;
+ tmps = "";
+ }
+ else
+ stab = stabent(tmps = str_get(st[1]),FALSE);
+ if (stab && stab_io(stab) && stab_io(stab)->ifp)
+ anum = fileno(stab_io(stab)->ifp);
+ else if (isDIGIT(*tmps))
+ anum = atoi(tmps);
+ else
+ goto say_undef;
+ if (isatty(anum))
+ goto say_yes;
+ goto say_no;
+ case O_FTTEXT:
+ case O_FTBINARY:
+ str = do_fttext(arg,st[1]);
+ break;
+#ifdef HAS_SOCKET
+ case O_SOCKET:
+ if ((arg[1].arg_type & A_MASK) == A_WORD)
+ stab = arg[1].arg_ptr.arg_stab;
+ else
+ stab = stabent(str_get(st[1]),TRUE);
+#ifndef lint
+ value = (double)do_socket(stab,arglast);
+#else
+ (void)do_socket(stab,arglast);
+#endif
+ goto donumset;
+ case O_BIND:
+ if ((arg[1].arg_type & A_MASK) == A_WORD)
+ stab = arg[1].arg_ptr.arg_stab;
+ else
+ stab = stabent(str_get(st[1]),TRUE);
+#ifndef lint
+ value = (double)do_bind(stab,arglast);
+#else
+ (void)do_bind(stab,arglast);
+#endif
+ goto donumset;
+ case O_CONNECT:
+ if ((arg[1].arg_type & A_MASK) == A_WORD)
+ stab = arg[1].arg_ptr.arg_stab;
+ else
+ stab = stabent(str_get(st[1]),TRUE);
+#ifndef lint
+ value = (double)do_connect(stab,arglast);
+#else
+ (void)do_connect(stab,arglast);
+#endif
+ goto donumset;
+ case O_LISTEN:
+ if ((arg[1].arg_type & A_MASK) == A_WORD)
+ stab = arg[1].arg_ptr.arg_stab;
+ else
+ stab = stabent(str_get(st[1]),TRUE);
+#ifndef lint
+ value = (double)do_listen(stab,arglast);
+#else
+ (void)do_listen(stab,arglast);
+#endif
+ goto donumset;
+ case O_ACCEPT:
+ if ((arg[1].arg_type & A_MASK) == A_WORD)
+ stab = arg[1].arg_ptr.arg_stab;
+ else
+ stab = stabent(str_get(st[1]),TRUE);
+ if ((arg[2].arg_type & A_MASK) == A_WORD)
+ stab2 = arg[2].arg_ptr.arg_stab;
+ else
+ stab2 = stabent(str_get(st[2]),TRUE);
+ do_accept(str,stab,stab2);
+ STABSET(str);
+ break;
+ case O_GHBYNAME:
+ if (maxarg < 1)
+ goto say_undef;
+ case O_GHBYADDR:
+ case O_GHOSTENT:
+ sp = do_ghent(optype,
+ gimme,arglast);
+ goto array_return;
+ case O_GNBYNAME:
+ if (maxarg < 1)
+ goto say_undef;
+ case O_GNBYADDR:
+ case O_GNETENT:
+ sp = do_gnent(optype,
+ gimme,arglast);
+ goto array_return;
+ case O_GPBYNAME:
+ if (maxarg < 1)
+ goto say_undef;
+ case O_GPBYNUMBER:
+ case O_GPROTOENT:
+ sp = do_gpent(optype,
+ gimme,arglast);
+ goto array_return;
+ case O_GSBYNAME:
+ if (maxarg < 1)
+ goto say_undef;
+ case O_GSBYPORT:
+ case O_GSERVENT:
+ sp = do_gsent(optype,
+ gimme,arglast);
+ goto array_return;
+ case O_SHOSTENT:
+ value = (double) sethostent((int)str_gnum(st[1]));
+ goto donumset;
+ case O_SNETENT:
+ value = (double) setnetent((int)str_gnum(st[1]));
+ goto donumset;
+ case O_SPROTOENT:
+ value = (double) setprotoent((int)str_gnum(st[1]));
+ goto donumset;
+ case O_SSERVENT:
+ value = (double) setservent((int)str_gnum(st[1]));
+ goto donumset;
+ case O_EHOSTENT:
+ value = (double) endhostent();
+ goto donumset;
+ case O_ENETENT:
+ value = (double) endnetent();
+ goto donumset;
+ case O_EPROTOENT:
+ value = (double) endprotoent();
+ goto donumset;
+ case O_ESERVENT:
+ value = (double) endservent();
+ goto donumset;
+ case O_SOCKPAIR:
+ if ((arg[1].arg_type & A_MASK) == A_WORD)
+ stab = arg[1].arg_ptr.arg_stab;
+ else
+ stab = stabent(str_get(st[1]),TRUE);
+ if ((arg[2].arg_type & A_MASK) == A_WORD)
+ stab2 = arg[2].arg_ptr.arg_stab;
+ else
+ stab2 = stabent(str_get(st[2]),TRUE);
+#ifndef lint
+ value = (double)do_spair(stab,stab2,arglast);
+#else
+ (void)do_spair(stab,stab2,arglast);
+#endif
+ goto donumset;
+ case O_SHUTDOWN:
+ if ((arg[1].arg_type & A_MASK) == A_WORD)
+ stab = arg[1].arg_ptr.arg_stab;
+ else
+ stab = stabent(str_get(st[1]),TRUE);
+#ifndef lint
+ value = (double)do_shutdown(stab,arglast);
+#else
+ (void)do_shutdown(stab,arglast);
+#endif
+ goto donumset;
+ case O_GSOCKOPT:
+ case O_SSOCKOPT:
+ if ((arg[1].arg_type & A_MASK) == A_WORD)
+ stab = arg[1].arg_ptr.arg_stab;
+ else
+ stab = stabent(str_get(st[1]),TRUE);
+ sp = do_sopt(optype,stab,arglast);
+ goto array_return;
+ case O_GETSOCKNAME:
+ case O_GETPEERNAME:
+ if ((arg[1].arg_type & A_MASK) == A_WORD)
+ stab = arg[1].arg_ptr.arg_stab;
+ else
+ stab = stabent(str_get(st[1]),TRUE);
+ if (!stab)
+ goto say_undef;
+ sp = do_getsockname(optype,stab,arglast);
+ goto array_return;
+
+#else /* HAS_SOCKET not defined */
+ case O_SOCKET:
+ case O_BIND:
+ case O_CONNECT:
+ case O_LISTEN:
+ case O_ACCEPT:
+ case O_SOCKPAIR:
+ case O_GHBYNAME:
+ case O_GHBYADDR:
+ case O_GHOSTENT:
+ case O_GNBYNAME:
+ case O_GNBYADDR:
+ case O_GNETENT:
+ case O_GPBYNAME:
+ case O_GPBYNUMBER:
+ case O_GPROTOENT:
+ case O_GSBYNAME:
+ case O_GSBYPORT:
+ case O_GSERVENT:
+ case O_SHOSTENT:
+ case O_SNETENT:
+ case O_SPROTOENT:
+ case O_SSERVENT:
+ case O_EHOSTENT:
+ case O_ENETENT:
+ case O_EPROTOENT:
+ case O_ESERVENT:
+ case O_SHUTDOWN:
+ case O_GSOCKOPT:
+ case O_SSOCKOPT:
+ case O_GETSOCKNAME:
+ case O_GETPEERNAME:
+ badsock:
+ fatal("Unsupported socket function");
+#endif /* HAS_SOCKET */
+ case O_SSELECT:
+#ifdef HAS_SELECT
+ sp = do_select(gimme,arglast);
+ goto array_return;
+#else
+ fatal("select not implemented");
+#endif
+ case O_FILENO:
+ if (maxarg < 1)
+ goto say_undef;
+ if ((arg[1].arg_type & A_MASK) == A_WORD)
+ stab = arg[1].arg_ptr.arg_stab;
+ else
+ stab = stabent(str_get(st[1]),TRUE);
+ if (!stab || !(stio = stab_io(stab)) || !(fp = stio->ifp))
+ goto say_undef;
+ value = fileno(fp);
+ goto donumset;
+ case O_BINMODE:
+ if (maxarg < 1)
+ goto say_undef;
+ if ((arg[1].arg_type & A_MASK) == A_WORD)
+ stab = arg[1].arg_ptr.arg_stab;
+ else
+ stab = stabent(str_get(st[1]),TRUE);
+ if (!stab || !(stio = stab_io(stab)) || !(fp = stio->ifp))
+ goto say_undef;
+#ifdef DOSISH
+#ifdef atarist
+ if(fflush(fp))
+ str_set(str, No);
+ else
+ {
+ fp->_flag |= _IOBIN;
+ str_set(str, Yes);
+ }
+#else
+ str_set(str, (setmode(fileno(fp), O_BINARY) != -1) ? Yes : No);
+#endif
+#else
+ str_set(str, Yes);
+#endif
+ STABSET(str);
+ break;
+ case O_VEC:
+ sp = do_vec(str == st[1], arg->arg_ptr.arg_str, arglast);
+ goto array_return;
+ case O_GPWNAM:
+ case O_GPWUID:
+ case O_GPWENT:
+#ifdef HAS_PASSWD
+ sp = do_gpwent(optype,
+ gimme,arglast);
+ goto array_return;
+ case O_SPWENT:
+ value = (double) setpwent();
+ goto donumset;
+ case O_EPWENT:
+ value = (double) endpwent();
+ goto donumset;
+#else
+ case O_EPWENT:
+ case O_SPWENT:
+ fatal("Unsupported password function");
+ break;
+#endif
+ case O_GGRNAM:
+ case O_GGRGID:
+ case O_GGRENT:
+#ifdef HAS_GROUP
+ sp = do_ggrent(optype,
+ gimme,arglast);
+ goto array_return;
+ case O_SGRENT:
+ value = (double) setgrent();
+ goto donumset;
+ case O_EGRENT:
+ value = (double) endgrent();
+ goto donumset;
+#else
+ case O_EGRENT:
+ case O_SGRENT:
+ fatal("Unsupported group function");
+ break;
+#endif
+ case O_GETLOGIN:
+#ifdef HAS_GETLOGIN
+ if (!(tmps = getlogin()))
+ goto say_undef;
+ str_set(str,tmps);
+#else
+ fatal("Unsupported function getlogin");
+#endif
+ break;
+ case O_OPEN_DIR:
+ case O_READDIR:
+ case O_TELLDIR:
+ case O_SEEKDIR:
+ case O_REWINDDIR:
+ case O_CLOSEDIR:
+ if (maxarg < 1)
+ goto say_undef;
+ if ((arg[1].arg_type & A_MASK) == A_WORD)
+ stab = arg[1].arg_ptr.arg_stab;
+ else
+ stab = stabent(str_get(st[1]),TRUE);
+ if (!stab)
+ goto say_undef;
+ sp = do_dirop(optype,stab,gimme,arglast);
+ goto array_return;
+ case O_SYSCALL:
+ value = (double)do_syscall(arglast);
+ goto donumset;
+ case O_PIPE_OP:
+#ifdef HAS_PIPE
+ if ((arg[1].arg_type & A_MASK) == A_WORD)
+ stab = arg[1].arg_ptr.arg_stab;
+ else
+ stab = stabent(str_get(st[1]),TRUE);
+ if ((arg[2].arg_type & A_MASK) == A_WORD)
+ stab2 = arg[2].arg_ptr.arg_stab;
+ else
+ stab2 = stabent(str_get(st[2]),TRUE);
+ do_pipe(str,stab,stab2);
+ STABSET(str);
+#else
+ fatal("Unsupported function pipe");
+#endif
+ break;
+ }
+
+ normal_return:
+ st[1] = str;
+#ifdef DEBUGGING
+ if (debug) {
+ dlevel--;
+ if (debug & 8)
+ deb("%s RETURNS \"%s\"\n",opname[optype],str_get(str));
+ }
+#endif
+ return arglast[0] + 1;
+}
diff --git a/gnu/usr.bin/perl/perl/form.c b/gnu/usr.bin/perl/perl/form.c
new file mode 100644
index 0000000..cfb7aed
--- /dev/null
+++ b/gnu/usr.bin/perl/perl/form.c
@@ -0,0 +1,422 @@
+/* $RCSfile: form.c,v $$Revision: 1.1.1.1 $$Date: 1994/09/10 06:27:33 $
+ *
+ * Copyright (c) 1991, Larry Wall
+ *
+ * You may distribute under the terms of either the GNU General Public
+ * License or the Artistic License, as specified in the README file.
+ *
+ * $Log: form.c,v $
+ * Revision 1.1.1.1 1994/09/10 06:27:33 gclarkii
+ * Initial import of Perl 4.046 bmaked
+ *
+ * Revision 1.1.1.1 1993/08/23 21:29:36 nate
+ * PERL!
+ *
+ * Revision 4.0.1.4 1993/02/05 19:34:32 lwall
+ * patch36: formats now ignore literal text for ~~ loop determination
+ *
+ * Revision 4.0.1.3 92/06/08 13:21:42 lwall
+ * patch20: removed implicit int declarations on funcions
+ * patch20: form feed for formats is now specifiable via $^L
+ * patch20: Perl now distinguishes overlapped copies from non-overlapped
+ *
+ * Revision 4.0.1.2 91/11/05 17:18:43 lwall
+ * patch11: formats didn't fill their fields as well as they could
+ * patch11: ^ fields chopped hyphens on line break
+ * patch11: # fields could write outside allocated memory
+ *
+ * Revision 4.0.1.1 91/06/07 11:07:59 lwall
+ * patch4: new copyright notice
+ * patch4: default top-of-form format is now FILEHANDLE_TOP
+ *
+ * Revision 4.0 91/03/20 01:19:23 lwall
+ * 4.0 baseline.
+ *
+ */
+
+#include "EXTERN.h"
+#include "perl.h"
+
+/* Forms stuff */
+
+static int countlines();
+
+void
+form_parseargs(fcmd)
+register FCMD *fcmd;
+{
+ register int i;
+ register ARG *arg;
+ register int items;
+ STR *str;
+ ARG *parselist();
+ line_t oldline = curcmd->c_line;
+ int oldsave = savestack->ary_fill;
+
+ str = fcmd->f_unparsed;
+ curcmd->c_line = fcmd->f_line;
+ fcmd->f_unparsed = Nullstr;
+ (void)savehptr(&curstash);
+ curstash = str->str_u.str_hash;
+ arg = parselist(str);
+ restorelist(oldsave);
+
+ items = arg->arg_len - 1; /* ignore $$ on end */
+ for (i = 1; i <= items; i++) {
+ if (!fcmd || fcmd->f_type == F_NULL)
+ fatal("Too many field values");
+ dehoist(arg,i);
+ fcmd->f_expr = make_op(O_ITEM,1,
+ arg[i].arg_ptr.arg_arg,Nullarg,Nullarg);
+ if (fcmd->f_flags & FC_CHOP) {
+ if ((fcmd->f_expr[1].arg_type & A_MASK) == A_STAB)
+ fcmd->f_expr[1].arg_type = A_LVAL;
+ else if ((fcmd->f_expr[1].arg_type & A_MASK) == A_EXPR)
+ fcmd->f_expr[1].arg_type = A_LEXPR;
+ else
+ fatal("^ field requires scalar lvalue");
+ }
+ fcmd = fcmd->f_next;
+ }
+ if (fcmd && fcmd->f_type)
+ fatal("Not enough field values");
+ curcmd->c_line = oldline;
+ Safefree(arg);
+ str_free(str);
+}
+
+int newsize;
+
+#define CHKLEN(allow) \
+newsize = (d - orec->o_str) + (allow); \
+if (newsize >= curlen) { \
+ curlen = d - orec->o_str; \
+ GROWSTR(&orec->o_str,&orec->o_len,orec->o_len + (allow)); \
+ d = orec->o_str + curlen; /* in case it moves */ \
+ curlen = orec->o_len - 2; \
+}
+
+void
+format(orec,fcmd,sp)
+register struct outrec *orec;
+register FCMD *fcmd;
+int sp;
+{
+ register char *d = orec->o_str;
+ register char *s;
+ register int curlen = orec->o_len - 2;
+ register int size;
+ FCMD *nextfcmd;
+ FCMD *linebeg = fcmd;
+ char tmpchar;
+ char *t;
+ CMD mycmd;
+ STR *str;
+ char *chophere;
+ int blank = TRUE;
+
+ mycmd.c_type = C_NULL;
+ orec->o_lines = 0;
+ for (; fcmd; fcmd = nextfcmd) {
+ nextfcmd = fcmd->f_next;
+ CHKLEN(fcmd->f_presize);
+ /*SUPPRESS 560*/
+ if (s = fcmd->f_pre) {
+ while (*s) {
+ if (*s == '\n') {
+ t = orec->o_str;
+ if (blank && (fcmd->f_flags & FC_REPEAT)) {
+ while (d > t && (d[-1] != '\n'))
+ d--;
+ }
+ else {
+ while (d > t && (d[-1] == ' ' || d[-1] == '\t'))
+ d--;
+ }
+ if (fcmd->f_flags & FC_NOBLANK) {
+ if (blank || d == orec->o_str || d[-1] == '\n') {
+ orec->o_lines--; /* don't print blank line */
+ linebeg = fcmd->f_next;
+ break;
+ }
+ else if (fcmd->f_flags & FC_REPEAT)
+ nextfcmd = linebeg;
+ else
+ linebeg = fcmd->f_next;
+ }
+ else
+ linebeg = fcmd->f_next;
+ blank = TRUE;
+ }
+ *d++ = *s++;
+ }
+ }
+ if (fcmd->f_unparsed)
+ form_parseargs(fcmd);
+ switch (fcmd->f_type) {
+ case F_NULL:
+ orec->o_lines++;
+ break;
+ case F_LEFT:
+ (void)eval(fcmd->f_expr,G_SCALAR,sp);
+ str = stack->ary_array[sp+1];
+ s = str_get(str);
+ size = fcmd->f_size;
+ CHKLEN(size);
+ chophere = Nullch;
+ while (size && *s && *s != '\n') {
+ if (*s == '\t')
+ *s = ' ';
+ else if (*s != ' ')
+ blank = FALSE;
+ size--;
+ if (*s && index(chopset,(*d++ = *s++)))
+ chophere = s;
+ if (*s == '\n' && (fcmd->f_flags & FC_CHOP))
+ *s = ' ';
+ }
+ if (size || !*s)
+ chophere = s;
+ else if (chophere && chophere < s && *s && index(chopset,*s))
+ chophere = s;
+ if (fcmd->f_flags & FC_CHOP) {
+ if (!chophere)
+ chophere = s;
+ size += (s - chophere);
+ d -= (s - chophere);
+ if (fcmd->f_flags & FC_MORE &&
+ *chophere && strNE(chophere,"\n")) {
+ while (size < 3) {
+ d--;
+ size++;
+ }
+ while (d[-1] == ' ' && size < fcmd->f_size) {
+ d--;
+ size++;
+ }
+ *d++ = '.';
+ *d++ = '.';
+ *d++ = '.';
+ size -= 3;
+ }
+ while (*chophere && index(chopset,*chophere)
+ && isSPACE(*chophere))
+ chophere++;
+ str_chop(str,chophere);
+ }
+ if (fcmd->f_next && fcmd->f_next->f_pre[0] == '\n')
+ size = 0; /* no spaces before newline */
+ while (size) {
+ size--;
+ *d++ = ' ';
+ }
+ break;
+ case F_RIGHT:
+ (void)eval(fcmd->f_expr,G_SCALAR,sp);
+ str = stack->ary_array[sp+1];
+ t = s = str_get(str);
+ size = fcmd->f_size;
+ CHKLEN(size);
+ chophere = Nullch;
+ while (size && *s && *s != '\n') {
+ if (*s == '\t')
+ *s = ' ';
+ else if (*s != ' ')
+ blank = FALSE;
+ size--;
+ if (*s && index(chopset,*s++))
+ chophere = s;
+ if (*s == '\n' && (fcmd->f_flags & FC_CHOP))
+ *s = ' ';
+ }
+ if (size || !*s)
+ chophere = s;
+ else if (chophere && chophere < s && *s && index(chopset,*s))
+ chophere = s;
+ if (fcmd->f_flags & FC_CHOP) {
+ if (!chophere)
+ chophere = s;
+ size += (s - chophere);
+ s = chophere;
+ while (*chophere && index(chopset,*chophere)
+ && isSPACE(*chophere))
+ chophere++;
+ }
+ tmpchar = *s;
+ *s = '\0';
+ while (size) {
+ size--;
+ *d++ = ' ';
+ }
+ size = s - t;
+ Copy(t,d,size,char);
+ d += size;
+ *s = tmpchar;
+ if (fcmd->f_flags & FC_CHOP)
+ str_chop(str,chophere);
+ break;
+ case F_CENTER: {
+ int halfsize;
+
+ (void)eval(fcmd->f_expr,G_SCALAR,sp);
+ str = stack->ary_array[sp+1];
+ t = s = str_get(str);
+ size = fcmd->f_size;
+ CHKLEN(size);
+ chophere = Nullch;
+ while (size && *s && *s != '\n') {
+ if (*s == '\t')
+ *s = ' ';
+ else if (*s != ' ')
+ blank = FALSE;
+ size--;
+ if (*s && index(chopset,*s++))
+ chophere = s;
+ if (*s == '\n' && (fcmd->f_flags & FC_CHOP))
+ *s = ' ';
+ }
+ if (size || !*s)
+ chophere = s;
+ else if (chophere && chophere < s && *s && index(chopset,*s))
+ chophere = s;
+ if (fcmd->f_flags & FC_CHOP) {
+ if (!chophere)
+ chophere = s;
+ size += (s - chophere);
+ s = chophere;
+ while (*chophere && index(chopset,*chophere)
+ && isSPACE(*chophere))
+ chophere++;
+ }
+ tmpchar = *s;
+ *s = '\0';
+ halfsize = size / 2;
+ while (size > halfsize) {
+ size--;
+ *d++ = ' ';
+ }
+ size = s - t;
+ Copy(t,d,size,char);
+ d += size;
+ *s = tmpchar;
+ if (fcmd->f_next && fcmd->f_next->f_pre[0] == '\n')
+ size = 0; /* no spaces before newline */
+ else
+ size = halfsize;
+ while (size) {
+ size--;
+ *d++ = ' ';
+ }
+ if (fcmd->f_flags & FC_CHOP)
+ str_chop(str,chophere);
+ break;
+ }
+ case F_LINES:
+ (void)eval(fcmd->f_expr,G_SCALAR,sp);
+ str = stack->ary_array[sp+1];
+ s = str_get(str);
+ size = str_len(str);
+ CHKLEN(size+1);
+ orec->o_lines += countlines(s,size) - 1;
+ Copy(s,d,size,char);
+ d += size;
+ if (size && s[size-1] != '\n') {
+ *d++ = '\n';
+ orec->o_lines++;
+ }
+ linebeg = fcmd->f_next;
+ break;
+ case F_DECIMAL: {
+ double value;
+
+ (void)eval(fcmd->f_expr,G_SCALAR,sp);
+ str = stack->ary_array[sp+1];
+ size = fcmd->f_size;
+ CHKLEN(size+1);
+ /* If the field is marked with ^ and the value is undefined,
+ blank it out. */
+ if ((fcmd->f_flags & FC_CHOP) && !str->str_pok && !str->str_nok) {
+ while (size) {
+ size--;
+ *d++ = ' ';
+ }
+ break;
+ }
+ blank = FALSE;
+ value = str_gnum(str);
+ if (fcmd->f_flags & FC_DP) {
+ sprintf(d, "%#*.*f", size, fcmd->f_decimals, value);
+ } else {
+ sprintf(d, "%*.0f", size, value);
+ }
+ d += size;
+ break;
+ }
+ }
+ }
+ CHKLEN(1);
+ *d++ = '\0';
+}
+
+static int
+countlines(s,size)
+register char *s;
+register int size;
+{
+ register int count = 0;
+
+ while (size--) {
+ if (*s++ == '\n')
+ count++;
+ }
+ return count;
+}
+
+void
+do_write(orec,stab,sp)
+struct outrec *orec;
+STAB *stab;
+int sp;
+{
+ register STIO *stio = stab_io(stab);
+ FILE *ofp = stio->ofp;
+
+#ifdef DEBUGGING
+ if (debug & 256)
+ fprintf(stderr,"left=%ld, todo=%ld\n",
+ (long)stio->lines_left, (long)orec->o_lines);
+#endif
+ if (stio->lines_left < orec->o_lines) {
+ if (!stio->top_stab) {
+ STAB *topstab;
+ char tmpbuf[256];
+
+ if (!stio->top_name) {
+ if (!stio->fmt_name)
+ stio->fmt_name = savestr(stab_name(stab));
+ sprintf(tmpbuf, "%s_TOP", stio->fmt_name);
+ topstab = stabent(tmpbuf,FALSE);
+ if (topstab && stab_form(topstab))
+ stio->top_name = savestr(tmpbuf);
+ else
+ stio->top_name = savestr("top");
+ }
+ topstab = stabent(stio->top_name,FALSE);
+ if (!topstab || !stab_form(topstab)) {
+ stio->lines_left = 100000000;
+ goto forget_top;
+ }
+ stio->top_stab = topstab;
+ }
+ if (stio->lines_left >= 0 && stio->page > 0)
+ fwrite(formfeed->str_ptr, formfeed->str_cur, 1, ofp);
+ stio->lines_left = stio->page_len;
+ stio->page++;
+ format(&toprec,stab_form(stio->top_stab),sp);
+ fputs(toprec.o_str,ofp);
+ stio->lines_left -= toprec.o_lines;
+ }
+ forget_top:
+ fputs(orec->o_str,ofp);
+ stio->lines_left -= orec->o_lines;
+}
diff --git a/gnu/usr.bin/perl/perl/form.h b/gnu/usr.bin/perl/perl/form.h
new file mode 100644
index 0000000..3f63289
--- /dev/null
+++ b/gnu/usr.bin/perl/perl/form.h
@@ -0,0 +1,51 @@
+/* $RCSfile: form.h,v $$Revision: 1.1.1.1 $$Date: 1994/09/10 06:27:34 $
+ *
+ * Copyright (c) 1991, Larry Wall
+ *
+ * You may distribute under the terms of either the GNU General Public
+ * License or the Artistic License, as specified in the README file.
+ *
+ * $Log: form.h,v $
+ * Revision 1.1.1.1 1994/09/10 06:27:34 gclarkii
+ * Initial import of Perl 4.046 bmaked
+ *
+ * Revision 1.1.1.1 1993/08/23 21:29:36 nate
+ * PERL!
+ *
+ * Revision 4.0.1.1 91/06/07 11:08:20 lwall
+ * patch4: new copyright notice
+ *
+ * Revision 4.0 91/03/20 01:19:37 lwall
+ * 4.0 baseline.
+ *
+ */
+
+#define F_NULL 0
+#define F_LEFT 1
+#define F_RIGHT 2
+#define F_CENTER 3
+#define F_LINES 4
+#define F_DECIMAL 5
+
+struct formcmd {
+ struct formcmd *f_next;
+ ARG *f_expr;
+ STR *f_unparsed;
+ line_t f_line;
+ char *f_pre;
+ short f_presize;
+ short f_size;
+ short f_decimals;
+ char f_type;
+ char f_flags;
+};
+
+#define FC_CHOP 1
+#define FC_NOBLANK 2
+#define FC_MORE 4
+#define FC_REPEAT 8
+#define FC_DP 16
+
+#define Nullfcmd Null(FCMD*)
+
+EXT char *chopset INIT(" \n-");
diff --git a/gnu/usr.bin/perl/perl/handy.h b/gnu/usr.bin/perl/perl/handy.h
new file mode 100644
index 0000000..df71984
--- /dev/null
+++ b/gnu/usr.bin/perl/perl/handy.h
@@ -0,0 +1,153 @@
+/* $RCSfile: handy.h,v $$Revision: 1.1.1.1 $$Date: 1994/09/10 06:27:34 $
+ *
+ * Copyright (c) 1991, Larry Wall
+ *
+ * You may distribute under the terms of either the GNU General Public
+ * License or the Artistic License, as specified in the README file.
+ *
+ * $Log: handy.h,v $
+ * Revision 1.1.1.1 1994/09/10 06:27:34 gclarkii
+ * Initial import of Perl 4.046 bmaked
+ *
+ * Revision 1.1.1.1 1993/08/23 21:29:36 nate
+ * PERL!
+ *
+ * Revision 4.0.1.4 92/06/08 13:23:17 lwall
+ * patch20: isascii() may now be supplied by a library routine
+ * patch20: Perl now distinguishes overlapped copies from non-overlapped
+ *
+ * Revision 4.0.1.3 91/11/05 22:54:26 lwall
+ * patch11: erratum
+ *
+ * Revision 4.0.1.2 91/11/05 17:23:38 lwall
+ * patch11: prepared for ctype implementations that don't define isascii()
+ *
+ * Revision 4.0.1.1 91/06/07 11:09:56 lwall
+ * patch4: new copyright notice
+ *
+ * Revision 4.0 91/03/20 01:22:15 lwall
+ * 4.0 baseline.
+ *
+ */
+
+#ifdef NULL
+#undef NULL
+#endif
+#ifndef I286
+# define NULL 0
+#else
+# define NULL 0L
+#endif
+#define Null(type) ((type)NULL)
+#define Nullch Null(char*)
+#define Nullfp Null(FILE*)
+
+#ifdef UTS
+#define bool int
+#else
+#define bool char
+#endif
+
+#ifdef TRUE
+#undef TRUE
+#endif
+#ifdef FALSE
+#undef FALSE
+#endif
+#define TRUE (1)
+#define FALSE (0)
+
+#define Ctl(ch) (ch & 037)
+
+#define strNE(s1,s2) (strcmp(s1,s2))
+#define strEQ(s1,s2) (!strcmp(s1,s2))
+#define strLT(s1,s2) (strcmp(s1,s2) < 0)
+#define strLE(s1,s2) (strcmp(s1,s2) <= 0)
+#define strGT(s1,s2) (strcmp(s1,s2) > 0)
+#define strGE(s1,s2) (strcmp(s1,s2) >= 0)
+#define strnNE(s1,s2,l) (strncmp(s1,s2,l))
+#define strnEQ(s1,s2,l) (!strncmp(s1,s2,l))
+
+#if defined(CTYPE256) || (!defined(isascii) && !defined(HAS_ISASCII))
+#define isALNUM(c) (isalpha(c) || isdigit(c) || c == '_')
+#define isALPHA(c) isalpha(c)
+#define isSPACE(c) isspace(c)
+#define isDIGIT(c) isdigit(c)
+#define isUPPER(c) isupper(c)
+#define isLOWER(c) islower(c)
+#else
+#define isALNUM(c) (isascii(c) && (isalpha(c) || isdigit(c) || c == '_'))
+#define isALPHA(c) (isascii(c) && isalpha(c))
+#define isSPACE(c) (isascii(c) && isspace(c))
+#define isDIGIT(c) (isascii(c) && isdigit(c))
+#define isUPPER(c) (isascii(c) && isupper(c))
+#define isLOWER(c) (isascii(c) && islower(c))
+#endif
+
+/* Line numbers are unsigned, 16 bits. */
+typedef unsigned short line_t;
+#ifdef lint
+#define NOLINE ((line_t)0)
+#else
+#define NOLINE ((line_t) 65535)
+#endif
+
+#ifndef lint
+#ifndef LEAKTEST
+#ifndef safemalloc
+char *safemalloc();
+char *saferealloc();
+void safefree();
+#endif
+#ifndef MSDOS
+#define New(x,v,n,t) (v = (t*)safemalloc((MEM_SIZE)((n) * sizeof(t))))
+#define Newc(x,v,n,t,c) (v = (c*)safemalloc((MEM_SIZE)((n) * sizeof(t))))
+#define Newz(x,v,n,t) (v = (t*)safemalloc((MEM_SIZE)((n) * sizeof(t)))), \
+ memzero((char*)(v), (n) * sizeof(t))
+#define Renew(v,n,t) (v = (t*)saferealloc((char*)(v),(MEM_SIZE)((n)*sizeof(t))))
+#define Renewc(v,n,t,c) (v = (c*)saferealloc((char*)(v),(MEM_SIZE)((n)*sizeof(t))))
+#else
+#define New(x,v,n,t) (v = (t*)safemalloc(((unsigned long)(n) * sizeof(t))))
+#define Newc(x,v,n,t,c) (v = (c*)safemalloc(((unsigned long)(n) * sizeof(t))))
+#define Newz(x,v,n,t) (v = (t*)safemalloc(((unsigned long)(n) * sizeof(t)))), \
+ memzero((char*)(v), (n) * sizeof(t))
+#define Renew(v,n,t) (v = (t*)saferealloc((char*)(v),((unsigned long)(n)*sizeof(t))))
+#define Renewc(v,n,t,c) (v = (c*)saferealloc((char*)(v),((unsigned long)(n)*sizeof(t))))
+#endif /* MSDOS */
+#define Safefree(d) safefree((char*)d)
+#define Str_new(x,len) str_new(len)
+#else /* LEAKTEST */
+char *safexmalloc();
+char *safexrealloc();
+void safexfree();
+#define New(x,v,n,t) (v = (t*)safexmalloc(x,(MEM_SIZE)((n) * sizeof(t))))
+#define Newc(x,v,n,t,c) (v = (c*)safexmalloc(x,(MEM_SIZE)((n) * sizeof(t))))
+#define Newz(x,v,n,t) (v = (t*)safexmalloc(x,(MEM_SIZE)((n) * sizeof(t)))), \
+ memzero((char*)(v), (n) * sizeof(t))
+#define Renew(v,n,t) (v = (t*)safexrealloc((char*)(v),(MEM_SIZE)((n)*sizeof(t))))
+#define Renewc(v,n,t,c) (v = (c*)safexrealloc((char*)(v),(MEM_SIZE)((n)*sizeof(t))))
+#define Safefree(d) safexfree((char*)d)
+#define Str_new(x,len) str_new(x,len)
+#define MAXXCOUNT 1200
+long xcount[MAXXCOUNT];
+long lastxcount[MAXXCOUNT];
+#endif /* LEAKTEST */
+#define Move(s,d,n,t) (void)memmove((char*)(d),(char*)(s), (n) * sizeof(t))
+#define Copy(s,d,n,t) (void)memcpy((char*)(d),(char*)(s), (n) * sizeof(t))
+#define Zero(d,n,t) (void)memzero((char*)(d), (n) * sizeof(t))
+#else /* lint */
+#define New(x,v,n,s) (v = Null(s *))
+#define Newc(x,v,n,s,c) (v = Null(s *))
+#define Newz(x,v,n,s) (v = Null(s *))
+#define Renew(v,n,s) (v = Null(s *))
+#define Move(s,d,n,t)
+#define Copy(s,d,n,t)
+#define Zero(d,n,t)
+#define Safefree(d) d = d
+#endif /* lint */
+
+#ifdef STRUCTCOPY
+#define StructCopy(s,d,t) *((t*)(d)) = *((t*)(s))
+#else
+#define StructCopy(s,d,t) Copy(s,d,1,t)
+#endif
diff --git a/gnu/usr.bin/perl/perl/hash.c b/gnu/usr.bin/perl/perl/hash.c
new file mode 100644
index 0000000..5d9b594
--- /dev/null
+++ b/gnu/usr.bin/perl/perl/hash.c
@@ -0,0 +1,718 @@
+/* $RCSfile: hash.c,v $$Revision: 1.1.1.1 $$Date: 1994/09/10 06:27:33 $
+ *
+ * Copyright (c) 1991, Larry Wall
+ *
+ * You may distribute under the terms of either the GNU General Public
+ * License or the Artistic License, as specified in the README file.
+ *
+ * $Log: hash.c,v $
+ * Revision 1.1.1.1 1994/09/10 06:27:33 gclarkii
+ * Initial import of Perl 4.046 bmaked
+ *
+ * Revision 1.1.1.1 1993/08/23 21:29:37 nate
+ * PERL!
+ *
+ * Revision 4.0.1.3 92/06/08 13:26:29 lwall
+ * patch20: removed implicit int declarations on functions
+ * patch20: delete could cause %array to give too low a count of buckets filled
+ * patch20: hash tables now split only if the memory is available to do so
+ *
+ * Revision 4.0.1.2 91/11/05 17:24:13 lwall
+ * patch11: saberized perl
+ *
+ * Revision 4.0.1.1 91/06/07 11:10:11 lwall
+ * patch4: new copyright notice
+ *
+ * Revision 4.0 91/03/20 01:22:26 lwall
+ * 4.0 baseline.
+ *
+ */
+
+#include "EXTERN.h"
+#include "perl.h"
+
+static void hsplit();
+
+static char coeff[] = {
+ 61,59,53,47,43,41,37,31,29,23,17,13,11,7,3,1,
+ 61,59,53,47,43,41,37,31,29,23,17,13,11,7,3,1,
+ 61,59,53,47,43,41,37,31,29,23,17,13,11,7,3,1,
+ 61,59,53,47,43,41,37,31,29,23,17,13,11,7,3,1,
+ 61,59,53,47,43,41,37,31,29,23,17,13,11,7,3,1,
+ 61,59,53,47,43,41,37,31,29,23,17,13,11,7,3,1,
+ 61,59,53,47,43,41,37,31,29,23,17,13,11,7,3,1,
+ 61,59,53,47,43,41,37,31,29,23,17,13,11,7,3,1};
+
+static void hfreeentries();
+
+STR *
+hfetch(tb,key,klen,lval)
+register HASH *tb;
+char *key;
+unsigned int klen;
+int lval;
+{
+ register char *s;
+ register int i;
+ register int hash;
+ register HENT *entry;
+ register int maxi;
+ STR *str;
+#ifdef SOME_DBM
+ datum dkey,dcontent;
+#endif
+
+ if (!tb)
+ return &str_undef;
+ if (!tb->tbl_array) {
+ if (lval)
+ Newz(503,tb->tbl_array, tb->tbl_max + 1, HENT*);
+ else
+ return &str_undef;
+ }
+
+ /* The hash function we use on symbols has to be equal to the first
+ * character when taken modulo 128, so that str_reset() can be implemented
+ * efficiently. We throw in the second character and the last character
+ * (times 128) so that long chains of identifiers starting with the
+ * same letter don't have to be strEQ'ed within hfetch(), since it
+ * compares hash values before trying strEQ().
+ */
+ if (!tb->tbl_coeffsize)
+ hash = *key + 128 * key[1] + 128 * key[klen-1]; /* assuming klen > 0 */
+ else { /* use normal coefficients */
+ if (klen < tb->tbl_coeffsize)
+ maxi = klen;
+ else
+ maxi = tb->tbl_coeffsize;
+ for (s=key, i=0, hash = 0;
+ i < maxi; /*SUPPRESS 8*/
+ s++, i++, hash *= 5) {
+ hash += *s * coeff[i];
+ }
+ }
+
+ entry = tb->tbl_array[hash & tb->tbl_max];
+ for (; entry; entry = entry->hent_next) {
+ if (entry->hent_hash != hash) /* strings can't be equal */
+ continue;
+ if (entry->hent_klen != klen)
+ continue;
+ if (bcmp(entry->hent_key,key,klen)) /* is this it? */
+ continue;
+ return entry->hent_val;
+ }
+#ifdef SOME_DBM
+ if (tb->tbl_dbm) {
+ dkey.dptr = key;
+ dkey.dsize = klen;
+#ifdef HAS_GDBM
+ dcontent = gdbm_fetch(tb->tbl_dbm,dkey);
+#else
+ dcontent = dbm_fetch(tb->tbl_dbm,dkey);
+#endif
+ if (dcontent.dptr) { /* found one */
+ str = Str_new(60,dcontent.dsize);
+ str_nset(str,dcontent.dptr,dcontent.dsize);
+ hstore(tb,key,klen,str,hash); /* cache it */
+ return str;
+ }
+ }
+#endif
+ if (lval) { /* gonna assign to this, so it better be there */
+ str = Str_new(61,0);
+ hstore(tb,key,klen,str,hash);
+ return str;
+ }
+ return &str_undef;
+}
+
+bool
+hstore(tb,key,klen,val,hash)
+register HASH *tb;
+char *key;
+unsigned int klen;
+STR *val;
+register int hash;
+{
+ register char *s;
+ register int i;
+ register HENT *entry;
+ register HENT **oentry;
+ register int maxi;
+
+ if (!tb)
+ return FALSE;
+
+ if (hash)
+ /*SUPPRESS 530*/
+ ;
+ else if (!tb->tbl_coeffsize)
+ hash = *key + 128 * key[1] + 128 * key[klen-1];
+ else { /* use normal coefficients */
+ if (klen < tb->tbl_coeffsize)
+ maxi = klen;
+ else
+ maxi = tb->tbl_coeffsize;
+ for (s=key, i=0, hash = 0;
+ i < maxi; /*SUPPRESS 8*/
+ s++, i++, hash *= 5) {
+ hash += *s * coeff[i];
+ }
+ }
+
+ if (!tb->tbl_array)
+ Newz(505,tb->tbl_array, tb->tbl_max + 1, HENT*);
+
+ oentry = &(tb->tbl_array[hash & tb->tbl_max]);
+ i = 1;
+
+ for (entry = *oentry; entry; i=0, entry = entry->hent_next) {
+ if (entry->hent_hash != hash) /* strings can't be equal */
+ continue;
+ if (entry->hent_klen != klen)
+ continue;
+ if (bcmp(entry->hent_key,key,klen)) /* is this it? */
+ continue;
+ Safefree(entry->hent_val);
+ entry->hent_val = val;
+ return TRUE;
+ }
+ New(501,entry, 1, HENT);
+
+ entry->hent_klen = klen;
+ entry->hent_key = nsavestr(key,klen);
+ entry->hent_val = val;
+ entry->hent_hash = hash;
+ entry->hent_next = *oentry;
+ *oentry = entry;
+
+ /* hdbmstore not necessary here because it's called from stabset() */
+
+ if (i) { /* initial entry? */
+ tb->tbl_fill++;
+#ifdef SOME_DBM
+ if (tb->tbl_dbm && tb->tbl_max >= DBM_CACHE_MAX)
+ return FALSE;
+#endif
+ if (tb->tbl_fill > tb->tbl_dosplit)
+ hsplit(tb);
+ }
+#ifdef SOME_DBM
+ else if (tb->tbl_dbm) { /* is this just a cache for dbm file? */
+ void hentdelayfree();
+
+ entry = tb->tbl_array[hash & tb->tbl_max];
+ oentry = &entry->hent_next;
+ entry = *oentry;
+ while (entry) { /* trim chain down to 1 entry */
+ *oentry = entry->hent_next;
+ hentdelayfree(entry); /* no doubt they'll want this next. */
+ entry = *oentry;
+ }
+ }
+#endif
+
+ return FALSE;
+}
+
+STR *
+hdelete(tb,key,klen)
+register HASH *tb;
+char *key;
+unsigned int klen;
+{
+ register char *s;
+ register int i;
+ register int hash;
+ register HENT *entry;
+ register HENT **oentry;
+ STR *str;
+ int maxi;
+#ifdef SOME_DBM
+ datum dkey;
+#endif
+
+ if (!tb || !tb->tbl_array)
+ return Nullstr;
+ if (!tb->tbl_coeffsize)
+ hash = *key + 128 * key[1] + 128 * key[klen-1];
+ else { /* use normal coefficients */
+ if (klen < tb->tbl_coeffsize)
+ maxi = klen;
+ else
+ maxi = tb->tbl_coeffsize;
+ for (s=key, i=0, hash = 0;
+ i < maxi; /*SUPPRESS 8*/
+ s++, i++, hash *= 5) {
+ hash += *s * coeff[i];
+ }
+ }
+
+ oentry = &(tb->tbl_array[hash & tb->tbl_max]);
+ entry = *oentry;
+ i = 1;
+ for (; entry; i=0, oentry = &entry->hent_next, entry = *oentry) {
+ if (entry->hent_hash != hash) /* strings can't be equal */
+ continue;
+ if (entry->hent_klen != klen)
+ continue;
+ if (bcmp(entry->hent_key,key,klen)) /* is this it? */
+ continue;
+ *oentry = entry->hent_next;
+ if (i && !*oentry)
+ tb->tbl_fill--;
+ str = str_mortal(entry->hent_val);
+ hentfree(entry);
+#ifdef SOME_DBM
+ do_dbm_delete:
+ if (tb->tbl_dbm) {
+ dkey.dptr = key;
+ dkey.dsize = klen;
+#ifdef HAS_GDBM
+ gdbm_delete(tb->tbl_dbm,dkey);
+#else
+ dbm_delete(tb->tbl_dbm,dkey);
+#endif
+ }
+#endif
+ return str;
+ }
+#ifdef SOME_DBM
+ str = Nullstr;
+ goto do_dbm_delete;
+#else
+ return Nullstr;
+#endif
+}
+
+static void
+hsplit(tb)
+HASH *tb;
+{
+ int oldsize = tb->tbl_max + 1;
+ register int newsize = oldsize * 2;
+ register int i;
+ register HENT **a;
+ register HENT **b;
+ register HENT *entry;
+ register HENT **oentry;
+
+ a = tb->tbl_array;
+ nomemok = TRUE;
+ Renew(a, newsize, HENT*);
+ nomemok = FALSE;
+ if (!a) {
+ tb->tbl_dosplit = tb->tbl_max + 1; /* never split again */
+ return;
+ }
+ Zero(&a[oldsize], oldsize, HENT*); /* zero 2nd half*/
+ tb->tbl_max = --newsize;
+ tb->tbl_dosplit = tb->tbl_max * FILLPCT / 100;
+ tb->tbl_array = a;
+
+ for (i=0; i<oldsize; i++,a++) {
+ if (!*a) /* non-existent */
+ continue;
+ b = a+oldsize;
+ for (oentry = a, entry = *a; entry; entry = *oentry) {
+ if ((entry->hent_hash & newsize) != i) {
+ *oentry = entry->hent_next;
+ entry->hent_next = *b;
+ if (!*b)
+ tb->tbl_fill++;
+ *b = entry;
+ continue;
+ }
+ else
+ oentry = &entry->hent_next;
+ }
+ if (!*a) /* everything moved */
+ tb->tbl_fill--;
+ }
+}
+
+HASH *
+hnew(lookat)
+unsigned int lookat;
+{
+ register HASH *tb;
+
+ Newz(502,tb, 1, HASH);
+ if (lookat) {
+ tb->tbl_coeffsize = lookat;
+ tb->tbl_max = 7; /* it's a normal associative array */
+ tb->tbl_dosplit = tb->tbl_max * FILLPCT / 100;
+ }
+ else {
+ tb->tbl_max = 127; /* it's a symbol table */
+ tb->tbl_dosplit = 128; /* so never split */
+ }
+ tb->tbl_fill = 0;
+#ifdef SOME_DBM
+ tb->tbl_dbm = 0;
+#endif
+ (void)hiterinit(tb); /* so each() will start off right */
+ return tb;
+}
+
+void
+hentfree(hent)
+register HENT *hent;
+{
+ if (!hent)
+ return;
+ str_free(hent->hent_val);
+ Safefree(hent->hent_key);
+ Safefree(hent);
+}
+
+void
+hentdelayfree(hent)
+register HENT *hent;
+{
+ if (!hent)
+ return;
+ str_2mortal(hent->hent_val); /* free between statements */
+ Safefree(hent->hent_key);
+ Safefree(hent);
+}
+
+void
+hclear(tb,dodbm)
+register HASH *tb;
+int dodbm;
+{
+ if (!tb)
+ return;
+ hfreeentries(tb,dodbm);
+ tb->tbl_fill = 0;
+#ifndef lint
+ if (tb->tbl_array)
+ (void)memzero((char*)tb->tbl_array, (tb->tbl_max + 1) * sizeof(HENT*));
+#endif
+}
+
+static void
+hfreeentries(tb,dodbm)
+register HASH *tb;
+int dodbm;
+{
+ register HENT *hent;
+ register HENT *ohent = Null(HENT*);
+#ifdef SOME_DBM
+ datum dkey;
+ datum nextdkey;
+#ifdef HAS_GDBM
+ GDBM_FILE old_dbm;
+#else
+#ifdef HAS_NDBM
+ DBM *old_dbm;
+#else
+ int old_dbm;
+#endif
+#endif
+#endif
+
+ if (!tb || !tb->tbl_array)
+ return;
+#ifdef SOME_DBM
+ if ((old_dbm = tb->tbl_dbm) && dodbm) {
+#ifdef HAS_GDBM
+ while (dkey = gdbm_firstkey(tb->tbl_dbm), dkey.dptr) {
+#else
+ while (dkey = dbm_firstkey(tb->tbl_dbm), dkey.dptr) {
+#endif
+ do {
+#ifdef HAS_GDBM
+ nextdkey = gdbm_nextkey(tb->tbl_dbm, dkey);
+#else
+#ifdef HAS_NDBM
+#ifdef _CX_UX
+ nextdkey = dbm_nextkey(tb->tbl_dbm, dkey);
+#else
+ nextdkey = dbm_nextkey(tb->tbl_dbm);
+#endif
+#else
+ nextdkey = nextkey(dkey);
+#endif
+#endif
+#ifdef HAS_GDBM
+ gdbm_delete(tb->tbl_dbm,dkey);
+#else
+ dbm_delete(tb->tbl_dbm,dkey);
+#endif
+ dkey = nextdkey;
+ } while (dkey.dptr); /* one way or another, this works */
+ }
+ }
+ tb->tbl_dbm = 0; /* now clear just cache */
+#endif
+ (void)hiterinit(tb);
+ /*SUPPRESS 560*/
+ while (hent = hiternext(tb)) { /* concise but not very efficient */
+ hentfree(ohent);
+ ohent = hent;
+ }
+ hentfree(ohent);
+#ifdef SOME_DBM
+ tb->tbl_dbm = old_dbm;
+#endif
+}
+
+void
+hfree(tb,dodbm)
+register HASH *tb;
+int dodbm;
+{
+ if (!tb)
+ return;
+ hfreeentries(tb,dodbm);
+ Safefree(tb->tbl_array);
+ Safefree(tb);
+}
+
+int
+hiterinit(tb)
+register HASH *tb;
+{
+ tb->tbl_riter = -1;
+ tb->tbl_eiter = Null(HENT*);
+ return tb->tbl_fill;
+}
+
+HENT *
+hiternext(tb)
+register HASH *tb;
+{
+ register HENT *entry;
+#ifdef SOME_DBM
+ datum key;
+#endif
+
+ entry = tb->tbl_eiter;
+#ifdef SOME_DBM
+ if (tb->tbl_dbm) {
+ if (entry) {
+#ifdef HAS_GDBM
+ key.dptr = entry->hent_key;
+ key.dsize = entry->hent_klen;
+ key = gdbm_nextkey(tb->tbl_dbm, key);
+#else
+#ifdef HAS_NDBM
+#ifdef _CX_UX
+ key.dptr = entry->hent_key;
+ key.dsize = entry->hent_klen;
+ key = dbm_nextkey(tb->tbl_dbm, key);
+#else
+ key = dbm_nextkey(tb->tbl_dbm);
+#endif /* _CX_UX */
+#else
+ key.dptr = entry->hent_key;
+ key.dsize = entry->hent_klen;
+ key = nextkey(key);
+#endif
+#endif
+ }
+ else {
+ Newz(504,entry, 1, HENT);
+ tb->tbl_eiter = entry;
+#ifdef HAS_GDBM
+ key = gdbm_firstkey(tb->tbl_dbm);
+#else
+ key = dbm_firstkey(tb->tbl_dbm);
+#endif
+ }
+ entry->hent_key = key.dptr;
+ entry->hent_klen = key.dsize;
+ if (!key.dptr) {
+ if (entry->hent_val)
+ str_free(entry->hent_val);
+ Safefree(entry);
+ tb->tbl_eiter = Null(HENT*);
+ return Null(HENT*);
+ }
+ return entry;
+ }
+#endif
+ if (!tb->tbl_array)
+ Newz(506,tb->tbl_array, tb->tbl_max + 1, HENT*);
+ do {
+ if (entry)
+ entry = entry->hent_next;
+ if (!entry) {
+ tb->tbl_riter++;
+ if (tb->tbl_riter > tb->tbl_max) {
+ tb->tbl_riter = -1;
+ break;
+ }
+ entry = tb->tbl_array[tb->tbl_riter];
+ }
+ } while (!entry);
+
+ tb->tbl_eiter = entry;
+ return entry;
+}
+
+char *
+hiterkey(entry,retlen)
+register HENT *entry;
+int *retlen;
+{
+ *retlen = entry->hent_klen;
+ return entry->hent_key;
+}
+
+STR *
+hiterval(tb,entry)
+register HASH *tb;
+register HENT *entry;
+{
+#ifdef SOME_DBM
+ datum key, content;
+
+ if (tb->tbl_dbm) {
+ key.dptr = entry->hent_key;
+ key.dsize = entry->hent_klen;
+#ifdef HAS_GDBM
+ content = gdbm_fetch(tb->tbl_dbm,key);
+#else
+ content = dbm_fetch(tb->tbl_dbm,key);
+#endif
+ if (!entry->hent_val)
+ entry->hent_val = Str_new(62,0);
+ str_nset(entry->hent_val,content.dptr,content.dsize);
+ }
+#endif
+ return entry->hent_val;
+}
+
+#ifdef SOME_DBM
+
+#ifndef O_CREAT
+# ifdef I_FCNTL
+# include <fcntl.h>
+# endif
+# ifdef I_SYS_FILE
+# include <sys/file.h>
+# endif
+#endif
+
+#ifndef O_RDONLY
+#define O_RDONLY 0
+#endif
+#ifndef O_RDWR
+#define O_RDWR 2
+#endif
+#ifndef O_CREAT
+#define O_CREAT 01000
+#endif
+
+#ifdef HAS_ODBM
+static int dbmrefcnt = 0;
+#endif
+
+bool
+hdbmopen(tb,fname,mode)
+register HASH *tb;
+char *fname;
+int mode;
+{
+ if (!tb)
+ return FALSE;
+#ifdef HAS_ODBM
+ if (tb->tbl_dbm) /* never really closed it */
+ return TRUE;
+#endif
+ if (tb->tbl_dbm) {
+ hdbmclose(tb);
+ tb->tbl_dbm = 0;
+ }
+ hclear(tb, FALSE); /* clear cache */
+#ifdef HAS_GDBM
+ if (mode >= 0)
+ tb->tbl_dbm = gdbm_open(fname, 0, GDBM_WRCREAT,mode, (void *) NULL);
+ if (!tb->tbl_dbm)
+ tb->tbl_dbm = gdbm_open(fname, 0, GDBM_WRITER, mode, (void *) NULL);
+ if (!tb->tbl_dbm)
+ tb->tbl_dbm = gdbm_open(fname, 0, GDBM_READER, mode, (void *) NULL);
+#else
+#ifdef HAS_NDBM
+ if (mode >= 0)
+ tb->tbl_dbm = dbm_open(fname, O_RDWR|O_CREAT, mode);
+ if (!tb->tbl_dbm)
+ tb->tbl_dbm = dbm_open(fname, O_RDWR, mode);
+ if (!tb->tbl_dbm)
+ tb->tbl_dbm = dbm_open(fname, O_RDONLY, mode);
+#else
+ if (dbmrefcnt++)
+ fatal("Old dbm can only open one database");
+ sprintf(buf,"%s.dir",fname);
+ if (stat(buf, &statbuf) < 0) {
+ if (mode < 0 || close(creat(buf,mode)) < 0)
+ return FALSE;
+ sprintf(buf,"%s.pag",fname);
+ if (close(creat(buf,mode)) < 0)
+ return FALSE;
+ }
+ tb->tbl_dbm = dbminit(fname) >= 0;
+#endif
+#endif
+ if (!tb->tbl_array && tb->tbl_dbm != 0)
+ Newz(507,tb->tbl_array, tb->tbl_max + 1, HENT*);
+ return tb->tbl_dbm != 0;
+}
+
+void
+hdbmclose(tb)
+register HASH *tb;
+{
+ if (tb && tb->tbl_dbm) {
+#ifdef HAS_GDBM
+ gdbm_close(tb->tbl_dbm);
+ tb->tbl_dbm = 0;
+#else
+#ifdef HAS_NDBM
+ dbm_close(tb->tbl_dbm);
+ tb->tbl_dbm = 0;
+#else
+ /* dbmrefcnt--; */ /* doesn't work, rats */
+#endif
+#endif
+ }
+ else if (dowarn)
+ warn("Close on unopened dbm file");
+}
+
+bool
+hdbmstore(tb,key,klen,str)
+register HASH *tb;
+char *key;
+unsigned int klen;
+register STR *str;
+{
+ datum dkey, dcontent;
+ int error;
+
+ if (!tb || !tb->tbl_dbm)
+ return FALSE;
+ dkey.dptr = key;
+ dkey.dsize = klen;
+ dcontent.dptr = str_get(str);
+ dcontent.dsize = str->str_cur;
+#ifdef HAS_GDBM
+ error = gdbm_store(tb->tbl_dbm, dkey, dcontent, GDBM_REPLACE);
+#else
+ error = dbm_store(tb->tbl_dbm, dkey, dcontent, DBM_REPLACE);
+#endif
+ if (error) {
+ if (errno == EPERM)
+ fatal("No write permission to dbm file");
+ warn("dbm store returned %d, errno %d, key \"%s\"",error,errno,key);
+#ifdef HAS_NDBM
+ dbm_clearerr(tb->tbl_dbm);
+#endif
+ }
+ return !error;
+}
+#endif /* SOME_DBM */
diff --git a/gnu/usr.bin/perl/perl/hash.h b/gnu/usr.bin/perl/perl/hash.h
new file mode 100644
index 0000000..ddf2a11
--- /dev/null
+++ b/gnu/usr.bin/perl/perl/hash.h
@@ -0,0 +1,78 @@
+/* $RCSfile: hash.h,v $$Revision: 1.1.1.1 $$Date: 1994/09/10 06:27:35 $
+ *
+ * Copyright (c) 1991, Larry Wall
+ *
+ * You may distribute under the terms of either the GNU General Public
+ * License or the Artistic License, as specified in the README file.
+ *
+ * $Log: hash.h,v $
+ * Revision 1.1.1.1 1994/09/10 06:27:35 gclarkii
+ * Initial import of Perl 4.046 bmaked
+ *
+ * Revision 1.1.1.1 1993/08/23 21:29:37 nate
+ * PERL!
+ *
+ * Revision 4.0.1.2 91/11/05 17:24:31 lwall
+ * patch11: random cleanup
+ *
+ * Revision 4.0.1.1 91/06/07 11:10:33 lwall
+ * patch4: new copyright notice
+ *
+ * Revision 4.0 91/03/20 01:22:38 lwall
+ * 4.0 baseline.
+ *
+ */
+
+#define FILLPCT 80 /* don't make greater than 99 */
+#define DBM_CACHE_MAX 63 /* cache 64 entries for dbm file */
+ /* (resident array acts as a write-thru cache)*/
+
+#define COEFFSIZE (16 * 8) /* size of coeff array */
+
+typedef struct hentry HENT;
+
+struct hentry {
+ HENT *hent_next;
+ char *hent_key;
+ STR *hent_val;
+ int hent_hash;
+ int hent_klen;
+};
+
+struct htbl {
+ HENT **tbl_array;
+ int tbl_max; /* subscript of last element of tbl_array */
+ int tbl_dosplit; /* how full to get before splitting */
+ int tbl_fill; /* how full tbl_array currently is */
+ int tbl_riter; /* current root of iterator */
+ HENT *tbl_eiter; /* current entry of iterator */
+ SPAT *tbl_spatroot; /* list of spats for this package */
+ char *tbl_name; /* name, if a symbol table */
+#ifdef SOME_DBM
+#ifdef HAS_GDBM
+ GDBM_FILE tbl_dbm;
+#else
+#ifdef HAS_NDBM
+ DBM *tbl_dbm;
+#else
+ int tbl_dbm;
+#endif
+#endif
+#endif
+ unsigned char tbl_coeffsize; /* is 0 for symbol tables */
+};
+
+STR *hfetch();
+bool hstore();
+STR *hdelete();
+HASH *hnew();
+void hclear();
+void hentfree();
+void hfree();
+int hiterinit();
+HENT *hiternext();
+char *hiterkey();
+STR *hiterval();
+bool hdbmopen();
+void hdbmclose();
+bool hdbmstore();
diff --git a/gnu/usr.bin/perl/perl/malloc.c b/gnu/usr.bin/perl/perl/malloc.c
new file mode 100644
index 0000000..5cc86d9
--- /dev/null
+++ b/gnu/usr.bin/perl/perl/malloc.c
@@ -0,0 +1,513 @@
+/* $RCSfile: malloc.c,v $$Revision: 1.1.1.1 $$Date: 1994/09/10 06:27:33 $
+ *
+ * $Log: malloc.c,v $
+ * Revision 1.1.1.1 1994/09/10 06:27:33 gclarkii
+ * Initial import of Perl 4.046 bmaked
+ *
+ * Revision 1.1.1.1 1993/08/23 21:29:37 nate
+ * PERL!
+ *
+ * Revision 4.0.1.4 92/06/08 14:28:38 lwall
+ * patch20: removed implicit int declarations on functions
+ * patch20: hash tables now split only if the memory is available to do so
+ * patch20: realloc(0, size) now does malloc in case library routines call it
+ *
+ * Revision 4.0.1.3 91/11/05 17:57:40 lwall
+ * patch11: safe malloc code now integrated into Perl's malloc when possible
+ *
+ * Revision 4.0.1.2 91/06/07 11:20:45 lwall
+ * patch4: many, many itty-bitty portability fixes
+ *
+ * Revision 4.0.1.1 91/04/11 17:48:31 lwall
+ * patch1: Configure now figures out malloc ptr type
+ *
+ * Revision 4.0 91/03/20 01:28:52 lwall
+ * 4.0 baseline.
+ *
+ */
+
+#ifndef lint
+/*SUPPRESS 592*/
+static char sccsid[] = "@(#)malloc.c 4.3 (Berkeley) 9/16/83";
+
+#ifdef DEBUGGING
+#define RCHECK
+#endif
+/*
+ * malloc.c (Caltech) 2/21/82
+ * Chris Kingsley, kingsley@cit-20.
+ *
+ * This is a very fast storage allocator. It allocates blocks of a small
+ * number of different sizes, and keeps free lists of each size. Blocks that
+ * don't exactly fit are passed up to the next larger size. In this
+ * implementation, the available sizes are 2^n-4 (or 2^n-12) bytes long.
+ * This is designed for use in a program that uses vast quantities of memory,
+ * but bombs when it runs out.
+ */
+
+#include "EXTERN.h"
+#include "perl.h"
+
+static findbucket(), morecore();
+
+/* I don't much care whether these are defined in sys/types.h--LAW */
+
+#define u_char unsigned char
+#define u_int unsigned int
+#define u_short unsigned short
+
+/*
+ * The overhead on a block is at least 4 bytes. When free, this space
+ * contains a pointer to the next free block, and the bottom two bits must
+ * be zero. When in use, the first byte is set to MAGIC, and the second
+ * byte is the size index. The remaining bytes are for alignment.
+ * If range checking is enabled and the size of the block fits
+ * in two bytes, then the top two bytes hold the size of the requested block
+ * plus the range checking words, and the header word MINUS ONE.
+ */
+union overhead {
+ union overhead *ov_next; /* when free */
+#if ALIGN_BYTES > 4
+ double strut; /* alignment problems */
+#endif
+ struct {
+ u_char ovu_magic; /* magic number */
+ u_char ovu_index; /* bucket # */
+#ifdef RCHECK
+ u_short ovu_size; /* actual block size */
+ u_int ovu_rmagic; /* range magic number */
+#endif
+ } ovu;
+#define ov_magic ovu.ovu_magic
+#define ov_index ovu.ovu_index
+#define ov_size ovu.ovu_size
+#define ov_rmagic ovu.ovu_rmagic
+};
+
+#define MAGIC 0xff /* magic # on accounting info */
+#define OLDMAGIC 0x7f /* same after a free() */
+#define RMAGIC 0x55555555 /* magic # on range info */
+#ifdef RCHECK
+#define RSLOP sizeof (u_int)
+#else
+#define RSLOP 0
+#endif
+
+/*
+ * nextf[i] is the pointer to the next free block of size 2^(i+3). The
+ * smallest allocatable block is 8 bytes. The overhead information
+ * precedes the data area returned to the user.
+ */
+#define NBUCKETS 30
+static union overhead *nextf[NBUCKETS];
+extern char *sbrk();
+
+#ifdef MSTATS
+/*
+ * nmalloc[i] is the difference between the number of mallocs and frees
+ * for a given block size.
+ */
+static u_int nmalloc[NBUCKETS];
+#include <stdio.h>
+#endif
+
+#ifdef debug
+#define ASSERT(p) if (!(p)) botch("p"); else
+static void
+botch(s)
+ char *s;
+{
+
+ printf("assertion botched: %s\n", s);
+ abort();
+}
+#else
+#define ASSERT(p)
+#endif
+
+#ifdef safemalloc
+static int an = 0;
+#endif
+
+MALLOCPTRTYPE *
+malloc(nbytes)
+ register MEM_SIZE nbytes;
+{
+ register union overhead *p;
+ register int bucket = 0;
+ register MEM_SIZE shiftr;
+
+#ifdef safemalloc
+#ifdef DEBUGGING
+ MEM_SIZE size = nbytes;
+#endif
+
+#ifdef MSDOS
+ if (nbytes > 0xffff) {
+ fprintf(stderr, "Allocation too large: %lx\n", (long)nbytes);
+ exit(1);
+ }
+#endif /* MSDOS */
+#ifdef DEBUGGING
+ if ((long)nbytes < 0)
+ fatal("panic: malloc");
+#endif
+#endif /* safemalloc */
+
+ /*
+ * Convert amount of memory requested into
+ * closest block size stored in hash buckets
+ * which satisfies request. Account for
+ * space used per block for accounting.
+ */
+ nbytes += sizeof (union overhead) + RSLOP;
+ nbytes = (nbytes + 3) &~ 3;
+ shiftr = (nbytes - 1) >> 2;
+ /* apart from this loop, this is O(1) */
+ while (shiftr >>= 1)
+ bucket++;
+ /*
+ * If nothing in hash bucket right now,
+ * request more memory from the system.
+ */
+ if (nextf[bucket] == NULL)
+ morecore(bucket);
+ if ((p = (union overhead *)nextf[bucket]) == NULL) {
+#ifdef safemalloc
+ if (!nomemok) {
+ fputs("Out of memory!\n", stderr);
+ exit(1);
+ }
+#else
+ return (NULL);
+#endif
+ }
+
+#ifdef safemalloc
+#ifdef DEBUGGING
+# if !(defined(I286) || defined(atarist))
+ if (debug & 128)
+ fprintf(stderr,"0x%x: (%05d) malloc %ld bytes\n",p+1,an++,(long)size);
+# else
+ if (debug & 128)
+ fprintf(stderr,"0x%lx: (%05d) malloc %ld bytes\n",p+1,an++,(long)size);
+# endif
+#endif
+#endif /* safemalloc */
+
+ /* remove from linked list */
+#ifdef RCHECK
+ if (*((int*)p) & (sizeof(union overhead) - 1))
+#if !(defined(I286) || defined(atarist))
+ fprintf(stderr,"Corrupt malloc ptr 0x%x at 0x%x\n",*((int*)p),p);
+#else
+ fprintf(stderr,"Corrupt malloc ptr 0x%lx at 0x%lx\n",*((int*)p),p);
+#endif
+#endif
+ nextf[bucket] = p->ov_next;
+ p->ov_magic = MAGIC;
+ p->ov_index= bucket;
+#ifdef MSTATS
+ nmalloc[bucket]++;
+#endif
+#ifdef RCHECK
+ /*
+ * Record allocated size of block and
+ * bound space with magic numbers.
+ */
+ if (nbytes <= 0x10000)
+ p->ov_size = nbytes - 1;
+ p->ov_rmagic = RMAGIC;
+ *((u_int *)((caddr_t)p + nbytes - RSLOP)) = RMAGIC;
+#endif
+ return ((MALLOCPTRTYPE *)(p + 1));
+}
+
+/*
+ * Allocate more memory to the indicated bucket.
+ */
+static
+morecore(bucket)
+ register int bucket;
+{
+ register union overhead *op;
+ register int rnu; /* 2^rnu bytes will be requested */
+ register int nblks; /* become nblks blocks of the desired size */
+ register MEM_SIZE siz;
+
+ if (nextf[bucket])
+ return;
+ /*
+ * Insure memory is allocated
+ * on a page boundary. Should
+ * make getpageize call?
+ */
+#ifndef atarist /* on the atari we dont have to worry about this */
+ op = (union overhead *)sbrk(0);
+#ifndef I286
+ if ((int)op & 0x3ff)
+ (void)sbrk(1024 - ((int)op & 0x3ff));
+#else
+ /* The sbrk(0) call on the I286 always returns the next segment */
+#endif
+#endif /* atarist */
+
+#if !(defined(I286) || defined(atarist))
+ /* take 2k unless the block is bigger than that */
+ rnu = (bucket <= 8) ? 11 : bucket + 3;
+#else
+ /* take 16k unless the block is bigger than that
+ (80286s like large segments!), probably good on the atari too */
+ rnu = (bucket <= 11) ? 14 : bucket + 3;
+#endif
+ nblks = 1 << (rnu - (bucket + 3)); /* how many blocks to get */
+ if (rnu < bucket)
+ rnu = bucket;
+ op = (union overhead *)sbrk(1L << rnu);
+ /* no more room! */
+ if ((int)op == -1)
+ return;
+ /*
+ * Round up to minimum allocation size boundary
+ * and deduct from block count to reflect.
+ */
+#ifndef I286
+ if ((int)op & 7) {
+ op = (union overhead *)(((MEM_SIZE)op + 8) &~ 7);
+ nblks--;
+ }
+#else
+ /* Again, this should always be ok on an 80286 */
+#endif
+ /*
+ * Add new memory allocated to that on
+ * free list for this hash bucket.
+ */
+ nextf[bucket] = op;
+ siz = 1 << (bucket + 3);
+ while (--nblks > 0) {
+ op->ov_next = (union overhead *)((caddr_t)op + siz);
+ op = (union overhead *)((caddr_t)op + siz);
+ }
+}
+
+void
+free(mp)
+ MALLOCPTRTYPE *mp;
+{
+ register MEM_SIZE size;
+ register union overhead *op;
+ char *cp = (char*)mp;
+
+#ifdef safemalloc
+#ifdef DEBUGGING
+# if !(defined(I286) || defined(atarist))
+ if (debug & 128)
+ fprintf(stderr,"0x%x: (%05d) free\n",cp,an++);
+# else
+ if (debug & 128)
+ fprintf(stderr,"0x%lx: (%05d) free\n",cp,an++);
+# endif
+#endif
+#endif /* safemalloc */
+
+ if (cp == NULL)
+ return;
+ op = (union overhead *)((caddr_t)cp - sizeof (union overhead));
+#ifdef debug
+ ASSERT(op->ov_magic == MAGIC); /* make sure it was in use */
+#else
+ if (op->ov_magic != MAGIC) {
+ warn("%s free() ignored",
+ op->ov_magic == OLDMAGIC ? "Duplicate" : "Bad");
+ return; /* sanity */
+ }
+ op->ov_magic = OLDMAGIC;
+#endif
+#ifdef RCHECK
+ ASSERT(op->ov_rmagic == RMAGIC);
+ if (op->ov_index <= 13)
+ ASSERT(*(u_int *)((caddr_t)op + op->ov_size + 1 - RSLOP) == RMAGIC);
+#endif
+ ASSERT(op->ov_index < NBUCKETS);
+ size = op->ov_index;
+ op->ov_next = nextf[size];
+ nextf[size] = op;
+#ifdef MSTATS
+ nmalloc[size]--;
+#endif
+}
+
+/*
+ * When a program attempts "storage compaction" as mentioned in the
+ * old malloc man page, it realloc's an already freed block. Usually
+ * this is the last block it freed; occasionally it might be farther
+ * back. We have to search all the free lists for the block in order
+ * to determine its bucket: 1st we make one pass thru the lists
+ * checking only the first block in each; if that fails we search
+ * ``reall_srchlen'' blocks in each list for a match (the variable
+ * is extern so the caller can modify it). If that fails we just copy
+ * however many bytes was given to realloc() and hope it's not huge.
+ */
+int reall_srchlen = 4; /* 4 should be plenty, -1 =>'s whole list */
+
+MALLOCPTRTYPE *
+realloc(mp, nbytes)
+ MALLOCPTRTYPE *mp;
+ MEM_SIZE nbytes;
+{
+ register MEM_SIZE onb;
+ union overhead *op;
+ char *res;
+ register int i;
+ int was_alloced = 0;
+ char *cp = (char*)mp;
+
+#ifdef safemalloc
+#ifdef DEBUGGING
+ MEM_SIZE size = nbytes;
+#endif
+
+#ifdef MSDOS
+ if (nbytes > 0xffff) {
+ fprintf(stderr, "Reallocation too large: %lx\n", size);
+ exit(1);
+ }
+#endif /* MSDOS */
+ if (!cp)
+ return malloc(nbytes);
+#ifdef DEBUGGING
+ if ((long)nbytes < 0)
+ fatal("panic: realloc");
+#endif
+#endif /* safemalloc */
+
+ op = (union overhead *)((caddr_t)cp - sizeof (union overhead));
+ if (op->ov_magic == MAGIC) {
+ was_alloced++;
+ i = op->ov_index;
+ } else {
+ /*
+ * Already free, doing "compaction".
+ *
+ * Search for the old block of memory on the
+ * free list. First, check the most common
+ * case (last element free'd), then (this failing)
+ * the last ``reall_srchlen'' items free'd.
+ * If all lookups fail, then assume the size of
+ * the memory block being realloc'd is the
+ * smallest possible.
+ */
+ if ((i = findbucket(op, 1)) < 0 &&
+ (i = findbucket(op, reall_srchlen)) < 0)
+ i = 0;
+ }
+ onb = (1L << (i + 3)) - sizeof (*op) - RSLOP;
+ /* avoid the copy if same size block */
+ if (was_alloced &&
+ nbytes <= onb && nbytes > (onb >> 1) - sizeof(*op) - RSLOP) {
+#ifdef RCHECK
+ /*
+ * Record new allocated size of block and
+ * bound space with magic numbers.
+ */
+ if (op->ov_index <= 13) {
+ /*
+ * Convert amount of memory requested into
+ * closest block size stored in hash buckets
+ * which satisfies request. Account for
+ * space used per block for accounting.
+ */
+ nbytes += sizeof (union overhead) + RSLOP;
+ nbytes = (nbytes + 3) &~ 3;
+ op->ov_size = nbytes - 1;
+ *((u_int *)((caddr_t)op + nbytes - RSLOP)) = RMAGIC;
+ }
+#endif
+ res = cp;
+ }
+ else {
+ if ((res = (char*)malloc(nbytes)) == NULL)
+ return (NULL);
+ if (cp != res) /* common optimization */
+ Copy(cp, res, (MEM_SIZE)(nbytes<onb?nbytes:onb), char);
+ if (was_alloced)
+ free(cp);
+ }
+
+#ifdef safemalloc
+#ifdef DEBUGGING
+# if !(defined(I286) || defined(atarist))
+ if (debug & 128) {
+ fprintf(stderr,"0x%x: (%05d) rfree\n",res,an++);
+ fprintf(stderr,"0x%x: (%05d) realloc %ld bytes\n",res,an++,(long)size);
+ }
+# else
+ if (debug & 128) {
+ fprintf(stderr,"0x%lx: (%05d) rfree\n",res,an++);
+ fprintf(stderr,"0x%lx: (%05d) realloc %ld bytes\n",res,an++,(long)size);
+ }
+# endif
+#endif
+#endif /* safemalloc */
+ return ((MALLOCPTRTYPE*)res);
+}
+
+/*
+ * Search ``srchlen'' elements of each free list for a block whose
+ * header starts at ``freep''. If srchlen is -1 search the whole list.
+ * Return bucket number, or -1 if not found.
+ */
+static int
+findbucket(freep, srchlen)
+ union overhead *freep;
+ int srchlen;
+{
+ register union overhead *p;
+ register int i, j;
+
+ for (i = 0; i < NBUCKETS; i++) {
+ j = 0;
+ for (p = nextf[i]; p && j != srchlen; p = p->ov_next) {
+ if (p == freep)
+ return (i);
+ j++;
+ }
+ }
+ return (-1);
+}
+
+#ifdef MSTATS
+/*
+ * mstats - print out statistics about malloc
+ *
+ * Prints two lines of numbers, one showing the length of the free list
+ * for each size category, the second showing the number of mallocs -
+ * frees for each size category.
+ */
+void
+mstats(s)
+ char *s;
+{
+ register int i, j;
+ register union overhead *p;
+ int totfree = 0,
+ totused = 0;
+
+ fprintf(stderr, "Memory allocation statistics %s\nfree:\t", s);
+ for (i = 0; i < NBUCKETS; i++) {
+ for (j = 0, p = nextf[i]; p; p = p->ov_next, j++)
+ ;
+ fprintf(stderr, " %d", j);
+ totfree += j * (1 << (i + 3));
+ }
+ fprintf(stderr, "\nused:\t");
+ for (i = 0; i < NBUCKETS; i++) {
+ fprintf(stderr, " %d", nmalloc[i]);
+ totused += nmalloc[i] * (1 << (i + 3));
+ }
+ fprintf(stderr, "\n\tTotal in use: %d, total free: %d\n",
+ totused, totfree);
+}
+#endif
+#endif /* lint */
diff --git a/gnu/usr.bin/perl/perl/patchlevel.h b/gnu/usr.bin/perl/perl/patchlevel.h
new file mode 100644
index 0000000..d248b35
--- /dev/null
+++ b/gnu/usr.bin/perl/perl/patchlevel.h
@@ -0,0 +1 @@
+#define PATCHLEVEL 36
diff --git a/gnu/usr.bin/perl/perl/perl.1 b/gnu/usr.bin/perl/perl/perl.1
new file mode 100644
index 0000000..15791c2
--- /dev/null
+++ b/gnu/usr.bin/perl/perl/perl.1
@@ -0,0 +1,6013 @@
+.rn '' }`
+''' $RCSfile: perl.1,v $$Revision: 1.1.1.1 $$Date: 1994/09/10 06:27:36 $
+'''
+''' $Log: perl.1,v $
+.\" Revision 1.1.1.1 1994/09/10 06:27:36 gclarkii
+.\" Initial import of Perl 4.046 bmaked
+.\"
+.\" Revision 1.1.1.1 1993/08/23 21:29:37 nate
+.\" PERL!
+.\"
+''' Revision 4.0.1.6 92/06/08 15:07:29 lwall
+''' patch20: documented that numbers may contain underline
+''' patch20: clarified that DATA may only be read from main script
+''' patch20: relaxed requirement for semicolon at the end of a block
+''' patch20: added ... as variant on ..
+''' patch20: documented need for 1; at the end of a required file
+''' patch20: extended bracket-style quotes to two-arg operators: s()() and tr()()
+''' patch20: paragraph mode now skips extra newlines automatically
+''' patch20: documented PERLLIB and PERLDB
+''' patch20: documented limit on size of regexp
+'''
+''' Revision 4.0.1.5 91/11/11 16:42:00 lwall
+''' patch19: added little-endian pack/unpack options
+'''
+''' Revision 4.0.1.4 91/11/05 18:11:05 lwall
+''' patch11: added sort {} LIST
+''' patch11: added eval {}
+''' patch11: documented meaning of scalar(%foo)
+''' patch11: sprintf() now supports any length of s field
+'''
+''' Revision 4.0.1.3 91/06/10 01:26:02 lwall
+''' patch10: documented some newer features in addenda
+'''
+''' Revision 4.0.1.2 91/06/07 11:41:23 lwall
+''' patch4: added global modifier for pattern matches
+''' patch4: default top-of-form format is now FILEHANDLE_TOP
+''' patch4: added $^P variable to control calling of perldb routines
+''' patch4: added $^F variable to specify maximum system fd, default 2
+''' patch4: changed old $^P to $^X
+'''
+''' Revision 4.0.1.1 91/04/11 17:50:44 lwall
+''' patch1: fixed some typos
+'''
+''' Revision 4.0 91/03/20 01:38:08 lwall
+''' 4.0 baseline.
+'''
+'''
+.de Sh
+.br
+.ne 5
+.PP
+\fB\\$1\fR
+.PP
+..
+.de Sp
+.if t .sp .5v
+.if n .sp
+..
+.de Ip
+.br
+.ie \\n(.$>=3 .ne \\$3
+.el .ne 3
+.IP "\\$1" \\$2
+..
+'''
+''' Set up \*(-- to give an unbreakable dash;
+''' string Tr holds user defined translation string.
+''' Bell System Logo is used as a dummy character.
+'''
+.tr \(*W-|\(bv\*(Tr
+.ie n \{\
+.ds -- \(*W-
+.if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch
+.if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\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 PERL 1 "\*(RP"
+.UC
+.SH NAME
+perl \- Practical Extraction and Report Language
+.SH SYNOPSIS
+.B perl
+[options] filename args
+.SH DESCRIPTION
+.I Perl
+is an interpreted language optimized for scanning arbitrary text files,
+extracting information from those text files, and printing reports based
+on that information.
+It's also a good language for many system management tasks.
+The language is intended to be practical (easy to use, efficient, complete)
+rather than beautiful (tiny, elegant, minimal).
+It combines (in the author's opinion, anyway) some of the best features of C,
+\fIsed\fR, \fIawk\fR, and \fIsh\fR,
+so people familiar with those languages should have little difficulty with it.
+(Language historians will also note some vestiges of \fIcsh\fR, Pascal, and
+even BASIC-PLUS.)
+Expression syntax corresponds quite closely to C expression syntax.
+Unlike most Unix utilities,
+.I perl
+does not arbitrarily limit the size of your data\*(--if you've got
+the memory,
+.I perl
+can slurp in your whole file as a single string.
+Recursion is of unlimited depth.
+And the hash tables used by associative arrays grow as necessary to prevent
+degraded performance.
+.I Perl
+uses sophisticated pattern matching techniques to scan large amounts of
+data very quickly.
+Although optimized for scanning text,
+.I perl
+can also deal with binary data, and can make dbm files look like associative
+arrays (where dbm is available).
+Setuid
+.I perl
+scripts are safer than C programs
+through a dataflow tracing mechanism which prevents many stupid security holes.
+If you have a problem that would ordinarily use \fIsed\fR
+or \fIawk\fR or \fIsh\fR, but it
+exceeds their capabilities or must run a little faster,
+and you don't want to write the silly thing in C, then
+.I perl
+may be for you.
+There are also translators to turn your
+.I sed
+and
+.I awk
+scripts into
+.I perl
+scripts.
+OK, enough hype.
+.PP
+Upon startup,
+.I perl
+looks for your script in one of the following places:
+.Ip 1. 4 2
+Specified line by line via
+.B \-e
+switches on the command line.
+.Ip 2. 4 2
+Contained in the file specified by the first filename on the command line.
+(Note that systems supporting the #! notation invoke interpreters this way.)
+.Ip 3. 4 2
+Passed in implicitly via standard input.
+This only works if there are no filename arguments\*(--to pass
+arguments to a
+.I stdin
+script you must explicitly specify a \- for the script name.
+.PP
+After locating your script,
+.I perl
+compiles it to an internal form.
+If the script is syntactically correct, it is executed.
+.Sh "Options"
+Note: on first reading this section may not make much sense to you. It's here
+at the front for easy reference.
+.PP
+A single-character option may be combined with the following option, if any.
+This is particularly useful when invoking a script using the #! construct which
+only allows one argument. Example:
+.nf
+
+.ne 2
+ #!/usr/bin/perl \-spi.bak # same as \-s \-p \-i.bak
+ .\|.\|.
+
+.fi
+Options include:
+.TP 5
+.BI \-0 digits
+specifies the record separator ($/) as an octal number.
+If there are no digits, the null character is the separator.
+Other switches may precede or follow the digits.
+For example, if you have a version of
+.I find
+which can print filenames terminated by the null character, you can say this:
+.nf
+
+ find . \-name '*.bak' \-print0 | perl \-n0e unlink
+
+.fi
+The special value 00 will cause Perl to slurp files in paragraph mode.
+The value 0777 will cause Perl to slurp files whole since there is no
+legal character with that value.
+.TP 5
+.B \-a
+turns on autosplit mode when used with a
+.B \-n
+or
+.BR \-p .
+An implicit split command to the @F array
+is done as the first thing inside the implicit while loop produced by
+the
+.B \-n
+or
+.BR \-p .
+.nf
+
+ perl \-ane \'print pop(@F), "\en";\'
+
+is equivalent to
+
+ while (<>) {
+ @F = split(\' \');
+ print pop(@F), "\en";
+ }
+
+.fi
+.TP 5
+.B \-c
+causes
+.I perl
+to check the syntax of the script and then exit without executing it.
+.TP 5
+.BI \-d
+runs the script under the perl debugger.
+See the section on Debugging.
+.TP 5
+.BI \-D number
+sets debugging flags.
+To watch how it executes your script, use
+.BR \-D14 .
+(This only works if debugging is compiled into your
+.IR perl .)
+Another nice value is \-D1024, which lists your compiled syntax tree.
+And \-D512 displays compiled regular expressions.
+.TP 5
+.BI \-e " commandline"
+may be used to enter one line of script.
+Multiple
+.B \-e
+commands may be given to build up a multi-line script.
+If
+.B \-e
+is given,
+.I perl
+will not look for a script filename in the argument list.
+.TP 5
+.BI \-i extension
+specifies that files processed by the <> construct are to be edited
+in-place.
+It does this by renaming the input file, opening the output file by the
+same name, and selecting that output file as the default for print statements.
+The extension, if supplied, is added to the name of the
+old file to make a backup copy.
+If no extension is supplied, no backup is made.
+Saying \*(L"perl \-p \-i.bak \-e "s/foo/bar/;" .\|.\|. \*(R" is the same as using
+the script:
+.nf
+
+.ne 2
+ #!/usr/bin/perl \-pi.bak
+ s/foo/bar/;
+
+which is equivalent to
+
+.ne 14
+ #!/usr/bin/perl
+ while (<>) {
+ if ($ARGV ne $oldargv) {
+ rename($ARGV, $ARGV . \'.bak\');
+ open(ARGVOUT, ">$ARGV");
+ select(ARGVOUT);
+ $oldargv = $ARGV;
+ }
+ s/foo/bar/;
+ }
+ continue {
+ print; # this prints to original filename
+ }
+ select(STDOUT);
+
+.fi
+except that the
+.B \-i
+form doesn't need to compare $ARGV to $oldargv to know when
+the filename has changed.
+It does, however, use ARGVOUT for the selected filehandle.
+Note that
+.I STDOUT
+is restored as the default output filehandle after the loop.
+.Sp
+You can use eof to locate the end of each input file, in case you want
+to append to each file, or reset line numbering (see example under eof).
+.TP 5
+.BI \-I directory
+may be used in conjunction with
+.B \-P
+to tell the C preprocessor where to look for include files.
+By default /usr/include and /usr/lib/perl are searched.
+.TP 5
+.BI \-l octnum
+enables automatic line-ending processing. It has two effects:
+first, it automatically chops the line terminator when used with
+.B \-n
+or
+.B \-p ,
+and second, it assigns $\e to have the value of
+.I octnum
+so that any print statements will have that line terminator added back on. If
+.I octnum
+is omitted, sets $\e to the current value of $/.
+For instance, to trim lines to 80 columns:
+.nf
+
+ perl -lpe \'substr($_, 80) = ""\'
+
+.fi
+Note that the assignment $\e = $/ is done when the switch is processed,
+so the input record separator can be different than the output record
+separator if the
+.B \-l
+switch is followed by a
+.B \-0
+switch:
+.nf
+
+ gnufind / -print0 | perl -ln0e 'print "found $_" if -p'
+
+.fi
+This sets $\e to newline and then sets $/ to the null character.
+.TP 5
+.B \-n
+causes
+.I perl
+to assume the following loop around your script, which makes it iterate
+over filename arguments somewhat like \*(L"sed \-n\*(R" or \fIawk\fR:
+.nf
+
+.ne 3
+ while (<>) {
+ .\|.\|. # your script goes here
+ }
+
+.fi
+Note that the lines are not printed by default.
+See
+.B \-p
+to have lines printed.
+Here is an efficient way to delete all files older than a week:
+.nf
+
+ find . \-mtime +7 \-print | perl \-nle \'unlink;\'
+
+.fi
+This is faster than using the \-exec switch of find because you don't have to
+start a process on every filename found.
+.TP 5
+.B \-p
+causes
+.I perl
+to assume the following loop around your script, which makes it iterate
+over filename arguments somewhat like \fIsed\fR:
+.nf
+
+.ne 5
+ while (<>) {
+ .\|.\|. # your script goes here
+ } continue {
+ print;
+ }
+
+.fi
+Note that the lines are printed automatically.
+To suppress printing use the
+.B \-n
+switch.
+A
+.B \-p
+overrides a
+.B \-n
+switch.
+.TP 5
+.B \-P
+causes your script to be run through the C preprocessor before
+compilation by
+.IR perl .
+(Since both comments and cpp directives begin with the # character,
+you should avoid starting comments with any words recognized
+by the C preprocessor such as \*(L"if\*(R", \*(L"else\*(R" or \*(L"define\*(R".)
+.TP 5
+.B \-s
+enables some rudimentary switch parsing for switches on the command line
+after the script name but before any filename arguments (or before a \-\|\-).
+Any switch found there is removed from @ARGV and sets the corresponding variable in the
+.I perl
+script.
+The following script prints \*(L"true\*(R" if and only if the script is
+invoked with a \-xyz switch.
+.nf
+
+.ne 2
+ #!/usr/bin/perl \-s
+ if ($xyz) { print "true\en"; }
+
+.fi
+.TP 5
+.B \-S
+makes
+.I perl
+use the PATH environment variable to search for the script
+(unless the name of the script starts with a slash).
+Typically this is used to emulate #! startup on machines that don't
+support #!, in the following manner:
+.nf
+
+ #!/usr/bin/perl
+ eval "exec /usr/bin/perl \-S $0 $*"
+ if $running_under_some_shell;
+
+.fi
+The system ignores the first line and feeds the script to /bin/sh,
+which proceeds to try to execute the
+.I perl
+script as a shell script.
+The shell executes the second line as a normal shell command, and thus
+starts up the
+.I perl
+interpreter.
+On some systems $0 doesn't always contain the full pathname,
+so the
+.B \-S
+tells
+.I perl
+to search for the script if necessary.
+After
+.I perl
+locates the script, it parses the lines and ignores them because
+the variable $running_under_some_shell is never true.
+A better construct than $* would be ${1+"$@"}, which handles embedded spaces
+and such in the filenames, but doesn't work if the script is being interpreted
+by csh.
+In order to start up sh rather than csh, some systems may have to replace the
+#! line with a line containing just
+a colon, which will be politely ignored by perl.
+Other systems can't control that, and need a totally devious construct that
+will work under any of csh, sh or perl, such as the following:
+.nf
+
+.ne 3
+ eval '(exit $?0)' && eval 'exec /usr/bin/perl -S $0 ${1+"$@"}'
+ & eval 'exec /usr/bin/perl -S $0 $argv:q'
+ if 0;
+
+.fi
+.TP 5
+.B \-u
+causes
+.I perl
+to dump core after compiling your script.
+You can then take this core dump and turn it into an executable file
+by using the undump program (not supplied).
+This speeds startup at the expense of some disk space (which you can
+minimize by stripping the executable).
+(Still, a "hello world" executable comes out to about 200K on my machine.)
+If you are going to run your executable as a set-id program then you
+should probably compile it using taintperl rather than normal perl.
+If you want to execute a portion of your script before dumping, use the
+dump operator instead.
+Note: availability of undump is platform specific and may not be available
+for a specific port of perl.
+.TP 5
+.B \-U
+allows
+.I perl
+to do unsafe operations.
+Currently the only \*(L"unsafe\*(R" operations are the unlinking of directories while
+running as superuser, and running setuid programs with fatal taint checks
+turned into warnings.
+.TP 5
+.B \-v
+prints the version and patchlevel of your
+.I perl
+executable.
+.TP 5
+.B \-w
+prints warnings about identifiers that are mentioned only once, and scalar
+variables that are used before being set.
+Also warns about redefined subroutines, and references to undefined
+filehandles or filehandles opened readonly that you are attempting to
+write on.
+Also warns you if you use == on values that don't look like numbers, and if
+your subroutines recurse more than 100 deep.
+.TP 5
+.BI \-x directory
+tells
+.I perl
+that the script is embedded in a message.
+Leading garbage will be discarded until the first line that starts
+with #! and contains the string "perl".
+Any meaningful switches on that line will be applied (but only one
+group of switches, as with normal #! processing).
+If a directory name is specified, Perl will switch to that directory
+before running the script.
+The
+.B \-x
+switch only controls the the disposal of leading garbage.
+The script must be terminated with _\|_END_\|_ if there is trailing garbage
+to be ignored (the script can process any or all of the trailing garbage
+via the DATA filehandle if desired).
+.Sh "Data Types and Objects"
+.PP
+.I Perl
+has three data types: scalars, arrays of scalars, and
+associative arrays of scalars.
+Normal arrays are indexed by number, and associative arrays by string.
+.PP
+The interpretation of operations and values in perl sometimes
+depends on the requirements
+of the context around the operation or value.
+There are three major contexts: string, numeric and array.
+Certain operations return array values
+in contexts wanting an array, and scalar values otherwise.
+(If this is true of an operation it will be mentioned in the documentation
+for that operation.)
+Operations which return scalars don't care whether the context is looking
+for a string or a number, but
+scalar variables and values are interpreted as strings or numbers
+as appropriate to the context.
+A scalar is interpreted as TRUE in the boolean sense if it is not the null
+string or 0.
+Booleans returned by operators are 1 for true and 0 or \'\' (the null
+string) for false.
+.PP
+There are actually two varieties of null string: defined and undefined.
+Undefined null strings are returned when there is no real value for something,
+such as when there was an error, or at end of file, or when you refer
+to an uninitialized variable or element of an array.
+An undefined null string may become defined the first time you access it, but
+prior to that you can use the defined() operator to determine whether the
+value is defined or not.
+.PP
+References to scalar variables always begin with \*(L'$\*(R', even when referring
+to a scalar that is part of an array.
+Thus:
+.nf
+
+.ne 3
+ $days \h'|2i'# a simple scalar variable
+ $days[28] \h'|2i'# 29th element of array @days
+ $days{\'Feb\'}\h'|2i'# one value from an associative array
+ $#days \h'|2i'# last index of array @days
+
+but entire arrays or array slices are denoted by \*(L'@\*(R':
+
+ @days \h'|2i'# ($days[0], $days[1],\|.\|.\|. $days[n])
+ @days[3,4,5]\h'|2i'# same as @days[3.\|.5]
+ @days{'a','c'}\h'|2i'# same as ($days{'a'},$days{'c'})
+
+and entire associative arrays are denoted by \*(L'%\*(R':
+
+ %days \h'|2i'# (key1, val1, key2, val2 .\|.\|.)
+.fi
+.PP
+Any of these eight constructs may serve as an lvalue,
+that is, may be assigned to.
+(It also turns out that an assignment is itself an lvalue in
+certain contexts\*(--see examples under s, tr and chop.)
+Assignment to a scalar evaluates the righthand side in a scalar context,
+while assignment to an array or array slice evaluates the righthand side
+in an array context.
+.PP
+You may find the length of array @days by evaluating
+\*(L"$#days\*(R", as in
+.IR csh .
+(Actually, it's not the length of the array, it's the subscript of the last element, since there is (ordinarily) a 0th element.)
+Assigning to $#days changes the length of the array.
+Shortening an array by this method does not actually destroy any values.
+Lengthening an array that was previously shortened recovers the values that
+were in those elements.
+You can also gain some measure of efficiency by preextending an array that
+is going to get big.
+(You can also extend an array by assigning to an element that is off the
+end of the array.
+This differs from assigning to $#whatever in that intervening values
+are set to null rather than recovered.)
+You can truncate an array down to nothing by assigning the null list () to
+it.
+The following are exactly equivalent
+.nf
+
+ @whatever = ();
+ $#whatever = $[ \- 1;
+
+.fi
+.PP
+If you evaluate an array in a scalar context, it returns the length of
+the array.
+The following is always true:
+.nf
+
+ scalar(@whatever) == $#whatever \- $[ + 1;
+
+.fi
+If you evaluate an associative array in a scalar context, it returns
+a value which is true if and only if the array contains any elements.
+(If there are any elements, the value returned is a string consisting
+of the number of used buckets and the number of allocated buckets, separated
+by a slash.)
+.PP
+Multi-dimensional arrays are not directly supported, but see the discussion
+of the $; variable later for a means of emulating multiple subscripts with
+an associative array.
+You could also write a subroutine to turn multiple subscripts into a single
+subscript.
+.PP
+Every data type has its own namespace.
+You can, without fear of conflict, use the same name for a scalar variable,
+an array, an associative array, a filehandle, a subroutine name, and/or
+a label.
+Since variable and array references always start with \*(L'$\*(R', \*(L'@\*(R',
+or \*(L'%\*(R', the \*(L"reserved\*(R" words aren't in fact reserved
+with respect to variable names.
+(They ARE reserved with respect to labels and filehandles, however, which
+don't have an initial special character.
+Hint: you could say open(LOG,\'logfile\') rather than open(log,\'logfile\').
+Using uppercase filehandles also improves readability and protects you
+from conflict with future reserved words.)
+Case IS significant\*(--\*(L"FOO\*(R", \*(L"Foo\*(R" and \*(L"foo\*(R" are all
+different names.
+Names which start with a letter may also contain digits and underscores.
+Names which do not start with a letter are limited to one character,
+e.g. \*(L"$%\*(R" or \*(L"$$\*(R".
+(Most of the one character names have a predefined significance to
+.IR perl .
+More later.)
+.PP
+Numeric literals are specified in any of the usual floating point or
+integer formats:
+.nf
+
+.ne 6
+ 12345
+ 12345.67
+ .23E-10
+ 0xffff # hex
+ 0377 # octal
+ 4_294_967_296
+
+.fi
+String literals are delimited by either single or double quotes.
+They work much like shell quotes:
+double-quoted string literals are subject to backslash and variable
+substitution; single-quoted strings are not (except for \e\' and \e\e).
+The usual backslash rules apply for making characters such as newline, tab,
+etc., as well as some more exotic forms:
+.nf
+
+ \et tab
+ \en newline
+ \er return
+ \ef form feed
+ \eb backspace
+ \ea alarm (bell)
+ \ee escape
+ \e033 octal char
+ \ex1b hex char
+ \ec[ control char
+ \el lowercase next char
+ \eu uppercase next char
+ \eL lowercase till \eE
+ \eU uppercase till \eE
+ \eE end case modification
+
+.fi
+You can also embed newlines directly in your strings, i.e. they can end on
+a different line than they begin.
+This is nice, but if you forget your trailing quote, the error will not be
+reported until
+.I perl
+finds another line containing the quote character, which
+may be much further on in the script.
+Variable substitution inside strings is limited to scalar variables, normal
+array values, and array slices.
+(In other words, identifiers beginning with $ or @, followed by an optional
+bracketed expression as a subscript.)
+The following code segment prints out \*(L"The price is $100.\*(R"
+.nf
+
+.ne 2
+ $Price = \'$100\';\h'|3.5i'# not interpreted
+ print "The price is $Price.\e\|n";\h'|3.5i'# interpreted
+
+.fi
+Note that you can put curly brackets around the identifier to delimit it
+from following alphanumerics.
+Also note that a single quoted string must be separated from a preceding
+word by a space, since single quote is a valid character in an identifier
+(see Packages).
+.PP
+Two special literals are _\|_LINE_\|_ and _\|_FILE_\|_, which represent the current
+line number and filename at that point in your program.
+They may only be used as separate tokens; they will not be interpolated
+into strings.
+In addition, the token _\|_END_\|_ may be used to indicate the logical end of the
+script before the actual end of file.
+Any following text is ignored, but may be read via the DATA filehandle.
+(The DATA filehandle may read data only from the main script, but not from
+any required file or evaluated string.)
+The two control characters ^D and ^Z are synonyms for _\|_END_\|_.
+.PP
+A word that doesn't have any other interpretation in the grammar will be
+treated as if it had single quotes around it.
+For this purpose, a word consists only of alphanumeric characters and underline,
+and must start with an alphabetic character.
+As with filehandles and labels, a bare word that consists entirely of
+lowercase letters risks conflict with future reserved words, and if you
+use the
+.B \-w
+switch, Perl will warn you about any such words.
+.PP
+Array values are interpolated into double-quoted strings by joining all the
+elements of the array with the delimiter specified in the $" variable,
+space by default.
+(Since in versions of perl prior to 3.0 the @ character was not a metacharacter
+in double-quoted strings, the interpolation of @array, $array[EXPR],
+@array[LIST], $array{EXPR}, or @array{LIST} only happens if array is
+referenced elsewhere in the program or is predefined.)
+The following are equivalent:
+.nf
+
+.ne 4
+ $temp = join($",@ARGV);
+ system "echo $temp";
+
+ system "echo @ARGV";
+
+.fi
+Within search patterns (which also undergo double-quotish substitution)
+there is a bad ambiguity: Is /$foo[bar]/ to be
+interpreted as /${foo}[bar]/ (where [bar] is a character class for the
+regular expression) or as /${foo[bar]}/ (where [bar] is the subscript to
+array @foo)?
+If @foo doesn't otherwise exist, then it's obviously a character class.
+If @foo exists, perl takes a good guess about [bar], and is almost always right.
+If it does guess wrong, or if you're just plain paranoid,
+you can force the correct interpretation with curly brackets as above.
+.PP
+A line-oriented form of quoting is based on the shell here-is syntax.
+Following a << you specify a string to terminate the quoted material, and all lines
+following the current line down to the terminating string are the value
+of the item.
+The terminating string may be either an identifier (a word), or some
+quoted text.
+If quoted, the type of quotes you use determines the treatment of the text,
+just as in regular quoting.
+An unquoted identifier works like double quotes.
+There must be no space between the << and the identifier.
+(If you put a space it will be treated as a null identifier, which is
+valid, and matches the first blank line\*(--see Merry Christmas example below.)
+The terminating string must appear by itself (unquoted and with no surrounding
+whitespace) on the terminating line.
+.nf
+
+ print <<EOF; # same as above
+The price is $Price.
+EOF
+
+ print <<"EOF"; # same as above
+The price is $Price.
+EOF
+
+ print << x 10; # null identifier is delimiter
+Merry Christmas!
+
+ print <<`EOC`; # execute commands
+echo hi there
+echo lo there
+EOC
+
+ print <<foo, <<bar; # you can stack them
+I said foo.
+foo
+I said bar.
+bar
+
+.fi
+Array literals are denoted by separating individual values by commas, and
+enclosing the list in parentheses:
+.nf
+
+ (LIST)
+
+.fi
+In a context not requiring an array value, the value of the array literal
+is the value of the final element, as in the C comma operator.
+For example,
+.nf
+
+.ne 4
+ @foo = (\'cc\', \'\-E\', $bar);
+
+assigns the entire array value to array foo, but
+
+ $foo = (\'cc\', \'\-E\', $bar);
+
+.fi
+assigns the value of variable bar to variable foo.
+Note that the value of an actual array in a scalar context is the length
+of the array; the following assigns to $foo the value 3:
+.nf
+
+.ne 2
+ @foo = (\'cc\', \'\-E\', $bar);
+ $foo = @foo; # $foo gets 3
+
+.fi
+You may have an optional comma before the closing parenthesis of an
+array literal, so that you can say:
+.nf
+
+ @foo = (
+ 1,
+ 2,
+ 3,
+ );
+
+.fi
+When a LIST is evaluated, each element of the list is evaluated in
+an array context, and the resulting array value is interpolated into LIST
+just as if each individual element were a member of LIST. Thus arrays
+lose their identity in a LIST\*(--the list
+
+ (@foo,@bar,&SomeSub)
+
+contains all the elements of @foo followed by all the elements of @bar,
+followed by all the elements returned by the subroutine named SomeSub.
+.PP
+A list value may also be subscripted like a normal array.
+Examples:
+.nf
+
+ $time = (stat($file))[8]; # stat returns array value
+ $digit = ('a','b','c','d','e','f')[$digit-10];
+ return (pop(@foo),pop(@foo))[0];
+
+.fi
+.PP
+Array lists may be assigned to if and only if each element of the list
+is an lvalue:
+.nf
+
+ ($a, $b, $c) = (1, 2, 3);
+
+ ($map{\'red\'}, $map{\'blue\'}, $map{\'green\'}) = (0x00f, 0x0f0, 0xf00);
+
+The final element may be an array or an associative array:
+
+ ($a, $b, @rest) = split;
+ local($a, $b, %rest) = @_;
+
+.fi
+You can actually put an array anywhere in the list, but the first array
+in the list will soak up all the values, and anything after it will get
+a null value.
+This may be useful in a local().
+.PP
+An associative array literal contains pairs of values to be interpreted
+as a key and a value:
+.nf
+
+.ne 2
+ # same as map assignment above
+ %map = ('red',0x00f,'blue',0x0f0,'green',0xf00);
+
+.fi
+Array assignment in a scalar context returns the number of elements
+produced by the expression on the right side of the assignment:
+.nf
+
+ $x = (($foo,$bar) = (3,2,1)); # set $x to 3, not 2
+
+.fi
+.PP
+There are several other pseudo-literals that you should know about.
+If a string is enclosed by backticks (grave accents), it first undergoes
+variable substitution just like a double quoted string.
+It is then interpreted as a command, and the output of that command
+is the value of the pseudo-literal, like in a shell.
+In a scalar context, a single string consisting of all the output is
+returned.
+In an array context, an array of values is returned, one for each line
+of output.
+(You can set $/ to use a different line terminator.)
+The command is executed each time the pseudo-literal is evaluated.
+The status value of the command is returned in $? (see Predefined Names
+for the interpretation of $?).
+Unlike in \f2csh\f1, no translation is done on the return
+data\*(--newlines remain newlines.
+Unlike in any of the shells, single quotes do not hide variable names
+in the command from interpretation.
+To pass a $ through to the shell you need to hide it with a backslash.
+.PP
+Evaluating a filehandle in angle brackets yields the next line
+from that file (newline included, so it's never false until EOF, at
+which time an undefined value is returned).
+Ordinarily you must assign that value to a variable,
+but there is one situation where an automatic assignment happens.
+If (and only if) the input symbol is the only thing inside the conditional of a
+.I while
+loop, the value is
+automatically assigned to the variable \*(L"$_\*(R".
+(This may seem like an odd thing to you, but you'll use the construct
+in almost every
+.I perl
+script you write.)
+Anyway, the following lines are equivalent to each other:
+.nf
+
+.ne 5
+ while ($_ = <STDIN>) { print; }
+ while (<STDIN>) { print; }
+ for (\|;\|<STDIN>;\|) { print; }
+ print while $_ = <STDIN>;
+ print while <STDIN>;
+
+.fi
+The filehandles
+.IR STDIN ,
+.I STDOUT
+and
+.I STDERR
+are predefined.
+(The filehandles
+.IR stdin ,
+.I stdout
+and
+.I stderr
+will also work except in packages, where they would be interpreted as
+local identifiers rather than global.)
+Additional filehandles may be created with the
+.I open
+function.
+.PP
+If a <FILEHANDLE> is used in a context that is looking for an array, an array
+consisting of all the input lines is returned, one line per array element.
+It's easy to make a LARGE data space this way, so use with care.
+.PP
+The null filehandle <> is special and can be used to emulate the behavior of
+\fIsed\fR and \fIawk\fR.
+Input from <> comes either from standard input, or from each file listed on
+the command line.
+Here's how it works: the first time <> is evaluated, the ARGV array is checked,
+and if it is null, $ARGV[0] is set to \'-\', which when opened gives you standard
+input.
+The ARGV array is then processed as a list of filenames.
+The loop
+.nf
+
+.ne 3
+ while (<>) {
+ .\|.\|. # code for each line
+ }
+
+.ne 10
+is equivalent to the following Perl-like pseudo code:
+
+ unshift(@ARGV, \'\-\') \|if \|$#ARGV < $[;
+ while ($ARGV = shift) {
+ open(ARGV, $ARGV);
+ while (<ARGV>) {
+ .\|.\|. # code for each line
+ }
+ }
+
+.fi
+except that it isn't as cumbersome to say, and will actually work.
+It really does shift array ARGV and put the current filename into
+variable ARGV.
+It also uses filehandle ARGV internally\*(--<> is just a synonym for
+<ARGV>, which is magical.
+(The pseudo code above doesn't work because it treats <ARGV> as non-magical.)
+.PP
+You can modify @ARGV before the first <> as long as the array ends up
+containing the list of filenames you really want.
+Line numbers ($.) continue as if the input was one big happy file.
+(But see example under eof for how to reset line numbers on each file.)
+.PP
+.ne 5
+If you want to set @ARGV to your own list of files, go right ahead.
+If you want to pass switches into your script, you can
+put a loop on the front like this:
+.nf
+
+.ne 10
+ while ($_ = $ARGV[0], /\|^\-/\|) {
+ shift;
+ last if /\|^\-\|\-$\|/\|;
+ /\|^\-D\|(.*\|)/ \|&& \|($debug = $1);
+ /\|^\-v\|/ \|&& \|$verbose++;
+ .\|.\|. # other switches
+ }
+ while (<>) {
+ .\|.\|. # code for each line
+ }
+
+.fi
+The <> symbol will return FALSE only once.
+If you call it again after this it will assume you are processing another
+@ARGV list, and if you haven't set @ARGV, will input from
+.IR STDIN .
+.PP
+If the string inside the angle brackets is a reference to a scalar variable
+(e.g. <$foo>),
+then that variable contains the name of the filehandle to input from.
+.PP
+If the string inside angle brackets is not a filehandle, it is interpreted
+as a filename pattern to be globbed, and either an array of filenames or the
+next filename in the list is returned, depending on context.
+One level of $ interpretation is done first, but you can't say <$foo>
+because that's an indirect filehandle as explained in the previous
+paragraph.
+You could insert curly brackets to force interpretation as a
+filename glob: <${foo}>.
+Example:
+.nf
+
+.ne 3
+ while (<*.c>) {
+ chmod 0644, $_;
+ }
+
+is equivalent to
+
+.ne 5
+ open(foo, "echo *.c | tr \-s \' \et\er\ef\' \'\e\e012\e\e012\e\e012\e\e012\'|");
+ while (<foo>) {
+ chop;
+ chmod 0644, $_;
+ }
+
+.fi
+In fact, it's currently implemented that way.
+(Which means it will not work on filenames with spaces in them unless
+you have /bin/csh on your machine.)
+Of course, the shortest way to do the above is:
+.nf
+
+ chmod 0644, <*.c>;
+
+.fi
+.Sh "Syntax"
+.PP
+A
+.I perl
+script consists of a sequence of declarations and commands.
+The only things that need to be declared in
+.I perl
+are report formats and subroutines.
+See the sections below for more information on those declarations.
+All uninitialized user-created objects are assumed to
+start with a null or 0 value until they
+are defined by some explicit operation such as assignment.
+The sequence of commands is executed just once, unlike in
+.I sed
+and
+.I awk
+scripts, where the sequence of commands is executed for each input line.
+While this means that you must explicitly loop over the lines of your input file
+(or files), it also means you have much more control over which files and which
+lines you look at.
+(Actually, I'm lying\*(--it is possible to do an implicit loop with either the
+.B \-n
+or
+.B \-p
+switch.)
+.PP
+A declaration can be put anywhere a command can, but has no effect on the
+execution of the primary sequence of commands\*(--declarations all take effect
+at compile time.
+Typically all the declarations are put at the beginning or the end of the script.
+.PP
+.I Perl
+is, for the most part, a free-form language.
+(The only exception to this is format declarations, for fairly obvious reasons.)
+Comments are indicated by the # character, and extend to the end of the line.
+If you attempt to use /* */ C comments, it will be interpreted either as
+division or pattern matching, depending on the context.
+So don't do that.
+.Sh "Compound statements"
+In
+.IR perl ,
+a sequence of commands may be treated as one command by enclosing it
+in curly brackets.
+We will call this a BLOCK.
+.PP
+The following compound commands may be used to control flow:
+.nf
+
+.ne 4
+ if (EXPR) BLOCK
+ if (EXPR) BLOCK else BLOCK
+ if (EXPR) BLOCK elsif (EXPR) BLOCK .\|.\|. else BLOCK
+ LABEL while (EXPR) BLOCK
+ LABEL while (EXPR) BLOCK continue BLOCK
+ LABEL for (EXPR; EXPR; EXPR) BLOCK
+ LABEL foreach VAR (ARRAY) BLOCK
+ LABEL BLOCK continue BLOCK
+
+.fi
+Note that, unlike C and Pascal, these are defined in terms of BLOCKs, not
+statements.
+This means that the curly brackets are \fIrequired\fR\*(--no dangling statements allowed.
+If you want to write conditionals without curly brackets there are several
+other ways to do it.
+The following all do the same thing:
+.nf
+
+.ne 5
+ if (!open(foo)) { die "Can't open $foo: $!"; }
+ die "Can't open $foo: $!" unless open(foo);
+ open(foo) || die "Can't open $foo: $!"; # foo or bust!
+ open(foo) ? \'hi mom\' : die "Can't open $foo: $!";
+ # a bit exotic, that last one
+
+.fi
+.PP
+The
+.I if
+statement is straightforward.
+Since BLOCKs are always bounded by curly brackets, there is never any
+ambiguity about which
+.I if
+an
+.I else
+goes with.
+If you use
+.I unless
+in place of
+.IR if ,
+the sense of the test is reversed.
+.PP
+The
+.I while
+statement executes the block as long as the expression is true
+(does not evaluate to the null string or 0).
+The LABEL is optional, and if present, consists of an identifier followed by
+a colon.
+The LABEL identifies the loop for the loop control statements
+.IR next ,
+.IR last ,
+and
+.I redo
+(see below).
+If there is a
+.I continue
+BLOCK, it is always executed just before
+the conditional is about to be evaluated again, similarly to the third part
+of a
+.I for
+loop in C.
+Thus it can be used to increment a loop variable, even when the loop has
+been continued via the
+.I next
+statement (similar to the C \*(L"continue\*(R" statement).
+.PP
+If the word
+.I while
+is replaced by the word
+.IR until ,
+the sense of the test is reversed, but the conditional is still tested before
+the first iteration.
+.PP
+In either the
+.I if
+or the
+.I while
+statement, you may replace \*(L"(EXPR)\*(R" with a BLOCK, and the conditional
+is true if the value of the last command in that block is true.
+.PP
+The
+.I for
+loop works exactly like the corresponding
+.I while
+loop:
+.nf
+
+.ne 12
+ for ($i = 1; $i < 10; $i++) {
+ .\|.\|.
+ }
+
+is the same as
+
+ $i = 1;
+ while ($i < 10) {
+ .\|.\|.
+ } continue {
+ $i++;
+ }
+.fi
+.PP
+The foreach loop iterates over a normal array value and sets the variable
+VAR to be each element of the array in turn.
+The variable is implicitly local to the loop, and regains its former value
+upon exiting the loop.
+The \*(L"foreach\*(R" keyword is actually identical to the \*(L"for\*(R" keyword,
+so you can use \*(L"foreach\*(R" for readability or \*(L"for\*(R" for brevity.
+If VAR is omitted, $_ is set to each value.
+If ARRAY is an actual array (as opposed to an expression returning an array
+value), you can modify each element of the array
+by modifying VAR inside the loop.
+Examples:
+.nf
+
+.ne 5
+ for (@ary) { s/foo/bar/; }
+
+ foreach $elem (@elements) {
+ $elem *= 2;
+ }
+
+.ne 3
+ for ((10,9,8,7,6,5,4,3,2,1,\'BOOM\')) {
+ print $_, "\en"; sleep(1);
+ }
+
+ for (1..15) { print "Merry Christmas\en"; }
+
+.ne 3
+ foreach $item (split(/:[\e\e\en:]*/, $ENV{\'TERMCAP\'})) {
+ print "Item: $item\en";
+ }
+
+.fi
+.PP
+The BLOCK by itself (labeled or not) is equivalent to a loop that executes
+once.
+Thus you can use any of the loop control statements in it to leave or
+restart the block.
+The
+.I continue
+block is optional.
+This construct is particularly nice for doing case structures.
+.nf
+
+.ne 6
+ foo: {
+ if (/^abc/) { $abc = 1; last foo; }
+ if (/^def/) { $def = 1; last foo; }
+ if (/^xyz/) { $xyz = 1; last foo; }
+ $nothing = 1;
+ }
+
+.fi
+There is no official switch statement in perl, because there
+are already several ways to write the equivalent.
+In addition to the above, you could write
+.nf
+
+.ne 6
+ foo: {
+ $abc = 1, last foo if /^abc/;
+ $def = 1, last foo if /^def/;
+ $xyz = 1, last foo if /^xyz/;
+ $nothing = 1;
+ }
+
+or
+
+.ne 6
+ foo: {
+ /^abc/ && do { $abc = 1; last foo; };
+ /^def/ && do { $def = 1; last foo; };
+ /^xyz/ && do { $xyz = 1; last foo; };
+ $nothing = 1;
+ }
+
+or
+
+.ne 6
+ foo: {
+ /^abc/ && ($abc = 1, last foo);
+ /^def/ && ($def = 1, last foo);
+ /^xyz/ && ($xyz = 1, last foo);
+ $nothing = 1;
+ }
+
+or even
+
+.ne 8
+ if (/^abc/)
+ { $abc = 1; }
+ elsif (/^def/)
+ { $def = 1; }
+ elsif (/^xyz/)
+ { $xyz = 1; }
+ else
+ {$nothing = 1;}
+
+.fi
+As it happens, these are all optimized internally to a switch structure,
+so perl jumps directly to the desired statement, and you needn't worry
+about perl executing a lot of unnecessary statements when you have a string
+of 50 elsifs, as long as you are testing the same simple scalar variable
+using ==, eq, or pattern matching as above.
+(If you're curious as to whether the optimizer has done this for a particular
+case statement, you can use the \-D1024 switch to list the syntax tree
+before execution.)
+.Sh "Simple statements"
+The only kind of simple statement is an expression evaluated for its side
+effects.
+Every simple statement must be terminated with a semicolon, unless it is the
+final statement in a block, in which case the semicolon is optional.
+(Semicolon is still encouraged there if the block takes up more than one line).
+.PP
+Any simple statement may optionally be followed by a
+single modifier, just before the terminating semicolon.
+The possible modifiers are:
+.nf
+
+.ne 4
+ if EXPR
+ unless EXPR
+ while EXPR
+ until EXPR
+
+.fi
+The
+.I if
+and
+.I unless
+modifiers have the expected semantics.
+The
+.I while
+and
+.I until
+modifiers also have the expected semantics (conditional evaluated first),
+except when applied to a do-BLOCK or a do-SUBROUTINE command,
+in which case the block executes once before the conditional is evaluated.
+This is so that you can write loops like:
+.nf
+
+.ne 4
+ do {
+ $_ = <STDIN>;
+ .\|.\|.
+ } until $_ \|eq \|".\|\e\|n";
+
+.fi
+(See the
+.I do
+operator below. Note also that the loop control commands described later will
+NOT work in this construct, since modifiers don't take loop labels.
+Sorry.)
+.Sh "Expressions"
+Since
+.I perl
+expressions work almost exactly like C expressions, only the differences
+will be mentioned here.
+.PP
+Here's what
+.I perl
+has that C doesn't:
+.Ip ** 8 2
+The exponentiation operator.
+.Ip **= 8
+The exponentiation assignment operator.
+.Ip (\|) 8 3
+The null list, used to initialize an array to null.
+.Ip . 8
+Concatenation of two strings.
+.Ip .= 8
+The concatenation assignment operator.
+.Ip eq 8
+String equality (== is numeric equality).
+For a mnemonic just think of \*(L"eq\*(R" as a string.
+(If you are used to the
+.I awk
+behavior of using == for either string or numeric equality
+based on the current form of the comparands, beware!
+You must be explicit here.)
+.Ip ne 8
+String inequality (!= is numeric inequality).
+.Ip lt 8
+String less than.
+.Ip gt 8
+String greater than.
+.Ip le 8
+String less than or equal.
+.Ip ge 8
+String greater than or equal.
+.Ip cmp 8
+String comparison, returning -1, 0, or 1.
+.Ip <=> 8
+Numeric comparison, returning -1, 0, or 1.
+.Ip =~ 8 2
+Certain operations search or modify the string \*(L"$_\*(R" by default.
+This operator makes that kind of operation work on some other string.
+The right argument is a search pattern, substitution, or translation.
+The left argument is what is supposed to be searched, substituted, or
+translated instead of the default \*(L"$_\*(R".
+The return value indicates the success of the operation.
+(If the right argument is an expression other than a search pattern,
+substitution, or translation, it is interpreted as a search pattern
+at run time.
+This is less efficient than an explicit search, since the pattern must
+be compiled every time the expression is evaluated.)
+The precedence of this operator is lower than unary minus and autoincrement/decrement, but higher than everything else.
+.Ip !~ 8
+Just like =~ except the return value is negated.
+.Ip x 8
+The repetition operator.
+Returns a string consisting of the left operand repeated the
+number of times specified by the right operand.
+In an array context, if the left operand is a list in parens, it repeats
+the list.
+.nf
+
+ print \'\-\' x 80; # print row of dashes
+ print \'\-\' x80; # illegal, x80 is identifier
+
+ print "\et" x ($tab/8), \' \' x ($tab%8); # tab over
+
+ @ones = (1) x 80; # an array of 80 1's
+ @ones = (5) x @ones; # set all elements to 5
+
+.fi
+.Ip x= 8
+The repetition assignment operator.
+Only works on scalars.
+.Ip .\|. 8
+The range operator, which is really two different operators depending
+on the context.
+In an array context, returns an array of values counting (by ones)
+from the left value to the right value.
+This is useful for writing \*(L"for (1..10)\*(R" loops and for doing
+slice operations on arrays.
+.Sp
+In a scalar context, .\|. returns a boolean value.
+The operator is bistable, like a flip-flop, and
+emulates the line-range (comma) operator of sed, awk, and various editors.
+Each .\|. operator maintains its own boolean state.
+It is false as long as its left operand is false.
+Once the left operand is true, the range operator stays true
+until the right operand is true,
+AFTER which the range operator becomes false again.
+(It doesn't become false till the next time the range operator is evaluated.
+It can test the right operand and become false on the
+same evaluation it became true (as in awk), but it still returns true once.
+If you don't want it to test the right operand till the next
+evaluation (as in sed), use three dots (.\|.\|.) instead of two.)
+The right operand is not evaluated while the operator is in the \*(L"false\*(R" state,
+and the left operand is not evaluated while the operator is in the \*(L"true\*(R" state.
+The precedence is a little lower than || and &&.
+The value returned is either the null string for false, or a sequence number
+(beginning with 1) for true.
+The sequence number is reset for each range encountered.
+The final sequence number in a range has the string \'E0\' appended to it, which
+doesn't affect its numeric value, but gives you something to search for if you
+want to exclude the endpoint.
+You can exclude the beginning point by waiting for the sequence number to be
+greater than 1.
+If either operand of scalar .\|. is static, that operand is implicitly compared
+to the $. variable, the current line number.
+Examples:
+.nf
+
+.ne 6
+As a scalar operator:
+ if (101 .\|. 200) { print; } # print 2nd hundred lines
+
+ next line if (1 .\|. /^$/); # skip header lines
+
+ s/^/> / if (/^$/ .\|. eof()); # quote body
+
+.ne 4
+As an array operator:
+ for (101 .\|. 200) { print; } # print $_ 100 times
+
+ @foo = @foo[$[ .\|. $#foo]; # an expensive no-op
+ @foo = @foo[$#foo-4 .\|. $#foo]; # slice last 5 items
+
+.fi
+.Ip \-x 8
+A file test.
+This unary operator takes one argument, either a filename or a filehandle,
+and tests the associated file to see if something is true about it.
+If the argument is omitted, tests $_, except for \-t, which tests
+.IR STDIN .
+It returns 1 for true and \'\' for false, or the undefined value if the
+file doesn't exist.
+Precedence is higher than logical and relational operators, but lower than
+arithmetic operators.
+The operator may be any of:
+.nf
+ \-r File is readable by effective uid/gid.
+ \-w File is writable by effective uid/gid.
+ \-x File is executable by effective uid/gid.
+ \-o File is owned by effective uid.
+ \-R File is readable by real uid/gid.
+ \-W File is writable by real uid/gid.
+ \-X File is executable by real uid/gid.
+ \-O File is owned by real uid.
+ \-e File exists.
+ \-z File has zero size.
+ \-s File has non-zero size (returns size).
+ \-f File is a plain file.
+ \-d File is a directory.
+ \-l File is a symbolic link.
+ \-p File is a named pipe (FIFO).
+ \-S File is a socket.
+ \-b File is a block special file.
+ \-c File is a character special file.
+ \-u File has setuid bit set.
+ \-g File has setgid bit set.
+ \-k File has sticky bit set.
+ \-t Filehandle is opened to a tty.
+ \-T File is a text file.
+ \-B File is a binary file (opposite of \-T).
+ \-M Age of file in days when script started.
+ \-A Same for access time.
+ \-C Same for inode change time.
+
+.fi
+The interpretation of the file permission operators \-r, \-R, \-w, \-W, \-x and \-X
+is based solely on the mode of the file and the uids and gids of the user.
+There may be other reasons you can't actually read, write or execute the file.
+Also note that, for the superuser, \-r, \-R, \-w and \-W always return 1, and
+\-x and \-X return 1 if any execute bit is set in the mode.
+Scripts run by the superuser may thus need to do a stat() in order to determine
+the actual mode of the file, or temporarily set the uid to something else.
+.Sp
+Example:
+.nf
+.ne 7
+
+ while (<>) {
+ chop;
+ next unless \-f $_; # ignore specials
+ .\|.\|.
+ }
+
+.fi
+Note that \-s/a/b/ does not do a negated substitution.
+Saying \-exp($foo) still works as expected, however\*(--only single letters
+following a minus are interpreted as file tests.
+.Sp
+The \-T and \-B switches work as follows.
+The first block or so of the file is examined for odd characters such as
+strange control codes or metacharacters.
+If too many odd characters (>10%) are found, it's a \-B file, otherwise it's a \-T file.
+Also, any file containing null in the first block is considered a binary file.
+If \-T or \-B is used on a filehandle, the current stdio buffer is examined
+rather than the first block.
+Both \-T and \-B return TRUE on a null file, or a file at EOF when testing
+a filehandle.
+.PP
+If any of the file tests (or either stat operator) are given the special
+filehandle consisting of a solitary underline, then the stat structure
+of the previous file test (or stat operator) is used, saving a system
+call.
+(This doesn't work with \-t, and you need to remember that lstat and -l
+will leave values in the stat structure for the symbolic link, not the
+real file.)
+Example:
+.nf
+
+ print "Can do.\en" if -r $a || -w _ || -x _;
+
+.ne 9
+ stat($filename);
+ print "Readable\en" if -r _;
+ print "Writable\en" if -w _;
+ print "Executable\en" if -x _;
+ print "Setuid\en" if -u _;
+ print "Setgid\en" if -g _;
+ print "Sticky\en" if -k _;
+ print "Text\en" if -T _;
+ print "Binary\en" if -B _;
+
+.fi
+.PP
+Here is what C has that
+.I perl
+doesn't:
+.Ip "unary &" 12
+Address-of operator.
+.Ip "unary *" 12
+Dereference-address operator.
+.Ip "(TYPE)" 12
+Type casting operator.
+.PP
+Like C,
+.I perl
+does a certain amount of expression evaluation at compile time, whenever
+it determines that all of the arguments to an operator are static and have
+no side effects.
+In particular, string concatenation happens at compile time between literals that don't do variable substitution.
+Backslash interpretation also happens at compile time.
+You can say
+.nf
+
+.ne 2
+ \'Now is the time for all\' . "\|\e\|n" .
+ \'good men to come to.\'
+
+.fi
+and this all reduces to one string internally.
+.PP
+The autoincrement operator has a little extra built-in magic to it.
+If you increment a variable that is numeric, or that has ever been used in
+a numeric context, you get a normal increment.
+If, however, the variable has only been used in string contexts since it
+was set, and has a value that is not null and matches the
+pattern /^[a\-zA\-Z]*[0\-9]*$/, the increment is done
+as a string, preserving each character within its range, with carry:
+.nf
+
+ print ++($foo = \'99\'); # prints \*(L'100\*(R'
+ print ++($foo = \'a0\'); # prints \*(L'a1\*(R'
+ print ++($foo = \'Az\'); # prints \*(L'Ba\*(R'
+ print ++($foo = \'zz\'); # prints \*(L'aaa\*(R'
+
+.fi
+The autodecrement is not magical.
+.PP
+The range operator (in an array context) makes use of the magical
+autoincrement algorithm if the minimum and maximum are strings.
+You can say
+
+ @alphabet = (\'A\' .. \'Z\');
+
+to get all the letters of the alphabet, or
+
+ $hexdigit = (0 .. 9, \'a\' .. \'f\')[$num & 15];
+
+to get a hexadecimal digit, or
+
+ @z2 = (\'01\' .. \'31\'); print @z2[$mday];
+
+to get dates with leading zeros.
+(If the final value specified is not in the sequence that the magical increment
+would produce, the sequence goes until the next value would be longer than
+the final value specified.)
+.PP
+The || and && operators differ from C's in that, rather than returning 0 or 1,
+they return the last value evaluated.
+Thus, a portable way to find out the home directory might be:
+.nf
+
+ $home = $ENV{'HOME'} || $ENV{'LOGDIR'} ||
+ (getpwuid($<))[7] || die "You're homeless!\en";
+
+.fi
+.PP
+Along with the literals and variables mentioned earlier,
+the operations in the following section can serve as terms in an expression.
+Some of these operations take a LIST as an argument.
+Such a list can consist of any combination of scalar arguments or array values;
+the array values will be included in the list as if each individual element were
+interpolated at that point in the list, forming a longer single-dimensional
+array value.
+Elements of the LIST should be separated by commas.
+If an operation is listed both with and without parentheses around its
+arguments, it means you can either use it as a unary operator or
+as a function call.
+To use it as a function call, the next token on the same line must
+be a left parenthesis.
+(There may be intervening white space.)
+Such a function then has highest precedence, as you would expect from
+a function.
+If any token other than a left parenthesis follows, then it is a
+unary operator, with a precedence depending only on whether it is a LIST
+operator or not.
+LIST operators have lowest precedence.
+All other unary operators have a precedence greater than relational operators
+but less than arithmetic operators.
+See the section on Precedence.
+.PP
+For operators that can be used in either a scalar or array context,
+failure is generally indicated in a scalar context by returning
+the undefined value, and in an array context by returning the null list.
+Remember though that
+THERE IS NO GENERAL RULE FOR CONVERTING A LIST INTO A SCALAR.
+Each operator decides which sort of scalar it would be most
+appropriate to return.
+Some operators return the length of the list
+that would have been returned in an array context.
+Some operators return the first value in the list.
+Some operators return the last value in the list.
+Some operators return a count of successful operations.
+In general, they do what you want, unless you want consistency.
+.Ip "/PATTERN/" 8 4
+See m/PATTERN/.
+.Ip "?PATTERN?" 8 4
+This is just like the /pattern/ search, except that it matches only once between
+calls to the
+.I reset
+operator.
+This is a useful optimization when you only want to see the first occurrence of
+something in each file of a set of files, for instance.
+Only ?? patterns local to the current package are reset.
+.Ip "accept(NEWSOCKET,GENERICSOCKET)" 8 2
+Does the same thing that the accept system call does.
+Returns true if it succeeded, false otherwise.
+See example in section on Interprocess Communication.
+.Ip "alarm(SECONDS)" 8 4
+.Ip "alarm SECONDS" 8
+Arranges to have a SIGALRM delivered to this process after the specified number
+of seconds (minus 1, actually) have elapsed. Thus, alarm(15) will cause
+a SIGALRM at some point more than 14 seconds in the future.
+Only one timer may be counting at once. Each call disables the previous
+timer, and an argument of 0 may be supplied to cancel the previous timer
+without starting a new one.
+The returned value is the amount of time remaining on the previous timer.
+.Ip "atan2(Y,X)" 8 2
+Returns the arctangent of Y/X in the range
+.if t \-\(*p to \(*p.
+.if n \-PI to PI.
+.Ip "bind(SOCKET,NAME)" 8 2
+Does the same thing that the bind system call does.
+Returns true if it succeeded, false otherwise.
+NAME should be a packed address of the proper type for the socket.
+See example in section on Interprocess Communication.
+.Ip "binmode(FILEHANDLE)" 8 4
+.Ip "binmode FILEHANDLE" 8 4
+Arranges for the file to be read in \*(L"binary\*(R" mode in operating systems
+that distinguish between binary and text files.
+Files that are not read in binary mode have CR LF sequences translated
+to LF on input and LF translated to CR LF on output.
+Binmode has no effect under Unix.
+If FILEHANDLE is an expression, the value is taken as the name of
+the filehandle.
+.Ip "caller(EXPR)"
+.Ip "caller"
+Returns the context of the current subroutine call:
+.nf
+
+ ($package,$filename,$line) = caller;
+
+.fi
+With EXPR, returns some extra information that the debugger uses to print
+a stack trace. The value of EXPR indicates how many call frames to go
+back before the current one.
+.Ip "chdir(EXPR)" 8 2
+.Ip "chdir EXPR" 8 2
+Changes the working directory to EXPR, if possible.
+If EXPR is omitted, changes to home directory.
+Returns 1 upon success, 0 otherwise.
+See example under
+.IR die .
+.Ip "chmod(LIST)" 8 2
+.Ip "chmod LIST" 8 2
+Changes the permissions of a list of files.
+The first element of the list must be the numerical mode.
+Returns the number of files successfully changed.
+.nf
+
+.ne 2
+ $cnt = chmod 0755, \'foo\', \'bar\';
+ chmod 0755, @executables;
+
+.fi
+.Ip "chop(LIST)" 8 7
+.Ip "chop(VARIABLE)" 8
+.Ip "chop VARIABLE" 8
+.Ip "chop" 8
+Chops off the last character of a string and returns the character chopped.
+It's used primarily to remove the newline from the end of an input record,
+but is much more efficient than s/\en// because it neither scans nor copies
+the string.
+If VARIABLE is omitted, chops $_.
+Example:
+.nf
+
+.ne 5
+ while (<>) {
+ chop; # avoid \en on last field
+ @array = split(/:/);
+ .\|.\|.
+ }
+
+.fi
+You can actually chop anything that's an lvalue, including an assignment:
+.nf
+
+ chop($cwd = \`pwd\`);
+ chop($answer = <STDIN>);
+
+.fi
+If you chop a list, each element is chopped.
+Only the value of the last chop is returned.
+.Ip "chown(LIST)" 8 2
+.Ip "chown LIST" 8 2
+Changes the owner (and group) of a list of files.
+The first two elements of the list must be the NUMERICAL uid and gid,
+in that order.
+Returns the number of files successfully changed.
+.nf
+
+.ne 2
+ $cnt = chown $uid, $gid, \'foo\', \'bar\';
+ chown $uid, $gid, @filenames;
+
+.fi
+.ne 23
+Here's an example that looks up non-numeric uids in the passwd file:
+.nf
+
+ print "User: ";
+ $user = <STDIN>;
+ chop($user);
+ print "Files: "
+ $pattern = <STDIN>;
+ chop($pattern);
+.ie t \{\
+ open(pass, \'/etc/passwd\') || die "Can't open passwd: $!\en";
+'br\}
+.el \{\
+ open(pass, \'/etc/passwd\')
+ || die "Can't open passwd: $!\en";
+'br\}
+ while (<pass>) {
+ ($login,$pass,$uid,$gid) = split(/:/);
+ $uid{$login} = $uid;
+ $gid{$login} = $gid;
+ }
+ @ary = <${pattern}>; # get filenames
+ if ($uid{$user} eq \'\') {
+ die "$user not in passwd file";
+ }
+ else {
+ chown $uid{$user}, $gid{$user}, @ary;
+ }
+
+.fi
+.Ip "chroot(FILENAME)" 8 5
+.Ip "chroot FILENAME" 8
+Does the same as the system call of that name.
+If you don't know what it does, don't worry about it.
+If FILENAME is omitted, does chroot to $_.
+.Ip "close(FILEHANDLE)" 8 5
+.Ip "close FILEHANDLE" 8
+Closes the file or pipe associated with the file handle.
+You don't have to close FILEHANDLE if you are immediately going to
+do another open on it, since open will close it for you.
+(See
+.IR open .)
+However, an explicit close on an input file resets the line counter ($.), while
+the implicit close done by
+.I open
+does not.
+Also, closing a pipe will wait for the process executing on the pipe to complete,
+in case you want to look at the output of the pipe afterwards.
+Closing a pipe explicitly also puts the status value of the command into $?.
+Example:
+.nf
+
+.ne 4
+ open(OUTPUT, \'|sort >foo\'); # pipe to sort
+ .\|.\|. # print stuff to output
+ close OUTPUT; # wait for sort to finish
+ open(INPUT, \'foo\'); # get sort's results
+
+.fi
+FILEHANDLE may be an expression whose value gives the real filehandle name.
+.Ip "closedir(DIRHANDLE)" 8 5
+.Ip "closedir DIRHANDLE" 8
+Closes a directory opened by opendir().
+.Ip "connect(SOCKET,NAME)" 8 2
+Does the same thing that the connect system call does.
+Returns true if it succeeded, false otherwise.
+NAME should be a package address of the proper type for the socket.
+See example in section on Interprocess Communication.
+.Ip "cos(EXPR)" 8 6
+.Ip "cos EXPR" 8 6
+Returns the cosine of EXPR (expressed in radians).
+If EXPR is omitted takes cosine of $_.
+.Ip "crypt(PLAINTEXT,SALT)" 8 6
+Encrypts a string exactly like the crypt() function in the C library.
+Useful for checking the password file for lousy passwords.
+Only the guys wearing white hats should do this.
+.Ip "dbmclose(ASSOC_ARRAY)" 8 6
+.Ip "dbmclose ASSOC_ARRAY" 8
+Breaks the binding between a dbm file and an associative array.
+The values remaining in the associative array are meaningless unless
+you happen to want to know what was in the cache for the dbm file.
+This function is only useful if you have ndbm.
+.Ip "dbmopen(ASSOC,DBNAME,MODE)" 8 6
+This binds a dbm or ndbm file to an associative array.
+ASSOC is the name of the associative array.
+(Unlike normal open, the first argument is NOT a filehandle, even though
+it looks like one).
+DBNAME is the name of the database (without the .dir or .pag extension).
+If the database does not exist, it is created with protection specified
+by MODE (as modified by the umask).
+If your system only supports the older dbm functions, you may perform only one
+dbmopen in your program.
+If your system has neither dbm nor ndbm, calling dbmopen produces a fatal
+error.
+.Sp
+Values assigned to the associative array prior to the dbmopen are lost.
+A certain number of values from the dbm file are cached in memory.
+By default this number is 64, but you can increase it by preallocating
+that number of garbage entries in the associative array before the dbmopen.
+You can flush the cache if necessary with the reset command.
+.Sp
+If you don't have write access to the dbm file, you can only read
+associative array variables, not set them.
+If you want to test whether you can write, either use file tests or
+try setting a dummy array entry inside an eval, which will trap the error.
+.Sp
+Note that functions such as keys() and values() may return huge array values
+when used on large dbm files.
+You may prefer to use the each() function to iterate over large dbm files.
+Example:
+.nf
+
+.ne 6
+ # print out history file offsets
+ dbmopen(HIST,'/usr/lib/news/history',0666);
+ while (($key,$val) = each %HIST) {
+ print $key, ' = ', unpack('L',$val), "\en";
+ }
+ dbmclose(HIST);
+
+.fi
+.Ip "defined(EXPR)" 8 6
+.Ip "defined EXPR" 8
+Returns a boolean value saying whether the lvalue EXPR has a real value
+or not.
+Many operations return the undefined value under exceptional conditions,
+such as end of file, uninitialized variable, system error and such.
+This function allows you to distinguish between an undefined null string
+and a defined null string with operations that might return a real null
+string, in particular referencing elements of an array.
+You may also check to see if arrays or subroutines exist.
+Use on predefined variables is not guaranteed to produce intuitive results.
+Examples:
+.nf
+
+.ne 7
+ print if defined $switch{'D'};
+ print "$val\en" while defined($val = pop(@ary));
+ die "Can't readlink $sym: $!"
+ unless defined($value = readlink $sym);
+ eval '@foo = ()' if defined(@foo);
+ die "No XYZ package defined" unless defined %_XYZ;
+ sub foo { defined &$bar ? &$bar(@_) : die "No bar"; }
+
+.fi
+See also undef.
+.Ip "delete $ASSOC{KEY}" 8 6
+Deletes the specified value from the specified associative array.
+Returns the deleted value, or the undefined value if nothing was deleted.
+Deleting from $ENV{} modifies the environment.
+Deleting from an array bound to a dbm file deletes the entry from the dbm
+file.
+.Sp
+The following deletes all the values of an associative array:
+.nf
+
+.ne 3
+ foreach $key (keys %ARRAY) {
+ delete $ARRAY{$key};
+ }
+
+.fi
+(But it would be faster to use the
+.I reset
+command.
+Saying undef %ARRAY is faster yet.)
+.Ip "die(LIST)" 8
+.Ip "die LIST" 8
+Outside of an eval, prints the value of LIST to
+.I STDERR
+and exits with the current value of $!
+(errno).
+If $! is 0, exits with the value of ($? >> 8) (\`command\` status).
+If ($? >> 8) is 0, exits with 255.
+Inside an eval, the error message is stuffed into $@ and the eval is terminated
+with the undefined value.
+.Sp
+Equivalent examples:
+.nf
+
+.ne 3
+.ie t \{\
+ die "Can't cd to spool: $!\en" unless chdir \'/usr/spool/news\';
+'br\}
+.el \{\
+ die "Can't cd to spool: $!\en"
+ unless chdir \'/usr/spool/news\';
+'br\}
+
+ chdir \'/usr/spool/news\' || die "Can't cd to spool: $!\en"
+
+.fi
+.Sp
+If the value of EXPR does not end in a newline, the current script line
+number and input line number (if any) are also printed, and a newline is
+supplied.
+Hint: sometimes appending \*(L", stopped\*(R" to your message will cause it to make
+better sense when the string \*(L"at foo line 123\*(R" is appended.
+Suppose you are running script \*(L"canasta\*(R".
+.nf
+
+.ne 7
+ die "/etc/games is no good";
+ die "/etc/games is no good, stopped";
+
+produce, respectively
+
+ /etc/games is no good at canasta line 123.
+ /etc/games is no good, stopped at canasta line 123.
+
+.fi
+See also
+.IR exit .
+.Ip "do BLOCK" 8 4
+Returns the value of the last command in the sequence of commands indicated
+by BLOCK.
+When modified by a loop modifier, executes the BLOCK once before testing the
+loop condition.
+(On other statements the loop modifiers test the conditional first.)
+.Ip "do SUBROUTINE (LIST)" 8 3
+Executes a SUBROUTINE declared by a
+.I sub
+declaration, and returns the value
+of the last expression evaluated in SUBROUTINE.
+If there is no subroutine by that name, produces a fatal error.
+(You may use the \*(L"defined\*(R" operator to determine if a subroutine
+exists.)
+If you pass arrays as part of LIST you may wish to pass the length
+of the array in front of each array.
+(See the section on subroutines later on.)
+The parentheses are required to avoid confusion with the \*(L"do EXPR\*(R"
+form.
+.Sp
+SUBROUTINE may also be a single scalar variable, in which case
+the name of the subroutine to execute is taken from the variable.
+.Sp
+As an alternate (and preferred) form,
+you may call a subroutine by prefixing the name with
+an ampersand: &foo(@args).
+If you aren't passing any arguments, you don't have to use parentheses.
+If you omit the parentheses, no @_ array is passed to the subroutine.
+The & form is also used to specify subroutines to the defined and undef
+operators:
+.nf
+
+ if (defined &$var) { &$var($parm); undef &$var; }
+
+.fi
+.Ip "do EXPR" 8 3
+Uses the value of EXPR as a filename and executes the contents of the file
+as a
+.I perl
+script.
+Its primary use is to include subroutines from a
+.I perl
+subroutine library.
+.nf
+
+ do \'stat.pl\';
+
+is just like
+
+ eval \`cat stat.pl\`;
+
+.fi
+except that it's more efficient, more concise, keeps track of the current
+filename for error messages, and searches all the
+.B \-I
+libraries if the file
+isn't in the current directory (see also the @INC array in Predefined Names).
+It's the same, however, in that it does reparse the file every time you
+call it, so if you are going to use the file inside a loop you might prefer
+to use \-P and #include, at the expense of a little more startup time.
+(The main problem with #include is that cpp doesn't grok # comments\*(--a
+workaround is to use \*(L";#\*(R" for standalone comments.)
+Note that the following are NOT equivalent:
+.nf
+
+.ne 2
+ do $foo; # eval a file
+ do $foo(); # call a subroutine
+
+.fi
+Note that inclusion of library routines is better done with
+the \*(L"require\*(R" operator.
+.Ip "dump LABEL" 8 6
+This causes an immediate core dump.
+Primarily this is so that you can use the undump program to turn your
+core dump into an executable binary after having initialized all your
+variables at the beginning of the program.
+When the new binary is executed it will begin by executing a "goto LABEL"
+(with all the restrictions that goto suffers).
+Think of it as a goto with an intervening core dump and reincarnation.
+If LABEL is omitted, restarts the program from the top.
+WARNING: any files opened at the time of the dump will NOT be open any more
+when the program is reincarnated, with possible resulting confusion on the part
+of perl.
+See also \-u.
+.Sp
+Example:
+.nf
+
+.ne 16
+ #!/usr/bin/perl
+ require 'getopt.pl';
+ require 'stat.pl';
+ %days = (
+ 'Sun',1,
+ 'Mon',2,
+ 'Tue',3,
+ 'Wed',4,
+ 'Thu',5,
+ 'Fri',6,
+ 'Sat',7);
+
+ dump QUICKSTART if $ARGV[0] eq '-d';
+
+ QUICKSTART:
+ do Getopt('f');
+
+.fi
+.Ip "each(ASSOC_ARRAY)" 8 6
+.Ip "each ASSOC_ARRAY" 8
+Returns a 2 element array consisting of the key and value for the next
+value of an associative array, so that you can iterate over it.
+Entries are returned in an apparently random order.
+When the array is entirely read, a null array is returned (which when
+assigned produces a FALSE (0) value).
+The next call to each() after that will start iterating again.
+The iterator can be reset only by reading all the elements from the array.
+You must not modify the array while iterating over it.
+There is a single iterator for each associative array, shared by all
+each(), keys() and values() function calls in the program.
+The following prints out your environment like the printenv program, only
+in a different order:
+.nf
+
+.ne 3
+ while (($key,$value) = each %ENV) {
+ print "$key=$value\en";
+ }
+
+.fi
+See also keys() and values().
+.Ip "eof(FILEHANDLE)" 8 8
+.Ip "eof()" 8
+.Ip "eof" 8
+Returns 1 if the next read on FILEHANDLE will return end of file, or if
+FILEHANDLE is not open.
+FILEHANDLE may be an expression whose value gives the real filehandle name.
+(Note that this function actually reads a character and then ungetc's it,
+so it is not very useful in an interactive context.)
+An eof without an argument returns the eof status for the last file read.
+Empty parentheses () may be used to indicate the pseudo file formed of the
+files listed on the command line, i.e. eof() is reasonable to use inside
+a while (<>) loop to detect the end of only the last file.
+Use eof(ARGV) or eof without the parentheses to test EACH file in a while (<>) loop.
+Examples:
+.nf
+
+.ne 7
+ # insert dashes just before last line of last file
+ while (<>) {
+ if (eof()) {
+ print "\-\|\-\|\-\|\-\|\-\|\-\|\-\|\-\|\-\|\-\|\-\|\-\|\-\|\-\en";
+ }
+ print;
+ }
+
+.ne 7
+ # reset line numbering on each input file
+ while (<>) {
+ print "$.\et$_";
+ if (eof) { # Not eof().
+ close(ARGV);
+ }
+ }
+
+.fi
+.Ip "eval(EXPR)" 8 6
+.Ip "eval EXPR" 8 6
+.Ip "eval BLOCK" 8 6
+EXPR is parsed and executed as if it were a little
+.I perl
+program.
+It is executed in the context of the current
+.I perl
+program, so that
+any variable settings, subroutine or format definitions remain afterwards.
+The value returned is the value of the last expression evaluated, just
+as with subroutines.
+If there is a syntax error or runtime error, or a die statement is
+executed, an undefined value is returned by
+eval, and $@ is set to the error message.
+If there was no error, $@ is guaranteed to be a null string.
+If EXPR is omitted, evaluates $_.
+The final semicolon, if any, may be omitted from the expression.
+.Sp
+Note that, since eval traps otherwise-fatal errors, it is useful for
+determining whether a particular feature
+(such as dbmopen or symlink) is implemented.
+It is also Perl's exception trapping mechanism, where the die operator is
+used to raise exceptions.
+.Sp
+If the code to be executed doesn't vary, you may use
+the eval-BLOCK form to trap run-time errors without incurring
+the penalty of recompiling each time.
+The error, if any, is still returned in $@.
+Evaluating a single-quoted string (as EXPR) has the same effect, except that
+the eval-EXPR form reports syntax errors at run time via $@, whereas the
+eval-BLOCK form reports syntax errors at compile time. The eval-EXPR form
+is optimized to eval-BLOCK the first time it succeeds. (Since the replacement
+side of a substitution is considered a single-quoted string when you
+use the e modifier, the same optimization occurs there.) Examples:
+.nf
+
+.ne 11
+ # make divide-by-zero non-fatal
+ eval { $answer = $a / $b; }; warn $@ if $@;
+
+ # optimized to same thing after first use
+ eval '$answer = $a / $b'; warn $@ if $@;
+
+ # a compile-time error
+ eval { $answer = };
+
+ # a run-time error
+ eval '$answer ='; # sets $@
+
+.fi
+.Ip "exec(LIST)" 8 8
+.Ip "exec LIST" 8 6
+If there is more than one argument in LIST, or if LIST is an array with
+more than one value,
+calls execvp() with the arguments in LIST.
+If there is only one scalar argument, the argument is checked for shell metacharacters.
+If there are any, the entire argument is passed to \*(L"/bin/sh \-c\*(R" for parsing.
+If there are none, the argument is split into words and passed directly to
+execvp(), which is more efficient.
+Note: exec (and system) do not flush your output buffer, so you may need to
+set $| to avoid lost output.
+Examples:
+.nf
+
+ exec \'/bin/echo\', \'Your arguments are: \', @ARGV;
+ exec "sort $outfile | uniq";
+
+.fi
+.Sp
+If you don't really want to execute the first argument, but want to lie
+to the program you are executing about its own name, you can specify
+the program you actually want to run by assigning that to a variable and
+putting the name of the variable in front of the LIST without a comma.
+(This always forces interpretation of the LIST as a multi-valued list, even
+if there is only a single scalar in the list.)
+Example:
+.nf
+
+.ne 2
+ $shell = '/bin/csh';
+ exec $shell '-sh'; # pretend it's a login shell
+
+.fi
+.Ip "exit(EXPR)" 8 6
+.Ip "exit EXPR" 8
+Evaluates EXPR and exits immediately with that value.
+Example:
+.nf
+
+.ne 2
+ $ans = <STDIN>;
+ exit 0 \|if \|$ans \|=~ \|/\|^[Xx]\|/\|;
+
+.fi
+See also
+.IR die .
+If EXPR is omitted, exits with 0 status.
+.Ip "exp(EXPR)" 8 3
+.Ip "exp EXPR" 8
+Returns
+.I e
+to the power of EXPR.
+If EXPR is omitted, gives exp($_).
+.Ip "fcntl(FILEHANDLE,FUNCTION,SCALAR)" 8 4
+Implements the fcntl(2) function.
+You'll probably have to say
+.nf
+
+ require "fcntl.ph"; # probably /usr/local/lib/perl/fcntl.ph
+
+.fi
+first to get the correct function definitions.
+If fcntl.ph doesn't exist or doesn't have the correct definitions
+you'll have to roll
+your own, based on your C header files such as <sys/fcntl.h>.
+(There is a perl script called h2ph that comes with the perl kit
+which may help you in this.)
+Argument processing and value return works just like ioctl below.
+Note that fcntl will produce a fatal error if used on a machine that doesn't implement
+fcntl(2).
+.Ip "fileno(FILEHANDLE)" 8 4
+.Ip "fileno FILEHANDLE" 8 4
+Returns the file descriptor for a filehandle.
+Useful for constructing bitmaps for select().
+If FILEHANDLE is an expression, the value is taken as the name of
+the filehandle.
+.Ip "flock(FILEHANDLE,OPERATION)" 8 4
+Calls flock(2) on FILEHANDLE.
+See manual page for flock(2) for definition of OPERATION.
+Returns true for success, false on failure.
+Will produce a fatal error if used on a machine that doesn't implement
+flock(2).
+Here's a mailbox appender for BSD systems.
+.nf
+
+.ne 20
+ $LOCK_SH = 1;
+ $LOCK_EX = 2;
+ $LOCK_NB = 4;
+ $LOCK_UN = 8;
+
+ sub lock {
+ flock(MBOX,$LOCK_EX);
+ # and, in case someone appended
+ # while we were waiting...
+ seek(MBOX, 0, 2);
+ }
+
+ sub unlock {
+ flock(MBOX,$LOCK_UN);
+ }
+
+ open(MBOX, ">>/usr/spool/mail/$ENV{'USER'}")
+ || die "Can't open mailbox: $!";
+
+ do lock();
+ print MBOX $msg,"\en\en";
+ do unlock();
+
+.fi
+.Ip "fork" 8 4
+Does a fork() call.
+Returns the child pid to the parent process and 0 to the child process.
+Note: unflushed buffers remain unflushed in both processes, which means
+you may need to set $| to avoid duplicate output.
+.Ip "getc(FILEHANDLE)" 8 4
+.Ip "getc FILEHANDLE" 8
+.Ip "getc" 8
+Returns the next character from the input file attached to FILEHANDLE, or
+a null string at EOF.
+If FILEHANDLE is omitted, reads from STDIN.
+.Ip "getlogin" 8 3
+Returns the current login from /etc/utmp, if any.
+If null, use getpwuid.
+
+ $login = getlogin || (getpwuid($<))[0] || "Somebody";
+
+.Ip "getpeername(SOCKET)" 8 3
+Returns the packed sockaddr address of other end of the SOCKET connection.
+.nf
+
+.ne 4
+ # An internet sockaddr
+ $sockaddr = 'S n a4 x8';
+ $hersockaddr = getpeername(S);
+.ie t \{\
+ ($family, $port, $heraddr) = unpack($sockaddr,$hersockaddr);
+'br\}
+.el \{\
+ ($family, $port, $heraddr) =
+ unpack($sockaddr,$hersockaddr);
+'br\}
+
+.fi
+.Ip "getpgrp(PID)" 8 4
+.Ip "getpgrp PID" 8
+Returns the current process group for the specified PID, 0 for the current
+process.
+Will produce a fatal error if used on a machine that doesn't implement
+getpgrp(2).
+If EXPR is omitted, returns process group of current process.
+.Ip "getppid" 8 4
+Returns the process id of the parent process.
+.Ip "getpriority(WHICH,WHO)" 8 4
+Returns the current priority for a process, a process group, or a user.
+(See getpriority(2).)
+Will produce a fatal error if used on a machine that doesn't implement
+getpriority(2).
+.Ip "getpwnam(NAME)" 8
+.Ip "getgrnam(NAME)" 8
+.Ip "gethostbyname(NAME)" 8
+.Ip "getnetbyname(NAME)" 8
+.Ip "getprotobyname(NAME)" 8
+.Ip "getpwuid(UID)" 8
+.Ip "getgrgid(GID)" 8
+.Ip "getservbyname(NAME,PROTO)" 8
+.Ip "gethostbyaddr(ADDR,ADDRTYPE)" 8
+.Ip "getnetbyaddr(ADDR,ADDRTYPE)" 8
+.Ip "getprotobynumber(NUMBER)" 8
+.Ip "getservbyport(PORT,PROTO)" 8
+.Ip "getpwent" 8
+.Ip "getgrent" 8
+.Ip "gethostent" 8
+.Ip "getnetent" 8
+.Ip "getprotoent" 8
+.Ip "getservent" 8
+.Ip "setpwent" 8
+.Ip "setgrent" 8
+.Ip "sethostent(STAYOPEN)" 8
+.Ip "setnetent(STAYOPEN)" 8
+.Ip "setprotoent(STAYOPEN)" 8
+.Ip "setservent(STAYOPEN)" 8
+.Ip "endpwent" 8
+.Ip "endgrent" 8
+.Ip "endhostent" 8
+.Ip "endnetent" 8
+.Ip "endprotoent" 8
+.Ip "endservent" 8
+These routines perform the same functions as their counterparts in the
+system library.
+Within an array context,
+the return values from the various get routines are as follows:
+.nf
+
+ ($name,$passwd,$uid,$gid,
+ $quota,$comment,$gcos,$dir,$shell) = getpw.\|.\|.
+ ($name,$passwd,$gid,$members) = getgr.\|.\|.
+ ($name,$aliases,$addrtype,$length,@addrs) = gethost.\|.\|.
+ ($name,$aliases,$addrtype,$net) = getnet.\|.\|.
+ ($name,$aliases,$proto) = getproto.\|.\|.
+ ($name,$aliases,$port,$proto) = getserv.\|.\|.
+
+.fi
+(If the entry doesn't exist you get a null list.)
+.Sp
+Within a scalar context, you get the name, unless the function was a
+lookup by name, in which case you get the other thing, whatever it is.
+(If the entry doesn't exist you get the undefined value.)
+For example:
+.nf
+
+ $uid = getpwnam
+ $name = getpwuid
+ $name = getpwent
+ $gid = getgrnam
+ $name = getgrgid
+ $name = getgrent
+ etc.
+
+.fi
+The $members value returned by getgr.\|.\|. is a space separated list
+of the login names of the members of the group.
+.Sp
+For the gethost.\|.\|. functions, if the h_errno variable is supported in C,
+it will be returned to you via $? if the function call fails.
+The @addrs value returned by a successful call is a list of the
+raw addresses returned by the corresponding system library call.
+In the Internet domain, each address is four bytes long and you can unpack
+it by saying something like:
+.nf
+
+ ($a,$b,$c,$d) = unpack('C4',$addr[0]);
+
+.fi
+.Ip "getsockname(SOCKET)" 8 3
+Returns the packed sockaddr address of this end of the SOCKET connection.
+.nf
+
+.ne 4
+ # An internet sockaddr
+ $sockaddr = 'S n a4 x8';
+ $mysockaddr = getsockname(S);
+.ie t \{\
+ ($family, $port, $myaddr) = unpack($sockaddr,$mysockaddr);
+'br\}
+.el \{\
+ ($family, $port, $myaddr) =
+ unpack($sockaddr,$mysockaddr);
+'br\}
+
+.fi
+.Ip "getsockopt(SOCKET,LEVEL,OPTNAME)" 8 3
+Returns the socket option requested, or undefined if there is an error.
+.Ip "gmtime(EXPR)" 8 4
+.Ip "gmtime EXPR" 8
+Converts a time as returned by the time function to a 9-element array with
+the time analyzed for the Greenwich timezone.
+Typically used as follows:
+.nf
+
+.ne 3
+.ie t \{\
+ ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = gmtime(time);
+'br\}
+.el \{\
+ ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) =
+ gmtime(time);
+'br\}
+
+.fi
+All array elements are numeric, and come straight out of a struct tm.
+In particular this means that $mon has the range 0.\|.11 and $wday has the
+range 0.\|.6.
+If EXPR is omitted, does gmtime(time).
+.Ip "goto LABEL" 8 6
+Finds the statement labeled with LABEL and resumes execution there.
+Currently you may only go to statements in the main body of the program
+that are not nested inside a do {} construct.
+This statement is not implemented very efficiently, and is here only to make
+the
+.IR sed -to- perl
+translator easier.
+I may change its semantics at any time, consistent with support for translated
+.I sed
+scripts.
+Use it at your own risk.
+Better yet, don't use it at all.
+.Ip "grep(EXPR,LIST)" 8 4
+Evaluates EXPR for each element of LIST (locally setting $_ to each element)
+and returns the array value consisting of those elements for which the
+expression evaluated to true.
+In a scalar context, returns the number of times the expression was true.
+.nf
+
+ @foo = grep(!/^#/, @bar); # weed out comments
+
+.fi
+Note that, since $_ is a reference into the array value, it can be
+used to modify the elements of the array.
+While this is useful and supported, it can cause bizarre results if
+the LIST is not a named array.
+.Ip "hex(EXPR)" 8 4
+.Ip "hex EXPR" 8
+Returns the decimal value of EXPR interpreted as an hex string.
+(To interpret strings that might start with 0 or 0x see oct().)
+If EXPR is omitted, uses $_.
+.Ip "index(STR,SUBSTR,POSITION)" 8 4
+.Ip "index(STR,SUBSTR)" 8 4
+Returns the position of the first occurrence of SUBSTR in STR at or after
+POSITION.
+If POSITION is omitted, starts searching from the beginning of the string.
+The return value is based at 0, or whatever you've
+set the $[ variable to.
+If the substring is not found, returns one less than the base, ordinarily \-1.
+.Ip "int(EXPR)" 8 4
+.Ip "int EXPR" 8
+Returns the integer portion of EXPR.
+If EXPR is omitted, uses $_.
+.Ip "ioctl(FILEHANDLE,FUNCTION,SCALAR)" 8 4
+Implements the ioctl(2) function.
+You'll probably have to say
+.nf
+
+ require "ioctl.ph"; # probably /usr/local/lib/perl/ioctl.ph
+
+.fi
+first to get the correct function definitions.
+If ioctl.ph doesn't exist or doesn't have the correct definitions
+you'll have to roll
+your own, based on your C header files such as <sys/ioctl.h>.
+(There is a perl script called h2ph that comes with the perl kit
+which may help you in this.)
+SCALAR will be read and/or written depending on the FUNCTION\*(--a pointer
+to the string value of SCALAR will be passed as the third argument of
+the actual ioctl call.
+(If SCALAR has no string value but does have a numeric value, that value
+will be passed rather than a pointer to the string value.
+To guarantee this to be true, add a 0 to the scalar before using it.)
+The pack() and unpack() functions are useful for manipulating the values
+of structures used by ioctl().
+The following example sets the erase character to DEL.
+.nf
+
+.ne 9
+ require 'ioctl.ph';
+ $sgttyb_t = "ccccs"; # 4 chars and a short
+ if (ioctl(STDIN,$TIOCGETP,$sgttyb)) {
+ @ary = unpack($sgttyb_t,$sgttyb);
+ $ary[2] = 127;
+ $sgttyb = pack($sgttyb_t,@ary);
+ ioctl(STDIN,$TIOCSETP,$sgttyb)
+ || die "Can't ioctl: $!";
+ }
+
+.fi
+The return value of ioctl (and fcntl) is as follows:
+.nf
+
+.ne 4
+ if OS returns:\h'|3i'perl returns:
+ -1\h'|3i' undefined value
+ 0\h'|3i' string "0 but true"
+ anything else\h'|3i' that number
+
+.fi
+Thus perl returns true on success and false on failure, yet you can still
+easily determine the actual value returned by the operating system:
+.nf
+
+ ($retval = ioctl(...)) || ($retval = -1);
+ printf "System returned %d\en", $retval;
+.fi
+.Ip "join(EXPR,LIST)" 8 8
+.Ip "join(EXPR,ARRAY)" 8
+Joins the separate strings of LIST or ARRAY into a single string with fields
+separated by the value of EXPR, and returns the string.
+Example:
+.nf
+
+.ie t \{\
+ $_ = join(\|\':\', $login,$passwd,$uid,$gid,$gcos,$home,$shell);
+'br\}
+.el \{\
+ $_ = join(\|\':\',
+ $login,$passwd,$uid,$gid,$gcos,$home,$shell);
+'br\}
+
+.fi
+See
+.IR split .
+.Ip "keys(ASSOC_ARRAY)" 8 6
+.Ip "keys ASSOC_ARRAY" 8
+Returns a normal array consisting of all the keys of the named associative
+array.
+The keys are returned in an apparently random order, but it is the same order
+as either the values() or each() function produces (given that the associative array
+has not been modified).
+Here is yet another way to print your environment:
+.nf
+
+.ne 5
+ @keys = keys %ENV;
+ @values = values %ENV;
+ while ($#keys >= 0) {
+ print pop(@keys), \'=\', pop(@values), "\en";
+ }
+
+or how about sorted by key:
+
+.ne 3
+ foreach $key (sort(keys %ENV)) {
+ print $key, \'=\', $ENV{$key}, "\en";
+ }
+
+.fi
+.Ip "kill(LIST)" 8 8
+.Ip "kill LIST" 8 2
+Sends a signal to a list of processes.
+The first element of the list must be the signal to send.
+Returns the number of processes successfully signaled.
+.nf
+
+ $cnt = kill 1, $child1, $child2;
+ kill 9, @goners;
+
+.fi
+If the signal is negative, kills process groups instead of processes.
+(On System V, a negative \fIprocess\fR number will also kill process groups,
+but that's not portable.)
+You may use a signal name in quotes.
+.Ip "last LABEL" 8 8
+.Ip "last" 8
+The
+.I last
+command is like the
+.I break
+statement in C (as used in loops); it immediately exits the loop in question.
+If the LABEL is omitted, the command refers to the innermost enclosing loop.
+The
+.I continue
+block, if any, is not executed:
+.nf
+
+.ne 4
+ line: while (<STDIN>) {
+ last line if /\|^$/; # exit when done with header
+ .\|.\|.
+ }
+
+.fi
+.Ip "length(EXPR)" 8 4
+.Ip "length EXPR" 8
+Returns the length in characters of the value of EXPR.
+If EXPR is omitted, returns length of $_.
+.Ip "link(OLDFILE,NEWFILE)" 8 2
+Creates a new filename linked to the old filename.
+Returns 1 for success, 0 otherwise.
+.Ip "listen(SOCKET,QUEUESIZE)" 8 2
+Does the same thing that the listen system call does.
+Returns true if it succeeded, false otherwise.
+See example in section on Interprocess Communication.
+.Ip "local(LIST)" 8 4
+Declares the listed variables to be local to the enclosing block,
+subroutine, eval or \*(L"do\*(R".
+All the listed elements must be legal lvalues.
+This operator works by saving the current values of those variables in LIST
+on a hidden stack and restoring them upon exiting the block, subroutine or eval.
+This means that called subroutines can also reference the local variable,
+but not the global one.
+The LIST may be assigned to if desired, which allows you to initialize
+your local variables.
+(If no initializer is given for a particular variable, it is created with
+an undefined value.)
+Commonly this is used to name the parameters to a subroutine.
+Examples:
+.nf
+
+.ne 13
+ sub RANGEVAL {
+ local($min, $max, $thunk) = @_;
+ local($result) = \'\';
+ local($i);
+
+ # Presumably $thunk makes reference to $i
+
+ for ($i = $min; $i < $max; $i++) {
+ $result .= eval $thunk;
+ }
+
+ $result;
+ }
+
+.ne 6
+ if ($sw eq \'-v\') {
+ # init local array with global array
+ local(@ARGV) = @ARGV;
+ unshift(@ARGV,\'echo\');
+ system @ARGV;
+ }
+ # @ARGV restored
+
+.ne 6
+ # temporarily add to digits associative array
+ if ($base12) {
+ # (NOTE: not claiming this is efficient!)
+ local(%digits) = (%digits,'t',10,'e',11);
+ do parse_num();
+ }
+
+.fi
+Note that local() is a run-time command, and so gets executed every time
+through a loop, using up more stack storage each time until it's all
+released at once when the loop is exited.
+.Ip "localtime(EXPR)" 8 4
+.Ip "localtime EXPR" 8
+Converts a time as returned by the time function to a 9-element array with
+the time analyzed for the local timezone.
+Typically used as follows:
+.nf
+
+.ne 3
+.ie t \{\
+ ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);
+'br\}
+.el \{\
+ ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) =
+ localtime(time);
+'br\}
+
+.fi
+All array elements are numeric, and come straight out of a struct tm.
+In particular this means that $mon has the range 0.\|.11 and $wday has the
+range 0.\|.6.
+If EXPR is omitted, does localtime(time).
+.Ip "log(EXPR)" 8 4
+.Ip "log EXPR" 8
+Returns logarithm (base
+.IR e )
+of EXPR.
+If EXPR is omitted, returns log of $_.
+.Ip "lstat(FILEHANDLE)" 8 6
+.Ip "lstat FILEHANDLE" 8
+.Ip "lstat(EXPR)" 8
+.Ip "lstat SCALARVARIABLE" 8
+Does the same thing as the stat() function, but stats a symbolic link
+instead of the file the symbolic link points to.
+If symbolic links are unimplemented on your system, a normal stat is done.
+.Ip "m/PATTERN/gio" 8 4
+.Ip "/PATTERN/gio" 8
+Searches a string for a pattern match, and returns true (1) or false (\'\').
+If no string is specified via the =~ or !~ operator,
+the $_ string is searched.
+(The string specified with =~ need not be an lvalue\*(--it may be the result of an expression evaluation, but remember the =~ binds rather tightly.)
+See also the section on regular expressions.
+.Sp
+If / is the delimiter then the initial \*(L'm\*(R' is optional.
+With the \*(L'm\*(R' you can use any pair of non-alphanumeric characters
+as delimiters.
+This is particularly useful for matching Unix path names that contain \*(L'/\*(R'.
+If the final delimiter is followed by the optional letter \*(L'i\*(R', the matching is
+done in a case-insensitive manner.
+PATTERN may contain references to scalar variables, which will be interpolated
+(and the pattern recompiled) every time the pattern search is evaluated.
+(Note that $) and $| may not be interpolated because they look like end-of-string tests.)
+If you want such a pattern to be compiled only once, add an \*(L"o\*(R" after
+the trailing delimiter.
+This avoids expensive run-time recompilations, and
+is useful when the value you are interpolating won't change over the
+life of the script.
+If the PATTERN evaluates to a null string, the most recent successful
+regular expression is used instead.
+.Sp
+If used in a context that requires an array value, a pattern match returns an
+array consisting of the subexpressions matched by the parentheses in the
+pattern,
+i.e. ($1, $2, $3.\|.\|.).
+It does NOT actually set $1, $2, etc. in this case, nor does it set $+, $`, $&
+or $'.
+If the match fails, a null array is returned.
+If the match succeeds, but there were no parentheses, an array value of (1)
+is returned.
+.Sp
+Examples:
+.nf
+
+.ne 4
+ open(tty, \'/dev/tty\');
+ <tty> \|=~ \|/\|^y\|/i \|&& \|do foo(\|); # do foo if desired
+
+ if (/Version: \|*\|([0\-9.]*\|)\|/\|) { $version = $1; }
+
+ next if m#^/usr/spool/uucp#;
+
+.ne 5
+ # poor man's grep
+ $arg = shift;
+ while (<>) {
+ print if /$arg/o; # compile only once
+ }
+
+ if (($F1, $F2, $Etc) = ($foo =~ /^(\eS+)\es+(\eS+)\es*(.*)/))
+
+.fi
+This last example splits $foo into the first two words and the remainder
+of the line, and assigns those three fields to $F1, $F2 and $Etc.
+The conditional is true if any variables were assigned, i.e. if the pattern
+matched.
+.Sp
+The \*(L"g\*(R" modifier specifies global pattern matching\*(--that is,
+matching as many times as possible within the string. How it behaves
+depends on the context. In an array context, it returns a list of
+all the substrings matched by all the parentheses in the regular expression.
+If there are no parentheses, it returns a list of all the matched strings,
+as if there were parentheses around the whole pattern. In a scalar context,
+it iterates through the string, returning TRUE each time it matches, and
+FALSE when it eventually runs out of matches. (In other words, it remembers
+where it left off last time and restarts the search at that point.) It
+presumes that you have not modified the string since the last match.
+Modifying the string between matches may result in undefined behavior.
+(You can actually get away with in-place modifications via substr()
+that do not change the length of the entire string. In general, however,
+you should be using s///g for such modifications.) Examples:
+.nf
+
+ # array context
+ ($one,$five,$fifteen) = (\`uptime\` =~ /(\ed+\e.\ed+)/g);
+
+ # scalar context
+ $/ = ""; $* = 1;
+ while ($paragraph = <>) {
+ while ($paragraph =~ /[a-z][\'")]*[.!?]+[\'")]*\es/g) {
+ $sentences++;
+ }
+ }
+ print "$sentences\en";
+
+.fi
+.Ip "mkdir(FILENAME,MODE)" 8 3
+Creates the directory specified by FILENAME, with permissions specified by
+MODE (as modified by umask).
+If it succeeds it returns 1, otherwise it returns 0 and sets $! (errno).
+.Ip "msgctl(ID,CMD,ARG)" 8 4
+Calls the System V IPC function msgctl. If CMD is &IPC_STAT, then ARG
+must be a variable which will hold the returned msqid_ds structure.
+Returns like ioctl: the undefined value for error, "0 but true" for
+zero, or the actual return value otherwise.
+.Ip "msgget(KEY,FLAGS)" 8 4
+Calls the System V IPC function msgget. Returns the message queue id,
+or the undefined value if there is an error.
+.Ip "msgsnd(ID,MSG,FLAGS)" 8 4
+Calls the System V IPC function msgsnd to send the message MSG to the
+message queue ID. MSG must begin with the long integer message type,
+which may be created with pack("L", $type). Returns true if
+successful, or false if there is an error.
+.Ip "msgrcv(ID,VAR,SIZE,TYPE,FLAGS)" 8 4
+Calls the System V IPC function msgrcv to receive a message from
+message queue ID into variable VAR with a maximum message size of
+SIZE. Note that if a message is received, the message type will be
+the first thing in VAR, and the maximum length of VAR is SIZE plus the
+size of the message type. Returns true if successful, or false if
+there is an error.
+.Ip "next LABEL" 8 8
+.Ip "next" 8
+The
+.I next
+command is like the
+.I continue
+statement in C; it starts the next iteration of the loop:
+.nf
+
+.ne 4
+ line: while (<STDIN>) {
+ next line if /\|^#/; # discard comments
+ .\|.\|.
+ }
+
+.fi
+Note that if there were a
+.I continue
+block on the above, it would get executed even on discarded lines.
+If the LABEL is omitted, the command refers to the innermost enclosing loop.
+.Ip "oct(EXPR)" 8 4
+.Ip "oct EXPR" 8
+Returns the decimal value of EXPR interpreted as an octal string.
+(If EXPR happens to start off with 0x, interprets it as a hex string instead.)
+The following will handle decimal, octal and hex in the standard notation:
+.nf
+
+ $val = oct($val) if $val =~ /^0/;
+
+.fi
+If EXPR is omitted, uses $_.
+.Ip "open(FILEHANDLE,EXPR)" 8 8
+.Ip "open(FILEHANDLE)" 8
+.Ip "open FILEHANDLE" 8
+Opens the file whose filename is given by EXPR, and associates it with
+FILEHANDLE.
+If FILEHANDLE is an expression, its value is used as the name of the
+real filehandle wanted.
+If EXPR is omitted, the scalar variable of the same name as the FILEHANDLE
+contains the filename.
+If the filename begins with \*(L"<\*(R" or nothing, the file is opened for
+input.
+If the filename begins with \*(L">\*(R", the file is opened for output.
+If the filename begins with \*(L">>\*(R", the file is opened for appending.
+(You can put a \'+\' in front of the \'>\' or \'<\' to indicate that you
+want both read and write access to the file.)
+If the filename begins with \*(L"|\*(R", the filename is interpreted
+as a command to which output is to be piped, and if the filename ends
+with a \*(L"|\*(R", the filename is interpreted as command which pipes
+input to us.
+(You may not have a command that pipes both in and out.)
+Opening \'\-\' opens
+.I STDIN
+and opening \'>\-\' opens
+.IR STDOUT .
+Open returns non-zero upon success, the undefined value otherwise.
+If the open involved a pipe, the return value happens to be the pid
+of the subprocess.
+Examples:
+.nf
+
+.ne 3
+ $article = 100;
+ open article || die "Can't find article $article: $!\en";
+ while (<article>) {\|.\|.\|.
+
+.ie t \{\
+ open(LOG, \'>>/usr/spool/news/twitlog\'\|); # (log is reserved)
+'br\}
+.el \{\
+ open(LOG, \'>>/usr/spool/news/twitlog\'\|);
+ # (log is reserved)
+'br\}
+
+.ie t \{\
+ open(article, "caesar <$article |"\|); # decrypt article
+'br\}
+.el \{\
+ open(article, "caesar <$article |"\|);
+ # decrypt article
+'br\}
+
+.ie t \{\
+ open(extract, "|sort >/tmp/Tmp$$"\|); # $$ is our process#
+'br\}
+.el \{\
+ open(extract, "|sort >/tmp/Tmp$$"\|);
+ # $$ is our process#
+'br\}
+
+.ne 7
+ # process argument list of files along with any includes
+
+ foreach $file (@ARGV) {
+ do process($file, \'fh00\'); # no pun intended
+ }
+
+ sub process {
+ local($filename, $input) = @_;
+ $input++; # this is a string increment
+ unless (open($input, $filename)) {
+ print STDERR "Can't open $filename: $!\en";
+ return;
+ }
+.ie t \{\
+ while (<$input>) { # note the use of indirection
+'br\}
+.el \{\
+ while (<$input>) { # note use of indirection
+'br\}
+ if (/^#include "(.*)"/) {
+ do process($1, $input);
+ next;
+ }
+ .\|.\|. # whatever
+ }
+ }
+
+.fi
+You may also, in the Bourne shell tradition, specify an EXPR beginning
+with \*(L">&\*(R", in which case the rest of the string
+is interpreted as the name of a filehandle
+(or file descriptor, if numeric) which is to be duped and opened.
+You may use & after >, >>, <, +>, +>> and +<.
+The mode you specify should match the mode of the original filehandle.
+Here is a script that saves, redirects, and restores
+.I STDOUT
+and
+.IR STDERR :
+.nf
+
+.ne 21
+ #!/usr/bin/perl
+ open(SAVEOUT, ">&STDOUT");
+ open(SAVEERR, ">&STDERR");
+
+ open(STDOUT, ">foo.out") || die "Can't redirect stdout";
+ open(STDERR, ">&STDOUT") || die "Can't dup stdout";
+
+ select(STDERR); $| = 1; # make unbuffered
+ select(STDOUT); $| = 1; # make unbuffered
+
+ print STDOUT "stdout 1\en"; # this works for
+ print STDERR "stderr 1\en"; # subprocesses too
+
+ close(STDOUT);
+ close(STDERR);
+
+ open(STDOUT, ">&SAVEOUT");
+ open(STDERR, ">&SAVEERR");
+
+ print STDOUT "stdout 2\en";
+ print STDERR "stderr 2\en";
+
+.fi
+If you open a pipe on the command \*(L"\-\*(R", i.e. either \*(L"|\-\*(R" or \*(L"\-|\*(R",
+then there is an implicit fork done, and the return value of open
+is the pid of the child within the parent process, and 0 within the child
+process.
+(Use defined($pid) to determine if the open was successful.)
+The filehandle behaves normally for the parent, but i/o to that
+filehandle is piped from/to the
+.IR STDOUT / STDIN
+of the child process.
+In the child process the filehandle isn't opened\*(--i/o happens from/to
+the new
+.I STDOUT
+or
+.IR STDIN .
+Typically this is used like the normal piped open when you want to exercise
+more control over just how the pipe command gets executed, such as when
+you are running setuid, and don't want to have to scan shell commands
+for metacharacters.
+The following pairs are more or less equivalent:
+.nf
+
+.ne 5
+ open(FOO, "|tr \'[a\-z]\' \'[A\-Z]\'");
+ open(FOO, "|\-") || exec \'tr\', \'[a\-z]\', \'[A\-Z]\';
+
+ open(FOO, "cat \-n '$file'|");
+ open(FOO, "\-|") || exec \'cat\', \'\-n\', $file;
+
+.fi
+Explicitly closing any piped filehandle causes the parent process to wait for the
+child to finish, and returns the status value in $?.
+Note: on any operation which may do a fork,
+unflushed buffers remain unflushed in both
+processes, which means you may need to set $| to
+avoid duplicate output.
+.Sp
+The filename that is passed to open will have leading and trailing
+whitespace deleted.
+In order to open a file with arbitrary weird characters in it, it's necessary
+to protect any leading and trailing whitespace thusly:
+.nf
+
+.ne 2
+ $file =~ s#^(\es)#./$1#;
+ open(FOO, "< $file\e0");
+
+.fi
+.Ip "opendir(DIRHANDLE,EXPR)" 8 3
+Opens a directory named EXPR for processing by readdir(), telldir(), seekdir(),
+rewinddir() and closedir().
+Returns true if successful.
+DIRHANDLEs have their own namespace separate from FILEHANDLEs.
+.Ip "ord(EXPR)" 8 4
+.Ip "ord EXPR" 8
+Returns the numeric ascii value of the first character of EXPR.
+If EXPR is omitted, uses $_.
+''' Comments on f & d by gnb@melba.bby.oz.au 22/11/89
+.Ip "pack(TEMPLATE,LIST)" 8 4
+Takes an array or list of values and packs it into a binary structure,
+returning the string containing the structure.
+The TEMPLATE is a sequence of characters that give the order and type
+of values, as follows:
+.nf
+
+ A An ascii string, will be space padded.
+ a An ascii string, will be null padded.
+ c A signed char value.
+ C An unsigned char value.
+ s A signed short value.
+ S An unsigned short value.
+ i A signed integer value.
+ I An unsigned integer value.
+ l A signed long value.
+ L An unsigned long value.
+ n A short in \*(L"network\*(R" order.
+ N A long in \*(L"network\*(R" order.
+ f A single-precision float in the native format.
+ d A double-precision float in the native format.
+ p A pointer to a string.
+ v A short in \*(L"VAX\*(R" (little-endian) order.
+ V A long in \*(L"VAX\*(R" (little-endian) order.
+ x A null byte.
+ X Back up a byte.
+ @ Null fill to absolute position.
+ u A uuencoded string.
+ b A bit string (ascending bit order, like vec()).
+ B A bit string (descending bit order).
+ h A hex string (low nybble first).
+ H A hex string (high nybble first).
+
+.fi
+Each letter may optionally be followed by a number which gives a repeat
+count.
+With all types except "a", "A", "b", "B", "h" and "H",
+the pack function will gobble up that many values
+from the LIST.
+A * for the repeat count means to use however many items are left.
+The "a" and "A" types gobble just one value, but pack it as a string of length
+count,
+padding with nulls or spaces as necessary.
+(When unpacking, "A" strips trailing spaces and nulls, but "a" does not.)
+Likewise, the "b" and "B" fields pack a string that many bits long.
+The "h" and "H" fields pack a string that many nybbles long.
+Real numbers (floats and doubles) are in the native machine format
+only; due to the multiplicity of floating formats around, and the lack
+of a standard \*(L"network\*(R" representation, no facility for
+interchange has been made.
+This means that packed floating point data
+written on one machine may not be readable on another - even if both
+use IEEE floating point arithmetic (as the endian-ness of the memory
+representation is not part of the IEEE spec).
+Note that perl uses
+doubles internally for all numeric calculation, and converting from
+double -> float -> double will lose precision (i.e. unpack("f",
+pack("f", $foo)) will not in general equal $foo).
+.br
+Examples:
+.nf
+
+ $foo = pack("cccc",65,66,67,68);
+ # foo eq "ABCD"
+ $foo = pack("c4",65,66,67,68);
+ # same thing
+
+ $foo = pack("ccxxcc",65,66,67,68);
+ # foo eq "AB\e0\e0CD"
+
+ $foo = pack("s2",1,2);
+ # "\e1\e0\e2\e0" on little-endian
+ # "\e0\e1\e0\e2" on big-endian
+
+ $foo = pack("a4","abcd","x","y","z");
+ # "abcd"
+
+ $foo = pack("aaaa","abcd","x","y","z");
+ # "axyz"
+
+ $foo = pack("a14","abcdefg");
+ # "abcdefg\e0\e0\e0\e0\e0\e0\e0"
+
+ $foo = pack("i9pl", gmtime);
+ # a real struct tm (on my system anyway)
+
+ sub bintodec {
+ unpack("N", pack("B32", substr("0" x 32 . shift, -32)));
+ }
+.fi
+The same template may generally also be used in the unpack function.
+.Ip "pipe(READHANDLE,WRITEHANDLE)" 8 3
+Opens a pair of connected pipes like the corresponding system call.
+Note that if you set up a loop of piped processes, deadlock can occur
+unless you are very careful.
+In addition, note that perl's pipes use stdio buffering, so you may need
+to set $| to flush your WRITEHANDLE after each command, depending on
+the application.
+[Requires version 3.0 patchlevel 9.]
+.Ip "pop(ARRAY)" 8
+.Ip "pop ARRAY" 8 6
+Pops and returns the last value of the array, shortening the array by 1.
+Has the same effect as
+.nf
+
+ $tmp = $ARRAY[$#ARRAY\-\|\-];
+
+.fi
+If there are no elements in the array, returns the undefined value.
+.Ip "print(FILEHANDLE LIST)" 8 10
+.Ip "print(LIST)" 8
+.Ip "print FILEHANDLE LIST" 8
+.Ip "print LIST" 8
+.Ip "print" 8
+Prints a string or a comma-separated list of strings.
+Returns non-zero if successful.
+FILEHANDLE may be a scalar variable name, in which case the variable contains
+the name of the filehandle, thus introducing one level of indirection.
+(NOTE: If FILEHANDLE is a variable and the next token is a term, it may be
+misinterpreted as an operator unless you interpose a + or put parens around
+the arguments.)
+If FILEHANDLE is omitted, prints by default to standard output (or to the
+last selected output channel\*(--see select()).
+If LIST is also omitted, prints $_ to
+.IR STDOUT .
+To set the default output channel to something other than
+.I STDOUT
+use the select operation.
+Note that, because print takes a LIST, anything in the LIST is evaluated
+in an array context, and any subroutine that you call will have one or more
+of its expressions evaluated in an array context.
+Also be careful not to follow the print keyword with a left parenthesis
+unless you want the corresponding right parenthesis to terminate the
+arguments to the print\*(--interpose a + or put parens around all the arguments.
+.Ip "printf(FILEHANDLE LIST)" 8 10
+.Ip "printf(LIST)" 8
+.Ip "printf FILEHANDLE LIST" 8
+.Ip "printf LIST" 8
+Equivalent to a \*(L"print FILEHANDLE sprintf(LIST)\*(R".
+.Ip "push(ARRAY,LIST)" 8 7
+Treats ARRAY (@ is optional) as a stack, and pushes the values of LIST
+onto the end of ARRAY.
+The length of ARRAY increases by the length of LIST.
+Has the same effect as
+.nf
+
+ for $value (LIST) {
+ $ARRAY[++$#ARRAY] = $value;
+ }
+
+.fi
+but is more efficient.
+.Ip "q/STRING/" 8 5
+.Ip "qq/STRING/" 8
+.Ip "qx/STRING/" 8
+These are not really functions, but simply syntactic sugar to let you
+avoid putting too many backslashes into quoted strings.
+The q operator is a generalized single quote, and the qq operator a
+generalized double quote.
+The qx operator is a generalized backquote.
+Any non-alphanumeric delimiter can be used in place of /, including newline.
+If the delimiter is an opening bracket or parenthesis, the final delimiter
+will be the corresponding closing bracket or parenthesis.
+(Embedded occurrences of the closing bracket need to be backslashed as usual.)
+Examples:
+.nf
+
+.ne 5
+ $foo = q!I said, "You said, \'She said it.\'"!;
+ $bar = q(\'This is it.\');
+ $today = qx{ date };
+ $_ .= qq
+*** The previous line contains the naughty word "$&".\en
+ if /(ibm|apple|awk)/; # :-)
+
+.fi
+.Ip "rand(EXPR)" 8 8
+.Ip "rand EXPR" 8
+.Ip "rand" 8
+Returns a random fractional number between 0 and the value of EXPR.
+(EXPR should be positive.)
+If EXPR is omitted, returns a value between 0 and 1.
+See also srand().
+.Ip "read(FILEHANDLE,SCALAR,LENGTH,OFFSET)" 8 5
+.Ip "read(FILEHANDLE,SCALAR,LENGTH)" 8 5
+Attempts to read LENGTH bytes of data into variable SCALAR from the specified
+FILEHANDLE.
+Returns the number of bytes actually read, or undef if there was an error.
+SCALAR will be grown or shrunk to the length actually read.
+An OFFSET may be specified to place the read data at some other place
+than the beginning of the string.
+This call is actually implemented in terms of stdio's fread call. To get
+a true read system call, see sysread.
+.Ip "readdir(DIRHANDLE)" 8 3
+.Ip "readdir DIRHANDLE" 8
+Returns the next directory entry for a directory opened by opendir().
+If used in an array context, returns all the rest of the entries in the
+directory.
+If there are no more entries, returns an undefined value in a scalar context
+or a null list in an array context.
+.Ip "readlink(EXPR)" 8 6
+.Ip "readlink EXPR" 8
+Returns the value of a symbolic link, if symbolic links are implemented.
+If not, gives a fatal error.
+If there is some system error, returns the undefined value and sets $! (errno).
+If EXPR is omitted, uses $_.
+.Ip "recv(SOCKET,SCALAR,LEN,FLAGS)" 8 4
+Receives a message on a socket.
+Attempts to receive LENGTH bytes of data into variable SCALAR from the specified
+SOCKET filehandle.
+Returns the address of the sender, or the undefined value if there's an error.
+SCALAR will be grown or shrunk to the length actually read.
+Takes the same flags as the system call of the same name.
+.Ip "redo LABEL" 8 8
+.Ip "redo" 8
+The
+.I redo
+command restarts the loop block without evaluating the conditional again.
+The
+.I continue
+block, if any, is not executed.
+If the LABEL is omitted, the command refers to the innermost enclosing loop.
+This command is normally used by programs that want to lie to themselves
+about what was just input:
+.nf
+
+.ne 16
+ # a simpleminded Pascal comment stripper
+ # (warning: assumes no { or } in strings)
+ line: while (<STDIN>) {
+ while (s|\|({.*}.*\|){.*}|$1 \||) {}
+ s|{.*}| \||;
+ if (s|{.*| \||) {
+ $front = $_;
+ while (<STDIN>) {
+ if (\|/\|}/\|) { # end of comment?
+ s|^|$front{|;
+ redo line;
+ }
+ }
+ }
+ print;
+ }
+
+.fi
+.Ip "rename(OLDNAME,NEWNAME)" 8 2
+Changes the name of a file.
+Returns 1 for success, 0 otherwise.
+Will not work across filesystem boundaries.
+.Ip "require(EXPR)" 8 6
+.Ip "require EXPR" 8
+.Ip "require" 8
+Includes the library file specified by EXPR, or by $_ if EXPR is not supplied.
+Has semantics similar to the following subroutine:
+.nf
+
+ sub require {
+ local($filename) = @_;
+ return 1 if $INC{$filename};
+ local($realfilename,$result);
+ ITER: {
+ foreach $prefix (@INC) {
+ $realfilename = "$prefix/$filename";
+ if (-f $realfilename) {
+ $result = do $realfilename;
+ last ITER;
+ }
+ }
+ die "Can't find $filename in \e@INC";
+ }
+ die $@ if $@;
+ die "$filename did not return true value" unless $result;
+ $INC{$filename} = $realfilename;
+ $result;
+ }
+
+.fi
+Note that the file will not be included twice under the same specified name.
+The file must return true as the last statement to indicate successful
+execution of any initialization code, so it's customary to end
+such a file with \*(L"1;\*(R" unless you're sure it'll return true otherwise.
+.Ip "reset(EXPR)" 8 6
+.Ip "reset EXPR" 8
+.Ip "reset" 8
+Generally used in a
+.I continue
+block at the end of a loop to clear variables and reset ?? searches
+so that they work again.
+The expression is interpreted as a list of single characters (hyphens allowed
+for ranges).
+All variables and arrays beginning with one of those letters are reset to
+their pristine state.
+If the expression is omitted, one-match searches (?pattern?) are reset to
+match again.
+Only resets variables or searches in the current package.
+Always returns 1.
+Examples:
+.nf
+
+.ne 3
+ reset \'X\'; \h'|2i'# reset all X variables
+ reset \'a\-z\';\h'|2i'# reset lower case variables
+ reset; \h'|2i'# just reset ?? searches
+
+.fi
+Note: resetting \*(L"A\-Z\*(R" is not recommended since you'll wipe out your ARGV and ENV
+arrays.
+.Sp
+The use of reset on dbm associative arrays does not change the dbm file.
+(It does, however, flush any entries cached by perl, which may be useful if
+you are sharing the dbm file.
+Then again, maybe not.)
+.Ip "return LIST" 8 3
+Returns from a subroutine with the value specified.
+(Note that a subroutine can automatically return
+the value of the last expression evaluated.
+That's the preferred method\*(--use of an explicit
+.I return
+is a bit slower.)
+.Ip "reverse(LIST)" 8 4
+.Ip "reverse LIST" 8
+In an array context, returns an array value consisting of the elements
+of LIST in the opposite order.
+In a scalar context, returns a string value consisting of the bytes of
+the first element of LIST in the opposite order.
+.Ip "rewinddir(DIRHANDLE)" 8 5
+.Ip "rewinddir DIRHANDLE" 8
+Sets the current position to the beginning of the directory for the readdir() routine on DIRHANDLE.
+.Ip "rindex(STR,SUBSTR,POSITION)" 8 6
+.Ip "rindex(STR,SUBSTR)" 8 4
+Works just like index except that it
+returns the position of the LAST occurrence of SUBSTR in STR.
+If POSITION is specified, returns the last occurrence at or before that
+position.
+.Ip "rmdir(FILENAME)" 8 4
+.Ip "rmdir FILENAME" 8
+Deletes the directory specified by FILENAME if it is empty.
+If it succeeds it returns 1, otherwise it returns 0 and sets $! (errno).
+If FILENAME is omitted, uses $_.
+.Ip "s/PATTERN/REPLACEMENT/gieo" 8 3
+Searches a string for a pattern, and if found, replaces that pattern with the
+replacement text and returns the number of substitutions made.
+Otherwise it returns false (0).
+The \*(L"g\*(R" is optional, and if present, indicates that all occurrences
+of the pattern are to be replaced.
+The \*(L"i\*(R" is also optional, and if present, indicates that matching
+is to be done in a case-insensitive manner.
+The \*(L"e\*(R" is likewise optional, and if present, indicates that
+the replacement string is to be evaluated as an expression rather than just
+as a double-quoted string.
+Any non-alphanumeric delimiter may replace the slashes;
+if single quotes are used, no
+interpretation is done on the replacement string (the e modifier overrides
+this, however); if backquotes are used, the replacement string is a command
+to execute whose output will be used as the actual replacement text.
+If the PATTERN is delimited by bracketing quotes, the REPLACEMENT
+has its own pair of quotes, which may or may not be bracketing quotes, e.g.
+s(foo)(bar) or s<foo>/bar/.
+If no string is specified via the =~ or !~ operator,
+the $_ string is searched and modified.
+(The string specified with =~ must be a scalar variable, an array element,
+or an assignment to one of those, i.e. an lvalue.)
+If the pattern contains a $ that looks like a variable rather than an
+end-of-string test, the variable will be interpolated into the pattern at
+run-time.
+If you only want the pattern compiled once the first time the variable is
+interpolated, add an \*(L"o\*(R" at the end.
+If the PATTERN evaluates to a null string, the most recent successful
+regular expression is used instead.
+See also the section on regular expressions.
+Examples:
+.nf
+
+ s/\|\e\|bgreen\e\|b/mauve/g; # don't change wintergreen
+
+ $path \|=~ \|s|\|/usr/bin|\|/usr/local/bin|;
+
+ s/Login: $foo/Login: $bar/; # run-time pattern
+
+ ($foo = $bar) =~ s/bar/foo/;
+
+ $_ = \'abc123xyz\';
+ s/\ed+/$&*2/e; # yields \*(L'abc246xyz\*(R'
+ s/\ed+/sprintf("%5d",$&)/e; # yields \*(L'abc 246xyz\*(R'
+ s/\ew/$& x 2/eg; # yields \*(L'aabbcc 224466xxyyzz\*(R'
+
+ s/\|([^ \|]*\|) *\|([^ \|]*\|)\|/\|$2 $1/; # reverse 1st two fields
+
+.fi
+(Note the use of $ instead of \|\e\| in the last example. See section
+on regular expressions.)
+.Ip "scalar(EXPR)" 8 3
+Forces EXPR to be interpreted in a scalar context and returns the value
+of EXPR.
+.Ip "seek(FILEHANDLE,POSITION,WHENCE)" 8 3
+Randomly positions the file pointer for FILEHANDLE, just like the fseek()
+call of stdio.
+FILEHANDLE may be an expression whose value gives the name of the filehandle.
+Returns 1 upon success, 0 otherwise.
+.Ip "seekdir(DIRHANDLE,POS)" 8 3
+Sets the current position for the readdir() routine on DIRHANDLE.
+POS must be a value returned by telldir().
+Has the same caveats about possible directory compaction as the corresponding
+system library routine.
+.Ip "select(FILEHANDLE)" 8 3
+.Ip "select" 8 3
+Returns the currently selected filehandle.
+Sets the current default filehandle for output, if FILEHANDLE is supplied.
+This has two effects: first, a
+.I write
+or a
+.I print
+without a filehandle will default to this FILEHANDLE.
+Second, references to variables related to output will refer to this output
+channel.
+For example, if you have to set the top of form format for more than
+one output channel, you might do the following:
+.nf
+
+.ne 4
+ select(REPORT1);
+ $^ = \'report1_top\';
+ select(REPORT2);
+ $^ = \'report2_top\';
+
+.fi
+FILEHANDLE may be an expression whose value gives the name of the actual filehandle.
+Thus:
+.nf
+
+ $oldfh = select(STDERR); $| = 1; select($oldfh);
+
+.fi
+.Ip "select(RBITS,WBITS,EBITS,TIMEOUT)" 8 3
+This calls the select system call with the bitmasks specified, which can
+be constructed using fileno() and vec(), along these lines:
+.nf
+
+ $rin = $win = $ein = '';
+ vec($rin,fileno(STDIN),1) = 1;
+ vec($win,fileno(STDOUT),1) = 1;
+ $ein = $rin | $win;
+
+.fi
+If you want to select on many filehandles you might wish to write a subroutine:
+.nf
+
+ sub fhbits {
+ local(@fhlist) = split(' ',$_[0]);
+ local($bits);
+ for (@fhlist) {
+ vec($bits,fileno($_),1) = 1;
+ }
+ $bits;
+ }
+ $rin = &fhbits('STDIN TTY SOCK');
+
+.fi
+The usual idiom is:
+.nf
+
+ ($nfound,$timeleft) =
+ select($rout=$rin, $wout=$win, $eout=$ein, $timeout);
+
+or to block until something becomes ready:
+
+.ie t \{\
+ $nfound = select($rout=$rin, $wout=$win, $eout=$ein, undef);
+'br\}
+.el \{\
+ $nfound = select($rout=$rin, $wout=$win,
+ $eout=$ein, undef);
+'br\}
+
+.fi
+Any of the bitmasks can also be undef.
+The timeout, if specified, is in seconds, which may be fractional.
+NOTE: not all implementations are capable of returning the $timeleft.
+If not, they always return $timeleft equal to the supplied $timeout.
+.Ip "semctl(ID,SEMNUM,CMD,ARG)" 8 4
+Calls the System V IPC function semctl. If CMD is &IPC_STAT or
+&GETALL, then ARG must be a variable which will hold the returned
+semid_ds structure or semaphore value array. Returns like ioctl: the
+undefined value for error, "0 but true" for zero, or the actual return
+value otherwise.
+.Ip "semget(KEY,NSEMS,SIZE,FLAGS)" 8 4
+Calls the System V IPC function semget. Returns the semaphore id, or
+the undefined value if there is an error.
+.Ip "semop(KEY,OPSTRING)" 8 4
+Calls the System V IPC function semop to perform semaphore operations
+such as signaling and waiting. OPSTRING must be a packed array of
+semop structures. Each semop structure can be generated with
+\&'pack("sss", $semnum, $semop, $semflag)'. The number of semaphore
+operations is implied by the length of OPSTRING. Returns true if
+successful, or false if there is an error. As an example, the
+following code waits on semaphore $semnum of semaphore id $semid:
+.nf
+
+ $semop = pack("sss", $semnum, -1, 0);
+ die "Semaphore trouble: $!\en" unless semop($semid, $semop);
+
+.fi
+To signal the semaphore, replace "-1" with "1".
+.Ip "send(SOCKET,MSG,FLAGS,TO)" 8 4
+.Ip "send(SOCKET,MSG,FLAGS)" 8
+Sends a message on a socket.
+Takes the same flags as the system call of the same name.
+On unconnected sockets you must specify a destination to send TO.
+Returns the number of characters sent, or the undefined value if
+there is an error.
+.Ip "setpgrp(PID,PGRP)" 8 4
+Sets the current process group for the specified PID, 0 for the current
+process.
+Will produce a fatal error if used on a machine that doesn't implement
+setpgrp(2).
+.Ip "setpriority(WHICH,WHO,PRIORITY)" 8 4
+Sets the current priority for a process, a process group, or a user.
+(See setpriority(2).)
+Will produce a fatal error if used on a machine that doesn't implement
+setpriority(2).
+.Ip "setsockopt(SOCKET,LEVEL,OPTNAME,OPTVAL)" 8 3
+Sets the socket option requested.
+Returns undefined if there is an error.
+OPTVAL may be specified as undef if you don't want to pass an argument.
+.Ip "shift(ARRAY)" 8 6
+.Ip "shift ARRAY" 8
+.Ip "shift" 8
+Shifts the first value of the array off and returns it,
+shortening the array by 1 and moving everything down.
+If there are no elements in the array, returns the undefined value.
+If ARRAY is omitted, shifts the @ARGV array in the main program, and the @_
+array in subroutines.
+(This is determined lexically.)
+See also unshift(), push() and pop().
+Shift() and unshift() do the same thing to the left end of an array that push()
+and pop() do to the right end.
+.Ip "shmctl(ID,CMD,ARG)" 8 4
+Calls the System V IPC function shmctl. If CMD is &IPC_STAT, then ARG
+must be a variable which will hold the returned shmid_ds structure.
+Returns like ioctl: the undefined value for error, "0 but true" for
+zero, or the actual return value otherwise.
+.Ip "shmget(KEY,SIZE,FLAGS)" 8 4
+Calls the System V IPC function shmget. Returns the shared memory
+segment id, or the undefined value if there is an error.
+.Ip "shmread(ID,VAR,POS,SIZE)" 8 4
+.Ip "shmwrite(ID,STRING,POS,SIZE)" 8
+Reads or writes the System V shared memory segment ID starting at
+position POS for size SIZE by attaching to it, copying in/out, and
+detaching from it. When reading, VAR must be a variable which
+will hold the data read. When writing, if STRING is too long,
+only SIZE bytes are used; if STRING is too short, nulls are
+written to fill out SIZE bytes. Return true if successful, or
+false if there is an error.
+.Ip "shutdown(SOCKET,HOW)" 8 3
+Shuts down a socket connection in the manner indicated by HOW, which has
+the same interpretation as in the system call of the same name.
+.Ip "sin(EXPR)" 8 4
+.Ip "sin EXPR" 8
+Returns the sine of EXPR (expressed in radians).
+If EXPR is omitted, returns sine of $_.
+.Ip "sleep(EXPR)" 8 6
+.Ip "sleep EXPR" 8
+.Ip "sleep" 8
+Causes the script to sleep for EXPR seconds, or forever if no EXPR.
+May be interrupted by sending the process a SIGALRM.
+Returns the number of seconds actually slept.
+You probably cannot mix alarm() and sleep() calls, since sleep() is
+often implemented using alarm().
+.Ip "socket(SOCKET,DOMAIN,TYPE,PROTOCOL)" 8 3
+Opens a socket of the specified kind and attaches it to filehandle SOCKET.
+DOMAIN, TYPE and PROTOCOL are specified the same as for the system call
+of the same name.
+You may need to run h2ph on sys/socket.h to get the proper values handy
+in a perl library file.
+Return true if successful.
+See the example in the section on Interprocess Communication.
+.Ip "socketpair(SOCKET1,SOCKET2,DOMAIN,TYPE,PROTOCOL)" 8 3
+Creates an unnamed pair of sockets in the specified domain, of the specified
+type.
+DOMAIN, TYPE and PROTOCOL are specified the same as for the system call
+of the same name.
+If unimplemented, yields a fatal error.
+Return true if successful.
+.Ip "sort(SUBROUTINE LIST)" 8 9
+.Ip "sort(LIST)" 8
+.Ip "sort SUBROUTINE LIST" 8
+.Ip "sort BLOCK LIST" 8
+.Ip "sort LIST" 8
+Sorts the LIST and returns the sorted array value.
+Nonexistent values of arrays are stripped out.
+If SUBROUTINE or BLOCK is omitted, sorts in standard string comparison order.
+If SUBROUTINE is specified, gives the name of a subroutine that returns
+an integer less than, equal to, or greater than 0,
+depending on how the elements of the array are to be ordered.
+(The <=> and cmp operators are extremely useful in such routines.)
+SUBROUTINE may be a scalar variable name, in which case the value provides
+the name of the subroutine to use.
+In place of a SUBROUTINE name, you can provide a BLOCK as an anonymous,
+in-line sort subroutine.
+.Sp
+In the interests of efficiency the normal calling code for subroutines
+is bypassed, with the following effects: the subroutine may not be a recursive
+subroutine, and the two elements to be compared are passed into the subroutine
+not via @_ but as $a and $b (see example below).
+They are passed by reference so don't modify $a and $b.
+.Sp
+Examples:
+.nf
+
+.ne 2
+ # sort lexically
+ @articles = sort @files;
+
+.ne 2
+ # same thing, but with explicit sort routine
+ @articles = sort {$a cmp $b} @files;
+
+.ne 2
+ # same thing in reversed order
+ @articles = sort {$b cmp $a} @files;
+
+.ne 2
+ # sort numerically ascending
+ @articles = sort {$a <=> $b} @files;
+
+.ne 2
+ # sort numerically descending
+ @articles = sort {$b <=> $a} @files;
+
+.ne 5
+ # sort using explicit subroutine name
+ sub byage {
+ $age{$a} <=> $age{$b}; # presuming integers
+ }
+ @sortedclass = sort byage @class;
+
+.ne 9
+ sub reverse { $b cmp $a; }
+ @harry = (\'dog\',\'cat\',\'x\',\'Cain\',\'Abel\');
+ @george = (\'gone\',\'chased\',\'yz\',\'Punished\',\'Axed\');
+ print sort @harry;
+ # prints AbelCaincatdogx
+ print sort reverse @harry;
+ # prints xdogcatCainAbel
+ print sort @george, \'to\', @harry;
+ # prints AbelAxedCainPunishedcatchaseddoggonetoxyz
+
+.fi
+.Ip "splice(ARRAY,OFFSET,LENGTH,LIST)" 8 8
+.Ip "splice(ARRAY,OFFSET,LENGTH)" 8
+.Ip "splice(ARRAY,OFFSET)" 8
+Removes the elements designated by OFFSET and LENGTH from an array, and
+replaces them with the elements of LIST, if any.
+Returns the elements removed from the array.
+The array grows or shrinks as necessary.
+If LENGTH is omitted, removes everything from OFFSET onward.
+The following equivalencies hold (assuming $[ == 0):
+.nf
+
+ push(@a,$x,$y)\h'|3.5i'splice(@a,$#a+1,0,$x,$y)
+ pop(@a)\h'|3.5i'splice(@a,-1)
+ shift(@a)\h'|3.5i'splice(@a,0,1)
+ unshift(@a,$x,$y)\h'|3.5i'splice(@a,0,0,$x,$y)
+ $a[$x] = $y\h'|3.5i'splice(@a,$x,1,$y);
+
+Example, assuming array lengths are passed before arrays:
+
+ sub aeq { # compare two array values
+ local(@a) = splice(@_,0,shift);
+ local(@b) = splice(@_,0,shift);
+ return 0 unless @a == @b; # same len?
+ while (@a) {
+ return 0 if pop(@a) ne pop(@b);
+ }
+ return 1;
+ }
+ if (&aeq($len,@foo[1..$len],0+@bar,@bar)) { ... }
+
+.fi
+.Ip "split(/PATTERN/,EXPR,LIMIT)" 8 8
+.Ip "split(/PATTERN/,EXPR)" 8 8
+.Ip "split(/PATTERN/)" 8
+.Ip "split" 8
+Splits a string into an array of strings, and returns it.
+(If not in an array context, returns the number of fields found and splits
+into the @_ array.
+(In an array context, you can force the split into @_
+by using ?? as the pattern delimiters, but it still returns the array value.))
+If EXPR is omitted, splits the $_ string.
+If PATTERN is also omitted, splits on whitespace (/[\ \et\en]+/).
+Anything matching PATTERN is taken to be a delimiter separating the fields.
+(Note that the delimiter may be longer than one character.)
+If LIMIT is specified, splits into no more than that many fields (though it
+may split into fewer).
+If LIMIT is unspecified, trailing null fields are stripped (which
+potential users of pop() would do well to remember).
+A pattern matching the null string (not to be confused with a null pattern //,
+which is just one member of the set of patterns matching a null string)
+will split the value of EXPR into separate characters at each point it
+matches that way.
+For example:
+.nf
+
+ print join(\':\', split(/ */, \'hi there\'));
+
+.fi
+produces the output \*(L'h:i:t:h:e:r:e\*(R'.
+.Sp
+The LIMIT parameter can be used to partially split a line
+.nf
+
+ ($login, $passwd, $remainder) = split(\|/\|:\|/\|, $_, 3);
+
+.fi
+(When assigning to a list, if LIMIT is omitted, perl supplies a LIMIT one
+larger than the number of variables in the list, to avoid unnecessary work.
+For the list above LIMIT would have been 4 by default.
+In time critical applications it behooves you not to split into
+more fields than you really need.)
+.Sp
+If the PATTERN contains parentheses, additional array elements are created
+from each matching substring in the delimiter.
+.Sp
+ split(/([,-])/,"1-10,20");
+.Sp
+produces the array value
+.Sp
+ (1,'-',10,',',20)
+.Sp
+The pattern /PATTERN/ may be replaced with an expression to specify patterns
+that vary at runtime.
+(To do runtime compilation only once, use /$variable/o.)
+As a special case, specifying a space (\'\ \') will split on white space
+just as split with no arguments does, but leading white space does NOT
+produce a null first field.
+Thus, split(\'\ \') can be used to emulate
+.IR awk 's
+default behavior, whereas
+split(/\ /) will give you as many null initial fields as there are
+leading spaces.
+.Sp
+Example:
+.nf
+
+.ne 5
+ open(passwd, \'/etc/passwd\');
+ while (<passwd>) {
+.ie t \{\
+ ($login, $passwd, $uid, $gid, $gcos, $home, $shell) = split(\|/\|:\|/\|);
+'br\}
+.el \{\
+ ($login, $passwd, $uid, $gid, $gcos, $home, $shell)
+ = split(\|/\|:\|/\|);
+'br\}
+ .\|.\|.
+ }
+
+.fi
+(Note that $shell above will still have a newline on it. See chop().)
+See also
+.IR join .
+.Ip "sprintf(FORMAT,LIST)" 8 4
+Returns a string formatted by the usual printf conventions.
+The * character is not supported.
+.Ip "sqrt(EXPR)" 8 4
+.Ip "sqrt EXPR" 8
+Return the square root of EXPR.
+If EXPR is omitted, returns square root of $_.
+.Ip "srand(EXPR)" 8 4
+.Ip "srand EXPR" 8
+Sets the random number seed for the
+.I rand
+operator.
+If EXPR is omitted, does srand(time).
+.Ip "stat(FILEHANDLE)" 8 8
+.Ip "stat FILEHANDLE" 8
+.Ip "stat(EXPR)" 8
+.Ip "stat SCALARVARIABLE" 8
+Returns a 13-element array giving the statistics for a file, either the file
+opened via FILEHANDLE, or named by EXPR.
+Returns a null list if the stat fails.
+Typically used as follows:
+.nf
+
+.ne 3
+ ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,
+ $atime,$mtime,$ctime,$blksize,$blocks)
+ = stat($filename);
+
+.fi
+If stat is passed the special filehandle consisting of an underline,
+no stat is done, but the current contents of the stat structure from
+the last stat or filetest are returned.
+Example:
+.nf
+
+.ne 3
+ if (-x $file && (($d) = stat(_)) && $d < 0) {
+ print "$file is executable NFS file\en";
+ }
+
+.fi
+(This only works on machines for which the device number is negative under NFS.)
+.Ip "study(SCALAR)" 8 6
+.Ip "study SCALAR" 8
+.Ip "study"
+Takes extra time to study SCALAR ($_ if unspecified) in anticipation of
+doing many pattern matches on the string before it is next modified.
+This may or may not save time, depending on the nature and number of patterns
+you are searching on, and on the distribution of character frequencies in
+the string to be searched\*(--you probably want to compare runtimes with and
+without it to see which runs faster.
+Those loops which scan for many short constant strings (including the constant
+parts of more complex patterns) will benefit most.
+You may have only one study active at a time\*(--if you study a different
+scalar the first is \*(L"unstudied\*(R".
+(The way study works is this: a linked list of every character in the string
+to be searched is made, so we know, for example, where all the \*(L'k\*(R' characters
+are.
+From each search string, the rarest character is selected, based on some
+static frequency tables constructed from some C programs and English text.
+Only those places that contain this \*(L"rarest\*(R" character are examined.)
+.Sp
+For example, here is a loop which inserts index producing entries before any line
+containing a certain pattern:
+.nf
+
+.ne 8
+ while (<>) {
+ study;
+ print ".IX foo\en" if /\ebfoo\eb/;
+ print ".IX bar\en" if /\ebbar\eb/;
+ print ".IX blurfl\en" if /\ebblurfl\eb/;
+ .\|.\|.
+ print;
+ }
+
+.fi
+In searching for /\ebfoo\eb/, only those locations in $_ that contain \*(L'f\*(R'
+will be looked at, because \*(L'f\*(R' is rarer than \*(L'o\*(R'.
+In general, this is a big win except in pathological cases.
+The only question is whether it saves you more time than it took to build
+the linked list in the first place.
+.Sp
+Note that if you have to look for strings that you don't know till runtime,
+you can build an entire loop as a string and eval that to avoid recompiling
+all your patterns all the time.
+Together with undefining $/ to input entire files as one record, this can
+be very fast, often faster than specialized programs like fgrep.
+The following scans a list of files (@files)
+for a list of words (@words), and prints out the names of those files that
+contain a match:
+.nf
+
+.ne 12
+ $search = \'while (<>) { study;\';
+ foreach $word (@words) {
+ $search .= "++\e$seen{\e$ARGV} if /\e\eb$word\e\eb/;\en";
+ }
+ $search .= "}";
+ @ARGV = @files;
+ undef $/;
+ eval $search; # this screams
+ $/ = "\en"; # put back to normal input delim
+ foreach $file (sort keys(%seen)) {
+ print $file, "\en";
+ }
+
+.fi
+.Ip "substr(EXPR,OFFSET,LEN)" 8 2
+.Ip "substr(EXPR,OFFSET)" 8 2
+Extracts a substring out of EXPR and returns it.
+First character is at offset 0, or whatever you've set $[ to.
+If OFFSET is negative, starts that far from the end of the string.
+If LEN is omitted, returns everything to the end of the string.
+You can use the substr() function as an lvalue, in which case EXPR must
+be an lvalue.
+If you assign something shorter than LEN, the string will shrink, and
+if you assign something longer than LEN, the string will grow to accommodate it.
+To keep the string the same length you may need to pad or chop your value using
+sprintf().
+.Ip "symlink(OLDFILE,NEWFILE)" 8 2
+Creates a new filename symbolically linked to the old filename.
+Returns 1 for success, 0 otherwise.
+On systems that don't support symbolic links, produces a fatal error at
+run time.
+To check for that, use eval:
+.nf
+
+ $symlink_exists = (eval \'symlink("","");\', $@ eq \'\');
+
+.fi
+.Ip "syscall(LIST)" 8 6
+.Ip "syscall LIST" 8
+Calls the system call specified as the first element of the list, passing
+the remaining elements as arguments to the system call.
+If unimplemented, produces a fatal error.
+The arguments are interpreted as follows: if a given argument is numeric,
+the argument is passed as an int.
+If not, the pointer to the string value is passed.
+You are responsible to make sure a string is pre-extended long enough
+to receive any result that might be written into a string.
+If your integer arguments are not literals and have never been interpreted
+in a numeric context, you may need to add 0 to them to force them to look
+like numbers.
+.nf
+
+ require 'syscall.ph'; # may need to run h2ph
+ syscall(&SYS_write, fileno(STDOUT), "hi there\en", 9);
+
+.fi
+.Ip "sysread(FILEHANDLE,SCALAR,LENGTH,OFFSET)" 8 5
+.Ip "sysread(FILEHANDLE,SCALAR,LENGTH)" 8 5
+Attempts to read LENGTH bytes of data into variable SCALAR from the specified
+FILEHANDLE, using the system call read(2).
+It bypasses stdio, so mixing this with other kinds of reads may cause
+confusion.
+Returns the number of bytes actually read, or undef if there was an error.
+SCALAR will be grown or shrunk to the length actually read.
+An OFFSET may be specified to place the read data at some other place
+than the beginning of the string.
+.Ip "system(LIST)" 8 6
+.Ip "system LIST" 8
+Does exactly the same thing as \*(L"exec LIST\*(R" except that a fork
+is done first, and the parent process waits for the child process to complete.
+Note that argument processing varies depending on the number of arguments.
+The return value is the exit status of the program as returned by the wait()
+call.
+To get the actual exit value divide by 256.
+See also
+.IR exec .
+.Ip "syswrite(FILEHANDLE,SCALAR,LENGTH,OFFSET)" 8 5
+.Ip "syswrite(FILEHANDLE,SCALAR,LENGTH)" 8 5
+Attempts to write LENGTH bytes of data from variable SCALAR to the specified
+FILEHANDLE, using the system call write(2).
+It bypasses stdio, so mixing this with prints may cause
+confusion.
+Returns the number of bytes actually written, or undef if there was an error.
+An OFFSET may be specified to place the read data at some other place
+than the beginning of the string.
+.Ip "tell(FILEHANDLE)" 8 6
+.Ip "tell FILEHANDLE" 8 6
+.Ip "tell" 8
+Returns the current file position for FILEHANDLE.
+FILEHANDLE may be an expression whose value gives the name of the actual
+filehandle.
+If FILEHANDLE is omitted, assumes the file last read.
+.Ip "telldir(DIRHANDLE)" 8 5
+.Ip "telldir DIRHANDLE" 8
+Returns the current position of the readdir() routines on DIRHANDLE.
+Value may be given to seekdir() to access a particular location in
+a directory.
+Has the same caveats about possible directory compaction as the corresponding
+system library routine.
+.Ip "time" 8 4
+Returns the number of non-leap seconds since 00:00:00 UTC, January 1, 1970.
+Suitable for feeding to gmtime() and localtime().
+.Ip "times" 8 4
+Returns a four-element array giving the user and system times, in seconds, for this
+process and the children of this process.
+.Sp
+ ($user,$system,$cuser,$csystem) = times;
+.Sp
+.Ip "tr/SEARCHLIST/REPLACEMENTLIST/cds" 8 5
+.Ip "y/SEARCHLIST/REPLACEMENTLIST/cds" 8
+Translates all occurrences of the characters found in the search list with
+the corresponding character in the replacement list.
+It returns the number of characters replaced or deleted.
+If no string is specified via the =~ or !~ operator,
+the $_ string is translated.
+(The string specified with =~ must be a scalar variable, an array element,
+or an assignment to one of those, i.e. an lvalue.)
+For
+.I sed
+devotees,
+.I y
+is provided as a synonym for
+.IR tr .
+If the SEARCHLIST is delimited by bracketing quotes, the REPLACEMENTLIST
+has its own pair of quotes, which may or may not be bracketing quotes, e.g.
+tr[A-Z][a-z] or tr(+-*/)/ABCD/.
+.Sp
+If the c modifier is specified, the SEARCHLIST character set is complemented.
+If the d modifier is specified, any characters specified by SEARCHLIST that
+are not found in REPLACEMENTLIST are deleted.
+(Note that this is slightly more flexible than the behavior of some
+.I tr
+programs, which delete anything they find in the SEARCHLIST, period.)
+If the s modifier is specified, sequences of characters that were translated
+to the same character are squashed down to 1 instance of the character.
+.Sp
+If the d modifier was used, the REPLACEMENTLIST is always interpreted exactly
+as specified.
+Otherwise, if the REPLACEMENTLIST is shorter than the SEARCHLIST,
+the final character is replicated till it is long enough.
+If the REPLACEMENTLIST is null, the SEARCHLIST is replicated.
+This latter is useful for counting characters in a class, or for squashing
+character sequences in a class.
+.Sp
+Examples:
+.nf
+
+ $ARGV[1] \|=~ \|y/A\-Z/a\-z/; \h'|3i'# canonicalize to lower case
+
+ $cnt = tr/*/*/; \h'|3i'# count the stars in $_
+
+ $cnt = tr/0\-9//; \h'|3i'# count the digits in $_
+
+ tr/a\-zA\-Z//s; \h'|3i'# bookkeeper \-> bokeper
+
+ ($HOST = $host) =~ tr/a\-z/A\-Z/;
+
+ y/a\-zA\-Z/ /cs; \h'|3i'# change non-alphas to single space
+
+ tr/\e200\-\e377/\e0\-\e177/;\h'|3i'# delete 8th bit
+
+.fi
+.Ip "truncate(FILEHANDLE,LENGTH)" 8 4
+.Ip "truncate(EXPR,LENGTH)" 8
+Truncates the file opened on FILEHANDLE, or named by EXPR, to the specified
+length.
+Produces a fatal error if truncate isn't implemented on your system.
+.Ip "umask(EXPR)" 8 4
+.Ip "umask EXPR" 8
+.Ip "umask" 8
+Sets the umask for the process and returns the old one.
+If EXPR is omitted, merely returns current umask.
+.Ip "undef(EXPR)" 8 6
+.Ip "undef EXPR" 8
+.Ip "undef" 8
+Undefines the value of EXPR, which must be an lvalue.
+Use only on a scalar value, an entire array, or a subroutine name (using &).
+(Undef will probably not do what you expect on most predefined variables or
+dbm array values.)
+Always returns the undefined value.
+You can omit the EXPR, in which case nothing is undefined, but you still
+get an undefined value that you could, for instance, return from a subroutine.
+Examples:
+.nf
+
+.ne 6
+ undef $foo;
+ undef $bar{'blurfl'};
+ undef @ary;
+ undef %assoc;
+ undef &mysub;
+ return (wantarray ? () : undef) if $they_blew_it;
+
+.fi
+.Ip "unlink(LIST)" 8 4
+.Ip "unlink LIST" 8
+Deletes a list of files.
+Returns the number of files successfully deleted.
+.nf
+
+.ne 2
+ $cnt = unlink \'a\', \'b\', \'c\';
+ unlink @goners;
+ unlink <*.bak>;
+
+.fi
+Note: unlink will not delete directories unless you are superuser and the
+.B \-U
+flag is supplied to
+.IR perl .
+Even if these conditions are met, be warned that unlinking a directory
+can inflict damage on your filesystem.
+Use rmdir instead.
+.Ip "unpack(TEMPLATE,EXPR)" 8 4
+Unpack does the reverse of pack: it takes a string representing
+a structure and expands it out into an array value, returning the array
+value.
+(In a scalar context, it merely returns the first value produced.)
+The TEMPLATE has the same format as in the pack function.
+Here's a subroutine that does substring:
+.nf
+
+.ne 4
+ sub substr {
+ local($what,$where,$howmuch) = @_;
+ unpack("x$where a$howmuch", $what);
+ }
+
+.ne 3
+and then there's
+
+ sub ord { unpack("c",$_[0]); }
+
+.fi
+In addition, you may prefix a field with a %<number> to indicate that
+you want a <number>-bit checksum of the items instead of the items themselves.
+Default is a 16-bit checksum.
+For example, the following computes the same number as the System V sum program:
+.nf
+
+.ne 4
+ while (<>) {
+ $checksum += unpack("%16C*", $_);
+ }
+ $checksum %= 65536;
+
+.fi
+.Ip "unshift(ARRAY,LIST)" 8 4
+Does the opposite of a
+.IR shift .
+Or the opposite of a
+.IR push ,
+depending on how you look at it.
+Prepends list to the front of the array, and returns the number of elements
+in the new array.
+.nf
+
+ unshift(ARGV, \'\-e\') unless $ARGV[0] =~ /^\-/;
+
+.fi
+.Ip "utime(LIST)" 8 2
+.Ip "utime LIST" 8 2
+Changes the access and modification times on each file of a list of files.
+The first two elements of the list must be the NUMERICAL access and
+modification times, in that order.
+Returns the number of files successfully changed.
+The inode modification time of each file is set to the current time.
+Example of a \*(L"touch\*(R" command:
+.nf
+
+.ne 3
+ #!/usr/bin/perl
+ $now = time;
+ utime $now, $now, @ARGV;
+
+.fi
+.Ip "values(ASSOC_ARRAY)" 8 6
+.Ip "values ASSOC_ARRAY" 8
+Returns a normal array consisting of all the values of the named associative
+array.
+The values are returned in an apparently random order, but it is the same order
+as either the keys() or each() function would produce on the same array.
+See also keys() and each().
+.Ip "vec(EXPR,OFFSET,BITS)" 8 2
+Treats a string as a vector of unsigned integers, and returns the value
+of the bitfield specified.
+May also be assigned to.
+BITS must be a power of two from 1 to 32.
+.Sp
+Vectors created with vec() can also be manipulated with the logical operators
+|, & and ^,
+which will assume a bit vector operation is desired when both operands are
+strings.
+This interpretation is not enabled unless there is at least one vec() in
+your program, to protect older programs.
+.Sp
+To transform a bit vector into a string or array of 0's and 1's, use these:
+.nf
+
+ $bits = unpack("b*", $vector);
+ @bits = split(//, unpack("b*", $vector));
+
+.fi
+If you know the exact length in bits, it can be used in place of the *.
+.Ip "wait" 8 6
+Waits for a child process to terminate and returns the pid of the deceased
+process, or -1 if there are no child processes.
+The status is returned in $?.
+.Ip "waitpid(PID,FLAGS)" 8 6
+Waits for a particular child process to terminate and returns the pid of the deceased
+process, or -1 if there is no such child process.
+The status is returned in $?.
+If you say
+.nf
+
+ require "sys/wait.h";
+ .\|.\|.
+ waitpid(-1,&WNOHANG);
+
+.fi
+then you can do a non-blocking wait for any process. Non-blocking wait
+is only available on machines supporting either the
+.I waitpid (2)
+or
+.I wait4 (2)
+system calls.
+However, waiting for a particular pid with FLAGS of 0 is implemented
+everywhere. (Perl emulates the system call by remembering the status
+values of processes that have exited but have not been harvested by the
+Perl script yet.)
+.Ip "wantarray" 8 4
+Returns true if the context of the currently executing subroutine
+is looking for an array value.
+Returns false if the context is looking for a scalar.
+.nf
+
+ return wantarray ? () : undef;
+
+.fi
+.Ip "warn(LIST)" 8 4
+.Ip "warn LIST" 8
+Produces a message on STDERR just like \*(L"die\*(R", but doesn't exit.
+.Ip "write(FILEHANDLE)" 8 6
+.Ip "write(EXPR)" 8
+.Ip "write" 8
+Writes a formatted record (possibly multi-line) to the specified file,
+using the format associated with that file.
+By default the format for a file is the one having the same name is the
+filehandle, but the format for the current output channel (see
+.IR select )
+may be set explicitly
+by assigning the name of the format to the $~ variable.
+.Sp
+Top of form processing is handled automatically:
+if there is insufficient room on the current page for the formatted
+record, the page is advanced by writing a form feed,
+a special top-of-page format is used
+to format the new page header, and then the record is written.
+By default the top-of-page format is the name of the filehandle with
+\*(L"_TOP\*(R" appended, but it may be dynamicallly set to the
+format of your choice by assigning the name to the $^ variable while
+the filehandle is selected.
+The number of lines remaining on the current page is in variable $-, which
+can be set to 0 to force a new page.
+.Sp
+If FILEHANDLE is unspecified, output goes to the current default output channel,
+which starts out as
+.I STDOUT
+but may be changed by the
+.I select
+operator.
+If the FILEHANDLE is an EXPR, then the expression is evaluated and the
+resulting string is used to look up the name of the FILEHANDLE at run time.
+For more on formats, see the section on formats later on.
+.Sp
+Note that write is NOT the opposite of read.
+.Sh "Precedence"
+.I Perl
+operators have the following associativity and precedence:
+.nf
+
+nonassoc\h'|1i'print printf exec system sort reverse
+\h'1.5i'chmod chown kill unlink utime die return
+left\h'|1i',
+right\h'|1i'= += \-= *= etc.
+right\h'|1i'?:
+nonassoc\h'|1i'.\|.
+left\h'|1i'||
+left\h'|1i'&&
+left\h'|1i'| ^
+left\h'|1i'&
+nonassoc\h'|1i'== != <=> eq ne cmp
+nonassoc\h'|1i'< > <= >= lt gt le ge
+nonassoc\h'|1i'chdir exit eval reset sleep rand umask
+nonassoc\h'|1i'\-r \-w \-x etc.
+left\h'|1i'<< >>
+left\h'|1i'+ \- .
+left\h'|1i'* / % x
+left\h'|1i'=~ !~
+right\h'|1i'! ~ and unary minus
+right\h'|1i'**
+nonassoc\h'|1i'++ \-\|\-
+left\h'|1i'\*(L'(\*(R'
+
+.fi
+As mentioned earlier, if any list operator (print, etc.) or
+any unary operator (chdir, etc.)
+is followed by a left parenthesis as the next token on the same line,
+the operator and arguments within parentheses are taken to
+be of highest precedence, just like a normal function call.
+Examples:
+.nf
+
+ chdir $foo || die;\h'|3i'# (chdir $foo) || die
+ chdir($foo) || die;\h'|3i'# (chdir $foo) || die
+ chdir ($foo) || die;\h'|3i'# (chdir $foo) || die
+ chdir +($foo) || die;\h'|3i'# (chdir $foo) || die
+
+but, because * is higher precedence than ||:
+
+ chdir $foo * 20;\h'|3i'# chdir ($foo * 20)
+ chdir($foo) * 20;\h'|3i'# (chdir $foo) * 20
+ chdir ($foo) * 20;\h'|3i'# (chdir $foo) * 20
+ chdir +($foo) * 20;\h'|3i'# chdir ($foo * 20)
+
+ rand 10 * 20;\h'|3i'# rand (10 * 20)
+ rand(10) * 20;\h'|3i'# (rand 10) * 20
+ rand (10) * 20;\h'|3i'# (rand 10) * 20
+ rand +(10) * 20;\h'|3i'# rand (10 * 20)
+
+.fi
+In the absence of parentheses,
+the precedence of list operators such as print, sort or chmod is
+either very high or very low depending on whether you look at the left
+side of operator or the right side of it.
+For example, in
+.nf
+
+ @ary = (1, 3, sort 4, 2);
+ print @ary; # prints 1324
+
+.fi
+the commas on the right of the sort are evaluated before the sort, but
+the commas on the left are evaluated after.
+In other words, list operators tend to gobble up all the arguments that
+follow them, and then act like a simple term with regard to the preceding
+expression.
+Note that you have to be careful with parens:
+.nf
+
+.ne 3
+ # These evaluate exit before doing the print:
+ print($foo, exit); # Obviously not what you want.
+ print $foo, exit; # Nor is this.
+
+.ne 4
+ # These do the print before evaluating exit:
+ (print $foo), exit; # This is what you want.
+ print($foo), exit; # Or this.
+ print ($foo), exit; # Or even this.
+
+Also note that
+
+ print ($foo & 255) + 1, "\en";
+
+.fi
+probably doesn't do what you expect at first glance.
+.Sh "Subroutines"
+A subroutine may be declared as follows:
+.nf
+
+ sub NAME BLOCK
+
+.fi
+.PP
+Any arguments passed to the routine come in as array @_,
+that is ($_[0], $_[1], .\|.\|.).
+The array @_ is a local array, but its values are references to the
+actual scalar parameters.
+The return value of the subroutine is the value of the last expression
+evaluated, and can be either an array value or a scalar value.
+Alternately, a return statement may be used to specify the returned value and
+exit the subroutine.
+To create local variables see the
+.I local
+operator.
+.PP
+A subroutine is called using the
+.I do
+operator or the & operator.
+.nf
+
+.ne 12
+Example:
+
+ sub MAX {
+ local($max) = pop(@_);
+ foreach $foo (@_) {
+ $max = $foo \|if \|$max < $foo;
+ }
+ $max;
+ }
+
+ .\|.\|.
+ $bestday = &MAX($mon,$tue,$wed,$thu,$fri);
+
+.ne 21
+Example:
+
+ # get a line, combining continuation lines
+ # that start with whitespace
+ sub get_line {
+ $thisline = $lookahead;
+ line: while ($lookahead = <STDIN>) {
+ if ($lookahead \|=~ \|/\|^[ \^\e\|t]\|/\|) {
+ $thisline \|.= \|$lookahead;
+ }
+ else {
+ last line;
+ }
+ }
+ $thisline;
+ }
+
+ $lookahead = <STDIN>; # get first line
+ while ($_ = do get_line(\|)) {
+ .\|.\|.
+ }
+
+.fi
+.nf
+.ne 6
+Use array assignment to a local list to name your formal arguments:
+
+ sub maybeset {
+ local($key, $value) = @_;
+ $foo{$key} = $value unless $foo{$key};
+ }
+
+.fi
+This also has the effect of turning call-by-reference into call-by-value,
+since the assignment copies the values.
+.Sp
+Subroutines may be called recursively.
+If a subroutine is called using the & form, the argument list is optional.
+If omitted, no @_ array is set up for the subroutine; the @_ array at the
+time of the call is visible to subroutine instead.
+.nf
+
+ do foo(1,2,3); # pass three arguments
+ &foo(1,2,3); # the same
+
+ do foo(); # pass a null list
+ &foo(); # the same
+ &foo; # pass no arguments\*(--more efficient
+
+.fi
+.Sh "Passing By Reference"
+Sometimes you don't want to pass the value of an array to a subroutine but
+rather the name of it, so that the subroutine can modify the global copy
+of it rather than working with a local copy.
+In perl you can refer to all the objects of a particular name by prefixing
+the name with a star: *foo.
+When evaluated, it produces a scalar value that represents all the objects
+of that name, including any filehandle, format or subroutine.
+When assigned to within a local() operation, it causes the name mentioned
+to refer to whatever * value was assigned to it.
+Example:
+.nf
+
+ sub doubleary {
+ local(*someary) = @_;
+ foreach $elem (@someary) {
+ $elem *= 2;
+ }
+ }
+ do doubleary(*foo);
+ do doubleary(*bar);
+
+.fi
+Assignment to *name is currently recommended only inside a local().
+You can actually assign to *name anywhere, but the previous referent of
+*name may be stranded forever.
+This may or may not bother you.
+.Sp
+Note that scalars are already passed by reference, so you can modify scalar
+arguments without using this mechanism by referring explicitly to the $_[nnn]
+in question.
+You can modify all the elements of an array by passing all the elements
+as scalars, but you have to use the * mechanism to push, pop or change the
+size of an array.
+The * mechanism will probably be more efficient in any case.
+.Sp
+Since a *name value contains unprintable binary data, if it is used as
+an argument in a print, or as a %s argument in a printf or sprintf, it
+then has the value '*name', just so it prints out pretty.
+.Sp
+Even if you don't want to modify an array, this mechanism is useful for
+passing multiple arrays in a single LIST, since normally the LIST mechanism
+will merge all the array values so that you can't extract out the
+individual arrays.
+.Sh "Regular Expressions"
+The patterns used in pattern matching are regular expressions such as
+those supplied in the Version 8 regexp routines.
+(In fact, the routines are derived from Henry Spencer's freely redistributable
+reimplementation of the V8 routines.)
+In addition, \ew matches an alphanumeric character (including \*(L"_\*(R") and \eW a nonalphanumeric.
+Word boundaries may be matched by \eb, and non-boundaries by \eB.
+A whitespace character is matched by \es, non-whitespace by \eS.
+A numeric character is matched by \ed, non-numeric by \eD.
+You may use \ew, \es and \ed within character classes.
+Also, \en, \er, \ef, \et and \eNNN have their normal interpretations.
+Within character classes \eb represents backspace rather than a word boundary.
+Alternatives may be separated by |.
+The bracketing construct \|(\ .\|.\|.\ \|) may also be used, in which case \e<digit>
+matches the digit'th substring.
+(Outside of the pattern, always use $ instead of \e in front of the digit.
+The scope of $<digit> (and $\`, $& and $\')
+extends to the end of the enclosing BLOCK or eval string, or to
+the next pattern match with subexpressions.
+The \e<digit> notation sometimes works outside the current pattern, but should
+not be relied upon.)
+You may have as many parentheses as you wish. If you have more than 9
+substrings, the variables $10, $11, ... refer to the corresponding
+substring. Within the pattern, \e10, \e11,
+etc. refer back to substrings if there have been at least that many left parens
+before the backreference. Otherwise (for backward compatibilty) \e10
+is the same as \e010, a backspace,
+and \e11 the same as \e011, a tab.
+And so on.
+(\e1 through \e9 are always backreferences.)
+.PP
+$+ returns whatever the last bracket match matched.
+$& returns the entire matched string.
+($0 used to return the same thing, but not any more.)
+$\` returns everything before the matched string.
+$\' returns everything after the matched string.
+Examples:
+.nf
+
+ s/\|^\|([^ \|]*\|) \|*([^ \|]*\|)\|/\|$2 $1\|/; # swap first two words
+
+.ne 5
+ if (/\|Time: \|(.\|.\|):\|(.\|.\|):\|(.\|.\|)\|/\|) {
+ $hours = $1;
+ $minutes = $2;
+ $seconds = $3;
+ }
+
+.fi
+By default, the ^ character is only guaranteed to match at the beginning
+of the string,
+the $ character only at the end (or before the newline at the end)
+and
+.I perl
+does certain optimizations with the assumption that the string contains
+only one line.
+The behavior of ^ and $ on embedded newlines will be inconsistent.
+You may, however, wish to treat a string as a multi-line buffer, such that
+the ^ will match after any newline within the string, and $ will match
+before any newline.
+At the cost of a little more overhead, you can do this by setting the variable
+$* to 1.
+Setting it back to 0 makes
+.I perl
+revert to its old behavior.
+.PP
+To facilitate multi-line substitutions, the . character never matches a newline
+(even when $* is 0).
+In particular, the following leaves a newline on the $_ string:
+.nf
+
+ $_ = <STDIN>;
+ s/.*(some_string).*/$1/;
+
+If the newline is unwanted, try one of
+
+ s/.*(some_string).*\en/$1/;
+ s/.*(some_string)[^\e000]*/$1/;
+ s/.*(some_string)(.|\en)*/$1/;
+ chop; s/.*(some_string).*/$1/;
+ /(some_string)/ && ($_ = $1);
+
+.fi
+Any item of a regular expression may be followed with digits in curly brackets
+of the form {n,m}, where n gives the minimum number of times to match the item
+and m gives the maximum.
+The form {n} is equivalent to {n,n} and matches exactly n times.
+The form {n,} matches n or more times.
+(If a curly bracket occurs in any other context, it is treated as a regular
+character.)
+The * modifier is equivalent to {0,}, the + modifier to {1,} and the ? modifier
+to {0,1}.
+There is no limit to the size of n or m, but large numbers will chew up
+more memory.
+.Sp
+You will note that all backslashed metacharacters in
+.I perl
+are alphanumeric,
+such as \eb, \ew, \en.
+Unlike some other regular expression languages, there are no backslashed
+symbols that aren't alphanumeric.
+So anything that looks like \e\e, \e(, \e), \e<, \e>, \e{, or \e} is always
+interpreted as a literal character, not a metacharacter.
+This makes it simple to quote a string that you want to use for a pattern
+but that you are afraid might contain metacharacters.
+Simply quote all the non-alphanumeric characters:
+.nf
+
+ $pattern =~ s/(\eW)/\e\e$1/g;
+
+.fi
+.Sh "Formats"
+Output record formats for use with the
+.I write
+operator may declared as follows:
+.nf
+
+.ne 3
+ format NAME =
+ FORMLIST
+ .
+
+.fi
+If name is omitted, format \*(L"STDOUT\*(R" is defined.
+FORMLIST consists of a sequence of lines, each of which may be of one of three
+types:
+.Ip 1. 4
+A comment.
+.Ip 2. 4
+A \*(L"picture\*(R" line giving the format for one output line.
+.Ip 3. 4
+An argument line supplying values to plug into a picture line.
+.PP
+Picture lines are printed exactly as they look, except for certain fields
+that substitute values into the line.
+Each picture field starts with either @ or ^.
+The @ field (not to be confused with the array marker @) is the normal
+case; ^ fields are used
+to do rudimentary multi-line text block filling.
+The length of the field is supplied by padding out the field
+with multiple <, >, or | characters to specify, respectively, left justification,
+right justification, or centering.
+As an alternate form of right justification,
+you may also use # characters (with an optional .) to specify a numeric field.
+(Use of ^ instead of @ causes the field to be blanked if undefined.)
+If any of the values supplied for these fields contains a newline, only
+the text up to the newline is printed.
+The special field @* can be used for printing multi-line values.
+It should appear by itself on a line.
+.PP
+The values are specified on the following line, in the same order as
+the picture fields.
+The values should be separated by commas.
+.PP
+Picture fields that begin with ^ rather than @ are treated specially.
+The value supplied must be a scalar variable name which contains a text
+string.
+.I Perl
+puts as much text as it can into the field, and then chops off the front
+of the string so that the next time the variable is referenced,
+more of the text can be printed.
+Normally you would use a sequence of fields in a vertical stack to print
+out a block of text.
+If you like, you can end the final field with .\|.\|., which will appear in the
+output if the text was too long to appear in its entirety.
+You can change which characters are legal to break on by changing the
+variable $: to a list of the desired characters.
+.PP
+Since use of ^ fields can produce variable length records if the text to be
+formatted is short, you can suppress blank lines by putting the tilde (~)
+character anywhere in the line.
+(Normally you should put it in the front if possible, for visibility.)
+The tilde will be translated to a space upon output.
+If you put a second tilde contiguous to the first, the line will be repeated
+until all the fields on the line are exhausted.
+(If you use a field of the @ variety, the expression you supply had better
+not give the same value every time forever!)
+.PP
+Examples:
+.nf
+.lg 0
+.cs R 25
+.ft C
+
+.ne 10
+# a report on the /etc/passwd file
+format STDOUT_TOP =
+\& Passwd File
+Name Login Office Uid Gid Home
+------------------------------------------------------------------
+\&.
+format STDOUT =
+@<<<<<<<<<<<<<<<<<< @||||||| @<<<<<<@>>>> @>>>> @<<<<<<<<<<<<<<<<<
+$name, $login, $office,$uid,$gid, $home
+\&.
+
+.ne 29
+# a report from a bug report form
+format STDOUT_TOP =
+\& Bug Reports
+@<<<<<<<<<<<<<<<<<<<<<<< @||| @>>>>>>>>>>>>>>>>>>>>>>>
+$system, $%, $date
+------------------------------------------------------------------
+\&.
+format STDOUT =
+Subject: @<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
+\& $subject
+Index: @<<<<<<<<<<<<<<<<<<<<<<<<<<<< ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<
+\& $index, $description
+Priority: @<<<<<<<<<< Date: @<<<<<<< ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<
+\& $priority, $date, $description
+From: @<<<<<<<<<<<<<<<<<<<<<<<<<<<<< ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<
+\& $from, $description
+Assigned to: @<<<<<<<<<<<<<<<<<<<<<< ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<
+\& $programmer, $description
+\&~ ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<
+\& $description
+\&~ ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<
+\& $description
+\&~ ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<
+\& $description
+\&~ ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<
+\& $description
+\&~ ^<<<<<<<<<<<<<<<<<<<<<<<...
+\& $description
+\&.
+
+.ft R
+.cs R
+.lg
+.fi
+It is possible to intermix prints with writes on the same output channel,
+but you'll have to handle $\- (lines left on the page) yourself.
+.PP
+If you are printing lots of fields that are usually blank, you should consider
+using the reset operator between records.
+Not only is it more efficient, but it can prevent the bug of adding another
+field and forgetting to zero it.
+.Sh "Interprocess Communication"
+The IPC facilities of perl are built on the Berkeley socket mechanism.
+If you don't have sockets, you can ignore this section.
+The calls have the same names as the corresponding system calls,
+but the arguments tend to differ, for two reasons.
+First, perl file handles work differently than C file descriptors.
+Second, perl already knows the length of its strings, so you don't need
+to pass that information.
+Here is a sample client (untested):
+.nf
+
+ ($them,$port) = @ARGV;
+ $port = 2345 unless $port;
+ $them = 'localhost' unless $them;
+
+ $SIG{'INT'} = 'dokill';
+ sub dokill { kill 9,$child if $child; }
+
+ require 'sys/socket.ph';
+
+ $sockaddr = 'S n a4 x8';
+ chop($hostname = `hostname`);
+
+ ($name, $aliases, $proto) = getprotobyname('tcp');
+ ($name, $aliases, $port) = getservbyname($port, 'tcp')
+ unless $port =~ /^\ed+$/;
+.ie t \{\
+ ($name, $aliases, $type, $len, $thisaddr) = gethostbyname($hostname);
+'br\}
+.el \{\
+ ($name, $aliases, $type, $len, $thisaddr) =
+ gethostbyname($hostname);
+'br\}
+ ($name, $aliases, $type, $len, $thataddr) = gethostbyname($them);
+
+ $this = pack($sockaddr, &AF_INET, 0, $thisaddr);
+ $that = pack($sockaddr, &AF_INET, $port, $thataddr);
+
+ socket(S, &PF_INET, &SOCK_STREAM, $proto) || die "socket: $!";
+ bind(S, $this) || die "bind: $!";
+ connect(S, $that) || die "connect: $!";
+
+ select(S); $| = 1; select(stdout);
+
+ if ($child = fork) {
+ while (<>) {
+ print S;
+ }
+ sleep 3;
+ do dokill();
+ }
+ else {
+ while (<S>) {
+ print;
+ }
+ }
+
+.fi
+And here's a server:
+.nf
+
+ ($port) = @ARGV;
+ $port = 2345 unless $port;
+
+ require 'sys/socket.ph';
+
+ $sockaddr = 'S n a4 x8';
+
+ ($name, $aliases, $proto) = getprotobyname('tcp');
+ ($name, $aliases, $port) = getservbyname($port, 'tcp')
+ unless $port =~ /^\ed+$/;
+
+ $this = pack($sockaddr, &AF_INET, $port, "\e0\e0\e0\e0");
+
+ select(NS); $| = 1; select(stdout);
+
+ socket(S, &PF_INET, &SOCK_STREAM, $proto) || die "socket: $!";
+ bind(S, $this) || die "bind: $!";
+ listen(S, 5) || die "connect: $!";
+
+ select(S); $| = 1; select(stdout);
+
+ for (;;) {
+ print "Listening again\en";
+ ($addr = accept(NS,S)) || die $!;
+ print "accept ok\en";
+
+ ($af,$port,$inetaddr) = unpack($sockaddr,$addr);
+ @inetaddr = unpack('C4',$inetaddr);
+ print "$af $port @inetaddr\en";
+
+ while (<NS>) {
+ print;
+ print NS;
+ }
+ }
+
+.fi
+.Sh "Predefined Names"
+The following names have special meaning to
+.IR perl .
+I could have used alphabetic symbols for some of these, but I didn't want
+to take the chance that someone would say reset \*(L"a\-zA\-Z\*(R" and wipe them all
+out.
+You'll just have to suffer along with these silly symbols.
+Most of them have reasonable mnemonics, or analogues in one of the shells.
+.Ip $_ 8
+The default input and pattern-searching space.
+The following pairs are equivalent:
+.nf
+
+.ne 2
+ while (<>) {\|.\|.\|. # only equivalent in while!
+ while ($_ = <>) {\|.\|.\|.
+
+.ne 2
+ /\|^Subject:/
+ $_ \|=~ \|/\|^Subject:/
+
+.ne 2
+ y/a\-z/A\-Z/
+ $_ =~ y/a\-z/A\-Z/
+
+.ne 2
+ chop
+ chop($_)
+
+.fi
+(Mnemonic: underline is understood in certain operations.)
+.Ip $. 8
+The current input line number of the last filehandle that was read.
+Readonly.
+Remember that only an explicit close on the filehandle resets the line number.
+Since <> never does an explicit close, line numbers increase across ARGV files
+(but see examples under eof).
+(Mnemonic: many programs use . to mean the current line number.)
+.Ip $/ 8
+The input record separator, newline by default.
+Works like
+.IR awk 's
+RS variable, including treating blank lines as delimiters
+if set to the null string.
+You may set it to a multicharacter string to match a multi-character
+delimiter.
+Note that setting it to "\en\en" means something slightly different
+than setting it to "", if the file contains consecutive blank lines.
+Setting it to "" will treat two or more consecutive blank lines as a single
+blank line.
+Setting it to "\en\en" will blindly assume that the next input character
+belongs to the next paragraph, even if it's a newline.
+(Mnemonic: / is used to delimit line boundaries when quoting poetry.)
+.Ip $, 8
+The output field separator for the print operator.
+Ordinarily the print operator simply prints out the comma separated fields
+you specify.
+In order to get behavior more like
+.IR awk ,
+set this variable as you would set
+.IR awk 's
+OFS variable to specify what is printed between fields.
+(Mnemonic: what is printed when there is a , in your print statement.)
+.Ip $"" 8
+This is like $, except that it applies to array values interpolated into
+a double-quoted string (or similar interpreted string).
+Default is a space.
+(Mnemonic: obvious, I think.)
+.Ip $\e 8
+The output record separator for the print operator.
+Ordinarily the print operator simply prints out the comma separated fields
+you specify, with no trailing newline or record separator assumed.
+In order to get behavior more like
+.IR awk ,
+set this variable as you would set
+.IR awk 's
+ORS variable to specify what is printed at the end of the print.
+(Mnemonic: you set $\e instead of adding \en at the end of the print.
+Also, it's just like /, but it's what you get \*(L"back\*(R" from
+.IR perl .)
+.Ip $# 8
+The output format for printed numbers.
+This variable is a half-hearted attempt to emulate
+.IR awk 's
+OFMT variable.
+There are times, however, when
+.I awk
+and
+.I perl
+have differing notions of what
+is in fact numeric.
+Also, the initial value is %.20g rather than %.6g, so you need to set $#
+explicitly to get
+.IR awk 's
+value.
+(Mnemonic: # is the number sign.)
+.Ip $% 8
+The current page number of the currently selected output channel.
+(Mnemonic: % is page number in nroff.)
+.Ip $= 8
+The current page length (printable lines) of the currently selected output
+channel.
+Default is 60.
+(Mnemonic: = has horizontal lines.)
+.Ip $\- 8
+The number of lines left on the page of the currently selected output channel.
+(Mnemonic: lines_on_page \- lines_printed.)
+.Ip $~ 8
+The name of the current report format for the currently selected output
+channel.
+Default is name of the filehandle.
+(Mnemonic: brother to $^.)
+.Ip $^ 8
+The name of the current top-of-page format for the currently selected output
+channel.
+Default is name of the filehandle with \*(L"_TOP\*(R" appended.
+(Mnemonic: points to top of page.)
+.Ip $| 8
+If set to nonzero, forces a flush after every write or print on the currently
+selected output channel.
+Default is 0.
+Note that
+.I STDOUT
+will typically be line buffered if output is to the
+terminal and block buffered otherwise.
+Setting this variable is useful primarily when you are outputting to a pipe,
+such as when you are running a
+.I perl
+script under rsh and want to see the
+output as it's happening.
+(Mnemonic: when you want your pipes to be piping hot.)
+.Ip $$ 8
+The process number of the
+.I perl
+running this script.
+(Mnemonic: same as shells.)
+.Ip $? 8
+The status returned by the last pipe close, backtick (\`\`) command or
+.I system
+operator.
+Note that this is the status word returned by the wait() system
+call, so the exit value of the subprocess is actually ($? >> 8).
+$? & 255 gives which signal, if any, the process died from, and whether
+there was a core dump.
+(Mnemonic: similar to sh and ksh.)
+.Ip $& 8 4
+The string matched by the last successful pattern match
+(not counting any matches hidden
+within a BLOCK or eval enclosed by the current BLOCK).
+(Mnemonic: like & in some editors.)
+.Ip $\` 8 4
+The string preceding whatever was matched by the last successful pattern match
+(not counting any matches hidden within a BLOCK or eval enclosed by the current
+BLOCK).
+(Mnemonic: \` often precedes a quoted string.)
+.Ip $\' 8 4
+The string following whatever was matched by the last successful pattern match
+(not counting any matches hidden within a BLOCK or eval enclosed by the current
+BLOCK).
+(Mnemonic: \' often follows a quoted string.)
+Example:
+.nf
+
+.ne 3
+ $_ = \'abcdefghi\';
+ /def/;
+ print "$\`:$&:$\'\en"; # prints abc:def:ghi
+
+.fi
+.Ip $+ 8 4
+The last bracket matched by the last search pattern.
+This is useful if you don't know which of a set of alternative patterns
+matched.
+For example:
+.nf
+
+ /Version: \|(.*\|)|Revision: \|(.*\|)\|/ \|&& \|($rev = $+);
+
+.fi
+(Mnemonic: be positive and forward looking.)
+.Ip $* 8 2
+Set to 1 to do multiline matching within a string, 0 to tell
+.I perl
+that it can assume that strings contain a single line, for the purpose
+of optimizing pattern matches.
+Pattern matches on strings containing multiple newlines can produce confusing
+results when $* is 0.
+Default is 0.
+(Mnemonic: * matches multiple things.)
+Note that this variable only influences the interpretation of ^ and $.
+A literal newline can be searched for even when $* == 0.
+.Ip $0 8
+Contains the name of the file containing the
+.I perl
+script being executed.
+Assigning to $0 modifies the argument area that the ps(1) program sees.
+(Mnemonic: same as sh and ksh.)
+.Ip $<digit> 8
+Contains the subpattern from the corresponding set of parentheses in the last
+pattern matched, not counting patterns matched in nested blocks that have
+been exited already.
+(Mnemonic: like \edigit.)
+.Ip $[ 8 2
+The index of the first element in an array, and of the first character in
+a substring.
+Default is 0, but you could set it to 1 to make
+.I perl
+behave more like
+.I awk
+(or Fortran)
+when subscripting and when evaluating the index() and substr() functions.
+(Mnemonic: [ begins subscripts.)
+.Ip $] 8 2
+The string printed out when you say \*(L"perl -v\*(R".
+It can be used to determine at the beginning of a script whether the perl
+interpreter executing the script is in the right range of versions.
+If used in a numeric context, returns the version + patchlevel / 1000.
+Example:
+.nf
+
+.ne 8
+ # see if getc is available
+ ($version,$patchlevel) =
+ $] =~ /(\ed+\e.\ed+).*\enPatch level: (\ed+)/;
+ print STDERR "(No filename completion available.)\en"
+ if $version * 1000 + $patchlevel < 2016;
+
+or, used numerically,
+
+ warn "No checksumming!\en" if $] < 3.019;
+
+.fi
+(Mnemonic: Is this version of perl in the right bracket?)
+.Ip $; 8 2
+The subscript separator for multi-dimensional array emulation.
+If you refer to an associative array element as
+.nf
+ $foo{$a,$b,$c}
+
+it really means
+
+ $foo{join($;, $a, $b, $c)}
+
+But don't put
+
+ @foo{$a,$b,$c} # a slice\*(--note the @
+
+which means
+
+ ($foo{$a},$foo{$b},$foo{$c})
+
+.fi
+Default is "\e034", the same as SUBSEP in
+.IR awk .
+Note that if your keys contain binary data there might not be any safe
+value for $;.
+(Mnemonic: comma (the syntactic subscript separator) is a semi-semicolon.
+Yeah, I know, it's pretty lame, but $, is already taken for something more
+important.)
+.Ip $! 8 2
+If used in a numeric context, yields the current value of errno, with all the
+usual caveats.
+(This means that you shouldn't depend on the value of $! to be anything
+in particular unless you've gotten a specific error return indicating a
+system error.)
+If used in a string context, yields the corresponding system error string.
+You can assign to $! in order to set errno
+if, for instance, you want $! to return the string for error n, or you want
+to set the exit value for the die operator.
+(Mnemonic: What just went bang?)
+.Ip $@ 8 2
+The perl syntax error message from the last eval command.
+If null, the last eval parsed and executed correctly (although the operations
+you invoked may have failed in the normal fashion).
+(Mnemonic: Where was the syntax error \*(L"at\*(R"?)
+.Ip $< 8 2
+The real uid of this process.
+(Mnemonic: it's the uid you came FROM, if you're running setuid.)
+.Ip $> 8 2
+The effective uid of this process.
+Example:
+.nf
+
+.ne 2
+ $< = $>; # set real uid to the effective uid
+ ($<,$>) = ($>,$<); # swap real and effective uid
+
+.fi
+(Mnemonic: it's the uid you went TO, if you're running setuid.)
+Note: $< and $> can only be swapped on machines supporting setreuid().
+.Ip $( 8 2
+The real gid of this process.
+If you are on a machine that supports membership in multiple groups
+simultaneously, gives a space separated list of groups you are in.
+The first number is the one returned by getgid(), and the subsequent ones
+by getgroups(), one of which may be the same as the first number.
+(Mnemonic: parentheses are used to GROUP things.
+The real gid is the group you LEFT, if you're running setgid.)
+.Ip $) 8 2
+The effective gid of this process.
+If you are on a machine that supports membership in multiple groups
+simultaneously, gives a space separated list of groups you are in.
+The first number is the one returned by getegid(), and the subsequent ones
+by getgroups(), one of which may be the same as the first number.
+(Mnemonic: parentheses are used to GROUP things.
+The effective gid is the group that's RIGHT for you, if you're running setgid.)
+.Sp
+Note: $<, $>, $( and $) can only be set on machines that support the
+corresponding set[re][ug]id() routine.
+$( and $) can only be swapped on machines supporting setregid().
+.Ip $: 8 2
+The current set of characters after which a string may be broken to
+fill continuation fields (starting with ^) in a format.
+Default is "\ \en-", to break on whitespace or hyphens.
+(Mnemonic: a \*(L"colon\*(R" in poetry is a part of a line.)
+.Ip $^D 8 2
+The current value of the debugging flags.
+(Mnemonic: value of
+.B \-D
+switch.)
+.Ip $^F 8 2
+The maximum system file descriptor, ordinarily 2. System file descriptors
+are passed to subprocesses, while higher file descriptors are not.
+During an open, system file descriptors are preserved even if the open
+fails. Ordinary file descriptors are closed before the open is attempted.
+.Ip $^I 8 2
+The current value of the inplace-edit extension.
+Use undef to disable inplace editing.
+(Mnemonic: value of
+.B \-i
+switch.)
+.Ip $^L 8 2
+What formats output to perform a formfeed. Default is \ef.
+.Ip $^P 8 2
+The internal flag that the debugger clears so that it doesn't
+debug itself. You could conceivable disable debugging yourself
+by clearing it.
+.Ip $^T 8 2
+The time at which the script began running, in seconds since the epoch.
+The values returned by the
+.B \-M ,
+.B \-A
+and
+.B \-C
+filetests are based on this value.
+.Ip $^W 8 2
+The current value of the warning switch.
+(Mnemonic: related to the
+.B \-w
+switch.)
+.Ip $^X 8 2
+The name that Perl itself was executed as, from argv[0].
+.Ip $ARGV 8 3
+contains the name of the current file when reading from <>.
+.Ip @ARGV 8 3
+The array ARGV contains the command line arguments intended for the script.
+Note that $#ARGV is the generally number of arguments minus one, since
+$ARGV[0] is the first argument, NOT the command name.
+See $0 for the command name.
+.Ip @INC 8 3
+The array INC contains the list of places to look for
+.I perl
+scripts to be
+evaluated by the \*(L"do EXPR\*(R" command or the \*(L"require\*(R" command.
+It initially consists of the arguments to any
+.B \-I
+command line switches, followed
+by the default
+.I perl
+library, probably \*(L"/usr/share/perl\*(R",
+followed by \*(L".\*(R", to represent the current directory.
+.Ip %INC 8 3
+The associative array INC contains entries for each filename that has
+been included via \*(L"do\*(R" or \*(L"require\*(R".
+The key is the filename you specified, and the value is the location of
+the file actually found.
+The \*(L"require\*(R" command uses this array to determine whether
+a given file has already been included.
+.Ip $ENV{expr} 8 2
+The associative array ENV contains your current environment.
+Setting a value in ENV changes the environment for child processes.
+.Ip $SIG{expr} 8 2
+The associative array SIG is used to set signal handlers for various signals.
+Example:
+.nf
+
+.ne 12
+ sub handler { # 1st argument is signal name
+ local($sig) = @_;
+ print "Caught a SIG$sig\-\|\-shutting down\en";
+ close(LOG);
+ exit(0);
+ }
+
+ $SIG{\'INT\'} = \'handler\';
+ $SIG{\'QUIT\'} = \'handler\';
+ .\|.\|.
+ $SIG{\'INT\'} = \'DEFAULT\'; # restore default action
+ $SIG{\'QUIT\'} = \'IGNORE\'; # ignore SIGQUIT
+
+.fi
+The SIG array only contains values for the signals actually set within
+the perl script.
+.Sh "Packages"
+Perl provides a mechanism for alternate namespaces to protect packages from
+stomping on each others variables.
+By default, a perl script starts compiling into the package known as \*(L"main\*(R".
+By use of the
+.I package
+declaration, you can switch namespaces.
+The scope of the package declaration is from the declaration itself to the end
+of the enclosing block (the same scope as the local() operator).
+Typically it would be the first declaration in a file to be included by
+the \*(L"require\*(R" operator.
+You can switch into a package in more than one place; it merely influences
+which symbol table is used by the compiler for the rest of that block.
+You can refer to variables and filehandles in other packages by prefixing
+the identifier with the package name and a single quote.
+If the package name is null, the \*(L"main\*(R" package as assumed.
+.PP
+Only identifiers starting with letters are stored in the packages symbol
+table.
+All other symbols are kept in package \*(L"main\*(R".
+In addition, the identifiers STDIN, STDOUT, STDERR, ARGV, ARGVOUT, ENV, INC
+and SIG are forced to be in package \*(L"main\*(R", even when used for
+other purposes than their built-in one.
+Note also that, if you have a package called \*(L"m\*(R", \*(L"s\*(R"
+or \*(L"y\*(R", the you can't use the qualified form of an identifier since it
+will be interpreted instead as a pattern match, a substitution
+or a translation.
+.PP
+Eval'ed strings are compiled in the package in which the eval was compiled
+in.
+(Assignments to $SIG{}, however, assume the signal handler specified is in the
+main package.
+Qualify the signal handler name if you wish to have a signal handler in
+a package.)
+For an example, examine perldb.pl in the perl library.
+It initially switches to the DB package so that the debugger doesn't interfere
+with variables in the script you are trying to debug.
+At various points, however, it temporarily switches back to the main package
+to evaluate various expressions in the context of the main package.
+.PP
+The symbol table for a package happens to be stored in the associative array
+of that name prepended with an underscore.
+The value in each entry of the associative array is
+what you are referring to when you use the *name notation.
+In fact, the following have the same effect (in package main, anyway),
+though the first is more
+efficient because it does the symbol table lookups at compile time:
+.nf
+
+.ne 2
+ local(*foo) = *bar;
+ local($_main{'foo'}) = $_main{'bar'};
+
+.fi
+You can use this to print out all the variables in a package, for instance.
+Here is dumpvar.pl from the perl library:
+.nf
+.ne 11
+ package dumpvar;
+
+ sub main'dumpvar {
+ \& ($package) = @_;
+ \& local(*stab) = eval("*_$package");
+ \& while (($key,$val) = each(%stab)) {
+ \& {
+ \& local(*entry) = $val;
+ \& if (defined $entry) {
+ \& print "\e$$key = '$entry'\en";
+ \& }
+.ne 7
+ \& if (defined @entry) {
+ \& print "\e@$key = (\en";
+ \& foreach $num ($[ .. $#entry) {
+ \& print " $num\et'",$entry[$num],"'\en";
+ \& }
+ \& print ")\en";
+ \& }
+.ne 10
+ \& if ($key ne "_$package" && defined %entry) {
+ \& print "\e%$key = (\en";
+ \& foreach $key (sort keys(%entry)) {
+ \& print " $key\et'",$entry{$key},"'\en";
+ \& }
+ \& print ")\en";
+ \& }
+ \& }
+ \& }
+ }
+
+.fi
+Note that, even though the subroutine is compiled in package dumpvar, the
+name of the subroutine is qualified so that its name is inserted into package
+\*(L"main\*(R".
+.Sh "Style"
+Each programmer will, of course, have his or her own preferences in regards
+to formatting, but there are some general guidelines that will make your
+programs easier to read.
+.Ip 1. 4 4
+Just because you CAN do something a particular way doesn't mean that
+you SHOULD do it that way.
+.I Perl
+is designed to give you several ways to do anything, so consider picking
+the most readable one.
+For instance
+
+ open(FOO,$foo) || die "Can't open $foo: $!";
+
+is better than
+
+ die "Can't open $foo: $!" unless open(FOO,$foo);
+
+because the second way hides the main point of the statement in a
+modifier.
+On the other hand
+
+ print "Starting analysis\en" if $verbose;
+
+is better than
+
+ $verbose && print "Starting analysis\en";
+
+since the main point isn't whether the user typed -v or not.
+.Sp
+Similarly, just because an operator lets you assume default arguments
+doesn't mean that you have to make use of the defaults.
+The defaults are there for lazy systems programmers writing one-shot
+programs.
+If you want your program to be readable, consider supplying the argument.
+.Sp
+Along the same lines, just because you
+.I can
+omit parentheses in many places doesn't mean that you ought to:
+.nf
+
+ return print reverse sort num values array;
+ return print(reverse(sort num (values(%array))));
+
+.fi
+When in doubt, parenthesize.
+At the very least it will let some poor schmuck bounce on the % key in vi.
+.Sp
+Even if you aren't in doubt, consider the mental welfare of the person who
+has to maintain the code after you, and who will probably put parens in
+the wrong place.
+.Ip 2. 4 4
+Don't go through silly contortions to exit a loop at the top or the
+bottom, when
+.I perl
+provides the "last" operator so you can exit in the middle.
+Just outdent it a little to make it more visible:
+.nf
+
+.ne 7
+ line:
+ for (;;) {
+ statements;
+ last line if $foo;
+ next line if /^#/;
+ statements;
+ }
+
+.fi
+.Ip 3. 4 4
+Don't be afraid to use loop labels\*(--they're there to enhance readability as
+well as to allow multi-level loop breaks.
+See last example.
+.Ip 4. 4 4
+For portability, when using features that may not be implemented on every
+machine, test the construct in an eval to see if it fails.
+If you know what version or patchlevel a particular feature was implemented,
+you can test $] to see if it will be there.
+.Ip 5. 4 4
+Choose mnemonic identifiers.
+.Ip 6. 4 4
+Be consistent.
+.Sh "Debugging"
+If you invoke
+.I perl
+with a
+.B \-d
+switch, your script will be run under a debugging monitor.
+It will halt before the first executable statement and ask you for a
+command, such as:
+.Ip "h" 12 4
+Prints out a help message.
+.Ip "T" 12 4
+Stack trace.
+.Ip "s" 12 4
+Single step.
+Executes until it reaches the beginning of another statement.
+.Ip "n" 12 4
+Next.
+Executes over subroutine calls, until it reaches the beginning of the
+next statement.
+.Ip "f" 12 4
+Finish.
+Executes statements until it has finished the current subroutine.
+.Ip "c" 12 4
+Continue.
+Executes until the next breakpoint is reached.
+.Ip "c line" 12 4
+Continue to the specified line.
+Inserts a one-time-only breakpoint at the specified line.
+.Ip "<CR>" 12 4
+Repeat last n or s.
+.Ip "l min+incr" 12 4
+List incr+1 lines starting at min.
+If min is omitted, starts where last listing left off.
+If incr is omitted, previous value of incr is used.
+.Ip "l min-max" 12 4
+List lines in the indicated range.
+.Ip "l line" 12 4
+List just the indicated line.
+.Ip "l" 12 4
+List next window.
+.Ip "-" 12 4
+List previous window.
+.Ip "w line" 12 4
+List window around line.
+.Ip "l subname" 12 4
+List subroutine.
+If it's a long subroutine it just lists the beginning.
+Use \*(L"l\*(R" to list more.
+.Ip "/pattern/" 12 4
+Regular expression search forward for pattern; the final / is optional.
+.Ip "?pattern?" 12 4
+Regular expression search backward for pattern; the final ? is optional.
+.Ip "L" 12 4
+List lines that have breakpoints or actions.
+.Ip "S" 12 4
+Lists the names of all subroutines.
+.Ip "t" 12 4
+Toggle trace mode on or off.
+.Ip "b line condition" 12 4
+Set a breakpoint.
+If line is omitted, sets a breakpoint on the
+line that is about to be executed.
+If a condition is specified, it is evaluated each time the statement is
+reached and a breakpoint is taken only if the condition is true.
+Breakpoints may only be set on lines that begin an executable statement.
+.Ip "b subname condition" 12 4
+Set breakpoint at first executable line of subroutine.
+.Ip "d line" 12 4
+Delete breakpoint.
+If line is omitted, deletes the breakpoint on the
+line that is about to be executed.
+.Ip "D" 12 4
+Delete all breakpoints.
+.Ip "a line command" 12 4
+Set an action for line.
+A multi-line command may be entered by backslashing the newlines.
+.Ip "A" 12 4
+Delete all line actions.
+.Ip "< command" 12 4
+Set an action to happen before every debugger prompt.
+A multi-line command may be entered by backslashing the newlines.
+.Ip "> command" 12 4
+Set an action to happen after the prompt when you've just given a command
+to return to executing the script.
+A multi-line command may be entered by backslashing the newlines.
+.Ip "V package" 12 4
+List all variables in package.
+Default is main package.
+.Ip "! number" 12 4
+Redo a debugging command.
+If number is omitted, redoes the previous command.
+.Ip "! -number" 12 4
+Redo the command that was that many commands ago.
+.Ip "H -number" 12 4
+Display last n commands.
+Only commands longer than one character are listed.
+If number is omitted, lists them all.
+.Ip "q or ^D" 12 4
+Quit.
+.Ip "command" 12 4
+Execute command as a perl statement.
+A missing semicolon will be supplied.
+.Ip "p expr" 12 4
+Same as \*(L"print DB'OUT expr\*(R".
+The DB'OUT filehandle is opened to /dev/tty, regardless of where STDOUT
+may be redirected to.
+.PP
+If you want to modify the debugger, copy perldb.pl from the perl library
+to your current directory and modify it as necessary.
+(You'll also have to put -I. on your command line.)
+You can do some customization by setting up a .perldb file which contains
+initialization code.
+For instance, you could make aliases like these:
+.nf
+
+ $DB'alias{'len'} = 's/^len(.*)/p length($1)/';
+ $DB'alias{'stop'} = 's/^stop (at|in)/b/';
+ $DB'alias{'.'} =
+ 's/^\e./p "\e$DB\e'sub(\e$DB\e'line):\et",\e$DB\e'line[\e$DB\e'line]/';
+
+.fi
+.Sh "Setuid Scripts"
+.I Perl
+is designed to make it easy to write secure setuid and setgid scripts.
+Unlike shells, which are based on multiple substitution passes on each line
+of the script,
+.I perl
+uses a more conventional evaluation scheme with fewer hidden \*(L"gotchas\*(R".
+Additionally, since the language has more built-in functionality, it
+has to rely less upon external (and possibly untrustworthy) programs to
+accomplish its purposes.
+.PP
+In an unpatched 4.2 or 4.3bsd kernel, setuid scripts are intrinsically
+insecure, but this kernel feature can be disabled.
+If it is,
+.I perl
+can emulate the setuid and setgid mechanism when it notices the otherwise
+useless setuid/gid bits on perl scripts.
+If the kernel feature isn't disabled,
+.I perl
+will complain loudly that your setuid script is insecure.
+You'll need to either disable the kernel setuid script feature, or put
+a C wrapper around the script.
+.PP
+When perl is executing a setuid script, it takes special precautions to
+prevent you from falling into any obvious traps.
+(In some ways, a perl script is more secure than the corresponding
+C program.)
+Any command line argument, environment variable, or input is marked as
+\*(L"tainted\*(R", and may not be used, directly or indirectly, in any
+command that invokes a subshell, or in any command that modifies files,
+directories or processes.
+Any variable that is set within an expression that has previously referenced
+a tainted value also becomes tainted (even if it is logically impossible
+for the tainted value to influence the variable).
+For example:
+.nf
+
+.ne 5
+ $foo = shift; # $foo is tainted
+ $bar = $foo,\'bar\'; # $bar is also tainted
+ $xxx = <>; # Tainted
+ $path = $ENV{\'PATH\'}; # Tainted, but see below
+ $abc = \'abc\'; # Not tainted
+
+.ne 4
+ system "echo $foo"; # Insecure
+ system "/bin/echo", $foo; # Secure (doesn't use sh)
+ system "echo $bar"; # Insecure
+ system "echo $abc"; # Insecure until PATH set
+
+.ne 5
+ $ENV{\'PATH\'} = \'/bin:/usr/bin\';
+ $ENV{\'IFS\'} = \'\' if $ENV{\'IFS\'} ne \'\';
+
+ $path = $ENV{\'PATH\'}; # Not tainted
+ system "echo $abc"; # Is secure now!
+
+.ne 5
+ open(FOO,"$foo"); # OK
+ open(FOO,">$foo"); # Not OK
+
+ open(FOO,"echo $foo|"); # Not OK, but...
+ open(FOO,"-|") || exec \'echo\', $foo; # OK
+
+ $zzz = `echo $foo`; # Insecure, zzz tainted
+
+ unlink $abc,$foo; # Insecure
+ umask $foo; # Insecure
+
+.ne 3
+ exec "echo $foo"; # Insecure
+ exec "echo", $foo; # Secure (doesn't use sh)
+ exec "sh", \'-c\', $foo; # Considered secure, alas
+
+.fi
+The taintedness is associated with each scalar value, so some elements
+of an array can be tainted, and others not.
+.PP
+If you try to do something insecure, you will get a fatal error saying
+something like \*(L"Insecure dependency\*(R" or \*(L"Insecure PATH\*(R".
+Note that you can still write an insecure system call or exec,
+but only by explicitly doing something like the last example above.
+You can also bypass the tainting mechanism by referencing
+subpatterns\*(--\c
+.I perl
+presumes that if you reference a substring using $1, $2, etc, you knew
+what you were doing when you wrote the pattern:
+.nf
+
+ $ARGV[0] =~ /^\-P(\ew+)$/;
+ $printer = $1; # Not tainted
+
+.fi
+This is fairly secure since \ew+ doesn't match shell metacharacters.
+Use of .+ would have been insecure, but
+.I perl
+doesn't check for that, so you must be careful with your patterns.
+This is the ONLY mechanism for untainting user supplied filenames if you
+want to do file operations on them (unless you make $> equal to $<).
+.PP
+It's also possible to get into trouble with other operations that don't care
+whether they use tainted values.
+Make judicious use of the file tests in dealing with any user-supplied
+filenames.
+When possible, do opens and such after setting $> = $<.
+.I Perl
+doesn't prevent you from opening tainted filenames for reading, so be
+careful what you print out.
+The tainting mechanism is intended to prevent stupid mistakes, not to remove
+the need for thought.
+.SH ENVIRONMENT
+.Ip HOME 12 4
+Used if chdir has no argument.
+.Ip LOGDIR 12 4
+Used if chdir has no argument and HOME is not set.
+.Ip PATH 12 4
+Used in executing subprocesses, and in finding the script if \-S
+is used.
+.Ip PERLLIB 12 4
+A colon-separated list of directories in which to look for Perl library
+files before looking in the standard library and the current directory.
+.Ip PERLDB 12 4
+The command used to get the debugger code. If unset, uses
+.br
+
+ require 'perldb.pl'
+
+.PP
+Apart from these,
+.I perl
+uses no other environment variables, except to make them available
+to the script being executed, and to child processes.
+However, scripts running setuid would do well to execute the following lines
+before doing anything else, just to keep people honest:
+.nf
+
+.ne 3
+ $ENV{\'PATH\'} = \'/bin:/usr/bin\'; # or whatever you need
+ $ENV{\'SHELL\'} = \'/bin/sh\' if $ENV{\'SHELL\'} ne \'\';
+ $ENV{\'IFS\'} = \'\' if $ENV{\'IFS\'} ne \'\';
+
+.fi
+.SH AUTHOR
+Larry Wall <lwall@netlabs.com>
+.br
+MS-DOS port by Diomidis Spinellis <dds@cc.ic.ac.uk>
+.SH FILES
+/tmp/perl\-eXXXXXX temporary file for
+.B \-e
+commands.
+.SH SEE ALSO
+a2p awk to perl translator
+.br
+s2p sed to perl translator
+.SH DIAGNOSTICS
+Compilation errors will tell you the line number of the error, with an
+indication of the next token or token type that was to be examined.
+(In the case of a script passed to
+.I perl
+via
+.B \-e
+switches, each
+.B \-e
+is counted as one line.)
+.PP
+Setuid scripts have additional constraints that can produce error messages
+such as \*(L"Insecure dependency\*(R".
+See the section on setuid scripts.
+.SH TRAPS
+Accustomed
+.IR awk
+users should take special note of the following:
+.Ip * 4 2
+Semicolons are required after all simple statements in
+.I perl
+(except at the end of a block).
+Newline is not a statement delimiter.
+.Ip * 4 2
+Curly brackets are required on ifs and whiles.
+.Ip * 4 2
+Variables begin with $ or @ in
+.IR perl .
+.Ip * 4 2
+Arrays index from 0 unless you set $[.
+Likewise string positions in substr() and index().
+.Ip * 4 2
+You have to decide whether your array has numeric or string indices.
+.Ip * 4 2
+Associative array values do not spring into existence upon mere reference.
+.Ip * 4 2
+You have to decide whether you want to use string or numeric comparisons.
+.Ip * 4 2
+Reading an input line does not split it for you. You get to split it yourself
+to an array.
+And the
+.I split
+operator has different arguments.
+.Ip * 4 2
+The current input line is normally in $_, not $0.
+It generally does not have the newline stripped.
+($0 is the name of the program executed.)
+.Ip * 4 2
+$<digit> does not refer to fields\*(--it refers to substrings matched by the last
+match pattern.
+.Ip * 4 2
+The
+.I print
+statement does not add field and record separators unless you set
+$, and $\e.
+.Ip * 4 2
+You must open your files before you print to them.
+.Ip * 4 2
+The range operator is \*(L".\|.\*(R", not comma.
+(The comma operator works as in C.)
+.Ip * 4 2
+The match operator is \*(L"=~\*(R", not \*(L"~\*(R".
+(\*(L"~\*(R" is the one's complement operator, as in C.)
+.Ip * 4 2
+The exponentiation operator is \*(L"**\*(R", not \*(L"^\*(R".
+(\*(L"^\*(R" is the XOR operator, as in C.)
+.Ip * 4 2
+The concatenation operator is \*(L".\*(R", not the null string.
+(Using the null string would render \*(L"/pat/ /pat/\*(R" unparsable,
+since the third slash would be interpreted as a division operator\*(--the
+tokener is in fact slightly context sensitive for operators like /, ?, and <.
+And in fact, . itself can be the beginning of a number.)
+.Ip * 4 2
+.IR Next ,
+.I exit
+and
+.I continue
+work differently.
+.Ip * 4 2
+The following variables work differently
+.nf
+
+ Awk \h'|2.5i'Perl
+ ARGC \h'|2.5i'$#ARGV
+ ARGV[0] \h'|2.5i'$0
+ FILENAME\h'|2.5i'$ARGV
+ FNR \h'|2.5i'$. \- something
+ FS \h'|2.5i'(whatever you like)
+ NF \h'|2.5i'$#Fld, or some such
+ NR \h'|2.5i'$.
+ OFMT \h'|2.5i'$#
+ OFS \h'|2.5i'$,
+ ORS \h'|2.5i'$\e
+ RLENGTH \h'|2.5i'length($&)
+ RS \h'|2.5i'$/
+ RSTART \h'|2.5i'length($\`)
+ SUBSEP \h'|2.5i'$;
+
+.fi
+.Ip * 4 2
+When in doubt, run the
+.I awk
+construct through a2p and see what it gives you.
+.PP
+Cerebral C programmers should take note of the following:
+.Ip * 4 2
+Curly brackets are required on ifs and whiles.
+.Ip * 4 2
+You should use \*(L"elsif\*(R" rather than \*(L"else if\*(R"
+.Ip * 4 2
+.I Break
+and
+.I continue
+become
+.I last
+and
+.IR next ,
+respectively.
+.Ip * 4 2
+There's no switch statement.
+.Ip * 4 2
+Variables begin with $ or @ in
+.IR perl .
+.Ip * 4 2
+Printf does not implement *.
+.Ip * 4 2
+Comments begin with #, not /*.
+.Ip * 4 2
+You can't take the address of anything.
+.Ip * 4 2
+ARGV must be capitalized.
+.Ip * 4 2
+The \*(L"system\*(R" calls link, unlink, rename, etc. return nonzero for success, not 0.
+.Ip * 4 2
+Signal handlers deal with signal names, not numbers.
+.PP
+Seasoned
+.I sed
+programmers should take note of the following:
+.Ip * 4 2
+Backreferences in substitutions use $ rather than \e.
+.Ip * 4 2
+The pattern matching metacharacters (, ), and | do not have backslashes in front.
+.Ip * 4 2
+The range operator is .\|. rather than comma.
+.PP
+Sharp shell programmers should take note of the following:
+.Ip * 4 2
+The backtick operator does variable interpretation without regard to the
+presence of single quotes in the command.
+.Ip * 4 2
+The backtick operator does no translation of the return value, unlike csh.
+.Ip * 4 2
+Shells (especially csh) do several levels of substitution on each command line.
+.I Perl
+does substitution only in certain constructs such as double quotes,
+backticks, angle brackets and search patterns.
+.Ip * 4 2
+Shells interpret scripts a little bit at a time.
+.I Perl
+compiles the whole program before executing it.
+.Ip * 4 2
+The arguments are available via @ARGV, not $1, $2, etc.
+.Ip * 4 2
+The environment is not automatically made available as variables.
+.SH ERRATA\0AND\0ADDENDA
+The Perl book,
+.I Programming\0Perl ,
+has the following omissions and goofs.
+.PP
+On page 5, the examples which read
+.nf
+
+ eval "/usr/bin/perl
+
+should read
+
+ eval "exec /usr/bin/perl
+
+.fi
+.PP
+On page 195, the equivalent to the System V sum program only works for
+very small files. To do larger files, use
+.nf
+
+ undef $/;
+ $checksum = unpack("%32C*",<>) % 32767;
+
+.fi
+.PP
+The descriptions of alarm and sleep refer to signal SIGALARM. These
+should refer to SIGALRM.
+.PP
+The
+.B \-0
+switch to set the initial value of $/ was added to Perl after the book
+went to press.
+.PP
+The
+.B \-l
+switch now does automatic line ending processing.
+.PP
+The qx// construct is now a synonym for backticks.
+.PP
+$0 may now be assigned to set the argument displayed by
+.I ps (1).
+.PP
+The new @###.## format was omitted accidentally from the description
+on formats.
+.PP
+It wasn't known at press time that s///ee caused multiple evaluations of
+the replacement expression. This is to be construed as a feature.
+.PP
+(LIST) x $count now does array replication.
+.PP
+There is now no limit on the number of parentheses in a regular expression.
+.PP
+In double-quote context, more escapes are supported: \ee, \ea, \ex1b, \ec[,
+\el, \eL, \eu, \eU, \eE. The latter five control up/lower case translation.
+.PP
+The
+.B $/
+variable may now be set to a multi-character delimiter.
+.PP
+There is now a g modifier on ordinary pattern matching that causes it
+to iterate through a string finding multiple matches.
+.PP
+All of the $^X variables are new except for $^T.
+.PP
+The default top-of-form format for FILEHANDLE is now FILEHANDLE_TOP rather
+than top.
+.PP
+The eval {} and sort {} constructs were added in version 4.018.
+.PP
+The v and V (little-endian) template options for pack and unpack were
+added in 4.019.
+.SH BUGS
+.PP
+.I Perl
+is at the mercy of your machine's definitions of various operations
+such as type casting, atof() and sprintf().
+.PP
+If your stdio requires an seek or eof between reads and writes on a particular
+stream, so does
+.IR perl .
+(This doesn't apply to sysread() and syswrite().)
+.PP
+While none of the built-in data types have any arbitrary size limits (apart
+from memory size), there are still a few arbitrary limits:
+a given identifier may not be longer than 255 characters,
+and no component of your PATH may be longer than 255 if you use \-S.
+A regular expression may not compile to more than 32767 bytes internally.
+.PP
+.I Perl
+actually stands for Pathologically Eclectic Rubbish Lister, but don't tell
+anyone I said that.
+.rn }` ''
diff --git a/gnu/usr.bin/perl/perl/perl.c b/gnu/usr.bin/perl/perl/perl.c
new file mode 100644
index 0000000..4d1a7ae
--- /dev/null
+++ b/gnu/usr.bin/perl/perl/perl.c
@@ -0,0 +1,1462 @@
+char rcsid[] = "$RCSfile: perl.c,v $$Revision: 1.3 $$Date: 1995/05/28 19:21:54 $\nPatch level: ###\n";
+/*
+ * Copyright (c) 1991, Larry Wall
+ *
+ * You may distribute under the terms of either the GNU General Public
+ * License or the Artistic License, as specified in the README file.
+ *
+ * $Log: perl.c,v $
+ * Revision 1.3 1995/05/28 19:21:54 ache
+ * Fix $] variable value (version number), close PR 449
+ * Submitted by: Bill Fenner <fenner@parc.xerox.com>
+ *
+ * Revision 1.2 1994/10/27 23:16:54 wollman
+ * Convince Perl to that is is part of the system, as /usr/bin/perl (binary)
+ * and /usr/share/perl (library). The latter was chosen as analogous to other
+ * directories already present in /usr/share, like /usr/share/groff_font and
+ * (particularly) /usr/share/mk.
+ *
+ * Revision 1.1.1.1 1994/09/10 06:27:33 gclarkii
+ * Initial import of Perl 4.046 bmaked
+ *
+ * Revision 1.1.1.1 1993/08/23 21:29:37 nate
+ * PERL!
+ *
+ * Revision 4.0.1.8 1993/02/05 19:39:30 lwall
+ * patch36: the taintanyway code wasn't tainting anyway
+ * patch36: Malformed cmd links core dump apparently fixed
+ *
+ * Revision 4.0.1.7 92/06/08 14:50:39 lwall
+ * patch20: PERLLIB now supports multiple directories
+ * patch20: running taintperl explicitly now does checks even if $< == $>
+ * patch20: -e 'cmd' no longer fails silently if /tmp runs out of space
+ * patch20: perl -P now uses location of sed determined by Configure
+ * patch20: form feed for formats is now specifiable via $^L
+ * patch20: paragraph mode now skips extra newlines automatically
+ * patch20: eval "1 #comment" didn't work
+ * patch20: couldn't require . files
+ * patch20: semantic compilation errors didn't abort execution
+ *
+ * Revision 4.0.1.6 91/11/11 16:38:45 lwall
+ * patch19: default arg for shift was wrong after first subroutine definition
+ * patch19: op/regexp.t failed from missing arg to bcmp()
+ *
+ * Revision 4.0.1.5 91/11/05 18:03:32 lwall
+ * patch11: random cleanup
+ * patch11: $0 was being truncated at times
+ * patch11: cppstdin now installed outside of source directory
+ * patch11: -P didn't allow use of #elif or #undef
+ * patch11: prepared for ctype implementations that don't define isascii()
+ * patch11: added eval {}
+ * patch11: eval confused by string containing null
+ *
+ * Revision 4.0.1.4 91/06/10 01:23:07 lwall
+ * patch10: perl -v printed incorrect copyright notice
+ *
+ * Revision 4.0.1.3 91/06/07 11:40:18 lwall
+ * patch4: changed old $^P to $^X
+ *
+ * Revision 4.0.1.2 91/06/07 11:26:16 lwall
+ * patch4: new copyright notice
+ * patch4: added $^P variable to control calling of perldb routines
+ * patch4: added $^F variable to specify maximum system fd, default 2
+ * patch4: debugger lost track of lines in eval
+ *
+ * Revision 4.0.1.1 91/04/11 17:49:05 lwall
+ * patch1: fixed undefined environ problem
+ *
+ * Revision 4.0 91/03/20 01:37:44 lwall
+ * 4.0 baseline.
+ *
+ */
+
+/*SUPPRESS 560*/
+
+#include "EXTERN.h"
+#include "perl.h"
+#include "perly.h"
+#include "patchlevel.h"
+
+char *getenv();
+
+#ifdef IAMSUID
+#ifndef DOSUID
+#define DOSUID
+#endif
+#endif
+
+#ifdef SETUID_SCRIPTS_ARE_SECURE_NOW
+#ifdef DOSUID
+#undef DOSUID
+#endif
+#endif
+
+static char* moreswitches();
+static void incpush();
+static char* cddir;
+static bool minus_c;
+static char patchlevel[6];
+static char *nrs = "\n";
+static int nrschar = '\n'; /* final char of rs, or 0777 if none */
+static int nrslen = 1;
+
+main(argc,argv,env)
+register int argc;
+register char **argv;
+register char **env;
+{
+ register STR *str;
+ register char *s;
+ char *scriptname;
+ char *getenv();
+ bool dosearch = FALSE;
+#ifdef DOSUID
+ char *validarg = "";
+#endif
+
+#ifdef SETUID_SCRIPTS_ARE_SECURE_NOW
+#ifdef IAMSUID
+#undef IAMSUID
+ fatal("suidperl is no longer needed since the kernel can now execute\n\
+setuid perl scripts securely.\n");
+#endif
+#endif
+
+ origargv = argv;
+ origargc = argc;
+ origenviron = environ;
+ uid = (int)getuid();
+ euid = (int)geteuid();
+ gid = (int)getgid();
+ egid = (int)getegid();
+ sprintf(patchlevel,"%3.3s%2.2d", "4.0", PATCHLEVEL);
+#ifdef MSDOS
+ /*
+ * There is no way we can refer to them from Perl so close them to save
+ * space. The other alternative would be to provide STDAUX and STDPRN
+ * filehandles.
+ */
+ (void)fclose(stdaux);
+ (void)fclose(stdprn);
+#endif
+ if (do_undump) {
+ origfilename = savestr(argv[0]);
+ do_undump = 0;
+ loop_ptr = -1; /* start label stack again */
+ goto just_doit;
+ }
+#ifdef TAINT
+#ifndef DOSUID
+ if (uid == euid && gid == egid)
+ taintanyway = TRUE; /* running taintperl explicitly */
+#endif
+#endif
+ (void)sprintf(index(rcsid,'#'), "%d\n", PATCHLEVEL);
+ linestr = Str_new(65,80);
+ str_nset(linestr,"",0);
+ str = str_make("",0); /* first used for -I flags */
+ curstash = defstash = hnew(0);
+ curstname = str_make("main",4);
+ stab_xhash(stabent("_main",TRUE)) = defstash;
+ defstash->tbl_name = "main";
+ incstab = hadd(aadd(stabent("INC",TRUE)));
+ incstab->str_pok |= SP_MULTI;
+ for (argc--,argv++; argc > 0; argc--,argv++) {
+ if (argv[0][0] != '-' || !argv[0][1])
+ break;
+#ifdef DOSUID
+ if (*validarg)
+ validarg = " PHOOEY ";
+ else
+ validarg = argv[0];
+#endif
+ s = argv[0]+1;
+ reswitch:
+ switch (*s) {
+ case '0':
+ case 'a':
+ case 'c':
+ case 'd':
+ case 'D':
+ case 'i':
+ case 'l':
+ case 'n':
+ case 'p':
+ case 'u':
+ case 'U':
+ case 'v':
+ case 'w':
+ if (s = moreswitches(s))
+ goto reswitch;
+ break;
+
+ case 'e':
+#ifdef TAINT
+ if (euid != uid || egid != gid)
+ fatal("No -e allowed in setuid scripts");
+#endif
+ if (!e_fp) {
+ e_tmpname = savestr(TMPPATH);
+ (void)mktemp(e_tmpname);
+ if (!*e_tmpname)
+ fatal("Can't mktemp()");
+ e_fp = fopen(e_tmpname,"w");
+ if (!e_fp)
+ fatal("Cannot open temporary file");
+ }
+ if (argv[1]) {
+ fputs(argv[1],e_fp);
+ argc--,argv++;
+ }
+ (void)putc('\n', e_fp);
+ break;
+ case 'I':
+#ifdef TAINT
+ if (euid != uid || egid != gid)
+ fatal("No -I allowed in setuid scripts");
+#endif
+ str_cat(str,"-");
+ str_cat(str,s);
+ str_cat(str," ");
+ if (*++s) {
+ (void)apush(stab_array(incstab),str_make(s,0));
+ }
+ else if (argv[1]) {
+ (void)apush(stab_array(incstab),str_make(argv[1],0));
+ str_cat(str,argv[1]);
+ argc--,argv++;
+ str_cat(str," ");
+ }
+ break;
+ case 'P':
+#ifdef TAINT
+ if (euid != uid || egid != gid)
+ fatal("No -P allowed in setuid scripts");
+#endif
+ preprocess = TRUE;
+ s++;
+ goto reswitch;
+ case 's':
+#ifdef TAINT
+ if (euid != uid || egid != gid)
+ fatal("No -s allowed in setuid scripts");
+#endif
+ doswitches = TRUE;
+ s++;
+ goto reswitch;
+ case 'S':
+#ifdef TAINT
+ if (euid != uid || egid != gid)
+ fatal("No -S allowed in setuid scripts");
+#endif
+ dosearch = TRUE;
+ s++;
+ goto reswitch;
+ case 'x':
+ doextract = TRUE;
+ s++;
+ if (*s)
+ cddir = savestr(s);
+ break;
+ case '-':
+ argc--,argv++;
+ goto switch_end;
+ case 0:
+ break;
+ default:
+ fatal("Unrecognized switch: -%s",s);
+ }
+ }
+ switch_end:
+ scriptname = argv[0];
+ if (e_fp) {
+ if (fflush(e_fp) || ferror(e_fp) || fclose(e_fp))
+ fatal("Can't write to temp file for -e: %s", strerror(errno));
+ argc++,argv--;
+ scriptname = e_tmpname;
+ }
+
+#ifdef DOSISH
+#define PERLLIB_SEP ';'
+#else
+#define PERLLIB_SEP ':'
+#endif
+#ifndef TAINT /* Can't allow arbitrary PERLLIB in setuid script */
+ incpush(getenv("PERLLIB"));
+#endif /* TAINT */
+
+#ifndef PRIVLIB
+#define PRIVLIB "/usr/share/perl"
+#endif
+ incpush(PRIVLIB);
+ (void)apush(stab_array(incstab),str_make(".",1));
+
+ str_set(&str_no,No);
+ str_set(&str_yes,Yes);
+
+ /* open script */
+
+ if (scriptname == Nullch)
+#ifdef MSDOS
+ {
+ if ( isatty(fileno(stdin)) )
+ moreswitches("v");
+ scriptname = "-";
+ }
+#else
+ scriptname = "-";
+#endif
+ if (dosearch && !index(scriptname, '/') && (s = getenv("PATH"))) {
+ char *xfound = Nullch, *xfailed = Nullch;
+ int len;
+
+ bufend = s + strlen(s);
+ while (*s) {
+#ifndef DOSISH
+ s = cpytill(tokenbuf,s,bufend,':',&len);
+#else
+#ifdef atarist
+ for (len = 0; *s && *s != ',' && *s != ';'; tokenbuf[len++] = *s++);
+ tokenbuf[len] = '\0';
+#else
+ for (len = 0; *s && *s != ';'; tokenbuf[len++] = *s++);
+ tokenbuf[len] = '\0';
+#endif
+#endif
+ if (*s)
+ s++;
+#ifndef DOSISH
+ if (len && tokenbuf[len-1] != '/')
+#else
+#ifdef atarist
+ if (len && ((tokenbuf[len-1] != '\\') && (tokenbuf[len-1] != '/')))
+#else
+ if (len && tokenbuf[len-1] != '\\')
+#endif
+#endif
+ (void)strcat(tokenbuf+len,"/");
+ (void)strcat(tokenbuf+len,scriptname);
+#ifdef DEBUGGING
+ if (debug & 1)
+ fprintf(stderr,"Looking for %s\n",tokenbuf);
+#endif
+ if (stat(tokenbuf,&statbuf) < 0) /* not there? */
+ continue;
+ if (S_ISREG(statbuf.st_mode)
+ && cando(S_IRUSR,TRUE,&statbuf) && cando(S_IXUSR,TRUE,&statbuf)) {
+ xfound = tokenbuf; /* bingo! */
+ break;
+ }
+ if (!xfailed)
+ xfailed = savestr(tokenbuf);
+ }
+ if (!xfound)
+ fatal("Can't execute %s", xfailed ? xfailed : scriptname );
+ if (xfailed)
+ Safefree(xfailed);
+ scriptname = savestr(xfound);
+ }
+
+ fdpid = anew(Nullstab); /* for remembering popen pids by fd */
+ pidstatus = hnew(COEFFSIZE);/* for remembering status of dead pids */
+
+ origfilename = savestr(scriptname);
+ curcmd->c_filestab = fstab(origfilename);
+ if (strEQ(origfilename,"-"))
+ scriptname = "";
+ if (preprocess) {
+ char *cpp = CPPSTDIN;
+
+ if (strEQ(cpp,"cppstdin"))
+ sprintf(tokenbuf, "%s/%s", SCRIPTDIR, cpp);
+ else
+ sprintf(tokenbuf, "%s", cpp);
+ str_cat(str,"-I");
+ str_cat(str,PRIVLIB);
+#ifdef MSDOS
+ (void)sprintf(buf, "\
+sed %s -e \"/^[^#]/b\" \
+ -e \"/^#[ ]*include[ ]/b\" \
+ -e \"/^#[ ]*define[ ]/b\" \
+ -e \"/^#[ ]*if[ ]/b\" \
+ -e \"/^#[ ]*ifdef[ ]/b\" \
+ -e \"/^#[ ]*ifndef[ ]/b\" \
+ -e \"/^#[ ]*else/b\" \
+ -e \"/^#[ ]*elif[ ]/b\" \
+ -e \"/^#[ ]*undef[ ]/b\" \
+ -e \"/^#[ ]*endif/b\" \
+ -e \"s/^#.*//\" \
+ %s | %s -C %s %s",
+ (doextract ? "-e \"1,/^#/d\n\"" : ""),
+#else
+ (void)sprintf(buf, "\
+%s %s -e '/^[^#]/b' \
+ -e '/^#[ ]*include[ ]/b' \
+ -e '/^#[ ]*define[ ]/b' \
+ -e '/^#[ ]*if[ ]/b' \
+ -e '/^#[ ]*ifdef[ ]/b' \
+ -e '/^#[ ]*ifndef[ ]/b' \
+ -e '/^#[ ]*else/b' \
+ -e '/^#[ ]*elif[ ]/b' \
+ -e '/^#[ ]*undef[ ]/b' \
+ -e '/^#[ ]*endif/b' \
+ -e 's/^[ ]*#.*//' \
+ %s | %s -C %s %s",
+#ifdef LOC_SED
+ LOC_SED,
+#else
+ "sed",
+#endif
+ (doextract ? "-e '1,/^#/d\n'" : ""),
+#endif
+ scriptname, tokenbuf, str_get(str), CPPMINUS);
+#ifdef DEBUGGING
+ if (debug & 64) {
+ fputs(buf,stderr);
+ fputs("\n",stderr);
+ }
+#endif
+ doextract = FALSE;
+#ifdef IAMSUID /* actually, this is caught earlier */
+ if (euid != uid && !euid) { /* if running suidperl */
+#ifdef HAS_SETEUID
+ (void)seteuid(uid); /* musn't stay setuid root */
+#else
+#ifdef HAS_SETREUID
+ (void)setreuid(-1, uid);
+#else
+ setuid(uid);
+#endif
+#endif
+ if (geteuid() != uid)
+ fatal("Can't do seteuid!\n");
+ }
+#endif /* IAMSUID */
+ rsfp = mypopen(buf,"r");
+ }
+ else if (!*scriptname) {
+#ifdef TAINT
+ if (euid != uid || egid != gid)
+ fatal("Can't take set-id script from stdin");
+#endif
+ rsfp = stdin;
+ }
+ else
+ rsfp = fopen(scriptname,"r");
+ if ((FILE*)rsfp == Nullfp) {
+#ifdef DOSUID
+#ifndef IAMSUID /* in case script is not readable before setuid */
+ if (euid && stat(stab_val(curcmd->c_filestab)->str_ptr,&statbuf) >= 0 &&
+ statbuf.st_mode & (S_ISUID|S_ISGID)) {
+ (void)sprintf(buf, "%s/sperl%s", BIN, patchlevel);
+ execv(buf, origargv); /* try again */
+ fatal("Can't do setuid\n");
+ }
+#endif
+#endif
+ fatal("Can't open perl script \"%s\": %s\n",
+ stab_val(curcmd->c_filestab)->str_ptr, strerror(errno));
+ }
+ str_free(str); /* free -I directories */
+ str = Nullstr;
+
+ /* do we need to emulate setuid on scripts? */
+
+ /* This code is for those BSD systems that have setuid #! scripts disabled
+ * in the kernel because of a security problem. Merely defining DOSUID
+ * in perl will not fix that problem, but if you have disabled setuid
+ * scripts in the kernel, this will attempt to emulate setuid and setgid
+ * on scripts that have those now-otherwise-useless bits set. The setuid
+ * root version must be called suidperl or sperlN.NNN. If regular perl
+ * discovers that it has opened a setuid script, it calls suidperl with
+ * the same argv that it had. If suidperl finds that the script it has
+ * just opened is NOT setuid root, it sets the effective uid back to the
+ * uid. We don't just make perl setuid root because that loses the
+ * effective uid we had before invoking perl, if it was different from the
+ * uid.
+ *
+ * DOSUID must be defined in both perl and suidperl, and IAMSUID must
+ * be defined in suidperl only. suidperl must be setuid root. The
+ * Configure script will set this up for you if you want it.
+ *
+ * There is also the possibility of have a script which is running
+ * set-id due to a C wrapper. We want to do the TAINT checks
+ * on these set-id scripts, but don't want to have the overhead of
+ * them in normal perl, and can't use suidperl because it will lose
+ * the effective uid info, so we have an additional non-setuid root
+ * version called taintperl or tperlN.NNN that just does the TAINT checks.
+ */
+
+#ifdef DOSUID
+ if (fstat(fileno(rsfp),&statbuf) < 0) /* normal stat is insecure */
+ fatal("Can't stat script \"%s\"",origfilename);
+ if (statbuf.st_mode & (S_ISUID|S_ISGID)) {
+ int len;
+
+#ifdef IAMSUID
+#ifndef HAS_SETREUID
+ /* On this access check to make sure the directories are readable,
+ * there is actually a small window that the user could use to make
+ * filename point to an accessible directory. So there is a faint
+ * chance that someone could execute a setuid script down in a
+ * non-accessible directory. I don't know what to do about that.
+ * But I don't think it's too important. The manual lies when
+ * it says access() is useful in setuid programs.
+ */
+ if (access(stab_val(curcmd->c_filestab)->str_ptr,1)) /*double check*/
+ fatal("Permission denied");
+#else
+ /* If we can swap euid and uid, then we can determine access rights
+ * with a simple stat of the file, and then compare device and
+ * inode to make sure we did stat() on the same file we opened.
+ * Then we just have to make sure he or she can execute it.
+ */
+ {
+ struct stat tmpstatbuf;
+
+ if (setreuid(euid,uid) < 0 || getuid() != euid || geteuid() != uid)
+ fatal("Can't swap uid and euid"); /* really paranoid */
+ if (stat(stab_val(curcmd->c_filestab)->str_ptr,&tmpstatbuf) < 0)
+ fatal("Permission denied"); /* testing full pathname here */
+ if (tmpstatbuf.st_dev != statbuf.st_dev ||
+ tmpstatbuf.st_ino != statbuf.st_ino) {
+ (void)fclose(rsfp);
+ if (rsfp = mypopen("/bin/mail root","w")) { /* heh, heh */
+ fprintf(rsfp,
+"User %d tried to run dev %d ino %d in place of dev %d ino %d!\n\
+(Filename of set-id script was %s, uid %d gid %d.)\n\nSincerely,\nperl\n",
+ uid,tmpstatbuf.st_dev, tmpstatbuf.st_ino,
+ statbuf.st_dev, statbuf.st_ino,
+ stab_val(curcmd->c_filestab)->str_ptr,
+ statbuf.st_uid, statbuf.st_gid);
+ (void)mypclose(rsfp);
+ }
+ fatal("Permission denied\n");
+ }
+ if (setreuid(uid,euid) < 0 || getuid() != uid || geteuid() != euid)
+ fatal("Can't reswap uid and euid");
+ if (!cando(S_IXUSR,FALSE,&statbuf)) /* can real uid exec? */
+ fatal("Permission denied\n");
+ }
+#endif /* HAS_SETREUID */
+#endif /* IAMSUID */
+
+ if (!S_ISREG(statbuf.st_mode))
+ fatal("Permission denied");
+ if (statbuf.st_mode & S_IWOTH)
+ fatal("Setuid/gid script is writable by world");
+ doswitches = FALSE; /* -s is insecure in suid */
+ curcmd->c_line++;
+ if (fgets(tokenbuf,sizeof tokenbuf, rsfp) == Nullch ||
+ strnNE(tokenbuf,"#!",2) ) /* required even on Sys V */
+ fatal("No #! line");
+ s = tokenbuf+2;
+ if (*s == ' ') s++;
+ while (!isSPACE(*s)) s++;
+ if (strnNE(s-4,"perl",4) && strnNE(s-9,"perl",4)) /* sanity check */
+ fatal("Not a perl script");
+ while (*s == ' ' || *s == '\t') s++;
+ /*
+ * #! arg must be what we saw above. They can invoke it by
+ * mentioning suidperl explicitly, but they may not add any strange
+ * arguments beyond what #! says if they do invoke suidperl that way.
+ */
+ len = strlen(validarg);
+ if (strEQ(validarg," PHOOEY ") ||
+ strnNE(s,validarg,len) || !isSPACE(s[len]))
+ fatal("Args must match #! line");
+
+#ifndef IAMSUID
+ if (euid != uid && (statbuf.st_mode & S_ISUID) &&
+ euid == statbuf.st_uid)
+ if (!do_undump)
+ fatal("YOU HAVEN'T DISABLED SET-ID SCRIPTS IN THE KERNEL YET!\n\
+FIX YOUR KERNEL, PUT A C WRAPPER AROUND THIS SCRIPT, OR USE -u AND UNDUMP!\n");
+#endif /* IAMSUID */
+
+ if (euid) { /* oops, we're not the setuid root perl */
+ (void)fclose(rsfp);
+#ifndef IAMSUID
+ (void)sprintf(buf, "%s/sperl%s", BIN, patchlevel);
+ execv(buf, origargv); /* try again */
+#endif
+ fatal("Can't do setuid\n");
+ }
+
+ if (statbuf.st_mode & S_ISGID && statbuf.st_gid != egid) {
+#ifdef HAS_SETEGID
+ (void)setegid(statbuf.st_gid);
+#else
+#ifdef HAS_SETREGID
+ (void)setregid((GIDTYPE)-1,statbuf.st_gid);
+#else
+ setgid(statbuf.st_gid);
+#endif
+#endif
+ if (getegid() != statbuf.st_gid)
+ fatal("Can't do setegid!\n");
+ }
+ if (statbuf.st_mode & S_ISUID) {
+ if (statbuf.st_uid != euid)
+#ifdef HAS_SETEUID
+ (void)seteuid(statbuf.st_uid); /* all that for this */
+#else
+#ifdef HAS_SETREUID
+ (void)setreuid((UIDTYPE)-1,statbuf.st_uid);
+#else
+ setuid(statbuf.st_uid);
+#endif
+#endif
+ if (geteuid() != statbuf.st_uid)
+ fatal("Can't do seteuid!\n");
+ }
+ else if (uid) { /* oops, mustn't run as root */
+#ifdef HAS_SETEUID
+ (void)seteuid((UIDTYPE)uid);
+#else
+#ifdef HAS_SETREUID
+ (void)setreuid((UIDTYPE)-1,(UIDTYPE)uid);
+#else
+ setuid((UIDTYPE)uid);
+#endif
+#endif
+ if (geteuid() != uid)
+ fatal("Can't do seteuid!\n");
+ }
+ uid = (int)getuid();
+ euid = (int)geteuid();
+ gid = (int)getgid();
+ egid = (int)getegid();
+ if (!cando(S_IXUSR,TRUE,&statbuf))
+ fatal("Permission denied\n"); /* they can't do this */
+ }
+#ifdef IAMSUID
+ else if (preprocess)
+ fatal("-P not allowed for setuid/setgid script\n");
+ else
+ fatal("Script is not setuid/setgid in suidperl\n");
+#else
+#ifndef TAINT /* we aren't taintperl or suidperl */
+ /* script has a wrapper--can't run suidperl or we lose euid */
+ else if (euid != uid || egid != gid) {
+ (void)fclose(rsfp);
+ (void)sprintf(buf, "%s/tperl%s", BIN, patchlevel);
+ execv(buf, origargv); /* try again */
+ fatal("Can't run setuid script with taint checks");
+ }
+#endif /* TAINT */
+#endif /* IAMSUID */
+#else /* !DOSUID */
+#ifndef TAINT /* we aren't taintperl or suidperl */
+ if (euid != uid || egid != gid) { /* (suidperl doesn't exist, in fact) */
+#ifndef SETUID_SCRIPTS_ARE_SECURE_NOW
+ fstat(fileno(rsfp),&statbuf); /* may be either wrapped or real suid */
+ if ((euid != uid && euid == statbuf.st_uid && statbuf.st_mode & S_ISUID)
+ ||
+ (egid != gid && egid == statbuf.st_gid && statbuf.st_mode & S_ISGID)
+ )
+ if (!do_undump)
+ fatal("YOU HAVEN'T DISABLED SET-ID SCRIPTS IN THE KERNEL YET!\n\
+FIX YOUR KERNEL, PUT A C WRAPPER AROUND THIS SCRIPT, OR USE -u AND UNDUMP!\n");
+#endif /* SETUID_SCRIPTS_ARE_SECURE_NOW */
+ /* not set-id, must be wrapped */
+ (void)fclose(rsfp);
+ (void)sprintf(buf, "%s/tperl%s", BIN, patchlevel);
+ execv(buf, origargv); /* try again */
+ fatal("Can't run setuid script with taint checks");
+ }
+#endif /* TAINT */
+#endif /* DOSUID */
+
+#if !defined(IAMSUID) && !defined(TAINT)
+
+ /* skip forward in input to the real script? */
+
+ while (doextract) {
+ if ((s = str_gets(linestr, rsfp, 0)) == Nullch)
+ fatal("No Perl script found in input\n");
+ if (*s == '#' && s[1] == '!' && instr(s,"perl")) {
+ ungetc('\n',rsfp); /* to keep line count right */
+ doextract = FALSE;
+ if (s = instr(s,"perl -")) {
+ s += 6;
+ /*SUPPRESS 530*/
+ while (s = moreswitches(s)) ;
+ }
+ if (cddir && chdir(cddir) < 0)
+ fatal("Can't chdir to %s",cddir);
+ }
+ }
+#endif /* !defined(IAMSUID) && !defined(TAINT) */
+
+ defstab = stabent("_",TRUE);
+
+ subname = str_make("main",4);
+ if (perldb) {
+ debstash = hnew(0);
+ stab_xhash(stabent("_DB",TRUE)) = debstash;
+ curstash = debstash;
+ dbargs = stab_xarray(aadd((tmpstab = stabent("args",TRUE))));
+ tmpstab->str_pok |= SP_MULTI;
+ dbargs->ary_flags = 0;
+ DBstab = stabent("DB",TRUE);
+ DBstab->str_pok |= SP_MULTI;
+ DBline = stabent("dbline",TRUE);
+ DBline->str_pok |= SP_MULTI;
+ DBsub = hadd(tmpstab = stabent("sub",TRUE));
+ tmpstab->str_pok |= SP_MULTI;
+ DBsingle = stab_val((tmpstab = stabent("single",TRUE)));
+ tmpstab->str_pok |= SP_MULTI;
+ DBtrace = stab_val((tmpstab = stabent("trace",TRUE)));
+ tmpstab->str_pok |= SP_MULTI;
+ DBsignal = stab_val((tmpstab = stabent("signal",TRUE)));
+ tmpstab->str_pok |= SP_MULTI;
+ curstash = defstash;
+ }
+
+ /* init tokener */
+
+ bufend = bufptr = str_get(linestr);
+
+ savestack = anew(Nullstab); /* for saving non-local values */
+ stack = anew(Nullstab); /* for saving non-local values */
+ stack->ary_flags = 0; /* not a real array */
+ afill(stack,63); afill(stack,-1); /* preextend stack */
+ afill(savestack,63); afill(savestack,-1);
+
+ /* now parse the script */
+
+ error_count = 0;
+ if (yyparse() || error_count) {
+ if (minus_c)
+ fatal("%s had compilation errors.\n", origfilename);
+ else {
+ fatal("Execution of %s aborted due to compilation errors.\n",
+ origfilename);
+ }
+ }
+
+ New(50,loop_stack,128,struct loop);
+#ifdef DEBUGGING
+ if (debug) {
+ New(51,debname,128,char);
+ New(52,debdelim,128,char);
+ }
+#endif
+ curstash = defstash;
+
+ preprocess = FALSE;
+ if (e_fp) {
+ e_fp = Nullfp;
+ (void)UNLINK(e_tmpname);
+ }
+
+ /* initialize everything that won't change if we undump */
+
+ if (sigstab = stabent("SIG",allstabs)) {
+ sigstab->str_pok |= SP_MULTI;
+ (void)hadd(sigstab);
+ }
+
+ magicalize("!#?^~=-%.+&*()<>,\\/[|`':\004\t\020\024\027\006");
+ userinit(); /* in case linked C routines want magical variables */
+
+ amperstab = stabent("&",allstabs);
+ leftstab = stabent("`",allstabs);
+ rightstab = stabent("'",allstabs);
+ sawampersand = (amperstab || leftstab || rightstab);
+ if (tmpstab = stabent(":",allstabs))
+ str_set(stab_val(tmpstab),chopset);
+ if (tmpstab = stabent("\024",allstabs))
+ time(&basetime);
+
+ /* these aren't necessarily magical */
+ if (tmpstab = stabent("\014",allstabs)) {
+ str_set(stab_val(tmpstab),"\f");
+ formfeed = stab_val(tmpstab);
+ }
+ if (tmpstab = stabent(";",allstabs))
+ str_set(STAB_STR(tmpstab),"\034");
+ if (tmpstab = stabent("]",allstabs)) {
+ str = STAB_STR(tmpstab);
+ str_set(str,rcsid);
+ str->str_u.str_nval = atof(patchlevel);
+ str->str_nok = 1;
+ }
+ str_nset(stab_val(stabent("\"", TRUE)), " ", 1);
+
+ stdinstab = stabent("STDIN",TRUE);
+ stdinstab->str_pok |= SP_MULTI;
+ if (!stab_io(stdinstab))
+ stab_io(stdinstab) = stio_new();
+ stab_io(stdinstab)->ifp = stdin;
+ tmpstab = stabent("stdin",TRUE);
+ stab_io(tmpstab) = stab_io(stdinstab);
+ tmpstab->str_pok |= SP_MULTI;
+
+ tmpstab = stabent("STDOUT",TRUE);
+ tmpstab->str_pok |= SP_MULTI;
+ if (!stab_io(tmpstab))
+ stab_io(tmpstab) = stio_new();
+ stab_io(tmpstab)->ofp = stab_io(tmpstab)->ifp = stdout;
+ defoutstab = tmpstab;
+ tmpstab = stabent("stdout",TRUE);
+ stab_io(tmpstab) = stab_io(defoutstab);
+ tmpstab->str_pok |= SP_MULTI;
+
+ curoutstab = stabent("STDERR",TRUE);
+ curoutstab->str_pok |= SP_MULTI;
+ if (!stab_io(curoutstab))
+ stab_io(curoutstab) = stio_new();
+ stab_io(curoutstab)->ofp = stab_io(curoutstab)->ifp = stderr;
+ tmpstab = stabent("stderr",TRUE);
+ stab_io(tmpstab) = stab_io(curoutstab);
+ tmpstab->str_pok |= SP_MULTI;
+ curoutstab = defoutstab; /* switch back to STDOUT */
+
+ statname = Str_new(66,0); /* last filename we did stat on */
+
+ /* now that script is parsed, we can modify record separator */
+
+ rs = nrs;
+ rslen = nrslen;
+ rschar = nrschar;
+ rspara = (nrslen == 2);
+ str_nset(stab_val(stabent("/", TRUE)), rs, rslen);
+
+ if (do_undump)
+ my_unexec();
+
+ just_doit: /* come here if running an undumped a.out */
+ argc--,argv++; /* skip name of script */
+ if (doswitches) {
+ for (; argc > 0 && **argv == '-'; argc--,argv++) {
+ if (argv[0][1] == '-') {
+ argc--,argv++;
+ break;
+ }
+ if (s = index(argv[0], '=')) {
+ *s++ = '\0';
+ str_set(stab_val(stabent(argv[0]+1,TRUE)),s);
+ }
+ else
+ str_numset(stab_val(stabent(argv[0]+1,TRUE)),(double)1.0);
+ }
+ }
+#ifdef TAINT
+ tainted = 1;
+#endif
+ if (tmpstab = stabent("0",allstabs)) {
+ str_set(stab_val(tmpstab),origfilename);
+ magicname("0", Nullch, 0);
+ }
+ if (tmpstab = stabent("\030",allstabs))
+ str_set(stab_val(tmpstab),origargv[0]);
+ if (argvstab = stabent("ARGV",allstabs)) {
+ argvstab->str_pok |= SP_MULTI;
+ (void)aadd(argvstab);
+ aclear(stab_array(argvstab));
+ for (; argc > 0; argc--,argv++) {
+ (void)apush(stab_array(argvstab),str_make(argv[0],0));
+ }
+ }
+#ifdef TAINT
+ (void) stabent("ENV",TRUE); /* must test PATH and IFS */
+#endif
+ if (envstab = stabent("ENV",allstabs)) {
+ envstab->str_pok |= SP_MULTI;
+ (void)hadd(envstab);
+ hclear(stab_hash(envstab), FALSE);
+ if (env != environ)
+ environ[0] = Nullch;
+ for (; *env; env++) {
+ if (!(s = index(*env,'=')))
+ continue;
+ *s++ = '\0';
+ str = str_make(s--,0);
+ str_magic(str, envstab, 'E', *env, s - *env);
+ (void)hstore(stab_hash(envstab), *env, s - *env, str, 0);
+ *s = '=';
+ }
+ }
+#ifdef TAINT
+ tainted = 0;
+#endif
+ if (tmpstab = stabent("$",allstabs))
+ str_numset(STAB_STR(tmpstab),(double)getpid());
+
+ if (dowarn) {
+ stab_check('A','Z');
+ stab_check('a','z');
+ }
+
+ if (setjmp(top_env)) /* sets goto_targ on longjump */
+ loop_ptr = -1; /* start label stack again */
+
+#ifdef DEBUGGING
+ if (debug & 1024)
+ dump_all();
+ if (debug)
+ fprintf(stderr,"\nEXECUTING...\n\n");
+#endif
+
+ if (minus_c) {
+ fprintf(stderr,"%s syntax OK\n", origfilename);
+ exit(0);
+ }
+
+ /* do it */
+
+ (void) cmd_exec(main_root,G_SCALAR,-1);
+
+ if (goto_targ)
+ fatal("Can't find label \"%s\"--aborting",goto_targ);
+ exit(0);
+ /* NOTREACHED */
+}
+
+void
+magicalize(list)
+register char *list;
+{
+ char sym[2];
+
+ sym[1] = '\0';
+ while (*sym = *list++)
+ magicname(sym, Nullch, 0);
+}
+
+void
+magicname(sym,name,namlen)
+char *sym;
+char *name;
+int namlen;
+{
+ register STAB *stab;
+
+ if (stab = stabent(sym,allstabs)) {
+ stab_flags(stab) = SF_VMAGIC;
+ str_magic(stab_val(stab), stab, 0, name, namlen);
+ }
+}
+
+static void
+incpush(p)
+char *p;
+{
+ char *s;
+
+ if (!p)
+ return;
+
+ /* Break at all separators */
+ while (*p) {
+ /* First, skip any consecutive separators */
+ while ( *p == PERLLIB_SEP ) {
+ /* Uncomment the next line for PATH semantics */
+ /* (void)apush(stab_array(incstab), str_make(".", 1)); */
+ p++;
+ }
+ if ( (s = index(p, PERLLIB_SEP)) != Nullch ) {
+ (void)apush(stab_array(incstab), str_make(p, (int)(s - p)));
+ p = s + 1;
+ } else {
+ (void)apush(stab_array(incstab), str_make(p, 0));
+ break;
+ }
+ }
+}
+
+void
+savelines(array, str)
+ARRAY *array;
+STR *str;
+{
+ register char *s = str->str_ptr;
+ register char *send = str->str_ptr + str->str_cur;
+ register char *t;
+ register int line = 1;
+
+ while (s && s < send) {
+ STR *tmpstr = Str_new(85,0);
+
+ t = index(s, '\n');
+ if (t)
+ t++;
+ else
+ t = send;
+
+ str_nset(tmpstr, s, t - s);
+ astore(array, line++, tmpstr);
+ s = t;
+ }
+}
+
+/* this routine is in perl.c by virtue of being sort of an alternate main() */
+
+int
+do_eval(str,optype,stash,savecmd,gimme,arglast)
+STR *str;
+int optype;
+HASH *stash;
+int savecmd;
+int gimme;
+int *arglast;
+{
+ STR **st = stack->ary_array;
+ int retval;
+ CMD *myroot = Nullcmd;
+ ARRAY *ar;
+ int i;
+ CMD * VOLATILE oldcurcmd = curcmd;
+ VOLATILE int oldtmps_base = tmps_base;
+ VOLATILE int oldsave = savestack->ary_fill;
+ VOLATILE int oldperldb = perldb;
+ SPAT * VOLATILE oldspat = curspat;
+ SPAT * VOLATILE oldlspat = lastspat;
+ static char *last_eval = Nullch;
+ static long last_elen = 0;
+ static CMD *last_root = Nullcmd;
+ VOLATILE int sp = arglast[0];
+ char *specfilename;
+ char *tmpfilename;
+ int parsing = 1;
+
+ tmps_base = tmps_max;
+ if (curstash != stash) {
+ (void)savehptr(&curstash);
+ curstash = stash;
+ }
+ str_set(stab_val(stabent("@",TRUE)),"");
+ if (curcmd->c_line == 0) /* don't debug debugger... */
+ perldb = FALSE;
+ curcmd = &compiling;
+ if (optype == O_EVAL) { /* normal eval */
+ curcmd->c_filestab = fstab("(eval)");
+ curcmd->c_line = 1;
+ str_sset(linestr,str);
+ str_cat(linestr,";\n;\n"); /* be kind to them */
+ if (perldb)
+ savelines(stab_xarray(curcmd->c_filestab), linestr);
+ }
+ else {
+ if (last_root && !in_eval) {
+ Safefree(last_eval);
+ last_eval = Nullch;
+ cmd_free(last_root);
+ last_root = Nullcmd;
+ }
+ specfilename = str_get(str);
+ str_set(linestr,"");
+ if (optype == O_REQUIRE && &str_undef !=
+ hfetch(stab_hash(incstab), specfilename, strlen(specfilename), 0)) {
+ curcmd = oldcurcmd;
+ tmps_base = oldtmps_base;
+ st[++sp] = &str_yes;
+ perldb = oldperldb;
+ return sp;
+ }
+ tmpfilename = savestr(specfilename);
+ if (*tmpfilename == '/' ||
+ (*tmpfilename == '.' &&
+ (tmpfilename[1] == '/' ||
+ (tmpfilename[1] == '.' && tmpfilename[2] == '/'))))
+ {
+ rsfp = fopen(tmpfilename,"r");
+ }
+ else {
+ ar = stab_array(incstab);
+ for (i = 0; i <= ar->ary_fill; i++) {
+ (void)sprintf(buf, "%s/%s",
+ str_get(afetch(ar,i,TRUE)), specfilename);
+ rsfp = fopen(buf,"r");
+ if (rsfp) {
+ char *s = buf;
+
+ if (*s == '.' && s[1] == '/')
+ s += 2;
+ Safefree(tmpfilename);
+ tmpfilename = savestr(s);
+ break;
+ }
+ }
+ }
+ curcmd->c_filestab = fstab(tmpfilename);
+ Safefree(tmpfilename);
+ tmpfilename = Nullch;
+ if (!rsfp) {
+ curcmd = oldcurcmd;
+ tmps_base = oldtmps_base;
+ if (optype == O_REQUIRE) {
+ sprintf(tokenbuf,"Can't locate %s in @INC", specfilename);
+ if (instr(tokenbuf,".h "))
+ strcat(tokenbuf," (change .h to .ph maybe?)");
+ if (instr(tokenbuf,".ph "))
+ strcat(tokenbuf," (did you run h2ph?)");
+ fatal("%s",tokenbuf);
+ }
+ if (gimme != G_ARRAY)
+ st[++sp] = &str_undef;
+ perldb = oldperldb;
+ return sp;
+ }
+ curcmd->c_line = 0;
+ }
+ in_eval++;
+ oldoldbufptr = oldbufptr = bufptr = str_get(linestr);
+ bufend = bufptr + linestr->str_cur;
+ if (++loop_ptr >= loop_max) {
+ loop_max += 128;
+ Renew(loop_stack, loop_max, struct loop);
+ }
+ loop_stack[loop_ptr].loop_label = "_EVAL_";
+ loop_stack[loop_ptr].loop_sp = sp;
+#ifdef DEBUGGING
+ if (debug & 4) {
+ deb("(Pushing label #%d _EVAL_)\n", loop_ptr);
+ }
+#endif
+ eval_root = Nullcmd;
+ if (setjmp(loop_stack[loop_ptr].loop_env)) {
+ retval = 1;
+ }
+ else {
+ error_count = 0;
+ if (rsfp) {
+ retval = yyparse();
+ retval |= error_count;
+ }
+ else if (last_root && last_elen == bufend - bufptr
+ && *bufptr == *last_eval && !bcmp(bufptr,last_eval,last_elen)){
+ retval = 0;
+ eval_root = last_root; /* no point in reparsing */
+ }
+ else if (in_eval == 1 && !savecmd) {
+ if (last_root) {
+ Safefree(last_eval);
+ last_eval = Nullch;
+ cmd_free(last_root);
+ }
+ last_root = Nullcmd;
+ last_elen = bufend - bufptr;
+ last_eval = nsavestr(bufptr, last_elen);
+ retval = yyparse();
+ retval |= error_count;
+ if (!retval)
+ last_root = eval_root;
+ if (!last_root) {
+ Safefree(last_eval);
+ last_eval = Nullch;
+ }
+ }
+ else
+ retval = yyparse();
+ }
+ myroot = eval_root; /* in case cmd_exec does another eval! */
+
+ if (retval || error_count) {
+ st = stack->ary_array;
+ sp = arglast[0];
+ if (gimme != G_ARRAY)
+ st[++sp] = &str_undef;
+ if (parsing) {
+#ifndef MANGLEDPARSE
+#ifdef DEBUGGING
+ if (debug & 128)
+ fprintf(stderr,"Freeing eval_root %lx\n",(long)eval_root);
+#endif
+ cmd_free(eval_root);
+#endif
+ /*SUPPRESS 29*/ /*SUPPRESS 30*/
+ if ((CMD*)eval_root == last_root)
+ last_root = Nullcmd;
+ eval_root = myroot = Nullcmd;
+ }
+ if (rsfp) {
+ fclose(rsfp);
+ rsfp = 0;
+ }
+ }
+ else {
+ parsing = 0;
+ sp = cmd_exec(eval_root,gimme,sp);
+ st = stack->ary_array;
+ for (i = arglast[0] + 1; i <= sp; i++)
+ st[i] = str_mortal(st[i]);
+ /* if we don't save result, free zaps it */
+ if (savecmd)
+ eval_root = myroot;
+ else if (in_eval != 1 && myroot != last_root)
+ cmd_free(myroot);
+ if (eval_root == myroot)
+ eval_root = Nullcmd;
+ }
+
+ perldb = oldperldb;
+ in_eval--;
+#ifdef DEBUGGING
+ if (debug & 4) {
+ char *tmps = loop_stack[loop_ptr].loop_label;
+ deb("(Popping label #%d %s)\n",loop_ptr,
+ tmps ? tmps : "" );
+ }
+#endif
+ loop_ptr--;
+ tmps_base = oldtmps_base;
+ curspat = oldspat;
+ lastspat = oldlspat;
+ if (savestack->ary_fill > oldsave) /* let them use local() */
+ restorelist(oldsave);
+
+ if (optype != O_EVAL) {
+ if (retval) {
+ if (optype == O_REQUIRE)
+ fatal("%s", str_get(stab_val(stabent("@",TRUE))));
+ }
+ else {
+ curcmd = oldcurcmd;
+ if (gimme == G_SCALAR ? str_true(st[sp]) : sp > arglast[0]) {
+ (void)hstore(stab_hash(incstab), specfilename,
+ strlen(specfilename), str_smake(stab_val(curcmd->c_filestab)),
+ 0 );
+ }
+ else if (optype == O_REQUIRE)
+ fatal("%s did not return a true value", specfilename);
+ }
+ }
+ curcmd = oldcurcmd;
+ return sp;
+}
+
+int
+do_try(cmd,gimme,arglast)
+CMD *cmd;
+int gimme;
+int *arglast;
+{
+ STR **st = stack->ary_array;
+
+ CMD * VOLATILE oldcurcmd = curcmd;
+ VOLATILE int oldtmps_base = tmps_base;
+ VOLATILE int oldsave = savestack->ary_fill;
+ SPAT * VOLATILE oldspat = curspat;
+ SPAT * VOLATILE oldlspat = lastspat;
+ VOLATILE int sp = arglast[0];
+
+ tmps_base = tmps_max;
+ str_set(stab_val(stabent("@",TRUE)),"");
+ in_eval++;
+ if (++loop_ptr >= loop_max) {
+ loop_max += 128;
+ Renew(loop_stack, loop_max, struct loop);
+ }
+ loop_stack[loop_ptr].loop_label = "_EVAL_";
+ loop_stack[loop_ptr].loop_sp = sp;
+#ifdef DEBUGGING
+ if (debug & 4) {
+ deb("(Pushing label #%d _EVAL_)\n", loop_ptr);
+ }
+#endif
+ if (setjmp(loop_stack[loop_ptr].loop_env)) {
+ st = stack->ary_array;
+ sp = arglast[0];
+ if (gimme != G_ARRAY)
+ st[++sp] = &str_undef;
+ }
+ else {
+ sp = cmd_exec(cmd,gimme,sp);
+ st = stack->ary_array;
+/* for (i = arglast[0] + 1; i <= sp; i++)
+ st[i] = str_mortal(st[i]); not needed, I think */
+ /* if we don't save result, free zaps it */
+ }
+
+ in_eval--;
+#ifdef DEBUGGING
+ if (debug & 4) {
+ char *tmps = loop_stack[loop_ptr].loop_label;
+ deb("(Popping label #%d %s)\n",loop_ptr,
+ tmps ? tmps : "" );
+ }
+#endif
+ loop_ptr--;
+ tmps_base = oldtmps_base;
+ curspat = oldspat;
+ lastspat = oldlspat;
+ curcmd = oldcurcmd;
+ if (savestack->ary_fill > oldsave) /* let them use local() */
+ restorelist(oldsave);
+
+ return sp;
+}
+
+/* This routine handles any switches that can be given during run */
+
+static char *
+moreswitches(s)
+char *s;
+{
+ int numlen;
+
+ switch (*s) {
+ case '0':
+ nrschar = scanoct(s, 4, &numlen);
+ nrs = nsavestr("\n",1);
+ *nrs = nrschar;
+ if (nrschar > 0377) {
+ nrslen = 0;
+ nrs = "";
+ }
+ else if (!nrschar && numlen >= 2) {
+ nrslen = 2;
+ nrs = "\n\n";
+ nrschar = '\n';
+ }
+ return s + numlen;
+ case 'a':
+ minus_a = TRUE;
+ s++;
+ return s;
+ case 'c':
+ minus_c = TRUE;
+ s++;
+ return s;
+ case 'd':
+#ifdef TAINT
+ if (euid != uid || egid != gid)
+ fatal("No -d allowed in setuid scripts");
+#endif
+ perldb = TRUE;
+ s++;
+ return s;
+ case 'D':
+#ifdef DEBUGGING
+#ifdef TAINT
+ if (euid != uid || egid != gid)
+ fatal("No -D allowed in setuid scripts");
+#endif
+ debug = atoi(s+1) | 32768;
+#else
+ warn("Recompile perl with -DDEBUGGING to use -D switch\n");
+#endif
+ /*SUPPRESS 530*/
+ for (s++; isDIGIT(*s); s++) ;
+ return s;
+ case 'i':
+ inplace = savestr(s+1);
+ /*SUPPRESS 530*/
+ for (s = inplace; *s && !isSPACE(*s); s++) ;
+ *s = '\0';
+ break;
+ case 'I':
+#ifdef TAINT
+ if (euid != uid || egid != gid)
+ fatal("No -I allowed in setuid scripts");
+#endif
+ if (*++s) {
+ (void)apush(stab_array(incstab),str_make(s,0));
+ }
+ else
+ fatal("No space allowed after -I");
+ break;
+ case 'l':
+ minus_l = TRUE;
+ s++;
+ if (isDIGIT(*s)) {
+ ors = savestr("\n");
+ orslen = 1;
+ *ors = scanoct(s, 3 + (*s == '0'), &numlen);
+ s += numlen;
+ }
+ else {
+ ors = nsavestr(nrs,nrslen);
+ orslen = nrslen;
+ }
+ return s;
+ case 'n':
+ minus_n = TRUE;
+ s++;
+ return s;
+ case 'p':
+ minus_p = TRUE;
+ s++;
+ return s;
+ case 'u':
+ do_undump = TRUE;
+ s++;
+ return s;
+ case 'U':
+ unsafe = TRUE;
+ s++;
+ return s;
+ case 'v':
+ fputs("\nThis is perl, version 4.0\n\n",stdout);
+ fputs(rcsid,stdout);
+ fputs("\nCopyright (c) 1989, 1990, 1991, Larry Wall\n",stdout);
+#ifdef MSDOS
+ fputs("MS-DOS port Copyright (c) 1989, 1990, Diomidis Spinellis\n",
+ stdout);
+#ifdef OS2
+ fputs("OS/2 port Copyright (c) 1990, 1991, Raymond Chen, Kai Uwe Rommel\n",
+ stdout);
+#endif
+#endif
+#ifdef atarist
+ fputs("atariST series port, ++jrb bammi@cadence.com\n", stdout);
+#endif
+ fputs("\n\
+Perl may be copied only under the terms of either the Artistic License or the\n\
+GNU General Public License, which may be found in the Perl 4.0 source kit.\n",stdout);
+#ifdef MSDOS
+ usage(origargv[0]);
+#endif
+ exit(0);
+ case 'w':
+ dowarn = TRUE;
+ s++;
+ return s;
+ case ' ':
+ case '\n':
+ case '\t':
+ break;
+ default:
+ fatal("Switch meaningless after -x: -%s",s);
+ }
+ return Nullch;
+}
+
+/* compliments of Tom Christiansen */
+
+/* unexec() can be found in the Gnu emacs distribution */
+
+void
+my_unexec()
+{
+#ifdef UNEXEC
+ int status;
+ extern int etext;
+ static char dumpname[BUFSIZ];
+ static char perlpath[256];
+
+ sprintf (dumpname, "%s.perldump", origfilename);
+ sprintf (perlpath, "%s/perl", BIN);
+
+ status = unexec(dumpname, perlpath, &etext, sbrk(0), 0);
+ if (status)
+ fprintf(stderr, "unexec of %s into %s failed!\n", perlpath, dumpname);
+ exit(status);
+#else
+#ifdef DOSISH
+ abort(); /* nothing else to do */
+#else /* ! MSDOS */
+# ifndef SIGABRT
+# define SIGABRT SIGILL
+# endif
+# ifndef SIGILL
+# define SIGILL 6 /* blech */
+# endif
+ kill(getpid(),SIGABRT); /* for use with undump */
+#endif /* ! MSDOS */
+#endif
+}
+
diff --git a/gnu/usr.bin/perl/perl/perl.h b/gnu/usr.bin/perl/perl/perl.h
new file mode 100644
index 0000000..7693aa0
--- /dev/null
+++ b/gnu/usr.bin/perl/perl/perl.h
@@ -0,0 +1,1066 @@
+/* $RCSfile: perl.h,v $$Revision: 1.1.1.1 $$Date: 1994/09/10 06:27:35 $
+ *
+ * Copyright (c) 1991, Larry Wall
+ *
+ * You may distribute under the terms of either the GNU General Public
+ * License or the Artistic License, as specified in the README file.
+ *
+ * $Log: perl.h,v $
+ * Revision 1.1.1.1 1994/09/10 06:27:35 gclarkii
+ * Initial import of Perl 4.046 bmaked
+ *
+ * Revision 1.1.1.1 1993/08/23 21:29:35 nate
+ * PERL!
+ *
+ * Revision 4.0.1.7 1993/02/05 19:40:30 lwall
+ * patch36: worked around certain busted compilers that don't init statics right
+ *
+ * Revision 4.0.1.6 92/06/08 14:55:10 lwall
+ * patch20: added Atari ST portability
+ * patch20: bcopy() and memcpy() now tested for overlap safety
+ * patch20: Perl now distinguishes overlapped copies from non-overlapped
+ * patch20: removed implicit int declarations on functions
+ *
+ * Revision 4.0.1.5 91/11/11 16:41:07 lwall
+ * patch19: uts wrongly defines S_ISDIR() et al
+ * patch19: too many preprocessors can't expand a macro right in #if
+ * patch19: added little-endian pack/unpack options
+ *
+ * Revision 4.0.1.4 91/11/05 18:06:10 lwall
+ * patch11: various portability fixes
+ * patch11: added support for dbz
+ * patch11: added some support for 64-bit integers
+ * patch11: hex() didn't understand leading 0x
+ *
+ * Revision 4.0.1.3 91/06/10 01:25:10 lwall
+ * patch10: certain pattern optimizations were botched
+ *
+ * Revision 4.0.1.2 91/06/07 11:28:33 lwall
+ * patch4: new copyright notice
+ * patch4: made some allowances for "semi-standard" C
+ * patch4: many, many itty-bitty portability fixes
+ *
+ * Revision 4.0.1.1 91/04/11 17:49:51 lwall
+ * patch1: hopefully straightened out some of the Xenix mess
+ *
+ * Revision 4.0 91/03/20 01:37:56 lwall
+ * 4.0 baseline.
+ *
+ */
+
+#define VOIDWANT 1
+#include "config.h"
+
+#ifdef MYMALLOC
+# ifdef HIDEMYMALLOC
+# define malloc Mymalloc
+# define realloc Myremalloc
+# define free Myfree
+# endif
+# define safemalloc malloc
+# define saferealloc realloc
+# define safefree free
+#endif
+
+/* work around some libPW problems */
+#define fatal Myfatal
+#ifdef DOINIT
+char Error[1];
+#endif
+
+/* define this once if either system, instead of cluttering up the src */
+#if defined(MSDOS) || defined(atarist)
+#define DOSISH 1
+#endif
+
+#ifdef DOSISH
+/* This stuff now in the MS-DOS config.h file. */
+#else /* !MSDOS */
+
+/*
+ * The following symbols are defined if your operating system supports
+ * functions by that name. All Unixes I know of support them, thus they
+ * are not checked by the configuration script, but are directly defined
+ * here.
+ */
+#define HAS_ALARM
+#define HAS_CHOWN
+#define HAS_CHROOT
+#define HAS_FORK
+#define HAS_GETLOGIN
+#define HAS_GETPPID
+#define HAS_KILL
+#define HAS_LINK
+#define HAS_PIPE
+#define HAS_WAIT
+#define HAS_UMASK
+/*
+ * The following symbols are defined if your operating system supports
+ * password and group functions in general. All Unix systems do.
+ */
+#define HAS_GROUP
+#define HAS_PASSWD
+
+#endif /* !MSDOS */
+
+#if defined(__STDC__) || defined(_AIX) || defined(__stdc__)
+# define STANDARD_C 1
+#endif
+
+#if defined(HASVOLATILE) || defined(STANDARD_C)
+#define VOLATILE volatile
+#else
+#define VOLATILE
+#endif
+
+#ifdef IAMSUID
+# ifndef TAINT
+# define TAINT
+# endif
+#endif
+
+#ifndef HAS_VFORK
+# define vfork fork
+#endif
+
+#ifdef HAS_GETPGRP2
+# ifndef HAS_GETPGRP
+# define HAS_GETPGRP
+# endif
+# define getpgrp getpgrp2
+#endif
+
+#ifdef HAS_SETPGRP2
+# ifndef HAS_SETPGRP
+# define HAS_SETPGRP
+# endif
+# define setpgrp setpgrp2
+#endif
+
+#include <stdio.h>
+#include <ctype.h>
+#include <setjmp.h>
+#ifndef MSDOS
+#ifdef PARAM_NEEDS_TYPES
+#include <sys/types.h>
+#endif
+#include <sys/param.h>
+#endif
+#ifdef STANDARD_C
+/* Use all the "standard" definitions */
+#include <stdlib.h>
+#include <string.h>
+#define MEM_SIZE size_t
+#else
+typedef unsigned int MEM_SIZE;
+#endif /* STANDARD_C */
+
+#if defined(HAS_MEMCMP) && defined(mips) && defined(ultrix)
+#undef HAS_MEMCMP
+#endif
+
+#ifdef HAS_MEMCPY
+# ifndef STANDARD_C
+# ifndef memcpy
+ extern char * memcpy();
+# endif
+# endif
+#else
+# ifndef memcpy
+# ifdef HAS_BCOPY
+# define memcpy(d,s,l) bcopy(s,d,l)
+# else
+# define memcpy(d,s,l) my_bcopy(s,d,l)
+# endif
+# endif
+#endif /* HAS_MEMCPY */
+
+#ifdef HAS_MEMSET
+# ifndef STANDARD_C
+# ifndef memset
+ extern char *memset();
+# endif
+# endif
+# define memzero(d,l) memset(d,0,l)
+#else
+# ifndef memzero
+# ifdef HAS_BZERO
+# define memzero(d,l) bzero(d,l)
+# else
+# define memzero(d,l) my_bzero(d,l)
+# endif
+# endif
+#endif /* HAS_MEMSET */
+
+#ifdef HAS_MEMCMP
+# ifndef STANDARD_C
+# ifndef memcmp
+ extern int memcmp();
+# endif
+# endif
+#else
+# ifndef memcmp
+# define memcmp(s1,s2,l) my_memcmp(s1,s2,l)
+# endif
+#endif /* HAS_MEMCMP */
+
+/* we prefer bcmp slightly for comparisons that don't care about ordering */
+#ifndef HAS_BCMP
+# ifndef bcmp
+# define bcmp(s1,s2,l) memcmp(s1,s2,l)
+# endif
+#endif /* HAS_BCMP */
+
+#ifndef HAS_MEMMOVE
+#if defined(HAS_BCOPY) && defined(SAFE_BCOPY)
+#define memmove(d,s,l) bcopy(s,d,l)
+#else
+#if defined(HAS_MEMCPY) && defined(SAFE_MEMCPY)
+#define memmove(d,s,l) memcpy(d,s,l)
+#else
+#define memmove(d,s,l) my_bcopy(s,d,l)
+#endif
+#endif
+#endif
+
+#ifndef _TYPES_ /* If types.h defines this it's easy. */
+#ifndef major /* Does everyone's types.h define this? */
+#include <sys/types.h>
+#endif
+#endif
+
+#ifdef I_NETINET_IN
+#include <netinet/in.h>
+#endif
+
+#include <sys/stat.h>
+#if defined(uts) || defined(UTekV)
+#undef S_ISDIR
+#undef S_ISCHR
+#undef S_ISBLK
+#undef S_ISREG
+#undef S_ISFIFO
+#undef S_ISLNK
+#define S_ISDIR(P) (((P)&S_IFMT)==S_IFDIR)
+#define S_ISCHR(P) (((P)&S_IFMT)==S_IFCHR)
+#define S_ISBLK(P) (((P)&S_IFMT)==S_IFBLK)
+#define S_ISREG(P) (((P)&S_IFMT)==S_IFREG)
+#define S_ISFIFO(P) (((P)&S_IFMT)==S_IFIFO)
+#ifdef S_IFLNK
+#define S_ISLNK(P) (((P)&S_IFMT)==S_IFLNK)
+#endif
+#endif
+
+#ifdef I_TIME
+# include <time.h>
+#endif
+
+#ifdef I_SYS_TIME
+# ifdef SYSTIMEKERNEL
+# define KERNEL
+# endif
+# include <sys/time.h>
+# ifdef SYSTIMEKERNEL
+# undef KERNEL
+# endif
+#endif
+
+#ifndef MSDOS
+#include <sys/times.h>
+#endif
+
+#if defined(HAS_STRERROR) && (!defined(HAS_MKDIR) || !defined(HAS_RMDIR))
+#undef HAS_STRERROR
+#endif
+
+#include <errno.h>
+#ifndef MSDOS
+#ifndef errno
+extern int errno; /* ANSI allows errno to be an lvalue expr */
+#endif
+#endif
+
+#ifndef strerror
+#ifdef HAS_STRERROR
+char *strerror();
+#else
+extern int sys_nerr;
+extern char *sys_errlist[];
+#define strerror(e) ((e) < 0 || (e) >= sys_nerr ? "(unknown)" : sys_errlist[e])
+#endif
+#endif
+
+#ifdef I_SYSIOCTL
+#ifndef _IOCTL_
+#include <sys/ioctl.h>
+#endif
+#endif
+
+#if defined(mc300) || defined(mc500) || defined(mc700) || defined(mc6000)
+#ifdef HAS_SOCKETPAIR
+#undef HAS_SOCKETPAIR
+#endif
+#ifdef HAS_NDBM
+#undef HAS_NDBM
+#endif
+#endif
+
+#ifdef WANT_DBZ
+#include <dbz.h>
+#define SOME_DBM
+#define dbm_fetch(db,dkey) fetch(dkey)
+#define dbm_delete(db,dkey) fatal("dbz doesn't implement delete")
+#define dbm_store(db,dkey,dcontent,flags) store(dkey,dcontent)
+#define dbm_close(db) dbmclose()
+#define dbm_firstkey(db) (fatal("dbz doesn't implement traversal"),fetch())
+#define nextkey() (fatal("dbz doesn't implement traversal"),fetch())
+#define dbm_nextkey(db) (fatal("dbz doesn't implement traversal"),fetch())
+#ifdef HAS_NDBM
+#undef HAS_NDBM
+#endif
+#ifndef HAS_ODBM
+#define HAS_ODBM
+#endif
+#else
+#ifdef HAS_GDBM
+#ifdef I_GDBM
+#include <gdbm.h>
+#endif
+#define SOME_DBM
+#ifdef HAS_NDBM
+#undef HAS_NDBM
+#endif
+#ifdef HAS_ODBM
+#undef HAS_ODBM
+#endif
+#else
+#ifdef HAS_NDBM
+#include <ndbm.h>
+#define SOME_DBM
+#ifdef HAS_ODBM
+#undef HAS_ODBM
+#endif
+#else
+#ifdef HAS_ODBM
+#ifdef NULL
+#undef NULL /* suppress redefinition message */
+#endif
+#include <dbm.h>
+#ifdef NULL
+#undef NULL
+#endif
+#define NULL 0 /* silly thing is, we don't even use this */
+#define SOME_DBM
+#define dbm_fetch(db,dkey) fetch(dkey)
+#define dbm_delete(db,dkey) delete(dkey)
+#define dbm_store(db,dkey,dcontent,flags) store(dkey,dcontent)
+#define dbm_close(db) dbmclose()
+#define dbm_firstkey(db) firstkey()
+#endif /* HAS_ODBM */
+#endif /* HAS_NDBM */
+#endif /* HAS_GDBM */
+#endif /* WANT_DBZ */
+#ifdef SOME_DBM
+EXT char *dbmkey;
+EXT int dbmlen;
+#endif
+
+#if INTSIZE == 2
+#define htoni htons
+#define ntohi ntohs
+#else
+#define htoni htonl
+#define ntohi ntohl
+#endif
+
+#if defined(I_DIRENT)
+# include <dirent.h>
+# define DIRENT dirent
+#else
+# ifdef I_SYS_NDIR
+# include <sys/ndir.h>
+# define DIRENT direct
+# else
+# ifdef I_SYS_DIR
+# ifdef hp9000s500
+# include <ndir.h> /* may be wrong in the future */
+# else
+# include <sys/dir.h>
+# endif
+# define DIRENT direct
+# endif
+# endif
+#endif
+
+#ifdef FPUTS_BOTCH
+/* work around botch in SunOS 4.0.1 and 4.0.2 */
+# ifndef fputs
+# define fputs(str,fp) fprintf(fp,"%s",str)
+# endif
+#endif
+
+/*
+ * The following gobbledygook brought to you on behalf of __STDC__.
+ * (I could just use #ifndef __STDC__, but this is more bulletproof
+ * in the face of half-implementations.)
+ */
+
+#ifndef S_IFMT
+# ifdef _S_IFMT
+# define S_IFMT _S_IFMT
+# else
+# define S_IFMT 0170000
+# endif
+#endif
+
+#ifndef S_ISDIR
+# define S_ISDIR(m) ((m & S_IFMT) == S_IFDIR)
+#endif
+
+#ifndef S_ISCHR
+# define S_ISCHR(m) ((m & S_IFMT) == S_IFCHR)
+#endif
+
+#ifndef S_ISBLK
+# ifdef S_IFBLK
+# define S_ISBLK(m) ((m & S_IFMT) == S_IFBLK)
+# else
+# define S_ISBLK(m) (0)
+# endif
+#endif
+
+#ifndef S_ISREG
+# define S_ISREG(m) ((m & S_IFMT) == S_IFREG)
+#endif
+
+#ifndef S_ISFIFO
+# ifdef S_IFIFO
+# define S_ISFIFO(m) ((m & S_IFMT) == S_IFIFO)
+# else
+# define S_ISFIFO(m) (0)
+# endif
+#endif
+
+#ifndef S_ISLNK
+# ifdef _S_ISLNK
+# define S_ISLNK(m) _S_ISLNK(m)
+# else
+# ifdef _S_IFLNK
+# define S_ISLNK(m) ((m & S_IFMT) == _S_IFLNK)
+# else
+# ifdef S_IFLNK
+# define S_ISLNK(m) ((m & S_IFMT) == S_IFLNK)
+# else
+# define S_ISLNK(m) (0)
+# endif
+# endif
+# endif
+#endif
+
+#ifndef S_ISSOCK
+# ifdef _S_ISSOCK
+# define S_ISSOCK(m) _S_ISSOCK(m)
+# else
+# ifdef _S_IFSOCK
+# define S_ISSOCK(m) ((m & S_IFMT) == _S_IFSOCK)
+# else
+# ifdef S_IFSOCK
+# define S_ISSOCK(m) ((m & S_IFMT) == S_IFSOCK)
+# else
+# define S_ISSOCK(m) (0)
+# endif
+# endif
+# endif
+#endif
+
+#ifndef S_IRUSR
+# ifdef S_IREAD
+# define S_IRUSR S_IREAD
+# define S_IWUSR S_IWRITE
+# define S_IXUSR S_IEXEC
+# else
+# define S_IRUSR 0400
+# define S_IWUSR 0200
+# define S_IXUSR 0100
+# endif
+# define S_IRGRP (S_IRUSR>>3)
+# define S_IWGRP (S_IWUSR>>3)
+# define S_IXGRP (S_IXUSR>>3)
+# define S_IROTH (S_IRUSR>>6)
+# define S_IWOTH (S_IWUSR>>6)
+# define S_IXOTH (S_IXUSR>>6)
+#endif
+
+#ifndef S_ISUID
+# define S_ISUID 04000
+#endif
+
+#ifndef S_ISGID
+# define S_ISGID 02000
+#endif
+
+#ifdef f_next
+#undef f_next
+#endif
+
+#if defined(cray) || defined(gould) || defined(i860)
+# define SLOPPYDIVIDE
+#endif
+
+#if defined(cray) || defined(convex) || defined (uts) || BYTEORDER > 0xffff
+# define QUAD
+#endif
+
+#ifdef QUAD
+# ifdef cray
+# define quad int
+# else
+# if defined(convex) || defined (uts)
+# define quad long long
+# else
+# define quad long
+# endif
+# endif
+#endif
+
+typedef MEM_SIZE STRLEN;
+
+typedef struct arg ARG;
+typedef struct cmd CMD;
+typedef struct formcmd FCMD;
+typedef struct scanpat SPAT;
+typedef struct stio STIO;
+typedef struct sub SUBR;
+typedef struct string STR;
+typedef struct atbl ARRAY;
+typedef struct htbl HASH;
+typedef struct regexp REGEXP;
+typedef struct stabptrs STBP;
+typedef struct stab STAB;
+typedef struct callsave CSV;
+
+#include "handy.h"
+#include "regexp.h"
+#include "str.h"
+#include "util.h"
+#include "form.h"
+#include "stab.h"
+#include "spat.h"
+#include "arg.h"
+#include "cmd.h"
+#include "array.h"
+#include "hash.h"
+
+#if defined(iAPX286) || defined(M_I286) || defined(I80286)
+# define I286
+#endif
+
+#ifndef STANDARD_C
+#ifdef CHARSPRINTF
+ char *sprintf();
+#else
+ int sprintf();
+#endif
+#endif
+
+EXT char *Yes INIT("1");
+EXT char *No INIT("");
+
+/* "gimme" values */
+
+/* Note: cmd.c assumes that it can use && to produce one of these values! */
+#define G_SCALAR 0
+#define G_ARRAY 1
+
+#ifdef CRIPPLED_CC
+int str_true();
+#else /* !CRIPPLED_CC */
+#define str_true(str) (Str = (str), \
+ (Str->str_pok ? \
+ ((*Str->str_ptr > '0' || \
+ Str->str_cur > 1 || \
+ (Str->str_cur && *Str->str_ptr != '0')) ? 1 : 0) \
+ : \
+ (Str->str_nok ? (Str->str_u.str_nval != 0.0) : 0 ) ))
+#endif /* CRIPPLED_CC */
+
+#ifdef DEBUGGING
+#define str_peek(str) (Str = (str), \
+ (Str->str_pok ? \
+ Str->str_ptr : \
+ (Str->str_nok ? \
+ (sprintf(tokenbuf,"num(%g)",Str->str_u.str_nval), \
+ (char*)tokenbuf) : \
+ "" )))
+#endif
+
+#ifdef CRIPPLED_CC
+char *str_get();
+#else
+#ifdef TAINT
+#define str_get(str) (Str = (str), tainted |= Str->str_tainted, \
+ (Str->str_pok ? Str->str_ptr : str_2ptr(Str)))
+#else
+#define str_get(str) (Str = (str), (Str->str_pok ? Str->str_ptr : str_2ptr(Str)))
+#endif /* TAINT */
+#endif /* CRIPPLED_CC */
+
+#ifdef CRIPPLED_CC
+double str_gnum();
+#else /* !CRIPPLED_CC */
+#ifdef TAINT
+#define str_gnum(str) (Str = (str), tainted |= Str->str_tainted, \
+ (Str->str_nok ? Str->str_u.str_nval : str_2num(Str)))
+#else /* !TAINT */
+#define str_gnum(str) (Str = (str), (Str->str_nok ? Str->str_u.str_nval : str_2num(Str)))
+#endif /* TAINT*/
+#endif /* CRIPPLED_CC */
+EXT STR *Str;
+
+#define GROWSTR(pp,lp,len) if (*(lp) < (len)) growstr(pp,lp,len)
+
+#ifndef DOSISH
+#define STR_GROW(str,len) if ((str)->str_len < (len)) str_grow(str,len)
+#define Str_Grow str_grow
+#else
+/* extra parentheses intentionally NOT placed around "len"! */
+#define STR_GROW(str,len) if ((str)->str_len < (unsigned long)len) \
+ str_grow(str,(unsigned long)len)
+#define Str_Grow(str,len) str_grow(str,(unsigned long)(len))
+#endif /* DOSISH */
+
+#ifndef BYTEORDER
+#define BYTEORDER 0x1234
+#endif
+
+#if defined(htonl) && !defined(HAS_HTONL)
+#define HAS_HTONL
+#endif
+#if defined(htons) && !defined(HAS_HTONS)
+#define HAS_HTONS
+#endif
+#if defined(ntohl) && !defined(HAS_NTOHL)
+#define HAS_NTOHL
+#endif
+#if defined(ntohs) && !defined(HAS_NTOHS)
+#define HAS_NTOHS
+#endif
+#ifndef HAS_HTONL
+#if (BYTEORDER & 0xffff) != 0x4321
+#define HAS_HTONS
+#define HAS_HTONL
+#define HAS_NTOHS
+#define HAS_NTOHL
+#define MYSWAP
+#define htons my_swap
+#define htonl my_htonl
+#define ntohs my_swap
+#define ntohl my_ntohl
+#endif
+#else
+#if (BYTEORDER & 0xffff) == 0x4321
+#undef HAS_HTONS
+#undef HAS_HTONL
+#undef HAS_NTOHS
+#undef HAS_NTOHL
+#endif
+#endif
+
+/*
+ * Little-endian byte order functions - 'v' for 'VAX', or 'reVerse'.
+ * -DWS
+ */
+#if BYTEORDER != 0x1234
+# define HAS_VTOHL
+# define HAS_VTOHS
+# define HAS_HTOVL
+# define HAS_HTOVS
+# if BYTEORDER == 0x4321
+# define vtohl(x) ((((x)&0xFF)<<24) \
+ +(((x)>>24)&0xFF) \
+ +(((x)&0x0000FF00)<<8) \
+ +(((x)&0x00FF0000)>>8) )
+# define vtohs(x) ((((x)&0xFF)<<8) + (((x)>>8)&0xFF))
+# define htovl(x) vtohl(x)
+# define htovs(x) vtohs(x)
+# endif
+ /* otherwise default to functions in util.c */
+#endif
+
+#ifdef CASTNEGFLOAT
+#define U_S(what) ((unsigned short)(what))
+#define U_I(what) ((unsigned int)(what))
+#define U_L(what) ((unsigned long)(what))
+#else
+unsigned long castulong();
+#define U_S(what) ((unsigned int)castulong(what))
+#define U_I(what) ((unsigned int)castulong(what))
+#define U_L(what) (castulong(what))
+#endif
+
+CMD *add_label();
+CMD *block_head();
+CMD *append_line();
+CMD *make_acmd();
+CMD *make_ccmd();
+CMD *make_icmd();
+CMD *invert();
+CMD *addcond();
+CMD *addloop();
+CMD *wopt();
+CMD *over();
+
+STAB *stabent();
+STAB *genstab();
+
+ARG *stab2arg();
+ARG *op_new();
+ARG *make_op();
+ARG *make_match();
+ARG *make_split();
+ARG *rcatmaybe();
+ARG *listish();
+ARG *maybelistish();
+ARG *localize();
+ARG *fixeval();
+ARG *jmaybe();
+ARG *l();
+ARG *fixl();
+ARG *mod_match();
+ARG *make_list();
+ARG *cmd_to_arg();
+ARG *addflags();
+ARG *hide_ary();
+ARG *cval_to_arg();
+
+STR *str_new();
+STR *stab_str();
+
+int apply();
+int do_each();
+int do_subr();
+int do_match();
+int do_unpack();
+int eval(); /* this evaluates expressions */
+int do_eval(); /* this evaluates eval operator */
+int do_assign();
+
+SUBR *make_sub();
+
+FCMD *load_format();
+
+char *scanpat();
+char *scansubst();
+char *scantrans();
+char *scanstr();
+char *scanident();
+char *str_append_till();
+char *str_gets();
+char *str_grow();
+
+bool do_open();
+bool do_close();
+bool do_print();
+bool do_aprint();
+bool do_exec();
+bool do_aexec();
+
+int do_subst();
+int cando();
+int ingroup();
+int whichsig();
+int userinit();
+#ifdef CRYPTSCRIPT
+void cryptswitch();
+#endif
+
+void str_replace();
+void str_inc();
+void str_dec();
+void str_free();
+void cmd_free();
+void arg_free();
+void spat_free();
+void regfree();
+void stab_clear();
+void do_chop();
+void do_vop();
+void do_write();
+void do_join();
+void do_sprintf();
+void do_accept();
+void do_pipe();
+void do_vecset();
+void do_unshift();
+void do_execfree();
+void magicalize();
+void magicname();
+void savelist();
+void saveitem();
+void saveint();
+void savelong();
+void savesptr();
+void savehptr();
+void restorelist();
+void repeatcpy();
+void make_form();
+void dehoist();
+void format();
+void my_unexec();
+void fatal();
+void warn();
+#ifdef DEBUGGING
+void dump_all();
+void dump_cmd();
+void dump_arg();
+void dump_flags();
+void dump_stab();
+void dump_spat();
+#endif
+#ifdef MSTATS
+void mstats();
+#endif
+
+HASH *savehash();
+ARRAY *saveary();
+
+EXT char **origargv;
+EXT int origargc;
+EXT char **origenviron;
+extern char **environ;
+
+EXT long subline INIT(0);
+EXT STR *subname INIT(Nullstr);
+EXT int arybase INIT(0);
+
+struct outrec {
+ long o_lines;
+ char *o_str;
+ int o_len;
+};
+
+EXT struct outrec outrec;
+EXT struct outrec toprec;
+
+EXT STAB *stdinstab INIT(Nullstab);
+EXT STAB *last_in_stab INIT(Nullstab);
+EXT STAB *defstab INIT(Nullstab);
+EXT STAB *argvstab INIT(Nullstab);
+EXT STAB *envstab INIT(Nullstab);
+EXT STAB *sigstab INIT(Nullstab);
+EXT STAB *defoutstab INIT(Nullstab);
+EXT STAB *curoutstab INIT(Nullstab);
+EXT STAB *argvoutstab INIT(Nullstab);
+EXT STAB *incstab INIT(Nullstab);
+EXT STAB *leftstab INIT(Nullstab);
+EXT STAB *amperstab INIT(Nullstab);
+EXT STAB *rightstab INIT(Nullstab);
+EXT STAB *DBstab INIT(Nullstab);
+EXT STAB *DBline INIT(Nullstab);
+EXT STAB *DBsub INIT(Nullstab);
+
+EXT HASH *defstash; /* main symbol table */
+EXT HASH *curstash; /* symbol table for current package */
+EXT HASH *debstash; /* symbol table for perldb package */
+
+EXT STR *curstname; /* name of current package */
+
+EXT STR *freestrroot INIT(Nullstr);
+EXT STR *lastretstr INIT(Nullstr);
+EXT STR *DBsingle INIT(Nullstr);
+EXT STR *DBtrace INIT(Nullstr);
+EXT STR *DBsignal INIT(Nullstr);
+EXT STR *formfeed INIT(Nullstr);
+
+EXT int lastspbase;
+EXT int lastsize;
+
+EXT char *hexdigit INIT("0123456789abcdef0123456789ABCDEFx");
+EXT char *origfilename;
+EXT FILE * VOLATILE rsfp INIT(Nullfp);
+EXT char buf[1024];
+EXT char *bufptr;
+EXT char *oldbufptr;
+EXT char *oldoldbufptr;
+EXT char *bufend;
+
+EXT STR *linestr INIT(Nullstr);
+
+EXT char *rs INIT("\n");
+EXT int rschar INIT('\n'); /* final char of rs, or 0777 if none */
+EXT int rslen INIT(1);
+EXT bool rspara INIT(FALSE);
+EXT char *ofs INIT(Nullch);
+EXT int ofslen INIT(0);
+EXT char *ors INIT(Nullch);
+EXT int orslen INIT(0);
+EXT char *ofmt INIT(Nullch);
+EXT char *inplace INIT(Nullch);
+EXT char *nointrp INIT("");
+
+EXT bool preprocess INIT(FALSE);
+EXT bool minus_n INIT(FALSE);
+EXT bool minus_p INIT(FALSE);
+EXT bool minus_l INIT(FALSE);
+EXT bool minus_a INIT(FALSE);
+EXT bool doswitches INIT(FALSE);
+EXT bool dowarn INIT(FALSE);
+EXT bool doextract INIT(FALSE);
+EXT bool allstabs INIT(FALSE); /* init all customary symbols in symbol table?*/
+EXT bool sawampersand INIT(FALSE); /* must save all match strings */
+EXT bool sawstudy INIT(FALSE); /* do fbminstr on all strings */
+EXT bool sawi INIT(FALSE); /* study must assume case insensitive */
+EXT bool sawvec INIT(FALSE);
+EXT bool localizing INIT(FALSE); /* are we processing a local() list? */
+
+#ifndef MAXSYSFD
+# define MAXSYSFD 2
+#endif
+EXT int maxsysfd INIT(MAXSYSFD); /* top fd to pass to subprocesses */
+
+#ifdef CSH
+EXT char *cshname INIT(CSH);
+EXT int cshlen INIT(0);
+#endif /* CSH */
+
+#ifdef TAINT
+EXT bool tainted INIT(FALSE); /* using variables controlled by $< */
+EXT bool taintanyway INIT(FALSE); /* force taint checks when !set?id */
+#endif
+
+EXT bool nomemok INIT(FALSE); /* let malloc context handle nomem */
+
+#ifndef DOSISH
+#define TMPPATH "/tmp/perl-eXXXXXX"
+#else
+#define TMPPATH "plXXXXXX"
+#endif /* MSDOS */
+EXT char *e_tmpname;
+EXT FILE *e_fp INIT(Nullfp);
+
+EXT char tokenbuf[256];
+EXT int expectterm INIT(TRUE); /* how to interpret ambiguous tokens */
+EXT VOLATILE int in_eval INIT(FALSE); /* trap fatal errors? */
+EXT int multiline INIT(0); /* $*--do strings hold >1 line? */
+EXT int forkprocess; /* so do_open |- can return proc# */
+EXT int do_undump INIT(0); /* -u or dump seen? */
+EXT int error_count INIT(0); /* how many errors so far, max 10 */
+EXT int multi_start INIT(0); /* 1st line of multi-line string */
+EXT int multi_end INIT(0); /* last line of multi-line string */
+EXT int multi_open INIT(0); /* delimiter of said string */
+EXT int multi_close INIT(0); /* delimiter of said string */
+
+FILE *popen();
+/* char *str_get(); */
+STR *interp();
+void free_arg();
+STIO *stio_new();
+void hoistmust();
+void scanconst();
+
+EXT struct stat statbuf;
+EXT struct stat statcache;
+EXT STAB *statstab INIT(Nullstab);
+EXT STR *statname INIT(Nullstr);
+#ifndef MSDOS
+EXT struct tms timesbuf;
+#endif
+EXT int uid;
+EXT int euid;
+EXT int gid;
+EXT int egid;
+UIDTYPE getuid();
+UIDTYPE geteuid();
+GIDTYPE getgid();
+GIDTYPE getegid();
+EXT int unsafe;
+
+#ifdef DEBUGGING
+EXT VOLATILE int debug INIT(0);
+EXT int dlevel INIT(0);
+EXT int dlmax INIT(128);
+EXT char *debname;
+EXT char *debdelim;
+#define YYDEBUG 1
+#endif
+EXT int perldb INIT(0);
+#define YYMAXDEPTH 300
+
+EXT line_t cmdline INIT(NOLINE);
+
+EXT STR str_undef;
+EXT STR str_no;
+EXT STR str_yes;
+
+/* runtime control stuff */
+
+EXT struct loop {
+ char *loop_label; /* what the loop was called, if anything */
+ int loop_sp; /* stack pointer to copy stuff down to */
+ jmp_buf loop_env;
+} *loop_stack;
+
+EXT int loop_ptr INIT(-1);
+EXT int loop_max INIT(128);
+
+EXT jmp_buf top_env;
+
+EXT char * VOLATILE goto_targ INIT(Nullch); /* cmd_exec gets strange when set */
+
+struct ufuncs {
+ int (*uf_val)();
+ int (*uf_set)();
+ int uf_index;
+};
+
+EXT ARRAY *stack; /* THE STACK */
+
+EXT ARRAY * VOLATILE savestack; /* to save non-local values on */
+
+EXT ARRAY *tosave; /* strings to save on recursive subroutine */
+
+EXT ARRAY *lineary; /* lines of script for debugger */
+EXT ARRAY *dbargs; /* args to call listed by caller function */
+
+EXT ARRAY *fdpid; /* keep fd-to-pid mappings for mypopen */
+EXT HASH *pidstatus; /* keep pid-to-status mappings for waitpid */
+
+EXT int *di; /* for tmp use in debuggers */
+EXT char *dc;
+EXT short *ds;
+
+/* Fix these up for __STDC__ */
+EXT time_t basetime INIT(0);
+char *mktemp();
+#ifndef STANDARD_C
+/* All of these are in stdlib.h or time.h for ANSI C */
+double atof();
+long time();
+struct tm *gmtime(), *localtime();
+char *index(), *rindex();
+char *strcpy(), *strcat();
+#endif /* ! STANDARD_C */
+
+#ifdef EUNICE
+#define UNLINK unlnk
+int unlnk();
+#else
+#define UNLINK unlink
+#endif
+
+#ifndef HAS_SETREUID
+#ifdef HAS_SETRESUID
+#define setreuid(r,e) setresuid(r,e,-1)
+#define HAS_SETREUID
+#endif
+#endif
+#ifndef HAS_SETREGID
+#ifdef HAS_SETRESGID
+#define setregid(r,e) setresgid(r,e,-1)
+#define HAS_SETREGID
+#endif
+#endif
+
+#define SCAN_DEF 0
+#define SCAN_TR 1
+#define SCAN_REPL 2
diff --git a/gnu/usr.bin/perl/perl/perly.c b/gnu/usr.bin/perl/perl/perly.c
new file mode 100644
index 0000000..9e314cd
--- /dev/null
+++ b/gnu/usr.bin/perl/perl/perly.c
@@ -0,0 +1,3063 @@
+#ifndef lint
+static char yysccsid[] = "@(#)yaccpar 1.9 (Berkeley) 02/21/93";
+#endif
+#define YYBYACC 1
+#define YYMAJOR 1
+#define YYMINOR 9
+#define yyclearin (yychar=(-1))
+#define yyerrok (yyerrflag=0)
+#define YYRECOVERING (yyerrflag!=0)
+#define YYPREFIX "yy"
+#line 43 "perly.y"
+#include "INTERN.h"
+#include "perl.h"
+
+/*SUPPRESS 530*/
+/*SUPPRESS 593*/
+/*SUPPRESS 595*/
+
+STAB *scrstab;
+ARG *arg4; /* rarely used arguments to make_op() */
+ARG *arg5;
+
+#line 58 "perly.y"
+typedef union {
+ int ival;
+ char *cval;
+ ARG *arg;
+ CMD *cmdval;
+ struct compcmd compval;
+ STAB *stabval;
+ FCMD *formval;
+} YYSTYPE;
+#line 34 "y.tab.c"
+#define WORD 257
+#define LABEL 258
+#define APPEND 259
+#define OPEN 260
+#define SSELECT 261
+#define LOOPEX 262
+#define DOTDOT 263
+#define USING 264
+#define FORMAT 265
+#define DO 266
+#define SHIFT 267
+#define PUSH 268
+#define POP 269
+#define LVALFUN 270
+#define WHILE 271
+#define UNTIL 272
+#define IF 273
+#define UNLESS 274
+#define ELSE 275
+#define ELSIF 276
+#define CONTINUE 277
+#define SPLIT 278
+#define FLIST 279
+#define FOR 280
+#define FILOP 281
+#define FILOP2 282
+#define FILOP3 283
+#define FILOP4 284
+#define FILOP22 285
+#define FILOP25 286
+#define FUNC0 287
+#define FUNC1 288
+#define FUNC2 289
+#define FUNC2x 290
+#define FUNC3 291
+#define FUNC4 292
+#define FUNC5 293
+#define HSHFUN 294
+#define HSHFUN3 295
+#define FLIST2 296
+#define SUB 297
+#define FILETEST 298
+#define LOCAL 299
+#define DELETE 300
+#define RELOP 301
+#define EQOP 302
+#define MULOP 303
+#define ADDOP 304
+#define PACKAGE 305
+#define AMPER 306
+#define FORMLIST 307
+#define REG 308
+#define ARYLEN 309
+#define ARY 310
+#define HSH 311
+#define STAR 312
+#define SUBST 313
+#define PATTERN 314
+#define RSTRING 315
+#define TRANS 316
+#define LISTOP 317
+#define OROR 318
+#define ANDAND 319
+#define UNIOP 320
+#define LS 321
+#define RS 322
+#define MATCH 323
+#define NMATCH 324
+#define UMINUS 325
+#define POW 326
+#define INC 327
+#define DEC 328
+#define YYERRCODE 256
+short yylhs[] = { -1,
+ 26, 0, 25, 25, 12, 12, 12, 5, 3, 6,
+ 6, 7, 7, 7, 7, 7, 10, 10, 10, 10,
+ 10, 10, 9, 9, 9, 9, 8, 8, 8, 8,
+ 8, 8, 8, 8, 11, 11, 21, 21, 24, 24,
+ 1, 1, 1, 2, 2, 27, 28, 15, 13, 13,
+ 16, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+ 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+ 14, 14, 14, 14, 14, 14, 14, 17, 17, 17,
+ 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
+ 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
+ 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
+ 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
+ 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
+ 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
+ 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
+ 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
+ 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
+ 17, 22, 22, 22, 22, 22, 22, 18, 18, 19,
+ 19, 20, 20, 4, 4, 23,
+};
+short yylen[] = { 2,
+ 0, 2, 3, 2, 0, 2, 5, 4, 0, 0,
+ 2, 1, 2, 1, 2, 3, 1, 1, 3, 3,
+ 3, 3, 5, 5, 3, 3, 6, 6, 4, 4,
+ 7, 6, 10, 2, 0, 1, 0, 1, 0, 1,
+ 1, 1, 1, 4, 3, 3, 3, 2, 3, 1,
+ 2, 3, 4, 4, 4, 4, 4, 4, 4, 4,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 5, 3, 3, 1, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 1, 4, 3,
+ 2, 2, 2, 1, 1, 4, 1, 1, 5, 6,
+ 5, 4, 5, 6, 8, 1, 1, 1, 1, 1,
+ 5, 5, 4, 4, 2, 5, 5, 4, 4, 2,
+ 1, 2, 1, 2, 2, 1, 2, 4, 7, 2,
+ 4, 5, 4, 2, 2, 3, 1, 5, 6, 6,
+ 7, 9, 6, 2, 4, 2, 4, 1, 1, 6,
+ 5, 4, 5, 4, 2, 1, 1, 3, 3, 4,
+ 5, 5, 6, 6, 7, 8, 4, 2, 6, 1,
+ 1, 1, 2, 2, 3, 3, 3, 1, 1, 1,
+ 1, 1, 1, 2, 1, 1,
+};
+short yydefred[] = { 1,
+ 0, 10, 0, 40, 0, 0, 0, 12, 41, 11,
+ 14, 0, 42, 43, 0, 0, 0, 0, 17, 9,
+ 186, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 106, 0, 97,
+ 95, 109, 108, 107, 110, 0, 0, 0, 0, 0,
+ 0, 0, 15, 0, 0, 0, 13, 0, 0, 0,
+ 0, 171, 170, 34, 0, 45, 46, 47, 10, 130,
+ 0, 127, 0, 122, 0, 0, 93, 0, 180, 181,
+ 0, 146, 0, 0, 144, 155, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 134, 135,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 182, 183, 0, 168, 0, 0, 86,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 124, 0, 0, 0, 84, 85,
+ 0, 0, 0, 0, 0, 0, 0, 4, 16, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 82, 83, 44, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 29, 0,
+ 30, 0, 25, 0, 26, 0, 0, 0, 36, 0,
+ 0, 136, 0, 0, 0, 0, 0, 0, 158, 159,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 185, 0, 0, 6, 0, 3, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 8, 131,
+ 0, 0, 0, 0, 128, 113, 0, 118, 0, 147,
+ 0, 145, 0, 0, 0, 0, 152, 0, 154, 0,
+ 0, 0, 133, 0, 0, 0, 0, 0, 160, 0,
+ 0, 0, 0, 0, 167, 0, 0, 89, 0, 0,
+ 114, 0, 119, 0, 0, 96, 0, 102, 0, 184,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 132, 0, 0, 111, 116, 0, 27, 28,
+ 23, 24, 151, 0, 0, 0, 32, 138, 0, 0,
+ 0, 0, 161, 162, 0, 0, 0, 0, 0, 153,
+ 0, 0, 112, 117, 99, 103, 101, 0, 0, 0,
+ 0, 143, 150, 31, 0, 139, 0, 140, 0, 163,
+ 164, 0, 0, 169, 104, 0, 100, 7, 129, 0,
+ 141, 0, 165, 0, 0, 0, 0, 166, 105, 33,
+ 142,
+};
+short yydgoto[] = { 1,
+ 8, 9, 89, 255, 76, 3, 10, 11, 77, 219,
+ 220, 168, 79, 80, 292, 294, 81, 198, 102, 137,
+ 208, 82, 83, 12, 84, 2, 13, 14,
+};
+short yysindex[] = { 0,
+ 0, 0, -193, 0, -54, -229, -212, 0, 0, 0,
+ 0, 383, 0, 0, 22, -232, -31, 40, 0, 0,
+ 0, -37, -36, -132, 562, -7, 107, -2, 2819, -29,
+ -23, -22, -21, 109, 111, -3, -4, 113, 123, 143,
+ 170, 172, 173, 174, 175, 186, 187, 188, 189, -34,
+ 191, 200, 2896, 202, 11, -228, -60, 0, -32, 0,
+ 0, 0, 0, 0, 0, 741, 848, 2819, 2819, 2819,
+ 2819, 912, 0, 2819, 2819, -98, 0, 98, -35, 1707,
+ -197, 0, 0, 0, -64, 0, 0, 0, 0, 0,
+ 3011, 0, 3105, 0, 204, -30, 0, -122, 0, 0,
+ -231, 0, -231, -231, 0, 0, 2819, -31, 2819, -31,
+ 2819, -31, 2819, -31, 2819, 2819, 205, 1027, 0, 0,
+ 1144, 3105, 3105, 3105, 3105, 3105, 206, 1208, 2819, 2819,
+ 2819, 2819, 2819, 0, 0, -237, 0, -237, 2819, 0,
+ -122, 2819, 131, -62, 216, 220, 2819, 2819, 2819, 2819,
+ 2819, 5754, 2819, 221, 0, -122, -197, -197, 0, 0,
+ 229, 32, -197, -197, -31, 224, -31, 0, 0, 2819,
+ 2819, 2819, 2819, 2819, 2819, 2819, 2819, 1319, 1494, 2819,
+ 2819, 2819, 2819, 1605, 1669, 1780, 1955, 2066, 2819, 2819,
+ 2130, 0, 0, 0, -113, 281, 1707, 279, 0, 5647,
+ 283, 2244, 2362, 284, 289, 293, 221, 294, 0, 65,
+ 0, 67, 0, 126, 0, 5528, 32, 2819, 0, 286,
+ -39, 0, 305, 279, 303, 303, 328, 329, 0, 0,
+ 130, 5658, 5647, 5647, 5647, 5647, 333, 303, 5658, 32,
+ 2819, 252, 2436, 2533, 74, -12, 84, -9, 221, 221,
+ 221, 2819, 0, 2725, 297, 0, 2819, 0, 221, 221,
+ 221, 221, 1707, 474, -122, -187, 2819, -257, 2819, -138,
+ 1707, 954, 117, 512, 2819, 238, 2819, 238, 2819, 486,
+ 2819, -162, 2819, -162, 51, 51, 2819, 51, 0, 0,
+ 2819, 348, 2819, 303, 0, 0, 32, 0, 32, 0,
+ 2819, 0, -31, -31, -31, -31, 0, 146, 0, 32,
+ 2819, -31, 0, 352, 279, 303, 3105, 3105, 0, 353,
+ 153, 279, 303, 303, 0, 279, 355, 0, 100, 2819,
+ 0, 32, 0, 32, 276, 0, 277, 0, 3, 0,
+ 2819, 154, 1707, 1707, 2819, 1707, 1707, 1707, 1707, 1707,
+ 1707, 221, 0, 1707, 303, 0, 0, 32, 0, 0,
+ 0, 0, 0, 362, -31, 345, 0, 0, 364, 279,
+ 365, 303, 0, 0, 367, 369, 279, 303, 370, 0,
+ 287, 114, 0, 0, 0, 0, 0, 14, -31, 1989,
+ 372, 0, 0, 0, 1027, 0, 373, 0, 303, 0,
+ 0, 374, 279, 0, 0, 292, 0, 0, 0, 381,
+ 0, 279, 0, 384, 386, -31, 393, 0, 0, 0,
+ 0,
+};
+short yyrindex[] = { 0,
+ 0, 0, 70, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 3189, 3385, 0, 3460, 0, 0, 5031, 0,
+ 0, 0, 0, 3497, 0, 0, 3539, 0, 0, 0,
+ 0, 0, 3576, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 5098, 0, 0, 0, 3661, 0, 3793, 0,
+ 0, 0, 0, 0, 0, 5195, 5207, 0, 0, 0,
+ 0, 0, 0, 0, 0, 1, 0, 0, -11, 2796,
+ 5280, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 3867, 3661, 0, 4782, 0, 0,
+ 0, 0, 0, 0, 0, 0, 396, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 385, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 4825, 0, 0, 0, 3909, 3952, 0, 0, 0, 0,
+ 5347, 3661, 0, 4158, 0, 4849, 5444, 5501, 0, 0,
+ 3994, 0, 5570, 5596, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 452, 2647, 164, 0, 128, 404,
+ 0, 0, 0, 0, 0, 0, 23, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 389, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 4200, 4243,
+ 4285, 0, 0, 0, 4084, 0, 0, 0, 30, 64,
+ 79, 81, 3733, 1030, 4916, 3409, 0, 4534, 0, 4576,
+ 3830, 0, 1883, 1422, 0, 5843, 0, 5894, 0, 4957,
+ 0, 4666, 0, 4740, 4375, 4449, 0, 4491, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 394, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 3878, 4698, 0, 4858, 4989, 5104, 5370, 5668,
+ 5820, 417, 0, 165, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 1582,
+ 0, 0, 0, 0, 418, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,
+};
+short yygindex[] = { 0,
+ 0, 0, 0, -178, -17, 335, 0, 0, 0, 448,
+ 66, 0, 6067, 342, 168, -148, 430, -69, -6, -96,
+ 151, 0, 0, 0, -87, 0, 0, 0,
+};
+#define YYTABLESIZE 6408
+short yytable[] = { 87,
+ 5, 253, 91, 93, 254, 136, 16, 97, 174, 203,
+ 107, 289, 108, 110, 112, 114, 109, 111, 113, 134,
+ 209, 105, 211, 201, 213, 99, 215, 17, 145, 18,
+ 148, 174, 101, 5, 174, 121, 118, 104, 309, 237,
+ 5, 238, 312, 5, 18, 5, 174, 18, 153, 155,
+ 144, 223, 224, 225, 226, 227, 228, 174, 150, 5,
+ 148, 328, 147, 38, 4, 189, 190, 308, 191, 2,
+ 21, 5, 253, 135, 86, 254, 315, 316, 100, 146,
+ 336, 38, 85, 338, 321, 322, 323, 324, 21, 326,
+ 149, 20, 147, 20, 204, 387, 205, 206, 88, 20,
+ 20, 20, 39, 6, 22, 304, 407, 305, 174, 39,
+ 174, 7, 39, 176, 39, 178, 179, 174, 356, 19,
+ 357, 20, 22, 5, 94, 5, 5, 174, 39, 192,
+ 193, 365, 335, 187, 188, 189, 190, 19, 191, 20,
+ 178, 179, 337, 174, 4, 355, 103, 256, 115, 258,
+ 116, 5, 122, 383, 186, 384, 169, 174, 381, 364,
+ 189, 190, 123, 191, 178, 186, 306, 370, 178, 174,
+ 319, 178, 406, 174, 377, 378, 165, 166, 167, 392,
+ 178, 179, 124, 6, 189, 190, 363, 191, 186, 293,
+ 186, 7, 39, 374, 389, 39, 291, 174, 187, 188,
+ 189, 190, 15, 191, 179, 51, 391, 179, 51, 125,
+ 185, 126, 127, 128, 129, 359, 360, 361, 362, 90,
+ 92, 186, 134, 399, 367, 130, 131, 132, 133, 403,
+ 138, 170, 171, 172, 173, 170, 171, 172, 173, 139,
+ 184, 142, 194, 202, 218, 242, 229, 371, 372, 99,
+ 412, 186, 119, 241, 99, 243, 5, 5, 5, 244,
+ 5, 5, 5, 257, 174, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 186, 135, 394, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 408, 100, 120, 117, 5, 5, 100, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 143, 252,
+ 5, 290, 291, 295, 300, 39, 39, 5, 5, 39,
+ 39, 39, 301, 302, 303, 39, 39, 39, 39, 39,
+ 39, 39, 39, 39, 311, 313, 293, 39, 39, 39,
+ 39, 39, 39, 39, 39, 39, 39, 39, 39, 39,
+ 39, 39, 39, 39, 39, 39, 98, 39, 39, 39,
+ 106, 317, 318, 325, 330, 39, 191, 39, 39, 39,
+ 39, 39, 39, 39, 39, 39, 39, 341, 353, 39,
+ 186, 314, 368, 373, 141, 380, 39, 39, 420, 320,
+ 385, 386, 393, 395, 396, 398, 327, 400, 156, 401,
+ 404, 405, 409, 411, 413, 68, 415, 176, 177, 178,
+ 179, 416, 72, 195, 418, 75, 419, 74, 186, 186,
+ 186, 186, 197, 421, 200, 183, 37, 187, 188, 189,
+ 190, 73, 191, 35, 179, 186, 186, 18, 186, 186,
+ 186, 186, 37, 186, 186, 186, 216, 48, 35, 78,
+ 410, 366, 197, 197, 197, 197, 197, 197, 0, 0,
+ 232, 233, 234, 235, 236, 0, 0, 0, 0, 0,
+ 239, 0, 369, 0, 39, 0, 0, 0, 375, 376,
+ 0, 39, 0, 379, 39, 0, 39, 157, 158, 159,
+ 160, 0, 0, 163, 164, 20, 0, 0, 69, 0,
+ 39, 186, 0, 0, 0, 263, 264, 265, 266, 268,
+ 270, 271, 272, 273, 274, 276, 278, 280, 282, 284,
+ 285, 286, 288, 0, 0, 0, 0, 397, 176, 177,
+ 178, 179, 0, 0, 402, 0, 0, 0, 0, 186,
+ 0, 0, 0, 0, 0, 0, 0, 0, 187, 188,
+ 189, 190, 0, 191, 0, 0, 0, 185, 0, 0,
+ 414, 0, 0, 0, 39, 0, 0, 39, 0, 417,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 68, 263, 0, 184, 0, 0,
+ 0, 72, 0, 0, 75, 185, 74, 0, 343, 0,
+ 344, 0, 0, 0, 0, 0, 346, 0, 347, 0,
+ 348, 0, 349, 0, 350, 0, 0, 0, 351, 0,
+ 0, 0, 0, 0, 354, 184, 0, 0, 19, 21,
+ 0, 0, 22, 23, 24, 0, 0, 0, 25, 26,
+ 27, 28, 29, 30, 31, 32, 33, 0, 197, 197,
+ 34, 35, 36, 37, 38, 39, 40, 41, 42, 43,
+ 44, 45, 46, 47, 48, 49, 50, 51, 52, 0,
+ 53, 54, 55, 0, 20, 0, 390, 69, 56, 0,
+ 57, 58, 59, 60, 61, 62, 63, 64, 65, 66,
+ 0, 0, 67, 0, 0, 0, 0, 39, 39, 70,
+ 71, 39, 39, 39, 0, 0, 0, 39, 39, 39,
+ 39, 39, 39, 39, 39, 39, 0, 0, 0, 39,
+ 39, 39, 39, 39, 39, 39, 39, 39, 39, 39,
+ 39, 39, 39, 39, 39, 39, 39, 39, 0, 39,
+ 39, 39, 0, 0, 0, 0, 0, 39, 0, 39,
+ 39, 39, 39, 39, 39, 39, 39, 39, 39, 0,
+ 0, 39, 0, 68, 176, 177, 178, 179, 39, 39,
+ 72, 0, 0, 75, 0, 74, 176, 177, 178, 179,
+ 0, 182, 183, 0, 187, 188, 189, 190, 0, 191,
+ 0, 0, 0, 0, 0, 0, 187, 188, 189, 190,
+ 0, 191, 176, 177, 178, 179, 0, 0, 95, 0,
+ 0, 22, 23, 24, 0, 0, 0, 25, 26, 27,
+ 28, 29, 187, 188, 189, 190, 0, 191, 0, 34,
+ 35, 0, 37, 38, 39, 40, 41, 42, 43, 44,
+ 45, 46, 47, 48, 49, 50, 51, 52, 0, 53,
+ 54, 55, 0, 20, 0, 0, 69, 56, 0, 96,
+ 58, 59, 60, 61, 62, 63, 64, 65, 66, 0,
+ 68, 67, 0, 0, 0, 0, 0, 72, 70, 71,
+ 75, 0, 74, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 68, 0, 0, 0, 0, 0,
+ 0, 72, 161, 0, 75, 0, 74, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 20, 0, 0, 69, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 186, 0, 0, 0, 0, 0, 151, 0, 0,
+ 22, 23, 24, 0, 0, 0, 25, 26, 27, 28,
+ 29, 345, 0, 0, 180, 0, 181, 0, 34, 35,
+ 0, 37, 38, 39, 40, 41, 42, 43, 44, 45,
+ 46, 47, 48, 49, 50, 51, 52, 69, 53, 54,
+ 55, 0, 0, 0, 0, 0, 56, 185, 152, 58,
+ 59, 60, 61, 62, 63, 64, 65, 66, 0, 68,
+ 67, 0, 0, 0, 0, 0, 72, 70, 71, 75,
+ 71, 74, 0, 71, 0, 0, 0, 184, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 71, 71, 0,
+ 71, 0, 71, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 21, 0, 0, 22, 23, 24,
+ 0, 0, 0, 25, 26, 27, 28, 29, 0, 0,
+ 0, 0, 71, 0, 0, 34, 35, 0, 37, 38,
+ 39, 40, 41, 42, 43, 44, 45, 46, 47, 48,
+ 49, 50, 51, 52, 0, 53, 54, 55, 0, 0,
+ 0, 0, 69, 56, 0, 57, 58, 59, 60, 61,
+ 62, 63, 64, 65, 66, 0, 0, 67, 21, 0,
+ 0, 22, 23, 24, 70, 71, 68, 25, 26, 27,
+ 28, 29, 0, 72, 222, 0, 75, 0, 74, 34,
+ 35, 0, 37, 38, 39, 40, 41, 42, 43, 44,
+ 45, 46, 47, 48, 49, 50, 51, 52, 0, 53,
+ 54, 55, 0, 0, 0, 0, 175, 56, 0, 57,
+ 58, 59, 60, 61, 62, 63, 64, 65, 66, 0,
+ 0, 67, 0, 0, 0, 0, 0, 0, 70, 71,
+ 68, 0, 0, 0, 0, 0, 0, 72, 230, 0,
+ 75, 0, 74, 0, 176, 177, 178, 179, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 69,
+ 0, 182, 183, 0, 187, 188, 189, 190, 0, 191,
+ 0, 0, 19, 21, 0, 0, 22, 23, 24, 0,
+ 0, 0, 25, 26, 27, 28, 29, 0, 0, 0,
+ 71, 71, 71, 71, 34, 35, 0, 37, 38, 39,
+ 40, 41, 42, 43, 44, 45, 46, 47, 48, 49,
+ 50, 51, 52, 0, 53, 54, 55, 0, 0, 0,
+ 0, 0, 56, 69, 57, 58, 59, 60, 61, 62,
+ 63, 64, 65, 66, 0, 0, 67, 0, 0, 0,
+ 0, 68, 0, 70, 71, 0, 71, 71, 72, 0,
+ 0, 75, 0, 74, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 267,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 199, 0, 0, 22, 23, 24, 0, 0, 0, 25,
+ 26, 27, 28, 29, 0, 0, 0, 0, 0, 0,
+ 0, 34, 35, 0, 37, 38, 39, 40, 41, 42,
+ 43, 44, 45, 46, 47, 48, 49, 50, 51, 52,
+ 0, 53, 54, 55, 69, 0, 0, 0, 0, 56,
+ 0, 57, 58, 59, 60, 61, 62, 63, 64, 65,
+ 66, 0, 72, 67, 21, 72, 0, 22, 23, 24,
+ 70, 71, 0, 25, 26, 27, 28, 29, 0, 72,
+ 72, 0, 72, 0, 72, 34, 35, 0, 37, 38,
+ 39, 40, 41, 42, 43, 44, 45, 46, 47, 48,
+ 49, 50, 51, 52, 0, 53, 54, 55, 0, 0,
+ 0, 0, 0, 56, 72, 57, 58, 59, 60, 61,
+ 62, 63, 64, 65, 66, 0, 68, 67, 0, 0,
+ 0, 0, 0, 72, 70, 71, 75, 0, 74, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 269, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 21, 0, 0, 22, 23,
+ 24, 0, 0, 0, 25, 26, 27, 28, 29, 0,
+ 0, 0, 0, 0, 0, 0, 34, 35, 0, 37,
+ 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
+ 48, 49, 50, 51, 52, 0, 53, 54, 55, 69,
+ 0, 0, 74, 0, 56, 74, 57, 58, 59, 60,
+ 61, 62, 63, 64, 65, 66, 0, 68, 67, 74,
+ 74, 0, 74, 0, 72, 70, 71, 75, 0, 74,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 275, 0, 0, 0, 0,
+ 0, 0, 0, 0, 74, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 72, 0, 0, 0, 0, 0,
+ 0, 0, 72, 72, 72, 72, 0, 0, 0, 0,
+ 0, 68, 0, 0, 0, 0, 0, 0, 72, 0,
+ 0, 75, 0, 74, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 277,
+ 69, 0, 0, 0, 0, 0, 0, 0, 0, 72,
+ 72, 0, 0, 0, 186, 0, 0, 0, 72, 72,
+ 21, 0, 0, 22, 23, 24, 0, 0, 0, 25,
+ 26, 27, 28, 29, 0, 0, 0, 180, 0, 181,
+ 0, 34, 35, 0, 37, 38, 39, 40, 41, 42,
+ 43, 44, 45, 46, 47, 48, 49, 50, 51, 52,
+ 0, 53, 54, 55, 69, 0, 0, 0, 0, 56,
+ 185, 57, 58, 59, 60, 61, 62, 63, 64, 65,
+ 66, 0, 68, 67, 0, 0, 0, 0, 0, 72,
+ 70, 71, 75, 0, 74, 0, 0, 0, 0, 0,
+ 184, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 279, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 74, 74, 74, 74, 0, 0, 0, 0,
+ 0, 21, 0, 0, 22, 23, 24, 0, 0, 0,
+ 25, 26, 27, 28, 29, 0, 0, 0, 0, 0,
+ 0, 0, 34, 35, 0, 37, 38, 39, 40, 41,
+ 42, 43, 44, 45, 46, 47, 48, 49, 50, 51,
+ 52, 0, 53, 54, 55, 69, 0, 0, 74, 74,
+ 56, 0, 57, 58, 59, 60, 61, 62, 63, 64,
+ 65, 66, 0, 73, 67, 21, 73, 0, 22, 23,
+ 24, 70, 71, 0, 25, 26, 27, 28, 29, 0,
+ 73, 73, 0, 73, 0, 73, 34, 35, 0, 37,
+ 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
+ 48, 49, 50, 51, 52, 0, 53, 54, 55, 175,
+ 0, 0, 0, 0, 56, 73, 57, 58, 59, 60,
+ 61, 62, 63, 64, 65, 66, 0, 68, 67, 0,
+ 0, 0, 0, 0, 72, 70, 71, 75, 0, 74,
+ 0, 0, 0, 0, 0, 0, 0, 176, 177, 178,
+ 179, 0, 0, 0, 0, 281, 0, 0, 0, 0,
+ 0, 0, 0, 0, 182, 183, 186, 187, 188, 189,
+ 190, 0, 191, 0, 0, 0, 21, 0, 0, 22,
+ 23, 24, 0, 0, 0, 25, 26, 27, 28, 29,
+ 0, 181, 0, 0, 0, 0, 0, 34, 35, 0,
+ 37, 38, 39, 40, 41, 42, 43, 44, 45, 46,
+ 47, 48, 49, 50, 51, 52, 0, 53, 54, 55,
+ 69, 0, 185, 0, 0, 56, 0, 57, 58, 59,
+ 60, 61, 62, 63, 64, 65, 66, 0, 68, 67,
+ 0, 0, 0, 0, 0, 72, 70, 71, 75, 0,
+ 74, 0, 184, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 283, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 73, 0, 0, 0, 0,
+ 0, 0, 0, 73, 73, 73, 73, 0, 0, 0,
+ 0, 0, 68, 0, 0, 0, 0, 0, 0, 72,
+ 0, 0, 75, 0, 74, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 287, 69, 0, 0, 0, 0, 0, 0, 0, 0,
+ 73, 0, 0, 0, 0, 0, 0, 0, 0, 73,
+ 73, 21, 0, 0, 22, 23, 24, 0, 0, 0,
+ 25, 26, 27, 28, 29, 0, 0, 0, 0, 0,
+ 0, 0, 34, 35, 0, 37, 38, 39, 40, 41,
+ 42, 43, 44, 45, 46, 47, 48, 49, 50, 51,
+ 52, 175, 53, 54, 55, 69, 0, 0, 0, 0,
+ 56, 0, 57, 58, 59, 60, 61, 62, 63, 64,
+ 65, 66, 0, 0, 67, 0, 68, 0, 0, 0,
+ 0, 70, 71, 72, 296, 0, 75, 0, 74, 176,
+ 177, 178, 179, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 182, 183, 0, 187,
+ 188, 189, 190, 0, 191, 0, 0, 0, 0, 0,
+ 0, 0, 21, 0, 0, 22, 23, 24, 0, 0,
+ 0, 25, 26, 27, 28, 29, 0, 0, 0, 0,
+ 0, 0, 0, 34, 35, 0, 37, 38, 39, 40,
+ 41, 42, 43, 44, 45, 46, 47, 48, 49, 50,
+ 51, 52, 0, 53, 54, 55, 0, 0, 0, 69,
+ 0, 56, 0, 57, 58, 59, 60, 61, 62, 63,
+ 64, 65, 66, 0, 0, 67, 21, 0, 0, 22,
+ 23, 24, 70, 71, 68, 25, 26, 27, 28, 29,
+ 0, 72, 298, 0, 75, 0, 74, 34, 35, 0,
+ 37, 38, 39, 40, 41, 42, 43, 44, 45, 46,
+ 47, 48, 49, 50, 51, 52, 0, 53, 54, 55,
+ 0, 0, 0, 0, 0, 56, 0, 57, 58, 59,
+ 60, 61, 62, 63, 64, 65, 66, 0, 0, 67,
+ 0, 0, 0, 0, 0, 0, 70, 71, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 68, 0,
+ 0, 0, 0, 0, 0, 72, 331, 0, 75, 0,
+ 74, 0, 0, 0, 0, 0, 0, 69, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 21, 0, 0, 22, 23, 24, 0, 0, 0, 25,
+ 26, 27, 28, 29, 0, 0, 0, 0, 0, 0,
+ 0, 34, 35, 0, 37, 38, 39, 40, 41, 42,
+ 43, 44, 45, 46, 47, 48, 49, 50, 51, 52,
+ 0, 53, 54, 55, 0, 0, 0, 0, 0, 56,
+ 0, 57, 58, 59, 60, 61, 62, 63, 64, 65,
+ 66, 69, 0, 67, 0, 68, 0, 0, 0, 0,
+ 70, 71, 72, 333, 0, 75, 0, 74, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 21, 0,
+ 0, 22, 23, 24, 0, 0, 0, 25, 26, 27,
+ 28, 29, 0, 0, 0, 0, 0, 0, 0, 34,
+ 35, 0, 37, 38, 39, 40, 41, 42, 43, 44,
+ 45, 46, 47, 48, 49, 50, 51, 52, 69, 53,
+ 54, 55, 0, 0, 0, 0, 0, 56, 0, 57,
+ 58, 59, 60, 61, 62, 63, 64, 65, 66, 0,
+ 0, 67, 0, 0, 186, 0, 0, 0, 70, 71,
+ 178, 0, 21, 0, 0, 22, 23, 24, 0, 0,
+ 0, 25, 26, 27, 28, 29, 0, 186, 0, 186,
+ 0, 0, 0, 34, 35, 0, 37, 38, 39, 40,
+ 41, 42, 43, 44, 45, 46, 47, 48, 49, 50,
+ 51, 52, 0, 53, 54, 55, 0, 0, 0, 0,
+ 186, 56, 0, 57, 58, 59, 60, 61, 62, 63,
+ 64, 65, 66, 0, 0, 67, 0, 68, 0, 0,
+ 0, 0, 70, 71, 72, 340, 0, 75, 0, 74,
+ 186, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 21,
+ 0, 0, 22, 23, 24, 0, 0, 0, 25, 26,
+ 27, 28, 29, 0, 0, 0, 0, 0, 0, 0,
+ 34, 35, 0, 37, 38, 39, 40, 41, 42, 43,
+ 44, 45, 46, 47, 48, 49, 50, 51, 52, 0,
+ 53, 54, 55, 0, 0, 0, 50, 0, 56, 50,
+ 57, 58, 59, 60, 61, 62, 63, 64, 65, 66,
+ 69, 68, 67, 50, 50, 0, 0, 0, 72, 70,
+ 71, 75, 0, 74, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 50, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 186,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 68, 0,
+ 0, 0, 0, 0, 0, 72, 0, 0, 75, 0,
+ 74, 0, 0, 0, 69, 0, 0, 186, 186, 186,
+ 186, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 186, 186, 0, 186, 186, 186,
+ 186, 0, 186, 186, 186, 0, 0, 0, 0, 0,
+ 0, 21, 0, 0, 22, 23, 24, 0, 0, 0,
+ 25, 26, 27, 28, 29, 0, 0, 0, 0, 0,
+ 0, 0, 34, 35, 0, 37, 38, 39, 40, 41,
+ 42, 43, 44, 45, 46, 47, 48, 49, 50, 51,
+ 52, 69, 53, 54, 55, 0, 0, 0, 0, 0,
+ 56, 0, 57, 58, 59, 60, 61, 62, 63, 64,
+ 65, 66, 0, 68, 67, 0, 0, 0, 0, 0,
+ 72, 70, 71, 75, 0, 74, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 50, 50, 50, 50,
+ 0, 0, 0, 0, 0, 21, 0, 0, 22, 23,
+ 24, 0, 0, 0, 25, 26, 27, 28, 29, 0,
+ 0, 0, 0, 0, 0, 0, 34, 35, 0, 37,
+ 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
+ 48, 49, 50, 51, 52, 0, 53, 54, 55, 0,
+ 0, 0, 50, 50, 56, 0, 57, 58, 59, 60,
+ 61, 62, 63, 64, 65, 66, 69, 68, 67, 0,
+ 0, 0, 0, 0, 72, 70, 71, 75, 0, 74,
+ 0, 0, 140, 0, 0, 22, 23, 24, 0, 0,
+ 0, 25, 26, 27, 28, 29, 0, 0, 0, 0,
+ 0, 0, 0, 34, 35, 0, 37, 38, 39, 40,
+ 41, 42, 43, 44, 45, 46, 47, 48, 49, 50,
+ 51, 52, 0, 53, 54, 55, 0, 0, 0, 0,
+ 0, 56, 0, 57, 58, 59, 60, 61, 62, 63,
+ 64, 65, 66, 0, 0, 67, 0, 0, 0, 0,
+ 0, 0, 70, 71, 0, 0, 126, 0, 0, 126,
+ 69, 0, 126, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 126, 126, 0, 126,
+ 0, 126, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 196, 0, 0,
+ 22, 23, 24, 0, 0, 0, 25, 26, 27, 28,
+ 29, 126, 126, 0, 0, 0, 0, 0, 34, 35,
+ 0, 37, 38, 39, 40, 41, 42, 43, 44, 45,
+ 46, 47, 48, 49, 50, 51, 52, 0, 53, 54,
+ 55, 0, 126, 0, 0, 0, 56, 0, 57, 58,
+ 59, 60, 61, 62, 63, 64, 65, 66, 0, 0,
+ 67, 0, 0, 0, 0, 0, 0, 70, 71, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 199, 0, 0, 22, 23, 24, 0, 0, 0,
+ 25, 26, 27, 28, 29, 0, 0, 0, 0, 0,
+ 0, 0, 34, 35, 0, 37, 38, 39, 40, 41,
+ 42, 43, 44, 45, 46, 47, 48, 49, 50, 51,
+ 52, 0, 53, 54, 55, 0, 0, 0, 0, 0,
+ 56, 0, 57, 58, 59, 60, 61, 62, 63, 64,
+ 65, 66, 121, 0, 67, 121, 0, 0, 121, 0,
+ 0, 70, 71, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 121, 121, 0, 121, 67, 121, 0, 67,
+ 0, 126, 67, 0, 0, 0, 0, 0, 0, 126,
+ 126, 126, 126, 0, 0, 0, 67, 67, 0, 67,
+ 0, 67, 0, 0, 0, 0, 0, 121, 121, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 126,
+ 126, 126, 126, 0, 0, 0, 0, 148, 0, 0,
+ 148, 67, 67, 148, 0, 0, 126, 126, 121, 126,
+ 126, 126, 126, 0, 126, 126, 126, 148, 148, 0,
+ 148, 0, 148, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 67, 0, 149, 0, 0, 149, 0, 0,
+ 149, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 148, 148, 149, 149, 0, 149, 0, 149,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 137, 0, 0, 137,
+ 0, 0, 137, 148, 0, 0, 0, 0, 0, 149,
+ 149, 0, 0, 0, 0, 0, 137, 137, 0, 137,
+ 0, 137, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 157, 0, 0, 157, 0, 0, 157,
+ 149, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 137, 137, 157, 157, 0, 157, 0, 157, 0,
+ 0, 0, 0, 0, 0, 0, 0, 121, 0, 0,
+ 0, 0, 0, 0, 0, 121, 121, 121, 121, 0,
+ 0, 0, 137, 0, 0, 0, 0, 0, 157, 157,
+ 0, 67, 0, 0, 0, 0, 0, 0, 0, 67,
+ 67, 67, 67, 0, 0, 121, 121, 121, 121, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 94, 157,
+ 0, 94, 121, 121, 94, 121, 121, 121, 121, 0,
+ 121, 121, 121, 0, 0, 0, 0, 0, 94, 94,
+ 0, 94, 148, 94, 0, 0, 67, 67, 0, 0,
+ 148, 148, 148, 148, 0, 67, 67, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 94, 94, 0, 0, 0, 0, 149,
+ 148, 148, 148, 148, 0, 0, 0, 149, 149, 149,
+ 149, 0, 0, 49, 0, 0, 49, 148, 148, 0,
+ 148, 148, 148, 148, 94, 148, 148, 148, 0, 0,
+ 49, 49, 0, 0, 0, 0, 0, 149, 149, 149,
+ 149, 137, 0, 0, 0, 0, 0, 0, 0, 137,
+ 137, 137, 137, 0, 149, 149, 0, 149, 149, 149,
+ 149, 0, 149, 149, 149, 49, 0, 0, 0, 0,
+ 98, 0, 0, 98, 0, 0, 98, 0, 157, 137,
+ 137, 137, 137, 0, 0, 0, 157, 157, 157, 157,
+ 98, 98, 0, 98, 0, 98, 137, 137, 0, 137,
+ 137, 137, 137, 0, 137, 137, 137, 0, 0, 0,
+ 52, 0, 0, 52, 0, 0, 157, 157, 157, 157,
+ 0, 0, 0, 0, 0, 98, 98, 52, 52, 0,
+ 0, 0, 0, 157, 157, 0, 157, 157, 157, 157,
+ 0, 157, 157, 157, 186, 0, 0, 186, 0, 0,
+ 186, 0, 0, 0, 0, 0, 98, 0, 54, 0,
+ 0, 54, 52, 94, 186, 186, 0, 186, 0, 186,
+ 0, 94, 94, 94, 94, 54, 54, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 115, 0, 0, 115,
+ 0, 0, 115, 0, 0, 0, 0, 0, 0, 186,
+ 186, 94, 94, 94, 94, 0, 115, 115, 0, 115,
+ 54, 115, 0, 0, 0, 0, 0, 0, 94, 94,
+ 0, 94, 94, 94, 94, 0, 94, 94, 94, 120,
+ 186, 0, 120, 0, 0, 120, 0, 0, 0, 0,
+ 0, 115, 115, 49, 49, 49, 49, 0, 0, 120,
+ 120, 0, 120, 0, 120, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 91, 115, 0, 91, 0, 0, 91, 0, 0,
+ 0, 0, 0, 0, 120, 120, 0, 0, 0, 0,
+ 0, 91, 91, 0, 91, 98, 91, 0, 0, 49,
+ 49, 0, 0, 98, 98, 98, 98, 0, 0, 0,
+ 0, 0, 0, 0, 0, 120, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 91, 91, 0, 0,
+ 0, 0, 0, 98, 98, 98, 98, 0, 0, 0,
+ 52, 52, 52, 52, 0, 0, 0, 0, 0, 0,
+ 98, 98, 0, 98, 98, 98, 98, 91, 98, 98,
+ 98, 90, 0, 0, 90, 0, 0, 90, 0, 186,
+ 0, 0, 0, 0, 0, 0, 0, 186, 186, 186,
+ 186, 90, 90, 0, 90, 0, 90, 0, 54, 54,
+ 54, 54, 0, 0, 0, 0, 52, 52, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 186, 186, 186,
+ 186, 115, 0, 0, 0, 0, 90, 90, 0, 115,
+ 115, 115, 115, 0, 186, 186, 0, 186, 186, 186,
+ 186, 0, 186, 186, 186, 173, 0, 0, 173, 0,
+ 0, 0, 0, 0, 54, 54, 0, 90, 0, 115,
+ 115, 115, 115, 0, 120, 173, 173, 0, 173, 0,
+ 173, 0, 120, 120, 120, 120, 115, 115, 0, 115,
+ 115, 115, 115, 0, 115, 115, 115, 175, 0, 0,
+ 175, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 173, 173, 120, 120, 120, 120, 91, 175, 175, 0,
+ 175, 0, 175, 0, 91, 91, 91, 91, 0, 120,
+ 120, 0, 120, 120, 120, 120, 0, 120, 120, 120,
+ 176, 173, 0, 176, 0, 0, 0, 0, 0, 0,
+ 0, 0, 175, 175, 91, 91, 91, 91, 0, 0,
+ 176, 176, 0, 176, 0, 176, 0, 0, 0, 0,
+ 0, 91, 91, 0, 91, 91, 91, 91, 0, 91,
+ 91, 91, 177, 175, 0, 177, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 176, 176, 0, 0, 0,
+ 0, 0, 177, 177, 0, 177, 90, 177, 0, 0,
+ 0, 0, 0, 0, 90, 90, 90, 90, 0, 0,
+ 0, 0, 0, 0, 0, 0, 176, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 177, 177, 0,
+ 0, 0, 0, 0, 90, 90, 90, 90, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 90, 90, 0, 90, 90, 90, 90, 177, 90,
+ 90, 90, 75, 0, 0, 75, 0, 0, 75, 0,
+ 173, 0, 0, 0, 0, 0, 0, 0, 173, 173,
+ 173, 173, 75, 75, 0, 75, 0, 75, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 173, 173,
+ 173, 173, 175, 0, 0, 0, 0, 75, 75, 0,
+ 175, 175, 175, 175, 0, 173, 173, 0, 173, 173,
+ 173, 173, 0, 173, 173, 173, 76, 0, 0, 76,
+ 0, 0, 76, 0, 0, 0, 0, 0, 75, 0,
+ 175, 175, 175, 175, 0, 176, 76, 76, 0, 76,
+ 0, 76, 0, 176, 176, 176, 176, 175, 175, 0,
+ 175, 175, 175, 175, 0, 175, 175, 175, 61, 0,
+ 0, 61, 0, 0, 61, 0, 0, 0, 0, 0,
+ 0, 76, 76, 176, 176, 176, 176, 177, 61, 61,
+ 0, 61, 0, 61, 0, 177, 177, 177, 177, 0,
+ 176, 176, 0, 176, 176, 176, 176, 0, 176, 176,
+ 176, 62, 76, 0, 62, 0, 0, 62, 0, 0,
+ 0, 0, 0, 61, 61, 177, 177, 177, 177, 0,
+ 0, 62, 62, 0, 62, 0, 62, 0, 0, 0,
+ 0, 0, 177, 177, 0, 177, 177, 177, 177, 0,
+ 177, 177, 177, 63, 61, 0, 63, 0, 0, 63,
+ 0, 0, 0, 0, 0, 0, 62, 62, 0, 0,
+ 0, 0, 0, 63, 63, 0, 63, 75, 63, 0,
+ 0, 0, 0, 0, 0, 75, 75, 75, 75, 0,
+ 0, 0, 0, 0, 0, 0, 0, 62, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 63, 63,
+ 0, 0, 0, 0, 0, 75, 75, 75, 75, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 75, 75, 0, 75, 75, 75, 75, 63,
+ 0, 75, 75, 64, 0, 0, 64, 0, 0, 64,
+ 0, 76, 0, 0, 0, 0, 0, 0, 0, 76,
+ 76, 76, 76, 64, 64, 0, 64, 0, 64, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 55, 0,
+ 0, 55, 0, 0, 0, 0, 0, 0, 0, 76,
+ 76, 76, 76, 61, 0, 55, 55, 0, 64, 64,
+ 0, 61, 61, 61, 61, 0, 76, 76, 0, 76,
+ 76, 76, 76, 0, 0, 76, 76, 65, 0, 0,
+ 65, 0, 0, 65, 0, 0, 0, 0, 0, 64,
+ 55, 61, 61, 61, 61, 0, 62, 65, 65, 0,
+ 65, 0, 65, 0, 62, 62, 62, 62, 61, 61,
+ 0, 61, 61, 61, 61, 0, 0, 61, 61, 92,
+ 0, 0, 92, 0, 0, 92, 0, 0, 0, 0,
+ 0, 0, 65, 65, 62, 62, 62, 62, 63, 92,
+ 92, 0, 92, 0, 92, 0, 63, 63, 63, 63,
+ 0, 62, 62, 0, 62, 62, 0, 0, 0, 0,
+ 62, 62, 87, 65, 0, 87, 0, 0, 87, 0,
+ 0, 0, 0, 0, 92, 92, 63, 63, 0, 63,
+ 0, 0, 87, 87, 0, 87, 125, 87, 0, 125,
+ 0, 0, 125, 63, 63, 0, 63, 63, 60, 0,
+ 0, 60, 63, 63, 0, 92, 125, 125, 0, 125,
+ 0, 125, 0, 0, 0, 60, 60, 87, 87, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 64, 0,
+ 0, 0, 0, 0, 0, 0, 64, 64, 64, 64,
+ 0, 125, 125, 0, 0, 0, 0, 0, 87, 0,
+ 60, 0, 0, 66, 0, 0, 66, 0, 0, 66,
+ 0, 0, 0, 0, 0, 0, 64, 64, 55, 55,
+ 55, 55, 125, 66, 66, 0, 66, 0, 66, 0,
+ 0, 0, 0, 64, 64, 0, 64, 64, 0, 0,
+ 0, 0, 64, 64, 68, 0, 0, 68, 0, 0,
+ 68, 0, 65, 0, 0, 0, 0, 0, 66, 66,
+ 65, 65, 65, 65, 68, 68, 0, 68, 0, 68,
+ 0, 0, 0, 0, 55, 55, 0, 0, 0, 59,
+ 0, 0, 59, 0, 0, 0, 0, 0, 0, 66,
+ 65, 65, 0, 0, 92, 0, 59, 59, 0, 68,
+ 68, 0, 92, 92, 92, 92, 0, 65, 65, 0,
+ 65, 65, 0, 0, 0, 0, 65, 65, 156, 0,
+ 0, 156, 0, 0, 156, 0, 0, 0, 0, 0,
+ 68, 59, 92, 92, 0, 0, 0, 87, 156, 156,
+ 0, 156, 0, 156, 0, 87, 87, 87, 87, 92,
+ 92, 0, 0, 0, 0, 0, 0, 0, 92, 92,
+ 0, 125, 0, 0, 0, 0, 0, 0, 0, 125,
+ 125, 125, 125, 156, 156, 87, 87, 0, 60, 60,
+ 60, 60, 0, 0, 0, 88, 0, 0, 88, 0,
+ 0, 88, 87, 87, 58, 0, 0, 58, 0, 125,
+ 125, 87, 87, 0, 156, 88, 88, 0, 88, 0,
+ 88, 58, 58, 0, 0, 0, 125, 125, 0, 0,
+ 0, 0, 0, 0, 0, 125, 125, 0, 66, 0,
+ 0, 0, 0, 0, 60, 60, 66, 66, 66, 66,
+ 88, 88, 0, 0, 0, 0, 58, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 66, 0, 68,
+ 0, 88, 0, 0, 0, 0, 0, 68, 68, 68,
+ 68, 0, 172, 66, 66, 172, 0, 0, 172, 0,
+ 0, 0, 66, 66, 123, 0, 0, 123, 0, 0,
+ 123, 0, 172, 172, 0, 172, 0, 172, 0, 59,
+ 59, 59, 59, 0, 123, 123, 0, 123, 0, 123,
+ 0, 0, 0, 0, 68, 68, 0, 0, 0, 0,
+ 0, 0, 0, 68, 68, 0, 0, 172, 172, 0,
+ 0, 0, 0, 156, 0, 0, 0, 0, 0, 123,
+ 123, 156, 156, 156, 156, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 59, 59, 77, 172, 0,
+ 77, 0, 0, 77, 0, 0, 0, 0, 0, 0,
+ 123, 156, 156, 156, 156, 0, 0, 77, 77, 0,
+ 77, 0, 77, 0, 0, 0, 0, 0, 156, 156,
+ 0, 156, 156, 156, 156, 0, 156, 0, 0, 0,
+ 88, 0, 0, 0, 0, 0, 0, 0, 88, 88,
+ 88, 88, 77, 77, 58, 58, 58, 58, 0, 0,
+ 0, 0, 0, 0, 174, 0, 0, 174, 0, 0,
+ 174, 0, 0, 0, 0, 0, 0, 0, 88, 88,
+ 88, 88, 0, 77, 174, 174, 0, 174, 0, 174,
+ 56, 0, 0, 56, 0, 88, 88, 0, 88, 88,
+ 88, 88, 0, 88, 0, 0, 0, 56, 56, 0,
+ 58, 58, 0, 0, 0, 0, 0, 0, 0, 174,
+ 174, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 172, 0, 0,
+ 0, 0, 56, 0, 0, 172, 172, 172, 172, 123,
+ 174, 0, 0, 0, 0, 0, 0, 123, 123, 123,
+ 123, 80, 0, 0, 80, 0, 0, 80, 0, 0,
+ 0, 0, 0, 0, 0, 172, 172, 172, 172, 0,
+ 0, 80, 80, 0, 80, 0, 80, 123, 123, 123,
+ 123, 0, 172, 172, 0, 172, 172, 172, 172, 0,
+ 172, 0, 0, 0, 123, 123, 0, 123, 123, 123,
+ 123, 0, 123, 0, 0, 0, 80, 80, 81, 0,
+ 0, 81, 77, 0, 81, 0, 0, 0, 0, 0,
+ 77, 77, 77, 77, 0, 0, 0, 0, 81, 81,
+ 0, 81, 0, 81, 0, 186, 0, 80, 307, 0,
+ 0, 293, 0, 0, 0, 0, 0, 0, 0, 0,
+ 77, 77, 77, 77, 0, 0, 0, 0, 180, 0,
+ 181, 0, 0, 81, 81, 0, 0, 77, 77, 0,
+ 77, 77, 77, 77, 0, 77, 0, 78, 0, 174,
+ 78, 0, 0, 78, 0, 0, 0, 174, 174, 174,
+ 174, 185, 0, 0, 81, 0, 0, 78, 78, 0,
+ 78, 0, 78, 79, 0, 0, 79, 0, 0, 79,
+ 56, 56, 56, 56, 0, 0, 0, 174, 174, 174,
+ 174, 184, 0, 79, 79, 0, 79, 0, 79, 0,
+ 0, 0, 78, 78, 174, 174, 0, 174, 174, 174,
+ 174, 0, 174, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 186, 0, 0, 0, 79, 79,
+ 293, 0, 0, 78, 0, 186, 56, 56, 0, 0,
+ 0, 291, 0, 0, 0, 0, 80, 180, 57, 181,
+ 0, 57, 0, 0, 80, 80, 80, 80, 180, 79,
+ 181, 0, 0, 0, 0, 57, 57, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 185, 0, 0, 0, 80, 80, 80, 80, 0, 0,
+ 0, 185, 0, 0, 0, 0, 0, 0, 0, 0,
+ 57, 80, 80, 81, 80, 80, 80, 80, 0, 80,
+ 184, 81, 81, 81, 81, 0, 0, 0, 0, 0,
+ 0, 184, 0, 0, 0, 0, 68, 0, 0, 0,
+ 175, 0, 0, 72, 0, 0, 75, 0, 74, 0,
+ 0, 81, 81, 81, 81, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 81, 81,
+ 0, 81, 81, 81, 81, 0, 81, 0, 176, 177,
+ 178, 179, 78, 0, 0, 0, 0, 0, 0, 0,
+ 78, 78, 78, 78, 148, 182, 183, 0, 187, 188,
+ 189, 190, 0, 191, 0, 0, 0, 0, 79, 0,
+ 53, 0, 0, 53, 0, 0, 79, 79, 79, 79,
+ 78, 78, 78, 78, 0, 0, 147, 53, 53, 69,
+ 0, 0, 0, 70, 0, 0, 70, 78, 78, 0,
+ 78, 78, 78, 78, 0, 78, 79, 79, 79, 79,
+ 70, 70, 0, 70, 0, 70, 0, 0, 0, 175,
+ 0, 0, 53, 79, 79, 0, 79, 79, 79, 79,
+ 175, 79, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 69, 70, 70, 69, 57, 57,
+ 57, 57, 0, 0, 0, 0, 0, 176, 177, 178,
+ 179, 69, 69, 0, 69, 0, 69, 0, 176, 177,
+ 178, 179, 0, 0, 182, 183, 70, 187, 188, 189,
+ 190, 0, 191, 0, 0, 182, 183, 0, 187, 188,
+ 189, 190, 0, 191, 0, 0, 69, 69, 0, 0,
+ 0, 0, 0, 0, 57, 57, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 21, 0, 0, 22, 23, 24, 0, 69, 0, 25,
+ 26, 27, 28, 29, 0, 0, 0, 0, 0, 0,
+ 0, 34, 35, 0, 37, 38, 39, 40, 41, 42,
+ 43, 44, 45, 46, 47, 48, 49, 50, 51, 52,
+ 0, 53, 54, 55, 0, 0, 0, 0, 0, 56,
+ 0, 57, 58, 59, 60, 61, 62, 63, 64, 65,
+ 66, 0, 0, 67, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 53, 53, 53, 53, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 70, 0, 0, 0, 0,
+ 0, 0, 0, 70, 70, 70, 70, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 154, 0, 0, 0, 0, 0, 162, 0,
+ 0, 0, 0, 0, 0, 0, 53, 53, 0, 0,
+ 0, 0, 0, 0, 0, 0, 69, 0, 0, 0,
+ 70, 70, 0, 0, 69, 69, 69, 69, 0, 70,
+ 70, 0, 0, 207, 0, 210, 0, 212, 0, 214,
+ 0, 0, 217, 0, 221, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 231, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 240, 0,
+ 0, 69, 69, 245, 246, 247, 248, 249, 250, 251,
+ 69, 69, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 259, 260, 261, 262,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 297, 299,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 310, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 329, 0, 332,
+ 334, 0, 0, 0, 0, 0, 0, 0, 339, 0,
+ 0, 0, 0, 342, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 352, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 358, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 207, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 382, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 388,
+};
+short yycheck[] = { 17,
+ 0, 41, 40, 40, 44, 40, 61, 25, 44, 40,
+ 40, 125, 30, 31, 32, 33, 40, 40, 40, 257,
+ 108, 28, 110, 93, 112, 257, 114, 257, 257, 41,
+ 91, 44, 40, 33, 44, 40, 40, 40, 217, 136,
+ 40, 138, 221, 43, 257, 45, 44, 59, 66, 67,
+ 40, 121, 122, 123, 124, 125, 126, 44, 91, 59,
+ 91, 240, 123, 41, 258, 323, 324, 216, 326, 0,
+ 41, 265, 41, 311, 307, 44, 225, 226, 310, 308,
+ 93, 59, 61, 93, 233, 234, 235, 236, 59, 238,
+ 123, 123, 123, 123, 101, 93, 103, 104, 59, 123,
+ 123, 123, 33, 297, 41, 41, 93, 41, 44, 40,
+ 44, 305, 43, 301, 45, 303, 304, 44, 297, 41,
+ 299, 41, 59, 123, 257, 125, 126, 44, 59, 327,
+ 328, 310, 59, 321, 322, 323, 324, 59, 326, 59,
+ 303, 304, 59, 44, 258, 294, 40, 165, 40, 167,
+ 40, 265, 40, 332, 38, 334, 59, 44, 59, 308,
+ 323, 324, 40, 326, 303, 38, 41, 316, 41, 44,
+ 41, 44, 59, 44, 323, 324, 275, 276, 277, 358,
+ 303, 304, 40, 297, 323, 324, 41, 326, 61, 44,
+ 63, 305, 123, 41, 41, 126, 44, 44, 321, 322,
+ 323, 324, 257, 326, 41, 41, 355, 44, 44, 40,
+ 94, 40, 40, 40, 40, 303, 304, 305, 306, 257,
+ 257, 94, 257, 372, 312, 40, 40, 40, 40, 378,
+ 40, 271, 272, 273, 274, 271, 272, 273, 274, 40,
+ 124, 40, 307, 40, 40, 308, 41, 317, 318, 257,
+ 399, 124, 257, 123, 257, 40, 256, 257, 258, 40,
+ 260, 261, 262, 40, 44, 265, 266, 267, 268, 269,
+ 270, 271, 272, 273, 274, 38, 311, 365, 278, 279,
+ 280, 281, 282, 283, 284, 285, 286, 287, 288, 289,
+ 290, 291, 292, 293, 294, 295, 296, 297, 298, 299,
+ 300, 389, 310, 308, 308, 305, 306, 310, 308, 309,
+ 310, 311, 312, 313, 314, 315, 316, 317, 308, 91,
+ 320, 41, 44, 41, 41, 256, 257, 327, 328, 260,
+ 261, 262, 44, 41, 41, 266, 267, 268, 269, 270,
+ 271, 272, 273, 274, 59, 41, 44, 278, 279, 280,
+ 281, 282, 283, 284, 285, 286, 287, 288, 289, 290,
+ 291, 292, 293, 294, 295, 296, 25, 298, 299, 300,
+ 29, 44, 44, 41, 123, 306, 326, 308, 309, 310,
+ 311, 312, 313, 314, 315, 316, 317, 91, 41, 320,
+ 263, 224, 41, 41, 53, 41, 327, 328, 416, 232,
+ 125, 125, 41, 59, 41, 41, 239, 41, 67, 41,
+ 41, 125, 41, 41, 41, 33, 125, 301, 302, 303,
+ 304, 41, 40, 89, 41, 43, 41, 45, 301, 302,
+ 303, 304, 91, 41, 93, 319, 41, 321, 322, 323,
+ 324, 59, 326, 59, 41, 318, 319, 59, 321, 322,
+ 323, 324, 59, 326, 327, 328, 115, 41, 41, 12,
+ 395, 311, 121, 122, 123, 124, 125, 126, -1, -1,
+ 129, 130, 131, 132, 133, -1, -1, -1, -1, -1,
+ 139, -1, 315, -1, 33, -1, -1, -1, 321, 322,
+ -1, 40, -1, 326, 43, -1, 45, 68, 69, 70,
+ 71, -1, -1, 74, 75, 123, -1, -1, 126, -1,
+ 59, 38, -1, -1, -1, 174, 175, 176, 177, 178,
+ 179, 180, 181, 182, 183, 184, 185, 186, 187, 188,
+ 189, 190, 191, -1, -1, -1, -1, 370, 301, 302,
+ 303, 304, -1, -1, 377, -1, -1, -1, -1, 38,
+ -1, -1, -1, -1, -1, -1, -1, -1, 321, 322,
+ 323, 324, -1, 326, -1, -1, -1, 94, -1, -1,
+ 403, -1, -1, -1, 123, -1, -1, 126, -1, 412,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, 33, 254, -1, 124, -1, -1,
+ -1, 40, -1, -1, 43, 94, 45, -1, 267, -1,
+ 269, -1, -1, -1, -1, -1, 275, -1, 277, -1,
+ 279, -1, 281, -1, 283, -1, -1, -1, 287, -1,
+ -1, -1, -1, -1, 293, 124, -1, -1, 256, 257,
+ -1, -1, 260, 261, 262, -1, -1, -1, 266, 267,
+ 268, 269, 270, 271, 272, 273, 274, -1, 317, 318,
+ 278, 279, 280, 281, 282, 283, 284, 285, 286, 287,
+ 288, 289, 290, 291, 292, 293, 294, 295, 296, -1,
+ 298, 299, 300, -1, 123, -1, 345, 126, 306, -1,
+ 308, 309, 310, 311, 312, 313, 314, 315, 316, 317,
+ -1, -1, 320, -1, -1, -1, -1, 256, 257, 327,
+ 328, 260, 261, 262, -1, -1, -1, 266, 267, 268,
+ 269, 270, 271, 272, 273, 274, -1, -1, -1, 278,
+ 279, 280, 281, 282, 283, 284, 285, 286, 287, 288,
+ 289, 290, 291, 292, 293, 294, 295, 296, -1, 298,
+ 299, 300, -1, -1, -1, -1, -1, 306, -1, 308,
+ 309, 310, 311, 312, 313, 314, 315, 316, 317, -1,
+ -1, 320, -1, 33, 301, 302, 303, 304, 327, 328,
+ 40, -1, -1, 43, -1, 45, 301, 302, 303, 304,
+ -1, 318, 319, -1, 321, 322, 323, 324, -1, 326,
+ -1, -1, -1, -1, -1, -1, 321, 322, 323, 324,
+ -1, 326, 301, 302, 303, 304, -1, -1, 257, -1,
+ -1, 260, 261, 262, -1, -1, -1, 266, 267, 268,
+ 269, 270, 321, 322, 323, 324, -1, 326, -1, 278,
+ 279, -1, 281, 282, 283, 284, 285, 286, 287, 288,
+ 289, 290, 291, 292, 293, 294, 295, 296, -1, 298,
+ 299, 300, -1, 123, -1, -1, 126, 306, -1, 308,
+ 309, 310, 311, 312, 313, 314, 315, 316, 317, -1,
+ 33, 320, -1, -1, -1, -1, -1, 40, 327, 328,
+ 43, -1, 45, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, 33, -1, -1, -1, -1, -1,
+ -1, 40, 41, -1, 43, -1, 45, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ 123, -1, -1, 126, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, 38, -1, -1, -1, -1, -1, 257, -1, -1,
+ 260, 261, 262, -1, -1, -1, 266, 267, 268, 269,
+ 270, 58, -1, -1, 61, -1, 63, -1, 278, 279,
+ -1, 281, 282, 283, 284, 285, 286, 287, 288, 289,
+ 290, 291, 292, 293, 294, 295, 296, 126, 298, 299,
+ 300, -1, -1, -1, -1, -1, 306, 94, 308, 309,
+ 310, 311, 312, 313, 314, 315, 316, 317, -1, 33,
+ 320, -1, -1, -1, -1, -1, 40, 327, 328, 43,
+ 41, 45, -1, 44, -1, -1, -1, 124, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, 58, 59, -1,
+ 61, -1, 63, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, 257, -1, -1, 260, 261, 262,
+ -1, -1, -1, 266, 267, 268, 269, 270, -1, -1,
+ -1, -1, 93, -1, -1, 278, 279, -1, 281, 282,
+ 283, 284, 285, 286, 287, 288, 289, 290, 291, 292,
+ 293, 294, 295, 296, -1, 298, 299, 300, -1, -1,
+ -1, -1, 126, 306, -1, 308, 309, 310, 311, 312,
+ 313, 314, 315, 316, 317, -1, -1, 320, 257, -1,
+ -1, 260, 261, 262, 327, 328, 33, 266, 267, 268,
+ 269, 270, -1, 40, 41, -1, 43, -1, 45, 278,
+ 279, -1, 281, 282, 283, 284, 285, 286, 287, 288,
+ 289, 290, 291, 292, 293, 294, 295, 296, -1, 298,
+ 299, 300, -1, -1, -1, -1, 263, 306, -1, 308,
+ 309, 310, 311, 312, 313, 314, 315, 316, 317, -1,
+ -1, 320, -1, -1, -1, -1, -1, -1, 327, 328,
+ 33, -1, -1, -1, -1, -1, -1, 40, 41, -1,
+ 43, -1, 45, -1, 301, 302, 303, 304, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, 126,
+ -1, 318, 319, -1, 321, 322, 323, 324, -1, 326,
+ -1, -1, 256, 257, -1, -1, 260, 261, 262, -1,
+ -1, -1, 266, 267, 268, 269, 270, -1, -1, -1,
+ 271, 272, 273, 274, 278, 279, -1, 281, 282, 283,
+ 284, 285, 286, 287, 288, 289, 290, 291, 292, 293,
+ 294, 295, 296, -1, 298, 299, 300, -1, -1, -1,
+ -1, -1, 306, 126, 308, 309, 310, 311, 312, 313,
+ 314, 315, 316, 317, -1, -1, 320, -1, -1, -1,
+ -1, 33, -1, 327, 328, -1, 327, 328, 40, -1,
+ -1, 43, -1, 45, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, 61,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ 257, -1, -1, 260, 261, 262, -1, -1, -1, 266,
+ 267, 268, 269, 270, -1, -1, -1, -1, -1, -1,
+ -1, 278, 279, -1, 281, 282, 283, 284, 285, 286,
+ 287, 288, 289, 290, 291, 292, 293, 294, 295, 296,
+ -1, 298, 299, 300, 126, -1, -1, -1, -1, 306,
+ -1, 308, 309, 310, 311, 312, 313, 314, 315, 316,
+ 317, -1, 41, 320, 257, 44, -1, 260, 261, 262,
+ 327, 328, -1, 266, 267, 268, 269, 270, -1, 58,
+ 59, -1, 61, -1, 63, 278, 279, -1, 281, 282,
+ 283, 284, 285, 286, 287, 288, 289, 290, 291, 292,
+ 293, 294, 295, 296, -1, 298, 299, 300, -1, -1,
+ -1, -1, -1, 306, 93, 308, 309, 310, 311, 312,
+ 313, 314, 315, 316, 317, -1, 33, 320, -1, -1,
+ -1, -1, -1, 40, 327, 328, 43, -1, 45, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, 61, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, 257, -1, -1, 260, 261,
+ 262, -1, -1, -1, 266, 267, 268, 269, 270, -1,
+ -1, -1, -1, -1, -1, -1, 278, 279, -1, 281,
+ 282, 283, 284, 285, 286, 287, 288, 289, 290, 291,
+ 292, 293, 294, 295, 296, -1, 298, 299, 300, 126,
+ -1, -1, 41, -1, 306, 44, 308, 309, 310, 311,
+ 312, 313, 314, 315, 316, 317, -1, 33, 320, 58,
+ 59, -1, 61, -1, 40, 327, 328, 43, -1, 45,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, 61, -1, -1, -1, -1,
+ -1, -1, -1, -1, 93, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, 263, -1, -1, -1, -1, -1,
+ -1, -1, 271, 272, 273, 274, -1, -1, -1, -1,
+ -1, 33, -1, -1, -1, -1, -1, -1, 40, -1,
+ -1, 43, -1, 45, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, 61,
+ 126, -1, -1, -1, -1, -1, -1, -1, -1, 318,
+ 319, -1, -1, -1, 38, -1, -1, -1, 327, 328,
+ 257, -1, -1, 260, 261, 262, -1, -1, -1, 266,
+ 267, 268, 269, 270, -1, -1, -1, 61, -1, 63,
+ -1, 278, 279, -1, 281, 282, 283, 284, 285, 286,
+ 287, 288, 289, 290, 291, 292, 293, 294, 295, 296,
+ -1, 298, 299, 300, 126, -1, -1, -1, -1, 306,
+ 94, 308, 309, 310, 311, 312, 313, 314, 315, 316,
+ 317, -1, 33, 320, -1, -1, -1, -1, -1, 40,
+ 327, 328, 43, -1, 45, -1, -1, -1, -1, -1,
+ 124, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ 61, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, 271, 272, 273, 274, -1, -1, -1, -1,
+ -1, 257, -1, -1, 260, 261, 262, -1, -1, -1,
+ 266, 267, 268, 269, 270, -1, -1, -1, -1, -1,
+ -1, -1, 278, 279, -1, 281, 282, 283, 284, 285,
+ 286, 287, 288, 289, 290, 291, 292, 293, 294, 295,
+ 296, -1, 298, 299, 300, 126, -1, -1, 327, 328,
+ 306, -1, 308, 309, 310, 311, 312, 313, 314, 315,
+ 316, 317, -1, 41, 320, 257, 44, -1, 260, 261,
+ 262, 327, 328, -1, 266, 267, 268, 269, 270, -1,
+ 58, 59, -1, 61, -1, 63, 278, 279, -1, 281,
+ 282, 283, 284, 285, 286, 287, 288, 289, 290, 291,
+ 292, 293, 294, 295, 296, -1, 298, 299, 300, 263,
+ -1, -1, -1, -1, 306, 93, 308, 309, 310, 311,
+ 312, 313, 314, 315, 316, 317, -1, 33, 320, -1,
+ -1, -1, -1, -1, 40, 327, 328, 43, -1, 45,
+ -1, -1, -1, -1, -1, -1, -1, 301, 302, 303,
+ 304, -1, -1, -1, -1, 61, -1, -1, -1, -1,
+ -1, -1, -1, -1, 318, 319, 38, 321, 322, 323,
+ 324, -1, 326, -1, -1, -1, 257, -1, -1, 260,
+ 261, 262, -1, -1, -1, 266, 267, 268, 269, 270,
+ -1, 63, -1, -1, -1, -1, -1, 278, 279, -1,
+ 281, 282, 283, 284, 285, 286, 287, 288, 289, 290,
+ 291, 292, 293, 294, 295, 296, -1, 298, 299, 300,
+ 126, -1, 94, -1, -1, 306, -1, 308, 309, 310,
+ 311, 312, 313, 314, 315, 316, 317, -1, 33, 320,
+ -1, -1, -1, -1, -1, 40, 327, 328, 43, -1,
+ 45, -1, 124, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, 61, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, 263, -1, -1, -1, -1,
+ -1, -1, -1, 271, 272, 273, 274, -1, -1, -1,
+ -1, -1, 33, -1, -1, -1, -1, -1, -1, 40,
+ -1, -1, 43, -1, 45, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ 61, 126, -1, -1, -1, -1, -1, -1, -1, -1,
+ 318, -1, -1, -1, -1, -1, -1, -1, -1, 327,
+ 328, 257, -1, -1, 260, 261, 262, -1, -1, -1,
+ 266, 267, 268, 269, 270, -1, -1, -1, -1, -1,
+ -1, -1, 278, 279, -1, 281, 282, 283, 284, 285,
+ 286, 287, 288, 289, 290, 291, 292, 293, 294, 295,
+ 296, 263, 298, 299, 300, 126, -1, -1, -1, -1,
+ 306, -1, 308, 309, 310, 311, 312, 313, 314, 315,
+ 316, 317, -1, -1, 320, -1, 33, -1, -1, -1,
+ -1, 327, 328, 40, 41, -1, 43, -1, 45, 301,
+ 302, 303, 304, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, 318, 319, -1, 321,
+ 322, 323, 324, -1, 326, -1, -1, -1, -1, -1,
+ -1, -1, 257, -1, -1, 260, 261, 262, -1, -1,
+ -1, 266, 267, 268, 269, 270, -1, -1, -1, -1,
+ -1, -1, -1, 278, 279, -1, 281, 282, 283, 284,
+ 285, 286, 287, 288, 289, 290, 291, 292, 293, 294,
+ 295, 296, -1, 298, 299, 300, -1, -1, -1, 126,
+ -1, 306, -1, 308, 309, 310, 311, 312, 313, 314,
+ 315, 316, 317, -1, -1, 320, 257, -1, -1, 260,
+ 261, 262, 327, 328, 33, 266, 267, 268, 269, 270,
+ -1, 40, 41, -1, 43, -1, 45, 278, 279, -1,
+ 281, 282, 283, 284, 285, 286, 287, 288, 289, 290,
+ 291, 292, 293, 294, 295, 296, -1, 298, 299, 300,
+ -1, -1, -1, -1, -1, 306, -1, 308, 309, 310,
+ 311, 312, 313, 314, 315, 316, 317, -1, -1, 320,
+ -1, -1, -1, -1, -1, -1, 327, 328, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, 33, -1,
+ -1, -1, -1, -1, -1, 40, 41, -1, 43, -1,
+ 45, -1, -1, -1, -1, -1, -1, 126, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ 257, -1, -1, 260, 261, 262, -1, -1, -1, 266,
+ 267, 268, 269, 270, -1, -1, -1, -1, -1, -1,
+ -1, 278, 279, -1, 281, 282, 283, 284, 285, 286,
+ 287, 288, 289, 290, 291, 292, 293, 294, 295, 296,
+ -1, 298, 299, 300, -1, -1, -1, -1, -1, 306,
+ -1, 308, 309, 310, 311, 312, 313, 314, 315, 316,
+ 317, 126, -1, 320, -1, 33, -1, -1, -1, -1,
+ 327, 328, 40, 41, -1, 43, -1, 45, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, 257, -1,
+ -1, 260, 261, 262, -1, -1, -1, 266, 267, 268,
+ 269, 270, -1, -1, -1, -1, -1, -1, -1, 278,
+ 279, -1, 281, 282, 283, 284, 285, 286, 287, 288,
+ 289, 290, 291, 292, 293, 294, 295, 296, 126, 298,
+ 299, 300, -1, -1, -1, -1, -1, 306, -1, 308,
+ 309, 310, 311, 312, 313, 314, 315, 316, 317, -1,
+ -1, 320, -1, -1, 38, -1, -1, -1, 327, 328,
+ 44, -1, 257, -1, -1, 260, 261, 262, -1, -1,
+ -1, 266, 267, 268, 269, 270, -1, 61, -1, 63,
+ -1, -1, -1, 278, 279, -1, 281, 282, 283, 284,
+ 285, 286, 287, 288, 289, 290, 291, 292, 293, 294,
+ 295, 296, -1, 298, 299, 300, -1, -1, -1, -1,
+ 94, 306, -1, 308, 309, 310, 311, 312, 313, 314,
+ 315, 316, 317, -1, -1, 320, -1, 33, -1, -1,
+ -1, -1, 327, 328, 40, 41, -1, 43, -1, 45,
+ 124, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, 257,
+ -1, -1, 260, 261, 262, -1, -1, -1, 266, 267,
+ 268, 269, 270, -1, -1, -1, -1, -1, -1, -1,
+ 278, 279, -1, 281, 282, 283, 284, 285, 286, 287,
+ 288, 289, 290, 291, 292, 293, 294, 295, 296, -1,
+ 298, 299, 300, -1, -1, -1, 41, -1, 306, 44,
+ 308, 309, 310, 311, 312, 313, 314, 315, 316, 317,
+ 126, 33, 320, 58, 59, -1, -1, -1, 40, 327,
+ 328, 43, -1, 45, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, 93, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, 263,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, 33, -1,
+ -1, -1, -1, -1, -1, 40, -1, -1, 43, -1,
+ 45, -1, -1, -1, 126, -1, -1, 301, 302, 303,
+ 304, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, 318, 319, -1, 321, 322, 323,
+ 324, -1, 326, 327, 328, -1, -1, -1, -1, -1,
+ -1, 257, -1, -1, 260, 261, 262, -1, -1, -1,
+ 266, 267, 268, 269, 270, -1, -1, -1, -1, -1,
+ -1, -1, 278, 279, -1, 281, 282, 283, 284, 285,
+ 286, 287, 288, 289, 290, 291, 292, 293, 294, 295,
+ 296, 126, 298, 299, 300, -1, -1, -1, -1, -1,
+ 306, -1, 308, 309, 310, 311, 312, 313, 314, 315,
+ 316, 317, -1, 33, 320, -1, -1, -1, -1, -1,
+ 40, 327, 328, 43, -1, 45, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, 271, 272, 273, 274,
+ -1, -1, -1, -1, -1, 257, -1, -1, 260, 261,
+ 262, -1, -1, -1, 266, 267, 268, 269, 270, -1,
+ -1, -1, -1, -1, -1, -1, 278, 279, -1, 281,
+ 282, 283, 284, 285, 286, 287, 288, 289, 290, 291,
+ 292, 293, 294, 295, 296, -1, 298, 299, 300, -1,
+ -1, -1, 327, 328, 306, -1, 308, 309, 310, 311,
+ 312, 313, 314, 315, 316, 317, 126, 33, 320, -1,
+ -1, -1, -1, -1, 40, 327, 328, 43, -1, 45,
+ -1, -1, 257, -1, -1, 260, 261, 262, -1, -1,
+ -1, 266, 267, 268, 269, 270, -1, -1, -1, -1,
+ -1, -1, -1, 278, 279, -1, 281, 282, 283, 284,
+ 285, 286, 287, 288, 289, 290, 291, 292, 293, 294,
+ 295, 296, -1, 298, 299, 300, -1, -1, -1, -1,
+ -1, 306, -1, 308, 309, 310, 311, 312, 313, 314,
+ 315, 316, 317, -1, -1, 320, -1, -1, -1, -1,
+ -1, -1, 327, 328, -1, -1, 38, -1, -1, 41,
+ 126, -1, 44, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, 58, 59, -1, 61,
+ -1, 63, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, 257, -1, -1,
+ 260, 261, 262, -1, -1, -1, 266, 267, 268, 269,
+ 270, 93, 94, -1, -1, -1, -1, -1, 278, 279,
+ -1, 281, 282, 283, 284, 285, 286, 287, 288, 289,
+ 290, 291, 292, 293, 294, 295, 296, -1, 298, 299,
+ 300, -1, 124, -1, -1, -1, 306, -1, 308, 309,
+ 310, 311, 312, 313, 314, 315, 316, 317, -1, -1,
+ 320, -1, -1, -1, -1, -1, -1, 327, 328, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, 257, -1, -1, 260, 261, 262, -1, -1, -1,
+ 266, 267, 268, 269, 270, -1, -1, -1, -1, -1,
+ -1, -1, 278, 279, -1, 281, 282, 283, 284, 285,
+ 286, 287, 288, 289, 290, 291, 292, 293, 294, 295,
+ 296, -1, 298, 299, 300, -1, -1, -1, -1, -1,
+ 306, -1, 308, 309, 310, 311, 312, 313, 314, 315,
+ 316, 317, 38, -1, 320, 41, -1, -1, 44, -1,
+ -1, 327, 328, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, 58, 59, -1, 61, 38, 63, -1, 41,
+ -1, 263, 44, -1, -1, -1, -1, -1, -1, 271,
+ 272, 273, 274, -1, -1, -1, 58, 59, -1, 61,
+ -1, 63, -1, -1, -1, -1, -1, 93, 94, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, 301,
+ 302, 303, 304, -1, -1, -1, -1, 38, -1, -1,
+ 41, 93, 94, 44, -1, -1, 318, 319, 124, 321,
+ 322, 323, 324, -1, 326, 327, 328, 58, 59, -1,
+ 61, -1, 63, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, 124, -1, 38, -1, -1, 41, -1, -1,
+ 44, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, 93, 94, 58, 59, -1, 61, -1, 63,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, 38, -1, -1, 41,
+ -1, -1, 44, 124, -1, -1, -1, -1, -1, 93,
+ 94, -1, -1, -1, -1, -1, 58, 59, -1, 61,
+ -1, 63, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, 38, -1, -1, 41, -1, -1, 44,
+ 124, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, 93, 94, 58, 59, -1, 61, -1, 63, -1,
+ -1, -1, -1, -1, -1, -1, -1, 263, -1, -1,
+ -1, -1, -1, -1, -1, 271, 272, 273, 274, -1,
+ -1, -1, 124, -1, -1, -1, -1, -1, 93, 94,
+ -1, 263, -1, -1, -1, -1, -1, -1, -1, 271,
+ 272, 273, 274, -1, -1, 301, 302, 303, 304, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, 38, 124,
+ -1, 41, 318, 319, 44, 321, 322, 323, 324, -1,
+ 326, 327, 328, -1, -1, -1, -1, -1, 58, 59,
+ -1, 61, 263, 63, -1, -1, 318, 319, -1, -1,
+ 271, 272, 273, 274, -1, 327, 328, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, 93, 94, -1, -1, -1, -1, 263,
+ 301, 302, 303, 304, -1, -1, -1, 271, 272, 273,
+ 274, -1, -1, 41, -1, -1, 44, 318, 319, -1,
+ 321, 322, 323, 324, 124, 326, 327, 328, -1, -1,
+ 58, 59, -1, -1, -1, -1, -1, 301, 302, 303,
+ 304, 263, -1, -1, -1, -1, -1, -1, -1, 271,
+ 272, 273, 274, -1, 318, 319, -1, 321, 322, 323,
+ 324, -1, 326, 327, 328, 93, -1, -1, -1, -1,
+ 38, -1, -1, 41, -1, -1, 44, -1, 263, 301,
+ 302, 303, 304, -1, -1, -1, 271, 272, 273, 274,
+ 58, 59, -1, 61, -1, 63, 318, 319, -1, 321,
+ 322, 323, 324, -1, 326, 327, 328, -1, -1, -1,
+ 41, -1, -1, 44, -1, -1, 301, 302, 303, 304,
+ -1, -1, -1, -1, -1, 93, 94, 58, 59, -1,
+ -1, -1, -1, 318, 319, -1, 321, 322, 323, 324,
+ -1, 326, 327, 328, 38, -1, -1, 41, -1, -1,
+ 44, -1, -1, -1, -1, -1, 124, -1, 41, -1,
+ -1, 44, 93, 263, 58, 59, -1, 61, -1, 63,
+ -1, 271, 272, 273, 274, 58, 59, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, 38, -1, -1, 41,
+ -1, -1, 44, -1, -1, -1, -1, -1, -1, 93,
+ 94, 301, 302, 303, 304, -1, 58, 59, -1, 61,
+ 93, 63, -1, -1, -1, -1, -1, -1, 318, 319,
+ -1, 321, 322, 323, 324, -1, 326, 327, 328, 38,
+ 124, -1, 41, -1, -1, 44, -1, -1, -1, -1,
+ -1, 93, 94, 271, 272, 273, 274, -1, -1, 58,
+ 59, -1, 61, -1, 63, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, 38, 124, -1, 41, -1, -1, 44, -1, -1,
+ -1, -1, -1, -1, 93, 94, -1, -1, -1, -1,
+ -1, 58, 59, -1, 61, 263, 63, -1, -1, 327,
+ 328, -1, -1, 271, 272, 273, 274, -1, -1, -1,
+ -1, -1, -1, -1, -1, 124, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, 93, 94, -1, -1,
+ -1, -1, -1, 301, 302, 303, 304, -1, -1, -1,
+ 271, 272, 273, 274, -1, -1, -1, -1, -1, -1,
+ 318, 319, -1, 321, 322, 323, 324, 124, 326, 327,
+ 328, 38, -1, -1, 41, -1, -1, 44, -1, 263,
+ -1, -1, -1, -1, -1, -1, -1, 271, 272, 273,
+ 274, 58, 59, -1, 61, -1, 63, -1, 271, 272,
+ 273, 274, -1, -1, -1, -1, 327, 328, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, 301, 302, 303,
+ 304, 263, -1, -1, -1, -1, 93, 94, -1, 271,
+ 272, 273, 274, -1, 318, 319, -1, 321, 322, 323,
+ 324, -1, 326, 327, 328, 38, -1, -1, 41, -1,
+ -1, -1, -1, -1, 327, 328, -1, 124, -1, 301,
+ 302, 303, 304, -1, 263, 58, 59, -1, 61, -1,
+ 63, -1, 271, 272, 273, 274, 318, 319, -1, 321,
+ 322, 323, 324, -1, 326, 327, 328, 38, -1, -1,
+ 41, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ 93, 94, 301, 302, 303, 304, 263, 58, 59, -1,
+ 61, -1, 63, -1, 271, 272, 273, 274, -1, 318,
+ 319, -1, 321, 322, 323, 324, -1, 326, 327, 328,
+ 38, 124, -1, 41, -1, -1, -1, -1, -1, -1,
+ -1, -1, 93, 94, 301, 302, 303, 304, -1, -1,
+ 58, 59, -1, 61, -1, 63, -1, -1, -1, -1,
+ -1, 318, 319, -1, 321, 322, 323, 324, -1, 326,
+ 327, 328, 38, 124, -1, 41, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, 93, 94, -1, -1, -1,
+ -1, -1, 58, 59, -1, 61, 263, 63, -1, -1,
+ -1, -1, -1, -1, 271, 272, 273, 274, -1, -1,
+ -1, -1, -1, -1, -1, -1, 124, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, 93, 94, -1,
+ -1, -1, -1, -1, 301, 302, 303, 304, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, 318, 319, -1, 321, 322, 323, 324, 124, 326,
+ 327, 328, 38, -1, -1, 41, -1, -1, 44, -1,
+ 263, -1, -1, -1, -1, -1, -1, -1, 271, 272,
+ 273, 274, 58, 59, -1, 61, -1, 63, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, 301, 302,
+ 303, 304, 263, -1, -1, -1, -1, 93, 94, -1,
+ 271, 272, 273, 274, -1, 318, 319, -1, 321, 322,
+ 323, 324, -1, 326, 327, 328, 38, -1, -1, 41,
+ -1, -1, 44, -1, -1, -1, -1, -1, 124, -1,
+ 301, 302, 303, 304, -1, 263, 58, 59, -1, 61,
+ -1, 63, -1, 271, 272, 273, 274, 318, 319, -1,
+ 321, 322, 323, 324, -1, 326, 327, 328, 38, -1,
+ -1, 41, -1, -1, 44, -1, -1, -1, -1, -1,
+ -1, 93, 94, 301, 302, 303, 304, 263, 58, 59,
+ -1, 61, -1, 63, -1, 271, 272, 273, 274, -1,
+ 318, 319, -1, 321, 322, 323, 324, -1, 326, 327,
+ 328, 38, 124, -1, 41, -1, -1, 44, -1, -1,
+ -1, -1, -1, 93, 94, 301, 302, 303, 304, -1,
+ -1, 58, 59, -1, 61, -1, 63, -1, -1, -1,
+ -1, -1, 318, 319, -1, 321, 322, 323, 324, -1,
+ 326, 327, 328, 38, 124, -1, 41, -1, -1, 44,
+ -1, -1, -1, -1, -1, -1, 93, 94, -1, -1,
+ -1, -1, -1, 58, 59, -1, 61, 263, 63, -1,
+ -1, -1, -1, -1, -1, 271, 272, 273, 274, -1,
+ -1, -1, -1, -1, -1, -1, -1, 124, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, 93, 94,
+ -1, -1, -1, -1, -1, 301, 302, 303, 304, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, 318, 319, -1, 321, 322, 323, 324, 124,
+ -1, 327, 328, 38, -1, -1, 41, -1, -1, 44,
+ -1, 263, -1, -1, -1, -1, -1, -1, -1, 271,
+ 272, 273, 274, 58, 59, -1, 61, -1, 63, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, 41, -1,
+ -1, 44, -1, -1, -1, -1, -1, -1, -1, 301,
+ 302, 303, 304, 263, -1, 58, 59, -1, 93, 94,
+ -1, 271, 272, 273, 274, -1, 318, 319, -1, 321,
+ 322, 323, 324, -1, -1, 327, 328, 38, -1, -1,
+ 41, -1, -1, 44, -1, -1, -1, -1, -1, 124,
+ 93, 301, 302, 303, 304, -1, 263, 58, 59, -1,
+ 61, -1, 63, -1, 271, 272, 273, 274, 318, 319,
+ -1, 321, 322, 323, 324, -1, -1, 327, 328, 38,
+ -1, -1, 41, -1, -1, 44, -1, -1, -1, -1,
+ -1, -1, 93, 94, 301, 302, 303, 304, 263, 58,
+ 59, -1, 61, -1, 63, -1, 271, 272, 273, 274,
+ -1, 318, 319, -1, 321, 322, -1, -1, -1, -1,
+ 327, 328, 38, 124, -1, 41, -1, -1, 44, -1,
+ -1, -1, -1, -1, 93, 94, 301, 302, -1, 304,
+ -1, -1, 58, 59, -1, 61, 38, 63, -1, 41,
+ -1, -1, 44, 318, 319, -1, 321, 322, 41, -1,
+ -1, 44, 327, 328, -1, 124, 58, 59, -1, 61,
+ -1, 63, -1, -1, -1, 58, 59, 93, 94, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, 263, -1,
+ -1, -1, -1, -1, -1, -1, 271, 272, 273, 274,
+ -1, 93, 94, -1, -1, -1, -1, -1, 124, -1,
+ 93, -1, -1, 38, -1, -1, 41, -1, -1, 44,
+ -1, -1, -1, -1, -1, -1, 301, 302, 271, 272,
+ 273, 274, 124, 58, 59, -1, 61, -1, 63, -1,
+ -1, -1, -1, 318, 319, -1, 321, 322, -1, -1,
+ -1, -1, 327, 328, 38, -1, -1, 41, -1, -1,
+ 44, -1, 263, -1, -1, -1, -1, -1, 93, 94,
+ 271, 272, 273, 274, 58, 59, -1, 61, -1, 63,
+ -1, -1, -1, -1, 327, 328, -1, -1, -1, 41,
+ -1, -1, 44, -1, -1, -1, -1, -1, -1, 124,
+ 301, 302, -1, -1, 263, -1, 58, 59, -1, 93,
+ 94, -1, 271, 272, 273, 274, -1, 318, 319, -1,
+ 321, 322, -1, -1, -1, -1, 327, 328, 38, -1,
+ -1, 41, -1, -1, 44, -1, -1, -1, -1, -1,
+ 124, 93, 301, 302, -1, -1, -1, 263, 58, 59,
+ -1, 61, -1, 63, -1, 271, 272, 273, 274, 318,
+ 319, -1, -1, -1, -1, -1, -1, -1, 327, 328,
+ -1, 263, -1, -1, -1, -1, -1, -1, -1, 271,
+ 272, 273, 274, 93, 94, 301, 302, -1, 271, 272,
+ 273, 274, -1, -1, -1, 38, -1, -1, 41, -1,
+ -1, 44, 318, 319, 41, -1, -1, 44, -1, 301,
+ 302, 327, 328, -1, 124, 58, 59, -1, 61, -1,
+ 63, 58, 59, -1, -1, -1, 318, 319, -1, -1,
+ -1, -1, -1, -1, -1, 327, 328, -1, 263, -1,
+ -1, -1, -1, -1, 327, 328, 271, 272, 273, 274,
+ 93, 94, -1, -1, -1, -1, 93, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, 302, -1, 263,
+ -1, 124, -1, -1, -1, -1, -1, 271, 272, 273,
+ 274, -1, 38, 318, 319, 41, -1, -1, 44, -1,
+ -1, -1, 327, 328, 38, -1, -1, 41, -1, -1,
+ 44, -1, 58, 59, -1, 61, -1, 63, -1, 271,
+ 272, 273, 274, -1, 58, 59, -1, 61, -1, 63,
+ -1, -1, -1, -1, 318, 319, -1, -1, -1, -1,
+ -1, -1, -1, 327, 328, -1, -1, 93, 94, -1,
+ -1, -1, -1, 263, -1, -1, -1, -1, -1, 93,
+ 94, 271, 272, 273, 274, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, 327, 328, 38, 124, -1,
+ 41, -1, -1, 44, -1, -1, -1, -1, -1, -1,
+ 124, 301, 302, 303, 304, -1, -1, 58, 59, -1,
+ 61, -1, 63, -1, -1, -1, -1, -1, 318, 319,
+ -1, 321, 322, 323, 324, -1, 326, -1, -1, -1,
+ 263, -1, -1, -1, -1, -1, -1, -1, 271, 272,
+ 273, 274, 93, 94, 271, 272, 273, 274, -1, -1,
+ -1, -1, -1, -1, 38, -1, -1, 41, -1, -1,
+ 44, -1, -1, -1, -1, -1, -1, -1, 301, 302,
+ 303, 304, -1, 124, 58, 59, -1, 61, -1, 63,
+ 41, -1, -1, 44, -1, 318, 319, -1, 321, 322,
+ 323, 324, -1, 326, -1, -1, -1, 58, 59, -1,
+ 327, 328, -1, -1, -1, -1, -1, -1, -1, 93,
+ 94, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, 263, -1, -1,
+ -1, -1, 93, -1, -1, 271, 272, 273, 274, 263,
+ 124, -1, -1, -1, -1, -1, -1, 271, 272, 273,
+ 274, 38, -1, -1, 41, -1, -1, 44, -1, -1,
+ -1, -1, -1, -1, -1, 301, 302, 303, 304, -1,
+ -1, 58, 59, -1, 61, -1, 63, 301, 302, 303,
+ 304, -1, 318, 319, -1, 321, 322, 323, 324, -1,
+ 326, -1, -1, -1, 318, 319, -1, 321, 322, 323,
+ 324, -1, 326, -1, -1, -1, 93, 94, 38, -1,
+ -1, 41, 263, -1, 44, -1, -1, -1, -1, -1,
+ 271, 272, 273, 274, -1, -1, -1, -1, 58, 59,
+ -1, 61, -1, 63, -1, 38, -1, 124, 41, -1,
+ -1, 44, -1, -1, -1, -1, -1, -1, -1, -1,
+ 301, 302, 303, 304, -1, -1, -1, -1, 61, -1,
+ 63, -1, -1, 93, 94, -1, -1, 318, 319, -1,
+ 321, 322, 323, 324, -1, 326, -1, 38, -1, 263,
+ 41, -1, -1, 44, -1, -1, -1, 271, 272, 273,
+ 274, 94, -1, -1, 124, -1, -1, 58, 59, -1,
+ 61, -1, 63, 38, -1, -1, 41, -1, -1, 44,
+ 271, 272, 273, 274, -1, -1, -1, 301, 302, 303,
+ 304, 124, -1, 58, 59, -1, 61, -1, 63, -1,
+ -1, -1, 93, 94, 318, 319, -1, 321, 322, 323,
+ 324, -1, 326, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, 38, -1, -1, -1, 93, 94,
+ 44, -1, -1, 124, -1, 38, 327, 328, -1, -1,
+ -1, 44, -1, -1, -1, -1, 263, 61, 41, 63,
+ -1, 44, -1, -1, 271, 272, 273, 274, 61, 124,
+ 63, -1, -1, -1, -1, 58, 59, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ 94, -1, -1, -1, 301, 302, 303, 304, -1, -1,
+ -1, 94, -1, -1, -1, -1, -1, -1, -1, -1,
+ 93, 318, 319, 263, 321, 322, 323, 324, -1, 326,
+ 124, 271, 272, 273, 274, -1, -1, -1, -1, -1,
+ -1, 124, -1, -1, -1, -1, 33, -1, -1, -1,
+ 263, -1, -1, 40, -1, -1, 43, -1, 45, -1,
+ -1, 301, 302, 303, 304, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, 318, 319,
+ -1, 321, 322, 323, 324, -1, 326, -1, 301, 302,
+ 303, 304, 263, -1, -1, -1, -1, -1, -1, -1,
+ 271, 272, 273, 274, 91, 318, 319, -1, 321, 322,
+ 323, 324, -1, 326, -1, -1, -1, -1, 263, -1,
+ 41, -1, -1, 44, -1, -1, 271, 272, 273, 274,
+ 301, 302, 303, 304, -1, -1, 123, 58, 59, 126,
+ -1, -1, -1, 41, -1, -1, 44, 318, 319, -1,
+ 321, 322, 323, 324, -1, 326, 301, 302, 303, 304,
+ 58, 59, -1, 61, -1, 63, -1, -1, -1, 263,
+ -1, -1, 93, 318, 319, -1, 321, 322, 323, 324,
+ 263, 326, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, 41, 93, 94, 44, 271, 272,
+ 273, 274, -1, -1, -1, -1, -1, 301, 302, 303,
+ 304, 58, 59, -1, 61, -1, 63, -1, 301, 302,
+ 303, 304, -1, -1, 318, 319, 124, 321, 322, 323,
+ 324, -1, 326, -1, -1, 318, 319, -1, 321, 322,
+ 323, 324, -1, 326, -1, -1, 93, 94, -1, -1,
+ -1, -1, -1, -1, 327, 328, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ 257, -1, -1, 260, 261, 262, -1, 124, -1, 266,
+ 267, 268, 269, 270, -1, -1, -1, -1, -1, -1,
+ -1, 278, 279, -1, 281, 282, 283, 284, 285, 286,
+ 287, 288, 289, 290, 291, 292, 293, 294, 295, 296,
+ -1, 298, 299, 300, -1, -1, -1, -1, -1, 306,
+ -1, 308, 309, 310, 311, 312, 313, 314, 315, 316,
+ 317, -1, -1, 320, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ 271, 272, 273, 274, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, 263, -1, -1, -1, -1,
+ -1, -1, -1, 271, 272, 273, 274, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, 66, -1, -1, -1, -1, -1, 72, -1,
+ -1, -1, -1, -1, -1, -1, 327, 328, -1, -1,
+ -1, -1, -1, -1, -1, -1, 263, -1, -1, -1,
+ 318, 319, -1, -1, 271, 272, 273, 274, -1, 327,
+ 328, -1, -1, 107, -1, 109, -1, 111, -1, 113,
+ -1, -1, 116, -1, 118, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, 128, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, 142, -1,
+ -1, 318, 319, 147, 148, 149, 150, 151, 152, 153,
+ 327, 328, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, 170, 171, 172, 173,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, 202, 203,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, 218, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, 241, -1, 243,
+ 244, -1, -1, -1, -1, -1, -1, -1, 252, -1,
+ -1, -1, -1, 257, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, 291, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, 301, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, 311, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, 330, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, 341,
+};
+#define YYFINAL 1
+#ifndef YYDEBUG
+#define YYDEBUG 0
+#endif
+#define YYMAXTOKEN 328
+#if YYDEBUG
+char *yyname[] = {
+"end-of-file",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+"'!'",0,0,0,0,"'&'",0,"'('","')'",0,"'+'","','","'-'",0,0,0,0,0,0,0,0,0,0,0,0,
+"':'","';'",0,"'='",0,"'?'",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,"'['",0,"']'","'^'",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+"'{'","'|'","'}'","'~'",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,"WORD","LABEL","APPEND","OPEN",
+"SSELECT","LOOPEX","DOTDOT","USING","FORMAT","DO","SHIFT","PUSH","POP",
+"LVALFUN","WHILE","UNTIL","IF","UNLESS","ELSE","ELSIF","CONTINUE","SPLIT",
+"FLIST","FOR","FILOP","FILOP2","FILOP3","FILOP4","FILOP22","FILOP25","FUNC0",
+"FUNC1","FUNC2","FUNC2x","FUNC3","FUNC4","FUNC5","HSHFUN","HSHFUN3","FLIST2",
+"SUB","FILETEST","LOCAL","DELETE","RELOP","EQOP","MULOP","ADDOP","PACKAGE",
+"AMPER","FORMLIST","REG","ARYLEN","ARY","HSH","STAR","SUBST","PATTERN",
+"RSTRING","TRANS","LISTOP","OROR","ANDAND","UNIOP","LS","RS","MATCH","NMATCH",
+"UMINUS","POW","INC","DEC",
+};
+char *yyrule[] = {
+"$accept : prog",
+"$$1 :",
+"prog : $$1 lineseq",
+"compblock : block CONTINUE block",
+"compblock : block else",
+"else :",
+"else : ELSE block",
+"else : ELSIF '(' expr ')' compblock",
+"block : '{' remember lineseq '}'",
+"remember :",
+"lineseq :",
+"lineseq : lineseq line",
+"line : decl",
+"line : label cond",
+"line : loop",
+"line : label ';'",
+"line : label sideff ';'",
+"sideff : error",
+"sideff : expr",
+"sideff : expr IF expr",
+"sideff : expr UNLESS expr",
+"sideff : expr WHILE expr",
+"sideff : expr UNTIL expr",
+"cond : IF '(' expr ')' compblock",
+"cond : UNLESS '(' expr ')' compblock",
+"cond : IF block compblock",
+"cond : UNLESS block compblock",
+"loop : label WHILE '(' texpr ')' compblock",
+"loop : label UNTIL '(' expr ')' compblock",
+"loop : label WHILE block compblock",
+"loop : label UNTIL block compblock",
+"loop : label FOR REG '(' expr crp compblock",
+"loop : label FOR '(' expr crp compblock",
+"loop : label FOR '(' nexpr ';' texpr ';' nexpr ')' block",
+"loop : label compblock",
+"nexpr :",
+"nexpr : sideff",
+"texpr :",
+"texpr : expr",
+"label :",
+"label : LABEL",
+"decl : format",
+"decl : subrout",
+"decl : package",
+"format : FORMAT WORD '=' FORMLIST",
+"format : FORMAT '=' FORMLIST",
+"subrout : SUB WORD block",
+"package : PACKAGE WORD ';'",
+"cexpr : ',' expr",
+"expr : expr ',' sexpr",
+"expr : sexpr",
+"csexpr : ',' sexpr",
+"sexpr : sexpr '=' sexpr",
+"sexpr : sexpr POW '=' sexpr",
+"sexpr : sexpr MULOP '=' sexpr",
+"sexpr : sexpr ADDOP '=' sexpr",
+"sexpr : sexpr LS '=' sexpr",
+"sexpr : sexpr RS '=' sexpr",
+"sexpr : sexpr '&' '=' sexpr",
+"sexpr : sexpr '^' '=' sexpr",
+"sexpr : sexpr '|' '=' sexpr",
+"sexpr : sexpr POW sexpr",
+"sexpr : sexpr MULOP sexpr",
+"sexpr : sexpr ADDOP sexpr",
+"sexpr : sexpr LS sexpr",
+"sexpr : sexpr RS sexpr",
+"sexpr : sexpr RELOP sexpr",
+"sexpr : sexpr EQOP sexpr",
+"sexpr : sexpr '&' sexpr",
+"sexpr : sexpr '^' sexpr",
+"sexpr : sexpr '|' sexpr",
+"sexpr : sexpr DOTDOT sexpr",
+"sexpr : sexpr ANDAND sexpr",
+"sexpr : sexpr OROR sexpr",
+"sexpr : sexpr '?' sexpr ':' sexpr",
+"sexpr : sexpr MATCH sexpr",
+"sexpr : sexpr NMATCH sexpr",
+"sexpr : term",
+"term : '-' term",
+"term : '+' term",
+"term : '!' term",
+"term : '~' term",
+"term : term INC",
+"term : term DEC",
+"term : INC term",
+"term : DEC term",
+"term : FILETEST WORD",
+"term : FILETEST sexpr",
+"term : FILETEST",
+"term : LOCAL '(' expr crp",
+"term : '(' expr crp",
+"term : '(' ')'",
+"term : DO sexpr",
+"term : DO block",
+"term : REG",
+"term : STAR",
+"term : REG '[' expr ']'",
+"term : HSH",
+"term : ARY",
+"term : REG '{' expr ';' '}'",
+"term : '(' expr crp '[' expr ']'",
+"term : '(' ')' '[' expr ']'",
+"term : ARY '[' expr ']'",
+"term : ARY '{' expr ';' '}'",
+"term : DELETE REG '{' expr ';' '}'",
+"term : DELETE '(' REG '{' expr ';' '}' ')'",
+"term : ARYLEN",
+"term : RSTRING",
+"term : PATTERN",
+"term : SUBST",
+"term : TRANS",
+"term : DO WORD '(' expr crp",
+"term : AMPER WORD '(' expr crp",
+"term : DO WORD '(' ')'",
+"term : AMPER WORD '(' ')'",
+"term : AMPER WORD",
+"term : DO REG '(' expr crp",
+"term : AMPER REG '(' expr crp",
+"term : DO REG '(' ')'",
+"term : AMPER REG '(' ')'",
+"term : AMPER REG",
+"term : LOOPEX",
+"term : LOOPEX WORD",
+"term : UNIOP",
+"term : UNIOP block",
+"term : UNIOP sexpr",
+"term : SSELECT",
+"term : SSELECT WORD",
+"term : SSELECT '(' handle ')'",
+"term : SSELECT '(' sexpr csexpr csexpr csexpr ')'",
+"term : OPEN WORD",
+"term : OPEN '(' WORD ')'",
+"term : OPEN '(' handle cexpr ')'",
+"term : FILOP '(' handle ')'",
+"term : FILOP WORD",
+"term : FILOP REG",
+"term : FILOP '(' ')'",
+"term : FILOP",
+"term : FILOP2 '(' handle cexpr ')'",
+"term : FILOP3 '(' handle csexpr cexpr ')'",
+"term : FILOP22 '(' handle ',' handle ')'",
+"term : FILOP4 '(' handle csexpr csexpr cexpr ')'",
+"term : FILOP25 '(' handle ',' handle csexpr csexpr cexpr ')'",
+"term : PUSH '(' aryword ',' expr crp",
+"term : POP aryword",
+"term : POP '(' aryword ')'",
+"term : SHIFT aryword",
+"term : SHIFT '(' aryword ')'",
+"term : SHIFT",
+"term : SPLIT",
+"term : SPLIT '(' sexpr csexpr csexpr ')'",
+"term : SPLIT '(' sexpr csexpr ')'",
+"term : SPLIT '(' sexpr ')'",
+"term : FLIST2 '(' sexpr cexpr ')'",
+"term : FLIST '(' expr crp",
+"term : LVALFUN sexpr",
+"term : LVALFUN",
+"term : FUNC0",
+"term : FUNC0 '(' ')'",
+"term : FUNC1 '(' ')'",
+"term : FUNC1 '(' expr ')'",
+"term : FUNC2 '(' sexpr cexpr ')'",
+"term : FUNC2x '(' sexpr csexpr ')'",
+"term : FUNC2x '(' sexpr csexpr cexpr ')'",
+"term : FUNC3 '(' sexpr csexpr cexpr ')'",
+"term : FUNC4 '(' sexpr csexpr csexpr cexpr ')'",
+"term : FUNC5 '(' sexpr csexpr csexpr csexpr cexpr ')'",
+"term : HSHFUN '(' hshword ')'",
+"term : HSHFUN hshword",
+"term : HSHFUN3 '(' hshword csexpr cexpr ')'",
+"term : bareword",
+"term : listop",
+"listop : LISTOP",
+"listop : LISTOP expr",
+"listop : LISTOP WORD",
+"listop : LISTOP WORD expr",
+"listop : LISTOP REG expr",
+"listop : LISTOP block expr",
+"handle : WORD",
+"handle : sexpr",
+"aryword : WORD",
+"aryword : ARY",
+"hshword : WORD",
+"hshword : HSH",
+"crp : ',' ')'",
+"crp : ')'",
+"bareword : WORD",
+};
+#endif
+#ifdef YYSTACKSIZE
+#undef YYMAXDEPTH
+#define YYMAXDEPTH YYSTACKSIZE
+#else
+#ifdef YYMAXDEPTH
+#define YYSTACKSIZE YYMAXDEPTH
+#else
+#define YYSTACKSIZE 500
+#define YYMAXDEPTH 500
+#endif
+#endif
+int yydebug;
+int yynerrs;
+int yyerrflag;
+int yychar;
+short *yyssp;
+YYSTYPE *yyvsp;
+YYSTYPE yyval;
+YYSTYPE yylval;
+short yyss[YYSTACKSIZE];
+YYSTYPE yyvs[YYSTACKSIZE];
+#define yystacksize YYSTACKSIZE
+#line 876 "perly.y"
+ /* PROGRAM */
+#line 1820 "y.tab.c"
+#define YYABORT goto yyabort
+#define YYREJECT goto yyabort
+#define YYACCEPT goto yyaccept
+#define YYERROR goto yyerrlab
+int
+yyparse()
+{
+ register int yym, yyn, yystate;
+#if YYDEBUG
+ register char *yys;
+ extern char *getenv();
+
+ if (yys = getenv("YYDEBUG"))
+ {
+ yyn = *yys;
+ if (yyn >= '0' && yyn <= '9')
+ yydebug = yyn - '0';
+ }
+#endif
+
+ yynerrs = 0;
+ yyerrflag = 0;
+ yychar = (-1);
+
+ yyssp = yyss;
+ yyvsp = yyvs;
+ *yyssp = yystate = 0;
+
+yyloop:
+ if (yyn = yydefred[yystate]) goto yyreduce;
+ if (yychar < 0)
+ {
+ if ((yychar = yylex()) < 0) yychar = 0;
+#if YYDEBUG
+ if (yydebug)
+ {
+ yys = 0;
+ if (yychar <= YYMAXTOKEN) yys = yyname[yychar];
+ if (!yys) yys = "illegal-symbol";
+ printf("%sdebug: state %d, reading %d (%s)\n",
+ YYPREFIX, yystate, yychar, yys);
+ }
+#endif
+ }
+ if ((yyn = yysindex[yystate]) && (yyn += yychar) >= 0 &&
+ yyn <= YYTABLESIZE && yycheck[yyn] == yychar)
+ {
+#if YYDEBUG
+ if (yydebug)
+ printf("%sdebug: state %d, shifting to state %d\n",
+ YYPREFIX, yystate, yytable[yyn]);
+#endif
+ if (yyssp >= yyss + yystacksize - 1)
+ {
+ goto yyoverflow;
+ }
+ *++yyssp = yystate = yytable[yyn];
+ *++yyvsp = yylval;
+ yychar = (-1);
+ if (yyerrflag > 0) --yyerrflag;
+ goto yyloop;
+ }
+ if ((yyn = yyrindex[yystate]) && (yyn += yychar) >= 0 &&
+ yyn <= YYTABLESIZE && yycheck[yyn] == yychar)
+ {
+ yyn = yytable[yyn];
+ goto yyreduce;
+ }
+ if (yyerrflag) goto yyinrecovery;
+#ifdef lint
+ goto yynewerror;
+#endif
+yynewerror:
+ yyerror("syntax error");
+#ifdef lint
+ goto yyerrlab;
+#endif
+yyerrlab:
+ ++yynerrs;
+yyinrecovery:
+ if (yyerrflag < 3)
+ {
+ yyerrflag = 3;
+ for (;;)
+ {
+ if ((yyn = yysindex[*yyssp]) && (yyn += YYERRCODE) >= 0 &&
+ yyn <= YYTABLESIZE && yycheck[yyn] == YYERRCODE)
+ {
+#if YYDEBUG
+ if (yydebug)
+ printf("%sdebug: state %d, error recovery shifting\
+ to state %d\n", YYPREFIX, *yyssp, yytable[yyn]);
+#endif
+ if (yyssp >= yyss + yystacksize - 1)
+ {
+ goto yyoverflow;
+ }
+ *++yyssp = yystate = yytable[yyn];
+ *++yyvsp = yylval;
+ goto yyloop;
+ }
+ else
+ {
+#if YYDEBUG
+ if (yydebug)
+ printf("%sdebug: error recovery discarding state %d\n",
+ YYPREFIX, *yyssp);
+#endif
+ if (yyssp <= yyss) goto yyabort;
+ --yyssp;
+ --yyvsp;
+ }
+ }
+ }
+ else
+ {
+ if (yychar == 0) goto yyabort;
+#if YYDEBUG
+ if (yydebug)
+ {
+ yys = 0;
+ if (yychar <= YYMAXTOKEN) yys = yyname[yychar];
+ if (!yys) yys = "illegal-symbol";
+ printf("%sdebug: state %d, error recovery discards token %d (%s)\n",
+ YYPREFIX, yystate, yychar, yys);
+ }
+#endif
+ yychar = (-1);
+ goto yyloop;
+ }
+yyreduce:
+#if YYDEBUG
+ if (yydebug)
+ printf("%sdebug: state %d, reducing by rule %d (%s)\n",
+ YYPREFIX, yystate, yyn, yyrule[yyn]);
+#endif
+ yym = yylen[yyn];
+ yyval = yyvsp[1-yym];
+ switch (yyn)
+ {
+case 1:
+#line 115 "perly.y"
+{
+#if defined(YYDEBUG) && defined(DEBUGGING)
+ yydebug = (debug & 1);
+#endif
+ expectterm = 2;
+ }
+break;
+case 2:
+#line 122 "perly.y"
+{ if (in_eval)
+ eval_root = block_head(yyvsp[0].cmdval);
+ else
+ main_root = block_head(yyvsp[0].cmdval); }
+break;
+case 3:
+#line 129 "perly.y"
+{ yyval.compval.comp_true = yyvsp[-2].cmdval; yyval.compval.comp_alt = yyvsp[0].cmdval; }
+break;
+case 4:
+#line 131 "perly.y"
+{ yyval.compval.comp_true = yyvsp[-1].cmdval; yyval.compval.comp_alt = yyvsp[0].cmdval; }
+break;
+case 5:
+#line 135 "perly.y"
+{ yyval.cmdval = Nullcmd; }
+break;
+case 6:
+#line 137 "perly.y"
+{ yyval.cmdval = yyvsp[0].cmdval; }
+break;
+case 7:
+#line 139 "perly.y"
+{ cmdline = yyvsp[-4].ival;
+ yyval.cmdval = make_ccmd(C_ELSIF,1,yyvsp[-2].arg,yyvsp[0].compval); }
+break;
+case 8:
+#line 144 "perly.y"
+{ yyval.cmdval = block_head(yyvsp[-1].cmdval);
+ if (cmdline > (line_t)yyvsp[-3].ival)
+ cmdline = yyvsp[-3].ival;
+ if (savestack->ary_fill > yyvsp[-2].ival)
+ restorelist(yyvsp[-2].ival);
+ expectterm = 2; }
+break;
+case 9:
+#line 153 "perly.y"
+{ yyval.ival = savestack->ary_fill; }
+break;
+case 10:
+#line 157 "perly.y"
+{ yyval.cmdval = Nullcmd; }
+break;
+case 11:
+#line 159 "perly.y"
+{ yyval.cmdval = append_line(yyvsp[-1].cmdval,yyvsp[0].cmdval); }
+break;
+case 12:
+#line 163 "perly.y"
+{ yyval.cmdval = Nullcmd; }
+break;
+case 13:
+#line 165 "perly.y"
+{ yyval.cmdval = add_label(yyvsp[-1].cval,yyvsp[0].cmdval); }
+break;
+case 15:
+#line 168 "perly.y"
+{ if (yyvsp[-1].cval != Nullch) {
+ yyval.cmdval = add_label(yyvsp[-1].cval, make_acmd(C_EXPR, Nullstab,
+ Nullarg, Nullarg) );
+ }
+ else {
+ yyval.cmdval = Nullcmd;
+ cmdline = NOLINE;
+ }
+ expectterm = 2; }
+break;
+case 16:
+#line 178 "perly.y"
+{ yyval.cmdval = add_label(yyvsp[-2].cval,yyvsp[-1].cmdval);
+ expectterm = 2; }
+break;
+case 17:
+#line 183 "perly.y"
+{ yyval.cmdval = Nullcmd; }
+break;
+case 18:
+#line 185 "perly.y"
+{ yyval.cmdval = make_acmd(C_EXPR, Nullstab, yyvsp[0].arg, Nullarg); }
+break;
+case 19:
+#line 187 "perly.y"
+{ yyval.cmdval = addcond(
+ make_acmd(C_EXPR, Nullstab, Nullarg, yyvsp[-2].arg), yyvsp[0].arg); }
+break;
+case 20:
+#line 190 "perly.y"
+{ yyval.cmdval = addcond(invert(
+ make_acmd(C_EXPR, Nullstab, Nullarg, yyvsp[-2].arg)), yyvsp[0].arg); }
+break;
+case 21:
+#line 193 "perly.y"
+{ yyval.cmdval = addloop(
+ make_acmd(C_EXPR, Nullstab, Nullarg, yyvsp[-2].arg), yyvsp[0].arg); }
+break;
+case 22:
+#line 196 "perly.y"
+{ yyval.cmdval = addloop(invert(
+ make_acmd(C_EXPR, Nullstab, Nullarg, yyvsp[-2].arg)), yyvsp[0].arg); }
+break;
+case 23:
+#line 201 "perly.y"
+{ cmdline = yyvsp[-4].ival;
+ yyval.cmdval = make_icmd(C_IF,yyvsp[-2].arg,yyvsp[0].compval); }
+break;
+case 24:
+#line 204 "perly.y"
+{ cmdline = yyvsp[-4].ival;
+ yyval.cmdval = invert(make_icmd(C_IF,yyvsp[-2].arg,yyvsp[0].compval)); }
+break;
+case 25:
+#line 207 "perly.y"
+{ cmdline = yyvsp[-2].ival;
+ yyval.cmdval = make_icmd(C_IF,cmd_to_arg(yyvsp[-1].cmdval),yyvsp[0].compval); }
+break;
+case 26:
+#line 210 "perly.y"
+{ cmdline = yyvsp[-2].ival;
+ yyval.cmdval = invert(make_icmd(C_IF,cmd_to_arg(yyvsp[-1].cmdval),yyvsp[0].compval)); }
+break;
+case 27:
+#line 215 "perly.y"
+{ cmdline = yyvsp[-4].ival;
+ yyval.cmdval = wopt(add_label(yyvsp[-5].cval,
+ make_ccmd(C_WHILE,1,yyvsp[-2].arg,yyvsp[0].compval) )); }
+break;
+case 28:
+#line 219 "perly.y"
+{ cmdline = yyvsp[-4].ival;
+ yyval.cmdval = wopt(add_label(yyvsp[-5].cval,
+ invert(make_ccmd(C_WHILE,1,yyvsp[-2].arg,yyvsp[0].compval)) )); }
+break;
+case 29:
+#line 223 "perly.y"
+{ cmdline = yyvsp[-2].ival;
+ yyval.cmdval = wopt(add_label(yyvsp[-3].cval,
+ make_ccmd(C_WHILE, 1, cmd_to_arg(yyvsp[-1].cmdval),yyvsp[0].compval) )); }
+break;
+case 30:
+#line 227 "perly.y"
+{ cmdline = yyvsp[-2].ival;
+ yyval.cmdval = wopt(add_label(yyvsp[-3].cval,
+ invert(make_ccmd(C_WHILE,1,cmd_to_arg(yyvsp[-1].cmdval),yyvsp[0].compval)) )); }
+break;
+case 31:
+#line 231 "perly.y"
+{ cmdline = yyvsp[-5].ival;
+ /*
+ * The following gobbledygook catches EXPRs that
+ * aren't explicit array refs and translates
+ * foreach VAR (EXPR) {
+ * into
+ * @ary = EXPR;
+ * foreach VAR (@ary) {
+ * where @ary is a hidden array made by genstab().
+ * (Note that @ary may become a local array if
+ * it is determined that it might be called
+ * recursively. See cmd_tosave().)
+ */
+ if (yyvsp[-2].arg->arg_type != O_ARRAY) {
+ scrstab = aadd(genstab());
+ yyval.cmdval = append_line(
+ make_acmd(C_EXPR, Nullstab,
+ l(make_op(O_ASSIGN,2,
+ listish(make_op(O_ARRAY, 1,
+ stab2arg(A_STAB,scrstab),
+ Nullarg,Nullarg )),
+ listish(make_list(yyvsp[-2].arg)),
+ Nullarg)),
+ Nullarg),
+ wopt(over(yyvsp[-4].stabval,add_label(yyvsp[-6].cval,
+ make_ccmd(C_WHILE, 0,
+ make_op(O_ARRAY, 1,
+ stab2arg(A_STAB,scrstab),
+ Nullarg,Nullarg ),
+ yyvsp[0].compval)))));
+ yyval.cmdval->c_line = yyvsp[-5].ival;
+ yyval.cmdval->c_head->c_line = yyvsp[-5].ival;
+ }
+ else {
+ yyval.cmdval = wopt(over(yyvsp[-4].stabval,add_label(yyvsp[-6].cval,
+ make_ccmd(C_WHILE,1,yyvsp[-2].arg,yyvsp[0].compval) )));
+ }
+ }
+break;
+case 32:
+#line 270 "perly.y"
+{ cmdline = yyvsp[-4].ival;
+ if (yyvsp[-2].arg->arg_type != O_ARRAY) {
+ scrstab = aadd(genstab());
+ yyval.cmdval = append_line(
+ make_acmd(C_EXPR, Nullstab,
+ l(make_op(O_ASSIGN,2,
+ listish(make_op(O_ARRAY, 1,
+ stab2arg(A_STAB,scrstab),
+ Nullarg,Nullarg )),
+ listish(make_list(yyvsp[-2].arg)),
+ Nullarg)),
+ Nullarg),
+ wopt(over(defstab,add_label(yyvsp[-5].cval,
+ make_ccmd(C_WHILE, 0,
+ make_op(O_ARRAY, 1,
+ stab2arg(A_STAB,scrstab),
+ Nullarg,Nullarg ),
+ yyvsp[0].compval)))));
+ yyval.cmdval->c_line = yyvsp[-4].ival;
+ yyval.cmdval->c_head->c_line = yyvsp[-4].ival;
+ }
+ else { /* lisp, anyone? */
+ yyval.cmdval = wopt(over(defstab,add_label(yyvsp[-5].cval,
+ make_ccmd(C_WHILE,1,yyvsp[-2].arg,yyvsp[0].compval) )));
+ }
+ }
+break;
+case 33:
+#line 298 "perly.y"
+{ yyval.compval.comp_true = yyvsp[0].cmdval;
+ yyval.compval.comp_alt = yyvsp[-2].cmdval;
+ cmdline = yyvsp[-8].ival;
+ yyval.cmdval = append_line(yyvsp[-6].cmdval,wopt(add_label(yyvsp[-9].cval,
+ make_ccmd(C_WHILE,1,yyvsp[-4].arg,yyval.compval) ))); }
+break;
+case 34:
+#line 304 "perly.y"
+{ yyval.cmdval = add_label(yyvsp[-1].cval,make_ccmd(C_BLOCK,1,Nullarg,yyvsp[0].compval)); }
+break;
+case 35:
+#line 308 "perly.y"
+{ yyval.cmdval = Nullcmd; }
+break;
+case 37:
+#line 313 "perly.y"
+{ (void)scanstr("1",SCAN_DEF); yyval.arg = yylval.arg; }
+break;
+case 39:
+#line 318 "perly.y"
+{ yyval.cval = Nullch; }
+break;
+case 41:
+#line 323 "perly.y"
+{ yyval.ival = 0; }
+break;
+case 42:
+#line 325 "perly.y"
+{ yyval.ival = 0; }
+break;
+case 43:
+#line 327 "perly.y"
+{ yyval.ival = 0; }
+break;
+case 44:
+#line 331 "perly.y"
+{ if (strEQ(yyvsp[-2].cval,"stdout"))
+ make_form(stabent("STDOUT",TRUE),yyvsp[0].formval);
+ else if (strEQ(yyvsp[-2].cval,"stderr"))
+ make_form(stabent("STDERR",TRUE),yyvsp[0].formval);
+ else
+ make_form(stabent(yyvsp[-2].cval,TRUE),yyvsp[0].formval);
+ Safefree(yyvsp[-2].cval); yyvsp[-2].cval = Nullch; }
+break;
+case 45:
+#line 339 "perly.y"
+{ make_form(stabent("STDOUT",TRUE),yyvsp[0].formval); }
+break;
+case 46:
+#line 343 "perly.y"
+{ make_sub(yyvsp[-1].cval,yyvsp[0].cmdval);
+ cmdline = NOLINE;
+ if (savestack->ary_fill > yyvsp[-2].ival)
+ restorelist(yyvsp[-2].ival); }
+break;
+case 47:
+#line 350 "perly.y"
+{ char tmpbuf[256];
+ STAB *tmpstab;
+
+ savehptr(&curstash);
+ saveitem(curstname);
+ str_set(curstname,yyvsp[-1].cval);
+ sprintf(tmpbuf,"'_%s",yyvsp[-1].cval);
+ tmpstab = stabent(tmpbuf,TRUE);
+ if (!stab_xhash(tmpstab))
+ stab_xhash(tmpstab) = hnew(0);
+ curstash = stab_xhash(tmpstab);
+ if (!curstash->tbl_name)
+ curstash->tbl_name = savestr(yyvsp[-1].cval);
+ curstash->tbl_coeffsize = 0;
+ Safefree(yyvsp[-1].cval); yyvsp[-1].cval = Nullch;
+ cmdline = NOLINE;
+ expectterm = 2;
+ }
+break;
+case 48:
+#line 371 "perly.y"
+{ yyval.arg = yyvsp[0].arg; }
+break;
+case 49:
+#line 375 "perly.y"
+{ yyval.arg = make_op(O_COMMA, 2, yyvsp[-2].arg, yyvsp[0].arg, Nullarg); }
+break;
+case 51:
+#line 380 "perly.y"
+{ yyval.arg = yyvsp[0].arg; }
+break;
+case 52:
+#line 384 "perly.y"
+{ yyvsp[-2].arg = listish(yyvsp[-2].arg);
+ if (yyvsp[-2].arg->arg_type == O_ASSIGN && yyvsp[-2].arg->arg_len == 1)
+ yyvsp[-2].arg->arg_type = O_ITEM; /* a local() */
+ if (yyvsp[-2].arg->arg_type == O_LIST)
+ yyvsp[0].arg = listish(yyvsp[0].arg);
+ yyval.arg = l(make_op(O_ASSIGN, 2, yyvsp[-2].arg, yyvsp[0].arg, Nullarg)); }
+break;
+case 53:
+#line 391 "perly.y"
+{ yyval.arg = l(make_op(O_POW, 2, yyvsp[-3].arg, yyvsp[0].arg, Nullarg)); }
+break;
+case 54:
+#line 393 "perly.y"
+{ yyval.arg = l(make_op(yyvsp[-2].ival, 2, yyvsp[-3].arg, yyvsp[0].arg, Nullarg)); }
+break;
+case 55:
+#line 395 "perly.y"
+{ yyval.arg = rcatmaybe(l(make_op(yyvsp[-2].ival, 2, yyvsp[-3].arg, yyvsp[0].arg, Nullarg)));}
+break;
+case 56:
+#line 397 "perly.y"
+{ yyval.arg = l(make_op(O_LEFT_SHIFT, 2, yyvsp[-3].arg, yyvsp[0].arg, Nullarg)); }
+break;
+case 57:
+#line 399 "perly.y"
+{ yyval.arg = l(make_op(O_RIGHT_SHIFT, 2, yyvsp[-3].arg, yyvsp[0].arg, Nullarg)); }
+break;
+case 58:
+#line 401 "perly.y"
+{ yyval.arg = l(make_op(O_BIT_AND, 2, yyvsp[-3].arg, yyvsp[0].arg, Nullarg)); }
+break;
+case 59:
+#line 403 "perly.y"
+{ yyval.arg = l(make_op(O_XOR, 2, yyvsp[-3].arg, yyvsp[0].arg, Nullarg)); }
+break;
+case 60:
+#line 405 "perly.y"
+{ yyval.arg = l(make_op(O_BIT_OR, 2, yyvsp[-3].arg, yyvsp[0].arg, Nullarg)); }
+break;
+case 61:
+#line 409 "perly.y"
+{ yyval.arg = make_op(O_POW, 2, yyvsp[-2].arg, yyvsp[0].arg, Nullarg); }
+break;
+case 62:
+#line 411 "perly.y"
+{ if (yyvsp[-1].ival == O_REPEAT)
+ yyvsp[-2].arg = listish(yyvsp[-2].arg);
+ yyval.arg = make_op(yyvsp[-1].ival, 2, yyvsp[-2].arg, yyvsp[0].arg, Nullarg);
+ if (yyvsp[-1].ival == O_REPEAT) {
+ if (yyval.arg[1].arg_type != A_EXPR ||
+ yyval.arg[1].arg_ptr.arg_arg->arg_type != O_LIST)
+ yyval.arg[1].arg_flags &= ~AF_ARYOK;
+ } }
+break;
+case 63:
+#line 420 "perly.y"
+{ yyval.arg = make_op(yyvsp[-1].ival, 2, yyvsp[-2].arg, yyvsp[0].arg, Nullarg); }
+break;
+case 64:
+#line 422 "perly.y"
+{ yyval.arg = make_op(O_LEFT_SHIFT, 2, yyvsp[-2].arg, yyvsp[0].arg, Nullarg); }
+break;
+case 65:
+#line 424 "perly.y"
+{ yyval.arg = make_op(O_RIGHT_SHIFT, 2, yyvsp[-2].arg, yyvsp[0].arg, Nullarg); }
+break;
+case 66:
+#line 426 "perly.y"
+{ yyval.arg = make_op(yyvsp[-1].ival, 2, yyvsp[-2].arg, yyvsp[0].arg, Nullarg); }
+break;
+case 67:
+#line 428 "perly.y"
+{ yyval.arg = make_op(yyvsp[-1].ival, 2, yyvsp[-2].arg, yyvsp[0].arg, Nullarg); }
+break;
+case 68:
+#line 430 "perly.y"
+{ yyval.arg = make_op(O_BIT_AND, 2, yyvsp[-2].arg, yyvsp[0].arg, Nullarg); }
+break;
+case 69:
+#line 432 "perly.y"
+{ yyval.arg = make_op(O_XOR, 2, yyvsp[-2].arg, yyvsp[0].arg, Nullarg); }
+break;
+case 70:
+#line 434 "perly.y"
+{ yyval.arg = make_op(O_BIT_OR, 2, yyvsp[-2].arg, yyvsp[0].arg, Nullarg); }
+break;
+case 71:
+#line 436 "perly.y"
+{ arg4 = Nullarg;
+ yyval.arg = make_op(O_F_OR_R, 4, yyvsp[-2].arg, yyvsp[0].arg, Nullarg);
+ yyval.arg[0].arg_flags |= yyvsp[-1].ival; }
+break;
+case 72:
+#line 440 "perly.y"
+{ yyval.arg = make_op(O_AND, 2, yyvsp[-2].arg, yyvsp[0].arg, Nullarg); }
+break;
+case 73:
+#line 442 "perly.y"
+{ yyval.arg = make_op(O_OR, 2, yyvsp[-2].arg, yyvsp[0].arg, Nullarg); }
+break;
+case 74:
+#line 444 "perly.y"
+{ yyval.arg = make_op(O_COND_EXPR, 3, yyvsp[-4].arg, yyvsp[-2].arg, yyvsp[0].arg); }
+break;
+case 75:
+#line 446 "perly.y"
+{ yyval.arg = mod_match(O_MATCH, yyvsp[-2].arg, yyvsp[0].arg); }
+break;
+case 76:
+#line 448 "perly.y"
+{ yyval.arg = mod_match(O_NMATCH, yyvsp[-2].arg, yyvsp[0].arg); }
+break;
+case 77:
+#line 450 "perly.y"
+{ yyval.arg = yyvsp[0].arg; }
+break;
+case 78:
+#line 454 "perly.y"
+{ yyval.arg = make_op(O_NEGATE, 1, yyvsp[0].arg, Nullarg, Nullarg); }
+break;
+case 79:
+#line 456 "perly.y"
+{ yyval.arg = yyvsp[0].arg; }
+break;
+case 80:
+#line 458 "perly.y"
+{ yyval.arg = make_op(O_NOT, 1, yyvsp[0].arg, Nullarg, Nullarg); }
+break;
+case 81:
+#line 460 "perly.y"
+{ yyval.arg = make_op(O_COMPLEMENT, 1, yyvsp[0].arg, Nullarg, Nullarg);}
+break;
+case 82:
+#line 462 "perly.y"
+{ yyval.arg = addflags(1, AF_POST|AF_UP,
+ l(make_op(O_ITEM,1,yyvsp[-1].arg,Nullarg,Nullarg))); }
+break;
+case 83:
+#line 465 "perly.y"
+{ yyval.arg = addflags(1, AF_POST,
+ l(make_op(O_ITEM,1,yyvsp[-1].arg,Nullarg,Nullarg))); }
+break;
+case 84:
+#line 468 "perly.y"
+{ yyval.arg = addflags(1, AF_PRE|AF_UP,
+ l(make_op(O_ITEM,1,yyvsp[0].arg,Nullarg,Nullarg))); }
+break;
+case 85:
+#line 471 "perly.y"
+{ yyval.arg = addflags(1, AF_PRE,
+ l(make_op(O_ITEM,1,yyvsp[0].arg,Nullarg,Nullarg))); }
+break;
+case 86:
+#line 474 "perly.y"
+{ opargs[yyvsp[-1].ival] = 0; /* force it special */
+ yyval.arg = make_op(yyvsp[-1].ival, 1,
+ stab2arg(A_STAB,stabent(yyvsp[0].cval,TRUE)),
+ Nullarg, Nullarg);
+ Safefree(yyvsp[0].cval); yyvsp[0].cval = Nullch;
+ }
+break;
+case 87:
+#line 481 "perly.y"
+{ opargs[yyvsp[-1].ival] = 1;
+ yyval.arg = make_op(yyvsp[-1].ival, 1, yyvsp[0].arg, Nullarg, Nullarg); }
+break;
+case 88:
+#line 484 "perly.y"
+{ opargs[yyvsp[0].ival] = (yyvsp[0].ival != O_FTTTY);
+ yyval.arg = make_op(yyvsp[0].ival, 1,
+ stab2arg(A_STAB,
+ yyvsp[0].ival == O_FTTTY?stabent("STDIN",TRUE):defstab),
+ Nullarg, Nullarg); }
+break;
+case 89:
+#line 490 "perly.y"
+{ yyval.arg = l(localize(make_op(O_ASSIGN, 1,
+ localize(listish(make_list(yyvsp[-1].arg))),
+ Nullarg,Nullarg))); }
+break;
+case 90:
+#line 494 "perly.y"
+{ yyval.arg = make_list(yyvsp[-1].arg); }
+break;
+case 91:
+#line 496 "perly.y"
+{ yyval.arg = make_list(Nullarg); }
+break;
+case 92:
+#line 498 "perly.y"
+{ yyval.arg = make_op(O_DOFILE,2,yyvsp[0].arg,Nullarg,Nullarg);
+ allstabs = TRUE;}
+break;
+case 93:
+#line 501 "perly.y"
+{ yyval.arg = cmd_to_arg(yyvsp[0].cmdval); }
+break;
+case 94:
+#line 503 "perly.y"
+{ yyval.arg = stab2arg(A_STAB,yyvsp[0].stabval); }
+break;
+case 95:
+#line 505 "perly.y"
+{ yyval.arg = stab2arg(A_STAR,yyvsp[0].stabval); }
+break;
+case 96:
+#line 507 "perly.y"
+{ yyval.arg = make_op(O_AELEM, 2,
+ stab2arg(A_STAB,aadd(yyvsp[-3].stabval)), yyvsp[-1].arg, Nullarg); }
+break;
+case 97:
+#line 510 "perly.y"
+{ yyval.arg = make_op(O_HASH, 1,
+ stab2arg(A_STAB,yyvsp[0].stabval),
+ Nullarg, Nullarg); }
+break;
+case 98:
+#line 514 "perly.y"
+{ yyval.arg = make_op(O_ARRAY, 1,
+ stab2arg(A_STAB,yyvsp[0].stabval),
+ Nullarg, Nullarg); }
+break;
+case 99:
+#line 518 "perly.y"
+{ yyval.arg = make_op(O_HELEM, 2,
+ stab2arg(A_STAB,hadd(yyvsp[-4].stabval)),
+ jmaybe(yyvsp[-2].arg),
+ Nullarg);
+ expectterm = FALSE; }
+break;
+case 100:
+#line 524 "perly.y"
+{ yyval.arg = make_op(O_LSLICE, 3,
+ Nullarg,
+ listish(make_list(yyvsp[-1].arg)),
+ listish(make_list(yyvsp[-4].arg))); }
+break;
+case 101:
+#line 529 "perly.y"
+{ yyval.arg = make_op(O_LSLICE, 3,
+ Nullarg,
+ listish(make_list(yyvsp[-1].arg)),
+ Nullarg); }
+break;
+case 102:
+#line 534 "perly.y"
+{ yyval.arg = make_op(O_ASLICE, 2,
+ stab2arg(A_STAB,aadd(yyvsp[-3].stabval)),
+ listish(make_list(yyvsp[-1].arg)),
+ Nullarg); }
+break;
+case 103:
+#line 539 "perly.y"
+{ yyval.arg = make_op(O_HSLICE, 2,
+ stab2arg(A_STAB,hadd(yyvsp[-4].stabval)),
+ listish(make_list(yyvsp[-2].arg)),
+ Nullarg);
+ expectterm = FALSE; }
+break;
+case 104:
+#line 545 "perly.y"
+{ yyval.arg = make_op(O_DELETE, 2,
+ stab2arg(A_STAB,hadd(yyvsp[-4].stabval)),
+ jmaybe(yyvsp[-2].arg),
+ Nullarg);
+ expectterm = FALSE; }
+break;
+case 105:
+#line 551 "perly.y"
+{ yyval.arg = make_op(O_DELETE, 2,
+ stab2arg(A_STAB,hadd(yyvsp[-5].stabval)),
+ jmaybe(yyvsp[-3].arg),
+ Nullarg);
+ expectterm = FALSE; }
+break;
+case 106:
+#line 557 "perly.y"
+{ yyval.arg = stab2arg(A_ARYLEN,yyvsp[0].stabval); }
+break;
+case 107:
+#line 559 "perly.y"
+{ yyval.arg = yyvsp[0].arg; }
+break;
+case 108:
+#line 561 "perly.y"
+{ yyval.arg = yyvsp[0].arg; }
+break;
+case 109:
+#line 563 "perly.y"
+{ yyval.arg = yyvsp[0].arg; }
+break;
+case 110:
+#line 565 "perly.y"
+{ yyval.arg = yyvsp[0].arg; }
+break;
+case 111:
+#line 567 "perly.y"
+{ yyval.arg = make_op((perldb ? O_DBSUBR : O_SUBR), 2,
+ stab2arg(A_WORD,stabent(yyvsp[-3].cval,MULTI)),
+ make_list(yyvsp[-1].arg),
+ Nullarg); Safefree(yyvsp[-3].cval); yyvsp[-3].cval = Nullch;
+ yyval.arg->arg_flags |= AF_DEPR; }
+break;
+case 112:
+#line 573 "perly.y"
+{ yyval.arg = make_op((perldb ? O_DBSUBR : O_SUBR), 2,
+ stab2arg(A_WORD,stabent(yyvsp[-3].cval,MULTI)),
+ make_list(yyvsp[-1].arg),
+ Nullarg); Safefree(yyvsp[-3].cval); yyvsp[-3].cval = Nullch; }
+break;
+case 113:
+#line 578 "perly.y"
+{ yyval.arg = make_op((perldb ? O_DBSUBR : O_SUBR), 2,
+ stab2arg(A_WORD,stabent(yyvsp[-2].cval,MULTI)),
+ make_list(Nullarg),
+ Nullarg);
+ Safefree(yyvsp[-2].cval); yyvsp[-2].cval = Nullch;
+ yyval.arg->arg_flags |= AF_DEPR; }
+break;
+case 114:
+#line 585 "perly.y"
+{ yyval.arg = make_op((perldb ? O_DBSUBR : O_SUBR), 2,
+ stab2arg(A_WORD,stabent(yyvsp[-2].cval,MULTI)),
+ make_list(Nullarg),
+ Nullarg);
+ Safefree(yyvsp[-2].cval); yyvsp[-2].cval = Nullch;
+ }
+break;
+case 115:
+#line 592 "perly.y"
+{ yyval.arg = make_op((perldb ? O_DBSUBR : O_SUBR), 2,
+ stab2arg(A_WORD,stabent(yyvsp[0].cval,MULTI)),
+ Nullarg,
+ Nullarg);
+ Safefree(yyvsp[0].cval); yyvsp[0].cval = Nullch;
+ }
+break;
+case 116:
+#line 599 "perly.y"
+{ yyval.arg = make_op((perldb ? O_DBSUBR : O_SUBR), 2,
+ stab2arg(A_STAB,yyvsp[-3].stabval),
+ make_list(yyvsp[-1].arg),
+ Nullarg);
+ yyval.arg->arg_flags |= AF_DEPR; }
+break;
+case 117:
+#line 605 "perly.y"
+{ yyval.arg = make_op((perldb ? O_DBSUBR : O_SUBR), 2,
+ stab2arg(A_STAB,yyvsp[-3].stabval),
+ make_list(yyvsp[-1].arg),
+ Nullarg); }
+break;
+case 118:
+#line 610 "perly.y"
+{ yyval.arg = make_op((perldb ? O_DBSUBR : O_SUBR), 2,
+ stab2arg(A_STAB,yyvsp[-2].stabval),
+ make_list(Nullarg),
+ Nullarg);
+ yyval.arg->arg_flags |= AF_DEPR; }
+break;
+case 119:
+#line 616 "perly.y"
+{ yyval.arg = make_op((perldb ? O_DBSUBR : O_SUBR), 2,
+ stab2arg(A_STAB,yyvsp[-2].stabval),
+ make_list(Nullarg),
+ Nullarg); }
+break;
+case 120:
+#line 621 "perly.y"
+{ yyval.arg = make_op((perldb ? O_DBSUBR : O_SUBR), 2,
+ stab2arg(A_STAB,yyvsp[0].stabval),
+ Nullarg,
+ Nullarg); }
+break;
+case 121:
+#line 626 "perly.y"
+{ yyval.arg = make_op(yyvsp[0].ival,0,Nullarg,Nullarg,Nullarg); }
+break;
+case 122:
+#line 628 "perly.y"
+{ yyval.arg = make_op(yyvsp[-1].ival,1,cval_to_arg(yyvsp[0].cval),
+ Nullarg,Nullarg); }
+break;
+case 123:
+#line 631 "perly.y"
+{ yyval.arg = make_op(yyvsp[0].ival,0,Nullarg,Nullarg,Nullarg); }
+break;
+case 124:
+#line 633 "perly.y"
+{ yyval.arg = make_op(yyvsp[-1].ival,1,cmd_to_arg(yyvsp[0].cmdval),Nullarg,Nullarg); }
+break;
+case 125:
+#line 635 "perly.y"
+{ yyval.arg = make_op(yyvsp[-1].ival,1,yyvsp[0].arg,Nullarg,Nullarg); }
+break;
+case 126:
+#line 637 "perly.y"
+{ yyval.arg = make_op(O_SELECT, 0, Nullarg, Nullarg, Nullarg);}
+break;
+case 127:
+#line 639 "perly.y"
+{ yyval.arg = make_op(O_SELECT, 1,
+ stab2arg(A_WORD,stabent(yyvsp[0].cval,TRUE)),
+ Nullarg,
+ Nullarg);
+ Safefree(yyvsp[0].cval); yyvsp[0].cval = Nullch; }
+break;
+case 128:
+#line 645 "perly.y"
+{ yyval.arg = make_op(O_SELECT, 1, yyvsp[-1].arg, Nullarg, Nullarg); }
+break;
+case 129:
+#line 647 "perly.y"
+{ arg4 = yyvsp[-1].arg;
+ yyval.arg = make_op(O_SSELECT, 4, yyvsp[-4].arg, yyvsp[-3].arg, yyvsp[-2].arg); }
+break;
+case 130:
+#line 650 "perly.y"
+{ yyval.arg = make_op(O_OPEN, 2,
+ stab2arg(A_WORD,stabent(yyvsp[0].cval,TRUE)),
+ stab2arg(A_STAB,stabent(yyvsp[0].cval,TRUE)),
+ Nullarg);
+ Safefree(yyvsp[0].cval); yyvsp[0].cval = Nullch;
+ }
+break;
+case 131:
+#line 657 "perly.y"
+{ yyval.arg = make_op(O_OPEN, 2,
+ stab2arg(A_WORD,stabent(yyvsp[-1].cval,TRUE)),
+ stab2arg(A_STAB,stabent(yyvsp[-1].cval,TRUE)),
+ Nullarg);
+ Safefree(yyvsp[-1].cval); yyvsp[-1].cval = Nullch;
+ }
+break;
+case 132:
+#line 664 "perly.y"
+{ yyval.arg = make_op(O_OPEN, 2,
+ yyvsp[-2].arg,
+ yyvsp[-1].arg, Nullarg); }
+break;
+case 133:
+#line 668 "perly.y"
+{ yyval.arg = make_op(yyvsp[-3].ival, 1,
+ yyvsp[-1].arg,
+ Nullarg, Nullarg); }
+break;
+case 134:
+#line 672 "perly.y"
+{ yyval.arg = make_op(yyvsp[-1].ival, 1,
+ stab2arg(A_WORD,stabent(yyvsp[0].cval,TRUE)),
+ Nullarg, Nullarg);
+ Safefree(yyvsp[0].cval); yyvsp[0].cval = Nullch; }
+break;
+case 135:
+#line 677 "perly.y"
+{ yyval.arg = make_op(yyvsp[-1].ival, 1,
+ stab2arg(A_STAB,yyvsp[0].stabval),
+ Nullarg, Nullarg); }
+break;
+case 136:
+#line 681 "perly.y"
+{ yyval.arg = make_op(yyvsp[-2].ival, 1,
+ stab2arg(A_WORD,Nullstab),
+ Nullarg, Nullarg); }
+break;
+case 137:
+#line 685 "perly.y"
+{ yyval.arg = make_op(yyvsp[0].ival, 0,
+ Nullarg, Nullarg, Nullarg); }
+break;
+case 138:
+#line 688 "perly.y"
+{ yyval.arg = make_op(yyvsp[-4].ival, 2, yyvsp[-2].arg, yyvsp[-1].arg, Nullarg); }
+break;
+case 139:
+#line 690 "perly.y"
+{ yyval.arg = make_op(yyvsp[-5].ival, 3, yyvsp[-3].arg, yyvsp[-2].arg, make_list(yyvsp[-1].arg)); }
+break;
+case 140:
+#line 692 "perly.y"
+{ yyval.arg = make_op(yyvsp[-5].ival, 2, yyvsp[-3].arg, yyvsp[-1].arg, Nullarg); }
+break;
+case 141:
+#line 694 "perly.y"
+{ arg4 = yyvsp[-1].arg; yyval.arg = make_op(yyvsp[-6].ival, 4, yyvsp[-4].arg, yyvsp[-3].arg, yyvsp[-2].arg); }
+break;
+case 142:
+#line 696 "perly.y"
+{ arg4 = yyvsp[-2].arg; arg5 = yyvsp[-1].arg;
+ yyval.arg = make_op(yyvsp[-8].ival, 5, yyvsp[-6].arg, yyvsp[-4].arg, yyvsp[-3].arg); }
+break;
+case 143:
+#line 699 "perly.y"
+{ yyval.arg = make_op(yyvsp[-5].ival, 2,
+ yyvsp[-3].arg,
+ make_list(yyvsp[-1].arg),
+ Nullarg); }
+break;
+case 144:
+#line 704 "perly.y"
+{ yyval.arg = make_op(O_POP, 1, yyvsp[0].arg, Nullarg, Nullarg); }
+break;
+case 145:
+#line 706 "perly.y"
+{ yyval.arg = make_op(O_POP, 1, yyvsp[-1].arg, Nullarg, Nullarg); }
+break;
+case 146:
+#line 708 "perly.y"
+{ yyval.arg = make_op(O_SHIFT, 1, yyvsp[0].arg, Nullarg, Nullarg); }
+break;
+case 147:
+#line 710 "perly.y"
+{ yyval.arg = make_op(O_SHIFT, 1, yyvsp[-1].arg, Nullarg, Nullarg); }
+break;
+case 148:
+#line 712 "perly.y"
+{ yyval.arg = make_op(O_SHIFT, 1,
+ stab2arg(A_STAB,
+ aadd(stabent(subline ? "_" : "ARGV", TRUE))),
+ Nullarg, Nullarg); }
+break;
+case 149:
+#line 717 "perly.y"
+{ static char p[]="/\\s+/";
+ char *oldend = bufend;
+ ARG *oldarg = yylval.arg;
+
+ bufend=p+5;
+ (void)scanpat(p);
+ bufend=oldend;
+ yyval.arg = make_split(defstab,yylval.arg,Nullarg);
+ yylval.arg = oldarg; }
+break;
+case 150:
+#line 727 "perly.y"
+{ yyval.arg = mod_match(O_MATCH, yyvsp[-2].arg,
+ make_split(defstab,yyvsp[-3].arg,yyvsp[-1].arg));}
+break;
+case 151:
+#line 730 "perly.y"
+{ yyval.arg = mod_match(O_MATCH, yyvsp[-1].arg,
+ make_split(defstab,yyvsp[-2].arg,Nullarg) ); }
+break;
+case 152:
+#line 733 "perly.y"
+{ yyval.arg = mod_match(O_MATCH,
+ stab2arg(A_STAB,defstab),
+ make_split(defstab,yyvsp[-1].arg,Nullarg) ); }
+break;
+case 153:
+#line 737 "perly.y"
+{ yyval.arg = make_op(yyvsp[-4].ival, 2,
+ yyvsp[-2].arg,
+ listish(make_list(yyvsp[-1].arg)),
+ Nullarg); }
+break;
+case 154:
+#line 742 "perly.y"
+{ yyval.arg = make_op(yyvsp[-3].ival, 1,
+ make_list(yyvsp[-1].arg),
+ Nullarg,
+ Nullarg); }
+break;
+case 155:
+#line 747 "perly.y"
+{ yyval.arg = l(make_op(yyvsp[-1].ival, 1, fixl(yyvsp[-1].ival,yyvsp[0].arg),
+ Nullarg, Nullarg)); }
+break;
+case 156:
+#line 750 "perly.y"
+{ yyval.arg = l(make_op(yyvsp[0].ival, 1,
+ stab2arg(A_STAB,defstab),
+ Nullarg, Nullarg)); }
+break;
+case 157:
+#line 754 "perly.y"
+{ yyval.arg = make_op(yyvsp[0].ival, 0, Nullarg, Nullarg, Nullarg); }
+break;
+case 158:
+#line 756 "perly.y"
+{ yyval.arg = make_op(yyvsp[-2].ival, 0, Nullarg, Nullarg, Nullarg); }
+break;
+case 159:
+#line 758 "perly.y"
+{ yyval.arg = make_op(yyvsp[-2].ival, 0, Nullarg, Nullarg, Nullarg); }
+break;
+case 160:
+#line 760 "perly.y"
+{ yyval.arg = make_op(yyvsp[-3].ival, 1, yyvsp[-1].arg, Nullarg, Nullarg); }
+break;
+case 161:
+#line 762 "perly.y"
+{ yyval.arg = make_op(yyvsp[-4].ival, 2, yyvsp[-2].arg, yyvsp[-1].arg, Nullarg);
+ if (yyvsp[-4].ival == O_INDEX && yyval.arg[2].arg_type == A_SINGLE)
+ fbmcompile(yyval.arg[2].arg_ptr.arg_str,0); }
+break;
+case 162:
+#line 766 "perly.y"
+{ yyval.arg = make_op(yyvsp[-4].ival, 2, yyvsp[-2].arg, yyvsp[-1].arg, Nullarg);
+ if (yyvsp[-4].ival == O_INDEX && yyval.arg[2].arg_type == A_SINGLE)
+ fbmcompile(yyval.arg[2].arg_ptr.arg_str,0); }
+break;
+case 163:
+#line 770 "perly.y"
+{ yyval.arg = make_op(yyvsp[-5].ival, 3, yyvsp[-3].arg, yyvsp[-2].arg, yyvsp[-1].arg);
+ if (yyvsp[-5].ival == O_INDEX && yyval.arg[2].arg_type == A_SINGLE)
+ fbmcompile(yyval.arg[2].arg_ptr.arg_str,0); }
+break;
+case 164:
+#line 774 "perly.y"
+{ yyval.arg = make_op(yyvsp[-5].ival, 3, yyvsp[-3].arg, yyvsp[-2].arg, yyvsp[-1].arg); }
+break;
+case 165:
+#line 776 "perly.y"
+{ arg4 = yyvsp[-1].arg;
+ yyval.arg = make_op(yyvsp[-6].ival, 4, yyvsp[-4].arg, yyvsp[-3].arg, yyvsp[-2].arg); }
+break;
+case 166:
+#line 779 "perly.y"
+{ arg4 = yyvsp[-2].arg; arg5 = yyvsp[-1].arg;
+ yyval.arg = make_op(yyvsp[-7].ival, 5, yyvsp[-5].arg, yyvsp[-4].arg, yyvsp[-3].arg); }
+break;
+case 167:
+#line 782 "perly.y"
+{ yyval.arg = make_op(yyvsp[-3].ival, 1,
+ yyvsp[-1].arg,
+ Nullarg,
+ Nullarg); }
+break;
+case 168:
+#line 787 "perly.y"
+{ yyval.arg = make_op(yyvsp[-1].ival, 1,
+ yyvsp[0].arg,
+ Nullarg,
+ Nullarg); }
+break;
+case 169:
+#line 792 "perly.y"
+{ yyval.arg = make_op(yyvsp[-5].ival, 3, yyvsp[-3].arg, yyvsp[-2].arg, yyvsp[-1].arg); }
+break;
+case 172:
+#line 798 "perly.y"
+{ yyval.arg = make_op(yyvsp[0].ival,2,
+ stab2arg(A_WORD,Nullstab),
+ stab2arg(A_STAB,defstab),
+ Nullarg); }
+break;
+case 173:
+#line 803 "perly.y"
+{ yyval.arg = make_op(yyvsp[-1].ival,2,
+ stab2arg(A_WORD,Nullstab),
+ maybelistish(yyvsp[-1].ival,make_list(yyvsp[0].arg)),
+ Nullarg); }
+break;
+case 174:
+#line 808 "perly.y"
+{ yyval.arg = make_op(yyvsp[-1].ival,2,
+ stab2arg(A_WORD,stabent(yyvsp[0].cval,TRUE)),
+ stab2arg(A_STAB,defstab),
+ Nullarg);
+ Safefree(yyvsp[0].cval); yyvsp[0].cval = Nullch;
+ }
+break;
+case 175:
+#line 815 "perly.y"
+{ yyval.arg = make_op(yyvsp[-2].ival,2,
+ stab2arg(A_WORD,stabent(yyvsp[-1].cval,TRUE)),
+ maybelistish(yyvsp[-2].ival,make_list(yyvsp[0].arg)),
+ Nullarg); Safefree(yyvsp[-1].cval); yyvsp[-1].cval = Nullch; }
+break;
+case 176:
+#line 820 "perly.y"
+{ yyval.arg = make_op(yyvsp[-2].ival,2,
+ stab2arg(A_STAB,yyvsp[-1].stabval),
+ maybelistish(yyvsp[-2].ival,make_list(yyvsp[0].arg)),
+ Nullarg); }
+break;
+case 177:
+#line 825 "perly.y"
+{ yyval.arg = make_op(yyvsp[-2].ival,2,
+ cmd_to_arg(yyvsp[-1].cmdval),
+ maybelistish(yyvsp[-2].ival,make_list(yyvsp[0].arg)),
+ Nullarg); }
+break;
+case 178:
+#line 832 "perly.y"
+{ yyval.arg = stab2arg(A_WORD,stabent(yyvsp[0].cval,TRUE));
+ Safefree(yyvsp[0].cval); yyvsp[0].cval = Nullch;}
+break;
+case 180:
+#line 838 "perly.y"
+{ yyval.arg = stab2arg(A_WORD,aadd(stabent(yyvsp[0].cval,TRUE)));
+ Safefree(yyvsp[0].cval); yyvsp[0].cval = Nullch; }
+break;
+case 181:
+#line 841 "perly.y"
+{ yyval.arg = stab2arg(A_STAB,yyvsp[0].stabval); }
+break;
+case 182:
+#line 845 "perly.y"
+{ yyval.arg = stab2arg(A_WORD,hadd(stabent(yyvsp[0].cval,TRUE)));
+ Safefree(yyvsp[0].cval); yyvsp[0].cval = Nullch; }
+break;
+case 183:
+#line 848 "perly.y"
+{ yyval.arg = stab2arg(A_STAB,yyvsp[0].stabval); }
+break;
+case 184:
+#line 852 "perly.y"
+{ yyval.ival = 1; }
+break;
+case 185:
+#line 854 "perly.y"
+{ yyval.ival = 0; }
+break;
+case 186:
+#line 863 "perly.y"
+{ char *s;
+ yyval.arg = op_new(1);
+ yyval.arg->arg_type = O_ITEM;
+ yyval.arg[1].arg_type = A_SINGLE;
+ yyval.arg[1].arg_ptr.arg_str = str_make(yyvsp[0].cval,0);
+ for (s = yyvsp[0].cval; *s && isLOWER(*s); s++) ;
+ if (dowarn && !*s)
+ warn(
+ "\"%s\" may clash with future reserved word",
+ yyvsp[0].cval );
+ Safefree(yyvsp[0].cval); yyvsp[0].cval = Nullch;
+ }
+break;
+#line 3008 "y.tab.c"
+ }
+ yyssp -= yym;
+ yystate = *yyssp;
+ yyvsp -= yym;
+ yym = yylhs[yyn];
+ if (yystate == 0 && yym == 0)
+ {
+#if YYDEBUG
+ if (yydebug)
+ printf("%sdebug: after reduction, shifting from state 0 to\
+ state %d\n", YYPREFIX, YYFINAL);
+#endif
+ yystate = YYFINAL;
+ *++yyssp = YYFINAL;
+ *++yyvsp = yyval;
+ if (yychar < 0)
+ {
+ if ((yychar = yylex()) < 0) yychar = 0;
+#if YYDEBUG
+ if (yydebug)
+ {
+ yys = 0;
+ if (yychar <= YYMAXTOKEN) yys = yyname[yychar];
+ if (!yys) yys = "illegal-symbol";
+ printf("%sdebug: state %d, reading %d (%s)\n",
+ YYPREFIX, YYFINAL, yychar, yys);
+ }
+#endif
+ }
+ if (yychar == 0) goto yyaccept;
+ goto yyloop;
+ }
+ if ((yyn = yygindex[yym]) && (yyn += yystate) >= 0 &&
+ yyn <= YYTABLESIZE && yycheck[yyn] == yystate)
+ yystate = yytable[yyn];
+ else
+ yystate = yydgoto[yym];
+#if YYDEBUG
+ if (yydebug)
+ printf("%sdebug: after reduction, shifting from state %d \
+to state %d\n", YYPREFIX, *yyssp, yystate);
+#endif
+ if (yyssp >= yyss + yystacksize - 1)
+ {
+ goto yyoverflow;
+ }
+ *++yyssp = yystate;
+ *++yyvsp = yyval;
+ goto yyloop;
+yyoverflow:
+ yyerror("yacc stack overflow");
+yyabort:
+ return (1);
+yyaccept:
+ return (0);
+}
diff --git a/gnu/usr.bin/perl/perl/perly.h b/gnu/usr.bin/perl/perl/perly.h
new file mode 100644
index 0000000..c6f13d1
--- /dev/null
+++ b/gnu/usr.bin/perl/perl/perly.h
@@ -0,0 +1,83 @@
+#define WORD 257
+#define LABEL 258
+#define APPEND 259
+#define OPEN 260
+#define SSELECT 261
+#define LOOPEX 262
+#define DOTDOT 263
+#define USING 264
+#define FORMAT 265
+#define DO 266
+#define SHIFT 267
+#define PUSH 268
+#define POP 269
+#define LVALFUN 270
+#define WHILE 271
+#define UNTIL 272
+#define IF 273
+#define UNLESS 274
+#define ELSE 275
+#define ELSIF 276
+#define CONTINUE 277
+#define SPLIT 278
+#define FLIST 279
+#define FOR 280
+#define FILOP 281
+#define FILOP2 282
+#define FILOP3 283
+#define FILOP4 284
+#define FILOP22 285
+#define FILOP25 286
+#define FUNC0 287
+#define FUNC1 288
+#define FUNC2 289
+#define FUNC2x 290
+#define FUNC3 291
+#define FUNC4 292
+#define FUNC5 293
+#define HSHFUN 294
+#define HSHFUN3 295
+#define FLIST2 296
+#define SUB 297
+#define FILETEST 298
+#define LOCAL 299
+#define DELETE 300
+#define RELOP 301
+#define EQOP 302
+#define MULOP 303
+#define ADDOP 304
+#define PACKAGE 305
+#define AMPER 306
+#define FORMLIST 307
+#define REG 308
+#define ARYLEN 309
+#define ARY 310
+#define HSH 311
+#define STAR 312
+#define SUBST 313
+#define PATTERN 314
+#define RSTRING 315
+#define TRANS 316
+#define LISTOP 317
+#define OROR 318
+#define ANDAND 319
+#define UNIOP 320
+#define LS 321
+#define RS 322
+#define MATCH 323
+#define NMATCH 324
+#define UMINUS 325
+#define POW 326
+#define INC 327
+#define DEC 328
+typedef union {
+ int ival;
+ char *cval;
+ ARG *arg;
+ CMD *cmdval;
+ struct compcmd compval;
+ STAB *stabval;
+ FCMD *formval;
+} YYSTYPE;
+extern YYSTYPE yylval;
+extern YYSTYPE yylval;
diff --git a/gnu/usr.bin/perl/perl/regcomp.c b/gnu/usr.bin/perl/perl/regcomp.c
new file mode 100644
index 0000000..0287778
--- /dev/null
+++ b/gnu/usr.bin/perl/perl/regcomp.c
@@ -0,0 +1,1481 @@
+/* NOTE: this is derived from Henry Spencer's regexp code, and should not
+ * confused with the original package (see point 3 below). Thanks, Henry!
+ */
+
+/* Additional note: this code is very heavily munged from Henry's version
+ * in places. In some spots I've traded clarity for efficiency, so don't
+ * blame Henry for some of the lack of readability.
+ */
+
+/* $RCSfile: regcomp.c,v $$Revision: 1.1.1.1 $$Date: 1994/09/10 06:27:33 $
+ *
+ * $Log: regcomp.c,v $
+ * Revision 1.1.1.1 1994/09/10 06:27:33 gclarkii
+ * Initial import of Perl 4.046 bmaked
+ *
+ * Revision 1.1.1.1 1993/08/23 21:29:39 nate
+ * PERL!
+ *
+ * Revision 4.0.1.5 92/06/08 15:23:36 lwall
+ * patch20: Perl now distinguishes overlapped copies from non-overlapped
+ * patch20: /^stuff/ wrongly assumed an implicit $* == 1
+ * patch20: /x{0}/ was wrongly interpreted as /x{0,}/
+ * patch20: added \W, \S and \D inside /[...]/
+ *
+ * Revision 4.0.1.4 91/11/05 22:55:14 lwall
+ * patch11: Erratum
+ *
+ * Revision 4.0.1.3 91/11/05 18:22:28 lwall
+ * patch11: minimum match length calculation in regexp is now cumulative
+ * patch11: initial .* in pattern had dependency on value of $*
+ * patch11: certain patterns made use of garbage pointers from uncleared memory
+ * patch11: prepared for ctype implementations that don't define isascii()
+ *
+ * Revision 4.0.1.2 91/06/07 11:48:24 lwall
+ * patch4: new copyright notice
+ * patch4: /(x+) \1/ incorrectly optimized to not match "xxx xx"
+ * patch4: // wouldn't use previous pattern if it started with a null character
+ *
+ * Revision 4.0.1.1 91/04/12 09:04:45 lwall
+ * patch1: random cleanup in cpp namespace
+ *
+ * Revision 4.0 91/03/20 01:39:01 lwall
+ * 4.0 baseline.
+ *
+ */
+/*SUPPRESS 112*/
+/*
+ * regcomp and regexec -- regsub and regerror are not used in perl
+ *
+ * Copyright (c) 1986 by University of Toronto.
+ * Written by Henry Spencer. Not derived from licensed software.
+ *
+ * Permission is granted to anyone to use this software for any
+ * purpose on any computer system, and to redistribute it freely,
+ * subject to the following restrictions:
+ *
+ * 1. The author is not responsible for the consequences of use of
+ * this software, no matter how awful, even if they arise
+ * from defects in it.
+ *
+ * 2. The origin of this software must not be misrepresented, either
+ * by explicit claim or by omission.
+ *
+ * 3. Altered versions must be plainly marked as such, and must not
+ * be misrepresented as being the original software.
+ *
+ *
+ **** Alterations to Henry's code are...
+ ****
+ **** Copyright (c) 1991, Larry Wall
+ ****
+ **** You may distribute under the terms of either the GNU General Public
+ **** License or the Artistic License, as specified in the README file.
+
+ *
+ * Beware that some of this code is subtly aware of the way operator
+ * precedence is structured in regular expressions. Serious changes in
+ * regular-expression syntax might require a total rethink.
+ */
+#include "EXTERN.h"
+#include "perl.h"
+#include "INTERN.h"
+#include "regcomp.h"
+
+#ifdef MSDOS
+# if defined(BUGGY_MSC6)
+ /* MSC 6.00A breaks on op/regexp.t test 85 unless we turn this off */
+ # pragma optimize("a",off)
+ /* But MSC 6.00A is happy with 'w', for aliases only across function calls*/
+ # pragma optimize("w",on )
+# endif /* BUGGY_MSC6 */
+#endif /* MSDOS */
+
+#ifndef STATIC
+#define STATIC static
+#endif
+
+#define ISMULT1(c) ((c) == '*' || (c) == '+' || (c) == '?')
+#define ISMULT2(s) ((*s) == '*' || (*s) == '+' || (*s) == '?' || \
+ ((*s) == '{' && regcurly(s)))
+#ifdef atarist
+#define PERL_META "^$.[()|?+*\\"
+#else
+#define META "^$.[()|?+*\\"
+#endif
+
+#ifdef SPSTART
+#undef SPSTART /* dratted cpp namespace... */
+#endif
+/*
+ * Flags to be passed up and down.
+ */
+#define HASWIDTH 01 /* Known never to match null string. */
+#define SIMPLE 02 /* Simple enough to be STAR/PLUS operand. */
+#define SPSTART 04 /* Starts with * or +. */
+#define WORST 0 /* Worst case. */
+
+/*
+ * Global work variables for regcomp().
+ */
+static char *regprecomp; /* uncompiled string. */
+static char *regparse; /* Input-scan pointer. */
+static char *regxend; /* End of input for compile */
+static int regnpar; /* () count. */
+static char *regcode; /* Code-emit pointer; &regdummy = don't. */
+static long regsize; /* Code size. */
+static int regfold;
+static int regsawbracket; /* Did we do {d,d} trick? */
+static int regsawback; /* Did we see \1, ...? */
+
+/*
+ * Forward declarations for regcomp()'s friends.
+ */
+STATIC int regcurly();
+STATIC char *reg();
+STATIC char *regbranch();
+STATIC char *regpiece();
+STATIC char *regatom();
+STATIC char *regclass();
+STATIC char *regnode();
+STATIC char *reganode();
+STATIC void regc();
+STATIC void reginsert();
+STATIC void regtail();
+STATIC void regoptail();
+
+/*
+ - regcomp - compile a regular expression into internal code
+ *
+ * We can't allocate space until we know how big the compiled form will be,
+ * but we can't compile it (and thus know how big it is) until we've got a
+ * place to put the code. So we cheat: we compile it twice, once with code
+ * generation turned off and size counting turned on, and once "for real".
+ * This also means that we don't allocate space until we are sure that the
+ * thing really will compile successfully, and we never have to move the
+ * code and thus invalidate pointers into it. (Note that it has to be in
+ * one piece because free() must be able to free it all.) [NB: not true in perl]
+ *
+ * Beware that the optimization-preparation code in here knows about some
+ * of the structure of the compiled regexp. [I'll say.]
+ */
+regexp *
+regcomp(exp,xend,fold)
+char *exp;
+char *xend;
+int fold;
+{
+ register regexp *r;
+ register char *scan;
+ register STR *longish;
+ STR *longest;
+ register int len;
+ register char *first;
+ int flags;
+ int backish;
+ int backest;
+ int curback;
+ int minlen;
+ int sawplus = 0;
+ int sawopen = 0;
+
+ if (exp == NULL)
+ fatal("NULL regexp argument");
+
+ /* First pass: determine size, legality. */
+ regfold = fold;
+ regparse = exp;
+ regxend = xend;
+ regprecomp = nsavestr(exp,xend-exp);
+ regsawbracket = 0;
+ regsawback = 0;
+ regnpar = 1;
+ regsize = 0L;
+ regcode = &regdummy;
+ regc((char)MAGIC);
+ if (reg(0, &flags) == NULL) {
+ Safefree(regprecomp);
+ regprecomp = Nullch;
+ return(NULL);
+ }
+
+ /* Small enough for pointer-storage convention? */
+ if (regsize >= 32767L) /* Probably could be 65535L. */
+ FAIL("regexp too big");
+
+ /* Allocate space. */
+ Newc(1001, r, sizeof(regexp) + (unsigned)regsize, char, regexp);
+ if (r == NULL)
+ FAIL("regexp out of space");
+
+ /* Second pass: emit code. */
+ if (regsawbracket)
+ Copy(regprecomp,exp,xend-exp,char);
+ r->prelen = xend-exp;
+ r->precomp = regprecomp;
+ r->subbeg = r->subbase = NULL;
+ regparse = exp;
+ regnpar = 1;
+ regcode = r->program;
+ regc((char)MAGIC);
+ if (reg(0, &flags) == NULL)
+ return(NULL);
+
+ /* Dig out information for optimizations. */
+ r->regstart = Nullstr; /* Worst-case defaults. */
+ r->reganch = 0;
+ r->regmust = Nullstr;
+ r->regback = -1;
+ r->regstclass = Nullch;
+ scan = r->program+1; /* First BRANCH. */
+ if (OP(regnext(scan)) == END) {/* Only one top-level choice. */
+ scan = NEXTOPER(scan);
+
+ first = scan;
+ while ((OP(first) == OPEN && (sawopen = 1)) ||
+ (OP(first) == BRANCH && OP(regnext(first)) != BRANCH) ||
+ (OP(first) == PLUS) ||
+ (OP(first) == CURLY && ARG1(first) > 0) ) {
+ if (OP(first) == PLUS)
+ sawplus = 1;
+ else
+ first += regarglen[OP(first)];
+ first = NEXTOPER(first);
+ }
+
+ /* Starting-point info. */
+ again:
+ if (OP(first) == EXACTLY) {
+ r->regstart =
+ str_make(OPERAND(first)+1,*OPERAND(first));
+ if (r->regstart->str_cur > !(sawstudy|fold))
+ fbmcompile(r->regstart,fold);
+ }
+ else if ((exp = index(simple,OP(first))) && exp > simple)
+ r->regstclass = first;
+ else if (OP(first) == BOUND || OP(first) == NBOUND)
+ r->regstclass = first;
+ else if (OP(first) == BOL) {
+ r->reganch = ROPT_ANCH;
+ first = NEXTOPER(first);
+ goto again;
+ }
+ else if ((OP(first) == STAR && OP(NEXTOPER(first)) == ANY) &&
+ !(r->reganch & ROPT_ANCH) ) {
+ /* turn .* into ^.* with an implied $*=1 */
+ r->reganch = ROPT_ANCH | ROPT_IMPLICIT;
+ first = NEXTOPER(first);
+ goto again;
+ }
+ if (sawplus && (!sawopen || !regsawback))
+ r->reganch |= ROPT_SKIP; /* x+ must match 1st of run */
+
+#ifdef DEBUGGING
+ if (debug & 512)
+ fprintf(stderr,"first %d next %d offset %d\n",
+ OP(first), OP(NEXTOPER(first)), first - scan);
+#endif
+ /*
+ * If there's something expensive in the r.e., find the
+ * longest literal string that must appear and make it the
+ * regmust. Resolve ties in favor of later strings, since
+ * the regstart check works with the beginning of the r.e.
+ * and avoiding duplication strengthens checking. Not a
+ * strong reason, but sufficient in the absence of others.
+ * [Now we resolve ties in favor of the earlier string if
+ * it happens that curback has been invalidated, since the
+ * earlier string may buy us something the later one won't.]
+ */
+ longish = str_make("",0);
+ longest = str_make("",0);
+ len = 0;
+ minlen = 0;
+ curback = 0;
+ backish = 0;
+ backest = 0;
+ while (OP(scan) != END) {
+ if (OP(scan) == BRANCH) {
+ if (OP(regnext(scan)) == BRANCH) {
+ curback = -30000;
+ while (OP(scan) == BRANCH)
+ scan = regnext(scan);
+ }
+ else /* single branch is ok */
+ scan = NEXTOPER(scan);
+ }
+ if (OP(scan) == EXACTLY) {
+ char *t;
+
+ first = scan;
+ while (OP(t = regnext(scan)) == CLOSE)
+ scan = t;
+ minlen += *OPERAND(first);
+ if (curback - backish == len) {
+ str_ncat(longish, OPERAND(first)+1,
+ *OPERAND(first));
+ len += *OPERAND(first);
+ curback += *OPERAND(first);
+ first = regnext(scan);
+ }
+ else if (*OPERAND(first) >= len + (curback >= 0)) {
+ len = *OPERAND(first);
+ str_nset(longish, OPERAND(first)+1,len);
+ backish = curback;
+ curback += len;
+ first = regnext(scan);
+ }
+ else
+ curback += *OPERAND(first);
+ }
+ else if (index(varies,OP(scan))) {
+ curback = -30000;
+ len = 0;
+ if (longish->str_cur > longest->str_cur) {
+ str_sset(longest,longish);
+ backest = backish;
+ }
+ str_nset(longish,"",0);
+ if (OP(scan) == PLUS &&
+ index(simple,OP(NEXTOPER(scan))))
+ minlen++;
+ else if (OP(scan) == CURLY &&
+ index(simple,OP(NEXTOPER(scan)+4)))
+ minlen += ARG1(scan);
+ }
+ else if (index(simple,OP(scan))) {
+ curback++;
+ minlen++;
+ len = 0;
+ if (longish->str_cur > longest->str_cur) {
+ str_sset(longest,longish);
+ backest = backish;
+ }
+ str_nset(longish,"",0);
+ }
+ scan = regnext(scan);
+ }
+
+ /* Prefer earlier on tie, unless we can tail match latter */
+
+ if (longish->str_cur + (OP(first) == EOL) > longest->str_cur) {
+ str_sset(longest,longish);
+ backest = backish;
+ }
+ else
+ str_nset(longish,"",0);
+ if (longest->str_cur
+ &&
+ (!r->regstart
+ ||
+ !fbminstr((unsigned char*) r->regstart->str_ptr,
+ (unsigned char *) r->regstart->str_ptr
+ + r->regstart->str_cur,
+ longest)
+ )
+ )
+ {
+ r->regmust = longest;
+ if (backest < 0)
+ backest = -1;
+ r->regback = backest;
+ if (longest->str_cur
+ > !(sawstudy || fold || OP(first) == EOL) )
+ fbmcompile(r->regmust,fold);
+ r->regmust->str_u.str_useful = 100;
+ if (OP(first) == EOL && longish->str_cur)
+ r->regmust->str_pok |= SP_TAIL;
+ }
+ else {
+ str_free(longest);
+ longest = Nullstr;
+ }
+ str_free(longish);
+ }
+
+ r->do_folding = fold;
+ r->nparens = regnpar - 1;
+ r->minlen = minlen;
+ Newz(1002, r->startp, regnpar, char*);
+ Newz(1002, r->endp, regnpar, char*);
+#ifdef DEBUGGING
+ if (debug & 512)
+ regdump(r);
+#endif
+ return(r);
+}
+
+/*
+ - reg - regular expression, i.e. main body or parenthesized thing
+ *
+ * Caller must absorb opening parenthesis.
+ *
+ * Combining parenthesis handling with the base level of regular expression
+ * is a trifle forced, but the need to tie the tails of the branches to what
+ * follows makes it hard to avoid.
+ */
+static char *
+reg(paren, flagp)
+int paren; /* Parenthesized? */
+int *flagp;
+{
+ register char *ret;
+ register char *br;
+ register char *ender;
+ register int parno;
+ int flags;
+
+ *flagp = HASWIDTH; /* Tentatively. */
+
+ /* Make an OPEN node, if parenthesized. */
+ if (paren) {
+ parno = regnpar;
+ regnpar++;
+ ret = reganode(OPEN, parno);
+ } else
+ ret = NULL;
+
+ /* Pick up the branches, linking them together. */
+ br = regbranch(&flags);
+ if (br == NULL)
+ return(NULL);
+ if (ret != NULL)
+ regtail(ret, br); /* OPEN -> first. */
+ else
+ ret = br;
+ if (!(flags&HASWIDTH))
+ *flagp &= ~HASWIDTH;
+ *flagp |= flags&SPSTART;
+ while (*regparse == '|') {
+ regparse++;
+ br = regbranch(&flags);
+ if (br == NULL)
+ return(NULL);
+ regtail(ret, br); /* BRANCH -> BRANCH. */
+ if (!(flags&HASWIDTH))
+ *flagp &= ~HASWIDTH;
+ *flagp |= flags&SPSTART;
+ }
+
+ /* Make a closing node, and hook it on the end. */
+ if (paren)
+ ender = reganode(CLOSE, parno);
+ else
+ ender = regnode(END);
+ regtail(ret, ender);
+
+ /* Hook the tails of the branches to the closing node. */
+ for (br = ret; br != NULL; br = regnext(br))
+ regoptail(br, ender);
+
+ /* Check for proper termination. */
+ if (paren && *regparse++ != ')') {
+ FAIL("unmatched () in regexp");
+ } else if (!paren && regparse < regxend) {
+ if (*regparse == ')') {
+ FAIL("unmatched () in regexp");
+ } else
+ FAIL("junk on end of regexp"); /* "Can't happen". */
+ /* NOTREACHED */
+ }
+
+ return(ret);
+}
+
+/*
+ - regbranch - one alternative of an | operator
+ *
+ * Implements the concatenation operator.
+ */
+static char *
+regbranch(flagp)
+int *flagp;
+{
+ register char *ret;
+ register char *chain;
+ register char *latest;
+ int flags;
+
+ *flagp = WORST; /* Tentatively. */
+
+ ret = regnode(BRANCH);
+ chain = NULL;
+ while (regparse < regxend && *regparse != '|' && *regparse != ')') {
+ latest = regpiece(&flags);
+ if (latest == NULL)
+ return(NULL);
+ *flagp |= flags&HASWIDTH;
+ if (chain == NULL) /* First piece. */
+ *flagp |= flags&SPSTART;
+ else
+ regtail(chain, latest);
+ chain = latest;
+ }
+ if (chain == NULL) /* Loop ran zero times. */
+ (void) regnode(NOTHING);
+
+ return(ret);
+}
+
+/*
+ - regpiece - something followed by possible [*+?]
+ *
+ * Note that the branching code sequences used for ? and the general cases
+ * of * and + are somewhat optimized: they use the same NOTHING node as
+ * both the endmarker for their branch list and the body of the last branch.
+ * It might seem that this node could be dispensed with entirely, but the
+ * endmarker role is not redundant.
+ */
+static char *
+regpiece(flagp)
+int *flagp;
+{
+ register char *ret;
+ register char op;
+ register char *next;
+ int flags;
+ char *origparse = regparse;
+ int orignpar = regnpar;
+ char *max;
+ int iter;
+ char ch;
+
+ ret = regatom(&flags);
+ if (ret == NULL)
+ return(NULL);
+
+ op = *regparse;
+
+ /* Here's a total kludge: if after the atom there's a {\d+,?\d*}
+ * then we decrement the first number by one and reset our
+ * parsing back to the beginning of the same atom. If the first number
+ * is down to 0, decrement the second number instead and fake up
+ * a ? after it. Given the way this compiler doesn't keep track
+ * of offsets on the first pass, this is the only way to replicate
+ * a piece of code. Sigh.
+ */
+ if (op == '{' && regcurly(regparse)) {
+ next = regparse + 1;
+ max = Nullch;
+ while (isDIGIT(*next) || *next == ',') {
+ if (*next == ',') {
+ if (max)
+ break;
+ else
+ max = next;
+ }
+ next++;
+ }
+ if (*next == '}') { /* got one */
+ if (!max)
+ max = next;
+ regparse++;
+ iter = atoi(regparse);
+ if (flags&SIMPLE) { /* we can do it right after all */
+ int tmp;
+
+ reginsert(CURLY, ret);
+ if (iter > 0)
+ *flagp = (WORST|HASWIDTH);
+ if (*max == ',')
+ max++;
+ else
+ max = regparse;
+ tmp = atoi(max);
+ if (!tmp && *max != '0')
+ tmp = 32767; /* meaning "infinity" */
+ if (tmp && tmp < iter)
+ fatal("Can't do {n,m} with n > m");
+ if (regcode != &regdummy) {
+#ifdef REGALIGN
+ *(unsigned short *)(ret+3) = iter;
+ *(unsigned short *)(ret+5) = tmp;
+#else
+ ret[3] = iter >> 8; ret[4] = iter & 0377;
+ ret[5] = tmp >> 8; ret[6] = tmp & 0377;
+#endif
+ }
+ regparse = next;
+ goto nest_check;
+ }
+ regsawbracket++; /* remember we clobbered exp */
+ if (iter > 0) {
+ ch = *max;
+ sprintf(regparse,"%.*d", max-regparse, iter - 1);
+ *max = ch;
+ if (*max == ',' && max[1] != '}') {
+ if (atoi(max+1) <= 0)
+ fatal("Can't do {n,m} with n > m");
+ ch = *next;
+ sprintf(max+1,"%.*d", next-(max+1), atoi(max+1) - 1);
+ *next = ch;
+ }
+ if (iter != 1 || *max == ',') {
+ regparse = origparse; /* back up input pointer */
+ regnpar = orignpar; /* don't make more parens */
+ }
+ else {
+ regparse = next;
+ goto nest_check;
+ }
+ *flagp = flags;
+ return ret;
+ }
+ if (*max == ',') {
+ max++;
+ iter = atoi(max);
+ if (max == next) { /* any number more? */
+ regparse = next;
+ op = '*'; /* fake up one with a star */
+ }
+ else if (iter > 0) {
+ op = '?'; /* fake up optional atom */
+ ch = *next;
+ sprintf(max,"%.*d", next-max, iter - 1);
+ *next = ch;
+ if (iter == 1)
+ regparse = next;
+ else {
+ regparse = origparse - 1; /* offset ++ below */
+ regnpar = orignpar;
+ }
+ }
+ else
+ fatal("Can't do {n,0}");
+ }
+ else
+ fatal("Can't do {0}");
+ }
+ }
+
+ if (!ISMULT1(op)) {
+ *flagp = flags;
+ return(ret);
+ }
+
+ if (!(flags&HASWIDTH) && op != '?')
+ FAIL("regexp *+ operand could be empty");
+ *flagp = (op != '+') ? (WORST|SPSTART) : (WORST|HASWIDTH);
+
+ if (op == '*' && (flags&SIMPLE))
+ reginsert(STAR, ret);
+ else if (op == '*') {
+ /* Emit x* as (x&|), where & means "self". */
+ reginsert(BRANCH, ret); /* Either x */
+ regoptail(ret, regnode(BACK)); /* and loop */
+ regoptail(ret, ret); /* back */
+ regtail(ret, regnode(BRANCH)); /* or */
+ regtail(ret, regnode(NOTHING)); /* null. */
+ } else if (op == '+' && (flags&SIMPLE))
+ reginsert(PLUS, ret);
+ else if (op == '+') {
+ /* Emit x+ as x(&|), where & means "self". */
+ next = regnode(BRANCH); /* Either */
+ regtail(ret, next);
+ regtail(regnode(BACK), ret); /* loop back */
+ regtail(next, regnode(BRANCH)); /* or */
+ regtail(ret, regnode(NOTHING)); /* null. */
+ } else if (op == '?') {
+ /* Emit x? as (x|) */
+ reginsert(BRANCH, ret); /* Either x */
+ regtail(ret, regnode(BRANCH)); /* or */
+ next = regnode(NOTHING); /* null. */
+ regtail(ret, next);
+ regoptail(ret, next);
+ }
+ nest_check:
+ regparse++;
+ if (ISMULT2(regparse))
+ FAIL("nested *?+ in regexp");
+
+ return(ret);
+}
+
+/*
+ - regatom - the lowest level
+ *
+ * Optimization: gobbles an entire sequence of ordinary characters so that
+ * it can turn them into a single node, which is smaller to store and
+ * faster to run. Backslashed characters are exceptions, each becoming a
+ * separate node; the code is simpler that way and it's not worth fixing.
+ *
+ * [Yes, it is worth fixing, some scripts can run twice the speed.]
+ */
+static char *
+regatom(flagp)
+int *flagp;
+{
+ register char *ret;
+ int flags;
+
+ *flagp = WORST; /* Tentatively. */
+
+ switch (*regparse++) {
+ case '^':
+ ret = regnode(BOL);
+ break;
+ case '$':
+ ret = regnode(EOL);
+ break;
+ case '.':
+ ret = regnode(ANY);
+ *flagp |= HASWIDTH|SIMPLE;
+ break;
+ case '[':
+ ret = regclass();
+ *flagp |= HASWIDTH|SIMPLE;
+ break;
+ case '(':
+ ret = reg(1, &flags);
+ if (ret == NULL)
+ return(NULL);
+ *flagp |= flags&(HASWIDTH|SPSTART);
+ break;
+ case '|':
+ case ')':
+ FAIL("internal urp in regexp"); /* Supposed to be caught earlier. */
+ break;
+ case '?':
+ case '+':
+ case '*':
+ FAIL("?+* follows nothing in regexp");
+ break;
+ case '\\':
+ switch (*regparse) {
+ case 'w':
+ ret = regnode(ALNUM);
+ *flagp |= HASWIDTH|SIMPLE;
+ regparse++;
+ break;
+ case 'W':
+ ret = regnode(NALNUM);
+ *flagp |= HASWIDTH|SIMPLE;
+ regparse++;
+ break;
+ case 'b':
+ ret = regnode(BOUND);
+ *flagp |= SIMPLE;
+ regparse++;
+ break;
+ case 'B':
+ ret = regnode(NBOUND);
+ *flagp |= SIMPLE;
+ regparse++;
+ break;
+ case 's':
+ ret = regnode(SPACE);
+ *flagp |= HASWIDTH|SIMPLE;
+ regparse++;
+ break;
+ case 'S':
+ ret = regnode(NSPACE);
+ *flagp |= HASWIDTH|SIMPLE;
+ regparse++;
+ break;
+ case 'd':
+ ret = regnode(DIGIT);
+ *flagp |= HASWIDTH|SIMPLE;
+ regparse++;
+ break;
+ case 'D':
+ ret = regnode(NDIGIT);
+ *flagp |= HASWIDTH|SIMPLE;
+ regparse++;
+ break;
+ case 'n':
+ case 'r':
+ case 't':
+ case 'f':
+ case 'e':
+ case 'a':
+ case 'x':
+ case 'c':
+ case '0':
+ goto defchar;
+ case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ {
+ int num = atoi(regparse);
+
+ if (num > 9 && num >= regnpar)
+ goto defchar;
+ else {
+ regsawback = 1;
+ ret = reganode(REF, num);
+ while (isDIGIT(*regparse))
+ regparse++;
+ *flagp |= SIMPLE;
+ }
+ }
+ break;
+ case '\0':
+ if (regparse >= regxend)
+ FAIL("trailing \\ in regexp");
+ /* FALL THROUGH */
+ default:
+ goto defchar;
+ }
+ break;
+ default: {
+ register int len;
+ register char ender;
+ register char *p;
+ char *oldp;
+ int numlen;
+
+ defchar:
+ ret = regnode(EXACTLY);
+ regc(0); /* save spot for len */
+ for (len=0, p=regparse-1;
+ len < 127 && p < regxend;
+ len++)
+ {
+ oldp = p;
+ switch (*p) {
+ case '^':
+ case '$':
+ case '.':
+ case '[':
+ case '(':
+ case ')':
+ case '|':
+ goto loopdone;
+ case '\\':
+ switch (*++p) {
+ case 'w':
+ case 'W':
+ case 'b':
+ case 'B':
+ case 's':
+ case 'S':
+ case 'd':
+ case 'D':
+ --p;
+ goto loopdone;
+ case 'n':
+ ender = '\n';
+ p++;
+ break;
+ case 'r':
+ ender = '\r';
+ p++;
+ break;
+ case 't':
+ ender = '\t';
+ p++;
+ break;
+ case 'f':
+ ender = '\f';
+ p++;
+ break;
+ case 'e':
+ ender = '\033';
+ p++;
+ break;
+ case 'a':
+ ender = '\007';
+ p++;
+ break;
+ case 'x':
+ ender = scanhex(++p, 2, &numlen);
+ p += numlen;
+ break;
+ case 'c':
+ p++;
+ ender = *p++;
+ if (isLOWER(ender))
+ ender = toupper(ender);
+ ender ^= 64;
+ break;
+ case '0': case '1': case '2': case '3':case '4':
+ case '5': case '6': case '7': case '8':case '9':
+ if (*p == '0' ||
+ (isDIGIT(p[1]) && atoi(p) >= regnpar) ) {
+ ender = scanoct(p, 3, &numlen);
+ p += numlen;
+ }
+ else {
+ --p;
+ goto loopdone;
+ }
+ break;
+ case '\0':
+ if (p >= regxend)
+ FAIL("trailing \\ in regexp");
+ /* FALL THROUGH */
+ default:
+ ender = *p++;
+ break;
+ }
+ break;
+ default:
+ ender = *p++;
+ break;
+ }
+ if (regfold && isUPPER(ender))
+ ender = tolower(ender);
+ if (ISMULT2(p)) { /* Back off on ?+*. */
+ if (len)
+ p = oldp;
+ else {
+ len++;
+ regc(ender);
+ }
+ break;
+ }
+ regc(ender);
+ }
+ loopdone:
+ regparse = p;
+ if (len <= 0)
+ FAIL("internal disaster in regexp");
+ *flagp |= HASWIDTH;
+ if (len == 1)
+ *flagp |= SIMPLE;
+ if (regcode != &regdummy)
+ *OPERAND(ret) = len;
+ regc('\0');
+ }
+ break;
+ }
+
+ return(ret);
+}
+
+static void
+regset(bits,def,c)
+char *bits;
+int def;
+register int c;
+{
+ if (regcode == &regdummy)
+ return;
+ c &= 255;
+ if (def)
+ bits[c >> 3] &= ~(1 << (c & 7));
+ else
+ bits[c >> 3] |= (1 << (c & 7));
+}
+
+static char *
+regclass()
+{
+ register char *bits;
+ register int class;
+ register int lastclass;
+ register int range = 0;
+ register char *ret;
+ register int def;
+ int numlen;
+
+ ret = regnode(ANYOF);
+ if (*regparse == '^') { /* Complement of range. */
+ regparse++;
+ def = 0;
+ } else {
+ def = 255;
+ }
+ bits = regcode;
+ for (class = 0; class < 32; class++)
+ regc(def);
+ if (*regparse == ']' || *regparse == '-')
+ goto skipcond; /* allow 1st char to be ] or - */
+ while (regparse < regxend && *regparse != ']') {
+ skipcond:
+ class = UCHARAT(regparse++);
+ if (class == '\\') {
+ class = UCHARAT(regparse++);
+ switch (class) {
+ case 'w':
+ for (class = 0; class < 256; class++)
+ if (isALNUM(class))
+ regset(bits,def,class);
+ lastclass = 1234;
+ continue;
+ case 'W':
+ for (class = 0; class < 256; class++)
+ if (!isALNUM(class))
+ regset(bits,def,class);
+ lastclass = 1234;
+ continue;
+ case 's':
+ for (class = 0; class < 256; class++)
+ if (isSPACE(class))
+ regset(bits,def,class);
+ lastclass = 1234;
+ continue;
+ case 'S':
+ for (class = 0; class < 256; class++)
+ if (!isSPACE(class))
+ regset(bits,def,class);
+ lastclass = 1234;
+ continue;
+ case 'd':
+ for (class = '0'; class <= '9'; class++)
+ regset(bits,def,class);
+ lastclass = 1234;
+ continue;
+ case 'D':
+ for (class = 0; class < '0'; class++)
+ regset(bits,def,class);
+ for (class = '9' + 1; class < 256; class++)
+ regset(bits,def,class);
+ lastclass = 1234;
+ continue;
+ case 'n':
+ class = '\n';
+ break;
+ case 'r':
+ class = '\r';
+ break;
+ case 't':
+ class = '\t';
+ break;
+ case 'f':
+ class = '\f';
+ break;
+ case 'b':
+ class = '\b';
+ break;
+ case 'e':
+ class = '\033';
+ break;
+ case 'a':
+ class = '\007';
+ break;
+ case 'x':
+ class = scanhex(regparse, 2, &numlen);
+ regparse += numlen;
+ break;
+ case 'c':
+ class = *regparse++;
+ if (isLOWER(class))
+ class = toupper(class);
+ class ^= 64;
+ break;
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ class = scanoct(--regparse, 3, &numlen);
+ regparse += numlen;
+ break;
+ }
+ }
+ if (range) {
+ if (lastclass > class)
+ FAIL("invalid [] range in regexp");
+ range = 0;
+ }
+ else {
+ lastclass = class;
+ if (*regparse == '-' && regparse+1 < regxend &&
+ regparse[1] != ']') {
+ regparse++;
+ range = 1;
+ continue; /* do it next time */
+ }
+ }
+ for ( ; lastclass <= class; lastclass++) {
+ regset(bits,def,lastclass);
+ if (regfold && isUPPER(lastclass))
+ regset(bits,def,tolower(lastclass));
+ }
+ lastclass = class;
+ }
+ if (*regparse != ']')
+ FAIL("unmatched [] in regexp");
+ regparse++;
+ return ret;
+}
+
+/*
+ - regnode - emit a node
+ */
+static char * /* Location. */
+regnode(op)
+char op;
+{
+ register char *ret;
+ register char *ptr;
+
+ ret = regcode;
+ if (ret == &regdummy) {
+#ifdef REGALIGN
+ if (!(regsize & 1))
+ regsize++;
+#endif
+ regsize += 3;
+ return(ret);
+ }
+
+#ifdef REGALIGN
+#ifndef lint
+ if (!((long)ret & 1))
+ *ret++ = 127;
+#endif
+#endif
+ ptr = ret;
+ *ptr++ = op;
+ *ptr++ = '\0'; /* Null "next" pointer. */
+ *ptr++ = '\0';
+ regcode = ptr;
+
+ return(ret);
+}
+
+/*
+ - reganode - emit a node with an argument
+ */
+static char * /* Location. */
+reganode(op, arg)
+char op;
+unsigned short arg;
+{
+ register char *ret;
+ register char *ptr;
+
+ ret = regcode;
+ if (ret == &regdummy) {
+#ifdef REGALIGN
+ if (!(regsize & 1))
+ regsize++;
+#endif
+ regsize += 5;
+ return(ret);
+ }
+
+#ifdef REGALIGN
+#ifndef lint
+ if (!((long)ret & 1))
+ *ret++ = 127;
+#endif
+#endif
+ ptr = ret;
+ *ptr++ = op;
+ *ptr++ = '\0'; /* Null "next" pointer. */
+ *ptr++ = '\0';
+#ifdef REGALIGN
+ *(unsigned short *)(ret+3) = arg;
+#else
+ ret[3] = arg >> 8; ret[4] = arg & 0377;
+#endif
+ ptr += 2;
+ regcode = ptr;
+
+ return(ret);
+}
+
+/*
+ - regc - emit (if appropriate) a byte of code
+ */
+static void
+regc(b)
+char b;
+{
+ if (regcode != &regdummy)
+ *regcode++ = b;
+ else
+ regsize++;
+}
+
+/*
+ - reginsert - insert an operator in front of already-emitted operand
+ *
+ * Means relocating the operand.
+ */
+static void
+reginsert(op, opnd)
+char op;
+char *opnd;
+{
+ register char *src;
+ register char *dst;
+ register char *place;
+ register offset = (op == CURLY ? 4 : 0);
+
+ if (regcode == &regdummy) {
+#ifdef REGALIGN
+ regsize += 4 + offset;
+#else
+ regsize += 3 + offset;
+#endif
+ return;
+ }
+
+ src = regcode;
+#ifdef REGALIGN
+ regcode += 4 + offset;
+#else
+ regcode += 3 + offset;
+#endif
+ dst = regcode;
+ while (src > opnd)
+ *--dst = *--src;
+
+ place = opnd; /* Op node, where operand used to be. */
+ *place++ = op;
+ *place++ = '\0';
+ *place++ = '\0';
+ while (offset-- > 0)
+ *place++ = '\0';
+#ifdef REGALIGN
+ *place++ = '\177';
+#endif
+}
+
+/*
+ - regtail - set the next-pointer at the end of a node chain
+ */
+static void
+regtail(p, val)
+char *p;
+char *val;
+{
+ register char *scan;
+ register char *temp;
+ register int offset;
+
+ if (p == &regdummy)
+ return;
+
+ /* Find last node. */
+ scan = p;
+ for (;;) {
+ temp = regnext(scan);
+ if (temp == NULL)
+ break;
+ scan = temp;
+ }
+
+#ifdef REGALIGN
+ offset = val - scan;
+#ifndef lint
+ *(short*)(scan+1) = offset;
+#else
+ offset = offset;
+#endif
+#else
+ if (OP(scan) == BACK)
+ offset = scan - val;
+ else
+ offset = val - scan;
+ *(scan+1) = (offset>>8)&0377;
+ *(scan+2) = offset&0377;
+#endif
+}
+
+/*
+ - regoptail - regtail on operand of first argument; nop if operandless
+ */
+static void
+regoptail(p, val)
+char *p;
+char *val;
+{
+ /* "Operandless" and "op != BRANCH" are synonymous in practice. */
+ if (p == NULL || p == &regdummy || OP(p) != BRANCH)
+ return;
+ regtail(NEXTOPER(p), val);
+}
+
+/*
+ - regcurly - a little FSA that accepts {\d+,?\d*}
+ */
+STATIC int
+regcurly(s)
+register char *s;
+{
+ if (*s++ != '{')
+ return FALSE;
+ if (!isDIGIT(*s))
+ return FALSE;
+ while (isDIGIT(*s))
+ s++;
+ if (*s == ',')
+ s++;
+ while (isDIGIT(*s))
+ s++;
+ if (*s != '}')
+ return FALSE;
+ return TRUE;
+}
+
+#ifdef DEBUGGING
+
+/*
+ - regdump - dump a regexp onto stderr in vaguely comprehensible form
+ */
+void
+regdump(r)
+regexp *r;
+{
+ register char *s;
+ register char op = EXACTLY; /* Arbitrary non-END op. */
+ register char *next;
+
+
+ s = r->program + 1;
+ while (op != END) { /* While that wasn't END last time... */
+#ifdef REGALIGN
+ if (!((long)s & 1))
+ s++;
+#endif
+ op = OP(s);
+ fprintf(stderr,"%2d%s", s-r->program, regprop(s)); /* Where, what. */
+ next = regnext(s);
+ s += regarglen[op];
+ if (next == NULL) /* Next ptr. */
+ fprintf(stderr,"(0)");
+ else
+ fprintf(stderr,"(%d)", (s-r->program)+(next-s));
+ s += 3;
+ if (op == ANYOF) {
+ s += 32;
+ }
+ if (op == EXACTLY) {
+ /* Literal string, where present. */
+ s++;
+ while (*s != '\0') {
+ (void)putchar(*s);
+ s++;
+ }
+ s++;
+ }
+ (void)putchar('\n');
+ }
+
+ /* Header fields of interest. */
+ if (r->regstart)
+ fprintf(stderr,"start `%s' ", r->regstart->str_ptr);
+ if (r->regstclass)
+ fprintf(stderr,"stclass `%s' ", regprop(r->regstclass));
+ if (r->reganch & ROPT_ANCH)
+ fprintf(stderr,"anchored ");
+ if (r->reganch & ROPT_SKIP)
+ fprintf(stderr,"plus ");
+ if (r->reganch & ROPT_IMPLICIT)
+ fprintf(stderr,"implicit ");
+ if (r->regmust != NULL)
+ fprintf(stderr,"must have \"%s\" back %d ", r->regmust->str_ptr,
+ r->regback);
+ fprintf(stderr, "minlen %d ", r->minlen);
+ fprintf(stderr,"\n");
+}
+
+/*
+ - regprop - printable representation of opcode
+ */
+char *
+regprop(op)
+char *op;
+{
+ register char *p;
+
+ (void) strcpy(buf, ":");
+
+ switch (OP(op)) {
+ case BOL:
+ p = "BOL";
+ break;
+ case EOL:
+ p = "EOL";
+ break;
+ case ANY:
+ p = "ANY";
+ break;
+ case ANYOF:
+ p = "ANYOF";
+ break;
+ case BRANCH:
+ p = "BRANCH";
+ break;
+ case EXACTLY:
+ p = "EXACTLY";
+ break;
+ case NOTHING:
+ p = "NOTHING";
+ break;
+ case BACK:
+ p = "BACK";
+ break;
+ case END:
+ p = "END";
+ break;
+ case ALNUM:
+ p = "ALNUM";
+ break;
+ case NALNUM:
+ p = "NALNUM";
+ break;
+ case BOUND:
+ p = "BOUND";
+ break;
+ case NBOUND:
+ p = "NBOUND";
+ break;
+ case SPACE:
+ p = "SPACE";
+ break;
+ case NSPACE:
+ p = "NSPACE";
+ break;
+ case DIGIT:
+ p = "DIGIT";
+ break;
+ case NDIGIT:
+ p = "NDIGIT";
+ break;
+ case CURLY:
+ (void)sprintf(buf+strlen(buf), "CURLY {%d,%d}",
+ ARG1(op),ARG2(op));
+ p = NULL;
+ break;
+ case REF:
+ (void)sprintf(buf+strlen(buf), "REF%d", ARG1(op));
+ p = NULL;
+ break;
+ case OPEN:
+ (void)sprintf(buf+strlen(buf), "OPEN%d", ARG1(op));
+ p = NULL;
+ break;
+ case CLOSE:
+ (void)sprintf(buf+strlen(buf), "CLOSE%d", ARG1(op));
+ p = NULL;
+ break;
+ case STAR:
+ p = "STAR";
+ break;
+ case PLUS:
+ p = "PLUS";
+ break;
+ default:
+ FAIL("corrupted regexp opcode");
+ }
+ if (p != NULL)
+ (void) strcat(buf, p);
+ return(buf);
+}
+#endif /* DEBUGGING */
+
+void
+regfree(r)
+struct regexp *r;
+{
+ if (r->precomp) {
+ Safefree(r->precomp);
+ r->precomp = Nullch;
+ }
+ if (r->subbase) {
+ Safefree(r->subbase);
+ r->subbase = Nullch;
+ }
+ if (r->regmust) {
+ str_free(r->regmust);
+ r->regmust = Nullstr;
+ }
+ if (r->regstart) {
+ str_free(r->regstart);
+ r->regstart = Nullstr;
+ }
+ Safefree(r->startp);
+ Safefree(r->endp);
+ Safefree(r);
+}
diff --git a/gnu/usr.bin/perl/perl/regcomp.h b/gnu/usr.bin/perl/perl/regcomp.h
new file mode 100644
index 0000000..b6b8c18
--- /dev/null
+++ b/gnu/usr.bin/perl/perl/regcomp.h
@@ -0,0 +1,203 @@
+/* $RCSfile: regcomp.h,v $$Revision: 1.1.1.1 $$Date: 1994/09/10 06:27:35 $
+ *
+ * $Log: regcomp.h,v $
+ * Revision 1.1.1.1 1994/09/10 06:27:35 gclarkii
+ * Initial import of Perl 4.046 bmaked
+ *
+ * Revision 1.1.1.1 1993/08/23 21:29:39 nate
+ * PERL!
+ *
+ * Revision 4.0.1.1 91/06/07 11:49:40 lwall
+ * patch4: no change
+ *
+ * Revision 4.0 91/03/20 01:39:09 lwall
+ * 4.0 baseline.
+ *
+ */
+
+/*
+ * The "internal use only" fields in regexp.h are present to pass info from
+ * compile to execute that permits the execute phase to run lots faster on
+ * simple cases. They are:
+ *
+ * regstart str that must begin a match; Nullch if none obvious
+ * reganch is the match anchored (at beginning-of-line only)?
+ * regmust string (pointer into program) that match must include, or NULL
+ * [regmust changed to STR* for bminstr()--law]
+ * regmlen length of regmust string
+ * [regmlen not used currently]
+ *
+ * Regstart and reganch permit very fast decisions on suitable starting points
+ * for a match, cutting down the work a lot. Regmust permits fast rejection
+ * of lines that cannot possibly match. The regmust tests are costly enough
+ * that regcomp() supplies a regmust only if the r.e. contains something
+ * potentially expensive (at present, the only such thing detected is * or +
+ * at the start of the r.e., which can involve a lot of backup). Regmlen is
+ * supplied because the test in regexec() needs it and regcomp() is computing
+ * it anyway.
+ * [regmust is now supplied always. The tests that use regmust have a
+ * heuristic that disables the test if it usually matches.]
+ *
+ * [In fact, we now use regmust in many cases to locate where the search
+ * starts in the string, so if regback is >= 0, the regmust search is never
+ * wasted effort. The regback variable says how many characters back from
+ * where regmust matched is the earliest possible start of the match.
+ * For instance, /[a-z].foo/ has a regmust of 'foo' and a regback of 2.]
+ */
+
+/*
+ * Structure for regexp "program". This is essentially a linear encoding
+ * of a nondeterministic finite-state machine (aka syntax charts or
+ * "railroad normal form" in parsing technology). Each node is an opcode
+ * plus a "next" pointer, possibly plus an operand. "Next" pointers of
+ * all nodes except BRANCH implement concatenation; a "next" pointer with
+ * a BRANCH on both ends of it is connecting two alternatives. (Here we
+ * have one of the subtle syntax dependencies: an individual BRANCH (as
+ * opposed to a collection of them) is never concatenated with anything
+ * because of operator precedence.) The operand of some types of node is
+ * a literal string; for others, it is a node leading into a sub-FSM. In
+ * particular, the operand of a BRANCH node is the first node of the branch.
+ * (NB this is *not* a tree structure: the tail of the branch connects
+ * to the thing following the set of BRANCHes.) The opcodes are:
+ */
+
+/* definition number opnd? meaning */
+#define END 0 /* no End of program. */
+#define BOL 1 /* no Match "" at beginning of line. */
+#define EOL 2 /* no Match "" at end of line. */
+#define ANY 3 /* no Match any one character. */
+#define ANYOF 4 /* str Match character in (or not in) this class. */
+#define CURLY 5 /* str Match this simple thing {n,m} times. */
+#define BRANCH 6 /* node Match this alternative, or the next... */
+#define BACK 7 /* no Match "", "next" ptr points backward. */
+#define EXACTLY 8 /* str Match this string (preceded by length). */
+#define NOTHING 9 /* no Match empty string. */
+#define STAR 10 /* node Match this (simple) thing 0 or more times. */
+#define PLUS 11 /* node Match this (simple) thing 1 or more times. */
+#define ALNUM 12 /* no Match any alphanumeric character */
+#define NALNUM 13 /* no Match any non-alphanumeric character */
+#define BOUND 14 /* no Match "" at any word boundary */
+#define NBOUND 15 /* no Match "" at any word non-boundary */
+#define SPACE 16 /* no Match any whitespace character */
+#define NSPACE 17 /* no Match any non-whitespace character */
+#define DIGIT 18 /* no Match any numeric character */
+#define NDIGIT 19 /* no Match any non-numeric character */
+#define REF 20 /* num Match some already matched string */
+#define OPEN 21 /* num Mark this point in input as start of #n. */
+#define CLOSE 22 /* num Analogous to OPEN. */
+
+/*
+ * Opcode notes:
+ *
+ * BRANCH The set of branches constituting a single choice are hooked
+ * together with their "next" pointers, since precedence prevents
+ * anything being concatenated to any individual branch. The
+ * "next" pointer of the last BRANCH in a choice points to the
+ * thing following the whole choice. This is also where the
+ * final "next" pointer of each individual branch points; each
+ * branch starts with the operand node of a BRANCH node.
+ *
+ * BACK Normal "next" pointers all implicitly point forward; BACK
+ * exists to make loop structures possible.
+ *
+ * STAR,PLUS '?', and complex '*' and '+', are implemented as circular
+ * BRANCH structures using BACK. Simple cases (one character
+ * per match) are implemented with STAR and PLUS for speed
+ * and to minimize recursive plunges.
+ *
+ * OPEN,CLOSE ...are numbered at compile time.
+ */
+
+#ifndef DOINIT
+extern char regarglen[];
+#else
+char regarglen[] = {0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2};
+#endif
+
+/* The following have no fixed length. */
+#ifndef DOINIT
+extern char varies[];
+#else
+char varies[] = {BRANCH,BACK,STAR,PLUS,CURLY,REF,0};
+#endif
+
+/* The following always have a length of 1. */
+#ifndef DOINIT
+extern char simple[];
+#else
+char simple[] = {ANY,ANYOF,ALNUM,NALNUM,SPACE,NSPACE,DIGIT,NDIGIT,0};
+#endif
+
+EXT char regdummy;
+
+/*
+ * A node is one char of opcode followed by two chars of "next" pointer.
+ * "Next" pointers are stored as two 8-bit pieces, high order first. The
+ * value is a positive offset from the opcode of the node containing it.
+ * An operand, if any, simply follows the node. (Note that much of the
+ * code generation knows about this implicit relationship.)
+ *
+ * Using two bytes for the "next" pointer is vast overkill for most things,
+ * but allows patterns to get big without disasters.
+ *
+ * [If REGALIGN is defined, the "next" pointer is always aligned on an even
+ * boundary, and reads the offset directly as a short. Also, there is no
+ * special test to reverse the sign of BACK pointers since the offset is
+ * stored negative.]
+ */
+
+#ifndef gould
+#ifndef cray
+#ifndef eta10
+#define REGALIGN
+#endif
+#endif
+#endif
+
+#define OP(p) (*(p))
+
+#ifndef lint
+#ifdef REGALIGN
+#define NEXT(p) (*(short*)(p+1))
+#define ARG1(p) (*(unsigned short*)(p+3))
+#define ARG2(p) (*(unsigned short*)(p+5))
+#else
+#define NEXT(p) (((*((p)+1)&0377)<<8) + (*((p)+2)&0377))
+#define ARG1(p) (((*((p)+3)&0377)<<8) + (*((p)+4)&0377))
+#define ARG2(p) (((*((p)+5)&0377)<<8) + (*((p)+6)&0377))
+#endif
+#else /* lint */
+#define NEXT(p) 0
+#endif /* lint */
+
+#define OPERAND(p) ((p) + 3)
+
+#ifdef REGALIGN
+#define NEXTOPER(p) ((p) + 4)
+#else
+#define NEXTOPER(p) ((p) + 3)
+#endif
+
+#define MAGIC 0234
+
+/*
+ * Utility definitions.
+ */
+#ifndef lint
+#ifndef CHARBITS
+#define UCHARAT(p) ((int)*(unsigned char *)(p))
+#else
+#define UCHARAT(p) ((int)*(p)&CHARBITS)
+#endif
+#else /* lint */
+#define UCHARAT(p) regdummy
+#endif /* lint */
+
+#define FAIL(m) fatal("/%s/: %s",regprecomp,m)
+
+char *regnext();
+#ifdef DEBUGGING
+void regdump();
+char *regprop();
+#endif
+
diff --git a/gnu/usr.bin/perl/perl/regexec.c b/gnu/usr.bin/perl/perl/regexec.c
new file mode 100644
index 0000000..b835306
--- /dev/null
+++ b/gnu/usr.bin/perl/perl/regexec.c
@@ -0,0 +1,913 @@
+/* NOTE: this is derived from Henry Spencer's regexp code, and should not
+ * confused with the original package (see point 3 below). Thanks, Henry!
+ */
+
+/* Additional note: this code is very heavily munged from Henry's version
+ * in places. In some spots I've traded clarity for efficiency, so don't
+ * blame Henry for some of the lack of readability.
+ */
+
+/* $RCSfile: regexec.c,v $$Revision: 1.1.1.1 $$Date: 1994/09/10 06:27:33 $
+ *
+ * $Log: regexec.c,v $
+ * Revision 1.1.1.1 1994/09/10 06:27:33 gclarkii
+ * Initial import of Perl 4.046 bmaked
+ *
+ * Revision 1.1.1.1 1993/08/23 21:29:39 nate
+ * PERL!
+ *
+ * Revision 4.0.1.4 92/06/08 15:25:50 lwall
+ * patch20: pattern modifiers i and g didn't interact right
+ * patch20: in some cases $` and $' didn't get set by match
+ * patch20: /x{0}/ was wrongly interpreted as /x{0,}/
+ *
+ * Revision 4.0.1.3 91/11/05 18:23:55 lwall
+ * patch11: prepared for ctype implementations that don't define isascii()
+ * patch11: initial .* in pattern had dependency on value of $*
+ *
+ * Revision 4.0.1.2 91/06/07 11:50:33 lwall
+ * patch4: new copyright notice
+ * patch4: // wouldn't use previous pattern if it started with a null character
+ *
+ * Revision 4.0.1.1 91/04/12 09:07:39 lwall
+ * patch1: regexec only allocated space for 9 subexpresssions
+ *
+ * Revision 4.0 91/03/20 01:39:16 lwall
+ * 4.0 baseline.
+ *
+ */
+/*SUPPRESS 112*/
+/*
+ * regcomp and regexec -- regsub and regerror are not used in perl
+ *
+ * Copyright (c) 1986 by University of Toronto.
+ * Written by Henry Spencer. Not derived from licensed software.
+ *
+ * Permission is granted to anyone to use this software for any
+ * purpose on any computer system, and to redistribute it freely,
+ * subject to the following restrictions:
+ *
+ * 1. The author is not responsible for the consequences of use of
+ * this software, no matter how awful, even if they arise
+ * from defects in it.
+ *
+ * 2. The origin of this software must not be misrepresented, either
+ * by explicit claim or by omission.
+ *
+ * 3. Altered versions must be plainly marked as such, and must not
+ * be misrepresented as being the original software.
+ *
+ **** Alterations to Henry's code are...
+ ****
+ **** Copyright (c) 1991, Larry Wall
+ ****
+ **** You may distribute under the terms of either the GNU General Public
+ **** License or the Artistic License, as specified in the README file.
+ *
+ * Beware that some of this code is subtly aware of the way operator
+ * precedence is structured in regular expressions. Serious changes in
+ * regular-expression syntax might require a total rethink.
+ */
+#include "EXTERN.h"
+#include "perl.h"
+#include "regcomp.h"
+
+#ifndef STATIC
+#define STATIC static
+#endif
+
+#ifdef DEBUGGING
+int regnarrate = 0;
+#endif
+
+/*
+ * regexec and friends
+ */
+
+/*
+ * Global work variables for regexec().
+ */
+static char *regprecomp;
+static char *reginput; /* String-input pointer. */
+static char regprev; /* char before regbol, \n if none */
+static char *regbol; /* Beginning of input, for ^ check. */
+static char *regeol; /* End of input, for $ check. */
+static char **regstartp; /* Pointer to startp array. */
+static char **regendp; /* Ditto for endp. */
+static char *reglastparen; /* Similarly for lastparen. */
+static char *regtill;
+
+static int regmyp_size = 0;
+static char **regmystartp = Null(char**);
+static char **regmyendp = Null(char**);
+
+/*
+ * Forwards.
+ */
+STATIC int regtry();
+STATIC int regmatch();
+STATIC int regrepeat();
+
+extern int multiline;
+
+/*
+ - regexec - match a regexp against a string
+ */
+int
+regexec(prog, stringarg, strend, strbeg, minend, screamer, safebase)
+register regexp *prog;
+char *stringarg;
+register char *strend; /* pointer to null at end of string */
+char *strbeg; /* real beginning of string */
+int minend; /* end of match must be at least minend after stringarg */
+STR *screamer;
+int safebase; /* no need to remember string in subbase */
+{
+ register char *s;
+ register int i;
+ register char *c;
+ register char *string = stringarg;
+ register int tmp;
+ int minlen = 0; /* must match at least this many chars */
+ int dontbother = 0; /* how many characters not to try at end */
+
+ /* Be paranoid... */
+ if (prog == NULL || string == NULL) {
+ fatal("NULL regexp parameter");
+ return(0);
+ }
+
+ if (string == strbeg) /* is ^ valid at stringarg? */
+ regprev = '\n';
+ else {
+ regprev = stringarg[-1];
+ if (!multiline && regprev == '\n')
+ regprev = '\0'; /* force ^ to NOT match */
+ }
+ regprecomp = prog->precomp;
+ /* Check validity of program. */
+ if (UCHARAT(prog->program) != MAGIC) {
+ FAIL("corrupted regexp program");
+ }
+
+ if (prog->do_folding) {
+ i = strend - string;
+ New(1101,c,i+1,char);
+ Copy(string, c, i+1, char);
+ string = c;
+ strend = string + i;
+ for (s = string; s < strend; s++)
+ if (isUPPER(*s))
+ *s = tolower(*s);
+ }
+
+ /* If there is a "must appear" string, look for it. */
+ s = string;
+ if (prog->regmust != Nullstr &&
+ (!(prog->reganch & ROPT_ANCH)
+ || (multiline && prog->regback >= 0)) ) {
+ if (stringarg == strbeg && screamer) {
+ if (screamfirst[prog->regmust->str_rare] >= 0)
+ s = screaminstr(screamer,prog->regmust);
+ else
+ s = Nullch;
+ }
+#ifndef lint
+ else
+ s = fbminstr((unsigned char*)s, (unsigned char*)strend,
+ prog->regmust);
+#endif
+ if (!s) {
+ ++prog->regmust->str_u.str_useful; /* hooray */
+ goto phooey; /* not present */
+ }
+ else if (prog->regback >= 0) {
+ s -= prog->regback;
+ if (s < string)
+ s = string;
+ minlen = prog->regback + prog->regmust->str_cur;
+ }
+ else if (--prog->regmust->str_u.str_useful < 0) { /* boo */
+ str_free(prog->regmust);
+ prog->regmust = Nullstr; /* disable regmust */
+ s = string;
+ }
+ else {
+ s = string;
+ minlen = prog->regmust->str_cur;
+ }
+ }
+
+ /* Mark beginning of line for ^ . */
+ regbol = string;
+
+ /* Mark end of line for $ (and such) */
+ regeol = strend;
+
+ /* see how far we have to get to not match where we matched before */
+ regtill = string+minend;
+
+ /* Allocate our backreference arrays */
+ if ( regmyp_size < prog->nparens + 1 ) {
+ /* Allocate or enlarge the arrays */
+ regmyp_size = prog->nparens + 1;
+ if ( regmyp_size < 10 ) regmyp_size = 10; /* minimum */
+ if ( regmystartp ) {
+ /* reallocate larger */
+ Renew(regmystartp,regmyp_size,char*);
+ Renew(regmyendp, regmyp_size,char*);
+ }
+ else {
+ /* Initial allocation */
+ New(1102,regmystartp,regmyp_size,char*);
+ New(1102,regmyendp, regmyp_size,char*);
+ }
+
+ }
+
+ /* Simplest case: anchored match need be tried only once. */
+ /* [unless multiline is set] */
+ if (prog->reganch & ROPT_ANCH) {
+ if (regtry(prog, string))
+ goto got_it;
+ else if (multiline || (prog->reganch & ROPT_IMPLICIT)) {
+ if (minlen)
+ dontbother = minlen - 1;
+ strend -= dontbother;
+ /* for multiline we only have to try after newlines */
+ if (s > string)
+ s--;
+ while (s < strend) {
+ if (*s++ == '\n') {
+ if (s < strend && regtry(prog, s))
+ goto got_it;
+ }
+ }
+ }
+ goto phooey;
+ }
+
+ /* Messy cases: unanchored match. */
+ if (prog->regstart) {
+ if (prog->reganch & ROPT_SKIP) { /* we have /x+whatever/ */
+ /* it must be a one character string */
+ i = prog->regstart->str_ptr[0];
+ while (s < strend) {
+ if (*s == i) {
+ if (regtry(prog, s))
+ goto got_it;
+ s++;
+ while (s < strend && *s == i)
+ s++;
+ }
+ s++;
+ }
+ }
+ else if (prog->regstart->str_pok == 3) {
+ /* We know what string it must start with. */
+#ifndef lint
+ while ((s = fbminstr((unsigned char*)s,
+ (unsigned char*)strend, prog->regstart)) != NULL)
+#else
+ while (s = Nullch)
+#endif
+ {
+ if (regtry(prog, s))
+ goto got_it;
+ s++;
+ }
+ }
+ else {
+ c = prog->regstart->str_ptr;
+ while ((s = ninstr(s, strend,
+ c, c + prog->regstart->str_cur )) != NULL) {
+ if (regtry(prog, s))
+ goto got_it;
+ s++;
+ }
+ }
+ goto phooey;
+ }
+ /*SUPPRESS 560*/
+ if (c = prog->regstclass) {
+ int doevery = (prog->reganch & ROPT_SKIP) == 0;
+
+ if (minlen)
+ dontbother = minlen - 1;
+ strend -= dontbother; /* don't bother with what can't match */
+ tmp = 1;
+ /* We know what class it must start with. */
+ switch (OP(c)) {
+ case ANYOF:
+ c = OPERAND(c);
+ while (s < strend) {
+ i = UCHARAT(s);
+ if (!(c[i >> 3] & (1 << (i&7)))) {
+ if (tmp && regtry(prog, s))
+ goto got_it;
+ else
+ tmp = doevery;
+ }
+ else
+ tmp = 1;
+ s++;
+ }
+ break;
+ case BOUND:
+ if (minlen)
+ dontbother++,strend--;
+ if (s != string) {
+ i = s[-1];
+ tmp = isALNUM(i);
+ }
+ else
+ tmp = isALNUM(regprev); /* assume not alphanumeric */
+ while (s < strend) {
+ i = *s;
+ if (tmp != isALNUM(i)) {
+ tmp = !tmp;
+ if (regtry(prog, s))
+ goto got_it;
+ }
+ s++;
+ }
+ if ((minlen || tmp) && regtry(prog,s))
+ goto got_it;
+ break;
+ case NBOUND:
+ if (minlen)
+ dontbother++,strend--;
+ if (s != string) {
+ i = s[-1];
+ tmp = isALNUM(i);
+ }
+ else
+ tmp = isALNUM(regprev); /* assume not alphanumeric */
+ while (s < strend) {
+ i = *s;
+ if (tmp != isALNUM(i))
+ tmp = !tmp;
+ else if (regtry(prog, s))
+ goto got_it;
+ s++;
+ }
+ if ((minlen || !tmp) && regtry(prog,s))
+ goto got_it;
+ break;
+ case ALNUM:
+ while (s < strend) {
+ i = *s;
+ if (isALNUM(i)) {
+ if (tmp && regtry(prog, s))
+ goto got_it;
+ else
+ tmp = doevery;
+ }
+ else
+ tmp = 1;
+ s++;
+ }
+ break;
+ case NALNUM:
+ while (s < strend) {
+ i = *s;
+ if (!isALNUM(i)) {
+ if (tmp && regtry(prog, s))
+ goto got_it;
+ else
+ tmp = doevery;
+ }
+ else
+ tmp = 1;
+ s++;
+ }
+ break;
+ case SPACE:
+ while (s < strend) {
+ if (isSPACE(*s)) {
+ if (tmp && regtry(prog, s))
+ goto got_it;
+ else
+ tmp = doevery;
+ }
+ else
+ tmp = 1;
+ s++;
+ }
+ break;
+ case NSPACE:
+ while (s < strend) {
+ if (!isSPACE(*s)) {
+ if (tmp && regtry(prog, s))
+ goto got_it;
+ else
+ tmp = doevery;
+ }
+ else
+ tmp = 1;
+ s++;
+ }
+ break;
+ case DIGIT:
+ while (s < strend) {
+ if (isDIGIT(*s)) {
+ if (tmp && regtry(prog, s))
+ goto got_it;
+ else
+ tmp = doevery;
+ }
+ else
+ tmp = 1;
+ s++;
+ }
+ break;
+ case NDIGIT:
+ while (s < strend) {
+ if (!isDIGIT(*s)) {
+ if (tmp && regtry(prog, s))
+ goto got_it;
+ else
+ tmp = doevery;
+ }
+ else
+ tmp = 1;
+ s++;
+ }
+ break;
+ }
+ }
+ else {
+ if (minlen)
+ dontbother = minlen - 1;
+ strend -= dontbother;
+ /* We don't know much -- general case. */
+ do {
+ if (regtry(prog, s))
+ goto got_it;
+ } while (s++ < strend);
+ }
+
+ /* Failure. */
+ goto phooey;
+
+ got_it:
+ prog->subbeg = strbeg;
+ prog->subend = strend;
+ if ((!safebase && (prog->nparens || sawampersand)) || prog->do_folding){
+ strend += dontbother; /* uncheat */
+ if (safebase) /* no need for $digit later */
+ s = strbeg;
+ else if (strbeg != prog->subbase) {
+ i = strend - string + (stringarg - strbeg);
+ s = nsavestr(strbeg,i); /* so $digit will work later */
+ if (prog->subbase)
+ Safefree(prog->subbase);
+ prog->subbeg = prog->subbase = s;
+ prog->subend = s+i;
+ }
+ else {
+ i = strend - string + (stringarg - strbeg);
+ prog->subbeg = s = prog->subbase;
+ prog->subend = s+i;
+ }
+ s += (stringarg - strbeg);
+ for (i = 0; i <= prog->nparens; i++) {
+ if (prog->endp[i]) {
+ prog->startp[i] = s + (prog->startp[i] - string);
+ prog->endp[i] = s + (prog->endp[i] - string);
+ }
+ }
+ if (prog->do_folding)
+ Safefree(string);
+ }
+ return(1);
+
+ phooey:
+ if (prog->do_folding)
+ Safefree(string);
+ return(0);
+}
+
+/*
+ - regtry - try match at specific point
+ */
+static int /* 0 failure, 1 success */
+regtry(prog, string)
+regexp *prog;
+char *string;
+{
+ register int i;
+ register char **sp;
+ register char **ep;
+
+ reginput = string;
+ regstartp = prog->startp;
+ regendp = prog->endp;
+ reglastparen = &prog->lastparen;
+ prog->lastparen = 0;
+
+ sp = prog->startp;
+ ep = prog->endp;
+ if (prog->nparens) {
+ for (i = prog->nparens; i >= 0; i--) {
+ *sp++ = NULL;
+ *ep++ = NULL;
+ }
+ }
+ if (regmatch(prog->program + 1) && reginput >= regtill) {
+ prog->startp[0] = string;
+ prog->endp[0] = reginput;
+ return(1);
+ } else
+ return(0);
+}
+
+/*
+ - regmatch - main matching routine
+ *
+ * Conceptually the strategy is simple: check to see whether the current
+ * node matches, call self recursively to see whether the rest matches,
+ * and then act accordingly. In practice we make some effort to avoid
+ * recursion, in particular by going through "ordinary" nodes (that don't
+ * need to know whether the rest of the match failed) by a loop instead of
+ * by recursion.
+ */
+/* [lwall] I've hoisted the register declarations to the outer block in order to
+ * maybe save a little bit of pushing and popping on the stack. It also takes
+ * advantage of machines that use a register save mask on subroutine entry.
+ */
+static int /* 0 failure, 1 success */
+regmatch(prog)
+char *prog;
+{
+ register char *scan; /* Current node. */
+ char *next; /* Next node. */
+ register int nextchar;
+ register int n; /* no or next */
+ register int ln; /* len or last */
+ register char *s; /* operand or save */
+ register char *locinput = reginput;
+
+ nextchar = *locinput;
+ scan = prog;
+#ifdef DEBUGGING
+ if (scan != NULL && regnarrate)
+ fprintf(stderr, "%s(\n", regprop(scan));
+#endif
+ while (scan != NULL) {
+#ifdef DEBUGGING
+ if (regnarrate)
+ fprintf(stderr, "%s...\n", regprop(scan));
+#endif
+
+#ifdef REGALIGN
+ next = scan + NEXT(scan);
+ if (next == scan)
+ next = NULL;
+#else
+ next = regnext(scan);
+#endif
+
+ switch (OP(scan)) {
+ case BOL:
+ if (locinput == regbol ? regprev == '\n' :
+ ((nextchar || locinput < regeol) &&
+ locinput[-1] == '\n') )
+ {
+ /* regtill = regbol; */
+ break;
+ }
+ return(0);
+ case EOL:
+ if ((nextchar || locinput < regeol) && nextchar != '\n')
+ return(0);
+ if (!multiline && regeol - locinput > 1)
+ return 0;
+ /* regtill = regbol; */
+ break;
+ case ANY:
+ if ((nextchar == '\0' && locinput >= regeol) ||
+ nextchar == '\n')
+ return(0);
+ nextchar = *++locinput;
+ break;
+ case EXACTLY:
+ s = OPERAND(scan);
+ ln = *s++;
+ /* Inline the first character, for speed. */
+ if (*s != nextchar)
+ return(0);
+ if (regeol - locinput < ln)
+ return 0;
+ if (ln > 1 && bcmp(s, locinput, ln) != 0)
+ return(0);
+ locinput += ln;
+ nextchar = *locinput;
+ break;
+ case ANYOF:
+ s = OPERAND(scan);
+ if (nextchar < 0)
+ nextchar = UCHARAT(locinput);
+ if (s[nextchar >> 3] & (1 << (nextchar&7)))
+ return(0);
+ if (!nextchar && locinput >= regeol)
+ return 0;
+ nextchar = *++locinput;
+ break;
+ case ALNUM:
+ if (!nextchar)
+ return(0);
+ if (!isALNUM(nextchar))
+ return(0);
+ nextchar = *++locinput;
+ break;
+ case NALNUM:
+ if (!nextchar && locinput >= regeol)
+ return(0);
+ if (isALNUM(nextchar))
+ return(0);
+ nextchar = *++locinput;
+ break;
+ case NBOUND:
+ case BOUND:
+ if (locinput == regbol) /* was last char in word? */
+ ln = isALNUM(regprev);
+ else
+ ln = isALNUM(locinput[-1]);
+ n = isALNUM(nextchar); /* is next char in word? */
+ if ((ln == n) == (OP(scan) == BOUND))
+ return(0);
+ break;
+ case SPACE:
+ if (!nextchar && locinput >= regeol)
+ return(0);
+ if (!isSPACE(nextchar))
+ return(0);
+ nextchar = *++locinput;
+ break;
+ case NSPACE:
+ if (!nextchar)
+ return(0);
+ if (isSPACE(nextchar))
+ return(0);
+ nextchar = *++locinput;
+ break;
+ case DIGIT:
+ if (!isDIGIT(nextchar))
+ return(0);
+ nextchar = *++locinput;
+ break;
+ case NDIGIT:
+ if (!nextchar && locinput >= regeol)
+ return(0);
+ if (isDIGIT(nextchar))
+ return(0);
+ nextchar = *++locinput;
+ break;
+ case REF:
+ n = ARG1(scan); /* which paren pair */
+ s = regmystartp[n];
+ if (!s)
+ return(0);
+ if (!regmyendp[n])
+ return(0);
+ if (s == regmyendp[n])
+ break;
+ /* Inline the first character, for speed. */
+ if (*s != nextchar)
+ return(0);
+ ln = regmyendp[n] - s;
+ if (locinput + ln > regeol)
+ return 0;
+ if (ln > 1 && bcmp(s, locinput, ln) != 0)
+ return(0);
+ locinput += ln;
+ nextchar = *locinput;
+ break;
+
+ case NOTHING:
+ break;
+ case BACK:
+ break;
+ case OPEN:
+ n = ARG1(scan); /* which paren pair */
+ reginput = locinput;
+
+ regmystartp[n] = locinput; /* for REF */
+ if (regmatch(next)) {
+ /*
+ * Don't set startp if some later
+ * invocation of the same parentheses
+ * already has.
+ */
+ if (regstartp[n] == NULL)
+ regstartp[n] = locinput;
+ return(1);
+ } else
+ return(0);
+ /* NOTREACHED */
+ case CLOSE: {
+ n = ARG1(scan); /* which paren pair */
+ reginput = locinput;
+
+ regmyendp[n] = locinput; /* for REF */
+ if (regmatch(next)) {
+ /*
+ * Don't set endp if some later
+ * invocation of the same parentheses
+ * already has.
+ */
+ if (regendp[n] == NULL) {
+ regendp[n] = locinput;
+ if (n > *reglastparen)
+ *reglastparen = n;
+ }
+ return(1);
+ } else
+ return(0);
+ }
+ /*NOTREACHED*/
+ case BRANCH: {
+ if (OP(next) != BRANCH) /* No choice. */
+ next = NEXTOPER(scan); /* Avoid recursion. */
+ else {
+ do {
+ reginput = locinput;
+ if (regmatch(NEXTOPER(scan)))
+ return(1);
+#ifdef REGALIGN
+ /*SUPPRESS 560*/
+ if (n = NEXT(scan))
+ scan += n;
+ else
+ scan = NULL;
+#else
+ scan = regnext(scan);
+#endif
+ } while (scan != NULL && OP(scan) == BRANCH);
+ return(0);
+ /* NOTREACHED */
+ }
+ }
+ break;
+ case CURLY:
+ ln = ARG1(scan); /* min to match */
+ n = ARG2(scan); /* max to match */
+ scan = NEXTOPER(scan) + 4;
+ goto repeat;
+ case STAR:
+ ln = 0;
+ n = 32767;
+ scan = NEXTOPER(scan);
+ goto repeat;
+ case PLUS:
+ /*
+ * Lookahead to avoid useless match attempts
+ * when we know what character comes next.
+ */
+ ln = 1;
+ n = 32767;
+ scan = NEXTOPER(scan);
+ repeat:
+ if (OP(next) == EXACTLY)
+ nextchar = *(OPERAND(next)+1);
+ else
+ nextchar = -1000;
+ reginput = locinput;
+ n = regrepeat(scan, n);
+ if (!multiline && OP(next) == EOL && ln < n)
+ ln = n; /* why back off? */
+ while (n >= ln) {
+ /* If it could work, try it. */
+ if (nextchar == -1000 || *reginput == nextchar)
+ if (regmatch(next))
+ return(1);
+ /* Couldn't or didn't -- back up. */
+ n--;
+ reginput = locinput + n;
+ }
+ return(0);
+ case END:
+ reginput = locinput; /* put where regtry can find it */
+ return(1); /* Success! */
+ default:
+ printf("%x %d\n",scan,scan[1]);
+ FAIL("regexp memory corruption");
+ }
+
+ scan = next;
+ }
+
+ /*
+ * We get here only if there's trouble -- normally "case END" is
+ * the terminating point.
+ */
+ FAIL("corrupted regexp pointers");
+ /*NOTREACHED*/
+#ifdef lint
+ return 0;
+#endif
+}
+
+/*
+ - regrepeat - repeatedly match something simple, report how many
+ */
+/*
+ * [This routine now assumes that it will only match on things of length 1.
+ * That was true before, but now we assume scan - reginput is the count,
+ * rather than incrementing count on every character.]
+ */
+static int
+regrepeat(p, max)
+char *p;
+int max;
+{
+ register char *scan;
+ register char *opnd;
+ register int c;
+ register char *loceol = regeol;
+
+ scan = reginput;
+ if (max != 32767 && max < loceol - scan)
+ loceol = scan + max;
+ opnd = OPERAND(p);
+ switch (OP(p)) {
+ case ANY:
+ while (scan < loceol && *scan != '\n')
+ scan++;
+ break;
+ case EXACTLY: /* length of string is 1 */
+ opnd++;
+ while (scan < loceol && *opnd == *scan)
+ scan++;
+ break;
+ case ANYOF:
+ c = UCHARAT(scan);
+ while (scan < loceol && !(opnd[c >> 3] & (1 << (c & 7)))) {
+ scan++;
+ c = UCHARAT(scan);
+ }
+ break;
+ case ALNUM:
+ while (scan < loceol && isALNUM(*scan))
+ scan++;
+ break;
+ case NALNUM:
+ while (scan < loceol && !isALNUM(*scan))
+ scan++;
+ break;
+ case SPACE:
+ while (scan < loceol && isSPACE(*scan))
+ scan++;
+ break;
+ case NSPACE:
+ while (scan < loceol && !isSPACE(*scan))
+ scan++;
+ break;
+ case DIGIT:
+ while (scan < loceol && isDIGIT(*scan))
+ scan++;
+ break;
+ case NDIGIT:
+ while (scan < loceol && !isDIGIT(*scan))
+ scan++;
+ break;
+ default: /* Oh dear. Called inappropriately. */
+ FAIL("internal regexp foulup");
+ /* NOTREACHED */
+ }
+
+ c = scan - reginput;
+ reginput = scan;
+
+ return(c);
+}
+
+/*
+ - regnext - dig the "next" pointer out of a node
+ *
+ * [Note, when REGALIGN is defined there are two places in regmatch()
+ * that bypass this code for speed.]
+ */
+char *
+regnext(p)
+register char *p;
+{
+ register int offset;
+
+ if (p == &regdummy)
+ return(NULL);
+
+ offset = NEXT(p);
+ if (offset == 0)
+ return(NULL);
+
+#ifdef REGALIGN
+ return(p+offset);
+#else
+ if (OP(p) == BACK)
+ return(p-offset);
+ else
+ return(p+offset);
+#endif
+}
diff --git a/gnu/usr.bin/perl/perl/regexp.h b/gnu/usr.bin/perl/perl/regexp.h
new file mode 100644
index 0000000..634b19b
--- /dev/null
+++ b/gnu/usr.bin/perl/perl/regexp.h
@@ -0,0 +1,56 @@
+/*
+ * Definitions etc. for regexp(3) routines.
+ *
+ * Caveat: this is V8 regexp(3) [actually, a reimplementation thereof],
+ * not the System V one.
+ */
+
+/* $RCSfile: regexp.h,v $$Revision: 1.1.1.1 $$Date: 1994/09/10 06:27:35 $
+ *
+ * $Log: regexp.h,v $
+ * Revision 1.1.1.1 1994/09/10 06:27:35 gclarkii
+ * Initial import of Perl 4.046 bmaked
+ *
+ * Revision 1.1.1.1 1993/08/23 21:29:39 nate
+ * PERL!
+ *
+ * Revision 4.0.1.2 91/11/05 18:24:31 lwall
+ * patch11: minimum match length calculation in regexp is now cumulative
+ * patch11: initial .* in pattern had dependency on value of $*
+ *
+ * Revision 4.0.1.1 91/06/07 11:51:18 lwall
+ * patch4: new copyright notice
+ * patch4: // wouldn't use previous pattern if it started with a null character
+ * patch4: $` was busted inside s///
+ *
+ * Revision 4.0 91/03/20 01:39:23 lwall
+ * 4.0 baseline.
+ *
+ */
+
+typedef struct regexp {
+ char **startp;
+ char **endp;
+ STR *regstart; /* Internal use only. */
+ char *regstclass;
+ STR *regmust; /* Internal use only. */
+ int regback; /* Can regmust locate first try? */
+ int minlen; /* mininum possible length of $& */
+ int prelen; /* length of precomp */
+ char *precomp; /* pre-compilation regular expression */
+ char *subbase; /* saved string so \digit works forever */
+ char *subbeg; /* same, but not responsible for allocation */
+ char *subend; /* end of subbase */
+ char reganch; /* Internal use only. */
+ char do_folding; /* do case-insensitive match? */
+ char lastparen; /* last paren matched */
+ char nparens; /* number of parentheses */
+ char program[1]; /* Unwarranted chumminess with compiler. */
+} regexp;
+
+#define ROPT_ANCH 1
+#define ROPT_SKIP 2
+#define ROPT_IMPLICIT 4
+
+regexp *regcomp();
+int regexec();
diff --git a/gnu/usr.bin/perl/perl/spat.h b/gnu/usr.bin/perl/perl/spat.h
new file mode 100644
index 0000000..7c392b0
--- /dev/null
+++ b/gnu/usr.bin/perl/perl/spat.h
@@ -0,0 +1,49 @@
+/* $RCSfile: spat.h,v $$Revision: 1.1.1.1 $$Date: 1994/09/10 06:27:35 $
+ *
+ * Copyright (c) 1991, Larry Wall
+ *
+ * You may distribute under the terms of either the GNU General Public
+ * License or the Artistic License, as specified in the README file.
+ *
+ * $Log: spat.h,v $
+ * Revision 1.1.1.1 1994/09/10 06:27:35 gclarkii
+ * Initial import of Perl 4.046 bmaked
+ *
+ * Revision 1.1.1.1 1993/08/23 21:29:39 nate
+ * PERL!
+ *
+ * Revision 4.0.1.1 91/06/07 11:51:59 lwall
+ * patch4: new copyright notice
+ * patch4: added global modifier for pattern matches
+ *
+ * Revision 4.0 91/03/20 01:39:36 lwall
+ * 4.0 baseline.
+ *
+ */
+
+struct scanpat {
+ SPAT *spat_next; /* list of all scanpats */
+ REGEXP *spat_regexp; /* compiled expression */
+ ARG *spat_repl; /* replacement string for subst */
+ ARG *spat_runtime; /* compile pattern at runtime */
+ STR *spat_short; /* for a fast bypass of execute() */
+ short spat_flags;
+ char spat_slen;
+};
+
+#define SPAT_USED 1 /* spat has been used once already */
+#define SPAT_ONCE 2 /* use pattern only once per reset */
+#define SPAT_SCANFIRST 4 /* initial constant not anchored */
+#define SPAT_ALL 8 /* initial constant is whole pat */
+#define SPAT_SKIPWHITE 16 /* skip leading whitespace for split */
+#define SPAT_FOLD 32 /* case insensitivity */
+#define SPAT_CONST 64 /* subst replacement is constant */
+#define SPAT_KEEP 128 /* keep 1st runtime pattern forever */
+#define SPAT_GLOBAL 256 /* pattern had a g modifier */
+
+EXT SPAT *curspat; /* what to do \ interps from */
+EXT SPAT *lastspat; /* what to use in place of null pattern */
+
+EXT char *hint INIT(Nullch); /* hint from cmd_exec to do_match et al */
+
+#define Nullspat Null(SPAT*)
diff --git a/gnu/usr.bin/perl/perl/stab.c b/gnu/usr.bin/perl/perl/stab.c
new file mode 100644
index 0000000..e34aa94
--- /dev/null
+++ b/gnu/usr.bin/perl/perl/stab.c
@@ -0,0 +1,1058 @@
+/* $RCSfile: stab.c,v $$Revision: 1.1.1.1 $$Date: 1994/09/10 06:27:33 $
+ *
+ * Copyright (c) 1991, Larry Wall
+ *
+ * You may distribute under the terms of either the GNU General Public
+ * License or the Artistic License, as specified in the README file.
+ *
+ * $Log: stab.c,v $
+ * Revision 1.1.1.1 1994/09/10 06:27:33 gclarkii
+ * Initial import of Perl 4.046 bmaked
+ *
+ * Revision 1.1.1.1 1993/08/23 21:29:39 nate
+ * PERL!
+ *
+ * Revision 4.0.1.5 1993/02/05 19:42:47 lwall
+ * patch36: length returned wrong value on certain semi-magical variables
+ *
+ * Revision 4.0.1.4 92/06/08 15:32:19 lwall
+ * patch20: fixed confusion between a *var's real name and its effective name
+ * patch20: the debugger now warns you on lines that can't set a breakpoint
+ * patch20: the debugger made perl forget the last pattern used by //
+ * patch20: paragraph mode now skips extra newlines automatically
+ * patch20: ($<,$>) = ... didn't work on some architectures
+ *
+ * Revision 4.0.1.3 91/11/05 18:35:33 lwall
+ * patch11: length($x) was sometimes wrong for numeric $x
+ * patch11: perl now issues warning if $SIG{'ALARM'} is referenced
+ * patch11: *foo = undef coredumped
+ * patch11: solitary subroutine references no longer trigger typo warnings
+ * patch11: local(*FILEHANDLE) had a memory leak
+ *
+ * Revision 4.0.1.2 91/06/07 11:55:53 lwall
+ * patch4: new copyright notice
+ * patch4: added $^P variable to control calling of perldb routines
+ * patch4: added $^F variable to specify maximum system fd, default 2
+ * patch4: $` was busted inside s///
+ * patch4: default top-of-form format is now FILEHANDLE_TOP
+ * patch4: length($`), length($&), length($') now optimized to avoid string copy
+ * patch4: $^D |= 1024 now does syntax tree dump at run-time
+ *
+ * Revision 4.0.1.1 91/04/12 09:10:24 lwall
+ * patch1: Configure now differentiates getgroups() type from getgid() type
+ * patch1: you may now use "die" and "caller" in a signal handler
+ *
+ * Revision 4.0 91/03/20 01:39:41 lwall
+ * 4.0 baseline.
+ *
+ */
+
+#include "EXTERN.h"
+#include "perl.h"
+
+#if !defined(NSIG) || defined(M_UNIX) || defined(M_XENIX)
+#include <signal.h>
+#endif
+
+static char *sig_name[] = {
+ SIG_NAME,0
+};
+
+#ifdef VOIDSIG
+#define handlertype void
+#else
+#define handlertype int
+#endif
+
+static handlertype sighandler();
+
+static int origalen = 0;
+
+STR *
+stab_str(str)
+STR *str;
+{
+ STAB *stab = str->str_u.str_stab;
+ register int paren;
+ register char *s;
+ register int i;
+
+ if (str->str_rare)
+ return stab_val(stab);
+
+ switch (*stab->str_magic->str_ptr) {
+ case '\004': /* ^D */
+#ifdef DEBUGGING
+ str_numset(stab_val(stab),(double)(debug & 32767));
+#endif
+ break;
+ case '\006': /* ^F */
+ str_numset(stab_val(stab),(double)maxsysfd);
+ break;
+ case '\t': /* ^I */
+ if (inplace)
+ str_set(stab_val(stab), inplace);
+ else
+ str_sset(stab_val(stab),&str_undef);
+ break;
+ case '\020': /* ^P */
+ str_numset(stab_val(stab),(double)perldb);
+ break;
+ case '\024': /* ^T */
+ str_numset(stab_val(stab),(double)basetime);
+ break;
+ case '\027': /* ^W */
+ str_numset(stab_val(stab),(double)dowarn);
+ break;
+ case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9': case '&':
+ if (curspat) {
+ paren = atoi(stab_ename(stab));
+ getparen:
+ if (curspat->spat_regexp &&
+ paren <= curspat->spat_regexp->nparens &&
+ (s = curspat->spat_regexp->startp[paren]) ) {
+ i = curspat->spat_regexp->endp[paren] - s;
+ if (i >= 0)
+ str_nset(stab_val(stab),s,i);
+ else
+ str_sset(stab_val(stab),&str_undef);
+ }
+ else
+ str_sset(stab_val(stab),&str_undef);
+ }
+ break;
+ case '+':
+ if (curspat) {
+ paren = curspat->spat_regexp->lastparen;
+ goto getparen;
+ }
+ break;
+ case '`':
+ if (curspat) {
+ if (curspat->spat_regexp &&
+ (s = curspat->spat_regexp->subbeg) ) {
+ i = curspat->spat_regexp->startp[0] - s;
+ if (i >= 0)
+ str_nset(stab_val(stab),s,i);
+ else
+ str_nset(stab_val(stab),"",0);
+ }
+ else
+ str_nset(stab_val(stab),"",0);
+ }
+ break;
+ case '\'':
+ if (curspat) {
+ if (curspat->spat_regexp &&
+ (s = curspat->spat_regexp->endp[0]) ) {
+ str_nset(stab_val(stab),s, curspat->spat_regexp->subend - s);
+ }
+ else
+ str_nset(stab_val(stab),"",0);
+ }
+ break;
+ case '.':
+#ifndef lint
+ if (last_in_stab && stab_io(last_in_stab)) {
+ str_numset(stab_val(stab),(double)stab_io(last_in_stab)->lines);
+ }
+#endif
+ break;
+ case '?':
+ str_numset(stab_val(stab),(double)statusvalue);
+ break;
+ case '^':
+ s = stab_io(curoutstab)->top_name;
+ if (s)
+ str_set(stab_val(stab),s);
+ else {
+ str_set(stab_val(stab),stab_ename(curoutstab));
+ str_cat(stab_val(stab),"_TOP");
+ }
+ break;
+ case '~':
+ s = stab_io(curoutstab)->fmt_name;
+ if (!s)
+ s = stab_ename(curoutstab);
+ str_set(stab_val(stab),s);
+ break;
+#ifndef lint
+ case '=':
+ str_numset(stab_val(stab),(double)stab_io(curoutstab)->page_len);
+ break;
+ case '-':
+ str_numset(stab_val(stab),(double)stab_io(curoutstab)->lines_left);
+ break;
+ case '%':
+ str_numset(stab_val(stab),(double)stab_io(curoutstab)->page);
+ break;
+#endif
+ case ':':
+ break;
+ case '/':
+ break;
+ case '[':
+ str_numset(stab_val(stab),(double)arybase);
+ break;
+ case '|':
+ if (!stab_io(curoutstab))
+ stab_io(curoutstab) = stio_new();
+ str_numset(stab_val(stab),
+ (double)((stab_io(curoutstab)->flags & IOF_FLUSH) != 0) );
+ break;
+ case ',':
+ str_nset(stab_val(stab),ofs,ofslen);
+ break;
+ case '\\':
+ str_nset(stab_val(stab),ors,orslen);
+ break;
+ case '#':
+ str_set(stab_val(stab),ofmt);
+ break;
+ case '!':
+ str_numset(stab_val(stab), (double)errno);
+ str_set(stab_val(stab), errno ? strerror(errno) : "");
+ stab_val(stab)->str_nok = 1; /* what a wonderful hack! */
+ break;
+ case '<':
+ str_numset(stab_val(stab),(double)uid);
+ break;
+ case '>':
+ str_numset(stab_val(stab),(double)euid);
+ break;
+ case '(':
+ s = buf;
+ (void)sprintf(s,"%d",(int)gid);
+ goto add_groups;
+ case ')':
+ s = buf;
+ (void)sprintf(s,"%d",(int)egid);
+ add_groups:
+ while (*s) s++;
+#ifdef HAS_GETGROUPS
+#ifndef NGROUPS
+#define NGROUPS 32
+#endif
+ {
+ GROUPSTYPE gary[NGROUPS];
+
+ i = getgroups(NGROUPS,gary);
+ while (--i >= 0) {
+ (void)sprintf(s," %ld", (long)gary[i]);
+ while (*s) s++;
+ }
+ }
+#endif
+ str_set(stab_val(stab),buf);
+ break;
+ case '*':
+ break;
+ case '0':
+ break;
+ default:
+ {
+ struct ufuncs *uf = (struct ufuncs *)str->str_ptr;
+
+ if (uf && uf->uf_val)
+ (*uf->uf_val)(uf->uf_index, stab_val(stab));
+ }
+ break;
+ }
+ return stab_val(stab);
+}
+
+STRLEN
+stab_len(str)
+STR *str;
+{
+ STAB *stab = str->str_u.str_stab;
+ int paren;
+ int i;
+ char *s;
+
+ if (str->str_rare)
+ return str_len(stab_val(stab));
+
+ switch (*stab->str_magic->str_ptr) {
+ case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9': case '&':
+ if (curspat) {
+ paren = atoi(stab_ename(stab));
+ getparen:
+ if (curspat->spat_regexp &&
+ paren <= curspat->spat_regexp->nparens &&
+ (s = curspat->spat_regexp->startp[paren]) ) {
+ i = curspat->spat_regexp->endp[paren] - s;
+ if (i >= 0)
+ return i;
+ else
+ return 0;
+ }
+ else
+ return 0;
+ }
+ break;
+ case '+':
+ if (curspat) {
+ paren = curspat->spat_regexp->lastparen;
+ goto getparen;
+ }
+ break;
+ case '`':
+ if (curspat) {
+ if (curspat->spat_regexp &&
+ (s = curspat->spat_regexp->subbeg) ) {
+ i = curspat->spat_regexp->startp[0] - s;
+ if (i >= 0)
+ return i;
+ else
+ return 0;
+ }
+ else
+ return 0;
+ }
+ break;
+ case '\'':
+ if (curspat) {
+ if (curspat->spat_regexp &&
+ (s = curspat->spat_regexp->endp[0]) ) {
+ return (STRLEN) (curspat->spat_regexp->subend - s);
+ }
+ else
+ return 0;
+ }
+ break;
+ case ',':
+ return (STRLEN)ofslen;
+ case '\\':
+ return (STRLEN)orslen;
+ }
+ return str_len(stab_str(str));
+}
+
+void
+stabset(mstr,str)
+register STR *mstr;
+STR *str;
+{
+ STAB *stab;
+ register char *s;
+ int i;
+
+ switch (mstr->str_rare) {
+ case 'E':
+ my_setenv(mstr->str_ptr,str_get(str));
+ /* And you'll never guess what the dog had */
+ /* in its mouth... */
+#ifdef TAINT
+ if (strEQ(mstr->str_ptr,"PATH")) {
+ char *strend = str->str_ptr + str->str_cur;
+
+ s = str->str_ptr;
+ while (s < strend) {
+ s = cpytill(tokenbuf,s,strend,':',&i);
+ s++;
+ if (*tokenbuf != '/'
+ || (stat(tokenbuf,&statbuf) && (statbuf.st_mode & 2)) )
+ str->str_tainted = 2;
+ }
+ }
+#endif
+ break;
+ case 'S':
+ s = str_get(str);
+ i = whichsig(mstr->str_ptr); /* ...no, a brick */
+ if (!i && (dowarn || strEQ(mstr->str_ptr,"ALARM")))
+ warn("No such signal: SIG%s", mstr->str_ptr);
+ if (strEQ(s,"IGNORE"))
+#ifndef lint
+ (void)signal(i,SIG_IGN);
+#else
+ ;
+#endif
+ else if (strEQ(s,"DEFAULT") || !*s)
+ (void)signal(i,SIG_DFL);
+ else {
+ (void)signal(i,sighandler);
+ if (!index(s,'\'')) {
+ sprintf(tokenbuf, "main'%s",s);
+ str_set(str,tokenbuf);
+ }
+ }
+ break;
+#ifdef SOME_DBM
+ case 'D':
+ stab = mstr->str_u.str_stab;
+ hdbmstore(stab_hash(stab),mstr->str_ptr,mstr->str_cur,str);
+ break;
+#endif
+ case 'L':
+ {
+ CMD *cmd;
+
+ stab = mstr->str_u.str_stab;
+ i = str_true(str);
+ str = afetch(stab_xarray(stab),atoi(mstr->str_ptr), FALSE);
+ if (str->str_magic && (cmd = str->str_magic->str_u.str_cmd)) {
+ cmd->c_flags &= ~CF_OPTIMIZE;
+ cmd->c_flags |= i? CFT_D1 : CFT_D0;
+ }
+ else
+ warn("Can't break at that line\n");
+ }
+ break;
+ case '#':
+ stab = mstr->str_u.str_stab;
+ afill(stab_array(stab), (int)str_gnum(str) - arybase);
+ break;
+ case 'X': /* merely a copy of a * string */
+ break;
+ case '*':
+ s = str->str_pok ? str_get(str) : "";
+ if (strNE(s,"StB") || str->str_cur != sizeof(STBP)) {
+ stab = mstr->str_u.str_stab;
+ if (!*s) {
+ STBP *stbp;
+
+ /*SUPPRESS 701*/
+ (void)savenostab(stab); /* schedule a free of this stab */
+ if (stab->str_len)
+ Safefree(stab->str_ptr);
+ Newz(601,stbp, 1, STBP);
+ stab->str_ptr = stbp;
+ stab->str_len = stab->str_cur = sizeof(STBP);
+ stab->str_pok = 1;
+ strcpy(stab_magic(stab),"StB");
+ stab_val(stab) = Str_new(70,0);
+ stab_line(stab) = curcmd->c_line;
+ stab_estab(stab) = stab;
+ }
+ else {
+ stab = stabent(s,TRUE);
+ if (!stab_xarray(stab))
+ aadd(stab);
+ if (!stab_xhash(stab))
+ hadd(stab);
+ if (!stab_io(stab))
+ stab_io(stab) = stio_new();
+ }
+ str_sset(str, (STR*) stab);
+ }
+ break;
+ case 's': {
+ struct lstring *lstr = (struct lstring*)str;
+ char *tmps;
+
+ mstr->str_rare = 0;
+ str->str_magic = Nullstr;
+ tmps = str_get(str);
+ str_insert(mstr,lstr->lstr_offset,lstr->lstr_len,
+ tmps,str->str_cur);
+ }
+ break;
+
+ case 'v':
+ do_vecset(mstr,str);
+ break;
+
+ case 0:
+ /*SUPPRESS 560*/
+ if (!(stab = mstr->str_u.str_stab))
+ break;
+ switch (*stab->str_magic->str_ptr) {
+ case '\004': /* ^D */
+#ifdef DEBUGGING
+ debug = (int)(str_gnum(str)) | 32768;
+ if (debug & 1024)
+ dump_all();
+#endif
+ break;
+ case '\006': /* ^F */
+ maxsysfd = (int)str_gnum(str);
+ break;
+ case '\t': /* ^I */
+ if (inplace)
+ Safefree(inplace);
+ if (str->str_pok || str->str_nok)
+ inplace = savestr(str_get(str));
+ else
+ inplace = Nullch;
+ break;
+ case '\020': /* ^P */
+ i = (int)str_gnum(str);
+ if (i != perldb) {
+ static SPAT *oldlastspat;
+
+ if (perldb)
+ oldlastspat = lastspat;
+ else
+ lastspat = oldlastspat;
+ }
+ perldb = i;
+ break;
+ case '\024': /* ^T */
+ basetime = (time_t)str_gnum(str);
+ break;
+ case '\027': /* ^W */
+ dowarn = (bool)str_gnum(str);
+ break;
+ case '.':
+ if (localizing)
+ savesptr((STR**)&last_in_stab);
+ break;
+ case '^':
+ Safefree(stab_io(curoutstab)->top_name);
+ stab_io(curoutstab)->top_name = s = savestr(str_get(str));
+ stab_io(curoutstab)->top_stab = stabent(s,TRUE);
+ break;
+ case '~':
+ Safefree(stab_io(curoutstab)->fmt_name);
+ stab_io(curoutstab)->fmt_name = s = savestr(str_get(str));
+ stab_io(curoutstab)->fmt_stab = stabent(s,TRUE);
+ break;
+ case '=':
+ stab_io(curoutstab)->page_len = (long)str_gnum(str);
+ break;
+ case '-':
+ stab_io(curoutstab)->lines_left = (long)str_gnum(str);
+ if (stab_io(curoutstab)->lines_left < 0L)
+ stab_io(curoutstab)->lines_left = 0L;
+ break;
+ case '%':
+ stab_io(curoutstab)->page = (long)str_gnum(str);
+ break;
+ case '|':
+ if (!stab_io(curoutstab))
+ stab_io(curoutstab) = stio_new();
+ stab_io(curoutstab)->flags &= ~IOF_FLUSH;
+ if (str_gnum(str) != 0.0) {
+ stab_io(curoutstab)->flags |= IOF_FLUSH;
+ }
+ break;
+ case '*':
+ i = (int)str_gnum(str);
+ multiline = (i != 0);
+ break;
+ case '/':
+ if (str->str_pok) {
+ rs = str_get(str);
+ rslen = str->str_cur;
+ if (rspara = !rslen) {
+ rs = "\n\n";
+ rslen = 2;
+ }
+ rschar = rs[rslen - 1];
+ }
+ else {
+ rschar = 0777; /* fake a non-existent char */
+ rslen = 1;
+ }
+ break;
+ case '\\':
+ if (ors)
+ Safefree(ors);
+ ors = savestr(str_get(str));
+ orslen = str->str_cur;
+ break;
+ case ',':
+ if (ofs)
+ Safefree(ofs);
+ ofs = savestr(str_get(str));
+ ofslen = str->str_cur;
+ break;
+ case '#':
+ if (ofmt)
+ Safefree(ofmt);
+ ofmt = savestr(str_get(str));
+ break;
+ case '[':
+ arybase = (int)str_gnum(str);
+ break;
+ case '?':
+ statusvalue = U_S(str_gnum(str));
+ break;
+ case '!':
+ errno = (int)str_gnum(str); /* will anyone ever use this? */
+ break;
+ case '<':
+ uid = (int)str_gnum(str);
+ if (delaymagic) {
+ delaymagic |= DM_RUID;
+ break; /* don't do magic till later */
+ }
+#ifdef HAS_SETRUID
+ (void)setruid((UIDTYPE)uid);
+#else
+#ifdef HAS_SETREUID
+ (void)setreuid((UIDTYPE)uid, (UIDTYPE)-1);
+#else
+ if (uid == euid) /* special case $< = $> */
+ (void)setuid(uid);
+ else
+ fatal("setruid() not implemented");
+#endif
+#endif
+ uid = (int)getuid();
+ break;
+ case '>':
+ euid = (int)str_gnum(str);
+ if (delaymagic) {
+ delaymagic |= DM_EUID;
+ break; /* don't do magic till later */
+ }
+#ifdef HAS_SETEUID
+ (void)seteuid((UIDTYPE)euid);
+#else
+#ifdef HAS_SETREUID
+ (void)setreuid((UIDTYPE)-1, (UIDTYPE)euid);
+#else
+ if (euid == uid) /* special case $> = $< */
+ setuid(euid);
+ else
+ fatal("seteuid() not implemented");
+#endif
+#endif
+ euid = (int)geteuid();
+ break;
+ case '(':
+ gid = (int)str_gnum(str);
+ if (delaymagic) {
+ delaymagic |= DM_RGID;
+ break; /* don't do magic till later */
+ }
+#ifdef HAS_SETRGID
+ (void)setrgid((GIDTYPE)gid);
+#else
+#ifdef HAS_SETREGID
+ (void)setregid((GIDTYPE)gid, (GIDTYPE)-1);
+#else
+ if (gid == egid) /* special case $( = $) */
+ (void)setgid(gid);
+ else
+ fatal("setrgid() not implemented");
+#endif
+#endif
+ gid = (int)getgid();
+ break;
+ case ')':
+ egid = (int)str_gnum(str);
+ if (delaymagic) {
+ delaymagic |= DM_EGID;
+ break; /* don't do magic till later */
+ }
+#ifdef HAS_SETEGID
+ (void)setegid((GIDTYPE)egid);
+#else
+#ifdef HAS_SETREGID
+ (void)setregid((GIDTYPE)-1, (GIDTYPE)egid);
+#else
+ if (egid == gid) /* special case $) = $( */
+ (void)setgid(egid);
+ else
+ fatal("setegid() not implemented");
+#endif
+#endif
+ egid = (int)getegid();
+ break;
+ case ':':
+ chopset = str_get(str);
+ break;
+ case '0':
+ if (!origalen) {
+ s = origargv[0];
+ s += strlen(s);
+ /* See if all the arguments are contiguous in memory */
+ for (i = 1; i < origargc; i++) {
+ if (origargv[i] == s + 1)
+ s += strlen(++s); /* this one is ok too */
+ }
+ if (origenviron[0] == s + 1) { /* can grab env area too? */
+ my_setenv("NoNeSuCh", Nullch);
+ /* force copy of environment */
+ for (i = 0; origenviron[i]; i++)
+ if (origenviron[i] == s + 1)
+ s += strlen(++s);
+ }
+ origalen = s - origargv[0];
+ }
+ s = str_get(str);
+ i = str->str_cur;
+ if (i >= origalen) {
+ i = origalen;
+ str->str_cur = i;
+ str->str_ptr[i] = '\0';
+ Copy(s, origargv[0], i, char);
+ }
+ else {
+ Copy(s, origargv[0], i, char);
+ s = origargv[0]+i;
+ *s++ = '\0';
+ while (++i < origalen)
+ *s++ = ' ';
+ }
+ break;
+ default:
+ {
+ struct ufuncs *uf = (struct ufuncs *)str->str_magic->str_ptr;
+
+ if (uf && uf->uf_set)
+ (*uf->uf_set)(uf->uf_index, str);
+ }
+ break;
+ }
+ break;
+ }
+}
+
+int
+whichsig(sig)
+char *sig;
+{
+ register char **sigv;
+
+ for (sigv = sig_name+1; *sigv; sigv++)
+ if (strEQ(sig,*sigv))
+ return sigv - sig_name;
+#ifdef SIGCLD
+ if (strEQ(sig,"CHLD"))
+ return SIGCLD;
+#endif
+#ifdef SIGCHLD
+ if (strEQ(sig,"CLD"))
+ return SIGCHLD;
+#endif
+ return 0;
+}
+
+static handlertype
+sighandler(sig)
+int sig;
+{
+ STAB *stab;
+ STR *str;
+ int oldsave = savestack->ary_fill;
+ int oldtmps_base = tmps_base;
+ register CSV *csv;
+ SUBR *sub;
+
+#ifdef OS2 /* or anybody else who requires SIG_ACK */
+ signal(sig, SIG_ACK);
+#endif
+ stab = stabent(
+ str_get(hfetch(stab_hash(sigstab),sig_name[sig],strlen(sig_name[sig]),
+ TRUE)), TRUE);
+ sub = stab_sub(stab);
+ if (!sub && *sig_name[sig] == 'C' && instr(sig_name[sig],"LD")) {
+ if (sig_name[sig][1] == 'H')
+ stab = stabent(str_get(hfetch(stab_hash(sigstab),"CLD",3,TRUE)),
+ TRUE);
+ else
+ stab = stabent(str_get(hfetch(stab_hash(sigstab),"CHLD",4,TRUE)),
+ TRUE);
+ sub = stab_sub(stab); /* gag */
+ }
+ if (!sub) {
+ if (dowarn)
+ warn("SIG%s handler \"%s\" not defined.\n",
+ sig_name[sig], stab_ename(stab) );
+ return;
+ }
+ /*SUPPRESS 701*/
+ saveaptr(&stack);
+ str = Str_new(15, sizeof(CSV));
+ str->str_state = SS_SCSV;
+ (void)apush(savestack,str);
+ csv = (CSV*)str->str_ptr;
+ csv->sub = sub;
+ csv->stab = stab;
+ csv->curcsv = curcsv;
+ csv->curcmd = curcmd;
+ csv->depth = sub->depth;
+ csv->wantarray = G_SCALAR;
+ csv->hasargs = TRUE;
+ csv->savearray = stab_xarray(defstab);
+ csv->argarray = stab_xarray(defstab) = stack = anew(defstab);
+ stack->ary_flags = 0;
+ curcsv = csv;
+ str = str_mortal(&str_undef);
+ str_set(str,sig_name[sig]);
+ (void)apush(stab_xarray(defstab),str);
+ sub->depth++;
+ if (sub->depth >= 2) { /* save temporaries on recursion? */
+ if (sub->depth == 100 && dowarn)
+ warn("Deep recursion on subroutine \"%s\"",stab_ename(stab));
+ savelist(sub->tosave->ary_array,sub->tosave->ary_fill);
+ }
+
+ tmps_base = tmps_max; /* protect our mortal string */
+ (void)cmd_exec(sub->cmd,G_SCALAR,0); /* so do it already */
+ tmps_base = oldtmps_base;
+
+ restorelist(oldsave); /* put everything back */
+}
+
+STAB *
+aadd(stab)
+register STAB *stab;
+{
+ if (!stab_xarray(stab))
+ stab_xarray(stab) = anew(stab);
+ return stab;
+}
+
+STAB *
+hadd(stab)
+register STAB *stab;
+{
+ if (!stab_xhash(stab))
+ stab_xhash(stab) = hnew(COEFFSIZE);
+ return stab;
+}
+
+STAB *
+fstab(name)
+char *name;
+{
+ char tmpbuf[1200];
+ STAB *stab;
+
+ sprintf(tmpbuf,"'_<%s", name);
+ stab = stabent(tmpbuf, TRUE);
+ str_set(stab_val(stab), name);
+ if (perldb)
+ (void)hadd(aadd(stab));
+ return stab;
+}
+
+STAB *
+stabent(name,add)
+register char *name;
+int add;
+{
+ register STAB *stab;
+ register STBP *stbp;
+ int len;
+ register char *namend;
+ HASH *stash;
+ char *sawquote = Nullch;
+ char *prevquote = Nullch;
+ bool global = FALSE;
+
+ if (isUPPER(*name)) {
+ if (*name > 'I') {
+ if (*name == 'S' && (
+ strEQ(name, "SIG") ||
+ strEQ(name, "STDIN") ||
+ strEQ(name, "STDOUT") ||
+ strEQ(name, "STDERR") ))
+ global = TRUE;
+ }
+ else if (*name > 'E') {
+ if (*name == 'I' && strEQ(name, "INC"))
+ global = TRUE;
+ }
+ else if (*name > 'A') {
+ if (*name == 'E' && strEQ(name, "ENV"))
+ global = TRUE;
+ }
+ else if (*name == 'A' && (
+ strEQ(name, "ARGV") ||
+ strEQ(name, "ARGVOUT") ))
+ global = TRUE;
+ }
+ for (namend = name; *namend; namend++) {
+ if (*namend == '\'' && namend[1])
+ prevquote = sawquote, sawquote = namend;
+ }
+ if (sawquote == name && name[1]) {
+ stash = defstash;
+ sawquote = Nullch;
+ name++;
+ }
+ else if (!isALPHA(*name) || global)
+ stash = defstash;
+ else if ((CMD*)curcmd == &compiling)
+ stash = curstash;
+ else
+ stash = curcmd->c_stash;
+ if (sawquote) {
+ char tmpbuf[256];
+ char *s, *d;
+
+ *sawquote = '\0';
+ /*SUPPRESS 560*/
+ if (s = prevquote) {
+ strncpy(tmpbuf,name,s-name+1);
+ d = tmpbuf+(s-name+1);
+ *d++ = '_';
+ strcpy(d,s+1);
+ }
+ else {
+ *tmpbuf = '_';
+ strcpy(tmpbuf+1,name);
+ }
+ stab = stabent(tmpbuf,TRUE);
+ if (!(stash = stab_xhash(stab)))
+ stash = stab_xhash(stab) = hnew(0);
+ if (!stash->tbl_name)
+ stash->tbl_name = savestr(name);
+ name = sawquote+1;
+ *sawquote = '\'';
+ }
+ len = namend - name;
+ stab = (STAB*)hfetch(stash,name,len,add);
+ if (stab == (STAB*)&str_undef)
+ return Nullstab;
+ if (stab->str_pok) {
+ stab->str_pok |= SP_MULTI;
+ return stab;
+ }
+ else {
+ if (stab->str_len)
+ Safefree(stab->str_ptr);
+ Newz(602,stbp, 1, STBP);
+ stab->str_ptr = stbp;
+ stab->str_len = stab->str_cur = sizeof(STBP);
+ stab->str_pok = 1;
+ strcpy(stab_magic(stab),"StB");
+ stab_val(stab) = Str_new(72,0);
+ stab_line(stab) = curcmd->c_line;
+ stab_estab(stab) = stab;
+ str_magic((STR*)stab, stab, '*', name, len);
+ stab_stash(stab) = stash;
+ if (isDIGIT(*name) && *name != '0') {
+ stab_flags(stab) = SF_VMAGIC;
+ str_magic(stab_val(stab), stab, 0, Nullch, 0);
+ }
+ if (add & 2)
+ stab->str_pok |= SP_MULTI;
+ return stab;
+ }
+}
+
+void
+stab_fullname(str,stab)
+STR *str;
+STAB *stab;
+{
+ HASH *tb = stab_stash(stab);
+
+ if (!tb)
+ return;
+ str_set(str,tb->tbl_name);
+ str_ncat(str,"'", 1);
+ str_scat(str,stab->str_magic);
+}
+
+void
+stab_efullname(str,stab)
+STR *str;
+STAB *stab;
+{
+ HASH *tb = stab_estash(stab);
+
+ if (!tb)
+ return;
+ str_set(str,tb->tbl_name);
+ str_ncat(str,"'", 1);
+ str_scat(str,stab_estab(stab)->str_magic);
+}
+
+STIO *
+stio_new()
+{
+ STIO *stio;
+
+ Newz(603,stio,1,STIO);
+ stio->page_len = 60;
+ return stio;
+}
+
+void
+stab_check(min,max)
+int min;
+register int max;
+{
+ register HENT *entry;
+ register int i;
+ register STAB *stab;
+
+ for (i = min; i <= max; i++) {
+ for (entry = defstash->tbl_array[i]; entry; entry = entry->hent_next) {
+ stab = (STAB*)entry->hent_val;
+ if (stab->str_pok & SP_MULTI)
+ continue;
+ curcmd->c_line = stab_line(stab);
+ warn("Possible typo: \"%s\"", stab_name(stab));
+ }
+ }
+}
+
+static int gensym = 0;
+
+STAB *
+genstab()
+{
+ (void)sprintf(tokenbuf,"_GEN_%d",gensym++);
+ return stabent(tokenbuf,TRUE);
+}
+
+/* hopefully this is only called on local symbol table entries */
+
+void
+stab_clear(stab)
+register STAB *stab;
+{
+ STIO *stio;
+ SUBR *sub;
+
+ if (!stab || !stab->str_ptr)
+ return;
+ afree(stab_xarray(stab));
+ stab_xarray(stab) = Null(ARRAY*);
+ (void)hfree(stab_xhash(stab), FALSE);
+ stab_xhash(stab) = Null(HASH*);
+ str_free(stab_val(stab));
+ stab_val(stab) = Nullstr;
+ /*SUPPRESS 560*/
+ if (stio = stab_io(stab)) {
+ do_close(stab,FALSE);
+ Safefree(stio->top_name);
+ Safefree(stio->fmt_name);
+ Safefree(stio);
+ }
+ /*SUPPRESS 560*/
+ if (sub = stab_sub(stab)) {
+ afree(sub->tosave);
+ cmd_free(sub->cmd);
+ }
+ Safefree(stab->str_ptr);
+ stab->str_ptr = Null(STBP*);
+ stab->str_len = 0;
+ stab->str_cur = 0;
+}
+
+#if defined(CRIPPLED_CC) && (defined(iAPX286) || defined(M_I286) || defined(I80286))
+#define MICROPORT
+#endif
+
+#ifdef MICROPORT /* Microport 2.4 hack */
+ARRAY *stab_array(stab)
+register STAB *stab;
+{
+ if (((STBP*)(stab->str_ptr))->stbp_array)
+ return ((STBP*)(stab->str_ptr))->stbp_array;
+ else
+ return ((STBP*)(aadd(stab)->str_ptr))->stbp_array;
+}
+
+HASH *stab_hash(stab)
+register STAB *stab;
+{
+ if (((STBP*)(stab->str_ptr))->stbp_hash)
+ return ((STBP*)(stab->str_ptr))->stbp_hash;
+ else
+ return ((STBP*)(hadd(stab)->str_ptr))->stbp_hash;
+}
+#endif /* Microport 2.4 hack */
diff --git a/gnu/usr.bin/perl/perl/stab.h b/gnu/usr.bin/perl/perl/stab.h
new file mode 100644
index 0000000..9da5a4a
--- /dev/null
+++ b/gnu/usr.bin/perl/perl/stab.h
@@ -0,0 +1,148 @@
+/* $RCSfile: stab.h,v $$Revision: 1.1.1.1 $$Date: 1994/09/10 06:27:35 $
+ *
+ * Copyright (c) 1991, Larry Wall
+ *
+ * You may distribute under the terms of either the GNU General Public
+ * License or the Artistic License, as specified in the README file.
+ *
+ * $Log: stab.h,v $
+ * Revision 1.1.1.1 1994/09/10 06:27:35 gclarkii
+ * Initial import of Perl 4.046 bmaked
+ *
+ * Revision 1.1.1.1 1993/08/23 21:29:39 nate
+ * PERL!
+ *
+ * Revision 4.0.1.3 92/06/08 15:33:44 lwall
+ * patch20: fixed confusion between a *var's real name and its effective name
+ * patch20: ($<,$>) = ... didn't work on some architectures
+ *
+ * Revision 4.0.1.2 91/11/05 18:36:15 lwall
+ * patch11: length($x) was sometimes wrong for numeric $x
+ *
+ * Revision 4.0.1.1 91/06/07 11:56:35 lwall
+ * patch4: new copyright notice
+ * patch4: length($`), length($&), length($') now optimized to avoid string copy
+ *
+ * Revision 4.0 91/03/20 01:39:49 lwall
+ * 4.0 baseline.
+ *
+ */
+
+struct stabptrs {
+ char stbp_magic[4];
+ STR *stbp_val; /* scalar value */
+ struct stio *stbp_io; /* filehandle value */
+ FCMD *stbp_form; /* format value */
+ ARRAY *stbp_array; /* array value */
+ HASH *stbp_hash; /* associative array value */
+ STAB *stbp_stab; /* effective stab, if *glob */
+ SUBR *stbp_sub; /* subroutine value */
+ int stbp_lastexpr; /* used by nothing_in_common() */
+ line_t stbp_line; /* line first declared at (for -w) */
+ char stbp_flags;
+};
+
+#if defined(CRIPPLED_CC) && (defined(iAPX286) || defined(M_I286) || defined(I80286))
+#define MICROPORT
+#endif
+
+#define stab_magic(stab) (((STBP*)(stab->str_ptr))->stbp_magic)
+#define stab_val(stab) (((STBP*)(stab->str_ptr))->stbp_val)
+#define stab_io(stab) (((STBP*)(stab->str_ptr))->stbp_io)
+#define stab_form(stab) (((STBP*)(stab->str_ptr))->stbp_form)
+#define stab_xarray(stab) (((STBP*)(stab->str_ptr))->stbp_array)
+#ifdef MICROPORT /* Microport 2.4 hack */
+ARRAY *stab_array();
+#else
+#define stab_array(stab) (((STBP*)(stab->str_ptr))->stbp_array ? \
+ ((STBP*)(stab->str_ptr))->stbp_array : \
+ ((STBP*)(aadd(stab)->str_ptr))->stbp_array)
+#endif
+#define stab_xhash(stab) (((STBP*)(stab->str_ptr))->stbp_hash)
+#ifdef MICROPORT /* Microport 2.4 hack */
+HASH *stab_hash();
+#else
+#define stab_hash(stab) (((STBP*)(stab->str_ptr))->stbp_hash ? \
+ ((STBP*)(stab->str_ptr))->stbp_hash : \
+ ((STBP*)(hadd(stab)->str_ptr))->stbp_hash)
+#endif /* Microport 2.4 hack */
+#define stab_sub(stab) (((STBP*)(stab->str_ptr))->stbp_sub)
+#define stab_lastexpr(stab) (((STBP*)(stab->str_ptr))->stbp_lastexpr)
+#define stab_line(stab) (((STBP*)(stab->str_ptr))->stbp_line)
+#define stab_flags(stab) (((STBP*)(stab->str_ptr))->stbp_flags)
+
+#define stab_stab(stab) (stab->str_magic->str_u.str_stab)
+#define stab_estab(stab) (((STBP*)(stab->str_ptr))->stbp_stab)
+
+#define stab_name(stab) (stab->str_magic->str_ptr)
+#define stab_ename(stab) stab_name(stab_estab(stab))
+
+#define stab_stash(stab) (stab->str_magic->str_u.str_stash)
+#define stab_estash(stab) stab_stash(stab_estab(stab))
+
+#define SF_VMAGIC 1 /* call routine to dereference STR val */
+#define SF_MULTI 2 /* seen more than once */
+
+struct stio {
+ FILE *ifp; /* ifp and ofp are normally the same */
+ FILE *ofp; /* but sockets need separate streams */
+#ifdef HAS_READDIR
+ DIR *dirp; /* for opendir, readdir, etc */
+#endif
+ long lines; /* $. */
+ long page; /* $% */
+ long page_len; /* $= */
+ long lines_left; /* $- */
+ char *top_name; /* $^ */
+ STAB *top_stab; /* $^ */
+ char *fmt_name; /* $~ */
+ STAB *fmt_stab; /* $~ */
+ short subprocess; /* -| or |- */
+ char type;
+ char flags;
+};
+
+#define IOF_ARGV 1 /* this fp iterates over ARGV */
+#define IOF_START 2 /* check for null ARGV and substitute '-' */
+#define IOF_FLUSH 4 /* this fp wants a flush after write op */
+
+struct sub {
+ CMD *cmd;
+ int (*usersub)();
+ int userindex;
+ STAB *filestab;
+ long depth; /* >= 2 indicates recursive call */
+ ARRAY *tosave;
+};
+
+#define Nullstab Null(STAB*)
+
+STRLEN stab_len();
+
+#define STAB_STR(s) (tmpstab = (s), stab_flags(tmpstab) & SF_VMAGIC ? stab_str(stab_val(tmpstab)->str_magic) : stab_val(tmpstab))
+#define STAB_LEN(s) (tmpstab = (s), stab_flags(tmpstab) & SF_VMAGIC ? stab_len(stab_val(tmpstab)->str_magic) : str_len(stab_val(tmpstab)))
+#define STAB_GET(s) (tmpstab = (s), str_get(stab_flags(tmpstab) & SF_VMAGIC ? stab_str(tmpstab->str_magic) : stab_val(tmpstab)))
+#define STAB_GNUM(s) (tmpstab = (s), str_gnum(stab_flags(tmpstab) & SF_VMAGIC ? stab_str(tmpstab->str_magic) : stab_val(tmpstab)))
+
+EXT STAB *tmpstab;
+
+EXT STAB *stab_index[128];
+
+EXT unsigned short statusvalue;
+
+EXT int delaymagic INIT(0);
+#define DM_UID 0x003
+#define DM_RUID 0x001
+#define DM_EUID 0x002
+#define DM_GID 0x030
+#define DM_RGID 0x010
+#define DM_EGID 0x020
+#define DM_DELAY 0x100
+
+STAB *aadd();
+STAB *hadd();
+STAB *fstab();
+void stabset();
+void stab_fullname();
+void stab_efullname();
+void stab_check();
diff --git a/gnu/usr.bin/perl/perl/str.c b/gnu/usr.bin/perl/perl/str.c
new file mode 100644
index 0000000..0f8b36d
--- /dev/null
+++ b/gnu/usr.bin/perl/perl/str.c
@@ -0,0 +1,1602 @@
+/* $RCSfile: str.c,v $$Revision: 1.1.1.1 $$Date: 1994/09/10 06:27:33 $
+ *
+ * Copyright (c) 1991, Larry Wall
+ *
+ * You may distribute under the terms of either the GNU General Public
+ * License or the Artistic License, as specified in the README file.
+ *
+ * $Log: str.c,v $
+ * Revision 1.1.1.1 1994/09/10 06:27:33 gclarkii
+ * Initial import of Perl 4.046 bmaked
+ *
+ * Revision 1.1.1.1 1993/08/23 21:29:39 nate
+ * PERL!
+ *
+ * Revision 4.0.1.7 1993/02/05 19:43:47 lwall
+ * patch36: the non-std stdio input code wasn't null-proof
+ *
+ * Revision 4.0.1.6 92/06/11 21:14:21 lwall
+ * patch34: quotes containing subscripts containing variables didn't parse right
+ *
+ * Revision 4.0.1.5 92/06/08 15:40:43 lwall
+ * patch20: removed implicit int declarations on functions
+ * patch20: Perl now distinguishes overlapped copies from non-overlapped
+ * patch20: paragraph mode now skips extra newlines automatically
+ * patch20: fixed memory leak in doube-quote interpretation
+ * patch20: made /\$$foo/ look for literal '$foo'
+ * patch20: "$var{$foo'bar}" didn't scan subscript correctly
+ * patch20: a splice on non-existent array elements could dump core
+ * patch20: running taintperl explicitly now does checks even if $< == $>
+ *
+ * Revision 4.0.1.4 91/11/05 18:40:51 lwall
+ * patch11: $foo .= <BAR> could overrun malloced memory
+ * patch11: \$ didn't always make it through double-quoter to regexp routines
+ * patch11: prepared for ctype implementations that don't define isascii()
+ *
+ * Revision 4.0.1.3 91/06/10 01:27:54 lwall
+ * patch10: $) and $| incorrectly handled in run-time patterns
+ *
+ * Revision 4.0.1.2 91/06/07 11:58:13 lwall
+ * patch4: new copyright notice
+ * patch4: taint check on undefined string could cause core dump
+ *
+ * Revision 4.0.1.1 91/04/12 09:15:30 lwall
+ * patch1: fixed undefined environ problem
+ * patch1: substr($ENV{"PATH"},0,0) = "/foo:" didn't modify environment
+ * patch1: $foo .= <BAR> could cause core dump for certain lengths of $foo
+ *
+ * Revision 4.0 91/03/20 01:39:55 lwall
+ * 4.0 baseline.
+ *
+ */
+
+#include "EXTERN.h"
+#include "perl.h"
+#include "perly.h"
+
+static void ucase();
+static void lcase();
+
+#ifndef str_get
+char *
+str_get(str)
+STR *str;
+{
+#ifdef TAINT
+ tainted |= str->str_tainted;
+#endif
+ return str->str_pok ? str->str_ptr : str_2ptr(str);
+}
+#endif
+
+/* dlb ... guess we have a "crippled cc".
+ * dlb the following functions are usually macros.
+ */
+#ifndef str_true
+int
+str_true(Str)
+STR *Str;
+{
+ if (Str->str_pok) {
+ if (*Str->str_ptr > '0' ||
+ Str->str_cur > 1 ||
+ (Str->str_cur && *Str->str_ptr != '0'))
+ return 1;
+ return 0;
+ }
+ if (Str->str_nok)
+ return (Str->str_u.str_nval != 0.0);
+ return 0;
+}
+#endif /* str_true */
+
+#ifndef str_gnum
+double str_gnum(Str)
+STR *Str;
+{
+#ifdef TAINT
+ tainted |= Str->str_tainted;
+#endif /* TAINT*/
+ if (Str->str_nok)
+ return Str->str_u.str_nval;
+ return str_2num(Str);
+}
+#endif /* str_gnum */
+/* dlb ... end of crutch */
+
+char *
+str_grow(str,newlen)
+register STR *str;
+#ifndef DOSISH
+register int newlen;
+#else
+unsigned long newlen;
+#endif
+{
+ register char *s = str->str_ptr;
+
+#ifdef MSDOS
+ if (newlen >= 0x10000) {
+ fprintf(stderr, "Allocation too large: %lx\n", newlen);
+ exit(1);
+ }
+#endif /* MSDOS */
+ if (str->str_state == SS_INCR) { /* data before str_ptr? */
+ str->str_len += str->str_u.str_useful;
+ str->str_ptr -= str->str_u.str_useful;
+ str->str_u.str_useful = 0L;
+ Move(s, str->str_ptr, str->str_cur+1, char);
+ s = str->str_ptr;
+ str->str_state = SS_NORM; /* normal again */
+ if (newlen > str->str_len)
+ newlen += 10 * (newlen - str->str_cur); /* avoid copy each time */
+ }
+ if (newlen > str->str_len) { /* need more room? */
+ if (str->str_len)
+ Renew(s,newlen,char);
+ else
+ New(703,s,newlen,char);
+ str->str_ptr = s;
+ str->str_len = newlen;
+ }
+ return s;
+}
+
+void
+str_numset(str,num)
+register STR *str;
+double num;
+{
+ if (str->str_pok) {
+ str->str_pok = 0; /* invalidate pointer */
+ if (str->str_state == SS_INCR)
+ Str_Grow(str,0);
+ }
+ str->str_u.str_nval = num;
+ str->str_state = SS_NORM;
+ str->str_nok = 1; /* validate number */
+#ifdef TAINT
+ str->str_tainted = tainted;
+#endif
+}
+
+char *
+str_2ptr(str)
+register STR *str;
+{
+ register char *s;
+ int olderrno;
+
+ if (!str)
+ return "";
+ if (str->str_nok) {
+ STR_GROW(str, 30);
+ s = str->str_ptr;
+ olderrno = errno; /* some Xenix systems wipe out errno here */
+#if defined(scs) && defined(ns32000)
+ gcvt(str->str_u.str_nval,20,s);
+#else
+#ifdef apollo
+ if (str->str_u.str_nval == 0.0)
+ (void)strcpy(s,"0");
+ else
+#endif /*apollo*/
+ (void)sprintf(s,"%.20g",str->str_u.str_nval);
+#endif /*scs*/
+ errno = olderrno;
+ while (*s) s++;
+#ifdef hcx
+ if (s[-1] == '.')
+ s--;
+#endif
+ }
+ else {
+ if (str == &str_undef)
+ return No;
+ if (dowarn)
+ warn("Use of uninitialized variable");
+ STR_GROW(str, 30);
+ s = str->str_ptr;
+ }
+ *s = '\0';
+ str->str_cur = s - str->str_ptr;
+ str->str_pok = 1;
+#ifdef DEBUGGING
+ if (debug & 32)
+ fprintf(stderr,"0x%lx ptr(%s)\n",str,str->str_ptr);
+#endif
+ return str->str_ptr;
+}
+
+double
+str_2num(str)
+register STR *str;
+{
+ if (!str)
+ return 0.0;
+ if (str->str_state == SS_INCR)
+ Str_Grow(str,0); /* just force copy down */
+ str->str_state = SS_NORM;
+ if (str->str_len && str->str_pok)
+ str->str_u.str_nval = atof(str->str_ptr);
+ else {
+ if (str == &str_undef)
+ return 0.0;
+ if (dowarn)
+ warn("Use of uninitialized variable");
+ str->str_u.str_nval = 0.0;
+ }
+ str->str_nok = 1;
+#ifdef DEBUGGING
+ if (debug & 32)
+ fprintf(stderr,"0x%lx num(%g)\n",str,str->str_u.str_nval);
+#endif
+ return str->str_u.str_nval;
+}
+
+/* Note: str_sset() should not be called with a source string that needs
+ * be reused, since it may destroy the source string if it is marked
+ * as temporary.
+ */
+
+void
+str_sset(dstr,sstr)
+STR *dstr;
+register STR *sstr;
+{
+#ifdef TAINT
+ if (sstr)
+ tainted |= sstr->str_tainted;
+#endif
+ if (sstr == dstr || dstr == &str_undef)
+ return;
+ if (!sstr)
+ dstr->str_pok = dstr->str_nok = 0;
+ else if (sstr->str_pok) {
+
+ /*
+ * Check to see if we can just swipe the string. If so, it's a
+ * possible small lose on short strings, but a big win on long ones.
+ * It might even be a win on short strings if dstr->str_ptr
+ * has to be allocated and sstr->str_ptr has to be freed.
+ */
+
+ if (sstr->str_pok & SP_TEMP) { /* slated for free anyway? */
+ if (dstr->str_ptr) {
+ if (dstr->str_state == SS_INCR)
+ dstr->str_ptr -= dstr->str_u.str_useful;
+ Safefree(dstr->str_ptr);
+ }
+ dstr->str_ptr = sstr->str_ptr;
+ dstr->str_len = sstr->str_len;
+ dstr->str_cur = sstr->str_cur;
+ dstr->str_state = sstr->str_state;
+ dstr->str_pok = sstr->str_pok & ~SP_TEMP;
+#ifdef TAINT
+ dstr->str_tainted = sstr->str_tainted;
+#endif
+ sstr->str_ptr = Nullch;
+ sstr->str_len = 0;
+ sstr->str_pok = 0; /* wipe out any weird flags */
+ sstr->str_state = 0; /* so sstr frees uneventfully */
+ }
+ else { /* have to copy actual string */
+ if (dstr->str_ptr) {
+ if (dstr->str_state == SS_INCR) {
+ Str_Grow(dstr,0);
+ }
+ }
+ str_nset(dstr,sstr->str_ptr,sstr->str_cur);
+ }
+ /*SUPPRESS 560*/
+ if (dstr->str_nok = sstr->str_nok)
+ dstr->str_u.str_nval = sstr->str_u.str_nval;
+ else {
+#ifdef STRUCTCOPY
+ dstr->str_u = sstr->str_u;
+#else
+ dstr->str_u.str_nval = sstr->str_u.str_nval;
+#endif
+ if (dstr->str_cur == sizeof(STBP)) {
+ char *tmps = dstr->str_ptr;
+
+ if (*tmps == 'S' && bcmp(tmps,"StB",4) == 0) {
+ if (dstr->str_magic && dstr->str_magic->str_rare == 'X') {
+ str_free(dstr->str_magic);
+ dstr->str_magic = Nullstr;
+ }
+ if (!dstr->str_magic) {
+ dstr->str_magic = str_smake(sstr->str_magic);
+ dstr->str_magic->str_rare = 'X';
+ }
+ }
+ }
+ }
+ }
+ else if (sstr->str_nok)
+ str_numset(dstr,sstr->str_u.str_nval);
+ else {
+ if (dstr->str_state == SS_INCR)
+ Str_Grow(dstr,0); /* just force copy down */
+
+#ifdef STRUCTCOPY
+ dstr->str_u = sstr->str_u;
+#else
+ dstr->str_u.str_nval = sstr->str_u.str_nval;
+#endif
+ dstr->str_pok = dstr->str_nok = 0;
+ }
+}
+
+void
+str_nset(str,ptr,len)
+register STR *str;
+register char *ptr;
+register STRLEN len;
+{
+ if (str == &str_undef)
+ return;
+ STR_GROW(str, len + 1);
+ if (ptr)
+ Move(ptr,str->str_ptr,len,char);
+ str->str_cur = len;
+ *(str->str_ptr+str->str_cur) = '\0';
+ str->str_nok = 0; /* invalidate number */
+ str->str_pok = 1; /* validate pointer */
+#ifdef TAINT
+ str->str_tainted = tainted;
+#endif
+}
+
+void
+str_set(str,ptr)
+register STR *str;
+register char *ptr;
+{
+ register STRLEN len;
+
+ if (str == &str_undef)
+ return;
+ if (!ptr)
+ ptr = "";
+ len = strlen(ptr);
+ STR_GROW(str, len + 1);
+ Move(ptr,str->str_ptr,len+1,char);
+ str->str_cur = len;
+ str->str_nok = 0; /* invalidate number */
+ str->str_pok = 1; /* validate pointer */
+#ifdef TAINT
+ str->str_tainted = tainted;
+#endif
+}
+
+void
+str_chop(str,ptr) /* like set but assuming ptr is in str */
+register STR *str;
+register char *ptr;
+{
+ register STRLEN delta;
+
+ if (!ptr || !(str->str_pok))
+ return;
+ delta = ptr - str->str_ptr;
+ str->str_len -= delta;
+ str->str_cur -= delta;
+ str->str_ptr += delta;
+ if (str->str_state == SS_INCR)
+ str->str_u.str_useful += delta;
+ else {
+ str->str_u.str_useful = delta;
+ str->str_state = SS_INCR;
+ }
+ str->str_nok = 0; /* invalidate number */
+ str->str_pok = 1; /* validate pointer (and unstudy str) */
+}
+
+void
+str_ncat(str,ptr,len)
+register STR *str;
+register char *ptr;
+register STRLEN len;
+{
+ if (str == &str_undef)
+ return;
+ if (!(str->str_pok))
+ (void)str_2ptr(str);
+ STR_GROW(str, str->str_cur + len + 1);
+ Move(ptr,str->str_ptr+str->str_cur,len,char);
+ str->str_cur += len;
+ *(str->str_ptr+str->str_cur) = '\0';
+ str->str_nok = 0; /* invalidate number */
+ str->str_pok = 1; /* validate pointer */
+#ifdef TAINT
+ str->str_tainted |= tainted;
+#endif
+}
+
+void
+str_scat(dstr,sstr)
+STR *dstr;
+register STR *sstr;
+{
+ if (!sstr)
+ return;
+#ifdef TAINT
+ tainted |= sstr->str_tainted;
+#endif
+ if (!(sstr->str_pok))
+ (void)str_2ptr(sstr);
+ if (sstr)
+ str_ncat(dstr,sstr->str_ptr,sstr->str_cur);
+}
+
+void
+str_cat(str,ptr)
+register STR *str;
+register char *ptr;
+{
+ register STRLEN len;
+
+ if (str == &str_undef)
+ return;
+ if (!ptr)
+ return;
+ if (!(str->str_pok))
+ (void)str_2ptr(str);
+ len = strlen(ptr);
+ STR_GROW(str, str->str_cur + len + 1);
+ Move(ptr,str->str_ptr+str->str_cur,len+1,char);
+ str->str_cur += len;
+ str->str_nok = 0; /* invalidate number */
+ str->str_pok = 1; /* validate pointer */
+#ifdef TAINT
+ str->str_tainted |= tainted;
+#endif
+}
+
+char *
+str_append_till(str,from,fromend,delim,keeplist)
+register STR *str;
+register char *from;
+register char *fromend;
+register int delim;
+char *keeplist;
+{
+ register char *to;
+ register STRLEN len;
+
+ if (str == &str_undef)
+ return Nullch;
+ if (!from)
+ return Nullch;
+ len = fromend - from;
+ STR_GROW(str, str->str_cur + len + 1);
+ str->str_nok = 0; /* invalidate number */
+ str->str_pok = 1; /* validate pointer */
+ to = str->str_ptr+str->str_cur;
+ for (; from < fromend; from++,to++) {
+ if (*from == '\\' && from+1 < fromend && delim != '\\') {
+ if (!keeplist) {
+ if (from[1] == delim || from[1] == '\\')
+ from++;
+ else
+ *to++ = *from++;
+ }
+ else if (from[1] && index(keeplist,from[1]))
+ *to++ = *from++;
+ else
+ from++;
+ }
+ else if (*from == delim)
+ break;
+ *to = *from;
+ }
+ *to = '\0';
+ str->str_cur = to - str->str_ptr;
+ return from;
+}
+
+STR *
+#ifdef LEAKTEST
+str_new(x,len)
+int x;
+#else
+str_new(len)
+#endif
+STRLEN len;
+{
+ register STR *str;
+
+ if (freestrroot) {
+ str = freestrroot;
+ freestrroot = str->str_magic;
+ str->str_magic = Nullstr;
+ str->str_state = SS_NORM;
+ }
+ else {
+ Newz(700+x,str,1,STR);
+ }
+ if (len)
+ STR_GROW(str, len + 1);
+ return str;
+}
+
+void
+str_magic(str, stab, how, name, namlen)
+register STR *str;
+STAB *stab;
+int how;
+char *name;
+STRLEN namlen;
+{
+ if (str == &str_undef || str->str_magic)
+ return;
+ str->str_magic = Str_new(75,namlen);
+ str = str->str_magic;
+ str->str_u.str_stab = stab;
+ str->str_rare = how;
+ if (name)
+ str_nset(str,name,namlen);
+}
+
+void
+str_insert(bigstr,offset,len,little,littlelen)
+STR *bigstr;
+STRLEN offset;
+STRLEN len;
+char *little;
+STRLEN littlelen;
+{
+ register char *big;
+ register char *mid;
+ register char *midend;
+ register char *bigend;
+ register int i;
+
+ if (bigstr == &str_undef)
+ return;
+ bigstr->str_nok = 0;
+ bigstr->str_pok = SP_VALID; /* disable possible screamer */
+
+ i = littlelen - len;
+ if (i > 0) { /* string might grow */
+ STR_GROW(bigstr, bigstr->str_cur + i + 1);
+ big = bigstr->str_ptr;
+ mid = big + offset + len;
+ midend = bigend = big + bigstr->str_cur;
+ bigend += i;
+ *bigend = '\0';
+ while (midend > mid) /* shove everything down */
+ *--bigend = *--midend;
+ Move(little,big+offset,littlelen,char);
+ bigstr->str_cur += i;
+ STABSET(bigstr);
+ return;
+ }
+ else if (i == 0) {
+ Move(little,bigstr->str_ptr+offset,len,char);
+ STABSET(bigstr);
+ return;
+ }
+
+ big = bigstr->str_ptr;
+ mid = big + offset;
+ midend = mid + len;
+ bigend = big + bigstr->str_cur;
+
+ if (midend > bigend)
+ fatal("panic: str_insert");
+
+ if (mid - big > bigend - midend) { /* faster to shorten from end */
+ if (littlelen) {
+ Move(little, mid, littlelen,char);
+ mid += littlelen;
+ }
+ i = bigend - midend;
+ if (i > 0) {
+ Move(midend, mid, i,char);
+ mid += i;
+ }
+ *mid = '\0';
+ bigstr->str_cur = mid - big;
+ }
+ /*SUPPRESS 560*/
+ else if (i = mid - big) { /* faster from front */
+ midend -= littlelen;
+ mid = midend;
+ str_chop(bigstr,midend-i);
+ big += i;
+ while (i--)
+ *--midend = *--big;
+ if (littlelen)
+ Move(little, mid, littlelen,char);
+ }
+ else if (littlelen) {
+ midend -= littlelen;
+ str_chop(bigstr,midend);
+ Move(little,midend,littlelen,char);
+ }
+ else {
+ str_chop(bigstr,midend);
+ }
+ STABSET(bigstr);
+}
+
+/* make str point to what nstr did */
+
+void
+str_replace(str,nstr)
+register STR *str;
+register STR *nstr;
+{
+ if (str == &str_undef)
+ return;
+ if (str->str_state == SS_INCR)
+ Str_Grow(str,0); /* just force copy down */
+ if (nstr->str_state == SS_INCR)
+ Str_Grow(nstr,0);
+ if (str->str_ptr)
+ Safefree(str->str_ptr);
+ str->str_ptr = nstr->str_ptr;
+ str->str_len = nstr->str_len;
+ str->str_cur = nstr->str_cur;
+ str->str_pok = nstr->str_pok;
+ str->str_nok = nstr->str_nok;
+#ifdef STRUCTCOPY
+ str->str_u = nstr->str_u;
+#else
+ str->str_u.str_nval = nstr->str_u.str_nval;
+#endif
+#ifdef TAINT
+ str->str_tainted = nstr->str_tainted;
+#endif
+ if (nstr->str_magic)
+ str_free(nstr->str_magic);
+ Safefree(nstr);
+}
+
+void
+str_free(str)
+register STR *str;
+{
+ if (!str || str == &str_undef)
+ return;
+ if (str->str_state) {
+ if (str->str_state == SS_FREE) /* already freed */
+ return;
+ if (str->str_state == SS_INCR && !(str->str_pok & 2)) {
+ str->str_ptr -= str->str_u.str_useful;
+ str->str_len += str->str_u.str_useful;
+ }
+ }
+ if (str->str_magic)
+ str_free(str->str_magic);
+ str->str_magic = freestrroot;
+#ifdef LEAKTEST
+ if (str->str_len) {
+ Safefree(str->str_ptr);
+ str->str_ptr = Nullch;
+ }
+ if ((str->str_pok & SP_INTRP) && str->str_u.str_args)
+ arg_free(str->str_u.str_args);
+ Safefree(str);
+#else /* LEAKTEST */
+ if (str->str_len) {
+ if (str->str_len > 127) { /* next user not likely to want more */
+ Safefree(str->str_ptr); /* so give it back to malloc */
+ str->str_ptr = Nullch;
+ str->str_len = 0;
+ }
+ else
+ str->str_ptr[0] = '\0';
+ }
+ if ((str->str_pok & SP_INTRP) && str->str_u.str_args)
+ arg_free(str->str_u.str_args);
+ str->str_cur = 0;
+ str->str_nok = 0;
+ str->str_pok = 0;
+ str->str_state = SS_FREE;
+#ifdef TAINT
+ str->str_tainted = 0;
+#endif
+ freestrroot = str;
+#endif /* LEAKTEST */
+}
+
+STRLEN
+str_len(str)
+register STR *str;
+{
+ if (!str)
+ return 0;
+ if (!(str->str_pok))
+ (void)str_2ptr(str);
+ if (str->str_ptr)
+ return str->str_cur;
+ else
+ return 0;
+}
+
+int
+str_eq(str1,str2)
+register STR *str1;
+register STR *str2;
+{
+ if (!str1 || str1 == &str_undef)
+ return (str2 == Nullstr || str2 == &str_undef || !str2->str_cur);
+ if (!str2 || str2 == &str_undef)
+ return !str1->str_cur;
+
+ if (!str1->str_pok)
+ (void)str_2ptr(str1);
+ if (!str2->str_pok)
+ (void)str_2ptr(str2);
+
+ if (str1->str_cur != str2->str_cur)
+ return 0;
+
+ return !bcmp(str1->str_ptr, str2->str_ptr, str1->str_cur);
+}
+
+int
+str_cmp(str1,str2)
+register STR *str1;
+register STR *str2;
+{
+ int retval;
+
+ if (!str1 || str1 == &str_undef)
+ return (str2 == Nullstr || str2 == &str_undef || !str2->str_cur)?0:-1;
+ if (!str2 || str2 == &str_undef)
+ return str1->str_cur != 0;
+
+ if (!str1->str_pok)
+ (void)str_2ptr(str1);
+ if (!str2->str_pok)
+ (void)str_2ptr(str2);
+
+ if (str1->str_cur < str2->str_cur) {
+ /*SUPPRESS 560*/
+ if (retval = memcmp(str1->str_ptr, str2->str_ptr, str1->str_cur))
+ return retval < 0 ? -1 : 1;
+ else
+ return -1;
+ }
+ /*SUPPRESS 560*/
+ else if (retval = memcmp(str1->str_ptr, str2->str_ptr, str2->str_cur))
+ return retval < 0 ? -1 : 1;
+ else if (str1->str_cur == str2->str_cur)
+ return 0;
+ else
+ return 1;
+}
+
+char *
+str_gets(str,fp,append)
+register STR *str;
+register FILE *fp;
+int append;
+{
+ register char *bp; /* we're going to steal some values */
+ register int cnt; /* from the stdio struct and put EVERYTHING */
+ register STDCHAR *ptr; /* in the innermost loop into registers */
+ register int newline = rschar;/* (assuming >= 6 registers) */
+ int i;
+ STRLEN bpx;
+ int shortbuffered;
+
+ if (str == &str_undef)
+ return Nullch;
+ if (rspara) { /* have to do this both before and after */
+ do { /* to make sure file boundaries work right */
+ i = getc(fp);
+ if (i != '\n') {
+ ungetc(i,fp);
+ break;
+ }
+ } while (i != EOF);
+ }
+#ifdef STDSTDIO /* Here is some breathtakingly efficient cheating */
+ cnt = fp->_cnt; /* get count into register */
+ str->str_nok = 0; /* invalidate number */
+ str->str_pok = 1; /* validate pointer */
+ if (str->str_len - append <= cnt + 1) { /* make sure we have the room */
+ if (cnt > 80 && str->str_len > append) {
+ shortbuffered = cnt - str->str_len + append + 1;
+ cnt -= shortbuffered;
+ }
+ else {
+ shortbuffered = 0;
+ STR_GROW(str, append+cnt+2);/* (remembering cnt can be -1) */
+ }
+ }
+ else
+ shortbuffered = 0;
+ bp = str->str_ptr + append; /* move these two too to registers */
+ ptr = fp->_ptr;
+ for (;;) {
+ screamer:
+ while (--cnt >= 0) { /* this */ /* eat */
+ if ((*bp++ = *ptr++) == newline) /* really */ /* dust */
+ goto thats_all_folks; /* screams */ /* sed :-) */
+ }
+
+ if (shortbuffered) { /* oh well, must extend */
+ cnt = shortbuffered;
+ shortbuffered = 0;
+ bpx = bp - str->str_ptr; /* prepare for possible relocation */
+ str->str_cur = bpx;
+ STR_GROW(str, str->str_len + append + cnt + 2);
+ bp = str->str_ptr + bpx; /* reconstitute our pointer */
+ continue;
+ }
+
+ fp->_cnt = cnt; /* deregisterize cnt and ptr */
+ fp->_ptr = ptr;
+ i = _filbuf(fp); /* get more characters */
+ cnt = fp->_cnt;
+ ptr = fp->_ptr; /* reregisterize cnt and ptr */
+
+ bpx = bp - str->str_ptr; /* prepare for possible relocation */
+ str->str_cur = bpx;
+ STR_GROW(str, bpx + cnt + 2);
+ bp = str->str_ptr + bpx; /* reconstitute our pointer */
+
+ if (i == newline) { /* all done for now? */
+ *bp++ = i;
+ goto thats_all_folks;
+ }
+ else if (i == EOF) /* all done for ever? */
+ goto thats_really_all_folks;
+ *bp++ = i; /* now go back to screaming loop */
+ }
+
+thats_all_folks:
+ if (rslen > 1 && (bp - str->str_ptr < rslen || bcmp(bp - rslen, rs, rslen)))
+ goto screamer; /* go back to the fray */
+thats_really_all_folks:
+ if (shortbuffered)
+ cnt += shortbuffered;
+ fp->_cnt = cnt; /* put these back or we're in trouble */
+ fp->_ptr = ptr;
+ *bp = '\0';
+ str->str_cur = bp - str->str_ptr; /* set length */
+
+#else /* !STDSTDIO */ /* The big, slow, and stupid way */
+
+ {
+ static char buf[8192];
+ char * bpe = buf + sizeof(buf) - 3;
+
+screamer:
+ bp = buf;
+ while ((i = getc(fp)) != EOF && (*bp++ = i) != newline && bp < bpe) ;
+
+ if (append)
+ str_ncat(str, buf, bp - buf);
+ else
+ str_nset(str, buf, bp - buf);
+ if (i != EOF /* joy */
+ &&
+ (i != newline
+ ||
+ (rslen > 1
+ &&
+ (str->str_cur < rslen
+ ||
+ bcmp(str->str_ptr + str->str_cur - rslen, rs, rslen)
+ )
+ )
+ )
+ )
+ {
+ append = -1;
+ goto screamer;
+ }
+ }
+
+#endif /* STDSTDIO */
+
+ if (rspara) {
+ while (i != EOF) {
+ i = getc(fp);
+ if (i != '\n') {
+ ungetc(i,fp);
+ break;
+ }
+ }
+ }
+ return str->str_cur - append ? str->str_ptr : Nullch;
+}
+
+ARG *
+parselist(str)
+STR *str;
+{
+ register CMD *cmd;
+ register ARG *arg;
+ CMD *oldcurcmd = curcmd;
+ int oldperldb = perldb;
+ int retval;
+
+ perldb = 0;
+ str_sset(linestr,str);
+ in_eval++;
+ oldoldbufptr = oldbufptr = bufptr = str_get(linestr);
+ bufend = bufptr + linestr->str_cur;
+ if (++loop_ptr >= loop_max) {
+ loop_max += 128;
+ Renew(loop_stack, loop_max, struct loop);
+ }
+ loop_stack[loop_ptr].loop_label = "_EVAL_";
+ loop_stack[loop_ptr].loop_sp = 0;
+#ifdef DEBUGGING
+ if (debug & 4) {
+ deb("(Pushing label #%d _EVAL_)\n", loop_ptr);
+ }
+#endif
+ if (setjmp(loop_stack[loop_ptr].loop_env)) {
+ in_eval--;
+ loop_ptr--;
+ perldb = oldperldb;
+ fatal("%s\n",stab_val(stabent("@",TRUE))->str_ptr);
+ }
+#ifdef DEBUGGING
+ if (debug & 4) {
+ char *tmps = loop_stack[loop_ptr].loop_label;
+ deb("(Popping label #%d %s)\n",loop_ptr,
+ tmps ? tmps : "" );
+ }
+#endif
+ loop_ptr--;
+ error_count = 0;
+ curcmd = &compiling;
+ curcmd->c_line = oldcurcmd->c_line;
+ retval = yyparse();
+ curcmd = oldcurcmd;
+ perldb = oldperldb;
+ in_eval--;
+ if (retval || error_count)
+ fatal("Invalid component in string or format");
+ cmd = eval_root;
+ arg = cmd->c_expr;
+ if (cmd->c_type != C_EXPR || cmd->c_next || arg->arg_type != O_LIST)
+ fatal("panic: error in parselist %d %x %d", cmd->c_type,
+ cmd->c_next, arg ? arg->arg_type : -1);
+ cmd->c_expr = Nullarg;
+ cmd_free(cmd);
+ eval_root = Nullcmd;
+ return arg;
+}
+
+void
+intrpcompile(src)
+STR *src;
+{
+ register char *s = str_get(src);
+ register char *send = s + src->str_cur;
+ register STR *str;
+ register char *t;
+ STR *toparse;
+ STRLEN len;
+ register int brackets;
+ register char *d;
+ STAB *stab;
+ char *checkpoint;
+ int sawcase = 0;
+
+ toparse = Str_new(76,0);
+ str = Str_new(77,0);
+
+ str_nset(str,"",0);
+ str_nset(toparse,"",0);
+ t = s;
+ while (s < send) {
+ if (*s == '\\' && s[1] && index("$@[{\\]}lLuUE",s[1])) {
+ str_ncat(str, t, s - t);
+ ++s;
+ if (isALPHA(*s)) {
+ str_ncat(str, "$c", 2);
+ sawcase = (*s != 'E');
+ }
+ else {
+ if (*nointrp) { /* in a regular expression */
+ if (*s == '@') /* always strip \@ */ /*SUPPRESS 530*/
+ ;
+ else /* don't strip \\, \[, \{ etc. */
+ str_ncat(str,s-1,1);
+ }
+ str_ncat(str, "$b", 2);
+ }
+ str_ncat(str, s, 1);
+ ++s;
+ t = s;
+ }
+ else if (*s == '$' && s+1 < send && *nointrp && index(nointrp,s[1])) {
+ str_ncat(str, t, s - t);
+ str_ncat(str, "$b", 2);
+ str_ncat(str, s, 2);
+ s += 2;
+ t = s;
+ }
+ else if ((*s == '@' || *s == '$') && s+1 < send) {
+ str_ncat(str,t,s-t);
+ t = s;
+ if (*s == '$' && s[1] == '#' && (isALPHA(s[2]) || s[2] == '_'))
+ s++;
+ s = scanident(s,send,tokenbuf);
+ if (*t == '@' &&
+ (!(stab = stabent(tokenbuf,FALSE)) ||
+ (*s == '{' ? !stab_xhash(stab) : !stab_xarray(stab)) )) {
+ str_ncat(str,"@",1);
+ s = ++t;
+ continue; /* grandfather @ from old scripts */
+ }
+ str_ncat(str,"$a",2);
+ str_ncat(toparse,",",1);
+ if (t[1] != '{' && (*s == '[' || *s == '{' /* }} */ ) &&
+ (stab = stabent(tokenbuf,FALSE)) &&
+ ((*s == '[') ? (stab_xarray(stab) != 0) : (stab_xhash(stab) != 0)) ) {
+ brackets = 0;
+ checkpoint = s;
+ do {
+ switch (*s) {
+ case '[':
+ brackets++;
+ break;
+ case '{':
+ brackets++;
+ break;
+ case ']':
+ brackets--;
+ break;
+ case '}':
+ brackets--;
+ break;
+ case '$':
+ case '%':
+ case '@':
+ case '&':
+ case '*':
+ s = scanident(s,send,tokenbuf);
+ continue;
+ case '\'':
+ case '"':
+ /*SUPPRESS 68*/
+ s = cpytill(tokenbuf,s+1,send,*s,&len);
+ if (s >= send)
+ fatal("Unterminated string");
+ break;
+ }
+ s++;
+ } while (brackets > 0 && s < send);
+ if (s > send)
+ fatal("Unmatched brackets in string");
+ if (*nointrp) { /* we're in a regular expression */
+ d = checkpoint;
+ if (*d == '{' && s[-1] == '}') { /* maybe {n,m} */
+ ++d;
+ if (isDIGIT(*d)) { /* matches /^{\d,?\d*}$/ */
+ if (*++d == ',')
+ ++d;
+ while (isDIGIT(*d))
+ d++;
+ if (d == s - 1)
+ s = checkpoint; /* Is {n,m}! Backoff! */
+ }
+ }
+ else if (*d == '[' && s[-1] == ']') { /* char class? */
+ int weight = 2; /* let's weigh the evidence */
+ char seen[256];
+ unsigned char un_char = 0, last_un_char;
+
+ Zero(seen,256,char);
+ *--s = '\0';
+ if (d[1] == '^')
+ weight += 150;
+ else if (d[1] == '$')
+ weight -= 3;
+ if (isDIGIT(d[1])) {
+ if (d[2]) {
+ if (isDIGIT(d[2]) && !d[3])
+ weight -= 10;
+ }
+ else
+ weight -= 100;
+ }
+ for (d++; d < s; d++) {
+ last_un_char = un_char;
+ un_char = (unsigned char)*d;
+ switch (*d) {
+ case '&':
+ case '$':
+ weight -= seen[un_char] * 10;
+ if (isALNUM(d[1])) {
+ d = scanident(d,s,tokenbuf);
+ if (stabent(tokenbuf,FALSE))
+ weight -= 100;
+ else
+ weight -= 10;
+ }
+ else if (*d == '$' && d[1] &&
+ index("[#!%*<>()-=",d[1])) {
+ if (!d[2] || /*{*/ index("])} =",d[2]))
+ weight -= 10;
+ else
+ weight -= 1;
+ }
+ break;
+ case '\\':
+ un_char = 254;
+ if (d[1]) {
+ if (index("wds",d[1]))
+ weight += 100;
+ else if (seen['\''] || seen['"'])
+ weight += 1;
+ else if (index("rnftb",d[1]))
+ weight += 40;
+ else if (isDIGIT(d[1])) {
+ weight += 40;
+ while (d[1] && isDIGIT(d[1]))
+ d++;
+ }
+ }
+ else
+ weight += 100;
+ break;
+ case '-':
+ if (last_un_char < (unsigned char) d[1]
+ || d[1] == '\\') {
+ if (index("aA01! ",last_un_char))
+ weight += 30;
+ if (index("zZ79~",d[1]))
+ weight += 30;
+ }
+ else
+ weight -= 1;
+ default:
+ if (isALPHA(*d) && d[1] && isALPHA(d[1])) {
+ bufptr = d;
+ if (yylex() != WORD)
+ weight -= 150;
+ d = bufptr;
+ }
+ if (un_char == last_un_char + 1)
+ weight += 5;
+ weight -= seen[un_char];
+ break;
+ }
+ seen[un_char]++;
+ }
+#ifdef DEBUGGING
+ if (debug & 512)
+ fprintf(stderr,"[%s] weight %d\n",
+ checkpoint+1,weight);
+#endif
+ *s++ = ']';
+ if (weight >= 0) /* probably a character class */
+ s = checkpoint;
+ }
+ }
+ }
+ if (*t == '@')
+ str_ncat(toparse, "join($\",", 8);
+ if (t[1] == '{' && s[-1] == '}') {
+ str_ncat(toparse, t, 1);
+ str_ncat(toparse, t+2, s - t - 3);
+ }
+ else
+ str_ncat(toparse, t, s - t);
+ if (*t == '@')
+ str_ncat(toparse, ")", 1);
+ t = s;
+ }
+ else
+ s++;
+ }
+ str_ncat(str,t,s-t);
+ if (sawcase)
+ str_ncat(str, "$cE", 3);
+ if (toparse->str_ptr && *toparse->str_ptr == ',') {
+ *toparse->str_ptr = '(';
+ str_ncat(toparse,",$$);",5);
+ str->str_u.str_args = parselist(toparse);
+ str->str_u.str_args->arg_len--; /* ignore $$ reference */
+ }
+ else
+ str->str_u.str_args = Nullarg;
+ str_free(toparse);
+ str->str_pok |= SP_INTRP;
+ str->str_nok = 0;
+ str_replace(src,str);
+}
+
+STR *
+interp(str,src,sp)
+register STR *str;
+STR *src;
+int sp;
+{
+ register char *s;
+ register char *t;
+ register char *send;
+ register STR **elem;
+ int docase = 0;
+ int l = 0;
+ int u = 0;
+ int L = 0;
+ int U = 0;
+
+ if (str == &str_undef)
+ return Nullstr;
+ if (!(src->str_pok & SP_INTRP)) {
+ int oldsave = savestack->ary_fill;
+
+ (void)savehptr(&curstash);
+ curstash = curcmd->c_stash; /* so stabent knows right package */
+ intrpcompile(src);
+ restorelist(oldsave);
+ }
+ s = src->str_ptr; /* assumed valid since str_pok set */
+ t = s;
+ send = s + src->str_cur;
+
+ if (src->str_u.str_args) {
+ (void)eval(src->str_u.str_args,G_ARRAY,sp);
+ /* Assuming we have correct # of args */
+ elem = stack->ary_array + sp;
+ }
+
+ str_nset(str,"",0);
+ while (s < send) {
+ if (*s == '$' && s+1 < send) {
+ if (s-t > 0)
+ str_ncat(str,t,s-t);
+ switch(*++s) {
+ default:
+ fatal("panic: unknown interp cookie\n");
+ break;
+ case 'a':
+ str_scat(str,*++elem);
+ break;
+ case 'b':
+ str_ncat(str,++s,1);
+ break;
+ case 'c':
+ if (docase && str->str_cur >= docase) {
+ char *b = str->str_ptr + --docase;
+
+ if (L)
+ lcase(b, str->str_ptr + str->str_cur);
+ else if (U)
+ ucase(b, str->str_ptr + str->str_cur);
+
+ if (u) /* note that l & u are independent of L & U */
+ ucase(b, b+1);
+ else if (l)
+ lcase(b, b+1);
+ l = u = 0;
+ }
+ docase = str->str_cur + 1;
+ switch (*++s) {
+ case 'u':
+ u = 1;
+ l = 0;
+ break;
+ case 'U':
+ U = 1;
+ L = 0;
+ break;
+ case 'l':
+ l = 1;
+ u = 0;
+ break;
+ case 'L':
+ L = 1;
+ U = 0;
+ break;
+ case 'E':
+ docase = L = U = l = u = 0;
+ break;
+ }
+ break;
+ }
+ t = ++s;
+ }
+ else
+ s++;
+ }
+ if (s-t > 0)
+ str_ncat(str,t,s-t);
+ return str;
+}
+
+static void
+ucase(s,send)
+register char *s;
+register char *send;
+{
+ while (s < send) {
+ if (isLOWER(*s))
+ *s = toupper(*s);
+ s++;
+ }
+}
+
+static void
+lcase(s,send)
+register char *s;
+register char *send;
+{
+ while (s < send) {
+ if (isUPPER(*s))
+ *s = tolower(*s);
+ s++;
+ }
+}
+
+void
+str_inc(str)
+register STR *str;
+{
+ register char *d;
+
+ if (!str || str == &str_undef)
+ return;
+ if (str->str_nok) {
+ str->str_u.str_nval += 1.0;
+ str->str_pok = 0;
+ return;
+ }
+ if (!str->str_pok || !*str->str_ptr) {
+ str->str_u.str_nval = 1.0;
+ str->str_nok = 1;
+ str->str_pok = 0;
+ return;
+ }
+ d = str->str_ptr;
+ while (isALPHA(*d)) d++;
+ while (isDIGIT(*d)) d++;
+ if (*d) {
+ str_numset(str,atof(str->str_ptr) + 1.0); /* punt */
+ return;
+ }
+ d--;
+ while (d >= str->str_ptr) {
+ if (isDIGIT(*d)) {
+ if (++*d <= '9')
+ return;
+ *(d--) = '0';
+ }
+ else {
+ ++*d;
+ if (isALPHA(*d))
+ return;
+ *(d--) -= 'z' - 'a' + 1;
+ }
+ }
+ /* oh,oh, the number grew */
+ STR_GROW(str, str->str_cur + 2);
+ str->str_cur++;
+ for (d = str->str_ptr + str->str_cur; d > str->str_ptr; d--)
+ *d = d[-1];
+ if (isDIGIT(d[1]))
+ *d = '1';
+ else
+ *d = d[1];
+}
+
+void
+str_dec(str)
+register STR *str;
+{
+ if (!str || str == &str_undef)
+ return;
+ if (str->str_nok) {
+ str->str_u.str_nval -= 1.0;
+ str->str_pok = 0;
+ return;
+ }
+ if (!str->str_pok) {
+ str->str_u.str_nval = -1.0;
+ str->str_nok = 1;
+ return;
+ }
+ str_numset(str,atof(str->str_ptr) - 1.0);
+}
+
+/* Make a string that will exist for the duration of the expression
+ * evaluation. Actually, it may have to last longer than that, but
+ * hopefully cmd_exec won't free it until it has been assigned to a
+ * permanent location. */
+
+static long tmps_size = -1;
+
+STR *
+str_mortal(oldstr)
+STR *oldstr;
+{
+ register STR *str = Str_new(78,0);
+
+ str_sset(str,oldstr);
+ if (++tmps_max > tmps_size) {
+ tmps_size = tmps_max;
+ if (!(tmps_size & 127)) {
+ if (tmps_size)
+ Renew(tmps_list, tmps_size + 128, STR*);
+ else
+ New(702,tmps_list, 128, STR*);
+ }
+ }
+ tmps_list[tmps_max] = str;
+ if (str->str_pok)
+ str->str_pok |= SP_TEMP;
+ return str;
+}
+
+/* same thing without the copying */
+
+STR *
+str_2mortal(str)
+register STR *str;
+{
+ if (!str || str == &str_undef)
+ return str;
+ if (++tmps_max > tmps_size) {
+ tmps_size = tmps_max;
+ if (!(tmps_size & 127)) {
+ if (tmps_size)
+ Renew(tmps_list, tmps_size + 128, STR*);
+ else
+ New(704,tmps_list, 128, STR*);
+ }
+ }
+ tmps_list[tmps_max] = str;
+ if (str->str_pok)
+ str->str_pok |= SP_TEMP;
+ return str;
+}
+
+STR *
+str_make(s,len)
+char *s;
+STRLEN len;
+{
+ register STR *str = Str_new(79,0);
+
+ if (!len)
+ len = strlen(s);
+ str_nset(str,s,len);
+ return str;
+}
+
+STR *
+str_nmake(n)
+double n;
+{
+ register STR *str = Str_new(80,0);
+
+ str_numset(str,n);
+ return str;
+}
+
+/* make an exact duplicate of old */
+
+STR *
+str_smake(old)
+register STR *old;
+{
+ register STR *new = Str_new(81,0);
+
+ if (!old)
+ return Nullstr;
+ if (old->str_state == SS_FREE) {
+ warn("semi-panic: attempt to dup freed string");
+ return Nullstr;
+ }
+ if (old->str_state == SS_INCR && !(old->str_pok & 2))
+ Str_Grow(old,0);
+ if (new->str_ptr)
+ Safefree(new->str_ptr);
+ StructCopy(old,new,STR);
+ if (old->str_ptr) {
+ new->str_ptr = nsavestr(old->str_ptr,old->str_len);
+ new->str_pok &= ~SP_TEMP;
+ }
+ return new;
+}
+
+void
+str_reset(s,stash)
+register char *s;
+HASH *stash;
+{
+ register HENT *entry;
+ register STAB *stab;
+ register STR *str;
+ register int i;
+ register SPAT *spat;
+ register int max;
+
+ if (!*s) { /* reset ?? searches */
+ for (spat = stash->tbl_spatroot;
+ spat != Nullspat;
+ spat = spat->spat_next) {
+ spat->spat_flags &= ~SPAT_USED;
+ }
+ return;
+ }
+
+ /* reset variables */
+
+ if (!stash->tbl_array)
+ return;
+ while (*s) {
+ i = *s;
+ if (s[1] == '-') {
+ s += 2;
+ }
+ max = *s++;
+ for ( ; i <= max; i++) {
+ for (entry = stash->tbl_array[i];
+ entry;
+ entry = entry->hent_next) {
+ stab = (STAB*)entry->hent_val;
+ str = stab_val(stab);
+ str->str_cur = 0;
+ str->str_nok = 0;
+#ifdef TAINT
+ str->str_tainted = tainted;
+#endif
+ if (str->str_ptr != Nullch)
+ str->str_ptr[0] = '\0';
+ if (stab_xarray(stab)) {
+ aclear(stab_xarray(stab));
+ }
+ if (stab_xhash(stab)) {
+ hclear(stab_xhash(stab), FALSE);
+ if (stab == envstab)
+ environ[0] = Nullch;
+ }
+ }
+ }
+ }
+}
+
+#ifdef TAINT
+void
+taintproper(s)
+char *s;
+{
+#ifdef DEBUGGING
+ if (debug & 2048)
+ fprintf(stderr,"%s %d %d %d\n",s,tainted,uid, euid);
+#endif
+ if (tainted && (!euid || euid != uid || egid != gid || taintanyway)) {
+ if (!unsafe)
+ fatal("%s", s);
+ else if (dowarn)
+ warn("%s", s);
+ }
+}
+
+void
+taintenv()
+{
+ register STR *envstr;
+
+ envstr = hfetch(stab_hash(envstab),"PATH",4,FALSE);
+ if (envstr == &str_undef || envstr->str_tainted) {
+ tainted = 1;
+ if (envstr->str_tainted == 2)
+ taintproper("Insecure directory in PATH");
+ else
+ taintproper("Insecure PATH");
+ }
+ envstr = hfetch(stab_hash(envstab),"IFS",3,FALSE);
+ if (envstr != &str_undef && envstr->str_tainted) {
+ tainted = 1;
+ taintproper("Insecure IFS");
+ }
+}
+#endif /* TAINT */
diff --git a/gnu/usr.bin/perl/perl/str.h b/gnu/usr.bin/perl/perl/str.h
new file mode 100644
index 0000000..8e95749
--- /dev/null
+++ b/gnu/usr.bin/perl/perl/str.h
@@ -0,0 +1,174 @@
+/* $RCSfile: str.h,v $$Revision: 1.1.1.1 $$Date: 1994/09/10 06:27:35 $
+ *
+ * Copyright (c) 1991, Larry Wall
+ *
+ * You may distribute under the terms of either the GNU General Public
+ * License or the Artistic License, as specified in the README file.
+ *
+ * $Log: str.h,v $
+ * Revision 1.1.1.1 1994/09/10 06:27:35 gclarkii
+ * Initial import of Perl 4.046 bmaked
+ *
+ * Revision 1.1.1.1 1993/08/23 21:29:39 nate
+ * PERL!
+ *
+ * Revision 4.0.1.4 92/06/08 15:41:45 lwall
+ * patch20: fixed confusion between a *var's real name and its effective name
+ * patch20: removed implicit int declarations on functions
+ *
+ * Revision 4.0.1.3 91/11/05 18:41:47 lwall
+ * patch11: random cleanup
+ * patch11: solitary subroutine references no longer trigger typo warnings
+ *
+ * Revision 4.0.1.2 91/06/07 11:58:33 lwall
+ * patch4: new copyright notice
+ *
+ * Revision 4.0.1.1 91/04/12 09:16:12 lwall
+ * patch1: you may now use "die" and "caller" in a signal handler
+ *
+ * Revision 4.0 91/03/20 01:40:04 lwall
+ * 4.0 baseline.
+ *
+ */
+
+struct string {
+ char * str_ptr; /* pointer to malloced string */
+ STRLEN str_len; /* allocated size */
+ union {
+ double str_nval; /* numeric value, if any */
+ long str_useful; /* is this search optimization effective? */
+ ARG *str_args; /* list of args for interpreted string */
+ HASH *str_hash; /* string represents an assoc array (stab?) */
+ ARRAY *str_array; /* string represents an array */
+ CMD *str_cmd; /* command for this source line */
+ struct {
+ STAB *stb_stab; /* magic stab for magic "key" string */
+ HASH *stb_stash; /* which symbol table this stab is in */
+ } stb_u;
+ } str_u;
+ STRLEN str_cur; /* length of str_ptr as a C string */
+ STR *str_magic; /* while free, link to next free str */
+ /* while in use, ptr to "key" for magic items */
+ unsigned char str_pok; /* state of str_ptr */
+ unsigned char str_nok; /* state of str_nval */
+ unsigned char str_rare; /* used by search strings */
+ unsigned char str_state; /* one of SS_* below */
+ /* also used by search strings for backoff */
+#ifdef TAINT
+ bool str_tainted; /* 1 if possibly under control of $< */
+#endif
+};
+
+struct stab { /* should be identical, except for str_ptr */
+ STBP * str_ptr; /* pointer to malloced string */
+ STRLEN str_len; /* allocated size */
+ union {
+ double str_nval; /* numeric value, if any */
+ long str_useful; /* is this search optimization effective? */
+ ARG *str_args; /* list of args for interpreted string */
+ HASH *str_hash; /* string represents an assoc array (stab?) */
+ ARRAY *str_array; /* string represents an array */
+ CMD *str_cmd; /* command for this source line */
+ struct {
+ STAB *stb_stab; /* magic stab for magic "key" string */
+ HASH *stb_stash; /* which symbol table this stab is in */
+ } stb_u;
+ } str_u;
+ STRLEN str_cur; /* length of str_ptr as a C string */
+ STR *str_magic; /* while free, link to next free str */
+ /* while in use, ptr to "key" for magic items */
+ unsigned char str_pok; /* state of str_ptr */
+ unsigned char str_nok; /* state of str_nval */
+ unsigned char str_rare; /* used by search strings */
+ unsigned char str_state; /* one of SS_* below */
+ /* also used by search strings for backoff */
+#ifdef TAINT
+ bool str_tainted; /* 1 if possibly under control of $< */
+#endif
+};
+
+#define str_stab stb_u.stb_stab
+#define str_stash stb_u.stb_stash
+
+/* some extra info tacked to some lvalue strings */
+
+struct lstring {
+ struct string lstr;
+ STRLEN lstr_offset;
+ STRLEN lstr_len;
+};
+
+/* These are the values of str_pok: */
+#define SP_VALID 1 /* str_ptr is valid */
+#define SP_FBM 2 /* string was compiled for fbm search */
+#define SP_STUDIED 4 /* string was studied */
+#define SP_CASEFOLD 8 /* case insensitive fbm search */
+#define SP_INTRP 16 /* string was compiled for interping */
+#define SP_TAIL 32 /* fbm string is tail anchored: /foo$/ */
+#define SP_MULTI 64 /* symbol table entry probably isn't a typo */
+#define SP_TEMP 128 /* string slated to die, so can be plundered */
+
+#define Nullstr Null(STR*)
+
+/* These are the values of str_state: */
+#define SS_NORM 0 /* normal string */
+#define SS_INCR 1 /* normal string, incremented ptr */
+#define SS_SARY 2 /* array on save stack */
+#define SS_SHASH 3 /* associative array on save stack */
+#define SS_SINT 4 /* integer on save stack */
+#define SS_SLONG 5 /* long on save stack */
+#define SS_SSTRP 6 /* STR* on save stack */
+#define SS_SHPTR 7 /* HASH* on save stack */
+#define SS_SNSTAB 8 /* non-stab on save stack */
+#define SS_SCSV 9 /* callsave structure on save stack */
+#define SS_SAPTR 10 /* ARRAY* on save stack */
+#define SS_HASH 253 /* carrying an hash */
+#define SS_ARY 254 /* carrying an array */
+#define SS_FREE 255 /* in free list */
+/* str_state may have any value 0-255 when used to hold fbm pattern, in which */
+/* case it indicates offset to rarest character in screaminstr key */
+
+/* the following macro updates any magic values this str is associated with */
+
+#ifdef TAINT
+#define STABSET(x) \
+ (x)->str_tainted |= tainted; \
+ if ((x)->str_magic) \
+ stabset((x)->str_magic,(x))
+#else
+#define STABSET(x) \
+ if ((x)->str_magic) \
+ stabset((x)->str_magic,(x))
+#endif
+
+#define STR_SSET(dst,src) if (dst != src) str_sset(dst,src)
+
+EXT STR **tmps_list;
+EXT int tmps_max INIT(-1);
+EXT int tmps_base INIT(-1);
+
+char *str_2ptr();
+double str_2num();
+STR *str_mortal();
+STR *str_2mortal();
+STR *str_make();
+STR *str_nmake();
+STR *str_smake();
+int str_cmp();
+int str_eq();
+void str_magic();
+void str_insert();
+void str_numset();
+void str_sset();
+void str_nset();
+void str_set();
+void str_chop();
+void str_cat();
+void str_scat();
+void str_ncat();
+void str_reset();
+void str_taintproper();
+void str_taintenv();
+STRLEN str_len();
+
+#define MULTI (3)
diff --git a/gnu/usr.bin/perl/perl/t/README b/gnu/usr.bin/perl/perl/t/README
new file mode 100644
index 0000000..47ab845
--- /dev/null
+++ b/gnu/usr.bin/perl/perl/t/README
@@ -0,0 +1,11 @@
+This is the perl test library. To run all the tests, just type 'TEST'.
+
+To add new tests, just look at the current tests and do likewise.
+
+If a test fails, run it by itself to see if it prints any informative
+diagnostics. If not, modify the test to print informative diagnostics.
+If you put out extra lines with a '#' character on the front, you don't
+have to worry about removing the extra print statements later since TEST
+ignores lines beginning with '#'.
+
+If you come up with new tests, send them to lwall@netlabs.com.
diff --git a/gnu/usr.bin/perl/perl/t/TEST b/gnu/usr.bin/perl/perl/t/TEST
new file mode 100755
index 0000000..957a868
--- /dev/null
+++ b/gnu/usr.bin/perl/perl/t/TEST
@@ -0,0 +1,102 @@
+#!./perl
+
+# $RCSfile: TEST,v $$Revision: 1.1.1.1 $$Date: 1993/08/23 21:30:01 $
+
+# This is written in a peculiar style, since we're trying to avoid
+# most of the constructs we'll be testing for.
+
+$| = 1;
+
+if ($ARGV[0] eq '-v') {
+ $verbose = 1;
+ shift;
+}
+
+chdir 't' if -f 't/TEST';
+
+if ($ARGV[0] eq '') {
+ @ARGV = split(/[ \n]/,
+ `echo base/*.t comp/*.t cmd/*.t io/*.t; echo op/*.t lib/*.t`);
+}
+
+open(CONFIG,"../config.sh");
+while (<CONFIG>) {
+ if (/sharpbang='(.*)'/) {
+ $sharpbang = ($1 eq '#!');
+ last;
+ }
+}
+$bad = 0;
+while ($test = shift) {
+ if ($test =~ /^$/) {
+ next;
+ }
+ $te = $test;
+ chop($te);
+ print "$te" . '.' x (15 - length($te));
+ if ($sharpbang) {
+ open(results,"./$test|") || (print "can't run.\n");
+ } else {
+ open(script,"$test") || die "Can't run $test.\n";
+ $_ = <script>;
+ close(script);
+ if (/#!..perl(.*)/) {
+ $switch = $1;
+ } else {
+ $switch = '';
+ }
+ open(results,"./perl$switch $test|") || (print "can't run.\n");
+ }
+ $ok = 0;
+ $next = 0;
+ while (<results>) {
+ if ($verbose) {
+ print $_;
+ }
+ unless (/^#/) {
+ if (/^1\.\.([0-9]+)/) {
+ $max = $1;
+ $totmax += $max;
+ $files += 1;
+ $next = 1;
+ $ok = 1;
+ } else {
+ $next = $1, $ok = 0, last if /^not ok ([0-9]*)/;
+ if (/^ok (.*)/ && $1 == $next) {
+ $next = $next + 1;
+ } else {
+ $ok = 0;
+ }
+ }
+ }
+ }
+ $next = $next - 1;
+ if ($ok && $next == $max) {
+ print "ok\n";
+ } else {
+ $next += 1;
+ print "FAILED on test $next\n";
+ $bad = $bad + 1;
+ $_ = $test;
+ if (/^base/) {
+ die "Failed a basic test--cannot continue.\n";
+ }
+ }
+}
+
+if ($bad == 0) {
+ if ($ok) {
+ print "All tests successful.\n";
+ } else {
+ die "FAILED--no tests were run for some reason.\n";
+ }
+} else {
+ if ($bad == 1) {
+ die "Failed 1 test.\n";
+ } else {
+ die "Failed $bad tests.\n";
+ }
+}
+($user,$sys,$cuser,$csys) = times;
+print sprintf("u=%g s=%g cu=%g cs=%g files=%d tests=%d\n",
+ $user,$sys,$cuser,$csys,$files,$totmax);
diff --git a/gnu/usr.bin/perl/perl/t/base/cond.t b/gnu/usr.bin/perl/perl/t/base/cond.t
new file mode 100755
index 0000000..7d49f4e
--- /dev/null
+++ b/gnu/usr.bin/perl/perl/t/base/cond.t
@@ -0,0 +1,19 @@
+#!./perl
+
+# $Header: /home/cvs/386BSD/ports/lang/perl/t/base/cond.t,v 1.1.1.1 1993/08/23 21:30:05 nate Exp $
+
+# make sure conditional operators work
+
+print "1..4\n";
+
+$x = '0';
+
+$x eq $x && (print "ok 1\n");
+$x ne $x && (print "not ok 1\n");
+$x eq $x || (print "not ok 2\n");
+$x ne $x || (print "ok 2\n");
+
+$x == $x && (print "ok 3\n");
+$x != $x && (print "not ok 3\n");
+$x == $x || (print "not ok 4\n");
+$x != $x || (print "ok 4\n");
diff --git a/gnu/usr.bin/perl/perl/t/base/if.t b/gnu/usr.bin/perl/perl/t/base/if.t
new file mode 100755
index 0000000..2a9b82c
--- /dev/null
+++ b/gnu/usr.bin/perl/perl/t/base/if.t
@@ -0,0 +1,11 @@
+#!./perl
+
+# $Header: /home/cvs/386BSD/ports/lang/perl/t/base/if.t,v 1.1.1.1 1993/08/23 21:30:05 nate Exp $
+
+print "1..2\n";
+
+# first test to see if we can run the tests.
+
+$x = 'test';
+if ($x eq $x) { print "ok 1\n"; } else { print "not ok 1\n";}
+if ($x ne $x) { print "not ok 2\n"; } else { print "ok 2\n";}
diff --git a/gnu/usr.bin/perl/perl/t/base/lex.t b/gnu/usr.bin/perl/perl/t/base/lex.t
new file mode 100755
index 0000000..cd6321d
--- /dev/null
+++ b/gnu/usr.bin/perl/perl/t/base/lex.t
@@ -0,0 +1,78 @@
+#!./perl
+
+# $Header: /home/cvs/386BSD/ports/lang/perl/t/base/lex.t,v 1.1.1.1 1993/08/23 21:30:05 nate Exp $
+
+print "1..18\n";
+
+$ # this is the register <space>
+= 'x';
+
+print "#1 :$ : eq :x:\n";
+if ($ eq 'x') {print "ok 1\n";} else {print "not ok 1\n";}
+
+$x = $#; # this is the register $#
+
+if ($x eq '') {print "ok 2\n";} else {print "not ok 2\n";}
+
+$x = $#x;
+
+if ($x eq '-1') {print "ok 3\n";} else {print "not ok 3\n";}
+
+$x = '\\'; # ';
+
+if (length($x) == 1) {print "ok 4\n";} else {print "not ok 4\n";}
+
+eval 'while (0) {
+ print "foo\n";
+}
+/^/ && (print "ok 5\n");
+';
+
+eval '$foo{1} / 1;';
+if (!$@) {print "ok 6\n";} else {print "not ok 6\n";}
+
+eval '$foo = 123+123.4+123e4+123.4E5+123.4e+5+.12;';
+
+$foo = int($foo * 100 + .5);
+if ($foo eq 2591024652) {print "ok 7\n";} else {print "not ok 7 :$foo:\n";}
+
+print <<'EOF';
+ok 8
+EOF
+
+$foo = 'ok 9';
+print <<EOF;
+$foo
+EOF
+
+eval <<\EOE, print $@;
+print <<'EOF';
+ok 10
+EOF
+
+$foo = 'ok 11';
+print <<EOF;
+$foo
+EOF
+EOE
+
+print <<`EOS` . <<\EOF;
+echo ok 12
+EOS
+ok 13
+EOF
+
+print qq/ok 14\n/;
+print qq(ok 15\n);
+
+print qq
+ok 16\n
+;
+
+print q<ok 17
+>;
+
+print <<; # Yow!
+ok 18
+
+# previous line intentionally left blank.
diff --git a/gnu/usr.bin/perl/perl/t/base/pat.t b/gnu/usr.bin/perl/perl/t/base/pat.t
new file mode 100755
index 0000000..2c8d9a9
--- /dev/null
+++ b/gnu/usr.bin/perl/perl/t/base/pat.t
@@ -0,0 +1,11 @@
+#!./perl
+
+# $Header: /home/cvs/386BSD/ports/lang/perl/t/base/pat.t,v 1.1.1.1 1993/08/23 21:30:05 nate Exp $
+
+print "1..2\n";
+
+# first test to see if we can run the tests.
+
+$_ = 'test';
+if (/^test/) { print "ok 1\n"; } else { print "not ok 1\n";}
+if (/^foo/) { print "not ok 2\n"; } else { print "ok 2\n";}
diff --git a/gnu/usr.bin/perl/perl/t/base/term.t b/gnu/usr.bin/perl/perl/t/base/term.t
new file mode 100755
index 0000000..c049c58
--- /dev/null
+++ b/gnu/usr.bin/perl/perl/t/base/term.t
@@ -0,0 +1,42 @@
+#!./perl
+
+# $Header: /home/cvs/386BSD/ports/lang/perl/t/base/term.t,v 1.1.1.1 1993/08/23 21:30:05 nate Exp $
+
+print "1..6\n";
+
+# check "" interpretation
+
+$x = "\n";
+if ($x lt ' ') {print "ok 1\n";} else {print "not ok 1\n";}
+
+# check `` processing
+
+$x = `echo hi there`;
+if ($x eq "hi there\n") {print "ok 2\n";} else {print "not ok 2\n";}
+
+# check $#array
+
+$x[0] = 'foo';
+$x[1] = 'foo';
+$tmp = $#x;
+print "#3\t:$tmp: == :1:\n";
+if ($#x == '1') {print "ok 3\n";} else {print "not ok 3\n";}
+
+# check numeric literal
+
+$x = 1;
+if ($x == '1') {print "ok 4\n";} else {print "not ok 4\n";}
+
+# check <> pseudoliteral
+
+open(try, "/dev/null") || (die "Can't open /dev/null.");
+if (<try> eq '') {
+ print "ok 5\n";
+}
+else {
+ print "not ok 5\n";
+ die "/dev/null IS NOT A CHARACTER SPECIAL FILE!!!!\n" unless -c '/dev/null';
+}
+
+open(try, "../Makefile") || (die "Can't open ../Makefile.");
+if (<try> ne '') {print "ok 6\n";} else {print "not ok 6\n";}
diff --git a/gnu/usr.bin/perl/perl/t/cmd/elsif.t b/gnu/usr.bin/perl/perl/t/cmd/elsif.t
new file mode 100755
index 0000000..0e3457f
--- /dev/null
+++ b/gnu/usr.bin/perl/perl/t/cmd/elsif.t
@@ -0,0 +1,25 @@
+#!./perl
+
+# $Header: /home/cvs/386BSD/ports/lang/perl/t/cmd/elsif.t,v 1.1.1.1 1993/08/23 21:30:05 nate Exp $
+
+sub foo {
+ if ($_[0] == 1) {
+ 1;
+ }
+ elsif ($_[0] == 2) {
+ 2;
+ }
+ elsif ($_[0] == 3) {
+ 3;
+ }
+ else {
+ 4;
+ }
+}
+
+print "1..4\n";
+
+if (($x = do foo(1)) == 1) {print "ok 1\n";} else {print "not ok 1 '$x'\n";}
+if (($x = do foo(2)) == 2) {print "ok 2\n";} else {print "not ok 2 '$x'\n";}
+if (($x = do foo(3)) == 3) {print "ok 3\n";} else {print "not ok 3 '$x'\n";}
+if (($x = do foo(4)) == 4) {print "ok 4\n";} else {print "not ok 4 '$x'\n";}
diff --git a/gnu/usr.bin/perl/perl/t/cmd/for.t b/gnu/usr.bin/perl/perl/t/cmd/for.t
new file mode 100755
index 0000000..4a0c922
--- /dev/null
+++ b/gnu/usr.bin/perl/perl/t/cmd/for.t
@@ -0,0 +1,49 @@
+#!./perl
+
+# $Header: /home/cvs/386BSD/ports/lang/perl/t/cmd/for.t,v 1.1.1.1 1993/08/23 21:30:05 nate Exp $
+
+print "1..7\n";
+
+for ($i = 0; $i <= 10; $i++) {
+ $x[$i] = $i;
+}
+$y = $x[10];
+print "#1 :$y: eq :10:\n";
+$y = join(' ', @x);
+print "#1 :$y: eq :0 1 2 3 4 5 6 7 8 9 10:\n";
+if (join(' ', @x) eq '0 1 2 3 4 5 6 7 8 9 10') {
+ print "ok 1\n";
+} else {
+ print "not ok 1\n";
+}
+
+$i = $c = 0;
+for (;;) {
+ $c++;
+ last if $i++ > 10;
+}
+if ($c == 12) {print "ok 2\n";} else {print "not ok 2\n";}
+
+$foo = 3210;
+@ary = (1,2,3,4,5);
+foreach $foo (@ary) {
+ $foo *= 2;
+}
+if (join('',@ary) eq '246810') {print "ok 3\n";} else {print "not ok 3\n";}
+
+for (@ary) {
+ s/(.*)/ok $1\n/;
+}
+
+print $ary[1];
+
+# test for internal scratch array generation
+# this also tests that $foo was restored to 3210 after test 3
+for (split(' ','a b c d e')) {
+ $foo .= $_;
+}
+if ($foo eq '3210abcde') {print "ok 5\n";} else {print "not ok 5 $foo\n";}
+
+foreach $foo (("ok 6\n","ok 7\n")) {
+ print $foo;
+}
diff --git a/gnu/usr.bin/perl/perl/t/cmd/mod.t b/gnu/usr.bin/perl/perl/t/cmd/mod.t
new file mode 100755
index 0000000..eeb44d9
--- /dev/null
+++ b/gnu/usr.bin/perl/perl/t/cmd/mod.t
@@ -0,0 +1,33 @@
+#!./perl
+
+# $Header: /home/cvs/386BSD/ports/lang/perl/t/cmd/mod.t,v 1.1.1.1 1993/08/23 21:30:05 nate Exp $
+
+print "1..7\n";
+
+print "ok 1\n" if 1;
+print "not ok 1\n" unless 1;
+
+print "ok 2\n" unless 0;
+print "not ok 2\n" if 0;
+
+1 && (print "not ok 3\n") if 0;
+1 && (print "ok 3\n") if 1;
+0 || (print "not ok 4\n") if 0;
+0 || (print "ok 4\n") if 1;
+
+$x = 0;
+do {$x[$x] = $x;} while ($x++) < 10;
+if (join(' ',@x) eq '0 1 2 3 4 5 6 7 8 9 10') {
+ print "ok 5\n";
+} else {
+ print "not ok 5\n";
+}
+
+$x = 15;
+$x = 10 while $x < 10;
+if ($x == 15) {print "ok 6\n";} else {print "not ok 6\n";}
+
+open(foo,'TEST') || open(foo,'t/TEST');
+$x = 0;
+$x++ while <foo>;
+print $x > 50 && $x < 1000 ? "ok 7\n" : "not ok 7\n";
diff --git a/gnu/usr.bin/perl/perl/t/cmd/subval.t b/gnu/usr.bin/perl/perl/t/cmd/subval.t
new file mode 100755
index 0000000..f7f411b
--- /dev/null
+++ b/gnu/usr.bin/perl/perl/t/cmd/subval.t
@@ -0,0 +1,179 @@
+#!./perl
+
+# $RCSfile: subval.t,v $$Revision: 1.1.1.1 $$Date: 1993/08/23 21:30:05 $
+
+sub foo1 {
+ 'true1';
+ if ($_[0]) { 'true2'; }
+}
+
+sub foo2 {
+ 'true1';
+ if ($_[0]) { return 'true2'; } else { return 'true3'; }
+ 'true0';
+}
+
+sub foo3 {
+ 'true1';
+ unless ($_[0]) { 'true2'; }
+}
+
+sub foo4 {
+ 'true1';
+ unless ($_[0]) { 'true2'; } else { 'true3'; }
+}
+
+sub foo5 {
+ 'true1';
+ 'true2' if $_[0];
+}
+
+sub foo6 {
+ 'true1';
+ 'true2' unless $_[0];
+}
+
+print "1..34\n";
+
+if (do foo1(0) eq '0') {print "ok 1\n";} else {print "not ok 1 $foo\n";}
+if (do foo1(1) eq 'true2') {print "ok 2\n";} else {print "not ok 2\n";}
+if (do foo2(0) eq 'true3') {print "ok 3\n";} else {print "not ok 3\n";}
+if (do foo2(1) eq 'true2') {print "ok 4\n";} else {print "not ok 4\n";}
+
+if (do foo3(0) eq 'true2') {print "ok 5\n";} else {print "not ok 5\n";}
+if (do foo3(1) eq '1') {print "ok 6\n";} else {print "not ok 6\n";}
+if (do foo4(0) eq 'true2') {print "ok 7\n";} else {print "not ok 7\n";}
+if (do foo4(1) eq 'true3') {print "ok 8\n";} else {print "not ok 8\n";}
+
+if (do foo5(0) eq '0') {print "ok 9\n";} else {print "not ok 9\n";}
+if (do foo5(1) eq 'true2') {print "ok 10\n";} else {print "not ok 10\n";}
+if (do foo6(0) eq 'true2') {print "ok 11\n";} else {print "not ok 11\n";}
+if (do foo6(1) eq '1') {print "ok 12\n";} else {print "not ok 12 $x\n";}
+
+# Now test to see that recursion works using a Fibonacci number generator
+
+sub fib {
+ local($arg) = @_;
+ local($foo);
+ $level++;
+ if ($arg <= 2) {
+ $foo = 1;
+ }
+ else {
+ $foo = do fib($arg-1) + do fib($arg-2);
+ }
+ $level--;
+ $foo;
+}
+
+@good = (0,1,1,2,3,5,8,13,21,34,55,89);
+
+for ($i = 1; $i <= 10; $i++) {
+ $foo = $i + 12;
+ if (do fib($i) == $good[$i]) {
+ print "ok $foo\n";
+ }
+ else {
+ print "not ok $foo\n";
+ }
+}
+
+sub ary1 {
+ (1,2,3);
+}
+
+print &ary1 eq 3 ? "ok 23\n" : "not ok 23\n";
+
+print join(':',&ary1) eq '1:2:3' ? "ok 24\n" : "not ok 24\n";
+
+sub ary2 {
+ do {
+ return (1,2,3);
+ (3,2,1);
+ };
+ 0;
+}
+
+print &ary2 eq 3 ? "ok 25\n" : "not ok 25\n";
+
+$x = join(':',&ary2);
+print $x eq '1:2:3' ? "ok 26\n" : "not ok 26 $x\n";
+
+sub somesub {
+ local($num,$P,$F,$L) = @_;
+ ($p,$f,$l) = caller;
+ print "$p:$f:$l" eq "$P:$F:$L" ? "ok $num\n" : "not ok $num $p:$f:$l ne $P:$F:$L\n";
+}
+
+&somesub(27, 'main', __FILE__, __LINE__);
+
+package foo;
+&main'somesub(28, 'foo', __FILE__, __LINE__);
+
+package main;
+$i = 28;
+open(FOO,">Cmd_subval.tmp");
+print FOO "blah blah\n";
+close FOO;
+
+&file_main(*F);
+close F;
+&info_main;
+
+&file_package(*F);
+close F;
+&info_package;
+
+unlink 'Cmd_subval.tmp';
+
+sub file_main {
+ local(*F) = @_;
+
+ open(F, 'Cmd_subval.tmp') || die "can't open\n";
+ $i++;
+ eof F ? print "not ok $i\n" : print "ok $i\n";
+}
+
+sub info_main {
+ local(*F);
+
+ open(F, 'Cmd_subval.tmp') || die "test: can't open\n";
+ $i++;
+ eof F ? print "not ok $i\n" : print "ok $i\n";
+ &iseof(*F);
+ close F;
+}
+
+sub iseof {
+ local(*UNIQ) = @_;
+
+ $i++;
+ eof UNIQ ? print "(not ok $i)\n" : print "ok $i\n";
+}
+
+{package foo;
+
+ sub main'file_package {
+ local(*F) = @_;
+
+ open(F, 'Cmd_subval.tmp') || die "can't open\n";
+ $main'i++;
+ eof F ? print "not ok $main'i\n" : print "ok $main'i\n";
+ }
+
+ sub main'info_package {
+ local(*F);
+
+ open(F, 'Cmd_subval.tmp') || die "can't open\n";
+ $main'i++;
+ eof F ? print "not ok $main'i\n" : print "ok $main'i\n";
+ &iseof(*F);
+ }
+
+ sub iseof {
+ local(*UNIQ) = @_;
+
+ $main'i++;
+ eof UNIQ ? print "not ok $main'i\n" : print "ok $main'i\n";
+ }
+}
diff --git a/gnu/usr.bin/perl/perl/t/cmd/switch.t b/gnu/usr.bin/perl/perl/t/cmd/switch.t
new file mode 100755
index 0000000..d0d4c93
--- /dev/null
+++ b/gnu/usr.bin/perl/perl/t/cmd/switch.t
@@ -0,0 +1,75 @@
+#!./perl
+
+# $Header: /home/cvs/386BSD/ports/lang/perl/t/cmd/switch.t,v 1.1.1.1 1993/08/23 21:30:05 nate Exp $
+
+print "1..18\n";
+
+sub foo1 {
+ $_ = shift(@_);
+ $a = 0;
+ until ($a++) {
+ next if $_ eq 1;
+ next if $_ eq 2;
+ next if $_ eq 3;
+ next if $_ eq 4;
+ return 20;
+ }
+ continue {
+ return $_;
+ }
+}
+
+print do foo1(0) == 20 ? "ok 1\n" : "not ok 1\n";
+print do foo1(1) == 1 ? "ok 2\n" : "not ok 2\n";
+print do foo1(2) == 2 ? "ok 3\n" : "not ok 3\n";
+print do foo1(3) == 3 ? "ok 4\n" : "not ok 4\n";
+print do foo1(4) == 4 ? "ok 5\n" : "not ok 5\n";
+print do foo1(5) == 20 ? "ok 6\n" : "not ok 6\n";
+
+sub foo2 {
+ $_ = shift(@_);
+ {
+ last if $_ == 1;
+ last if $_ == 2;
+ last if $_ == 3;
+ last if $_ == 4;
+ }
+ continue {
+ return 20;
+ }
+ return $_;
+}
+
+print do foo2(0) == 20 ? "ok 7\n" : "not ok 1\n";
+print do foo2(1) == 1 ? "ok 8\n" : "not ok 8\n";
+print do foo2(2) == 2 ? "ok 9\n" : "not ok 9\n";
+print do foo2(3) == 3 ? "ok 10\n" : "not ok 10\n";
+print do foo2(4) == 4 ? "ok 11\n" : "not ok 11\n";
+print do foo2(5) == 20 ? "ok 12\n" : "not ok 12\n";
+
+sub foo3 {
+ $_ = shift(@_);
+ if (/^1/) {
+ return 1;
+ }
+ elsif (/^2/) {
+ return 2;
+ }
+ elsif (/^3/) {
+ return 3;
+ }
+ elsif (/^4/) {
+ return 4;
+ }
+ else {
+ return 20;
+ }
+ return 40;
+}
+
+print do foo3(0) == 20 ? "ok 13\n" : "not ok 13\n";
+print do foo3(1) == 1 ? "ok 14\n" : "not ok 14\n";
+print do foo3(2) == 2 ? "ok 15\n" : "not ok 15\n";
+print do foo3(3) == 3 ? "ok 16\n" : "not ok 16\n";
+print do foo3(4) == 4 ? "ok 17\n" : "not ok 17\n";
+print do foo3(5) == 20 ? "ok 18\n" : "not ok 18\n";
diff --git a/gnu/usr.bin/perl/perl/t/cmd/while.t b/gnu/usr.bin/perl/perl/t/cmd/while.t
new file mode 100755
index 0000000..006e251
--- /dev/null
+++ b/gnu/usr.bin/perl/perl/t/cmd/while.t
@@ -0,0 +1,110 @@
+#!./perl
+
+# $Header: /home/cvs/386BSD/ports/lang/perl/t/cmd/while.t,v 1.1.1.1 1993/08/23 21:30:05 nate Exp $
+
+print "1..10\n";
+
+open (tmp,'>Cmd.while.tmp') || die "Can't create Cmd.while.tmp.";
+print tmp "tvi925\n";
+print tmp "tvi920\n";
+print tmp "vt100\n";
+print tmp "Amiga\n";
+print tmp "paper\n";
+close tmp;
+
+# test "last" command
+
+open(fh,'Cmd.while.tmp') || die "Can't open Cmd.while.tmp.";
+while (<fh>) {
+ last if /vt100/;
+}
+if (!eof && /vt100/) {print "ok 1\n";} else {print "not ok 1 $_\n";}
+
+# test "next" command
+
+$bad = '';
+open(fh,'Cmd.while.tmp') || die "Can't open Cmd.while.tmp.";
+while (<fh>) {
+ next if /vt100/;
+ $bad = 1 if /vt100/;
+}
+if (!eof || /vt100/ || $bad) {print "not ok 2\n";} else {print "ok 2\n";}
+
+# test "redo" command
+
+$bad = '';
+open(fh,'Cmd.while.tmp') || die "Can't open Cmd.while.tmp.";
+while (<fh>) {
+ if (s/vt100/VT100/g) {
+ s/VT100/Vt100/g;
+ redo;
+ }
+ $bad = 1 if /vt100/;
+ $bad = 1 if /VT100/;
+}
+if (!eof || $bad) {print "not ok 3\n";} else {print "ok 3\n";}
+
+# now do the same with a label and a continue block
+
+# test "last" command
+
+$badcont = '';
+open(fh,'Cmd.while.tmp') || die "Can't open Cmd.while.tmp.";
+line: while (<fh>) {
+ if (/vt100/) {last line;}
+} continue {
+ $badcont = 1 if /vt100/;
+}
+if (!eof && /vt100/) {print "ok 4\n";} else {print "not ok 4\n";}
+if (!$badcont) {print "ok 5\n";} else {print "not ok 5\n";}
+
+# test "next" command
+
+$bad = '';
+$badcont = 1;
+open(fh,'Cmd.while.tmp') || die "Can't open Cmd.while.tmp.";
+entry: while (<fh>) {
+ next entry if /vt100/;
+ $bad = 1 if /vt100/;
+} continue {
+ $badcont = '' if /vt100/;
+}
+if (!eof || /vt100/ || $bad) {print "not ok 6\n";} else {print "ok 6\n";}
+if (!$badcont) {print "ok 7\n";} else {print "not ok 7\n";}
+
+# test "redo" command
+
+$bad = '';
+$badcont = '';
+open(fh,'Cmd.while.tmp') || die "Can't open Cmd.while.tmp.";
+loop: while (<fh>) {
+ if (s/vt100/VT100/g) {
+ s/VT100/Vt100/g;
+ redo loop;
+ }
+ $bad = 1 if /vt100/;
+ $bad = 1 if /VT100/;
+} continue {
+ $badcont = 1 if /vt100/;
+}
+if (!eof || $bad) {print "not ok 8\n";} else {print "ok 8\n";}
+if (!$badcont) {print "ok 9\n";} else {print "not ok 9\n";}
+
+`/bin/rm -f Cmd.while.tmp`;
+
+#$x = 0;
+#while (1) {
+# if ($x > 1) {last;}
+# next;
+#} continue {
+# if ($x++ > 10) {last;}
+# next;
+#}
+#
+#if ($x < 10) {print "ok 10\n";} else {print "not ok 10\n";}
+
+$i = 9;
+{
+ $i++;
+}
+print "ok $i\n";
diff --git a/gnu/usr.bin/perl/perl/t/comp/cmdopt.t b/gnu/usr.bin/perl/perl/t/comp/cmdopt.t
new file mode 100755
index 0000000..3c47130
--- /dev/null
+++ b/gnu/usr.bin/perl/perl/t/comp/cmdopt.t
@@ -0,0 +1,83 @@
+#!./perl
+
+# $Header: /home/cvs/386BSD/ports/lang/perl/t/comp/cmdopt.t,v 1.1.1.1 1993/08/23 21:30:06 nate Exp $
+
+print "1..40\n";
+
+# test the optimization of constants
+
+if (1) { print "ok 1\n";} else { print "not ok 1\n";}
+unless (0) { print "ok 2\n";} else { print "not ok 2\n";}
+
+if (0) { print "not ok 3\n";} else { print "ok 3\n";}
+unless (1) { print "not ok 4\n";} else { print "ok 4\n";}
+
+unless (!1) { print "ok 5\n";} else { print "not ok 5\n";}
+if (!0) { print "ok 6\n";} else { print "not ok 6\n";}
+
+unless (!0) { print "not ok 7\n";} else { print "ok 7\n";}
+if (!1) { print "not ok 8\n";} else { print "ok 8\n";}
+
+$x = 1;
+if (1 && $x) { print "ok 9\n";} else { print "not ok 9\n";}
+if (0 && $x) { print "not ok 10\n";} else { print "ok 10\n";}
+$x = '';
+if (1 && $x) { print "not ok 11\n";} else { print "ok 11\n";}
+if (0 && $x) { print "not ok 12\n";} else { print "ok 12\n";}
+
+$x = 1;
+if (1 || $x) { print "ok 13\n";} else { print "not ok 13\n";}
+if (0 || $x) { print "ok 14\n";} else { print "not ok 14\n";}
+$x = '';
+if (1 || $x) { print "ok 15\n";} else { print "not ok 15\n";}
+if (0 || $x) { print "not ok 16\n";} else { print "ok 16\n";}
+
+
+# test the optimization of registers
+
+$x = 1;
+if ($x) { print "ok 17\n";} else { print "not ok 17\n";}
+unless ($x) { print "not ok 18\n";} else { print "ok 18\n";}
+
+$x = '';
+if ($x) { print "not ok 19\n";} else { print "ok 19\n";}
+unless ($x) { print "ok 20\n";} else { print "not ok 20\n";}
+
+# test optimization of string operations
+
+$a = 'a';
+if ($a eq 'a') { print "ok 21\n";} else { print "not ok 21\n";}
+if ($a ne 'a') { print "not ok 22\n";} else { print "ok 22\n";}
+
+if ($a =~ /a/) { print "ok 23\n";} else { print "not ok 23\n";}
+if ($a !~ /a/) { print "not ok 24\n";} else { print "ok 24\n";}
+# test interaction of logicals and other operations
+
+$a = 'a';
+$x = 1;
+if ($a eq 'a' && $x) { print "ok 25\n";} else { print "not ok 25\n";}
+if ($a ne 'a' && $x) { print "not ok 26\n";} else { print "ok 26\n";}
+$x = '';
+if ($a eq 'a' && $x) { print "not ok 27\n";} else { print "ok 27\n";}
+if ($a ne 'a' && $x) { print "not ok 28\n";} else { print "ok 28\n";}
+
+$x = 1;
+if ($a eq 'a' || $x) { print "ok 29\n";} else { print "not ok 29\n";}
+if ($a ne 'a' || $x) { print "ok 30\n";} else { print "not ok 30\n";}
+$x = '';
+if ($a eq 'a' || $x) { print "ok 31\n";} else { print "not ok 31\n";}
+if ($a ne 'a' || $x) { print "not ok 32\n";} else { print "ok 32\n";}
+
+$x = 1;
+if ($a =~ /a/ && $x) { print "ok 33\n";} else { print "not ok 33\n";}
+if ($a !~ /a/ && $x) { print "not ok 34\n";} else { print "ok 34\n";}
+$x = '';
+if ($a =~ /a/ && $x) { print "not ok 35\n";} else { print "ok 35\n";}
+ if ($a !~ /a/ && $x) { print "not ok 36\n";} else { print "ok 36\n";}
+
+$x = 1;
+if ($a =~ /a/ || $x) { print "ok 37\n";} else { print "not ok 37\n";}
+if ($a !~ /a/ || $x) { print "ok 38\n";} else { print "not ok 38\n";}
+$x = '';
+if ($a =~ /a/ || $x) { print "ok 39\n";} else { print "not ok 39\n";}
+if ($a !~ /a/ || $x) { print "not ok 40\n";} else { print "ok 40\n";}
diff --git a/gnu/usr.bin/perl/perl/t/comp/cpp.t b/gnu/usr.bin/perl/perl/t/comp/cpp.t
new file mode 100755
index 0000000..8cceb73
--- /dev/null
+++ b/gnu/usr.bin/perl/perl/t/comp/cpp.t
@@ -0,0 +1,51 @@
+#!./perl -P
+
+# $RCSfile: cpp.t,v $$Revision: 1.1.1.1 $$Date: 1993/08/23 21:30:06 $
+
+open(CONFIG,"../config.sh") || die;
+while (<CONFIG>) {
+ if (/^cppstdin/) {
+ if (/^cppstdin='(.*cppstdin)'/ && ! -e $1) {
+ print "1..0\n";
+ exit; # Can't test till after install, alas.
+ }
+ last;
+ }
+}
+close CONFIG;
+
+print "1..3\n";
+
+#this is a comment
+#define MESS "ok 1\n"
+print MESS;
+
+#If you capitalize, it's a comment.
+#ifdef MESS
+ print "ok 2\n";
+#else
+ print "not ok 2\n";
+#endif
+
+open(TRY,">Comp.cpp.tmp") || die "Can't open temp perl file.";
+
+($prog = <<'END') =~ s/X//g;
+X$ok = "not ok 3\n";
+X#include "Comp.cpp.inc"
+X#ifdef OK
+X$ok = OK;
+X#endif
+Xprint $ok;
+END
+print TRY $prog;
+close TRY;
+
+open(TRY,">Comp.cpp.inc") || (die "Can't open temp include file.");
+print TRY '#define OK "ok 3\n"' . "\n";
+close TRY;
+
+$pwd=`pwd`;
+$pwd =~ s/\n//;
+$x = `./perl -P Comp.cpp.tmp`;
+print $x;
+unlink "Comp.cpp.tmp", "Comp.cpp.inc";
diff --git a/gnu/usr.bin/perl/perl/t/comp/decl.t b/gnu/usr.bin/perl/perl/t/comp/decl.t
new file mode 100755
index 0000000..f1c84c2
--- /dev/null
+++ b/gnu/usr.bin/perl/perl/t/comp/decl.t
@@ -0,0 +1,49 @@
+#!./perl
+
+# $Header: /home/cvs/386BSD/ports/lang/perl/t/comp/decl.t,v 1.1.1.1 1993/08/23 21:30:07 nate Exp $
+
+# check to see if subroutine declarations work everwhere
+
+sub one {
+ print "ok 1\n";
+}
+format one =
+ok 5
+.
+
+print "1..7\n";
+
+do one();
+do two();
+
+sub two {
+ print "ok 2\n";
+}
+format two =
+@<<<
+$foo
+.
+
+if ($x eq $x) {
+ sub three {
+ print "ok 3\n";
+ }
+ do three();
+}
+
+do four();
+$~ = 'one';
+write;
+$~ = 'two';
+$foo = "ok 6";
+write;
+$~ = 'three';
+write;
+
+format three =
+ok 7
+.
+
+sub four {
+ print "ok 4\n";
+}
diff --git a/gnu/usr.bin/perl/perl/t/comp/multiline.t b/gnu/usr.bin/perl/perl/t/comp/multiline.t
new file mode 100755
index 0000000..78df482
--- /dev/null
+++ b/gnu/usr.bin/perl/perl/t/comp/multiline.t
@@ -0,0 +1,40 @@
+#!./perl
+
+# $Header: /home/cvs/386BSD/ports/lang/perl/t/comp/multiline.t,v 1.1.1.1 1993/08/23 21:30:06 nate Exp $
+
+print "1..5\n";
+
+open(try,'>Comp.try') || (die "Can't open temp file.");
+
+$x = 'now is the time
+for all good men
+to come to.
+';
+
+$y = 'now is the time' . "\n" .
+'for all good men' . "\n" .
+'to come to.' . "\n";
+
+if ($x eq $y) {print "ok 1\n";} else {print "not ok 1\n";}
+
+print try $x;
+close try;
+
+open(try,'Comp.try') || (die "Can't reopen temp file.");
+$count = 0;
+$z = '';
+while (<try>) {
+ $z .= $_;
+ $count = $count + 1;
+}
+
+if ($z eq $y) {print "ok 2\n";} else {print "not ok 2\n";}
+
+if ($count == 3) {print "ok 3\n";} else {print "not ok 3\n";}
+
+$_ = `cat Comp.try`;
+
+if (/.*\n.*\n.*\n$/) {print "ok 4\n";} else {print "not ok 4\n";}
+`/bin/rm -f Comp.try`;
+
+if ($_ eq $y) {print "ok 5\n";} else {print "not ok 5\n";}
diff --git a/gnu/usr.bin/perl/perl/t/comp/package.t b/gnu/usr.bin/perl/perl/t/comp/package.t
new file mode 100755
index 0000000..5237011
--- /dev/null
+++ b/gnu/usr.bin/perl/perl/t/comp/package.t
@@ -0,0 +1,33 @@
+#!./perl
+
+print "1..7\n";
+
+$blurfl = 123;
+$foo = 3;
+
+package XYZ;
+
+$bar = 4;
+
+{
+ package ABC;
+ $blurfl = 5;
+ $main'a = $'b;
+}
+
+$ABC'dyick = 6;
+
+$xyz = 2;
+
+$main = join(':', sort(keys _main));
+$XYZ = join(':', sort(keys _XYZ));
+$ABC = join(':', sort(keys _ABC));
+
+print $XYZ eq 'ABC:XYZ:bar:main:xyz' ? "ok 1\n" : "not ok 1 '$XYZ'\n";
+print $ABC eq 'blurfl:dyick' ? "ok 2\n" : "not ok 2\n";
+print $main'blurfl == 123 ? "ok 3\n" : "not ok 3\n";
+package ABC;
+print $blurfl == 5 ? "ok 4\n" : "not ok 4\n";
+eval 'print $blurfl == 5 ? "ok 5\n" : "not ok 5\n";';
+eval 'package main; print $blurfl == 123 ? "ok 6\n" : "not ok 6\n";';
+print $blurfl == 5 ? "ok 7\n" : "not ok 7\n";
diff --git a/gnu/usr.bin/perl/perl/t/comp/script.t b/gnu/usr.bin/perl/perl/t/comp/script.t
new file mode 100755
index 0000000..9dcf901
--- /dev/null
+++ b/gnu/usr.bin/perl/perl/t/comp/script.t
@@ -0,0 +1,23 @@
+#!./perl
+
+# $Header: /home/cvs/386BSD/ports/lang/perl/t/comp/script.t,v 1.1.1.1 1993/08/23 21:30:06 nate Exp $
+
+print "1..3\n";
+
+$x = `./perl -e 'print "ok\n";'`;
+
+if ($x eq "ok\n") {print "ok 1\n";} else {print "not ok 1\n";}
+
+open(try,">Comp.script") || (die "Can't open temp file.");
+print try 'print "ok\n";'; print try "\n";
+close try;
+
+$x = `./perl Comp.script`;
+
+if ($x eq "ok\n") {print "ok 2\n";} else {print "not ok 2\n";}
+
+$x = `./perl <Comp.script`;
+
+if ($x eq "ok\n") {print "ok 3\n";} else {print "not ok 3\n";}
+
+`/bin/rm -f Comp.script`;
diff --git a/gnu/usr.bin/perl/perl/t/comp/term.t b/gnu/usr.bin/perl/perl/t/comp/term.t
new file mode 100755
index 0000000..70b23fd
--- /dev/null
+++ b/gnu/usr.bin/perl/perl/t/comp/term.t
@@ -0,0 +1,35 @@
+#!./perl
+
+# $Header: /home/cvs/386BSD/ports/lang/perl/t/comp/term.t,v 1.1.1.1 1993/08/23 21:30:06 nate Exp $
+
+# tests that aren't important enough for base.term
+
+print "1..14\n";
+
+$x = "\\n";
+print "#1\t:$x: eq " . ':\n:' . "\n";
+if ($x eq '\n') {print "ok 1\n";} else {print "not ok 1\n";}
+
+$x = "#2\t:$x: eq :\\n:\n";
+print $x;
+unless (index($x,'\\\\')>0) {print "ok 2\n";} else {print "not ok 2\n";}
+
+if (length('\\\\') == 2) {print "ok 3\n";} else {print "not ok 3\n";}
+
+$one = 'a';
+
+if (length("\\n") == 2) {print "ok 4\n";} else {print "not ok 4\n";}
+if (length("\\\n") == 2) {print "ok 5\n";} else {print "not ok 5\n";}
+if (length("$one\\n") == 3) {print "ok 6\n";} else {print "not ok 6\n";}
+if (length("$one\\\n") == 3) {print "ok 7\n";} else {print "not ok 7\n";}
+if (length("\\n$one") == 3) {print "ok 8\n";} else {print "not ok 8\n";}
+if (length("\\\n$one") == 3) {print "ok 9\n";} else {print "not ok 9\n";}
+if (length("\\${one}") == 2) {print "ok 10\n";} else {print "not ok 10\n";}
+
+if ("${one}b" eq "ab") { print "ok 11\n";} else {print "not ok 11\n";}
+
+@foo = (1,2,3);
+if ("$foo[1]b" eq "2b") { print "ok 12\n";} else {print "not ok 12\n";}
+if ("@foo[0..1]b" eq "1 2b") { print "ok 13\n";} else {print "not ok 13\n";}
+$" = '::';
+if ("@foo[0..1]b" eq "1::2b") { print "ok 14\n";} else {print "not ok 14\n";}
diff --git a/gnu/usr.bin/perl/perl/t/io/argv.t b/gnu/usr.bin/perl/perl/t/io/argv.t
new file mode 100755
index 0000000..99c5936
--- /dev/null
+++ b/gnu/usr.bin/perl/perl/t/io/argv.t
@@ -0,0 +1,36 @@
+#!./perl
+
+# $Header: /home/cvs/386BSD/ports/lang/perl/t/io/argv.t,v 1.1.1.1 1993/08/23 21:30:06 nate Exp $
+
+print "1..5\n";
+
+open(try, '>Io.argv.tmp') || (die "Can't open temp file.");
+print try "a line\n";
+close try;
+
+$x = `./perl -e 'while (<>) {print \$.,\$_;}' Io.argv.tmp Io.argv.tmp`;
+
+if ($x eq "1a line\n2a line\n") {print "ok 1\n";} else {print "not ok 1\n";}
+
+$x = `echo foo|./perl -e 'while (<>) {print $_;}' Io.argv.tmp -`;
+
+if ($x eq "a line\nfoo\n") {print "ok 2\n";} else {print "not ok 2\n";}
+
+$x = `echo foo|./perl -e 'while (<>) {print $_;}'`;
+
+if ($x eq "foo\n") {print "ok 3\n";} else {print "not ok 3 :$x:\n";}
+
+@ARGV = ('Io.argv.tmp', 'Io.argv.tmp', '/dev/null', 'Io.argv.tmp');
+while (<>) {
+ $y .= $. . $_;
+ if (eof()) {
+ if ($. == 3) {print "ok 4\n";} else {print "not ok 4\n";}
+ }
+}
+
+if ($y eq "1a line\n2a line\n3a line\n")
+ {print "ok 5\n";}
+else
+ {print "not ok 5\n";}
+
+`/bin/rm -f Io.argv.tmp`;
diff --git a/gnu/usr.bin/perl/perl/t/io/dup.t b/gnu/usr.bin/perl/perl/t/io/dup.t
new file mode 100755
index 0000000..8d11eca
--- /dev/null
+++ b/gnu/usr.bin/perl/perl/t/io/dup.t
@@ -0,0 +1,32 @@
+#!./perl
+
+# $Header: /home/cvs/386BSD/ports/lang/perl/t/io/dup.t,v 1.1.1.1 1993/08/23 21:30:06 nate Exp $
+
+print "1..6\n";
+
+print "ok 1\n";
+
+open(dupout,">&STDOUT");
+open(duperr,">&STDERR");
+
+open(STDOUT,">Io.dup") || die "Can't open stdout";
+open(STDERR,">&STDOUT") || die "Can't open stderr";
+
+select(STDERR); $| = 1;
+select(STDOUT); $| = 1;
+
+print STDOUT "ok 2\n";
+print STDERR "ok 3\n";
+system 'echo ok 4';
+system 'echo ok 5 1>&2';
+
+close(STDOUT);
+close(STDERR);
+
+open(STDOUT,">&dupout");
+open(STDERR,">&duperr");
+
+system 'cat Io.dup';
+unlink 'Io.dup';
+
+print STDOUT "ok 6\n";
diff --git a/gnu/usr.bin/perl/perl/t/io/fs.t b/gnu/usr.bin/perl/perl/t/io/fs.t
new file mode 100755
index 0000000..1d95cdc
--- /dev/null
+++ b/gnu/usr.bin/perl/perl/t/io/fs.t
@@ -0,0 +1,85 @@
+#!./perl
+
+# $RCSfile: fs.t,v $$Revision: 1.1.1.1 $$Date: 1993/08/23 21:30:05 $
+
+print "1..22\n";
+
+$wd = `pwd`;
+chop($wd);
+
+`rm -f tmp 2>/dev/null; mkdir tmp 2>/dev/null`;
+chdir './tmp';
+`/bin/rm -rf a b c x`;
+
+umask(022);
+
+if ((umask(0)&0777) == 022) {print "ok 1\n";} else {print "not ok 1\n";}
+open(fh,'>x') || die "Can't create x";
+close(fh);
+open(fh,'>a') || die "Can't create a";
+close(fh);
+
+if (link('a','b')) {print "ok 2\n";} else {print "not ok 2\n";}
+
+if (link('b','c')) {print "ok 3\n";} else {print "not ok 3\n";}
+
+($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,$atime,$mtime,$ctime,
+ $blksize,$blocks) = stat('c');
+
+if ($nlink == 3) {print "ok 4\n";} else {print "not ok 4\n";}
+if (($mode & 0777) == 0666) {print "ok 5\n";} else {print "not ok 5\n";}
+
+if ((chmod 0777,'a') == 1) {print "ok 6\n";} else {print "not ok 6\n";}
+
+($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,$atime,$mtime,$ctime,
+ $blksize,$blocks) = stat('c');
+if (($mode & 0777) == 0777) {print "ok 7\n";} else {print "not ok 7\n";}
+
+if ((chmod 0700,'c','x') == 2) {print "ok 8\n";} else {print "not ok 8\n";}
+
+($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,$atime,$mtime,$ctime,
+ $blksize,$blocks) = stat('c');
+if (($mode & 0777) == 0700) {print "ok 9\n";} else {print "not ok 9\n";}
+($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,$atime,$mtime,$ctime,
+ $blksize,$blocks) = stat('x');
+if (($mode & 0777) == 0700) {print "ok 10\n";} else {print "not ok 10\n";}
+
+if ((unlink 'b','x') == 2) {print "ok 11\n";} else {print "not ok 11\n";}
+($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,$atime,$mtime,$ctime,
+ $blksize,$blocks) = stat('b');
+if ($ino == 0) {print "ok 12\n";} else {print "not ok 12\n";}
+($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,$atime,$mtime,$ctime,
+ $blksize,$blocks) = stat('x');
+if ($ino == 0) {print "ok 13\n";} else {print "not ok 13\n";}
+
+if (rename('a','b')) {print "ok 14\n";} else {print "not ok 14\n";}
+($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,$atime,$mtime,$ctime,
+ $blksize,$blocks) = stat('a');
+if ($ino == 0) {print "ok 15\n";} else {print "not ok 15\n";}
+$foo = (utime 500000000,500000001,'b');
+if ($foo == 1) {print "ok 16\n";} else {print "not ok 16 $foo\n";}
+($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,$atime,$mtime,$ctime,
+ $blksize,$blocks) = stat('b');
+if ($ino) {print "ok 17\n";} else {print "not ok 17\n";}
+if (($atime == 500000000 && $mtime == 500000001) || $wd =~ m#/afs/#)
+ {print "ok 18\n";}
+else
+ {print "not ok 18 $atime $mtime\n";}
+
+if ((unlink 'b') == 1) {print "ok 19\n";} else {print "not ok 19\n";}
+($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,$atime,$mtime,$ctime,
+ $blksize,$blocks) = stat('b');
+if ($ino == 0) {print "ok 20\n";} else {print "not ok 20\n";}
+unlink 'c';
+
+chdir $wd || die "Can't cd back to $wd";
+
+unlink 'c';
+if (`ls -l perl 2>/dev/null` =~ /^l.*->/) { # we have symbolic links
+ if (symlink("TEST","c")) {print "ok 21\n";} else {print "not ok 21\n";}
+ $foo = `grep perl c`;
+ if ($foo) {print "ok 22\n";} else {print "not ok 22\n";}
+}
+else {
+ print "ok 21\nok 22\n";
+}
diff --git a/gnu/usr.bin/perl/perl/t/io/inplace.t b/gnu/usr.bin/perl/perl/t/io/inplace.t
new file mode 100755
index 0000000..b22afda
--- /dev/null
+++ b/gnu/usr.bin/perl/perl/t/io/inplace.t
@@ -0,0 +1,21 @@
+#!./perl
+
+$^I = '.bak';
+
+# $Header: /home/cvs/386BSD/ports/lang/perl/t/io/inplace.t,v 1.1.1.1 1993/08/23 21:30:05 nate Exp $
+
+print "1..2\n";
+
+@ARGV = ('.a','.b','.c');
+`echo foo | tee .a .b .c`;
+while (<>) {
+ s/foo/bar/;
+}
+continue {
+ print;
+}
+
+if (`cat .a .b .c` eq "bar\nbar\nbar\n") {print "ok 1\n";} else {print "not ok 1\n";}
+if (`cat .a.bak .b.bak .c.bak` eq "foo\nfoo\nfoo\n") {print "ok 2\n";} else {print "not ok 2\n";}
+
+unlink '.a', '.b', '.c', '.a.bak', '.b.bak', '.c.bak';
diff --git a/gnu/usr.bin/perl/perl/t/io/pipe.t b/gnu/usr.bin/perl/perl/t/io/pipe.t
new file mode 100755
index 0000000..791a9c7
--- /dev/null
+++ b/gnu/usr.bin/perl/perl/t/io/pipe.t
@@ -0,0 +1,56 @@
+#!./perl
+
+# $Header: /home/cvs/386BSD/ports/lang/perl/t/io/pipe.t,v 1.1.1.1 1993/08/23 21:30:06 nate Exp $
+
+$| = 1;
+print "1..8\n";
+
+open(PIPE, "|-") || (exec 'tr', '[A-Z]', '[a-z]');
+print PIPE "OK 1\n";
+print PIPE "ok 2\n";
+close PIPE;
+
+if (open(PIPE, "-|")) {
+ while(<PIPE>) {
+ s/^not //;
+ print;
+ }
+}
+else {
+ print STDOUT "not ok 3\n";
+ exec 'echo', 'not ok 4';
+}
+
+pipe(READER,WRITER) || die "Can't open pipe";
+
+if ($pid = fork) {
+ close WRITER;
+ while(<READER>) {
+ s/^not //;
+ y/A-Z/a-z/;
+ print;
+ }
+}
+else {
+ die "Couldn't fork" unless defined $pid;
+ close READER;
+ print WRITER "not ok 5\n";
+ open(STDOUT,">&WRITER") || die "Can't dup WRITER to STDOUT";
+ close WRITER;
+ exec 'echo', 'not ok 6';
+}
+
+
+pipe(READER,WRITER) || die "Can't open pipe";
+close READER;
+
+$SIG{'PIPE'} = 'broken_pipe';
+
+sub broken_pipe {
+ print "ok 7\n";
+}
+
+print WRITER "not ok 7\n";
+close WRITER;
+
+print "ok 8\n";
diff --git a/gnu/usr.bin/perl/perl/t/io/print.t b/gnu/usr.bin/perl/perl/t/io/print.t
new file mode 100755
index 0000000..1185442
--- /dev/null
+++ b/gnu/usr.bin/perl/perl/t/io/print.t
@@ -0,0 +1,32 @@
+#!./perl
+
+# $Header: /home/cvs/386BSD/ports/lang/perl/t/io/print.t,v 1.1.1.1 1993/08/23 21:30:06 nate Exp $
+
+print "1..16\n";
+
+$foo = 'STDOUT';
+print $foo "ok 1\n";
+
+print "ok 2\n","ok 3\n","ok 4\n";
+print STDOUT "ok 5\n";
+
+open(foo,">-");
+print foo "ok 6\n";
+
+printf "ok %d\n",7;
+printf("ok %d\n",8);
+
+@a = ("ok %d%c",9,ord("\n"));
+printf @a;
+
+$a[1] = 10;
+printf STDOUT @a;
+
+$, = ' ';
+$\ = "\n";
+
+print "ok","11";
+
+@x = ("ok","12\nok","13\nok");
+@y = ("15\nok","16");
+print @x,"14\nok",@y;
diff --git a/gnu/usr.bin/perl/perl/t/io/tell.t b/gnu/usr.bin/perl/perl/t/io/tell.t
new file mode 100755
index 0000000..27e69a0
--- /dev/null
+++ b/gnu/usr.bin/perl/perl/t/io/tell.t
@@ -0,0 +1,44 @@
+#!./perl
+
+# $Header: /home/cvs/386BSD/ports/lang/perl/t/io/tell.t,v 1.1.1.1 1993/08/23 21:30:06 nate Exp $
+
+print "1..13\n";
+
+$TST = 'tst';
+
+open($TST, '../Makefile') || (die "Can't open ../Makefile");
+
+if (eof(tst)) { print "not ok 1\n"; } else { print "ok 1\n"; }
+
+$firstline = <$TST>;
+$secondpos = tell;
+
+$x = 0;
+while (<tst>) {
+ if (eof) {$x++;}
+}
+if ($x == 1) { print "ok 2\n"; } else { print "not ok 2\n"; }
+
+$lastpos = tell;
+
+unless (eof) { print "not ok 3\n"; } else { print "ok 3\n"; }
+
+if (seek($TST,0,0)) { print "ok 4\n"; } else { print "not ok 4\n"; }
+
+if (eof) { print "not ok 5\n"; } else { print "ok 5\n"; }
+
+if ($firstline eq <tst>) { print "ok 6\n"; } else { print "not ok 6\n"; }
+
+if ($secondpos == tell) { print "ok 7\n"; } else { print "not ok 7\n"; }
+
+if (seek(tst,0,1)) { print "ok 8\n"; } else { print "not ok 8\n"; }
+
+if (eof($TST)) { print "not ok 9\n"; } else { print "ok 9\n"; }
+
+if ($secondpos == tell) { print "ok 10\n"; } else { print "not ok 10\n"; }
+
+if (seek(tst,0,2)) { print "ok 11\n"; } else { print "not ok 11\n"; }
+
+if ($lastpos == tell) { print "ok 12\n"; } else { print "not ok 12\n"; }
+
+unless (eof) { print "not ok 13\n"; } else { print "ok 13\n"; }
diff --git a/gnu/usr.bin/perl/perl/t/lib/big.t b/gnu/usr.bin/perl/perl/t/lib/big.t
new file mode 100755
index 0000000..9b27a5f
--- /dev/null
+++ b/gnu/usr.bin/perl/perl/t/lib/big.t
@@ -0,0 +1,280 @@
+#!./perl
+require "../../lib/bigint.pl";
+
+$test = 0;
+$| = 1;
+print "1..246\n";
+while (<DATA>) {
+ chop;
+ if (/^&/) {
+ $f = $_;
+ } else {
+ ++$test;
+ @args = split(/:/,$_,99);
+ $ans = pop(@args);
+ $try = "$f('" . join("','", @args) . "');";
+ if (($ans1 = eval($try)) eq $ans) {
+ print "ok $test\n";
+ } else {
+ print "not ok $test\n";
+ print "# '$try' expected: '$ans' got: '$ans1'\n";
+ }
+ }
+}
+__END__
+&bnorm
+abc:NaN
+ 1 a:NaN
+1bcd2:NaN
+11111b:NaN
++1z:NaN
+-1z:NaN
+0:+0
++0:+0
++00:+0
++0 0 0:+0
+000000 0000000 00000:+0
+-0:+0
+-0000:+0
++1:+1
++01:+1
++001:+1
++00000100000:+100000
+123456789:+123456789
+-1:-1
+-01:-1
+-001:-1
+-123456789:-123456789
+-00000100000:-100000
+&bneg
+abd:NaN
++0:+0
++1:-1
+-1:+1
++123456789:-123456789
+-123456789:+123456789
+&babs
+abc:NaN
++0:+0
++1:+1
+-1:+1
++123456789:+123456789
+-123456789:+123456789
+&bcmp
+abc:abc:
+abc:+0:
++0:abc:
++0:+0:0
+-1:+0:-1
++0:-1:1
++1:+0:1
++0:+1:-1
+-1:+1:-1
++1:-1:1
+-1:-1:0
++1:+1:0
++123:+123:0
++123:+12:1
++12:+123:-1
+-123:-123:0
+-123:-12:-1
+-12:-123:1
++123:+124:-1
++124:+123:1
+-123:-124:1
+-124:-123:-1
+&badd
+abc:abc:NaN
+abc:+0:NaN
++0:abc:NaN
++0:+0:+0
++1:+0:+1
++0:+1:+1
++1:+1:+2
+-1:+0:-1
++0:-1:-1
+-1:-1:-2
+-1:+1:+0
++1:-1:+0
++9:+1:+10
++99:+1:+100
++999:+1:+1000
++9999:+1:+10000
++99999:+1:+100000
++999999:+1:+1000000
++9999999:+1:+10000000
++99999999:+1:+100000000
++999999999:+1:+1000000000
++9999999999:+1:+10000000000
++99999999999:+1:+100000000000
++10:-1:+9
++100:-1:+99
++1000:-1:+999
++10000:-1:+9999
++100000:-1:+99999
++1000000:-1:+999999
++10000000:-1:+9999999
++100000000:-1:+99999999
++1000000000:-1:+999999999
++10000000000:-1:+9999999999
++123456789:+987654321:+1111111110
+-123456789:+987654321:+864197532
+-123456789:-987654321:-1111111110
++123456789:-987654321:-864197532
+&bsub
+abc:abc:NaN
+abc:+0:NaN
++0:abc:NaN
++0:+0:+0
++1:+0:+1
++0:+1:-1
++1:+1:+0
+-1:+0:-1
++0:-1:+1
+-1:-1:+0
+-1:+1:-2
++1:-1:+2
++9:+1:+8
++99:+1:+98
++999:+1:+998
++9999:+1:+9998
++99999:+1:+99998
++999999:+1:+999998
++9999999:+1:+9999998
++99999999:+1:+99999998
++999999999:+1:+999999998
++9999999999:+1:+9999999998
++99999999999:+1:+99999999998
++10:-1:+11
++100:-1:+101
++1000:-1:+1001
++10000:-1:+10001
++100000:-1:+100001
++1000000:-1:+1000001
++10000000:-1:+10000001
++100000000:-1:+100000001
++1000000000:-1:+1000000001
++10000000000:-1:+10000000001
++123456789:+987654321:-864197532
+-123456789:+987654321:-1111111110
+-123456789:-987654321:+864197532
++123456789:-987654321:+1111111110
+&bmul
+abc:abc:NaN
+abc:+0:NaN
++0:abc:NaN
++0:+0:+0
++0:+1:+0
++1:+0:+0
++0:-1:+0
+-1:+0:+0
++123456789123456789:+0:+0
++0:+123456789123456789:+0
+-1:-1:+1
+-1:+1:-1
++1:-1:-1
++1:+1:+1
++2:+3:+6
+-2:+3:-6
++2:-3:-6
+-2:-3:+6
++111:+111:+12321
++10101:+10101:+102030201
++1001001:+1001001:+1002003002001
++100010001:+100010001:+10002000300020001
++10000100001:+10000100001:+100002000030000200001
++11111111111:+9:+99999999999
++22222222222:+9:+199999999998
++33333333333:+9:+299999999997
++44444444444:+9:+399999999996
++55555555555:+9:+499999999995
++66666666666:+9:+599999999994
++77777777777:+9:+699999999993
++88888888888:+9:+799999999992
++99999999999:+9:+899999999991
+&bdiv
+abc:abc:NaN
+abc:+1:abc:NaN
++1:abc:NaN
++0:+0:NaN
++0:+1:+0
++1:+0:NaN
++0:-1:+0
+-1:+0:NaN
++1:+1:+1
+-1:-1:+1
++1:-1:-1
+-1:+1:-1
++1:+2:+0
++2:+1:+2
++1000000000:+9:+111111111
++2000000000:+9:+222222222
++3000000000:+9:+333333333
++4000000000:+9:+444444444
++5000000000:+9:+555555555
++6000000000:+9:+666666666
++7000000000:+9:+777777777
++8000000000:+9:+888888888
++9000000000:+9:+1000000000
++35500000:+113:+314159
++71000000:+226:+314159
++106500000:+339:+314159
++1000000000:+3:+333333333
++10:+5:+2
++100:+4:+25
++1000:+8:+125
++10000:+16:+625
++999999999999:+9:+111111111111
++999999999999:+99:+10101010101
++999999999999:+999:+1001001001
++999999999999:+9999:+100010001
++999999999999999:+99999:+10000100001
+&bmod
+abc:abc:NaN
+abc:+1:abc:NaN
++1:abc:NaN
++0:+0:NaN
++0:+1:+0
++1:+0:NaN
++0:-1:+0
+-1:+0:NaN
++1:+1:+0
+-1:-1:+0
++1:-1:+0
+-1:+1:+0
++1:+2:+1
++2:+1:+0
++1000000000:+9:+1
++2000000000:+9:+2
++3000000000:+9:+3
++4000000000:+9:+4
++5000000000:+9:+5
++6000000000:+9:+6
++7000000000:+9:+7
++8000000000:+9:+8
++9000000000:+9:+0
++35500000:+113:+33
++71000000:+226:+66
++106500000:+339:+99
++1000000000:+3:+1
++10:+5:+0
++100:+4:+0
++1000:+8:+0
++10000:+16:+0
++999999999999:+9:+0
++999999999999:+99:+0
++999999999999:+999:+0
++999999999999:+9999:+0
++999999999999999:+99999:+0
+&bgcd
+abc:abc:NaN
+abc:+0:NaN
++0:abc:NaN
++0:+0:+0
++0:+1:+1
++1:+0:+1
++1:+1:+1
++2:+3:+1
++3:+2:+1
++100:+625:+25
++4096:+81:+1
diff --git a/gnu/usr.bin/perl/perl/t/op/append.t b/gnu/usr.bin/perl/perl/t/op/append.t
new file mode 100755
index 0000000..92c6f48
--- /dev/null
+++ b/gnu/usr.bin/perl/perl/t/op/append.t
@@ -0,0 +1,21 @@
+#!./perl
+
+# $Header: /home/cvs/386BSD/ports/lang/perl/t/op/append.t,v 1.1.1.1 1993/08/23 21:30:04 nate Exp $
+
+print "1..3\n";
+
+$a = 'ab' . 'c'; # compile time
+$b = 'def';
+
+$c = $a . $b;
+print "#1\t:$c: eq :abcdef:\n";
+if ($c eq 'abcdef') {print "ok 1\n";} else {print "not ok 1\n";}
+
+$c .= 'xyz';
+print "#2\t:$c: eq :abcdefxyz:\n";
+if ($c eq 'abcdefxyz') {print "ok 2\n";} else {print "not ok 2\n";}
+
+$_ = $a;
+$_ .= $b;
+print "#3\t:$_: eq :abcdef:\n";
+if ($_ eq 'abcdef') {print "ok 3\n";} else {print "not ok 3\n";}
diff --git a/gnu/usr.bin/perl/perl/t/op/array.t b/gnu/usr.bin/perl/perl/t/op/array.t
new file mode 100755
index 0000000..39e05e3
--- /dev/null
+++ b/gnu/usr.bin/perl/perl/t/op/array.t
@@ -0,0 +1,120 @@
+#!./perl
+
+# $Header: /home/cvs/386BSD/ports/lang/perl/t/op/array.t,v 1.1.1.1 1993/08/23 21:30:02 nate Exp $
+
+print "1..36\n";
+
+@ary = (1,2,3,4,5);
+if (join('',@ary) eq '12345') {print "ok 1\n";} else {print "not ok 1\n";}
+
+$tmp = $ary[$#ary]; --$#ary;
+if ($tmp == 5) {print "ok 2\n";} else {print "not ok 2\n";}
+if ($#ary == 3) {print "ok 3\n";} else {print "not ok 3\n";}
+if (join('',@ary) eq '1234') {print "ok 4\n";} else {print "not ok 4\n";}
+
+$[ = 1;
+@ary = (1,2,3,4,5);
+if (join('',@ary) eq '12345') {print "ok 5\n";} else {print "not ok 5\n";}
+
+$tmp = $ary[$#ary]; --$#ary;
+if ($tmp == 5) {print "ok 6\n";} else {print "not ok 6\n";}
+if ($#ary == 4) {print "ok 7\n";} else {print "not ok 7\n";}
+if (join('',@ary) eq '1234') {print "ok 8\n";} else {print "not ok 8\n";}
+
+if ($ary[5] eq '') {print "ok 9\n";} else {print "not ok 9\n";}
+
+$#ary += 1; # see if we can recover element 5
+if ($#ary == 5) {print "ok 10\n";} else {print "not ok 10\n";}
+if ($ary[5] == 5) {print "ok 11\n";} else {print "not ok 11\n";}
+
+$[ = 0;
+@foo = ();
+$r = join(',', $#foo, @foo);
+if ($r eq "-1") {print "ok 12\n";} else {print "not ok 12 $r\n";}
+$foo[0] = '0';
+$r = join(',', $#foo, @foo);
+if ($r eq "0,0") {print "ok 13\n";} else {print "not ok 13 $r\n";}
+$foo[2] = '2';
+$r = join(',', $#foo, @foo);
+if ($r eq "2,0,,2") {print "ok 14\n";} else {print "not ok 14 $r\n";}
+@bar = ();
+$bar[0] = '0';
+$bar[1] = '1';
+$r = join(',', $#bar, @bar);
+if ($r eq "1,0,1") {print "ok 15\n";} else {print "not ok 15 $r\n";}
+@bar = ();
+$r = join(',', $#bar, @bar);
+if ($r eq "-1") {print "ok 16\n";} else {print "not ok 16 $r\n";}
+$bar[0] = '0';
+$r = join(',', $#bar, @bar);
+if ($r eq "0,0") {print "ok 17\n";} else {print "not ok 17 $r\n";}
+$bar[2] = '2';
+$r = join(',', $#bar, @bar);
+if ($r eq "2,0,,2") {print "ok 18\n";} else {print "not ok 18 $r\n";}
+reset 'b';
+@bar = ();
+$bar[0] = '0';
+$r = join(',', $#bar, @bar);
+if ($r eq "0,0") {print "ok 19\n";} else {print "not ok 19 $r\n";}
+$bar[2] = '2';
+$r = join(',', $#bar, @bar);
+if ($r eq "2,0,,2") {print "ok 20\n";} else {print "not ok 20 $r\n";}
+
+$foo = 'now is the time';
+if (($F1,$F2,$Etc) = ($foo =~ /^(\S+)\s+(\S+)\s*(.*)/)) {
+ if ($F1 eq 'now' && $F2 eq 'is' && $Etc eq 'the time') {
+ print "ok 21\n";
+ }
+ else {
+ print "not ok 21\n";
+ }
+}
+else {
+ print "not ok 21\n";
+}
+
+$foo = 'lskjdf';
+if ($cnt = (($F1,$F2,$Etc) = ($foo =~ /^(\S+)\s+(\S+)\s*(.*)/))) {
+ print "not ok 22 $cnt $F1:$F2:$Etc\n";
+}
+else {
+ print "ok 22\n";
+}
+
+%foo = ('blurfl','dyick','foo','bar','etc.','etc.');
+%bar = %foo;
+print $bar{'foo'} eq 'bar' ? "ok 23\n" : "not ok 23\n";
+%bar = ();
+print $bar{'foo'} eq '' ? "ok 24\n" : "not ok 24\n";
+(%bar,$a,$b) = (%foo,'how','now');
+print $bar{'foo'} eq 'bar' ? "ok 25\n" : "not ok 25\n";
+print $bar{'how'} eq 'now' ? "ok 26\n" : "not ok 26\n";
+@bar{keys %foo} = values %foo;
+print $bar{'foo'} eq 'bar' ? "ok 27\n" : "not ok 27\n";
+print $bar{'how'} eq 'now' ? "ok 28\n" : "not ok 28\n";
+
+@foo = grep(/e/,split(' ','now is the time for all good men to come to'));
+print join(' ',@foo) eq 'the time men come' ? "ok 29\n" : "not ok 29\n";
+
+@foo = grep(!/e/,split(' ','now is the time for all good men to come to'));
+print join(' ',@foo) eq 'now is for all good to to' ? "ok 30\n" : "not ok 30\n";
+
+$foo = join('',('a','b','c','d','e','f')[0..5]);
+print $foo eq 'abcdef' ? "ok 31\n" : "not ok 31\n";
+
+$foo = join('',('a','b','c','d','e','f')[0..1]);
+print $foo eq 'ab' ? "ok 32\n" : "not ok 32\n";
+
+$foo = join('',('a','b','c','d','e','f')[6]);
+print $foo eq '' ? "ok 33\n" : "not ok 33\n";
+
+@foo = ('a','b','c','d','e','f')[0,2,4];
+@bar = ('a','b','c','d','e','f')[1,3,5];
+$foo = join('',(@foo,@bar)[0..5]);
+print $foo eq 'acebdf' ? "ok 34\n" : "not ok 34\n";
+
+$foo = ('a','b','c','d','e','f')[0,2,4];
+print $foo eq 'e' ? "ok 35\n" : "not ok 35\n";
+
+$foo = ('a','b','c','d','e','f')[1];
+print $foo eq 'b' ? "ok 36\n" : "not ok 36\n";
diff --git a/gnu/usr.bin/perl/perl/t/op/auto.t b/gnu/usr.bin/perl/perl/t/op/auto.t
new file mode 100755
index 0000000..5301f93
--- /dev/null
+++ b/gnu/usr.bin/perl/perl/t/op/auto.t
@@ -0,0 +1,48 @@
+#!./perl
+
+# $Header: /home/cvs/386BSD/ports/lang/perl/t/op/auto.t,v 1.1.1.1 1993/08/23 21:30:01 nate Exp $
+
+print "1..34\n";
+
+$x = 10000;
+if (0 + ++$x - 1 == 10000) { print "ok 1\n";} else {print "not ok 1\n";}
+if (0 + $x-- - 1 == 10000) { print "ok 2\n";} else {print "not ok 2\n";}
+if (1 * $x == 10000) { print "ok 3\n";} else {print "not ok 3\n";}
+if (0 + $x-- - 0 == 10000) { print "ok 4\n";} else {print "not ok 4\n";}
+if (1 + $x == 10000) { print "ok 5\n";} else {print "not ok 5\n";}
+if (1 + $x++ == 10000) { print "ok 6\n";} else {print "not ok 6\n";}
+if (0 + $x == 10000) { print "ok 7\n";} else {print "not ok 7\n";}
+if (0 + --$x + 1 == 10000) { print "ok 8\n";} else {print "not ok 8\n";}
+if (0 + ++$x + 0 == 10000) { print "ok 9\n";} else {print "not ok 9\n";}
+if ($x == 10000) { print "ok 10\n";} else {print "not ok 10\n";}
+
+$x[0] = 10000;
+if (0 + ++$x[0] - 1 == 10000) { print "ok 11\n";} else {print "not ok 11\n";}
+if (0 + $x[0]-- - 1 == 10000) { print "ok 12\n";} else {print "not ok 12\n";}
+if (1 * $x[0] == 10000) { print "ok 13\n";} else {print "not ok 13\n";}
+if (0 + $x[0]-- - 0 == 10000) { print "ok 14\n";} else {print "not ok 14\n";}
+if (1 + $x[0] == 10000) { print "ok 15\n";} else {print "not ok 15\n";}
+if (1 + $x[0]++ == 10000) { print "ok 16\n";} else {print "not ok 16\n";}
+if (0 + $x[0] == 10000) { print "ok 17\n";} else {print "not ok 17\n";}
+if (0 + --$x[0] + 1 == 10000) { print "ok 18\n";} else {print "not ok 18\n";}
+if (0 + ++$x[0] + 0 == 10000) { print "ok 19\n";} else {print "not ok 19\n";}
+if ($x[0] == 10000) { print "ok 20\n";} else {print "not ok 20\n";}
+
+$x{0} = 10000;
+if (0 + ++$x{0} - 1 == 10000) { print "ok 21\n";} else {print "not ok 21\n";}
+if (0 + $x{0}-- - 1 == 10000) { print "ok 22\n";} else {print "not ok 22\n";}
+if (1 * $x{0} == 10000) { print "ok 23\n";} else {print "not ok 23\n";}
+if (0 + $x{0}-- - 0 == 10000) { print "ok 24\n";} else {print "not ok 24\n";}
+if (1 + $x{0} == 10000) { print "ok 25\n";} else {print "not ok 25\n";}
+if (1 + $x{0}++ == 10000) { print "ok 26\n";} else {print "not ok 26\n";}
+if (0 + $x{0} == 10000) { print "ok 27\n";} else {print "not ok 27\n";}
+if (0 + --$x{0} + 1 == 10000) { print "ok 28\n";} else {print "not ok 28\n";}
+if (0 + ++$x{0} + 0 == 10000) { print "ok 29\n";} else {print "not ok 29\n";}
+if ($x{0} == 10000) { print "ok 30\n";} else {print "not ok 30\n";}
+
+# test magical autoincrement
+
+if (++($foo = '99') eq '100') {print "ok 31\n";} else {print "not ok 31\n";}
+if (++($foo = 'a0') eq 'a1') {print "ok 32\n";} else {print "not ok 32\n";}
+if (++($foo = 'Az') eq 'Ba') {print "ok 33\n";} else {print "not ok 33\n";}
+if (++($foo = 'zz') eq 'aaa') {print "ok 34\n";} else {print "not ok 34\n";}
diff --git a/gnu/usr.bin/perl/perl/t/op/chop.t b/gnu/usr.bin/perl/perl/t/op/chop.t
new file mode 100755
index 0000000..d691d73
--- /dev/null
+++ b/gnu/usr.bin/perl/perl/t/op/chop.t
@@ -0,0 +1,30 @@
+#!./perl
+
+# $Header: /home/cvs/386BSD/ports/lang/perl/t/op/chop.t,v 1.1.1.1 1993/08/23 21:30:04 nate Exp $
+
+print "1..4\n";
+
+# optimized
+
+$_ = 'abc';
+$c = do foo();
+if ($c . $_ eq 'cab') {print "ok 1\n";} else {print "not ok 1 $c$_\n";}
+
+# unoptimized
+
+$_ = 'abc';
+$c = chop($_);
+if ($c . $_ eq 'cab') {print "ok 2\n";} else {print "not ok 2\n";}
+
+sub foo {
+ chop;
+}
+
+@foo = ("hi \n","there\n","!\n");
+@bar = @foo;
+chop(@bar);
+print join('',@bar) eq 'hi there!' ? "ok 3\n" : "not ok 3\n";
+
+$foo = "\n";
+chop($foo,@foo);
+print join('',$foo,@foo) eq 'hi there!' ? "ok 4\n" : "not ok 4\n";
diff --git a/gnu/usr.bin/perl/perl/t/op/cond.t b/gnu/usr.bin/perl/perl/t/op/cond.t
new file mode 100755
index 0000000..054a5ff
--- /dev/null
+++ b/gnu/usr.bin/perl/perl/t/op/cond.t
@@ -0,0 +1,12 @@
+#!./perl
+
+# $Header: /home/cvs/386BSD/ports/lang/perl/t/op/cond.t,v 1.1.1.1 1993/08/23 21:30:04 nate Exp $
+
+print "1..4\n";
+
+print 1 ? "ok 1\n" : "not ok 1\n"; # compile time
+print 0 ? "not ok 2\n" : "ok 2\n";
+
+$x = 1;
+print $x ? "ok 3\n" : "not ok 3\n"; # run time
+print !$x ? "not ok 4\n" : "ok 4\n";
diff --git a/gnu/usr.bin/perl/perl/t/op/dbm.t b/gnu/usr.bin/perl/perl/t/op/dbm.t
new file mode 100755
index 0000000..23d4d98
--- /dev/null
+++ b/gnu/usr.bin/perl/perl/t/op/dbm.t
@@ -0,0 +1,106 @@
+#!./perl
+
+# $RCSfile: dbm.t,v $$Revision: 1.1.1.1 $$Date: 1993/08/23 21:30:02 $
+
+if (!-r '/usr/include/dbm.h' && !-r '/usr/include/ndbm.h'
+ && !-r '/usr/include/rpcsvc/dbm.h') {
+ print "1..0\n";
+ exit;
+}
+
+print "1..12\n";
+
+unlink <Op.dbmx.*>;
+umask(0);
+print (dbmopen(h,'Op.dbmx',0640) ? "ok 1\n" : "not ok 1\n");
+($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,$atime,$mtime,$ctime,
+ $blksize,$blocks) = stat('Op.dbmx.pag');
+print (($mode & 0777) == 0640 ? "ok 2\n" : "not ok 2\n");
+while (($key,$value) = each(h)) {
+ $i++;
+}
+print (!$i ? "ok 3\n" : "not ok 3\n");
+
+$h{'goner1'} = 'snork';
+
+$h{'abc'} = 'ABC';
+$h{'def'} = 'DEF';
+$h{'jkl','mno'} = "JKL\034MNO";
+$h{'a',2,3,4,5} = join("\034",'A',2,3,4,5);
+$h{'a'} = 'A';
+$h{'b'} = 'B';
+$h{'c'} = 'C';
+$h{'d'} = 'D';
+$h{'e'} = 'E';
+$h{'f'} = 'F';
+$h{'g'} = 'G';
+$h{'h'} = 'H';
+$h{'i'} = 'I';
+
+$h{'goner2'} = 'snork';
+delete $h{'goner2'};
+
+dbmclose(h);
+print (dbmopen(h,'Op.dbmx',0640) ? "ok 4\n" : "not ok 4\n");
+
+$h{'j'} = 'J';
+$h{'k'} = 'K';
+$h{'l'} = 'L';
+$h{'m'} = 'M';
+$h{'n'} = 'N';
+$h{'o'} = 'O';
+$h{'p'} = 'P';
+$h{'q'} = 'Q';
+$h{'r'} = 'R';
+$h{'s'} = 'S';
+$h{'t'} = 'T';
+$h{'u'} = 'U';
+$h{'v'} = 'V';
+$h{'w'} = 'W';
+$h{'x'} = 'X';
+$h{'y'} = 'Y';
+$h{'z'} = 'Z';
+
+$h{'goner3'} = 'snork';
+
+delete $h{'goner1'};
+delete $h{'goner3'};
+
+@keys = keys(%h);
+@values = values(%h);
+
+if ($#keys == 29 && $#values == 29) {print "ok 5\n";} else {print "not ok 5\n";}
+
+while (($key,$value) = each(h)) {
+ if ($key eq $keys[$i] && $value eq $values[$i] && $key gt $value) {
+ $key =~ y/a-z/A-Z/;
+ $i++ if $key eq $value;
+ }
+}
+
+if ($i == 30) {print "ok 6\n";} else {print "not ok 6\n";}
+
+@keys = ('blurfl', keys(h), 'dyick');
+if ($#keys == 31) {print "ok 7\n";} else {print "not ok 7\n";}
+
+$h{'foo'} = '';
+$h{''} = 'bar';
+
+# check cache overflow and numeric keys and contents
+$ok = 1;
+for ($i = 1; $i < 200; $i++) { $h{$i + 0} = $i + 0; }
+for ($i = 1; $i < 200; $i++) { $ok = 0 unless $h{$i} == $i; }
+print ($ok ? "ok 8\n" : "not ok 8\n");
+
+($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,$atime,$mtime,$ctime,
+ $blksize,$blocks) = stat('Op.dbmx.pag');
+print ($size > 0 ? "ok 9\n" : "not ok 9\n");
+
+@h{0..200} = 200..400;
+@foo = @h{0..200};
+print join(':',200..400) eq join(':',@foo) ? "ok 10\n" : "not ok 10\n";
+
+print ($h{'foo'} eq '' ? "ok 11\n" : "not ok 11\n");
+print ($h{''} eq 'bar' ? "ok 12\n" : "not ok 12\n");
+
+unlink 'Op.dbmx.dir', 'Op.dbmx.pag';
diff --git a/gnu/usr.bin/perl/perl/t/op/delete.t b/gnu/usr.bin/perl/perl/t/op/delete.t
new file mode 100755
index 0000000..e4e1fea
--- /dev/null
+++ b/gnu/usr.bin/perl/perl/t/op/delete.t
@@ -0,0 +1,29 @@
+#!./perl
+
+# $Header: /home/cvs/386BSD/ports/lang/perl/t/op/delete.t,v 1.1.1.1 1993/08/23 21:30:03 nate Exp $
+
+print "1..6\n";
+
+$foo{1} = 'a';
+$foo{2} = 'b';
+$foo{3} = 'c';
+
+$foo = delete $foo{2};
+
+if ($foo eq 'b') {print "ok 1\n";} else {print "not ok 1 $foo\n";}
+if ($foo{2} eq '') {print "ok 2\n";} else {print "not ok 2 $foo{2}\n";}
+if ($foo{1} eq 'a') {print "ok 3\n";} else {print "not ok 3\n";}
+if ($foo{3} eq 'c') {print "ok 4\n";} else {print "not ok 4\n";}
+
+$foo = join('',values(foo));
+if ($foo eq 'ac' || $foo eq 'ca') {print "ok 5\n";} else {print "not ok 5\n";}
+
+foreach $key (keys foo) {
+ delete $foo{$key};
+}
+
+$foo{'foo'} = 'x';
+$foo{'bar'} = 'y';
+
+$foo = join('',values(foo));
+if ($foo eq 'xy' || $foo eq 'yx') {print "ok 6\n";} else {print "not ok 6\n";}
diff --git a/gnu/usr.bin/perl/perl/t/op/do.t b/gnu/usr.bin/perl/perl/t/op/do.t
new file mode 100755
index 0000000..370012c
--- /dev/null
+++ b/gnu/usr.bin/perl/perl/t/op/do.t
@@ -0,0 +1,44 @@
+#!./perl
+
+# $Header: /home/cvs/386BSD/ports/lang/perl/t/op/do.t,v 1.1.1.1 1993/08/23 21:30:03 nate Exp $
+
+sub foo1
+{
+ print $_[0];
+ 'value';
+}
+
+sub foo2
+{
+ shift(_);
+ print $_[0];
+ $x = 'value';
+ $x;
+}
+
+print "1..15\n";
+
+$_[0] = "not ok 1\n";
+$result = do foo1("ok 1\n");
+print "#2\t:$result: eq :value:\n";
+if ($result EQ 'value') { print "ok 2\n"; } else { print "not ok 2\n"; }
+if ($_[0] EQ "not ok 1\n") { print "ok 3\n"; } else { print "not ok 3\n"; }
+
+$_[0] = "not ok 4\n";
+$result = do foo2("not ok 4\n","ok 4\n","not ok 4\n");
+print "#5\t:$result: eq :value:\n";
+if ($result EQ 'value') { print "ok 5\n"; } else { print "not ok 5\n"; }
+if ($_[0] EQ "not ok 4\n") { print "ok 6\n"; } else { print "not ok 6\n"; }
+
+$result = do{print "ok 7\n"; 'value';};
+print "#8\t:$result: eq :value:\n";
+if ($result EQ 'value') { print "ok 8\n"; } else { print "not ok 8\n"; }
+
+sub blather {
+ print @_;
+}
+
+do blather("ok 9\n","ok 10\n");
+@x = ("ok 11\n", "ok 12\n");
+@y = ("ok 14\n", "ok 15\n");
+do blather(@x,"ok 13\n",@y);
diff --git a/gnu/usr.bin/perl/perl/t/op/each.t b/gnu/usr.bin/perl/perl/t/op/each.t
new file mode 100755
index 0000000..532d1b0
--- /dev/null
+++ b/gnu/usr.bin/perl/perl/t/op/each.t
@@ -0,0 +1,53 @@
+#!./perl
+
+# $Header: /home/cvs/386BSD/ports/lang/perl/t/op/each.t,v 1.1.1.1 1993/08/23 21:30:03 nate Exp $
+
+print "1..3\n";
+
+$h{'abc'} = 'ABC';
+$h{'def'} = 'DEF';
+$h{'jkl','mno'} = "JKL\034MNO";
+$h{'a',2,3,4,5} = join("\034",'A',2,3,4,5);
+$h{'a'} = 'A';
+$h{'b'} = 'B';
+$h{'c'} = 'C';
+$h{'d'} = 'D';
+$h{'e'} = 'E';
+$h{'f'} = 'F';
+$h{'g'} = 'G';
+$h{'h'} = 'H';
+$h{'i'} = 'I';
+$h{'j'} = 'J';
+$h{'k'} = 'K';
+$h{'l'} = 'L';
+$h{'m'} = 'M';
+$h{'n'} = 'N';
+$h{'o'} = 'O';
+$h{'p'} = 'P';
+$h{'q'} = 'Q';
+$h{'r'} = 'R';
+$h{'s'} = 'S';
+$h{'t'} = 'T';
+$h{'u'} = 'U';
+$h{'v'} = 'V';
+$h{'w'} = 'W';
+$h{'x'} = 'X';
+$h{'y'} = 'Y';
+$h{'z'} = 'Z';
+
+@keys = keys %h;
+@values = values %h;
+
+if ($#keys == 29 && $#values == 29) {print "ok 1\n";} else {print "not ok 1\n";}
+
+while (($key,$value) = each(h)) {
+ if ($key eq $keys[$i] && $value eq $values[$i] && $key gt $value) {
+ $key =~ y/a-z/A-Z/;
+ $i++ if $key eq $value;
+ }
+}
+
+if ($i == 30) {print "ok 2\n";} else {print "not ok 2\n";}
+
+@keys = ('blurfl', keys(%h), 'dyick');
+if ($#keys == 31) {print "ok 3\n";} else {print "not ok 3\n";}
diff --git a/gnu/usr.bin/perl/perl/t/op/eval.t b/gnu/usr.bin/perl/perl/t/op/eval.t
new file mode 100755
index 0000000..b21b44d
--- /dev/null
+++ b/gnu/usr.bin/perl/perl/t/op/eval.t
@@ -0,0 +1,57 @@
+#!./perl
+
+# $RCSfile: eval.t,v $$Revision: 1.1.1.1 $$Date: 1993/08/23 21:30:02 $
+
+print "1..16\n";
+
+eval 'print "ok 1\n";';
+
+if ($@ eq '') {print "ok 2\n";} else {print "not ok 2\n";}
+
+eval "\$foo\n = # this is a comment\n'ok 3';";
+print $foo,"\n";
+
+eval "\$foo\n = # this is a comment\n'ok 4\n';";
+print $foo;
+
+print eval '
+$foo ='; # this tests for a call through yyerror()
+if ($@ =~ /line 2/) {print "ok 5\n";} else {print "not ok 5\n";}
+
+print eval '$foo = /'; # this tests for a call through fatal()
+if ($@ =~ /Search/) {print "ok 6\n";} else {print "not ok 6\n";}
+
+print eval '"ok 7\n";';
+
+# calculate a factorial with recursive evals
+
+$foo = 5;
+$fact = 'if ($foo <= 1) {1;} else {push(@x,$foo--); (eval $fact) * pop(@x);}';
+$ans = eval $fact;
+if ($ans == 120) {print "ok 8\n";} else {print "not ok 8\n";}
+
+$foo = 5;
+$fact = 'local($foo)=$foo; $foo <= 1 ? 1 : $foo-- * (eval $fact);';
+$ans = eval $fact;
+if ($ans == 120) {print "ok 9\n";} else {print "not ok 9 $ans\n";}
+
+open(try,'>Op.eval');
+print try 'print "ok 10\n"; unlink "Op.eval";',"\n";
+close try;
+
+do 'Op.eval'; print $@;
+
+# Test the singlequoted eval optimizer
+
+$i = 11;
+for (1..3) {
+ eval 'print "ok ", $i++, "\n"';
+}
+
+eval {
+ print "ok 14\n";
+ die "ok 16\n";
+ 1;
+} || print "ok 15\n$@";
+
+
diff --git a/gnu/usr.bin/perl/perl/t/op/exec.t b/gnu/usr.bin/perl/perl/t/op/exec.t
new file mode 100755
index 0000000..69909f7
--- /dev/null
+++ b/gnu/usr.bin/perl/perl/t/op/exec.t
@@ -0,0 +1,21 @@
+#!./perl
+
+# $Header: /home/cvs/386BSD/ports/lang/perl/t/op/exec.t,v 1.1.1.1 1993/08/23 21:30:03 nate Exp $
+
+$| = 1; # flush stdout
+print "1..8\n";
+
+print "not ok 1\n" if system "echo ok \\1"; # shell interpreted
+print "not ok 2\n" if system "echo ok 2"; # split and directly called
+print "not ok 3\n" if system "echo", "ok", "3"; # directly called
+
+if (system "true") {print "not ok 4\n";} else {print "ok 4\n";}
+
+if ((system "/bin/sh -c 'exit 1'") != 256) { print "not "; }
+print "ok 5\n";
+
+if ((system "lskdfj") == 255 << 8) {print "ok 6\n";} else {print "not ok 6\n";}
+
+unless (exec "lskdjfalksdjfdjfkls") {print "ok 7\n";} else {print "not ok 7\n";}
+
+exec "echo","ok","8";
diff --git a/gnu/usr.bin/perl/perl/t/op/exp.t b/gnu/usr.bin/perl/perl/t/op/exp.t
new file mode 100755
index 0000000..2195e54
--- /dev/null
+++ b/gnu/usr.bin/perl/perl/t/op/exp.t
@@ -0,0 +1,27 @@
+#!./perl
+
+# $Header: /home/cvs/386BSD/ports/lang/perl/t/op/exp.t,v 1.1.1.1 1993/08/23 21:30:03 nate Exp $
+
+print "1..6\n";
+
+# compile time evaluation
+
+$s = sqrt(2);
+if (substr($s,0,5) eq '1.414') {print "ok 1\n";} else {print "not ok 1\n";}
+
+$s = exp(1);
+if (substr($s,0,7) eq '2.71828') {print "ok 2\n";} else {print "not ok 2\n";}
+
+if (exp(log(1)) == 1) {print "ok 3\n";} else {print "not ok 3\n";}
+
+# run time evaluation
+
+$x1 = 1;
+$x2 = 2;
+$s = sqrt($x2);
+if (substr($s,0,5) eq '1.414') {print "ok 4\n";} else {print "not ok 4\n";}
+
+$s = exp($x1);
+if (substr($s,0,7) eq '2.71828') {print "ok 5\n";} else {print "not ok 5\n";}
+
+if (exp(log($x1)) == 1) {print "ok 6\n";} else {print "not ok 6\n";}
diff --git a/gnu/usr.bin/perl/perl/t/op/flip.t b/gnu/usr.bin/perl/perl/t/op/flip.t
new file mode 100755
index 0000000..74ba508
--- /dev/null
+++ b/gnu/usr.bin/perl/perl/t/op/flip.t
@@ -0,0 +1,26 @@
+#!./perl
+
+# $Header: /home/cvs/386BSD/ports/lang/perl/t/op/flip.t,v 1.1.1.1 1993/08/23 21:30:04 nate Exp $
+
+print "1..8\n";
+
+@a = (1,2,3,4,5,6,7,8,9,10,11,12);
+
+while ($_ = shift(a)) {
+ if ($x = /4/../8/) { $z = $x; print "ok ", $x + 0, "\n"; }
+ $y .= /1/../2/;
+}
+
+if ($z eq '5E0') {print "ok 6\n";} else {print "not ok 6\n";}
+
+if ($y eq '12E0123E0') {print "ok 7\n";} else {print "not ok 7\n";}
+
+@a = ('a','b','c','d','e','f','g');
+
+open(of,'../Makefile');
+while (<of>) {
+ (3 .. 5) && $foo .= $_;
+}
+$x = ($foo =~ y/\n/\n/);
+
+if ($x eq 3) {print "ok 8\n";} else {print "not ok 8 $x:$foo:\n";}
diff --git a/gnu/usr.bin/perl/perl/t/op/fork.t b/gnu/usr.bin/perl/perl/t/op/fork.t
new file mode 100755
index 0000000..10b54a2
--- /dev/null
+++ b/gnu/usr.bin/perl/perl/t/op/fork.t
@@ -0,0 +1,16 @@
+#!./perl
+
+# $Header: /home/cvs/386BSD/ports/lang/perl/t/op/fork.t,v 1.1.1.1 1993/08/23 21:30:04 nate Exp $
+
+$| = 1;
+print "1..2\n";
+
+if ($cid = fork) {
+ sleep 2;
+ if ($result = (kill 9, $cid)) {print "ok 2\n";} else {print "not ok 2 $result\n";}
+}
+else {
+ $| = 1;
+ print "ok 1\n";
+ sleep 10;
+}
diff --git a/gnu/usr.bin/perl/perl/t/op/glob.t b/gnu/usr.bin/perl/perl/t/op/glob.t
new file mode 100755
index 0000000..68b0844
--- /dev/null
+++ b/gnu/usr.bin/perl/perl/t/op/glob.t
@@ -0,0 +1,22 @@
+#!./perl
+
+# $Header: /home/cvs/386BSD/ports/lang/perl/t/op/glob.t,v 1.1.1.1 1993/08/23 21:30:04 nate Exp $
+
+print "1..4\n";
+
+@ops = <op/*>;
+$list = join(' ',@ops);
+
+chop($otherway = `echo op/*`);
+
+print $list eq $otherway ? "ok 1\n" : "not ok 1\n$list\n$otherway\n";
+
+print $/ eq "\n" ? "ok 2\n" : "not ok 2\n";
+
+while (<jskdfjskdfj* op/* jskdjfjkosvk*>) {
+ $not = "not " unless $_ eq shift @ops;
+ $not = "not at all " if $/ eq "\0";
+}
+print "${not}ok 3\n";
+
+print $/ eq "\n" ? "ok 4\n" : "not ok 4\n";
diff --git a/gnu/usr.bin/perl/perl/t/op/goto.t b/gnu/usr.bin/perl/perl/t/op/goto.t
new file mode 100755
index 0000000..44ef343
--- /dev/null
+++ b/gnu/usr.bin/perl/perl/t/op/goto.t
@@ -0,0 +1,33 @@
+#!./perl
+
+# $RCSfile: goto.t,v $$Revision: 1.1.1.1 $$Date: 1993/08/23 21:30:03 $
+
+print "1..3\n";
+
+while (0) {
+ $foo = 1;
+ label1:
+ $foo = 2;
+ goto label2;
+} continue {
+ $foo = 0;
+ goto label4;
+ label3:
+ $foo = 4;
+ goto label4;
+}
+goto label1;
+
+$foo = 3;
+
+label2:
+print "#1\t:$foo: == 2\n";
+if ($foo == 2) {print "ok 1\n";} else {print "not ok 1\n";}
+goto label3;
+
+label4:
+print "#2\t:$foo: == 4\n";
+if ($foo == 4) {print "ok 2\n";} else {print "not ok 2\n";}
+
+$x = `./perl -e 'goto foo;' 2>&1`;
+if ($x =~ /label/) {print "ok 3\n";} else {print "not ok 3\n";}
diff --git a/gnu/usr.bin/perl/perl/t/op/groups.t b/gnu/usr.bin/perl/perl/t/op/groups.t
new file mode 100755
index 0000000..e1520cc
--- /dev/null
+++ b/gnu/usr.bin/perl/perl/t/op/groups.t
@@ -0,0 +1,47 @@
+#!./perl
+
+if (! -x '/usr/ucb/groups') {
+ print "1..0\n";
+ exit 0;
+}
+
+print "1..2\n";
+
+$pwgid = $( + 0;
+($pwgnam) = getgrgid($pwgid);
+@basegroup{$pwgid,$pwgnam} = (1,1);
+
+$seen{$pwgid}++;
+
+for (split(' ', $()) {
+ next if $seen{$_}++;
+ ($group) = getgrgid($_);
+ if (defined $group) {
+ push(@gr, $group);
+ }
+ else {
+ push(@gr, $_);
+ }
+}
+
+$gr1 = join(' ', sort @gr);
+
+$gr2 = join(' ', grep(!$basegroup{$_}, sort split(' ',`/usr/ucb/groups`)));
+
+if ($gr1 eq $gr2) {
+ print "ok 1\n";
+}
+else {
+ print "#gr1 is <$gr1>\n";
+ print "#gr2 is <$gr2>\n";
+ print "not ok 1\n";
+}
+
+# multiple 0's indicate GROUPSTYPE is currently long but should be short
+
+if ($pwgid == 0 || $seen{0} < 2) {
+ print "ok 2\n";
+}
+else {
+ print "not ok 2 (groupstype should be type short, not long)\n";
+}
diff --git a/gnu/usr.bin/perl/perl/t/op/index.t b/gnu/usr.bin/perl/perl/t/op/index.t
new file mode 100755
index 0000000..769314b
--- /dev/null
+++ b/gnu/usr.bin/perl/perl/t/op/index.t
@@ -0,0 +1,42 @@
+#!./perl
+
+# $Header: /home/cvs/386BSD/ports/lang/perl/t/op/index.t,v 1.1.1.1 1993/08/23 21:30:01 nate Exp $
+
+print "1..20\n";
+
+
+$foo = 'Now is the time for all good men to come to the aid of their country.';
+
+$first = substr($foo,0,index($foo,'the'));
+print ($first eq "Now is " ? "ok 1\n" : "not ok 1\n");
+
+$last = substr($foo,rindex($foo,'the'),100);
+print ($last eq "their country." ? "ok 2\n" : "not ok 2\n");
+
+$last = substr($foo,index($foo,'Now'),2);
+print ($last eq "No" ? "ok 3\n" : "not ok 3\n");
+
+$last = substr($foo,rindex($foo,'Now'),2);
+print ($last eq "No" ? "ok 4\n" : "not ok 4\n");
+
+$last = substr($foo,index($foo,'.'),100);
+print ($last eq "." ? "ok 5\n" : "not ok 5\n");
+
+$last = substr($foo,rindex($foo,'.'),100);
+print ($last eq "." ? "ok 6\n" : "not ok 6\n");
+
+print index("ababa","a",-1) == 0 ? "ok 7\n" : "not ok 7\n";
+print index("ababa","a",0) == 0 ? "ok 8\n" : "not ok 8\n";
+print index("ababa","a",1) == 2 ? "ok 9\n" : "not ok 9\n";
+print index("ababa","a",2) == 2 ? "ok 10\n" : "not ok 10\n";
+print index("ababa","a",3) == 4 ? "ok 11\n" : "not ok 11\n";
+print index("ababa","a",4) == 4 ? "ok 12\n" : "not ok 12\n";
+print index("ababa","a",5) == -1 ? "ok 13\n" : "not ok 13\n";
+
+print rindex("ababa","a",-1) == -1 ? "ok 14\n" : "not ok 14\n";
+print rindex("ababa","a",0) == 0 ? "ok 15\n" : "not ok 15\n";
+print rindex("ababa","a",1) == 0 ? "ok 16\n" : "not ok 16\n";
+print rindex("ababa","a",2) == 2 ? "ok 17\n" : "not ok 17\n";
+print rindex("ababa","a",3) == 2 ? "ok 18\n" : "not ok 18\n";
+print rindex("ababa","a",4) == 4 ? "ok 19\n" : "not ok 19\n";
+print rindex("ababa","a",5) == 4 ? "ok 20\n" : "not ok 20\n";
diff --git a/gnu/usr.bin/perl/perl/t/op/int.t b/gnu/usr.bin/perl/perl/t/op/int.t
new file mode 100755
index 0000000..09434b8
--- /dev/null
+++ b/gnu/usr.bin/perl/perl/t/op/int.t
@@ -0,0 +1,17 @@
+#!./perl
+
+# $Header: /home/cvs/386BSD/ports/lang/perl/t/op/int.t,v 1.1.1.1 1993/08/23 21:30:04 nate Exp $
+
+print "1..4\n";
+
+# compile time evaluation
+
+if (int(1.234) == 1) {print "ok 1\n";} else {print "not ok 1\n";}
+
+if (int(-1.234) == -1) {print "ok 2\n";} else {print "not ok 2\n";}
+
+# run time evaluation
+
+$x = 1.234;
+if (int($x) == 1) {print "ok 3\n";} else {print "not ok 3\n";}
+if (int(-$x) == -1) {print "ok 4\n";} else {print "not ok 4\n";}
diff --git a/gnu/usr.bin/perl/perl/t/op/join.t b/gnu/usr.bin/perl/perl/t/op/join.t
new file mode 100755
index 0000000..a6678e9
--- /dev/null
+++ b/gnu/usr.bin/perl/perl/t/op/join.t
@@ -0,0 +1,12 @@
+#!./perl
+
+# $Header: /home/cvs/386BSD/ports/lang/perl/t/op/join.t,v 1.1.1.1 1993/08/23 21:30:02 nate Exp $
+
+print "1..3\n";
+
+@x = (1, 2, 3);
+if (join(':',@x) eq '1:2:3') {print "ok 1\n";} else {print "not ok 1\n";}
+
+if (join('',1,2,3) eq '123') {print "ok 2\n";} else {print "not ok 2\n";}
+
+if (join(':',split(/ /,"1 2 3")) eq '1:2:3') {print "ok 3\n";} else {print "not ok 3\n";}
diff --git a/gnu/usr.bin/perl/perl/t/op/list.t b/gnu/usr.bin/perl/perl/t/op/list.t
new file mode 100755
index 0000000..52b2347
--- /dev/null
+++ b/gnu/usr.bin/perl/perl/t/op/list.t
@@ -0,0 +1,83 @@
+#!./perl
+
+# $Header: /home/cvs/386BSD/ports/lang/perl/t/op/list.t,v 1.1.1.1 1993/08/23 21:30:02 nate Exp $
+
+print "1..27\n";
+
+@foo = (1, 2, 3, 4);
+if ($foo[0] == 1 && $foo[3] == 4) {print "ok 1\n";} else {print "not ok 1\n";}
+
+$_ = join(':',@foo);
+if ($_ eq '1:2:3:4') {print "ok 2\n";} else {print "not ok 2\n";}
+
+($a,$b,$c,$d) = (1,2,3,4);
+if ("$a;$b;$c;$d" eq '1;2;3;4') {print "ok 3\n";} else {print "not ok 3\n";}
+
+($c,$b,$a) = split(/ /,"111 222 333");
+if ("$a;$b;$c" eq '333;222;111') {print "ok 4\n";} else {print "not ok 4\n";}
+
+($a,$b,$c) = ($c,$b,$a);
+if ("$a;$b;$c" eq '111;222;333') {print "ok 5\n";} else {print "not ok 5 $a;$b;$c\n";}
+
+($a, $b) = ($b, $a);
+if ("$a;$b;$c" eq '222;111;333') {print "ok 6\n";} else {print "not ok 6\n";}
+
+($a, $b[1], $c{2}, $d) = (1, 2, 3, 4);
+if ($a eq 1) {print "ok 7\n";} else {print "not ok 7\n";}
+if ($b[1] eq 2) {print "ok 8\n";} else {print "not ok 8\n";}
+if ($c{2} eq 3) {print "ok 9\n";} else {print "not ok 9\n";}
+if ($d eq 4) {print "ok 10\n";} else {print "not ok 10\n";}
+
+@foo = (1,2,3,4,5,6,7,8);
+($a, $b, $c, $d) = @foo;
+print "#11 $a;$b;$c;$d eq 1;2;3;4\n";
+if ("$a;$b;$c;$d" eq '1;2;3;4') {print "ok 11\n";} else {print "not ok 11\n";}
+
+@foo = @bar = (1);
+if (join(':',@foo,@bar) eq '1:1') {print "ok 12\n";} else {print "not ok 12\n";}
+
+@foo = ();
+@foo = 1+2+3;
+if (join(':',@foo) eq '6') {print "ok 13\n";} else {print "not ok 13\n";}
+
+for ($x = 0; $x < 3; $x++) {
+ ($a, $b, $c) =
+ $x == 0?
+ ('ok ', 14, "\n"):
+ $x == 1?
+ ('ok ', 15, "\n"):
+ # default
+ ('ok ', 16, "\n");
+
+ print $a,$b,$c;
+}
+
+@a = ($x == 12345 || (1,2,3));
+if (join('',@a) eq '123') {print "ok 17\n";} else {print "not ok 17\n";}
+
+@a = ($x == $x || (4,5,6));
+if (join('',@a) eq '1') {print "ok 18\n";} else {print "not ok 18\n";}
+
+if (join('',1,2,(3,4,5)) eq '12345'){print "ok 19\n";}else{print "not ok 19\n";}
+if (join('',(1,2,3,4,5)) eq '12345'){print "ok 20\n";}else{print "not ok 20\n";}
+if (join('',(1,2,3,4),5) eq '12345'){print "ok 21\n";}else{print "not ok 21\n";}
+if (join('',1,(2,3,4),5) eq '12345'){print "ok 22\n";}else{print "not ok 22\n";}
+if (join('',1,2,(3,4),5) eq '12345'){print "ok 23\n";}else{print "not ok 23\n";}
+if (join('',1,2,3,(4),5) eq '12345'){print "ok 24\n";}else{print "not ok 24\n";}
+
+for ($x = 0; $x < 3; $x++) {
+ ($a, $b, $c) = do {
+ if ($x == 0) {
+ ('ok ', 25, "\n");
+ }
+ elsif ($x == 1) {
+ ('ok ', 26, "\n");
+ }
+ else {
+ ('ok ', 27, "\n");
+ }
+ };
+
+ print $a,$b,$c;
+}
+
diff --git a/gnu/usr.bin/perl/perl/t/op/local.t b/gnu/usr.bin/perl/perl/t/op/local.t
new file mode 100755
index 0000000..67396e7
--- /dev/null
+++ b/gnu/usr.bin/perl/perl/t/op/local.t
@@ -0,0 +1,45 @@
+#!./perl
+
+# $Header: /home/cvs/386BSD/ports/lang/perl/t/op/local.t,v 1.1.1.1 1993/08/23 21:30:03 nate Exp $
+
+print "1..20\n";
+
+sub foo {
+ local($a, $b) = @_;
+ local($c, $d);
+ $c = "ok 3\n";
+ $d = "ok 4\n";
+ { local($a,$c) = ("ok 9\n", "ok 10\n"); ($x, $y) = ($a, $c); }
+ print $a, $b;
+ $c . $d;
+}
+
+$a = "ok 5\n";
+$b = "ok 6\n";
+$c = "ok 7\n";
+$d = "ok 8\n";
+
+print do foo("ok 1\n","ok 2\n");
+
+print $a,$b,$c,$d,$x,$y;
+
+# same thing, only with arrays and associative arrays
+
+sub foo2 {
+ local($a, @b) = @_;
+ local(@c, %d);
+ @c = "ok 13\n";
+ $d{''} = "ok 14\n";
+ { local($a,@c) = ("ok 19\n", "ok 20\n"); ($x, $y) = ($a, @c); }
+ print $a, @b;
+ $c[0] . $d{''};
+}
+
+$a = "ok 15\n";
+@b = "ok 16\n";
+@c = "ok 17\n";
+$d{''} = "ok 18\n";
+
+print do foo2("ok 11\n","ok 12\n");
+
+print $a,@b,@c,%d,$x,$y;
diff --git a/gnu/usr.bin/perl/perl/t/op/magic.t b/gnu/usr.bin/perl/perl/t/op/magic.t
new file mode 100755
index 0000000..1f47a99
--- /dev/null
+++ b/gnu/usr.bin/perl/perl/t/op/magic.t
@@ -0,0 +1,32 @@
+#!./perl
+
+# $Header: /home/cvs/386BSD/ports/lang/perl/t/op/magic.t,v 1.1.1.1 1993/08/23 21:30:03 nate Exp $
+
+$| = 1; # command buffering
+
+print "1..5\n";
+
+eval '$ENV{"foo"} = "hi there";'; # check that ENV is inited inside eval
+if (`echo \$foo` eq "hi there\n") {print "ok 1\n";} else {print "not ok 1\n";}
+
+unlink 'ajslkdfpqjsjfk';
+$! = 0;
+open(foo,'ajslkdfpqjsjfk');
+if ($! == 2) {print "ok 2\n";} else {print "not ok 2\n";}
+
+# the next tests are embedded inside system simply because sh spits out
+# a newline onto stderr when a child process kills itself with SIGINT.
+
+system './perl',
+'-e', '$| = 1; # command buffering',
+
+'-e', '$SIG{"INT"} = "ok3"; kill 2,$$;',
+'-e', '$SIG{"INT"} = "IGNORE"; kill 2,$$; print "ok 4\n";',
+'-e', '$SIG{"INT"} = "DEFAULT"; kill 2,$$; print "not ok\n";',
+
+'-e', 'sub ok3 { print "ok 3\n" if pop(@_) eq "INT"; }';
+
+@val1 = @ENV{keys(%ENV)}; # can we slice ENV?
+@val2 = values(%ENV);
+
+print join(':',@val1) eq join(':',@val2) ? "ok 5\n" : "not ok 5\n";
diff --git a/gnu/usr.bin/perl/perl/t/op/mkdir.t b/gnu/usr.bin/perl/perl/t/op/mkdir.t
new file mode 100755
index 0000000..0290ed4
--- /dev/null
+++ b/gnu/usr.bin/perl/perl/t/op/mkdir.t
@@ -0,0 +1,15 @@
+#!./perl
+
+# $Header: /home/cvs/386BSD/ports/lang/perl/t/op/mkdir.t,v 1.1.1.1 1993/08/23 21:30:04 nate Exp $
+
+print "1..7\n";
+
+`rm -rf blurfl`;
+
+print (mkdir('blurfl',0777) ? "ok 1\n" : "not ok 1\n");
+print (mkdir('blurfl',0777) ? "not ok 2\n" : "ok 2\n");
+print ($! =~ /exist/ ? "ok 3\n" : "not ok 3\n");
+print (-d 'blurfl' ? "ok 4\n" : "not ok 4\n");
+print (rmdir('blurfl') ? "ok 5\n" : "not ok 5\n");
+print (rmdir('blurfl') ? "not ok 6\n" : "ok 6\n");
+print ($! =~ /such|exist/ ? "ok 7\n" : "not ok 7\n");
diff --git a/gnu/usr.bin/perl/perl/t/op/oct.t b/gnu/usr.bin/perl/perl/t/op/oct.t
new file mode 100755
index 0000000..9322cf0
--- /dev/null
+++ b/gnu/usr.bin/perl/perl/t/op/oct.t
@@ -0,0 +1,9 @@
+#!./perl
+
+# $Header: /home/cvs/386BSD/ports/lang/perl/t/op/oct.t,v 1.1.1.1 1993/08/23 21:30:04 nate Exp $
+
+print "1..3\n";
+
+if (oct('01234') == 01234) {print "ok 1\n";} else {print "not ok 1\n";}
+if (oct('0x1234') == 0x1234) {print "ok 2\n";} else {print "not ok 2\n";}
+if (hex('01234') == 0x1234) {print "ok 3\n";} else {print "not ok 3\n";}
diff --git a/gnu/usr.bin/perl/perl/t/op/ord.t b/gnu/usr.bin/perl/perl/t/op/ord.t
new file mode 100755
index 0000000..9d31988
--- /dev/null
+++ b/gnu/usr.bin/perl/perl/t/op/ord.t
@@ -0,0 +1,14 @@
+#!./perl
+
+# $Header: /home/cvs/386BSD/ports/lang/perl/t/op/ord.t,v 1.1.1.1 1993/08/23 21:30:04 nate Exp $
+
+print "1..2\n";
+
+# compile time evaluation
+
+if (ord('A') == 65) {print "ok 1\n";} else {print "not ok 1\n";}
+
+# run time evaluation
+
+$x = 'ABC';
+if (ord($x) == 65) {print "ok 2\n";} else {print "not ok 2\n";}
diff --git a/gnu/usr.bin/perl/perl/t/op/pack.t b/gnu/usr.bin/perl/perl/t/op/pack.t
new file mode 100755
index 0000000..1dfaddf
--- /dev/null
+++ b/gnu/usr.bin/perl/perl/t/op/pack.t
@@ -0,0 +1,20 @@
+#!./perl
+
+# $Header: /home/cvs/386BSD/ports/lang/perl/t/op/pack.t,v 1.1.1.1 1993/08/23 21:30:03 nate Exp $
+
+print "1..3\n";
+
+$format = "c2x5CCxsdila6";
+# Need the expression in here to force ary[5] to be numeric. This avoids
+# test2 failing because ary2 goes str->numeric->str and ary doesn't.
+@ary = (1,-100,127,128,32767,987.654321098 / 100.0,12345,123456,"abcdef");
+$foo = pack($format,@ary);
+@ary2 = unpack($format,$foo);
+
+print ($#ary == $#ary2 ? "ok 1\n" : "not ok 1\n");
+
+$out1=join(':',@ary);
+$out2=join(':',@ary2);
+print ($out1 eq $out2 ? "ok 2\n" : "not ok 2\n");
+
+print ($foo =~ /def/ ? "ok 3\n" : "not ok 3\n");
diff --git a/gnu/usr.bin/perl/perl/t/op/pat.t b/gnu/usr.bin/perl/perl/t/op/pat.t
new file mode 100755
index 0000000..ce9f35c
--- /dev/null
+++ b/gnu/usr.bin/perl/perl/t/op/pat.t
@@ -0,0 +1,184 @@
+#!./perl
+
+# $RCSfile: pat.t,v $$Revision: 1.1.1.1 $$Date: 1993/08/23 21:30:01 $
+
+print "1..51\n";
+
+$x = "abc\ndef\n";
+
+if ($x =~ /^abc/) {print "ok 1\n";} else {print "not ok 1\n";}
+if ($x !~ /^def/) {print "ok 2\n";} else {print "not ok 2\n";}
+
+$* = 1;
+if ($x =~ /^def/) {print "ok 3\n";} else {print "not ok 3\n";}
+$* = 0;
+
+$_ = '123';
+if (/^([0-9][0-9]*)/) {print "ok 4\n";} else {print "not ok 4\n";}
+
+if ($x =~ /^xxx/) {print "not ok 5\n";} else {print "ok 5\n";}
+if ($x !~ /^abc/) {print "not ok 6\n";} else {print "ok 6\n";}
+
+if ($x =~ /def/) {print "ok 7\n";} else {print "not ok 7\n";}
+if ($x !~ /def/) {print "not ok 8\n";} else {print "ok 8\n";}
+
+if ($x !~ /.def/) {print "ok 9\n";} else {print "not ok 9\n";}
+if ($x =~ /.def/) {print "not ok 10\n";} else {print "ok 10\n";}
+
+if ($x =~ /\ndef/) {print "ok 11\n";} else {print "not ok 11\n";}
+if ($x !~ /\ndef/) {print "not ok 12\n";} else {print "ok 12\n";}
+
+$_ = 'aaabbbccc';
+if (/(a*b*)(c*)/ && $1 eq 'aaabbb' && $2 eq 'ccc') {
+ print "ok 13\n";
+} else {
+ print "not ok 13\n";
+}
+if (/(a+b+c+)/ && $1 eq 'aaabbbccc') {
+ print "ok 14\n";
+} else {
+ print "not ok 14\n";
+}
+
+if (/a+b?c+/) {print "not ok 15\n";} else {print "ok 15\n";}
+
+$_ = 'aaabccc';
+if (/a+b?c+/) {print "ok 16\n";} else {print "not ok 16\n";}
+if (/a*b+c*/) {print "ok 17\n";} else {print "not ok 17\n";}
+
+$_ = 'aaaccc';
+if (/a*b?c*/) {print "ok 18\n";} else {print "not ok 18\n";}
+if (/a*b+c*/) {print "not ok 19\n";} else {print "ok 19\n";}
+
+$_ = 'abcdef';
+if (/bcd|xyz/) {print "ok 20\n";} else {print "not ok 20\n";}
+if (/xyz|bcd/) {print "ok 21\n";} else {print "not ok 21\n";}
+
+if (m|bc/*d|) {print "ok 22\n";} else {print "not ok 22\n";}
+
+if (/^$_$/) {print "ok 23\n";} else {print "not ok 23\n";}
+
+$* = 1; # test 3 only tested the optimized version--this one is for real
+if ("ab\ncd\n" =~ /^cd/) {print "ok 24\n";} else {print "not ok 24\n";}
+$* = 0;
+
+$XXX{123} = 123;
+$XXX{234} = 234;
+$XXX{345} = 345;
+
+@XXX = ('ok 25','not ok 25', 'ok 26','not ok 26','not ok 27');
+while ($_ = shift(XXX)) {
+ ?(.*)? && (print $1,"\n");
+ /not/ && reset;
+ /not ok 26/ && reset 'X';
+}
+
+while (($key,$val) = each(XXX)) {
+ print "not ok 27\n";
+ exit;
+}
+
+print "ok 27\n";
+
+'cde' =~ /[^ab]*/;
+'xyz' =~ //;
+if ($& eq 'xyz') {print "ok 28\n";} else {print "not ok 28\n";}
+
+$foo = '[^ab]*';
+'cde' =~ /$foo/;
+'xyz' =~ //;
+if ($& eq 'xyz') {print "ok 29\n";} else {print "not ok 29\n";}
+
+$foo = '[^ab]*';
+'cde' =~ /$foo/;
+'xyz' =~ /$null/;
+if ($& eq 'xyz') {print "ok 30\n";} else {print "not ok 30\n";}
+
+$_ = 'abcdefghi';
+/def/; # optimized up to cmd
+if ("$`:$&:$'" eq 'abc:def:ghi') {print "ok 31\n";} else {print "not ok 31\n";}
+
+/cde/ + 0; # optimized only to spat
+if ("$`:$&:$'" eq 'ab:cde:fghi') {print "ok 32\n";} else {print "not ok 32\n";}
+
+/[d][e][f]/; # not optimized
+if ("$`:$&:$'" eq 'abc:def:ghi') {print "ok 33\n";} else {print "not ok 33\n";}
+
+$_ = 'now is the {time for all} good men to come to.';
+/ {([^}]*)}/;
+if ($1 eq 'time for all') {print "ok 34\n";} else {print "not ok 34 $1\n";}
+
+$_ = 'xxx {3,4} yyy zzz';
+print /( {3,4})/ ? "ok 35\n" : "not ok 35\n";
+print $1 eq ' ' ? "ok 36\n" : "not ok 36\n";
+print /( {4,})/ ? "not ok 37\n" : "ok 37\n";
+print /( {2,3}.)/ ? "ok 38\n" : "not ok 38\n";
+print $1 eq ' y' ? "ok 39\n" : "not ok 39\n";
+print /(y{2,3}.)/ ? "ok 40\n" : "not ok 40\n";
+print $1 eq 'yyy ' ? "ok 41\n" : "not ok 41\n";
+print /x {3,4}/ ? "not ok 42\n" : "ok 42\n";
+print /^xxx {3,4}/ ? "not ok 43\n" : "ok 43\n";
+
+$_ = "now is the time for all good men to come to.";
+@words = /(\w+)/g;
+print join(':',@words) eq "now:is:the:time:for:all:good:men:to:come:to"
+ ? "ok 44\n"
+ : "not ok 44\n";
+
+@words = ();
+while (/\w+/g) {
+ push(@words, $&);
+}
+print join(':',@words) eq "now:is:the:time:for:all:good:men:to:come:to"
+ ? "ok 45\n"
+ : "not ok 45\n";
+
+@words = ();
+while (/to/g) {
+ push(@words, $&);
+}
+print join(':',@words) eq "to:to"
+ ? "ok 46\n"
+ : "not ok 46 @words\n";
+
+@words = /to/g;
+print join(':',@words) eq "to:to"
+ ? "ok 47\n"
+ : "not ok 47 @words\n";
+
+$_ = "abcdefghi";
+
+$pat1 = 'def';
+$pat2 = '^def';
+$pat3 = '.def.';
+$pat4 = 'abc';
+$pat5 = '^abc';
+$pat6 = 'abc$';
+$pat7 = 'ghi';
+$pat8 = '\w*ghi';
+$pat9 = 'ghi$';
+
+$t1=$t2=$t3=$t4=$t5=$t6=$t7=$t8=$t9=0;
+
+for $iter (1..5) {
+ $t1++ if /$pat1/o;
+ $t2++ if /$pat2/o;
+ $t3++ if /$pat3/o;
+ $t4++ if /$pat4/o;
+ $t5++ if /$pat5/o;
+ $t6++ if /$pat6/o;
+ $t7++ if /$pat7/o;
+ $t8++ if /$pat8/o;
+ $t9++ if /$pat9/o;
+}
+
+$x = "$t1$t2$t3$t4$t5$t6$t7$t8$t9";
+print $x eq '505550555' ? "ok 48\n" : "not ok 48 $x\n";
+
+$xyz = 'xyz';
+print "abc" =~ /^abc$|$xyz/ ? "ok 49\n" : "not ok 49\n";
+
+# perl 4.009 says "unmatched ()"
+eval '"abc" =~ /a(bc$)|$xyz/; $result = "$&:$1"';
+print $@ eq "" ? "ok 50\n" : "not ok 50\n";
+print $result eq "abc:bc" ? "ok 51\n" : "not ok 51\n";
diff --git a/gnu/usr.bin/perl/perl/t/op/push.t b/gnu/usr.bin/perl/perl/t/op/push.t
new file mode 100755
index 0000000..3d738ac
--- /dev/null
+++ b/gnu/usr.bin/perl/perl/t/op/push.t
@@ -0,0 +1,44 @@
+#!./perl
+
+# $Header: /home/cvs/386BSD/ports/lang/perl/t/op/push.t,v 1.1.1.1 1993/08/23 21:30:03 nate Exp $
+
+@tests = split(/\n/, <<EOF);
+0 3, 0 1 2, 3 4 5 6 7
+0 0 a b c, , a b c 0 1 2 3 4 5 6 7
+8 0 a b c, , 0 1 2 3 4 5 6 7 a b c
+7 0 6.5, , 0 1 2 3 4 5 6 6.5 7
+1 0 a b c d e f g h i j,, 0 a b c d e f g h i j 1 2 3 4 5 6 7
+0 1 a, 0, a 1 2 3 4 5 6 7
+1 6 x y z, 1 2 3 4 5 6, 0 x y z 7
+0 7 x y z, 0 1 2 3 4 5 6, x y z 7
+1 7 x y z, 1 2 3 4 5 6 7, 0 x y z
+4, 4 5 6 7, 0 1 2 3
+-4, 4 5 6 7, 0 1 2 3
+EOF
+
+print "1..", 2 + @tests, "\n";
+die "blech" unless @tests;
+
+@x = (1,2,3);
+push(@x,@x);
+if (join(':',@x) eq '1:2:3:1:2:3') {print "ok 1\n";} else {print "not ok 1\n";}
+push(x,4);
+if (join(':',@x) eq '1:2:3:1:2:3:4') {print "ok 2\n";} else {print "not ok 2\n";}
+
+$test = 3;
+foreach $line (@tests) {
+ ($list,$get,$leave) = split(/,\t*/,$line);
+ @list = split(' ',$list);
+ @get = split(' ',$get);
+ @leave = split(' ',$leave);
+ @x = (0,1,2,3,4,5,6,7);
+ @got = splice(@x,@list);
+ if (join(':',@got) eq join(':',@get) &&
+ join(':',@x) eq join(':',@leave)) {
+ print "ok ",$test++,"\n";
+ }
+ else {
+ print "not ok ",$test++," got: @got == @get left: @x == @leave\n";
+ }
+}
+
diff --git a/gnu/usr.bin/perl/perl/t/op/range.t b/gnu/usr.bin/perl/perl/t/op/range.t
new file mode 100755
index 0000000..6214f95
--- /dev/null
+++ b/gnu/usr.bin/perl/perl/t/op/range.t
@@ -0,0 +1,36 @@
+#!./perl
+
+# $Header: /home/cvs/386BSD/ports/lang/perl/t/op/range.t,v 1.1.1.1 1993/08/23 21:30:03 nate Exp $
+
+print "1..8\n";
+
+print join(':',1..5) eq '1:2:3:4:5' ? "ok 1\n" : "not ok 1\n";
+
+@foo = (1,2,3,4,5,6,7,8,9);
+@foo[2..4] = ('c','d','e');
+
+print join(':',@foo[$foo[0]..5]) eq '2:c:d:e:6' ? "ok 2\n" : "not ok 2\n";
+
+@bar[2..4] = ('c','d','e');
+print join(':',@bar[1..5]) eq ':c:d:e:' ? "ok 3\n" : "not ok 3\n";
+
+($a,@bcd[0..2],$e) = ('a','b','c','d','e');
+print join(':',$a,@bcd[0..2],$e) eq 'a:b:c:d:e' ? "ok 4\n" : "not ok 4\n";
+
+$x = 0;
+for (1..100) {
+ $x += $_;
+}
+print $x == 5050 ? "ok 5\n" : "not ok 5 $x\n";
+
+$x = 0;
+for ((100,2..99,1)) {
+ $x += $_;
+}
+print $x == 5050 ? "ok 6\n" : "not ok 6 $x\n";
+
+$x = join('','a'..'z');
+print $x eq 'abcdefghijklmnopqrstuvwxyz' ? "ok 7\n" : "not ok 7 $x\n";
+
+@x = 'A'..'ZZ';
+print @x == 27 * 26 ? "ok 8\n" : "not ok 8\n";
diff --git a/gnu/usr.bin/perl/perl/t/op/re_tests b/gnu/usr.bin/perl/perl/t/op/re_tests
new file mode 100644
index 0000000..ee03d6f
--- /dev/null
+++ b/gnu/usr.bin/perl/perl/t/op/re_tests
@@ -0,0 +1,274 @@
+abc abc y $& abc
+abc xbc n - -
+abc axc n - -
+abc abx n - -
+abc xabcy y $& abc
+abc ababc y $& abc
+ab*c abc y $& abc
+ab*bc abc y $& abc
+ab*bc abbc y $& abbc
+ab*bc abbbbc y $& abbbbc
+ab{0,}bc abbbbc y $& abbbbc
+ab+bc abbc y $& abbc
+ab+bc abc n - -
+ab+bc abq n - -
+ab{1,}bc abq n - -
+ab+bc abbbbc y $& abbbbc
+ab{1,}bc abbbbc y $& abbbbc
+ab{1,3}bc abbbbc y $& abbbbc
+ab{3,4}bc abbbbc y $& abbbbc
+ab{4,5}bc abbbbc n - -
+ab?bc abbc y $& abbc
+ab?bc abc y $& abc
+ab{0,1}bc abc y $& abc
+ab?bc abbbbc n - -
+ab?c abc y $& abc
+ab{0,1}c abc y $& abc
+^abc$ abc y $& abc
+^abc$ abcc n - -
+^abc abcc y $& abc
+^abc$ aabc n - -
+abc$ aabc y $& abc
+^ abc y $&
+$ abc y $&
+a.c abc y $& abc
+a.c axc y $& axc
+a.*c axyzc y $& axyzc
+a.*c axyzd n - -
+a[bc]d abc n - -
+a[bc]d abd y $& abd
+a[b-d]e abd n - -
+a[b-d]e ace y $& ace
+a[b-d] aac y $& ac
+a[-b] a- y $& a-
+a[b-] a- y $& a-
+a[b-a] - c - -
+a[]b - c - -
+a[ - c - -
+a] a] y $& a]
+a[]]b a]b y $& a]b
+a[^bc]d aed y $& aed
+a[^bc]d abd n - -
+a[^-b]c adc y $& adc
+a[^-b]c a-c n - -
+a[^]b]c a]c n - -
+a[^]b]c adc y $& adc
+ab|cd abc y $& ab
+ab|cd abcd y $& ab
+()ef def y $&-$1 ef-
+()* - c - -
+*a - c - -
+^* - c - -
+$* - c - -
+(*)b - c - -
+$b b n - -
+a\ - c - -
+a\(b a(b y $&-$1 a(b-
+a\(*b ab y $& ab
+a\(*b a((b y $& a((b
+a\\b a\b y $& a\b
+abc) - c - -
+(abc - c - -
+((a)) abc y $&-$1-$2 a-a-a
+(a)b(c) abc y $&-$1-$2 abc-a-c
+a+b+c aabbabc y $& abc
+a{1,}b{1,}c aabbabc y $& abc
+a** - c - -
+a*? - c - -
+(a*)* - c - -
+(a*)+ - c - -
+(a|)* - c - -
+(a*|b)* - c - -
+(a+|b)* ab y $&-$1 ab-b
+(a+|b){0,} ab y $&-$1 ab-b
+(a+|b)+ ab y $&-$1 ab-b
+(a+|b){1,} ab y $&-$1 ab-b
+(a+|b)? ab y $&-$1 a-a
+(a+|b){0,1} ab y $&-$1 a-a
+(^)* - c - -
+(ab|)* - c - -
+)( - c - -
+[^ab]* cde y $& cde
+abc n - -
+a* y $&
+([abc])*d abbbcd y $&-$1 abbbcd-c
+([abc])*bcd abcd y $&-$1 abcd-a
+a|b|c|d|e e y $& e
+(a|b|c|d|e)f ef y $&-$1 ef-e
+((a*|b))* - c - -
+abcd*efg abcdefg y $& abcdefg
+ab* xabyabbbz y $& ab
+ab* xayabbbz y $& a
+(ab|cd)e abcde y $&-$1 cde-cd
+[abhgefdc]ij hij y $& hij
+^(ab|cd)e abcde n x$1y xy
+(abc|)ef abcdef y $&-$1 ef-
+(a|b)c*d abcd y $&-$1 bcd-b
+(ab|ab*)bc abc y $&-$1 abc-a
+a([bc]*)c* abc y $&-$1 abc-bc
+a([bc]*)(c*d) abcd y $&-$1-$2 abcd-bc-d
+a([bc]+)(c*d) abcd y $&-$1-$2 abcd-bc-d
+a([bc]*)(c+d) abcd y $&-$1-$2 abcd-b-cd
+a[bcd]*dcdcde adcdcde y $& adcdcde
+a[bcd]+dcdcde adcdcde n - -
+(ab|a)b*c abc y $&-$1 abc-ab
+((a)(b)c)(d) abcd y $1-$2-$3-$4 abc-a-b-d
+[a-zA-Z_][a-zA-Z0-9_]* alpha y $& alpha
+^a(bc+|b[eh])g|.h$ abh y $&-$1 bh-
+(bc+d$|ef*g.|h?i(j|k)) effgz y $&-$1-$2 effgz-effgz-
+(bc+d$|ef*g.|h?i(j|k)) ij y $&-$1-$2 ij-ij-j
+(bc+d$|ef*g.|h?i(j|k)) effg n - -
+(bc+d$|ef*g.|h?i(j|k)) bcdd n - -
+(bc+d$|ef*g.|h?i(j|k)) reffgz y $&-$1-$2 effgz-effgz-
+((((((((((a)))))))))) a y $10 a
+((((((((((a))))))))))\10 aa y $& aa
+((((((((((a))))))))))\41 aa n - -
+((((((((((a))))))))))\41 a! y $& a!
+(((((((((a))))))))) a y $& a
+multiple words of text uh-uh n - -
+multiple words multiple words, yeah y $& multiple words
+(.*)c(.*) abcde y $&-$1-$2 abcde-ab-de
+\((.*), (.*)\) (a, b) y ($2, $1) (b, a)
+[k] ab n - -
+abcd abcd y $&-\$&-\\$& abcd-$&-\abcd
+a(bc)d abcd y $1-\$1-\\$1 bc-$1-\bc
+a[-]?c ac y $& ac
+(abc)\1 abcabc y $1 abc
+([a-c]*)\1 abcabc y $1 abc
+'abc'i ABC y $& ABC
+'abc'i XBC n - -
+'abc'i AXC n - -
+'abc'i ABX n - -
+'abc'i XABCY y $& ABC
+'abc'i ABABC y $& ABC
+'ab*c'i ABC y $& ABC
+'ab*bc'i ABC y $& ABC
+'ab*bc'i ABBC y $& ABBC
+'ab*bc'i ABBBBC y $& ABBBBC
+'ab{0,}bc'i ABBBBC y $& ABBBBC
+'ab+bc'i ABBC y $& ABBC
+'ab+bc'i ABC n - -
+'ab+bc'i ABQ n - -
+'ab{1,}bc'i ABQ n - -
+'ab+bc'i ABBBBC y $& ABBBBC
+'ab{1,}bc'i ABBBBC y $& ABBBBC
+'ab{1,3}bc'i ABBBBC y $& ABBBBC
+'ab{3,4}bc'i ABBBBC y $& ABBBBC
+'ab{4,5}bc'i ABBBBC n - -
+'ab?bc'i ABBC y $& ABBC
+'ab?bc'i ABC y $& ABC
+'ab{0,1}bc'i ABC y $& ABC
+'ab?bc'i ABBBBC n - -
+'ab?c'i ABC y $& ABC
+'ab{0,1}c'i ABC y $& ABC
+'^abc$'i ABC y $& ABC
+'^abc$'i ABCC n - -
+'^abc'i ABCC y $& ABC
+'^abc$'i AABC n - -
+'abc$'i AABC y $& ABC
+'^'i ABC y $&
+'$'i ABC y $&
+'a.c'i ABC y $& ABC
+'a.c'i AXC y $& AXC
+'a.*c'i AXYZC y $& AXYZC
+'a.*c'i AXYZD n - -
+'a[bc]d'i ABC n - -
+'a[bc]d'i ABD y $& ABD
+'a[b-d]e'i ABD n - -
+'a[b-d]e'i ACE y $& ACE
+'a[b-d]'i AAC y $& AC
+'a[-b]'i A- y $& A-
+'a[b-]'i A- y $& A-
+'a[b-a]'i - c - -
+'a[]b'i - c - -
+'a['i - c - -
+'a]'i A] y $& A]
+'a[]]b'i A]B y $& A]B
+'a[^bc]d'i AED y $& AED
+'a[^bc]d'i ABD n - -
+'a[^-b]c'i ADC y $& ADC
+'a[^-b]c'i A-C n - -
+'a[^]b]c'i A]C n - -
+'a[^]b]c'i ADC y $& ADC
+'ab|cd'i ABC y $& AB
+'ab|cd'i ABCD y $& AB
+'()ef'i DEF y $&-$1 EF-
+'()*'i - c - -
+'*a'i - c - -
+'^*'i - c - -
+'$*'i - c - -
+'(*)b'i - c - -
+'$b'i B n - -
+'a\'i - c - -
+'a\(b'i A(B y $&-$1 A(B-
+'a\(*b'i AB y $& AB
+'a\(*b'i A((B y $& A((B
+'a\\b'i A\B y $& A\B
+'abc)'i - c - -
+'(abc'i - c - -
+'((a))'i ABC y $&-$1-$2 A-A-A
+'(a)b(c)'i ABC y $&-$1-$2 ABC-A-C
+'a+b+c'i AABBABC y $& ABC
+'a{1,}b{1,}c'i AABBABC y $& ABC
+'a**'i - c - -
+'a*?'i - c - -
+'(a*)*'i - c - -
+'(a*)+'i - c - -
+'(a|)*'i - c - -
+'(a*|b)*'i - c - -
+'(a+|b)*'i AB y $&-$1 AB-B
+'(a+|b){0,}'i AB y $&-$1 AB-B
+'(a+|b)+'i AB y $&-$1 AB-B
+'(a+|b){1,}'i AB y $&-$1 AB-B
+'(a+|b)?'i AB y $&-$1 A-A
+'(a+|b){0,1}'i AB y $&-$1 A-A
+'(^)*'i - c - -
+'(ab|)*'i - c - -
+')('i - c - -
+'[^ab]*'i CDE y $& CDE
+'abc'i n - -
+'a*'i y $&
+'([abc])*d'i ABBBCD y $&-$1 ABBBCD-C
+'([abc])*bcd'i ABCD y $&-$1 ABCD-A
+'a|b|c|d|e'i E y $& E
+'(a|b|c|d|e)f'i EF y $&-$1 EF-E
+'((a*|b))*'i - c - -
+'abcd*efg'i ABCDEFG y $& ABCDEFG
+'ab*'i XABYABBBZ y $& AB
+'ab*'i XAYABBBZ y $& A
+'(ab|cd)e'i ABCDE y $&-$1 CDE-CD
+'[abhgefdc]ij'i HIJ y $& HIJ
+'^(ab|cd)e'i ABCDE n x$1y XY
+'(abc|)ef'i ABCDEF y $&-$1 EF-
+'(a|b)c*d'i ABCD y $&-$1 BCD-B
+'(ab|ab*)bc'i ABC y $&-$1 ABC-A
+'a([bc]*)c*'i ABC y $&-$1 ABC-BC
+'a([bc]*)(c*d)'i ABCD y $&-$1-$2 ABCD-BC-D
+'a([bc]+)(c*d)'i ABCD y $&-$1-$2 ABCD-BC-D
+'a([bc]*)(c+d)'i ABCD y $&-$1-$2 ABCD-B-CD
+'a[bcd]*dcdcde'i ADCDCDE y $& ADCDCDE
+'a[bcd]+dcdcde'i ADCDCDE n - -
+'(ab|a)b*c'i ABC y $&-$1 ABC-AB
+'((a)(b)c)(d)'i ABCD y $1-$2-$3-$4 ABC-A-B-D
+'[a-zA-Z_][a-zA-Z0-9_]*'i ALPHA y $& ALPHA
+'^a(bc+|b[eh])g|.h$'i ABH y $&-$1 BH-
+'(bc+d$|ef*g.|h?i(j|k))'i EFFGZ y $&-$1-$2 EFFGZ-EFFGZ-
+'(bc+d$|ef*g.|h?i(j|k))'i IJ y $&-$1-$2 IJ-IJ-J
+'(bc+d$|ef*g.|h?i(j|k))'i EFFG n - -
+'(bc+d$|ef*g.|h?i(j|k))'i BCDD n - -
+'(bc+d$|ef*g.|h?i(j|k))'i REFFGZ y $&-$1-$2 EFFGZ-EFFGZ-
+'((((((((((a))))))))))'i A y $10 A
+'((((((((((a))))))))))\10'i AA y $& AA
+'((((((((((a))))))))))\41'i AA n - -
+'((((((((((a))))))))))\41'i A! y $& A!
+'(((((((((a)))))))))'i A y $& A
+'multiple words of text'i UH-UH n - -
+'multiple words'i MULTIPLE WORDS, YEAH y $& MULTIPLE WORDS
+'(.*)c(.*)'i ABCDE y $&-$1-$2 ABCDE-AB-DE
+'\((.*), (.*)\)'i (A, B) y ($2, $1) (B, A)
+'[k]'i AB n - -
+'abcd'i ABCD y $&-\$&-\\$& ABCD-$&-\ABCD
+'a(bc)d'i ABCD y $1-\$1-\\$1 BC-$1-\BC
+'a[-]?c'i AC y $& AC
+'(abc)\1'i ABCABC y $1 ABC
+'([a-c]*)\1'i ABCABC y $1 ABC
diff --git a/gnu/usr.bin/perl/perl/t/op/read.t b/gnu/usr.bin/perl/perl/t/op/read.t
new file mode 100755
index 0000000..4151e5c
--- /dev/null
+++ b/gnu/usr.bin/perl/perl/t/op/read.t
@@ -0,0 +1,20 @@
+#!./perl
+
+# $Header: /home/cvs/386BSD/ports/lang/perl/t/op/read.t,v 1.1.1.1 1993/08/23 21:30:04 nate Exp $
+
+print "1..4\n";
+
+
+open(FOO,'op/read.t') || open(FOO,'./read.t') || open(FOO,'t/op/read.t') || die "Can't open op.read";
+seek(FOO,4,0);
+$got = read(FOO,$buf,4);
+print "This is got ... $got\n";
+
+print ($got == 4 ? "ok 1\n" : "not ok 1\n");
+print ($buf eq "perl" ? "ok 2\n" : "not ok 2 :$buf:\n");
+
+seek(FOO,20000,0);
+$got = read(FOO,$buf,4);
+
+print ($got == 0 ? "ok 3\n" : "not ok 3\n");
+print ($buf eq "" ? "ok 4\n" : "not ok 4\n");
diff --git a/gnu/usr.bin/perl/perl/t/op/readdir.t b/gnu/usr.bin/perl/perl/t/op/readdir.t
new file mode 100755
index 0000000..1800699
--- /dev/null
+++ b/gnu/usr.bin/perl/perl/t/op/readdir.t
@@ -0,0 +1,20 @@
+#!./perl
+
+eval 'opendir(NOSUCH, "no/such/directory");';
+if ($@) { print "1..0\n"; exit; }
+
+print "1..3\n";
+
+if (opendir(OP, "op")) { print "ok 1\n"; } else { print "not ok 1\n"; }
+@D = grep(/^[^\.].*\.t$/, readdir(OP));
+closedir(OP);
+
+if (@D > 20 && @D < 100) { print "ok 2\n"; } else { print "not ok 2\n"; }
+
+@R = sort @D;
+@G = <op/*.t>;
+while (@R && @G && "op/".$R[0] eq $G[0]) {
+ shift(@R);
+ shift(@G);
+}
+if (@R == 0 && @G == 0) { print "ok 3\n"; } else { print "not ok 3\n"; }
diff --git a/gnu/usr.bin/perl/perl/t/op/regexp.t b/gnu/usr.bin/perl/perl/t/op/regexp.t
new file mode 100755
index 0000000..58f6666
--- /dev/null
+++ b/gnu/usr.bin/perl/perl/t/op/regexp.t
@@ -0,0 +1,35 @@
+#!./perl
+
+# $RCSfile: regexp.t,v $$Revision: 1.1.1.1 $$Date: 1993/08/23 21:30:03 $
+
+open(TESTS,'op/re_tests') || open(TESTS,'t/op/re_tests')
+ || die "Can't open re_tests";
+while (<TESTS>) { }
+$numtests = $.;
+close(TESTS);
+
+print "1..$numtests\n";
+open(TESTS,'op/re_tests') || open(TESTS,'t/op/re_tests')
+ || die "Can't open re_tests";
+$| = 1;
+while (<TESTS>) {
+ ($pat, $subject, $result, $repl, $expect) = split(/[\t\n]/,$_);
+ $input = join(':',$pat,$subject,$result,$repl,$expect);
+ $pat = "'$pat'" unless $pat =~ /^'/;
+ eval "\$match = (\$subject =~ m$pat); \$got = \"$repl\";";
+ if ($result eq 'c') {
+ if ($@ ne '') {print "ok $.\n";} else {print "not ok $.\n";}
+ }
+ elsif ($result eq 'n') {
+ if (!$match) {print "ok $.\n";} else {print "not ok $. $input => $got\n";}
+ }
+ else {
+ if ($match && $got eq $expect) {
+ print "ok $.\n";
+ }
+ else {
+ print "not ok $. $input => $got\n";
+ }
+ }
+}
+close(TESTS);
diff --git a/gnu/usr.bin/perl/perl/t/op/repeat.t b/gnu/usr.bin/perl/perl/t/op/repeat.t
new file mode 100755
index 0000000..68c61fc
--- /dev/null
+++ b/gnu/usr.bin/perl/perl/t/op/repeat.t
@@ -0,0 +1,42 @@
+#!./perl
+
+# $Header: /home/cvs/386BSD/ports/lang/perl/t/op/repeat.t,v 1.1.1.1 1993/08/23 21:30:02 nate Exp $
+
+print "1..19\n";
+
+# compile time
+
+if ('-' x 5 eq '-----') {print "ok 1\n";} else {print "not ok 1\n";}
+if ('-' x 1 eq '-') {print "ok 2\n";} else {print "not ok 2\n";}
+if ('-' x 0 eq '') {print "ok 3\n";} else {print "not ok 3\n";}
+
+if ('ab' x 3 eq 'ababab') {print "ok 4\n";} else {print "not ok 4\n";}
+
+# run time
+
+$a = '-';
+if ($a x 5 eq '-----') {print "ok 5\n";} else {print "not ok 5\n";}
+if ($a x 1 eq '-') {print "ok 6\n";} else {print "not ok 6\n";}
+if ($a x 0 eq '') {print "ok 7\n";} else {print "not ok 7\n";}
+
+$a = 'ab';
+if ($a x 3 eq 'ababab') {print "ok 8\n";} else {print "not ok 8\n";}
+
+$a = 'xyz';
+$a x= 2;
+if ($a eq 'xyzxyz') {print "ok 9\n";} else {print "not ok 9\n";}
+$a x= 1;
+if ($a eq 'xyzxyz') {print "ok 10\n";} else {print "not ok 10\n";}
+$a x= 0;
+if ($a eq '') {print "ok 11\n";} else {print "not ok 11\n";}
+
+@x = (1,2,3);
+
+print join('', @x x 4) eq '3333' ? "ok 12\n" : "not ok 12\n";
+print join('', (@x) x 4) eq '123123123123' ? "ok 13\n" : "not ok 13\n";
+print join('', (@x,()) x 4) eq '123123123123' ? "ok 14\n" : "not ok 14\n";
+print join('', (@x,1) x 4) eq '1231123112311231' ? "ok 15\n" : "not ok 15\n";
+print join(':', () x 4) eq '' ? "ok 16\n" : "not ok 16\n";
+print join(':', (9) x 4) eq '9:9:9:9' ? "ok 17\n" : "not ok 17\n";
+print join(':', (9,9) x 4) eq '9:9:9:9:9:9:9:9' ? "ok 18\n" : "not ok 18\n";
+print join('', (split(//,"123")) x 2) eq '123123' ? "ok 19\n" : "not ok 19\n";
diff --git a/gnu/usr.bin/perl/perl/t/op/s.t b/gnu/usr.bin/perl/perl/t/op/s.t
new file mode 100755
index 0000000..5930020
--- /dev/null
+++ b/gnu/usr.bin/perl/perl/t/op/s.t
@@ -0,0 +1,179 @@
+#!./perl
+
+# $Header: /home/cvs/386BSD/ports/lang/perl/t/op/s.t,v 1.1.1.1 1993/08/23 21:30:01 nate Exp $
+
+print "1..51\n";
+
+$x = 'foo';
+$_ = "x";
+s/x/\$x/;
+print "#1\t:$_: eq :\$x:\n";
+if ($_ eq '$x') {print "ok 1\n";} else {print "not ok 1\n";}
+
+$_ = "x";
+s/x/$x/;
+print "#2\t:$_: eq :foo:\n";
+if ($_ eq 'foo') {print "ok 2\n";} else {print "not ok 2\n";}
+
+$_ = "x";
+s/x/\$x $x/;
+print "#3\t:$_: eq :\$x foo:\n";
+if ($_ eq '$x foo') {print "ok 3\n";} else {print "not ok 3\n";}
+
+$b = 'cd';
+($a = 'abcdef') =~ s'(b${b}e)'\n$1';
+print "#4\t:$1: eq :bcde:\n";
+print "#4\t:$a: eq :a\\n\$1f:\n";
+if ($1 eq 'bcde' && $a eq 'a\n$1f') {print "ok 4\n";} else {print "not ok 4\n";}
+
+$a = 'abacada';
+if (($a =~ s/a/x/g) == 4 && $a eq 'xbxcxdx')
+ {print "ok 5\n";} else {print "not ok 5\n";}
+
+if (($a =~ s/a/y/g) == 0 && $a eq 'xbxcxdx')
+ {print "ok 6\n";} else {print "not ok 6 $a\n";}
+
+if (($a =~ s/b/y/g) == 1 && $a eq 'xyxcxdx')
+ {print "ok 7\n";} else {print "not ok 7 $a\n";}
+
+$_ = 'ABACADA';
+if (/a/i && s///gi && $_ eq 'BCD') {print "ok 8\n";} else {print "not ok 8 $_\n";}
+
+$_ = '\\' x 4;
+if (length($_) == 4) {print "ok 9\n";} else {print "not ok 9\n";}
+s/\\/\\\\/g;
+if ($_ eq '\\' x 8) {print "ok 10\n";} else {print "not ok 10 $_\n";}
+
+$_ = '\/' x 4;
+if (length($_) == 8) {print "ok 11\n";} else {print "not ok 11\n";}
+s/\//\/\//g;
+if ($_ eq '\\//' x 4) {print "ok 12\n";} else {print "not ok 12\n";}
+if (length($_) == 12) {print "ok 13\n";} else {print "not ok 13\n";}
+
+$_ = 'aaaXXXXbbb';
+s/^a//;
+print $_ eq 'aaXXXXbbb' ? "ok 14\n" : "not ok 14\n";
+
+$_ = 'aaaXXXXbbb';
+s/a//;
+print $_ eq 'aaXXXXbbb' ? "ok 15\n" : "not ok 15\n";
+
+$_ = 'aaaXXXXbbb';
+s/^a/b/;
+print $_ eq 'baaXXXXbbb' ? "ok 16\n" : "not ok 16\n";
+
+$_ = 'aaaXXXXbbb';
+s/a/b/;
+print $_ eq 'baaXXXXbbb' ? "ok 17\n" : "not ok 17\n";
+
+$_ = 'aaaXXXXbbb';
+s/aa//;
+print $_ eq 'aXXXXbbb' ? "ok 18\n" : "not ok 18\n";
+
+$_ = 'aaaXXXXbbb';
+s/aa/b/;
+print $_ eq 'baXXXXbbb' ? "ok 19\n" : "not ok 19\n";
+
+$_ = 'aaaXXXXbbb';
+s/b$//;
+print $_ eq 'aaaXXXXbb' ? "ok 20\n" : "not ok 20\n";
+
+$_ = 'aaaXXXXbbb';
+s/b//;
+print $_ eq 'aaaXXXXbb' ? "ok 21\n" : "not ok 21\n";
+
+$_ = 'aaaXXXXbbb';
+s/bb//;
+print $_ eq 'aaaXXXXb' ? "ok 22\n" : "not ok 22\n";
+
+$_ = 'aaaXXXXbbb';
+s/aX/y/;
+print $_ eq 'aayXXXbbb' ? "ok 23\n" : "not ok 23\n";
+
+$_ = 'aaaXXXXbbb';
+s/Xb/z/;
+print $_ eq 'aaaXXXzbb' ? "ok 24\n" : "not ok 24\n";
+
+$_ = 'aaaXXXXbbb';
+s/aaX.*Xbb//;
+print $_ eq 'ab' ? "ok 25\n" : "not ok 25\n";
+
+$_ = 'aaaXXXXbbb';
+s/bb/x/;
+print $_ eq 'aaaXXXXxb' ? "ok 26\n" : "not ok 26\n";
+
+# now for some unoptimized versions of the same.
+
+$_ = 'aaaXXXXbbb';
+$x ne $x || s/^a//;
+print $_ eq 'aaXXXXbbb' ? "ok 27\n" : "not ok 27\n";
+
+$_ = 'aaaXXXXbbb';
+$x ne $x || s/a//;
+print $_ eq 'aaXXXXbbb' ? "ok 28\n" : "not ok 28\n";
+
+$_ = 'aaaXXXXbbb';
+$x ne $x || s/^a/b/;
+print $_ eq 'baaXXXXbbb' ? "ok 29\n" : "not ok 29\n";
+
+$_ = 'aaaXXXXbbb';
+$x ne $x || s/a/b/;
+print $_ eq 'baaXXXXbbb' ? "ok 30\n" : "not ok 30\n";
+
+$_ = 'aaaXXXXbbb';
+$x ne $x || s/aa//;
+print $_ eq 'aXXXXbbb' ? "ok 31\n" : "not ok 31\n";
+
+$_ = 'aaaXXXXbbb';
+$x ne $x || s/aa/b/;
+print $_ eq 'baXXXXbbb' ? "ok 32\n" : "not ok 32\n";
+
+$_ = 'aaaXXXXbbb';
+$x ne $x || s/b$//;
+print $_ eq 'aaaXXXXbb' ? "ok 33\n" : "not ok 33\n";
+
+$_ = 'aaaXXXXbbb';
+$x ne $x || s/b//;
+print $_ eq 'aaaXXXXbb' ? "ok 34\n" : "not ok 34\n";
+
+$_ = 'aaaXXXXbbb';
+$x ne $x || s/bb//;
+print $_ eq 'aaaXXXXb' ? "ok 35\n" : "not ok 35\n";
+
+$_ = 'aaaXXXXbbb';
+$x ne $x || s/aX/y/;
+print $_ eq 'aayXXXbbb' ? "ok 36\n" : "not ok 36\n";
+
+$_ = 'aaaXXXXbbb';
+$x ne $x || s/Xb/z/;
+print $_ eq 'aaaXXXzbb' ? "ok 37\n" : "not ok 37\n";
+
+$_ = 'aaaXXXXbbb';
+$x ne $x || s/aaX.*Xbb//;
+print $_ eq 'ab' ? "ok 38\n" : "not ok 38\n";
+
+$_ = 'aaaXXXXbbb';
+$x ne $x || s/bb/x/;
+print $_ eq 'aaaXXXXxb' ? "ok 39\n" : "not ok 39\n";
+
+$_ = 'abc123xyz';
+s/\d+/$&*2/e; # yields 'abc246xyz'
+print $_ eq 'abc246xyz' ? "ok 40\n" : "not ok 40\n";
+s/\d+/sprintf("%5d",$&)/e; # yields 'abc 246xyz'
+print $_ eq 'abc 246xyz' ? "ok 41\n" : "not ok 41\n";
+s/\w/$& x 2/eg; # yields 'aabbcc 224466xxyyzz'
+print $_ eq 'aabbcc 224466xxyyzz' ? "ok 42\n" : "not ok 42\n";
+
+$_ = "aaaaa";
+print y/a/b/ == 5 ? "ok 43\n" : "not ok 43\n";
+print y/a/b/ == 0 ? "ok 44\n" : "not ok 44\n";
+print y/b// == 5 ? "ok 45\n" : "not ok 45\n";
+print y/b/c/s == 5 ? "ok 46\n" : "not ok 46\n";
+print y/c// == 1 ? "ok 47\n" : "not ok 47\n";
+print y/c//d == 1 ? "ok 48\n" : "not ok 48\n";
+print $_ eq "" ? "ok 49\n" : "not ok 49\n";
+
+$_ = "Now is the %#*! time for all good men...";
+print (($x=(y/a-zA-Z //cd)) == 7 ? "ok 50\n" : "not ok 50\n");
+print y/ / /s == 8 ? "ok 51\n" : "not ok 51\n";
+
diff --git a/gnu/usr.bin/perl/perl/t/op/sleep.t b/gnu/usr.bin/perl/perl/t/op/sleep.t
new file mode 100755
index 0000000..81113712
--- /dev/null
+++ b/gnu/usr.bin/perl/perl/t/op/sleep.t
@@ -0,0 +1,8 @@
+#!./perl
+
+# $Header: /home/cvs/386BSD/ports/lang/perl/t/op/sleep.t,v 1.1.1.1 1993/08/23 21:30:04 nate Exp $
+
+print "1..1\n";
+
+$x = sleep 2;
+if ($x >= 2 && $x <= 10) {print "ok 1\n";} else {print "not ok 1 $x\n";}
diff --git a/gnu/usr.bin/perl/perl/t/op/sort.t b/gnu/usr.bin/perl/perl/t/op/sort.t
new file mode 100755
index 0000000..4692ee4
--- /dev/null
+++ b/gnu/usr.bin/perl/perl/t/op/sort.t
@@ -0,0 +1,48 @@
+#!./perl
+
+# $RCSfile: sort.t,v $$Revision: 1.1.1.1 $$Date: 1993/08/23 21:30:02 $
+
+print "1..10\n";
+
+sub reverse { $a lt $b ? 1 : $a gt $b ? -1 : 0; }
+
+@harry = ('dog','cat','x','Cain','Abel');
+@george = ('gone','chased','yz','Punished','Axed');
+
+$x = join('', sort @harry);
+print ($x eq 'AbelCaincatdogx' ? "ok 1\n" : "not ok 1\n");
+
+$x = join('', sort reverse @harry);
+print ($x eq 'xdogcatCainAbel' ? "ok 2\n" : "not ok 2\n");
+
+$x = join('', sort @george, 'to', @harry);
+print ($x eq 'AbelAxedCainPunishedcatchaseddoggonetoxyz'?"ok 3\n":"not ok 3\n");
+
+@a = ();
+@b = reverse @a;
+print ("@b" eq "" ? "ok 4\n" : "not ok 4 (@b)\n");
+
+@a = (1);
+@b = reverse @a;
+print ("@b" eq "1" ? "ok 5\n" : "not ok 5 (@b)\n");
+
+@a = (1,2);
+@b = reverse @a;
+print ("@b" eq "2 1" ? "ok 6\n" : "not ok 6 (@b)\n");
+
+@a = (1,2,3);
+@b = reverse @a;
+print ("@b" eq "3 2 1" ? "ok 7\n" : "not ok 7 (@b)\n");
+
+@a = (1,2,3,4);
+@b = reverse @a;
+print ("@b" eq "4 3 2 1" ? "ok 8\n" : "not ok 8 (@b)\n");
+
+@a = (10,2,3,4);
+@b = sort {$a <=> $b;} @a;
+print ("@b" eq "2 3 4 10" ? "ok 9\n" : "not ok 9 (@b)\n");
+
+$sub = 'reverse';
+$x = join('', sort $sub @harry);
+print ($x eq 'xdogcatCainAbel' ? "ok 10\n" : "not ok 10\n");
+
diff --git a/gnu/usr.bin/perl/perl/t/op/split.t b/gnu/usr.bin/perl/perl/t/op/split.t
new file mode 100755
index 0000000..63bf3c7
--- /dev/null
+++ b/gnu/usr.bin/perl/perl/t/op/split.t
@@ -0,0 +1,57 @@
+#!./perl
+
+# $Header: /home/cvs/386BSD/ports/lang/perl/t/op/split.t,v 1.1.1.1 1993/08/23 21:30:02 nate Exp $
+
+print "1..12\n";
+
+$FS = ':';
+
+$_ = 'a:b:c';
+
+($a,$b,$c) = split($FS,$_);
+
+if (join(';',$a,$b,$c) eq 'a;b;c') {print "ok 1\n";} else {print "not ok 1\n";}
+
+@ary = split(/:b:/);
+if (join("$_",@ary) eq 'aa:b:cc') {print "ok 2\n";} else {print "not ok 2\n";}
+
+$_ = "abc\n";
+@xyz = (@ary = split(//));
+if (join(".",@ary) eq "a.b.c.\n") {print "ok 3\n";} else {print "not ok 3\n";}
+
+$_ = "a:b:c::::";
+@ary = split(/:/);
+if (join(".",@ary) eq "a.b.c") {print "ok 4\n";} else {print "not ok 4\n";}
+
+$_ = join(':',split(' '," a b\tc \t d "));
+if ($_ eq 'a:b:c:d') {print "ok 5\n";} else {print "not ok 5 #$_#\n";}
+
+$_ = join(':',split(/ */,"foo bar bie\tdoll"));
+if ($_ eq "f:o:o:b:a:r:b:i:e:\t:d:o:l:l")
+ {print "ok 6\n";} else {print "not ok 6\n";}
+
+$_ = join(':', 'foo', split(/ /,'a b c'), 'bar');
+if ($_ eq "foo:a:b::c:bar") {print "ok 7\n";} else {print "not ok 7 $_\n";}
+
+# Can we say how many fields to split to?
+$_ = join(':', split(' ','1 2 3 4 5 6', 3));
+print $_ eq '1:2:3 4 5 6' ? "ok 8\n" : "not ok 8 $_\n";
+
+# Can we do it as a variable?
+$x = 4;
+$_ = join(':', split(' ','1 2 3 4 5 6', $x));
+print $_ eq '1:2:3:4 5 6' ? "ok 9\n" : "not ok 9 $_\n";
+
+# Does the 999 suppress null field chopping?
+$_ = join(':', split(/:/,'1:2:3:4:5:6:::', 999));
+print $_ eq '1:2:3:4:5:6:::' ? "ok 10\n" : "not ok 10 $_\n";
+
+# Does assignment to a list imply split to one more field than that?
+$foo = `./perl -D1024 -e '(\$a,\$b) = split;' 2>&1`;
+print $foo =~ /DEBUGGING/ || $foo =~ /num\(3\)/ ? "ok 11\n" : "not ok 11\n";
+
+# Can we say how many fields to split to when assigning to a list?
+($a,$b) = split(' ','1 2 3 4 5 6', 2);
+$_ = join(':',$a,$b);
+print $_ eq '1:2 3 4 5 6' ? "ok 12\n" : "not ok 12 $_\n";
+
diff --git a/gnu/usr.bin/perl/perl/t/op/sprintf.t b/gnu/usr.bin/perl/perl/t/op/sprintf.t
new file mode 100755
index 0000000..cdb4af5
--- /dev/null
+++ b/gnu/usr.bin/perl/perl/t/op/sprintf.t
@@ -0,0 +1,8 @@
+#!./perl
+
+# $Header: /home/cvs/386BSD/ports/lang/perl/t/op/sprintf.t,v 1.1.1.1 1993/08/23 21:30:01 nate Exp $
+
+print "1..1\n";
+
+$x = sprintf("%3s %-4s%%foo %5d%c%3.1f","hi",123,456,65,3.0999);
+if ($x eq ' hi 123 %foo 456A3.1') {print "ok 1\n";} else {print "not ok 1 '$x'\n";}
diff --git a/gnu/usr.bin/perl/perl/t/op/stat.t b/gnu/usr.bin/perl/perl/t/op/stat.t
new file mode 100755
index 0000000..a5db14f
--- /dev/null
+++ b/gnu/usr.bin/perl/perl/t/op/stat.t
@@ -0,0 +1,176 @@
+#!./perl
+
+# $RCSfile: stat.t,v $$Revision: 1.1.1.1 $$Date: 1993/08/23 21:30:01 $
+
+print "1..56\n";
+
+chop($cwd = `pwd`);
+
+$DEV = `ls -l /dev`;
+
+unlink "Op.stat.tmp";
+open(FOO, ">Op.stat.tmp");
+
+$junk = `ls Op.stat.tmp`; # hack to make Apollo update link count
+
+($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,$atime,$mtime,$ctime,
+ $blksize,$blocks) = stat(FOO);
+if ($nlink == 1) {print "ok 1\n";} else {print "not ok 1\n";}
+if ($mtime && $mtime == $ctime) {print "ok 2\n";} else {print "not ok 2\n";}
+
+print FOO "Now is the time for all good men to come to.\n";
+close(FOO);
+
+sleep 2;
+
+`rm -f Op.stat.tmp2; ln Op.stat.tmp Op.stat.tmp2; chmod 644 Op.stat.tmp`;
+
+($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,$atime,$mtime,$ctime,
+ $blksize,$blocks) = stat('Op.stat.tmp');
+
+if ($nlink == 2) {print "ok 3\n";} else {print "not ok 3\n";}
+if (($mtime && $mtime != $ctime) || $cwd =~ m#/afs/#) {
+ print "ok 4\n";
+}
+else {
+ print "not ok 4\n";
+}
+print "#4 :$mtime: != :$ctime:\n";
+
+`rm -f Op.stat.tmp`;
+`touch Op.stat.tmp`;
+
+if (-z 'Op.stat.tmp') {print "ok 5\n";} else {print "not ok 5\n";}
+if (! -s 'Op.stat.tmp') {print "ok 6\n";} else {print "not ok 6\n";}
+
+`echo hi >Op.stat.tmp`;
+if (! -z 'Op.stat.tmp') {print "ok 7\n";} else {print "not ok 7\n";}
+if (-s 'Op.stat.tmp') {print "ok 8\n";} else {print "not ok 8\n";}
+
+unlink 'Op.stat.tmp';
+$olduid = $>; # can't test -r if uid == 0
+`echo hi >Op.stat.tmp`;
+chmod 0,'Op.stat.tmp';
+eval '$> = 1;'; # so switch uid (may not be implemented)
+if (!$> || ! -r 'Op.stat.tmp') {print "ok 9\n";} else {print "not ok 9\n";}
+if (!$> || ! -w 'Op.stat.tmp') {print "ok 10\n";} else {print "not ok 10\n";}
+eval '$> = $olduid;'; # switch uid back (may not be implemented)
+print "# olduid=$olduid, newuid=$>\n" unless ($> == $olduid);
+if (! -x 'Op.stat.tmp') {print "ok 11\n";} else {print "not ok 11\n";}
+
+foreach ((12,13,14,15,16,17)) {
+ print "ok $_\n"; #deleted tests
+}
+
+chmod 0700,'Op.stat.tmp';
+if (-r 'Op.stat.tmp') {print "ok 18\n";} else {print "not ok 18\n";}
+if (-w 'Op.stat.tmp') {print "ok 19\n";} else {print "not ok 19\n";}
+if (-x 'Op.stat.tmp') {print "ok 20\n";} else {print "not ok 20\n";}
+
+if (-f 'Op.stat.tmp') {print "ok 21\n";} else {print "not ok 21\n";}
+if (! -d 'Op.stat.tmp') {print "ok 22\n";} else {print "not ok 22\n";}
+
+if (-d '.') {print "ok 23\n";} else {print "not ok 23\n";}
+if (! -f '.') {print "ok 24\n";} else {print "not ok 24\n";}
+
+if (`ls -l perl` =~ /^l.*->/) {
+ if (-l 'perl') {print "ok 25\n";} else {print "not ok 25\n";}
+}
+else {
+ print "ok 25\n";
+}
+
+if (-o 'Op.stat.tmp') {print "ok 26\n";} else {print "not ok 26\n";}
+
+if (-e 'Op.stat.tmp') {print "ok 27\n";} else {print "not ok 27\n";}
+`rm -f Op.stat.tmp Op.stat.tmp2`;
+if (! -e 'Op.stat.tmp') {print "ok 28\n";} else {print "not ok 28\n";}
+
+if ($DEV !~ /\nc.* (\S+)\n/)
+ {print "ok 29\n";}
+elsif (-c "/dev/$1")
+ {print "ok 29\n";}
+else
+ {print "not ok 29\n";}
+if (! -c '.') {print "ok 30\n";} else {print "not ok 30\n";}
+
+if ($DEV !~ /\ns.* (\S+)\n/)
+ {print "ok 31\n";}
+elsif (-S "/dev/$1")
+ {print "ok 31\n";}
+else
+ {print "not ok 31\n";}
+if (! -S '.') {print "ok 32\n";} else {print "not ok 32\n";}
+
+if ($DEV !~ /\nb.* (\S+)\n/)
+ {print "ok 33\n";}
+elsif (-b "/dev/$1")
+ {print "ok 33\n";}
+else
+ {print "not ok 33\n";}
+if (! -b '.') {print "ok 34\n";} else {print "not ok 34\n";}
+
+$cnt = $uid = 0;
+
+die "Can't run op/stat.t test 35 without pwd working" unless $cwd;
+chdir '/usr/bin' || die "Can't cd to /usr/bin";
+while (defined($_ = <*>)) {
+ $cnt++;
+ $uid++ if -u;
+ last if $uid && $uid < $cnt;
+}
+chdir $cwd || die "Can't cd back to $cwd";
+
+# I suppose this is going to fail somewhere...
+if ($uid > 0 && $uid < $cnt) {print "ok 35\n";} else {print "not ok 35\n";}
+
+unless (open(tty,"/dev/tty")) {
+ print STDERR "Can't open /dev/tty--run t/TEST outside of make.\n";
+}
+if (-t tty) {print "ok 36\n";} else {print "not ok 36\n";}
+if (-c tty) {print "ok 37\n";} else {print "not ok 37\n";}
+close(tty);
+if (! -t tty) {print "ok 38\n";} else {print "not ok 38\n";}
+open(null,"/dev/null");
+if (! -t null || -e '/xenix') {print "ok 39\n";} else {print "not ok 39\n";}
+close(null);
+if (-t) {print "ok 40\n";} else {print "not ok 40\n";}
+
+# These aren't strictly "stat" calls, but so what?
+
+if (-T 'op/stat.t') {print "ok 41\n";} else {print "not ok 41\n";}
+if (! -B 'op/stat.t') {print "ok 42\n";} else {print "not ok 42\n";}
+
+if (-B './perl') {print "ok 43\n";} else {print "not ok 43\n";}
+if (! -T './perl') {print "ok 44\n";} else {print "not ok 44\n";}
+
+open(FOO,'op/stat.t');
+eval { -T FOO; };
+if ($@ =~ /not implemented/) {
+ print "# $@";
+ for (45 .. 54) {
+ print "ok $_\n";
+ }
+}
+else {
+ if (-T FOO) {print "ok 45\n";} else {print "not ok 45\n";}
+ if (! -B FOO) {print "ok 46\n";} else {print "not ok 46\n";}
+ $_ = <FOO>;
+ if (/perl/) {print "ok 47\n";} else {print "not ok 47\n";}
+ if (-T FOO) {print "ok 48\n";} else {print "not ok 48\n";}
+ if (! -B FOO) {print "ok 49\n";} else {print "not ok 49\n";}
+ close(FOO);
+
+ open(FOO,'op/stat.t');
+ $_ = <FOO>;
+ if (/perl/) {print "ok 50\n";} else {print "not ok 50\n";}
+ if (-T FOO) {print "ok 51\n";} else {print "not ok 51\n";}
+ if (! -B FOO) {print "ok 52\n";} else {print "not ok 52\n";}
+ seek(FOO,0,0);
+ if (-T FOO) {print "ok 53\n";} else {print "not ok 53\n";}
+ if (! -B FOO) {print "ok 54\n";} else {print "not ok 54\n";}
+}
+close(FOO);
+
+if (-T '/dev/null') {print "ok 55\n";} else {print "not ok 55\n";}
+if (-B '/dev/null') {print "ok 56\n";} else {print "not ok 56\n";}
diff --git a/gnu/usr.bin/perl/perl/t/op/study.t b/gnu/usr.bin/perl/perl/t/op/study.t
new file mode 100755
index 0000000..a0fdc4c
--- /dev/null
+++ b/gnu/usr.bin/perl/perl/t/op/study.t
@@ -0,0 +1,69 @@
+#!./perl
+
+# $Header: /home/cvs/386BSD/ports/lang/perl/t/op/study.t,v 1.1.1.1 1993/08/23 21:30:02 nate Exp $
+
+print "1..24\n";
+
+$x = "abc\ndef\n";
+study($x);
+
+if ($x =~ /^abc/) {print "ok 1\n";} else {print "not ok 1\n";}
+if ($x !~ /^def/) {print "ok 2\n";} else {print "not ok 2\n";}
+
+$* = 1;
+if ($x =~ /^def/) {print "ok 3\n";} else {print "not ok 3\n";}
+$* = 0;
+
+$_ = '123';
+study;
+if (/^([0-9][0-9]*)/) {print "ok 4\n";} else {print "not ok 4\n";}
+
+if ($x =~ /^xxx/) {print "not ok 5\n";} else {print "ok 5\n";}
+if ($x !~ /^abc/) {print "not ok 6\n";} else {print "ok 6\n";}
+
+if ($x =~ /def/) {print "ok 7\n";} else {print "not ok 7\n";}
+if ($x !~ /def/) {print "not ok 8\n";} else {print "ok 8\n";}
+
+study($x);
+if ($x !~ /.def/) {print "ok 9\n";} else {print "not ok 9\n";}
+if ($x =~ /.def/) {print "not ok 10\n";} else {print "ok 10\n";}
+
+if ($x =~ /\ndef/) {print "ok 11\n";} else {print "not ok 11\n";}
+if ($x !~ /\ndef/) {print "not ok 12\n";} else {print "ok 12\n";}
+
+$_ = 'aaabbbccc';
+study;
+if (/(a*b*)(c*)/ && $1 eq 'aaabbb' && $2 eq 'ccc') {
+ print "ok 13\n";
+} else {
+ print "not ok 13\n";
+}
+if (/(a+b+c+)/ && $1 eq 'aaabbbccc') {
+ print "ok 14\n";
+} else {
+ print "not ok 14\n";
+}
+
+if (/a+b?c+/) {print "not ok 15\n";} else {print "ok 15\n";}
+
+$_ = 'aaabccc';
+study;
+if (/a+b?c+/) {print "ok 16\n";} else {print "not ok 16\n";}
+if (/a*b+c*/) {print "ok 17\n";} else {print "not ok 17\n";}
+
+$_ = 'aaaccc';
+study;
+if (/a*b?c*/) {print "ok 18\n";} else {print "not ok 18\n";}
+if (/a*b+c*/) {print "not ok 19\n";} else {print "ok 19\n";}
+
+$_ = 'abcdef';
+study;
+if (/bcd|xyz/) {print "ok 20\n";} else {print "not ok 20\n";}
+if (/xyz|bcd/) {print "ok 21\n";} else {print "not ok 21\n";}
+
+if (m|bc/*d|) {print "ok 22\n";} else {print "not ok 22\n";}
+
+if (/^$_$/) {print "ok 23\n";} else {print "not ok 23\n";}
+
+$* = 1; # test 3 only tested the optimized version--this one is for real
+if ("ab\ncd\n" =~ /^cd/) {print "ok 24\n";} else {print "not ok 24\n";}
diff --git a/gnu/usr.bin/perl/perl/t/op/substr.t b/gnu/usr.bin/perl/perl/t/op/substr.t
new file mode 100755
index 0000000..09f312f
--- /dev/null
+++ b/gnu/usr.bin/perl/perl/t/op/substr.t
@@ -0,0 +1,47 @@
+#!./perl
+
+# $Header: /home/cvs/386BSD/ports/lang/perl/t/op/substr.t,v 1.1.1.1 1993/08/23 21:30:01 nate Exp $
+
+print "1..22\n";
+
+$a = 'abcdefxyz';
+
+print (substr($a,0,3) eq 'abc' ? "ok 1\n" : "not ok 1\n");
+print (substr($a,3,3) eq 'def' ? "ok 2\n" : "not ok 2\n");
+print (substr($a,6,999) eq 'xyz' ? "ok 3\n" : "not ok 3\n");
+print (substr($a,999,999) eq '' ? "ok 4\n" : "not ok 4\n");
+print (substr($a,6,-1) eq '' ? "ok 5\n" : "not ok 5\n");
+print (substr($a,-3,1) eq 'x' ? "ok 6\n" : "not ok 6\n");
+
+$[ = 1;
+
+print (substr($a,1,3) eq 'abc' ? "ok 7\n" : "not ok 7\n");
+print (substr($a,4,3) eq 'def' ? "ok 8\n" : "not ok 8\n");
+print (substr($a,7,999) eq 'xyz' ? "ok 9\n" : "not ok 9\n");
+print (substr($a,999,999) eq '' ? "ok 10\n" : "not ok 10\n");
+print (substr($a,7,-1) eq '' ? "ok 11\n" : "not ok 11\n");
+print (substr($a,-3,1) eq 'x' ? "ok 12\n" : "not ok 12\n");
+
+$[ = 0;
+
+substr($a,3,3) = 'XYZ';
+print $a eq 'abcXYZxyz' ? "ok 13\n" : "not ok 13\n";
+substr($a,0,2) = '';
+print $a eq 'cXYZxyz' ? "ok 14\n" : "not ok 14\n";
+y/a/a/;
+substr($a,0,0) = 'ab';
+print $a eq 'abcXYZxyz' ? "ok 15\n" : "not ok 15 $a\n";
+substr($a,0,0) = '12345678';
+print $a eq '12345678abcXYZxyz' ? "ok 16\n" : "not ok 16\n";
+substr($a,-3,3) = 'def';
+print $a eq '12345678abcXYZdef' ? "ok 17\n" : "not ok 17\n";
+substr($a,-3,3) = '<';
+print $a eq '12345678abcXYZ<' ? "ok 18\n" : "not ok 18\n";
+substr($a,-1,1) = '12345678';
+print $a eq '12345678abcXYZ12345678' ? "ok 19\n" : "not ok 19\n";
+
+$a = 'abcdefxyz';
+
+print (substr($a,6) eq 'xyz' ? "ok 20\n" : "not ok 20\n");
+print (substr($a,-3) eq 'xyz' ? "ok 21\n" : "not ok 21\n");
+print (substr($a,999) eq '' ? "ok 22\n" : "not ok 22\n");
diff --git a/gnu/usr.bin/perl/perl/t/op/time.t b/gnu/usr.bin/perl/perl/t/op/time.t
new file mode 100755
index 0000000..f8e5545
--- /dev/null
+++ b/gnu/usr.bin/perl/perl/t/op/time.t
@@ -0,0 +1,43 @@
+#!./perl
+
+# $Header: /home/cvs/386BSD/ports/lang/perl/t/op/time.t,v 1.1.1.1 1993/08/23 21:30:03 nate Exp $
+
+print "1..5\n";
+
+($beguser,$begsys) = times;
+
+$beg = time;
+
+while (($now = time) == $beg) {}
+
+if ($now > $beg && $now - $beg < 10){print "ok 1\n";} else {print "not ok 1\n";}
+
+for ($i = 0; $i < 100000; $i++) {
+ ($nowuser, $nowsys) = times;
+ $i = 200000 if $nowuser > $beguser && $nowsys > $begsys;
+ last if time - $beg > 20;
+}
+
+if ($i >= 200000) {print "ok 2\n";} else {print "not ok 2\n";}
+
+($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime($beg);
+($xsec,$foo) = localtime($now);
+$localyday = $yday;
+
+if ($sec != $xsec && $mday && $year)
+ {print "ok 3\n";}
+else
+ {print "not ok 3\n";}
+
+($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = gmtime($beg);
+($xsec,$foo) = localtime($now);
+
+if ($sec != $xsec && $mday && $year)
+ {print "ok 4\n";}
+else
+ {print "not ok 4\n";}
+
+if (index(" :0:1:-1:365:366:-365:-366:",':' . ($localyday - $yday) . ':') > 0)
+ {print "ok 5\n";}
+else
+ {print "not ok 5\n";}
diff --git a/gnu/usr.bin/perl/perl/t/op/undef.t b/gnu/usr.bin/perl/perl/t/op/undef.t
new file mode 100755
index 0000000..b4827db
--- /dev/null
+++ b/gnu/usr.bin/perl/perl/t/op/undef.t
@@ -0,0 +1,56 @@
+#!./perl
+
+# $Header: /home/cvs/386BSD/ports/lang/perl/t/op/undef.t,v 1.1.1.1 1993/08/23 21:30:02 nate Exp $
+
+print "1..21\n";
+
+print defined($a) ? "not ok 1\n" : "ok 1\n";
+
+$a = 1+1;
+print defined($a) ? "ok 2\n" : "not ok 2\n";
+
+undef $a;
+print defined($a) ? "not ok 3\n" : "ok 3\n";
+
+$a = "hi";
+print defined($a) ? "ok 4\n" : "not ok 4\n";
+
+$a = $b;
+print defined($a) ? "not ok 5\n" : "ok 5\n";
+
+@ary = ("1arg");
+$a = pop(@ary);
+print defined($a) ? "ok 6\n" : "not ok 6\n";
+$a = pop(@ary);
+print defined($a) ? "not ok 7\n" : "ok 7\n";
+
+@ary = ("1arg");
+$a = shift(@ary);
+print defined($a) ? "ok 8\n" : "not ok 8\n";
+$a = shift(@ary);
+print defined($a) ? "not ok 9\n" : "ok 9\n";
+
+$ary{'foo'} = 'hi';
+print defined($ary{'foo'}) ? "ok 10\n" : "not ok 10\n";
+print defined($ary{'bar'}) ? "not ok 11\n" : "ok 11\n";
+undef $ary{'foo'};
+print defined($ary{'foo'}) ? "not ok 12\n" : "ok 12\n";
+
+print defined(@ary) ? "ok 13\n" : "not ok 13\n";
+print defined(%ary) ? "ok 14\n" : "not ok 14\n";
+undef @ary;
+print defined(@ary) ? "not ok 15\n" : "ok 15\n";
+undef %ary;
+print defined(%ary) ? "not ok 16\n" : "ok 16\n";
+@ary = (1);
+print defined @ary ? "ok 17\n" : "not ok 17\n";
+%ary = (1,1);
+print defined %ary ? "ok 18\n" : "not ok 18\n";
+
+sub foo { print "ok 19\n"; }
+
+&foo || print "not ok 19\n";
+
+print defined &foo ? "ok 20\n" : "not ok 20\n";
+undef &foo;
+print defined(&foo) ? "not ok 21\n" : "ok 21\n";
diff --git a/gnu/usr.bin/perl/perl/t/op/unshift.t b/gnu/usr.bin/perl/perl/t/op/unshift.t
new file mode 100755
index 0000000..53d7388
--- /dev/null
+++ b/gnu/usr.bin/perl/perl/t/op/unshift.t
@@ -0,0 +1,14 @@
+#!./perl
+
+# $Header: /home/cvs/386BSD/ports/lang/perl/t/op/unshift.t,v 1.1.1.1 1993/08/23 21:30:02 nate Exp $
+
+print "1..2\n";
+
+@a = (1,2,3);
+$cnt1 = unshift(a,0);
+
+if (join(' ',@a) eq '0 1 2 3') {print "ok 1\n";} else {print "not ok 1\n";}
+$cnt2 = unshift(a,3,2,1);
+if (join(' ',@a) eq '3 2 1 0 1 2 3') {print "ok 2\n";} else {print "not ok 2\n";}
+
+
diff --git a/gnu/usr.bin/perl/perl/t/op/vec.t b/gnu/usr.bin/perl/perl/t/op/vec.t
new file mode 100755
index 0000000..5134476
--- /dev/null
+++ b/gnu/usr.bin/perl/perl/t/op/vec.t
@@ -0,0 +1,24 @@
+#!./perl
+
+# $Header: /home/cvs/386BSD/ports/lang/perl/t/op/vec.t,v 1.1.1.1 1993/08/23 21:30:03 nate Exp $
+
+print "1..13\n";
+
+print vec($foo,0,1) == 0 ? "ok 1\n" : "not ok 1\n";
+print length($foo) == 0 ? "ok 2\n" : "not ok 2\n";
+vec($foo,0,1) = 1;
+print length($foo) == 1 ? "ok 3\n" : "not ok 3\n";
+print ord($foo) == 1 ? "ok 4\n" : "not ok 4\n";
+print vec($foo,0,1) == 1 ? "ok 5\n" : "not ok 5\n";
+
+print vec($foo,20,1) == 0 ? "ok 6\n" : "not ok 6\n";
+vec($foo,20,1) = 1;
+print vec($foo,20,1) == 1 ? "ok 7\n" : "not ok 7\n";
+print length($foo) == 3 ? "ok 8\n" : "not ok 8\n";
+print vec($foo,1,8) == 0 ? "ok 9\n" : "not ok 9\n";
+vec($foo,1,8) = 0xf1;
+print vec($foo,1,8) == 0xf1 ? "ok 10\n" : "not ok 10\n";
+print ((ord(substr($foo,1,1)) & 255) == 0xf1 ? "ok 11\n" : "not ok 11\n");
+print vec($foo,2,4) == 1 ? "ok 12\n" : "not ok 12\n";
+print vec($foo,3,4) == 15 ? "ok 13\n" : "not ok 13\n";
+
diff --git a/gnu/usr.bin/perl/perl/t/op/write.t b/gnu/usr.bin/perl/perl/t/op/write.t
new file mode 100755
index 0000000..d17f195
--- /dev/null
+++ b/gnu/usr.bin/perl/perl/t/op/write.t
@@ -0,0 +1,129 @@
+#!./perl
+
+# $Header: /home/cvs/386BSD/ports/lang/perl/t/op/write.t,v 1.1.1.1 1993/08/23 21:30:02 nate Exp $
+
+print "1..3\n";
+
+format OUT =
+the quick brown @<<
+$fox
+jumped
+@*
+$multiline
+^<<<<<<<<<
+$foo
+^<<<<<<<<<
+$foo
+^<<<<<<...
+$foo
+now @<<the@>>>> for all@|||||men to come @<<<<
+'i' . 's', "time\n", $good, 'to'
+.
+
+open(OUT, '>Op.write.tmp') || die "Can't create Op.write.tmp";
+
+$fox = 'foxiness';
+$good = 'good';
+$multiline = "forescore\nand\nseven years\n";
+$foo = 'when in the course of human events it becomes necessary';
+write(OUT);
+close OUT;
+
+$right =
+"the quick brown fox
+jumped
+forescore
+and
+seven years
+when in
+the course
+of huma...
+now is the time for all good men to come to\n";
+
+if (`cat Op.write.tmp` eq $right)
+ { print "ok 1\n"; unlink 'Op.write.tmp'; }
+else
+ { print "not ok 1\n"; }
+
+format OUT2 =
+the quick brown @<<
+$fox
+jumped
+@*
+$multiline
+^<<<<<<<<< ~~
+$foo
+now @<<the@>>>> for all@|||||men to come @<<<<
+'i' . 's', "time\n", $good, 'to'
+.
+
+open(OUT2, '>Op.write.tmp') || die "Can't create Op.write.tmp";
+
+$fox = 'foxiness';
+$good = 'good';
+$multiline = "forescore\nand\nseven years\n";
+$foo = 'when in the course of human events it becomes necessary';
+write(OUT2);
+close OUT2;
+
+$right =
+"the quick brown fox
+jumped
+forescore
+and
+seven years
+when in
+the course
+of human
+events it
+becomes
+necessary
+now is the time for all good men to come to\n";
+
+if (`cat Op.write.tmp` eq $right)
+ { print "ok 2\n"; unlink 'Op.write.tmp'; }
+else
+ { print "not ok 2\n"; }
+
+eval <<'EOFORMAT';
+format OUT2 =
+the brown quick @<<
+$fox
+jumped
+@*
+$multiline
+^<<<<<<<<< ~~
+$foo
+now @<<the@>>>> for all@|||||men to come @<<<<
+'i' . 's', "time\n", $good, 'to'
+.
+EOFORMAT
+
+open(OUT2, '>Op.write.tmp') || die "Can't create Op.write.tmp";
+
+$fox = 'foxiness';
+$good = 'good';
+$multiline = "forescore\nand\nseven years\n";
+$foo = 'when in the course of human events it becomes necessary';
+write(OUT2);
+close OUT2;
+
+$right =
+"the brown quick fox
+jumped
+forescore
+and
+seven years
+when in
+the course
+of human
+events it
+becomes
+necessary
+now is the time for all good men to come to\n";
+
+if (`cat Op.write.tmp` eq $right)
+ { print "ok 3\n"; unlink 'Op.write.tmp'; }
+else
+ { print "not ok 3\n"; }
+
diff --git a/gnu/usr.bin/perl/perl/t/printme b/gnu/usr.bin/perl/perl/t/printme
new file mode 100644
index 0000000..feefccb2
--- /dev/null
+++ b/gnu/usr.bin/perl/perl/t/printme
@@ -0,0 +1,6 @@
+
+
+
+
+print "Hello World\n";
+
diff --git a/gnu/usr.bin/perl/perl/tdoio.c b/gnu/usr.bin/perl/perl/tdoio.c
new file mode 100644
index 0000000..1cd6269
--- /dev/null
+++ b/gnu/usr.bin/perl/perl/tdoio.c
@@ -0,0 +1,2951 @@
+/* $RCSfile: tdoio.c,v $$Revision: 1.1.1.1 $$Date: 1994/09/10 06:27:36 $
+ *
+ * Copyright (c) 1991, Larry Wall
+ *
+ * You may distribute under the terms of either the GNU General Public
+ * License or the Artistic License, as specified in the README file.
+ *
+ * $Log: tdoio.c,v $
+ * Revision 1.1.1.1 1994/09/10 06:27:36 gclarkii
+ * Initial import of Perl 4.046 bmaked
+ *
+ * Revision 1.2 1994/03/09 22:24:27 ache
+ * (cast) added for last argument of semctl
+ *
+ * Revision 1.1.1.1 1993/08/23 21:29:36 nate
+ * PERL!
+ *
+ * Revision 4.0.1.6 92/06/11 21:08:16 lwall
+ * patch34: some systems don't declare h_errno extern in header files
+ *
+ * Revision 4.0.1.5 92/06/08 13:00:21 lwall
+ * patch20: some machines don't define ENOTSOCK in errno.h
+ * patch20: new warnings for failed use of stat operators on filenames with \n
+ * patch20: wait failed when STDOUT or STDERR reopened to a pipe
+ * patch20: end of file latch not reset on reopen of STDIN
+ * patch20: seek(HANDLE, 0, 1) went to eof because of ancient Ultrix workaround
+ * patch20: fixed memory leak on system() for vfork() machines
+ * patch20: get*by* routines now return something useful in a scalar context
+ * patch20: h_errno now accessible via $?
+ *
+ * Revision 4.0.1.4 91/11/05 16:51:43 lwall
+ * patch11: prepared for ctype implementations that don't define isascii()
+ * patch11: perl mistook some streams for sockets because they return mode 0 too
+ * patch11: reopening STDIN, STDOUT and STDERR failed on some machines
+ * patch11: certain perl errors should set EBADF so that $! looks better
+ * patch11: truncate on a closed filehandle could dump
+ * patch11: stats of _ forgot whether prior stat was actually lstat
+ * patch11: -T returned true on NFS directory
+ *
+ * Revision 4.0.1.3 91/06/10 01:21:19 lwall
+ * patch10: read didn't work from character special files open for writing
+ * patch10: close-on-exec wrongly set on system file descriptors
+ *
+ * Revision 4.0.1.2 91/06/07 10:53:39 lwall
+ * patch4: new copyright notice
+ * patch4: system fd's are now treated specially
+ * patch4: added $^F variable to specify maximum system fd, default 2
+ * patch4: character special files now opened with bidirectional stdio buffers
+ * patch4: taintchecks could improperly modify parent in vfork()
+ * patch4: many, many itty-bitty portability fixes
+ *
+ * Revision 4.0.1.1 91/04/11 17:41:06 lwall
+ * patch1: hopefully straightened out some of the Xenix mess
+ *
+ * Revision 4.0 91/03/20 01:07:06 lwall
+ * 4.0 baseline.
+ *
+ */
+
+#include "EXTERN.h"
+#include "perl.h"
+#include <unistd.h>
+#include <stdio.h>
+
+#ifdef HAS_SOCKET
+#include <sys/socket.h>
+#include <netdb.h>
+#ifndef ENOTSOCK
+#include <net/errno.h>
+#endif
+#endif
+
+#ifdef HAS_SELECT
+#ifdef I_SYS_SELECT
+#ifndef I_SYS_TIME
+#include <sys/select.h>
+#endif
+#endif
+#endif
+
+#ifdef HOST_NOT_FOUND
+extern int h_errno;
+#endif
+
+#if defined(HAS_MSG) || defined(HAS_SEM) || defined(HAS_SHM)
+#include <sys/ipc.h>
+#ifdef HAS_MSG
+#include <sys/msg.h>
+#endif
+#ifdef HAS_SEM
+#include <sys/sem.h>
+#endif
+#ifdef HAS_SHM
+#include <sys/shm.h>
+#endif
+#endif
+
+#ifdef I_PWD
+#include <pwd.h>
+#endif
+#ifdef I_GRP
+#include <grp.h>
+#endif
+#ifdef I_UTIME
+#include <utime.h>
+#endif
+#ifdef I_FCNTL
+#include <fcntl.h>
+#endif
+#ifdef I_SYS_FILE
+#include <sys/file.h>
+#endif
+
+int laststatval = -1;
+int laststype = O_STAT;
+
+static char* warn_nl = "Unsuccessful %s on filename containing newline";
+
+bool
+do_open(stab,name,len)
+STAB *stab;
+register char *name;
+int len;
+{
+ FILE *fp;
+ register STIO *stio = stab_io(stab);
+ char *myname = savestr(name);
+ int result;
+ int fd;
+ int writing = 0;
+ char mode[3]; /* stdio file mode ("r\0" or "r+\0") */
+ FILE *saveifp = Nullfp;
+ FILE *saveofp = Nullfp;
+ char savetype = ' ';
+
+ mode[0] = mode[1] = mode[2] = '\0';
+ name = myname;
+ forkprocess = 1; /* assume true if no fork */
+ while (len && isSPACE(name[len-1]))
+ name[--len] = '\0';
+ if (!stio)
+ stio = stab_io(stab) = stio_new();
+ else if (stio->ifp) {
+ fd = fileno(stio->ifp);
+ if (stio->type == '-')
+ result = 0;
+ else if (fd <= maxsysfd) {
+ saveifp = stio->ifp;
+ saveofp = stio->ofp;
+ savetype = stio->type;
+ result = 0;
+ }
+ else if (stio->type == '|')
+ result = mypclose(stio->ifp);
+ else if (stio->ifp != stio->ofp) {
+ if (stio->ofp) {
+ result = fclose(stio->ofp);
+ fclose(stio->ifp); /* clear stdio, fd already closed */
+ }
+ else
+ result = fclose(stio->ifp);
+ }
+ else
+ result = fclose(stio->ifp);
+ if (result == EOF && fd > maxsysfd)
+ fprintf(stderr,"Warning: unable to close filehandle %s properly.\n",
+ stab_ename(stab));
+ stio->ofp = stio->ifp = Nullfp;
+ }
+ if (*name == '+' && len > 1 && name[len-1] != '|') { /* scary */
+ mode[1] = *name++;
+ mode[2] = '\0';
+ --len;
+ writing = 1;
+ }
+ else {
+ mode[1] = '\0';
+ }
+ stio->type = *name;
+ if (*name == '|') {
+ /*SUPPRESS 530*/
+ for (name++; isSPACE(*name); name++) ;
+#ifdef TAINT
+ taintenv();
+ taintproper("Insecure dependency in piped open");
+#endif
+ fp = mypopen(name,"w");
+ writing = 1;
+ }
+ else if (*name == '>') {
+#ifdef TAINT
+ taintproper("Insecure dependency in open");
+#endif
+ name++;
+ if (*name == '>') {
+ mode[0] = stio->type = 'a';
+ name++;
+ }
+ else
+ mode[0] = 'w';
+ writing = 1;
+ if (*name == '&') {
+ duplicity:
+ name++;
+ while (isSPACE(*name))
+ name++;
+ if (isDIGIT(*name))
+ fd = atoi(name);
+ else {
+ stab = stabent(name,FALSE);
+ if (!stab || !stab_io(stab)) {
+#ifdef EINVAL
+ errno = EINVAL;
+#endif
+ goto say_false;
+ }
+ if (stab_io(stab) && stab_io(stab)->ifp) {
+ fd = fileno(stab_io(stab)->ifp);
+ if (stab_io(stab)->type == 's')
+ stio->type = 's';
+ }
+ else
+ fd = -1;
+ }
+ if (!(fp = fdopen(fd = dup(fd),mode))) {
+ close(fd);
+ }
+ }
+ else {
+ while (isSPACE(*name))
+ name++;
+ if (strEQ(name,"-")) {
+ fp = stdout;
+ stio->type = '-';
+ }
+ else {
+ fp = fopen(name,mode);
+ }
+ }
+ }
+ else {
+ if (*name == '<') {
+ mode[0] = 'r';
+ name++;
+ while (isSPACE(*name))
+ name++;
+ if (*name == '&')
+ goto duplicity;
+ if (strEQ(name,"-")) {
+ fp = stdin;
+ stio->type = '-';
+ }
+ else
+ fp = fopen(name,mode);
+ }
+ else if (name[len-1] == '|') {
+#ifdef TAINT
+ taintenv();
+ taintproper("Insecure dependency in piped open");
+#endif
+ name[--len] = '\0';
+ while (len && isSPACE(name[len-1]))
+ name[--len] = '\0';
+ /*SUPPRESS 530*/
+ for (; isSPACE(*name); name++) ;
+ fp = mypopen(name,"r");
+ stio->type = '|';
+ }
+ else {
+ stio->type = '<';
+ /*SUPPRESS 530*/
+ for (; isSPACE(*name); name++) ;
+ if (strEQ(name,"-")) {
+ fp = stdin;
+ stio->type = '-';
+ }
+ else
+ fp = fopen(name,"r");
+ }
+ }
+ if (!fp) {
+ if (dowarn && stio->type == '<' && index(name, '\n'))
+ warn(warn_nl, "open");
+ Safefree(myname);
+ goto say_false;
+ }
+ Safefree(myname);
+ if (stio->type &&
+ stio->type != '|' && stio->type != '-') {
+ if (fstat(fileno(fp),&statbuf) < 0) {
+ (void)fclose(fp);
+ goto say_false;
+ }
+ if (S_ISSOCK(statbuf.st_mode))
+ stio->type = 's'; /* in case a socket was passed in to us */
+#ifdef HAS_SOCKET
+ else if (
+#ifdef S_IFMT
+ !(statbuf.st_mode & S_IFMT)
+#else
+ !statbuf.st_mode
+#endif
+ ) {
+ int buflen = sizeof tokenbuf;
+ if (getsockname(fileno(fp), tokenbuf, &buflen) >= 0
+ || errno != ENOTSOCK)
+ stio->type = 's'; /* some OS's return 0 on fstat()ed socket */
+ /* but some return 0 for streams too, sigh */
+ }
+#endif
+ }
+ if (saveifp) { /* must use old fp? */
+ fd = fileno(saveifp);
+ if (saveofp) {
+ fflush(saveofp); /* emulate fclose() */
+ if (saveofp != saveifp) { /* was a socket? */
+ fclose(saveofp);
+ if (fd > 2)
+ Safefree(saveofp);
+ }
+ }
+ if (fd != fileno(fp)) {
+ int pid;
+ STR *str;
+
+ dup2(fileno(fp), fd);
+ str = afetch(fdpid,fileno(fp),TRUE);
+ pid = str->str_u.str_useful;
+ str->str_u.str_useful = 0;
+ str = afetch(fdpid,fd,TRUE);
+ str->str_u.str_useful = pid;
+ fclose(fp);
+
+ }
+ fp = saveifp;
+ clearerr(fp);
+ }
+#if defined(HAS_FCNTL) && defined(F_SETFD)
+ fd = fileno(fp);
+ fcntl(fd,F_SETFD,fd > maxsysfd);
+#endif
+ stio->ifp = fp;
+ if (writing) {
+ if (stio->type == 's'
+ || (stio->type == '>' && S_ISCHR(statbuf.st_mode)) ) {
+ if (!(stio->ofp = fdopen(fileno(fp),"w"))) {
+ fclose(fp);
+ stio->ifp = Nullfp;
+ goto say_false;
+ }
+ }
+ else
+ stio->ofp = fp;
+ }
+ return TRUE;
+
+say_false:
+ stio->ifp = saveifp;
+ stio->ofp = saveofp;
+ stio->type = savetype;
+ return FALSE;
+}
+
+FILE *
+nextargv(stab)
+register STAB *stab;
+{
+ register STR *str;
+#ifndef FLEXFILENAMES
+ int filedev;
+ int fileino;
+#endif
+ int fileuid;
+ int filegid;
+ static int filemode = 0;
+ static int lastfd;
+ static char *oldname;
+
+ if (!argvoutstab)
+ argvoutstab = stabent("ARGVOUT",TRUE);
+ if (filemode & (S_ISUID|S_ISGID)) {
+ fflush(stab_io(argvoutstab)->ifp); /* chmod must follow last write */
+#ifdef HAS_FCHMOD
+ (void)fchmod(lastfd,filemode);
+#else
+ (void)chmod(oldname,filemode);
+#endif
+ }
+ filemode = 0;
+ while (alen(stab_xarray(stab)) >= 0) {
+ str = ashift(stab_xarray(stab));
+ str_sset(stab_val(stab),str);
+ STABSET(stab_val(stab));
+ oldname = str_get(stab_val(stab));
+ if (do_open(stab,oldname,stab_val(stab)->str_cur)) {
+ if (inplace) {
+#ifdef TAINT
+ taintproper("Insecure dependency in inplace open");
+#endif
+ if (strEQ(oldname,"-")) {
+ str_free(str);
+ defoutstab = stabent("STDOUT",TRUE);
+ return stab_io(stab)->ifp;
+ }
+#ifndef FLEXFILENAMES
+ filedev = statbuf.st_dev;
+ fileino = statbuf.st_ino;
+#endif
+ filemode = statbuf.st_mode;
+ fileuid = statbuf.st_uid;
+ filegid = statbuf.st_gid;
+ if (!S_ISREG(filemode)) {
+ warn("Can't do inplace edit: %s is not a regular file",
+ oldname );
+ do_close(stab,FALSE);
+ str_free(str);
+ continue;
+ }
+ if (*inplace) {
+#ifdef SUFFIX
+ add_suffix(str,inplace);
+#else
+ str_cat(str,inplace);
+#endif
+#ifndef FLEXFILENAMES
+ if (stat(str->str_ptr,&statbuf) >= 0
+ && statbuf.st_dev == filedev
+ && statbuf.st_ino == fileino ) {
+ warn("Can't do inplace edit: %s > 14 characters",
+ str->str_ptr );
+ do_close(stab,FALSE);
+ str_free(str);
+ continue;
+ }
+#endif
+#ifdef HAS_RENAME
+#ifndef DOSISH
+ if (rename(oldname,str->str_ptr) < 0) {
+ warn("Can't rename %s to %s: %s, skipping file",
+ oldname, str->str_ptr, strerror(errno) );
+ do_close(stab,FALSE);
+ str_free(str);
+ continue;
+ }
+#else
+ do_close(stab,FALSE);
+ (void)unlink(str->str_ptr);
+ (void)rename(oldname,str->str_ptr);
+ do_open(stab,str->str_ptr,stab_val(stab)->str_cur);
+#endif /* MSDOS */
+#else
+ (void)UNLINK(str->str_ptr);
+ if (link(oldname,str->str_ptr) < 0) {
+ warn("Can't rename %s to %s: %s, skipping file",
+ oldname, str->str_ptr, strerror(errno) );
+ do_close(stab,FALSE);
+ str_free(str);
+ continue;
+ }
+ (void)UNLINK(oldname);
+#endif
+ }
+ else {
+#ifndef DOSISH
+ if (UNLINK(oldname) < 0) {
+ warn("Can't rename %s to %s: %s, skipping file",
+ oldname, str->str_ptr, strerror(errno) );
+ do_close(stab,FALSE);
+ str_free(str);
+ continue;
+ }
+#else
+ fatal("Can't do inplace edit without backup");
+#endif
+ }
+
+ str_nset(str,">",1);
+ str_cat(str,oldname);
+ errno = 0; /* in case sprintf set errno */
+ if (!do_open(argvoutstab,str->str_ptr,str->str_cur)) {
+ warn("Can't do inplace edit on %s: %s",
+ oldname, strerror(errno) );
+ do_close(stab,FALSE);
+ str_free(str);
+ continue;
+ }
+ defoutstab = argvoutstab;
+ lastfd = fileno(stab_io(argvoutstab)->ifp);
+ (void)fstat(lastfd,&statbuf);
+#ifdef HAS_FCHMOD
+ (void)fchmod(lastfd,filemode);
+#else
+ (void)chmod(oldname,filemode);
+#endif
+ if (fileuid != statbuf.st_uid || filegid != statbuf.st_gid) {
+#ifdef HAS_FCHOWN
+ (void)fchown(lastfd,fileuid,filegid);
+#else
+#ifdef HAS_CHOWN
+ (void)chown(oldname,fileuid,filegid);
+#endif
+#endif
+ }
+ }
+ str_free(str);
+ return stab_io(stab)->ifp;
+ }
+ else
+ fprintf(stderr,"Can't open %s: %s\n",str_get(str), strerror(errno));
+ str_free(str);
+ }
+ if (inplace) {
+ (void)do_close(argvoutstab,FALSE);
+ defoutstab = stabent("STDOUT",TRUE);
+ }
+ return Nullfp;
+}
+
+#ifdef HAS_PIPE
+void
+do_pipe(str, rstab, wstab)
+STR *str;
+STAB *rstab;
+STAB *wstab;
+{
+ register STIO *rstio;
+ register STIO *wstio;
+ int fd[2];
+
+ if (!rstab)
+ goto badexit;
+ if (!wstab)
+ goto badexit;
+
+ rstio = stab_io(rstab);
+ wstio = stab_io(wstab);
+
+ if (!rstio)
+ rstio = stab_io(rstab) = stio_new();
+ else if (rstio->ifp)
+ do_close(rstab,FALSE);
+ if (!wstio)
+ wstio = stab_io(wstab) = stio_new();
+ else if (wstio->ifp)
+ do_close(wstab,FALSE);
+
+ if (pipe(fd) < 0)
+ goto badexit;
+ rstio->ifp = fdopen(fd[0], "r");
+ wstio->ofp = fdopen(fd[1], "w");
+ wstio->ifp = wstio->ofp;
+ rstio->type = '<';
+ wstio->type = '>';
+ if (!rstio->ifp || !wstio->ofp) {
+ if (rstio->ifp) fclose(rstio->ifp);
+ else close(fd[0]);
+ if (wstio->ofp) fclose(wstio->ofp);
+ else close(fd[1]);
+ goto badexit;
+ }
+
+ str_sset(str,&str_yes);
+ return;
+
+badexit:
+ str_sset(str,&str_undef);
+ return;
+}
+#endif
+
+bool
+do_close(stab,explicit)
+STAB *stab;
+bool explicit;
+{
+ bool retval = FALSE;
+ register STIO *stio;
+ int status;
+
+ if (!stab)
+ stab = argvstab;
+ if (!stab) {
+ errno = EBADF;
+ return FALSE;
+ }
+ stio = stab_io(stab);
+ if (!stio) { /* never opened */
+ if (dowarn && explicit)
+ warn("Close on unopened file <%s>",stab_ename(stab));
+ return FALSE;
+ }
+ if (stio->ifp) {
+ if (stio->type == '|') {
+ status = mypclose(stio->ifp);
+ retval = (status == 0);
+ statusvalue = (unsigned short)status & 0xffff;
+ }
+ else if (stio->type == '-')
+ retval = TRUE;
+ else {
+ if (stio->ofp && stio->ofp != stio->ifp) { /* a socket */
+ retval = (fclose(stio->ofp) != EOF);
+ fclose(stio->ifp); /* clear stdio, fd already closed */
+ }
+ else
+ retval = (fclose(stio->ifp) != EOF);
+ }
+ stio->ofp = stio->ifp = Nullfp;
+ }
+ if (explicit)
+ stio->lines = 0;
+ stio->type = ' ';
+ return retval;
+}
+
+bool
+do_eof(stab)
+STAB *stab;
+{
+ register STIO *stio;
+ int ch;
+
+ if (!stab) { /* eof() */
+ if (argvstab)
+ stio = stab_io(argvstab);
+ else
+ return TRUE;
+ }
+ else
+ stio = stab_io(stab);
+
+ if (!stio)
+ return TRUE;
+
+ while (stio->ifp) {
+
+#ifdef STDSTDIO /* (the code works without this) */
+ if (stio->ifp->_cnt > 0) /* cheat a little, since */
+ return FALSE; /* this is the most usual case */
+#endif
+
+ ch = getc(stio->ifp);
+ if (ch != EOF) {
+ (void)ungetc(ch, stio->ifp);
+ return FALSE;
+ }
+#ifdef STDSTDIO
+ if (stio->ifp->_cnt < -1)
+ stio->ifp->_cnt = -1;
+#endif
+ if (!stab) { /* not necessarily a real EOF yet? */
+ if (!nextargv(argvstab)) /* get another fp handy */
+ return TRUE;
+ }
+ else
+ return TRUE; /* normal fp, definitely end of file */
+ }
+ return TRUE;
+}
+
+long
+do_tell(stab)
+STAB *stab;
+{
+ register STIO *stio;
+
+ if (!stab)
+ goto phooey;
+
+ stio = stab_io(stab);
+ if (!stio || !stio->ifp)
+ goto phooey;
+
+#ifdef ULTRIX_STDIO_BOTCH
+ if (feof(stio->ifp))
+ (void)fseek (stio->ifp, 0L, 2); /* ultrix 1.2 workaround */
+#endif
+
+ return ftell(stio->ifp);
+
+phooey:
+ if (dowarn)
+ warn("tell() on unopened file");
+ errno = EBADF;
+ return -1L;
+}
+
+bool
+do_seek(stab, pos, whence)
+STAB *stab;
+long pos;
+int whence;
+{
+ register STIO *stio;
+
+ if (!stab)
+ goto nuts;
+
+ stio = stab_io(stab);
+ if (!stio || !stio->ifp)
+ goto nuts;
+
+#ifdef ULTRIX_STDIO_BOTCH
+ if (feof(stio->ifp))
+ (void)fseek (stio->ifp, 0L, 2); /* ultrix 1.2 workaround */
+#endif
+
+ return fseek(stio->ifp, pos, whence) >= 0;
+
+nuts:
+ if (dowarn)
+ warn("seek() on unopened file");
+ errno = EBADF;
+ return FALSE;
+}
+
+int
+do_ctl(optype,stab,func,argstr)
+int optype;
+STAB *stab;
+int func;
+STR *argstr;
+{
+ register STIO *stio;
+ register char *s;
+ int retval;
+
+ if (!stab || !argstr || !(stio = stab_io(stab)) || !stio->ifp) {
+ errno = EBADF; /* well, sort of... */
+ return -1;
+ }
+
+ if (argstr->str_pok || !argstr->str_nok) {
+ if (!argstr->str_pok)
+ s = str_get(argstr);
+
+#ifdef IOCPARM_MASK
+#ifndef IOCPARM_LEN
+#define IOCPARM_LEN(x) (((x) >> 16) & IOCPARM_MASK)
+#endif
+#endif
+#ifdef IOCPARM_LEN
+ retval = IOCPARM_LEN(func); /* on BSDish systes we're safe */
+#else
+ retval = 256; /* otherwise guess at what's safe */
+#endif
+ if (argstr->str_cur < retval) {
+ Str_Grow(argstr,retval+1);
+ argstr->str_cur = retval;
+ }
+
+ s = argstr->str_ptr;
+ s[argstr->str_cur] = 17; /* a little sanity check here */
+ }
+ else {
+ retval = (int)str_gnum(argstr);
+#ifdef DOSISH
+ s = (char*)(long)retval; /* ouch */
+#else
+ s = (char*)retval; /* ouch */
+#endif
+ }
+
+#ifndef lint
+ if (optype == O_IOCTL)
+ retval = ioctl(fileno(stio->ifp), func, s);
+ else
+#ifdef DOSISH
+ fatal("fcntl is not implemented");
+#else
+#ifdef HAS_FCNTL
+ retval = fcntl(fileno(stio->ifp), func, s);
+#else
+ fatal("fcntl is not implemented");
+#endif
+#endif
+#else /* lint */
+ retval = 0;
+#endif /* lint */
+
+ if (argstr->str_pok) {
+ if (s[argstr->str_cur] != 17)
+ fatal("Return value overflowed string");
+ s[argstr->str_cur] = 0; /* put our null back */
+ }
+ return retval;
+}
+
+int
+do_stat(str,arg,gimme,arglast)
+STR *str;
+register ARG *arg;
+int gimme;
+int *arglast;
+{
+ register ARRAY *ary = stack;
+ register int sp = arglast[0] + 1;
+ int max = 13;
+
+ if ((arg[1].arg_type & A_MASK) == A_WORD) {
+ tmpstab = arg[1].arg_ptr.arg_stab;
+ if (tmpstab != defstab) {
+ laststype = O_STAT;
+ statstab = tmpstab;
+ str_set(statname,"");
+ if (!stab_io(tmpstab) || !stab_io(tmpstab)->ifp ||
+ fstat(fileno(stab_io(tmpstab)->ifp),&statcache) < 0) {
+ max = 0;
+ laststatval = -1;
+ }
+ }
+ else if (laststatval < 0)
+ max = 0;
+ }
+ else {
+ str_set(statname,str_get(ary->ary_array[sp]));
+ statstab = Nullstab;
+#ifdef HAS_LSTAT
+ laststype = arg->arg_type;
+ if (arg->arg_type == O_LSTAT)
+ laststatval = lstat(str_get(statname),&statcache);
+ else
+#endif
+ laststatval = stat(str_get(statname),&statcache);
+ if (laststatval < 0) {
+ if (dowarn && index(str_get(statname), '\n'))
+ warn(warn_nl, "stat");
+ max = 0;
+ }
+ }
+
+ if (gimme != G_ARRAY) {
+ if (max)
+ str_sset(str,&str_yes);
+ else
+ str_sset(str,&str_undef);
+ STABSET(str);
+ ary->ary_array[sp] = str;
+ return sp;
+ }
+ sp--;
+ if (max) {
+#ifndef lint
+ (void)astore(ary,++sp,
+ str_2mortal(str_nmake((double)statcache.st_dev)));
+ (void)astore(ary,++sp,
+ str_2mortal(str_nmake((double)statcache.st_ino)));
+ (void)astore(ary,++sp,
+ str_2mortal(str_nmake((double)statcache.st_mode)));
+ (void)astore(ary,++sp,
+ str_2mortal(str_nmake((double)statcache.st_nlink)));
+ (void)astore(ary,++sp,
+ str_2mortal(str_nmake((double)statcache.st_uid)));
+ (void)astore(ary,++sp,
+ str_2mortal(str_nmake((double)statcache.st_gid)));
+ (void)astore(ary,++sp,
+ str_2mortal(str_nmake((double)statcache.st_rdev)));
+ (void)astore(ary,++sp,
+ str_2mortal(str_nmake((double)statcache.st_size)));
+ (void)astore(ary,++sp,
+ str_2mortal(str_nmake((double)statcache.st_atime)));
+ (void)astore(ary,++sp,
+ str_2mortal(str_nmake((double)statcache.st_mtime)));
+ (void)astore(ary,++sp,
+ str_2mortal(str_nmake((double)statcache.st_ctime)));
+#ifdef STATBLOCKS
+ (void)astore(ary,++sp,
+ str_2mortal(str_nmake((double)statcache.st_blksize)));
+ (void)astore(ary,++sp,
+ str_2mortal(str_nmake((double)statcache.st_blocks)));
+#else
+ (void)astore(ary,++sp,
+ str_2mortal(str_make("",0)));
+ (void)astore(ary,++sp,
+ str_2mortal(str_make("",0)));
+#endif
+#else /* lint */
+ (void)astore(ary,++sp,str_nmake(0.0));
+#endif /* lint */
+ }
+ return sp;
+}
+
+#if !defined(HAS_TRUNCATE) && !defined(HAS_CHSIZE) && defined(F_FREESP)
+ /* code courtesy of William Kucharski */
+#define HAS_CHSIZE
+
+int chsize(fd, length)
+int fd; /* file descriptor */
+off_t length; /* length to set file to */
+{
+ extern long lseek();
+ struct flock fl;
+ struct stat filebuf;
+
+ if (fstat(fd, &filebuf) < 0)
+ return -1;
+
+ if (filebuf.st_size < length) {
+
+ /* extend file length */
+
+ if ((lseek(fd, (length - 1), 0)) < 0)
+ return -1;
+
+ /* write a "0" byte */
+
+ if ((write(fd, "", 1)) != 1)
+ return -1;
+ }
+ else {
+ /* truncate length */
+
+ fl.l_whence = 0;
+ fl.l_len = 0;
+ fl.l_start = length;
+ fl.l_type = F_WRLCK; /* write lock on file space */
+
+ /*
+ * This relies on the UNDOCUMENTED F_FREESP argument to
+ * fcntl(2), which truncates the file so that it ends at the
+ * position indicated by fl.l_start.
+ *
+ * Will minor miracles never cease?
+ */
+
+ if (fcntl(fd, F_FREESP, &fl) < 0)
+ return -1;
+
+ }
+
+ return 0;
+}
+#endif /* F_FREESP */
+
+int /*SUPPRESS 590*/
+do_truncate(str,arg,gimme,arglast)
+STR *str;
+register ARG *arg;
+int gimme;
+int *arglast;
+{
+ register ARRAY *ary = stack;
+ register int sp = arglast[0] + 1;
+ off_t len = (off_t)str_gnum(ary->ary_array[sp+1]);
+ int result = 1;
+ STAB *tmpstab;
+
+#if defined(HAS_TRUNCATE) || defined(HAS_CHSIZE)
+#ifdef HAS_TRUNCATE
+ if ((arg[1].arg_type & A_MASK) == A_WORD) {
+ tmpstab = arg[1].arg_ptr.arg_stab;
+ if (!stab_io(tmpstab) || !stab_io(tmpstab)->ifp ||
+ ftruncate(fileno(stab_io(tmpstab)->ifp), len) < 0)
+ result = 0;
+ }
+ else if (truncate(str_get(ary->ary_array[sp]), len) < 0)
+ result = 0;
+#else
+ if ((arg[1].arg_type & A_MASK) == A_WORD) {
+ tmpstab = arg[1].arg_ptr.arg_stab;
+ if (!stab_io(tmpstab) || !stab_io(tmpstab)->ifp ||
+ chsize(fileno(stab_io(tmpstab)->ifp), len) < 0)
+ result = 0;
+ }
+ else {
+ int tmpfd;
+
+ if ((tmpfd = open(str_get(ary->ary_array[sp]), 0)) < 0)
+ result = 0;
+ else {
+ if (chsize(tmpfd, len) < 0)
+ result = 0;
+ close(tmpfd);
+ }
+ }
+#endif
+
+ if (result)
+ str_sset(str,&str_yes);
+ else
+ str_sset(str,&str_undef);
+ STABSET(str);
+ ary->ary_array[sp] = str;
+ return sp;
+#else
+ fatal("truncate not implemented");
+#endif
+}
+
+int
+looks_like_number(str)
+STR *str;
+{
+ register char *s;
+ register char *send;
+
+ if (!str->str_pok)
+ return TRUE;
+ s = str->str_ptr;
+ send = s + str->str_cur;
+ while (isSPACE(*s))
+ s++;
+ if (s >= send)
+ return FALSE;
+ if (*s == '+' || *s == '-')
+ s++;
+ while (isDIGIT(*s))
+ s++;
+ if (s == send)
+ return TRUE;
+ if (*s == '.')
+ s++;
+ else if (s == str->str_ptr)
+ return FALSE;
+ while (isDIGIT(*s))
+ s++;
+ if (s == send)
+ return TRUE;
+ if (*s == 'e' || *s == 'E') {
+ s++;
+ if (*s == '+' || *s == '-')
+ s++;
+ while (isDIGIT(*s))
+ s++;
+ }
+ while (isSPACE(*s))
+ s++;
+ if (s >= send)
+ return TRUE;
+ return FALSE;
+}
+
+bool
+do_print(str,fp)
+register STR *str;
+FILE *fp;
+{
+ register char *tmps;
+
+ if (!fp) {
+ if (dowarn)
+ warn("print to unopened file");
+ errno = EBADF;
+ return FALSE;
+ }
+ if (!str)
+ return TRUE;
+ if (ofmt &&
+ ((str->str_nok && str->str_u.str_nval != 0.0)
+ || (looks_like_number(str) && str_gnum(str) != 0.0) ) ) {
+ fprintf(fp, ofmt, str->str_u.str_nval);
+ return !ferror(fp);
+ }
+ else {
+ tmps = str_get(str);
+ if (*tmps == 'S' && tmps[1] == 't' && tmps[2] == 'B' && tmps[3] == '\0'
+ && str->str_cur == sizeof(STBP) && strlen(tmps) < str->str_cur) {
+ STR *tmpstr = str_mortal(&str_undef);
+ stab_efullname(tmpstr,((STAB*)str));/* a stab value, be nice */
+ str = tmpstr;
+ tmps = str->str_ptr;
+ putc('*',fp);
+ }
+ if (str->str_cur && (fwrite(tmps,1,str->str_cur,fp) == 0 || ferror(fp)))
+ return FALSE;
+ }
+ return TRUE;
+}
+
+bool
+do_aprint(arg,fp,arglast)
+register ARG *arg;
+register FILE *fp;
+int *arglast;
+{
+ register STR **st = stack->ary_array;
+ register int sp = arglast[1];
+ register int retval;
+ register int items = arglast[2] - sp;
+
+ if (!fp) {
+ if (dowarn)
+ warn("print to unopened file");
+ errno = EBADF;
+ return FALSE;
+ }
+ st += ++sp;
+ if (arg->arg_type == O_PRTF) {
+ do_sprintf(arg->arg_ptr.arg_str,items,st);
+ retval = do_print(arg->arg_ptr.arg_str,fp);
+ }
+ else {
+ retval = (items <= 0);
+ for (; items > 0; items--,st++) {
+ if (retval && ofslen) {
+ if (fwrite(ofs, 1, ofslen, fp) == 0 || ferror(fp)) {
+ retval = FALSE;
+ break;
+ }
+ }
+ if (!(retval = do_print(*st, fp)))
+ break;
+ }
+ if (retval && orslen)
+ if (fwrite(ors, 1, orslen, fp) == 0 || ferror(fp))
+ retval = FALSE;
+ }
+ return retval;
+}
+
+int
+mystat(arg,str)
+ARG *arg;
+STR *str;
+{
+ STIO *stio;
+
+ if (arg[1].arg_type & A_DONT) {
+ stio = stab_io(arg[1].arg_ptr.arg_stab);
+ if (stio && stio->ifp) {
+ statstab = arg[1].arg_ptr.arg_stab;
+ str_set(statname,"");
+ laststype = O_STAT;
+ return (laststatval = fstat(fileno(stio->ifp), &statcache));
+ }
+ else {
+ if (arg[1].arg_ptr.arg_stab == defstab)
+ return laststatval;
+ if (dowarn)
+ warn("Stat on unopened file <%s>",
+ stab_ename(arg[1].arg_ptr.arg_stab));
+ statstab = Nullstab;
+ str_set(statname,"");
+ return (laststatval = -1);
+ }
+ }
+ else {
+ statstab = Nullstab;
+ str_set(statname,str_get(str));
+ laststype = O_STAT;
+ laststatval = stat(str_get(str),&statcache);
+ if (laststatval < 0 && dowarn && index(str_get(str), '\n'))
+ warn(warn_nl, "stat");
+ return laststatval;
+ }
+}
+
+int
+mylstat(arg,str)
+ARG *arg;
+STR *str;
+{
+ if (arg[1].arg_type & A_DONT) {
+ if (arg[1].arg_ptr.arg_stab == defstab) {
+ if (laststype != O_LSTAT)
+ fatal("The stat preceding -l _ wasn't an lstat");
+ return laststatval;
+ }
+ fatal("You can't use -l on a filehandle");
+ }
+
+ laststype = O_LSTAT;
+ statstab = Nullstab;
+ str_set(statname,str_get(str));
+#ifdef HAS_LSTAT
+ laststatval = lstat(str_get(str),&statcache);
+#else
+ laststatval = stat(str_get(str),&statcache);
+#endif
+ if (laststatval < 0 && dowarn && index(str_get(str), '\n'))
+ warn(warn_nl, "lstat");
+ return laststatval;
+}
+
+STR *
+do_fttext(arg,str)
+register ARG *arg;
+STR *str;
+{
+ int i;
+ int len;
+ int odd = 0;
+ STDCHAR tbuf[512];
+ register STDCHAR *s;
+ register STIO *stio;
+
+ if (arg[1].arg_type & A_DONT) {
+ if (arg[1].arg_ptr.arg_stab == defstab) {
+ if (statstab)
+ stio = stab_io(statstab);
+ else {
+ str = statname;
+ goto really_filename;
+ }
+ }
+ else {
+ statstab = arg[1].arg_ptr.arg_stab;
+ str_set(statname,"");
+ stio = stab_io(statstab);
+ }
+ if (stio && stio->ifp) {
+#if defined(STDSTDIO) || defined(atarist) /* this will work with atariST */
+ fstat(fileno(stio->ifp),&statcache);
+ if (S_ISDIR(statcache.st_mode)) /* handle NFS glitch */
+ return arg->arg_type == O_FTTEXT ? &str_no : &str_yes;
+ if (stio->ifp->_cnt <= 0) {
+ i = getc(stio->ifp);
+ if (i != EOF)
+ (void)ungetc(i,stio->ifp);
+ }
+ if (stio->ifp->_cnt <= 0) /* null file is anything */
+ return &str_yes;
+ len = stio->ifp->_cnt + (stio->ifp->_ptr - stio->ifp->_base);
+ s = stio->ifp->_base;
+#else
+ fatal("-T and -B not implemented on filehandles");
+#endif
+ }
+ else {
+ if (dowarn)
+ warn("Test on unopened file <%s>",
+ stab_ename(arg[1].arg_ptr.arg_stab));
+ errno = EBADF;
+ return &str_undef;
+ }
+ }
+ else {
+ statstab = Nullstab;
+ str_set(statname,str_get(str));
+ really_filename:
+ i = open(str_get(str),0);
+ if (i < 0) {
+ if (dowarn && index(str_get(str), '\n'))
+ warn(warn_nl, "open");
+ return &str_undef;
+ }
+ fstat(i,&statcache);
+ len = read(i,tbuf,512);
+ (void)close(i);
+ if (len <= 0) {
+ if (S_ISDIR(statcache.st_mode) && arg->arg_type == O_FTTEXT)
+ return &str_no; /* special case NFS directories */
+ return &str_yes; /* null file is anything */
+ }
+ s = tbuf;
+ }
+
+ /* now scan s to look for textiness */
+
+ for (i = 0; i < len; i++,s++) {
+ if (!*s) { /* null never allowed in text */
+ odd += len;
+ break;
+ }
+ else if (*s & 128)
+ odd++;
+ else if (*s < 32 &&
+ *s != '\n' && *s != '\r' && *s != '\b' &&
+ *s != '\t' && *s != '\f' && *s != 27)
+ odd++;
+ }
+
+ if ((odd * 10 > len) == (arg->arg_type == O_FTTEXT)) /* allow 10% odd */
+ return &str_no;
+ else
+ return &str_yes;
+}
+
+static char **Argv = Null(char **);
+static char *Cmd = Nullch;
+
+bool
+do_aexec(really,arglast)
+STR *really;
+int *arglast;
+{
+ register STR **st = stack->ary_array;
+ register int sp = arglast[1];
+ register int items = arglast[2] - sp;
+ register char **a;
+ char *tmps;
+
+ if (items) {
+ New(401,Argv, items+1, char*);
+ a = Argv;
+ for (st += ++sp; items > 0; items--,st++) {
+ if (*st)
+ *a++ = str_get(*st);
+ else
+ *a++ = "";
+ }
+ *a = Nullch;
+#ifdef TAINT
+ if (*Argv[0] != '/') /* will execvp use PATH? */
+ taintenv(); /* testing IFS here is overkill, probably */
+#endif
+ if (really && *(tmps = str_get(really)))
+ execvp(tmps,Argv);
+ else
+ execvp(Argv[0],Argv);
+ }
+ do_execfree();
+ return FALSE;
+}
+
+void
+do_execfree()
+{
+ if (Argv) {
+ Safefree(Argv);
+ Argv = Null(char **);
+ }
+ if (Cmd) {
+ Safefree(Cmd);
+ Cmd = Nullch;
+ }
+}
+
+bool
+do_exec(cmd)
+char *cmd;
+{
+ register char **a;
+ register char *s;
+ char flags[10];
+
+ /* save an extra exec if possible */
+
+#ifdef CSH
+ if (strnEQ(cmd,cshname,cshlen) && strnEQ(cmd+cshlen," -c",3)) {
+ strcpy(flags,"-c");
+ s = cmd+cshlen+3;
+ if (*s == 'f') {
+ s++;
+ strcat(flags,"f");
+ }
+ if (*s == ' ')
+ s++;
+ if (*s++ == '\'') {
+ char *ncmd = s;
+
+ while (*s)
+ s++;
+ if (s[-1] == '\n')
+ *--s = '\0';
+ if (s[-1] == '\'') {
+ *--s = '\0';
+ execl(cshname,"csh", flags,ncmd,(char*)0);
+ *s = '\'';
+ return FALSE;
+ }
+ }
+ }
+#endif /* CSH */
+
+ /* see if there are shell metacharacters in it */
+
+ /*SUPPRESS 530*/
+ for (s = cmd; *s && isALPHA(*s); s++) ; /* catch VAR=val gizmo */
+ if (*s == '=')
+ goto doshell;
+ for (s = cmd; *s; s++) {
+ if (*s != ' ' && !isALPHA(*s) && index("$&*(){}[]'\";\\|?<>~`\n",*s)) {
+ if (*s == '\n' && !s[1]) {
+ *s = '\0';
+ break;
+ }
+ doshell:
+ execl("/bin/sh","sh","-c",cmd,(char*)0);
+ return FALSE;
+ }
+ }
+ New(402,Argv, (s - cmd) / 2 + 2, char*);
+ Cmd = nsavestr(cmd, s-cmd);
+ a = Argv;
+ for (s = Cmd; *s;) {
+ while (*s && isSPACE(*s)) s++;
+ if (*s)
+ *(a++) = s;
+ while (*s && !isSPACE(*s)) s++;
+ if (*s)
+ *s++ = '\0';
+ }
+ *a = Nullch;
+ if (Argv[0]) {
+ execvp(Argv[0],Argv);
+ if (errno == ENOEXEC) { /* for system V NIH syndrome */
+ do_execfree();
+ goto doshell;
+ }
+ }
+ do_execfree();
+ return FALSE;
+}
+
+#ifdef HAS_SOCKET
+int
+do_socket(stab, arglast)
+STAB *stab;
+int *arglast;
+{
+ register STR **st = stack->ary_array;
+ register int sp = arglast[1];
+ register STIO *stio;
+ int domain, type, protocol, fd;
+
+ if (!stab) {
+ errno = EBADF;
+ return FALSE;
+ }
+
+ stio = stab_io(stab);
+ if (!stio)
+ stio = stab_io(stab) = stio_new();
+ else if (stio->ifp)
+ do_close(stab,FALSE);
+
+ domain = (int)str_gnum(st[++sp]);
+ type = (int)str_gnum(st[++sp]);
+ protocol = (int)str_gnum(st[++sp]);
+#ifdef TAINT
+ taintproper("Insecure dependency in socket");
+#endif
+ fd = socket(domain,type,protocol);
+ if (fd < 0)
+ return FALSE;
+ stio->ifp = fdopen(fd, "r"); /* stdio gets confused about sockets */
+ stio->ofp = fdopen(fd, "w");
+ stio->type = 's';
+ if (!stio->ifp || !stio->ofp) {
+ if (stio->ifp) fclose(stio->ifp);
+ if (stio->ofp) fclose(stio->ofp);
+ if (!stio->ifp && !stio->ofp) close(fd);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+int
+do_bind(stab, arglast)
+STAB *stab;
+int *arglast;
+{
+ register STR **st = stack->ary_array;
+ register int sp = arglast[1];
+ register STIO *stio;
+ char *addr;
+
+ if (!stab)
+ goto nuts;
+
+ stio = stab_io(stab);
+ if (!stio || !stio->ifp)
+ goto nuts;
+
+ addr = str_get(st[++sp]);
+#ifdef TAINT
+ taintproper("Insecure dependency in bind");
+#endif
+ return bind(fileno(stio->ifp), addr, st[sp]->str_cur) >= 0;
+
+nuts:
+ if (dowarn)
+ warn("bind() on closed fd");
+ errno = EBADF;
+ return FALSE;
+
+}
+
+int
+do_connect(stab, arglast)
+STAB *stab;
+int *arglast;
+{
+ register STR **st = stack->ary_array;
+ register int sp = arglast[1];
+ register STIO *stio;
+ char *addr;
+
+ if (!stab)
+ goto nuts;
+
+ stio = stab_io(stab);
+ if (!stio || !stio->ifp)
+ goto nuts;
+
+ addr = str_get(st[++sp]);
+#ifdef TAINT
+ taintproper("Insecure dependency in connect");
+#endif
+ return connect(fileno(stio->ifp), addr, st[sp]->str_cur) >= 0;
+
+nuts:
+ if (dowarn)
+ warn("connect() on closed fd");
+ errno = EBADF;
+ return FALSE;
+
+}
+
+int
+do_listen(stab, arglast)
+STAB *stab;
+int *arglast;
+{
+ register STR **st = stack->ary_array;
+ register int sp = arglast[1];
+ register STIO *stio;
+ int backlog;
+
+ if (!stab)
+ goto nuts;
+
+ stio = stab_io(stab);
+ if (!stio || !stio->ifp)
+ goto nuts;
+
+ backlog = (int)str_gnum(st[++sp]);
+ return listen(fileno(stio->ifp), backlog) >= 0;
+
+nuts:
+ if (dowarn)
+ warn("listen() on closed fd");
+ errno = EBADF;
+ return FALSE;
+}
+
+void
+do_accept(str, nstab, gstab)
+STR *str;
+STAB *nstab;
+STAB *gstab;
+{
+ register STIO *nstio;
+ register STIO *gstio;
+ int len = sizeof buf;
+ int fd;
+
+ if (!nstab)
+ goto badexit;
+ if (!gstab)
+ goto nuts;
+
+ gstio = stab_io(gstab);
+ nstio = stab_io(nstab);
+
+ if (!gstio || !gstio->ifp)
+ goto nuts;
+ if (!nstio)
+ nstio = stab_io(nstab) = stio_new();
+ else if (nstio->ifp)
+ do_close(nstab,FALSE);
+
+ fd = accept(fileno(gstio->ifp),(struct sockaddr *)buf,&len);
+ if (fd < 0)
+ goto badexit;
+ nstio->ifp = fdopen(fd, "r");
+ nstio->ofp = fdopen(fd, "w");
+ nstio->type = 's';
+ if (!nstio->ifp || !nstio->ofp) {
+ if (nstio->ifp) fclose(nstio->ifp);
+ if (nstio->ofp) fclose(nstio->ofp);
+ if (!nstio->ifp && !nstio->ofp) close(fd);
+ goto badexit;
+ }
+
+ str_nset(str, buf, len);
+ return;
+
+nuts:
+ if (dowarn)
+ warn("accept() on closed fd");
+ errno = EBADF;
+badexit:
+ str_sset(str,&str_undef);
+ return;
+}
+
+int
+do_shutdown(stab, arglast)
+STAB *stab;
+int *arglast;
+{
+ register STR **st = stack->ary_array;
+ register int sp = arglast[1];
+ register STIO *stio;
+ int how;
+
+ if (!stab)
+ goto nuts;
+
+ stio = stab_io(stab);
+ if (!stio || !stio->ifp)
+ goto nuts;
+
+ how = (int)str_gnum(st[++sp]);
+ return shutdown(fileno(stio->ifp), how) >= 0;
+
+nuts:
+ if (dowarn)
+ warn("shutdown() on closed fd");
+ errno = EBADF;
+ return FALSE;
+
+}
+
+int
+do_sopt(optype, stab, arglast)
+int optype;
+STAB *stab;
+int *arglast;
+{
+ register STR **st = stack->ary_array;
+ register int sp = arglast[1];
+ register STIO *stio;
+ int fd;
+ unsigned int lvl;
+ unsigned int optname;
+
+ if (!stab)
+ goto nuts;
+
+ stio = stab_io(stab);
+ if (!stio || !stio->ifp)
+ goto nuts;
+
+ fd = fileno(stio->ifp);
+ lvl = (unsigned int)str_gnum(st[sp+1]);
+ optname = (unsigned int)str_gnum(st[sp+2]);
+ switch (optype) {
+ case O_GSOCKOPT:
+ st[sp] = str_2mortal(Str_new(22,257));
+ st[sp]->str_cur = 256;
+ st[sp]->str_pok = 1;
+ if (getsockopt(fd, lvl, optname, st[sp]->str_ptr,
+ (int*)&st[sp]->str_cur) < 0)
+ goto nuts;
+ break;
+ case O_SSOCKOPT:
+ st[sp] = st[sp+3];
+ if (setsockopt(fd, lvl, optname, st[sp]->str_ptr, st[sp]->str_cur) < 0)
+ goto nuts;
+ st[sp] = &str_yes;
+ break;
+ }
+
+ return sp;
+
+nuts:
+ if (dowarn)
+ warn("[gs]etsockopt() on closed fd");
+ st[sp] = &str_undef;
+ errno = EBADF;
+ return sp;
+
+}
+
+int
+do_getsockname(optype, stab, arglast)
+int optype;
+STAB *stab;
+int *arglast;
+{
+ register STR **st = stack->ary_array;
+ register int sp = arglast[1];
+ register STIO *stio;
+ int fd;
+
+ if (!stab)
+ goto nuts;
+
+ stio = stab_io(stab);
+ if (!stio || !stio->ifp)
+ goto nuts;
+
+ st[sp] = str_2mortal(Str_new(22,257));
+ st[sp]->str_cur = 256;
+ st[sp]->str_pok = 1;
+ fd = fileno(stio->ifp);
+ switch (optype) {
+ case O_GETSOCKNAME:
+ if (getsockname(fd, st[sp]->str_ptr, (int*)&st[sp]->str_cur) < 0)
+ goto nuts2;
+ break;
+ case O_GETPEERNAME:
+ if (getpeername(fd, st[sp]->str_ptr, (int*)&st[sp]->str_cur) < 0)
+ goto nuts2;
+ break;
+ }
+
+ return sp;
+
+nuts:
+ if (dowarn)
+ warn("get{sock,peer}name() on closed fd");
+ errno = EBADF;
+nuts2:
+ st[sp] = &str_undef;
+ return sp;
+
+}
+
+int
+do_ghent(which,gimme,arglast)
+int which;
+int gimme;
+int *arglast;
+{
+ register ARRAY *ary = stack;
+ register int sp = arglast[0];
+ register char **elem;
+ register STR *str;
+ struct hostent *gethostbyname();
+ struct hostent *gethostbyaddr();
+#ifdef HAS_GETHOSTENT
+ struct hostent *gethostent();
+#endif
+ struct hostent *hent;
+ unsigned long len;
+
+ if (which == O_GHBYNAME) {
+ char *name = str_get(ary->ary_array[sp+1]);
+
+ hent = gethostbyname(name);
+ }
+ else if (which == O_GHBYADDR) {
+ STR *addrstr = ary->ary_array[sp+1];
+ int addrtype = (int)str_gnum(ary->ary_array[sp+2]);
+ char *addr = str_get(addrstr);
+
+ hent = gethostbyaddr(addr,addrstr->str_cur,addrtype);
+ }
+ else
+#ifdef HAS_GETHOSTENT
+ hent = gethostent();
+#else
+ fatal("gethostent not implemented");
+#endif
+
+#ifdef HOST_NOT_FOUND
+ if (!hent)
+ statusvalue = (unsigned short)h_errno & 0xffff;
+#endif
+
+ if (gimme != G_ARRAY) {
+ astore(ary, ++sp, str = str_mortal(&str_undef));
+ if (hent) {
+ if (which == O_GHBYNAME) {
+#ifdef h_addr
+ str_nset(str, *hent->h_addr, hent->h_length);
+#else
+ str_nset(str, hent->h_addr, hent->h_length);
+#endif
+ }
+ else
+ str_set(str, hent->h_name);
+ }
+ return sp;
+ }
+
+ if (hent) {
+#ifndef lint
+ (void)astore(ary, ++sp, str = str_mortal(&str_no));
+ str_set(str, hent->h_name);
+ (void)astore(ary, ++sp, str = str_mortal(&str_no));
+ for (elem = hent->h_aliases; *elem; elem++) {
+ str_cat(str, *elem);
+ if (elem[1])
+ str_ncat(str," ",1);
+ }
+ (void)astore(ary, ++sp, str = str_mortal(&str_no));
+ str_numset(str, (double)hent->h_addrtype);
+ (void)astore(ary, ++sp, str = str_mortal(&str_no));
+ len = hent->h_length;
+ str_numset(str, (double)len);
+#ifdef h_addr
+ for (elem = hent->h_addr_list; *elem; elem++) {
+ (void)astore(ary, ++sp, str = str_mortal(&str_no));
+ str_nset(str, *elem, len);
+ }
+#else
+ (void)astore(ary, ++sp, str = str_mortal(&str_no));
+ str_nset(str, hent->h_addr, len);
+#endif /* h_addr */
+#else /* lint */
+ elem = Nullch;
+ elem = elem;
+ (void)astore(ary, ++sp, str_mortal(&str_no));
+#endif /* lint */
+ }
+
+ return sp;
+}
+
+int
+do_gnent(which,gimme,arglast)
+int which;
+int gimme;
+int *arglast;
+{
+ register ARRAY *ary = stack;
+ register int sp = arglast[0];
+ register char **elem;
+ register STR *str;
+ struct netent *getnetbyname();
+ struct netent *getnetbyaddr();
+ struct netent *getnetent();
+ struct netent *nent;
+
+ if (which == O_GNBYNAME) {
+ char *name = str_get(ary->ary_array[sp+1]);
+
+ nent = getnetbyname(name);
+ }
+ else if (which == O_GNBYADDR) {
+ unsigned long addr = U_L(str_gnum(ary->ary_array[sp+1]));
+ int addrtype = (int)str_gnum(ary->ary_array[sp+2]);
+
+ nent = getnetbyaddr((long)addr,addrtype);
+ }
+ else
+ nent = getnetent();
+
+ if (gimme != G_ARRAY) {
+ astore(ary, ++sp, str = str_mortal(&str_undef));
+ if (nent) {
+ if (which == O_GNBYNAME)
+ str_numset(str, (double)nent->n_net);
+ else
+ str_set(str, nent->n_name);
+ }
+ return sp;
+ }
+
+ if (nent) {
+#ifndef lint
+ (void)astore(ary, ++sp, str = str_mortal(&str_no));
+ str_set(str, nent->n_name);
+ (void)astore(ary, ++sp, str = str_mortal(&str_no));
+ for (elem = nent->n_aliases; *elem; elem++) {
+ str_cat(str, *elem);
+ if (elem[1])
+ str_ncat(str," ",1);
+ }
+ (void)astore(ary, ++sp, str = str_mortal(&str_no));
+ str_numset(str, (double)nent->n_addrtype);
+ (void)astore(ary, ++sp, str = str_mortal(&str_no));
+ str_numset(str, (double)nent->n_net);
+#else /* lint */
+ elem = Nullch;
+ elem = elem;
+ (void)astore(ary, ++sp, str_mortal(&str_no));
+#endif /* lint */
+ }
+
+ return sp;
+}
+
+int
+do_gpent(which,gimme,arglast)
+int which;
+int gimme;
+int *arglast;
+{
+ register ARRAY *ary = stack;
+ register int sp = arglast[0];
+ register char **elem;
+ register STR *str;
+ struct protoent *getprotobyname();
+ struct protoent *getprotobynumber();
+ struct protoent *getprotoent();
+ struct protoent *pent;
+
+ if (which == O_GPBYNAME) {
+ char *name = str_get(ary->ary_array[sp+1]);
+
+ pent = getprotobyname(name);
+ }
+ else if (which == O_GPBYNUMBER) {
+ int proto = (int)str_gnum(ary->ary_array[sp+1]);
+
+ pent = getprotobynumber(proto);
+ }
+ else
+ pent = getprotoent();
+
+ if (gimme != G_ARRAY) {
+ astore(ary, ++sp, str = str_mortal(&str_undef));
+ if (pent) {
+ if (which == O_GPBYNAME)
+ str_numset(str, (double)pent->p_proto);
+ else
+ str_set(str, pent->p_name);
+ }
+ return sp;
+ }
+
+ if (pent) {
+#ifndef lint
+ (void)astore(ary, ++sp, str = str_mortal(&str_no));
+ str_set(str, pent->p_name);
+ (void)astore(ary, ++sp, str = str_mortal(&str_no));
+ for (elem = pent->p_aliases; *elem; elem++) {
+ str_cat(str, *elem);
+ if (elem[1])
+ str_ncat(str," ",1);
+ }
+ (void)astore(ary, ++sp, str = str_mortal(&str_no));
+ str_numset(str, (double)pent->p_proto);
+#else /* lint */
+ elem = Nullch;
+ elem = elem;
+ (void)astore(ary, ++sp, str_mortal(&str_no));
+#endif /* lint */
+ }
+
+ return sp;
+}
+
+int
+do_gsent(which,gimme,arglast)
+int which;
+int gimme;
+int *arglast;
+{
+ register ARRAY *ary = stack;
+ register int sp = arglast[0];
+ register char **elem;
+ register STR *str;
+ struct servent *getservbyname();
+ struct servent *getservbynumber();
+ struct servent *getservent();
+ struct servent *sent;
+
+ if (which == O_GSBYNAME) {
+ char *name = str_get(ary->ary_array[sp+1]);
+ char *proto = str_get(ary->ary_array[sp+2]);
+
+ if (proto && !*proto)
+ proto = Nullch;
+
+ sent = getservbyname(name,proto);
+ }
+ else if (which == O_GSBYPORT) {
+ int port = (int)str_gnum(ary->ary_array[sp+1]);
+ char *proto = str_get(ary->ary_array[sp+2]);
+
+ sent = getservbyport(port,proto);
+ }
+ else
+ sent = getservent();
+
+ if (gimme != G_ARRAY) {
+ astore(ary, ++sp, str = str_mortal(&str_undef));
+ if (sent) {
+ if (which == O_GSBYNAME) {
+#ifdef HAS_NTOHS
+ str_numset(str, (double)ntohs(sent->s_port));
+#else
+ str_numset(str, (double)(sent->s_port));
+#endif
+ }
+ else
+ str_set(str, sent->s_name);
+ }
+ return sp;
+ }
+
+ if (sent) {
+#ifndef lint
+ (void)astore(ary, ++sp, str = str_mortal(&str_no));
+ str_set(str, sent->s_name);
+ (void)astore(ary, ++sp, str = str_mortal(&str_no));
+ for (elem = sent->s_aliases; *elem; elem++) {
+ str_cat(str, *elem);
+ if (elem[1])
+ str_ncat(str," ",1);
+ }
+ (void)astore(ary, ++sp, str = str_mortal(&str_no));
+#ifdef HAS_NTOHS
+ str_numset(str, (double)ntohs(sent->s_port));
+#else
+ str_numset(str, (double)(sent->s_port));
+#endif
+ (void)astore(ary, ++sp, str = str_mortal(&str_no));
+ str_set(str, sent->s_proto);
+#else /* lint */
+ elem = Nullch;
+ elem = elem;
+ (void)astore(ary, ++sp, str_mortal(&str_no));
+#endif /* lint */
+ }
+
+ return sp;
+}
+
+#endif /* HAS_SOCKET */
+
+#ifdef HAS_SELECT
+int
+do_select(gimme,arglast)
+int gimme;
+int *arglast;
+{
+ register STR **st = stack->ary_array;
+ register int sp = arglast[0];
+ register int i;
+ register int j;
+ register char *s;
+ register STR *str;
+ double value;
+ int maxlen = 0;
+ int nfound;
+ struct timeval timebuf;
+ struct timeval *tbuf = &timebuf;
+ int growsize;
+#if BYTEORDER != 0x1234 && BYTEORDER != 0x12345678
+ int masksize;
+ int offset;
+ char *fd_sets[4];
+ int k;
+
+#if BYTEORDER & 0xf0000
+#define ORDERBYTE (0x88888888 - BYTEORDER)
+#else
+#define ORDERBYTE (0x4444 - BYTEORDER)
+#endif
+
+#endif
+
+ for (i = 1; i <= 3; i++) {
+ j = st[sp+i]->str_cur;
+ if (maxlen < j)
+ maxlen = j;
+ }
+
+#if BYTEORDER == 0x1234 || BYTEORDER == 0x12345678
+ growsize = maxlen; /* little endians can use vecs directly */
+#else
+#ifdef NFDBITS
+
+#ifndef NBBY
+#define NBBY 8
+#endif
+
+ masksize = NFDBITS / NBBY;
+#else
+ masksize = sizeof(long); /* documented int, everyone seems to use long */
+#endif
+ growsize = maxlen + (masksize - (maxlen % masksize));
+ Zero(&fd_sets[0], 4, char*);
+#endif
+
+ for (i = 1; i <= 3; i++) {
+ str = st[sp+i];
+ j = str->str_len;
+ if (j < growsize) {
+ if (str->str_pok) {
+ Str_Grow(str,growsize);
+ s = str_get(str) + j;
+ while (++j <= growsize) {
+ *s++ = '\0';
+ }
+ }
+ else if (str->str_ptr) {
+ Safefree(str->str_ptr);
+ str->str_ptr = Nullch;
+ }
+ }
+#if BYTEORDER != 0x1234 && BYTEORDER != 0x12345678
+ s = str->str_ptr;
+ if (s) {
+ New(403, fd_sets[i], growsize, char);
+ for (offset = 0; offset < growsize; offset += masksize) {
+ for (j = 0, k=ORDERBYTE; j < masksize; j++, (k >>= 4))
+ fd_sets[i][j+offset] = s[(k % masksize) + offset];
+ }
+ }
+#endif
+ }
+ str = st[sp+4];
+ if (str->str_nok || str->str_pok) {
+ value = str_gnum(str);
+ if (value < 0.0)
+ value = 0.0;
+ timebuf.tv_sec = (long)value;
+ value -= (double)timebuf.tv_sec;
+ timebuf.tv_usec = (long)(value * 1000000.0);
+ }
+ else
+ tbuf = Null(struct timeval*);
+
+#if BYTEORDER == 0x1234 || BYTEORDER == 0x12345678
+ nfound = select(
+ maxlen * 8,
+ st[sp+1]->str_ptr,
+ st[sp+2]->str_ptr,
+ st[sp+3]->str_ptr,
+ tbuf);
+#else
+ nfound = select(
+ maxlen * 8,
+ fd_sets[1],
+ fd_sets[2],
+ fd_sets[3],
+ tbuf);
+ for (i = 1; i <= 3; i++) {
+ if (fd_sets[i]) {
+ str = st[sp+i];
+ s = str->str_ptr;
+ for (offset = 0; offset < growsize; offset += masksize) {
+ for (j = 0, k=ORDERBYTE; j < masksize; j++, (k >>= 4))
+ s[(k % masksize) + offset] = fd_sets[i][j+offset];
+ }
+ Safefree(fd_sets[i]);
+ }
+ }
+#endif
+
+ st[++sp] = str_mortal(&str_no);
+ str_numset(st[sp], (double)nfound);
+ if (gimme == G_ARRAY && tbuf) {
+ value = (double)(timebuf.tv_sec) +
+ (double)(timebuf.tv_usec) / 1000000.0;
+ st[++sp] = str_mortal(&str_no);
+ str_numset(st[sp], value);
+ }
+ return sp;
+}
+#endif /* SELECT */
+
+#ifdef HAS_SOCKET
+int
+do_spair(stab1, stab2, arglast)
+STAB *stab1;
+STAB *stab2;
+int *arglast;
+{
+ register STR **st = stack->ary_array;
+ register int sp = arglast[2];
+ register STIO *stio1;
+ register STIO *stio2;
+ int domain, type, protocol, fd[2];
+
+ if (!stab1 || !stab2)
+ return FALSE;
+
+ stio1 = stab_io(stab1);
+ stio2 = stab_io(stab2);
+ if (!stio1)
+ stio1 = stab_io(stab1) = stio_new();
+ else if (stio1->ifp)
+ do_close(stab1,FALSE);
+ if (!stio2)
+ stio2 = stab_io(stab2) = stio_new();
+ else if (stio2->ifp)
+ do_close(stab2,FALSE);
+
+ domain = (int)str_gnum(st[++sp]);
+ type = (int)str_gnum(st[++sp]);
+ protocol = (int)str_gnum(st[++sp]);
+#ifdef TAINT
+ taintproper("Insecure dependency in socketpair");
+#endif
+#ifdef HAS_SOCKETPAIR
+ if (socketpair(domain,type,protocol,fd) < 0)
+ return FALSE;
+#else
+ fatal("Socketpair unimplemented");
+#endif
+ stio1->ifp = fdopen(fd[0], "r");
+ stio1->ofp = fdopen(fd[0], "w");
+ stio1->type = 's';
+ stio2->ifp = fdopen(fd[1], "r");
+ stio2->ofp = fdopen(fd[1], "w");
+ stio2->type = 's';
+ if (!stio1->ifp || !stio1->ofp || !stio2->ifp || !stio2->ofp) {
+ if (stio1->ifp) fclose(stio1->ifp);
+ if (stio1->ofp) fclose(stio1->ofp);
+ if (!stio1->ifp && !stio1->ofp) close(fd[0]);
+ if (stio2->ifp) fclose(stio2->ifp);
+ if (stio2->ofp) fclose(stio2->ofp);
+ if (!stio2->ifp && !stio2->ofp) close(fd[1]);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+#endif /* HAS_SOCKET */
+
+int
+do_gpwent(which,gimme,arglast)
+int which;
+int gimme;
+int *arglast;
+{
+#ifdef I_PWD
+ register ARRAY *ary = stack;
+ register int sp = arglast[0];
+ register STR *str;
+ struct passwd *getpwnam();
+ struct passwd *getpwuid();
+ struct passwd *getpwent();
+ struct passwd *pwent;
+
+ if (which == O_GPWNAM) {
+ char *name = str_get(ary->ary_array[sp+1]);
+
+ pwent = getpwnam(name);
+ }
+ else if (which == O_GPWUID) {
+ int uid = (int)str_gnum(ary->ary_array[sp+1]);
+
+ pwent = getpwuid(uid);
+ }
+ else
+ pwent = getpwent();
+
+ if (gimme != G_ARRAY) {
+ astore(ary, ++sp, str = str_mortal(&str_undef));
+ if (pwent) {
+ if (which == O_GPWNAM)
+ str_numset(str, (double)pwent->pw_uid);
+ else
+ str_set(str, pwent->pw_name);
+ }
+ return sp;
+ }
+
+ if (pwent) {
+ (void)astore(ary, ++sp, str = str_mortal(&str_no));
+ str_set(str, pwent->pw_name);
+ (void)astore(ary, ++sp, str = str_mortal(&str_no));
+ str_set(str, pwent->pw_passwd);
+ (void)astore(ary, ++sp, str = str_mortal(&str_no));
+ str_numset(str, (double)pwent->pw_uid);
+ (void)astore(ary, ++sp, str = str_mortal(&str_no));
+ str_numset(str, (double)pwent->pw_gid);
+ (void)astore(ary, ++sp, str = str_mortal(&str_no));
+#ifdef PWCHANGE
+ str_numset(str, (double)pwent->pw_change);
+#else
+#ifdef PWQUOTA
+ str_numset(str, (double)pwent->pw_quota);
+#else
+#ifdef PWAGE
+ str_set(str, pwent->pw_age);
+#endif
+#endif
+#endif
+ (void)astore(ary, ++sp, str = str_mortal(&str_no));
+#ifdef PWCLASS
+ str_set(str,pwent->pw_class);
+#else
+#ifdef PWCOMMENT
+ str_set(str, pwent->pw_comment);
+#endif
+#endif
+ (void)astore(ary, ++sp, str = str_mortal(&str_no));
+ str_set(str, pwent->pw_gecos);
+ (void)astore(ary, ++sp, str = str_mortal(&str_no));
+ str_set(str, pwent->pw_dir);
+ (void)astore(ary, ++sp, str = str_mortal(&str_no));
+ str_set(str, pwent->pw_shell);
+#ifdef PWEXPIRE
+ (void)astore(ary, ++sp, str = str_mortal(&str_no));
+ str_numset(str, (double)pwent->pw_expire);
+#endif
+ }
+
+ return sp;
+#else
+ fatal("password routines not implemented");
+#endif
+}
+
+int
+do_ggrent(which,gimme,arglast)
+int which;
+int gimme;
+int *arglast;
+{
+#ifdef I_GRP
+ register ARRAY *ary = stack;
+ register int sp = arglast[0];
+ register char **elem;
+ register STR *str;
+ struct group *getgrnam();
+ struct group *getgrgid();
+ struct group *getgrent();
+ struct group *grent;
+
+ if (which == O_GGRNAM) {
+ char *name = str_get(ary->ary_array[sp+1]);
+
+ grent = getgrnam(name);
+ }
+ else if (which == O_GGRGID) {
+ int gid = (int)str_gnum(ary->ary_array[sp+1]);
+
+ grent = getgrgid(gid);
+ }
+ else
+ grent = getgrent();
+
+ if (gimme != G_ARRAY) {
+ astore(ary, ++sp, str = str_mortal(&str_undef));
+ if (grent) {
+ if (which == O_GGRNAM)
+ str_numset(str, (double)grent->gr_gid);
+ else
+ str_set(str, grent->gr_name);
+ }
+ return sp;
+ }
+
+ if (grent) {
+ (void)astore(ary, ++sp, str = str_mortal(&str_no));
+ str_set(str, grent->gr_name);
+ (void)astore(ary, ++sp, str = str_mortal(&str_no));
+ str_set(str, grent->gr_passwd);
+ (void)astore(ary, ++sp, str = str_mortal(&str_no));
+ str_numset(str, (double)grent->gr_gid);
+ (void)astore(ary, ++sp, str = str_mortal(&str_no));
+ for (elem = grent->gr_mem; *elem; elem++) {
+ str_cat(str, *elem);
+ if (elem[1])
+ str_ncat(str," ",1);
+ }
+ }
+
+ return sp;
+#else
+ fatal("group routines not implemented");
+#endif
+}
+
+int
+do_dirop(optype,stab,gimme,arglast)
+int optype;
+STAB *stab;
+int gimme;
+int *arglast;
+{
+#if defined(DIRENT) && defined(HAS_READDIR)
+ register ARRAY *ary = stack;
+ register STR **st = ary->ary_array;
+ register int sp = arglast[1];
+ register STIO *stio;
+ long along;
+#ifndef apollo
+ struct DIRENT *readdir();
+#endif
+ register struct DIRENT *dp;
+
+ if (!stab)
+ goto nope;
+ if (!(stio = stab_io(stab)))
+ stio = stab_io(stab) = stio_new();
+ if (!stio->dirp && optype != O_OPEN_DIR)
+ goto nope;
+ st[sp] = &str_yes;
+ switch (optype) {
+ case O_OPEN_DIR:
+ if (stio->dirp)
+ closedir(stio->dirp);
+ if (!(stio->dirp = opendir(str_get(st[sp+1]))))
+ goto nope;
+ break;
+ case O_READDIR:
+ if (gimme == G_ARRAY) {
+ --sp;
+ /*SUPPRESS 560*/
+ while (dp = readdir(stio->dirp)) {
+#ifdef DIRNAMLEN
+ (void)astore(ary,++sp,
+ str_2mortal(str_make(dp->d_name,dp->d_namlen)));
+#else
+ (void)astore(ary,++sp,
+ str_2mortal(str_make(dp->d_name,0)));
+#endif
+ }
+ }
+ else {
+ if (!(dp = readdir(stio->dirp)))
+ goto nope;
+ st[sp] = str_mortal(&str_undef);
+#ifdef DIRNAMLEN
+ str_nset(st[sp], dp->d_name, dp->d_namlen);
+#else
+ str_set(st[sp], dp->d_name);
+#endif
+ }
+ break;
+#if defined(HAS_TELLDIR) || defined(telldir)
+ case O_TELLDIR: {
+#ifndef telldir
+ long telldir();
+#endif
+ st[sp] = str_mortal(&str_undef);
+ str_numset(st[sp], (double)telldir(stio->dirp));
+ break;
+ }
+#endif
+#if defined(HAS_SEEKDIR) || defined(seekdir)
+ case O_SEEKDIR:
+ st[sp] = str_mortal(&str_undef);
+ along = (long)str_gnum(st[sp+1]);
+ (void)seekdir(stio->dirp,along);
+ break;
+#endif
+#if defined(HAS_REWINDDIR) || defined(rewinddir)
+ case O_REWINDDIR:
+ st[sp] = str_mortal(&str_undef);
+ (void)rewinddir(stio->dirp);
+ break;
+#endif
+ case O_CLOSEDIR:
+ st[sp] = str_mortal(&str_undef);
+ (void)closedir(stio->dirp);
+ stio->dirp = 0;
+ break;
+ default:
+ goto phooey;
+ }
+ return sp;
+
+nope:
+ st[sp] = &str_undef;
+ if (!errno)
+ errno = EBADF;
+ return sp;
+
+#endif
+phooey:
+ fatal("Unimplemented directory operation");
+}
+
+int
+apply(type,arglast)
+int type;
+int *arglast;
+{
+ register STR **st = stack->ary_array;
+ register int sp = arglast[1];
+ register int items = arglast[2] - sp;
+ register int val;
+ register int val2;
+ register int tot = 0;
+ char *s;
+
+#ifdef TAINT
+ for (st += ++sp; items--; st++)
+ tainted |= (*st)->str_tainted;
+ st = stack->ary_array;
+ sp = arglast[1];
+ items = arglast[2] - sp;
+#endif
+ switch (type) {
+ case O_CHMOD:
+#ifdef TAINT
+ taintproper("Insecure dependency in chmod");
+#endif
+ if (--items > 0) {
+ tot = items;
+ val = (int)str_gnum(st[++sp]);
+ while (items--) {
+ if (chmod(str_get(st[++sp]),val))
+ tot--;
+ }
+ }
+ break;
+#ifdef HAS_CHOWN
+ case O_CHOWN:
+#ifdef TAINT
+ taintproper("Insecure dependency in chown");
+#endif
+ if (items > 2) {
+ items -= 2;
+ tot = items;
+ val = (int)str_gnum(st[++sp]);
+ val2 = (int)str_gnum(st[++sp]);
+ while (items--) {
+ if (chown(str_get(st[++sp]),val,val2))
+ tot--;
+ }
+ }
+ break;
+#endif
+#ifdef HAS_KILL
+ case O_KILL:
+#ifdef TAINT
+ taintproper("Insecure dependency in kill");
+#endif
+ if (--items > 0) {
+ tot = items;
+ s = str_get(st[++sp]);
+ if (isUPPER(*s)) {
+ if (*s == 'S' && s[1] == 'I' && s[2] == 'G')
+ s += 3;
+ if (!(val = whichsig(s)))
+ fatal("Unrecognized signal name \"%s\"",s);
+ }
+ else
+ val = (int)str_gnum(st[sp]);
+ if (val < 0) {
+ val = -val;
+ while (items--) {
+ int proc = (int)str_gnum(st[++sp]);
+#ifdef HAS_KILLPG
+ if (killpg(proc,val)) /* BSD */
+#else
+ if (kill(-proc,val)) /* SYSV */
+#endif
+ tot--;
+ }
+ }
+ else {
+ while (items--) {
+ if (kill((int)(str_gnum(st[++sp])),val))
+ tot--;
+ }
+ }
+ }
+ break;
+#endif
+ case O_UNLINK:
+#ifdef TAINT
+ taintproper("Insecure dependency in unlink");
+#endif
+ tot = items;
+ while (items--) {
+ s = str_get(st[++sp]);
+ if (euid || unsafe) {
+ if (UNLINK(s))
+ tot--;
+ }
+ else { /* don't let root wipe out directories without -U */
+#ifdef HAS_LSTAT
+ if (lstat(s,&statbuf) < 0 || S_ISDIR(statbuf.st_mode))
+#else
+ if (stat(s,&statbuf) < 0 || S_ISDIR(statbuf.st_mode))
+#endif
+ tot--;
+ else {
+ if (UNLINK(s))
+ tot--;
+ }
+ }
+ }
+ break;
+ case O_UTIME:
+#ifdef TAINT
+ taintproper("Insecure dependency in utime");
+#endif
+ if (items > 2) {
+#ifdef I_UTIME
+ struct utimbuf utbuf;
+#else
+ struct {
+ long actime;
+ long modtime;
+ } utbuf;
+#endif
+
+ Zero(&utbuf, sizeof utbuf, char);
+ utbuf.actime = (long)str_gnum(st[++sp]); /* time accessed */
+ utbuf.modtime = (long)str_gnum(st[++sp]); /* time modified */
+ items -= 2;
+#ifndef lint
+ tot = items;
+ while (items--) {
+ if (utime(str_get(st[++sp]),&utbuf))
+ tot--;
+ }
+#endif
+ }
+ else
+ items = 0;
+ break;
+ }
+ return tot;
+}
+
+/* Do the permissions allow some operation? Assumes statcache already set. */
+
+int
+cando(bit, effective, statbufp)
+int bit;
+int effective;
+register struct stat *statbufp;
+{
+#ifdef DOSISH
+ /* [Comments and code from Len Reed]
+ * MS-DOS "user" is similar to UNIX's "superuser," but can't write
+ * to write-protected files. The execute permission bit is set
+ * by the Miscrosoft C library stat() function for the following:
+ * .exe files
+ * .com files
+ * .bat files
+ * directories
+ * All files and directories are readable.
+ * Directories and special files, e.g. "CON", cannot be
+ * write-protected.
+ * [Comment by Tom Dinger -- a directory can have the write-protect
+ * bit set in the file system, but DOS permits changes to
+ * the directory anyway. In addition, all bets are off
+ * here for networked software, such as Novell and
+ * Sun's PC-NFS.]
+ */
+
+ /* Atari stat() does pretty much the same thing. we set x_bit_set_in_stat
+ * too so it will actually look into the files for magic numbers
+ */
+ return (bit & statbufp->st_mode) ? TRUE : FALSE;
+
+#else /* ! MSDOS */
+ if ((effective ? euid : uid) == 0) { /* root is special */
+ if (bit == S_IXUSR) {
+ if (statbufp->st_mode & 0111 || S_ISDIR(statbufp->st_mode))
+ return TRUE;
+ }
+ else
+ return TRUE; /* root reads and writes anything */
+ return FALSE;
+ }
+ if (statbufp->st_uid == (effective ? euid : uid) ) {
+ if (statbufp->st_mode & bit)
+ return TRUE; /* ok as "user" */
+ }
+ else if (ingroup((int)statbufp->st_gid,effective)) {
+ if (statbufp->st_mode & bit >> 3)
+ return TRUE; /* ok as "group" */
+ }
+ else if (statbufp->st_mode & bit >> 6)
+ return TRUE; /* ok as "other" */
+ return FALSE;
+#endif /* ! MSDOS */
+}
+
+int
+ingroup(testgid,effective)
+int testgid;
+int effective;
+{
+ if (testgid == (effective ? egid : gid))
+ return TRUE;
+#ifdef HAS_GETGROUPS
+#ifndef NGROUPS
+#define NGROUPS 32
+#endif
+ {
+ GROUPSTYPE gary[NGROUPS];
+ int anum;
+
+ anum = getgroups(NGROUPS,gary);
+ while (--anum >= 0)
+ if (gary[anum] == testgid)
+ return TRUE;
+ }
+#endif
+ return FALSE;
+}
+
+#if defined(HAS_MSG) || defined(HAS_SEM) || defined(HAS_SHM)
+
+int
+do_ipcget(optype, arglast)
+int optype;
+int *arglast;
+{
+ register STR **st = stack->ary_array;
+ register int sp = arglast[0];
+ key_t key;
+ int n, flags;
+
+ key = (key_t)str_gnum(st[++sp]);
+ n = (optype == O_MSGGET) ? 0 : (int)str_gnum(st[++sp]);
+ flags = (int)str_gnum(st[++sp]);
+ errno = 0;
+ switch (optype)
+ {
+#ifdef HAS_MSG
+ case O_MSGGET:
+ return msgget(key, flags);
+#endif
+#ifdef HAS_SEM
+ case O_SEMGET:
+ return semget(key, n, flags);
+#endif
+#ifdef HAS_SHM
+ case O_SHMGET:
+ return shmget(key, n, flags);
+#endif
+#if !defined(HAS_MSG) || !defined(HAS_SEM) || !defined(HAS_SHM)
+ default:
+ fatal("%s not implemented", opname[optype]);
+#endif
+ }
+ return -1; /* should never happen */
+}
+
+int
+do_ipcctl(optype, arglast)
+int optype;
+int *arglast;
+{
+ register STR **st = stack->ary_array;
+ register int sp = arglast[0];
+ STR *astr;
+ char *a;
+ int id, n, cmd, infosize, getinfo, ret;
+
+ id = (int)str_gnum(st[++sp]);
+ n = (optype == O_SEMCTL) ? (int)str_gnum(st[++sp]) : 0;
+ cmd = (int)str_gnum(st[++sp]);
+ astr = st[++sp];
+
+ infosize = 0;
+ getinfo = (cmd == IPC_STAT);
+
+ switch (optype)
+ {
+#ifdef HAS_MSG
+ case O_MSGCTL:
+ if (cmd == IPC_STAT || cmd == IPC_SET)
+ infosize = sizeof(struct msqid_ds);
+ break;
+#endif
+#ifdef HAS_SHM
+ case O_SHMCTL:
+ if (cmd == IPC_STAT || cmd == IPC_SET)
+ infosize = sizeof(struct shmid_ds);
+ break;
+#endif
+#ifdef HAS_SEM
+ case O_SEMCTL:
+ if (cmd == IPC_STAT || cmd == IPC_SET)
+ infosize = sizeof(struct semid_ds);
+ else if (cmd == GETALL || cmd == SETALL)
+ {
+ struct semid_ds semds;
+ if (semctl(id, 0, IPC_STAT, (union semun)&semds) == -1)
+ return -1;
+ getinfo = (cmd == GETALL);
+ infosize = semds.sem_nsems * sizeof(short);
+ /* "short" is technically wrong but much more portable
+ than guessing about u_?short(_t)? */
+ }
+ break;
+#endif
+#if !defined(HAS_MSG) || !defined(HAS_SEM) || !defined(HAS_SHM)
+ default:
+ fatal("%s not implemented", opname[optype]);
+#endif
+ }
+
+ if (infosize)
+ {
+ if (getinfo)
+ {
+ STR_GROW(astr, infosize+1);
+ a = str_get(astr);
+ }
+ else
+ {
+ a = str_get(astr);
+ if (astr->str_cur != infosize)
+ {
+ errno = EINVAL;
+ return -1;
+ }
+ }
+ }
+ else
+ {
+ int i = (int)str_gnum(astr);
+ a = (char *)i; /* ouch */
+ }
+ errno = 0;
+ switch (optype)
+ {
+#ifdef HAS_MSG
+ case O_MSGCTL:
+ ret = msgctl(id, cmd, (struct msqid_ds *)a);
+ break;
+#endif
+#ifdef HAS_SEM
+ case O_SEMCTL:
+ ret = semctl(id, n, cmd, (union semun)((int)a));
+ break;
+#endif
+#ifdef HAS_SHM
+ case O_SHMCTL:
+ ret = shmctl(id, cmd, (struct shmid_ds *)a);
+ break;
+#endif
+ }
+ if (getinfo && ret >= 0) {
+ astr->str_cur = infosize;
+ astr->str_ptr[infosize] = '\0';
+ }
+ return ret;
+}
+
+int
+do_msgsnd(arglast)
+int *arglast;
+{
+#ifdef HAS_MSG
+ register STR **st = stack->ary_array;
+ register int sp = arglast[0];
+ STR *mstr;
+ char *mbuf;
+ int id, msize, flags;
+
+ id = (int)str_gnum(st[++sp]);
+ mstr = st[++sp];
+ flags = (int)str_gnum(st[++sp]);
+ mbuf = str_get(mstr);
+ if ((msize = mstr->str_cur - sizeof(long)) < 0) {
+ errno = EINVAL;
+ return -1;
+ }
+ errno = 0;
+ return msgsnd(id, (struct msgbuf *)mbuf, msize, flags);
+#else
+ fatal("msgsnd not implemented");
+#endif
+}
+
+int
+do_msgrcv(arglast)
+int *arglast;
+{
+#ifdef HAS_MSG
+ register STR **st = stack->ary_array;
+ register int sp = arglast[0];
+ STR *mstr;
+ char *mbuf;
+ long mtype;
+ int id, msize, flags, ret;
+
+ id = (int)str_gnum(st[++sp]);
+ mstr = st[++sp];
+ msize = (int)str_gnum(st[++sp]);
+ mtype = (long)str_gnum(st[++sp]);
+ flags = (int)str_gnum(st[++sp]);
+ mbuf = str_get(mstr);
+ if (mstr->str_cur < sizeof(long)+msize+1) {
+ STR_GROW(mstr, sizeof(long)+msize+1);
+ mbuf = str_get(mstr);
+ }
+ errno = 0;
+ ret = msgrcv(id, (struct msgbuf *)mbuf, msize, mtype, flags);
+ if (ret >= 0) {
+ mstr->str_cur = sizeof(long)+ret;
+ mstr->str_ptr[sizeof(long)+ret] = '\0';
+ }
+ return ret;
+#else
+ fatal("msgrcv not implemented");
+#endif
+}
+
+int
+do_semop(arglast)
+int *arglast;
+{
+#ifdef HAS_SEM
+ register STR **st = stack->ary_array;
+ register int sp = arglast[0];
+ STR *opstr;
+ char *opbuf;
+ int id, opsize;
+
+ id = (int)str_gnum(st[++sp]);
+ opstr = st[++sp];
+ opbuf = str_get(opstr);
+ opsize = opstr->str_cur;
+ if (opsize < sizeof(struct sembuf)
+ || (opsize % sizeof(struct sembuf)) != 0) {
+ errno = EINVAL;
+ return -1;
+ }
+ errno = 0;
+ return semop(id, (struct sembuf *)opbuf, opsize/sizeof(struct sembuf));
+#else
+ fatal("semop not implemented");
+#endif
+}
+
+int
+do_shmio(optype, arglast)
+int optype;
+int *arglast;
+{
+#ifdef HAS_SHM
+ register STR **st = stack->ary_array;
+ register int sp = arglast[0];
+ STR *mstr;
+ char *mbuf, *shm;
+ int id, mpos, msize;
+ struct shmid_ds shmds;
+#ifndef VOIDSHMAT
+ extern char *shmat();
+#endif
+
+ id = (int)str_gnum(st[++sp]);
+ mstr = st[++sp];
+ mpos = (int)str_gnum(st[++sp]);
+ msize = (int)str_gnum(st[++sp]);
+ errno = 0;
+ if (shmctl(id, IPC_STAT, &shmds) == -1)
+ return -1;
+ if (mpos < 0 || msize < 0 || mpos + msize > shmds.shm_segsz) {
+ errno = EFAULT; /* can't do as caller requested */
+ return -1;
+ }
+ shm = (char*)shmat(id, (char*)NULL, (optype == O_SHMREAD) ? SHM_RDONLY : 0);
+ if (shm == (char *)-1) /* I hate System V IPC, I really do */
+ return -1;
+ mbuf = str_get(mstr);
+ if (optype == O_SHMREAD) {
+ if (mstr->str_cur < msize) {
+ STR_GROW(mstr, msize+1);
+ mbuf = str_get(mstr);
+ }
+ Copy(shm + mpos, mbuf, msize, char);
+ mstr->str_cur = msize;
+ mstr->str_ptr[msize] = '\0';
+ }
+ else {
+ int n;
+
+ if ((n = mstr->str_cur) > msize)
+ n = msize;
+ Copy(mbuf, shm + mpos, n, char);
+ if (n < msize)
+ memzero(shm + mpos + n, msize - n);
+ }
+ return shmdt(shm);
+#else
+ fatal("shm I/O not implemented");
+#endif
+}
+
+#endif /* SYSV IPC */
diff --git a/gnu/usr.bin/perl/perl/toke.c b/gnu/usr.bin/perl/perl/toke.c
new file mode 100644
index 0000000..bf2e116
--- /dev/null
+++ b/gnu/usr.bin/perl/perl/toke.c
@@ -0,0 +1,2767 @@
+/* $RCSfile: toke.c,v $$Revision: 1.1.1.1 $$Date: 1994/09/10 06:27:34 $
+ *
+ * Copyright (c) 1991, Larry Wall
+ *
+ * You may distribute under the terms of either the GNU General Public
+ * License or the Artistic License, as specified in the README file.
+ *
+ * $Log: toke.c,v $
+ * Revision 1.1.1.1 1994/09/10 06:27:34 gclarkii
+ * Initial import of Perl 4.046 bmaked
+ *
+ * Revision 1.1.1.1 1993/08/23 21:29:40 nate
+ * PERL!
+ *
+ * Revision 4.0.1.9 1993/02/05 19:48:43 lwall
+ * patch36: now detects ambiguous use of filetest operators as well as unary
+ * patch36: fixed ambiguity on - within tr///
+ *
+ * Revision 4.0.1.8 92/06/23 12:33:45 lwall
+ * patch35: bad interaction between backslash and hyphen in tr///
+ *
+ * Revision 4.0.1.7 92/06/11 21:16:30 lwall
+ * patch34: expectterm incorrectly set to indicate start of program or block
+ *
+ * Revision 4.0.1.6 92/06/08 16:03:49 lwall
+ * patch20: an EXPR may now start with a bareword
+ * patch20: print $fh EXPR can now expect term rather than operator in EXPR
+ * patch20: added ... as variant on ..
+ * patch20: new warning on spurious backslash
+ * patch20: new warning on missing $ for foreach variable
+ * patch20: "foo"x1024 now legal without space after x
+ * patch20: new warning on print accidentally used as function
+ * patch20: tr/stuff// wasn't working right
+ * patch20: 2. now eats the dot
+ * patch20: <@ARGV> now notices @ARGV
+ * patch20: tr/// now lets you say \-
+ *
+ * Revision 4.0.1.5 91/11/11 16:45:51 lwall
+ * patch19: default arg for shift was wrong after first subroutine definition
+ *
+ * Revision 4.0.1.4 91/11/05 19:02:48 lwall
+ * patch11: \x and \c were subject to double interpretation in regexps
+ * patch11: prepared for ctype implementations that don't define isascii()
+ * patch11: nested list operators could miscount parens
+ * patch11: once-thru blocks didn't display right in the debugger
+ * patch11: sort eval "whatever" didn't work
+ * patch11: underscore is now allowed within literal octal and hex numbers
+ *
+ * Revision 4.0.1.3 91/06/10 01:32:26 lwall
+ * patch10: m'$foo' now treats string as single quoted
+ * patch10: certain pattern optimizations were botched
+ *
+ * Revision 4.0.1.2 91/06/07 12:05:56 lwall
+ * patch4: new copyright notice
+ * patch4: debugger lost track of lines in eval
+ * patch4: //o and s///o now optimize themselves fully at runtime
+ * patch4: added global modifier for pattern matches
+ *
+ * Revision 4.0.1.1 91/04/12 09:18:18 lwall
+ * patch1: perl -de "print" wouldn't stop at the first statement
+ *
+ * Revision 4.0 91/03/20 01:42:14 lwall
+ * 4.0 baseline.
+ *
+ */
+
+#include "EXTERN.h"
+#include "perl.h"
+#include "perly.h"
+
+static void set_csh();
+
+#ifdef I_FCNTL
+#include <fcntl.h>
+#endif
+#ifdef I_SYS_FILE
+#include <sys/file.h>
+#endif
+
+#ifdef f_next
+#undef f_next
+#endif
+
+/* which backslash sequences to keep in m// or s// */
+
+static char *patleave = "\\.^$@dDwWsSbB+*?|()-nrtfeaxc0123456789[{]}";
+
+char *reparse; /* if non-null, scanident found ${foo[$bar]} */
+
+void checkcomma();
+
+#ifdef CLINE
+#undef CLINE
+#endif
+#define CLINE (cmdline = (curcmd->c_line < cmdline ? curcmd->c_line : cmdline))
+
+#ifdef atarist
+#define PERL_META(c) ((c) | 128)
+#else
+#define META(c) ((c) | 128)
+#endif
+
+#define RETURN(retval) return (bufptr = s,(int)retval)
+#define OPERATOR(retval) return (expectterm = TRUE,bufptr = s,(int)retval)
+#define TERM(retval) return (CLINE, expectterm = FALSE,bufptr = s,(int)retval)
+#define LOOPX(f) return(yylval.ival=f,expectterm = FALSE,bufptr = s,(int)LOOPEX)
+#define FTST(f) return(yylval.ival=f,expectterm = TRUE,bufptr = s,(int)FILETEST)
+#define FUN0(f) return(yylval.ival = f,expectterm = FALSE,bufptr = s,(int)FUNC0)
+#define FUN1(f) return(yylval.ival = f,expectterm = FALSE,bufptr = s,(int)FUNC1)
+#define FUN2(f) return(yylval.ival = f,expectterm = FALSE,bufptr = s,(int)FUNC2)
+#define FUN2x(f) return(yylval.ival = f,expectterm = FALSE,bufptr = s,(int)FUNC2x)
+#define FUN3(f) return(yylval.ival = f,expectterm = FALSE,bufptr = s,(int)FUNC3)
+#define FUN4(f) return(yylval.ival = f,expectterm = FALSE,bufptr = s,(int)FUNC4)
+#define FUN5(f) return(yylval.ival = f,expectterm = FALSE,bufptr = s,(int)FUNC5)
+#define FL(f) return(yylval.ival=f,expectterm = FALSE,bufptr = s,(int)FLIST)
+#define FL2(f) return(yylval.ival=f,expectterm = FALSE,bufptr = s,(int)FLIST2)
+#define HFUN(f) return(yylval.ival=f,expectterm = TRUE,bufptr = s,(int)HSHFUN)
+#define HFUN3(f) return(yylval.ival=f,expectterm = FALSE,bufptr = s,(int)HSHFUN3)
+#define LFUN(f) return(yylval.ival=f,expectterm = TRUE,bufptr = s,(int)LVALFUN)
+#define AOP(f) return(yylval.ival=f,expectterm = TRUE,bufptr = s,(int)ADDOP)
+#define MOP(f) return(yylval.ival=f,expectterm = TRUE,bufptr = s,(int)MULOP)
+#define EOP(f) return(yylval.ival=f,expectterm = TRUE,bufptr = s,(int)EQOP)
+#define ROP(f) return(yylval.ival=f,expectterm = TRUE,bufptr = s,(int)RELOP)
+#define FOP(f) return(yylval.ival=f,expectterm = FALSE,bufptr = s,(int)FILOP)
+#define FOP2(f) return(yylval.ival=f,expectterm = FALSE,bufptr = s,(int)FILOP2)
+#define FOP3(f) return(yylval.ival=f,expectterm = FALSE,bufptr = s,(int)FILOP3)
+#define FOP4(f) return(yylval.ival=f,expectterm = FALSE,bufptr = s,(int)FILOP4)
+#define FOP22(f) return(yylval.ival=f,expectterm = FALSE,bufptr = s,(int)FILOP22)
+#define FOP25(f) return(yylval.ival=f,expectterm = FALSE,bufptr = s,(int)FILOP25)
+
+static char *last_uni;
+
+/* This bit of chicanery makes a unary function followed by
+ * a parenthesis into a function with one argument, highest precedence.
+ */
+#define UNI(f) return(yylval.ival = f, \
+ expectterm = TRUE, \
+ bufptr = s, \
+ last_uni = oldbufptr, \
+ (*s == '(' || (s = skipspace(s), *s == '(') ? (int)FUNC1 : (int)UNIOP) )
+
+/* This does similarly for list operators, merely by pretending that the
+ * paren came before the listop rather than after.
+ */
+#ifdef atarist
+#define LOP(f) return(CLINE, *s == '(' || (s = skipspace(s), *s == '(') ? \
+ (*s = (char) PERL_META('('), bufptr = oldbufptr, '(') : \
+ (yylval.ival=f,expectterm = TRUE,bufptr = s,(int)LISTOP))
+#else
+#define LOP(f) return(CLINE, *s == '(' || (s = skipspace(s), *s == '(') ? \
+ (*s = (char) META('('), bufptr = oldbufptr, '(') : \
+ (yylval.ival=f,expectterm = TRUE,bufptr = s,(int)LISTOP))
+#endif
+/* grandfather return to old style */
+#define OLDLOP(f) return(yylval.ival=f,expectterm = TRUE,bufptr = s,(int)LISTOP)
+
+char *
+skipspace(s)
+register char *s;
+{
+ while (s < bufend && isSPACE(*s))
+ s++;
+ return s;
+}
+
+void
+check_uni() {
+ char *s;
+ char ch;
+
+ if (oldoldbufptr != last_uni)
+ return;
+ while (isSPACE(*last_uni))
+ last_uni++;
+ for (s = last_uni; isALNUM(*s) || *s == '-'; s++) ;
+ ch = *s;
+ *s = '\0';
+ warn("Warning: Use of \"%s\" without parens is ambiguous", last_uni);
+ *s = ch;
+}
+
+#ifdef CRIPPLED_CC
+
+#undef UNI
+#undef LOP
+#define UNI(f) return uni(f,s)
+#define LOP(f) return lop(f,s)
+
+int
+uni(f,s)
+int f;
+char *s;
+{
+ yylval.ival = f;
+ expectterm = TRUE;
+ bufptr = s;
+ last_uni = oldbufptr;
+ if (*s == '(')
+ return FUNC1;
+ s = skipspace(s);
+ if (*s == '(')
+ return FUNC1;
+ else
+ return UNIOP;
+}
+
+int
+lop(f,s)
+int f;
+char *s;
+{
+ CLINE;
+ if (*s != '(')
+ s = skipspace(s);
+ if (*s == '(') {
+#ifdef atarist
+ *s = PERL_META('(');
+#else
+ *s = META('(');
+#endif
+ bufptr = oldbufptr;
+ return '(';
+ }
+ else {
+ yylval.ival=f;
+ expectterm = TRUE;
+ bufptr = s;
+ return LISTOP;
+ }
+}
+
+#endif /* CRIPPLED_CC */
+
+int
+yylex()
+{
+ register char *s = bufptr;
+ register char *d;
+ register int tmp;
+ static bool in_format = FALSE;
+ static bool firstline = TRUE;
+ extern int yychar; /* last token */
+
+ oldoldbufptr = oldbufptr;
+ oldbufptr = s;
+
+ retry:
+#ifdef YYDEBUG
+ if (debug & 1)
+ if (index(s,'\n'))
+ fprintf(stderr,"Tokener at %s",s);
+ else
+ fprintf(stderr,"Tokener at %s\n",s);
+#endif
+#ifdef BADSWITCH
+ if (*s & 128) {
+ if ((*s & 127) == '(') {
+ *s++ = '(';
+ oldbufptr = s;
+ }
+ else if ((*s & 127) == '}') {
+ *s++ = '}';
+ RETURN('}');
+ }
+ else
+ warn("Unrecognized character \\%03o ignored", *s++ & 255);
+ goto retry;
+ }
+#endif
+ switch (*s) {
+ default:
+ if ((*s & 127) == '(') {
+ *s++ = '(';
+ oldbufptr = s;
+ }
+ else if ((*s & 127) == '}') {
+ *s++ = '}';
+ RETURN('}');
+ }
+ else
+ warn("Unrecognized character \\%03o ignored", *s++ & 255);
+ goto retry;
+ case 4:
+ case 26:
+ goto fake_eof; /* emulate EOF on ^D or ^Z */
+ case 0:
+ if (!rsfp)
+ RETURN(0);
+ if (s++ < bufend)
+ goto retry; /* ignore stray nulls */
+ last_uni = 0;
+ if (firstline) {
+ firstline = FALSE;
+ if (minus_n || minus_p || perldb) {
+ str_set(linestr,"");
+ if (perldb) {
+ char *getenv();
+ char *pdb = getenv("PERLDB");
+
+ str_cat(linestr, pdb ? pdb : "require 'perldb.pl'");
+ str_cat(linestr, ";");
+ }
+ if (minus_n || minus_p) {
+ str_cat(linestr,"line: while (<>) {");
+ if (minus_l)
+ str_cat(linestr,"chop;");
+ if (minus_a)
+ str_cat(linestr,"@F=split(' ');");
+ }
+ oldoldbufptr = oldbufptr = s = str_get(linestr);
+ bufend = linestr->str_ptr + linestr->str_cur;
+ goto retry;
+ }
+ }
+ if (in_format) {
+ bufptr = bufend;
+ yylval.formval = load_format();
+ in_format = FALSE;
+ oldoldbufptr = oldbufptr = s = str_get(linestr) + 1;
+ bufend = linestr->str_ptr + linestr->str_cur;
+ OPERATOR(FORMLIST);
+ }
+ curcmd->c_line++;
+#ifdef CRYPTSCRIPT
+ cryptswitch();
+#endif /* CRYPTSCRIPT */
+ do {
+ if ((s = str_gets(linestr, rsfp, 0)) == Nullch) {
+ fake_eof:
+ if (rsfp) {
+ if (preprocess)
+ (void)mypclose(rsfp);
+ else if ((FILE*)rsfp == stdin)
+ clearerr(stdin);
+ else
+ (void)fclose(rsfp);
+ rsfp = Nullfp;
+ }
+ if (minus_n || minus_p) {
+ str_set(linestr,minus_p ? ";}continue{print" : "");
+ str_cat(linestr,";}");
+ oldoldbufptr = oldbufptr = s = str_get(linestr);
+ bufend = linestr->str_ptr + linestr->str_cur;
+ minus_n = minus_p = 0;
+ goto retry;
+ }
+ oldoldbufptr = oldbufptr = s = str_get(linestr);
+ str_set(linestr,"");
+ RETURN(';'); /* not infinite loop because rsfp is NULL now */
+ }
+ if (doextract && *linestr->str_ptr == '#')
+ doextract = FALSE;
+ } while (doextract);
+ oldoldbufptr = oldbufptr = bufptr = s;
+ if (perldb) {
+ STR *str = Str_new(85,0);
+
+ str_sset(str,linestr);
+ astore(stab_xarray(curcmd->c_filestab),(int)curcmd->c_line,str);
+ }
+#ifdef DEBUG
+ if (firstline) {
+ char *showinput();
+ s = showinput();
+ }
+#endif
+ bufend = linestr->str_ptr + linestr->str_cur;
+ if (curcmd->c_line == 1) {
+ if (*s == '#' && s[1] == '!') {
+ if (!in_eval && !instr(s,"perl") && instr(origargv[0],"perl")) {
+ char **newargv;
+ char *cmd;
+
+ s += 2;
+ if (*s == ' ')
+ s++;
+ cmd = s;
+ while (s < bufend && !isSPACE(*s))
+ s++;
+ *s++ = '\0';
+ while (s < bufend && isSPACE(*s))
+ s++;
+ if (s < bufend) {
+ Newz(899,newargv,origargc+3,char*);
+ newargv[1] = s;
+ while (s < bufend && !isSPACE(*s))
+ s++;
+ *s = '\0';
+ Copy(origargv+1, newargv+2, origargc+1, char*);
+ }
+ else
+ newargv = origargv;
+ newargv[0] = cmd;
+ execv(cmd,newargv);
+ fatal("Can't exec %s", cmd);
+ }
+ }
+ else {
+ while (s < bufend && isSPACE(*s))
+ s++;
+ if (*s == ':') /* for csh's that have to exec sh scripts */
+ s++;
+ }
+ }
+ goto retry;
+ case ' ': case '\t': case '\f': case '\r': case 013:
+ s++;
+ goto retry;
+ case '#':
+ if (preprocess && s == str_get(linestr) &&
+ s[1] == ' ' && (isDIGIT(s[2]) || strnEQ(s+2,"line ",5)) ) {
+ while (*s && !isDIGIT(*s))
+ s++;
+ curcmd->c_line = atoi(s)-1;
+ while (isDIGIT(*s))
+ s++;
+ d = bufend;
+ while (s < d && isSPACE(*s)) s++;
+ s[strlen(s)-1] = '\0'; /* wipe out newline */
+ if (*s == '"') {
+ s++;
+ s[strlen(s)-1] = '\0'; /* wipe out trailing quote */
+ }
+ if (*s)
+ curcmd->c_filestab = fstab(s);
+ else
+ curcmd->c_filestab = fstab(origfilename);
+ oldoldbufptr = oldbufptr = s = str_get(linestr);
+ }
+ /* FALL THROUGH */
+ case '\n':
+ if (in_eval && !rsfp) {
+ d = bufend;
+ while (s < d && *s != '\n')
+ s++;
+ if (s < d)
+ s++;
+ if (in_format) {
+ bufptr = s;
+ yylval.formval = load_format();
+ in_format = FALSE;
+ oldoldbufptr = oldbufptr = s = bufptr + 1;
+ TERM(FORMLIST);
+ }
+ curcmd->c_line++;
+ }
+ else {
+ *s = '\0';
+ bufend = s;
+ }
+ goto retry;
+ case '-':
+ if (s[1] && isALPHA(s[1]) && !isALPHA(s[2])) {
+ s++;
+ last_uni = oldbufptr;
+ switch (*s++) {
+ case 'r': FTST(O_FTEREAD);
+ case 'w': FTST(O_FTEWRITE);
+ case 'x': FTST(O_FTEEXEC);
+ case 'o': FTST(O_FTEOWNED);
+ case 'R': FTST(O_FTRREAD);
+ case 'W': FTST(O_FTRWRITE);
+ case 'X': FTST(O_FTREXEC);
+ case 'O': FTST(O_FTROWNED);
+ case 'e': FTST(O_FTIS);
+ case 'z': FTST(O_FTZERO);
+ case 's': FTST(O_FTSIZE);
+ case 'f': FTST(O_FTFILE);
+ case 'd': FTST(O_FTDIR);
+ case 'l': FTST(O_FTLINK);
+ case 'p': FTST(O_FTPIPE);
+ case 'S': FTST(O_FTSOCK);
+ case 'u': FTST(O_FTSUID);
+ case 'g': FTST(O_FTSGID);
+ case 'k': FTST(O_FTSVTX);
+ case 'b': FTST(O_FTBLK);
+ case 'c': FTST(O_FTCHR);
+ case 't': FTST(O_FTTTY);
+ case 'T': FTST(O_FTTEXT);
+ case 'B': FTST(O_FTBINARY);
+ case 'M': stabent("\024",TRUE); FTST(O_FTMTIME);
+ case 'A': stabent("\024",TRUE); FTST(O_FTATIME);
+ case 'C': stabent("\024",TRUE); FTST(O_FTCTIME);
+ default:
+ s -= 2;
+ break;
+ }
+ }
+ tmp = *s++;
+ if (*s == tmp) {
+ s++;
+ RETURN(DEC);
+ }
+ if (expectterm) {
+ if (isSPACE(*s) || !isSPACE(*bufptr))
+ check_uni();
+ OPERATOR('-');
+ }
+ else
+ AOP(O_SUBTRACT);
+ case '+':
+ tmp = *s++;
+ if (*s == tmp) {
+ s++;
+ RETURN(INC);
+ }
+ if (expectterm) {
+ if (isSPACE(*s) || !isSPACE(*bufptr))
+ check_uni();
+ OPERATOR('+');
+ }
+ else
+ AOP(O_ADD);
+
+ case '*':
+ if (expectterm) {
+ check_uni();
+ s = scanident(s,bufend,tokenbuf);
+ yylval.stabval = stabent(tokenbuf,TRUE);
+ TERM(STAR);
+ }
+ tmp = *s++;
+ if (*s == tmp) {
+ s++;
+ OPERATOR(POW);
+ }
+ MOP(O_MULTIPLY);
+ case '%':
+ if (expectterm) {
+ if (!isALPHA(s[1]))
+ check_uni();
+ s = scanident(s,bufend,tokenbuf);
+ yylval.stabval = hadd(stabent(tokenbuf,TRUE));
+ TERM(HSH);
+ }
+ s++;
+ MOP(O_MODULO);
+
+ case '^':
+ case '~':
+ case '(':
+ case ',':
+ case ':':
+ case '[':
+ tmp = *s++;
+ OPERATOR(tmp);
+ case '{':
+ tmp = *s++;
+ yylval.ival = curcmd->c_line;
+ if (isSPACE(*s) || *s == '#')
+ cmdline = NOLINE; /* invalidate current command line number */
+ expectterm = 2;
+ RETURN(tmp);
+ case ';':
+ if (curcmd->c_line < cmdline)
+ cmdline = curcmd->c_line;
+ tmp = *s++;
+ OPERATOR(tmp);
+ case ')':
+ case ']':
+ tmp = *s++;
+ TERM(tmp);
+ case '}':
+ *s |= 128;
+ RETURN(';');
+ case '&':
+ s++;
+ tmp = *s++;
+ if (tmp == '&')
+ OPERATOR(ANDAND);
+ s--;
+ if (expectterm) {
+ d = bufend;
+ while (s < d && isSPACE(*s))
+ s++;
+ if (isALPHA(*s) || *s == '_' || *s == '\'')
+ *(--s) = '\\'; /* force next ident to WORD */
+ else
+ check_uni();
+ OPERATOR(AMPER);
+ }
+ OPERATOR('&');
+ case '|':
+ s++;
+ tmp = *s++;
+ if (tmp == '|')
+ OPERATOR(OROR);
+ s--;
+ OPERATOR('|');
+ case '=':
+ s++;
+ tmp = *s++;
+ if (tmp == '=')
+ EOP(O_EQ);
+ if (tmp == '~')
+ OPERATOR(MATCH);
+ s--;
+ OPERATOR('=');
+ case '!':
+ s++;
+ tmp = *s++;
+ if (tmp == '=')
+ EOP(O_NE);
+ if (tmp == '~')
+ OPERATOR(NMATCH);
+ s--;
+ OPERATOR('!');
+ case '<':
+ if (expectterm) {
+ if (s[1] != '<' && !index(s,'>'))
+ check_uni();
+ s = scanstr(s, SCAN_DEF);
+ TERM(RSTRING);
+ }
+ s++;
+ tmp = *s++;
+ if (tmp == '<')
+ OPERATOR(LS);
+ if (tmp == '=') {
+ tmp = *s++;
+ if (tmp == '>')
+ EOP(O_NCMP);
+ s--;
+ ROP(O_LE);
+ }
+ s--;
+ ROP(O_LT);
+ case '>':
+ s++;
+ tmp = *s++;
+ if (tmp == '>')
+ OPERATOR(RS);
+ if (tmp == '=')
+ ROP(O_GE);
+ s--;
+ ROP(O_GT);
+
+#define SNARFWORD \
+ d = tokenbuf; \
+ while (isALNUM(*s) || *s == '\'') \
+ *d++ = *s++; \
+ while (d[-1] == '\'') \
+ d--,s--; \
+ *d = '\0'; \
+ d = tokenbuf;
+
+ case '$':
+ if (s[1] == '#' && (isALPHA(s[2]) || s[2] == '_')) {
+ s++;
+ s = scanident(s,bufend,tokenbuf);
+ yylval.stabval = aadd(stabent(tokenbuf,TRUE));
+ TERM(ARYLEN);
+ }
+ d = s;
+ s = scanident(s,bufend,tokenbuf);
+ if (reparse) { /* turn ${foo[bar]} into ($foo[bar]) */
+ do_reparse:
+ s[-1] = ')';
+ s = d;
+ s[1] = s[0];
+ s[0] = '(';
+ goto retry;
+ }
+ yylval.stabval = stabent(tokenbuf,TRUE);
+ expectterm = FALSE;
+ if (isSPACE(*s) && oldoldbufptr && oldoldbufptr < bufptr) {
+ s++;
+ while (isSPACE(*oldoldbufptr))
+ oldoldbufptr++;
+ if (*oldoldbufptr == 'p' && strnEQ(oldoldbufptr,"print",5)) {
+ if (index("&*<%", *s) && isALPHA(s[1]))
+ expectterm = TRUE; /* e.g. print $fh &sub */
+ else if (*s == '.' && isDIGIT(s[1]))
+ expectterm = TRUE; /* e.g. print $fh .3 */
+ else if (index("/?-+", *s) && !isSPACE(s[1]))
+ expectterm = TRUE; /* e.g. print $fh -1 */
+ }
+ }
+ RETURN(REG);
+
+ case '@':
+ d = s;
+ s = scanident(s,bufend,tokenbuf);
+ if (reparse)
+ goto do_reparse;
+ yylval.stabval = aadd(stabent(tokenbuf,TRUE));
+ TERM(ARY);
+
+ case '/': /* may either be division or pattern */
+ case '?': /* may either be conditional or pattern */
+ if (expectterm) {
+ check_uni();
+ s = scanpat(s);
+ TERM(PATTERN);
+ }
+ tmp = *s++;
+ if (tmp == '/')
+ MOP(O_DIVIDE);
+ OPERATOR(tmp);
+
+ case '.':
+ if (!expectterm || !isDIGIT(s[1])) {
+ tmp = *s++;
+ if (*s == tmp) {
+ s++;
+ if (*s == tmp) {
+ s++;
+ yylval.ival = 0;
+ }
+ else
+ yylval.ival = AF_COMMON;
+ OPERATOR(DOTDOT);
+ }
+ if (expectterm)
+ check_uni();
+ AOP(O_CONCAT);
+ }
+ /* FALL THROUGH */
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ case '\'': case '"': case '`':
+ s = scanstr(s, SCAN_DEF);
+ TERM(RSTRING);
+
+ case '\\': /* some magic to force next word to be a WORD */
+ s++; /* used by do and sub to force a separate namespace */
+ if (!isALPHA(*s) && *s != '_' && *s != '\'') {
+ warn("Spurious backslash ignored");
+ goto retry;
+ }
+ /* FALL THROUGH */
+ case '_':
+ SNARFWORD;
+ if (d[1] == '_') {
+ if (strEQ(d,"__LINE__") || strEQ(d,"__FILE__")) {
+ ARG *arg = op_new(1);
+
+ yylval.arg = arg;
+ arg->arg_type = O_ITEM;
+ if (d[2] == 'L')
+ (void)sprintf(tokenbuf,"%ld",(long)curcmd->c_line);
+ else
+ strcpy(tokenbuf, stab_val(curcmd->c_filestab)->str_ptr);
+ arg[1].arg_type = A_SINGLE;
+ arg[1].arg_ptr.arg_str = str_make(tokenbuf,strlen(tokenbuf));
+ TERM(RSTRING);
+ }
+ else if (strEQ(d,"__END__")) {
+ STAB *stab;
+ int fd;
+
+ /*SUPPRESS 560*/
+ if (!in_eval && (stab = stabent("DATA",FALSE))) {
+ stab->str_pok |= SP_MULTI;
+ if (!stab_io(stab))
+ stab_io(stab) = stio_new();
+ stab_io(stab)->ifp = rsfp;
+#if defined(HAS_FCNTL) && defined(F_SETFD)
+ fd = fileno(rsfp);
+ fcntl(fd,F_SETFD,fd >= 3);
+#endif
+ if (preprocess)
+ stab_io(stab)->type = '|';
+ else if ((FILE*)rsfp == stdin)
+ stab_io(stab)->type = '-';
+ else
+ stab_io(stab)->type = '<';
+ rsfp = Nullfp;
+ }
+ goto fake_eof;
+ }
+ }
+ break;
+ case 'a': case 'A':
+ SNARFWORD;
+ if (strEQ(d,"alarm"))
+ UNI(O_ALARM);
+ if (strEQ(d,"accept"))
+ FOP22(O_ACCEPT);
+ if (strEQ(d,"atan2"))
+ FUN2(O_ATAN2);
+ break;
+ case 'b': case 'B':
+ SNARFWORD;
+ if (strEQ(d,"bind"))
+ FOP2(O_BIND);
+ if (strEQ(d,"binmode"))
+ FOP(O_BINMODE);
+ break;
+ case 'c': case 'C':
+ SNARFWORD;
+ if (strEQ(d,"chop"))
+ LFUN(O_CHOP);
+ if (strEQ(d,"continue"))
+ OPERATOR(CONTINUE);
+ if (strEQ(d,"chdir")) {
+ (void)stabent("ENV",TRUE); /* may use HOME */
+ UNI(O_CHDIR);
+ }
+ if (strEQ(d,"close"))
+ FOP(O_CLOSE);
+ if (strEQ(d,"closedir"))
+ FOP(O_CLOSEDIR);
+ if (strEQ(d,"cmp"))
+ EOP(O_SCMP);
+ if (strEQ(d,"caller"))
+ UNI(O_CALLER);
+ if (strEQ(d,"crypt")) {
+#ifdef FCRYPT
+ static int cryptseen = 0;
+
+ if (!cryptseen++)
+ init_des();
+#endif
+ FUN2(O_CRYPT);
+ }
+ if (strEQ(d,"chmod"))
+ LOP(O_CHMOD);
+ if (strEQ(d,"chown"))
+ LOP(O_CHOWN);
+ if (strEQ(d,"connect"))
+ FOP2(O_CONNECT);
+ if (strEQ(d,"cos"))
+ UNI(O_COS);
+ if (strEQ(d,"chroot"))
+ UNI(O_CHROOT);
+ break;
+ case 'd': case 'D':
+ SNARFWORD;
+ if (strEQ(d,"do")) {
+ d = bufend;
+ while (s < d && isSPACE(*s))
+ s++;
+ if (isALPHA(*s) || *s == '_')
+ *(--s) = '\\'; /* force next ident to WORD */
+ OPERATOR(DO);
+ }
+ if (strEQ(d,"die"))
+ LOP(O_DIE);
+ if (strEQ(d,"defined"))
+ LFUN(O_DEFINED);
+ if (strEQ(d,"delete"))
+ OPERATOR(DELETE);
+ if (strEQ(d,"dbmopen"))
+ HFUN3(O_DBMOPEN);
+ if (strEQ(d,"dbmclose"))
+ HFUN(O_DBMCLOSE);
+ if (strEQ(d,"dump"))
+ LOOPX(O_DUMP);
+ break;
+ case 'e': case 'E':
+ SNARFWORD;
+ if (strEQ(d,"else"))
+ OPERATOR(ELSE);
+ if (strEQ(d,"elsif")) {
+ yylval.ival = curcmd->c_line;
+ OPERATOR(ELSIF);
+ }
+ if (strEQ(d,"eq") || strEQ(d,"EQ"))
+ EOP(O_SEQ);
+ if (strEQ(d,"exit"))
+ UNI(O_EXIT);
+ if (strEQ(d,"eval")) {
+ allstabs = TRUE; /* must initialize everything since */
+ UNI(O_EVAL); /* we don't know what will be used */
+ }
+ if (strEQ(d,"eof"))
+ FOP(O_EOF);
+ if (strEQ(d,"exp"))
+ UNI(O_EXP);
+ if (strEQ(d,"each"))
+ HFUN(O_EACH);
+ if (strEQ(d,"exec")) {
+ set_csh();
+ LOP(O_EXEC_OP);
+ }
+ if (strEQ(d,"endhostent"))
+ FUN0(O_EHOSTENT);
+ if (strEQ(d,"endnetent"))
+ FUN0(O_ENETENT);
+ if (strEQ(d,"endservent"))
+ FUN0(O_ESERVENT);
+ if (strEQ(d,"endprotoent"))
+ FUN0(O_EPROTOENT);
+ if (strEQ(d,"endpwent"))
+ FUN0(O_EPWENT);
+ if (strEQ(d,"endgrent"))
+ FUN0(O_EGRENT);
+ break;
+ case 'f': case 'F':
+ SNARFWORD;
+ if (strEQ(d,"for") || strEQ(d,"foreach")) {
+ yylval.ival = curcmd->c_line;
+ while (s < bufend && isSPACE(*s))
+ s++;
+ if (isALPHA(*s))
+ fatal("Missing $ on loop variable");
+ OPERATOR(FOR);
+ }
+ if (strEQ(d,"format")) {
+ d = bufend;
+ while (s < d && isSPACE(*s))
+ s++;
+ if (isALPHA(*s) || *s == '_')
+ *(--s) = '\\'; /* force next ident to WORD */
+ in_format = TRUE;
+ allstabs = TRUE; /* must initialize everything since */
+ OPERATOR(FORMAT); /* we don't know what will be used */
+ }
+ if (strEQ(d,"fork"))
+ FUN0(O_FORK);
+ if (strEQ(d,"fcntl"))
+ FOP3(O_FCNTL);
+ if (strEQ(d,"fileno"))
+ FOP(O_FILENO);
+ if (strEQ(d,"flock"))
+ FOP2(O_FLOCK);
+ break;
+ case 'g': case 'G':
+ SNARFWORD;
+ if (strEQ(d,"gt") || strEQ(d,"GT"))
+ ROP(O_SGT);
+ if (strEQ(d,"ge") || strEQ(d,"GE"))
+ ROP(O_SGE);
+ if (strEQ(d,"grep"))
+ FL2(O_GREP);
+ if (strEQ(d,"goto"))
+ LOOPX(O_GOTO);
+ if (strEQ(d,"gmtime"))
+ UNI(O_GMTIME);
+ if (strEQ(d,"getc"))
+ FOP(O_GETC);
+ if (strnEQ(d,"get",3)) {
+ d += 3;
+ if (*d == 'p') {
+ if (strEQ(d,"ppid"))
+ FUN0(O_GETPPID);
+ if (strEQ(d,"pgrp"))
+ UNI(O_GETPGRP);
+ if (strEQ(d,"priority"))
+ FUN2(O_GETPRIORITY);
+ if (strEQ(d,"protobyname"))
+ UNI(O_GPBYNAME);
+ if (strEQ(d,"protobynumber"))
+ FUN1(O_GPBYNUMBER);
+ if (strEQ(d,"protoent"))
+ FUN0(O_GPROTOENT);
+ if (strEQ(d,"pwent"))
+ FUN0(O_GPWENT);
+ if (strEQ(d,"pwnam"))
+ FUN1(O_GPWNAM);
+ if (strEQ(d,"pwuid"))
+ FUN1(O_GPWUID);
+ if (strEQ(d,"peername"))
+ FOP(O_GETPEERNAME);
+ }
+ else if (*d == 'h') {
+ if (strEQ(d,"hostbyname"))
+ UNI(O_GHBYNAME);
+ if (strEQ(d,"hostbyaddr"))
+ FUN2(O_GHBYADDR);
+ if (strEQ(d,"hostent"))
+ FUN0(O_GHOSTENT);
+ }
+ else if (*d == 'n') {
+ if (strEQ(d,"netbyname"))
+ UNI(O_GNBYNAME);
+ if (strEQ(d,"netbyaddr"))
+ FUN2(O_GNBYADDR);
+ if (strEQ(d,"netent"))
+ FUN0(O_GNETENT);
+ }
+ else if (*d == 's') {
+ if (strEQ(d,"servbyname"))
+ FUN2(O_GSBYNAME);
+ if (strEQ(d,"servbyport"))
+ FUN2(O_GSBYPORT);
+ if (strEQ(d,"servent"))
+ FUN0(O_GSERVENT);
+ if (strEQ(d,"sockname"))
+ FOP(O_GETSOCKNAME);
+ if (strEQ(d,"sockopt"))
+ FOP3(O_GSOCKOPT);
+ }
+ else if (*d == 'g') {
+ if (strEQ(d,"grent"))
+ FUN0(O_GGRENT);
+ if (strEQ(d,"grnam"))
+ FUN1(O_GGRNAM);
+ if (strEQ(d,"grgid"))
+ FUN1(O_GGRGID);
+ }
+ else if (*d == 'l') {
+ if (strEQ(d,"login"))
+ FUN0(O_GETLOGIN);
+ }
+ d -= 3;
+ }
+ break;
+ case 'h': case 'H':
+ SNARFWORD;
+ if (strEQ(d,"hex"))
+ UNI(O_HEX);
+ break;
+ case 'i': case 'I':
+ SNARFWORD;
+ if (strEQ(d,"if")) {
+ yylval.ival = curcmd->c_line;
+ OPERATOR(IF);
+ }
+ if (strEQ(d,"index"))
+ FUN2x(O_INDEX);
+ if (strEQ(d,"int"))
+ UNI(O_INT);
+ if (strEQ(d,"ioctl"))
+ FOP3(O_IOCTL);
+ break;
+ case 'j': case 'J':
+ SNARFWORD;
+ if (strEQ(d,"join"))
+ FL2(O_JOIN);
+ break;
+ case 'k': case 'K':
+ SNARFWORD;
+ if (strEQ(d,"keys"))
+ HFUN(O_KEYS);
+ if (strEQ(d,"kill"))
+ LOP(O_KILL);
+ break;
+ case 'l': case 'L':
+ SNARFWORD;
+ if (strEQ(d,"last"))
+ LOOPX(O_LAST);
+ if (strEQ(d,"local"))
+ OPERATOR(LOCAL);
+ if (strEQ(d,"length"))
+ UNI(O_LENGTH);
+ if (strEQ(d,"lt") || strEQ(d,"LT"))
+ ROP(O_SLT);
+ if (strEQ(d,"le") || strEQ(d,"LE"))
+ ROP(O_SLE);
+ if (strEQ(d,"localtime"))
+ UNI(O_LOCALTIME);
+ if (strEQ(d,"log"))
+ UNI(O_LOG);
+ if (strEQ(d,"link"))
+ FUN2(O_LINK);
+ if (strEQ(d,"listen"))
+ FOP2(O_LISTEN);
+ if (strEQ(d,"lstat"))
+ FOP(O_LSTAT);
+ break;
+ case 'm': case 'M':
+ if (s[1] == '\'') {
+ d = "m";
+ s++;
+ }
+ else {
+ SNARFWORD;
+ }
+ if (strEQ(d,"m")) {
+ s = scanpat(s-1);
+ if (yylval.arg)
+ TERM(PATTERN);
+ else
+ RETURN(1); /* force error */
+ }
+ switch (d[1]) {
+ case 'k':
+ if (strEQ(d,"mkdir"))
+ FUN2(O_MKDIR);
+ break;
+ case 's':
+ if (strEQ(d,"msgctl"))
+ FUN3(O_MSGCTL);
+ if (strEQ(d,"msgget"))
+ FUN2(O_MSGGET);
+ if (strEQ(d,"msgrcv"))
+ FUN5(O_MSGRCV);
+ if (strEQ(d,"msgsnd"))
+ FUN3(O_MSGSND);
+ break;
+ }
+ break;
+ case 'n': case 'N':
+ SNARFWORD;
+ if (strEQ(d,"next"))
+ LOOPX(O_NEXT);
+ if (strEQ(d,"ne") || strEQ(d,"NE"))
+ EOP(O_SNE);
+ break;
+ case 'o': case 'O':
+ SNARFWORD;
+ if (strEQ(d,"open"))
+ OPERATOR(OPEN);
+ if (strEQ(d,"ord"))
+ UNI(O_ORD);
+ if (strEQ(d,"oct"))
+ UNI(O_OCT);
+ if (strEQ(d,"opendir"))
+ FOP2(O_OPEN_DIR);
+ break;
+ case 'p': case 'P':
+ SNARFWORD;
+ if (strEQ(d,"print")) {
+ checkcomma(s,d,"filehandle");
+ LOP(O_PRINT);
+ }
+ if (strEQ(d,"printf")) {
+ checkcomma(s,d,"filehandle");
+ LOP(O_PRTF);
+ }
+ if (strEQ(d,"push")) {
+ yylval.ival = O_PUSH;
+ OPERATOR(PUSH);
+ }
+ if (strEQ(d,"pop"))
+ OPERATOR(POP);
+ if (strEQ(d,"pack"))
+ FL2(O_PACK);
+ if (strEQ(d,"package"))
+ OPERATOR(PACKAGE);
+ if (strEQ(d,"pipe"))
+ FOP22(O_PIPE_OP);
+ break;
+ case 'q': case 'Q':
+ SNARFWORD;
+ if (strEQ(d,"q")) {
+ s = scanstr(s-1, SCAN_DEF);
+ TERM(RSTRING);
+ }
+ if (strEQ(d,"qq")) {
+ s = scanstr(s-2, SCAN_DEF);
+ TERM(RSTRING);
+ }
+ if (strEQ(d,"qx")) {
+ s = scanstr(s-2, SCAN_DEF);
+ TERM(RSTRING);
+ }
+ break;
+ case 'r': case 'R':
+ SNARFWORD;
+ if (strEQ(d,"return"))
+ OLDLOP(O_RETURN);
+ if (strEQ(d,"require")) {
+ allstabs = TRUE; /* must initialize everything since */
+ UNI(O_REQUIRE); /* we don't know what will be used */
+ }
+ if (strEQ(d,"reset"))
+ UNI(O_RESET);
+ if (strEQ(d,"redo"))
+ LOOPX(O_REDO);
+ if (strEQ(d,"rename"))
+ FUN2(O_RENAME);
+ if (strEQ(d,"rand"))
+ UNI(O_RAND);
+ if (strEQ(d,"rmdir"))
+ UNI(O_RMDIR);
+ if (strEQ(d,"rindex"))
+ FUN2x(O_RINDEX);
+ if (strEQ(d,"read"))
+ FOP3(O_READ);
+ if (strEQ(d,"readdir"))
+ FOP(O_READDIR);
+ if (strEQ(d,"rewinddir"))
+ FOP(O_REWINDDIR);
+ if (strEQ(d,"recv"))
+ FOP4(O_RECV);
+ if (strEQ(d,"reverse"))
+ LOP(O_REVERSE);
+ if (strEQ(d,"readlink"))
+ UNI(O_READLINK);
+ break;
+ case 's': case 'S':
+ if (s[1] == '\'') {
+ d = "s";
+ s++;
+ }
+ else {
+ SNARFWORD;
+ }
+ if (strEQ(d,"s")) {
+ s = scansubst(s);
+ if (yylval.arg)
+ TERM(SUBST);
+ else
+ RETURN(1); /* force error */
+ }
+ switch (d[1]) {
+ case 'a':
+ case 'b':
+ break;
+ case 'c':
+ if (strEQ(d,"scalar"))
+ UNI(O_SCALAR);
+ break;
+ case 'd':
+ break;
+ case 'e':
+ if (strEQ(d,"select"))
+ OPERATOR(SSELECT);
+ if (strEQ(d,"seek"))
+ FOP3(O_SEEK);
+ if (strEQ(d,"semctl"))
+ FUN4(O_SEMCTL);
+ if (strEQ(d,"semget"))
+ FUN3(O_SEMGET);
+ if (strEQ(d,"semop"))
+ FUN2(O_SEMOP);
+ if (strEQ(d,"send"))
+ FOP3(O_SEND);
+ if (strEQ(d,"setpgrp"))
+ FUN2(O_SETPGRP);
+ if (strEQ(d,"setpriority"))
+ FUN3(O_SETPRIORITY);
+ if (strEQ(d,"sethostent"))
+ FUN1(O_SHOSTENT);
+ if (strEQ(d,"setnetent"))
+ FUN1(O_SNETENT);
+ if (strEQ(d,"setservent"))
+ FUN1(O_SSERVENT);
+ if (strEQ(d,"setprotoent"))
+ FUN1(O_SPROTOENT);
+ if (strEQ(d,"setpwent"))
+ FUN0(O_SPWENT);
+ if (strEQ(d,"setgrent"))
+ FUN0(O_SGRENT);
+ if (strEQ(d,"seekdir"))
+ FOP2(O_SEEKDIR);
+ if (strEQ(d,"setsockopt"))
+ FOP4(O_SSOCKOPT);
+ break;
+ case 'f':
+ case 'g':
+ break;
+ case 'h':
+ if (strEQ(d,"shift"))
+ TERM(SHIFT);
+ if (strEQ(d,"shmctl"))
+ FUN3(O_SHMCTL);
+ if (strEQ(d,"shmget"))
+ FUN3(O_SHMGET);
+ if (strEQ(d,"shmread"))
+ FUN4(O_SHMREAD);
+ if (strEQ(d,"shmwrite"))
+ FUN4(O_SHMWRITE);
+ if (strEQ(d,"shutdown"))
+ FOP2(O_SHUTDOWN);
+ break;
+ case 'i':
+ if (strEQ(d,"sin"))
+ UNI(O_SIN);
+ break;
+ case 'j':
+ case 'k':
+ break;
+ case 'l':
+ if (strEQ(d,"sleep"))
+ UNI(O_SLEEP);
+ break;
+ case 'm':
+ case 'n':
+ break;
+ case 'o':
+ if (strEQ(d,"socket"))
+ FOP4(O_SOCKET);
+ if (strEQ(d,"socketpair"))
+ FOP25(O_SOCKPAIR);
+ if (strEQ(d,"sort")) {
+ checkcomma(s,d,"subroutine name");
+ d = bufend;
+ while (s < d && isSPACE(*s)) s++;
+ if (*s == ';' || *s == ')') /* probably a close */
+ fatal("sort is now a reserved word");
+ if (isALPHA(*s) || *s == '_') {
+ /*SUPPRESS 530*/
+ for (d = s; isALNUM(*d); d++) ;
+ strncpy(tokenbuf,s,d-s);
+ tokenbuf[d-s] = '\0';
+ if (strNE(tokenbuf,"keys") &&
+ strNE(tokenbuf,"values") &&
+ strNE(tokenbuf,"split") &&
+ strNE(tokenbuf,"grep") &&
+ strNE(tokenbuf,"readdir") &&
+ strNE(tokenbuf,"unpack") &&
+ strNE(tokenbuf,"do") &&
+ strNE(tokenbuf,"eval") &&
+ (d >= bufend || isSPACE(*d)) )
+ *(--s) = '\\'; /* force next ident to WORD */
+ }
+ LOP(O_SORT);
+ }
+ break;
+ case 'p':
+ if (strEQ(d,"split"))
+ TERM(SPLIT);
+ if (strEQ(d,"sprintf"))
+ FL(O_SPRINTF);
+ if (strEQ(d,"splice")) {
+ yylval.ival = O_SPLICE;
+ OPERATOR(PUSH);
+ }
+ break;
+ case 'q':
+ if (strEQ(d,"sqrt"))
+ UNI(O_SQRT);
+ break;
+ case 'r':
+ if (strEQ(d,"srand"))
+ UNI(O_SRAND);
+ break;
+ case 's':
+ break;
+ case 't':
+ if (strEQ(d,"stat"))
+ FOP(O_STAT);
+ if (strEQ(d,"study")) {
+ sawstudy++;
+ LFUN(O_STUDY);
+ }
+ break;
+ case 'u':
+ if (strEQ(d,"substr"))
+ FUN2x(O_SUBSTR);
+ if (strEQ(d,"sub")) {
+ yylval.ival = savestack->ary_fill; /* restore stuff on reduce */
+ savelong(&subline);
+ saveitem(subname);
+
+ subline = curcmd->c_line;
+ d = bufend;
+ while (s < d && isSPACE(*s))
+ s++;
+ if (isALPHA(*s) || *s == '_' || *s == '\'') {
+ str_sset(subname,curstname);
+ str_ncat(subname,"'",1);
+ for (d = s+1; isALNUM(*d) || *d == '\''; d++)
+ /*SUPPRESS 530*/
+ ;
+ if (d[-1] == '\'')
+ d--;
+ str_ncat(subname,s,d-s);
+ *(--s) = '\\'; /* force next ident to WORD */
+ }
+ else
+ str_set(subname,"?");
+ OPERATOR(SUB);
+ }
+ break;
+ case 'v':
+ case 'w':
+ case 'x':
+ break;
+ case 'y':
+ if (strEQ(d,"system")) {
+ set_csh();
+ LOP(O_SYSTEM);
+ }
+ if (strEQ(d,"symlink"))
+ FUN2(O_SYMLINK);
+ if (strEQ(d,"syscall"))
+ LOP(O_SYSCALL);
+ if (strEQ(d,"sysread"))
+ FOP3(O_SYSREAD);
+ if (strEQ(d,"syswrite"))
+ FOP3(O_SYSWRITE);
+ break;
+ case 'z':
+ break;
+ }
+ break;
+ case 't': case 'T':
+ SNARFWORD;
+ if (strEQ(d,"tr")) {
+ s = scantrans(s);
+ if (yylval.arg)
+ TERM(TRANS);
+ else
+ RETURN(1); /* force error */
+ }
+ if (strEQ(d,"tell"))
+ FOP(O_TELL);
+ if (strEQ(d,"telldir"))
+ FOP(O_TELLDIR);
+ if (strEQ(d,"time"))
+ FUN0(O_TIME);
+ if (strEQ(d,"times"))
+ FUN0(O_TMS);
+ if (strEQ(d,"truncate"))
+ FOP2(O_TRUNCATE);
+ break;
+ case 'u': case 'U':
+ SNARFWORD;
+ if (strEQ(d,"using"))
+ OPERATOR(USING);
+ if (strEQ(d,"until")) {
+ yylval.ival = curcmd->c_line;
+ OPERATOR(UNTIL);
+ }
+ if (strEQ(d,"unless")) {
+ yylval.ival = curcmd->c_line;
+ OPERATOR(UNLESS);
+ }
+ if (strEQ(d,"unlink"))
+ LOP(O_UNLINK);
+ if (strEQ(d,"undef"))
+ LFUN(O_UNDEF);
+ if (strEQ(d,"unpack"))
+ FUN2(O_UNPACK);
+ if (strEQ(d,"utime"))
+ LOP(O_UTIME);
+ if (strEQ(d,"umask"))
+ UNI(O_UMASK);
+ if (strEQ(d,"unshift")) {
+ yylval.ival = O_UNSHIFT;
+ OPERATOR(PUSH);
+ }
+ break;
+ case 'v': case 'V':
+ SNARFWORD;
+ if (strEQ(d,"values"))
+ HFUN(O_VALUES);
+ if (strEQ(d,"vec")) {
+ sawvec = TRUE;
+ FUN3(O_VEC);
+ }
+ break;
+ case 'w': case 'W':
+ SNARFWORD;
+ if (strEQ(d,"while")) {
+ yylval.ival = curcmd->c_line;
+ OPERATOR(WHILE);
+ }
+ if (strEQ(d,"warn"))
+ LOP(O_WARN);
+ if (strEQ(d,"wait"))
+ FUN0(O_WAIT);
+ if (strEQ(d,"waitpid"))
+ FUN2(O_WAITPID);
+ if (strEQ(d,"wantarray")) {
+ yylval.arg = op_new(1);
+ yylval.arg->arg_type = O_ITEM;
+ yylval.arg[1].arg_type = A_WANTARRAY;
+ TERM(RSTRING);
+ }
+ if (strEQ(d,"write"))
+ FOP(O_WRITE);
+ break;
+ case 'x': case 'X':
+ if (*s == 'x' && isDIGIT(s[1]) && !expectterm) {
+ s++;
+ MOP(O_REPEAT);
+ }
+ SNARFWORD;
+ if (strEQ(d,"x")) {
+ if (!expectterm)
+ MOP(O_REPEAT);
+ check_uni();
+ }
+ break;
+ case 'y': case 'Y':
+ if (s[1] == '\'') {
+ d = "y";
+ s++;
+ }
+ else {
+ SNARFWORD;
+ }
+ if (strEQ(d,"y")) {
+ s = scantrans(s);
+ TERM(TRANS);
+ }
+ break;
+ case 'z': case 'Z':
+ SNARFWORD;
+ break;
+ }
+ yylval.cval = savestr(d);
+ if (expectterm == 2) { /* special case: start of statement */
+ while (isSPACE(*s)) s++;
+ if (*s == ':') {
+ s++;
+ CLINE;
+ OPERATOR(LABEL);
+ }
+ TERM(WORD);
+ }
+ expectterm = FALSE;
+ if (oldoldbufptr && oldoldbufptr < bufptr) {
+ while (isSPACE(*oldoldbufptr))
+ oldoldbufptr++;
+ if (*oldoldbufptr == 'p' && strnEQ(oldoldbufptr,"print",5))
+ expectterm = TRUE;
+ else if (*oldoldbufptr == 's' && strnEQ(oldoldbufptr,"sort",4))
+ expectterm = TRUE;
+ }
+ return (CLINE, bufptr = s, (int)WORD);
+}
+
+void
+checkcomma(s,name,what)
+register char *s;
+char *name;
+char *what;
+{
+ char *w;
+
+ if (dowarn && *s == ' ' && s[1] == '(') {
+ w = index(s,')');
+ if (w)
+ for (w++; *w && isSPACE(*w); w++) ;
+ if (!w || !*w || !index(";|}", *w)) /* an advisory hack only... */
+ warn("%s (...) interpreted as function",name);
+ }
+ while (s < bufend && isSPACE(*s))
+ s++;
+ if (*s == '(')
+ s++;
+ while (s < bufend && isSPACE(*s))
+ s++;
+ if (isALPHA(*s) || *s == '_') {
+ w = s++;
+ while (isALNUM(*s))
+ s++;
+ while (s < bufend && isSPACE(*s))
+ s++;
+ if (*s == ',') {
+ *s = '\0';
+ w = instr(
+ "tell eof times getlogin wait length shift umask getppid \
+ cos exp int log rand sin sqrt ord wantarray",
+ w);
+ *s = ',';
+ if (w)
+ return;
+ fatal("No comma allowed after %s", what);
+ }
+ }
+}
+
+char *
+scanident(s,send,dest)
+register char *s;
+register char *send;
+char *dest;
+{
+ register char *d;
+ int brackets = 0;
+
+ reparse = Nullch;
+ s++;
+ d = dest;
+ if (isDIGIT(*s)) {
+ while (isDIGIT(*s))
+ *d++ = *s++;
+ }
+ else {
+ while (isALNUM(*s) || *s == '\'')
+ *d++ = *s++;
+ }
+ while (d > dest+1 && d[-1] == '\'')
+ d--,s--;
+ *d = '\0';
+ d = dest;
+ if (!*d) {
+ *d = *s++;
+ if (*d == '{' /* } */ ) {
+ d = dest;
+ brackets++;
+ while (s < send && brackets) {
+ if (!reparse && (d == dest || (*s && isALNUM(*s) ))) {
+ *d++ = *s++;
+ continue;
+ }
+ else if (!reparse)
+ reparse = s;
+ switch (*s++) {
+ /* { */
+ case '}':
+ brackets--;
+ if (reparse && reparse == s - 1)
+ reparse = Nullch;
+ break;
+ case '{': /* } */
+ brackets++;
+ break;
+ }
+ }
+ *d = '\0';
+ d = dest;
+ }
+ else
+ d[1] = '\0';
+ }
+ if (*d == '^' && (isUPPER(*s) || index("[\\]^_?", *s))) {
+#ifdef DEBUGGING
+ if (*s == 'D')
+ debug |= 32768;
+#endif
+ *d = *s++ ^ 64;
+ }
+ return s;
+}
+
+void
+scanconst(spat,string,len)
+SPAT *spat;
+char *string;
+int len;
+{
+ register STR *tmpstr;
+ register char *t;
+ register char *d;
+ register char *e;
+ char *origstring = string;
+ static char *vert = "|";
+
+ if (ninstr(string, string+len, vert, vert+1))
+ return;
+ if (*string == '^')
+ string++, len--;
+ tmpstr = Str_new(86,len);
+ str_nset(tmpstr,string,len);
+ t = str_get(tmpstr);
+ e = t + len;
+ tmpstr->str_u.str_useful = 100;
+ for (d=t; d < e; ) {
+ switch (*d) {
+ case '{':
+ if (isDIGIT(d[1]))
+ e = d;
+ else
+ goto defchar;
+ break;
+ case '.': case '[': case '$': case '(': case ')': case '|': case '+':
+ case '^':
+ e = d;
+ break;
+ case '\\':
+ if (d[1] && index("wWbB0123456789sSdDlLuUExc",d[1])) {
+ e = d;
+ break;
+ }
+ Move(d+1,d,e-d,char);
+ e--;
+ switch(*d) {
+ case 'n':
+ *d = '\n';
+ break;
+ case 't':
+ *d = '\t';
+ break;
+ case 'f':
+ *d = '\f';
+ break;
+ case 'r':
+ *d = '\r';
+ break;
+ case 'e':
+ *d = '\033';
+ break;
+ case 'a':
+ *d = '\007';
+ break;
+ }
+ /* FALL THROUGH */
+ default:
+ defchar:
+ if (d[1] == '*' || (d[1] == '{' && d[2] == '0') || d[1] == '?') {
+ e = d;
+ break;
+ }
+ d++;
+ }
+ }
+ if (d == t) {
+ str_free(tmpstr);
+ return;
+ }
+ *d = '\0';
+ tmpstr->str_cur = d - t;
+ if (d == t+len)
+ spat->spat_flags |= SPAT_ALL;
+ if (*origstring != '^')
+ spat->spat_flags |= SPAT_SCANFIRST;
+ spat->spat_short = tmpstr;
+ spat->spat_slen = d - t;
+}
+
+char *
+scanpat(s)
+register char *s;
+{
+ register SPAT *spat;
+ register char *d;
+ register char *e;
+ int len;
+ SPAT savespat;
+ STR *str = Str_new(93,0);
+ char delim;
+
+ Newz(801,spat,1,SPAT);
+ spat->spat_next = curstash->tbl_spatroot; /* link into spat list */
+ curstash->tbl_spatroot = spat;
+
+ switch (*s++) {
+ case 'm':
+ s++;
+ break;
+ case '/':
+ break;
+ case '?':
+ spat->spat_flags |= SPAT_ONCE;
+ break;
+ default:
+ fatal("panic: scanpat");
+ }
+ s = str_append_till(str,s,bufend,s[-1],patleave);
+ if (s >= bufend) {
+ str_free(str);
+ yyerror("Search pattern not terminated");
+ yylval.arg = Nullarg;
+ return s;
+ }
+ delim = *s++;
+ while (*s == 'i' || *s == 'o' || *s == 'g') {
+ if (*s == 'i') {
+ s++;
+ sawi = TRUE;
+ spat->spat_flags |= SPAT_FOLD;
+ }
+ if (*s == 'o') {
+ s++;
+ spat->spat_flags |= SPAT_KEEP;
+ }
+ if (*s == 'g') {
+ s++;
+ spat->spat_flags |= SPAT_GLOBAL;
+ }
+ }
+ len = str->str_cur;
+ e = str->str_ptr + len;
+ if (delim == '\'')
+ d = e;
+ else
+ d = str->str_ptr;
+ for (; d < e; d++) {
+ if (*d == '\\')
+ d++;
+ else if ((*d == '$' && d[1] && d[1] != '|' && d[1] != ')') ||
+ (*d == '@')) {
+ register ARG *arg;
+
+ spat->spat_runtime = arg = op_new(1);
+ arg->arg_type = O_ITEM;
+ arg[1].arg_type = A_DOUBLE;
+ arg[1].arg_ptr.arg_str = str_smake(str);
+ d = scanident(d,bufend,buf);
+ (void)stabent(buf,TRUE); /* make sure it's created */
+ for (; d < e; d++) {
+ if (*d == '\\')
+ d++;
+ else if (*d == '$' && d[1] && d[1] != '|' && d[1] != ')') {
+ d = scanident(d,bufend,buf);
+ (void)stabent(buf,TRUE);
+ }
+ else if (*d == '@') {
+ d = scanident(d,bufend,buf);
+ if (strEQ(buf,"ARGV") || strEQ(buf,"ENV") ||
+ strEQ(buf,"SIG") || strEQ(buf,"INC"))
+ (void)stabent(buf,TRUE);
+ }
+ }
+ goto got_pat; /* skip compiling for now */
+ }
+ }
+ if (spat->spat_flags & SPAT_FOLD)
+ StructCopy(spat, &savespat, SPAT);
+ scanconst(spat,str->str_ptr,len);
+ if ((spat->spat_flags & SPAT_ALL) && (spat->spat_flags & SPAT_SCANFIRST)) {
+ fbmcompile(spat->spat_short, spat->spat_flags & SPAT_FOLD);
+ spat->spat_regexp = regcomp(str->str_ptr,str->str_ptr+len,
+ spat->spat_flags & SPAT_FOLD);
+ /* Note that this regexp can still be used if someone says
+ * something like /a/ && s//b/; so we can't delete it.
+ */
+ }
+ else {
+ if (spat->spat_flags & SPAT_FOLD)
+ StructCopy(&savespat, spat, SPAT);
+ if (spat->spat_short)
+ fbmcompile(spat->spat_short, spat->spat_flags & SPAT_FOLD);
+ spat->spat_regexp = regcomp(str->str_ptr,str->str_ptr+len,
+ spat->spat_flags & SPAT_FOLD);
+ hoistmust(spat);
+ }
+ got_pat:
+ str_free(str);
+ yylval.arg = make_match(O_MATCH,stab2arg(A_STAB,defstab),spat);
+ return s;
+}
+
+char *
+scansubst(start)
+char *start;
+{
+ register char *s = start;
+ register SPAT *spat;
+ register char *d;
+ register char *e;
+ int len;
+ STR *str = Str_new(93,0);
+ char term = *s;
+
+ if (term && (d = index("([{< )]}> )]}>",term)))
+ term = d[5];
+
+ Newz(802,spat,1,SPAT);
+ spat->spat_next = curstash->tbl_spatroot; /* link into spat list */
+ curstash->tbl_spatroot = spat;
+
+ s = str_append_till(str,s+1,bufend,term,patleave);
+ if (s >= bufend) {
+ str_free(str);
+ yyerror("Substitution pattern not terminated");
+ yylval.arg = Nullarg;
+ return s;
+ }
+ len = str->str_cur;
+ e = str->str_ptr + len;
+ for (d = str->str_ptr; d < e; d++) {
+ if (*d == '\\')
+ d++;
+ else if ((*d == '$' && d[1] && d[1] != '|' && /*(*/ d[1] != ')') ||
+ *d == '@' ) {
+ register ARG *arg;
+
+ spat->spat_runtime = arg = op_new(1);
+ arg->arg_type = O_ITEM;
+ arg[1].arg_type = A_DOUBLE;
+ arg[1].arg_ptr.arg_str = str_smake(str);
+ d = scanident(d,e,buf);
+ (void)stabent(buf,TRUE); /* make sure it's created */
+ for (; *d; d++) {
+ if (*d == '$' && d[1] && d[-1] != '\\' && d[1] != '|') {
+ d = scanident(d,e,buf);
+ (void)stabent(buf,TRUE);
+ }
+ else if (*d == '@' && d[-1] != '\\') {
+ d = scanident(d,e,buf);
+ if (strEQ(buf,"ARGV") || strEQ(buf,"ENV") ||
+ strEQ(buf,"SIG") || strEQ(buf,"INC"))
+ (void)stabent(buf,TRUE);
+ }
+ }
+ goto get_repl; /* skip compiling for now */
+ }
+ }
+ scanconst(spat,str->str_ptr,len);
+get_repl:
+ if (term != *start)
+ s++;
+ s = scanstr(s, SCAN_REPL);
+ if (s >= bufend) {
+ str_free(str);
+ yyerror("Substitution replacement not terminated");
+ yylval.arg = Nullarg;
+ return s;
+ }
+ spat->spat_repl = yylval.arg;
+ if ((spat->spat_repl[1].arg_type & A_MASK) == A_SINGLE)
+ spat->spat_flags |= SPAT_CONST;
+ else if ((spat->spat_repl[1].arg_type & A_MASK) == A_DOUBLE) {
+ STR *tmpstr;
+ register char *t;
+
+ spat->spat_flags |= SPAT_CONST;
+ tmpstr = spat->spat_repl[1].arg_ptr.arg_str;
+ e = tmpstr->str_ptr + tmpstr->str_cur;
+ for (t = tmpstr->str_ptr; t < e; t++) {
+ if (*t == '$' && t[1] && (index("`'&+0123456789",t[1]) ||
+ (t[1] == '{' /*}*/ && isDIGIT(t[2])) ))
+ spat->spat_flags &= ~SPAT_CONST;
+ }
+ }
+ while (*s == 'g' || *s == 'i' || *s == 'e' || *s == 'o') {
+ int es = 0;
+
+ if (*s == 'e') {
+ s++;
+ es++;
+ if ((spat->spat_repl[1].arg_type & A_MASK) == A_DOUBLE)
+ spat->spat_repl[1].arg_type = A_SINGLE;
+ spat->spat_repl = make_op(
+ (!es && spat->spat_repl[1].arg_type == A_SINGLE
+ ? O_EVALONCE
+ : O_EVAL),
+ 2,
+ spat->spat_repl,
+ Nullarg,
+ Nullarg);
+ spat->spat_flags &= ~SPAT_CONST;
+ }
+ if (*s == 'g') {
+ s++;
+ spat->spat_flags |= SPAT_GLOBAL;
+ }
+ if (*s == 'i') {
+ s++;
+ sawi = TRUE;
+ spat->spat_flags |= SPAT_FOLD;
+ if (!(spat->spat_flags & SPAT_SCANFIRST)) {
+ str_free(spat->spat_short); /* anchored opt doesn't do */
+ spat->spat_short = Nullstr; /* case insensitive match */
+ spat->spat_slen = 0;
+ }
+ }
+ if (*s == 'o') {
+ s++;
+ spat->spat_flags |= SPAT_KEEP;
+ }
+ }
+ if (spat->spat_short && (spat->spat_flags & SPAT_SCANFIRST))
+ fbmcompile(spat->spat_short, spat->spat_flags & SPAT_FOLD);
+ if (!spat->spat_runtime) {
+ spat->spat_regexp = regcomp(str->str_ptr,str->str_ptr+len,
+ spat->spat_flags & SPAT_FOLD);
+ hoistmust(spat);
+ }
+ yylval.arg = make_match(O_SUBST,stab2arg(A_STAB,defstab),spat);
+ str_free(str);
+ return s;
+}
+
+void
+hoistmust(spat)
+register SPAT *spat;
+{
+ if (!spat->spat_short && spat->spat_regexp->regstart &&
+ (!spat->spat_regexp->regmust || spat->spat_regexp->reganch & ROPT_ANCH)
+ ) {
+ if (!(spat->spat_regexp->reganch & ROPT_ANCH))
+ spat->spat_flags |= SPAT_SCANFIRST;
+ else if (spat->spat_flags & SPAT_FOLD)
+ return;
+ spat->spat_short = str_smake(spat->spat_regexp->regstart);
+ }
+ else if (spat->spat_regexp->regmust) {/* is there a better short-circuit? */
+ if (spat->spat_short &&
+ str_eq(spat->spat_short,spat->spat_regexp->regmust))
+ {
+ if (spat->spat_flags & SPAT_SCANFIRST) {
+ str_free(spat->spat_short);
+ spat->spat_short = Nullstr;
+ }
+ else {
+ str_free(spat->spat_regexp->regmust);
+ spat->spat_regexp->regmust = Nullstr;
+ return;
+ }
+ }
+ if (!spat->spat_short || /* promote the better string */
+ ((spat->spat_flags & SPAT_SCANFIRST) &&
+ (spat->spat_short->str_cur < spat->spat_regexp->regmust->str_cur) )){
+ str_free(spat->spat_short); /* ok if null */
+ spat->spat_short = spat->spat_regexp->regmust;
+ spat->spat_regexp->regmust = Nullstr;
+ spat->spat_flags |= SPAT_SCANFIRST;
+ }
+ }
+}
+
+char *
+scantrans(start)
+char *start;
+{
+ register char *s = start;
+ ARG *arg =
+ l(make_op(O_TRANS,2,stab2arg(A_STAB,defstab),Nullarg,Nullarg));
+ STR *tstr;
+ STR *rstr;
+ register char *t;
+ register char *r;
+ register short *tbl;
+ register int i;
+ register int j;
+ int tlen, rlen;
+ int squash;
+ int delete;
+ int complement;
+
+ New(803,tbl,256,short);
+ arg[2].arg_type = A_NULL;
+ arg[2].arg_ptr.arg_cval = (char*) tbl;
+
+ s = scanstr(s, SCAN_TR);
+ if (s >= bufend) {
+ yyerror("Translation pattern not terminated");
+ yylval.arg = Nullarg;
+ return s;
+ }
+ tstr = yylval.arg[1].arg_ptr.arg_str;
+ yylval.arg[1].arg_ptr.arg_str = Nullstr;
+ arg_free(yylval.arg);
+ t = tstr->str_ptr;
+ tlen = tstr->str_cur;
+
+ if (s[-1] == *start)
+ s--;
+
+ s = scanstr(s, SCAN_TR|SCAN_REPL);
+ if (s >= bufend) {
+ yyerror("Translation replacement not terminated");
+ yylval.arg = Nullarg;
+ return s;
+ }
+ rstr = yylval.arg[1].arg_ptr.arg_str;
+ yylval.arg[1].arg_ptr.arg_str = Nullstr;
+ arg_free(yylval.arg);
+ r = rstr->str_ptr;
+ rlen = rstr->str_cur;
+
+ complement = delete = squash = 0;
+ while (*s == 'c' || *s == 'd' || *s == 's') {
+ if (*s == 'c')
+ complement = 1;
+ else if (*s == 'd')
+ delete = 2;
+ else
+ squash = 1;
+ s++;
+ }
+ arg[2].arg_len = delete|squash;
+ yylval.arg = arg;
+ if (complement) {
+ Zero(tbl, 256, short);
+ for (i = 0; i < tlen; i++)
+ tbl[t[i] & 0377] = -1;
+ for (i = 0, j = 0; i < 256; i++) {
+ if (!tbl[i]) {
+ if (j >= rlen) {
+ if (delete)
+ tbl[i] = -2;
+ else if (rlen)
+ tbl[i] = r[j-1] & 0377;
+ else
+ tbl[i] = i;
+ }
+ else
+ tbl[i] = r[j++] & 0377;
+ }
+ }
+ }
+ else {
+ if (!rlen && !delete) {
+ r = t; rlen = tlen;
+ }
+ for (i = 0; i < 256; i++)
+ tbl[i] = -1;
+ for (i = 0, j = 0; i < tlen; i++,j++) {
+ if (j >= rlen) {
+ if (delete) {
+ if (tbl[t[i] & 0377] == -1)
+ tbl[t[i] & 0377] = -2;
+ continue;
+ }
+ --j;
+ }
+ if (tbl[t[i] & 0377] == -1)
+ tbl[t[i] & 0377] = r[j] & 0377;
+ }
+ }
+ str_free(tstr);
+ str_free(rstr);
+ return s;
+}
+
+char *
+scanstr(start, in_what)
+char *start;
+int in_what;
+{
+ register char *s = start;
+ register char term;
+ register char *d;
+ register ARG *arg;
+ register char *send;
+ register bool makesingle = FALSE;
+ register STAB *stab;
+ bool alwaysdollar = FALSE;
+ bool hereis = FALSE;
+ STR *herewas;
+ STR *str;
+ /* which backslash sequences to keep */
+ char *leave = (in_what & SCAN_TR)
+ ? "\\$@nrtfbeacx0123456789-"
+ : "\\$@nrtfbeacx0123456789[{]}lLuUE";
+ int len;
+
+ arg = op_new(1);
+ yylval.arg = arg;
+ arg->arg_type = O_ITEM;
+
+ switch (*s) {
+ default: /* a substitution replacement */
+ arg[1].arg_type = A_DOUBLE;
+ makesingle = TRUE; /* maybe disable runtime scanning */
+ term = *s;
+ if (term == '\'')
+ leave = Nullch;
+ goto snarf_it;
+ case '0':
+ {
+ unsigned long i;
+ int shift;
+
+ arg[1].arg_type = A_SINGLE;
+ if (s[1] == 'x') {
+ shift = 4;
+ s += 2;
+ }
+ else if (s[1] == '.')
+ goto decimal;
+ else
+ shift = 3;
+ i = 0;
+ for (;;) {
+ switch (*s) {
+ default:
+ goto out;
+ case '_':
+ s++;
+ break;
+ case '8': case '9':
+ if (shift != 4)
+ yyerror("Illegal octal digit");
+ /* FALL THROUGH */
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7':
+ i <<= shift;
+ i += *s++ & 15;
+ break;
+ case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
+ case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
+ if (shift != 4)
+ goto out;
+ i <<= 4;
+ i += (*s++ & 7) + 9;
+ break;
+ }
+ }
+ out:
+ str = Str_new(92,0);
+ str_numset(str,(double)i);
+ if (str->str_ptr) {
+ Safefree(str->str_ptr);
+ str->str_ptr = Nullch;
+ str->str_len = str->str_cur = 0;
+ }
+ arg[1].arg_ptr.arg_str = str;
+ }
+ break;
+ case '1': case '2': case '3': case '4': case '5':
+ case '6': case '7': case '8': case '9': case '.':
+ decimal:
+ arg[1].arg_type = A_SINGLE;
+ d = tokenbuf;
+ while (isDIGIT(*s) || *s == '_') {
+ if (*s == '_')
+ s++;
+ else
+ *d++ = *s++;
+ }
+ if (*s == '.' && s[1] != '.') {
+ *d++ = *s++;
+ while (isDIGIT(*s) || *s == '_') {
+ if (*s == '_')
+ s++;
+ else
+ *d++ = *s++;
+ }
+ }
+ if (*s && index("eE",*s) && index("+-0123456789",s[1])) {
+ *d++ = *s++;
+ if (*s == '+' || *s == '-')
+ *d++ = *s++;
+ while (isDIGIT(*s))
+ *d++ = *s++;
+ }
+ *d = '\0';
+ str = Str_new(92,0);
+ str_numset(str,atof(tokenbuf));
+ if (str->str_ptr) {
+ Safefree(str->str_ptr);
+ str->str_ptr = Nullch;
+ str->str_len = str->str_cur = 0;
+ }
+ arg[1].arg_ptr.arg_str = str;
+ break;
+ case '<':
+ if (in_what & (SCAN_REPL|SCAN_TR))
+ goto do_double;
+ if (*++s == '<') {
+ hereis = TRUE;
+ d = tokenbuf;
+ if (!rsfp)
+ *d++ = '\n';
+ if (*++s && index("`'\"",*s)) {
+ term = *s++;
+ s = cpytill(d,s,bufend,term,&len);
+ if (s < bufend)
+ s++;
+ d += len;
+ }
+ else {
+ if (*s == '\\')
+ s++, term = '\'';
+ else
+ term = '"';
+ while (isALNUM(*s))
+ *d++ = *s++;
+ } /* assuming tokenbuf won't clobber */
+ *d++ = '\n';
+ *d = '\0';
+ len = d - tokenbuf;
+ d = "\n";
+ if (rsfp || !(d=ninstr(s,bufend,d,d+1)))
+ herewas = str_make(s,bufend-s);
+ else
+ s--, herewas = str_make(s,d-s);
+ s += herewas->str_cur;
+ if (term == '\'')
+ goto do_single;
+ if (term == '`')
+ goto do_back;
+ goto do_double;
+ }
+ d = tokenbuf;
+ s = cpytill(d,s,bufend,'>',&len);
+ if (s < bufend)
+ s++;
+ else
+ fatal("Unterminated <> operator");
+
+ if (*d == '$') d++;
+ while (*d && (isALNUM(*d) || *d == '\''))
+ d++;
+ if (d - tokenbuf != len) {
+ s = start;
+ term = *s;
+ arg[1].arg_type = A_GLOB;
+ set_csh();
+ alwaysdollar = TRUE; /* treat $) and $| as variables */
+ goto snarf_it;
+ }
+ else {
+ d = tokenbuf;
+ if (!len)
+ (void)strcpy(d,"ARGV");
+ if (*d == '$') {
+ arg[1].arg_type = A_INDREAD;
+ arg[1].arg_ptr.arg_stab = stabent(d+1,TRUE);
+ }
+ else {
+ arg[1].arg_type = A_READ;
+ arg[1].arg_ptr.arg_stab = stabent(d,TRUE);
+ if (!stab_io(arg[1].arg_ptr.arg_stab))
+ stab_io(arg[1].arg_ptr.arg_stab) = stio_new();
+ if (strEQ(d,"ARGV")) {
+ (void)aadd(arg[1].arg_ptr.arg_stab);
+ stab_io(arg[1].arg_ptr.arg_stab)->flags |=
+ IOF_ARGV|IOF_START;
+ }
+ }
+ }
+ break;
+
+ case 'q':
+ s++;
+ if (*s == 'q') {
+ s++;
+ goto do_double;
+ }
+ if (*s == 'x') {
+ s++;
+ goto do_back;
+ }
+ /* FALL THROUGH */
+ case '\'':
+ do_single:
+ term = *s;
+ arg[1].arg_type = A_SINGLE;
+ leave = Nullch;
+ goto snarf_it;
+
+ case '"':
+ do_double:
+ term = *s;
+ arg[1].arg_type = A_DOUBLE;
+ makesingle = TRUE; /* maybe disable runtime scanning */
+ alwaysdollar = TRUE; /* treat $) and $| as variables */
+ goto snarf_it;
+ case '`':
+ do_back:
+ term = *s;
+ arg[1].arg_type = A_BACKTICK;
+ set_csh();
+ alwaysdollar = TRUE; /* treat $) and $| as variables */
+ snarf_it:
+ {
+ STR *tmpstr;
+ STR *tmpstr2 = Nullstr;
+ char *tmps;
+ char *start;
+ bool dorange = FALSE;
+
+ CLINE;
+ multi_start = curcmd->c_line;
+ if (hereis)
+ multi_open = multi_close = '<';
+ else {
+ multi_open = term;
+ if (term && (tmps = index("([{< )]}> )]}>",term)))
+ term = tmps[5];
+ multi_close = term;
+ }
+ tmpstr = Str_new(87,80);
+ if (hereis) {
+ term = *tokenbuf;
+ if (!rsfp) {
+ d = s;
+ while (s < bufend &&
+ (*s != term || bcmp(s,tokenbuf,len) != 0) ) {
+ if (*s++ == '\n')
+ curcmd->c_line++;
+ }
+ if (s >= bufend) {
+ curcmd->c_line = multi_start;
+ fatal("EOF in string");
+ }
+ str_nset(tmpstr,d+1,s-d);
+ s += len - 1;
+ str_ncat(herewas,s,bufend-s);
+ str_replace(linestr,herewas);
+ oldoldbufptr = oldbufptr = bufptr = s = str_get(linestr);
+ bufend = linestr->str_ptr + linestr->str_cur;
+ hereis = FALSE;
+ }
+ else
+ str_nset(tmpstr,"",0); /* avoid "uninitialized" warning */
+ }
+ else
+ s = str_append_till(tmpstr,s+1,bufend,term,leave);
+ while (s >= bufend) { /* multiple line string? */
+ if (!rsfp ||
+ !(oldoldbufptr = oldbufptr = s = str_gets(linestr, rsfp, 0))) {
+ curcmd->c_line = multi_start;
+ fatal("EOF in string");
+ }
+ curcmd->c_line++;
+ if (perldb) {
+ STR *str = Str_new(88,0);
+
+ str_sset(str,linestr);
+ astore(stab_xarray(curcmd->c_filestab),
+ (int)curcmd->c_line,str);
+ }
+ bufend = linestr->str_ptr + linestr->str_cur;
+ if (hereis) {
+ if (*s == term && bcmp(s,tokenbuf,len) == 0) {
+ s = bufend - 1;
+ *s = ' ';
+ str_scat(linestr,herewas);
+ bufend = linestr->str_ptr + linestr->str_cur;
+ }
+ else {
+ s = bufend;
+ str_scat(tmpstr,linestr);
+ }
+ }
+ else
+ s = str_append_till(tmpstr,s,bufend,term,leave);
+ }
+ multi_end = curcmd->c_line;
+ s++;
+ if (tmpstr->str_cur + 5 < tmpstr->str_len) {
+ tmpstr->str_len = tmpstr->str_cur + 1;
+ Renew(tmpstr->str_ptr, tmpstr->str_len, char);
+ }
+ if (arg[1].arg_type == A_SINGLE) {
+ arg[1].arg_ptr.arg_str = tmpstr;
+ break;
+ }
+ tmps = s;
+ s = tmpstr->str_ptr;
+ send = s + tmpstr->str_cur;
+ while (s < send) { /* see if we can make SINGLE */
+ if (*s == '\\' && s[1] && isDIGIT(s[1]) && !isDIGIT(s[2]) &&
+ !alwaysdollar && s[1] != '0')
+ *s = '$'; /* grandfather \digit in subst */
+ if ((*s == '$' || *s == '@') && s+1 < send &&
+ (alwaysdollar || (s[1] != ')' && s[1] != '|'))) {
+ makesingle = FALSE; /* force interpretation */
+ }
+ else if (*s == '\\' && s+1 < send) {
+ if (index("lLuUE",s[1]))
+ makesingle = FALSE;
+ s++;
+ }
+ s++;
+ }
+ s = d = start = tmpstr->str_ptr; /* assuming shrinkage only */
+ while (s < send || dorange) {
+ if (in_what & SCAN_TR) {
+ if (dorange) {
+ int i;
+ int max;
+ if (!tmpstr2) { /* oops, have to grow */
+ tmpstr2 = str_smake(tmpstr);
+ s = tmpstr2->str_ptr + (s - tmpstr->str_ptr);
+ send = tmpstr2->str_ptr + (send - tmpstr->str_ptr);
+ }
+ i = d - tmpstr->str_ptr;
+ STR_GROW(tmpstr, tmpstr->str_len + 256);
+ d = tmpstr->str_ptr + i;
+ d -= 2;
+ max = d[1] & 0377;
+ for (i = (*d & 0377); i <= max; i++)
+ *d++ = i;
+ start = s;
+ dorange = FALSE;
+ continue;
+ }
+ else if (*s == '-' && s+1 < send && s != start) {
+ dorange = TRUE;
+ s++;
+ }
+ }
+ else {
+ if ((*s == '$' && s+1 < send &&
+ (alwaysdollar || /*(*/(s[1] != ')' && s[1] != '|')) ) ||
+ (*s == '@' && s+1 < send) ) {
+ if (s[1] == '#' && (isALPHA(s[2]) || s[2] == '_'))
+ *d++ = *s++;
+ len = scanident(s,send,tokenbuf) - s;
+ if (*s == '$' || strEQ(tokenbuf,"ARGV")
+ || strEQ(tokenbuf,"ENV")
+ || strEQ(tokenbuf,"SIG")
+ || strEQ(tokenbuf,"INC") )
+ (void)stabent(tokenbuf,TRUE); /* add symbol */
+ while (len--)
+ *d++ = *s++;
+ continue;
+ }
+ }
+ if (*s == '\\' && s+1 < send) {
+ s++;
+ switch (*s) {
+ case '-':
+ if (in_what & SCAN_TR) {
+ *d++ = *s++;
+ continue;
+ }
+ /* FALL THROUGH */
+ default:
+ if (!makesingle && (!leave || (*s && index(leave,*s))))
+ *d++ = '\\';
+ *d++ = *s++;
+ continue;
+ case '0': case '1': case '2': case '3':
+ case '4': case '5': case '6': case '7':
+ *d++ = scanoct(s, 3, &len);
+ s += len;
+ continue;
+ case 'x':
+ *d++ = scanhex(++s, 2, &len);
+ s += len;
+ continue;
+ case 'c':
+ s++;
+ *d = *s++;
+ if (isLOWER(*d))
+ *d = toupper(*d);
+ *d++ ^= 64;
+ continue;
+ case 'b':
+ *d++ = '\b';
+ break;
+ case 'n':
+ *d++ = '\n';
+ break;
+ case 'r':
+ *d++ = '\r';
+ break;
+ case 'f':
+ *d++ = '\f';
+ break;
+ case 't':
+ *d++ = '\t';
+ break;
+ case 'e':
+ *d++ = '\033';
+ break;
+ case 'a':
+ *d++ = '\007';
+ break;
+ }
+ s++;
+ continue;
+ }
+ *d++ = *s++;
+ }
+ *d = '\0';
+
+ if (arg[1].arg_type == A_DOUBLE && makesingle)
+ arg[1].arg_type = A_SINGLE; /* now we can optimize on it */
+
+ tmpstr->str_cur = d - tmpstr->str_ptr;
+ if (arg[1].arg_type == A_GLOB) {
+ arg[1].arg_ptr.arg_stab = stab = genstab();
+ stab_io(stab) = stio_new();
+ str_sset(stab_val(stab), tmpstr);
+ }
+ else
+ arg[1].arg_ptr.arg_str = tmpstr;
+ s = tmps;
+ if (tmpstr2)
+ str_free(tmpstr2);
+ break;
+ }
+ }
+ if (hereis)
+ str_free(herewas);
+ return s;
+}
+
+FCMD *
+load_format()
+{
+ FCMD froot;
+ FCMD *flinebeg;
+ char *eol;
+ register FCMD *fprev = &froot;
+ register FCMD *fcmd;
+ register char *s;
+ register char *t;
+ register STR *str;
+ bool noblank;
+ bool repeater;
+
+ Zero(&froot, 1, FCMD);
+ s = bufptr;
+ while (s < bufend || (rsfp && (s = str_gets(linestr,rsfp, 0)) != Nullch)) {
+ curcmd->c_line++;
+ if (in_eval && !rsfp) {
+ eol = index(s,'\n');
+ if (!eol++)
+ eol = bufend;
+ }
+ else
+ eol = bufend = linestr->str_ptr + linestr->str_cur;
+ if (perldb) {
+ STR *tmpstr = Str_new(89,0);
+
+ str_nset(tmpstr, s, eol-s);
+ astore(stab_xarray(curcmd->c_filestab), (int)curcmd->c_line,tmpstr);
+ }
+ if (*s == '.') {
+ /*SUPPRESS 530*/
+ for (t = s+1; *t == ' ' || *t == '\t'; t++) ;
+ if (*t == '\n') {
+ bufptr = s;
+ return froot.f_next;
+ }
+ }
+ if (*s == '#') {
+ s = eol;
+ continue;
+ }
+ flinebeg = Nullfcmd;
+ noblank = FALSE;
+ repeater = FALSE;
+ while (s < eol) {
+ Newz(804,fcmd,1,FCMD);
+ fprev->f_next = fcmd;
+ fprev = fcmd;
+ for (t=s; t < eol && *t != '@' && *t != '^'; t++) {
+ if (*t == '~') {
+ noblank = TRUE;
+ *t = ' ';
+ if (t[1] == '~') {
+ repeater = TRUE;
+ t[1] = ' ';
+ }
+ }
+ }
+ fcmd->f_pre = nsavestr(s, t-s);
+ fcmd->f_presize = t-s;
+ s = t;
+ if (s >= eol) {
+ if (noblank)
+ fcmd->f_flags |= FC_NOBLANK;
+ if (repeater)
+ fcmd->f_flags |= FC_REPEAT;
+ break;
+ }
+ if (!flinebeg)
+ flinebeg = fcmd; /* start values here */
+ if (*s++ == '^')
+ fcmd->f_flags |= FC_CHOP; /* for doing text filling */
+ switch (*s) {
+ case '*':
+ fcmd->f_type = F_LINES;
+ *s = '\0';
+ break;
+ case '<':
+ fcmd->f_type = F_LEFT;
+ while (*s == '<')
+ s++;
+ break;
+ case '>':
+ fcmd->f_type = F_RIGHT;
+ while (*s == '>')
+ s++;
+ break;
+ case '|':
+ fcmd->f_type = F_CENTER;
+ while (*s == '|')
+ s++;
+ break;
+ case '#':
+ case '.':
+ /* Catch the special case @... and handle it as a string
+ field. */
+ if (*s == '.' && s[1] == '.') {
+ goto default_format;
+ }
+ fcmd->f_type = F_DECIMAL;
+ {
+ char *p;
+
+ /* Read a format in the form @####.####, where either group
+ of ### may be empty, or the final .### may be missing. */
+ while (*s == '#')
+ s++;
+ if (*s == '.') {
+ s++;
+ p = s;
+ while (*s == '#')
+ s++;
+ fcmd->f_decimals = s-p;
+ fcmd->f_flags |= FC_DP;
+ } else {
+ fcmd->f_decimals = 0;
+ }
+ }
+ break;
+ default:
+ default_format:
+ fcmd->f_type = F_LEFT;
+ break;
+ }
+ if (fcmd->f_flags & FC_CHOP && *s == '.') {
+ fcmd->f_flags |= FC_MORE;
+ while (*s == '.')
+ s++;
+ }
+ fcmd->f_size = s-t;
+ }
+ if (flinebeg) {
+ again:
+ if (s >= bufend &&
+ (!rsfp || (s = str_gets(linestr, rsfp, 0)) == Nullch) )
+ goto badform;
+ curcmd->c_line++;
+ if (in_eval && !rsfp) {
+ eol = index(s,'\n');
+ if (!eol++)
+ eol = bufend;
+ }
+ else
+ eol = bufend = linestr->str_ptr + linestr->str_cur;
+ if (perldb) {
+ STR *tmpstr = Str_new(90,0);
+
+ str_nset(tmpstr, s, eol-s);
+ astore(stab_xarray(curcmd->c_filestab),
+ (int)curcmd->c_line,tmpstr);
+ }
+ if (strnEQ(s,".\n",2)) {
+ bufptr = s;
+ yyerror("Missing values line");
+ return froot.f_next;
+ }
+ if (*s == '#') {
+ s = eol;
+ goto again;
+ }
+ str = flinebeg->f_unparsed = Str_new(91,eol - s);
+ str->str_u.str_hash = curstash;
+ str_nset(str,"(",1);
+ flinebeg->f_line = curcmd->c_line;
+ eol[-1] = '\0';
+ if (!flinebeg->f_next->f_type || index(s, ',')) {
+ eol[-1] = '\n';
+ str_ncat(str, s, eol - s - 1);
+ str_ncat(str,",$$);",5);
+ s = eol;
+ }
+ else {
+ eol[-1] = '\n';
+ while (s < eol && isSPACE(*s))
+ s++;
+ t = s;
+ while (s < eol) {
+ switch (*s) {
+ case ' ': case '\t': case '\n': case ';':
+ str_ncat(str, t, s - t);
+ str_ncat(str, "," ,1);
+ while (s < eol && (isSPACE(*s) || *s == ';'))
+ s++;
+ t = s;
+ break;
+ case '$':
+ str_ncat(str, t, s - t);
+ t = s;
+ s = scanident(s,eol,tokenbuf);
+ str_ncat(str, t, s - t);
+ t = s;
+ if (s < eol && *s && index("$'\"",*s))
+ str_ncat(str, ",", 1);
+ break;
+ case '"': case '\'':
+ str_ncat(str, t, s - t);
+ t = s;
+ s++;
+ while (s < eol && (*s != *t || s[-1] == '\\'))
+ s++;
+ if (s < eol)
+ s++;
+ str_ncat(str, t, s - t);
+ t = s;
+ if (s < eol && *s && index("$'\"",*s))
+ str_ncat(str, ",", 1);
+ break;
+ default:
+ yyerror("Please use commas to separate fields");
+ }
+ }
+ str_ncat(str,"$$);",4);
+ }
+ }
+ }
+ badform:
+ bufptr = str_get(linestr);
+ yyerror("Format not terminated");
+ return froot.f_next;
+}
+
+static void
+set_csh()
+{
+#ifdef CSH
+ if (!cshlen)
+ cshlen = strlen(cshname);
+#endif
+}
diff --git a/gnu/usr.bin/perl/perl/usersub.c b/gnu/usr.bin/perl/perl/usersub.c
new file mode 100644
index 0000000..8c7cb65
--- /dev/null
+++ b/gnu/usr.bin/perl/perl/usersub.c
@@ -0,0 +1,151 @@
+/* $RCSfile: usersub.c,v $$Revision: 1.1.1.1 $$Date: 1994/09/10 06:27:34 $
+ *
+ * This file contains stubs for routines that the user may define to
+ * set up glue routines for C libraries or to decrypt encrypted scripts
+ * for execution.
+ *
+ * $Log: usersub.c,v $
+ * Revision 1.1.1.1 1994/09/10 06:27:34 gclarkii
+ * Initial import of Perl 4.046 bmaked
+ *
+ * Revision 1.1.1.1 1993/08/23 21:29:40 nate
+ * PERL!
+ *
+ * Revision 4.0.1.2 92/06/08 16:04:24 lwall
+ * patch20: removed implicit int declarations on functions
+ *
+ * Revision 4.0.1.1 91/11/11 16:47:17 lwall
+ * patch19: deleted some unused functions from usersub.c
+ *
+ * Revision 4.0 91/03/20 01:55:56 lwall
+ * 4.0 baseline.
+ *
+ */
+
+#include "EXTERN.h"
+#include "perl.h"
+
+int
+userinit()
+{
+ return 0;
+}
+
+/*
+ * The following is supplied by John Macdonald as a means of decrypting
+ * and executing (presumably proprietary) scripts that have been encrypted
+ * by a (presumably secret) method. The idea is that you supply your own
+ * routine in place of cryptfilter (which is purposefully a very weak
+ * encryption). If an encrypted script is detected, a process is forked
+ * off to run the cryptfilter routine as input to perl.
+ */
+
+#ifdef CRYPTSCRIPT
+
+#include <signal.h>
+#ifdef I_VFORK
+#include <vfork.h>
+#endif
+
+#ifdef CRYPTLOCAL
+
+#include "cryptlocal.h"
+
+#else /* ndef CRYPTLOCAL */
+
+#define CRYPT_MAGIC_1 0xfb
+#define CRYPT_MAGIC_2 0xf1
+
+void
+cryptfilter( fil )
+FILE * fil;
+{
+ int ch;
+
+ while( (ch = getc( fil )) != EOF ) {
+ putchar( (ch ^ 0x80) );
+ }
+}
+
+#endif /* CRYPTLOCAL */
+
+#ifndef MSDOS
+static FILE *lastpipefile;
+static int pipepid;
+
+#ifdef VOIDSIG
+# define VOID void
+#else
+# define VOID int
+#endif
+
+FILE *
+mypfiopen(fil,func) /* open a pipe to function call for input */
+FILE *fil;
+VOID (*func)();
+{
+ int p[2];
+ STR *str;
+
+ if (pipe(p) < 0) {
+ fclose( fil );
+ fatal("Can't get pipe for decrypt");
+ }
+
+ /* make sure that the child doesn't get anything extra */
+ fflush(stdout);
+ fflush(stderr);
+
+ while ((pipepid = fork()) < 0) {
+ if (errno != EAGAIN) {
+ close(p[0]);
+ close(p[1]);
+ fclose( fil );
+ fatal("Can't fork for decrypt");
+ }
+ sleep(5);
+ }
+ if (pipepid == 0) {
+ close(p[0]);
+ if (p[1] != 1) {
+ dup2(p[1], 1);
+ close(p[1]);
+ }
+ (*func)(fil);
+ fflush(stdout);
+ fflush(stderr);
+ _exit(0);
+ }
+ close(p[1]);
+ close(fileno(fil));
+ fclose(fil);
+ str = afetch(fdpid,p[0],TRUE);
+ str->str_u.str_useful = pipepid;
+ return fdopen(p[0], "r");
+}
+
+void
+cryptswitch()
+{
+ int ch;
+#ifdef STDSTDIO
+ /* cheat on stdio if possible */
+ if (rsfp->_cnt > 0 && (*rsfp->_ptr & 0xff) != CRYPT_MAGIC_1)
+ return;
+#endif
+ ch = getc(rsfp);
+ if (ch == CRYPT_MAGIC_1) {
+ if (getc(rsfp) == CRYPT_MAGIC_2) {
+ if( perldb ) fatal("can't debug an encrypted script");
+ rsfp = mypfiopen( rsfp, cryptfilter );
+ preprocess = 1; /* force call to pclose when done */
+ }
+ else
+ fatal( "bad encryption format" );
+ }
+ else
+ ungetc(ch,rsfp);
+}
+#endif /* !MSDOS */
+
+#endif /* CRYPTSCRIPT */
diff --git a/gnu/usr.bin/perl/perl/util.c b/gnu/usr.bin/perl/perl/util.c
new file mode 100644
index 0000000..fd4b436
--- /dev/null
+++ b/gnu/usr.bin/perl/perl/util.c
@@ -0,0 +1,1783 @@
+/* $RCSfile: util.c,v $$Revision: 1.1.1.1 $$Date: 1994/09/10 06:27:34 $
+ *
+ * Copyright (c) 1991, Larry Wall
+ *
+ * You may distribute under the terms of either the GNU General Public
+ * License or the Artistic License, as specified in the README file.
+ *
+ * $Log: util.c,v $
+ * Revision 1.1.1.1 1994/09/10 06:27:34 gclarkii
+ * Initial import of Perl 4.046 bmaked
+ *
+ * Revision 1.1.1.1 1993/08/23 21:29:40 nate
+ * PERL!
+ *
+ * Revision 4.0.1.6 92/06/11 21:18:47 lwall
+ * patch34: boneheaded typo in my_bcopy()
+ *
+ * Revision 4.0.1.5 92/06/08 16:08:37 lwall
+ * patch20: removed implicit int declarations on functions
+ * patch20: Perl now distinguishes overlapped copies from non-overlapped
+ * patch20: fixed confusion between a *var's real name and its effective name
+ * patch20: bcopy() and memcpy() now tested for overlap safety
+ * patch20: added Atari ST portability
+ *
+ * Revision 4.0.1.4 91/11/11 16:48:54 lwall
+ * patch19: study was busted by 4.018
+ * patch19: added little-endian pack/unpack options
+ *
+ * Revision 4.0.1.3 91/11/05 19:18:26 lwall
+ * patch11: safe malloc code now integrated into Perl's malloc when possible
+ * patch11: index("little", "longer string") could visit faraway places
+ * patch11: warn '-' x 10000 dumped core
+ * patch11: forked exec on non-existent program now issues a warning
+ *
+ * Revision 4.0.1.2 91/06/07 12:10:42 lwall
+ * patch4: new copyright notice
+ * patch4: made some allowances for "semi-standard" C
+ * patch4: index() could blow up searching for null string
+ * patch4: taintchecks could improperly modify parent in vfork()
+ * patch4: exec would close files even if you cleared close-on-exec flag
+ *
+ * Revision 4.0.1.1 91/04/12 09:19:25 lwall
+ * patch1: random cleanup in cpp namespace
+ *
+ * Revision 4.0 91/03/20 01:56:39 lwall
+ * 4.0 baseline.
+ *
+ */
+/*SUPPRESS 112*/
+
+#include "EXTERN.h"
+#include "perl.h"
+
+#if !defined(NSIG) || defined(M_UNIX) || defined(M_XENIX)
+#include <signal.h>
+#endif
+
+#ifdef I_VFORK
+# include <vfork.h>
+#endif
+
+#ifdef I_VARARGS
+# include <varargs.h>
+#endif
+
+#ifdef I_FCNTL
+# include <fcntl.h>
+#endif
+#ifdef I_SYS_FILE
+# include <sys/file.h>
+#endif
+
+#define FLUSH
+
+#ifndef safemalloc
+
+static char nomem[] = "Out of memory!\n";
+
+/* paranoid version of malloc */
+
+#ifdef DEBUGGING
+static int an = 0;
+#endif
+
+/* NOTE: Do not call the next three routines directly. Use the macros
+ * in handy.h, so that we can easily redefine everything to do tracking of
+ * allocated hunks back to the original New to track down any memory leaks.
+ */
+
+char *
+safemalloc(size)
+#ifdef MSDOS
+unsigned long size;
+#else
+MEM_SIZE size;
+#endif /* MSDOS */
+{
+ char *ptr;
+#ifndef STANDARD_C
+ char *malloc();
+#endif /* ! STANDARD_C */
+
+#ifdef MSDOS
+ if (size > 0xffff) {
+ fprintf(stderr, "Allocation too large: %lx\n", size) FLUSH;
+ exit(1);
+ }
+#endif /* MSDOS */
+#ifdef DEBUGGING
+ if ((long)size < 0)
+ fatal("panic: malloc");
+#endif
+ ptr = malloc(size?size:1); /* malloc(0) is NASTY on our system */
+#ifdef DEBUGGING
+# if !(defined(I286) || defined(atarist))
+ if (debug & 128)
+ fprintf(stderr,"0x%x: (%05d) malloc %ld bytes\n",ptr,an++,(long)size);
+# else
+ if (debug & 128)
+ fprintf(stderr,"0x%lx: (%05d) malloc %ld bytes\n",ptr,an++,(long)size);
+# endif
+#endif
+ if (ptr != Nullch)
+ return ptr;
+ else if (nomemok)
+ return Nullch;
+ else {
+ fputs(nomem,stderr) FLUSH;
+ exit(1);
+ }
+ /*NOTREACHED*/
+#ifdef lint
+ return ptr;
+#endif
+}
+
+/* paranoid version of realloc */
+
+char *
+saferealloc(where,size)
+char *where;
+#ifndef MSDOS
+MEM_SIZE size;
+#else
+unsigned long size;
+#endif /* MSDOS */
+{
+ char *ptr;
+#ifndef STANDARD_C
+ char *realloc();
+#endif /* ! STANDARD_C */
+
+#ifdef MSDOS
+ if (size > 0xffff) {
+ fprintf(stderr, "Reallocation too large: %lx\n", size) FLUSH;
+ exit(1);
+ }
+#endif /* MSDOS */
+ if (!where)
+ fatal("Null realloc");
+#ifdef DEBUGGING
+ if ((long)size < 0)
+ fatal("panic: realloc");
+#endif
+ ptr = realloc(where,size?size:1); /* realloc(0) is NASTY on our system */
+#ifdef DEBUGGING
+# if !(defined(I286) || defined(atarist))
+ if (debug & 128) {
+ fprintf(stderr,"0x%x: (%05d) rfree\n",where,an++);
+ fprintf(stderr,"0x%x: (%05d) realloc %ld bytes\n",ptr,an++,(long)size);
+ }
+# else
+ if (debug & 128) {
+ fprintf(stderr,"0x%lx: (%05d) rfree\n",where,an++);
+ fprintf(stderr,"0x%lx: (%05d) realloc %ld bytes\n",ptr,an++,(long)size);
+ }
+# endif
+#endif
+ if (ptr != Nullch)
+ return ptr;
+ else if (nomemok)
+ return Nullch;
+ else {
+ fputs(nomem,stderr) FLUSH;
+ exit(1);
+ }
+ /*NOTREACHED*/
+#ifdef lint
+ return ptr;
+#endif
+}
+
+/* safe version of free */
+
+void
+safefree(where)
+char *where;
+{
+#ifdef DEBUGGING
+# if !(defined(I286) || defined(atarist))
+ if (debug & 128)
+ fprintf(stderr,"0x%x: (%05d) free\n",where,an++);
+# else
+ if (debug & 128)
+ fprintf(stderr,"0x%lx: (%05d) free\n",where,an++);
+# endif
+#endif
+ if (where) {
+ /*SUPPRESS 701*/
+ free(where);
+ }
+}
+
+#endif /* !safemalloc */
+
+#ifdef LEAKTEST
+
+#define ALIGN sizeof(long)
+
+char *
+safexmalloc(x,size)
+int x;
+MEM_SIZE size;
+{
+ register char *where;
+
+ where = safemalloc(size + ALIGN);
+ xcount[x]++;
+ where[0] = x % 100;
+ where[1] = x / 100;
+ return where + ALIGN;
+}
+
+char *
+safexrealloc(where,size)
+char *where;
+MEM_SIZE size;
+{
+ return saferealloc(where - ALIGN, size + ALIGN) + ALIGN;
+}
+
+void
+safexfree(where)
+char *where;
+{
+ int x;
+
+ if (!where)
+ return;
+ where -= ALIGN;
+ x = where[0] + 100 * where[1];
+ xcount[x]--;
+ safefree(where);
+}
+
+static void
+xstat()
+{
+ register int i;
+
+ for (i = 0; i < MAXXCOUNT; i++) {
+ if (xcount[i] > lastxcount[i]) {
+ fprintf(stderr,"%2d %2d\t%ld\n", i / 100, i % 100, xcount[i]);
+ lastxcount[i] = xcount[i];
+ }
+ }
+}
+
+#endif /* LEAKTEST */
+
+/* copy a string up to some (non-backslashed) delimiter, if any */
+
+char *
+cpytill(to,from,fromend,delim,retlen)
+register char *to;
+register char *from;
+register char *fromend;
+register int delim;
+int *retlen;
+{
+ char *origto = to;
+
+ for (; from < fromend; from++,to++) {
+ if (*from == '\\') {
+ if (from[1] == delim)
+ from++;
+ else if (from[1] == '\\')
+ *to++ = *from++;
+ }
+ else if (*from == delim)
+ break;
+ *to = *from;
+ }
+ *to = '\0';
+ *retlen = to - origto;
+ return from;
+}
+
+/* return ptr to little string in big string, NULL if not found */
+/* This routine was donated by Corey Satten. */
+
+char *
+instr(big, little)
+register char *big;
+register char *little;
+{
+ register char *s, *x;
+ register int first;
+
+ if (!little)
+ return big;
+ first = *little++;
+ if (!first)
+ return big;
+ while (*big) {
+ if (*big++ != first)
+ continue;
+ for (x=big,s=little; *s; /**/ ) {
+ if (!*x)
+ return Nullch;
+ if (*s++ != *x++) {
+ s--;
+ break;
+ }
+ }
+ if (!*s)
+ return big-1;
+ }
+ return Nullch;
+}
+
+/* same as instr but allow embedded nulls */
+
+char *
+ninstr(big, bigend, little, lend)
+register char *big;
+register char *bigend;
+char *little;
+char *lend;
+{
+ register char *s, *x;
+ register int first = *little;
+ register char *littleend = lend;
+
+ if (!first && little > littleend)
+ return big;
+ if (bigend - big < littleend - little)
+ return Nullch;
+ bigend -= littleend - little++;
+ while (big <= bigend) {
+ if (*big++ != first)
+ continue;
+ for (x=big,s=little; s < littleend; /**/ ) {
+ if (*s++ != *x++) {
+ s--;
+ break;
+ }
+ }
+ if (s >= littleend)
+ return big-1;
+ }
+ return Nullch;
+}
+
+/* reverse of the above--find last substring */
+
+char *
+rninstr(big, bigend, little, lend)
+register char *big;
+char *bigend;
+char *little;
+char *lend;
+{
+ register char *bigbeg;
+ register char *s, *x;
+ register int first = *little;
+ register char *littleend = lend;
+
+ if (!first && little > littleend)
+ return bigend;
+ bigbeg = big;
+ big = bigend - (littleend - little++);
+ while (big >= bigbeg) {
+ if (*big-- != first)
+ continue;
+ for (x=big+2,s=little; s < littleend; /**/ ) {
+ if (*s++ != *x++) {
+ s--;
+ break;
+ }
+ }
+ if (s >= littleend)
+ return big+1;
+ }
+ return Nullch;
+}
+
+unsigned char fold[] = {
+ 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, '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', 91, 92, 93, 94, 95,
+ 96, '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', 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
+};
+
+static unsigned char freq[] = {
+ 1, 2, 84, 151, 154, 155, 156, 157,
+ 165, 246, 250, 3, 158, 7, 18, 29,
+ 40, 51, 62, 73, 85, 96, 107, 118,
+ 129, 140, 147, 148, 149, 150, 152, 153,
+ 255, 182, 224, 205, 174, 176, 180, 217,
+ 233, 232, 236, 187, 235, 228, 234, 226,
+ 222, 219, 211, 195, 188, 193, 185, 184,
+ 191, 183, 201, 229, 181, 220, 194, 162,
+ 163, 208, 186, 202, 200, 218, 198, 179,
+ 178, 214, 166, 170, 207, 199, 209, 206,
+ 204, 160, 212, 216, 215, 192, 175, 173,
+ 243, 172, 161, 190, 203, 189, 164, 230,
+ 167, 248, 227, 244, 242, 255, 241, 231,
+ 240, 253, 169, 210, 245, 237, 249, 247,
+ 239, 168, 252, 251, 254, 238, 223, 221,
+ 213, 225, 177, 197, 171, 196, 159, 4,
+ 5, 6, 8, 9, 10, 11, 12, 13,
+ 14, 15, 16, 17, 19, 20, 21, 22,
+ 23, 24, 25, 26, 27, 28, 30, 31,
+ 32, 33, 34, 35, 36, 37, 38, 39,
+ 41, 42, 43, 44, 45, 46, 47, 48,
+ 49, 50, 52, 53, 54, 55, 56, 57,
+ 58, 59, 60, 61, 63, 64, 65, 66,
+ 67, 68, 69, 70, 71, 72, 74, 75,
+ 76, 77, 78, 79, 80, 81, 82, 83,
+ 86, 87, 88, 89, 90, 91, 92, 93,
+ 94, 95, 97, 98, 99, 100, 101, 102,
+ 103, 104, 105, 106, 108, 109, 110, 111,
+ 112, 113, 114, 115, 116, 117, 119, 120,
+ 121, 122, 123, 124, 125, 126, 127, 128,
+ 130, 131, 132, 133, 134, 135, 136, 137,
+ 138, 139, 141, 142, 143, 144, 145, 146
+};
+
+void
+fbmcompile(str, iflag)
+STR *str;
+int iflag;
+{
+ register unsigned char *s;
+ register unsigned char *table;
+ register unsigned int i;
+ register unsigned int len = str->str_cur;
+ int rarest = 0;
+ unsigned int frequency = 256;
+
+ Str_Grow(str,len+258);
+#ifndef lint
+ table = (unsigned char*)(str->str_ptr + len + 1);
+#else
+ table = Null(unsigned char*);
+#endif
+ s = table - 2;
+ for (i = 0; i < 256; i++) {
+ table[i] = len;
+ }
+ i = 0;
+#ifndef lint
+ while (s >= (unsigned char*)(str->str_ptr))
+#endif
+ {
+ if (table[*s] == len) {
+#ifndef pdp11
+ if (iflag)
+ table[*s] = table[fold[*s]] = i;
+#else
+ if (iflag) {
+ int j;
+ j = fold[*s];
+ table[j] = i;
+ table[*s] = i;
+ }
+#endif /* pdp11 */
+ else
+ table[*s] = i;
+ }
+ s--,i++;
+ }
+ str->str_pok |= SP_FBM; /* deep magic */
+
+#ifndef lint
+ s = (unsigned char*)(str->str_ptr); /* deeper magic */
+#else
+ s = Null(unsigned char*);
+#endif
+ if (iflag) {
+ register unsigned int tmp, foldtmp;
+ str->str_pok |= SP_CASEFOLD;
+ for (i = 0; i < len; i++) {
+ tmp=freq[s[i]];
+ foldtmp=freq[fold[s[i]]];
+ if (tmp < frequency && foldtmp < frequency) {
+ rarest = i;
+ /* choose most frequent among the two */
+ frequency = (tmp > foldtmp) ? tmp : foldtmp;
+ }
+ }
+ }
+ else {
+ for (i = 0; i < len; i++) {
+ if (freq[s[i]] < frequency) {
+ rarest = i;
+ frequency = freq[s[i]];
+ }
+ }
+ }
+ str->str_rare = s[rarest];
+ str->str_state = rarest;
+#ifdef DEBUGGING
+ if (debug & 512)
+ fprintf(stderr,"rarest char %c at %d\n",str->str_rare, str->str_state);
+#endif
+}
+
+char *
+fbminstr(big, bigend, littlestr)
+unsigned char *big;
+register unsigned char *bigend;
+STR *littlestr;
+{
+ register unsigned char *s;
+ register int tmp;
+ register int littlelen;
+ register unsigned char *little;
+ register unsigned char *table;
+ register unsigned char *olds;
+ register unsigned char *oldlittle;
+
+#ifndef lint
+ if (!(littlestr->str_pok & SP_FBM)) {
+ if (!littlestr->str_ptr)
+ return (char*)big;
+ return ninstr((char*)big,(char*)bigend,
+ littlestr->str_ptr, littlestr->str_ptr + littlestr->str_cur);
+ }
+#endif
+
+ littlelen = littlestr->str_cur;
+#ifndef lint
+ if (littlestr->str_pok & SP_TAIL && !multiline) { /* tail anchored? */
+ if (littlelen > bigend - big)
+ return Nullch;
+ little = (unsigned char*)littlestr->str_ptr;
+ if (littlestr->str_pok & SP_CASEFOLD) { /* oops, fake it */
+ big = bigend - littlelen; /* just start near end */
+ if (bigend[-1] == '\n' && little[littlelen-1] != '\n')
+ big--;
+ }
+ else {
+ s = bigend - littlelen;
+ if (*s == *little && bcmp(s,little,littlelen)==0)
+ return (char*)s; /* how sweet it is */
+ else if (bigend[-1] == '\n' && little[littlelen-1] != '\n'
+ && s > big) {
+ s--;
+ if (*s == *little && bcmp(s,little,littlelen)==0)
+ return (char*)s;
+ }
+ return Nullch;
+ }
+ }
+ table = (unsigned char*)(littlestr->str_ptr + littlelen + 1);
+#else
+ table = Null(unsigned char*);
+#endif
+ if (--littlelen >= bigend - big)
+ return Nullch;
+ s = big + littlelen;
+ oldlittle = little = table - 2;
+ if (littlestr->str_pok & SP_CASEFOLD) { /* case insensitive? */
+ if (s < bigend) {
+ top1:
+ /*SUPPRESS 560*/
+ if (tmp = table[*s]) {
+#ifdef POINTERRIGOR
+ if (bigend - s > tmp) {
+ s += tmp;
+ goto top1;
+ }
+#else
+ if ((s += tmp) < bigend)
+ goto top1;
+#endif
+ return Nullch;
+ }
+ else {
+ tmp = littlelen; /* less expensive than calling strncmp() */
+ olds = s;
+ while (tmp--) {
+ if (*--s == *--little || fold[*s] == *little)
+ continue;
+ s = olds + 1; /* here we pay the price for failure */
+ little = oldlittle;
+ if (s < bigend) /* fake up continue to outer loop */
+ goto top1;
+ return Nullch;
+ }
+#ifndef lint
+ return (char *)s;
+#endif
+ }
+ }
+ }
+ else {
+ if (s < bigend) {
+ top2:
+ /*SUPPRESS 560*/
+ if (tmp = table[*s]) {
+#ifdef POINTERRIGOR
+ if (bigend - s > tmp) {
+ s += tmp;
+ goto top2;
+ }
+#else
+ if ((s += tmp) < bigend)
+ goto top2;
+#endif
+ return Nullch;
+ }
+ else {
+ tmp = littlelen; /* less expensive than calling strncmp() */
+ olds = s;
+ while (tmp--) {
+ if (*--s == *--little)
+ continue;
+ s = olds + 1; /* here we pay the price for failure */
+ little = oldlittle;
+ if (s < bigend) /* fake up continue to outer loop */
+ goto top2;
+ return Nullch;
+ }
+#ifndef lint
+ return (char *)s;
+#endif
+ }
+ }
+ }
+ return Nullch;
+}
+
+char *
+screaminstr(bigstr, littlestr)
+STR *bigstr;
+STR *littlestr;
+{
+ register unsigned char *s, *x;
+ register unsigned char *big;
+ register int pos;
+ register int previous;
+ register int first;
+ register unsigned char *little;
+ register unsigned char *bigend;
+ register unsigned char *littleend;
+
+ if ((pos = screamfirst[littlestr->str_rare]) < 0)
+ return Nullch;
+#ifndef lint
+ little = (unsigned char *)(littlestr->str_ptr);
+#else
+ little = Null(unsigned char *);
+#endif
+ littleend = little + littlestr->str_cur;
+ first = *little++;
+ previous = littlestr->str_state;
+#ifndef lint
+ big = (unsigned char *)(bigstr->str_ptr);
+#else
+ big = Null(unsigned char*);
+#endif
+ bigend = big + bigstr->str_cur;
+ while (pos < previous) {
+#ifndef lint
+ if (!(pos += screamnext[pos]))
+#endif
+ return Nullch;
+ }
+#ifdef POINTERRIGOR
+ if (littlestr->str_pok & SP_CASEFOLD) { /* case insignificant? */
+ do {
+ if (big[pos-previous] != first && big[pos-previous] != fold[first])
+ continue;
+ for (x=big+pos+1-previous,s=little; s < littleend; /**/ ) {
+ if (x >= bigend)
+ return Nullch;
+ if (*s++ != *x++ && fold[*(s-1)] != *(x-1)) {
+ s--;
+ break;
+ }
+ }
+ if (s == littleend)
+#ifndef lint
+ return (char *)(big+pos-previous);
+#else
+ return Nullch;
+#endif
+ } while (
+#ifndef lint
+ pos += screamnext[pos] /* does this goof up anywhere? */
+#else
+ pos += screamnext[0]
+#endif
+ );
+ }
+ else {
+ do {
+ if (big[pos-previous] != first)
+ continue;
+ for (x=big+pos+1-previous,s=little; s < littleend; /**/ ) {
+ if (x >= bigend)
+ return Nullch;
+ if (*s++ != *x++) {
+ s--;
+ break;
+ }
+ }
+ if (s == littleend)
+#ifndef lint
+ return (char *)(big+pos-previous);
+#else
+ return Nullch;
+#endif
+ } while (
+#ifndef lint
+ pos += screamnext[pos]
+#else
+ pos += screamnext[0]
+#endif
+ );
+ }
+#else /* !POINTERRIGOR */
+ big -= previous;
+ if (littlestr->str_pok & SP_CASEFOLD) { /* case insignificant? */
+ do {
+ if (big[pos] != first && big[pos] != fold[first])
+ continue;
+ for (x=big+pos+1,s=little; s < littleend; /**/ ) {
+ if (x >= bigend)
+ return Nullch;
+ if (*s++ != *x++ && fold[*(s-1)] != *(x-1)) {
+ s--;
+ break;
+ }
+ }
+ if (s == littleend)
+#ifndef lint
+ return (char *)(big+pos);
+#else
+ return Nullch;
+#endif
+ } while (
+#ifndef lint
+ pos += screamnext[pos] /* does this goof up anywhere? */
+#else
+ pos += screamnext[0]
+#endif
+ );
+ }
+ else {
+ do {
+ if (big[pos] != first)
+ continue;
+ for (x=big+pos+1,s=little; s < littleend; /**/ ) {
+ if (x >= bigend)
+ return Nullch;
+ if (*s++ != *x++) {
+ s--;
+ break;
+ }
+ }
+ if (s == littleend)
+#ifndef lint
+ return (char *)(big+pos);
+#else
+ return Nullch;
+#endif
+ } while (
+#ifndef lint
+ pos += screamnext[pos]
+#else
+ pos += screamnext[0]
+#endif
+ );
+ }
+#endif /* POINTERRIGOR */
+ return Nullch;
+}
+
+/* copy a string to a safe spot */
+
+char *
+savestr(str)
+char *str;
+{
+ register char *newaddr;
+
+ New(902,newaddr,strlen(str)+1,char);
+ (void)strcpy(newaddr,str);
+ return newaddr;
+}
+
+/* same thing but with a known length */
+
+char *
+nsavestr(str, len)
+char *str;
+register int len;
+{
+ register char *newaddr;
+
+ New(903,newaddr,len+1,char);
+ Copy(str,newaddr,len,char); /* might not be null terminated */
+ newaddr[len] = '\0'; /* is now */
+ return newaddr;
+}
+
+/* grow a static string to at least a certain length */
+
+void
+growstr(strptr,curlen,newlen)
+char **strptr;
+int *curlen;
+int newlen;
+{
+ if (newlen > *curlen) { /* need more room? */
+ if (*curlen)
+ Renew(*strptr,newlen,char);
+ else
+ New(905,*strptr,newlen,char);
+ *curlen = newlen;
+ }
+}
+
+#ifndef I_VARARGS
+/*VARARGS1*/
+char *
+mess(pat,a1,a2,a3,a4)
+char *pat;
+long a1, a2, a3, a4;
+{
+ char *s;
+ int usermess = strEQ(pat,"%s");
+ STR *tmpstr;
+
+ s = buf;
+ if (usermess) {
+ tmpstr = str_mortal(&str_undef);
+ str_set(tmpstr, (char*)a1);
+ *s++ = tmpstr->str_ptr[tmpstr->str_cur-1];
+ }
+ else {
+ (void)sprintf(s,pat,a1,a2,a3,a4);
+ s += strlen(s);
+ }
+
+ if (s[-1] != '\n') {
+ if (curcmd->c_line) {
+ (void)sprintf(s," at %s line %ld",
+ stab_val(curcmd->c_filestab)->str_ptr, (long)curcmd->c_line);
+ s += strlen(s);
+ }
+ if (last_in_stab &&
+ stab_io(last_in_stab) &&
+ stab_io(last_in_stab)->lines ) {
+ (void)sprintf(s,", <%s> line %ld",
+ last_in_stab == argvstab ? "" : stab_ename(last_in_stab),
+ (long)stab_io(last_in_stab)->lines);
+ s += strlen(s);
+ }
+ (void)strcpy(s,".\n");
+ if (usermess)
+ str_cat(tmpstr,buf+1);
+ }
+ if (usermess)
+ return tmpstr->str_ptr;
+ else
+ return buf;
+}
+
+/*VARARGS1*/
+void fatal(pat,a1,a2,a3,a4)
+char *pat;
+long a1, a2, a3, a4;
+{
+ extern FILE *e_fp;
+ extern char *e_tmpname;
+ char *tmps;
+ char *message;
+
+ message = mess(pat,a1,a2,a3,a4);
+ if (in_eval) {
+ str_set(stab_val(stabent("@",TRUE)),message);
+ tmps = "_EVAL_";
+ while (loop_ptr >= 0 && (!loop_stack[loop_ptr].loop_label ||
+ strNE(tmps,loop_stack[loop_ptr].loop_label) )) {
+#ifdef DEBUGGING
+ if (debug & 4) {
+ deb("(Skipping label #%d %s)\n",loop_ptr,
+ loop_stack[loop_ptr].loop_label);
+ }
+#endif
+ loop_ptr--;
+ }
+#ifdef DEBUGGING
+ if (debug & 4) {
+ deb("(Found label #%d %s)\n",loop_ptr,
+ loop_stack[loop_ptr].loop_label);
+ }
+#endif
+ if (loop_ptr < 0) {
+ in_eval = 0;
+ fatal("Bad label: %s", tmps);
+ }
+ longjmp(loop_stack[loop_ptr].loop_env, 1);
+ }
+ fputs(message,stderr);
+ (void)fflush(stderr);
+ if (e_fp)
+ (void)UNLINK(e_tmpname);
+ statusvalue >>= 8;
+ exit((int)((errno&255)?errno:((statusvalue&255)?statusvalue:255)));
+}
+
+/*VARARGS1*/
+void warn(pat,a1,a2,a3,a4)
+char *pat;
+long a1, a2, a3, a4;
+{
+ char *message;
+
+ message = mess(pat,a1,a2,a3,a4);
+ fputs(message,stderr);
+#ifdef LEAKTEST
+#ifdef DEBUGGING
+ if (debug & 4096)
+ xstat();
+#endif
+#endif
+ (void)fflush(stderr);
+}
+#else
+/*VARARGS0*/
+char *
+mess(args)
+va_list args;
+{
+ char *pat;
+ char *s;
+ STR *tmpstr;
+ int usermess;
+#ifndef HAS_VPRINTF
+#ifdef CHARVSPRINTF
+ char *vsprintf();
+#else
+ int vsprintf();
+#endif
+#endif
+
+#ifdef lint
+ pat = Nullch;
+#else
+ pat = va_arg(args, char *);
+#endif
+ s = buf;
+ usermess = strEQ(pat, "%s");
+ if (usermess) {
+ tmpstr = str_mortal(&str_undef);
+ str_set(tmpstr, va_arg(args, char *));
+ *s++ = tmpstr->str_ptr[tmpstr->str_cur-1];
+ }
+ else {
+ (void) vsprintf(s,pat,args);
+ s += strlen(s);
+ }
+
+ if (s[-1] != '\n') {
+ if (curcmd->c_line) {
+ (void)sprintf(s," at %s line %ld",
+ stab_val(curcmd->c_filestab)->str_ptr, (long)curcmd->c_line);
+ s += strlen(s);
+ }
+ if (last_in_stab &&
+ stab_io(last_in_stab) &&
+ stab_io(last_in_stab)->lines ) {
+ (void)sprintf(s,", <%s> line %ld",
+ last_in_stab == argvstab ? "" : last_in_stab->str_magic->str_ptr,
+ (long)stab_io(last_in_stab)->lines);
+ s += strlen(s);
+ }
+ (void)strcpy(s,".\n");
+ if (usermess)
+ str_cat(tmpstr,buf+1);
+ }
+
+ if (usermess)
+ return tmpstr->str_ptr;
+ else
+ return buf;
+}
+
+/*VARARGS0*/
+void fatal(va_alist)
+va_dcl
+{
+ va_list args;
+ extern FILE *e_fp;
+ extern char *e_tmpname;
+ char *tmps;
+ char *message;
+
+#ifndef lint
+ va_start(args);
+#else
+ args = 0;
+#endif
+ message = mess(args);
+ va_end(args);
+ if (in_eval) {
+ str_set(stab_val(stabent("@",TRUE)),message);
+ tmps = "_EVAL_";
+ while (loop_ptr >= 0 && (!loop_stack[loop_ptr].loop_label ||
+ strNE(tmps,loop_stack[loop_ptr].loop_label) )) {
+#ifdef DEBUGGING
+ if (debug & 4) {
+ deb("(Skipping label #%d %s)\n",loop_ptr,
+ loop_stack[loop_ptr].loop_label);
+ }
+#endif
+ loop_ptr--;
+ }
+#ifdef DEBUGGING
+ if (debug & 4) {
+ deb("(Found label #%d %s)\n",loop_ptr,
+ loop_stack[loop_ptr].loop_label);
+ }
+#endif
+ if (loop_ptr < 0) {
+ in_eval = 0;
+ fatal("Bad label: %s", tmps);
+ }
+ longjmp(loop_stack[loop_ptr].loop_env, 1);
+ }
+ fputs(message,stderr);
+ (void)fflush(stderr);
+ if (e_fp)
+ (void)UNLINK(e_tmpname);
+ statusvalue >>= 8;
+ exit((int)((errno&255)?errno:((statusvalue&255)?statusvalue:255)));
+}
+
+/*VARARGS0*/
+void warn(va_alist)
+va_dcl
+{
+ va_list args;
+ char *message;
+
+#ifndef lint
+ va_start(args);
+#else
+ args = 0;
+#endif
+ message = mess(args);
+ va_end(args);
+
+ fputs(message,stderr);
+#ifdef LEAKTEST
+#ifdef DEBUGGING
+ if (debug & 4096)
+ xstat();
+#endif
+#endif
+ (void)fflush(stderr);
+}
+#endif
+
+void
+my_setenv(nam,val)
+char *nam, *val;
+{
+ register int i=envix(nam); /* where does it go? */
+
+ if (environ == origenviron) { /* need we copy environment? */
+ int j;
+ int max;
+ char **tmpenv;
+
+ /*SUPPRESS 530*/
+ for (max = i; environ[max]; max++) ;
+ New(901,tmpenv, max+2, char*);
+ for (j=0; j<max; j++) /* copy environment */
+ tmpenv[j] = savestr(environ[j]);
+ tmpenv[max] = Nullch;
+ environ = tmpenv; /* tell exec where it is now */
+ }
+ if (!val) {
+ while (environ[i]) {
+ environ[i] = environ[i+1];
+ i++;
+ }
+ return;
+ }
+ if (!environ[i]) { /* does not exist yet */
+ Renew(environ, i+2, char*); /* just expand it a bit */
+ environ[i+1] = Nullch; /* make sure it's null terminated */
+ }
+ else
+ Safefree(environ[i]);
+ New(904, environ[i], strlen(nam) + strlen(val) + 2, char);
+#ifndef MSDOS
+ (void)sprintf(environ[i],"%s=%s",nam,val);/* all that work just for this */
+#else
+ /* MS-DOS requires environment variable names to be in uppercase */
+ /* [Tom Dinger, 27 August 1990: Well, it doesn't _require_ it, but
+ * some utilities and applications may break because they only look
+ * for upper case strings. (Fixed strupr() bug here.)]
+ */
+ strcpy(environ[i],nam); strupr(environ[i]);
+ (void)sprintf(environ[i] + strlen(nam),"=%s",val);
+#endif /* MSDOS */
+}
+
+int
+envix(nam)
+char *nam;
+{
+ register int i, len = strlen(nam);
+
+ for (i = 0; environ[i]; i++) {
+ if (strnEQ(environ[i],nam,len) && environ[i][len] == '=')
+ break; /* strnEQ must come first to avoid */
+ } /* potential SEGV's */
+ return i;
+}
+
+#ifdef EUNICE
+int
+unlnk(f) /* unlink all versions of a file */
+char *f;
+{
+ int i;
+
+ for (i = 0; unlink(f) >= 0; i++) ;
+ return i ? 0 : -1;
+}
+#endif
+
+#if !defined(HAS_BCOPY) || !defined(SAFE_BCOPY)
+char *
+my_bcopy(from,to,len)
+register char *from;
+register char *to;
+register int len;
+{
+ char *retval = to;
+
+ if (from - to >= 0) {
+ while (len--)
+ *to++ = *from++;
+ }
+ else {
+ to += len;
+ from += len;
+ while (len--)
+ *(--to) = *(--from);
+ }
+ return retval;
+}
+#endif
+
+#if !defined(HAS_BZERO) && !defined(HAS_MEMSET)
+char *
+my_bzero(loc,len)
+register char *loc;
+register int len;
+{
+ char *retval = loc;
+
+ while (len--)
+ *loc++ = 0;
+ return retval;
+}
+#endif
+
+#ifndef HAS_MEMCMP
+int
+my_memcmp(s1,s2,len)
+register unsigned char *s1;
+register unsigned char *s2;
+register int len;
+{
+ register int tmp;
+
+ while (len--) {
+ if (tmp = *s1++ - *s2++)
+ return tmp;
+ }
+ return 0;
+}
+#endif /* HAS_MEMCMP */
+
+#ifdef I_VARARGS
+#ifndef HAS_VPRINTF
+
+#ifdef CHARVSPRINTF
+char *
+#else
+int
+#endif
+vsprintf(dest, pat, args)
+char *dest, *pat, *args;
+{
+ FILE fakebuf;
+
+ fakebuf._ptr = dest;
+ fakebuf._cnt = 32767;
+#ifndef _IOSTRG
+#define _IOSTRG 0
+#endif
+ fakebuf._flag = _IOWRT|_IOSTRG;
+ _doprnt(pat, args, &fakebuf); /* what a kludge */
+ (void)putc('\0', &fakebuf);
+#ifdef CHARVSPRINTF
+ return(dest);
+#else
+ return 0; /* perl doesn't use return value */
+#endif
+}
+
+#ifdef DEBUGGING
+int
+vfprintf(fd, pat, args)
+FILE *fd;
+char *pat, *args;
+{
+ _doprnt(pat, args, fd);
+ return 0; /* wrong, but perl doesn't use the return value */
+}
+#endif
+#endif /* HAS_VPRINTF */
+#endif /* I_VARARGS */
+
+/*
+ * I think my_swap(), htonl() and ntohl() have never been used.
+ * perl.h contains last-chance references to my_swap(), my_htonl()
+ * and my_ntohl(). I presume these are the intended functions;
+ * but htonl() and ntohl() have the wrong names. There are no
+ * functions my_htonl() and my_ntohl() defined anywhere.
+ * -DWS
+ */
+#ifdef MYSWAP
+#if BYTEORDER != 0x4321
+short
+my_swap(s)
+short s;
+{
+#if (BYTEORDER & 1) == 0
+ short result;
+
+ result = ((s & 255) << 8) + ((s >> 8) & 255);
+ return result;
+#else
+ return s;
+#endif
+}
+
+long
+htonl(l)
+register long l;
+{
+ union {
+ long result;
+ char c[sizeof(long)];
+ } u;
+
+#if BYTEORDER == 0x1234
+ u.c[0] = (l >> 24) & 255;
+ u.c[1] = (l >> 16) & 255;
+ u.c[2] = (l >> 8) & 255;
+ u.c[3] = l & 255;
+ return u.result;
+#else
+#if ((BYTEORDER - 0x1111) & 0x444) || !(BYTEORDER & 0xf)
+ fatal("Unknown BYTEORDER\n");
+#else
+ register int o;
+ register int s;
+
+ for (o = BYTEORDER - 0x1111, s = 0; s < (sizeof(long)*8); o >>= 4, s += 8) {
+ u.c[o & 0xf] = (l >> s) & 255;
+ }
+ return u.result;
+#endif
+#endif
+}
+
+long
+ntohl(l)
+register long l;
+{
+ union {
+ long l;
+ char c[sizeof(long)];
+ } u;
+
+#if BYTEORDER == 0x1234
+ u.c[0] = (l >> 24) & 255;
+ u.c[1] = (l >> 16) & 255;
+ u.c[2] = (l >> 8) & 255;
+ u.c[3] = l & 255;
+ return u.l;
+#else
+#if ((BYTEORDER - 0x1111) & 0x444) || !(BYTEORDER & 0xf)
+ fatal("Unknown BYTEORDER\n");
+#else
+ register int o;
+ register int s;
+
+ u.l = l;
+ l = 0;
+ for (o = BYTEORDER - 0x1111, s = 0; s < (sizeof(long)*8); o >>= 4, s += 8) {
+ l |= (u.c[o & 0xf] & 255) << s;
+ }
+ return l;
+#endif
+#endif
+}
+
+#endif /* BYTEORDER != 0x4321 */
+#endif /* MYSWAP */
+
+/*
+ * Little-endian byte order functions - 'v' for 'VAX', or 'reVerse'.
+ * If these functions are defined,
+ * the BYTEORDER is neither 0x1234 nor 0x4321.
+ * However, this is not assumed.
+ * -DWS
+ */
+
+#define HTOV(name,type) \
+ type \
+ name (n) \
+ register type n; \
+ { \
+ union { \
+ type value; \
+ char c[sizeof(type)]; \
+ } u; \
+ register int i; \
+ register int s; \
+ for (i = 0, s = 0; i < sizeof(u.c); i++, s += 8) { \
+ u.c[i] = (n >> s) & 0xFF; \
+ } \
+ return u.value; \
+ }
+
+#define VTOH(name,type) \
+ type \
+ name (n) \
+ register type n; \
+ { \
+ union { \
+ type value; \
+ char c[sizeof(type)]; \
+ } u; \
+ register int i; \
+ register int s; \
+ u.value = n; \
+ n = 0; \
+ for (i = 0, s = 0; i < sizeof(u.c); i++, s += 8) { \
+ n += (u.c[i] & 0xFF) << s; \
+ } \
+ return n; \
+ }
+
+#if defined(HAS_HTOVS) && !defined(htovs)
+HTOV(htovs,short)
+#endif
+#if defined(HAS_HTOVL) && !defined(htovl)
+HTOV(htovl,long)
+#endif
+#if defined(HAS_VTOHS) && !defined(vtohs)
+VTOH(vtohs,short)
+#endif
+#if defined(HAS_VTOHL) && !defined(vtohl)
+VTOH(vtohl,long)
+#endif
+
+#ifndef DOSISH
+FILE *
+mypopen(cmd,mode)
+char *cmd;
+char *mode;
+{
+ int p[2];
+ register int this, that;
+ register int pid;
+ STR *str;
+ int doexec = strNE(cmd,"-");
+
+ if (pipe(p) < 0)
+ return Nullfp;
+ this = (*mode == 'w');
+ that = !this;
+#ifdef TAINT
+ if (doexec) {
+ taintenv();
+ taintproper("Insecure dependency in exec");
+ }
+#endif
+ while ((pid = (doexec?vfork():fork())) < 0) {
+ if (errno != EAGAIN) {
+ close(p[this]);
+ if (!doexec)
+ fatal("Can't fork");
+ return Nullfp;
+ }
+ sleep(5);
+ }
+ if (pid == 0) {
+#define THIS that
+#define THAT this
+ close(p[THAT]);
+ if (p[THIS] != (*mode == 'r')) {
+ dup2(p[THIS], *mode == 'r');
+ close(p[THIS]);
+ }
+ if (doexec) {
+#if !defined(HAS_FCNTL) || !defined(F_SETFD)
+ int fd;
+
+#ifndef NOFILE
+#define NOFILE 20
+#endif
+ for (fd = maxsysfd + 1; fd < NOFILE; fd++)
+ close(fd);
+#endif
+ do_exec(cmd); /* may or may not use the shell */
+ warn("Can't exec \"%s\": %s", cmd, strerror(errno));
+ _exit(1);
+ }
+ /*SUPPRESS 560*/
+ if (tmpstab = stabent("$",allstabs))
+ str_numset(STAB_STR(tmpstab),(double)getpid());
+ forkprocess = 0;
+ hclear(pidstatus, FALSE); /* we have no children */
+ return Nullfp;
+#undef THIS
+#undef THAT
+ }
+ do_execfree(); /* free any memory malloced by child on vfork */
+ close(p[that]);
+ if (p[that] < p[this]) {
+ dup2(p[this], p[that]);
+ close(p[this]);
+ p[this] = p[that];
+ }
+ str = afetch(fdpid,p[this],TRUE);
+ str->str_u.str_useful = pid;
+ forkprocess = pid;
+ return fdopen(p[this], mode);
+}
+#else
+#ifdef atarist
+FILE *popen();
+FILE *
+mypopen(cmd,mode)
+char *cmd;
+char *mode;
+{
+ return popen(cmd, mode);
+}
+#endif
+
+#endif /* !DOSISH */
+
+#ifdef NOTDEF
+dumpfds(s)
+char *s;
+{
+ int fd;
+ struct stat tmpstatbuf;
+
+ fprintf(stderr,"%s", s);
+ for (fd = 0; fd < 32; fd++) {
+ if (fstat(fd,&tmpstatbuf) >= 0)
+ fprintf(stderr," %d",fd);
+ }
+ fprintf(stderr,"\n");
+}
+#endif
+
+#ifndef HAS_DUP2
+dup2(oldfd,newfd)
+int oldfd;
+int newfd;
+{
+#if defined(HAS_FCNTL) && defined(F_DUPFD)
+ close(newfd);
+ fcntl(oldfd, F_DUPFD, newfd);
+#else
+ int fdtmp[256];
+ int fdx = 0;
+ int fd;
+
+ if (oldfd == newfd)
+ return 0;
+ close(newfd);
+ while ((fd = dup(oldfd)) != newfd) /* good enough for low fd's */
+ fdtmp[fdx++] = fd;
+ while (fdx > 0)
+ close(fdtmp[--fdx]);
+#endif
+}
+#endif
+
+#ifndef DOSISH
+int
+mypclose(ptr)
+FILE *ptr;
+{
+#ifdef VOIDSIG
+ void (*hstat)(), (*istat)(), (*qstat)();
+#else
+ int (*hstat)(), (*istat)(), (*qstat)();
+#endif
+ int status;
+ STR *str;
+ int pid;
+
+ str = afetch(fdpid,fileno(ptr),TRUE);
+ pid = (int)str->str_u.str_useful;
+ astore(fdpid,fileno(ptr),Nullstr);
+ fclose(ptr);
+#ifdef UTS
+ if(kill(pid, 0) < 0) { return(pid); } /* HOM 12/23/91 */
+#endif
+ hstat = signal(SIGHUP, SIG_IGN);
+ istat = signal(SIGINT, SIG_IGN);
+ qstat = signal(SIGQUIT, SIG_IGN);
+ pid = wait4pid(pid, &status, 0);
+ signal(SIGHUP, hstat);
+ signal(SIGINT, istat);
+ signal(SIGQUIT, qstat);
+ return(pid < 0 ? pid : status);
+}
+
+int
+wait4pid(pid,statusp,flags)
+int pid;
+int *statusp;
+int flags;
+{
+#if !defined(HAS_WAIT4) && !defined(HAS_WAITPID)
+ int result;
+ STR *str;
+ char spid[16];
+#endif
+
+ if (!pid)
+ return -1;
+#ifdef HAS_WAIT4
+ return wait4((pid==-1)?0:pid,statusp,flags,Null(struct rusage *));
+#else
+#ifdef HAS_WAITPID
+ return waitpid(pid,statusp,flags);
+#else
+ if (pid > 0) {
+ sprintf(spid, "%d", pid);
+ str = hfetch(pidstatus,spid,strlen(spid),FALSE);
+ if (str != &str_undef) {
+ *statusp = (int)str->str_u.str_useful;
+ hdelete(pidstatus,spid,strlen(spid));
+ return pid;
+ }
+ }
+ else {
+ HENT *entry;
+
+ hiterinit(pidstatus);
+ if (entry = hiternext(pidstatus)) {
+ pid = atoi(hiterkey(entry,statusp));
+ str = hiterval(pidstatus,entry);
+ *statusp = (int)str->str_u.str_useful;
+ sprintf(spid, "%d", pid);
+ hdelete(pidstatus,spid,strlen(spid));
+ return pid;
+ }
+ }
+ if (flags)
+ fatal("Can't do waitpid with flags");
+ else {
+ while ((result = wait(statusp)) != pid && pid > 0 && result >= 0)
+ pidgone(result,*statusp);
+ if (result < 0)
+ *statusp = -1;
+ }
+ return result;
+#endif
+#endif
+}
+#endif /* !DOSISH */
+
+void
+/*SUPPRESS 590*/
+pidgone(pid,status)
+int pid;
+int status;
+{
+#if defined(HAS_WAIT4) || defined(HAS_WAITPID)
+#else
+ register STR *str;
+ char spid[16];
+
+ sprintf(spid, "%d", pid);
+ str = hfetch(pidstatus,spid,strlen(spid),TRUE);
+ str->str_u.str_useful = status;
+#endif
+ return;
+}
+
+#ifdef atarist
+int pclose();
+int
+mypclose(ptr)
+FILE *ptr;
+{
+ return pclose(ptr);
+}
+#endif
+
+void
+repeatcpy(to,from,len,count)
+register char *to;
+register char *from;
+int len;
+register int count;
+{
+ register int todo;
+ register char *frombase = from;
+
+ if (len == 1) {
+ todo = *from;
+ while (count-- > 0)
+ *to++ = todo;
+ return;
+ }
+ while (count-- > 0) {
+ for (todo = len; todo > 0; todo--) {
+ *to++ = *from++;
+ }
+ from = frombase;
+ }
+}
+
+#ifndef CASTNEGFLOAT
+unsigned long
+castulong(f)
+double f;
+{
+ long along;
+
+#if CASTFLAGS & 2
+# define BIGDOUBLE 2147483648.0
+ if (f >= BIGDOUBLE)
+ return (unsigned long)(f-(long)(f/BIGDOUBLE)*BIGDOUBLE)|0x80000000;
+#endif
+ if (f >= 0.0)
+ return (unsigned long)f;
+ along = (long)f;
+ return (unsigned long)along;
+}
+#endif
+
+#ifndef HAS_RENAME
+int
+same_dirent(a,b)
+char *a;
+char *b;
+{
+ char *fa = rindex(a,'/');
+ char *fb = rindex(b,'/');
+ struct stat tmpstatbuf1;
+ struct stat tmpstatbuf2;
+#ifndef MAXPATHLEN
+#define MAXPATHLEN 1024
+#endif
+ char tmpbuf[MAXPATHLEN+1];
+
+ if (fa)
+ fa++;
+ else
+ fa = a;
+ if (fb)
+ fb++;
+ else
+ fb = b;
+ if (strNE(a,b))
+ return FALSE;
+ if (fa == a)
+ strcpy(tmpbuf,".");
+ else
+ strncpy(tmpbuf, a, fa - a);
+ if (stat(tmpbuf, &tmpstatbuf1) < 0)
+ return FALSE;
+ if (fb == b)
+ strcpy(tmpbuf,".");
+ else
+ strncpy(tmpbuf, b, fb - b);
+ if (stat(tmpbuf, &tmpstatbuf2) < 0)
+ return FALSE;
+ return tmpstatbuf1.st_dev == tmpstatbuf2.st_dev &&
+ tmpstatbuf1.st_ino == tmpstatbuf2.st_ino;
+}
+#endif /* !HAS_RENAME */
+
+unsigned long
+scanoct(start, len, retlen)
+char *start;
+int len;
+int *retlen;
+{
+ register char *s = start;
+ register unsigned long retval = 0;
+
+ while (len-- && *s >= '0' && *s <= '7') {
+ retval <<= 3;
+ retval |= *s++ - '0';
+ }
+ *retlen = s - start;
+ return retval;
+}
+
+unsigned long
+scanhex(start, len, retlen)
+char *start;
+int len;
+int *retlen;
+{
+ register char *s = start;
+ register unsigned long retval = 0;
+ char *tmp;
+
+ while (len-- && *s && (tmp = index(hexdigit, *s))) {
+ retval <<= 4;
+ retval |= (tmp - hexdigit) & 15;
+ s++;
+ }
+ *retlen = s - start;
+ return retval;
+}
diff --git a/gnu/usr.bin/perl/perl/util.h b/gnu/usr.bin/perl/perl/util.h
new file mode 100644
index 0000000..003e4438
--- /dev/null
+++ b/gnu/usr.bin/perl/perl/util.h
@@ -0,0 +1,64 @@
+/* $RCSfile: util.h,v $$Revision: 1.1.1.1 $$Date: 1994/09/10 06:27:35 $
+ *
+ * Copyright (c) 1991, Larry Wall
+ *
+ * You may distribute under the terms of either the GNU General Public
+ * License or the Artistic License, as specified in the README file.
+ *
+ * $Log: util.h,v $
+ * Revision 1.1.1.1 1994/09/10 06:27:35 gclarkii
+ * Initial import of Perl 4.046 bmaked
+ *
+ * Revision 1.1.1.1 1993/08/23 21:29:40 nate
+ * PERL!
+ *
+ * Revision 4.0.1.4 92/06/11 21:19:36 lwall
+ * patch34: pidgone() wasn't declared right
+ *
+ * Revision 4.0.1.3 92/06/08 16:09:20 lwall
+ * patch20: bcopy() and memcpy() now tested for overlap safety
+ *
+ * Revision 4.0.1.2 91/11/05 19:18:40 lwall
+ * patch11: safe malloc code now integrated into Perl's malloc when possible
+ *
+ * Revision 4.0.1.1 91/06/07 12:11:00 lwall
+ * patch4: new copyright notice
+ *
+ * Revision 4.0 91/03/20 01:56:48 lwall
+ * 4.0 baseline.
+ *
+ */
+
+EXT int *screamfirst INIT(Null(int*));
+EXT int *screamnext INIT(Null(int*));
+
+#ifndef safemalloc
+char *safemalloc();
+char *saferealloc();
+#endif
+char *cpytill();
+char *instr();
+char *fbminstr();
+char *screaminstr();
+void fbmcompile();
+char *savestr();
+void my_setenv();
+int envix();
+void growstr();
+char *ninstr();
+char *rninstr();
+char *nsavestr();
+FILE *mypopen();
+int mypclose();
+#if !defined(HAS_BCOPY) || !defined(SAFE_BCOPY)
+char *my_bcopy();
+#endif
+#if !defined(HAS_BZERO) && !defined(HAS_MEMSET)
+char *my_bzero();
+#endif
+#ifndef HAS_MEMCMP
+int my_memcmp();
+#endif
+unsigned long scanoct();
+unsigned long scanhex();
+void pidgone();
diff --git a/gnu/usr.bin/perl/sperl/Makefile b/gnu/usr.bin/perl/sperl/Makefile
new file mode 100644
index 0000000..af19d47
--- /dev/null
+++ b/gnu/usr.bin/perl/sperl/Makefile
@@ -0,0 +1,30 @@
+#
+#
+
+PROG= suidperl
+LINKS= ${BINDIR}/suidperl ${BINDIR}/sperl4.036
+
+SRCS+= array.c cmd.c cons.c consarg.c
+SRCS+= doarg.c doio.c dolist.c dump.c
+SRCS+= eval.c form.c hash.c malloc.c
+SRCS+= perl.c perly.c regcomp.c regexec.c
+SRCS+= stab.c str.c toke.c util.c
+SRCS+= usersub.c
+.PATH: ${.CURDIR}/../perl
+
+
+CFLAGS+= -I${.CURDIR}/../perl -DIAMSUID -DTAINT
+LDADD= -lm
+DPADD= ${LIBM}
+
+LDADD+= -lcrypt
+DPADD+= ${LIBCRYPT}
+
+MAN1=
+MLINKS+= perl.1 suidperl.1
+
+BINOWN= root
+BINMODE=4711
+
+.include "../../Makefile.inc"
+.include <bsd.prog.mk>
diff --git a/gnu/usr.bin/perl/tperl/Makefile b/gnu/usr.bin/perl/tperl/Makefile
new file mode 100644
index 0000000..f76988e
--- /dev/null
+++ b/gnu/usr.bin/perl/tperl/Makefile
@@ -0,0 +1,28 @@
+#
+#
+
+PROG= tperl
+LINKS= ${BINDIR}/tperl ${BINDIR}/tperl4.036
+
+SRCS+= array.c cmd.c cons.c consarg.c
+SRCS+= doarg.c doio.c dolist.c dump.c
+SRCS+= eval.c form.c hash.c malloc.c
+SRCS+= perl.c perly.c regcomp.c regexec.c
+SRCS+= stab.c str.c toke.c util.c
+SRCS+= usersub.c
+.PATH: ${.CURDIR}/../perl
+
+
+CFLAGS+= -I${.CURDIR}/../perl -DTAINT
+LDADD+= -lm
+DPADD= ${LIBM}
+
+LDADD+= -lcrypt
+DPADD+= ${LIBCRYPT}
+
+MAN1=
+MLINKS+= perl.1 tperl.1
+MLINKS+= perl.1 taintperl.1
+
+.include "../../Makefile.inc"
+.include <bsd.prog.mk>
diff --git a/gnu/usr.bin/perl/usub/Makefile b/gnu/usr.bin/perl/usub/Makefile
new file mode 100644
index 0000000..826a976
--- /dev/null
+++ b/gnu/usr.bin/perl/usub/Makefile
@@ -0,0 +1,32 @@
+PROG= curseperl
+
+# From perl
+SRCS+= array.c cmd.c cons.c consarg.c doarg.c doio.c dolist.c dump.c
+SRCS+= eval.c form.c hash.c malloc.c perl.c perly.c regcomp.c regexec.c
+SRCS+= stab.c str.c toke.c util.c
+
+# Local to us.
+SRCS+= usersub.c curses.c
+
+CFLAGS+= -DDEBUGGING -I${.CURDIR}/../perl
+LDADD+= -lncurses -lmytinfo -lcrypt -lm
+DPADD+= ${LIBNCURSES} ${LIBMYTINFO} ${LIBCRYPT} ${LIBM}
+CLEANFILES+= curses.c
+VPATH+= ${.CURDIR}/../perl
+NOMAN= yes
+
+# If perl exists in none of these places, something is horribly wrong.
+.if exists(${.CURDIR}/../perl/obj/perl)
+PERL=${.CURDIR}/../perl/obj/perl
+.endif
+.if !defined(PERL) && exists(${.CURDIR}/../perl/perl)
+PERL=${.CURDIR}/../perl/perl
+.else
+PERL= /usr/bin/perl
+.endif
+
+curses.c: curses.mus
+ ${PERL} ${.CURDIR}/mus ${.CURDIR}/curses.mus > curses.c
+
+.include "../../Makefile.inc"
+.include <bsd.prog.mk>
diff --git a/gnu/usr.bin/perl/usub/README b/gnu/usr.bin/perl/usub/README
new file mode 100644
index 0000000..4e14596
--- /dev/null
+++ b/gnu/usr.bin/perl/usub/README
@@ -0,0 +1,117 @@
+[ Note: This directory was actually brought in to be able to use curseperl,
+ but it's also a useful reference for general extension ]
+
+This directory contains an example of how you might link in C subroutines
+with perl to make your own special copy of perl. In the perl distribution
+directory, there will be (after make is run) a file called uperl.o, which
+is all of perl except for a single undefined subroutine, named userinit().
+See usersub.c.
+
+The sole purpose of the userinit() routine is to call the initialization
+routines for any modules that you want to link in. In this example, we just
+call init_curses(), which sets up to link in the System V curses routines.
+You'll find this in the file curses.c, which is the processed output of
+curses.mus. (To get BSD curses, replace curses.mus with bsdcurses.mus.)
+
+The magicname() routine adds variable names into the symbol table. Along
+with the name of the variable as Perl knows it, we pass a structure containing
+an index identifying the variable, and the names of two C functions that
+know how to set or evaluate a variable given the index of the variable.
+Our example uses a macro to handle this conveniently.
+
+The init routine calls make_usub() to add user-defined subroutine names
+into the symbol table. The arguments are
+
+ make_usub(subname, subindex, subfunc, filename);
+ char *subname;
+ int subindex;
+ int subfunc();
+ char *filename;
+
+The subname is the name that will be used in the Perl program. The subindex
+will be passed to subfunc() when it is called to tell it which C function
+is desired. subfunc() is a glue routine that translates the arguments
+from Perl internal stack form to the form required by the routine in
+question, calls the desired C function, and then translates any return
+value back into the stack format. The glue routine used by curses just
+has a large switch statement, each branch of which does the processing
+for a particular C function. The subindex could, however, be used to look
+up a function in a dynamically linked library. No example of this is
+provided.
+
+As a help in producing the glue routine, a preprocessor called "mus" lets
+you specify argument and return value types in a tabular format. An entry
+such as:
+
+ CASE int waddstr
+ I WINDOW* win
+ I char* str
+ END
+
+indicates that waddstr takes two input arguments, the first of which is a
+pointer to a window, and the second of which is an ordinary C string. It
+also indicates that an integer is returned. The mus program turns this into:
+
+ case US_waddstr:
+ if (items != 2)
+ fatal("Usage: &waddstr($win, $str)");
+ else {
+ int retval;
+ WINDOW* win = *(WINDOW**) str_get(st[1]);
+ char* str = (char*) str_get(st[2]);
+
+ retval = waddstr(win, str);
+ str_numset(st[0], (double) retval);
+ }
+ return sp;
+
+It's also possible to have output parameters, indicated by O, and input/ouput
+parameters indicated by IO.
+
+The mus program isn't perfect. You'll note that curses.mus has some
+cases which are hand coded. They'll be passed straight through unmodified.
+You can produce similar cases by analogy to what's in curses.c, as well
+as similar routines in the doarg.c, dolist.c and doio.c routines of Perl.
+The mus program is only intended to get you about 90% there. It's not clear,
+for instance, how a given structure should be passed to Perl. But that
+shouldn't bother you--if you've gotten this far, it's already obvious
+that you are totally mad.
+
+Here's an example of how to return an array value:
+
+ case US_appl_errlist:
+ if (!wantarray) {
+ str_numset(st[0], (double) appl_nerr);
+ return sp;
+ }
+ astore(stack, sp + appl_nerr, Nullstr); /* extend stack */
+ st = stack->ary_array + sp; /* possibly realloced */
+ for (i = 0; i < appl_nerr; i++) {
+ tmps = appl_errlist[i];
+ st[i] = str_2mortal(str_make(tmps,strlen(tmps)));
+ }
+ return sp + appl_nerr - 1;
+
+
+In addition, there is a program, man2mus, that will scan a man page for
+function prototypes and attempt to construct a mus CASE entry for you. It has
+to guess about input/output parameters, so you'll have to tidy up after it.
+But it can save you a lot of time if the man pages for a library are
+reasonably well formed.
+
+If you happen to have curses on your machine, you might try compiling
+a copy of curseperl. The "pager" program in this directory is a rudimentary
+start on writing a pager--don't believe the help message, which is stolen
+from the less program.
+
+User-defined subroutines may not currently be called as a signal handler,
+though a signal handler may itself call a user-defined subroutine.
+
+There are now glue routines to call back from C into Perl. In usersub.c
+in this directory, you'll find callback() and callv(). The callback()
+routine presumes that any arguments to pass to the Perl subroutine
+have already been pushed onto the Perl stack. The callv() routine
+is a wrapper that pushes an argv-style array of strings onto the
+stack for you, and then calls callback(). Be sure to recheck your
+stack pointer after returning from these routine, since the Perl code
+may have reallocated it.
diff --git a/gnu/usr.bin/perl/usub/curses.mus b/gnu/usr.bin/perl/usub/curses.mus
new file mode 100644
index 0000000..03269c3
--- /dev/null
+++ b/gnu/usr.bin/perl/usub/curses.mus
@@ -0,0 +1,813 @@
+/* $RCSfile: curses.mus,v $$Revision: 1.1 $$Date: 1995/03/24 04:33:49 $
+ *
+ * $Log: curses.mus,v $
+# Revision 1.1 1995/03/24 04:33:49 jkh
+# Bring back perl/usub as usub/, this time containing an updated curseperl
+# which is also installed by default (the reason for which should also be
+# plain shortly).
+#
+ * Revision 4.0.1.2 92/06/08 16:06:12 lwall
+ * patch20: function key support added to curses.mus
+ *
+ * Revision 4.0.1.1 91/11/05 19:06:19 lwall
+ * patch11: usub/curses.mus now supports SysV curses
+ *
+ * Revision 4.0 91/03/20 01:56:13 lwall
+ * 4.0 baseline.
+ *
+ * Revision 3.0.1.1 90/08/09 04:05:21 lwall
+ * patch19: Initial revision
+ *
+ */
+
+#include "EXTERN.h"
+#include "perl.h"
+
+char *savestr();
+static char *getcap();
+
+#undef bool
+#include <ncurses.h>
+
+#ifndef A_UNDERLINE
+#define NOSETATTR
+#define A_STANDOUT 0x0200
+#define A_UNDERLINE 0x0100
+#define A_REVERSE 0x0200
+#define A_BLINK 0x0400
+#define A_BOLD 0x0800
+#define A_ALTCHARSET 0x1000
+#define A_NORMAL 0
+#endif
+
+#ifdef USG
+static char *tcbuf = NULL;
+#endif
+
+#ifdef NOSETATTR
+static unsigned curattr = NORMAL;
+#endif
+
+enum uservars {
+ UV_curscr,
+ UV_stdscr,
+ UV_LINES,
+ UV_COLS,
+ UV_ERR,
+ UV_OK,
+ UV_A_STANDOUT,
+ UV_A_UNDERLINE,
+ UV_A_REVERSE,
+ UV_A_BLINK,
+ UV_A_DIM,
+ UV_A_BOLD,
+ UV_A_NORMAL,
+};
+
+enum usersubs {
+ US_addch,
+ US_waddch,
+ US_addstr,
+ US_waddstr,
+ US_box,
+ US_clear,
+ US_wclear,
+ US_clearok,
+ US_clrtobot,
+ US_wclrtobot,
+ US_clrtoeol,
+ US_wclrtoeol,
+ US_delch,
+ US_wdelch,
+ US_deleteln,
+ US_wdeleteln,
+ US_erase,
+ US_werase,
+ US_idlok,
+ US_insch,
+ US_winsch,
+ US_insertln,
+ US_winsertln,
+ US_move,
+ US_wmove,
+ US_overlay,
+ US_overwrite,
+ US_refresh,
+ US_wrefresh,
+ US_standout,
+ US_wstandout,
+ US_standend,
+ US_wstandend,
+ US_cbreak,
+ US_nocbreak,
+ US_echo,
+ US_noecho,
+ US_getch,
+ US_wgetch,
+ US_getstr,
+ US_wgetstr,
+ US_raw,
+ US_noraw,
+ US_baudrate,
+ US_delwin,
+ US_endwin,
+ US_erasechar,
+ US_getyx,
+ US_inch,
+ US_winch,
+ US_initscr,
+ US_killchar,
+ US_leaveok,
+ US_longname,
+ US_mvwin,
+ US_newwin,
+ US_nl,
+ US_nonl,
+ US_scrollok,
+ US_subwin,
+ US_touchline,
+ US_touchwin,
+ US_unctrl,
+#ifndef __FreeBSD__
+ US_gettmode,
+#endif
+ US_mvcur,
+ US_scroll,
+ US_savetty,
+ US_resetty,
+ US_attroff,
+ US_wattroff,
+ US_attron,
+ US_wattron,
+ US_attrset,
+ US_wattrset,
+#ifdef CURSEFMT
+ US_printw, /* remove */
+ US_wprintw, /* remove */
+ US_scanw, /* delete */
+ US_wscanw, /* delete */
+#endif
+ US_getcap,
+ US_mysub,
+ US_testcallback,
+};
+
+static int usersub();
+static int userset();
+static int userval();
+
+int
+init_curses()
+{
+ struct ufuncs uf;
+ char *filename = "curses.c";
+
+ uf.uf_set = userset;
+ uf.uf_val = userval;
+
+#define MAGICVAR(name, ix) uf.uf_index = ix, magicname(name, &uf, sizeof uf)
+
+ MAGICVAR("curscr", UV_curscr);
+ MAGICVAR("stdscr", UV_stdscr);
+ MAGICVAR("LINES", UV_LINES);
+ MAGICVAR("COLS", UV_COLS);
+ MAGICVAR("ERR", UV_ERR);
+ MAGICVAR("OK", UV_OK);
+ MAGICVAR("A_STANDOUT", UV_A_STANDOUT);
+ MAGICVAR("A_UNDERLINE", UV_A_UNDERLINE);
+ MAGICVAR("A_REVERSE", UV_A_REVERSE);
+ MAGICVAR("A_BLINK", UV_A_BLINK);
+ MAGICVAR("A_DIM", UV_A_DIM);
+ MAGICVAR("A_BOLD", UV_A_BOLD);
+ MAGICVAR("A_NORMAL", UV_A_NORMAL);
+
+ make_usub("addch", US_addch, usersub, filename);
+ make_usub("waddch", US_waddch, usersub, filename);
+ make_usub("addstr", US_addstr, usersub, filename);
+ make_usub("waddstr", US_waddstr, usersub, filename);
+ make_usub("box", US_box, usersub, filename);
+ make_usub("clear", US_clear, usersub, filename);
+ make_usub("wclear", US_wclear, usersub, filename);
+ make_usub("clearok", US_clearok, usersub, filename);
+ make_usub("clrtobot", US_clrtobot, usersub, filename);
+ make_usub("wclrtobot", US_wclrtobot, usersub, filename);
+ make_usub("clrtoeol", US_clrtoeol, usersub, filename);
+ make_usub("wclrtoeol", US_wclrtoeol, usersub, filename);
+ make_usub("delch", US_delch, usersub, filename);
+ make_usub("wdelch", US_wdelch, usersub, filename);
+ make_usub("deleteln", US_deleteln, usersub, filename);
+ make_usub("wdeleteln", US_wdeleteln, usersub, filename);
+ make_usub("erase", US_erase, usersub, filename);
+ make_usub("werase", US_werase, usersub, filename);
+ make_usub("idlok", US_idlok, usersub, filename);
+ make_usub("insch", US_insch, usersub, filename);
+ make_usub("winsch", US_winsch, usersub, filename);
+ make_usub("insertln", US_insertln, usersub, filename);
+ make_usub("winsertln", US_winsertln, usersub, filename);
+ make_usub("move", US_move, usersub, filename);
+ make_usub("wmove", US_wmove, usersub, filename);
+ make_usub("overlay", US_overlay, usersub, filename);
+ make_usub("overwrite", US_overwrite, usersub, filename);
+ make_usub("refresh", US_refresh, usersub, filename);
+ make_usub("wrefresh", US_wrefresh, usersub, filename);
+ make_usub("standout", US_standout, usersub, filename);
+ make_usub("wstandout", US_wstandout, usersub, filename);
+ make_usub("standend", US_standend, usersub, filename);
+ make_usub("wstandend", US_wstandend, usersub, filename);
+ make_usub("cbreak", US_cbreak, usersub, filename);
+ make_usub("nocbreak", US_nocbreak, usersub, filename);
+ make_usub("echo", US_echo, usersub, filename);
+ make_usub("noecho", US_noecho, usersub, filename);
+ make_usub("getch", US_getch, usersub, filename);
+ make_usub("wgetch", US_wgetch, usersub, filename);
+ make_usub("getstr", US_getstr, usersub, filename);
+ make_usub("wgetstr", US_wgetstr, usersub, filename);
+ make_usub("raw", US_raw, usersub, filename);
+ make_usub("noraw", US_noraw, usersub, filename);
+ make_usub("baudrate", US_baudrate, usersub, filename);
+ make_usub("delwin", US_delwin, usersub, filename);
+ make_usub("endwin", US_endwin, usersub, filename);
+ make_usub("erasechar", US_erasechar, usersub, filename);
+ make_usub("getyx", US_getyx, usersub, filename);
+ make_usub("inch", US_inch, usersub, filename);
+ make_usub("winch", US_winch, usersub, filename);
+ make_usub("initscr", US_initscr, usersub, filename);
+ make_usub("killchar", US_killchar, usersub, filename);
+ make_usub("leaveok", US_leaveok, usersub, filename);
+ make_usub("longname", US_longname, usersub, filename);
+ make_usub("mvwin", US_mvwin, usersub, filename);
+ make_usub("newwin", US_newwin, usersub, filename);
+ make_usub("nl", US_nl, usersub, filename);
+ make_usub("nonl", US_nonl, usersub, filename);
+ make_usub("scrollok", US_scrollok, usersub, filename);
+ make_usub("subwin", US_subwin, usersub, filename);
+ make_usub("touchline", US_touchline, usersub, filename);
+ make_usub("touchwin", US_touchwin, usersub, filename);
+ make_usub("unctrl", US_unctrl, usersub, filename);
+#ifndef __FreeBSD__
+ make_usub("gettmode", US_gettmode, usersub, filename);
+#endif
+ make_usub("mvcur", US_mvcur, usersub, filename);
+ make_usub("scroll", US_scroll, usersub, filename);
+ make_usub("savetty", US_savetty, usersub, filename);
+ make_usub("resetty", US_resetty, usersub, filename);
+ make_usub("getcap", US_getcap, usersub, filename);
+ make_usub("attroff", US_attroff, usersub, filename);
+ make_usub("wattroff", US_wattroff, usersub, filename);
+ make_usub("attron", US_attron, usersub, filename);
+ make_usub("wattron", US_wattron, usersub, filename);
+ make_usub("attrset", US_attrset, usersub, filename);
+ make_usub("wattrset", US_wattrset, usersub, filename);
+#ifdef CURSEFMT
+ make_usub("printw", US_printw, usersub, filename);
+ make_usub("wprintw", US_wprintw, usersub, filename);
+ make_usub("scanw", US_scanw, usersub, filename);
+ make_usub("wscanw", US_wscanw, usersub, filename);
+#endif
+ make_usub("testcallback", US_testcallback,usersub, filename);
+ };
+
+#ifdef NOSETATTR
+#define attron(attr) wattron(stdscr, attr)
+#define attroff(attr) wattroff(stdscr, attr)
+#define attset(attr) wattset(stdscr, attr)
+
+int
+wattron(win, attr)
+WINDOW *win;
+chtype attr;
+{
+ curattr |= attr;
+ if (curattr & A_STANDOUT) {
+ return(wstandout(win));
+ } else {
+ return(wstandend(win));
+ }
+}
+
+int
+wattroff(win, attr)
+WINDOW *win;
+chtype attr;
+{
+ curattr &= (~attr);
+ if (curattr & A_STANDOUT) {
+ return(wstandout(win));
+ } else {
+ return(wstandend(win));
+ }
+}
+
+int
+wattrset(win, attr)
+WINDOW *win;
+chtype attr;
+{
+ curattr = attr;
+ if (curattr & A_STANDOUT) {
+ return(wstandout(win));
+ } else {
+ return(wstandend(win));
+ }
+}
+
+#endif
+
+static int
+usersub(ix, sp, items)
+int ix;
+register int sp;
+register int items;
+{
+ STR **st = stack->ary_array + sp;
+ register int i;
+ register char *tmps;
+ register STR *Str; /* used in str_get and str_gnum macros */
+
+ switch (ix) {
+CASE int addch
+I char ch
+END
+
+CASE int waddch
+I WINDOW* win
+I char ch
+END
+
+CASE int addstr
+I char* str
+END
+
+CASE int waddstr
+I WINDOW* win
+I char* str
+END
+
+CASE int box
+I WINDOW* win
+I char vert
+I char hor
+END
+
+CASE int clear
+END
+
+CASE int wclear
+I WINDOW* win
+END
+
+CASE int clearok
+I WINDOW* win
+I bool boolf
+END
+
+CASE int clrtobot
+END
+
+CASE int wclrtobot
+I WINDOW* win
+END
+
+CASE int clrtoeol
+END
+
+CASE int wclrtoeol
+I WINDOW* win
+END
+
+CASE int delch
+END
+
+CASE int wdelch
+I WINDOW* win
+END
+
+CASE int deleteln
+END
+
+CASE int wdeleteln
+I WINDOW* win
+END
+
+CASE int erase
+END
+
+CASE int werase
+I WINDOW* win
+END
+
+CASE int idlok
+I WINDOW* win
+I bool boolf
+END
+
+CASE int insch
+I char c
+END
+
+CASE int winsch
+I WINDOW* win
+I char c
+END
+
+CASE int insertln
+END
+
+CASE int winsertln
+I WINDOW* win
+END
+
+CASE int move
+I int y
+I int x
+END
+
+CASE int wmove
+I WINDOW* win
+I int y
+I int x
+END
+
+CASE int overlay
+I WINDOW* win1
+I WINDOW* win2
+END
+
+CASE int overwrite
+I WINDOW* win1
+I WINDOW* win2
+END
+
+CASE int refresh
+END
+
+CASE int wrefresh
+I WINDOW* win
+END
+
+CASE int standout
+END
+
+CASE int wstandout
+I WINDOW* win
+END
+
+CASE int standend
+END
+
+CASE int wstandend
+I WINDOW* win
+END
+
+CASE int cbreak
+END
+
+CASE int nocbreak
+END
+
+CASE int echo
+END
+
+CASE int noecho
+END
+
+ case US_getch:
+ if (items != 0)
+ fatal("Usage: &getch()");
+ else {
+ int retval;
+ char retch;
+
+ retval = getch();
+ if (retval == EOF)
+ st[0] = &str_undef;
+ else {
+ retch = retval;
+ if (retval > 0377)
+ str_numset(st[0], (double) retval);
+ else
+ str_nset(st[0], &retch, 1);
+ }
+ }
+ return sp;
+
+ case US_wgetch:
+ if (items != 1)
+ fatal("Usage: &wgetch($win)");
+ else {
+ int retval;
+ char retch;
+ WINDOW* win = *(WINDOW**) str_get(st[1]);
+
+ retval = wgetch(win);
+ if (retval == EOF)
+ st[0] = &str_undef;
+ else {
+ retch = retval;
+ if (retval > 0377)
+ str_numset(st[0], (double) retval);
+ else
+ str_nset(st[0], &retch, 1);
+ }
+ }
+ return sp;
+
+CASE int getstr
+O char* str
+END
+
+CASE int wgetstr
+I WINDOW* win
+O char* str
+END
+
+CASE int raw
+END
+
+CASE int noraw
+END
+
+CASE int baudrate
+END
+
+CASE int delwin
+I WINDOW* win
+END
+
+CASE int endwin
+END
+
+CASE int erasechar
+END
+
+ case US_getyx:
+ if (items != 3)
+ fatal("Usage: &getyx($win, $y, $x)");
+ else {
+ int retval;
+ STR* str = str_new(0);
+ WINDOW* win = *(WINDOW**) str_get(st[1]);
+ int y;
+ int x;
+
+ do_sprintf(str, items - 1, st + 1);
+ retval = getyx(win, y, x);
+ str_numset(st[2], (double)y);
+ str_numset(st[3], (double)x);
+ str_numset(st[0], (double) retval);
+ str_free(str);
+ }
+ return sp;
+
+CASE int inch
+END
+
+CASE int winch
+I WINDOW* win
+END
+
+CASE WINDOW* initscr
+END
+
+CASE int killchar
+END
+
+CASE int leaveok
+I WINDOW* win
+I bool boolf
+END
+
+#ifdef BSD
+CASE char* longname
+END
+#else
+CASE char* longname
+I char* termbug
+I char* name
+END
+#endif
+
+CASE int mvwin
+I WINDOW* win
+I int y
+I int x
+END
+
+CASE WINDOW* newwin
+I int lines
+I int cols
+I int begin_y
+I int begin_x
+END
+
+CASE int nl
+END
+
+CASE int nonl
+END
+
+CASE int scrollok
+I WINDOW* win
+I bool boolf
+END
+
+CASE WINDOW* subwin
+I WINDOW* win
+I int lines
+I int cols
+I int begin_y
+I int begin_x
+END
+
+CASE int touchline
+I WINDOW* win
+I int y
+I int startx
+END
+
+CASE int touchwin
+I WINDOW* win
+END
+
+CASE char* unctrl
+I char ch
+END
+
+#ifndef __FreeBSD__
+CASE int gettmode
+END
+#endif
+
+CASE int mvcur
+I int lasty
+I int lastx
+I int newy
+I int newx
+END
+
+CASE int scroll
+I WINDOW* win
+END
+
+CASE int savetty
+END
+
+CASE void resetty
+END
+
+CASE int attroff
+I chtype str
+END
+
+CASE int wattroff
+I WINDOW* win
+I chtype str
+END
+
+CASE int wattron
+I WINDOW* win
+I chtype str
+END
+
+CASE int attron
+I chtype str
+END
+
+CASE int attrset
+I chtype str
+END
+
+CASE int wattrset
+I WINDOW* win
+I chtype str
+END
+
+#ifdef CURSEFMT
+ case US_printw:
+ if (items < 1)
+ fatal("Usage: &printw($fmt, $arg1, $arg2, ... )");
+ else {
+ int retval;
+ STR* str = str_new(0);
+
+ do_sprintf(str, items - 1, st + 1);
+ retval = addstr(str->str_ptr);
+ str_numset(st[0], (double) retval);
+ str_free(str);
+ }
+ return sp;
+
+ case US_wprintw:
+ if (items < 2)
+ fatal("Usage: &wprintw($win, $fmt, $arg1, $arg2, ... )");
+ else {
+ int retval;
+ STR* str = str_new(0);
+ WINDOW* win = *(WINDOW**) str_get(st[1]);
+
+ do_sprintf(str, items - 1, st + 1);
+ retval = waddstr(win, str->str_ptr);
+ str_numset(st[0], (double) retval);
+ str_free(str);
+ }
+ return sp;
+
+#endif
+CASE char* getcap
+I char* str
+END
+ default:
+ fatal("Unimplemented user-defined subroutine");
+ }
+ return sp;
+}
+
+static char
+*getcap(cap)
+register char *cap;
+{
+ static char *tcbuf = NULL;
+ static char nocaperr[] = "Cannot read termcap entry.";
+ extern char *tgetstr();
+ char *cp, *tp;
+ static char capstr[256];
+
+ cp = capstr;
+ if (tcbuf == NULL) {
+ if ((tcbuf = malloc(1024)) == NULL) {
+ fatal(nocaperr);
+ }
+ tp = getenv("TERM");
+ if (!tp)
+ tp = "tty";
+ if (tgetent(tcbuf, tp) == -1) {
+ fatal(nocaperr);
+ }
+ }
+ return (tgetstr(cap, &cp));
+}
+
+static int
+userval(ix, str)
+int ix;
+STR *str;
+{
+ switch (ix) {
+ case UV_COLS:
+ str_numset(str, (double)COLS);
+ break;
+ case UV_ERR:
+ str_numset(str, (double)ERR);
+ break;
+ case UV_LINES:
+ str_numset(str, (double)LINES);
+ break;
+ case UV_OK:
+ str_numset(str, (double)OK);
+ break;
+ case UV_curscr:
+ str_nset(str, &curscr, sizeof(WINDOW*));
+ break;
+ case UV_stdscr:
+ str_nset(str, &stdscr, sizeof(WINDOW*));
+ break;
+ case UV_A_STANDOUT:
+ str_numset(str, (double)A_STANDOUT);
+ break;
+ case UV_A_UNDERLINE:
+ str_numset(str, (double)A_UNDERLINE);
+ break;
+ case UV_A_REVERSE:
+ str_numset(str, (double)A_REVERSE);
+ break;
+ case UV_A_BLINK:
+ str_numset(str, (double)A_BLINK);
+ break;
+ case UV_A_DIM:
+ str_numset(str, (double)A_DIM);
+ break;
+ case UV_A_BOLD:
+ str_numset(str, (double)A_BOLD);
+ break;
+ case UV_A_NORMAL:
+ str_numset(str, (double)A_NORMAL);
+ break;
+ }
+ return 0;
+}
+
+static int
+userset(ix, str)
+int ix;
+STR *str;
+{
+ switch (ix) {
+ case UV_COLS:
+ COLS = (int)str_gnum(str);
+ break;
+ case UV_LINES:
+ LINES = (int)str_gnum(str);
+ break;
+ }
+ return 0;
+}
diff --git a/gnu/usr.bin/perl/usub/man2mus b/gnu/usr.bin/perl/usub/man2mus
new file mode 100755
index 0000000..a304678
--- /dev/null
+++ b/gnu/usr.bin/perl/usub/man2mus
@@ -0,0 +1,66 @@
+#!/usr/bin/perl
+while (<>) {
+ if (/^\.SH SYNOPSIS/) {
+ $spec = '';
+ for ($_ = <>; $_ && !/^\.SH/; $_ = <>) {
+ s/^\.[IRB][IRB]\s*//;
+ s/^\.[IRB]\s+//;
+ next if /^\./;
+ s/\\f\w//g;
+ s/\\&//g;
+ s/^\s+//;
+ next if /^$/;
+ next if /^#/;
+ $spec .= $_;
+ }
+ $_ = $spec;
+ 0 while s/\(([^),;]*)\s*,\s*([^);]*)\)/($1|$2)/g;
+ s/\(\*([^,;]*)\)\(\)/(*)()$1/g;
+ s/(\w+)\[\]/*$1/g;
+
+ s/\n/ /g;
+ s/\s+/ /g;
+ s/(\w+) \(([^*])/$1($2/g;
+ s/^ //;
+ s/ ?; ?/\n/g;
+ s/\) /)\n/g;
+ s/ \* / \*/g;
+ s/\* / \*/g;
+
+ $* = 1;
+ 0 while s/^((struct )?\w+ )([^\n,]*), ?(.*)/$1$3\n$1$4/g;
+ $* = 0;
+ s/\|/,/g;
+
+ @cases = ();
+ for (reverse split(/\n/,$_)) {
+ if (/\)$/) {
+ ($type,$name,$args) = split(/(\w+)\(/);
+ $type =~ s/ $//;
+ if ($type =~ /^(\w+) =/) {
+ $type = $type{$1} if $type{$1};
+ }
+ $type = 'int' if $type eq '';
+ @args = grep(/./, split(/[,)]/,$args));
+ $case = "CASE $type $name\n";
+ foreach $arg (@args) {
+ $type = $type{$arg} || "int";
+ $type =~ s/ //g;
+ $type .= "\t" if length($type) < 8;
+ if ($type =~ /\*/) {
+ $case .= "IO $type $arg\n";
+ }
+ else {
+ $case .= "I $type $arg\n";
+ }
+ }
+ $case .= "END\n\n";
+ unshift(@cases, $case);
+ }
+ else {
+ $type{$name} = $type if ($type,$name) = /(.*\W)(\w+)$/;
+ }
+ }
+ print @cases;
+ }
+}
diff --git a/gnu/usr.bin/perl/usub/mus b/gnu/usr.bin/perl/usub/mus
new file mode 100755
index 0000000..b1675fd
--- /dev/null
+++ b/gnu/usr.bin/perl/usub/mus
@@ -0,0 +1,135 @@
+#!/usr/bin/perl
+
+while (<>) {
+ if (s/^CASE\s+//) {
+ @fields = split;
+ $funcname = pop(@fields);
+ $rettype = "@fields";
+ @modes = ();
+ @types = ();
+ @names = ();
+ @outies = ();
+ @callnames = ();
+ $pre = "\n";
+ $post = '';
+
+ while (<>) {
+ last unless /^[IO]+\s/;
+ @fields = split(' ');
+ push(@modes, shift(@fields));
+ push(@names, pop(@fields));
+ push(@types, "@fields");
+ }
+ while (s/^<\s//) {
+ $pre .= "\t $_";
+ $_ = <>;
+ }
+ while (s/^>\s//) {
+ $post .= "\t $_";
+ $_ = <>;
+ }
+ $items = @names;
+ $namelist = '$' . join(', $', @names);
+ $namelist = '' if $namelist eq '$';
+ print <<EOF;
+ case US_$funcname:
+ if (items != $items)
+ fatal("Usage: &$funcname($namelist)");
+ else {
+EOF
+ if ($rettype eq 'void') {
+ print <<EOF;
+ int retval = 1;
+EOF
+ }
+ else {
+ print <<EOF;
+ $rettype retval;
+EOF
+ }
+ foreach $i (1..@names) {
+ $mode = $modes[$i-1];
+ $type = $types[$i-1];
+ $name = $names[$i-1];
+ if ($type =~ /^[A-Z]+\*$/) {
+ $cast = "*($type*)";
+ }
+ else {
+ $cast = "($type)";
+ }
+ $what = ($type =~ /^(struct\s+\w+|char|[A-Z]+)\s*\*$/ ? "get" : "gnum");
+ $type .= "\t" if length($type) < 4;
+ $cast .= "\t" if length($cast) < 8;
+ $x = "\t" x (length($name) < 6);
+ if ($mode =~ /O/) {
+ if ($what eq 'gnum') {
+ push(@outies, "\t str_numset(st[$i], (double) $name);\n");
+ push(@callnames, "&$name");
+ }
+ else {
+ push(@outies, "\t str_set(st[$i], (char*) $name);\n");
+ push(@callnames, "$name");
+ }
+ }
+ else {
+ push(@callnames, $name);
+ }
+ if ($mode =~ /I/) {
+ print <<EOF;
+ $type $name =$x $cast str_$what(st[$i]);
+EOF
+ }
+ elsif ($type =~ /char/) {
+ print <<EOF;
+ char ${name}[133];
+EOF
+ }
+ else {
+ print <<EOF;
+ $type $name;
+EOF
+ }
+ }
+ $callnames = join(', ', @callnames);
+ $outies = join("\n",@outies);
+ if ($rettype eq 'void') {
+ print <<EOF;
+$pre (void)$funcname($callnames);
+EOF
+ }
+ else {
+ print <<EOF;
+$pre retval = $funcname($callnames);
+EOF
+ }
+ if ($rettype =~ /^(struct\s+\w+|char)\s*\*$/) {
+ print <<EOF;
+ str_set(st[0], (char*) retval);
+EOF
+ }
+ elsif ($rettype =~ /^[A-Z]+\s*\*$/) {
+ print <<EOF;
+ str_nset(st[0], (char*) &retval, sizeof retval);
+EOF
+ }
+ else {
+ print <<EOF;
+ str_numset(st[0], (double) retval);
+EOF
+ }
+ print $outies if $outies;
+ print $post if $post;
+ if (/^END/) {
+ print "\t}\n\treturn sp;\n";
+ }
+ else {
+ redo;
+ }
+ }
+ elsif (/^END/) {
+ print "\t}\n\treturn sp;\n";
+ }
+ else {
+ print;
+ }
+}
diff --git a/gnu/usr.bin/perl/usub/pager b/gnu/usr.bin/perl/usub/pager
new file mode 100755
index 0000000..d55ace2
--- /dev/null
+++ b/gnu/usr.bin/perl/usub/pager
@@ -0,0 +1,190 @@
+#!/usr/bin/curseperl
+
+eval <<'EndOfMain'; $evaloffset = __LINE__;
+
+ $SIG{'INT'} = 'endit';
+ $| = 1; # command buffering on stdout
+ &initterm;
+ &inithelp;
+ &slurpfile && &pagearray;
+
+EndOfMain
+
+&endit;
+
+################################################################################
+
+sub initterm {
+
+ &initscr; &cbreak; &noecho; &scrollok($stdscr, 1);
+ &defbell unless defined &bell;
+
+ $lines = $LINES; $lines1 = $lines - 1; $lines2 = $lines - 2;
+ $cols = $COLS; $cols1 = $cols - 1; $cols2 = $cols - 2;;
+
+# $dl = &getcap('dl');
+# $al = &getcap('al');
+# $ho = &getcap('ho');
+# $ce = &getcap('ce');
+}
+
+sub slurpfile {
+ while (<>) {
+ s/^(\t+)/' ' x length($1)/e;
+ &expand($_) if /\t/;
+ if (length($_) < $cols) {
+ push(@lines, $_);
+ }
+ else {
+ while ($_ && $_ ne "\n") {
+ push(@lines, substr($_,0,$cols));
+ substr($_,0,$cols) = '';
+ }
+ }
+ }
+ 1;
+}
+
+sub drawscreen {
+ &move(0,0);
+ for ($line .. $line + $lines2) {
+ &addstr($lines[$_]);
+ }
+ &clrtobot;
+ &percent;
+ &refresh;
+}
+
+sub expand {
+ while (($off = index($_[0],"\t")) >= 0) {
+ substr($_[0], $off, 1) = ' ' x (8 - $off % 8);
+ }
+}
+
+sub pagearray {
+ $line = 0;
+
+ $| = 1;
+
+ for (&drawscreen;;&drawscreen) {
+
+ $ch = &getch;
+ $ch = 'j' if $ch eq "\n";
+
+ if ($ch eq ' ') {
+ last if $percent >= 100;
+ &move(0,0);
+ $line += $lines1;
+ }
+ elsif ($ch eq 'b') {
+ $line -= $lines1;
+ &move(0,0);
+ $line = 0 if $line < 0;
+ }
+ elsif ($ch eq 'j') {
+ next if $percent >= 100;
+ $line += 1;
+# if ($dl && $ho) {
+# print $ho, $dl;
+# &mvcur(0,0,$lines2,0);
+# print $ce,$lines[$line+$lines2],$ce;
+# &wmove($curscr,0,0);
+# &wdeleteln($curscr);
+# &wmove($curscr,$lines2,0);
+# &waddstr($curscr,$lines[$line+$lines2]);
+# }
+ &wmove($stdscr,0,0);
+ &wdeleteln($stdscr);
+ &wmove($stdscr,$lines2,0);
+ &waddstr($stdscr,$lines[$line+$lines2]);
+ &percent;
+ &refresh;
+ redo;
+ }
+ elsif ($ch eq 'k') {
+ next if $line <= 0;
+ $line -= 1;
+# if ($al && $ho && $ce) {
+# print $ho, $al, $ce, $lines[$line];
+# &wmove($curscr,0,0);
+# &winsertln($curscr);
+# &waddstr($curscr,$lines[$line]);
+# }
+ &wmove($stdscr,0,0);
+ &winsertln($stdscr);
+ &waddstr($stdscr,$lines[$line]);
+ &percent;
+ &refresh;
+ redo;
+ }
+ elsif ($ch eq "\f") {
+ &clear;
+ }
+ elsif ($ch eq 'q') {
+ last;
+ }
+ elsif ($ch eq 'h') {
+ &clear;
+ &help;
+ &clear;
+ }
+ else {
+ &bell;
+ }
+ }
+}
+
+sub defbell {
+ eval q#
+ sub bell {
+ print "\007";
+ }
+ #;
+}
+
+sub help {
+ local(*lines) = *helplines;
+ local($line);
+ &pagearray;
+}
+
+sub inithelp {
+ @helplines = split(/\n/,<<'EOT');
+
+ h Display this help.
+ q Exit.
+
+ SPACE Forward screen.
+ b Backward screen.
+ j, CR Forward 1 line.
+ k Backward 1 line.
+ FF Repaint screen.
+EOT
+ for (@helplines) {
+ s/$/\n/;
+ }
+}
+
+sub percent {
+ &standout;
+ $percent = int(($line + $lines1) * 100 / @lines);
+ &move($lines1,0);
+ &addstr("($percent%)");
+ &standend;
+ &clrtoeol;
+}
+
+sub endit {
+ &move($lines1,0);
+ &clrtoeol;
+ &refresh;
+ &endwin;
+
+ if ($@) {
+ print ""; # force flush of stdout
+ $@ =~ s/\(eval\)/$0/ && $@ =~ s/line (\d+)/'line ' . ($1 + $evaloffset)/e;
+ die $@;
+ }
+
+ exit;
+}
diff --git a/gnu/usr.bin/perl/usub/usersub.c b/gnu/usr.bin/perl/usub/usersub.c
new file mode 100644
index 0000000..26fbcbc
--- /dev/null
+++ b/gnu/usr.bin/perl/usub/usersub.c
@@ -0,0 +1,77 @@
+/* $RCSfile: usersub.c,v $$Revision: 1.1 $$Date: 1995/03/24 04:33:54 $
+ *
+ * $Log: usersub.c,v $
+ * Revision 1.1 1995/03/24 04:33:54 jkh
+ * Bring back perl/usub as usub/, this time containing an updated curseperl
+ * which is also installed by default (the reason for which should also be
+ * plain shortly).
+ *
+ * Revision 4.0.1.1 91/11/05 19:07:24 lwall
+ * patch11: there are now subroutines for calling back from C into Perl
+ *
+ * Revision 4.0 91/03/20 01:56:34 lwall
+ * 4.0 baseline.
+ *
+ * Revision 3.0.1.1 90/08/09 04:06:10 lwall
+ * patch19: Initial revision
+ *
+ */
+
+#include "EXTERN.h"
+#include "perl.h"
+
+int
+userinit()
+{
+ init_curses();
+}
+
+/* Be sure to refetch the stack pointer after calling these routines. */
+
+int
+callback(subname, sp, gimme, hasargs, numargs)
+char *subname;
+int sp; /* stack pointer after args are pushed */
+int gimme; /* called in array or scalar context */
+int hasargs; /* whether to create a @_ array for routine */
+int numargs; /* how many args are pushed on the stack */
+{
+ static ARG myarg[3]; /* fake syntax tree node */
+ int arglast[3];
+
+ arglast[2] = sp;
+ sp -= numargs;
+ arglast[1] = sp--;
+ arglast[0] = sp;
+
+ if (!myarg[0].arg_ptr.arg_str)
+ myarg[0].arg_ptr.arg_str = str_make("",0);
+
+ myarg[1].arg_type = A_WORD;
+ myarg[1].arg_ptr.arg_stab = stabent(subname, FALSE);
+
+ myarg[2].arg_type = hasargs ? A_EXPR : A_NULL;
+
+ return do_subr(myarg, gimme, arglast);
+}
+
+int
+callv(subname, sp, gimme, argv)
+char *subname;
+register int sp; /* current stack pointer */
+int gimme; /* called in array or scalar context */
+register char **argv; /* null terminated arg list, NULL for no arglist */
+{
+ register int items = 0;
+ int hasargs = (argv != 0);
+
+ astore(stack, ++sp, Nullstr); /* reserve spot for 1st return arg */
+ if (hasargs) {
+ while (*argv) {
+ astore(stack, ++sp, str_2mortal(str_make(*argv,0)));
+ items++;
+ argv++;
+ }
+ }
+ return callback(subname, sp, gimme, hasargs, items);
+}
diff --git a/gnu/usr.bin/perl/x2p/EXTERN.h b/gnu/usr.bin/perl/x2p/EXTERN.h
new file mode 100644
index 0000000..b0bb6d0
--- /dev/null
+++ b/gnu/usr.bin/perl/x2p/EXTERN.h
@@ -0,0 +1,29 @@
+/* $RCSfile: EXTERN.h,v $$Revision: 1.1.1.1 $$Date: 1994/09/10 06:27:54 $
+ *
+ * Copyright (c) 1991, Larry Wall
+ *
+ * You may distribute under the terms of either the GNU General Public
+ * License or the Artistic License, as specified in the README file.
+ *
+ * $Log: EXTERN.h,v $
+ * Revision 1.1.1.1 1994/09/10 06:27:54 gclarkii
+ * Initial import of Perl 4.046 bmaked
+ *
+ * Revision 1.1.1.1 1993/08/23 21:30:11 nate
+ * PERL!
+ *
+ * Revision 4.0.1.1 91/06/07 12:11:15 lwall
+ * patch4: new copyright notice
+ *
+ * Revision 4.0 91/03/20 01:56:53 lwall
+ * 4.0 baseline.
+ *
+ */
+
+#undef EXT
+#define EXT extern
+
+#undef INIT
+#define INIT(x)
+
+#undef DOINIT
diff --git a/gnu/usr.bin/perl/x2p/INTERN.h b/gnu/usr.bin/perl/x2p/INTERN.h
new file mode 100644
index 0000000..d8a8a3e
--- /dev/null
+++ b/gnu/usr.bin/perl/x2p/INTERN.h
@@ -0,0 +1,29 @@
+/* $RCSfile: INTERN.h,v $$Revision: 1.1.1.1 $$Date: 1994/09/10 06:27:54 $
+ *
+ * Copyright (c) 1991, Larry Wall
+ *
+ * You may distribute under the terms of either the GNU General Public
+ * License or the Artistic License, as specified in the README file.
+ *
+ * $Log: INTERN.h,v $
+ * Revision 1.1.1.1 1994/09/10 06:27:54 gclarkii
+ * Initial import of Perl 4.046 bmaked
+ *
+ * Revision 1.1.1.1 1993/08/23 21:30:11 nate
+ * PERL!
+ *
+ * Revision 4.0.1.1 91/06/07 12:11:20 lwall
+ * patch4: new copyright notice
+ *
+ * Revision 4.0 91/03/20 01:56:58 lwall
+ * 4.0 baseline.
+ *
+ */
+
+#undef EXT
+#define EXT
+
+#undef INIT
+#define INIT(x) = x
+
+#define DOINIT
diff --git a/gnu/usr.bin/perl/x2p/Makefile b/gnu/usr.bin/perl/x2p/Makefile
new file mode 100644
index 0000000..8057dfb
--- /dev/null
+++ b/gnu/usr.bin/perl/x2p/Makefile
@@ -0,0 +1,23 @@
+
+PROG= a2p
+
+SRCS+= a2p.c hash.c str.c walk.c util.c
+CFLAGS+= -I${.CURDIR}/../perl
+CLEANFILES+= y.tab.h a2p.c
+
+LDADD= -lm
+DPADD= ${LIBM}
+
+MAN1+= a2p.1 s2p.1 h2ph.1
+
+beforeinstall:
+ ${INSTALL} -c -o ${BINOWN} -g ${BINGRP} -m 555 ${.CURDIR}/s2p \
+ ${DESTDIR}${BINDIR}
+ ${INSTALL} -c -o ${BINOWN} -g ${BINGRP} -m 555 ${.CURDIR}/h2ph \
+ ${DESTDIR}${BINDIR}
+
+afterinstall:
+ (DESTDIR=${DESTDIR}; cd ${DESTDIR}/usr/include; h2ph * sys/*)
+
+.include "../../Makefile.inc"
+.include <bsd.prog.mk>
diff --git a/gnu/usr.bin/perl/x2p/a2p.1 b/gnu/usr.bin/perl/x2p/a2p.1
new file mode 100644
index 0000000..58d8c07
--- /dev/null
+++ b/gnu/usr.bin/perl/x2p/a2p.1
@@ -0,0 +1,199 @@
+.rn '' }`
+''' $Header: /home/cvs/386BSD/ports/lang/perl/x2p/a2p.man,v 1.1.1.1 1993/08/23 21:30:10 nate Exp $
+'''
+''' $Log: a2p.man,v $
+.\" Revision 1.1.1.1 1993/08/23 21:30:10 nate
+.\" PERL!
+.\"
+''' Revision 4.0 91/03/20 01:57:11 lwall
+''' 4.0 baseline.
+'''
+''' Revision 3.0 89/10/18 15:34:22 lwall
+''' 3.0 baseline
+'''
+''' Revision 2.0.1.1 88/07/11 23:16:25 root
+''' patch2: changes related to 1985 awk
+'''
+''' Revision 2.0 88/06/05 00:15:36 root
+''' Baseline version 2.0.
+'''
+'''
+.de Sh
+.br
+.ne 5
+.PP
+\fB\\$1\fR
+.PP
+..
+.de Sp
+.if t .sp .5v
+.if n .sp
+..
+.de Ip
+.br
+.ie \\n.$>=3 .ne \\$3
+.el .ne 3
+.IP "\\$1" \\$2
+..
+'''
+''' Set up \*(-- to give an unbreakable dash;
+''' string Tr holds user defined translation string.
+''' Bell System Logo is used as a dummy character.
+'''
+.tr \(*W-|\(bv\*(Tr
+.ie n \{\
+.ds -- \(*W-
+.if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch
+.if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\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 A2P 1 LOCAL
+.SH NAME
+a2p - Awk to Perl translator
+.SH SYNOPSIS
+.B a2p [options] filename
+.SH DESCRIPTION
+.I A2p
+takes an awk script specified on the command line (or from standard input)
+and produces a comparable
+.I perl
+script on the standard output.
+.Sh "Options"
+Options include:
+.TP 5
+.B \-D<number>
+sets debugging flags.
+.TP 5
+.B \-F<character>
+tells a2p that this awk script is always invoked with this -F switch.
+.TP 5
+.B \-n<fieldlist>
+specifies the names of the input fields if input does not have to be split into
+an array.
+If you were translating an awk script that processes the password file, you
+might say:
+.sp
+ a2p -7 -nlogin.password.uid.gid.gcos.shell.home
+.sp
+Any delimiter can be used to separate the field names.
+.TP 5
+.B \-<number>
+causes a2p to assume that input will always have that many fields.
+.Sh "Considerations"
+A2p cannot do as good a job translating as a human would, but it usually
+does pretty well.
+There are some areas where you may want to examine the perl script produced
+and tweak it some.
+Here are some of them, in no particular order.
+.PP
+There is an awk idiom of putting int() around a string expression to force
+numeric interpretation, even though the argument is always integer anyway.
+This is generally unneeded in perl, but a2p can't tell if the argument
+is always going to be integer, so it leaves it in.
+You may wish to remove it.
+.PP
+Perl differentiates numeric comparison from string comparison.
+Awk has one operator for both that decides at run time which comparison
+to do.
+A2p does not try to do a complete job of awk emulation at this point.
+Instead it guesses which one you want.
+It's almost always right, but it can be spoofed.
+All such guesses are marked with the comment \*(L"#???\*(R".
+You should go through and check them.
+You might want to run at least once with the \-w switch to perl, which
+will warn you if you use == where you should have used eq.
+.PP
+Perl does not attempt to emulate the behavior of awk in which nonexistent
+array elements spring into existence simply by being referenced.
+If somehow you are relying on this mechanism to create null entries for
+a subsequent for...in, they won't be there in perl.
+.PP
+If a2p makes a split line that assigns to a list of variables that looks
+like (Fld1, Fld2, Fld3...) you may want
+to rerun a2p using the \-n option mentioned above.
+This will let you name the fields throughout the script.
+If it splits to an array instead, the script is probably referring to the number
+of fields somewhere.
+.PP
+The exit statement in awk doesn't necessarily exit; it goes to the END
+block if there is one.
+Awk scripts that do contortions within the END block to bypass the block under
+such circumstances can be simplified by removing the conditional
+in the END block and just exiting directly from the perl script.
+.PP
+Perl has two kinds of array, numerically-indexed and associative.
+Awk arrays are usually translated to associative arrays, but if you happen
+to know that the index is always going to be numeric you could change
+the {...} to [...].
+Iteration over an associative array is done using the keys() function, but
+iteration over a numeric array is NOT.
+You might need to modify any loop that is iterating over the array in question.
+.PP
+Awk starts by assuming OFMT has the value %.6g.
+Perl starts by assuming its equivalent, $#, to have the value %.20g.
+You'll want to set $# explicitly if you use the default value of OFMT.
+.PP
+Near the top of the line loop will be the split operation that is implicit in
+the awk script.
+There are times when you can move this down past some conditionals that
+test the entire record so that the split is not done as often.
+.PP
+For aesthetic reasons you may wish to change the array base $[ from 1 back
+to perl's default of 0, but remember to change all array subscripts AND
+all substr() and index() operations to match.
+.PP
+Cute comments that say "# Here is a workaround because awk is dumb" are passed
+through unmodified.
+.PP
+Awk scripts are often embedded in a shell script that pipes stuff into and
+out of awk.
+Often the shell script wrapper can be incorporated into the perl script, since
+perl can start up pipes into and out of itself, and can do other things that
+awk can't do by itself.
+.PP
+Scripts that refer to the special variables RSTART and RLENGTH can often
+be simplified by referring to the variables $`, $& and $', as long as they
+are within the scope of the pattern match that sets them.
+.PP
+The produced perl script may have subroutines defined to deal with awk's
+semantics regarding getline and print.
+Since a2p usually picks correctness over efficiency.
+it is almost always possible to rewrite such code to be more efficient by
+discarding the semantic sugar.
+.PP
+For efficiency, you may wish to remove the keyword from any return statement
+that is the last statement executed in a subroutine.
+A2p catches the most common case, but doesn't analyze embedded blocks for
+subtler cases.
+.PP
+ARGV[0] translates to $ARGV0, but ARGV[n] translates to $ARGV[$n].
+A loop that tries to iterate over ARGV[0] won't find it.
+.SH ENVIRONMENT
+A2p uses no environment variables.
+.SH AUTHOR
+Larry Wall <lwall@jpl-devvax.Jpl.Nasa.Gov>
+.SH FILES
+.SH SEE ALSO
+perl The perl compiler/interpreter
+.br
+s2p sed to perl translator
+.SH DIAGNOSTICS
+.SH BUGS
+It would be possible to emulate awk's behavior in selecting string versus
+numeric operations at run time by inspection of the operands, but it would
+be gross and inefficient.
+Besides, a2p almost always guesses right.
+.PP
+Storage for the awk syntax tree is currently static, and can run out.
+.rn }` ''
diff --git a/gnu/usr.bin/perl/x2p/a2p.h b/gnu/usr.bin/perl/x2p/a2p.h
new file mode 100644
index 0000000..cc59fb7
--- /dev/null
+++ b/gnu/usr.bin/perl/x2p/a2p.h
@@ -0,0 +1,344 @@
+/* $RCSfile: a2p.h,v $$Revision: 1.1.1.1 $$Date: 1994/09/10 06:27:53 $
+ *
+ * Copyright (c) 1991, Larry Wall
+ *
+ * You may distribute under the terms of either the GNU General Public
+ * License or the Artistic License, as specified in the README file.
+ *
+ * $Log: a2p.h,v $
+ * Revision 1.1.1.1 1994/09/10 06:27:53 gclarkii
+ * Initial import of Perl 4.046 bmaked
+ *
+ * Revision 1.1.1.1 1993/08/23 21:30:09 nate
+ * PERL!
+ *
+ * Revision 4.0.1.2 92/06/08 16:12:23 lwall
+ * patch20: hash tables now split only if the memory is available to do so
+ *
+ * Revision 4.0.1.1 91/06/07 12:12:27 lwall
+ * patch4: new copyright notice
+ *
+ * Revision 4.0 91/03/20 01:57:07 lwall
+ * 4.0 baseline.
+ *
+ */
+
+#define VOIDUSED 1
+#include "config.h"
+
+#ifndef HAS_BCOPY
+# define bcopy(s1,s2,l) memcpy(s2,s1,l)
+#endif
+#ifndef HAS_BZERO
+# define bzero(s,l) memset(s,0,l)
+#endif
+
+#include "handy.h"
+#define Nullop 0
+
+#define OPROG 1
+#define OJUNK 2
+#define OHUNKS 3
+#define ORANGE 4
+#define OPAT 5
+#define OHUNK 6
+#define OPPAREN 7
+#define OPANDAND 8
+#define OPOROR 9
+#define OPNOT 10
+#define OCPAREN 11
+#define OCANDAND 12
+#define OCOROR 13
+#define OCNOT 14
+#define ORELOP 15
+#define ORPAREN 16
+#define OMATCHOP 17
+#define OMPAREN 18
+#define OCONCAT 19
+#define OASSIGN 20
+#define OADD 21
+#define OSUBTRACT 22
+#define OMULT 23
+#define ODIV 24
+#define OMOD 25
+#define OPOSTINCR 26
+#define OPOSTDECR 27
+#define OPREINCR 28
+#define OPREDECR 29
+#define OUMINUS 30
+#define OUPLUS 31
+#define OPAREN 32
+#define OGETLINE 33
+#define OSPRINTF 34
+#define OSUBSTR 35
+#define OSTRING 36
+#define OSPLIT 37
+#define OSNEWLINE 38
+#define OINDEX 39
+#define ONUM 40
+#define OSTR 41
+#define OVAR 42
+#define OFLD 43
+#define ONEWLINE 44
+#define OCOMMENT 45
+#define OCOMMA 46
+#define OSEMICOLON 47
+#define OSCOMMENT 48
+#define OSTATES 49
+#define OSTATE 50
+#define OPRINT 51
+#define OPRINTF 52
+#define OBREAK 53
+#define ONEXT 54
+#define OEXIT 55
+#define OCONTINUE 56
+#define OREDIR 57
+#define OIF 58
+#define OWHILE 59
+#define OFOR 60
+#define OFORIN 61
+#define OVFLD 62
+#define OBLOCK 63
+#define OREGEX 64
+#define OLENGTH 65
+#define OLOG 66
+#define OEXP 67
+#define OSQRT 68
+#define OINT 69
+#define ODO 70
+#define OPOW 71
+#define OSUB 72
+#define OGSUB 73
+#define OMATCH 74
+#define OUSERFUN 75
+#define OUSERDEF 76
+#define OCLOSE 77
+#define OATAN2 78
+#define OSIN 79
+#define OCOS 80
+#define ORAND 81
+#define OSRAND 82
+#define ODELETE 83
+#define OSYSTEM 84
+#define OCOND 85
+#define ORETURN 86
+#define ODEFINED 87
+#define OSTAR 88
+
+#ifdef DOINIT
+char *opname[] = {
+ "0",
+ "PROG",
+ "JUNK",
+ "HUNKS",
+ "RANGE",
+ "PAT",
+ "HUNK",
+ "PPAREN",
+ "PANDAND",
+ "POROR",
+ "PNOT",
+ "CPAREN",
+ "CANDAND",
+ "COROR",
+ "CNOT",
+ "RELOP",
+ "RPAREN",
+ "MATCHOP",
+ "MPAREN",
+ "CONCAT",
+ "ASSIGN",
+ "ADD",
+ "SUBTRACT",
+ "MULT",
+ "DIV",
+ "MOD",
+ "POSTINCR",
+ "POSTDECR",
+ "PREINCR",
+ "PREDECR",
+ "UMINUS",
+ "UPLUS",
+ "PAREN",
+ "GETLINE",
+ "SPRINTF",
+ "SUBSTR",
+ "STRING",
+ "SPLIT",
+ "SNEWLINE",
+ "INDEX",
+ "NUM",
+ "STR",
+ "VAR",
+ "FLD",
+ "NEWLINE",
+ "COMMENT",
+ "COMMA",
+ "SEMICOLON",
+ "SCOMMENT",
+ "STATES",
+ "STATE",
+ "PRINT",
+ "PRINTF",
+ "BREAK",
+ "NEXT",
+ "EXIT",
+ "CONTINUE",
+ "REDIR",
+ "IF",
+ "WHILE",
+ "FOR",
+ "FORIN",
+ "VFLD",
+ "BLOCK",
+ "REGEX",
+ "LENGTH",
+ "LOG",
+ "EXP",
+ "SQRT",
+ "INT",
+ "DO",
+ "POW",
+ "SUB",
+ "GSUB",
+ "MATCH",
+ "USERFUN",
+ "USERDEF",
+ "CLOSE",
+ "ATAN2",
+ "SIN",
+ "COS",
+ "RAND",
+ "SRAND",
+ "DELETE",
+ "SYSTEM",
+ "COND",
+ "RETURN",
+ "DEFINED",
+ "STAR",
+ "89"
+};
+#else
+extern char *opname[];
+#endif
+
+EXT int mop INIT(1);
+
+union u_ops {
+ int ival;
+ char *cval;
+};
+#if defined(iAPX286) || defined(M_I286) || defined(I80286) /* 80286 hack */
+#define OPSMAX (64000/sizeof(union u_ops)) /* approx. max segment size */
+#else
+#define OPSMAX 50000
+#endif /* 80286 hack */
+union u_ops ops[OPSMAX];
+
+#include <stdio.h>
+#include <ctype.h>
+
+typedef struct string STR;
+typedef struct htbl HASH;
+
+#include "str.h"
+#include "hash.h"
+
+/* A string is TRUE if not "" or "0". */
+#define True(val) (tmps = (val), (*tmps && !(*tmps == '0' && !tmps[1])))
+EXT char *Yes INIT("1");
+EXT char *No INIT("");
+
+#define str_true(str) (Str = (str), (Str->str_pok ? True(Str->str_ptr) : (Str->str_nok ? (Str->str_nval != 0.0) : 0 )))
+
+#define str_peek(str) (Str = (str), (Str->str_pok ? Str->str_ptr : (Str->str_nok ? (sprintf(buf,"num(%g)",Str->str_nval),buf) : "" )))
+#define str_get(str) (Str = (str), (Str->str_pok ? Str->str_ptr : str_2ptr(Str)))
+#define str_gnum(str) (Str = (str), (Str->str_nok ? Str->str_nval : str_2num(Str)))
+EXT STR *Str;
+
+#define GROWSTR(pp,lp,len) if (*(lp) < (len)) growstr(pp,lp,len)
+
+STR *str_new();
+
+char *scanpat();
+char *scannum();
+
+void str_free();
+
+EXT int line INIT(0);
+
+EXT FILE *rsfp;
+EXT char buf[2048];
+EXT char *bufptr INIT(buf);
+
+EXT STR *linestr INIT(Nullstr);
+
+EXT char tokenbuf[2048];
+EXT int expectterm INIT(TRUE);
+
+#ifdef DEBUGGING
+EXT int debug INIT(0);
+EXT int dlevel INIT(0);
+#define YYDEBUG 1
+extern int yydebug;
+#endif
+
+EXT STR *freestrroot INIT(Nullstr);
+
+EXT STR str_no;
+EXT STR str_yes;
+
+EXT bool do_split INIT(FALSE);
+EXT bool split_to_array INIT(FALSE);
+EXT bool set_array_base INIT(FALSE);
+EXT bool saw_RS INIT(FALSE);
+EXT bool saw_OFS INIT(FALSE);
+EXT bool saw_ORS INIT(FALSE);
+EXT bool saw_line_op INIT(FALSE);
+EXT bool in_begin INIT(TRUE);
+EXT bool do_opens INIT(FALSE);
+EXT bool do_fancy_opens INIT(FALSE);
+EXT bool lval_field INIT(FALSE);
+EXT bool do_chop INIT(FALSE);
+EXT bool need_entire INIT(FALSE);
+EXT bool absmaxfld INIT(FALSE);
+EXT bool saw_altinput INIT(FALSE);
+
+EXT bool nomemok INIT(FALSE);
+
+EXT char const_FS INIT(0);
+EXT char *namelist INIT(Nullch);
+EXT char fswitch INIT(0);
+
+EXT int saw_FS INIT(0);
+EXT int maxfld INIT(0);
+EXT int arymax INIT(0);
+char *nameary[100];
+
+EXT STR *opens;
+
+EXT HASH *symtab;
+EXT HASH *curarghash;
+
+#define P_MIN 0
+#define P_LISTOP 5
+#define P_COMMA 10
+#define P_ASSIGN 15
+#define P_COND 20
+#define P_DOTDOT 25
+#define P_OROR 30
+#define P_ANDAND 35
+#define P_OR 40
+#define P_AND 45
+#define P_EQ 50
+#define P_REL 55
+#define P_UNI 60
+#define P_FILETEST 65
+#define P_SHIFT 70
+#define P_ADD 75
+#define P_MUL 80
+#define P_MATCH 85
+#define P_UNARY 90
+#define P_POW 95
+#define P_AUTO 100
+#define P_MAX 999
diff --git a/gnu/usr.bin/perl/x2p/a2p.y b/gnu/usr.bin/perl/x2p/a2p.y
new file mode 100644
index 0000000..bc86632
--- /dev/null
+++ b/gnu/usr.bin/perl/x2p/a2p.y
@@ -0,0 +1,406 @@
+%{
+/* $RCSfile: a2p.y,v $$Revision: 1.1.1.1 $$Date: 1993/08/23 21:30:09 $
+ *
+ * Copyright (c) 1991, Larry Wall
+ *
+ * You may distribute under the terms of either the GNU General Public
+ * License or the Artistic License, as specified in the README file.
+ *
+ * $Log: a2p.y,v $
+ * Revision 1.1.1.1 1993/08/23 21:30:09 nate
+ * PERL!
+ *
+ * Revision 4.0.1.2 92/06/08 16:13:03 lwall
+ * patch20: in a2p, getline should allow variable to be array element
+ *
+ * Revision 4.0.1.1 91/06/07 12:12:41 lwall
+ * patch4: new copyright notice
+ *
+ * Revision 4.0 91/03/20 01:57:21 lwall
+ * 4.0 baseline.
+ *
+ */
+
+#include "INTERN.h"
+#include "a2p.h"
+
+int root;
+int begins = Nullop;
+int ends = Nullop;
+
+%}
+%token BEGIN END
+%token REGEX
+%token SEMINEW NEWLINE COMMENT
+%token FUN1 FUNN GRGR
+%token PRINT PRINTF SPRINTF SPLIT
+%token IF ELSE WHILE FOR IN
+%token EXIT NEXT BREAK CONTINUE RET
+%token GETLINE DO SUB GSUB MATCH
+%token FUNCTION USERFUN DELETE
+
+%right ASGNOP
+%right '?' ':'
+%left OROR
+%left ANDAND
+%left IN
+%left NUMBER VAR SUBSTR INDEX
+%left MATCHOP
+%left RELOP '<' '>'
+%left OR
+%left STRING
+%left '+' '-'
+%left '*' '/' '%'
+%right UMINUS
+%left NOT
+%right '^'
+%left INCR DECR
+%left FIELD VFIELD
+
+%%
+
+program : junk hunks
+ { root = oper4(OPROG,$1,begins,$2,ends); }
+ ;
+
+begin : BEGIN '{' maybe states '}' junk
+ { begins = oper4(OJUNK,begins,$3,$4,$6); in_begin = FALSE;
+ $$ = Nullop; }
+ ;
+
+end : END '{' maybe states '}'
+ { ends = oper3(OJUNK,ends,$3,$4); $$ = Nullop; }
+ | end NEWLINE
+ { $$ = $1; }
+ ;
+
+hunks : hunks hunk junk
+ { $$ = oper3(OHUNKS,$1,$2,$3); }
+ | /* NULL */
+ { $$ = Nullop; }
+ ;
+
+hunk : patpat
+ { $$ = oper1(OHUNK,$1); need_entire = TRUE; }
+ | patpat '{' maybe states '}'
+ { $$ = oper2(OHUNK,$1,oper2(OJUNK,$3,$4)); }
+ | FUNCTION USERFUN '(' arg_list ')' maybe '{' maybe states '}'
+ { fixfargs($2,$4,0); $$ = oper5(OUSERDEF,$2,$4,$6,$8,$9); }
+ | '{' maybe states '}'
+ { $$ = oper2(OHUNK,Nullop,oper2(OJUNK,$2,$3)); }
+ | begin
+ | end
+ ;
+
+arg_list: expr_list
+ { $$ = rememberargs($$); }
+ ;
+
+patpat : cond
+ { $$ = oper1(OPAT,$1); }
+ | cond ',' cond
+ { $$ = oper2(ORANGE,$1,$3); }
+ ;
+
+cond : expr
+ | match
+ | rel
+ | compound_cond
+ ;
+
+compound_cond
+ : '(' compound_cond ')'
+ { $$ = oper1(OCPAREN,$2); }
+ | cond ANDAND maybe cond
+ { $$ = oper3(OCANDAND,$1,$3,$4); }
+ | cond OROR maybe cond
+ { $$ = oper3(OCOROR,$1,$3,$4); }
+ | NOT cond
+ { $$ = oper1(OCNOT,$2); }
+ ;
+
+rel : expr RELOP expr
+ { $$ = oper3(ORELOP,$2,$1,$3); }
+ | expr '>' expr
+ { $$ = oper3(ORELOP,string(">",1),$1,$3); }
+ | expr '<' expr
+ { $$ = oper3(ORELOP,string("<",1),$1,$3); }
+ | '(' rel ')'
+ { $$ = oper1(ORPAREN,$2); }
+ ;
+
+match : expr MATCHOP expr
+ { $$ = oper3(OMATCHOP,$2,$1,$3); }
+ | expr MATCHOP REGEX
+ { $$ = oper3(OMATCHOP,$2,$1,oper1(OREGEX,$3)); }
+ | REGEX %prec MATCHOP
+ { $$ = oper1(OREGEX,$1); }
+ | '(' match ')'
+ { $$ = oper1(OMPAREN,$2); }
+ ;
+
+expr : term
+ { $$ = $1; }
+ | expr term
+ { $$ = oper2(OCONCAT,$1,$2); }
+ | variable ASGNOP cond
+ { $$ = oper3(OASSIGN,$2,$1,$3);
+ if ((ops[$1].ival & 255) == OFLD)
+ lval_field = TRUE;
+ if ((ops[$1].ival & 255) == OVFLD)
+ lval_field = TRUE;
+ }
+ ;
+
+term : variable
+ { $$ = $1; }
+ | NUMBER
+ { $$ = oper1(ONUM,$1); }
+ | STRING
+ { $$ = oper1(OSTR,$1); }
+ | term '+' term
+ { $$ = oper2(OADD,$1,$3); }
+ | term '-' term
+ { $$ = oper2(OSUBTRACT,$1,$3); }
+ | term '*' term
+ { $$ = oper2(OMULT,$1,$3); }
+ | term '/' term
+ { $$ = oper2(ODIV,$1,$3); }
+ | term '%' term
+ { $$ = oper2(OMOD,$1,$3); }
+ | term '^' term
+ { $$ = oper2(OPOW,$1,$3); }
+ | term IN VAR
+ { $$ = oper2(ODEFINED,aryrefarg($3),$1); }
+ | term '?' term ':' term
+ { $$ = oper3(OCOND,$1,$3,$5); }
+ | variable INCR
+ { $$ = oper1(OPOSTINCR,$1); }
+ | variable DECR
+ { $$ = oper1(OPOSTDECR,$1); }
+ | INCR variable
+ { $$ = oper1(OPREINCR,$2); }
+ | DECR variable
+ { $$ = oper1(OPREDECR,$2); }
+ | '-' term %prec UMINUS
+ { $$ = oper1(OUMINUS,$2); }
+ | '+' term %prec UMINUS
+ { $$ = oper1(OUPLUS,$2); }
+ | '(' cond ')'
+ { $$ = oper1(OPAREN,$2); }
+ | GETLINE
+ { $$ = oper0(OGETLINE); }
+ | GETLINE variable
+ { $$ = oper1(OGETLINE,$2); }
+ | GETLINE '<' expr
+ { $$ = oper3(OGETLINE,Nullop,string("<",1),$3);
+ if (ops[$3].ival != OSTR + (1<<8)) do_fancy_opens = TRUE; }
+ | GETLINE variable '<' expr
+ { $$ = oper3(OGETLINE,$2,string("<",1),$4);
+ if (ops[$4].ival != OSTR + (1<<8)) do_fancy_opens = TRUE; }
+ | term 'p' GETLINE
+ { $$ = oper3(OGETLINE,Nullop,string("|",1),$1);
+ if (ops[$1].ival != OSTR + (1<<8)) do_fancy_opens = TRUE; }
+ | term 'p' GETLINE variable
+ { $$ = oper3(OGETLINE,$4,string("|",1),$1);
+ if (ops[$1].ival != OSTR + (1<<8)) do_fancy_opens = TRUE; }
+ | FUN1
+ { $$ = oper0($1); need_entire = do_chop = TRUE; }
+ | FUN1 '(' ')'
+ { $$ = oper1($1,Nullop); need_entire = do_chop = TRUE; }
+ | FUN1 '(' expr ')'
+ { $$ = oper1($1,$3); }
+ | FUNN '(' expr_list ')'
+ { $$ = oper1($1,$3); }
+ | USERFUN '(' expr_list ')'
+ { $$ = oper2(OUSERFUN,$1,$3); }
+ | SPRINTF expr_list
+ { $$ = oper1(OSPRINTF,$2); }
+ | SUBSTR '(' expr ',' expr ',' expr ')'
+ { $$ = oper3(OSUBSTR,$3,$5,$7); }
+ | SUBSTR '(' expr ',' expr ')'
+ { $$ = oper2(OSUBSTR,$3,$5); }
+ | SPLIT '(' expr ',' VAR ',' expr ')'
+ { $$ = oper3(OSPLIT,$3,aryrefarg(numary($5)),$7); }
+ | SPLIT '(' expr ',' VAR ',' REGEX ')'
+ { $$ = oper3(OSPLIT,$3,aryrefarg(numary($5)),oper1(OREGEX,$7));}
+ | SPLIT '(' expr ',' VAR ')'
+ { $$ = oper2(OSPLIT,$3,aryrefarg(numary($5))); }
+ | INDEX '(' expr ',' expr ')'
+ { $$ = oper2(OINDEX,$3,$5); }
+ | MATCH '(' expr ',' REGEX ')'
+ { $$ = oper2(OMATCH,$3,oper1(OREGEX,$5)); }
+ | MATCH '(' expr ',' expr ')'
+ { $$ = oper2(OMATCH,$3,$5); }
+ | SUB '(' expr ',' expr ')'
+ { $$ = oper2(OSUB,$3,$5); }
+ | SUB '(' REGEX ',' expr ')'
+ { $$ = oper2(OSUB,oper1(OREGEX,$3),$5); }
+ | GSUB '(' expr ',' expr ')'
+ { $$ = oper2(OGSUB,$3,$5); }
+ | GSUB '(' REGEX ',' expr ')'
+ { $$ = oper2(OGSUB,oper1(OREGEX,$3),$5); }
+ | SUB '(' expr ',' expr ',' expr ')'
+ { $$ = oper3(OSUB,$3,$5,$7); }
+ | SUB '(' REGEX ',' expr ',' expr ')'
+ { $$ = oper3(OSUB,oper1(OREGEX,$3),$5,$7); }
+ | GSUB '(' expr ',' expr ',' expr ')'
+ { $$ = oper3(OGSUB,$3,$5,$7); }
+ | GSUB '(' REGEX ',' expr ',' expr ')'
+ { $$ = oper3(OGSUB,oper1(OREGEX,$3),$5,$7); }
+ ;
+
+variable: VAR
+ { $$ = oper1(OVAR,$1); }
+ | VAR '[' expr_list ']'
+ { $$ = oper2(OVAR,aryrefarg($1),$3); }
+ | FIELD
+ { $$ = oper1(OFLD,$1); }
+ | VFIELD term
+ { $$ = oper1(OVFLD,$2); }
+ ;
+
+expr_list
+ : expr
+ | clist
+ | /* NULL */
+ { $$ = Nullop; }
+ ;
+
+clist : expr ',' maybe expr
+ { $$ = oper3(OCOMMA,$1,$3,$4); }
+ | clist ',' maybe expr
+ { $$ = oper3(OCOMMA,$1,$3,$4); }
+ | '(' clist ')' /* these parens are invisible */
+ { $$ = $2; }
+ ;
+
+junk : junk hunksep
+ { $$ = oper2(OJUNK,$1,$2); }
+ | /* NULL */
+ { $$ = Nullop; }
+ ;
+
+hunksep : ';'
+ { $$ = oper2(OJUNK,oper0(OSEMICOLON),oper0(ONEWLINE)); }
+ | SEMINEW
+ { $$ = oper2(OJUNK,oper0(OSEMICOLON),oper0(ONEWLINE)); }
+ | NEWLINE
+ { $$ = oper0(ONEWLINE); }
+ | COMMENT
+ { $$ = oper1(OCOMMENT,$1); }
+ ;
+
+maybe : maybe nlstuff
+ { $$ = oper2(OJUNK,$1,$2); }
+ | /* NULL */
+ { $$ = Nullop; }
+ ;
+
+nlstuff : NEWLINE
+ { $$ = oper0(ONEWLINE); }
+ | COMMENT
+ { $$ = oper1(OCOMMENT,$1); }
+ ;
+
+separator
+ : ';' maybe
+ { $$ = oper2(OJUNK,oper0(OSEMICOLON),$2); }
+ | SEMINEW maybe
+ { $$ = oper2(OJUNK,oper0(OSNEWLINE),$2); }
+ | NEWLINE maybe
+ { $$ = oper2(OJUNK,oper0(OSNEWLINE),$2); }
+ | COMMENT maybe
+ { $$ = oper2(OJUNK,oper1(OSCOMMENT,$1),$2); }
+ ;
+
+states : states statement
+ { $$ = oper2(OSTATES,$1,$2); }
+ | /* NULL */
+ { $$ = Nullop; }
+ ;
+
+statement
+ : simple separator maybe
+ { $$ = oper2(OJUNK,oper2(OSTATE,$1,$2),$3); }
+ | ';' maybe
+ { $$ = oper2(OSTATE,Nullop,oper2(OJUNK,oper0(OSEMICOLON),$2)); }
+ | SEMINEW maybe
+ { $$ = oper2(OSTATE,Nullop,oper2(OJUNK,oper0(OSNEWLINE),$2)); }
+ | compound
+ ;
+
+simpnull: simple
+ | /* NULL */
+ { $$ = Nullop; }
+ ;
+
+simple
+ : expr
+ | PRINT expr_list redir expr
+ { $$ = oper3(OPRINT,$2,$3,$4);
+ do_opens = TRUE;
+ saw_ORS = saw_OFS = TRUE;
+ if (!$2) need_entire = TRUE;
+ if (ops[$4].ival != OSTR + (1<<8)) do_fancy_opens = TRUE; }
+ | PRINT expr_list
+ { $$ = oper1(OPRINT,$2);
+ if (!$2) need_entire = TRUE;
+ saw_ORS = saw_OFS = TRUE;
+ }
+ | PRINTF expr_list redir expr
+ { $$ = oper3(OPRINTF,$2,$3,$4);
+ do_opens = TRUE;
+ if (!$2) need_entire = TRUE;
+ if (ops[$4].ival != OSTR + (1<<8)) do_fancy_opens = TRUE; }
+ | PRINTF expr_list
+ { $$ = oper1(OPRINTF,$2);
+ if (!$2) need_entire = TRUE;
+ }
+ | BREAK
+ { $$ = oper0(OBREAK); }
+ | NEXT
+ { $$ = oper0(ONEXT); }
+ | EXIT
+ { $$ = oper0(OEXIT); }
+ | EXIT expr
+ { $$ = oper1(OEXIT,$2); }
+ | CONTINUE
+ { $$ = oper0(OCONTINUE); }
+ | RET
+ { $$ = oper0(ORETURN); }
+ | RET expr
+ { $$ = oper1(ORETURN,$2); }
+ | DELETE VAR '[' expr ']'
+ { $$ = oper2(ODELETE,aryrefarg($2),$4); }
+ ;
+
+redir : '>' %prec FIELD
+ { $$ = oper1(OREDIR,string(">",1)); }
+ | GRGR
+ { $$ = oper1(OREDIR,string(">>",2)); }
+ | '|'
+ { $$ = oper1(OREDIR,string("|",1)); }
+ ;
+
+compound
+ : IF '(' cond ')' maybe statement
+ { $$ = oper2(OIF,$3,bl($6,$5)); }
+ | IF '(' cond ')' maybe statement ELSE maybe statement
+ { $$ = oper3(OIF,$3,bl($6,$5),bl($9,$8)); }
+ | WHILE '(' cond ')' maybe statement
+ { $$ = oper2(OWHILE,$3,bl($6,$5)); }
+ | DO maybe statement WHILE '(' cond ')'
+ { $$ = oper2(ODO,bl($3,$2),$6); }
+ | FOR '(' simpnull ';' cond ';' simpnull ')' maybe statement
+ { $$ = oper4(OFOR,$3,$5,$7,bl($10,$9)); }
+ | FOR '(' simpnull ';' ';' simpnull ')' maybe statement
+ { $$ = oper4(OFOR,$3,string("",0),$6,bl($9,$8)); }
+ | FOR '(' expr ')' maybe statement
+ { $$ = oper2(OFORIN,$3,bl($6,$5)); }
+ | '{' maybe states '}' maybe
+ { $$ = oper3(OBLOCK,oper2(OJUNK,$2,$3),Nullop,$5); }
+ ;
+
+%%
+#include "a2py.c"
diff --git a/gnu/usr.bin/perl/x2p/a2py.c b/gnu/usr.bin/perl/x2p/a2py.c
new file mode 100644
index 0000000..fcc196b
--- /dev/null
+++ b/gnu/usr.bin/perl/x2p/a2py.c
@@ -0,0 +1,1304 @@
+/* $RCSfile: a2py.c,v $$Revision: 1.1.1.1 $$Date: 1994/09/10 06:27:53 $
+ *
+ * Copyright (c) 1991, Larry Wall
+ *
+ * You may distribute under the terms of either the GNU General Public
+ * License or the Artistic License, as specified in the README file.
+ *
+ * $Log: a2py.c,v $
+ * Revision 1.1.1.1 1994/09/10 06:27:53 gclarkii
+ * Initial import of Perl 4.046 bmaked
+ *
+ * Revision 1.1.1.1 1993/08/23 21:30:10 nate
+ * PERL!
+ *
+ * Revision 4.0.1.2 92/06/08 16:15:16 lwall
+ * patch20: in a2p, now warns about spurious backslashes
+ * patch20: in a2p, now allows [ to be backslashed in pattern
+ * patch20: in a2p, now allows numbers of the form 2.
+ *
+ * Revision 4.0.1.1 91/06/07 12:12:59 lwall
+ * patch4: new copyright notice
+ *
+ * Revision 4.0 91/03/20 01:57:26 lwall
+ * 4.0 baseline.
+ *
+ */
+
+#ifdef OS2
+#include "../patchlevel.h"
+#endif
+#include "util.h"
+char *index();
+
+char *filename;
+char *myname;
+
+int checkers = 0;
+STR *walk();
+
+#ifdef OS2
+usage()
+{
+ printf("\nThis is the AWK to PERL translator, version 4.0, patchlevel %d\n", PATCHLEVEL);
+ printf("\nUsage: %s [-D<number>] [-F<char>] [-n<fieldlist>] [-<number>] filename\n", myname);
+ printf("\n -D<number> sets debugging flags."
+ "\n -F<character> the awk script to translate is always invoked with"
+ "\n this -F switch."
+ "\n -n<fieldlist> specifies the names of the input fields if input does"
+ "\n not have to be split into an array."
+ "\n -<number> causes a2p to assume that input will always have that"
+ "\n many fields.\n");
+ exit(1);
+}
+#endif
+main(argc,argv,env)
+register int argc;
+register char **argv;
+register char **env;
+{
+ register STR *str;
+ register char *s;
+ int i;
+ STR *tmpstr;
+
+ myname = argv[0];
+ linestr = str_new(80);
+ str = str_new(0); /* first used for -I flags */
+ for (argc--,argv++; argc; argc--,argv++) {
+ if (argv[0][0] != '-' || !argv[0][1])
+ break;
+ reswitch:
+ switch (argv[0][1]) {
+#ifdef DEBUGGING
+ case 'D':
+ debug = atoi(argv[0]+2);
+#ifdef YYDEBUG
+ yydebug = (debug & 1);
+#endif
+ break;
+#endif
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ maxfld = atoi(argv[0]+1);
+ absmaxfld = TRUE;
+ break;
+ case 'F':
+ fswitch = argv[0][2];
+ break;
+ case 'n':
+ namelist = savestr(argv[0]+2);
+ break;
+ case '-':
+ argc--,argv++;
+ goto switch_end;
+ case 0:
+ break;
+ default:
+ fatal("Unrecognized switch: %s\n",argv[0]);
+#ifdef OS2
+ usage();
+#endif
+ }
+ }
+ switch_end:
+
+ /* open script */
+
+ if (argv[0] == Nullch) {
+#ifdef OS2
+ if ( isatty(fileno(stdin)) )
+ usage();
+#endif
+ argv[0] = "-";
+ }
+ filename = savestr(argv[0]);
+
+ filename = savestr(argv[0]);
+ if (strEQ(filename,"-"))
+ argv[0] = "";
+ if (!*argv[0])
+ rsfp = stdin;
+ else
+ rsfp = fopen(argv[0],"r");
+ if (rsfp == Nullfp)
+ fatal("Awk script \"%s\" doesn't seem to exist.\n",filename);
+
+ /* init tokener */
+
+ bufptr = str_get(linestr);
+ symtab = hnew();
+ curarghash = hnew();
+
+ /* now parse the report spec */
+
+ if (yyparse())
+ fatal("Translation aborted due to syntax errors.\n");
+
+#ifdef DEBUGGING
+ if (debug & 2) {
+ int type, len;
+
+ for (i=1; i<mop;) {
+ type = ops[i].ival;
+ len = type >> 8;
+ type &= 255;
+ printf("%d\t%d\t%d\t%-10s",i++,type,len,opname[type]);
+ if (type == OSTRING)
+ printf("\t\"%s\"\n",ops[i].cval),i++;
+ else {
+ while (len--) {
+ printf("\t%d",ops[i].ival),i++;
+ }
+ putchar('\n');
+ }
+ }
+ }
+ if (debug & 8)
+ dump(root);
+#endif
+
+ /* first pass to look for numeric variables */
+
+ prewalk(0,0,root,&i);
+
+ /* second pass to produce new program */
+
+ tmpstr = walk(0,0,root,&i,P_MIN);
+ str = str_make("#!");
+ str_cat(str, BIN);
+ str_cat(str, "/perl\neval \"exec ");
+ str_cat(str, BIN);
+ str_cat(str, "/perl -S $0 $*\"\n\
+ if $running_under_some_shell;\n\
+ # this emulates #! processing on NIH machines.\n\
+ # (remove #! line above if indigestible)\n\n");
+ str_cat(str,
+ "eval '$'.$1.'$2;' while $ARGV[0] =~ /^([A-Za-z_]+=)(.*)/ && shift;\n");
+ str_cat(str,
+ " # process any FOO=bar switches\n\n");
+ if (do_opens && opens) {
+ str_scat(str,opens);
+ str_free(opens);
+ str_cat(str,"\n");
+ }
+ str_scat(str,tmpstr);
+ str_free(tmpstr);
+#ifdef DEBUGGING
+ if (!(debug & 16))
+#endif
+ fixup(str);
+ putlines(str);
+ if (checkers) {
+ fprintf(stderr,
+ "Please check my work on the %d line%s I've marked with \"#???\".\n",
+ checkers, checkers == 1 ? "" : "s" );
+ fprintf(stderr,
+ "The operation I've selected may be wrong for the operand types.\n");
+ }
+ exit(0);
+}
+
+#define RETURN(retval) return (bufptr = s,retval)
+#define XTERM(retval) return (expectterm = TRUE,bufptr = s,retval)
+#define XOP(retval) return (expectterm = FALSE,bufptr = s,retval)
+#define ID(x) return (yylval=string(x,0),expectterm = FALSE,bufptr = s,idtype)
+
+int idtype;
+
+yylex()
+{
+ register char *s = bufptr;
+ register char *d;
+ register int tmp;
+
+ retry:
+#ifdef YYDEBUG
+ if (yydebug)
+ if (index(s,'\n'))
+ fprintf(stderr,"Tokener at %s",s);
+ else
+ fprintf(stderr,"Tokener at %s\n",s);
+#endif
+ switch (*s) {
+ default:
+ fprintf(stderr,
+ "Unrecognized character %c in file %s line %d--ignoring.\n",
+ *s++,filename,line);
+ goto retry;
+ case '\\':
+ s++;
+ if (*s && *s != '\n') {
+ yyerror("Ignoring spurious backslash");
+ goto retry;
+ }
+ /*FALLSTHROUGH*/
+ case 0:
+ s = str_get(linestr);
+ *s = '\0';
+ if (!rsfp)
+ RETURN(0);
+ line++;
+ if ((s = str_gets(linestr, rsfp)) == Nullch) {
+ if (rsfp != stdin)
+ fclose(rsfp);
+ rsfp = Nullfp;
+ s = str_get(linestr);
+ RETURN(0);
+ }
+ goto retry;
+ case ' ': case '\t':
+ s++;
+ goto retry;
+ case '\n':
+ *s = '\0';
+ XTERM(NEWLINE);
+ case '#':
+ yylval = string(s,0);
+ *s = '\0';
+ XTERM(COMMENT);
+ case ';':
+ tmp = *s++;
+ if (*s == '\n') {
+ s++;
+ XTERM(SEMINEW);
+ }
+ XTERM(tmp);
+ case '(':
+ tmp = *s++;
+ XTERM(tmp);
+ case '{':
+ case '[':
+ case ')':
+ case ']':
+ case '?':
+ case ':':
+ tmp = *s++;
+ XOP(tmp);
+ case 127:
+ s++;
+ XTERM('}');
+ case '}':
+ for (d = s + 1; isspace(*d); d++) ;
+ if (!*d)
+ s = d - 1;
+ *s = 127;
+ XTERM(';');
+ case ',':
+ tmp = *s++;
+ XTERM(tmp);
+ case '~':
+ s++;
+ yylval = string("~",1);
+ XTERM(MATCHOP);
+ case '+':
+ case '-':
+ if (s[1] == *s) {
+ s++;
+ if (*s++ == '+')
+ XTERM(INCR);
+ else
+ XTERM(DECR);
+ }
+ /* FALL THROUGH */
+ case '*':
+ case '%':
+ case '^':
+ tmp = *s++;
+ if (*s == '=') {
+ if (tmp == '^')
+ yylval = string("**=",3);
+ else
+ yylval = string(s-1,2);
+ s++;
+ XTERM(ASGNOP);
+ }
+ XTERM(tmp);
+ case '&':
+ s++;
+ tmp = *s++;
+ if (tmp == '&')
+ XTERM(ANDAND);
+ s--;
+ XTERM('&');
+ case '|':
+ s++;
+ tmp = *s++;
+ if (tmp == '|')
+ XTERM(OROR);
+ s--;
+ while (*s == ' ' || *s == '\t')
+ s++;
+ if (strnEQ(s,"getline",7))
+ XTERM('p');
+ else
+ XTERM('|');
+ case '=':
+ s++;
+ tmp = *s++;
+ if (tmp == '=') {
+ yylval = string("==",2);
+ XTERM(RELOP);
+ }
+ s--;
+ yylval = string("=",1);
+ XTERM(ASGNOP);
+ case '!':
+ s++;
+ tmp = *s++;
+ if (tmp == '=') {
+ yylval = string("!=",2);
+ XTERM(RELOP);
+ }
+ if (tmp == '~') {
+ yylval = string("!~",2);
+ XTERM(MATCHOP);
+ }
+ s--;
+ XTERM(NOT);
+ case '<':
+ s++;
+ tmp = *s++;
+ if (tmp == '=') {
+ yylval = string("<=",2);
+ XTERM(RELOP);
+ }
+ s--;
+ XTERM('<');
+ case '>':
+ s++;
+ tmp = *s++;
+ if (tmp == '>') {
+ yylval = string(">>",2);
+ XTERM(GRGR);
+ }
+ if (tmp == '=') {
+ yylval = string(">=",2);
+ XTERM(RELOP);
+ }
+ s--;
+ XTERM('>');
+
+#define SNARFWORD \
+ d = tokenbuf; \
+ while (isalpha(*s) || isdigit(*s) || *s == '_') \
+ *d++ = *s++; \
+ *d = '\0'; \
+ d = tokenbuf; \
+ if (*s == '(') \
+ idtype = USERFUN; \
+ else \
+ idtype = VAR;
+
+ case '$':
+ s++;
+ if (*s == '0') {
+ s++;
+ do_chop = TRUE;
+ need_entire = TRUE;
+ idtype = VAR;
+ ID("0");
+ }
+ do_split = TRUE;
+ if (isdigit(*s)) {
+ for (d = s; isdigit(*s); s++) ;
+ yylval = string(d,s-d);
+ tmp = atoi(d);
+ if (tmp > maxfld)
+ maxfld = tmp;
+ XOP(FIELD);
+ }
+ split_to_array = set_array_base = TRUE;
+ XOP(VFIELD);
+
+ case '/': /* may either be division or pattern */
+ if (expectterm) {
+ s = scanpat(s);
+ XTERM(REGEX);
+ }
+ tmp = *s++;
+ if (*s == '=') {
+ yylval = string("/=",2);
+ s++;
+ XTERM(ASGNOP);
+ }
+ XTERM(tmp);
+
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9': case '.':
+ s = scannum(s);
+ XOP(NUMBER);
+ case '"':
+ s++;
+ s = cpy2(tokenbuf,s,s[-1]);
+ if (!*s)
+ fatal("String not terminated:\n%s",str_get(linestr));
+ s++;
+ yylval = string(tokenbuf,0);
+ XOP(STRING);
+
+ case 'a': case 'A':
+ SNARFWORD;
+ if (strEQ(d,"ARGC"))
+ set_array_base = TRUE;
+ if (strEQ(d,"ARGV")) {
+ yylval=numary(string("ARGV",0));
+ XOP(VAR);
+ }
+ if (strEQ(d,"atan2")) {
+ yylval = OATAN2;
+ XTERM(FUNN);
+ }
+ ID(d);
+ case 'b': case 'B':
+ SNARFWORD;
+ if (strEQ(d,"break"))
+ XTERM(BREAK);
+ if (strEQ(d,"BEGIN"))
+ XTERM(BEGIN);
+ ID(d);
+ case 'c': case 'C':
+ SNARFWORD;
+ if (strEQ(d,"continue"))
+ XTERM(CONTINUE);
+ if (strEQ(d,"cos")) {
+ yylval = OCOS;
+ XTERM(FUN1);
+ }
+ if (strEQ(d,"close")) {
+ do_fancy_opens = 1;
+ yylval = OCLOSE;
+ XTERM(FUN1);
+ }
+ if (strEQ(d,"chdir"))
+ *d = toupper(*d);
+ else if (strEQ(d,"crypt"))
+ *d = toupper(*d);
+ else if (strEQ(d,"chop"))
+ *d = toupper(*d);
+ else if (strEQ(d,"chmod"))
+ *d = toupper(*d);
+ else if (strEQ(d,"chown"))
+ *d = toupper(*d);
+ ID(d);
+ case 'd': case 'D':
+ SNARFWORD;
+ if (strEQ(d,"do"))
+ XTERM(DO);
+ if (strEQ(d,"delete"))
+ XTERM(DELETE);
+ if (strEQ(d,"die"))
+ *d = toupper(*d);
+ ID(d);
+ case 'e': case 'E':
+ SNARFWORD;
+ if (strEQ(d,"END"))
+ XTERM(END);
+ if (strEQ(d,"else"))
+ XTERM(ELSE);
+ if (strEQ(d,"exit")) {
+ saw_line_op = TRUE;
+ XTERM(EXIT);
+ }
+ if (strEQ(d,"exp")) {
+ yylval = OEXP;
+ XTERM(FUN1);
+ }
+ if (strEQ(d,"elsif"))
+ *d = toupper(*d);
+ else if (strEQ(d,"eq"))
+ *d = toupper(*d);
+ else if (strEQ(d,"eval"))
+ *d = toupper(*d);
+ else if (strEQ(d,"eof"))
+ *d = toupper(*d);
+ else if (strEQ(d,"each"))
+ *d = toupper(*d);
+ else if (strEQ(d,"exec"))
+ *d = toupper(*d);
+ ID(d);
+ case 'f': case 'F':
+ SNARFWORD;
+ if (strEQ(d,"FS")) {
+ saw_FS++;
+ if (saw_FS == 1 && in_begin) {
+ for (d = s; *d && isspace(*d); d++) ;
+ if (*d == '=') {
+ for (d++; *d && isspace(*d); d++) ;
+ if (*d == '"' && d[2] == '"')
+ const_FS = d[1];
+ }
+ }
+ ID(tokenbuf);
+ }
+ if (strEQ(d,"for"))
+ XTERM(FOR);
+ else if (strEQ(d,"function"))
+ XTERM(FUNCTION);
+ if (strEQ(d,"FILENAME"))
+ d = "ARGV";
+ if (strEQ(d,"foreach"))
+ *d = toupper(*d);
+ else if (strEQ(d,"format"))
+ *d = toupper(*d);
+ else if (strEQ(d,"fork"))
+ *d = toupper(*d);
+ else if (strEQ(d,"fh"))
+ *d = toupper(*d);
+ ID(d);
+ case 'g': case 'G':
+ SNARFWORD;
+ if (strEQ(d,"getline"))
+ XTERM(GETLINE);
+ if (strEQ(d,"gsub"))
+ XTERM(GSUB);
+ if (strEQ(d,"ge"))
+ *d = toupper(*d);
+ else if (strEQ(d,"gt"))
+ *d = toupper(*d);
+ else if (strEQ(d,"goto"))
+ *d = toupper(*d);
+ else if (strEQ(d,"gmtime"))
+ *d = toupper(*d);
+ ID(d);
+ case 'h': case 'H':
+ SNARFWORD;
+ if (strEQ(d,"hex"))
+ *d = toupper(*d);
+ ID(d);
+ case 'i': case 'I':
+ SNARFWORD;
+ if (strEQ(d,"if"))
+ XTERM(IF);
+ if (strEQ(d,"in"))
+ XTERM(IN);
+ if (strEQ(d,"index")) {
+ set_array_base = TRUE;
+ XTERM(INDEX);
+ }
+ if (strEQ(d,"int")) {
+ yylval = OINT;
+ XTERM(FUN1);
+ }
+ ID(d);
+ case 'j': case 'J':
+ SNARFWORD;
+ if (strEQ(d,"join"))
+ *d = toupper(*d);
+ ID(d);
+ case 'k': case 'K':
+ SNARFWORD;
+ if (strEQ(d,"keys"))
+ *d = toupper(*d);
+ else if (strEQ(d,"kill"))
+ *d = toupper(*d);
+ ID(d);
+ case 'l': case 'L':
+ SNARFWORD;
+ if (strEQ(d,"length")) {
+ yylval = OLENGTH;
+ XTERM(FUN1);
+ }
+ if (strEQ(d,"log")) {
+ yylval = OLOG;
+ XTERM(FUN1);
+ }
+ if (strEQ(d,"last"))
+ *d = toupper(*d);
+ else if (strEQ(d,"local"))
+ *d = toupper(*d);
+ else if (strEQ(d,"lt"))
+ *d = toupper(*d);
+ else if (strEQ(d,"le"))
+ *d = toupper(*d);
+ else if (strEQ(d,"locatime"))
+ *d = toupper(*d);
+ else if (strEQ(d,"link"))
+ *d = toupper(*d);
+ ID(d);
+ case 'm': case 'M':
+ SNARFWORD;
+ if (strEQ(d,"match")) {
+ set_array_base = TRUE;
+ XTERM(MATCH);
+ }
+ if (strEQ(d,"m"))
+ *d = toupper(*d);
+ ID(d);
+ case 'n': case 'N':
+ SNARFWORD;
+ if (strEQ(d,"NF"))
+ do_chop = do_split = split_to_array = set_array_base = TRUE;
+ if (strEQ(d,"next")) {
+ saw_line_op = TRUE;
+ XTERM(NEXT);
+ }
+ if (strEQ(d,"ne"))
+ *d = toupper(*d);
+ ID(d);
+ case 'o': case 'O':
+ SNARFWORD;
+ if (strEQ(d,"ORS")) {
+ saw_ORS = TRUE;
+ d = "\\";
+ }
+ if (strEQ(d,"OFS")) {
+ saw_OFS = TRUE;
+ d = ",";
+ }
+ if (strEQ(d,"OFMT")) {
+ d = "#";
+ }
+ if (strEQ(d,"open"))
+ *d = toupper(*d);
+ else if (strEQ(d,"ord"))
+ *d = toupper(*d);
+ else if (strEQ(d,"oct"))
+ *d = toupper(*d);
+ ID(d);
+ case 'p': case 'P':
+ SNARFWORD;
+ if (strEQ(d,"print")) {
+ XTERM(PRINT);
+ }
+ if (strEQ(d,"printf")) {
+ XTERM(PRINTF);
+ }
+ if (strEQ(d,"push"))
+ *d = toupper(*d);
+ else if (strEQ(d,"pop"))
+ *d = toupper(*d);
+ ID(d);
+ case 'q': case 'Q':
+ SNARFWORD;
+ ID(d);
+ case 'r': case 'R':
+ SNARFWORD;
+ if (strEQ(d,"RS")) {
+ d = "/";
+ saw_RS = TRUE;
+ }
+ if (strEQ(d,"rand")) {
+ yylval = ORAND;
+ XTERM(FUN1);
+ }
+ if (strEQ(d,"return"))
+ XTERM(RET);
+ if (strEQ(d,"reset"))
+ *d = toupper(*d);
+ else if (strEQ(d,"redo"))
+ *d = toupper(*d);
+ else if (strEQ(d,"rename"))
+ *d = toupper(*d);
+ ID(d);
+ case 's': case 'S':
+ SNARFWORD;
+ if (strEQ(d,"split")) {
+ set_array_base = TRUE;
+ XOP(SPLIT);
+ }
+ if (strEQ(d,"substr")) {
+ set_array_base = TRUE;
+ XTERM(SUBSTR);
+ }
+ if (strEQ(d,"sub"))
+ XTERM(SUB);
+ if (strEQ(d,"sprintf"))
+ XTERM(SPRINTF);
+ if (strEQ(d,"sqrt")) {
+ yylval = OSQRT;
+ XTERM(FUN1);
+ }
+ if (strEQ(d,"SUBSEP")) {
+ d = ";";
+ }
+ if (strEQ(d,"sin")) {
+ yylval = OSIN;
+ XTERM(FUN1);
+ }
+ if (strEQ(d,"srand")) {
+ yylval = OSRAND;
+ XTERM(FUN1);
+ }
+ if (strEQ(d,"system")) {
+ yylval = OSYSTEM;
+ XTERM(FUN1);
+ }
+ if (strEQ(d,"s"))
+ *d = toupper(*d);
+ else if (strEQ(d,"shift"))
+ *d = toupper(*d);
+ else if (strEQ(d,"select"))
+ *d = toupper(*d);
+ else if (strEQ(d,"seek"))
+ *d = toupper(*d);
+ else if (strEQ(d,"stat"))
+ *d = toupper(*d);
+ else if (strEQ(d,"study"))
+ *d = toupper(*d);
+ else if (strEQ(d,"sleep"))
+ *d = toupper(*d);
+ else if (strEQ(d,"symlink"))
+ *d = toupper(*d);
+ else if (strEQ(d,"sort"))
+ *d = toupper(*d);
+ ID(d);
+ case 't': case 'T':
+ SNARFWORD;
+ if (strEQ(d,"tr"))
+ *d = toupper(*d);
+ else if (strEQ(d,"tell"))
+ *d = toupper(*d);
+ else if (strEQ(d,"time"))
+ *d = toupper(*d);
+ else if (strEQ(d,"times"))
+ *d = toupper(*d);
+ ID(d);
+ case 'u': case 'U':
+ SNARFWORD;
+ if (strEQ(d,"until"))
+ *d = toupper(*d);
+ else if (strEQ(d,"unless"))
+ *d = toupper(*d);
+ else if (strEQ(d,"umask"))
+ *d = toupper(*d);
+ else if (strEQ(d,"unshift"))
+ *d = toupper(*d);
+ else if (strEQ(d,"unlink"))
+ *d = toupper(*d);
+ else if (strEQ(d,"utime"))
+ *d = toupper(*d);
+ ID(d);
+ case 'v': case 'V':
+ SNARFWORD;
+ if (strEQ(d,"values"))
+ *d = toupper(*d);
+ ID(d);
+ case 'w': case 'W':
+ SNARFWORD;
+ if (strEQ(d,"while"))
+ XTERM(WHILE);
+ if (strEQ(d,"write"))
+ *d = toupper(*d);
+ else if (strEQ(d,"wait"))
+ *d = toupper(*d);
+ ID(d);
+ case 'x': case 'X':
+ SNARFWORD;
+ if (strEQ(d,"x"))
+ *d = toupper(*d);
+ ID(d);
+ case 'y': case 'Y':
+ SNARFWORD;
+ if (strEQ(d,"y"))
+ *d = toupper(*d);
+ ID(d);
+ case 'z': case 'Z':
+ SNARFWORD;
+ ID(d);
+ }
+}
+
+char *
+scanpat(s)
+register char *s;
+{
+ register char *d;
+
+ switch (*s++) {
+ case '/':
+ break;
+ default:
+ fatal("Search pattern not found:\n%s",str_get(linestr));
+ }
+
+ d = tokenbuf;
+ for (; *s; s++,d++) {
+ if (*s == '\\') {
+ if (s[1] == '/')
+ *d++ = *s++;
+ else if (s[1] == '\\')
+ *d++ = *s++;
+ else if (s[1] == '[')
+ *d++ = *s++;
+ }
+ else if (*s == '[') {
+ *d++ = *s++;
+ do {
+ if (*s == '\\' && s[1])
+ *d++ = *s++;
+ if (*s == '/' || (*s == '-' && s[1] == ']'))
+ *d++ = '\\';
+ *d++ = *s++;
+ } while (*s && *s != ']');
+ }
+ else if (*s == '/')
+ break;
+ *d = *s;
+ }
+ *d = '\0';
+
+ if (!*s)
+ fatal("Search pattern not terminated:\n%s",str_get(linestr));
+ s++;
+ yylval = string(tokenbuf,0);
+ return s;
+}
+
+yyerror(s)
+char *s;
+{
+ fprintf(stderr,"%s in file %s at line %d\n",
+ s,filename,line);
+}
+
+char *
+scannum(s)
+register char *s;
+{
+ register char *d;
+
+ switch (*s) {
+ case '1': case '2': case '3': case '4': case '5':
+ case '6': case '7': case '8': case '9': case '0' : case '.':
+ d = tokenbuf;
+ while (isdigit(*s)) {
+ *d++ = *s++;
+ }
+ if (*s == '.') {
+ if (isdigit(s[1])) {
+ *d++ = *s++;
+ while (isdigit(*s)) {
+ *d++ = *s++;
+ }
+ }
+ else
+ s++;
+ }
+ if (index("eE",*s) && index("+-0123456789",s[1])) {
+ *d++ = *s++;
+ if (*s == '+' || *s == '-')
+ *d++ = *s++;
+ while (isdigit(*s))
+ *d++ = *s++;
+ }
+ *d = '\0';
+ yylval = string(tokenbuf,0);
+ break;
+ }
+ return s;
+}
+
+string(ptr,len)
+char *ptr;
+{
+ int retval = mop;
+
+ ops[mop++].ival = OSTRING + (1<<8);
+ if (!len)
+ len = strlen(ptr);
+ ops[mop].cval = safemalloc(len+1);
+ strncpy(ops[mop].cval,ptr,len);
+ ops[mop++].cval[len] = '\0';
+ if (mop >= OPSMAX)
+ fatal("Recompile a2p with larger OPSMAX\n");
+ return retval;
+}
+
+oper0(type)
+int type;
+{
+ int retval = mop;
+
+ if (type > 255)
+ fatal("type > 255 (%d)\n",type);
+ ops[mop++].ival = type;
+ if (mop >= OPSMAX)
+ fatal("Recompile a2p with larger OPSMAX\n");
+ return retval;
+}
+
+oper1(type,arg1)
+int type;
+int arg1;
+{
+ int retval = mop;
+
+ if (type > 255)
+ fatal("type > 255 (%d)\n",type);
+ ops[mop++].ival = type + (1<<8);
+ ops[mop++].ival = arg1;
+ if (mop >= OPSMAX)
+ fatal("Recompile a2p with larger OPSMAX\n");
+ return retval;
+}
+
+oper2(type,arg1,arg2)
+int type;
+int arg1;
+int arg2;
+{
+ int retval = mop;
+
+ if (type > 255)
+ fatal("type > 255 (%d)\n",type);
+ ops[mop++].ival = type + (2<<8);
+ ops[mop++].ival = arg1;
+ ops[mop++].ival = arg2;
+ if (mop >= OPSMAX)
+ fatal("Recompile a2p with larger OPSMAX\n");
+ return retval;
+}
+
+oper3(type,arg1,arg2,arg3)
+int type;
+int arg1;
+int arg2;
+int arg3;
+{
+ int retval = mop;
+
+ if (type > 255)
+ fatal("type > 255 (%d)\n",type);
+ ops[mop++].ival = type + (3<<8);
+ ops[mop++].ival = arg1;
+ ops[mop++].ival = arg2;
+ ops[mop++].ival = arg3;
+ if (mop >= OPSMAX)
+ fatal("Recompile a2p with larger OPSMAX\n");
+ return retval;
+}
+
+oper4(type,arg1,arg2,arg3,arg4)
+int type;
+int arg1;
+int arg2;
+int arg3;
+int arg4;
+{
+ int retval = mop;
+
+ if (type > 255)
+ fatal("type > 255 (%d)\n",type);
+ ops[mop++].ival = type + (4<<8);
+ ops[mop++].ival = arg1;
+ ops[mop++].ival = arg2;
+ ops[mop++].ival = arg3;
+ ops[mop++].ival = arg4;
+ if (mop >= OPSMAX)
+ fatal("Recompile a2p with larger OPSMAX\n");
+ return retval;
+}
+
+oper5(type,arg1,arg2,arg3,arg4,arg5)
+int type;
+int arg1;
+int arg2;
+int arg3;
+int arg4;
+int arg5;
+{
+ int retval = mop;
+
+ if (type > 255)
+ fatal("type > 255 (%d)\n",type);
+ ops[mop++].ival = type + (5<<8);
+ ops[mop++].ival = arg1;
+ ops[mop++].ival = arg2;
+ ops[mop++].ival = arg3;
+ ops[mop++].ival = arg4;
+ ops[mop++].ival = arg5;
+ if (mop >= OPSMAX)
+ fatal("Recompile a2p with larger OPSMAX\n");
+ return retval;
+}
+
+int depth = 0;
+
+dump(branch)
+int branch;
+{
+ register int type;
+ register int len;
+ register int i;
+
+ type = ops[branch].ival;
+ len = type >> 8;
+ type &= 255;
+ for (i=depth; i; i--)
+ printf(" ");
+ if (type == OSTRING) {
+ printf("%-5d\"%s\"\n",branch,ops[branch+1].cval);
+ }
+ else {
+ printf("(%-5d%s %d\n",branch,opname[type],len);
+ depth++;
+ for (i=1; i<=len; i++)
+ dump(ops[branch+i].ival);
+ depth--;
+ for (i=depth; i; i--)
+ printf(" ");
+ printf(")\n");
+ }
+}
+
+bl(arg,maybe)
+int arg;
+int maybe;
+{
+ if (!arg)
+ return 0;
+ else if ((ops[arg].ival & 255) != OBLOCK)
+ return oper2(OBLOCK,arg,maybe);
+ else if ((ops[arg].ival >> 8) < 2)
+ return oper2(OBLOCK,ops[arg+1].ival,maybe);
+ else
+ return arg;
+}
+
+fixup(str)
+STR *str;
+{
+ register char *s;
+ register char *t;
+
+ for (s = str->str_ptr; *s; s++) {
+ if (*s == ';' && s[1] == ' ' && s[2] == '\n') {
+ strcpy(s+1,s+2);
+ s++;
+ }
+ else if (*s == '\n') {
+ for (t = s+1; isspace(*t & 127); t++) ;
+ t--;
+ while (isspace(*t & 127) && *t != '\n') t--;
+ if (*t == '\n' && t-s > 1) {
+ if (s[-1] == '{')
+ s--;
+ strcpy(s+1,t);
+ }
+ s++;
+ }
+ }
+}
+
+putlines(str)
+STR *str;
+{
+ register char *d, *s, *t, *e;
+ register int pos, newpos;
+
+ d = tokenbuf;
+ pos = 0;
+ for (s = str->str_ptr; *s; s++) {
+ *d++ = *s;
+ pos++;
+ if (*s == '\n') {
+ *d = '\0';
+ d = tokenbuf;
+ pos = 0;
+ putone();
+ }
+ else if (*s == '\t')
+ pos += 7;
+ if (pos > 78) { /* split a long line? */
+ *d-- = '\0';
+ newpos = 0;
+ for (t = tokenbuf; isspace(*t & 127); t++) {
+ if (*t == '\t')
+ newpos += 8;
+ else
+ newpos += 1;
+ }
+ e = d;
+ while (d > tokenbuf && (*d != ' ' || d[-1] != ';'))
+ d--;
+ if (d < t+10) {
+ d = e;
+ while (d > tokenbuf &&
+ (*d != ' ' || d[-1] != '|' || d[-2] != '|') )
+ d--;
+ }
+ if (d < t+10) {
+ d = e;
+ while (d > tokenbuf &&
+ (*d != ' ' || d[-1] != '&' || d[-2] != '&') )
+ d--;
+ }
+ if (d < t+10) {
+ d = e;
+ while (d > tokenbuf && (*d != ' ' || d[-1] != ','))
+ d--;
+ }
+ if (d < t+10) {
+ d = e;
+ while (d > tokenbuf && *d != ' ')
+ d--;
+ }
+ if (d > t+3) {
+ char save[2048];
+ strcpy(save, d);
+ *d = '\n';
+ d[1] = '\0';
+ putone();
+ putchar('\n');
+ if (d[-1] != ';' && !(newpos % 4)) {
+ *t++ = ' ';
+ *t++ = ' ';
+ newpos += 2;
+ }
+ strcpy(t,save+1);
+ newpos += strlen(t);
+ d = t + strlen(t);
+ pos = newpos;
+ }
+ else
+ d = e + 1;
+ }
+ }
+}
+
+putone()
+{
+ register char *t;
+
+ for (t = tokenbuf; *t; t++) {
+ *t &= 127;
+ if (*t == 127) {
+ *t = ' ';
+ strcpy(t+strlen(t)-1, "\t#???\n");
+ checkers++;
+ }
+ }
+ t = tokenbuf;
+ if (*t == '#') {
+ if (strnEQ(t,"#!/bin/awk",10) || strnEQ(t,"#! /bin/awk",11))
+ return;
+ if (strnEQ(t,"#!/usr/bin/awk",14) || strnEQ(t,"#! /usr/bin/awk",15))
+ return;
+ }
+ fputs(tokenbuf,stdout);
+}
+
+numary(arg)
+int arg;
+{
+ STR *key;
+ int dummy;
+
+ key = walk(0,0,arg,&dummy,P_MIN);
+ str_cat(key,"[]");
+ hstore(symtab,key->str_ptr,str_make("1"));
+ str_free(key);
+ set_array_base = TRUE;
+ return arg;
+}
+
+rememberargs(arg)
+int arg;
+{
+ int type;
+ STR *str;
+
+ if (!arg)
+ return arg;
+ type = ops[arg].ival & 255;
+ if (type == OCOMMA) {
+ rememberargs(ops[arg+1].ival);
+ rememberargs(ops[arg+3].ival);
+ }
+ else if (type == OVAR) {
+ str = str_new(0);
+ hstore(curarghash,ops[ops[arg+1].ival+1].cval,str);
+ }
+ else
+ fatal("panic: unknown argument type %d, line %d\n",type,line);
+ return arg;
+}
+
+aryrefarg(arg)
+int arg;
+{
+ int type = ops[arg].ival & 255;
+ STR *str;
+
+ if (type != OSTRING)
+ fatal("panic: aryrefarg %d, line %d\n",type,line);
+ str = hfetch(curarghash,ops[arg+1].cval);
+ if (str)
+ str_set(str,"*");
+ return arg;
+}
+
+fixfargs(name,arg,prevargs)
+int name;
+int arg;
+int prevargs;
+{
+ int type;
+ STR *str;
+ int numargs;
+
+ if (!arg)
+ return prevargs;
+ type = ops[arg].ival & 255;
+ if (type == OCOMMA) {
+ numargs = fixfargs(name,ops[arg+1].ival,prevargs);
+ numargs = fixfargs(name,ops[arg+3].ival,numargs);
+ }
+ else if (type == OVAR) {
+ str = hfetch(curarghash,ops[ops[arg+1].ival+1].cval);
+ if (strEQ(str_get(str),"*")) {
+ char tmpbuf[128];
+
+ str_set(str,""); /* in case another routine has this */
+ ops[arg].ival &= ~255;
+ ops[arg].ival |= OSTAR;
+ sprintf(tmpbuf,"%s:%d",ops[name+1].cval,prevargs);
+ fprintf(stderr,"Adding %s\n",tmpbuf);
+ str = str_new(0);
+ str_set(str,"*");
+ hstore(curarghash,tmpbuf,str);
+ }
+ numargs = prevargs + 1;
+ }
+ else
+ fatal("panic: unknown argument type %d, arg %d, line %d\n",
+ type,prevargs+1,line);
+ return numargs;
+}
+
+fixrargs(name,arg,prevargs)
+char *name;
+int arg;
+int prevargs;
+{
+ int type;
+ STR *str;
+ int numargs;
+
+ if (!arg)
+ return prevargs;
+ type = ops[arg].ival & 255;
+ if (type == OCOMMA) {
+ numargs = fixrargs(name,ops[arg+1].ival,prevargs);
+ numargs = fixrargs(name,ops[arg+3].ival,numargs);
+ }
+ else {
+ char tmpbuf[128];
+
+ sprintf(tmpbuf,"%s:%d",name,prevargs);
+ str = hfetch(curarghash,tmpbuf);
+ if (str && strEQ(str->str_ptr,"*")) {
+ if (type == OVAR || type == OSTAR) {
+ ops[arg].ival &= ~255;
+ ops[arg].ival |= OSTAR;
+ }
+ else
+ fatal("Can't pass expression by reference as arg %d of %s\n",
+ prevargs+1, name);
+ }
+ numargs = prevargs + 1;
+ }
+ return numargs;
+}
+
diff --git a/gnu/usr.bin/perl/x2p/find2perl b/gnu/usr.bin/perl/x2p/find2perl
new file mode 100755
index 0000000..fd74c3f
--- /dev/null
+++ b/gnu/usr.bin/perl/x2p/find2perl
@@ -0,0 +1,568 @@
+#!/usr/bin/perl
+
+eval 'exec /usr/bin/perl -S $0 ${1+"$@"}'
+ if $running_under_some_shell;
+
+$bin = "/usr/bin";
+
+
+while ($ARGV[0] =~ /^[^-!(]/) {
+ push(@roots, shift);
+}
+@roots = ('.') unless @roots;
+for (@roots) { $_ = &quote($_); }
+$roots = join(',', @roots);
+
+$indent = 1;
+
+while (@ARGV) {
+ $_ = shift;
+ s/^-// || /^[()!]/ || die "Unrecognized switch: $_\n";
+ if ($_ eq '(') {
+ $out .= &tab . "(\n";
+ $indent++;
+ next;
+ }
+ elsif ($_ eq ')') {
+ $indent--;
+ $out .= &tab . ")";
+ }
+ elsif ($_ eq '!') {
+ $out .= &tab . "!";
+ next;
+ }
+ elsif ($_ eq 'name') {
+ $out .= &tab;
+ $pat = &fileglob_to_re(shift);
+ $out .= '/' . $pat . "/";
+ }
+ elsif ($_ eq 'perm') {
+ $onum = shift;
+ die "Malformed -perm argument: $onum\n" unless $onum =~ /^-?[0-7]+$/;
+ if ($onum =~ s/^-//) {
+ $onum = '0' . sprintf("%o", oct($onum) & 017777); # s/b 07777 ?
+ $out .= &tab . "((\$mode & $onum) == $onum)";
+ }
+ else {
+ $onum = '0' . $onum unless $onum =~ /^0/;
+ $out .= &tab . "((\$mode & 0777) == $onum)";
+ }
+ }
+ elsif ($_ eq 'type') {
+ ($filetest = shift) =~ tr/s/S/;
+ $out .= &tab . "-$filetest _";
+ }
+ elsif ($_ eq 'print') {
+ $out .= &tab . 'print("$name\n")';
+ }
+ elsif ($_ eq 'print0') {
+ $out .= &tab . 'print("$name\0")';
+ }
+ elsif ($_ eq 'fstype') {
+ $out .= &tab;
+ $type = shift;
+ if ($type eq 'nfs')
+ { $out .= '$dev < 0'; }
+ else
+ { $out .= '$dev >= 0'; }
+ }
+ elsif ($_ eq 'user') {
+ $uname = shift;
+ $out .= &tab . "\$uid == \$uid{'$uname'}";
+ $inituser++;
+ }
+ elsif ($_ eq 'group') {
+ $gname = shift;
+ $out .= &tab . "\$gid == \$gid{'$gname'}";
+ $initgroup++;
+ }
+ elsif ($_ eq 'nouser') {
+ $out .= &tab . '!defined $uid{$uid}';
+ $inituser++;
+ }
+ elsif ($_ eq 'nogroup') {
+ $out .= &tab . '!defined $gid{$gid}';
+ $initgroup++;
+ }
+ elsif ($_ eq 'links') {
+ $out .= &tab . '$nlink ' . &n(shift);
+ }
+ elsif ($_ eq 'inum') {
+ $out .= &tab . '$ino ' . &n(shift);
+ }
+ elsif ($_ eq 'size') {
+ $out .= &tab . 'int((-s _ + 511) / 512) ' . &n(shift);
+ }
+ elsif ($_ eq 'atime') {
+ $out .= &tab . 'int(-A _) ' . &n(shift);
+ }
+ elsif ($_ eq 'mtime') {
+ $out .= &tab . 'int(-M _) ' . &n(shift);
+ }
+ elsif ($_ eq 'ctime') {
+ $out .= &tab . 'int(-C _) ' . &n(shift);
+ }
+ elsif ($_ eq 'exec') {
+ for (@cmd = (); @ARGV && $ARGV[0] ne ';'; push(@cmd,shift)) { }
+ shift;
+ $_ = "@cmd";
+ if (m#^(/bin/)?rm -f {}$#) {
+ if (!@ARGV) {
+ $out .= &tab . 'unlink($_)';
+ }
+ else {
+ $out .= &tab . '(unlink($_) || 1)';
+ }
+ }
+ elsif (m#^(/bin/)?rm {}$#) {
+ $out .= &tab . '(unlink($_) || warn "$name: $!\n")';
+ }
+ else {
+ for (@cmd) { s/'/\\'/g; }
+ $" = "','";
+ $out .= &tab . "&exec(0, '@cmd')";
+ $" = ' ';
+ $initexec++;
+ }
+ }
+ elsif ($_ eq 'ok') {
+ for (@cmd = (); @ARGV && $ARGV[0] ne ';'; push(@cmd,shift)) { }
+ shift;
+ for (@cmd) { s/'/\\'/g; }
+ $" = "','";
+ $out .= &tab . "&exec(1, '@cmd')";
+ $" = ' ';
+ $initexec++;
+ }
+ elsif ($_ eq 'prune') {
+ $out .= &tab . '($prune = 1)';
+ }
+ elsif ($_ eq 'xdev') {
+ $out .= &tab . '(($prune |= ($dev != $topdev)),1)';
+ }
+ elsif ($_ eq 'newer') {
+ $out .= &tab;
+ $file = shift;
+ $newername = 'AGE_OF' . $file;
+ $newername =~ s/[^\w]/_/g;
+ $newername = '$' . $newername;
+ $out .= "-M _ < $newername";
+ $initnewer .= "$newername = -M " . &quote($file) . ";\n";
+ }
+ elsif ($_ eq 'eval') {
+ $prog = &quote(shift);
+ $out .= &tab . "eval $prog";
+ }
+ elsif ($_ eq 'depth') {
+ $depth++;
+ next;
+ }
+ elsif ($_ eq 'ls') {
+ $out .= &tab . "&ls";
+ $initls++;
+ }
+ elsif ($_ eq 'tar') {
+ $out .= &tab;
+ die "-tar must have a filename argument\n" unless @ARGV;
+ $file = shift;
+ $fh = 'FH' . $file;
+ $fh =~ s/[^\w]/_/g;
+ $out .= "&tar($fh)";
+ $file = '>' . $file;
+ $initfile .= "open($fh, " . &quote($file) .
+ qq{) || die "Can't open $fh: \$!\\n";\n};
+ $inittar++;
+ $flushall = "\n&tflushall;\n";
+ }
+ elsif (/^n?cpio$/) {
+ $depth++;
+ $out .= &tab;
+ die "-$_ must have a filename argument\n" unless @ARGV;
+ $file = shift;
+ $fh = 'FH' . $file;
+ $fh =~ s/[^\w]/_/g;
+ $out .= "&cpio('" . substr($_,0,1) . "', $fh)";
+ $file = '>' . $file;
+ $initfile .= "open($fh, " . &quote($file) .
+ qq{) || die "Can't open $fh: \$!\\n";\n};
+ $initcpio++;
+ $flushall = "\n&flushall;\n";
+ }
+ else {
+ die "Unrecognized switch: -$_\n";
+ }
+ if (@ARGV) {
+ if ($ARGV[0] eq '-o') {
+ { local($statdone) = 1; $out .= "\n" . &tab . "||\n"; }
+ $statdone = 0 if $indent == 1 && $delayedstat;
+ $saw_or++;
+ shift;
+ }
+ else {
+ $out .= " &&" unless $ARGV[0] eq ')';
+ $out .= "\n";
+ shift if $ARGV[0] eq '-a';
+ }
+ }
+}
+
+print <<"END";
+#!$bin/perl
+
+eval 'exec $bin/perl -S \$0 \${1+"\$@"}'
+ if \$running_under_some_shell;
+
+END
+
+if ($initls) {
+ print <<'END';
+@rwx = ('---','--x','-w-','-wx','r--','r-x','rw-','rwx');
+@moname = (Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec);
+
+END
+}
+
+if ($inituser || $initls) {
+ print 'while (($name, $pw, $uid) = getpwent) {', "\n";
+ print ' $uid{$name} = $uid{$uid} = $uid;', "\n" if $inituser;
+ print ' $user{$uid} = $name unless $user{$uid};', "\n" if $initls;
+ print "}\n\n";
+}
+
+if ($initgroup || $initls) {
+ print 'while (($name, $pw, $gid) = getgrent) {', "\n";
+ print ' $gid{$name} = $gid{$gid} = $gid;', "\n" if $initgroup;
+ print ' $group{$gid} = $name unless $group{$gid};', "\n" if $initls;
+ print "}\n\n";
+}
+
+print $initnewer, "\n" if $initnewer;
+
+print $initfile, "\n" if $initfile;
+
+$find = $depth ? "finddepth" : "find";
+print <<"END";
+require "$find.pl";
+
+# Traverse desired filesystems
+
+&$find($roots);
+$flushall
+exit;
+
+sub wanted {
+$out;
+}
+
+END
+
+if ($initexec) {
+ print <<'END';
+sub exec {
+ local($ok, @cmd) = @_;
+ foreach $word (@cmd) {
+ $word =~ s#{}#$name#g;
+ }
+ if ($ok) {
+ local($old) = select(STDOUT);
+ $| = 1;
+ print "@cmd";
+ select($old);
+ return 0 unless <STDIN> =~ /^y/;
+ }
+ chdir $cwd; # sigh
+ system @cmd;
+ chdir $dir;
+ return !$?;
+}
+
+END
+}
+
+if ($initls) {
+ print <<'END';
+sub ls {
+ ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$sizemm,
+ $atime,$mtime,$ctime,$blksize,$blocks) = lstat(_);
+
+ $pname = $name;
+
+ if (defined $blocks) {
+ $blocks = int(($blocks + 1) / 2);
+ }
+ else {
+ $blocks = int(($size + 1023) / 1024);
+ }
+
+ if (-f _) { $perms = '-'; }
+ elsif (-d _) { $perms = 'd'; }
+ elsif (-c _) { $perms = 'c'; $sizemm = &sizemm; }
+ elsif (-b _) { $perms = 'b'; $sizemm = &sizemm; }
+ elsif (-p _) { $perms = 'p'; }
+ elsif (-S _) { $perms = 's'; }
+ else { $perms = 'l'; $pname .= ' -> ' . readlink($_); }
+
+ $tmpmode = $mode;
+ $tmp = $rwx[$tmpmode & 7];
+ $tmpmode >>= 3;
+ $tmp = $rwx[$tmpmode & 7] . $tmp;
+ $tmpmode >>= 3;
+ $tmp = $rwx[$tmpmode & 7] . $tmp;
+ substr($tmp,2,1) =~ tr/-x/Ss/ if -u _;
+ substr($tmp,5,1) =~ tr/-x/Ss/ if -g _;
+ substr($tmp,8,1) =~ tr/-x/Tt/ if -k _;
+ $perms .= $tmp;
+
+ $user = $user{$uid} || $uid;
+ $group = $group{$gid} || $gid;
+
+ ($sec,$min,$hour,$mday,$mon,$year) = localtime($mtime);
+ $moname = $moname[$mon];
+ if (-M _ > 365.25 / 2) {
+ $timeyear = '19' . $year;
+ }
+ else {
+ $timeyear = sprintf("%02d:%02d", $hour, $min);
+ }
+
+ printf "%5lu %4ld %-10s %2d %-8s %-8s %8s %s %2d %5s %s\n",
+ $ino,
+ $blocks,
+ $perms,
+ $nlink,
+ $user,
+ $group,
+ $sizemm,
+ $moname,
+ $mday,
+ $timeyear,
+ $pname;
+ 1;
+}
+
+sub sizemm {
+ sprintf("%3d, %3d", ($rdev >> 8) & 255, $rdev & 255);
+}
+
+END
+}
+
+if ($initcpio) {
+print <<'END';
+sub cpio {
+ local($nc,$fh) = @_;
+ local($text);
+
+ if ($name eq 'TRAILER!!!') {
+ $text = '';
+ $size = 0;
+ }
+ else {
+ ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,
+ $atime,$mtime,$ctime,$blksize,$blocks) = lstat(_);
+ if (-f _) {
+ open(IN, "./$_\0") || do {
+ warn "Couldn't open $name: $!\n";
+ return;
+ };
+ }
+ else {
+ $text = readlink($_);
+ $size = 0 unless defined $text;
+ }
+ }
+
+ ($nm = $name) =~ s#^\./##;
+ $nc{$fh} = $nc;
+ if ($nc eq 'n') {
+ $cpout{$fh} .=
+ sprintf("%06o%06o%06o%06o%06o%06o%06o%06o%011lo%06o%011lo%s\0",
+ 070707,
+ $dev & 0777777,
+ $ino & 0777777,
+ $mode & 0777777,
+ $uid & 0777777,
+ $gid & 0777777,
+ $nlink & 0777777,
+ $rdev & 0177777,
+ $mtime,
+ length($nm)+1,
+ $size,
+ $nm);
+ }
+ else {
+ $cpout{$fh} .= "\0" if length($cpout{$fh}) & 1;
+ $cpout{$fh} .= pack("SSSSSSSSLSLa*",
+ 070707, $dev, $ino, $mode, $uid, $gid, $nlink, $rdev, $mtime,
+ length($nm)+1, $size, $nm . (length($nm) & 1 ? "\0" : "\0\0"));
+ }
+ if ($text ne '') {
+ $cpout{$fh} .= $text;
+ }
+ elsif ($size) {
+ &flush($fh) while ($l = length($cpout{$fh})) >= 5120;
+ while (sysread(IN, $cpout{$fh}, 5120 - $l, $l)) {
+ &flush($fh);
+ $l = length($cpout{$fh});
+ }
+ }
+ close IN;
+}
+
+sub flush {
+ local($fh) = @_;
+
+ while (length($cpout{$fh}) >= 5120) {
+ syswrite($fh,$cpout{$fh},5120);
+ ++$blocks{$fh};
+ substr($cpout{$fh}, 0, 5120) = '';
+ }
+}
+
+sub flushall {
+ $name = 'TRAILER!!!';
+ foreach $fh (keys %cpout) {
+ &cpio($nc{$fh},$fh);
+ $cpout{$fh} .= "0" x (5120 - length($cpout{$fh}));
+ &flush($fh);
+ print $blocks{$fh} * 10, " blocks\n";
+ }
+}
+
+END
+}
+
+if ($inittar) {
+print <<'END';
+sub tar {
+ local($fh) = @_;
+ local($linkname,$header,$l,$slop);
+ local($linkflag) = "\0";
+
+ ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,
+ $atime,$mtime,$ctime,$blksize,$blocks) = lstat(_);
+ $nm = $name;
+ if ($nlink > 1) {
+ if ($linkname = $linkseen{$fh,$dev,$ino}) {
+ $linkflag = 1;
+ }
+ else {
+ $linkseen{$fh,$dev,$ino} = $nm;
+ }
+ }
+ if (-f _) {
+ open(IN, "./$_\0") || do {
+ warn "Couldn't open $name: $!\n";
+ return;
+ };
+ $size = 0 if $linkflag ne "\0";
+ }
+ else {
+ $linkname = readlink($_);
+ $linkflag = 2 if defined $linkname;
+ $nm .= '/' if -d _;
+ $size = 0;
+ }
+
+ $header = pack("a100a8a8a8a12a12a8a1a100",
+ $nm,
+ sprintf("%6o ", $mode & 0777),
+ sprintf("%6o ", $uid & 0777777),
+ sprintf("%6o ", $gid & 0777777),
+ sprintf("%11o ", $size),
+ sprintf("%11o ", $mtime),
+ " ",
+ $linkflag,
+ $linkname);
+ $l = length($header) % 512;
+ substr($header, 148, 6) = sprintf("%6o", unpack("%16C*", $header));
+ substr($header, 154, 1) = "\0"; # blech
+ $tarout{$fh} .= $header;
+ $tarout{$fh} .= "\0" x (512 - $l) if $l;
+ if ($size) {
+ &tflush($fh) while ($l = length($tarout{$fh})) >= 10240;
+ while (sysread(IN, $tarout{$fh}, 10240 - $l, $l)) {
+ $slop = length($tarout{$fh}) % 512;
+ $tarout{$fh} .= "\0" x (512 - $slop) if $slop;
+ &tflush($fh);
+ $l = length($tarout{$fh});
+ }
+ }
+ close IN;
+}
+
+sub tflush {
+ local($fh) = @_;
+
+ while (length($tarout{$fh}) >= 10240) {
+ syswrite($fh,$tarout{$fh},10240);
+ ++$blocks{$fh};
+ substr($tarout{$fh}, 0, 10240) = '';
+ }
+}
+
+sub tflushall {
+ local($len);
+
+ foreach $fh (keys %tarout) {
+ $len = 10240 - length($tarout{$fh});
+ $len += 10240 if $len < 1024;
+ $tarout{$fh} .= "\0" x $len;
+ &tflush($fh);
+ }
+}
+
+END
+}
+
+exit;
+
+############################################################################
+
+sub tab {
+ local($tabstring);
+
+ $tabstring = "\t" x ($indent / 2) . ' ' x ($indent % 2 * 4);
+ if (!$statdone) {
+ if ($_ =~ /^(name|print|prune|exec|ok|\(|\))/) {
+ $delayedstat++;
+ }
+ else {
+ if ($saw_or) {
+ $tabstring .= <<'ENDOFSTAT' . $tabstring;
+($nlink || (($dev,$ino,$mode,$nlink,$uid,$gid) = lstat($_))) &&
+ENDOFSTAT
+ }
+ else {
+ $tabstring .= <<'ENDOFSTAT' . $tabstring;
+(($dev,$ino,$mode,$nlink,$uid,$gid) = lstat($_)) &&
+ENDOFSTAT
+ }
+ $statdone = 1;
+ }
+ }
+ $tabstring =~ s/^\s+/ / if $out =~ /!$/;
+ $tabstring;
+}
+
+sub fileglob_to_re {
+ local($tmp) = @_;
+
+ $tmp =~ s/([.^\$()])/\\$1/g;
+ $tmp =~ s/([?*])/.$1/g;
+ "^$tmp$";
+}
+
+sub n {
+ local($n) = @_;
+
+ $n =~ s/^-/< / || $n =~ s/^\+/> / || $n =~ s/^/== /;
+ $n =~ s/ 0*(\d)/ $1/;
+ $n;
+}
+
+sub quote {
+ local($string) = @_;
+ $string =~ s/'/\\'/;
+ "'$string'";
+}
diff --git a/gnu/usr.bin/perl/x2p/h2ph b/gnu/usr.bin/perl/x2p/h2ph
new file mode 100755
index 0000000..143791f
--- /dev/null
+++ b/gnu/usr.bin/perl/x2p/h2ph
@@ -0,0 +1,262 @@
+#!/usr/bin/perl
+'di';
+'ig00';
+
+$destdir = $ENV{'DESTDIR'};
+$perlincl = $destdir . '/usr/share/perl';
+
+chdir $destdir . '/usr/include' || die "Can't cd $destdir/usr/include";
+
+@isatype = split(' ',<<END);
+ char uchar u_char
+ short ushort u_short
+ int uint u_int
+ long ulong u_long
+ FILE
+END
+
+@isatype{@isatype} = (1) x @isatype;
+
+@ARGV = ('-') unless @ARGV;
+
+foreach $file (@ARGV) {
+ if ($file eq '-') {
+ open(IN, "-");
+ open(OUT, ">-");
+ }
+ else {
+ ($outfile = $file) =~ s/\.h$/.ph/ || next;
+ print "$file -> $outfile\n";
+ if ($file =~ m|^(.*)/|) {
+ $dir = $1;
+ if (!-d "$perlincl/$dir") {
+ mkdir("$perlincl/$dir",0777);
+ }
+ }
+ open(IN,"$file") || ((warn "Can't open $file: $!\n"),next);
+ open(OUT,">$perlincl/$outfile") || die "Can't create $outfile: $!\n";
+ }
+ while (<IN>) {
+ chop;
+ while (/\\$/) {
+ chop;
+ $_ .= <IN>;
+ chop;
+ }
+ if (s:/\*:\200:g) {
+ s:\*/:\201:g;
+ s/\200[^\201]*\201//g; # delete single line comments
+ if (s/\200.*//) { # begin multi-line comment?
+ $_ .= '/*';
+ $_ .= <IN>;
+ redo;
+ }
+ }
+ if (s/^#\s*//) {
+ if (s/^define\s+(\w+)//) {
+ $name = $1;
+ $new = '';
+ s/\s+$//;
+ if (s/^\(([\w,\s]*)\)//) {
+ $args = $1;
+ if ($args ne '') {
+ foreach $arg (split(/,\s*/,$args)) {
+ $arg =~ s/^\s*([^\s].*[^\s])\s*$/$1/;
+ $curargs{$arg} = 1;
+ }
+ $args =~ s/\b(\w)/\$$1/g;
+ $args = "local($args) = \@_;\n$t ";
+ }
+ s/^\s+//;
+ do expr(0);
+ $new =~ s/(["\\])/\\$1/g;
+ if ($t ne '') {
+ $new =~ s/(['\\])/\\$1/g;
+ print OUT $t,
+ "eval 'sub $name {\n$t ${args}eval \"$new\";\n$t}';\n";
+ }
+ else {
+ print OUT "sub $name {\n ${args}eval \"$new\";\n}\n";
+ }
+ %curargs = ();
+ }
+ else {
+ s/^\s+//;
+ do expr(0);
+ $new = 1 if $new eq '';
+ if ($t ne '') {
+ $new =~ s/(['\\])/\\$1/g;
+ print OUT $t,"eval 'sub $name {",$new,";}';\n";
+ }
+ else {
+ print OUT $t,"sub $name {",$new,";}\n";
+ }
+ }
+ }
+ elsif (/^include\s+<(.*)>/) {
+ ($incl = $1) =~ s/\.h$/.ph/;
+ print OUT $t,"require '$incl';\n";
+ }
+ elsif (/^ifdef\s+(\w+)/) {
+ print OUT $t,"if (defined &$1) {\n";
+ $tab += 4;
+ $t = "\t" x ($tab / 8) . ' ' x ($tab % 8);
+ }
+ elsif (/^ifndef\s+(\w+)/) {
+ print OUT $t,"if (!defined &$1) {\n";
+ $tab += 4;
+ $t = "\t" x ($tab / 8) . ' ' x ($tab % 8);
+ }
+ elsif (s/^if\s+//) {
+ $new = '';
+ do expr(1);
+ print OUT $t,"if ( $new) {\n";
+ $tab += 4;
+ $t = "\t" x ($tab / 8) . ' ' x ($tab % 8);
+ }
+ elsif (s/^elif\s+//) {
+ $new = '';
+ do expr(1);
+ $tab -= 4;
+ $t = "\t" x ($tab / 8) . ' ' x ($tab % 8);
+ print OUT $t,"}\n${t}elsif ($new) {\n";
+ $tab += 4;
+ $t = "\t" x ($tab / 8) . ' ' x ($tab % 8);
+ }
+ elsif (/^else/) {
+ $tab -= 4;
+ $t = "\t" x ($tab / 8) . ' ' x ($tab % 8);
+ print OUT $t,"}\n${t}else {\n";
+ $tab += 4;
+ $t = "\t" x ($tab / 8) . ' ' x ($tab % 8);
+ }
+ elsif (/^endif/) {
+ $tab -= 4;
+ $t = "\t" x ($tab / 8) . ' ' x ($tab % 8);
+ print OUT $t,"}\n";
+ }
+ }
+ }
+ print OUT "1;\n";
+}
+
+sub expr {
+$hd=0;
+ while ($_ ne '') {
+ s/^(\s+)// && do {$new .= ' '; next;};
+ s/^(0x[0-9a-fA-F]+)// && do {$new .= $1; next;};
+ s/^(\d+)// && do {$new .= $1; next;};
+ s/^("(\\"|[^"])*")// && do {$new .= $1; next;};
+ s/^'((\\"|[^"])*)'// && do {
+ if ($curargs{$1}) {
+ $new .= "ord('\$$1')";
+ }
+ else {
+ $new .= "ord('$1')";
+ }
+ next;
+ };
+ s/^sizeof\s*\(([^)]+)\)/{$1}/ && do {
+ $new .= '$sizeof';
+ next;
+ };
+ s/^([_a-zA-Z]\w*)// && do {
+ $id = $1;
+ if ($id eq 'struct') {
+ s/^\s+(\w+)//;
+ $id .= ' ' . $1;
+ $isatype{$id} = 1;
+ }
+ elsif ($id eq 'unsigned') {
+ s/^\s+(\w+)//;
+ $id .= ' ' . $1;
+ $isatype{$id} = 1;
+ }
+ if ($curargs{$id}) {
+ $new .= '$' . $id;
+ }
+ elsif ($id eq 'defined') {
+ $new .= 'defined';
+ $hd=1;
+ }
+ elsif (/^\(/) {
+ s/^\((\w),/("$1",/ if $id =~ /^_IO[WR]*$/i; # cheat
+ $new .= " &$id";
+ }
+ elsif ($isatype{$id}) {
+ if ($new =~ /{\s*$/) {
+ $new .= "'$id'";
+ $hd=0;
+ }
+ elsif ($new =~ /\(\s*$/ && /^[\s*]*\)/) {
+ $new =~ s/\(\s*$//;
+ s/^[\s*]*\)//;
+ }
+ else {
+ $new .= $id;
+ }
+ }
+ else {
+ if ($hd == 0) {
+ $new .= 'defined &' . $id . ' && &' . $id;
+ } else {
+ $new .= ' &' . $id;
+ }
+ $hd=0;
+ }
+ next;
+ };
+ s/^(.)// && do {$new .= $1; next;};
+ }
+}
+##############################################################################
+
+ # These next few lines are legal in both Perl and nroff.
+
+.00; # finish .ig
+
+'di \" finish diversion--previous line must be blank
+.nr nl 0-1 \" fake up transition to first page again
+.nr % 0 \" start at page 1
+'; __END__ ############# From here on it's a standard manual page ############
+.TH H2PH 1 "August 8, 1990"
+.AT 3
+.SH NAME
+h2ph \- convert .h C header files to .ph Perl header files
+.SH SYNOPSIS
+.B h2ph [headerfiles]
+.SH DESCRIPTION
+.I h2ph
+converts any C header files specified to the corresponding Perl header file
+format.
+It is most easily run while in /usr/include:
+.nf
+
+ cd /usr/include; h2ph * sys/*
+
+.fi
+If run with no arguments, filters standard input to standard output.
+.SH ENVIRONMENT
+No environment variables are used.
+.SH FILES
+/usr/include/*.h
+.br
+/usr/include/sys/*.h
+.br
+etc.
+.SH AUTHOR
+Larry Wall
+.SH "SEE ALSO"
+perl(1)
+.SH DIAGNOSTICS
+The usual warnings if it can't read or write the files involved.
+.SH BUGS
+Doesn't construct the %sizeof array for you.
+.PP
+It doesn't handle all C constructs, but it does attempt to isolate
+definitions inside evals so that you can get at the definitions
+that it can translate.
+.PP
+It's only intended as a rough tool.
+You may need to dicker with the files produced.
+.ex
diff --git a/gnu/usr.bin/perl/x2p/h2ph.1 b/gnu/usr.bin/perl/x2p/h2ph.1
new file mode 100755
index 0000000..3ac76f4
--- /dev/null
+++ b/gnu/usr.bin/perl/x2p/h2ph.1
@@ -0,0 +1,41 @@
+.TH H2PH 1 "August 8, 1990"
+.AT 3
+.SH NAME
+h2ph \- convert .h C header files to .ph Perl header files
+.SH SYNOPSIS
+.B h2ph [headerfiles]
+.SH DESCRIPTION
+.I h2ph
+converts any C header files specified to the corresponding Perl header file
+format.
+It is most easily run while in /usr/include:
+.nf
+
+ cd /usr/include; h2ph * sys/*
+
+.fi
+If run with no arguments, filters standard input to standard output.
+.SH ENVIRONMENT
+No environment variables are used.
+.SH FILES
+/usr/include/*.h
+.br
+/usr/include/sys/*.h
+.br
+etc.
+.SH AUTHOR
+Larry Wall
+.SH "SEE ALSO"
+perl(1)
+.SH DIAGNOSTICS
+The usual warnings if it can't read or write the files involved.
+.SH BUGS
+Doesn't construct the %sizeof array for you.
+.PP
+It doesn't handle all C constructs, but it does attempt to isolate
+definitions inside evals so that you can get at the definitions
+that it can translate.
+.PP
+It's only intended as a rough tool.
+You may need to dicker with the files produced.
+.ex
diff --git a/gnu/usr.bin/perl/x2p/handy.h b/gnu/usr.bin/perl/x2p/handy.h
new file mode 100644
index 0000000..1db94d4
--- /dev/null
+++ b/gnu/usr.bin/perl/x2p/handy.h
@@ -0,0 +1,49 @@
+/* $RCSfile: handy.h,v $$Revision: 1.1.1.1 $$Date: 1994/09/10 06:27:54 $
+ *
+ * Copyright (c) 1991, Larry Wall
+ *
+ * You may distribute under the terms of either the GNU General Public
+ * License or the Artistic License, as specified in the README file.
+ *
+ * $Log: handy.h,v $
+ * Revision 1.1.1.1 1994/09/10 06:27:54 gclarkii
+ * Initial import of Perl 4.046 bmaked
+ *
+ * Revision 1.1.1.1 1993/08/23 21:30:10 nate
+ * PERL!
+ *
+ * Revision 4.0.1.2 91/06/07 12:15:43 lwall
+ * patch4: new copyright notice
+ *
+ * Revision 4.0.1.1 91/04/12 09:29:08 lwall
+ * patch1: random cleanup in cpp namespace
+ *
+ * Revision 4.0 91/03/20 01:57:45 lwall
+ * 4.0 baseline.
+ *
+ */
+
+#define Null(type) ((type)0)
+#define Nullch Null(char*)
+#define Nullfp Null(FILE*)
+
+#define bool char
+#ifdef TRUE
+#undef TRUE
+#endif
+#ifdef FALSE
+#undef FALSE
+#endif
+#define TRUE (1)
+#define FALSE (0)
+
+#define Ctl(ch) (ch & 037)
+
+#define strNE(s1,s2) (strcmp(s1,s2))
+#define strEQ(s1,s2) (!strcmp(s1,s2))
+#define strLT(s1,s2) (strcmp(s1,s2) < 0)
+#define strLE(s1,s2) (strcmp(s1,s2) <= 0)
+#define strGT(s1,s2) (strcmp(s1,s2) > 0)
+#define strGE(s1,s2) (strcmp(s1,s2) >= 0)
+#define strnNE(s1,s2,l) (strncmp(s1,s2,l))
+#define strnEQ(s1,s2,l) (!strncmp(s1,s2,l))
diff --git a/gnu/usr.bin/perl/x2p/hash.c b/gnu/usr.bin/perl/x2p/hash.c
new file mode 100644
index 0000000..d1ae8ac
--- /dev/null
+++ b/gnu/usr.bin/perl/x2p/hash.c
@@ -0,0 +1,253 @@
+/* $RCSfile: hash.c,v $$Revision: 1.1.1.1 $$Date: 1994/09/10 06:27:54 $
+ *
+ * Copyright (c) 1991, Larry Wall
+ *
+ * You may distribute under the terms of either the GNU General Public
+ * License or the Artistic License, as specified in the README file.
+ *
+ * $Log: hash.c,v $
+ * Revision 1.1.1.1 1994/09/10 06:27:54 gclarkii
+ * Initial import of Perl 4.046 bmaked
+ *
+ * Revision 1.1.1.1 1993/08/23 21:30:10 nate
+ * PERL!
+ *
+ * Revision 4.0.1.1 91/06/07 12:15:55 lwall
+ * patch4: new copyright notice
+ *
+ * Revision 4.0 91/03/20 01:57:49 lwall
+ * 4.0 baseline.
+ *
+ */
+
+#include <stdio.h>
+#include "EXTERN.h"
+#include "handy.h"
+#include "util.h"
+#include "a2p.h"
+
+STR *
+hfetch(tb,key)
+register HASH *tb;
+char *key;
+{
+ register char *s;
+ register int i;
+ register int hash;
+ register HENT *entry;
+
+ if (!tb)
+ return Nullstr;
+ for (s=key, i=0, hash = 0;
+ /* while */ *s;
+ s++, i++, hash *= 5) {
+ hash += *s * coeff[i];
+ }
+ entry = tb->tbl_array[hash & tb->tbl_max];
+ for (; entry; entry = entry->hent_next) {
+ if (entry->hent_hash != hash) /* strings can't be equal */
+ continue;
+ if (strNE(entry->hent_key,key)) /* is this it? */
+ continue;
+ return entry->hent_val;
+ }
+ return Nullstr;
+}
+
+bool
+hstore(tb,key,val)
+register HASH *tb;
+char *key;
+STR *val;
+{
+ register char *s;
+ register int i;
+ register int hash;
+ register HENT *entry;
+ register HENT **oentry;
+
+ if (!tb)
+ return FALSE;
+ for (s=key, i=0, hash = 0;
+ /* while */ *s;
+ s++, i++, hash *= 5) {
+ hash += *s * coeff[i];
+ }
+
+ oentry = &(tb->tbl_array[hash & tb->tbl_max]);
+ i = 1;
+
+ for (entry = *oentry; entry; i=0, entry = entry->hent_next) {
+ if (entry->hent_hash != hash) /* strings can't be equal */
+ continue;
+ if (strNE(entry->hent_key,key)) /* is this it? */
+ continue;
+ /*NOSTRICT*/
+ safefree((char*)entry->hent_val);
+ entry->hent_val = val;
+ return TRUE;
+ }
+ /*NOSTRICT*/
+ entry = (HENT*) safemalloc(sizeof(HENT));
+
+ entry->hent_key = savestr(key);
+ entry->hent_val = val;
+ entry->hent_hash = hash;
+ entry->hent_next = *oentry;
+ *oentry = entry;
+
+ if (i) { /* initial entry? */
+ tb->tbl_fill++;
+ if ((tb->tbl_fill * 100 / (tb->tbl_max + 1)) > FILLPCT)
+ hsplit(tb);
+ }
+
+ return FALSE;
+}
+
+#ifdef NOTUSED
+bool
+hdelete(tb,key)
+register HASH *tb;
+char *key;
+{
+ register char *s;
+ register int i;
+ register int hash;
+ register HENT *entry;
+ register HENT **oentry;
+
+ if (!tb)
+ return FALSE;
+ for (s=key, i=0, hash = 0;
+ /* while */ *s;
+ s++, i++, hash *= 5) {
+ hash += *s * coeff[i];
+ }
+
+ oentry = &(tb->tbl_array[hash & tb->tbl_max]);
+ entry = *oentry;
+ i = 1;
+ for (; entry; i=0, oentry = &entry->hent_next, entry = entry->hent_next) {
+ if (entry->hent_hash != hash) /* strings can't be equal */
+ continue;
+ if (strNE(entry->hent_key,key)) /* is this it? */
+ continue;
+ safefree((char*)entry->hent_val);
+ safefree(entry->hent_key);
+ *oentry = entry->hent_next;
+ safefree((char*)entry);
+ if (i)
+ tb->tbl_fill--;
+ return TRUE;
+ }
+ return FALSE;
+}
+#endif
+
+hsplit(tb)
+HASH *tb;
+{
+ int oldsize = tb->tbl_max + 1;
+ register int newsize = oldsize * 2;
+ register int i;
+ register HENT **a;
+ register HENT **b;
+ register HENT *entry;
+ register HENT **oentry;
+
+ a = (HENT**) saferealloc((char*)tb->tbl_array, newsize * sizeof(HENT*));
+ bzero((char*)&a[oldsize], oldsize * sizeof(HENT*)); /* zero second half */
+ tb->tbl_max = --newsize;
+ tb->tbl_array = a;
+
+ for (i=0; i<oldsize; i++,a++) {
+ if (!*a) /* non-existent */
+ continue;
+ b = a+oldsize;
+ for (oentry = a, entry = *a; entry; entry = *oentry) {
+ if ((entry->hent_hash & newsize) != i) {
+ *oentry = entry->hent_next;
+ entry->hent_next = *b;
+ if (!*b)
+ tb->tbl_fill++;
+ *b = entry;
+ continue;
+ }
+ else
+ oentry = &entry->hent_next;
+ }
+ if (!*a) /* everything moved */
+ tb->tbl_fill--;
+ }
+}
+
+HASH *
+hnew()
+{
+ register HASH *tb = (HASH*)safemalloc(sizeof(HASH));
+
+ tb->tbl_array = (HENT**) safemalloc(8 * sizeof(HENT*));
+ tb->tbl_fill = 0;
+ tb->tbl_max = 7;
+ hiterinit(tb); /* so each() will start off right */
+ bzero((char*)tb->tbl_array, 8 * sizeof(HENT*));
+ return tb;
+}
+
+#ifdef NOTUSED
+hshow(tb)
+register HASH *tb;
+{
+ fprintf(stderr,"%5d %4d (%2d%%)\n",
+ tb->tbl_max+1,
+ tb->tbl_fill,
+ tb->tbl_fill * 100 / (tb->tbl_max+1));
+}
+#endif
+
+hiterinit(tb)
+register HASH *tb;
+{
+ tb->tbl_riter = -1;
+ tb->tbl_eiter = Null(HENT*);
+ return tb->tbl_fill;
+}
+
+HENT *
+hiternext(tb)
+register HASH *tb;
+{
+ register HENT *entry;
+
+ entry = tb->tbl_eiter;
+ do {
+ if (entry)
+ entry = entry->hent_next;
+ if (!entry) {
+ tb->tbl_riter++;
+ if (tb->tbl_riter > tb->tbl_max) {
+ tb->tbl_riter = -1;
+ break;
+ }
+ entry = tb->tbl_array[tb->tbl_riter];
+ }
+ } while (!entry);
+
+ tb->tbl_eiter = entry;
+ return entry;
+}
+
+char *
+hiterkey(entry)
+register HENT *entry;
+{
+ return entry->hent_key;
+}
+
+STR *
+hiterval(entry)
+register HENT *entry;
+{
+ return entry->hent_val;
+}
diff --git a/gnu/usr.bin/perl/x2p/hash.h b/gnu/usr.bin/perl/x2p/hash.h
new file mode 100644
index 0000000..452321c
--- /dev/null
+++ b/gnu/usr.bin/perl/x2p/hash.h
@@ -0,0 +1,63 @@
+/* $RCSfile: hash.h,v $$Revision: 1.1.1.1 $$Date: 1994/09/10 06:27:54 $
+ *
+ * Copyright (c) 1991, Larry Wall
+ *
+ * You may distribute under the terms of either the GNU General Public
+ * License or the Artistic License, as specified in the README file.
+ *
+ * $Log: hash.h,v $
+ * Revision 1.1.1.1 1994/09/10 06:27:54 gclarkii
+ * Initial import of Perl 4.046 bmaked
+ *
+ * Revision 1.1.1.1 1993/08/23 21:30:10 nate
+ * PERL!
+ *
+ * Revision 4.0.1.1 91/06/07 12:16:04 lwall
+ * patch4: new copyright notice
+ *
+ * Revision 4.0 91/03/20 01:57:53 lwall
+ * 4.0 baseline.
+ *
+ */
+
+#define FILLPCT 60 /* don't make greater than 99 */
+
+#ifdef DOINIT
+char coeff[] = {
+ 61,59,53,47,43,41,37,31,29,23,17,13,11,7,3,1,
+ 61,59,53,47,43,41,37,31,29,23,17,13,11,7,3,1,
+ 61,59,53,47,43,41,37,31,29,23,17,13,11,7,3,1,
+ 61,59,53,47,43,41,37,31,29,23,17,13,11,7,3,1,
+ 61,59,53,47,43,41,37,31,29,23,17,13,11,7,3,1,
+ 61,59,53,47,43,41,37,31,29,23,17,13,11,7,3,1,
+ 61,59,53,47,43,41,37,31,29,23,17,13,11,7,3,1,
+ 61,59,53,47,43,41,37,31,29,23,17,13,11,7,3,1};
+#else
+extern char coeff[];
+#endif
+
+typedef struct hentry HENT;
+
+struct hentry {
+ HENT *hent_next;
+ char *hent_key;
+ STR *hent_val;
+ int hent_hash;
+};
+
+struct htbl {
+ HENT **tbl_array;
+ int tbl_max;
+ int tbl_fill;
+ int tbl_riter; /* current root of iterator */
+ HENT *tbl_eiter; /* current entry of iterator */
+};
+
+STR *hfetch();
+bool hstore();
+bool hdelete();
+HASH *hnew();
+int hiterinit();
+HENT *hiternext();
+char *hiterkey();
+STR *hiterval();
diff --git a/gnu/usr.bin/perl/x2p/malloc.c b/gnu/usr.bin/perl/x2p/malloc.c
new file mode 100644
index 0000000..e7fff7f
--- /dev/null
+++ b/gnu/usr.bin/perl/x2p/malloc.c
@@ -0,0 +1,516 @@
+/* $RCSfile: malloc.c,v $$Revision: 1.1.1.1 $$Date: 1994/09/10 06:27:54 $
+ *
+ * $Log: malloc.c,v $
+ * Revision 1.1.1.1 1994/09/10 06:27:54 gclarkii
+ * Initial import of Perl 4.046 bmaked
+ *
+ * Revision 1.2 1993/08/24 17:57:39 nate
+ * Fix for ALIGN macros in PERL that conflict with 4.4 macros
+ *
+ * Revision 1.1.1.1 1993/08/23 21:30:11 nate
+ * PERL!
+ *
+ * Revision 4.0.1.4 92/06/08 14:28:38 lwall
+ * patch20: removed implicit int declarations on functions
+ * patch20: hash tables now split only if the memory is available to do so
+ * patch20: realloc(0, size) now does malloc in case library routines call it
+ *
+ * Revision 4.0.1.3 91/11/05 17:57:40 lwall
+ * patch11: safe malloc code now integrated into Perl's malloc when possible
+ *
+ * Revision 4.0.1.2 91/06/07 11:20:45 lwall
+ * patch4: many, many itty-bitty portability fixes
+ *
+ * Revision 4.0.1.1 91/04/11 17:48:31 lwall
+ * patch1: Configure now figures out malloc ptr type
+ *
+ * Revision 4.0 91/03/20 01:28:52 lwall
+ * 4.0 baseline.
+ *
+ */
+
+#ifndef lint
+/*SUPPRESS 592*/
+static char sccsid[] = "@(#)malloc.c 4.3 (Berkeley) 9/16/83";
+
+#ifdef DEBUGGING
+#define RCHECK
+#endif
+/*
+ * malloc.c (Caltech) 2/21/82
+ * Chris Kingsley, kingsley@cit-20.
+ *
+ * This is a very fast storage allocator. It allocates blocks of a small
+ * number of different sizes, and keeps free lists of each size. Blocks that
+ * don't exactly fit are passed up to the next larger size. In this
+ * implementation, the available sizes are 2^n-4 (or 2^n-12) bytes long.
+ * This is designed for use in a program that uses vast quantities of memory,
+ * but bombs when it runs out.
+ */
+
+#include "EXTERN.h"
+#include "../perl.h"
+
+static findbucket(), morecore();
+
+/* I don't much care whether these are defined in sys/types.h--LAW */
+
+#define u_char unsigned char
+#define u_int unsigned int
+#define u_short unsigned short
+
+/*
+ * The overhead on a block is at least 4 bytes. When free, this space
+ * contains a pointer to the next free block, and the bottom two bits must
+ * be zero. When in use, the first byte is set to MAGIC, and the second
+ * byte is the size index. The remaining bytes are for alignment.
+ * If range checking is enabled and the size of the block fits
+ * in two bytes, then the top two bytes hold the size of the requested block
+ * plus the range checking words, and the header word MINUS ONE.
+ */
+union overhead {
+ union overhead *ov_next; /* when free */
+#if ALIGN_BYTES > 4
+ double strut; /* alignment problems */
+#endif
+ struct {
+ u_char ovu_magic; /* magic number */
+ u_char ovu_index; /* bucket # */
+#ifdef RCHECK
+ u_short ovu_size; /* actual block size */
+ u_int ovu_rmagic; /* range magic number */
+#endif
+ } ovu;
+#define ov_magic ovu.ovu_magic
+#define ov_index ovu.ovu_index
+#define ov_size ovu.ovu_size
+#define ov_rmagic ovu.ovu_rmagic
+};
+
+#define MAGIC 0xff /* magic # on accounting info */
+#define OLDMAGIC 0x7f /* same after a free() */
+#define RMAGIC 0x55555555 /* magic # on range info */
+#ifdef RCHECK
+#define RSLOP sizeof (u_int)
+#else
+#define RSLOP 0
+#endif
+
+/*
+ * nextf[i] is the pointer to the next free block of size 2^(i+3). The
+ * smallest allocatable block is 8 bytes. The overhead information
+ * precedes the data area returned to the user.
+ */
+#define NBUCKETS 30
+static union overhead *nextf[NBUCKETS];
+extern char *sbrk();
+
+#ifdef MSTATS
+/*
+ * nmalloc[i] is the difference between the number of mallocs and frees
+ * for a given block size.
+ */
+static u_int nmalloc[NBUCKETS];
+#include <stdio.h>
+#endif
+
+#ifdef debug
+#define ASSERT(p) if (!(p)) botch("p"); else
+static void
+botch(s)
+ char *s;
+{
+
+ printf("assertion botched: %s\n", s);
+ abort();
+}
+#else
+#define ASSERT(p)
+#endif
+
+#ifdef safemalloc
+static int an = 0;
+#endif
+
+MALLOCPTRTYPE *
+malloc(nbytes)
+ register MEM_SIZE nbytes;
+{
+ register union overhead *p;
+ register int bucket = 0;
+ register MEM_SIZE shiftr;
+
+#ifdef safemalloc
+#ifdef DEBUGGING
+ MEM_SIZE size = nbytes;
+#endif
+
+#ifdef MSDOS
+ if (nbytes > 0xffff) {
+ fprintf(stderr, "Allocation too large: %lx\n", (long)nbytes);
+ exit(1);
+ }
+#endif /* MSDOS */
+#ifdef DEBUGGING
+ if ((long)nbytes < 0)
+ fatal("panic: malloc");
+#endif
+#endif /* safemalloc */
+
+ /*
+ * Convert amount of memory requested into
+ * closest block size stored in hash buckets
+ * which satisfies request. Account for
+ * space used per block for accounting.
+ */
+ nbytes += sizeof (union overhead) + RSLOP;
+ nbytes = (nbytes + 3) &~ 3;
+ shiftr = (nbytes - 1) >> 2;
+ /* apart from this loop, this is O(1) */
+ while (shiftr >>= 1)
+ bucket++;
+ /*
+ * If nothing in hash bucket right now,
+ * request more memory from the system.
+ */
+ if (nextf[bucket] == NULL)
+ morecore(bucket);
+ if ((p = (union overhead *)nextf[bucket]) == NULL) {
+#ifdef safemalloc
+ if (!nomemok) {
+ fputs("Out of memory!\n", stderr);
+ exit(1);
+ }
+#else
+ return (NULL);
+#endif
+ }
+
+#ifdef safemalloc
+#ifdef DEBUGGING
+# if !(defined(I286) || defined(atarist))
+ if (debug & 128)
+ fprintf(stderr,"0x%x: (%05d) malloc %ld bytes\n",p+1,an++,(long)size);
+# else
+ if (debug & 128)
+ fprintf(stderr,"0x%lx: (%05d) malloc %ld bytes\n",p+1,an++,(long)size);
+# endif
+#endif
+#endif /* safemalloc */
+
+ /* remove from linked list */
+#ifdef RCHECK
+ if (*((int*)p) & (sizeof(union overhead) - 1))
+#if !(defined(I286) || defined(atarist))
+ fprintf(stderr,"Corrupt malloc ptr 0x%x at 0x%x\n",*((int*)p),p);
+#else
+ fprintf(stderr,"Corrupt malloc ptr 0x%lx at 0x%lx\n",*((int*)p),p);
+#endif
+#endif
+ nextf[bucket] = p->ov_next;
+ p->ov_magic = MAGIC;
+ p->ov_index= bucket;
+#ifdef MSTATS
+ nmalloc[bucket]++;
+#endif
+#ifdef RCHECK
+ /*
+ * Record allocated size of block and
+ * bound space with magic numbers.
+ */
+ if (nbytes <= 0x10000)
+ p->ov_size = nbytes - 1;
+ p->ov_rmagic = RMAGIC;
+ *((u_int *)((caddr_t)p + nbytes - RSLOP)) = RMAGIC;
+#endif
+ return ((MALLOCPTRTYPE *)(p + 1));
+}
+
+/*
+ * Allocate more memory to the indicated bucket.
+ */
+static
+morecore(bucket)
+ register int bucket;
+{
+ register union overhead *op;
+ register int rnu; /* 2^rnu bytes will be requested */
+ register int nblks; /* become nblks blocks of the desired size */
+ register MEM_SIZE siz;
+
+ if (nextf[bucket])
+ return;
+ /*
+ * Insure memory is allocated
+ * on a page boundary. Should
+ * make getpageize call?
+ */
+#ifndef atarist /* on the atari we dont have to worry about this */
+ op = (union overhead *)sbrk(0);
+#ifndef I286
+ if ((int)op & 0x3ff)
+ (void)sbrk(1024 - ((int)op & 0x3ff));
+#else
+ /* The sbrk(0) call on the I286 always returns the next segment */
+#endif
+#endif /* atarist */
+
+#if !(defined(I286) || defined(atarist))
+ /* take 2k unless the block is bigger than that */
+ rnu = (bucket <= 8) ? 11 : bucket + 3;
+#else
+ /* take 16k unless the block is bigger than that
+ (80286s like large segments!), probably good on the atari too */
+ rnu = (bucket <= 11) ? 14 : bucket + 3;
+#endif
+ nblks = 1 << (rnu - (bucket + 3)); /* how many blocks to get */
+ if (rnu < bucket)
+ rnu = bucket;
+ op = (union overhead *)sbrk(1L << rnu);
+ /* no more room! */
+ if ((int)op == -1)
+ return;
+ /*
+ * Round up to minimum allocation size boundary
+ * and deduct from block count to reflect.
+ */
+#ifndef I286
+ if ((int)op & 7) {
+ op = (union overhead *)(((MEM_SIZE)op + 8) &~ 7);
+ nblks--;
+ }
+#else
+ /* Again, this should always be ok on an 80286 */
+#endif
+ /*
+ * Add new memory allocated to that on
+ * free list for this hash bucket.
+ */
+ nextf[bucket] = op;
+ siz = 1 << (bucket + 3);
+ while (--nblks > 0) {
+ op->ov_next = (union overhead *)((caddr_t)op + siz);
+ op = (union overhead *)((caddr_t)op + siz);
+ }
+}
+
+void
+free(mp)
+ MALLOCPTRTYPE *mp;
+{
+ register MEM_SIZE size;
+ register union overhead *op;
+ char *cp = (char*)mp;
+
+#ifdef safemalloc
+#ifdef DEBUGGING
+# if !(defined(I286) || defined(atarist))
+ if (debug & 128)
+ fprintf(stderr,"0x%x: (%05d) free\n",cp,an++);
+# else
+ if (debug & 128)
+ fprintf(stderr,"0x%lx: (%05d) free\n",cp,an++);
+# endif
+#endif
+#endif /* safemalloc */
+
+ if (cp == NULL)
+ return;
+ op = (union overhead *)((caddr_t)cp - sizeof (union overhead));
+#ifdef debug
+ ASSERT(op->ov_magic == MAGIC); /* make sure it was in use */
+#else
+ if (op->ov_magic != MAGIC) {
+ warn("%s free() ignored",
+ op->ov_magic == OLDMAGIC ? "Duplicate" : "Bad");
+ return; /* sanity */
+ }
+ op->ov_magic = OLDMAGIC;
+#endif
+#ifdef RCHECK
+ ASSERT(op->ov_rmagic == RMAGIC);
+ if (op->ov_index <= 13)
+ ASSERT(*(u_int *)((caddr_t)op + op->ov_size + 1 - RSLOP) == RMAGIC);
+#endif
+ ASSERT(op->ov_index < NBUCKETS);
+ size = op->ov_index;
+ op->ov_next = nextf[size];
+ nextf[size] = op;
+#ifdef MSTATS
+ nmalloc[size]--;
+#endif
+}
+
+/*
+ * When a program attempts "storage compaction" as mentioned in the
+ * old malloc man page, it realloc's an already freed block. Usually
+ * this is the last block it freed; occasionally it might be farther
+ * back. We have to search all the free lists for the block in order
+ * to determine its bucket: 1st we make one pass thru the lists
+ * checking only the first block in each; if that fails we search
+ * ``reall_srchlen'' blocks in each list for a match (the variable
+ * is extern so the caller can modify it). If that fails we just copy
+ * however many bytes was given to realloc() and hope it's not huge.
+ */
+int reall_srchlen = 4; /* 4 should be plenty, -1 =>'s whole list */
+
+MALLOCPTRTYPE *
+realloc(mp, nbytes)
+ MALLOCPTRTYPE *mp;
+ MEM_SIZE nbytes;
+{
+ register MEM_SIZE onb;
+ union overhead *op;
+ char *res;
+ register int i;
+ int was_alloced = 0;
+ char *cp = (char*)mp;
+
+#ifdef safemalloc
+#ifdef DEBUGGING
+ MEM_SIZE size = nbytes;
+#endif
+
+#ifdef MSDOS
+ if (nbytes > 0xffff) {
+ fprintf(stderr, "Reallocation too large: %lx\n", size);
+ exit(1);
+ }
+#endif /* MSDOS */
+ if (!cp)
+ return malloc(nbytes);
+#ifdef DEBUGGING
+ if ((long)nbytes < 0)
+ fatal("panic: realloc");
+#endif
+#endif /* safemalloc */
+
+ op = (union overhead *)((caddr_t)cp - sizeof (union overhead));
+ if (op->ov_magic == MAGIC) {
+ was_alloced++;
+ i = op->ov_index;
+ } else {
+ /*
+ * Already free, doing "compaction".
+ *
+ * Search for the old block of memory on the
+ * free list. First, check the most common
+ * case (last element free'd), then (this failing)
+ * the last ``reall_srchlen'' items free'd.
+ * If all lookups fail, then assume the size of
+ * the memory block being realloc'd is the
+ * smallest possible.
+ */
+ if ((i = findbucket(op, 1)) < 0 &&
+ (i = findbucket(op, reall_srchlen)) < 0)
+ i = 0;
+ }
+ onb = (1L << (i + 3)) - sizeof (*op) - RSLOP;
+ /* avoid the copy if same size block */
+ if (was_alloced &&
+ nbytes <= onb && nbytes > (onb >> 1) - sizeof(*op) - RSLOP) {
+#ifdef RCHECK
+ /*
+ * Record new allocated size of block and
+ * bound space with magic numbers.
+ */
+ if (op->ov_index <= 13) {
+ /*
+ * Convert amount of memory requested into
+ * closest block size stored in hash buckets
+ * which satisfies request. Account for
+ * space used per block for accounting.
+ */
+ nbytes += sizeof (union overhead) + RSLOP;
+ nbytes = (nbytes + 3) &~ 3;
+ op->ov_size = nbytes - 1;
+ *((u_int *)((caddr_t)op + nbytes - RSLOP)) = RMAGIC;
+ }
+#endif
+ res = cp;
+ }
+ else {
+ if ((res = (char*)malloc(nbytes)) == NULL)
+ return (NULL);
+ if (cp != res) /* common optimization */
+ Copy(cp, res, (MEM_SIZE)(nbytes<onb?nbytes:onb), char);
+ if (was_alloced)
+ free(cp);
+ }
+
+#ifdef safemalloc
+#ifdef DEBUGGING
+# if !(defined(I286) || defined(atarist))
+ if (debug & 128) {
+ fprintf(stderr,"0x%x: (%05d) rfree\n",res,an++);
+ fprintf(stderr,"0x%x: (%05d) realloc %ld bytes\n",res,an++,(long)size);
+ }
+# else
+ if (debug & 128) {
+ fprintf(stderr,"0x%lx: (%05d) rfree\n",res,an++);
+ fprintf(stderr,"0x%lx: (%05d) realloc %ld bytes\n",res,an++,(long)size);
+ }
+# endif
+#endif
+#endif /* safemalloc */
+ return ((MALLOCPTRTYPE*)res);
+}
+
+/*
+ * Search ``srchlen'' elements of each free list for a block whose
+ * header starts at ``freep''. If srchlen is -1 search the whole list.
+ * Return bucket number, or -1 if not found.
+ */
+static int
+findbucket(freep, srchlen)
+ union overhead *freep;
+ int srchlen;
+{
+ register union overhead *p;
+ register int i, j;
+
+ for (i = 0; i < NBUCKETS; i++) {
+ j = 0;
+ for (p = nextf[i]; p && j != srchlen; p = p->ov_next) {
+ if (p == freep)
+ return (i);
+ j++;
+ }
+ }
+ return (-1);
+}
+
+#ifdef MSTATS
+/*
+ * mstats - print out statistics about malloc
+ *
+ * Prints two lines of numbers, one showing the length of the free list
+ * for each size category, the second showing the number of mallocs -
+ * frees for each size category.
+ */
+void
+mstats(s)
+ char *s;
+{
+ register int i, j;
+ register union overhead *p;
+ int totfree = 0,
+ totused = 0;
+
+ fprintf(stderr, "Memory allocation statistics %s\nfree:\t", s);
+ for (i = 0; i < NBUCKETS; i++) {
+ for (j = 0, p = nextf[i]; p; p = p->ov_next, j++)
+ ;
+ fprintf(stderr, " %d", j);
+ totfree += j * (1 << (i + 3));
+ }
+ fprintf(stderr, "\nused:\t");
+ for (i = 0; i < NBUCKETS; i++) {
+ fprintf(stderr, " %d", nmalloc[i]);
+ totused += nmalloc[i] * (1 << (i + 3));
+ }
+ fprintf(stderr, "\n\tTotal in use: %d, total free: %d\n",
+ totused, totfree);
+}
+#endif
+#endif /* lint */
diff --git a/gnu/usr.bin/perl/x2p/s2p b/gnu/usr.bin/perl/x2p/s2p
new file mode 100755
index 0000000..c110e5e
--- /dev/null
+++ b/gnu/usr.bin/perl/x2p/s2p
@@ -0,0 +1,769 @@
+#!/usr/bin/perl
+
+eval 'exec /usr/bin/perl -S $0 ${1+"$@"}'
+ if $running_under_some_shell;
+
+$bin = '/usr/bin';
+
+# $RCSfile: s2p,v $$Revision: 1.1.1.1 $$Date: 1994/09/10 06:27:54 $
+#
+# $Log: s2p,v $
+# Revision 1.1.1.1 1994/09/10 06:27:54 gclarkii
+# Initial import of Perl 4.046 bmaked
+#
+# Revision 1.2 1994/03/05 01:28:48 ache
+# 1) Perl uses scrambler crypt() version from libc instead of proper one
+# from -lcrypt (if exist)
+# 2) We have now all sem/shm/msg stuff, add it to perl too
+#
+# Revision 1.1.1.1 1993/08/23 21:30:10 nate
+# PERL!
+#
+# Revision 4.0.1.2 92/06/08 17:26:31 lwall
+# patch20: s2p didn't output portable startup code
+# patch20: added ... as variant on ..
+# patch20: s2p didn't translate s/pat/\&/ or s/pat/\$/ or s/pat/\\1/ right
+#
+# Revision 4.0.1.1 91/06/07 12:19:18 lwall
+# patch4: s2p now handles embedded newlines better and optimizes common idioms
+#
+# Revision 4.0 91/03/20 01:57:59 lwall
+# 4.0 baseline.
+#
+#
+
+$indent = 4;
+$shiftwidth = 4;
+$l = '{'; $r = '}';
+
+while ($ARGV[0] =~ /^-/) {
+ $_ = shift;
+ last if /^--/;
+ if (/^-D/) {
+ $debug++;
+ open(BODY,'>-');
+ next;
+ }
+ if (/^-n/) {
+ $assumen++;
+ next;
+ }
+ if (/^-p/) {
+ $assumep++;
+ next;
+ }
+ die "I don't recognize this switch: $_\n";
+}
+
+unless ($debug) {
+ open(BODY,">/tmp/sperl$$") ||
+ &Die("Can't open temp file: $!\n");
+}
+
+if (!$assumen && !$assumep) {
+ print BODY &q(<<'EOT');
+: while ($ARGV[0] =~ /^-/) {
+: $_ = shift;
+: last if /^--/;
+: if (/^-n/) {
+: $nflag++;
+: next;
+: }
+: die "I don't recognize this switch: $_\\n";
+: }
+:
+EOT
+}
+
+print BODY &q(<<'EOT');
+: #ifdef PRINTIT
+: #ifdef ASSUMEP
+: $printit++;
+: #else
+: $printit++ unless $nflag;
+: #endif
+: #endif
+: <><>
+: $\ = "\n"; # automatically add newline on print
+: <><>
+: #ifdef TOPLABEL
+: LINE:
+: while (chop($_ = <>)) {
+: #else
+: LINE:
+: while (<>) {
+: chop;
+: #endif
+EOT
+
+LINE:
+while (<>) {
+
+ # Wipe out surrounding whitespace.
+
+ s/[ \t]*(.*)\n$/$1/;
+
+ # Perhaps it's a label/comment.
+
+ if (/^:/) {
+ s/^:[ \t]*//;
+ $label = &make_label($_);
+ if ($. == 1) {
+ $toplabel = $label;
+ if (/^(top|(re)?start|redo|begin(ning)|again|input)$/i) {
+ $_ = <>;
+ redo LINE; # Never referenced, so delete it if not a comment.
+ }
+ }
+ $_ = "$label:";
+ if ($lastlinewaslabel++) {
+ $indent += 4;
+ print BODY &tab, ";\n";
+ $indent -= 4;
+ }
+ if ($indent >= 2) {
+ $indent -= 2;
+ $indmod = 2;
+ }
+ next;
+ } else {
+ $lastlinewaslabel = '';
+ }
+
+ # Look for one or two address clauses
+
+ $addr1 = '';
+ $addr2 = '';
+ if (s/^([0-9]+)//) {
+ $addr1 = "$1";
+ $addr1 = "\$. == $addr1" unless /^,/;
+ }
+ elsif (s/^\$//) {
+ $addr1 = 'eof()';
+ }
+ elsif (s|^/||) {
+ $addr1 = &fetchpat('/');
+ }
+ if (s/^,//) {
+ if (s/^([0-9]+)//) {
+ $addr2 = "$1";
+ } elsif (s/^\$//) {
+ $addr2 = "eof()";
+ } elsif (s|^/||) {
+ $addr2 = &fetchpat('/');
+ } else {
+ &Die("Invalid second address at line $.\n");
+ }
+ if ($addr2 =~ /^\d+$/) {
+ $addr1 .= "..$addr2";
+ }
+ else {
+ $addr1 .= "...$addr2";
+ }
+ }
+
+ # Now we check for metacommands {, }, and ! and worry
+ # about indentation.
+
+ s/^[ \t]+//;
+ # a { to keep vi happy
+ if ($_ eq '}') {
+ $indent -= 4;
+ next;
+ }
+ if (s/^!//) {
+ $if = 'unless';
+ $else = "$r else $l\n";
+ } else {
+ $if = 'if';
+ $else = '';
+ }
+ if (s/^{//) { # a } to keep vi happy
+ $indmod = 4;
+ $redo = $_;
+ $_ = '';
+ $rmaybe = '';
+ } else {
+ $rmaybe = "\n$r";
+ if ($addr2 || $addr1) {
+ $space = ' ' x $shiftwidth;
+ } else {
+ $space = '';
+ }
+ $_ = &transmogrify();
+ }
+
+ # See if we can optimize to modifier form.
+
+ if ($addr1) {
+ if ($_ !~ /[\n{}]/ && $rmaybe && !$change &&
+ $_ !~ / if / && $_ !~ / unless /) {
+ s/;$/ $if $addr1;/;
+ $_ = substr($_,$shiftwidth,1000);
+ } else {
+ $_ = "$if ($addr1) $l\n$change$_$rmaybe";
+ }
+ $change = '';
+ next LINE;
+ }
+} continue {
+ @lines = split(/\n/,$_);
+ for (@lines) {
+ unless (s/^ *<<--//) {
+ print BODY &tab;
+ }
+ print BODY $_, "\n";
+ }
+ $indent += $indmod;
+ $indmod = 0;
+ if ($redo) {
+ $_ = $redo;
+ $redo = '';
+ redo LINE;
+ }
+}
+if ($lastlinewaslabel++) {
+ $indent += 4;
+ print BODY &tab, ";\n";
+ $indent -= 4;
+}
+
+if ($appendseen || $tseen || !$assumen) {
+ $printit++ if $dseen || (!$assumen && !$assumep);
+ print BODY &q(<<'EOT');
+: #ifdef SAWNEXT
+: }
+: continue {
+: #endif
+: #ifdef PRINTIT
+: #ifdef DSEEN
+: #ifdef ASSUMEP
+: print if $printit++;
+: #else
+: if ($printit)
+: { print; }
+: else
+: { $printit++ unless $nflag; }
+: #endif
+: #else
+: print if $printit;
+: #endif
+: #else
+: print;
+: #endif
+: #ifdef TSEEN
+: $tflag = 0;
+: #endif
+: #ifdef APPENDSEEN
+: if ($atext) { chop $atext; print $atext; $atext = ''; }
+: #endif
+EOT
+
+print BODY &q(<<'EOT');
+: }
+EOT
+}
+
+close BODY;
+
+unless ($debug) {
+ open(HEAD,">/tmp/sperl2$$.c")
+ || &Die("Can't open temp file 2: $!\n");
+ print HEAD "#define PRINTIT\n" if $printit;
+ print HEAD "#define APPENDSEEN\n" if $appendseen;
+ print HEAD "#define TSEEN\n" if $tseen;
+ print HEAD "#define DSEEN\n" if $dseen;
+ print HEAD "#define ASSUMEN\n" if $assumen;
+ print HEAD "#define ASSUMEP\n" if $assumep;
+ print HEAD "#define TOPLABEL\n" if $toplabel;
+ print HEAD "#define SAWNEXT\n" if $sawnext;
+ if ($opens) {print HEAD "$opens\n";}
+ open(BODY,"/tmp/sperl$$")
+ || &Die("Can't reopen temp file: $!\n");
+ while (<BODY>) {
+ print HEAD $_;
+ }
+ close HEAD;
+
+ print &q(<<"EOT");
+: #!$bin/perl
+: eval 'exec $bin/perl -S \$0 \${1+"\$@"}'
+: if \$running_under_some_shell;
+:
+EOT
+ open(BODY,"cc -E /tmp/sperl2$$.c |") ||
+ &Die("Can't reopen temp file: $!\n");
+ while (<BODY>) {
+ /^# [0-9]/ && next;
+ /^[ \t]*$/ && next;
+ s/^<><>//;
+ print;
+ }
+}
+
+&Cleanup;
+exit;
+
+sub Cleanup {
+ chdir "/tmp";
+ unlink "sperl$$", "sperl2$$", "sperl2$$.c";
+}
+sub Die {
+ &Cleanup;
+ die $_[0];
+}
+sub tab {
+ "\t" x ($indent / 8) . ' ' x ($indent % 8);
+}
+sub make_filehandle {
+ local($_) = $_[0];
+ local($fname) = $_;
+ if (!$seen{$fname}) {
+ $_ = "FH_" . $_ if /^\d/;
+ s/[^a-zA-Z0-9]/_/g;
+ s/^_*//;
+ $_ = "\U$_";
+ if ($fhseen{$_}) {
+ for ($tmp = "a"; $fhseen{"$_$tmp"}; $a++) {}
+ $_ .= $tmp;
+ }
+ $fhseen{$_} = 1;
+ $opens .= &q(<<"EOT");
+: open($_, '>$fname') || die "Can't create $fname: \$!";
+EOT
+ $seen{$fname} = $_;
+ }
+ $seen{$fname};
+}
+
+sub make_label {
+ local($label) = @_;
+ $label =~ s/[^a-zA-Z0-9]/_/g;
+ if ($label =~ /^[0-9_]/) { $label = 'L' . $label; }
+ $label = substr($label,0,8);
+
+ # Could be a reserved word, so capitalize it.
+ substr($label,0,1) =~ y/a-z/A-Z/
+ if $label =~ /^[a-z]/;
+
+ $label;
+}
+
+sub transmogrify {
+ { # case
+ if (/^d/) {
+ $dseen++;
+ chop($_ = &q(<<'EOT'));
+: <<--#ifdef PRINTIT
+: $printit = 0;
+: <<--#endif
+: next LINE;
+EOT
+ $sawnext++;
+ next;
+ }
+
+ if (/^n/) {
+ chop($_ = &q(<<'EOT'));
+: <<--#ifdef PRINTIT
+: <<--#ifdef DSEEN
+: <<--#ifdef ASSUMEP
+: print if $printit++;
+: <<--#else
+: if ($printit)
+: { print; }
+: else
+: { $printit++ unless $nflag; }
+: <<--#endif
+: <<--#else
+: print if $printit;
+: <<--#endif
+: <<--#else
+: print;
+: <<--#endif
+: <<--#ifdef APPENDSEEN
+: if ($atext) {chop $atext; print $atext; $atext = '';}
+: <<--#endif
+: $_ = <>;
+: chop;
+: <<--#ifdef TSEEN
+: $tflag = 0;
+: <<--#endif
+EOT
+ next;
+ }
+
+ if (/^a/) {
+ $appendseen++;
+ $command = $space . "\$atext .= <<'End_Of_Text';\n<<--";
+ $lastline = 0;
+ while (<>) {
+ s/^[ \t]*//;
+ s/^[\\]//;
+ unless (s|\\$||) { $lastline = 1;}
+ s/^([ \t]*\n)/<><>$1/;
+ $command .= $_;
+ $command .= '<<--';
+ last if $lastline;
+ }
+ $_ = $command . "End_Of_Text";
+ last;
+ }
+
+ if (/^[ic]/) {
+ if (/^c/) { $change = 1; }
+ $addr1 = 1 if $addr1 eq '';
+ $addr1 = '$iter = (' . $addr1 . ')';
+ $command = $space .
+ " if (\$iter == 1) { print <<'End_Of_Text'; }\n<<--";
+ $lastline = 0;
+ while (<>) {
+ s/^[ \t]*//;
+ s/^[\\]//;
+ unless (s/\\$//) { $lastline = 1;}
+ s/'/\\'/g;
+ s/^([ \t]*\n)/<><>$1/;
+ $command .= $_;
+ $command .= '<<--';
+ last if $lastline;
+ }
+ $_ = $command . "End_Of_Text";
+ if ($change) {
+ $dseen++;
+ $change = "$_\n";
+ chop($_ = &q(<<"EOT"));
+: <<--#ifdef PRINTIT
+: $space\$printit = 0;
+: <<--#endif
+: ${space}next LINE;
+EOT
+ $sawnext++;
+ }
+ last;
+ }
+
+ if (/^s/) {
+ $delim = substr($_,1,1);
+ $len = length($_);
+ $repl = $end = 0;
+ $inbracket = 0;
+ for ($i = 2; $i < $len; $i++) {
+ $c = substr($_,$i,1);
+ if ($c eq $delim) {
+ if ($inbracket) {
+ substr($_, $i, 0) = '\\';
+ $i++;
+ $len++;
+ }
+ else {
+ if ($repl) {
+ $end = $i;
+ last;
+ } else {
+ $repl = $i;
+ }
+ }
+ }
+ elsif ($c eq '\\') {
+ $i++;
+ if ($i >= $len) {
+ $_ .= 'n';
+ $_ .= <>;
+ $len = length($_);
+ $_ = substr($_,0,--$len);
+ }
+ elsif (substr($_,$i,1) =~ /^[n]$/) {
+ ;
+ }
+ elsif (!$repl &&
+ substr($_,$i,1) =~ /^[(){}\w]$/) {
+ $i--;
+ $len--;
+ substr($_, $i, 1) = '';
+ }
+ elsif (!$repl &&
+ substr($_,$i,1) =~ /^[<>]$/) {
+ substr($_,$i,1) = 'b';
+ }
+ elsif ($repl && substr($_,$i,1) =~ /^\d$/) {
+ substr($_,$i-1,1) = '$';
+ }
+ }
+ elsif ($c eq '&' && $repl) {
+ substr($_, $i, 0) = '$';
+ $i++;
+ $len++;
+ }
+ elsif ($c eq '$' && $repl) {
+ substr($_, $i, 0) = '\\';
+ $i++;
+ $len++;
+ }
+ elsif ($c eq '[' && !$repl) {
+ $i++ if substr($_,$i,1) eq '^';
+ $i++ if substr($_,$i,1) eq ']';
+ $inbracket = 1;
+ }
+ elsif ($c eq ']') {
+ $inbracket = 0;
+ }
+ elsif ($c eq "\t") {
+ substr($_, $i, 1) = '\\t';
+ $i++;
+ $len++;
+ }
+ elsif (!$repl && index("()+",$c) >= 0) {
+ substr($_, $i, 0) = '\\';
+ $i++;
+ $len++;
+ }
+ }
+ &Die("Malformed substitution at line $.\n")
+ unless $end;
+ $pat = substr($_, 0, $repl + 1);
+ $repl = substr($_, $repl+1, $end-$repl-1);
+ $end = substr($_, $end + 1, 1000);
+ &simplify($pat);
+ $dol = '$';
+ $subst = "$pat$repl$delim";
+ $cmd = '';
+ while ($end) {
+ if ($end =~ s/^g//) {
+ $subst .= 'g';
+ next;
+ }
+ if ($end =~ s/^p//) {
+ $cmd .= ' && (print)';
+ next;
+ }
+ if ($end =~ s/^w[ \t]*//) {
+ $fh = &make_filehandle($end);
+ $cmd .= " && (print $fh \$_)";
+ $end = '';
+ next;
+ }
+ &Die("Unrecognized substitution command".
+ "($end) at line $.\n");
+ }
+ chop ($_ = &q(<<"EOT"));
+: <<--#ifdef TSEEN
+: $subst && \$tflag++$cmd;
+: <<--#else
+: $subst$cmd;
+: <<--#endif
+EOT
+ next;
+ }
+
+ if (/^p/) {
+ $_ = 'print;';
+ next;
+ }
+
+ if (/^w/) {
+ s/^w[ \t]*//;
+ $fh = &make_filehandle($_);
+ $_ = "print $fh \$_;";
+ next;
+ }
+
+ if (/^r/) {
+ $appendseen++;
+ s/^r[ \t]*//;
+ $file = $_;
+ $_ = "\$atext .= `cat $file 2>/dev/null`;";
+ next;
+ }
+
+ if (/^P/) {
+ $_ = 'print $1 if /^(.*)/;';
+ next;
+ }
+
+ if (/^D/) {
+ chop($_ = &q(<<'EOT'));
+: s/^.*\n?//;
+: redo LINE if $_;
+: next LINE;
+EOT
+ $sawnext++;
+ next;
+ }
+
+ if (/^N/) {
+ chop($_ = &q(<<'EOT'));
+: $_ .= "\n";
+: $len1 = length;
+: $_ .= <>;
+: chop if $len1 < length;
+: <<--#ifdef TSEEN
+: $tflag = 0;
+: <<--#endif
+EOT
+ next;
+ }
+
+ if (/^h/) {
+ $_ = '$hold = $_;';
+ next;
+ }
+
+ if (/^H/) {
+ $_ = '$hold .= "\n"; $hold .= $_;';
+ next;
+ }
+
+ if (/^g/) {
+ $_ = '$_ = $hold;';
+ next;
+ }
+
+ if (/^G/) {
+ $_ = '$_ .= "\n"; $_ .= $hold;';
+ next;
+ }
+
+ if (/^x/) {
+ $_ = '($_, $hold) = ($hold, $_);';
+ next;
+ }
+
+ if (/^b$/) {
+ $_ = 'next LINE;';
+ $sawnext++;
+ next;
+ }
+
+ if (/^b/) {
+ s/^b[ \t]*//;
+ $lab = &make_label($_);
+ if ($lab eq $toplabel) {
+ $_ = 'redo LINE;';
+ } else {
+ $_ = "goto $lab;";
+ }
+ next;
+ }
+
+ if (/^t$/) {
+ $_ = 'next LINE if $tflag;';
+ $sawnext++;
+ $tseen++;
+ next;
+ }
+
+ if (/^t/) {
+ s/^t[ \t]*//;
+ $lab = &make_label($_);
+ $_ = q/if ($tflag) {$tflag = 0; /;
+ if ($lab eq $toplabel) {
+ $_ .= 'redo LINE;}';
+ } else {
+ $_ .= "goto $lab;}";
+ }
+ $tseen++;
+ next;
+ }
+
+ if (/^y/) {
+ s/abcdefghijklmnopqrstuvwxyz/a-z/g;
+ s/ABCDEFGHIJKLMNOPQRSTUVWXYZ/A-Z/g;
+ s/abcdef/a-f/g;
+ s/ABCDEF/A-F/g;
+ s/0123456789/0-9/g;
+ s/01234567/0-7/g;
+ $_ .= ';';
+ }
+
+ if (/^=/) {
+ $_ = 'print $.;';
+ next;
+ }
+
+ if (/^q/) {
+ chop($_ = &q(<<'EOT'));
+: close(ARGV);
+: @ARGV = ();
+: next LINE;
+EOT
+ $sawnext++;
+ next;
+ }
+ } continue {
+ if ($space) {
+ s/^/$space/;
+ s/(\n)(.)/$1$space$2/g;
+ }
+ last;
+ }
+ $_;
+}
+
+sub fetchpat {
+ local($outer) = @_;
+ local($addr) = $outer;
+ local($inbracket);
+ local($prefix,$delim,$ch);
+
+ # Process pattern one potential delimiter at a time.
+
+ DELIM: while (s#^([^\]+(|)[\\/]*)([]+(|)[\\/])##) {
+ $prefix = $1;
+ $delim = $2;
+ if ($delim eq '\\') {
+ s/(.)//;
+ $ch = $1;
+ $delim = '' if $ch =~ /^[(){}A-Za-mo-z]$/;
+ $ch = 'b' if $ch =~ /^[<>]$/;
+ $delim .= $ch;
+ }
+ elsif ($delim eq '[') {
+ $inbracket = 1;
+ s/^\^// && ($delim .= '^');
+ s/^]// && ($delim .= ']');
+ }
+ elsif ($delim eq ']') {
+ $inbracket = 0;
+ }
+ elsif ($inbracket || $delim ne $outer) {
+ $delim = '\\' . $delim;
+ }
+ $addr .= $prefix;
+ $addr .= $delim;
+ if ($delim eq $outer && !$inbracket) {
+ last DELIM;
+ }
+ }
+ $addr =~ s/\t/\\t/g;
+ &simplify($addr);
+ $addr;
+}
+
+sub q {
+ local($string) = @_;
+ local($*) = 1;
+ $string =~ s/^:\t?//g;
+ $string;
+}
+
+sub simplify {
+ $_[0] =~ s/_a-za-z0-9/\\w/ig;
+ $_[0] =~ s/a-z_a-z0-9/\\w/ig;
+ $_[0] =~ s/a-za-z_0-9/\\w/ig;
+ $_[0] =~ s/a-za-z0-9_/\\w/ig;
+ $_[0] =~ s/_0-9a-za-z/\\w/ig;
+ $_[0] =~ s/0-9_a-za-z/\\w/ig;
+ $_[0] =~ s/0-9a-z_a-z/\\w/ig;
+ $_[0] =~ s/0-9a-za-z_/\\w/ig;
+ $_[0] =~ s/\[\\w\]/\\w/g;
+ $_[0] =~ s/\[^\\w\]/\\W/g;
+ $_[0] =~ s/\[0-9\]/\\d/g;
+ $_[0] =~ s/\[^0-9\]/\\D/g;
+ $_[0] =~ s/\\d\\d\*/\\d+/g;
+ $_[0] =~ s/\\D\\D\*/\\D+/g;
+ $_[0] =~ s/\\w\\w\*/\\w+/g;
+ $_[0] =~ s/\\t\\t\*/\\t+/g;
+ $_[0] =~ s/(\[.[^]]*\])\1\*/$1+/g;
+ $_[0] =~ s/([\w\s!@#%^&-=,:;'"])\1\*/$1+/g;
+}
+
diff --git a/gnu/usr.bin/perl/x2p/s2p.1 b/gnu/usr.bin/perl/x2p/s2p.1
new file mode 100644
index 0000000..ab74717
--- /dev/null
+++ b/gnu/usr.bin/perl/x2p/s2p.1
@@ -0,0 +1,108 @@
+.rn '' }`
+''' $RCSfile: s2p.man,v $$Revision: 1.1.1.1 $$Date: 1993/08/23 21:30:10 $
+'''
+''' $Log: s2p.man,v $
+.\" Revision 1.1.1.1 1993/08/23 21:30:10 nate
+.\" PERL!
+.\"
+''' Revision 4.0.1.1 91/06/07 12:19:57 lwall
+''' patch4: s2p now handles embedded newlines better and optimizes common idioms
+'''
+''' Revision 4.0 91/03/20 01:58:07 lwall
+''' 4.0 baseline.
+'''
+''' Revision 3.0 89/10/18 15:35:09 lwall
+''' 3.0 baseline
+'''
+''' Revision 2.0 88/06/05 00:15:59 root
+''' Baseline version 2.0.
+'''
+'''
+.de Sh
+.br
+.ne 5
+.PP
+\fB\\$1\fR
+.PP
+..
+.de Sp
+.if t .sp .5v
+.if n .sp
+..
+.de Ip
+.br
+.ie \\n.$>=3 .ne \\$3
+.el .ne 3
+.IP "\\$1" \\$2
+..
+'''
+''' Set up \*(-- to give an unbreakable dash;
+''' string Tr holds user defined translation string.
+''' Bell System Logo is used as a dummy character.
+'''
+.tr \(*W-|\(bv\*(Tr
+.ie n \{\
+.ds -- \(*W-
+.if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch
+.if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\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 S2P 1 NEW
+.SH NAME
+s2p - Sed to Perl translator
+.SH SYNOPSIS
+.B s2p [options] filename
+.SH DESCRIPTION
+.I S2p
+takes a sed script specified on the command line (or from standard input)
+and produces a comparable
+.I perl
+script on the standard output.
+.Sh "Options"
+Options include:
+.TP 5
+.B \-D<number>
+sets debugging flags.
+.TP 5
+.B \-n
+specifies that this sed script was always invoked with a sed -n.
+Otherwise a switch parser is prepended to the front of the script.
+.TP 5
+.B \-p
+specifies that this sed script was never invoked with a sed -n.
+Otherwise a switch parser is prepended to the front of the script.
+.Sh "Considerations"
+The perl script produced looks very sed-ish, and there may very well be
+better ways to express what you want to do in perl.
+For instance, s2p does not make any use of the split operator, but you might
+want to.
+.PP
+The perl script you end up with may be either faster or slower than the original
+sed script.
+If you're only interested in speed you'll just have to try it both ways.
+Of course, if you want to do something sed doesn't do, you have no choice.
+It's often possible to speed up the perl script by various methods, such
+as deleting all references to $\e and chop.
+.SH ENVIRONMENT
+S2p uses no environment variables.
+.SH AUTHOR
+Larry Wall <lwall@jpl-devvax.Jpl.Nasa.Gov>
+.SH FILES
+.SH SEE ALSO
+perl The perl compiler/interpreter
+.br
+a2p awk to perl translator
+.SH DIAGNOSTICS
+.SH BUGS
+.rn }` ''
diff --git a/gnu/usr.bin/perl/x2p/str.c b/gnu/usr.bin/perl/x2p/str.c
new file mode 100644
index 0000000..4e078a6
--- /dev/null
+++ b/gnu/usr.bin/perl/x2p/str.c
@@ -0,0 +1,470 @@
+/* $RCSfile: str.c,v $$Revision: 1.1.1.1 $$Date: 1994/09/10 06:27:54 $
+ *
+ * Copyright (c) 1991, Larry Wall
+ *
+ * You may distribute under the terms of either the GNU General Public
+ * License or the Artistic License, as specified in the README file.
+ *
+ * $Log: str.c,v $
+ * Revision 1.1.1.1 1994/09/10 06:27:54 gclarkii
+ * Initial import of Perl 4.046 bmaked
+ *
+ * Revision 1.1.1.1 1993/08/23 21:30:09 nate
+ * PERL!
+ *
+ * Revision 4.0.1.1 91/06/07 12:20:08 lwall
+ * patch4: new copyright notice
+ *
+ * Revision 4.0 91/03/20 01:58:15 lwall
+ * 4.0 baseline.
+ *
+ */
+
+#include "handy.h"
+#include "EXTERN.h"
+#include "util.h"
+#include "a2p.h"
+
+str_numset(str,num)
+register STR *str;
+double num;
+{
+ str->str_nval = num;
+ str->str_pok = 0; /* invalidate pointer */
+ str->str_nok = 1; /* validate number */
+}
+
+char *
+str_2ptr(str)
+register STR *str;
+{
+ register char *s;
+
+ if (!str)
+ return "";
+ GROWSTR(&(str->str_ptr), &(str->str_len), 24);
+ s = str->str_ptr;
+ if (str->str_nok) {
+ sprintf(s,"%.20g",str->str_nval);
+ while (*s) s++;
+ }
+ *s = '\0';
+ str->str_cur = s - str->str_ptr;
+ str->str_pok = 1;
+#ifdef DEBUGGING
+ if (debug & 32)
+ fprintf(stderr,"0x%lx ptr(%s)\n",str,str->str_ptr);
+#endif
+ return str->str_ptr;
+}
+
+double
+str_2num(str)
+register STR *str;
+{
+ if (!str)
+ return 0.0;
+ if (str->str_len && str->str_pok)
+ str->str_nval = atof(str->str_ptr);
+ else
+ str->str_nval = 0.0;
+ str->str_nok = 1;
+#ifdef DEBUGGING
+ if (debug & 32)
+ fprintf(stderr,"0x%lx num(%g)\n",str,str->str_nval);
+#endif
+ return str->str_nval;
+}
+
+str_sset(dstr,sstr)
+STR *dstr;
+register STR *sstr;
+{
+ if (!sstr)
+ str_nset(dstr,No,0);
+ else if (sstr->str_nok)
+ str_numset(dstr,sstr->str_nval);
+ else if (sstr->str_pok)
+ str_nset(dstr,sstr->str_ptr,sstr->str_cur);
+ else
+ str_nset(dstr,"",0);
+}
+
+str_nset(str,ptr,len)
+register STR *str;
+register char *ptr;
+register int len;
+{
+ GROWSTR(&(str->str_ptr), &(str->str_len), len + 1);
+ bcopy(ptr,str->str_ptr,len);
+ str->str_cur = len;
+ *(str->str_ptr+str->str_cur) = '\0';
+ str->str_nok = 0; /* invalidate number */
+ str->str_pok = 1; /* validate pointer */
+}
+
+str_set(str,ptr)
+register STR *str;
+register char *ptr;
+{
+ register int len;
+
+ if (!ptr)
+ ptr = "";
+ len = strlen(ptr);
+ GROWSTR(&(str->str_ptr), &(str->str_len), len + 1);
+ bcopy(ptr,str->str_ptr,len+1);
+ str->str_cur = len;
+ str->str_nok = 0; /* invalidate number */
+ str->str_pok = 1; /* validate pointer */
+}
+
+str_chop(str,ptr) /* like set but assuming ptr is in str */
+register STR *str;
+register char *ptr;
+{
+ if (!(str->str_pok))
+ str_2ptr(str);
+ str->str_cur -= (ptr - str->str_ptr);
+ bcopy(ptr,str->str_ptr, str->str_cur + 1);
+ str->str_nok = 0; /* invalidate number */
+ str->str_pok = 1; /* validate pointer */
+}
+
+str_ncat(str,ptr,len)
+register STR *str;
+register char *ptr;
+register int len;
+{
+ if (!(str->str_pok))
+ str_2ptr(str);
+ GROWSTR(&(str->str_ptr), &(str->str_len), str->str_cur + len + 1);
+ bcopy(ptr,str->str_ptr+str->str_cur,len);
+ str->str_cur += len;
+ *(str->str_ptr+str->str_cur) = '\0';
+ str->str_nok = 0; /* invalidate number */
+ str->str_pok = 1; /* validate pointer */
+}
+
+str_scat(dstr,sstr)
+STR *dstr;
+register STR *sstr;
+{
+ if (!(sstr->str_pok))
+ str_2ptr(sstr);
+ if (sstr)
+ str_ncat(dstr,sstr->str_ptr,sstr->str_cur);
+}
+
+str_cat(str,ptr)
+register STR *str;
+register char *ptr;
+{
+ register int len;
+
+ if (!ptr)
+ return;
+ if (!(str->str_pok))
+ str_2ptr(str);
+ len = strlen(ptr);
+ GROWSTR(&(str->str_ptr), &(str->str_len), str->str_cur + len + 1);
+ bcopy(ptr,str->str_ptr+str->str_cur,len+1);
+ str->str_cur += len;
+ str->str_nok = 0; /* invalidate number */
+ str->str_pok = 1; /* validate pointer */
+}
+
+char *
+str_append_till(str,from,delim,keeplist)
+register STR *str;
+register char *from;
+register int delim;
+char *keeplist;
+{
+ register char *to;
+ register int len;
+
+ if (!from)
+ return Nullch;
+ len = strlen(from);
+ GROWSTR(&(str->str_ptr), &(str->str_len), str->str_cur + len + 1);
+ str->str_nok = 0; /* invalidate number */
+ str->str_pok = 1; /* validate pointer */
+ to = str->str_ptr+str->str_cur;
+ for (; *from; from++,to++) {
+ if (*from == '\\' && from[1] && delim != '\\') {
+ if (!keeplist) {
+ if (from[1] == delim || from[1] == '\\')
+ from++;
+ else
+ *to++ = *from++;
+ }
+ else if (index(keeplist,from[1]))
+ *to++ = *from++;
+ else
+ from++;
+ }
+ else if (*from == delim)
+ break;
+ *to = *from;
+ }
+ *to = '\0';
+ str->str_cur = to - str->str_ptr;
+ return from;
+}
+
+STR *
+str_new(len)
+int len;
+{
+ register STR *str;
+
+ if (freestrroot) {
+ str = freestrroot;
+ freestrroot = str->str_link.str_next;
+ }
+ else {
+ str = (STR *) safemalloc(sizeof(STR));
+ bzero((char*)str,sizeof(STR));
+ }
+ if (len)
+ GROWSTR(&(str->str_ptr), &(str->str_len), len + 1);
+ return str;
+}
+
+void
+str_grow(str,len)
+register STR *str;
+int len;
+{
+ if (len && str)
+ GROWSTR(&(str->str_ptr), &(str->str_len), len + 1);
+}
+
+/* make str point to what nstr did */
+
+void
+str_replace(str,nstr)
+register STR *str;
+register STR *nstr;
+{
+ safefree(str->str_ptr);
+ str->str_ptr = nstr->str_ptr;
+ str->str_len = nstr->str_len;
+ str->str_cur = nstr->str_cur;
+ str->str_pok = nstr->str_pok;
+ if (str->str_nok = nstr->str_nok)
+ str->str_nval = nstr->str_nval;
+ safefree((char*)nstr);
+}
+
+void
+str_free(str)
+register STR *str;
+{
+ if (!str)
+ return;
+ if (str->str_len)
+ str->str_ptr[0] = '\0';
+ str->str_cur = 0;
+ str->str_nok = 0;
+ str->str_pok = 0;
+ str->str_link.str_next = freestrroot;
+ freestrroot = str;
+}
+
+str_len(str)
+register STR *str;
+{
+ if (!str)
+ return 0;
+ if (!(str->str_pok))
+ str_2ptr(str);
+ if (str->str_len)
+ return str->str_cur;
+ else
+ return 0;
+}
+
+char *
+str_gets(str,fp)
+register STR *str;
+register FILE *fp;
+{
+#ifdef STDSTDIO /* Here is some breathtakingly efficient cheating */
+
+ register char *bp; /* we're going to steal some values */
+ register int cnt; /* from the stdio struct and put EVERYTHING */
+ register STDCHAR *ptr; /* in the innermost loop into registers */
+ register char newline = '\n'; /* (assuming at least 6 registers) */
+ int i;
+ int bpx;
+
+ cnt = fp->_cnt; /* get count into register */
+ str->str_nok = 0; /* invalidate number */
+ str->str_pok = 1; /* validate pointer */
+ if (str->str_len <= cnt) /* make sure we have the room */
+ GROWSTR(&(str->str_ptr), &(str->str_len), cnt+1);
+ bp = str->str_ptr; /* move these two too to registers */
+ ptr = fp->_ptr;
+ for (;;) {
+ while (--cnt >= 0) {
+ if ((*bp++ = *ptr++) == newline)
+ if (bp <= str->str_ptr || bp[-2] != '\\')
+ goto thats_all_folks;
+ else {
+ line++;
+ bp -= 2;
+ }
+ }
+
+ fp->_cnt = cnt; /* deregisterize cnt and ptr */
+ fp->_ptr = ptr;
+ i = _filbuf(fp); /* get more characters */
+ cnt = fp->_cnt;
+ ptr = fp->_ptr; /* reregisterize cnt and ptr */
+
+ bpx = bp - str->str_ptr; /* prepare for possible relocation */
+ GROWSTR(&(str->str_ptr), &(str->str_len), str->str_cur + cnt + 1);
+ bp = str->str_ptr + bpx; /* reconstitute our pointer */
+
+ if (i == newline) { /* all done for now? */
+ *bp++ = i;
+ goto thats_all_folks;
+ }
+ else if (i == EOF) /* all done for ever? */
+ goto thats_all_folks;
+ *bp++ = i; /* now go back to screaming loop */
+ }
+
+thats_all_folks:
+ fp->_cnt = cnt; /* put these back or we're in trouble */
+ fp->_ptr = ptr;
+ *bp = '\0';
+ str->str_cur = bp - str->str_ptr; /* set length */
+
+#else /* !STDSTDIO */ /* The big, slow, and stupid way */
+
+ static char buf[4192];
+
+ if (fgets(buf, sizeof buf, fp) != Nullch)
+ str_set(str, buf);
+ else
+ str_set(str, No);
+
+#endif /* STDSTDIO */
+
+ return str->str_cur ? str->str_ptr : Nullch;
+}
+
+void
+str_inc(str)
+register STR *str;
+{
+ register char *d;
+
+ if (!str)
+ return;
+ if (str->str_nok) {
+ str->str_nval += 1.0;
+ str->str_pok = 0;
+ return;
+ }
+ if (!str->str_pok) {
+ str->str_nval = 1.0;
+ str->str_nok = 1;
+ return;
+ }
+ for (d = str->str_ptr; *d && *d != '.'; d++) ;
+ d--;
+ if (!isdigit(*str->str_ptr) || !isdigit(*d) ) {
+ str_numset(str,atof(str->str_ptr) + 1.0); /* punt */
+ return;
+ }
+ while (d >= str->str_ptr) {
+ if (++*d <= '9')
+ return;
+ *(d--) = '0';
+ }
+ /* oh,oh, the number grew */
+ GROWSTR(&(str->str_ptr), &(str->str_len), str->str_cur + 2);
+ str->str_cur++;
+ for (d = str->str_ptr + str->str_cur; d > str->str_ptr; d--)
+ *d = d[-1];
+ *d = '1';
+}
+
+void
+str_dec(str)
+register STR *str;
+{
+ register char *d;
+
+ if (!str)
+ return;
+ if (str->str_nok) {
+ str->str_nval -= 1.0;
+ str->str_pok = 0;
+ return;
+ }
+ if (!str->str_pok) {
+ str->str_nval = -1.0;
+ str->str_nok = 1;
+ return;
+ }
+ for (d = str->str_ptr; *d && *d != '.'; d++) ;
+ d--;
+ if (!isdigit(*str->str_ptr) || !isdigit(*d) || (*d == '0' && d == str->str_ptr)) {
+ str_numset(str,atof(str->str_ptr) - 1.0); /* punt */
+ return;
+ }
+ while (d >= str->str_ptr) {
+ if (--*d >= '0')
+ return;
+ *(d--) = '9';
+ }
+}
+
+/* make a string that will exist for the duration of the expression eval */
+
+STR *
+str_mortal(oldstr)
+STR *oldstr;
+{
+ register STR *str = str_new(0);
+ static long tmps_size = -1;
+
+ str_sset(str,oldstr);
+ if (++tmps_max > tmps_size) {
+ tmps_size = tmps_max;
+ if (!(tmps_size & 127)) {
+ if (tmps_size)
+ tmps_list = (STR**)saferealloc((char*)tmps_list,
+ (tmps_size + 128) * sizeof(STR*) );
+ else
+ tmps_list = (STR**)safemalloc(128 * sizeof(char*));
+ }
+ }
+ tmps_list[tmps_max] = str;
+ return str;
+}
+
+STR *
+str_make(s)
+char *s;
+{
+ register STR *str = str_new(0);
+
+ str_set(str,s);
+ return str;
+}
+
+STR *
+str_nmake(n)
+double n;
+{
+ register STR *str = str_new(0);
+
+ str_numset(str,n);
+ return str;
+}
diff --git a/gnu/usr.bin/perl/x2p/str.h b/gnu/usr.bin/perl/x2p/str.h
new file mode 100644
index 0000000..642e18e
--- /dev/null
+++ b/gnu/usr.bin/perl/x2p/str.h
@@ -0,0 +1,49 @@
+/* $RCSfile: str.h,v $$Revision: 1.1.1.1 $$Date: 1994/09/10 06:27:55 $
+ *
+ * Copyright (c) 1991, Larry Wall
+ *
+ * You may distribute under the terms of either the GNU General Public
+ * License or the Artistic License, as specified in the README file.
+ *
+ * $Log: str.h,v $
+ * Revision 1.1.1.1 1994/09/10 06:27:55 gclarkii
+ * Initial import of Perl 4.046 bmaked
+ *
+ * Revision 1.1.1.1 1993/08/23 21:30:10 nate
+ * PERL!
+ *
+ * Revision 4.0.1.1 91/06/07 12:20:22 lwall
+ * patch4: new copyright notice
+ *
+ * Revision 4.0 91/03/20 01:58:21 lwall
+ * 4.0 baseline.
+ *
+ */
+
+struct string {
+ char * str_ptr; /* pointer to malloced string */
+ double str_nval; /* numeric value, if any */
+ int str_len; /* allocated size */
+ int str_cur; /* length of str_ptr as a C string */
+ union {
+ STR *str_next; /* while free, link to next free str */
+ } str_link;
+ char str_pok; /* state of str_ptr */
+ char str_nok; /* state of str_nval */
+};
+
+#define Nullstr Null(STR*)
+
+/* the following macro updates any magic values this str is associated with */
+
+#define STABSET(x) (x->str_link.str_magic && stabset(x->str_link.str_magic,x))
+
+EXT STR **tmps_list;
+EXT long tmps_max INIT(-1);
+
+char *str_2ptr();
+double str_2num();
+STR *str_mortal();
+STR *str_make();
+STR *str_nmake();
+char *str_gets();
diff --git a/gnu/usr.bin/perl/x2p/util.c b/gnu/usr.bin/perl/x2p/util.c
new file mode 100644
index 0000000..70a6cd7
--- /dev/null
+++ b/gnu/usr.bin/perl/x2p/util.c
@@ -0,0 +1,271 @@
+/* $RCSfile: util.c,v $$Revision: 1.1.1.1 $$Date: 1994/09/10 06:27:55 $
+ *
+ * Copyright (c) 1991, Larry Wall
+ *
+ * You may distribute under the terms of either the GNU General Public
+ * License or the Artistic License, as specified in the README file.
+ *
+ * $Log: util.c,v $
+ * Revision 1.1.1.1 1994/09/10 06:27:55 gclarkii
+ * Initial import of Perl 4.046 bmaked
+ *
+ * Revision 1.1.1.1 1993/08/23 21:30:10 nate
+ * PERL!
+ *
+ * Revision 4.0.1.1 91/06/07 12:20:35 lwall
+ * patch4: new copyright notice
+ *
+ * Revision 4.0 91/03/20 01:58:25 lwall
+ * 4.0 baseline.
+ *
+ */
+
+#include <stdio.h>
+
+#include "handy.h"
+#include "EXTERN.h"
+#include "a2p.h"
+#include "INTERN.h"
+#include "util.h"
+
+#define FLUSH
+#define MEM_SIZE unsigned int
+
+static char nomem[] = "Out of memory!\n";
+
+/* paranoid version of malloc */
+
+static int an = 0;
+
+char *
+safemalloc(size)
+MEM_SIZE size;
+{
+ char *ptr;
+ char *malloc();
+
+ ptr = malloc(size?size:1); /* malloc(0) is NASTY on our system */
+#ifdef DEBUGGING
+ if (debug & 128)
+ fprintf(stderr,"0x%x: (%05d) malloc %d bytes\n",ptr,an++,size);
+#endif
+ if (ptr != Nullch)
+ return ptr;
+ else {
+ fputs(nomem,stdout) FLUSH;
+ exit(1);
+ }
+ /*NOTREACHED*/
+}
+
+/* paranoid version of realloc */
+
+char *
+saferealloc(where,size)
+char *where;
+MEM_SIZE size;
+{
+ char *ptr;
+ char *realloc();
+
+ ptr = realloc(where,size?size:1); /* realloc(0) is NASTY on our system */
+#ifdef DEBUGGING
+ if (debug & 128) {
+ fprintf(stderr,"0x%x: (%05d) rfree\n",where,an++);
+ fprintf(stderr,"0x%x: (%05d) realloc %d bytes\n",ptr,an++,size);
+ }
+#endif
+ if (ptr != Nullch)
+ return ptr;
+ else {
+ fputs(nomem,stdout) FLUSH;
+ exit(1);
+ }
+ /*NOTREACHED*/
+}
+
+/* safe version of free */
+
+safefree(where)
+char *where;
+{
+#ifdef DEBUGGING
+ if (debug & 128)
+ fprintf(stderr,"0x%x: (%05d) free\n",where,an++);
+#endif
+ free(where);
+}
+
+/* safe version of string copy */
+
+char *
+safecpy(to,from,len)
+char *to;
+register char *from;
+register int len;
+{
+ register char *dest = to;
+
+ if (from != Nullch)
+ for (len--; len && (*dest++ = *from++); len--) ;
+ *dest = '\0';
+ return to;
+}
+
+/* copy a string up to some (non-backslashed) delimiter, if any */
+
+char *
+cpytill(to,from,delim)
+register char *to, *from;
+register int delim;
+{
+ for (; *from; from++,to++) {
+ if (*from == '\\') {
+ if (from[1] == delim)
+ from++;
+ else if (from[1] == '\\')
+ *to++ = *from++;
+ }
+ else if (*from == delim)
+ break;
+ *to = *from;
+ }
+ *to = '\0';
+ return from;
+}
+
+
+char *
+cpy2(to,from,delim)
+register char *to, *from;
+register int delim;
+{
+ for (; *from; from++,to++) {
+ if (*from == '\\')
+ *to++ = *from++;
+ else if (*from == '$')
+ *to++ = '\\';
+ else if (*from == delim)
+ break;
+ *to = *from;
+ }
+ *to = '\0';
+ return from;
+}
+
+/* return ptr to little string in big string, NULL if not found */
+
+char *
+instr(big, little)
+char *big, *little;
+
+{
+ register char *t, *s, *x;
+
+ for (t = big; *t; t++) {
+ for (x=t,s=little; *s; x++,s++) {
+ if (!*x)
+ return Nullch;
+ if (*s != *x)
+ break;
+ }
+ if (!*s)
+ return t;
+ }
+ return Nullch;
+}
+
+/* copy a string to a safe spot */
+
+char *
+savestr(str)
+char *str;
+{
+ register char *newaddr = safemalloc((MEM_SIZE)(strlen(str)+1));
+
+ (void)strcpy(newaddr,str);
+ return newaddr;
+}
+
+/* grow a static string to at least a certain length */
+
+void
+growstr(strptr,curlen,newlen)
+char **strptr;
+int *curlen;
+int newlen;
+{
+ if (newlen > *curlen) { /* need more room? */
+ if (*curlen)
+ *strptr = saferealloc(*strptr,(MEM_SIZE)newlen);
+ else
+ *strptr = safemalloc((MEM_SIZE)newlen);
+ *curlen = newlen;
+ }
+}
+
+/*VARARGS1*/
+fatal(pat,a1,a2,a3,a4)
+char *pat;
+{
+ fprintf(stderr,pat,a1,a2,a3,a4);
+ exit(1);
+}
+
+/*VARARGS1*/
+warn(pat,a1,a2,a3,a4)
+char *pat;
+{
+ fprintf(stderr,pat,a1,a2,a3,a4);
+}
+
+static bool firstsetenv = TRUE;
+extern char **environ;
+
+void
+setenv(nam,val)
+char *nam, *val;
+{
+ register int i=envix(nam); /* where does it go? */
+
+ if (!environ[i]) { /* does not exist yet */
+ if (firstsetenv) { /* need we copy environment? */
+ int j;
+#ifndef lint
+ char **tmpenv = (char**) /* point our wand at memory */
+ safemalloc((i+2) * sizeof(char*));
+#else
+ char **tmpenv = Null(char **);
+#endif /* lint */
+
+ firstsetenv = FALSE;
+ for (j=0; j<i; j++) /* copy environment */
+ tmpenv[j] = environ[j];
+ environ = tmpenv; /* tell exec where it is now */
+ }
+#ifndef lint
+ else
+ environ = (char**) saferealloc((char*) environ,
+ (i+2) * sizeof(char*));
+ /* just expand it a bit */
+#endif /* lint */
+ environ[i+1] = Nullch; /* make sure it's null terminated */
+ }
+ environ[i] = safemalloc(strlen(nam) + strlen(val) + 2);
+ /* this may or may not be in */
+ /* the old environ structure */
+ sprintf(environ[i],"%s=%s",nam,val);/* all that work just for this */
+}
+
+int
+envix(nam)
+char *nam;
+{
+ register int i, len = strlen(nam);
+
+ for (i = 0; environ[i]; i++) {
+ if (strnEQ(environ[i],nam,len) && environ[i][len] == '=')
+ break; /* strnEQ must come first to avoid */
+ } /* potential SEGV's */
+ return i;
+}
diff --git a/gnu/usr.bin/perl/x2p/util.h b/gnu/usr.bin/perl/x2p/util.h
new file mode 100644
index 0000000..ad94422
--- /dev/null
+++ b/gnu/usr.bin/perl/x2p/util.h
@@ -0,0 +1,56 @@
+/* $RCSfile: util.h,v $$Revision: 1.1.1.1 $$Date: 1994/09/10 06:27:55 $
+ *
+ * Copyright (c) 1991, Larry Wall
+ *
+ * You may distribute under the terms of either the GNU General Public
+ * License or the Artistic License, as specified in the README file.
+ *
+ * $Log: util.h,v $
+ * Revision 1.1.1.1 1994/09/10 06:27:55 gclarkii
+ * Initial import of Perl 4.046 bmaked
+ *
+ * Revision 1.1.1.1 1993/08/23 21:30:10 nate
+ * PERL!
+ *
+ * Revision 4.0.1.2 91/11/05 19:21:20 lwall
+ * patch11: various portability fixes
+ *
+ * Revision 4.0.1.1 91/06/07 12:20:43 lwall
+ * patch4: new copyright notice
+ *
+ * Revision 4.0 91/03/20 01:58:29 lwall
+ * 4.0 baseline.
+ *
+ */
+
+/* is the string for makedir a directory name or a filename? */
+
+#define fatal Myfatal
+
+#define MD_DIR 0
+#define MD_FILE 1
+
+void util_init();
+int doshell();
+char *safemalloc();
+char *saferealloc();
+char *safecpy();
+char *safecat();
+char *cpytill();
+char *cpy2();
+char *instr();
+#ifdef SETUIDGID
+ int eaccess();
+#endif
+char *getwd();
+void cat();
+void prexit();
+char *get_a_line();
+char *savestr();
+int makedir();
+void setenv();
+int envix();
+void notincl();
+char *getval();
+void growstr();
+void setdef();
diff --git a/gnu/usr.bin/perl/x2p/walk.c b/gnu/usr.bin/perl/x2p/walk.c
new file mode 100644
index 0000000..c7e5e44
--- /dev/null
+++ b/gnu/usr.bin/perl/x2p/walk.c
@@ -0,0 +1,2089 @@
+/* $RCSfile: walk.c,v $$Revision: 1.1.1.1 $$Date: 1994/09/10 06:27:55 $
+ *
+ * Copyright (c) 1991, Larry Wall
+ *
+ * You may distribute under the terms of either the GNU General Public
+ * License or the Artistic License, as specified in the README file.
+ *
+ * $Log: walk.c,v $
+ * Revision 1.1.1.1 1994/09/10 06:27:55 gclarkii
+ * Initial import of Perl 4.046 bmaked
+ *
+ * Revision 1.1.1.1 1993/08/23 21:30:11 nate
+ * PERL!
+ *
+ * Revision 4.0.1.3 92/06/08 17:33:46 lwall
+ * patch20: in a2p, simplified the filehandle model
+ * patch20: in a2p, made RS="" translate to $/ = "\n\n"
+ * patch20: in a2p, do {...} while ... was missing some reconstruction code
+ * patch20: in a2p, getline should allow variable to be array element
+ *
+ * Revision 4.0.1.2 91/11/05 19:25:09 lwall
+ * patch11: in a2p, split on whitespace produced extra null field
+ *
+ * Revision 4.0.1.1 91/06/07 12:22:04 lwall
+ * patch4: new copyright notice
+ * patch4: a2p didn't correctly implement -n switch
+ *
+ * Revision 4.0 91/03/20 01:58:36 lwall
+ * 4.0 baseline.
+ *
+ */
+
+#include "handy.h"
+#include "EXTERN.h"
+#include "util.h"
+#include "a2p.h"
+
+bool exitval = FALSE;
+bool realexit = FALSE;
+bool saw_getline = FALSE;
+bool subretnum = FALSE;
+bool saw_FNR = FALSE;
+bool saw_argv0 = FALSE;
+bool saw_fh = FALSE;
+int maxtmp = 0;
+char *lparen;
+char *rparen;
+char *limit;
+STR *subs;
+STR *curargs = Nullstr;
+
+STR *
+walk(useval,level,node,numericptr,minprec)
+int useval;
+int level;
+register int node;
+int *numericptr;
+int minprec; /* minimum precedence without parens */
+{
+ register int len;
+ register STR *str;
+ register int type;
+ register int i;
+ register STR *tmpstr;
+ STR *tmp2str;
+ STR *tmp3str;
+ char *t;
+ char *d, *s;
+ int numarg;
+ int numeric = FALSE;
+ STR *fstr;
+ int prec = P_MAX; /* assume no parens needed */
+ char *index();
+
+ if (!node) {
+ *numericptr = 0;
+ return str_make("");
+ }
+ type = ops[node].ival;
+ len = type >> 8;
+ type &= 255;
+ switch (type) {
+ case OPROG:
+ arymax = 0;
+ if (namelist) {
+ while (isalpha(*namelist)) {
+ for (d = tokenbuf,s=namelist;
+ isalpha(*s) || isdigit(*s) || *s == '_';
+ *d++ = *s++) ;
+ *d = '\0';
+ while (*s && !isalpha(*s)) s++;
+ namelist = s;
+ nameary[++arymax] = savestr(tokenbuf);
+ }
+ }
+ if (maxfld < arymax)
+ maxfld = arymax;
+ opens = str_new(0);
+ subs = str_new(0);
+ str = walk(0,level,ops[node+1].ival,&numarg,P_MIN);
+ if (do_split && need_entire && !absmaxfld)
+ split_to_array = TRUE;
+ if (do_split && split_to_array)
+ set_array_base = TRUE;
+ if (set_array_base) {
+ str_cat(str,"$[ = 1;\t\t\t# set array base to 1\n");
+ }
+ if (fswitch && !const_FS)
+ const_FS = fswitch;
+ if (saw_FS > 1 || saw_RS)
+ const_FS = 0;
+ if (saw_ORS && need_entire)
+ do_chop = TRUE;
+ if (fswitch) {
+ str_cat(str,"$FS = '");
+ if (index("*+?.[]()|^$\\",fswitch))
+ str_cat(str,"\\");
+ sprintf(tokenbuf,"%c",fswitch);
+ str_cat(str,tokenbuf);
+ str_cat(str,"';\t\t# field separator from -F switch\n");
+ }
+ else if (saw_FS && !const_FS) {
+ str_cat(str,"$FS = ' ';\t\t# set field separator\n");
+ }
+ if (saw_OFS) {
+ str_cat(str,"$, = ' ';\t\t# set output field separator\n");
+ }
+ if (saw_ORS) {
+ str_cat(str,"$\\ = \"\\n\";\t\t# set output record separator\n");
+ }
+ if (saw_argv0) {
+ str_cat(str,"$ARGV0 = $0;\t\t# remember what we ran as\n");
+ }
+ if (str->str_cur > 20)
+ str_cat(str,"\n");
+ if (ops[node+2].ival) {
+ str_scat(str,fstr=walk(0,level,ops[node+2].ival,&numarg,P_MIN));
+ str_free(fstr);
+ str_cat(str,"\n\n");
+ }
+ fstr = walk(0,level+1,ops[node+3].ival,&numarg,P_MIN);
+ if (*fstr->str_ptr) {
+ if (saw_line_op)
+ str_cat(str,"line: ");
+ str_cat(str,"while (<>) {\n");
+ tab(str,++level);
+ if (saw_FS && !const_FS)
+ do_chop = TRUE;
+ if (do_chop) {
+ str_cat(str,"chop;\t# strip record separator\n");
+ tab(str,level);
+ }
+ if (do_split)
+ emit_split(str,level);
+ str_scat(str,fstr);
+ str_free(fstr);
+ fixtab(str,--level);
+ str_cat(str,"}\n");
+ if (saw_FNR)
+ str_cat(str,"continue {\n $FNRbase = $. if eof;\n}\n");
+ }
+ else
+ str_cat(str,"while (<>) { } # (no line actions)\n");
+ if (ops[node+4].ival) {
+ realexit = TRUE;
+ str_cat(str,"\n");
+ tab(str,level);
+ str_scat(str,fstr=walk(0,level,ops[node+4].ival,&numarg,P_MIN));
+ str_free(fstr);
+ str_cat(str,"\n");
+ }
+ if (exitval)
+ str_cat(str,"exit $ExitValue;\n");
+ if (subs->str_ptr) {
+ str_cat(str,"\n");
+ str_scat(str,subs);
+ }
+ if (saw_getline) {
+ for (len = 0; len < 4; len++) {
+ if (saw_getline & (1 << len)) {
+ sprintf(tokenbuf,"\nsub Getline%d {\n",len);
+ str_cat(str, tokenbuf);
+ if (len & 2) {
+ if (do_fancy_opens)
+ str_cat(str," &Pick('',@_);\n");
+ else
+ str_cat(str," ($fh) = @_;\n");
+ }
+ else {
+ if (saw_FNR)
+ str_cat(str," $FNRbase = $. if eof;\n");
+ }
+ if (len & 1)
+ str_cat(str," local($_);\n");
+ if (len & 2)
+ str_cat(str,
+ " if ($getline_ok = (($_ = <$fh>) ne ''))");
+ else
+ str_cat(str,
+ " if ($getline_ok = (($_ = <>) ne ''))");
+ str_cat(str, " {\n");
+ level += 2;
+ tab(str,level);
+ i = 0;
+ if (do_chop) {
+ i++;
+ str_cat(str,"chop;\t# strip record separator\n");
+ tab(str,level);
+ }
+ if (do_split && !(len & 1)) {
+ i++;
+ emit_split(str,level);
+ }
+ if (!i)
+ str_cat(str,";\n");
+ fixtab(str,--level);
+ str_cat(str,"}\n $_;\n}\n");
+ --level;
+ }
+ }
+ }
+ if (do_fancy_opens) {
+ str_cat(str,"\n\
+sub Pick {\n\
+ local($mode,$name,$pipe) = @_;\n\
+ $fh = $name;\n\
+ open($name,$mode.$name.$pipe) unless $opened{$name}++;\n\
+}\n\
+");
+ }
+ break;
+ case OHUNKS:
+ str = walk(0,level,ops[node+1].ival,&numarg,P_MIN);
+ str_scat(str,fstr=walk(0,level,ops[node+2].ival,&numarg,P_MIN));
+ str_free(fstr);
+ if (len == 3) {
+ str_scat(str,fstr=walk(0,level,ops[node+3].ival,&numarg,P_MIN));
+ str_free(fstr);
+ }
+ else {
+ }
+ break;
+ case ORANGE:
+ prec = P_DOTDOT;
+ str = walk(1,level,ops[node+1].ival,&numarg,prec+1);
+ str_cat(str," .. ");
+ str_scat(str,fstr=walk(1,level,ops[node+2].ival,&numarg,prec+1));
+ str_free(fstr);
+ break;
+ case OPAT:
+ goto def;
+ case OREGEX:
+ str = str_new(0);
+ str_set(str,"/");
+ tmpstr=walk(0,level,ops[node+1].ival,&numarg,P_MIN);
+ /* translate \nnn to [\nnn] */
+ for (s = tmpstr->str_ptr, d = tokenbuf; *s; s++, d++) {
+ if (*s == '\\' && isdigit(s[1]) && isdigit(s[2]) && isdigit(s[3])){
+ *d++ = '[';
+ *d++ = *s++;
+ *d++ = *s++;
+ *d++ = *s++;
+ *d++ = *s;
+ *d = ']';
+ }
+ else
+ *d = *s;
+ }
+ *d = '\0';
+ for (d=tokenbuf; *d; d++)
+ *d += 128;
+ str_cat(str,tokenbuf);
+ str_free(tmpstr);
+ str_cat(str,"/");
+ break;
+ case OHUNK:
+ if (len == 1) {
+ str = str_new(0);
+ str = walk(0,level,oper1(OPRINT,0),&numarg,P_MIN);
+ str_cat(str," if ");
+ str_scat(str,fstr=walk(0,level,ops[node+1].ival,&numarg,P_MIN));
+ str_free(fstr);
+ str_cat(str,";");
+ }
+ else {
+ tmpstr = walk(0,level,ops[node+1].ival,&numarg,P_MIN);
+ if (*tmpstr->str_ptr) {
+ str = str_new(0);
+ str_set(str,"if (");
+ str_scat(str,tmpstr);
+ str_cat(str,") {\n");
+ tab(str,++level);
+ str_scat(str,fstr=walk(0,level,ops[node+2].ival,&numarg,P_MIN));
+ str_free(fstr);
+ fixtab(str,--level);
+ str_cat(str,"}\n");
+ tab(str,level);
+ }
+ else {
+ str = walk(0,level,ops[node+2].ival,&numarg,P_MIN);
+ }
+ }
+ break;
+ case OPPAREN:
+ str = str_new(0);
+ str_set(str,"(");
+ str_scat(str,fstr=walk(useval != 0,level,ops[node+1].ival,&numarg,P_MIN));
+ str_free(fstr);
+ str_cat(str,")");
+ break;
+ case OPANDAND:
+ prec = P_ANDAND;
+ str = walk(1,level,ops[node+1].ival,&numarg,prec);
+ str_cat(str," && ");
+ str_scat(str,fstr=walk(1,level,ops[node+2].ival,&numarg,prec+1));
+ str_free(fstr);
+ str_scat(str,fstr=walk(1,level,ops[node+3].ival,&numarg,prec+1));
+ str_free(fstr);
+ break;
+ case OPOROR:
+ prec = P_OROR;
+ str = walk(1,level,ops[node+1].ival,&numarg,prec);
+ str_cat(str," || ");
+ str_scat(str,fstr=walk(1,level,ops[node+2].ival,&numarg,prec+1));
+ str_free(fstr);
+ str_scat(str,fstr=walk(1,level,ops[node+3].ival,&numarg,prec+1));
+ str_free(fstr);
+ break;
+ case OPNOT:
+ prec = P_UNARY;
+ str = str_new(0);
+ str_set(str,"!");
+ str_scat(str,fstr=walk(1,level,ops[node+1].ival,&numarg,prec));
+ str_free(fstr);
+ break;
+ case OCOND:
+ prec = P_COND;
+ str = walk(1,level,ops[node+1].ival,&numarg,prec);
+ str_cat(str," ? ");
+ str_scat(str,fstr=walk(1,level,ops[node+2].ival,&numarg,prec+1));
+ str_free(fstr);
+ str_cat(str," : ");
+ str_scat(str,fstr=walk(1,level,ops[node+3].ival,&numarg,prec+1));
+ str_free(fstr);
+ break;
+ case OCPAREN:
+ str = str_new(0);
+ str_set(str,"(");
+ str_scat(str,fstr=walk(useval != 0,level,ops[node+1].ival,&numarg,P_MIN));
+ str_free(fstr);
+ numeric |= numarg;
+ str_cat(str,")");
+ break;
+ case OCANDAND:
+ prec = P_ANDAND;
+ str = walk(1,level,ops[node+1].ival,&numarg,prec);
+ numeric = 1;
+ str_cat(str," && ");
+ str_scat(str,fstr=walk(1,level,ops[node+2].ival,&numarg,prec+1));
+ str_free(fstr);
+ str_scat(str,fstr=walk(1,level,ops[node+3].ival,&numarg,prec+1));
+ str_free(fstr);
+ break;
+ case OCOROR:
+ prec = P_OROR;
+ str = walk(1,level,ops[node+1].ival,&numarg,prec);
+ numeric = 1;
+ str_cat(str," || ");
+ str_scat(str,fstr=walk(1,level,ops[node+2].ival,&numarg,prec+1));
+ str_free(fstr);
+ str_scat(str,fstr=walk(1,level,ops[node+3].ival,&numarg,prec+1));
+ str_free(fstr);
+ break;
+ case OCNOT:
+ prec = P_UNARY;
+ str = str_new(0);
+ str_set(str,"!");
+ str_scat(str,fstr=walk(1,level,ops[node+1].ival,&numarg,prec));
+ str_free(fstr);
+ numeric = 1;
+ break;
+ case ORELOP:
+ prec = P_REL;
+ str = walk(1,level,ops[node+2].ival,&numarg,prec+1);
+ numeric |= numarg;
+ tmpstr = walk(0,level,ops[node+1].ival,&numarg,P_MIN);
+ tmp2str = walk(1,level,ops[node+3].ival,&numarg,prec+1);
+ numeric |= numarg;
+ if (!numeric ||
+ (!numarg && (*tmp2str->str_ptr == '"' || *tmp2str->str_ptr == '\''))) {
+ t = tmpstr->str_ptr;
+ if (strEQ(t,"=="))
+ str_set(tmpstr,"eq");
+ else if (strEQ(t,"!="))
+ str_set(tmpstr,"ne");
+ else if (strEQ(t,"<"))
+ str_set(tmpstr,"lt");
+ else if (strEQ(t,"<="))
+ str_set(tmpstr,"le");
+ else if (strEQ(t,">"))
+ str_set(tmpstr,"gt");
+ else if (strEQ(t,">="))
+ str_set(tmpstr,"ge");
+ if (!index(tmpstr->str_ptr,'\'') && !index(tmpstr->str_ptr,'"') &&
+ !index(tmp2str->str_ptr,'\'') && !index(tmp2str->str_ptr,'"') )
+ numeric |= 2;
+ }
+ if (numeric & 2) {
+ if (numeric & 1) /* numeric is very good guess */
+ str_cat(str," ");
+ else
+ str_cat(str,"\377");
+ numeric = 1;
+ }
+ else
+ str_cat(str," ");
+ str_scat(str,tmpstr);
+ str_free(tmpstr);
+ str_cat(str," ");
+ str_scat(str,tmp2str);
+ str_free(tmp2str);
+ numeric = 1;
+ break;
+ case ORPAREN:
+ str = str_new(0);
+ str_set(str,"(");
+ str_scat(str,fstr=walk(useval != 0,level,ops[node+1].ival,&numarg,P_MIN));
+ str_free(fstr);
+ numeric |= numarg;
+ str_cat(str,")");
+ break;
+ case OMATCHOP:
+ prec = P_MATCH;
+ str = walk(1,level,ops[node+2].ival,&numarg,prec+1);
+ str_cat(str," ");
+ tmpstr = walk(0,level,ops[node+1].ival,&numarg,P_MIN);
+ if (strEQ(tmpstr->str_ptr,"~"))
+ str_cat(str,"=~");
+ else {
+ str_scat(str,tmpstr);
+ str_free(tmpstr);
+ }
+ str_cat(str," ");
+ str_scat(str,fstr=walk(1,level,ops[node+3].ival,&numarg,prec+1));
+ str_free(fstr);
+ numeric = 1;
+ break;
+ case OMPAREN:
+ str = str_new(0);
+ str_set(str,"(");
+ str_scat(str,
+ fstr=walk(useval != 0,level,ops[node+1].ival,&numarg,P_MIN));
+ str_free(fstr);
+ numeric |= numarg;
+ str_cat(str,")");
+ break;
+ case OCONCAT:
+ prec = P_ADD;
+ type = ops[ops[node+1].ival].ival & 255;
+ str = walk(1,level,ops[node+1].ival,&numarg,prec+(type != OCONCAT));
+ str_cat(str," . ");
+ type = ops[ops[node+2].ival].ival & 255;
+ str_scat(str,
+ fstr=walk(1,level,ops[node+2].ival,&numarg,prec+(type != OCONCAT)));
+ str_free(fstr);
+ break;
+ case OASSIGN:
+ prec = P_ASSIGN;
+ str = walk(0,level,ops[node+2].ival,&numarg,prec+1);
+ str_cat(str," ");
+ tmpstr = walk(0,level,ops[node+1].ival,&numarg,P_MIN);
+ str_scat(str,tmpstr);
+ if (str_len(tmpstr) > 1)
+ numeric = 1;
+ str_free(tmpstr);
+ str_cat(str," ");
+ str_scat(str,fstr=walk(1,level,ops[node+3].ival,&numarg,prec));
+ str_free(fstr);
+ numeric |= numarg;
+ if (strEQ(str->str_ptr,"$/ = ''"))
+ str_set(str, "$/ = \"\\n\\n\"");
+ break;
+ case OADD:
+ prec = P_ADD;
+ str = walk(1,level,ops[node+1].ival,&numarg,prec);
+ str_cat(str," + ");
+ str_scat(str,fstr=walk(1,level,ops[node+2].ival,&numarg,prec+1));
+ str_free(fstr);
+ numeric = 1;
+ break;
+ case OSUBTRACT:
+ prec = P_ADD;
+ str = walk(1,level,ops[node+1].ival,&numarg,prec);
+ str_cat(str," - ");
+ str_scat(str,fstr=walk(1,level,ops[node+2].ival,&numarg,prec+1));
+ str_free(fstr);
+ numeric = 1;
+ break;
+ case OMULT:
+ prec = P_MUL;
+ str = walk(1,level,ops[node+1].ival,&numarg,prec);
+ str_cat(str," * ");
+ str_scat(str,fstr=walk(1,level,ops[node+2].ival,&numarg,prec+1));
+ str_free(fstr);
+ numeric = 1;
+ break;
+ case ODIV:
+ prec = P_MUL;
+ str = walk(1,level,ops[node+1].ival,&numarg,prec);
+ str_cat(str," / ");
+ str_scat(str,fstr=walk(1,level,ops[node+2].ival,&numarg,prec+1));
+ str_free(fstr);
+ numeric = 1;
+ break;
+ case OPOW:
+ prec = P_POW;
+ str = walk(1,level,ops[node+1].ival,&numarg,prec+1);
+ str_cat(str," ** ");
+ str_scat(str,fstr=walk(1,level,ops[node+2].ival,&numarg,prec));
+ str_free(fstr);
+ numeric = 1;
+ break;
+ case OMOD:
+ prec = P_MUL;
+ str = walk(1,level,ops[node+1].ival,&numarg,prec);
+ str_cat(str," % ");
+ str_scat(str,fstr=walk(1,level,ops[node+2].ival,&numarg,prec+1));
+ str_free(fstr);
+ numeric = 1;
+ break;
+ case OPOSTINCR:
+ prec = P_AUTO;
+ str = walk(1,level,ops[node+1].ival,&numarg,prec+1);
+ str_cat(str,"++");
+ numeric = 1;
+ break;
+ case OPOSTDECR:
+ prec = P_AUTO;
+ str = walk(1,level,ops[node+1].ival,&numarg,prec+1);
+ str_cat(str,"--");
+ numeric = 1;
+ break;
+ case OPREINCR:
+ prec = P_AUTO;
+ str = str_new(0);
+ str_set(str,"++");
+ str_scat(str,fstr=walk(1,level,ops[node+1].ival,&numarg,prec+1));
+ str_free(fstr);
+ numeric = 1;
+ break;
+ case OPREDECR:
+ prec = P_AUTO;
+ str = str_new(0);
+ str_set(str,"--");
+ str_scat(str,fstr=walk(1,level,ops[node+1].ival,&numarg,prec+1));
+ str_free(fstr);
+ numeric = 1;
+ break;
+ case OUMINUS:
+ prec = P_UNARY;
+ str = str_new(0);
+ str_set(str,"-");
+ str_scat(str,fstr=walk(1,level,ops[node+1].ival,&numarg,prec));
+ str_free(fstr);
+ numeric = 1;
+ break;
+ case OUPLUS:
+ numeric = 1;
+ goto def;
+ case OPAREN:
+ str = str_new(0);
+ str_set(str,"(");
+ str_scat(str,
+ fstr=walk(useval != 0,level,ops[node+1].ival,&numarg,P_MIN));
+ str_free(fstr);
+ str_cat(str,")");
+ numeric |= numarg;
+ break;
+ case OGETLINE:
+ str = str_new(0);
+ if (useval)
+ str_cat(str,"(");
+ if (len > 0) {
+ str_scat(str,fstr=walk(1,level,ops[node+1].ival,&numarg,P_MIN));
+ if (!*fstr->str_ptr) {
+ str_cat(str,"$_");
+ len = 2; /* a legal fiction */
+ }
+ str_free(fstr);
+ }
+ else
+ str_cat(str,"$_");
+ if (len > 1) {
+ tmpstr=walk(1,level,ops[node+3].ival,&numarg,P_MIN);
+ fstr=walk(1,level,ops[node+2].ival,&numarg,P_MIN);
+ if (!do_fancy_opens) {
+ t = tmpstr->str_ptr;
+ if (*t == '"' || *t == '\'')
+ t = cpytill(tokenbuf,t+1,*t);
+ else
+ fatal("Internal error: OGETLINE %s", t);
+ d = savestr(t);
+ s = savestr(tokenbuf);
+ for (t = tokenbuf; *t; t++) {
+ *t &= 127;
+ if (islower(*t))
+ *t = toupper(*t);
+ if (!isalpha(*t) && !isdigit(*t))
+ *t = '_';
+ }
+ if (!index(tokenbuf,'_'))
+ strcpy(t,"_FH");
+ tmp3str = hfetch(symtab,tokenbuf);
+ if (!tmp3str) {
+ do_opens = TRUE;
+ str_cat(opens,"open(");
+ str_cat(opens,tokenbuf);
+ str_cat(opens,", ");
+ d[1] = '\0';
+ str_cat(opens,d);
+ str_cat(opens,tmpstr->str_ptr+1);
+ opens->str_cur--;
+ if (*fstr->str_ptr == '|')
+ str_cat(opens,"|");
+ str_cat(opens,d);
+ if (*fstr->str_ptr == '|')
+ str_cat(opens,") || die 'Cannot pipe from \"");
+ else
+ str_cat(opens,") || die 'Cannot open file \"");
+ if (*d == '"')
+ str_cat(opens,"'.\"");
+ str_cat(opens,s);
+ if (*d == '"')
+ str_cat(opens,"\".'");
+ str_cat(opens,"\".';\n");
+ hstore(symtab,tokenbuf,str_make("x"));
+ }
+ safefree(s);
+ safefree(d);
+ str_set(tmpstr,"'");
+ str_cat(tmpstr,tokenbuf);
+ str_cat(tmpstr,"'");
+ }
+ if (*fstr->str_ptr == '|')
+ str_cat(tmpstr,", '|'");
+ str_free(fstr);
+ }
+ else
+ tmpstr = str_make("");
+ sprintf(tokenbuf," = &Getline%d(%s)",len,tmpstr->str_ptr);
+ str_cat(str,tokenbuf);
+ str_free(tmpstr);
+ if (useval)
+ str_cat(str,",$getline_ok)");
+ saw_getline |= 1 << len;
+ break;
+ case OSPRINTF:
+ str = str_new(0);
+ str_set(str,"sprintf(");
+ str_scat(str,fstr=walk(1,level,ops[node+1].ival,&numarg,P_MIN));
+ str_free(fstr);
+ str_cat(str,")");
+ break;
+ case OSUBSTR:
+ str = str_new(0);
+ str_set(str,"substr(");
+ str_scat(str,fstr=walk(1,level,ops[node+1].ival,&numarg,P_COMMA+1));
+ str_free(fstr);
+ str_cat(str,", ");
+ str_scat(str,fstr=walk(1,level,ops[node+2].ival,&numarg,P_COMMA+1));
+ str_free(fstr);
+ str_cat(str,", ");
+ if (len == 3) {
+ str_scat(str,fstr=walk(1,level,ops[node+3].ival,&numarg,P_COMMA+1));
+ str_free(fstr);
+ }
+ else
+ str_cat(str,"999999");
+ str_cat(str,")");
+ break;
+ case OSTRING:
+ str = str_new(0);
+ str_set(str,ops[node+1].cval);
+ break;
+ case OSPLIT:
+ str = str_new(0);
+ limit = ", 9999)";
+ numeric = 1;
+ tmpstr = walk(1,level,ops[node+2].ival,&numarg,P_MIN);
+ if (useval)
+ str_set(str,"(@");
+ else
+ str_set(str,"@");
+ str_scat(str,tmpstr);
+ str_cat(str," = split(");
+ if (len == 3) {
+ fstr = walk(1,level,ops[node+3].ival,&numarg,P_COMMA+1);
+ if (str_len(fstr) == 3 && *fstr->str_ptr == '\'') {
+ i = fstr->str_ptr[1] & 127;
+ if (index("*+?.[]()|^$\\",i))
+ sprintf(tokenbuf,"/\\%c/",i);
+ else if (i == ' ')
+ sprintf(tokenbuf,"' '");
+ else
+ sprintf(tokenbuf,"/%c/",i);
+ str_cat(str,tokenbuf);
+ }
+ else
+ str_scat(str,fstr);
+ str_free(fstr);
+ }
+ else if (const_FS) {
+ sprintf(tokenbuf,"/[%c\\n]/",const_FS);
+ str_cat(str,tokenbuf);
+ }
+ else if (saw_FS)
+ str_cat(str,"$FS");
+ else {
+ str_cat(str,"' '");
+ limit = ")";
+ }
+ str_cat(str,", ");
+ str_scat(str,fstr=walk(1,level,ops[node+1].ival,&numarg,P_COMMA+1));
+ str_free(fstr);
+ str_cat(str,limit);
+ if (useval) {
+ str_cat(str,")");
+ }
+ str_free(tmpstr);
+ break;
+ case OINDEX:
+ str = str_new(0);
+ str_set(str,"index(");
+ str_scat(str,fstr=walk(1,level,ops[node+1].ival,&numarg,P_COMMA+1));
+ str_free(fstr);
+ str_cat(str,", ");
+ str_scat(str,fstr=walk(1,level,ops[node+2].ival,&numarg,P_COMMA+1));
+ str_free(fstr);
+ str_cat(str,")");
+ numeric = 1;
+ break;
+ case OMATCH:
+ str = str_new(0);
+ prec = P_ANDAND;
+ str_scat(str,fstr=walk(1,level,ops[node+1].ival,&numarg,P_MATCH+1));
+ str_free(fstr);
+ str_cat(str," =~ ");
+ str_scat(str,fstr=walk(1,level,ops[node+2].ival,&numarg,P_MATCH+1));
+ str_free(fstr);
+ str_cat(str," && ($RLENGTH = length($&), $RSTART = length($`)+1)");
+ numeric = 1;
+ break;
+ case OUSERDEF:
+ str = str_new(0);
+ subretnum = FALSE;
+ fstr=walk(1,level-1,ops[node+2].ival,&numarg,P_MIN);
+ curargs = str_new(0);
+ str_sset(curargs,fstr);
+ str_cat(curargs,",");
+ tmp2str=walk(1,level,ops[node+5].ival,&numarg,P_MIN);
+ str_free(curargs);
+ curargs = Nullstr;
+ level--;
+ subretnum |= numarg;
+ s = Nullch;
+ t = tmp2str->str_ptr;
+ while (t = instr(t,"return "))
+ s = t++;
+ if (s) {
+ i = 0;
+ for (t = s+7; *t; t++) {
+ if (*t == ';' || *t == '}')
+ i++;
+ }
+ if (i == 1) {
+ strcpy(s,s+7);
+ tmp2str->str_cur -= 7;
+ }
+ }
+ str_set(str,"\n");
+ tab(str,level);
+ str_cat(str,"sub ");
+ str_scat(str,tmpstr=walk(1,level,ops[node+1].ival,&numarg,P_MIN));
+ str_cat(str," {\n");
+ tab(str,++level);
+ if (fstr->str_cur) {
+ str_cat(str,"local(");
+ str_scat(str,fstr);
+ str_cat(str,") = @_;");
+ }
+ str_free(fstr);
+ str_scat(str,fstr=walk(1,level,ops[node+3].ival,&numarg,P_MIN));
+ str_free(fstr);
+ fixtab(str,level);
+ str_scat(str,fstr=walk(1,level,ops[node+4].ival,&numarg,P_MIN));
+ str_free(fstr);
+ fixtab(str,level);
+ str_scat(str,tmp2str);
+ str_free(tmp2str);
+ fixtab(str,--level);
+ str_cat(str,"}\n");
+ tab(str,level);
+ str_scat(subs,str);
+ str_set(str,"");
+ str_cat(tmpstr,"(");
+ tmp2str = str_new(0);
+ if (subretnum)
+ str_set(tmp2str,"1");
+ hstore(symtab,tmpstr->str_ptr,tmp2str);
+ str_free(tmpstr);
+ level++;
+ break;
+ case ORETURN:
+ str = str_new(0);
+ if (len > 0) {
+ str_cat(str,"return ");
+ str_scat(str,fstr=walk(1,level,ops[node+1].ival,&numarg,P_UNI+1));
+ str_free(fstr);
+ if (numarg)
+ subretnum = TRUE;
+ }
+ else
+ str_cat(str,"return");
+ break;
+ case OUSERFUN:
+ str = str_new(0);
+ str_set(str,"&");
+ str_scat(str,fstr=walk(1,level,ops[node+1].ival,&numarg,P_MIN));
+ str_free(fstr);
+ str_cat(str,"(");
+ tmpstr = hfetch(symtab,str->str_ptr+3);
+ if (tmpstr && tmpstr->str_ptr)
+ numeric |= atoi(tmpstr->str_ptr);
+ str_scat(str,fstr=walk(1,level,ops[node+2].ival,&numarg,P_MIN));
+ str_free(fstr);
+ str_cat(str,")");
+ break;
+ case OGSUB:
+ case OSUB:
+ if (type == OGSUB)
+ s = "g";
+ else
+ s = "";
+ str = str_new(0);
+ tmpstr = str_new(0);
+ i = 0;
+ if (len == 3) {
+ tmpstr = walk(1,level,ops[node+3].ival,&numarg,P_MATCH+1);
+ if (strNE(tmpstr->str_ptr,"$_")) {
+ str_cat(tmpstr, " =~ s");
+ i++;
+ }
+ else
+ str_set(tmpstr, "s");
+ }
+ else
+ str_set(tmpstr, "s");
+ type = ops[ops[node+2].ival].ival;
+ len = type >> 8;
+ type &= 255;
+ tmp3str = str_new(0);
+ if (type == OSTR) {
+ tmp2str=walk(1,level,ops[ops[node+2].ival+1].ival,&numarg,P_MIN);
+ for (t = tmp2str->str_ptr, d=tokenbuf; *t; d++,t++) {
+ if (*t == '&')
+ *d++ = '$' + 128;
+ else if (*t == '$')
+ *d++ = '\\' + 128;
+ *d = *t + 128;
+ }
+ *d = '\0';
+ str_set(tmp2str,tokenbuf);
+ }
+ else {
+ tmp2str=walk(1,level,ops[node+2].ival,&numarg,P_MIN);
+ str_set(tmp3str,"($s_ = '\"'.(");
+ str_scat(tmp3str,tmp2str);
+ str_cat(tmp3str,").'\"') =~ s/&/\\$&/g, ");
+ str_set(tmp2str,"eval $s_");
+ s = (*s == 'g' ? "ge" : "e");
+ i++;
+ }
+ type = ops[ops[node+1].ival].ival;
+ len = type >> 8;
+ type &= 255;
+ fstr=walk(1,level,ops[node+1].ival,&numarg,P_MIN);
+ if (type == OREGEX) {
+ if (useval && i)
+ str_cat(str,"(");
+ str_scat(str,tmp3str);
+ str_scat(str,tmpstr);
+ str_scat(str,fstr);
+ str_scat(str,tmp2str);
+ str_cat(str,"/");
+ str_cat(str,s);
+ }
+ else if ((type == OFLD && !split_to_array) || (type == OVAR && len == 1)) {
+ if (useval && i)
+ str_cat(str,"(");
+ str_scat(str,tmp3str);
+ str_scat(str,tmpstr);
+ str_cat(str,"/");
+ str_scat(str,fstr);
+ str_cat(str,"/");
+ str_scat(str,tmp2str);
+ str_cat(str,"/");
+ str_cat(str,s);
+ }
+ else {
+ i++;
+ if (useval)
+ str_cat(str,"(");
+ str_cat(str,"$s = ");
+ str_scat(str,fstr);
+ str_cat(str,", ");
+ str_scat(str,tmp3str);
+ str_scat(str,tmpstr);
+ str_cat(str,"/$s/");
+ str_scat(str,tmp2str);
+ str_cat(str,"/");
+ str_cat(str,s);
+ }
+ if (useval && i)
+ str_cat(str,")");
+ str_free(fstr);
+ str_free(tmpstr);
+ str_free(tmp2str);
+ str_free(tmp3str);
+ numeric = 1;
+ break;
+ case ONUM:
+ str = walk(1,level,ops[node+1].ival,&numarg,P_MIN);
+ numeric = 1;
+ break;
+ case OSTR:
+ tmpstr = walk(1,level,ops[node+1].ival,&numarg,P_MIN);
+ s = "'";
+ for (t = tmpstr->str_ptr, d=tokenbuf; *t; d++,t++) {
+ if (*t == '\'')
+ s = "\"";
+ else if (*t == '\\') {
+ s = "\"";
+ *d++ = *t++ + 128;
+ switch (*t) {
+ case '\\': case '"': case 'n': case 't': case '$':
+ break;
+ default: /* hide this from perl */
+ *d++ = '\\' + 128;
+ }
+ }
+ *d = *t + 128;
+ }
+ *d = '\0';
+ str = str_new(0);
+ str_set(str,s);
+ str_cat(str,tokenbuf);
+ str_free(tmpstr);
+ str_cat(str,s);
+ break;
+ case ODEFINED:
+ prec = P_UNI;
+ str = str_new(0);
+ str_set(str,"defined $");
+ goto addvar;
+ case ODELETE:
+ str = str_new(0);
+ str_set(str,"delete $");
+ goto addvar;
+ case OSTAR:
+ str = str_new(0);
+ str_set(str,"*");
+ goto addvar;
+ case OVAR:
+ str = str_new(0);
+ str_set(str,"$");
+ addvar:
+ str_scat(str,tmpstr=walk(1,level,ops[node+1].ival,&numarg,P_MIN));
+ if (len == 1) {
+ tmp2str = hfetch(symtab,tmpstr->str_ptr);
+ if (tmp2str && atoi(tmp2str->str_ptr))
+ numeric = 2;
+ if (strEQ(str->str_ptr,"$FNR")) {
+ numeric = 1;
+ saw_FNR++;
+ str_set(str,"($.-$FNRbase)");
+ }
+ else if (strEQ(str->str_ptr,"$NR")) {
+ numeric = 1;
+ str_set(str,"$.");
+ }
+ else if (strEQ(str->str_ptr,"$NF")) {
+ numeric = 1;
+ str_set(str,"$#Fld");
+ }
+ else if (strEQ(str->str_ptr,"$0"))
+ str_set(str,"$_");
+ else if (strEQ(str->str_ptr,"$ARGC"))
+ str_set(str,"($#ARGV+1)");
+ }
+ else {
+#ifdef NOTDEF
+ if (curargs) {
+ sprintf(tokenbuf,"$%s,",tmpstr->str_ptr);
+ ??? if (instr(curargs->str_ptr,tokenbuf))
+ str_cat(str,"\377"); /* can't translate yet */
+ }
+#endif
+ str_cat(tmpstr,"[]");
+ tmp2str = hfetch(symtab,tmpstr->str_ptr);
+ if (tmp2str && atoi(tmp2str->str_ptr))
+ str_cat(str,"[");
+ else
+ str_cat(str,"{");
+ str_scat(str,fstr=walk(1,level,ops[node+2].ival,&numarg,P_MIN));
+ str_free(fstr);
+ if (strEQ(str->str_ptr,"$ARGV[0")) {
+ str_set(str,"$ARGV0");
+ saw_argv0++;
+ }
+ else {
+ if (tmp2str && atoi(tmp2str->str_ptr))
+ strcpy(tokenbuf,"]");
+ else
+ strcpy(tokenbuf,"}");
+ *tokenbuf += 128;
+ str_cat(str,tokenbuf);
+ }
+ }
+ str_free(tmpstr);
+ break;
+ case OFLD:
+ str = str_new(0);
+ if (split_to_array) {
+ str_set(str,"$Fld");
+ str_cat(str,"[");
+ str_scat(str,fstr=walk(1,level,ops[node+1].ival,&numarg,P_MIN));
+ str_free(fstr);
+ str_cat(str,"]");
+ }
+ else {
+ i = atoi(walk(1,level,ops[node+1].ival,&numarg,P_MIN)->str_ptr);
+ if (i <= arymax)
+ sprintf(tokenbuf,"$%s",nameary[i]);
+ else
+ sprintf(tokenbuf,"$Fld%d",i);
+ str_set(str,tokenbuf);
+ }
+ break;
+ case OVFLD:
+ str = str_new(0);
+ str_set(str,"$Fld[");
+ i = ops[node+1].ival;
+ if ((ops[i].ival & 255) == OPAREN)
+ i = ops[i+1].ival;
+ tmpstr=walk(1,level,i,&numarg,P_MIN);
+ str_scat(str,tmpstr);
+ str_free(tmpstr);
+ str_cat(str,"]");
+ break;
+ case OJUNK:
+ goto def;
+ case OSNEWLINE:
+ str = str_new(2);
+ str_set(str,";\n");
+ tab(str,level);
+ break;
+ case ONEWLINE:
+ str = str_new(1);
+ str_set(str,"\n");
+ tab(str,level);
+ break;
+ case OSCOMMENT:
+ str = str_new(0);
+ str_set(str,";");
+ tmpstr = walk(0,level,ops[node+1].ival,&numarg,P_MIN);
+ for (s = tmpstr->str_ptr; *s && *s != '\n'; s++)
+ *s += 128;
+ str_scat(str,tmpstr);
+ str_free(tmpstr);
+ tab(str,level);
+ break;
+ case OCOMMENT:
+ str = str_new(0);
+ tmpstr = walk(0,level,ops[node+1].ival,&numarg,P_MIN);
+ for (s = tmpstr->str_ptr; *s && *s != '\n'; s++)
+ *s += 128;
+ str_scat(str,tmpstr);
+ str_free(tmpstr);
+ tab(str,level);
+ break;
+ case OCOMMA:
+ prec = P_COMMA;
+ str = walk(1,level,ops[node+1].ival,&numarg,prec);
+ str_cat(str,", ");
+ str_scat(str,fstr=walk(1,level,ops[node+2].ival,&numarg,P_MIN));
+ str_free(fstr);
+ str_scat(str,fstr=walk(1,level,ops[node+3].ival,&numarg,prec+1));
+ str_free(fstr);
+ break;
+ case OSEMICOLON:
+ str = str_new(1);
+ str_set(str,";\n");
+ tab(str,level);
+ break;
+ case OSTATES:
+ str = walk(0,level,ops[node+1].ival,&numarg,P_MIN);
+ str_scat(str,fstr=walk(0,level,ops[node+2].ival,&numarg,P_MIN));
+ str_free(fstr);
+ break;
+ case OSTATE:
+ str = str_new(0);
+ if (len >= 1) {
+ str_scat(str,fstr=walk(0,level,ops[node+1].ival,&numarg,P_MIN));
+ str_free(fstr);
+ if (len >= 2) {
+ tmpstr = walk(0,level,ops[node+2].ival,&numarg,P_MIN);
+ if (*tmpstr->str_ptr == ';') {
+ addsemi(str);
+ str_cat(str,tmpstr->str_ptr+1);
+ }
+ str_free(tmpstr);
+ }
+ }
+ break;
+ case OCLOSE:
+ str = str_make("close(");
+ tmpstr = walk(1,level,ops[node+1].ival,&numarg,P_MIN);
+ if (!do_fancy_opens) {
+ t = tmpstr->str_ptr;
+ if (*t == '"' || *t == '\'')
+ t = cpytill(tokenbuf,t+1,*t);
+ else
+ fatal("Internal error: OCLOSE %s",t);
+ s = savestr(tokenbuf);
+ for (t = tokenbuf; *t; t++) {
+ *t &= 127;
+ if (islower(*t))
+ *t = toupper(*t);
+ if (!isalpha(*t) && !isdigit(*t))
+ *t = '_';
+ }
+ if (!index(tokenbuf,'_'))
+ strcpy(t,"_FH");
+ str_free(tmpstr);
+ safefree(s);
+ str_set(str,"close ");
+ str_cat(str,tokenbuf);
+ }
+ else {
+ sprintf(tokenbuf,"delete $opened{%s} && close(%s)",
+ tmpstr->str_ptr, tmpstr->str_ptr);
+ str_free(tmpstr);
+ str_set(str,tokenbuf);
+ }
+ break;
+ case OPRINTF:
+ case OPRINT:
+ lparen = ""; /* set to parens if necessary */
+ rparen = "";
+ str = str_new(0);
+ if (len == 3) { /* output redirection */
+ tmpstr = walk(1,level,ops[node+3].ival,&numarg,P_MIN);
+ tmp2str = walk(1,level,ops[node+2].ival,&numarg,P_MIN);
+ if (!do_fancy_opens) {
+ t = tmpstr->str_ptr;
+ if (*t == '"' || *t == '\'')
+ t = cpytill(tokenbuf,t+1,*t);
+ else
+ fatal("Internal error: OPRINT");
+ d = savestr(t);
+ s = savestr(tokenbuf);
+ for (t = tokenbuf; *t; t++) {
+ *t &= 127;
+ if (islower(*t))
+ *t = toupper(*t);
+ if (!isalpha(*t) && !isdigit(*t))
+ *t = '_';
+ }
+ if (!index(tokenbuf,'_'))
+ strcpy(t,"_FH");
+ tmp3str = hfetch(symtab,tokenbuf);
+ if (!tmp3str) {
+ str_cat(opens,"open(");
+ str_cat(opens,tokenbuf);
+ str_cat(opens,", ");
+ d[1] = '\0';
+ str_cat(opens,d);
+ str_scat(opens,tmp2str);
+ str_cat(opens,tmpstr->str_ptr+1);
+ if (*tmp2str->str_ptr == '|')
+ str_cat(opens,") || die 'Cannot pipe to \"");
+ else
+ str_cat(opens,") || die 'Cannot create file \"");
+ if (*d == '"')
+ str_cat(opens,"'.\"");
+ str_cat(opens,s);
+ if (*d == '"')
+ str_cat(opens,"\".'");
+ str_cat(opens,"\".';\n");
+ hstore(symtab,tokenbuf,str_make("x"));
+ }
+ str_free(tmpstr);
+ str_free(tmp2str);
+ safefree(s);
+ safefree(d);
+ }
+ else {
+ sprintf(tokenbuf,"&Pick('%s', %s) &&\n",
+ tmp2str->str_ptr, tmpstr->str_ptr);
+ str_cat(str,tokenbuf);
+ tab(str,level+1);
+ strcpy(tokenbuf,"$fh");
+ str_free(tmpstr);
+ str_free(tmp2str);
+ lparen = "(";
+ rparen = ")";
+ }
+ }
+ else
+ strcpy(tokenbuf,"");
+ str_cat(str,lparen); /* may be null */
+ if (type == OPRINTF)
+ str_cat(str,"printf");
+ else
+ str_cat(str,"print");
+ saw_fh = 0;
+ if (len == 3 || do_fancy_opens) {
+ if (*tokenbuf) {
+ str_cat(str," ");
+ saw_fh = 1;
+ }
+ str_cat(str,tokenbuf);
+ }
+ tmpstr = walk(1+(type==OPRINT),level,ops[node+1].ival,&numarg,P_MIN);
+ if (!*tmpstr->str_ptr && lval_field) {
+ t = saw_OFS ? "$," : "' '";
+ if (split_to_array) {
+ sprintf(tokenbuf,"join(%s,@Fld)",t);
+ str_cat(tmpstr,tokenbuf);
+ }
+ else {
+ for (i = 1; i < maxfld; i++) {
+ if (i <= arymax)
+ sprintf(tokenbuf,"$%s, ",nameary[i]);
+ else
+ sprintf(tokenbuf,"$Fld%d, ",i);
+ str_cat(tmpstr,tokenbuf);
+ }
+ if (maxfld <= arymax)
+ sprintf(tokenbuf,"$%s",nameary[maxfld]);
+ else
+ sprintf(tokenbuf,"$Fld%d",maxfld);
+ str_cat(tmpstr,tokenbuf);
+ }
+ }
+ if (*tmpstr->str_ptr) {
+ str_cat(str," ");
+ if (!saw_fh && *tmpstr->str_ptr == '(') {
+ str_cat(str,"(");
+ str_scat(str,tmpstr);
+ str_cat(str,")");
+ }
+ else
+ str_scat(str,tmpstr);
+ }
+ else {
+ str_cat(str," $_");
+ }
+ str_cat(str,rparen); /* may be null */
+ str_free(tmpstr);
+ break;
+ case ORAND:
+ str = str_make("rand(1)");
+ break;
+ case OSRAND:
+ str = str_make("srand(");
+ goto maybe0;
+ case OATAN2:
+ str = str_make("atan2(");
+ goto maybe0;
+ case OSIN:
+ str = str_make("sin(");
+ goto maybe0;
+ case OCOS:
+ str = str_make("cos(");
+ goto maybe0;
+ case OSYSTEM:
+ str = str_make("system(");
+ goto maybe0;
+ case OLENGTH:
+ str = str_make("length(");
+ goto maybe0;
+ case OLOG:
+ str = str_make("log(");
+ goto maybe0;
+ case OEXP:
+ str = str_make("exp(");
+ goto maybe0;
+ case OSQRT:
+ str = str_make("sqrt(");
+ goto maybe0;
+ case OINT:
+ str = str_make("int(");
+ maybe0:
+ numeric = 1;
+ if (len > 0)
+ tmpstr = walk(1,level,ops[node+1].ival,&numarg,P_MIN);
+ else
+ tmpstr = str_new(0);;
+ if (!tmpstr->str_ptr || !*tmpstr->str_ptr) {
+ if (lval_field) {
+ t = saw_OFS ? "$," : "' '";
+ if (split_to_array) {
+ sprintf(tokenbuf,"join(%s,@Fld)",t);
+ str_cat(tmpstr,tokenbuf);
+ }
+ else {
+ sprintf(tokenbuf,"join(%s, ",t);
+ str_cat(tmpstr,tokenbuf);
+ for (i = 1; i < maxfld; i++) {
+ if (i <= arymax)
+ sprintf(tokenbuf,"$%s,",nameary[i]);
+ else
+ sprintf(tokenbuf,"$Fld%d,",i);
+ str_cat(tmpstr,tokenbuf);
+ }
+ if (maxfld <= arymax)
+ sprintf(tokenbuf,"$%s)",nameary[maxfld]);
+ else
+ sprintf(tokenbuf,"$Fld%d)",maxfld);
+ str_cat(tmpstr,tokenbuf);
+ }
+ }
+ else
+ str_cat(tmpstr,"$_");
+ }
+ if (strEQ(tmpstr->str_ptr,"$_")) {
+ if (type == OLENGTH && !do_chop) {
+ str = str_make("(length(");
+ str_cat(tmpstr,") - 1");
+ }
+ }
+ str_scat(str,tmpstr);
+ str_free(tmpstr);
+ str_cat(str,")");
+ break;
+ case OBREAK:
+ str = str_new(0);
+ str_set(str,"last");
+ break;
+ case ONEXT:
+ str = str_new(0);
+ str_set(str,"next line");
+ break;
+ case OEXIT:
+ str = str_new(0);
+ if (realexit) {
+ prec = P_UNI;
+ str_set(str,"exit");
+ if (len == 1) {
+ str_cat(str," ");
+ exitval = TRUE;
+ str_scat(str,
+ fstr=walk(1,level,ops[node+1].ival,&numarg,prec+1));
+ str_free(fstr);
+ }
+ }
+ else {
+ if (len == 1) {
+ str_set(str,"$ExitValue = ");
+ exitval = TRUE;
+ str_scat(str,
+ fstr=walk(1,level,ops[node+1].ival,&numarg,P_ASSIGN));
+ str_free(fstr);
+ str_cat(str,"; ");
+ }
+ str_cat(str,"last line");
+ }
+ break;
+ case OCONTINUE:
+ str = str_new(0);
+ str_set(str,"next");
+ break;
+ case OREDIR:
+ goto def;
+ case OIF:
+ str = str_new(0);
+ str_set(str,"if (");
+ str_scat(str,fstr=walk(1,level,ops[node+1].ival,&numarg,P_MIN));
+ str_free(fstr);
+ str_cat(str,") ");
+ str_scat(str,fstr=walk(0,level,ops[node+2].ival,&numarg,P_MIN));
+ str_free(fstr);
+ if (len == 3) {
+ i = ops[node+3].ival;
+ if (i) {
+ if ((ops[i].ival & 255) == OBLOCK) {
+ i = ops[i+1].ival;
+ if (i) {
+ if ((ops[i].ival & 255) != OIF)
+ i = 0;
+ }
+ }
+ else
+ i = 0;
+ }
+ if (i) {
+ str_cat(str,"els");
+ str_scat(str,fstr=walk(0,level,i,&numarg,P_MIN));
+ str_free(fstr);
+ }
+ else {
+ str_cat(str,"else ");
+ str_scat(str,fstr=walk(0,level,ops[node+3].ival,&numarg,P_MIN));
+ str_free(fstr);
+ }
+ }
+ break;
+ case OWHILE:
+ str = str_new(0);
+ str_set(str,"while (");
+ str_scat(str,fstr=walk(1,level,ops[node+1].ival,&numarg,P_MIN));
+ str_free(fstr);
+ str_cat(str,") ");
+ str_scat(str,fstr=walk(0,level,ops[node+2].ival,&numarg,P_MIN));
+ str_free(fstr);
+ break;
+ case ODO:
+ str = str_new(0);
+ str_set(str,"do ");
+ str_scat(str,fstr=walk(1,level,ops[node+1].ival,&numarg,P_MIN));
+ str_free(fstr);
+ if (str->str_ptr[str->str_cur - 1] == '\n')
+ --str->str_cur;;
+ str_cat(str," while (");
+ str_scat(str,fstr=walk(0,level,ops[node+2].ival,&numarg,P_MIN));
+ str_free(fstr);
+ str_cat(str,");");
+ break;
+ case OFOR:
+ str = str_new(0);
+ str_set(str,"for (");
+ str_scat(str,tmpstr=walk(1,level,ops[node+1].ival,&numarg,P_MIN));
+ i = numarg;
+ if (i) {
+ t = s = tmpstr->str_ptr;
+ while (isalpha(*t) || isdigit(*t) || *t == '$' || *t == '_')
+ t++;
+ i = t - s;
+ if (i < 2)
+ i = 0;
+ }
+ str_cat(str,"; ");
+ fstr=walk(1,level,ops[node+2].ival,&numarg,P_MIN);
+ if (i && (t = index(fstr->str_ptr,0377))) {
+ if (strnEQ(fstr->str_ptr,s,i))
+ *t = ' ';
+ }
+ str_scat(str,fstr);
+ str_free(fstr);
+ str_free(tmpstr);
+ str_cat(str,"; ");
+ str_scat(str,fstr=walk(1,level,ops[node+3].ival,&numarg,P_MIN));
+ str_free(fstr);
+ str_cat(str,") ");
+ str_scat(str,fstr=walk(0,level,ops[node+4].ival,&numarg,P_MIN));
+ str_free(fstr);
+ break;
+ case OFORIN:
+ tmpstr = walk(0,level,ops[node+1].ival,&numarg,P_MIN);
+ d = index(tmpstr->str_ptr,'$');
+ if (!d)
+ fatal("Illegal for loop: %s",tmpstr->str_ptr);
+ s = index(d,'{');
+ if (!s)
+ s = index(d,'[');
+ if (!s)
+ fatal("Illegal for loop: %s",d);
+ *s++ = '\0';
+ for (t = s; i = *t; t++) {
+ i &= 127;
+ if (i == '}' || i == ']')
+ break;
+ }
+ if (*t)
+ *t = '\0';
+ str = str_new(0);
+ str_set(str,d+1);
+ str_cat(str,"[]");
+ tmp2str = hfetch(symtab,str->str_ptr);
+ if (tmp2str && atoi(tmp2str->str_ptr)) {
+ sprintf(tokenbuf,
+ "foreach %s ($[ .. $#%s) ",
+ s,
+ d+1);
+ }
+ else {
+ sprintf(tokenbuf,
+ "foreach %s (keys %%%s) ",
+ s,
+ d+1);
+ }
+ str_set(str,tokenbuf);
+ str_scat(str,fstr=walk(0,level,ops[node+2].ival,&numarg,P_MIN));
+ str_free(fstr);
+ str_free(tmpstr);
+ break;
+ case OBLOCK:
+ str = str_new(0);
+ str_set(str,"{");
+ if (len >= 2 && ops[node+2].ival) {
+ str_scat(str,fstr=walk(0,level,ops[node+2].ival,&numarg,P_MIN));
+ str_free(fstr);
+ }
+ fixtab(str,++level);
+ str_scat(str,fstr=walk(0,level,ops[node+1].ival,&numarg,P_MIN));
+ str_free(fstr);
+ addsemi(str);
+ fixtab(str,--level);
+ str_cat(str,"}\n");
+ tab(str,level);
+ if (len >= 3) {
+ str_scat(str,fstr=walk(0,level,ops[node+3].ival,&numarg,P_MIN));
+ str_free(fstr);
+ }
+ break;
+ default:
+ def:
+ if (len) {
+ if (len > 5)
+ fatal("Garbage length in walk");
+ str = walk(0,level,ops[node+1].ival,&numarg,P_MIN);
+ for (i = 2; i<= len; i++) {
+ str_scat(str,fstr=walk(0,level,ops[node+i].ival,&numarg,P_MIN));
+ str_free(fstr);
+ }
+ }
+ else {
+ str = Nullstr;
+ }
+ break;
+ }
+ if (!str)
+ str = str_new(0);
+
+ if (useval && prec < minprec) { /* need parens? */
+ fstr = str_new(str->str_cur+2);
+ str_nset(fstr,"(",1);
+ str_scat(fstr,str);
+ str_ncat(fstr,")",1);
+ str_free(str);
+ str = fstr;
+ }
+
+ *numericptr = numeric;
+#ifdef DEBUGGING
+ if (debug & 4) {
+ printf("%3d %5d %15s %d %4d ",level,node,opname[type],len,str->str_cur);
+ for (t = str->str_ptr; *t && t - str->str_ptr < 40; t++)
+ if (*t == '\n')
+ printf("\\n");
+ else if (*t == '\t')
+ printf("\\t");
+ else
+ putchar(*t);
+ putchar('\n');
+ }
+#endif
+ return str;
+}
+
+tab(str,lvl)
+register STR *str;
+register int lvl;
+{
+ while (lvl > 1) {
+ str_cat(str,"\t");
+ lvl -= 2;
+ }
+ if (lvl)
+ str_cat(str," ");
+}
+
+fixtab(str,lvl)
+register STR *str;
+register int lvl;
+{
+ register char *s;
+
+ /* strip trailing white space */
+
+ s = str->str_ptr+str->str_cur - 1;
+ while (s >= str->str_ptr && (*s == ' ' || *s == '\t' || *s == '\n'))
+ s--;
+ s[1] = '\0';
+ str->str_cur = s + 1 - str->str_ptr;
+ if (s >= str->str_ptr && *s != '\n')
+ str_cat(str,"\n");
+
+ tab(str,lvl);
+}
+
+addsemi(str)
+register STR *str;
+{
+ register char *s;
+
+ s = str->str_ptr+str->str_cur - 1;
+ while (s >= str->str_ptr && (*s == ' ' || *s == '\t' || *s == '\n'))
+ s--;
+ if (s >= str->str_ptr && *s != ';' && *s != '}')
+ str_cat(str,";");
+}
+
+emit_split(str,level)
+register STR *str;
+int level;
+{
+ register int i;
+
+ if (split_to_array)
+ str_cat(str,"@Fld");
+ else {
+ str_cat(str,"(");
+ for (i = 1; i < maxfld; i++) {
+ if (i <= arymax)
+ sprintf(tokenbuf,"$%s,",nameary[i]);
+ else
+ sprintf(tokenbuf,"$Fld%d,",i);
+ str_cat(str,tokenbuf);
+ }
+ if (maxfld <= arymax)
+ sprintf(tokenbuf,"$%s)",nameary[maxfld]);
+ else
+ sprintf(tokenbuf,"$Fld%d)",maxfld);
+ str_cat(str,tokenbuf);
+ }
+ if (const_FS) {
+ sprintf(tokenbuf," = split(/[%c\\n]/, $_, 9999);\n",const_FS);
+ str_cat(str,tokenbuf);
+ }
+ else if (saw_FS)
+ str_cat(str," = split($FS, $_, 9999);\n");
+ else
+ str_cat(str," = split(' ', $_, 9999);\n");
+ tab(str,level);
+}
+
+prewalk(numit,level,node,numericptr)
+int numit;
+int level;
+register int node;
+int *numericptr;
+{
+ register int len;
+ register int type;
+ register int i;
+ char *t;
+ char *d, *s;
+ int numarg;
+ int numeric = FALSE;
+ STR *tmpstr;
+ STR *tmp2str;
+
+ if (!node) {
+ *numericptr = 0;
+ return 0;
+ }
+ type = ops[node].ival;
+ len = type >> 8;
+ type &= 255;
+ switch (type) {
+ case OPROG:
+ prewalk(0,level,ops[node+1].ival,&numarg);
+ if (ops[node+2].ival) {
+ prewalk(0,level,ops[node+2].ival,&numarg);
+ }
+ ++level;
+ prewalk(0,level,ops[node+3].ival,&numarg);
+ --level;
+ if (ops[node+3].ival) {
+ prewalk(0,level,ops[node+4].ival,&numarg);
+ }
+ break;
+ case OHUNKS:
+ prewalk(0,level,ops[node+1].ival,&numarg);
+ prewalk(0,level,ops[node+2].ival,&numarg);
+ if (len == 3) {
+ prewalk(0,level,ops[node+3].ival,&numarg);
+ }
+ break;
+ case ORANGE:
+ prewalk(1,level,ops[node+1].ival,&numarg);
+ prewalk(1,level,ops[node+2].ival,&numarg);
+ break;
+ case OPAT:
+ goto def;
+ case OREGEX:
+ prewalk(0,level,ops[node+1].ival,&numarg);
+ break;
+ case OHUNK:
+ if (len == 1) {
+ prewalk(0,level,ops[node+1].ival,&numarg);
+ }
+ else {
+ i = prewalk(0,level,ops[node+1].ival,&numarg);
+ if (i) {
+ ++level;
+ prewalk(0,level,ops[node+2].ival,&numarg);
+ --level;
+ }
+ else {
+ prewalk(0,level,ops[node+2].ival,&numarg);
+ }
+ }
+ break;
+ case OPPAREN:
+ prewalk(0,level,ops[node+1].ival,&numarg);
+ break;
+ case OPANDAND:
+ prewalk(0,level,ops[node+1].ival,&numarg);
+ prewalk(0,level,ops[node+2].ival,&numarg);
+ break;
+ case OPOROR:
+ prewalk(0,level,ops[node+1].ival,&numarg);
+ prewalk(0,level,ops[node+2].ival,&numarg);
+ break;
+ case OPNOT:
+ prewalk(0,level,ops[node+1].ival,&numarg);
+ break;
+ case OCPAREN:
+ prewalk(0,level,ops[node+1].ival,&numarg);
+ numeric |= numarg;
+ break;
+ case OCANDAND:
+ prewalk(0,level,ops[node+1].ival,&numarg);
+ numeric = 1;
+ prewalk(0,level,ops[node+2].ival,&numarg);
+ break;
+ case OCOROR:
+ prewalk(0,level,ops[node+1].ival,&numarg);
+ numeric = 1;
+ prewalk(0,level,ops[node+2].ival,&numarg);
+ break;
+ case OCNOT:
+ prewalk(0,level,ops[node+1].ival,&numarg);
+ numeric = 1;
+ break;
+ case ORELOP:
+ prewalk(0,level,ops[node+2].ival,&numarg);
+ numeric |= numarg;
+ prewalk(0,level,ops[node+1].ival,&numarg);
+ prewalk(0,level,ops[node+3].ival,&numarg);
+ numeric |= numarg;
+ numeric = 1;
+ break;
+ case ORPAREN:
+ prewalk(0,level,ops[node+1].ival,&numarg);
+ numeric |= numarg;
+ break;
+ case OMATCHOP:
+ prewalk(0,level,ops[node+2].ival,&numarg);
+ prewalk(0,level,ops[node+1].ival,&numarg);
+ prewalk(0,level,ops[node+3].ival,&numarg);
+ numeric = 1;
+ break;
+ case OMPAREN:
+ prewalk(0,level,ops[node+1].ival,&numarg);
+ numeric |= numarg;
+ break;
+ case OCONCAT:
+ prewalk(0,level,ops[node+1].ival,&numarg);
+ prewalk(0,level,ops[node+2].ival,&numarg);
+ break;
+ case OASSIGN:
+ prewalk(0,level,ops[node+2].ival,&numarg);
+ prewalk(0,level,ops[node+1].ival,&numarg);
+ prewalk(0,level,ops[node+3].ival,&numarg);
+ if (numarg || strlen(ops[ops[node+1].ival+1].cval) > 1) {
+ numericize(ops[node+2].ival);
+ if (!numarg)
+ numericize(ops[node+3].ival);
+ }
+ numeric |= numarg;
+ break;
+ case OADD:
+ prewalk(1,level,ops[node+1].ival,&numarg);
+ prewalk(1,level,ops[node+2].ival,&numarg);
+ numeric = 1;
+ break;
+ case OSUBTRACT:
+ prewalk(1,level,ops[node+1].ival,&numarg);
+ prewalk(1,level,ops[node+2].ival,&numarg);
+ numeric = 1;
+ break;
+ case OMULT:
+ prewalk(1,level,ops[node+1].ival,&numarg);
+ prewalk(1,level,ops[node+2].ival,&numarg);
+ numeric = 1;
+ break;
+ case ODIV:
+ prewalk(1,level,ops[node+1].ival,&numarg);
+ prewalk(1,level,ops[node+2].ival,&numarg);
+ numeric = 1;
+ break;
+ case OPOW:
+ prewalk(1,level,ops[node+1].ival,&numarg);
+ prewalk(1,level,ops[node+2].ival,&numarg);
+ numeric = 1;
+ break;
+ case OMOD:
+ prewalk(1,level,ops[node+1].ival,&numarg);
+ prewalk(1,level,ops[node+2].ival,&numarg);
+ numeric = 1;
+ break;
+ case OPOSTINCR:
+ prewalk(1,level,ops[node+1].ival,&numarg);
+ numeric = 1;
+ break;
+ case OPOSTDECR:
+ prewalk(1,level,ops[node+1].ival,&numarg);
+ numeric = 1;
+ break;
+ case OPREINCR:
+ prewalk(1,level,ops[node+1].ival,&numarg);
+ numeric = 1;
+ break;
+ case OPREDECR:
+ prewalk(1,level,ops[node+1].ival,&numarg);
+ numeric = 1;
+ break;
+ case OUMINUS:
+ prewalk(1,level,ops[node+1].ival,&numarg);
+ numeric = 1;
+ break;
+ case OUPLUS:
+ prewalk(1,level,ops[node+1].ival,&numarg);
+ numeric = 1;
+ break;
+ case OPAREN:
+ prewalk(0,level,ops[node+1].ival,&numarg);
+ numeric |= numarg;
+ break;
+ case OGETLINE:
+ break;
+ case OSPRINTF:
+ prewalk(0,level,ops[node+1].ival,&numarg);
+ break;
+ case OSUBSTR:
+ prewalk(0,level,ops[node+1].ival,&numarg);
+ prewalk(1,level,ops[node+2].ival,&numarg);
+ if (len == 3) {
+ prewalk(1,level,ops[node+3].ival,&numarg);
+ }
+ break;
+ case OSTRING:
+ break;
+ case OSPLIT:
+ numeric = 1;
+ prewalk(0,level,ops[node+2].ival,&numarg);
+ if (len == 3)
+ prewalk(0,level,ops[node+3].ival,&numarg);
+ prewalk(0,level,ops[node+1].ival,&numarg);
+ break;
+ case OINDEX:
+ prewalk(0,level,ops[node+1].ival,&numarg);
+ prewalk(0,level,ops[node+2].ival,&numarg);
+ numeric = 1;
+ break;
+ case OMATCH:
+ prewalk(0,level,ops[node+1].ival,&numarg);
+ prewalk(0,level,ops[node+2].ival,&numarg);
+ numeric = 1;
+ break;
+ case OUSERDEF:
+ subretnum = FALSE;
+ --level;
+ tmpstr = walk(0,level,ops[node+1].ival,&numarg,P_MIN);
+ ++level;
+ prewalk(0,level,ops[node+2].ival,&numarg);
+ prewalk(0,level,ops[node+4].ival,&numarg);
+ prewalk(0,level,ops[node+5].ival,&numarg);
+ --level;
+ str_cat(tmpstr,"(");
+ tmp2str = str_new(0);
+ if (subretnum || numarg)
+ str_set(tmp2str,"1");
+ hstore(symtab,tmpstr->str_ptr,tmp2str);
+ str_free(tmpstr);
+ level++;
+ break;
+ case ORETURN:
+ if (len > 0) {
+ prewalk(0,level,ops[node+1].ival,&numarg);
+ if (numarg)
+ subretnum = TRUE;
+ }
+ break;
+ case OUSERFUN:
+ tmp2str = str_new(0);
+ str_scat(tmp2str,tmpstr=walk(1,level,ops[node+1].ival,&numarg,P_MIN));
+ fixrargs(tmpstr->str_ptr,ops[node+2].ival,0);
+ str_free(tmpstr);
+ str_cat(tmp2str,"(");
+ tmpstr = hfetch(symtab,tmp2str->str_ptr);
+ if (tmpstr && tmpstr->str_ptr)
+ numeric |= atoi(tmpstr->str_ptr);
+ prewalk(0,level,ops[node+2].ival,&numarg);
+ str_free(tmp2str);
+ break;
+ case OGSUB:
+ case OSUB:
+ if (len >= 3)
+ prewalk(0,level,ops[node+3].ival,&numarg);
+ prewalk(0,level,ops[ops[node+2].ival+1].ival,&numarg);
+ prewalk(0,level,ops[node+1].ival,&numarg);
+ numeric = 1;
+ break;
+ case ONUM:
+ prewalk(0,level,ops[node+1].ival,&numarg);
+ numeric = 1;
+ break;
+ case OSTR:
+ prewalk(0,level,ops[node+1].ival,&numarg);
+ break;
+ case ODEFINED:
+ case ODELETE:
+ case OSTAR:
+ case OVAR:
+ prewalk(0,level,ops[node+1].ival,&numarg);
+ if (len == 1) {
+ if (numit)
+ numericize(node);
+ }
+ else {
+ prewalk(0,level,ops[node+2].ival,&numarg);
+ }
+ break;
+ case OFLD:
+ prewalk(0,level,ops[node+1].ival,&numarg);
+ break;
+ case OVFLD:
+ i = ops[node+1].ival;
+ prewalk(0,level,i,&numarg);
+ break;
+ case OJUNK:
+ goto def;
+ case OSNEWLINE:
+ break;
+ case ONEWLINE:
+ break;
+ case OSCOMMENT:
+ break;
+ case OCOMMENT:
+ break;
+ case OCOMMA:
+ prewalk(0,level,ops[node+1].ival,&numarg);
+ prewalk(0,level,ops[node+2].ival,&numarg);
+ prewalk(0,level,ops[node+3].ival,&numarg);
+ break;
+ case OSEMICOLON:
+ break;
+ case OSTATES:
+ prewalk(0,level,ops[node+1].ival,&numarg);
+ prewalk(0,level,ops[node+2].ival,&numarg);
+ break;
+ case OSTATE:
+ if (len >= 1) {
+ prewalk(0,level,ops[node+1].ival,&numarg);
+ if (len >= 2) {
+ prewalk(0,level,ops[node+2].ival,&numarg);
+ }
+ }
+ break;
+ case OCLOSE:
+ prewalk(0,level,ops[node+1].ival,&numarg);
+ break;
+ case OPRINTF:
+ case OPRINT:
+ if (len == 3) { /* output redirection */
+ prewalk(0,level,ops[node+3].ival,&numarg);
+ prewalk(0,level,ops[node+2].ival,&numarg);
+ }
+ prewalk(0+(type==OPRINT),level,ops[node+1].ival,&numarg);
+ break;
+ case ORAND:
+ break;
+ case OSRAND:
+ goto maybe0;
+ case OATAN2:
+ goto maybe0;
+ case OSIN:
+ goto maybe0;
+ case OCOS:
+ goto maybe0;
+ case OSYSTEM:
+ goto maybe0;
+ case OLENGTH:
+ goto maybe0;
+ case OLOG:
+ goto maybe0;
+ case OEXP:
+ goto maybe0;
+ case OSQRT:
+ goto maybe0;
+ case OINT:
+ maybe0:
+ numeric = 1;
+ if (len > 0)
+ prewalk(type != OLENGTH && type != OSYSTEM,
+ level,ops[node+1].ival,&numarg);
+ break;
+ case OBREAK:
+ break;
+ case ONEXT:
+ break;
+ case OEXIT:
+ if (len == 1) {
+ prewalk(1,level,ops[node+1].ival,&numarg);
+ }
+ break;
+ case OCONTINUE:
+ break;
+ case OREDIR:
+ goto def;
+ case OIF:
+ prewalk(0,level,ops[node+1].ival,&numarg);
+ prewalk(0,level,ops[node+2].ival,&numarg);
+ if (len == 3) {
+ prewalk(0,level,ops[node+3].ival,&numarg);
+ }
+ break;
+ case OWHILE:
+ prewalk(0,level,ops[node+1].ival,&numarg);
+ prewalk(0,level,ops[node+2].ival,&numarg);
+ break;
+ case OFOR:
+ prewalk(0,level,ops[node+1].ival,&numarg);
+ prewalk(0,level,ops[node+2].ival,&numarg);
+ prewalk(0,level,ops[node+3].ival,&numarg);
+ prewalk(0,level,ops[node+4].ival,&numarg);
+ break;
+ case OFORIN:
+ prewalk(0,level,ops[node+2].ival,&numarg);
+ prewalk(0,level,ops[node+1].ival,&numarg);
+ break;
+ case OBLOCK:
+ if (len == 2) {
+ prewalk(0,level,ops[node+2].ival,&numarg);
+ }
+ ++level;
+ prewalk(0,level,ops[node+1].ival,&numarg);
+ --level;
+ break;
+ default:
+ def:
+ if (len) {
+ if (len > 5)
+ fatal("Garbage length in prewalk");
+ prewalk(0,level,ops[node+1].ival,&numarg);
+ for (i = 2; i<= len; i++) {
+ prewalk(0,level,ops[node+i].ival,&numarg);
+ }
+ }
+ break;
+ }
+ *numericptr = numeric;
+ return 1;
+}
+
+numericize(node)
+register int node;
+{
+ register int len;
+ register int type;
+ register int i;
+ STR *tmpstr;
+ STR *tmp2str;
+ int numarg;
+
+ type = ops[node].ival;
+ len = type >> 8;
+ type &= 255;
+ if (type == OVAR && len == 1) {
+ tmpstr=walk(0,0,ops[node+1].ival,&numarg,P_MIN);
+ tmp2str = str_make("1");
+ hstore(symtab,tmpstr->str_ptr,tmp2str);
+ }
+}
diff --git a/gnu/usr.bin/ptx/Makefile b/gnu/usr.bin/ptx/Makefile
index b778f7a..b06f5b4 100644
--- a/gnu/usr.bin/ptx/Makefile
+++ b/gnu/usr.bin/ptx/Makefile
@@ -1,7 +1,12 @@
PROG= ptx
-SRCS= argmatch.c diacrit.c error.c getopt.c getopt1.c ptx.c regex.c xmalloc.c
+SRCS= argmatch.c diacrit.c error.c getopt.c getopt1.c ptx.c xmalloc.c
-MAN1= NOMAN
+LDADD+= -lgnuregex
+DPADD+= ${LIBGNUREGEX}
CFLAGS+= -DHAVE_CONFIG_H -DDEFAULT_IGNORE_FILE=\"/usr/share/dict/eign\"
+NOMAN=
+
+SUBDIR+= doc
+
.include <bsd.prog.mk>
diff --git a/gnu/usr.bin/ptx/bumpalloc.h b/gnu/usr.bin/ptx/bumpalloc.h
index bbf901f..6fe8952 100644
--- a/gnu/usr.bin/ptx/bumpalloc.h
+++ b/gnu/usr.bin/ptx/bumpalloc.h
@@ -27,12 +27,12 @@
/* Routines `xmalloc' and `xrealloc' are called to do the actual memory
management. This implies that the program will abort with an `Virtual
Memory exhausted!' error if any problem arise.
-
+
To work correctly, at least EXPONENT and TYPE should always be the
same for all uses of this macro for any given TABLE. A secure way to
achieve this is to never use this macro directly, but use it to define
other macros, which would then be TABLE-specific.
-
+
The first time through, COUNT is usually zero. Note that COUNT is not
updated by this macro, but it should be update elsewhere, later. This
is convenient, because it allows TABLE[COUNT] to refer to the new
diff --git a/gnu/usr.bin/ptx/doc/Makefile b/gnu/usr.bin/ptx/doc/Makefile
new file mode 100644
index 0000000..ff514e2
--- /dev/null
+++ b/gnu/usr.bin/ptx/doc/Makefile
@@ -0,0 +1,3 @@
+INFO = ptx
+
+.include <bsd.info.mk>
diff --git a/gnu/usr.bin/ptx/doc/ptx.texinfo b/gnu/usr.bin/ptx/doc/ptx.texinfo
new file mode 100644
index 0000000..e690c55
--- /dev/null
+++ b/gnu/usr.bin/ptx/doc/ptx.texinfo
@@ -0,0 +1,554 @@
+\input texinfo @c -*-texinfo-*-
+@c %**start of header
+@setfilename ptx.info
+@settitle GNU @code{ptx} reference manual
+@finalout
+@c %**end of header
+
+@ifinfo
+This file documents the @code{ptx} command, which has the purpose of
+generated permuted indices for group of files.
+
+Copyright (C) 1990, 1991, 1993 by the Free Software Foundation, Inc.
+
+Permission is granted to make and distribute verbatim copies of
+this manual provided the copyright notice and this permission notice
+are preserved on all copies.
+
+@ignore
+Permission is granted to process this file through TeX and print the
+results, provided the printed document carries copying permission
+notice identical to this one except for the removal of this paragraph
+(this paragraph not being relevant to the printed manual).
+
+@end ignore
+Permission is granted to copy and distribute modified versions of this
+manual under the conditions for verbatim copying, provided that the entire
+resulting derived work is distributed under the terms of a permission
+notice identical to this one.
+
+Permission is granted to copy and distribute translations of this manual
+into another language, under the above conditions for modified versions,
+except that this permission notice may be stated in a translation approved
+by the Foundation.
+@end ifinfo
+
+@titlepage
+@title ptx
+@subtitle The GNU permuted indexer
+@subtitle Edition 0.3, for ptx version 0.3
+@subtitle November 1993
+@author by Francois Pinard
+
+@page
+@vskip 0pt plus 1filll
+Copyright @copyright{} 1990, 1991, 1993 Free Software Foundation, Inc.
+
+Permission is granted to make and distribute verbatim copies of
+this manual provided the copyright notice and this permission notice
+are preserved on all copies.
+
+Permission is granted to copy and distribute modified versions of this
+manual under the conditions for verbatim copying, provided that the entire
+resulting derived work is distributed under the terms of a permission
+notice identical to this one.
+
+Permission is granted to copy and distribute translations of this manual
+into another language, under the above conditions for modified versions,
+except that this permission notice may be stated in a translation approved
+by the Foundation.
+@end titlepage
+
+@node Top, Invoking ptx, (dir), (dir)
+@chapter Introduction
+
+This is the 0.3 beta release of @code{ptx}, the GNU version of a
+permuted index generator. This software has the main goal of providing
+a replacement for the traditional @code{ptx} as found on System V
+machines, able to handle small files quickly, while providing a platform
+for more development.
+
+This version reimplements and extends traditional @code{ptx}. Among
+other things, it can produce a readable @dfn{KWIC} (keywords in their
+context) without the need of @code{nroff}, there is also an option to
+produce @TeX{} compatible output. This version does not handle huge
+input files, that is, those files which do not fit in memory all at
+once.
+
+@emph{Please note} that an overall renaming of all options is
+foreseeable. In fact, GNU ptx specifications are not frozen yet.
+
+@menu
+* Invoking ptx:: How to use this program
+* Compatibility:: The GNU extensions to @code{ptx}
+
+ --- The Detailed Node Listing ---
+
+How to use this program
+
+* General options:: Options which affect general program behaviour.
+* Charset selection:: Underlying character set considerations.
+* Input processing:: Input fields, contexts, and keyword selection.
+* Output formatting:: Types of output format, and sizing the fields.
+@end menu
+
+@node Invoking ptx, Compatibility, Top, Top
+@chapter How to use this program
+
+This tool reads a text file and essentially produces a permuted index, with
+each keyword in its context. The calling sketch is one of:
+
+@example
+ptx [@var{option} @dots{}] [@var{file} @dots{}]
+@end example
+
+or:
+
+@example
+ptx -G [@var{option} @dots{}] [@var{input} [@var{output}]]
+@end example
+
+The @samp{-G} (or its equivalent: @samp{--traditional}) option disables
+all GNU extensions and revert to traditional mode, thus introducing some
+limitations, and changes several of the program's default option values.
+When @samp{-G} is not specified, GNU extensions are always enabled. GNU
+extensions to @code{ptx} are documented wherever appropriate in this
+document. See @xref{Compatibility} for an explicit list of them.
+
+Individual options are explained later in this document.
+
+When GNU extensions are enabled, there may be zero, one or several
+@var{file} after the options. If there is no @var{file}, the program
+reads the standard input. If there is one or several @var{file}, they
+give the name of input files which are all read in turn, as if all the
+input files were concatenated. However, there is a full contextual
+break between each file and, when automatic referencing is requested,
+file names and line numbers refer to individual text input files. In
+all cases, the program produces the permuted index onto the standard
+output.
+
+When GNU extensions are @emph{not} enabled, that is, when the program
+operates in traditional mode, there may be zero, one or two parameters
+besides the options. If there is no parameters, the program reads the
+standard input and produces the permuted index onto the standard output.
+If there is only one parameter, it names the text @var{input} to be read
+instead of the standard input. If two parameters are given, they give
+respectively the name of the @var{input} file to read and the name of
+the @var{output} file to produce. @emph{Be very careful} to note that,
+in this case, the contents of file given by the second parameter is
+destroyed. This behaviour is dictated only by System V @code{ptx}
+compatibility, because GNU Standards discourage output parameters not
+introduced by an option.
+
+Note that for @emph{any} file named as the value of an option or as an
+input text file, a single dash @kbd{-} may be used, in which case
+standard input is assumed. However, it would not make sense to use this
+convention more than once per program invocation.
+
+@menu
+* General options:: Options which affect general program behaviour.
+* Charset selection:: Underlying character set considerations.
+* Input processing:: Input fields, contexts, and keyword selection.
+* Output formatting:: Types of output format, and sizing the fields.
+@end menu
+
+@node General options, Charset selection, Invoking ptx, Invoking ptx
+@section General options
+
+@table @code
+
+@item -C
+@itemx --copyright
+Prints a short note about the Copyright and copying conditions, then
+exit without further processing.
+
+@item -G
+@itemx --traditional
+As already explained, this option disables all GNU extensions to
+@code{ptx} and switch to traditional mode.
+
+@item --help
+Prints a short help on standard output, then exit without further
+processing.
+
+@item --version
+Prints the program verison on standard output, then exit without further
+processing.
+
+@end table
+
+@node Charset selection, Input processing, General options, Invoking ptx
+@section Charset selection
+
+As it is setup now, the program assumes that the input file is coded
+using 8-bit ISO 8859-1 code, also known as Latin-1 character set,
+@emph{unless} if it is compiled for MS-DOS, in which case it uses the
+character set of the IBM-PC. (GNU @code{ptx} is not known to work on
+smaller MS-DOS machines anymore.) Compared to 7-bit ASCII, the set of
+characters which are letters is then different, this fact alters the
+behaviour of regular expression matching. Thus, the default regular
+expression for a keyword allows foreign or diacriticized letters.
+Keyword sorting, however, is still crude; it obeys the underlying
+character set ordering quite blindly.
+
+@table @code
+
+@item -f
+@itemx --ignore-case
+Fold lower case letters to upper case for sorting.
+
+@end table
+
+@node Input processing, Output formatting, Charset selection, Invoking ptx
+@section Word selection
+
+@table @code
+
+@item -b @var{file}
+@item --break-file=@var{file}
+
+This option is an alternative way to option @code{-W} for describing
+which characters make up words. This option introduces the name of a
+file which contains a list of characters which can@emph{not} be part of
+one word, this file is called the @dfn{Break file}. Any character which
+is not part of the Break file is a word constituent. If both options
+@code{-b} and @code{-W} are specified, then @code{-W} has precedence and
+@code{-b} is ignored.
+
+When GNU extensions are enabled, the only way to avoid newline as a
+break character is to write all the break characters in the file with no
+newline at all, not even at the end of the file. When GNU extensions
+are disabled, spaces, tabs and newlines are always considered as break
+characters even if not included in the Break file.
+
+@item -i @var{file}
+@itemx --ignore-file=@var{file}
+
+The file associated with this option contains a list of words which will
+never be taken as keywords in concordance output. It is called the
+@dfn{Ignore file}. The file contains exactly one word in each line; the
+end of line separation of words is not subject to the value of the
+@code{-S} option.
+
+There is a default Ignore file used by @code{ptx} when this option is
+not specified, usually found in @file{/usr/local/lib/eign} if this has
+not been changed at installation time. If you want to deactivate the
+default Ignore file, specify @code{/dev/null} instead.
+
+@item -o @var{file}
+@itemx --only-file=@var{file}
+
+The file associated with this option contains a list of words which will
+be retained in concordance output, any word not mentioned in this file
+is ignored. The file is called the @dfn{Only file}. The file contains
+exactly one word in each line; the end of line separation of words is
+not subject to the value of the @code{-S} option.
+
+There is no default for the Only file. In the case there are both an
+Only file and an Ignore file, a word will be subject to be a keyword
+only if it is given in the Only file and not given in the Ignore file.
+
+@item -r
+@itemx --references
+
+On each input line, the leading sequence of non white characters will be
+taken to be a reference that has the purpose of identifying this input
+line on the produced permuted index. See @xref{Output formatting} for
+more information about reference production. Using this option change
+the default value for option @code{-S}.
+
+Using this option, the program does not try very hard to remove
+references from contexts in output, but it succeeds in doing so
+@emph{when} the context ends exactly at the newline. If option
+@code{-r} is used with @code{-S} default value, or when GNU extensions
+are disabled, this condition is always met and references are completely
+excluded from the output contexts.
+
+@item -S @var{regexp}
+@itemx --sentence-regexp=@var{regexp}
+
+This option selects which regular expression will describe the end of a
+line or the end of a sentence. In fact, there is other distinction
+between end of lines or end of sentences than the effect of this regular
+expression, and input line boundaries have no special significance
+outside this option. By default, when GNU extensions are enabled and if
+@code{-r} option is not used, end of sentences are used. In this
+case, the precise @var{regex} is imported from GNU emacs:
+
+@example
+[.?!][]\"')@}]*\\($\\|\t\\| \\)[ \t\n]*
+@end example
+
+Whenever GNU extensions are disabled or if @code{-r} option is used, end
+of lines are used; in this case, the default @var{regexp} is just:
+
+@example
+\n
+@end example
+
+Using an empty REGEXP is equivalent to completely disabling end of line or end
+of sentence recognition. In this case, the whole file is considered to
+be a single big line or sentence. The user might want to disallow all
+truncation flag generation as well, through option @code{-F ""}.
+@xref{Regexps, , Syntax of Regular Expressions, emacs, The GNU Emacs
+Manual}.
+
+When the keywords happen to be near the beginning of the input line or
+sentence, this often creates an unused area at the beginning of the
+output context line; when the keywords happen to be near the end of the
+input line or sentence, this often creates an unused area at the end of
+the output context line. The program tries to fill those unused areas
+by wrapping around context in them; the tail of the input line or
+sentence is used to fill the unused area on the left of the output line;
+the head of the input line or sentence is used to fill the unused area
+on the right of the output line.
+
+As a matter of convenience to the user, many usual backslashed escape
+sequences, as found in the C language, are recognized and converted to
+the corresponding characters by @code{ptx} itself.
+
+@item -W @var{regexp}
+@itemx --word-regexp=@var{regexp}
+
+This option selects which regular expression will describe each keyword.
+By default, if GNU extensions are enabled, a word is a sequence of
+letters; the @var{regexp} used is @code{\w+}. When GNU extensions are
+disabled, a word is by default anything which ends with a space, a tab
+or a newline; the @var{regexp} used is @code{[^ \t\n]+}.
+
+An empty REGEXP is equivalent to not using this option, letting the
+default dive in. @xref{Regexps, , Syntax of Regular Expressions, emacs,
+The GNU Emacs Manual}.
+
+As a matter of convenience to the user, many usual backslashed escape
+sequences, as found in the C language, are recognized and converted to
+the corresponding characters by @code{ptx} itself.
+
+@end table
+
+@node Output formatting, , Input processing, Invoking ptx
+@section Output formatting
+
+Output format is mainly controlled by @code{-O} and @code{-T} options,
+described in the table below. When neither @code{-O} nor @code{-T} is
+selected, and if GNU extensions are enabled, the program choose an
+output format suited for a dumb terminal. Each keyword occurrence is
+output to the center of one line, surrounded by its left and right
+contexts. Each field is properly justified, so the concordance output
+could readily be observed. As a special feature, if automatic
+references are selected by option @code{-A} and are output before the
+left context, that is, if option @code{-R} is @emph{not} selected, then
+a colon is added after the reference; this nicely interfaces with GNU
+Emacs @code{next-error} processing. In this default output format, each
+white space character, like newline and tab, is merely changed to
+exactly one space, with no special attempt to compress consecutive
+spaces. This might change in the future. Except for those white space
+characters, every other character of the underlying set of 256
+characters is transmitted verbatim.
+
+Output format is further controlled by the following options.
+
+@table @code
+
+@item -g @var{number}
+@itemx --gap-size=@var{number}
+
+Select the size of the minimum white gap between the fields on the output
+line.
+
+@item -w @var{number}
+@itemx --width=@var{number}
+
+Select the output maximum width of each final line. If references are
+used, they are included or excluded from the output maximum width
+depending on the value of option @code{-R}. If this option is not
+selected, that is, when references are output before the left context,
+the output maximum width takes into account the maximum length of all
+references. If this options is selected, that is, when references are
+output after the right context, the output maximum width does not take
+into account the space taken by references, nor the gap that precedes
+them.
+
+@item -A
+@itemx --auto-reference
+
+Select automatic references. Each input line will have an automatic
+reference made up of the file name and the line ordinal, with a single
+colon between them. However, the file name will be empty when standard
+input is being read. If both @code{-A} and @code{-r} are selected, then
+the input reference is still read and skipped, but the automatic
+reference is used at output time, overriding the input reference.
+
+@item -R
+@itemx --right-side-refs
+
+In default output format, when option @code{-R} is not used, any
+reference produced by the effect of options @code{-r} or @code{-A} are
+given to the far right of output lines, after the right context. In
+default output format, when option @code{-R} is specified, references
+are rather given to the beginning of each output line, before the left
+context. For any other output format, option @code{-R} is almost
+ignored, except for the fact that the width of references is @emph{not}
+taken into account in total output width given by @code{-w} whenever
+@code{-R} is selected.
+
+This option is automatically selected whenever GNU extensions are
+disabled.
+
+@item -F @var{string}
+@itemx --flac-truncation=@var{string}
+
+This option will request that any truncation in the output be reported
+using the string @var{string}. Most output fields theoretically extend
+towards the beginning or the end of the current line, or current
+sentence, as selected with option @code{-S}. But there is a maximum
+allowed output line width, changeable through option @code{-w}, which is
+further divided into space for various output fields. When a field has
+to be truncated because cannot extend until the beginning or the end of
+the current line to fit in the, then a truncation occurs. By default,
+the string used is a single slash, as in @code{-F /}.
+
+@var{string} may have more than one character, as in @code{-F ...}.
+Also, in the particular case @var{string} is empty (@code{-F ""}),
+truncation flagging is disabled, and no truncation marks are appended in
+this case.
+
+As a matter of convenience to the user, many usual backslashed escape
+sequences, as found in the C language, are recognized and converted to
+the corresponding characters by @code{ptx} itself.
+
+@item -M @var{string}
+@itemx --macro-name=@var{string}
+
+Select another @var{string} to be used instead of @samp{xx}, while
+generating output suitable for @code{nroff}, @code{troff} or @TeX{}.
+
+@item -O
+@itemx --format=roff
+
+Choose an output format suitable for @code{nroff} or @code{troff}
+processing. Each output line will look like:
+
+@example
+.xx "@var{tail}" "@var{before}" "@var{keyword_and_after}" "@var{head}" "@var{ref}"
+@end example
+
+so it will be possible to write an @samp{.xx} roff macro to take care of
+the output typesetting. This is the default output format when GNU
+extensions are disabled. Option @samp{-M} might be used to change
+@samp{xx} to another macro name.
+
+In this output format, each non-graphical character, like newline and
+tab, is merely changed to exactly one space, with no special attempt to
+compress consecutive spaces. Each quote character: @kbd{"} is doubled
+so it will be correctly processed by @code{nroff} or @code{troff}.
+
+@item -T
+@itemx --format=tex
+
+Choose an output format suitable for @TeX{} processing. Each output
+line will look like:
+
+@example
+\xx @{@var{tail}@}@{@var{before}@}@{@var{keyword}@}@{@var{after}@}@{@var{head}@}@{@var{ref}@}
+@end example
+
+@noindent
+so it will be possible to write write a @code{\xx} definition to take
+care of the output typesetting. Note that when references are not being
+produced, that is, neither option @code{-A} nor option @code{-r} is
+selected, the last parameter of each @code{\xx} call is inhibited.
+Option @samp{-M} might be used to change @samp{xx} to another macro
+name.
+
+In this output format, some special characters, like @kbd{$}, @kbd{%},
+@kbd{&}, @kbd{#} and @kbd{_} are automatically protected with a
+backslash. Curly brackets @kbd{@{}, @kbd{@}} are also protected with a
+backslash, but also enclosed in a pair of dollar signs to force
+mathematical mode. The backslash itself produces the sequence
+@code{\backslash@{@}}. Circumflex and tilde diacritics produce the
+sequence @code{^\@{ @}} and @code{~\@{ @}} respectively. Other
+diacriticized characters of the underlying character set produce an
+appropriate @TeX{} sequence as far as possible. The other non-graphical
+characters, like newline and tab, and all others characters which are
+not part of ASCII, are merely changed to exactly one space, with no
+special attempt to compress consecutive spaces. Let me know how to
+improve this special character processing for @TeX{}.
+
+@end table
+
+@node Compatibility, , Invoking ptx, Top
+@chapter The GNU extensions to @code{ptx}
+
+This version of @code{ptx} contains a few features which do not exist in
+System V @code{ptx}. These extra features are suppressed by using the
+@samp{-G} command line option, unless overridden by other command line
+options. Some GNU extensions cannot be recovered by overriding, so the
+simple rule is to avoid @samp{-G} if you care about GNU extensions.
+Here are the differences between this program and System V @code{ptx}.
+
+@itemize @bullet
+
+@item
+This program can read many input files at once, it always writes the
+resulting concordance on standard output. On the other end, System V
+@code{ptx} reads only one file and produce the result on standard output
+or, if a second @var{file} parameter is given on the command, to that
+@var{file}.
+
+Having output parameters not introduced by options is a quite dangerous
+practice which GNU avoids as far as possible. So, for using @code{ptx}
+portably between GNU and System V, you should pay attention to always
+use it with a single input file, and always expect the result on
+standard output. You might also want to automatically configure in a
+@samp{-G} option to @code{ptx} calls in products using @code{ptx}, if
+the configurator finds that the installed @code{ptx} accepts @samp{-G}.
+
+@item
+The only options available in System V @code{ptx} are options @samp{-b},
+@samp{-f}, @samp{-g}, @samp{-i}, @samp{-o}, @samp{-r}, @samp{-t} and
+@samp{-w}. All other options are GNU extensions and are not repeated in
+this enumeration. Moreover, some options have a slightly different
+meaning when GNU extensions are enabled, as explained below.
+
+@item
+By default, concordance output is not formatted for @code{troff} or
+@code{nroff}. It is rather formatted for a dumb terminal. @code{troff}
+or @code{nroff} output may still be selected through option @code{-O}.
+
+@item
+Unless @code{-R} option is used, the maximum reference width is
+subtracted from the total output line width. With GNU extensions
+disabled, width of references is not taken into account in the output
+line width computations.
+
+@item
+All 256 characters, even @kbd{NUL}s, are always read and processed from
+input file with no adverse effect, even if GNU extensions are disabled.
+However, System V @code{ptx} does not accept 8-bit characters, a few
+control characters are rejected, and the tilda @kbd{~} is condemned.
+
+@item
+Input line length is only limited by available memory, even if GNU
+extensions are disabled. However, System V @code{ptx} processes only
+the first 200 characters in each line.
+
+@item
+The break (non-word) characters default to be every character except all
+letters of the underlying character set, diacriticized or not. When GNU
+extensions are disabled, the break characters default to space, tab and
+newline only.
+
+@item
+The program makes better use of output line width. If GNU extensions
+are disabled, the program rather tries to imitate System V @code{ptx},
+but still, there are some slight disposition glitches this program does
+not completely reproduce.
+
+@item
+The user can specify both an Ignore file and an Only file. This is not
+allowed with System V @code{ptx}.
+
+@end itemize
+
+@bye
diff --git a/gnu/usr.bin/ptx/ptx.c b/gnu/usr.bin/ptx/ptx.c
index 2dc306e..8c1b8d2 100644
--- a/gnu/usr.bin/ptx/ptx.c
+++ b/gnu/usr.bin/ptx/ptx.c
@@ -79,7 +79,7 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\n";
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
-
+
#if !defined(S_ISREG) && defined(S_IFREG)
#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
#endif
@@ -101,7 +101,7 @@ extern int errno;
#include "bumpalloc.h"
#include "diacrit.h"
-#include "regex.h"
+#include "gnuregex.h"
#ifndef __STDC__
void *xmalloc ();
@@ -257,25 +257,25 @@ char *text_buffer_maxend; /* allocated end of text_buffer */
while (0)
/* Occurrences table.
-
+
The `keyword' pointer provides the central word, which is surrounded
by a left context and a right context. The `keyword' and `length'
field allow full 8-bit characters keys, even including NULs. At other
places in this program, the name `keyafter' refers to the keyword
followed by its right context.
-
+
The left context does not extend, towards the beginning of the file,
further than a distance given by the `left' value. This value is
relative to the keyword beginning, it is usually negative. This
insures that, except for white space, we will never have to backward
scan the source text, when it is time to generate the final output
lines.
-
+
The right context, indirectly attainable through the keyword end, does
not extend, towards the end of the file, further than a distance given
by the `right' value. This value is relative to the keyword
beginning, it is usually positive.
-
+
When automatic references are used, the `reference' value is the
overall line number in all input files read so far, in this case, it
is of type (int). When input references are used, the `reference'
@@ -302,7 +302,7 @@ size_t number_of_occurs[1]; /* number of used slots in occurs_table */
#define ALLOC_NEW_OCCURS(language) \
BUMP_ALLOC (occurs_table[language], number_of_occurs[language], 9, OCCURS)
-
+
/* Communication among output routines. */
@@ -472,7 +472,7 @@ alloc_and_compile_regex (const char *string)
/* The fastmap should be compiled before `re_match'. The following
call is not mandatory, because `re_search' is always called sooner,
and it compiles the fastmap if this has not been done yet. */
-
+
re_compile_fastmap (pattern);
/* Do not waste extra allocated space. */
@@ -581,7 +581,7 @@ swallow_file_in_memory (const char *file_name, BLOCK *block)
/* As special cases, a file name which is NULL or "-" indicates standard
input, which is already opened. In all other cases, open the file from
- its name. */
+ its name. */
if (!file_name || !*file_name || strcmp (file_name, "-") == 0)
file_handle = fileno (stdin);
@@ -1363,8 +1363,8 @@ fix_output_parameters (void)
. One ending the tail field.
. One beginning the before field, another ending the keyafter field.
. One ending the tail field, another beginning the before field.
- . One ending the keyafter field, another beginning the head field.
-
+ . One ending the keyafter field, another beginning the head field.
+
So, there is at most two truncation marks, which could appear both
on the left side of the center of the output line, both on the
right side, or one on either side. */
@@ -1987,7 +1987,7 @@ main (int argc, char *const argv[])
/* Decode program options. */
program_name = argv[0];
-
+
while ((optchar = getopt_long (argc, argv, "ACF:GM:ORS:TW:b:i:fg:o:trw:",
long_options, NULL)),
optchar != EOF)
diff --git a/gnu/usr.bin/rcs/CREDITS b/gnu/usr.bin/rcs/CREDITS
new file mode 100644
index 0000000..6eca1b9
--- /dev/null
+++ b/gnu/usr.bin/rcs/CREDITS
@@ -0,0 +1,24 @@
+RCS was designed and built by Walter F. Tichy of Purdue University.
+RCS version 3 was released in 1983.
+
+Adam Hammer, Thomas Narten, and Daniel Trinkle of Purdue supported RCS through
+version 4.3, released in 1990. Guy Harris of Sun contributed many porting
+fixes. Paul Eggert of System Development Corporation contributed bug fixes
+and tuneups. Jay Lepreau contributed 4.3BSD support.
+
+Paul Eggert of Twin Sun wrote the changes for RCS versions 5.5 and 5.6 (1991).
+Rich Braun of Kronos and Andy Glew of Intel contributed ideas for new options.
+Bill Hahn of Stratus contributed ideas for setuid support.
+Ideas for piece tables came from Joe Berkovitz of Stratus and Walter F. Tichy.
+Matt Cross of Stratus contributed test case ideas.
+Adam Hammer of Purdue QAed.
+
+Paul Eggert wrote most of the changes for this version of RCS,
+currently in beta test. K. Richard Pixley of Cygnus Support
+contributed several bug fixes. Robert Lupton of Princeton
+and Daniel Trinkle contributed ideas for $Name expansion.
+Brendan Kehoe of Cygnus Support suggested rlog's -N option.
+Paul D. Smith of Data General suggested improvements in option
+and error processing. Adam Hammer of Purdue QAed.
+
+$Id: CREDITS,v 1.1 1993/11/03 17:50:39 eggert Exp $
diff --git a/gnu/usr.bin/rcs/Makefile b/gnu/usr.bin/rcs/Makefile
index 2181815..4a9fd08 100644
--- a/gnu/usr.bin/rcs/Makefile
+++ b/gnu/usr.bin/rcs/Makefile
@@ -1,3 +1,3 @@
-SUBDIR= lib ci co ident merge rcs rcsdiff rcsmerge rlog rcsfreeze
+SUBDIR= lib ci co ident merge rcs rcsclean rcsdiff rcsmerge rlog rcsfreeze
.include <bsd.subdir.mk>
diff --git a/gnu/usr.bin/rcs/Makefile.inc b/gnu/usr.bin/rcs/Makefile.inc
index b9eca7d..cd593ed 100644
--- a/gnu/usr.bin/rcs/Makefile.inc
+++ b/gnu/usr.bin/rcs/Makefile.inc
@@ -1,3 +1,7 @@
-# @(#)Makefile.inc 5.1 (Berkeley) 5/11/90
+# Location of librcs
-BINDIR?= /usr/bin
+.if exists(${.CURDIR}/../lib/obj)
+LIBRCS= ${.CURDIR}/../lib/obj/librcs.a
+.else
+LIBRCS= ${.CURDIR}/../lib/librcs.a
+.endif
diff --git a/gnu/usr.bin/rcs/NEWS b/gnu/usr.bin/rcs/NEWS
new file mode 100644
index 0000000..62b7c2b
--- /dev/null
+++ b/gnu/usr.bin/rcs/NEWS
@@ -0,0 +1,548 @@
+Recent changes to RCS (and possible future changes)
+
+ $Id: NEWS,v 1.5 1995/06/16 06:19:24 eggert Exp $
+
+ Copyright 1991, 1992, 1993, 1994, 1995 Paul Eggert
+ Distributed under license by the Free Software Foundation, Inc.
+
+ This file is part of RCS.
+
+ RCS is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 2, or (at your
+ option) any later version.
+
+ RCS is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with RCS; see the file COPYING.
+ If not, write to the Free Software Foundation,
+ 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ Report problems and direct all questions to:
+
+ rcs-bugs@cs.purdue.edu
+
+
+Here is a brief summary of user-visible changes since 5.6.
+
+ New options:
+ `-kb' supports binary files.
+ `-T' preserves the modification time of RCS files.
+ `-V' prints the version number.
+ `-zLT' causes RCS to use local time in working files and logs.
+ `rcsclean -n' outputs what rcsclean would do, without actually doing it.
+ `rlog -N' omits symbolic names.
+ There is a new keyword `Name'.
+ Inserted log lines now have the same prefix as the preceding `$Log' line.
+
+Most changes for RCS version 5.7 are to fix bugs and improve portability.
+RCS now conforms to GNU configuration standards and to Posix 1003.1b-1993.
+
+
+Features new to RCS version 5.7, and possibly incompatible
+in minor ways with previous practice, include:
+
+ Inserted log lines now have the same prefix as the preceding `$Log' line.
+ E.g. if a $Log line starts with `// $Log', log lines are prefixed with `// '.
+ RCS still records the (now obsolescent) comment leader inside RCS files,
+ but it ignores the comment leader unless it is emulating older RCS versions.
+ If you plan to access a file with both old and new versions of RCS,
+ make sure its comment leader matches its `$Log' line prefix.
+ For backwards compatibility with older versions of RCS,
+ if the log prefix is `/*' or `(*' surrounded by optional white space,
+ inserted log lines contain ` *' instead of `/*' or `(*';
+ however, this usage is obsolescent and should not be relied on.
+
+ $Log string `Revision' times now use the same format as other times.
+
+ Log lines are now inserted even if -kk is specified; this simplifies merging.
+
+ ci's -rR option (with a nonempty R) now just specifies a revision number R.
+ In some beta versions, it also reestablished the default behavior of
+ releasing a lock and removing the working file.
+ Now, only the bare -r option does this.
+
+ With an empty extension, any appearance of a directory named `RCS'
+ in a pathname identifies the pathname as being that of an RCS file.
+ For example, `a/RCS/b/c' is now an RCS file with an empty extension.
+ Formerly, `RCS' had to be the last directory in the pathname.
+
+ rlog's -d option by default now uses exclusive time ranges.
+ E.g. `rlog -d"<T"' now excludes revisions whose times equal T exactly.
+ Use `rlog -d"<=T"' to get the old behavior.
+
+ merge now takes up to three -L options, one for each input file.
+ Formerly, it took at most two -L options, for the 1st and 3rd input files.
+
+ `rcs' now requires at least one option; this is for future expansion.
+
+Other features new to RCS version 5.7 include:
+
+ merge and rcsmerge now pass -A, -E, and -e options to the subsidiary diff3.
+
+ rcs -kb acts like rcs -ko, except it uses binary I/O on working files.
+ This makes no difference under Posix or Unix, but it does matter elsewhere.
+ With -kb in effect, rcsmerge refuses to merge;
+ this avoids common problems with CVS merging.
+
+ The following is for future use by GNU Emacs 19's version control package:
+
+ rcs's new -M option causes it to not send mail when you break somebody
+ else's lock. This is not meant for casual use; see rcs(1).
+
+ ci's new -i option causes an error if the RCS file already exists.
+ Similarly, -j causes an error if the RCS file does not already exist.
+
+ The new keyword `Name' is supported; its value is the name, if any,
+ used to check out the revision. E.g. `co -rN foo' causes foo's
+ $Name...$ keyword strings to end in `: N $'.
+
+ The new -zZONE option causes RCS to output dates and times using ISO 8601
+ format with ZONE as the time zone, and to use ZONE as the default time
+ zone for input. Its most common use is the -zLT option, which causes RCS
+ to use local time externally. You can also specify foreign time zones;
+ e.g. -z+05:30 causes RCS to use India time (5 hours 30 minutes east of UTC).
+ This option does not affect RCS files themselves, which always use UTC;
+ it affects only output (e.g. rlog output, keyword expansion, diff -c times)
+ and interpretation of options (e.g. the -d option of ci, co, and rlog).
+ Bare -z restores the default behavior of UTC with no time zone indication,
+ and the traditional RCS date separator `/' instead of the ISO 8601 `-'.
+ RCSINIT may contain a -z option. ci -k parses UTC offsets.
+
+ The new -T option of ci, co, rcs, and rcsclean preserves the modification
+ time of the RCS file unless a revision is added or removed.
+ ci -T sets the RCS file's modification time to the new revision's time
+ if the former precedes the latter and there is a new revision;
+ otherwise, it preserves the RCS file's modification time.
+ Use this option with care, as it can confuse `make'; see ci(1).
+
+ The new -N option of rlog omits symbolic names from the output.
+
+ A revision number that starts with `.' is considered to be relative to
+ the default branch (normally the trunk). A branch number followed by `.'
+ stands for the last revision on that branch.
+
+ If someone else already holds the lock, rcs -l now asks whether you want
+ to break it, instead of immediately reporting an error.
+
+ ci now always unlocks a revision like 3.5 if you check in a revision
+ like 3.5.2.1 that is the first of a new branch of that revision.
+ Formerly it was inconsistent.
+
+ File names may now contain tab, newline, space, and '$'.
+ They are represented in keyword strings with \t, \n, \040, and \044.
+ \ in a file name is now represented by \\ in a keyword string.
+
+ Identifiers may now start with a digit and (unless they are symbolic names)
+ may contain `.'. This permits author names like `john.doe' and `4tran'.
+
+ A bare -V option now prints the current version number.
+
+ rcsdiff outputs more readable context diff headers if diff -L works.
+
+ rcsdiff -rN -rN now suppresses needless checkout and comparison
+ of identical revisions.
+
+ Error messages now contain the names of files to which they apply.
+
+ Mach style memory mapping is now supported.
+
+ The installation procedure now conforms to the GNU coding standards.
+
+ When properly configured, RCS now strictly conforms to Posix 1003.1b-1993.
+
+
+Features new to RCS version 5.6 include:
+
+ Security holes have been plugged; setgid use is no longer supported.
+
+ co can retrieve old revisions much more efficiently.
+ To generate the Nth youngest revision on the trunk,
+ the old method used up to N passes through copies of the working file;
+ the new method uses a piece table to generate the working file in one pass.
+
+ When ci finds no changes in the working file,
+ it automatically reverts to the previous revision unless -f is given.
+
+ RCS follows symbolic links to RCS files instead of breaking them,
+ and warns when it breaks hard links to RCS files.
+
+ `$' stands for the revision number taken from working file keyword strings.
+ E.g. if F contains an Id keyword string,
+ `rcsdiff -r$ F' compares F to its checked-in revision, and
+ `rcs -nL:$ F' gives the symbolic name L to F's revision.
+
+ co and ci's new -M option sets the modification time
+ of the working file to be that of the revision.
+ Without -M, ci now tries to avoid changing the working file's
+ modification time if its contents are unchanged.
+
+ rcs's new -m option changes the log message of an old revision.
+
+ RCS is portable to hosts that do not permit `,' in filenames.
+ (`,' is not part of the Posix portable filename character set.)
+ A new -x option specifies extensions other than `,v' for RCS files.
+ The Unix default is `-x,v/', so that the working file `w' corresponds
+ to the first file in the list `RCS/w,v', `w,v', `RCS/w' that works.
+ The non-Unix default is `-x', so that only `RCS/w' is tried.
+ Eventually, the Unix default should change to `-x/,v'
+ to encourage interoperability among all Posix hosts.
+
+ A new RCSINIT environment variable specifies defaults for options like -x.
+
+ The separator for revision ranges has been changed from `-' to `:', because
+ the range `A-B' is ambiguous if `A', `B' and `A-B' are all symbolic names.
+ E.g. the old `rlog -r1.5-1.7' is now `rlog -r1.5:1.7'; ditto for `rcs -o'.
+ For a while RCS will still support (but warn about) the old `-' separator.
+
+ RCS manipulates its lock files using a method that is more reliable under NFS.
+
+
+Features new to RCS version 5 include:
+
+ RCS can check in arbitrary files, not just text files, if diff -a works.
+ RCS can merge lines containing just a single `.' if diff3 -m works.
+ GNU diff supports the -a and -m options.
+
+ RCS can now be used as a setuid program.
+ See ci(1) for how users can employ setuid copies of ci, co, and rcsclean.
+ Setuid privileges yield extra security if the effective user owns RCS files
+ and directories, and if only the effective user can write RCS directories.
+ RCS uses the real user for all accesses other than writing RCS directories.
+ As described in ci(1), there are three levels of setuid support.
+
+ 1. Setuid works fully if the seteuid() system call lets any
+ process switch back and forth between real and effective users,
+ as specified in Posix 1003.1a Draft 5.
+
+ 2. On hosts with saved setuids (a Posix 1003.1-1990 option) and without
+ a modern seteuid(), setuid works unless the real or effective user is root.
+
+ 3. On hosts that lack both modern seteuid() and saved setuids,
+ setuid does not work, and RCS uses the effective user for all accesses;
+ formerly it was inconsistent.
+
+ New options to co, rcsdiff, and rcsmerge give more flexibility to keyword
+ substitution.
+
+ -kkv substitutes the default `$Keyword: value $' for keyword strings.
+ However, a locker's name is inserted only as a file is being locked,
+ i.e. by `ci -l' and `co -l'. This is normally the default.
+
+ -kkvl acts like -kkv, except that a locker's name is always inserted
+ if the given revision is currently locked. This was the default in
+ version 4. It is now the default only with when using rcsdiff to
+ compare a revision to a working file whose mode is that of a file
+ checked out for changes.
+
+ -kk substitutes just `$Keyword$', which helps to ignore keyword values
+ when comparing revisions.
+
+ -ko retrieves the old revision's keyword string, thus bypassing keyword
+ substitution.
+
+ -kv retrieves just `value'. This can ease the use of keyword values, but
+ it is dangerous because it causes RCS to lose track of where the keywords
+ are, so for safety the owner write permission of the working file is
+ turned off when -kv is used; to edit the file later, check it out again
+ without -kv.
+
+ rcs -ko sets the default keyword substitution to be in the style of co -ko,
+ and similarly for the other -k options. This can be useful with file
+ formats that cannot tolerate changing the lengths of keyword strings.
+ However it also renders a RCS file readable only by RCS version 5 or later.
+ Use rcs -kkv to restore the usual default substitution.
+
+ RCS can now be used by development groups that span time zone boundaries.
+ All times are now displayed in UTC, and UTC is the default time zone.
+ To use local time with co -d, append ` LT' to the time.
+ When interchanging RCS files with sites running older versions of RCS,
+ time stamp discrepancies may prevent checkins; to work around this,
+ use `ci -d' with a time slightly in the future.
+
+ Dates are now displayed using four-digit years, not two-digit years.
+ Years given in -d options must now have four digits.
+ This change is required for RCS to continue to work after 1999/12/31.
+ The form of dates in version 5 RCS files will not change until 2000/01/01,
+ so in the meantime RCS files can still be interchanged with sites
+ running older versions of RCS. To make room for the longer dates,
+ rlog now outputs `lines: +A -D' instead of `lines added/del: A/D'.
+
+ To help prevent diff programs that are broken or have run out of memory
+ from trashing an RCS file, ci now checks diff output more carefully.
+
+ ci -k now handles the Log keyword, so that checking in a file
+ with -k does not normally alter the file's contents.
+
+ RCS no longer outputs white space at the ends of lines
+ unless the original working file had it.
+ For consistency with other keywords,
+ a space, not a tab, is now output after `$Log:'.
+ Rlog now puts lockers and symbolic names on separate lines in the output
+ to avoid generating lines that are too long.
+ A similar fix has been made to lists in the RCS files themselves.
+
+ RCS no longer outputs the string `Locker: ' when expanding Header or Id
+ keywords. This saves space and reverts back to version 3 behavior.
+
+ The default branch is not put into the RCS file unless it is nonempty.
+ Therefore, files generated by RCS version 5 can be read by RCS version 3
+ unless they use the default branch feature introduced in version 4.
+ This fixes a compatibility problem introduced by version 4.
+
+ RCS can now emulate older versions of RCS; see `co -V'.
+ This may be useful to overcome compatibility problems
+ due to the above changes.
+
+ Programs like Emacs can now interact with RCS commands via a pipe:
+ the new -I option causes ci, co, and rcs to run interactively,
+ even if standard input is not a terminal.
+ These commands now accept multiple inputs from stdin separated by `.' lines.
+
+ ci now silently ignores the -t option if the RCS file already exists.
+ This simplifies some shell scripts and improves security in setuid sites.
+
+ Descriptive text may be given directly in an argument of the form -t-string.
+
+ The character set for symbolic names has been upgraded
+ from Ascii to ISO 8859.
+
+ rcsdiff now passes through all options used by GNU diff;
+ this is a longer list than 4.3BSD diff.
+
+ merge's new -L option gives tags for merge's overlap report lines.
+ This ability used to be present in a different, undocumented form;
+ the new form is chosen for compatibility with GNU diff3's -L option.
+
+ rcsmerge and merge now have a -q option, just like their siblings do.
+
+ rcsclean's new -n option outputs what rcsclean would do,
+ without actually doing it.
+
+ RCS now attempts to ignore parts of an RCS file that look like they come
+ from a future version of RCS.
+
+ When properly configured, RCS now strictly conforms with Posix 1003.1-1990.
+ RCS can still be compiled in non-Posix traditional Unix environments,
+ and can use common BSD and USG extensions to Posix.
+ RCS is a conforming Standard C program, and also compiles under traditional C.
+
+ Arbitrary limits on internal table sizes have been removed.
+ The only limit now is the amount of memory available via malloc().
+
+ File temporaries, lock files, signals, and system call return codes
+ are now handled more cleanly, portably, and quickly.
+ Some race conditions have been removed.
+
+ A new compile-time option RCSPREFIX lets administrators avoid absolute path
+ names for subsidiary programs, trading speed for flexibility.
+
+ The configuration procedure is now more automatic.
+
+ Snooping has been removed.
+
+
+Version 4 was the first version distributed by FSF.
+Beside bug fixes, features new to RCS version 4 include:
+
+ The notion of default branch has been added; see rcs -b.
+
+
+Version 3 was included in the 4.3BSD distribution.
+
+
+Here are some possible future changes for RCS:
+
+ Bring back sccstorcs.
+
+ Add an option to `rcsmerge' so that it can use an arbitrary program
+ to do the 3-way merge, instead of the default `merge'.
+ Likewise for `rcsdiff' and `diff'. It should be possible to pass
+ arbitrary options to these programs, and to the subsidiary `co's.
+
+ Add format options for finer control over the output of ident and rlog.
+ E.g. there should be an easy way for rlog to output lines like
+ `src/main.c 2.4 wft', one for each locked revision.
+ rlog options should have three orthogonal types: selecting files,
+ selecting revisions, and selecting rlog format.
+
+ Add format options for finer control over the output of keyword strings.
+ E.g. there should be some way to prepend @(#), and there should be some
+ way to change $ to some other character to disable further substitution.
+ These options should make the resulting files uneditable, like -kv.
+
+ Add long options, e.g. `--version'. Unfortunately RCS's option syntax
+ is incompatible with getopt. Perhaps the best way is to overload `rcs', e.g.
+ `rcs diff --keyword-substitution=old file' instead of `rcsdiff -ko file'.
+
+ Add a way to put only the interesting part of the path into the $Header
+ keyword expansion.
+
+ rlog -rM:N should work even if M and N have different numbers of fields,
+ so long as M is an ancestor of N or vice versa.
+
+ rcs should evaluate options in order; this allows rcs -oS -nS.
+
+ rcs should be able to fix minor mistakes in checkin dates and authors.
+
+ Be able to redo your most recent checkin with minor changes.
+
+ co -u shouldn't complain about a writable working file if it won't change
+ its contents.
+
+ Configure the Makefile automatically, as well as conf.h.
+
+ Add a new option to rcs that behaves like -o, but that doesn't lose the
+ nonempty log messages, but instead merges them with the next revision
+ if it exists, perhaps with a 1-line header containing author, date, etc.
+
+ Add a `-' option to take the list of pathnames from standard input.
+ Perhaps the pathnames should be null-terminated, not newline-terminated,
+ so that pathnames that contain newlines are handled properly.
+
+ Permit multiple option-pathname pairs, e.g. co -r1.4 a -r1.5 b.
+
+ Add options to allow arbitrary combinations of working file names
+ with RCS file names -- they shouldn't have to match.
+
+ Add an option to break a symbolic link to an RCS file,
+ instead of breaking the hard link that it points to.
+
+ Add ways to specify the earliest revision, the most recent revision,
+ the earliest or latest revision on a particular branch, and
+ the parent or child of some other revision.
+
+ If a user has multiple locks, perhaps ci should fall back on ci -k's
+ method to figure out which revision to use.
+
+ Symbolic names need not refer to existing branches and revisions.
+ rcs(1)'s BUGS section says this is a bug. Is it? If so, it should be fixed.
+
+ Add an option to rcs -o so that old log messages are not deleted if
+ the next undeleted revision exists, but are merely appended to the log
+ message of that revision.
+
+ ci -k should be able to get keyword values from the first `$Log' entry.
+
+ Add an option to rcsclean to clean directories recursively.
+
+ Write an rcsck program that repairs corrupted RCS files,
+ much as fsck repairs corrupted file systems.
+ For example, it should remove stale lock files.
+
+ Clean up the source code with a consistent indenting style.
+
+ Update the date parser to use the more modern getdate.y by Bellovin,
+ Salz, and Berets, or the even more modern getdate by Moraes. None of
+ these getdate implementations are as robust as RCS's old warhorse in
+ avoiding problems like arithmetic overflow, so they'll have to be
+ fixed first.
+
+ Break up the code into a library so that it's easier to write new programs
+ that manipulate RCS files, and so that useless code is removed from the
+ existing programs. For example, the rcs command contains unnecessary
+ keyword substitution baggage, and the merge command can be greatly pruned.
+
+ Make it easier to use your favorite text editor to edit log messages,
+ etc. instead of having to type them in irretrievably at the terminal.
+
+ Let the user specify a search path for default branches,
+ e.g. to use L as the default branch if it works, and M otherwise.
+ Let the user require that at least one entry in the default branch path works.
+ Let the user say that later entries in the default branch path are read only,
+ i.e. one cannot check in changes to them.
+ This should be an option settable by RCSINIT.
+
+ Add a way for a user to see which revisions affected which lines.
+
+ Have `rlog -nN F' print just the revision number that N translates to.
+ E.g. `rlog -nB. F' would print the highest revision on the branch B.
+ Use this to add an option -bB to rcsbranch, to freeze the named branch.
+ This should interact well with default branches.
+
+ Add a co option that prints the revision number before each line,
+ as SCCS's `get -m' does.
+
+The following projects require a change to RCS file format.
+
+ Allow keyword expansion to be changed on a per-revision basis,
+ not on a per-file basis as now. This would allow -ko to be used
+ on imported revisions, with the default -kkv otherwise.
+
+ When two or more branches are merged, record all the ancestors
+ of the new revision. The hard part of this is keeping track of all
+ the ancestors of a working file while it's checked out.
+
+ Add loose locking, which is like non-strict but applies to all users,
+ not just the owner of the RCS file.
+
+ Be able to store RCS files in compressed format.
+ Don't bother to use a .Z extension that would exceed file name length limits;
+ just look at the magic number.
+
+ Add locker commentary, e.g. `co -l -m"checkout to fix merge bug" foo'
+ to tell others why you checked out `foo'.
+ Also record the time when the revision was locked,
+ and perhaps the working pathname (if applicable).
+
+ Let the user mark an RCS revision as deleted; checking out such a revision
+ would result in no working file. Similarly, using `co -d' with a date either
+ before the initial revision or after the file was marked deleted should
+ remove the working file. For extra credit, extend the notion of `deleted' to
+ include `renamed'. RCS should support arbitrary combinations of renaming and
+ deletion, e.g. renaming A to B and B to A, checking in new revisions to both
+ files, and then renaming them back.
+
+ Be able to check in an entire directory structure into a single RCS file.
+
+ Use a better scheme for locking revisions; the current scheme requires
+ changing the RCS file just to lock or unlock a revision.
+ The new scheme should coexist as well as possible with older versions of RCS,
+ and should avoid the rare NFS bugs mentioned in rcsedit.c.
+ E.g. if there's a reliable lockd running, RCS should use it
+ instead of relying on NFS.
+
+ Add rcs options for changing keyword names, e.g. XConsortium instead of Id.
+
+ Add a `$Description' keyword; but this may be tricky, since descriptions can
+ contain newlines and $s.
+
+ Add a `$Copyright' keyword that expands to a copyright notice.
+
+ Add frozen branches a la SCCS. In general, be able to emulate all of
+ SCCS, so that an SCCS-to-RCS program can be practical. For example,
+ there should be an equivalent to the SCCS prt command.
+
+ Add support for distributed RCS, where widely separated
+ users cannot easily access each others' RCS files,
+ and must periodically distribute and reconcile new revisions.
+
+ Be able to create empty branches.
+
+ Be able to store just deltas from a read-only principal copy,
+ e.g. from source on CD-ROM.
+
+ Improve RCS's method for storing binary files.
+ Although it is more efficient than SCCS's,
+ the diff algorithm is still line oriented,
+ and often generates long output for minor changes to an executable file.
+
+ From the user's point of view, it would be best if
+ RCS detected and handled binary files without human intervention,
+ switching expansion methods as needed from revision to revision.
+
+ Allow RCS to determine automagically whether -ko or -kb should be the default
+ by inspecting the file's contents or name. The magic should be optional
+ and user-programmable.
+
+ Extend the grammar of RCS files so that keywords need not be in a fixed order.
+
+ Internationalize messages; unfortunately, there's no common standard yet.
+ This requires a change in RCS file format because of the
+ `empty log message' and `checked in with -k' hacks inside RCS files.
+
+ Add documentation in texinfo format.
diff --git a/gnu/usr.bin/rcs/REFS b/gnu/usr.bin/rcs/REFS
new file mode 100644
index 0000000..eaf96a5
--- /dev/null
+++ b/gnu/usr.bin/rcs/REFS
@@ -0,0 +1,90 @@
+Here are references to RCS and related free software and documentation.
+Some of this information changes often; see the Frequently Asked Questions
+for more up-to-date references.
+
+ $Id: REFS,v 1.1 1995/06/16 06:19:24 eggert Exp $
+
+
+Frequently Asked Questions (FAQs)
+
+<http://www.qucis.queensu.ca/Software-Engineering/>
+<ftp://rtfm.mit.edu//pub/usenet-by-hierarchy/comp/software-eng/>
+ for software engineering; e.g. see
+ <http://www.qucis.queensu.ca/Software-Engineering/blurb/rcs>.
+
+<http://www.iac.honeywell.com/Pub/Tech/CM/CMFAQ.html>
+<ftp://rtfm.mit.edu//pub/usenet-by-hierarchy/comp/software/config-mgmt/>
+ for configuration management
+
+<http://www.winternet.com/~zoo/cvs/FAQ.txt>
+<ftp://ftp.odi.com/pub/users/dgg/FAQ.gz>
+ for CVS (see below)
+
+
+RCS and related GNU project software
+
+<ftp://ftp.cs.purdue.edu/pub/RCS/>
+ The RCS project distribution directory also contains beta versions,
+ ports, and prebuilt documentation.
+
+<ftp://prep.ai.mit.edu/pub/gnu/>
+ The GNU project distribution directory contains:
+ diffutils-N-tar.gz
+ the latest diffutils release; recommended for RCS
+ emacs-N-tar.gz
+ The latest Emacs release contains VC, a version-control package
+ that makes RCS easier to use.
+ make-N-tar.gz
+ GNU Make, which can automatically build from RCS files.
+ rcs-N-tar.gz
+ the latest RCS release
+ cvs-N-tar.gz
+ the latest official CVS release (see below)
+
+<ftp://ftp.leo.org/pub/comp/os/os2/gnu/devtools/> DOS, OS/2 ports
+<ftp://ftp.cc.utexas.edu/microlib/nt/gnu/> NT port
+
+
+CVS
+
+CVS, the Concurrent Versions System, keeps tracks of source changes
+made by groups of developers working on the same files concurrently,
+allowing them to resync as needed.
+
+<http://www.winternet.com/~zoo/cvs/>
+<http://www.loria.fr/~molli/cvs-index.html>
+ These pages have useful information about CVS.
+
+<ftp://prep.ai.mit.edu/pub/gnu/cvs-1.3.tar.gz>
+ CVS 1.3 is the latest released version.
+
+<ftp://ftp.delos.com/pub/cvs/alpha/cvs-1.4A2.tar.gz>
+ CVS 1.4 is in alpha test, but it is recommended if you are installing CVS
+ for the first time, or on a recent operating system.
+
+<ftp://ftp-os2.cdrom.com/pub/os2/unix/> DOS, OS/2 ports
+<ftp://ftp.cc.utexas.edu/microlib/nt/gnu/> NT port
+
+<ftp://ftp.cyclic.com/pub/cvs/>
+ Cyclic CVS adds network transparency to CVS; it supports efficient,
+ reliable, and authenticated repository access via TCP/IP.
+
+
+Other software that uses RCS
+
+<ftp://ftp.nau.edu/pub/Aegis/>
+ Aegis manages revisions, baselines, mandatory reviews, and mandatory testing.
+
+<ftp://ftp.vix.com/pub/patches/csu/>
+ BCS, the Baseline Configuration System,
+ manages revisions, baselines, and staging areas.
+
+<ftp://riftp.osf.org/pub/ode/>
+ ODE, the Open Software Foundation Development Environment,
+ manages revisions, builds, and sandboxes.
+ OSF uses it for their own development.
+
+<ftp://bellcore.com/pub/Odin/>
+ Odin, a `make' replacement, can build directly from arbitrary revisions
+ without requiring checkouts of working copies. It also handles
+ parallel builds on multiple remote hosts and of multiple variants.
diff --git a/gnu/usr.bin/rcs/ci/Makefile b/gnu/usr.bin/rcs/ci/Makefile
index 9b64e08..2fbb74f 100644
--- a/gnu/usr.bin/rcs/ci/Makefile
+++ b/gnu/usr.bin/rcs/ci/Makefile
@@ -1,7 +1,8 @@
-PROG= ci
-
-SRCS= ci.c
-LDADD= -L${.CURDIR}/../lib/obj -lrcs
+PROG= ci
+SRCS= ci.c
CFLAGS+= -I${.CURDIR}/../lib
+LDADD= ${LIBRCS}
+DPADD= ${LIBRCS}
+.include "../../Makefile.inc"
.include <bsd.prog.mk>
diff --git a/gnu/usr.bin/rcs/ci/ci.1 b/gnu/usr.bin/rcs/ci/ci.1
index 5736dc9..b11cf8d 100644
--- a/gnu/usr.bin/rcs/ci/ci.1
+++ b/gnu/usr.bin/rcs/ci/ci.1
@@ -2,8 +2,10 @@
.ds Rv \\$3
.ds Dt \\$4
..
-.Id $Id: ci.1,v 5.9 1991/10/07 17:32:46 eggert Exp $
+.Id $Id: ci.1,v 1.2 1995/10/28 21:49:06 peter Exp $
+.ds i \&\s-1ISO\s0
.ds r \&\s-1RCS\s0
+.ds u \&\s-1UTC\s0
.if n .ds - \%--
.if t .ds - \(em
.TH CI 1 \*(Dt GNU
@@ -41,7 +43,7 @@ new branch can be created. This restriction is not enforced
for the owner of the file if non-strict locking is used
(see
.BR rcs (1)).
-A lock held by someone else may be broken with the
+A lock held by someone else can be broken with the
.B rcs
command.
.PP
@@ -105,7 +107,9 @@ The number
.I rev
of the deposited revision can be given by any of the options
.BR \-f ,
+.BR \-i ,
.BR \-I ,
+.BR \-j ,
.BR \-k ,
.BR \-l ,
.BR \-M ,
@@ -114,7 +118,15 @@ of the deposited revision can be given by any of the options
or
.BR \-u .
.I rev
-may be symbolic, numeric, or mixed.
+can be symbolic, numeric, or mixed.
+Symbolic names in
+.I rev
+must already be defined;
+see the
+.B \-n
+and
+.B \-N
+options for assigning names during checkin.
If
.I rev
is
@@ -124,6 +136,15 @@ determines the revision number from keyword values in the working file.
.PP
If
.I rev
+begins with a period,
+then the default branch (normally the trunk) is prepended to it.
+If
+.I rev
+is a branch number followed by a period,
+then the latest revision on that branch is used.
+.PP
+If
+.I rev
is a revision number, it must be higher than the latest
one on the branch to which
.I rev
@@ -172,25 +193,28 @@ Exception: On the trunk, revisions can be appended to the end, but
not inserted.
.SH OPTIONS
.TP
-.BR \-r [\f2rev\fP]
-checks in a revision, releases the corresponding lock, and
-removes the working file. This is the default.
-.RS
-.PP
-The
+.BI \-r rev
+Check in revision
+.IR rev .
+.TP
+.BR \-r
+The bare
.B \-r
-option has an unusual meaning in
+option (without any revision) has an unusual meaning in
.BR ci .
-In other \*r commands,
+With other \*r commands, a bare
.B \-r
-merely specifies a revision number,
-but in
-.B ci
-it also releases a lock and removes the working file.
-See
+option specifies the most recent revision on the default branch,
+but with
+.BR ci ,
+a bare
+.B \-r
+option reestablishes the default behavior of releasing a lock and
+removing the working file, and is used to override any default
+.B \-l
+or
.B \-u
-for a tricky example.
-.RE
+options established by shell aliases or scripts.
.TP
.BR \-l [\f2rev\fP]
works like
@@ -213,6 +237,7 @@ immediately after checkin.
.PP
The
.BR \-l ,
+bare
.BR \-r ,
and
.B \-u
@@ -221,7 +246,7 @@ For example,
.B "ci\ \-u\ \-r"
is equivalent to
.B "ci\ \-r"
-because
+because bare
.B \-r
overrides
.BR \-u .
@@ -244,7 +269,7 @@ several sites should be checked in with the
.B \-k
option at these sites to
preserve the original number, date, author, and state.
-The extracted keyword values and the default log message may be overridden
+The extracted keyword values and the default log message can be overridden
with the options
.BR \-d ,
.BR \-m ,
@@ -259,6 +284,14 @@ unless
.B \-f
is given.
.TP
+.BR \-i [\f2rev\fP]
+initial checkin; report an error if the \*r file already exists.
+This avoids race conditions in certain applications.
+.TP
+.BR \-j [\f2rev\fP]
+just checkin and do not initialize;
+report an error if the \*r file does not already exist.
+.TP
.BR \-I [\f2rev\fP]
interactive mode;
the user is prompted and questioned
@@ -296,6 +329,18 @@ Use this option with care; it can confuse
uses the string
.I msg
as the log message for all revisions checked in.
+By convention, log messages that start with
+.B #
+are comments and are ignored by programs like GNU Emacs's
+.B vc
+package.
+Also, log messages that start with
+.BI { clumpname }
+(followed by white space) are meant to be clumped together if possible,
+even if they are associated with different files; the
+.BI { clumpname }
+label is used only for clumping,
+and is not considered to be part of the log message itself.
.TP
.BI \-n "name"
assigns the symbolic name
@@ -326,7 +371,7 @@ into the \*r file,
deleting the existing text.
The
.I file
-may not begin with
+cannot begin with
.BR \- .
.TP
.BI \-t\- string
@@ -356,6 +401,41 @@ For backward compatibility with older versions of \*r, a bare
option is ignored.
.RE
.TP
+.B \-T
+Set the \*r file's modification time to the new revision's time
+if the former precedes the latter and there is a new revision;
+preserve the \*r file's modification time otherwise.
+If you have locked a revision,
+.B ci
+usually updates the \*r file's modification time to the current time,
+because the lock is stored in the \*r file
+and removing the lock requires changing the \*r file.
+This can create an \*r file newer than the working file in one of two ways:
+first,
+.B "ci\ \-M"
+can create a working file with a date before the current time;
+second, when reverting to the previous revision
+the \*r file can change while the working file remains unchanged.
+These two cases can cause excessive recompilation caused by a
+.BR make (1)
+dependency of the working file on the \*r file.
+The
+.B \-T
+option inhibits this recompilation by lying about the \*r file's date.
+Use this option with care; it can suppress recompilation even when
+a checkin of one working file should affect
+another working file associated with the same \*r file.
+For example, suppose the \*r file's time is 01:00,
+the (changed) working file's time is 02:00,
+some other copy of the working file has a time of 03:00,
+and the current time is 04:00.
+Then
+.B "ci\ \-d\ \-T"
+sets the \*r file's time to 02:00 instead of the usual 04:00;
+this causes
+.BR make (1)
+to think (incorrectly) that the other copy is newer than the \*r file.
+.TP
.BI \-w "login"
uses
.I login
@@ -364,6 +444,9 @@ Useful for lying about the author, and for
.B \-k
if no author is available.
.TP
+.BI \-V
+Print \*r's version number.
+.TP
.BI \-V n
Emulate \*r version
.IR n .
@@ -375,9 +458,9 @@ for details.
specifies the suffixes for \*r files.
A nonempty suffix matches any pathname ending in the suffix.
An empty suffix matches any pathname of the form
-.BI RCS/ file
+.BI RCS/ path
or
-.IB path /RCS/ file.
+.IB path1 /RCS/ path2.
The
.B \-x
option can specify a list of suffixes
@@ -398,10 +481,49 @@ The default for
.IR suffixes
is installation-dependent; normally it is
.B ,v/
-for hosts like Unix that permit commas in file names,
+for hosts like Unix that permit commas in filenames,
and is empty (i.e. just the empty suffix) for other hosts.
+.TP
+.BI \-z zone
+specifies the date output format in keyword substitution,
+and specifies the default time zone for
+.I date
+in the
+.BI \-d date
+option.
+The
+.I zone
+should be empty, a numeric \*u offset, or the special string
+.B LT
+for local time.
+The default is an empty
+.IR zone ,
+which uses the traditional \*r format of \*u without any time zone indication
+and with slashes separating the parts of the date;
+otherwise, times are output in \*i 8601 format with time zone indication.
+For example, if local time is January 11, 1990, 8pm Pacific Standard Time,
+eight hours west of \*u,
+then the time is output as follows:
+.RS
+.LP
+.RS
+.nf
+.ta \w'\f3\-z+05:30\fP 'u +\w'\f31990-01-11 09:30:00+05:30\fP 'u
+.ne 4
+\f2option\fP \f2time output\fP
+\f3\-z\fP \f31990/01/12 04:00:00\fP \f2(default)\fP
+\f3\-zLT\fP \f31990-01-11 20:00:00\-08\fP
+\f3\-z+05:30\fP \f31990-01-12 09:30:00+05:30\fP
+.ta 4n +4n +4n +4n
+.fi
+.RE
+.LP
+The
+.B \-z
+option does not affect dates stored in \*r files,
+which are always \*u.
.SH "FILE NAMING"
-Pairs of \*r files and working files may be specified in three ways
+Pairs of \*r files and working files can be specified in three ways
(see also the
example section).
.PP
@@ -423,9 +545,9 @@ If
.I X
is empty,
.IB path1 /
-must be
+must start with
.B RCS/
-or must end in
+or must contain
.BR /RCS/ .
.PP
2) Only the \*r file is given. Then the working file is created in the current
@@ -516,7 +638,7 @@ preserves its read and execute permissions.
.B ci
always turns off all write permissions of \*r files.
.SH FILES
-Several temporary files may be created in the directory containing
+Temporary files are created in the directory containing
the working file, and also in the temporary directory (see
.B \s-1TMPDIR\s0
under
@@ -576,21 +698,23 @@ who can check in new revisions but cannot otherwise change the \*r files.
.SH "SETUID USE"
To prevent anybody but their \*r administrator from deleting revisions,
a set of users can employ setuid privileges as follows.
-.nr n \w'\(bu '+1n-1/1n
-.IP \(bu \nn
+.nr n \w'\(bu'+2n-1/1n
+.ds n \nn
+.if \n(.g .if r an-tag-sep .ds n \w'\(bu'u+\n[an-tag-sep]u
+.IP \(bu \*n
Check that the host supports \*r setuid use.
Consult a trustworthy expert if there are any doubts.
It is best if the
-.B seteuid()
+.B seteuid
system call works as described in Posix 1003.1a Draft 5,
because \*r can switch back and forth easily
between real and effective users, even if the real user is
.BR root .
If not, the second best is if the
-.B setuid()
+.B setuid
system call supports saved setuid
(the {\s-1_POSIX_SAVED_IDS\s0} behavior of Posix 1003.1-1990);
-this fails only if the real user is
+this fails only if the real or effective user is
.BR root .
If \*r detects any failure in setuid, it quits immediately.
.IP \(bu \nn
@@ -599,7 +723,7 @@ Choose a user
to serve as \*r administrator for the set of users.
Only
.I A
-will be able to invoke the
+can invoke the
.B rcs
command on the users' \*r files.
.I A
@@ -608,9 +732,9 @@ should not be
or any other user with special powers.
Mutually suspicious sets of users should use different administrators.
.IP \(bu \nn
-Choose a path name
+Choose a pathname
.I B
-that will be a directory of files to be executed by the users.
+to be a directory of files to be executed by the users.
.IP \(bu \nn
Have
.I A
@@ -733,8 +857,9 @@ Useful
options include
.BR \-q ,
.BR \-V ,
+.BR \-x ,
and
-.BR \-x .
+.BR \-z .
.TP
.B \s-1TMPDIR\s0
Name of the temporary directory.
@@ -755,14 +880,15 @@ The exit status is zero if and only if all operations were successful.
.SH IDENTIFICATION
Author: Walter F. Tichy.
.br
-Revision Number: \*(Rv; Release Date: \*(Dt.
+Manual Page Revision: \*(Rv; Release Date: \*(Dt.
.br
-Copyright \(co 1982, 1988, 1989 by Walter F. Tichy.
+Copyright \(co 1982, 1988, 1989 Walter F. Tichy.
.br
-Copyright \(co 1990, 1991 by Paul Eggert.
+Copyright \(co 1990, 1991, 1992, 1993, 1994, 1995 Paul Eggert.
.SH "SEE ALSO"
-co(1), ident(1), make(1), rcs(1), rcsclean(1), rcsdiff(1),
-rcsintro(1), rcsmerge(1), rlog(1), rcsfile(5)
+co(1),
+ident(1), make(1), rcs(1), rcsclean(1), rcsdiff(1),
+rcsintro(1), rcsmerge(1), rlog(1), setuid(2), rcsfile(5)
.br
Walter F. Tichy,
\*r\*-A System for Version Control,
diff --git a/gnu/usr.bin/rcs/ci/ci.c b/gnu/usr.bin/rcs/ci/ci.c
index 566747e..701b15c 100644
--- a/gnu/usr.bin/rcs/ci/ci.c
+++ b/gnu/usr.bin/rcs/ci/ci.c
@@ -1,5 +1,7 @@
-/* Copyright (C) 1982, 1988, 1989 Walter Tichy
- Copyright 1990, 1991 by Paul Eggert
+/* Check in revisions of RCS files from working files. */
+
+/* Copyright 1982, 1988, 1989 Walter Tichy
+ Copyright 1990, 1991, 1992, 1993, 1994, 1995 Paul Eggert
Distributed under license by the Free Software Foundation, Inc.
This file is part of RCS.
@@ -15,8 +17,9 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
-along with RCS; see the file COPYING. If not, write to
-the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+along with RCS; see the file COPYING.
+If not, write to the Free Software Foundation,
+59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
Report problems and direct all questions to:
@@ -25,16 +28,49 @@ Report problems and direct all questions to:
*/
/*
- * RCS checkin operation
- */
-/*******************************************************************
- * check revisions into RCS files
- *******************************************************************
- */
-
-
-
-/* $Log: ci.c,v $
+ * Revision 5.30 1995/06/16 06:19:24 eggert
+ * Update FSF address.
+ *
+ * Revision 5.29 1995/06/01 16:23:43 eggert
+ * (main): Add -kb.
+ * Use `cmpdate', not `cmpnum', to compare dates.
+ * This is for MKS RCS's incompatible 20th-century date format.
+ * Don't worry about errno after ftruncate fails.
+ * Fix input file rewinding bug when large_memory && !maps_memory
+ * and checking in a branch tip.
+ *
+ * (fixwork): Fall back on chmod if fchmod fails, since it might be ENOSYS.
+ *
+ * Revision 5.28 1994/03/20 04:52:58 eggert
+ * Do not generate a corrupted RCS file if the user modifies the working file
+ * while `ci' is running.
+ * Do not remove the lock when `ci -l' reverts.
+ * Move buffer-flushes out of critical sections, since they aren't critical.
+ * Use ORCSerror to clean up after a fatal error.
+ * Specify subprocess input via file descriptor, not file name.
+ *
+ * Revision 5.27 1993/11/09 17:40:15 eggert
+ * -V now prints version on stdout and exits. Don't print usage twice.
+ *
+ * Revision 5.26 1993/11/03 17:42:27 eggert
+ * Add -z. Don't subtract from RCS file timestamp even if -T.
+ * Scan for and use Name keyword if -k.
+ * Don't discard ignored phrases. Improve quality of diagnostics.
+ *
+ * Revision 5.25 1992/07/28 16:12:44 eggert
+ * Add -i, -j, -V. Check that working and RCS files are distinct.
+ *
+ * Revision 5.24 1992/02/17 23:02:06 eggert
+ * `-rREV' now just specifies a revision REV; only bare `-r' reverts to default.
+ * Add -T.
+ *
+ * Revision 5.23 1992/01/27 16:42:51 eggert
+ * Always unlock branchpoint if caller has a lock.
+ * Add support for bad_chmod_close, bad_creat0. lint -> RCS_lint
+ *
+ * Revision 5.22 1992/01/06 02:42:34 eggert
+ * Invoke utime() before chmod() to keep some buggy systems happy.
+ *
* Revision 5.21 1991/11/20 17:58:07 eggert
* Don't read the delta tree from a nonexistent RCS file.
*
@@ -114,37 +150,37 @@ Report problems and direct all questions to:
*
* Revision 4.9 89/05/01 15:10:54 narten
* changed copyright header to reflect current distribution rules
- *
+ *
* Revision 4.8 88/11/08 13:38:23 narten
* changes from root@seismo.CSS.GOV (Super User)
* -d with no arguments uses the mod time of the file it is checking in
- *
+ *
* Revision 4.7 88/08/09 19:12:07 eggert
* Make sure workfile is a regular file; use its mode if RCSfile doesn't have one.
* Use execv(), not system(); allow cc -R; remove lint.
* isatty(fileno(stdin)) -> ttystdin()
- *
+ *
* Revision 4.6 87/12/18 11:34:41 narten
* lint cleanups (from Guy Harris)
- *
+ *
* Revision 4.5 87/10/18 10:18:48 narten
* Updating version numbers. Changes relative to revision 1.1 are actually
* relative to 4.3
- *
+ *
* Revision 1.3 87/09/24 13:57:19 narten
- * Sources now pass through lint (if you ignore printf/sprintf/fprintf
+ * Sources now pass through lint (if you ignore printf/sprintf/fprintf
* warnings)
- *
+ *
* Revision 1.2 87/03/27 14:21:33 jenkins
* Port to suns
- *
+ *
* Revision 4.3 83/12/15 12:28:54 wft
* ci -u and ci -l now set mode of working file properly.
- *
+ *
* Revision 4.2 83/12/05 13:40:54 wft
* Merged with 3.9.1.1: added calls to clearerr(stdin).
* made rewriteflag external.
- *
+ *
* Revision 4.1 83/05/10 17:03:06 wft
* Added option -d and -w, and updated assingment of date, etc. to new delta.
* Added handling of default branches.
@@ -155,13 +191,13 @@ Report problems and direct all questions to:
* Removed calls to stat(); now done by pairfilenames().
* Changed most calls to catchints() with restoreints().
* Directed all interactive messages to stderr.
- *
+ *
* Revision 3.9.1.1 83/10/19 04:21:03 lepreau
* Added clearerr(stdin) to getlogmsg() for re-reading stdin.
- *
+ *
* Revision 3.9 83/02/15 15:25:44 wft
* 4.2 prerelease
- *
+ *
* Revision 3.9 83/02/15 15:25:44 wft
* Added call to fastcopy() to copy remainder of RCS file.
*
@@ -214,16 +250,16 @@ struct Symrev {
};
static char const *getcurdate P((void));
-static int addbranch P((struct hshentry*,struct buf*));
+static int addbranch P((struct hshentry*,struct buf*,int));
static int addelta P((void));
static int addsyms P((char const*));
-static int fixwork P((mode_t,char const*));
+static int fixwork P((mode_t,time_t));
static int removelock P((struct hshentry*));
-static int xpandfile P((RILE*,char const*,struct hshentry const*,char const**));
+static int xpandfile P((RILE*,struct hshentry const*,char const**,int));
static struct cbuf getlogmsg P((void));
static void cleanup P((void));
static void incnum P((char const*,struct buf*));
-static void addassoclst P((int, char *));
+static void addassoclst P((int,char const*));
static FILE *exfile;
static RILE *workptr; /* working file pointer */
@@ -236,37 +272,41 @@ static struct hshentries *gendeltas; /* deltas to be generated */
static struct hshentry *targetdelta; /* old delta to be generated */
static struct hshentry newdelta; /* new delta to be inserted */
static struct stat workstat;
-static struct Symrev *assoclst, *lastassoc;
+static struct Symrev *assoclst, **nextassoc;
-mainProg(ciId, "ci", "$Id: ci.c,v 5.21 1991/11/20 17:58:07 eggert Exp $")
+mainProg(ciId, "ci", "$Id: ci.c,v 1.3 1995/10/28 21:49:08 peter Exp $")
{
static char const cmdusage[] =
- "\nci usage: ci -{fklqru}[rev] -mmsg -{nN}name -sstate -t[textfile] -Vn file ...";
+ "\nci usage: ci -{fIklMqru}[rev] -d[date] -mmsg -{nN}name -sstate -ttext -T -Vn -wwho -xsuff -zzone file ...";
static char const default_state[] = DEFAULTSTATE;
char altdate[datesize];
char olddate[datesize];
- char newdatebuf[datesize], targetdatebuf[datesize];
+ char newdatebuf[datesize + zonelenmax];
+ char targetdatebuf[datesize + zonelenmax];
char *a, **newargv, *textfile;
char const *author, *krev, *rev, *state;
- char const *diffilename, *expfilename;
- char const *workdiffname, *newworkfilename;
- char const *mtime;
- int lockflag, lockthis, mtimeflag, removedlock;
+ char const *diffname, *expname;
+ char const *newworkname;
+ int initflag, mustread;
+ int lockflag, lockthis, mtimeflag, removedlock, Ttimeflag;
int r;
- int changedRCS, changework, newhead;
+ int changedRCS, changework, dolog, newhead;
int usestatdate; /* Use mod time of file for -d. */
mode_t newworkmode; /* mode for working file */
+ time_t mtime, wtime;
struct hshentry *workdelta;
-
+
setrid();
- author = rev = state = textfile = nil;
- lockflag = false;
+ author = rev = state = textfile = 0;
+ initflag = lockflag = mustread = false;
mtimeflag = false;
+ Ttimeflag = false;
altdate[0]= '\0'; /* empty alternate date for -d */
usestatdate=false;
suffixes = X_DEFAULT;
+ nextassoc = &assoclst;
argc = getRCSINIT(argc, argv, &newargv);
argv = newargv;
@@ -274,7 +314,13 @@ mainProg(ciId, "ci", "$Id: ci.c,v 5.21 1991/11/20 17:58:07 eggert Exp $")
switch (*a++) {
case 'r':
+ if (*a)
+ goto revno;
keepworkingfile = lockflag = false;
+ break;
+
+ case 'l':
+ keepworkingfile = lockflag = true;
revno:
if (*a) {
if (rev) warn("redefinition of revision number");
@@ -282,14 +328,18 @@ mainProg(ciId, "ci", "$Id: ci.c,v 5.21 1991/11/20 17:58:07 eggert Exp $")
}
break;
- case 'l':
- keepworkingfile=lockflag=true;
- goto revno;
-
case 'u':
keepworkingfile=true; lockflag=false;
goto revno;
+ case 'i':
+ initflag = true;
+ goto revno;
+
+ case 'j':
+ mustread = true;
+ goto revno;
+
case 'I':
interactiveflag = true;
goto revno;
@@ -310,7 +360,7 @@ mainProg(ciId, "ci", "$Id: ci.c,v 5.21 1991/11/20 17:58:07 eggert Exp $")
if (msg.size) redefined('m');
msg = cleanlogmsg(a, strlen(a));
if (!msg.size)
- warn("missing message for -m option");
+ error("missing message for -m option");
break;
case 'n':
@@ -318,16 +368,16 @@ mainProg(ciId, "ci", "$Id: ci.c,v 5.21 1991/11/20 17:58:07 eggert Exp $")
error("missing symbolic name after -n");
break;
}
- checksid(a);
+ checkssym(a);
addassoclst(false, a);
break;
-
+
case 'N':
if (!*a) {
error("missing symbolic name after -N");
break;
}
- checksid(a);
+ checkssym(a);
addassoclst(true, a);
break;
@@ -337,7 +387,7 @@ mainProg(ciId, "ci", "$Id: ci.c,v 5.21 1991/11/20 17:58:07 eggert Exp $")
checksid(a);
state = a;
} else
- warn("missing state for -s option");
+ error("missing state for -s option");
break;
case 't':
@@ -350,7 +400,7 @@ mainProg(ciId, "ci", "$Id: ci.c,v 5.21 1991/11/20 17:58:07 eggert Exp $")
case 'd':
if (altdate[0] || usestatdate)
redefined('d');
- altdate[0] = 0;
+ altdate[0] = '\0';
if (!(usestatdate = !*a))
str2date(a, altdate);
break;
@@ -365,7 +415,7 @@ mainProg(ciId, "ci", "$Id: ci.c,v 5.21 1991/11/20 17:58:07 eggert Exp $")
checksid(a);
author = a;
} else
- warn("missing author for -w option");
+ error("missing author for -w option");
break;
case 'x':
@@ -376,26 +426,34 @@ mainProg(ciId, "ci", "$Id: ci.c,v 5.21 1991/11/20 17:58:07 eggert Exp $")
setRCSversion(*argv);
break;
+ case 'z':
+ zone_set(a);
+ break;
-
+ case 'T':
+ if (!*a) {
+ Ttimeflag = true;
+ break;
+ }
+ /* fall into */
default:
- faterror("unknown option: %s%s", *argv, cmdusage);
+ error("unknown option: %s%s", *argv, cmdusage);
};
} /* end processing of options */
- if (argc<1) faterror("no input file%s", cmdusage);
-
- /* now handle all filenames */
- do {
- targetdelta=nil;
+ /* Handle all pathnames. */
+ if (nerror) cleanup();
+ else if (argc < 1) faterror("no input file%s", cmdusage);
+ else for (; 0 < argc; cleanup(), ++argv, --argc) {
+ targetdelta = 0;
ffree();
- switch (pairfilenames(argc, argv, rcswriteopen, false, false)) {
+ switch (pairnames(argc, argv, rcswriteopen, mustread, false)) {
case -1: /* New RCS file */
# if has_setuid && has_getuid
if (euid() != ruid()) {
- error("setuid initial checkin prohibited; use `rcs -i -a' first");
+ workerror("setuid initial checkin prohibited; use `rcs -i -a' first");
continue;
}
# endif
@@ -406,38 +464,52 @@ mainProg(ciId, "ci", "$Id: ci.c,v 5.21 1991/11/20 17:58:07 eggert Exp $")
continue;
case 1: /* Normal checkin with prev . RCS file */
+ if (initflag) {
+ rcserror("already exists");
+ continue;
+ }
rcsinitflag = !Head;
}
- /* now RCSfilename contains the name of the RCS file, and
- * workfilename contains the name of the working file.
+ /*
+ * RCSname contains the name of the RCS file, and
+ * workname contains the name of the working file.
* If the RCS file exists, finptr contains the file descriptor for the
- * RCS file. The admin node is initialized.
- * RCSstat is set.
+ * RCS file, and RCSstat is set. The admin node is initialized.
*/
- diagnose("%s <-- %s\n", RCSfilename,workfilename);
+ diagnose("%s <-- %s\n", RCSname, workname);
- if (!(workptr = Iopen(workfilename, FOPEN_R_WORK, &workstat))) {
- eerror(workfilename);
+ if (!(workptr = Iopen(workname, FOPEN_R_WORK, &workstat))) {
+ eerror(workname);
continue;
}
- if (finptr && !checkaccesslist()) continue; /* give up */
+
+ if (finptr) {
+ if (same_file(RCSstat, workstat, 0)) {
+ rcserror("RCS file is the same as working file %s.",
+ workname
+ );
+ continue;
+ }
+ if (!checkaccesslist())
+ continue;
+ }
krev = rev;
if (keepflag) {
/* get keyword values from working file */
if (!getoldkeys(workptr)) continue;
if (!rev && !*(krev = prevrev.string)) {
- error("can't find a revision number in %s",workfilename);
+ workerror("can't find a revision number");
continue;
}
if (!*prevdate.string && *altdate=='\0' && usestatdate==false)
- warn("can't find a date in %s", workfilename);
+ workwarn("can't find a date");
if (!*prevauthor.string && !author)
- warn("can't find an author in %s", workfilename);
+ workwarn("can't find an author");
if (!*prevstate.string && !state)
- warn("can't find a state in %s", workfilename);
+ workwarn("can't find a state");
} /* end processing keepflag */
/* Read the delta tree. */
@@ -453,17 +525,20 @@ mainProg(ciId, "ci", "$Id: ci.c,v 5.21 1991/11/20 17:58:07 eggert Exp $")
continue;
newdelta.num = newdelnum.string;
- newdelta.branches=nil;
- newdelta.lockedby=nil; /*might be changed by addlock() */
+ newdelta.branches = 0;
+ newdelta.lockedby = 0; /* This might be changed by addlock(). */
newdelta.selector = true;
+ newdelta.name = 0;
+ clear_buf(&newdelta.ig);
+ clear_buf(&newdelta.igtext);
/* set author */
- if (author!=nil)
+ if (author)
newdelta.author=author; /* set author given by -w */
else if (keepflag && *prevauthor.string)
newdelta.author=prevauthor.string; /* preserve old author if possible*/
else newdelta.author=getcaller();/* otherwise use caller's id */
newdelta.state = default_state;
- if (state!=nil)
+ if (state)
newdelta.state=state; /* set state given by -s */
else if (keepflag && *prevstate.string)
newdelta.state=prevstate.string; /* preserve old state if possible */
@@ -479,9 +554,9 @@ mainProg(ciId, "ci", "$Id: ci.c,v 5.21 1991/11/20 17:58:07 eggert Exp $")
} else
newdelta.date = getcurdate(); /* use current date */
/* now check validity of date -- needed because of -d and -k */
- if (targetdelta!=nil &&
- cmpnum(newdelta.date,targetdelta->date) < 0) {
- error("Date %s precedes %s in existing revision %s.",
+ if (targetdelta &&
+ cmpdate(newdelta.date,targetdelta->date) < 0) {
+ rcserror("Date %s precedes %s in revision %s.",
date2str(newdelta.date, newdatebuf),
date2str(targetdelta->date, targetdatebuf),
targetdelta->num
@@ -490,48 +565,46 @@ mainProg(ciId, "ci", "$Id: ci.c,v 5.21 1991/11/20 17:58:07 eggert Exp $")
}
- if (lockflag && addlock(&newdelta) < 0) continue;
+ if (lockflag && addlock(&newdelta, true) < 0) continue;
+
+ if (keepflag && *prevname.string)
+ if (addsymbol(newdelta.num, prevname.string, false) < 0)
+ continue;
if (!addsyms(newdelta.num))
continue;
-
- putadmin(frewrite);
+
+ putadmin();
puttree(Head,frewrite);
putdesc(false,textfile);
- changework = Expand != OLD_EXPAND;
+ changework = Expand < MIN_UNCHANGED_EXPAND;
+ dolog = true;
lockthis = lockflag;
workdelta = &newdelta;
/* build rest of file */
if (rcsinitflag) {
- diagnose("initial revision: %s\n", newdelnum.string);
+ diagnose("initial revision: %s\n", newdelta.num);
/* get logmessage */
newdelta.log=getlogmsg();
- if (!putdftext(newdelnum.string,newdelta.log,workptr,frewrite,false)) continue;
+ putdftext(&newdelta, workptr, frewrite, false);
RCSstat.st_mode = workstat.st_mode;
+ RCSstat.st_nlink = 0;
changedRCS = true;
} else {
- diffilename = maketemp(0);
- workdiffname = workfilename;
- if (workdiffname[0] == '+') {
- /* Some diffs have options with leading '+'. */
- char *dp = ftnalloc(char, strlen(workfilename)+3);
- workdiffname = dp;
- *dp++ = '.';
- *dp++ = SLASH;
- VOID strcpy(dp, workfilename);
- }
+ diffname = maketemp(0);
newhead = Head == &newdelta;
if (!newhead)
foutptr = frewrite;
- expfilename = buildrevision(
+ expname = buildrevision(
gendeltas, targetdelta, (FILE*)0, false
);
if (
!forceciflag &&
+ strcmp(newdelta.state, targetdelta->state) == 0 &&
(changework = rcsfcmp(
- workptr, &workstat, expfilename, targetdelta
+ workptr, &workstat, expname, targetdelta
)) <= 0
) {
diagnose("file is unchanged; reverting to previous revision %s\n",
@@ -541,12 +614,8 @@ mainProg(ciId, "ci", "$Id: ci.c,v 5.21 1991/11/20 17:58:07 eggert Exp $")
diagnose("previous revision was not locked; ignoring -l option\n");
lockthis = 0;
}
- if (!(changedRCS =
- lockflag < removedlock
- || assoclst
- || newdelta.state != default_state
- && strcmp(newdelta.state, targetdelta->state) != 0
- ))
+ dolog = false;
+ if (! (changedRCS = lockflag<removedlock || assoclst))
workdelta = targetdelta;
else {
/*
@@ -555,20 +624,22 @@ mainProg(ciId, "ci", "$Id: ci.c,v 5.21 1991/11/20 17:58:07 eggert Exp $")
*/
long hwm = ftell(frewrite);
int bad_truncate;
- if (fseek(frewrite, 0L, SEEK_SET) != 0)
- Oerror();
+ Orewind(frewrite);
+
+ /*
+ * Work around a common ftruncate() bug:
+ * NFS won't let you truncate a file that you
+ * currently lack permissions for, even if you
+ * had permissions when you opened it.
+ * Also, Posix 1003.1b-1993 sec 5.6.7.2 p 128 l 1022
+ * says ftruncate might fail because it's not supported.
+ */
# if !has_ftruncate
- bad_truncate = 1;
-# else
- /*
- * Work around a common ftruncate() bug.
- * We can't rely on has_truncate, because we might
- * be using a filesystem exported to us via NFS.
- */
- bad_truncate = ftruncate(fileno(frewrite),(off_t)0);
- if (bad_truncate && errno != EACCES)
- Oerror();
+# undef ftruncate
+# define ftruncate(fd,length) (-1)
# endif
+ bad_truncate = ftruncate(fileno(frewrite), (off_t)0);
+
Irewind(finptr);
Lexinit();
getadmin();
@@ -581,11 +652,11 @@ mainProg(ciId, "ci", "$Id: ci.c,v 5.21 1991/11/20 17:58:07 eggert Exp $")
workdelta->log = targetdelta->log;
if (newdelta.state != default_state)
workdelta->state = newdelta.state;
- if (removedlock && removelock(workdelta)<0)
+ if (lockthis<removedlock && removelock(workdelta)<0)
continue;
if (!addsyms(workdelta->num))
continue;
- if (!dorewrite(true, true))
+ if (dorewrite(true, true) != 0)
continue;
fastcopy(finptr, frewrite);
if (bad_truncate)
@@ -595,48 +666,127 @@ mainProg(ciId, "ci", "$Id: ci.c,v 5.21 1991/11/20 17:58:07 eggert Exp $")
afputc('\n', frewrite);
}
} else {
+ int wfd = Ifileno(workptr);
+ struct stat checkworkstat;
+ char const *diffv[6 + !!OPEN_O_BINARY], **diffp;
+# if large_memory && !maps_memory
+ FILE *wfile = workptr->stream;
+ long wfile_off;
+# endif
+# if !has_fflush_input && !(large_memory && maps_memory)
+ off_t wfd_off;
+# endif
+
diagnose("new revision: %s; previous revision: %s\n",
- newdelnum.string, targetdelta->num
+ newdelta.num, targetdelta->num
);
newdelta.log = getlogmsg();
- switch (run((char*)0, diffilename,
- DIFF DIFF_FLAGS,
- newhead ? workdiffname : expfilename,
- newhead ? expfilename : workdiffname,
- (char*)0
- )) {
+# if !large_memory
+ Irewind(workptr);
+# if has_fflush_input
+ if (fflush(workptr) != 0)
+ Ierror();
+# endif
+# else
+# if !maps_memory
+ if (
+ (wfile_off = ftell(wfile)) == -1
+ || fseek(wfile, 0L, SEEK_SET) != 0
+# if has_fflush_input
+ || fflush(wfile) != 0
+# endif
+ )
+ Ierror();
+# endif
+# endif
+# if !has_fflush_input && !(large_memory && maps_memory)
+ wfd_off = lseek(wfd, (off_t)0, SEEK_CUR);
+ if (wfd_off == -1
+ || (wfd_off != 0
+ && lseek(wfd, (off_t)0, SEEK_SET) != 0))
+ Ierror();
+# endif
+ diffp = diffv;
+ *++diffp = DIFF;
+ *++diffp = DIFFFLAGS;
+# if OPEN_O_BINARY
+ if (Expand == BINARY_EXPAND)
+ *++diffp = "--binary";
+# endif
+ *++diffp = newhead ? "-" : expname;
+ *++diffp = newhead ? expname : "-";
+ *++diffp = 0;
+ switch (runv(wfd, diffname, diffv)) {
case DIFF_FAILURE: case DIFF_SUCCESS: break;
- default: faterror("diff failed");
+ default: rcsfaterror("diff failed");
}
+# if !has_fflush_input && !(large_memory && maps_memory)
+ if (lseek(wfd, wfd_off, SEEK_CUR) == -1)
+ Ierror();
+# endif
+# if large_memory && !maps_memory
+ if (fseek(wfile, wfile_off, SEEK_SET) != 0)
+ Ierror();
+# endif
if (newhead) {
Irewind(workptr);
- if (!putdftext(newdelnum.string,newdelta.log,workptr,frewrite,false)) continue;
- if (!putdtext(targetdelta->num,targetdelta->log,diffilename,frewrite,true)) continue;
+ putdftext(&newdelta, workptr, frewrite, false);
+ if (!putdtext(targetdelta,diffname,frewrite,true)) continue;
} else
- if (!putdtext(newdelnum.string,newdelta.log,diffilename,frewrite,true)) continue;
+ if (!putdtext(&newdelta,diffname,frewrite,true)) continue;
+
+ /*
+ * Check whether the working file changed during checkin,
+ * to avoid producing an inconsistent RCS file.
+ */
+ if (
+ fstat(wfd, &checkworkstat) != 0
+ || workstat.st_mtime != checkworkstat.st_mtime
+ || workstat.st_size != checkworkstat.st_size
+ ) {
+ workerror("file changed during checkin");
+ continue;
+ }
+
changedRCS = true;
}
}
- if (!donerewrite(changedRCS))
+
+ /* Deduce time_t of new revision if it is needed later. */
+ wtime = (time_t)-1;
+ if (mtimeflag | Ttimeflag)
+ wtime = date2time(workdelta->date);
+
+ if (donerewrite(changedRCS,
+ !Ttimeflag ? (time_t)-1
+ : finptr && wtime < RCSstat.st_mtime ? RCSstat.st_mtime
+ : wtime
+ ) != 0)
continue;
if (!keepworkingfile) {
Izclose(&workptr);
- r = un_link(workfilename); /* Get rid of old file */
+ r = un_link(workname); /* Get rid of old file */
} else {
newworkmode = WORKMODE(RCSstat.st_mode,
! (Expand==VAL_EXPAND || lockthis < StrictLocks)
);
- mtime = mtimeflag ? workdelta->date : (char const*)0;
+ mtime = mtimeflag ? wtime : (time_t)-1;
/* Expand if it might change or if we can't fix mode, time. */
if (changework || (r=fixwork(newworkmode,mtime)) != 0) {
Irewind(workptr);
/* Expand keywords in file. */
locker_expansion = lockthis;
+ workdelta->name =
+ namedrev(
+ assoclst ? assoclst->ssymbol
+ : keepflag && *prevname.string ? prevname.string
+ : rev,
+ workdelta
+ );
switch (xpandfile(
- workptr, workfilename,
- workdelta, &newworkfilename
+ workptr, workdelta, &newworkname, dolog
)) {
default:
continue;
@@ -651,24 +801,24 @@ mainProg(ciId, "ci", "$Id: ci.c,v 5.21 1991/11/20 17:58:07 eggert Exp $")
break;
/* fall into */
case 1:
- if (!(r = setfiledate(newworkfilename,mtime))) {
- Izclose(&workptr);
- ignoreints();
- r = chnamemod(&exfile, newworkfilename, workfilename, newworkmode);
- keepdirtemp(newworkfilename);
- restoreints();
- }
+ Izclose(&workptr);
+ aflush(exfile);
+ ignoreints();
+ r = chnamemod(&exfile, newworkname,
+ workname, 1, newworkmode, mtime
+ );
+ keepdirtemp(newworkname);
+ restoreints();
}
}
}
if (r != 0) {
- eerror(workfilename);
+ eerror(workname);
continue;
}
diagnose("done\n");
- } while (cleanup(),
- ++argv, --argc >=1);
+ }
tempunlink();
exitmain(exitstatus);
@@ -682,16 +832,17 @@ cleanup()
Izclose(&workptr);
Ozclose(&exfile);
Ozclose(&fcopy);
- Ozclose(&frewrite);
+ ORCSclose();
dirtempunlink();
}
-#if lint
+#if RCS_lint
# define exiterr ciExit
#endif
- exiting void
+ void
exiterr()
{
+ ORCSerror();
dirtempunlink();
tempunlink();
_exit(EXIT_FAILURE);
@@ -710,26 +861,28 @@ addelta()
*/
{
register char *tp;
- register unsigned i;
+ register int i;
int removedlock;
- unsigned newdnumlength; /* actual length of new rev. num. */
+ int newdnumlength; /* actual length of new rev. num. */
newdnumlength = countnumflds(newdelnum.string);
if (rcsinitflag) {
/* this covers non-existing RCS file and a file initialized with rcs -i */
- if ((newdnumlength==0)&&(Dbranch!=nil)) {
+ if (newdnumlength==0 && Dbranch) {
bufscpy(&newdelnum, Dbranch);
newdnumlength = countnumflds(Dbranch);
}
if (newdnumlength==0) bufscpy(&newdelnum, "1.1");
else if (newdnumlength==1) bufscat(&newdelnum, ".1");
else if (newdnumlength>2) {
- error("Branch point doesn't exist for %s.",newdelnum.string);
+ rcserror("Branch point doesn't exist for revision %s.",
+ newdelnum.string
+ );
return -1;
} /* newdnumlength == 2 is OK; */
Head = &newdelta;
- newdelta.next=nil;
+ newdelta.next = 0;
return 0;
}
if (newdnumlength==0) {
@@ -752,11 +905,11 @@ addelta()
} else if (!targetdelta->next && countnumflds(targetdelta->num)>2) {
/* new tip revision on side branch */
targetdelta->next= &newdelta;
- newdelta.next = nil;
+ newdelta.next = 0;
} else {
/* middle revision; start a new branch */
bufscpy(&newdelnum, "");
- return addbranch(targetdelta,&newdelnum);
+ return addbranch(targetdelta, &newdelnum, 1);
}
incnum(targetdelta->num, &newdelnum);
return 1; /* successful use of existing lock */
@@ -765,7 +918,7 @@ addelta()
/* no existing lock; try Dbranch */
/* update newdelnum */
if (StrictLocks || !myself(RCSstat.st_uid)) {
- error("no lock set by %s",getcaller());
+ rcserror("no lock set by %s", getcaller());
return -1;
}
if (Dbranch) {
@@ -787,8 +940,9 @@ addelta()
bufscat(&newdelnum, ".1");
}
if (cmpnum(newdelnum.string,Head->num) <= 0) {
- error("deltanumber %s too low; must be higher than %s",
- newdelnum.string, Head->num);
+ rcserror("revision %s too low; must be higher than %s",
+ newdelnum.string, Head->num
+ );
return -1;
}
targetdelta = Head;
@@ -803,44 +957,46 @@ addelta()
/* put new revision on side branch */
/*first, get branch point */
tp = newdelnum.string;
- for (i = newdnumlength - (newdnumlength&1 ^ 1); (--i); )
+ for (i = newdnumlength - ((newdnumlength&1) ^ 1); --i; )
while (*tp++ != '.')
- ;
+ continue;
*--tp = 0; /* Kill final dot to get old delta temporarily. */
- if (!(targetdelta=genrevs(newdelnum.string,(char*)nil,(char*)nil,(char*)nil,&gendeltas)))
+ if (!(targetdelta=genrevs(newdelnum.string,(char*)0,(char*)0,(char*)0,&gendeltas)))
return -1;
if (cmpnum(targetdelta->num, newdelnum.string) != 0) {
- error("can't find branchpoint %s", newdelnum.string);
+ rcserror("can't find branch point %s", newdelnum.string);
return -1;
}
*tp = '.'; /* Restore final dot. */
- return addbranch(targetdelta,&newdelnum);
+ return addbranch(targetdelta, &newdelnum, 0);
}
}
static int
-addbranch(branchpoint,num)
+addbranch(branchpoint, num, removedlock)
struct hshentry *branchpoint;
struct buf *num;
+ int removedlock;
/* adds a new branch and branch delta at branchpoint.
* If num is the null string, appends the new branch, incrementing
* the highest branch number (initially 1), and setting the level number to 1.
* the new delta and branchhead are in globals newdelta and newbranch, resp.
* the new number is placed into num.
* Return -1 on error, 1 if a lock is removed, 0 otherwise.
+ * If REMOVEDLOCK is 1, a lock was already removed.
*/
{
struct branchhead *bhead, **btrail;
struct buf branchnum;
- int removedlock, result;
- unsigned field, numlength;
+ int result;
+ int field, numlength;
static struct branchhead newbranch; /* new branch to be inserted */
numlength = countnumflds(num->string);
- if (branchpoint->branches==nil) {
+ if (!branchpoint->branches) {
/* start first branch */
branchpoint->branches = &newbranch;
if (numlength==0) {
@@ -848,7 +1004,7 @@ addbranch(branchpoint,num)
bufscat(num, ".1.1");
} else if (numlength&1)
bufscat(num, ".1");
- newbranch.nextbranch=nil;
+ newbranch.nextbranch = 0;
} else if (numlength==0) {
/* append new branch to the end */
@@ -860,10 +1016,10 @@ addbranch(branchpoint,num)
incnum(branchnum.string, num);
bufautoend(&branchnum);
bufscat(num, ".1");
- newbranch.nextbranch=nil;
+ newbranch.nextbranch = 0;
} else {
/* place the branch properly */
- field = numlength - (numlength&1 ^ 1);
+ field = numlength - ((numlength&1) ^ 1);
/* field of branch number */
btrail = &branchpoint->branches;
while (0 < (result=cmpnumfld(num->string,(*btrail)->hsh->num,field))) {
@@ -882,17 +1038,22 @@ addbranch(branchpoint,num)
/* branch exists; append to end */
bufautobegin(&branchnum);
getbranchno(num->string, &branchnum);
- targetdelta=genrevs(branchnum.string,(char*)nil,
- (char*)nil,(char*)nil,&gendeltas);
+ targetdelta = genrevs(
+ branchnum.string, (char*)0, (char*)0, (char*)0,
+ &gendeltas
+ );
bufautoend(&branchnum);
if (!targetdelta)
return -1;
if (cmpnum(num->string,targetdelta->num) <= 0) {
- error("deltanumber %s too low; must be higher than %s",
- num->string,targetdelta->num);
+ rcserror("revision %s too low; must be higher than %s",
+ num->string, targetdelta->num
+ );
return -1;
}
- if (0 <= (removedlock = removelock(targetdelta))) {
+ if (!removedlock
+ && 0 <= (removedlock = removelock(targetdelta))
+ ) {
if (numlength&1)
incnum(targetdelta->num,num);
targetdelta->next = &newdelta;
@@ -903,8 +1064,11 @@ addbranch(branchpoint,num)
}
}
newbranch.hsh = &newdelta;
- newdelta.next=nil;
- return 0;
+ newdelta.next = 0;
+ if (branchpoint->lockedby)
+ if (strcmp(branchpoint->lockedby, getcaller()) == 0)
+ return removelock(branchpoint); /* This returns 1. */
+ return removedlock;
}
static int
@@ -914,7 +1078,7 @@ addsyms(num)
register struct Symrev *p;
for (p = assoclst; p; p = p->nextsym)
- if (!addsymbol(num, p->ssymbol, p->override))
+ if (addsymbol(num, p->ssymbol, p->override) < 0)
return false;
return true;
}
@@ -966,7 +1130,7 @@ struct hshentry * delta;
* return 0; return 1 if a lock is actually removed.
*/
{
- register struct lock *next, **trail;
+ register struct rcslock *next, **trail;
char const *num;
num=delta->num;
@@ -978,12 +1142,12 @@ struct hshentry * delta;
delta->lockedby = 0;
return 1;
} else {
- error("revision %s locked by %s",num,next->login);
+ rcserror("revision %s locked by %s", num, next->login);
return -1;
}
if (!StrictLocks && myself(RCSstat.st_uid))
return 0;
- error("no lock set by %s for revision %s", getcaller(), num);
+ rcserror("no lock set by %s for revision %s", getcaller(), num);
return -1;
}
@@ -994,76 +1158,70 @@ getcurdate()
/* Return a pointer to the current date. */
{
static char buffer[datesize]; /* date buffer */
- time_t t;
- if (!buffer[0]) {
- t = time((time_t *)0);
- if (t == -1)
- faterror("time not available");
- time2date(t, buffer);
- }
+ if (!buffer[0])
+ time2date(now(), buffer);
return buffer;
}
static int
#if has_prototypes
-fixwork(mode_t newworkmode, char const *mtime)
+fixwork(mode_t newworkmode, time_t mtime)
/* The `#if has_prototypes' is needed because mode_t might promote to int. */
#else
fixwork(newworkmode, mtime)
mode_t newworkmode;
- char const *mtime;
+ time_t mtime;
#endif
{
- int r;
return
1 < workstat.st_nlink
- || newworkmode&S_IWUSR && !myself(workstat.st_uid)
+ || (newworkmode&S_IWUSR && !myself(workstat.st_uid))
+ || setmtime(workname, mtime) != 0
? -1
- :
- workstat.st_mode != newworkmode
- &&
- (r =
-# if has_fchmod
- fchmod(Ifileno(workptr), newworkmode)
-# else
- chmod(workfilename, newworkmode)
-# endif
- ) != 0
- ? r
- :
- setfiledate(workfilename, mtime);
+ : workstat.st_mode == newworkmode ? 0
+#if has_fchmod
+ : fchmod(Ifileno(workptr), newworkmode) == 0 ? 0
+#endif
+#if bad_chmod_close
+ : -1
+#else
+ : chmod(workname, newworkmode)
+#endif
+ ;
}
static int
-xpandfile(unexfile, dir, delta, exfilename)
+xpandfile(unexfile, delta, exname, dolog)
RILE *unexfile;
- char const *dir;
struct hshentry const *delta;
- char const **exfilename;
+ char const **exname;
+ int dolog;
/*
* Read unexfile and copy it to a
- * file in dir, performing keyword substitution with data from delta.
+ * file, performing keyword substitution with data from delta.
* Return -1 if unsuccessful, 1 if expansion occurred, 0 otherwise.
* If successful, stores the stream descriptor into *EXFILEP
- * and its name into *EXFILENAME.
+ * and its name into *EXNAME.
*/
{
- char const *targetfname;
+ char const *targetname;
int e, r;
- targetfname = makedirtemp(dir, 1);
- if (!(exfile = fopen(targetfname, FOPEN_W_WORK))) {
- eerror(targetfname);
- error("can't expand working file");
+ targetname = makedirtemp(1);
+ if (!(exfile = fopenSafer(targetname, FOPEN_W_WORK))) {
+ eerror(targetname);
+ workerror("can't build working file");
return -1;
}
r = 0;
- if (Expand == OLD_EXPAND)
+ if (MIN_UNEXPAND <= Expand)
fastcopy(unexfile,exfile);
else {
for (;;) {
- e = expandline(unexfile,exfile,delta,false,(FILE*)nil);
+ e = expandline(
+ unexfile, exfile, delta, false, (FILE*)0, dolog
+ );
if (e < 0)
break;
r |= e;
@@ -1071,8 +1229,7 @@ xpandfile(unexfile, dir, delta, exfilename)
break;
}
}
- *exfilename = targetfname;
- aflush(exfile);
+ *exname = targetname;
return r & 1;
}
@@ -1113,7 +1270,7 @@ getlogmsg()
/* generate std. log message */
caller = getcaller();
i = sizeof(ciklog)+strlen(caller)+3;
- bufalloc(&logbuf, i+datesize);
+ bufalloc(&logbuf, i + datesize + zonelenmax);
tp = logbuf.string;
VOID sprintf(tp, "%s%s at ", ciklog, caller);
VOID date2str(getcurdate(), tp+i);
@@ -1147,19 +1304,15 @@ getlogmsg()
static void
addassoclst(flag, sp)
-int flag;
-char * sp;
+ int flag;
+ char const *sp;
{
struct Symrev *pt;
-
+
pt = talloc(struct Symrev);
pt->ssymbol = sp;
pt->override = flag;
- pt->nextsym = nil;
- if (lastassoc)
- lastassoc->nextsym = pt;
- else
- assoclst = pt;
- lastassoc = pt;
- return;
+ pt->nextsym = 0;
+ *nextassoc = pt;
+ nextassoc = &pt->nextsym;
}
diff --git a/gnu/usr.bin/rcs/co/Makefile b/gnu/usr.bin/rcs/co/Makefile
index e9de8da..0c73865 100644
--- a/gnu/usr.bin/rcs/co/Makefile
+++ b/gnu/usr.bin/rcs/co/Makefile
@@ -1,7 +1,8 @@
-PROG= co
-
-SRCS= co.c
-LDADD= -L${.CURDIR}/../lib/obj -lrcs
+PROG= co
+SRCS= co.c
CFLAGS+= -I${.CURDIR}/../lib
+LDADD= ${LIBRCS}
+DPADD= ${LIBRCS}
+.include "../../Makefile.inc"
.include <bsd.prog.mk>
diff --git a/gnu/usr.bin/rcs/co/co.1 b/gnu/usr.bin/rcs/co/co.1
index d9ce65e..8d0a6e7 100644
--- a/gnu/usr.bin/rcs/co/co.1
+++ b/gnu/usr.bin/rcs/co/co.1
@@ -2,9 +2,10 @@
.ds Rv \\$3
.ds Dt \\$4
..
-.Id $Id: co.1,v 5.7 1991/08/19 03:13:55 eggert Exp $
-.ds g \&\s-1UTC\s0
+.Id $Id: co.1,v 5.13 1995/06/01 16:23:43 eggert Exp $
+.ds i \&\s-1ISO\s0
.ds r \&\s-1RCS\s0
+.ds u \&\s-1UTC\s0
.if n .ds - \%--
.if t .ds - \(em
.TH CO 1 \*(Dt GNU
@@ -23,12 +24,12 @@ all others denote working files.
Names are paired as explained in
.BR ci (1).
.PP
-Revisions of an \*r file may be checked out locked or unlocked. Locking a
+Revisions of an \*r file can be checked out locked or unlocked. Locking a
revision prevents overlapping updates. A revision checked out for reading or
processing (e.g., compiling) need not be locked. A revision checked out
for editing and later checkin must normally be locked. Checkout with locking
fails if the revision to be checked out is currently locked by another user.
-(A lock may be broken with
+(A lock can be broken with
.BR rcs "(1).)\ \&"
Checkout with locking also requires the caller to be on the access list of
the \*r file, unless he is the owner of the
@@ -51,7 +52,7 @@ on the default branch (normally the trunk, see the
.B \-b
option of
.BR rcs (1)).
-A revision or branch number may be attached
+A revision or branch number can be attached
to any of the options
.BR \-f ,
.BR \-I ,
@@ -73,7 +74,7 @@ retrieve from a single branch, the
.I selected
branch,
which is either specified by one of
-.BR \-f,
+.BR \-f ,
\&.\|.\|.,
.BR \-u ,
or the default branch.
@@ -88,7 +89,7 @@ always performs keyword substitution (see below).
.TP
.BR \-r [\f2rev\fP]
retrieves the latest revision whose number is less than or equal to
-.I rev.
+.IR rev .
If
.I rev
indicates a branch rather than a revision,
@@ -108,7 +109,16 @@ is
.B co
determines the revision number from keyword values in the working file.
Otherwise, a revision is composed of one or more numeric or symbolic fields
-separated by periods. The numeric equivalent of a symbolic field
+separated by periods.
+If
+.I rev
+begins with a period,
+then the default branch (normally the trunk) is prepended to it.
+If
+.I rev
+is a branch number followed by a period,
+then the latest revision on that branch is used.
+The numeric equivalent of a symbolic field
is specified with the
.B \-n
option of the commands
@@ -166,7 +176,7 @@ Like
except that a locker's name is always inserted
if the given revision is currently locked.
.TP
-.BR \-kk
+.B \-kk
Generate only keyword names in keyword strings; omit their values.
See
.SM "KEYWORD SUBSTITUTION"
@@ -176,11 +186,17 @@ For example, for the
keyword, generate the string
.B $\&Revision$
instead of
-.BR "$\&Revision: \*(Rv $".
+.BR "$\&Revision: \*(Rv $" .
This option is useful to ignore differences due to keyword substitution
when comparing different revisions of a file.
+Log messages are inserted after
+.B $\&Log$
+keywords even if
+.B \-kk
+is specified,
+since this tends to be more useful when merging changes.
.TP
-.BR \-ko
+.B \-ko
Generate the old keyword string,
present in the working file just before it was checked in.
For example, for the
@@ -190,18 +206,33 @@ keyword, generate the string
instead of
.B "$\&Revision: \*(Rv $"
if that is how the string appeared when the file was checked in.
-This can be useful for binary file formats
+This can be useful for file formats
that cannot tolerate any changes to substrings
that happen to take the form of keyword strings.
.TP
-.BR \-kv
+.B \-kb
+Generate a binary image of the old keyword string.
+This acts like
+.BR \-ko ,
+except it performs all working file input and output in binary mode.
+This makes little difference on Posix and Unix hosts,
+but on DOS-like hosts one should use
+.B "rcs\ \-i\ \-kb"
+to initialize an \*r file intended to be used for binary files.
+Also, on all hosts,
+.BR rcsmerge (1)
+normally refuses to merge files when
+.B \-kb
+is in effect.
+.TP
+.B \-kv
Generate only keyword values for keyword strings.
For example, for the
.B Revision
keyword, generate the string
.B \*(Rv
instead of
-.BR "$\&Revision: \*(Rv $".
+.BR "$\&Revision: \*(Rv $" .
This can help generate files in programming languages where it is hard to
strip keyword delimiters like
.B "$\&Revision:\ $"
@@ -233,8 +264,8 @@ even if the standard input is not a terminal.
.BI \-d date
retrieves the latest revision on the selected branch whose checkin date/time is
less than or equal to
-.I date.
-The date and time may be given in free format.
+.IR date .
+The date and time can be given in free format.
The time zone
.B LT
stands for local time;
@@ -243,38 +274,43 @@ For example, the following
.IR date s
are equivalent
if local time is January 11, 1990, 8pm Pacific Standard Time,
-eight hours west of Coordinated Universal Time (\*g):
+eight hours west of Coordinated Universal Time (\*u):
.RS
.LP
.RS
.nf
.ta \w'\f3Thu, 11 Jan 1990 20:00:00 \-0800\fP 'u
-.ne 9
+.ne 10
\f38:00 pm lt\fP
-\f34:00 AM, Jan. 12, 1990\fP note: default is \*g
-\f31990/01/12 04:00:00\fP \*r date format
+\f34:00 AM, Jan. 12, 1990\fP default is \*u
+\f31990-01-12 04:00:00+00\fP \*i 8601 (\*u)
+\f31990-01-11 20:00:00\-08\fP \*i 8601 (local time)
+\f31990/01/12 04:00:00\fP traditional \*r format
\f3Thu Jan 11 20:00:00 1990 LT\fP output of \f3ctime\fP(3) + \f3LT\fP
\f3Thu Jan 11 20:00:00 PST 1990\fP output of \f3date\fP(1)
\f3Fri Jan 12 04:00:00 GMT 1990\fP
-\f3Thu, 11 Jan 1990 20:00:00 \-0800\fP
-\f3Fri-JST, 1990, 1pm Jan 12\fP
-\f312-January-1990, 04:00-WET\fP
+\f3Thu, 11 Jan 1990 20:00:00 \-0800\fP Internet RFC 822
+\f312-January-1990, 04:00 WET\fP
.ta 4n +4n +4n +4n
.fi
.RE
.LP
-Most fields in the date and time may be defaulted.
-The default time zone is \*g.
+Most fields in the date and time can be defaulted.
+The default time zone is normally \*u, but this can be overridden by the
+.B \-z
+option.
The other defaults are determined in the order year, month, day,
hour, minute, and second (most to least significant). At least one of these
fields must be provided. For omitted fields that are of higher significance
than the highest provided field, the time zone's current values are assumed.
For all other omitted fields,
the lowest possible values are assumed.
-For example, the date
+For example, without
+.BR \-z ,
+the date
.B "20, 10:30"
defaults to
-10:30:00 \*g of the 20th of the \*g time zone's current month and year.
+10:30:00 \*u of the 20th of the \*u time zone's current month and year.
The date/time must be quoted if it contains spaces.
.RE
.TP
@@ -286,12 +322,22 @@ Use this option with care; it can confuse
.TP
.BI \-s state
retrieves the latest revision on the selected branch whose state is set to
-.I state.
+.IR state .
+.TP
+.B \-T
+Preserve the modification time on the \*r file
+even if the \*r file changes because a lock is added or removed.
+This option can suppress extensive recompilation caused by a
+.BR make (1)
+dependency of some other copy of the working file on the \*r file.
+Use this option with care; it can suppress recompilation even when it is needed,
+i.e. when the change of lock
+would mean a change to keyword strings in the other working file.
.TP
.BR \-w [\f2login\fP]
retrieves the latest revision on the selected branch which was checked in
by the user with login name
-.I login.
+.IR login .
If the argument
.I login
is
@@ -299,7 +345,7 @@ omitted, the caller's login is assumed.
.TP
.BI \-j joinlist
generates a new revision which is the join of the revisions on
-.I joinlist.
+.IR joinlist .
This option is largely obsoleted by
.BR rcsmerge (1)
but is retained for backwards compatibility.
@@ -319,7 +365,7 @@ For the initial such pair,
.I rev1
denotes the revision selected
by the above options
-.BR \-f,
+.BR \-f ,
\&.\|.\|.,
.BR \-w .
For all other pairs,
@@ -335,13 +381,13 @@ joins revisions
and
.I rev3
with respect to
-.I rev2.
+.IR rev2 .
This means that all changes that transform
.I rev2
into
.I rev1
are applied to a copy of
-.I rev3.
+.IR rev3 .
This is particularly useful if
.I rev1
and
@@ -372,7 +418,7 @@ reports overlaps as described in
.PP
For the initial pair,
.I rev2
-may be omitted. The default is the common
+can be omitted. The default is the common
ancestor.
If any of the arguments indicate branches, the latest revisions
on those branches are assumed.
@@ -381,22 +427,28 @@ The options
and
.B \-u
lock or unlock
-.I rev1.
+.IR rev1 .
.RE
.TP
+.BI \-V
+Print \*r's version number.
+.TP
.BI \-V n
Emulate \*r version
.I n,
where
.I n
-may be
+can be
.BR 3 ,
.BR 4 ,
or
.BR 5 .
-This may be useful when interchanging \*r files with others who are
+This can be useful when interchanging \*r files with others who are
running older versions of \*r.
To see which version of \*r your correspondents are running, have them invoke
+.BR "rcs \-V" ;
+this works with newer versions of \*r.
+If it doesn't work, have them invoke
.B rlog
on an \*r file;
if none of the first few lines of output contain the string
@@ -404,15 +456,14 @@ if none of the first few lines of output contain the string
it is version 3;
if the dates' years have just two digits, it is version 4;
otherwise, it is version 5.
-An \*r file generated while emulating version 3 will lose its default branch.
-An \*r revision generated while emulating version 4 or earlier will have
-a timestamp that is off by up to 13 hours.
-A revision extracted while emulating version 4 or earlier will contain
-dates of the form
+An \*r file generated while emulating version 3 loses its default branch.
+An \*r revision generated while emulating version 4 or earlier has
+a time stamp that is off by up to 13 hours.
+A revision extracted while emulating version 4 or earlier contains
+abbreviated dates of the form
.IB yy / mm / dd
-instead of
-.IB yyyy / mm / dd
-and may also contain different white space in the substitution for
+and can also contain different white space and line prefixes
+in the substitution for
.BR $\&Log$ .
.TP
.BI \-x "suffixes"
@@ -422,6 +473,46 @@ to characterize \*r files.
See
.BR ci (1)
for details.
+.TP
+.BI \-z zone
+specifies the date output format in keyword substitution,
+and specifies the default time zone for
+.I date
+in the
+.BI \-d date
+option.
+The
+.I zone
+should be empty, a numeric \*u offset, or the special string
+.B LT
+for local time.
+The default is an empty
+.IR zone ,
+which uses the traditional \*r format of \*u without any time zone indication
+and with slashes separating the parts of the date;
+otherwise, times are output in \*i 8601 format with time zone indication.
+For example, if local time is January 11, 1990, 8pm Pacific Standard Time,
+eight hours west of \*u,
+then the time is output as follows:
+.RS
+.LP
+.RS
+.nf
+.ta \w'\f3\-z+05:30\fP 'u +\w'\f31990-01-11 09:30:00+05:30\fP 'u
+.ne 4
+\f2option\fP \f2time output\fP
+\f3\-z\fP \f31990/01/12 04:00:00\fP \f2(default)\fP
+\f3\-zLT\fP \f31990-01-11 20:00:00\-08\fP
+\f3\-z+05:30\fP \f31990-01-12 09:30:00+05:30\fP
+.ta 4n +4n +4n +4n
+.fi
+.RE
+.LP
+The
+.B \-z
+option does not affect dates stored in \*r files,
+which are always \*u.
+.RE
.SH "KEYWORD SUBSTITUTION"
Strings of the form
.BI $ keyword $
@@ -436,7 +527,7 @@ where
and
.I value
are pairs listed below.
-Keywords may be embedded in literal strings
+Keywords can be embedded in literal strings
or comments to identify a revision.
.PP
Initially, the user enters strings of the form
@@ -459,12 +550,18 @@ Keywords and their corresponding values:
The login name of the user who checked in the revision.
.TP
.B $\&Date$
-The date and time (\*g) the revision was checked in.
+The date and time the revision was checked in.
+With
+.BI \-z zone
+a numeric time zone offset is appended; otherwise, the date is \*u.
.TP
.B $\&Header$
A standard header containing the full pathname of the \*r file, the
-revision number, the date (\*g), the author, the state,
+revision number, the date and time, the author, the state,
and the locker (if locked).
+With
+.BI \-z zone
+a numeric time zone offset is appended to the date; otherwise, the date is \*u.
.TP
.B $\&Id$
Same as
@@ -477,7 +574,10 @@ The login name of the user who locked the revision (empty if not locked).
.B $\&Log$
The log message supplied during checkin, preceded by a header
containing the \*r filename, the revision number, the author, and the date
-(\*g).
+and time.
+With
+.BI \-z zone
+a numeric time zone offset is appended; otherwise, the date is \*u.
Existing log messages are
.I not
replaced.
@@ -485,6 +585,58 @@ Instead, the new log message is inserted after
.BR $\&Log: .\|.\|. $ .
This is useful for
accumulating a complete change log in a source file.
+.RS
+.LP
+Each inserted line is prefixed by the string that prefixes the
+.B $\&Log$
+line. For example, if the
+.B $\&Log$
+line is
+.RB \*(lq "//\ $\&Log: tan.cc\ $" \*(rq,
+\*r prefixes each line of the log with
+.RB \*(lq "//\ " \*(rq.
+This is useful for languages with comments that go to the end of the line.
+The convention for other languages is to use a
+.RB \*(lq " \(** " \(rq
+prefix inside a multiline comment.
+For example, the initial log comment of a C program
+conventionally is of the following form:
+.RS
+.LP
+.nf
+.ft 3
+.ne 3
+/\(**
+.in +\w'/'u
+\(** $\&Log$
+\(**/
+.in
+.ft
+.fi
+.RE
+.LP
+For backwards compatibility with older versions of \*r, if the log prefix is
+.B /\(**
+or
+.B (\(**
+surrounded by optional white space, inserted log lines contain a space
+instead of
+.B /
+or
+.BR ( ;
+however, this usage is obsolescent and should not be relied on.
+.RE
+.TP
+.B $\&Name$
+The symbolic name used to check out the revision, if any.
+For example,
+.B "co\ \-rJoe"
+generates
+.BR "$\&Name:\ Joe\ $" .
+Plain
+.B co
+generates just
+.BR "$\&Name:\ \ $" .
.TP
.B $\&RCSfile$
The name of the \*r file without a path.
@@ -502,6 +654,22 @@ option of
.BR rcs (1)
or
.BR ci (1).
+.PP
+The following characters in keyword values are represented by escape sequences
+to keep keyword strings well-formed.
+.LP
+.RS
+.nf
+.ne 6
+.ta \w'newline 'u
+\f2char escape sequence\fP
+tab \f3\et\fP
+newline \f3\en\fP
+space \f3\e040
+$ \e044
+\e \e\e\fP
+.fi
+.RE
.SH "FILE MODES"
The working file inherits the read and execute permissions from the \*r
file. In addition, the owner write permission is turned on, unless
@@ -523,7 +691,10 @@ is given, the working file is deleted without asking.
.B co
accesses files much as
.BR ci (1)
-does, except that it does not need to read the working file.
+does, except that it does not need to read the working file
+unless a revision number of
+.B $
+is specified.
.SH ENVIRONMENT
.TP
.B \s-1RCSINIT\s0
@@ -539,14 +710,14 @@ The exit status is zero if and only if all operations were successful.
.SH IDENTIFICATION
Author: Walter F. Tichy.
.br
-Revision Number: \*(Rv; Release Date: \*(Dt.
+Manual Page Revision: \*(Rv; Release Date: \*(Dt.
.br
-Copyright \(co 1982, 1988, 1989 by Walter F. Tichy.
+Copyright \(co 1982, 1988, 1989 Walter F. Tichy.
.br
-Copyright \(co 1990, 1991 by Paul Eggert.
+Copyright \(co 1990, 1991, 1992, 1993, 1994, 1995 Paul Eggert.
.SH "SEE ALSO"
-ci(1), ctime(3), date(1), ident(1), make(1),
-rcs(1), rcsdiff(1), rcsintro(1), rcsmerge(1), rlog(1),
+rcsintro(1), ci(1), ctime(3), date(1), ident(1), make(1),
+rcs(1), rcsclean(1), rcsdiff(1), rcsmerge(1), rlog(1),
rcsfile(5)
.br
Walter F. Tichy,
@@ -562,8 +733,4 @@ by writing them differently. In nroff and troff, this is done by embedding the
null-character
.B \e&
into the keyword.
-.SH BUGS
-The
-.B \-d
-option sometimes gets confused, and accepts no date before 1970.
.br
diff --git a/gnu/usr.bin/rcs/co/co.c b/gnu/usr.bin/rcs/co/co.c
index 9435574..91da3ef 100644
--- a/gnu/usr.bin/rcs/co/co.c
+++ b/gnu/usr.bin/rcs/co/co.c
@@ -1,5 +1,7 @@
-/* Copyright (C) 1982, 1988, 1989 Walter Tichy
- Copyright 1990, 1991 by Paul Eggert
+/* Check out working files from revisions of RCS files. */
+
+/* Copyright 1982, 1988, 1989 Walter Tichy
+ Copyright 1990, 1991, 1992, 1993, 1994, 1995 Paul Eggert
Distributed under license by the Free Software Foundation, Inc.
This file is part of RCS.
@@ -15,8 +17,9 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
-along with RCS; see the file COPYING. If not, write to
-the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+along with RCS; see the file COPYING.
+If not, write to the Free Software Foundation,
+59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
Report problems and direct all questions to:
@@ -25,17 +28,39 @@ Report problems and direct all questions to:
*/
/*
- * RCS checkout operation
- */
-/*****************************************************************************
- * check out revisions from RCS files
- *****************************************************************************
- */
-
-
-/* $Log: co.c,v $
+ * Revision 5.18 1995/06/16 06:19:24 eggert
+ * Update FSF address.
+ *
+ * Revision 5.17 1995/06/01 16:23:43 eggert
+ * (main, preparejoin): Pass argument instead of using `join' static variable.
+ * (main): Add -kb.
+ *
+ * Revision 5.16 1994/03/17 14:05:48 eggert
+ * Move buffer-flushes out of critical sections, since they aren't critical.
+ * Use ORCSerror to clean up after a fatal error. Remove lint.
+ * Specify subprocess input via file descriptor, not file name.
+ *
+ * Revision 5.15 1993/11/09 17:40:15 eggert
+ * -V now prints version on stdout and exits. Don't print usage twice.
+ *
+ * Revision 5.14 1993/11/03 17:42:27 eggert
+ * Add -z. Generate a value for the Name keyword.
+ * Don't arbitrarily limit the number of joins.
+ * Improve quality of diagnostics.
+ *
+ * Revision 5.13 1992/07/28 16:12:44 eggert
+ * Add -V. Check that working and RCS files are distinct.
+ *
+ * Revision 5.12 1992/02/17 23:02:08 eggert
+ * Add -T.
+ *
+ * Revision 5.11 1992/01/24 18:44:19 eggert
+ * Add support for bad_creat0. lint -> RCS_lint
+ *
+ * Revision 5.10 1992/01/06 02:42:34 eggert
+ * Update usage string.
+ *
* Revision 5.9 1991/10/07 17:32:46 eggert
- * ci -u src/RCS/co.c,v src/co.c <<\.
* -k affects just working file, not RCS file.
*
* Revision 5.8 1991/08/19 03:13:55 eggert
@@ -71,28 +96,28 @@ Report problems and direct all questions to:
*
* Revision 4.7 89/05/01 15:11:41 narten
* changed copyright header to reflect current distribution rules
- *
+ *
* Revision 4.6 88/08/09 19:12:15 eggert
* Fix "co -d" core dump; rawdate wasn't always initialized.
* Use execv(), not system(); fix putchar('\0') and diagnose() botches; remove lint
- *
+ *
* Revision 4.5 87/12/18 11:35:40 narten
* lint cleanups (from Guy Harris)
- *
+ *
* Revision 4.4 87/10/18 10:20:53 narten
* Updating version numbers changes relative to 1.1, are actually
* relative to 4.2
- *
+ *
* Revision 1.3 87/09/24 13:58:30 narten
- * Sources now pass through lint (if you ignore printf/sprintf/fprintf
+ * Sources now pass through lint (if you ignore printf/sprintf/fprintf
* warnings)
- *
+ *
* Revision 1.2 87/03/27 14:21:38 jenkins
* Port to suns
- *
+ *
* Revision 4.2 83/12/05 13:39:48 wft
* made rewriteflag external.
- *
+ *
* Revision 4.1 83/05/10 16:52:55 wft
* Added option -u and -f.
* Added handling of default branch.
@@ -100,7 +125,7 @@ Report problems and direct all questions to:
* Removed calls to stat(); now done by pairfilenames().
* Changed and renamed rmoldfile() to rmworkfile().
* Replaced catchints() calls with restoreints(), unlink()--link() with rename();
- *
+ *
* Revision 3.7 83/02/15 15:27:07 wft
* Added call to fastcopy() to copy remainder of RCS file.
*
@@ -143,17 +168,19 @@ Report problems and direct all questions to:
#include "rcsbase.h"
+static char *addjoin P((char*));
static char const *getancestor P((char const*,char const*));
static int buildjoin P((char const*));
-static int preparejoin P((void));
+static int preparejoin P((char*));
static int rmlock P((struct hshentry const*));
static int rmworkfile P((void));
static void cleanup P((void));
static char const quietarg[] = "-q";
-static char const *expandarg, *join, *suffixarg, *versionarg;
-static char const *joinlist[joinlength]; /* revisions to be joined */
+static char const *expandarg, *suffixarg, *versionarg, *zonearg, *incexcarg;
+static char const **joinlist; /* revisions to be joined */
+static int joinlength;
static FILE *neworkptr;
static int exitstatus;
static int forceflag;
@@ -164,25 +191,31 @@ static struct hshentries *gendeltas; /* deltas to be generated */
static struct hshentry *targetdelta; /* final delta to be generated */
static struct stat workstat;
-mainProg(coId, "co", "$Id: co.c,v 5.9 1991/10/07 17:32:46 eggert Exp $")
+mainProg(coId, "co", "$Id: co.c,v 1.5 1995/10/29 19:31:07 peter Exp $")
{
static char const cmdusage[] =
- "\nco usage: co -{flpqru}[rev] -ddate -jjoinlist -sstate -w[login] -Vn file ...";
+ "\nco usage: co -{fIlMpqru}[rev] -ddate -jjoins -ksubst -sstate -T -w[who] -Vn -xsuff -zzone file ...";
- char *a, **newargv;
+ char *a, *joinflag, **newargv;
char const *author, *date, *rev, *state;
- char const *joinfilename, *newdate, *neworkfilename;
+ char const *joinname, *newdate, *neworkname;
int changelock; /* 1 if a lock has been changed, -1 if error */
int expmode, r, tostdout, workstatstat;
+ int Ttimeflag;
struct buf numericrev; /* expanded revision number */
char finaldate[datesize];
+# if OPEN_O_BINARY
+ int stdout_mode = 0;
+# endif
setrid();
- author = date = rev = state = nil;
+ author = date = rev = state = 0;
+ joinflag = 0;
bufautobegin(&numericrev);
expmode = -1;
suffixes = X_DEFAULT;
tostdout = false;
+ Ttimeflag = false;
argc = getRCSINIT(argc, argv, &newargv);
argv = newargv;
@@ -203,14 +236,14 @@ mainProg(coId, "co", "$Id: co.c,v 5.9 1991/10/07 17:32:46 eggert Exp $")
case 'l':
if (lockflag < 0) {
- warn("-l overrides -u.");
+ warn("-u overridden by -l.");
}
lockflag = 1;
goto revno;
case 'u':
if (0 < lockflag) {
- warn("-l overrides -u.");
+ warn("-l overridden by -u.");
}
lockflag = -1;
goto revno;
@@ -236,8 +269,8 @@ mainProg(coId, "co", "$Id: co.c,v 5.9 1991/10/07 17:32:46 eggert Exp $")
case 'j':
if (*a) {
- if (join) redefined('j');
- join = a;
+ if (joinflag) redefined('j');
+ joinflag = a;
}
break;
@@ -252,6 +285,12 @@ mainProg(coId, "co", "$Id: co.c,v 5.9 1991/10/07 17:32:46 eggert Exp $")
}
break;
+ case 'T':
+ if (*a)
+ goto unknown;
+ Ttimeflag = true;
+ break;
+
case 'w':
if (author) redefined('w');
if (*a)
@@ -270,6 +309,16 @@ mainProg(coId, "co", "$Id: co.c,v 5.9 1991/10/07 17:32:46 eggert Exp $")
setRCSversion(versionarg);
break;
+ case 'z':
+ zonearg = *argv;
+ zone_set(a);
+ break;
+
+ case 'K': /* set keyword inclusions/exclusions */
+ incexcarg = *argv;
+ setIncExc(incexcarg);
+ break;
+
case 'k': /* set keyword expand mode */
expandarg = *argv;
if (0 <= expmode) redefined('k');
@@ -277,69 +326,81 @@ mainProg(coId, "co", "$Id: co.c,v 5.9 1991/10/07 17:32:46 eggert Exp $")
break;
/* fall into */
default:
- faterror("unknown option: %s%s", *argv, cmdusage);
+ unknown:
+ error("unknown option: %s%s", *argv, cmdusage);
};
} /* end of option processing */
- if (argc<1) faterror("no input file%s", cmdusage);
- if (tostdout)
-# if text_equals_binary_stdio || text_work_stdio
- workstdout = stdout;
-# else
- if (!(workstdout = fdopen(STDOUT_FILENO, FOPEN_W_WORK)))
- efaterror("stdout");
-# endif
-
- /* now handle all filenames */
- do {
+ /* Now handle all pathnames. */
+ if (nerror) cleanup();
+ else if (argc < 1) faterror("no input file%s", cmdusage);
+ else for (; 0 < argc; cleanup(), ++argv, --argc) {
ffree();
- if (pairfilenames(argc, argv, lockflag?rcswriteopen:rcsreadopen, true, false) <= 0)
+ if (pairnames(argc, argv, lockflag?rcswriteopen:rcsreadopen, true, false) <= 0)
continue;
- /* now RCSfilename contains the name of the RCS file, and finptr
- * points at it. workfilename contains the name of the working file.
+ /*
+ * RCSname contains the name of the RCS file, and finptr
+ * points at it. workname contains the name of the working file.
* Also, RCSstat has been set.
*/
- diagnose("%s --> %s\n", RCSfilename,tostdout?"stdout":workfilename);
+ diagnose("%s --> %s\n", RCSname, tostdout?"standard output":workname);
workstatstat = -1;
if (tostdout) {
- neworkfilename = 0;
- neworkptr = workstdout;
+# if OPEN_O_BINARY
+ int newmode = Expand==BINARY_EXPAND ? OPEN_O_BINARY : 0;
+ if (stdout_mode != newmode) {
+ stdout_mode = newmode;
+ oflush();
+ VOID setmode(STDOUT_FILENO, newmode);
+ }
+# endif
+ neworkname = 0;
+ neworkptr = workstdout = stdout;
} else {
- workstatstat = stat(workfilename, &workstat);
- neworkfilename = makedirtemp(workfilename, 1);
- if (!(neworkptr = fopen(neworkfilename, FOPEN_W_WORK))) {
+ workstatstat = stat(workname, &workstat);
+ if (workstatstat == 0 && same_file(RCSstat, workstat, 0)) {
+ rcserror("RCS file is the same as working file %s.",
+ workname
+ );
+ continue;
+ }
+ neworkname = makedirtemp(1);
+ if (!(neworkptr = fopenSafer(neworkname, FOPEN_W_WORK))) {
if (errno == EACCES)
- error("%s: parent directory isn't writable",
- workfilename
- );
+ workerror("permission denied on parent directory");
else
- eerror(neworkfilename);
+ eerror(neworkname);
continue;
}
}
gettree(); /* reads in the delta tree */
- if (Head==nil) {
+ if (!Head) {
/* no revisions; create empty file */
diagnose("no revisions present; generating empty revision 0.0\n");
+ if (lockflag)
+ warn(
+ "no revisions, so nothing can be %slocked",
+ lockflag < 0 ? "un" : ""
+ );
Ozclose(&fcopy);
if (workstatstat == 0)
if (!rmworkfile()) continue;
changelock = 0;
newdate = 0;
- /* Can't reserve a delta, so don't call addlock */
} else {
- if (rev!=nil) {
+ int locks = lockflag ? findlock(false, &targetdelta) : 0;
+ if (rev) {
/* expand symbolic revision number */
if (!expandsym(rev, &numericrev))
continue;
- } else
- switch (lockflag<0 ? findlock(false,&targetdelta) : 0) {
+ } else {
+ switch (locks) {
default:
continue;
case 0:
@@ -349,6 +410,7 @@ mainProg(coId, "co", "$Id: co.c,v 5.9 1991/10/07 17:32:46 eggert Exp $")
bufscpy(&numericrev, targetdelta->num);
break;
}
+ }
/* get numbers of deltas to be generated */
if (!(targetdelta=genrevs(numericrev.string,date,author,state,&gendeltas)))
continue;
@@ -359,23 +421,24 @@ mainProg(coId, "co", "$Id: co.c,v 5.9 1991/10/07 17:32:46 eggert Exp $")
: lockflag == 0 ?
0
:
- addlock(targetdelta);
+ addlock(targetdelta, true);
if (
- changelock < 0 ||
- changelock && !checkaccesslist() ||
- !dorewrite(lockflag, changelock)
+ changelock < 0
+ || (changelock && !checkaccesslist())
+ || dorewrite(lockflag, changelock) != 0
)
continue;
if (0 <= expmode)
Expand = expmode;
if (0 < lockflag && Expand == VAL_EXPAND) {
- error("cannot combine -kv and -l");
+ rcserror("cannot combine -kv and -l");
continue;
}
- if (join && !preparejoin()) continue;
+ if (joinflag && !preparejoin(joinflag))
+ continue;
diagnose("revision %s%s\n",targetdelta->num,
0<lockflag ? " (locked)" :
@@ -389,10 +452,11 @@ mainProg(coId, "co", "$Id: co.c,v 5.9 1991/10/07 17:32:46 eggert Exp $")
getdesc(false); /* don't echo*/
locker_expansion = 0 < lockflag;
- joinfilename = buildrevision(
+ targetdelta->name = namedrev(rev, targetdelta);
+ joinname = buildrevision(
gendeltas, targetdelta,
- join&&tostdout ? (FILE*)0 : neworkptr,
- Expand!=OLD_EXPAND
+ joinflag&&tostdout ? (FILE*)0 : neworkptr,
+ Expand < MIN_UNEXPAND
);
# if !large_memory
if (fcopy == neworkptr)
@@ -402,46 +466,48 @@ mainProg(coId, "co", "$Id: co.c,v 5.9 1991/10/07 17:32:46 eggert Exp $")
finptr, MADV_SEQUENTIAL
);
- if (!donerewrite(changelock))
+ if (donerewrite(changelock,
+ Ttimeflag ? RCSstat.st_mtime : (time_t)-1
+ ) != 0)
continue;
+ if (changelock) {
+ locks += lockflag;
+ if (1 < locks)
+ rcswarn("You now have %d locks.", locks);
+ }
+
newdate = targetdelta->date;
- if (join) {
+ if (joinflag) {
newdate = 0;
- if (!joinfilename) {
+ if (!joinname) {
aflush(neworkptr);
- joinfilename = neworkfilename;
+ joinname = neworkname;
}
- if (!buildjoin(joinfilename))
+ if (Expand == BINARY_EXPAND)
+ workerror("merging binary files");
+ if (!buildjoin(joinname))
continue;
}
}
if (!tostdout) {
- r = 0;
- if (mtimeflag && newdate) {
- if (!join)
- aflush(neworkptr);
- r = setfiledate(neworkfilename, newdate);
- }
- if (r == 0) {
- ignoreints();
- r = chnamemod(&neworkptr, neworkfilename, workfilename,
- WORKMODE(RCSstat.st_mode,
- !(Expand==VAL_EXPAND || lockflag<=0&&StrictLocks)
- )
- );
- keepdirtemp(neworkfilename);
- restoreints();
- }
+ mode_t m = WORKMODE(RCSstat.st_mode,
+ ! (Expand==VAL_EXPAND || (lockflag<=0 && StrictLocks))
+ );
+ time_t t = mtimeflag&&newdate ? date2time(newdate) : (time_t)-1;
+ aflush(neworkptr);
+ ignoreints();
+ r = chnamemod(&neworkptr, neworkname, workname, 1, m, t);
+ keepdirtemp(neworkname);
+ restoreints();
if (r != 0) {
- eerror(workfilename);
- error("see %s", neworkfilename);
+ eerror(workname);
+ error("see %s", neworkname);
continue;
}
diagnose("done\n");
}
- } while (cleanup(),
- ++argv, --argc >=1);
+ }
tempunlink();
Ofclose(workstdout);
@@ -454,7 +520,7 @@ cleanup()
{
if (nerror) exitstatus = EXIT_FAILURE;
Izclose(&finptr);
- Ozclose(&frewrite);
+ ORCSclose();
# if !large_memory
if (fcopy!=workstdout) Ozclose(&fcopy);
# endif
@@ -462,12 +528,13 @@ cleanup()
dirtempunlink();
}
-#if lint
+#if RCS_lint
# define exiterr coExit
#endif
- exiting void
+ void
exiterr()
{
+ ORCSerror();
dirtempunlink();
tempunlink();
_exit(EXIT_FAILURE);
@@ -480,7 +547,8 @@ exiterr()
static int
rmworkfile()
-/* Function: prepares to remove workfilename, if it exists, and if
+/*
+ * Prepare to remove workname, if it exists, and if
* it is read-only.
* Otherwise (file writable):
* if !quietmode asks the user whether to really delete it (default: fail);
@@ -491,12 +559,12 @@ rmworkfile()
if (workstat.st_mode&(S_IWUSR|S_IWGRP|S_IWOTH) && !forceflag) {
/* File is writable */
if (!yesorno(false, "writable %s exists%s; remove it? [ny](n): ",
- workfilename,
+ workname,
myself(workstat.st_uid) ? "" : ", and you do not own it"
)) {
error(!quietflag && ttystdin()
? "checkout aborted"
- : "writable %s exists; checkout aborted", workfilename);
+ : "writable %s exists; checkout aborted", workname);
return false;
}
}
@@ -513,31 +581,33 @@ rmlock(delta)
* 0 if there is no lock on delta,
* and 1 if a lock was found and removed.
*/
-{ register struct lock * next, * trail;
+{ register struct rcslock * next, * trail;
char const *num;
- struct lock dummy;
+ struct rcslock dummy;
int whomatch, nummatch;
num=delta->num;
dummy.nextlock=next=Locks;
trail = &dummy;
- while (next!=nil) {
+ while (next) {
whomatch = strcmp(getcaller(), next->login);
nummatch=strcmp(num,next->delta->num);
if ((whomatch==0) && (nummatch==0)) break;
/*found a lock on delta by caller*/
if ((whomatch!=0)&&(nummatch==0)) {
- error("revision %s locked by %s; use co -r or rcs -u",num,next->login);
+ rcserror("revision %s locked by %s; use co -r or rcs -u",
+ num, next->login
+ );
return -1;
}
trail=next;
next=next->nextlock;
}
- if (next!=nil) {
+ if (next) {
/*found one; delete it */
trail->nextlock=next->nextlock;
Locks=dummy.nextlock;
- next->delta->lockedby=nil; /* reset locked-by */
+ next->delta->lockedby = 0;
return 1; /*success*/
} else return 0; /*no lock on delta*/
}
@@ -550,15 +620,15 @@ rmlock(delta)
*****************************************************************/
- static char const *
+ static char *
addjoin(joinrev)
char *joinrev;
/* Add joinrev's number to joinlist, yielding address of char past joinrev,
- * or nil if no such revision exists.
+ * or 0 if no such revision exists.
*/
{
register char *j;
- register struct hshentry const *d;
+ register struct hshentry *d;
char terminator;
struct buf numrev;
struct hshentries *joindeltas;
@@ -580,32 +650,32 @@ addjoin(joinrev)
bufautobegin(&numrev);
d = 0;
if (expandsym(joinrev, &numrev))
- d = genrevs(numrev.string,(char*)nil,(char*)nil,(char*)nil,&joindeltas);
+ d = genrevs(numrev.string,(char*)0,(char*)0,(char*)0,&joindeltas);
bufautoend(&numrev);
*j = terminator;
if (d) {
joinlist[++lastjoin] = d->num;
return j;
}
- return nil;
+ return 0;
}
static int
-preparejoin()
-/* Function: Parses a join list pointed to by join and places pointers to the
+preparejoin(j)
+ register char *j;
+/* Parse join list J and place pointers to the
* revision numbers into joinlist.
*/
{
- register char const *j;
-
- j=join;
lastjoin= -1;
for (;;) {
while ((*j==' ')||(*j=='\t')||(*j==',')) j++;
if (*j=='\0') break;
if (lastjoin>=joinlength-2) {
- error("too many joins");
- return(false);
+ joinlist =
+ (joinlength *= 2) == 0
+ ? tnalloc(char const *, joinlength = 16)
+ : trealloc(char const *, joinlist, joinlength);
}
if (!(j = addjoin(j))) return false;
while ((*j==' ') || (*j=='\t')) j++;
@@ -615,8 +685,7 @@ preparejoin()
if (*j!='\0') {
if (!(j = addjoin(j))) return false;
} else {
- error("join pair incomplete");
- return false;
+ rcsfaterror("join pair incomplete");
}
} else {
if (lastjoin==0) { /* first pair */
@@ -627,15 +696,13 @@ preparejoin()
if (!(joinlist[0] = getancestor(targetdelta->num,joinlist[1])))
return false;
} else {
- error("join pair incomplete");
- return false;
+ rcsfaterror("join pair incomplete");
}
}
}
- if (lastjoin<1) {
- error("empty join");
- return false;
- } else return true;
+ if (lastjoin < 1)
+ rcsfaterror("empty join");
+ return true;
}
@@ -643,13 +710,13 @@ preparejoin()
static char const *
getancestor(r1, r2)
char const *r1, *r2;
-/* Yield the common ancestor of r1 and r2 if successful, nil otherwise.
+/* Yield the common ancestor of r1 and r2 if successful, 0 otherwise.
* Work reliably only if r1 and r2 are not branch numbers.
*/
{
static struct buf t1, t2;
- unsigned l1, l2, l3;
+ int l1, l2, l3;
char const *r;
l1 = countnumflds(r1);
@@ -662,16 +729,16 @@ getancestor(r1, r2)
/* This will terminate since r1 and r2 are not the same; see above. */
if (l3==0) {
/* no common prefix; common ancestor on main trunk */
- VOID partialno(&t1, r1, l1>2 ? (unsigned)2 : l1);
- VOID partialno(&t2, r2, l2>2 ? (unsigned)2 : l2);
+ VOID partialno(&t1, r1, l1>2 ? 2 : l1);
+ VOID partialno(&t2, r2, l2>2 ? 2 : l2);
r = cmpnum(t1.string,t2.string)<0 ? t1.string : t2.string;
if (cmpnum(r,r1)!=0 && cmpnum(r,r2)!=0)
return r;
} else if (cmpnumfld(r1, r2, l3+1)!=0)
return partialno(&t1,r1,l3);
}
- error("common ancestor of %s and %s undefined", r1, r2);
- return nil;
+ rcserror("common ancestor of %s and %s undefined", r1, r2);
+ return 0;
}
@@ -688,7 +755,7 @@ buildjoin(initialfile)
struct buf subs;
char const *rev2, *rev3;
int i;
- char const *cov[10], *mergev[12];
+ char const *cov[10], *mergev[11];
char const **p;
bufautobegin(&commarg);
@@ -696,22 +763,19 @@ buildjoin(initialfile)
rev2 = maketemp(0);
rev3 = maketemp(3); /* buildrevision() may use 1 and 2 */
- cov[0] = nil;
- /* cov[1] setup below */
- cov[2] = CO;
- /* cov[3] setup below */
- p = &cov[4];
+ cov[1] = CO;
+ /* cov[2] setup below */
+ p = &cov[3];
if (expandarg) *p++ = expandarg;
if (suffixarg) *p++ = suffixarg;
if (versionarg) *p++ = versionarg;
+ if (zonearg) *p++ = zonearg;
*p++ = quietarg;
- *p++ = RCSfilename;
- *p = nil;
+ *p++ = RCSname;
+ *p = 0;
- mergev[0] = nil;
- mergev[1] = nil;
- mergev[2] = MERGE;
- mergev[3] = mergev[5] = "-L";
+ mergev[1] = MERGE;
+ mergev[2] = mergev[4] = "-L";
/* rest of mergev setup below */
i=0;
@@ -728,28 +792,26 @@ buildjoin(initialfile)
diagnose("revision %s\n",joinlist[i]);
bufscpy(&commarg, "-p");
bufscat(&commarg, joinlist[i]);
- cov[1] = rev2;
- cov[3] = commarg.string;
- if (runv(cov))
+ cov[2] = commarg.string;
+ if (runv(-1, rev2, cov))
goto badmerge;
diagnose("revision %s\n",joinlist[i+1]);
bufscpy(&commarg, "-p");
bufscat(&commarg, joinlist[i+1]);
- cov[1] = rev3;
- cov[3] = commarg.string;
- if (runv(cov))
+ cov[2] = commarg.string;
+ if (runv(-1, rev3, cov))
goto badmerge;
diagnose("merging...\n");
- mergev[4] = subs.string;
- mergev[6] = joinlist[i+1];
- p = &mergev[7];
+ mergev[3] = subs.string;
+ mergev[5] = joinlist[i+1];
+ p = &mergev[6];
if (quietflag) *p++ = quietarg;
if (lastjoin<=i+2 && workstdout) *p++ = "-p";
*p++ = initialfile;
*p++ = rev2;
*p++ = rev3;
- *p = nil;
- switch (runv(mergev)) {
+ *p = 0;
+ switch (runv(-1, (char*)0, mergev)) {
case DIFF_FAILURE: case DIFF_SUCCESS:
break;
default:
diff --git a/gnu/usr.bin/rcs/doc/rcs.ms b/gnu/usr.bin/rcs/doc/rcs.ms
index 7b3f807..1c90810 100644
--- a/gnu/usr.bin/rcs/doc/rcs.ms
+++ b/gnu/usr.bin/rcs/doc/rcs.ms
@@ -3,15 +3,6 @@
.\"
.\" \*s stands for $, and avoids problems when this file is checked in.
.ds s $
-.\" PS and PE center pic diagrams. (The corresponding ms-macros may not.)
-.de PS
-.nr pE (\\n(.lu-\\$2u)/2u
-.in +\\n(pEu
-.ne \\$1u
-..
-.de PE
-.in -\\n(pEu
-..
.de D(
.DS
.nr VS 12p
@@ -27,7 +18,7 @@
.de Id
.ND \\$4
..
-.Id $Id: rcs.ms,v 5.2 1991/01/03 10:57:28 eggert Exp $
+.Id $Id: rcs.ms,v 5.4 1995/06/01 16:23:43 eggert Exp $
.RP
.TL
RCS\*-A System for Version Control
@@ -292,7 +283,7 @@ has a similar function. It accumulates
the log messages that are requested during check-in.
Thus, one can maintain the complete history of a revision directly inside it,
by enclosing it in a comment.
-Figure 1 is a partial reproduction of a log contained in revision 4.1 of
+Figure 1 is an edited version of a log contained in revision 4.1 of
the file \fIci.c\fR. The log appears at the beginning of the file,
and makes it easy to determine what the recent modifications were.
.sp
@@ -301,23 +292,25 @@ and makes it easy to determine what the recent modifications were.
.ne 18
.nf
.in +0.5i
-/* \*sLog: ci.c,v \*s
- * Revision 4.1 1983/05/10 17:03:06 wft
- * Added option \-d and \-w, and updated assignment of date, etc. to new delta.
- * Added handling of default branches.
- *
- * Revision 3.9 1983/02/15 15:25:44 wft
- * Added call to fastcopy() to copy remainder of RCS file.
- *
- * Revision 3.8 1983/01/14 15:34:05 wft
- * Added ignoring of interrupts while new RCS file is renamed;
- * avoids deletion of RCS files by interrupts.
- *
- * Revision 3.7 1982/12/10 16:09:20 wft
- * Corrected checking of return code from diff.
- * An RCS file now inherits its mode during the first ci from the working file,
- * except that write permission is removed.
- */
+/*
+.in +\w'/'u
+* \*sLog: ci.c,v \*s
+* Revision 4.1 1983/05/10 17:03:06 wft
+* Added option \-d and \-w, and updated assignment of date, etc. to new delta.
+* Added handling of default branches.
+*
+* Revision 3.9 1983/02/15 15:25:44 wft
+* Added call to fastcopy() to copy remainder of RCS file.
+*
+* Revision 3.8 1983/01/14 15:34:05 wft
+* Added ignoring of interrupts while new RCS file is renamed;
+* avoids deletion of RCS files by interrupts.
+*
+* Revision 3.7 1982/12/10 16:09:20 wft
+* Corrected checking of return code from diff.
+* An RCS file now inherits its mode during the first ci from the working file,
+* except that write permission is removed.
+*/
.in 0
.ce 1
Figure 1. Log entries produced by the marker \*sLog\*s.
@@ -421,7 +414,7 @@ between 1.3 and 1.3.1.1
into a revision at level 2. The operation \fIrcsmerge\fR automates this
process (see the Appendix).
.ne 7
-.PS 4i
+.PS 4i
.ps -2
box "1.1"
arrow
@@ -460,7 +453,7 @@ that the customer has received revision 1.3, added his local modifications
as revision 1.3.1.1, then received revision 2.4, and merged
2.4 and 1.3.1.1, resulting in 2.4.1.1.
.ne 7
-.PS 4i
+.PS 4i
.ps -2
R13: box "1.3"
line invis
@@ -561,7 +554,7 @@ branch revision is reached. Figure 5 illustrates a tree with
one side branch. Triangles pointing to the left and right represent
reverse and forward deltas, respectively.
.ne 8
-.PS 4i
+.PS 4i
.ps -2
define BD X [line invis $1 right .5;
line up .3 then left .5 down .3 then right .5 down .3 then up .3] X
@@ -570,21 +563,21 @@ define FD X [line invis $1 right .5;
line left .5 down .3 then up .6 then right .5 down .3;] X
right
-D11: BD(" 1.1")
+D11: BD(" 1.1")
arrow right from D11.e
-D12: BD(" 1.2")
- arrow right from D12.e
-D13: BD(" 1.3")
- arrow right from D13.e
-D21: BD(" 2.1")
- arrow right from D21.e
-D22: box "2.2"
+D12: BD(" 1.2")
+ arrow right from D12.e
+D13: BD(" 1.3")
+ arrow right from D13.e
+D21: BD(" 2.1")
+ arrow right from D21.e
+D22: box "2.2"
line invis down from D21.s
-F1: FD("1.3.1.1 ")
+F1: FD("1.3.1.1 ")
arrow from D13.se to F1.w
arrow from F1.e right
right
-F2: FD("1.3.1.2 ")
+F2: FD("1.3.1.2 ")
.ps +2
.PE
.ce 1
@@ -1291,9 +1284,10 @@ locks, unlocks, breaks locks, toggles the strict-locking feature,
sets state attributes and symbolic revision numbers, changes the
description, and deletes revisions. A revision can
only be deleted if it is not the fork of a side branch.
+.br
+.ne 10
.IP "\fIrcsclean\fP \fB\- clean working directory\fP"
.sp 0
-.ne 10
\fIRcsclean\fR removes working files that were checked out but never changed.*
.FS *
The \fIrcsclean\fP and \fIrcsfreeze\fP commands
diff --git a/gnu/usr.bin/rcs/ident/Makefile b/gnu/usr.bin/rcs/ident/Makefile
index 1a618e5..f28f8d3 100644
--- a/gnu/usr.bin/rcs/ident/Makefile
+++ b/gnu/usr.bin/rcs/ident/Makefile
@@ -1,7 +1,8 @@
-PROG= ident
-
-SRCS= ident.c
-LDADD= -L${.CURDIR}/../lib/obj -lrcs
+PROG= ident
+SRCS= ident.c
CFLAGS+= -I${.CURDIR}/../lib
+LDADD= ${LIBRCS}
+DPADD= ${LIBRCS}
+.include "../../Makefile.inc"
.include <bsd.prog.mk>
diff --git a/gnu/usr.bin/rcs/ident/ident.1 b/gnu/usr.bin/rcs/ident/ident.1
index 37c8eda..33c10eb 100644
--- a/gnu/usr.bin/rcs/ident/ident.1
+++ b/gnu/usr.bin/rcs/ident/ident.1
@@ -3,25 +3,28 @@
.ds Dt \\$4
.ds iD \\$3 \\$4 \\$5 \\$6 \\$7
..
-.Id $Id: ident.1,v 5.0 1990/08/22 09:09:36 eggert Exp $
-.ds r \s-1RCS\s0
+.Id $Id: ident.1,v 5.4 1993/11/09 17:40:15 eggert Exp $
+.ds r \&\s-1RCS\s0
+.ds u \&\s-1UTC\s0
.if n .ds - \%--
.if t .ds - \(em
.TH IDENT 1 \*(Dt GNU
.SH NAME
-ident \- identify files
+ident \- identify RCS keyword strings in files
.SH SYNOPSIS
.B ident
[
.B \-q
] [
+.B \-V
+] [
.I file
\&.\|.\|. ]
.SH DESCRIPTION
.B ident
-searches for all occurrences of the pattern
-.BI $ keyword : .\|.\|. $
-in the named files or, if no file name appears, the standard input.
+searches for all instances of the pattern
+.BI $ keyword : "\ text\ " $
+in the named files or, if no files are named, the standard input.
.PP
These patterns are normally inserted automatically by the \*r command
.BR co (1),
@@ -30,6 +33,11 @@ The option
.B \-q
suppresses
the warning given if there are no patterns in a file.
+The option
+.B \-V
+prints
+.BR ident 's
+version number.
.PP
.B ident
works on text files as well as object files and dumps.
@@ -37,7 +45,15 @@ For example, if the C program in
.B f.c
contains
.IP
-\f3char rcsid[] = \&"$\&Id: f.c,v \*(iD $\&";\fP
+.ft 3
+#include <stdio.h>
+.br
+static char const rcsid[] =
+.br
+ \&"$\&Id: f.c,v \*(iD $\&";
+.br
+int main() { return printf(\&"%s\en\&", rcsid) == EOF; }
+.ft P
.LP
and
.B f.c
@@ -57,14 +73,104 @@ f.o:
$\&Id: f.c,v \*(iD $
.ft
.fi
+.PP
+If a C program defines a string like
+.B rcsid
+above but does not use it,
+.BR lint (1)
+may complain, and some C compilers will optimize away the string.
+The most reliable solution is to have the program use the
+.B rcsid
+string, as shown in the example above.
+.PP
+.B ident
+finds all instances of the
+.BI $ keyword : "\ text\ " $
+pattern, even if
+.I keyword
+is not actually an \*r-supported keyword.
+This gives you information about nonstandard keywords like
+.BR $\&XConsortium$ .
+.SH KEYWORDS
+Here is the list of keywords currently maintained by
+.BR co (1).
+All times are given in Coordinated Universal Time (\*u,
+sometimes called \&\s-1GMT\s0) by default, but if the files
+were checked out with
+.BR co 's
+.BI \-z zone
+option, times are given with a numeric time zone indication appended.
+.TP
+.B $\&Author$
+The login name of the user who checked in the revision.
+.TP
+.B $\&Date$
+The date and time the revision was checked in.
+.TP
+.B $\&Header$
+A standard header containing the full pathname of the \*r file, the
+revision number, the date and time, the author, the state,
+and the locker (if locked).
+.TP
+.B $\&Id$
+Same as
+.BR $\&Header$ ,
+except that the \*r filename is without a path.
+.TP
+.B $\&Locker$
+The login name of the user who locked the revision (empty if not locked).
+.TP
+.B $\&Log$
+The log message supplied during checkin.
+For
+.BR ident 's
+purposes, this is equivalent to
+.BR $\&RCSfile$ .
+.TP
+.B $\&Name$
+The symbolic name used to check out the revision, if any.
+.TP
+.B $\&RCSfile$
+The name of the \*r file without a path.
+.TP
+.B $\&Revision$
+The revision number assigned to the revision.
+.TP
+.B $\&Source$
+The full pathname of the \*r file.
+.TP
+.B $\&State$
+The state assigned to the revision with the
+.B \-s
+option of
+.BR rcs (1)
+or
+.BR ci (1).
+.PP
+.BR co (1)
+represents the following characters in keyword values by escape sequences
+to keep keyword strings well-formed.
+.LP
+.RS
+.nf
+.ne 6
+.ta \w'newline 'u
+\f2char escape sequence\fP
+tab \f3\et\fP
+newline \f3\en\fP
+space \f3\e040
+$ \e044
+\e \e\e\fP
+.fi
+.RE
.SH IDENTIFICATION
Author: Walter F. Tichy.
.br
-Revision Number: \*(Rv; Release Date: \*(Dt.
+Manual Page Revision: \*(Rv; Release Date: \*(Dt.
.br
-Copyright \(co 1982, 1988, 1989 by Walter F. Tichy.
+Copyright \(co 1982, 1988, 1989 Walter F. Tichy.
.br
-Copyright \(co 1990 by Paul Eggert.
+Copyright \(co 1990, 1992, 1993 Paul Eggert.
.SH "SEE ALSO"
ci(1), co(1), rcs(1), rcsdiff(1), rcsintro(1), rcsmerge(1), rlog(1),
rcsfile(5)
diff --git a/gnu/usr.bin/rcs/ident/ident.c b/gnu/usr.bin/rcs/ident/ident.c
index a2cc018..2d50e77 100644
--- a/gnu/usr.bin/rcs/ident/ident.c
+++ b/gnu/usr.bin/rcs/ident/ident.c
@@ -1,5 +1,7 @@
-/* Copyright (C) 1982, 1988, 1989 Walter Tichy
- Copyright 1990, 1991 by Paul Eggert
+/* Identify RCS keyword strings in files. */
+
+/* Copyright 1982, 1988, 1989 Walter Tichy
+ Copyright 1990, 1991, 1992, 1993, 1994, 1995 Paul Eggert
Distributed under license by the Free Software Foundation, Inc.
This file is part of RCS.
@@ -15,8 +17,9 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
-along with RCS; see the file COPYING. If not, write to
-the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+along with RCS; see the file COPYING.
+If not, write to the Free Software Foundation,
+59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
Report problems and direct all questions to:
@@ -25,10 +28,25 @@ Report problems and direct all questions to:
*/
/*
- * RCS identification operation
- */
-
-/* $Log: ident.c,v $
+ * Revision 5.9 1995/06/16 06:19:24 eggert
+ * Update FSF address.
+ *
+ * Revision 5.8 1995/06/01 16:23:43 eggert
+ * (exiterr, reportError): New functions, needed for DOS and OS/2 ports.
+ * (scanfile): Use them.
+ *
+ * Revision 5.7 1994/03/20 04:52:58 eggert
+ * Remove `exiting' from identExit.
+ *
+ * Revision 5.6 1993/11/09 17:40:15 eggert
+ * Add -V.
+ *
+ * Revision 5.5 1993/11/03 17:42:27 eggert
+ * Test for char == EOF, not char < 0.
+ *
+ * Revision 5.4 1992/01/24 18:44:19 eggert
+ * lint -> RCS_lint
+ *
* Revision 5.3 1991/09/10 22:15:46 eggert
* Open files with FOPEN_R, not FOPEN_R_WORK,
* because they might be executables, not working files.
@@ -45,26 +63,26 @@ Report problems and direct all questions to:
*
* Revision 4.5 89/05/01 15:11:54 narten
* changed copyright header to reflect current distribution rules
- *
+ *
* Revision 4.4 87/10/23 17:09:57 narten
* added exit(0) so exit return code would be non random
- *
+ *
* Revision 4.3 87/10/18 10:23:55 narten
* Updating version numbers. Changes relative to 1.1 are actually relative
* to 4.1
- *
+ *
* Revision 1.3 87/07/09 09:20:52 trinkle
* Added check to make sure there is at least one arg before comparing argv[1]
* with "-q". This necessary on machines that don't allow dereferncing null
* pointers (i.e. Suns).
- *
+ *
* Revision 1.2 87/03/27 14:21:47 jenkins
* Port to suns
- *
+ *
* Revision 4.1 83/05/10 16:31:02 wft
* Added option -q and input from reading stdin.
* Marker matching is now done with trymatch() (independent of keywords).
- *
+ *
* Revision 3.4 83/02/18 17:37:49 wft
* removed printing of new line after last file.
*
@@ -81,85 +99,123 @@ Report problems and direct all questions to:
#include "rcsbase.h"
static int match P((FILE*));
-static void scanfile P((FILE*,char const*,int));
+static int scanfile P((FILE*,char const*,int));
+static void reportError P((char const*));
-mainProg(identId, "ident", "$Id: ident.c,v 5.3 1991/09/10 22:15:46 eggert Exp $")
+mainProg(identId, "ident", "$Id: ident.c,v 1.3 1995/10/28 21:49:19 peter Exp $")
/* Ident searches the named files for all occurrences
- * of the pattern $keyword:...$, where the keywords are
- * Author, Date, Header, Id, Log, RCSfile, Revision, Source, and State.
+ * of the pattern $@: text $ where @ is a keyword.
*/
{
FILE *fp;
- int quiet;
+ int quiet = 0;
int status = EXIT_SUCCESS;
+ char const *a;
- if ((quiet = argc > 1 && strcmp("-q",argv[1])==0)) {
- argc--; argv++;
- }
+ while ((a = *++argv) && *a=='-')
+ while (*++a)
+ switch (*a) {
+ case 'q':
+ quiet = 1;
+ break;
- if (argc<2)
- scanfile(stdin, (char*)0, quiet);
+ case 'V':
+ VOID printf("RCS version %s\n", RCS_version_string);
+ quiet = -1;
+ break;
+
+ default:
+ VOID fprintf(stderr,
+ "ident: usage: ident -{qV} [file...]\n"
+ );
+ exitmain(EXIT_FAILURE);
+ break;
+ }
+
+ if (0 <= quiet)
+ if (!a)
+ VOID scanfile(stdin, (char*)0, quiet);
+ else
+ do {
+ if (!(fp = fopen(a, FOPEN_RB))) {
+ reportError(a);
+ status = EXIT_FAILURE;
+ } else if (
+ scanfile(fp, a, quiet) != 0
+ || (argv[1] && putchar('\n') == EOF)
+ )
+ break;
+ } while ((a = *++argv));
- while ( --argc > 0 ) {
- if (!(fp = fopen(*++argv, FOPEN_R))) {
- VOID fprintf(stderr, "%s error: can't open %s\n", cmdid, *argv);
- status = EXIT_FAILURE;
- } else {
- scanfile(fp, *argv, quiet);
- if (argc>1) VOID putchar('\n');
- }
- }
if (ferror(stdout) || fclose(stdout)!=0) {
- VOID fprintf(stderr, "%s error: write error\n", cmdid);
+ reportError("standard output");
status = EXIT_FAILURE;
}
exitmain(status);
}
-#if lint
- exiting void identExit() { _exit(EXIT_FAILURE); }
+#if RCS_lint
+# define exiterr identExit
#endif
-
+ void
+exiterr()
+{
+ _exit(EXIT_FAILURE);
+}
static void
+reportError(s)
+ char const *s;
+{
+ int e = errno;
+ VOID fprintf(stderr, "%s error: ", cmdid);
+ errno = e;
+ perror(s);
+}
+
+
+ static int
scanfile(file, name, quiet)
register FILE *file;
char const *name;
int quiet;
/* Function: scan an open file with descriptor file for keywords.
- * Return false if there's a read error.
+ * Return -1 if there's a write error; exit immediately on a read error.
*/
{
register int c;
- if (name)
+ if (name) {
VOID printf("%s:\n", name);
- else
- name = "input";
+ if (ferror(stdout))
+ return -1;
+ } else
+ name = "standard input";
c = 0;
- for (;;) {
- if (c < 0) {
- if (feof(file))
- break;
- if (ferror(file))
- goto read_error;
- }
+ while (c != EOF || ! (feof(file)|ferror(file))) {
if (c == KDELIM) {
if ((c = match(file)))
continue;
+ if (ferror(stdout))
+ return -1;
quiet = true;
}
c = getc(file);
}
+ if (ferror(file) || fclose(file) != 0) {
+ reportError(name);
+ /*
+ * The following is equivalent to exit(EXIT_FAILURE), but we invoke
+ * exiterr to keep lint happy. The DOS and OS/2 ports need exiterr.
+ */
+ VOID fflush(stderr);
+ VOID fflush(stdout);
+ exiterr();
+ }
if (!quiet)
VOID fprintf(stderr, "%s warning: no id keywords in %s\n", cmdid, name);
- if (fclose(file) == 0)
- return;
-
- read_error:
- VOID fprintf(stderr, "%s error: %s: read error\n", cmdid, name);
- exit(EXIT_FAILURE);
+ return 0;
}
@@ -174,7 +230,7 @@ match(fp) /* group substring between two KDELIM's; then do pattern match */
tp = line;
while ((c = getc(fp)) != VDELIM) {
- if (c < 0)
+ if (c == EOF && feof(fp) | ferror(fp))
return c;
switch (ctab[c]) {
case LETTER: case Letter:
@@ -193,7 +249,7 @@ match(fp) /* group substring between two KDELIM's; then do pattern match */
return c ? c : '\n';
*tp++ = c;
while( (c = getc(fp)) != KDELIM ) {
- if (c < 0 && feof(fp) | ferror(fp))
+ if (c == EOF && feof(fp) | ferror(fp))
return c;
switch (ctab[c]) {
default:
@@ -209,6 +265,6 @@ match(fp) /* group substring between two KDELIM's; then do pattern match */
return c;
*tp++ = c; /*append trailing KDELIM*/
*tp = '\0';
- VOID fprintf(stdout, " %c%s\n", KDELIM, line);
+ VOID printf(" %c%s\n", KDELIM, line);
return 0;
}
diff --git a/gnu/usr.bin/rcs/lib/Makefile b/gnu/usr.bin/rcs/lib/Makefile
index b198e9e..0170d4a 100644
--- a/gnu/usr.bin/rcs/lib/Makefile
+++ b/gnu/usr.bin/rcs/lib/Makefile
@@ -1,5 +1,14 @@
-LIB= rcs
-SRCS= maketime.c partime.c rcsedit.c rcsfcmp.c rcsfnms.c rcsgen.c rcskeep.c \
- rcskeys.c rcslex.c rcsmap.c rcsrev.c rcssyn.c rcsutil.c merger.c
+# Define FSYNC_ALL to get slower but safer writes in case of crashes in
+# the middle of CVS/RCS changes
+#CFLAGS += -DFSYNC_ALL
+
+LIB = rcs
+SRCS = maketime.c partime.c rcsedit.c rcsfcmp.c rcsfnms.c rcsgen.c \
+ rcskeep.c rcskeys.c rcslex.c rcsmap.c rcsrev.c rcssyn.c rcstime.c \
+ rcsutil.c merger.c version.c
+
+NOPROFILE=noprofile
+
+install:
.include <bsd.lib.mk>
diff --git a/gnu/usr.bin/rcs/lib/conf.h b/gnu/usr.bin/rcs/lib/conf.h
index d29e511..b1d404a 100644
--- a/gnu/usr.bin/rcs/lib/conf.h
+++ b/gnu/usr.bin/rcs/lib/conf.h
@@ -1,6 +1,6 @@
/* RCS compile-time configuration */
- /* $Id: conf.sh,v 5.14 1991/11/20 18:21:10 eggert Exp $ */
+ /* $Id: conf.h,v 1.4 1995/10/28 21:49:25 peter Exp $ */
/*
* This file is generated automatically.
@@ -10,7 +10,8 @@
*/
#define exitmain(n) return n /* how to exit from main() */
-/* #define _POSIX_SOURCE */ /* Define this if Posix + strict Standard C. */
+/* #define _POSIX_C_SOURCE 2147483647L */ /* if strict C + Posix 1003.1b-1993 or later */
+/* #define _POSIX_SOURCE */ /* if strict C + Posix 1003.1-1990 */
#include <errno.h>
#include <stdio.h>
@@ -22,48 +23,28 @@
#include <dirent.h>
#include <fcntl.h>
#include <limits.h>
+/* #include <mach/mach.h> */
+/* #include <net/errno.h> */
#include <pwd.h>
+/* #include <siginfo.h> */
#include <signal.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/wait.h>
+/* #include <ucontext.h> */
#include <unistd.h>
#include <utime.h>
/* #include <vfork.h> */
-/* Define the following symbols to be 1 or 0. */
-#define has_sys_dir_h 1 /* Does #include <sys/dir.h> work? */
+/* Define boolean symbols to be 0 (false, the default), or 1 (true). */
#define has_sys_param_h 1 /* Does #include <sys/param.h> work? */
+/* extern int errno; */ /* Uncomment if <errno.h> doesn't declare errno. */
#define has_readlink 1 /* Does readlink() work? */
+#define readlink_isreg_errno EINVAL /* errno after readlink on regular file */
-/* #undef NAME_MAX */ /* Uncomment this if NAME_MAX is broken. */
-
-#if !defined(NAME_MAX) && !defined(_POSIX_NAME_MAX)
-# if has_sys_dir_h
-# include <sys/dir.h>
-# endif
-# ifndef NAME_MAX
-# ifndef MAXNAMLEN
-# define MAXNAMLEN 14
-# endif
-# define NAME_MAX MAXNAMLEN
-# endif
-#endif
-#if !defined(PATH_MAX) && !defined(_POSIX_PATH_MAX)
-# if has_sys_param_h
-# include <sys/param.h>
-# define included_sys_param_h 1
-# endif
-# ifndef PATH_MAX
-# ifndef MAXPATHLEN
-# define MAXPATHLEN 1024
-# endif
-# define PATH_MAX (MAXPATHLEN-1)
-# endif
-#endif
#if has_readlink && !defined(MAXSYMLINKS)
-# if has_sys_param_h && !included_sys_param_h
+# if has_sys_param_h
# include <sys/param.h>
# endif
# ifndef MAXSYMLINKS
@@ -71,25 +52,55 @@
# endif
#endif
-/* Comment out the keyword definitions below if the keywords work. */
-/* #define const */
-/* #define volatile */
-
/* Comment out the typedefs below if the types are already declared. */
/* Fix any uncommented typedefs that are wrong. */
/* typedef int mode_t; */
+/* typedef long off_t; */
/* typedef int pid_t; */
-typedef int sig_atomic_t;
+/* typedef int sig_atomic_t; */
/* typedef unsigned size_t; */
/* typedef int ssize_t; */
/* typedef long time_t; */
/* typedef int uid_t; */
-/* Define the following symbols to be 1 or 0. */
+/* Comment out the keyword definitions below if the keywords work. */
+/* #define const */
+/* #define volatile */
+
+/* Define boolean symbols to be 0 (false, the default), or 1 (true). */
#define has_prototypes 1 /* Do function prototypes work? */
#define has_stdarg 1 /* Does <stdarg.h> work? */
-#define has_varargs 0 /* Does <varargs.h> work? */
+/* #define has_varargs ? */ /* Does <varargs.h> work? */
#define va_start_args 2 /* How many args does va_start() take? */
+
+#if O_BINARY
+ /* Text and binary i/o behave differently. */
+ /* This is incompatible with Posix and Unix. */
+# define FOPEN_RB "rb"
+# define FOPEN_R_WORK (Expand==BINARY_EXPAND ? "r" : "rb")
+# define FOPEN_WB "wb"
+# define FOPEN_W_WORK (Expand==BINARY_EXPAND ? "w" : "wb")
+# define FOPEN_WPLUS_WORK (Expand==BINARY_EXPAND ? "w+" : "w+b")
+# define OPEN_O_BINARY O_BINARY
+#else
+ /*
+ * Text and binary i/o behave the same.
+ * Omit "b", since some nonstandard hosts reject it.
+ */
+# define FOPEN_RB "r"
+# define FOPEN_R_WORK "r"
+# define FOPEN_WB "w"
+# define FOPEN_W_WORK "w"
+# define FOPEN_WPLUS_WORK "w+"
+# define OPEN_O_BINARY 0
+#endif
+
+/* This may need changing on non-Unix systems (notably DOS). */
+#define OPEN_CREAT_READONLY (S_IRUSR|S_IRGRP|S_IROTH) /* lock file mode */
+#define OPEN_O_LOCK 0 /* extra open flags for creating lock file */
+#define OPEN_O_WRONLY O_WRONLY /* main open flag for creating a lock file */
+
+/* Define or comment out the following symbols as needed. */
#if has_prototypes
# define P(params) params
#else
@@ -113,105 +124,114 @@ typedef int sig_atomic_t;
#else
# define vararg_start(ap,p) va_start(ap)
#endif
-
-#define text_equals_binary_stdio 1 /* Does stdio treat text like binary? */
-#define text_work_stdio 0 /* Text i/o for working file, binary for RCS file? */
-#if text_equals_binary_stdio
- /* Text and binary i/o behave the same, or binary i/o does not work. */
-# define FOPEN_R "r"
-# define FOPEN_W "w"
-# define FOPEN_WPLUS "w+"
-#else
- /* Text and binary i/o behave differently. */
- /* This is incompatible with Posix and Unix. */
-# define FOPEN_R "rb"
-# define FOPEN_W "wb"
-# define FOPEN_WPLUS "w+b"
-#endif
-#if text_work_stdio
-# define FOPEN_R_WORK "r"
-# define FOPEN_W_WORK "w"
-# define FOPEN_WPLUS_WORK "w+"
+#define bad_chmod_close 0 /* Can chmod() close file descriptors? */
+#define bad_creat0 0 /* Do writes fail after creat(f,0)? */
+#define bad_fopen_wplus 0 /* Does fopen(f,"w+") fail to truncate f? */
+#define getlogin_is_secure 0 /* Is getlogin() secure? Usually it's not. */
+#define has_attribute_noreturn 1 /* Does __attribute__((noreturn)) work? */
+#if has_attribute_noreturn
+# define exiting __attribute__((noreturn))
#else
-# define FOPEN_R_WORK FOPEN_R
-# define FOPEN_W_WORK FOPEN_W
-# define FOPEN_WPLUS_WORK FOPEN_WPLUS
+# define exiting
#endif
-
-/* Define or comment out the following symbols as needed. */
-#define bad_fopen_wplus 0 /* Does fopen(f,FOPEN_WPLUS) fail to truncate f? */
-#define getlogin_is_secure 0 /* Is getlogin() secure? Usually it's not. */
#define has_dirent 1 /* Do opendir(), readdir(), closedir() work? */
-#define has_fchmod 0 /* Does fchmod() work? */
-#define has_fputs 0 /* Does fputs() work? */
+#define void_closedir 0 /* Does closedir() yield void? */
+#define has_fchmod 1 /* Does fchmod() work? */
+#define has_fflush_input 0 /* Does fflush() work on input files? */
+#define has_fputs 1 /* Does fputs() work? */
#define has_ftruncate 1 /* Does ftruncate() work? */
#define has_getuid 1 /* Does getuid() work? */
#define has_getpwuid 1 /* Does getpwuid() work? */
-#define has_link 1 /* Does link() work? */
#define has_memcmp 1 /* Does memcmp() work? */
#define has_memcpy 1 /* Does memcpy() work? */
#define has_memmove 1 /* Does memmove() work? */
+#define has_map_fd 0 /* Does map_fd() work? */
+#define has_mmap 1 /* Does mmap() work on regular files? */
#define has_madvise 0 /* Does madvise() work? */
-#define has_mmap 0 /* Does mmap() work on regular files? */
+#define mmap_signal SIGBUS /* signal received if you reference nonexistent part of mmapped file */
#define has_rename 1 /* Does rename() work? */
#define bad_a_rename 0 /* Does rename(A,B) fail if A is unwritable? */
#define bad_b_rename 0 /* Does rename(A,B) fail if B is unwritable? */
+#define bad_NFS_rename 0 /* Can rename(A,B) falsely report success? */
+/* typedef int void; */ /* Some ancient compilers need this. */
#define VOID (void) /* 'VOID e;' discards the value of an expression 'e'. */
-#define has_seteuid 0 /* Does seteuid() work? See README. */
+#define has_seteuid 1 /* Does seteuid() work? See ../INSTALL.RCS. */
+#define has_setreuid 0 /* Does setreuid() work? See ../INSTALL.RCS. */
#define has_setuid 1 /* Does setuid() exist? */
+#define has_sigaction 1 /* Does struct sigaction work? */
+#define has_sa_sigaction 0 /* Does struct sigaction have sa_sigaction? */
#define has_signal 1 /* Does signal() work? */
-#define signal_args P((int)) /* arguments of signal handlers */
#define signal_type void /* type returned by signal handlers */
#define sig_zaps_handler 0 /* Must a signal handler reinvoke signal()? */
-#define has_sigaction 1 /* Does struct sigaction work? */
/* #define has_sigblock ? */ /* Does sigblock() work? */
/* #define sigmask(s) (1 << ((s)-1)) */ /* Yield mask for signal number. */
-#define has_sys_siglist 0 /* Does sys_siglist[] work? */
-typedef ssize_t fread_type; /* type returned by fread() and fwrite() */
+typedef size_t fread_type; /* type returned by fread() and fwrite() */
typedef size_t freadarg_type; /* type of their size arguments */
typedef void *malloc_type; /* type returned by malloc() */
#define has_getcwd 1 /* Does getcwd() work? */
/* #define has_getwd ? */ /* Does getwd() work? */
+#define needs_getabsname 0 /* Must we define getabsname? */
#define has_mktemp 1 /* Does mktemp() work? */
#define has_NFS 1 /* Might NFS be used? */
+#define has_psiginfo 0 /* Does psiginfo() work? */
+#define has_psignal 1 /* Does psignal() work? */
+/* #define has_si_errno ? */ /* Does siginfo_t have si_errno? */
+/* #define has_sys_siglist ? */ /* Does sys_siglist[] work? */
/* #define strchr index */ /* Use old-fashioned name for strchr()? */
/* #define strrchr rindex */ /* Use old-fashioned name for strrchr()? */
#define bad_unlink 0 /* Does unlink() fail on unwritable files? */
-#define has_vfork 0 /* Does vfork() work? */
+#define has_vfork 1 /* Does vfork() work? */
#define has_fork 1 /* Does fork() work? */
#define has_spawn 0 /* Does spawn*() work? */
-#define has_wait 1 /* Does wait() work? */
-#define has_waitpid 0 /* Does waitpid() work? */
+#define has_waitpid 1 /* Does waitpid() work? */
+#define bad_wait_if_SIGCHLD_ignored 0 /* Does ignoring SIGCHLD break wait()? */
#define RCS_SHELL "/bin/sh" /* shell to run RCS subprograms */
+#define has_printf_dot 1 /* Does "%.2d" print leading 0? */
#define has_vfprintf 1 /* Does vfprintf() work? */
+#define has_attribute_format_printf 1 /* Does __attribute__((format(printf,N,N+1))) work? */
+#if has_attribute_format_printf
+# define printf_string(m, n) __attribute__((format(printf, m, n)))
+#else
+# define printf_string(m, n)
+#endif
+#if has_attribute_format_printf && has_attribute_noreturn
+ /* Work around a bug in GCC 2.5.x. */
+# define printf_string_exiting(m, n) __attribute__((format(printf, m, n), noreturn))
+#else
+# define printf_string_exiting(m, n) printf_string(m, n) exiting
+#endif
/* #define has__doprintf ? */ /* Does _doprintf() work? */
/* #define has__doprnt ? */ /* Does _doprnt() work? */
/* #undef EXIT_FAILURE */ /* Uncomment this if EXIT_FAILURE is broken. */
-#define large_memory 0 /* Can main memory hold entire RCS files? */
-/* #undef ULONG_MAX */ /* Uncomment this if ULONG_MAX is broken (e.g. < 0). */
-/* struct utimbuf { time_t actime, modtime; }; */ /* Uncomment this if needed. */
+#define large_memory 1 /* Can main memory hold entire RCS files? */
+#ifndef LONG_MAX
+#define LONG_MAX 2147483647L /* long maximum */
+#endif
+/* Do struct stat s and t describe the same file? Answer d if unknown. */
+#define same_file(s,t,d) ((s).st_ino==(t).st_ino && (s).st_dev==(t).st_dev)
+#define has_utimbuf 1 /* Does struct utimbuf work? */
#define CO "/usr/bin/co" /* name of 'co' program */
#define COMPAT2 0 /* Are version 2 files supported? */
-#define DATEFORM "%.2d.%.2d.%.2d.%.2d.%.2d.%.2d" /* e.g. 01.01.01.01.01.01 */
#define DIFF "/usr/bin/diff" /* name of 'diff' program */
#define DIFF3 "/usr/bin/diff3" /* name of 'diff3' program */
#define DIFF3_BIN 1 /* Is diff3 user-visible (not the /usr/lib auxiliary)? */
-#define DIFF_FLAGS , "-an" /* Make diff output suitable for RCS. */
-#define DIFF_L 1 /* Does diff -L work? */
+#define DIFFFLAGS "-an" /* Make diff output suitable for RCS. */
+#define DIFF_L 1 /* Does diff -L work? */
#define DIFF_SUCCESS 0 /* DIFF status if no differences are found */
#define DIFF_FAILURE 1 /* DIFF status if differences are found */
#define DIFF_TROUBLE 2 /* DIFF status if trouble */
#define ED "/bin/ed" /* name of 'ed' program (used only if !DIFF3_BIN) */
#define MERGE "/usr/bin/merge" /* name of 'merge' program */
#define TMPDIR "/tmp" /* default directory for temporary files */
-#define SLASH '/' /* principal pathname separator */
-#define SLASHes '/' /* `case SLASHes:' labels all pathname separators */
-#define isSLASH(c) ((c) == SLASH) /* Is arg a pathname separator? */
+#define SLASH '/' /* principal filename separator */
+#define SLASHes '/' /* `case SLASHes:' labels all filename separators */
+#define isSLASH(c) ((c) == SLASH) /* Is arg a filename separator? */
#define ROOTPATH(p) isSLASH((p)[0]) /* Is p an absolute pathname? */
#define X_DEFAULT ",v/" /* default value for -x option */
+#define SLASHSLASH_is_SLASH 1 /* Are // and / the same directory? */
+#define ALL_ABSOLUTE 1 /* Do all subprograms satisfy ROOTPATH? */
#define DIFF_ABSOLUTE 1 /* Is ROOTPATH(DIFF) true? */
-#define ALL_ABSOLUTE 1 /* Are all subprograms absolute pathnames? */
-#define SENDMAIL "/usr/bin/mail" /* how to send mail */
+#define SENDMAIL "/usr/sbin/sendmail" /* how to send mail */
#define TZ_must_be_set 0 /* Must TZ be set for gmtime() to work? */
@@ -219,40 +239,21 @@ typedef void *malloc_type; /* type returned by malloc() */
/* Adjust the following declarations as needed. */
-#if __GNUC__ && !__STRICT_ANSI__
-# define exiting volatile /* GCC extension: function cannot return */
-#else
-# define exiting
-#endif
+/* The rest is for the benefit of non-standard, traditional hosts. */
+/* Don't bother to declare functions that in traditional hosts do not appear, */
+/* or are declared in .h files, or return int or void. */
-#if has_ftruncate
- int ftruncate P((int,off_t));
-#endif
-/* <sys/mman.h> */
-#if has_madvise
- int madvise P((caddr_t,size_t,int));
-#endif
-#if has_mmap
- caddr_t mmap P((caddr_t,size_t,int,int,int,off_t));
- int munmap P((caddr_t,size_t));
+/* traditional BSD */
+
+#if has_sys_siglist && !defined(sys_siglist)
+ extern char const * const sys_siglist[];
#endif
/* Posix (ISO/IEC 9945-1: 1990 / IEEE Std 1003.1-1990) */
-/* These definitions are for the benefit of non-Posix hosts, and */
-/* Posix hosts that have Standard C compilers but traditional include files. */
-/* Unfortunately, mixed-up hosts are all too common. */
/* <fcntl.h> */
-#ifdef F_DUPFD
- int fcntl P((int,int,...));
-#else
- int dup2 P((int,int));
-#endif
-#ifndef O_BINARY /* some non-Posix hosts need O_BINARY */
-# define O_BINARY 0 /* no effect on Posix */
-#endif
#ifdef O_CREAT
# define open_can_creat 1
#else
@@ -262,43 +263,12 @@ typedef void *malloc_type; /* type returned by malloc() */
# define O_RDWR 2
# define O_CREAT 01000
# define O_TRUNC 02000
- int creat P((char const*,mode_t));
#endif
#ifndef O_EXCL
-# define O_EXCL 0
-#endif
-
-/* <pwd.h> */
-#if has_getpwuid
- struct passwd *getpwuid P((uid_t));
+#define O_EXCL 0
#endif
-/* <signal.h> */
-#if has_sigaction
- int sigaction P((int,struct sigaction const*,struct sigaction*));
- int sigaddset P((sigset_t*,int));
- int sigemptyset P((sigset_t*));
-#else
-#if has_sigblock
- /* BSD */
- int sigblock P((int));
- int sigmask P((int));
- int sigsetmask P((int));
-#endif
-#endif
-
-/* <stdio.h> */
-FILE *fdopen P((int,char const*));
-int fileno P((FILE*));
-
/* <sys/stat.h> */
-int chmod P((char const*,mode_t));
-int fstat P((int,struct stat*));
-int stat P((char const*,struct stat*));
-mode_t umask P((mode_t));
-#if has_fchmod
- int fchmod P((int,mode_t));
-#endif
#ifndef S_IRUSR
# ifdef S_IREAD
# define S_IRUSR S_IREAD
@@ -326,166 +296,100 @@ mode_t umask P((mode_t));
# endif
#endif
#ifndef S_ISREG
-# define S_ISREG(n) (((n) & S_IFMT) == S_IFREG)
+#define S_ISREG(n) (((n) & S_IFMT) == S_IFREG)
#endif
/* <sys/wait.h> */
-#if has_wait
- pid_t wait P((int*));
-#endif
#ifndef WEXITSTATUS
-# define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8)
-# undef WIFEXITED /* Avoid 4.3BSD incompatibility with Posix. */
+#define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8)
+#undef WIFEXITED /* Avoid 4.3BSD incompatibility with Posix. */
#endif
#ifndef WIFEXITED
-# define WIFEXITED(stat_val) (!((stat_val) & 255))
+#define WIFEXITED(stat_val) (((stat_val) & 0377) == 0)
+#endif
+#ifndef WTERMSIG
+#define WTERMSIG(stat_val) ((stat_val) & 0177)
+#undef WIFSIGNALED /* Avoid 4.3BSD incompatibility with Posix. */
+#endif
+#ifndef WIFSIGNALED
+#define WIFSIGNALED(stat_val) ((unsigned)(stat_val) - 1 < 0377)
#endif
/* <unistd.h> */
char *getlogin P((void));
-int close P((int));
-int isatty P((int));
-int link P((char const*,char const*));
-int open P((char const*,int,...));
-int unlink P((char const*));
-int _filbuf P((FILE*)); /* keeps lint quiet in traditional C */
-int _flsbuf P((int,FILE*)); /* keeps lint quiet in traditional C */
-long pathconf P((char const*,int));
-ssize_t write P((int,void const*,size_t));
#ifndef STDIN_FILENO
# define STDIN_FILENO 0
# define STDOUT_FILENO 1
# define STDERR_FILENO 2
#endif
-#if has_fork
-# if !has_vfork
-# undef vfork
-# define vfork fork
-# endif
- pid_t vfork P((void)); /* vfork is nonstandard but faster */
+#if has_fork && !has_vfork
+# undef vfork
+# define vfork fork
#endif
#if has_getcwd || !has_getwd
char *getcwd P((char*,size_t));
#else
char *getwd P((char*));
#endif
-#if has_getuid
- uid_t getuid P((void));
-#endif
-#if has_readlink
-/* ssize_t readlink P((char const*,char*,size_t)); *//* BSD; not standard yet */
-#endif
-#if has_setuid
-# if !has_seteuid
-# undef seteuid
-# define seteuid setuid
-# endif
- int seteuid P((uid_t));
- uid_t geteuid P((void));
+#if has_setuid && !has_seteuid
+# undef seteuid
+# define seteuid setuid
#endif
#if has_spawn
- int spawnv P((int,char const*,char*const*));
# if ALL_ABSOLUTE
# define spawn_RCS spawnv
# else
# define spawn_RCS spawnvp
- int spawnvp P((int,char const*,char*const*));
# endif
#else
- int execv P((char const*,char*const*));
# if ALL_ABSOLUTE
# define exec_RCS execv
# else
# define exec_RCS execvp
- int execvp P((char const*,char*const*));
# endif
#endif
/* utime.h */
-int utime P((char const*,struct utimbuf const*));
+#if !has_utimbuf
+ struct utimbuf { time_t actime, modtime; };
+#endif
/* Standard C library */
-/* These definitions are for the benefit of hosts that have */
-/* traditional C include files, possibly with Standard C compilers. */
-/* Unfortunately, mixed-up hosts are all too common. */
-
-/* <errno.h> */
-extern int errno;
-
-/* <limits.h> */
-#ifndef ULONG_MAX
- /* This does not work in #ifs, but it's good enough for us. */
-# define ULONG_MAX ((unsigned long)-1)
-#endif
-
-/* <signal.h> */
-#if has_signal
- signal_type (*signal P((int,signal_type(*)signal_args)))signal_args;
-#endif
/* <stdio.h> */
-FILE *fopen P((char const*,char const*));
-fread_type fread P((void*,freadarg_type,freadarg_type,FILE*));
-fread_type fwrite P((void const*,freadarg_type,freadarg_type,FILE*));
-int fclose P((FILE*));
-int feof P((FILE*));
-int ferror P((FILE*));
-int fflush P((FILE*));
-int fprintf P((FILE*,char const*,...));
-int fputs P((char const*,FILE*));
-int fseek P((FILE*,long,int));
-int printf P((char const*,...));
-int rename P((char const*,char const*));
-int sprintf P((char*,char const*,...));
-/* long ftell P((FILE*)); */
-void clearerr P((FILE*));
-void perror P((char const*));
#ifndef L_tmpnam
-# define L_tmpnam 32 /* power of 2 > sizeof("/usr/tmp/xxxxxxxxxxxxxxx") */
+#define L_tmpnam 32 /* power of 2 > sizeof("/usr/tmp/xxxxxxxxxxxxxxx") */
#endif
#ifndef SEEK_SET
-# define SEEK_SET 0
+#define SEEK_SET 0
+#endif
+#ifndef SEEK_CUR
+#define SEEK_CUR 1
#endif
#if has_mktemp
char *mktemp P((char*)); /* traditional */
#else
char *tmpnam P((char*));
#endif
-#if has_vfprintf
- int vfprintf P((FILE*,char const*,va_list));
-#else
-#if has__doprintf
- void _doprintf P((FILE*,char const*,va_list)); /* Minix */
-#else
- void _doprnt P((char const*,va_list,FILE*)); /* BSD */
-#endif
-#endif
/* <stdlib.h> */
char *getenv P((char const*));
-exiting void _exit P((int));
-exiting void exit P((int));
+void _exit P((int)) exiting;
+void exit P((int)) exiting;
malloc_type malloc P((size_t));
malloc_type realloc P((malloc_type,size_t));
-void free P((malloc_type));
#ifndef EXIT_FAILURE
-# define EXIT_FAILURE 1
+#define EXIT_FAILURE 1
#endif
#ifndef EXIT_SUCCESS
-# define EXIT_SUCCESS 0
-#endif
-#if !has_fork && !has_spawn
- int system P((char const*));
+#define EXIT_SUCCESS 0
#endif
/* <string.h> */
char *strcpy P((char*,char const*));
char *strchr P((char const*,int));
char *strrchr P((char const*,int));
-int memcmp P((void const*,void const*,size_t));
-int strcmp P((char const*,char const*));
-size_t strlen P((char const*));
void *memcpy P((void*,void const*,size_t));
#if has_memmove
void *memmove P((void*,void const*,size_t));
diff --git a/gnu/usr.bin/rcs/lib/maketime.c b/gnu/usr.bin/rcs/lib/maketime.c
index c95c9f0..0f98926 100644
--- a/gnu/usr.bin/rcs/lib/maketime.c
+++ b/gnu/usr.bin/rcs/lib/maketime.c
@@ -1,344 +1,344 @@
-#
-/*
- * MAKETIME derive 32-bit time value from TM structure.
- *
- * Usage:
- * int zone; Minutes west of GMT, or
- * 48*60 for localtime
- * time_t t;
- * struct tm *tp; Pointer to TM structure from <time.h>
- * t = maketime(tp,zone);
- *
- * Returns:
- * -1 if failure; parameter out of range or nonsensical.
- * else time-value.
- * Notes:
- * This code is quasi-public; it may be used freely in like software.
- * It is not to be sold, nor used in licensed software without
- * permission of the author.
- * For everyone's benefit, please report bugs and improvements!
- * Copyright 1981 by Ken Harrenstien, SRI International.
- * (ARPANET: KLH @ SRI)
- */
-/* $Log: maketime.c,v $
- * Revision 5.3 1991/08/19 03:13:55 eggert
- * Add setfiledate, str2time, TZ_must_be_set.
- *
- * Revision 5.2 1990/11/01 05:03:30 eggert
- * Remove lint.
- *
- * Revision 5.1 1990/10/04 06:30:13 eggert
- * Calculate the GMT offset of 'xxx LT' as of xxx, not as of now.
- * Don't assume time_t is 32 bits. Fix bugs near epoch and near end of time.
- *
- * Revision 5.0 1990/08/22 08:12:38 eggert
- * Switch to GMT and fix the bugs exposed thereby.
- * Permit dates past 1999/12/31. Ansify and Posixate.
- *
- * Revision 1.8 88/11/08 13:54:53 narten
- * allow negative timezones (-24h <= x <= 24h)
- *
- * Revision 1.7 88/08/28 14:47:52 eggert
- * Allow cc -R. Remove unportable "#endif XXX"s.
- *
- * Revision 1.6 87/12/18 17:05:58 narten
- * include rcsparam.h
- *
- * Revision 1.5 87/12/18 11:35:51 narten
- * maketime.c: fixed USG code - you have tgo call "tzset" in order to have
- * "timezone" set. ("localtime" calls it, but it's probably better not to
- * count on "localtime" having been called.)
- *
- * Revision 1.4 87/10/18 10:26:57 narten
- * Updating version numbers. Changes relative to 1.0 are actually
- * relative to 1.2
- *
- * Revision 1.3 87/09/24 13:58:45 narten
- * Sources now pass through lint (if you ignore printf/sprintf/fprintf
- * warnings)
- *
- * Revision 1.2 87/03/27 14:21:48 jenkins
- * Port to suns
- *
- * Revision 1.2 83/12/05 10:12:56 wft
- * added cond. compilation for USG Unix; long timezone;
- *
- * Revision 1.1 82/05/06 11:38:00 wft
- * Initial revision
- *
- */
-
-
-#include "rcsbase.h"
-
-libId(maketId, "$Id: maketime.c,v 5.3 1991/08/19 03:13:55 eggert Exp $")
-
-static struct tm const *time2tm P((time_t));
-
-#define given(v) (0 <= (v)) /* Negative values are unspecified. */
-
-static int const daytb[] = {
- /* # days in year thus far, indexed by month (0-12!!) */
- 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365
-};
+/* Convert struct partime into time_t. */
- static time_t
-maketime(atm,zone)
- struct tm const *atm;
- int zone;
-{
- register struct tm const *tp;
- register int i;
- int year, yday, mon, day, hour, min, sec, leap, localzone;
- int attempts;
- time_t t, tres;
-
- attempts = 2;
- localzone = zone==48*60;
- tres = -1;
- year = mon = day = 0; /* Keep lint happy. */
-
- do {
-
- if (localzone || !given(atm->tm_year)) {
- if (tres == -1)
- if ((tres = time((time_t*)0)) == -1)
- return -1;
- tp = time2tm(tres);
- /* Get breakdowns of default time, adjusting to zone. */
- year = tp->tm_year; /* Use to set up defaults */
- yday = tp->tm_yday;
- mon = tp->tm_mon;
- day = tp->tm_mday;
- hour = tp->tm_hour;
- min = tp->tm_min;
- if (localzone) {
- tp = localtime(&tres);
- zone =
- min - tp->tm_min + 60*(
- hour - tp->tm_hour + 24*(
- /* If years differ, it's by one day. */
- year - tp->tm_year
- ? year - tp->tm_year
- : yday - tp->tm_yday));
- }
- /* Adjust the default day, month and year according to zone. */
- if ((min -= zone) < 0) {
- if (hour-(59-min)/60 < 0 && --day <= 0) {
- if (--mon < 0) {
- --year;
- mon = 11;
- }
- day = daytb[mon+1] - daytb[mon] + (mon==1&&!(year&3));
- }
- } else
- if (
- 24 <= hour+min/60 &&
- daytb[mon+1] - daytb[mon] + (mon==1&&!(year&3)) < ++day
- ) {
- if (11 < ++mon) {
- ++year;
- mon = 0;
- }
- day = 1;
- }
- }
- if (zone < -24*60 || 24*60 < zone)
- return -1;
+/* Copyright 1992, 1993, 1994, 1995 Paul Eggert
+ Distributed under license by the Free Software Foundation, Inc.
+This file is part of RCS.
-#ifdef DEBUG
-printf("first YMD: %d %d %d\n",year,mon,day);
-#endif
- tp = atm;
-
- /* First must find date, using specified year, month, day.
- * If one of these is unspecified, it defaults either to the
- * current date (if no more global spec was given) or to the
- * zero-value for that spec (i.e. a more global spec was seen).
- * Reject times that do not fit in time_t,
- * without assuming that time_t is 32 bits or is signed.
- */
- if (given(tp->tm_year))
- {
- year = tp->tm_year;
- mon = 0; /* Since year was given, default */
- day = 1; /* for remaining specs is zero */
- }
- if (year < 69) /* 1969/12/31 OK in some timezones. */
- return -1; /* ERR: year out of range */
- leap = !(year&3) && (year%100 || !((year+300)%400));
- year -= 70; /* UNIX time starts at 1970 */
+RCS is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
- /*
- * Find day of year.
- */
- {
- if (given(tp->tm_mon))
- { mon = tp->tm_mon; /* Month was specified */
- day = 1; /* so set remaining default */
- }
- if (11 < (unsigned)mon)
- return -1; /* ERR: bad month */
- if (given(tp->tm_mday)) day = tp->tm_mday;
- if(day < 1
- || (((daytb[mon+1]-daytb[mon]) < day)
- && (day!=29 || mon!=1 || !leap) ))
- return -1; /* ERR: bad day */
- yday = daytb[mon] /* Add # of days in months so far */
- + ((leap /* Leap year, and past Feb? If */
- && mon>1)? 1:0) /* so, add leap day for this year */
- + day-1; /* And finally add # days this mon */
+RCS is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
- }
- if (leap+365 <= (unsigned)yday)
- return -1; /* ERR: bad YDAY */
-
- if (year < 0) {
- if (yday != 364)
- return -1; /* ERR: too early */
- t = -1;
- } else {
- tres = year*365; /* Get # days of years so far */
- if (tres/365 != year)
- return -1; /* ERR: overflow */
- t = tres
- + ((year+1)>>2) /* plus # of leap days since 1970 */
- + yday; /* and finally add # days this year */
- if (t+4 < tres)
- return -1; /* ERR: overflow */
- }
- tres = t;
+You should have received a copy of the GNU General Public License
+along with RCS; see the file COPYING.
+If not, write to the Free Software Foundation,
+59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- if (given(i = tp->tm_wday)) /* Check WDAY if present */
- if (i != (tres+4)%7) /* 1970/01/01 was Thu = 4 */
- return -1; /* ERR: bad WDAY */
+Report problems and direct all questions to:
-#ifdef DEBUG
-printf("YMD: %d %d %d, T=%ld\n",year,mon,day,tres);
-#endif
- /*
- * Now determine time. If not given, default to zeros
- * (since time is always the least global spec)
- */
- tres *= 86400L; /* Get # seconds (24*60*60) */
- if (tres/86400L != t)
- return -1; /* ERR: overflow */
- hour = min = sec = 0;
- if (given(tp->tm_hour)) hour = tp->tm_hour;
- if (given(tp->tm_min )) min = tp->tm_min;
- if (given(tp->tm_sec )) sec = tp->tm_sec;
- if (60 <= (unsigned)min || 60 < (unsigned)sec)
- return -1; /* ERR: MS out of range */
- if (24 <= (unsigned)hour)
- if(hour != 24 || (min+sec) !=0) /* Allow 24:00 */
- return -1; /* ERR: H out of range */
-
- t = tres;
- tres += sec + 60L*(zone + min + 60*hour);
-
-#ifdef DEBUG
-printf("HMS: %d %d %d T=%ld\n",hour,min,sec,tres);
+ rcs-bugs@cs.purdue.edu
+
+*/
+
+#if has_conf_h
+# include "conf.h"
+#else
+# ifdef __STDC__
+# define P(x) x
+# else
+# define const
+# define P(x) ()
+# endif
+# include <stdlib.h>
+# include <time.h>
#endif
- if (!localzone) /* check for overflow */
- return (year<0 ? (tres<0||86400L<=tres) : tres<t) ? -1 : tres;
-
- /* Check results; LT may have had a different GMT offset back then. */
- tp = localtime(&tres);
- if (given(atm->tm_sec) && atm->tm_sec != tp->tm_sec)
- return -1; /* If seconds don't match, we're in trouble. */
- if (!(
- given(atm->tm_min) && atm->tm_min != tp->tm_min ||
- given(atm->tm_hour) && atm->tm_hour != tp->tm_hour ||
- given(atm->tm_mday) && atm->tm_mday != tp->tm_mday ||
- given(atm->tm_mon) && atm->tm_mon != tp->tm_mon ||
- given(atm->tm_year) && atm->tm_year != tp->tm_year
- ))
- return tres; /* Everything matches. */
-
- } while (--attempts);
-
- return -1;
+#include "partime.h"
+#include "maketime.h"
+
+char const maketId[]
+ = "$Id: maketime.c,v 1.3 1995/10/28 21:49:29 peter Exp $";
+
+static int isleap P((int));
+static int month_days P((struct tm const*));
+static time_t maketime P((struct partime const*,time_t));
+
+/*
+* For maximum portability, use only localtime and gmtime.
+* Make no assumptions about the time_t epoch or the range of time_t values.
+* Avoid mktime because it's not universal and because there's no easy,
+* portable way for mktime to yield the inverse of gmtime.
+*/
+
+#define TM_YEAR_ORIGIN 1900
+
+ static int
+isleap(y)
+ int y;
+{
+ return (y&3) == 0 && (y%100 != 0 || y%400 == 0);
+}
+
+static int const month_yday[] = {
+ /* days in year before start of months 0-12 */
+ 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365
+};
+
+/* Yield the number of days in TM's month. */
+ static int
+month_days(tm)
+ struct tm const *tm;
+{
+ int m = tm->tm_mon;
+ return month_yday[m+1] - month_yday[m]
+ + (m==1 && isleap(tm->tm_year + TM_YEAR_ORIGIN));
}
/*
-* Convert Unix time to struct tm format.
-* Use Coordinated Universal Time (UTC) if version 5 or newer;
-* use local time otherwise.
+* Convert UNIXTIME to struct tm form.
+* Use gmtime if available and if !LOCALZONE, localtime otherwise.
*/
- static struct tm const *
-time2tm(unixtime)
+ struct tm *
+time2tm(unixtime, localzone)
time_t unixtime;
+ int localzone;
{
- struct tm const *tm;
+ struct tm *tm;
# if TZ_must_be_set
static char const *TZ;
if (!TZ && !(TZ = getenv("TZ")))
- faterror("TZ is not set");
+ faterror("The TZ environment variable is not set; please set it to your timezone");
# endif
- if (!(tm = (RCSversion<VERSION(5) ? localtime : gmtime)(&unixtime)))
- faterror("UTC is not available; perhaps TZ is not set?");
+ if (localzone || !(tm = gmtime(&unixtime)))
+ tm = localtime(&unixtime);
return tm;
}
+/* Yield A - B, measured in seconds. */
+ time_t
+difftm(a, b)
+ struct tm const *a, *b;
+{
+ int ay = a->tm_year + (TM_YEAR_ORIGIN - 1);
+ int by = b->tm_year + (TM_YEAR_ORIGIN - 1);
+ int difference_in_day_of_year = a->tm_yday - b->tm_yday;
+ int intervening_leap_days = (
+ ((ay >> 2) - (by >> 2))
+ - (ay/100 - by/100)
+ + ((ay/100 >> 2) - (by/100 >> 2))
+ );
+ time_t difference_in_years = ay - by;
+ time_t difference_in_days = (
+ difference_in_years*365
+ + (intervening_leap_days + difference_in_day_of_year)
+ );
+ return
+ (
+ (
+ 24*difference_in_days
+ + (a->tm_hour - b->tm_hour)
+ )*60 + (a->tm_min - b->tm_min)
+ )*60 + (a->tm_sec - b->tm_sec);
+}
+
/*
-* Convert Unix time to RCS format.
-* For compatibility with older versions of RCS,
-* dates before AD 2000 are stored without the leading "19".
+* Adjust time T by adding SECONDS. SECONDS must be at most 24 hours' worth.
+* Adjust only T's year, mon, mday, hour, min and sec members;
+* plus adjust wday if it is defined.
*/
void
-time2date(unixtime,date)
- time_t unixtime;
- char date[datesize];
+adjzone(t, seconds)
+ register struct tm *t;
+ long seconds;
{
- register struct tm const *tm = time2tm(unixtime);
- VOID sprintf(date, DATEFORM,
- tm->tm_year + (tm->tm_year<100 ? 0 : 1900),
- tm->tm_mon+1, tm->tm_mday,
- tm->tm_hour, tm->tm_min, tm->tm_sec
- );
+ /*
+ * This code can be off by a second if SECONDS is not a multiple of 60,
+ * if T is local time, and if a leap second happens during this minute.
+ * But this bug has never occurred, and most likely will not ever occur.
+ * Liberia, the last country for which SECONDS % 60 was nonzero,
+ * switched to UTC in May 1972; the first leap second was in June 1972.
+ */
+ int leap_second = t->tm_sec == 60;
+ long sec = seconds + (t->tm_sec - leap_second);
+ if (sec < 0) {
+ if ((t->tm_min -= (59-sec)/60) < 0) {
+ if ((t->tm_hour -= (59-t->tm_min)/60) < 0) {
+ t->tm_hour += 24;
+ if (TM_DEFINED(t->tm_wday) && --t->tm_wday < 0)
+ t->tm_wday = 6;
+ if (--t->tm_mday <= 0) {
+ if (--t->tm_mon < 0) {
+ --t->tm_year;
+ t->tm_mon = 11;
+ }
+ t->tm_mday = month_days(t);
+ }
+ }
+ t->tm_min += 24 * 60;
+ }
+ sec += 24L * 60 * 60;
+ } else
+ if (60 <= (t->tm_min += sec/60))
+ if (24 <= (t->tm_hour += t->tm_min/60)) {
+ t->tm_hour -= 24;
+ if (TM_DEFINED(t->tm_wday) && ++t->tm_wday == 7)
+ t->tm_wday = 0;
+ if (month_days(t) < ++t->tm_mday) {
+ if (11 < ++t->tm_mon) {
+ ++t->tm_year;
+ t->tm_mon = 0;
+ }
+ t->tm_mday = 1;
+ }
+ }
+ t->tm_min %= 60;
+ t->tm_sec = (int) (sec%60) + leap_second;
}
+/*
+* Convert TM to time_t, using localtime if LOCALZONE and gmtime otherwise.
+* Use only TM's year, mon, mday, hour, min, and sec members.
+* Ignore TM's old tm_yday and tm_wday, but fill in their correct values.
+* Yield -1 on failure (e.g. a member out of range).
+* Posix 1003.1-1990 doesn't allow leap seconds, but some implementations
+* have them anyway, so allow them if localtime/gmtime does.
+*/
+ time_t
+tm2time(tm, localzone)
+ struct tm *tm;
+ int localzone;
+{
+ /* Cache the most recent t,tm pairs; 1 for gmtime, 1 for localtime. */
+ static time_t t_cache[2];
+ static struct tm tm_cache[2];
+
+ time_t d, gt;
+ struct tm const *gtm;
+ /*
+ * The maximum number of iterations should be enough to handle any
+ * combinations of leap seconds, time zone rule changes, and solar time.
+ * 4 is probably enough; we use a bigger number just to be safe.
+ */
+ int remaining_tries = 8;
+
+ /* Avoid subscript errors. */
+ if (12 <= (unsigned)tm->tm_mon)
+ return -1;
+
+ tm->tm_yday = month_yday[tm->tm_mon] + tm->tm_mday
+ - (tm->tm_mon<2 || ! isleap(tm->tm_year + TM_YEAR_ORIGIN));
+
+ /* Make a first guess. */
+ gt = t_cache[localzone];
+ gtm = gt ? &tm_cache[localzone] : time2tm(gt,localzone);
+
+ /* Repeatedly use the error from the guess to improve the guess. */
+ while ((d = difftm(tm, gtm)) != 0) {
+ if (--remaining_tries == 0)
+ return -1;
+ gt += d;
+ gtm = time2tm(gt,localzone);
+ }
+ t_cache[localzone] = gt;
+ tm_cache[localzone] = *gtm;
+
+ /*
+ * Check that the guess actually matches;
+ * overflow can cause difftm to yield 0 even on differing times,
+ * or tm may have members out of range (e.g. bad leap seconds).
+ */
+ if ( (tm->tm_year ^ gtm->tm_year)
+ | (tm->tm_mon ^ gtm->tm_mon)
+ | (tm->tm_mday ^ gtm->tm_mday)
+ | (tm->tm_hour ^ gtm->tm_hour)
+ | (tm->tm_min ^ gtm->tm_min)
+ | (tm->tm_sec ^ gtm->tm_sec))
+ return -1;
+ tm->tm_wday = gtm->tm_wday;
+ return gt;
+}
+/*
+* Check *PT and convert it to time_t.
+* If it is incompletely specified, use DEFAULT_TIME to fill it out.
+* Use localtime if PT->zone is the special value TM_LOCAL_ZONE.
+* Yield -1 on failure.
+* ISO 8601 day-of-year and week numbers are not yet supported.
+*/
static time_t
-str2time(source)
- char const *source;
-/* Parse a free-format date in SOURCE, yielding a Unix format time. */
+maketime(pt, default_time)
+ struct partime const *pt;
+ time_t default_time;
{
- int zone;
- time_t unixtime;
- struct tm parseddate;
+ int localzone, wday;
+ struct tm tm;
+ struct tm *tm0 = 0;
+ time_t r;
+
+ tm0 = 0; /* Keep gcc -Wall happy. */
+ localzone = pt->zone==TM_LOCAL_ZONE;
+
+ tm = pt->tm;
+
+ if (TM_DEFINED(pt->ymodulus) || !TM_DEFINED(tm.tm_year)) {
+ /* Get tm corresponding to current time. */
+ tm0 = time2tm(default_time, localzone);
+ if (!localzone)
+ adjzone(tm0, pt->zone);
+ }
+
+ if (TM_DEFINED(pt->ymodulus))
+ tm.tm_year +=
+ (tm0->tm_year + TM_YEAR_ORIGIN)/pt->ymodulus * pt->ymodulus;
+ else if (!TM_DEFINED(tm.tm_year)) {
+ /* Set default year, month, day from current time. */
+ tm.tm_year = tm0->tm_year + TM_YEAR_ORIGIN;
+ if (!TM_DEFINED(tm.tm_mon)) {
+ tm.tm_mon = tm0->tm_mon;
+ if (!TM_DEFINED(tm.tm_mday))
+ tm.tm_mday = tm0->tm_mday;
+ }
+ }
+
+ /* Convert from partime year (Gregorian) to Posix year. */
+ tm.tm_year -= TM_YEAR_ORIGIN;
+
+ /* Set remaining default fields to be their minimum values. */
+ if (!TM_DEFINED(tm.tm_mon)) tm.tm_mon = 0;
+ if (!TM_DEFINED(tm.tm_mday)) tm.tm_mday = 1;
+ if (!TM_DEFINED(tm.tm_hour)) tm.tm_hour = 0;
+ if (!TM_DEFINED(tm.tm_min)) tm.tm_min = 0;
+ if (!TM_DEFINED(tm.tm_sec)) tm.tm_sec = 0;
- if (!partime(source, &parseddate, &zone))
- faterror("can't parse date/time: %s", source);
- if ((unixtime = maketime(&parseddate, zone)) == -1)
- faterror("bad date/time: %s", source);
- return unixtime;
+ if (!localzone)
+ adjzone(&tm, -pt->zone);
+ wday = tm.tm_wday;
+
+ /* Convert and fill in the rest of the tm. */
+ r = tm2time(&tm, localzone);
+
+ /* Check weekday. */
+ if (r != -1 && TM_DEFINED(wday) && wday != tm.tm_wday)
+ return -1;
+
+ return r;
}
- void
-str2date(source, target)
+/* Parse a free-format date in SOURCE, yielding a Unix format time. */
+ time_t
+str2time(source, default_time, default_zone)
char const *source;
- char target[datesize];
-/* Parse a free-format date in SOURCE, convert it
- * into RCS internal format, and store the result into TARGET.
- */
+ time_t default_time;
+ long default_zone;
{
- time2date(str2time(source), target);
+ struct partime pt;
+
+ if (*partime(source, &pt))
+ return -1;
+ if (pt.zone == TM_UNDEFINED_ZONE)
+ pt.zone = default_zone;
+ return maketime(&pt, default_time);
}
+#if TEST
+#include <stdio.h>
int
-setfiledate(file, date)
- char const *file, date[datesize];
-/* Set the access and modification time of FILE to DATE. */
+main(argc, argv) int argc; char **argv;
{
- static struct utimbuf times; /* static so unused fields are zero */
- char datebuf[datesize];
-
- if (!date)
- return 0;
- times.actime = times.modtime = str2time(date2str(date, datebuf));
- return utime(file, &times);
+ time_t default_time = time((time_t *)0);
+ long default_zone = argv[1] ? atol(argv[1]) : 0;
+ char buf[1000];
+ while (fgets(buf, 1000, stdin)) {
+ time_t t = str2time(buf, default_time, default_zone);
+ printf("%s", asctime(gmtime(&t)));
+ }
+ return 0;
}
+#endif
diff --git a/gnu/usr.bin/rcs/lib/maketime.h b/gnu/usr.bin/rcs/lib/maketime.h
new file mode 100644
index 0000000..fbe1256
--- /dev/null
+++ b/gnu/usr.bin/rcs/lib/maketime.h
@@ -0,0 +1,39 @@
+/* Yield time_t from struct partime yielded by partime. */
+
+/* Copyright 1993, 1994, 1995 Paul Eggert
+ Distributed under license by the Free Software Foundation, Inc.
+
+This file is part of RCS.
+
+RCS is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+RCS is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with RCS; see the file COPYING.
+If not, write to the Free Software Foundation,
+59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+Report problems and direct all questions to:
+
+ rcs-bugs@cs.purdue.edu
+
+*/
+
+#if defined(__STDC__) || has_prototypes
+# define __MAKETIME_P(x) x
+#else
+# define __MAKETIME_P(x) ()
+#endif
+
+struct tm *time2tm __MAKETIME_P((time_t,int));
+time_t difftm __MAKETIME_P((struct tm const *, struct tm const *));
+time_t str2time __MAKETIME_P((char const *, time_t, long));
+time_t tm2time __MAKETIME_P((struct tm *, int));
+void adjzone __MAKETIME_P((struct tm *, long));
diff --git a/gnu/usr.bin/rcs/lib/merger.c b/gnu/usr.bin/rcs/lib/merger.c
index 7162ffa..fd36d26 100644
--- a/gnu/usr.bin/rcs/lib/merger.c
+++ b/gnu/usr.bin/rcs/lib/merger.c
@@ -1,6 +1,6 @@
-/* merger - three-way file merge internals */
+/* three-way file merge internals */
-/* Copyright 1991 by Paul Eggert
+/* Copyright 1991, 1992, 1993, 1994, 1995 Paul Eggert
Distributed under license by the Free Software Foundation, Inc.
This file is part of RCS.
@@ -16,8 +16,9 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
-along with RCS; see the file COPYING. If not, write to
-the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+along with RCS; see the file COPYING.
+If not, write to the Free Software Foundation,
+59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
Report problems and direct all questions to:
@@ -27,38 +28,40 @@ Report problems and direct all questions to:
#include "rcsbase.h"
-libId(mergerId, "$Id: merger.c,v 1.3 1991/08/20 23:05:00 eggert Exp $")
+libId(mergerId, "$Id: merger.c,v 1.7 1995/06/16 06:19:24 eggert Exp $")
+ static char const *normalize_arg P((char const*,char**));
static char const *
normalize_arg(s, b)
char const *s;
char **b;
/*
* If S looks like an option, prepend ./ to it. Yield the result.
- * Set *B to the address of any storage that was allocated..
+ * Set *B to the address of any storage that was allocated.
*/
{
char *t;
- switch (*s) {
- case '-': case '+':
- *b = t = testalloc(strlen(s) + 3);
- VOID sprintf(t, ".%c%s", SLASH, s);
- return t;
- default:
- *b = 0;
- return s;
+ if (*s == '-') {
+ *b = t = testalloc(strlen(s) + 3);
+ VOID sprintf(t, ".%c%s", SLASH, s);
+ return t;
+ } else {
+ *b = 0;
+ return s;
}
}
int
-merge(tostdout, label, argv)
+merge(tostdout, edarg, label, argv)
int tostdout;
- char const *const label[2];
+ char const *edarg;
+ char const *const label[3];
char const *const argv[3];
/*
- * Do `merge [-p] -L l0 -L l1 a0 a1 a2',
+ * Do `merge [-p] EDARG -L l0 -L l1 -L l2 a0 a1 a2',
* where TOSTDOUT specifies whether -p is present,
- * LABEL gives l0 and l1, and ARGV gives a0, a1, and a2.
+ * EDARG gives the editing type (e.g. "-A", or null for the default),
+ * LABEL gives l0, l1 and l2, and ARGV gives a0, a1 and a2.
* Yield DIFF_SUCCESS or DIFF_FAILURE.
*/
{
@@ -75,29 +78,34 @@ merge(tostdout, label, argv)
for (i=3; 0<=--i; )
a[i] = normalize_arg(argv[i], &b[i]);
+ if (!edarg)
+ edarg = "-E";
+
#if DIFF3_BIN
t = 0;
if (!tostdout)
t = maketemp(0);
s = run(
- (char*)0, t,
- DIFF3, "-am", "-L", label[0], "-L", label[1],
+ -1, t,
+ DIFF3, edarg, "-am",
+ "-L", label[0],
+ "-L", label[1],
+ "-L", label[2],
a[0], a[1], a[2], (char*)0
);
switch (s) {
case DIFF_SUCCESS:
break;
case DIFF_FAILURE:
- if (!quietflag)
- warn("overlaps during merge");
+ warn("conflicts during merge");
break;
default:
exiterr();
}
if (t) {
- if (!(f = fopen(argv[0], FOPEN_W)))
+ if (!(f = fopenSafer(argv[0], "w")))
efaterror(argv[0]);
- if (!(rt = Iopen(t, FOPEN_R, (struct stat*)0)))
+ if (!(rt = Iopen(t, "r", (struct stat*)0)))
efaterror(t);
fastcopy(rt, f);
Ifclose(rt);
@@ -106,29 +114,30 @@ merge(tostdout, label, argv)
#else
for (i=0; i<2; i++)
switch (run(
- (char*)0, d[i]=maketemp(i),
+ -1, d[i]=maketemp(i),
DIFF, a[i], a[2], (char*)0
)) {
case DIFF_FAILURE: case DIFF_SUCCESS: break;
- default: exiterr();
+ default: faterror("diff failed");
}
t = maketemp(2);
s = run(
- (char*)0, t,
- DIFF3, "-E", d[0], d[1], a[0], a[1], a[2],
- label[0], label[1], (char*)0
+ -1, t,
+ DIFF3, edarg, d[0], d[1], a[0], a[1], a[2],
+ label[0], label[2], (char*)0
);
if (s != DIFF_SUCCESS) {
s = DIFF_FAILURE;
- if (!quietflag)
- warn("overlaps or other problems during merge");
+ warn("overlaps or other problems during merge");
}
- if (!(f = fopen(t, "a")))
+ if (!(f = fopenSafer(t, "a+")))
efaterror(t);
aputs(tostdout ? "1,$p\n" : "w\n", f);
- Ofclose(f);
- if (run(t, (char*)0, ED, "-", a[0], (char*)0))
+ Orewind(f);
+ aflush(f);
+ if (run(fileno(f), (char*)0, ED, "-", a[0], (char*)0))
exiterr();
+ Ofclose(f);
#endif
tempunlink();
diff --git a/gnu/usr.bin/rcs/lib/partime.c b/gnu/usr.bin/rcs/lib/partime.c
index 4751fc5..4246566 100644
--- a/gnu/usr.bin/rcs/lib/partime.c
+++ b/gnu/usr.bin/rcs/lib/partime.c
@@ -1,639 +1,701 @@
-/*
- * PARTIME parse date/time string into a TM structure
- *
- * Returns:
- * 0 if parsing failed
- * else time values in specified TM structure and zone (unspecified values
- * set to TMNULL)
- * Notes:
- * This code is quasi-public; it may be used freely in like software.
- * It is not to be sold, nor used in licensed software without
- * permission of the author.
- * For everyone's benefit, please report bugs and improvements!
- * Copyright 1980 by Ken Harrenstien, SRI International.
- * (ARPANET: KLH @ SRI)
- */
-
-/* Hacknotes:
- * If parsing changed so that no backup needed, could perhaps modify
- * to use a FILE input stream. Need terminator, though.
- * Perhaps should return 0 on success, else a non-zero error val?
- */
-
-/* $Log: partime.c,v $
- * Revision 5.6 1991/08/19 03:13:55 eggert
- * Update timezones.
- *
- * Revision 5.5 1991/04/21 11:58:18 eggert
- * Don't put , just before } in initializer.
- *
- * Revision 5.4 1990/10/04 06:30:15 eggert
- * Remove date vs time heuristics that fail between 2000 and 2400.
- * Check for overflow when lexing an integer.
- * Parse 'Jan 10 LT' as 'Jan 10, LT', not 'Jan, 10 LT'.
- *
- * Revision 5.3 1990/09/24 18:56:31 eggert
- * Update timezones.
- *
- * Revision 5.2 1990/09/04 08:02:16 eggert
- * Don't parse two-digit years, because it won't work after 1999/12/31.
- * Don't permit 'Aug Aug'.
- *
- * Revision 5.1 1990/08/29 07:13:49 eggert
- * Be able to parse our own date format. Don't assume year<10000.
- *
- * Revision 5.0 1990/08/22 08:12:40 eggert
- * Switch to GMT and fix the bugs exposed thereby. Update timezones.
- * Ansify and Posixate. Fix peekahead and int-size bugs.
- *
- * Revision 1.4 89/05/01 14:48:46 narten
- * fixed #ifdef DEBUG construct
- *
- * Revision 1.3 88/08/28 14:53:40 eggert
- * Remove unportable "#endif XXX"s.
- *
- * Revision 1.2 87/03/27 14:21:53 jenkins
- * Port to suns
- *
- * Revision 1.1 82/05/06 11:38:26 wft
- * Initial revision
- *
- */
-
-#include "rcsbase.h"
-
-libId(partId, "$Id: partime.c,v 5.6 1991/08/19 03:13:55 eggert Exp $")
-
-#define given(v) (0 <= (v))
-#define TMNULL (-1) /* Items not given are given this value */
-#define TZ_OFFSET (24*60) /* TMNULL < zone_offset - TZ_OFFSET */
-
-struct tmwent {
- char const *went;
- short wval;
- char wflgs;
- char wtype;
-};
- /* wflgs */
-#define TWTIME 02 /* Word is a time value (absence implies date) */
-#define TWDST 04 /* Word is a DST-type timezone */
- /* wtype */
-#define TM_MON 1 /* month name */
-#define TM_WDAY 2 /* weekday name */
-#define TM_ZON 3 /* time zone name */
-#define TM_LT 4 /* local time */
-#define TM_DST 5 /* daylight savings time */
-#define TM_12 6 /* AM, PM, NOON, or MIDNIGHT */
- /* wval (for wtype==TM_12) */
-#define T12_AM 1
-#define T12_PM 2
-#define T12_NOON 12
-#define T12_MIDNIGHT 0
-
-static struct tmwent const tmwords [] = {
- {"january", 0, 0, TM_MON},
- {"february", 1, 0, TM_MON},
- {"march", 2, 0, TM_MON},
- {"april", 3, 0, TM_MON},
- {"may", 4, 0, TM_MON},
- {"june", 5, 0, TM_MON},
- {"july", 6, 0, TM_MON},
- {"august", 7, 0, TM_MON},
- {"september", 8, 0, TM_MON},
- {"october", 9, 0, TM_MON},
- {"november", 10, 0, TM_MON},
- {"december", 11, 0, TM_MON},
-
- {"sunday", 0, 0, TM_WDAY},
- {"monday", 1, 0, TM_WDAY},
- {"tuesday", 2, 0, TM_WDAY},
- {"wednesday", 3, 0, TM_WDAY},
- {"thursday", 4, 0, TM_WDAY},
- {"friday", 5, 0, TM_WDAY},
- {"saturday", 6, 0, TM_WDAY},
-
- {"gmt", 0*60, TWTIME, TM_ZON}, /* Greenwich */
- {"utc", 0*60, TWTIME, TM_ZON},
- {"ut", 0*60, TWTIME, TM_ZON},
- {"cut", 0*60, TWTIME, TM_ZON},
-
- {"nzst", -12*60, TWTIME, TM_ZON}, /* New Zealand */
- {"jst", -9*60, TWTIME, TM_ZON}, /* Japan */
- {"kst", -9*60, TWTIME, TM_ZON}, /* Korea */
- {"ist", -5*60-30, TWTIME, TM_ZON},/* India */
- {"eet", -2*60, TWTIME, TM_ZON}, /* Eastern Europe */
- {"cet", -1*60, TWTIME, TM_ZON}, /* Central Europe */
- {"met", -1*60, TWTIME, TM_ZON}, /* Middle Europe */
- {"wet", 0*60, TWTIME, TM_ZON}, /* Western Europe */
- {"nst", 3*60+30, TWTIME, TM_ZON},/* Newfoundland */
- {"ast", 4*60, TWTIME, TM_ZON}, /* Atlantic */
- {"est", 5*60, TWTIME, TM_ZON}, /* Eastern */
- {"cst", 6*60, TWTIME, TM_ZON}, /* Central */
- {"mst", 7*60, TWTIME, TM_ZON}, /* Mountain */
- {"pst", 8*60, TWTIME, TM_ZON}, /* Pacific */
- {"akst", 9*60, TWTIME, TM_ZON}, /* Alaska */
- {"hast", 10*60, TWTIME, TM_ZON}, /* Hawaii-Aleutian */
- {"hst", 10*60, TWTIME, TM_ZON}, /* Hawaii */
- {"sst", 11*60, TWTIME, TM_ZON}, /* Samoa */
-
- {"nzdt", -12*60, TWTIME+TWDST, TM_ZON}, /* New Zealand */
- {"kdt", -9*60, TWTIME+TWDST, TM_ZON}, /* Korea */
- {"bst", 0*60, TWTIME+TWDST, TM_ZON}, /* Britain */
- {"ndt", 3*60+30, TWTIME+TWDST, TM_ZON}, /* Newfoundland */
- {"adt", 4*60, TWTIME+TWDST, TM_ZON}, /* Atlantic */
- {"edt", 5*60, TWTIME+TWDST, TM_ZON}, /* Eastern */
- {"cdt", 6*60, TWTIME+TWDST, TM_ZON}, /* Central */
- {"mdt", 7*60, TWTIME+TWDST, TM_ZON}, /* Mountain */
- {"pdt", 8*60, TWTIME+TWDST, TM_ZON}, /* Pacific */
- {"akdt", 9*60, TWTIME+TWDST, TM_ZON}, /* Alaska */
- {"hadt", 10*60, TWTIME+TWDST, TM_ZON}, /* Hawaii-Aleutian */
+/* Parse a string, yielding a struct partime that describes it. */
-#if 0
- /*
- * The following names are duplicates or are not well attested.
- * A standard is needed.
- */
- {"east", -10*60, TWTIME, TM_ZON}, /* Eastern Australia */
- {"cast", -9*60-30, TWTIME, TM_ZON},/* Central Australia */
- {"cst", -8*60, TWTIME, TM_ZON}, /* China */
- {"hkt", -8*60, TWTIME, TM_ZON}, /* Hong Kong */
- {"sst", -8*60, TWTIME, TM_ZON}, /* Singapore */
- {"wast", -8*60, TWTIME, TM_ZON}, /* Western Australia */
- {"?", -6*60-30, TWTIME, TM_ZON},/* Burma */
- {"?", -4*60-30, TWTIME, TM_ZON},/* Afghanistan */
- {"it", -3*60-30, TWTIME, TM_ZON},/* Iran */
- {"ist", -2*60, TWTIME, TM_ZON}, /* Israel */
- {"mez", -1*60, TWTIME, TM_ZON}, /* Mittel-Europaeische Zeit */
- {"ast", 1*60, TWTIME, TM_ZON}, /* Azores */
- {"fst", 2*60, TWTIME, TM_ZON}, /* Fernando de Noronha */
- {"bst", 3*60, TWTIME, TM_ZON}, /* Brazil */
- {"wst", 4*60, TWTIME, TM_ZON}, /* Western Brazil */
- {"ast", 5*60, TWTIME, TM_ZON}, /* Acre Brazil */
- {"?", 9*60+30, TWTIME, TM_ZON},/* Marquesas */
- {"?", 12*60, TWTIME, TM_ZON}, /* Kwajalein */
-
- {"eadt", -10*60, TWTIME+TWDST, TM_ZON}, /* Eastern Australia */
- {"cadt", -9*60-30, TWTIME+TWDST, TM_ZON}, /* Central Australia */
- {"cdt", -8*60, TWTIME+TWDST, TM_ZON}, /* China */
- {"wadt", -8*60, TWTIME+TWDST, TM_ZON}, /* Western Australia */
- {"idt", -2*60, TWTIME+TWDST, TM_ZON}, /* Israel */
- {"eest", -2*60, TWTIME+TWDST, TM_ZON}, /* Eastern Europe */
- {"cest", -1*60, TWTIME+TWDST, TM_ZON}, /* Central Europe */
- {"mest", -1*60, TWTIME+TWDST, TM_ZON}, /* Middle Europe */
- {"mesz", -1*60, TWTIME+TWDST, TM_ZON}, /* Mittel-Europaeische Sommerzeit */
- {"west", 0*60, TWTIME+TWDST, TM_ZON}, /* Western Europe */
- {"adt", 1*60, TWTIME+TWDST, TM_ZON}, /* Azores */
- {"fdt", 2*60, TWTIME+TWDST, TM_ZON}, /* Fernando de Noronha */
- {"edt", 3*60, TWTIME+TWDST, TM_ZON}, /* Eastern Brazil */
- {"wdt", 4*60, TWTIME+TWDST, TM_ZON}, /* Western Brazil */
- {"adt", 5*60, TWTIME+TWDST, TM_ZON}, /* Acre Brazil */
+/* Copyright 1993, 1994, 1995 Paul Eggert
+ Distributed under license by the Free Software Foundation, Inc.
+
+This file is part of RCS.
+
+RCS is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+RCS is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with RCS; see the file COPYING.
+If not, write to the Free Software Foundation,
+59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+Report problems and direct all questions to:
+
+ rcs-bugs@cs.purdue.edu
+
+*/
+
+#if has_conf_h
+# include "conf.h"
+#else
+# ifdef __STDC__
+# define P(x) x
+# else
+# define const
+# define P(x) ()
+# endif
+# include <limits.h>
+# include <time.h>
#endif
- {"lt", 0, TWTIME, TM_LT}, /* local time */
- {"dst", 1*60, TWTIME, TM_DST}, /* daylight savings time */
- {"ddst", 2*60, TWTIME, TM_DST}, /* double dst */
+#include <ctype.h>
+#undef isdigit
+#define isdigit(c) (((unsigned)(c)-'0') <= 9) /* faster than stock */
+
+#include "partime.h"
+
+char const partimeId[]
+ = "$Id: partime.c,v 5.13 1995/06/16 06:19:24 eggert Exp $";
- {"am", T12_AM, TWTIME, TM_12},
- {"pm", T12_PM, TWTIME, TM_12},
- {"noon", T12_NOON, TWTIME, TM_12},
- {"midnight", T12_MIDNIGHT, TWTIME, TM_12},
- {0, 0, 0, 0} /* Zero entry to terminate searches */
+/* Lookup tables for names of months, weekdays, time zones. */
+
+#define NAME_LENGTH_MAXIMUM 4
+
+struct name_val {
+ char name[NAME_LENGTH_MAXIMUM];
+ int val;
};
-struct token {
- char const *tcp;/* pointer to string */
- int tcnt; /* # chars */
- char tbrk; /* "break" char */
- char tbrkl; /* last break char */
- char tflg; /* 0 = alpha, 1 = numeric */
- union { /* Resulting value; */
- int tnum;/* either a #, or */
- struct tmwent const *ttmw;/* a ptr to a tmwent. */
- } tval;
+
+static char const *parse_decimal P((char const*,int,int,int,int,int*,int*));
+static char const *parse_fixed P((char const*,int,int*));
+static char const *parse_pattern_letter P((char const*,int,struct partime*));
+static char const *parse_prefix P((char const*,struct partime*,int*));
+static char const *parse_ranged P((char const*,int,int,int,int*));
+static int lookup P((char const*,struct name_val const[]));
+static int merge_partime P((struct partime*, struct partime const*));
+static void undefine P((struct partime*));
+
+
+static struct name_val const month_names[] = {
+ {"jan",0}, {"feb",1}, {"mar",2}, {"apr",3}, {"may",4}, {"jun",5},
+ {"jul",6}, {"aug",7}, {"sep",8}, {"oct",9}, {"nov",10}, {"dec",11},
+ {"", TM_UNDEFINED}
};
-static struct tmwent const*ptmatchstr P((char const*,int,struct tmwent const*));
-static int pt12hack P((struct tm *,int));
-static int ptitoken P((struct token *));
-static int ptstash P((int *,int));
-static int pttoken P((struct token *));
+static struct name_val const weekday_names[] = {
+ {"sun",0}, {"mon",1}, {"tue",2}, {"wed",3}, {"thu",4}, {"fri",5}, {"sat",6},
+ {"", TM_UNDEFINED}
+};
+
+#define hr60nonnegative(t) ((t)/100 * 60 + (t)%100)
+#define hr60(t) ((t)<0 ? -hr60nonnegative(-(t)) : hr60nonnegative(t))
+#define zs(t,s) {s, hr60(t)}
+#define zd(t,s,d) zs(t, s), zs((t)+100, d)
+
+static struct name_val const zone_names[] = {
+ zs(-1000, "hst"), /* Hawaii */
+ zd(-1000,"hast","hadt"),/* Hawaii-Aleutian */
+ zd(- 900,"akst","akdt"),/* Alaska */
+ zd(- 800, "pst", "pdt"),/* Pacific */
+ zd(- 700, "mst", "mdt"),/* Mountain */
+ zd(- 600, "cst", "cdt"),/* Central */
+ zd(- 500, "est", "edt"),/* Eastern */
+ zd(- 400, "ast", "adt"),/* Atlantic */
+ zd(- 330, "nst", "ndt"),/* Newfoundland */
+ zs( 000, "utc"), /* Coordinated Universal */
+ zs( 000, "cut"), /* " */
+ zs( 000, "ut"), /* Universal */
+ zs( 000, "z"), /* Zulu (required by ISO 8601) */
+ zd( 000, "gmt", "bst"),/* Greenwich Mean, British Summer */
+ zs( 000, "wet"), /* Western Europe */
+ zs( 100, "met"), /* Middle Europe */
+ zs( 100, "cet"), /* Central Europe */
+ zs( 200, "eet"), /* Eastern Europe */
+ zs( 530, "ist"), /* India */
+ zd( 900, "jst", "jdt"),/* Japan */
+ zd( 900, "kst", "kdt"),/* Korea */
+ zd( 1200,"nzst","nzdt"),/* New Zealand */
+ { "lt", 1 },
+#if 0
+ /* The following names are duplicates or are not well attested. */
+ zs(-1100, "sst"), /* Samoa */
+ zs(-1000, "tht"), /* Tahiti */
+ zs(- 930, "mqt"), /* Marquesas */
+ zs(- 900, "gbt"), /* Gambier */
+ zd(- 900, "yst", "ydt"),/* Yukon - name is no longer used */
+ zs(- 830, "pit"), /* Pitcairn */
+ zd(- 500, "cst", "cdt"),/* Cuba */
+ zd(- 500, "ast", "adt"),/* Acre */
+ zd(- 400, "wst", "wdt"),/* Western Brazil */
+ zd(- 400, "ast", "adt"),/* Andes */
+ zd(- 400, "cst", "cdt"),/* Chile */
+ zs(- 300, "wgt"), /* Western Greenland */
+ zd(- 300, "est", "edt"),/* Eastern South America */
+ zs(- 300, "mgt"), /* Middle Greenland */
+ zd(- 200, "fst", "fdt"),/* Fernando de Noronha */
+ zs(- 100, "egt"), /* Eastern Greenland */
+ zs(- 100, "aat"), /* Atlantic Africa */
+ zs(- 100, "act"), /* Azores and Canaries */
+ zs( 000, "wat"), /* West Africa */
+ zs( 100, "cat"), /* Central Africa */
+ zd( 100, "mez","mesz"),/* Mittel-Europaeische Zeit */
+ zs( 200, "sat"), /* South Africa */
+ zd( 200, "ist", "idt"),/* Israel */
+ zs( 300, "eat"), /* East Africa */
+ zd( 300, "ast", "adt"),/* Arabia */
+ zd( 300, "msk", "msd"),/* Moscow */
+ zd( 330, "ist", "idt"),/* Iran */
+ zs( 400, "gst"), /* Gulf */
+ zs( 400, "smt"), /* Seychelles & Mascarene */
+ zd( 400, "esk", "esd"),/* Yekaterinburg */
+ zd( 400, "bsk", "bsd"),/* Baku */
+ zs( 430, "aft"), /* Afghanistan */
+ zd( 500, "osk", "osd"),/* Omsk */
+ zs( 500, "pkt"), /* Pakistan */
+ zd( 500, "tsk", "tsd"),/* Tashkent */
+ zs( 545, "npt"), /* Nepal */
+ zs( 600, "bgt"), /* Bangladesh */
+ zd( 600, "nsk", "nsd"),/* Novosibirsk */
+ zs( 630, "bmt"), /* Burma */
+ zs( 630, "cct"), /* Cocos */
+ zs( 700, "ict"), /* Indochina */
+ zs( 700, "jvt"), /* Java */
+ zd( 700, "isk", "isd"),/* Irkutsk */
+ zs( 800, "hkt"), /* Hong Kong */
+ zs( 800, "pst"), /* Philippines */
+ zs( 800, "sgt"), /* Singapore */
+ zd( 800, "cst", "cdt"),/* China */
+ zd( 800, "ust", "udt"),/* Ulan Bator */
+ zd( 800, "wst", "wst"),/* Western Australia */
+ zd( 800, "ysk", "ysd"),/* Yakutsk */
+ zs( 900, "blt"), /* Belau */
+ zs( 900, "mlt"), /* Moluccas */
+ zd( 900, "vsk", "vsd"),/* Vladivostok */
+ zd( 930, "cst", "cst"),/* Central Australia */
+ zs( 1000, "gst"), /* Guam */
+ zd( 1000, "gsk", "gsd"),/* Magadan */
+ zd( 1000, "est", "est"),/* Eastern Australia */
+ zd( 1100,"lhst","lhst"),/* Lord Howe */
+ zd( 1100, "psk", "psd"),/* Petropavlovsk-Kamchatski */
+ zs( 1100,"ncst"), /* New Caledonia */
+ zs( 1130,"nrft"), /* Norfolk */
+ zd( 1200, "ask", "asd"),/* Anadyr */
+ zs( 1245,"nz-chat"), /* Chatham */
+ zs( 1300, "tgt"), /* Tongatapu */
+#endif
+ {"", -1}
+};
static int
-goodzone(t, offset, am)
- register struct token const *t;
- int offset;
- int *am;
+lookup (s, table)
+ char const *s;
+ struct name_val const table[];
+/* Look for a prefix of S in TABLE, returning val for first matching entry. */
{
- register int m;
- if (
- t->tflg &&
- t->tcnt == 4+offset &&
- (m = t->tval.tnum) <= 2400 &&
- isdigit(t->tcp[offset]) &&
- (m%=100) < 60
- ) {
- m += t->tval.tnum/100 * 60;
- if (t->tcp[offset-1]=='+')
- m = -m;
- *am = m;
- return 1;
+ int j;
+ char buf[NAME_LENGTH_MAXIMUM];
+
+ for (j = 0; j < NAME_LENGTH_MAXIMUM; j++) {
+ unsigned char c = *s++;
+ buf[j] = isupper (c) ? tolower (c) : c;
+ if (!isalpha (c))
+ break;
+ }
+ for (; table[0].name[0]; table++)
+ for (j = 0; buf[j] == table[0].name[j]; )
+ if (++j == NAME_LENGTH_MAXIMUM || !table[0].name[j])
+ goto done;
+ done:
+ return table[0].val;
+}
+
+
+ static void
+undefine (t) struct partime *t;
+/* Set *T to ``undefined'' values. */
+{
+ t->tm.tm_sec = t->tm.tm_min = t->tm.tm_hour = t->tm.tm_mday = t->tm.tm_mon
+ = t->tm.tm_year = t->tm.tm_wday = t->tm.tm_yday
+ = t->ymodulus = t->yweek
+ = TM_UNDEFINED;
+ t->zone = TM_UNDEFINED_ZONE;
+}
+
+/*
+* Array of patterns to look for in a date string.
+* Order is important: we look for the first matching pattern
+* whose values do not contradict values that we already know about.
+* See `parse_pattern_letter' below for the meaning of the pattern codes.
+*/
+static char const * const patterns[] = {
+ /*
+ * These traditional patterns must come first,
+ * to prevent an ISO 8601 format from misinterpreting their prefixes.
+ */
+ "E_n_y", "x", /* RFC 822 */
+ "E_n", "n_E", "n", "t:m:s_A", "t:m_A", "t_A", /* traditional */
+ "y/N/D$", /* traditional RCS */
+
+ /* ISO 8601:1988 formats, generalized a bit. */
+ "y-N-D$", "4ND$", "Y-N$",
+ "RND$", "-R=N$", "-R$", "--N=D$", "N=DT",
+ "--N$", "---D$", "DT",
+ "Y-d$", "4d$", "R=d$", "-d$", "dT",
+ "y-W-X", "yWX", "y=W",
+ "-r-W-X", "r-W-XT", "-rWX", "rWXT", "-W=X", "W=XT", "-W",
+ "-w-X", "w-XT", "---X$", "XT", "4$",
+ "T",
+ "h:m:s$", "hms$", "h:m$", "hm$", "h$", "-m:s$", "-ms$", "-m$", "--s$",
+ "Y", "Z",
+
+ 0
+};
+
+ static char const *
+parse_prefix (str, t, pi) char const *str; struct partime *t; int *pi;
+/*
+* Parse an initial prefix of STR, setting *T accordingly.
+* Return the first character after the prefix, or 0 if it couldn't be parsed.
+* Start with pattern *PI; if success, set *PI to the next pattern to try.
+* Set *PI to -1 if we know there are no more patterns to try;
+* if *PI is initially negative, give up immediately.
+*/
+{
+ int i = *pi;
+ char const *pat;
+ unsigned char c;
+
+ if (i < 0)
+ return 0;
+
+ /* Remove initial noise. */
+ while (!isalnum (c = *str) && c != '-' && c != '+') {
+ if (!c) {
+ undefine (t);
+ *pi = -1;
+ return str;
+ }
+ str++;
}
+
+ /* Try a pattern until one succeeds. */
+ while ((pat = patterns[i++]) != 0) {
+ char const *s = str;
+ undefine (t);
+ do {
+ if (!(c = *pat++)) {
+ *pi = i;
+ return s;
+ }
+ } while ((s = parse_pattern_letter (s, c, t)) != 0);
+ }
+
return 0;
}
- int
-partime(astr, atm, zone)
-char const *astr;
-register struct tm *atm;
-int *zone;
+ static char const *
+parse_fixed (s, digits, res) char const *s; int digits, *res;
+/*
+* Parse an initial prefix of S of length DIGITS; it must be a number.
+* Store the parsed number into *RES.
+* Return the first character after the prefix, or 0 if it couldn't be parsed.
+*/
{
- register int i;
- struct token btoken, atoken;
- int zone_offset; /* minutes west of GMT, plus TZ_OFFSET */
- register char const *cp;
- register char ch;
- int ord, midnoon;
- int *atmfield, dst, m;
- int got1 = 0;
-
- atm->tm_sec = TMNULL;
- atm->tm_min = TMNULL;
- atm->tm_hour = TMNULL;
- atm->tm_mday = TMNULL;
- atm->tm_mon = TMNULL;
- atm->tm_year = TMNULL;
- atm->tm_wday = TMNULL;
- atm->tm_yday = TMNULL;
- midnoon = TMNULL; /* and our own temp stuff */
- zone_offset = TMNULL;
- dst = TMNULL;
- btoken.tcnt = btoken.tbrk = 0;
- btoken.tcp = astr;
-
- for (;; got1=1) {
- if (!ptitoken(&btoken)) /* Get a token */
- { if(btoken.tval.tnum) return(0); /* Read error? */
- if (given(midnoon)) /* EOF, wrap up */
- if (!pt12hack(atm, midnoon))
- return 0;
- if (!given(atm->tm_min))
- atm->tm_min = 0;
- *zone =
- (given(zone_offset) ? zone_offset-TZ_OFFSET : 0)
- - (given(dst) ? dst : 0);
- return got1;
- }
- if(btoken.tflg == 0) /* Alpha? */
- { i = btoken.tval.ttmw->wval;
- switch (btoken.tval.ttmw->wtype) {
- default:
+ int n = 0;
+ char const *lim = s + digits;
+ while (s < lim) {
+ unsigned d = *s++ - '0';
+ if (9 < d)
return 0;
- case TM_MON:
- atmfield = &atm->tm_mon;
- break;
- case TM_WDAY:
- atmfield = &atm->tm_wday;
- break;
- case TM_DST:
- atmfield = &dst;
+ n = 10*n + d;
+ }
+ *res = n;
+ return s;
+}
+
+ static char const *
+parse_ranged (s, digits, lo, hi, res) char const *s; int digits, lo, hi, *res;
+/*
+* Parse an initial prefix of S of length DIGITS;
+* it must be a number in the range LO through HI.
+* Store the parsed number into *RES.
+* Return the first character after the prefix, or 0 if it couldn't be parsed.
+*/
+{
+ s = parse_fixed (s, digits, res);
+ return s && lo<=*res && *res<=hi ? s : 0;
+}
+
+ static char const *
+parse_decimal (s, digits, lo, hi, resolution, res, fres)
+ char const *s;
+ int digits, lo, hi, resolution, *res, *fres;
+/*
+* Parse an initial prefix of S of length DIGITS;
+* it must be a number in the range LO through HI
+* and it may be followed by a fraction that is to be computed using RESOLUTION.
+* Store the parsed number into *RES; store the fraction times RESOLUTION,
+* rounded to the nearest integer, into *FRES.
+* Return the first character after the prefix, or 0 if it couldn't be parsed.
+*/
+{
+ s = parse_fixed (s, digits, res);
+ if (s && lo<=*res && *res<=hi) {
+ int f = 0;
+ if ((s[0]==',' || s[0]=='.') && isdigit ((unsigned char) s[1])) {
+ char const *s1 = ++s;
+ int num10 = 0, denom10 = 10, product;
+ while (isdigit ((unsigned char) *++s))
+ denom10 *= 10;
+ s = parse_fixed (s1, s - s1, &num10);
+ product = num10*resolution;
+ f = (product + (denom10>>1)) / denom10;
+ f -= f & (product%denom10 == denom10>>1); /* round to even */
+ if (f < 0 || product/resolution != num10)
+ return 0; /* overflow */
+ }
+ *fres = f;
+ return s;
+ }
+ return 0;
+}
+
+ char *
+parzone (s, zone) char const *s; long *zone;
+/*
+* Parse an initial prefix of S; it must denote a time zone.
+* Set *ZONE to the number of seconds east of GMT,
+* or to TM_LOCAL_ZONE if it is the local time zone.
+* Return the first character after the prefix, or 0 if it couldn't be parsed.
+*/
+{
+ char sign;
+ int hh, mm, ss;
+ int minutesEastOfUTC;
+ long offset, z;
+
+ /*
+ * The formats are LT, n, n DST, nDST, no, o
+ * where n is a time zone name
+ * and o is a time zone offset of the form [-+]hh[:mm[:ss]].
+ */
+ switch (*s) {
+ case '-': case '+':
+ z = 0;
break;
- case TM_LT:
- if (ptstash(&dst, 0))
+
+ default:
+ minutesEastOfUTC = lookup (s, zone_names);
+ if (minutesEastOfUTC == -1)
return 0;
- i = 48*60; /* local time magic number -- see maketime() */
- /* fall into */
- case TM_ZON:
- i += TZ_OFFSET;
- if (btoken.tval.ttmw->wflgs & TWDST)
- if (ptstash(&dst, 60))
- return 0;
- /* Peek ahead for offset immediately afterwards. */
+
+ /* Don't bother to check rest of spelling. */
+ while (isalpha ((unsigned char) *s))
+ s++;
+
+ /* Don't modify LT. */
+ if (minutesEastOfUTC == 1) {
+ *zone = TM_LOCAL_ZONE;
+ return (char *) s;
+ }
+
+ z = minutesEastOfUTC * 60L;
+
+ /* Look for trailing " DST". */
+ if (
+ (s[-1]=='T' || s[-1]=='t') &&
+ (s[-2]=='S' || s[-2]=='s') &&
+ (s[-3]=='D' || s[-3]=='t')
+ )
+ goto trailing_dst;
+ while (isspace ((unsigned char) *s))
+ s++;
if (
- (btoken.tbrk=='-' || btoken.tbrk=='+') &&
- (atoken=btoken, ++atoken.tcnt, ptitoken(&atoken)) &&
- goodzone(&atoken, 0, &m)
+ (s[0]=='D' || s[0]=='d') &&
+ (s[1]=='S' || s[1]=='s') &&
+ (s[2]=='T' || s[2]=='t')
) {
- i += m;
- btoken = atoken;
+ s += 3;
+ trailing_dst:
+ *zone = z + 60*60;
+ return (char *) s;
+ }
+
+ switch (*s) {
+ case '-': case '+': break;
+ default: return (char *) s;
}
- atmfield = &zone_offset;
- break;
- case TM_12:
- atmfield = &midnoon;
- }
- if (ptstash(atmfield, i))
- return(0); /* ERR: val already set */
- continue;
- }
-
- /* Token is number. Lots of hairy heuristics. */
- if (!isdigit(*btoken.tcp)) {
- if (!goodzone(&btoken, 1, &m))
- return 0;
- zone_offset = TZ_OFFSET + m;
- continue;
}
+ sign = *s++;
- i = btoken.tval.tnum; /* Value now known to be valid; get it. */
- if (btoken.tcnt == 3) /* 3 digits = HMM */
- {
-hhmm4: if (ptstash(&atm->tm_min, i%100))
- return(0); /* ERR: min conflict */
- i /= 100;
-hh2: if (ptstash(&atm->tm_hour, i))
- return(0); /* ERR: hour conflict */
- continue;
- }
-
- if (4 < btoken.tcnt)
- goto year4; /* far in the future */
- if(btoken.tcnt == 4) /* 4 digits = YEAR or HHMM */
- { if (given(atm->tm_year)) goto hhmm4; /* Already got yr? */
- if (given(atm->tm_hour)) goto year4; /* Already got hr? */
- if(btoken.tbrk == ':') /* HHMM:SS ? */
- if ( ptstash(&atm->tm_hour, i/100)
- || ptstash(&atm->tm_min, i%100))
- return(0); /* ERR: hr/min clash */
- else goto coltm2; /* Go handle SS */
- if(btoken.tbrk != ',' && btoken.tbrk != '/'
- && (atoken=btoken, ptitoken(&atoken)) /* Peek */
- && ( atoken.tflg
- ? !isdigit(*atoken.tcp)
- : atoken.tval.ttmw->wflgs & TWTIME)) /* HHMM-ZON */
- goto hhmm4;
- goto year4; /* Give up, assume year. */
- }
-
- /* From this point on, assume tcnt == 1 or 2 */
- /* 2 digits = MM, DD, or HH (MM and SS caught at coltime) */
- if(btoken.tbrk == ':') /* HH:MM[:SS] */
- goto coltime; /* must be part of time. */
- if (31 < i)
+ if (!(s = parse_ranged (s, 2, 0, 23, &hh)))
return 0;
-
- /* Check for numerical-format date */
- for (cp = "/-."; ch = *cp++;)
- { ord = (ch == '.' ? 0 : 1); /* n/m = D/M or M/D */
- if(btoken.tbrk == ch) /* "NN-" */
- { if(btoken.tbrkl != ch)
- {
- atoken = btoken;
- atoken.tcnt++;
- if (ptitoken(&atoken)
- && atoken.tflg == 0
- && atoken.tval.ttmw->wtype == TM_MON)
- goto dd2;
- if(ord)goto mm2; else goto dd2; /* "NN-" */
- } /* "-NN-" */
- if (!given(atm->tm_mday)
- && given(atm->tm_year)) /* If "YYYY-NN-" */
- goto mm2; /* then always MM */
- if(ord)goto dd2; else goto mm2;
- }
- if(btoken.tbrkl == ch /* "-NN" */
- && given(ord ? atm->tm_mon : atm->tm_mday))
- if (!given(ord ? atm->tm_mday : atm->tm_mon)) /* MM/DD */
- if(ord)goto dd2; else goto mm2;
- }
-
- /* Now reduced to choice between HH and DD */
- if (given(atm->tm_hour)) goto dd2; /* Have hour? Assume day. */
- if (given(atm->tm_mday)) goto hh2; /* Have day? Assume hour. */
- if (given(atm->tm_mon)) goto dd2; /* Have month? Assume day. */
- if(i > 24) goto dd2; /* Impossible HH means DD */
- atoken = btoken;
- if (!ptitoken(&atoken)) /* Read ahead! */
- if(atoken.tval.tnum) return(0); /* ERR: bad token */
- else goto dd2; /* EOF, assume day. */
- if ( atoken.tflg
- ? !isdigit(*atoken.tcp)
- : atoken.tval.ttmw->wflgs & TWTIME)
- /* If next token is a time spec, assume hour */
- goto hh2; /* e.g. "3 PM", "11-EDT" */
-
-dd2: if (ptstash(&atm->tm_mday, i)) /* Store day (1 based) */
- return(0);
- continue;
-
-mm2: if (ptstash(&atm->tm_mon, i-1)) /* Store month (make zero based) */
- return(0);
- continue;
-
-year4: if ((i-=1900) < 0 || ptstash(&atm->tm_year, i)) /* Store year-1900 */
- return(0); /* ERR: year conflict */
- continue;
-
- /* Hack HH:MM[[:]SS] */
-coltime:
- if (ptstash(&atm->tm_hour, i)) return 0;
- if (!ptitoken(&btoken))
- return(!btoken.tval.tnum);
- if(!btoken.tflg) return(0); /* ERR: HH:<alpha> */
- if(btoken.tcnt == 4) /* MMSS */
- if (ptstash(&atm->tm_min, btoken.tval.tnum/100)
- || ptstash(&atm->tm_sec, btoken.tval.tnum%100))
- return(0);
- else continue;
- if(btoken.tcnt != 2
- || ptstash(&atm->tm_min, btoken.tval.tnum))
- return(0); /* ERR: MM bad */
- if (btoken.tbrk != ':') continue; /* Seconds follow? */
-coltm2: if (!ptitoken(&btoken))
- return(!btoken.tval.tnum);
- if(!btoken.tflg || btoken.tcnt != 2 /* Verify SS */
- || ptstash(&atm->tm_sec, btoken.tval.tnum))
- return(0); /* ERR: SS bad */
- }
-}
-
-/* Store date/time value, return 0 if successful.
- * Fail if entry is already set.
- */
- static int
-ptstash(adr,val)
-int *adr;
-int val;
-{ register int *a;
- if (given(*(a=adr)))
- return 1;
- *a = val;
- return(0);
-}
-
-/* This subroutine is invoked for AM, PM, NOON and MIDNIGHT when wrapping up
- * just prior to returning from partime.
- */
- static int
-pt12hack(tm, aval)
-register struct tm *tm;
-register int aval;
-{ register int h = tm->tm_hour;
- switch (aval) {
- case T12_AM:
- case T12_PM:
- if (h > 12)
- return 0;
- if (h == 12)
- tm->tm_hour = 0;
- if (aval == T12_PM)
- tm->tm_hour += 12;
- break;
- default:
- if (0 < tm->tm_min || 0 < tm->tm_sec)
- return 0;
- if (!given(h) || h==12)
- tm->tm_hour = aval;
- else if (aval==T12_MIDNIGHT && (h==0 || h==24))
+ mm = ss = 0;
+ if (*s == ':')
+ s++;
+ if (isdigit ((unsigned char) *s)) {
+ if (!(s = parse_ranged (s, 2, 0, 59, &mm)))
return 0;
+ if (*s==':' && s[-3]==':' && isdigit ((unsigned char) s[1])) {
+ if (!(s = parse_ranged (s + 1, 2, 0, 59, &ss)))
+ return 0;
+ }
}
- return 1;
+ if (isdigit ((unsigned char) *s))
+ return 0;
+ offset = (hh*60 + mm)*60L + ss;
+ *zone = z + (sign=='-' ? -offset : offset);
+ /*
+ * ?? Are fractions allowed here?
+ * If so, they're not implemented.
+ */
+ return (char *) s;
}
-/* Get a token and identify it to some degree.
- * Returns 0 on failure; token.tval will be 0 for normal EOF, otherwise
- * hit error of some sort
- */
-
- static int
-ptitoken(tkp)
-register struct token *tkp;
+ static char const *
+parse_pattern_letter (s, c, t) char const *s; int c; struct partime *t;
+/*
+* Parse an initial prefix of S, matching the pattern whose code is C.
+* Set *T accordingly.
+* Return the first character after the prefix, or 0 if it couldn't be parsed.
+*/
{
- register char const *cp;
- register int i, j, k;
-
- if (!pttoken(tkp))
-#ifdef DEBUG
- {
- VOID printf("EOF\n");
- return(0);
- }
-#else
- return(0);
-#endif
- cp = tkp->tcp;
+ switch (c) {
+ case '$': /* The next character must be a non-digit. */
+ if (isdigit ((unsigned char) *s))
+ return 0;
+ break;
-#ifdef DEBUG
- VOID printf("Token: \"%.*s\" ", tkp->tcnt, cp);
-#endif
+ case '-': case '/': case ':':
+ /* These characters stand for themselves. */
+ if (*s++ != c)
+ return 0;
+ break;
- if (tkp->tflg) {
- i = tkp->tcnt;
- if (*cp == '+' || *cp == '-') {
- cp++;
- i--;
- }
- while (0 <= --i) {
- j = tkp->tval.tnum*10;
- k = j + (*cp++ - '0');
- if (j/10 != tkp->tval.tnum || k < j) {
- /* arithmetic overflow */
- tkp->tval.tnum = 1;
+ case '4': /* 4-digit year */
+ s = parse_fixed (s, 4, &t->tm.tm_year);
+ break;
+
+ case '=': /* optional '-' */
+ s += *s == '-';
+ break;
+
+ case 'A': /* AM or PM */
+ /*
+ * This matches the regular expression [AaPp][Mm]?.
+ * It must not be followed by a letter or digit;
+ * otherwise it would match prefixes of strings like "PST".
+ */
+ switch (*s++) {
+ case 'A': case 'a':
+ if (t->tm.tm_hour == 12)
+ t->tm.tm_hour = 0;
+ break;
+
+ case 'P': case 'p':
+ if (t->tm.tm_hour != 12)
+ t->tm.tm_hour += 12;
+ break;
+
+ default: return 0;
+ }
+ switch (*s) {
+ case 'M': case 'm': s++; break;
+ }
+ if (isalnum (*s))
return 0;
+ break;
+
+ case 'D': /* day of month [01-31] */
+ s = parse_ranged (s, 2, 1, 31, &t->tm.tm_mday);
+ break;
+
+ case 'd': /* day of year [001-366] */
+ s = parse_ranged (s, 3, 1, 366, &t->tm.tm_yday);
+ t->tm.tm_yday--;
+ break;
+
+ case 'E': /* extended day of month [1-9, 01-31] */
+ s = parse_ranged (s, (
+ isdigit ((unsigned char) s[0]) &&
+ isdigit ((unsigned char) s[1])
+ ) + 1, 1, 31, &t->tm.tm_mday);
+ break;
+
+ case 'h': /* hour [00-23 followed by optional fraction] */
+ {
+ int frac;
+ s = parse_decimal (s, 2, 0, 23, 60*60, &t->tm.tm_hour, &frac);
+ t->tm.tm_min = frac / 60;
+ t->tm.tm_sec = frac % 60;
}
- tkp->tval.tnum = k;
- }
- } else if (!(tkp->tval.ttmw = ptmatchstr(cp, tkp->tcnt, tmwords)))
- {
-#ifdef DEBUG
- VOID printf("Not found!\n");
-#endif
- tkp->tval.tnum = 1;
- return 0;
- }
+ break;
-#ifdef DEBUG
- if(tkp->tflg)
- VOID printf("Val: %d.\n",tkp->tval.tnum);
- else VOID printf("Found: \"%s\", val: %d, type %d\n",
- tkp->tval.ttmw->went,tkp->tval.ttmw->wval,tkp->tval.ttmw->wtype);
-#endif
+ case 'm': /* minute [00-59 followed by optional fraction] */
+ s = parse_decimal (s, 2, 0, 59, 60, &t->tm.tm_min, &t->tm.tm_sec);
+ break;
+
+ case 'n': /* month name [e.g. "Jan"] */
+ if (!TM_DEFINED (t->tm.tm_mon = lookup (s, month_names)))
+ return 0;
+ /* Don't bother to check rest of spelling. */
+ while (isalpha ((unsigned char) *s))
+ s++;
+ break;
+
+ case 'N': /* month [01-12] */
+ s = parse_ranged (s, 2, 1, 12, &t->tm.tm_mon);
+ t->tm.tm_mon--;
+ break;
- return(1);
+ case 'r': /* year % 10 (remainder in origin-0 decade) [0-9] */
+ s = parse_fixed (s, 1, &t->tm.tm_year);
+ t->ymodulus = 10;
+ break;
+
+ case_R:
+ case 'R': /* year % 100 (remainder in origin-0 century) [00-99] */
+ s = parse_fixed (s, 2, &t->tm.tm_year);
+ t->ymodulus = 100;
+ break;
+
+ case 's': /* second [00-60 followed by optional fraction] */
+ {
+ int frac;
+ s = parse_decimal (s, 2, 0, 60, 1, &t->tm.tm_sec, &frac);
+ t->tm.tm_sec += frac;
+ }
+ break;
+
+ case 'T': /* 'T' or 't' */
+ switch (*s++) {
+ case 'T': case 't': break;
+ default: return 0;
+ }
+ break;
+
+ case 't': /* traditional hour [1-9 or 01-12] */
+ s = parse_ranged (s, (
+ isdigit ((unsigned char) s[0]) && isdigit ((unsigned char) s[1])
+ ) + 1, 1, 12, &t->tm.tm_hour);
+ break;
+
+ case 'w': /* 'W' or 'w' only (stands for current week) */
+ switch (*s++) {
+ case 'W': case 'w': break;
+ default: return 0;
+ }
+ break;
+
+ case 'W': /* 'W' or 'w', followed by a week of year [00-53] */
+ switch (*s++) {
+ case 'W': case 'w': break;
+ default: return 0;
+ }
+ s = parse_ranged (s, 2, 0, 53, &t->yweek);
+ break;
+
+ case 'X': /* weekday (1=Mon ... 7=Sun) [1-7] */
+ s = parse_ranged (s, 1, 1, 7, &t->tm.tm_wday);
+ t->tm.tm_wday--;
+ break;
+
+ case 'x': /* weekday name [e.g. "Sun"] */
+ if (!TM_DEFINED (t->tm.tm_wday = lookup (s, weekday_names)))
+ return 0;
+ /* Don't bother to check rest of spelling. */
+ while (isalpha ((unsigned char) *s))
+ s++;
+ break;
+
+ case 'y': /* either R or Y */
+ if (
+ isdigit ((unsigned char) s[0]) &&
+ isdigit ((unsigned char) s[1]) &&
+ !isdigit ((unsigned char) s[2])
+ )
+ goto case_R;
+ /* fall into */
+ case 'Y': /* year in full [4 or more digits] */
+ {
+ int len = 0;
+ while (isdigit ((unsigned char) s[len]))
+ len++;
+ if (len < 4)
+ return 0;
+ s = parse_fixed (s, len, &t->tm.tm_year);
+ }
+ break;
+
+ case 'Z': /* time zone */
+ s = parzone (s, &t->zone);
+ break;
+
+ case '_': /* possibly empty sequence of non-alphanumerics */
+ while (!isalnum (*s) && *s)
+ s++;
+ break;
+
+ default: /* bad pattern */
+ return 0;
+ }
+ return s;
}
-/* Read token from input string into token structure */
static int
-pttoken(tkp)
-register struct token *tkp;
+merge_partime (t, u) struct partime *t; struct partime const *u;
+/*
+* If there is no conflict, merge into *T the additional information in *U
+* and return 0. Otherwise do nothing and return -1.
+*/
{
- register char const *cp;
- register int c;
- char const *astr;
-
- tkp->tcp = astr = cp = tkp->tcp + tkp->tcnt;
- tkp->tbrkl = tkp->tbrk; /* Set "last break" */
- tkp->tcnt = tkp->tbrk = tkp->tflg = 0;
- tkp->tval.tnum = 0;
-
- while(c = *cp++)
- { switch(c)
- { case ' ': case '\t': /* Flush all whitespace */
- case '\r': case '\n':
- case '\v': case '\f':
- if (!tkp->tcnt) { /* If no token yet */
- tkp->tcp = cp; /* ignore the brk */
- continue; /* and go on. */
- }
- /* fall into */
- case '(': case ')': /* Perhaps any non-alphanum */
- case '-': case ',': /* shd qualify as break? */
- case '+':
- case '/': case ':': case '.': /* Break chars */
- if(tkp->tcnt == 0) /* If no token yet */
- { tkp->tcp = cp; /* ignore the brk */
- tkp->tbrkl = c;
- continue; /* and go on. */
- }
- tkp->tbrk = c;
- return(tkp->tcnt);
- }
- if (!tkp->tcnt++) { /* If first char of token, */
- if (isdigit(c)) {
- tkp->tflg = 1;
- if (astr<cp-2 && (cp[-2]=='-'||cp[-2]=='+')) {
- /* timezone is break+sign+digit */
- tkp->tcp--;
- tkp->tcnt++;
- }
- }
- } else if ((isdigit(c)!=0) != tkp->tflg) { /* else check type */
- tkp->tbrk = c;
- return --tkp->tcnt; /* Wrong type, back up */
- }
- }
- return(tkp->tcnt); /* When hit EOF */
+# define conflict(a,b) ((a) != (b) && TM_DEFINED (a) && TM_DEFINED (b))
+ if (
+ conflict (t->tm.tm_sec, u->tm.tm_sec) ||
+ conflict (t->tm.tm_min, u->tm.tm_min) ||
+ conflict (t->tm.tm_hour, u->tm.tm_hour) ||
+ conflict (t->tm.tm_mday, u->tm.tm_mday) ||
+ conflict (t->tm.tm_mon, u->tm.tm_mon) ||
+ conflict (t->tm.tm_year, u->tm.tm_year) ||
+ conflict (t->tm.tm_wday, u->tm.tm_yday) ||
+ conflict (t->ymodulus, u->ymodulus) ||
+ conflict (t->yweek, u->yweek) ||
+ (
+ t->zone != u->zone &&
+ t->zone != TM_UNDEFINED_ZONE &&
+ u->zone != TM_UNDEFINED_ZONE
+ )
+ )
+ return -1;
+# undef conflict
+# define merge_(a,b) if (TM_DEFINED (b)) (a) = (b);
+ merge_ (t->tm.tm_sec, u->tm.tm_sec)
+ merge_ (t->tm.tm_min, u->tm.tm_min)
+ merge_ (t->tm.tm_hour, u->tm.tm_hour)
+ merge_ (t->tm.tm_mday, u->tm.tm_mday)
+ merge_ (t->tm.tm_mon, u->tm.tm_mon)
+ merge_ (t->tm.tm_year, u->tm.tm_year)
+ merge_ (t->tm.tm_wday, u->tm.tm_yday)
+ merge_ (t->ymodulus, u->ymodulus)
+ merge_ (t->yweek, u->yweek)
+# undef merge_
+ if (u->zone != TM_UNDEFINED_ZONE) t->zone = u->zone;
+ return 0;
}
-
- static struct tmwent const *
-ptmatchstr(astr,cnt,astruc)
- char const *astr;
- int cnt;
- struct tmwent const *astruc;
+ char *
+partime (s, t) char const *s; struct partime *t;
+/*
+* Parse a date/time prefix of S, putting the parsed result into *T.
+* Return the first character after the prefix.
+* The prefix may contain no useful information;
+* in that case, *T will contain only undefined values.
+*/
{
- register char const *cp, *mp;
- register int c;
- struct tmwent const *lastptr;
- int i;
-
- lastptr = 0;
- for(;mp = astruc->went; astruc += 1)
- { cp = astr;
- for(i = cnt; i > 0; i--)
- {
- switch (*cp++ - (c = *mp++))
- { case 0: continue; /* Exact match */
- case 'A'-'a':
- if (ctab[c] == Letter)
- continue;
- }
- break;
- }
- if(i==0)
- if (!*mp) return astruc; /* Exact match */
- else if(lastptr) return(0); /* Ambiguous */
- else lastptr = astruc; /* 1st ambig */
- }
- return lastptr;
+ struct partime p;
+
+ undefine (t);
+ while (*s) {
+ int i = 0;
+ char const *s1;
+ do {
+ if (!(s1 = parse_prefix (s, &p, &i)))
+ return (char *) s;
+ } while (merge_partime (t, &p) != 0);
+ s = s1;
+ }
+ return (char *) s;
}
diff --git a/gnu/usr.bin/rcs/lib/partime.h b/gnu/usr.bin/rcs/lib/partime.h
new file mode 100644
index 0000000..5d3983f
--- /dev/null
+++ b/gnu/usr.bin/rcs/lib/partime.h
@@ -0,0 +1,71 @@
+/* Parse a string, yielding a struct partime that describes it. */
+
+/* Copyright 1993, 1994, 1995 Paul Eggert
+ Distributed under license by the Free Software Foundation, Inc.
+
+This file is part of RCS.
+
+RCS is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+RCS is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with RCS; see the file COPYING.
+If not, write to the Free Software Foundation,
+59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+Report problems and direct all questions to:
+
+ rcs-bugs@cs.purdue.edu
+
+*/
+
+#define TM_UNDEFINED (-1)
+#define TM_DEFINED(x) (0 <= (x))
+
+#define TM_UNDEFINED_ZONE ((long) -24 * 60 * 60)
+#define TM_LOCAL_ZONE (TM_UNDEFINED_ZONE - 1)
+
+struct partime {
+ /*
+ * This structure describes the parsed time.
+ * Only the following tm_* values in it are used:
+ * sec, min, hour, mday, mon, year, wday, yday.
+ * If TM_UNDEFINED(value), the parser never found the value.
+ * The tm_year field is the actual year, not the year - 1900;
+ * but see ymodulus below.
+ */
+ struct tm tm;
+
+ /*
+ * If !TM_UNDEFINED(ymodulus),
+ * then tm.tm_year is actually modulo ymodulus.
+ */
+ int ymodulus;
+
+ /*
+ * Week of year, ISO 8601 style.
+ * If TM_UNDEFINED(yweek), the parser never found yweek.
+ * Weeks start on Mondays.
+ * Week 1 includes Jan 4.
+ */
+ int yweek;
+
+ /* Seconds east of UTC; or TM_LOCAL_ZONE or TM_UNDEFINED_ZONE. */
+ long zone;
+};
+
+#if defined(__STDC__) || has_prototypes
+# define __PARTIME_P(x) x
+#else
+# define __PARTIME_P(x) ()
+#endif
+
+char *partime __PARTIME_P((char const *, struct partime *));
+char *parzone __PARTIME_P((char const *, long *));
diff --git a/gnu/usr.bin/rcs/lib/rcsbase.h b/gnu/usr.bin/rcs/lib/rcsbase.h
index c0904bb..31fb6ff 100644
--- a/gnu/usr.bin/rcs/lib/rcsbase.h
+++ b/gnu/usr.bin/rcs/lib/rcsbase.h
@@ -1,11 +1,9 @@
+/* RCS common definitions and data structures */
-/*
- * RCS common definitions and data structures
- */
-#define RCSBASE "$Id: rcsbase.h,v 5.11 1991/10/07 17:32:46 eggert Exp $"
+#define RCSBASE "$Id: rcsbase.h,v 1.5 1995/10/29 19:31:09 peter Exp $"
-/* Copyright (C) 1982, 1988, 1989 Walter Tichy
- Copyright 1990, 1991 by Paul Eggert
+/* Copyright 1982, 1988, 1989 Walter Tichy
+ Copyright 1990, 1991, 1992, 1993, 1994, 1995 Paul Eggert
Distributed under license by the Free Software Foundation, Inc.
This file is part of RCS.
@@ -21,8 +19,9 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
-along with RCS; see the file COPYING. If not, write to
-the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+along with RCS; see the file COPYING.
+If not, write to the Free Software Foundation,
+59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
Report problems and direct all questions to:
@@ -30,19 +29,54 @@ Report problems and direct all questions to:
*/
-
-
-/*****************************************************************************
- * INSTRUCTIONS:
- * =============
- * See the Makefile for how to define C preprocessor symbols.
- * If you need to change the comment leaders, update the table comtable[]
- * in rcsfnms.c. (This can wait until you know what a comment leader is.)
- *****************************************************************************
- */
-
-
-/* $Log: rcsbase.h,v $
+/*
+ * Revision 5.20 1995/06/16 06:19:24 eggert
+ * Update FSF address.
+ *
+ * Revision 5.19 1995/06/01 16:23:43 eggert
+ * (SIZEABLE_PATH): Don't depend on PATH_MAX: it's not worth configuring.
+ * (Ioffset_type,BINARY_EXPAND,MIN_UNEXPAND,MIN_UNCHANGED_EXPAND): New macros.
+ * (maps_memory): New macro; replaces many instances of `has_mmap'.
+ * (cacheptr): Renamed from cachetell.
+ * (struct RILE): New alternate name for RILE; the type is now recursive.
+ * (deallocate): New member for RILE, used for generic buffer deallocation.
+ * (cacheunget_): No longer take a failure arg; just call Ierror on failure.
+ * (struct rcslock): Renamed from struct lock, to avoid collisions with
+ * system headers on some hosts. All users changed.
+ * (basefilename): Renamed from basename, likewise.
+ * (dirtpname): Remove; no longer external.
+ * (dirlen, dateform): Remove; no longer used.
+ * (cmpdate, fopenSafer, fdSafer, readAccessFilenameBuffer): New functions.
+ * (zonelenmax): Increase to 9 for full ISO 8601 format.
+ * (catchmmapints): Depend on has_NFS.
+ *
+ * Revision 5.18 1994/03/17 14:05:48 eggert
+ * Add primitives for reading backwards from a RILE;
+ * this is needed to go back and find the $Log prefix.
+ * Specify subprocess input via file descriptor, not file name. Remove lint.
+ *
+ * Revision 5.17 1993/11/09 17:40:15 eggert
+ * Move RCS-specific time handling into rcstime.c.
+ * printf_string now takes two arguments, alas.
+ *
+ * Revision 5.16 1993/11/03 17:42:27 eggert
+ * Don't arbitrarily limit the number of joins. Remove `nil'.
+ * Add Name keyword. Don't discard ignored phrases.
+ * Add support for merge -A vs -E, and allow up to three labels.
+ * Improve quality of diagnostics and prototypes.
+ *
+ * Revision 5.15 1992/07/28 16:12:44 eggert
+ * Statement macro names now end in _.
+ *
+ * Revision 5.14 1992/02/17 23:02:22 eggert
+ * Add -T support. Work around NFS mmap SIGBUS problem.
+ *
+ * Revision 5.13 1992/01/24 18:44:19 eggert
+ * Add support for bad_creat0. lint -> RCS_lint
+ *
+ * Revision 5.12 1992/01/06 02:42:34 eggert
+ * while (E) ; -> while (E) continue;
+ *
* Revision 5.11 1991/10/07 17:32:46 eggert
* Support piece tables even if !has_mmap.
*
@@ -85,45 +119,45 @@ Report problems and direct all questions to:
* Remove snoop and v2 support.
*
* Revision 4.9 89/05/01 15:17:14 narten
- * botched previous USG fix
- *
+ * botched previous USG fix
+ *
* Revision 4.8 89/05/01 14:53:05 narten
* changed #include <strings.h> -> string.h for USG systems.
- *
+ *
* Revision 4.7 88/11/08 15:58:45 narten
* removed defs for functions loaded from libraries
- *
+ *
* Revision 4.6 88/08/09 19:12:36 eggert
* Shrink stdio code size; remove lint; permit -Dhshsize=nn.
- *
+ *
* Revision 4.5 87/12/18 17:06:41 narten
* made removed BSD ifdef, now uses V4_2BSD
- *
+ *
* Revision 4.4 87/10/18 10:29:49 narten
* Updating version numbers
* Changes relative to 1.1 are actually relative to 4.2
- *
+ *
* Revision 1.3 87/09/24 14:02:25 narten
* changes for lint
- *
+ *
* Revision 1.2 87/03/27 14:22:02 jenkins
* Port to suns
- *
+ *
* Revision 4.2 83/12/20 16:04:20 wft
* merged 3.6.1.1 and 4.1 (SMALLOG, logsize).
* moved setting of STRICT_LOCKING to Makefile.
* changed DOLLAR to UNKN (conflict with KDELIM).
- *
+ *
* Revision 4.1 83/05/04 09:12:41 wft
* Added markers Id and RCSfile.
* Added Dbranch for default branches.
- *
+ *
* Revision 3.6.1.1 83/12/02 21:56:22 wft
* Increased logsize, added macro SMALLOG.
- *
+ *
* Revision 3.6 83/01/15 16:43:28 wft
* 4.2 prerelease
- *
+ *
* Revision 3.6 83/01/15 16:43:28 wft
* Replaced dbm.h with BYTESIZ, fixed definition of rindex().
* Added variants of NCPFN and NCPPN for bsd 4.2, selected by defining V4_2BSD.
@@ -156,10 +190,10 @@ Report problems and direct all questions to:
#define EXIT_TROUBLE DIFF_TROUBLE
-#ifdef PATH_MAX
-# define SIZEABLE_PATH PATH_MAX /* size of a large path; not a hard limit */
-#else
+#ifdef _POSIX_PATH_MAX
# define SIZEABLE_PATH _POSIX_PATH_MAX
+#else
+# define SIZEABLE_PATH 255 /* size of a large path; not a hard limit */
#endif
/* for traditional C hosts with unusual size arguments */
@@ -188,8 +222,7 @@ Report problems and direct all questions to:
/* used in production environments. */
#define yearlength 16 /* (good through AD 9,999,999,999,999,999) */
-#define datesize (yearlength+16) /* size of output of DATEFORM */
-#define joinlength 20 /* number of joined revisions permitted */
+#define datesize (yearlength+16) /* size of output of time2date */
#define RCSTMPPREFIX '_' /* prefix for temp files in working dir */
#define KDELIM '$' /* delimiter for keywords */
#define VDELIM ':' /* separates keywords from values */
@@ -199,7 +232,6 @@ Report problems and direct all questions to:
#define true 1
#define false 0
-#define nil 0
/*
@@ -208,68 +240,79 @@ Report problems and direct all questions to:
* setupcache - sets up the local RILE cache, but does not initialize it
* cache, uncache - caches and uncaches the local RILE;
* (uncache,cache) is needed around functions that advance the RILE pointer
- * Igeteof(f,c,s) - get a char c from f, executing statement s at EOF
- * cachegeteof(c,s) - Igeteof applied to the local RILE
- * Iget(f,c) - like Igeteof, except EOF is an error
- * cacheget(c) - Iget applied to the local RILE
- * Ifileno, Irewind, Iseek, Itell - analogs to stdio routines
+ * Igeteof_(f,c,s) - get a char c from f, executing statement s at EOF
+ * cachegeteof_(c,s) - Igeteof_ applied to the local RILE
+ * Iget_(f,c) - like Igeteof_, except EOF is an error
+ * cacheget_(c) - Iget_ applied to the local RILE
+ * cacheunget_(f,c,s) - read c backwards from cached f, executing s at BOF
+ * Ifileno, Ioffset_type, Irewind, Itell - analogs to stdio routines
+ *
+ * By conventions, macros whose names end in _ are statements, not expressions.
+ * Following such macros with `; else' results in a syntax error.
*/
+#define maps_memory (has_map_fd || has_mmap)
+
#if large_memory
typedef unsigned char const *Iptr_type;
- typedef struct {
+ typedef struct RILE {
Iptr_type ptr, lim;
- unsigned char *base; /* for lint, not Iptr_type even if has_mmap */
-# if has_mmap
-# define Ifileno(f) ((f)->fd)
- int fd;
+ unsigned char *base; /* not Iptr_type for lint's sake */
+ unsigned char *readlim;
+ int fd;
+# if maps_memory
+ void (*deallocate) P((struct RILE *));
# else
-# define Ifileno(f) fileno((f)->stream)
FILE *stream;
- unsigned char *readlim;
# endif
} RILE;
-# if has_mmap
+# if maps_memory
# define declarecache register Iptr_type ptr, lim
# define setupcache(f) (lim = (f)->lim)
-# define Igeteof(f,c,s) if ((f)->ptr==(f)->lim) s else (c)= *(f)->ptr++
-# define cachegeteof(c,s) if (ptr==lim) s else (c)= *ptr++
+# define Igeteof_(f,c,s) if ((f)->ptr==(f)->lim) s else (c)= *(f)->ptr++;
+# define cachegeteof_(c,s) if (ptr==lim) s else (c)= *ptr++;
# else
+ int Igetmore P((RILE*));
# define declarecache register Iptr_type ptr; register RILE *rRILE
# define setupcache(f) (rRILE = (f))
-# define Igeteof(f,c,s) if ((f)->ptr==(f)->readlim && !Igetmore(f)) s else (c)= *(f)->ptr++
-# define cachegeteof(c,s) if (ptr==rRILE->readlim && !Igetmore(rRILE)) s else (c)= *ptr++
+# define Igeteof_(f,c,s) if ((f)->ptr==(f)->readlim && !Igetmore(f)) s else (c)= *(f)->ptr++;
+# define cachegeteof_(c,s) if (ptr==rRILE->readlim && !Igetmore(rRILE)) s else (c)= *ptr++;
# endif
# define uncache(f) ((f)->ptr = ptr)
# define cache(f) (ptr = (f)->ptr)
-# define Iget(f,c) Igeteof(f,c,Ieof();)
-# define cacheget(c) cachegeteof(c,Ieof();)
-# define Itell(f) ((f)->ptr)
-# define Iseek(f,p) ((f)->ptr = (p))
-# define Irewind(f) Iseek(f, (f)->base)
-# define cachetell() ptr
+# define Iget_(f,c) Igeteof_(f,c,Ieof();)
+# define cacheget_(c) cachegeteof_(c,Ieof();)
+# define cacheunget_(f,c) (c)=(--ptr)[-1];
+# define Ioffset_type size_t
+# define Itell(f) ((f)->ptr - (f)->base)
+# define Irewind(f) ((f)->ptr = (f)->base)
+# define cacheptr() ptr
+# define Ifileno(f) ((f)->fd)
#else
# define RILE FILE
# define declarecache register FILE *ptr
# define setupcache(f) (ptr = (f))
# define uncache(f)
# define cache(f)
-# define Igeteof(f,c,s) if(((c)=getc(f))<0){testIerror(f);if(feof(f))s}else
-# define cachegeteof(c,s) Igeteof(ptr,c,s)
-# define Iget(f,c) if (((c)=getc(f))<0) testIeof(f); else
-# define cacheget(c) Iget(ptr,c)
+# define Igeteof_(f,c,s) {if(((c)=getc(f))==EOF){testIerror(f);if(feof(f))s}}
+# define cachegeteof_(c,s) Igeteof_(ptr,c,s)
+# define Iget_(f,c) { if (((c)=getc(f))==EOF) testIeof(f); }
+# define cacheget_(c) Iget_(ptr,c)
+# define cacheunget_(f,c) if(fseek(ptr,-2L,SEEK_CUR))Ierror();else cacheget_(c)
+# define Ioffset_type long
+# define Itell(f) ftell(f)
# define Ifileno(f) fileno(f)
#endif
/* Print a char, but abort on write error. */
-#define aputc(c,o) if (putc(c,o)<0) testOerror(o); else
+#define aputc_(c,o) { if (putc(c,o)==EOF) testOerror(o); }
/* Get a character from an RCS file, perhaps copying to a new RCS file. */
-#define GETCeof(o,c,s) { cachegeteof(c,s); if (o) aputc(c,o); }
-#define GETC(o,c) { cacheget(c); if (o) aputc(c,o); }
+#define GETCeof_(o,c,s) { cachegeteof_(c,s) if (o) aputc_(c,o) }
+#define GETC_(o,c) { cacheget_(c) if (o) aputc_(c,o) }
-#define WORKMODE(RCSmode, writable) ((RCSmode)&~(S_IWUSR|S_IWGRP|S_IWOTH) | ((writable)?S_IWUSR:0))
+#define WORKMODE(RCSmode, writable) (((RCSmode)&(mode_t)~(S_IWUSR|S_IWGRP|S_IWOTH)) | ((writable)?S_IWUSR:0))
/* computes mode of working file: same as RCSmode, but write permission */
/* determined by writable */
@@ -286,7 +329,7 @@ enum tokens {
* there should be no overlap among SDELIM, KDELIM, and VDELIM
*/
-#define isdigit(c) ((unsigned)((c)-'0') <= 9) /* faster than ctab[c]==DIGIT */
+#define isdigit(c) (((unsigned)(c)-'0') <= 9) /* faster than ctab[c]==DIGIT */
@@ -313,13 +356,15 @@ struct hshentry {
char const * author; /* login of person checking in */
char const * lockedby; /* who locks the revision */
char const * state; /* state of revision (Exp by default) */
+ char const * name; /* name (if any) by which retrieved */
struct cbuf log; /* log message requested at checkin */
struct branchhead * branches; /* list of first revisions on branches*/
- struct cbuf ig; /* ignored phrases of revision */
+ struct cbuf ig; /* ignored phrases in admin part */
+ struct cbuf igtext; /* ignored phrases in deltatext part */
struct hshentry * next; /* next revision on same branch */
struct hshentry * nexthsh; /* next revision with same hash value */
- unsigned long insertlns;/* lines inserted (computed by rlog) */
- unsigned long deletelns;/* lines deleted (computed by rlog) */
+ long insertlns;/* lines inserted (computed by rlog) */
+ long deletelns;/* lines deleted (computed by rlog) */
char selector; /* true if selected, false if deleted */
};
@@ -342,10 +387,10 @@ struct access {
};
/* list element for locks */
-struct lock {
+struct rcslock {
char const * login;
struct hshentry * delta;
- struct lock * nextlock;
+ struct rcslock * nextlock;
};
/* list element for symbolic names */
@@ -358,12 +403,12 @@ struct assoc {
#define mainArgs (argc,argv) int argc; char **argv;
-#if lint
+#if RCS_lint
# define libId(name,rcsid)
# define mainProg(name,cmd,rcsid) int name mainArgs
#else
# define libId(name,rcsid) char const name[] = rcsid;
-# define mainProg(name,cmd,rcsid) char const copyright[] = "Copyright 1982,1988,1989 by Walter F. Tichy\nPurdue CS\nCopyright 1990,1991 by Paul Eggert", rcsbaseId[] = RCSBASE, cmdid[] = cmd; libId(name,rcsid) int main mainArgs
+# define mainProg(n,c,i) char const Copyright[] = "Copyright 1982,1988,1989 Walter F. Tichy, Purdue CS\nCopyright 1990,1991,1992,1993,1994,1995 Paul Eggert", baseid[] = RCSBASE, cmdid[] = c; libId(n,i) int main P((int,char**)); int main mainArgs
#endif
/*
@@ -376,14 +421,16 @@ struct assoc {
#define IDH "Id"
#define LOCKER "Locker"
#define LOG "Log"
+#define NAME "Name"
#define RCSFILE "RCSfile"
#define REVISION "Revision"
#define SOURCE "Source"
#define STATE "State"
+#define FREEBSD "FreeBSD"
#define keylength 8 /* max length of any of the above keywords */
enum markers { Nomatch, Author, Date, Header, Id,
- Locker, Log, RCSfile, Revision, Source, State };
+ Locker, Log, Name, RCSfile, Revision, Source, State, FreeBSD };
/* This must be in the same order as rcskeys.c's Keyword[] array. */
#define DELNUMFORM "\n\n%s\n%s\n"
@@ -393,39 +440,31 @@ enum markers { Nomatch, Author, Date, Header, Id,
/* main program */
extern char const cmdid[];
-exiting void exiterr P((void));
-
-/* maketime */
-int setfiledate P((char const*,char const[datesize]));
-void str2date P((char const*,char[datesize]));
-void time2date P((time_t,char[datesize]));
+void exiterr P((void)) exiting;
/* merge */
-int merge P((int,char const*const[2],char const*const[3]));
-
-/* partime */
-int partime P((char const*,struct tm*,int*));
+int merge P((int,char const*,char const*const[3],char const*const[3]));
/* rcsedit */
#define ciklogsize 23 /* sizeof("checked in with -k by ") */
extern FILE *fcopy;
-extern char const *resultfile;
+extern char const *resultname;
extern char const ciklog[ciklogsize];
extern int locker_expansion;
-extern struct buf dirtfname[];
-#define newRCSfilename (dirtfname[0].string)
RILE *rcswriteopen P((struct buf*,struct stat*,int));
-char const *makedirtemp P((char const*,int));
+char const *makedirtemp P((int));
char const *getcaller P((void));
-int addlock P((struct hshentry*));
+int addlock P((struct hshentry*,int));
int addsymbol P((char const*,char const*,int));
int checkaccesslist P((void));
-int chnamemod P((FILE**,char const*,char const*,mode_t));
-int donerewrite P((int));
+int chnamemod P((FILE**,char const*,char const*,int,mode_t,time_t));
+int donerewrite P((int,time_t));
int dorewrite P((int,int));
-int expandline P((RILE*,FILE*,struct hshentry const*,int,FILE*));
+int expandline P((RILE*,FILE*,struct hshentry const*,int,FILE*,int));
int findlock P((int,struct hshentry**));
-void aflush P((FILE*));
+int setmtime P((char const*,time_t));
+void ORCSclose P((void));
+void ORCSerror P((void));
void copystring P((void));
void dirtempunlink P((void));
void enterstring P((void));
@@ -450,20 +489,21 @@ void xpandstring P((struct hshentry const*));
int rcsfcmp P((RILE*,struct stat const*,char const*,struct hshentry const*));
/* rcsfnms */
-#define bufautobegin(b) ((void) ((b)->string = 0, (b)->size = 0))
+#define bufautobegin(b) clear_buf(b)
+#define clear_buf(b) (VOID ((b)->string = 0, (b)->size = 0))
extern FILE *workstdout;
-extern char *workfilename;
-extern char const *RCSfilename;
+extern char *workname;
+extern char const *RCSname;
extern char const *suffixes;
+extern int fdlock;
extern struct stat RCSstat;
RILE *rcsreadopen P((struct buf*,struct stat*,int));
char *bufenlarge P((struct buf*,char const**));
-char const *basename P((char const*));
+char const *basefilename P((char const*));
char const *getfullRCSname P((void));
char const *maketemp P((int));
char const *rcssuffix P((char const*));
-int pairfilenames P((int,char**,RILE*(*)P((struct buf*,struct stat*,int)),int,int));
-size_t dirlen P((char const*));
+int pairnames P((int,char**,RILE*(*)P((struct buf*,struct stat*,int)),int,int));
struct cbuf bufremember P((struct buf*,size_t));
void bufalloc P((struct buf*,size_t));
void bufautoend P((struct buf*));
@@ -477,15 +517,17 @@ extern int interactiveflag;
extern struct buf curlogbuf;
char const *buildrevision P((struct hshentries const*,struct hshentry*,FILE*,int));
int getcstdin P((void));
+int putdtext P((struct hshentry const*,char const*,FILE*,int));
int ttystdin P((void));
-int yesorno P((int,char const*,...));
+int yesorno P((int,char const*,...)) printf_string(2,3);
struct cbuf cleanlogmsg P((char*,size_t));
struct cbuf getsstdin P((char const*,char const*,char const*,struct buf*));
void putdesc P((int,char*));
+void putdftext P((struct hshentry const*,RILE*,FILE*,int));
/* rcskeep */
extern int prevkeys;
-extern struct buf prevauthor, prevdate, prevrev, prevstate;
+extern struct buf prevauthor, prevdate, prevname, prevrev, prevstate;
int getoldkeys P((RILE*));
/* rcskeys */
@@ -502,16 +544,19 @@ extern int hshenter;
extern int nerror;
extern int nextc;
extern int quietflag;
-extern unsigned long rcsline;
+extern long rcsline;
char const *getid P((void));
-exiting void efaterror P((char const*));
-exiting void enfaterror P((int,char const*));
-exiting void faterror P((char const*,...));
-exiting void fatserror P((char const*,...));
-exiting void Ieof P((void));
-exiting void Ierror P((void));
-exiting void Oerror P((void));
+void efaterror P((char const*)) exiting;
+void enfaterror P((int,char const*)) exiting;
+void fatcleanup P((int)) exiting;
+void faterror P((char const*,...)) printf_string_exiting(1,2);
+void fatserror P((char const*,...)) printf_string_exiting(1,2);
+void rcsfaterror P((char const*,...)) printf_string_exiting(1,2);
+void Ieof P((void)) exiting;
+void Ierror P((void)) exiting;
+void Oerror P((void)) exiting;
char *checkid P((char*,int));
+char *checksym P((char*,int));
int eoflex P((void));
int getkeyopt P((char const*));
int getlex P((enum tokens));
@@ -522,16 +567,19 @@ void Ifclose P((RILE*));
void Izclose P((RILE**));
void Lexinit P((void));
void Ofclose P((FILE*));
+void Orewind P((FILE*));
void Ozclose P((FILE**));
+void aflush P((FILE*));
void afputc P((int,FILE*));
-void aprintf P((FILE*,char const*,...));
+void aprintf P((FILE*,char const*,...)) printf_string(2,3);
void aputs P((char const*,FILE*));
void checksid P((char*));
-void diagnose P((char const*,...));
+void checkssym P((char*));
+void diagnose P((char const*,...)) printf_string(1,2);
void eerror P((char const*));
void eflush P((void));
void enerror P((int,char const*));
-void error P((char const*,...));
+void error P((char const*,...)) printf_string(1,2);
void fvfprintf P((FILE*,char const*,va_list));
void getkey P((char const*));
void getkeystring P((char const*));
@@ -540,10 +588,14 @@ void oflush P((void));
void printstring P((void));
void readstring P((void));
void redefined P((int));
+void rcserror P((char const*,...)) printf_string(1,2);
+void rcswarn P((char const*,...)) printf_string(1,2);
void testIerror P((FILE*));
void testOerror P((FILE*));
-void warn P((char const*,...));
+void warn P((char const*,...)) printf_string(1,2);
void warnignore P((void));
+void workerror P((char const*,...)) printf_string(1,2);
+void workwarn P((char const*,...)) printf_string(1,2);
#if has_madvise && has_mmap && large_memory
void advise_access P((RILE*,int));
# define if_advise_access(p,f,advice) if (p) advise_access(f,advice)
@@ -551,7 +603,7 @@ void warnignore P((void));
# define advise_access(f,advice)
# define if_advise_access(p,f,advice)
#endif
-#if has_mmap && large_memory
+#if large_memory && maps_memory
RILE *I_open P((char const*,struct stat*));
# define Iopen(f,m,s) I_open(f,s)
#else
@@ -563,18 +615,20 @@ void warnignore P((void));
#endif
/* rcsmap */
-extern const enum tokens ctab[];
+extern enum tokens const ctab[];
/* rcsrev */
-char *partialno P((struct buf*,char const*,unsigned));
+char *partialno P((struct buf*,char const*,int));
+char const *namedrev P((char const*,struct hshentry*));
char const *tiprev P((void));
+int cmpdate P((char const*,char const*));
int cmpnum P((char const*,char const*));
-int cmpnumfld P((char const*,char const*,unsigned));
-int compartial P((char const*,char const*,unsigned));
+int cmpnumfld P((char const*,char const*,int));
+int compartial P((char const*,char const*,int));
int expandsym P((char const*,struct buf*));
int fexpandsym P((char const*,struct buf*,RILE*));
struct hshentry *genrevs P((char const*,char const*,char const*,char const*,struct hshentries**));
-unsigned countnumflds P((char const*));
+int countnumflds P((char const*));
void getbranchno P((char const*,struct buf*));
/* rcssyn */
@@ -584,8 +638,12 @@ void getbranchno P((char const*,struct buf*));
#define KEY_EXPAND 2 /* -kk `$Keyword$' */
#define VAL_EXPAND 3 /* -kv `value' */
#define OLD_EXPAND 4 /* -ko use old string, omitting expansion */
+#define BINARY_EXPAND 5 /* -kb like -ko, but use binary mode I/O */
+#define MIN_UNEXPAND OLD_EXPAND /* min value for no logical expansion */
+#define MIN_UNCHANGED_EXPAND (OPEN_O_BINARY ? BINARY_EXPAND : OLD_EXPAND)
+ /* min value guaranteed to yield an identical file */
struct diffcmd {
- unsigned long
+ long
line1, /* number of first line */
nlines, /* number of lines affected */
adprev, /* previous 'a' line1+1 or 'd' line1 */
@@ -595,45 +653,55 @@ extern char const * Dbranch;
extern struct access * AccessList;
extern struct assoc * Symbols;
extern struct cbuf Comment;
-extern struct lock * Locks;
+extern struct cbuf Ignored;
+extern struct rcslock *Locks;
extern struct hshentry * Head;
extern int Expand;
extern int StrictLocks;
-extern unsigned TotalDeltas;
+extern int TotalDeltas;
extern char const *const expand_names[];
-extern char const Kdesc[];
-extern char const Klog[];
-extern char const Ktext[];
+extern char const
+ Kaccess[], Kauthor[], Kbranch[], Kcomment[],
+ Kdate[], Kdesc[], Kexpand[], Khead[], Klocks[], Klog[],
+ Knext[], Kstate[], Kstrict[], Ksymbols[], Ktext[];
+void unexpected_EOF P((void)) exiting;
int getdiffcmd P((RILE*,int,FILE*,struct diffcmd*));
-int putdftext P((char const*,struct cbuf,RILE*,FILE*,int));
-int putdtext P((char const*,struct cbuf,char const*,FILE*,int));
int str2expmode P((char const*));
void getadmin P((void));
void getdesc P((int));
void gettree P((void));
-void ignorephrase P((void));
+void ignorephrases P((char const*));
void initdiffcmd P((struct diffcmd*));
-void putadmin P((FILE*));
+void putadmin P((void));
void putstring P((FILE*,int,struct cbuf,int));
void puttree P((struct hshentry const*,FILE*));
+/* rcstime */
+#define zonelenmax 9 /* maxiumum length of time zone string, e.g. "+12:34:56" */
+char const *date2str P((char const[datesize],char[datesize + zonelenmax]));
+time_t date2time P((char const[datesize]));
+void str2date P((char const*,char[datesize]));
+void time2date P((time_t,char[datesize]));
+void zone_set P((char const*));
+
/* rcsutil */
extern int RCSversion;
+FILE *fopenSafer P((char const*,char const*));
char *cgetenv P((char const*));
char *fstr_save P((char const*));
char *str_save P((char const*));
-char const *date2str P((char const[datesize],char[datesize]));
char const *getusername P((int));
+int fdSafer P((int));
int getRCSINIT P((int,char**,char***));
-int run P((char const*,char const*,...));
-int runv P((char const**));
+int run P((int,char const*,...));
+int runv P((int,char const*,char const**));
malloc_type fremember P((malloc_type));
malloc_type ftestalloc P((size_t));
malloc_type testalloc P((size_t));
malloc_type testrealloc P((malloc_type,size_t));
#define ftalloc(T) ftnalloc(T,1)
#define talloc(T) tnalloc(T,1)
-#if lint
+#if RCS_lint
extern malloc_type lintalloc;
# define ftnalloc(T,n) (lintalloc = ftestalloc(sizeof(T)*(n)), (T*)0)
# define tnalloc(T,n) (lintalloc = testalloc(sizeof(T)*(n)), (T*)0)
@@ -645,6 +713,7 @@ malloc_type testrealloc P((malloc_type,size_t));
# define trealloc(T,p,n) ((T*) testrealloc((malloc_type)(p), sizeof(T)*(n)))
# define tfree(p) free((malloc_type)(p))
#endif
+time_t now P((void));
void awrite P((char const*,size_t,FILE*));
void fastcopy P((RILE*,FILE*));
void ffree P((void));
@@ -659,6 +728,14 @@ void setRCSversion P((char const*));
# define ignoreints()
# define restoreints()
#endif
+#if has_mmap && large_memory
+# if has_NFS && mmap_signal
+ void catchmmapints P((void));
+ void readAccessFilenameBuffer P((char const*,unsigned char const*));
+# else
+# define catchmmapints()
+# endif
+#endif
#if has_getuid
uid_t ruid P((void));
# define myself(u) ((u) == ruid())
@@ -675,3 +752,6 @@ void setRCSversion P((char const*));
# define seteid()
# define setrid()
#endif
+
+/* version */
+extern char const RCS_version_string[];
diff --git a/gnu/usr.bin/rcs/lib/rcsedit.c b/gnu/usr.bin/rcs/lib/rcsedit.c
index fab4f62..7273de5 100644
--- a/gnu/usr.bin/rcs/lib/rcsedit.c
+++ b/gnu/usr.bin/rcs/lib/rcsedit.c
@@ -1,15 +1,14 @@
-/*
- * RCS stream editor
- */
-/**********************************************************************************
+/* RCS stream editor */
+
+/******************************************************************************
* edits the input file according to a
* script from stdin, generated by diff -n
* performs keyword expansion
- **********************************************************************************
+ ******************************************************************************
*/
-/* Copyright (C) 1982, 1988, 1989 Walter Tichy
- Copyright 1990, 1991 by Paul Eggert
+/* Copyright 1982, 1988, 1989 Walter Tichy
+ Copyright 1990, 1991, 1992, 1993, 1994, 1995 Paul Eggert
Distributed under license by the Free Software Foundation, Inc.
This file is part of RCS.
@@ -25,8 +24,9 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
-along with RCS; see the file COPYING. If not, write to
-the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+along with RCS; see the file COPYING.
+If not, write to the Free Software Foundation,
+59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
Report problems and direct all questions to:
@@ -34,8 +34,55 @@ Report problems and direct all questions to:
*/
-
-/* $Log: rcsedit.c,v $
+/*
+ * Revision 5.19 1995/06/16 06:19:24 eggert
+ * Update FSF address.
+ *
+ * Revision 5.18 1995/06/01 16:23:43 eggert
+ * (dirtpname): No longer external.
+ * (do_link): Simplify logic.
+ * (finisheditline, finishedit): Replace Iseek/Itell with what they stand for.
+ * (fopen_update_truncate): Replace `#if' with `if'.
+ * (keyreplace, makedirtemp): dirlen(x) -> basefilename(x)-x.
+ *
+ * (edit_string): Fix bug: if !large_memory, a bogus trailing `@' was output
+ * at the end of incomplete lines.
+ *
+ * (keyreplace): Do not assume that seeking backwards
+ * at the start of a file will fail; on some systems it succeeds.
+ * Convert C- and Pascal-style comment starts to ` *' in comment leader.
+ *
+ * (rcswriteopen): Use fdSafer to get safer file descriptor.
+ * Open RCS file with FOPEN_RB.
+ *
+ * (chnamemod): Work around bad_NFS_rename bug; don't ignore un_link result.
+ * Fall back on chmod if fchmod fails, since it might be ENOSYS.
+ *
+ * (aflush): Move to rcslex.c.
+ *
+ * Revision 5.17 1994/03/20 04:52:58 eggert
+ * Normally calculate the $Log prefix from context, not from RCS file.
+ * Move setmtime here from rcsutil.c. Add ORCSerror. Remove lint.
+ *
+ * Revision 5.16 1993/11/03 17:42:27 eggert
+ * Add -z. Add Name keyword. If bad_unlink, ignore errno when unlink fails.
+ * Escape white space, $, and \ in keyword string file names.
+ * Don't output 2 spaces between date and time after Log.
+ *
+ * Revision 5.15 1992/07/28 16:12:44 eggert
+ * Some hosts have readlink but not ELOOP. Avoid `unsigned'.
+ * Preserve dates more systematically. Statement macro names now end in _.
+ *
+ * Revision 5.14 1992/02/17 23:02:24 eggert
+ * Add -T support.
+ *
+ * Revision 5.13 1992/01/24 18:44:19 eggert
+ * Add support for bad_chmod_close, bad_creat0.
+ *
+ * Revision 5.12 1992/01/06 02:42:34 eggert
+ * Add setmode parameter to chnamemod. addsymbol now reports changes.
+ * while (E) ; -> while (E) continue;
+ *
* Revision 5.11 1991/11/03 01:11:44 eggert
* Move the warning about link breaking to where they're actually being broken.
*
@@ -82,50 +129,50 @@ Report problems and direct all questions to:
*
* Revision 4.8 89/05/01 15:12:35 narten
* changed copyright header to reflect current distribution rules
- *
+ *
* Revision 4.7 88/11/08 13:54:14 narten
* misplaced semicolon caused infinite loop
- *
+ *
* Revision 4.6 88/08/09 19:12:45 eggert
* Shrink stdio code size; allow cc -R.
- *
+ *
* Revision 4.5 87/12/18 11:38:46 narten
* Changes from the 43. version. Don't know the significance of the
* first change involving "rewind". Also, additional "lint" cleanup.
* (Guy Harris)
- *
+ *
* Revision 4.4 87/10/18 10:32:21 narten
* Updating version numbers. Changes relative to version 1.1 actually
* relative to 4.1
- *
+ *
* Revision 1.4 87/09/24 13:59:29 narten
- * Sources now pass through lint (if you ignore printf/sprintf/fprintf
+ * Sources now pass through lint (if you ignore printf/sprintf/fprintf
* warnings)
- *
+ *
* Revision 1.3 87/09/15 16:39:39 shepler
* added an initializatin of the variables editline and linecorr
* this will be done each time a file is processed.
* (there was an obscure bug where if co was used to retrieve multiple files
* it would dump)
* fix attributed to Roy Morris @FileNet Corp ...!felix!roy
- *
+ *
* Revision 1.2 87/03/27 14:22:17 jenkins
* Port to suns
- *
+ *
* Revision 4.1 83/05/12 13:10:30 wft
* Added new markers Id and RCSfile; added locker to Header and Id.
* Overhauled expandline completely() (problem with $01234567890123456789@).
* Moved trymatch() and marker table to rcskeys.c.
- *
+ *
* Revision 3.7 83/05/12 13:04:39 wft
* Added retry to expandline to resume after failed match which ended in $.
* Fixed truncation problem for $19chars followed by@@.
* Log no longer expands full path of RCS file.
- *
+ *
* Revision 3.6 83/05/11 16:06:30 wft
* added retry to expandline to resume after failed match which ended in $.
* Fixed truncation problem for $19chars followed by@@.
- *
+ *
* Revision 3.5 82/12/04 13:20:56 wft
* Added expansion of keyword Locker.
*
@@ -154,27 +201,36 @@ Report problems and direct all questions to:
#include "rcsbase.h"
-libId(editId, "$Id: rcsedit.c,v 5.11 1991/11/03 01:11:44 eggert Exp $")
-
-static void keyreplace P((enum markers,struct hshentry const*,FILE*));
+libId(editId, "$Id: rcsedit.c,v 1.5 1995/10/29 19:31:10 peter Exp $")
+static void editEndsPrematurely P((void)) exiting;
+static void editLineNumberOverflow P((void)) exiting;
+static void escape_string P((FILE*,char const*));
+static void keyreplace P((enum markers,struct hshentry const*,int,RILE*,FILE*,int));
FILE *fcopy; /* result file descriptor */
-char const *resultfile; /* result file name */
+char const *resultname; /* result pathname */
int locker_expansion; /* should the locker name be appended to Id val? */
#if !large_memory
static RILE *fedit; /* edit file descriptor */
- static char const *editfile; /* edit pathname */
+ static char const *editname; /* edit pathname */
#endif
-static unsigned long editline; /* edit line counter; #lines before cursor */
+static long editline; /* edit line counter; #lines before cursor */
static long linecorr; /* #adds - #deletes in each edit run. */
/*used to correct editline in case file is not rewound after */
/* applying one delta */
-#define DIRTEMPNAMES 2
+/* indexes into dirtpname */
+#define lockdirtp_index 0
+#define newRCSdirtp_index bad_creat0
+#define newworkdirtp_index (newRCSdirtp_index+1)
+#define DIRTEMPNAMES (newworkdirtp_index + 1)
+
enum maker {notmade, real, effective};
-struct buf dirtfname[DIRTEMPNAMES]; /* unlink these when done */
-static enum maker volatile dirtfmaker[DIRTEMPNAMES]; /* if these are set */
+static struct buf dirtpname[DIRTEMPNAMES]; /* unlink these when done */
+static enum maker volatile dirtpmaker[DIRTEMPNAMES]; /* if these are set */
+#define lockname (dirtpname[lockdirtp_index].string)
+#define newRCSname (dirtpname[newRCSdirtp_index].string)
#if has_NFS || bad_unlink
@@ -187,17 +243,19 @@ un_link(s)
*/
{
# if bad_unlink
- int e;
if (unlink(s) == 0)
return 0;
- e = errno;
-# if has_NFS
- if (e == ENOENT)
- return 0;
-# endif
- if (chmod(s, S_IWUSR) != 0) {
- errno = e;
- return -1;
+ else {
+ int e = errno;
+ /*
+ * Forge ahead even if errno == ENOENT; some completely
+ * brain-damaged hosts (e.g. PCTCP 2.2) yield ENOENT
+ * even for existing unwritable files.
+ */
+ if (chmod(s, S_IWUSR) != 0) {
+ errno = e;
+ return -1;
+ }
}
# endif
# if has_NFS
@@ -212,38 +270,37 @@ un_link(s)
# if !has_NFS
# define do_link(s,t) link(s,t)
# else
+ static int do_link P((char const*,char const*));
static int
do_link(s, t)
char const *s, *t;
/* Link S to T, ignoring bogus EEXIST problems due to NFS failures. */
{
- struct stat sb, tb;
-
- if (link(s,t) == 0)
- return 0;
- if (errno != EEXIST)
- return -1;
- if (
- stat(s, &sb) == 0 &&
- stat(t, &tb) == 0 &&
- sb.st_ino == tb.st_ino &&
- sb.st_dev == tb.st_dev
- )
- return 0;
- errno = EEXIST;
- return -1;
+ int r = link(s, t);
+
+ if (r != 0 && errno == EEXIST) {
+ struct stat sb, tb;
+ if (
+ stat(s, &sb) == 0 &&
+ stat(t, &tb) == 0 &&
+ same_file(sb, tb, 0)
+ )
+ r = 0;
+ errno = EEXIST;
+ }
+ return r;
}
# endif
#endif
- static exiting void
+ static void
editEndsPrematurely()
{
fatserror("edit script ends prematurely");
}
- static exiting void
+ static void
editLineNumberOverflow()
{
fatserror("edit script refers to line past end of file");
@@ -255,11 +312,12 @@ editLineNumberOverflow()
#if has_memmove
# define movelines(s1, s2, n) VOID memmove(s1, s2, (n)*sizeof(Iptr_type))
#else
+ static void movelines P((Iptr_type*,Iptr_type const*,long));
static void
movelines(s1, s2, n)
register Iptr_type *s1;
register Iptr_type const *s2;
- register unsigned long n;
+ register long n;
{
if (s1 < s2)
do {
@@ -275,22 +333,26 @@ movelines(s1, s2, n)
}
#endif
+static void deletelines P((long,long));
+static void finisheditline P((RILE*,FILE*,Iptr_type,struct hshentry const*));
+static void insertline P((long,Iptr_type));
+static void snapshotline P((FILE*,Iptr_type));
+
/*
* `line' contains pointers to the lines in the currently `edited' file.
* It is a 0-origin array that represents linelim-gapsize lines.
- * line[0..gap-1] and line[gap+gapsize..linelim-1] contain pointers to lines.
- * line[gap..gap+gapsize-1] contains garbage.
+ * line[0 .. gap-1] and line[gap+gapsize .. linelim-1] hold pointers to lines.
+ * line[gap .. gap+gapsize-1] contains garbage.
*
* Any @s in lines are duplicated.
* Lines are terminated by \n, or (for a last partial line only) by single @.
*/
static Iptr_type *line;
-static unsigned long gap, gapsize, linelim;
-
+static size_t gap, gapsize, linelim;
static void
insertline(n, l)
- unsigned long n;
+ long n;
Iptr_type l;
/* Before line N, insert line L. N is 0-origin. */
{
@@ -316,10 +378,10 @@ insertline(n, l)
static void
deletelines(n, nlines)
- unsigned long n, nlines;
+ long n, nlines;
/* Delete lines N through N+NLINES-1. N is 0-origin. */
{
- unsigned long l = n + nlines;
+ long l = n + nlines;
if (linelim-gapsize < l || l < n)
editLineNumberOverflow();
if (l < gap)
@@ -340,7 +402,7 @@ snapshotline(f, l)
do {
if ((c = *l++) == SDELIM && *l++ != SDELIM)
return;
- aputc(c, f);
+ aputc_(c, f)
} while (c != '\n');
}
@@ -363,8 +425,8 @@ finisheditline(fin, fout, l, delta)
Iptr_type l;
struct hshentry const *delta;
{
- Iseek(fin, l);
- if (expandline(fin, fout, delta, true, (FILE*)0) < 0)
+ fin->ptr = l;
+ if (expandline(fin, fout, delta, true, (FILE*)0, true) < 0)
faterror("finisheditline internal error");
}
@@ -386,28 +448,27 @@ finishedit(delta, outfile, done)
else {
register Iptr_type *p, *lim, *l = line;
register RILE *fin = finptr;
- Iptr_type here = Itell(fin);
+ Iptr_type here = fin->ptr;
for (p=l, lim=l+gap; p<lim; )
finisheditline(fin, outfile, *p++, delta);
for (p+=gapsize, lim=l+linelim; p<lim; )
finisheditline(fin, outfile, *p++, delta);
- Iseek(fin, here);
+ fin->ptr = here;
}
}
}
-/* Open a temporary FILENAME for output, truncating any previous contents. */
-# define fopen_update_truncate(filename) fopen(filename, FOPEN_W_WORK)
+/* Open a temporary NAME for output, truncating any previous contents. */
+# define fopen_update_truncate(name) fopenSafer(name, FOPEN_W_WORK)
#else /* !large_memory */
+ static FILE * fopen_update_truncate P((char const*));
static FILE *
-fopen_update_truncate(filename)
- char const *filename;
+fopen_update_truncate(name)
+ char const *name;
{
-# if bad_fopen_wplus
- if (un_link(filename) != 0)
- efaterror(filename);
-# endif
- return fopen(filename, FOPEN_WPLUS_WORK);
+ if (bad_fopen_wplus && un_link(name) != 0)
+ efaterror(name);
+ return fopenSafer(name, FOPEN_WPLUS_WORK);
}
#endif
@@ -417,31 +478,31 @@ openfcopy(f)
FILE *f;
{
if (!(fcopy = f)) {
- if (!resultfile)
- resultfile = maketemp(2);
- if (!(fcopy = fopen_update_truncate(resultfile)))
- efaterror(resultfile);
+ if (!resultname)
+ resultname = maketemp(2);
+ if (!(fcopy = fopen_update_truncate(resultname)))
+ efaterror(resultname);
}
}
#if !large_memory
+ static void swapeditfiles P((FILE*));
static void
swapeditfiles(outfile)
FILE *outfile;
-/* Function: swaps resultfile and editfile, assigns fedit=fcopy,
+/* Function: swaps resultname and editname, assigns fedit=fcopy,
* and rewinds fedit for reading. Set fcopy to outfile if nonnull;
- * otherwise, set fcopy to be resultfile opened for reading and writing.
+ * otherwise, set fcopy to be resultname opened for reading and writing.
*/
{
char const *tmpptr;
editline = 0; linecorr = 0;
- if (fseek(fcopy, 0L, SEEK_SET) != 0)
- Oerror();
+ Orewind(fcopy);
fedit = fcopy;
- tmpptr=editfile; editfile=resultfile; resultfile=tmpptr;
+ tmpptr=editname; editname=resultname; resultname=tmpptr;
openfcopy(outfile);
}
@@ -450,7 +511,7 @@ snapshotedit(f)
FILE *f;
/* Copy the current state of the edits to F. */
{
- finishedit((struct hshentry *)nil, (FILE*)0, false);
+ finishedit((struct hshentry *)0, (FILE*)0, false);
fastcopy(fedit, f);
Irewind(fedit);
}
@@ -461,7 +522,7 @@ finishedit(delta, outfile, done)
FILE *outfile;
int done;
/* copy the rest of the edit file and close it (if it exists).
- * if delta!=nil, perform keyword substitution at the same time.
+ * if delta, perform keyword substitution at the same time.
* If DONE is set, we are finishing the last pass.
*/
{
@@ -471,8 +532,8 @@ finishedit(delta, outfile, done)
fe = fedit;
if (fe) {
fc = fcopy;
- if (delta!=nil) {
- while (1 < expandline(fe,fc,delta,false,(FILE*)0))
+ if (delta) {
+ while (1 < expandline(fe,fc,delta,false,(FILE*)0,true))
;
} else {
fastcopy(fe,fc);
@@ -489,13 +550,14 @@ finishedit(delta, outfile, done)
#if large_memory
# define copylines(upto,delta) (editline = (upto))
#else
+ static void copylines P((long,struct hshentry const*));
static void
-copylines(upto,delta)
- register unsigned long upto;
+copylines(upto, delta)
+ register long upto;
struct hshentry const *delta;
/*
* Copy input lines editline+1..upto from fedit to fcopy.
- * If delta != nil, keyword expansion is done simultaneously.
+ * If delta, keyword expansion is done simultaneously.
* editline is updated. Rewinds a file only if necessary.
*/
{
@@ -506,7 +568,7 @@ copylines(upto,delta)
if (upto < editline) {
/* swap files */
- finishedit((struct hshentry *)nil, (FILE*)0, false);
+ finishedit((struct hshentry *)0, (FILE*)0, false);
/* assumes edit only during last pass, from the beginning*/
}
fe = fedit;
@@ -514,15 +576,15 @@ copylines(upto,delta)
if (editline < upto)
if (delta)
do {
- if (expandline(fe,fc,delta,false,(FILE*)0) <= 1)
- editLineNumberOverflow();
+ if (expandline(fe,fc,delta,false,(FILE*)0,true) <= 1)
+ editLineNumberOverflow();
} while (++editline < upto);
else {
setupcache(fe); cache(fe);
do {
do {
- cachegeteof(c, editLineNumberOverflow(););
- aputc(c, fc);
+ cachegeteof_(c, editLineNumberOverflow();)
+ aputc_(c, fc)
} while (c != '\n');
} while (++editline < upto);
uncache(fe);
@@ -541,8 +603,8 @@ xpandstring(delta)
* If foutptr is nonnull, the string is also copied unchanged to foutptr.
*/
{
- while (1 < expandline(finptr,fcopy,delta,true,foutptr))
- ;
+ while (1 < expandline(finptr,fcopy,delta,true,foutptr,true))
+ continue;
}
@@ -566,7 +628,7 @@ copystring()
fcop = fcopy;
amidline = false;
for (;;) {
- GETC(frew,c);
+ GETC_(frew,c)
switch (c) {
case '\n':
++editline;
@@ -574,7 +636,7 @@ copystring()
amidline = false;
break;
case SDELIM:
- GETC(frew,c);
+ GETC_(frew,c)
if (c != SDELIM) {
/* end of string */
nextc = c;
@@ -587,7 +649,7 @@ copystring()
amidline = true;
break;
}
- aputc(c,fcop);
+ aputc_(c,fcop)
}
}
@@ -597,18 +659,18 @@ enterstring()
/* Like copystring, except the string is put into the edit data structure. */
{
#if !large_memory
- editfile = 0;
+ editname = 0;
fedit = 0;
editline = linecorr = 0;
- resultfile = maketemp(1);
- if (!(fcopy = fopen_update_truncate(resultfile)))
- efaterror(resultfile);
+ resultname = maketemp(1);
+ if (!(fcopy = fopen_update_truncate(resultname)))
+ efaterror(resultname);
copystring();
#else
register int c;
declarecache;
register FILE *frew;
- register unsigned long e, oe;
+ register long e, oe;
register int amidline, oamidline;
register Iptr_type optr;
register RILE *fin;
@@ -622,8 +684,8 @@ enterstring()
frew = foutptr;
amidline = false;
for (;;) {
- optr = cachetell();
- GETC(frew,c);
+ optr = cacheptr();
+ GETC_(frew,c)
oamidline = amidline;
oe = e;
switch (c) {
@@ -633,7 +695,7 @@ enterstring()
amidline = false;
break;
case SDELIM:
- GETC(frew,c);
+ GETC_(frew,c)
if (c != SDELIM) {
/* end of string */
nextc = c;
@@ -667,13 +729,13 @@ edit_string()
* Read an edit script from finptr and applies it to the edit file.
#if !large_memory
* The result is written to fcopy.
- * If delta!=nil, keyword expansion is performed simultaneously.
+ * If delta, keyword expansion is performed simultaneously.
* If running out of lines in fedit, fedit and fcopy are swapped.
- * editfile is the name of the file that goes with fedit.
+ * editname is the name of the file that goes with fedit.
#endif
* If foutptr is set, the edit script is also copied verbatim to foutptr.
* Assumes that all these files are open.
- * resultfile is the name of the file that goes with fcopy.
+ * resultname is the name of the file that goes with fcopy.
* Assumes the next input character from finptr is the first character of
* the edit script. Resets nextc on exit.
*/
@@ -684,13 +746,13 @@ edit_string()
register FILE *frew;
# if !large_memory
register FILE *f;
- unsigned long line_lim = ULONG_MAX;
+ long line_lim = LONG_MAX;
register RILE *fe;
# endif
- register unsigned long i;
+ register long i;
register RILE *fin;
# if large_memory
- register unsigned long j;
+ register long j;
# endif
struct diffcmd dc;
@@ -718,12 +780,13 @@ edit_string()
do {
/*skip next line*/
do {
- Igeteof(fe, c, { if (i!=1) editLineNumberOverflow(); line_lim = dc.dafter; break; } );
+ Igeteof_(fe, c, { if (i!=1) editLineNumberOverflow(); line_lim = dc.dafter; break; } )
} while (c != '\n');
} while (--i);
# endif
} else {
- copylines(dc.line1, delta); /*copy only; no delete*/
+ /* Copy lines without deleting any. */
+ copylines(dc.line1, delta);
i = dc.nlines;
# if large_memory
j = editline+linecorr;
@@ -733,7 +796,7 @@ edit_string()
f = fcopy;
if (delta)
do {
- switch (expandline(fin,f,delta,true,frew)) {
+ switch (expandline(fin,f,delta,true,frew,true)){
case 0: case 1:
if (i==1)
return;
@@ -748,17 +811,12 @@ edit_string()
cache(fin);
do {
# if large_memory
- insertline(j++, cachetell());
+ insertline(j++, cacheptr());
# endif
for (;;) {
- GETC(frew, c);
-# if !large_memory
- aputc(c, f);
-# endif
- if (c == '\n')
- break;
+ GETC_(frew, c)
if (c==SDELIM) {
- GETC(frew, c);
+ GETC_(frew, c)
if (c!=SDELIM) {
if (--i)
editEndsPrematurely();
@@ -767,6 +825,11 @@ edit_string()
return;
}
}
+# if !large_memory
+ aputc_(c, f)
+# endif
+ if (c == '\n')
+ break;
}
++rcsline;
} while (--i);
@@ -782,17 +845,18 @@ edit_string()
int
-expandline(infile, outfile, delta, delimstuffed, frewfile)
+expandline(infile, outfile, delta, delimstuffed, frewfile, dolog)
RILE *infile;
FILE *outfile, *frewfile;
struct hshentry const *delta;
- int delimstuffed;
+ int delimstuffed, dolog;
/*
* Read a line from INFILE and write it to OUTFILE.
+ * Do keyword expansion with data from DELTA.
* If DELIMSTUFFED is true, double SDELIM is replaced with single SDELIM.
- * Keyword expansion is performed with data from delta.
* If FREWFILE is set, copy the line unchanged to FREWFILE.
* DELIMSTUFFED must be true if FREWFILE is set.
+ * Append revision history to log only if DOLOG is set.
* Yields -1 if no data is copied, 0 if an incomplete line is copied,
* 2 if a complete line is copied; adds 1 to yield if expansion occurred.
*/
@@ -815,15 +879,15 @@ expandline(infile, outfile, delta, delimstuffed, frewfile)
r = -1;
for (;;) {
- if (ds) {
- GETC(frew, c);
- } else
- cachegeteof(c, goto uncache_exit;);
+ if (ds)
+ GETC_(frew, c)
+ else
+ cachegeteof_(c, goto uncache_exit;)
for (;;) {
switch (c) {
case SDELIM:
if (ds) {
- GETC(frew, c);
+ GETC_(frew, c)
if (c != SDELIM) {
/* end of string */
nextc=c;
@@ -832,13 +896,13 @@ expandline(infile, outfile, delta, delimstuffed, frewfile)
}
/* fall into */
default:
- aputc(c,out);
+ aputc_(c,out)
r = 0;
break;
case '\n':
rcsline += ds;
- aputc(c,out);
+ aputc_(c,out)
r = 2;
goto uncache_exit;
@@ -849,11 +913,11 @@ expandline(infile, outfile, delta, delimstuffed, frewfile)
tp = keyval.string;
*tp++ = KDELIM;
for (;;) {
- if (ds) {
- GETC(frew, c);
- } else
- cachegeteof(c, goto keystring_eof;);
- if (tp < keyval.string+keylength+1)
+ if (ds)
+ GETC_(frew, c)
+ else
+ cachegeteof_(c, goto keystring_eof;)
+ if (tp <= &keyval.string[keylength])
switch (ctab[c]) {
case LETTER: case Letter:
*tp++ = c;
@@ -876,17 +940,17 @@ expandline(infile, outfile, delta, delimstuffed, frewfile)
/* try to find closing KDELIM, and replace value */
tlim = keyval.string + keyval.size;
for (;;) {
- if (ds) {
- GETC(frew, c);
- } else
- cachegeteof(c, goto keystring_eof;);
+ if (ds)
+ GETC_(frew, c)
+ else
+ cachegeteof_(c, goto keystring_eof;)
if (c=='\n' || c==KDELIM)
break;
*tp++ =c;
if (tlim <= tp)
tp = bufenlarge(&keyval, &tlim);
if (c==SDELIM && ds) { /*skip next SDELIM */
- GETC(frew, c);
+ GETC_(frew, c)
if (c != SDELIM) {
/* end of string before closing KDELIM or newline */
nextc = c;
@@ -902,7 +966,9 @@ expandline(infile, outfile, delta, delimstuffed, frewfile)
}
}
/* now put out the new keyword value */
- keyreplace(matchresult,delta,out);
+ uncache(infile);
+ keyreplace(matchresult, delta, ds, infile, out, dolog);
+ cache(infile);
e = 1;
break;
}
@@ -919,113 +985,229 @@ expandline(infile, outfile, delta, delimstuffed, frewfile)
}
+ static void
+escape_string(out, s)
+ register FILE *out;
+ register char const *s;
+/* Output to OUT the string S, escaping chars that would break `ci -k'. */
+{
+ register char c;
+ for (;;)
+ switch ((c = *s++)) {
+ case 0: return;
+ case '\t': aputs("\\t", out); break;
+ case '\n': aputs("\\n", out); break;
+ case ' ': aputs("\\040", out); break;
+ case KDELIM: aputs("\\044", out); break;
+ case '\\': if (VERSION(5)<=RCSversion) {aputs("\\\\", out); break;}
+ /* fall into */
+ default: aputc_(c, out) break;
+ }
+}
+
char const ciklog[ciklogsize] = "checked in with -k by ";
static void
-keyreplace(marker,delta,out)
+keyreplace(marker, delta, delimstuffed, infile, out, dolog)
enum markers marker;
register struct hshentry const *delta;
+ int delimstuffed;
+ RILE *infile;
register FILE *out;
+ int dolog;
/* function: outputs the keyword value(s) corresponding to marker.
* Attributes are derived from delta.
*/
{
register char const *sp, *cp, *date;
- register char c;
+ register int c;
register size_t cs, cw, ls;
char const *sp1;
- char datebuf[datesize];
+ char datebuf[datesize + zonelenmax];
int RCSv;
+ int exp;
sp = Keyword[(int)marker];
-
- if (Expand == KEY_EXPAND) {
- aprintf(out, "%c%s%c", KDELIM, sp, KDELIM);
- return;
- }
-
- date= delta->date;
+ exp = Expand;
+ date = delta->date;
RCSv = RCSversion;
- if (Expand == KEYVAL_EXPAND || Expand == KEYVALLOCK_EXPAND)
- aprintf(out, "%c%s%c%c", KDELIM, sp, VDELIM,
+ if (exp != VAL_EXPAND)
+ aprintf(out, "%c%s", KDELIM, sp);
+ if (exp != KEY_EXPAND) {
+
+ if (exp != VAL_EXPAND)
+ aprintf(out, "%c%c", VDELIM,
marker==Log && RCSv<VERSION(5) ? '\t' : ' '
);
- switch (marker) {
- case Author:
+ switch (marker) {
+ case Author:
aputs(delta->author, out);
break;
- case Date:
+ case Date:
aputs(date2str(date,datebuf), out);
break;
- case Id:
- case Header:
- aprintf(out, "%s %s %s %s %s",
- marker==Id || RCSv<VERSION(4)
- ? basename(RCSfilename)
- : getfullRCSname(),
+ case FreeBSD:
+ case Id:
+ case Header:
+ escape_string(out,
+ marker==Id || marker==FreeBSD || RCSv<VERSION(4)
+ ? basefilename(RCSname)
+ : getfullRCSname()
+ );
+ aprintf(out, " %s %s %s %s",
delta->num,
date2str(date, datebuf),
delta->author,
RCSv==VERSION(3) && delta->lockedby ? "Locked"
: delta->state
);
- if (delta->lockedby!=nil)
+ if (delta->lockedby)
if (VERSION(5) <= RCSv) {
- if (locker_expansion || Expand==KEYVALLOCK_EXPAND)
+ if (locker_expansion || exp==KEYVALLOCK_EXPAND)
aprintf(out, " %s", delta->lockedby);
} else if (RCSv == VERSION(4))
aprintf(out, " Locker: %s", delta->lockedby);
break;
- case Locker:
+ case Locker:
if (delta->lockedby)
if (
locker_expansion
- || Expand == KEYVALLOCK_EXPAND
+ || exp == KEYVALLOCK_EXPAND
|| RCSv <= VERSION(4)
)
aputs(delta->lockedby, out);
break;
- case Log:
- case RCSfile:
- aputs(basename(RCSfilename), out);
+ case Log:
+ case RCSfile:
+ escape_string(out, basefilename(RCSname));
break;
- case Revision:
+ case Name:
+ if (delta->name)
+ aputs(delta->name, out);
+ break;
+ case Revision:
aputs(delta->num, out);
break;
- case Source:
- aputs(getfullRCSname(), out);
+ case Source:
+ escape_string(out, getfullRCSname());
break;
- case State:
+ case State:
aputs(delta->state, out);
break;
- default:
+ default:
break;
- }
- if (Expand == KEYVAL_EXPAND || Expand == KEYVALLOCK_EXPAND) {
+ }
+ if (exp != VAL_EXPAND)
afputc(' ', out);
- afputc(KDELIM, out);
}
- if (marker == Log) {
+ if (exp != VAL_EXPAND)
+ afputc(KDELIM, out);
+
+ if (marker == Log && dolog) {
+ struct buf leader;
+
sp = delta->log.string;
ls = delta->log.size;
if (sizeof(ciklog)-1<=ls && !memcmp(sp,ciklog,sizeof(ciklog)-1))
return;
+ bufautobegin(&leader);
+ if (RCSversion < VERSION(5)) {
+ cp = Comment.string;
+ cs = Comment.size;
+ } else {
+ int kdelim_found = 0;
+ Ioffset_type chars_read = Itell(infile);
+ declarecache;
+ setupcache(infile); cache(infile);
+
+ c = 0; /* Pacify `gcc -Wall'. */
+
+ /*
+ * Back up to the start of the current input line,
+ * setting CS to the number of characters before `$Log'.
+ */
+ cs = 0;
+ for (;;) {
+ if (!--chars_read)
+ goto done_backing_up;
+ cacheunget_(infile, c)
+ if (c == '\n')
+ break;
+ if (c == SDELIM && delimstuffed) {
+ if (!--chars_read)
+ break;
+ cacheunget_(infile, c)
+ if (c != SDELIM) {
+ cacheget_(c)
+ break;
+ }
+ }
+ cs += kdelim_found;
+ kdelim_found |= c==KDELIM;
+ }
+ cacheget_(c)
+ done_backing_up:;
+
+ /* Copy characters before `$Log' into LEADER. */
+ bufalloc(&leader, cs);
+ cp = leader.string;
+ for (cw = 0; cw < cs; cw++) {
+ leader.string[cw] = c;
+ if (c == SDELIM && delimstuffed)
+ cacheget_(c)
+ cacheget_(c)
+ }
+
+ /* Convert traditional C or Pascal leader to ` *'. */
+ for (cw = 0; cw < cs; cw++)
+ if (ctab[(unsigned char) cp[cw]] != SPACE)
+ break;
+ if (
+ cw+1 < cs
+ && cp[cw+1] == '*'
+ && (cp[cw] == '/' || cp[cw] == '(')
+ ) {
+ size_t i = cw+1;
+ for (;;)
+ if (++i == cs) {
+ warn(
+ "`%c* $Log' is obsolescent; use ` * $Log'.",
+ cp[cw]
+ );
+ leader.string[cw] = ' ';
+ break;
+ } else if (ctab[(unsigned char) cp[i]] != SPACE)
+ break;
+ }
+
+ /* Skip `$Log ... $' string. */
+ do {
+ cacheget_(c)
+ } while (c != KDELIM);
+ uncache(infile);
+ }
afputc('\n', out);
- cp = Comment.string;
- cw = cs = Comment.size;
awrite(cp, cs, out);
- /* oddity: 2 spaces between date and time, not 1 as usual */
- sp1 = strchr(date2str(date,datebuf), ' ');
- aprintf(out, "Revision %s %.*s %s %s",
- delta->num, (int)(sp1-datebuf), datebuf, sp1, delta->author
- );
+ sp1 = date2str(date, datebuf);
+ if (VERSION(5) <= RCSv) {
+ aprintf(out, "Revision %s %s %s",
+ delta->num, sp1, delta->author
+ );
+ } else {
+ /* oddity: 2 spaces between date and time, not 1 as usual */
+ sp1 = strchr(sp1, ' ');
+ aprintf(out, "Revision %s %.*s %s %s",
+ delta->num, (int)(sp1-datebuf), datebuf, sp1,
+ delta->author
+ );
+ }
/* Do not include state: it may change and is not updated. */
- /* Comment is the comment leader. */
+ cw = cs;
if (VERSION(5) <= RCSv)
for (; cw && (cp[cw-1]==' ' || cp[cw-1]=='\t'); --cw)
- ;
+ continue;
for (;;) {
afputc('\n', out);
awrite(cp, cw, out);
@@ -1044,10 +1226,12 @@ keyreplace(marker,delta,out)
} while (c != '\n');
}
}
+ bufautoend(&leader);
}
}
#if has_readlink
+ static int resolve_symlink P((struct buf*));
static int
resolve_symlink(L)
struct buf *L;
@@ -1063,7 +1247,7 @@ resolve_symlink(L)
size_t s;
ssize_t r;
struct buf bigbuf;
- unsigned linkcount = MAXSYMLINKS + 1;
+ int linkcount = MAXSYMLINKS;
b = a;
s = sizeof(a);
@@ -1073,21 +1257,29 @@ resolve_symlink(L)
bufalloc(&bigbuf, s<<1);
b = bigbuf.string;
s = bigbuf.size;
- } else if (!--linkcount) {
+ } else if (!linkcount--) {
+# ifndef ELOOP
+ /*
+ * Some pedantic Posix 1003.1-1990 hosts have readlink
+ * but not ELOOP. Approximate ELOOP with EMLINK.
+ */
+# define ELOOP EMLINK
+# endif
errno = ELOOP;
return -1;
} else {
/* Splice symbolic link into L. */
b[r] = '\0';
- L->string[ROOTPATH(b) ? (size_t)0 : dirlen(L->string)] = '\0';
+ L->string[
+ ROOTPATH(b) ? 0 : basefilename(L->string) - L->string
+ ] = '\0';
bufscat(L, b);
}
e = errno;
bufautoend(&bigbuf);
errno = e;
switch (e) {
- case ENXIO:
- case EINVAL: return 1;
+ case readlink_isreg_errno: return 1;
case ENOENT: return 0;
default: return -1;
}
@@ -1100,24 +1292,23 @@ rcswriteopen(RCSbuf, status, mustread)
struct stat *status;
int mustread;
/*
- * Create the lock file corresponding to RCSNAME.
- * Then try to open RCSNAME for reading and yield its FILE* descriptor.
+ * Create the lock file corresponding to RCSBUF.
+ * Then try to open RCSBUF for reading and yield its RILE* descriptor.
* Put its status into *STATUS too.
* MUSTREAD is true if the file must already exist, too.
* If all goes well, discard any previously acquired locks,
- * and set frewrite to the FILE* descriptor of the lock file,
- * which will eventually turn into the new RCS file.
+ * and set fdlock to the file descriptor of the RCS lockfile.
*/
{
register char *tp;
- register char const *sp, *RCSname, *x;
+ register char const *sp, *RCSpath, *x;
RILE *f;
size_t l;
- int e, exists, fdesc, previouslock, r;
+ int e, exists, fdesc, fdescSafer, r, waslocked;
struct buf *dirt;
struct stat statbuf;
- previouslock = frewrite != 0;
+ waslocked = 0 <= fdlock;
exists =
# if has_readlink
resolve_symlink(RCSbuf);
@@ -1125,7 +1316,7 @@ rcswriteopen(RCSbuf, status, mustread)
stat(RCSbuf->string, &statbuf) == 0 ? 1
: errno==ENOENT ? 0 : -1;
# endif
- if (exists < (mustread|previouslock))
+ if (exists < (mustread|waslocked))
/*
* There's an unusual problem with the RCS file;
* or the RCS file doesn't exist,
@@ -1133,26 +1324,26 @@ rcswriteopen(RCSbuf, status, mustread)
*/
return 0;
- RCSname = RCSbuf->string;
- sp = basename(RCSname);
- l = sp - RCSname;
- dirt = &dirtfname[previouslock];
- bufscpy(dirt, RCSname);
+ RCSpath = RCSbuf->string;
+ sp = basefilename(RCSpath);
+ l = sp - RCSpath;
+ dirt = &dirtpname[waslocked];
+ bufscpy(dirt, RCSpath);
tp = dirt->string + l;
- x = rcssuffix(RCSname);
+ x = rcssuffix(RCSpath);
# if has_readlink
if (!x) {
- error("symbolic link to non RCS filename `%s'", RCSname);
+ error("symbolic link to non RCS file `%s'", RCSpath);
errno = EINVAL;
return 0;
}
# endif
if (*sp == *x) {
- error("RCS filename `%s' incompatible with suffix `%s'", sp, x);
+ error("RCS pathname `%s' incompatible with suffix `%s'", sp, x);
errno = EINVAL;
return 0;
}
- /* Create a lock file whose name is a function of the RCS filename. */
+ /* Create a lock filename that is a function of the RCS filename. */
if (*x) {
/*
* The suffix is nonempty.
@@ -1172,38 +1363,41 @@ rcswriteopen(RCSbuf, status, mustread)
* with last char replaced by '_'.
*/
while ((*tp++ = *sp++))
- ;
+ continue;
tp -= 2;
if (*tp == '_') {
- error("RCS filename `%s' ends with `%c'", RCSname, *tp);
+ error("RCS pathname `%s' ends with `%c'", RCSpath, *tp);
errno = EINVAL;
return 0;
}
*tp = '_';
}
- sp = tp = dirt->string;
+ sp = dirt->string;
f = 0;
/*
* good news:
- * open(f, O_CREAT|O_EXCL|O_TRUNC|O_WRONLY, READONLY) is atomic
- * according to Posix 1003.1-1990.
+ * open(f, O_CREAT|O_EXCL|O_TRUNC|..., OPEN_CREAT_READONLY)
+ * is atomic according to Posix 1003.1-1990.
* bad news:
* NFS ignores O_EXCL and doesn't comply with Posix 1003.1-1990.
* good news:
- * (O_TRUNC,READONLY) normally guarantees atomicity even with NFS.
+ * (O_TRUNC,OPEN_CREAT_READONLY) normally guarantees atomicity
+ * even with NFS.
* bad news:
- * If you're root, (O_TRUNC,READONLY) doesn't guarantee atomicity.
+ * If you're root, (O_TRUNC,OPEN_CREAT_READONLY) doesn't
+ * guarantee atomicity.
* good news:
* Root-over-the-wire NFS access is rare for security reasons.
* This bug has never been reported in practice with RCS.
* So we don't worry about this bug.
*
* An even rarer NFS bug can occur when clients retry requests.
- * Suppose client A renames the lock file ",f," to "f,v"
- * at about the same time that client B creates ",f,",
+ * This can happen in the usual case of NFS over UDP.
+ * Suppose client A releases a lock by renaming ",f," to "f,v" at
+ * about the same time that client B obtains a lock by creating ",f,",
* and suppose A's first rename request is delayed, so A reissues it.
* The sequence of events might be:
* A sends rename(",f,", "f,v")
@@ -1216,20 +1410,20 @@ rcswriteopen(RCSbuf, status, mustread)
* This not only wrongly deletes B's lock, it removes the RCS file!
* Most NFS implementations have idempotency caches that usually prevent
* this scenario, but such caches are finite and can be overrun.
- * This problem afflicts programs that use the traditional
+ * This problem afflicts not only RCS, which uses open() and rename()
+ * to get and release locks; it also afflicts the traditional
* Unix method of using link() and unlink() to get and release locks,
- * as well as RCS's method of using open() and rename().
- * There is no easy workaround for either link-unlink or open-rename.
+ * and the less traditional method of using mkdir() and rmdir().
+ * There is no easy workaround.
* Any new method based on lockf() seemingly would be incompatible with
* the old methods; besides, lockf() is notoriously buggy under NFS.
* Since this problem afflicts scads of Unix programs, but is so rare
* that nobody seems to be worried about it, we won't worry either.
*/
-# define READONLY (S_IRUSR|S_IRGRP|S_IROTH)
# if !open_can_creat
-# define create(f) creat(f, READONLY)
+# define create(f) creat(f, OPEN_CREAT_READONLY)
# else
-# define create(f) open(f, O_BINARY|O_CREAT|O_EXCL|O_TRUNC|O_WRONLY, READONLY)
+# define create(f) open(f, OPEN_O_BINARY|OPEN_O_LOCK|OPEN_O_WRONLY|O_CREAT|O_EXCL|O_TRUNC, OPEN_CREAT_READONLY)
# endif
catchints();
@@ -1241,34 +1435,35 @@ rcswriteopen(RCSbuf, status, mustread)
*/
seteid();
fdesc = create(sp);
+ fdescSafer = fdSafer(fdesc); /* Do it now; setrid might use stderr. */
e = errno;
setrid();
- if (fdesc < 0) {
- if (e == EACCES && stat(tp,&statbuf) == 0)
+ if (0 <= fdesc)
+ dirtpmaker[0] = effective;
+
+ if (fdescSafer < 0) {
+ if (e == EACCES && stat(sp,&statbuf) == 0)
/* The RCS file is busy. */
e = EEXIST;
} else {
- dirtfmaker[0] = effective;
e = ENOENT;
if (exists) {
- f = Iopen(RCSname, FOPEN_R, status);
+ f = Iopen(RCSpath, FOPEN_RB, status);
e = errno;
- if (f && previouslock) {
+ if (f && waslocked) {
/* Discard the previous lock in favor of this one. */
- Ozclose(&frewrite);
+ ORCSclose();
seteid();
- if ((r = un_link(newRCSfilename)) != 0)
- e = errno;
+ r = un_link(lockname);
+ e = errno;
setrid();
if (r != 0)
- enfaterror(e, newRCSfilename);
- bufscpy(&dirtfname[0], tp);
+ enfaterror(e, lockname);
+ bufscpy(&dirtpname[lockdirtp_index], sp);
}
}
- if (!(frewrite = fdopen(fdesc, FOPEN_W))) {
- efaterror(newRCSfilename);
- }
+ fdlock = fdescSafer;
}
restoreints();
@@ -1286,33 +1481,31 @@ keepdirtemp(name)
{
register int i;
for (i=DIRTEMPNAMES; 0<=--i; )
- if (dirtfname[i].string == name) {
- dirtfmaker[i] = notmade;
+ if (dirtpname[i].string == name) {
+ dirtpmaker[i] = notmade;
return;
}
faterror("keepdirtemp");
}
char const *
-makedirtemp(name, n)
- register char const *name;
- int n;
+makedirtemp(isworkfile)
+ int isworkfile;
/*
- * Have maketemp() do all the work if name is null.
- * Otherwise, create a unique filename in name's dir using n and name
- * and store it into the dirtfname[n].
- * Because of storage in tfnames, dirtempunlink() can unlink the file later.
- * Return a pointer to the filename created.
+ * Create a unique pathname and store it into dirtpname.
+ * Because of storage in tpnames, dirtempunlink() can unlink the file later.
+ * Return a pointer to the pathname created.
+ * If ISWORKFILE is 1, put it into the working file's directory;
+ * if 0, put the unique file in RCSfile's directory.
*/
{
register char *tp, *np;
register size_t dl;
register struct buf *bn;
+ register char const *name = isworkfile ? workname : RCSname;
- if (!name)
- return maketemp(n);
- dl = dirlen(name);
- bn = &dirtfname[n];
+ dl = basefilename(name) - name;
+ bn = &dirtpname[newRCSdirtp_index + isworkfile];
bufalloc(bn,
# if has_mktemp
dl + 9
@@ -1324,19 +1517,19 @@ makedirtemp(name, n)
np = tp = bn->string;
tp += dl;
*tp++ = '_';
- *tp++ = '0'+n;
+ *tp++ = '0'+isworkfile;
catchints();
# if has_mktemp
VOID strcpy(tp, "XXXXXX");
if (!mktemp(np) || !*np)
- faterror("can't make temporary file name `%.*s%c_%cXXXXXX'",
- (int)dl, name, SLASH, '0'+n
+ faterror("can't make temporary pathname `%.*s_%cXXXXXX'",
+ (int)dl, name, '0'+isworkfile
);
# else
/*
* Posix 1003.1-1990 has no reliable way
* to create a unique file in a named directory.
- * We fudge here. If the working file name is abcde,
+ * We fudge here. If the filename is abcde,
* the temp filename is _Ncde where N is a digit.
*/
name += dl;
@@ -1344,7 +1537,7 @@ makedirtemp(name, n)
if (*name) name++;
VOID strcpy(tp, name);
# endif
- dirtfmaker[n] = real;
+ dirtpmaker[newRCSdirtp_index + isworkfile] = real;
return np;
}
@@ -1356,84 +1549,127 @@ dirtempunlink()
enum maker m;
for (i = DIRTEMPNAMES; 0 <= --i; )
- if ((m = dirtfmaker[i]) != notmade) {
+ if ((m = dirtpmaker[i]) != notmade) {
if (m == effective)
seteid();
- VOID un_link(dirtfname[i].string);
+ VOID un_link(dirtpname[i].string);
if (m == effective)
setrid();
- dirtfmaker[i] = notmade;
+ dirtpmaker[i] = notmade;
}
}
int
#if has_prototypes
-chnamemod(FILE **fromp, char const *from, char const *to, mode_t mode)
+chnamemod(
+ FILE **fromp, char const *from, char const *to,
+ int set_mode, mode_t mode, time_t mtime
+)
/* The `#if has_prototypes' is needed because mode_t might promote to int. */
#else
- chnamemod(fromp,from,to,mode) FILE **fromp; char const *from,*to; mode_t mode;
+ chnamemod(fromp, from, to, set_mode, mode, mtime)
+ FILE **fromp; char const *from,*to;
+ int set_mode; mode_t mode; time_t mtime;
#endif
/*
- * Rename a file (with optional stream pointer *FROMP) from FROM to TO.
+ * Rename a file (with stream pointer *FROMP) from FROM to TO.
* FROM already exists.
- * Change its mode to MODE, before renaming if possible.
- * If FROMP, close and clear *FROMP before renaming it.
+ * If 0 < SET_MODE, change the mode to MODE, before renaming if possible.
+ * If MTIME is not -1, change its mtime to MTIME before renaming.
+ * Close and clear *FROMP before renaming it.
* Unlink TO if it already exists.
* Return -1 on error (setting errno), 0 otherwise.
*/
{
+ mode_t mode_while_renaming = mode;
+ int fchmod_set_mode = 0;
+
+# if bad_a_rename || bad_NFS_rename
+ struct stat st;
+ if (bad_NFS_rename || (bad_a_rename && set_mode <= 0)) {
+ if (fstat(fileno(*fromp), &st) != 0)
+ return -1;
+ if (bad_a_rename && set_mode <= 0)
+ mode = st.st_mode;
+ }
+# endif
+
# if bad_a_rename
/*
- * This host is brain damaged. A race condition is possible
- * while the lock file is temporarily writable.
- * There doesn't seem to be a workaround.
- */
- mode_t mode_while_renaming = mode|S_IWUSR;
-# else
-# define mode_while_renaming mode
+ * There's a short window of inconsistency
+ * during which the lock file is writable.
+ */
+ mode_while_renaming = mode|S_IWUSR;
+ if (mode != mode_while_renaming)
+ set_mode = 1;
# endif
- if (fromp) {
-# if has_fchmod
- if (fchmod(fileno(*fromp), mode_while_renaming) != 0)
- return -1;
-# endif
- Ozclose(fromp);
- }
+
# if has_fchmod
- else
+ if (0<set_mode && fchmod(fileno(*fromp),mode_while_renaming) == 0)
+ fchmod_set_mode = set_mode;
# endif
- if (chmod(from, mode_while_renaming) != 0)
+ /* If bad_chmod_close, we must close before chmod. */
+ Ozclose(fromp);
+ if (fchmod_set_mode<set_mode && chmod(from, mode_while_renaming) != 0)
+ return -1;
+
+ if (setmtime(from, mtime) != 0)
return -1;
# if !has_rename || bad_b_rename
- VOID un_link(to);
/*
- * We need not check the result;
- * link() or rename() will catch it.
- * No harm is done if TO does not exist.
- * However, there's a short window of inconsistency
- * during which TO does not exist.
- */
+ * There's a short window of inconsistency
+ * during which TO does not exist.
+ */
+ if (un_link(to) != 0 && errno != ENOENT)
+ return -1;
# endif
- return
-# if !has_rename
- do_link(from,to) != 0 ? -1 : un_link(from)
-# else
- rename(from, to) != 0
-# if has_NFS
- && errno != ENOENT
-# endif
- ? -1
-# if bad_a_rename
- : mode != mode_while_renaming ? chmod(to, mode)
-# endif
- : 0
-# endif
- ;
+# if has_rename
+ if (rename(from,to) != 0 && !(has_NFS && errno==ENOENT))
+ return -1;
+# else
+ if (do_link(from,to) != 0 || un_link(from) != 0)
+ return -1;
+# endif
-# undef mode_while_renaming
+# if bad_NFS_rename
+ {
+ /*
+ * Check whether the rename falsely reported success.
+ * A race condition can occur between the rename and the stat.
+ */
+ struct stat tostat;
+ if (stat(to, &tostat) != 0)
+ return -1;
+ if (! same_file(st, tostat, 0)) {
+ errno = EIO;
+ return -1;
+ }
+ }
+# endif
+
+# if bad_a_rename
+ if (0 < set_mode && chmod(to, mode) != 0)
+ return -1;
+# endif
+
+ return 0;
+}
+
+ int
+setmtime(file, mtime)
+ char const *file;
+ time_t mtime;
+/* Set FILE's last modified time to MTIME, but do nothing if MTIME is -1. */
+{
+ static struct utimbuf amtime; /* static so unused fields are zero */
+ if (mtime == -1)
+ return 0;
+ amtime.actime = now();
+ amtime.modtime = mtime;
+ return utime(file, &amtime);
}
@@ -1449,13 +1685,13 @@ findlock(delete, target)
* Return 0 for no locks, 1 for one, 2 for two or more.
*/
{
- register struct lock *next, **trail, **found;
+ register struct rcslock *next, **trail, **found;
found = 0;
for (trail = &Locks; (next = *trail); trail = &next->nextlock)
if (strcmp(getcaller(), next->login) == 0) {
if (found) {
- error("multiple revisions locked by %s; please specify one", getcaller());
+ rcserror("multiple revisions locked by %s; please specify one", getcaller());
return 2;
}
found = trail;
@@ -1465,36 +1701,37 @@ findlock(delete, target)
next = *found;
*target = next->delta;
if (delete) {
- next->delta->lockedby = nil;
+ next->delta->lockedby = 0;
*found = next->nextlock;
}
return 1;
}
int
-addlock(delta)
+addlock(delta, verbose)
struct hshentry * delta;
+ int verbose;
/*
* Add a lock held by caller to DELTA and yield 1 if successful.
- * Print an error message and yield -1 if no lock is added because
+ * Print an error message if verbose and yield -1 if no lock is added because
* DELTA is locked by somebody other than caller.
* Return 0 if the caller already holds the lock.
*/
{
- register struct lock *next;
+ register struct rcslock *next;
- next=Locks;
for (next = Locks; next; next = next->nextlock)
if (cmpnum(delta->num, next->delta->num) == 0)
if (strcmp(getcaller(), next->login) == 0)
return 0;
else {
- error("revision %s already locked by %s",
- delta->num, next->login
- );
+ if (verbose)
+ rcserror("Revision %s is already locked by %s.",
+ delta->num, next->login
+ );
return -1;
}
- next = ftalloc(struct lock);
+ next = ftalloc(struct rcslock);
delta->lockedby = next->login = getcaller();
next->delta = delta;
next->nextlock = Locks;
@@ -1511,28 +1748,30 @@ addsymbol(num, name, rebind)
* Associate with revision NUM the new symbolic NAME.
* If NAME already exists and REBIND is set, associate NAME with NUM;
* otherwise, print an error message and return false;
- * Return true if successful.
+ * Return -1 if unsuccessful, 0 if no change, 1 if change.
*/
{
register struct assoc *next;
for (next = Symbols; next; next = next->nextassoc)
if (strcmp(name, next->symbol) == 0)
- if (rebind || strcmp(next->num,num) == 0) {
+ if (strcmp(next->num,num) == 0)
+ return 0;
+ else if (rebind) {
next->num = num;
- return true;
+ return 1;
} else {
- error("symbolic name %s already bound to %s",
+ rcserror("symbolic name %s already bound to %s",
name, next->num
);
- return false;
+ return -1;
}
next = ftalloc(struct assoc);
next->symbol = name;
next->num = num;
next->nextassoc = Symbols;
Symbols = next;
- return true;
+ return 1;
}
@@ -1568,7 +1807,7 @@ checkaccesslist()
return true;
} while ((next = next->nextaccess));
- error("user %s not on the access list", getcaller());
+ rcserror("user %s not on the access list", getcaller());
return false;
}
@@ -1581,45 +1820,65 @@ dorewrite(lockflag, changed)
* Prepare to rewrite an RCS file if CHANGED is positive.
* Stop rewriting if CHANGED is zero, because there won't be any changes.
* Fail if CHANGED is negative.
- * Return true on success.
+ * Return 0 on success, -1 on failure.
*/
{
- int r, e;
+ int r = 0, e;
if (lockflag)
if (changed) {
if (changed < 0)
- return false;
- putadmin(frewrite);
+ return -1;
+ putadmin();
puttree(Head, frewrite);
aprintf(frewrite, "\n\n%s%c", Kdesc, nextc);
foutptr = frewrite;
} else {
- Ozclose(&frewrite);
+# if bad_creat0
+ int nr = !!frewrite, ne = 0;
+# endif
+ ORCSclose();
seteid();
ignoreints();
- r = un_link(newRCSfilename);
+# if bad_creat0
+ if (nr) {
+ nr = un_link(newRCSname);
+ ne = errno;
+ keepdirtemp(newRCSname);
+ }
+# endif
+ r = un_link(lockname);
e = errno;
- keepdirtemp(newRCSfilename);
+ keepdirtemp(lockname);
restoreints();
setrid();
- if (r != 0) {
- enerror(e, RCSfilename);
- return false;
- }
+ if (r != 0)
+ enerror(e, lockname);
+# if bad_creat0
+ if (nr != 0) {
+ enerror(ne, newRCSname);
+ r = -1;
+ }
+# endif
}
- return true;
+ return r;
}
int
-donerewrite(changed)
+donerewrite(changed, newRCStime)
int changed;
+ time_t newRCStime;
/*
* Finish rewriting an RCS file if CHANGED is nonzero.
- * Return true on success.
+ * Set its mode if CHANGED is positive.
+ * Set its modification time to NEWRCSTIME unless it is -1.
+ * Return 0 on success, -1 on failure.
*/
{
- int r, e;
+ int r = 0, e = 0;
+# if bad_creat0
+ int lr, le;
+# endif
if (changed && !nerror) {
if (finptr) {
@@ -1627,30 +1886,64 @@ donerewrite(changed)
Izclose(&finptr);
}
if (1 < RCSstat.st_nlink)
- warn("breaking hard link to %s", RCSfilename);
+ rcswarn("breaking hard link");
+ aflush(frewrite);
seteid();
ignoreints();
- r = chnamemod(&frewrite, newRCSfilename, RCSfilename,
- RCSstat.st_mode & ~(S_IWUSR|S_IWGRP|S_IWOTH)
+ r = chnamemod(
+ &frewrite, newRCSname, RCSname, changed,
+ RCSstat.st_mode & (mode_t)~(S_IWUSR|S_IWGRP|S_IWOTH),
+ newRCStime
);
e = errno;
- keepdirtemp(newRCSfilename);
+ keepdirtemp(newRCSname);
+# if bad_creat0
+ lr = un_link(lockname);
+ le = errno;
+ keepdirtemp(lockname);
+# endif
restoreints();
setrid();
if (r != 0) {
- enerror(e, RCSfilename);
- error("saved in %s", newRCSfilename);
- dirtempunlink();
- return false;
+ enerror(e, RCSname);
+ error("saved in %s", newRCSname);
}
+# if bad_creat0
+ if (lr != 0) {
+ enerror(le, lockname);
+ r = -1;
+ }
+# endif
}
- return true;
+ return r;
}
void
-aflush(f)
- FILE *f;
+ORCSclose()
+{
+ if (0 <= fdlock) {
+ if (close(fdlock) != 0)
+ efaterror(lockname);
+ fdlock = -1;
+ }
+ Ozclose(&frewrite);
+}
+
+ void
+ORCSerror()
+/*
+* Like ORCSclose, except we are cleaning up after an interrupt or fatal error.
+* Do not report errors, since this may loop. This is needed only because
+* some brain-damaged hosts (e.g. OS/2) cannot unlink files that are open, and
+* some nearly-Posix hosts (e.g. NFS) work better if the files are closed first.
+* This isn't a completely reliable away to work around brain-damaged hosts,
+* because of the gap between actual file opening and setting frewrite etc.,
+* but it's better than nothing.
+*/
{
- if (fflush(f) != 0)
- Oerror();
+ if (0 <= fdlock)
+ VOID close(fdlock);
+ if (frewrite)
+ /* Avoid fclose, since stdio may not be reentrant. */
+ VOID close(fileno(frewrite));
}
diff --git a/gnu/usr.bin/rcs/lib/rcsfcmp.c b/gnu/usr.bin/rcs/lib/rcsfcmp.c
index 75a6bbc..c9cef57 100644
--- a/gnu/usr.bin/rcs/lib/rcsfcmp.c
+++ b/gnu/usr.bin/rcs/lib/rcsfcmp.c
@@ -1,14 +1,13 @@
-/*
- * RCS file comparison
- */
+/* Compare working files, ignoring RCS keyword strings. */
+
/*****************************************************************************
* rcsfcmp()
* Testprogram: define FCMPTEST
*****************************************************************************
*/
-/* Copyright (C) 1982, 1988, 1989 Walter Tichy
- Copyright 1990, 1991 by Paul Eggert
+/* Copyright 1982, 1988, 1989 Walter Tichy
+ Copyright 1990, 1991, 1992, 1993, 1994, 1995 Paul Eggert
Distributed under license by the Free Software Foundation, Inc.
This file is part of RCS.
@@ -24,8 +23,9 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
-along with RCS; see the file COPYING. If not, write to
-the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+along with RCS; see the file COPYING.
+If not, write to the Free Software Foundation,
+59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
Report problems and direct all questions to:
@@ -37,7 +37,24 @@ Report problems and direct all questions to:
-/* $Log: rcsfcmp.c,v $
+/*
+ * Revision 5.14 1995/06/16 06:19:24 eggert
+ * Update FSF address.
+ *
+ * Revision 5.13 1995/06/01 16:23:43 eggert
+ * (rcsfcmp): Add -kb support.
+ *
+ * Revision 5.12 1994/03/17 14:05:48 eggert
+ * Normally calculate the $Log prefix from context, not from RCS file.
+ * Calculate line numbers correctly even if the $Log prefix contains newlines.
+ * Remove lint.
+ *
+ * Revision 5.11 1993/11/03 17:42:27 eggert
+ * Fix yet another off-by-one error when comparing Log string expansions.
+ *
+ * Revision 5.10 1992/07/28 16:12:44 eggert
+ * Statement macro names now end in _.
+ *
* Revision 5.9 1991/10/07 17:32:46 eggert
* Count log lines correctly.
*
@@ -69,24 +86,24 @@ Report problems and direct all questions to:
*
* Revision 4.5 89/05/01 15:12:42 narten
* changed copyright header to reflect current distribution rules
- *
+ *
* Revision 4.4 88/08/09 19:12:50 eggert
* Shrink stdio code size.
- *
+ *
* Revision 4.3 87/12/18 11:40:02 narten
* lint cleanups (Guy Harris)
- *
+ *
* Revision 4.2 87/10/18 10:33:06 narten
- * updting version number. Changes relative to 1.1 actually relative to
+ * updting version number. Changes relative to 1.1 actually relative to
* 4.1
- *
+ *
* Revision 1.2 87/03/27 14:22:19 jenkins
* Port to suns
- *
+ *
* Revision 4.1 83/05/10 16:24:04 wft
* Marker matching now uses trymatch(). Marker pattern is now
* checked precisely.
- *
+ *
* Revision 3.1 82/12/04 13:21:40 wft
* Initial revision.
*
@@ -101,8 +118,9 @@ Report problems and direct all questions to:
#include "rcsbase.h"
-libId(fcmpId, "$Id: rcsfcmp.c,v 5.9 1991/10/07 17:32:46 eggert Exp $")
+libId(fcmpId, "$Id: rcsfcmp.c,v 1.3 1995/10/28 21:49:38 peter Exp $")
+ static int discardkeyval P((int,RILE*));
static int
discardkeyval(c, f)
register int c;
@@ -114,24 +132,24 @@ discardkeyval(c, f)
case '\n':
return c;
default:
- Igeteof(f, c, return EOF;);
+ Igeteof_(f, c, return EOF;)
break;
}
}
int
-rcsfcmp(xfp, xstatp, ufname, delta)
+rcsfcmp(xfp, xstatp, uname, delta)
register RILE *xfp;
struct stat const *xstatp;
- char const *ufname;
+ char const *uname;
struct hshentry const *delta;
-/* Compare the files xfp and ufname. Return zero
- * if xfp has the same contents as ufname and neither has keywords,
+/* Compare the files xfp and uname. Return zero
+ * if xfp has the same contents as uname and neither has keywords,
* otherwise -1 if they are the same ignoring keyword values,
* and 1 if they differ even ignoring
* keyword values. For the LOG-keyword, rcsfcmp skips the log message
* given by the parameter delta in xfp. Thus, rcsfcmp returns nonpositive
- * if xfp contains the same as ufname, with the keywords expanded.
+ * if xfp contains the same as uname, with the keywords expanded.
* Implementation: character-by-character comparison until $ is found.
* If a $ is found, read in the marker keywords; if they are real keywords
* and identical, read in keyword value. If value is terminated properly,
@@ -145,23 +163,24 @@ rcsfcmp(xfp, xstatp, ufname, delta)
register int xeof, ueof;
register char * tp;
register char const *sp;
+ register size_t leaderlen;
int result;
enum markers match1;
struct stat ustat;
- if (!(ufp = Iopen(ufname, FOPEN_R_WORK, &ustat))) {
- efaterror(ufname);
+ if (!(ufp = Iopen(uname, FOPEN_R_WORK, &ustat))) {
+ efaterror(uname);
}
xeof = ueof = false;
- if (Expand==OLD_EXPAND) {
+ if (MIN_UNEXPAND <= Expand) {
if (!(result = xstatp->st_size!=ustat.st_size)) {
-# if has_mmap && large_memory
+# if large_memory && maps_memory
result = !!memcmp(xfp->base,ufp->base,(size_t)xstatp->st_size);
# else
for (;;) {
/* get the next characters */
- Igeteof(xfp, xc, xeof=true;);
- Igeteof(ufp, uc, ueof=true;);
+ Igeteof_(xfp, xc, xeof=true;)
+ Igeteof_(ufp, uc, ueof=true;)
if (xeof | ueof)
goto eof;
if (xc != uc)
@@ -172,21 +191,22 @@ rcsfcmp(xfp, xstatp, ufname, delta)
} else {
xc = 0;
uc = 0; /* Keep lint happy. */
+ leaderlen = 0;
result = 0;
for (;;) {
if (xc != KDELIM) {
/* get the next characters */
- Igeteof(xfp, xc, xeof=true;);
- Igeteof(ufp, uc, ueof=true;);
+ Igeteof_(xfp, xc, xeof=true;)
+ Igeteof_(ufp, uc, ueof=true;)
if (xeof | ueof)
goto eof;
} else {
/* try to get both keywords */
tp = xkeyword;
for (;;) {
- Igeteof(xfp, xc, xeof=true;);
- Igeteof(ufp, uc, ueof=true;);
+ Igeteof_(xfp, xc, xeof=true;)
+ Igeteof_(ufp, uc, ueof=true;)
if (xeof | ueof)
goto eof;
if (xc != uc)
@@ -221,8 +241,8 @@ rcsfcmp(xfp, xstatp, ufname, delta)
}
switch (xc) {
default:
- Igeteof(xfp, xc, xeof=true;);
- Igeteof(ufp, uc, ueof=true;);
+ Igeteof_(xfp, xc, xeof=true;)
+ Igeteof_(ufp, uc, ueof=true;)
if (xeof | ueof)
goto eof;
continue;
@@ -237,38 +257,47 @@ rcsfcmp(xfp, xstatp, ufname, delta)
goto return1;
if (xc==KDELIM) {
/* Skip closing KDELIM. */
- Igeteof(xfp, xc, xeof=true;);
- Igeteof(ufp, uc, ueof=true;);
+ Igeteof_(xfp, xc, xeof=true;)
+ Igeteof_(ufp, uc, ueof=true;)
if (xeof | ueof)
goto eof;
/* if the keyword is LOG, also skip the log message in xfp*/
if (match1==Log) {
/* first, compute the number of line feeds in log msg */
- unsigned lncnt;
+ int lncnt;
size_t ls, ccnt;
sp = delta->log.string;
ls = delta->log.size;
if (ls<sizeof(ciklog)-1 || memcmp(sp,ciklog,sizeof(ciklog)-1)) {
- /* This log message was inserted. */
- lncnt = 3;
- while (ls--) if (*sp++=='\n') lncnt++;
+ /*
+ * This log message was inserted. Skip its header.
+ * The number of newlines to skip is
+ * 1 + (C+1)*(1+L+1), where C is the number of newlines
+ * in the comment leader, and L is the number of
+ * newlines in the log string.
+ */
+ int c1 = 1;
+ for (ccnt=Comment.size; ccnt--; )
+ c1 += Comment.string[ccnt] == '\n';
+ lncnt = 2*c1 + 1;
+ while (ls--) if (*sp++=='\n') lncnt += c1;
for (;;) {
if (xc=='\n')
if(--lncnt==0) break;
- Igeteof(xfp, xc, goto returnresult;);
+ Igeteof_(xfp, xc, goto returnresult;)
}
/* skip last comment leader */
/* Can't just skip another line here, because there may be */
/* additional characters on the line (after the Log....$) */
- for (ccnt=Comment.size; ccnt--; ) {
- Igeteof(xfp, xc, goto returnresult;);
- if(xc=='\n') break;
+ ccnt = RCSversion<VERSION(5) ? Comment.size : leaderlen;
+ do {
+ Igeteof_(xfp, xc, goto returnresult;)
/*
* Read to the end of the comment leader or '\n',
- * whatever comes first. Some editors strip
- * trailing white space from a leader like " * ".
+ * whatever comes first, because the leader's
+ * trailing white space was probably stripped.
*/
- }
+ } while (ccnt-- && (xc!='\n' || --c1));
}
}
} else {
@@ -284,6 +313,10 @@ rcsfcmp(xfp, xstatp, ufname, delta)
}
if (xc != uc)
goto return1;
+ if (xc == '\n')
+ leaderlen = 0;
+ else
+ leaderlen++;
}
}
diff --git a/gnu/usr.bin/rcs/lib/rcsfnms.c b/gnu/usr.bin/rcs/lib/rcsfnms.c
index 02562f0..fe6a6aa 100644
--- a/gnu/usr.bin/rcs/lib/rcsfnms.c
+++ b/gnu/usr.bin/rcs/lib/rcsfnms.c
@@ -1,15 +1,14 @@
-/*
- * RCS file name handling
- */
+/* RCS filename and pathname handling */
+
/****************************************************************************
* creation and deletion of /tmp temporaries
- * pairing of RCS file names and working file names.
+ * pairing of RCS pathnames and working pathnames.
* Testprogram: define PAIRTEST
****************************************************************************
*/
-/* Copyright (C) 1982, 1988, 1989 Walter Tichy
- Copyright 1990, 1991 by Paul Eggert
+/* Copyright 1982, 1988, 1989 Walter Tichy
+ Copyright 1990, 1991, 1992, 1993, 1994, 1995 Paul Eggert
Distributed under license by the Free Software Foundation, Inc.
This file is part of RCS.
@@ -25,8 +24,9 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
-along with RCS; see the file COPYING. If not, write to
-the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+along with RCS; see the file COPYING.
+If not, write to the Free Software Foundation,
+59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
Report problems and direct all questions to:
@@ -37,7 +37,44 @@ Report problems and direct all questions to:
-/* $Log: rcsfnms.c,v $
+/*
+ * Revision 5.16 1995/06/16 06:19:24 eggert
+ * Update FSF address.
+ *
+ * Revision 5.15 1995/06/01 16:23:43 eggert
+ * (basefilename): Renamed from basename to avoid collisions.
+ * (dirlen): Remove (for similar reasons).
+ * (rcsreadopen): Open with FOPEN_RB.
+ * (SLASHSLASH_is_SLASH): Default is 0.
+ * (getcwd): Work around bad_wait_if_SIGCHLD_ignored bug.
+ *
+ * Revision 5.14 1994/03/17 14:05:48 eggert
+ * Strip trailing SLASHes from TMPDIR; some systems need this. Remove lint.
+ *
+ * Revision 5.13 1993/11/03 17:42:27 eggert
+ * Determine whether a file name is too long indirectly,
+ * by examining inode numbers, instead of trying to use operating system
+ * primitives like pathconf, which are not trustworthy in general.
+ * File names may now hold white space or $.
+ * Do not flatten ../X in pathnames; that may yield wrong answer for symlinks.
+ * Add getabsname hook. Improve quality of diagnostics.
+ *
+ * Revision 5.12 1992/07/28 16:12:44 eggert
+ * Add .sty. .pl now implies Perl, not Prolog. Fix fdlock initialization bug.
+ * Check that $PWD is really ".". Be consistent about pathnames vs filenames.
+ *
+ * Revision 5.11 1992/02/17 23:02:25 eggert
+ * `a/RCS/b/c' is now an RCS file with an empty extension, not just `a/b/RCS/c'.
+ *
+ * Revision 5.10 1992/01/24 18:44:19 eggert
+ * Fix bug: Expand and Ignored weren't reinitialized.
+ * Avoid `char const c=ch;' compiler bug.
+ * Add support for bad_creat0.
+ *
+ * Revision 5.9 1992/01/06 02:42:34 eggert
+ * Shorten long (>31 chars) name.
+ * while (E) ; -> while (E) continue;
+ *
* Revision 5.8 1991/09/24 00:28:40 eggert
* Don't export bindex().
*
@@ -66,8 +103,8 @@ Report problems and direct all questions to:
*
* Revision 5.0 1990/08/22 08:12:50 eggert
* Ignore signals when manipulating the semaphore file.
- * Modernize list of file name extensions.
- * Permit paths of arbitrary length. Beware file names beginning with "-".
+ * Modernize list of filename extensions.
+ * Permit paths of arbitrary length. Beware filenames beginning with "-".
* Remove compile-time limits; use malloc instead.
* Permit dates past 1999/12/31. Make lock and temp files faster and safer.
* Ansify and Posixate.
@@ -75,43 +112,43 @@ Report problems and direct all questions to:
*
* Revision 4.8 89/05/01 15:09:41 narten
* changed getwd to not stat empty directories.
- *
+ *
* Revision 4.7 88/08/09 19:12:53 eggert
* Fix troff macro comment leader bug; add Prolog; allow cc -R; remove lint.
- *
+ *
* Revision 4.6 87/12/18 11:40:23 narten
* additional file types added from 4.3 BSD version, and SPARC assembler
* comment character added. Also, more lint cleanups. (Guy Harris)
- *
+ *
* Revision 4.5 87/10/18 10:34:16 narten
* Updating version numbers. Changes relative to 1.1 actually relative
* to verion 4.3
- *
+ *
* Revision 1.3 87/03/27 14:22:21 jenkins
* Port to suns
- *
+ *
* Revision 1.2 85/06/26 07:34:28 svb
* Comment leader '% ' for '*.tex' files added.
- *
+ *
* Revision 4.3 83/12/15 12:26:48 wft
- * Added check for KDELIM in file names to pairfilenames().
- *
+ * Added check for KDELIM in filenames to pairfilenames().
+ *
* Revision 4.2 83/12/02 22:47:45 wft
- * Added csh, red, and sl file name suffixes.
- *
+ * Added csh, red, and sl filename suffixes.
+ *
* Revision 4.1 83/05/11 16:23:39 wft
* Added initialization of Dbranch to InitAdmin(). Canged pairfilenames():
* 1. added copying of path from workfile to RCS file, if RCS file is omitted;
* 2. added getting the file status of RCS and working files;
* 3. added ignoring of directories.
- *
+ *
* Revision 3.7 83/05/11 15:01:58 wft
- * Added comtable[] which pairs file name suffixes with comment leaders;
+ * Added comtable[] which pairs filename suffixes with comment leaders;
* updated InitAdmin() accordingly.
- *
+ *
* Revision 3.6 83/04/05 14:47:36 wft
* fixed Suffix in InitAdmin().
- *
+ *
* Revision 3.5 83/01/17 18:01:04 wft
* Added getwd() and rename(); these can be removed by defining
* V4_2BSD, since they are not needed in 4.2 bsd.
@@ -121,7 +158,7 @@ Report problems and direct all questions to:
* removed unused variable.
*
* Revision 3.3 82/11/28 20:31:37 wft
- * Changed mktempfile() to store the generated file names.
+ * Changed mktempfile() to store the generated filenames.
* Changed getfullRCSname() to store the file and pathname, and to
* delete leading "../" and "./".
*
@@ -140,72 +177,87 @@ Report problems and direct all questions to:
#include "rcsbase.h"
-libId(fnmsId, "$Id: rcsfnms.c,v 5.8 1991/09/24 00:28:40 eggert Exp $")
+libId(fnmsId, "$Id: rcsfnms.c,v 1.3 1995/10/28 21:49:39 peter Exp $")
-char const *RCSfilename;
-char *workfilename;
+static char const *bindex P((char const*,int));
+static int fin2open P((char const*, size_t, char const*, size_t, char const*, size_t, RILE*(*)P((struct buf*,struct stat*,int)), int));
+static int finopen P((RILE*(*)P((struct buf*,struct stat*,int)), int));
+static int suffix_matches P((char const*,char const*));
+static size_t dir_useful_len P((char const*));
+static size_t suffixlen P((char const*));
+static void InitAdmin P((void));
+
+char const *RCSname;
+char *workname;
+int fdlock;
FILE *workstdout;
struct stat RCSstat;
char const *suffixes;
static char const rcsdir[] = "RCS";
-#define rcsdirlen (sizeof(rcsdir)-1)
+#define rcslen (sizeof(rcsdir)-1)
static struct buf RCSbuf, RCSb;
static int RCSerrno;
-/* Temp file names to be unlinked when done, if they are not nil. */
+/* Temp names to be unlinked when done, if they are not 0. */
#define TEMPNAMES 5 /* must be at least DIRTEMPNAMES (see rcsedit.c) */
-static char *volatile tfnames[TEMPNAMES];
+static char *volatile tpnames[TEMPNAMES];
struct compair {
char const *suffix, *comlead;
};
+/*
+* This table is present only for backwards compatibility.
+* Normally we ignore this table, and use the prefix of the `$Log' line instead.
+*/
static struct compair const comtable[] = {
-/* comtable pairs each filename suffix with a comment leader. The comment */
-/* leader is placed before each line generated by the $Log keyword. This */
-/* table is used to guess the proper comment leader from the working file's */
-/* suffix during initial ci (see InitAdmin()). Comment leaders are needed */
-/* for languages without multiline comments; for others they are optional. */
- "a", "-- ", /* Ada */
- "ada", "-- ",
- "asm", ";; ", /* assembler (MS-DOS) */
- "bat", ":: ", /* batch (MS-DOS) */
- "c", " * ", /* C */
- "c++", "// ", /* C++ in all its infinite guises */
- "cc", "// ",
- "cpp", "// ",
- "cxx", "// ",
- "cl", ";;; ", /* Common Lisp */
- "cmd", ":: ", /* command (OS/2) */
- "cmf", "c ", /* CM Fortran */
- "cs", " * ", /* C* */
- "el", "; ", /* Emacs Lisp */
- "f", "c ", /* Fortran */
- "for", "c ",
- "h", " * ", /* C-header */
- "hpp", "// ", /* C++ header */
- "hxx", "// ",
- "l", " * ", /* lex NOTE: conflict between lex and franzlisp */
- "lisp",";;; ", /* Lucid Lisp */
- "lsp", ";; ", /* Microsoft Lisp */
- "mac", ";; ", /* macro (DEC-10, MS-DOS, PDP-11, VMS, etc) */
- "me", ".\\\" ",/* me-macros t/nroff*/
- "ml", "; ", /* mocklisp */
- "mm", ".\\\" ",/* mm-macros t/nroff*/
- "ms", ".\\\" ",/* ms-macros t/nroff*/
- "p", " * ", /* Pascal */
- "pas", " * ",
- "pl", "% ", /* Prolog */
- "tex", "% ", /* TeX */
- "y", " * ", /* yacc */
- nil, "# " /* default for unknown suffix; must always be last */
+ { "a" , "-- " }, /* Ada */
+ { "ada" , "-- " },
+ { "adb" , "-- " },
+ { "ads" , "-- " },
+ { "asm" , ";; " }, /* assembler (MS-DOS) */
+ { "bat" , ":: " }, /* batch (MS-DOS) */
+ { "body", "-- " }, /* Ada */
+ { "c" , " * " }, /* C */
+ { "c++" , "// " }, /* C++ in all its infinite guises */
+ { "cc" , "// " },
+ { "cpp" , "// " },
+ { "cxx" , "// " },
+ { "cl" , ";;; "}, /* Common Lisp */
+ { "cmd" , ":: " }, /* command (OS/2) */
+ { "cmf" , "c " }, /* CM Fortran */
+ { "cs" , " * " }, /* C* */
+ { "el" , "; " }, /* Emacs Lisp */
+ { "f" , "c " }, /* Fortran */
+ { "for" , "c " },
+ { "h" , " * " }, /* C-header */
+ { "hpp" , "// " }, /* C++ header */
+ { "hxx" , "// " },
+ { "l" , " * " }, /* lex (NOTE: franzlisp disagrees) */
+ { "lisp", ";;; "}, /* Lucid Lisp */
+ { "lsp" , ";; " }, /* Microsoft Lisp */
+ { "m" , "// " }, /* Objective C */
+ { "mac" , ";; " }, /* macro (DEC-10, MS-DOS, PDP-11, VMS, etc) */
+ { "me" , ".\\\" "}, /* troff -me */
+ { "ml" , "; " }, /* mocklisp */
+ { "mm" , ".\\\" "}, /* troff -mm */
+ { "ms" , ".\\\" "}, /* troff -ms */
+ { "p" , " * " }, /* Pascal */
+ { "pas" , " * " },
+ { "ps" , "% " }, /* PostScript */
+ { "spec", "-- " }, /* Ada */
+ { "sty" , "% " }, /* LaTeX style */
+ { "tex" , "% " }, /* TeX */
+ { "y" , " * " }, /* yacc */
+ { 0 , "# " } /* default for unknown suffix; must be last */
};
#if has_mktemp
+ static char const *tmp P((void));
static char const *
tmp()
/* Yield the name of the tmp directory. */
@@ -224,14 +276,14 @@ tmp()
char const *
maketemp(n)
int n;
-/* Create a unique filename using n and the process id and store it
- * into the nth slot in tfnames.
- * Because of storage in tfnames, tempunlink() can unlink the file later.
- * Returns a pointer to the filename created.
+/* Create a unique pathname using n and the process id and store it
+ * into the nth slot in tpnames.
+ * Because of storage in tpnames, tempunlink() can unlink the file later.
+ * Return a pointer to the pathname created.
*/
{
char *p;
- char const *t = tfnames[n];
+ char const *t = tpnames[n];
if (t)
return t;
@@ -240,25 +292,26 @@ maketemp(n)
{
# if has_mktemp
char const *tp = tmp();
- p = testalloc(strlen(tp) + 10);
- VOID sprintf(p, "%s%cT%cXXXXXX", tp, SLASH, '0'+n);
+ size_t tplen = dir_useful_len(tp);
+ p = testalloc(tplen + 10);
+ VOID sprintf(p, "%.*s%cT%cXXXXXX", (int)tplen, tp, SLASH, '0'+n);
if (!mktemp(p) || !*p)
- faterror("can't make temporary file name `%s%cT%cXXXXXX'",
- tp, SLASH, '0'+n
+ faterror("can't make temporary pathname `%.*s%cT%cXXXXXX'",
+ (int)tplen, tp, SLASH, '0'+n
);
# else
- static char tfnamebuf[TEMPNAMES][L_tmpnam];
- p = tfnamebuf[n];
+ static char tpnamebuf[TEMPNAMES][L_tmpnam];
+ p = tpnamebuf[n];
if (!tmpnam(p) || !*p)
# ifdef P_tmpdir
- faterror("can't make temporary file name `%s...'",P_tmpdir);
+ faterror("can't make temporary pathname `%s...'",P_tmpdir);
# else
- faterror("can't make temporary file name");
+ faterror("can't make temporary pathname");
# endif
# endif
}
- tfnames[n] = p;
+ tpnames[n] = p;
return p;
}
@@ -271,28 +324,28 @@ tempunlink()
register char *p;
for (i = TEMPNAMES; 0 <= --i; )
- if ((p = tfnames[i])) {
+ if ((p = tpnames[i])) {
VOID unlink(p);
/*
* We would tfree(p) here,
* but this might dump core if we're handing a signal.
* We're about to exit anyway, so we won't bother.
*/
- tfnames[i] = 0;
+ tpnames[i] = 0;
}
}
static char const *
-bindex(sp,ch)
+bindex(sp, c)
register char const *sp;
- int ch;
+ register int c;
/* Function: Finds the last occurrence of character c in string sp
* and returns a pointer to the character just beyond it. If the
* character doesn't occur in the string, sp is returned.
*/
{
- register char const c=ch, *r;
+ register char const *r;
r = sp;
while (*sp) {
if (*sp++ == c) r=sp;
@@ -333,64 +386,22 @@ InitAdmin()
register char const *Suffix;
register int i;
- Head=nil; Dbranch=nil; AccessList=nil; Symbols=nil; Locks=nil;
+ Head=0; Dbranch=0; AccessList=0; Symbols=0; Locks=0;
StrictLocks=STRICT_LOCKING;
/* guess the comment leader from the suffix*/
- Suffix=bindex(workfilename, '.');
- if (Suffix==workfilename) Suffix= ""; /* empty suffix; will get default*/
+ Suffix = bindex(workname, '.');
+ if (Suffix==workname) Suffix= ""; /* empty suffix; will get default*/
for (i=0; !suffix_matches(Suffix,comtable[i].suffix); i++)
- ;
+ continue;
Comment.string = comtable[i].comlead;
Comment.size = strlen(comtable[i].comlead);
+ Expand = KEYVAL_EXPAND;
+ clear_buf(&Ignored);
Lexinit(); /* note: if !finptr, reads nothing; only initializes */
}
-/* 'cpp' does not like this line. It seems to be the leading '_' in the */
-/* second occurence of '_POSIX_NO_TRUNC'. It evaluates correctly with */
-/* just the first term so lets just do that for now. */
-/*#if defined(_POSIX_NO_TRUNC) && _POSIX_NO_TRUNC!=-1*/
-#if defined(_POSIX_NO_TRUNC)
-# define LONG_NAMES_MAY_BE_SILENTLY_TRUNCATED 0
-#else
-# define LONG_NAMES_MAY_BE_SILENTLY_TRUNCATED 1
-#endif
-
-#if LONG_NAMES_MAY_BE_SILENTLY_TRUNCATED
-#ifdef NAME_MAX
-# define filenametoolong(path) (NAME_MAX < strlen(basename(path)))
-#else
- static int
-filenametoolong(path)
- char *path;
-/* Yield true if the last file name in PATH is too long. */
-{
- static unsigned long dot_namemax;
-
- register size_t namelen;
- register char *base;
- register unsigned long namemax;
-
- base = path + dirlen(path);
- namelen = strlen(base);
- if (namelen <= _POSIX_NAME_MAX) /* fast check for shorties */
- return false;
- if (base != path) {
- *--base = 0;
- namemax = pathconf(path, _PC_NAME_MAX);
- *base = SLASH;
- } else {
- /* Cache the results for the working directory, for speed. */
- if (!dot_namemax)
- dot_namemax = pathconf(".", _PC_NAME_MAX);
- namemax = dot_namemax;
- }
- /* If pathconf() yielded -1, namemax is now ULONG_MAX. */
- return namemax<namelen;
-}
-#endif
-#endif
void
bufalloc(b, size)
@@ -422,7 +433,7 @@ bufrealloc(b, size)
bufalloc(b, size);
else {
while ((b->size <<= 1) < size)
- ;
+ continue;
b->string = trealloc(char, b->string, b->size);
}
}
@@ -495,7 +506,7 @@ bufscpy(b, s)
char const *
-basename(p)
+basefilename(p)
char const *p;
/* Yield the address of the base filename of the pathname P. */
{
@@ -507,19 +518,11 @@ basename(p)
}
}
- size_t
-dirlen(p)
- char const *p;
-/* Yield the length of P's directory, including its trailing SLASH. */
-{
- return basename(p) - p;
-}
-
static size_t
suffixlen(x)
char const *x;
-/* Yield the length of X, an RCS filename suffix. */
+/* Yield the length of X, an RCS pathname suffix. */
{
register char const *p;
@@ -538,10 +541,10 @@ suffixlen(x)
char const *
rcssuffix(name)
char const *name;
-/* Yield the suffix of NAME if it is an RCS filename, 0 otherwise. */
+/* Yield the suffix of NAME if it is an RCS pathname, 0 otherwise. */
{
char const *x, *p, *nz;
- size_t dl, nl, xl;
+ size_t nl, xl;
nl = strlen(name);
nz = name + nl;
@@ -550,30 +553,29 @@ rcssuffix(name)
if ((xl = suffixlen(x))) {
if (xl <= nl && memcmp(p = nz-xl, x, xl) == 0)
return p;
- } else {
- dl = dirlen(name);
- if (
- rcsdirlen < dl &&
- !memcmp(p = name+(dl-=rcsdirlen+1), rcsdir, rcsdirlen) &&
- (!dl || isSLASH(*--p))
- )
- return nz;
- }
+ } else
+ for (p = name; p < nz - rcslen; p++)
+ if (
+ isSLASH(p[rcslen])
+ && (p==name || isSLASH(p[-1]))
+ && memcmp(p, rcsdir, rcslen) == 0
+ )
+ return nz;
x += xl;
} while (*x++);
return 0;
}
/*ARGSUSED*/ RILE *
-rcsreadopen(RCSname, status, mustread)
- struct buf *RCSname;
+rcsreadopen(RCSpath, status, mustread)
+ struct buf *RCSpath;
struct stat *status;
int mustread;
-/* Open RCSNAME for reading and yield its FILE* descriptor.
+/* Open RCSPATH for reading and yield its FILE* descriptor.
* If successful, set *STATUS to its status.
- * Pass this routine to pairfilenames() for read-only access to the file. */
+ * Pass this routine to pairnames() for read-only access to the file. */
{
- return Iopen(RCSname->string, FOPEN_R, status);
+ return Iopen(RCSpath->string, FOPEN_RB, status);
}
static int
@@ -594,7 +596,7 @@ finopen(rcsopen, mustread)
* We prefer an old name to that of a nonexisting new RCS file,
* unless we tried locking the old name and failed.
*/
- preferold = RCSbuf.string[0] && (mustread||frewrite);
+ preferold = RCSbuf.string[0] && (mustread||0<=fdlock);
finptr = (*rcsopen)(&RCSb, &RCSstat, mustread);
interesting = finptr || errno!=ENOENT;
@@ -615,7 +617,7 @@ fin2open(d, dlen, base, baselen, x, xlen, rcsopen, mustread)
/*
* D is a directory name with length DLEN (including trailing slash).
* BASE is a filename with length BASELEN.
- * X is an RCS filename suffix with length XLEN.
+ * X is an RCS pathname suffix with length XLEN.
* Use RCSOPEN to open an RCS file; MUSTREAD is set if the file must be read.
* Yield true if successful.
* Try dRCS/basex first; if that fails and x is nonempty, try dbasex.
@@ -626,12 +628,12 @@ fin2open(d, dlen, base, baselen, x, xlen, rcsopen, mustread)
{
register char *p;
- bufalloc(&RCSb, dlen + rcsdirlen + 1 + baselen + xlen + 1);
+ bufalloc(&RCSb, dlen + rcslen + 1 + baselen + xlen + 1);
/* Try dRCS/basex. */
VOID memcpy(p = RCSb.string, d, dlen);
- VOID memcpy(p += dlen, rcsdir, rcsdirlen);
- p += rcsdirlen;
+ VOID memcpy(p += dlen, rcsdir, rcslen);
+ p += rcslen;
*p++ = SLASH;
VOID memcpy(p, base, baselen);
VOID memcpy(p += baselen, x, xlen);
@@ -651,16 +653,17 @@ fin2open(d, dlen, base, baselen, x, xlen, rcsopen, mustread)
}
int
-pairfilenames(argc, argv, rcsopen, mustread, quiet)
+pairnames(argc, argv, rcsopen, mustread, quiet)
int argc;
char **argv;
RILE *(*rcsopen)P((struct buf*,struct stat*,int));
int mustread, quiet;
-/* Function: Pairs the filenames pointed to by argv; argc indicates
+/*
+ * Pair the pathnames pointed to by argv; argc indicates
* how many there are.
- * Places a pointer to the RCS filename into RCSfilename,
- * and a pointer to the name of the working file into workfilename.
- * If both the workfilename and the RCS filename are given, and workstdout
+ * Place a pointer to the RCS pathname into RCSname,
+ * and a pointer to the pathname of the working file into workname.
+ * If both are given, and workstdout
* is set, a warning is printed.
*
* If the RCS file exists, places its status into RCSstat.
@@ -677,80 +680,62 @@ pairfilenames(argc, argv, rcsopen, mustread, quiet)
static struct buf tempbuf;
register char *p, *arg, *RCS1;
- char const *purefname, *pureRCSname, *x;
+ char const *base, *RCSbase, *x;
int paired;
size_t arglen, dlen, baselen, xlen;
- if (!(arg = *argv)) return 0; /* already paired filename */
+ fdlock = -1;
+
+ if (!(arg = *argv)) return 0; /* already paired pathname */
if (*arg == '-') {
- error("%s option is ignored after file names", arg);
+ error("%s option is ignored after pathnames", arg);
return 0;
}
- purefname = basename(arg);
-
- /* Allocate buffer temporary to hold the default paired file name. */
- p = arg;
- for (;;) {
- switch (*p++) {
- /* Beware characters that cause havoc with ci -k. */
- case KDELIM:
- error("RCS file name `%s' contains %c", arg, KDELIM);
- return 0;
- case ' ': case '\n': case '\t':
- error("RCS file name `%s' contains white space", arg);
- return 0;
- default:
- continue;
- case 0:
- break;
- }
- break;
- }
-
+ base = basefilename(arg);
paired = false;
/* first check suffix to see whether it is an RCS file or not */
if ((x = rcssuffix(arg)))
{
- /* RCS file name given*/
+ /* RCS pathname given */
RCS1 = arg;
- pureRCSname = purefname;
- baselen = x - purefname;
+ RCSbase = base;
+ baselen = x - base;
if (
1 < argc &&
- !rcssuffix(workfilename = p = argv[1]) &&
+ !rcssuffix(workname = p = argv[1]) &&
baselen <= (arglen = strlen(p)) &&
- ((p+=arglen-baselen) == workfilename || isSLASH(p[-1])) &&
- memcmp(purefname, p, baselen) == 0
+ ((p+=arglen-baselen) == workname || isSLASH(p[-1])) &&
+ memcmp(base, p, baselen) == 0
) {
argv[1] = 0;
paired = true;
} else {
- bufscpy(&tempbuf, purefname);
- workfilename = p = tempbuf.string;
+ bufscpy(&tempbuf, base);
+ workname = p = tempbuf.string;
p[baselen] = 0;
}
} else {
/* working file given; now try to find RCS file */
- workfilename = arg;
- baselen = p - purefname - 1;
- /* derive RCS file name*/
+ workname = arg;
+ baselen = strlen(base);
+ /* Derive RCS pathname. */
if (
1 < argc &&
(x = rcssuffix(RCS1 = argv[1])) &&
baselen <= x - RCS1 &&
- ((pureRCSname=x-baselen)==RCS1 || isSLASH(pureRCSname[-1])) &&
- memcmp(purefname, pureRCSname, baselen) == 0
+ ((RCSbase=x-baselen)==RCS1 || isSLASH(RCSbase[-1])) &&
+ memcmp(base, RCSbase, baselen) == 0
) {
argv[1] = 0;
paired = true;
} else
- pureRCSname = RCS1 = 0;
+ RCSbase = RCS1 = 0;
}
- /* now we have a (tentative) RCS filename in RCS1 and workfilename */
+ /* Now we have a (tentative) RCS pathname in RCS1 and workname. */
/* Second, try to find the right RCS file */
- if (pureRCSname!=RCS1) {
+ if (RCSbase!=RCS1) {
/* a path for RCSfile is given; single RCS file to look for */
bufscpy(&RCSbuf, RCS1);
finptr = (*rcsopen)(&RCSbuf, &RCSstat, mustread);
@@ -758,16 +743,16 @@ pairfilenames(argc, argv, rcsopen, mustread, quiet)
} else {
bufscpy(&RCSbuf, "");
if (RCS1)
- /* RCS file name was given without path. */
- VOID fin2open(arg, (size_t)0, pureRCSname, baselen,
+ /* RCS filename was given without path. */
+ VOID fin2open(arg, (size_t)0, RCSbase, baselen,
x, strlen(x), rcsopen, mustread
);
else {
- /* No RCS file name was given. */
+ /* No RCS pathname was given. */
/* Try each suffix in turn. */
- dlen = purefname-arg;
+ dlen = base-arg;
x = suffixes;
- while (! fin2open(arg, dlen, purefname, baselen,
+ while (! fin2open(arg, dlen, base, baselen,
x, xlen=suffixlen(x), rcsopen, mustread
)) {
x += xlen;
@@ -776,7 +761,7 @@ pairfilenames(argc, argv, rcsopen, mustread, quiet)
}
}
}
- RCSfilename = p = RCSbuf.string;
+ RCSname = p = RCSbuf.string;
if (finptr) {
if (!S_ISREG(RCSstat.st_mode)) {
error("%s isn't a regular file -- ignored", p);
@@ -784,7 +769,7 @@ pairfilenames(argc, argv, rcsopen, mustread, quiet)
}
Lexinit(); getadmin();
} else {
- if (RCSerrno!=ENOENT || mustread || !frewrite) {
+ if (RCSerrno!=ENOENT || mustread || fdlock<0) {
if (RCSerrno == EEXIST)
error("RCS file %s is in use", p);
else if (!quiet || RCSerrno!=ENOENT)
@@ -793,25 +778,9 @@ pairfilenames(argc, argv, rcsopen, mustread, quiet)
}
InitAdmin();
};
-# if LONG_NAMES_MAY_BE_SILENTLY_TRUNCATED
- if (filenametoolong(p)) {
- error("RCS file name %s is too long", p);
- return 0;
- }
-# ifndef NAME_MAX
- /*
- * Check workfilename too, even though it cannot be longer,
- * because it may reside on a different filesystem.
- */
- if (filenametoolong(workfilename)) {
- error("working file name %s is too long", workfilename);
- return 0;
- }
-# endif
-# endif
if (paired && workstdout)
- warn("Option -p is set; ignoring output file %s",workfilename);
+ workwarn("Working file ignored due to -p option");
prevkeys = false;
return finptr ? 1 : -1;
@@ -820,83 +789,106 @@ pairfilenames(argc, argv, rcsopen, mustread, quiet)
char const *
getfullRCSname()
-/* Function: returns a pointer to the full path name of the RCS file.
- * Gets the working directory's name at most once.
- * Removes leading "../" and "./".
+/*
+ * Return a pointer to the full pathname of the RCS file.
+ * Remove leading `./'.
*/
{
- static char const *wdptr;
- static struct buf rcsbuf, wdbuf;
- static size_t pathlength;
-
- register char const *realname;
- register size_t parentdirlength;
- register unsigned dotdotcounter;
- register char *d;
- register char const *wd;
-
- if (ROOTPATH(RCSfilename)) {
- return(RCSfilename);
- } else {
+ if (ROOTPATH(RCSname)) {
+ return RCSname;
+ } else {
+ static struct buf rcsbuf;
+# if needs_getabsname
+ bufalloc(&rcsbuf, SIZEABLE_PATH + 1);
+ while (getabsname(RCSname, rcsbuf.string, rcsbuf.size) != 0)
+ if (errno == ERANGE)
+ bufalloc(&rcsbuf, rcsbuf.size<<1);
+ else
+ efaterror("getabsname");
+# else
+ static char const *wdptr;
+ static struct buf wdbuf;
+ static size_t wdlen;
+
+ register char const *r;
+ register size_t dlen;
+ register char *d;
+ register char const *wd;
+
if (!(wd = wdptr)) {
/* Get working directory for the first time. */
- if (!(d = cgetenv("PWD"))) {
+ char *PWD = cgetenv("PWD");
+ struct stat PWDstat, dotstat;
+ if (! (
+ (d = PWD) &&
+ ROOTPATH(PWD) &&
+ stat(PWD, &PWDstat) == 0 &&
+ stat(".", &dotstat) == 0 &&
+ same_file(PWDstat, dotstat, 1)
+ )) {
bufalloc(&wdbuf, SIZEABLE_PATH + 1);
-# if !has_getcwd && has_getwd
- d = getwd(wdbuf.string);
+# if has_getcwd || !has_getwd
+ while (!(d = getcwd(wdbuf.string, wdbuf.size)))
+ if (errno == ERANGE)
+ bufalloc(&wdbuf, wdbuf.size<<1);
+ else if ((d = PWD))
+ break;
+ else
+ efaterror("getcwd");
# else
- while (
- !(d = getcwd(wdbuf.string, wdbuf.size))
- && errno==ERANGE
- )
- bufalloc(&wdbuf, wdbuf.size<<1);
+ d = getwd(wdbuf.string);
+ if (!d && !(d = PWD))
+ efaterror("getwd");
# endif
- if (!d)
- efaterror("working directory");
}
- parentdirlength = strlen(d);
- while (parentdirlength && isSLASH(d[parentdirlength-1])) {
- d[--parentdirlength] = 0;
- /* Check needed because some getwd implementations */
- /* generate "/" for the root. */
- }
+ wdlen = dir_useful_len(d);
+ d[wdlen] = 0;
wdptr = wd = d;
- pathlength = parentdirlength;
- }
- /*the following must be redone since RCSfilename may change*/
- /* Find how many `../'s to remove from RCSfilename. */
- dotdotcounter =0;
- realname = RCSfilename;
- while (realname[0]=='.') {
- if (isSLASH(realname[1])) {
- /* drop leading ./ */
- realname += 2;
- } else if (realname[1]=='.' && isSLASH(realname[2])) {
- /* drop leading ../ and remember */
- dotdotcounter++;
- realname += 3;
- } else
- break;
}
- /* Now remove dotdotcounter trailing directories from wd. */
- parentdirlength = pathlength;
- while (dotdotcounter && parentdirlength) {
- /* move pointer backwards over trailing directory */
- if (isSLASH(wd[--parentdirlength])) {
- dotdotcounter--;
- }
- }
- /* build full path name */
- bufalloc(&rcsbuf, parentdirlength+strlen(realname)+2);
+ /*
+ * Remove leading `./'s from RCSname.
+ * Do not try to handle `../', since removing it may yield
+ * the wrong answer in the presence of symbolic links.
+ */
+ for (r = RCSname; r[0]=='.' && isSLASH(r[1]); r += 2)
+ /* `.////' is equivalent to `./'. */
+ while (isSLASH(r[2]))
+ r++;
+ /* Build full pathname. */
+ dlen = wdlen;
+ bufalloc(&rcsbuf, dlen + strlen(r) + 2);
d = rcsbuf.string;
- VOID memcpy(d, wd, parentdirlength);
- d += parentdirlength;
+ VOID memcpy(d, wd, dlen);
+ d += dlen;
*d++ = SLASH;
- VOID strcpy(d, realname);
- return rcsbuf.string;
+ VOID strcpy(d, r);
+# endif
+ return rcsbuf.string;
}
}
+ static size_t
+dir_useful_len(d)
+ char const *d;
+/*
+* D names a directory; yield the number of characters of D's useful part.
+* To create a file in D, append a SLASH and a file name to D's useful part.
+* Ignore trailing slashes if possible; not only are they ugly,
+* but some non-Posix systems misbehave unless the slashes are omitted.
+*/
+{
+# ifndef SLASHSLASH_is_SLASH
+# define SLASHSLASH_is_SLASH 0
+# endif
+ size_t dlen = strlen(d);
+ if (!SLASHSLASH_is_SLASH && dlen==2 && isSLASH(d[0]) && isSLASH(d[1]))
+ --dlen;
+ else
+ while (dlen && isSLASH(d[dlen-1]))
+ --dlen;
+ return dlen;
+}
+
#ifndef isSLASH
int
isSLASH(c)
@@ -927,9 +919,6 @@ getcwd(path, size)
register char *p, *lim;
int closeerrno, closeerror, e, fd[2], readerror, toolong, wstatus;
pid_t child;
-# if !has_waitpid
- pid_t w;
-# endif
if (!size) {
errno = EINVAL;
@@ -937,6 +926,12 @@ getcwd(path, size)
}
if (pipe(fd) != 0)
return 0;
+# if bad_wait_if_SIGCHLD_ignored
+# ifndef SIGCHLD
+# define SIGCHLD SIGCLD
+# endif
+ VOID signal(SIGCHLD, SIG_DFL);
+# endif
if (!(child = vfork())) {
if (
close(fd[0]) == 0 &&
@@ -988,12 +983,15 @@ getcwd(path, size)
if (waitpid(child, &wstatus, 0) < 0)
wstatus = 1;
# else
- do {
- if ((w = wait(&wstatus)) < 0) {
- wstatus = 1;
- break;
- }
- } while (w != child);
+ {
+ pid_t w;
+ do {
+ if ((w = wait(&wstatus)) < 0) {
+ wstatus = 1;
+ break;
+ }
+ } while (w != child);
+ }
# endif
}
if (!fp) {
@@ -1026,7 +1024,7 @@ getcwd(path, size)
#ifdef PAIRTEST
-/* test program for pairfilenames() and getfullRCSname() */
+/* test program for pairnames() and getfullRCSname() */
char const cmdid[] = "pair";
@@ -1052,20 +1050,20 @@ int argc; char *argv[];
}
do {
- RCSfilename=workfilename=nil;
- result = pairfilenames(argc,argv,rcsreadopen,!initflag,quietflag);
+ RCSname = workname = 0;
+ result = pairnames(argc,argv,rcsreadopen,!initflag,quietflag);
if (result!=0) {
- diagnose("RCS file: %s; working file: %s\nFull RCS file name: %s\n",
- RCSfilename,workfilename,getfullRCSname()
+ diagnose("RCS pathname: %s; working pathname: %s\nFull RCS pathname: %s\n",
+ RCSname, workname, getfullRCSname()
);
}
switch (result) {
case 0: continue; /* already paired file */
case 1: if (initflag) {
- error("RCS file %s exists already",RCSfilename);
+ rcserror("already exists");
} else {
- diagnose("RCS file %s exists\n",RCSfilename);
+ diagnose("RCS file %s exists\n", RCSname);
}
Ifclose(finptr);
break;
@@ -1078,7 +1076,7 @@ int argc; char *argv[];
}
- exiting void
+ void
exiterr()
{
dirtempunlink();
diff --git a/gnu/usr.bin/rcs/lib/rcsgen.c b/gnu/usr.bin/rcs/lib/rcsgen.c
index 9a6072e..0c8e5c0 100644
--- a/gnu/usr.bin/rcs/lib/rcsgen.c
+++ b/gnu/usr.bin/rcs/lib/rcsgen.c
@@ -1,9 +1,7 @@
-/*
- * RCS revision generation
- */
+/* Generate RCS revisions. */
-/* Copyright (C) 1982, 1988, 1989 Walter Tichy
- Copyright 1990, 1991 by Paul Eggert
+/* Copyright 1982, 1988, 1989 Walter Tichy
+ Copyright 1990, 1991, 1992, 1993, 1994, 1995 Paul Eggert
Distributed under license by the Free Software Foundation, Inc.
This file is part of RCS.
@@ -19,8 +17,9 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
-along with RCS; see the file COPYING. If not, write to
-the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+along with RCS; see the file COPYING.
+If not, write to the Free Software Foundation,
+59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
Report problems and direct all questions to:
@@ -28,9 +27,28 @@ Report problems and direct all questions to:
*/
-
-
-/* $Log: rcsgen.c,v $
+/*
+ * Revision 5.16 1995/06/16 06:19:24 eggert
+ * Update FSF address.
+ *
+ * Revision 5.15 1995/06/01 16:23:43 eggert
+ * (putadmin): Open RCS file with FOPEN_WB.
+ *
+ * Revision 5.14 1994/03/17 14:05:48 eggert
+ * Work around SVR4 stdio performance bug.
+ * Flush stderr after prompt. Remove lint.
+ *
+ * Revision 5.13 1993/11/03 17:42:27 eggert
+ * Don't discard ignored phrases. Improve quality of diagnostics.
+ *
+ * Revision 5.12 1992/07/28 16:12:44 eggert
+ * Statement macro names now end in _.
+ * Be consistent about pathnames vs filenames.
+ *
+ * Revision 5.11 1992/01/24 18:44:19 eggert
+ * Move put routines here from rcssyn.c.
+ * Add support for bad_creat0.
+ *
* Revision 5.10 1991/10/07 17:32:46 eggert
* Fix log bugs, e.g. ci -t/dev/null when has_mmap.
*
@@ -69,39 +87,39 @@ Report problems and direct all questions to:
*
* Revision 4.7 89/05/01 15:12:49 narten
* changed copyright header to reflect current distribution rules
- *
+ *
* Revision 4.6 88/08/28 14:59:10 eggert
* Shrink stdio code size; allow cc -R; remove lint; isatty() -> ttystdin()
- *
+ *
* Revision 4.5 87/12/18 11:43:25 narten
* additional lint cleanups, and a bug fix from the 4.3BSD version that
* keeps "ci" from sticking a '\377' into the description if you run it
* with a zero-length file as the description. (Guy Harris)
- *
+ *
* Revision 4.4 87/10/18 10:35:10 narten
* Updating version numbers. Changes relative to 1.1 actually relative to
* 4.2
- *
+ *
* Revision 1.3 87/09/24 13:59:51 narten
- * Sources now pass through lint (if you ignore printf/sprintf/fprintf
+ * Sources now pass through lint (if you ignore printf/sprintf/fprintf
* warnings)
- *
+ *
* Revision 1.2 87/03/27 14:22:27 jenkins
* Port to suns
- *
+ *
* Revision 4.2 83/12/02 23:01:39 wft
* merged 4.1 and 3.3.1.1 (clearerr(stdin)).
- *
+ *
* Revision 4.1 83/05/10 16:03:33 wft
* Changed putamin() to abort if trying to reread redirected stdin.
* Fixed getdesc() to output a prompt on initial newline.
- *
+ *
* Revision 3.3.1.1 83/10/19 04:21:51 lepreau
* Added clearerr(stdin) for re-reading description from stdin.
- *
+ *
* Revision 3.3 82/11/28 21:36:49 wft
* 4.2 prerelease
- *
+ *
* Revision 3.3 82/11/28 21:36:49 wft
* Replaced ferror() followed by fclose() with ffclose().
* Putdesc() now suppresses the prompts if stdin
@@ -122,12 +140,14 @@ Report problems and direct all questions to:
#include "rcsbase.h"
-libId(genId, "$Id: rcsgen.c,v 5.10 1991/10/07 17:32:46 eggert Exp $")
+libId(genId, "$Id: rcsgen.c,v 1.3 1995/10/28 21:49:41 peter Exp $")
int interactiveflag; /* Should we act as if stdin is a tty? */
struct buf curlogbuf; /* buffer for current log message */
enum stringwork { enter, copy, edit, expand, edit_expand };
+
+static void putdelta P((struct hshentry const*,FILE*));
static void scandeltatext P((struct hshentry*,enum stringwork,int));
@@ -145,11 +165,11 @@ buildrevision(deltas, target, outfile, expandflag)
* otherwise written into a temporary file.
* Temporary files are allocated by maketemp().
* if expandflag is set, keyword expansion is performed.
- * Return nil if outfile is set, the name of the temporary file otherwise.
+ * Return 0 if outfile is set, the name of the temporary file otherwise.
*
* Algorithm: Copy initial revision unchanged. Then edit all revisions but
- * the last one into it, alternating input and output files (resultfile and
- * editfile). The last revision is then edited in, performing simultaneous
+ * the last one into it, alternating input and output files (resultname and
+ * editname). The last revision is then edited in, performing simultaneous
* keyword substitution (this saves one extra pass).
* All this simplifies if only one revision needs to be generated,
* or no keyword expansion is necessary, or if output goes to stdout.
@@ -163,7 +183,7 @@ buildrevision(deltas, target, outfile, expandflag)
return 0;
else {
Ozclose(&fcopy);
- return(resultfile);
+ return resultname;
}
} else {
/* several revisions to generate */
@@ -175,17 +195,17 @@ buildrevision(deltas, target, outfile, expandflag)
}
if (expandflag || outfile) {
/* first, get to beginning of file*/
- finishedit((struct hshentry *)nil, outfile, false);
+ finishedit((struct hshentry*)0, outfile, false);
}
- scandeltatext(deltas->first, expandflag?edit_expand:edit, true);
+ scandeltatext(target, expandflag?edit_expand:edit, true);
finishedit(
- expandflag ? deltas->first : (struct hshentry*)nil,
+ expandflag ? target : (struct hshentry*)0,
outfile, true
);
if (outfile)
return 0;
Ozclose(&fcopy);
- return resultfile;
+ return resultname;
}
}
@@ -193,12 +213,13 @@ buildrevision(deltas, target, outfile, expandflag)
static void
scandeltatext(delta, func, needlog)
- struct hshentry * delta;
+ struct hshentry *delta;
enum stringwork func;
int needlog;
/* Function: Scans delta text nodes up to and including the one given
* by delta. For the one given by delta, the log message is saved into
* delta->log if needlog is set; func specifies how to handle the text.
+ * Similarly, if needlog, delta->igtext is set to the ignored phrases.
* Assumes the initial lexeme must be read in first.
* Does not advance nexttok after it is finished.
*/
@@ -217,11 +238,11 @@ scandeltatext(delta, func, needlog)
if (needlog && delta==nextdelta) {
cb = savestring(&curlogbuf);
delta->log = cleanlogmsg(curlogbuf.string, cb.size);
+ nextlex();
+ delta->igtext = getphrases(Ktext);
} else {readstring();
+ ignorephrases(Ktext);
}
- nextlex();
- while (nexttok==ID && strcmp(NextString,Ktext)!=0)
- ignorephrase();
getkeystring(Ktext);
if (delta==nextdelta)
@@ -233,7 +254,7 @@ scandeltatext(delta, func, needlog)
case enter: enterstring(); break;
case copy: copystring(); break;
case expand: xpandstring(delta); break;
- case edit: editstring((struct hshentry *)nil); break;
+ case edit: editstring((struct hshentry *)0); break;
case edit_expand: editstring(delta); break;
}
}
@@ -284,7 +305,7 @@ getcstdin()
if (feof(in) && ttystdin())
clearerr(in);
c = getc(in);
- if (c < 0) {
+ if (c == EOF) {
testIerror(in);
if (feof(in) && ttystdin())
afputc('\n',stderr);
@@ -327,9 +348,9 @@ putdesc(textflag, textfile)
char *textfile;
/* Function: puts the descriptive text into file frewrite.
* if finptr && !textflag, the text is copied from the old description.
- * Otherwise, if the textfile!=nil, the text is read from that
- * file, or from stdin, if textfile==nil.
- * A textfile with a leading '-' is treated as a string, not a file name.
+ * Otherwise, if textfile, the text is read from that
+ * file, or from stdin, if !textfile.
+ * A textfile with a leading '-' is treated as a string, not a pathname.
* If finptr, the old descriptive text is discarded.
* Always clears foutptr.
*/
@@ -369,13 +390,13 @@ putdesc(textflag, textfile)
p = textfile + 1;
s = strlen(p);
} else {
- if (!(txt = fopen(textfile, "r")))
+ if (!(txt = fopenSafer(textfile, "r")))
efaterror(textfile);
bufalloc(&desc, 1);
p = desc.string;
plim = p + desc.size;
for (;;) {
- if ((c=getc(txt)) < 0) {
+ if ((c=getc(txt)) == EOF) {
testIerror(txt);
if (feof(txt))
break;
@@ -392,7 +413,7 @@ putdesc(textflag, textfile)
desclean = cleanlogmsg(p, s);
}
putstring(frew, false, desclean, true);
- aputc('\n', frew);
+ aputc_('\n', frew)
}
}
@@ -406,16 +427,17 @@ getsstdin(option, name, note, buf)
register size_t i;
register int tty = ttystdin();
- if (tty)
+ if (tty) {
aprintf(stderr,
"enter %s, terminated with single '.' or end of file:\n%s>> ",
name, note
);
- else if (feof(stdin))
- faterror("can't reread redirected stdin for %s; use -%s<%s>",
+ eflush();
+ } else if (feof(stdin))
+ rcsfaterror("can't reread redirected stdin for %s; use -%s<%s>",
name, option, name
);
-
+
for (
i = 0, p = 0;
c = getcstdin(), !feof(stdin);
@@ -426,7 +448,234 @@ getsstdin(option, name, note, buf)
/* Remove trailing '.'. */
--i;
break;
- } else if (tty)
+ } else if (tty) {
aputs(">> ", stderr);
+ eflush();
+ }
return cleanlogmsg(p, i);
}
+
+
+ void
+putadmin()
+/* Output the admin node. */
+{
+ register FILE *fout;
+ struct assoc const *curassoc;
+ struct rcslock const *curlock;
+ struct access const *curaccess;
+
+ if (!(fout = frewrite)) {
+# if bad_creat0
+ ORCSclose();
+ fout = fopenSafer(makedirtemp(0), FOPEN_WB);
+# else
+ int fo = fdlock;
+ fdlock = -1;
+ fout = fdopen(fo, FOPEN_WB);
+# endif
+
+ if (!(frewrite = fout))
+ efaterror(RCSname);
+ }
+
+ /*
+ * Output the first character with putc, not printf.
+ * Otherwise, an SVR4 stdio bug buffers output inefficiently.
+ */
+ aputc_(*Khead, fout)
+ aprintf(fout, "%s\t%s;\n", Khead + 1, Head?Head->num:"");
+ if (Dbranch && VERSION(4)<=RCSversion)
+ aprintf(fout, "%s\t%s;\n", Kbranch, Dbranch);
+
+ aputs(Kaccess, fout);
+ curaccess = AccessList;
+ while (curaccess) {
+ aprintf(fout, "\n\t%s", curaccess->login);
+ curaccess = curaccess->nextaccess;
+ }
+ aprintf(fout, ";\n%s", Ksymbols);
+ curassoc = Symbols;
+ while (curassoc) {
+ aprintf(fout, "\n\t%s:%s", curassoc->symbol, curassoc->num);
+ curassoc = curassoc->nextassoc;
+ }
+ aprintf(fout, ";\n%s", Klocks);
+ curlock = Locks;
+ while (curlock) {
+ aprintf(fout, "\n\t%s:%s", curlock->login, curlock->delta->num);
+ curlock = curlock->nextlock;
+ }
+ if (StrictLocks) aprintf(fout, "; %s", Kstrict);
+ aprintf(fout, ";\n");
+ if (Comment.size) {
+ aprintf(fout, "%s\t", Kcomment);
+ putstring(fout, true, Comment, false);
+ aprintf(fout, ";\n");
+ }
+ if (Expand != KEYVAL_EXPAND)
+ aprintf(fout, "%s\t%c%s%c;\n",
+ Kexpand, SDELIM, expand_names[Expand], SDELIM
+ );
+ awrite(Ignored.string, Ignored.size, fout);
+ aputc_('\n', fout)
+}
+
+
+ static void
+putdelta(node, fout)
+ register struct hshentry const *node;
+ register FILE * fout;
+/* Output the delta NODE to FOUT. */
+{
+ struct branchhead const *nextbranch;
+
+ if (!node) return;
+
+ aprintf(fout, "\n%s\n%s\t%s;\t%s %s;\t%s %s;\nbranches",
+ node->num,
+ Kdate, node->date,
+ Kauthor, node->author,
+ Kstate, node->state?node->state:""
+ );
+ nextbranch = node->branches;
+ while (nextbranch) {
+ aprintf(fout, "\n\t%s", nextbranch->hsh->num);
+ nextbranch = nextbranch->nextbranch;
+ }
+
+ aprintf(fout, ";\n%s\t%s;\n", Knext, node->next?node->next->num:"");
+ awrite(node->ig.string, node->ig.size, fout);
+}
+
+
+ void
+puttree(root, fout)
+ struct hshentry const *root;
+ register FILE *fout;
+/* Output the delta tree with base ROOT in preorder to FOUT. */
+{
+ struct branchhead const *nextbranch;
+
+ if (!root) return;
+
+ if (root->selector)
+ putdelta(root, fout);
+
+ puttree(root->next, fout);
+
+ nextbranch = root->branches;
+ while (nextbranch) {
+ puttree(nextbranch->hsh, fout);
+ nextbranch = nextbranch->nextbranch;
+ }
+}
+
+
+ int
+putdtext(delta, srcname, fout, diffmt)
+ struct hshentry const *delta;
+ char const *srcname;
+ FILE *fout;
+ int diffmt;
+/*
+ * Output a deltatext node with delta number DELTA->num, log message DELTA->log,
+ * ignored phrases DELTA->igtext and text SRCNAME to FOUT.
+ * Double up all SDELIMs in both the log and the text.
+ * Make sure the log message ends in \n.
+ * Return false on error.
+ * If DIFFMT, also check that the text is valid diff -n output.
+ */
+{
+ RILE *fin;
+ if (!(fin = Iopen(srcname, "r", (struct stat*)0))) {
+ eerror(srcname);
+ return false;
+ }
+ putdftext(delta, fin, fout, diffmt);
+ Ifclose(fin);
+ return true;
+}
+
+ void
+putstring(out, delim, s, log)
+ register FILE *out;
+ struct cbuf s;
+ int delim, log;
+/*
+ * Output to OUT one SDELIM if DELIM, then the string S with SDELIMs doubled.
+ * If LOG is set then S is a log string; append a newline if S is nonempty.
+ */
+{
+ register char const *sp;
+ register size_t ss;
+
+ if (delim)
+ aputc_(SDELIM, out)
+ sp = s.string;
+ for (ss = s.size; ss; --ss) {
+ if (*sp == SDELIM)
+ aputc_(SDELIM, out)
+ aputc_(*sp++, out)
+ }
+ if (s.size && log)
+ aputc_('\n', out)
+ aputc_(SDELIM, out)
+}
+
+ void
+putdftext(delta, finfile, foutfile, diffmt)
+ struct hshentry const *delta;
+ RILE *finfile;
+ FILE *foutfile;
+ int diffmt;
+/* like putdtext(), except the source file is already open */
+{
+ declarecache;
+ register FILE *fout;
+ register int c;
+ register RILE *fin;
+ int ed;
+ struct diffcmd dc;
+
+ fout = foutfile;
+ aprintf(fout, DELNUMFORM, delta->num, Klog);
+
+ /* put log */
+ putstring(fout, true, delta->log, true);
+ aputc_('\n', fout)
+
+ /* put ignored phrases */
+ awrite(delta->igtext.string, delta->igtext.size, fout);
+
+ /* put text */
+ aprintf(fout, "%s\n%c", Ktext, SDELIM);
+
+ fin = finfile;
+ setupcache(fin);
+ if (!diffmt) {
+ /* Copy the file */
+ cache(fin);
+ for (;;) {
+ cachegeteof_(c, break;)
+ if (c==SDELIM) aputc_(SDELIM, fout) /*double up SDELIM*/
+ aputc_(c, fout)
+ }
+ } else {
+ initdiffcmd(&dc);
+ while (0 <= (ed = getdiffcmd(fin, false, fout, &dc)))
+ if (ed) {
+ cache(fin);
+ while (dc.nlines--)
+ do {
+ cachegeteof_(c, { if (!dc.nlines) goto OK_EOF; unexpected_EOF(); })
+ if (c == SDELIM)
+ aputc_(SDELIM, fout)
+ aputc_(c, fout)
+ } while (c != '\n');
+ uncache(fin);
+ }
+ }
+ OK_EOF:
+ aprintf(fout, "%c\n", SDELIM);
+}
diff --git a/gnu/usr.bin/rcs/lib/rcskeep.c b/gnu/usr.bin/rcs/lib/rcskeep.c
index 1a0c78f..f8a0d2a 100644
--- a/gnu/usr.bin/rcs/lib/rcskeep.c
+++ b/gnu/usr.bin/rcs/lib/rcskeep.c
@@ -1,14 +1,7 @@
-/*
- * RCS keyword extraction
- */
-/*****************************************************************************
- * main routine: getoldkeys()
- * Testprogram: define KEEPTEST
- *****************************************************************************
- */
+/* Extract RCS keyword string values from working files. */
-/* Copyright (C) 1982, 1988, 1989 Walter Tichy
- Copyright 1990, 1991 by Paul Eggert
+/* Copyright 1982, 1988, 1989 Walter Tichy
+ Copyright 1990, 1991, 1992, 1993, 1994, 1995 Paul Eggert
Distributed under license by the Free Software Foundation, Inc.
This file is part of RCS.
@@ -24,8 +17,9 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
-along with RCS; see the file COPYING. If not, write to
-the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+along with RCS; see the file COPYING.
+If not, write to the Free Software Foundation,
+59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
Report problems and direct all questions to:
@@ -33,9 +27,25 @@ Report problems and direct all questions to:
*/
-
-
-/* $Log: rcskeep.c,v $
+/*
+ * Revision 5.10 1995/06/16 06:19:24 eggert
+ * Update FSF address.
+ *
+ * Revision 5.9 1995/06/01 16:23:43 eggert
+ * (getoldkeys): Don't panic if a Name: is empty.
+ *
+ * Revision 5.8 1994/03/17 14:05:48 eggert
+ * Remove lint.
+ *
+ * Revision 5.7 1993/11/09 17:40:15 eggert
+ * Use simpler timezone parsing strategy now that we're using ISO 8601 format.
+ *
+ * Revision 5.6 1993/11/03 17:42:27 eggert
+ * Scan for Name keyword. Improve quality of diagnostics.
+ *
+ * Revision 5.5 1992/07/28 16:12:44 eggert
+ * Statement macro names now end in _.
+ *
* Revision 5.4 1991/08/19 03:13:55 eggert
* Tune.
*
@@ -56,28 +66,28 @@ Report problems and direct all questions to:
*
* Revision 4.6 89/05/01 15:12:56 narten
* changed copyright header to reflect current distribution rules
- *
+ *
* Revision 4.5 88/08/09 19:13:03 eggert
* Remove lint and speed up by making FILE *fp local, not global.
- *
+ *
* Revision 4.4 87/12/18 11:44:21 narten
* more lint cleanups (Guy Harris)
- *
+ *
* Revision 4.3 87/10/18 10:35:50 narten
* Updating version numbers. Changes relative to 1.1 actually relative
* to 4.1
- *
+ *
* Revision 1.3 87/09/24 14:00:00 narten
- * Sources now pass through lint (if you ignore printf/sprintf/fprintf
+ * Sources now pass through lint (if you ignore printf/sprintf/fprintf
* warnings)
- *
+ *
* Revision 1.2 87/03/27 14:22:29 jenkins
* Port to suns
- *
+ *
* Revision 4.1 83/05/10 16:26:44 wft
* Added new markers Id and RCSfile; extraction added.
* Marker matching with trymatch().
- *
+ *
* Revision 3.2 82/12/24 12:08:26 wft
* added missing #endif.
*
@@ -86,33 +96,29 @@ Report problems and direct all questions to:
*
*/
-/*
-#define KEEPTEST
-*/
-/* Testprogram; prints out the keyword values found. */
-
#include "rcsbase.h"
-libId(keepId, "$Id: rcskeep.c,v 5.4 1991/08/19 03:13:55 eggert Exp $")
+libId(keepId, "$Id: rcskeep.c,v 1.3 1995/10/28 21:49:43 peter Exp $")
-static int checknum P((char const*,int));
-static int getval P((RILE*,struct buf*,int));
+static int badly_terminated P((void));
+static int checknum P((char const*));
static int get0val P((int,RILE*,struct buf*,int));
+static int getval P((RILE*,struct buf*,int));
static int keepdate P((RILE*));
static int keepid P((int,RILE*,struct buf*));
static int keeprev P((RILE*));
int prevkeys;
-struct buf prevauthor, prevdate, prevrev, prevstate;
+struct buf prevauthor, prevdate, prevname, prevrev, prevstate;
int
getoldkeys(fp)
register RILE *fp;
/* Function: Tries to read keyword values for author, date,
* revision number, and state out of the file fp.
- * If FNAME is nonnull, it is opened and closed instead of using FP.
+ * If fp is null, workname is opened and closed instead of using fp.
* The results are placed into
- * prevauthor, prevdate, prevrev, prevstate.
+ * prevauthor, prevdate, prevname, prevrev, prevstate.
* Aborts immediately if it finds an error and returns false.
* If it returns true, it doesn't mean that any of the
* values were found; instead, check to see whether the corresponding arrays
@@ -123,14 +129,15 @@ getoldkeys(fp)
char keyword[keylength+1];
register char * tp;
int needs_closing;
+ int prevname_found;
if (prevkeys)
return true;
needs_closing = false;
if (!fp) {
- if (!(fp = Iopen(workfilename, FOPEN_R_WORK, (struct stat*)0))) {
- eerror(workfilename);
+ if (!(fp = Iopen(workname, FOPEN_R_WORK, (struct stat*)0))) {
+ eerror(workname);
return false;
}
needs_closing = true;
@@ -139,6 +146,7 @@ getoldkeys(fp)
/* initialize to empty */
bufscpy(&prevauthor, "");
bufscpy(&prevdate, "");
+ bufscpy(&prevname, ""); prevname_found = 0;
bufscpy(&prevrev, "");
bufscpy(&prevstate, "");
@@ -149,7 +157,7 @@ getoldkeys(fp)
/* try to get keyword */
tp = keyword;
for (;;) {
- Igeteof(fp, c, goto ok;);
+ Igeteof_(fp, c, goto ok;)
switch (c) {
default:
if (keyword+keylength <= tp)
@@ -165,7 +173,7 @@ getoldkeys(fp)
} while (c==KDELIM);
if (c!=VDELIM) continue;
*tp = c;
- Igeteof(fp, c, break;);
+ Igeteof_(fp, c, break;)
switch (c) {
case ' ': case '\t': break;
default: continue;
@@ -184,7 +192,7 @@ getoldkeys(fp)
case Header:
case Id:
if (!(
- getval(fp, (struct buf*)nil, false) &&
+ getval(fp, (struct buf*)0, false) &&
keeprev(fp) &&
(c = keepdate(fp)) &&
keepid(c, fp, &prevauthor) &&
@@ -192,8 +200,8 @@ getoldkeys(fp)
))
return false;
/* Skip either ``who'' (new form) or ``Locker: who'' (old). */
- if (getval(fp, (struct buf*)nil, true) &&
- getval(fp, (struct buf*)nil, true))
+ if (getval(fp, (struct buf*)0, true) &&
+ getval(fp, (struct buf*)0, true))
c = 0;
else if (nerror)
return false;
@@ -201,13 +209,24 @@ getoldkeys(fp)
c = KDELIM;
break;
case Locker:
+ (void) getval(fp, (struct buf*)0, false);
+ c = 0;
+ break;
case Log:
case RCSfile:
case Source:
- if (!getval(fp, (struct buf*)nil, false))
+ if (!getval(fp, (struct buf*)0, false))
return false;
c = 0;
break;
+ case Name:
+ if (getval(fp, &prevname, false)) {
+ if (*prevname.string)
+ checkssym(prevname.string);
+ prevname_found = 1;
+ }
+ c = 0;
+ break;
case Revision:
if (!keeprev(fp))
return false;
@@ -222,16 +241,18 @@ getoldkeys(fp)
continue;
}
if (!c)
- Igeteof(fp, c, c=0;);
+ Igeteof_(fp, c, c=0;)
if (c != KDELIM) {
- error("closing %c missing on keyword", KDELIM);
+ workerror("closing %c missing on keyword", KDELIM);
return false;
}
- if (*prevauthor.string && *prevdate.string && *prevrev.string && *prevstate.string) {
+ if (prevname_found &&
+ *prevauthor.string && *prevdate.string &&
+ *prevrev.string && *prevstate.string
+ )
break;
- }
}
- Igeteof(fp, c, break;);
+ Igeteof_(fp, c, break;)
}
ok:
@@ -246,7 +267,7 @@ getoldkeys(fp)
static int
badly_terminated()
{
- error("badly terminated keyword value");
+ workerror("badly terminated keyword value");
return false;
}
@@ -257,12 +278,12 @@ getval(fp, target, optional)
int optional;
/* Reads a keyword value from FP into TARGET.
* Returns true if one is found, false otherwise.
- * Does not modify target if it is nil.
+ * Does not modify target if it is 0.
* Do not report an error if OPTIONAL is set and KDELIM is found instead.
*/
{
int c;
- Igeteof(fp, c, return badly_terminated(););
+ Igeteof_(fp, c, return badly_terminated();)
return get0val(c, fp, target, optional);
}
@@ -305,8 +326,6 @@ get0val(c, fp, target, optional)
VOID printf("getval: %s\n", target);
# endif
}
- if (!got1)
- error("too much white space in keyword value");
return got1;
case KDELIM:
@@ -317,7 +336,7 @@ get0val(c, fp, target, optional)
case 0:
return badly_terminated();
}
- Igeteof(fp, c, return badly_terminated(););
+ Igeteof_(fp, c, return badly_terminated();)
}
}
@@ -329,8 +348,7 @@ keepdate(fp)
* Return 0 on error, lookahead character otherwise.
*/
{
- struct buf prevday, prevtime, prevzone;
- register char const *p;
+ struct buf prevday, prevtime;
register int c;
c = 0;
@@ -338,24 +356,18 @@ keepdate(fp)
if (getval(fp,&prevday,false)) {
bufautobegin(&prevtime);
if (getval(fp,&prevtime,false)) {
- bufautobegin(&prevzone);
- bufscpy(&prevzone, "");
- Igeteof(fp, c, c=0;);
- if (c=='-' || c=='+')
- if (!get0val(c,fp,&prevzone,false))
- c = 0;
- else
- Igeteof(fp, c, c=0;);
+ Igeteof_(fp, c, c=0;)
if (c) {
- p = prevday.string;
- bufalloc(&prevdate, strlen(p) + strlen(prevtime.string) + strlen(prevzone.string) + 5);
- VOID sprintf(prevdate.string, "%s%s %s %s",
+ register char const *d = prevday.string, *t = prevtime.string;
+ bufalloc(&prevdate, strlen(d) + strlen(t) + 9);
+ VOID sprintf(prevdate.string, "%s%s %s%s",
/* Parse dates put out by old versions of RCS. */
- isdigit(p[0]) && isdigit(p[1]) && p[2]=='/' ? "19" : "",
- p, prevtime.string, prevzone.string
+ isdigit(d[0]) && isdigit(d[1]) && !isdigit(d[2])
+ ? "19" : "",
+ d, t,
+ strchr(t,'-') || strchr(t,'+') ? "" : "+0000"
);
}
- bufautoend(&prevzone);
}
bufautoend(&prevtime);
}
@@ -371,11 +383,11 @@ keepid(c, fp, b)
/* Get previous identifier from C+FP into B. */
{
if (!c)
- Igeteof(fp, c, return false;);
+ Igeteof_(fp, c, return false;)
if (!get0val(c, fp, b, false))
return false;
checksid(b->string);
- return true;
+ return !nerror;
}
static int
@@ -383,28 +395,45 @@ keeprev(fp)
RILE *fp;
/* Get previous revision from FP into prevrev. */
{
- return getval(fp,&prevrev,false) && checknum(prevrev.string,-1);
+ return getval(fp,&prevrev,false) && checknum(prevrev.string);
}
static int
-checknum(sp,fields)
- register char const *sp;
- int fields;
-{ register int dotcount;
- dotcount=0;
- while(*sp) {
- if (*sp=='.') dotcount++;
- else if (!isdigit(*sp)) return false;
- sp++;
- }
- return fields<0 ? dotcount&1 : dotcount==fields;
+checknum(s)
+ char const *s;
+{
+ register char const *sp;
+ register int dotcount = 0;
+ for (sp=s; ; sp++) {
+ switch (*sp) {
+ case 0:
+ if (dotcount & 1)
+ return true;
+ else
+ break;
+
+ case '.':
+ dotcount++;
+ continue;
+
+ default:
+ if (isdigit(*sp))
+ continue;
+ break;
+ }
+ break;
+ }
+ workerror("%s is not a revision number", s);
+ return false;
}
#ifdef KEEPTEST
+/* Print the keyword values found. */
+
char const cmdid[] ="keeptest";
int
@@ -412,10 +441,10 @@ main(argc, argv)
int argc; char *argv[];
{
while (*(++argv)) {
- workfilename = *argv;
+ workname = *argv;
getoldkeys((RILE*)0);
- VOID printf("%s: revision: %s, date: %s, author: %s, state: %s\n",
- *argv, prevrev.string, prevdate.string, prevauthor.string, prevstate.string);
+ VOID printf("%s: revision: %s, date: %s, author: %s, name: %s, state: %s\n",
+ *argv, prevrev.string, prevdate.string, prevauthor.string, prevname.string, prevstate.string);
}
exitmain(EXIT_SUCCESS);
}
diff --git a/gnu/usr.bin/rcs/lib/rcskeys.c b/gnu/usr.bin/rcs/lib/rcskeys.c
index 82850a7..492d8cb 100644
--- a/gnu/usr.bin/rcs/lib/rcskeys.c
+++ b/gnu/usr.bin/rcs/lib/rcskeys.c
@@ -1,9 +1,7 @@
-/*
- * RCS keyword table and match operation
- */
+/* RCS keyword table and match operation */
-/* Copyright (C) 1982, 1988, 1989 Walter Tichy
- Copyright 1990, 1991 by Paul Eggert
+/* Copyright 1982, 1988, 1989 Walter Tichy
+ Copyright 1990, 1991, 1992, 1993, 1995 Paul Eggert
Distributed under license by the Free Software Foundation, Inc.
This file is part of RCS.
@@ -19,8 +17,9 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
-along with RCS; see the file COPYING. If not, write to
-the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+along with RCS; see the file COPYING.
+If not, write to the Free Software Foundation,
+59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
Report problems and direct all questions to:
@@ -28,9 +27,13 @@ Report problems and direct all questions to:
*/
-
-
-/* $Log: rcskeys.c,v $
+/*
+ * Revision 5.4 1995/06/16 06:19:24 eggert
+ * Update FSF address.
+ *
+ * Revision 5.3 1993/11/03 17:42:27 eggert
+ * Add Name keyword.
+ *
* Revision 5.2 1991/08/19 03:13:55 eggert
* Say `T const' instead of `const T'; it's less confusing for pointer types.
* (This change was made in other source files too.)
@@ -43,34 +46,42 @@ Report problems and direct all questions to:
*
* Revision 4.3 89/05/01 15:13:02 narten
* changed copyright header to reflect current distribution rules
- *
+ *
* Revision 4.2 87/10/18 10:36:33 narten
* Updating version numbers. Changes relative to 1.1 actuallyt
* relative to 4.1
- *
+ *
* Revision 1.2 87/09/24 14:00:10 narten
- * Sources now pass through lint (if you ignore printf/sprintf/fprintf
+ * Sources now pass through lint (if you ignore printf/sprintf/fprintf
* warnings)
- *
+ *
* Revision 4.1 83/05/04 10:06:53 wft
* Initial revision.
- *
+ *
*/
#include "rcsbase.h"
-libId(keysId, "$Id: rcskeys.c,v 5.2 1991/08/19 03:13:55 eggert Exp $")
+libId(keysId, "$Id: rcskeys.c,v 1.7 1995/10/29 19:31:11 peter Exp $")
char const *const Keyword[] = {
/* This must be in the same order as rcsbase.h's enum markers type. */
- nil,
+ 0,
AUTHOR, DATE, HEADER, IDH,
- LOCKER, LOG, RCSFILE, REVISION, SOURCE, STATE
+ LOCKER, LOG, NAME, RCSFILE, REVISION, SOURCE, STATE,
+ FREEBSD
};
+/* Expand all keywords by default */
+static int ExpandKeyword[] = {
+ false,
+ true, true, true, true,
+ true, true, true, true, true, true, true,
+ false
+};
enum markers
trymatch(string)
@@ -83,6 +94,8 @@ trymatch(string)
register int j;
register char const *p, *s;
for (j = sizeof(Keyword)/sizeof(*Keyword); (--j); ) {
+ if (!ExpandKeyword[j])
+ continue;
/* try next keyword */
p = Keyword[j];
s = string;
@@ -100,3 +113,33 @@ trymatch(string)
return(Nomatch);
}
+setIncExc(arg)
+ char *arg;
+/* Sets up the ExpandKeyword table according to command-line flags */
+{
+ char *key;
+ int include = 0, j;
+
+ arg += 2;
+ switch (*arg++) {
+ case 'e':
+ include = false;
+ break;
+ case 'i':
+ include = true;
+ break;
+ default:
+ return(false);
+ }
+ if (include)
+ for (j = sizeof(Keyword)/sizeof(*Keyword); (--j); )
+ ExpandKeyword[j] = false;
+ key = strtok(arg, ",");
+ while (key) {
+ for (j = sizeof(Keyword)/sizeof(*Keyword); (--j); )
+ if (!strcmp(key, Keyword[j]))
+ ExpandKeyword[j] = include;
+ key = strtok(NULL, ",");
+ }
+ return(true);
+}
diff --git a/gnu/usr.bin/rcs/lib/rcslex.c b/gnu/usr.bin/rcs/lib/rcslex.c
index 51e31f3..9929dc4 100644
--- a/gnu/usr.bin/rcs/lib/rcslex.c
+++ b/gnu/usr.bin/rcs/lib/rcslex.c
@@ -1,17 +1,16 @@
-/*
- * RCS file input
- */
-/*********************************************************************************
+/* lexical analysis of RCS files */
+
+/******************************************************************************
* Lexical Analysis.
* hashtable, Lexinit, nextlex, getlex, getkey,
* getid, getnum, readstring, printstring, savestring,
* checkid, fatserror, error, faterror, warn, diagnose
* Testprogram: define LEXDB
- *********************************************************************************
+ ******************************************************************************
*/
-/* Copyright (C) 1982, 1988, 1989 Walter Tichy
- Copyright 1990, 1991 by Paul Eggert
+/* Copyright 1982, 1988, 1989 Walter Tichy
+ Copyright 1990, 1991, 1992, 1993, 1994, 1995 Paul Eggert
Distributed under license by the Free Software Foundation, Inc.
This file is part of RCS.
@@ -27,8 +26,9 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
-along with RCS; see the file COPYING. If not, write to
-the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+along with RCS; see the file COPYING.
+If not, write to the Free Software Foundation,
+59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
Report problems and direct all questions to:
@@ -38,7 +38,43 @@ Report problems and direct all questions to:
-/* $Log: rcslex.c,v $
+/*
+ * Revision 5.19 1995/06/16 06:19:24 eggert
+ * Update FSF address.
+ *
+ * Revision 5.18 1995/06/01 16:23:43 eggert
+ * (map_fd_deallocate,mmap_deallocate,read_deallocate,nothing_to_deallocate):
+ * New functions.
+ * (Iclose): If large_memory and maps_memory, use them to deallocate mapping.
+ * (fd2RILE): Use map_fd if available.
+ * If one mapping method fails, try the next instead of giving up;
+ * if they all fail, fall back on ordinary read.
+ * Work around bug: root mmap over NFS succeeds, but accessing dumps core.
+ * Use MAP_FAILED macro for mmap failure, and `char *' instead of caddr_t.
+ * (advise_access): Use madvise only if this instance used mmap.
+ * (Iopen): Use fdSafer to get safer file descriptor.
+ * (aflush): Moved here from rcsedit.c.
+ *
+ * Revision 5.17 1994/03/20 04:52:58 eggert
+ * Don't worry if madvise fails. Add Orewind. Remove lint.
+ *
+ * Revision 5.16 1993/11/09 17:55:29 eggert
+ * Fix `label: }' typo.
+ *
+ * Revision 5.15 1993/11/03 17:42:27 eggert
+ * Improve quality of diagnostics by putting file names in them more often.
+ * Don't discard ignored phrases.
+ *
+ * Revision 5.14 1992/07/28 16:12:44 eggert
+ * Identifiers may now start with a digit and (unless they are symbolic names)
+ * may contain `.'. Avoid `unsigned'. Statement macro names now end in _.
+ *
+ * Revision 5.13 1992/02/17 23:02:27 eggert
+ * Work around NFS mmap SIGBUS problem.
+ *
+ * Revision 5.12 1992/01/06 02:42:34 eggert
+ * Use OPEN_O_BINARY if mode contains 'b'.
+ *
* Revision 5.11 1991/11/03 03:30:44 eggert
* Fix porting bug to ancient hosts lacking vfprintf.
*
@@ -80,31 +116,31 @@ Report problems and direct all questions to:
*
* Revision 4.6 89/05/01 15:13:07 narten
* changed copyright header to reflect current distribution rules
- *
+ *
* Revision 4.5 88/08/28 15:01:12 eggert
* Don't loop when writing error messages to a full filesystem.
* Flush stderr/stdout when mixing output.
* Yield exit status compatible with diff(1).
* Shrink stdio code size; allow cc -R; remove lint.
- *
+ *
* Revision 4.4 87/12/18 11:44:47 narten
* fixed to use "varargs" in "fprintf"; this is required if it is to
* work on a SPARC machine such as a Sun-4
- *
+ *
* Revision 4.3 87/10/18 10:37:18 narten
* Updating version numbers. Changes relative to 1.1 actually relative
* to version 4.1
- *
+ *
* Revision 1.3 87/09/24 14:00:17 narten
- * Sources now pass through lint (if you ignore printf/sprintf/fprintf
+ * Sources now pass through lint (if you ignore printf/sprintf/fprintf
* warnings)
- *
+ *
* Revision 1.2 87/03/27 14:22:33 jenkins
* Port to suns
- *
+ *
* Revision 4.1 83/03/25 18:12:51 wft
* Only changed $Header to $Id.
- *
+ *
* Revision 3.3 82/12/10 16:22:37 wft
* Improved error messages, changed exit status on error to 1.
*
@@ -132,7 +168,14 @@ Report problems and direct all questions to:
#include "rcsbase.h"
-libId(lexId, "$Id: rcslex.c,v 5.11 1991/11/03 03:30:44 eggert Exp $")
+libId(lexId, "$Id: rcslex.c,v 1.4 1995/10/28 21:49:46 peter Exp $")
+
+static char *checkidentifier P((char*,int,int));
+static void errsay P((char const*));
+static void fatsay P((char const*));
+static void lookup P((char const*));
+static void startsay P((const char*,const char*));
+static void warnsay P((char const*));
static struct hshentry *nexthsh; /*pointer to next hash entry, set by lookup*/
@@ -142,7 +185,7 @@ int hshenter; /*if true, next suitable lexeme will be entered */
/*into the symbol table. Handle with care. */
int nextc; /*next input character, initialized by Lexinit */
-unsigned long rcsline; /*current line-number of input */
+long rcsline; /*current line-number of input */
int nerror; /*counter for errors */
int quietflag; /*indicates quiet mode */
RILE * finptr; /*input file descriptor */
@@ -172,9 +215,9 @@ static int ignored_phrases; /* have we ignored phrases in this RCS file? */
void
warnignore()
{
- if (! (ignored_phrases|quietflag)) {
+ if (!ignored_phrases) {
ignored_phrases = true;
- warn("Unknown phrases like `%s ...;' are in the RCS file.", NextString);
+ rcswarn("Unknown phrases like `%s ...;' are present.", NextString);
}
}
@@ -205,7 +248,7 @@ lookup(str)
/* empty slot found */
*p = n = ftalloc(struct hshentry);
n->num = fstr_save(str);
- n->nexthsh = nil;
+ n->nexthsh = 0;
# ifdef LEXDB
VOID printf("\nEntered: %s at %u ", str, ihash);
# endif
@@ -231,7 +274,7 @@ Lexinit()
{ register int c;
for (c = hshsize; 0 <= --c; ) {
- hshtab[c] = nil;
+ hshtab[c] = 0;
}
nerror = 0;
@@ -241,7 +284,7 @@ Lexinit()
ignored_phrases = false;
rcsline = 1;
bufrealloc(&tokbuf, 2);
- Iget(finptr, nextc);
+ Iget_(finptr, nextc)
nextlex(); /*initial token*/
}
}
@@ -288,46 +331,48 @@ nextlex()
/* Note: falls into next case */
case SPACE:
- GETC(frew, c);
+ GETC_(frew, c)
continue;
- case DIGIT:
- sp = tokbuf.string;
- limit = sp + tokbuf.size;
- *sp++ = c;
- for (;;) {
- GETC(frew, c);
- if ((d=ctab[c])!=DIGIT && d!=PERIOD)
- break;
- *sp++ = c; /* 1.2. and 1.2 are different */
- if (limit <= sp)
- sp = bufenlarge(&tokbuf, &limit);
- }
- *sp = 0;
- if (hshenter)
- lookup(tokbuf.string);
- else
- NextString = fstr_save(tokbuf.string);
- d = NUM;
- break;
-
-
- case LETTER:
+ case IDCHAR:
+ case LETTER:
case Letter:
+ d = ID;
+ /* fall into */
+ case DIGIT:
+ case PERIOD:
sp = tokbuf.string;
limit = sp + tokbuf.size;
*sp++ = c;
for (;;) {
- GETC(frew, c);
- if ((d=ctab[c])!=LETTER && d!=Letter && d!=DIGIT && d!=IDCHAR)
+ GETC_(frew, c)
+ switch (ctab[c]) {
+ case IDCHAR:
+ case LETTER:
+ case Letter:
+ d = ID;
+ /* fall into */
+ case DIGIT:
+ case PERIOD:
+ *sp++ = c;
+ if (limit <= sp)
+ sp = bufenlarge(&tokbuf, &limit);
+ continue;
+
+ default:
break;
- *sp++ = c;
- if (limit <= sp)
- sp = bufenlarge(&tokbuf, &limit);
+ }
+ break;
}
*sp = 0;
+ if (d == DIGIT || d == PERIOD) {
+ d = NUM;
+ if (hshenter) {
+ lookup(tokbuf.string);
+ break;
+ }
+ }
NextString = fstr_save(tokbuf.string);
- d = ID; /* may be ID or keyword */
break;
case SBEGIN: /* long string */
@@ -338,7 +383,7 @@ nextlex()
case COLON:
case SEMI:
- GETC(frew, c);
+ GETC_(frew, c)
break;
} break; }
nextc = c;
@@ -374,11 +419,11 @@ eoflex()
++rcsline;
/* fall into */
case SPACE:
- cachegeteof(c, {uncache(fin);return true;});
+ cachegeteof_(c, {uncache(fin);return true;})
break;
}
if (fout)
- aputc(c, fout);
+ aputc_(c, fout)
}
}
@@ -442,7 +487,7 @@ getkeystring(key)
getid()
/* Function: Checks if nexttok is an identifier. If so,
* advances the input by calling nextlex and returns a pointer
- * to the identifier; otherwise returns nil.
+ * to the identifier; otherwise returns 0.
* Treats keywords as identifiers.
*/
{
@@ -451,14 +496,15 @@ getid()
name = NextString;
nextlex();
return name;
- } else return nil;
+ } else
+ return 0;
}
struct hshentry * getnum()
/* Function: Checks if nexttok is a number. If so,
* advances the input by calling nextlex and returns a pointer
- * to the hashtable entry. Otherwise returns nil.
+ * to the hashtable entry. Otherwise returns 0.
* Doesn't work if hshenter is false.
*/
{
@@ -467,46 +513,55 @@ struct hshentry * getnum()
num=nexthsh;
nextlex();
return num;
- } else return nil;
+ } else
+ return 0;
}
struct cbuf
getphrases(key)
char const *key;
-/* Get a series of phrases that do not start with KEY, yield resulting buffer.
- * Stop when the next phrase starts with a token that is not an identifier,
- * or is KEY.
- * Assume !foutptr.
- */
+/*
+* Get a series of phrases that do not start with KEY. Yield resulting buffer.
+* Stop when the next phrase starts with a token that is not an identifier,
+* or is KEY. Copy input to foutptr if it is set. Unlike ignorephrases(),
+* this routine assumes nextlex() has already been invoked before we start.
+*/
{
declarecache;
register int c;
- register char *p;
- char const *limit;
- register char const *ki, *kn;
+ register char const *kn;
struct cbuf r;
- struct buf b;
register RILE *fin;
+ register FILE *frew;
+# if large_memory
+# define savech_(c) ;
+# else
+ register char *p;
+ char const *limit;
+ struct buf b;
+# define savech_(c) {if (limit<=p)p=bufenlarge(&b,&limit); *p++ =(c);}
+# endif
- if (nexttok!=ID || strcmp(NextString,key) == 0) {
- r.string = 0;
- r.size = 0;
- return r;
- } else {
+ if (nexttok!=ID || strcmp(NextString,key) == 0)
+ clear_buf(&r);
+ else {
warnignore();
fin = finptr;
+ frew = foutptr;
setupcache(fin); cache(fin);
- bufautobegin(&b);
- bufscpy(&b, NextString);
+# if large_memory
+ r.string = (char const*)cacheptr() - strlen(NextString) - 1;
+# else
+ bufautobegin(&b);
+ bufscpy(&b, NextString);
+ p = b.string + strlen(b.string);
+ limit = b.string + b.size;
+# endif
ffree1(NextString);
- p = b.string + strlen(b.string);
- limit = b.string + b.size;
c = nextc;
for (;;) {
for (;;) {
- if (limit <= p)
- p = bufenlarge(&b, &limit);
- *p++ = c;
+ savech_(c)
switch (ctab[c]) {
default:
fatserror("unknown character `%c'", c);
@@ -516,15 +571,13 @@ getphrases(key)
/* fall into */
case COLON: case DIGIT: case LETTER: case Letter:
case PERIOD: case SPACE:
- cacheget(c);
+ GETC_(frew, c)
continue;
case SBEGIN: /* long string */
for (;;) {
for (;;) {
- if (limit <= p)
- p = bufenlarge(&b, &limit);
- cacheget(c);
- *p++ = c;
+ GETC_(frew, c)
+ savech_(c)
switch (c) {
case '\n':
++rcsline;
@@ -537,48 +590,50 @@ getphrases(key)
}
break;
}
- cacheget(c);
+ GETC_(frew, c)
if (c != SDELIM)
break;
- if (limit <= p)
- p = bufenlarge(&b, &limit);
- *p++ = c;
+ savech_(c)
}
continue;
case SEMI:
- cacheget(c);
+ cacheget_(c)
if (ctab[c] == NEWLN) {
+ if (frew)
+ aputc_(c, frew)
++rcsline;
- if (limit <= p)
- p = bufenlarge(&b, &limit);
- *p++ = c;
- cacheget(c);
+ savech_(c)
+ cacheget_(c)
}
+# if large_memory
+ r.size = (char const*)cacheptr() - 1 - r.string;
+# endif
for (;;) {
switch (ctab[c]) {
case NEWLN:
++rcsline;
/* fall into */
case SPACE:
- cacheget(c);
+ cacheget_(c)
continue;
default: break;
}
break;
}
+ if (frew)
+ aputc_(c, frew)
break;
}
break;
}
- switch (ctab[c]) {
- case LETTER:
- case Letter:
+ if (ctab[c] == Letter) {
for (kn = key; c && *kn==c; kn++)
- cacheget(c);
+ GETC_(frew, c)
if (!*kn)
switch (ctab[c]) {
case DIGIT: case LETTER: case Letter:
+ case IDCHAR: case PERIOD:
break;
default:
nextc = c;
@@ -587,23 +642,26 @@ getphrases(key)
uncache(fin);
goto returnit;
}
- for (ki=key; ki<kn; ) {
- if (limit <= p)
- p = bufenlarge(&b, &limit);
- *p++ = *ki++;
- }
- break;
-
- default:
+# if !large_memory
+ {
+ register char const *ki;
+ for (ki=key; ki<kn; )
+ savech_(*ki++)
+ }
+# endif
+ } else {
nextc = c;
uncache(fin);
nextlex();
- goto returnit;
+ break;
}
}
- returnit:
- return bufremember(&b, (size_t)(p - b.string));
+ returnit:;
+# if !large_memory
+ return bufremember(&b, (size_t)(p - b.string));
+# endif
}
+ return r;
}
@@ -619,14 +677,14 @@ readstring()
fin=finptr; frew=foutptr;
setupcache(fin); cache(fin);
for (;;) {
- GETC(frew, c);
+ GETC_(frew, c)
switch (c) {
case '\n':
++rcsline;
break;
case SDELIM:
- GETC(frew, c);
+ GETC_(frew, c)
if (c != SDELIM) {
/* end of string */
nextc = c;
@@ -653,13 +711,13 @@ printstring()
fout = stdout;
setupcache(fin); cache(fin);
for (;;) {
- cacheget(c);
+ cacheget_(c)
switch (c) {
case '\n':
++rcsline;
break;
case SDELIM:
- cacheget(c);
+ cacheget_(c)
if (c != SDELIM) {
nextc=c;
uncache(fin);
@@ -667,7 +725,7 @@ printstring()
}
break;
}
- aputc(c,fout);
+ aputc_(c,fout)
}
}
@@ -695,13 +753,13 @@ savestring(target)
setupcache(fin); cache(fin);
tp = target->string; limit = tp + target->size;
for (;;) {
- GETC(frew, c);
+ GETC_(frew, c)
switch (c) {
case '\n':
++rcsline;
break;
case SDELIM:
- GETC(frew, c);
+ GETC_(frew, c)
if (c != SDELIM) {
/* end of string */
nextc=c;
@@ -719,44 +777,76 @@ savestring(target)
}
- char *
-checkid(id, delimiter)
+ static char *
+checkidentifier(id, delimiter, dotok)
register char *id;
int delimiter;
+ register int dotok;
/* Function: check whether the string starting at id is an */
/* identifier and return a pointer to the delimiter*/
/* after the identifier. White space, delim and 0 */
/* are legal delimiters. Aborts the program if not*/
/* a legal identifier. Useful for checking commands*/
/* If !delim, the only delimiter is 0. */
+/* Allow '.' in identifier only if DOTOK is set. */
{
- register enum tokens d;
register char *temp;
- register char c,tc;
+ register char c;
register char delim = delimiter;
+ int isid = false;
temp = id;
- if ((d = ctab[(unsigned char)(c = *id)])==LETTER || d==Letter) {
- while ((d = ctab[(unsigned char)(c = *++id)])==LETTER
- || d==Letter || d==DIGIT || d==IDCHAR
- )
- ;
- if (c && (!delim || c!=delim && c!=' ' && c!='\t' && c!='\n')) {
+ for (;; id++) {
+ switch (ctab[(unsigned char)(c = *id)]) {
+ case IDCHAR:
+ case LETTER:
+ case Letter:
+ isid = true;
+ continue;
+
+ case DIGIT:
+ continue;
+
+ case PERIOD:
+ if (dotok)
+ continue;
+ break;
+
+ default:
+ break;
+ }
+ break;
+ }
+ if ( ! isid
+ || (c && (!delim || (c!=delim && c!=' ' && c!='\t' && c!='\n')))
+ ) {
/* append \0 to end of id before error message */
- tc = c;
- while( (c=(*++id))!=' ' && c!='\t' && c!='\n' && c!='\0' && c!=delim) ;
+ while ((c = *id) && c!=' ' && c!='\t' && c!='\n' && c!=delim)
+ id++;
*id = '\0';
- faterror("invalid character %c in identifier `%s'",tc,temp);
- }
- } else {
- /* append \0 to end of id before error message */
- while( (c=(*++id))!=' ' && c!='\t' && c!='\n' && c!='\0' && c!=delim) ;
- *id = '\0';
- faterror("identifier `%s' doesn't start with letter", temp);
- }
+ faterror("invalid %s `%s'",
+ dotok ? "identifier" : "symbol", temp
+ );
+ }
return id;
}
+ char *
+checkid(id, delimiter)
+ char *id;
+ int delimiter;
+{
+ return checkidentifier(id, delimiter, true);
+}
+
+ char *
+checksym(sym, delimiter)
+ char *sym;
+ int delimiter;
+{
+ return checkidentifier(sym, delimiter, false);
+}
+
void
checksid(id)
char *id;
@@ -765,16 +855,92 @@ checksid(id)
VOID checkid(id, 0);
}
+ void
+checkssym(sym)
+ char *sym;
+{
+ VOID checksym(sym, 0);
+}
+
+
+#if !large_memory
+# define Iclose(f) fclose(f)
+#else
+# if !maps_memory
+ static int Iclose P((RILE *));
+ static int
+ Iclose(f)
+ register RILE *f;
+ {
+ tfree(f->base);
+ f->base = 0;
+ return fclose(f->stream);
+ }
+# else
+ static int Iclose P((RILE *));
+ static int
+ Iclose(f)
+ register RILE *f;
+ {
+ (* f->deallocate) (f);
+ f->base = 0;
+ return close(f->fd);
+ }
+
+# if has_map_fd
+ static void map_fd_deallocate P((RILE *));
+ static void
+ map_fd_deallocate(f)
+ register RILE *f;
+ {
+ if (vm_deallocate(
+ task_self(),
+ (vm_address_t) f->base,
+ (vm_size_t) (f->lim - f->base)
+ ) != KERN_SUCCESS)
+ efaterror("vm_deallocate");
+ }
+# endif
+# if has_mmap
+ static void mmap_deallocate P((RILE *));
+ static void
+ mmap_deallocate(f)
+ register RILE *f;
+ {
+ if (munmap((char *) f->base, (size_t) (f->lim - f->base)) != 0)
+ efaterror("munmap");
+ }
+# endif
+ static void read_deallocate P((RILE *));
+ static void
+ read_deallocate(f)
+ RILE *f;
+ {
+ tfree(f->base);
+ }
+ static void nothing_to_deallocate P((RILE *));
+ static void
+ nothing_to_deallocate(f)
+ RILE *f;
+ {
+ }
+# endif
+#endif
+
+
+#if large_memory && maps_memory
+ static RILE *fd2_RILE P((int,char const*,struct stat*));
static RILE *
-#if has_mmap && large_memory
-fd2_RILE(fd, filename, status)
+fd2_RILE(fd, name, status)
#else
-fd2RILE(fd, filename, mode, status)
- char const *mode;
+ static RILE *fd2RILE P((int,char const*,char const*,struct stat*));
+ static RILE *
+fd2RILE(fd, name, type, status)
+ char const *type;
#endif
int fd;
- char const *filename;
+ char const *name;
register struct stat *status;
{
struct stat st;
@@ -782,67 +948,127 @@ fd2RILE(fd, filename, mode, status)
if (!status)
status = &st;
if (fstat(fd, status) != 0)
- efaterror(filename);
+ efaterror(name);
if (!S_ISREG(status->st_mode)) {
- error("`%s' is not a regular file", filename);
+ error("`%s' is not a regular file", name);
VOID close(fd);
errno = EINVAL;
return 0;
} else {
-# if ! (has_mmap && large_memory)
+# if !(large_memory && maps_memory)
FILE *stream;
- if (!(stream = fdopen(fd, mode)))
- efaterror(filename);
+ if (!(stream = fdopen(fd, type)))
+ efaterror(name);
# endif
# if !large_memory
return stream;
# else
# define RILES 3
- {
- static RILE rilebuf[RILES];
-
- register RILE *f;
- size_t s = status->st_size;
-
- if (s != status->st_size)
- faterror("`%s' is enormous", filename);
- for (f = rilebuf; f->base; f++)
- if (f == rilebuf+RILES)
- faterror("too many RILEs");
- if (!s) {
- static unsigned char dummy;
- f->base = &dummy;
- } else {
-# if has_mmap
- if (
- (f->base = (unsigned char *)mmap(
- (caddr_t)0, s, PROT_READ, MAP_SHARED,
- fd, (off_t)0
- )) == (unsigned char *)-1
- )
- efaterror("mmap");
-# else
- f->base = tnalloc(unsigned char, s);
+ {
+ static RILE rilebuf[RILES];
+
+ register RILE *f;
+ size_t s = status->st_size;
+
+ if (s != status->st_size)
+ faterror("%s: too large", name);
+ for (f = rilebuf; f->base; f++)
+ if (f == rilebuf+RILES)
+ faterror("too many RILEs");
+# if maps_memory
+ f->deallocate = nothing_to_deallocate;
+# endif
+ if (!s) {
+ static unsigned char nothing;
+ f->base = &nothing; /* Any nonzero address will do. */
+ } else {
+ f->base = 0;
+# if has_map_fd
+ map_fd(
+ fd, (vm_offset_t)0, (vm_address_t*) &f->base,
+ TRUE, (vm_size_t)s
+ );
+ f->deallocate = map_fd_deallocate;
+# endif
+# if has_mmap
+ if (!f->base) {
+ catchmmapints();
+ f->base = (unsigned char *) mmap(
+ (char *)0, s, PROT_READ, MAP_SHARED,
+ fd, (off_t)0
+ );
+# ifndef MAP_FAILED
+# define MAP_FAILED (-1)
# endif
+ if (f->base == (unsigned char *) MAP_FAILED)
+ f->base = 0;
+ else {
+# if has_NFS && mmap_signal
+ /*
+ * On many hosts, the superuser
+ * can mmap an NFS file it can't read.
+ * So access the first page now, and print
+ * a nice message if a bus error occurs.
+ */
+ readAccessFilenameBuffer(name, f->base);
+# endif
+ }
+ f->deallocate = mmap_deallocate;
+ }
+# endif
+ if (!f->base) {
+ f->base = tnalloc(unsigned char, s);
+# if maps_memory
+ {
+ /*
+ * We can't map the file into memory for some reason.
+ * Read it into main memory all at once; this is
+ * the simplest substitute for memory mapping.
+ */
+ char *bufptr = (char *) f->base;
+ size_t bufsiz = s;
+ do {
+ ssize_t r = read(fd, bufptr, bufsiz);
+ switch (r) {
+ case -1:
+ efaterror(name);
+
+ case 0:
+ /* The file must have shrunk! */
+ status->st_size = s -= bufsiz;
+ bufsiz = 0;
+ break;
+
+ default:
+ bufptr += r;
+ bufsiz -= r;
+ break;
+ }
+ } while (bufsiz);
+ if (lseek(fd, (off_t)0, SEEK_SET) == -1)
+ efaterror(name);
+ f->deallocate = read_deallocate;
}
- f->ptr = f->base;
- f->lim = f->base + s;
-# if has_mmap
- f->fd = fd;
-# else
- f->readlim = f->base;
- f->stream = stream;
# endif
- if_advise_access(s, f, MADV_SEQUENTIAL);
- return f;
+ }
}
+ f->ptr = f->base;
+ f->lim = f->base + s;
+ f->fd = fd;
+# if !maps_memory
+ f->readlim = f->base;
+ f->stream = stream;
+# endif
+ if_advise_access(s, f, MADV_SEQUENTIAL);
+ return f;
+ }
# endif
}
}
-#if !has_mmap && large_memory
+#if !maps_memory && large_memory
int
Igetmore(f)
register RILE *f;
@@ -868,59 +1094,42 @@ advise_access(f, advice)
register RILE *f;
int advice;
{
- if (madvise((caddr_t)f->base, (size_t)(f->lim - f->base), advice) != 0)
- efaterror("madvise");
+ if (f->deallocate == mmap_deallocate)
+ VOID madvise((char *)f->base, (size_t)(f->lim - f->base), advice);
+ /* Don't worry if madvise fails; it's only advisory. */
}
#endif
RILE *
-#if has_mmap && large_memory
-I_open(filename, status)
+#if large_memory && maps_memory
+I_open(name, status)
#else
-Iopen(filename, mode, status)
- char const *mode;
+Iopen(name, type, status)
+ char const *type;
#endif
- char const *filename;
+ char const *name;
struct stat *status;
-/* Open FILENAME for reading, yield its descriptor, and set *STATUS. */
+/* Open NAME for reading, yield its descriptor, and set *STATUS. */
{
- int fd;
+ int fd = fdSafer(open(name, O_RDONLY
+# if OPEN_O_BINARY
+ | (strchr(type,'b') ? OPEN_O_BINARY : 0)
+# endif
+ ));
- if ((fd = open(filename,O_RDONLY|O_BINARY)) < 0)
+ if (fd < 0)
return 0;
-# if has_mmap && large_memory
- return fd2_RILE(fd, filename, status);
+# if large_memory && maps_memory
+ return fd2_RILE(fd, name, status);
# else
- return fd2RILE(fd, filename, mode, status);
+ return fd2RILE(fd, name, type, status);
# endif
}
-#if !large_memory
-# define Iclose(f) fclose(f)
-#else
- static int
- Iclose(f)
- register RILE *f;
- {
-# if has_mmap
- size_t s = f->lim - f->base;
- if (s && munmap((caddr_t)f->base, s) != 0)
- return -1;
- f->base = 0;
- return close(f->fd);
-# else
- tfree(f->base);
- f->base = 0;
- return fclose(f->stream);
-# endif
- }
-#endif
-
-
static int Oerrloop;
- exiting void
+ void
Oerror()
{
if (Oerrloop)
@@ -929,8 +1138,8 @@ Oerror()
efaterror("output error");
}
-exiting void Ieof() { fatserror("unexpected end of file"); }
-exiting void Ierror() { efaterror("input error"); }
+void Ieof() { fatserror("unexpected end of file"); }
+void Ierror() { efaterror("input error"); }
void testIerror(f) FILE *f; { if (ferror(f)) Ierror(); }
void testOerror(o) FILE *o; { if (ferror(o)) Oerror(); }
@@ -951,19 +1160,17 @@ testIeof(f)
void Irewind(f) FILE *f; { if (fseek(f,0L,SEEK_SET) != 0) Ierror(); }
#endif
-void eflush()
-{
- if (fflush(stderr) != 0 && !Oerrloop)
- Oerror();
-}
+void Orewind(f) FILE *f; { if (fseek(f,0L,SEEK_SET) != 0) Oerror(); }
+void aflush(f) FILE *f; { if (fflush(f) != 0) Oerror(); }
+void eflush() { if (fflush(stderr)!=0 && !Oerrloop) Oerror(); }
void oflush()
{
if (fflush(workstdout ? workstdout : stdout) != 0 && !Oerrloop)
Oerror();
}
- static exiting void
+ void
fatcleanup(already_newline)
int already_newline;
{
@@ -971,8 +1178,38 @@ fatcleanup(already_newline)
exiterr();
}
-static void errsay() { oflush(); aprintf(stderr,"%s error: ",cmdid); nerror++; }
-static void fatsay() { oflush(); VOID fprintf(stderr,"%s error: ",cmdid); }
+ static void
+startsay(s, t)
+ const char *s, *t;
+{
+ oflush();
+ if (s)
+ aprintf(stderr, "%s: %s: %s", cmdid, s, t);
+ else
+ aprintf(stderr, "%s: %s", cmdid, t);
+}
+
+ static void
+fatsay(s)
+ char const *s;
+{
+ startsay(s, "");
+}
+
+ static void
+errsay(s)
+ char const *s;
+{
+ fatsay(s);
+ nerror++;
+}
+
+ static void
+warnsay(s)
+ char const *s;
+{
+ startsay(s, "warning: ");
+}
void eerror(s) char const *s; { enerror(errno,s); }
@@ -981,20 +1218,20 @@ enerror(e,s)
int e;
char const *s;
{
- errsay();
+ errsay((char const*)0);
errno = e;
perror(s);
eflush();
}
-exiting void efaterror(s) char const *s; { enfaterror(errno,s); }
+void efaterror(s) char const *s; { enfaterror(errno,s); }
- exiting void
+ void
enfaterror(e,s)
int e;
char const *s;
{
- fatsay();
+ fatsay((char const*)0);
errno = e;
perror(s);
fatcleanup(true);
@@ -1009,7 +1246,7 @@ error(char const *format,...)
/* non-fatal error */
{
va_list args;
- errsay();
+ errsay((char const*)0);
vararg_start(args, format);
fvfprintf(stderr, format, args);
va_end(args);
@@ -1018,17 +1255,51 @@ error(char const *format,...)
}
#if has_prototypes
- exiting void
+ void
+rcserror(char const *format,...)
+#else
+ /*VARARGS1*/ void rcserror(format, va_alist) char const *format; va_dcl
+#endif
+/* non-fatal RCS file error */
+{
+ va_list args;
+ errsay(RCSname);
+ vararg_start(args, format);
+ fvfprintf(stderr, format, args);
+ va_end(args);
+ afputc('\n',stderr);
+ eflush();
+}
+
+#if has_prototypes
+ void
+workerror(char const *format,...)
+#else
+ /*VARARGS1*/ void workerror(format, va_alist) char const *format; va_dcl
+#endif
+/* non-fatal working file error */
+{
+ va_list args;
+ errsay(workname);
+ vararg_start(args, format);
+ fvfprintf(stderr, format, args);
+ va_end(args);
+ afputc('\n',stderr);
+ eflush();
+}
+
+#if has_prototypes
+ void
fatserror(char const *format,...)
#else
- /*VARARGS1*/ exiting void
+ /*VARARGS1*/ void
fatserror(format, va_alist) char const *format; va_dcl
#endif
-/* fatal syntax error */
+/* fatal RCS file syntax error */
{
va_list args;
oflush();
- VOID fprintf(stderr, "%s: %s:%lu: ", cmdid, RCSfilename, rcsline);
+ VOID fprintf(stderr, "%s: %s:%ld: ", cmdid, RCSname, rcsline);
vararg_start(args, format);
fvfprintf(stderr, format, args);
va_end(args);
@@ -1036,16 +1307,16 @@ fatserror(char const *format,...)
}
#if has_prototypes
- exiting void
+ void
faterror(char const *format,...)
#else
- /*VARARGS1*/ exiting void faterror(format, va_alist)
+ /*VARARGS1*/ void faterror(format, va_alist)
char const *format; va_dcl
#endif
/* fatal error, terminates program after cleanup */
{
va_list args;
- fatsay();
+ fatsay((char const*)0);
vararg_start(args, format);
fvfprintf(stderr, format, args);
va_end(args);
@@ -1054,20 +1325,76 @@ faterror(char const *format,...)
#if has_prototypes
void
-warn(char const *format,...)
+rcsfaterror(char const *format,...)
#else
- /*VARARGS1*/ void warn(format, va_alist) char const *format; va_dcl
+ /*VARARGS1*/ void rcsfaterror(format, va_alist)
+ char const *format; va_dcl
#endif
-/* prints a warning message */
+/* fatal RCS file error, terminates program after cleanup */
{
va_list args;
- oflush();
- aprintf(stderr,"%s warning: ",cmdid);
+ fatsay(RCSname);
vararg_start(args, format);
fvfprintf(stderr, format, args);
va_end(args);
- afputc('\n',stderr);
- eflush();
+ fatcleanup(false);
+}
+
+#if has_prototypes
+ void
+warn(char const *format,...)
+#else
+ /*VARARGS1*/ void warn(format, va_alist) char const *format; va_dcl
+#endif
+/* warning */
+{
+ va_list args;
+ if (!quietflag) {
+ warnsay((char *)0);
+ vararg_start(args, format);
+ fvfprintf(stderr, format, args);
+ va_end(args);
+ afputc('\n', stderr);
+ eflush();
+ }
+}
+
+#if has_prototypes
+ void
+rcswarn(char const *format,...)
+#else
+ /*VARARGS1*/ void rcswarn(format, va_alist) char const *format; va_dcl
+#endif
+/* RCS file warning */
+{
+ va_list args;
+ if (!quietflag) {
+ warnsay(RCSname);
+ vararg_start(args, format);
+ fvfprintf(stderr, format, args);
+ va_end(args);
+ afputc('\n', stderr);
+ eflush();
+ }
+}
+
+#if has_prototypes
+ void
+workwarn(char const *format,...)
+#else
+ /*VARARGS1*/ void workwarn(format, va_alist) char const *format; va_dcl
+#endif
+/* working file warning */
+{
+ va_list args;
+ if (!quietflag) {
+ warnsay(workname);
+ vararg_start(args, format);
+ fvfprintf(stderr, format, args);
+ va_end(args);
+ afputc('\n', stderr);
+ eflush();
+ }
}
void
@@ -1102,12 +1429,11 @@ diagnose(char const *format,...)
void
afputc(c, f)
-/* Function: afputc(c,f) acts like aputc(c,f), but is smaller and slower.
- */
+/* afputc(c,f); acts like aputc_(c,f) but is smaller and slower. */
int c;
register FILE *f;
{
- aputc(c,f);
+ aputc_(c,f)
}
@@ -1138,6 +1464,7 @@ fvfprintf(FILE *stream, char const *format, va_list args)
{
#if has_vfprintf
if (vfprintf(stream, format, args) < 0)
+ Oerror();
#else
# if has__doprintf
_doprintf(stream, format, args);
@@ -1153,8 +1480,8 @@ fvfprintf(FILE *stream, char const *format, va_list args)
# endif
# endif
if (ferror(stream))
-#endif
Oerror();
+#endif
}
#if has_prototypes
@@ -1235,7 +1562,7 @@ int argc; char * argv[];
exitmain(EXIT_SUCCESS);
}
-exiting void exiterr() { _exit(EXIT_FAILURE); }
+void exiterr() { _exit(EXIT_FAILURE); }
#endif
diff --git a/gnu/usr.bin/rcs/lib/rcsmap.c b/gnu/usr.bin/rcs/lib/rcsmap.c
index 0e7b23c..0345ef8 100644
--- a/gnu/usr.bin/rcs/lib/rcsmap.c
+++ b/gnu/usr.bin/rcs/lib/rcsmap.c
@@ -1,7 +1,7 @@
/* RCS map of character types */
/* Copyright (C) 1982, 1988, 1989 Walter Tichy
- Copyright 1990, 1991 by Paul Eggert
+ Copyright 1990, 1991, 1995 by Paul Eggert
Distributed under license by the Free Software Foundation, Inc.
This file is part of RCS.
@@ -17,8 +17,9 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
-along with RCS; see the file COPYING. If not, write to
-the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+along with RCS; see the file COPYING.
+If not, write to the Free Software Foundation,
+59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
Report problems and direct all questions to:
@@ -28,7 +29,7 @@ Report problems and direct all questions to:
#include "rcsbase.h"
-libId(mapId, "$Id: rcsmap.c,v 5.2 1991/08/19 03:13:55 eggert Exp $")
+libId(mapId, "$Id: rcsmap.c,v 5.3 1995/06/16 06:19:24 eggert Exp $")
/* map of character types */
/* ISO 8859/1 (Latin-1) */
diff --git a/gnu/usr.bin/rcs/lib/rcsrev.c b/gnu/usr.bin/rcs/lib/rcsrev.c
index ce11f54..c0d0bda 100644
--- a/gnu/usr.bin/rcs/lib/rcsrev.c
+++ b/gnu/usr.bin/rcs/lib/rcsrev.c
@@ -1,9 +1,7 @@
-/*
- * RCS revision number handling
- */
+/* Handle RCS revision numbers. */
-/* Copyright (C) 1982, 1988, 1989 Walter Tichy
- Copyright 1990, 1991 by Paul Eggert
+/* Copyright 1982, 1988, 1989 Walter Tichy
+ Copyright 1990, 1991, 1992, 1993, 1994, 1995 Paul Eggert
Distributed under license by the Free Software Foundation, Inc.
This file is part of RCS.
@@ -19,8 +17,9 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
-along with RCS; see the file COPYING. If not, write to
-the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+along with RCS; see the file COPYING.
+If not, write to the Free Software Foundation,
+59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
Report problems and direct all questions to:
@@ -28,10 +27,31 @@ Report problems and direct all questions to:
*/
-
-
-
-/* $Log: rcsrev.c,v $
+/*
+ * Revision 5.10 1995/06/16 06:19:24 eggert
+ * Update FSF address.
+ *
+ * Revision 5.9 1995/06/01 16:23:43 eggert
+ * (cmpdate, normalizeyear): New functions work around MKS RCS incompatibility.
+ * (cmpnum, compartial): s[d] -> *(s+d) to work around Cray compiler bug.
+ * (genrevs, genbranch): cmpnum -> cmpdate
+ *
+ * Revision 5.8 1994/03/17 14:05:48 eggert
+ * Remove lint.
+ *
+ * Revision 5.7 1993/11/09 17:40:15 eggert
+ * Fix format string typos.
+ *
+ * Revision 5.6 1993/11/03 17:42:27 eggert
+ * Revision number `.N' now stands for `D.N', where D is the default branch.
+ * Add -z. Improve quality of diagnostics. Add `namedrev' for Name support.
+ *
+ * Revision 5.5 1992/07/28 16:12:44 eggert
+ * Identifiers may now start with a digit. Avoid `unsigned'.
+ *
+ * Revision 5.4 1992/01/06 02:42:34 eggert
+ * while (E) ; -> while (E) continue;
+ *
* Revision 5.3 1991/08/19 03:13:55 eggert
* Add `-r$', `-rB.'. Remove botches like `<now>' from messages. Tune.
*
@@ -48,25 +68,25 @@ Report problems and direct all questions to:
*
* Revision 4.5 89/05/01 15:13:22 narten
* changed copyright header to reflect current distribution rules
- *
+ *
* Revision 4.4 87/12/18 11:45:22 narten
- * more lint cleanups. Also, the NOTREACHED comment is no longer necessary,
+ * more lint cleanups. Also, the NOTREACHED comment is no longer necessary,
* since there's now a return value there with a value. (Guy Harris)
- *
+ *
* Revision 4.3 87/10/18 10:38:42 narten
- * Updating version numbers. Changes relative to version 1.1 actually
+ * Updating version numbers. Changes relative to version 1.1 actually
* relative to 4.1
- *
+ *
* Revision 1.3 87/09/24 14:00:37 narten
- * Sources now pass through lint (if you ignore printf/sprintf/fprintf
+ * Sources now pass through lint (if you ignore printf/sprintf/fprintf
* warnings)
- *
+ *
* Revision 1.2 87/03/27 14:22:37 jenkins
* Port to suns
- *
+ *
* Revision 4.1 83/03/25 21:10:45 wft
* Only changed $Header to $Id.
- *
+ *
* Revision 3.4 82/12/04 13:24:08 wft
* Replaced getdelta() with gettree().
*
@@ -83,25 +103,21 @@ Report problems and direct all questions to:
* in that case.
*/
-
-
-/*
-#define REVTEST
-*/
-/* version REVTEST is for testing the routines that generate a sequence
- * of delta numbers needed to regenerate a given delta.
- */
-
#include "rcsbase.h"
-libId(revId, "$Id: rcsrev.c,v 5.3 1991/08/19 03:13:55 eggert Exp $")
+libId(revId, "$Id: rcsrev.c,v 1.4 1995/10/29 22:06:29 peter Exp $")
static char const *branchtip P((char const*));
-static struct hshentry *genbranch P((struct hshentry const*,char const*,unsigned,char const*,char const*,char const*,struct hshentries**));
+static char const *lookupsym P((char const*));
+static char const *normalizeyear P((char const*,char[5]));
+static struct hshentry *genbranch P((struct hshentry const*,char const*,int,char const*,char const*,char const*,struct hshentries**));
+static void absent P((char const*,int));
+static void cantfindbranch P((char const*,char const[datesize],char const*,char const*));
+static void store1 P((struct hshentries***,struct hshentry*));
- unsigned
+ int
countnumflds(s)
char const *s;
/* Given a pointer s to a dotted number (date or revision number),
@@ -109,9 +125,9 @@ countnumflds(s)
*/
{
register char const *sp;
- register unsigned count;
- if ((sp=s)==nil) return(0);
- if (*sp == '\0') return(0);
+ register int count;
+ if (!(sp=s) || !*sp)
+ return 0;
count = 1;
do {
if (*sp++ == '.') count++;
@@ -123,12 +139,12 @@ countnumflds(s)
getbranchno(revno,branchno)
char const *revno;
struct buf *branchno;
-/* Given a non-nil revision number revno, getbranchno copies the number of the branch
+/* Given a revision number revno, getbranchno copies the number of the branch
* on which revno is into branchno. If revno itself is a branch number,
* it is copied unchanged.
*/
{
- register unsigned numflds;
+ register int numflds;
register char *tp;
bufscpy(branchno, revno);
@@ -137,7 +153,7 @@ getbranchno(revno,branchno)
tp = branchno->string;
while (--numflds)
while (*tp++ != '.')
- ;
+ continue;
*(tp-1)='\0';
}
}
@@ -156,8 +172,8 @@ int cmpnum(num1, num2)
register size_t d1, d2;
register int r;
- s1=num1==nil?"":num1;
- s2=num2==nil?"":num2;
+ s1 = num1 ? num1 : "";
+ s2 = num2 ? num2 : "";
for (;;) {
/* Give precedence to shorter one. */
@@ -167,8 +183,10 @@ int cmpnum(num1, num2)
return -1;
/* Strip leading zeros, then find number of digits. */
- while (*s1=='0') ++s1; for (d1=0; isdigit(s1[d1]); d1++) ;
- while (*s2=='0') ++s2; for (d2=0; isdigit(s2[d2]); d2++) ;
+ while (*s1=='0') ++s1;
+ while (*s2=='0') ++s2;
+ for (d1=0; isdigit(*(s1+d1)); d1++) continue;
+ for (d2=0; isdigit(*(s2+d2)); d2++) continue;
/* Do not convert to integer; it might overflow! */
if (d1 != d2)
@@ -188,7 +206,7 @@ int cmpnum(num1, num2)
int cmpnumfld(num1, num2, fld)
char const *num1, *num2;
- unsigned fld;
+ int fld;
/* Compare the two dotted numbers at field fld.
* num1 and num2 must have at least fld fields.
* fld must be positive.
@@ -202,25 +220,63 @@ int cmpnumfld(num1, num2, fld)
/* skip fld-1 fields */
while (--fld) {
while (*s1++ != '.')
- ;
+ continue;
while (*s2++ != '.')
- ;
+ continue;
}
/* Now s1 and s2 point to the beginning of the respective fields */
- while (*s1=='0') ++s1; for (d1=0; isdigit(s1[d1]); d1++) ;
- while (*s2=='0') ++s2; for (d2=0; isdigit(s2[d2]); d2++) ;
+ while (*s1=='0') ++s1; for (d1=0; isdigit(*(s1+d1)); d1++) continue;
+ while (*s2=='0') ++s2; for (d2=0; isdigit(*(s2+d2)); d2++) continue;
return d1<d2 ? -1 : d1==d2 ? memcmp(s1,s2,d1) : 1;
}
+ int
+cmpdate(d1, d2)
+ char const *d1, *d2;
+/*
+* Compare the two dates. This is just like cmpnum,
+* except that for compatibility with old versions of RCS,
+* 1900 is added to dates with two-digit years.
+*/
+{
+ char year1[5], year2[5];
+ int r = cmpnumfld(normalizeyear(d1,year1), normalizeyear(d2,year2), 1);
+
+ if (r)
+ return r;
+ else {
+ while (isdigit(*d1)) d1++; d1 += *d1=='.';
+ while (isdigit(*d2)) d2++; d2 += *d2=='.';
+ return cmpnum(d1, d2);
+ }
+}
+
+ static char const *
+normalizeyear(date, year)
+ char const *date;
+ char year[5];
+{
+ if (isdigit(date[0]) && isdigit(date[1]) && !isdigit(date[2])) {
+ year[0] = '1';
+ year[1] = '9';
+ year[2] = date[0];
+ year[3] = date[1];
+ year[4] = 0;
+ return year;
+ } else
+ return date;
+}
+
+
static void
cantfindbranch(revno, date, author, state)
char const *revno, date[datesize], *author, *state;
{
- char datebuf[datesize];
+ char datebuf[datesize + zonelenmax];
- error("No revision on branch %s has%s%s%s%s%s%s.",
+ rcserror("No revision on branch %s has%s%s%s%s%s%s.",
revno,
date ? " a date before " : "",
date ? date2str(date,datebuf) : "",
@@ -234,11 +290,11 @@ cantfindbranch(revno, date, author, state)
static void
absent(revno, field)
char const *revno;
- unsigned field;
+ int field;
{
struct buf t;
bufautobegin(&t);
- error("%s %s absent", field&1?"revision":"branch",
+ rcserror("%s %s absent", field&1?"revision":"branch",
partialno(&t,revno,field)
);
bufautoend(&t);
@@ -248,7 +304,7 @@ absent(revno, field)
int
compartial(num1, num2, length)
char const *num1, *num2;
- unsigned length;
+ int length;
/* compare the first "length" fields of two dot numbers;
the omitted field is considered to be larger than any number */
@@ -267,20 +323,21 @@ compartial(num1, num2, length)
if (!*s1) return 1;
if (!*s2) return -1;
- while (*s1=='0') ++s1; for (d1=0; isdigit(s1[d1]); d1++) ;
- while (*s2=='0') ++s2; for (d2=0; isdigit(s2[d2]); d2++) ;
+ while (*s1=='0') ++s1; for (d1=0; isdigit(*(s1+d1)); d1++) continue;
+ while (*s2=='0') ++s2; for (d2=0; isdigit(*(s2+d2)); d2++) continue;
if (d1 != d2)
return d1<d2 ? -1 : 1;
if ((r = memcmp(s1, s2, d1)))
return r;
+ if (!--length)
+ return 0;
+
s1 += d1;
s2 += d1;
if (*s1 == '.') s1++;
if (*s2 == '.') s2++;
-
- if ( --length == 0 ) return 0;
}
}
@@ -288,7 +345,7 @@ compartial(num1, num2, length)
char * partialno(rev1,rev2,length)
struct buf *rev1;
char const *rev2;
- register unsigned length;
+ register int length;
/* Function: Copies length fields of revision number rev2 into rev1.
* Return rev1's string.
*/
@@ -335,20 +392,20 @@ struct hshentry * genrevs(revno,date,author,state,store)
* revision given by revno, date, author, and state, and stores pointers
* to these deltas into a list whose starting address is given by store.
* The last delta (target delta) is returned.
- * If the proper delta could not be found, nil is returned.
+ * If the proper delta could not be found, 0 is returned.
*/
{
- unsigned length;
+ int length;
register struct hshentry * next;
int result;
char const *branchnum;
struct buf t;
- char datebuf[datesize];
+ char datebuf[datesize + zonelenmax];
bufautobegin(&t);
if (!(next = Head)) {
- error("RCS file empty");
+ rcserror("RCS file empty");
goto norev;
}
@@ -360,7 +417,7 @@ struct hshentry * genrevs(revno,date,author,state,store)
store1(&store, next);
next = next->next;
if (!next) {
- error("branch number %s too low", partialno(&t,revno,1));
+ rcserror("branch number %s too low", partialno(&t,revno,1));
goto norev;
}
}
@@ -373,19 +430,19 @@ struct hshentry * genrevs(revno,date,author,state,store)
if (length<=1){
/* pick latest one on given branch */
branchnum = next->num; /* works even for empty revno*/
- while ((next!=nil) &&
- (cmpnumfld(branchnum,next->num,1)==0) &&
- !(
- (date==nil?1:(cmpnum(date,next->date)>=0)) &&
- (author==nil?1:(strcmp(author,next->author)==0)) &&
- (state ==nil?1:(strcmp(state, next->state) ==0))
- )
- )
+ while (next &&
+ cmpnumfld(branchnum,next->num,1) == 0 &&
+ (
+ (date && cmpdate(date,next->date) < 0) ||
+ (author && strcmp(author,next->author) != 0) ||
+ (state && strcmp(state,next->state) != 0)
+ )
+ )
{
store1(&store, next);
next=next->next;
}
- if ((next==nil) ||
+ if (!next ||
(cmpnumfld(branchnum,next->num,1)!=0))/*overshot*/ {
cantfindbranch(
length ? revno : partialno(&t,branchnum,1),
@@ -395,7 +452,7 @@ struct hshentry * genrevs(revno,date,author,state,store)
} else {
store1(&store, next);
}
- *store = nil;
+ *store = 0;
return next;
}
@@ -409,8 +466,8 @@ struct hshentry * genrevs(revno,date,author,state,store)
break;
}
- if ((next==nil) || (cmpnumfld(revno,next->num,1)!=0)) {
- error("revision number %s too low", partialno(&t,revno,2));
+ if (!next || cmpnumfld(revno,next->num,1) != 0) {
+ rcserror("revision number %s too low", partialno(&t,revno,2));
goto norev;
}
if ((length>2) && (result!=0)) {
@@ -424,29 +481,33 @@ struct hshentry * genrevs(revno,date,author,state,store)
if (length>2)
return genbranch(next,revno,length,date,author,state,store);
else { /* length == 2*/
- if ((date!=nil) && (cmpnum(date,next->date)<0)){
- error("Revision %s has date %s.",
+ if (date && cmpdate(date,next->date)<0) {
+ rcserror("Revision %s has date %s.",
next->num,
date2str(next->date, datebuf)
);
- return nil;
- }
- if ((author!=nil)&&(strcmp(author,next->author)!=0)) {
- error("Revision %s has author %s.",next->num,next->author);
- return nil;
+ return 0;
+ }
+ if (author && strcmp(author,next->author)!=0) {
+ rcserror("Revision %s has author %s.",
+ next->num, next->author
+ );
+ return 0;
}
- if ((state!=nil)&&(strcmp(state,next->state)!=0)) {
- error("Revision %s has state %s.",next->num,
- next->state==nil?"<empty>":next->state);
- return nil;
+ if (state && strcmp(state,next->state)!=0) {
+ rcserror("Revision %s has state %s.",
+ next->num,
+ next->state ? next->state : "<empty>"
+ );
+ return 0;
}
- *store=nil;
+ *store = 0;
return next;
}
norev:
bufautoend(&t);
- return nil;
+ return 0;
}
@@ -456,7 +517,7 @@ struct hshentry * genrevs(revno,date,author,state,store)
genbranch(bpoint, revno, length, date, author, state, store)
struct hshentry const *bpoint;
char const *revno;
- unsigned length;
+ int length;
char const *date, *author, *state;
struct hshentries **store;
/* Function: given a branchpoint, a revision number, date, author, and state,
@@ -464,15 +525,15 @@ genbranch(bpoint, revno, length, date, author, state, store)
* from the branch point on.
* Pointers to the found deltas are stored in a list beginning with store.
* revno must be on a side branch.
- * return nil on error
+ * Return 0 on error.
*/
{
- unsigned field;
+ int field;
register struct hshentry * next, * trail;
register struct branchhead const *bhead;
int result;
struct buf t;
- char datebuf[datesize];
+ char datebuf[datesize + zonelenmax];
field = 3;
bhead = bpoint->branches;
@@ -480,9 +541,11 @@ genbranch(bpoint, revno, length, date, author, state, store)
do {
if (!bhead) {
bufautobegin(&t);
- error("no side branches present for %s", partialno(&t,revno,field-1));
+ rcserror("no side branches present for %s",
+ partialno(&t,revno,field-1)
+ );
bufautoend(&t);
- return nil;
+ return 0;
}
/*find branch head*/
@@ -491,31 +554,33 @@ genbranch(bpoint, revno, length, date, author, state, store)
bhead = bhead->nextbranch;
if (!bhead) {
bufautobegin(&t);
- error("branch number %s too high",partialno(&t,revno,field));
+ rcserror("branch number %s too high",
+ partialno(&t,revno,field)
+ );
bufautoend(&t);
- return nil;
+ return 0;
}
}
if (result<0) {
absent(revno, field);
- return nil;
+ return 0;
}
next = bhead->hsh;
if (length==field) {
/* pick latest one on that branch */
- trail=nil;
- do { if ((date==nil?1:(cmpnum(date,next->date)>=0)) &&
- (author==nil?1:(strcmp(author,next->author)==0)) &&
- (state ==nil?1:(strcmp(state, next->state) ==0))
+ trail = 0;
+ do { if ((!date || cmpdate(date,next->date)>=0) &&
+ (!author || strcmp(author,next->author)==0) &&
+ (!state || strcmp(state,next->state)==0)
) trail = next;
next=next->next;
- } while (next!=nil);
+ } while (next);
- if (trail==nil) {
+ if (!trail) {
cantfindbranch(revno, date, author, state);
- return nil;
+ return 0;
} else { /* print up to last one suitable */
next = bhead->hsh;
while (next!=trail) {
@@ -524,7 +589,7 @@ genbranch(bpoint, revno, length, date, author, state, store)
}
store1(&store, next);
}
- *store = nil;
+ *store = 0;
return next;
}
@@ -533,44 +598,49 @@ genbranch(bpoint, revno, length, date, author, state, store)
/* check low */
if (cmpnumfld(revno,next->num,field+1)<0) {
bufautobegin(&t);
- error("revision number %s too low", partialno(&t,revno,field+1));
+ rcserror("revision number %s too low",
+ partialno(&t,revno,field+1)
+ );
bufautoend(&t);
- return(nil);
+ return 0;
}
do {
store1(&store, next);
trail = next;
next = next->next;
- } while ((next!=nil) &&
- (cmpnumfld(revno,next->num,field+1) >=0));
+ } while (next && cmpnumfld(revno,next->num,field+1)>=0);
if ((length>field+1) && /*need exact hit */
(cmpnumfld(revno,trail->num,field+1) !=0)){
absent(revno, field+1);
- return(nil);
+ return 0;
}
if (length == field+1) {
- if ((date!=nil) && (cmpnum(date,trail->date)<0)){
- error("Revision %s has date %s.",
+ if (date && cmpdate(date,trail->date)<0) {
+ rcserror("Revision %s has date %s.",
trail->num,
date2str(trail->date, datebuf)
);
- return nil;
+ return 0;
}
- if ((author!=nil)&&(strcmp(author,trail->author)!=0)) {
- error("Revision %s has author %s.",trail->num,trail->author);
- return nil;
+ if (author && strcmp(author,trail->author)!=0) {
+ rcserror("Revision %s has author %s.",
+ trail->num, trail->author
+ );
+ return 0;
}
- if ((state!=nil)&&(strcmp(state,trail->state)!=0)) {
- error("Revision %s has state %s.",trail->num,
- trail->state==nil?"<empty>":trail->state);
- return nil;
+ if (state && strcmp(state,trail->state)!=0) {
+ rcserror("Revision %s has state %s.",
+ trail->num,
+ trail->state ? trail->state : "<empty>"
+ );
+ return 0;
}
}
bhead = trail->branches;
} while ((field+=2) <= length);
- * store = nil;
+ *store = 0;
return trail;
}
@@ -580,17 +650,14 @@ lookupsym(id)
char const *id;
/* Function: looks up id in the list of symbolic names starting
* with pointer SYMBOLS, and returns a pointer to the corresponding
- * revision number. Returns nil if not present.
+ * revision number. Return 0 if not present.
*/
{
register struct assoc const *next;
- next = Symbols;
- while (next!=nil) {
+ for (next = Symbols; next; next = next->nextassoc)
if (strcmp(id, next->symbol)==0)
return next->num;
- else next=next->nextassoc;
- }
- return nil;
+ return 0;
}
int expandsym(source, target)
@@ -617,13 +684,12 @@ fexpandsym(source, target, fp)
register char const *sp, *bp;
register char *tp;
char const *tlim;
- register enum tokens d;
- unsigned dots;
+ int dots;
sp = source;
bufalloc(target, 1);
tp = target->string;
- if (!sp || !*sp) { /*accept nil pointer as a legal value*/
+ if (!sp || !*sp) { /* Accept 0 pointer as a legal value. */
*tp='\0';
return true;
}
@@ -631,7 +697,7 @@ fexpandsym(source, target, fp)
if (!getoldkeys(fp))
return false;
if (!*prevrev.string) {
- error("working file lacks revision number");
+ workerror("working file lacks revision number");
return false;
}
bufscpy(target, prevrev.string);
@@ -641,72 +707,122 @@ fexpandsym(source, target, fp)
dots = 0;
for (;;) {
- switch (ctab[(unsigned char)*sp]) {
- case DIGIT:
- while (*sp=='0' && isdigit(sp[1]))
- /* skip leading zeroes */
- sp++;
- do {
- if (tlim <= tp)
- tp = bufenlarge(target, &tlim);
- } while (isdigit(*tp++ = *sp++));
- --sp;
- tp[-1] = '\0';
- break;
+ register char *p = tp;
+ size_t s = tp - target->string;
+ int id = false;
+ for (;;) {
+ switch (ctab[(unsigned char)*sp]) {
+ case IDCHAR:
+ case LETTER:
+ case Letter:
+ id = true;
+ /* fall into */
+ case DIGIT:
+ if (tlim <= p)
+ p = bufenlarge(target, &tlim);
+ *p++ = *sp++;
+ continue;
+
+ default:
+ break;
+ }
+ break;
+ }
+ if (tlim <= p)
+ p = bufenlarge(target, &tlim);
+ *p = 0;
+ tp = target->string + s;
- case LETTER:
- case Letter:
- {
- register char *p = tp;
- register size_t s = tp - target->string;
- do {
- if (tlim <= p)
- p = bufenlarge(target, &tlim);
- *p++ = *sp++;
- } while ((d=ctab[(unsigned char)*sp])==LETTER ||
- d==Letter || d==DIGIT ||
- (d==IDCHAR));
- if (tlim <= p)
- p = bufenlarge(target, &tlim);
- *p = 0;
- tp = target->string + s;
- }
+ if (id) {
bp = lookupsym(tp);
- if (bp==nil) {
- error("Symbolic number %s is undefined.", tp);
+ if (!bp) {
+ rcserror("Symbolic name `%s' is undefined.",tp);
return false;
}
- do {
- if (tlim <= tp)
- tp = bufenlarge(target, &tlim);
- } while ((*tp++ = *bp++));
- break;
+ } else {
+ /* skip leading zeros */
+ for (bp = tp; *bp=='0' && isdigit(bp[1]); bp++)
+ continue;
+
+ if (!*bp)
+ if (s || *sp!='.')
+ break;
+ else {
+ /* Insert default branch before initial `.'. */
+ char const *b;
+ if (Dbranch)
+ b = Dbranch;
+ else if (Head)
+ b = Head->num;
+ else
+ break;
+ getbranchno(b, target);
+ bp = tp = target->string;
+ tlim = tp + target->size;
+ }
+ }
+
+ while ((*tp++ = *bp++))
+ if (tlim <= tp)
+ tp = bufenlarge(target, &tlim);
- default:
- goto improper;
- }
switch (*sp++) {
- case '\0': return true;
- case '.': break;
- default: goto improper;
- }
- if (!*sp) {
- if (dots & 1)
- goto improper;
- if (!(bp = branchtip(target->string)))
- return false;
- bufscpy(target, bp);
+ case '\0':
return true;
+
+ case '.':
+ if (!*sp) {
+ if (dots & 1)
+ break;
+ if (!(bp = branchtip(target->string)))
+ return false;
+ bufscpy(target, bp);
+ return true;
+ }
+ ++dots;
+ tp[-1] = '.';
+ continue;
}
- ++dots;
- tp[-1] = '.';
+ break;
}
- improper:
- error("improper revision number: %s", source);
+ rcserror("improper revision number: %s", source);
return false;
}
+ char const *
+namedrev(name, delta)
+ char const *name;
+ struct hshentry *delta;
+/* Yield NAME if it names DELTA, 0 otherwise. */
+{
+ if (name) {
+ char const *id = 0, *p, *val;
+ for (p = name; ; p++)
+ switch (ctab[(unsigned char)*p]) {
+ case IDCHAR:
+ case LETTER:
+ case Letter:
+ id = name;
+ break;
+
+ case DIGIT:
+ break;
+
+ case UNKN:
+ if (!*p && id &&
+ (val = lookupsym(id)) &&
+ strcmp(val, delta->num) == 0
+ )
+ return id;
+ /* fall into */
+ default:
+ return 0;
+ }
+ }
+ return 0;
+}
+
static char const *
branchtip(branch)
char const *branch;
@@ -728,6 +844,11 @@ tiprev()
#ifdef REVTEST
+/*
+* Test the routines that generate a sequence of delta numbers
+* needed to regenerate a given delta.
+*/
+
char const cmdid[] = "revtest";
int
@@ -761,20 +882,20 @@ int argc; char * argv[];
/* all output goes to stderr, to have diagnostics and */
/* errors in sequence. */
aputs("\nEnter revision number or <return> or '.': ",stderr);
- if (!gets(symrevno)) break;
+ if (!fgets(symrevno, 100, stdin)) break;
if (*symrevno == '.') break;
aprintf(stderr,"%s;\n",symrevno);
expandsym(symrevno,&numricrevno);
aprintf(stderr,"expanded number: %s; ",numricrevno.string);
aprintf(stderr,"Date: ");
- gets(date); aprintf(stderr,"%s; ",date);
+ fgets(date, 20, stdin); aprintf(stderr,"%s; ",date);
aprintf(stderr,"Author: ");
- gets(author); aprintf(stderr,"%s; ",author);
+ fgets(author, 20, stdin); aprintf(stderr,"%s; ",author);
aprintf(stderr,"State: ");
- gets(state); aprintf(stderr, "%s;\n", state);
- target = genrevs(numricrevno.string, *date?date:(char *)nil, *author?author:(char *)nil,
- *state?state:(char*)nil, &gendeltas);
- if (target!=nil) {
+ fgets(state, 20, stdin); aprintf(stderr, "%s;\n", state);
+ target = genrevs(numricrevno.string, *date?date:(char *)0, *author?author:(char *)0,
+ *state?state:(char*)0, &gendeltas);
+ if (target) {
while (gendeltas) {
aprintf(stderr,"%s\n",gendeltas->first->num);
gendeltas = gendeltas->next;
@@ -785,6 +906,6 @@ int argc; char * argv[];
exitmain(EXIT_SUCCESS);
}
-exiting void exiterr() { _exit(EXIT_FAILURE); }
+void exiterr() { _exit(EXIT_FAILURE); }
#endif
diff --git a/gnu/usr.bin/rcs/lib/rcssyn.c b/gnu/usr.bin/rcs/lib/rcssyn.c
index 31086c2..35772fe 100644
--- a/gnu/usr.bin/rcs/lib/rcssyn.c
+++ b/gnu/usr.bin/rcs/lib/rcssyn.c
@@ -1,16 +1,15 @@
-/*
- * RCS file input
- */
-/*********************************************************************************
+/* RCS file syntactic analysis */
+
+/******************************************************************************
* Syntax Analysis.
* Keyword table
* Testprogram: define SYNTEST
* Compatibility with Release 2: define COMPAT2=1
- *********************************************************************************
+ ******************************************************************************
*/
-/* Copyright (C) 1982, 1988, 1989 Walter Tichy
- Copyright 1990, 1991 by Paul Eggert
+/* Copyright 1982, 1988, 1989 Walter Tichy
+ Copyright 1990, 1991, 1992, 1993, 1994, 1995 Paul Eggert
Distributed under license by the Free Software Foundation, Inc.
This file is part of RCS.
@@ -26,8 +25,9 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
-along with RCS; see the file COPYING. If not, write to
-the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+along with RCS; see the file COPYING.
+If not, write to the Free Software Foundation,
+59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
Report problems and direct all questions to:
@@ -35,8 +35,31 @@ Report problems and direct all questions to:
*/
-
-/* $Log: rcssyn.c,v $
+/*
+ * Revision 5.15 1995/06/16 06:19:24 eggert
+ * Update FSF address.
+ *
+ * Revision 5.14 1995/06/01 16:23:43 eggert
+ * (expand_names): Add "b" for -kb.
+ * (getdelta): Don't strip leading "19" from MKS RCS dates; see cmpdate.
+ *
+ * Revision 5.13 1994/03/20 04:52:58 eggert
+ * Remove lint.
+ *
+ * Revision 5.12 1993/11/03 17:42:27 eggert
+ * Parse MKS RCS dates; ignore \r in diff control lines.
+ * Don't discard ignored phrases. Improve quality of diagnostics.
+ *
+ * Revision 5.11 1992/07/28 16:12:44 eggert
+ * Avoid `unsigned'. Statement macro names now end in _.
+ *
+ * Revision 5.10 1992/01/24 18:44:19 eggert
+ * Move put routines to rcsgen.c.
+ *
+ * Revision 5.9 1992/01/06 02:42:34 eggert
+ * ULONG_MAX/10 -> ULONG_MAX_OVER_10
+ * while (E) ; -> while (E) continue;
+ *
* Revision 5.8 1991/08/19 03:13:55 eggert
* Tune.
*
@@ -78,27 +101,27 @@ Report problems and direct all questions to:
*
* Revision 4.6 89/05/01 15:13:32 narten
* changed copyright header to reflect current distribution rules
- *
+ *
* Revision 4.5 88/08/09 19:13:21 eggert
* Allow cc -R; remove lint.
- *
+ *
* Revision 4.4 87/12/18 11:46:16 narten
* more lint cleanups (Guy Harris)
- *
+ *
* Revision 4.3 87/10/18 10:39:36 narten
* Updating version numbers. Changes relative to 1.1 actually relative to
* 4.1
- *
+ *
* Revision 1.3 87/09/24 14:00:49 narten
- * Sources now pass through lint (if you ignore printf/sprintf/fprintf
+ * Sources now pass through lint (if you ignore printf/sprintf/fprintf
* warnings)
- *
+ *
* Revision 1.2 87/03/27 14:22:40 jenkins
* Port to suns
- *
+ *
* Revision 4.1 83/03/28 11:38:49 wft
* Added parsing and printing of default branch.
- *
+ *
* Revision 3.6 83/01/15 17:46:50 wft
* Changed readdelta() to initialize selector and log-pointer.
* Changed puttree to check for selector==DELETE; putdtext() uses DELNUMFORM.
@@ -127,54 +150,55 @@ Report problems and direct all questions to:
* generates files of release 3 format. Need not be defined if no
* old RCS files generated with release 2 exist.
*/
-/* version SYNTEST inputs a RCS file and then prints out its internal
- * data structures.
-*/
#include "rcsbase.h"
-libId(synId, "$Id: rcssyn.c,v 5.8 1991/08/19 03:13:55 eggert Exp $")
+libId(synId, "$Id: rcssyn.c,v 1.3 1995/10/28 21:49:53 peter Exp $")
-/* forward */
static char const *getkeyval P((char const*,enum tokens,int));
+static int getdelta P((void));
static int strn2expmode P((char const*,size_t));
+static struct hshentry *getdnum P((void));
+static void badDiffOutput P((char const*)) exiting;
+static void diffLineNumberTooLarge P((char const*)) exiting;
+static void getsemi P((char const*));
/* keyword table */
char const
- Kdesc[] = "desc",
- Klog[] = "log",
- Ktext[] = "text";
-
-static char const
Kaccess[] = "access",
Kauthor[] = "author",
Kbranch[] = "branch",
- K_branches[]= "branches",
Kcomment[] = "comment",
Kdate[] = "date",
+ Kdesc[] = "desc",
Kexpand[] = "expand",
Khead[] = "head",
Klocks[] = "locks",
+ Klog[] = "log",
Knext[] = "next",
Kstate[] = "state",
Kstrict[] = "strict",
+ Ksymbols[] = "symbols",
+ Ktext[] = "text";
+
+static char const
#if COMPAT2
Ksuffix[] = "suffix",
#endif
- Ksymbols[] = "symbols";
+ K_branches[]= "branches";
static struct buf Commleader;
-static struct cbuf Ignored;
struct cbuf Comment;
+struct cbuf Ignored;
struct access * AccessList;
struct assoc * Symbols;
-struct lock * Locks;
+struct rcslock *Locks;
int Expand;
int StrictLocks;
struct hshentry * Head;
char const * Dbranch;
-unsigned TotalDeltas;
+int TotalDeltas;
static void
@@ -204,11 +228,11 @@ getadmin()
register char const *id;
struct access * newaccess;
struct assoc * newassoc;
- struct lock * newlock;
+ struct rcslock *newlock;
struct hshentry * delta;
struct access **LastAccess;
struct assoc **LastSymbol;
- struct lock **LastLock;
+ struct rcslock **LastLock;
struct buf b;
struct cbuf cb;
@@ -218,7 +242,7 @@ getadmin()
Head = getdnum();
getsemi(Khead);
- Dbranch = nil;
+ Dbranch = 0;
if (getkeyopt(Kbranch)) {
if ((delta = getnum()))
Dbranch = delta->num;
@@ -240,18 +264,18 @@ getadmin()
getkey(Kaccess);
LastAccess = &AccessList;
- while (id=getid()) {
+ while ((id = getid())) {
newaccess = ftalloc(struct access);
newaccess->login = id;
*LastAccess = newaccess;
LastAccess = &newaccess->nextaccess;
}
- *LastAccess = nil;
+ *LastAccess = 0;
getsemi(Kaccess);
getkey(Ksymbols);
LastSymbol = &Symbols;
- while (id = getid()) {
+ while ((id = getid())) {
if (!getlex(COLON))
fatserror("missing ':' in symbolic name definition");
if (!(delta=getnum())) {
@@ -264,31 +288,31 @@ getadmin()
LastSymbol = &newassoc->nextassoc;
}
}
- *LastSymbol = nil;
+ *LastSymbol = 0;
getsemi(Ksymbols);
getkey(Klocks);
LastLock = &Locks;
- while (id = getid()) {
+ while ((id = getid())) {
if (!getlex(COLON))
fatserror("missing ':' in lock");
if (!(delta=getdnum())) {
fatserror("missing number in lock");
} else { /*add new pair to lock list*/
- newlock = ftalloc(struct lock);
+ newlock = ftalloc(struct rcslock);
newlock->login=id;
newlock->delta=delta;
*LastLock = newlock;
LastLock = &newlock->nextlock;
}
}
- *LastLock = nil;
+ *LastLock = 0;
getsemi(Klocks);
if ((StrictLocks = getkeyopt(Kstrict)))
getsemi(Kstrict);
- Comment.size = 0;
+ clear_buf(&Comment);
if (getkeyopt(Kcomment)) {
if (nexttok==STRING) {
Comment = savestring(&Commleader);
@@ -316,7 +340,7 @@ getadmin()
char const *const expand_names[] = {
/* These must agree with *_EXPAND in rcsbase.h. */
- "kv","kvl","k","v","o",
+ "kv", "kvl", "k", "v", "o", "b",
0
};
@@ -343,20 +367,30 @@ strn2expmode(s, n)
void
-ignorephrase()
-/* Ignore a phrase introduced by a later version of RCS. */
+ignorephrases(key)
+ const char *key;
+/*
+* Ignore a series of phrases that do not start with KEY.
+* Stop when the next phrase starts with a token that is not an identifier,
+* or is KEY.
+*/
{
- warnignore();
- hshenter=false;
for (;;) {
- switch (nexttok) {
- case SEMI: hshenter=true; nextlex(); return;
- case ID:
- case NUM: ffree1(NextString); break;
- case STRING: readstring(); break;
- default: break;
- }
- nextlex();
+ nextlex();
+ if (nexttok != ID || strcmp(NextString,key) == 0)
+ break;
+ warnignore();
+ hshenter=false;
+ for (;; nextlex()) {
+ switch (nexttok) {
+ case SEMI: hshenter=true; break;
+ case ID:
+ case NUM: ffree1(NextString); continue;
+ case STRING: readstring(); continue;
+ default: continue;
+ }
+ break;
+ }
}
}
@@ -374,7 +408,7 @@ getdelta()
return false;
hshenter = false; /*Don't enter dates into hashtable*/
- Delta->date = getkeyval(Kdate, NUM, false);
+ Delta->date = getkeyval(Kdate, NUM, false);
hshenter=true; /*reset hshenter for revision numbers.*/
Delta->author = getkeyval(Kauthor, ID, false);
@@ -389,13 +423,13 @@ getdelta()
*LastBranch = NewBranch;
LastBranch = &NewBranch->nextbranch;
}
- *LastBranch = nil;
+ *LastBranch = 0;
getsemi(K_branches);
getkey(Knext);
Delta->next = num = getdnum();
getsemi(Knext);
- Delta->lockedby = nil;
+ Delta->lockedby = 0;
Delta->log.string = 0;
Delta->selector = true;
Delta->ig = getphrases(Kdesc);
@@ -410,9 +444,10 @@ gettree()
* updates the lockedby fields.
*/
{
- struct lock const *currlock;
+ struct rcslock const *currlock;
- while (getdelta());
+ while (getdelta())
+ continue;
currlock=Locks;
while (currlock) {
currlock->delta->lockedby = currlock->login;
@@ -453,7 +488,7 @@ getkeyval(keyword, token, optional)
* the actual character string of <id> or <num> is returned.
*/
{
- register char const *val = nil;
+ register char const *val = 0;
getkey(keyword);
if (nexttok==token) {
@@ -468,220 +503,10 @@ getkeyval(keyword, token, optional)
}
-
-
void
-putadmin(fout)
-register FILE * fout;
-/* Function: Print the <admin> node read with getadmin() to file fout.
- * Assumption: Variables AccessList, Symbols, Locks, StrictLocks,
- * and Head have been set.
- */
-{
- struct assoc const *curassoc;
- struct lock const *curlock;
- struct access const *curaccess;
-
- aprintf(fout, "%s\t%s;\n", Khead, Head?Head->num:"");
- if (Dbranch && VERSION(4)<=RCSversion)
- aprintf(fout, "%s\t%s;\n", Kbranch, Dbranch);
-
- aputs(Kaccess, fout);
- curaccess = AccessList;
- while (curaccess) {
- aprintf(fout, "\n\t%s", curaccess->login);
- curaccess = curaccess->nextaccess;
- }
- aprintf(fout, ";\n%s", Ksymbols);
- curassoc = Symbols;
- while (curassoc) {
- aprintf(fout, "\n\t%s:%s", curassoc->symbol, curassoc->num);
- curassoc = curassoc->nextassoc;
- }
- aprintf(fout, ";\n%s", Klocks);
- curlock = Locks;
- while (curlock) {
- aprintf(fout, "\n\t%s:%s", curlock->login, curlock->delta->num);
- curlock = curlock->nextlock;
- }
- if (StrictLocks) aprintf(fout, "; %s", Kstrict);
- aprintf(fout, ";\n");
- if (Comment.size) {
- aprintf(fout, "%s\t", Kcomment);
- putstring(fout, true, Comment, false);
- aprintf(fout, ";\n");
- }
- if (Expand != KEYVAL_EXPAND)
- aprintf(fout, "%s\t%c%s%c;\n",
- Kexpand, SDELIM, expand_names[Expand], SDELIM
- );
- awrite(Ignored.string, Ignored.size, fout);
- aputc('\n', fout);
-}
-
-
-
-
- static void
-putdelta(node,fout)
-register struct hshentry const *node;
-register FILE * fout;
-/* Function: prints a <delta> node to fout;
- */
-{
- struct branchhead const *nextbranch;
-
- if (node == nil) return;
-
- aprintf(fout, "\n%s\n%s\t%s;\t%s %s;\t%s %s;\nbranches",
- node->num,
- Kdate, node->date,
- Kauthor, node->author,
- Kstate, node->state?node->state:""
- );
- nextbranch = node->branches;
- while (nextbranch) {
- aprintf(fout, "\n\t%s", nextbranch->hsh->num);
- nextbranch = nextbranch->nextbranch;
- }
-
- aprintf(fout, ";\n%s\t%s;\n", Knext, node->next?node->next->num:"");
- awrite(node->ig.string, node->ig.size, fout);
-}
-
-
-
-
- void
-puttree(root,fout)
-struct hshentry const *root;
-register FILE * fout;
-/* Function: prints the delta tree in preorder to fout, starting with root.
- */
-{
- struct branchhead const *nextbranch;
-
- if (root==nil) return;
-
- if (root->selector)
- putdelta(root,fout);
-
- puttree(root->next,fout);
-
- nextbranch = root->branches;
- while (nextbranch) {
- puttree(nextbranch->hsh,fout);
- nextbranch = nextbranch->nextbranch;
- }
-}
-
-
- static exiting void
unexpected_EOF()
{
- faterror("unexpected EOF in diff output");
-}
-
-int putdtext(num,log,srcfilename,fout,diffmt)
- char const *num, *srcfilename;
- struct cbuf log;
- FILE *fout;
- int diffmt;
-/* Function: write a deltatext-node to fout.
- * num points to the deltanumber, log to the logmessage, and
- * sourcefile contains the text. Doubles up all SDELIMs in both the
- * log and the text; Makes sure the log message ends in \n.
- * returns false on error.
- * If diffmt is true, also checks that text is valid diff -n output.
- */
-{
- RILE *fin;
- int result;
- if (!(fin = Iopen(srcfilename, "r", (struct stat*)0))) {
- eerror(srcfilename);
- return false;
- }
- result = putdftext(num,log,fin,fout,diffmt);
- Ifclose(fin);
- return result;
-}
-
- void
-putstring(out, delim, s, log)
- register FILE *out;
- struct cbuf s;
- int delim, log;
-/*
- * Output to OUT one SDELIM if DELIM, then the string S with SDELIMs doubled.
- * If LOG is set then S is a log string; append a newline if S is nonempty.
- */
-{
- register char const *sp;
- register size_t ss;
-
- if (delim)
- aputc(SDELIM, out);
- sp = s.string;
- for (ss = s.size; ss; --ss) {
- if (*sp == SDELIM)
- aputc(SDELIM, out);
- aputc(*sp++, out);
- }
- if (s.size && log)
- aputc('\n', out);
- aputc(SDELIM, out);
-}
-
- int
-putdftext(num,log,finfile,foutfile,diffmt)
- char const *num;
- struct cbuf log;
- RILE *finfile;
- FILE *foutfile;
- int diffmt;
-/* like putdtext(), except the source file is already open */
-{
- declarecache;
- register FILE *fout;
- register int c;
- register RILE *fin;
- int ed;
- struct diffcmd dc;
-
- fout = foutfile;
- aprintf(fout,DELNUMFORM,num,Klog);
- /* put log */
- putstring(fout, true, log, true);
- /* put text */
- aprintf(fout, "\n%s\n%c", Ktext, SDELIM);
- fin = finfile;
- setupcache(fin);
- if (!diffmt) {
- /* Copy the file */
- cache(fin);
- for (;;) {
- cachegeteof(c, break;);
- if (c==SDELIM) aputc(SDELIM,fout); /*double up SDELIM*/
- aputc(c,fout);
- }
- } else {
- initdiffcmd(&dc);
- while (0 <= (ed = getdiffcmd(fin,false,fout,&dc)))
- if (ed) {
- cache(fin);
- while (dc.nlines--)
- do {
- cachegeteof(c, { if (!dc.nlines) goto OK_EOF; unexpected_EOF(); });
- if (c == SDELIM)
- aputc(SDELIM,fout);
- aputc(c,fout);
- } while (c != '\n');
- uncache(fin);
- }
- }
- OK_EOF:
- aprintf(fout, "%c\n", SDELIM);
- return true;
+ rcsfaterror("unexpected EOF in diff output");
}
void
@@ -693,18 +518,18 @@ initdiffcmd(dc)
dc->dafter = 0;
}
- static exiting void
+ static void
badDiffOutput(buf)
char const *buf;
{
- faterror("bad diff output line: %s", buf);
+ rcsfaterror("bad diff output line: %s", buf);
}
- static exiting void
+ static void
diffLineNumberTooLarge(buf)
char const *buf;
{
- faterror("diff line number too large: %s", buf);
+ rcsfaterror("diff line number too large: %s", buf);
}
int
@@ -726,16 +551,16 @@ getdiffcmd(finfile, delimiter, foutfile, dc)
register FILE *fout;
register char *p;
register RILE *fin;
- unsigned long line1, nlines, t;
+ long line1, nlines, t;
char buf[BUFSIZ];
fin = finfile;
fout = foutfile;
setupcache(fin); cache(fin);
- cachegeteof(c, { if (delimiter) unexpected_EOF(); return -1; } );
+ cachegeteof_(c, { if (delimiter) unexpected_EOF(); return -1; } )
if (delimiter) {
if (c==SDELIM) {
- cacheget(c);
+ cacheget_(c)
if (c==SDELIM) {
buf[0] = c;
buf[1] = 0;
@@ -751,23 +576,22 @@ getdiffcmd(finfile, delimiter, foutfile, dc)
p = buf;
do {
if (buf+BUFSIZ-2 <= p) {
- faterror("diff output command line too long");
+ rcsfaterror("diff output command line too long");
}
*p++ = c;
- cachegeteof(c, unexpected_EOF();) ;
+ cachegeteof_(c, unexpected_EOF();)
} while (c != '\n');
uncache(fin);
if (delimiter)
++rcsline;
*p = '\0';
for (p = buf+1; (c = *p++) == ' '; )
- ;
+ continue;
line1 = 0;
while (isdigit(c)) {
- t = line1 * 10;
if (
- ULONG_MAX/10 < line1 ||
- (line1 = t + (c - '0')) < t
+ LONG_MAX/10 < line1 ||
+ (t = line1 * 10, (line1 = t + (c - '0')) < t)
)
diffLineNumberTooLarge(buf);
c = *p++;
@@ -776,14 +600,15 @@ getdiffcmd(finfile, delimiter, foutfile, dc)
c = *p++;
nlines = 0;
while (isdigit(c)) {
- t = nlines * 10;
if (
- ULONG_MAX/10 < nlines ||
- (nlines = t + (c - '0')) < t
+ LONG_MAX/10 < nlines ||
+ (t = nlines * 10, (nlines = t + (c - '0')) < t)
)
diffLineNumberTooLarge(buf);
c = *p++;
}
+ if (c == '\r')
+ c = *p++;
if (c || !nlines) {
badDiffOutput(buf);
}
@@ -792,13 +617,13 @@ getdiffcmd(finfile, delimiter, foutfile, dc)
switch (buf[0]) {
case 'a':
if (line1 < dc->adprev) {
- faterror("backward insertion in diff output: %s", buf);
+ rcsfaterror("backward insertion in diff output: %s", buf);
}
dc->adprev = line1 + 1;
break;
case 'd':
if (line1 < dc->adprev || line1 < dc->dafter) {
- faterror("backward deletion in diff output: %s", buf);
+ rcsfaterror("backward deletion in diff output: %s", buf);
}
dc->adprev = line1;
dc->dafter = line1 + nlines;
@@ -818,6 +643,8 @@ getdiffcmd(finfile, delimiter, foutfile, dc)
#ifdef SYNTEST
+/* Input an RCS file and print its internal data structures. */
+
char const cmdid[] = "syntest";
int
@@ -834,10 +661,10 @@ int argc; char * argv[];
}
Lexinit();
getadmin();
- putadmin(stdout);
+ fdlock = STDOUT_FILENO;
+ putadmin();
gettree();
- puttree(Head,stdout);
getdesc(true);
@@ -849,9 +676,6 @@ int argc; char * argv[];
exitmain(EXIT_SUCCESS);
}
-
-exiting void exiterr() { _exit(EXIT_FAILURE); }
-
+void exiterr() { _exit(EXIT_FAILURE); }
#endif
-
diff --git a/gnu/usr.bin/rcs/lib/rcstime.c b/gnu/usr.bin/rcs/lib/rcstime.c
new file mode 100644
index 0000000..a49a857
--- /dev/null
+++ b/gnu/usr.bin/rcs/lib/rcstime.c
@@ -0,0 +1,191 @@
+/* Convert between RCS time format and Posix and/or C formats. */
+
+/* Copyright 1992, 1993, 1994, 1995 Paul Eggert
+ Distributed under license by the Free Software Foundation, Inc.
+
+This file is part of RCS.
+
+RCS is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+RCS is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with RCS; see the file COPYING.
+If not, write to the Free Software Foundation,
+59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+Report problems and direct all questions to:
+
+ rcs-bugs@cs.purdue.edu
+
+*/
+
+#include "rcsbase.h"
+#include "partime.h"
+#include "maketime.h"
+
+libId(rcstimeId, "$Id: rcstime.c,v 1.4 1995/06/16 06:19:24 eggert Exp $")
+
+static long zone_offset; /* seconds east of UTC, or TM_LOCAL_ZONE */
+static int use_zone_offset; /* if zero, use UTC without zone indication */
+
+/*
+* Convert Unix time to RCS format.
+* For compatibility with older versions of RCS,
+* dates from 1900 through 1999 are stored without the leading "19".
+*/
+ void
+time2date(unixtime,date)
+ time_t unixtime;
+ char date[datesize];
+{
+ register struct tm const *tm = time2tm(unixtime, RCSversion<VERSION(5));
+ VOID sprintf(date,
+# if has_printf_dot
+ "%.2d.%.2d.%.2d.%.2d.%.2d.%.2d",
+# else
+ "%02d.%02d.%02d.%02d.%02d.%02d",
+# endif
+ tm->tm_year + ((unsigned)tm->tm_year < 100 ? 0 : 1900),
+ tm->tm_mon+1, tm->tm_mday,
+ tm->tm_hour, tm->tm_min, tm->tm_sec
+ );
+}
+
+/* Like str2time, except die if an error was found. */
+static time_t str2time_checked P((char const*,time_t,long));
+ static time_t
+str2time_checked(source, default_time, default_zone)
+ char const *source;
+ time_t default_time;
+ long default_zone;
+{
+ time_t t = str2time(source, default_time, default_zone);
+ if (t == -1)
+ faterror("unknown date/time: %s", source);
+ return t;
+}
+
+/*
+* Parse a free-format date in SOURCE, convert it
+* into RCS internal format, and store the result into TARGET.
+*/
+ void
+str2date(source, target)
+ char const *source;
+ char target[datesize];
+{
+ time2date(
+ str2time_checked(source, now(),
+ use_zone_offset ? zone_offset
+ : RCSversion<VERSION(5) ? TM_LOCAL_ZONE
+ : 0
+ ),
+ target
+ );
+}
+
+/* Convert an RCS internal format date to time_t. */
+ time_t
+date2time(source)
+ char const source[datesize];
+{
+ char s[datesize + zonelenmax];
+ return str2time_checked(date2str(source, s), (time_t)0, 0);
+}
+
+
+/* Set the time zone for date2str output. */
+ void
+zone_set(s)
+ char const *s;
+{
+ if ((use_zone_offset = *s)) {
+ long zone;
+ char const *zonetail = parzone(s, &zone);
+ if (!zonetail || *zonetail)
+ error("%s: not a known time zone", s);
+ else
+ zone_offset = zone;
+ }
+}
+
+
+/*
+* Format a user-readable form of the RCS format DATE into the buffer DATEBUF.
+* Yield DATEBUF.
+*/
+ char const *
+date2str(date, datebuf)
+ char const date[datesize];
+ char datebuf[datesize + zonelenmax];
+{
+ register char const *p = date;
+
+ while (*p++ != '.')
+ continue;
+ if (!use_zone_offset)
+ VOID sprintf(datebuf,
+ "19%.*s/%.2s/%.2s %.2s:%.2s:%s"
+ + (date[2]=='.' && VERSION(5)<=RCSversion ? 0 : 2),
+ (int)(p-date-1), date,
+ p, p+3, p+6, p+9, p+12
+ );
+ else {
+ struct tm t;
+ struct tm const *z;
+ int non_hour;
+ long zone;
+ char c;
+
+ t.tm_year = atoi(date) - (date[2]=='.' ? 0 : 1900);
+ t.tm_mon = atoi(p) - 1;
+ t.tm_mday = atoi(p+3);
+ t.tm_hour = atoi(p+6);
+ t.tm_min = atoi(p+9);
+ t.tm_sec = atoi(p+12);
+ t.tm_wday = -1;
+ zone = zone_offset;
+ if (zone == TM_LOCAL_ZONE) {
+ time_t u = tm2time(&t, 0), d;
+ z = localtime(&u);
+ d = difftm(z, &t);
+ zone = (time_t)-1 < 0 || d < -d ? d : -(long)-d;
+ } else {
+ adjzone(&t, zone);
+ z = &t;
+ }
+ c = '+';
+ if (zone < 0) {
+ zone = -zone;
+ c = '-';
+ }
+ VOID sprintf(datebuf,
+# if has_printf_dot
+ "%.2d-%.2d-%.2d %.2d:%.2d:%.2d%c%.2d",
+# else
+ "%02d-%02d-%02d %02d:%02d:%02d%c%02d",
+# endif
+ z->tm_year + 1900,
+ z->tm_mon + 1, z->tm_mday, z->tm_hour, z->tm_min, z->tm_sec,
+ c, (int) (zone / (60*60))
+ );
+ if ((non_hour = zone % (60*60))) {
+# if has_printf_dot
+ static char const fmt[] = ":%.2d";
+# else
+ static char const fmt[] = ":%02d";
+# endif
+ VOID sprintf(datebuf + strlen(datebuf), fmt, non_hour / 60);
+ if ((non_hour %= 60))
+ VOID sprintf(datebuf + strlen(datebuf), fmt, non_hour);
+ }
+ }
+ return datebuf;
+}
diff --git a/gnu/usr.bin/rcs/lib/rcsutil.c b/gnu/usr.bin/rcs/lib/rcsutil.c
index c523ccf1..455f054 100644
--- a/gnu/usr.bin/rcs/lib/rcsutil.c
+++ b/gnu/usr.bin/rcs/lib/rcsutil.c
@@ -1,9 +1,7 @@
-/*
- * RCS utilities
- */
+/* RCS utility functions */
-/* Copyright (C) 1982, 1988, 1989 Walter Tichy
- Copyright 1990, 1991 by Paul Eggert
+/* Copyright 1982, 1988, 1989 Walter Tichy
+ Copyright 1990, 1991, 1992, 1993, 1994, 1995 Paul Eggert
Distributed under license by the Free Software Foundation, Inc.
This file is part of RCS.
@@ -19,8 +17,9 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
-along with RCS; see the file COPYING. If not, write to
-the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+along with RCS; see the file COPYING.
+If not, write to the Free Software Foundation,
+59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
Report problems and direct all questions to:
@@ -31,7 +30,58 @@ Report problems and direct all questions to:
-/* $Log: rcsutil.c,v $
+/*
+ * Revision 5.20 1995/06/16 06:19:24 eggert
+ * (catchsig): Remove `return'.
+ * Update FSF address.
+ *
+ * Revision 5.19 1995/06/02 18:19:00 eggert
+ * (catchsigaction): New name for `catchsig', for sa_sigaction signature.
+ * Use nRCS even if !has_psiginfo, to remove unused variable warning.
+ * (setup_catchsig): Use sa_sigaction only if has_sa_sigaction.
+ * Use ENOTSUP only if defined.
+ *
+ * Revision 5.18 1995/06/01 16:23:43 eggert
+ * (catchsig, restoreints, setup_catchsig): Use SA_SIGINFO, not has_psiginfo,
+ * to determine whether to use SA_SIGINFO feature,
+ * but also check at runtime whether the feature works.
+ * (catchsig): If an mmap_signal occurs, report the affected file name.
+ * (unsupported_SA_SIGINFO, accessName): New variables.
+ * (setup_catchsig): If using SA_SIGINFO, use sa_sigaction, not sa_handler.
+ * If SA_SIGINFO fails, fall back on sa_handler method.
+ *
+ * (readAccessFilenameBuffer, dupSafer, fdSafer, fopenSafer): New functions.
+ * (concatenate): Remove.
+ *
+ * (runv): Work around bad_wait_if_SIGCHLD_ignored bug.
+ * Remove reference to OPEN_O_WORK.
+ *
+ * Revision 5.17 1994/03/20 04:52:58 eggert
+ * Specify subprocess input via file descriptor, not file name.
+ * Avoid messing with I/O buffers in the child process.
+ * Define dup in terms of F_DUPFD if it exists.
+ * Move setmtime to rcsedit.c. Remove lint.
+ *
+ * Revision 5.16 1993/11/09 17:40:15 eggert
+ * -V now prints version on stdout and exits.
+ *
+ * Revision 5.15 1993/11/03 17:42:27 eggert
+ * Use psiginfo and setreuid if available. Move date2str to maketime.c.
+ *
+ * Revision 5.14 1992/07/28 16:12:44 eggert
+ * Add -V. has_sigaction overrides sig_zaps_handler. Fix -M bug.
+ * Add mmap_signal, which minimizes signal handling for non-mmap hosts.
+ *
+ * Revision 5.13 1992/02/17 23:02:28 eggert
+ * Work around NFS mmap SIGBUS problem. Add -T support.
+ *
+ * Revision 5.12 1992/01/24 18:44:19 eggert
+ * Work around NFS mmap bug that leads to SIGBUS core dumps. lint -> RCS_lint
+ *
+ * Revision 5.11 1992/01/06 02:42:34 eggert
+ * O_BINARY -> OPEN_O_WORK
+ * while (E) ; -> while (E) continue;
+ *
* Revision 5.10 1991/10/07 17:32:46 eggert
* Support piece tables even if !has_mmap.
*
@@ -75,32 +125,32 @@ Report problems and direct all questions to:
*
* Revision 4.6 89/05/01 15:13:40 narten
* changed copyright header to reflect current distribution rules
- *
+ *
* Revision 4.5 88/11/08 16:01:02 narten
* corrected use of varargs routines
- *
+ *
* Revision 4.4 88/08/09 19:13:24 eggert
* Check for memory exhaustion.
* Permit signal handlers to yield either 'void' or 'int'; fix oldSIGINT botch.
* Use execv(), not system(); yield exit status like diff(1)'s.
- *
+ *
* Revision 4.3 87/10/18 10:40:22 narten
* Updating version numbers. Changes relative to 1.1 actually
* relative to 4.1
- *
+ *
* Revision 1.3 87/09/24 14:01:01 narten
- * Sources now pass through lint (if you ignore printf/sprintf/fprintf
+ * Sources now pass through lint (if you ignore printf/sprintf/fprintf
* warnings)
- *
+ *
* Revision 1.2 87/03/27 14:22:43 jenkins
* Port to suns
- *
+ *
* Revision 4.1 83/05/10 15:53:13 wft
* Added getcaller() and findlock().
* Changed catchints() to check SIGINT for SIG_IGN before setting up the signal
* (needed for background jobs in older shells). Added restoreints().
* Removed printing of full RCS path from logcommand().
- *
+ *
* Revision 3.8 83/02/15 15:41:49 wft
* Added routine fastcopy() to copy remainder of a file in blocks.
*
@@ -136,7 +186,7 @@ Report problems and direct all questions to:
#include "rcsbase.h"
-libId(utilId, "$Id: rcsutil.c,v 5.10 1991/10/07 17:32:46 eggert Exp $")
+libId(utilId, "$Id: rcsutil.c,v 1.3 1995/10/28 21:49:57 peter Exp $")
#if !has_memcmp
int
@@ -170,7 +220,7 @@ memcpy(s1, s2, n)
}
#endif
-#if lint
+#if RCS_lint
malloc_type lintalloc;
#endif
@@ -187,6 +237,7 @@ struct alloclist {
static struct alloclist *alloced;
+ static malloc_type okalloc P((malloc_type));
static malloc_type
okalloc(p)
malloc_type p;
@@ -242,7 +293,7 @@ ffree()
tfree(p->alloc);
tfree(p);
}
- alloced = nil;
+ alloced = 0;
}
void
@@ -297,16 +348,18 @@ getusername(suspicious)
/* Prefer getenv() unless suspicious; it's much faster. */
# if getlogin_is_secure
(suspicious
- ||
- !(name = cgetenv("LOGNAME"))
- && !(name = cgetenv("USER")))
+ || (
+ !(name = cgetenv("LOGNAME"))
+ && !(name = cgetenv("USER"))
+ ))
&& !(name = getlogin())
# else
suspicious
- ||
+ || (
!(name = cgetenv("LOGNAME"))
&& !(name = cgetenv("USER"))
&& !(name = getlogin())
+ )
# endif
) {
#if has_getuid && has_getpwuid
@@ -320,7 +373,7 @@ getusername(suspicious)
#if has_setuid
faterror("setuid not supported");
#else
- faterror("Who are you? Please set LOGNAME.");
+ faterror("Who are you? Please setenv LOGNAME.");
#endif
#endif
}
@@ -343,65 +396,191 @@ getusername(suspicious)
*/
static sig_atomic_t volatile heldsignal, holdlevel;
+#ifdef SA_SIGINFO
+ static int unsupported_SA_SIGINFO;
+ static siginfo_t bufsiginfo;
+ static siginfo_t *volatile heldsiginfo;
+#endif
- static signal_type
-catchsig(s)
- int s;
-{
- char const *sname;
- char buf[BUFSIZ];
-#if sig_zaps_handler
- /* If a signal arrives before we reset the signal handler, we lose. */
- VOID signal(s, SIG_IGN);
-#endif
- if (holdlevel) {
- heldsignal = s;
- return;
- }
- ignoreints();
- setrid();
- if (!quietflag) {
- sname = nil;
-#if has_sys_siglist && defined(NSIG)
- if ((unsigned)s < NSIG) {
-# ifndef sys_siglist
- extern char const *sys_siglist[];
-# endif
- sname = sys_siglist[s];
- }
+#if has_NFS && has_mmap && large_memory && mmap_signal
+ static char const *accessName;
+
+ void
+ readAccessFilenameBuffer(filename, p)
+ char const *filename;
+ unsigned char const *p;
+ {
+ unsigned char volatile t;
+ accessName = filename;
+ t = *p;
+ accessName = 0;
+ }
#else
- switch (s) {
-#ifdef SIGHUP
- case SIGHUP: sname = "Hangup"; break;
+# define accessName ((char const *) 0)
#endif
-#ifdef SIGINT
+
+
+#if !has_psignal
+
+# define psignal my_psignal
+ static void my_psignal P((int,char const*));
+ static void
+my_psignal(sig, s)
+ int sig;
+ char const *s;
+{
+ char const *sname = "Unknown signal";
+# if has_sys_siglist && defined(NSIG)
+ if ((unsigned)sig < NSIG)
+ sname = sys_siglist[sig];
+# else
+ switch (sig) {
+# ifdef SIGHUP
+ case SIGHUP: sname = "Hangup"; break;
+# endif
+# ifdef SIGINT
case SIGINT: sname = "Interrupt"; break;
-#endif
-#ifdef SIGPIPE
+# endif
+# ifdef SIGPIPE
case SIGPIPE: sname = "Broken pipe"; break;
-#endif
-#ifdef SIGQUIT
+# endif
+# ifdef SIGQUIT
case SIGQUIT: sname = "Quit"; break;
-#endif
-#ifdef SIGTERM
+# endif
+# ifdef SIGTERM
case SIGTERM: sname = "Terminated"; break;
-#endif
-#ifdef SIGXCPU
+# endif
+# ifdef SIGXCPU
case SIGXCPU: sname = "Cputime limit exceeded"; break;
-#endif
-#ifdef SIGXFSZ
+# endif
+# ifdef SIGXFSZ
case SIGXFSZ: sname = "Filesize limit exceeded"; break;
-#endif
+# endif
+# if has_mmap && large_memory
+# if defined(SIGBUS) && mmap_signal==SIGBUS
+ case SIGBUS: sname = "Bus error"; break;
+# endif
+# if defined(SIGSEGV) && mmap_signal==SIGSEGV
+ case SIGSEGV: sname = "Segmentation fault"; break;
+# endif
+# endif
}
+# endif
+
+ /* Avoid calling sprintf etc., in case they're not reentrant. */
+ {
+ char const *p;
+ char buf[BUFSIZ], *b = buf;
+ for (p = s; *p; *b++ = *p++)
+ continue;
+ *b++ = ':';
+ *b++ = ' ';
+ for (p = sname; *p; *b++ = *p++)
+ continue;
+ *b++ = '\n';
+ VOID write(STDERR_FILENO, buf, b - buf);
+ }
+}
+#endif
+
+static signal_type catchsig P((int));
+#ifdef SA_SIGINFO
+ static signal_type catchsigaction P((int,siginfo_t*,void*));
+#endif
+
+ static signal_type
+catchsig(s)
+ int s;
+#ifdef SA_SIGINFO
+{
+ catchsigaction(s, (siginfo_t *)0, (void *)0);
+}
+ static signal_type
+catchsigaction(s, i, c)
+ int s;
+ siginfo_t *i;
+ void *c;
#endif
- if (sname)
- VOID sprintf(buf, "\nRCS: %s. Cleaning up.\n", sname);
- else
- VOID sprintf(buf, "\nRCS: Signal %d. Cleaning up.\n", s);
- VOID write(STDERR_FILENO, buf, strlen(buf));
+{
+# if sig_zaps_handler
+ /* If a signal arrives before we reset the handler, we lose. */
+ VOID signal(s, SIG_IGN);
+# endif
+
+# ifdef SA_SIGINFO
+ if (!unsupported_SA_SIGINFO)
+ i = 0;
+# endif
+
+ if (holdlevel) {
+ heldsignal = s;
+# ifdef SA_SIGINFO
+ if (i) {
+ bufsiginfo = *i;
+ heldsiginfo = &bufsiginfo;
+ }
+# endif
+ return;
+ }
+
+ ignoreints();
+ setrid();
+ if (!quietflag) {
+ /* Avoid calling sprintf etc., in case they're not reentrant. */
+ char const *p;
+ char buf[BUFSIZ], *b = buf;
+
+ if ( ! (
+# if has_mmap && large_memory && mmap_signal
+ /* Check whether this signal was planned. */
+ s == mmap_signal && accessName
+# else
+ 0
+# endif
+ )) {
+ char const *nRCS = "\nRCS";
+# if defined(SA_SIGINFO) && has_si_errno && has_mmap && large_memory && mmap_signal
+ if (s == mmap_signal && i && i->si_errno) {
+ errno = i->si_errno;
+ perror(nRCS++);
+ }
+# endif
+# if defined(SA_SIGINFO) && has_psiginfo
+ if (i)
+ psiginfo(i, nRCS);
+ else
+ psignal(s, nRCS);
+# else
+ psignal(s, nRCS);
+# endif
}
- exiterr();
+
+ for (p = "RCS: "; *p; *b++ = *p++)
+ continue;
+# if has_mmap && large_memory && mmap_signal
+ if (s == mmap_signal) {
+ p = accessName;
+ if (!p)
+ p = "Was a file changed by some other process? ";
+ else {
+ char const *p1;
+ for (p1 = p; *p1; p1++)
+ continue;
+ VOID write(STDERR_FILENO, buf, b - buf);
+ VOID write(STDERR_FILENO, p, p1 - p);
+ b = buf;
+ p = ": Permission denied. ";
+ }
+ while (*p)
+ *b++ = *p++;
+ }
+# endif
+ for (p = "Cleaning up.\n"; *p; *b++ = *p++)
+ continue;
+ VOID write(STDERR_FILENO, buf, b - buf);
+ }
+ exiterr();
}
void
@@ -414,62 +593,62 @@ ignoreints()
restoreints()
{
if (!--holdlevel && heldsignal)
+# ifdef SA_SIGINFO
+ VOID catchsigaction(heldsignal, heldsiginfo, (void *)0);
+# else
VOID catchsig(heldsignal);
+# endif
}
-static int const sig[] = {
-#ifdef SIGHUP
- SIGHUP,
-#endif
-#ifdef SIGINT
- SIGINT,
-#endif
-#ifdef SIGPIPE
- SIGPIPE,
-#endif
-#ifdef SIGQUIT
- SIGQUIT,
-#endif
-#ifdef SIGTERM
- SIGTERM,
-#endif
-#ifdef SIGXCPU
- SIGXCPU,
-#endif
-#ifdef SIGXFSZ
- SIGXFSZ,
-#endif
-};
-#define SIGS (sizeof(sig)/sizeof(*sig))
-
+static void setup_catchsig P((int const*,int));
#if has_sigaction
+ static void check_sig P((int));
static void
check_sig(r)
int r;
{
if (r != 0)
- efaterror("signal");
+ efaterror("signal handling");
}
static void
- setup_catchsig()
+ setup_catchsig(sig, sigs)
+ int const *sig;
+ int sigs;
{
- register int i;
- sigset_t blocked;
+ register int i, j;
struct sigaction act;
- check_sig(sigemptyset(&blocked));
- for (i=SIGS; 0<=--i; )
- check_sig(sigaddset(&blocked, sig[i]));
- for (i=SIGS; 0<=--i; ) {
- check_sig(sigaction(sig[i], (struct sigaction*)nil, &act));
+ for (i=sigs; 0<=--i; ) {
+ check_sig(sigaction(sig[i], (struct sigaction*)0, &act));
if (act.sa_handler != SIG_IGN) {
- act.sa_handler = catchsig;
- act.sa_mask = blocked;
- check_sig(sigaction(sig[i], &act, (struct sigaction*)nil));
+ act.sa_handler = catchsig;
+# ifdef SA_SIGINFO
+ if (!unsupported_SA_SIGINFO) {
+# if has_sa_sigaction
+ act.sa_sigaction = catchsigaction;
+# else
+ act.sa_handler = catchsigaction;
+# endif
+ act.sa_flags |= SA_SIGINFO;
+ }
+# endif
+ for (j=sigs; 0<=--j; )
+ check_sig(sigaddset(&act.sa_mask, sig[j]));
+ if (sigaction(sig[i], &act, (struct sigaction*)0) != 0) {
+# if defined(SA_SIGINFO) && defined(ENOTSUP)
+ if (errno == ENOTSUP && !unsupported_SA_SIGINFO) {
+ /* Turn off use of SA_SIGINFO and try again. */
+ unsupported_SA_SIGINFO = 1;
+ i++;
+ continue;
+ }
+# endif
+ check_sig(-1);
+ }
}
}
}
@@ -478,16 +657,18 @@ static int const sig[] = {
#if has_sigblock
static void
- setup_catchsig()
+ setup_catchsig(sig, sigs)
+ int const *sig;
+ int sigs;
{
register int i;
int mask;
mask = 0;
- for (i=SIGS; 0<=--i; )
+ for (i=sigs; 0<=--i; )
mask |= sigmask(sig[i]);
mask = sigblock(mask);
- for (i=SIGS; 0<=--i; )
+ for (i=sigs; 0<=--i; )
if (
signal(sig[i], catchsig) == SIG_IGN &&
signal(sig[i], SIG_IGN) != catchsig
@@ -499,11 +680,13 @@ static int const sig[] = {
#else
static void
- setup_catchsig()
+ setup_catchsig(sig, sigs)
+ int const *sig;
+ int sigs;
{
register i;
- for (i=SIGS; 0<=--i; )
+ for (i=sigs; 0<=--i; )
if (
signal(sig[i], SIG_IGN) != SIG_IGN &&
signal(sig[i], catchsig) != SIG_IGN
@@ -514,16 +697,68 @@ static int const sig[] = {
#endif
#endif
+
+static int const regsigs[] = {
+# ifdef SIGHUP
+ SIGHUP,
+# endif
+# ifdef SIGINT
+ SIGINT,
+# endif
+# ifdef SIGPIPE
+ SIGPIPE,
+# endif
+# ifdef SIGQUIT
+ SIGQUIT,
+# endif
+# ifdef SIGTERM
+ SIGTERM,
+# endif
+# ifdef SIGXCPU
+ SIGXCPU,
+# endif
+# ifdef SIGXFSZ
+ SIGXFSZ,
+# endif
+};
+
void
catchints()
{
static int catching_ints;
if (!catching_ints) {
- catching_ints = true;
- setup_catchsig();
+ catching_ints = true;
+ setup_catchsig(regsigs, (int) (sizeof(regsigs)/sizeof(*regsigs)));
}
}
+#if has_mmap && large_memory && mmap_signal
+
+ /*
+ * If you mmap an NFS file, and someone on another client removes the last
+ * link to that file, and you later reference an uncached part of that file,
+ * you'll get a SIGBUS or SIGSEGV (depending on the operating system).
+ * Catch the signal and report the problem to the user.
+ * Unfortunately, there's no portable way to differentiate between this
+ * problem and actual bugs in the program.
+ * This NFS problem is rare, thank goodness.
+ *
+ * This can also occur if someone truncates the file, even without NFS.
+ */
+
+ static int const mmapsigs[] = { mmap_signal };
+
+ void
+ catchmmapints()
+ {
+ static int catching_mmap_ints;
+ if (!catching_mmap_ints) {
+ catching_mmap_ints = true;
+ setup_catchsig(mmapsigs, (int)(sizeof(mmapsigs)/sizeof(*mmapsigs)));
+ }
+ }
+#endif
+
#endif /* has_signal */
@@ -535,7 +770,7 @@ fastcopy(inf,outf)
*/
{
#if large_memory
-# if has_mmap
+# if maps_memory
awrite((char const*)inf->ptr, (size_t)(inf->lim - inf->ptr), outf);
inf->ptr = inf->lim;
# else
@@ -586,10 +821,81 @@ awrite(buf, chars, f)
Oerror();
}
+/* dup a file descriptor; the result must not be stdin, stdout, or stderr. */
+ static int dupSafer P((int));
+ static int
+dupSafer(fd)
+ int fd;
+{
+# ifdef F_DUPFD
+ return fcntl(fd, F_DUPFD, STDERR_FILENO + 1);
+# else
+ int e, f, i, used = 0;
+ while (STDIN_FILENO <= (f = dup(fd)) && f <= STDERR_FILENO)
+ used |= 1<<f;
+ e = errno;
+ for (i = STDIN_FILENO; i <= STDERR_FILENO; i++)
+ if (used & (1<<i))
+ VOID close(i);
+ errno = e;
+ return f;
+# endif
+}
+/* Renumber a file descriptor so that it's not stdin, stdout, or stderr. */
+ int
+fdSafer(fd)
+ int fd;
+{
+ if (STDIN_FILENO <= fd && fd <= STDERR_FILENO) {
+ int f = dupSafer(fd);
+ int e = errno;
+ VOID close(fd);
+ errno = e;
+ fd = f;
+ }
+ return fd;
+}
+
+/* Like fopen, except the result is never stdin, stdout, or stderr. */
+ FILE *
+fopenSafer(filename, type)
+ char const *filename;
+ char const *type;
+{
+ FILE *stream = fopen(filename, type);
+ if (stream) {
+ int fd = fileno(stream);
+ if (STDIN_FILENO <= fd && fd <= STDERR_FILENO) {
+ int f = dupSafer(fd);
+ if (f < 0) {
+ int e = errno;
+ VOID fclose(stream);
+ errno = e;
+ return 0;
+ }
+ if (fclose(stream) != 0) {
+ int e = errno;
+ VOID close(f);
+ errno = e;
+ return 0;
+ }
+ stream = fdopen(f, type);
+ }
+ }
+ return stream;
+}
+#ifdef F_DUPFD
+# undef dup
+# define dup(fd) fcntl(fd, F_DUPFD, 0)
+#endif
+
+#if has_fork || has_spawn
+
+ static int movefd P((int,int));
static int
movefd(old, new)
int old, new;
@@ -604,6 +910,7 @@ movefd(old, new)
return close(old)==0 ? new : -1;
}
+ static int fdreopen P((int,char const*,int));
static int
fdreopen(fd, file, flags)
int fd;
@@ -620,38 +927,26 @@ fdreopen(fd, file, flags)
return movefd(newfd, fd);
}
-#if !has_spawn
- static void
-tryopen(fd,file,flags)
- int fd, flags;
- char const *file;
-{
- if (file && fdreopen(fd,file,flags) != fd)
- efaterror(file);
-}
-#else
- static int
-tryopen(fd,file,flags)
- int fd, flags;
- char const *file;
-{
- int newfd = -1;
- if (file && ((newfd=dup(fd)) < 0 || fdreopen(fd,file,flags) != fd))
- efaterror(file);
- return newfd;
-}
+#if has_spawn
+ static void redirect P((int,int));
static void
redirect(old, new)
int old, new;
+/*
+* Move file descriptor OLD to NEW.
+* If OLD is -1, do nothing.
+* If OLD is -2, just close NEW.
+*/
{
- if (0 <= old && (close(new) != 0 || movefd(old,new) < 0))
+ if ((old != -1 && close(new) != 0) || (0 <= old && movefd(old,new) < 0))
efaterror("spawn I/O redirection");
}
#endif
+#else /* !has_fork && !has_spawn */
-#if !has_fork && !has_spawn
+ static void bufargcat P((struct buf*,int,char const*));
static void
bufargcat(b, c, s)
register struct buf *b;
@@ -681,53 +976,145 @@ bufargcat(b, c, s)
*p++ = '\'';
*p = 0;
}
+
#endif
+#if !has_spawn && has_fork
/*
-* Run a command specified by the strings in 'inoutargs'.
-* inoutargs[0], if nonnil, is the name of the input file.
-* inoutargs[1], if nonnil, is the name of the output file.
-* inoutargs[2..] form the command to be run.
+* Output the string S to stderr, without touching any I/O buffers.
+* This is useful if you are a child process, whose buffers are usually wrong.
+* Exit immediately if the write does not completely succeed.
+*/
+static void write_stderr P((char const *));
+ static void
+write_stderr(s)
+ char const *s;
+{
+ size_t slen = strlen(s);
+ if (write(STDERR_FILENO, s, slen) != slen)
+ _exit(EXIT_TROUBLE);
+}
+#endif
+
+/*
+* Run a command.
+* infd, if not -1, is the input file descriptor.
+* outname, if nonzero, is the name of the output file.
+* args[1..] form the command to be run; args[0] might be modified.
*/
int
-runv(inoutargs)
- char const **inoutargs;
+runv(infd, outname, args)
+ int infd;
+ char const *outname, **args;
{
- register char const **p;
int wstatus;
+#if bad_wait_if_SIGCHLD_ignored
+ static int fixed_SIGCHLD;
+ if (!fixed_SIGCHLD) {
+ fixed_SIGCHLD = true;
+# ifndef SIGCHLD
+# define SIGCHLD SIGCLD
+# endif
+ VOID signal(SIGCHLD, SIG_DFL);
+ }
+#endif
+
oflush();
eflush();
{
#if has_spawn
int in, out;
- p = inoutargs;
- in = tryopen(STDIN_FILENO, *p++, O_BINARY|O_RDONLY);
- out = tryopen(STDOUT_FILENO, *p++, O_BINARY|O_CREAT|O_TRUNC|O_WRONLY);
- wstatus = spawn_RCS(0, *p, (char*const*)p);
- if (wstatus == -1 && errno == ENOEXEC) {
- *--p = RCS_SHELL;
- wstatus = spawnv(0, *p, (char*const*)p);
+ char const *file;
+
+ in = -1;
+ if (infd != -1 && infd != STDIN_FILENO) {
+ if ((in = dup(STDIN_FILENO)) < 0) {
+ if (errno != EBADF)
+ efaterror("spawn input setup");
+ in = -2;
+ } else {
+# ifdef F_DUPFD
+ if (close(STDIN_FILENO) != 0)
+ efaterror("spawn input close");
+# endif
+ }
+ if (
+# ifdef F_DUPFD
+ fcntl(infd, F_DUPFD, STDIN_FILENO) != STDIN_FILENO
+# else
+ dup2(infd, STDIN_FILENO) != STDIN_FILENO
+# endif
+ )
+ efaterror("spawn input redirection");
+ }
+
+ out = -1;
+ if (outname) {
+ if ((out = dup(STDOUT_FILENO)) < 0) {
+ if (errno != EBADF)
+ efaterror("spawn output setup");
+ out = -2;
+ }
+ if (fdreopen(
+ STDOUT_FILENO, outname,
+ O_CREAT | O_TRUNC | O_WRONLY
+ ) < 0)
+ efaterror(outname);
}
+
+ wstatus = spawn_RCS(0, args[1], (char**)(args + 1));
+# ifdef RCS_SHELL
+ if (wstatus == -1 && errno == ENOEXEC) {
+ args[0] = RCS_SHELL;
+ wstatus = spawnv(0, args[0], (char**)args);
+ }
+# endif
redirect(in, STDIN_FILENO);
redirect(out, STDOUT_FILENO);
#else
#if has_fork
pid_t pid;
-# if !has_waitpid
- pid_t w;
-# endif
if (!(pid = vfork())) {
- p = inoutargs;
- tryopen(STDIN_FILENO, *p++, O_BINARY|O_RDONLY);
- tryopen(STDOUT_FILENO, *p++, O_BINARY|O_CREAT|O_TRUNC|O_WRONLY);
- VOID exec_RCS(*p, (char*const*)p);
- if (errno == ENOEXEC) {
- *--p = RCS_SHELL;
- VOID execv(*p, (char*const*)p);
+ char const *notfound;
+ if (infd != -1 && infd != STDIN_FILENO && (
+# ifdef F_DUPFD
+ (VOID close(STDIN_FILENO),
+ fcntl(infd, F_DUPFD, STDIN_FILENO) != STDIN_FILENO)
+# else
+ dup2(infd, STDIN_FILENO) != STDIN_FILENO
+# endif
+ )) {
+ /* Avoid perror since it may misuse buffers. */
+ write_stderr(args[1]);
+ write_stderr(": I/O redirection failed\n");
+ _exit(EXIT_TROUBLE);
}
- VOID write(STDERR_FILENO, *p, strlen(*p));
- VOID write(STDERR_FILENO, ": not found\n", 12);
+
+ if (outname)
+ if (fdreopen(
+ STDOUT_FILENO, outname,
+ O_CREAT | O_TRUNC | O_WRONLY
+ ) < 0) {
+ /* Avoid perror since it may misuse buffers. */
+ write_stderr(args[1]);
+ write_stderr(": ");
+ write_stderr(outname);
+ write_stderr(": cannot create\n");
+ _exit(EXIT_TROUBLE);
+ }
+ VOID exec_RCS(args[1], (char**)(args + 1));
+ notfound = args[1];
+# ifdef RCS_SHELL
+ if (errno == ENOEXEC) {
+ args[0] = notfound = RCS_SHELL;
+ VOID execv(args[0], (char**)args);
+ }
+# endif
+
+ /* Avoid perror since it may misuse buffers. */
+ write_stderr(notfound);
+ write_stderr(": not found\n");
_exit(EXIT_TROUBLE);
}
if (pid < 0)
@@ -736,83 +1123,71 @@ runv(inoutargs)
if (waitpid(pid, &wstatus, 0) < 0)
efaterror("waitpid");
# else
- do {
- if ((w = wait(&wstatus)) < 0)
- efaterror("wait");
- } while (w != pid);
+ {
+ pid_t w;
+ do {
+ if ((w = wait(&wstatus)) < 0)
+ efaterror("wait");
+ } while (w != pid);
+ }
# endif
#else
static struct buf b;
+ char const *p;
/* Use system(). On many hosts system() discards signals. Yuck! */
- p = inoutargs+2;
+ p = args + 1;
bufscpy(&b, *p);
while (*++p)
bufargcat(&b, ' ', *p);
- if (inoutargs[0])
- bufargcat(&b, '<', inoutargs[0]);
- if (inoutargs[1])
- bufargcat(&b, '>', inoutargs[1]);
+ if (infd != -1 && infd != STDIN_FILENO) {
+ char redirection[32];
+ VOID sprintf(redirection, "<&%d", infd);
+ bufscat(&b, redirection);
+ }
+ if (outname)
+ bufargcat(&b, '>', outname);
wstatus = system(b.string);
#endif
#endif
}
- if (!WIFEXITED(wstatus))
- faterror("%s failed", inoutargs[2]);
+ if (!WIFEXITED(wstatus)) {
+ if (WIFSIGNALED(wstatus)) {
+ psignal(WTERMSIG(wstatus), args[1]);
+ fatcleanup(1);
+ }
+ faterror("%s failed for unknown reason", args[1]);
+ }
return WEXITSTATUS(wstatus);
}
#define CARGSMAX 20
/*
* Run a command.
-* The first two arguments are the input and output files (if nonnil);
-* the rest specify the command and its arguments.
+* infd, if not -1, is the input file descriptor.
+* outname, if nonzero, is the name of the output file.
+* The remaining arguments specify the command and its arguments.
*/
int
#if has_prototypes
-run(char const *infile, char const *outfile, ...)
+run(int infd, char const *outname, ...)
#else
/*VARARGS2*/
-run(infile, outfile, va_alist)
- char const *infile;
- char const *outfile;
+run(infd, outname, va_alist)
+ int infd;
+ char const *outname;
va_dcl
#endif
{
va_list ap;
char const *rgargs[CARGSMAX];
- register i = 0;
- rgargs[0] = infile;
- rgargs[1] = outfile;
- vararg_start(ap, outfile);
- for (i = 2; (rgargs[i++] = va_arg(ap, char const*)); )
+ register int i;
+ vararg_start(ap, outname);
+ for (i = 1; (rgargs[i++] = va_arg(ap, char const*)); )
if (CARGSMAX <= i)
faterror("too many command arguments");
va_end(ap);
- return runv(rgargs);
-}
-
-
- char const *
-date2str(date, datebuf)
- char const date[datesize];
- char datebuf[datesize];
-/*
-* Format a user-readable form of the RCS format DATE into the buffer DATEBUF.
-* Yield DATEBUF.
-*/
-{
- register char const *p = date;
-
- while (*p++ != '.')
- ;
- VOID sprintf(datebuf,
- "19%.*s/%.2s/%.2s %.2s:%.2s:%s" +
- (date[2]=='.' && VERSION(5)<=RCSversion ? 0 : 2),
- (int)(p-date-1), date,
- p, p+3, p+6, p+9, p+12
- );
- return datebuf;
+ return runv(infd, outname, rgargs);
}
@@ -825,23 +1200,28 @@ setRCSversion(str)
static int oldversion;
register char const *s = str + 2;
- int v = VERSION_DEFAULT;
-
- if (oldversion)
- redefined('V');
- oldversion = true;
if (*s) {
+ int v = VERSION_DEFAULT;
+
+ if (oldversion)
+ redefined('V');
+ oldversion = true;
v = 0;
while (isdigit(*s))
v = 10*v + *s++ - '0';
if (*s)
- faterror("%s isn't a number", str);
- if (v < VERSION_min || VERSION_max < v)
- faterror("%s out of range %d..%d", str, VERSION_min, VERSION_max);
+ error("%s isn't a number", str);
+ else if (v < VERSION_min || VERSION_max < v)
+ error("%s out of range %d..%d",
+ str, VERSION_min, VERSION_max
+ );
+
+ RCSversion = VERSION(v);
+ } else {
+ printf("RCS version %s\n", RCS_version_string);
+ exit(0);
}
-
- RCSversion = VERSION(v);
}
int
@@ -850,7 +1230,7 @@ getRCSINIT(argc, argv, newargv)
char **argv, ***newargv;
{
register char *p, *q, **pp;
- unsigned n;
+ size_t n;
if (!(q = cgetenv("RCSINIT")))
*newargv = argv;
@@ -919,7 +1299,7 @@ getRCSINIT(argc, argv, newargv)
}
copyrest:
while ((*pp++ = *argv++))
- ;
+ continue;
}
return argc;
}
@@ -947,8 +1327,11 @@ getRCSINIT(argc, argv, newargv)
*/
static void
-set_uid_to(u)
- uid_t u;
+#if has_prototypes
+set_uid_to(uid_t u)
+#else
+ set_uid_to(u) uid_t u;
+#endif
/* Become user u. */
{
static int looping;
@@ -956,8 +1339,13 @@ set_uid_to(u)
if (euid() == ruid())
return;
#if (has_fork||has_spawn) && DIFF_ABSOLUTE
- if (seteuid(u) != 0)
- efaterror("setuid");
+# if has_setreuid
+ if (setreuid(u==euid() ? ruid() : euid(), u) != 0)
+ efaterror("setuid");
+# else
+ if (seteuid(u) != 0)
+ efaterror("setuid");
+# endif
#endif
if (geteuid() != u) {
if (looping)
@@ -992,3 +1380,12 @@ setrid()
set_uid_to(ruid());
}
#endif
+
+ time_t
+now()
+{
+ static time_t t;
+ if (!t && time(&t) == -1)
+ efaterror("time");
+ return t;
+}
diff --git a/gnu/usr.bin/rcs/lib/version.c b/gnu/usr.bin/rcs/lib/version.c
new file mode 100644
index 0000000..81f5585
--- /dev/null
+++ b/gnu/usr.bin/rcs/lib/version.c
@@ -0,0 +1,2 @@
+#include "rcsbase.h"
+char const RCS_version_string[] = "5.7";
diff --git a/gnu/usr.bin/rcs/merge/Makefile b/gnu/usr.bin/rcs/merge/Makefile
index d14afb2..9022bc4 100644
--- a/gnu/usr.bin/rcs/merge/Makefile
+++ b/gnu/usr.bin/rcs/merge/Makefile
@@ -1,7 +1,8 @@
-PROG= merge
-
+PROG= merge
SRCS= merge.c
-LDADD= -L${.CURDIR}/../lib/obj -lrcs
CFLAGS+= -I${.CURDIR}/../lib
+LDADD= ${LIBRCS}
+DPADD= ${LIBRCS}
+.include "../../Makefile.inc"
.include <bsd.prog.mk>
diff --git a/gnu/usr.bin/rcs/merge/merge.1 b/gnu/usr.bin/rcs/merge/merge.1
index 8b1957f..e4860d2 100644
--- a/gnu/usr.bin/rcs/merge/merge.1
+++ b/gnu/usr.bin/rcs/merge/merge.1
@@ -2,22 +2,14 @@
.ds Rv \\$3
.ds Dt \\$4
..
-.Id $Id: merge.1,v 5.3 1991/02/28 19:18:45 eggert Exp $
+.Id $Id: merge.1,v 5.7 1995/06/01 16:23:43 eggert Exp $
.TH MERGE 1 \*(Dt GNU
.SH NAME
merge \- three-way file merge
.SH SYNOPSIS
.B merge
[
-.B \-L
-.I label1
-[
-.B \-L
-.I label3
-] ] [
-.B \-p
-] [
-.B \-q
+.I "options"
]
.I "file1 file2 file3"
.SH DESCRIPTION
@@ -28,11 +20,8 @@ to
.I file3
into
.IR file1 .
-The result goes to standard output if
-.B \-p
-is present, into
-.I file1
-otherwise.
+The result ordinarily goes into
+.IR file1 .
.B merge
is useful for combining separate changes to an original. Suppose
.I file2
@@ -46,57 +35,101 @@ Then
.B merge
combines both changes.
.PP
-An overlap occurs if both
+A conflict occurs if both
.I file1
and
.I file3
have changes in a common segment of lines.
-On a few older hosts where
-.B diff3
-does not support the
-.B \-E
-option,
-.B merge
-does not detect overlaps, and merely supplies the changed lines from
-.I file3.
-On most hosts, if overlaps occur,
+If a conflict is found,
.B merge
-outputs a message (unless the
-.B \-q
-option is given),
-and includes both alternatives
-in the result. The alternatives are delimited as follows:
+normally outputs a warning and brackets the conflict with
+.B <<<<<<<
+and
+.B >>>>>>>
+lines.
+A typical conflict will look like this:
.LP
.RS
.nf
-.BI <<<<<<< " file1"
-.I "lines in file1"
+.BI <<<<<<< " file A"
+.I "lines in file A"
.B "======="
-.I "lines in file3"
-.BI >>>>>>> " file3"
+.I "lines in file B"
+.BI >>>>>>> " file B"
.RE
.fi
.LP
-If there are overlaps, the user should edit the result and delete one of the
+If there are conflicts, the user should edit the result and delete one of the
alternatives.
-If the
-.BI \-L "\ label1"
+.SH OPTIONS
+.TP
+.B \-A
+Output conflicts using the
+.B \-A
+style of
+.BR diff3 (1),
+if supported by
+.BR diff3 .
+This merges all changes leading from
+.I file2
+to
+.I file3
+into
+.IR file1 ,
+and generates the most verbose output.
+.TP
+\f3\-E\fP, \f3\-e\fP
+These options specify conflict styles that generate less information
+than
+.BR \-A .
+See
+.BR diff3 (1)
+for details.
+The default is
+.BR \-E .
+With
+.BR \-e ,
+.B merge
+does not warn about conflicts.
+.TP
+.BI \-L " label"
+This option may be given up to three times, and specifies labels
+to be used in place of the corresponding file names in conflict reports.
+That is,
+.B "merge\ \-L\ x\ \-L\ y\ \-L\ z\ a\ b\ c"
+generates output that looks like it came from files
+.BR x ,
+.B y
and
-.BI \-L "\ label3"
-options are given, the labels are output in place of the names
-.I file1
+.B z
+instead of from files
+.BR a ,
+.B b
and
-.I file3
-in overlap reports.
+.BR c .
+.TP
+.BI \-p
+Send results to standard output instead of overwriting
+.IR file1 .
+.TP
+.BI \-q
+Quiet; do not warn about conflicts.
+.BI \-V
+Print \*r's version number.
.SH DIAGNOSTICS
-Exit status is 0 for no overlaps, 1 for some overlaps, 2 for trouble.
+Exit status is 0 for no conflicts, 1 for some conflicts, 2 for trouble.
.SH IDENTIFICATION
Author: Walter F. Tichy.
.br
-Revision Number: \*(Rv; Release Date: \*(Dt.
+Manual Page Revision: \*(Rv; Release Date: \*(Dt.
.br
-Copyright \(co 1982, 1988, 1989 by Walter F. Tichy.
+Copyright \(co 1982, 1988, 1989 Walter F. Tichy.
.br
-Copyright \(co 1990, 1991 by Paul Eggert.
+Copyright \(co 1990, 1991, 1992, 1993, 1994, 1995 Paul Eggert.
.SH SEE ALSO
diff3(1), diff(1), rcsmerge(1), co(1).
+.SH BUGS
+It normally does not make sense to merge binary files as if they were text, but
+.B merge
+tries to do it anyway.
+.br
diff --git a/gnu/usr.bin/rcs/merge/merge.c b/gnu/usr.bin/rcs/merge/merge.c
index 4067c18..44d33a3 100644
--- a/gnu/usr.bin/rcs/merge/merge.c
+++ b/gnu/usr.bin/rcs/merge/merge.c
@@ -1,6 +1,6 @@
/* merge - three-way file merge */
-/* Copyright 1991 by Paul Eggert
+/* Copyright 1991, 1992, 1993, 1994, 1995 Paul Eggert
Distributed under license by the Free Software Foundation, Inc.
This file is part of RCS.
@@ -16,8 +16,9 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
-along with RCS; see the file COPYING. If not, write to
-the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+along with RCS; see the file COPYING.
+If not, write to the Free Software Foundation,
+59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
Report problems and direct all questions to:
@@ -27,44 +28,59 @@ Report problems and direct all questions to:
#include "rcsbase.h"
+static void badoption P((char const*));
static char const usage[] =
- "\nmerge: usage: merge [-p] [-q] [-L label1 [-L label3]] file1 file2 file3\n";
+ "\nmerge: usage: merge [-AeEpqxX3] [-L lab [-L lab [-L lab]]] file1 file2 file3";
- static exiting void
+ static void
badoption(a)
char const *a;
{
- faterror("unknown option: %s%s", a-2, usage);
+ error("unknown option: %s%s", a, usage);
}
-mainProg(mergeId, "merge", "$Id: merge.c,v 1.2 1991/08/19 03:13:55 eggert Exp $")
+mainProg(mergeId, "merge", "$Id: merge.c,v 1.8 1995/06/16 06:19:24 eggert Exp $")
{
register char const *a;
- char const *label[2], *arg[3];
+ char const *arg[3], *label[3], *edarg = 0;
int labels, tostdout;
labels = 0;
tostdout = false;
- while ((a = *++argv) && *a++ == '-') {
+ for (; (a = *++argv) && *a++ == '-'; --argc) {
switch (*a++) {
+ case 'A': case 'E': case 'e':
+ if (edarg && edarg[1] != (*argv)[1])
+ error("%s and %s are incompatible",
+ edarg, *argv
+ );
+ edarg = *argv;
+ break;
+
case 'p': tostdout = true; break;
case 'q': quietflag = true; break;
+
case 'L':
- if (1<labels)
+ if (3 <= labels)
faterror("too many -L options");
if (!(label[labels++] = *++argv))
faterror("-L needs following argument");
--argc;
break;
+
+ case 'V':
+ printf("RCS version %s\n", RCS_version_string);
+ exitmain(0);
+
default:
- badoption(a);
+ badoption(a - 2);
+ continue;
}
if (*a)
- badoption(a);
- --argc;
+ badoption(a - 2);
}
if (argc != 4)
@@ -77,19 +93,19 @@ mainProg(mergeId, "merge", "$Id: merge.c,v 1.2 1991/08/19 03:13:55 eggert Exp $"
arg[1] = argv[1];
arg[2] = argv[2];
- switch (labels) {
- case 0: label[0] = arg[0]; /* fall into */
- case 1: label[1] = arg[2];
- }
+ for (; labels < 3; labels++)
+ label[labels] = arg[labels];
- exitmain(merge(tostdout, label, arg));
+ if (nerror)
+ exiterr();
+ exitmain(merge(tostdout, edarg, label, arg));
}
-#if lint
+#if RCS_lint
# define exiterr mergeExit
#endif
- exiting void
+ void
exiterr()
{
tempunlink();
diff --git a/gnu/usr.bin/rcs/rcs/Makefile b/gnu/usr.bin/rcs/rcs/Makefile
index d62c8d1..344ab6e 100644
--- a/gnu/usr.bin/rcs/rcs/Makefile
+++ b/gnu/usr.bin/rcs/rcs/Makefile
@@ -1,10 +1,11 @@
-PROG= rcs
-
-SRCS= rcs.c
-LDADD= -L${.CURDIR}/../lib/obj -lrcs
+PROG= rcs
+SRCS= rcs.c
CFLAGS+= -I${.CURDIR}/../lib
+LDADD= ${LIBRCS}
+DPADD= ${LIBRCS}
-MAN1= rcs.0 rcsintro.0
-MAN5= rcsfile.0
+MAN1= rcs.1 rcsintro.1
+MAN5= rcsfile.5
+.include "../../Makefile.inc"
.include <bsd.prog.mk>
diff --git a/gnu/usr.bin/rcs/rcs/rcs.1 b/gnu/usr.bin/rcs/rcs/rcs.1
index 9866a9c..38daf8b 100644
--- a/gnu/usr.bin/rcs/rcs/rcs.1
+++ b/gnu/usr.bin/rcs/rcs/rcs.1
@@ -2,16 +2,26 @@
.ds Rv \\$3
.ds Dt \\$4
..
-.Id $Id: rcs.1,v 5.6 1991/09/26 23:16:17 eggert Exp $
+.Id $Id: rcs.1,v 5.13 1995/06/05 08:28:35 eggert Exp $
.ds r \&\s-1RCS\s0
.if n .ds - \%--
.if t .ds - \(em
+.if !\n(.g \{\
+. if !\w|\*(lq| \{\
+. ds lq ``
+. if \w'\(lq' .ds lq "\(lq
+. \}
+. if !\w|\*(rq| \{\
+. ds rq ''
+. if \w'\(rq' .ds rq "\(rq
+. \}
+.\}
.TH RCS 1 \*(Dt GNU
.SH NAME
rcs \- change RCS file attributes
.SH SYNOPSIS
.B rcs
-.RI [ " options " ] " file " .\|.\|.
+.IR "options file " .\|.\|.
.SH DESCRIPTION
.B rcs
creates new \*r files or changes attributes of existing ones.
@@ -72,22 +82,29 @@ is omitted, the default
branch is reset to the (dynamically) highest branch on the trunk.
.TP
.BI \-c string
-sets the comment leader to
+Set the comment leader to
.IR string .
-The comment leader
-is printed before every log message line generated by the keyword
-.B $\&Log$
-during checkout (see
-.BR co (1)).
-This is useful for programming
-languages without multi-line comments.
An initial
-.B ci ,
+.BR ci ,
or an
.B "rcs\ \-i"
without
.BR \-c ,
-guesses the comment leader from the suffix of the working file.
+guesses the comment leader from the suffix of the working filename.
+.RS
+.PP
+This option is obsolescent, since \*r normally uses the preceding
+.B $\&Log$
+line's prefix when inserting log lines during checkout (see
+.BR co (1)).
+However, older versions of \*r use the comment leader instead of the
+.B $\&Log$
+line's prefix, so
+if you plan to access a file with both old and new versions of \*r,
+make sure its comment leader matches its
+.B $\&Log$
+line prefix.
+.RE
.TP
.BI \-k subst
Set the default keyword substitution to
@@ -120,9 +137,7 @@ If
.I rev
is omitted, lock the latest revision on the default branch.
Locking prevents overlapping changes.
-A lock is removed with
-.B ci
-or
+If someone else already holds the lock, the lock is broken as with
.B "rcs\ \-u"
(see below).
.TP
@@ -133,7 +148,7 @@ If a branch is given, unlock the latest revision on that branch.
If
.I rev
is omitted, remove the latest lock held by the caller.
-Normally, only the locker of a revision may unlock it.
+Normally, only the locker of a revision can unlock it.
Somebody else unlocking a revision breaks the lock.
This causes a mail message to be sent to the original locker.
The message contains a commentary solicited from the breaker.
@@ -163,6 +178,13 @@ Replace revision
log message with
.IR msg .
.TP
+.B \-M
+Do not send mail when breaking somebody else's lock.
+This option is not meant for casual use;
+it is meant for programs that warn users by other means, and invoke
+.B "rcs\ \-u"
+only as a low-level lock-breaking operation.
+.TP
\f3\-n\fP\f2name\fP[\f3:\fP[\f2rev\fP]]
Associate the symbolic name
.I name
@@ -235,7 +257,7 @@ from revision
.I rev
to the end of the branch containing
.IR rev .
-None of the outdated revisions may have branches or locks.
+None of the outdated revisions can have branches or locks.
.TP
.B \-q
Run quietly; do not print diagnostics.
@@ -247,7 +269,7 @@ Run interactively, even if the standard input is not a terminal.
Set the state attribute of the revision
.I rev
to
-.I state .
+.IR state .
If
.I rev
is a branch number, assume the latest revision on that branch.
@@ -276,7 +298,7 @@ Write descriptive text from the contents of the named
into the \*r file, deleting the existing text.
The
.IR file
-pathname may not begin with
+pathname cannot begin with
.BR \- .
If
.I file
@@ -298,6 +320,19 @@ Write descriptive text from the
.I string
into the \*r file, deleting the existing text.
.TP
+.B \-T
+Preserve the modification time on the \*r file
+unless a revision is removed.
+This option can suppress extensive recompilation caused by a
+.BR make (1)
+dependency of some copy of the working file on the \*r file.
+Use this option with care; it can suppress recompilation even when it is needed,
+i.e. when a change to the \*r file
+would mean a change to keyword strings in the working file.
+.TP
+.BI \-V
+Print \*r's version number.
+.TP
.BI \-V n
Emulate \*r version
.IR n .
@@ -312,6 +347,19 @@ to characterize \*r files.
See
.BR ci (1)
for details.
+.TP
+.BI \-z zone
+Use
+.I zone
+as the default time zone.
+This option has no effect;
+it is present for compatibility with other \*r commands.
+.PP
+At least one explicit option must be given,
+to ensure compatibility with future planned extensions
+to the
+.B rcs
+command.
.SH COMPATIBILITY
The
.BI \-b rev
@@ -359,14 +407,14 @@ The exit status is zero if and only if all operations were successful.
.SH IDENTIFICATION
Author: Walter F. Tichy.
.br
-Revision Number: \*(Rv; Release Date: \*(Dt.
+Manual Page Revision: \*(Rv; Release Date: \*(Dt.
.br
-Copyright \(co 1982, 1988, 1989 by Walter F. Tichy.
+Copyright \(co 1982, 1988, 1989 Walter F. Tichy.
.br
-Copyright \(co 1990, 1991 by Paul Eggert.
+Copyright \(co 1990, 1991, 1992, 1993, 1994, 1995 Paul Eggert.
.SH "SEE ALSO"
-co(1), ci(1), ident(1), rcsdiff(1), rcsintro(1), rcsmerge(1), rlog(1),
-rcsfile(5)
+rcsintro(1), co(1), ci(1), ident(1), rcsclean(1), rcsdiff(1),
+rcsmerge(1), rlog(1), rcsfile(5)
.br
Walter F. Tichy,
\*r\*-A System for Version Control,
@@ -374,6 +422,15 @@ Walter F. Tichy,
.BR 15 ,
7 (July 1985), 637-654.
.SH BUGS
+A catastrophe (e.g. a system crash) can cause \*r to leave behind
+a semaphore file that causes later invocations of \*r to claim
+that the \*r file is in use.
+To fix this, remove the semaphore file.
+A semaphore file's name typically begins with
+.B ,
+or ends with
+.BR _ .
+.PP
The separator for revision ranges in the
.B \-o
option used to be
diff --git a/gnu/usr.bin/rcs/rcs/rcs.c b/gnu/usr.bin/rcs/rcs/rcs.c
index 70e7ffc..bb51afb 100644
--- a/gnu/usr.bin/rcs/rcs/rcs.c
+++ b/gnu/usr.bin/rcs/rcs/rcs.c
@@ -1,8 +1,7 @@
-/*
- * RCS create/change operation
- */
-/* Copyright (C) 1982, 1988, 1989 Walter Tichy
- Copyright 1990, 1991 by Paul Eggert
+/* Change RCS file attributes. */
+
+/* Copyright 1982, 1988, 1989 Walter Tichy
+ Copyright 1990, 1991, 1992, 1993, 1994, 1995 Paul Eggert
Distributed under license by the Free Software Foundation, Inc.
This file is part of RCS.
@@ -18,8 +17,9 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
-along with RCS; see the file COPYING. If not, write to
-the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+along with RCS; see the file COPYING.
+If not, write to the Free Software Foundation,
+59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
Report problems and direct all questions to:
@@ -27,10 +27,44 @@ Report problems and direct all questions to:
*/
-
-
-
-/* $Log: rcs.c,v $
+/*
+ * Revision 5.21 1995/06/16 06:19:24 eggert
+ * Update FSF address.
+ *
+ * Revision 5.20 1995/06/01 16:23:43 eggert
+ * (main): Warn if no options were given. Punctuate messages properly.
+ *
+ * (sendmail): Rewind mailmess before flushing it.
+ * Output another warning if mail should work but fails.
+ *
+ * (buildeltatext): Pass "--binary" if -kb and if --binary makes a difference.
+ *
+ * Revision 5.19 1994/03/17 14:05:48 eggert
+ * Use ORCSerror to clean up after a fatal error. Remove lint.
+ * Specify subprocess input via file descriptor, not file name. Remove lint.
+ * Flush stderr after prompt.
+ *
+ * Revision 5.18 1993/11/09 17:40:15 eggert
+ * -V now prints version on stdout and exits. Don't print usage twice.
+ *
+ * Revision 5.17 1993/11/03 17:42:27 eggert
+ * Add -z. Don't lose track of -m or -t when there are no other changes.
+ * Don't discard ignored phrases. Improve quality of diagnostics.
+ *
+ * Revision 5.16 1992/07/28 16:12:44 eggert
+ * rcs -l now asks whether you want to break the lock.
+ * Add -V. Set RCS file's mode and time at right moment.
+ *
+ * Revision 5.15 1992/02/17 23:02:20 eggert
+ * Add -T.
+ *
+ * Revision 5.14 1992/01/27 16:42:53 eggert
+ * Add -M. Avoid invoking umask(); it's one less thing to configure.
+ * Add support for bad_creat0. lint -> RCS_lint
+ *
+ * Revision 5.13 1992/01/06 02:42:34 eggert
+ * Avoid changing RCS file in common cases where no change can occur.
+ *
* Revision 5.12 1991/11/20 17:58:08 eggert
* Don't read the delta tree from a nonexistent RCS file.
*
@@ -77,42 +111,42 @@ Report problems and direct all questions to:
*
* Revision 4.11 89/05/01 15:12:06 narten
* changed copyright header to reflect current distribution rules
- *
+ *
* Revision 4.10 88/11/08 16:01:54 narten
* didn't install previous patch correctly
- *
+ *
* Revision 4.9 88/11/08 13:56:01 narten
* removed include <sysexits.h> (not needed)
* minor fix for -A option
- *
+ *
* Revision 4.8 88/08/09 19:12:27 eggert
* Don't access freed storage.
* Use execv(), not system(); yield proper exit status; remove lint.
- *
+ *
* Revision 4.7 87/12/18 11:37:17 narten
* lint cleanups (Guy Harris)
- *
+ *
* Revision 4.6 87/10/18 10:28:48 narten
- * Updating verison numbers. Changes relative to 1.1 are actually
+ * Updating verison numbers. Changes relative to 1.1 are actually
* relative to 4.3
- *
+ *
* Revision 1.4 87/09/24 13:58:52 narten
- * Sources now pass through lint (if you ignore printf/sprintf/fprintf
+ * Sources now pass through lint (if you ignore printf/sprintf/fprintf
* warnings)
- *
+ *
* Revision 1.3 87/03/27 14:21:55 jenkins
* Port to suns
- *
+ *
* Revision 1.2 85/12/17 13:59:09 albitz
* Changed setstate to rcs_setstate because of conflict with random.o.
- *
+ *
* Revision 4.3 83/12/15 12:27:33 wft
* rcs -u now breaks most recent lock if it can't find a lock by the caller.
- *
+ *
* Revision 4.2 83/12/05 10:18:20 wft
* Added conditional compilation for sending mail.
* Alternatives: V4_2BSD, V6, USG, and other.
- *
+ *
* Revision 4.1 83/05/10 16:43:02 wft
* Simplified breaklock(); added calls to findlock() and getcaller().
* Added option -b (default branch). Updated -s and -w for -b.
@@ -120,10 +154,10 @@ Report problems and direct all questions to:
* Replaced most catchints() calls with restoreints().
* Removed check for exit status of delivermail().
* Directed all interactive output to stderr.
- *
+ *
* Revision 3.9.1.1 83/12/02 22:08:51 wft
* Added conditional compilation for 4.2 sendmail and 4.1 delivermail.
- *
+ *
* Revision 3.9 83/02/15 15:38:39 wft
* Added call to fastcopy() to copy remainder of RCS file.
*
@@ -205,69 +239,80 @@ struct delrevpair {
int code;
};
+static int branchpoint P((struct hshentry*,struct hshentry*));
+static int breaklock P((struct hshentry const*));
static int buildeltatext P((struct hshentries const*));
+static int doaccess P((void));
+static int doassoc P((void));
+static int dolocks P((void));
+static int domessages P((void));
+static int rcs_setstate P((char const*,char const*));
static int removerevs P((void));
static int sendmail P((char const*,char const*));
-static struct Lockrev *rmnewlocklst P((struct Lockrev const*));
-static void breaklock P((struct hshentry const*));
+static int setlock P((char const*));
+static struct Lockrev **rmnewlocklst P((char const*));
+static struct hshentry *searchcutpt P((char const*,int,struct hshentries*));
static void buildtree P((void));
static void cleanup P((void));
-static void doaccess P((void));
-static void doassoc P((void));
-static void dolocks P((void));
-static void domessages P((void));
static void getaccessor P((char*,enum changeaccess));
static void getassoclst P((int,char*));
static void getchaccess P((char const*,enum changeaccess));
static void getdelrev P((char*));
static void getmessage P((char*));
static void getstates P((char*));
-static void rcs_setstate P((char const*,char const*));
static void scanlogtext P((struct hshentry*,int));
-static void setlock P((char const*));
static struct buf numrev;
static char const *headstate;
static int chgheadstate, exitstatus, lockhead, unlockcaller;
+static int suppress_mail;
static struct Lockrev *newlocklst, *rmvlocklst;
-static struct Message *messagelst, *lastmessage;
-static struct Status *statelst, *laststate;
-static struct Symrev *assoclst, *lastassoc;
+static struct Message *messagelst, **nextmessage;
+static struct Status *statelst, **nextstate;
+static struct Symrev *assoclst, **nextassoc;
static struct chaccess *chaccess, **nextchaccess;
static struct delrevpair delrev;
static struct hshentry *cuthead, *cuttail, *delstrt;
static struct hshentries *gendeltas;
-mainProg(rcsId, "rcs", "$Id: rcs.c,v 5.12 1991/11/20 17:58:08 eggert Exp $")
+mainProg(rcsId, "rcs", "$Id: rcs.c,v 1.3 1995/10/28 21:50:13 peter Exp $")
{
static char const cmdusage[] =
- "\nrcs usage: rcs -{ae}logins -Afile -{blu}[rev] -cstring -{iLU} -{nNs}name[:rev] -orange -t[file] -Vn file ...";
+ "\nrcs usage: rcs -{ae}logins -Afile -{blu}[rev] -cstring -{iILqTU} -ksubst -mrev:msg -{nN}name[:[rev]] -orange -sstate[:rev] -t[text] -Vn -xsuff -zzone file ...";
char *a, **newargv, *textfile;
char const *branchsym, *commsyml;
- int branchflag, expmode, initflag;
- int e, r, strictlock, strict_selected, textflag;
- mode_t defaultRCSmode; /* default mode for new RCS files */
- mode_t RCSmode;
+ int branchflag, changed, expmode, initflag;
+ int strictlock, strict_selected, textflag;
+ int keepRCStime, Ttimeflag;
+ size_t commsymlen;
struct buf branchnum;
- struct stat workstat;
- struct Lockrev *curlock, * rmvlock, *lockpt;
+ struct Lockrev *lockpt;
+ struct Lockrev **curlock, **rmvlock;
struct Status * curstate;
nosetid();
+ nextassoc = &assoclst;
nextchaccess = &chaccess;
- branchsym = commsyml = textfile = nil;
+ nextmessage = &messagelst;
+ nextstate = &statelst;
+ branchsym = commsyml = textfile = 0;
branchflag = strictlock = false;
bufautobegin(&branchnum);
- curlock = rmvlock = nil;
- defaultRCSmode = 0;
+ commsymlen = 0;
+ curlock = &newlocklst;
+ rmvlock = &rmvlocklst;
expmode = -1;
suffixes = X_DEFAULT;
initflag= textflag = false;
strict_selected = 0;
+ Ttimeflag = false;
/* preprocessing command options */
+ if (1 < argc && argv[1][0] != '-')
+ warn("No options were given; this usage is obsolescent.");
+
argc = getRCSINIT(argc, argv, &newargv);
argv = newargv;
while (a = *++argv, 0<--argc && *a++=='-') {
@@ -286,6 +331,7 @@ mainProg(rcsId, "rcs", "$Id: rcs.c,v 5.12 1991/11/20 17:58:08 eggert Exp $")
case 'c': /* change comment symbol */
if (commsyml) redefined('c');
commsyml = a;
+ commsymlen = strlen(a);
break;
case 'a': /* add new accessor */
@@ -294,11 +340,11 @@ mainProg(rcsId, "rcs", "$Id: rcs.c,v 5.12 1991/11/20 17:58:08 eggert Exp $")
case 'A': /* append access list according to accessfile */
if (!*a) {
- error("missing file name after -A");
+ error("missing pathname after -A");
break;
}
*argv = a;
- if (0 < pairfilenames(1,argv,rcsreadopen,true,false)) {
+ if (0 < pairnames(1,argv,rcsreadopen,true,false)) {
while (AccessList) {
getchaccess(str_save(AccessList->login),append);
AccessList = AccessList->nextaccess;
@@ -317,14 +363,10 @@ mainProg(rcsId, "rcs", "$Id: rcs.c,v 5.12 1991/11/20 17:58:08 eggert Exp $")
lockhead = true;
break;
}
- lockpt = talloc(struct Lockrev);
+ *curlock = lockpt = talloc(struct Lockrev);
lockpt->revno = a;
- lockpt->nextrev = nil;
- if ( curlock )
- curlock->nextrev = lockpt;
- else
- newlocklst = lockpt;
- curlock = lockpt;
+ lockpt->nextrev = 0;
+ curlock = &lockpt->nextrev;
break;
case 'u': /* release lock of a locked revision */
@@ -332,33 +374,28 @@ mainProg(rcsId, "rcs", "$Id: rcs.c,v 5.12 1991/11/20 17:58:08 eggert Exp $")
unlockcaller=true;
break;
}
- lockpt = talloc(struct Lockrev);
+ *rmvlock = lockpt = talloc(struct Lockrev);
lockpt->revno = a;
- lockpt->nextrev = nil;
- if (rmvlock)
- rmvlock->nextrev = lockpt;
- else
- rmvlocklst = lockpt;
- rmvlock = lockpt;
-
- curlock = rmnewlocklst(lockpt);
+ lockpt->nextrev = 0;
+ rmvlock = &lockpt->nextrev;
+ curlock = rmnewlocklst(lockpt->revno);
break;
case 'L': /* set strict locking */
- if (strict_selected++) { /* Already selected L or U? */
+ if (strict_selected) {
if (!strictlock) /* Already selected -U? */
- warn("-L overrides -U.");
+ warn("-U overridden by -L");
}
strictlock = true;
+ strict_selected = true;
break;
case 'U': /* release strict locking */
- if (strict_selected++) { /* Already selected L or U? */
+ if (strict_selected) {
if (strictlock) /* Already selected -L? */
- warn("-L overrides -U.");
+ warn("-L overridden by -U");
}
- else
- strictlock = false;
+ strict_selected = true;
break;
case 'n': /* add new association: error, if name exists */
@@ -381,6 +418,10 @@ mainProg(rcsId, "rcs", "$Id: rcs.c,v 5.12 1991/11/20 17:58:08 eggert Exp $")
getmessage(a);
break;
+ case 'M': /* do not send mail */
+ suppress_mail = true;
+ break;
+
case 'o': /* delete revisions */
if (delrev.strt) redefined('o');
if (!*a) {
@@ -406,6 +447,12 @@ mainProg(rcsId, "rcs", "$Id: rcs.c,v 5.12 1991/11/20 17:58:08 eggert Exp $")
}
break;
+ case 'T': /* do not update last-mod time for minor changes */
+ if (*a)
+ goto unknown;
+ Ttimeflag = true;
+ break;
+
case 'I':
interactiveflag = true;
break;
@@ -422,41 +469,38 @@ mainProg(rcsId, "rcs", "$Id: rcs.c,v 5.12 1991/11/20 17:58:08 eggert Exp $")
setRCSversion(*argv);
break;
+ case 'z':
+ zone_set(a);
+ break;
+
case 'k': /* set keyword expand mode */
if (0 <= expmode) redefined('k');
if (0 <= (expmode = str2expmode(a)))
break;
/* fall into */
default:
- faterror("unknown option: %s%s", *argv, cmdusage);
+ unknown:
+ error("unknown option: %s%s", *argv, cmdusage);
};
} /* end processing of options */
- if (argc<1) faterror("no input file%s", cmdusage);
- if (nerror) {
- diagnose("%s aborted\n",cmdid);
- exitmain(EXIT_FAILURE);
- }
- if (initflag) {
- defaultRCSmode = umask((mode_t)0);
- VOID umask(defaultRCSmode);
- defaultRCSmode = (S_IRUSR|S_IRGRP|S_IROTH) & ~defaultRCSmode;
- }
+ /* Now handle all pathnames. */
+ if (nerror) cleanup();
+ else if (argc < 1) faterror("no input file%s", cmdusage);
+ else for (; 0 < argc; cleanup(), ++argv, --argc) {
- /* now handle all filenames */
- do {
ffree();
if ( initflag ) {
- switch (pairfilenames(argc, argv, rcswriteopen, false, false)) {
+ switch (pairnames(argc, argv, rcswriteopen, false, false)) {
case -1: break; /* not exist; ok */
case 0: continue; /* error */
- case 1: error("file %s exists already", RCSfilename);
+ case 1: rcserror("already exists");
continue;
}
}
else {
- switch (pairfilenames(argc, argv, rcswriteopen, true, false)) {
+ switch (pairnames(argc, argv, rcswriteopen, true, false)) {
case -1: continue; /* not exist */
case 0: continue; /* errors */
case 1: break; /* file exists; ok*/
@@ -464,115 +508,134 @@ mainProg(rcsId, "rcs", "$Id: rcs.c,v 5.12 1991/11/20 17:58:08 eggert Exp $")
}
- /* now RCSfilename contains the name of the RCS file, and
- * workfilename contains the name of the working file.
+ /*
+ * RCSname contains the name of the RCS file, and
+ * workname contains the name of the working file.
* if !initflag, finptr contains the file descriptor for the
* RCS file. The admin node is initialized.
*/
- diagnose("RCS file: %s\n", RCSfilename);
+ diagnose("RCS file: %s\n", RCSname);
- RCSmode = defaultRCSmode;
- if (initflag) {
- if (stat(workfilename, &workstat) == 0)
- RCSmode = workstat.st_mode;
- } else {
+ changed = initflag | textflag;
+ keepRCStime = Ttimeflag;
+ if (!initflag) {
if (!checkaccesslist()) continue;
gettree(); /* Read the delta tree. */
- RCSmode = RCSstat.st_mode;
}
- RCSmode &= ~(S_IWUSR|S_IWGRP|S_IWOTH);
/* update admin. node */
- if (strict_selected) StrictLocks = strictlock;
- if (commsyml) {
+ if (strict_selected) {
+ changed |= StrictLocks ^ strictlock;
+ StrictLocks = strictlock;
+ }
+ if (
+ commsyml &&
+ (
+ commsymlen != Comment.size ||
+ memcmp(commsyml, Comment.string, commsymlen) != 0
+ )
+ ) {
Comment.string = commsyml;
Comment.size = strlen(commsyml);
+ changed = true;
+ }
+ if (0 <= expmode && Expand != expmode) {
+ Expand = expmode;
+ changed = true;
}
- if (0 <= expmode) Expand = expmode;
/* update default branch */
if (branchflag && expandsym(branchsym, &branchnum)) {
if (countnumflds(branchnum.string)) {
- Dbranch = branchnum.string;
+ if (cmpnum(Dbranch, branchnum.string) != 0) {
+ Dbranch = branchnum.string;
+ changed = true;
+ }
} else
- Dbranch = nil;
- }
+ if (Dbranch) {
+ Dbranch = 0;
+ changed = true;
+ }
+ }
- doaccess(); /* Update access list. */
+ changed |= doaccess(); /* Update access list. */
- doassoc(); /* Update association list. */
+ changed |= doassoc(); /* Update association list. */
- dolocks(); /* Update locks. */
+ changed |= dolocks(); /* Update locks. */
- domessages(); /* Update log messages. */
+ changed |= domessages(); /* Update log messages. */
/* update state attribution */
if (chgheadstate) {
/* change state of default branch or head */
- if (Dbranch==nil) {
- if (Head==nil)
- warn("can't change states in an empty tree");
- else Head->state = headstate;
- } else {
- rcs_setstate(Dbranch,headstate); /* Can't set directly */
- }
- }
- curstate = statelst;
- while( curstate ) {
- rcs_setstate(curstate->revno,curstate->status);
- curstate = curstate->nextstatus;
+ if (!Dbranch) {
+ if (!Head)
+ rcswarn("can't change states in an empty tree");
+ else if (strcmp(Head->state, headstate) != 0) {
+ Head->state = headstate;
+ changed = true;
+ }
+ } else
+ changed |= rcs_setstate(Dbranch,headstate);
}
+ for (curstate = statelst; curstate; curstate = curstate->nextstatus)
+ changed |= rcs_setstate(curstate->revno,curstate->status);
- cuthead = cuttail = nil;
+ cuthead = cuttail = 0;
if (delrev.strt && removerevs()) {
/* rebuild delta tree if some deltas are deleted */
if ( cuttail )
- VOID genrevs(cuttail->num, (char *)nil,(char *)nil,
- (char *)nil, &gendeltas);
+ VOID genrevs(
+ cuttail->num, (char *)0, (char *)0, (char *)0,
+ &gendeltas
+ );
buildtree();
+ changed = true;
+ keepRCStime = false;
}
if (nerror)
continue;
- putadmin(frewrite);
+ putadmin();
if ( Head )
puttree(Head, frewrite);
putdesc(textflag,textfile);
if ( Head) {
- if (!delrev.strt && !messagelst) {
- /* No revision was deleted and no message was changed. */
- fastcopy(finptr, frewrite);
- } else {
+ if (delrev.strt || messagelst) {
if (!cuttail || buildeltatext(gendeltas)) {
advise_access(finptr, MADV_SEQUENTIAL);
- scanlogtext((struct hshentry *)nil, false);
+ scanlogtext((struct hshentry *)0, false);
/* copy rest of delta text nodes that are not deleted */
+ changed = true;
}
}
}
- Izclose(&finptr);
- if ( ! nerror ) { /* move temporary file to RCS file if no error */
- /* update mode */
- ignoreints();
- r = chnamemod(&frewrite, newRCSfilename, RCSfilename, RCSmode);
- e = errno;
- keepdirtemp(newRCSfilename);
- restoreints();
- if (r != 0) {
- enerror(e, RCSfilename);
- error("saved in %s", newRCSfilename);
- dirtempunlink();
- break;
- }
- diagnose("done\n");
- } else {
- diagnose("%s aborted; %s unchanged.\n",cmdid,RCSfilename);
- }
- } while (cleanup(),
- ++argv, --argc >=1);
+
+ if (initflag) {
+ /* Adjust things for donerewrite's sake. */
+ if (stat(workname, &RCSstat) != 0) {
+# if bad_creat0
+ mode_t m = umask(0);
+ (void) umask(m);
+ RCSstat.st_mode = (S_IRUSR|S_IRGRP|S_IROTH) & ~m;
+# else
+ changed = -1;
+# endif
+ }
+ RCSstat.st_nlink = 0;
+ keepRCStime = false;
+ }
+ if (donerewrite(changed,
+ keepRCStime ? RCSstat.st_mtime : (time_t)-1
+ ) != 0)
+ break;
+
+ diagnose("done\n");
+ }
tempunlink();
exitmain(exitstatus);
@@ -584,13 +647,14 @@ cleanup()
if (nerror) exitstatus = EXIT_FAILURE;
Izclose(&finptr);
Ozclose(&fcopy);
- Ozclose(&frewrite);
+ ORCSclose();
dirtempunlink();
}
- exiting void
+ void
exiterr()
{
+ ORCSerror();
dirtempunlink();
tempunlink();
_exit(EXIT_FAILURE);
@@ -609,9 +673,10 @@ char * sp;
char const *temp;
int c;
- while( (c=(*++sp)) == ' ' || c == '\t' || c =='\n') ;
+ while ((c = *++sp) == ' ' || c == '\t' || c =='\n')
+ continue;
temp = sp;
- sp = checkid(sp, ':'); /* check for invalid symbolic name */
+ sp = checksym(sp, ':'); /* check for invalid symbolic name */
c = *sp; *sp = '\0';
while( c == ' ' || c == '\t' || c == '\n') c = *++sp;
@@ -624,18 +689,15 @@ char * sp;
pt->ssymbol = temp;
pt->override = flag;
if (c == '\0') /* delete symbol */
- pt->revno = nil;
+ pt->revno = 0;
else {
- while( (c = *++sp) == ' ' || c == '\n' || c == '\t') ;
+ while ((c = *++sp) == ' ' || c == '\n' || c == '\t')
+ continue;
pt->revno = sp;
}
- pt->nextsym = nil;
- if (lastassoc)
- lastassoc->nextsym = pt;
- else
- assoclst = pt;
- lastassoc = pt;
- return;
+ pt->nextsym = 0;
+ *nextassoc = pt;
+ nextassoc = &pt->nextsym;
}
@@ -646,10 +708,11 @@ getchaccess(login, command)
{
register struct chaccess *pt;
- *nextchaccess = pt = talloc(struct chaccess);
+ pt = talloc(struct chaccess);
pt->login = login;
pt->command = command;
- pt->nextchaccess = nil;
+ pt->nextchaccess = 0;
+ *nextchaccess = pt;
nextchaccess = &pt->nextchaccess;
}
@@ -668,10 +731,11 @@ getaccessor(opt, command)
register char *sp;
sp = opt;
- while( ( c = *++sp) == ' ' || c == '\n' || c == '\t' || c == ',') ;
+ while ((c = *++sp) == ' ' || c == '\n' || c == '\t' || c == ',')
+ continue;
if ( c == '\0') {
if (command == erase && sp-opt == 1) {
- getchaccess((char const*)nil, command);
+ getchaccess((char*)0, command);
return;
}
error("missing login name after option -a or -e");
@@ -709,11 +773,8 @@ getmessage(option)
pt->revno = option;
pt->message = cb;
pt->nextmessage = 0;
- if (lastmessage)
- lastmessage->nextmessage = pt;
- else
- messagelst = pt;
- lastmessage = pt;
+ *nextmessage = pt;
+ nextmessage = &pt->nextmessage;
}
@@ -728,7 +789,8 @@ char *sp;
struct Status *pt;
register c;
- while( (c=(*++sp)) ==' ' || c == '\t' || c == '\n') ;
+ while ((c = *++sp) ==' ' || c == '\t' || c == '\n')
+ continue;
temp = sp;
sp = checkid(sp,':'); /* check for invalid state attribute */
c = *sp; *sp = '\0';
@@ -744,16 +806,14 @@ char *sp;
return;
}
- while( (c = *++sp) == ' ' || c == '\t' || c == '\n') ;
+ while ((c = *++sp) == ' ' || c == '\t' || c == '\n')
+ continue;
pt = talloc(struct Status);
pt->status = temp;
pt->revno = sp;
- pt->nextstatus = nil;
- if (laststate)
- laststate->nextstatus = pt;
- else
- statelst = pt;
- laststate = pt;
+ pt->nextstatus = 0;
+ *nextstate = pt;
+ nextstate = &pt->nextstatus;
}
@@ -769,7 +829,8 @@ char *sp;
int separator;
pt = &delrev;
- while((c = (*++sp)) == ' ' || c == '\n' || c == '\t') ;
+ while ((c = (*++sp)) == ' ' || c == '\n' || c == '\t')
+ continue;
/* Support old ambiguous '-' syntax; this will go away. */
if (strchr(sp,':'))
@@ -781,11 +842,12 @@ char *sp;
}
if (c == separator) { /* -o:rev */
- while( (c = (*++sp)) == ' ' || c == '\n' || c == '\t') ;
+ while ((c = (*++sp)) == ' ' || c == '\n' || c == '\t')
+ continue;
pt->strt = sp; pt->code = 1;
while( c != ' ' && c != '\n' && c != '\t' && c != '\0') c =(*++sp);
*sp = '\0';
- pt->end = nil;
+ pt->end = 0;
return;
}
else {
@@ -795,15 +857,18 @@ char *sp;
*sp = '\0';
while( c == ' ' || c == '\n' || c == '\t' ) c = *++sp;
if ( c == '\0' ) { /* -o rev or branch */
- pt->end = nil; pt->code = 0;
+ pt->code = 0;
+ pt->end = 0;
return;
}
if (c != separator) {
- faterror("invalid range %s %s after -o", pt->strt, sp);
+ error("invalid range %s %s after -o", pt->strt, sp);
}
- while( (c = *++sp) == ' ' || c == '\n' || c == '\t') ;
+ while ((c = *++sp) == ' ' || c == '\n' || c == '\t')
+ continue;
if (!c) { /* -orev: */
- pt->end = nil; pt->code = 2;
+ pt->code = 2;
+ pt->end = 0;
return;
}
}
@@ -821,11 +886,11 @@ scanlogtext(delta,edit)
struct hshentry *delta;
int edit;
/* Function: Scans delta text nodes up to and including the one given
- * by delta, or up to last one present, if delta==nil.
- * For the one given by delta (if delta!=nil), the log message is saved into
+ * by delta, or up to last one present, if !delta.
+ * For the one given by delta (if delta), the log message is saved into
* delta->log if delta==cuttail; the text is edited if EDIT is set, else copied.
* Assumes the initial lexeme must be read in first.
- * Does not advance nexttok after it is finished, except if delta==nil.
+ * Does not advance nexttok after it is finished, except if !delta.
*/
{
struct hshentry const *nextdelta;
@@ -835,12 +900,14 @@ scanlogtext(delta,edit)
foutptr = 0;
if (eoflex()) {
if(delta)
- faterror("can't find delta for revision %s", delta->num);
+ rcsfaterror("can't find delta for revision %s",
+ delta->num
+ );
return; /* no more delta text nodes */
}
nextlex();
if (!(nextdelta=getnum()))
- faterror("delta number corrupted");
+ fatserror("delta number corrupted");
if (nextdelta->selector) {
foutptr = frewrite;
aprintf(frewrite,DELNUMFORM,nextdelta->num,Klog);
@@ -850,17 +917,19 @@ scanlogtext(delta,edit)
cb = savestring(&curlogbuf);
if (!delta->log.string)
delta->log = cleanlogmsg(curlogbuf.string, cb.size);
- } else if (nextdelta->log.string && nextdelta->selector) {
- foutptr = 0;
- readstring();
- foutptr = frewrite;
- putstring(foutptr, false, nextdelta->log, true);
- afputc(nextc, foutptr);
- } else {readstring();
- }
- nextlex();
- while (nexttok==ID && strcmp(NextString,Ktext)!=0)
- ignorephrase();
+ nextlex();
+ delta->igtext = getphrases(Ktext);
+ } else {
+ if (nextdelta->log.string && nextdelta->selector) {
+ foutptr = 0;
+ readstring();
+ foutptr = frewrite;
+ putstring(foutptr, false, nextdelta->log, true);
+ afputc(nextc, foutptr);
+ } else
+ readstring();
+ ignorephrases(Ktext);
+ }
getkeystring(Ktext);
if (delta==nextdelta)
@@ -870,74 +939,70 @@ scanlogtext(delta,edit)
}
/* got the one we're looking for */
if (edit)
- editstring((struct hshentry *)nil);
+ editstring((struct hshentry*)0);
else
enterstring();
}
- static struct Lockrev *
+ static struct Lockrev **
rmnewlocklst(which)
- struct Lockrev const *which;
-/* Function: remove lock to revision which->revno from newlocklst */
-
+ char const *which;
+/* Remove lock to revision WHICH from newlocklst. */
{
- struct Lockrev * pt, *pre;
-
- while( newlocklst && (! strcmp(newlocklst->revno, which->revno))){
- struct Lockrev *pn = newlocklst->nextrev;
- tfree(newlocklst);
- newlocklst = pn;
- }
+ struct Lockrev *pt, **pre;
- pt = pre = newlocklst;
- while( pt ) {
- if ( ! strcmp(pt->revno, which->revno) ) {
- pre->nextrev = pt->nextrev;
+ pre = &newlocklst;
+ while ((pt = *pre))
+ if (strcmp(pt->revno, which) != 0)
+ pre = &pt->nextrev;
+ else {
+ *pre = pt->nextrev;
tfree(pt);
- pt = pre->nextrev;
- }
- else {
- pre = pt;
- pt = pt->nextrev;
- }
- }
+ }
return pre;
}
- static void
+ static int
doaccess()
{
register struct chaccess *ch;
register struct access **p, *t;
+ register int changed = false;
for (ch = chaccess; ch; ch = ch->nextchaccess) {
switch (ch->command) {
case erase:
- if (!ch->login)
- AccessList = nil;
- else
- for (p = &AccessList; (t = *p); )
- if (strcmp(ch->login, t->login) == 0)
+ if (!ch->login) {
+ if (AccessList) {
+ AccessList = 0;
+ changed = true;
+ }
+ } else
+ for (p = &AccessList; (t = *p); p = &t->nextaccess)
+ if (strcmp(ch->login, t->login) == 0) {
*p = t->nextaccess;
- else
- p = &t->nextaccess;
+ changed = true;
+ break;
+ }
break;
case append:
for (p = &AccessList; ; p = &t->nextaccess)
if (!(t = *p)) {
*p = t = ftalloc(struct access);
t->login = ch->login;
- t->nextaccess = nil;
+ t->nextaccess = 0;
+ changed = true;
break;
} else if (strcmp(ch->login, t->login) == 0)
break;
break;
}
}
+ return changed;
}
@@ -951,26 +1016,29 @@ sendmail(Delta, who)
{
#ifdef SENDMAIL
char const *messagefile;
- int old1, old2, c;
+ int old1, old2, c, status;
FILE * mailmess;
#endif
aprintf(stderr, "Revision %s is already locked by %s.\n", Delta, who);
+ if (suppress_mail)
+ return true;
if (!yesorno(false, "Do you want to break the lock? [ny](n): "))
return false;
/* go ahead with breaking */
#ifdef SENDMAIL
messagefile = maketemp(0);
- if (!(mailmess = fopen(messagefile, "w"))) {
+ if (!(mailmess = fopenSafer(messagefile, "w+"))) {
efaterror(messagefile);
}
aprintf(mailmess, "Subject: Broken lock on %s\n\nYour lock on revision %s of file %s\nhas been broken by %s for the following reason:\n",
- basename(RCSfilename), Delta, getfullRCSname(), getcaller()
+ basefilename(RCSname), Delta, getfullRCSname(), getcaller()
);
aputs("State the reason for breaking the lock:\n(terminate with single '.' or end of file)\n>> ", stderr);
+ eflush();
old1 = '\n'; old2 = ' ';
for (; ;) {
@@ -984,23 +1052,28 @@ sendmail(Delta, who)
else {
afputc(old1, mailmess);
old2 = old1; old1 = c;
- if (c=='\n') aputs(">> ", stderr);
+ if (c == '\n') {
+ aputs(">> ", stderr);
+ eflush();
+ }
}
}
+ Orewind(mailmess);
+ aflush(mailmess);
+ status = run(fileno(mailmess), (char*)0, SENDMAIL, who, (char*)0);
Ozclose(&mailmess);
-
- if (run(messagefile, (char*)nil, SENDMAIL, who, (char*)nil))
- warn("Mail may have failed."),
-#else
- warn("Mail notification of broken locks is not available."),
+ if (status == 0)
+ return true;
+ warn("Mail failed.");
#endif
- warn("Please tell `%s' why you broke the lock.", who);
+ warn("Mail notification of broken locks is not available.");
+ warn("Please tell `%s' why you broke the lock.", who);
return(true);
}
- static void
+ static int
breaklock(delta)
struct hshentry const *delta;
/* function: Finds the lock held by caller on delta,
@@ -1009,36 +1082,28 @@ breaklock(delta)
* Prints an error message if there is no such lock or error.
*/
{
- register struct lock * next, * trail;
+ register struct rcslock *next, **trail;
char const *num;
- struct lock dummy;
num=delta->num;
- dummy.nextlock=next=Locks;
- trail = &dummy;
- while (next!=nil) {
+ for (trail = &Locks; (next = *trail); trail = &next->nextlock)
if (strcmp(num, next->delta->num) == 0) {
if (
strcmp(getcaller(),next->login) != 0
&& !sendmail(num, next->login)
) {
- error("%s still locked by %s", num, next->login);
- return;
+ rcserror("revision %s still locked by %s",
+ num, next->login
+ );
+ return false;
}
- break; /* exact match */
+ diagnose("%s unlocked\n", next->delta->num);
+ *trail = next->nextlock;
+ next->delta->lockedby = 0;
+ return true;
}
- trail=next;
- next=next->nextlock;
- }
- if (next!=nil) {
- /*found one */
- diagnose("%s unlocked\n",next->delta->num);
- trail->nextlock=next->nextlock;
- next->delta->lockedby=nil;
- Locks=dummy.nextlock;
- } else {
- error("no lock set on revision %s", num);
- }
+ rcserror("no lock set on revision %s", num);
+ return false;
}
@@ -1046,14 +1111,14 @@ breaklock(delta)
static struct hshentry *
searchcutpt(object, length, store)
char const *object;
- unsigned length;
+ int length;
struct hshentries *store;
/* Function: Search store and return entry with number being object. */
-/* cuttail = nil, if the entry is Head; otherwise, cuttail */
+/* cuttail = 0, if the entry is Head; otherwise, cuttail */
/* is the entry point to the one with number being object */
{
- cuthead = nil;
+ cuthead = 0;
while (compartial(store->first->num, object, length)) {
cuthead = store->first;
store = store->rest;
@@ -1073,36 +1138,22 @@ struct hshentry *strt, *tail;
{
struct hshentry *pt;
- struct lock const *lockpt;
- int flag;
-
+ struct rcslock const *lockpt;
- pt = strt;
- flag = false;
- while( pt != tail) {
+ for (pt = strt; pt != tail; pt = pt->next) {
if ( pt->branches ){ /* a branch point */
- flag = true;
- error("can't remove branch point %s", pt->num);
- }
- lockpt = Locks;
- while(lockpt && lockpt->delta != pt)
- lockpt = lockpt->nextlock;
- if ( lockpt ) {
- flag = true;
- error("can't remove locked revision %s",pt->num);
- }
- pt = pt->next;
- }
-
- if ( ! flag ) {
- pt = strt;
- while( pt != tail ) {
- pt->selector = false;
- diagnose("deleting revision %s\n",pt->num);
- pt = pt->next;
+ rcserror("can't remove branch point %s", pt->num);
+ return true;
}
+ for (lockpt = Locks; lockpt; lockpt = lockpt->nextlock)
+ if (lockpt->delta == pt) {
+ rcserror("can't remove locked revision %s", pt->num);
+ return true;
+ }
+ pt->selector = false;
+ diagnose("deleting revision %s\n",pt->num);
}
- return flag;
+ return false;
}
@@ -1111,34 +1162,33 @@ struct hshentry *strt, *tail;
removerevs()
/* Function: get the revision range to be removed, and place the */
/* first revision removed in delstrt, the revision before */
-/* delstrt in cuthead( nil, if delstrt is head), and the */
-/* revision after the last removed revision in cuttail(nil */
+/* delstrt in cuthead (0, if delstrt is head), and the */
+/* revision after the last removed revision in cuttail (0 */
/* if the last is a leaf */
{
struct hshentry *target, *target2, *temp;
- unsigned length;
- int flag;
+ int length;
+ int cmp;
- flag = false;
if (!expandsym(delrev.strt, &numrev)) return 0;
- target = genrevs(numrev.string, (char*)nil, (char*)nil, (char*)nil, &gendeltas);
+ target = genrevs(numrev.string,(char*)0,(char*)0,(char*)0,&gendeltas);
if ( ! target ) return 0;
- if (cmpnum(target->num, numrev.string)) flag = true;
+ cmp = cmpnum(target->num, numrev.string);
length = countnumflds(numrev.string);
if (delrev.code == 0) { /* -o rev or -o branch */
if (length & 1)
temp=searchcutpt(target->num,length+1,gendeltas);
- else if (flag) {
- error("Revision %s doesn't exist.", numrev.string);
+ else if (cmp) {
+ rcserror("Revision %s doesn't exist.", numrev.string);
return 0;
}
else
temp = searchcutpt(numrev.string, length, gendeltas);
cuttail = target->next;
if ( branchpoint(temp, cuttail) ) {
- cuttail = nil;
+ cuttail = 0;
return 0;
}
delstrt = temp; /* first revision to be removed */
@@ -1146,7 +1196,7 @@ removerevs()
}
if (length & 1) { /* invalid branch after -o */
- error("invalid branch range %s after -o", numrev.string);
+ rcserror("invalid branch range %s after -o", numrev.string);
return 0;
}
@@ -1162,7 +1212,7 @@ removerevs()
cuttail = cuttail->next;
}
if ( branchpoint(temp, cuttail) ){
- cuttail = nil;
+ cuttail = 0;
return 0;
}
delstrt = temp;
@@ -1172,23 +1222,23 @@ removerevs()
if (delrev.code == 2) { /* -o rev- */
if ( length == 2 ) {
temp = searchcutpt(target->num, 1,gendeltas);
- if ( flag)
+ if (cmp)
cuttail = target;
else
cuttail = target->next;
}
else {
- if ( flag){
+ if (cmp) {
cuthead = target;
if ( !(temp = target->next) ) return 0;
}
else
temp = searchcutpt(target->num, length, gendeltas);
getbranchno(temp->num, &numrev); /* get branch number */
- target = genrevs(numrev.string, (char*)nil, (char*)nil, (char*)nil, &gendeltas);
+ VOID genrevs(numrev.string, (char*)0, (char*)0, (char*)0, &gendeltas);
}
if ( branchpoint( temp, cuttail ) ) {
- cuttail = nil;
+ cuttail = 0;
return 0;
}
delstrt = temp;
@@ -1199,28 +1249,29 @@ removerevs()
if (!expandsym(delrev.end, &numrev)) return 0;
if (
length != countnumflds(numrev.string)
- || length>2 && compartial(numrev.string, target->num, length-1)
+ || (length>2 && compartial(numrev.string, target->num, length-1))
) {
- error("invalid revision range %s-%s", target->num, numrev.string);
+ rcserror("invalid revision range %s-%s",
+ target->num, numrev.string
+ );
return 0;
}
- target2 = genrevs(numrev.string,(char*)nil,(char*)nil,(char*)nil,&gendeltas);
+ target2 = genrevs(numrev.string,(char*)0,(char*)0,(char*)0,&gendeltas);
if ( ! target2 ) return 0;
if ( length > 2) { /* delete revisions on branches */
if ( cmpnum(target->num, target2->num) > 0) {
- if (cmpnum(target2->num, numrev.string))
- flag = true;
- else
- flag = false;
+ cmp = cmpnum(target2->num, numrev.string);
temp = target;
target = target2;
target2 = temp;
}
- if ( flag ) {
+ if (cmp) {
if ( ! cmpnum(target->num, target2->num) ) {
- error("Revisions %s-%s don't exist.", delrev.strt,delrev.end);
+ rcserror("Revisions %s-%s don't exist.",
+ delrev.strt, delrev.end
+ );
return 0;
}
cuthead = target;
@@ -1237,13 +1288,12 @@ removerevs()
target2 = temp;
}
else
- if (cmpnum(target2->num, numrev.string))
- flag = true;
- else
- flag = false;
- if ( flag ) {
+ cmp = cmpnum(target2->num, numrev.string);
+ if (cmp) {
if ( ! cmpnum(target->num, target2->num) ) {
- error("Revisions %s-%s don't exist.", delrev.strt, delrev.end);
+ rcserror("Revisions %s-%s don't exist.",
+ delrev.strt, delrev.end
+ );
return 0;
}
cuttail = target2;
@@ -1253,7 +1303,7 @@ removerevs()
temp = searchcutpt(target->num, length, gendeltas);
}
if ( branchpoint(temp, cuttail) ) {
- cuttail = nil;
+ cuttail = 0;
return 0;
}
delstrt = temp;
@@ -1262,32 +1312,29 @@ removerevs()
- static void
+ static int
doassoc()
-/* Function: add or delete(if revno is nil) association */
-/* which is stored in assoclst */
-
+/* Add or delete (if !revno) association that is stored in assoclst. */
{
char const *p;
+ int changed = false;
struct Symrev const *curassoc;
- struct assoc * pre, * pt;
+ struct assoc **pre, *pt;
/* add new associations */
- curassoc = assoclst;
- while( curassoc ) {
- if ( curassoc->revno == nil ) { /* delete symbol */
- pre = pt = Symbols;
- while( pt && strcmp(pt->symbol,curassoc->ssymbol) ) {
- pre = pt;
- pt = pt->nextassoc;
- }
- if ( pt )
- if ( pre == pt )
- Symbols = pt->nextassoc;
- else
- pre->nextassoc = pt->nextassoc;
- else
- warn("can't delete nonexisting symbol %s",curassoc->ssymbol);
+ for (curassoc = assoclst; curassoc; curassoc = curassoc->nextsym) {
+ char const *ssymbol = curassoc->ssymbol;
+
+ if (!curassoc->revno) { /* delete symbol */
+ for (pre = &Symbols; ; pre = &pt->nextassoc)
+ if (!(pt = *pre)) {
+ rcswarn("can't delete nonexisting symbol %s", ssymbol);
+ break;
+ } else if (strcmp(pt->symbol, ssymbol) == 0) {
+ *pre = pt->nextassoc;
+ changed = true;
+ break;
+ }
}
else {
if (curassoc->revno[0]) {
@@ -1295,20 +1342,19 @@ doassoc()
if (expandsym(curassoc->revno, &numrev))
p = fstr_save(numrev.string);
} else if (!(p = tiprev()))
- error("no latest revision to associate with symbol %s",
- curassoc->ssymbol
+ rcserror("no latest revision to associate with symbol %s",
+ ssymbol
);
if (p)
- VOID addsymbol(p, curassoc->ssymbol, curassoc->override);
+ changed |= addsymbol(p, ssymbol, curassoc->override);
}
- curassoc = curassoc->nextsym;
}
-
+ return changed;
}
- static void
+ static int
dolocks()
/* Function: remove lock for caller or first lock if unlockcaller is set;
* remove locks which are stored in rmvlocklst,
@@ -1318,64 +1364,60 @@ dolocks()
{
struct Lockrev const *lockpt;
struct hshentry *target;
+ int changed = false;
if (unlockcaller) { /* find lock for caller */
if ( Head ) {
if (Locks) {
switch (findlock(true, &target)) {
case 0:
- breaklock(Locks->delta); /* remove most recent lock */
+ /* remove most recent lock */
+ changed |= breaklock(Locks->delta);
break;
case 1:
diagnose("%s unlocked\n",target->num);
+ changed = true;
break;
}
} else {
- warn("No locks are set.");
+ rcswarn("No locks are set.");
}
} else {
- warn("can't unlock an empty tree");
+ rcswarn("can't unlock an empty tree");
}
}
/* remove locks which are stored in rmvlocklst */
- lockpt = rmvlocklst;
- while( lockpt ) {
+ for (lockpt = rmvlocklst; lockpt; lockpt = lockpt->nextrev)
if (expandsym(lockpt->revno, &numrev)) {
- target = genrevs(numrev.string, (char *)nil, (char *)nil, (char *)nil, &gendeltas);
+ target = genrevs(numrev.string, (char *)0, (char *)0, (char *)0, &gendeltas);
if ( target )
if (!(countnumflds(numrev.string)&1) && cmpnum(target->num,numrev.string))
- error("can't unlock nonexisting revision %s",lockpt->revno);
+ rcserror("can't unlock nonexisting revision %s",
+ lockpt->revno
+ );
else
- breaklock(target);
+ changed |= breaklock(target);
/* breaklock does its own diagnose */
}
- lockpt = lockpt->nextrev;
- }
/* add new locks which stored in newlocklst */
- lockpt = newlocklst;
- while( lockpt ) {
- setlock(lockpt->revno);
- lockpt = lockpt->nextrev;
- }
-
- if (lockhead) { /* lock default branch or head */
- if (Dbranch) {
- setlock(Dbranch);
- } else if (Head) {
- if (0 <= addlock(Head))
- diagnose("%s locked\n",Head->num);
- } else {
- warn("can't lock an empty tree");
- }
- }
-
+ for (lockpt = newlocklst; lockpt; lockpt = lockpt->nextrev)
+ changed |= setlock(lockpt->revno);
+
+ if (lockhead) /* lock default branch or head */
+ if (Dbranch)
+ changed |= setlock(Dbranch);
+ else if (Head)
+ changed |= setlock(Head->num);
+ else
+ rcswarn("can't lock an empty tree");
+ return changed;
}
- static void
+ static int
setlock(rev)
char const *rev;
/* Function: Given a revision or branch number, finds the corresponding
@@ -1383,25 +1425,36 @@ setlock(rev)
*/
{
struct hshentry *target;
+ int r;
if (expandsym(rev, &numrev)) {
- target = genrevs(numrev.string, (char*)nil, (char*)nil,
- (char*)nil, &gendeltas);
+ target = genrevs(numrev.string, (char*)0, (char*)0,
+ (char*)0, &gendeltas);
if ( target )
if (!(countnumflds(numrev.string)&1) && cmpnum(target->num,numrev.string))
- error("can't lock nonexisting revision %s", numrev.string);
- else
- if (0 <= addlock(target))
- diagnose("%s locked\n", target->num);
- }
+ rcserror("can't lock nonexisting revision %s",
+ numrev.string
+ );
+ else {
+ if ((r = addlock(target, false)) < 0 && breaklock(target))
+ r = addlock(target, true);
+ if (0 <= r) {
+ if (r)
+ diagnose("%s locked\n", target->num);
+ return r;
+ }
+ }
+ }
+ return 0;
}
- static void
+ static int
domessages()
{
struct hshentry *target;
struct Message *p;
+ int changed = false;
for (p = messagelst; p; p = p->nextmessage)
if (
@@ -1409,12 +1462,19 @@ domessages()
(target = genrevs(
numrev.string, (char*)0, (char*)0, (char*)0, &gendeltas
))
- )
+ ) {
+ /*
+ * We can't check the old log -- it's much later in the file.
+ * We pessimistically assume that it changed.
+ */
target->log = p->message;
+ changed = true;
+ }
+ return changed;
}
- static void
+ static int
rcs_setstate(rev,status)
char const *rev, *status;
/* Function: Given a revision or branch number, finds the corresponding delta
@@ -1424,15 +1484,19 @@ rcs_setstate(rev,status)
struct hshentry *target;
if (expandsym(rev, &numrev)) {
- target = genrevs(numrev.string, (char*)nil, (char*)nil,
- (char*)nil, &gendeltas);
+ target = genrevs(numrev.string, (char*)0, (char*)0,
+ (char*)0, &gendeltas);
if ( target )
if (!(countnumflds(numrev.string)&1) && cmpnum(target->num,numrev.string))
- error("can't set state of nonexisting revision %s to %s",
- numrev.string, status);
- else
+ rcserror("can't set state of nonexisting revision %s",
+ numrev.string
+ );
+ else if (strcmp(target->state, status) != 0) {
target->state = status;
- }
+ return true;
+ }
+ }
+ return false;
}
@@ -1446,15 +1510,15 @@ buildeltatext(deltas)
/* change to delta text */
{
register FILE *fcut; /* temporary file to rebuild delta tree */
- char const *cutfilename, *diffilename;
+ char const *cutname;
- cutfilename = nil;
+ fcut = 0;
cuttail->selector = false;
scanlogtext(deltas->first, false);
if ( cuthead ) {
- cutfilename = maketemp(3);
- if (!(fcut = fopen(cutfilename, FOPEN_W_WORK))) {
- efaterror(cutfilename);
+ cutname = maketemp(3);
+ if (!(fcut = fopenSafer(cutname, FOPEN_WPLUS_WORK))) {
+ efaterror(cutname);
}
while (deltas->first != cuthead) {
@@ -1463,25 +1527,36 @@ buildeltatext(deltas)
}
snapshotedit(fcut);
- Ofclose(fcut);
+ Orewind(fcut);
+ aflush(fcut);
}
while (deltas->first != cuttail)
scanlogtext((deltas = deltas->rest)->first, true);
- finishedit((struct hshentry *)nil, (FILE*)0, true);
+ finishedit((struct hshentry*)0, (FILE*)0, true);
Ozclose(&fcopy);
- if ( cuthead ) {
- diffilename = maketemp(0);
- switch (run((char*)nil,diffilename,
- DIFF DIFF_FLAGS, cutfilename, resultfile, (char*)nil
- )) {
+ if (fcut) {
+ char const *diffname = maketemp(0);
+ char const *diffv[6 + !!OPEN_O_BINARY];
+ char const **diffp = diffv;
+ *++diffp = DIFF;
+ *++diffp = DIFFFLAGS;
+# if OPEN_O_BINARY
+ if (Expand == BINARY_EXPAND)
+ *++diffp == "--binary";
+# endif
+ *++diffp = "-";
+ *++diffp = resultname;
+ *++diffp = 0;
+ switch (runv(fileno(fcut), diffname, diffv)) {
case DIFF_FAILURE: case DIFF_SUCCESS: break;
- default: faterror ("diff failed");
+ default: rcsfaterror("diff failed");
}
- return putdtext(cuttail->num,cuttail->log,diffilename,frewrite,true);
+ Ofclose(fcut);
+ return putdtext(cuttail,diffname,frewrite,true);
} else
- return putdtext(cuttail->num,cuttail->log,resultfile,frewrite,false);
+ return putdtext(cuttail,resultname,frewrite,false);
}
@@ -1512,9 +1587,9 @@ buildtree()
pre->nextbranch = pt->nextbranch;
}
else {
- if ( cuttail == nil && !quietflag) {
+ if (!cuttail && !quietflag) {
if (!yesorno(false, "Do you really want to delete all revisions? [ny](n): ")) {
- error("No revision deleted");
+ rcserror("No revision deleted");
Delta = delstrt;
while( Delta) {
Delta->selector = true;
@@ -1528,7 +1603,7 @@ buildtree()
return;
}
-#if lint
+#if RCS_lint
/* This lets us lint everything all at once. */
char const cmdid[] = "";
diff --git a/gnu/usr.bin/rcs/rcs/rcsfile.5 b/gnu/usr.bin/rcs/rcs/rcsfile.5
index d0dbbb8..5a1929f 100644
--- a/gnu/usr.bin/rcs/rcs/rcsfile.5
+++ b/gnu/usr.bin/rcs/rcs/rcsfile.5
@@ -1,8 +1,11 @@
+.lf 1 ./rcsfile.5in
+.\" Set p to 1 if your formatter can handle pic output.
+.if t .nr p 1
.de Id
.ds Rv \\$3
.ds Dt \\$4
..
-.Id $Id: rcsfile.5,v 5.1 1991/08/19 03:13:55 eggert Exp $
+.Id $Id: rcsfile.5in,v 5.6 1995/06/05 08:28:35 eggert Exp $
.ds r \s-1RCS\s0
.if n .ds - \%--
.if t .ds - \(em
@@ -18,39 +21,43 @@ The text is free format: space, backspace, tab, newline, vertical
tab, form feed, and carriage return (collectively,
.IR "white space")
have no significance except in strings.
-However, an \*r file must end in a newline character.
+However, white space cannot appear within an id, num, or sym,
+and an \*r file must end with a newline.
.PP
Strings are enclosed by
.BR @ .
If a string contains a
.BR @ ,
it must be doubled;
-otherwise, strings may contain arbitrary binary data.
+otherwise, strings can contain arbitrary binary data.
.PP
The meta syntax uses the following conventions: `|' (bar) separates
alternatives; `{' and `}' enclose optional phrases; `{' and `}*' enclose
-phrases that may be repeated zero or more times;
-`{' and '}+' enclose phrases that must appear at least once and may be
+phrases that can be repeated zero or more times;
+`{' and '}+' enclose phrases that must appear at least once and can be
repeated;
Terminal symbols are in
.BR boldface ;
nonterminal symbols are in
.IR italics .
.LP
+.nr w \w'\f3deltatext\fP '
+.nr y \w'\f3newphrase\fP '
+.if \nw<\ny .nr w \ny
.nr x \w'\f3branches\fP'
.nr y \w'{ \f3comment\fP'
.if \nx<\ny .nr x \ny
.nr y \w'\f3{ branch\fP'
.if \nx<\ny .nr x \ny
-.ta \w'\f2deltatext\fP 'u +\w'::= 'u +\nxu+\w' 'u
-.fc ~
+.ta \nwu +\w'::= 'u +\nxu+\w' 'u
+.fc #
.nf
\f2rcstext\fP ::= \f2admin\fP {\f2delta\fP}* \f2desc\fP {\f2deltatext\fP}*
.LP
\f2admin\fP ::= \f3head\fP {\f2num\fP}\f3;\fP
{ \f3branch\fP {\f2num\fP}\f3;\fP }
\f3access\fP {\f2id\fP}*\f3;\fP
- \f3symbols\fP {\f2id\fP \f3:\fP \f2num\fP}*\f3;\fP
+ \f3symbols\fP {\f2sym\fP \f3:\fP \f2num\fP}*\f3;\fP
\f3locks\fP {\f2id\fP \f3:\fP \f2num\fP}*\f3;\fP {\f3strict ;\fP}
{ \f3comment\fP {\f2string\fP}\f3;\fP }
{ \f3expand\fP {\f2string\fP}\f3;\fP }
@@ -71,13 +78,13 @@ nonterminal symbols are in
{ \f2newphrase\fP }*
\f3text\fP \f2string\fP
.LP
-\f2num\fP ::= {\f2digit\fP{\f3.\fP}}+
+\f2num\fP ::= {\f2digit\fP | \f3.\fP}+
.LP
-\f2digit\fP ::= \f30\fP | \f31\fP | .\|.\|. | \f39\fP
+\f2digit\fP ::= \f30\fP | \f31\fP | \f32\fP | \f33\fP | \f34\fP | \f35\fP | \f36\fP | \f37\fP | \f38\fP | \f39\fP
.LP
-\f2id\fP ::= \f2letter\fP{\f2idchar\fP}*
+\f2id\fP ::= {\f2num\fP} \f2idchar\fP {\f2idchar\fP | \f2num\fP}*
.LP
-\f2letter\fP ::= any letter
+\f2sym\fP ::= {\f2digit\fP}* \f2idchar\fP {\f2idchar\fP | \f2digit\fP}*
.LP
\f2idchar\fP ::= any visible graphic character except \f2special\fP
.LP
@@ -91,12 +98,35 @@ nonterminal symbols are in
.fi
.PP
Identifiers are case sensitive. Keywords are in lower case only.
-The sets of keywords and identifiers may overlap.
-In most environments RCS uses the ISO 8859/1 encoding:
-letters are octal codes 101\-132, 141\-172, 300\-326, 330\-366 and 370-377,
+The sets of keywords and identifiers can overlap.
+In most environments \*r uses the \s-1ISO\s0 8859/1 encoding:
visible graphic characters are codes 041\-176 and 240\-377,
and white space characters are codes 010\-015 and 040.
.PP
+Dates, which appear after the
+.B date
+keyword, are of the form
+\f2Y\fP\f3.\fP\f2mm\fP\f3.\fP\f2dd\fP\f3.\fP\f2hh\fP\f3.\fP\f2mm\fP\f3.\fP\f2ss\fP,
+where
+.I Y
+is the year,
+.I mm
+the month (01\-12),
+.I dd
+the day (01\-31),
+.I hh
+the hour (00\-23),
+.I mm
+the minute (00\-59),
+and
+.I ss
+the second (00\-60).
+.I Y
+contains just the last two digits of the year
+for years from 1900 through 1999,
+and all the digits of years thereafter.
+Dates use the Gregorian calendar; times use UTC.
+.PP
The
.I newphrase
productions in the grammar are reserved for future extensions
@@ -131,7 +161,7 @@ All
nodes whose numbers consist of
.RI 2 n
fields
-.RI ( n >=2)
+.RI ( n \(>=2)
(e.g., 3.1.1.1, 2.1.2.2, etc.)
are linked as follows.
All nodes whose first
@@ -151,11 +181,11 @@ field of a node contains a list of the
numbers of the first nodes of all sequences for which it is a branchpoint.
This list is ordered in increasing numbers.
.LP
+The following diagram shows an example of an \*r file's organization.
+.if !\np \{\
.nf
.vs 12
-.ne 38
-Example:
-.if t .in +0.5i
+.ne 36
.cs 1 20
.eo
@@ -195,12 +225,183 @@ Example:
\ /
.ec
-.if t .in
.cs 1
-.ce
-Fig. 1: A revision tree
.vs
.fi
+.\}
+.if \np \{\
+.lf 232
+.PS 4.250i 3.812i
+.\" -2.0625 -4.25 1.75 0
+.\" 0.000i 4.250i 3.812i 0.000i
+.nr 00 \n(.u
+.nf
+.nr 0x 1
+\h'3.812i'
+.sp -1
+.lf 242
+\h'2.062i-(\w'Head'u/2u)'\v'0.125i-(0v/2u)+0v+0.22m'Head
+.sp -1
+\h'2.062i'\v'0.250i'\D'l0.000i 0.500i'
+.sp -1
+\h'2.087i'\v'0.650i'\D'l-0.025i 0.100i'
+.sp -1
+\h'2.062i'\v'0.750i'\D'l-0.025i -0.100i'
+.sp -1
+\h'1.688i'\v'1.250i'\D'l0.750i 0.000i'
+.sp -1
+\h'2.438i'\v'1.250i'\D'l0.000i -0.500i'
+.sp -1
+\h'2.438i'\v'0.750i'\D'l-0.750i 0.000i'
+.sp -1
+\h'1.688i'\v'0.750i'\D'l0.000i 0.500i'
+.sp -1
+.lf 244
+\h'2.062i-(\w'2.1'u/2u)'\v'1.000i-(0v/2u)+0v+0.22m'2.1
+.sp -1
+\h'2.062i'\v'1.250i'\D'l0.000i 0.500i'
+.sp -1
+\h'2.087i'\v'1.650i'\D'l-0.025i 0.100i'
+.sp -1
+\h'2.062i'\v'1.750i'\D'l-0.025i -0.100i'
+.sp -1
+.lf 246
+\h'2.062i-(\w'1.3'u/2u)'\v'2.000i-(1v/2u)+0v+0.22m'1.3
+.sp -1
+\h'2.062i'\v'2.250i'\D'l-0.375i -0.500i'
+.sp -1
+\h'1.688i'\v'1.750i'\D'l0.750i 0.000i'
+.sp -1
+\h'2.438i'\v'1.750i'\D'l-0.375i 0.500i'
+.sp -1
+\h'1.875i'\v'2.000i'\D'~-0.500i 0.000i 0.000i -0.500i'
+.sp -1
+\h'1.350i'\v'1.600i'\D'l0.025i -0.100i'
+.sp -1
+\h'1.375i'\v'1.500i'\D'l0.025i 0.100i'
+.sp -1
+.lf 249
+\h'1.375i-(\w'1.3.1.1'u/2u)'\v'1.250i-(1v/2u)+1v+0.22m'1.3.1.1
+.sp -1
+\h'1.375i'\v'1.000i'\D'l-0.375i 0.500i'
+.sp -1
+\h'1.000i'\v'1.500i'\D'l0.750i 0.000i'
+.sp -1
+\h'1.750i'\v'1.500i'\D'l-0.375i -0.500i'
+.sp -1
+\h'2.062i'\v'2.250i'\D'l0.000i 0.500i'
+.sp -1
+\h'2.087i'\v'2.650i'\D'l-0.025i 0.100i'
+.sp -1
+\h'2.062i'\v'2.750i'\D'l-0.025i -0.100i'
+.sp -1
+.lf 252
+\h'2.062i-(\w'1.2'u/2u)'\v'3.000i-(1v/2u)+0v+0.22m'1.2
+.sp -1
+\h'2.062i'\v'3.250i'\D'l-0.375i -0.500i'
+.sp -1
+\h'1.688i'\v'2.750i'\D'l0.750i 0.000i'
+.sp -1
+\h'2.438i'\v'2.750i'\D'l-0.375i 0.500i'
+.sp -1
+\h'1.875i'\v'3.000i'\D'~-0.500i 0.000i -0.500i 0.000i -0.500i 0.000i 0.000i -0.500i'
+.sp -1
+\h'0.350i'\v'2.600i'\D'l0.025i -0.100i'
+.sp -1
+\h'0.375i'\v'2.500i'\D'l0.025i 0.100i'
+.sp -1
+.lf 255
+\h'0.375i-(\w'1.2.1.1'u/2u)'\v'2.250i-(1v/2u)+1v+0.22m'1.2.1.1
+.sp -1
+\h'0.375i'\v'2.000i'\D'l-0.375i 0.500i'
+.sp -1
+\h'0.000i'\v'2.500i'\D'l0.750i 0.000i'
+.sp -1
+\h'0.750i'\v'2.500i'\D'l-0.375i -0.500i'
+.sp -1
+\h'0.375i'\v'2.000i'\D'l0.000i -0.500i'
+.sp -1
+\h'0.350i'\v'1.600i'\D'l0.025i -0.100i'
+.sp -1
+\h'0.375i'\v'1.500i'\D'l0.025i 0.100i'
+.sp -1
+.lf 257
+\h'0.375i-(\w'1.2.1.3'u/2u)'\v'1.250i-(1v/2u)+1v+0.22m'1.2.1.3
+.sp -1
+\h'0.375i'\v'1.000i'\D'l-0.375i 0.500i'
+.sp -1
+\h'0.000i'\v'1.500i'\D'l0.750i 0.000i'
+.sp -1
+\h'0.750i'\v'1.500i'\D'l-0.375i -0.500i'
+.sp -1
+\h'2.250i'\v'3.000i'\D'~0.500i 0.000i 0.000i -0.500i'
+.sp -1
+\h'2.725i'\v'2.600i'\D'l0.025i -0.100i'
+.sp -1
+\h'2.750i'\v'2.500i'\D'l0.025i 0.100i'
+.sp -1
+.lf 261
+\h'2.750i-(\w'1.2.2.1'u/2u)'\v'2.250i-(1v/2u)+1v+0.22m'1.2.2.1
+.sp -1
+\h'2.750i'\v'2.000i'\D'l-0.375i 0.500i'
+.sp -1
+\h'2.375i'\v'2.500i'\D'l0.750i 0.000i'
+.sp -1
+\h'3.125i'\v'2.500i'\D'l-0.375i -0.500i'
+.sp -1
+\h'2.938i'\v'2.250i'\D'~0.500i 0.000i 0.000i -0.500i 0.000i -0.500i'
+.sp -1
+\h'3.413i'\v'1.350i'\D'l0.025i -0.100i'
+.sp -1
+\h'3.438i'\v'1.250i'\D'l0.025i 0.100i'
+.sp -1
+.lf 264
+\h'3.438i-(\w'\s-21.2.2.1.1.1\s0'u/2u)'\v'1.000i-(1v/2u)+1v+0.22m'\s-21.2.2.1.1.1\s0
+.sp -1
+\h'3.438i'\v'0.750i'\D'l-0.375i 0.500i'
+.sp -1
+\h'3.062i'\v'1.250i'\D'l0.750i 0.000i'
+.sp -1
+\h'3.812i'\v'1.250i'\D'l-0.375i -0.500i'
+.sp -1
+\h'2.750i'\v'2.000i'\D'l0.000i -0.500i'
+.sp -1
+\h'2.725i'\v'1.600i'\D'l0.025i -0.100i'
+.sp -1
+\h'2.750i'\v'1.500i'\D'l0.025i 0.100i'
+.sp -1
+.lf 267
+\h'2.750i-(\w'1.2.2.2'u/2u)'\v'1.250i-(1v/2u)+1v+0.22m'1.2.2.2
+.sp -1
+\h'2.750i'\v'1.000i'\D'l-0.375i 0.500i'
+.sp -1
+\h'2.375i'\v'1.500i'\D'l0.750i 0.000i'
+.sp -1
+\h'3.125i'\v'1.500i'\D'l-0.375i -0.500i'
+.sp -1
+\h'2.062i'\v'3.250i'\D'l0.000i 0.500i'
+.sp -1
+\h'2.087i'\v'3.650i'\D'l-0.025i 0.100i'
+.sp -1
+\h'2.062i'\v'3.750i'\D'l-0.025i -0.100i'
+.sp -1
+.lf 270
+\h'2.062i-(\w'1.1'u/2u)'\v'4.000i-(1v/2u)+0v+0.22m'1.1
+.sp -1
+\h'2.062i'\v'4.250i'\D'l-0.375i -0.500i'
+.sp -1
+\h'1.688i'\v'3.750i'\D'l0.750i 0.000i'
+.sp -1
+\h'2.438i'\v'3.750i'\D'l-0.375i 0.500i'
+.sp -1
+.sp 4.250i+1
+.if \n(00 .fi
+.br
+.nr 0x 0
+.lf 271
+.PE
+.lf 272
+.\}
.PP
.SH IDENTIFICATION
.de VL
@@ -209,13 +410,14 @@ Fig. 1: A revision tree
Author: Walter F. Tichy,
Purdue University, West Lafayette, IN, 47907.
.br
-Revision Number: \*(Rv; Release Date: \*(Dt.
+Manual Page Revision: \*(Rv; Release Date: \*(Dt.
.br
-Copyright \(co 1982, 1988, 1989 by Walter F. Tichy.
+Copyright \(co 1982, 1988, 1989 Walter F. Tichy.
.br
-Copyright \(co 1990, 1991 by Paul Eggert.
+Copyright \(co 1990, 1991, 1992, 1993, 1994, 1995 Paul Eggert.
.SH SEE ALSO
-ci(1), co(1), ident(1), rcs(1), rcsdiff(1), rcsmerge(1), rlog(1),
+rcsintro(1), ci(1), co(1), ident(1), rcs(1), rcsclean(1), rcsdiff(1),
+rcsmerge(1), rlog(1)
.br
Walter F. Tichy,
\*r\*-A System for Version Control,
diff --git a/gnu/usr.bin/rcs/rcs/rcsintro.1 b/gnu/usr.bin/rcs/rcs/rcsintro.1
index a76caa0..fa97043 100644
--- a/gnu/usr.bin/rcs/rcs/rcsintro.1
+++ b/gnu/usr.bin/rcs/rcs/rcsintro.1
@@ -2,10 +2,20 @@
.ds Rv \\$3
.ds Dt \\$4
..
-.Id $Id: rcsintro.1,v 5.1 1991/04/21 12:00:46 eggert Exp $
+.Id $Id: rcsintro.1,v 5.3 1993/11/03 17:42:27 eggert Exp $
.ds r \&\s-1RCS\s0
.if n .ds - \%--
.if t .ds - \(em
+.if !\n(.g \{\
+. if !\w|\*(lq| \{\
+. ds lq ``
+. if \w'\(lq' .ds lq "\(lq
+. \}
+. if !\w|\*(rq| \{\
+. ds rq ''
+. if \w'\(rq' .ds rq "\(rq
+. \}
+.\}
.am SS
.LP
..
@@ -276,11 +286,11 @@ details.
.SH IDENTIFICATION
Author: Walter F. Tichy.
.br
-Revision Number: \*(Rv; Release Date: \*(Dt.
+Manual Page Revision: \*(Rv; Release Date: \*(Dt.
.br
-Copyright \(co 1982, 1988, 1989 by Walter F. Tichy.
+Copyright \(co 1982, 1988, 1989 Walter F. Tichy.
.br
-Copyright \(co 1990, 1991 by Paul Eggert.
+Copyright \(co 1990, 1991, 1992, 1993 Paul Eggert.
.SH "SEE ALSO"
ci(1), co(1), ident(1), rcs(1), rcsdiff(1), rcsintro(1), rcsmerge(1), rlog(1)
.br
diff --git a/gnu/usr.bin/rcs/rcsclean/Makefile b/gnu/usr.bin/rcs/rcsclean/Makefile
index fc0c626..fe538a0 100644
--- a/gnu/usr.bin/rcs/rcsclean/Makefile
+++ b/gnu/usr.bin/rcs/rcsclean/Makefile
@@ -1,7 +1,8 @@
-PROG= rcsclean
-
-SRCS= rcsclean.c
-LDADD= -L${.CURDIR}/../lib/obj -lrcs
+PROG= rcsclean
+SRCS= rcsclean.c
CFLAGS+= -I${.CURDIR}/../lib
+LDADD= ${LIBRCS}
+DPADD= ${LIBRCS}
+.include "../../Makefile.inc"
.include <bsd.prog.mk>
diff --git a/gnu/usr.bin/rcs/rcsclean/rcsclean.1 b/gnu/usr.bin/rcs/rcsclean/rcsclean.1
index 07ed722..be58c94 100644
--- a/gnu/usr.bin/rcs/rcsclean/rcsclean.1
+++ b/gnu/usr.bin/rcs/rcsclean/rcsclean.1
@@ -2,7 +2,7 @@
.ds Rv \\$3
.ds Dt \\$4
..
-.Id $Id: rcsclean.1,v 1.8 1991/11/03 01:09:19 eggert Exp $
+.Id $Id: rcsclean.1,v 1.12 1993/11/03 17:42:27 eggert Exp $
.ds r \&\s-1RCS\s0
.if n .ds - \%--
.if t .ds - \(em
@@ -14,7 +14,11 @@ rcsclean \- clean up working files
.RI [ options "] [ " file " .\|.\|. ]"
.SH DESCRIPTION
.B rcsclean
-removes working files that were checked out and never modified.
+removes files that are not being worked on.
+.B "rcsclean \-u"
+also unlocks and removes files that are being worked on
+but have not changed.
+.PP
For each
.I file
given,
@@ -32,13 +36,13 @@ and
.B "rm \-f"
commands on the standard output.
.PP
+Files are paired as explained in
+.BR ci (1).
If no
.I file
is given, all working files in the current directory are cleaned.
Pathnames matching an \*r suffix denote \*r files;
all others denote working files.
-Names are paired as explained in
-.BR ci (1).
.PP
The number of the revision to which the working file is compared
may be attached to any of the options
@@ -58,15 +62,15 @@ uses the latest revision on the default branch, normally the root.
.B rcsclean
is useful for
.B clean
-targets in Makefiles.
+targets in makefiles.
See also
.BR rcsdiff (1),
which prints out the differences,
and
.BR ci (1),
which
-normally asks whether to check in a file
-if it was not changed.
+normally reverts to the previous revision
+if a file was not changed.
.SH OPTIONS
.TP
.BI \-k subst
@@ -89,9 +93,22 @@ Do not log the actions taken on standard output.
.BR \-r [\f2rev\fP]
This option has no effect other than specifying the revision for comparison.
.TP
+.B \-T
+Preserve the modification time on the \*r file
+even if the \*r file changes because a lock is removed.
+This option can suppress extensive recompilation caused by a
+.BR make (1)
+dependency of some other copy of the working file on the \*r file.
+Use this option with care; it can suppress recompilation even when it is needed,
+i.e. when the lock removal
+would mean a change to keyword strings in the other working file.
+.TP
.BR \-u [\f2rev\fP]
Unlock the revision if it is locked and no difference is found.
.TP
+.BI \-V
+Print \*r's version number.
+.TP
.BI \-V n
Emulate \*r version
.IR n .
@@ -106,6 +123,14 @@ to characterize \*r files.
See
.BR ci (1)
for details.
+.TP
+.BI \-z zone
+Use
+.I zone
+as the time zone for keyword substitution;
+see
+.BR co (1)
+for details.
.SH EXAMPLES
.LP
.RS
@@ -147,19 +172,20 @@ Useful
options include
.BR \-q ,
.BR \-V ,
+.BR \-x ,
and
-.BR \-x .
+.BR \-z .
.SH DIAGNOSTICS
The exit status is zero if and only if all operations were successful.
Missing working files and \*r files are silently ignored.
.SH IDENTIFICATION
Author: Walter F. Tichy.
.br
-Revision Number: \*(Rv; Release Date: \*(Dt.
+Manual Page Revision: \*(Rv; Release Date: \*(Dt.
.br
-Copyright \(co 1982, 1988, 1989 by Walter F. Tichy.
+Copyright \(co 1982, 1988, 1989 Walter F. Tichy.
.br
-Copyright \(co 1990, 1991 by Paul Eggert.
+Copyright \(co 1990, 1991, 1992, 1993 Paul Eggert.
.SH "SEE ALSO"
ci(1), co(1), ident(1), rcs(1), rcsdiff(1), rcsintro(1), rcsmerge(1), rlog(1),
rcsfile(5)
diff --git a/gnu/usr.bin/rcs/rcsclean/rcsclean.c b/gnu/usr.bin/rcs/rcsclean/rcsclean.c
index ba24ab7..3d8ecd3 100644
--- a/gnu/usr.bin/rcs/rcsclean/rcsclean.c
+++ b/gnu/usr.bin/rcs/rcsclean/rcsclean.c
@@ -1,6 +1,6 @@
-/* rcsclean - clean up working files */
+/* Clean up working files. */
-/* Copyright 1991 by Paul Eggert
+/* Copyright 1991, 1992, 1993, 1994, 1995 Paul Eggert
Distributed under license by the Free Software Foundation, Inc.
This file is part of RCS.
@@ -16,8 +16,9 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
-along with RCS; see the file COPYING. If not, write to
-the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+along with RCS; see the file COPYING.
+If not, write to the Free Software Foundation,
+59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
Report problems and direct all questions to:
@@ -37,16 +38,17 @@ static void cleanup P((void));
static RILE *workptr;
static int exitstatus;
-mainProg(rcscleanId, "rcsclean", "$Id: rcsclean.c,v 5.1 1991/11/03 01:11:44 eggert Exp $")
+mainProg(rcscleanId, "rcsclean", "$Id: rcsclean.c,v 5.9 1995/06/16 06:19:24 eggert Exp $")
{
static char const usage[] =
- "\nrcsclean: usage: rcsclean [-ksubst] [-{nqru}[rev]] [-Vn] [-xsuffixes] [file ...]";
+ "\nrcsclean: usage: rcsclean -ksubst -{nqru}[rev] -T -Vn -xsuff -zzone file ...";
static struct buf revision;
char *a, **newargv;
char const *rev, *p;
- int changelock, expmode, perform, unlocked, unlockflag, waslocked;
+ int dounlock, expmode, perform, unlocked, unlockflag, waslocked;
+ int Ttimeflag;
struct hshentries *deltas;
struct hshentry *delta;
struct stat workstat;
@@ -54,25 +56,26 @@ mainProg(rcscleanId, "rcsclean", "$Id: rcsclean.c,v 5.1 1991/11/03 01:11:44 egge
setrid();
expmode = -1;
- rev = nil;
+ rev = 0;
suffixes = X_DEFAULT;
perform = true;
unlockflag = false;
+ Ttimeflag = false;
argc = getRCSINIT(argc, argv, &newargv);
argv = newargv;
for (;;) {
- if (--argc <= 0) {
+ if (--argc < 1) {
# if has_dirent
argc = get_directory(".", &newargv);
argv = newargv;
break;
# else
- faterror("no file names specified");
+ faterror("no pathnames specified");
# endif
}
a = *++argv;
- if (*a++ != '-')
+ if (!*a || *a++ != '-')
break;
switch (*a++) {
case 'k':
@@ -98,6 +101,12 @@ mainProg(rcscleanId, "rcsclean", "$Id: rcsclean.c,v 5.1 1991/11/03 01:11:44 egge
}
break;
+ case 'T':
+ if (*a)
+ goto unknown;
+ Ttimeflag = true;
+ break;
+
case 'u':
unlockflag = true;
goto handle_revision;
@@ -110,25 +119,42 @@ mainProg(rcscleanId, "rcsclean", "$Id: rcsclean.c,v 5.1 1991/11/03 01:11:44 egge
suffixes = a;
break;
+ case 'z':
+ zone_set(a);
+ break;
+
default:
unknown:
- faterror("unknown option: %s%s", *argv, usage);
+ error("unknown option: %s%s", *argv, usage);
}
}
- do {
+ dounlock = perform & unlockflag;
+
+ if (nerror)
+ cleanup();
+ else
+ for (; 0 < argc; cleanup(), ++argv, --argc) {
+
ffree();
if (!(
- 0 < pairfilenames(
+ 0 < pairnames(
argc, argv,
- unlockflag&perform ? rcswriteopen : rcsreadopen,
+ dounlock ? rcswriteopen : rcsreadopen,
true, true
) &&
- (workptr = Iopen(workfilename,FOPEN_R_WORK,&workstat))
+ (workptr = Iopen(workname, FOPEN_R_WORK, &workstat))
))
continue;
+ if (same_file(RCSstat, workstat, 0)) {
+ rcserror("RCS file is the same as working file %s.",
+ workname
+ );
+ continue;
+ }
+
gettree();
p = 0;
@@ -155,11 +181,13 @@ mainProg(rcscleanId, "rcsclean", "$Id: rcsclean.c,v 5.1 1991/11/03 01:11:44 egge
waslocked = delta && delta->lockedby;
locker_expansion = unlock(delta);
unlocked = locker_expansion & unlockflag;
- changelock = unlocked & perform;
if (unlocked<waslocked && workstat.st_mode&(S_IWUSR|S_IWGRP|S_IWOTH))
continue;
- if (!dorewrite(unlockflag, changelock))
+ if (unlocked && !checkaccesslist())
+ continue;
+
+ if (dorewrite(dounlock, unlocked) != 0)
continue;
if (0 <= expmode)
@@ -174,31 +202,33 @@ mainProg(rcscleanId, "rcsclean", "$Id: rcsclean.c,v 5.1 1991/11/03 01:11:44 egge
getdesc(false);
if (
- !delta ? workstat.st_size!=0 :
+ !delta ? workstat.st_size!=0 :
0 < rcsfcmp(
- workptr, &workstat,
- buildrevision(deltas, delta, (FILE*)0, false),
- delta
+ workptr, &workstat,
+ buildrevision(deltas, delta, (FILE*)0, false),
+ delta
)
)
continue;
if (quietflag < unlocked)
- aprintf(stdout, "rcs -u%s %s\n", delta->num, RCSfilename);
+ aprintf(stdout, "rcs -u%s %s\n", delta->num, RCSname);
- if_advise_access(changelock && deltas->first != delta,
- finptr, MADV_SEQUENTIAL
- );
- if (!donerewrite(changelock))
- continue;
+ if (perform & unlocked) {
+ if_advise_access(deltas->first != delta, finptr, MADV_SEQUENTIAL);
+ if (donerewrite(true,
+ Ttimeflag ? RCSstat.st_mtime : (time_t)-1
+ ) != 0)
+ continue;
+ }
if (!quietflag)
- aprintf(stdout, "rm -f %s\n", workfilename);
+ aprintf(stdout, "rm -f %s\n", workname);
Izclose(&workptr);
- if (perform && un_link(workfilename) != 0)
- eerror(workfilename);
+ if (perform && un_link(workname) != 0)
+ eerror(workname);
- } while (cleanup(), ++argv, 0 < --argc);
+ }
tempunlink();
if (!quietflag)
@@ -213,16 +243,17 @@ cleanup()
Izclose(&finptr);
Izclose(&workptr);
Ozclose(&fcopy);
- Ozclose(&frewrite);
+ ORCSclose();
dirtempunlink();
}
-#if lint
-# define exiterr rcscleanExit
+#if RCS_lint
+# define exiterr rcscleanExit
#endif
- exiting void
+ void
exiterr()
{
+ ORCSerror();
dirtempunlink();
tempunlink();
_exit(EXIT_FAILURE);
@@ -232,7 +263,7 @@ exiterr()
unlock(delta)
struct hshentry *delta;
{
- register struct lock **al, *l;
+ register struct rcslock **al, *l;
if (delta && delta->lockedby && strcmp(getcaller(),delta->lockedby)==0)
for (al = &Locks; (l = *al); al = &l->nextlock)
@@ -269,7 +300,7 @@ get_directory(dirname, aargv)
while ((errno = 0, e = readdir(d))) {
char const *en = e->d_name;
size_t s = strlen(en) + 1;
- if (en[0]=='.' && (!en[1] || en[1]=='.' && !en[2]))
+ if (en[0]=='.' && (!en[1] || (en[1]=='.' && !en[2])))
continue;
if (rcssuffix(en))
continue;
@@ -281,7 +312,12 @@ get_directory(dirname, aargv)
VOID strcpy(a+chars, en);
chars += s;
}
- if (errno || closedir(d) != 0)
+# if void_closedir
+# define close_directory(d) (closedir(d), 0)
+# else
+# define close_directory(d) closedir(d)
+# endif
+ if (errno || close_directory(d) != 0)
efaterror(dirname);
if (chars)
a = trealloc(char, a, chars);
diff --git a/gnu/usr.bin/rcs/rcsdiff/Makefile b/gnu/usr.bin/rcs/rcsdiff/Makefile
index 837c241..45ce23f 100644
--- a/gnu/usr.bin/rcs/rcsdiff/Makefile
+++ b/gnu/usr.bin/rcs/rcsdiff/Makefile
@@ -1,7 +1,8 @@
-PROG= rcsdiff
-
-SRCS= rcsdiff.c
-LDADD= -L${.CURDIR}/../lib/obj -lrcs
+PROG= rcsdiff
+SRCS= rcsdiff.c
CFLAGS+= -I${.CURDIR}/../lib
+LDADD= ${LIBRCS}
+DPADD= ${LIBRCS}
+.include "../../Makefile.inc"
.include <bsd.prog.mk>
diff --git a/gnu/usr.bin/rcs/rcsdiff/rcsdiff.1 b/gnu/usr.bin/rcs/rcsdiff/rcsdiff.1
index b78bbdd..373c337 100644
--- a/gnu/usr.bin/rcs/rcsdiff/rcsdiff.1
+++ b/gnu/usr.bin/rcs/rcsdiff/rcsdiff.1
@@ -2,7 +2,7 @@
.ds Rv \\$3
.ds Dt \\$4
..
-.Id $Id: rcsdiff.1,v 5.3 1991/04/21 12:00:46 eggert Exp $
+.Id $Id: rcsdiff.1,v 5.5 1993/11/03 17:42:27 eggert Exp $
.ds r \&\s-1RCS\s0
.if n .ds - \%--
.if t .ds - \(em
@@ -20,10 +20,14 @@ rcsdiff \- compare RCS revisions
[
.BI \-r rev2
] ] [
-.BI \-V n
+.B \-T
+] [
+.RI "\f3\-V\fP[" n ]
] [
.BI \-x suffixes
] [
+.BI \-z zone
+] [
.I "diff options"
]
.I "file .\|.\|."
@@ -68,9 +72,11 @@ See
.BR co (1)
for details
about
-.B \-V
+.BR \-T ,
+.BR \-V ,
+.B \-x
and
-.BR \-x .
+.BR \-z .
Otherwise, all options of
.BR diff (1)
that apply to regular files are accepted, with the same meaning as for
@@ -136,11 +142,11 @@ Exit status is 0 for no differences during any comparison,
.SH IDENTIFICATION
Author: Walter F. Tichy.
.br
-Revision Number: \*(Rv; Release Date: \*(Dt.
+Manual Page Revision: \*(Rv; Release Date: \*(Dt.
.br
-Copyright \(co 1982, 1988, 1989 by Walter F. Tichy.
+Copyright \(co 1982, 1988, 1989 Walter F. Tichy.
.br
-Copyright \(co 1990, 1991 by Paul Eggert.
+Copyright \(co 1990, 1991, 1992, 1993 Paul Eggert.
.SH "SEE ALSO"
ci(1), co(1), diff(1), ident(1), rcs(1), rcsintro(1), rcsmerge(1), rlog(1)
.br
diff --git a/gnu/usr.bin/rcs/rcsdiff/rcsdiff.c b/gnu/usr.bin/rcs/rcsdiff/rcsdiff.c
index 7155c8d..9e31541 100644
--- a/gnu/usr.bin/rcs/rcsdiff/rcsdiff.c
+++ b/gnu/usr.bin/rcs/rcsdiff/rcsdiff.c
@@ -1,13 +1,7 @@
-/*
- * RCS rcsdiff operation
- */
-/*****************************************************************************
- * generate difference between RCS revisions
- *****************************************************************************
- */
+/* Compare RCS revisions. */
-/* Copyright (C) 1982, 1988, 1989 Walter Tichy
- Copyright 1990, 1991 by Paul Eggert
+/* Copyright 1982, 1988, 1989 Walter Tichy
+ Copyright 1990, 1991, 1992, 1993, 1994, 1995 Paul Eggert
Distributed under license by the Free Software Foundation, Inc.
This file is part of RCS.
@@ -23,8 +17,9 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
-along with RCS; see the file COPYING. If not, write to
-the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+along with RCS; see the file COPYING.
+If not, write to the Free Software Foundation,
+59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
Report problems and direct all questions to:
@@ -32,10 +27,37 @@ Report problems and direct all questions to:
*/
-
-
-
-/* $Log: rcsdiff.c,v $
+/*
+ * Revision 5.19 1995/06/16 06:19:24 eggert
+ * Update FSF address.
+ *
+ * Revision 5.18 1995/06/01 16:23:43 eggert
+ * (main): Pass "--binary" if -kb and if --binary makes a difference.
+ * Don't treat + options specially.
+ *
+ * Revision 5.17 1994/03/17 14:05:48 eggert
+ * Specify subprocess input via file descriptor, not file name. Remove lint.
+ *
+ * Revision 5.16 1993/11/09 17:40:15 eggert
+ * -V now prints version on stdout and exits. Don't print usage twice.
+ *
+ * Revision 5.15 1993/11/03 17:42:27 eggert
+ * Add -z. Ignore -T. Pass -Vn to `co'. Add Name keyword.
+ * Put revision numbers in -c output. Improve quality of diagnostics.
+ *
+ * Revision 5.14 1992/07/28 16:12:44 eggert
+ * Add -V. Use co -M for better dates with traditional diff -c.
+ *
+ * Revision 5.13 1992/02/17 23:02:23 eggert
+ * Output more readable context diff headers.
+ * Suppress needless checkout and comparison of identical revisions.
+ *
+ * Revision 5.12 1992/01/24 18:44:19 eggert
+ * Add GNU diff 1.15.2's new options. lint -> RCS_lint
+ *
+ * Revision 5.11 1992/01/06 02:42:34 eggert
+ * Update usage string.
+ *
* Revision 5.10 1991/10/07 17:32:46 eggert
* Remove lint.
*
@@ -75,30 +97,30 @@ Report problems and direct all questions to:
*
* Revision 4.6 89/05/01 15:12:27 narten
* changed copyright header to reflect current distribution rules
- *
+ *
* Revision 4.5 88/08/09 19:12:41 eggert
* Use execv(), not system(); yield exit status like diff(1)s; allow cc -R.
- *
+ *
* Revision 4.4 87/12/18 11:37:46 narten
* changes Jay Lepreau made in the 4.3 BSD version, to add support for
* "-i", "-w", and "-t" flags and to permit flags to be bundled together,
* merged in.
- *
+ *
* Revision 4.3 87/10/18 10:31:42 narten
* Updating version numbers. Changes relative to 1.1 actually
* relative to 4.1
- *
+ *
* Revision 1.3 87/09/24 13:59:21 narten
- * Sources now pass through lint (if you ignore printf/sprintf/fprintf
+ * Sources now pass through lint (if you ignore printf/sprintf/fprintf
* warnings)
- *
+ *
* Revision 1.2 87/03/27 14:22:15 jenkins
* Port to suns
- *
+ *
* Revision 4.1 83/05/03 22:13:19 wft
* Added default branch, option -q, exit status like diff.
* Added fterror() to replace faterror().
- *
+ *
* Revision 3.6 83/01/15 17:52:40 wft
* Expanded mainprogram to handle multiple RCS files.
*
@@ -129,29 +151,30 @@ static int exitstatus;
static RILE *workptr;
static struct stat workstat;
-mainProg(rcsdiffId, "rcsdiff", "$Id: rcsdiff.c,v 5.10 1991/10/07 17:32:46 eggert Exp $")
+mainProg(rcsdiffId, "rcsdiff", "$Id: rcsdiff.c,v 1.4 1995/10/29 22:06:42 peter Exp $")
{
static char const cmdusage[] =
- "\nrcsdiff usage: rcsdiff [-q] [-rrev1 [-rrev2]] [-Vn] [diff options] file ...";
+ "\nrcsdiff usage: rcsdiff -ksubst -q -rrev1 [-rrev2] -Vn -xsuff -zzone [diff options] file ...";
int revnums; /* counter for revision numbers given */
char const *rev1, *rev2; /* revision numbers from command line */
char const *xrev1, *xrev2; /* expanded revision numbers */
- char const *expandarg, *lexpandarg, *versionarg;
+ char const *expandarg, *lexpandarg, *suffixarg, *versionarg, *zonearg;
#if DIFF_L
static struct buf labelbuf[2];
int file_labels;
char const **diff_label1, **diff_label2;
char date2[datesize];
#endif
- char const *cov[9];
- char const **diffv, **diffp; /* argv for subsidiary diff */
+ char const *cov[10 + !DIFF_L];
+ char const **diffv, **diffp, **diffpend; /* argv for subsidiary diff */
char const **pp, *p, *diffvstr;
struct buf commarg;
struct buf numericrev; /* expanded revision number */
struct hshentries *gendeltas; /* deltas to be generated */
struct hshentry * target;
char *a, *dcp, **newargv;
+ int no_diff_means_no_output;
register c;
exitstatus = DIFF_SUCCESS;
@@ -159,38 +182,42 @@ mainProg(rcsdiffId, "rcsdiff", "$Id: rcsdiff.c,v 5.10 1991/10/07 17:32:46 eggert
bufautobegin(&commarg);
bufautobegin(&numericrev);
revnums = 0;
- rev1 = rev2 = xrev2 = nil;
+ rev1 = rev2 = xrev2 = 0;
#if DIFF_L
file_labels = 0;
#endif
- expandarg = versionarg = 0;
+ expandarg = suffixarg = versionarg = zonearg = 0;
+ no_diff_means_no_output = true;
suffixes = X_DEFAULT;
- /* Room for args + 2 i/o [+ 2 labels] + 1 file + 1 trailing null. */
- diffp = diffv = tnalloc(char const*, argc + 4 + 2*DIFF_L);
- *diffp++ = nil;
- *diffp++ = nil;
+ /*
+ * Room for runv extra + args [+ --binary] [+ 2 labels]
+ * + 1 file + 1 trailing null.
+ */
+ diffv = tnalloc(char const*, 1 + argc + !!OPEN_O_BINARY + 2*DIFF_L + 2);
+ diffp = diffv + 1;
*diffp++ = DIFF;
argc = getRCSINIT(argc, argv, &newargv);
argv = newargv;
while (a = *++argv, 0<--argc && *a++=='-') {
dcp = a;
- while (c = *a++) switch (c) {
+ while ((c = *a++)) switch (c) {
case 'r':
switch (++revnums) {
case 1: rev1=a; break;
case 2: rev2=a; break;
- default: faterror("too many revision numbers");
+ default: error("too many revision numbers");
}
goto option_handled;
+ case '-': case 'D':
+ no_diff_means_no_output = false;
+ /* fall into */
+ case 'C': case 'F': case 'I': case 'L': case 'W':
#if DIFF_L
- case 'L':
- if (++file_labels == 2)
+ if (c == 'L' && file_labels++ == 2)
faterror("too many -L options");
- /* fall into */
#endif
- case 'C': case 'D': case 'F': case 'I':
*dcp++ = c;
if (*a)
do *dcp++ = *a++;
@@ -203,7 +230,10 @@ mainProg(rcsdiffId, "rcsdiff", "$Id: rcsdiff.c,v 5.10 1991/10/07 17:32:46 eggert
*diffp++ = *argv++;
}
break;
- case 'B': case 'H': case 'T':
+ case 'y':
+ no_diff_means_no_output = false;
+ /* fall into */
+ case 'B': case 'H':
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
@@ -215,8 +245,18 @@ mainProg(rcsdiffId, "rcsdiff", "$Id: rcsdiff.c,v 5.10 1991/10/07 17:32:46 eggert
quietflag=true;
break;
case 'x':
+ suffixarg = *argv;
suffixes = *argv + 2;
goto option_handled;
+ case 'z':
+ zonearg = *argv;
+ zone_set(*argv + 2);
+ goto option_handled;
+ case 'T':
+ /* Ignore -T, so that RCSINIT can contain -T. */
+ if (*a)
+ goto unknown;
+ break;
case 'V':
versionarg = *argv;
setRCSversion(versionarg);
@@ -227,7 +267,8 @@ mainProg(rcsdiffId, "rcsdiff", "$Id: rcsdiff.c,v 5.10 1991/10/07 17:32:46 eggert
goto option_handled;
/* fall into */
default:
- faterror("unknown option: %s%s", *argv, cmdusage);
+ unknown:
+ error("unknown option: %s%s", *argv, cmdusage);
};
option_handled:
if (dcp != *argv+1) {
@@ -236,12 +277,10 @@ mainProg(rcsdiffId, "rcsdiff", "$Id: rcsdiff.c,v 5.10 1991/10/07 17:32:46 eggert
}
} /* end of option processing */
- if (argc<1) faterror("no input file%s", cmdusage);
-
- for (pp = diffv+3, c = 0; pp<diffp; )
+ for (pp = diffv+2, c = 0; pp<diffp; )
c += strlen(*pp++) + 1;
diffvstr = a = tnalloc(char, c + 1);
- for (pp = diffv+3; pp<diffp; ) {
+ for (pp = diffv+2; pp<diffp; ) {
p = *pp++;
*a++ = ' ';
while ((*a = *p++))
@@ -250,30 +289,37 @@ mainProg(rcsdiffId, "rcsdiff", "$Id: rcsdiff.c,v 5.10 1991/10/07 17:32:46 eggert
*a = 0;
#if DIFF_L
- diff_label1 = diff_label2 = nil;
+ diff_label1 = diff_label2 = 0;
if (file_labels < 2) {
if (!file_labels)
diff_label1 = diffp++;
diff_label2 = diffp++;
}
#endif
- diffp[2] = nil;
-
- cov[0] = 0;
- cov[2] = CO;
- cov[3] = "-q";
-
- /* now handle all filenames */
- do {
+ diffpend = diffp;
+
+ cov[1] = CO;
+ cov[2] = "-q";
+# if !DIFF_L
+ cov[3] = "-M";
+# endif
+
+ /* Now handle all pathnames. */
+ if (nerror)
+ cleanup();
+ else if (argc < 1)
+ faterror("no input file%s", cmdusage);
+ else
+ for (; 0 < argc; cleanup(), ++argv, --argc) {
ffree();
- if (pairfilenames(argc, argv, rcsreadopen, true, false) <= 0)
+ if (pairnames(argc, argv, rcsreadopen, true, false) <= 0)
continue;
- diagnose("===================================================================\nRCS file: %s\n",RCSfilename);
+ diagnose("===================================================================\nRCS file: %s\n",RCSname);
if (!rev2) {
/* Make sure work file is readable, and get its status. */
- if (!(workptr = Iopen(workfilename,FOPEN_R_WORK,&workstat))) {
- eerror(workfilename);
+ if (!(workptr = Iopen(workname, FOPEN_R_WORK, &workstat))) {
+ eerror(workname);
continue;
}
}
@@ -281,15 +327,15 @@ mainProg(rcsdiffId, "rcsdiff", "$Id: rcsdiff.c,v 5.10 1991/10/07 17:32:46 eggert
gettree(); /* reads in the delta tree */
- if (Head==nil) {
- error("no revisions present");
+ if (!Head) {
+ rcserror("no revisions present");
continue;
}
if (revnums==0 || !*rev1)
rev1 = Dbranch ? Dbranch : Head->num;
if (!fexpandsym(rev1, &numericrev, workptr)) continue;
- if (!(target=genrevs(numericrev.string,(char *)nil,(char *)nil,(char *)nil,&gendeltas))) continue;
+ if (!(target=genrevs(numericrev.string,(char *)0,(char *)0,(char *)0,&gendeltas))) continue;
xrev1=target->num;
#if DIFF_L
if (diff_label1)
@@ -304,8 +350,10 @@ mainProg(rcsdiffId, "rcsdiff", "$Id: rcsdiff.c,v 5.10 1991/10/07 17:32:46 eggert
workptr
))
continue;
- if (!(target=genrevs(numericrev.string,(char *)nil,(char *)nil,(char *)nil,&gendeltas))) continue;
+ if (!(target=genrevs(numericrev.string,(char *)0,(char *)0,(char *)0,&gendeltas))) continue;
xrev2=target->num;
+ if (no_diff_means_no_output && xrev1 == xrev2)
+ continue;
} else if (
target->lockedby
&& !lexpandarg
@@ -320,55 +368,60 @@ mainProg(rcsdiffId, "rcsdiff", "$Id: rcsdiff.c,v 5.10 1991/10/07 17:32:46 eggert
*diff_label2 = setup_label(&labelbuf[1], target->num, target->date);
else {
time2date(workstat.st_mtime, date2);
- *diff_label2 = setup_label(&labelbuf[1], workfilename, date2);
+ *diff_label2 = setup_label(&labelbuf[1], (char*)0, date2);
}
#endif
diagnose("retrieving revision %s\n", xrev1);
bufscpy(&commarg, "-p");
- bufscat(&commarg, xrev1);
+ bufscat(&commarg, rev1); /* not xrev1, for $Name's sake */
- cov[1] = diffp[0] = maketemp(0);
- pp = &cov[4];
+ pp = &cov[3 + !DIFF_L];
*pp++ = commarg.string;
- if (lexpandarg)
- *pp++ = lexpandarg;
- if (versionarg)
- *pp++ = versionarg;
- *pp++ = RCSfilename;
+ if (lexpandarg) *pp++ = lexpandarg;
+ if (suffixarg) *pp++ = suffixarg;
+ if (versionarg) *pp++ = versionarg;
+ if (zonearg) *pp++ = zonearg;
+ *pp++ = RCSname;
*pp = 0;
- if (runv(cov)) {
- error("co failed");
+ diffp = diffpend;
+# if OPEN_O_BINARY
+ if (Expand == BINARY_EXPAND)
+ *diffp++ = "--binary";
+# endif
+ diffp[0] = maketemp(0);
+ if (runv(-1, diffp[0], cov)) {
+ rcserror("co failed");
continue;
}
if (!rev2) {
- diffp[1] = workfilename;
- if (workfilename[0] == '+') {
- /* Some diffs have options with leading '+'. */
- char *dp = ftnalloc(char, strlen(workfilename)+3);
+ diffp[1] = workname;
+ if (*workname == '-') {
+ char *dp = ftnalloc(char, strlen(workname)+3);
diffp[1] = dp;
*dp++ = '.';
*dp++ = SLASH;
- VOID strcpy(dp, workfilename);
+ VOID strcpy(dp, workname);
}
} else {
diagnose("retrieving revision %s\n",xrev2);
bufscpy(&commarg, "-p");
- bufscat(&commarg, xrev2);
- cov[1] = diffp[1] = maketemp(1);
- cov[4] = commarg.string;
- if (runv(cov)) {
- error("co failed");
+ bufscat(&commarg, rev2); /* not xrev2, for $Name's sake */
+ cov[3 + !DIFF_L] = commarg.string;
+ diffp[1] = maketemp(1);
+ if (runv(-1, diffp[1], cov)) {
+ rcserror("co failed");
continue;
}
}
if (!rev2)
- diagnose("diff%s -r%s %s\n", diffvstr, xrev1, workfilename);
+ diagnose("diff%s -r%s %s\n", diffvstr, xrev1, workname);
else
diagnose("diff%s -r%s -r%s\n", diffvstr, xrev1, xrev2);
- switch (runv(diffv)) {
+ diffp[2] = 0;
+ switch (runv(-1, (char*)0, diffv)) {
case DIFF_SUCCESS:
break;
case DIFF_FAILURE:
@@ -376,11 +429,9 @@ mainProg(rcsdiffId, "rcsdiff", "$Id: rcsdiff.c,v 5.10 1991/10/07 17:32:46 eggert
exitstatus = DIFF_FAILURE;
break;
default:
- error("diff failed");
+ workerror("diff failed");
}
- } while (cleanup(),
- ++argv, --argc >=1);
-
+ }
tempunlink();
exitmain(exitstatus);
@@ -394,10 +445,10 @@ cleanup()
Izclose(&workptr);
}
-#if lint
+#if RCS_lint
# define exiterr rdiffExit
#endif
- exiting void
+ void
exiterr()
{
tempunlink();
@@ -406,17 +457,24 @@ exiterr()
#if DIFF_L
static char const *
-setup_label(b, name, date)
+setup_label(b, num, date)
struct buf *b;
- char const *name;
+ char const *num;
char const date[datesize];
{
char *p;
- size_t l = strlen(name) + 3;
- bufalloc(b, l+datesize);
+ char datestr[datesize + zonelenmax];
+ VOID date2str(date, datestr);
+ bufalloc(b,
+ strlen(workname)
+ + sizeof datestr + 4
+ + (num ? strlen(num) : 0)
+ );
p = b->string;
- VOID sprintf(p, "-L%s\t", name);
- VOID date2str(date, p+l);
+ if (num)
+ VOID sprintf(p, "-L%s\t%s\t%s", workname, datestr, num);
+ else
+ VOID sprintf(p, "-L%s\t%s", workname, datestr);
return p;
}
#endif
diff --git a/gnu/usr.bin/rcs/rcsfreeze/Makefile b/gnu/usr.bin/rcs/rcsfreeze/Makefile
index 825d4bf..a71f9d7 100644
--- a/gnu/usr.bin/rcs/rcsfreeze/Makefile
+++ b/gnu/usr.bin/rcs/rcsfreeze/Makefile
@@ -1,7 +1,8 @@
-# Do nothing for the following
-obj clean cleandir depend rcsfreeze all:
- @echo No need to make $@ for rcsfreeze\; ignored
+MAN1= rcsfreeze.1
-install:
- install -c -o bin -g bin -m 555 rcsfreeze.sh /usr/bin/rcsfreeze
- install -c -o bin -g bin -m 444 rcsfreeze.1 /usr/share/man/man1
+afterinstall:
+ ${INSTALL} -c -o ${BINOWN} -g ${BINGRP} -m ${BINMODE} \
+ ${.CURDIR}/rcsfreeze.sh ${DESTDIR}${BINDIR}/rcsfreeze
+
+.include "../../Makefile.inc"
+.include <bsd.prog.mk>
diff --git a/gnu/usr.bin/rcs/rcsfreeze/rcsfreeze.sh b/gnu/usr.bin/rcs/rcsfreeze/rcsfreeze.sh
index 4219979..96954f0 100644
--- a/gnu/usr.bin/rcs/rcsfreeze/rcsfreeze.sh
+++ b/gnu/usr.bin/rcs/rcsfreeze/rcsfreeze.sh
@@ -2,7 +2,7 @@
# rcsfreeze - assign a symbolic revision number to a configuration of RCS files
-# $Id: rcsfreeze.sh,v 4.4 1991/04/21 11:58:24 eggert Exp $
+# $Id: rcsfreeze.sh,v 4.6 1993/11/03 17:42:27 eggert Exp $
# The idea is to run rcsfreeze each time a new version is checked
# in. A unique symbolic revision number (C_[number], where number
@@ -25,22 +25,22 @@
# {RCS/}.rcsfreeze.ver version number
# {RCS/}.rscfreeze.log log messages, most recent first
-PATH=/usr/gnu/bin:/usr/local/bin:/bin:/usr/bin:/usr/ucb:$PATH
+PATH=/usr/local/bin:/bin:/usr/bin:/usr/ucb:$PATH
export PATH
DATE=`date` || exit
# Check whether we have an RCS subdirectory, so we can have the right
# prefix for our paths.
-if [ -d RCS ]
-then RCSDIR=RCS/
-else RCSDIR=
+if test -d RCS
+then RCSDIR=RCS/ EXT=
+else RCSDIR= EXT=,v
fi
# Version number stuff, log message file
VERSIONFILE=${RCSDIR}.rcsfreeze.ver
LOGFILE=${RCSDIR}.rcsfreeze.log
# Initialize, rcsfreeze never run before in the current directory
-[ -r $VERSIONFILE ] || { echo 0 >$VERSIONFILE && >>$LOGFILE; } || exit
+test -r $VERSIONFILE || { echo 0 >$VERSIONFILE && >>$LOGFILE; } || exit
# Get Version number, increase it, write back to file.
VERSIONNUMBER=`cat $VERSIONFILE` &&
@@ -79,22 +79,21 @@ trap 'rm -f $TMPLOG; exit 1' 1 2 13 15
# combine old and new logfiles
cp $TMPLOG $LOGFILE &&
-rm -f $TMPLOG || exit
-trap 1 2 13 15
+rm -f $TMPLOG &&
# Now the real work begins by assigning a symbolic revision number
-# to each rcs file. Take the most recent version of the main trunk.
+# to each rcs file. Take the most recent version on the default branch.
-status=
-
-for FILE in ${RCSDIR}*
+# If there are any .*,v files, throw them in too.
+# But ignore RCS/.* files that do not end in ,v.
+DOTFILES=
+for DOTFILE in ${RCSDIR}.*,v
do
-# get the revision number of the most recent revision
- HEAD=`rlog -h $FILE` &&
- REV=`echo "$HEAD" | sed -n 's/^head:[ ]*//p'` &&
-# assign symbolic name to it.
- echo >&2 "rcsfreeze: $REV $FILE" &&
- rcs -q -n$SYMREVNAME:$REV $FILE || status=$?
+ if test -f "$DOTFILE"
+ then
+ DOTFILES="${RCSDIR}.*,v"
+ break
+ fi
done
-exit $status
+exec rcs -q -n$SYMREVNAME: ${RCSDIR}*$EXT $DOTFILES
diff --git a/gnu/usr.bin/rcs/rcsmerge/Makefile b/gnu/usr.bin/rcs/rcsmerge/Makefile
index 0c1f643..9fd8afa 100644
--- a/gnu/usr.bin/rcs/rcsmerge/Makefile
+++ b/gnu/usr.bin/rcs/rcsmerge/Makefile
@@ -1,7 +1,8 @@
-PROG= rcsmerge
-
-SRCS= rcsmerge.c
-LDADD= -L${.CURDIR}/../lib/obj -lrcs
+PROG= rcsmerge
+SRCS= rcsmerge.c
CFLAGS+= -I${.CURDIR}/../lib
+LDADD= ${LIBRCS}
+DPADD= ${LIBRCS}
+.include "../../Makefile.inc"
.include <bsd.prog.mk>
diff --git a/gnu/usr.bin/rcs/rcsmerge/rcsmerge.1 b/gnu/usr.bin/rcs/rcsmerge/rcsmerge.1
index 82871b0..96b6a46 100644
--- a/gnu/usr.bin/rcs/rcsmerge/rcsmerge.1
+++ b/gnu/usr.bin/rcs/rcsmerge/rcsmerge.1
@@ -2,7 +2,7 @@
.ds Rv \\$3
.ds Dt \\$4
..
-.Id $Id: rcsmerge.1,v 5.3 1991/08/19 03:13:55 eggert Exp $
+.Id $Id: rcsmerge.1,v 5.6 1995/06/01 16:23:43 eggert Exp $
.ds r \&\s-1RCS\s0
.if n .ds - \%--
.if t .ds - \(em
@@ -38,6 +38,35 @@ the overlapping regions as explained in
The command is useful for incorporating changes into a checked-out revision.
.SH OPTIONS
.TP
+.B \-A
+Output conflicts using the
+.B \-A
+style of
+.BR diff3 (1),
+if supported by
+.BR diff3 .
+This merges all changes leading from
+.I file2
+to
+.I file3
+into
+.IR file1 ,
+and generates the most verbose output.
+.TP
+\f3\-E\fP, \f3\-e\fP
+These options specify conflict styles that generate less information
+than
+.BR \-A .
+See
+.BR diff3 (1)
+for details.
+The default is
+.BR \-E .
+With
+.BR \-e ,
+.B rcsmerge
+does not warn about conflicts.
+.TP
.BI \-k subst
Use
.I subst
@@ -51,6 +80,11 @@ ignores differences in keyword values when merging the changes from
.B 1.1
to
.BR 1.2 .
+It normally does not make sense to merge binary files as if they were text, so
+.B rcsmerge
+refuses to merge files if
+.B \-kb
+expansion is used.
.TP
.BR \-p [\f2rev\fP]
Send the result to standard output instead of overwriting the working file.
@@ -65,6 +99,13 @@ Here an empty
.I rev
stands for the latest revision on the default branch, normally the head.
.TP
+.B \-T
+This option has no effect;
+it is present for compatibility with other \*r commands.
+.TP
+.BI \-V
+Print \*r's version number.
+.TP
.BI \-V n
Emulate \*r version
.IR n .
@@ -79,6 +120,14 @@ to characterize \*r files.
See
.BR ci (1)
for details.
+.TP
+.BI \-z zone
+Use
+.I zone
+as the time zone for keyword substitution.
+See
+.BR co (1)
+for details.
.SH EXAMPLES
Suppose you have released revision 2.8 of
.BR f.c .
@@ -123,11 +172,11 @@ Exit status is 0 for no overlaps, 1 for some overlaps, 2 for trouble.
.SH IDENTIFICATION
Author: Walter F. Tichy.
.br
-Revision Number: \*(Rv; Release Date: \*(Dt.
+Manual Page Revision: \*(Rv; Release Date: \*(Dt.
.br
-Copyright \(co 1982, 1988, 1989 by Walter F. Tichy.
+Copyright \(co 1982, 1988, 1989 Walter F. Tichy.
.br
-Copyright \(co 1990, 1991 by Paul Eggert.
+Copyright \(co 1990, 1991, 1992, 1993, 1994, 1995 Paul Eggert.
.SH "SEE ALSO"
ci(1), co(1), ident(1), merge(1), rcs(1), rcsdiff(1), rcsintro(1), rlog(1),
rcsfile(5)
diff --git a/gnu/usr.bin/rcs/rcsmerge/rcsmerge.c b/gnu/usr.bin/rcs/rcsmerge/rcsmerge.c
index e5d4394..a4d9b86 100644
--- a/gnu/usr.bin/rcs/rcsmerge/rcsmerge.c
+++ b/gnu/usr.bin/rcs/rcsmerge/rcsmerge.c
@@ -1,13 +1,7 @@
-/*
- * rcsmerge operation
- */
-/*****************************************************************************
- * join 2 revisions with respect to a third
- *****************************************************************************
- */
+/* Merge RCS revisions. */
-/* Copyright (C) 1982, 1988, 1989 Walter Tichy
- Copyright 1990, 1991 by Paul Eggert
+/* Copyright 1982, 1988, 1989 Walter Tichy
+ Copyright 1990, 1991, 1992, 1993, 1994, 1995 Paul Eggert
Distributed under license by the Free Software Foundation, Inc.
This file is part of RCS.
@@ -23,8 +17,9 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
-along with RCS; see the file COPYING. If not, write to
-the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+along with RCS; see the file COPYING.
+If not, write to the Free Software Foundation,
+59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
Report problems and direct all questions to:
@@ -32,9 +27,33 @@ Report problems and direct all questions to:
*/
-
-
-/* $Log: rcsmerge.c,v $
+/*
+ * Revision 5.15 1995/06/16 06:19:24 eggert
+ * Update FSF address.
+ *
+ * Revision 5.14 1995/06/01 16:23:43 eggert
+ * (main): Report an error if -kb, so don't worry about binary stdout.
+ * Punctuate messages properly. Rewrite to avoid `goto end'.
+ *
+ * Revision 5.13 1994/03/17 14:05:48 eggert
+ * Specify subprocess input via file descriptor, not file name. Remove lint.
+ *
+ * Revision 5.12 1993/11/09 17:40:15 eggert
+ * -V now prints version on stdout and exits. Don't print usage twice.
+ *
+ * Revision 5.11 1993/11/03 17:42:27 eggert
+ * Add -A, -E, -e, -z. Ignore -T. Allow up to three file labels.
+ * Pass -Vn to `co'. Pass unexpanded revision name to `co', so that Name works.
+ *
+ * Revision 5.10 1992/07/28 16:12:44 eggert
+ * Add -V.
+ *
+ * Revision 5.9 1992/01/24 18:44:19 eggert
+ * lint -> RCS_lint
+ *
+ * Revision 5.8 1992/01/06 02:42:34 eggert
+ * Update usage string.
+ *
* Revision 5.7 1991/11/20 17:58:09 eggert
* Don't Iopen(f, "r+"); it's not portable.
*
@@ -64,26 +83,26 @@ Report problems and direct all questions to:
*
* Revision 4.5 89/05/01 15:13:16 narten
* changed copyright header to reflect current distribution rules
- *
+ *
* Revision 4.4 88/08/09 19:13:13 eggert
* Beware merging into a readonly file.
* Beware merging a revision to itself (no change).
* Use execv(), not system(); yield exit status like diff(1)'s.
- *
+ *
* Revision 4.3 87/10/18 10:38:02 narten
- * Updating version numbers. Changes relative to version 1.1
+ * Updating version numbers. Changes relative to version 1.1
* actually relative to 4.1
- *
+ *
* Revision 1.3 87/09/24 14:00:31 narten
- * Sources now pass through lint (if you ignore printf/sprintf/fprintf
+ * Sources now pass through lint (if you ignore printf/sprintf/fprintf
* warnings)
- *
+ *
* Revision 1.2 87/03/27 14:22:36 jenkins
* Port to suns
- *
+ *
* Revision 4.1 83/03/28 11:14:57 wft
* Added handling of default branch.
- *
+ *
* Revision 3.3 82/12/24 15:29:00 wft
* Added call to catchsig().
*
@@ -98,17 +117,17 @@ Report problems and direct all questions to:
static char const co[] = CO;
-mainProg(rcsmergeId, "rcsmerge", "$Id: rcsmerge.c,v 5.7 1991/11/20 17:58:09 eggert Exp $")
+mainProg(rcsmergeId, "rcsmerge", "$Id: rcsmerge.c,v 1.3 1995/10/28 21:50:52 peter Exp $")
{
static char const cmdusage[] =
- "\nrcsmerge usage: rcsmerge -rrev1 [-rrev2] [-p] [-Vn] file";
+ "\nrcsmerge usage: rcsmerge -rrev1 [-rrev2] -ksubst -{pq}[rev] -Vn -xsuff -zzone file";
static char const quietarg[] = "-q";
register int i;
char *a, **newargv;
char const *arg[3];
- char const *rev[2]; /*revision numbers*/
- char const *expandarg, *versionarg;
+ char const *rev[3], *xrev[3]; /*revision numbers*/
+ char const *edarg, *expandarg, *suffixarg, *versionarg, *zonearg;
int tostdout;
int status;
RILE *workptr;
@@ -119,10 +138,10 @@ mainProg(rcsmergeId, "rcsmerge", "$Id: rcsmerge.c,v 5.7 1991/11/20 17:58:09 egge
bufautobegin(&commarg);
bufautobegin(&numericrev);
- rev[0] = rev[1] = nil;
+ edarg = rev[1] = rev[2] = 0;
status = 0; /* Keep lint happy. */
tostdout = false;
- expandarg = versionarg = quietarg; /* i.e. a no-op */
+ expandarg = suffixarg = versionarg = zonearg = quietarg; /* no-op */
suffixes = X_DEFAULT;
argc = getRCSINIT(argc, argv, &newargv);
@@ -140,16 +159,33 @@ mainProg(rcsmergeId, "rcsmerge", "$Id: rcsmerge.c,v 5.7 1991/11/20 17:58:09 egge
break;
/* falls into -r */
case 'r':
- if (!rev[0])
- rev[0] = a;
- else if (!rev[1])
+ if (!rev[1])
rev[1] = a;
+ else if (!rev[2])
+ rev[2] = a;
else
- faterror("too many revision numbers");
+ error("too many revision numbers");
break;
+
+ case 'A': case 'E': case 'e':
+ if (*a)
+ goto unknown;
+ edarg = *argv;
+ break;
+
case 'x':
+ suffixarg = *argv;
suffixes = a;
break;
+ case 'z':
+ zonearg = *argv;
+ zone_set(a);
+ break;
+ case 'T':
+ /* Ignore -T, so that RCSINIT can contain -T. */
+ if (*a)
+ goto unknown;
+ break;
case 'V':
versionarg = *argv;
setRCSversion(versionarg);
@@ -161,90 +197,88 @@ mainProg(rcsmergeId, "rcsmerge", "$Id: rcsmerge.c,v 5.7 1991/11/20 17:58:09 egge
break;
/* fall into */
default:
- faterror("unknown option: %s%s", *argv, cmdusage);
+ unknown:
+ error("unknown option: %s%s", *argv, cmdusage);
};
} /* end of option processing */
- if (argc<1) faterror("no input file%s", cmdusage);
- if (!rev[0]) faterror("no base revision number given");
+ if (!rev[1]) faterror("no base revision number given");
- /* now handle all filenames */
+ /* Now handle all pathnames. */
- if (0 < pairfilenames(argc, argv, rcsreadopen, true, false)) {
+ if (!nerror) {
+ if (argc < 1)
+ faterror("no input file%s", cmdusage);
+ if (0 < pairnames(argc, argv, rcsreadopen, true, false)) {
- if (argc>2 || (argc==2&&argv[1]!=nil))
- warn("too many arguments");
- diagnose("RCS file: %s\n", RCSfilename);
- if (!(workptr = Iopen(workfilename,
- FOPEN_R_WORK,
- (struct stat*)0
- )))
- efaterror(workfilename);
+ if (argc>2 || (argc==2 && argv[1]))
+ warn("excess arguments ignored");
+ if (Expand == BINARY_EXPAND)
+ workerror("merging binary files");
+ diagnose("RCS file: %s\n", RCSname);
+ if (!(workptr = Iopen(workname, FOPEN_R_WORK, (struct stat*)0)))
+ efaterror(workname);
gettree(); /* reads in the delta tree */
- if (Head==nil) faterror("no revisions present");
+ if (!Head) rcsfaterror("no revisions present");
- if (!*rev[0])
- rev[0] = Dbranch ? Dbranch : Head->num;
- if (!fexpandsym(rev[0], &numericrev, workptr))
- goto end;
- if (!(target=genrevs(numericrev.string, (char *)nil, (char *)nil, (char *)nil,&gendeltas))) goto end;
- rev[0] = target->num;
- if (!rev[1] || !*rev[1])
+ if (!*rev[1])
rev[1] = Dbranch ? Dbranch : Head->num;
- if (!fexpandsym(rev[1], &numericrev, workptr))
- goto end;
- if (!(target=genrevs(numericrev.string, (char *)nil, (char *)nil, (char *)nil,&gendeltas))) goto end;
- rev[1] = target->num;
-
- if (strcmp(rev[0],rev[1]) == 0) {
- if (tostdout) {
- FILE *o;
-# if text_equals_binary_stdio || text_work_stdio
- o = stdout;
-# else
- if (!(o=fdopen(STDOUT_FILENO,FOPEN_W_WORK)))
- efaterror("stdout");
-# endif
- fastcopy(workptr,o);
- Ofclose(o);
- }
- goto end;
- }
- Izclose(&workptr);
+ if (fexpandsym(rev[1], &numericrev, workptr)
+ && (target=genrevs(numericrev.string, (char *)0, (char *)0, (char*)0, &gendeltas))
+ ) {
+ xrev[1] = target->num;
+ if (!rev[2] || !*rev[2])
+ rev[2] = Dbranch ? Dbranch : Head->num;
+ if (fexpandsym(rev[2], &numericrev, workptr)
+ && (target=genrevs(numericrev.string, (char *)0, (char *)0, (char *)0, &gendeltas))
+ ) {
+ xrev[2] = target->num;
+
+ if (strcmp(xrev[1],xrev[2]) == 0) {
+ if (tostdout) {
+ fastcopy(workptr, stdout);
+ Ofclose(stdout);
+ }
+ } else {
+ Izclose(&workptr);
- for (i=0; i<2; i++) {
- diagnose("retrieving revision %s\n", rev[i]);
+ for (i=1; i<=2; i++) {
+ diagnose("retrieving revision %s\n", xrev[i]);
bufscpy(&commarg, "-p");
- bufscat(&commarg, rev[i]);
+ bufscat(&commarg, rev[i]); /* not xrev[i], for $Name's sake */
if (run(
- (char*)0,
+ -1,
/* Do not collide with merger.c maketemp(). */
- arg[i+1] = maketemp(i+3),
- co, quietarg, commarg.string, expandarg,
- versionarg, RCSfilename, (char*)0
+ arg[i] = maketemp(i+2),
+ co, quietarg, commarg.string,
+ expandarg, suffixarg, versionarg, zonearg,
+ RCSname, (char*)0
))
- faterror("co failed");
+ rcsfaterror("co failed");
+ }
+ diagnose("Merging differences between %s and %s into %s%s\n",
+ xrev[1], xrev[2], workname,
+ tostdout?"; result to stdout":"");
+
+ arg[0] = xrev[0] = workname;
+ status = merge(tostdout, edarg, xrev, arg);
+ }
+ }
}
- diagnose("Merging differences between %s and %s into %s%s\n",
- rev[0], rev[1], workfilename,
- tostdout?"; result to stdout":"");
- arg[0] = rev[0] = workfilename;
- status = merge(tostdout, rev, arg);
+ Izclose(&workptr);
+ }
}
-
-end:
- Izclose(&workptr);
tempunlink();
exitmain(nerror ? DIFF_TROUBLE : status);
}
-#if lint
+#if RCS_lint
# define exiterr rmergeExit
#endif
- exiting void
+ void
exiterr()
{
tempunlink();
diff --git a/gnu/usr.bin/rcs/rcstest b/gnu/usr.bin/rcs/rcstest
index e0b6c82..47eab4f 100755
--- a/gnu/usr.bin/rcs/rcstest
+++ b/gnu/usr.bin/rcs/rcstest
@@ -1,4 +1,4 @@
-#!/bin/sh
+#! /bin/sh
# Test RCS's functions.
# The RCS commands are searched for in the PATH as usual;
@@ -15,10 +15,10 @@
# The current directory and ./RCS must be readable, writable, and searchable.
-# $Id: rcstest,v 5.8 1991/11/20 17:58:10 eggert Exp $
+# $Id: rcstest,v 5.14 1995/06/16 06:19:24 eggert Exp $
-# Copyright 1990, 1991 by Paul Eggert
+# Copyright 1990, 1991, 1992, 1993, 1994, 1995 Paul Eggert
# Distributed under license by the Free Software Foundation, Inc.
#
# This file is part of RCS.
@@ -34,13 +34,23 @@
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
-# along with RCS; see the file COPYING. If not, write to
-# the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+# along with RCS; see the file COPYING.
+# If not, write to the Free Software Foundation,
+# 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
# Report problems and direct all questions to:
#
# rcs-bugs@cs.purdue.edu
+# The Makefile overrides the following defaults.
+: ${ALL_CFLAGS=-Dhas_conf_h}
+: ${CC=cc}
+: ${DIFF=diff}
+# : ${LDFLAGS=} ${LIBS=} tickles old shell bug
+
+CL="$CC $ALL_CFLAGS $LDFLAGS -o a.out"
+L=$LIBS
+
RCSINIT=-x
export RCSINIT
@@ -55,26 +65,26 @@ case $1 in
*) echo >&2 "$0: usage: $0 [-v]"; exit 2
esac
-test -d RCS || {
- echo >&2 "$0: RCS: not a directory; please \`mkdir RCS' first."
- exit 1
-}
+if test -d RCS
+then rmdir=:
+else rmdir=rmdir; mkdir RCS || exit
+fi
rm -f a.* $RCSfile $RCS_alt $lockfile &&
echo 1.1 >a.11 &&
echo 1.1.1.1 >a.3x1 &&
echo 1.2 >a.12 || { echo "#initialization failed"; exit 2; }
-case `diff -c a.11 a.3x1` in
-*'! 1.1.1.1')
- diff='diff -c';;
+case "`$DIFF -c a.11 a.3x1`" in
+*!\ 1.1.1.1)
+ diff="$DIFF -c";;
*)
- echo "#warning: diff -c does not work, so diagnostics may be cryptic"
- diff=diff
+ echo "#warning: $DIFF -c does not work, so diagnostics may be cryptic"
+ diff=$DIFF
esac
rcs -i -L -ta.11 $q a.c &&
-<$RCSfile || {
+test -r $RCSfile || {
echo "#rcs -i -L failed; perhaps RCS is not properly installed."
exit 1
}
@@ -84,7 +94,7 @@ rm -f $RCSfile || exit 2
cp a.11 a.c &&
ci -ta.11 -mm $q a.c &&
-<$RCSfile &&
+test -r $RCSfile &&
rcs -L $q a.c || { echo "#ci+rcs -L failed"; exit 1; }
test ! -f a.c || { echo "#ci did not remove working file"; exit 1; }
for l in '' '-l'
@@ -99,6 +109,7 @@ ci -mm $q a.c &&
co $q a.c &&
$diff a.12 a.c || { echo "#ci+co failed"; exit 1; }
+rm -f a.c &&
co -r1.1 $q a.c &&
$diff a.11 a.c || { echo "#can't retrieve first revision"; exit 1; }
@@ -108,21 +119,24 @@ ci -r1.1.1 -mm $q a.c &&
co -r1.1.1.1 $q a.c &&
$diff a.3x1 a.c || { echo "#branches failed"; exit 1; }
+rm -f a.c &&
co -l $q a.c &&
ci -f -mm $q a.c &&
co -r1.3 $q a.c &&
$diff a.12 a.c || { echo "#(co -l; ci -f) failed"; exit 1; }
+rm -f a.c &&
co -l $q a.c &&
echo 1.4 >a.c &&
ci -l -mm $q a.c &&
echo error >a.c &&
ci -mm $q a.c || { echo "#ci -l failed"; exit 1; }
+rm -f a.c &&
co -l $q a.c &&
echo 1.5 >a.c &&
ci -u -mm $q a.c &&
-<a.c || { echo "#ci -u didn't create a working file"; exit 1; }
+test -r a.c || { echo "#ci -u didn't create a working file"; exit 1; }
rm -f a.c &&
echo error >a.c || exit 2
ci -mm $q a.c 2>/dev/null && { echo "#ci -u didn't unlock the file"; exit 1; }
@@ -166,42 +180,28 @@ case $LOGNAME in
esac
esac
esac
-date=`date -u 2>/dev/null` ||
-date=`TZ=GMT0 date 2>/dev/null` ||
-date=`TZ= date` || exit 2
-set $date
-case $2 in
-Jan) m=01;; Feb) m=02;; Mar) m=03;; Apr) m=04;; May) m=05;; Jun) m=06;;
-Jul) m=07;; Aug) m=08;; Sep) m=09;; Oct) m=10;; Nov) m=11;; Dec) m=12;;
-*) echo >&2 "$0: $2: unknown month name"; exit 2
-esac
-case $3 in
-?) d=0$3;;
-*) d=$3
-esac
-case $6 in
-[0-9][0-9][0-9][0-9]*) D=$6/$m/$d;;
-*)
- case $5 in
- [0-9][0-9][0-9][0-9]*) D=$5/$m/$d;;
- *) echo >&2 "$0: bad date format: $date"; exit 2
- esac
+
+
+# Get the date of the previous revision in UTC.
+date=`rlog -r a.c | sed -n '/^date: /{ s///; s/;.*//; p; q; }'` || exit
+case $date in
+[0-9][0-9][0-9]*[0-9]/[0-1][0-9]/[0-3][0-9]\ [0-2][0-9]:[0-5][0-9]:[0-6][0-9]);;
+*) echo >&2 "$0: $date: bad rlog date output"; exit 1
esac
-T=$4
-case $PWD in
-'') PWD=`pwd`
-esac &&
+PWD=`pwd` && export PWD &&
+rm -f a.c &&
co -l $q a.c &&
sed 's/@/$/g' >a.kv <<EOF
@Author: w @
-@Date: $D $T @
-@Header: $PWD$SLASH$RCSfile 2.1 $D $T w s @
-@Id: a.c 2.1 $D $T w s @
+@Date: $date @
+@Header: $PWD$SLASH$RCSfile 2.1 $date w s @
+@Id: a.c 2.1 $date w s @
@Locker: @
-@Log: a.c @
- * Revision 2.1 $D $T w
+ * @Log: a.c @
+ * Revision 2.1 $date w
* m
*
+@Name: Oz @
@RCSfile: a.c @
@Revision: 2.1 @
@Source: $PWD$SLASH$RCSfile @
@@ -210,25 +210,28 @@ EOF
test $? = 0 &&
sed 's/:.*\$/$/' a.kv >a.k &&
sed -e 's/w s [$]/w s '"$me"' $/' -e 's/[$]Locker: /&'"$me/" a.kv >a.kvl &&
-sed -e '/^\$/!d' -e 's/\$$/: old $/' a.k >a.o &&
+sed s/Oz//g a.kv >a.e &&
+sed s/Oz/N/g a.kv >a.N &&
+sed -e '/\$/!d' -e 's/\$$/: old $/' a.k >a.o &&
sed -e 's/\$[^ ]*: //' -e 's/ \$//' a.kv >a.v &&
cp a.o a.c &&
-ci -d"$date" -ss -ww -u2.1 -mm $q a.c &&
+ci -d"$date" -nOz -ss -ww -u2.1 -mm $q a.c &&
$diff a.kv a.c || { echo "#keyword expansion failed"; exit 1; }
-co -p -ko $q a.c >a.oo &&
+co -pOz -ko $q a.c >a.oo &&
$diff a.o a.oo || { echo "#co -p -ko failed"; exit 1; }
-cp a.kv a.o || exit 2
-rcs -o2.1 $q a.c &&
+cp a.kv a.o && cp a.o a.b || exit 2
+rcs -oOz $q a.c &&
rcs -l $q a.c &&
ci -k -u $q a.c &&
$diff a.kv a.c || { echo "#ci -k failed"; exit 1; }
-sed '/^[^$]/d' a.kv >a.i &&
+sed -n 's/^[^$]*\$/$/p' a.kv >a.i &&
ident a.c >a.i1 &&
sed -e 1d -e 's/^[ ]*//' a.i1 >a.i2 &&
$diff a.i a.i2 || { echo "#ident failed"; exit 1; }
rcs -i $q a.c 2>/dev/null && { echo "#rcs -i permitted existing file"; exit 1; }
+rm -f a.c &&
co -l $q a.c &&
echo 2.2 >a.c &&
ci -mm $q a.c &&
@@ -259,40 +262,73 @@ rcs -nN:1.1 $q a.c &&
co -rN $q a.c &&
$diff a.11 a.c || { echo "#rcs -n failed"; exit 1; }
+rm -f a.c &&
rcs -NN:2.1 $q a.c &&
co -rN $q a.c &&
-$diff a.kv a.c || { echo "#rcs -N failed"; exit 1; }
+$diff a.N a.c || { echo "#rcs -N failed"; exit 1; }
+rm -f a.c &&
co -l $q a.c &&
-rcs -c':::' $q a.c &&
-echo '$''Log$' >a.c &&
+echo ':::$''Log$' >a.c &&
ci -u -mm $q a.c &&
-test " `sed '$!d' a.c`" = ' :::' || { echo "#rcs -c failed"; exit 1; }
+test " `sed '$!d' a.c`" = ' :::' || { echo "#comment leader failed"; exit 1; }
+rm -f a.c &&
rcs -o2.2: $q a.c &&
co $q a.c &&
-$diff a.kv a.c || { echo "#rcs -o failed"; exit 1; }
+$diff a.e a.c || { echo "#rcs -o failed"; exit 1; }
-rcsdiff -r1.1 -r2.1 $q a.c >a.0
+rcsdiff -r1.1 -rOz $q a.c >a.0
case $? in
1) ;;
*) echo "#rcsdiff bad status"; exit 1
esac
-diff a.11 a.kv >a.1
+$DIFF a.11 a.kv >a.1
$diff a.0 a.1 || { echo "#rcsdiff failed"; exit 1; }
rcs -l2.1 $q a.c || { echo "#rcs -l2.1 failed"; exit 1; }
-for i in k kv kvl o v
+for i in b k kv kvl o v
do
rm -f a.c &&
cp a.$i a.c &&
- rcsdiff -k$i $q a.c || { echo "#rcsdiff -k$i failed"; exit 1; }
+ rcsdiff -k$i -rOz $q a.c || { echo "#rcsdiff -k$i failed"; exit 1; }
done
co -p1.1 -ko $q a.c >a.t &&
$diff a.11 a.t || { echo "#co -p1.1 -ko failed"; exit 1; }
rcs -u2.1 $q a.c || { echo "#rcs -u2.1 failed"; exit 1; }
rm -f a.c &&
+rcsclean $q a.c &&
+rcsclean -u $q a.c || { echo "#rcsclean botched a nonexistent file"; exit 1; }
+
+rm -f a.c &&
+co $q a.c &&
+rcsclean -n $q a.c &&
+rcsclean -n -u $q a.c &&
+test -f a.c || { echo "#rcsclean -n removed a file"; exit 1; }
+
+rm -f a.c &&
+co $q a.c &&
+rcsclean $q a.c &&
+test ! -f a.c || { echo "#rcsclean missed an unlocked file"; exit 1; }
+
+rm -f a.c &&
+co -l $q a.c &&
+rcsclean $q a.c &&
+test -f a.c || { echo "#rcsclean removed a locked file"; exit 1; }
+rcsclean -u $q a.c &&
+test ! -f a.c || {
+ echo "#rcsclean -u missed an unchanged locked file"; exit 1;
+}
+
+rm -f a.c &&
+co -l $q a.c &&
+echo change >>a.c &&
+rcsclean $q a.c &&
+rcsclean $q -u a.c &&
+test -f a.c || { echo "#rcsclean removed a changed file"; exit 1; }
+
+rm -f a.c &&
co -l $q a.c &&
cat >a.c <<'EOF'
2.2
@@ -324,7 +360,7 @@ b1
c
d1
EOF
-rcsmerge -r2.2 -r2.3 $q a.c
+rcsmerge -E -r2.2 -r2.3 $q a.c
case $? in
0)
if $diff a.0 a.c >/dev/null
@@ -343,16 +379,36 @@ case $? in
echo "#rcsmerge bad status"; exit 1
esac
-nl='
-'
+# Avoid `tr' if possible; it's not portable, and it can't handle null bytes.
+# Our substitute exclusive-ORs with '\n';
+# this ensures null bytes on output, which is even better than `tr',
+# since some diffs think a file is binary only if it contains null bytes.
+cat >a.c <<'EOF'
+#include <stdio.h>
+int main() {
+ int c;
+ while ((c=getchar()) != EOF)
+ putchar(c ^ '\n');
+ return 0;
+}
+EOF
+tr=tr
+if (rm -f a.exe a.out && $CL a.c $L >&2) >/dev/null 2>&1
+then
+ if test -s a.out
+ then tr=./a.out
+ elif test -s a.exe
+ then tr=./a.exe
+ fi
+fi
{
- co -p $q a.c | tr "$nl" '\200' >a.24 &&
+ co -p $q a.c | $tr '\012' '\200' >a.24 &&
cp a.24 a.c &&
ciOut=`(ci -l -mm $q a.c 2>&1)` &&
case $ciOut in
?*) echo >&2 "$ciOut"
esac &&
- co -p $q a.c | tr '\200' "$nl" >a.c &&
+ co -p $q a.c | $tr '\200' '\012' >a.c &&
rcsdiff -r2.3 $q a.c >/dev/null &&
echo 2.5 >a.c &&
@@ -378,15 +434,15 @@ locks: strict
access list:
symbolic names:
N: 2.1
+ Oz: 2.1
n: 1.8
-comment leader: ":::"
keyword substitution: kv
total revisions: 13; selected revisions: 1
description:
1.1
----------------------------
revision 2.1
-date: $D $T; author: w; state: s; lines: +13 -1
+date: $date; author: w; state: s; lines: +14 -1
=============================================================================
EOF
test $? = 0 || { echo "#rlog failed"; exit 1; }
@@ -394,4 +450,5 @@ test $? = 0 || { echo "#rlog failed"; exit 1; }
test ! -f $lockfile || { echo "#lock file not removed"; exit 1; }
-exec rm -f a.* $RCSfile $RCS_alt
+rm -f a.* $RCSfile $RCS_alt
+$rmdir RCS
diff --git a/gnu/usr.bin/rcs/rlog/Makefile b/gnu/usr.bin/rcs/rlog/Makefile
index b6a1268..bdbf68f 100644
--- a/gnu/usr.bin/rcs/rlog/Makefile
+++ b/gnu/usr.bin/rcs/rlog/Makefile
@@ -1,7 +1,8 @@
-PROG= rlog
-
-SRCS= rlog.c
-LDADD= -L${.CURDIR}/../lib/obj -lrcs
+PROG= rlog
+SRCS= rlog.c
CFLAGS+= -I${.CURDIR}/../lib
+LDADD= ${LIBRCS}
+DPADD= ${LIBRCS}
+.include "../../Makefile.inc"
.include <bsd.prog.mk>
diff --git a/gnu/usr.bin/rcs/rlog/rlog.1 b/gnu/usr.bin/rcs/rlog/rlog.1
index fa627ff..cc4b45c9 100644
--- a/gnu/usr.bin/rcs/rlog/rlog.1
+++ b/gnu/usr.bin/rcs/rlog/rlog.1
@@ -2,9 +2,10 @@
.ds Rv \\$3
.ds Dt \\$4
..
-.Id $Id: rlog.1,v 5.3 1991/08/22 06:50:48 eggert Exp $
-.ds g \&\s-1UTC\s0
+.Id $Id: rlog.1,v 5.9 1995/06/16 06:19:24 eggert Exp $
+.ds i \&\s-1ISO\s0
.ds r \&\s-1RCS\s0
+.ds u \&\s-1UTC\s0
.if n .ds - \%--
.if t .ds - \(em
.TH RLOG 1 \*(Dt GNU
@@ -34,13 +35,17 @@ reverse chronological order for each branch. For each revision,
prints revision number, author, date/time, state, number of
lines added/deleted (with respect to the previous revision),
locker of the revision (if any), and log message.
-All times are displayed in Coordinated Universal Time (\*g).
+All times are displayed in Coordinated Universal Time (\*u) by default;
+this can be overridden with
+.BR \-z .
Without options,
.B rlog
prints complete information.
The options below restrict this output.
-.nr n \w'\f3\-V\fP\f2n\fP '+1n-1/1n
-.TP \nn
+.nr n \w'\f3\-V\fP\f2n\fP'+2n-1/1n
+.ds n \nn
+.if \n(.g .if r an-tag-sep .ds n \w'\f3\-V\fP\f2n\fP'u+\n[an-tag-sep]u
+.TP \*n
.B \-L
Ignore \*r files that have no locks set.
This is convenient in combination with
@@ -64,6 +69,9 @@ Print the same as
.BR \-h ,
plus the descriptive text.
.TP
+.B \-N
+Do not print the symbolic names.
+.TP
.B \-b
Print information about the revisions on the default branch, normally
the highest branch on the trunk.
@@ -80,23 +88,28 @@ selects the revisions that were deposited between
.I d1
and
.I d2
-inclusive.
+exclusive.
A range of the form
.BI < d
or
.IB d >
selects
-all revisions dated
-.I d
-or earlier.
+all revisions earlier than
+.IR d .
A range of the form
.IB d <
or
.BI > d
selects
-all revisions dated
-.I d
-or later.
+all revisions dated later than
+.IR d .
+If
+.B <
+or
+.B >
+is followed by
+.B =
+then the ranges are inclusive, not exclusive.
A range of the form
.I d
selects the single, latest revision dated
@@ -174,6 +187,13 @@ If
.I logins
is omitted, the user's login is assumed.
.TP
+.B \-T
+This option has no effect;
+it is present for compatibility with other \*r commands.
+.TP
+.BI \-V
+Print \*r's version number.
+.TP
.BI \-V n
Emulate \*r version
.I n
@@ -203,6 +223,40 @@ with the union of the revisions selected by
.B \-b
and
.BR \-r .
+.TP
+.BI \-z zone
+specifies the date output format,
+and specifies the default time zone for
+.I date
+in the
+.BI \-d dates
+option.
+The
+.I zone
+should be empty, a numeric \*u offset, or the special string
+.B LT
+for local time.
+The default is an empty
+.IR zone ,
+which uses the traditional \*r format of \*u without any time zone indication
+and with slashes separating the parts of the date;
+otherwise, times are output in \*i 8601 format with time zone indication.
+For example, if local time is January 11, 1990, 8pm Pacific Standard Time,
+eight hours west of \*u,
+then the time is output as follows:
+.RS
+.LP
+.RS
+.nf
+.ta \w'\f3\-z+05:30\fP 'u +\w'\f31990-01-11 09:30:00+05:30\fP 'u
+.ne 4
+\f2option\fP \f2time output\fP
+\f3\-z\fP \f31990/01/12 04:00:00\fP \f2(default)\fP
+\f3\-zLT\fP \f31990-01-11 20:00:00\-08\fP
+\f3\-z+05:30\fP \f31990-01-12 09:30:00+05:30\fP
+.ta 4n +4n +4n +4n
+.fi
+.RE
.SH EXAMPLES
.LP
.nf
@@ -229,11 +283,11 @@ The exit status is zero if and only if all operations were successful.
.SH IDENTIFICATION
Author: Walter F. Tichy.
.br
-Revision Number: \*(Rv; Release Date: \*(Dt.
+Manual Page Revision: \*(Rv; Release Date: \*(Dt.
.br
-Copyright \(co 1982, 1988, 1989 by Walter F. Tichy.
+Copyright \(co 1982, 1988, 1989 Walter F. Tichy.
.br
-Copyright \(co 1990, 1991 by Paul Eggert.
+Copyright \(co 1990, 1991, 1992, 1993, 1994, 1995 Paul Eggert.
.SH "SEE ALSO"
ci(1), co(1), ident(1), rcs(1), rcsdiff(1), rcsintro(1), rcsmerge(1),
rcsfile(5)
diff --git a/gnu/usr.bin/rcs/rlog/rlog.c b/gnu/usr.bin/rcs/rlog/rlog.c
index b18b0c9..a3e63be 100644
--- a/gnu/usr.bin/rcs/rlog/rlog.c
+++ b/gnu/usr.bin/rcs/rlog/rlog.c
@@ -1,13 +1,7 @@
-/*
- * RLOG operation
- */
-/*****************************************************************************
- * print contents of RCS files
- *****************************************************************************
- */
+/* Print log messages and other information about RCS files. */
-/* Copyright (C) 1982, 1988, 1989 Walter Tichy
- Copyright 1990, 1991 by Paul Eggert
+/* Copyright 1982, 1988, 1989 Walter Tichy
+ Copyright 1990, 1991, 1992, 1993, 1994, 1995 Paul Eggert
Distributed under license by the Free Software Foundation, Inc.
This file is part of RCS.
@@ -23,8 +17,9 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
-along with RCS; see the file COPYING. If not, write to
-the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+along with RCS; see the file COPYING.
+If not, write to the Free Software Foundation,
+59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
Report problems and direct all questions to:
@@ -32,10 +27,41 @@ Report problems and direct all questions to:
*/
-
-
-
-/* $Log: rlog.c,v $
+/*
+ * Revision 5.18 1995/06/16 06:19:24 eggert
+ * Update FSF address.
+ *
+ * Revision 5.17 1995/06/01 16:23:43 eggert
+ * (struct rcslockers): Renamed from `struct lockers'.
+ * (getnumericrev): Return error indication instead of ignoring errors.
+ * (main): Check it. Don't use dateform.
+ * (recentdate, extdate): cmpnum -> cmpdate
+ *
+ * Revision 5.16 1994/04/13 16:30:34 eggert
+ * Fix bug; `rlog -lxxx' inverted the sense of -l.
+ *
+ * Revision 5.15 1994/03/17 14:05:48 eggert
+ * -d'<DATE' now excludes DATE; the new syntax -d'<=DATE' includes it.
+ * Emulate -V4's white space generation more precisely.
+ * Work around SVR4 stdio performance bug. Remove lint.
+ *
+ * Revision 5.14 1993/11/09 17:40:15 eggert
+ * -V now prints version on stdout and exits.
+ *
+ * Revision 5.13 1993/11/03 17:42:27 eggert
+ * Add -N, -z. Ignore -T.
+ *
+ * Revision 5.12 1992/07/28 16:12:44 eggert
+ * Don't miss B.0 when handling branch B. Diagnose missing `,' in -r.
+ * Add -V. Avoid `unsigned'. Statement macro names now end in _.
+ *
+ * Revision 5.11 1992/01/24 18:44:19 eggert
+ * Don't duplicate unexpected_EOF's function. lint -> RCS_lint
+ *
+ * Revision 5.10 1992/01/06 02:42:34 eggert
+ * Update usage string.
+ * while (E) ; -> while (E) continue;
+ *
* Revision 5.9 1991/09/17 19:07:40 eggert
* Getscript() didn't uncache partial lines.
*
@@ -72,37 +98,37 @@ Report problems and direct all questions to:
*
* Revision 4.7 89/05/01 15:13:48 narten
* changed copyright header to reflect current distribution rules
- *
+ *
* Revision 4.6 88/08/09 19:13:28 eggert
* Check for memory exhaustion; don't access freed storage.
* Shrink stdio code size; remove lint.
- *
+ *
* Revision 4.5 87/12/18 11:46:38 narten
* more lint cleanups (Guy Harris)
- *
+ *
* Revision 4.4 87/10/18 10:41:12 narten
* Updating version numbers
* Changes relative to 1.1 actually relative to 4.2
- *
+ *
* Revision 1.3 87/09/24 14:01:10 narten
- * Sources now pass through lint (if you ignore printf/sprintf/fprintf
+ * Sources now pass through lint (if you ignore printf/sprintf/fprintf
* warnings)
- *
+ *
* Revision 1.2 87/03/27 14:22:45 jenkins
* Port to suns
- *
+ *
* Revision 4.2 83/12/05 09:18:09 wft
* changed rewriteflag to external.
- *
+ *
* Revision 4.1 83/05/11 16:16:55 wft
* Added -b, updated getnumericrev() accordingly.
* Replaced getpwuid() with getcaller().
- *
+ *
* Revision 3.7 83/05/11 14:24:13 wft
* Added options -L and -R;
* Fixed selection bug with -l on multiple files.
* Fixed error on dates of the form -d'>date' (rewrote getdatepair()).
- *
+ *
* Revision 3.6 82/12/24 15:57:53 wft
* shortened output format.
*
@@ -131,9 +157,9 @@ Report problems and direct all questions to:
#include "rcsbase.h"
-struct lockers { /* lockers in locker option; stored */
+struct rcslockers { /* lockers in locker option; stored */
char const * login; /* lockerlist */
- struct lockers * lockerlink;
+ struct rcslockers * lockerlink;
} ;
struct stateattri { /* states in state option; stored in */
@@ -147,28 +173,29 @@ struct authors { /* login names in author option; */
} ;
struct Revpairs{ /* revision or branch range in -r */
- unsigned numfld; /* option; stored in revlist */
+ int numfld; /* option; stored in revlist */
char const * strtrev;
char const * endrev;
struct Revpairs * rnext;
} ;
struct Datepairs{ /* date range in -d option; stored in */
+ struct Datepairs *dnext;
char strtdate[datesize]; /* duelst and datelist */
char enddate[datesize];
- struct Datepairs * dnext;
+ char ne_date; /* datelist only; distinguishes < from <= */
};
static char extractdelta P((struct hshentry const*));
static int checkrevpair P((char const*,char const*));
+static int extdate P((struct hshentry*));
+static int getnumericrev P((void));
static struct hshentry const *readdeltalog P((void));
-static unsigned extdate P((struct hshentry*));
static void cleanup P((void));
static void exttree P((struct hshentry*));
static void getauthor P((char*));
static void getdatepair P((char*));
static void getlocker P((char*));
-static void getnumericrev P((void));
static void getrevpairs P((char*));
static void getscript P((struct hshentry*));
static void getstate P((char*));
@@ -187,31 +214,36 @@ static int lockflag;
static struct Datepairs *datelist, *duelst;
static struct Revpairs *revlist, *Revlst;
static struct authors *authorlist;
-static struct lockers *lockerlist;
+static struct rcslockers *lockerlist;
static struct stateattri *statelist;
-mainProg(rlogId, "rlog", "$Id: rlog.c,v 5.9 1991/09/17 19:07:40 eggert Exp $")
+mainProg(rlogId, "rlog", "$Id: rlog.c,v 1.9 1995/10/29 18:07:04 peter Exp $")
{
static char const cmdusage[] =
- "\nrlog usage: rlog -{bhLRt} -ddates -l[lockers] -rrevs -sstates -w[logins] -Vn file ...";
+ "\nrlog usage: rlog -{bhLNRt} -v[string] -ddates -l[lockers] -r[revs] -sstates -Vn -w[logins] -xsuff -zzone file ...";
register FILE *out;
char *a, **newargv;
struct Datepairs *currdate;
- char const *accessListString, *accessFormat, *commentFormat;
+ char const *accessListString, *accessFormat;
char const *headFormat, *symbolFormat;
struct access const *curaccess;
struct assoc const *curassoc;
struct hshentry const *delta;
- struct lock const *currlock;
+ struct rcslock const *currlock;
int descflag, selectflag;
int onlylockflag; /* print only files with locks */
- int onlyRCSflag; /* print only RCS file name */
- unsigned revno;
-
- descflag = selectflag = true;
- onlylockflag = onlyRCSflag = false;
+ int onlyRCSflag; /* print only RCS pathname */
+ int pre5;
+ int shownames;
+ int revno;
+ int versionlist;
+ char *vstring;
+
+ descflag = selectflag = shownames = true;
+ versionlist = onlylockflag = onlyRCSflag = false;
+ vstring=0;
out = stdout;
suffixes = X_DEFAULT;
@@ -224,6 +256,10 @@ mainProg(rlogId, "rlog", "$Id: rlog.c,v 5.9 1991/09/17 19:07:40 eggert Exp $")
onlylockflag = true;
break;
+ case 'N':
+ shownames = false;
+ break;
+
case 'R':
onlyRCSflag =true;
break;
@@ -270,49 +306,68 @@ mainProg(rlogId, "rlog", "$Id: rlog.c,v 5.9 1991/09/17 19:07:40 eggert Exp $")
suffixes = a;
break;
+ case 'z':
+ zone_set(a);
+ break;
+
+ case 'T':
+ /* Ignore -T, so that RCSINIT can contain -T. */
+ if (*a)
+ goto unknown;
+ break;
+
case 'V':
setRCSversion(*argv);
break;
+ case 'v':
+ versionlist = true;
+ vstring = a;
+ break;
+
default:
- faterror("unknown option: %s%s", *argv, cmdusage);
+ unknown:
+ error("unknown option: %s%s", *argv, cmdusage);
};
} /* end of option processing */
- if (argc<1) faterror("no input file%s", cmdusage);
-
if (! (descflag|selectflag)) {
warn("-t overrides -h.");
descflag = true;
}
- if (RCSversion < VERSION(5)) {
+ pre5 = RCSversion < VERSION(5);
+ if (pre5) {
accessListString = "\naccess list: ";
accessFormat = " %s";
- commentFormat = "\ncomment leader: \"";
- headFormat = "\nRCS file: %s; Working file: %s\nhead: %s%s\nbranch: %s%s\nlocks: ";
- insDelFormat = " lines added/del: %lu/%lu";
+ headFormat = "RCS file: %s; Working file: %s\nhead: %s%s\nbranch: %s%s\nlocks: ";
+ insDelFormat = " lines added/del: %ld/%ld";
symbolFormat = " %s: %s;";
} else {
accessListString = "\naccess list:";
accessFormat = "\n\t%s";
- commentFormat = "\ncomment leader: \"";
- headFormat = "\nRCS file: %s\nWorking file: %s\nhead:%s%s\nbranch:%s%s\nlocks:%s";
- insDelFormat = " lines: +%lu -%lu";
+ headFormat = "RCS file: %s\nWorking file: %s\nhead:%s%s\nbranch:%s%s\nlocks:%s";
+ insDelFormat = " lines: +%ld -%ld";
symbolFormat = "\n\t%s: %s";
}
- /* now handle all filenames */
- do {
+ /* Now handle all pathnames. */
+ if (nerror)
+ cleanup();
+ else if (argc < 1)
+ faterror("no input file%s", cmdusage);
+ else
+ for (; 0 < argc; cleanup(), ++argv, --argc) {
ffree();
- if (pairfilenames(argc, argv, rcsreadopen, true, false) <= 0)
+ if (pairnames(argc, argv, rcsreadopen, true, false) <= 0)
continue;
- /* now RCSfilename contains the name of the RCS file, and finptr
- * the file descriptor. Workfilename contains the name of the
- * working file.
+ /*
+ * RCSname contains the name of the RCS file,
+ * and finptr the file descriptor;
+ * workname contains the name of the working file.
*/
/* Keep only those locks given by -l. */
@@ -323,14 +378,32 @@ mainProg(rlogId, "rlog", "$Id: rlog.c,v 5.9 1991/09/17 19:07:40 eggert Exp $")
if (onlylockflag && !Locks)
continue;
+ if ( versionlist ) {
+ gettree();
+ aprintf(out, "%s%s %s\n", vstring, workname, tiprev());
+ continue;
+ }
+
if ( onlyRCSflag ) {
- aprintf(out, "%s\n", RCSfilename);
+ aprintf(out, "%s\n", RCSname);
continue;
}
- /* print RCS filename , working filename and optional
+
+ gettree();
+
+ if (!getnumericrev())
+ continue;
+
+ /*
+ * Output the first character with putc, not printf.
+ * Otherwise, an SVR4 stdio bug buffers output inefficiently.
+ */
+ aputc_('\n', out)
+
+ /* print RCS pathname, working pathname and optional
administrative information */
/* could use getfullRCSname() here, but that is very slow */
- aprintf(out, headFormat, RCSfilename, workfilename,
+ aprintf(out, headFormat, RCSname, workname,
Head ? " " : "", Head ? Head->num : "",
Dbranch ? " " : "", Dbranch ? Dbranch : "",
StrictLocks ? " strict" : ""
@@ -341,8 +414,8 @@ mainProg(rlogId, "rlog", "$Id: rlog.c,v 5.9 1991/09/17 19:07:40 eggert Exp $")
currlock->delta->num);
currlock = currlock->nextlock;
}
- if (StrictLocks && RCSversion<VERSION(5))
- aputs(" strict", out);
+ if (StrictLocks && pre5)
+ aputs(" ; strict" + (Locks?3:0), out);
aputs(accessListString, out); /* print access list */
curaccess = AccessList;
@@ -351,40 +424,40 @@ mainProg(rlogId, "rlog", "$Id: rlog.c,v 5.9 1991/09/17 19:07:40 eggert Exp $")
curaccess = curaccess->nextaccess;
}
- aputs("\nsymbolic names:", out); /* print symbolic names */
- for (curassoc=Symbols; curassoc; curassoc=curassoc->nextassoc)
- aprintf(out, symbolFormat, curassoc->symbol, curassoc->num);
- aputs(commentFormat, out);
- awrite(Comment.string, Comment.size, out);
- aputs("\"\n", out);
- if (VERSION(5)<=RCSversion || Expand != KEYVAL_EXPAND)
- aprintf(out, "keyword substitution: %s\n",
+ if (shownames) {
+ aputs("\nsymbolic names:", out); /* print symbolic names */
+ for (curassoc=Symbols; curassoc; curassoc=curassoc->nextassoc)
+ aprintf(out, symbolFormat, curassoc->symbol, curassoc->num);
+ }
+ if (pre5) {
+ aputs("\ncomment leader: \"", out);
+ awrite(Comment.string, Comment.size, out);
+ afputc('\"', out);
+ }
+ if (!pre5 || Expand != KEYVAL_EXPAND)
+ aprintf(out, "\nkeyword substitution: %s",
expand_names[Expand]
);
- gettree();
-
- aprintf(out, "total revisions: %u", TotalDeltas);
+ aprintf(out, "\ntotal revisions: %d", TotalDeltas);
revno = 0;
if (Head && selectflag & descflag) {
- getnumericrev(); /* get numeric revision or branch names */
-
exttree(Head);
/* get most recently date of the dates pointed by duelst */
currdate = duelst;
while( currdate) {
- VOID sprintf(currdate->strtdate,DATEFORM,0,0,0,0,0,0);
+ VOID strcpy(currdate->strtdate, "0.0.0.0.0.0");
recentdate(Head, currdate);
currdate = currdate->dnext;
}
revno = extdate(Head);
- aprintf(out, ";\tselected revisions: %u", revno);
+ aprintf(out, ";\tselected revisions: %d", revno);
}
afputc('\n',out);
@@ -394,17 +467,17 @@ mainProg(rlogId, "rlog", "$Id: rlog.c,v 5.9 1991/09/17 19:07:40 eggert Exp $")
}
if (revno) {
while (! (delta = readdeltalog())->selector || --revno)
- ;
+ continue;
if (delta->next && countnumflds(delta->num)==2)
/* Read through delta->next to get its insertlns. */
while (readdeltalog() != delta->next)
- ;
+ continue;
putrunk();
putree(Head);
}
+ aputs("----------------------------\n", out);
aputs("=============================================================================\n",out);
- } while (cleanup(),
- ++argv, --argc >= 1);
+ }
Ofclose(out);
exitmain(exitstatus);
}
@@ -416,10 +489,10 @@ cleanup()
Izclose(&finptr);
}
-#if lint
+#if RCS_lint
# define exiterr rlogExit
#endif
- exiting void
+ void
exiterr()
{
_exit(EXIT_FAILURE);
@@ -447,7 +520,7 @@ putree(root)
order on each branch */
{
- if ( root == nil ) return;
+ if (!root) return;
putree(root->next);
@@ -462,8 +535,7 @@ putforest(branchroot)
struct branchhead const *branchroot;
/* function: print branches that has the same direct ancestor */
{
-
- if ( branchroot == nil ) return;
+ if (!branchroot) return;
putforest(branchroot->nextbranch);
@@ -480,8 +552,7 @@ putabranch(root)
/* function : print one branch */
{
-
- if ( root == nil) return;
+ if (!root) return;
putabranch(root->next);
@@ -507,17 +578,19 @@ putadelta(node,editscript,trunk)
size_t n;
struct branchhead const *newbranch;
struct buf branchnum;
- char datebuf[datesize];
+ char datebuf[datesize + zonelenmax];
+ int pre5 = RCSversion < VERSION(5);
if (!node->selector)
return;
out = stdout;
aprintf(out,
- "----------------------------\nrevision %s", node->num
+ "----------------------------\nrevision %s%s",
+ node->num, pre5 ? " " : ""
);
if ( node->lockedby )
- aprintf(out, "\tlocked by: %s;", node->lockedby);
+ aprintf(out, pre5+"\tlocked by: %s;", node->lockedby);
aprintf(out, "\ndate: %s; author: %s; state: %s;",
date2str(node->date, datebuf),
@@ -556,9 +629,6 @@ putadelta(node,editscript,trunk)
}
-
-
-
static struct hshentry const *
readdeltalog()
/* Function : get the log message and skip the text of a deltatext node.
@@ -583,9 +653,7 @@ readdeltalog()
cb = savestring(&logbuf);
Delta->log = bufremember(&logbuf, cb.size);
- nextlex();
- while (nexttok==ID && strcmp(NextString,Ktext)!=0)
- ignorephrase();
+ ignorephrases(Ktext);
getkeystring(Ktext);
Delta->insertlns = Delta->deletelns = 0;
if ( Delta != Head)
@@ -607,7 +675,7 @@ struct hshentry * Delta;
declarecache;
register RILE *fin;
register int c;
- register unsigned long i;
+ register long i;
struct diffcmd dc;
fin = finptr;
@@ -623,16 +691,16 @@ struct hshentry * Delta;
cache(fin);
do {
for (;;) {
- cacheget(c);
+ cacheget_(c)
switch (c) {
default:
continue;
case SDELIM:
- cacheget(c);
+ cacheget_(c)
if (c == SDELIM)
continue;
if (--i)
- fatserror("unexpected end to edit script");
+ unexpected_EOF();
nextc = c;
uncache(fin);
return;
@@ -661,10 +729,10 @@ struct hshentry *root;
{
struct branchhead const *newbranch;
- if (root == nil) return;
+ if (!root) return;
root->selector = extractdelta(root);
- root->log.string = nil;
+ root->log.string = 0;
exttree(root->next);
newbranch = root->branches;
@@ -685,26 +753,26 @@ char * argv;
{
register char c;
- struct lockers * newlocker;
+ struct rcslockers *newlocker;
argv--;
- while( ( c = (*++argv)) == ',' || c == ' ' || c == '\t' ||
- c == '\n' || c == ';') ;
+ while ((c = *++argv)==',' || c==' ' || c=='\t' || c=='\n' || c==';')
+ continue;
if ( c == '\0') {
- lockerlist=nil;
+ lockerlist = 0;
return;
}
while( c != '\0' ) {
- newlocker = talloc(struct lockers);
+ newlocker = talloc(struct rcslockers);
newlocker->lockerlink = lockerlist;
newlocker->login = argv;
lockerlist = newlocker;
- while ( ( c = (*++argv)) != ',' && c != '\0' && c != ' '
- && c != '\t' && c != '\n' && c != ';') ;
+ while ((c = *++argv) && c!=',' && c!=' ' && c!='\t' && c!='\n' && c!=';')
+ continue;
*argv = '\0';
if ( c == '\0' ) return;
- while( ( c = (*++argv)) == ',' || c == ' ' || c == '\t' ||
- c == '\n' || c == ';') ;
+ while ((c = *++argv)==',' || c==' ' || c=='\t' || c=='\n' || c==';')
+ continue;
}
}
@@ -721,12 +789,12 @@ char *argv;
struct authors * newauthor;
argv--;
- while( ( c = (*++argv)) == ',' || c == ' ' || c == '\t' ||
- c == '\n' || c == ';') ;
+ while ((c = *++argv)==',' || c==' ' || c=='\t' || c=='\n' || c==';')
+ continue;
if ( c == '\0' ) {
authorlist = talloc(struct authors);
authorlist->login = getusername(false);
- authorlist->nextauthor = nil;
+ authorlist->nextauthor = 0;
return;
}
@@ -735,12 +803,12 @@ char *argv;
newauthor->nextauthor = authorlist;
newauthor->login = argv;
authorlist = newauthor;
- while( ( c = *++argv) != ',' && c != '\0' && c != ' '
- && c != '\t' && c != '\n' && c != ';') ;
+ while ((c = *++argv) && c!=',' && c!=' ' && c!='\t' && c!='\n' && c!=';')
+ continue;
* argv = '\0';
if ( c == '\0') return;
- while( ( c = (*++argv)) == ',' || c == ' ' || c == '\t' ||
- c == '\n' || c == ';') ;
+ while ((c = *++argv)==',' || c==' ' || c=='\t' || c=='\n' || c==';')
+ continue;
}
}
@@ -758,10 +826,10 @@ char * argv;
struct stateattri *newstate;
argv--;
- while( ( c = (*++argv)) == ',' || c == ' ' || c == '\t' ||
- c == '\n' || c == ';') ;
+ while ((c = *++argv)==',' || c==' ' || c=='\t' || c=='\n' || c==';')
+ continue;
if ( c == '\0'){
- warn("missing state attributes after -s options");
+ error("missing state attributes after -s options");
return;
}
@@ -770,12 +838,12 @@ char * argv;
newstate->nextstate = statelist;
newstate->status = argv;
statelist = newstate;
- while( (c = (*++argv)) != ',' && c != '\0' && c != ' '
- && c != '\t' && c != '\n' && c != ';') ;
+ while ((c = *++argv) && c!=',' && c!=' ' && c!='\t' && c!='\n' && c!=';')
+ continue;
*argv = '\0';
if ( c == '\0' ) return;
- while( ( c = (*++argv)) == ',' || c == ' ' || c == '\t' ||
- c == '\n' || c == ';') ;
+ while ((c = *++argv)==',' || c==' ' || c=='\t' || c=='\n' || c==';')
+ continue;
}
}
@@ -787,25 +855,21 @@ trunclocks()
/* id's on lockerlist. Do not truncate if lockerlist empty. */
{
- struct lockers const *plocker;
- struct lock * plocked, * nextlocked;
+ struct rcslockers const *plocker;
+ struct rcslock *p, **pp;
- if ( (lockerlist == nil) || (Locks == nil)) return;
+ if (!lockerlist) return;
/* shorten Locks to those contained in lockerlist */
- plocked = Locks;
- Locks = nil;
- while( plocked != nil) {
- plocker = lockerlist;
- while((plocker != nil) && ( strcmp(plocker->login, plocked->login)!=0))
- plocker = plocker->lockerlink;
- nextlocked = plocked->nextlock;
- if ( plocker != nil) {
- plocked->nextlock = Locks;
- Locks = plocked;
- }
- plocked = nextlocked;
- }
+ for (pp = &Locks; (p = *pp); )
+ for (plocker = lockerlist; ; )
+ if (strcmp(plocker->login, p->login) == 0) {
+ pp = &p->nextlock;
+ break;
+ } else if (!(plocker = plocker->lockerlink)) {
+ *pp = p->nextlock;
+ break;
+ }
}
@@ -821,10 +885,10 @@ recentdate(root, pd)
{
struct branchhead const *newbranch;
- if ( root == nil) return;
+ if (!root) return;
if (root->selector) {
- if ( cmpnum(root->date, pd->strtdate) >= 0 &&
- cmpnum(root->date, pd->enddate) <= 0)
+ if ( cmpdate(root->date, pd->strtdate) >= 0 &&
+ cmpdate(root->date, pd->enddate) <= 0)
VOID strcpy(pd->strtdate, root->date);
}
@@ -841,7 +905,7 @@ recentdate(root, pd)
- static unsigned
+ static int
extdate(root)
struct hshentry * root;
/* function: select revisions which are in the date range specified */
@@ -850,7 +914,7 @@ struct hshentry * root;
{
struct branchhead const *newbranch;
struct Datepairs const *pdate;
- unsigned revno;
+ int revno, ne;
if (!root)
return 0;
@@ -858,20 +922,25 @@ struct hshentry * root;
if ( datelist || duelst) {
pdate = datelist;
while( pdate ) {
- if ( (pdate->strtdate)[0] == '\0' || cmpnum(root->date,pdate->strtdate) >= 0){
- if ((pdate->enddate)[0] == '\0' || cmpnum(pdate->enddate,root->date) >= 0)
+ ne = pdate->ne_date;
+ if (
+ (!pdate->strtdate[0]
+ || ne <= cmpdate(root->date, pdate->strtdate))
+ &&
+ (!pdate->enddate[0]
+ || ne <= cmpdate(pdate->enddate, root->date))
+ )
break;
- }
pdate = pdate->dnext;
}
- if ( pdate == nil) {
+ if (!pdate) {
pdate = duelst;
for (;;) {
if (!pdate) {
root->selector = false;
break;
}
- if ( cmpnum(root->date, pdate->strtdate) == 0)
+ if (cmpdate(root->date, pdate->strtdate) == 0)
break;
pdate = pdate->dnext;
}
@@ -896,11 +965,11 @@ extractdelta(pdelta)
/* statelist, revlist and yield true if pdelta is selected. */
{
- struct lock const *plock;
+ struct rcslock const *plock;
struct stateattri const *pstate;
struct authors const *pauthor;
struct Revpairs const *prevision;
- unsigned length;
+ int length;
if ((pauthor = authorlist)) /* only certain authors wanted */
while (strcmp(pauthor->login, pdelta->author) != 0)
@@ -946,10 +1015,10 @@ getdatepair(argv)
int switchflag;
argv--;
- while( ( c = (*++argv)) == ',' || c == ' ' || c == '\t' ||
- c == '\n' || c == ';') ;
+ while ((c = *++argv)==',' || c==' ' || c=='\t' || c=='\n' || c==';')
+ continue;
if ( c == '\0' ) {
- warn("missing date/time after -d");
+ error("missing date/time after -d");
return;
}
@@ -958,9 +1027,13 @@ getdatepair(argv)
nextdate = talloc(struct Datepairs);
if ( c == '<' ) { /* case: -d <date */
c = *++argv;
+ if (!(nextdate->ne_date = c!='='))
+ c = *++argv;
(nextdate->strtdate)[0] = '\0';
} else if (c == '>') { /* case: -d'>date' */
c = *++argv;
+ if (!(nextdate->ne_date = c!='='))
+ c = *++argv;
(nextdate->enddate)[0] = '\0';
switchflag = true;
} else {
@@ -978,7 +1051,11 @@ getdatepair(argv)
goto end;
} else {
/* case: -d date< or -d date>; see switchflag */
- while ( (c= *++argv) == ' ' || c=='\t' || c=='\n');
+ int eq = argv[1]=='=';
+ nextdate->ne_date = !eq;
+ argv += eq;
+ while ((c = *++argv) == ' ' || c=='\t' || c=='\n')
+ continue;
if ( c == ';' || c == '\0') {
/* second date missing */
if (switchflag)
@@ -1000,14 +1077,17 @@ getdatepair(argv)
nextdate->dnext = datelist;
datelist = nextdate;
end:
+ if (RCSversion < VERSION(5))
+ nextdate->ne_date = 0;
if ( c == '\0') return;
- while( (c = *++argv) == ';' || c == ' ' || c == '\t' || c =='\n');
+ while ((c = *++argv) == ';' || c == ' ' || c == '\t' || c =='\n')
+ continue;
}
}
- static void
+ static int
getnumericrev()
/* function: get the numeric name of revisions which stored in revlist */
/* and then stored the numeric names in Revlst */
@@ -1015,12 +1095,12 @@ getnumericrev()
{
struct Revpairs * ptr, *pt;
- unsigned n;
+ int n;
struct buf s, e;
char const *lrev;
struct buf const *rstart, *rend;
- Revlst = nil;
+ Revlst = 0;
ptr = revlist;
bufautobegin(&s);
bufautobegin(&e);
@@ -1031,48 +1111,48 @@ getnumericrev()
switch (ptr->numfld) {
- case 1: /* -r rev */
- if (expandsym(ptr->strtrev, &s)) {
- rend = &s;
- n = countnumflds(s.string);
- if (!n && (lrev = tiprev())) {
- bufscpy(&s, lrev);
- n = countnumflds(lrev);
- }
- }
+ case 1: /* -rREV */
+ if (!expandsym(ptr->strtrev, &s))
+ goto freebufs;
+ rend = &s;
+ n = countnumflds(s.string);
+ if (!n && (lrev = tiprev())) {
+ bufscpy(&s, lrev);
+ n = countnumflds(lrev);
+ }
break;
- case 2: /* -r rev- */
- if (expandsym(ptr->strtrev, &s)) {
- bufscpy(&e, s.string);
- n = countnumflds(s.string);
- (n<2 ? e.string : strrchr(e.string,'.'))[0] = 0;
- }
+ case 2: /* -rREV: */
+ if (!expandsym(ptr->strtrev, &s))
+ goto freebufs;
+ bufscpy(&e, s.string);
+ n = countnumflds(s.string);
+ (n<2 ? e.string : strrchr(e.string,'.'))[0] = 0;
break;
- case 3: /* -r -rev */
- if (expandsym(ptr->endrev, &e)) {
- if ((n = countnumflds(e.string)) < 2)
- bufscpy(&s, ".1");
- else {
- bufscpy(&s, e.string);
- VOID strcpy(strrchr(s.string,'.'), ".1");
- }
- }
+ case 3: /* -r:REV */
+ if (!expandsym(ptr->endrev, &e))
+ goto freebufs;
+ if ((n = countnumflds(e.string)) < 2)
+ bufscpy(&s, ".0");
+ else {
+ bufscpy(&s, e.string);
+ VOID strcpy(strrchr(s.string,'.'), ".0");
+ }
break;
- default: /* -r rev1-rev2 */
- if (
+ default: /* -rREV1:REV2 */
+ if (!(
expandsym(ptr->strtrev, &s)
&& expandsym(ptr->endrev, &e)
&& checkrevpair(s.string, e.string)
- ) {
- n = countnumflds(s.string);
- /* Swap if out of order. */
- if (compartial(s.string,e.string,n) > 0) {
- rstart = &e;
- rend = &s;
- }
+ ))
+ goto freebufs;
+ n = countnumflds(s.string);
+ /* Swap if out of order. */
+ if (compartial(s.string,e.string,n) > 0) {
+ rstart = &e;
+ rend = &s;
}
break;
}
@@ -1095,8 +1175,11 @@ getnumericrev()
pt->rnext=Revlst; Revlst=pt;
pt->numfld = countnumflds(pt->strtrev);
}
+
+ freebufs:
bufautoend(&s);
bufautoend(&e);
+ return !ptr;
}
@@ -1109,13 +1192,13 @@ checkrevpair(num1,num2)
fields( if length <= 2, may be different if first field) */
{
- unsigned length = countnumflds(num1);
+ int length = countnumflds(num1);
if (
countnumflds(num2) != length
- || 2 < length && compartial(num1, num2, length-1) != 0
+ || (2 < length && compartial(num1, num2, length-1) != 0)
) {
- error("invalid branch or revision pair %s : %s", num1, num2);
+ rcserror("invalid branch or revision pair %s : %s", num1, num2);
return false;
}
@@ -1172,7 +1255,8 @@ register char * argv;
while (c==' ' || c=='\t' || c=='\n')
c = *++argv;
if (c == separator) {
- while( (c =(*++argv)) == ' ' || c == '\t' || c =='\n') ;
+ while ((c = *++argv) == ' ' || c == '\t' || c =='\n')
+ continue;
nextrevpair->endrev = argv;
for (;; c = *++argv) {
switch (c) {
@@ -1183,8 +1267,8 @@ register char * argv;
break;
case ':': case '-':
if (c == separator)
- continue;
- break;
+ break;
+ continue;
}
break;
}
@@ -1192,13 +1276,15 @@ register char * argv;
while (c==' ' || c=='\t' || c =='\n')
c = *++argv;
nextrevpair->numfld =
- !nextrevpair->endrev[0] ? 2 /* -rrev- */ :
- !nextrevpair->strtrev[0] ? 3 /* -r-rev */ :
- 4 /* -rrev1-rev2 */;
+ !nextrevpair->endrev[0] ? 2 /* -rREV: */ :
+ !nextrevpair->strtrev[0] ? 3 /* -r:REV */ :
+ 4 /* -rREV1:REV2 */;
}
if (!c)
break;
- if (c!=',' && c!=';')
+ else if (c==',' || c==';')
+ c = *++argv;
+ else
error("missing `,' near `%c%s'", c, argv+1);
}
}
diff --git a/gnu/usr.bin/sdiff/Makefile b/gnu/usr.bin/sdiff/Makefile
new file mode 100644
index 0000000..449a933
--- /dev/null
+++ b/gnu/usr.bin/sdiff/Makefile
@@ -0,0 +1,9 @@
+PROG= sdiff
+SRCS= sdiff.c getopt.c getopt1.c version.c
+CFLAGS+= -I$(.CURDIR)/../diff -DHAVE_CONFIG_H \
+ -DDIFF_PROGRAM=\"/usr/bin/diff\"
+.PATH: $(.CURDIR)/../diff
+MAN= sdiff.1
+
+.include <bsd.prog.mk>
+.PATH: $(.CURDIR)/../diff
diff --git a/gnu/usr.bin/sdiff/sdiff.1 b/gnu/usr.bin/sdiff/sdiff.1
new file mode 100644
index 0000000..8b7e88c
--- /dev/null
+++ b/gnu/usr.bin/sdiff/sdiff.1
@@ -0,0 +1,198 @@
+.TH SDIFF 1 "22sep1993" "GNU Tools" "GNU Tools"
+.SH NAME
+sdiff \- find differences between two files and merge interactively
+.SH SYNOPSIS
+.B sdiff
+.B -o
+outfile [options] from-file to-file
+.SH DESCRIPTION
+The
+.I sdiff
+command merges two files and interactively outputs the
+results to
+.IR outfile .
+
+If
+.I from-file
+is a directory and
+.I to-file
+is not,
+.I sdiff
+compares the file in
+.I from-file
+whose file name is that of
+.IR to-file ,
+and vice versa.
+.I from-file
+and
+.I to-file
+may not both be
+directories.
+
+.I sdiff
+options begin with
+.BR \- ,
+so normally
+.I from-file
+and
+.I to-file
+may not begin with
+.BR \- .
+However,
+.B \-\-
+as an
+argument by itself treats the remaining arguments as file names even if
+they begin with
+.BR \- .
+You may not use
+.B \-
+as an input file.
+
+.I sdiff
+without
+.B \-o
+(or
+.BR \-\-output )
+produces a
+side-by-side difference. This usage is obsolete; use
+.B "diff \-\-side\-by\-side"
+instead.
+.SS Options
+Below is a summary of all of the options that GNU
+.I sdiff
+accepts.
+Each option has two equivalent names, one of which is a single
+letter preceded by
+.BR \- ,
+and the other of which is a long name
+preceded by
+.BR \-\- .
+Multiple single letter options (unless they take
+an argument) can be combined into a single command line argument. Long
+named options can be abbreviated to any unique prefix of their name.
+.TP
+.B \-a
+Treat all files as text and compare them line-by-line, even if they
+do not appear to be text.
+.TP
+.B \-b
+Ignore changes in amount of white space.
+.TP
+.B \-B
+Ignore changes that just insert or delete blank lines.
+.TP
+.B \-d
+Change the algorithm to perhaps find a smaller set of changes. This
+makes
+.I sdiff
+slower (sometimes much slower).
+.TP
+.B \-H
+Use heuristics to speed handling of large files that have numerous
+scattered small changes.
+.TP
+.B \-\-expand\-tabs
+Expand tabs to spaces in the output, to preserve the alignment of tabs
+in the input files.
+.TP
+.B \-i
+Ignore changes in case; consider upper- and lower-case to be the same.
+.TP
+.BI "\-I " regexp
+Ignore changes that just insert or delete lines that match
+.IR regexp .
+.TP
+.B \-\-ignore\-all\-space
+Ignore white space when comparing lines.
+.TP
+.B \-\-ignore\-blank\-lines
+Ignore changes that just insert or delete blank lines.
+.TP
+.B \-\-ignore\-case
+Ignore changes in case; consider upper- and lower-case to be the same.
+.TP
+.BI \-\-ignore\-matching\-lines= regexp
+Ignore changes that just insert or delete lines that match
+.IR regexp .
+.TP
+.B \-\-ignore\-space\-change
+Ignore changes in amount of white space.
+.TP
+.B \-l
+.br
+.ns
+.TP
+.B \-\-left\-column
+Print only the left column of two common lines.
+.TP
+.B \-\-minimal
+Change the algorithm to perhaps find a smaller set of changes. This
+makes
+.I sdiff
+slower (sometimes much slower).
+.TP
+.BI "\-o " file
+.br
+.ns
+.TP
+.BI \-\-output= file
+Put merged output into
+.IR file .
+This option is required for merging.
+.TP
+.B \-s
+.br
+.ns
+.TP
+.B \-\-suppress\-common\-lines
+Do not print common lines.
+.TP
+.B \-\-speed\-large\-files
+Use heuristics to speed handling of large files that have numerous
+scattered small changes.
+.TP
+.B \-t
+Expand tabs to spaces in the output, to preserve the alignment of tabs
+in the input files.
+.TP
+.B \-\-text
+Treat all files as text and compare them line-by-line, even if they
+do not appear to be text.
+.TP
+.B \-v
+.br
+.ns
+.TP
+.B \-\-version
+Output the version number of
+.IR sdiff .
+.TP
+.BI "\-w " columns
+.br
+.ns
+.TP
+.BI \-\-width= columns
+Use an output width of
+.IR columns .
+Note that for historical reasons, this option is
+.B \-W
+in
+.IR diff ,
+.B \-w
+in
+.IR sdiff .
+.TP
+.B \-W
+Ignore horizontal white space when comparing lines.
+Note that for historical reasons, this option is
+.B \-w
+in
+.IR diff ,
+.B \-W
+in
+.IR sdiff .
+.SH SEE ALSO
+cmp(1), comm(1), diff(1), diff3(1).
+.SH DIAGNOSTICS
+An exit status of 0 means no differences were found, 1 means some
+differences were found, and 2 means trouble.
diff --git a/gnu/usr.bin/send-pr/COPYING b/gnu/usr.bin/send-pr/COPYING
new file mode 100644
index 0000000..515b6d3
--- /dev/null
+++ b/gnu/usr.bin/send-pr/COPYING
@@ -0,0 +1,339 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 675 Mass Ave, Cambridge, MA 02139, USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+he GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ Appendix: How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) 19yy <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) 19yy name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/gnu/usr.bin/send-pr/Makefile b/gnu/usr.bin/send-pr/Makefile
new file mode 100644
index 0000000..a6e4d22
--- /dev/null
+++ b/gnu/usr.bin/send-pr/Makefile
@@ -0,0 +1,36 @@
+#
+# Makefile for building a standalone send-pr.
+#
+
+MAN1= send-pr.1
+SUBMITTERS= current-users
+RELEASE= `uname -rsm`
+RELEASE_EV!= uname -rsm
+CLEANFILES+= send-pr send-pr.el
+
+SUBDIR+= doc
+
+LINKS= ${BINDIR}/send-pr ${BINDIR}/sendbug
+MLINKS= send-pr.1 sendbug.1
+
+all: send-pr _PROGSUBDIR
+
+send-pr: send-pr.sh Makefile
+ sed -e 's,@DATADIR@,/etc,g' \
+ -e 's/@DEFAULT_RELEASE@/$(RELEASE)/g' \
+ -e 's/^SUBMITTER=.*/SUBMITTER=$(SUBMITTERS)/' \
+ ${.ALLSRC:N*Makefile} > ${.TARGET}
+
+send-pr.el: send-pr-el.in Makefile
+ sed -e 's,@DATADIR@,/etc,g' \
+ -e 's/@DEFAULT_RELEASE@/$(RELEASE_EV)/g' \
+ -e 's/"unknown"/"$(SUBMITTERS)"/g' \
+ ${.ALLSRC:N*Makefile} > ${.TARGET}
+
+beforeinstall:
+ ${INSTALL} -c -o ${BINOWN} -g ${BINGRP} -m ${BINMODE} \
+ send-pr ${DESTDIR}${BINDIR}/send-pr
+ ${INSTALL} -c -o ${BINOWN} -g ${BINGRP} -m 0644 \
+ ${.CURDIR}/categories ${DESTDIR}/etc/gnats/freefall
+
+.include <bsd.prog.mk>
diff --git a/gnu/usr.bin/send-pr/README b/gnu/usr.bin/send-pr/README
new file mode 100644
index 0000000..b479179
--- /dev/null
+++ b/gnu/usr.bin/send-pr/README
@@ -0,0 +1,43 @@
+ send-pr - sends bug reports to a central support site
+
+`send-pr' uses electronic mail to submit support questions and
+software bugs to a central site. No piece of software is perfect, and
+software organizations understand this `send-pr' is designed to allow
+users who have problems to submit reports of these problems to sites
+responsible for supporting the software in question, in a defined form
+which can be read by an electronically managed database.
+
+`send-pr' is part of a suite of programs known collectively as GNATS,
+an acronym for Problem Report Management System. GNATS consists of
+several programs which, used in concert, formulate and partially
+administer a database of Problem Reports, or PRs, at a central support
+site. A PR goes through several states in its lifetime; GNATS tracks
+the PR and all information associated with it through each state and
+finally acts as an archive for PRs which have been resolved.
+
+The same engine can be used to submit bugs to any number of support
+sites by setting up aliases for each of them; `send-pr' error-checks
+each PR as it is sent to be sure that the category specified matches a
+category supported by the site in question.
+
+`send-pr' invokes an editor on a problem report template (after trying
+to fill in some fields with reasonable default values). When you exit
+the editor, `send-pr' sends the completed form to the support site.
+At the support site, the PR is assigned a unique number and is stored
+in the GNATS database according to its category and customer-id. GNATS
+automatically replies with an acknowledgement, citing the category and
+the PR number.
+
+See the Texinfo file `send-pr.texi' or the Info file `send-pr.info'
+for detailed installation and usage information.
+
+See the file MANIFEST for a list of the files which should have
+accompanied this distribution.
+
+See `send-pr.texi', `send-pr.info', or the file INSTALL for the
+installation procedure for `send-pr'.
+
+
+Copyright (c) 1993, Free Software Foundation, Inc.
+See the file COPYING for copyright information concerning this
+distribution and all its components.
diff --git a/gnu/usr.bin/send-pr/categories b/gnu/usr.bin/send-pr/categories
new file mode 100644
index 0000000..ddf4e56
--- /dev/null
+++ b/gnu/usr.bin/send-pr/categories
@@ -0,0 +1,8 @@
+bin
+conf
+docs
+gnu
+i386
+kern
+misc
+ports
diff --git a/gnu/usr.bin/send-pr/doc/Makefile b/gnu/usr.bin/send-pr/doc/Makefile
new file mode 100644
index 0000000..3a09e56
--- /dev/null
+++ b/gnu/usr.bin/send-pr/doc/Makefile
@@ -0,0 +1,3 @@
+INFO = send-pr
+
+.include <bsd.info.mk>
diff --git a/gnu/usr.bin/send-pr/doc/categ.texi b/gnu/usr.bin/send-pr/doc/categ.texi
new file mode 100644
index 0000000..b02243e
--- /dev/null
+++ b/gnu/usr.bin/send-pr/doc/categ.texi
@@ -0,0 +1,123 @@
+@node Valid Categories
+@unnumberedsec Valid Categories
+@cindex valid categories
+@cindex example of a list of valid categories
+
+@table @code
+@item bfd
+@sc{gnu} binary file descriptor library.
+
+@item bifrabulator
+This one doesn't actually exist.
+
+@item binutils
+@sc{gnu} utilities for binary files (@code{ar}, @code{nm}, @code{size}@dots{}).
+
+@item bison
+@sc{gnu} parser generator.
+
+@item byacc
+Free parser generator.
+
+@item config
+Cygnus Support Software configuration and installation.
+
+@item cvs
+Concurrent Version System.
+
+@item diff
+@sc{gnu} @code{diff} program.
+
+@item doc
+Documentation and manuals.
+
+@item emacs
+@sc{gnu} Emacs editor and related functions.
+
+@item flex
+@sc{gnu} lexical analyzer.
+
+@item g++
+@sc{gnu} C++ compiler.
+
+@item gas
+@sc{gnu} assembler.
+
+@item gcc
+@sc{gnu} C compiler.
+
+@item gdb
+@sc{gnu} source code debugger.
+
+@item glob
+The filename globbing functions.
+
+@item gprof
+@sc{gnu} profiler.
+
+@item grep
+@sc{gnu} @code{grep} program.
+
+@item info
+@sc{gnu} @code{info} hypertext reader.
+
+@item ispell
+@sc{gnu} spelling checker.
+
+@item kerberos
+Kerberos authentication system.
+
+@item ld
+@sc{gnu} linker.
+
+@item libc
+Cygnus Support C Support Library.
+
+@item libg++
+@sc{gnu} C++ class library.
+
+@item libiberty
+@sc{gnu} @samp{libiberty} library.
+
+@item libm
+Cygnus Support C Math Library.
+
+@item make
+@sc{gnu} @code{make} program.
+
+@item makeinfo
+@sc{gnu} utility to build Info files from Texinfo documents.
+
+@item mas
+@sc{gnu} Motorola syntax assembler.
+
+@item newlib
+Cygnus Support C Support and Math Libraries.
+
+@item patch
+@sc{gnu} bug patch program.
+
+@item gnats
+@sc{gnu} Problem Report Management System.
+
+@item rcs
+Revision Control System.
+
+@item readline
+@sc{gnu} @code{readline} library.
+
+@item send-pr
+@sc{gnu} Problem Report submitting program.
+
+@item test
+Category to use when testing @code{send-pr}.
+
+@item texindex
+@sc{gnu} documentation indexing utility.
+
+@item texinfo
+@sc{gnu} documentation macros.
+
+@item other
+Anything which is not covered by the above categories.
+@end table
diff --git a/gnu/usr.bin/send-pr/doc/fields.texi b/gnu/usr.bin/send-pr/doc/fields.texi
new file mode 100644
index 0000000..e8921d6
--- /dev/null
+++ b/gnu/usr.bin/send-pr/doc/fields.texi
@@ -0,0 +1,518 @@
+@node Fields
+@section Problem Report format
+@cindex Problem Report format
+@cindex format
+@cindex database similarities
+@cindex fields
+
+The format of a PR is designed to reflect the nature of @sc{gnats} as a
+database. Information is arranged into @dfn{fields}, and kept in
+individual records (Problem Reports).
+
+Problem Report fields are denoted by a keyword which begins with
+@samp{>} and ends with @samp{:}, as in @samp{>Confidential:}. Fields
+belong to one of three data types:
+
+@table @asis
+@cindex Problem Report data types
+@cindex @emph{Enumerated} data types
+@item @sc{Enumerated}
+One of a specific set of values, which vary according to the field. The
+value for each keyword must be on the same line as the keyword. These
+values are not configurable (yet).
+
+@ifset SENDPR
+For each @sc{Enumerated} keyword, the possible choices are listed in the
+@code{send-pr} template as a comment.
+@end ifset
+The following fields are @sc{Enumerated} format; see the descriptions of
+fields below for explanations of each field in detail:
+
+@smallexample
+@group
+>Confidential: >Severity: >Priority:
+>Class: >State: >Number:
+@end group
+@end smallexample
+
+@cindex @emph{Text} data types
+@item @sc{Text}
+One single line of text which must begin and end on the same line (i.e.,
+before a newline) as the keyword. See the descriptions of fields below
+for explanations of each field in detail. The following fields are
+@sc{Text} format:
+
+@smallexample
+@group
+>Submitter-Id: >Originator: >Synopsis:
+>Category: >Release: >Responsible:
+>Arrival-Date:
+@end group
+@end smallexample
+
+@cindex @emph{MultiText} data types
+@item @sc{MultiText}
+Text of any length may occur in this field. @sc{MultiText} may span
+multiple lines and may also include blank lines. A @sc{MultiText} field
+ends only when another keyword appears. See the descriptions of fields
+below for explanations of each field in detail.
+
+The following fields are @sc{MultiText} format:
+
+@smallexample
+@group
+>Organization: >Environment: >Description:
+>How-To-Repeat: >Fix: >Audit-Trail:
+>Unformatted:
+@end group
+@end smallexample
+
+@end table
+
+A Problem Report contains two different types of fields: @dfn{Mail
+Header} fields, which are used by the mail handler for delivery, and
+@dfn{Problem Report} fields, which contain information relevant to the
+Problem Report and its submitter. A Problem Report is essentially a
+specially formatted electronic mail message.
+
+@ifclear SENDPR
+@subheading Example Problem Report
+@end ifclear
+
+The following is an example Problem Report. Mail headers are at the
+top, followed by @sc{gnats} fields, which begin with @samp{>} and end
+with @samp{:}. The @samp{Subject:} line in the mail header and the
+@samp{>Synopsis:} field are usually duplicates of each other.
+
+@cindex sample Problem Report
+@cindex example Problem Report
+@cindex Problem Report template
+@cartouche
+@smallexample
+@group
+Message-Id: @var{message-id}
+Date: @var{date}
+From: @var{address}
+Reply-To: @var{address}
+To: @var{bug-address}
+Subject: @var{subject}
+
+>Number: @var{gnats-id}
+>Category: @var{category}
+>Synopsis: @var{synopsis}
+>Confidential: yes @emph{or} no
+>Severity: critical, serious, @emph{or} non-critical
+>Priority: high, medium @emph{or} low
+>Responsible: @var{responsible}
+>State: open, analyzed, suspended, feedback, @emph{or} closed
+>Class: sw-bug, doc-bug, change-request, support,
+@ifset SENDPR
+@emph{or} duplicate
+@end ifset
+@ifclear SENDPR
+duplicate, @emph{or} mistaken
+@end ifclear
+>Submitter-Id: @var{submitter-id}
+>Arrival-Date: @var{date}
+>Originator: @var{name}
+>Organization: @var{organization}
+>Release: @var{release}
+>Environment:
+ @var{environment}
+>Description:
+ @var{description}
+>How-To-Repeat:
+ @var{how-to-repeat}
+>Fix:
+ @var{fix}
+>Audit-Trail:
+@var{appended-messages@dots{}}
+State-Changed-From-To: @var{from}-@var{to}
+State-Changed-When: @var{date}
+State-Changed-Why:
+ @var{reason}
+Responsible-Changed-From-To: @var{from}-@var{to}
+Responsible-Changed-When: @var{date}
+Responsible-Changed-Why:
+ @var{reason}
+>Unformatted:
+ @var{miscellaneous}
+@end group
+@end smallexample
+@end cartouche
+
+@menu
+* Mail header fields::
+* Problem Report fields::
+@end menu
+
+@c ----------------------
+@node Mail header fields
+@subsection Mail header fields
+@cindex mail header fields
+@cindex Internet standard RFC-822
+
+A Problem Report may contain any mail header field described in the
+Internet standard RFC-822. However, only the fields which identify the
+sender and the subject are required by @code{send-pr}:
+
+@table @code
+@cindex @code{To:} header
+@item To:
+The preconfigured mail address for the Support Site where the PR is to
+be sent, automatically supplied by @code{send-pr}.
+
+@cindex @code{Subject:} header
+@item Subject:
+A terse description of the problem. This field normally contains the
+same information as the @samp{>Synopsis:} field.
+
+@cindex @code{From:} header
+@item From:
+Usually supplied automatically by the originator's mailer; should
+contain the originator's electronic mail address.
+
+@cindex @code{Reply-To:} header
+@item Reply-To:
+A return address to which electronic replies can be sent; in most cases,
+the same address as the @code{From:} field.
+@end table
+
+@ifclear SENDPR
+@cindex @code{Received-By:} headers
+One of the configurable options for @sc{gnats} is whether or not to
+retain @w{@samp{Received-By:}} headers, which often consume a lot of
+space and are not often used. @xref{Local configuration,,Changing your
+local configuration}.
+@end ifclear
+
+@c ----------------------
+@node Problem Report fields
+@subsection Problem Report fields
+@cindex GNATS database fields
+@cindex field format
+
+@c FIXME - this node is loooooooooooooooong...
+
+@subheading Field descriptions
+
+The following fields are present whenever a PR is submitted via the
+program @code{send-pr}. @sc{gnats} adds additional fields when the PR
+arrives at the Support Site; explanations of these follow this list.
+
+@cindex fields - list
+@cindex GNATS fields - list
+@table @code
+@item >Submitter-Id:
+@cindex @code{Submitter-Id} field
+@cindex @code{>Submitter-Id:}
+(@sc{Text}) A unique identification code assigned by the Support Site.
+It is used to identify all Problem Reports coming from a particular
+site. (Submitters without a value for this field can invoke
+@code{send-pr} with the @samp{--request-id} option to apply for one from
+the support organization. Problem Reports from those not affiliated
+with the support organization should use the default value of @samp{net}
+for this field.)
+
+@item >Originator:
+@cindex @code{Originator} field
+@cindex @code{>Originator:}
+(@sc{Text}) Originator's real name. The default is the value of the
+originator's environment variable @code{NAME}.
+
+@item >Organization:
+@cindex @code{>Organization:}
+@cindex @code{Organization} field
+(@sc{MultiText}) The originator's organization. The default value is
+set with the variable @w{@code{DEFAULT_ORGANIZATION}} in the
+@ifclear SENDPR
+@file{config} file (@pxref{config,,The @code{config} file}).
+@end ifclear
+@ifset SENDPR
+@code{send-pr} shell script.
+@end ifset
+
+@item >Confidential:
+@cindex @code{Confidential} field
+@cindex @code{>Confidential:}
+@cindex confidentiality in PRs
+@cindex PR confidentiality
+(@sc{Enumerated}) Use of this field depends on the originator's
+relationship with the support organization; contractual agreements often
+have provisions for preserving confidentiality. Conversely, a lack of a
+contract often means that any data provided will not be considered
+confidential. Submitters should be advised to contact the support
+organization directly if this is an issue.
+
+If the originator's relationship to the support organization provides
+for confidentiality, then if the value of this field is @samp{yes} the
+support organization treats the PR as confidential; any code samples
+provided are not made publicly available (e.g., in regression test
+suites). The default value is @samp{yes}.
+
+@item >Synopsis:
+@cindex @code{Synopsis} field
+@cindex @code{>Synopsis:}
+(@sc{Text}) One-line summary of the problem. @w{@code{send-pr}} copies
+this information to the @samp{Subject:} line when you submit a Problem
+Report.
+
+@item >Severity:
+@cindex @code{Severity} field
+@cindex @code{>Severity:}
+(@sc{Enumerated}) The severity of the problem. Accepted values include:
+
+@table @code
+@cindex @emph{critical} severity problems
+@item critical
+The product, component or concept is completely non-operational or some
+essential functionality is missing. No workaround is known.
+
+@cindex @emph{serious} severity problems
+@item serious
+The product, component or concept is not working properly or significant
+functionality is missing. Problems that would otherwise be considered
+@samp{critical} are rated @samp{serious} when a workaround is known.
+
+@cindex @emph{non-critical} severity problems
+@item non-critical
+The product, component or concept is working in general, but lacks
+features, has irritating behavior, does something wrong, or doesn't
+match its documentation.
+@end table
+The default value is @samp{serious}.
+@sp 1
+
+@item >Priority:
+@cindex @code{Priority} field
+@cindex @code{>Priority:}
+(@sc{Enumerated}) How soon the originator requires a solution. Accepted
+values include:
+
+@table @code
+@cindex @emph{high} priority problems
+@item high
+A solution is needed as soon as possible.
+
+@cindex @emph{medium} priority problems
+@item medium
+The problem should be solved in the next release.
+
+@cindex @emph{low} priority problems
+@item low
+The problem should be solved in a future release.
+@end table
+@noindent
+The default value is @samp{medium}.
+@sp 1
+
+@item >Category:
+@cindex @code{Category} field
+@cindex @code{>Category:}
+(@sc{Text}) The name of the product, component or concept where
+the problem lies. The values for this field are defined by the Support
+Site.
+@ifclear SENDPR
+@xref{categories,,The @code{categories} file}, for details.
+@end ifclear
+
+@item >Class:
+@cindex @code{Class} field
+@cindex @code{>Class:}
+(@sc{Enumerated}) The class of a problem can be one of the following:
+
+@table @code
+@cindex @emph{sw-bug} class
+@item sw-bug
+A general product problem. (@samp{sw} stands for ``software''.)
+
+@cindex @emph{doc-bug} class
+@item doc-bug
+A problem with the documentation.
+
+@cindex @emph{change-request} class
+@item change-request
+A request for a change in behavior, etc.
+
+@cindex @emph{support} class
+@item support
+A support problem or question.
+
+@cindex @emph{duplicate} class
+@item duplicate (@var{pr-number})
+Duplicate PR. @var{pr-number} should be the number of the original PR.
+
+@ifclear SENDPR
+@cindex @emph{mistaken} class
+@item mistaken
+No problem, user error or misunderstanding. This value is valid only at
+the Support Site.
+@end ifclear
+@end table
+
+@noindent
+The default is @samp{sw-bug}.
+@sp 1
+
+@item >Release:
+@cindex @code{Release} field
+@cindex @code{>Release:}
+(@sc{Text}) Release or version number of the product, component or
+concept.
+
+@item >Environment:
+@cindex @code{Environment} field
+@cindex @code{>Environment:}
+(@sc{MultiText}) Description of the environment where the problem occured:
+machine architecture, operating system, host and target types,
+libraries, pathnames, etc.
+
+@item >Description:
+@cindex @code{Description} field
+@cindex @code{>Description:}
+(@sc{MultiText}) Precise description of the problem.
+
+@item >How-To-Repeat:
+@cindex @code{How-To-Repeat} field
+@cindex @code{>How-To-Repeat:}
+(@sc{MultiText}) Example code, input, or activities to reproduce the
+problem. The support organization uses example code both to reproduce
+the problem and to test whether the problem is fixed. Include all
+preconditions, inputs, outputs, conditions after the problem, and
+symptoms. Any additional important information should be included.
+Include all the details that would be necessary for someone else to
+recreate the problem reported, however obvious. Sometimes seemingly
+arbitrary or obvious information can point the way toward a solution.
+See also @ref{Helpful hints,,Helpful hints}.
+
+@item >Fix:
+@cindex @code{Fix} field
+@cindex @code{>Fix:}
+(@sc{MultiText}) A description of a solution to the problem, or a patch
+which solves the problem. (This field is most often filled in at the
+Support Site; we provide it to the submitter in case she has solved the
+problem.)
+
+@end table
+
+@noindent
+@sc{gnats} adds the following fields when the PR arrives at the Support
+Site:
+
+@table @code
+@cindex @code{Number} field
+@cindex @code{>Number:}
+@item >Number:
+(@sc{Enumerated}) The incremental identification number for this PR.
+@ifclear SENDPR
+This is included in the automated reply to the submitter (if that
+feature of @sc{gnats} is activated; @pxref{Local configuration,,Changing
+your local configuration}). It is also included in the copy of the PR
+that is sent to the maintainer.
+@end ifclear
+
+The @samp{>Number:} field is often paired with the @samp{>Category:}
+field as
+
+@smallexample
+@var{category}/@var{number}
+@end smallexample
+
+@noindent
+in subsequent email messages. This is for historical reasons, as well
+as because Problem Reports are stored in subdirectories which are named
+by category.
+
+@cindex @code{State} field
+@cindex @code{>State:}
+@item >State:
+(@sc{Enumerated}) The current state of the PR. Accepted values are:
+
+@table @code
+@item open
+The PR has been filed and the responsible person notified.
+
+@item analyzed
+The responsible person has analyzed the problem.
+
+@item feedback
+The problem has been solved, and the originator has been given a patch
+or other fix.
+
+@item closed
+The changes have been integrated, documented, and tested, and the
+originator has confirmed that the solution works.
+
+@item suspended
+Work on the problem has been postponed.
+@end table
+
+@noindent
+The initial state of a PR is @samp{open}. @xref{States,,States of
+Problem Reports}.
+
+@cindex @code{Responsible} field
+@cindex @code{>Responsible:}
+@item >Responsible:
+(@sc{Text}) The person responsible for this category.
+@ifclear SENDPR
+@sc{gnats} retrieves this information from the @file{categories} file
+(@pxref{categories,,The @code{categories} file}).
+@end ifclear
+
+@item >Arrival-Date:
+@cindex @code{>Arrival-Date:}
+@cindex @code{Arrival-Date} field
+(@sc{Text}) The time that this PR was received by @sc{gnats}. The date
+is provided automatically by @sc{gnats}.
+
+@item >Audit-Trail:
+@cindex @code{>Audit-Trail:}
+@cindex @code{Audit-Trail} field
+(@sc{MultiText}) Tracks related electronic mail as well as changes in
+the @samp{>State:} and @samp{>Responsible:} fields with the sub-fields:
+
+@table @code
+@cindex @code{State-Changed-<From>-<To>:} in @code{>Audit-Trail:}
+@item @w{State-Changed-<From>-<To>: @var{oldstate}>-<@var{newstate}}
+The old and new @samp{>State:} field values.
+
+@cindex @code{Responsible-Changed-<From>-<To>:} in @code{>Audit-Trail:}
+@item @w{Responsible-Changed-<From>-<To>: @var{oldresp}>-<@var{newresp}}
+The old and new @samp{>Responsible:} field values.
+
+@cindex @code{State-Changed-By:} in @code{>Audit-Trail:}
+@cindex @code{Responsible-Changed-By:} in @code{>Audit-Trail:}
+@item State-Changed-By: @var{name}
+@itemx Responsible-Changed-By: @var{name}
+The name of the maintainer who effected the change.
+
+@cindex @code{State-Changed-When:} in @code{>Audit-Trail:}
+@cindex @code{Responsible-Changed-When:} in @code{>Audit-Trail:}
+@item State-Changed-When: @var{timestamp}
+@itemx Responsible-Changed-When: @var{timestamp}
+The time the change was made.
+
+@cindex @code{State-Changed-Why:} in @code{>Audit-Trail:}
+@cindex @code{Responsible-Changed-Why:} in @code{>Audit-Trail:}
+@item State-Changed-Why: @var{reason@dots{}}
+@itemx Responsible-Changed-Why: @var{reason@dots{}}
+The reason for the change.
+@end table
+
+@noindent
+@cindex subsequent mail
+@cindex other mail
+@cindex appending PRs
+@cindex saving related mail
+@cindex related mail
+The @samp{>Audit-Trail:} field also contains any mail messages received
+by @sc{gnats} related to this PR, in the order received.
+
+@item >Unformatted:
+@cindex @code{>Unformatted:}
+@cindex @code{Unformatted} field
+(@sc{MultiText}) Any random text found outside the fields in the
+original Problem Report.
+@end table
+
diff --git a/gnu/usr.bin/send-pr/doc/s-usage.texi b/gnu/usr.bin/send-pr/doc/s-usage.texi
new file mode 100644
index 0000000..06fefee
--- /dev/null
+++ b/gnu/usr.bin/send-pr/doc/s-usage.texi
@@ -0,0 +1,519 @@
+@c This is the usage section for send-pr. It is called as
+@c chapter (Invoking send-pr) by send-pr.texi, and also as
+@c section (Submitting Problem Reports) by gnats.texi (chapter/section
+@c identifiers are adjusted accordingly)
+
+@c FIXME! This still seems jumbled...
+
+You can invoke @code{send-pr} from a shell prompt or from within
+@sc{gnu} Emacs using @w{@samp{M-x send-pr}}.
+
+@menu
+* using send-pr:: Creating new Problem Reports
+* send-pr in Emacs:: Using send-pr from within Emacs
+* send-pr from the shell:: Invoking send-pr from the shell
+* Helpful hints::
+@end menu
+
+@node using send-pr
+@section Creating new Problem Reports
+
+@c FIXME - this is a long node
+Invoking @code{send-pr} presents a PR @dfn{template} with a number of
+fields already filled in. Complete the template as thoroughly as
+possible to make a useful bug report. Submit only one bug with each PR.
+
+@cindex template
+A template consists of three sections:
+
+@table @dfn
+@item Comments
+The top several lines of a blank template consist of a series of
+comments that provide some basic instructions for completing the Problem
+Report, as well as a list of valid entries for the @samp{>Category:}
+field. These comments are all preceded by the string @samp{SEND-PR:}
+and are erased automatically when the PR is submitted. The
+instructional comments within @samp{<} and @samp{>} are also removed.
+(Only these comments are removed; lines you provide that happen to have
+those characters in them, such as examples of shell-level redirection,
+are not affected.)
+
+@item Mail Header
+@code{send-pr} creates a standard mail header. @code{send-pr} completes
+all fields except the @samp{Subject:} line with default values.
+(@xref{Fields,,Problem Report format}.)
+
+@item @sc{gnats} fields
+These are the informational fields that @sc{gnats} uses to route your
+Problem Report to the responsible party for further action. They should
+be filled out as completely as possible. (@xref{Fields,,Problem Report
+format}. Also see @ref{Helpful hints,,Helpful hints}.)
+@end table
+
+@ifset SENDPR
+@noindent
+For examples of a Problem Report template and complete Problem Report,
+see @ref{An Example}.
+@end ifset
+
+The default template contains your preconfigured @samp{>Submitter-Id:}.
+@code{send-pr} attempts to determine values for the @samp{>Originator:}
+and @samp{>Organization:} fields (@pxref{Fields,,Problem Report
+format}). @code{send-pr} also attempts to find out some information
+about your system and architecture, and places this information in the
+@samp{>Environment:} field if it finds any.
+
+You may submit problem reports to different Support Sites from the
+default site by specifying the alternate site when you invoke
+@code{send-pr}. Each @code{site} has its own list of categories for
+which it accepts Problem Reports.
+@c FIXME! This should go in..
+@c For a list of sites to whom @code{send-pr} is configured to send
+@c Problem Reports, type @w{@samp{send-pr -S}}.
+@ifset SENDPR
+(@xref{default site,,Setting a default @var{site}}.)
+@end ifset
+
+@code{send-pr} also provides the mail header section of the template
+with default values in the @samp{To:}, @samp{From:}, and
+@samp{Reply-To:} fields. The @samp{Subject:} field is empty.
+
+The template begins with a comment section:
+
+@cindex template comment section
+@cindex comment section in the PR template
+@smallexample
+@group
+SEND-PR: -*- send-pr -*-
+SEND-PR: Lines starting with `SEND-PR' will be removed
+SEND-PR: automatically as well as all comments (the text
+SEND-PR: below enclosed in `<' and `>').
+SEND-PR:
+SEND-PR: Please consult the document `Reporting Problems
+SEND-PR: Using send-pr' if you are not sure how to fill out
+SEND-PR: a problem report.
+SEND-PR:
+SEND-PR: Choose from the following categories:
+@end group
+@end smallexample
+
+@noindent
+and also contains a list of valid @code{>Category:} values for the
+Support Site to whom you are submitting this Problem Report. One (and
+only one) of these values should be placed in the @code{>Category:}
+field.
+@ifset SENDPR
+A complete sample bug report, from template to completed PR, is shown in
+@ref{An Example}. For a complete list of valid categories, type
+@w{@samp{send-pr -L}} at your prompt. @xref{Valid Categories,,Valid
+Categories}, for a sample list of categories, .
+@end ifset
+
+@c FIXME.. this sounds awkward
+The mail header is just below the comment section. Fill out the
+@samp{Subject:} field, if it is not already completed using the value of
+@samp{>Synopsis:}. The other mail header fields contain default values.
+
+@cindex mail header section
+@smallexample
+@group
+To: @var{support-site}
+Subject: @emph{complete this field}
+From: @var{your-login}@@@var{your-site}
+Reply-To: @var{your-login}@@@var{your-site}
+X-send-pr-version: send-pr @value{VERSION}
+@end group
+@end smallexample
+
+@noindent
+where @var{support-site} is an alias for the Support Site you wish to
+submit this PR to.
+
+The rest of the template contains @sc{gnats} fields. Each field is
+either automatically completed with valid information (such as your
+@samp{>Submitter-Id:}) or contains a one-line instruction specifying the
+information that field requires in order to be correct. For example,
+the @samp{>Confidential:} field expects a value of @samp{yes} or
+@samp{no}, and the answer must fit on one line; similarly, the
+@samp{>Synopsis:} field expects a short synopsis of the problem, which
+must also fit on one line. Fill out the fields as completely as
+possible. @xref{Helpful hints,,Helpful hints}, for suggestions as to
+what kinds of information to include.
+
+In this example, words in @emph{italics} are filled in with
+pre-configured information:
+
+@cindex @code{send-pr} fields
+@smallexample
+@group
+>Submitter-Id: @emph{your submitter-id}
+>Originator: @emph{your name here}
+>Organization:
+ @emph{your organization}
+>Confidential:<[ yes | no ] (one line)>
+>Synopsis: <synopsis of the problem (one line)>
+>Severity: <[non-critical | serious | critical](one line)>
+>Priority: <[ low | medium | high ] (one line)>
+>Category: <name of the product (one line)>
+>Class: <[sw-bug | doc-bug | change-request | support]>
+>Release: <release number or tag (one line)>
+>Environment:
+ <machine, os, target, libraries (multiple lines)>
+
+>Description:
+ <precise description of the problem (multiple lines)>
+>How-To-Repeat:
+ <code/input/activities to reproduce (multiple lines)>
+>Fix:
+ <how to correct or work around the problem, if known
+ (multiple lines)>
+@end group
+@end smallexample
+
+@cindex @code{Submitter-Id} field
+@cindex @code{>Submitter-Id:}
+When you finish editing the Problem Report, @code{send-pr} mails it to
+the address named in the @samp{To:} field in the mail header.
+@code{send-pr} checks that the complete form contains a valid
+@samp{>Category:}.
+
+@ifset SENDPR
+Your copy of @code{send-pr} should have already been customized on
+installation to reflect your @samp{>Submitter-Id:}. (@xref{Installing
+send-pr, , Installing @code{send-pr} on your system}.) If you don't
+know your @samp{>Submitter-Id:}, you can request it using
+@w{@samp{send-pr --request-id}}. If your organization is not affiliated
+with the site you send Problem Reports to, a good generic
+@samp{>Submitter-Id:} to use is @samp{net}.
+@end ifset
+
+@cindex bad Problem Reports
+@cindex errors
+@cindex invalid Problem Reports
+If your PR has an invalid value in one of the @sc{Enumerated} fields
+(@pxref{Fields,,Problem Report format}), @code{send-pr} places the PR in
+a temporary file named @samp{/tmp/pbad@var{nnnn}} on your machine.
+@var{nnnn} is the process identification number given to your current
+@code{send-pr} session. If you are running @code{send-pr} from the
+shell, you are prompted as to whether or not you wish to try editing the
+same Problem Report again. If you are running @code{send-pr} from
+Emacs, the Problem Report is placed in the buffer
+@w{@samp{*send-pr-error*}}; you can edit this file and then submit it
+with
+
+@smallexample
+M-x gnats-submit-pr
+@end smallexample
+
+@cindex subsequent mail
+@cindex other mail
+@cindex appending PRs
+@cindex saving related mail
+@cindex related mail
+Any further mail concerning this Problem Report should be carbon-copied
+to the @sc{gnats} mailing address as well, with the category and
+identification number in the @samp{Subject:} line of the message.
+
+@smallexample
+Subject: Re: PR @var{category}/@var{gnats-id}: @var{original message subject}
+@end smallexample
+
+@noindent
+Messages which arrive with @samp{Subject:} lines of this form are
+automatically appended to the Problem Report in the @samp{>Audit-Trail:}
+field in the order received.
+
+@c ---------------------------------------------------------------
+@node send-pr in Emacs
+@section Using @code{send-pr} from within Emacs
+@cindex using @code{send-pr} from within Emacs
+@cindex @code{send-pr} within Emacs
+@cindex invoking @code{send-pr} from Emacs
+@cindex interactive interface
+
+You can use an interactive @code{send-pr} interface from within @sc{gnu}
+Emacs to fill out your Problem Report. We recommend that you
+familiarize yourself with Emacs before using this feature
+(@pxref{Introduction,,Introduction,emacs,GNU Emacs}).
+
+Call @code{send-pr} with @w{@samp{M-x send-pr}}.@footnote{If typing
+@w{@samp{M-x send-pr}} doesn't work, see your system administrator for
+help loading @code{send-pr} into Emacs.} @code{send-pr} responds with a
+Problem Report template preconfigured for the Support Site from which
+you received @code{send-pr}. (If you use @code{send-pr} locally, the
+default Support Site is probably your local site.)
+
+You may also submit problem reports to different Support Sites from the
+default site. To use this feature, invoke @code{send-pr} with
+
+@smallexample
+C-u M-x send-pr
+@end smallexample
+
+@code{send-pr} prompts you for the name of a @var{site}. @var{site} is
+an alias on your local machine which points to an alternate Support
+Site.
+
+@cindex Emacs
+@code{send-pr} displays the template and prompts you in the minibuffer
+with the line:
+@smallexample
+>Category: other
+@end smallexample
+
+@noindent
+Delete the default value @samp{other} @emph{in the minibuffer} and
+replace it with the keyword corresponding to your problem (the list of
+valid categories is in the topmost section of the PR template). For
+example, if the problem you wish to report has to do with the @sc{gnu} C
+compiler, and your support organization accepts bugs submitted for this
+program under the category @samp{gcc}, delete @samp{other} and then type
+@w{@samp{gcc[@key{RET}]}}. @code{send-pr} replaces the line
+
+@smallexample
+>Category: <name of the product (one line)>
+@end smallexample
+
+@noindent
+in the template with
+
+@smallexample
+>Category: gcc
+@end smallexample
+
+@noindent
+and moves on to another field.
+
+@cindex completion in Emacs
+@cindex name completion in Emacs
+@w{@code{send-pr}} provides name completion in the minibuffer. For
+instance, you can also type @w{@samp{gc[@key{TAB}]}}, and @code{send-pr}
+attempts to complete the entry for you. Typing @w{@samp{g[@key{TAB}]}}
+may not have the same effect if several possible entries begin with
+@samp{g}. In that case @code{send-pr} cannot complete the entry because
+it cannot determine whether you mean @samp{gcc} or, for example,
+@samp{gdb}, if both of those are possible categories.
+@w{@code{send-pr}} continues to prompt you for a valid entry until you
+enter one.
+
+@w{@code{send-pr}} prompts you interactively to enter each field for
+which there is a range of specific choices. If you attempt to enter a
+value which is not in the range of acceptable entries, @code{send-pr}
+responds with @w{@samp{[No match]}} and allows you to change the entry
+until it contains an acceptable value. This avoids unusable information
+(at least in these fields) and also avoids typographical errors which
+could cause problems later.
+
+@code{send-pr} prompts you for the following fields:
+
+@c FIXME - should these go before the discussion on completion?
+@example
+@group
+>Category:
+>Confidential: (@emph{default}: no)
+>Severity: (@emph{default}: serious)
+>Priority: (@emph{default}: medium)
+>Class: (@emph{default}: sw-bug)
+>Release:
+>Synopsis: (@emph{this value is copied to @code{Subject:}})
+@end group
+@end example
+
+@noindent
+After you complete these fields, @w{@code{send-pr}} places the cursor in
+the @samp{>Description:} field and displays the message
+
+@smallexample
+To send the problem report use: C-c C-c
+@end smallexample
+
+@noindent
+in the minibuffer. At this point, edit the file in the main buffer to
+reflect your specific problem, putting relevant information in the
+proper fields.
+@ifset SENDPR
+@xref{An Example}, for a sample Problem Report.
+@end ifset
+
+@w{@samp{send-pr}} provides a few key bindings to make moving
+around in a template buffer more simple:
+
+@table @code
+@item C-c C-f
+@itemx M-x change-field
+Changes the field under the cursor. @code{edit-pr} prompts you for a
+new value.
+
+@item M-C-b
+@itemx M-x gnats-backward-field
+Moves the cursor to the beginning of the value of the current field.
+
+@item M-C-f
+@itemx M-x gnats-forward-field
+Moves the cursor to the end of the value of the current field.
+
+@item M-p
+@itemx M-x gnats-previous-field
+Moves the cursor back one field to the beginning of the value of the
+previous field.
+
+@item M-n
+@itemx M-x gnats-next-field
+Moves the cursor forward one field to the beginning of the value of the
+next field.
+@end table
+
+@code{send-pr} takes over again when you type @samp{C-c C-c} to send the
+message. @code{send-pr} reports any errors in a separate buffer, which
+remains in existence until you send the PR properly (or, of course,
+until you explicitly kill the buffer).
+
+For detailed instructions on using Emacs, see
+@ref{Introduction,,,emacs,GNU Emacs}.
+
+@node send-pr from the shell
+@section Invoking @code{send-pr} from the shell
+@cindex command line options
+@cindex invoking @code{send-pr} from the shell
+@cindex shell invocation
+
+@c FIXME! Add [ -S ] right after [ -L ]...
+@smallexample
+send-pr [ @var{site} ]
+ [ -f @var{problem-report} | --file @var{problem-report} ]
+ [ -t @var{mail-address} | --to @var{mail-address} ]
+ [ --request-id ]
+ [ -L | --list ] [ -P | --print ]
+ [ -V | --version] [ -h | --help ]
+@end smallexample
+
+@var{site} is an alias on your local machine which points to an address
+used by a Support Site. If this argument is not present, the default
+@var{site} is usually the site which you received @code{send-pr} from,
+or your local site if you use @sc{gnats} locally.
+@ifset SENDPR
+(@xref{default site,,Setting a default @var{site}}.)
+@end ifset
+
+Invoking @code{send-pr} with no options calls the editor named in your
+environment variable @code{EDITOR} on a default PR template. If the
+environment variable @code{PR_FORM} is set, its value is used as a file
+name which contains a valid template. If @code{PR_FORM} points to a
+missing or unreadable file, or if the file is empty, @code{send-pr}
+generates an error message and opens the editor on a default template.
+
+@table @code
+@item -f @var{problem-report}
+@itemx --file @var{problem-report}
+Specifies a file, @var{problem-report}, where a completed Problem Report
+already exists. @code{send-pr} sends the contents of the file without
+invoking an editor. If @var{problem-report} is @samp{-},
+@w{@code{send-pr}} reads from standard input.
+
+@item -t @var{mail-address}
+@itemx --to @var{mail-address}
+Sends the PR to @var{mail-address}. The default is preset when
+@code{send-pr} is configured. @emph{This option is not recommended};
+instead, use the argument @var{site} on the command line.
+
+@item --request-id
+Sends a request for a @code{>Submitter-Id:} to the Support Site.
+
+@item -L
+@item --list
+@cindex listing valid categories
+Prints the list of valid @code{>Category:} values on standard output.
+No mail is sent.
+
+@ignore
+@item -S
+@itemx --sites
+Displays a list of valid @var{site} values on standard output. No mail
+is sent.
+@end ignore
+
+@item -P
+@itemx --print
+Displays the PR template. If the variable @code{PR_FORM} is set in your
+environment, the file it specifies is printed. If @code{PR_FORM} is not
+set, @code{send-pr} prints the standard blank form. If the file
+specified by @code{PR_FORM} doesn't exist, @code{send-pr} displays an
+error message. No mail is sent.
+
+@item -V
+@itemx --version
+Displays the @code{send-pr} version number and a usage summary. No mail
+is sent.
+
+@item -h
+@itemx --help
+Displays a usage summary for @code{send-pr}. No mail is sent.
+@end table
+
+@node Helpful hints
+@section Helpful hints
+@cindex helpful hints
+@cindex Using and Porting GNU CC
+@cindex effective problem reporting
+@cindex kinds of helpful information
+@cindex information to submit
+@cindex Report all the facts!
+
+There is no orthodox standard for submitting effective bug reports,
+though you might do well to consult the section on submitting bugs for
+@sc{gnu} @code{gcc} in @ref{Bugs, , Reporting Bugs, gcc, Using and
+Porting GNU CC}, by Richard Stallman. This section contains
+instructions on what kinds of information to include and what kinds of
+mistakes to avoid.
+
+In general, common sense (assuming such an animal exists) dictates the
+kind of information that would be most helpful in tracking down and
+resolving problems in software.
+@itemize @bullet
+@item
+Include anything @emph{you} would want to know if you were looking at
+the report from the other end. There's no need to include every minute
+detail about your environment, although anything that might be different
+from someone else's environment should be included (your path, for
+instance).
+
+@item
+Narratives are often useful, given a certain degree of restraint. If a
+person responsible for a bug can see that A was executed, and then B and
+then C, knowing that sequence of events might trigger the realization of
+an intermediate step that was missing, or an extra step that might have
+changed the environment enough to cause a visible problem. Again,
+restraint is always in order (``I set the build running, went to get a
+cup of coffee (Columbian, cream but no sugar), talked to Sheila on the
+phone, and then THIS happened@dots{}'') but be sure to include anything
+relevant.
+
+@item
+Richard Stallman writes, ``The fundamental principle of reporting bugs
+usefully is this: @strong{report all the facts}. If you are not sure
+whether to state a fact or leave it out, state it!'' This holds true
+across all problem reporting systems, for computer software or social
+injustice or motorcycle maintenance. It is especially important in the
+software field due to the major differences seemingly insignificant
+changes can make (a changed variable, a missing semicolon, etc.).
+
+@item
+Submit only @emph{one} problem with each Problem Report. If you have
+multiple problems, use multiple PRs. This aids in tracking each problem
+and also in analyzing the problems associated with a given program.
+
+@item
+It never hurts to do a little research to find out if the bug you've
+found has already been reported. Most software releases contain lists
+of known bugs in the Release Notes which come with the software; see
+your system administrator if you don't have a copy of these.
+
+@item
+The more closely a PR adheres to the standard format, the less
+interaction is required by a database administrator to route the
+information to the proper place. Keep in mind that anything that
+requires human interaction also requires time that might be better spent
+in actually fixing the problem. It is therefore in everyone's best
+interest that the information contained in a PR be as correct as
+possible (in both format and content) at the time of submission.
+@end itemize
diff --git a/gnu/usr.bin/send-pr/doc/send-pr.texi b/gnu/usr.bin/send-pr/doc/send-pr.texi
new file mode 100644
index 0000000..b9edd9c
--- /dev/null
+++ b/gnu/usr.bin/send-pr/doc/send-pr.texi
@@ -0,0 +1,657 @@
+\input texinfo @c -*-texinfo-*-
+@setfilename send-pr.info
+@settitle Reporting Problems Using send-pr
+
+@setchapternewpage odd
+
+@include version.texi
+@set SENDPR
+
+@ifinfo
+@format
+START-INFO-DIR-ENTRY
+* send-pr:: Reporting problems--using send-pr
+END-INFO-DIR-ENTRY
+@end format
+@end ifinfo
+
+@ifinfo
+Copyright @copyright{} 1993 Free Software Foundation, Inc.
+
+Permission is granted to make and distribute verbatim copies of
+this manual provided the copyright notice and this permission notice
+are preserved on all copies.
+
+@ignore
+Permission is granted to process this file through TeX and print the
+results, provided the printed document carries a copying permission
+notice identical to this one except for the removal of this paragraph
+(this paragraph not being relevant to the printed manual).
+
+@end ignore
+
+Permission is granted to copy and distribute modified versions of this
+manual under the conditions for verbatim copying, provided also that
+the entire resulting derived work is distributed under the terms of a
+permission notice identical to this one.
+
+Permission is granted to copy and distribute translations of this manual
+into another language, under the above conditions for modified versions.
+@end ifinfo
+
+@titlepage
+@finalout
+@title Reporting Problems
+@subtitle Using @code{send-pr}, version @value{VERSION}
+@subtitle October 1993
+@author Jeffrey M. Osier
+@author Cygnus Support
+@page
+
+@vskip 0pt plus 1filll
+
+Copyright @copyright{} 1993 Free Software Foundation, Inc.
+
+Permission is granted to make and distribute verbatim copies of
+this manual provided the copyright notice and this permission notice
+are preserved on all copies.
+
+Permission is granted to copy and distribute modified versions of this
+manual under the conditions for verbatim copying, provided also that
+the entire resulting derived work is distributed under the terms of a
+permission notice identical to this one.
+
+Permission is granted to copy and distribute translations of this manual
+into another language, under the above conditions for modified versions.
+
+@end titlepage
+
+@c ---------------------------------------------------------------
+@node Top
+@top Overview
+@cindex foreword to @code{send-pr}
+@cindex overview to @code{send-pr}
+@cindex introduction to @code{send-pr}
+
+This manual documents @code{send-pr},
+@ifinfo
+version @value{VERSION},
+@end ifinfo
+which uses electronic mail to submit support questions and problem
+reports to a central Support Site. No body of work is perfect, and
+support organizations understand this; @code{send-pr} is designed to
+allow users who have problems to submit reports of these problems to
+sites responsible for supporting the products in question, in a defined
+form which can be read by an electronically managed database.
+
+@cindex GNATS
+@code{send-pr} is part of a suite of programs known collectively as
+@sc{gnats}, the @sc{gnu} Problem Report Management System. @sc{gnats}
+consists of several programs which, used in concert, formulate and
+partially administer a database of @dfn{Problem Reports}, or @dfn{PRs},
+at a central Support Site. A PR goes through several states in its
+lifetime; @sc{gnats} tracks the PR and all information associated with it
+through each state and finally acts as an archive for PRs which have
+been @dfn{closed}.
+
+Because @code{send-pr} exists as a shell (@file{/bin/sh}) script and as
+an Elisp file for use with @sc{gnu} Emacs, it can be used from any
+machine on your network which can run a shell script and/or Emacs.
+
+In general, you can use any editor and mailer to submit valid Problem
+Reports, as long as the format required by @sc{gnats} is preserved.
+@code{send-pr} automates the process, however, and ensures that certain
+fields necessary for automatic processing are present. @code{send-pr}
+is strongly recommended for all initial problem-oriented correspondence
+with your Support Site. The organization you submit Problem Reports to
+supplies an address to which further information can be sent; the person
+responsible for the category of the problem you report contacts you
+directly.
+
+@menu
+* send-pr in detail:: Details about send-pr and GNATS
+* Invoking send-pr:: Editing and sending PRs
+* An Example:: A working example
+* Installing send-pr:: Installing send-pr on your system
+* Index::
+@end menu
+
+@node send-pr in detail
+@chapter Details about send-pr and GNATS
+
+@cindex details about @code{send-pr}
+@cindex Problem Reports
+A @dfn{Problem Report} is a message that describes a problem you are
+having with a body of work. @code{send-pr} organizes this message into
+a form which can be understood and automatically processed by @sc{gnats},
+the @sc{gnu} Problem Report Management System. A Problem Report is
+organized into @dfn{fields} which contain data describing you, your
+organization, and the problem you are announcing (@pxref{Fields,,Problem
+Report format}). Problem Reports go through several defined states in
+their lifetimes, from @dfn{open} to @dfn{closed} (@pxref{States,,States
+of Problem Reports}).
+
+@menu
+* States:: States of Problem Reports
+* Fields:: Problem Report format
+@end menu
+
+@include states.texi
+
+@include fields.texi
+
+@node Invoking send-pr
+@chapter Editing and sending PRs
+@cindex editing and sending PRs
+@cindex sending PRs
+@cindex invoking send-pr
+@cindex using send-pr
+@cindex generating new PRs
+
+@include s-usage.texi
+
+@node An Example
+@chapter An Example
+@cindex an example
+@cindex example PR
+@cindex Cygnus Support
+@cindex GNU software support
+
+Cygnus Support in Mountain View, CA, uses @sc{gnats} and @code{send-pr}
+extensively for their support activities. As a support company, Cygnus
+finds problem tracking to be a crucial part of everyday business.
+Cygnus supports the @sc{gnu} compiling tools (including @sc{gnats} and
+@code{send-pr}) over several many platforms
+
+With each shipment of the Cygnus Support Developer's Kit, customers
+receive the latest version of @code{send-pr}, which contains an
+up-to-date listing of valid categories (values for the @code{>Category:}
+field). Using these tools, Cygnus' customers can communicate their
+problems to Cygnus effectively and receive automatic confirmation of
+receipt as well as notification of changes in the status of their
+reported problems. Much of Cygnus' support mechanism relies on
+electronic mail.
+
+As an example, let's pretend we're a customer of Cygnus Support, and
+that we're having a problem compiling some of our software using the
+@sc{gnu} C compiler, which Cygnus supports.
+
+Assume that we're getting an error in our @code{bifrabulator} program
+wherein the @samp{prestidigitation} routines don't match with the
+@samp{whatsitsname}. We've made sure we're following the rules of the
+program and checked the Release Notes from Cygnus and found that the bug
+isn't already known. In other words, we're pretty sure we've found a
+bug.
+
+@cindex Imaginary Software, Ltd.
+Our first step is to call @code{send-pr}. It really doesn't matter
+whether we use @code{send-pr} from the shell or from within Emacs.
+Indeed, if we use Emacs as a primary editor, calling @code{send-pr} from
+the shell is likely to start @code{send-pr} in an Emacs buffer anyway.
+So, since our company, @emph{Imaginary Software, Ltd.}, uses @sc{gnu}
+software extensively, we're pretty familiar with Emacs, so from within
+Emacs we type
+@smallexample
+M-x send-pr
+@end smallexample
+@noindent
+and we're greeted with the following screen:
+
+@cindex default PR template
+@cindex example of a default template
+@cindex blank PR template
+@cindex @code{bifrabulator}
+@cartouche
+@smallexample
+SEND-PR: -*- text -*-
+SEND-PR: Lines starting with `SEND-PR' will be removed
+SEND-PR: automatically as well as all comments (the text
+SEND-PR: below enclosed in `<' and `>').
+SEND-PR: Please consult the manual if you are not sure
+SEND-PR: how to fill out a problem report.
+SEND-PR:
+SEND-PR: Choose from the following categories:
+SEND-PR:
+SEND-PR: bfd binutils bison
+SEND-PR: byacc clib config cvs diff
+SEND-PR: doc emacs flex g++ gas
+SEND-PR: gcc gdb glob gprof grep
+SEND-PR: info ispell kerberos ld libg++
+SEND-PR: libiberty make makeinfo mas newlib
+SEND-PR: other patch rcs readline send-pr
+SEND-PR: test texindex texinfo texinfo.tex
+SEND-PR: bifrabulator <---@emph{note: this one is fake}
+SEND-PR:
+To: cygnus-bugs@@cygnus.com
+Subject:
+From: jeffrey@@imaginary.com
+Reply-To: jeffrey@@imaginary.com
+X-send-pr-version: send-pr @value{VERSION}
+
+>Submitter-Id: imaginary
+>Originator: Jeffrey Osier
+>Organization:
+Imaginary Software, Ltd.
+>Confidential: <[ yes | no ] (one line)>
+>Synopsis: <synopsis of the problem (one line)>
+>Severity: <[ non-critical | serious | critical ] (one line)>
+>Priority: <[ low | medium | high ] (one line)>
+>Category: <name of the product (one line)>
+>Class: <[sw-bug|doc-bug|change-request|support](oneline)>
+>Release: <release number or tag (one line)>
+>Environment:
+ <machine, os, target, libraries (multiple lines)>
+System: SunOS imaginary.com 4.1.1 1 sun4
+Architecture: sun4
+
+>Description:
+ <precise description of the problem (multiple lines)>
+>How-To-Repeat:
+ <code/input/activities to reproduce (multiple lines)>
+>Fix:
+@iftex
+@hrule
+@end iftex
+-----Emacs: *send-pr* (send-pr Fill)----All------------------
+@iftex
+@hrule
+@end iftex
+>Category: other[]
+@end smallexample
+@end cartouche
+@page
+We know from past experience that we need to set certain information into
+each field, so we compile all the information we know about our problem.
+We have some sample code which we know should work, even though it
+doesn't, so we'll include that. Below is the completed PR; we send this
+using @kbd{C-c C-c}. (The comments have been truncated).
+
+@cindex completed Problem Report
+@cindex example of a completed PR
+@cartouche
+@smallexample
+SEND-PR: Lines starting with `SEND-PR' will be removed
+SEND-PR: automatically as well as all comments (the text
+SEND-PR: @dots{}
+SEND-PR:
+To: cygnus-bugs@@cygnus.com
+Subject: bifrabulator routines don't match
+From: jeffrey@@imaginary.com
+Reply-To: jeffrey@@imaginary.com
+X-send-pr-version: send-pr @value{VERSION}
+
+>Submitter-Id: imaginary
+>Originator: Jeffrey Osier
+>Organization:
+Imaginary Software, Ltd.
+>Confidential: no
+>Synopsis: bifrabulator routines don't match
+>Severity: serious
+>Priority: medium
+>Category: bifrabulator
+>Class: sw-bug
+>Release: progressive-930101
+>Environment:
+System: SunOS imaginary.com 4.1.1 1 sun4
+Architecture: sun4 (SPARC)
+
+>Description:
+ the following code I fed into the bifrabulator came back
+ with a strange error. apparently, the prestidigitation
+ routine doesn't match with the whatsitsname in all cases.
+
+>How-To-Repeat:
+ call the bifrabulator on the following code.
+ @emph{code sample@dots{}}
+
+>Fix:
+@iftex
+@hrule
+@end iftex
+-----Emacs: *send-pr* (send-pr Fill)----All------------------
+@iftex
+@hrule
+@end iftex
+To send the problem report use: C-c C-c
+@end smallexample
+@end cartouche
+
+We type @kbd{C-c C-c}, and off it goes. Now, we depend on Cygnus
+Support to figure out the answer to our problem.
+
+Soon afterward, we get the following message from Cygnus:
+
+@smallexample
+@group
+From: gnats (GNATS management)
+Sender: gnats-admin
+Reply-To: hacker@@cygnus.com
+To: jeffrey@@imaginary.com
+Subject: Re: bifrabulator/1425: routines don't match
+
+Thank you very much for your problem report.
+It has the internal identification: g++/1425.
+The individual assigned to look at your bug is: hacker
+(F.B. Hacker)
+
+Category: bifrabulator
+Responsible: hacker
+Synopsis: bifrabulator routines don't match
+Arrival-Date: Sat Feb 30 03:12:55 1993
+@end group
+@end smallexample
+
+@noindent
+This is our receipt that the bug has been accepted and forwarded to the
+responsible party.
+
+@noindent
+A while later, we get the analysis:
+
+@smallexample
+@group
+To: jeffrey@@imaginary.com
+From: hacker@@cygnus.com
+Subject: Re: bifrabulator/1425: routines don't match
+Reply-To: hacker@@cygnus.com
+
+Got your message, Jeff. It seems that the bifrabulator was
+confusing the prestidigitation routines with the realitychecker
+when lexically parsing the whatsitsname.
+
+I'm working on robustisizing the bifrabulator now.
+
+How about lunch next week?
+--
+F.B. Hacker
+Cygnus Support, Mountain View, CA 415 903 1400
+#include <std-disclaimer.h>
+@end group
+@end smallexample
+
+@noindent
+About the same time, we get another message from Cygnus.
+
+@cindex state change example
+@cindex example of a state change
+@smallexample
+@group
+From: hacker@@cygnus.com
+To: jeffrey@@imaginary.com
+Subject: Re: bifrabulator/1425: doesn't match prestidig
+Reply-To: hacker@@cygnus.com
+
+
+ `F.B. Hacker' changed the state to `analyzed'.
+
+State-Changed-From-To: open-analyzed
+State-Changed-By: hacker
+State-Changed-When: Fri Feb 31 1993 08:59:16 1993
+State-Changed-Why:
+ figured out the problem, working on a patch this afternoon
+--
+F.B. Hacker
+Cygnus Support, Mountain View, CA 415 903 1400
+#include <std-disclaimer.h>
+@end group
+@end smallexample
+
+@noindent
+The bug has now been analyzed, and Cygnus is working on a solution.
+
+@noindent
+Sometime later, we get more mail from F.B.:
+
+@smallexample
+@group
+To: jeffrey@@imaginary.com
+From: hacker@@cygnus.com
+Subject: Re: bifrabulator/1425: routines don't match
+Reply-To: hacker@@cygnus.com
+
+There's a patch now that you can ftp over and check out.
+
+Hey, that joke you sent me was great! The one about the
+strings walking into a bar... my boss laughed for an hour!
+--
+F.B. Hacker
+Cygnus Support, Mountain View, CA 415 903 1400
+#include <std-disclaimer.h>
+@end group
+@end smallexample
+@sp 2
+@smallexample
+@group
+From: hacker@@cygnus.com
+To: jeffrey@@imaginary.com
+Subject: Re: bifrabulator/1425: doesn't match prestidig
+Reply-To: hacker@@cygnus.com
+
+
+ `F.B. Hacker' changed the state to `feedback'.
+
+State-Changed-From-To: analyzed-feedback
+State-Changed-By: hacker
+State-Changed-When: Fri Feb 31 1993 23:43:16 1993
+State-Changed-Why:
+ got the patch finished, notified Jeff at Imaginary Software
+--
+F.B. Hacker
+Cygnus Support, Mountain View, CA 415 903 1400
+#include <std-disclaimer.h>
+@end group
+@end smallexample
+
+@noindent
+The bug has gone into @dfn{feedback} status now, until we get the patch,
+install it and test it. When everything tests well, we can mail F.B.
+back and tell him the bug's been fixed, and he can change the state of
+the PR from @dfn{feedback} to @dfn{closed}.
+
+Following is a list of valid @samp{>Category:} entries that are
+supported by Cygnus.
+
+@menu
+* Valid Categories::
+@end menu
+
+@c FIXME - is this list up to date?
+@include categ.texi
+
+@node Installing send-pr
+@appendix Installing @code{send-pr} on your system
+@cindex installation
+
+If you receive @code{send-pr} as part of a larger software distribution,
+it probably gets installed when the full distribution is installed. If
+you are using @sc{gnats} at your site as well, you must decide where
+@code{send-pr} sends Problem Reports by default; see @ref{default site,,
+Setting a default @var{site}}.
+
+@menu
+* installation:: installing `send-pr' by itself
+* default site:: setting a default site
+@end menu
+
+@node installation
+@section Installing @code{send-pr} by itself
+@cindex installation procedure
+
+Install @code{send-pr} by following these steps (you may need
+@code{root} access in order to change the @file{aliases} file and to
+install @code{send-pr}):
+
+@itemize @bullet
+@item
+Unpack the distribution into a directory which we refer to as
+@var{srcdir}.
+
+@item
+Edit the file @file{Makefile} to reflect local conventions.
+Specifically, you should edit the variable @samp{prefix} to alter the
+installation location. The default is @file{/usr/local}. All files are
+installed under @samp{prefix} (see below).
+
+@item @emph{Run}
+@smallexample
+make all install [ info ] [ install-info ] [ clean ]
+@end smallexample
+
+@noindent
+The targets mean the following:
+
+@table @code
+@item all
+Builds @code{send-pr} and @code{install-sid}
+
+@item install
+Installs the following:
+
+@table @code
+@item install-sid
+@itemx send-pr
+into @file{@var{prefix}/bin}
+
+@item send-pr.1
+into @file{@var{prefix}/man/man1}
+
+@item @var{site}
+the list of valid @var{categories} for the Support Site from which you
+received @code{send-pr}, installed as
+@w{@file{@var{prefix}/lib/gnats/@var{site}}}
+
+@item send-pr.el
+into @w{@file{@var{prefix}/lib/emacs/lisp}}@footnote{If your main Emacs
+lisp repository is in a different directory from this, substitute that
+directory for @w{@file{@var{prefix}/lib/emacs/lisp}}.}
+@end table
+
+@item info (@emph{optional})
+Builds @file{send-pr.info} from @file{send-pr.texi}@*
+@c FIXME - is this still true?
+(@file{send-pr.info} is included with this distribution)
+
+@item install-info (@emph{optional})
+Installs @file{send-pr.info} into @w{@file{@var{prefix}/info}}
+
+@item clean (@emph{optional})
+Removes all intermediary build files that can be rebuilt from source
+code
+@end table
+
+@item
+Run
+
+@smallexample
+install-sid @var{your-sid}
+@end smallexample
+
+@noindent
+where @var{your-sid} is the identification code you received with
+@w{@code{send-pr}}. @code{send-pr} automatically inserts this value
+into the template field @samp{>Submitter-Id:}. If you've downloaded
+@code{send-pr} from the Net, use @samp{net} for this value.
+
+@item
+Place the following line in
+@w{@file{@var{prefix}/lib/emacs/lisp/default.el}}, or instruct your
+users to place the following line in their @file{.emacs} files:
+
+@smallexample
+(autoload 'send-pr "send-pr" "Submit a Problem Report." t)
+@end smallexample
+
+@item
+Create a mail alias for the Support Site from which you received
+@code{send-pr}, and for every site with which you wish to use
+@code{send-pr} to communicate. Each alias must have a suffix of
+@samp{-gnats}. The Support Site(s) will provide the correct addresses
+where these aliases should point. For instance, edit your mail aliases
+file to contain something like:
+
+@smallexample
+# support sites; for use with send-pr
+cygnus-gnats: bugs@@cygnus.com # Cygnus Support
+bumblebee-gnats: bumblebugs@@bumblebee.com # Bumblebee Inc.
+mycompany-gnats: bugs@@my.company.com (@emph{if you use @sc{gnats} locally})
+@end smallexample
+
+@code{send-pr} automatically searches for these aliases when you type
+
+@smallexample
+send-pr cygnus
+send-pr bumblebee
+send-pr @var{site}@dots{}
+@end smallexample
+
+@noindent
+@code{send-pr} also uses @var{site} to determine the categories of
+problems accepted by the site in question by looking in
+
+@smallexample
+@var{prefix}/lib/gnats/@var{site}
+@end smallexample
+
+@end itemize
+
+@node default site
+@section Setting a default @var{site}
+@cindex default @var{site}
+@cindex setting a default @var{site}
+
+@code{send-pr} is capable of sending Problem Reports to any number of
+Support Sites, using mail aliases which have @samp{-gnats} appended them.
+@code{send-pr} automatically appends the suffix, so that when you type
+
+@smallexample
+send-pr @var{site}
+@end smallexample
+
+@noindent
+the Problem Report goes to the address noted in the @file{aliases} file
+as @w{@samp{@var{site}-gnats}}. You can do this in the Emacs version of
+@code{send-pr} by invoking the program with
+
+@smallexample
+C-u M-x send-pr
+@end smallexample
+
+@noindent
+You are prompted for @var{site}.
+
+@var{site} is also used to error-check the @samp{>Category:} field, as a
+precaution against sending mistaken information (and against sending
+information to the wrong site).
+
+You may also simply type
+
+@smallexample
+send-pr
+@end smallexample
+
+@noindent
+from the shell (or @w{@samp{M-x send-pr}} in Emacs), and the Problem
+Report you generate will be sent to the @var{site}, which is usually the
+site from which you received your distribution of @w{@code{send-pr}}.
+If you use @sc{gnats} at your own organization, the default is usually
+your local address for reporting problems.
+
+To change this, simply edit the file @file{Makefile} before installing
+and change the line
+
+@smallexample
+GNATS_SITE = @var{site}
+@end smallexample
+
+@noindent
+to reflect the site where you wish to send PRs by default.
+
+@c ---------------------------------------------------------------
+@node Index
+@unnumbered Index
+
+@printindex cp
+
+@c ---------------------------------------------------------------
+@contents
+@bye
diff --git a/gnu/usr.bin/send-pr/doc/states.texi b/gnu/usr.bin/send-pr/doc/states.texi
new file mode 100644
index 0000000..16ea890
--- /dev/null
+++ b/gnu/usr.bin/send-pr/doc/states.texi
@@ -0,0 +1,53 @@
+@node States
+@section States of Problem Reports
+
+@cindex life-cycle of a Problem Report
+@cindex states of Problem Reports
+@cindex Problem Report states
+@cindex automatic notification
+
+Each PR goes through a defined series of states between origination and
+closure. The originator of a PR receives notification automatically of
+any state changes.
+
+@table @dfn
+@cindex @emph{open} state
+@cindex initial state (@dfn{open})
+@cindex state---@dfn{open}
+@item open
+The initial state of a Problem Report. This means the PR has been filed
+and the responsible person(s) notified.
+
+@item analyzed
+@cindex @emph{analyzed} state
+@cindex state---@dfn{analyzed}
+The responsible person has analyzed the problem. The analysis should
+contain a preliminary evaluation of the problem and an estimate of the
+amount of time and resources necessary to solve the problem. It should
+also suggest possible workarounds.
+
+@item feedback
+@cindex @emph{feedback} state
+@cindex state---@dfn{feedback}
+The problem has been solved, and the originator has been given a patch
+or other fix. The PR remains in this state until the originator
+acknowledges that the solution works.
+
+@item closed
+@cindex @emph{closed} state
+@cindex state---@dfn{closed}
+@cindex final state (@dfn{closed})
+A Problem Report is closed (``the bug stops here'') only when any
+changes have been integrated, documented, and tested, and the submitter
+has confirmed the solution.
+
+@item suspended
+@cindex @emph{suspended} state
+@cindex state---@dfn{suspended}
+Work on the problem has been postponed. This happens if a timely
+solution is not possible or is not cost-effective at the present time.
+The PR continues to exist, though a solution is not being actively
+sought. If the problem cannot be solved at all, it should be closed
+rather than suspended.
+@end table
+
diff --git a/gnu/usr.bin/send-pr/doc/version.texi b/gnu/usr.bin/send-pr/doc/version.texi
new file mode 100644
index 0000000..7aff863
--- /dev/null
+++ b/gnu/usr.bin/send-pr/doc/version.texi
@@ -0,0 +1 @@
+@set VERSION 3.2
diff --git a/gnu/usr.bin/send-pr/install-sid.sh b/gnu/usr.bin/send-pr/install-sid.sh
new file mode 100755
index 0000000..f7f24e5
--- /dev/null
+++ b/gnu/usr.bin/send-pr/install-sid.sh
@@ -0,0 +1,82 @@
+#!/bin/sh
+# Drop in the SUBMITTER id into a site's installed send-pr script.
+# Copyright (C) 1993 Free Software Foundation, Inc.
+# Contributed by Brendan Kehoe (brendan@cygnus.com), based on a
+# version written by Heinz G. Seidl (hgs@ide.com).
+#
+# This file is part of GNU GNATS.
+#
+# GNU GNATS is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# GNU GNATS is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GNU GNATS; see the file COPYING. If not, write to
+# the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+COMMAND=`echo $0 | sed -e 's,.*/,,g'`
+USAGE="Usage: $COMMAND [--install-dir=prefix] [--help] [--version] submitter-id"
+
+VERSION=3.2
+
+BINDIR=@BINDIR@
+
+SUBMITTER=
+TEMP=/tmp/sp$$
+
+if [ $# -eq 0 ]; then
+ echo "$USAGE"
+ exit 1
+fi
+
+while [ $# -gt 0 ]; do
+ case "$1" in
+ -install-dir=*|--install-dir=*|--install-di=*|--install-d=*|--install-=*|--install=*|--instal=*|--insta=*|--inst=*|--ins=*|--in=*|--i=*)
+ I=`echo "$1" | sed 's/-*i[a-z\-]*=//'`
+ BINDIR=$I/bin ;;
+ --version) echo $COMMAND version $VERSION ; exit 1 ;;
+ -*) echo "$USAGE" ; exit 1 ;;
+ *) SUBMITTER=$1 ;;
+ esac
+ shift
+done
+
+path=`echo $0 | sed -e "s;${COMMAND};;"`
+
+[ -z "$path" ] && path=.
+
+if [ -f $BINDIR/send-pr ]; then
+ SPPATH=$BINDIR/send-pr
+elif [ -f $path/send-pr ]; then
+ SPPATH=$path/send-pr
+else
+ echo "$COMMAND: cannot find \`$BINDIR/send-pr' or \`$path/send-pr'" >&2
+ exit 1
+fi
+
+trap 'rm -f $TEMP ; exit 0' 0
+trap 'echo "$COM: Aborting ..."; rm -f $TEMP ; exit 1' 1 2 3 13 15
+
+sed -e "s/^SUBMITTER=.*/SUBMITTER=${SUBMITTER}/" $SPPATH > $TEMP
+
+if grep $SUBMITTER $TEMP > /dev/null; then
+ cp $SPPATH $SPPATH.orig &&
+ rm -f $SPPATH &&
+ cp $TEMP $SPPATH &&
+ chmod a+rx $SPPATH &&
+ rm -f $TEMP $SPPATH.orig ||
+ { echo "$COMMAND: unable to replace send-pr" >&2 ; exit 1; }
+else
+ echo "$COMMAND: something went wrong when sed-ing the submitter into send-pr" >&2
+ exit 1
+fi
+
+echo "$COMMAND: \`$SUBMITTER' is now the default submitter ID for send-pr"
+
+exit 0
diff --git a/gnu/usr.bin/send-pr/send-pr-el.in b/gnu/usr.bin/send-pr/send-pr-el.in
new file mode 100644
index 0000000..036b4e7
--- /dev/null
+++ b/gnu/usr.bin/send-pr/send-pr-el.in
@@ -0,0 +1,744 @@
+;;;; -*-emacs-lisp-*-
+;;;;---------------------------------------------------------------------------
+;;;; EMACS interface for send-pr (by Heinz G. Seidl, hgs@cygnus.com)
+;;;; Slightly hacked by Brendan Kehoe (brendan@cygnus.com).
+;;;;
+;;;; This file is part of the Problem Report Management System (GNATS)
+;;;; Copyright 1992, 1993 Cygnus Support
+;;;;
+;;;; This program is free software; you can redistribute it and/or
+;;;; modify it under the terms of the GNU General Public
+;;;; License as published by the Free Software Foundation; either
+;;;; version 2 of the License, or (at your option) any later version.
+;;;;
+;;;; This program is distributed in the hope that it will be useful,
+;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+;;;; General Public License for more details.
+;;;;
+;;;; You should have received a copy of the GNU Library General Public
+;;;; License along with this program; if not, write to the Free
+;;;; Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+;;;;
+;;;;---------------------------------------------------------------------------
+;;;;
+;;;; This file contains the EMACS interface to the Problem Report Management
+;;;; System (GNATS):
+;;;;
+;;;; - The `send-pr' command and the `send-pr-mode' for sending
+;;;; Problem Reports (PRs).
+;;;;
+;;;; For more information about how to send a PR see send-pr(1).
+;;;;
+;;;;---------------------------------------------------------------------------
+;;;;
+;;;; Configuration: the symbol `DEFAULT-RELEASE' can be replaced by
+;;;; site/release specific strings during the configuration/installation
+;;;; process.
+;;;;
+;;;; Install this file in your EMACS library directory.
+;;;;
+;;;;---------------------------------------------------------------------------
+
+(provide 'send-pr)
+
+;;;;---------------------------------------------------------------------------
+;;;; Customization: put the following forms into your default.el file
+;;;; (or into your .emacs)
+;;;;---------------------------------------------------------------------------
+
+;(autoload 'send-pr-mode "send-pr"
+; "Major mode for sending problem reports." t)
+
+;(autoload 'send-pr "send-pr"
+; "Command to create and send a problem report." t)
+
+;;;;---------------------------------------------------------------------------
+;;;; End of Customization Section
+;;;;---------------------------------------------------------------------------
+
+(autoload 'server-buffer-done "server")
+(defvar server-buffer-clients nil)
+(defvar mail-self-blind nil)
+(defvar mail-default-reply-to nil)
+
+(defconst send-pr::version "3.2")
+
+(defvar gnats:root "/home/gnats"
+ "*The top of the tree containing the GNATS database.")
+
+;;;;---------------------------------------------------------------------------
+;;;; hooks
+;;;;---------------------------------------------------------------------------
+
+(defvar text-mode-hook nil) ; we define it here in case it's not defined
+(defvar send-pr-mode-hook text-mode-hook "Called when send-pr is invoked.")
+
+;;;;---------------------------------------------------------------------------
+;;;; Domains and default values for (some of) the Problem Report fields;
+;;;; constants and definitions.
+;;;;---------------------------------------------------------------------------
+
+(defconst gnats::emacs-19p
+ (not (or (and (boundp 'epoch::version) epoch::version)
+ (string-lessp emacs-version "19")))
+ "Is this emacs v19?")
+
+;;; These may be changed during configuration/installation or by the individual
+;;; user in his/her .emacs file.
+;;;
+(defun gnats::get-config (var)
+ (let ((shell-file-name "/bin/sh")
+ (buf (generate-new-buffer " *GNATS config*"))
+ ret)
+ (save-excursion
+ (set-buffer buf)
+ (shell-command (concat ". " gnats:root "/gnats-adm/config; echo $" var )
+ t)
+ (if (looking-at "/bin/sh:\\|\n")
+ (setq ret nil)
+ (setq ret (buffer-substring (point-min) (- (point-max) 1)))))
+ (kill-buffer buf)
+ ret))
+
+;; const because it must match the script's value
+(defconst send-pr:datadir (or (gnats::get-config "DATADIR") "@DATADIR@")
+ "*Where the `gnats' subdirectory containing category lists lives.")
+
+(defvar send-pr::sites nil
+ "List of GNATS support sites; computed at runtime.")
+(defvar send-pr:default-site
+ (or (gnats::get-config "GNATS_SITE") "freefall")
+ "Default site to send bugs to.")
+(defvar send-pr:::site send-pr:default-site
+ "The site to which a problem report is currently being submitted, or NIL
+if using the default site (buffer local).")
+
+(defvar send-pr:::categories nil
+ "Buffer local list of available categories, derived at runtime from
+send-pr:::site and send-pr::category-alist.")
+(defvar send-pr::category-alist nil
+ "Alist of GNATS support sites and the categories supported at each; computed
+at runtime.")
+
+;;; Ideally we would get all the following values from a central database
+;;; during runtime instead of having them here in the code.
+;;;
+(defconst send-pr::fields
+ (` (("Category" send-pr::set-categories
+ (, (or (gnats::get-config "DEFAULT_CATEGORY") nil)) enum)
+ ("Class" (("sw-bug") ("doc-bug") ("change-request") ("support"))
+ (, (or (gnats::get-config "DEFAULT_CONFIDENTIAL") 0)) enum)
+ ("Confidential" (("yes") ("no"))
+ (, (or (gnats::get-config "DEFAULT_CONFIDENTIAL") 1)) enum)
+ ("Severity" (("non-critical") ("serious") ("critical"))
+ (, (or (gnats::get-config "DEFAULT_SEVERITY") 1)) enum)
+ ("Priority" (("low") ("medium") ("high"))
+ (, (or (gnats::get-config "DEFAULT_PRIORITY") 1)) enum)
+ ("Release" nil
+ (, (or (gnats::get-config "DEFAULT_RELEASE") "@DEFAULT_RELEASE@"))
+ text)
+ ("Submitter-Id" nil
+ (, (or (gnats::get-config "DEFAULT_SUBMITTER") "unknown"))
+ text)
+ ("Synopsis" nil nil text
+ (lambda (a b c) (gnats::set-mail-field "Subject" c)))))
+ "AList, keyed on the name of the field, of:
+1) The field name.
+2) The list of completions. This can be a list, a function to call, or nil.
+3) The default value.
+4) The type of the field.
+5) A sub-function to call when changed.")
+
+(defvar gnats::fields nil)
+
+(defmacro gnats::push (i l)
+ (` (setq (, l) (cons (,@ (list i l))))))
+
+(defun send-pr::set-categories (&optional arg)
+ "Get the list of categories for the current site out of
+send-pr::category-alist if there or from send-pr if not. With arg, force
+update."
+ ;;
+ (let ((entry (assoc send-pr:::site send-pr::category-alist)))
+ (or (and entry (null arg))
+ (let ((oldpr (getenv "GNATS_ROOT")) cats)
+ (send-pr::set-sites arg)
+ (setenv "GNATS_ROOT" gnats:root)
+ (setq cats (gnats::get-value-from-shell
+ "send-pr" "-CL" send-pr:::site))
+ (setenv "GNATS_ROOT" oldpr)
+ (if entry (setcdr entry cats)
+ (setq entry (cons send-pr:::site cats))
+ (gnats::push entry send-pr::category-alist))))
+ (setq send-pr:::categories (cdr entry))))
+
+(defun send-pr::set-sites (&optional arg)
+ "Get the list of sites (by listing the contents of DATADIR/gnats) and assign
+it to send-pr::sites. With arg, force update."
+ (or (and (null arg) send-pr::sites)
+ (progn
+ (setq send-pr::sites nil)
+ (mapcar
+ (function
+ (lambda (file)
+ (or (memq t (mapcar (function (lambda (x) (string= x file)))
+ '("." ".." "pr-edit" "pr-addr")))
+ (not (file-readable-p file))
+ (gnats::push (list (file-name-nondirectory file))
+ send-pr::sites))))
+ (directory-files (format "%s/gnats" send-pr:datadir) t))
+ (setq send-pr::sites (reverse send-pr::sites)))))
+
+(defconst send-pr::pr-buffer-name "*send-pr*"
+ "Name of the temporary buffer, where the problem report gets composed.")
+
+(defconst send-pr::err-buffer-name "*send-pr-error*"
+ "Name of the temporary buffer, where send-pr error messages appear.")
+
+(defvar send-pr:::err-buffer nil
+ "The error buffer used by the current PR buffer.")
+
+(defconst gnats::indent 17 "Indent for formatting the value.")
+
+;;;;---------------------------------------------------------------------------
+;;;; `send-pr' - command for creating and sending of problem reports
+;;;;---------------------------------------------------------------------------
+
+(fset 'send-pr 'send-pr:send-pr)
+(defun send-pr:send-pr (&optional site)
+ "Create a buffer and read in the result of `send-pr -P'.
+When finished with editing the problem report use \\[send-pr:submit-pr]
+to send the PR with `send-pr -b -f -'."
+ ;;
+ (interactive
+ (if current-prefix-arg
+ (list (completing-read "Site: " (send-pr::set-sites 'recheck) nil t
+ send-pr:default-site))))
+ (or site (setq site send-pr:default-site))
+ (let ((buf (get-buffer send-pr::pr-buffer-name)))
+ (if (or (not buf)
+ (progn (switch-to-buffer buf)
+ (cond ((or (not (buffer-modified-p buf))
+ (y-or-n-p "Erase previous problem report? "))
+ (erase-buffer) t)
+ (t nil))))
+ (send-pr::start-up site))))
+
+(defun send-pr::start-up (site)
+ (switch-to-buffer (get-buffer-create send-pr::pr-buffer-name))
+ (setq default-directory (expand-file-name "~/"))
+ (auto-save-mode auto-save-default)
+ (let ((oldpr (getenv "GNATS_ROOT"))
+ (case-fold-search nil))
+ (setenv "GNATS_ROOT" gnats:root)
+ (shell-command (concat "send-pr -P " site) t)
+ (setenv "GNATS_ROOT" oldpr)
+ (if (looking-at "send-pr:")
+ (cond ((looking-at "send-pr: .* does not have a categories list")
+ (setq send-pr::sites nil)
+ (error "send-pr: the GNATS site %s does not have a categories list" site))
+ (t (error (buffer-substring (point-min) (point-max)))))
+ (save-excursion
+ ;; Clear cruft inserted by bdamaged .cshrcs
+ (re-search-forward "^SEND-PR:")
+ (delete-region 1 (match-beginning 0)))))
+ (set-buffer-modified-p nil)
+ (send-pr:send-pr-mode)
+ (setq send-pr:::site site)
+ (send-pr::set-categories)
+ (if (null send-pr:::categories)
+ (progn
+ (and send-pr:::err-buffer (kill-buffer send-pr:::err-buffer))
+ (kill-buffer nil)
+ (message "send-pr: no categories found"))
+ (and mail-default-reply-to
+ (gnats::set-mail-field "Reply-To" mail-default-reply-to))
+ (and mail-self-blind
+ (gnats::set-mail-field "BCC" (user-login-name)))
+ (mapcar 'send-pr::maybe-change-field send-pr::fields)
+ (gnats::position-on-field "Description")
+ (message (substitute-command-keys
+ "To send the problem report use: \\[send-pr:submit-pr]"))))
+
+(fset 'do-send-pr 'send-pr:submit-pr) ;backward compat
+(defun send-pr:submit-pr ()
+ "Pipe the contents of the buffer *send-pr* to `send-pr -f -.' unless this
+buffer was loaded with emacsclient, in which case save the buffer and exit."
+ ;;
+ (interactive)
+ (cond
+ ((and (boundp 'server-buffer-clients)
+ server-buffer-clients)
+ (let ((buffer (current-buffer))
+ (version-control nil) (buffer-backed-up nil))
+ (save-buffer buffer)
+ (kill-buffer buffer)
+ (server-buffer-done buffer)))
+ (t
+ (or (and send-pr:::err-buffer
+ (buffer-name send-pr:::err-buffer))
+ (setq send-pr:::err-buffer
+ (get-buffer-create send-pr::err-buffer-name)))
+ (let ((err-buffer send-pr:::err-buffer) mesg ok)
+ (save-excursion (set-buffer err-buffer) (erase-buffer))
+ (message "running send-pr...")
+ (let ((oldpr (getenv "GNATS_ROOT")))
+ (setenv "GNATS_ROOT" gnats:root)
+ (call-process-region (point-min) (point-max) "send-pr"
+ nil err-buffer nil send-pr:::site
+ "-b" "-f" "-")
+ (setenv "GNATS_ROOT" oldpr))
+ (message "running send-pr...done")
+ ;; stupidly we cannot check the return value in EMACS 18.57, thus we need
+ ;; this kluge to find out whether send-pr succeeded.
+ (if (save-excursion
+ (set-buffer err-buffer)
+ (goto-char (point-min))
+ (setq mesg (buffer-substring (point-min) (- (point-max) 1)))
+ (search-forward "problem report sent" nil t))
+ (progn (message mesg)
+ (kill-buffer err-buffer)
+ (delete-auto-save-file-if-necessary)
+ (set-buffer-modified-p nil)
+ (bury-buffer))
+ (pop-to-buffer err-buffer))
+ ))))
+
+;;;;---------------------------------------------------------------------------
+;;;; send-pr:send-pr-mode mode
+;;;;---------------------------------------------------------------------------
+
+(defvar send-pr-mode-map
+ (let ((map (make-sparse-keymap)))
+ (define-key map "\C-c\C-c" 'send-pr:submit-pr)
+ (define-key map "\C-c\C-f" 'gnats:change-field)
+ (define-key map "\M-n" 'gnats:next-field)
+ (define-key map "\M-p" 'gnats:previous-field)
+ (define-key map "\C-\M-f" 'gnats:forward-field)
+ (define-key map "\C-\M-b" 'gnats:backward-field)
+ map)
+ "Keymap for send-pr mode.")
+
+(defconst gnats::keyword "^>\\([-a-zA-Z]+\\):")
+(defconst gnats::before-keyword "[ \t\n\f]*[\n\f]+>\\([-a-zA-Z]+\\):")
+(defconst gnats::after-keyword "^>\\([-a-zA-Z]+\\):[ \t\n\f]+")
+
+(fset 'send-pr-mode 'send-pr:send-pr-mode)
+(defun send-pr:send-pr-mode ()
+ "Major mode for submitting problem reports.
+For information about the form see gnats(1) and send-pr(1).
+Special commands: \\{send-pr-mode-map}
+Turning on send-pr-mode calls the value of the variable send-pr-mode-hook,
+if it is not nil."
+ (interactive)
+ (gnats::patch-exec-path)
+ (put 'send-pr:send-pr-mode 'mode-class 'special)
+ (kill-all-local-variables)
+ (setq major-mode 'send-pr:send-pr-mode)
+ (setq mode-name "send-pr")
+ (use-local-map send-pr-mode-map)
+ (set-syntax-table text-mode-syntax-table)
+ (setq local-abbrev-table text-mode-abbrev-table)
+ (setq buffer-offer-save t)
+ (make-local-variable 'send-pr:::site)
+ (make-local-variable 'send-pr:::categories)
+ (make-local-variable 'send-pr:::err-buffer)
+ (make-local-variable 'paragraph-separate)
+ (setq paragraph-separate (concat (default-value 'paragraph-separate)
+ "\\|" gnats::keyword "[ \t\n\f]*$"))
+ (make-local-variable 'paragraph-start)
+ (setq paragraph-start (concat (default-value 'paragraph-start)
+ "\\|" gnats::keyword))
+ (run-hooks 'send-pr-mode-hook)
+ t)
+
+;;;;---------------------------------------------------------------------------
+;;;; Functions to read and replace field values.
+;;;;---------------------------------------------------------------------------
+
+(defun gnats::position-on-field (field)
+ (goto-char (point-min))
+ (if (not (re-search-forward (concat "^>" field ":") nil t))
+ (error "Field `>%s:' not found." field)
+ (re-search-forward "[ \t\n\f]*")
+ (if (looking-at gnats::keyword)
+ (backward-char 1))
+ t))
+
+(defun gnats::mail-position-on-field (field)
+ (let (end
+ (case-fold-search t))
+ (goto-char (point-min))
+ (re-search-forward "^$")
+ (setq end (match-beginning 0))
+ (goto-char (point-min))
+ (if (not (re-search-forward (concat "^" field ":") end 'go-to-end))
+ (insert field ": \n")
+ (re-search-forward "[ \t\n\f]*"))
+ (skip-chars-backward "\n")
+ t))
+
+(defun gnats::field-contents (field &optional elem move)
+ (let (pos)
+ (unwind-protect
+ (save-excursion
+ (if (not (gnats::position-on-field field))
+ nil
+ (setq pos (point-marker))
+ (if (or (looking-at "<.*>$") (eolp))
+ t
+ (looking-at ".*$") ; to set match-{beginning,end}
+ (gnats::nth-word
+ (buffer-substring (match-beginning 0) (match-end 0))
+ elem))))
+ (and move pos (goto-char pos)))))
+
+(defun gnats::functionp (thing)
+ (or (and (symbolp thing) (fboundp thing))
+ (and (listp thing) (eq (car thing) 'lambda))))
+
+(defun gnats::field-values (field)
+ "Return the possible (known) values for field FIELD."
+ (let* ((fields (if (eq major-mode 'gnats:gnats-mode) gnats::fields
+ send-pr::fields))
+ (thing (elt (assoc field fields) 1)))
+ (cond ((gnats::functionp thing) (funcall thing))
+ ((listp thing) thing)
+ (t (error "ACK")))))
+
+(defun gnats::field-default (field)
+ "Return the default value for field FIELD."
+ (let* ((fields (if (eq major-mode 'gnats:gnats-mode) gnats::fields
+ send-pr::fields))
+ (thing (elt (assoc field fields) 2)))
+ (cond ((stringp thing) thing)
+ ((null thing) "")
+ ((numberp thing) (car (elt (gnats::field-values field) thing)))
+ ((gnats::functionp thing)
+ (funcall thing (gnats::field-contents field)))
+ ((eq thing t) (gnats::field-contents field))
+ (t (error "ACK")))))
+
+(defun gnats::field-type (field)
+ "Return the type of field FIELD."
+ (let* ((fields (if (eq major-mode 'gnats:gnats-mode) gnats::fields
+ send-pr::fields))
+ (thing (elt (assoc field fields) 3)))
+ thing))
+
+(defun gnats::field-action (field)
+ "Return the extra handling function for field FIELD."
+ (let* ((fields (if (eq major-mode 'gnats:gnats-mode) gnats::fields
+ send-pr::fields))
+ (thing (elt (assoc field fields) 4)))
+ (cond ((null thing) 'ignore)
+ ((gnats::functionp thing) thing)
+ (t (error "ACK")))))
+
+;;;;---------------------------------------------------------------------------
+;;;; Point movement functions
+;;;;---------------------------------------------------------------------------
+
+(or (fboundp 'defsubst) (fset 'defsubst 'defun))
+
+(defun send-pr::maybe-change-field (field)
+ (setq field (car field))
+ (let ((thing (gnats::field-contents field)))
+ (and thing (eq t thing)
+ (not (eq 'multi-text (gnats::field-type field)))
+ (gnats:change-field field))))
+
+(defun gnats:change-field (&optional field default)
+ "Change the value of the field containing the cursor. With arg, ask the
+user for the field to change. From a program, the function takes optional
+arguments of the field to change and the default value to use."
+ (interactive)
+ (or field current-prefix-arg (setq field (gnats::current-field)))
+ (or field
+ (setq field
+ (completing-read "Field: "
+ (if (eq major-mode 'gnats:gnats-mode)
+ gnats::fields
+ send-pr::fields)
+ nil t)))
+ (gnats::position-on-field field)
+ (sit-for 0)
+ (let* ((old (gnats::field-contents field))
+ new)
+ (if (null old)
+ (error "ACK")
+ (let ((prompt (concat ">" field ": "))
+ (domain (gnats::field-values field))
+ (type (gnats::field-type field))
+ (action (gnats::field-action field)))
+ (or default (setq default (gnats::field-default field)))
+ (setq new (if (eq type 'enum)
+ (completing-read prompt domain nil t
+ (if gnats::emacs-19p (cons default 0)
+ default))
+ (read-string prompt (if gnats::emacs-19p (cons default 1)
+ default))))
+ (gnats::set-field field new)
+ (funcall action field old new)
+ new))))
+
+(defun gnats::set-field (field value)
+ (save-excursion
+ (gnats::position-on-field field)
+ (delete-horizontal-space)
+ (looking-at ".*$")
+ (replace-match
+ (concat (make-string (- gnats::indent (length field) 2) ?\40 ) value) t)))
+
+(defun gnats::set-mail-field (field value)
+ (save-excursion
+ (gnats::mail-position-on-field field)
+ (delete-horizontal-space)
+ (looking-at ".*$")
+ (replace-match (concat " " value) t)))
+
+(defun gnats::before-keyword (&optional where)
+ "Returns t if point is in some white space before a keyword.
+If where is nil, then point is not changed; if where is t then point is moved
+to the beginning of the keyword, otherwise it is moved to the beginning
+of the white space it was in."
+ ;;
+ (if (looking-at gnats::before-keyword)
+ (prog1 t
+ (cond ((eq where t)
+ (re-search-forward "^>") (backward-char))
+ ((not (eq where nil))
+ (re-search-backward "[^ \t\n\f]") (forward-char))))
+ nil))
+
+(defun gnats::after-keyword (&optional where)
+ "Returns t if point is in some white space after a keyword.
+If where is nil, then point is not changed; if where is t then point is moved
+to the beginning of the keyword, otherwise it is moved to the end of the white
+space it was in."
+ ;;
+ (if (gnats::looking-after gnats::after-keyword)
+ (prog1 t
+ (cond ((eq where t)
+ (re-search-backward "^>"))
+ ((not (eq where nil))
+ (re-search-forward "[^ \t\n\f]") (backward-char))))
+ nil))
+
+(defun gnats::in-keyword (&optional where)
+ "Returns t if point is within a keyword.
+If where is nil, then point is not changed; if where is t then point is moved
+to the beginning of the keyword."
+ ;;
+ (let ((old-point (point-marker)))
+ (beginning-of-line)
+ (cond ((and (looking-at gnats::keyword)
+ (< old-point (match-end 0)))
+ (prog1 t
+ (if (eq where t)
+ t
+ (goto-char old-point))))
+ (t (goto-char old-point)
+ nil))))
+
+(defun gnats::forward-bofield ()
+ "Moves point to the beginning of a field. Assumes that point is in the
+keyword."
+ ;;
+ (if (re-search-forward "[ \t\n\f]+[^ \t\n\f]" (point-max) '-)
+ (backward-char)
+ t))
+
+(defun gnats::backward-eofield ()
+ "Moves point to the end of a field. Assumes point is in the keyword."
+ ;;
+ (if (re-search-backward "[^ \t\n\f][ \t\n\f]+" (point-min) '-)
+ (forward-char)
+ t))
+
+(defun gnats::forward-eofield ()
+ "Moves point to the end of a field. Assumes that point is in the field."
+ ;;
+ ;; look for the next field
+ (if (re-search-forward gnats::keyword (point-max) '-)
+ (progn (beginning-of-line) (gnats::backward-eofield))
+ (re-search-backward "[^ \t\n\f][ \t\n\f]*" (point-min) '-)
+ (forward-char)))
+
+(defun gnats::backward-bofield ()
+ "Moves point to the beginning of a field. Assumes that point is in the
+field."
+ ;;
+ ;;look for previous field
+ (if (re-search-backward gnats::keyword (point-min) '-)
+ (gnats::forward-bofield)
+ t))
+
+
+(defun gnats:forward-field ()
+ "Move point forward to the end of the field or to the beginning of the next
+field."
+ ;;
+ (interactive)
+ (if (or (gnats::before-keyword t) (gnats::in-keyword t)
+ (gnats::after-keyword t))
+ (gnats::forward-bofield)
+ (gnats::forward-eofield)))
+
+(defun gnats:backward-field ()
+ "Move point backward to the beginning/end of a field."
+ ;;
+ (interactive)
+ (backward-char)
+ (if (or (gnats::before-keyword t) (gnats::in-keyword t)
+ (gnats::after-keyword t))
+ (gnats::backward-eofield)
+ (gnats::backward-bofield)))
+
+(defun gnats:next-field ()
+ "Move point to the beginning of the next field."
+ ;;
+ (interactive)
+ (if (or (gnats::before-keyword t) (gnats::in-keyword t)
+ (gnats::after-keyword t))
+ (gnats::forward-bofield)
+ (if (re-search-forward gnats::keyword (point-max) '-)
+ (gnats::forward-bofield)
+ t)))
+
+(defun gnats:previous-field ()
+ "Move point to the beginning of the previous field."
+ ;;
+ (interactive)
+ (backward-char)
+ (if (or (gnats::after-keyword t) (gnats::in-keyword t)
+ (gnats::before-keyword t))
+ (progn (re-search-backward gnats::keyword (point-min) '-)
+ (gnats::forward-bofield))
+ (gnats::backward-bofield)))
+
+(defun gnats:beginning-of-field ()
+ "Move point to the beginning of the current field."
+ (interactive)
+ (cond ((gnats::in-keyword t)
+ (gnats::forward-bofield))
+ ((gnats::after-keyword 0))
+ (t
+ (gnats::backward-bofield))))
+
+(defun gnats::current-field ()
+ (save-excursion
+ (if (cond ((or (gnats::in-keyword t) (gnats::after-keyword t))
+ (looking-at gnats::keyword))
+ ((re-search-backward gnats::keyword nil t)))
+ (buffer-substring (match-beginning 1) (match-end 1))
+ nil)))
+
+;;;;---------------------------------------------------------------------------
+;;;; Support functions
+;;;;---------------------------------------------------------------------------
+
+(defun gnats::looking-after (regex)
+ "Returns t if point is after regex."
+ ;;
+ (let* ((old-point (point))
+ (start (if (eobp)
+ old-point
+ (forward-char) (point))))
+ (cond ((re-search-backward regex (point-min) t)
+ (goto-char old-point)
+ (cond ((eq (match-end 0) start)
+ t))))))
+
+(defun gnats::nth-word (string &optional elem)
+ "Returns the elem-th word of the string.
+If elem is nil, then the first wort is returned, if elem is 0 then
+the whole string is returned."
+ ;;
+ (if (integerp elem)
+ (cond ((eq elem 0) string)
+ ((eq elem 1) (gnats::first-word string))
+ ((equal string "") "")
+ ((>= elem 2)
+ (let ((i 0) (value ""))
+ (setq string ; strip leading blanks
+ (substring string (or (string-match "[^ \t]" string) 0)))
+ (while (< i elem)
+ (setq value
+ (substring string 0
+ (string-match "[ \t]*$\\|[ \t]+" string)))
+ (setq string
+ (substring string (match-end 0)))
+ (setq i (+ i 1)))
+ value)))
+ (gnats::first-word string)))
+
+(defun gnats::first-word (string)
+ (setq string
+ (substring string (or (string-match "[^ \t]" string) 0)))
+ (substring string 0 (string-match "[ \t]*$\\|[ \t]+" string)))
+
+;;;;---------------------------------------------------------------------------
+
+(defun gnats::patch-exec-path ()
+ ;;
+ "Replaces `//' by `/' in `exec-path'."
+ ;;
+ ;(make-local-variable 'exec-path)
+ (let ((err-buffer (get-buffer-create " *gnats::patch-exec-path*"))
+ (ret))
+ (setq exec-path (save-excursion (set-buffer err-buffer)
+ (prin1 exec-path err-buffer)
+ (goto-char (point-min))
+ (replace-string "//" "/")
+ (goto-char (point-min))
+ (setq ret (read err-buffer))
+ (kill-buffer err-buffer)
+ ret
+ ))))
+
+(defun gnats::get-value-from-shell (&rest command)
+ "Execute shell command to get a list of valid values for `variable'."
+ ;;
+ (let ((err-buffer (get-buffer-create " *gnats::get-value-from-shell*")))
+ (save-excursion
+ (set-buffer err-buffer)
+ (unwind-protect
+ (condition-case var
+ (progn
+ (apply 'call-process
+ (car command) nil err-buffer nil (cdr command))
+ (goto-char (point-min))
+ (if (looking-at "[-a-z]+: ")
+ (error (buffer-substring (point-min) (point-max))))
+ (read err-buffer))
+ (error nil))
+ (kill-buffer err-buffer)))))
+
+(or (fboundp 'setenv)
+ (defun setenv (variable &optional value)
+ "Set the value of the environment variable named VARIABLE to VALUE.
+VARIABLE should be a string. VALUE is optional; if not provided or is
+`nil', the environment variable VARIABLE will be removed.
+This function works by modifying `process-environment'."
+ (interactive "sSet environment variable: \nsSet %s to value: ")
+ (if (string-match "=" variable)
+ (error "Environment variable name `%s' contains `='" variable)
+ (let ((pattern (concat "\\`" (regexp-quote (concat variable "="))))
+ (case-fold-search nil)
+ (scan process-environment))
+ (while scan
+ (cond
+ ((string-match pattern (car scan))
+ (if (eq nil value)
+ (setq process-environment (delq (car scan)
+ process-environment))
+ (setcar scan (concat variable "=" value)))
+ (setq scan nil))
+ ((null (setq scan (cdr scan)))
+ (setq process-environment
+ (cons (concat variable "=" value)
+ process-environment)))))))))
+
+;;;; end of send-pr.el
diff --git a/gnu/usr.bin/send-pr/send-pr.1 b/gnu/usr.bin/send-pr/send-pr.1
new file mode 100644
index 0000000..af29f44
--- /dev/null
+++ b/gnu/usr.bin/send-pr/send-pr.1
@@ -0,0 +1,260 @@
+.\" -*- nroff -*-
+.\" ---------------------------------------------------------------------------
+.\" man page for send-pr (by Heinz G. Seidl, hgs@cygnus.com)
+.\" updated Feb 1993 for GNATS 3.00 by Jeffrey Osier, jeffrey@cygnus.com
+.\"
+.\" This file is part of the Problem Report Management System (GNATS)
+.\" Copyright 1992 Cygnus Support
+.\"
+.\" This program is free software; you can redistribute it and/or
+.\" modify it under the terms of the GNU General Public
+.\" License as published by the Free Software Foundation; either
+.\" version 2 of the License, or (at your option) any later version.
+.\"
+.\" This program is distributed in the hope that it will be useful,
+.\" but WITHOUT ANY WARRANTY; without even the implied warranty of
+.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+.\" General Public License for more details.
+.\"
+.\" You should have received a copy of the GNU Library General Public
+.\" License along with this program; if not, write to the Free
+.\" Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA
+.\"
+.\" ---------------------------------------------------------------------------
+.nh
+.TH SEND-PR 1 xVERSIONx "February 1993"
+.SH NAME
+send-pr \- send problem report (PR) to a central support site
+.SH SYNOPSIS
+.B send-pr
+[
+.I site
+]
+[
+.B \-f
+.I problem-report
+]
+[
+.B \-t
+.I mail-address
+]
+.br
+.in +0.8i
+[
+.B \-P
+]
+[
+.B \-L
+]
+[
+.B \-\-request-id
+]
+[
+.B \-v
+]
+.SH DESCRIPTION
+.B send-pr
+is a tool used to submit
+.I problem reports
+.\" SITE ADMINISTRATORS - change this if you use a local default
+(PRs) to a central support site. In most cases the correct
+.I site
+will be the default. This argument indicates the support site which
+is responsible for the category of problem involved. Some sites may
+use a local address as a default.
+.I site
+values are defined by using the
+.BR aliases (5).
+.LP
+.B send-pr
+invokes an editor on a problem report template (after trying to fill
+in some fields with reasonable default values). When you exit the
+editor,
+.B send-pr
+sends the completed form to the
+.I Problem Report Management System
+(\fBGNATS\fR) at a central support site. At the support site, the PR
+is assigned a unique number and is stored in the \fBGNATS\fR database
+according to its category and submitter-id. \fBGNATS\fR automatically
+replies with an acknowledgement, citing the category and the PR
+number.
+.LP
+To ensure that a PR is handled promptly, it should contain your (unique)
+\fIsubmitter-id\fR and one of the available \fIcategories\fR to identify the
+problem area. (Use
+.B `send-pr -L'
+to see a list of categories.)
+.LP
+The
+.B send-pr
+template at your site should already be customized with your
+submitter-id (running `\|\fBinstall-sid\fP \fIsubmitter-id\fP\|' to
+accomplish this is part of the installation procedures for
+.BR send-pr ).
+If this hasn't been done, see your system administrator for your
+submitter-id, or request one from your support site by invoking
+.B `send-pr \-\-request\-id'.
+If your site does not distinguish between different user sites, or if
+you are not affiliated with the support site, use
+.B `net'
+for this field.
+.LP
+The more precise your problem description and the more complete your
+information, the faster your support team can solve your problems.
+.SH OPTIONS
+.TP
+.BI \-f " problem-report"
+specify a file (\fIproblem-report\fR) which already contains a
+complete problem report.
+.B send-pr
+sends the contents of the file without invoking the editor. If
+the value for
+.I problem-report
+is
+.BR `\|\-\|' ,
+then
+.B send-pr
+reads from standard input.
+.TP
+.BI \-t " mail-address"
+Change mail address at the support site for problem reports. The
+default
+.I mail-address
+is the address used for the default
+.IR site .
+Use the
+.I site
+argument rather than this option in nearly all cases.
+.TP
+.B \-P
+print the form specified by the environment variable
+.B PR_FORM
+on standard output. If
+.B PR_FORM
+is not set, print the standard blank PR template. No mail is sent.
+.TP
+.B -L
+print the list of available categories. No mail is sent.
+.TP
+.B \-\-request\-id
+sends mail to the default support site, or
+.I site
+if specified, with a request for your
+.IR submitter-id .
+If you are
+not affiliated with
+.IR site ,
+use a
+.I submitter-id
+of
+.BR net \|'.
+.TP
+.B \-v
+Display the
+.B send-pr
+version number.
+.LP
+Note: use
+.B send-pr
+to submit problem reports rather than mailing them directly. Using
+both the template and
+.B send-pr
+itself will help ensure all necessary information will reach the
+support site.
+.SH ENVIRONMENT
+The environment variable
+.B EDITOR
+specifies the editor to invoke on the template.
+.br
+default:
+.B vi
+.sp
+If the environment variable
+.B PR_FORM
+is set, then its value is used as the file name of the template for
+your problem-report editing session. You can use this to start with a
+partially completed form (for example, a form with the identification
+fields already completed).
+.SH "HOW TO FILL OUT A PROBLEM REPORT"
+Problem reports have to be in a particular form so that a program can
+easily manage them. Please remember the following guidelines:
+.IP \(bu 3m
+describe only
+.B one problem
+with each problem report.
+.IP \(bu 3m
+For follow-up mail, use the same subject line as the one in the automatic
+acknowledgent. It consists of category, PR number and the original synopsis
+line. This allows the support site to relate several mail messages to a
+particular PR and to record them automatically.
+.IP \(bu 3m
+Please try to be as accurate as possible in the subject and/or synopsis line.
+.IP \(bu 3m
+The subject and the synopsis line are not confidential. This is
+because open-bugs lists are compiled from them. Avoid confidential
+information there.
+.LP
+See the GNU
+.B Info
+file
+.B send-pr.info
+or the document \fIReporting Problems With send-pr\fR\ for detailed
+information on reporting problems
+.SH "HOW TO SUBMIT TEST CASES, CODE, ETC."
+Submit small code samples with the PR. Contact the support site for
+instructions on submitting larger test cases and problematic source
+code.
+.SH FILES
+.ta \w'/tmp/pbad$$ 'u
+/tmp/p$$ copy of PR used in editing session
+.br
+/tmp/pf$$ copy of empty PR form, for testing purposes
+.br
+/tmp/pbad$$ file for rejected PRs
+.SH EMACS USER INTERFACE
+An Emacs user interface for
+.B send-pr
+with completion of field values is part of the
+.B send-pr
+distribution (invoked with
+.BR "M-x send-pr" ).
+See the file
+.B send-pr.info
+or the ASCII file
+.B INSTALL
+in the top level directory of the distribution for configuration and
+installation information. The Emacs LISP template file is
+.B send-pr-el.in
+and is installed as
+.BR send-pr.el .
+.SH INSTALLATION AND CONFIGURATION
+See
+.B send-pr.info
+or
+.B INSTALL
+for installation instructions.
+.SH SEE ALSO
+.I Reporting Problems Using send-pr
+(also installed as the GNU Info file
+.BR send-pr.info ).
+.SH AUTHORS
+Jeffrey Osier, Brendan Kehoe, Jason Merrill, Heinz G. Seidl (Cygnus
+Support)
+.SH COPYING
+Copyright (c) 1992, 1993 Free Software Foundation, Inc.
+.PP
+Permission is granted to make and distribute verbatim copies of
+this manual provided the copyright notice and this permission notice
+are preserved on all copies.
+.PP
+Permission is granted to copy and distribute modified versions of this
+manual under the conditions for verbatim copying, provided that the
+entire resulting derived work is distributed under the terms of a
+permission notice identical to this one.
+.PP
+Permission is granted to copy and distribute translations of this
+manual into another language, under the above conditions for modified
+versions, except that this permission notice may be included in
+translations approved by the Free Software Foundation instead of in
+the original English.
+
diff --git a/gnu/usr.bin/send-pr/send-pr.sh b/gnu/usr.bin/send-pr/send-pr.sh
new file mode 100644
index 0000000..7aaa501
--- /dev/null
+++ b/gnu/usr.bin/send-pr/send-pr.sh
@@ -0,0 +1,516 @@
+#!/bin/sh
+# Submit a problem report to a GNATS site.
+# Copyright (C) 1993 Free Software Foundation, Inc.
+# Contributed by Brendan Kehoe (brendan@cygnus.com), based on a
+# version written by Heinz G. Seidl (hgs@ide.com).
+#
+# This file is part of GNU GNATS.
+#
+# GNU GNATS is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# GNU GNATS is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GNU GNATS; see the file COPYING. If not, write to
+# the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+# The version of this send-pr.
+VERSION=3.2
+
+# The submitter-id for your site.
+SUBMITTER=unknown
+
+# Where the GNATS directory lives, if at all.
+[ -z "$GNATS_ROOT" ] &&
+GNATS_ROOT=
+
+# The default mail address for PR submissions.
+GNATS_ADDR=FreeBSD-gnats-submit@freebsd.org
+
+# Where the gnats category tree lives.
+DATADIR=@DATADIR@
+
+# If we've been moved around, try using GCC_EXEC_PREFIX.
+[ ! -d $DATADIR/gnats -a -d "$GCC_EXEC_PREFIX" ] && DATADIR=@DATADIR@
+
+# The default release for this host.
+DEFAULT_RELEASE="@DEFAULT_RELEASE@"
+
+# The default organization.
+DEFAULT_ORGANIZATION=
+
+# The default site to look for.
+GNATS_SITE=freefall
+
+# Newer config information?
+[ -f ${GNATS_ROOT}/gnats-adm/config ] && . ${GNATS_ROOT}/gnats-adm/config
+
+# What mailer to use. This must come after the config file, since it is
+# host-dependent.
+MAIL_AGENT="/usr/sbin/sendmail -oi -t"
+
+ECHON=bsd
+
+if [ $ECHON = bsd ] ; then
+ ECHON1="echo -n"
+ ECHON2=
+elif [ $ECHON = sysv ] ; then
+ ECHON1=echo
+ ECHON2='\c'
+else
+ ECHON1=echo
+ ECHON2=
+fi
+
+#
+
+[ -z "$TMPDIR" ] && TMPDIR=/tmp
+
+TEMP=$TMPDIR/p$$
+BAD=$TMPDIR/pbad$$
+REF=$TMPDIR/pf$$
+
+if [ -z "$LOGNAME" -a -n "$USER" ]; then
+ LOGNAME=$USER
+fi
+
+FROM="$LOGNAME"
+REPLY_TO="$LOGNAME"
+
+# Find out the name of the originator of this PR.
+if [ -n "$NAME" ]; then
+ ORIGINATOR="$NAME"
+elif [ -f $HOME/.fullname ]; then
+ ORIGINATOR="`sed -e '1q' $HOME/.fullname`"
+elif [ -f /bin/domainname ]; then
+ if [ "`/bin/domainname`" != "" -a -f /usr/bin/ypcat ]; then
+ # Must use temp file due to incompatibilities in quoting behavior
+ # and to protect shell metacharacters in the expansion of $LOGNAME
+ /usr/bin/ypcat passwd 2>/dev/null | cat - /etc/passwd | grep "^$LOGNAME:" |
+ cut -f5 -d':' | sed -e 's/,.*//' > $TEMP
+ ORIGINATOR="`cat $TEMP`"
+ rm -f $TEMP
+ fi
+fi
+
+if [ "$ORIGINATOR" = "" ]; then
+ grep "^$LOGNAME:" /etc/passwd | cut -f5 -d':' | sed -e 's/,.*//' > $TEMP
+ ORIGINATOR="`cat $TEMP`"
+ rm -f $TEMP
+fi
+
+if [ -n "$ORGANIZATION" ]; then
+ if [ -f "$ORGANIZATION" ]; then
+ ORGANIZATION="`cat $ORGANIZATION`"
+ fi
+else
+ if [ -n "$DEFAULT_ORGANIZATION" ]; then
+ ORGANIZATION="$DEFAULT_ORGANIZATION"
+ elif [ -f $HOME/.organization ]; then
+ ORGANIZATION="`cat $HOME/.organization`"
+ elif [ -f $HOME/.signature ]; then
+ ORGANIZATION="`cat $HOME/.signature`"
+ fi
+fi
+
+# If they don't have a preferred editor set, then use
+if [ -z "$VISUAL" ]; then
+ if [ -z "$EDITOR" ]; then
+ EDIT=vi
+ else
+ EDIT="$EDITOR"
+ fi
+else
+ EDIT="$VISUAL"
+fi
+
+# Find out some information.
+SYSTEM=`( [ -f /bin/uname ] && /bin/uname -a ) || \
+ ( [ -f /usr/bin/uname ] && /usr/bin/uname -a ) || echo ""`
+ARCH=`[ -f /bin/arch ] && /bin/arch`
+MACHINE=`[ -f /bin/machine ] && /bin/machine`
+
+COMMAND=`echo $0 | sed -e 's,.*/,,'`
+USAGE="Usage: $COMMAND [-PVL] [-t address] [-f filename] [--request-id]
+[--version]"
+REMOVE=
+BATCH=
+
+while [ $# -gt 0 ]; do
+ case "$1" in
+ -r) ;; # Ignore for backward compat.
+ -t | --to) if [ $# -eq 1 ]; then echo "$USAGE"; exit 1; fi
+ shift ; GNATS_ADDR="$1"
+ EXPLICIT_GNATS_ADDR=true
+ ;;
+ -f | --file) if [ $# -eq 1 ]; then echo "$USAGE"; exit 1; fi
+ shift ; IN_FILE="$1"
+ if [ "$IN_FILE" != "-" -a ! -r "$IN_FILE" ]; then
+ echo "$COMMAND: cannot read $IN_FILE"
+ exit 1
+ fi
+ ;;
+ -b | --batch) BATCH=true ;;
+ -p | -P | --print) PRINT=true ;;
+ -L | --list) FORMAT=norm ;;
+ -l | -CL | --lisp) FORMAT=lisp ;;
+ --request-id) REQUEST_ID=true ;;
+ -h | --help) echo "$USAGE"; exit 0 ;;
+ -V | --version) echo "$VERSION"; exit 0 ;;
+ -*) echo "$USAGE" ; exit 1 ;;
+ *) if [ -z "$USER_GNATS_SITE" ]; then
+ if [ ! -r "$DATADIR/gnats/$1" ]; then
+ echo "$COMMAND: the GNATS site $1 does not have a categories list."
+ exit 1
+ else
+ # The site name is the alias they'll have to have created.
+ USER_GNATS_SITE=$1
+ fi
+ else
+ echo "$USAGE" ; exit 1
+ fi
+ ;;
+ esac
+ shift
+done
+
+if [ -n "$USER_GNATS_SITE" ]; then
+ GNATS_SITE=$USER_GNATS_SITE
+ GNATS_ADDR=$USER_GNATS_SITE-gnats
+fi
+
+if [ "$SUBMITTER" = "unknown" -a -z "$REQUEST_ID" -a -z "$IN_FILE" ]; then
+ cat << '__EOF__'
+It seems that send-pr is not installed with your unique submitter-id.
+You need to run
+
+ install-sid YOUR-SID
+
+where YOUR-SID is the identification code you received with `send-pr'.
+`send-pr' will automatically insert this value into the template field
+`>Submitter-Id'. If you've downloaded `send-pr' from the Net, use `net'
+for this value. If you do not know your id, run `send-pr --request-id' to
+get one from your support site.
+__EOF__
+ exit 1
+fi
+
+if [ -r "$DATADIR/gnats/$GNATS_SITE" ]; then
+ CATEGORIES=`grep -v '^#' $DATADIR/gnats/$GNATS_SITE | sort`
+else
+ echo "$COMMAND: could not read $DATADIR/gnats/$GNATS_SITE for categories list."
+ exit 1
+fi
+
+if [ -z "$CATEGORIES" ]; then
+ echo "$COMMAND: the categories list for $GNATS_SITE was empty!"
+ exit 1
+fi
+
+case "$FORMAT" in
+ lisp) echo "$CATEGORIES" | \
+ awk 'BEGIN {printf "( "} {printf "(\"%s\") ",$0} END {printf ")\n"}'
+ exit 0
+ ;;
+ norm) l=`echo "$CATEGORIES" | \
+ awk 'BEGIN {max = 0; } { if (length($0) > max) { max = length($0); } }
+ END {print max + 1;}'`
+ c=`expr 70 / $l`
+ if [ $c -eq 0 ]; then c=1; fi
+ echo "$CATEGORIES" | \
+ awk 'BEGIN {print "Known categories:"; i = 0 }
+ { printf ("%-'$l'.'$l's", $0); if ((++i % '$c') == 0) { print "" } }
+ END { print ""; }'
+ exit 0
+ ;;
+esac
+
+ORIGINATOR_C='<Name of the PR author (one line)>'
+ORGANIZATION_C='<Organization of PR author (multiple lines)>'
+CONFIDENTIAL_C='<[ yes | no ] (one line)>'
+SYNOPSIS_C='<Synopsis of the problem (one line)>'
+SEVERITY_C='<[ non-critical | serious | critical ] (one line)>'
+PRIORITY_C='<[ low | medium | high ] (one line)>'
+CATEGORY_C='<Problem category (as listed above)>'
+CLASS_C='<[ sw-bug | doc-bug | change-request | support ] (one line)>'
+RELEASE_C='<Release number or tag (one line)>'
+ENVIRONMENT_C='<Relevant environment information (multiple lines)>'
+DESCRIPTION_C='<Precise description of the problem (multiple lines)>'
+HOW_TO_REPEAT_C='<Code/input/activities to reproduce the problem (multiple lines)>'
+FIX_C='<How to correct or work around the problem, if known (multiple lines)>'
+
+# Catch some signals. ($xs kludge needed by Sun /bin/sh)
+xs=0
+trap 'rm -f $REF $TEMP; exit $xs' 0
+trap 'echo "$COMMAND: Aborting ..."; rm -f $REF $TEMP; xs=1; exit' 1 2 3 13 15
+
+# If they told us to use a specific file, then do so.
+if [ -n "$IN_FILE" ]; then
+ if [ "$IN_FILE" = "-" ]; then
+ # The PR is coming from the standard input.
+ if [ -n "$EXPLICIT_GNATS_ADDR" ]; then
+ sed -e "s;^[Tt][Oo]:.*;To: $GNATS_ADDR;" > $TEMP
+ else
+ cat > $TEMP
+ fi
+ else
+ # Use the file they named.
+ if [ -n "$EXPLICIT_GNATS_ADDR" ]; then
+ sed -e "s;^[Tt][Oo]:.*;To: $GNATS_ADDR;" $IN_FILE > $TEMP
+ else
+ cat $IN_FILE > $TEMP
+ fi
+ fi
+else
+
+ if [ -n "$PR_FORM" -a -z "$PRINT_INTERN" ]; then
+ # If their PR_FORM points to a bogus entry, then bail.
+ if [ ! -f "$PR_FORM" -o ! -r "$PR_FORM" -o ! -s "$PR_FORM" ]; then
+ echo "$COMMAND: can't seem to read your template file (\`$PR_FORM'), ignoring PR_FORM"
+ sleep 1
+ PRINT_INTERN=bad_prform
+ fi
+ fi
+
+ if [ -n "$PR_FORM" -a -z "$PRINT_INTERN" ]; then
+ cp $PR_FORM $TEMP ||
+ ( echo "$COMMAND: could not copy $PR_FORM" ; xs=1; exit )
+ else
+ for file in $TEMP $REF ; do
+ cat > $file << '__EOF__'
+SEND-PR: -*- send-pr -*-
+SEND-PR: Lines starting with `SEND-PR' will be removed automatically, as
+SEND-PR: will all comments (text enclosed in `<' and `>').
+SEND-PR:
+SEND-PR: Please consult the send-pr man page `send-pr(1)' or the Texinfo
+SEND-PR: manual if you are not sure how to fill out a problem report.
+SEND-PR:
+SEND-PR: Choose from the following categories:
+SEND-PR:
+__EOF__
+
+ # Format the categories so they fit onto lines.
+ l=`echo "$CATEGORIES" | \
+ awk 'BEGIN {max = 0; } { if (length($0) > max) { max = length($0); } }
+ END {print max + 1;}'`
+ c=`expr 61 / $l`
+ if [ $c -eq 0 ]; then c=1; fi
+ echo "$CATEGORIES" | \
+ awk 'BEGIN {printf "SEND-PR: "; i = 0 }
+ { printf ("%-'$l'.'$l's", $0);
+ if ((++i % '$c') == 0) { printf "\nSEND-PR: " } }
+ END { printf "\nSEND-PR:\n"; }' >> $file
+
+
+
+ cat >> $file << __EOF__
+To: $GNATS_ADDR
+Subject:
+From: $FROM
+Reply-To: $REPLY_TO
+X-send-pr-version: $VERSION
+
+
+>Submitter-Id: $SUBMITTER
+>Originator: $ORIGINATOR
+>Organization: ${ORGANIZATION-$ORGANIZATION_C}
+>Confidential: $CONFIDENTIAL_C
+>Synopsis: $SYNOPSIS_C
+>Severity: $SEVERITY_C
+>Priority: $PRIORITY_C
+>Category: $CATEGORY_C
+>Release: ${DEFAULT_RELEASE-$RELEASE_C}
+>Class: $CLASS_C
+>Environment:
+
+ $ENVIRONMENT_C
+
+>Description:
+
+ $DESCRIPTION_C
+
+>How-To-Repeat:
+
+ $HOW_TO_REPEAT_C
+
+>Fix:
+
+ $FIX_C
+
+__EOF__
+
+ done
+ fi
+
+ if [ "$PRINT" = true -o "$PRINT_INTERN" = true ]; then
+ cat $TEMP
+ xs=0; exit
+ fi
+
+ chmod u+w $TEMP
+ if [ -z "$REQUEST_ID" ]; then
+ eval $EDIT $TEMP
+ else
+ ed -s $TEMP << '__EOF__'
+/^Subject/s/^Subject:.*/Subject: request for a customer id/
+/^>Category/s/^>Category:.*/>Category: send-pr/
+w
+q
+__EOF__
+ fi
+
+ if cmp -s $REF $TEMP ; then
+ echo "$COMMAND: problem report not filled out, therefore not sent"
+ xs=1; exit
+ fi
+fi
+
+#
+# Check the enumeration fields
+
+# This is a "sed-subroutine" with one keyword parameter
+# (with workaround for Sun sed bug)
+#
+SED_CMD='
+/$PATTERN/{
+s|||
+s|<.*>||
+s|^[ ]*||
+s|[ ]*$||
+p
+q
+}'
+
+
+while [ -z "$REQUEST_ID" ]; do
+ CNT=0
+
+ # 1) Confidential
+ #
+ PATTERN=">Confidential:"
+ CONFIDENTIAL=`eval sed -n -e "\"$SED_CMD\"" $TEMP`
+ case "$CONFIDENTIAL" in
+ ""|yes|no) CNT=`expr $CNT + 1` ;;
+ *) echo "$COMMAND: \`$CONFIDENTIAL' is not a valid value for \`Confidential'." ;;
+ esac
+ #
+ # 2) Severity
+ #
+ PATTERN=">Severity:"
+ SEVERITY=`eval sed -n -e "\"$SED_CMD\"" $TEMP`
+ case "$SEVERITY" in
+ ""|non-critical|serious|critical) CNT=`expr $CNT + 1` ;;
+ *) echo "$COMMAND: \`$SEVERITY' is not a valid value for \`Severity'."
+ esac
+ #
+ # 3) Priority
+ #
+ PATTERN=">Priority:"
+ PRIORITY=`eval sed -n -e "\"$SED_CMD\"" $TEMP`
+ case "$PRIORITY" in
+ ""|low|medium|high) CNT=`expr $CNT + 1` ;;
+ *) echo "$COMMAND: \`$PRIORITY' is not a valid value for \`Priority'."
+ esac
+ #
+ # 4) Category
+ #
+ PATTERN=">Category:"
+ CATEGORY=`eval sed -n -e "\"$SED_CMD\"" $TEMP`
+ FOUND=
+ for C in $CATEGORIES
+ do
+ if [ "$C" = "$CATEGORY" ]; then FOUND=true ; break ; fi
+ done
+ if [ -n "$FOUND" ]; then
+ CNT=`expr $CNT + 1`
+ else
+ if [ -z "$CATEGORY" ]; then
+ echo "$COMMAND: you must include a Category: field in your report."
+ else
+ echo "$COMMAND: \`$CATEGORY' is not a known category."
+ fi
+ fi
+ #
+ # 5) Class
+ #
+ PATTERN=">Class:"
+ CLASS=`eval sed -n -e "\"$SED_CMD\"" $TEMP`
+ case "$CLASS" in
+ ""|sw-bug|doc-bug|change-request|support) CNT=`expr $CNT + 1` ;;
+ *) echo "$COMMAND: \`$CLASS' is not a valid value for \`Class'."
+ esac
+
+ [ $CNT -lt 5 -a -z "$BATCH" ] &&
+ echo "Errors were found with the problem report."
+
+ while true; do
+ if [ -z "$BATCH" ]; then
+ $ECHON1 "a)bort, e)dit or s)end? $ECHON2"
+ read input
+ else
+ if [ $CNT -eq 5 ]; then
+ input=s
+ else
+ input=a
+ fi
+ fi
+ case "$input" in
+ a*)
+ if [ -z "$BATCH" ]; then
+ echo "$COMMAND: the problem report remains in $BAD and is not sent."
+ mv $TEMP $BAD
+ else
+ echo "$COMMAND: the problem report is not sent."
+ fi
+ xs=1; exit
+ ;;
+ e*)
+ eval $EDIT $TEMP
+ continue 2
+ ;;
+ s*)
+ break 2
+ ;;
+ esac
+ done
+done
+#
+# Remove comments and send the problem report
+# (we have to use patterns, where the comment contains regex chars)
+#
+# /^>Originator:/s;$ORIGINATOR;;
+sed -e "
+/^SEND-PR:/d
+/^>Organization:/,/^>[A-Za-z-]*:/s;$ORGANIZATION_C;;
+/^>Confidential:/s;<.*>;;
+/^>Synopsis:/s;$SYNOPSIS_C;;
+/^>Severity:/s;<.*>;;
+/^>Priority:/s;<.*>;;
+/^>Category:/s;$CATEGORY_C;;
+/^>Class:/s;<.*>;;
+/^>Release:/,/^>[A-Za-z-]*:/s;$RELEASE_C;;
+/^>Environment:/,/^>[A-Za-z-]*:/s;$ENVIRONMENT_C;;
+/^>Description:/,/^>[A-Za-z-]*:/s;$DESCRIPTION_C;;
+/^>How-To-Repeat:/,/^>[A-Za-z-]*:/s;$HOW_TO_REPEAT_C;;
+/^>Fix:/,/^>[A-Za-z-]*:/s;$FIX_C;;
+" $TEMP > $REF
+
+if $MAIL_AGENT < $REF; then
+ echo "$COMMAND: problem report sent"
+ xs=0; exit
+else
+ echo "$COMMAND: mysterious mail failure."
+ if [ -z "$BATCH" ]; then
+ echo "$COMMAND: the problem report remains in $BAD and is not sent."
+ mv $REF $BAD
+ else
+ echo "$COMMAND: the problem report is not sent."
+ fi
+ xs=1; exit
+fi
diff --git a/gnu/usr.bin/sort/Makefile b/gnu/usr.bin/sort/Makefile
new file mode 100644
index 0000000..78eb30d
--- /dev/null
+++ b/gnu/usr.bin/sort/Makefile
@@ -0,0 +1,11 @@
+PROG= sort
+SRCS= sort.c error.c version.c long-options.c getopt.c getopt1.c
+
+CFLAGS+=-I${.CURDIR} -DDIRENT=1 -DHAVE_LONG_DOUBLE=1 -DHAVE_LONG_DOUBLE=1 \
+ -DHAVE_ST_BLKSIZE=1 -DHAVE_VPRINTF=1 -DRETSIGTYPE=void \
+ -DSTDC_HEADERS=1 -DHAVE_STRERROR=1 -DHAVE_FCNTL_H=1 \
+ -DHAVE_LIMITS_H=1 -DHAVE_MEMORY_H=1 -DHAVE_STRING_H=1 \
+ -DHAVE_UNISTD_H=1
+
+
+.include <bsd.prog.mk>
diff --git a/gnu/usr.bin/sort/error.c b/gnu/usr.bin/sort/error.c
index a36198b..611f220 100644
--- a/gnu/usr.bin/sort/error.c
+++ b/gnu/usr.bin/sort/error.c
@@ -1,5 +1,5 @@
/* error.c -- error handler for noninteractive utilities
- Copyright (C) 1990, 91, 92, 93, 94, 95 Free Software Foundation, Inc.
+ Copyright (C) 1990, 1991, 1992, 1993 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -15,60 +15,57 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
-/* Written by David MacKenzie <djm@gnu.ai.mit.edu>. */
+/* Written by David MacKenzie. */
#ifdef HAVE_CONFIG_H
+#if defined (CONFIG_BROKETS)
+/* We use <config.h> instead of "config.h" so that a compilation
+ using -I. -I$srcdir will use ./config.h rather than $srcdir/config.h
+ (which it would do because it found this file in $srcdir). */
#include <config.h>
+#else
+#include "config.h"
+#endif
#endif
#include <stdio.h>
-#if HAVE_VPRINTF || HAVE_DOPRNT || _LIBC
-# if __STDC__
-# include <stdarg.h>
-# define VA_START(args, lastarg) va_start(args, lastarg)
-# else
-# include <varargs.h>
-# define VA_START(args, lastarg) va_start(args)
-# endif
-#else
-# define va_alist a1, a2, a3, a4, a5, a6, a7, a8
-# define va_dcl char *a1, *a2, *a3, *a4, *a5, *a6, *a7, *a8;
-#endif
+#ifdef HAVE_VPRINTF
-#if STDC_HEADERS || _LIBC
-# include <stdlib.h>
-# include <string.h>
-#else
-void exit ();
-#endif
+#if __STDC__
+#include <stdarg.h>
+#define VA_START(args, lastarg) va_start(args, lastarg)
+#else /* !__STDC__ */
+#include <varargs.h>
+#define VA_START(args, lastarg) va_start(args)
+#endif /* !__STDC__ */
-/* This variable is incremented each time `error' is called. */
-unsigned int error_message_count;
+#else /* !HAVE_VPRINTF */
-/* If NULL, error will flush stdout, then print on stderr the program
- name, a colon and a space. Otherwise, error will call this
- function without parameters instead. */
-void (*error_print_progname) () = NULL;
+#ifdef HAVE_DOPRNT
+#define va_alist args
+#define va_dcl int args;
+#else /* !HAVE_DOPRNT */
+#define va_alist a1, a2, a3, a4, a5, a6, a7, a8
+#define va_dcl char *a1, *a2, *a3, *a4, *a5, *a6, *a7, *a8;
+#endif /* !HAVE_DOPRNT */
-#ifdef _LIBC
-#define program_name program_invocation_name
-#endif
+#endif /* !HAVE_VPRINTF */
+
+#ifdef STDC_HEADERS
+#include <stdlib.h>
+#include <string.h>
+#else /* !STDC_HEADERS */
+void exit ();
+#endif /* !STDC_HEADERS */
-/* The calling program should define program_name and set it to the
- name of the executing program. */
extern char *program_name;
-#if HAVE_STRERROR || _LIBC
-# ifndef strerror /* On some systems, strerror is a macro */
-char *strerror ();
-# endif
-#else
+#ifndef HAVE_STRERROR
static char *
private_strerror (errnum)
int errnum;
{
- extern char *sys_errlist[];
extern int sys_nerr;
if (errnum > 0 && errnum <= sys_nerr)
@@ -76,51 +73,40 @@ private_strerror (errnum)
return "Unknown system error";
}
#define strerror private_strerror
-#endif
+#endif /* !HAVE_STRERROR */
/* Print the program name and error message MESSAGE, which is a printf-style
format string with optional args.
If ERRNUM is nonzero, print its corresponding system error message.
Exit with status STATUS if it is nonzero. */
/* VARARGS */
-
void
-#if defined(VA_START) && __STDC__
-error (int status, int errnum, const char *message, ...)
-#else
+#if defined (HAVE_VPRINTF) && __STDC__
+error (int status, int errnum, char *message, ...)
+#else /* !HAVE_VPRINTF or !__STDC__ */
error (status, errnum, message, va_alist)
int status;
int errnum;
char *message;
va_dcl
-#endif
+#endif /* !HAVE_VPRINTF or !__STDC__ */
{
-#ifdef VA_START
+#ifdef HAVE_VPRINTF
va_list args;
-#endif
+#endif /* HAVE_VPRINTF */
- if (error_print_progname)
- (*error_print_progname) ();
- else
- {
- fflush (stdout);
- fprintf (stderr, "%s: ", program_name);
- }
-
-#ifdef VA_START
+ fprintf (stderr, "%s: ", program_name);
+#ifdef HAVE_VPRINTF
VA_START (args, message);
-# if HAVE_VPRINTF || _LIBC
vfprintf (stderr, message, args);
-# else
- _doprnt (message, args, stderr);
-# endif
va_end (args);
-#else
+#else /* !HAVE_VPRINTF */
+#ifdef HAVE_DOPRNT
+ _doprnt (message, &args, stderr);
+#else /* !HAVE_DOPRNT */
fprintf (stderr, message, a1, a2, a3, a4, a5, a6, a7, a8);
-#endif
-
- ++error_message_count;
-
+#endif /* !HAVE_DOPRNT */
+#endif /* !HAVE_VPRINTF */
if (errnum)
fprintf (stderr, ": %s", strerror (errnum));
putc ('\n', stderr);
diff --git a/gnu/usr.bin/sort/getopt.c b/gnu/usr.bin/sort/getopt.c
index 8bcf559..7a4673b 100644
--- a/gnu/usr.bin/sort/getopt.c
+++ b/gnu/usr.bin/sort/getopt.c
@@ -3,7 +3,7 @@
"Keep this file name-space clean" means, talk to roland@gnu.ai.mit.edu
before changing it!
- Copyright (C) 1987, 88, 89, 90, 91, 92, 93, 94, 95
+ Copyright (C) 1987, 88, 89, 90, 91, 92, 1993
Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify it
@@ -20,17 +20,18 @@
along with this program; if not, write to the Free Software
Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
-/* This tells Alpha OSF/1 not to define a getopt prototype in <stdio.h>.
- Ditto for AIX 3.2 and <stdlib.h>. */
-#ifndef _NO_PROTO
-#define _NO_PROTO
-#endif
-
#ifdef HAVE_CONFIG_H
+#if defined (emacs) || defined (CONFIG_BROKETS)
+/* We use <config.h> instead of "config.h" so that a compilation
+ using -I. -I$srcdir will use ./config.h rather than $srcdir/config.h
+ (which it would do because it found this file in $srcdir). */
#include <config.h>
+#else
+#include "config.h"
+#endif
#endif
-#if !defined (__STDC__) || !__STDC__
+#ifndef __STDC__
/* This is a separate conditional since some stdc systems
reject `defined (const)'. */
#ifndef const
@@ -38,6 +39,11 @@
#endif
#endif
+/* This tells Alpha OSF/1 not to define a getopt prototype in <stdio.h>. */
+#ifndef _NO_PROTO
+#define _NO_PROTO
+#endif
+
#include <stdio.h>
/* Comment out all this code if we are using the GNU C Library, and are not
@@ -59,16 +65,10 @@
#include <stdlib.h>
#endif /* GNU C library. */
-#ifndef _
-/* This is for other GNU distributions with internationalized messages.
- When compiling libc, the _ macro is predefined. */
-#ifdef HAVE_LIBINTL_H
-# include <libintl.h>
-# define _(msgid) gettext (msgid)
-#else
-# define _(msgid) (msgid)
-#endif
-#endif
+/* If GETOPT_COMPAT is defined, `+' as well as `--' can introduce a
+ long-named option. Because this is not POSIX.2 compliant, it is
+ being phased out. */
+/* #define GETOPT_COMPAT */
/* This version of `getopt' appears to the caller like standard Unix `getopt'
but it behaves differently for the user, since it allows the user
@@ -92,7 +92,7 @@
Also, when `ordering' is RETURN_IN_ORDER,
each non-option ARGV-element is returned here. */
-char *optarg = NULL;
+char *optarg = 0;
/* Index in ARGV of the next element to be scanned.
This is used for communication to and from the caller
@@ -162,9 +162,6 @@ static enum
{
REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER
} ordering;
-
-/* Value of POSIXLY_CORRECT environment variable. */
-static char *posixly_correct;
#ifdef __GNU_LIBRARY__
/* We want to avoid inclusion of string.h with non-GNU libraries
@@ -195,18 +192,19 @@ my_index (str, chr)
}
/* If using GCC, we can safely declare strlen this way.
- If not using GCC, it is ok not to declare it. */
+ If not using GCC, it is ok not to declare it.
+ (Supposedly there are some machines where it might get a warning,
+ but changing this conditional to __STDC__ is too risky.) */
#ifdef __GNUC__
-/* Note that Motorola Delta 68k R3V7 comes with GCC but not stddef.h.
- That was relevant to code that was here before. */
-#if !defined (__STDC__) || !__STDC__
-/* gcc with -traditional declares the built-in strlen to return int,
- and has done so at least since version 2.4.5. -- rms. */
-extern int strlen (const char *);
-#endif /* not __STDC__ */
-#endif /* __GNUC__ */
-
-#endif /* not __GNU_LIBRARY__ */
+#ifdef IN_GCC
+#include "gstddef.h"
+#else
+#include <stddef.h>
+#endif
+extern size_t strlen (const char *);
+#endif
+
+#endif /* GNU C library. */
/* Handle permutation of arguments. */
@@ -281,42 +279,6 @@ exchange (argv)
first_nonopt += (optind - last_nonopt);
last_nonopt = optind;
}
-
-/* Initialize the internal data when the first call is made. */
-
-static const char *
-_getopt_initialize (optstring)
- const char *optstring;
-{
- /* Start processing options with ARGV-element 1 (since ARGV-element 0
- is the program name); the sequence of previously skipped
- non-option ARGV-elements is empty. */
-
- first_nonopt = last_nonopt = optind = 1;
-
- nextchar = NULL;
-
- posixly_correct = getenv ("POSIXLY_CORRECT");
-
- /* Determine how to handle the ordering of options and nonoptions. */
-
- if (optstring[0] == '-')
- {
- ordering = RETURN_IN_ORDER;
- ++optstring;
- }
- else if (optstring[0] == '+')
- {
- ordering = REQUIRE_ORDER;
- ++optstring;
- }
- else if (posixly_correct != NULL)
- ordering = REQUIRE_ORDER;
- else
- ordering = PERMUTE;
-
- return optstring;
-}
/* Scan elements of ARGV (whose length is ARGC) for option characters
given in OPTSTRING.
@@ -383,18 +345,41 @@ _getopt_internal (argc, argv, optstring, longopts, longind, long_only)
int *longind;
int long_only;
{
- optarg = NULL;
+ int option_index;
+
+ optarg = 0;
+
+ /* Initialize the internal data when the first call is made.
+ Start processing options with ARGV-element 1 (since ARGV-element 0
+ is the program name); the sequence of previously skipped
+ non-option ARGV-elements is empty. */
if (optind == 0)
{
- optstring = _getopt_initialize (optstring);
- optind = 1; /* Don't scan ARGV[0], the program name. */
+ first_nonopt = last_nonopt = optind = 1;
+
+ nextchar = NULL;
+
+ /* Determine how to handle the ordering of options and nonoptions. */
+
+ if (optstring[0] == '-')
+ {
+ ordering = RETURN_IN_ORDER;
+ ++optstring;
+ }
+ else if (optstring[0] == '+')
+ {
+ ordering = REQUIRE_ORDER;
+ ++optstring;
+ }
+ else if (getenv ("POSIXLY_CORRECT") != NULL)
+ ordering = REQUIRE_ORDER;
+ else
+ ordering = PERMUTE;
}
if (nextchar == NULL || *nextchar == '\0')
{
- /* Advance to the next ARGV-element. */
-
if (ordering == PERMUTE)
{
/* If we have just processed some options following some non-options,
@@ -405,16 +390,21 @@ _getopt_internal (argc, argv, optstring, longopts, longind, long_only)
else if (last_nonopt != optind)
first_nonopt = optind;
- /* Skip any additional non-options
+ /* Now skip any additional non-options
and extend the range of non-options previously skipped. */
while (optind < argc
- && (argv[optind][0] != '-' || argv[optind][1] == '\0'))
+ && (argv[optind][0] != '-' || argv[optind][1] == '\0')
+#ifdef GETOPT_COMPAT
+ && (longopts == NULL
+ || argv[optind][0] != '+' || argv[optind][1] == '\0')
+#endif /* GETOPT_COMPAT */
+ )
optind++;
last_nonopt = optind;
}
- /* The special ARGV-element `--' means premature end of options.
+ /* Special ARGV-element `--' means premature end of options.
Skip it like a null option,
then exchange with previous non-options as if it were an option,
then skip everything else like a non-option. */
@@ -447,7 +437,12 @@ _getopt_internal (argc, argv, optstring, longopts, longind, long_only)
/* If we have come to a non-option and did not permute it,
either stop the scan or describe it to the caller and pass it by. */
- if ((argv[optind][0] != '-' || argv[optind][1] == '\0'))
+ if ((argv[optind][0] != '-' || argv[optind][1] == '\0')
+#ifdef GETOPT_COMPAT
+ && (longopts == NULL
+ || argv[optind][0] != '+' || argv[optind][1] == '\0')
+#endif /* GETOPT_COMPAT */
+ )
{
if (ordering == REQUIRE_ORDER)
return EOF;
@@ -456,53 +451,36 @@ _getopt_internal (argc, argv, optstring, longopts, longind, long_only)
}
/* We have found another option-ARGV-element.
- Skip the initial punctuation. */
+ Start decoding its characters. */
nextchar = (argv[optind] + 1
+ (longopts != NULL && argv[optind][1] == '-'));
}
- /* Decode the current option-ARGV-element. */
-
- /* Check whether the ARGV-element is a long option.
-
- If long_only and the ARGV-element has the form "-f", where f is
- a valid short option, don't consider it an abbreviated form of
- a long option that starts with f. Otherwise there would be no
- way to give the -f short option.
-
- On the other hand, if there's a long option "fubar" and
- the ARGV-element is "-fu", do consider that an abbreviation of
- the long option, just like "--fu", and not "-f" with arg "u".
-
- This distinction seems to be the most useful approach. */
-
if (longopts != NULL
- && (argv[optind][1] == '-'
- || (long_only && (argv[optind][2]
- || !my_index (optstring, argv[optind][1])))))
+ && ((argv[optind][0] == '-'
+ && (argv[optind][1] == '-' || long_only))
+#ifdef GETOPT_COMPAT
+ || argv[optind][0] == '+'
+#endif /* GETOPT_COMPAT */
+ ))
{
- char *nameend;
const struct option *p;
- const struct option *pfound = NULL;
+ char *s = nextchar;
int exact = 0;
int ambig = 0;
+ const struct option *pfound = NULL;
int indfound;
- int option_index;
-
- for (nameend = nextchar; *nameend && *nameend != '='; nameend++)
- /* Do nothing. */ ;
-#ifdef lint
- indfound = 0; /* Avoid spurious compiler warning. */
-#endif
+ while (*s && *s != '=')
+ s++;
- /* Test all long options for either exact match
- or abbreviated matches. */
- for (p = longopts, option_index = 0; p->name; p++, option_index++)
- if (!strncmp (p->name, nextchar, nameend - nextchar))
+ /* Test all options for either exact match or abbreviated matches. */
+ for (p = longopts, option_index = 0; p->name;
+ p++, option_index++)
+ if (!strncmp (p->name, nextchar, s - nextchar))
{
- if (nameend - nextchar == strlen (p->name))
+ if (s - nextchar == strlen (p->name))
{
/* Exact match found. */
pfound = p;
@@ -517,14 +495,14 @@ _getopt_internal (argc, argv, optstring, longopts, longind, long_only)
indfound = option_index;
}
else
- /* Second or later nonexact match found. */
+ /* Second nonexact match found. */
ambig = 1;
}
if (ambig && !exact)
{
if (opterr)
- fprintf (stderr, _("%s: option `%s' is ambiguous\n"),
+ fprintf (stderr, "%s: option `%s' is ambiguous\n",
argv[0], argv[optind]);
nextchar += strlen (nextchar);
optind++;
@@ -535,26 +513,27 @@ _getopt_internal (argc, argv, optstring, longopts, longind, long_only)
{
option_index = indfound;
optind++;
- if (*nameend)
+ if (*s)
{
/* Don't test has_arg with >, because some C compilers don't
allow it to be used on enums. */
if (pfound->has_arg)
- optarg = nameend + 1;
+ optarg = s + 1;
else
{
if (opterr)
- if (argv[optind - 1][1] == '-')
- /* --option */
- fprintf (stderr,
- _("%s: option `--%s' doesn't allow an argument\n"),
- argv[0], pfound->name);
- else
- /* +option or -option */
- fprintf (stderr,
- _("%s: option `%c%s' doesn't allow an argument\n"),
- argv[0], argv[optind - 1][0], pfound->name);
-
+ {
+ if (argv[optind - 1][1] == '-')
+ /* --option */
+ fprintf (stderr,
+ "%s: option `--%s' doesn't allow an argument\n",
+ argv[0], pfound->name);
+ else
+ /* +option or -option */
+ fprintf (stderr,
+ "%s: option `%c%s' doesn't allow an argument\n",
+ argv[0], argv[optind - 1][0], pfound->name);
+ }
nextchar += strlen (nextchar);
return '?';
}
@@ -566,9 +545,8 @@ _getopt_internal (argc, argv, optstring, longopts, longind, long_only)
else
{
if (opterr)
- fprintf (stderr,
- _("%s: option `%s' requires an argument\n"),
- argv[0], argv[optind - 1]);
+ fprintf (stderr, "%s: option `%s' requires an argument\n",
+ argv[0], argv[optind - 1]);
nextchar += strlen (nextchar);
return optstring[0] == ':' ? ':' : '?';
}
@@ -583,23 +561,25 @@ _getopt_internal (argc, argv, optstring, longopts, longind, long_only)
}
return pfound->val;
}
-
/* Can't find it as a long option. If this is not getopt_long_only,
or the option starts with '--' or is not a valid short
option, then it's an error.
Otherwise interpret it as a short option. */
if (!long_only || argv[optind][1] == '-'
+#ifdef GETOPT_COMPAT
+ || argv[optind][0] == '+'
+#endif /* GETOPT_COMPAT */
|| my_index (optstring, *nextchar) == NULL)
{
if (opterr)
{
if (argv[optind][1] == '-')
/* --option */
- fprintf (stderr, _("%s: unrecognized option `--%s'\n"),
+ fprintf (stderr, "%s: unrecognized option `--%s'\n",
argv[0], nextchar);
else
/* +option or -option */
- fprintf (stderr, _("%s: unrecognized option `%c%s'\n"),
+ fprintf (stderr, "%s: unrecognized option `%c%s'\n",
argv[0], argv[optind][0], nextchar);
}
nextchar = (char *) "";
@@ -608,7 +588,7 @@ _getopt_internal (argc, argv, optstring, longopts, longind, long_only)
}
}
- /* Look at and handle the next short option-character. */
+ /* Look at and handle the next option-character. */
{
char c = *nextchar++;
@@ -622,13 +602,16 @@ _getopt_internal (argc, argv, optstring, longopts, longind, long_only)
{
if (opterr)
{
- if (posixly_correct)
- /* 1003.2 specifies the format of this message. */
- fprintf (stderr, _("%s: illegal option -- %c\n"),
+#if 0
+ if (c < 040 || c >= 0177)
+ fprintf (stderr, "%s: unrecognized option, character code 0%o\n",
argv[0], c);
else
- fprintf (stderr, _("%s: invalid option -- %c\n"),
- argv[0], c);
+ fprintf (stderr, "%s: unrecognized option `-%c'\n", argv[0], c);
+#else
+ /* 1003.2 specifies the format of this message. */
+ fprintf (stderr, "%s: illegal option -- %c\n", argv[0], c);
+#endif
}
optopt = c;
return '?';
@@ -644,7 +627,7 @@ _getopt_internal (argc, argv, optstring, longopts, longind, long_only)
optind++;
}
else
- optarg = NULL;
+ optarg = 0;
nextchar = NULL;
}
else
@@ -661,10 +644,14 @@ _getopt_internal (argc, argv, optstring, longopts, longind, long_only)
{
if (opterr)
{
+#if 0
+ fprintf (stderr, "%s: option `-%c' requires an argument\n",
+ argv[0], c);
+#else
/* 1003.2 specifies the format of this message. */
- fprintf (stderr,
- _("%s: option requires an argument -- %c\n"),
- argv[0], c);
+ fprintf (stderr, "%s: option requires an argument -- %c\n",
+ argv[0], c);
+#endif
}
optopt = c;
if (optstring[0] == ':')
diff --git a/gnu/usr.bin/sort/getopt.h b/gnu/usr.bin/sort/getopt.h
index 4ac33b7..45541f5 100644
--- a/gnu/usr.bin/sort/getopt.h
+++ b/gnu/usr.bin/sort/getopt.h
@@ -1,5 +1,5 @@
/* Declarations for getopt.
- Copyright (C) 1989, 90, 91, 92, 93, 94 Free Software Foundation, Inc.
+ Copyright (C) 1989, 1990, 1991, 1992, 1993 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
@@ -76,7 +76,7 @@ extern int optopt;
struct option
{
-#if defined (__STDC__) && __STDC__
+#if __STDC__
const char *name;
#else
char *name;
@@ -94,15 +94,15 @@ struct option
#define required_argument 1
#define optional_argument 2
-#if defined (__STDC__) && __STDC__
-#ifdef __GNU_LIBRARY__
+#if __STDC__
+#if defined(__GNU_LIBRARY__)
/* Many other libraries have conflicting prototypes for getopt, with
differences in the consts, in stdlib.h. To avoid compilation
errors, only prototype getopt for the GNU C library. */
extern int getopt (int argc, char *const *argv, const char *shortopts);
#else /* not __GNU_LIBRARY__ */
extern int getopt ();
-#endif /* __GNU_LIBRARY__ */
+#endif /* not __GNU_LIBRARY__ */
extern int getopt_long (int argc, char *const *argv, const char *shortopts,
const struct option *longopts, int *longind);
extern int getopt_long_only (int argc, char *const *argv,
@@ -120,7 +120,7 @@ extern int getopt_long ();
extern int getopt_long_only ();
extern int _getopt_internal ();
-#endif /* __STDC__ */
+#endif /* not __STDC__ */
#ifdef __cplusplus
}
diff --git a/gnu/usr.bin/sort/getopt1.c b/gnu/usr.bin/sort/getopt1.c
index 4580211..f784b57 100644
--- a/gnu/usr.bin/sort/getopt1.c
+++ b/gnu/usr.bin/sort/getopt1.c
@@ -1,5 +1,5 @@
/* getopt_long and getopt_long_only entry points for GNU getopt.
- Copyright (C) 1987, 88, 89, 90, 91, 92, 1993, 1994
+ Copyright (C) 1987, 88, 89, 90, 91, 92, 1993
Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify it
@@ -17,12 +17,19 @@
Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
#ifdef HAVE_CONFIG_H
+#if defined (emacs) || defined (CONFIG_BROKETS)
+/* We use <config.h> instead of "config.h" so that a compilation
+ using -I. -I$srcdir will use ./config.h rather than $srcdir/config.h
+ (which it would do because it found this file in $srcdir). */
#include <config.h>
+#else
+#include "config.h"
+#endif
#endif
#include "getopt.h"
-#if !defined (__STDC__) || !__STDC__
+#ifndef __STDC__
/* This is a separate conditional since some stdc systems
reject `defined (const)'. */
#ifndef const
diff --git a/gnu/usr.bin/sort/long-options.c b/gnu/usr.bin/sort/long-options.c
index dd7a8ca..8587667 100644
--- a/gnu/usr.bin/sort/long-options.c
+++ b/gnu/usr.bin/sort/long-options.c
@@ -1,5 +1,5 @@
/* Utility to accept --help and --version options as unobtrusively as possible.
- Copyright (C) 1993, 1994 Free Software Foundation, Inc.
+ Copyright (C) 1993 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -18,11 +18,21 @@
/* Jim Meyering (meyering@comco.com) */
#ifdef HAVE_CONFIG_H
+#if defined (CONFIG_BROKETS)
+/* We use <config.h> instead of "config.h" so that a compilation
+ using -I. -I$srcdir will use ./config.h rather than $srcdir/config.h
+ (which it would do because it found this file in $srcdir). */
#include <config.h>
+#else
+#include "config.h"
+#endif
#endif
#include <stdio.h>
#include <getopt.h>
+#include <sys/types.h>
+#include "system.h"
+#include "version.h"
#include "long-options.h"
static struct option const long_options[] =
@@ -36,11 +46,9 @@ static struct option const long_options[] =
Be careful not to gobble up `--'. */
void
-parse_long_options (argc, argv, command_name, version_string, usage)
+parse_long_options (argc, argv, usage)
int argc;
char **argv;
- const char *command_name;
- const char *version_string;
void (*usage)();
{
int c;
@@ -59,10 +67,10 @@ parse_long_options (argc, argv, command_name, version_string, usage)
switch (c)
{
case 'h':
- (*usage) (0);
+ usage (0);
case 'v':
- printf ("%s - %s\n", command_name, version_string);
+ printf ("%s\n", version_string);
exit (0);
default:
diff --git a/gnu/usr.bin/sort/long-options.h b/gnu/usr.bin/sort/long-options.h
index 986a52d..9d1a9c7 100644
--- a/gnu/usr.bin/sort/long-options.h
+++ b/gnu/usr.bin/sort/long-options.h
@@ -1,10 +1 @@
-#undef __P
-#if defined (__STDC__) && __STDC__
-#define __P(args) args
-#else
-#define __P(args) ()
-#endif
-
-void
- parse_long_options __P ((int _argc, char **_argv, const char *_command_name,
- const char *_version_string, void (*_usage) (int)));
+void parse_long_options ();
diff --git a/gnu/usr.bin/sort/sort.1 b/gnu/usr.bin/sort/sort.1
index e9f4b1e..17ea03f 100644
--- a/gnu/usr.bin/sort/sort.1
+++ b/gnu/usr.bin/sort/sort.1
@@ -1,4 +1,4 @@
-.TH SORT 1 "GNU Text Utilities" "FSF" \" -*- nroff -*-
+.TH SORT 1 \" -*- nroff -*-
.SH NAME
sort \- sort lines of text files
.SH SYNOPSIS
@@ -192,7 +192,7 @@ option is taken to apply to both the \fI+pos\fP and the \fI\-pos\fP
parts of a key specification. Keys may span multiple fields.
.PP
In addition, when GNU
-.B sort
+.B join
is invoked with exactly one argument, the following options are recognized:
.TP
.I "\-\-help"
diff --git a/gnu/usr.bin/sort/sort.c b/gnu/usr.bin/sort/sort.c
index dc3addb..a6c7539 100644
--- a/gnu/usr.bin/sort/sort.c
+++ b/gnu/usr.bin/sort/sort.c
@@ -1,5 +1,5 @@
/* sort - sort lines of text (with all kinds of options).
- Copyright (C) 1988, 1991, 1992, 1993, 1994, 1995 Free Software Foundation
+ Copyright (C) 1988, 1991 Free Software Foundation
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -13,13 +13,22 @@
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
Written December 1988 by Mike Haertel.
The author may be reached (Email) at the address mike@gnu.ai.mit.edu,
or (US mail) as Mike Haertel c/o Free Software Foundation. */
+#ifdef HAVE_CONFIG_H
+#if defined (CONFIG_BROKETS)
+/* We use <config.h> instead of "config.h" so that a compilation
+ using -I. -I$srcdir will use ./config.h rather than $srcdir/config.h
+ (which it would do because it found this file in $srcdir). */
#include <config.h>
+#else
+#include "config.h"
+#endif
+#endif
/* Get isblank from GNU libc. */
#define _GNU_SOURCE
@@ -27,13 +36,13 @@
#include <sys/types.h>
#include <signal.h>
#include <stdio.h>
+#ifdef __FreeBSD__
+#include <locale.h>
+#endif
#include "system.h"
-#include "version.h"
#include "long-options.h"
-#include "error.h"
-#include "xstrtod.h"
-#ifdef HAVE_LIMITS_H
+#ifdef _POSIX_VERSION
#include <limits.h>
#else
#ifndef UCHAR_MAX
@@ -46,73 +55,16 @@ char *realloc ();
void free ();
#endif
-/* Undefine, to avoid warning about redefinition on some systems. */
-#undef min
-#define min(a, b) ((a) < (b) ? (a) : (b))
+void error ();
+static void usage ();
+#define min(a, b) ((a) < (b) ? (a) : (b))
#define UCHAR_LIM (UCHAR_MAX + 1)
#define UCHAR(c) ((unsigned char) (c))
-#ifndef DEFAULT_TMPDIR
-#define DEFAULT_TMPDIR "/tmp"
-#endif
-
/* The kind of blanks for '-b' to skip in various options. */
enum blanktype { bl_start, bl_end, bl_both };
-/* Lines are held in core as counted strings. */
-struct line
-{
- char *text; /* Text of the line. */
- int length; /* Length not including final newline. */
- char *keybeg; /* Start of first key. */
- char *keylim; /* Limit of first key. */
-};
-
-/* Arrays of lines. */
-struct lines
-{
- struct line *lines; /* Dynamically allocated array of lines. */
- int used; /* Number of slots used. */
- int alloc; /* Number of slots allocated. */
- int limit; /* Max number of slots to allocate. */
-};
-
-/* Input buffers. */
-struct buffer
-{
- char *buf; /* Dynamically allocated buffer. */
- int used; /* Number of bytes used. */
- int alloc; /* Number of bytes allocated. */
- int left; /* Number of bytes left after line parsing. */
-};
-
-struct keyfield
-{
- int sword; /* Zero-origin 'word' to start at. */
- int schar; /* Additional characters to skip. */
- int skipsblanks; /* Skip leading white space at start. */
- int eword; /* Zero-origin first word after field. */
- int echar; /* Additional characters in field. */
- int skipeblanks; /* Skip trailing white space at finish. */
- int *ignore; /* Boolean array of characters to ignore. */
- char *translate; /* Translation applied to characters. */
- int numeric; /* Flag for numeric comparison. Handle
- strings of digits with optional decimal
- point, but no exponential notation. */
- int general_numeric; /* Flag for general, numeric comparison.
- Handle numbers in exponential notation. */
- int month; /* Flag for comparison by month name. */
- int reverse; /* Reverse the sense of comparison. */
- struct keyfield *next; /* Next keyfield to try. */
-};
-
-struct month
-{
- char *name;
- int val;
-};
-
/* The name this program was run with. */
char *program_name;
@@ -133,7 +85,11 @@ static char fold_toupper[UCHAR_LIM];
/* Table mapping 3-letter month names to integers.
Alphabetic order allows binary search. */
-static struct month const monthtab[] =
+static struct month
+{
+ char *name;
+ int val;
+} const monthtab[] =
{
{"APR", 4},
{"AUG", 8},
@@ -154,17 +110,17 @@ static struct month const monthtab[] =
/* Initial buffer size for in core sorting. Will not grow unless a
line longer than this is seen. */
-static int sortalloc = 512 * 1024;
+static int sortalloc = 524288;
/* Initial buffer size for in core merge buffers. Bear in mind that
up to NMERGE * mergealloc bytes may be allocated for merge buffers. */
-static int mergealloc = 16 * 1024;
+static int mergealloc = 16384;
/* Guess of average line length. */
static int linelength = 30;
/* Maximum number of elements for the array(s) of struct line's, in bytes. */
-#define LINEALLOC (256 * 1024)
+#define LINEALLOC 262144
/* Prefix for temporary file names. */
static char *temp_file_prefix;
@@ -189,55 +145,49 @@ static int unique;
/* Nonzero if any of the input files are the standard input. */
static int have_read_stdin;
-/* Lists of key field comparisons to be tried. */
-static struct keyfield keyhead;
+/* Lines are held in core as counted strings. */
+struct line
+{
+ char *text; /* Text of the line. */
+ int length; /* Length not including final newline. */
+ char *keybeg; /* Start of first key. */
+ char *keylim; /* Limit of first key. */
+};
-static void
-usage (int status)
+/* Arrays of lines. */
+struct lines
{
- if (status != 0)
- fprintf (stderr, _("Try `%s --help' for more information.\n"),
- program_name);
- else
- {
- printf (_("\
-Usage: %s [OPTION]... [FILE]...\n\
-"),
- program_name);
- printf (_("\
-Write sorted concatenation of all FILE(s) to standard output.\n\
-\n\
- +POS1 [-POS2] start a key at POS1, end it before POS2\n\
- -M compare (unknown) < `JAN' < ... < `DEC', imply -b\n\
- -T DIRECT use DIRECT for temporary files, not $TMPDIR or %s\n\
- -b ignore leading blanks in sort fields or keys\n\
- -c check if given files already sorted, do not sort\n\
- -d consider only [a-zA-Z0-9 ] characters in keys\n\
- -f fold lower case to upper case characters in keys\n\
- -g compare according to general numerical value, imply -b\n\
- -i consider only [\\040-\\0176] characters in keys\n\
- -k POS1[,POS2] same as +POS1 [-POS2], but all positions counted from 1\n\
- -m merge already sorted files, do not sort\n\
- -n compare according to string numerical value, imply -b\n\
- -o FILE write result on FILE instead of standard output\n\
- -r reverse the result of comparisons\n\
- -s stabilize sort by disabling last resort comparison\n\
- -t SEP use SEParator instead of non- to whitespace transition\n\
- -u with -c, check for strict ordering\n\
- -u with -m, only output the first of an equal sequence\n\
- --help display this help and exit\n\
- --version output version information and exit\n\
-\n\
-POS is F[.C][OPTS], where F is the field number and C the character\n\
-position in the field, both counted from zero. OPTS is made up of one\n\
-or more of Mbdfinr, this effectively disable global -Mbdfinr settings\n\
-for that key. If no key given, use the entire line as key. With no\n\
-FILE, or when FILE is -, read standard input.\n\
-")
- , DEFAULT_TMPDIR);
- }
- exit (status);
-}
+ struct line *lines; /* Dynamically allocated array of lines. */
+ int used; /* Number of slots used. */
+ int alloc; /* Number of slots allocated. */
+ int limit; /* Max number of slots to allocate. */
+};
+
+/* Input buffers. */
+struct buffer
+{
+ char *buf; /* Dynamically allocated buffer. */
+ int used; /* Number of bytes used. */
+ int alloc; /* Number of bytes allocated. */
+ int left; /* Number of bytes left after line parsing. */
+};
+
+/* Lists of key field comparisons to be tried. */
+static struct keyfield
+{
+ int sword; /* Zero-origin 'word' to start at. */
+ int schar; /* Additional characters to skip. */
+ int skipsblanks; /* Skip leading white space at start. */
+ int eword; /* Zero-origin first word after field. */
+ int echar; /* Additional characters in field. */
+ int skipeblanks; /* Skip trailing white space at finish. */
+ int *ignore; /* Boolean array of characters to ignore. */
+ char *translate; /* Translation applied to characters. */
+ int numeric; /* Flag for numeric comparison. */
+ int month; /* Flag for comparison by month name. */
+ int reverse; /* Reverse the sense of comparison. */
+ struct keyfield *next; /* Next keyfield to try. */
+} keyhead;
/* The list of temporary files. */
static struct tempnode
@@ -249,7 +199,7 @@ static struct tempnode
/* Clean up any remaining temporary files. */
static void
-cleanup (void)
+cleanup ()
{
struct tempnode *node;
@@ -259,15 +209,16 @@ cleanup (void)
/* Allocate N bytes of memory dynamically, with error checking. */
-static char *
-xmalloc (unsigned int n)
+char *
+xmalloc (n)
+ unsigned n;
{
char *p;
p = malloc (n);
if (p == 0)
{
- error (0, 0, _("virtual memory exhausted"));
+ error (0, 0, "virtual memory exhausted");
cleanup ();
exit (2);
}
@@ -279,8 +230,10 @@ xmalloc (unsigned int n)
If P is NULL, run xmalloc.
If N is 0, run free and return NULL. */
-static char *
-xrealloc (char *p, unsigned int n)
+char *
+xrealloc (p, n)
+ char *p;
+ unsigned n;
{
if (p == 0)
return xmalloc (n);
@@ -292,7 +245,7 @@ xrealloc (char *p, unsigned int n)
p = realloc (p, n);
if (p == 0)
{
- error (0, 0, _("virtual memory exhausted"));
+ error (0, 0, "virtual memory exhausted");
cleanup ();
exit (2);
}
@@ -300,81 +253,50 @@ xrealloc (char *p, unsigned int n)
}
static FILE *
-xtmpfopen (const char *file)
+xfopen (file, how)
+ char *file, *how;
{
- FILE *fp;
- int fd;
+ FILE *fp = strcmp (file, "-") ? fopen (file, how) : stdin;
- fd = open (file, O_WRONLY | O_CREAT | O_TRUNC, 0600);
- if (fd < 0 || (fp = fdopen (fd, "w")) == NULL)
+ if (fp == 0)
{
error (0, errno, "%s", file);
cleanup ();
exit (2);
}
-
- return fp;
-}
-
-static FILE *
-xfopen (const char *file, const char *how)
-{
- FILE *fp;
-
- if (strcmp (file, "-") == 0)
- {
- fp = stdin;
- }
- else
- {
- if ((fp = fopen (file, how)) == NULL)
- {
- error (0, errno, "%s", file);
- cleanup ();
- exit (2);
- }
- }
-
if (fp == stdin)
have_read_stdin = 1;
return fp;
}
static void
-xfclose (FILE *fp)
+xfclose (fp)
+ FILE *fp;
{
- if (fp == stdin)
- {
- /* Allow reading stdin from tty more than once. */
- if (feof (fp))
- clearerr (fp);
- }
- else if (fp == stdout)
- {
- if (fflush (fp) != 0)
- {
- error (0, errno, _("flushing file"));
- cleanup ();
- exit (2);
- }
- }
- else
+ fflush (fp);
+ if (fp != stdin && fp != stdout)
{
if (fclose (fp) != 0)
{
- error (0, errno, _("error closing file"));
+ error (0, errno, "error closing file");
cleanup ();
exit (2);
}
}
+ else
+ /* Allow reading stdin from tty more than once. */
+ clearerr (fp);
}
static void
-xfwrite (const char *buf, int size, int nelem, FILE *fp)
+xfwrite (buf, size, nelem, fp)
+ char *buf;
+ int size, nelem;
+ FILE *fp;
{
if (fwrite (buf, size, nelem, fp) != nelem)
{
- error (0, errno, _("write error"));
+ error (0, errno, "write error");
cleanup ();
exit (2);
}
@@ -383,25 +305,18 @@ xfwrite (const char *buf, int size, int nelem, FILE *fp)
/* Return a name for a temporary file. */
static char *
-tempname (void)
+tempname ()
{
- static unsigned int seq;
+ static int seq;
int len = strlen (temp_file_prefix);
- char *name = xmalloc (len + 1 + sizeof ("sort") - 1 + 5 + 5 + 1);
- struct tempnode *node;
-
- node = (struct tempnode *) xmalloc (sizeof (struct tempnode));
- sprintf (name,
- "%s%ssort%5.5d%5.5d",
- temp_file_prefix,
- (len && temp_file_prefix[len - 1] != '/') ? "/" : "",
- (unsigned int) getpid () & 0xffff, seq);
-
- /* Make sure that SEQ's value fits in 5 digits. */
- ++seq;
- if (seq >= 100000)
- seq = 0;
+ char *name = xmalloc (len + 16);
+ struct tempnode *node =
+ (struct tempnode *) xmalloc (sizeof (struct tempnode));
+ if (len && temp_file_prefix[len - 1] != '/')
+ sprintf (name, "%s/sort%5.5d%5.5d", temp_file_prefix, getpid (), ++seq);
+ else
+ sprintf (name, "%ssort%5.5d%5.5d", temp_file_prefix, getpid (), ++seq);
node->name = name;
node->next = temphead.next;
temphead.next = node;
@@ -412,7 +327,8 @@ tempname (void)
remove it if it is found on the list. */
static void
-zaptemp (char *name)
+zaptemp (name)
+ char *name;
{
struct tempnode *node, *temp;
@@ -432,7 +348,7 @@ zaptemp (char *name)
/* Initialize the character class tables. */
static void
-inittables (void)
+inittables ()
{
int i;
@@ -456,7 +372,9 @@ inittables (void)
/* Initialize BUF, allocating ALLOC bytes initially. */
static void
-initbuf (struct buffer *buf, int alloc)
+initbuf (buf, alloc)
+ struct buffer *buf;
+ int alloc;
{
buf->alloc = alloc;
buf->buf = xmalloc (buf->alloc);
@@ -469,11 +387,13 @@ initbuf (struct buffer *buf, int alloc)
of bytes buffered. */
static int
-fillbuf (struct buffer *buf, FILE *fp)
+fillbuf (buf, fp)
+ struct buffer *buf;
+ FILE *fp;
{
int cc;
- memmove (buf->buf, buf->buf + buf->used - buf->left, buf->left);
+ bcopy (buf->buf + buf->used - buf->left, buf->buf, buf->left);
buf->used = buf->left;
while (!feof (fp) && (buf->used == 0 || !memchr (buf->buf, '\n', buf->used)))
@@ -486,7 +406,7 @@ fillbuf (struct buffer *buf, FILE *fp)
cc = fread (buf->buf + buf->used, 1, buf->alloc - buf->used, fp);
if (ferror (fp))
{
- error (0, errno, _("read error"));
+ error (0, errno, "read error");
cleanup ();
exit (2);
}
@@ -511,7 +431,10 @@ fillbuf (struct buffer *buf, FILE *fp)
for, ever. */
static void
-initlines (struct lines *lines, int alloc, int limit)
+initlines (lines, alloc, limit)
+ struct lines *lines;
+ int alloc;
+ int limit;
{
lines->alloc = alloc;
lines->lines = (struct line *) xmalloc (lines->alloc * sizeof (struct line));
@@ -523,7 +446,9 @@ initlines (struct lines *lines, int alloc, int limit)
by KEY in LINE. */
static char *
-begfield (const struct line *line, const struct keyfield *key)
+begfield (line, key)
+ struct line *line;
+ struct keyfield *key;
{
register char *ptr = line->text, *lim = ptr + line->length;
register int sword = key->sword, schar = key->schar;
@@ -549,10 +474,8 @@ begfield (const struct line *line, const struct keyfield *key)
while (ptr < lim && blanks[UCHAR (*ptr)])
++ptr;
- if (ptr + schar <= lim)
- ptr += schar;
- else
- ptr = lim;
+ while (ptr < lim && schar--)
+ ++ptr;
return ptr;
}
@@ -561,28 +484,19 @@ begfield (const struct line *line, const struct keyfield *key)
in LINE specified by KEY. */
static char *
-limfield (const struct line *line, const struct keyfield *key)
+limfield (line, key)
+ struct line *line;
+ struct keyfield *key;
{
register char *ptr = line->text, *lim = ptr + line->length;
register int eword = key->eword, echar = key->echar;
- /* Note: from the POSIX spec:
- The leading field separator itself is included in
- a field when -t is not used. FIXME: move this comment up... */
-
- /* Move PTR past EWORD fields or to one past the last byte on LINE,
- whichever comes first. If there are more than EWORD fields, leave
- PTR pointing at the beginning of the field having zero-based index,
- EWORD. If a delimiter character was specified (via -t), then that
- `beginning' is the first character following the delimiting TAB.
- Otherwise, leave PTR pointing at the first `blank' character after
- the preceding field. */
if (tab)
while (ptr < lim && eword--)
{
while (ptr < lim && *ptr != tab)
++ptr;
- if (ptr < lim && (eword || echar > 0))
+ if (ptr < lim && (eword || key->skipeblanks))
++ptr;
}
else
@@ -594,54 +508,23 @@ limfield (const struct line *line, const struct keyfield *key)
++ptr;
}
- /* Make LIM point to the end of (one byte past) the current field. */
- if (tab)
- {
- char *newlim;
- newlim = memchr (ptr, tab, lim - ptr);
- if (newlim)
- lim = newlim;
- }
- else
- {
- char *newlim;
- newlim = ptr;
- while (newlim < lim && blanks[UCHAR (*newlim)])
- ++newlim;
- while (newlim < lim && !blanks[UCHAR (*newlim)])
- ++newlim;
- lim = newlim;
- }
-
- /* If we're skipping leading blanks, don't start counting characters
- until after skipping past any leading blanks. */
- if (key->skipsblanks)
+ if (key->skipeblanks)
while (ptr < lim && blanks[UCHAR (*ptr)])
++ptr;
- /* Advance PTR by ECHAR (if possible), but no further than LIM. */
- if (ptr + echar <= lim)
- ptr += echar;
- else
- ptr = lim;
+ while (ptr < lim && echar--)
+ ++ptr;
return ptr;
}
-/* FIXME */
-
-void
-trim_trailing_blanks (const char *a_start, char **a_end)
-{
- while (*a_end > a_start && blanks[UCHAR (*(*a_end - 1))])
- --(*a_end);
-}
-
/* Find the lines in BUF, storing pointers and lengths in LINES.
- Also replace newlines in BUF with NULs. */
+ Also replace newlines with NULs. */
static void
-findlines (struct buffer *buf, struct lines *lines)
+findlines (buf, lines)
+ struct buffer *buf;
+ struct lines *lines;
{
register char *beg = buf->buf, *lim = buf->buf + buf->used, *ptr;
struct keyfield *key = keyhead.next;
@@ -686,11 +569,6 @@ findlines (struct buffer *buf, struct lines *lines)
++beg;
lines->lines[lines->used].keybeg = beg;
}
- if (key->skipeblanks)
- {
- trim_trailing_blanks (lines->lines[lines->used].keybeg,
- &lines->lines[lines->used].keylim);
- }
}
else
{
@@ -710,7 +588,8 @@ findlines (struct buffer *buf, struct lines *lines)
of the fraction. Strings not of this form are considered to be zero. */
static int
-fraccompare (register const char *a, register const char *b)
+fraccompare (a, b)
+ register char *a, *b;
{
register tmpa = UCHAR (*a), tmpb = UCHAR (*b);
@@ -765,12 +644,12 @@ fraccompare (register const char *a, register const char *b)
hideously fast. */
static int
-numcompare (register const char *a, register const char *b)
+numcompare (a, b)
+ register char *a, *b;
{
register int tmpa, tmpb, loga, logb, tmp;
- tmpa = UCHAR (*a);
- tmpb = UCHAR (*b);
+ tmpa = UCHAR (*a), tmpb = UCHAR (*b);
while (blanks[tmpa])
tmpa = UCHAR (*++a);
@@ -779,30 +658,19 @@ numcompare (register const char *a, register const char *b)
if (tmpa == '-')
{
- do
- tmpa = UCHAR (*++a);
- while (tmpa == '0');
+ tmpa = UCHAR (*++a);
if (tmpb != '-')
{
- if (tmpa == '.')
- do
- tmpa = UCHAR (*++a);
- while (tmpa == '0');
- if (digits[tmpa])
- return -1;
- while (tmpb == '0')
- tmpb = UCHAR (*++b);
- if (tmpb == '.')
- do
- tmpb = *++b;
- while (tmpb == '0');
- if (digits[tmpb])
+ if (digits[tmpa] && digits[tmpb])
return -1;
return 0;
}
- do
+ tmpb = UCHAR (*++b);
+
+ while (tmpa == '0')
+ tmpa = UCHAR (*++a);
+ while (tmpb == '0')
tmpb = UCHAR (*++b);
- while (tmpb == '0');
while (tmpa == tmpb && digits[tmpa])
tmpa = UCHAR (*++a), tmpb = UCHAR (*++b);
@@ -832,22 +700,7 @@ numcompare (register const char *a, register const char *b)
}
else if (tmpb == '-')
{
- do
- tmpb = UCHAR (*++b);
- while (tmpb == '0');
- if (tmpb == '.')
- do
- tmpb = *++b;
- while (tmpb == '0');
- if (digits[tmpb])
- return 1;
- while (tmpa == '0')
- tmpa = UCHAR (*++a);
- if (tmpa == '.')
- do
- tmpa = UCHAR (*++a);
- while (tmpa == '0');
- if (digits[tmpa])
+ if (digits[UCHAR (tmpa)] && digits[UCHAR (*++b)])
return 1;
return 0;
}
@@ -886,29 +739,13 @@ numcompare (register const char *a, register const char *b)
}
}
-static int
-general_numcompare (const char *sa, const char *sb)
-{
- double a, b;
- /* FIXME: add option to warn about failed conversions. */
- /* FIXME: maybe add option to try expensive FP conversion
- only if A and B can't be compared more cheaply/accurately. */
- if (xstrtod (sa, NULL, &a))
- {
- a = 0;
- }
- if (xstrtod (sb, NULL, &b))
- {
- b = 0;
- }
- return a == b ? 0 : a < b ? -1 : 1;
-}
-
/* Return an integer <= 12 associated with month name S with length LEN,
0 if the name in S is not recognized. */
static int
-getmonth (const char *s, int len)
+getmonth (s, len)
+ char *s;
+ int len;
{
char month[4];
register int i, lo = 0, hi = 12;
@@ -937,7 +774,8 @@ getmonth (const char *s, int len)
are no more keys or a difference is found. */
static int
-keycompare (const struct line *a, const struct line *b)
+keycompare (a, b)
+ struct line *a, *b;
{
register char *texta, *textb, *lima, *limb, *translate;
register int *ignore;
@@ -986,16 +824,6 @@ keycompare (const struct line *a, const struct line *b)
if (lenb < 0)
lenb = 0;
- if (key->skipeblanks)
- {
- char *a_end = texta + lena;
- char *b_end = textb + lenb;
- trim_trailing_blanks (texta, &a_end);
- trim_trailing_blanks (textb, &b_end);
- lena = a_end - texta;
- lenb = b_end - textb;
- }
-
/* Actually compare the fields. */
if (key->numeric)
{
@@ -1014,23 +842,6 @@ keycompare (const struct line *a, const struct line *b)
return key->reverse ? -diff : diff;
continue;
}
- else if (key->general_numeric)
- {
- if (*lima || *limb)
- {
- char savea = *lima, saveb = *limb;
-
- *lima = *limb = '\0';
- diff = general_numcompare (texta, textb);
- *lima = savea, *limb = saveb;
- }
- else
- diff = general_numcompare (texta, textb);
-
- if (diff)
- return key->reverse ? -diff : diff;
- continue;
- }
else if (key->month)
{
diff = getmonth (texta, lena) - getmonth (textb, lenb);
@@ -1039,64 +850,38 @@ keycompare (const struct line *a, const struct line *b)
continue;
}
else if (ignore && translate)
-
-#define CMP_WITH_IGNORE(A, B) \
- do \
- { \
- while (texta < lima && textb < limb) \
- { \
- while (texta < lima && ignore[UCHAR (*texta)]) \
- ++texta; \
- while (textb < limb && ignore[UCHAR (*textb)]) \
- ++textb; \
- if (texta < lima && textb < limb) \
- { \
- if ((A) != (B)) \
- { \
- diff = (A) - (B); \
- break; \
- } \
- ++texta; \
- ++textb; \
- } \
- \
- if (texta == lima && textb < limb && !ignore[UCHAR (*textb)]) \
- diff = -1; \
- else if (texta < lima && textb == limb \
- && !ignore[UCHAR (*texta)]) \
- diff = 1; \
- } \
- \
- if (diff == 0) \
- { \
- while (texta < lima && ignore[UCHAR (*texta)]) \
- ++texta; \
- while (textb < limb && ignore[UCHAR (*textb)]) \
- ++textb; \
- \
- if (texta == lima && textb < limb) \
- diff = -1; \
- else if (texta < lima && textb == limb) \
- diff = 1; \
- } \
- /* Relative lengths are meaningless if characters were ignored. \
- Handling this case here avoids what might be an invalid length \
- comparison below. */ \
- if (diff == 0 && texta == lima && textb == limb) \
- return 0; \
- } \
- while (0)
-
- CMP_WITH_IGNORE (translate[UCHAR (*texta)], translate[UCHAR (*textb)]);
+ while (texta < lima && textb < limb)
+ {
+ while (texta < lima && ignore[UCHAR (*texta)])
+ ++texta;
+ while (textb < limb && ignore[UCHAR (*textb)])
+ ++textb;
+ if (texta < lima && textb < limb &&
+ translate[UCHAR (*texta++)] != translate[UCHAR (*textb++)])
+ {
+ diff = translate[UCHAR (*--texta)] - translate[UCHAR (*--textb)];
+ break;
+ }
+ }
else if (ignore)
- CMP_WITH_IGNORE (*texta, *textb);
+ while (texta < lima && textb < limb)
+ {
+ while (texta < lima && ignore[UCHAR (*texta)])
+ ++texta;
+ while (textb < limb && ignore[UCHAR (*textb)])
+ ++textb;
+ if (texta < lima && textb < limb && *texta++ != *textb++)
+ {
+ diff = *--texta - *--textb;
+ break;
+ }
+ }
else if (translate)
while (texta < lima && textb < limb)
{
if (translate[UCHAR (*texta++)] != translate[UCHAR (*textb++)])
{
- diff = (translate[UCHAR (*--texta)]
- - translate[UCHAR (*--textb)]);
+ diff = translate[UCHAR (*--texta)] - translate[UCHAR (*--textb)];
break;
}
}
@@ -1116,7 +901,8 @@ keycompare (const struct line *a, const struct line *b)
depending on whether A compares less than, equal to, or greater than B. */
static int
-compare (register const struct line *a, register const struct line *b)
+compare (a, b)
+ register struct line *a, *b;
{
int diff, tmpa, tmpb, mini;
@@ -1155,17 +941,18 @@ compare (register const struct line *a, register const struct line *b)
}
/* Check that the lines read from the given FP come in order. Return
- 1 if they do and 0 if there is a disorder.
- FIXME: return number of first out-of-order line if not sorted. */
+ 1 if they do and 0 if there is a disorder. */
static int
-checkfp (FILE *fp)
+checkfp (fp)
+ FILE *fp;
{
struct buffer buf; /* Input buffer. */
struct lines lines; /* Lines scanned from the buffer. */
struct line temp; /* Copy of previous line. */
int cc; /* Character count. */
- int alloc, sorted = 1;
+ int cmp; /* Result of calling compare. */
+ int alloc, i, success = 1;
initbuf (&buf, mergealloc);
initlines (&lines, mergealloc / linelength + 1,
@@ -1174,69 +961,64 @@ checkfp (FILE *fp)
temp.text = xmalloc (alloc);
cc = fillbuf (&buf, fp);
- if (cc == 0)
- goto finish;
-
findlines (&buf, &lines);
- while (1)
- {
- struct line *prev_line; /* Pointer to previous line. */
- int cmp; /* Result of calling compare. */
- int i;
+ if (cc)
+ do
+ {
+ /* Compare each line in the buffer with its successor. */
+ for (i = 0; i < lines.used - 1; ++i)
+ {
+ cmp = compare (&lines.lines[i], &lines.lines[i + 1]);
+ if ((unique && cmp >= 0) || (cmp > 0))
+ {
+ success = 0;
+ goto finish;
+ }
+ }
- /* Compare each line in the buffer with its successor. */
- for (i = 0; i < lines.used - 1; ++i)
- {
- cmp = compare (&lines.lines[i], &lines.lines[i + 1]);
- if ((unique && cmp >= 0) || (cmp > 0))
- {
- sorted = 0;
- goto finish;
- }
- }
+ /* Save the last line of the buffer and refill the buffer. */
+ if (lines.lines[lines.used - 1].length > alloc)
+ {
+ while (lines.lines[lines.used - 1].length + 1 > alloc)
+ alloc *= 2;
+ temp.text = xrealloc (temp.text, alloc);
+ }
+ bcopy (lines.lines[lines.used - 1].text, temp.text,
+ lines.lines[lines.used - 1].length + 1);
+ temp.length = lines.lines[lines.used - 1].length;
- /* Save the last line of the buffer and refill the buffer. */
- prev_line = lines.lines + (lines.used - 1);
- if (prev_line->length > alloc)
- {
- while (prev_line->length + 1 > alloc)
- alloc *= 2;
- temp.text = xrealloc (temp.text, alloc);
- }
- memcpy (temp.text, prev_line->text, prev_line->length + 1);
- temp.length = prev_line->length;
- temp.keybeg = temp.text + (prev_line->keybeg - prev_line->text);
- temp.keylim = temp.text + (prev_line->keylim - prev_line->text);
-
- cc = fillbuf (&buf, fp);
- if (cc == 0)
- break;
-
- findlines (&buf, &lines);
- /* Make sure the line saved from the old buffer contents is
- less than or equal to the first line of the new buffer. */
- cmp = compare (&temp, &lines.lines[0]);
- if ((unique && cmp >= 0) || (cmp > 0))
- {
- sorted = 0;
- break;
- }
- }
+ cc = fillbuf (&buf, fp);
+ if (cc)
+ {
+ findlines (&buf, &lines);
+ /* Make sure the line saved from the old buffer contents is
+ less than or equal to the first line of the new buffer. */
+ cmp = compare (&temp, &lines.lines[0]);
+ if ((unique && cmp >= 0) || (cmp > 0))
+ {
+ success = 0;
+ break;
+ }
+ }
+ }
+ while (cc);
finish:
xfclose (fp);
free (buf.buf);
free ((char *) lines.lines);
free (temp.text);
- return sorted;
+ return success;
}
/* Merge lines from FPS onto OFP. NFPS cannot be greater than NMERGE.
Close FPS before returning. */
static void
-mergefps (FILE **fps, register int nfps, FILE *ofp)
+mergefps (fps, nfps, ofp)
+ FILE *fps[], *ofp;
+ register int nfps;
{
struct buffer buffer[NMERGE]; /* Input buffers for each file. */
struct lines lines[NMERGE]; /* Line tables for each buffer. */
@@ -1250,10 +1032,6 @@ mergefps (FILE **fps, register int nfps, FILE *ofp)
output. */
register int i, j, t;
-#ifdef lint /* Suppress `used before initialized' warning. */
- savealloc = 0;
-#endif
-
/* Allocate space for a saved line if necessary. */
if (unique)
{
@@ -1297,7 +1075,7 @@ mergefps (FILE **fps, register int nfps, FILE *ofp)
/* Repeatedly output the smallest line until no input remains. */
while (nfps)
{
- /* If uniqified output is turned on, output only the first of
+ /* If uniqified output is turned out, output only the first of
an identical series of lines. */
if (unique)
{
@@ -1316,7 +1094,7 @@ mergefps (FILE **fps, register int nfps, FILE *ofp)
saved.text = xrealloc (saved.text, savealloc);
}
saved.length = lines[ord[0]].lines[cur[ord[0]]].length;
- memcpy (saved.text, lines[ord[0]].lines[cur[ord[0]]].text,
+ bcopy (lines[ord[0]].lines[cur[ord[0]]].text, saved.text,
saved.length + 1);
if (lines[ord[0]].lines[cur[ord[0]]].keybeg != NULL)
{
@@ -1398,7 +1176,9 @@ mergefps (FILE **fps, register int nfps, FILE *ofp)
/* Sort the array LINES with NLINES members, using TEMP for temporary space. */
static void
-sortlines (struct line *lines, int nlines, struct line *temp)
+sortlines (lines, nlines, temp)
+ struct line *lines, *temp;
+ int nlines;
{
register struct line *lo, *hi, *t;
register int nlo, nhi;
@@ -1439,7 +1219,9 @@ sortlines (struct line *lines, int nlines, struct line *temp)
Return a count of disordered files. */
static int
-check (char **files, int nfiles)
+check (files, nfiles)
+ char *files[];
+ int nfiles;
{
int i, disorders = 0;
FILE *fp;
@@ -1449,7 +1231,7 @@ check (char **files, int nfiles)
fp = xfopen (files[i], "r");
if (!checkfp (fp))
{
- fprintf (stderr, _("%s: disorder on %s\n"), program_name, files[i]);
+ printf ("%s: disorder on %s\n", program_name, files[i]);
++disorders;
}
}
@@ -1459,7 +1241,10 @@ check (char **files, int nfiles)
/* Merge NFILES FILES onto OFP. */
static void
-merge (char **files, int nfiles, FILE *ofp)
+merge (files, nfiles, ofp)
+ char *files[];
+ int nfiles;
+ FILE *ofp;
{
int i, j, t;
char *temp;
@@ -1472,7 +1257,7 @@ merge (char **files, int nfiles, FILE *ofp)
{
for (j = 0; j < NMERGE; ++j)
fps[j] = xfopen (files[i * NMERGE + j], "r");
- tfp = xtmpfopen (temp = tempname ());
+ tfp = xfopen (temp = tempname (), "w");
mergefps (fps, NMERGE, tfp);
xfclose (tfp);
for (j = 0; j < NMERGE; ++j)
@@ -1481,7 +1266,7 @@ merge (char **files, int nfiles, FILE *ofp)
}
for (j = 0; j < nfiles % NMERGE; ++j)
fps[j] = xfopen (files[i * NMERGE + j], "r");
- tfp = xtmpfopen (temp = tempname ());
+ tfp = xfopen (temp = tempname (), "w");
mergefps (fps, nfiles % NMERGE, tfp);
xfclose (tfp);
for (j = 0; j < nfiles % NMERGE; ++j)
@@ -1500,7 +1285,10 @@ merge (char **files, int nfiles, FILE *ofp)
/* Sort NFILES FILES onto OFP. */
static void
-sort (char **files, int nfiles, FILE *ofp)
+sort (files, nfiles, ofp)
+ char **files;
+ int nfiles;
+ FILE *ofp;
{
struct buffer buf;
struct lines lines;
@@ -1508,7 +1296,7 @@ sort (char **files, int nfiles, FILE *ofp)
int i, ntmp;
FILE *fp, *tfp;
struct tempnode *node;
- int n_temp_files = 0;
+ int ntemp = 0;
char **tempfiles;
initbuf (&buf, sortalloc);
@@ -1531,12 +1319,12 @@ sort (char **files, int nfiles, FILE *ofp)
xrealloc ((char *) tmp, ntmp * sizeof (struct line));
}
sortlines (lines.lines, lines.used, tmp);
- if (feof (fp) && !nfiles && !n_temp_files && !buf.left)
+ if (feof (fp) && !nfiles && !ntemp && !buf.left)
tfp = ofp;
else
{
- ++n_temp_files;
- tfp = xtmpfopen (tempname ());
+ ++ntemp;
+ tfp = xfopen (tempname (), "w");
}
for (i = 0; i < lines.used; ++i)
if (!unique || i == 0
@@ -1555,13 +1343,13 @@ sort (char **files, int nfiles, FILE *ofp)
free ((char *) lines.lines);
free ((char *) tmp);
- if (n_temp_files)
+ if (ntemp)
{
- tempfiles = (char **) xmalloc (n_temp_files * sizeof (char *));
- i = n_temp_files;
+ tempfiles = (char **) xmalloc (ntemp * sizeof (char *));
+ i = ntemp;
for (node = temphead.next; i > 0; node = node->next)
tempfiles[--i] = node->name;
- merge (tempfiles, n_temp_files, ofp);
+ merge (tempfiles, ntemp, ofp);
free ((char *) tempfiles);
}
}
@@ -1569,7 +1357,8 @@ sort (char **files, int nfiles, FILE *ofp)
/* Insert key KEY at the end of the list (`keyhead'). */
static void
-insertkey (struct keyfield *key)
+insertkey (key)
+ struct keyfield *key;
{
struct keyfield *k = &keyhead;
@@ -1580,26 +1369,28 @@ insertkey (struct keyfield *key)
}
static void
-badfieldspec (const char *s)
+badfieldspec (s)
+ char *s;
{
- error (2, 0, _("invalid field specification `%s'"), s);
+ error (2, 0, "invalid field specification `%s'", s);
}
/* Handle interrupts and hangups. */
static void
-sighandler (int sig)
+sighandler (sig)
+ int sig;
{
-#ifdef SA_INTERRUPT
+#ifdef _POSIX_VERSION
struct sigaction sigact;
sigact.sa_handler = SIG_DFL;
sigemptyset (&sigact.sa_mask);
sigact.sa_flags = 0;
sigaction (sig, &sigact, NULL);
-#else /* !SA_INTERRUPT */
+#else /* !_POSIX_VERSION */
signal (sig, SIG_DFL);
-#endif /* SA_INTERRUPT */
+#endif /* _POSIX_VERSION */
cleanup ();
kill (getpid (), sig);
}
@@ -1610,8 +1401,10 @@ sighandler (int sig)
BLANKTYPE is the kind of blanks that 'b' should skip. */
static char *
-set_ordering (register const char *s, struct keyfield *key,
- enum blanktype blanktype)
+set_ordering (s, key, blanktype)
+ register char *s;
+ struct keyfield *key;
+ enum blanktype blanktype;
{
while (*s)
{
@@ -1629,9 +1422,11 @@ set_ordering (register const char *s, struct keyfield *key,
case 'f':
key->translate = fold_toupper;
break;
+#if 0
case 'g':
- key->general_numeric = 1;
+ /* Reserved for comparing floating-point numbers. */
break;
+#endif
case 'i':
key->ignore = nonprinting;
break;
@@ -1640,24 +1435,22 @@ set_ordering (register const char *s, struct keyfield *key,
break;
case 'n':
key->numeric = 1;
- if (blanktype == bl_start || blanktype == bl_both)
- key->skipsblanks = 1;
- if (blanktype == bl_end || blanktype == bl_both)
- key->skipeblanks = 1;
break;
case 'r':
key->reverse = 1;
break;
default:
- return (char *) s;
+ return s;
}
++s;
}
- return (char *) s;
+ return s;
}
void
-main (int argc, char **argv)
+main (argc, argv)
+ int argc;
+ char *argv[];
{
struct keyfield *key = NULL, gkey;
char *s;
@@ -1665,22 +1458,25 @@ main (int argc, char **argv)
int checkonly = 0, mergeonly = 0, nfiles = 0;
char *minus = "-", *outfile = minus, **files, *tmp;
FILE *ofp;
-#ifdef SA_INTERRUPT
+#ifdef _POSIX_VERSION
struct sigaction oldact, newact;
-#endif /* SA_INTERRUPT */
+#endif /* _POSIX_VERSION */
+#ifdef __FreeBSD__
+ (void) setlocale(LC_CTYPE, "");
+#endif
program_name = argv[0];
- parse_long_options (argc, argv, "sort", version_string, usage);
+ parse_long_options (argc, argv, usage);
have_read_stdin = 0;
inittables ();
temp_file_prefix = getenv ("TMPDIR");
if (temp_file_prefix == NULL)
- temp_file_prefix = DEFAULT_TMPDIR;
+ temp_file_prefix = "/tmp";
-#ifdef SA_INTERRUPT
+#ifdef _POSIX_VERSION
newact.sa_handler = sighandler;
sigemptyset (&newact.sa_mask);
newact.sa_flags = 0;
@@ -1697,7 +1493,7 @@ main (int argc, char **argv)
sigaction (SIGTERM, NULL, &oldact);
if (oldact.sa_handler != SIG_IGN)
sigaction (SIGTERM, &newact, NULL);
-#else /* !SA_INTERRUPT */
+#else /* !_POSIX_VERSION */
if (signal (SIGINT, SIG_IGN) != SIG_IGN)
signal (SIGINT, sighandler);
if (signal (SIGHUP, SIG_IGN) != SIG_IGN)
@@ -1706,12 +1502,12 @@ main (int argc, char **argv)
signal (SIGPIPE, sighandler);
if (signal (SIGTERM, SIG_IGN) != SIG_IGN)
signal (SIGTERM, sighandler);
-#endif /* !SA_INTERRUPT */
+#endif /* !_POSIX_VERSION */
gkey.sword = gkey.eword = -1;
gkey.ignore = NULL;
gkey.translate = NULL;
- gkey.numeric = gkey.general_numeric = gkey.month = gkey.reverse = 0;
+ gkey.numeric = gkey.month = gkey.reverse = 0;
gkey.skipsblanks = gkey.skipeblanks = 0;
files = (char **) xmalloc (sizeof (char *) * argc);
@@ -1727,9 +1523,9 @@ main (int argc, char **argv)
key->ignore = NULL;
key->translate = NULL;
key->skipsblanks = key->skipeblanks = 0;
- key->numeric = key->general_numeric = key->month = key->reverse = 0;
+ key->numeric = key->month = key->reverse = 0;
s = argv[i] + 1;
- if (! (digits[UCHAR (*s)] || (*s == '.' && digits[UCHAR (s[1])])))
+ if (!digits[UCHAR (*s)])
badfieldspec (argv[i]);
for (t = 0; digits[UCHAR (*s)]; ++s)
t = 10 * t + *s - '0';
@@ -1751,7 +1547,7 @@ main (int argc, char **argv)
else if (argv[i][0] == '-' && argv[i][1])
{
s = argv[i] + 1;
- if (digits[UCHAR (*s)] || (*s == '.' && digits[UCHAR (s[1])]))
+ if (digits[UCHAR (*s)])
{
if (!key)
usage (2);
@@ -1786,7 +1582,7 @@ main (int argc, char **argv)
else
{
if (i == argc - 1)
- error (2, 0, _("option `-k' requires an argument"));
+ error (2, 0, "option `-k' requires an argument");
else
s = argv[++i];
}
@@ -1804,34 +1600,15 @@ main (int argc, char **argv)
badfieldspec (argv[i]);
for (t = 0; digits[UCHAR (*s)]; ++s)
t = 10 * t + *s - '0';
- if (t == 0)
- {
- /* Provoke with `sort -k0' */
- error (0, 0, _("the starting field number argument \
-to the `-k' option must be positive"));
- badfieldspec (argv[i]);
- }
- --t;
+ if (t)
+ t--;
t2 = 0;
if (*s == '.')
{
- if (!digits[UCHAR (s[1])])
- {
- /* Provoke with `sort -k1.' */
- error (0, 0, _("starting field spec has `.' but \
-lacks following character offset"));
- badfieldspec (argv[i]);
- }
for (++s; digits[UCHAR (*s)]; ++s)
t2 = 10 * t2 + *s - '0';
- if (t2 == 0)
- {
- /* Provoke with `sort -k1.0' */
- error (0, 0, _("starting field character offset \
-argument to the `-k' option\nmust be positive"));
- badfieldspec (argv[i]);
- }
- --t2;
+ if (t2)
+ t2--;
}
if (t2 || t)
{
@@ -1841,52 +1618,20 @@ argument to the `-k' option\nmust be positive"));
else
key->sword = -1;
s = set_ordering (s, key, bl_start);
- if (*s == 0)
- {
- key->eword = -1;
- key->echar = 0;
- }
- else if (*s != ',')
+ if (*s && *s != ',')
badfieldspec (argv[i]);
- else if (*s == ',')
+ else if (*s++)
{
- /* Skip over comma. */
- ++s;
- if (*s == 0)
- {
- /* Provoke with `sort -k1,' */
- error (0, 0, _("field specification has `,' but \
-lacks following field spec"));
- badfieldspec (argv[i]);
- }
/* Get POS2. */
for (t = 0; digits[UCHAR (*s)]; ++s)
t = t * 10 + *s - '0';
- if (t == 0)
- {
- /* Provoke with `sort -k1,0' */
- error (0, 0, _("ending field number argument \
-to the `-k' option must be positive"));
- badfieldspec (argv[i]);
- }
- --t;
t2 = 0;
if (*s == '.')
{
- if (!digits[UCHAR (s[1])])
- {
- /* Provoke with `sort -k1,1.' */
- error (0, 0, _("ending field spec has `.' \
-but lacks following character offset"));
- badfieldspec (argv[i]);
- }
for (++s; digits[UCHAR (*s)]; ++s)
t2 = t2 * 10 + *s - '0';
- }
- else
- {
- /* `-k 2,3' is equivalent to `+1 -3'. */
- ++t;
+ if (t2)
+ t--;
}
key->eword = t;
key->echar = t2;
@@ -1906,7 +1651,7 @@ but lacks following character offset"));
else
{
if (i == argc - 1)
- error (2, 0, _("option `-o' requires an argument"));
+ error (2, 0, "option `-o' requires an argument");
else
outfile = argv[++i];
}
@@ -1923,20 +1668,19 @@ but lacks following character offset"));
goto outer;
}
else
- error (2, 0, _("option `-t' requires an argument"));
+ error (2, 0, "option `-t' requires an argument");
break;
case 'T':
if (s[1])
temp_file_prefix = ++s;
- else
+ else if (i < argc - 1)
{
- if (i < argc - 1)
- temp_file_prefix = argv[++i];
- else
- error (2, 0, _("option `-T' requires an argument"));
+ temp_file_prefix = argv[++i];
+ goto outer;
}
- goto outer;
- /* break; */
+ else
+ error (2, 0, "option `-T' requires an argument");
+ break;
case 'u':
unique = 1;
break;
@@ -1945,7 +1689,7 @@ but lacks following character offset"));
Solaris 2. */
goto outer;
default:
- fprintf (stderr, _("%s: unrecognized option `-%c'\n"),
+ fprintf (stderr, "%s: unrecognized option `-%c'\n",
argv[0], *s);
usage (2);
}
@@ -1966,8 +1710,7 @@ but lacks following character offset"));
/* Inheritance of global options to individual keys. */
for (key = keyhead.next; key; key = key->next)
if (!key->ignore && !key->translate && !key->skipsblanks && !key->reverse
- && !key->skipeblanks && !key->month && !key->numeric
- && !key->general_numeric)
+ && !key->skipeblanks && !key->month && !key->numeric)
{
key->ignore = gkey.ignore;
key->translate = gkey.translate;
@@ -1975,13 +1718,11 @@ but lacks following character offset"));
key->skipeblanks = gkey.skipeblanks;
key->month = gkey.month;
key->numeric = gkey.numeric;
- key->general_numeric = gkey.general_numeric;
key->reverse = gkey.reverse;
}
if (!keyhead.next && (gkey.ignore || gkey.translate || gkey.skipsblanks
- || gkey.skipeblanks || gkey.month || gkey.numeric
- || gkey.general_numeric))
+ || gkey.skipeblanks || gkey.month || gkey.numeric))
insertkey (&gkey);
reverse = gkey.reverse;
@@ -1996,61 +1737,32 @@ but lacks following character offset"));
if (strcmp (outfile, "-"))
{
- struct stat outstat;
- if (stat (outfile, &outstat) == 0)
+ for (i = 0; i < nfiles; ++i)
+ if (!strcmp (outfile, files[i]))
+ break;
+ if (i == nfiles)
+ ofp = xfopen (outfile, "w");
+ else
{
- /* The following code prevents a race condition when
- people use the brain dead shell programming idiom:
- cat file | sort -o file
- This feature is provided for historical compatibility,
- but we strongly discourage ever relying on this in
- new shell programs. */
-
- /* Temporarily copy each input file that might be another name
- for the output file. When in doubt (e.g. a pipe), copy. */
- for (i = 0; i < nfiles; ++i)
+ char buf[8192];
+ FILE *fp = xfopen (outfile, "r");
+ int cc;
+
+ tmp = tempname ();
+ ofp = xfopen (tmp, "w");
+ while ((cc = fread (buf, 1, sizeof buf, fp)) > 0)
+ xfwrite (buf, 1, cc, ofp);
+ if (ferror (fp))
{
- char buf[8192];
- FILE *fp;
- int cc;
-
- if (S_ISREG (outstat.st_mode) && strcmp (outfile, files[i]))
- {
- struct stat instat;
- if ((strcmp (files[i], "-")
- ? stat (files[i], &instat)
- : fstat (fileno (stdin), &instat)) != 0)
- {
- error (0, errno, "%s", files[i]);
- cleanup ();
- exit (2);
- }
- if (S_ISREG (instat.st_mode)
- && (instat.st_ino != outstat.st_ino
- || instat.st_dev != outstat.st_dev))
- {
- /* We know the files are distinct. */
- continue;
- }
- }
-
- fp = xfopen (files[i], "r");
- tmp = tempname ();
- ofp = xtmpfopen (tmp);
- while ((cc = fread (buf, 1, sizeof buf, fp)) > 0)
- xfwrite (buf, 1, cc, ofp);
- if (ferror (fp))
- {
- error (0, errno, "%s", files[i]);
- cleanup ();
- exit (2);
- }
- xfclose (ofp);
- xfclose (fp);
- files[i] = tmp;
+ error (0, errno, "%s", outfile);
+ cleanup ();
+ exit (2);
}
+ xfclose (ofp);
+ xfclose (fp);
+ files[i] = tmp;
+ ofp = xfopen (outfile, "w");
}
- ofp = xfopen (outfile, "w");
}
else
ofp = stdout;
@@ -2067,12 +1779,57 @@ but lacks following character offset"));
Solaris, Ultrix, and Irix. This premature fflush makes the output
reappear. --karl@cs.umb.edu */
if (fflush (ofp) < 0)
- error (1, errno, _("%s: write error"), outfile);
+ error (1, errno, "fflush", outfile);
if (have_read_stdin && fclose (stdin) == EOF)
- error (1, errno, outfile);
+ error (1, errno, "-");
if (ferror (stdout) || fclose (stdout) == EOF)
- error (1, errno, _("%s: write error"), outfile);
+ error (1, errno, "write error");
exit (0);
}
+
+static void
+usage (status)
+ int status;
+{
+ if (status != 0)
+ fprintf (stderr, "Try `%s --help' for more information.\n",
+ program_name);
+ else
+ {
+ printf ("\
+Usage: %s [OPTION]... [FILE]...\n\
+",
+ program_name);
+ printf ("\
+\n\
+ +POS1 [-POS2] start a key at POS1, end it before POS2\n\
+ -M compare (unknown) < `JAN' < ... < `DEC', imply -b\n\
+ -T DIRECT use DIRECTfor temporary files, not $TEMPDIR nor /tmp\n\
+ -b ignore leading blanks in sort fields or keys\n\
+ -c check if given files already sorted, do not sort\n\
+ -d consider only [a-zA-Z0-9 ] characters in keys\n\
+ -f fold lower case to upper case characters in keys\n\
+ -i consider only [\\040-\\0176] characters in keys\n\
+ -k POS1[,POS2] same as +POS1 [-POS2], but all positions counted from 1\n\
+ -m merge already sorted files, do not sort\n\
+ -n compare according to string numerical value, imply -b\n\
+ -o FILE write result on FILE instead of standard output\n\
+ -r reverse the result of comparisons\n\
+ -s stabilize sort by disabling last resort comparison\n\
+ -t SEP use SEParator instead of non- to whitespace transition\n\
+ -u with -c, check for strict ordering\n\
+ -u with -m, only output the first of an equal sequence\n\
+ --help display this help and exit\n\
+ --version output version information and exit\n\
+\n\
+POS is F[.C][OPTS], where F is the field number and C the character\n\
+position in the field, both counted from zero. OPTS is made up of one\n\
+or more of Mbdfinr, this effectively disable global -Mbdfinr settings\n\
+for that key. If no key given, use the entire line as key. With no\n\
+FILE, or when FILE is -, read standard input.\n\
+");
+ }
+ exit (status);
+}
diff --git a/gnu/usr.bin/sort/system.h b/gnu/usr.bin/sort/system.h
index bfb19e1..4e2ec1e 100644
--- a/gnu/usr.bin/sort/system.h
+++ b/gnu/usr.bin/sort/system.h
@@ -13,25 +13,48 @@
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
/* Include sys/types.h before this file. */
#include <sys/stat.h>
-#ifdef STAT_MACROS_BROKEN
+#ifdef STAT_MACROS_BROKEN
+#ifdef S_ISBLK
#undef S_ISBLK
+#endif
+#ifdef S_ISCHR
#undef S_ISCHR
+#endif
+#ifdef S_ISDIR
#undef S_ISDIR
+#endif
+#ifdef S_ISFIFO
#undef S_ISFIFO
+#endif
+#ifdef S_ISLNK
#undef S_ISLNK
+#endif
+#ifdef S_ISMPB
#undef S_ISMPB
+#endif
+#ifdef S_ISMPC
#undef S_ISMPC
+#endif
+#ifdef S_ISNWK
#undef S_ISNWK
+#endif
+#ifdef S_ISREG
#undef S_ISREG
+#endif
+#ifdef S_ISSOCK
#undef S_ISSOCK
-#endif /* STAT_MACROS_BROKEN. */
+#endif
+#endif /* STAT_MACROS_BROKEN. */
+#ifndef S_ISREG /* Doesn't have POSIX.1 stat stuff. */
+#define mode_t unsigned short
+#endif
#if !defined(S_ISBLK) && defined(S_IFBLK)
#define S_ISBLK(m) (((m) & S_IFMT) == S_IFBLK)
#endif
@@ -67,56 +90,42 @@
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
-
#ifndef _POSIX_VERSION
off_t lseek ();
#endif
-#ifndef STDIN_FILENO
-#define STDIN_FILENO 0
+#if defined(HAVE_STRING_H) || defined(STDC_HEADERS)
+#if !defined(STDC_HEADERS) && defined(HAVE_MEMORY_H)
+#include <memory.h>
#endif
-
-#ifndef STDOUT_FILENO
-#define STDOUT_FILENO 1
+#include <string.h>
+#ifndef index
+#define index strchr
#endif
-
-#ifndef STDERR_FILENO
-#define STDERR_FILENO 2
+#ifndef rindex
+#define rindex strrchr
+#endif
+/* Don't define bcopy; we need one that can handle overlaps. */
+#ifndef bzero
+#define bzero(s, n) memset ((s), 0, (n))
+#endif
+#ifndef bcmp
+#define bcmp(s1, s2, n) memcmp ((s1), (s2), (n))
#endif
-
-/* Don't use bcopy! Use memmove if source and destination may overlap,
- memcpy otherwise. */
-
-#ifdef HAVE_STRING_H
-# if !STDC_HEADERS && HAVE_MEMORY_H
-# include <memory.h>
-# endif
-# include <string.h>
#else
-# include <strings.h>
+#include <strings.h>
char *memchr ();
#endif
#include <errno.h>
-#ifndef errno
-extern int errno;
-#endif
-
#ifdef STDC_HEADERS
#include <stdlib.h>
#else
char *getenv ();
+extern int errno;
#endif
-#ifndef EXIT_FAILURE
-# define EXIT_FAILURE 1
-#endif
-
-#ifndef EXIT_SUCCESS
-# define EXIT_SUCCESS 0
-#endif
-
-#ifdef HAVE_FCNTL_H
+#if defined(HAVE_FCNTL_H) || defined(_POSIX_VERSION)
#include <fcntl.h>
#else
#include <sys/file.h>
@@ -164,10 +173,10 @@ char *getenv ();
#include <ctype.h>
-#if defined (STDC_HEADERS) || (!defined (isascii) && !defined (HAVE_ISASCII))
+#if !defined(isascii) || defined(__FreeBSD__)
#define ISASCII(c) 1
#else
-#define ISASCII(c) isascii(c)
+#define ISASCII(c) isascii (c)
#endif
#ifdef isblank
@@ -191,15 +200,3 @@ char *getenv ();
#define ISSPACE(c) (ISASCII (c) && isspace (c))
#define ISUPPER(c) (ISASCII (c) && isupper (c))
#define ISXDIGIT(c) (ISASCII (c) && isxdigit (c))
-
-/* Disable string localization for the time being. */
-#undef _
-#define _(String) String
-
-#ifndef __P
-# if PROTOTYPES
-# define __P(Args) Args
-# else
-# define __P(Args) ()
-# endif
-#endif
diff --git a/gnu/usr.bin/sort/version.c b/gnu/usr.bin/sort/version.c
index 0289fcb..64c62b19 100644
--- a/gnu/usr.bin/sort/version.c
+++ b/gnu/usr.bin/sort/version.c
@@ -1,3 +1,13 @@
+#ifdef HAVE_CONFIG_H
+#if defined (CONFIG_BROKETS)
+/* We use <config.h> instead of "config.h" so that a compilation
+ using -I. -I$srcdir will use ./config.h rather than $srcdir/config.h
+ (which it would do because it found this file in $srcdir). */
#include <config.h>
+#else
+#include "config.h"
+#endif
+#endif
+
#include "version.h"
-const char *version_string = "GNU textutils 1.14";
+const char *version_string = "GNU textutils 1.9";
diff --git a/gnu/usr.bin/tar/Makefile b/gnu/usr.bin/tar/Makefile
index 810fe3b..c9c76bf 100644
--- a/gnu/usr.bin/tar/Makefile
+++ b/gnu/usr.bin/tar/Makefile
@@ -1,14 +1,17 @@
PROG= tar
SRCS= buffer.c create.c diffarch.c extract.c fnmatch.c getdate.y \
getoldopt.c getopt.c getopt1.c gnu.c list.c mangle.c names.c port.c \
- regex.c rtapelib.c tar.c update.c version.c
+ rtapelib.c tar.c update.c version.c
CFLAGS+= -DRETSIGTYPE=void -DDIRENT=1 -DHAVE_SYS_MTIO_H=1 -DHAVE_UNISTD_H=1
CFLAGS+= -DHAVE_GETGRGID=1 -DHAVE_GETPWUID=1 -DHAVE_STRING_H=1
CFLAGS+= -DHAVE_LIMITS_H=1 -DHAVE_STRSTR=1 -DHAVE_VALLOC=1 -DHAVE_MKDIR=1
CFLAGS+= -DHAVE_MKNOD=1 -DHAVE_RENAME=1 -DHAVE_FTRUNCATE=1 -DHAVE_GETCWD=1
-CFLAGS+= -DHAVE_VPRINTF=1 -DNEEDPAD -I${.CURDIR}
+CFLAGS+= -DBSD42=1 -DHAVE_VPRINTF=1 -DNEEDPAD -I${.CURDIR}
CFLAGS+= -DDEF_AR_FILE=\"/dev/rst0\" -DDEFBLOCKING=20
-NOMAN=noman
+CLEANFILES+=y.tab.h
+NOSHARED=yes
+
+DPADD+= ${LIBGNUREGEX}
+LDADD+= -lgnuregex
.include <bsd.prog.mk>
-.include "../../usr.bin/Makefile.inc"
diff --git a/gnu/usr.bin/tar/Makefile.gnu b/gnu/usr.bin/tar/Makefile.gnu
index a03617a..f43f8ed 100644
--- a/gnu/usr.bin/tar/Makefile.gnu
+++ b/gnu/usr.bin/tar/Makefile.gnu
@@ -73,7 +73,7 @@ DEFS = -DRETSIGTYPE=void -DDIRENT=1 -DHAVE_SYS_MTIO_H=1 -DHAVE_UNISTD_H=1 -DHAV
# Set this to rtapelib.o unless you defined NO_REMOTE, in which case
# make it empty.
RTAPELIB = rtapelib.o
-LIBS =
+LIBS =
CFLAGS = -g
LDFLAGS = -g
@@ -82,7 +82,7 @@ prefix = /usr/bin
exec_prefix = $(prefix)
# Prefix for each installed program, normally empty or `g'.
-binprefix =
+binprefix =
# The directory to install tar in.
bindir = $(exec_prefix)/bin
@@ -102,8 +102,8 @@ SRC2 = version.c list.c names.c diffarch.c port.c fnmatch.c getopt.c malloc.c
SRC3 = getopt1.c regex.c getdate.y getdate.c alloca.c
SRCS = $(SRC1) $(SRC2) $(SRC3)
OBJ1 = tar.o create.o extract.o buffer.o getoldopt.o update.o gnu.o mangle.o
-OBJ2 = version.o list.o names.o diffarch.o port.o fnmatch.o getopt.o
-OBJ3 = getopt1.o regex.o getdate.o $(RTAPELIB)
+OBJ2 = version.o list.o names.o diffarch.o port.o fnmatch.o getopt.o
+OBJ3 = getopt1.o regex.o getdate.o $(RTAPELIB)
OBJS = $(OBJ1) $(OBJ2) $(OBJ3)
AUX = README INSTALL NEWS COPYING ChangeLog Makefile.in makefile.pc \
configure configure.in \
@@ -113,7 +113,7 @@ AUX = README INSTALL NEWS COPYING ChangeLog Makefile.in makefile.pc \
level-0 level-1 backup-specs dump-remind getpagesize.h
# tar.texinfo tar.info* texinfo.tex \
-all: tar rmt
+all: tar rmt
# tar.info
.c.o:
diff --git a/gnu/usr.bin/tar/buffer.c b/gnu/usr.bin/tar/buffer.c
index e0ffc2d..eb7e3ef 100644
--- a/gnu/usr.bin/tar/buffer.c
+++ b/gnu/usr.bin/tar/buffer.c
@@ -57,7 +57,7 @@ time_t time ();
#include "tar.h"
#include "port.h"
#include "rmt.h"
-#include "regex.h"
+#include "gnuregex.h"
/* Either stdout or stderr: The thing we write messages (standard msgs, not
errors) to. Stdout unless we're writing a pipe, in which case stderr */
diff --git a/gnu/usr.bin/tar/create.c b/gnu/usr.bin/tar/create.c
index 62b9c51..c3be00c 100644
--- a/gnu/usr.bin/tar/create.c
+++ b/gnu/usr.bin/tar/create.c
@@ -544,7 +544,7 @@ dump_file (p, curdev, toplevel)
}
if (save_linkflag == LF_SPARSE)
{
- if (finish_sparse_file (f, &sizeleft, hstat.st_size, p))
+ if (finish_sparse_file (f, &sizeleft, (long) hstat.st_size, p))
goto padit;
}
else
@@ -574,7 +574,7 @@ dump_file (p, curdev, toplevel)
if (count < 0)
{
msg_perror ("read error at byte %ld, reading\
- %d bytes, in file %s", hstat.st_size - sizeleft, bufsize, p);
+ %d bytes, in file %s", (long) hstat.st_size - sizeleft, bufsize, p);
goto padit;
}
sizeleft -= count;
@@ -875,10 +875,20 @@ dump_file (p, curdev, toplevel)
#if defined(S_IFBLK) || defined(S_IFCHR)
if (type != LF_FIFO)
{
- to_oct ((long) major (hstat.st_rdev), 8,
- header->header.devmajor);
- to_oct ((long) minor (hstat.st_rdev), 8,
- header->header.devminor);
+ if (checked_to_oct ((long) major (hstat.st_rdev), 8,
+ header->header.devmajor))
+ {
+ msg ("%s: major number too large; not dumped", p);
+ critical_error = 1;
+ goto badfile;
+ }
+ if (checked_to_oct ((long) minor (hstat.st_rdev), 8,
+ header->header.devminor))
+ {
+ msg ("%s: minor number too large; not dumped", p);
+ critical_error = 1;
+ goto badfile;
+ }
}
#endif
@@ -1397,6 +1407,22 @@ to_oct (value, digs, where)
/*
+ * Call to_oct (), then return nonzero iff the conversion failed.
+ */
+int
+checked_to_oct (value, digs, where)
+ register long value;
+ register int digs;
+ register char *where;
+{
+ long from_oct ();
+
+ to_oct (value, digs, where);
+ return from_oct (digs, where) != value;
+}
+
+
+/*
* Write the EOT record(s).
* We actually zero at least one record, through the end of the block.
* Old tar writes garbage after two zeroed records -- and PDtar used to.
diff --git a/gnu/usr.bin/tar/extract.c b/gnu/usr.bin/tar/extract.c
index d162cab..4b09fad 100644
--- a/gnu/usr.bin/tar/extract.c
+++ b/gnu/usr.bin/tar/extract.c
@@ -310,6 +310,14 @@ extract_archive ()
fd = 1;
goto extract_file;
}
+
+ if (f_unlink && !f_keep) {
+ if (unlink(skipcrud + current_file_name) == -1)
+ if (errno != ENOENT)
+ msg_perror ("Could not unlink %s",
+ skipcrud + current_file_name);
+ }
+
#ifdef O_CTG
/*
* Contiguous files (on the Masscomp) have to specify
@@ -556,6 +564,13 @@ extract_archive ()
{
struct stat st1, st2;
+ if (f_unlink && !f_keep) {
+ if (unlink(skipcrud + current_file_name) == -1)
+ if (errno != ENOENT)
+ msg_perror ("Could not unlink %s",
+ skipcrud + current_file_name);
+ }
+
check = link (current_link_name, skipcrud + current_file_name);
if (check == 0)
@@ -578,6 +593,13 @@ extract_archive ()
#ifdef S_ISLNK
case LF_SYMLINK:
again_symlink:
+ if (f_unlink && !f_keep) {
+ if (unlink(skipcrud + current_file_name) == -1)
+ if (errno != ENOENT)
+ msg_perror ("Could not unlink %s",
+ skipcrud + current_file_name);
+ }
+
check = symlink (current_link_name,
skipcrud + current_file_name);
/* FIXME, don't worry uid, gid, etc... */
@@ -602,6 +624,13 @@ extract_archive ()
#endif
#if defined(S_IFCHR) || defined(S_IFBLK)
make_node:
+ if (f_unlink && !f_keep) {
+ if (unlink(skipcrud + current_file_name) == -1)
+ if (errno != ENOENT)
+ msg_perror ("Could not unlink %s",
+ skipcrud + current_file_name);
+ }
+
check = mknod (current_file_name + skipcrud,
(int) hstat.st_mode, (int) hstat.st_rdev);
if (check != 0)
@@ -619,6 +648,13 @@ extract_archive ()
/* If local system doesn't support FIFOs, use default case */
case LF_FIFO:
make_fifo:
+ if (f_unlink && !f_keep) {
+ if (unlink(skipcrud + current_file_name) == -1)
+ if (errno != ENOENT)
+ msg_perror ("Could not unlink %s",
+ skipcrud + current_file_name);
+ }
+
check = mkfifo (current_file_name + skipcrud,
(int) hstat.st_mode);
if (check != 0)
@@ -699,9 +735,9 @@ extract_archive ()
if (!f_modified)
{
- tmp = ((struct saved_dir_info *)
+ tmp = ((struct saved_dir_info *)
ck_malloc (sizeof (struct saved_dir_info)));
- tmp->path = (char *) ck_malloc (strlen (skipcrud
+ tmp->path = (char *) ck_malloc (strlen (skipcrud
+ current_file_name) + 1);
strcpy (tmp->path, skipcrud + current_file_name);
tmp->mode = hstat.st_mode;
@@ -853,7 +889,7 @@ extract_sparse_file (fd, sizeleft, totalsize, name)
}
else if (count != written)
{
- msg ("could only write %d of %d bytes to file %s", count,
+ msg ("could only write %d of %d bytes to file %s", count,
totalsize, name);
skip_file ((long) (*sizeleft));
}
@@ -874,7 +910,7 @@ extract_sparse_file (fd, sizeleft, totalsize, name)
}
/* Set back the utime and mode for all the extracted directories. */
-void
+void
restore_saved_dir_info ()
{
struct utimbuf acc_upd_times;
diff --git a/gnu/usr.bin/tar/getdate.y b/gnu/usr.bin/tar/getdate.y
index 7b0ac79..aa8f6b5 100644
--- a/gnu/usr.bin/tar/getdate.y
+++ b/gnu/usr.bin/tar/getdate.y
@@ -1,5 +1,5 @@
%{
-/* $Revision: 2.1 $
+/* $Revision: 1.1.1.1 $
**
** Originally written by Steven M. Bellovin <smb@research.att.com> while
** at the University of North Carolina at Chapel Hill. Later tweaked by
@@ -40,7 +40,7 @@ char *alloca ();
tricks are need, but defaults to using the gettimeofday system call.
Include <sys/time.h> if that will be used. */
-#if !defined (USG) && !defined (sgi) && !defined (__386BSD__)
+#if !defined (USG) && !defined (sgi) && !defined (__FreeBSD__)
#include <sys/time.h>
#endif
@@ -98,7 +98,7 @@ extern struct tm *localtime();
#if !defined(lint) && !defined(SABER)
static char RCS[] =
- "$Header: str2date.y,v 2.1 90/09/06 08:15:06 cronan Exp $";
+ "$Header: /home/ncvs/src/gnu/usr.bin/tar/getdate.y,v 1.1.1.1 1993/06/18 04:22:21 jkh Exp $";
#endif /* !defined(lint) && !defined(SABER) */
@@ -872,7 +872,7 @@ get_date(p, now)
#if sgi
ftz.timezone = (int) _timezone / 60;
#else /* not sgi */
-#ifdef __386BSD__
+#ifdef __FreeBSD__
ftz.timezone = 0;
#else /* neither sgi nor 386BSD */
#if defined (USG)
diff --git a/gnu/usr.bin/tar/getopt.c b/gnu/usr.bin/tar/getopt.c
index 3db9abf..6b8e3f2 100644
--- a/gnu/usr.bin/tar/getopt.c
+++ b/gnu/usr.bin/tar/getopt.c
@@ -10,12 +10,12 @@
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 2, or (at your option) any
later version.
-
+
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
-
+
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
diff --git a/gnu/usr.bin/tar/getopt.h b/gnu/usr.bin/tar/getopt.h
index 93a5cf7..f977e15 100644
--- a/gnu/usr.bin/tar/getopt.h
+++ b/gnu/usr.bin/tar/getopt.h
@@ -5,12 +5,12 @@
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 2, or (at your option) any
later version.
-
+
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
-
+
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
diff --git a/gnu/usr.bin/tar/getopt1.c b/gnu/usr.bin/tar/getopt1.c
index c3582cf..b2b23f2 100644
--- a/gnu/usr.bin/tar/getopt1.c
+++ b/gnu/usr.bin/tar/getopt1.c
@@ -5,12 +5,12 @@
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 2, or (at your option) any
later version.
-
+
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
-
+
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
@@ -55,7 +55,7 @@ getopt_long (argc, argv, options, long_options, opt_index)
but does match a short option, it is parsed as a short option
instead. */
-int
+int
getopt_long_only (argc, argv, options, long_options, opt_index)
int argc;
char *const *argv;
diff --git a/gnu/usr.bin/tar/list.c b/gnu/usr.bin/tar/list.c
index a0c65a3..28e6ab3 100644
--- a/gnu/usr.bin/tar/list.c
+++ b/gnu/usr.bin/tar/list.c
@@ -95,6 +95,11 @@ read_and (do_something)
{
prev_status = status;
status = read_header ();
+ /* check if the namelist got emptied during the course of reading */
+ /* the tape, if so stop by setting status to EOF */
+ if ((namelist == NULL) && nlpsfreed) {
+ status = EOF;
+ }
switch (status)
{
@@ -323,7 +328,7 @@ recurse:
recsum = from_oct (8, header->header.chksum);
- sum = 0;
+ signed_sum = sum = 0;
p = header->charptr;
for (i = sizeof (*header); --i >= 0;)
{
@@ -553,11 +558,11 @@ void
print_header ()
{
char modes[11];
- char *timestamp;
+ char timestamp[80];
char uform[11], gform[11]; /* These hold formatted ints */
char *user, *group;
char size[24]; /* Holds a formatted long or maj, min */
- time_t longie; /* To make ctime() call portable */
+ time_t longie;
int pad;
char *name;
extern long baserec;
@@ -636,7 +641,7 @@ print_header ()
/* Timestamp */
longie = hstat.st_mtime;
- timestamp = ctime (&longie);
+ strftime(timestamp, sizeof(timestamp), "%c", localtime(&longie));
timestamp[16] = '\0';
timestamp[24] = '\0';
diff --git a/gnu/usr.bin/tar/port.c b/gnu/usr.bin/tar/port.c
index 10ec32e..9a40dc3 100644
--- a/gnu/usr.bin/tar/port.c
+++ b/gnu/usr.bin/tar/port.c
@@ -1002,7 +1002,7 @@ un_quote_string (string)
}
#ifndef __MSDOS__
-void
+void
ck_pipe (pipes)
int *pipes;
{
@@ -1223,7 +1223,7 @@ msg_perror (str, args)
#endif /* !HAVE_VPRINTF and HAVE_DOPRNT */
#if !defined(HAVE_VPRINTF) && !defined(HAVE_DOPRNT)
-void
+void
msg (str, a1, a2, a3, a4, a5, a6)
char *str;
{
diff --git a/gnu/usr.bin/tar/regex.c b/gnu/usr.bin/tar/regex.c
deleted file mode 100644
index cb94d59..0000000
--- a/gnu/usr.bin/tar/regex.c
+++ /dev/null
@@ -1,4932 +0,0 @@
-/* Extended regular expression matching and search library,
- version 0.11.
- (Implements POSIX draft P10003.2/D11.2, except for
- internationalization features.)
-
- Copyright (C) 1993 Free Software Foundation, Inc.
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2, or (at your option)
- any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
-
-/* AIX requires this to be the first thing in the file. */
-#if defined (_AIX) && !defined (REGEX_MALLOC)
- #pragma alloca
-#endif
-
-#define _GNU_SOURCE
-
-/* We need this for `regex.h', and perhaps for the Emacs include files. */
-#include <sys/types.h>
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-/* The `emacs' switch turns on certain matching commands
- that make sense only in Emacs. */
-#ifdef emacs
-
-#include "lisp.h"
-#include "buffer.h"
-#include "syntax.h"
-
-/* Emacs uses `NULL' as a predicate. */
-#undef NULL
-
-#else /* not emacs */
-
-/* We used to test for `BSTRING' here, but only GCC and Emacs define
- `BSTRING', as far as I know, and neither of them use this code. */
-#if HAVE_STRING_H || STDC_HEADERS
-#include <string.h>
-#ifndef bcmp
-#define bcmp(s1, s2, n) memcmp ((s1), (s2), (n))
-#endif
-#ifndef bcopy
-#define bcopy(s, d, n) memcpy ((d), (s), (n))
-#endif
-#ifndef bzero
-#define bzero(s, n) memset ((s), 0, (n))
-#endif
-#else
-#include <strings.h>
-#endif
-
-#ifdef STDC_HEADERS
-#include <stdlib.h>
-#else
-char *malloc ();
-char *realloc ();
-#endif
-
-
-/* Define the syntax stuff for \<, \>, etc. */
-
-/* This must be nonzero for the wordchar and notwordchar pattern
- commands in re_match_2. */
-#ifndef Sword
-#define Sword 1
-#endif
-
-#ifdef SYNTAX_TABLE
-
-extern char *re_syntax_table;
-
-#else /* not SYNTAX_TABLE */
-
-/* How many characters in the character set. */
-#define CHAR_SET_SIZE 256
-
-static char re_syntax_table[CHAR_SET_SIZE];
-
-static void
-init_syntax_once ()
-{
- register int c;
- static int done = 0;
-
- if (done)
- return;
-
- bzero (re_syntax_table, sizeof re_syntax_table);
-
- for (c = 'a'; c <= 'z'; c++)
- re_syntax_table[c] = Sword;
-
- for (c = 'A'; c <= 'Z'; c++)
- re_syntax_table[c] = Sword;
-
- for (c = '0'; c <= '9'; c++)
- re_syntax_table[c] = Sword;
-
- re_syntax_table['_'] = Sword;
-
- done = 1;
-}
-
-#endif /* not SYNTAX_TABLE */
-
-#define SYNTAX(c) re_syntax_table[c]
-
-#endif /* not emacs */
-
-/* Get the interface, including the syntax bits. */
-#include "regex.h"
-
-/* isalpha etc. are used for the character classes. */
-#include <ctype.h>
-
-#ifndef isascii
-#define isascii(c) 1
-#endif
-
-#ifdef isblank
-#define ISBLANK(c) (isascii (c) && isblank (c))
-#else
-#define ISBLANK(c) ((c) == ' ' || (c) == '\t')
-#endif
-#ifdef isgraph
-#define ISGRAPH(c) (isascii (c) && isgraph (c))
-#else
-#define ISGRAPH(c) (isascii (c) && isprint (c) && !isspace (c))
-#endif
-
-#define ISPRINT(c) (isascii (c) && isprint (c))
-#define ISDIGIT(c) (isascii (c) && isdigit (c))
-#define ISALNUM(c) (isascii (c) && isalnum (c))
-#define ISALPHA(c) (isascii (c) && isalpha (c))
-#define ISCNTRL(c) (isascii (c) && iscntrl (c))
-#define ISLOWER(c) (isascii (c) && islower (c))
-#define ISPUNCT(c) (isascii (c) && ispunct (c))
-#define ISSPACE(c) (isascii (c) && isspace (c))
-#define ISUPPER(c) (isascii (c) && isupper (c))
-#define ISXDIGIT(c) (isascii (c) && isxdigit (c))
-
-#ifndef NULL
-#define NULL 0
-#endif
-
-/* We remove any previous definition of `SIGN_EXTEND_CHAR',
- since ours (we hope) works properly with all combinations of
- machines, compilers, `char' and `unsigned char' argument types.
- (Per Bothner suggested the basic approach.) */
-#undef SIGN_EXTEND_CHAR
-#if __STDC__
-#define SIGN_EXTEND_CHAR(c) ((signed char) (c))
-#else /* not __STDC__ */
-/* As in Harbison and Steele. */
-#define SIGN_EXTEND_CHAR(c) ((((unsigned char) (c)) ^ 128) - 128)
-#endif
-
-/* Should we use malloc or alloca? If REGEX_MALLOC is not defined, we
- use `alloca' instead of `malloc'. This is because using malloc in
- re_search* or re_match* could cause memory leaks when C-g is used in
- Emacs; also, malloc is slower and causes storage fragmentation. On
- the other hand, malloc is more portable, and easier to debug.
-
- Because we sometimes use alloca, some routines have to be macros,
- not functions -- `alloca'-allocated space disappears at the end of the
- function it is called in. */
-
-#ifdef REGEX_MALLOC
-
-#define REGEX_ALLOCATE malloc
-#define REGEX_REALLOCATE(source, osize, nsize) realloc (source, nsize)
-
-#else /* not REGEX_MALLOC */
-
-/* Emacs already defines alloca, sometimes. */
-#ifndef alloca
-
-/* Make alloca work the best possible way. */
-#ifdef __GNUC__
-#define alloca __builtin_alloca
-#else /* not __GNUC__ */
-#if HAVE_ALLOCA_H
-#include <alloca.h>
-#else /* not __GNUC__ or HAVE_ALLOCA_H */
-#ifndef _AIX /* Already did AIX, up at the top. */
-char *alloca ();
-#endif /* not _AIX */
-#endif /* not HAVE_ALLOCA_H */
-#endif /* not __GNUC__ */
-
-#endif /* not alloca */
-
-#define REGEX_ALLOCATE alloca
-
-/* Assumes a `char *destination' variable. */
-#define REGEX_REALLOCATE(source, osize, nsize) \
- (destination = (char *) alloca (nsize), \
- bcopy (source, destination, osize), \
- destination)
-
-#endif /* not REGEX_MALLOC */
-
-
-/* True if `size1' is non-NULL and PTR is pointing anywhere inside
- `string1' or just past its end. This works if PTR is NULL, which is
- a good thing. */
-#define FIRST_STRING_P(ptr) \
- (size1 && string1 <= (ptr) && (ptr) <= string1 + size1)
-
-/* (Re)Allocate N items of type T using malloc, or fail. */
-#define TALLOC(n, t) ((t *) malloc ((n) * sizeof (t)))
-#define RETALLOC(addr, n, t) ((addr) = (t *) realloc (addr, (n) * sizeof (t)))
-#define REGEX_TALLOC(n, t) ((t *) REGEX_ALLOCATE ((n) * sizeof (t)))
-
-#define BYTEWIDTH 8 /* In bits. */
-
-#define STREQ(s1, s2) ((strcmp (s1, s2) == 0))
-
-#define MAX(a, b) ((a) > (b) ? (a) : (b))
-#define MIN(a, b) ((a) < (b) ? (a) : (b))
-
-typedef char boolean;
-#define false 0
-#define true 1
-
-/* These are the command codes that appear in compiled regular
- expressions. Some opcodes are followed by argument bytes. A
- command code can specify any interpretation whatsoever for its
- arguments. Zero bytes may appear in the compiled regular expression.
-
- The value of `exactn' is needed in search.c (search_buffer) in Emacs.
- So regex.h defines a symbol `RE_EXACTN_VALUE' to be 1; the value of
- `exactn' we use here must also be 1. */
-
-typedef enum
-{
- no_op = 0,
-
- /* Followed by one byte giving n, then by n literal bytes. */
- exactn = 1,
-
- /* Matches any (more or less) character. */
- anychar,
-
- /* Matches any one char belonging to specified set. First
- following byte is number of bitmap bytes. Then come bytes
- for a bitmap saying which chars are in. Bits in each byte
- are ordered low-bit-first. A character is in the set if its
- bit is 1. A character too large to have a bit in the map is
- automatically not in the set. */
- charset,
-
- /* Same parameters as charset, but match any character that is
- not one of those specified. */
- charset_not,
-
- /* Start remembering the text that is matched, for storing in a
- register. Followed by one byte with the register number, in
- the range 0 to one less than the pattern buffer's re_nsub
- field. Then followed by one byte with the number of groups
- inner to this one. (This last has to be part of the
- start_memory only because we need it in the on_failure_jump
- of re_match_2.) */
- start_memory,
-
- /* Stop remembering the text that is matched and store it in a
- memory register. Followed by one byte with the register
- number, in the range 0 to one less than `re_nsub' in the
- pattern buffer, and one byte with the number of inner groups,
- just like `start_memory'. (We need the number of inner
- groups here because we don't have any easy way of finding the
- corresponding start_memory when we're at a stop_memory.) */
- stop_memory,
-
- /* Match a duplicate of something remembered. Followed by one
- byte containing the register number. */
- duplicate,
-
- /* Fail unless at beginning of line. */
- begline,
-
- /* Fail unless at end of line. */
- endline,
-
- /* Succeeds if at beginning of buffer (if emacs) or at beginning
- of string to be matched (if not). */
- begbuf,
-
- /* Analogously, for end of buffer/string. */
- endbuf,
-
- /* Followed by two byte relative address to which to jump. */
- jump,
-
- /* Same as jump, but marks the end of an alternative. */
- jump_past_alt,
-
- /* Followed by two-byte relative address of place to resume at
- in case of failure. */
- on_failure_jump,
-
- /* Like on_failure_jump, but pushes a placeholder instead of the
- current string position when executed. */
- on_failure_keep_string_jump,
-
- /* Throw away latest failure point and then jump to following
- two-byte relative address. */
- pop_failure_jump,
-
- /* Change to pop_failure_jump if know won't have to backtrack to
- match; otherwise change to jump. This is used to jump
- back to the beginning of a repeat. If what follows this jump
- clearly won't match what the repeat does, such that we can be
- sure that there is no use backtracking out of repetitions
- already matched, then we change it to a pop_failure_jump.
- Followed by two-byte address. */
- maybe_pop_jump,
-
- /* Jump to following two-byte address, and push a dummy failure
- point. This failure point will be thrown away if an attempt
- is made to use it for a failure. A `+' construct makes this
- before the first repeat. Also used as an intermediary kind
- of jump when compiling an alternative. */
- dummy_failure_jump,
-
- /* Push a dummy failure point and continue. Used at the end of
- alternatives. */
- push_dummy_failure,
-
- /* Followed by two-byte relative address and two-byte number n.
- After matching N times, jump to the address upon failure. */
- succeed_n,
-
- /* Followed by two-byte relative address, and two-byte number n.
- Jump to the address N times, then fail. */
- jump_n,
-
- /* Set the following two-byte relative address to the
- subsequent two-byte number. The address *includes* the two
- bytes of number. */
- set_number_at,
-
- wordchar, /* Matches any word-constituent character. */
- notwordchar, /* Matches any char that is not a word-constituent. */
-
- wordbeg, /* Succeeds if at word beginning. */
- wordend, /* Succeeds if at word end. */
-
- wordbound, /* Succeeds if at a word boundary. */
- notwordbound /* Succeeds if not at a word boundary. */
-
-#ifdef emacs
- ,before_dot, /* Succeeds if before point. */
- at_dot, /* Succeeds if at point. */
- after_dot, /* Succeeds if after point. */
-
- /* Matches any character whose syntax is specified. Followed by
- a byte which contains a syntax code, e.g., Sword. */
- syntaxspec,
-
- /* Matches any character whose syntax is not that specified. */
- notsyntaxspec
-#endif /* emacs */
-} re_opcode_t;
-
-/* Common operations on the compiled pattern. */
-
-/* Store NUMBER in two contiguous bytes starting at DESTINATION. */
-
-#define STORE_NUMBER(destination, number) \
- do { \
- (destination)[0] = (number) & 0377; \
- (destination)[1] = (number) >> 8; \
- } while (0)
-
-/* Same as STORE_NUMBER, except increment DESTINATION to
- the byte after where the number is stored. Therefore, DESTINATION
- must be an lvalue. */
-
-#define STORE_NUMBER_AND_INCR(destination, number) \
- do { \
- STORE_NUMBER (destination, number); \
- (destination) += 2; \
- } while (0)
-
-/* Put into DESTINATION a number stored in two contiguous bytes starting
- at SOURCE. */
-
-#define EXTRACT_NUMBER(destination, source) \
- do { \
- (destination) = *(source) & 0377; \
- (destination) += SIGN_EXTEND_CHAR (*((source) + 1)) << 8; \
- } while (0)
-
-#ifdef DEBUG
-static void
-extract_number (dest, source)
- int *dest;
- unsigned char *source;
-{
- int temp = SIGN_EXTEND_CHAR (*(source + 1));
- *dest = *source & 0377;
- *dest += temp << 8;
-}
-
-#ifndef EXTRACT_MACROS /* To debug the macros. */
-#undef EXTRACT_NUMBER
-#define EXTRACT_NUMBER(dest, src) extract_number (&dest, src)
-#endif /* not EXTRACT_MACROS */
-
-#endif /* DEBUG */
-
-/* Same as EXTRACT_NUMBER, except increment SOURCE to after the number.
- SOURCE must be an lvalue. */
-
-#define EXTRACT_NUMBER_AND_INCR(destination, source) \
- do { \
- EXTRACT_NUMBER (destination, source); \
- (source) += 2; \
- } while (0)
-
-#ifdef DEBUG
-static void
-extract_number_and_incr (destination, source)
- int *destination;
- unsigned char **source;
-{
- extract_number (destination, *source);
- *source += 2;
-}
-
-#ifndef EXTRACT_MACROS
-#undef EXTRACT_NUMBER_AND_INCR
-#define EXTRACT_NUMBER_AND_INCR(dest, src) \
- extract_number_and_incr (&dest, &src)
-#endif /* not EXTRACT_MACROS */
-
-#endif /* DEBUG */
-
-/* If DEBUG is defined, Regex prints many voluminous messages about what
- it is doing (if the variable `debug' is nonzero). If linked with the
- main program in `iregex.c', you can enter patterns and strings
- interactively. And if linked with the main program in `main.c' and
- the other test files, you can run the already-written tests. */
-
-#ifdef DEBUG
-
-/* We use standard I/O for debugging. */
-#include <stdio.h>
-
-/* It is useful to test things that ``must'' be true when debugging. */
-#include <assert.h>
-
-static int debug = 0;
-
-#define DEBUG_STATEMENT(e) e
-#define DEBUG_PRINT1(x) if (debug) printf (x)
-#define DEBUG_PRINT2(x1, x2) if (debug) printf (x1, x2)
-#define DEBUG_PRINT3(x1, x2, x3) if (debug) printf (x1, x2, x3)
-#define DEBUG_PRINT4(x1, x2, x3, x4) if (debug) printf (x1, x2, x3, x4)
-#define DEBUG_PRINT_COMPILED_PATTERN(p, s, e) \
- if (debug) print_partial_compiled_pattern (s, e)
-#define DEBUG_PRINT_DOUBLE_STRING(w, s1, sz1, s2, sz2) \
- if (debug) print_double_string (w, s1, sz1, s2, sz2)
-
-
-extern void printchar ();
-
-/* Print the fastmap in human-readable form. */
-
-void
-print_fastmap (fastmap)
- char *fastmap;
-{
- unsigned was_a_range = 0;
- unsigned i = 0;
-
- while (i < (1 << BYTEWIDTH))
- {
- if (fastmap[i++])
- {
- was_a_range = 0;
- printchar (i - 1);
- while (i < (1 << BYTEWIDTH) && fastmap[i])
- {
- was_a_range = 1;
- i++;
- }
- if (was_a_range)
- {
- printf ("-");
- printchar (i - 1);
- }
- }
- }
- putchar ('\n');
-}
-
-
-/* Print a compiled pattern string in human-readable form, starting at
- the START pointer into it and ending just before the pointer END. */
-
-void
-print_partial_compiled_pattern (start, end)
- unsigned char *start;
- unsigned char *end;
-{
- int mcnt, mcnt2;
- unsigned char *p = start;
- unsigned char *pend = end;
-
- if (start == NULL)
- {
- printf ("(null)\n");
- return;
- }
-
- /* Loop over pattern commands. */
- while (p < pend)
- {
- switch ((re_opcode_t) *p++)
- {
- case no_op:
- printf ("/no_op");
- break;
-
- case exactn:
- mcnt = *p++;
- printf ("/exactn/%d", mcnt);
- do
- {
- putchar ('/');
- printchar (*p++);
- }
- while (--mcnt);
- break;
-
- case start_memory:
- mcnt = *p++;
- printf ("/start_memory/%d/%d", mcnt, *p++);
- break;
-
- case stop_memory:
- mcnt = *p++;
- printf ("/stop_memory/%d/%d", mcnt, *p++);
- break;
-
- case duplicate:
- printf ("/duplicate/%d", *p++);
- break;
-
- case anychar:
- printf ("/anychar");
- break;
-
- case charset:
- case charset_not:
- {
- register int c;
-
- printf ("/charset%s",
- (re_opcode_t) *(p - 1) == charset_not ? "_not" : "");
-
- assert (p + *p < pend);
-
- for (c = 0; c < *p; c++)
- {
- unsigned bit;
- unsigned char map_byte = p[1 + c];
-
- putchar ('/');
-
- for (bit = 0; bit < BYTEWIDTH; bit++)
- if (map_byte & (1 << bit))
- printchar (c * BYTEWIDTH + bit);
- }
- p += 1 + *p;
- break;
- }
-
- case begline:
- printf ("/begline");
- break;
-
- case endline:
- printf ("/endline");
- break;
-
- case on_failure_jump:
- extract_number_and_incr (&mcnt, &p);
- printf ("/on_failure_jump/0/%d", mcnt);
- break;
-
- case on_failure_keep_string_jump:
- extract_number_and_incr (&mcnt, &p);
- printf ("/on_failure_keep_string_jump/0/%d", mcnt);
- break;
-
- case dummy_failure_jump:
- extract_number_and_incr (&mcnt, &p);
- printf ("/dummy_failure_jump/0/%d", mcnt);
- break;
-
- case push_dummy_failure:
- printf ("/push_dummy_failure");
- break;
-
- case maybe_pop_jump:
- extract_number_and_incr (&mcnt, &p);
- printf ("/maybe_pop_jump/0/%d", mcnt);
- break;
-
- case pop_failure_jump:
- extract_number_and_incr (&mcnt, &p);
- printf ("/pop_failure_jump/0/%d", mcnt);
- break;
-
- case jump_past_alt:
- extract_number_and_incr (&mcnt, &p);
- printf ("/jump_past_alt/0/%d", mcnt);
- break;
-
- case jump:
- extract_number_and_incr (&mcnt, &p);
- printf ("/jump/0/%d", mcnt);
- break;
-
- case succeed_n:
- extract_number_and_incr (&mcnt, &p);
- extract_number_and_incr (&mcnt2, &p);
- printf ("/succeed_n/0/%d/0/%d", mcnt, mcnt2);
- break;
-
- case jump_n:
- extract_number_and_incr (&mcnt, &p);
- extract_number_and_incr (&mcnt2, &p);
- printf ("/jump_n/0/%d/0/%d", mcnt, mcnt2);
- break;
-
- case set_number_at:
- extract_number_and_incr (&mcnt, &p);
- extract_number_and_incr (&mcnt2, &p);
- printf ("/set_number_at/0/%d/0/%d", mcnt, mcnt2);
- break;
-
- case wordbound:
- printf ("/wordbound");
- break;
-
- case notwordbound:
- printf ("/notwordbound");
- break;
-
- case wordbeg:
- printf ("/wordbeg");
- break;
-
- case wordend:
- printf ("/wordend");
-
-#ifdef emacs
- case before_dot:
- printf ("/before_dot");
- break;
-
- case at_dot:
- printf ("/at_dot");
- break;
-
- case after_dot:
- printf ("/after_dot");
- break;
-
- case syntaxspec:
- printf ("/syntaxspec");
- mcnt = *p++;
- printf ("/%d", mcnt);
- break;
-
- case notsyntaxspec:
- printf ("/notsyntaxspec");
- mcnt = *p++;
- printf ("/%d", mcnt);
- break;
-#endif /* emacs */
-
- case wordchar:
- printf ("/wordchar");
- break;
-
- case notwordchar:
- printf ("/notwordchar");
- break;
-
- case begbuf:
- printf ("/begbuf");
- break;
-
- case endbuf:
- printf ("/endbuf");
- break;
-
- default:
- printf ("?%d", *(p-1));
- }
- }
- printf ("/\n");
-}
-
-
-void
-print_compiled_pattern (bufp)
- struct re_pattern_buffer *bufp;
-{
- unsigned char *buffer = bufp->buffer;
-
- print_partial_compiled_pattern (buffer, buffer + bufp->used);
- printf ("%d bytes used/%d bytes allocated.\n", bufp->used, bufp->allocated);
-
- if (bufp->fastmap_accurate && bufp->fastmap)
- {
- printf ("fastmap: ");
- print_fastmap (bufp->fastmap);
- }
-
- printf ("re_nsub: %d\t", bufp->re_nsub);
- printf ("regs_alloc: %d\t", bufp->regs_allocated);
- printf ("can_be_null: %d\t", bufp->can_be_null);
- printf ("newline_anchor: %d\n", bufp->newline_anchor);
- printf ("no_sub: %d\t", bufp->no_sub);
- printf ("not_bol: %d\t", bufp->not_bol);
- printf ("not_eol: %d\t", bufp->not_eol);
- printf ("syntax: %d\n", bufp->syntax);
- /* Perhaps we should print the translate table? */
-}
-
-
-void
-print_double_string (where, string1, size1, string2, size2)
- const char *where;
- const char *string1;
- const char *string2;
- int size1;
- int size2;
-{
- unsigned this_char;
-
- if (where == NULL)
- printf ("(null)");
- else
- {
- if (FIRST_STRING_P (where))
- {
- for (this_char = where - string1; this_char < size1; this_char++)
- printchar (string1[this_char]);
-
- where = string2;
- }
-
- for (this_char = where - string2; this_char < size2; this_char++)
- printchar (string2[this_char]);
- }
-}
-
-#else /* not DEBUG */
-
-#undef assert
-#define assert(e)
-
-#define DEBUG_STATEMENT(e)
-#define DEBUG_PRINT1(x)
-#define DEBUG_PRINT2(x1, x2)
-#define DEBUG_PRINT3(x1, x2, x3)
-#define DEBUG_PRINT4(x1, x2, x3, x4)
-#define DEBUG_PRINT_COMPILED_PATTERN(p, s, e)
-#define DEBUG_PRINT_DOUBLE_STRING(w, s1, sz1, s2, sz2)
-
-#endif /* not DEBUG */
-
-/* Set by `re_set_syntax' to the current regexp syntax to recognize. Can
- also be assigned to arbitrarily: each pattern buffer stores its own
- syntax, so it can be changed between regex compilations. */
-reg_syntax_t re_syntax_options = RE_SYNTAX_EMACS;
-
-
-/* Specify the precise syntax of regexps for compilation. This provides
- for compatibility for various utilities which historically have
- different, incompatible syntaxes.
-
- The argument SYNTAX is a bit mask comprised of the various bits
- defined in regex.h. We return the old syntax. */
-
-reg_syntax_t
-re_set_syntax (syntax)
- reg_syntax_t syntax;
-{
- reg_syntax_t ret = re_syntax_options;
-
- re_syntax_options = syntax;
- return ret;
-}
-
-/* This table gives an error message for each of the error codes listed
- in regex.h. Obviously the order here has to be same as there. */
-
-static const char *re_error_msg[] =
- { NULL, /* REG_NOERROR */
- "No match", /* REG_NOMATCH */
- "Invalid regular expression", /* REG_BADPAT */
- "Invalid collation character", /* REG_ECOLLATE */
- "Invalid character class name", /* REG_ECTYPE */
- "Trailing backslash", /* REG_EESCAPE */
- "Invalid back reference", /* REG_ESUBREG */
- "Unmatched [ or [^", /* REG_EBRACK */
- "Unmatched ( or \\(", /* REG_EPAREN */
- "Unmatched \\{", /* REG_EBRACE */
- "Invalid content of \\{\\}", /* REG_BADBR */
- "Invalid range end", /* REG_ERANGE */
- "Memory exhausted", /* REG_ESPACE */
- "Invalid preceding regular expression", /* REG_BADRPT */
- "Premature end of regular expression", /* REG_EEND */
- "Regular expression too big", /* REG_ESIZE */
- "Unmatched ) or \\)", /* REG_ERPAREN */
- };
-
-/* Subroutine declarations and macros for regex_compile. */
-
-static void store_op1 (), store_op2 ();
-static void insert_op1 (), insert_op2 ();
-static boolean at_begline_loc_p (), at_endline_loc_p ();
-static boolean group_in_compile_stack ();
-static reg_errcode_t compile_range ();
-
-/* Fetch the next character in the uncompiled pattern---translating it
- if necessary. Also cast from a signed character in the constant
- string passed to us by the user to an unsigned char that we can use
- as an array index (in, e.g., `translate'). */
-#define PATFETCH(c) \
- do {if (p == pend) return REG_EEND; \
- c = (unsigned char) *p++; \
- if (translate) c = translate[c]; \
- } while (0)
-
-/* Fetch the next character in the uncompiled pattern, with no
- translation. */
-#define PATFETCH_RAW(c) \
- do {if (p == pend) return REG_EEND; \
- c = (unsigned char) *p++; \
- } while (0)
-
-/* Go backwards one character in the pattern. */
-#define PATUNFETCH p--
-
-
-/* If `translate' is non-null, return translate[D], else just D. We
- cast the subscript to translate because some data is declared as
- `char *', to avoid warnings when a string constant is passed. But
- when we use a character as a subscript we must make it unsigned. */
-#define TRANSLATE(d) (translate ? translate[(unsigned char) (d)] : (d))
-
-
-/* Macros for outputting the compiled pattern into `buffer'. */
-
-/* If the buffer isn't allocated when it comes in, use this. */
-#define INIT_BUF_SIZE 32
-
-/* Make sure we have at least N more bytes of space in buffer. */
-#define GET_BUFFER_SPACE(n) \
- while (b - bufp->buffer + (n) > bufp->allocated) \
- EXTEND_BUFFER ()
-
-/* Make sure we have one more byte of buffer space and then add C to it. */
-#define BUF_PUSH(c) \
- do { \
- GET_BUFFER_SPACE (1); \
- *b++ = (unsigned char) (c); \
- } while (0)
-
-
-/* Ensure we have two more bytes of buffer space and then append C1 and C2. */
-#define BUF_PUSH_2(c1, c2) \
- do { \
- GET_BUFFER_SPACE (2); \
- *b++ = (unsigned char) (c1); \
- *b++ = (unsigned char) (c2); \
- } while (0)
-
-
-/* As with BUF_PUSH_2, except for three bytes. */
-#define BUF_PUSH_3(c1, c2, c3) \
- do { \
- GET_BUFFER_SPACE (3); \
- *b++ = (unsigned char) (c1); \
- *b++ = (unsigned char) (c2); \
- *b++ = (unsigned char) (c3); \
- } while (0)
-
-
-/* Store a jump with opcode OP at LOC to location TO. We store a
- relative address offset by the three bytes the jump itself occupies. */
-#define STORE_JUMP(op, loc, to) \
- store_op1 (op, loc, (to) - (loc) - 3)
-
-/* Likewise, for a two-argument jump. */
-#define STORE_JUMP2(op, loc, to, arg) \
- store_op2 (op, loc, (to) - (loc) - 3, arg)
-
-/* Like `STORE_JUMP', but for inserting. Assume `b' is the buffer end. */
-#define INSERT_JUMP(op, loc, to) \
- insert_op1 (op, loc, (to) - (loc) - 3, b)
-
-/* Like `STORE_JUMP2', but for inserting. Assume `b' is the buffer end. */
-#define INSERT_JUMP2(op, loc, to, arg) \
- insert_op2 (op, loc, (to) - (loc) - 3, arg, b)
-
-
-/* This is not an arbitrary limit: the arguments which represent offsets
- into the pattern are two bytes long. So if 2^16 bytes turns out to
- be too small, many things would have to change. */
-#define MAX_BUF_SIZE (1L << 16)
-
-
-/* Extend the buffer by twice its current size via realloc and
- reset the pointers that pointed into the old block to point to the
- correct places in the new one. If extending the buffer results in it
- being larger than MAX_BUF_SIZE, then flag memory exhausted. */
-#define EXTEND_BUFFER() \
- do { \
- unsigned char *old_buffer = bufp->buffer; \
- if (bufp->allocated == MAX_BUF_SIZE) \
- return REG_ESIZE; \
- bufp->allocated <<= 1; \
- if (bufp->allocated > MAX_BUF_SIZE) \
- bufp->allocated = MAX_BUF_SIZE; \
- bufp->buffer = (unsigned char *) realloc (bufp->buffer, bufp->allocated);\
- if (bufp->buffer == NULL) \
- return REG_ESPACE; \
- /* If the buffer moved, move all the pointers into it. */ \
- if (old_buffer != bufp->buffer) \
- { \
- b = (b - old_buffer) + bufp->buffer; \
- begalt = (begalt - old_buffer) + bufp->buffer; \
- if (fixup_alt_jump) \
- fixup_alt_jump = (fixup_alt_jump - old_buffer) + bufp->buffer;\
- if (laststart) \
- laststart = (laststart - old_buffer) + bufp->buffer; \
- if (pending_exact) \
- pending_exact = (pending_exact - old_buffer) + bufp->buffer; \
- } \
- } while (0)
-
-
-/* Since we have one byte reserved for the register number argument to
- {start,stop}_memory, the maximum number of groups we can report
- things about is what fits in that byte. */
-#define MAX_REGNUM 255
-
-/* But patterns can have more than `MAX_REGNUM' registers. We just
- ignore the excess. */
-typedef unsigned regnum_t;
-
-
-/* Macros for the compile stack. */
-
-/* Since offsets can go either forwards or backwards, this type needs to
- be able to hold values from -(MAX_BUF_SIZE - 1) to MAX_BUF_SIZE - 1. */
-typedef int pattern_offset_t;
-
-typedef struct
-{
- pattern_offset_t begalt_offset;
- pattern_offset_t fixup_alt_jump;
- pattern_offset_t inner_group_offset;
- pattern_offset_t laststart_offset;
- regnum_t regnum;
-} compile_stack_elt_t;
-
-
-typedef struct
-{
- compile_stack_elt_t *stack;
- unsigned size;
- unsigned avail; /* Offset of next open position. */
-} compile_stack_type;
-
-
-#define INIT_COMPILE_STACK_SIZE 32
-
-#define COMPILE_STACK_EMPTY (compile_stack.avail == 0)
-#define COMPILE_STACK_FULL (compile_stack.avail == compile_stack.size)
-
-/* The next available element. */
-#define COMPILE_STACK_TOP (compile_stack.stack[compile_stack.avail])
-
-
-/* Set the bit for character C in a list. */
-#define SET_LIST_BIT(c) \
- (b[((unsigned char) (c)) / BYTEWIDTH] \
- |= 1 << (((unsigned char) c) % BYTEWIDTH))
-
-
-/* Get the next unsigned number in the uncompiled pattern. */
-#define GET_UNSIGNED_NUMBER(num) \
- { if (p != pend) \
- { \
- PATFETCH (c); \
- while (ISDIGIT (c)) \
- { \
- if (num < 0) \
- num = 0; \
- num = num * 10 + c - '0'; \
- if (p == pend) \
- break; \
- PATFETCH (c); \
- } \
- } \
- }
-
-#define CHAR_CLASS_MAX_LENGTH 6 /* Namely, `xdigit'. */
-
-#define IS_CHAR_CLASS(string) \
- (STREQ (string, "alpha") || STREQ (string, "upper") \
- || STREQ (string, "lower") || STREQ (string, "digit") \
- || STREQ (string, "alnum") || STREQ (string, "xdigit") \
- || STREQ (string, "space") || STREQ (string, "print") \
- || STREQ (string, "punct") || STREQ (string, "graph") \
- || STREQ (string, "cntrl") || STREQ (string, "blank"))
-
-/* `regex_compile' compiles PATTERN (of length SIZE) according to SYNTAX.
- Returns one of error codes defined in `regex.h', or zero for success.
-
- Assumes the `allocated' (and perhaps `buffer') and `translate'
- fields are set in BUFP on entry.
-
- If it succeeds, results are put in BUFP (if it returns an error, the
- contents of BUFP are undefined):
- `buffer' is the compiled pattern;
- `syntax' is set to SYNTAX;
- `used' is set to the length of the compiled pattern;
- `fastmap_accurate' is zero;
- `re_nsub' is the number of subexpressions in PATTERN;
- `not_bol' and `not_eol' are zero;
-
- The `fastmap' and `newline_anchor' fields are neither
- examined nor set. */
-
-static reg_errcode_t
-regex_compile (pattern, size, syntax, bufp)
- const char *pattern;
- int size;
- reg_syntax_t syntax;
- struct re_pattern_buffer *bufp;
-{
- /* We fetch characters from PATTERN here. Even though PATTERN is
- `char *' (i.e., signed), we declare these variables as unsigned, so
- they can be reliably used as array indices. */
- register unsigned char c, c1;
-
- /* A random tempory spot in PATTERN. */
- const char *p1;
-
- /* Points to the end of the buffer, where we should append. */
- register unsigned char *b;
-
- /* Keeps track of unclosed groups. */
- compile_stack_type compile_stack;
-
- /* Points to the current (ending) position in the pattern. */
- const char *p = pattern;
- const char *pend = pattern + size;
-
- /* How to translate the characters in the pattern. */
- char *translate = bufp->translate;
-
- /* Address of the count-byte of the most recently inserted `exactn'
- command. This makes it possible to tell if a new exact-match
- character can be added to that command or if the character requires
- a new `exactn' command. */
- unsigned char *pending_exact = 0;
-
- /* Address of start of the most recently finished expression.
- This tells, e.g., postfix * where to find the start of its
- operand. Reset at the beginning of groups and alternatives. */
- unsigned char *laststart = 0;
-
- /* Address of beginning of regexp, or inside of last group. */
- unsigned char *begalt;
-
- /* Place in the uncompiled pattern (i.e., the {) to
- which to go back if the interval is invalid. */
- const char *beg_interval;
-
- /* Address of the place where a forward jump should go to the end of
- the containing expression. Each alternative of an `or' -- except the
- last -- ends with a forward jump of this sort. */
- unsigned char *fixup_alt_jump = 0;
-
- /* Counts open-groups as they are encountered. Remembered for the
- matching close-group on the compile stack, so the same register
- number is put in the stop_memory as the start_memory. */
- regnum_t regnum = 0;
-
-#ifdef DEBUG
- DEBUG_PRINT1 ("\nCompiling pattern: ");
- if (debug)
- {
- unsigned debug_count;
-
- for (debug_count = 0; debug_count < size; debug_count++)
- printchar (pattern[debug_count]);
- putchar ('\n');
- }
-#endif /* DEBUG */
-
- /* Initialize the compile stack. */
- compile_stack.stack = TALLOC (INIT_COMPILE_STACK_SIZE, compile_stack_elt_t);
- if (compile_stack.stack == NULL)
- return REG_ESPACE;
-
- compile_stack.size = INIT_COMPILE_STACK_SIZE;
- compile_stack.avail = 0;
-
- /* Initialize the pattern buffer. */
- bufp->syntax = syntax;
- bufp->fastmap_accurate = 0;
- bufp->not_bol = bufp->not_eol = 0;
-
- /* Set `used' to zero, so that if we return an error, the pattern
- printer (for debugging) will think there's no pattern. We reset it
- at the end. */
- bufp->used = 0;
-
- /* Always count groups, whether or not bufp->no_sub is set. */
- bufp->re_nsub = 0;
-
-#if !defined (emacs) && !defined (SYNTAX_TABLE)
- /* Initialize the syntax table. */
- init_syntax_once ();
-#endif
-
- if (bufp->allocated == 0)
- {
- if (bufp->buffer)
- { /* If zero allocated, but buffer is non-null, try to realloc
- enough space. This loses if buffer's address is bogus, but
- that is the user's responsibility. */
- RETALLOC (bufp->buffer, INIT_BUF_SIZE, unsigned char);
- }
- else
- { /* Caller did not allocate a buffer. Do it for them. */
- bufp->buffer = TALLOC (INIT_BUF_SIZE, unsigned char);
- }
- if (!bufp->buffer) return REG_ESPACE;
-
- bufp->allocated = INIT_BUF_SIZE;
- }
-
- begalt = b = bufp->buffer;
-
- /* Loop through the uncompiled pattern until we're at the end. */
- while (p != pend)
- {
- PATFETCH (c);
-
- switch (c)
- {
- case '^':
- {
- if ( /* If at start of pattern, it's an operator. */
- p == pattern + 1
- /* If context independent, it's an operator. */
- || syntax & RE_CONTEXT_INDEP_ANCHORS
- /* Otherwise, depends on what's come before. */
- || at_begline_loc_p (pattern, p, syntax))
- BUF_PUSH (begline);
- else
- goto normal_char;
- }
- break;
-
-
- case '$':
- {
- if ( /* If at end of pattern, it's an operator. */
- p == pend
- /* If context independent, it's an operator. */
- || syntax & RE_CONTEXT_INDEP_ANCHORS
- /* Otherwise, depends on what's next. */
- || at_endline_loc_p (p, pend, syntax))
- BUF_PUSH (endline);
- else
- goto normal_char;
- }
- break;
-
-
- case '+':
- case '?':
- if ((syntax & RE_BK_PLUS_QM)
- || (syntax & RE_LIMITED_OPS))
- goto normal_char;
- handle_plus:
- case '*':
- /* If there is no previous pattern... */
- if (!laststart)
- {
- if (syntax & RE_CONTEXT_INVALID_OPS)
- return REG_BADRPT;
- else if (!(syntax & RE_CONTEXT_INDEP_OPS))
- goto normal_char;
- }
-
- {
- /* Are we optimizing this jump? */
- boolean keep_string_p = false;
-
- /* 1 means zero (many) matches is allowed. */
- char zero_times_ok = 0, many_times_ok = 0;
-
- /* If there is a sequence of repetition chars, collapse it
- down to just one (the right one). We can't combine
- interval operators with these because of, e.g., `a{2}*',
- which should only match an even number of `a's. */
-
- for (;;)
- {
- zero_times_ok |= c != '+';
- many_times_ok |= c != '?';
-
- if (p == pend)
- break;
-
- PATFETCH (c);
-
- if (c == '*'
- || (!(syntax & RE_BK_PLUS_QM) && (c == '+' || c == '?')))
- ;
-
- else if (syntax & RE_BK_PLUS_QM && c == '\\')
- {
- if (p == pend) return REG_EESCAPE;
-
- PATFETCH (c1);
- if (!(c1 == '+' || c1 == '?'))
- {
- PATUNFETCH;
- PATUNFETCH;
- break;
- }
-
- c = c1;
- }
- else
- {
- PATUNFETCH;
- break;
- }
-
- /* If we get here, we found another repeat character. */
- }
-
- /* Star, etc. applied to an empty pattern is equivalent
- to an empty pattern. */
- if (!laststart)
- break;
-
- /* Now we know whether or not zero matches is allowed
- and also whether or not two or more matches is allowed. */
- if (many_times_ok)
- { /* More than one repetition is allowed, so put in at the
- end a backward relative jump from `b' to before the next
- jump we're going to put in below (which jumps from
- laststart to after this jump).
-
- But if we are at the `*' in the exact sequence `.*\n',
- insert an unconditional jump backwards to the .,
- instead of the beginning of the loop. This way we only
- push a failure point once, instead of every time
- through the loop. */
- assert (p - 1 > pattern);
-
- /* Allocate the space for the jump. */
- GET_BUFFER_SPACE (3);
-
- /* We know we are not at the first character of the pattern,
- because laststart was nonzero. And we've already
- incremented `p', by the way, to be the character after
- the `*'. Do we have to do something analogous here
- for null bytes, because of RE_DOT_NOT_NULL? */
- if (TRANSLATE (*(p - 2)) == TRANSLATE ('.')
- && p < pend && TRANSLATE (*p) == TRANSLATE ('\n')
- && !(syntax & RE_DOT_NEWLINE))
- { /* We have .*\n. */
- STORE_JUMP (jump, b, laststart);
- keep_string_p = true;
- }
- else
- /* Anything else. */
- STORE_JUMP (maybe_pop_jump, b, laststart - 3);
-
- /* We've added more stuff to the buffer. */
- b += 3;
- }
-
- /* On failure, jump from laststart to b + 3, which will be the
- end of the buffer after this jump is inserted. */
- GET_BUFFER_SPACE (3);
- INSERT_JUMP (keep_string_p ? on_failure_keep_string_jump
- : on_failure_jump,
- laststart, b + 3);
- pending_exact = 0;
- b += 3;
-
- if (!zero_times_ok)
- {
- /* At least one repetition is required, so insert a
- `dummy_failure_jump' before the initial
- `on_failure_jump' instruction of the loop. This
- effects a skip over that instruction the first time
- we hit that loop. */
- GET_BUFFER_SPACE (3);
- INSERT_JUMP (dummy_failure_jump, laststart, laststart + 6);
- b += 3;
- }
- }
- break;
-
-
- case '.':
- laststart = b;
- BUF_PUSH (anychar);
- break;
-
-
- case '[':
- {
- boolean had_char_class = false;
-
- if (p == pend) return REG_EBRACK;
-
- /* Ensure that we have enough space to push a charset: the
- opcode, the length count, and the bitset; 34 bytes in all. */
- GET_BUFFER_SPACE (34);
-
- laststart = b;
-
- /* We test `*p == '^' twice, instead of using an if
- statement, so we only need one BUF_PUSH. */
- BUF_PUSH (*p == '^' ? charset_not : charset);
- if (*p == '^')
- p++;
-
- /* Remember the first position in the bracket expression. */
- p1 = p;
-
- /* Push the number of bytes in the bitmap. */
- BUF_PUSH ((1 << BYTEWIDTH) / BYTEWIDTH);
-
- /* Clear the whole map. */
- bzero (b, (1 << BYTEWIDTH) / BYTEWIDTH);
-
- /* charset_not matches newline according to a syntax bit. */
- if ((re_opcode_t) b[-2] == charset_not
- && (syntax & RE_HAT_LISTS_NOT_NEWLINE))
- SET_LIST_BIT ('\n');
-
- /* Read in characters and ranges, setting map bits. */
- for (;;)
- {
- if (p == pend) return REG_EBRACK;
-
- PATFETCH (c);
-
- /* \ might escape characters inside [...] and [^...]. */
- if ((syntax & RE_BACKSLASH_ESCAPE_IN_LISTS) && c == '\\')
- {
- if (p == pend) return REG_EESCAPE;
-
- PATFETCH (c1);
- SET_LIST_BIT (c1);
- continue;
- }
-
- /* Could be the end of the bracket expression. If it's
- not (i.e., when the bracket expression is `[]' so
- far), the ']' character bit gets set way below. */
- if (c == ']' && p != p1 + 1)
- break;
-
- /* Look ahead to see if it's a range when the last thing
- was a character class. */
- if (had_char_class && c == '-' && *p != ']')
- return REG_ERANGE;
-
- /* Look ahead to see if it's a range when the last thing
- was a character: if this is a hyphen not at the
- beginning or the end of a list, then it's the range
- operator. */
- if (c == '-'
- && !(p - 2 >= pattern && p[-2] == '[')
- && !(p - 3 >= pattern && p[-3] == '[' && p[-2] == '^')
- && *p != ']')
- {
- reg_errcode_t ret
- = compile_range (&p, pend, translate, syntax, b);
- if (ret != REG_NOERROR) return ret;
- }
-
- else if (p[0] == '-' && p[1] != ']')
- { /* This handles ranges made up of characters only. */
- reg_errcode_t ret;
-
- /* Move past the `-'. */
- PATFETCH (c1);
-
- ret = compile_range (&p, pend, translate, syntax, b);
- if (ret != REG_NOERROR) return ret;
- }
-
- /* See if we're at the beginning of a possible character
- class. */
-
- else if (syntax & RE_CHAR_CLASSES && c == '[' && *p == ':')
- { /* Leave room for the null. */
- char str[CHAR_CLASS_MAX_LENGTH + 1];
-
- PATFETCH (c);
- c1 = 0;
-
- /* If pattern is `[[:'. */
- if (p == pend) return REG_EBRACK;
-
- for (;;)
- {
- PATFETCH (c);
- if (c == ':' || c == ']' || p == pend
- || c1 == CHAR_CLASS_MAX_LENGTH)
- break;
- str[c1++] = c;
- }
- str[c1] = '\0';
-
- /* If isn't a word bracketed by `[:' and:`]':
- undo the ending character, the letters, and leave
- the leading `:' and `[' (but set bits for them). */
- if (c == ':' && *p == ']')
- {
- int ch;
- boolean is_alnum = STREQ (str, "alnum");
- boolean is_alpha = STREQ (str, "alpha");
- boolean is_blank = STREQ (str, "blank");
- boolean is_cntrl = STREQ (str, "cntrl");
- boolean is_digit = STREQ (str, "digit");
- boolean is_graph = STREQ (str, "graph");
- boolean is_lower = STREQ (str, "lower");
- boolean is_print = STREQ (str, "print");
- boolean is_punct = STREQ (str, "punct");
- boolean is_space = STREQ (str, "space");
- boolean is_upper = STREQ (str, "upper");
- boolean is_xdigit = STREQ (str, "xdigit");
-
- if (!IS_CHAR_CLASS (str)) return REG_ECTYPE;
-
- /* Throw away the ] at the end of the character
- class. */
- PATFETCH (c);
-
- if (p == pend) return REG_EBRACK;
-
- for (ch = 0; ch < 1 << BYTEWIDTH; ch++)
- {
- if ( (is_alnum && ISALNUM (ch))
- || (is_alpha && ISALPHA (ch))
- || (is_blank && ISBLANK (ch))
- || (is_cntrl && ISCNTRL (ch))
- || (is_digit && ISDIGIT (ch))
- || (is_graph && ISGRAPH (ch))
- || (is_lower && ISLOWER (ch))
- || (is_print && ISPRINT (ch))
- || (is_punct && ISPUNCT (ch))
- || (is_space && ISSPACE (ch))
- || (is_upper && ISUPPER (ch))
- || (is_xdigit && ISXDIGIT (ch)))
- SET_LIST_BIT (ch);
- }
- had_char_class = true;
- }
- else
- {
- c1++;
- while (c1--)
- PATUNFETCH;
- SET_LIST_BIT ('[');
- SET_LIST_BIT (':');
- had_char_class = false;
- }
- }
- else
- {
- had_char_class = false;
- SET_LIST_BIT (c);
- }
- }
-
- /* Discard any (non)matching list bytes that are all 0 at the
- end of the map. Decrease the map-length byte too. */
- while ((int) b[-1] > 0 && b[b[-1] - 1] == 0)
- b[-1]--;
- b += b[-1];
- }
- break;
-
-
- case '(':
- if (syntax & RE_NO_BK_PARENS)
- goto handle_open;
- else
- goto normal_char;
-
-
- case ')':
- if (syntax & RE_NO_BK_PARENS)
- goto handle_close;
- else
- goto normal_char;
-
-
- case '\n':
- if (syntax & RE_NEWLINE_ALT)
- goto handle_alt;
- else
- goto normal_char;
-
-
- case '|':
- if (syntax & RE_NO_BK_VBAR)
- goto handle_alt;
- else
- goto normal_char;
-
-
- case '{':
- if (syntax & RE_INTERVALS && syntax & RE_NO_BK_BRACES)
- goto handle_interval;
- else
- goto normal_char;
-
-
- case '\\':
- if (p == pend) return REG_EESCAPE;
-
- /* Do not translate the character after the \, so that we can
- distinguish, e.g., \B from \b, even if we normally would
- translate, e.g., B to b. */
- PATFETCH_RAW (c);
-
- switch (c)
- {
- case '(':
- if (syntax & RE_NO_BK_PARENS)
- goto normal_backslash;
-
- handle_open:
- bufp->re_nsub++;
- regnum++;
-
- if (COMPILE_STACK_FULL)
- {
- RETALLOC (compile_stack.stack, compile_stack.size << 1,
- compile_stack_elt_t);
- if (compile_stack.stack == NULL) return REG_ESPACE;
-
- compile_stack.size <<= 1;
- }
-
- /* These are the values to restore when we hit end of this
- group. They are all relative offsets, so that if the
- whole pattern moves because of realloc, they will still
- be valid. */
- COMPILE_STACK_TOP.begalt_offset = begalt - bufp->buffer;
- COMPILE_STACK_TOP.fixup_alt_jump
- = fixup_alt_jump ? fixup_alt_jump - bufp->buffer + 1 : 0;
- COMPILE_STACK_TOP.laststart_offset = b - bufp->buffer;
- COMPILE_STACK_TOP.regnum = regnum;
-
- /* We will eventually replace the 0 with the number of
- groups inner to this one. But do not push a
- start_memory for groups beyond the last one we can
- represent in the compiled pattern. */
- if (regnum <= MAX_REGNUM)
- {
- COMPILE_STACK_TOP.inner_group_offset = b - bufp->buffer + 2;
- BUF_PUSH_3 (start_memory, regnum, 0);
- }
-
- compile_stack.avail++;
-
- fixup_alt_jump = 0;
- laststart = 0;
- begalt = b;
- break;
-
-
- case ')':
- if (syntax & RE_NO_BK_PARENS) goto normal_backslash;
-
- if (COMPILE_STACK_EMPTY)
- if (syntax & RE_UNMATCHED_RIGHT_PAREN_ORD)
- goto normal_backslash;
- else
- return REG_ERPAREN;
-
- handle_close:
- if (fixup_alt_jump)
- { /* Push a dummy failure point at the end of the
- alternative for a possible future
- `pop_failure_jump' to pop. See comments at
- `push_dummy_failure' in `re_match_2'. */
- BUF_PUSH (push_dummy_failure);
-
- /* We allocated space for this jump when we assigned
- to `fixup_alt_jump', in the `handle_alt' case below. */
- STORE_JUMP (jump_past_alt, fixup_alt_jump, b - 1);
- }
-
- /* See similar code for backslashed left paren above. */
- if (COMPILE_STACK_EMPTY)
- if (syntax & RE_UNMATCHED_RIGHT_PAREN_ORD)
- goto normal_char;
- else
- return REG_ERPAREN;
-
- /* Since we just checked for an empty stack above, this
- ``can't happen''. */
- assert (compile_stack.avail != 0);
- {
- /* We don't just want to restore into `regnum', because
- later groups should continue to be numbered higher,
- as in `(ab)c(de)' -- the second group is #2. */
- regnum_t this_group_regnum;
-
- compile_stack.avail--;
- begalt = bufp->buffer + COMPILE_STACK_TOP.begalt_offset;
- fixup_alt_jump
- = COMPILE_STACK_TOP.fixup_alt_jump
- ? bufp->buffer + COMPILE_STACK_TOP.fixup_alt_jump - 1
- : 0;
- laststart = bufp->buffer + COMPILE_STACK_TOP.laststart_offset;
- this_group_regnum = COMPILE_STACK_TOP.regnum;
-
- /* We're at the end of the group, so now we know how many
- groups were inside this one. */
- if (this_group_regnum <= MAX_REGNUM)
- {
- unsigned char *inner_group_loc
- = bufp->buffer + COMPILE_STACK_TOP.inner_group_offset;
-
- *inner_group_loc = regnum - this_group_regnum;
- BUF_PUSH_3 (stop_memory, this_group_regnum,
- regnum - this_group_regnum);
- }
- }
- break;
-
-
- case '|': /* `\|'. */
- if (syntax & RE_LIMITED_OPS || syntax & RE_NO_BK_VBAR)
- goto normal_backslash;
- handle_alt:
- if (syntax & RE_LIMITED_OPS)
- goto normal_char;
-
- /* Insert before the previous alternative a jump which
- jumps to this alternative if the former fails. */
- GET_BUFFER_SPACE (3);
- INSERT_JUMP (on_failure_jump, begalt, b + 6);
- pending_exact = 0;
- b += 3;
-
- /* The alternative before this one has a jump after it
- which gets executed if it gets matched. Adjust that
- jump so it will jump to this alternative's analogous
- jump (put in below, which in turn will jump to the next
- (if any) alternative's such jump, etc.). The last such
- jump jumps to the correct final destination. A picture:
- _____ _____
- | | | |
- | v | v
- a | b | c
-
- If we are at `b', then fixup_alt_jump right now points to a
- three-byte space after `a'. We'll put in the jump, set
- fixup_alt_jump to right after `b', and leave behind three
- bytes which we'll fill in when we get to after `c'. */
-
- if (fixup_alt_jump)
- STORE_JUMP (jump_past_alt, fixup_alt_jump, b);
-
- /* Mark and leave space for a jump after this alternative,
- to be filled in later either by next alternative or
- when know we're at the end of a series of alternatives. */
- fixup_alt_jump = b;
- GET_BUFFER_SPACE (3);
- b += 3;
-
- laststart = 0;
- begalt = b;
- break;
-
-
- case '{':
- /* If \{ is a literal. */
- if (!(syntax & RE_INTERVALS)
- /* If we're at `\{' and it's not the open-interval
- operator. */
- || ((syntax & RE_INTERVALS) && (syntax & RE_NO_BK_BRACES))
- || (p - 2 == pattern && p == pend))
- goto normal_backslash;
-
- handle_interval:
- {
- /* If got here, then the syntax allows intervals. */
-
- /* At least (most) this many matches must be made. */
- int lower_bound = -1, upper_bound = -1;
-
- beg_interval = p - 1;
-
- if (p == pend)
- {
- if (syntax & RE_NO_BK_BRACES)
- goto unfetch_interval;
- else
- return REG_EBRACE;
- }
-
- GET_UNSIGNED_NUMBER (lower_bound);
-
- if (c == ',')
- {
- GET_UNSIGNED_NUMBER (upper_bound);
- if (upper_bound < 0) upper_bound = RE_DUP_MAX;
- }
- else
- /* Interval such as `{1}' => match exactly once. */
- upper_bound = lower_bound;
-
- if (lower_bound < 0 || upper_bound > RE_DUP_MAX
- || lower_bound > upper_bound)
- {
- if (syntax & RE_NO_BK_BRACES)
- goto unfetch_interval;
- else
- return REG_BADBR;
- }
-
- if (!(syntax & RE_NO_BK_BRACES))
- {
- if (c != '\\') return REG_EBRACE;
-
- PATFETCH (c);
- }
-
- if (c != '}')
- {
- if (syntax & RE_NO_BK_BRACES)
- goto unfetch_interval;
- else
- return REG_BADBR;
- }
-
- /* We just parsed a valid interval. */
-
- /* If it's invalid to have no preceding re. */
- if (!laststart)
- {
- if (syntax & RE_CONTEXT_INVALID_OPS)
- return REG_BADRPT;
- else if (syntax & RE_CONTEXT_INDEP_OPS)
- laststart = b;
- else
- goto unfetch_interval;
- }
-
- /* If the upper bound is zero, don't want to succeed at
- all; jump from `laststart' to `b + 3', which will be
- the end of the buffer after we insert the jump. */
- if (upper_bound == 0)
- {
- GET_BUFFER_SPACE (3);
- INSERT_JUMP (jump, laststart, b + 3);
- b += 3;
- }
-
- /* Otherwise, we have a nontrivial interval. When
- we're all done, the pattern will look like:
- set_number_at <jump count> <upper bound>
- set_number_at <succeed_n count> <lower bound>
- succeed_n <after jump addr> <succed_n count>
- <body of loop>
- jump_n <succeed_n addr> <jump count>
- (The upper bound and `jump_n' are omitted if
- `upper_bound' is 1, though.) */
- else
- { /* If the upper bound is > 1, we need to insert
- more at the end of the loop. */
- unsigned nbytes = 10 + (upper_bound > 1) * 10;
-
- GET_BUFFER_SPACE (nbytes);
-
- /* Initialize lower bound of the `succeed_n', even
- though it will be set during matching by its
- attendant `set_number_at' (inserted next),
- because `re_compile_fastmap' needs to know.
- Jump to the `jump_n' we might insert below. */
- INSERT_JUMP2 (succeed_n, laststart,
- b + 5 + (upper_bound > 1) * 5,
- lower_bound);
- b += 5;
-
- /* Code to initialize the lower bound. Insert
- before the `succeed_n'. The `5' is the last two
- bytes of this `set_number_at', plus 3 bytes of
- the following `succeed_n'. */
- insert_op2 (set_number_at, laststart, 5, lower_bound, b);
- b += 5;
-
- if (upper_bound > 1)
- { /* More than one repetition is allowed, so
- append a backward jump to the `succeed_n'
- that starts this interval.
-
- When we've reached this during matching,
- we'll have matched the interval once, so
- jump back only `upper_bound - 1' times. */
- STORE_JUMP2 (jump_n, b, laststart + 5,
- upper_bound - 1);
- b += 5;
-
- /* The location we want to set is the second
- parameter of the `jump_n'; that is `b-2' as
- an absolute address. `laststart' will be
- the `set_number_at' we're about to insert;
- `laststart+3' the number to set, the source
- for the relative address. But we are
- inserting into the middle of the pattern --
- so everything is getting moved up by 5.
- Conclusion: (b - 2) - (laststart + 3) + 5,
- i.e., b - laststart.
-
- We insert this at the beginning of the loop
- so that if we fail during matching, we'll
- reinitialize the bounds. */
- insert_op2 (set_number_at, laststart, b - laststart,
- upper_bound - 1, b);
- b += 5;
- }
- }
- pending_exact = 0;
- beg_interval = NULL;
- }
- break;
-
- unfetch_interval:
- /* If an invalid interval, match the characters as literals. */
- assert (beg_interval);
- p = beg_interval;
- beg_interval = NULL;
-
- /* normal_char and normal_backslash need `c'. */
- PATFETCH (c);
-
- if (!(syntax & RE_NO_BK_BRACES))
- {
- if (p > pattern && p[-1] == '\\')
- goto normal_backslash;
- }
- goto normal_char;
-
-#ifdef emacs
- /* There is no way to specify the before_dot and after_dot
- operators. rms says this is ok. --karl */
- case '=':
- BUF_PUSH (at_dot);
- break;
-
- case 's':
- laststart = b;
- PATFETCH (c);
- BUF_PUSH_2 (syntaxspec, syntax_spec_code[c]);
- break;
-
- case 'S':
- laststart = b;
- PATFETCH (c);
- BUF_PUSH_2 (notsyntaxspec, syntax_spec_code[c]);
- break;
-#endif /* emacs */
-
-
- case 'w':
- laststart = b;
- BUF_PUSH (wordchar);
- break;
-
-
- case 'W':
- laststart = b;
- BUF_PUSH (notwordchar);
- break;
-
-
- case '<':
- BUF_PUSH (wordbeg);
- break;
-
- case '>':
- BUF_PUSH (wordend);
- break;
-
- case 'b':
- BUF_PUSH (wordbound);
- break;
-
- case 'B':
- BUF_PUSH (notwordbound);
- break;
-
- case '`':
- BUF_PUSH (begbuf);
- break;
-
- case '\'':
- BUF_PUSH (endbuf);
- break;
-
- case '1': case '2': case '3': case '4': case '5':
- case '6': case '7': case '8': case '9':
- if (syntax & RE_NO_BK_REFS)
- goto normal_char;
-
- c1 = c - '0';
-
- if (c1 > regnum)
- return REG_ESUBREG;
-
- /* Can't back reference to a subexpression if inside of it. */
- if (group_in_compile_stack (compile_stack, c1))
- goto normal_char;
-
- laststart = b;
- BUF_PUSH_2 (duplicate, c1);
- break;
-
-
- case '+':
- case '?':
- if (syntax & RE_BK_PLUS_QM)
- goto handle_plus;
- else
- goto normal_backslash;
-
- default:
- normal_backslash:
- /* You might think it would be useful for \ to mean
- not to translate; but if we don't translate it
- it will never match anything. */
- c = TRANSLATE (c);
- goto normal_char;
- }
- break;
-
-
- default:
- /* Expects the character in `c'. */
- normal_char:
- /* If no exactn currently being built. */
- if (!pending_exact
-
- /* If last exactn not at current position. */
- || pending_exact + *pending_exact + 1 != b
-
- /* We have only one byte following the exactn for the count. */
- || *pending_exact == (1 << BYTEWIDTH) - 1
-
- /* If followed by a repetition operator. */
- || *p == '*' || *p == '^'
- || ((syntax & RE_BK_PLUS_QM)
- ? *p == '\\' && (p[1] == '+' || p[1] == '?')
- : (*p == '+' || *p == '?'))
- || ((syntax & RE_INTERVALS)
- && ((syntax & RE_NO_BK_BRACES)
- ? *p == '{'
- : (p[0] == '\\' && p[1] == '{'))))
- {
- /* Start building a new exactn. */
-
- laststart = b;
-
- BUF_PUSH_2 (exactn, 0);
- pending_exact = b - 1;
- }
-
- BUF_PUSH (c);
- (*pending_exact)++;
- break;
- } /* switch (c) */
- } /* while p != pend */
-
-
- /* Through the pattern now. */
-
- if (fixup_alt_jump)
- STORE_JUMP (jump_past_alt, fixup_alt_jump, b);
-
- if (!COMPILE_STACK_EMPTY)
- return REG_EPAREN;
-
- free (compile_stack.stack);
-
- /* We have succeeded; set the length of the buffer. */
- bufp->used = b - bufp->buffer;
-
-#ifdef DEBUG
- if (debug)
- {
- DEBUG_PRINT1 ("\nCompiled pattern: ");
- print_compiled_pattern (bufp);
- }
-#endif /* DEBUG */
-
- return REG_NOERROR;
-} /* regex_compile */
-
-/* Subroutines for `regex_compile'. */
-
-/* Store OP at LOC followed by two-byte integer parameter ARG. */
-
-static void
-store_op1 (op, loc, arg)
- re_opcode_t op;
- unsigned char *loc;
- int arg;
-{
- *loc = (unsigned char) op;
- STORE_NUMBER (loc + 1, arg);
-}
-
-
-/* Like `store_op1', but for two two-byte parameters ARG1 and ARG2. */
-
-static void
-store_op2 (op, loc, arg1, arg2)
- re_opcode_t op;
- unsigned char *loc;
- int arg1, arg2;
-{
- *loc = (unsigned char) op;
- STORE_NUMBER (loc + 1, arg1);
- STORE_NUMBER (loc + 3, arg2);
-}
-
-
-/* Copy the bytes from LOC to END to open up three bytes of space at LOC
- for OP followed by two-byte integer parameter ARG. */
-
-static void
-insert_op1 (op, loc, arg, end)
- re_opcode_t op;
- unsigned char *loc;
- int arg;
- unsigned char *end;
-{
- register unsigned char *pfrom = end;
- register unsigned char *pto = end + 3;
-
- while (pfrom != loc)
- *--pto = *--pfrom;
-
- store_op1 (op, loc, arg);
-}
-
-
-/* Like `insert_op1', but for two two-byte parameters ARG1 and ARG2. */
-
-static void
-insert_op2 (op, loc, arg1, arg2, end)
- re_opcode_t op;
- unsigned char *loc;
- int arg1, arg2;
- unsigned char *end;
-{
- register unsigned char *pfrom = end;
- register unsigned char *pto = end + 5;
-
- while (pfrom != loc)
- *--pto = *--pfrom;
-
- store_op2 (op, loc, arg1, arg2);
-}
-
-
-/* P points to just after a ^ in PATTERN. Return true if that ^ comes
- after an alternative or a begin-subexpression. We assume there is at
- least one character before the ^. */
-
-static boolean
-at_begline_loc_p (pattern, p, syntax)
- const char *pattern, *p;
- reg_syntax_t syntax;
-{
- const char *prev = p - 2;
- boolean prev_prev_backslash = prev > pattern && prev[-1] == '\\';
-
- return
- /* After a subexpression? */
- (*prev == '(' && (syntax & RE_NO_BK_PARENS || prev_prev_backslash))
- /* After an alternative? */
- || (*prev == '|' && (syntax & RE_NO_BK_VBAR || prev_prev_backslash));
-}
-
-
-/* The dual of at_begline_loc_p. This one is for $. We assume there is
- at least one character after the $, i.e., `P < PEND'. */
-
-static boolean
-at_endline_loc_p (p, pend, syntax)
- const char *p, *pend;
- int syntax;
-{
- const char *next = p;
- boolean next_backslash = *next == '\\';
- const char *next_next = p + 1 < pend ? p + 1 : NULL;
-
- return
- /* Before a subexpression? */
- (syntax & RE_NO_BK_PARENS ? *next == ')'
- : next_backslash && next_next && *next_next == ')')
- /* Before an alternative? */
- || (syntax & RE_NO_BK_VBAR ? *next == '|'
- : next_backslash && next_next && *next_next == '|');
-}
-
-
-/* Returns true if REGNUM is in one of COMPILE_STACK's elements and
- false if it's not. */
-
-static boolean
-group_in_compile_stack (compile_stack, regnum)
- compile_stack_type compile_stack;
- regnum_t regnum;
-{
- int this_element;
-
- for (this_element = compile_stack.avail - 1;
- this_element >= 0;
- this_element--)
- if (compile_stack.stack[this_element].regnum == regnum)
- return true;
-
- return false;
-}
-
-
-/* Read the ending character of a range (in a bracket expression) from the
- uncompiled pattern *P_PTR (which ends at PEND). We assume the
- starting character is in `P[-2]'. (`P[-1]' is the character `-'.)
- Then we set the translation of all bits between the starting and
- ending characters (inclusive) in the compiled pattern B.
-
- Return an error code.
-
- We use these short variable names so we can use the same macros as
- `regex_compile' itself. */
-
-static reg_errcode_t
-compile_range (p_ptr, pend, translate, syntax, b)
- const char **p_ptr, *pend;
- char *translate;
- reg_syntax_t syntax;
- unsigned char *b;
-{
- unsigned this_char;
-
- const char *p = *p_ptr;
- int range_start, range_end;
-
- if (p == pend)
- return REG_ERANGE;
-
- /* Even though the pattern is a signed `char *', we need to fetch
- with unsigned char *'s; if the high bit of the pattern character
- is set, the range endpoints will be negative if we fetch using a
- signed char *.
-
- We also want to fetch the endpoints without translating them; the
- appropriate translation is done in the bit-setting loop below. */
- range_start = ((unsigned char *) p)[-2];
- range_end = ((unsigned char *) p)[0];
-
- /* Have to increment the pointer into the pattern string, so the
- caller isn't still at the ending character. */
- (*p_ptr)++;
-
- /* If the start is after the end, the range is empty. */
- if (range_start > range_end)
- return syntax & RE_NO_EMPTY_RANGES ? REG_ERANGE : REG_NOERROR;
-
- /* Here we see why `this_char' has to be larger than an `unsigned
- char' -- the range is inclusive, so if `range_end' == 0xff
- (assuming 8-bit characters), we would otherwise go into an infinite
- loop, since all characters <= 0xff. */
- for (this_char = range_start; this_char <= range_end; this_char++)
- {
- SET_LIST_BIT (TRANSLATE (this_char));
- }
-
- return REG_NOERROR;
-}
-
-/* Failure stack declarations and macros; both re_compile_fastmap and
- re_match_2 use a failure stack. These have to be macros because of
- REGEX_ALLOCATE. */
-
-
-/* Number of failure points for which to initially allocate space
- when matching. If this number is exceeded, we allocate more
- space, so it is not a hard limit. */
-#ifndef INIT_FAILURE_ALLOC
-#define INIT_FAILURE_ALLOC 5
-#endif
-
-/* Roughly the maximum number of failure points on the stack. Would be
- exactly that if always used MAX_FAILURE_SPACE each time we failed.
- This is a variable only so users of regex can assign to it; we never
- change it ourselves. */
-int re_max_failures = 2000;
-
-typedef const unsigned char *fail_stack_elt_t;
-
-typedef struct
-{
- fail_stack_elt_t *stack;
- unsigned size;
- unsigned avail; /* Offset of next open position. */
-} fail_stack_type;
-
-#define FAIL_STACK_EMPTY() (fail_stack.avail == 0)
-#define FAIL_STACK_PTR_EMPTY() (fail_stack_ptr->avail == 0)
-#define FAIL_STACK_FULL() (fail_stack.avail == fail_stack.size)
-#define FAIL_STACK_TOP() (fail_stack.stack[fail_stack.avail])
-
-
-/* Initialize `fail_stack'. Do `return -2' if the alloc fails. */
-
-#define INIT_FAIL_STACK() \
- do { \
- fail_stack.stack = (fail_stack_elt_t *) \
- REGEX_ALLOCATE (INIT_FAILURE_ALLOC * sizeof (fail_stack_elt_t)); \
- \
- if (fail_stack.stack == NULL) \
- return -2; \
- \
- fail_stack.size = INIT_FAILURE_ALLOC; \
- fail_stack.avail = 0; \
- } while (0)
-
-
-/* Double the size of FAIL_STACK, up to approximately `re_max_failures' items.
-
- Return 1 if succeeds, and 0 if either ran out of memory
- allocating space for it or it was already too large.
-
- REGEX_REALLOCATE requires `destination' be declared. */
-
-#define DOUBLE_FAIL_STACK(fail_stack) \
- ((fail_stack).size > re_max_failures * MAX_FAILURE_ITEMS \
- ? 0 \
- : ((fail_stack).stack = (fail_stack_elt_t *) \
- REGEX_REALLOCATE ((fail_stack).stack, \
- (fail_stack).size * sizeof (fail_stack_elt_t), \
- ((fail_stack).size << 1) * sizeof (fail_stack_elt_t)), \
- \
- (fail_stack).stack == NULL \
- ? 0 \
- : ((fail_stack).size <<= 1, \
- 1)))
-
-
-/* Push PATTERN_OP on FAIL_STACK.
-
- Return 1 if was able to do so and 0 if ran out of memory allocating
- space to do so. */
-#define PUSH_PATTERN_OP(pattern_op, fail_stack) \
- ((FAIL_STACK_FULL () \
- && !DOUBLE_FAIL_STACK (fail_stack)) \
- ? 0 \
- : ((fail_stack).stack[(fail_stack).avail++] = pattern_op, \
- 1))
-
-/* This pushes an item onto the failure stack. Must be a four-byte
- value. Assumes the variable `fail_stack'. Probably should only
- be called from within `PUSH_FAILURE_POINT'. */
-#define PUSH_FAILURE_ITEM(item) \
- fail_stack.stack[fail_stack.avail++] = (fail_stack_elt_t) item
-
-/* The complement operation. Assumes `fail_stack' is nonempty. */
-#define POP_FAILURE_ITEM() fail_stack.stack[--fail_stack.avail]
-
-/* Used to omit pushing failure point id's when we're not debugging. */
-#ifdef DEBUG
-#define DEBUG_PUSH PUSH_FAILURE_ITEM
-#define DEBUG_POP(item_addr) *(item_addr) = POP_FAILURE_ITEM ()
-#else
-#define DEBUG_PUSH(item)
-#define DEBUG_POP(item_addr)
-#endif
-
-
-/* Push the information about the state we will need
- if we ever fail back to it.
-
- Requires variables fail_stack, regstart, regend, reg_info, and
- num_regs be declared. DOUBLE_FAIL_STACK requires `destination' be
- declared.
-
- Does `return FAILURE_CODE' if runs out of memory. */
-
-#define PUSH_FAILURE_POINT(pattern_place, string_place, failure_code) \
- do { \
- char *destination; \
- /* Must be int, so when we don't save any registers, the arithmetic \
- of 0 + -1 isn't done as unsigned. */ \
- int this_reg; \
- \
- DEBUG_STATEMENT (failure_id++); \
- DEBUG_STATEMENT (nfailure_points_pushed++); \
- DEBUG_PRINT2 ("\nPUSH_FAILURE_POINT #%u:\n", failure_id); \
- DEBUG_PRINT2 (" Before push, next avail: %d\n", (fail_stack).avail);\
- DEBUG_PRINT2 (" size: %d\n", (fail_stack).size);\
- \
- DEBUG_PRINT2 (" slots needed: %d\n", NUM_FAILURE_ITEMS); \
- DEBUG_PRINT2 (" available: %d\n", REMAINING_AVAIL_SLOTS); \
- \
- /* Ensure we have enough space allocated for what we will push. */ \
- while (REMAINING_AVAIL_SLOTS < NUM_FAILURE_ITEMS) \
- { \
- if (!DOUBLE_FAIL_STACK (fail_stack)) \
- return failure_code; \
- \
- DEBUG_PRINT2 ("\n Doubled stack; size now: %d\n", \
- (fail_stack).size); \
- DEBUG_PRINT2 (" slots available: %d\n", REMAINING_AVAIL_SLOTS);\
- } \
- \
- /* Push the info, starting with the registers. */ \
- DEBUG_PRINT1 ("\n"); \
- \
- for (this_reg = lowest_active_reg; this_reg <= highest_active_reg; \
- this_reg++) \
- { \
- DEBUG_PRINT2 (" Pushing reg: %d\n", this_reg); \
- DEBUG_STATEMENT (num_regs_pushed++); \
- \
- DEBUG_PRINT2 (" start: 0x%x\n", regstart[this_reg]); \
- PUSH_FAILURE_ITEM (regstart[this_reg]); \
- \
- DEBUG_PRINT2 (" end: 0x%x\n", regend[this_reg]); \
- PUSH_FAILURE_ITEM (regend[this_reg]); \
- \
- DEBUG_PRINT2 (" info: 0x%x\n ", reg_info[this_reg]); \
- DEBUG_PRINT2 (" match_null=%d", \
- REG_MATCH_NULL_STRING_P (reg_info[this_reg])); \
- DEBUG_PRINT2 (" active=%d", IS_ACTIVE (reg_info[this_reg])); \
- DEBUG_PRINT2 (" matched_something=%d", \
- MATCHED_SOMETHING (reg_info[this_reg])); \
- DEBUG_PRINT2 (" ever_matched=%d", \
- EVER_MATCHED_SOMETHING (reg_info[this_reg])); \
- DEBUG_PRINT1 ("\n"); \
- PUSH_FAILURE_ITEM (reg_info[this_reg].word); \
- } \
- \
- DEBUG_PRINT2 (" Pushing low active reg: %d\n", lowest_active_reg);\
- PUSH_FAILURE_ITEM (lowest_active_reg); \
- \
- DEBUG_PRINT2 (" Pushing high active reg: %d\n", highest_active_reg);\
- PUSH_FAILURE_ITEM (highest_active_reg); \
- \
- DEBUG_PRINT2 (" Pushing pattern 0x%x: ", pattern_place); \
- DEBUG_PRINT_COMPILED_PATTERN (bufp, pattern_place, pend); \
- PUSH_FAILURE_ITEM (pattern_place); \
- \
- DEBUG_PRINT2 (" Pushing string 0x%x: `", string_place); \
- DEBUG_PRINT_DOUBLE_STRING (string_place, string1, size1, string2, \
- size2); \
- DEBUG_PRINT1 ("'\n"); \
- PUSH_FAILURE_ITEM (string_place); \
- \
- DEBUG_PRINT2 (" Pushing failure id: %u\n", failure_id); \
- DEBUG_PUSH (failure_id); \
- } while (0)
-
-/* This is the number of items that are pushed and popped on the stack
- for each register. */
-#define NUM_REG_ITEMS 3
-
-/* Individual items aside from the registers. */
-#ifdef DEBUG
-#define NUM_NONREG_ITEMS 5 /* Includes failure point id. */
-#else
-#define NUM_NONREG_ITEMS 4
-#endif
-
-/* We push at most this many items on the stack. */
-#define MAX_FAILURE_ITEMS ((num_regs - 1) * NUM_REG_ITEMS + NUM_NONREG_ITEMS)
-
-/* We actually push this many items. */
-#define NUM_FAILURE_ITEMS \
- ((highest_active_reg - lowest_active_reg + 1) * NUM_REG_ITEMS \
- + NUM_NONREG_ITEMS)
-
-/* How many items can still be added to the stack without overflowing it. */
-#define REMAINING_AVAIL_SLOTS ((fail_stack).size - (fail_stack).avail)
-
-
-/* Pops what PUSH_FAIL_STACK pushes.
-
- We restore into the parameters, all of which should be lvalues:
- STR -- the saved data position.
- PAT -- the saved pattern position.
- LOW_REG, HIGH_REG -- the highest and lowest active registers.
- REGSTART, REGEND -- arrays of string positions.
- REG_INFO -- array of information about each subexpression.
-
- Also assumes the variables `fail_stack' and (if debugging), `bufp',
- `pend', `string1', `size1', `string2', and `size2'. */
-
-#define POP_FAILURE_POINT(str, pat, low_reg, high_reg, regstart, regend, reg_info)\
-{ \
- DEBUG_STATEMENT (fail_stack_elt_t failure_id;) \
- int this_reg; \
- const unsigned char *string_temp; \
- \
- assert (!FAIL_STACK_EMPTY ()); \
- \
- /* Remove failure points and point to how many regs pushed. */ \
- DEBUG_PRINT1 ("POP_FAILURE_POINT:\n"); \
- DEBUG_PRINT2 (" Before pop, next avail: %d\n", fail_stack.avail); \
- DEBUG_PRINT2 (" size: %d\n", fail_stack.size); \
- \
- assert (fail_stack.avail >= NUM_NONREG_ITEMS); \
- \
- DEBUG_POP (&failure_id); \
- DEBUG_PRINT2 (" Popping failure id: %u\n", failure_id); \
- \
- /* If the saved string location is NULL, it came from an \
- on_failure_keep_string_jump opcode, and we want to throw away the \
- saved NULL, thus retaining our current position in the string. */ \
- string_temp = POP_FAILURE_ITEM (); \
- if (string_temp != NULL) \
- str = (const char *) string_temp; \
- \
- DEBUG_PRINT2 (" Popping string 0x%x: `", str); \
- DEBUG_PRINT_DOUBLE_STRING (str, string1, size1, string2, size2); \
- DEBUG_PRINT1 ("'\n"); \
- \
- pat = (unsigned char *) POP_FAILURE_ITEM (); \
- DEBUG_PRINT2 (" Popping pattern 0x%x: ", pat); \
- DEBUG_PRINT_COMPILED_PATTERN (bufp, pat, pend); \
- \
- /* Restore register info. */ \
- high_reg = (unsigned) POP_FAILURE_ITEM (); \
- DEBUG_PRINT2 (" Popping high active reg: %d\n", high_reg); \
- \
- low_reg = (unsigned) POP_FAILURE_ITEM (); \
- DEBUG_PRINT2 (" Popping low active reg: %d\n", low_reg); \
- \
- for (this_reg = high_reg; this_reg >= low_reg; this_reg--) \
- { \
- DEBUG_PRINT2 (" Popping reg: %d\n", this_reg); \
- \
- reg_info[this_reg].word = POP_FAILURE_ITEM (); \
- DEBUG_PRINT2 (" info: 0x%x\n", reg_info[this_reg]); \
- \
- regend[this_reg] = (const char *) POP_FAILURE_ITEM (); \
- DEBUG_PRINT2 (" end: 0x%x\n", regend[this_reg]); \
- \
- regstart[this_reg] = (const char *) POP_FAILURE_ITEM (); \
- DEBUG_PRINT2 (" start: 0x%x\n", regstart[this_reg]); \
- } \
- \
- DEBUG_STATEMENT (nfailure_points_popped++); \
-} /* POP_FAILURE_POINT */
-
-/* re_compile_fastmap computes a ``fastmap'' for the compiled pattern in
- BUFP. A fastmap records which of the (1 << BYTEWIDTH) possible
- characters can start a string that matches the pattern. This fastmap
- is used by re_search to skip quickly over impossible starting points.
-
- The caller must supply the address of a (1 << BYTEWIDTH)-byte data
- area as BUFP->fastmap.
-
- We set the `fastmap', `fastmap_accurate', and `can_be_null' fields in
- the pattern buffer.
-
- Returns 0 if we succeed, -2 if an internal error. */
-
-int
-re_compile_fastmap (bufp)
- struct re_pattern_buffer *bufp;
-{
- int j, k;
- fail_stack_type fail_stack;
-#ifndef REGEX_MALLOC
- char *destination;
-#endif
- /* We don't push any register information onto the failure stack. */
- unsigned num_regs = 0;
-
- register char *fastmap = bufp->fastmap;
- unsigned char *pattern = bufp->buffer;
- unsigned long size = bufp->used;
- const unsigned char *p = pattern;
- register unsigned char *pend = pattern + size;
-
- /* Assume that each path through the pattern can be null until
- proven otherwise. We set this false at the bottom of switch
- statement, to which we get only if a particular path doesn't
- match the empty string. */
- boolean path_can_be_null = true;
-
- /* We aren't doing a `succeed_n' to begin with. */
- boolean succeed_n_p = false;
-
- assert (fastmap != NULL && p != NULL);
-
- INIT_FAIL_STACK ();
- bzero (fastmap, 1 << BYTEWIDTH); /* Assume nothing's valid. */
- bufp->fastmap_accurate = 1; /* It will be when we're done. */
- bufp->can_be_null = 0;
-
- while (p != pend || !FAIL_STACK_EMPTY ())
- {
- if (p == pend)
- {
- bufp->can_be_null |= path_can_be_null;
-
- /* Reset for next path. */
- path_can_be_null = true;
-
- p = fail_stack.stack[--fail_stack.avail];
- }
-
- /* We should never be about to go beyond the end of the pattern. */
- assert (p < pend);
-
-#ifdef SWITCH_ENUM_BUG
- switch ((int) ((re_opcode_t) *p++))
-#else
- switch ((re_opcode_t) *p++)
-#endif
- {
-
- /* I guess the idea here is to simply not bother with a fastmap
- if a backreference is used, since it's too hard to figure out
- the fastmap for the corresponding group. Setting
- `can_be_null' stops `re_search_2' from using the fastmap, so
- that is all we do. */
- case duplicate:
- bufp->can_be_null = 1;
- return 0;
-
-
- /* Following are the cases which match a character. These end
- with `break'. */
-
- case exactn:
- fastmap[p[1]] = 1;
- break;
-
-
- case charset:
- for (j = *p++ * BYTEWIDTH - 1; j >= 0; j--)
- if (p[j / BYTEWIDTH] & (1 << (j % BYTEWIDTH)))
- fastmap[j] = 1;
- break;
-
-
- case charset_not:
- /* Chars beyond end of map must be allowed. */
- for (j = *p * BYTEWIDTH; j < (1 << BYTEWIDTH); j++)
- fastmap[j] = 1;
-
- for (j = *p++ * BYTEWIDTH - 1; j >= 0; j--)
- if (!(p[j / BYTEWIDTH] & (1 << (j % BYTEWIDTH))))
- fastmap[j] = 1;
- break;
-
-
- case wordchar:
- for (j = 0; j < (1 << BYTEWIDTH); j++)
- if (SYNTAX (j) == Sword)
- fastmap[j] = 1;
- break;
-
-
- case notwordchar:
- for (j = 0; j < (1 << BYTEWIDTH); j++)
- if (SYNTAX (j) != Sword)
- fastmap[j] = 1;
- break;
-
-
- case anychar:
- /* `.' matches anything ... */
- for (j = 0; j < (1 << BYTEWIDTH); j++)
- fastmap[j] = 1;
-
- /* ... except perhaps newline. */
- if (!(bufp->syntax & RE_DOT_NEWLINE))
- fastmap['\n'] = 0;
-
- /* Return if we have already set `can_be_null'; if we have,
- then the fastmap is irrelevant. Something's wrong here. */
- else if (bufp->can_be_null)
- return 0;
-
- /* Otherwise, have to check alternative paths. */
- break;
-
-
-#ifdef emacs
- case syntaxspec:
- k = *p++;
- for (j = 0; j < (1 << BYTEWIDTH); j++)
- if (SYNTAX (j) == (enum syntaxcode) k)
- fastmap[j] = 1;
- break;
-
-
- case notsyntaxspec:
- k = *p++;
- for (j = 0; j < (1 << BYTEWIDTH); j++)
- if (SYNTAX (j) != (enum syntaxcode) k)
- fastmap[j] = 1;
- break;
-
-
- /* All cases after this match the empty string. These end with
- `continue'. */
-
-
- case before_dot:
- case at_dot:
- case after_dot:
- continue;
-#endif /* not emacs */
-
-
- case no_op:
- case begline:
- case endline:
- case begbuf:
- case endbuf:
- case wordbound:
- case notwordbound:
- case wordbeg:
- case wordend:
- case push_dummy_failure:
- continue;
-
-
- case jump_n:
- case pop_failure_jump:
- case maybe_pop_jump:
- case jump:
- case jump_past_alt:
- case dummy_failure_jump:
- EXTRACT_NUMBER_AND_INCR (j, p);
- p += j;
- if (j > 0)
- continue;
-
- /* Jump backward implies we just went through the body of a
- loop and matched nothing. Opcode jumped to should be
- `on_failure_jump' or `succeed_n'. Just treat it like an
- ordinary jump. For a * loop, it has pushed its failure
- point already; if so, discard that as redundant. */
- if ((re_opcode_t) *p != on_failure_jump
- && (re_opcode_t) *p != succeed_n)
- continue;
-
- p++;
- EXTRACT_NUMBER_AND_INCR (j, p);
- p += j;
-
- /* If what's on the stack is where we are now, pop it. */
- if (!FAIL_STACK_EMPTY ()
- && fail_stack.stack[fail_stack.avail - 1] == p)
- fail_stack.avail--;
-
- continue;
-
-
- case on_failure_jump:
- case on_failure_keep_string_jump:
- handle_on_failure_jump:
- EXTRACT_NUMBER_AND_INCR (j, p);
-
- /* For some patterns, e.g., `(a?)?', `p+j' here points to the
- end of the pattern. We don't want to push such a point,
- since when we restore it above, entering the switch will
- increment `p' past the end of the pattern. We don't need
- to push such a point since we obviously won't find any more
- fastmap entries beyond `pend'. Such a pattern can match
- the null string, though. */
- if (p + j < pend)
- {
- if (!PUSH_PATTERN_OP (p + j, fail_stack))
- return -2;
- }
- else
- bufp->can_be_null = 1;
-
- if (succeed_n_p)
- {
- EXTRACT_NUMBER_AND_INCR (k, p); /* Skip the n. */
- succeed_n_p = false;
- }
-
- continue;
-
-
- case succeed_n:
- /* Get to the number of times to succeed. */
- p += 2;
-
- /* Increment p past the n for when k != 0. */
- EXTRACT_NUMBER_AND_INCR (k, p);
- if (k == 0)
- {
- p -= 4;
- succeed_n_p = true; /* Spaghetti code alert. */
- goto handle_on_failure_jump;
- }
- continue;
-
-
- case set_number_at:
- p += 4;
- continue;
-
-
- case start_memory:
- case stop_memory:
- p += 2;
- continue;
-
-
- default:
- abort (); /* We have listed all the cases. */
- } /* switch *p++ */
-
- /* Getting here means we have found the possible starting
- characters for one path of the pattern -- and that the empty
- string does not match. We need not follow this path further.
- Instead, look at the next alternative (remembered on the
- stack), or quit if no more. The test at the top of the loop
- does these things. */
- path_can_be_null = false;
- p = pend;
- } /* while p */
-
- /* Set `can_be_null' for the last path (also the first path, if the
- pattern is empty). */
- bufp->can_be_null |= path_can_be_null;
- return 0;
-} /* re_compile_fastmap */
-
-/* Set REGS to hold NUM_REGS registers, storing them in STARTS and
- ENDS. Subsequent matches using PATTERN_BUFFER and REGS will use
- this memory for recording register information. STARTS and ENDS
- must be allocated using the malloc library routine, and must each
- be at least NUM_REGS * sizeof (regoff_t) bytes long.
-
- If NUM_REGS == 0, then subsequent matches should allocate their own
- register data.
-
- Unless this function is called, the first search or match using
- PATTERN_BUFFER will allocate its own register data, without
- freeing the old data. */
-
-void
-re_set_registers (bufp, regs, num_regs, starts, ends)
- struct re_pattern_buffer *bufp;
- struct re_registers *regs;
- unsigned num_regs;
- regoff_t *starts, *ends;
-{
- if (num_regs)
- {
- bufp->regs_allocated = REGS_REALLOCATE;
- regs->num_regs = num_regs;
- regs->start = starts;
- regs->end = ends;
- }
- else
- {
- bufp->regs_allocated = REGS_UNALLOCATED;
- regs->num_regs = 0;
- regs->start = regs->end = (regoff_t) 0;
- }
-}
-
-/* Searching routines. */
-
-/* Like re_search_2, below, but only one string is specified, and
- doesn't let you say where to stop matching. */
-
-int
-re_search (bufp, string, size, startpos, range, regs)
- struct re_pattern_buffer *bufp;
- const char *string;
- int size, startpos, range;
- struct re_registers *regs;
-{
- return re_search_2 (bufp, NULL, 0, string, size, startpos, range,
- regs, size);
-}
-
-
-/* Using the compiled pattern in BUFP->buffer, first tries to match the
- virtual concatenation of STRING1 and STRING2, starting first at index
- STARTPOS, then at STARTPOS + 1, and so on.
-
- STRING1 and STRING2 have length SIZE1 and SIZE2, respectively.
-
- RANGE is how far to scan while trying to match. RANGE = 0 means try
- only at STARTPOS; in general, the last start tried is STARTPOS +
- RANGE.
-
- In REGS, return the indices of the virtual concatenation of STRING1
- and STRING2 that matched the entire BUFP->buffer and its contained
- subexpressions.
-
- Do not consider matching one past the index STOP in the virtual
- concatenation of STRING1 and STRING2.
-
- We return either the position in the strings at which the match was
- found, -1 if no match, or -2 if error (such as failure
- stack overflow). */
-
-int
-re_search_2 (bufp, string1, size1, string2, size2, startpos, range, regs, stop)
- struct re_pattern_buffer *bufp;
- const char *string1, *string2;
- int size1, size2;
- int startpos;
- int range;
- struct re_registers *regs;
- int stop;
-{
- int val;
- register char *fastmap = bufp->fastmap;
- register char *translate = bufp->translate;
- int total_size = size1 + size2;
- int endpos = startpos + range;
-
- /* Check for out-of-range STARTPOS. */
- if (startpos < 0 || startpos > total_size)
- return -1;
-
- /* Fix up RANGE if it might eventually take us outside
- the virtual concatenation of STRING1 and STRING2. */
- if (endpos < -1)
- range = -1 - startpos;
- else if (endpos > total_size)
- range = total_size - startpos;
-
- /* If the search isn't to be a backwards one, don't waste time in a
- search for a pattern that must be anchored. */
- if (bufp->used > 0 && (re_opcode_t) bufp->buffer[0] == begbuf && range > 0)
- {
- if (startpos > 0)
- return -1;
- else
- range = 1;
- }
-
- /* Update the fastmap now if not correct already. */
- if (fastmap && !bufp->fastmap_accurate)
- if (re_compile_fastmap (bufp) == -2)
- return -2;
-
- /* Loop through the string, looking for a place to start matching. */
- for (;;)
- {
- /* If a fastmap is supplied, skip quickly over characters that
- cannot be the start of a match. If the pattern can match the
- null string, however, we don't need to skip characters; we want
- the first null string. */
- if (fastmap && startpos < total_size && !bufp->can_be_null)
- {
- if (range > 0) /* Searching forwards. */
- {
- register const char *d;
- register int lim = 0;
- int irange = range;
-
- if (startpos < size1 && startpos + range >= size1)
- lim = range - (size1 - startpos);
-
- d = (startpos >= size1 ? string2 - size1 : string1) + startpos;
-
- /* Written out as an if-else to avoid testing `translate'
- inside the loop. */
- if (translate)
- while (range > lim
- && !fastmap[(unsigned char)
- translate[(unsigned char) *d++]])
- range--;
- else
- while (range > lim && !fastmap[(unsigned char) *d++])
- range--;
-
- startpos += irange - range;
- }
- else /* Searching backwards. */
- {
- register char c = (size1 == 0 || startpos >= size1
- ? string2[startpos - size1]
- : string1[startpos]);
-
- if (!fastmap[(unsigned char) TRANSLATE (c)])
- goto advance;
- }
- }
-
- /* If can't match the null string, and that's all we have left, fail. */
- if (range >= 0 && startpos == total_size && fastmap
- && !bufp->can_be_null)
- return -1;
-
- val = re_match_2 (bufp, string1, size1, string2, size2,
- startpos, regs, stop);
- if (val >= 0)
- return startpos;
-
- if (val == -2)
- return -2;
-
- advance:
- if (!range)
- break;
- else if (range > 0)
- {
- range--;
- startpos++;
- }
- else
- {
- range++;
- startpos--;
- }
- }
- return -1;
-} /* re_search_2 */
-
-/* Declarations and macros for re_match_2. */
-
-static int bcmp_translate ();
-static boolean alt_match_null_string_p (),
- common_op_match_null_string_p (),
- group_match_null_string_p ();
-
-/* Structure for per-register (a.k.a. per-group) information.
- This must not be longer than one word, because we push this value
- onto the failure stack. Other register information, such as the
- starting and ending positions (which are addresses), and the list of
- inner groups (which is a bits list) are maintained in separate
- variables.
-
- We are making a (strictly speaking) nonportable assumption here: that
- the compiler will pack our bit fields into something that fits into
- the type of `word', i.e., is something that fits into one item on the
- failure stack. */
-typedef union
-{
- fail_stack_elt_t word;
- struct
- {
- /* This field is one if this group can match the empty string,
- zero if not. If not yet determined, `MATCH_NULL_UNSET_VALUE'. */
-#define MATCH_NULL_UNSET_VALUE 3
- unsigned match_null_string_p : 2;
- unsigned is_active : 1;
- unsigned matched_something : 1;
- unsigned ever_matched_something : 1;
- } bits;
-} register_info_type;
-
-#define REG_MATCH_NULL_STRING_P(R) ((R).bits.match_null_string_p)
-#define IS_ACTIVE(R) ((R).bits.is_active)
-#define MATCHED_SOMETHING(R) ((R).bits.matched_something)
-#define EVER_MATCHED_SOMETHING(R) ((R).bits.ever_matched_something)
-
-
-/* Call this when have matched a real character; it sets `matched' flags
- for the subexpressions which we are currently inside. Also records
- that those subexprs have matched. */
-#define SET_REGS_MATCHED() \
- do \
- { \
- unsigned r; \
- for (r = lowest_active_reg; r <= highest_active_reg; r++) \
- { \
- MATCHED_SOMETHING (reg_info[r]) \
- = EVER_MATCHED_SOMETHING (reg_info[r]) \
- = 1; \
- } \
- } \
- while (0)
-
-
-/* This converts PTR, a pointer into one of the search strings `string1'
- and `string2' into an offset from the beginning of that string. */
-#define POINTER_TO_OFFSET(ptr) \
- (FIRST_STRING_P (ptr) ? (ptr) - string1 : (ptr) - string2 + size1)
-
-/* Registers are set to a sentinel when they haven't yet matched. */
-#define REG_UNSET_VALUE ((char *) -1)
-#define REG_UNSET(e) ((e) == REG_UNSET_VALUE)
-
-
-/* Macros for dealing with the split strings in re_match_2. */
-
-#define MATCHING_IN_FIRST_STRING (dend == end_match_1)
-
-/* Call before fetching a character with *d. This switches over to
- string2 if necessary. */
-#define PREFETCH() \
- while (d == dend) \
- { \
- /* End of string2 => fail. */ \
- if (dend == end_match_2) \
- goto fail; \
- /* End of string1 => advance to string2. */ \
- d = string2; \
- dend = end_match_2; \
- }
-
-
-/* Test if at very beginning or at very end of the virtual concatenation
- of `string1' and `string2'. If only one string, it's `string2'. */
-#define AT_STRINGS_BEG(d) ((d) == (size1 ? string1 : string2) || !size2)
-#define AT_STRINGS_END(d) ((d) == end2)
-
-
-/* Test if D points to a character which is word-constituent. We have
- two special cases to check for: if past the end of string1, look at
- the first character in string2; and if before the beginning of
- string2, look at the last character in string1. */
-#define WORDCHAR_P(d) \
- (SYNTAX ((d) == end1 ? *string2 \
- : (d) == string2 - 1 ? *(end1 - 1) : *(d)) \
- == Sword)
-
-/* Test if the character before D and the one at D differ with respect
- to being word-constituent. */
-#define AT_WORD_BOUNDARY(d) \
- (AT_STRINGS_BEG (d) || AT_STRINGS_END (d) \
- || WORDCHAR_P (d - 1) != WORDCHAR_P (d))
-
-
-/* Free everything we malloc. */
-#ifdef REGEX_MALLOC
-#define FREE_VAR(var) if (var) free (var); var = NULL
-#define FREE_VARIABLES() \
- do { \
- FREE_VAR (fail_stack.stack); \
- FREE_VAR (regstart); \
- FREE_VAR (regend); \
- FREE_VAR (old_regstart); \
- FREE_VAR (old_regend); \
- FREE_VAR (best_regstart); \
- FREE_VAR (best_regend); \
- FREE_VAR (reg_info); \
- FREE_VAR (reg_dummy); \
- FREE_VAR (reg_info_dummy); \
- } while (0)
-#else /* not REGEX_MALLOC */
-/* Some MIPS systems (at least) want this to free alloca'd storage. */
-#define FREE_VARIABLES() alloca (0)
-#endif /* not REGEX_MALLOC */
-
-
-/* These values must meet several constraints. They must not be valid
- register values; since we have a limit of 255 registers (because
- we use only one byte in the pattern for the register number), we can
- use numbers larger than 255. They must differ by 1, because of
- NUM_FAILURE_ITEMS above. And the value for the lowest register must
- be larger than the value for the highest register, so we do not try
- to actually save any registers when none are active. */
-#define NO_HIGHEST_ACTIVE_REG (1 << BYTEWIDTH)
-#define NO_LOWEST_ACTIVE_REG (NO_HIGHEST_ACTIVE_REG + 1)
-
-/* Matching routines. */
-
-#ifndef emacs /* Emacs never uses this. */
-/* re_match is like re_match_2 except it takes only a single string. */
-
-int
-re_match (bufp, string, size, pos, regs)
- struct re_pattern_buffer *bufp;
- const char *string;
- int size, pos;
- struct re_registers *regs;
- {
- return re_match_2 (bufp, NULL, 0, string, size, pos, regs, size);
-}
-#endif /* not emacs */
-
-
-/* re_match_2 matches the compiled pattern in BUFP against the
- the (virtual) concatenation of STRING1 and STRING2 (of length SIZE1
- and SIZE2, respectively). We start matching at POS, and stop
- matching at STOP.
-
- If REGS is non-null and the `no_sub' field of BUFP is nonzero, we
- store offsets for the substring each group matched in REGS. See the
- documentation for exactly how many groups we fill.
-
- We return -1 if no match, -2 if an internal error (such as the
- failure stack overflowing). Otherwise, we return the length of the
- matched substring. */
-
-int
-re_match_2 (bufp, string1, size1, string2, size2, pos, regs, stop)
- struct re_pattern_buffer *bufp;
- const char *string1, *string2;
- int size1, size2;
- int pos;
- struct re_registers *regs;
- int stop;
-{
- /* General temporaries. */
- int mcnt;
- unsigned char *p1;
-
- /* Just past the end of the corresponding string. */
- const char *end1, *end2;
-
- /* Pointers into string1 and string2, just past the last characters in
- each to consider matching. */
- const char *end_match_1, *end_match_2;
-
- /* Where we are in the data, and the end of the current string. */
- const char *d, *dend;
-
- /* Where we are in the pattern, and the end of the pattern. */
- unsigned char *p = bufp->buffer;
- register unsigned char *pend = p + bufp->used;
-
- /* We use this to map every character in the string. */
- char *translate = bufp->translate;
-
- /* Failure point stack. Each place that can handle a failure further
- down the line pushes a failure point on this stack. It consists of
- restart, regend, and reg_info for all registers corresponding to
- the subexpressions we're currently inside, plus the number of such
- registers, and, finally, two char *'s. The first char * is where
- to resume scanning the pattern; the second one is where to resume
- scanning the strings. If the latter is zero, the failure point is
- a ``dummy''; if a failure happens and the failure point is a dummy,
- it gets discarded and the next next one is tried. */
- fail_stack_type fail_stack;
-#ifdef DEBUG
- static unsigned failure_id = 0;
- unsigned nfailure_points_pushed = 0, nfailure_points_popped = 0;
-#endif
-
- /* We fill all the registers internally, independent of what we
- return, for use in backreferences. The number here includes
- an element for register zero. */
- unsigned num_regs = bufp->re_nsub + 1;
-
- /* The currently active registers. */
- unsigned lowest_active_reg = NO_LOWEST_ACTIVE_REG;
- unsigned highest_active_reg = NO_HIGHEST_ACTIVE_REG;
-
- /* Information on the contents of registers. These are pointers into
- the input strings; they record just what was matched (on this
- attempt) by a subexpression part of the pattern, that is, the
- regnum-th regstart pointer points to where in the pattern we began
- matching and the regnum-th regend points to right after where we
- stopped matching the regnum-th subexpression. (The zeroth register
- keeps track of what the whole pattern matches.) */
- const char **regstart, **regend;
-
- /* If a group that's operated upon by a repetition operator fails to
- match anything, then the register for its start will need to be
- restored because it will have been set to wherever in the string we
- are when we last see its open-group operator. Similarly for a
- register's end. */
- const char **old_regstart, **old_regend;
-
- /* The is_active field of reg_info helps us keep track of which (possibly
- nested) subexpressions we are currently in. The matched_something
- field of reg_info[reg_num] helps us tell whether or not we have
- matched any of the pattern so far this time through the reg_num-th
- subexpression. These two fields get reset each time through any
- loop their register is in. */
- register_info_type *reg_info;
-
- /* The following record the register info as found in the above
- variables when we find a match better than any we've seen before.
- This happens as we backtrack through the failure points, which in
- turn happens only if we have not yet matched the entire string. */
- unsigned best_regs_set = false;
- const char **best_regstart, **best_regend;
-
- /* Logically, this is `best_regend[0]'. But we don't want to have to
- allocate space for that if we're not allocating space for anything
- else (see below). Also, we never need info about register 0 for
- any of the other register vectors, and it seems rather a kludge to
- treat `best_regend' differently than the rest. So we keep track of
- the end of the best match so far in a separate variable. We
- initialize this to NULL so that when we backtrack the first time
- and need to test it, it's not garbage. */
- const char *match_end = NULL;
-
- /* Used when we pop values we don't care about. */
- const char **reg_dummy;
- register_info_type *reg_info_dummy;
-
-#ifdef DEBUG
- /* Counts the total number of registers pushed. */
- unsigned num_regs_pushed = 0;
-#endif
-
- DEBUG_PRINT1 ("\n\nEntering re_match_2.\n");
-
- INIT_FAIL_STACK ();
-
- /* Do not bother to initialize all the register variables if there are
- no groups in the pattern, as it takes a fair amount of time. If
- there are groups, we include space for register 0 (the whole
- pattern), even though we never use it, since it simplifies the
- array indexing. We should fix this. */
- if (bufp->re_nsub)
- {
- regstart = REGEX_TALLOC (num_regs, const char *);
- regend = REGEX_TALLOC (num_regs, const char *);
- old_regstart = REGEX_TALLOC (num_regs, const char *);
- old_regend = REGEX_TALLOC (num_regs, const char *);
- best_regstart = REGEX_TALLOC (num_regs, const char *);
- best_regend = REGEX_TALLOC (num_regs, const char *);
- reg_info = REGEX_TALLOC (num_regs, register_info_type);
- reg_dummy = REGEX_TALLOC (num_regs, const char *);
- reg_info_dummy = REGEX_TALLOC (num_regs, register_info_type);
-
- if (!(regstart && regend && old_regstart && old_regend && reg_info
- && best_regstart && best_regend && reg_dummy && reg_info_dummy))
- {
- FREE_VARIABLES ();
- return -2;
- }
- }
-#ifdef REGEX_MALLOC
- else
- {
- /* We must initialize all our variables to NULL, so that
- `FREE_VARIABLES' doesn't try to free them. */
- regstart = regend = old_regstart = old_regend = best_regstart
- = best_regend = reg_dummy = NULL;
- reg_info = reg_info_dummy = (register_info_type *) NULL;
- }
-#endif /* REGEX_MALLOC */
-
- /* The starting position is bogus. */
- if (pos < 0 || pos > size1 + size2)
- {
- FREE_VARIABLES ();
- return -1;
- }
-
- /* Initialize subexpression text positions to -1 to mark ones that no
- start_memory/stop_memory has been seen for. Also initialize the
- register information struct. */
- for (mcnt = 1; mcnt < num_regs; mcnt++)
- {
- regstart[mcnt] = regend[mcnt]
- = old_regstart[mcnt] = old_regend[mcnt] = REG_UNSET_VALUE;
-
- REG_MATCH_NULL_STRING_P (reg_info[mcnt]) = MATCH_NULL_UNSET_VALUE;
- IS_ACTIVE (reg_info[mcnt]) = 0;
- MATCHED_SOMETHING (reg_info[mcnt]) = 0;
- EVER_MATCHED_SOMETHING (reg_info[mcnt]) = 0;
- }
-
- /* We move `string1' into `string2' if the latter's empty -- but not if
- `string1' is null. */
- if (size2 == 0 && string1 != NULL)
- {
- string2 = string1;
- size2 = size1;
- string1 = 0;
- size1 = 0;
- }
- end1 = string1 + size1;
- end2 = string2 + size2;
-
- /* Compute where to stop matching, within the two strings. */
- if (stop <= size1)
- {
- end_match_1 = string1 + stop;
- end_match_2 = string2;
- }
- else
- {
- end_match_1 = end1;
- end_match_2 = string2 + stop - size1;
- }
-
- /* `p' scans through the pattern as `d' scans through the data.
- `dend' is the end of the input string that `d' points within. `d'
- is advanced into the following input string whenever necessary, but
- this happens before fetching; therefore, at the beginning of the
- loop, `d' can be pointing at the end of a string, but it cannot
- equal `string2'. */
- if (size1 > 0 && pos <= size1)
- {
- d = string1 + pos;
- dend = end_match_1;
- }
- else
- {
- d = string2 + pos - size1;
- dend = end_match_2;
- }
-
- DEBUG_PRINT1 ("The compiled pattern is: ");
- DEBUG_PRINT_COMPILED_PATTERN (bufp, p, pend);
- DEBUG_PRINT1 ("The string to match is: `");
- DEBUG_PRINT_DOUBLE_STRING (d, string1, size1, string2, size2);
- DEBUG_PRINT1 ("'\n");
-
- /* This loops over pattern commands. It exits by returning from the
- function if the match is complete, or it drops through if the match
- fails at this starting point in the input data. */
- for (;;)
- {
- DEBUG_PRINT2 ("\n0x%x: ", p);
-
- if (p == pend)
- { /* End of pattern means we might have succeeded. */
- DEBUG_PRINT1 ("end of pattern ... ");
-
- /* If we haven't matched the entire string, and we want the
- longest match, try backtracking. */
- if (d != end_match_2)
- {
- DEBUG_PRINT1 ("backtracking.\n");
-
- if (!FAIL_STACK_EMPTY ())
- { /* More failure points to try. */
- boolean same_str_p = (FIRST_STRING_P (match_end)
- == MATCHING_IN_FIRST_STRING);
-
- /* If exceeds best match so far, save it. */
- if (!best_regs_set
- || (same_str_p && d > match_end)
- || (!same_str_p && !MATCHING_IN_FIRST_STRING))
- {
- best_regs_set = true;
- match_end = d;
-
- DEBUG_PRINT1 ("\nSAVING match as best so far.\n");
-
- for (mcnt = 1; mcnt < num_regs; mcnt++)
- {
- best_regstart[mcnt] = regstart[mcnt];
- best_regend[mcnt] = regend[mcnt];
- }
- }
- goto fail;
- }
-
- /* If no failure points, don't restore garbage. */
- else if (best_regs_set)
- {
- restore_best_regs:
- /* Restore best match. It may happen that `dend ==
- end_match_1' while the restored d is in string2.
- For example, the pattern `x.*y.*z' against the
- strings `x-' and `y-z-', if the two strings are
- not consecutive in memory. */
- DEBUG_PRINT1 ("Restoring best registers.\n");
-
- d = match_end;
- dend = ((d >= string1 && d <= end1)
- ? end_match_1 : end_match_2);
-
- for (mcnt = 1; mcnt < num_regs; mcnt++)
- {
- regstart[mcnt] = best_regstart[mcnt];
- regend[mcnt] = best_regend[mcnt];
- }
- }
- } /* d != end_match_2 */
-
- DEBUG_PRINT1 ("Accepting match.\n");
-
- /* If caller wants register contents data back, do it. */
- if (regs && !bufp->no_sub)
- {
- /* Have the register data arrays been allocated? */
- if (bufp->regs_allocated == REGS_UNALLOCATED)
- { /* No. So allocate them with malloc. We need one
- extra element beyond `num_regs' for the `-1' marker
- GNU code uses. */
- regs->num_regs = MAX (RE_NREGS, num_regs + 1);
- regs->start = TALLOC (regs->num_regs, regoff_t);
- regs->end = TALLOC (regs->num_regs, regoff_t);
- if (regs->start == NULL || regs->end == NULL)
- return -2;
- bufp->regs_allocated = REGS_REALLOCATE;
- }
- else if (bufp->regs_allocated == REGS_REALLOCATE)
- { /* Yes. If we need more elements than were already
- allocated, reallocate them. If we need fewer, just
- leave it alone. */
- if (regs->num_regs < num_regs + 1)
- {
- regs->num_regs = num_regs + 1;
- RETALLOC (regs->start, regs->num_regs, regoff_t);
- RETALLOC (regs->end, regs->num_regs, regoff_t);
- if (regs->start == NULL || regs->end == NULL)
- return -2;
- }
- }
- else
- assert (bufp->regs_allocated == REGS_FIXED);
-
- /* Convert the pointer data in `regstart' and `regend' to
- indices. Register zero has to be set differently,
- since we haven't kept track of any info for it. */
- if (regs->num_regs > 0)
- {
- regs->start[0] = pos;
- regs->end[0] = (MATCHING_IN_FIRST_STRING ? d - string1
- : d - string2 + size1);
- }
-
- /* Go through the first `min (num_regs, regs->num_regs)'
- registers, since that is all we initialized. */
- for (mcnt = 1; mcnt < MIN (num_regs, regs->num_regs); mcnt++)
- {
- if (REG_UNSET (regstart[mcnt]) || REG_UNSET (regend[mcnt]))
- regs->start[mcnt] = regs->end[mcnt] = -1;
- else
- {
- regs->start[mcnt] = POINTER_TO_OFFSET (regstart[mcnt]);
- regs->end[mcnt] = POINTER_TO_OFFSET (regend[mcnt]);
- }
- }
-
- /* If the regs structure we return has more elements than
- were in the pattern, set the extra elements to -1. If
- we (re)allocated the registers, this is the case,
- because we always allocate enough to have at least one
- -1 at the end. */
- for (mcnt = num_regs; mcnt < regs->num_regs; mcnt++)
- regs->start[mcnt] = regs->end[mcnt] = -1;
- } /* regs && !bufp->no_sub */
-
- FREE_VARIABLES ();
- DEBUG_PRINT4 ("%u failure points pushed, %u popped (%u remain).\n",
- nfailure_points_pushed, nfailure_points_popped,
- nfailure_points_pushed - nfailure_points_popped);
- DEBUG_PRINT2 ("%u registers pushed.\n", num_regs_pushed);
-
- mcnt = d - pos - (MATCHING_IN_FIRST_STRING
- ? string1
- : string2 - size1);
-
- DEBUG_PRINT2 ("Returning %d from re_match_2.\n", mcnt);
-
- return mcnt;
- }
-
- /* Otherwise match next pattern command. */
-#ifdef SWITCH_ENUM_BUG
- switch ((int) ((re_opcode_t) *p++))
-#else
- switch ((re_opcode_t) *p++)
-#endif
- {
- /* Ignore these. Used to ignore the n of succeed_n's which
- currently have n == 0. */
- case no_op:
- DEBUG_PRINT1 ("EXECUTING no_op.\n");
- break;
-
-
- /* Match the next n pattern characters exactly. The following
- byte in the pattern defines n, and the n bytes after that
- are the characters to match. */
- case exactn:
- mcnt = *p++;
- DEBUG_PRINT2 ("EXECUTING exactn %d.\n", mcnt);
-
- /* This is written out as an if-else so we don't waste time
- testing `translate' inside the loop. */
- if (translate)
- {
- do
- {
- PREFETCH ();
- if (translate[(unsigned char) *d++] != (char) *p++)
- goto fail;
- }
- while (--mcnt);
- }
- else
- {
- do
- {
- PREFETCH ();
- if (*d++ != (char) *p++) goto fail;
- }
- while (--mcnt);
- }
- SET_REGS_MATCHED ();
- break;
-
-
- /* Match any character except possibly a newline or a null. */
- case anychar:
- DEBUG_PRINT1 ("EXECUTING anychar.\n");
-
- PREFETCH ();
-
- if ((!(bufp->syntax & RE_DOT_NEWLINE) && TRANSLATE (*d) == '\n')
- || (bufp->syntax & RE_DOT_NOT_NULL && TRANSLATE (*d) == '\000'))
- goto fail;
-
- SET_REGS_MATCHED ();
- DEBUG_PRINT2 (" Matched `%d'.\n", *d);
- d++;
- break;
-
-
- case charset:
- case charset_not:
- {
- register unsigned char c;
- boolean not = (re_opcode_t) *(p - 1) == charset_not;
-
- DEBUG_PRINT2 ("EXECUTING charset%s.\n", not ? "_not" : "");
-
- PREFETCH ();
- c = TRANSLATE (*d); /* The character to match. */
-
- /* Cast to `unsigned' instead of `unsigned char' in case the
- bit list is a full 32 bytes long. */
- if (c < (unsigned) (*p * BYTEWIDTH)
- && p[1 + c / BYTEWIDTH] & (1 << (c % BYTEWIDTH)))
- not = !not;
-
- p += 1 + *p;
-
- if (!not) goto fail;
-
- SET_REGS_MATCHED ();
- d++;
- break;
- }
-
-
- /* The beginning of a group is represented by start_memory.
- The arguments are the register number in the next byte, and the
- number of groups inner to this one in the next. The text
- matched within the group is recorded (in the internal
- registers data structure) under the register number. */
- case start_memory:
- DEBUG_PRINT3 ("EXECUTING start_memory %d (%d):\n", *p, p[1]);
-
- /* Find out if this group can match the empty string. */
- p1 = p; /* To send to group_match_null_string_p. */
-
- if (REG_MATCH_NULL_STRING_P (reg_info[*p]) == MATCH_NULL_UNSET_VALUE)
- REG_MATCH_NULL_STRING_P (reg_info[*p])
- = group_match_null_string_p (&p1, pend, reg_info);
-
- /* Save the position in the string where we were the last time
- we were at this open-group operator in case the group is
- operated upon by a repetition operator, e.g., with `(a*)*b'
- against `ab'; then we want to ignore where we are now in
- the string in case this attempt to match fails. */
- old_regstart[*p] = REG_MATCH_NULL_STRING_P (reg_info[*p])
- ? REG_UNSET (regstart[*p]) ? d : regstart[*p]
- : regstart[*p];
- DEBUG_PRINT2 (" old_regstart: %d\n",
- POINTER_TO_OFFSET (old_regstart[*p]));
-
- regstart[*p] = d;
- DEBUG_PRINT2 (" regstart: %d\n", POINTER_TO_OFFSET (regstart[*p]));
-
- IS_ACTIVE (reg_info[*p]) = 1;
- MATCHED_SOMETHING (reg_info[*p]) = 0;
-
- /* This is the new highest active register. */
- highest_active_reg = *p;
-
- /* If nothing was active before, this is the new lowest active
- register. */
- if (lowest_active_reg == NO_LOWEST_ACTIVE_REG)
- lowest_active_reg = *p;
-
- /* Move past the register number and inner group count. */
- p += 2;
- break;
-
-
- /* The stop_memory opcode represents the end of a group. Its
- arguments are the same as start_memory's: the register
- number, and the number of inner groups. */
- case stop_memory:
- DEBUG_PRINT3 ("EXECUTING stop_memory %d (%d):\n", *p, p[1]);
-
- /* We need to save the string position the last time we were at
- this close-group operator in case the group is operated
- upon by a repetition operator, e.g., with `((a*)*(b*)*)*'
- against `aba'; then we want to ignore where we are now in
- the string in case this attempt to match fails. */
- old_regend[*p] = REG_MATCH_NULL_STRING_P (reg_info[*p])
- ? REG_UNSET (regend[*p]) ? d : regend[*p]
- : regend[*p];
- DEBUG_PRINT2 (" old_regend: %d\n",
- POINTER_TO_OFFSET (old_regend[*p]));
-
- regend[*p] = d;
- DEBUG_PRINT2 (" regend: %d\n", POINTER_TO_OFFSET (regend[*p]));
-
- /* This register isn't active anymore. */
- IS_ACTIVE (reg_info[*p]) = 0;
-
- /* If this was the only register active, nothing is active
- anymore. */
- if (lowest_active_reg == highest_active_reg)
- {
- lowest_active_reg = NO_LOWEST_ACTIVE_REG;
- highest_active_reg = NO_HIGHEST_ACTIVE_REG;
- }
- else
- { /* We must scan for the new highest active register, since
- it isn't necessarily one less than now: consider
- (a(b)c(d(e)f)g). When group 3 ends, after the f), the
- new highest active register is 1. */
- unsigned char r = *p - 1;
- while (r > 0 && !IS_ACTIVE (reg_info[r]))
- r--;
-
- /* If we end up at register zero, that means that we saved
- the registers as the result of an `on_failure_jump', not
- a `start_memory', and we jumped to past the innermost
- `stop_memory'. For example, in ((.)*) we save
- registers 1 and 2 as a result of the *, but when we pop
- back to the second ), we are at the stop_memory 1.
- Thus, nothing is active. */
- if (r == 0)
- {
- lowest_active_reg = NO_LOWEST_ACTIVE_REG;
- highest_active_reg = NO_HIGHEST_ACTIVE_REG;
- }
- else
- highest_active_reg = r;
- }
-
- /* If just failed to match something this time around with a
- group that's operated on by a repetition operator, try to
- force exit from the ``loop'', and restore the register
- information for this group that we had before trying this
- last match. */
- if ((!MATCHED_SOMETHING (reg_info[*p])
- || (re_opcode_t) p[-3] == start_memory)
- && (p + 2) < pend)
- {
- boolean is_a_jump_n = false;
-
- p1 = p + 2;
- mcnt = 0;
- switch ((re_opcode_t) *p1++)
- {
- case jump_n:
- is_a_jump_n = true;
- case pop_failure_jump:
- case maybe_pop_jump:
- case jump:
- case dummy_failure_jump:
- EXTRACT_NUMBER_AND_INCR (mcnt, p1);
- if (is_a_jump_n)
- p1 += 2;
- break;
-
- default:
- /* do nothing */ ;
- }
- p1 += mcnt;
-
- /* If the next operation is a jump backwards in the pattern
- to an on_failure_jump right before the start_memory
- corresponding to this stop_memory, exit from the loop
- by forcing a failure after pushing on the stack the
- on_failure_jump's jump in the pattern, and d. */
- if (mcnt < 0 && (re_opcode_t) *p1 == on_failure_jump
- && (re_opcode_t) p1[3] == start_memory && p1[4] == *p)
- {
- /* If this group ever matched anything, then restore
- what its registers were before trying this last
- failed match, e.g., with `(a*)*b' against `ab' for
- regstart[1], and, e.g., with `((a*)*(b*)*)*'
- against `aba' for regend[3].
-
- Also restore the registers for inner groups for,
- e.g., `((a*)(b*))*' against `aba' (register 3 would
- otherwise get trashed). */
-
- if (EVER_MATCHED_SOMETHING (reg_info[*p]))
- {
- unsigned r;
-
- EVER_MATCHED_SOMETHING (reg_info[*p]) = 0;
-
- /* Restore this and inner groups' (if any) registers. */
- for (r = *p; r < *p + *(p + 1); r++)
- {
- regstart[r] = old_regstart[r];
-
- /* xx why this test? */
- if ((int) old_regend[r] >= (int) regstart[r])
- regend[r] = old_regend[r];
- }
- }
- p1++;
- EXTRACT_NUMBER_AND_INCR (mcnt, p1);
- PUSH_FAILURE_POINT (p1 + mcnt, d, -2);
-
- goto fail;
- }
- }
-
- /* Move past the register number and the inner group count. */
- p += 2;
- break;
-
-
- /* \<digit> has been turned into a `duplicate' command which is
- followed by the numeric value of <digit> as the register number. */
- case duplicate:
- {
- register const char *d2, *dend2;
- int regno = *p++; /* Get which register to match against. */
- DEBUG_PRINT2 ("EXECUTING duplicate %d.\n", regno);
-
- /* Can't back reference a group which we've never matched. */
- if (REG_UNSET (regstart[regno]) || REG_UNSET (regend[regno]))
- goto fail;
-
- /* Where in input to try to start matching. */
- d2 = regstart[regno];
-
- /* Where to stop matching; if both the place to start and
- the place to stop matching are in the same string, then
- set to the place to stop, otherwise, for now have to use
- the end of the first string. */
-
- dend2 = ((FIRST_STRING_P (regstart[regno])
- == FIRST_STRING_P (regend[regno]))
- ? regend[regno] : end_match_1);
- for (;;)
- {
- /* If necessary, advance to next segment in register
- contents. */
- while (d2 == dend2)
- {
- if (dend2 == end_match_2) break;
- if (dend2 == regend[regno]) break;
-
- /* End of string1 => advance to string2. */
- d2 = string2;
- dend2 = regend[regno];
- }
- /* At end of register contents => success */
- if (d2 == dend2) break;
-
- /* If necessary, advance to next segment in data. */
- PREFETCH ();
-
- /* How many characters left in this segment to match. */
- mcnt = dend - d;
-
- /* Want how many consecutive characters we can match in
- one shot, so, if necessary, adjust the count. */
- if (mcnt > dend2 - d2)
- mcnt = dend2 - d2;
-
- /* Compare that many; failure if mismatch, else move
- past them. */
- if (translate
- ? bcmp_translate (d, d2, mcnt, translate)
- : bcmp (d, d2, mcnt))
- goto fail;
- d += mcnt, d2 += mcnt;
- }
- }
- break;
-
-
- /* begline matches the empty string at the beginning of the string
- (unless `not_bol' is set in `bufp'), and, if
- `newline_anchor' is set, after newlines. */
- case begline:
- DEBUG_PRINT1 ("EXECUTING begline.\n");
-
- if (AT_STRINGS_BEG (d))
- {
- if (!bufp->not_bol) break;
- }
- else if (d[-1] == '\n' && bufp->newline_anchor)
- {
- break;
- }
- /* In all other cases, we fail. */
- goto fail;
-
-
- /* endline is the dual of begline. */
- case endline:
- DEBUG_PRINT1 ("EXECUTING endline.\n");
-
- if (AT_STRINGS_END (d))
- {
- if (!bufp->not_eol) break;
- }
-
- /* We have to ``prefetch'' the next character. */
- else if ((d == end1 ? *string2 : *d) == '\n'
- && bufp->newline_anchor)
- {
- break;
- }
- goto fail;
-
-
- /* Match at the very beginning of the data. */
- case begbuf:
- DEBUG_PRINT1 ("EXECUTING begbuf.\n");
- if (AT_STRINGS_BEG (d))
- break;
- goto fail;
-
-
- /* Match at the very end of the data. */
- case endbuf:
- DEBUG_PRINT1 ("EXECUTING endbuf.\n");
- if (AT_STRINGS_END (d))
- break;
- goto fail;
-
-
- /* on_failure_keep_string_jump is used to optimize `.*\n'. It
- pushes NULL as the value for the string on the stack. Then
- `pop_failure_point' will keep the current value for the
- string, instead of restoring it. To see why, consider
- matching `foo\nbar' against `.*\n'. The .* matches the foo;
- then the . fails against the \n. But the next thing we want
- to do is match the \n against the \n; if we restored the
- string value, we would be back at the foo.
-
- Because this is used only in specific cases, we don't need to
- check all the things that `on_failure_jump' does, to make
- sure the right things get saved on the stack. Hence we don't
- share its code. The only reason to push anything on the
- stack at all is that otherwise we would have to change
- `anychar's code to do something besides goto fail in this
- case; that seems worse than this. */
- case on_failure_keep_string_jump:
- DEBUG_PRINT1 ("EXECUTING on_failure_keep_string_jump");
-
- EXTRACT_NUMBER_AND_INCR (mcnt, p);
- DEBUG_PRINT3 (" %d (to 0x%x):\n", mcnt, p + mcnt);
-
- PUSH_FAILURE_POINT (p + mcnt, NULL, -2);
- break;
-
-
- /* Uses of on_failure_jump:
-
- Each alternative starts with an on_failure_jump that points
- to the beginning of the next alternative. Each alternative
- except the last ends with a jump that in effect jumps past
- the rest of the alternatives. (They really jump to the
- ending jump of the following alternative, because tensioning
- these jumps is a hassle.)
-
- Repeats start with an on_failure_jump that points past both
- the repetition text and either the following jump or
- pop_failure_jump back to this on_failure_jump. */
- case on_failure_jump:
- on_failure:
- DEBUG_PRINT1 ("EXECUTING on_failure_jump");
-
- EXTRACT_NUMBER_AND_INCR (mcnt, p);
- DEBUG_PRINT3 (" %d (to 0x%x)", mcnt, p + mcnt);
-
- /* If this on_failure_jump comes right before a group (i.e.,
- the original * applied to a group), save the information
- for that group and all inner ones, so that if we fail back
- to this point, the group's information will be correct.
- For example, in \(a*\)*\1, we need the preceding group,
- and in \(\(a*\)b*\)\2, we need the inner group. */
-
- /* We can't use `p' to check ahead because we push
- a failure point to `p + mcnt' after we do this. */
- p1 = p;
-
- /* We need to skip no_op's before we look for the
- start_memory in case this on_failure_jump is happening as
- the result of a completed succeed_n, as in \(a\)\{1,3\}b\1
- against aba. */
- while (p1 < pend && (re_opcode_t) *p1 == no_op)
- p1++;
-
- if (p1 < pend && (re_opcode_t) *p1 == start_memory)
- {
- /* We have a new highest active register now. This will
- get reset at the start_memory we are about to get to,
- but we will have saved all the registers relevant to
- this repetition op, as described above. */
- highest_active_reg = *(p1 + 1) + *(p1 + 2);
- if (lowest_active_reg == NO_LOWEST_ACTIVE_REG)
- lowest_active_reg = *(p1 + 1);
- }
-
- DEBUG_PRINT1 (":\n");
- PUSH_FAILURE_POINT (p + mcnt, d, -2);
- break;
-
-
- /* A smart repeat ends with `maybe_pop_jump'.
- We change it to either `pop_failure_jump' or `jump'. */
- case maybe_pop_jump:
- EXTRACT_NUMBER_AND_INCR (mcnt, p);
- DEBUG_PRINT2 ("EXECUTING maybe_pop_jump %d.\n", mcnt);
- {
- register unsigned char *p2 = p;
-
- /* Compare the beginning of the repeat with what in the
- pattern follows its end. If we can establish that there
- is nothing that they would both match, i.e., that we
- would have to backtrack because of (as in, e.g., `a*a')
- then we can change to pop_failure_jump, because we'll
- never have to backtrack.
-
- This is not true in the case of alternatives: in
- `(a|ab)*' we do need to backtrack to the `ab' alternative
- (e.g., if the string was `ab'). But instead of trying to
- detect that here, the alternative has put on a dummy
- failure point which is what we will end up popping. */
-
- /* Skip over open/close-group commands. */
- while (p2 + 2 < pend
- && ((re_opcode_t) *p2 == stop_memory
- || (re_opcode_t) *p2 == start_memory))
- p2 += 3; /* Skip over args, too. */
-
- /* If we're at the end of the pattern, we can change. */
- if (p2 == pend)
- {
- /* Consider what happens when matching ":\(.*\)"
- against ":/". I don't really understand this code
- yet. */
- p[-3] = (unsigned char) pop_failure_jump;
- DEBUG_PRINT1
- (" End of pattern: change to `pop_failure_jump'.\n");
- }
-
- else if ((re_opcode_t) *p2 == exactn
- || (bufp->newline_anchor && (re_opcode_t) *p2 == endline))
- {
- register unsigned char c
- = *p2 == (unsigned char) endline ? '\n' : p2[2];
- p1 = p + mcnt;
-
- /* p1[0] ... p1[2] are the `on_failure_jump' corresponding
- to the `maybe_finalize_jump' of this case. Examine what
- follows. */
- if ((re_opcode_t) p1[3] == exactn && p1[5] != c)
- {
- p[-3] = (unsigned char) pop_failure_jump;
- DEBUG_PRINT3 (" %c != %c => pop_failure_jump.\n",
- c, p1[5]);
- }
-
- else if ((re_opcode_t) p1[3] == charset
- || (re_opcode_t) p1[3] == charset_not)
- {
- int not = (re_opcode_t) p1[3] == charset_not;
-
- if (c < (unsigned char) (p1[4] * BYTEWIDTH)
- && p1[5 + c / BYTEWIDTH] & (1 << (c % BYTEWIDTH)))
- not = !not;
-
- /* `not' is equal to 1 if c would match, which means
- that we can't change to pop_failure_jump. */
- if (!not)
- {
- p[-3] = (unsigned char) pop_failure_jump;
- DEBUG_PRINT1 (" No match => pop_failure_jump.\n");
- }
- }
- }
- }
- p -= 2; /* Point at relative address again. */
- if ((re_opcode_t) p[-1] != pop_failure_jump)
- {
- p[-1] = (unsigned char) jump;
- DEBUG_PRINT1 (" Match => jump.\n");
- goto unconditional_jump;
- }
- /* Note fall through. */
-
-
- /* The end of a simple repeat has a pop_failure_jump back to
- its matching on_failure_jump, where the latter will push a
- failure point. The pop_failure_jump takes off failure
- points put on by this pop_failure_jump's matching
- on_failure_jump; we got through the pattern to here from the
- matching on_failure_jump, so didn't fail. */
- case pop_failure_jump:
- {
- /* We need to pass separate storage for the lowest and
- highest registers, even though we don't care about the
- actual values. Otherwise, we will restore only one
- register from the stack, since lowest will == highest in
- `pop_failure_point'. */
- unsigned dummy_low_reg, dummy_high_reg;
- unsigned char *pdummy;
- const char *sdummy;
-
- DEBUG_PRINT1 ("EXECUTING pop_failure_jump.\n");
- POP_FAILURE_POINT (sdummy, pdummy,
- dummy_low_reg, dummy_high_reg,
- reg_dummy, reg_dummy, reg_info_dummy);
- }
- /* Note fall through. */
-
-
- /* Unconditionally jump (without popping any failure points). */
- case jump:
- unconditional_jump:
- EXTRACT_NUMBER_AND_INCR (mcnt, p); /* Get the amount to jump. */
- DEBUG_PRINT2 ("EXECUTING jump %d ", mcnt);
- p += mcnt; /* Do the jump. */
- DEBUG_PRINT2 ("(to 0x%x).\n", p);
- break;
-
-
- /* We need this opcode so we can detect where alternatives end
- in `group_match_null_string_p' et al. */
- case jump_past_alt:
- DEBUG_PRINT1 ("EXECUTING jump_past_alt.\n");
- goto unconditional_jump;
-
-
- /* Normally, the on_failure_jump pushes a failure point, which
- then gets popped at pop_failure_jump. We will end up at
- pop_failure_jump, also, and with a pattern of, say, `a+', we
- are skipping over the on_failure_jump, so we have to push
- something meaningless for pop_failure_jump to pop. */
- case dummy_failure_jump:
- DEBUG_PRINT1 ("EXECUTING dummy_failure_jump.\n");
- /* It doesn't matter what we push for the string here. What
- the code at `fail' tests is the value for the pattern. */
- PUSH_FAILURE_POINT (0, 0, -2);
- goto unconditional_jump;
-
-
- /* At the end of an alternative, we need to push a dummy failure
- point in case we are followed by a `pop_failure_jump', because
- we don't want the failure point for the alternative to be
- popped. For example, matching `(a|ab)*' against `aab'
- requires that we match the `ab' alternative. */
- case push_dummy_failure:
- DEBUG_PRINT1 ("EXECUTING push_dummy_failure.\n");
- /* See comments just above at `dummy_failure_jump' about the
- two zeroes. */
- PUSH_FAILURE_POINT (0, 0, -2);
- break;
-
- /* Have to succeed matching what follows at least n times.
- After that, handle like `on_failure_jump'. */
- case succeed_n:
- EXTRACT_NUMBER (mcnt, p + 2);
- DEBUG_PRINT2 ("EXECUTING succeed_n %d.\n", mcnt);
-
- assert (mcnt >= 0);
- /* Originally, this is how many times we HAVE to succeed. */
- if (mcnt > 0)
- {
- mcnt--;
- p += 2;
- STORE_NUMBER_AND_INCR (p, mcnt);
- DEBUG_PRINT3 (" Setting 0x%x to %d.\n", p, mcnt);
- }
- else if (mcnt == 0)
- {
- DEBUG_PRINT2 (" Setting two bytes from 0x%x to no_op.\n", p+2);
- p[2] = (unsigned char) no_op;
- p[3] = (unsigned char) no_op;
- goto on_failure;
- }
- break;
-
- case jump_n:
- EXTRACT_NUMBER (mcnt, p + 2);
- DEBUG_PRINT2 ("EXECUTING jump_n %d.\n", mcnt);
-
- /* Originally, this is how many times we CAN jump. */
- if (mcnt)
- {
- mcnt--;
- STORE_NUMBER (p + 2, mcnt);
- goto unconditional_jump;
- }
- /* If don't have to jump any more, skip over the rest of command. */
- else
- p += 4;
- break;
-
- case set_number_at:
- {
- DEBUG_PRINT1 ("EXECUTING set_number_at.\n");
-
- EXTRACT_NUMBER_AND_INCR (mcnt, p);
- p1 = p + mcnt;
- EXTRACT_NUMBER_AND_INCR (mcnt, p);
- DEBUG_PRINT3 (" Setting 0x%x to %d.\n", p1, mcnt);
- STORE_NUMBER (p1, mcnt);
- break;
- }
-
- case wordbound:
- DEBUG_PRINT1 ("EXECUTING wordbound.\n");
- if (AT_WORD_BOUNDARY (d))
- break;
- goto fail;
-
- case notwordbound:
- DEBUG_PRINT1 ("EXECUTING notwordbound.\n");
- if (AT_WORD_BOUNDARY (d))
- goto fail;
- break;
-
- case wordbeg:
- DEBUG_PRINT1 ("EXECUTING wordbeg.\n");
- if (WORDCHAR_P (d) && (AT_STRINGS_BEG (d) || !WORDCHAR_P (d - 1)))
- break;
- goto fail;
-
- case wordend:
- DEBUG_PRINT1 ("EXECUTING wordend.\n");
- if (!AT_STRINGS_BEG (d) && WORDCHAR_P (d - 1)
- && (!WORDCHAR_P (d) || AT_STRINGS_END (d)))
- break;
- goto fail;
-
-#ifdef emacs
-#ifdef emacs19
- case before_dot:
- DEBUG_PRINT1 ("EXECUTING before_dot.\n");
- if (PTR_CHAR_POS ((unsigned char *) d) >= point)
- goto fail;
- break;
-
- case at_dot:
- DEBUG_PRINT1 ("EXECUTING at_dot.\n");
- if (PTR_CHAR_POS ((unsigned char *) d) != point)
- goto fail;
- break;
-
- case after_dot:
- DEBUG_PRINT1 ("EXECUTING after_dot.\n");
- if (PTR_CHAR_POS ((unsigned char *) d) <= point)
- goto fail;
- break;
-#else /* not emacs19 */
- case at_dot:
- DEBUG_PRINT1 ("EXECUTING at_dot.\n");
- if (PTR_CHAR_POS ((unsigned char *) d) + 1 != point)
- goto fail;
- break;
-#endif /* not emacs19 */
-
- case syntaxspec:
- DEBUG_PRINT2 ("EXECUTING syntaxspec %d.\n", mcnt);
- mcnt = *p++;
- goto matchsyntax;
-
- case wordchar:
- DEBUG_PRINT1 ("EXECUTING Emacs wordchar.\n");
- mcnt = (int) Sword;
- matchsyntax:
- PREFETCH ();
- if (SYNTAX (*d++) != (enum syntaxcode) mcnt)
- goto fail;
- SET_REGS_MATCHED ();
- break;
-
- case notsyntaxspec:
- DEBUG_PRINT2 ("EXECUTING notsyntaxspec %d.\n", mcnt);
- mcnt = *p++;
- goto matchnotsyntax;
-
- case notwordchar:
- DEBUG_PRINT1 ("EXECUTING Emacs notwordchar.\n");
- mcnt = (int) Sword;
- matchnotsyntax:
- PREFETCH ();
- if (SYNTAX (*d++) == (enum syntaxcode) mcnt)
- goto fail;
- SET_REGS_MATCHED ();
- break;
-
-#else /* not emacs */
- case wordchar:
- DEBUG_PRINT1 ("EXECUTING non-Emacs wordchar.\n");
- PREFETCH ();
- if (!WORDCHAR_P (d))
- goto fail;
- SET_REGS_MATCHED ();
- d++;
- break;
-
- case notwordchar:
- DEBUG_PRINT1 ("EXECUTING non-Emacs notwordchar.\n");
- PREFETCH ();
- if (WORDCHAR_P (d))
- goto fail;
- SET_REGS_MATCHED ();
- d++;
- break;
-#endif /* not emacs */
-
- default:
- abort ();
- }
- continue; /* Successfully executed one pattern command; keep going. */
-
-
- /* We goto here if a matching operation fails. */
- fail:
- if (!FAIL_STACK_EMPTY ())
- { /* A restart point is known. Restore to that state. */
- DEBUG_PRINT1 ("\nFAIL:\n");
- POP_FAILURE_POINT (d, p,
- lowest_active_reg, highest_active_reg,
- regstart, regend, reg_info);
-
- /* If this failure point is a dummy, try the next one. */
- if (!p)
- goto fail;
-
- /* If we failed to the end of the pattern, don't examine *p. */
- assert (p <= pend);
- if (p < pend)
- {
- boolean is_a_jump_n = false;
-
- /* If failed to a backwards jump that's part of a repetition
- loop, need to pop this failure point and use the next one. */
- switch ((re_opcode_t) *p)
- {
- case jump_n:
- is_a_jump_n = true;
- case maybe_pop_jump:
- case pop_failure_jump:
- case jump:
- p1 = p + 1;
- EXTRACT_NUMBER_AND_INCR (mcnt, p1);
- p1 += mcnt;
-
- if ((is_a_jump_n && (re_opcode_t) *p1 == succeed_n)
- || (!is_a_jump_n
- && (re_opcode_t) *p1 == on_failure_jump))
- goto fail;
- break;
- default:
- /* do nothing */ ;
- }
- }
-
- if (d >= string1 && d <= end1)
- dend = end_match_1;
- }
- else
- break; /* Matching at this starting point really fails. */
- } /* for (;;) */
-
- if (best_regs_set)
- goto restore_best_regs;
-
- FREE_VARIABLES ();
-
- return -1; /* Failure to match. */
-} /* re_match_2 */
-
-/* Subroutine definitions for re_match_2. */
-
-
-/* We are passed P pointing to a register number after a start_memory.
-
- Return true if the pattern up to the corresponding stop_memory can
- match the empty string, and false otherwise.
-
- If we find the matching stop_memory, sets P to point to one past its number.
- Otherwise, sets P to an undefined byte less than or equal to END.
-
- We don't handle duplicates properly (yet). */
-
-static boolean
-group_match_null_string_p (p, end, reg_info)
- unsigned char **p, *end;
- register_info_type *reg_info;
-{
- int mcnt;
- /* Point to after the args to the start_memory. */
- unsigned char *p1 = *p + 2;
-
- while (p1 < end)
- {
- /* Skip over opcodes that can match nothing, and return true or
- false, as appropriate, when we get to one that can't, or to the
- matching stop_memory. */
-
- switch ((re_opcode_t) *p1)
- {
- /* Could be either a loop or a series of alternatives. */
- case on_failure_jump:
- p1++;
- EXTRACT_NUMBER_AND_INCR (mcnt, p1);
-
- /* If the next operation is not a jump backwards in the
- pattern. */
-
- if (mcnt >= 0)
- {
- /* Go through the on_failure_jumps of the alternatives,
- seeing if any of the alternatives cannot match nothing.
- The last alternative starts with only a jump,
- whereas the rest start with on_failure_jump and end
- with a jump, e.g., here is the pattern for `a|b|c':
-
- /on_failure_jump/0/6/exactn/1/a/jump_past_alt/0/6
- /on_failure_jump/0/6/exactn/1/b/jump_past_alt/0/3
- /exactn/1/c
-
- So, we have to first go through the first (n-1)
- alternatives and then deal with the last one separately. */
-
-
- /* Deal with the first (n-1) alternatives, which start
- with an on_failure_jump (see above) that jumps to right
- past a jump_past_alt. */
-
- while ((re_opcode_t) p1[mcnt-3] == jump_past_alt)
- {
- /* `mcnt' holds how many bytes long the alternative
- is, including the ending `jump_past_alt' and
- its number. */
-
- if (!alt_match_null_string_p (p1, p1 + mcnt - 3,
- reg_info))
- return false;
-
- /* Move to right after this alternative, including the
- jump_past_alt. */
- p1 += mcnt;
-
- /* Break if it's the beginning of an n-th alternative
- that doesn't begin with an on_failure_jump. */
- if ((re_opcode_t) *p1 != on_failure_jump)
- break;
-
- /* Still have to check that it's not an n-th
- alternative that starts with an on_failure_jump. */
- p1++;
- EXTRACT_NUMBER_AND_INCR (mcnt, p1);
- if ((re_opcode_t) p1[mcnt-3] != jump_past_alt)
- {
- /* Get to the beginning of the n-th alternative. */
- p1 -= 3;
- break;
- }
- }
-
- /* Deal with the last alternative: go back and get number
- of the `jump_past_alt' just before it. `mcnt' contains
- the length of the alternative. */
- EXTRACT_NUMBER (mcnt, p1 - 2);
-
- if (!alt_match_null_string_p (p1, p1 + mcnt, reg_info))
- return false;
-
- p1 += mcnt; /* Get past the n-th alternative. */
- } /* if mcnt > 0 */
- break;
-
-
- case stop_memory:
- assert (p1[1] == **p);
- *p = p1 + 2;
- return true;
-
-
- default:
- if (!common_op_match_null_string_p (&p1, end, reg_info))
- return false;
- }
- } /* while p1 < end */
-
- return false;
-} /* group_match_null_string_p */
-
-
-/* Similar to group_match_null_string_p, but doesn't deal with alternatives:
- It expects P to be the first byte of a single alternative and END one
- byte past the last. The alternative can contain groups. */
-
-static boolean
-alt_match_null_string_p (p, end, reg_info)
- unsigned char *p, *end;
- register_info_type *reg_info;
-{
- int mcnt;
- unsigned char *p1 = p;
-
- while (p1 < end)
- {
- /* Skip over opcodes that can match nothing, and break when we get
- to one that can't. */
-
- switch ((re_opcode_t) *p1)
- {
- /* It's a loop. */
- case on_failure_jump:
- p1++;
- EXTRACT_NUMBER_AND_INCR (mcnt, p1);
- p1 += mcnt;
- break;
-
- default:
- if (!common_op_match_null_string_p (&p1, end, reg_info))
- return false;
- }
- } /* while p1 < end */
-
- return true;
-} /* alt_match_null_string_p */
-
-
-/* Deals with the ops common to group_match_null_string_p and
- alt_match_null_string_p.
-
- Sets P to one after the op and its arguments, if any. */
-
-static boolean
-common_op_match_null_string_p (p, end, reg_info)
- unsigned char **p, *end;
- register_info_type *reg_info;
-{
- int mcnt;
- boolean ret;
- int reg_no;
- unsigned char *p1 = *p;
-
- switch ((re_opcode_t) *p1++)
- {
- case no_op:
- case begline:
- case endline:
- case begbuf:
- case endbuf:
- case wordbeg:
- case wordend:
- case wordbound:
- case notwordbound:
-#ifdef emacs
- case before_dot:
- case at_dot:
- case after_dot:
-#endif
- break;
-
- case start_memory:
- reg_no = *p1;
- assert (reg_no > 0 && reg_no <= MAX_REGNUM);
- ret = group_match_null_string_p (&p1, end, reg_info);
-
- /* Have to set this here in case we're checking a group which
- contains a group and a back reference to it. */
-
- if (REG_MATCH_NULL_STRING_P (reg_info[reg_no]) == MATCH_NULL_UNSET_VALUE)
- REG_MATCH_NULL_STRING_P (reg_info[reg_no]) = ret;
-
- if (!ret)
- return false;
- break;
-
- /* If this is an optimized succeed_n for zero times, make the jump. */
- case jump:
- EXTRACT_NUMBER_AND_INCR (mcnt, p1);
- if (mcnt >= 0)
- p1 += mcnt;
- else
- return false;
- break;
-
- case succeed_n:
- /* Get to the number of times to succeed. */
- p1 += 2;
- EXTRACT_NUMBER_AND_INCR (mcnt, p1);
-
- if (mcnt == 0)
- {
- p1 -= 4;
- EXTRACT_NUMBER_AND_INCR (mcnt, p1);
- p1 += mcnt;
- }
- else
- return false;
- break;
-
- case duplicate:
- if (!REG_MATCH_NULL_STRING_P (reg_info[*p1]))
- return false;
- break;
-
- case set_number_at:
- p1 += 4;
-
- default:
- /* All other opcodes mean we cannot match the empty string. */
- return false;
- }
-
- *p = p1;
- return true;
-} /* common_op_match_null_string_p */
-
-
-/* Return zero if TRANSLATE[S1] and TRANSLATE[S2] are identical for LEN
- bytes; nonzero otherwise. */
-
-static int
-bcmp_translate (s1, s2, len, translate)
- unsigned char *s1, *s2;
- register int len;
- char *translate;
-{
- register unsigned char *p1 = s1, *p2 = s2;
- while (len)
- {
- if (translate[*p1++] != translate[*p2++]) return 1;
- len--;
- }
- return 0;
-}
-
-/* Entry points for GNU code. */
-
-/* re_compile_pattern is the GNU regular expression compiler: it
- compiles PATTERN (of length SIZE) and puts the result in BUFP.
- Returns 0 if the pattern was valid, otherwise an error string.
-
- Assumes the `allocated' (and perhaps `buffer') and `translate' fields
- are set in BUFP on entry.
-
- We call regex_compile to do the actual compilation. */
-
-const char *
-re_compile_pattern (pattern, length, bufp)
- const char *pattern;
- int length;
- struct re_pattern_buffer *bufp;
-{
- reg_errcode_t ret;
-
- /* GNU code is written to assume at least RE_NREGS registers will be set
- (and at least one extra will be -1). */
- bufp->regs_allocated = REGS_UNALLOCATED;
-
- /* And GNU code determines whether or not to get register information
- by passing null for the REGS argument to re_match, etc., not by
- setting no_sub. */
- bufp->no_sub = 0;
-
- /* Match anchors at newline. */
- bufp->newline_anchor = 1;
-
- ret = regex_compile (pattern, length, re_syntax_options, bufp);
-
- return re_error_msg[(int) ret];
-}
-
-/* Entry points compatible with 4.2 BSD regex library. We don't define
- them if this is an Emacs or POSIX compilation. */
-
-#if !defined (emacs) && !defined (_POSIX_SOURCE)
-
-/* BSD has one and only one pattern buffer. */
-static struct re_pattern_buffer re_comp_buf;
-
-char *
-re_comp (s)
- const char *s;
-{
- reg_errcode_t ret;
-
- if (!s)
- {
- if (!re_comp_buf.buffer)
- return "No previous regular expression";
- return 0;
- }
-
- if (!re_comp_buf.buffer)
- {
- re_comp_buf.buffer = (unsigned char *) malloc (200);
- if (re_comp_buf.buffer == NULL)
- return "Memory exhausted";
- re_comp_buf.allocated = 200;
-
- re_comp_buf.fastmap = (char *) malloc (1 << BYTEWIDTH);
- if (re_comp_buf.fastmap == NULL)
- return "Memory exhausted";
- }
-
- /* Since `re_exec' always passes NULL for the `regs' argument, we
- don't need to initialize the pattern buffer fields which affect it. */
-
- /* Match anchors at newlines. */
- re_comp_buf.newline_anchor = 1;
-
- ret = regex_compile (s, strlen (s), re_syntax_options, &re_comp_buf);
-
- /* Yes, we're discarding `const' here. */
- return (char *) re_error_msg[(int) ret];
-}
-
-
-int
-re_exec (s)
- const char *s;
-{
- const int len = strlen (s);
- return
- 0 <= re_search (&re_comp_buf, s, len, 0, len, (struct re_registers *) 0);
-}
-#endif /* not emacs and not _POSIX_SOURCE */
-
-/* POSIX.2 functions. Don't define these for Emacs. */
-
-#ifndef emacs
-
-/* regcomp takes a regular expression as a string and compiles it.
-
- PREG is a regex_t *. We do not expect any fields to be initialized,
- since POSIX says we shouldn't. Thus, we set
-
- `buffer' to the compiled pattern;
- `used' to the length of the compiled pattern;
- `syntax' to RE_SYNTAX_POSIX_EXTENDED if the
- REG_EXTENDED bit in CFLAGS is set; otherwise, to
- RE_SYNTAX_POSIX_BASIC;
- `newline_anchor' to REG_NEWLINE being set in CFLAGS;
- `fastmap' and `fastmap_accurate' to zero;
- `re_nsub' to the number of subexpressions in PATTERN.
-
- PATTERN is the address of the pattern string.
-
- CFLAGS is a series of bits which affect compilation.
-
- If REG_EXTENDED is set, we use POSIX extended syntax; otherwise, we
- use POSIX basic syntax.
-
- If REG_NEWLINE is set, then . and [^...] don't match newline.
- Also, regexec will try a match beginning after every newline.
-
- If REG_ICASE is set, then we considers upper- and lowercase
- versions of letters to be equivalent when matching.
-
- If REG_NOSUB is set, then when PREG is passed to regexec, that
- routine will report only success or failure, and nothing about the
- registers.
-
- It returns 0 if it succeeds, nonzero if it doesn't. (See regex.h for
- the return codes and their meanings.) */
-
-int
-regcomp (preg, pattern, cflags)
- regex_t *preg;
- const char *pattern;
- int cflags;
-{
- reg_errcode_t ret;
- unsigned syntax
- = (cflags & REG_EXTENDED) ?
- RE_SYNTAX_POSIX_EXTENDED : RE_SYNTAX_POSIX_BASIC;
-
- /* regex_compile will allocate the space for the compiled pattern. */
- preg->buffer = 0;
- preg->allocated = 0;
-
- /* Don't bother to use a fastmap when searching. This simplifies the
- REG_NEWLINE case: if we used a fastmap, we'd have to put all the
- characters after newlines into the fastmap. This way, we just try
- every character. */
- preg->fastmap = 0;
-
- if (cflags & REG_ICASE)
- {
- unsigned i;
-
- preg->translate = (char *) malloc (CHAR_SET_SIZE);
- if (preg->translate == NULL)
- return (int) REG_ESPACE;
-
- /* Map uppercase characters to corresponding lowercase ones. */
- for (i = 0; i < CHAR_SET_SIZE; i++)
- preg->translate[i] = ISUPPER (i) ? tolower (i) : i;
- }
- else
- preg->translate = NULL;
-
- /* If REG_NEWLINE is set, newlines are treated differently. */
- if (cflags & REG_NEWLINE)
- { /* REG_NEWLINE implies neither . nor [^...] match newline. */
- syntax &= ~RE_DOT_NEWLINE;
- syntax |= RE_HAT_LISTS_NOT_NEWLINE;
- /* It also changes the matching behavior. */
- preg->newline_anchor = 1;
- }
- else
- preg->newline_anchor = 0;
-
- preg->no_sub = !!(cflags & REG_NOSUB);
-
- /* POSIX says a null character in the pattern terminates it, so we
- can use strlen here in compiling the pattern. */
- ret = regex_compile (pattern, strlen (pattern), syntax, preg);
-
- /* POSIX doesn't distinguish between an unmatched open-group and an
- unmatched close-group: both are REG_EPAREN. */
- if (ret == REG_ERPAREN) ret = REG_EPAREN;
-
- return (int) ret;
-}
-
-
-/* regexec searches for a given pattern, specified by PREG, in the
- string STRING.
-
- If NMATCH is zero or REG_NOSUB was set in the cflags argument to
- `regcomp', we ignore PMATCH. Otherwise, we assume PMATCH has at
- least NMATCH elements, and we set them to the offsets of the
- corresponding matched substrings.
-
- EFLAGS specifies `execution flags' which affect matching: if
- REG_NOTBOL is set, then ^ does not match at the beginning of the
- string; if REG_NOTEOL is set, then $ does not match at the end.
-
- We return 0 if we find a match and REG_NOMATCH if not. */
-
-int
-regexec (preg, string, nmatch, pmatch, eflags)
- const regex_t *preg;
- const char *string;
- size_t nmatch;
- regmatch_t pmatch[];
- int eflags;
-{
- int ret;
- struct re_registers regs;
- regex_t private_preg;
- int len = strlen (string);
- boolean want_reg_info = !preg->no_sub && nmatch > 0;
-
- private_preg = *preg;
-
- private_preg.not_bol = !!(eflags & REG_NOTBOL);
- private_preg.not_eol = !!(eflags & REG_NOTEOL);
-
- /* The user has told us exactly how many registers to return
- information about, via `nmatch'. We have to pass that on to the
- matching routines. */
- private_preg.regs_allocated = REGS_FIXED;
-
- if (want_reg_info)
- {
- regs.num_regs = nmatch;
- regs.start = TALLOC (nmatch, regoff_t);
- regs.end = TALLOC (nmatch, regoff_t);
- if (regs.start == NULL || regs.end == NULL)
- return (int) REG_NOMATCH;
- }
-
- /* Perform the searching operation. */
- ret = re_search (&private_preg, string, len,
- /* start: */ 0, /* range: */ len,
- want_reg_info ? &regs : (struct re_registers *) 0);
-
- /* Copy the register information to the POSIX structure. */
- if (want_reg_info)
- {
- if (ret >= 0)
- {
- unsigned r;
-
- for (r = 0; r < nmatch; r++)
- {
- pmatch[r].rm_so = regs.start[r];
- pmatch[r].rm_eo = regs.end[r];
- }
- }
-
- /* If we needed the temporary register info, free the space now. */
- free (regs.start);
- free (regs.end);
- }
-
- /* We want zero return to mean success, unlike `re_search'. */
- return ret >= 0 ? (int) REG_NOERROR : (int) REG_NOMATCH;
-}
-
-
-/* Returns a message corresponding to an error code, ERRCODE, returned
- from either regcomp or regexec. We don't use PREG here. */
-
-size_t
-regerror (errcode, preg, errbuf, errbuf_size)
- int errcode;
- const regex_t *preg;
- char *errbuf;
- size_t errbuf_size;
-{
- const char *msg;
- size_t msg_size;
-
- if (errcode < 0
- || errcode >= (sizeof (re_error_msg) / sizeof (re_error_msg[0])))
- /* Only error codes returned by the rest of the code should be passed
- to this routine. If we are given anything else, or if other regex
- code generates an invalid error code, then the program has a bug.
- Dump core so we can fix it. */
- abort ();
-
- msg_size = strlen (msg) + 1; /* Includes the null. */
-
- if (errbuf_size != 0)
- {
- if (msg_size > errbuf_size)
- {
- strncpy (errbuf, msg, errbuf_size - 1);
- errbuf[errbuf_size - 1] = 0;
- }
- else
- strcpy (errbuf, msg);
- }
-
- return msg_size;
-}
-
-
-/* Free dynamically allocated space used by PREG. */
-
-void
-regfree (preg)
- regex_t *preg;
-{
- if (preg->buffer != NULL)
- free (preg->buffer);
- preg->buffer = NULL;
-
- preg->allocated = 0;
- preg->used = 0;
-
- if (preg->fastmap != NULL)
- free (preg->fastmap);
- preg->fastmap = NULL;
- preg->fastmap_accurate = 0;
-
- if (preg->translate != NULL)
- free (preg->translate);
- preg->translate = NULL;
-}
-
-#endif /* not emacs */
-
-/*
-Local variables:
-make-backup-files: t
-version-control: t
-trim-versions-without-asking: nil
-End:
-*/
diff --git a/gnu/usr.bin/tar/tar.1 b/gnu/usr.bin/tar/tar.1
new file mode 100644
index 0000000..4da7a81
--- /dev/null
+++ b/gnu/usr.bin/tar/tar.1
@@ -0,0 +1,387 @@
+.\" Copyright (c) 1991, 1992, 1993 Free Software Foundation -*- nroff -*-
+.\" See /usr/src/gnu/COPYING for conditions of redistribution
+.\"
+.\" Written by John F. Woods <jfw@jfwhome.funhouse.com>
+.\"
+.\" $Id: tar.1,v 1.4 1995/10/25 02:17:44 torstenb Exp $
+.\"
+.Dd 6 August 1994
+.Os FreeBSD
+.Dt TAR 1
+.Sh NAME
+.Nm tar
+.Nd
+tape archiver; manipulate "tar" archive files
+.Sh SYNOPSIS
+.Nm
+.Op Cm Bq -
+.Op Cm bundled-options
+.Op Ar [gnu-style-flags]
+.Op Ar tarfile
+.Op Ar blocksize
+.Op Ar exclude-file
+.Op Ar filenames
+.Op Fl C Ar directory-name
+.Sh DESCRIPTION
+.Nm
+is short for
+.Dq tape archiver,
+so named for historical reasons; the
+.Nm
+program creates, adds files to, or extracts files from an archive file
+in
+.Dq tar
+format, called a
+.Ar tarfile .
+A tarfile is often a magnetic tape, but can be a floppy diskette or any
+regular disk file.
+.Pp
+The first argument word of the
+.Nm
+command line is usually a command word of bundled function and modifier
+letters, optionally preceded by a dash;
+it must contain exactly one function letter from the set
+.Cm A ,
+.Cm c ,
+.Cm d ,
+.Cm r ,
+.Cm t ,
+.Cm u ,
+.Cm x ,
+for append, create, difference, replace, table of contents, update, and
+extract (further described below). The command word can also contain other
+function modifiers described below, some of which will take arguments from
+the command line in the order they are specified in the command word (review
+the EXAMPLES section). Functions and function modifiers can also be specified
+with the GNU argument convention (preceded by two dashes, one function or
+modifier per word. Command-line arguments that specify files to
+add to, extract from, or list from an archive may be given as shell
+pattern matching strings.
+.Sh FUNCTIONS
+Exactly one of the following functions must be specified.
+.Pp
+.Bl -tag -width "--concatenate" -compact
+.It Fl A
+.It Fl -catenate
+.It Fl "-concatenate"
+Append the contents of named file, which must itself be a tar archive,
+to the end of the archive (erasing the old end-of-archive block).
+This has the effect of adding the files contained in the named file to
+the first archive, rather than adding the second archive as an element
+of the first.
+.Em Note:
+This option requires a rewritable tarfile,
+and therefore does not work on quarter-inch cartridge tapes.
+.It Fl c
+.It Fl -create
+Create a new archive (or truncates an old one) and writes the named files
+to it.
+.It Fl d
+.It Fl -diff
+.It Fl -compare
+Find differences between files in the archive and corresponding files in
+the file system.
+.It Fl -delete
+Delete named files from the archive (Does not work on quarter-inch tapes).
+.It Fl r
+.It Fl -append
+Append files to the end of an archive (Does not work on quarter-inch tapes).
+.It Fl t
+.It Fl -list
+List the contents of an archive; if filename arguments are given, only those
+files are listed, otherwise the entire table of contents is listed.
+.It Fl u
+.It Fl -update
+Append the named files if the on-disk version has a modification date
+more recent than their copy in the archive (if any). Does not work on
+quarter-inch tapes.
+.It Fl x
+.It Fl -extract
+.It Fl -get
+Extract files from an archive. The owner, modification time, and file
+permissions are restored, if possible. If no
+.Ar file
+arguments are given, extract all the files in the archive. If a
+.Ar filename
+argument matches the name of a directory on the tape, that directory and
+its contents are extracted (as well as all directories under that directory).
+If the archive contains multiple entries corresponding to the same file
+(see the
+.Fl -append
+command above), the last one extracted will overwrite all earlier versions.
+.El
+.Sh OPTIONS
+The other options to
+.Nm
+may be combined arbitrarily; single-letter options may be bundled in with
+the command word. Verbose options which take arguments will be
+followed by the argument; single-letter options will consume
+successive command line arguments (see the
+.Sx EXAMPLES
+below).
+.Pp
+.Bl -tag -width "--preserve-permissions" -compact
+.It Fl -help
+Prints a message listing and briefly describing all the command
+options to tar.
+.It Fl -atime-preserve
+Restore the access times on files which are written to tape (note that
+this will change the inode-change time!).
+.It Fl b
+.It Fl -block-size Ar number
+Sets the block size for reading or writing to N 512-byte blocks.
+.It Fl B
+.It Fl -read-full-blocks
+Re-assemble short reads into full blocks (for reading 4.2BSD pipes).
+.It Fl C Ar directory
+.It Fl -directory Ar directory
+Change to
+.Ar directory
+for extraction.
+.It Fl -checkpoint
+Print directory names while reading the archive.
+.It Fl f Ar [hostname:]file
+.It Fl -file Ar [hostname:]file
+Read or write the specified
+.Ar file
+(default is /dev/rst0). If a
+.Ar hostname
+is specified,
+.Nm
+will use
+.Xr rmt 8
+to read or write the specified
+.Ar file
+on a remote machine.
+.It Fl F Ar file
+.It Fl -info-script Ar file
+.It Fl -new-volume-script Ar file
+Run a script at the end of each archive volume (implies
+.Fl M ) .
+.It Fl -fast-read
+Stop after all non-wildcard extraction targets have been found
+in the archive.
+.It Fl G
+.It Fl -incremental
+Create/list/extract old GNU-format incremental backup.
+.It Fl g Ar file
+.It Fl -listed-incremental Ar file
+Create/list/extract new GNU-format incremental backup.
+.It Fl h
+.it Fl -dereference
+Don't write symlinks as symlinks; write the data of the files they name.
+.It Fl i
+.It Fl -ignore-zeros
+Ignore blocks of zeroes in archive (usually means End-Of-File).
+.It Fl -ignore-failed-read
+Don't exit with non-zero status on unreadable files.
+.It Fl k
+.It Fl -keep-old-files
+Keep files which already exist on disk; don't overwrite them from the archive.
+.It Fl K Ar file
+.It Fl -starting-file Ar file
+Begin at
+.Ar file
+in the archive.
+.It Fl l
+.It Fl -one-file-system
+Stay in local filesystem when creating an archive (do not cross mount
+points).
+.It Fl L Ar number
+.It Fl -tape-length Ar number
+Change tapes after writing N*1024 bytes.
+.It Fl m
+.It Fl -modification-time
+Don't extract file modified time.
+.It Fl M
+.It Fl -multi-volume
+Create/list/extract multi-volume archive.
+.It Fl N Ar date
+.It Fl -after-date Ar date
+.It Fl -newer Ar date
+Only store files newer than
+.Ar date .
+.It Fl o
+.It Fl -old-archive
+.It Fl -portability
+Write a V7 format archive, rather than POSIX format.
+.It Fl O
+.It Fl -to-stdout
+Extract files to standard output.
+.It Fl p
+.It Fl -same-permissions
+.It Fl -preserve-permissions
+Extract all protection information.
+.It Fl -preserve
+Has the effect of
+.Fl p s.
+.It Fl P
+.It Fl -absolute-paths
+Don't strip leading `/' from file names.
+.It Fl R
+.It Fl -record-number
+Show record number within archive with each message.
+.It Fl -remove-files
+Remove files after adding them to the archive.
+.It Fl s
+.It Fl -same-order
+.It Fl -preserve-order
+List of names to extract is sorted to match archive.
+.It Fl S
+.It Fl -sparse
+Handle "sparse" files efficiently.
+.It Fl T Ar file
+.It Fl -files-from Ar file
+Get names of files to extract or create from
+.Ar file ,
+one per line.
+.It Fl -null
+Modifies behavior of
+.Fl T
+to expect null-terminated names; disables
+.Fl C.
+.It Fl -totals
+Prints total bytes written with --create.
+.It Fl v
+.It Fl -verbose
+Lists files written to archive with --create or extracted with --extract;
+lists file protection information along with file names with --list.
+.It Fl V Ar volume-name
+.It Fl -label Ar volume-name
+Create archive with the given
+.Ar volume-name .
+.It Fl -version
+Print tar program version number.
+.It Fl w
+.It Fl -interactive
+.It Fl -confirmation
+Ask for confirmation for every action.
+.It Fl W
+.It Fl -verify
+Attempt to verify the archive after writing it.
+.It Fl -exclude Ar pattern
+Exclude files matching the
+.Ar pattern
+(don't extract them, don't add them, don't list them).
+.It Fl X Ar file
+.It Fl -exclude-from Ar file
+Exclude files listed in
+.Ar file .
+.It Fl Z
+.It Fl -compress
+.It Fl -uncompress
+Filter the archive through
+.Xr compress 1 .
+.It Fl z
+.It Fl -gzip
+.It Fl -gunzip
+Filter the archive through
+.Xr gzip 1 .
+.It Fl -use-compress-program Ar program
+Filter the archive through
+.Ar program
+(which must accept
+.Fl d
+to mean ``decompress'').
+.It Fl -block-compress
+Block the output of compression program for tapes or floppies
+(otherwise writes will be of odd length, which device drivers may reject).
+.It Fl [0-7][lmh]
+Specify tape drive and density.
+.It Fl -norecurse
+Don't recurse into subdirectories when creating.
+.It Fl -unlink
+Unlink files before creating them.
+.El
+.Sh EXAMPLES
+To create an archive on tape drive /dev/rst0 with a block size of 20
+blocks, containing files named "bert" and "ernie", you can enter
+.Dl tar cfb /dev/rst0 20 bert ernie
+or
+.Dl tar --create --file /dev/rst0 --block-size 20 bert ernie
+Note that the
+.Fl f
+and
+.Fl b
+flags both require arguments, which they take from the command line in
+the order they were listed in the command word.
+.Pp
+Because /dev/rst0 is the default device, and 20 is the default block
+size, the above example could have simply been
+.Dl tar c bert ernie
+.Pp
+To extract all the C sources and headers from an archive named
+"backup.tar", type
+.Dl tar xf backup.tar "*.[ch]"
+Note that the pattern must be quoted to prevent the shell from
+attempting to expand it according the files in the current working
+directory (the shell does not have access to the list of files in
+the archive, of course).
+.Pp
+To create a compressed archive on diskette, using gzip, use a command-line like
+.Dl tar --block-compress -z -c -v -f /dev/rfd1a -b 36 tar/
+Note that you cannot mix bundled flags and --style flags; you can use
+single-letter flags in the manner above, rather than having to type
+.Dl tar --block-compress --gzip --verbose --file /dev/rfd1a --block-size 20 tar/
+.Pp
+The above-created diskette can be listed with
+.Dl tar tvfbz /dev/rfd1a 36
+.Pp
+To join two tar archives into a single archive, use
+.Dl tar Af archive1.tar archive2.tar
+which will add the files contained in archive2.tar onto the end of
+archive1.tar (note that this can't be done by simply typing
+.Dl cat archive2.tar >> archive1.tar
+because of the end-of-file block at the end of a tar archive).
+.Sh ENVIRONMENT
+The tar program examines the following environment variables.
+.Bl -tag -width "POSIXLY-CORRECT"
+.It POSIXLY-CORRECT
+Normally, tar will process flag arguments that appear in the file list
+If set in the environment, this causes tar to consider the first
+non-flag argument to terminate flag processing, as per the POSIX specification.
+.It SHELL
+In interactive mode, a permissible response to the prompt is to
+request to spawn a subshell, which will be "/bin/sh" unless the SHELL variable
+is set.
+.It TAPE
+Changes tar's default tape drive (which is still overridden by the
+.Fl f
+flag).
+.El
+.Sh FILES
+.Bl -tag -width "/dev/rst0"
+.It Pa /dev/rst0
+The default tape drive.
+.El
+.\" This next request is for sections 1, 6, 7 & 8 only
+.\" (command return values (to shell) and fprintf/stderr type diagnostics)
+.\" .Sh DIAGNOSTICS
+.Sh SEE ALSO
+.Xr compress 1 ,
+.Xr gzip 1 ,
+.Xr pax 1 ,
+.Xr ft 8 ,
+.Xr rmt 8
+.\" .Sh STANDARDS
+.Sh HISTORY
+The tar format has a rich history, dating back to Sixth Edition UNIX.
+The current implementation of tar is the GNU implementation, which
+originated as the public-domain tar written by John Gilmore.
+.Sh AUTHORS
+A cast of thousands, including [as listed in the ChangeLog file in the
+source] John Gilmore (author of original public
+domain version), Jay Fenlason (first GNU author), Joy Kendall, Jim
+Kingdon, David J. MacKenzie, Michael I Bushnell, Noah Friedman, and
+innumerable others who have contributed fixes and additions.
+
+Man page obtained by the FreeBSD group from the NetBSD 1.0 release.
+.Sh BUGS
+The
+.Fl C
+feature does not work like historical tar programs, and is probably
+untrustworthy.
+.Pp
+The -A command should work to join an arbitrary number of tar archives
+together, but it does not; attempting to do so leaves the
+end-of-archive blocks in place for the second and subsequent archives.
diff --git a/gnu/usr.bin/tar/tar.c b/gnu/usr.bin/tar/tar.c
index 9382582..8fb8f81 100644
--- a/gnu/usr.bin/tar/tar.c
+++ b/gnu/usr.bin/tar/tar.c
@@ -25,6 +25,9 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
#include <stdio.h>
#include <sys/types.h> /* Needed for typedefs in tar.h */
+#ifdef __FreeBSD__
+#include <locale.h>
+#endif
#include "getopt.h"
/*
@@ -35,7 +38,7 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "tar.h"
#include "port.h"
-#include "regex.h"
+#include "gnuregex.h"
#include "fnmatch.h"
/*
@@ -84,6 +87,7 @@ void name_add ();
void name_init ();
void options ();
char *un_quote_string ();
+int nlpsfreed = 0;
#ifndef S_ISLNK
#define lstat stat
@@ -168,7 +172,7 @@ struct option long_options[] =
{"gzip", 0, 0, 'z'},
{"ungzip", 0, 0, 'z'},
{"use-compress-program", 1, 0, 18},
-
+
{"same-permissions", 0, &f_use_protection, 1},
{"sparse", 0, &f_sparse_files, 1},
@@ -181,6 +185,9 @@ struct option long_options[] =
{"force-local", 0, &f_force_local, 1},
{"atime-preserve", 0, &f_atime_preserve, 1},
+ {"unlink", 0, &f_unlink, 1},
+ {"fast-read", 0, &f_fast_read, 1},
+
{0, 0, 0, 0}
};
@@ -194,6 +201,10 @@ main (argc, argv)
{
extern char version_string[];
+#ifdef __FreeBSD__
+ (void) setlocale (LC_ALL, "");
+#endif
+
tar = argv[0]; /* JF: was "tar" Set program name */
filename_terminator = '\n';
errors = 0;
@@ -277,7 +288,7 @@ main (argc, argv)
}
if (f_volno_file)
closeout_volume_number ();
- exit (errors);
+ exit (errors ? EX_ARGSBAD : 0); /* FIXME (should be EX_NONDESCRIPT) */
/* NOTREACHED */
}
@@ -757,6 +768,8 @@ Other options:\n\
filter the archive through PROG (which must accept -d)\n\
--block-compress block the output of compression program for tapes\n\
-[0-7][lmh] specify drive and density\n\
+--unlink unlink files before creating them\n\
+--fast-read stop after desired names in archive have been found\n\
", stdout);
}
@@ -987,9 +1000,10 @@ name_gather ()
{
if (*p == '-' && p[1] == 'C' && p[2] == '\0')
{
- chdir_name = name_next (0);
p = name_next (0);
- if (!p)
+ chdir_name = p ? strdup(p) : p;
+ p = name_next (0);
+ if (!chdir_name)
{
msg ("Missing file name after -C");
exit (EX_ARGSBAD);
@@ -1031,7 +1045,8 @@ addname (name)
if (name[0] == '-' && name[1] == 'C' && name[2] == '\0')
{
- chdir_name = name_next (0);
+ name = name_next (0);
+ chdir_name = name ? strdup(name) : name;
name = name_next (0);
if (!chdir_name)
{
@@ -1118,6 +1133,7 @@ name_match (p)
register char *p;
{
register struct name *nlp;
+ struct name *tmpnlp;
register int len;
again:
@@ -1169,7 +1185,36 @@ again:
}
if (nlp->change_dir && chdir (nlp->change_dir))
msg_perror ("Can't change to directory %s", nlp->change_dir);
+ if (f_fast_read) {
+ if (strcmp(p, nlp->name) == 0) {
+ /* remove the current entry, since we found a match */
+ /* use brute force, this code is a mess anyway */
+ if (namelist->next == NULL) {
+ /* the list contains one element */
+ free(namelist);
+ namelist = NULL;
+ } else {
+ if (nlp == namelist) {
+ /* the first element is the one */
+ tmpnlp = namelist->next;
+ free(namelist);
+ namelist = tmpnlp;
+ } else {
+ tmpnlp = namelist;
+ while (tmpnlp->next != nlp) {
+ tmpnlp = tmpnlp->next;
+ }
+ tmpnlp->next = nlp->next;
+ free(nlp);
+ }
+ }
+ /* set a boolean to decide wether we started with a */
+ /* non-empty namelist, that was emptied */
+ nlpsfreed = 1;
+ }
+ }
return 1; /* We got a match */
+
}
}
diff --git a/gnu/usr.bin/tar/tar.h b/gnu/usr.bin/tar/tar.h
index c3fec78..21c5d52 100644
--- a/gnu/usr.bin/tar/tar.h
+++ b/gnu/usr.bin/tar/tar.h
@@ -231,6 +231,8 @@ TAR_EXTERN char *f_volno_file; /* --volno-file */
TAR_EXTERN int f_force_local; /* --force-local */
TAR_EXTERN int f_atime_preserve;/* --atime-preserve */
TAR_EXTERN int f_compress_block; /* --compress-block */
+TAR_EXTERN int f_unlink; /* --unlink */
+TAR_EXTERN int f_fast_read; /* --fast-read */
/*
* We default to Unix Standard format rather than 4.2BSD tar format.
@@ -273,6 +275,10 @@ TAR_EXTERN char *gnu_dumpfile;
*/
TAR_EXTERN char read_error_flag;
+/*
+ * global boolean, see name_match in tar.c
+ */
+extern int nlpsfreed;
/*
* Declarations of functions available to the world.
diff --git a/gnu/usr.bin/texinfo/Makefile b/gnu/usr.bin/texinfo/Makefile
new file mode 100644
index 0000000..172255c
--- /dev/null
+++ b/gnu/usr.bin/texinfo/Makefile
@@ -0,0 +1,9 @@
+#
+# Bmake file for texinfo
+# $Id: Makefile,v 1.2 1994/09/15 12:09:35 jkh Exp $
+#
+
+SUBDIR= info info-files makedoc makeinfo texindex doc
+
+.include <bsd.subdir.mk>
+
diff --git a/gnu/usr.bin/texinfo/Makefile.inc b/gnu/usr.bin/texinfo/Makefile.inc
new file mode 100644
index 0000000..9ee8dae
--- /dev/null
+++ b/gnu/usr.bin/texinfo/Makefile.inc
@@ -0,0 +1,4 @@
+# Texinfo defaults.
+# $Id: Makefile.inc,v 1.3 1995/07/08 16:45:49 joerg Exp $
+
+INFODIR?= /usr/share/info
diff --git a/gnu/usr.bin/texinfo/doc/Makefile b/gnu/usr.bin/texinfo/doc/Makefile
new file mode 100644
index 0000000..fed0a54
--- /dev/null
+++ b/gnu/usr.bin/texinfo/doc/Makefile
@@ -0,0 +1,8 @@
+INFO= info info-stnd makeinfo texi
+.if exists(../makeinfo/obj)
+MAKEINFO= ${.CURDIR}/../makeinfo/obj/makeinfo
+.else
+MAKEINFO= ${.CURDIR}/../makeinfo/makeinfo
+.endif
+
+.include <bsd.info.mk>
diff --git a/gnu/usr.bin/texinfo/doc/info-stnd.texi b/gnu/usr.bin/texinfo/doc/info-stnd.texi
new file mode 100644
index 0000000..286973b
--- /dev/null
+++ b/gnu/usr.bin/texinfo/doc/info-stnd.texi
@@ -0,0 +1,1359 @@
+\input texinfo @c -*-texinfo-*-
+@comment %**start of header
+@setfilename info-stnd.info
+@settitle GNU Info
+@set InfoProgVer 2.9
+@paragraphindent none
+@footnotestyle separate
+@synindex vr cp
+@synindex fn cp
+@synindex ky cp
+@comment %**end of header
+
+@ifinfo
+This file documents GNU Info, a program for viewing the on-line formatted
+versions of Texinfo files. This documentation is different from the
+documentation for the Info reader that is part of GNU Emacs. If you do
+not know how to use Info, but have a working Info reader, you should
+read that documentation first.
+
+Copyright @copyright{} 1992, 1993 Free Software Foundation, Inc.
+
+Permission is granted to make and distribute verbatim copies of this
+manual provided the copyright notice and this permission notice are
+preserved on all copies.
+
+@ignore
+Permission is granted to process this file through TeX and print the
+results, provided the printed document carries a copying permission
+notice identical to this one except for the removal of this paragraph
+(this paragraph not being relevant to the printed manual).
+@end ignore
+
+Permission is granted to copy and distribute modified versions of this
+manual under the conditions for verbatim copying, provided also that the
+sections entitled ``Copying'' and ``GNU General Public License'' are
+included exactly as in the original, and provided that the entire
+resulting derived work is distributed under the terms of a permission
+notice identical to this one.
+
+Permission is granted to copy and distribute translations of this manual
+into another language, under the above conditions for modified versions,
+except that this permission notice may be stated in a translation
+approved by the Free Software Foundation.
+@end ifinfo
+
+@titlepage
+@title GNU Info User's Guide
+@subtitle For GNU Info version @value{InfoProgVer}
+@author Brian J. Fox (bfox@@ai.mit.edu)
+@page
+@vskip 0pt plus 1filll
+Copyright @copyright{} 1992, 1993 Free Software Foundation
+
+Permission is granted to make and distribute verbatim copies of this
+manual provided the copyright notice and this permission notice are
+preserved on all copies.
+
+Permission is granted to copy and distribute modified versions of this
+manual under the conditions for verbatim copying, provided also that the
+sections entitled ``Copying'' and ``GNU General Public License'' are
+included exactly as in the original, and provided that the entire
+resulting derived work is distributed under the terms of a permission
+notice identical to this one.
+
+Permission is granted to copy and distribute translations of this manual
+into another language, under the above conditions for modified versions,
+except that this permission notice may be stated in a translation
+approved by the Free Software Foundation.
+@end titlepage
+
+@ifinfo
+@node Top, What is Info, (dir), (dir)
+@top The GNU Info Program
+
+This file documents GNU Info, a program for viewing the on-line
+formatted versions of Texinfo files, version @value{InfoProgVer}. This
+documentation is different from the documentation for the Info reader
+that is part of GNU Emacs.
+@end ifinfo
+
+@menu
+* What is Info::
+* Options:: Options you can pass on the command line.
+* Cursor Commands:: Commands which move the cursor within a node.
+* Scrolling Commands:: Commands for moving the node around
+ in a window.
+* Node Commands:: Commands for selecting a new node.
+* Searching Commands:: Commands for searching an Info file.
+* Xref Commands:: Commands for selecting cross references.
+* Window Commands:: Commands which manipulate multiple windows.
+* Printing Nodes:: How to print out the contents of a node.
+* Miscellaneous Commands:: A few commands that defy categories.
+* Variables:: How to change the default behavior of Info.
+* GNU Info Global Index:: Global index containing keystrokes,
+ command names, variable names,
+ and general concepts.
+@end menu
+
+@node What is Info, Options, Top, Top
+@chapter What is Info?
+
+@iftex
+This file documents GNU Info, a program for viewing the on-line formatted
+versions of Texinfo files, version @value{InfoProgVer}.
+@end iftex
+
+@dfn{Info} is a program which is used to view Info files on an ASCII
+terminal. @dfn{Info files} are the result of processing Texinfo files
+with the program @code{makeinfo} or with one of the Emacs commands, such
+as @code{M-x texinfo-format-buffer}. Texinfo itself is a documentation
+system that uses a single source file to produce both on-line
+information and printed output. You can typeset and print the
+files that you read in Info.@refill
+
+@node Options, Cursor Commands, What is Info, Top
+@chapter Command Line Options
+@cindex command line options
+@cindex arguments, command line
+
+GNU Info accepts several options to control the initial node being
+viewed, and to specify which directories to search for Info files. Here
+is a template showing an invocation of GNU Info from the shell:
+
+@example
+info [--@var{option-name} @var{option-value}] @var{menu-item}@dots{}
+@end example
+
+The following @var{option-names} are available when invoking Info from
+the shell:
+
+@table @code
+@cindex directory path
+@item --directory @var{directory-path}
+@itemx -d @var{directory-path}
+Add @var{directory-path} to the list of directory paths searched when
+Info needs to find a file. You may issue @code{--directory} multiple
+times; once for each directory which contains Info files.
+Alternatively, you may specify a value for the environment variable
+@code{INFOPATH}; if @code{--directory} is not given, the value of
+@code{INFOPATH} is used. The value of @code{INFOPATH} is a colon
+separated list of directory names. If you do not supply @code{INFOPATH}
+or @code{--directory-path}, Info uses a default path.
+
+@item --file @var{filename}
+@itemx -f @var{filename}
+@cindex Info file, selecting
+Specify a particular Info file to visit. By default, Info visits
+the file @code{dir}; if you use this option, Info will start with
+@code{(@var{filename})Top} as the first file and node.
+
+@item --node @var{nodename}
+@itemx -n @var{nodename}
+@cindex node, selecting
+Specify a particular node to visit in the initial file that Info
+loads. This is especially useful in conjunction with
+@code{--file}@footnote{Of course, you can specify both the file and node
+in a @code{--node} command; but don't forget to escape the open and
+close parentheses from the shell as in: @code{info --node
+'(emacs)Buffers'}}. You may specify @code{--node} multiple times; for
+an interactive Info, each @var{nodename} is visited in its own window,
+for a non-interactive Info (such as when @code{--output} is given) each
+@var{nodename} is processed sequentially.
+
+@item --output @var{filename}
+@itemx -o @var{filename}
+@cindex file, outputting to
+@cindex outputting to a file
+Specify @var{filename} as the name of a file to which to direct output.
+Each node that Info visits will be output to @var{filename} instead of
+interactively viewed. A value of @code{-} for @var{filename} specifies
+the standard output.
+
+@item --subnodes
+@cindex @code{--subnodes}, command line option
+This option only has meaning when given in conjunction with
+@code{--output}. It means to recursively output the nodes appearing in
+the menus of each node being output. Menu items which resolve to
+external Info files are not output, and neither are menu items which are
+members of an index. Each node is only output once.
+
+@item --help
+@itemx -h
+Produces a relatively brief description of the available Info options.
+
+@item --version
+@cindex version information
+Prints the version information of Info and exits.
+
+@item @var{menu-item}
+@cindex menu, following
+Info treats its remaining arguments as the names of menu items. The
+first argument is a menu item in the initial node visited, while
+the second argument is a menu item in the first argument's node.
+You can easily move to the node of your choice by specifying the menu
+names which describe the path to that node. For example,
+
+@example
+info emacs buffers
+@end example
+
+@noindent
+first selects the menu item @samp{Emacs} in the node @samp{(dir)Top},
+and then selects the menu item @samp{Buffers} in the node
+@samp{(emacs)Top}.
+@end table
+
+@node Cursor Commands, Scrolling Commands, Options, Top
+@chapter Moving the Cursor
+@cindex cursor, moving
+
+Many people find that reading screens of text page by page is made
+easier when one is able to indicate particular pieces of text with some
+kind of pointing device. Since this is the case, GNU Info (both the
+Emacs and standalone versions) have several commands which allow you to
+move the cursor about the screen. The notation used in this manual to
+describe keystrokes is identical to the notation used within the Emacs
+manual, and the GNU Readline manual. @xref{Characters, , Character
+Conventions, emacs, the GNU Emacs Manual}, if you are unfamiliar with the
+notation.
+
+The following table lists the basic cursor movement commands in Info.
+Each entry consists of the key sequence you should type to execute the
+cursor movement, the @code{M-x}@footnote{@code{M-x} is also a command; it
+invokes @code{execute-extended-command}. @xref{M-x, , Executing an
+extended command, emacs, the GNU Emacs Manual}, for more detailed
+information.} command name (displayed in parentheses), and a short
+description of what the command does. All of the cursor motion commands
+can take an @dfn{numeric} argument (@pxref{Miscellaneous Commands,
+@code{universal-argument}}), to find out how to supply them. With a
+numeric argument, the motion commands are simply executed that
+many times; for example, a numeric argument of 4 given to
+@code{next-line} causes the cursor to move down 4 lines. With a
+negative numeric argument, the motion is reversed; an argument of -4
+given to the @code{next-line} command would cause the cursor to move
+@emph{up} 4 lines.
+
+@table @asis
+@item @code{C-n} (@code{next-line})
+@kindex C-n
+@findex next-line
+Move the cursor down to the next line.
+
+@item @code{C-p} (@code{prev-line})
+@kindex C-p
+@findex prev-line
+Move the cursor up to the previous line.
+
+@item @code{C-a} (@code{beginning-of-line})
+@kindex C-a, in Info windows
+@findex beginning-of-line
+Move the cursor to the start of the current line.
+
+@item @code{C-e} (@code{end-of-line})
+@kindex C-e, in Info windows
+@findex end-of-line
+Move the cursor to the end of the current line.
+
+@item @code{C-f} (@code{forward-char})
+@kindex C-f, in Info windows
+@findex forward-char
+Move the cursor forward a character.
+
+@item @code{C-b} (@code{backward-char})
+@kindex C-b, in Info windows
+@findex backward-char
+Move the cursor backward a character.
+
+@item @code{M-f} (@code{forward-word})
+@kindex M-f, in Info windows
+@findex forward-word
+Move the cursor forward a word.
+
+@item @code{M-b} (@code{backward-word})
+@kindex M-b, in Info windows
+@findex backward-word
+Move the cursor backward a word.
+
+@item @code{M-<} (@code{beginning-of-node})
+@itemx @code{b}
+@kindex b, in Info windows
+@kindex M-<
+@findex beginning-of-node
+Move the cursor to the start of the current node.
+
+@item @code{M->} (@code{end-of-node})
+@kindex M->
+@findex end-of-node
+Move the cursor to the end of the current node.
+
+@item @code{M-r} (@code{move-to-window-line})
+@kindex M-r
+@findex move-to-window-line
+Move the cursor to a specific line of the window. Without a numeric
+argument, @code{M-r} moves the cursor to the start of the line in the
+center of the window. With a numeric argument of @var{n}, @code{M-r}
+moves the cursor to the start of the @var{n}th line in the window.
+@end table
+
+@node Scrolling Commands, Node Commands, Cursor Commands, Top
+@chapter Moving Text Within a Window
+@cindex scrolling
+
+Sometimes you are looking at a screenful of text, and only part of the
+current paragraph you are reading is visible on the screen. The
+commands detailed in this section are used to shift which part of the
+current node is visible on the screen.
+
+@table @asis
+@item @code{SPC} (@code{scroll-forward})
+@itemx @code{C-v}
+@kindex SPC, in Info windows
+@kindex C-v
+@findex scroll-forward
+Shift the text in this window up. That is, show more of the node which
+is currently below the bottom of the window. With a numeric argument,
+show that many more lines at the bottom of the window; a numeric
+argument of 4 would shift all of the text in the window up 4 lines
+(discarding the top 4 lines), and show you four new lines at the bottom
+of the window. Without a numeric argument, @key{SPC} takes the bottom
+two lines of the window and places them at the top of the window,
+redisplaying almost a completely new screenful of lines.
+
+@item @code{DEL} (@code{scroll-backward})
+@itemx @code{M-v}
+@kindex DEL, in Info windows
+@kindex M-v
+@findex scroll-backward
+Shift the text in this window down. The inverse of
+@code{scroll-forward}.
+@end table
+
+@cindex scrolling through node structure
+The @code{scroll-forward} and @code{scroll-backward} commands can also
+move forward and backward through the node structure of the file. If
+you press @key{SPC} while viewing the end of a node, or @key{DEL} while
+viewing the beginning of a node, what happens is controlled by the
+variable @code{scroll-behavior}. @xref{Variables,
+@code{scroll-behavior}}, for more information.
+
+@table @asis
+@item @code{C-l} (@code{redraw-display})
+@kindex C-l
+@findex redraw-display
+Redraw the display from scratch, or shift the line containing the cursor
+to a specified location. With no numeric argument, @samp{C-l} clears
+the screen, and then redraws its entire contents. Given a numeric
+argument of @var{n}, the line containing the cursor is shifted so that
+it is on the @var{n}th line of the window.
+
+@item @code{C-x w} (@code{toggle-wrap})
+@kindex C-w
+@findex toggle-wrap
+Toggles the state of line wrapping in the current window. Normally,
+lines which are longer than the screen width @dfn{wrap}, i.e., they are
+continued on the next line. Lines which wrap have a @samp{\} appearing
+in the rightmost column of the screen. You can cause such lines to be
+terminated at the rightmost column by changing the state of line
+wrapping in the window with @code{C-x w}. When a line which needs more
+space than one screen width to display is displayed, a @samp{$} appears
+in the rightmost column of the screen, and the remainder of the line is
+invisible.
+@end table
+
+@node Node Commands, Searching Commands, Scrolling Commands, Top
+@chapter Selecting a New Node
+@cindex nodes, selection of
+
+This section details the numerous Info commands which select a new node
+to view in the current window.
+
+The most basic node commands are @samp{n}, @samp{p}, @samp{u}, and
+@samp{l}.
+
+When you are viewing a node, the top line of the node contains some Info
+@dfn{pointers} which describe where the next, previous, and up nodes
+are. Info uses this line to move about the node structure of the file
+when you use the following commands:
+
+@table @asis
+@item @code{n} (@code{next-node})
+@kindex n
+@findex next-node
+Select the `Next' node.
+
+@item @code{p} (@code{prev-node})
+@kindex p
+@findex prev-node
+Select the `Prev' node.
+
+@item @code{u} (@code{up-node})
+@kindex u
+@findex up-node
+Select the `Up' node.
+@end table
+
+You can easily select a node that you have already viewed in this window
+by using the @samp{l} command -- this name stands for "last", and
+actually moves through the list of already visited nodes for this
+window. @samp{l} with a negative numeric argument moves forward through
+the history of nodes for this window, so you can quickly step between
+two adjacent (in viewing history) nodes.
+
+@table @asis
+@item @code{l} (@code{history-node})
+@kindex l
+@findex history-node
+Select the most recently selected node in this window.
+@end table
+
+Two additional commands make it easy to select the most commonly
+selected nodes; they are @samp{t} and @samp{d}.
+
+@table @asis
+@item @code{t} (@code{top-node})
+@kindex t
+@findex top-node
+Select the node @samp{Top} in the current Info file.
+
+@item @code{d} (@code{dir-node})
+@kindex d
+@findex dir-node
+Select the directory node (i.e., the node @samp{(dir)}).
+@end table
+
+Here are some other commands which immediately result in the selection
+of a different node in the current window:
+
+@table @asis
+@item @code{<} (@code{first-node})
+@kindex <
+@findex first-node
+Selects the first node which appears in this file. This node is most
+often @samp{Top}, but it does not have to be.
+
+@item @code{>} (@code{last-node})
+@kindex >
+@findex last-node
+Select the last node which appears in this file.
+
+@item @code{]} (@code{global-next-node})
+@kindex ]
+@findex global-next-node
+Move forward or down through node structure. If the node that you are
+currently viewing has a @samp{Next} pointer, that node is selected.
+Otherwise, if this node has a menu, the first menu item is selected. If
+there is no @samp{Next} and no menu, the same process is tried with the
+@samp{Up} node of this node.
+
+@item @code{[} (@code{global-prev-node})
+@kindex [
+@findex global-prev-node
+Move backward or up through node structure. If the node that you are
+currently viewing has a @samp{Prev} pointer, that node is selected.
+Otherwise, if the node has an @samp{Up} pointer, that node is selected,
+and if it has a menu, the last item in the menu is selected.
+@end table
+
+You can get the same behavior as @code{global-next-node} and
+@code{global-prev-node} while simply scrolling through the file with
+@key{SPC} and @key{DEL}; @xref{Variables, @code{scroll-behavior}}, for
+more information.
+
+@table @asis
+@item @code{g} (@code{goto-node})
+@kindex g
+@findex goto-node
+Read the name of a node and select it. No completion is done while
+reading the node name, since the desired node may reside in a separate
+file. The node must be typed exactly as it appears in the Info file. A
+file name may be included as with any node specification, for example
+
+@example
+@code{g(emacs)Buffers}
+@end example
+
+finds the node @samp{Buffers} in the Info file @file{emacs}.
+
+@item @code{C-x k} (@code{kill-node})
+@kindex C-x k
+@findex kill-node
+Kill a node. The node name is prompted for in the echo area, with a
+default of the current node. @dfn{Killing} a node means that Info tries
+hard to forget about it, removing it from the list of history nodes kept
+for the window where that node is found. Another node is selected in
+the window which contained the killed node.
+
+@item @code{C-x C-f} (@code{view-file})
+@kindex C-x C-f
+@findex view-file
+Read the name of a file and selects the entire file. The command
+@example
+@code{C-x C-f @var{filename}}
+@end example
+is equivalent to typing
+@example
+@code{g(@var{filename})*}
+@end example
+
+@item @code{C-x C-b} (@code{list-visited-nodes})
+@kindex C-x C-b
+@findex list-visited-nodes
+Make a window containing a menu of all of the currently visited nodes.
+This window becomes the selected window, and you may use the standard
+Info commands within it.
+
+@item @code{C-x b} (@code{select-visited-node})
+@kindex C-x b
+@findex select-visited-node
+Select a node which has been previously visited in a visible window.
+This is similar to @samp{C-x C-b} followed by @samp{m}, but no window is
+created.
+@end table
+
+@node Searching Commands, Xref Commands, Node Commands, Top
+@chapter Searching an Info File
+@cindex searching
+
+GNU Info allows you to search for a sequence of characters throughout an
+entire Info file, search through the indices of an Info file, or find
+areas within an Info file which discuss a particular topic.
+
+@table @asis
+@item @code{s} (@code{search})
+@kindex s
+@findex search
+Read a string in the echo area and search for it.
+
+@item @code{C-s} (@code{isearch-forward})
+@kindex C-s
+@findex isearch-forward
+Interactively search forward through the Info file for a string as you
+type it.
+
+@item @code{C-r} (@code{isearch-backward})
+@kindex C-r
+@findex isearch-backward
+Interactively search backward through the Info file for a string as
+you type it.
+
+@item @code{i} (@code{index-search})
+@kindex i
+@findex index-search
+Look up a string in the indices for this Info file, and select a node
+where the found index entry points to.
+
+@item @code{,} (@code{next-index-match})
+@kindex ,
+@findex next-index-match
+Move to the node containing the next matching index item from the last
+@samp{i} command.
+@end table
+
+The most basic searching command is @samp{s} (@code{search}). The
+@samp{s} command prompts you for a string in the echo area, and then
+searches the remainder of the Info file for an occurrence of that string.
+If the string is found, the node containing it is selected, and the
+cursor is left positioned at the start of the found string. Subsequent
+@samp{s} commands show you the default search string within @samp{[} and
+@samp{]}; pressing @key{RET} instead of typing a new string will use the
+default search string.
+
+@dfn{Incremental searching} is similar to basic searching, but the
+string is looked up while you are typing it, instead of waiting until
+the entire search string has been specified.
+
+@node Xref Commands, Window Commands, Searching Commands, Top
+@chapter Selecting Cross References
+
+We have already discussed the @samp{Next}, @samp{Prev}, and @samp{Up}
+pointers which appear at the top of a node. In addition to these
+pointers, a node may contain other pointers which refer you to a
+different node, perhaps in another Info file. Such pointers are called
+@dfn{cross references}, or @dfn{xrefs} for short.
+
+@menu
+* Parts of an Xref:: What a cross reference is made of.
+* Selecting Xrefs:: Commands for selecting menu or note items.
+@end menu
+
+@node Parts of an Xref, Selecting Xrefs, , Xref Commands
+@section Parts of an Xref
+
+Cross references have two major parts: the first part is called the
+@dfn{label}; it is the name that you can use to refer to the cross
+reference, and the second is the @dfn{target}; it is the full name of
+the node that the cross reference points to.
+
+The target is separated from the label by a colon @samp{:}; first the
+label appears, and then the target. For example, in the sample menu
+cross reference below, the single colon separates the label from the
+target.
+
+@example
+* Foo Label: Foo Target. More information about Foo.
+@end example
+
+Note the @samp{.} which ends the name of the target. The @samp{.} is
+not part of the target; it serves only to let Info know where the target
+name ends.
+
+A shorthand way of specifying references allows two adjacent colons to
+stand for a target name which is the same as the label name:
+
+@example
+* Foo Commands:: Commands pertaining to Foo.
+@end example
+
+In the above example, the name of the target is the same as the name of
+the label, in this case @code{Foo Commands}.
+
+You will normally see two types of cross reference while viewing nodes:
+@dfn{menu} references, and @dfn{note} references. Menu references
+appear within a node's menu; they begin with a @samp{*} at the beginning
+of a line, and continue with a label, a target, and a comment which
+describes what the contents of the node pointed to contains.
+
+Note references appear within the body of the node text; they begin with
+@code{*Note}, and continue with a label and a target.
+
+Like @samp{Next}, @samp{Prev}, and @samp{Up} pointers, cross references
+can point to any valid node. They are used to refer you to a place
+where more detailed information can be found on a particular subject.
+Here is a cross reference which points to a node within the Texinfo
+documentation: @xref{xref, , Writing an Xref, texinfo, the Texinfo
+Manual}, for more information on creating your own texinfo cross
+references.
+
+@node Selecting Xrefs, , Parts of an Xref, Xref Commands
+@section Selecting Xrefs
+
+The following table lists the Info commands which operate on menu items.
+
+@table @asis
+@item @code{1} (@code{menu-digit})
+@itemx @code{2} @dots{} @code{9}
+@cindex 1 @dots{} 9, in Info windows
+@kindex 1 @dots{} 9, in Info windows
+@findex menu-digit
+Within an Info window, pressing a single digit, (such as @samp{1}),
+selects that menu item, and places its node in the current window.
+For convenience, there is one exception; pressing @samp{0} selects the
+@emph{last} item in the node's menu.
+
+@item @code{0} (@code{last-menu-item})
+@kindex 0, in Info windows
+@findex last-menu-item
+Select the last item in the current node's menu.
+
+@item @code{m} (@code{menu-item})
+@kindex m
+@findex menu-item
+Reads the name of a menu item in the echo area and selects its node.
+Completion is available while reading the menu label.
+
+@item @code{M-x find-menu}
+@findex find-menu
+Move the cursor to the start of this node's menu.
+@end table
+
+This table lists the Info commands which operate on note cross references.
+
+@table @asis
+@item @code{f} (@code{xref-item})
+@itemx @code{r}
+@kindex f
+@kindex r
+@findex xref-item
+Reads the name of a note cross reference in the echo area and selects
+its node. Completion is available while reading the cross reference
+label.
+@end table
+
+Finally, the next few commands operate on menu or note references alike:
+
+@table @asis
+@item @code{TAB} (@code{move-to-next-xref})
+@kindex TAB, in Info windows
+@findex move-to-next-xref
+Move the cursor to the start of the next nearest menu item or note
+reference in this node. You can then use @key{RET}
+(@code{select-reference-this-line}) to select the menu or note reference.
+
+@item @code{M-TAB} (@code{move-to-prev-xref})
+@kindex M-TAB, in Info windows
+@findex move-to-prev-xref
+Move the cursor the start of the nearest previous menu item or note
+reference in this node.
+
+@item @code{RET} (@code{select-reference-this-line})
+@kindex RET, in Info windows
+@findex select-reference-this-line
+Select the menu item or note reference appearing on this line.
+@end table
+
+@node Window Commands, Printing Nodes, Xref Commands, Top
+@chapter Manipulating Multiple Windows
+@cindex windows, manipulating
+
+A @dfn{window} is a place to show the text of a node. Windows have a
+view area where the text of the node is displayed, and an associated
+@dfn{mode line}, which briefly describes the node being viewed.
+
+GNU Info supports multiple windows appearing in a single screen; each
+window is separated from the next by its modeline. At any time, there
+is only one @dfn{active} window, that is, the window in which the cursor
+appears. There are commands available for creating windows, changing
+the size of windows, selecting which window is active, and for deleting
+windows.
+
+@menu
+* The Mode Line:: What appears in the mode line?
+* Basic Windows:: Manipulating windows in Info.
+* The Echo Area:: Used for displaying errors and reading input.
+@end menu
+
+@node The Mode Line, Basic Windows, , Window Commands
+@section The Mode Line
+
+A @dfn{mode line} is a line of inverse video which appears at the bottom
+of an Info window. It describes the contents of the window just above
+it; this information includes the name of the file and node appearing in
+that window, the number of screen lines it takes to display the node,
+and the percentage of text that is above the top of the window. It can
+also tell you if the indirect tags table for this Info file needs to be
+updated, and whether or not the Info file was compressed when stored on
+disk.
+
+Here is a sample mode line for a window containing an uncompressed file
+named @file{dir}, showing the node @samp{Top}.
+
+@example
+@group
+-----Info: (dir)Top, 40 lines --Top---------------------------------------
+ ^^ ^ ^^^ ^^
+ (file)Node #lines where
+@end group
+@end example
+
+When a node comes from a file which is compressed on disk, this is
+indicated in the mode line with two small @samp{z}'s. In addition, if
+the Info file containing the node has been split into subfiles, the name
+of the subfile containing the node appears in the modeline as well:
+
+@example
+--zz-Info: (emacs)Top, 291 lines --Top-- Subfile: emacs-1.Z---------------
+@end example
+
+When Info makes a node internally, such that there is no corresponding
+info file on disk, the name of the node is surrounded by asterisks
+(@samp{*}). The name itself tells you what the contents of the window
+are; the sample mode line below shows an internally constructed node
+showing possible completions:
+
+@example
+-----Info: *Completions*, 7 lines --All-----------------------------------
+@end example
+
+@node Basic Windows, The Echo Area, The Mode Line, Window Commands
+@section Window Commands
+
+It can be convenient to view more than one node at a time. To allow
+this, Info can display more than one @dfn{window}. Each window has its
+own mode line (@pxref{The Mode Line}) and history of nodes viewed in that
+window (@pxref{Node Commands, , @code{history-node}}).
+
+@table @asis
+@item @code{C-x o} (@code{next-window})
+@cindex windows, selecting
+@kindex C-x o
+@findex next-window
+Select the next window on the screen. Note that the echo area can only be
+selected if it is already in use, and you have left it temporarily.
+Normally, @samp{C-x o} simply moves the cursor into the next window on
+the screen, or if you are already within the last window, into the first
+window on the screen. Given a numeric argument, @samp{C-x o} moves over
+that many windows. A negative argument causes @samp{C-x o} to select
+the previous window on the screen.
+
+@item @code{M-x prev-window}
+@findex prev-window
+Select the previous window on the screen. This is identical to
+@samp{C-x o} with a negative argument.
+
+@item @code{C-x 2} (@code{split-window})
+@cindex windows, creating
+@kindex C-x 2
+@findex split-window
+Split the current window into two windows, both showing the same node.
+Each window is one half the size of the original window, and the cursor
+remains in the original window. The variable @code{automatic-tiling}
+can cause all of the windows on the screen to be resized for you
+automatically, please @pxref{Variables, , automatic-tiling} for more
+information.
+
+@item @code{C-x 0} (@code{delete-window})
+@cindex windows, deleting
+@kindex C-x 0
+@findex delete-window
+Delete the current window from the screen. If you have made too many
+windows and your screen appears cluttered, this is the way to get rid of
+some of them.
+
+@item @code{C-x 1} (@code{keep-one-window})
+@kindex C-x 1
+@findex keep-one-window
+Delete all of the windows excepting the current one.
+
+@item @code{ESC C-v} (@code{scroll-other-window})
+@kindex ESC C-v, in Info windows
+@findex scroll-other-window
+Scroll the other window, in the same fashion that @samp{C-v} might
+scroll the current window. Given a negative argument, scroll the
+"other" window backward.
+
+@item @code{C-x ^} (@code{grow-window})
+@kindex C-x ^
+@findex grow-window
+Grow (or shrink) the current window. Given a numeric argument, grow
+the current window that many lines; with a negative numeric argument,
+shrink the window instead.
+
+@item @code{C-x t} (@code{tile-windows})
+@cindex tiling
+@kindex C-x t
+@findex tile-windows
+Divide the available screen space among all of the visible windows.
+Each window is given an equal portion of the screen in which to display
+its contents. The variable @code{automatic-tiling} can cause
+@code{tile-windows} to be called when a window is created or deleted.
+@xref{Variables, , @code{automatic-tiling}}.
+@end table
+
+@node The Echo Area, , Basic Windows, Window Commands
+@section The Echo Area
+@cindex echo area
+
+The @dfn{echo area} is a one line window which appears at the bottom of
+the screen. It is used to display informative or error messages, and to
+read lines of input from you when that is necessary. Almost all of the
+commands available in the echo area are identical to their Emacs
+counterparts, so please refer to that documentation for greater depth of
+discussion on the concepts of editing a line of text. The following
+table briefly lists the commands that are available while input is being
+read in the echo area:
+
+@table @asis
+@item @code{C-f} (@code{echo-area-forward})
+@kindex C-f, in the echo area
+@findex echo-area-forward
+Move forward a character.
+
+@item @code{C-b} (@code{echo-area-backward})
+@kindex C-b, in the echo area
+@findex echo-area-backward
+Move backward a character.
+
+@item @code{C-a} (@code{echo-area-beg-of-line})
+@kindex C-a, in the echo area
+@findex echo-area-beg-of-line
+Move to the start of the input line.
+
+@item @code{C-e} (@code{echo-area-end-of-line})
+@kindex C-e, in the echo area
+@findex echo-area-end-of-line
+Move to the end of the input line.
+
+@item @code{M-f} (@code{echo-area-forward-word})
+@kindex M-f, in the echo area
+@findex echo-area-forward-word
+Move forward a word.
+
+@item @code{M-b} (@code{echo-area-backward-word})
+@kindex M-b, in the echo area
+@findex echo-area-backward-word
+Move backward a word.
+
+@item @code{C-d} (@code{echo-area-delete})
+@kindex C-d, in the echo area
+@findex echo-area-delete
+Delete the character under the cursor.
+
+@item @code{DEL} (@code{echo-area-rubout})
+@kindex DEL, in the echo area
+@findex echo-area-rubout
+Delete the character behind the cursor.
+
+@item @code{C-g} (@code{echo-area-abort})
+@kindex C-g, in the echo area
+@findex echo-area-abort
+Cancel or quit the current operation. If completion is being read,
+@samp{C-g} discards the text of the input line which does not match any
+completion. If the input line is empty, @samp{C-g} aborts the calling
+function.
+
+@item @code{RET} (@code{echo-area-newline})
+@kindex RET, in the echo area
+@findex echo-area-newline
+Accept (or forces completion of) the current input line.
+
+@item @code{C-q} (@code{echo-area-quoted-insert})
+@kindex C-q, in the echo area
+@findex echo-area-quoted-insert
+Insert the next character verbatim. This is how you can insert control
+characters into a search string, for example.
+
+@item @var{printing character} (@code{echo-area-insert})
+@kindex printing characters, in the echo area
+@findex echo-area-insert
+Insert the character.
+
+@item @code{M-TAB} (@code{echo-area-tab-insert})
+@kindex M-TAB, in the echo area
+@findex echo-area-tab-insert
+Insert a TAB character.
+
+@item @code{C-t} (@code{echo-area-transpose-chars})
+@kindex C-t, in the echo area
+@findex echo-area-transpose-chars
+Transpose the characters at the cursor.
+@end table
+
+The next group of commands deal with @dfn{killing}, and @dfn{yanking}
+text. For an in depth discussion of killing and yanking,
+@pxref{Killing, , Killing and Deleting, emacs, the GNU Emacs Manual}
+
+@table @asis
+@item @code{M-d} (@code{echo-area-kill-word})
+@kindex M-d, in the echo area
+@findex echo-area-kill-word
+Kill the word following the cursor.
+
+@item @code{M-DEL} (@code{echo-area-backward-kill-word})
+@kindex M-DEL, in the echo area
+@findex echo-area-backward-kill-word
+Kill the word preceding the cursor.
+
+@item @code{C-k} (@code{echo-area-kill-line})
+@kindex C-k, in the echo area
+@findex echo-area-kill-line
+Kill the text from the cursor to the end of the line.
+
+@item @code{C-x DEL} (@code{echo-area-backward-kill-line})
+@kindex C-x DEL, in the echo area
+@findex echo-area-backward-kill-line
+Kill the text from the cursor to the beginning of the line.
+
+@item @code{C-y} (@code{echo-area-yank})
+@kindex C-y, in the echo area
+@findex echo-area-yank
+Yank back the contents of the last kill.
+
+@item @code{M-y} (@code{echo-area-yank-pop})
+@kindex M-y, in the echo area
+@findex echo-area-yank-pop
+Yank back a previous kill, removing the last yanked text first.
+@end table
+
+Sometimes when reading input in the echo area, the command that needed
+input will only accept one of a list of several choices. The choices
+represent the @dfn{possible completions}, and you must respond with one
+of them. Since there are a limited number of responses you can make,
+Info allows you to abbreviate what you type, only typing as much of the
+response as is necessary to uniquely identify it. In addition, you can
+request Info to fill in as much of the response as is possible; this
+is called @dfn{completion}.
+
+The following commands are available when completing in the echo area:
+
+@table @asis
+@item @code{TAB} (@code{echo-area-complete})
+@itemx @code{SPC}
+@kindex TAB, in the echo area
+@kindex SPC, in the echo area
+@findex echo-area-complete
+Insert as much of a completion as is possible.
+
+@item @code{?} (@code{echo-area-possible-completions})
+@kindex ?, in the echo area
+@findex echo-area-possible-completions
+Display a window containing a list of the possible completions of what
+you have typed so far. For example, if the available choices are:
+
+@example
+@group
+bar
+foliate
+food
+forget
+@end group
+@end example
+
+@noindent
+and you have typed an @samp{f}, followed by @samp{?}, the possible
+completions would contain:
+
+@example
+@group
+foliate
+food
+forget
+@end group
+@end example
+
+@noindent
+i.e., all of the choices which begin with @samp{f}. Pressing @key{SPC}
+or @key{TAB} would result in @samp{fo} appearing in the echo area, since
+all of the choices which begin with @samp{f} continue with @samp{o}.
+Now, typing @samp{l} followed by @samp{TAB} results in @samp{foliate}
+appearing in the echo area, since that is the only choice which begins
+with @samp{fol}.
+
+@item @code{ESC C-v} (@code{echo-area-scroll-completions-window})
+@kindex ESC C-v, in the echo area
+@findex echo-area-scroll-completions-window
+Scroll the completions window, if that is visible, or the "other"
+window if not.
+@end table
+
+@node Printing Nodes, Miscellaneous Commands, Window Commands, Top
+@chapter Printing Out Nodes
+@cindex printing
+
+You may wish to print out the contents of a node as a quick reference
+document for later use. Info provides you with a command for doing
+this. In general, we recommend that you use @TeX{} to format the
+document and print sections of it, by running @code{tex} on the Texinfo
+source file.
+
+@table @asis
+@item @code{M-x print-node}
+@findex print-node
+@cindex INFO_PRINT_COMMAND, environment variable
+Pipe the contents of the current node through the command in the
+environment variable @code{INFO_PRINT_COMMAND}. If the variable does not
+exist, the node is simply piped to @code{lpr}.
+@end table
+
+@node Miscellaneous Commands, Variables, Printing Nodes, Top
+@chapter Miscellaneous Commands
+
+GNU Info contains several commands which self-document GNU Info:
+
+@table @asis
+@item @code{M-x describe-command}
+@cindex functions, describing
+@cindex commands, describing
+@findex describe-command
+Read the name of an Info command in the echo area and then display a
+brief description of what that command does.
+
+@item @code{M-x describe-key}
+@cindex keys, describing
+@findex describe-key
+Read a key sequence in the echo area, and then display the name and
+documentation of the Info command that the key sequence invokes.
+
+@item @code{M-x describe-variable}
+Read the name of a variable in the echo area and then display a brief
+description of what the variable affects.
+
+@item @code{M-x where-is}
+@findex where-is
+Read the name of an Info command in the echo area, and then display
+a key sequence which can be typed in order to invoke that command.
+
+@item @code{C-h} (@code{get-help-window})
+@itemx @code{?}
+@kindex C-h
+@kindex ?, in Info windows
+@findex get-help-window
+Create (or Move into) the window displaying @code{*Help*}, and place
+a node containing a quick reference card into it. This window displays
+the most concise information about GNU Info available.
+
+@item @code{h} (@code{get-info-help-node})
+@kindex h
+@findex get-info-help-node
+Try hard to visit the node @code{(info)Help}. The Info file
+@file{info.texi} distributed with GNU Info contains this node. Of
+course, the file must first be processed with @code{makeinfo}, and then
+placed into the location of your Info directory.
+@end table
+
+Here are the commands for creating a numeric argument:
+
+@table @asis
+@item @code{C-u} (@code{universal-argument})
+@cindex numeric arguments
+@kindex C-u
+@findex universal-argument
+Start (or multiply by 4) the current numeric argument. @samp{C-u} is
+a good way to give a small numeric argument to cursor movement or
+scrolling commands; @samp{C-u C-v} scrolls the screen 4 lines, while
+@samp{C-u C-u C-n} moves the cursor down 16 lines.
+
+@item @code{M-1} (@code{add-digit-to-numeric-arg})
+@itemx @code{M-2} @dots{} @code{M-9}
+@kindex M-1 @dots{} M-9
+@findex add-digit-to-numeric-arg
+Add the digit value of the invoking key to the current numeric
+argument. Once Info is reading a numeric argument, you may just type
+the digits of the argument, without the Meta prefix. For example, you
+might give @samp{C-l} a numeric argument of 32 by typing:
+
+@example
+@kbd{C-u 3 2 C-l}
+@end example
+
+@noindent
+or
+
+@example
+@kbd{M-3 2 C-l}
+@end example
+@end table
+
+@samp{C-g} is used to abort the reading of a multi-character key
+sequence, to cancel lengthy operations (such as multi-file searches) and
+to cancel reading input in the echo area.
+
+@table @asis
+@item @code{C-g} (@code{abort-key})
+@cindex cancelling typeahead
+@cindex cancelling the current operation
+@kindex C-g, in Info windows
+@findex abort-key
+Cancel current operation.
+@end table
+
+The @samp{q} command of Info simply quits running Info.
+
+@table @asis
+@item @code{q} (@code{quit})
+@cindex quitting
+@kindex q
+@findex quit
+Exit GNU Info.
+@end table
+
+If the operating system tells GNU Info that the screen is 60 lines tall,
+and it is actually only 40 lines tall, here is a way to tell Info that
+the operating system is correct.
+
+@table @asis
+@item @code{M-x set-screen-height}
+@findex set-screen-height
+@cindex screen, changing the height of
+Read a height value in the echo area and set the height of the
+displayed screen to that value.
+@end table
+
+Finally, Info provides a convenient way to display footnotes which might
+be associated with the current node that you are viewing:
+
+@table @asis
+@item @code{ESC C-f} (@code{show-footnotes})
+@kindex ESC C-f
+@findex show-footnotes
+@cindex footnotes, displaying
+Show the footnotes (if any) associated with the current node in another
+window. You can have Info automatically display the footnotes
+associated with a node when the node is selected by setting the variable
+@code{automatic-footnotes}. @xref{Variables, , @code{automatic-footnotes}}.
+@end table
+
+@node Variables, GNU Info Global Index, Miscellaneous Commands, Top
+@chapter Manipulating Variables
+
+GNU Info contains several @dfn{variables} whose values are looked at by various
+Info commands. You can change the values of these variables, and thus
+change the behavior of Info to more closely match your environment and
+Info file reading manner.
+
+@table @asis
+@item @code{M-x set-variable}
+@cindex variables, setting
+@findex set-variable
+Read the name of a variable, and the value for it, in the echo area and
+then set the variable to that value. Completion is available when
+reading the variable name; often, completion is available when reading
+the value to give to the variable, but that depends on the variable
+itself. If a variable does @emph{not} supply multiple choices to
+complete over, it expects a numeric value.
+
+@item @code{M-x describe-variable}
+@cindex variables, describing
+@findex describe-variable
+Read the name of a variable in the echo area and then display a brief
+description of what the variable affects.
+@end table
+
+Here is a list of the variables that you can set in Info.
+
+@table @code
+@item automatic-footnotes
+@vindex automatic-footnotes
+When set to @code{On}, footnotes appear and disappear automatically.
+This variable is @code{On} by default. When a node is selected, a
+window containing the footnotes which appear in that node is created,
+and the footnotes are displayed within the new window. The window that
+Info creates to contain the footnotes is called @samp{*Footnotes*}. If
+a node is selected which contains no footnotes, and a @samp{*Footnotes*}
+window is on the screen, the @samp{*Footnotes*} window is deleted.
+Footnote windows created in this fashion are not automatically tiled so
+that they can use as little of the display as is possible.
+
+@item automatic-tiling
+@vindex automatic-tiling
+When set to @code{On}, creating or deleting a window resizes other
+windows. This variable is @code{Off} by default. Normally, typing
+@samp{C-x 2} divides the current window into two equal parts. When
+@code{automatic-tiling} is set to @code{On}, all of the windows are
+resized automatically, keeping an equal number of lines visible in each
+window. There are exceptions to the automatic tiling; specifically, the
+windows @samp{*Completions*} and @samp{*Footnotes*} are @emph{not}
+resized through automatic tiling; they remain their original size.
+
+@item visible-bell
+@vindex visible-bell
+When set to @code{On}, GNU Info attempts to flash the screen instead of
+ringing the bell. This variable is @code{Off} by default. Of course,
+Info can only flash the screen if the terminal allows it; in the case
+that the terminal does not allow it, the setting of this variable has no
+effect. However, you can make Info perform quietly by setting the
+@code{errors-ring-bell} variable to @code{Off}.
+
+@item errors-ring-bell
+@vindex errors-ring-bell
+When set to @code{On}, errors cause the bell to ring. The default
+setting of this variable is @code{On}.
+
+@item gc-compressed-files
+@vindex gc-compressed-files
+When set to @code{On}, Info garbage collects files which had to be
+uncompressed. The default value of this variable is @code{Off}.
+Whenever a node is visited in Info, the Info file containing that node
+is read into core, and Info reads information about the tags and nodes
+contained in that file. Once the tags information is read by Info, it
+is never forgotten. However, the actual text of the nodes does not need
+to remain in core unless a particular Info window needs it. For
+non-compressed files, the text of the nodes does not remain in core when
+it is no longer in use. But de-compressing a file can be a time
+consuming operation, and so Info tries hard not to do it twice.
+@code{gc-compressed-files} tells Info it is okay to garbage collect the
+text of the nodes of a file which was compressed on disk.
+
+@item show-index-match
+@vindex show-index-match
+When set to @code{On}, the portion of the matched search string is
+highlighted in the message which explains where the matched search
+string was found. The default value of this variable is @code{On}.
+When Info displays the location where an index match was found,
+(@pxref{Searching Commands, , @code{next-index-match}}), the portion of the
+string that you had typed is highlighted by displaying it in the inverse
+case from its surrounding characters.
+
+@item scroll-behavior
+@vindex scroll-behavior
+Control what happens when forward scrolling is requested at the end of
+a node, or when backward scrolling is requested at the beginning of a
+node. The default value for this variable is @code{Continuous}. There
+are three possible values for this variable:
+
+@table @code
+@item Continuous
+Try to get the first item in this node's menu, or failing that, the
+@samp{Next} node, or failing that, the @samp{Next} of the @samp{Up}.
+This behavior is identical to using the @samp{]}
+(@code{global-next-node}) and @samp{[} (@code{global-prev-node})
+commands.
+
+@item Next Only
+Only try to get the @samp{Next} node.
+
+@item Page Only
+Simply give up, changing nothing. If @code{scroll-behavior} is
+@code{Page Only}, no scrolling command can change the node that is being
+viewed.
+@end table
+
+@item scroll-step
+@vindex scroll-step
+The number of lines to scroll when the cursor moves out of the window.
+Scrolling happens automatically if the cursor has moved out of the
+visible portion of the node text when it is time to display. Usually
+the scrolling is done so as to put the cursor on the center line of the
+current window. However, if the variable @code{scroll-step} has a
+nonzero value, Info attempts to scroll the node text by that many lines;
+if that is enough to bring the cursor back into the window, that is what
+is done. The default value of this variable is 0, thus placing the
+cursor (and the text it is attached to) in the center of the window.
+Setting this variable to 1 causes a kind of "smooth scrolling" which
+some people prefer.
+
+@item ISO-Latin
+@cindex ISO Latin characters
+@vindex ISO-Latin
+When set to @code{On}, Info accepts and displays ISO Latin characters.
+By default, Info assumes an ASCII character set. @code{ISO-Latin} tells
+Info that it is running in an environment where the European standard
+character set is in use, and allows you to input such characters to
+Info, as well as display them.
+@end table
+
+
+
+@c the following is incomplete
+@ignore
+@c node Info for Sys Admins
+@c chapter Info for System Administrators
+
+This text describes some common ways of setting up an Info hierarchy
+from scratch, and details the various options that are available when
+installing Info. This text is designed for the person who is installing
+GNU Info on the system; although users may find the information present
+in this section interesting, none of it is vital to understanding how to
+use GNU Info.
+
+@menu
+* Setting the INFOPATH:: Where are my Info files kept?
+* Editing the DIR node:: What goes in `DIR', and why?
+* Storing Info files:: Alternate formats allow flexibility in setups.
+* Using `localdir':: Building DIR on the fly.
+* Example setups:: Some common ways to organize Info files.
+@end menu
+
+@c node Setting the INFOPATH
+@c section Setting the INFOPATH
+
+Where are my Info files kept?
+
+@c node Editing the DIR node
+@c section Editing the DIR node
+
+What goes in `DIR', and why?
+
+@c node Storing Info files
+@c section Storing Info files
+
+Alternate formats allow flexibility in setups.
+
+@c node Using `localdir'
+@c section Using `localdir'
+
+Building DIR on the fly.
+
+@c node Example setups
+@c section Example setups
+
+Some common ways to organize Info files.
+@end ignore
+
+@node GNU Info Global Index, , Variables, Top
+@appendix Global Index
+
+@printindex cp
+
+@contents
+@bye
diff --git a/gnu/usr.bin/texinfo/doc/info.texi b/gnu/usr.bin/texinfo/doc/info.texi
new file mode 100644
index 0000000..5eec9f1
--- /dev/null
+++ b/gnu/usr.bin/texinfo/doc/info.texi
@@ -0,0 +1,861 @@
+\input texinfo @c -*-texinfo-*-
+@comment %**start of header
+@setfilename info.info
+@settitle Info 1.0
+@comment %**end of header
+
+@iftex
+@finalout
+@end iftex
+
+@ifinfo
+This file describes how to use Info,
+the on-line, menu-driven GNU documentation system.
+
+Copyright (C) 1989, 1992 Free Software Foundation, Inc.
+
+Permission is granted to make and distribute verbatim copies of
+this manual provided the copyright notice and this permission notice
+are preserved on all copies.
+
+@ignore
+Permission is granted to process this file through TeX and print the
+results, provided the printed document carries copying permission
+notice identical to this one except for the removal of this paragraph
+(this paragraph not being relevant to the printed manual).
+
+@end ignore
+Permission is granted to copy and distribute modified versions of this
+manual under the conditions for verbatim copying, provided that the entire
+resulting derived work is distributed under the terms of a permission
+notice identical to this one.
+
+Permission is granted to copy and distribute translations of this manual
+into another language, under the above conditions for modified versions,
+except that this permission notice may be stated in a translation approved
+by the Free Software Foundation.
+@end ifinfo
+
+@setchapternewpage odd
+@titlepage
+@sp 11
+@center @titlefont{Info}
+@sp 2
+@center The
+@sp 2
+@center On-line, Menu-driven
+@sp 2
+@center GNU Documentation System
+
+@page
+@vskip 0pt plus 1filll
+Copyright @copyright{} 1989, 1992, 1993 Free Software Foundation, Inc.
+@sp 2
+
+Published by the Free Software Foundation @*
+675 Massachusetts Avenue, @*
+Cambridge, MA 02139 USA @*
+
+Permission is granted to make and distribute verbatim copies of
+this manual provided the copyright notice and this permission notice
+are preserved on all copies.
+
+Permission is granted to copy and distribute modified versions of this
+manual under the conditions for verbatim copying, provided that the entire
+resulting derived work is distributed under the terms of a permission
+notice identical to this one.
+
+Permission is granted to copy and distribute translations of this manual
+into another language, under the above conditions for modified versions,
+except that this permission notice may be stated in a translation approved
+by the Free Software Foundation.
+@end titlepage
+
+@ifinfo
+@node Top, Getting Started, (dir), (dir)
+@top Info: An Introduction
+
+Info is a program for reading documentation, which you are using now.
+
+To learn how to use Info, type the command @kbd{h}. It brings you
+to a programmed instruction sequence.
+
+@c Need to make sure that `Info-help' goes to the right node,
+@c which is the first node of the first chapter. (It should.)
+@c (Info-find-node "info"
+@c (if (< (window-height) 23)
+@c "Help-Small-Screen"
+@c "Help")))
+
+To learn advanced Info commands, type @kbd{n} twice. This
+brings you to @cite{Info for Experts}, skipping over the .
+`Getting Started' chapter.
+@end ifinfo
+
+@menu
+* Getting Started::
+* Advanced Info::
+* Create an Info File::
+@end menu
+
+@node Getting Started, Advanced Info, Top, Top
+@comment node-name, next, previous, up
+@chapter Getting Started
+
+This first part of the Info manual describes how to get around inside
+of Info. The second part of the manual describes various advanced
+Info commands, and how to write an Info as distinct from a Texinfo
+file. The third part is about how to generate Info files from
+Texinfo files.
+
+@iftex
+This manual is primarily designed for use on a computer, so that you can
+try Info commands while reading about them. Reading it on paper is less
+effective, since you must take it on faith that the commands described
+really do what the manual says. By all means go through this manual now
+that you have it; but please try going through the on-line version as
+well.
+
+There are two ways of looking at the online version of this manual:
+
+@enumerate
+@item
+Type @code{info} at your shell's command line. This approach uses a
+small stand-alone program designed just to read Info files.
+
+@item
+Type @code{emacs} at the command line; then type @kbd{C-h i} (Control
+@kbd{h}, followed by @kbd{i}). This approach uses
+the Info mode of the Emacs program, an editor with many other
+capabilities.
+@end enumerate
+
+In either case, then type @kbd{mInfo} (just the letters), followed by
+@key{RET}---the ``Return'' or ``Enter'' key. At this point, you should
+be ready to follow the instructions in this manual as you read them on
+the screen.
+@c FIXME! (pesch@cygnus.com, 14 dec 1992)
+@c Is it worth worrying about what-if the beginner goes to somebody
+@c else's Emacs session, which already has an Info running in the middle
+@c of something---in which case these simple instructions won't work?
+@end iftex
+
+@menu
+* Help-Small-Screen:: Starting Info on a Small Screen
+* Help:: How to use Info
+* Help-P:: Returning to the Previous node
+* Help-^L:: The Space, Rubout, B and ^L commands.
+* Help-M:: Menus
+* Help-Adv:: Some advanced Info commands
+* Help-Q:: Quitting Info
+@end menu
+
+@node Help-Small-Screen, Help, , Getting Started
+@comment node-name, next, previous, up
+@section Starting Info on a Small Screen
+
+@iftex
+(In Info, you only see this section if your terminal has a small
+number of lines; most readers pass by it without seeing it.)
+@end iftex
+
+Since your terminal has an unusually small number of lines on its
+screen, it is necessary to give you special advice at the beginning.
+
+If you see the text @samp{--All----} at near the bottom right corner
+of the screen, it means the entire text you are looking at fits on the
+screen. If you see @samp{--Top----} instead, it means that there is
+more text below that does not fit. To move forward through the text
+and see another screen full, press the Space bar, @key{SPC}. To move
+back up, press the key labeled @samp{Rubout} or @samp{Delete} or
+@key{DEL}.
+
+@ifinfo
+Here are 40 lines of junk, so you can try @key{SPC} and @key{DEL} and
+see what they do. At the end are instructions of what you should do
+next.
+
+This is line 17 @*
+This is line 18 @*
+This is line 19 @*
+This is line 20 @*
+This is line 21 @*
+This is line 22 @*
+This is line 23 @*
+This is line 24 @*
+This is line 25 @*
+This is line 26 @*
+This is line 27 @*
+This is line 28 @*
+This is line 29 @*
+This is line 30 @*
+This is line 31 @*
+This is line 32 @*
+This is line 33 @*
+This is line 34 @*
+This is line 35 @*
+This is line 36 @*
+This is line 37 @*
+This is line 38 @*
+This is line 39 @*
+This is line 40 @*
+This is line 41 @*
+This is line 42 @*
+This is line 43 @*
+This is line 44 @*
+This is line 45 @*
+This is line 46 @*
+This is line 47 @*
+This is line 48 @*
+This is line 49 @*
+This is line 50 @*
+This is line 51 @*
+This is line 52 @*
+This is line 53 @*
+This is line 54 @*
+This is line 55 @*
+This is line 56 @*
+
+If you have managed to get here, go back to the beginning with
+@key{DEL}, and come back here again, then you understand @key{SPC} and
+@key{DEL}. So now type an @kbd{n}---just one character; do not type
+the quotes and do not type the Return key, @key{RET}, afterward---to
+get to the normal start of the course.
+@end ifinfo
+
+@node Help, Help-P, Help-Small-Screen, Getting Started
+@comment node-name, next, previous, up
+@section How to use Info
+
+You are talking to the program Info, for reading documentation.
+
+ Right now you are looking at one @dfn{Node} of Information.
+A node contains text describing a specific topic at a specific
+level of detail. This node's topic is ``how to use Info''.
+
+ The top line of a node is its @dfn{header}. This node's header (look at
+it now) says that it is the node named @samp{Help} in the file
+@file{info}. It says that the @samp{Next} node after this one is the node
+called @samp{Help-P}. An advanced Info command lets you go to any node
+whose name you know.
+
+ Besides a @samp{Next}, a node can have a @samp{Previous} or an @samp{Up}.
+This node has a @samp{Previous} but no @samp{Up}, as you can see.
+
+ Now it is time to move on to the @samp{Next} node, named @samp{Help-P}.
+
+>> Type @samp{n} to move there. Type just one character;
+ do not type the quotes and do not type a @key{RET} afterward.
+
+@samp{>>} in the margin means it is really time to try a command.
+
+@node Help-P, Help-^L, Help, Getting Started
+@comment node-name, next, previous, up
+@section Returning to the Previous node
+
+This node is called @samp{Help-P}. The @samp{Previous} node, as you see,
+is @samp{Help}, which is the one you just came from using the @kbd{n}
+command. Another @kbd{n} command now would take you to the next
+node, @samp{Help-^L}.
+
+>> But do not do that yet. First, try the @kbd{p} command, which takes
+ you to the @samp{Previous} node. When you get there, you can do an
+ @kbd{n} again to return here.
+
+ This all probably seems insultingly simple so far, but @emph{do not} be
+led into skimming. Things will get more complicated soon. Also,
+do not try a new command until you are told it is time to. Otherwise,
+you may make Info skip past an important warning that was coming up.
+
+>> Now do an @kbd{n} to get to the node @samp{Help-^L} and learn more.
+
+@node Help-^L, Help-M, Help-P, Getting Started
+@comment node-name, next, previous, up
+@section The Space, Rubout, B and ^L commands.
+
+ This node's header tells you that you are now at node @samp{Help-^L}, and
+that @kbd{p} would get you back to @samp{Help-P}. The node's title is
+underlined; it says what the node is about (most nodes have titles).
+
+ This is a big node and it does not all fit on your display screen.
+You can tell that there is more that is not visible because you
+can see the string @samp{--Top-----} rather than @samp{--All----} near
+the bottom right corner of the screen.
+
+ The @key{SPC}, @key{DEL} and @kbd{b} commands exist to allow you to ``move
+around'' in a node that does not all fit on the screen at once.
+@key{SPC} moves forward, to show what was below the bottom of the screen.
+@key{DEL} moves backward, to show what was above the top of the screen
+(there is not anything above the top until you have typed some spaces).
+
+>> Now try typing a @key{SPC} (afterward, type a @key{DEL} to return here).
+
+ When you type the @key{SPC}, the two lines that were at the bottom
+of the screen appear at the top, followed by more lines. @key{DEL}
+takes the two lines from the top and moves them to the bottom,
+@emph{usually}, but if there are not a full screen's worth of lines above
+them they may not make it all the way to the bottom.
+
+ If you type a @key{SPC} when there is no more to see, it rings the
+bell and otherwise does nothing. The same goes for a @key{DEL} when
+the header of the node is visible.
+
+ If your screen is ever garbaged, you can tell Info to print it out
+again by typing @kbd{C-l} (@kbd{Control-L}, that is---hold down ``Control'' and
+type an @key{L} or @kbd{l}).
+
+>> Type @kbd{C-l} now.
+
+ To move back to the beginning of the node you are on, you can type
+a lot of @key{DEL}s. You can also type simply @kbd{b} for beginning.
+
+>> Try that now. (I have put in enough verbiage to make sure you are
+ not on the first screenful now). Then come back, typing @key{SPC}
+ several times.
+
+ You have just learned a considerable number of commands. If you
+want to use one but have trouble remembering which, you should type
+a @key{?} which prints out a brief list of commands. When you are
+finished looking at the list, make it go away by typing a @key{SPC}.
+
+>> Type a @key{?} now. After it finishes, type a @key{SPC}.
+
+ (If you are using the standalone Info reader, type `l' to return here.)
+
+ From now on, you will encounter large nodes without warning, and
+will be expected to know how to use @key{SPC} and @key{DEL} to move
+around in them without being told. Since not all terminals have
+the same size screen, it would be impossible to warn you anyway.
+
+>> Now type @kbd{n} to see the description of the @kbd{m} command.
+
+@node Help-M, Help-Adv, Help-^L, Getting Started
+@comment node-name, next, previous, up
+@section Menus
+
+Menus and the @kbd{m} command
+
+ With only the @kbd{n} and @kbd{p} commands for moving between nodes, nodes
+are restricted to a linear sequence. Menus allow a branching
+structure. A menu is a list of other nodes you can move to. It is
+actually just part of the text of the node formatted specially so that
+Info can interpret it. The beginning of a menu is always identified
+by a line which starts with @samp{* Menu:}. A node contains a menu if and
+only if it has a line in it which starts that way. The only menu you
+can use at any moment is the one in the node you are in. To use a
+menu in any other node, you must move to that node first.
+
+ After the start of the menu, each line that starts with a @samp{*}
+identifies one subtopic. The line usually contains a brief name
+for the subtopic (followed by a @samp{:}), the name of the node that talks
+about that subtopic, and optionally some further description of the
+subtopic. Lines in the menu that do not start with a @samp{*} have no
+special meaning---they are only for the human reader's benefit and do
+not define additional subtopics. Here is an example:
+
+@example
+* Foo: FOO's Node This tells about FOO
+@end example
+
+The subtopic name is Foo, and the node describing it is @samp{FOO's Node}.
+The rest of the line is just for the reader's Information.
+[[ But this line is not a real menu item, simply because there is
+no line above it which starts with @samp{* Menu:}.]]
+
+ When you use a menu to go to another node (in a way that will be
+described soon), what you specify is the subtopic name, the first
+thing in the menu line. Info uses it to find the menu line, extracts
+the node name from it, and goes to that node. The reason that there
+is both a subtopic name and a node name is that the node name must be
+meaningful to the computer and may therefore have to be ugly looking.
+The subtopic name can be chosen just to be convenient for the user to
+specify. Often the node name is convenient for the user to specify
+and so both it and the subtopic name are the same. There is an
+abbreviation for this:
+
+@example
+* Foo:: This tells about FOO
+@end example
+
+@noindent
+This means that the subtopic name and node name are the same; they are
+both @samp{Foo}.
+
+>> Now use @key{SPC}s to find the menu in this node, then come back to
+ the front with a @kbd{b}. As you see, a menu is actually visible in
+ its node. If you cannot find a menu in a node by looking at it,
+ then the node does not have a menu and the @kbd{m} command is not
+ available.
+
+ The command to go to one of the subnodes is @kbd{m}---but @emph{do not do it
+yet!} Before you use @kbd{m}, you must understand the difference between
+commands and arguments. So far, you have learned several commands
+that do not need arguments. When you type one, Info processes it and
+is instantly ready for another command. The @kbd{m} command is different:
+it is incomplete without the @dfn{name of the subtopic}. Once you have
+typed @kbd{m}, Info tries to read the subtopic name.
+
+ Now look for the line containing many dashes near the bottom of the
+screen. There is one more line beneath that one, but usually it is
+blank If it is empty, Info is ready for a command, such as @kbd{n} or @kbd{b}
+or @key{SPC} or @kbd{m}. If that line contains text ending in a colon, it
+mean Info is trying to read the @dfn{argument} to a command. At such
+times, commands do not work, because Info tries to use them as the
+argument. You must either type the argument and finish the command
+you started, or type @kbd{Control-g} to cancel the command. When you have
+done one of those things, the line becomes blank again.
+
+ The command to go to a subnode via a menu is @kbd{m}. After you type
+the @kbd{m}, the line at the bottom of the screen says @samp{Menu item: }.
+You must then type the name of the subtopic you want, and end it with
+a @key{RET}.
+
+ You can abbreviate the subtopic name. If the abbreviation is not
+unique, the first matching subtopic is chosen. Some menus put
+the shortest possible abbreviation for each subtopic name in capital
+letters, so you can see how much you need to type. It does not
+matter whether you use upper case or lower case when you type the
+subtopic. You should not put any spaces at the end, or inside of the
+item name, except for one space where a space appears in the item in
+the menu.
+
+ Here is a menu to give you a chance to practice.
+
+* Menu: The menu starts here.
+
+This menu givs you three ways of going to one place, Help-FOO.
+
+* Foo: Help-FOO. A node you can visit for fun.@*
+* Bar: Help-FOO. Strange! two ways to get to the same place.@*
+* Help-FOO:: And yet another!@*
+
+
+>> Now type just an @kbd{m} and see what happens:
+
+ Now you are ``inside'' an @kbd{m} command. Commands cannot be used
+now; the next thing you will type must be the name of a subtopic.
+
+ You can change your mind about doing the @kbd{m} by typing Control-g.
+
+>> Try that now; notice the bottom line clear.
+
+>> Then type another @kbd{m}.
+
+>> Now type @samp{BAR} item name. Do not type @key{RET} yet.
+
+ While you are typing the item name, you can use the @key{DEL}
+character to cancel one character at a time if you make a mistake.
+
+>> Type one to cancel the @samp{R}. You could type another @samp{R} to
+ replace it. You do not have to, since @samp{BA} is a valid abbreviation.
+
+>> Now you are ready to go. Type a @key{RET}.
+
+ After visiting Help-FOO, you should return here.
+
+>> Type @kbd{n} to see more commands.
+
+@c If a menu appears at the end of this node, remove it.
+@c It is an accident of the menu updating command.
+
+Here is another way to get to Help-FOO, a menu. You can ignore this
+if you want, or else try it (but then please come back to here).
+
+@menu
+* Help-FOO::
+@end menu
+
+@node Help-FOO, , , Help-M
+@comment node-name, next, previous, up
+@subsection The @kbd{u} command
+
+ Congratulations! This is the node @samp{Help-FOO}. Unlike the other
+nodes you have seen, this one has an @samp{Up}: @samp{Help-M}, the node you
+just came from via the @kbd{m} command. This is the usual
+convention---the nodes you reach from a menu have @samp{Up} nodes that lead
+back to the menu. Menus move Down in the tree, and @samp{Up} moves Up.
+@samp{Previous}, on the other hand, is usually used to ``stay on the same
+level but go backwards''
+
+ You can go back to the node @samp{Help-M} by typing the command
+@kbd{u} for ``Up''. That puts you at the @emph{front} of the
+node---to get back to where you were reading you have to type
+some @key{SPC}s.
+
+>> Now type @kbd{u} to move back up to @samp{Help-M}.
+
+@node Help-Adv, Help-Q, Help-M, Getting Started
+@comment node-name, next, previous, up
+@section Some advanced Info commands
+
+ The course is almost over, so please stick with it to the end.
+
+ If you have been moving around to different nodes and wish to
+retrace your steps, the @kbd{l} command (@kbd{l} for @dfn{last}) will
+do that, one node at a time. If you have been following directions,
+an @kbd{l} command now will get you back to @samp{Help-M}. Another
+@kbd{l} command would undo the @kbd{u} and get you back to
+@samp{Help-FOO}. Another @kbd{l} would undo the @kbd{m} and get you
+back to @samp{Help-M}.
+
+>> Try typing three @kbd{l}'s, pausing in between to see what each
+ @kbd{l} does.
+
+Then follow directions again and you will end up back here.
+
+ Note the difference between @kbd{l} and @kbd{p}: @kbd{l} moves to
+where @emph{you} last were, whereas @kbd{p} always moves to the node
+which the header says is the @samp{Previous} node (from this node, to
+@samp{Help-M}).
+
+ The @samp{d} command gets you instantly to the Directory node.
+This node, which is the first one you saw when you entered Info,
+has a menu which leads (directly, or indirectly through other menus),
+to all the nodes that exist.
+
+>> Try doing a @samp{d}, then do an @kbd{l} to return here (yes,
+ @emph{do} return).
+
+ Sometimes, in Info documentation, you will see a cross reference.
+Cross references look like this: @xref{Help-Cross, Cross}. That is a
+real, live cross reference which is named @samp{Cross} and points at
+the node named @samp{Help-Cross}.
+
+ If you wish to follow a cross reference, you must use the @samp{f}
+command. The @samp{f} must be followed by the cross reference name
+(in this case, @samp{Cross}). You can use @key{DEL} to edit the name,
+and if you change your mind about following any reference you can use
+@kbd{Control-g} to cancel the command.
+
+ Completion is available in the @samp{f} command; you can complete among
+all the cross reference names in the current node.
+
+>> Type @samp{f}, followed by @samp{Cross}, and a @key{RET}.
+
+ To get a list of all the cross references in the current node, you can
+type @kbd{?} after an @samp{f}. The @samp{f} continues to await a
+cross reference name even after printing the list, so if you do not
+actually want to follow a reference you should type a @kbd{Control-g}
+to cancel the @samp{f}.
+
+>> Type "f?" to get a list of the footnotes in this node. Then type a
+ @kbd{Control-g} and see how the @samp{f} gives up.
+
+>> Now type @kbd{n} to see the last node of the course.
+
+@c If a menu appears at the end of this node, remove it.
+@c It is an accident of the menu updating command.
+
+@node Help-Cross, , , Help-Adv
+@comment node-name, next, previous, up
+@unnumberedsubsec The node reached by the cross reference in Info
+
+ This is the node reached by the cross reference named @samp{Cross}.
+
+ While this node is specifically intended to be reached by a cross
+reference, most cross references lead to nodes that ``belong''
+someplace else far away in the structure of Info. So you cannot expect
+the footnote to have a @samp{Next}, @samp{Previous} or @samp{Up} pointing back to
+where you came from. In general, the @kbd{l} (el) command is the only
+way to get back there.
+
+>> Type @kbd{l} to return to the node where the cross reference was.
+
+@node Help-Q, , Help-Adv, Getting Started
+@comment node-name, next, previous, up
+@section Quitting Info
+
+ To get out of Info, back to what you were doing before, type @kbd{q}
+for @dfn{Quit}.
+
+ This is the end of the course on using Info. There are some other
+commands that are not essential or are meant for experienced users;
+they are useful, and you can find them by looking in the directory for
+documentation on Info. Finding them will be a good exercise in using
+Info in the usual manner.
+
+>> Type @samp{d} to go to the Info directory node; then type
+ @samp{mInfo} and @key{RET}, to get to the node about Info
+ and see what other help is available.
+
+@node Advanced Info, Create an Info File, Getting Started, Top
+@comment node-name, next, previous, up
+@chapter Info for Experts
+
+This chapter describes various advanced Info commands, and how to write
+an Info as distinct from a Texinfo file. (However, in most cases, writing a
+Texinfo file is better, since you can use it @emph{both} to generate an
+Info file and to make a printed manual. @xref{Top,, Overview of
+Texinfo, texinfo, Texinfo: The GNU Documentation Format}.)
+
+@menu
+* Expert:: Advanced Info commands: g, s, e, and 1 - 5.
+* Add:: Describes how to add new nodes to the hierarchy.
+ Also tells what nodes look like.
+* Menus:: How to add to or create menus in Info nodes.
+* Cross-refs:: How to add cross-references to Info nodes.
+* Tags:: How to make tag tables for Info files.
+* Checking:: Checking an Info File
+@end menu
+
+@node Expert, Add, , Advanced Info
+@comment node-name, next, previous, up
+@section Advanced Info Commands
+
+@kbd{g}, @kbd{s}, @kbd{1}, -- @kbd{5}, and @kbd{e}
+
+If you know a node's name, you can go there by typing @kbd{g}, the
+name, and @key{RET}. Thus, @kbd{gTop@key{RET}} would go to the node
+called @samp{Top} in this file (its directory node).
+@kbd{gExpert@key{RET}} would come back here.
+
+Unlike @kbd{m}, @kbd{g} does not allow the use of abbreviations.
+
+To go to a node in another file, you can include the filename in the
+node name by putting it at the front, in parentheses. Thus,
+@kbd{g(dir)Top@key{RET}} would go to the Info Directory node, which is
+node @samp{Top} in the file @file{dir}.
+
+The node name @samp{*} specifies the whole file. So you can look at
+all of the current file by typing @kbd{g*@key{RET}} or all of any
+other file with @kbd{g(FILENAME)@key{RET}}.
+
+The @kbd{s} command allows you to search a whole file for a string.
+It switches to the next node if and when that is necessary. You
+type @kbd{s} followed by the string to search for, terminated by
+@key{RET}. To search for the same string again, just @kbd{s} followed
+by @key{RET} will do. The file's nodes are scanned in the order
+they are in in the file, which has no necessary relationship to the
+order that they may be in in the tree structure of menus and @samp{next} pointers.
+But normally the two orders are not very different. In any case,
+you can always do a @kbd{b} to find out what node you have reached, if
+the header is not visible (this can happen, because @kbd{s} puts your
+cursor at the occurrence of the string, not at the beginning of the
+node).
+
+If you grudge the system each character of type-in it requires, you
+might like to use the commands @kbd{1}, @kbd{2}, @kbd{3}, @kbd{4}, and
+@kbd{5}. They are short for the @kbd{m} command together with an
+argument. "1", "2", "3", "4", and "5". @kbd{1} goes through the
+first item in the current node's menu; @kbd{2} goes through the second
+item, etc. Note that numbers larger than 5 are not allowed. If the
+item you want is that far down, you are better off using an
+abbreviation for its name than counting.
+
+The Info command @kbd{e} changes from Info mode to an ordinary
+Emacs editing mode, so that you can edit the text of the current node.
+Type @kbd{C-c C-c} to switch back to Info. The @kbd{e} command is allowed
+only if the variable @code{Info-enable-edit} is non-@code{nil}.
+
+@node Add, Menus, Expert, Advanced Info
+@comment node-name, next, previous, up
+@section Adding a new node to Info
+
+To add a new topic to the list in the directory, you must:
+
+@enumerate
+@item
+Create a node, in some file, to document that topic.
+
+@item
+Put that topic in the menu in the directory. @xref{Menus, Menu}.
+@end enumerate
+
+ The new node can live in an existing documentation file, or in a new
+one. It must have a @key{^_} character before it (invisible to the
+user; this node has one but you cannot see it), and it ends with either
+a @key{^_}, a @key{^L}, or the end of file. Note: If you put in a
+@key{^L} to end a new node, be sure that there is a @key{^_} after it
+to start the next one, since @key{^L} cannot @emph{start} a node.
+Also, a nicer way to make a node boundary be a page boundary as well
+is to put a @key{^L} @emph{right after} the @key{^_}.
+
+ The @key{^_} starting a node must be followed by a newline or a
+@key{^L} newline, after which comes the node's header line. The
+header line must give the node's name (by which Info finds it),
+and state the names of the @samp{Next}, @samp{Previous}, and @samp{Up} nodes (if
+there are any). As you can see, this node's @samp{Up} node is the node
+@samp{Top}, which points at all the documentation for Info. The @samp{Next}
+node is @samp{Menus}.
+
+ The keywords @dfn{Node}, @dfn{Previous}, @dfn{Up} and @dfn{Next},
+may appear in any order, anywhere in the header line, but the
+recommended order is the one in this sentence. Each keyword must be
+followed by a colon, spaces and tabs, and then the appropriate name.
+The name may be terminated with a tab, a comma, or a newline. A space
+does not end it; node names may contain spaces. The case of letters
+in the names is insignificant.
+
+ A node name has two forms. A node in the current file is named by
+what appears after the @samp{Node: } in that node's first line. For
+example, this node's name is @samp{Add}. A node in another file is
+named by @samp{(@var{filename})@var{node-within-file}}, as in
+@samp{(info)Add} for this node. If the file name is relative, it is
+taken starting from the standard Info file directory of your site.
+The name @samp{(@var{filename})Top} can be abbreviated to just
+@samp{(@var{filename})}. By convention, the name @samp{Top} is used for
+the ``highest'' node in any single file---the node whose @samp{Up} points
+out of the file. The Directory node is @file{(dir)}. The @samp{Top} node
+of a document file listed in the Directory should have an @samp{Up:
+(dir)} in it.
+
+ The node name @kbd{*} is special: it refers to the entire file.
+Thus, @kbd{g*} shows you the whole current file. The use of the
+node @kbd{*} is to make it possible to make old-fashioned,
+unstructured files into nodes of the tree.
+
+ The @samp{Node:} name, in which a node states its own name, must not
+contain a filename, since Info when searching for a node does not
+expect one to be there. The @samp{Next}, @samp{Previous} and @samp{Up} names may
+contain them. In this node, since the @samp{Up} node is in the same file,
+it was not necessary to use one.
+
+ Note that the nodes in this file have a file name in the header
+line. The file names are ignored by Info, but they serve as comments
+to help identify the node for the user.
+
+@node Menus, Cross-refs, Add, Advanced Info
+@comment node-name, next, previous, up
+@section How to Create Menus
+
+ Any node in the Info hierarchy may have a @dfn{menu}---a list of subnodes.
+The @kbd{m} command searches the current node's menu for the topic which it
+reads from the terminal.
+
+ A menu begins with a line starting with @samp{* Menu:}. The rest of the
+line is a comment. After the starting line, every line that begins
+with a @samp{* } lists a single topic. The name of the topic--the
+argument that the user must give to the @kbd{m} command to select this
+topic---comes right after the star and space, and is followed by a
+colon, spaces and tabs, and the name of the node which discusses that
+topic. The node name, like node names following @samp{Next}, @samp{Previous}
+and @samp{Up}, may be terminated with a tab, comma, or newline; it may also
+be terminated with a period.
+
+ If the node name and topic name are the same, than rather than
+giving the name twice, the abbreviation @samp{* NAME::} may be used
+(and should be used, whenever possible, as it reduces the visual
+clutter in the menu).
+
+ It is considerate to choose the topic names so that they differ
+from each other very near the beginning---this allows the user to type
+short abbreviations. In a long menu, it is a good idea to capitalize
+the beginning of each item name which is the minimum acceptable
+abbreviation for it (a long menu is more than 5 or so entries).
+
+ The nodes listed in a node's menu are called its ``subnodes'', and
+it is their ``superior''. They should each have an @samp{Up:} pointing at
+the superior. It is often useful to arrange all or most of the
+subnodes in a sequence of @samp{Next} and @samp{Previous} pointers so that someone who
+wants to see them all need not keep revisiting the Menu.
+
+ The Info Directory is simply the menu of the node @samp{(dir)Top}---that
+is, node @samp{Top} in file @file{.../info/dir}. You can put new entries
+in that menu just like any other menu. The Info Directory is @emph{not} the
+same as the file directory called @file{info}. It happens that many of
+Info's files live on that file directory, but they do not have to; and
+files on that directory are not automatically listed in the Info
+Directory node.
+
+ Also, although the Info node graph is claimed to be a ``hierarchy'',
+in fact it can be @emph{any} directed graph. Shared structures and
+pointer cycles are perfectly possible, and can be used if they are
+appropriate to the meaning to be expressed. There is no need for all
+the nodes in a file to form a connected structure. In fact, this file
+has two connected components. You are in one of them, which is under
+the node @samp{Top}; the other contains the node @samp{Help} which the
+@kbd{h} command goes to. In fact, since there is no garbage
+collector, nothing terrible happens if a substructure is not pointed
+to, but such a substructure is rather useless since nobody can
+ever find out that it exists.
+
+@node Cross-refs, Tags, Menus, Advanced Info
+@comment node-name, next, previous, up
+@section Creating Cross References
+
+ A cross reference can be placed anywhere in the text, unlike a menu
+item which must go at the front of a line. A cross reference looks
+like a menu item except that it has @samp{*note} instead of @kbd{*}.
+It @emph{cannot} be terminated by a @samp{)}, because @samp{)}'s are
+so often part of node names. If you wish to enclose a cross reference
+in parentheses, terminate it with a period first. Here are two
+examples of cross references pointers:
+
+@example
+*Note details: commands. (See *note 3: Full Proof.)
+@end example
+
+They are just examples. The places they ``lead to'' do not really exist!
+
+@node Tags, Checking, Cross-refs, Advanced Info
+@comment node-name, next, previous, up
+@section Tag Tables for Info Files
+
+ You can speed up the access to nodes of a large Info file by giving
+it a tag table. Unlike the tag table for a program, the tag table for
+an Info file lives inside the file itself and is used
+automatically whenever Info reads in the file.
+
+ To make a tag table, go to a node in the file using Emacs Info mode and type
+@kbd{M-x Info-tagify}. Then you must use @kbd{C-x C-s} to save the
+file.
+
+ Once the Info file has a tag table, you must make certain it is up
+to date. If, as a result of deletion of text, any node moves back
+more than a thousand characters in the file from the position
+recorded in the tag table, Info will no longer be able to find that
+node. To update the tag table, use the @code{Info-tagify} command again.
+
+ An Info file tag table appears at the end of the file and looks like
+this:
+
+@example
+^_
+Tag Table:
+File: info, Node: Cross-refs^?21419
+File: info, Node: Tags^?22145
+^_
+End Tag Table
+@end example
+
+@noindent
+Note that it contains one line per node, and this line contains
+the beginning of the node's header (ending just after the node name),
+a @key{DEL} character, and the character position in the file of the
+beginning of the node.
+
+@node Checking, , Tags, Advanced Info
+@comment node-name, next, previous, up
+@section Checking an Info File
+
+ When creating an Info file, it is easy to forget the name of a node
+when you are making a pointer to it from another node. If you put in
+the wrong name for a node, this is not detected until someone
+tries to go through the pointer using Info. Verification of the Info
+file is an automatic process which checks all pointers to nodes and
+reports any pointers which are invalid. Every @samp{Next}, @samp{Previous}, and
+@samp{Up} is checked, as is every menu item and every cross reference. In
+addition, any @samp{Next} which does not have a @samp{Previous} pointing back is
+reported. Only pointers within the file are checked, because checking
+pointers to other files would be terribly slow. But those are usually
+few.
+
+ To check an Info file, do @kbd{M-x Info-validate} while looking at
+any node of the file with Emacs Info mode.
+
+@node Create an Info File, , Advanced Info, Top
+@comment node-name, next, previous, up
+@chapter Creating an Info File from a Makeinfo file
+
+@code{makeinfo} is a utility that converts a Texinfo file into an Info
+file; @code{texinfo-format-region} and @code{texinfo-format-buffer} are
+GNU Emacs functions that do the same.
+
+@xref{Create an Info File, , Creating an Info File, texinfo, the Texinfo
+Manual}, to learn how to create an Info file from a Texinfo file.
+
+@xref{Top,, Overview of Texinfo, texinfo, Texinfo: The GNU Documentation
+Format}, to learn how to write a Texinfo file.
+
+@bye
+
diff --git a/gnu/usr.bin/texinfo/doc/makeinfo.texi b/gnu/usr.bin/texinfo/doc/makeinfo.texi
new file mode 100644
index 0000000..21ee2d3
--- /dev/null
+++ b/gnu/usr.bin/texinfo/doc/makeinfo.texi
@@ -0,0 +1,285 @@
+\input texinfo @c -*-texinfo-*-
+@comment %**start of header
+@setfilename makeinfo.info
+@set VERSION 1.51
+@paragraphindent none
+@comment %**start of header
+
+@ifinfo
+This file is an extract from the @cite{Texinfo} manual.@*
+It documents @code{makeinfo}, a program that converts Texinfo
+files into Info files.
+
+Copyright (C) 1992, 1993 Free Software Foundation, Inc.
+
+Permission is granted to make and distribute verbatim copies of
+this manual provided the copyright notice and this permission notice
+are preserved on all copies.
+
+@ignore
+Permission is granted to process this file through TeX and print the
+results, provided the printed document carries copying permission
+notice identical to this one except for the removal of this paragraph
+(this paragraph not being relevant to the printed manual).
+
+@end ignore
+Permission is granted to copy and distribute modified versions of this
+manual under the conditions for verbatim copying, provided that the entire
+resulting derived work is distributed under the terms of a permission
+notice identical to this one.
+
+Permission is granted to copy and distribute translations of this manual
+into another language, under the above conditions for modified versions,
+except that this permission notice may be stated in a translation approved
+by the Free Software Foundation.
+@end ifinfo
+
+@titlepage
+@title Makeinfo
+@author Brian J. Fox and Robert J. Chassell
+
+@page
+@vskip 0pt plus 1filll
+Copyright @copyright{} 1992, 1993 Free Software Foundation, Inc.
+
+
+Permission is granted to make and distribute verbatim copies of
+this manual provided the copyright notice and this permission notice
+are preserved on all copies.
+
+Permission is granted to copy and distribute modified versions of this
+manual under the conditions for verbatim copying, provided that the entire
+resulting derived work is distributed under the terms of a permission
+notice identical to this one.
+
+Permission is granted to copy and distribute translations of this manual
+into another language, under the above conditions for modified versions,
+except that this permission notice may be stated in a translation approved
+by the Free Software Foundation.
+@end titlepage
+
+@ifinfo
+@node Top, What is makeinfo, (dir), (dir)
+@unnumbered @code{makeinfo}
+
+This file documents the use of the @code{makeinfo} program, versions
+@value{VERSION} and later. It is an extract from the @cite{Texinfo} manual.
+@end ifinfo
+
+@menu
+* What is makeinfo::
+@end menu
+
+@node What is makeinfo, , Top, Top
+@chapter What is @code{makeinfo}?
+
+@iftex
+This file documents the use of the @code{makeinfo} program, versions
+@value{VERSION} and later. It is an extract from the @cite{Texinfo} manual.
+@end iftex
+
+@code{makeinfo} is a program for converting @dfn{Texinfo} files into @dfn{Info}
+files. Texinfo is a documentation system that uses a single source file to
+produce both on-line information and printed output.
+
+You can read the on-line information using Info; type @code{info} to
+learn about Info.
+@ifinfo
+@xref{Top, Texinfo, Overview of Texinfo, texinfo.texi, Texinfo},
+@end ifinfo
+@iftex
+See the @cite{Texinfo} manual,
+@end iftex
+to learn about the Texinfo documentation system.
+
+@menu
+* Formatting Control::
+* Options::
+* Pointer Validation::
+@end menu
+
+@node Formatting Control, Options, , What is makeinfo
+@section Controlling Paragraph Formats
+
+In general, @code{makeinfo} @dfn{fills} the paragraphs that it outputs
+to an Info file. Filling is the process of breaking and connecting
+lines so that lines are the same length as or shorter than the number
+specified as the fill column. Lines are broken between words. With
+@code{makeinfo}, you can control:
+
+@itemize @bullet
+@item
+The width of each paragraph (the @dfn{fill-column}).
+@item
+The amount of indentation that the first line of
+each paragraph receives (the @dfn{paragraph-indentation}).
+@end itemize
+
+@node Options, Pointer Validation, Formatting Control, What is makeinfo
+@section Command Line Options
+
+The following command line options are available for @code{makeinfo}.
+
+@need 100
+@table @code
+@item -D @var{var}
+Cause @var{var} to be defined. This is equivalent to
+@code{@@set @var{var}} in the Texinfo file.
+
+@need 150
+@item --error-limit @var{limit}
+Set the maximum number of errors that @code{makeinfo} will report
+before exiting (on the assumption that continuing would be useless).
+The default number of errors that can be reported before
+@code{makeinfo} gives up is 100.@refill
+
+@need 150
+@item --fill-column @var{width}
+Specify the maximum number of columns in a line; this is the right-hand
+edge of a line. Paragraphs that are filled will be filled to this
+width. The default value for @code{fill-column} is 72.
+@refill
+
+@item --footnote-style @var{style}
+Set the footnote style to @var{style}, either @samp{end} for the end
+node style or @samp{separate} for the separate node style. The value
+set by this option overrides the value set in a Texinfo file by an
+@code{@@footnotestyle} command. When the footnote style is
+@samp{separate}, @code{makeinfo} makes a new node containing the
+footnotes found in the current node. When the footnote style is
+@samp{end}, @code{makeinfo} places the footnote references at the end
+of the current node.@refill
+
+@need 150
+@item -I @var{dir}
+Add @code{dir} to the directory search list for finding files that are
+included using the @code{@@include} command. By default,
+@code{makeinfo} searches only the current directory.
+
+@need 150
+@item --no-headers
+Do not include menus or node lines in the output. This results in an
+@sc{ascii} file that you cannot read in Info since it does not contain
+the requisite nodes or menus; but you can print such a file in a
+single, typewriter-like font and produce acceptable output.
+
+@need 150
+@item --no-split
+Suppress the splitting stage of @code{makeinfo}. Normally, large
+output files (where the size is greater than 70k bytes) are split into
+smaller subfiles, each one approximately 50k bytes. If you specify
+@samp{--no-split}, @code{makeinfo} will not split up the output
+file.@refill
+
+@need 100
+@item --no-pointer-validate
+@item --no-validate
+Suppress the pointer-validation phase of @code{makeinfo}. Normally,
+after a Texinfo file is processed, some consistency checks are made to
+ensure that cross references can be resolved, etc.
+@xref{Pointer Validation}.@refill
+
+@need 150
+@item --no-warn
+Suppress the output of warning messages. This does @emph{not}
+suppress the output of error messages, only warnings. You might
+want this if the file you are creating has examples of Texinfo cross
+references within it, and the nodes that are referenced do not actually
+exist.@refill
+
+@item --no-number-footnotes
+Supress automatic footnote numbering. By default, @code{makeinfo}
+numbers each footnote sequentially in a single node, resetting the
+current footnote number to 1 at the start of each node.
+
+@need 150
+@item --output @var{file}
+@itemx -o @var{file}
+Specify that the output should be directed to @var{file} and not to the
+file name specified in the @code{@@setfilename} command found in the Texinfo
+source. @var{file} can be the special token @samp{-}, which specifies
+standard output.
+
+@need 150
+@item --paragraph-indent @var{indent}
+Set the paragraph indentation style to @var{indent}. The value set by
+this option overrides the value set in a Texinfo file by an
+@code{@@paragraphindent} command. The value of @var{indent} is
+interpreted as follows:@refill
+
+@itemize @bullet
+@item
+If the value of @var{indent} is @samp{asis}, do not change the
+existing indentation at the starts of paragraphs.@refill
+
+@item
+If the value of @var{indent} is zero, delete any existing
+indentation.@refill
+
+@item
+If the value of @var{indent} is greater than zero, indent each
+paragraph by that number of spaces.@refill
+@end itemize
+
+@need 100
+@item --reference-limit @var{limit}
+Set the value of the number of references to a node that
+@code{makeinfo} will make without reporting a warning. If a node has more
+than this number of references in it, @code{makeinfo} will make the
+references but also report a warning.@refill
+
+@need 150
+@item -U @var{var}
+Cause @var{var} to be undefined. This is equivalent to
+@code{@@clear @var{var}} in the Texinfo file.
+
+@need 100
+@item --verbose
+Cause @code{makeinfo} to display messages saying what it is doing.
+Normally, @code{makeinfo} only outputs messages if there are errors or
+warnings.@refill
+
+@need 100
+@item --version
+Report the version number of this copy of @code{makeinfo}.@refill
+@end table
+
+@node Pointer Validation, , Options, What is makeinfo
+@section Pointer Validation
+@cindex Pointer validation with @code{makeinfo}
+@cindex Validation of pointers
+
+If you do not suppress pointer-validation (by using the
+@samp{--no-pointer-validation} option), @code{makeinfo}
+will check the validity of the final Info file. Mostly,
+this means ensuring that nodes you have referenced
+really exist. Here is a complete list of what is
+checked:@refill
+
+@enumerate
+@item
+If a `Next', `Previous', or `Up' node reference is a reference to a
+node in the current file and is not an external reference such as to
+@file{(dir)}, then the referenced node must exist.@refill
+
+@item
+In every node, if the `Previous' node is different from the `Up' node,
+then the `Previous' node must also be pointed to by a `Next' node.@refill
+
+@item
+Every node except the `Top' node must have an `Up' pointer.@refill
+
+@item
+The node referenced by an `Up' pointer must contain a reference to the
+current node in some manner other than through a `Next' reference.
+This includes menu entries and cross references.@refill
+
+@item
+If the `Next' reference of a node is not the same as the `Next' reference
+of the `Up' reference, then the node referenced by the `Next' pointer
+must have a `Previous' pointer that points back to the current node.
+This rule allows the last node in a section to point to the first node
+of the next chapter.@refill
+@end enumerate
+
+@bye
diff --git a/gnu/usr.bin/texinfo/doc/texi.texi b/gnu/usr.bin/texinfo/doc/texi.texi
new file mode 100644
index 0000000..f77f662
--- /dev/null
+++ b/gnu/usr.bin/texinfo/doc/texi.texi
@@ -0,0 +1,15626 @@
+\input texinfo @c -*-texinfo-*-
+@comment %**start of header
+@setfilename texi.info
+@settitle Texinfo @value{edition}
+@syncodeindex vr fn
+@c footnotestyle separate
+@c paragraphindent 2
+@smallbook
+@comment %**end of header
+
+@ignore
+@ifinfo
+@format
+START-INFO-DIR-ENTRY
+* Texinfo: (texi.info). The documentation format for the GNU Project.
+END-INFO-DIR-ENTRY
+@end format
+@end ifinfo
+@end ignore
+
+@c Set smallbook if printing in smallbook format so the example of the
+@c smallbook font is actually written using smallbook; in bigbook, a kludge
+@c is used for TeX output.
+@c set smallbook
+@clear smallbook
+
+@set edition 2.18
+@set update-date 26 March 1993
+@set update-month March 1993
+
+@c Experiment with smaller amounts of whitespace between chapters
+@c and sections.
+@tex
+\global\chapheadingskip = 15pt plus 4pt minus 2pt
+\global\secheadingskip = 12pt plus 3pt minus 2pt
+\global\subsecheadingskip = 9pt plus 2pt minus 2pt
+@end tex
+
+@c Experiment with smaller amounts of whitespace between paragraphs in
+@c the 8.5 by 11 inch format.
+@ifclear smallbook
+@tex
+\global\parskip 6pt plus 1pt
+@end tex
+@end ifclear
+
+@finalout
+
+@c Currently undocumented commands, 24 March 1993:
+@c See documentation in `texinfmt.el' file.
+@c
+@c raisesections (Two useful commands.)
+@c lowersections
+@c nwnode (Same as node, but no warnings; for `makeinfo'.)
+@c math (Unsatisfactory TeX definition; no processing for Info.)
+@c definfoenclose (For ifinfo text only; not supported by `makeinfo';
+@c each instance requires a corresponding TeX definition.)
+
+@ifinfo
+This file documents Texinfo, a documentation system that uses a single
+source file to produce both on-line information and a printed manual.
+
+Copyright (C) 1988, 1990, 1991, 1992, 1993 Free Software Foundation, Inc.
+
+This is the second edition of the Texinfo documentation,@*
+and is consistent with version 2 of @file{texinfo.tex}.
+
+Permission is granted to make and distribute verbatim copies of
+this manual provided the copyright notice and this permission notice
+are preserved on all copies.
+
+@ignore
+Permission is granted to process this file through TeX and print the
+results, provided the printed document carries copying permission
+notice identical to this one except for the removal of this paragraph
+(this paragraph not being relevant to the printed manual).
+
+@end ignore
+Permission is granted to copy and distribute modified versions of this
+manual under the conditions for verbatim copying, provided that the entire
+resulting derived work is distributed under the terms of a permission
+notice identical to this one.
+
+Permission is granted to copy and distribute translations of this manual
+into another language, under the above conditions for modified versions,
+except that this permission notice may be stated in a translation approved
+by the Free Software Foundation.
+@end ifinfo
+
+@setchapternewpage odd
+@titlepage
+@c use the new format for titles
+@title Texinfo
+@subtitle The GNU Documentation Format
+@subtitle Edition @value{edition}, for Texinfo Version Two
+@subtitle @value{update-month}
+
+@author by Robert J. Chassell and Richard M. Stallman
+
+@comment Include the Distribution inside the titlepage so
+@c that headings are turned off.
+
+@page
+@vskip 0pt plus 1filll
+Copyright @copyright{} 1988, 1990, 1991, 1992, 1993 Free Software Foundation, Inc.
+
+@sp 2
+This is the second edition of the Texinfo documentation,@*
+and is consistent with version 2 of @file{texinfo.tex}.
+@sp 2
+
+Published by the Free Software Foundation @*
+675 Massachusetts Avenue, @*
+Cambridge, MA 02139 USA @*
+Printed copies are available for $15 each.@*
+ISBN-1882114-12-4
+
+Permission is granted to make and distribute verbatim copies of
+this manual provided the copyright notice and this permission notice
+are preserved on all copies.
+
+Permission is granted to copy and distribute modified versions of this
+manual under the conditions for verbatim copying, provided that the entire
+resulting derived work is distributed under the terms of a permission
+notice identical to this one.
+
+Permission is granted to copy and distribute translations of this manual
+into another language, under the above conditions for modified versions,
+except that this permission notice may be stated in a translation approved
+by the Free Software Foundation.
+@sp 2
+Cover art by Etienne Suvasa.
+@end titlepage
+
+@ifinfo
+@node Top, Copying, (dir), (dir)
+@top Texinfo
+
+Texinfo is a documentation system that uses a single source file to
+produce both on-line information and printed output.@refill
+
+The first part of this master menu lists the major nodes in this Info
+document, including the @@-command and concept indices. The rest of
+the menu lists all the lower level nodes in the document.@refill
+
+This is Edition @value{edition} of the Texinfo documentation,
+@w{@value{update-date},} for Texinfo Version 2.
+@end ifinfo
+
+@c Here is a spare copy of the chapter menu entry descriptions,
+@c in case they are accidently deleted
+@ignore
+Your rights.
+Texinfo in brief.
+How to use Texinfo mode.
+What is at the beginning of a Texinfo file?
+What is at the end of a Texinfo file?
+How to create chapters, sections, subsections,
+ appendices, and other parts.
+How to provide structure for a document.
+How to write nodes.
+How to write menus.
+How to write cross references.
+How to mark words and phrases as code,
+ keyboard input, meta-syntactic
+ variables, and the like.
+How to write quotations, examples, etc.
+How to write lists and tables.
+How to create indices.
+How to insert @@-signs, braces, etc.
+How to indicate results of evaluation,
+ expansion of macros, errors, etc.
+How to force and prevent line and page breaks.
+How to describe functions and the like in a uniform manner.
+How to write footnotes.
+How to specify text for either @TeX{} or Info.
+How to print hardcopy.
+How to create an Info file.
+How to install an Info file
+A list of all the Texinfo @@-commands.
+Hints on how to write a Texinfo document.
+A sample Texinfo file to look at.
+Tell readers they have the right to copy
+ and distribute.
+How to incorporate other Texinfo files.
+How to write page headings and footings.
+How to find formatting mistakes.
+All about paragraph refilling.
+A description of @@-Command syntax.
+Texinfo second edition features.
+A menu containing commands and variables.
+A menu covering many topics.
+@end ignore
+
+@menu
+* Copying:: Your rights.
+* Overview:: Texinfo in brief.
+* Texinfo Mode:: How to use Texinfo mode.
+* Beginning a File:: What is at the beginning of a Texinfo file?
+* Ending a File:: What is at the end of a Texinfo file?
+* Structuring:: How to create chapters, sections, subsections,
+ appendices, and other parts.
+* Nodes:: How to write nodes.
+* Menus:: How to write menus.
+* Cross References:: How to write cross references.
+* Marking Text:: How to mark words and phrases as code,
+ keyboard input, meta-syntactic
+ variables, and the like.
+* Quotations and Examples:: How to write quotations, examples, etc.
+* Lists and Tables:: How to write lists and tables.
+* Indices:: How to create indices.
+* Insertions:: How to insert @@-signs, braces, etc.
+* Glyphs:: How to indicate results of evaluation,
+ expansion of macros, errors, etc.
+* Breaks:: How to force and prevent line and page breaks.
+* Definition Commands:: How to describe functions and the like
+ in a uniform manner.
+* Footnotes:: How to write footnotes.
+* Conditionals:: How to specify text for either @TeX{} or Info.
+* Format/Print Hardcopy:: How to convert a Texinfo file to a file
+ for printing and how to print that file.
+* Create an Info File:: Convert a Texinfo file into an Info file.
+* Install an Info File:: Make an Info file accessible to users.
+* Command List:: All the Texinfo @@-commands.
+* Tips:: Hints on how to write a Texinfo document.
+* Sample Texinfo File:: A sample Texinfo file to look at.
+* Sample Permissions:: Tell readers they have the right to copy
+ and distribute.
+* Include Files:: How to incorporate other Texinfo files.
+* Headings:: How to write page headings and footings.
+* Catching Mistakes:: How to find formatting mistakes.
+* Refilling Paragraphs:: All about paragraph refilling.
+* Command Syntax:: A description of @@-Command syntax.
+* Obtaining TeX:: How to Obtain @TeX{}.
+* New Features:: Texinfo second edition features.
+* Command and Variable Index:: A menu containing commands and variables.
+* Concept Index:: A menu covering many topics.
+
+ --- The Detailed Node Listing ---
+
+Overview of Texinfo
+
+* Using Texinfo:: Create a conventional printed book
+ or an Info file.
+* Info Files:: What is an Info file?
+* Printed Books:: Characteristics of a printed book or manual.
+* Formatting Commands:: @@-commands are used for formatting.
+* Conventions:: General rules for writing a Texinfo file.
+* Comments:: How to write comments and mark regions that
+ the formatting commands will ignore.
+* Minimum:: What a Texinfo file must have.
+* Six Parts:: Usually, a Texinfo file has six parts.
+* Short Sample:: A short sample Texinfo file.
+* Acknowledgements::
+
+Using Texinfo Mode
+
+* Texinfo Mode Overview:: How Texinfo mode can help you.
+* Emacs Editing:: Texinfo mode adds to GNU Emacs' general
+ purpose editing features.
+* Inserting:: How to insert frequently used @@-commands.
+* Showing the Structure:: How to show the structure of a file.
+* Updating Nodes and Menus:: How to update or create new nodes and menus.
+* Info Formatting:: How to format for Info.
+* Printing:: How to format and print part or all of a file.
+* Texinfo Mode Summary:: Summary of all the Texinfo mode commands.
+
+Updating Nodes and Menus
+
+* Updating Commands:: Five major updating commands.
+* Updating Requirements:: How to structure a Texinfo file for
+ using the updating command.
+* Other Updating Commands:: How to indent descriptions, insert
+ missing nodes lines, and update
+ nodes in sequence.
+
+Beginning a Texinfo File
+
+* Four Parts:: Four parts begin a Texinfo file.
+* Sample Beginning:: Here is a sample beginning for a Texinfo file.
+* Header:: The very beginning of a Texinfo file.
+* Info Summary and Permissions:: Summary and copying permissions for Info.
+* Titlepage & Copyright Page:: Creating the title and copyright pages.
+* The Top Node:: Creating the `Top' node and master menu.
+* Software Copying Permissions:: Ensure that you and others continue to
+ have the right to use and share software.
+
+The Texinfo File Header
+
+* First Line:: The first line of a Texinfo file.
+* Start of Header:: Formatting a region requires this.
+* setfilename:: Tell Info the name of the Info file.
+* settitle:: Create a title for the printed work.
+* setchapternewpage:: Start chapters on right-hand pages.
+* paragraphindent:: An option to specify paragraph indentation.
+* End of Header:: Formatting a region requires this.
+
+The Title and Copyright Pages
+
+* titlepage:: Create a title for the printed document.
+* titlefont center sp:: The @code{@@titlefont}, @code{@@center},
+ and @code{@@sp} commands.
+* title subtitle author:: The @code{@@title}, @code{@@subtitle},
+ and @code{@@author} commands.
+* Copyright & Permissions:: How to write the copyright notice and
+ include copying permissions.
+* end titlepage:: Turn on page headings after the title and
+ copyright pages.
+* headings on off:: An option for turning headings on and off
+ and double or single sided printing.
+
+The `Top' Node and Master Menu
+
+* Title of Top Node:: Sketch what the file is about.
+* Master Menu Parts:: A master menu has three or more parts.
+
+Ending a Texinfo File
+
+* Printing Indices & Menus:: How to print an index in hardcopy and
+ generate index menus in Info.
+* Contents:: How to create a table of contents.
+* File End:: How to mark the end of a file.
+
+Chapter Structuring
+
+* Tree Structuring:: A manual is like an upside down tree @dots{}
+* Structuring Command Types:: How to divide a manual into parts.
+* makeinfo top:: The @code{@@top} command, part of the `Top' node.
+* chapter::
+* unnumbered & appendix::
+* majorheading & chapheading::
+* section::
+* unnumberedsec appendixsec heading::
+* subsection::
+* unnumberedsubsec appendixsubsec subheading::
+* subsubsection:: Commands for the lowest level sections.
+
+Nodes
+
+* Two Paths:: Different commands to structure
+ Info output and printed output.
+* Node Menu Illustration:: A diagram, and sample nodes and menus.
+* node:: How to write a node, in detail.
+* makeinfo Pointer Creation:: How to create node pointers with @code{makeinfo}.
+
+The @code{@@node} Command
+
+* Node Names:: How to choose node and pointer names.
+* Writing a Node:: How to write an @code{@@node} line.
+* Node Line Tips:: Keep names short.
+* Node Line Requirements:: Keep names unique, without @@-commands.
+* First Node:: How to write a `Top' node.
+* makeinfo top command:: How to use the @code{@@top} command.
+* Top Node Summary:: Write a brief description for readers.
+
+Menus
+
+* Menu Location:: Put a menu in a short node.
+* Writing a Menu:: What is a menu?
+* Menu Parts:: A menu entry has three parts.
+* Less Cluttered Menu Entry:: Two part menu entry.
+* Menu Example:: Two and three part menu entries.
+* Other Info Files:: How to refer to a different Info file.
+
+Cross References
+
+* References:: What cross references are for.
+* Cross Reference Commands:: A summary of the different commands.
+* Cross Reference Parts:: A cross reference has several parts.
+* xref:: Begin a reference with `See' @dots{}
+* Top Node Naming:: How to refer to the beginning of another file.
+* ref:: A reference for the last part of a sentence.
+* pxref:: How to write a parenthetical cross reference.
+* inforef:: How to refer to an Info-only file.
+
+@code{@@xref}
+
+* Reference Syntax:: What a reference looks like and requires.
+* One Argument:: @code{@@xref} with one argument.
+* Two Arguments:: @code{@@xref} with two arguments.
+* Three Arguments:: @code{@@xref} with three arguments.
+* Four and Five Arguments:: @code{@@xref} with four and five arguments.
+
+Marking Words and Phrases
+
+* Indicating:: How to indicate definitions, files, etc.
+* Emphasis:: How to emphasize text.
+
+Indicating Definitions, Commands, etc.
+
+* Useful Highlighting:: Highlighting provides useful information.
+* code:: How to indicate code.
+* kbd:: How to show keyboard input.
+* key:: How to specify keys.
+* samp:: How to show a literal sequence of characters.
+* var:: How to indicate a metasyntactic variable.
+* file:: How to indicate the name of a file.
+* dfn:: How to specify a definition.
+* cite:: How to refer to a book that is not in Info.
+
+Emphasizing Text
+
+* emph & strong:: How to emphasize text in Texinfo.
+* Smallcaps:: How to use the small caps font.
+* Fonts:: Various font commands for printed output.
+
+Quotations and Examples
+
+* Block Enclosing Commands:: Use different constructs for
+ different purposes.
+* quotation:: How to write a quotation.
+* example:: How to write an example in a fixed-width font.
+* noindent:: How to prevent paragraph indentation.
+* Lisp Example:: How to illustrate Lisp code.
+* smallexample & smalllisp:: Forms for the @code{@@smallbook} option.
+* display:: How to write an example in the current font.
+* format:: How to write an example that does not narrow
+ the margins.
+* exdent:: How to undo the indentation of a line.
+* flushleft & flushright:: How to push text flushleft or flushright.
+* cartouche:: How to draw cartouches around examples.
+
+Making Lists and Tables
+
+* Introducing Lists:: Texinfo formats lists for you.
+* itemize:: How to construct a simple list.
+* enumerate:: How to construct a numbered list.
+* Two-column Tables:: How to construct a two-column table.
+
+Making a Two-column Table
+
+* table:: How to construct a two-column table.
+* ftable vtable:: How to construct a two-column table
+ with automatic indexing.
+* itemx:: How to put more entries in the first column.
+
+Creating Indices
+
+* Index Entries:: Choose different words for index entries.
+* Predefined Indices:: Use different indices for different kinds
+ of entry.
+* Indexing Commands:: How to make an index entry.
+* Combining Indices:: How to combine indices.
+* New Indices:: How to define your own indices.
+
+Combining Indices
+
+* syncodeindex:: How to merge two indices, using @code{@@code}
+ font for the merged-from index.
+* synindex:: How to merge two indices, using the
+ default font of the merged-to index.
+
+Special Insertions
+
+* Braces Atsigns Periods:: How to insert braces, @samp{@@} and periods.
+* dmn:: How to format a dimension.
+* Dots Bullets:: How to insert dots and bullets.
+* TeX and copyright:: How to insert the @TeX{} logo
+ and the copyright symbol.
+* minus:: How to insert a minus sign.
+
+Inserting @samp{@@}, Braces, and Periods
+
+* Inserting An Atsign::
+* Inserting Braces:: How to insert @samp{@{} and @samp{@}}
+* Controlling Spacing:: How to insert the right amount of space
+ after punctuation within a sentence.
+
+Inserting Ellipsis, Dots, and Bullets
+
+* dots:: How to insert dots @dots{}
+* bullet:: How to insert a bullet.
+
+Inserting @TeX{} and the Copyright Symbol
+
+* tex:: How to insert the @TeX{} logo.
+* copyright symbol:: How to use @code{@@copyright}@{@}.
+
+Glyphs for Examples
+
+* Glyphs Summary::
+* result:: How to show the result of expression.
+* expansion:: How to indicate an expansion.
+* Print Glyph:: How to indicate printed output.
+* Error Glyph:: How to indicate an error message.
+* Equivalence:: How to indicate equivalence.
+* Point Glyph:: How to indicate the location of point.
+
+Making and Preventing Breaks
+
+* Break Commands:: Cause and prevent splits.
+* Line Breaks:: How to force a single line to use two lines.
+* w:: How to prevent unwanted line breaks.
+* sp:: How to insert blank lines.
+* page:: How to force the start of a new page.
+* group:: How to prevent unwanted page breaks.
+* need:: Another way to prevent unwanted page breaks.
+
+Definition Commands
+
+* Def Cmd Template:: How to structure a description using a
+ definition command.
+* Optional Arguments:: How to handle optional and repeated arguments.
+* deffnx:: How to group two or more `first' lines.
+* Def Cmds in Detail:: All the definition commands.
+* Def Cmd Conventions:: Conventions for writing definitions.
+* Sample Function Definition::
+
+The Definition Commands
+
+* Functions Commands:: Commands for functions and similar entities.
+* Variables Commands:: Commands for variables and similar entities.
+* Typed Functions:: Commands for functions in typed languages.
+* Typed Variables:: Commands for variables in typed languages.
+* Abstract Objects:: Commands for object-oriented programming.
+* Data Types:: The definition command for data types.
+
+Conditionally Visible Text
+
+* Conditional Commands:: How to specify text for Info or @TeX{}.
+* Using Ordinary TeX Commands:: You can use any and all @TeX{} commands.
+* set clear value:: How to designate which text to format (for
+ both Info and @TeX{}); and how to set a
+ flag to a string that you can insert.
+
+@code{@@set}, @code{@@clear}, and @code{@@value}
+
+* ifset ifclear:: Format a region if a flag is set.
+* value:: Replace a flag with a string.
+* value Example:: An easy way to update edition information.
+
+Format and Print Hardcopy
+
+* Use TeX:: Use @TeX{} to format for hardcopy.
+* Shell Format & Print:: How to format and print a hardcopy manual
+ with shell commands.
+* Within Emacs:: How to format and print from an Emacs shell.
+* Texinfo Mode Printing:: How to format and print in Texinfo mode.
+* Compile-Command:: How to print using Emacs's compile command.
+* Requirements Summary:: @TeX{} formatting requirements summary.
+* Preparing for TeX:: What you need to do to use @TeX{}.
+* Overfull hboxes:: What are and what to do with overfull hboxes.
+* smallbook:: How to print small format books and manuals.
+* A4 Paper:: How to print on European A4 paper.
+* Cropmarks and Magnification:: How to print marks to indicate the size
+ of pages and how to print scaled up output.
+
+Creating an Info File
+
+* makeinfo advantages:: @code{makeinfo} provides better error checking.
+* Invoking makeinfo:: How to run @code{makeinfo} from a shell.
+* makeinfo options:: Specify fill-column and other options.
+* Pointer Validation:: How to check that pointers point somewhere.
+* makeinfo in Emacs:: How to run @code{makeinfo} from Emacs.
+* texinfo-format commands:: Two Info formatting commands written
+ in Emacs Lisp are an alternative
+ to @code{makeinfo}.
+* Batch Formatting:: How to format for Info in Emacs Batch mode.
+* Tag and Split Files:: How tagged and split files help Info
+ to run better.
+
+Installing an Info File
+
+* Directory file:: The top level menu for all Info files.
+* New Info File:: Listing a new info file.
+* Other Info Directories:: How to specify Info files that are
+ located in other directories.
+
+Sample Permissions
+
+* Inserting Permissions:: How to put permissions in your document.
+* ifinfo Permissions:: Sample @samp{ifinfo} copying permissions.
+* Titlepage Permissions:: Sample Titlepage copying permissions.
+
+Include Files
+
+* Using Include Files:: How to use the @code{@@include} command.
+* texinfo-multiple-files-update:: How to create and update nodes and
+ menus when using included files.
+* Include File Requirements:: What @code{texinfo-multiple-files-update} expects.
+* Sample Include File:: A sample outer file with included files
+ within it; and a sample included file.
+* Include Files Evolution:: How use of the @code{@@include} command
+ has changed over time.
+
+Page Headings
+
+* Headings Introduced:: Conventions for using page headings.
+* Heading Format:: Standard page heading formats.
+* Heading Choice:: How to specify the type of page heading.
+* Custom Headings:: How to create your own headings and footings.
+
+Formatting Mistakes
+
+* makeinfo preferred:: @code{makeinfo} finds errors.
+* Debugging with Info:: How to catch errors with Info formatting.
+* Debugging with TeX:: How to catch errors with @TeX{} formatting.
+* Using texinfo-show-structure:: How to use @code{texinfo-show-structure}.
+* Using occur:: How to list all lines containing a pattern.
+* Running Info-Validate:: How to find badly referenced nodes.
+
+Finding Badly Referenced Nodes
+
+* Using Info-validate:: How to run @code{Info-validate}.
+* Unsplit:: How to create an unsplit file.
+* Tagifying:: How to tagify a file.
+* Splitting:: How to split a file manually.
+
+Second Edition Features
+
+* New Texinfo Mode Commands:: The updating commands are especially useful.
+* New Commands:: Many newly described @@-commands.
+@end menu
+
+@node Copying, Overview, Top, Top
+@comment node-name, next, previous, up
+@unnumbered Texinfo Copying Conditions
+@cindex Copying conditions
+@cindex Conditions for copying Texinfo
+
+The programs currently being distributed that relate to Texinfo include
+portions of GNU Emacs, plus other separate programs (including
+@code{makeinfo}, @code{info}, @code{texindex}, and @file{texinfo.tex}).
+These programs are @dfn{free}; this means that everyone is free to use
+them and free to redistribute them on a free basis. The Texinfo-related
+programs are not in the public domain; they are copyrighted and there
+are restrictions on their distribution, but these restrictions are
+designed to permit everything that a good cooperating citizen would want
+to do. What is not allowed is to try to prevent others from further
+sharing any version of these programs that they might get from
+you.@refill
+
+ Specifically, we want to make sure that you have the right to give
+away copies of the programs that relate to Texinfo, that you receive
+source code or else can get it if you want it, that you can change these
+programs or use pieces of them in new free programs, and that you know
+you can do these things.@refill
+
+ To make sure that everyone has such rights, we have to forbid you to
+deprive anyone else of these rights. For example, if you distribute
+copies of the Texinfo related programs, you must give the recipients all
+the rights that you have. You must make sure that they, too, receive or
+can get the source code. And you must tell them their rights.@refill
+
+ Also, for our own protection, we must make certain that everyone finds
+out that there is no warranty for the programs that relate to Texinfo.
+If these programs are modified by someone else and passed on, we want
+their recipients to know that what they have is not what we distributed,
+so that any problems introduced by others will not reflect on our
+reputation.@refill
+
+ The precise conditions of the licenses for the programs currently
+being distributed that relate to Texinfo are found in the General Public
+Licenses that accompany them.@refill
+
+@node Overview, Texinfo Mode, Copying, Top
+@comment node-name, next, previous, up
+@chapter Overview of Texinfo
+@cindex Overview of Texinfo
+@cindex Texinfo overview
+
+@dfn{Texinfo}@footnote{Note that the first syllable of ``Texinfo'' is
+pronounced like ``speck'', not ``hex''. This odd pronunciation is
+derived from, but is not the same as, the pronunciation of @TeX{}. In
+the word @TeX{}, the @samp{X} is actually the Greek letter ``chi''
+rather than the English letter ``ex''. Pronounce @TeX{} as if the
+@samp{X} were the last sound in the name `Bach'; but pronounce Texinfo
+as if the @samp{x} were a `k'. Spell ``Texinfo'' with a capital ``T''
+and write the other letters in lower case.}
+is a documentation system that uses a single source file to produce both
+on-line information and printed output. This means that instead of
+writing two different documents, one for the on-line help or other on-line
+information and the other for a typeset manual or other printed work, you
+need write only one document. When the work is revised, you need revise
+only one document. (You can read the on-line information, known as an
+@dfn{Info file}, with an Info documentation-reading program.)@refill
+
+@menu
+* Using Texinfo:: Create a conventional printed book
+ or an Info file.
+* Info Files:: What is an Info file?
+* Printed Books:: Characteristics of a printed book or manual.
+* Formatting Commands:: @@-commands are used for formatting.
+* Conventions:: General rules for writing a Texinfo file.
+* Comments:: How to write comments and mark regions that
+ the formatting commands will ignore.
+* Minimum:: What a Texinfo file must have.
+* Six Parts:: Usually, a Texinfo file has six parts.
+* Short Sample:: A short sample Texinfo file.
+* Acknowledgements::
+@end menu
+
+@node Using Texinfo, Info Files, , Overview
+@ifinfo
+@heading Using Texinfo
+@end ifinfo
+
+Using Texinfo, you can create a printed document with the normal
+features of a book, including chapters, sections, cross references,
+and indices. From the same Texinfo source file, you can create a
+menu-driven, on-line Info file with nodes, menus, cross references,
+and indices. You can, if you wish, make the chapters and sections of
+the printed document correspond to the nodes of the on-line
+information; and you use the same cross references and indices for
+both the Info file and the printed work. @cite{The GNU
+Emacs Manual} is a good example of a Texinfo file, as is this manual.@refill
+
+To make a printed document, you process a Texinfo source file with the
+@TeX{} typesetting program. This creates a @sc{dvi} file that you can
+typeset and print as a book or report. (Note that the Texinfo language is
+completely different from @TeX{}'s usual language, Plain@TeX{}, which
+Texinfo replaces.) If you do not have @TeX{}, but do have
+@code{troff} or @code{nroff}, you can use the @code{texi2roff} program
+instead.@refill
+
+To make an Info file, you process a Texinfo source file with the
+@code{makeinfo} utility or Emacs's @code{texinfo-format-buffer} command;
+this creates an Info file that you can install on-line.@refill
+
+@TeX{} and @code{texi2roff} work with many types of printer; similarly,
+Info works with almost every type of computer terminal. This power
+makes Texinfo a general purpose system, but brings with it a constraint,
+which is that a Texinfo file may contain only the customary
+``typewriter'' characters (letters, numbers, spaces, and punctuation
+marks) but no special graphics.@refill
+
+A Texinfo file is a plain @sc{ascii} file containing text and
+@dfn{@@-commands} (words preceded by an @samp{@@}) that tell the
+typesetting and formatting programs what to do. You may edit a
+Texinfo file with any text editor; but it is especially convenient to
+use GNU Emacs since that editor has a special mode, called Texinfo
+mode, that provides various Texinfo-related features. (@xref{Texinfo
+Mode}.)@refill
+
+Before writing a Texinfo source file, you should become familiar with
+the Info documentation reading program and learn about nodes,
+menus, cross references, and the rest. (@inforef{Top, info, info},
+for more information.)@refill
+
+You can use Texinfo to create both on-line help and printed manuals;
+moreover, Texinfo is freely redistributable. For these reasons, Texinfo
+is the format in which documentation for GNU utilities and libraries is
+written.@refill
+
+@node Info Files, Printed Books, Using Texinfo, Overview
+@comment node-name, next, previous, up
+@section Info files
+@cindex Info files
+
+An Info file is a Texinfo file formatted so that the Info documentation
+reading program can operate on it. (@code{makeinfo}
+and @code{texinfo-format-buffer} are two commands that convert a Texinfo file
+into an Info file.)@refill
+
+Info files are divided into pieces called @dfn{nodes}, each of which
+contains the discussion of one topic. Each node has a name, and
+contains both text for the user to read and pointers to other nodes,
+which are identified by their names. The Info program displays one node
+at a time, and provides commands with which the user can move to other
+related nodes.@refill
+
+@ifinfo
+@inforef{Top, info, info}, for more information about using Info.@refill
+@end ifinfo
+
+Each node of an Info file may have any number of child nodes that
+describe subtopics of the node's topic. The names of child
+nodes are listed in a @dfn{menu} within the parent node; this
+allows you to use certain Info commands to move to one of the child
+nodes. Generally, an Info file is organized like a book. If a node
+is at the logical level of a chapter, its child nodes are at the level
+of sections; likewise, the child nodes of sections are at the level
+of subsections.@refill
+
+All the children of any one parent are linked together in a
+bidirectional chain of `Next' and `Previous' pointers. The `Next'
+pointer provides a link to the next section, and the `Previous' pointer
+provides a link to the previous section. This means that all the nodes
+that are at the level of sections within a chapter are linked together.
+Normally the order in this chain is the same as the order of the
+children in the parent's menu. Each child node records the parent node
+name as its `Up' pointer. The last child has no `Next' pointer, and the
+first child has the parent both as its `Previous' and as its `Up'
+pointer.@footnote{In some documents, the first child has no `Previous'
+pointer. Occasionally, the last child has the node name of the next
+following higher level node as its `Next' pointer.}@refill
+
+The book-like structuring of an Info file into nodes that correspond
+to chapters, sections, and the like is a matter of convention, not a
+requirement. The `Up', `Previous', and `Next' pointers of a node can
+point to any other nodes, and a menu can contain any other nodes.
+Thus, the node structure can be any directed graph. But it is usually
+more comprehensible to follow a structure that corresponds to the
+structure of chapters and sections in a printed book or report.@refill
+
+In addition to menus and to `Next', `Previous', and `Up' pointers, Info
+provides pointers of another kind, called references, that can be
+sprinkled throughout the text. This is usually the best way to
+represent links that do not fit a hierarchical structure.@refill
+
+Usually, you will design a document so that its nodes match the
+structure of chapters and sections in the printed output. But there
+are times when this is not right for the material being discussed.
+Therefore, Texinfo uses separate commands to specify the node
+structure for the Info file and the section structure for the printed
+output.@refill
+
+Generally, you enter an Info file through a node that by convention is
+called @samp{Top}. This node normally contains just a brief summary
+of the file's purpose, and a large menu through which the rest of the
+file is reached. From this node, you can either traverse the file
+systematically by going from node to node, or you can go to a specific
+node listed in the main menu, or you can search the index menus and
+then go directly to the node that has the information you want.@refill
+@c !!! With the standalone Info system you may go to specific nodes
+@c directly..
+
+If you want to read through an Info file in sequence, as if it were a
+printed manual, you can get the whole file with the advanced Info
+command @kbd{g* @key{RET}}. (@inforef{Expert, Advanced Info commands,
+info}.)@refill
+
+@c !!! dir file may be located in one of many places:
+@c /usr/local/emacs/info mentioned in info.c DEFAULT_INFOPATH
+@c /usr/local/lib/emacs/info mentioned in info.c DEFAULT_INFOPATH
+@c /usr/gnu/info mentioned in info.c DEFAULT_INFOPATH
+@c /usr/local/info
+@c /usr/local/lib/info
+The @file{dir} file in the @file{info} directory serves as the
+departure point for the whole Info system. From it, you can reach the
+`Top' nodes of each of the documents in a complete Info system.@refill
+
+@node Printed Books, Formatting Commands, Info Files, Overview
+@comment node-name, next, previous, up
+@section Printed Books
+@cindex Printed book and manual characteristics
+@cindex Manual characteristics, printed
+@cindex Book characteristics, printed
+@cindex Texinfo printed book characteristics
+@cindex Characteristics, printed books or manuals
+
+A Texinfo file can be formatted and typeset as a printed book or manual.
+To do this, you need @TeX{}, a powerful, sophisticated typesetting
+program written by Donald Knuth.@footnote{You can also use the
+@code{texi2roff} program if you do not have @TeX{}; since Texinfo is
+designed for use with @TeX{}, @code{texi2roff} is not described here.
+@code{texi2roff} is part of the standard GNU distribution.}@refill
+
+A Texinfo-based book is similar to any other typeset, printed work: it
+can have a title page, copyright page, table of contents, and preface,
+as well as chapters, numbered or unnumbered sections and subsections,
+page headers, cross references, footnotes, and indices.@refill
+
+You can use Texinfo to write a book without ever having the intention
+of converting it into on-line information. You can use Texinfo for
+writing a printed novel, and even to write a printed memo, although
+this latter application is not recommended since electronic mail is so
+much easier.@refill
+
+@TeX{} is a general purpose typesetting program. Texinfo provides a
+file called @file{texinfo.tex} that contains information (definitions or
+@dfn{macros}) that @TeX{} uses when it typesets a Texinfo file.
+(@file{texinfo.tex} tells @TeX{} how to convert the Texinfo @@-commands
+to @TeX{} commands, which @TeX{} can then process to create the typeset
+document.) @file{texinfo.tex} contains the specifications for printing
+a document.@refill
+
+Most often, documents are printed on 8.5 inch by 11 inch
+pages (216@dmn{mm} by 280@dmn{mm}; this is the default size), but you
+can also print for 7 inch by 9.25 inch pages (178@dmn{mm} by
+235@dmn{mm}; the @code{@@smallbook} size) or on European A4 size paper
+(@code{@@afourpaper}). (@xref{smallbook, , Printing ``Small'' Books}.
+Also, see @ref{A4 Paper, ,Printing on A4 Paper}.)@refill
+
+By changing the parameters in @file{texinfo.tex}, you can change the
+size of the printed document. In addition, you can change the style in
+which the printed document is formatted; for example, you can change the
+sizes and fonts used, the amount of indentation for each paragraph, the
+degree to which words are hyphenated, and the like. By changing the
+specifications, you can make a book look dignified, old and serious, or
+light-hearted, young and cheery.@refill
+
+@TeX{} is freely distributable. It is written in a dialect of Pascal
+called WEB and can be compiled either in Pascal or (by using a
+conversion program that comes with the @TeX{} distribution) in C.
+(@xref{TeX Mode, ,@TeX{} Mode, emacs, The GNU Emacs Manual}, for information
+about @TeX{}.)@refill
+
+@TeX{} is very powerful and has a great many features. Because a
+Texinfo file must be able to present information both on a
+character-only terminal in Info form and in a typeset book, the
+formatting commands that Texinfo supports are necessarily
+limited.@refill
+
+@xref{Obtaining TeX, , How to Obtain @TeX{}}.
+
+
+@node Formatting Commands, Conventions, Printed Books, Overview
+@comment node-name, next, previous, up
+@section @@-commands
+@cindex @@-commands
+@cindex Formatting commands
+
+In a Texinfo file, the commands that tell @TeX{} how to typeset the
+printed manual and tell @code{makeinfo} and
+@code{texinfo-format-buffer} how to create an Info file are preceded
+by @samp{@@}; they are called @dfn{@@-commands}. For example,
+@code{@@node} is the command to indicate a node and @code{@@chapter}
+is the command to indicate the start of a chapter.@refill
+
+@quotation
+@strong{Please note:} All the @@-commands, with the exception of the
+@code{@@TeX@{@}} command, must be written entirely in lower
+case.@refill
+@end quotation
+
+The Texinfo @@-commands are a strictly limited set of constructs. The
+strict limits make it possible for Texinfo files to be understood both
+by @TeX{} and by the code that converts them into Info files. You can
+display Info files on any terminal that displays alphabetic and
+numeric characters. Similarly, you can print the output generated by
+@TeX{} on a wide variety of printers.@refill
+
+Depending on what they do or what arguments@footnote{The word
+@dfn{argument} comes from the way it is used in mathematics and does
+not refer to a disputation between two people; it refers to the
+information presented to the command. According to the @cite{Oxford
+English Dictionary}, the word derives from the Latin for @dfn{to make
+clear, prove}; thus it came to mean `the evidence offered as proof',
+which is to say, `the information offered', which led to its
+mathematical meaning. In its other thread of derivation, the word
+came to mean `to assert in a manner against which others may make
+counter assertions', which led to the meaning of `argument' as a
+disputation.} they take, you need to write @@-commands on lines of
+their own or as part of sentences:@refill
+
+@itemize @bullet
+@item
+Write a command such as @code{@@noindent} at the beginning of a line as
+the only text on the line. (@code{@@noindent} prevents the beginning of
+the next line from being indented as the beginning of a
+paragraph.)@refill
+
+@item
+Write a command such as @code{@@chapter} at the beginning of a line
+followed by the command's arguments, in this case the chapter title, on
+the rest of the line. (@code{@@chapter} creates chapter titles.)@refill
+
+@item
+Write a command such as @code{@@dots@{@}} wherever you wish but usually
+within a sentence. (@code{@@dots@{@}} creates dots @dots{})@refill
+
+@item
+Write a command such as @code{@@code@{@var{sample-code}@}} wherever you
+wish (but usually within a sentence) with its argument,
+@var{sample-code} in this example, between the braces. (@code{@@code}
+marks text as being code.)@refill
+
+@item
+Write a command such as @code{@@example} at the beginning of a line of
+its own; write the body-text on following lines; and write the matching
+@code{@@end} command, @code{@@end example} in this case, at the
+beginning of a line of its own after the body-text. (@code{@@example}
+@dots{} @code{@@end example} indents and typesets body-text as an
+example.)@refill
+@end itemize
+
+@noindent
+@cindex Braces, when to use
+As a general rule, a command requires braces if it mingles among other
+text; but it does not need braces if it starts a line of its own. The
+non-alphabetic commands, such as @code{@@:}, are exceptions to the rule;
+they do not need braces.@refill
+
+As you gain experience with Texinfo, you will rapidly learn how to
+write the different commands: the different ways to write commands
+make it easier to write and read Texinfo files than if all commands
+followed exactly the same syntax. (For details about @@-command
+syntax, see @ref{Command Syntax, , @@-Command Syntax}.)@refill
+
+@node Conventions, Comments, Formatting Commands, Overview
+@comment node-name, next, previous, up
+@section General Syntactic Conventions
+@cindex General syntactic conventions
+@cindex Syntactic conventions
+@cindex Conventions, syntactic
+
+All @sc{ascii} printing characters except @samp{@@}, @samp{@{} and
+@samp{@}} can appear in a Texinfo file and stand for themselves.
+@samp{@@} is the escape character which introduces commands.
+@samp{@{} and @samp{@}} should be used only to surround arguments to
+certain commands. To put one of these special characters into the
+document, put an @samp{@@} character in front of it, like this:
+@samp{@@@@}, @samp{@@@{}, and @samp{@@@}}.@refill
+
+@ifinfo
+It is customary in @TeX{} to use doubled single-quote characters to
+begin and end quotations: ` ` and ' ' (but without a space between the
+two single-quote characters). This convention should be followed in
+Texinfo files. @TeX{} converts doubled single-quote characters to
+left- and right-hand doubled quotation marks and Info converts doubled
+single-quote characters to @sc{ascii} double-quotes: ` ` and ' ' to " .@refill
+@end ifinfo
+@iftex
+It is customary in @TeX{} to use doubled single-quote characters to
+begin and end quotations: @w{@tt{ `` }} and @w{@tt{ '' }}. This
+convention should be followed in Texinfo files. @TeX{} converts
+doubled single-quote characters to left- and right-hand doubled
+quotation marks, ``like this'', and Info converts doubled single-quote
+characters to @sc{ascii} double-quotes: @w{@tt{ `` }} and
+@w{@tt{ '' }} to @w{@tt{ " }}.@refill
+@end iftex
+
+Use three hyphens in a row, @samp{---}, for a dash---like this. In
+@TeX{}, a single or even a double hyphen produces a printed dash that
+is shorter than the usual typeset dash. Info reduces three hyphens to two for
+display on the screen.@refill
+
+To prevent a paragraph from being indented in the printed manual, put
+the command @code{@@noindent} on a line by itself before the
+paragraph.@refill
+
+If you mark off a region of the Texinfo file with the @code{@@iftex}
+and @w{@code{@@end iftex}} commands, that region will appear only in
+the printed copy; in that region, you can use certain commands
+borrowed from Plain@TeX{} that you cannot use in Info. Likewise, if
+you mark off a region with the @code{@@ifinfo} and @code{@@end ifinfo}
+commands, that region will appear only in the Info file; in that
+region, you can use Info commands that you cannot use in @TeX{}.
+(@xref{Conditionals}.)
+
+@cindex Tabs; don't use!
+@quotation
+@strong{Caution:} Do not use tabs in a Texinfo file! @TeX{} uses
+variable-width fonts, which means that it cannot predefine a tab to work
+in all circumstances. Consequently, @TeX{} treats tabs like single
+spaces, and that is not what they look like.@refill
+
+@noindent
+To avoid this problem, Texinfo mode causes GNU Emacs to insert multiple
+spaces when you press the @key{TAB} key.@refill
+
+@noindent
+Also, you can run @code{untabify} in Emacs to convert tabs in a region
+to multiple spaces.@refill
+@end quotation
+
+@node Comments, Minimum, Conventions, Overview
+@comment node-name, next, previous, up
+@section Comments
+
+You can write comments in a Texinfo file that will not appear in
+either the Info file or the printed manual by using the
+@code{@@comment} command (which may be abbreviated to @code{@@c}).
+Such comments are for the person who reads the Texinfo file. All the
+text on a line that follows either @code{@@comment} or @code{@@c} is a
+comment; the rest of the line does not appear in either the Info file
+or the printed manual. (Often, you can write the @code{@@comment} or
+@code{@@c} in the middle of a line, and only the text that follows after
+the @code{@@comment} or @code{@@c} command does not appear; but some
+commands, such as @code{@@settitle} and @code{@@setfilename}, work on a
+whole line. You cannot use @code{@@comment} or @code{@@c} in a line
+beginning with such a command.)@refill
+@cindex Comments
+@findex comment
+@findex c @r{(comment)}
+
+You can write long stretches of text that will not appear in either
+the Info file or the printed manual by using the @code{@@ignore} and
+@code{@@end ignore} commands. Write each of these commands on a line
+of its own, starting each command at the beginning of the line. Text
+between these two commands does not appear in the processed output.
+You can use @code{@@ignore} and @code{@@end ignore} for writing
+comments. Often, @code{@@ignore} and @code{@@end ignore} is used
+to enclose a part of the copying permissions that applies to the
+Texinfo source file of a document, but not to the Info or printed
+version of the document.@refill
+@cindex Ignored text
+@cindex Unprocessed text
+@findex ignore
+@c !!! Perhaps include this comment about ignore and ifset:
+@ignore
+Text enclosed by @code{@@ignore} or by failing @code{@@ifset} or
+@code{@@ifclear} conditions is ignored in the sense that it will not
+contribute to the formatted output. However, TeX and makeinfo must
+still parse the ignored text, in order to understand when to
+@emph{stop} ignoring text from the source file; that means that you
+will still get error messages if you have invalid Texinfo markup
+within ignored text.
+@end ignore
+
+@node Minimum, Six Parts, Comments, Overview
+@comment node-name, next, previous, up
+@section What a Texinfo File Must Have
+@cindex Minimal Texinfo file (requirements)
+@cindex Must have in Texinfo file
+@cindex Required in Texinfo file
+@cindex Texinfo file minimum
+
+By convention, the names of Texinfo files end with one of the
+extensions @file{.texinfo}, @file{.texi}, or @file{.tex}. The longer
+extension is preferred since it describes more clearly to a human
+reader the nature of the file. The shorter extensions are for
+operating systems that cannot handle long file names.@refill
+
+In order to be made into a printed manual and an Info file, a
+Texinfo file @strong{must} begin with lines like this:@refill
+
+@example
+@group
+\input texinfo
+@@setfilename @var{info-file-name}
+@@settitle @var{name-of-manual}
+@end group
+@end example
+
+@noindent
+The contents of the file follow this beginning, and then you @strong{must} end
+a Texinfo file with a line like this:@refill
+
+@example
+@@bye
+@end example
+
+@findex input @r{(@TeX{} command)}
+@noindent
+The @samp{\input texinfo} line tells @TeX{} to use the
+@file{texinfo.tex} file, which tells @TeX{} how to translate the Texinfo
+@@-commands into @TeX{} typesetting commands. (Note the use of the
+backslash, @samp{\}; this is correct for @TeX{}.) The
+@samp{@@setfilename} line provides a name for the Info file and the
+@samp{@@settitle} line specifies a title for the page headers (or
+footers) of the printed manual.@refill
+
+The @code{@@bye} line at the end of the file on a line of its own tells
+the formatters that the file is ended and to stop formatting.@refill
+
+Usually, you will not use quite such a spare format, but will include
+mode setting and start-of-header and end-of-header lines at the
+beginning of a Texinfo file, like this:@refill
+
+@example
+@group
+\input texinfo @@c -*-texinfo-*-
+@@c %**start of header
+@@setfilename @var{info-file-name}
+@@settitle @var{name-of-manual}
+@@c %**end of header
+@end group
+@end example
+
+@noindent
+In the first line, @samp{-*-texinfo-*-} causes Emacs to switch into
+Texinfo mode when you edit the file.
+
+The @code{@@c} lines which surround the @samp{@@setfilename} and
+@samp{@@settitle} lines are optional, but you need them in order to
+run @TeX{} or Info on just part of the file. (@xref{Start of Header},
+for more information.)@refill
+
+Furthermore, you will usually provide a Texinfo file with a title
+page, indices, and the like. But the minimum, which can be useful
+for short documents, is just the three lines at the beginning and the
+one line at the end.@refill
+
+@node Six Parts, Short Sample, Minimum, Overview
+@comment node-name, next, previous, up
+@section Six Parts of a Texinfo File
+
+Generally, a Texinfo file contains more than the minimal
+beginning and end---it usually contains six parts:@refill
+
+@table @r
+@item 1. Header
+The @dfn{Header} names the file, tells @TeX{} which definitions' file to
+use, and performs other ``housekeeping'' tasks.@refill
+
+@item 2. Summary Description and Copyright
+The @dfn{Summary Description and Copyright} segment describes the document
+and contains the copyright notice and copying permissions for the Info
+file. The segment must be enclosed between @code{@@ifinfo} and
+@code{@@end ifinfo} commands so that the formatters place it only in the Info
+file.@refill
+
+@item 3. Title and Copyright
+The @dfn{Title and Copyright} segment contains the title and copyright pages
+and copying permissions for the printed manual. The segment must be
+enclosed between @code{@@titlepage} and @code{@@end titlepage} commands.
+The title and copyright page appear only in the printed @w{manual}.@refill
+
+@item 4. `Top' Node and Master Menu
+The @dfn{Master Menu} contains a complete menu of all the nodes in the whole
+Info file. It appears only in the Info file, in the `Top' node.@refill
+
+@item 5. Body
+The @dfn{Body} of the document may be structured like a traditional book or
+encyclopedia or it may be free form.@refill
+
+@item 6. End
+The @dfn{End} contains commands for printing indices and generating
+the table of contents, and the @code{@@bye} command on a line of its
+own.@refill
+@end table
+
+@node Short Sample, Acknowledgements, Six Parts, Overview
+@comment node-name, next, previous, up
+@section A Short Sample Texinfo File
+@cindex Sample Texinfo file
+
+Here is a complete but very short Texinfo file, in 6 parts. The first
+three parts of the file, from @samp{\input texinfo} through to
+@samp{@@end titlepage}, look more intimidating than they are. Most of
+the material is standard boilerplate; when you write a manual, simply
+insert the names for your own manual in this segment. (@xref{Beginning a
+File}.)@refill
+
+@noindent
+In the following, the sample text is @emph{indented}; comments on it are
+not. The complete file, without any comments, is shown in
+@ref{Sample Texinfo File}.
+
+@subheading Part 1: Header
+
+@noindent
+The header does not appear in either the Info file or the@*
+printed output. It sets various parameters, including the@*
+name of the Info file and the title used in the header.
+
+@example
+@group
+\input texinfo @@c -*-texinfo-*-
+@@c %**start of header
+@@setfilename sample.info
+@@settitle Sample Document
+@@c %**end of header
+
+@@setchapternewpage odd
+@end group
+@end example
+
+@subheading Part 2: Summary Description and Copyright
+
+@noindent
+The summary description and copyright segment does not@*
+appear in the printed document.
+
+@example
+@group
+@@ifinfo
+This is a short example of a complete Texinfo file.
+
+Copyright @@copyright@{@} 1990 Free Software Foundation, Inc.
+@@end ifinfo
+@end group
+@end example
+
+@subheading Part 3: Titlepage and Copyright
+
+@noindent
+The titlepage segment does not appear in the Info file.
+
+@example
+@group
+@@titlepage
+@@sp 10
+@@comment The title is printed in a large font.
+@@center @@titlefont@{Sample Title@}
+@end group
+
+@group
+@@c The following two commands start the copyright page.
+@@page
+@@vskip 0pt plus 1filll
+Copyright @@copyright@{@} 1990 Free Software Foundation, Inc.
+@@end titlepage
+@end group
+@end example
+
+@subheading Part 4: `Top' Node and Master Menu
+
+@noindent
+The `Top' node contains the master menu for the Info file.@*
+Since a printed manual uses a table of contents rather than@*
+a menu, the master menu appears only in the Info file.
+
+@example
+@group
+@@node Top, First Chapter, (dir), (dir)
+@@comment node-name, next, previous, up
+@end group
+@end example
+
+@example
+@group
+@@menu
+* First Chapter:: The first chapter is the
+ only chapter in this sample.
+* Concept Index:: This index has two entries.
+@@end menu
+@end group
+@end example
+
+@subheading Part 5: The Body of the Document
+
+@noindent
+The body segment contains all the text of the document, but not the
+indices or table of contents. This example illustrates a node and a
+chapter containing an enumerated list.@refill
+
+@example
+@group
+@@node First Chapter, Concept Index, Top, Top
+@@comment node-name, next, previous, up
+@@chapter First Chapter
+@@cindex Sample index entry
+@end group
+
+@group
+This is the contents of the first chapter.
+@@cindex Another sample index entry
+@end group
+
+@group
+Here is a numbered list.
+
+@@enumerate
+@@item
+This is the first item.
+
+@@item
+This is the second item.
+@@end enumerate
+@end group
+
+@group
+The @@code@{makeinfo@} and @@code@{texinfo-format-buffer@}
+commands transform a Texinfo file such as this into
+an Info file; and @@TeX@{@} typesets it for a printed
+manual.
+@end group
+@end example
+
+@subheading Part 6: The End of the Document
+
+@noindent
+The end segment contains commands both for generating an index in a node
+and unnumbered chapter of its own and for generating the table of
+contents; and it contains the @code{@@bye} command that marks the end of
+the document.@refill
+
+@example
+@group
+@@node Concept Index, , First Chapter, Top
+@@comment node-name, next, previous, up
+@@unnumbered Concept Index
+@end group
+
+@group
+@@printindex cp
+
+@@contents
+@@bye
+@end group
+@end example
+
+@subheading The Results
+
+Here is what the contents of the first chapter of the sample look like:
+
+@sp 1
+@need 700
+@quotation
+This is the contents of the first chapter.
+
+Here is a numbered list.
+
+@enumerate
+@item
+This is the first item.
+
+@item
+This is the second item.
+@end enumerate
+
+The @code{makeinfo} and @code{texinfo-format-buffer}
+commands transform a Texinfo file such as this into
+an Info file; and @TeX{} typesets it for a printed
+manual.
+@end quotation
+
+@node Acknowledgements, , Short Sample, Overview
+@comment node-name, next, previous, up
+@section Acknowledgements
+
+Richard M.@: Stallman wrote Edition 1.0 of this manual.
+@w{Robert J.@: Chassell} revised and extended it,
+starting with Edition 1.1.
+
+Our thanks go out to all who helped improve this work, particularly to
+@w{Francois Pinard} and @w{David D.@: Zuhn}, who tirelessly recorded
+and reported mistakes and obscurities; our special thanks go to
+@w{Melissa Weisshaus} for her frequent and often tedious reviews of
+nearly similar editions. Our mistakes are our own.
+
+@c ignore until mailing lists set up
+@ignore
+Please send suggestions and corrections to:
+
+@example
+@group
+@r{Internet address:}
+ bug-gnu-texinfo@@prep.ai.mit.edu
+
+@r{UUCP path:}
+ mit-eddie!prep.ai.mit.edu!bug-gnu-texinfo
+@end group
+@end example
+
+@noindent
+Please include the manual's edition number in your messages.
+@end ignore
+
+@node Texinfo Mode, Beginning a File, Overview, Top
+@comment node-name, next, previous, up
+@chapter Using Texinfo Mode
+@cindex Texinfo mode
+@cindex Mode, using Texinfo
+@cindex GNU Emacs
+@cindex Emacs
+
+You may edit a Texinfo file with any text editor you choose. A Texinfo
+file is no different from any other @sc{ascii} file. However, GNU Emacs
+comes with a special mode, called Texinfo
+mode, that provides Emacs commands and tools to help ease your work.@refill
+
+This chapter describes features of GNU Emacs' Texinfo mode but not any
+features of the Texinfo formatting language. If you are reading this
+manual straight through from the beginning, you may want to skim through
+this chapter briefly and come back to it after reading succeeding
+chapters which describe the Texinfo formatting language in
+detail.@refill
+
+@menu
+* Texinfo Mode Overview:: How Texinfo mode can help you.
+* Emacs Editing:: Texinfo mode adds to GNU Emacs' general
+ purpose editing features.
+* Inserting:: How to insert frequently used @@-commands.
+* Showing the Structure:: How to show the structure of a file.
+* Updating Nodes and Menus:: How to update or create new nodes and menus.
+* Info Formatting:: How to format for Info.
+* Printing:: How to format and print part or all of a file.
+* Texinfo Mode Summary:: Summary of all the Texinfo mode commands.
+@end menu
+
+@node Texinfo Mode Overview, Emacs Editing, , Texinfo Mode
+@ifinfo
+@heading Texinfo Mode Overview
+@end ifinfo
+
+Texinfo mode provides special features for working with Texinfo
+files:@refill
+
+@itemize @bullet
+@item
+Insert frequently used @@commands. @refill
+
+@item
+Automatically create @code{@@node} lines.
+
+@item
+Show the structure of a Texinfo source file.@refill
+
+@item
+Automatically create or update the `Next',@*
+`Previous', and `Up' pointers of a node.
+
+@item
+Automatically create or update menus.@refill
+
+@item
+Automatically create a master menu.@refill
+
+@item
+Format a part or all of a file for Info.@refill
+
+@item
+Typeset and print part or all of a file.@refill
+@end itemize
+
+Perhaps the two most helpful features are those for inserting frequently
+used @@-commands and for creating node pointers and menus.@refill
+
+@node Emacs Editing, Inserting, Texinfo Mode Overview, Texinfo Mode
+@section The Usual GNU Emacs Editing Commands
+
+In most cases, the usual Text mode commands work the same in Texinfo
+mode as they do in Text mode. Texinfo mode adds new editing commands
+and tools to GNU Emacs' general purpose editing features. The major
+difference concerns filling. In Texinfo mode, the paragraph
+separation variable and syntax table are redefined so that Texinfo
+commands that should be on lines of their own are not inadvertently
+included in paragraphs. Thus, the @kbd{M-q} (@code{fill-paragraph})
+command will refill a paragraph but not mix an indexing command on a
+line adjacent to it into the paragraph.@refill
+
+In addition, Texinfo mode sets the @code{page-delimiter} variable to
+the value of @code{texinfo-chapter-level-regexp}; by default, this is
+a regular expression matching the commands for chapters and their
+equivalents, such as appendices. With this value for the page
+delimiter, you can jump from chapter title to chapter title with the
+@kbd{C-x ]} (@code{forward-page}) and @kbd{C-x [}
+(@code{backward-page}) commands and narrow to a chapter with the
+@kbd{C-x p} (@code{narrow-to-page}) command. (@xref{Pages, , ,emacs,
+The GNU Emacs Manual}, for details about the page commands.)@refill
+
+You may name a Texinfo file however you wish, but the convention is to
+end a Texinfo file name with one of the three extensions
+@file{.texinfo}, @file{.texi}, or @file{.tex}. A longer extension is
+preferred, since it is explicit, but a shorter extension may be
+necessary for operating systems that limit the length of file names.
+GNU Emacs automatically enters Texinfo mode when you visit a file with
+a @file{.texinfo} or @file{.texi}
+extension. Also, Emacs switches to Texinfo mode
+when you visit a
+file that has @samp{-*-texinfo-*-} in its first line. If ever you are
+in another mode and wish to switch to Texinfo mode, type @code{M-x
+texinfo-mode}.@refill
+
+Like all other Emacs features, you can customize or enhance Texinfo
+mode as you wish. In particular, the keybindings are very easy to
+change. The keybindings described here are the default or standard
+ones.@refill
+
+@node Inserting, Showing the Structure, Emacs Editing, Texinfo Mode
+@comment node-name, next, previous, up
+@section Inserting Frequently Used Commands
+@cindex Inserting frequently used commands
+@cindex Frequently used commands, inserting
+@cindex Commands, inserting them
+
+Texinfo mode provides commands to insert various frequently used
+@@-commands into the buffer. You can use these commands to save
+keystrokes.@refill
+
+The insert commands are invoked by typing @kbd{C-c} twice and then the
+first letter of the @@-command:@refill
+
+@table @kbd
+@item C-c C-c c
+@itemx M-x texinfo-insert-@@code
+@findex texinfo-insert-@@code
+Insert @code{@@code@{@}} and put the
+cursor between the braces.@refill
+
+@item C-c C-c d
+@itemx M-x texinfo-insert-@@dfn
+@findex texinfo-insert-@@dfn
+Insert @code{@@dfn@{@}} and put the
+cursor between the braces.@refill
+
+@item C-c C-c e
+@itemx M-x texinfo-insert-@@end
+@findex texinfo-insert-@@end
+Insert @code{@@end} and attempt to insert the correct following word,
+such as @samp{example} or @samp{table}. (This command does not handle
+nested lists correctly, but inserts the word appropriate to the
+immediately preceding list.)@refill
+
+@item C-c C-c i
+@itemx M-x texinfo-insert-@@item
+@findex texinfo-insert-@@item
+Insert @code{@@item} and put the
+cursor at the beginning of the next line.@refill
+
+@item C-c C-c k
+@itemx M-x texinfo-insert-@@kbd
+@findex texinfo-insert-@@kbd
+Insert @code{@@kbd@{@}} and put the
+cursor between the braces.@refill
+
+@item C-c C-c n
+@itemx M-x texinfo-insert-@@node
+@findex texinfo-insert-@@node
+Insert @code{@@node} and a comment line
+listing the sequence for the `Next',
+`Previous', and `Up' nodes.
+Leave point after the @code{@@node}.@refill
+
+@item C-c C-c o
+@itemx M-x texinfo-insert-@@noindent
+@findex texinfo-insert-@@noindent
+Insert @code{@@noindent} and put the
+cursor at the beginning of the next line.@refill
+
+@item C-c C-c s
+@itemx M-x texinfo-insert-@@samp
+@findex texinfo-insert-@@samp
+Insert @code{@@samp@{@}} and put the
+cursor between the braces.@refill
+
+@item C-c C-c t
+@itemx M-x texinfo-insert-@@table
+@findex texinfo-insert-@@table
+Insert @code{@@table} followed by a @key{SPC}
+and leave the cursor after the @key{SPC}.@refill
+
+@item C-c C-c v
+@itemx M-x texinfo-insert-@@var
+@findex texinfo-insert-@@var
+Insert @code{@@var@{@}} and put the
+cursor between the braces.@refill
+
+@item C-c C-c x
+@itemx M-x texinfo-insert-@@example
+@findex texinfo-insert-@@example
+Insert @code{@@example} and put the
+cursor at the beginning of the next line.@refill
+
+@c M-@{ was the binding for texinfo-insert-braces;
+@c in Emacs 19, backward-paragraph will take this binding.
+@item C-c C-c @{
+@itemx M-x texinfo-insert-braces
+@findex texinfo-insert-braces
+Insert @code{@{@}} and put the cursor between the braces.@refill
+
+@item C-c C-c @}
+@itemx C-c C-c ]
+@itemx M-x up-list
+@findex up-list
+Move from between a pair of braces forward past the closing brace.
+Typing @kbd{C-c C-c ]} is easier than typing @kbd{C-c C-c @}}, which
+is, however, more mnemonic; hence the two keybindings. (Also, you can
+move out from between braces by typing @kbd{C-f}.)@refill
+@end table
+
+To put a command such as @w{@code{@@code@{@dots{}@}}} around an
+@emph{existing} word, position the cursor in front of the word and type
+@kbd{C-u 1 C-c C-c c}. This makes it easy to edit existing plain text.
+The value of the prefix argument tells Emacs how many words following
+point to include between braces---1 for one word, 2 for two words, and
+so on. Use a negative argument to enclose the previous word or words.
+If you do not specify a prefix argument, Emacs inserts the @@-command
+string and positions the cursor between the braces. This feature works
+only for those @@-commands that operate on a word or words within one
+line, such as @code{@@kbd} and @code{@@var}.@refill
+
+This set of insert commands was created after analyzing the frequency
+with which different @@-commands are used in the @cite{GNU Emacs
+Manual} and the @cite{GDB Manual}. If you wish to add your own insert
+commands, you can bind a keyboard macro to a key, use abbreviations,
+or extend the code in @file{texinfo.el}.@refill
+
+@findex texinfo-start-menu-description
+@cindex Menu description, start
+@cindex Description for menu, start
+@kbd{C-c C-c C-d} (@code{texinfo-start-menu-description}) is an insert
+command that works differently from the other insert commands. It
+inserts a node's section or chapter title in the space for the
+description in a menu entry line. (A menu entry has three parts, the
+entry name, the node name, and the description. Only the node name is
+required, but a description helps explain what the node is about.
+@xref{Menu Parts, , The Parts of a Menu}.)@refill
+
+To use @code{texinfo-start-menu-description}, position point in a menu
+entry line and type @kbd{C-c C-c C-d}. The command looks for and copies
+the title that goes with the node name, and inserts the title as a
+description; it positions point at beginning of the inserted text so you
+can edit it. The function does not insert the title if the menu entry
+line already contains a description.@refill
+
+This command is only an aid to writing descriptions; it does not do the
+whole job. You must edit the inserted text since a title tends to use
+the same words as a node name but a useful description uses different
+words.@refill
+
+@node Showing the Structure, Updating Nodes and Menus, Inserting, Texinfo Mode
+@comment node-name, next, previous, up
+@section Showing the Section Structure of a File
+@cindex Showing the section structure of a file
+@cindex Section structure of a file, showing it
+@cindex Structure of a file, showing it
+@cindex Outline of file structure, showing it
+@cindex Contents-like outline of file structure
+@cindex File section structure, showing it
+@cindex Texinfo file section structure, showing it
+
+You can show the section structure of a Texinfo file by using the
+@kbd{C-c C-s} command (@code{texinfo-show-structure}). This command
+shows the section structure of a Texinfo file by listing the lines
+that begin with the @@-commands for @code{@@chapter},
+@code{@@section}, and the like. It constructs what amounts
+to a table of contents. These lines are displayed in another buffer
+called the @samp{*Occur*} buffer. In that buffer, you can position
+the cursor over one of the lines and use the @kbd{C-c C-c} command
+(@code{occur-mode-goto-occurrence}), to jump to the corresponding spot
+in the Texinfo file.@refill
+
+@table @kbd
+@item C-c C-s
+@itemx M-x texinfo-show-structure
+@findex texinfo-show-structure
+Show the @code{@@chapter}, @code{@@section}, and such lines of a
+Texinfo file.@refill
+
+@item C-c C-c
+@itemx M-x occur-mode-goto-occurrence
+@findex occur-mode-goto-occurrence
+Go to the line in the Texinfo file corresponding to the line under the
+cursor in the @file{*Occur*} buffer.@refill
+@end table
+
+If you call @code{texinfo-show-structure} with a prefix argument by
+typing @w{@kbd{C-u C-c C-s}}, it will list not only those lines with the
+@@-commands for @code{@@chapter}, @code{@@section}, and the like,
+but also the @code{@@node} lines. (This is how the
+@code{texinfo-show-structure} command worked without an argument in
+the first version of Texinfo. It was changed because @code{@@node}
+lines clutter up the @samp{*Occur*} buffer and are usually not
+needed.) You can use @code{texinfo-show-structure} with a prefix
+argument to check whether the `Next', `Previous', and `Up' pointers of
+an @code{@@node} line are correct.@refill
+
+Often, when you are working on a manual, you will be interested only
+in the structure of the current chapter. In this case, you can mark
+off the region of the buffer that you are interested in with the
+@kbd{C-x n} (@code{narrow-to-region}) command and
+@code{texinfo-show-structure} will work on only that region. To see
+the whole buffer again, use @w{@kbd{C-x w}} (@code{widen}).
+(@xref{Narrowing, , , emacs, The GNU Emacs Manual}, for more
+information about the narrowing commands.)@refill
+
+@vindex page-delimiter
+@cindex Page delimiter in Texinfo mode
+In addition to providing the @code{texinfo-show-structure} command,
+Texinfo mode sets the value of the page delimiter variable to match
+the chapter-level @@-commands. This enables you to use the @kbd{C-x
+]} (@code{forward-page}) and @kbd{C-x [} (@code{backward-page})
+commands to move forward and backward by chapter, and to use the
+@kbd{C-x p} (@code{narrow-to-page}) command to narrow to a chapter.
+@xref{Pages, , , emacs, The GNU Emacs Manual}, for more information
+about the page commands.@refill
+
+@node Updating Nodes and Menus, Info Formatting, Showing the Structure, Texinfo Mode
+@comment node-name, next, previous, up
+@section Updating Nodes and Menus
+@cindex Updating nodes and menus
+@cindex Create nodes, menus automatically
+@cindex Insert nodes, menus automatically
+@cindex Automatically insert nodes, menus
+
+Texinfo mode provides commands for automatically creating or updating
+menus and node pointers. The commands are called ``update'' commands
+because their most frequent use is for updating a Texinfo file after
+you have worked on it; but you can use them to insert the `Next',
+`Previous', and `Up' pointers into an @code{@@node} line that has none and to
+create menus in a file that has none.@refill
+
+If you do not use the updating commands, you need to write menus and
+node pointers by hand, which is a tedious task.@refill
+
+@menu
+* Updating Commands:: Five major updating commands.
+* Updating Requirements:: How to structure a Texinfo file for
+ using the updating command.
+* Other Updating Commands:: How to indent descriptions, insert
+ missing nodes lines, and update
+ nodes in sequence.
+@end menu
+
+@node Updating Commands, Updating Requirements, , Updating Nodes and Menus
+@ifinfo
+@subheading The Updating Commands
+@end ifinfo
+
+You can use the updating commands@refill
+
+@itemize @bullet
+@item
+to insert or update the `Next', `Previous', and `Up' pointers of a
+node,@refill
+
+@item
+to insert or update the menu for a section, and@refill
+
+@item
+to create a master menu for a Texinfo source file.@refill
+@end itemize
+
+You can also use the commands to update all the nodes and menus in a
+region or in a whole Texinfo file.@refill
+
+The updating commands work only with conventional Texinfo files, which
+are structured hierarchically like books. In such files, a structuring
+command line must follow closely after each @code{@@node} line, except
+for the `Top' @code{@@node} line. (A @dfn{structuring command line} is
+a line beginning with @code{@@chapter}, @code{@@section}, or other
+similar command.)
+
+You can write the structuring command line on the line that follows
+immediately after an @code{@@node} line or else on the line that
+follows after a single @code{@@comment} line or a single
+@code{@@ifinfo} line. You cannot interpose more than one line between
+the @code{@@node} line and the structuring command line; and you may
+interpose only an @code{@@comment} line or an @code{@@ifinfo} line.
+
+Commands which work on a whole buffer require that the `Top' node be
+followed by a node with an @code{@@chapter} or equivalent-level command.
+Note that the menu updating commands will not create a main or master
+menu for a Texinfo file that has only @code{@@chapter}-level nodes! The
+menu updating commands only create menus @emph{within} nodes for lower level
+nodes. To create a menu of chapters, you must provide a `Top'
+node.@refill
+
+The menu updating commands remove menu entries that refer to other Info
+files since they do not refer to nodes within the current buffer. This
+is a deficiency. Rather than use menu entries, you can use cross
+references to refer to other Info files. None of the updating commands
+affect cross references.@refill
+
+Texinfo mode has five updating commands that are used most often: two
+are for updating the node pointers or menu of a single node (or a
+region); two are for updating every node pointer and menu in a file;
+and one, the @code{texinfo-master-menu} command, is for creating a
+master menu for a complete file, and optionally, for updating every
+node and menu in the whole Texinfo file.@refill
+
+The @code{texinfo-master-menu} command is the primary command:@refill
+
+@table @kbd
+@item C-c C-u m
+@itemx M-x texinfo-master-menu
+@findex texinfo-master-menu
+Create or update a master menu that includes all the other menus
+(incorporating the descriptions from pre-existing menus, if
+any).@refill
+
+With an argument (prefix argument, @kbd{C-u,} if interactive), first create or
+update all the nodes and all the regular menus in the buffer before
+constructing the master menu. (@xref{The Top Node, , The Top Node and
+Master Menu}, for more about a master menu.)@refill
+
+For @code{texinfo-master-menu} to work, the Texinfo file must have a
+`Top' node and at least one subsequent node.@refill
+
+After extensively editing a Texinfo file, you can type the following:
+
+@example
+C-u M-x texinfo-master-menu
+@exdent or
+C-u C-c C-u m
+@end example
+
+@noindent
+This updates all the nodes and menus completely and all at once.@refill
+@end table
+
+The other major updating commands do smaller jobs and are designed for
+the person who updates nodes and menus as he or she writes a Texinfo
+file.@refill
+
+@need 1000
+The commands are:@refill
+
+@table @kbd
+@item C-c C-u C-n
+@itemx M-x texinfo-update-node
+@findex texinfo-update-node
+Insert the `Next', `Previous', and `Up' pointers for the node that point is
+within (i.e., for the @code{@@node} line preceding point). If the
+@code{@@node} line has pre-existing `Next', `Previous', or `Up'
+pointers in it, the old pointers are removed and new ones inserted.
+With an argument (prefix argument, @kbd{C-u}, if interactive), this command
+updates all @code{@@node} lines in the region (which is the text
+between point and mark).@refill
+
+@item C-c C-u C-m
+@itemx M-x texinfo-make-menu
+@findex texinfo-make-menu
+Create or update the menu in the node that point is within.
+With an argument (@kbd{C-u} as prefix argument, if
+interactive), the command makes or updates menus for the
+nodes which are either within or a part of the
+region.@refill
+
+Whenever @code{texinfo-make-menu} updates an existing menu, the
+descriptions from that menu are incorporated into the new menu. This
+is done by copying descriptions from the existing menu to the entries
+in the new menu that have the same node names. If the node names are
+different, the descriptions are not copied to the new menu.@refill
+
+@item C-c C-u C-e
+@itemx M-x texinfo-every-node-update
+@findex texinfo-every-node-update
+Insert or update the `Next', `Previous', and `Up' pointers for every
+node in the buffer.@refill
+
+@item C-c C-u C-a
+@itemx M-x texinfo-all-menus-update
+@findex texinfo-all-menus-update
+Create or update all the menus in the buffer. With an argument
+(@kbd{C-u} as prefix argument, if interactive), first insert
+or update all the node
+pointers before working on the menus.@refill
+
+If a master menu exists, the @code{texinfo-all-menus-update} command
+updates it; but the command does not create a new master menu if none
+already exists. (Use the @code{texinfo-master-menu} command for
+that.)@refill
+
+When working on a document that does not merit a master menu, you can
+type the following:
+
+@example
+C-u C-c C-u C-a
+@exdent or
+C-u M-x texinfo-all-menus-update
+@end example
+
+@noindent
+This updates all the nodes and menus.@refill
+@end table
+
+The @code{texinfo-column-for-description} variable specifies the
+column to which menu descriptions are indented. By default, the value
+is 32 although it is often useful to reduce it to as low as 24. You
+can set the variable with the @kbd{M-x edit-options} command
+(@pxref{Edit Options, , Editing Variable Values, emacs, The GNU Emacs
+Manual}) or with the @kbd{M-x set-variable} command (@pxref{Examining,
+, Examining and Setting Variables, emacs, The GNU Emacs
+Manual}).@refill
+
+Also, the @code{texinfo-indent-menu-description} command may be used to
+indent existing menu descriptions to a specified column. Finally, if
+you wish, you can use the @code{texinfo-insert-node-lines} command to
+insert missing @code{@@node} lines into a file. (@xref{Other Updating
+Commands}, for more information.)@refill
+
+@node Updating Requirements, Other Updating Commands, Updating Commands, Updating Nodes and Menus
+@comment node-name, next, previous, up
+@subsection Updating Requirements
+@cindex Updating requirements
+@cindex Requirements for updating commands
+
+To use the updating commands, you must organize the Texinfo file
+hierarchically with chapters, sections, subsections, and the like.
+When you construct the hierarchy of the manual, do not `jump down'
+more than one level at a time: you can follow the `Top' node with a
+chapter, but not with a section; you can follow a chapter with a
+section, but not with a subsection. However, you may `jump up' any
+number of levels at one time---for example, from a subsection to a
+chapter.@refill
+
+Each @code{@@node} line, with the exception of the line for the `Top'
+node, must be followed by a line with a structuring command such as
+@code{@@chapter}, @code{@@section}, or
+@code{@@unnumberedsubsec}.@refill
+
+Each @code{@@node} line/structuring-command line combination
+must look either like this:@refill
+
+@example
+@group
+@@node Comments, Minimum, Conventions, Overview
+@@comment node-name, next, previous, up
+@@section Comments
+@end group
+@end example
+
+or like this (without the @code{@@comment} line):
+
+@example
+@group
+@@node Comments, Minimum, Conventions, Overview
+@@section Comments
+@end group
+@end example
+
+@noindent
+In this example, `Comments' is the name of both the node and the
+section. The next node is called `Minimum' and the previous node is
+called `Conventions'. The `Comments' section is within the `Overview'
+node, which is specified by the `Up' pointer. (Instead of an
+@code{@@comment} line, you can write an @code{@@ifinfo} line.)@refill
+
+If a file has a `Top' node, it must be called @samp{top} or @samp{Top}
+and be the first node in the file.@refill
+
+The menu updating commands create a menu of sections within a chapter,
+a menu of subsections within a section, and so on. This means that
+you must have a `Top' node if you want a menu of chapters.@refill
+
+Incidentally, the @code{makeinfo} command will create an Info file for
+a hierarchically organized Texinfo file that lacks `Next', `Previous'
+and `Up' pointers. Thus, if you can be sure that your Texinfo file
+will be formatted with @code{makeinfo}, you have no need for the
+`update node' commands. (@xref{Create an Info File, , Creating an
+Info File}, for more information about @code{makeinfo}.) However,
+both @code{makeinfo} and the @code{texinfo-format-@dots{}} commands
+require that you insert menus in the file.@refill
+
+@node Other Updating Commands, , Updating Requirements, Updating Nodes and Menus
+@comment node-name, next, previous, up
+@subsection Other Updating Commands
+
+In addition to the five major updating commands, Texinfo mode
+possesses several less frequently used updating commands:@refill
+
+@table @kbd
+@item M-x texinfo-insert-node-lines
+@findex texinfo-insert-node-lines
+Insert @code{@@node} lines before the @code{@@chapter},
+@code{@@section}, and other sectioning commands wherever they are
+missing throughout a region in a Texinfo file.@refill
+
+With an argument (@kbd{C-u} as prefix argument, if interactive), the
+@code{texinfo-insert-node-lines} command not only inserts
+@code{@@node} lines but also inserts the chapter or section titles as
+the names of the corresponding nodes. In addition, it inserts the
+titles as node names in pre-existing @code{@@node} lines that lack
+names. Since node names should be more concise than section or
+chapter titles, you must manually edit node names so inserted.@refill
+
+For example, the following marks a whole buffer as a region and inserts
+@code{@@node} lines and titles throughout:@refill
+
+@example
+C-x h C-u M-x texinfo-insert-node-lines
+@end example
+
+(Note that this command inserts titles as node names in @code{@@node}
+lines; the @code{texinfo-start-menu-description} command
+(@pxref{Inserting, Inserting Frequently Used Commands}) inserts titles
+as descriptions in menu entries, a different action. However, in both
+cases, you need to edit the inserted text.)@refill
+
+@item M-x texinfo-multiple-files-update
+@findex texinfo-multiple-files-update @r{(in brief)}
+Update nodes and menus in a document built from several separate files.
+With @kbd{C-u} as a prefix argument, create and insert a master menu in
+the outer file. With a numeric prefix argument, such as @kbd{C-u 2}, first
+update all the menus and all the `Next', `Previous', and `Up' pointers
+of all the included files before creating and inserting a master menu in
+the outer file. The @code{texinfo-multiple-files-update} command is
+described in the appendix on @code{@@include} files.
+@ifinfo
+@xref{texinfo-multiple-files-update}.@refill
+@end ifinfo
+@iftex
+@xref{texinfo-multiple-files-update, ,
+@code{texinfo-multiple-files-update}}.@refill
+@end iftex
+
+@item M-x texinfo-indent-menu-description
+@findex texinfo-indent-menu-description
+Indent every description in the menu following point to the specified
+column. You can use this command to give yourself more space for
+descriptions. With an argument (@kbd{C-u} as prefix argument, if
+interactive), the @code{texinfo-indent-menu-description} command indents
+every description in every menu in the region. However, this command
+does not indent the second and subsequent lines of a multi-line
+description.@refill
+
+@item M-x texinfo-sequential-node-update
+@findex texinfo-sequential-node-update
+Insert the names of the nodes immediately following and preceding the
+current node as the `Next' or `Previous' pointers regardless of those
+nodes' hierarchical level. This means that the `Next' node of a
+subsection may well be the next chapter. Sequentially ordered nodes are
+useful for novels and other documents that you read through
+sequentially. (However, in Info, the @code{g* @key{RET}} command lets
+you look through the file sequentially, so sequentially ordered nodes
+are not strictly necessary.) With an argument (prefix argument, if
+interactive), the @code{texinfo-sequential-node-update} command
+sequentially updates all the nodes in the region.@refill
+@end table
+
+@node Info Formatting, Printing, Updating Nodes and Menus, Texinfo Mode
+@comment node-name, next, previous, up
+@section Formatting for Info
+@cindex Formatting for Info
+@cindex Running an Info formatter
+@cindex Info formatting
+
+Texinfo mode provides several commands for formatting part or all of a
+Texinfo file for Info. Often, when you are writing a document, you
+want to format only part of a file---that is, a region.@refill
+
+You can use either the @code{texinfo-format-region} or the
+@code{makeinfo-region} command to format a region:@refill
+
+@table @kbd
+@findex texinfo-format-region
+@item C-c C-e C-r
+@itemx M-x texinfo-format-region
+@itemx C-c C-m C-r
+@itemx M-x makeinfo-region
+Format the current region for Info.@refill
+@end table
+
+You can use either the @code{texinfo-format-buffer} or the
+@code{makeinfo-buffer} command to format a whole buffer:@refill
+
+@table @kbd
+@findex texinfo-format-buffer
+@item C-c C-e C-b
+@itemx M-x texinfo-format-buffer
+@itemx C-c C-m C-b
+@itemx M-x makeinfo-buffer
+Format the current buffer for Info.@refill
+@end table
+
+@need 1000
+For example, after writing a Texinfo file, you can type the following:
+
+@example
+C-u C-c C-u m
+@exdent or
+C-u M-x texinfo-master-menu
+@end example
+
+@noindent
+This updates all the nodes and menus. Then type the following to create
+an Info file:
+
+@example
+C-c C-m C-b
+@exdent or
+M-x makeinfo-buffer
+@end example
+
+For the Info formatting commands to work, the file @emph{must} include
+a line that has @code{@@setfilename} in its header.@refill
+
+Not all systems support the @code{makeinfo}-based formatting commands.@refill
+
+@xref{Create an Info File}, for details about Info formatting.@refill
+
+@node Printing, Texinfo Mode Summary, Info Formatting, Texinfo Mode
+@comment node-name, next, previous, up
+@section Formatting and Printing
+@cindex Formatting for printing
+@cindex Printing a region or buffer
+@cindex Region formatting and printing
+@cindex Buffer formatting and printing
+@cindex Part of file formatting and printing
+
+Typesetting and printing a Texinfo file is a multi-step process in which
+you first create a file for printing (called a @sc{dvi} file), and then
+print the file. Optionally, you may also create indices. To do this,
+you must run the @code{texindex} command after first running the
+@code{tex} typesetting command; and then you must run the @code{tex}
+command again. @refill
+
+Often, when you are writing a document, you want to typeset and print
+only part of a file to see what it will look like. You can use the
+@code{texinfo-tex-region} and related commands for this purpose. Use
+the @code{texinfo-tex-buffer} command to format all of a
+buffer.@refill
+
+@table @kbd
+@item C-c C-t C-r
+@itemx M-x texinfo-tex-region
+@findex texinfo-tex-region
+Run @TeX{} on the region.@refill
+
+@item C-c C-t C-b
+@itemx M-x texinfo-tex-buffer
+@findex texinfo-tex-buffer
+Run @TeX{} on the buffer.@refill
+
+@item C-c C-t C-i
+@itemx M-x texinfo-texindex
+Run @code{texindex} to sort the indices of a Texinfo file formatted with
+@code{texinfo-tex-region} or @code{texinfo-tex-buffer}. You must run
+the @code{tex} command a second time after sorting the raw index
+files.@refill
+
+@item C-c C-t C-p
+@itemx M-x texinfo-tex-print
+@findex texinfo-tex-print
+Print the file (or the part of the file) previously formatted with
+@code{texinfo-tex-buffer} or @code{texinfo-tex-region}.@refill
+@end table
+
+For @code{texinfo-tex-region} or @code{texinfo-tex-buffer} to work, the
+file @emph{must} start with a @samp{\input texinfo} line and must
+include an @code{@@settitle} line. The file must end with @code{@@bye}
+on a line by itself. (When you use @code{texinfo-tex-region}, you must
+surround the @code{@@settitle} line with start-of-header and
+end-of-header lines.)@refill
+
+@xref{Format/Print Hardcopy}, for a description of the other @TeX{} related
+commands, such as @code{tex-show-print-queue}.@refill
+
+@node Texinfo Mode Summary, , Printing, Texinfo Mode
+@comment node-name, next, previous, up
+@section Texinfo Mode Summary
+
+In Texinfo mode, each set of commands has default keybindings that
+begin with the same keys. All the commands that are custom-created
+for Texinfo mode begin with @kbd{C-c}. The keys are somewhat
+mnemonic.@refill
+
+@subheading Insert Commands
+
+The insert commands are invoked by typing @kbd{C-c} twice and then the
+first letter of the @@-command to be inserted. (It might make more
+sense mnemonically to use @kbd{C-c C-i}, for `custom insert', but
+@kbd{C-c C-c} is quick to type.)@refill
+
+@example
+C-c C-c c @r{Insert} @samp{@@code}.
+C-c C-c d @r{Insert} @samp{@@dfn}.
+C-c C-c e @r{Insert} @samp{@@end}.
+C-c C-c i @r{Insert} @samp{@@item}.
+C-c C-c n @r{Insert} @samp{@@node}.
+C-c C-c s @r{Insert} @samp{@@samp}.
+C-c C-c v @r{Insert} @samp{@@var}.
+C-c C-c @{ @r{Insert braces.}
+C-c C-c ]
+C-c C-c @} @r{Move out of enclosing braces.}
+
+@group
+C-c C-c C-d @r{Insert a node's section title}
+ @r{in the space for the description}
+ @r{in a menu entry line.}
+@end group
+@end example
+
+@subheading Show Structure
+
+The @code{texinfo-show-structure} command is often used within a
+narrowed region.@refill
+
+@example
+C-c C-s @r{List all the headings.}
+@end example
+
+@subheading The Master Update Command
+
+The @code{texinfo-master-menu} command creates a master menu; and can
+be used to update every node and menu in a file as well.@refill
+
+@example
+@group
+C-c C-u m
+M-x texinfo-master-menu
+ @r{Create or update a master menu.}
+@end group
+
+@group
+C-u C-c C-u m @r{With @kbd{C-u} as a prefix argument, first}
+ @r{create or update all nodes and regular}
+ @r{menus, and then create a master menu.}
+@end group
+@end example
+
+@subheading Update Pointers
+
+@c !!! added verbiage to prevent overfull hbox --bob 26 Mar 93
+The update pointer commands are invoked by typing @kbd{C-c C-u} and
+then either typing @kbd{C-n} for @code{texinfo-update-node} or typing
+@kbd{C-e} for @code{texinfo-every-node-update}.@refill
+
+@example
+C-c C-u C-n @r{Update a node.}
+C-c C-u C-e @r{Update every node in the buffer.}
+@end example
+
+@subheading Update Menus
+
+Invoke the update menu commands by typing @kbd{C-c C-u}
+and then either @kbd{C-m} for @code{texinfo-make-menu} or
+@kbd{C-a} for @code{texinfo-all-menus-update}. To update
+both nodes and menus at the same time, precede @kbd{C-c C-u
+C-a} with @kbd{C-u}.@refill
+
+@example
+C-c C-u C-m @r{Make or update a menu.}
+
+@group
+C-c C-u C-a @r{Make or update all}
+ @r{menus in a buffer.}
+@end group
+
+@group
+C-u C-c C-u C-a @r{With @kbd{C-u} as a prefix argument,}
+ @r{first create or update all nodes and}
+ @r{then create or update all menus.}
+@end group
+@end example
+
+@subheading Format for Info
+
+The Info formatting commands that are written in Emacs Lisp are
+invoked by typing @kbd{C-c C-e} and then either @kbd{C-r} for a region
+or @kbd{C-b} for the whole buffer.@refill
+
+The Info formatting commands that are written in C and based on the
+@code{makeinfo} program are invoked by typing @kbd{C-c C-m} and then
+either @kbd{C-r} for a region or @kbd{C-b} for the whole buffer.@refill
+
+@need 800
+@noindent
+Use the @code{texinfo-format@dots{}} commands:
+
+@example
+@group
+C-c C-e C-r @r{Format the region.}
+C-c C-e C-b @r{Format the buffer.}
+@end group
+@end example
+
+@need 750
+@noindent
+Use @code{makeinfo}:
+
+@example
+C-c C-m C-r @r{Format the region.}
+C-c C-m C-b @r{Format the buffer.}
+C-c C-m C-l @r{Recenter the @code{makeinfo} output buffer.}
+C-c C-m C-k @r{Kill the @code{makeinfo} formatting job.}
+@end example
+
+@subheading Typeset and Print
+
+The @TeX{} typesetting and printing commands are invoked by typing
+@kbd{C-c C-t} and then another control command: @kbd{C-r} for
+@code{texinfo-tex-region}, @kbd{C-b} for @code{texinfo-tex-buffer},
+and so on.@refill
+
+@example
+C-c C-t C-r @r{Run @TeX{} on the region.}
+C-c C-t C-b @r{Run @TeX{} on the buffer.}
+C-c C-t C-i @r{Run} @code{texindex}.
+C-c C-t C-p @r{Print the @sc{dvi} file.}
+C-c C-t C-q @r{Show the print queue.}
+C-c C-t C-d @r{Delete a job from the print queue.}
+C-c C-t C-k @r{Kill the current @TeX{} formatting job.}
+C-c C-t C-x @r{Quit a currently stopped @TeX{} formatting job.}
+C-c C-t C-l @r{Recenter the output buffer.}
+@end example
+
+@subheading Other Updating Commands
+
+The `other updating commands' do not have standard keybindings because
+they are rarely used.
+
+@example
+@group
+M-x texinfo-insert-node-lines
+ @r{Insert missing @code{@@node} lines in region.}
+ @r{With @kbd{C-u} as a prefix argument,}
+ @r{use section titles as node names.}
+@end group
+
+@group
+M-x texinfo-multiple-files-update
+ @r{Update a multi-file document.}
+ @r{With @kbd{C-u 2} as a prefix argument,}
+ @r{create or update all nodes and menus}
+ @r{in all included files first.}
+@end group
+
+@group
+M-x texinfo-indent-menu-description
+ @r{Indent descriptions.}
+@end group
+
+@group
+M-x texinfo-sequential-node-update
+ @r{Insert node pointers in strict sequence.}
+@end group
+@end example
+
+@node Beginning a File, Ending a File, Texinfo Mode, Top
+@comment node-name, next, previous, up
+@chapter Beginning a Texinfo File
+@cindex Beginning a Texinfo file
+@cindex Texinfo file beginning
+@cindex File beginning
+
+Certain pieces of information must be provided at the beginning of a
+Texinfo file, such as the name of the file and the title of the
+document.@refill
+
+@menu
+* Four Parts:: Four parts begin a Texinfo file.
+* Sample Beginning:: Here is a sample beginning for a Texinfo file.
+* Header:: The very beginning of a Texinfo file.
+* Info Summary and Permissions:: Summary and copying permissions for Info.
+* Titlepage & Copyright Page:: Creating the title and copyright pages.
+* The Top Node:: Creating the `Top' node and master menu.
+* Software Copying Permissions:: Ensure that you and others continue to
+ have the right to use and share software.
+@end menu
+
+@node Four Parts, Sample Beginning, , Beginning a File
+@ifinfo
+@heading Four Parts Begin a File
+@end ifinfo
+
+Generally, the beginning of a Texinfo file has four parts:@refill
+
+@enumerate
+@item
+The header, delimited by special comment lines, that includes the
+commands for naming the Texinfo file and telling @TeX{} what
+definitions' file to use when processing the Texinfo file.@refill
+
+@item
+A short statement of what the file is about, with a copyright notice
+and copying permissions. This is enclosed in @code{@@ifinfo} and
+@code{@@end ifinfo} commands so that the formatters place it only
+in the Info file.@refill
+
+@item
+A title page and copyright page, with a copyright notice and copying
+permissions. This is enclosed between @code{@@titlepage} and
+@code{@@end titlepage} commands. The title and copyright page appear
+only in the printed @w{manual}.@refill
+
+@item
+The `Top' node that contains a menu for the whole Info file. The
+contents of this node appear only in the Info file.@refill
+@end enumerate
+
+Also, optionally, you may include the copying conditions for a program
+and a warranty disclaimer. The copying section will be followed by an
+introduction or else by the first chapter of the manual.@refill
+
+Since the copyright notice and copying permissions for the Texinfo
+document (in contrast to the copying permissions for a program) are in
+parts that appear only in the Info file or only in the printed manual,
+this information must be given twice.@refill
+
+@node Sample Beginning, Header, Four Parts, Beginning a File
+@comment node-name, next, previous, up
+@section Sample Texinfo File Beginning
+
+The following sample shows what is needed.@refill
+
+@example
+\input texinfo @@c -*-texinfo-*-
+@@c %**start of header
+@@setfilename @var{name-of-info-file}
+@@settitle @var{name-of-manual}
+@@setchapternewpage odd
+@@c %**end of header
+
+@@ifinfo
+This file documents @dots{}
+
+Copyright @var{year} @var{copyright-owner}
+
+@group
+Permission is granted to @dots{}
+@@end ifinfo
+@end group
+
+@group
+@@c This title page illustrates only one of the
+@@c two methods of forming a title page.
+@end group
+
+@group
+@@titlepage
+@@title @var{name-of-manual-when-printed}
+@@subtitle @var{subtitle-if-any}
+@@subtitle @var{second-subtitle}
+@@author @var{author}
+@end group
+
+@group
+@@c The following two commands
+@@c start the copyright page.
+@@page
+@@vskip 0pt plus 1filll
+Copyright @@copyright@{@} @var{year} @var{copyright-owner}
+@end group
+
+Published by @dots{}
+
+Permission is granted to @dots{}
+@@end titlepage
+
+@@node Top, Overview, (dir), (dir)
+
+@@ifinfo
+This document describes @dots{}
+
+This document applies to version @dots{}
+of the program named @dots{}
+@@end ifinfo
+
+@group
+@@menu
+* Copying:: Your rights and freedoms.
+* First Chapter:: Getting started @dots{}
+* Second Chapter:: @dots{}
+ @dots{}
+ @dots{}
+@@end menu
+@end group
+
+@group
+@@node First Chapter, Second Chapter, top, top
+@@comment node-name, next, previous, up
+@@chapter First Chapter
+@@cindex Index entry for First Chapter
+@end group
+@end example
+
+@node Header, Info Summary and Permissions, Sample Beginning, Beginning a File
+@comment node-name, next, previous, up
+@section The Texinfo File Header
+@cindex Header for Texinfo files
+@cindex Texinfo file header
+
+Texinfo files start with at least three lines that provide Info and
+@TeX{} with necessary information. These are the @code{\input
+texinfo} line, the @code{@@settitle} line, and the
+@code{@@setfilename} line. If you want to run @TeX{} on just a part
+of the Texinfo File, you must write the @code{@@settitle}
+and @code{@@setfilename} lines between start-of-header and end-of-header
+lines.@refill
+
+Thus, the beginning of a Texinfo file looks like this:
+
+@example
+@group
+\input texinfo @@c -*-texinfo-*-
+@@setfilename sample.info
+@@settitle Sample Document
+@end group
+@end example
+
+@noindent
+or else like this:
+
+@example
+@group
+\input texinfo @@c -*-texinfo-*-
+@@c %**start of header
+@@setfilename sample.info
+@@settitle Sample Document
+@@c %**end of header
+@end group
+@end example
+
+@menu
+* First Line:: The first line of a Texinfo file.
+* Start of Header:: Formatting a region requires this.
+* setfilename:: Tell Info the name of the Info file.
+* settitle:: Create a title for the printed work.
+* setchapternewpage:: Start chapters on right-hand pages.
+* paragraphindent:: An option to specify paragraph indentation.
+* End of Header:: Formatting a region requires this.
+@end menu
+
+@node First Line, Start of Header, , Header
+@comment node-name, next, previous, up
+@subsection The First Line of a Texinfo File
+@cindex First line of a Texinfo file
+@cindex Beginning line of a Texinfo file
+@cindex Header of a Texinfo file
+
+Every Texinfo file that is to be the top-level input to @TeX{} must begin
+with a line that looks like this:@refill
+
+@example
+\input texinfo @@c -*-texinfo-*-
+@end example
+
+@noindent
+This line serves two functions:
+
+@enumerate
+@item
+When the file is processed by @TeX{}, the @code{\input texinfo} command
+tells @TeX{} to load the macros needed for processing a Texinfo file.
+These are in a file called @file{texinfo.tex}, which is usually located
+in the @file{/usr/lib/tex/macros} directory. @TeX{} uses the backslash,
+@samp{\}, to mark the beginning of a command, just as Texinfo uses
+@code{@@}. The @file{texinfo.tex} file causes the switch from @samp{\}
+to @samp{@@}; before the switch occurs, @TeX{} requires @samp{\}, which
+is why it appears at the beginning of the file.@refill
+
+@item
+When the file is edited in GNU Emacs, the @samp{-*-texinfo-*-} mode
+specification tells Emacs to use Texinfo mode.@refill
+@end enumerate
+
+@node Start of Header, setfilename, First Line, Header
+@comment node-name, next, previous, up
+@subsection Start of Header
+@cindex Start of header line
+
+Write a start-of-header line on the second line of a Texinfo file.
+Follow the start-of-header line with @code{@@setfilename} and
+@code{@@settitle} lines and, optionally, with other command lines, such
+as @code{@@smallbook} or @code{@@footnotestyle}; and then by an
+end-of-header line (@pxref{End of Header}).@refill
+
+With these lines, you can format part of a Texinfo file for Info or
+typeset part for printing.@refill
+
+A start-of-header line looks like this:@refill
+
+@example
+@@c %**start of header
+@end example
+
+The odd string of characters, @samp{%**}, is to ensure that no other
+comment is accidentally taken for a start-of-header line.@refill
+
+@node setfilename, settitle, Start of Header, Header
+@comment node-name, next, previous, up
+@subsection @code{@@setfilename}
+@cindex Info file requires @code{@@setfilename}
+@findex setfilename
+
+In order to be made into an Info file, a Texinfo file must contain a line
+that looks like this:@refill
+
+@example
+@@setfilename @var{info-file-name}
+@end example
+
+Write the @code{@@setfilename} command at the beginning of a line and
+follow it on the same line by the Info file name. Do not write
+anything else on the line; anything on the line after the command is
+considered part of the file name, including a comment.@refill
+
+The @code{@@setfilename} line specifies the name of the Info file to be
+generated. This name should be different from the name of the Texinfo
+file. The convention is to write a name with a @samp{.info} extension,
+to produce an Info file name such as @file{texinfo.info}.@refill
+
+Some operating systems cannot handle long file names. You can run into
+a problem even when the file name you specify is itself short enough.
+This occurs because the Info formatters split a long Info file into
+short indirect subfiles, and name them by appending `-1', `-2', @dots{},
+`-10', `-11', and so on, to the original file name. (@xref{Tag and
+Split Files, , Tag Files and Split Files}.) The subfile name
+@file{texinfo.info-10}, for example, is too long for some systems; so
+the Info file name for this document is actually @file{texinfo} rather than
+@file{texinfo.info}.@refill
+
+The Info formatting commands ignore everything written before the
+@code{@@setfilename} line, which is why the very first line of
+the file (the @code{\input} line) does not need to be commented out.
+The @code{@@setfilename} line is ignored when you typeset a printed
+manual.@refill
+
+@node settitle, setchapternewpage, setfilename, Header
+@comment node-name, next, previous, up
+@subsection @code{@@settitle}
+@findex settitle
+
+In order to be made into a printed manual, a Texinfo file must contain
+a line that looks like this:@refill
+
+@example
+@@settitle @var{title}
+@end example
+
+Write the @code{@@settitle} command at the beginning of a line and
+follow it on the same line by the title. This tells @TeX{} the title
+to use in a header or footer. Do not write anything else on the line;
+anything on the line after the command is considered part of the
+title, including a comment.@refill
+
+Conventionally, @TeX{} formats a Texinfo file for double-sided output
+so as to print the title in the left-hand (even-numbered) page
+headings and the current chapter titles in the right-hand
+(odd-numbered) page headings. (@TeX{} learns the title of each
+chapter from each @code{@@chapter} command.) Page footers are not
+printed.@refill
+
+Even if you are printing in a single-sided style, @TeX{} looks for an
+@code{@@settitle} command line, in case you include the manual title
+in the heading. @refill
+
+The @code{@@settitle} command should precede everything that generates
+actual output in @TeX{}.@refill
+
+Although the title in the @code{@@settitle} command is usually the
+same as the title on the title page, it does not affect the title as
+it appears on the title page. Thus, the two do not need not match
+exactly; and the title in the @code{@@settitle} command can be a
+shortened or expanded version of the title as it appears on the title
+page. (@xref{titlepage, , @code{@@titlepage}}.)@refill
+
+@TeX{} prints page headings only for that text that comes after the
+@code{@@end titlepage} command in the Texinfo file, or that comes
+after an @code{@@headings} command that turns on headings.
+(@xref{headings on off, , The @code{@@headings} Command}, for more
+information.)@refill
+
+You may, if you wish, create your own, customized headings and
+footings. @xref{Headings, , Page Headings}, for a detailed discussion
+of this process.@refill
+
+@node setchapternewpage, paragraphindent, settitle, Header
+@comment node-name, next, previous, up
+@subsection @code{@@setchapternewpage}
+@cindex Starting chapters
+@cindex Pages, starting odd
+@findex setchapternewpage
+
+In a book or a manual, text is usually printed on both sides of the
+paper, chapters start on right-hand pages, and right-hand pages have
+odd numbers. But in short reports, text often is printed only on one
+side of the paper. Also in short reports, chapters sometimes do not
+start on new pages, but are printed on the same page as the end of the
+preceding chapter, after a small amount of vertical whitespace.@refill
+
+You can use the @code{@@setchapternewpage} command with various
+arguments to specify how @TeX{} should start chapters and whether it
+should typeset pages for printing on one or both sides of the paper
+(single-sided or double-sided printing).@refill
+
+Write the @code{@@setchapternewpage} command at the beginning of a
+line followed by its argument.@refill
+
+For example, you would write the following to cause each chapter to
+start on a fresh odd-numbered page:@refill
+
+@example
+@@setchapternewpage odd
+@end example
+
+You can specify one of three alternatives with the
+@code{@@setchapternewpage} command:@refill
+
+@table @asis
+@ignore
+@item No @code{@@setchapternewpage} command
+If the Texinfo file does not contain an @code{@@setchapternewpage}
+command before the @code{@@titlepage} command, @TeX{} automatically
+begins chapters on new pages and prints headings in the standard
+format for single-sided printing. This is the conventional format for
+single-sided printing.@refill
+
+The result is exactly the same as when you write
+@code{@@setchapternewpage on}.@refill
+@end ignore
+@item @code{@@setchapternewpage off}
+Cause @TeX{} to typeset a new chapter on the same page as the last
+chapter, after skipping some vertical whitespace. Also, cause @TeX{} to
+format page headers for single-sided printing. (You can override the
+headers format with the @code{@@headings double} command; see
+@ref{headings on off, , The @code{@@headings} Command}.)@refill
+
+@item @code{@@setchapternewpage on}
+Cause @TeX{} to start new chapters on new pages and to typeset page
+headers for single-sided printing. This is the form most often
+used for short reports.@refill
+
+This alternative is the default.@refill
+
+@item @code{@@setchapternewpage odd}
+Cause @TeX{} to start new chapters on new, odd-numbered pages
+(right-handed pages) and to typeset for double-sided printing. This is
+the form most often used for books and manuals.@refill
+@end table
+
+@noindent
+Texinfo does not have an @code{@@setchapternewpage even} command.@refill
+
+@noindent
+(You can countermand or modify an @code{@@setchapternewpage} command
+with an @code{@@headings} command. @xref{headings on off, , The
+@code{@@headings} Command}.)@refill
+
+At the beginning of a manual or book, pages are not numbered---for
+example, the title and copyright pages of a book are not numbered.
+By convention, table of contents pages are numbered with roman
+numerals and not in sequence with the rest of the document.@refill
+
+Since an Info file does not have pages, the @code{@@setchapternewpage}
+command has no effect on it.@refill
+
+Usually, you do not write an @code{@@setchapternewpage} command for
+single-sided printing, but accept the default which is to typeset for
+single-sided printing and to start new chapters on new pages. Usually,
+you write an @code{@@setchapternewpage odd} command for double-sided
+printing.@refill
+
+@node paragraphindent, End of Header, setchapternewpage, Header
+@comment node-name, next, previous, up
+@subsection Paragraph Indenting
+@cindex Indenting paragraphs
+@cindex Paragraph indentation
+@findex paragraphindent
+
+The Info formatting commands may insert spaces at the beginning of the
+first line of each paragraph, thereby indenting that paragraph. You
+can use the @code{@@paragraphindent} command to specify the
+indentation. Write an @code{@@paragraphindent} command at the
+beginning of a line followed by either @samp{asis} or a number. The
+template is:@refill
+
+@example
+@@paragraphindent @var{indent}
+@end example
+
+The Info formatting commands indent according to the value of
+@var{indent}:@refill
+
+@itemize @bullet
+@item
+If the value of @var{indent} is @samp{asis}, the Info formatting
+commands do not change the existing indentation.@refill
+
+@item
+If the value of @var{indent} is 0, the Info formatting commands delete
+existing indentation.@refill
+
+@item
+If the value of @var{indent} is greater than 0, the Info formatting
+commands indent the paragraph by that number of spaces.@refill
+@end itemize
+
+The default value of @var{indent} is @samp{asis}.@refill
+
+Write the @code{@@paragraphindent} command before or shortly after the
+end-of-header line at the beginning of a Texinfo file. (If you write
+the command between the start-of-header and end-of-header lines, the
+region formatting commands indent paragraphs as specified.)@refill
+
+@c !!! added verbiage to prevent overfull hbox --bob 26 Mar 93
+A peculiarity of @code{texinfo-format-buffer} and
+@code{texinfo-format-region} is that they do not indent (nor
+fill) paragraphs that contain @code{@@w} or @code{@@*} commands.
+@xref{Refilling Paragraphs}, for a detailed description of what goes
+on.@refill
+
+@node End of Header, , paragraphindent, Header
+@comment node-name, next, previous, up
+@subsection End of Header
+@cindex End of header line
+
+Follow the header lines with an @w{end-of-header} line.
+An end-of-header line looks like this:@refill
+
+@example
+@@c %**end of header
+@end example
+
+If you include the @code{@@setchapternewpage} command between the
+start-of-header and end-of-header lines, @TeX{} will typeset a region as
+that command specifies. Similarly, if you include an @code{@@smallbook}
+command between the start-of-header and end-of-header lines, @TeX{} will
+typeset a region in the ``small'' book format.@refill
+
+@ifinfo
+The reason for the odd string of characters (@samp{%**}) is so that the
+@code{texinfo-tex-region} command does not accidentally find
+something that it should not when it is looking for the header.@refill
+
+The start-of-header line and the end-of-header line are Texinfo mode
+variables that you can change.@refill
+@end ifinfo
+
+@iftex
+@xref{Start of Header}.
+@end iftex
+
+@node Info Summary and Permissions, Titlepage & Copyright Page, Header, Beginning a File
+@comment node-name, next, previous, up
+@section Summary and Copying Permissions for Info
+
+The title page and the copyright page appear only in the printed copy of
+the manual; therefore, the same information must be inserted in a
+section that appears only in the Info file. This section usually
+contains a brief description of the contents of the Info file, a
+copyright notice, and copying permissions.@refill
+
+The copyright notice should read:@refill
+
+@example
+Copyright @var{year} @var{copyright-owner}
+@end example
+
+@noindent
+and be put on a line by itself.@refill
+
+Standard text for the copyright permissions is contained in an appendix
+to this manual; see @ref{ifinfo Permissions, , @samp{ifinfo} Copying
+Permissions}, for the complete text.@refill
+
+The permissions text appears in an Info file @emph{before} the first
+node. This mean that a reader does @emph{not} see this text when
+reading the file using Info, except when using the advanced Info command
+@kbd{g *}.
+
+@node Titlepage & Copyright Page, The Top Node, Info Summary and Permissions, Beginning a File
+@comment node-name, next, previous, up
+@section The Title and Copyright Pages
+
+A manual's name and author are usually printed on a title page.
+Sometimes copyright information is printed on the title page as well;
+more often, copyright information is printed on the back of the title
+page.
+
+The title and copyright pages appear in the printed manual, but not in the
+Info file. Because of this, it is possible to use several slightly
+obscure @TeX{} typesetting commands that cannot be used in an Info file.
+In addition, this part of the beginning of a Texinfo file contains the text
+of the copying permissions that will appear in the printed manual.@refill
+
+@xref{Titlepage Permissions, , Titlepage Copying Permissions}, for the
+standard text for the copyright permissions.@refill
+
+@menu
+* titlepage:: Create a title for the printed document.
+* titlefont center sp:: The @code{@@titlefont}, @code{@@center},
+ and @code{@@sp} commands.
+* title subtitle author:: The @code{@@title}, @code{@@subtitle},
+ and @code{@@author} commands.
+* Copyright & Permissions:: How to write the copyright notice and
+ include copying permissions.
+* end titlepage:: Turn on page headings after the title and
+ copyright pages.
+* headings on off:: An option for turning headings on and off
+ and double or single sided printing.
+@end menu
+
+@node titlepage, titlefont center sp, , Titlepage & Copyright Page
+@comment node-name, next, previous, up
+@subsection @code{@@titlepage}
+@cindex Title page
+@findex titlepage
+
+Start the material for the title page and following copyright page
+with @code{@@titlepage} on a line by itself and end it with
+@code{@@end titlepage} on a line by itself.@refill
+
+The @code{@@end titlepage} command starts a new page and turns on page
+numbering. (@xref{Headings, , Page Headings}, for details about how to
+generate of page headings.) All the material that you want to
+appear on unnumbered pages should be put between the
+@code{@@titlepage} and @code{@@end titlepage} commands. By using the
+@code{@@page} command you can force a page break within the region
+delineated by the @code{@@titlepage} and @code{@@end titlepage}
+commands and thereby create more than one unnumbered page. This is
+how the copyright page is produced. (The @code{@@titlepage} command
+might perhaps have been better named the
+@code{@@titleandadditionalpages} command, but that would have been
+rather long!)@refill
+
+@c !!! append refill to footnote when makeinfo can handle it.
+When you write a manual about a computer program, you should write the
+version of the program to which the manual applies on the title
+page. If the manual changes more frequently than the program or is
+independent of it, you should also include an edition
+number@footnote{We have found that it is helpful to refer to versions
+of manuals as `editions' and versions of programs as `versions';
+otherwise, we find we are liable to confuse each other in conversation
+by referring to both the documentation and the software with the same
+words.} for the manual. This helps readers keep track of which manual
+is for which version of the program. (The `Top' node
+should also contain this information; see @ref{makeinfo top, ,
+@code{@@top}}.)@refill
+
+Texinfo provides two methods for creating a title page. One method
+uses the @code{@@titlefont}, @code{@@sp}, and @code{@@center} commands
+to generate a title page in which the words on the page are
+centered.@refill
+
+The second method uses the @code{@@title}, @code{@@subtitle}, and
+@code{@@author} commands to create a title page with black rules under
+the title and author lines and the subtitle text set flush to the
+right hand side of the page. With this method, you do not specify any
+of the actual formatting of the title page. You specify the text
+you want, and Texinfo does the formatting. You may use either
+method.@refill
+
+@node titlefont center sp, title subtitle author, titlepage, Titlepage & Copyright Page
+@comment node-name, next, previous, up
+@subsection @code{@@titlefont}, @code{@@center}, and @code{@@sp}
+@findex titlefont
+@findex center
+@findex sp @r{(titlepage line spacing)}
+
+You can use the @code{@@titlefont}, @code{@@sp}, and @code{@@center}
+commands to create a title page for a printed document. (This is the
+first of the two methods for creating a title page in Texinfo.)@refill
+
+Use the @code{@@titlefont} command to select a large font suitable for
+the title itself.@refill
+
+@need 700
+For example:
+
+@example
+@@titlefont@{Texinfo@}
+@end example
+
+Use the @code{@@center} command at the beginning of a line to center
+the remaining text on that line. Thus,@refill
+
+@example
+@@center @@titlefont@{Texinfo@}
+@end example
+
+@noindent
+centers the title, which in this example is ``Texinfo'' printed
+in the title font.@refill
+
+Use the @code{@@sp} command to insert vertical space. For example:@refill
+
+@example
+@@sp 2
+@end example
+
+@noindent
+This inserts two blank lines on the printed page. (@xref{sp, ,
+@code{@@sp}}, for more information about the @code{@@sp}
+command.)@refill
+
+A template for this method looks like this:@refill
+
+@example
+@group
+@@titlepage
+@@sp 10
+@@center @@titlefont@{@var{name-of-manual-when-printed}@}
+@@sp 2
+@@center @var{subtitle-if-any}
+@@sp 2
+@@center @var{author}
+@dots{}
+@@end titlepage
+@end group
+@end example
+
+The spacing of the example fits an 8 1/2 by 11 inch manual.@refill
+
+@node title subtitle author, Copyright & Permissions, titlefont center sp, Titlepage & Copyright Page
+@comment node-name, next, previous, up
+@subsection @code{@@title}, @code{@@subtitle}, and @code{@@author}
+@findex title
+@findex subtitle
+@findex author
+
+You can use the @code{@@title}, @code{@@subtitle}, and @code{@@author}
+commands to create a title page in which the vertical and horizontal
+spacing is done for you automatically. This contrasts with the method
+described in
+the previous section, in which the @code{@@sp} command is needed to
+adjust vertical spacing.@refill
+
+Write the @code{@@title}, @code{@@subtitle}, or @code{@@author}
+commands at the beginning of a line followed by the title, subtitle,
+or author.@refill
+
+The @code{@@title} command produces a line in which the title is set
+flush to the left-hand side of the page in a larger than normal font.
+The title is underlined with a black rule.@refill
+
+The @code{@@subtitle} command sets subtitles in a normal-sized font
+flush to the right-hand side of the page.@refill
+
+The @code{@@author} command sets the names of the author or authors in
+a middle-sized font flush to the left-hand side of the page on a line
+near the bottom of the title page. The names are underlined with a
+black rule that is thinner than the rule that underlines the title.
+(The black rule only occurs if the @code{@@author} command line is
+followed by an @code{@@page} command line.)@refill
+
+There are two ways to use the @code{@@author} command: you can write
+the name or names on the remaining part of the line that starts with
+an @code{@@author} command:@refill
+
+@example
+@@author by Jane Smith and John Doe
+@end example
+
+@noindent
+or you can write the names one above each other by using two (or more)
+@code{@@author} commands:@refill
+
+@example
+@group
+@@author Jane Smith
+@@author John Doe
+@end group
+@end example
+
+@noindent
+(Only the bottom name is underlined with a black rule.)@refill
+
+@need 950
+A template for this method looks like this:@refill
+
+@example
+@group
+@@titlepage
+@@title @var{name-of-manual-when-printed}
+@@subtitle @var{subtitle-if-any}
+@@subtitle @var{second-subtitle}
+@@author @var{author}
+@@page
+@dots{}
+@@end titlepage
+@end group
+@end example
+
+@ifinfo
+@noindent
+Contrast this form with the form of a title page written using the
+@code{@@sp}, @code{@@center}, and @code{@@titlefont} commands:@refill
+
+@example
+@@titlepage
+@@sp 10
+@@center @@titlefont@{Name of Manual When Printed@}
+@@sp 2
+@@center Subtitle, If Any
+@@sp 1
+@@center Second subtitle
+@@sp 2
+@@center Author
+@@page
+@dots{}
+@@end titlepage
+@end example
+@end ifinfo
+
+@node Copyright & Permissions, end titlepage, title subtitle author, Titlepage & Copyright Page
+@comment node-name, next, previous, up
+@subsection Copyright Page and Permissions
+@cindex Copyright page
+@cindex Printed permissions
+@cindex Permissions, printed
+
+By international treaty, the copyright notice for a book should be
+either on the title page or on the back of the title page. The
+copyright notice should include the year followed by the name of the
+organization or person who owns the copyright.@refill
+
+When the copyright notice is on the back of the title page, that page
+is customarily not numbered. Therefore, in Texinfo, the information
+on the copyright page should be within @code{@@titlepage} and
+@code{@@end titlepage} commands.@refill
+
+@findex vskip
+@findex filll
+@cindex Vertical whitespace (@samp{vskip})
+Use the @code{@@page} command to cause a page break. To push the
+copyright notice and the other text on the copyright page towards the
+bottom of the page, you can write a somewhat mysterious line after the
+@code{@@page} command that reads like this:@refill
+
+@example
+@@vskip 0pt plus 1filll
+@end example
+
+@noindent
+This is a @TeX{} command that is not supported by the Info formatting
+commands. The @code{@@vskip} command inserts whitespace. The
+@samp{0pt plus 1filll} means to put in zero points of mandatory whitespace,
+and as much optional whitespace as needed to push the
+following text to the bottom of the page. Note the use of three
+@samp{l}s in the word @samp{filll}; this is the correct usage in
+@TeX{}.@refill
+
+@findex copyright
+In a printed manual, the @code{@@copyright@{@}} command generates a
+@samp{c} inside a circle. (In Info, it generates @samp{(C)}.) The
+copyright notice itself has the following legally defined sequence:@refill
+
+@example
+Copyright @copyright{} @var{year} @var{copyright-owner}
+@end example
+
+It is customary to put information on how to get a manual after the
+copyright notice, followed by the copying permissions for the
+manual.@refill
+
+Note that permissions must be given here as well as in the summary
+segment within @code{@@ifinfo} and @code{@@end ifinfo} that
+immediately follows the header since this text appears only in the
+printed manual and the @samp{ifinfo} text appears only in the Info
+file.@refill
+
+@xref{Sample Permissions}, for the standard text.@refill
+
+@node end titlepage, headings on off, Copyright & Permissions, Titlepage & Copyright Page
+@comment node-name, next, previous, up
+@subsection Heading Generation
+@findex end titlepage
+@cindex Headings, page, begin to appear
+@cindex Titlepage end starts headings
+@cindex End titlepage starts headings
+
+An @code{@@end titlepage} command on a line by itself not only marks
+the end of the title and copyright pages, but also causes @TeX{} to start
+generating page headings and page numbers.
+
+To repeat what is said elsewhere, Texinfo has two standard page heading
+formats, one for documents which are printed on one side of each sheet of paper
+(single-sided printing), and the other for documents which are printed on both
+sides of each sheet (double-sided printing).
+(@xref{setchapternewpage, ,@code{@@setchapternewpage}}.)
+You can specify these formats in different ways:@refill
+
+@itemize @bullet
+@item
+The conventional way is to write an @code{@@setchapternewpage} command
+before the title page commands, and then have the @code{@@end
+titlepage} command start generating page headings in the manner desired.
+(@xref{setchapternewpage, , @code{@@setchapternewpage}}.)@refill
+
+@item
+Alternatively, you can use the @code{@@headings} command to prevent page
+headings from being generated or to start them for either single or
+double-sided printing. (Write an @code{@@headings} command immediately
+after the @code{@@end titlepage} command. @xref{headings on off, , The
+@code{@@headings} Command}, for more information.)@refill
+
+@item
+Or, you may specify your own page heading and footing format.
+@xref{Headings, , Page Headings}, for detailed
+information about page headings and footings.@refill
+@end itemize
+
+Most documents are formatted with the standard single-sided or
+double-sided format, using @code{@@setchapternewpage odd} for
+double-sided printing and no @code{@@setchapternewpage} command for
+single-sided printing.@refill
+
+@node headings on off, , end titlepage, Titlepage & Copyright Page
+@comment node-name, next, previous, up
+@subsection The @code{@@headings} Command
+@findex headings
+
+The @code{@@headings} command is rarely used. It specifies what kind of
+page headings and footings to print on each page. Usually, this is
+controlled by the @code{@@setchapternewpage} command. You need the
+@code{@@headings} command only if the @code{@@setchapternewpage} command
+does not do what you want, or if you want to turn off pre-defined page
+headings prior to defining your own. Write an @code{@@headings} command
+immediately after the @code{@@end titlepage} command.@refill
+
+There are four ways to use the @code{@@headings} command:@refill
+
+@table @code
+@item @@headings off
+Turn off printing of page headings.@refill
+
+@item @@headings single
+Turn on page headings appropriate for single-sided printing.
+@refill
+
+@item @@headings double
+@itemx @@headings on
+Turn on page headings appropriate for double-sided printing. The two
+commands, @code{@@headings on} and @code{@@headings double}, are
+synonymous.@refill
+@end table
+
+For example, suppose you write @code{@@setchapternewpage off} before the
+@code{@@titlepage} command to tell @TeX{} to start a new chapter on the
+same page as the end of the last chapter. This command also causes
+@TeX{} to typeset page headers for single-sided printing. To cause
+@TeX{} to typeset for double sided printing, write @code{@@headings
+double} after the @code{@@end titlepage} command.
+
+You can stop @TeX{} from generating any page headings at all by
+writing @code{@@headings off} on a line of its own immediately after the
+line containing the @code{@@end titlepage} command, like this:@refill
+
+@example
+@@end titlepage
+@@headings off
+@end example
+
+@noindent
+The @code{@@headings off} command overrides the @code{@@end titlepage}
+command, which would otherwise cause @TeX{} to print page
+headings.@refill
+
+You can also specify your own style of page heading and footing.
+@xref{Headings, , Page Headings}, for more information.@refill
+
+@node The Top Node, Software Copying Permissions, Titlepage & Copyright Page, Beginning a File
+@comment node-name, next, previous, up
+@section The `Top' Node and Master Menu
+@cindex @samp{@r{Top}} node
+@cindex Master menu
+@cindex Node, `Top'
+
+The `Top' node is the node from which you enter an Info file.@refill
+
+A `Top' node should contain a brief description of the Info file and an
+extensive, master menu for the whole Info file.
+This helps the reader understand what the Info file is
+about. Also, you should write the version number of the program to
+which the Info file applies; or, at least, the edition number.@refill
+
+The contents of the `Top' node should appear only in the Info file; none
+of it should appear in printed output, so enclose it between
+@code{@@ifinfo} and @code{@@end ifinfo} commands. (@TeX{} does not
+print either an @code{@@node} line or a menu; they appear only in Info;
+strictly speaking, you are not required to enclose these parts between
+@code{@@ifinfo} and @code{@@end ifinfo}, but it is simplest to do so.
+@xref{Conditionals, , Conditionally Visible Text}.)@refill
+
+@menu
+* Title of Top Node:: Sketch what the file is about.
+* Master Menu Parts:: A master menu has three or more parts.
+@end menu
+
+@node Title of Top Node, Master Menu Parts, , The Top Node
+@ifinfo
+@subheading `Top' Node Title
+@end ifinfo
+
+Sometimes, you will want to place an @code{@@top} sectioning command
+line containing the title of the document immediately after the
+@code{@@node Top} line (@pxref{makeinfo top command, , The @code{@@top}
+Sectioning Command}, for more information).@refill
+
+For example, the beginning of the Top node of this manual contains an
+@code{@@top} sectioning command, a short description, and edition and
+version information. It looks like this:@refill
+
+@example
+@group
+@dots{}
+@@end titlepage
+
+@@ifinfo
+@@node Top, Copying, (dir), (dir)
+@@top Texinfo
+
+Texinfo is a documentation system@dots{}
+@end group
+
+@group
+This is edition@dots{}
+@dots{}
+@@end ifinfo
+@end group
+
+@group
+@@menu
+* Copying:: Texinfo is freely
+ redistributable.
+* Overview:: What is Texinfo?
+@dots{}
+@end group
+@@end menu
+@end example
+
+In a `Top' node, the `Previous', and `Up' nodes usually refer to the top
+level directory of the whole Info system, which is called @samp{(dir)}.
+The `Next' node refers to the first node that follows the main or master
+menu, which is usually the copying permissions, introduction, or first
+chapter.@refill
+
+@node Master Menu Parts, , Title of Top Node, The Top Node
+@subsection Parts of a Master Menu
+@cindex Master menu parts
+@cindex Parts of a master menu
+
+A @dfn{master menu} is a detailed main menu listing all the nodes in a
+file.
+
+A master menu is enclosed in @code{@@menu} and @code{@@end menu}
+commands and does not appear in the printed document.@refill
+
+Generally, a master menu is divided into parts.@refill
+
+@itemize @bullet
+@item
+The first part contains the major nodes in the Texinfo file: the nodes
+for the chapters, chapter-like sections, and the appendices.@refill
+
+@item
+The second part contains nodes for the indices.@refill
+
+@item
+The third and subsequent parts contain a listing of the other, lower
+level nodes, often ordered by chapter. This way, rather than go
+through an intermediary menu, an inquirer can go directly to a
+particular node when searching for specific information. These menu
+items are not required; add them if you think they are a
+convenience.@refill
+@end itemize
+
+Each section in the menu can be introduced by a descriptive line. So
+long as the line does not begin with an asterisk, it will not be
+treated as a menu entry. (@xref{Writing a Menu}, for more
+information.)@refill
+
+For example, the master menu for this manual looks like the following
+(but has many more entries):@refill
+
+@example
+@group
+@@menu
+* Copying:: Texinfo is freely
+ redistributable.
+* Overview:: What is Texinfo?
+* Texinfo Mode:: Special features in GNU Emacs.
+@dots{}
+@dots{}
+@end group
+@group
+* Command and Variable Index::
+ An entry for each @@-command.
+* Concept Index:: An entry for each concept.
+@end group
+
+@group
+ --- The Detailed Node Listing ---
+
+Overview of Texinfo
+
+* Info Files:: What is an Info file?
+* Printed Manuals:: Characteristics of
+ a printed manual.
+@dots{}
+@dots{}
+@end group
+
+@group
+Using Texinfo Mode
+
+* Info on a Region:: Formatting part of a file
+ for Info.
+@dots{}
+@dots{}
+@@end menu
+@end group
+@end example
+
+@node Software Copying Permissions, , The Top Node, Beginning a File
+@comment node-name, next, previous, up
+@section Software Copying Permissions
+@cindex Software copying permissions
+@cindex Copying software
+@cindex Distribution
+@cindex License agreement
+
+If the Texinfo file has a section containing the ``General Public
+License'' and the distribution information and a warranty disclaimer
+for the software that is documented, this section usually follows the
+`Top' node. The General Public License is very important to Project
+GNU software. It ensures that you and others will continue to have a
+right to use and share the software.@refill
+
+The copying and distribution information and the disclaimer are
+followed by an introduction or else by the first chapter of the
+manual.@refill
+
+@cindex Introduction, as part of file
+Although an introduction is not a required part of a Texinfo file, it
+is very helpful. Ideally, it should state clearly and concisely what
+the file is about and who would be interested in reading it. In
+general, an introduction would follow the licensing and distribution
+information, although sometimes people put it earlier in the document.
+Usually, an introduction is put in an @code{@@unnumbered} section.
+(@xref{unnumbered & appendix, , The @code{@@unnumbered} and
+@code{@@appendix} Commands}.)@refill
+
+@node Ending a File, Structuring, Beginning a File, Top
+@comment node-name, next, previous, up
+@chapter Ending a Texinfo File
+@cindex Ending a Texinfo file
+@cindex Texinfo file ending
+@cindex File ending
+@findex bye
+
+The end of a Texinfo file should include the commands that create
+indices and generate detailed and summary tables of contents.
+And it must include the @code{@@bye} command that marks the last line
+processed by @TeX{}.@refill
+
+@need 700
+For example:
+
+@example
+@@node Concept Index, , Variables Index, Top
+@@c node-name, next, previous, up
+@@unnumbered Concept Index
+
+@@printindex cp
+
+@@contents
+@@bye
+@end example
+
+@menu
+* Printing Indices & Menus:: How to print an index in hardcopy and
+ generate index menus in Info.
+* Contents:: How to create a table of contents.
+* File End:: How to mark the end of a file.
+@end menu
+
+@node Printing Indices & Menus, Contents, , Ending a File
+@comment node-name, next, previous, up
+@section Index Menus and Printing an Index
+@findex printindex
+@cindex Printing an index
+@cindex Indices, printing and menus
+@cindex Generating menus with indices
+@cindex Menus generated with indices
+
+To print an index means to include it as part of a manual or Info
+file. This does not happen automatically just because you use
+@code{@@cindex} or other index-entry generating commands in the
+Texinfo file; those just cause the raw data for the index to be
+accumulated. To generate an index, you must include the
+@code{@@printindex} command at the place in the document where you
+want the index to appear. Also, as part of the process of creating a
+printed manual, you must run a program called @code{texindex}
+(@pxref{Format/Print Hardcopy}) to sort the raw data to produce a sorted
+index file. The sorted index file is what is actually used to
+print the index.@refill
+
+Texinfo offers six different types of predefined index: the concept
+index, the function index, the variables index, the keystroke index, the
+program index, and the data type index (@pxref{Predefined Indices}). Each
+index type has a two-letter name: @samp{cp}, @samp{fn}, @samp{vr},
+@samp{ky}, @samp{pg}, and @samp{tp}. You may merge indices, or put them
+into separate sections (@pxref{Combining Indices}); or you may define
+your own indices (@pxref{New Indices, , Defining New Indices}).@refill
+
+The @code{@@printindex} command takes a two-letter index name, reads
+the corresponding sorted index file and formats it appropriately into
+an index.@refill
+
+@ignore
+The two-letter index names are:
+
+@table @samp
+@item cp
+concept index
+@item fn
+function index
+@item vr
+variable index
+@item ky
+key index
+@item pg
+program index
+@item tp
+data type index
+@end table
+@end ignore
+The @code{@@printindex} command does not generate a chapter heading
+for the index. Consequently, you should precede the
+@code{@@printindex} command with a suitable section or chapter command
+(usually @code{@@unnumbered}) to supply the chapter heading and put
+the index into the table of contents. Precede the @code{@@unnumbered}
+command with an @code{@@node} line.@refill
+
+@need 1200
+For example:
+
+@smallexample
+@group
+@@node Variable Index, Concept Index, Function Index, Top
+@@comment node-name, next, previous, up
+@@unnumbered Variable Index
+
+@@printindex vr
+@end group
+
+@group
+@@node Concept Index, , Variable Index, Top
+@@comment node-name, next, previous, up
+@@unnumbered Concept Index
+
+@@printindex cp
+@end group
+
+@group
+@@summarycontents
+@@contents
+@@bye
+@end group
+@end smallexample
+
+@noindent
+(Readers often prefer that the concept index come last in a book,
+since that makes it easiest to find.)@refill
+
+@ignore
+In @TeX{}, the @code{@@printindex} command needs a sorted index file
+to work from. @TeX{} does not know how to do sorting; this is a
+deficiency. @TeX{} writes output files of raw index data; use the
+@code{texindex} program to convert these files to sorted index files.
+(@xref{Format/Print Hardcopy}, for more information.)@refill
+@end ignore
+@node Contents, File End, Printing Indices & Menus, Ending a File
+@comment node-name, next, previous, up
+@section Generating a Table of Contents
+@cindex Table of contents
+@cindex Contents, Table of
+@findex contents
+@findex summarycontents
+@findex shortcontents
+
+The @code{@@chapter}, @code{@@section}, and other structuring commands
+supply the information to make up a table of contents, but they do not
+cause an actual table to appear in the manual. To do this, you must
+use the @code{@@contents} and @code{@@summarycontents}
+commands:@refill
+
+@table @code
+@item @@contents
+Generate a table of contents in a printed manual, including all
+chapters, sections, subsections, etc., as well as appendices and
+unnumbered chapters. (Headings generated by the @code{@@heading}
+series of commands do not appear in the table of contents.) The
+@code{@@contents} command should be written on a line by
+itself.@refill
+
+@item @@shortcontents
+@itemx @@summarycontents
+(@code{@@summarycontents} is a synonym for @code{@@shortcontents}; the
+two commands are exactly the same.)@refill
+
+Generate a short or summary table of contents that lists only the
+chapters (and appendices and unnumbered chapters). Omit sections, subsections
+and subsubsections. Only a long manual needs a short table
+of contents in addition to the full table of contents.@refill
+
+Write the @code{@@shortcontents} command on a line by itself right
+@emph{before} the @code{@@contents} command.@refill
+@end table
+
+The table of contents commands automatically generate a chapter-like
+heading at the top of the first table of contents page. Write the table
+of contents commands at the very end of a Texinfo file, just before the
+@code{@@bye} command, following any index sections---anything in the
+Texinfo file after the table of contents commands will be omitted from
+the table of contents.@refill
+
+When you print a manual with a table of contents, the table of
+contents are printed last and numbered with roman numerals. You need
+to place those pages in their proper place, after the title page,
+yourself. (This is the only collating you need to do for a printed
+manual. The table of contents is printed last because it is generated
+after the rest of the manual is typeset.)@refill
+
+@need 700
+Here is an example of where to write table of contents commands:@refill
+
+@example
+@group
+@var{indices}@dots{}
+@@shortcontents
+@@contents
+@@bye
+@end group
+@end example
+
+Since an Info file uses menus instead of tables of contents, the Info
+formatting commands ignore the @code{@@contents} and
+@code{@@shortcontents} commands.@refill
+
+@node File End, , Contents, Ending a File
+@comment node-name, next, previous, up
+@section @code{@@bye} File Ending
+@findex bye
+
+An @code{@@bye} command terminates @TeX{} or Info formatting. None of
+the formatting commands see any of the file following @code{@@bye}.
+The @code{@@bye} command should be on a line by itself.@refill
+
+If you wish, you may follow the @code{@@bye} line with notes. These notes
+will not be formatted and will not appear in either Info or a printed
+manual; it is as if text after @code{@@bye} were within @code{@@ignore}
+@dots{} @code{@@end ignore}. Also, you may follow the @code{@@bye} line
+with a local variables list. @xref{Compile-Command, , Using Local
+Variables and the Compile Command}, for more information.@refill
+
+@node Structuring, Nodes, Ending a File, Top
+@comment node-name, next, previous, up
+@chapter Chapter Structuring
+@cindex Chapter structuring
+@cindex Structuring of chapters
+
+The @dfn{chapter structuring} commands divide a document into a hierarchy of
+chapters, sections, subsections, and subsubsections. These commands
+generate large headings; they also provide information for the table
+of contents of a printed manual (@pxref{Contents, , Generating a Table
+of Contents}).@refill
+
+The chapter structuring commands do not create an Info node structure,
+so normally you should put an @code{@@node} command immediately before
+each chapter structuring command (@pxref{Nodes}). The only time you
+are likely to use the chapter structuring commands without using the
+node structuring commands is if you are writing a document that
+contains no cross references and will never be transformed into Info
+format.@refill
+
+It is unlikely that you will ever write a Texinfo file that is
+intended only as an Info file and not as a printable document. If you
+do, you might still use chapter structuring commands to create a
+heading at the top of each node---but you don't need to.@refill
+
+@menu
+* Tree Structuring:: A manual is like an upside down tree @dots{}
+* Structuring Command Types:: How to divide a manual into parts.
+* makeinfo top:: The @code{@@top} command, part of the `Top' node.
+* chapter::
+* unnumbered & appendix::
+* majorheading & chapheading::
+* section::
+* unnumberedsec appendixsec heading::
+* subsection::
+* unnumberedsubsec appendixsubsec subheading::
+* subsubsection:: Commands for the lowest level sections.
+@end menu
+
+@node Tree Structuring, Structuring Command Types, , Structuring
+@comment node-name, next, previous, up
+@section Tree Structure of Sections
+@cindex Tree structuring
+
+A Texinfo file is usually structured like a book with chapters,
+sections, subsections, and the like. This structure can be visualized
+as a tree (or rather as an upside-down tree) with the root at the top
+and the levels corresponding to chapters, sections, subsection, and
+subsubsections.@refill
+
+Here is a diagram that shows a Texinfo file with three chapters,
+each of which has two sections.@refill
+
+@example
+@group
+ Top
+ |
+ -------------------------------------
+ | | |
+ Chapter 1 Chapter 2 Chapter 3
+ | | |
+ -------- -------- --------
+ | | | | | |
+ Section Section Section Section Section Section
+ 1.1 1.2 2.1 2.2 3.1 3.2
+
+@end group
+@end example
+
+In a Texinfo file that has this structure, the beginning of Chapter 2
+looks like this:@refill
+
+@example
+@group
+@@node Chapter 2, Chapter 3, Chapter 1, top
+@@chapter Chapter 2
+@end group
+@end example
+
+The chapter structuring commands are described in the sections that
+follow; the @code{@@node} and @code{@@menu} commands are described in
+following chapters. (@xref{Nodes}, and see @ref{Menus}.)@refill
+
+@node Structuring Command Types, makeinfo top, Tree Structuring, Structuring
+@comment node-name, next, previous, up
+@section Types of Structuring Command
+
+The chapter structuring commands fall into four groups or series, each
+of which contains structuring commands corresponding to the
+hierarchical levels of chapters, sections, subsections, and
+subsubsections.@refill
+
+The four groups are the @code{@@chapter} series, the
+@code{@@unnumbered} series, the @code{@@appendix} series, and the
+@code{@@heading} series.@refill
+
+Each command produces titles that have a different appearance on the
+printed page or Info file; only some of the commands produce
+titles that are listed in the table of contents of a printed book or
+manual.@refill
+
+@itemize @bullet
+@item
+The @code{@@chapter} and @code{@@appendix} series of commands produce
+numbered or lettered entries both in the body of a printed work and in
+its table of contents.@refill
+
+@item
+The @code{@@unnumbered} series of commands produce unnumbered entries
+both in the body of a printed work and in its table of contents. The
+@code{@@top} command, which has a special use, is a member of this
+series (@pxref{makeinfo top, , @code{@@top}}).@refill
+
+@item
+The @code{@@heading} series of commands produce unnumbered headings
+that do not appear in a table of contents. The heading commands never
+start a new page.@refill
+
+@item
+The @code{@@majorheading} command produces results similar to using
+the @code{@@chapheading} command but generates a larger vertical
+whitespace before the heading.@refill
+
+@item
+When an @code{@@setchapternewpage} command says to do so, the
+@code{@@chapter}, @code{@@unnumbered}, and @code{@@appendix} commands
+start new pages in the printed manual; the @code{@@heading} commands
+do not.@refill
+@end itemize
+
+@need 1000
+Here are the four groups of chapter structuring commands:@refill
+
+@c Slightly different formatting for regular sized books and smallbooks.
+@ifset smallbook
+@sp 1
+@tex
+{\let\rm=\indrm \let\tt=\indtt
+\halign{\hskip\itemindent#\hfil& \hskip.5em#\hfil& \hskip.5em#\hfil&
+\hskip.5em#\hfil\cr
+
+& & & \rm No new pages\cr
+\rm Numbered& \rm Unnumbered& \rm Lettered and numbered& \rm Unnumbered\cr
+\rm In contents& \rm In contents& \rm In contents& \rm Not in contents\cr
+
+& & & \cr
+ & \tt @@top& & \tt @@majorheading\cr
+\tt @@chapter& \tt @@unnumbered& \tt @@appendix& \tt @@chapheading\cr
+\tt @@section& \tt @@unnumberedsec& \tt @@appendixsec& \tt @@heading\cr
+\tt @@subsection&\tt @@unnumberedsubsec&\tt @@appendixsubsec&
+\tt @@subheading\cr
+\tt @@subsubsection& \tt @@unnumberedsubsubsec& \tt @@appendixsubsubsec&
+\tt @@subsubheading\cr}}
+@end tex
+@end ifset
+@ifclear smallbook
+@sp 1
+@tex
+\vbox{
+\halign{\hskip\itemindent\hskip.5em#\hfil& \hskip.5em#\hfil&
+\hskip.5em#\hfil& \hskip.5em #\hfil\cr
+
+& & & \cr
+& & & \rm No new pages\cr
+\rm Numbered& \rm Unnumbered& \rm Lettered and numbered& \rm Unnumbered\cr
+\rm In contents& \rm In contents& \rm In contents& \rm Not in contents\cr
+
+& & & \cr
+ & \tt @@top& & \tt @@majorheading\cr
+\tt @@chapter& \tt @@unnumbered& \tt @@appendix& \tt @@chapheading\cr
+\tt @@section& \tt @@unnumberedsec& \tt @@appendixsec& \tt @@heading\cr
+\tt @@subsection&\tt @@unnumberedsubsec&\tt @@appendixsubsec&
+\tt @@subheading\cr
+\tt @@subsubsection& \tt @@unnumberedsubsubsec& \tt @@appendixsubsubsec&
+\tt @@subsubheading\cr}}
+@end tex
+@end ifclear
+@ifinfo
+@example
+@group
+ @r{No new pages}
+@r{Numbered} @r{Unnumbered} @r{Lettered and numbered} @r{Unnumbered}
+@r{In contents} @r{In contents} @r{In contents} @r{Not in contents}
+
+ @@top @@majorheading
+@@chapter @@unnumbered @@appendix @@chapheading
+@@section @@unnumberedsec @@appendixsec @@heading
+@@subsection @@unnumberedsubsec @@appendixsubsec @@subheading
+@@subsubsection @@unnumberedsubsubsec @@appendixsubsubsec @@subsubheading
+@end group
+@end example
+@end ifinfo
+
+@c Cannot line up columns properly inside of an example because of roman
+@c proportional fonts.
+@ignore
+@ifset smallbook
+@iftex
+@smallexample
+@group
+ @r{No new pages}
+@r{Numbered} @r{Unnumbered} @r{Lettered and numbered} @r{Unnumbered}
+@r{In contents} @r{In contents} @r{In contents} @r{Not in contents}
+
+ @@top @@majorheading
+@@chapter @@unnumbered @@appendix @@chapheading
+@@section @@unnumberedsec @@appendixsec @@heading
+@@subsection @@unnumberedsubsec @@appendixsubsec @@subheading
+@@subsubsection @@unnumberedsubsubsec @@appendixsubsubsec @@subsubheading
+@end group
+@end smallexample
+@end iftex
+@end ifset
+@ifclear smallbook
+@iftex
+@smallexample
+@group
+ @r{No new pages}
+@r{Numbered} @r{Unnumbered} @r{Lettered and numbered} @r{Unnumbered}
+@r{In contents} @r{In contents} @r{In contents} @r{Not in contents}
+
+ @@top @@majorheading
+@@chapter @@unnumbered @@appendix @@chapheading
+@@section @@unnumberedsec @@appendixsec @@heading
+@@subsection @@unnumberedsubsec @@appendixsubsec @@subheading
+@@subsubsection @@unnumberedsubsubsec @@appendixsubsubsec @@subsubheading
+@end group
+@end smallexample
+@end iftex
+@end ignore
+
+@node makeinfo top, chapter, Structuring Command Types, Structuring
+@comment node-name, next, previous, up
+@section @code{@@top}
+
+The @code{@@top} command is a special sectioning command that you use
+only after an @code{@@node Top} line at the beginning of a Texinfo file.
+The @code{@@top} command tells the @code{makeinfo} formatter
+which node is the `Top'
+node. It has the same typesetting effect as @code{@@unnumbered}
+(@pxref{unnumbered & appendix, , @code{@@unnumbered}, @code{@@appendix}}).
+For detailed information, see
+@ref{makeinfo top command, , The @code{@@top} Command}.@refill
+
+@node chapter, unnumbered & appendix, makeinfo top, Structuring
+@comment node-name, next, previous, up
+@section @code{@@chapter}
+@findex chapter
+
+@code{@@chapter} identifies a chapter in the document. Write the
+command at the beginning of a line and follow it on the same line by
+the title of the chapter.@refill
+
+For example, this chapter in this manual is entitled ``Chapter
+Structuring''; the @code{@@chapter} line looks like this:@refill
+
+@example
+@@chapter Chapter Structuring
+@end example
+
+In @TeX{}, the @code{@@chapter} command creates a chapter in the
+document, specifying the chapter title. The chapter is numbered
+automatically.@refill
+
+In Info, the @code{@@chapter} command causes the title to appear on a
+line by itself, with a line of asterisks inserted underneath. Thus,
+in Info, the above example produces the following output:@refill
+
+@example
+Chapter Structuring
+*******************
+@end example
+
+@node unnumbered & appendix, majorheading & chapheading, chapter, Structuring
+@comment node-name, next, previous, up
+@section @code{@@unnumbered}, @code{@@appendix}
+@findex unnumbered
+@findex appendix
+
+Use the @code{@@unnumbered} command to create a chapter that appears
+in a printed manual without chapter numbers of any kind. Use the
+@code{@@appendix} command to create an appendix in a printed manual
+that is labelled by letter instead of by number.@refill
+
+For Info file output, the @code{@@unnumbered} and @code{@@appendix}
+commands are equivalent to @code{@@chapter}: the title is printed on a
+line by itself with a line of asterisks underneath. (@xref{chapter, ,
+@code{@@chapter}}.)@refill
+
+To create an appendix or an unnumbered chapter, write an
+@code{@@appendix} or @code{@@unnumbered} command at the beginning of a
+line and follow it on the same line by the title, as you would if you
+were creating a chapter.@refill
+
+@node majorheading & chapheading, section, unnumbered & appendix, Structuring
+@section @code{@@majorheading}, @code{@@chapheading}
+@findex majorheading
+@findex chapheading
+
+The @code{@@majorheading} and @code{@@chapheading} commands put
+chapter-like headings in the body of a document.@refill
+
+However, neither command causes @TeX{} to produce a numbered heading
+or an entry in the table of contents; and neither command causes
+@TeX{} to start a new page in a printed manual.@refill
+
+In @TeX{}, an @code{@@majorheading} command generates a larger vertical
+whitespace before the heading than an @code{@@chapheading} command but
+is otherwise the same.@refill
+
+In Info,
+the @code{@@majorheading} and
+@code{@@chapheading} commands are equivalent to
+@code{@@chapter}: the title is printed on a line by itself with a line
+of asterisks underneath. (@xref{chapter, , @code{@@chapter}}.)@refill
+
+@node section, unnumberedsec appendixsec heading, majorheading & chapheading, Structuring
+@comment node-name, next, previous, up
+@section @code{@@section}
+@findex section
+
+In a printed manual, an @code{@@section} command identifies a
+numbered section within a chapter. The section title appears in the
+table of contents. In Info, an @code{@@section} command provides a
+title for a segment of text, underlined with @samp{=}.@refill
+
+This section is headed with an @code{@@section} command and looks like
+this in the Texinfo file:@refill
+
+@example
+@@section @@code@{@@@@section@}
+@end example
+
+To create a section, write the @code{@@section} command at the
+beginning of a line and follow it on the same line by the section
+title.@refill
+
+Thus,
+
+@example
+@@section This is a section
+@end example
+
+@noindent
+produces
+
+@example
+@group
+This is a section
+=================
+@end group
+@end example
+
+@noindent
+in Info.
+
+@node unnumberedsec appendixsec heading, subsection, section, Structuring
+@comment node-name, next, previous, up
+@section @code{@@unnumberedsec}, @code{@@appendixsec}, @code{@@heading}
+@findex unnumberedsec
+@findex appendixsec
+@findex heading
+
+The @code{@@unnumberedsec}, @code{@@appendixsec}, and @code{@@heading}
+commands are, respectively, the unnumbered, appendix-like, and
+heading-like equivalents of the @code{@@section} command.
+(@xref{section, , @code{@@section}}.)@refill
+
+@table @code
+@item @@unnumberedsec
+The @code{@@unnumberedsec} command may be used within an
+unnumbered chapter or within a regular chapter or appendix to
+provide an unnumbered section.@refill
+
+@item @@appendixsec
+@itemx @@appendixsection
+@code{@@appendixsection} is a longer spelling of the
+@code{@@appendixsec} command; the two are synonymous.@refill
+@findex appendixsection
+
+Conventionally, the @code{@@appendixsec} or @code{@@appendixsection}
+command is used only within appendices.@refill
+
+@item @@heading
+You may use the @code{@@heading} command anywhere you wish for a
+section-style heading that will not appear in the table of contents.@refill
+@end table
+
+@node subsection, unnumberedsubsec appendixsubsec subheading, unnumberedsec appendixsec heading, Structuring
+@comment node-name, next, previous, up
+@section The @code{@@subsection} Command
+@findex subsection
+
+Subsections are to sections as sections are to chapters.
+(@xref{section, , @code{@@section}}.) In Info, subsection titles are
+underlined with @samp{-}. For example,@refill
+
+@example
+@@subsection This is a subsection
+@end example
+
+@noindent
+produces
+
+@example
+@group
+This is a subsection
+--------------------
+@end group
+@end example
+
+In a printed manual, subsections are listed in the table of contents
+and are numbered three levels deep.@refill
+
+@node unnumberedsubsec appendixsubsec subheading, subsubsection, subsection, Structuring
+@comment node-name, next, previous, up
+@section The @code{@@subsection}-like Commands
+@cindex Subsection-like commands
+@findex unnumberedsubsec
+@findex appendixsubsec
+@findex subheading
+
+The @code{@@unnumberedsubsec}, @code{@@appendixsubsec}, and
+@code{@@subheading} commands are, respectively, the unnumbered,
+appendix-like, and heading-like equivalents of the @code{@@subsection}
+command. (@xref{subsection, , @code{@@subsection}}.)@refill
+
+In Info, the @code{@@subsection}-like commands generate a title
+underlined with hyphens. In a printed manual, an @code{@@subheading}
+command produces a heading like that of a subsection except that it is
+not numbered and does not appear in the table of contents. Similarly,
+an @code{@@unnumberedsubsec} command produces an unnumbered heading like
+that of a subsection and an @code{@@appendixsubsec} command produces a
+subsection-like heading labelled with a letter and numbers; both of
+these commands produce headings that appear in the table of
+contents.@refill
+
+@node subsubsection, , unnumberedsubsec appendixsubsec subheading, Structuring
+@comment node-name, next, previous, up
+@section The `subsub' Commands
+@cindex Subsub commands
+@findex subsubsection
+@findex unnumberedsubsubsec
+@findex appendixsubsubsec
+@findex subsubheading
+
+The fourth and lowest level sectioning commands in Texinfo are the
+`subsub' commands. They are:@refill
+
+@table @code
+@item @@subsubsection
+Subsubsections are to subsections as subsections are to sections.
+(@xref{subsection, , @code{@@subsection}}.) In a printed manual,
+subsubsection titles appear in the table of contents and are numbered
+four levels deep.@refill
+
+@item @@unnumberedsubsubsec
+Unnumbered subsubsection titles appear in the table of contents of a
+printed manual, but lack numbers. Otherwise, unnumbered
+subsubsections are the same as subsubsections. In Info, unnumbered
+subsubsections look exactly like ordinary subsubsections.@refill
+
+@item @@appendixsubsubsec
+Conventionally, appendix commands are used only for appendices and are
+lettered and numbered appropriately in a printed manual. They also
+appear in the table of contents. In Info, appendix subsubsections look
+exactly like ordinary subsubsections.@refill
+
+@item @@subsubheading
+The @code{@@subsubheading} command may be used anywhere that you need
+a small heading that will not appear in the table of contents. In
+Info, subsubheadings look exactly like ordinary subsubsection
+headings.@refill
+@end table
+
+In Info, `subsub' titles are underlined with periods.
+For example,@refill
+
+@example
+@@subsubsection This is a subsubsection
+@end example
+
+@noindent
+produces
+
+@example
+@group
+This is a subsubsection
+.......................
+@end group
+@end example
+
+@node Nodes, Menus, Structuring, Top
+@comment node-name, next, previous, up
+@chapter Nodes
+
+@dfn{Nodes} are the primary segments of a Texinfo file. They do not
+themselves impose a hierarchic or any other kind of structure on a file.
+Nodes contain @dfn{node pointers} that name other nodes, and can contain
+@dfn{menus} which are lists of nodes. In Info, the movement commands
+can carry you to a pointed-to node or to a node listed in a menu. Node
+pointers and menus provide structure for Info files just as chapters,
+sections, subsections, and the like, provide structure for printed
+books.@refill
+
+@menu
+* Two Paths:: Different commands to structure
+ Info output and printed output.
+* Node Menu Illustration:: A diagram, and sample nodes and menus.
+* node:: How to write a node, in detail.
+* makeinfo Pointer Creation:: How to create node pointers with @code{makeinfo}.
+@end menu
+
+@node Two Paths, Node Menu Illustration, , Nodes
+@ifinfo
+@heading Two Paths
+@end ifinfo
+
+The node and menu commands and the chapter structuring commands are
+independent of each other:
+
+@itemize @bullet
+@item
+In Info, node and menu commands provide structure. The chapter
+structuring commands generate headings with different kinds of
+underlining---asterisks for chapters, hyphens for sections, and so on;
+they do nothing else.@refill
+
+@item
+In @TeX{}, the chapter structuring commands generate chapter and section
+numbers and tables of contents. The node and menu commands provide
+information for cross references; they do nothing else.@refill
+@end itemize
+
+You can use node pointers and menus to structure an Info file any way
+you want; and you can write a Texinfo file so that its Info output has a
+different structure than its printed output. However, most Texinfo
+files are written such that the structure for the Info output
+corresponds to the structure for the printed output. It is not
+convenient to do otherwise.@refill
+
+Generally, printed output is structured in a tree-like hierarchy in
+which the chapters are the major limbs from which the sections branch
+out. Similarly, node pointers and menus are organized to create a
+matching structure in the Info output.@refill
+
+@node Node Menu Illustration, node, Two Paths, Nodes
+@comment node-name, next, previous, up
+@section Node and Menu Illustration
+
+Here is a copy of the diagram shown earlier that illustrates a Texinfo
+file with three chapters, each of which contains two sections.@refill
+
+Note that the ``root'' is at the top of the diagram and the ``leaves''
+are at the bottom. This is how such a diagram is drawn conventionally;
+it illustrates an upside-down tree. For this reason, the root node is
+called the `Top' node, and `Up' node pointers carry you closer to the
+root.@refill
+
+@example
+@group
+ Top
+ |
+ -------------------------------------
+ | | |
+ Chapter 1 Chapter 2 Chapter 3
+ | | |
+ -------- -------- --------
+ | | | | | |
+ Section Section Section Section Section Section
+ 1.1 1.2 2.1 2.2 3.1 3.2
+
+@end group
+@end example
+
+Write the beginning of the node for Chapter 2 like this:@refill
+
+@example
+@group
+@@node Chapter 2, Chapter 3, Chapter 1, top
+@@comment node-name, next, previous, up
+@end group
+@end example
+
+@noindent
+This @code{@@node} line says that the name of this node is ``Chapter 2'', the
+name of the `Next' node is ``Chapter 3'', the name of the `Previous'
+node is ``Chapter 1'', and the name of the `Up' node is ``Top''.
+
+@quotation
+@strong{Please Note:} `Next' refers to the next node at the same
+hierarchical level in the manual, not necessarily to the next node
+within the Texinfo file. In the Texinfo file, the subsequent node may
+be at a lower level---a section-level node may follow a chapter-level
+node, and a subsection-level node may follow a section-level node.
+`Next' and `Previous' refer to nodes at the @emph{same} hierarchical
+level. (The `Top' node contains the exception to this rule. Since the
+`Top' node is the only node at that level, `Next' refers to the first
+following node, which is almost always a chapter or chapter-level
+node.)@refill
+@end quotation
+
+To go to Sections 2.1 and 2.2 using Info, you need a menu inside Chapter
+2. (@xref{Menus}.) You would write the menu just
+before the beginning of Section 2.1, like this:@refill
+
+@example
+@group
+ @@menu
+ * Sect. 2.1:: Description of this section.
+ * Sect. 2.2::
+ @@end menu
+@end group
+@end example
+
+Write the node for Sect. 2.1 like this:@refill
+
+@example
+@group
+ @@node Sect. 2.1, Sect. 2.2, Chapter 2, Chapter 2
+ @@comment node-name, next, previous, up
+@end group
+@end example
+
+In Info format, the `Next' and `Previous' pointers of a node usually
+lead to other nodes at the same level---from chapter to chapter or from
+section to section (sometimes, as shown, the `Previous' pointer points
+up); an `Up' pointer usually leads to a node at the level above (closer
+to the `Top' node); and a `Menu' leads to nodes at a level below (closer
+to `leaves'). (A cross reference can point to a node at any level;
+see @ref{Cross References}.)@refill
+
+Usually, an @code{@@node} command and a chapter structuring command are
+used in sequence, along with indexing commands. (You may follow the
+@code{@@node} line with a comment line that reminds you which pointer is
+which.)@refill
+
+Here is the beginning of the chapter in this manual called ``Ending a
+Texinfo File''. This shows an @code{@@node} line followed by a comment
+line, an @code{@@chapter} line, and then by indexing lines.@refill
+
+@example
+@group
+@@node Ending a File, Structuring, Beginning a File, Top
+@@comment node-name, next, previous, up
+@@chapter Ending a Texinfo File
+@@cindex Ending a Texinfo file
+@@cindex Texinfo file ending
+@@cindex File ending
+@end group
+@end example
+
+@node node, makeinfo Pointer Creation, Node Menu Illustration, Nodes
+@comment node-name, next, previous, up
+@section The @code{@@node} Command
+
+@cindex Node, defined
+A @dfn{node} is a segment of text that begins at an @code{@@node}
+command and continues until the next @code{@@node} command. The
+definition of node is different from that for chapter or section. A
+chapter may contain sections and a section may contain subsections;
+but a node cannot contain subnodes; the text of a node continues only
+until the next @code{@@node} command in the file. A node usually
+contains only one chapter structuring command, the one that follows
+the @code{@@node} line. On the other hand, in printed output nodes
+are used only for cross references, so a chapter or section may
+contain any number of nodes. Indeed, a chapter usually contains
+several nodes, one for each section, subsection, and
+subsubsection.@refill
+
+To create a node, write an @code{@@node} command at the beginning of a
+line, and follow it with four arguments, separated by commas, on the
+rest of the same line. These arguments are the name of the node, and
+the names of the `Next', `Previous', and `Up' pointers, in that order.
+You may insert spaces before each pointer if you wish; the spaces are
+ignored. You must write the name of the node, and the names of the
+`Next', `Previous', and `Up' pointers, all on the same line. Otherwise,
+the formatters fail. (@inforef{Top, info, info}, for more information
+about nodes in Info.)@refill
+
+Usually, you write one of the chapter-structuring command lines
+immediately after an @code{@@node} line---for example, an
+@code{@@section} or @code{@@subsection} line. (@xref{Structuring
+Command Types, , Types of Structuring Command}.)@refill
+
+@quotation
+@strong{Please note:} The GNU Emacs Texinfo mode updating commands work
+only with Texinfo files in which @code{@@node} lines are followed by chapter
+structuring lines. @xref{Updating Requirements}.@refill
+@end quotation
+
+@TeX{} uses @code{@@node} lines to identify the names to use for cross
+references. For this reason, you must write @code{@@node} lines in a
+Texinfo file that you intend to format for printing, even if you do not
+intend to format it for Info. (Cross references, such as the one at the
+end of this sentence, are made with @code{@@xref} and its related
+commands; see @ref{Cross References}.)@refill
+
+@menu
+* Node Names:: How to choose node and pointer names.
+* Writing a Node:: How to write an @code{@@node} line.
+* Node Line Tips:: Keep names short.
+* Node Line Requirements:: Keep names unique, without @@-commands.
+* First Node:: How to write a `Top' node.
+* makeinfo top command:: How to use the @code{@@top} command.
+* Top Node Summary:: Write a brief description for readers.
+@end menu
+
+@node Node Names, Writing a Node, , node
+@ifinfo
+@subheading Choosing Node and Pointer Names
+@end ifinfo
+
+The name of a node identifies the node. The pointers enable
+you to reach other nodes and consist of the names of those nodes.@refill
+
+Normally, a node's `Up' pointer contains the name of the node whose menu
+mentions that node. The node's `Next' pointer contains the name of the
+node that follows that node in that menu and its `Previous' pointer
+contains the name of the node that precedes it in that menu. When a
+node's `Previous' node is the same as its `Up' node, both node pointers
+name the same node.@refill
+
+Usually, the first node of a Texinfo file is the `Top' node, and its
+`Up' and `Previous' pointers point to the @file{dir} file, which
+contains the main menu for all of Info.@refill
+
+The `Top' node itself contains the main or master menu for the manual.
+Also, it is helpful to include a brief description of the manual in the
+`Top' node. @xref{First Node}, for information on how to write the
+first node of a Texinfo file.@refill
+
+@node Writing a Node, Node Line Tips, Node Names, node
+@comment node-name, next, previous, up
+@subsection How to Write an @code{@@node} Line
+@cindex Writing an @code{@@node} line
+@cindex @code{@@node} line writing
+@cindex Node line writing
+
+The easiest way to write an @code{@@node} line is to write @code{@@node}
+at the beginning of a line and then the name of the node, like
+this:@refill
+
+@example
+@@node @var{node-name}
+@end example
+
+If you are using GNU Emacs, you can use the update node commands
+provided by Texinfo mode to insert the names of the pointers; or you
+can leave the pointers out of the Texinfo file and let @code{makeinfo}
+insert node pointers into the Info file it creates. (@xref{Texinfo
+Mode}, and @ref{makeinfo Pointer Creation}.)@refill
+
+Alternatively, you can insert the `Next', `Previous', and `Up'
+pointers yourself. If you do this, you may find it helpful to use the
+Texinfo mode keyboard command @kbd{C-c C-c n}. This command inserts
+@samp{@@node} and a comment line listing the names of the pointers in
+their proper order. The comment line helps you keep track of which
+arguments are for which pointers. This comment line is especially useful
+if you are not familiar with Texinfo.@refill
+
+The template for a node line with `Next', `Previous', and `Up' pointers
+looks like this:@refill
+
+@example
+@@node @var{node-name}, @var{next}, @var{previous}, @var{up}
+@end example
+
+If you wish, you can ignore @code{@@node} lines altogether in your first
+draft and then use the @code{texinfo-insert-node-lines} command to
+create @code{@@node} lines for you. However, we do not
+recommend this practice. It is better to name the node itself
+at the same time that you
+write a segment so you can easily make cross references. A large number
+of cross references are an especially important feature of a good Info
+file.@refill
+
+After you have inserted an @code{@@node} line, you should immediately
+write an @@-command for the chapter or section and insert its name.
+Next (and this is important!), put in several index entries. Usually,
+you will find at least two and often as many as four or five ways of
+referring to the node in the index. Use them all. This will make it
+much easier for people to find the node.@refill
+
+@node Node Line Tips, Node Line Requirements, Writing a Node, node
+@comment node-name, next, previous, up
+@subsection @code{@@node} Line Tips
+
+Here are three suggestions:
+
+@itemize @bullet
+@item
+Try to pick node names that are informative but short.@refill
+
+In the Info file, the file name, node name, and pointer names are all
+inserted on one line, which may run into the right edge of the window.
+(This does not cause a problem with Info, but is ugly.)@refill
+
+@item
+Try to pick node names that differ from each other near the beginnings
+of their names. This way, it is easy to use automatic name completion in
+Info.@refill
+
+@item
+By convention, node names are capitalized just as they would be for
+section or chapter titles---initial and significant words are
+capitalized; others are not.@refill
+@end itemize
+
+@node Node Line Requirements, First Node, Node Line Tips, node
+@comment node-name, next, previous, up
+@subsection @code{@@node} Line Requirements
+
+@cindex Node line requirements
+Here are several requirements for @code{@@node} lines:
+
+@itemize @bullet
+@cindex Unique nodename requirement
+@cindex Nodename must be unique
+@item
+All the node names for a single Info file must be unique.@refill
+
+Duplicates confuse the Info movement commands. This means, for
+example, that if you end every chapter with a summary, you must name
+each summary node differently. You cannot just call each one
+``Summary''. You may, however, duplicate the titles of chapters, sections,
+and the like. Thus you can end each chapter in a book with a section
+called ``Summary'', so long as the node names for those sections are all
+different.@refill
+
+@item
+A pointer name must be the name of a node.@refill
+
+The node to which a pointer points may come before or after the
+node containing the pointer.@refill
+
+@cindex @@-command in nodename
+@cindex Nodename, cannot contain
+@item
+You cannot use any of the Texinfo @@-commands in a node name;
+@w{@@-commands} confuse Info.@refill
+
+@need 750
+Thus, the beginning of the section called @code{@@chapter} looks like
+this:@refill
+
+@smallexample
+@group
+@@node chapter, unnumbered & appendix, makeinfo top, Structuring
+@@comment node-name, next, previous, up
+@@section @@code@{@@@@chapter@}
+@@findex chapter
+@end group
+@end smallexample
+
+@cindex Comma in nodename
+@cindex Colon in nodename
+@cindex Apostrophe in nodename
+@item
+You cannot use commas, colons, or apostrophes within a node name; these
+confuse @TeX{} or the Info formatters.@refill
+
+@need 700
+For example, the following is a section title:
+
+@smallexample
+@@code@{@@@@unnumberedsec@}, @@code@{@@@@appendixsec@}, @@code@{@@@@heading@}
+@end smallexample
+
+@noindent
+The corresponding node name is:
+
+@smallexample
+unnumberedsec appendixsec heading
+@end smallexample
+
+@cindex Case in nodename
+@item
+Case is significant.
+@end itemize
+
+@node First Node, makeinfo top command, Node Line Requirements, node
+@comment node-name, next, previous, up
+@subsection The First Node
+@cindex @samp{@r{Top}} node is first
+@cindex First node
+
+The first node of a Texinfo file is the `Top' node, except in an
+included file (@pxref{Include Files}).
+
+The `Top' node (which must be named @samp{top} or @samp{Top}) should
+have as its `Up' and `Previous' nodes the name of a node in another
+file, where there is a menu that leads to this file. Specify the file
+name in parentheses. If the file is to be installed directly in the
+Info directory file, use @samp{(dir)} as the parent of the `Top' node;
+this is short for @samp{(dir)top}, and specifies the `Top' node in the
+@file{dir} file, which contains the main menu for Info. For example,
+the @code{@@node Top} line of this manual looks like this:@refill
+
+@example
+@@node Top, Overview, (dir), (dir)
+@end example
+
+@noindent
+(You may use the Texinfo updating commands or the @code{makeinfo}
+utility to insert these `Next' and @samp{(dir)} pointers
+automatically.)@refill
+
+@xref{Install an Info File}, for more information about installing
+an Info file in the @file{info} directory.@refill
+
+The `Top' node contains the main or master menu for the document.
+
+@node makeinfo top command, Top Node Summary, First Node, node
+@comment node-name, next, previous, up
+@subsection The @code{@@top} Sectioning Command
+@findex top @r{(@@-command)}
+
+A special sectioning command, @code{@@top}, has been created for use
+with the @code{@@node Top} line. The @code{@@top} sectioning command tells
+@code{makeinfo} that it marks the `Top' node in the file. It provides
+the information that @code{makeinfo} needs to insert node
+pointers automatically. Write the @code{@@top} command at the
+beginning of the line immediately following the @code{@@node Top}
+line. Write the title on the remaining part of the same line as the
+@code{@@top} command.@refill
+
+In Info, the @code{@@top} sectioning command causes the title to appear on a
+line by itself, with a line of asterisks inserted underneath.@refill
+
+In @TeX{} and @code{texinfo-format-buffer}, the @code{@@top}
+sectioning command is merely a synonym for @code{@@unnumbered}.
+Neither of these formatters require an @code{@@top} command, and do
+nothing special with it. You can use @code{@@chapter} or
+@code{@@unnumbered} after the @code{@@node Top} line when you use
+these formatters. Also, you can use @code{@@chapter} or
+@code{@@unnumbered} when you use the Texinfo updating commands to
+create or update pointers and menus.@refill
+
+Whatever sectioning command follows an @code{@@node Top} line, whether
+it be @code{@@top} or @code{@@chapter}, the @code{@@node Top} line and
+the immediately following line and any additional text must be
+enclosed between @code{@@ifinfo} and @code{@@end ifinfo} commands.
+(@xref{Conditionals}.) This prevents the title and the accompanying
+text from appearing in printed output. Write the @code{@@ifinfo}
+command before the @code{@@node} line and write the @code{@@end ifinfo} command
+after the @code{@@top} or other sectioning command and after any
+additional text. (You can write the @code{@@end ifinfo} command after
+the @code{@@end menu} command if you like.)@refill
+
+@node Top Node Summary, , makeinfo top command, node
+@subsection The `Top' Node Summary
+@cindex @samp{@r{Top}} node summary
+
+You can help readers by writing a summary in the `Top' node, after the
+@code{@@top} line, before the main or master menu. The summary should
+briefly describe the Info file. You should also write the version
+number of the program to which the manual applies in this section. This
+helps the reader keep track of which manual is for which version of the
+program. If the manual changes more frequently than the program or is
+independent of it, you should also include an edition number for the
+manual. (The title page should also contain this information:
+see @ref{titlepage, , @code{@@titlepage}}.)@refill
+
+Put the whole of the `Top' node, including the @code{@@top} sectioning
+command line if you
+have one, between @code{@@ifinfo} and @code{@@end
+ifinfo} so none of the text appears in the printed output
+(@pxref{Conditionals, , Conditionally Visible Text}). (You may want to
+repeat the brief description from the `Top' node within @code{@@iftex}
+@dots{} @code{@@end iftex} at the beginning of the first chapter, for
+those who read the printed manual.)
+
+@node makeinfo Pointer Creation, , node, Nodes
+@section Creating Pointers with @code{makeinfo}
+@cindex Creating pointers with @code{makeinfo}
+@cindex Pointer creation with @code{makeinfo}
+@cindex Automatic pointer creation with @code{makeinfo}
+
+The @code{makeinfo} program has a feature for automatically creating
+node pointers for a hierarchically organized file that lacks
+them.@refill
+
+When you take advantage of this feature, you do not need to write the
+`Next', `Previous', and `Up' pointers after the name of a node.
+However, you must write a sectioning command, such as @code{@@chapter}
+or @code{@@section}, on the line immediately following each truncated
+@code{@@node} line. You cannot write a comment line after a node
+line; the section line must follow it immediately.@refill
+
+In addition, you must follow the `Top' @code{@@node} line with a line beginning
+with @code{@@top} to mark the `Top' node in the file. @xref{makeinfo
+top, , @code{@@top}}.
+
+Finally, you must write the name of each node (except for the `Top'
+node) in a menu that is one or more hierarchical levels above the
+node's hierarchical level.@refill
+
+This node pointer insertion feature in @code{makeinfo} is an
+alternative to the menu and pointer creation and update commands in
+Texinfo mode. (@xref{Updating Nodes and Menus}.) It is especially
+helpful to people who do not use GNU Emacs for writing Texinfo
+documents.@refill
+
+@node Menus, Cross References, Nodes, Top
+@comment node-name, next, previous, up
+@chapter Menus
+@cindex Menus
+@findex menu
+
+@dfn{Menus} contain pointers to subordinate
+nodes.@footnote{Menus can carry you to any node, regardless
+of the hierarchical structure; even to nodes in a different
+Info file. However, the GNU Emacs Texinfo mode updating
+commands work only to create menus of subordinate nodes.
+Conventionally, cross references are used to refer to other
+nodes.} In Info, you use menus to go to such nodes. Menus
+have no effect in printed manuals and do not appear in
+them.@refill
+
+By convention, a menu is put at the end of a node since a reader who
+uses the menu may not see text that follows it.@refill
+
+@ifinfo
+A node that has a menu should @emph{not} contain much text. If you
+have a lot of text and a menu, move most of the text into a new
+subnode---all but a few lines.@refill
+@end ifinfo
+@iftex
+@emph{A node that has a menu should not contain much text.} If you
+have a lot of text and a menu, move most of the text into a new
+subnode---all but a few lines. Otherwise, a reader with a terminal
+that displays only a few lines may miss the menu and its associated
+text. As a practical matter, you should locate a menu within 20 lines
+of the beginning of the node.@refill
+@end iftex
+
+@menu
+* Menu Location:: Put a menu in a short node.
+* Writing a Menu:: What is a menu?
+* Menu Parts:: A menu entry has three parts.
+* Less Cluttered Menu Entry:: Two part menu entry.
+* Menu Example:: Two and three part menu entries.
+* Other Info Files:: How to refer to a different Info file.
+@end menu
+
+@node Menu Location, Writing a Menu, , Menus
+@ifinfo
+@heading Menus Need Short Nodes
+@end ifinfo
+@cindex Menu location
+@cindex Location of menus
+@cindex Nodes for menus are short
+@cindex Short nodes for menus
+
+@ifinfo
+A reader can easily see a menu that is close to the beginning of the
+node. The node should be short. As a practical matter, you should
+locate a menu within 20 lines of the beginning of the node.
+Otherwise, a reader with a terminal that displays only a few lines may
+miss the menu and its associated text.@refill
+@end ifinfo
+
+The short text before a menu may look awkward in a printed manual. To
+avoid this, you can write a menu near the beginning of its node and
+follow the menu by an @code{@@node} line, and then an @code{@@heading}
+line located within @code{@@ifinfo} and @code{@@end ifinfo}. This way,
+the menu, @code{@@node} line, and title appear only in the Info file,
+not the printed document.@refill
+
+For example, the preceding two paragraphs follow an Info-only menu,
+@code{@@node} line, and heading, and look like this:@refill
+
+@example
+@group
+@@menu
+* Menu Location:: Put a menu in a short node.
+* Writing a Menu:: What is a menu?
+* Menu Parts:: A menu entry has three parts.
+* Less Cluttered Menu Entry:: Two part menu entry.
+* Menu Example:: Two and three part entries.
+* Other Info Files:: How to refer to a different
+ Info file.
+@@end menu
+
+@@node Menu Location, Writing a Menu, , Menus
+@@ifinfo
+@@heading Menus Need Short Nodes
+@@end ifinfo
+@end group
+@end example
+
+The Texinfo file for this document contains more than a dozen
+examples of this procedure. One is at the beginning of this chapter;
+another is at the beginning of the ``Cross References'' chapter.@refill
+
+@node Writing a Menu, Menu Parts, Menu Location, Menus
+@section Writing a Menu
+@cindex Writing a menu
+@cindex Menu writing
+
+A menu consists of an @code{@@menu} command on a line by
+itself followed by menu entry lines or menu comment lines
+and then by an @code{@@end menu} command on a line by
+itself.@refill
+
+A menu looks like this:@refill
+
+@example
+@group
+@@menu
+Larger Units of Text
+
+* Files:: All about handling files.
+* Multiples: Buffers. Multiple buffers; editing
+ several files at once.
+@@end menu
+@end group
+@end example
+
+In a menu, every line that begins with an @w{@samp{* }} is a
+@dfn{menu entry}. (Note the space after the asterisk.) A
+line that does not start with an @w{@samp{* }} may also
+appear in a menu. Such a line is not a menu entry but is a
+menu comment line that appears in the Info file. In
+the example above, the line @samp{Larger Units of Text} is a
+menu comment line; the two lines starting with @w{@samp{* }}
+are menu entries.
+
+@node Menu Parts, Less Cluttered Menu Entry, Writing a Menu, Menus
+@section The Parts of a Menu
+@cindex Parts of a menu
+@cindex Menu parts
+@cindex @code{@@menu} parts
+
+A menu entry has three parts, only the second of which is
+required:@refill
+
+@enumerate
+@item
+The menu entry name.
+
+@item
+The name of the node (required).
+
+@item
+A description of the item.
+@end enumerate
+
+The template for a menu entry looks like this:@refill
+
+@example
+* @var{menu-entry-name}: @var{node-name}. @var{description}
+@end example
+
+Follow the menu entry name with a single colon and follow the node name
+with tab, comma, period, or newline.@refill
+
+In Info, a user selects a node with the @kbd{m} (@code{Info-menu})
+command. The menu entry name is what the user types after the @kbd{m}
+command.@refill
+
+The third part of a menu entry is a descriptive phrase or
+sentence. Menu entry names and node names are often short; the
+description explains to the reader what the node is about. The
+description, which is optional, can spread over two or more lines. A
+useful description complements the node name rather than repeats
+it.@refill
+
+@node Less Cluttered Menu Entry, Menu Example, Menu Parts, Menus
+@comment node-name, next, previous, up
+@section Less Cluttered Menu Entry
+@cindex Two part menu entry
+@cindex Double-colon menu entries
+@cindex Menu entries with two colons
+@cindex Less cluttered menu entry
+@cindex Uncluttered menu entry
+
+When the menu entry name and node name are the same, you can write
+the name immediately after the asterisk and space at the beginning of
+the line and follow the name with two colons.@refill
+
+@need 800
+For example, write
+
+@example
+* Name:: @var{description}
+@end example
+
+@need 800
+@noindent
+instead of
+
+@example
+* Name: Name. @var{description}
+@end example
+
+You should use the node name for the menu entry name whenever possible,
+since it reduces visual clutter in the menu.@refill
+
+@node Menu Example, Other Info Files, Less Cluttered Menu Entry, Menus
+@comment node-name, next, previous, up
+@section A Menu Example
+@cindex Menu example
+@cindex Example menu
+
+A menu looks like this in Texinfo:@refill
+
+@example
+@group
+@@menu
+* menu entry name: Node name. A short description.
+* Node name:: This form is preferred.
+@@end menu
+@end group
+@end example
+
+@need 800
+@noindent
+This produces:
+
+@example
+@group
+* menu:
+
+* menu entry name: Node name. A short description.
+* Node name:: This form is preferred.
+@end group
+@end example
+
+@need 700
+Here is an example as you might see it in a Texinfo file:@refill
+
+@example
+@group
+@@menu
+Larger Units of Text
+
+* Files:: All about handling files.
+* Multiples: Buffers. Multiple buffers; editing
+ several files at once.
+@@end menu
+@end group
+@end example
+
+@need 800
+@noindent
+This produces:
+
+@example
+@group
+* menu:
+Larger Units of Text
+
+* Files:: All about handling files.
+* Multiples: Buffers. Multiple buffers; editing
+ several files at once.
+@end group
+@end example
+
+In this example, the menu has two entries. @samp{Files} is both a menu
+entry name and the name of the node referred to by that name.
+@samp{Multiples} is the menu entry name; it refers to the node named
+@samp{Buffers}. The line @samp{Larger Units of Text} is a comment; it
+appears in the menu, but is not an entry.@refill
+
+Since no file name is specified with either @samp{Files} or
+@samp{Buffers}, they must be the names of nodes in the same Info file
+(@pxref{Other Info Files, , Referring to Other Info Files}).@refill
+
+@node Other Info Files, , Menu Example, Menus
+@comment node-name, next, previous, up
+@section Referring to Other Info Files
+@cindex Referring to other Info files
+@cindex Nodes in other Info files
+@cindex Other Info files' nodes
+@cindex Going to other Info files' nodes
+@cindex Info; other files' nodes
+
+You can create a menu entry that enables a reader in Info to go to a
+node in another Info file by writing the file name in parentheses just
+before the node name. In this case, you should use the three-part menu
+entry format, which saves the reader from having to type the file
+name.@refill
+
+@need 800
+The format looks like this:@refill
+
+@example
+@group
+@@menu
+* @var{first-entry-name}:(@var{filename})@var{nodename}. @var{description}
+* @var{second-entry-name}:(@var{filename})@var{second-node}. @var{description}
+@@end menu
+@end group
+@end example
+
+For example, to refer directly to the @samp{Outlining} and
+@samp{Rebinding} nodes in the @cite{Emacs Manual}, you would write a
+menu like this:@refill
+
+@example
+@group
+@@menu
+* Outlining: (emacs)Outline Mode. The major mode for
+ editing outlines.
+* Rebinding: (emacs)Rebinding. How to redefine the
+ meaning of a key.
+@@end menu
+@end group
+@end example
+
+If you do not list the node name, but only name the file, then Info
+presumes that you are referring to the `Top' node.@refill
+
+The @file{dir} file that contains the main menu for Info has menu
+entries that list only file names. These take you directly to the `Top'
+nodes of each Info document. (@xref{Install an Info File}.)@refill
+
+@need 700
+For example:
+
+@example
+@group
+* Info: (info). Documentation browsing system.
+* Emacs: (emacs). The extensible, self-documenting
+ text editor.
+@end group
+@end example
+
+@noindent
+(The @file{dir} top level directory for the Info system is an Info file,
+not a Texinfo file, but a menu entry looks the same in both types of
+file.)@refill
+
+Note that the GNU Emacs Texinfo mode menu updating commands only work
+with nodes within the current buffer, so you cannot use them to create
+menus that refer to other files. You must write such menus by hand.@refill
+
+@node Cross References, Marking Text, Menus, Top
+@comment node-name, next, previous, up
+@chapter Cross References
+@cindex Making cross references
+@cindex Cross references
+@cindex References
+
+@dfn{Cross references} are used to refer the reader to other parts of the
+same or different Texinfo files. In Texinfo, nodes are the
+places to which cross references can refer.@refill
+
+@menu
+* References:: What cross references are for.
+* Cross Reference Commands:: A summary of the different commands.
+* Cross Reference Parts:: A cross reference has several parts.
+* xref:: Begin a reference with `See' @dots{}
+* Top Node Naming:: How to refer to the beginning of another file.
+* ref:: A reference for the last part of a sentence.
+* pxref:: How to write a parenthetical cross reference.
+* inforef:: How to refer to an Info-only file.
+@end menu
+
+@node References, Cross Reference Commands, , Cross References
+@ifinfo
+@heading What References Are For
+@end ifinfo
+
+Often, but not always, a printed document should be designed so that
+it can be read sequentially. People tire of flipping back and forth
+to find information that should be presented to them as they need
+it.@refill
+
+However, in any document, some information will be too detailed for
+the current context, or incidental to it; use cross references to
+provide access to such information. Also, an on-line help system or a
+reference manual is not like a novel; few read such documents in
+sequence from beginning to end. Instead, people look up what they
+need. For this reason, such creations should contain many cross
+references to help readers find other information that they may not
+have read.@refill
+
+In a printed manual, a cross reference results in a page reference,
+unless it is to another manual altogether, in which case the cross
+reference names that manual.@refill
+
+In Info, a cross reference results in an entry that you can follow using
+the Info @samp{f} command. (@inforef{Help-Adv, Some advanced Info
+commands, info}.)@refill
+
+The various cross reference commands use nodes to define cross
+reference locations. This is evident in Info, in which a cross
+reference takes you to the specified node. @TeX{} also uses nodes to
+define cross reference locations, but the action is less obvious. When
+@TeX{} generates a @sc{dvi} file, it records nodes' page numbers and
+uses the page numbers in making references. Thus, if you are writing
+a manual that will only be printed, and will not be used on-line, you
+must nonetheless write @code{@@node} lines to name the places to which
+you make cross references.@refill
+
+@need 800
+@node Cross Reference Commands, Cross Reference Parts, References, Cross References
+@comment node-name, next, previous, up
+@section Different Cross Reference Commands
+@cindex Different cross reference commands
+
+There are four different cross reference commands:@refill
+
+@table @code
+@item @@xref
+Used to start a sentence in the printed manual saying
+@w{`See @dots{}'} or an entry in the Info file saying
+@samp{*Note @dots{}}.
+
+@item @@ref
+Used within or, more often, at the end of a sentence; same as
+@code{@@xref} for Info; produces just the reference in the printed
+manual without a preceding `See'.@refill
+
+@item @@pxref
+Used within parentheses to make a reference that suits both an Info
+file and a printed book. Starts with a lower case `see' within the
+printed manual. (@samp{p} is for `parenthesis'.)@refill
+
+@item @@inforef
+Used to make a reference to an Info file for which there is no printed
+manual.@refill
+@end table
+
+@noindent
+(The @code{@@cite} command is used to make references to books and
+manuals for which there is no corresponding Info file and, therefore,
+no node to which to point. @xref{cite, , @code{@@cite}}.)@refill
+
+@node Cross Reference Parts, xref, Cross Reference Commands, Cross References
+@comment node-name, next, previous, up
+@section Parts of a Cross Reference
+@cindex Cross reference parts
+@cindex Parts of a cross reference
+
+A cross reference command requires only one argument, which is the
+name of the node to which it refers. But a cross reference command
+may contain up to four additional arguments. By using these
+arguments, you can provide a cross reference name for Info, a topic
+description or section title for the printed output, the name of a
+different Info file, and the name of a different printed
+manual.@refill
+
+Here is a simple cross reference example:@refill
+
+@example
+@@xref@{Node name@}.
+@end example
+
+@noindent
+which produces
+
+@example
+*Note Node name::.
+@end example
+
+@noindent
+and
+
+@quotation
+See Section @var{nnn} [Node name], page @var{ppp}.
+@end quotation
+
+@need 700
+Here is an example of a full five-part cross reference:@refill
+
+@example
+@group
+@@xref@{Node name, Cross Reference Name, Particular Topic,
+info-file-name, A Printed Manual@}, for details.
+@end group
+@end example
+
+@noindent
+which produces
+
+@example
+*Note Cross Reference Name: (info-file-name)Node name,
+for details.
+@end example
+
+@noindent
+in Info and
+
+@quotation
+See section ``Particular Topic'' in @i{A Printed Manual}, for details.
+@end quotation
+
+@noindent
+in a printed book.
+
+The five possible arguments for a cross reference are:@refill
+
+@enumerate
+@item
+The node name (required). This is the node to which the
+cross reference takes you. In a printed document, the location of the
+node provides the page reference only for references within the same
+document.@refill
+
+@item
+The cross reference name for the Info reference, if it is to be different
+from the node name. If you include this argument, it argument becomes
+the first part of the cross reference. It is usually omitted.@refill
+
+@item
+A topic description or section name. Often, this is the title of the
+section. This is used as the name of the reference in the printed
+manual. If omitted, the node name is used.@refill
+
+@item
+The name of the Info file in which the reference is located, if it is
+different from the current file.@refill
+
+@item
+The name of a printed manual from a different Texinfo file.@refill
+@end enumerate
+
+The template for a full five argument cross reference looks like
+this:@refill
+
+@example
+@group
+@@xref@{@var{node-name}, @var{cross-reference-name}, @var{title-or-topic},
+@var{info-file-name}, @var{printed-manual-title}@}.
+@end group
+@end example
+
+Cross references with one, two, three, four, and five arguments are
+described separately following the description of @code{@@xref}.@refill
+
+Write a node name in a cross reference in exactly the same way as in
+the @code{@@node} line, including the same capitalization; otherwise, the
+formatters may not find the reference.@refill
+
+You can write cross reference commands within a paragraph, but note
+how Info and @TeX{} format the output of each of the various commands:
+write @code{@@xref} at the beginning of a sentence; write
+@code{@@pxref} only within parentheses, and so on.@refill
+
+@node xref, Top Node Naming, Cross Reference Parts, Cross References
+@comment node-name, next, previous, up
+@section @code{@@xref}
+@findex xref
+@cindex Cross references using @code{@@xref}
+@cindex References using @code{@@xref}
+
+The @code{@@xref} command generates a cross reference for the
+beginning of a sentence. The Info formatting commands convert it into
+an Info cross reference, which the Info @samp{f} command can use to
+bring you directly to another node. The @TeX{} typesetting commands
+convert it into a page reference, or a reference to another book or
+manual.@refill
+
+@menu
+* Reference Syntax:: What a reference looks like and requires.
+* One Argument:: @code{@@xref} with one argument.
+* Two Arguments:: @code{@@xref} with two arguments.
+* Three Arguments:: @code{@@xref} with three arguments.
+* Four and Five Arguments:: @code{@@xref} with four and five arguments.
+@end menu
+
+@node Reference Syntax, One Argument, , xref
+@ifinfo
+@subheading What a Reference Looks Like and Requires
+@end ifinfo
+
+Most often, an Info cross reference looks like this:@refill
+
+@example
+*Note @var{node-name}::.
+@end example
+
+@noindent
+or like this
+
+@example
+*Note @var{cross-reference-name}: @var{node-name}.
+@end example
+
+@noindent
+In @TeX{}, a cross reference looks like this:
+
+@example
+See Section @var{section-number} [@var{node-name}], page @var{page}.
+@end example
+
+@noindent
+or like this
+
+@example
+See Section @var{section-number} [@var{title-or-topic}], page @var{page}.
+@end example
+
+The @code{@@xref} command does not generate a period or comma to end
+the cross reference in either the Info file or the printed output.
+You must write that period or comma yourself; otherwise, Info will not
+recognize the end of the reference. (The @code{@@pxref} command works
+differently. @xref{pxref, , @code{@@pxref}}.)@refill
+
+@quotation
+@strong{Please note:} A period or comma @strong{must} follow the closing
+brace of an @code{@@xref}. It is required to terminate the cross
+reference. This period or comma will appear in the output, both in
+the Info file and in the printed manual.@refill
+@end quotation
+
+@code{@@xref} must refer to an Info node by name. Use @code{@@node}
+to define the node (@pxref{Writing a Node}).@refill
+
+@code{@@xref} is followed by several arguments inside braces, separated by
+commas. Whitespace before and after these commas is ignored.@refill
+
+A cross reference requires only the name of a node; but it may contain
+up to four additional arguments. Each of these variations produces a
+cross reference that looks somewhat different.@refill
+
+@quotation
+@strong{Please note:} Commas separate arguments in a cross reference;
+avoid including them in the title or other part lest the formatters
+mistake them for separators.@refill
+@end quotation
+
+@node One Argument, Two Arguments, Reference Syntax, xref
+@subsection @code{@@xref} with One Argument
+
+The simplest form of @code{@@xref} takes one argument, the name of
+another node in the same Info file. The Info formatters produce
+output that the Info readers can use to jump to the reference; @TeX{}
+produces output that specifies the page and section number for you.@refill
+
+@need 700
+@noindent
+For example,
+
+@example
+@@xref@{Tropical Storms@}.
+@end example
+
+@noindent
+produces
+
+@example
+*Note Tropical Storms::.
+@end example
+
+@noindent
+and
+
+@quotation
+See Section 3.1 [Tropical Storms], page 24.
+@end quotation
+
+@noindent
+(Note that in the preceding example the closing brace is followed by a
+period.)@refill
+
+You can write a clause after the cross reference, like this:@refill
+
+@example
+@@xref@{Tropical Storms@}, for more info.
+@end example
+
+@noindent
+which produces
+
+@example
+*Note Tropical Storms::, for more info.
+@end example
+
+@quotation
+See Section 3.1 [Tropical Storms], page 24, for more info.
+@end quotation
+
+@noindent
+(Note that in the preceding example the closing brace is followed by a
+comma, and then by the clause, which is followed by a period.)@refill
+
+@node Two Arguments, Three Arguments, One Argument, xref
+@subsection @code{@@xref} with Two Arguments
+
+With two arguments, the second is used as the name of the Info cross
+reference, while the first is still the name of the node to which the
+cross reference points.@refill
+
+@need 750
+@noindent
+The template is like this:
+
+@example
+@@xref@{@var{node-name}, @var{cross-reference-name}@}.
+@end example
+
+@need 700
+@noindent
+For example,
+
+@example
+@@xref@{Electrical Effects, Lightning@}.
+@end example
+
+@noindent
+produces:
+
+@example
+*Note Lightning: Electrical Effects.
+@end example
+
+@noindent
+and
+
+@quotation
+See Section 5.2 [Electrical Effects], page 57.
+@end quotation
+
+@noindent
+(Note that in the preceding example the closing brace is followed by a
+period; and that the node name is printed, not the cross reference name.)@refill
+
+You can write a clause after the cross reference, like this:@refill
+
+@example
+@@xref@{Electrical Effects, Lightning@}, for more info.
+@end example
+
+@noindent
+which produces
+@example
+*Note Lightning: Electrical Effects, for more info.
+@end example
+
+@noindent
+and
+
+@quotation
+See Section 5.2 [Electrical Effects], page 57, for more info.
+@end quotation
+
+@noindent
+(Note that in the preceding example the closing brace is followed by a
+comma, and then by the clause, which is followed by a period.)@refill
+
+@node Three Arguments, Four and Five Arguments, Two Arguments, xref
+@subsection @code{@@xref} with Three Arguments
+
+A third argument replaces the node name in the @TeX{} output. The third
+argument should be the name of the section in the printed output, or
+else state the topic discussed by that section. Often, you will want to
+use initial upper case letters so it will be easier to read when the
+reference is printed. Use a third argument when the node name is
+unsuitable because of syntax or meaning.@refill
+
+Remember to avoid placing a comma within the title or topic section of
+a cross reference, or within any other section. The formatters divide
+cross references into arguments according to the commas; a comma
+within a title or other section will divide it into two arguments. In
+a reference, you need to write a title such as ``Clouds, Mist, and
+Fog'' without the commas.@refill
+
+Also, remember to write a comma or period after the closing brace of a
+@code{@@xref} to terminate the cross reference. In the following
+examples, a clause follows a terminating comma.@refill
+
+
+@need 750
+@noindent
+The template is like this:
+
+@example
+@group
+@@xref@{@var{node-name}, @var{cross-reference-name}, @var{title-or-topic}@}.
+@end group
+@end example
+
+@need 700
+@noindent
+For example,
+
+@example
+@group
+@@xref@{Electrical Effects, Lightning, Thunder and Lightning@},
+for details.
+@end group
+@end example
+
+@noindent
+produces
+
+@example
+*Note Lightning: Electrical Effects, for details.
+@end example
+
+@noindent
+and
+
+@quotation
+See Section 5.2 [Thunder and Lightning], page 57, for details.
+@end quotation
+
+If a third argument is given and the second one is empty, then the
+third argument serves both. (Note how two commas, side by side, mark
+the empty second argument.)@refill
+
+@example
+@group
+@@xref@{Electrical Effects, , Thunder and Lightning@},
+for details.
+@end group
+@end example
+
+@noindent
+produces
+
+@example
+*Note Thunder and Lightning: Electrical Effects, for details.
+@end example
+
+@noindent
+and
+
+@quotation
+See Section 5.2 [Thunder and Lightning], page 57, for details.
+@end quotation
+
+As a practical matter, it is often best to write cross references with
+just the first argument if the node name and the section title are the
+same, and with the first and third arguments if the node name and title
+are different.@refill
+
+Here are several examples from @cite{The GAWK Manual}:@refill
+
+@smallexample
+@@xref@{Sample Program@}.
+@@xref@{Glossary@}.
+@@xref@{Case-sensitivity, ,Case-sensitivity in Matching@}.
+@@xref@{Close Output, , Closing Output Files and Pipes@},
+ for more information.
+@@xref@{Regexp, , Regular Expressions as Patterns@}.
+@end smallexample
+
+@node Four and Five Arguments, , Three Arguments, xref
+@subsection @code{@@xref} with Four and Five Arguments
+
+In a cross reference, a fourth argument specifies the name of another
+Info file, different from the file in which the reference appears, and
+a fifth argument specifies its title as a printed manual.@refill
+
+Remember that a comma or period must follow the closing brace of an
+@code{@@xref} command to terminate the cross reference. In the
+following examples, a clause follows a terminating comma.@refill
+
+@need 800
+@noindent
+The template is:
+
+@example
+@group
+@@xref@{@var{node-name}, @var{cross-reference-name}, @var{title-or-topic},
+@var{info-file-name}, @var{printed-manual-title}@}.
+@end group
+@end example
+
+@need 700
+@noindent
+For example,
+
+@example
+@@xref@{Electrical Effects, Lightning, Thunder and Lightning,
+weather, An Introduction to Meteorology@}, for details.
+@end example
+
+@noindent
+produces
+
+@example
+*Note Lightning: (weather)Electrical Effects, for details.
+@end example
+
+@noindent
+The name of the Info file is enclosed in parentheses and precedes
+the name of the node.
+
+@noindent
+In a printed manual, the reference looks like this:@refill
+
+@quotation
+See section ``Thunder and Lightning'' in @i{An Introduction to
+Meteorology}, for details.
+@end quotation
+
+@noindent
+The title of the printed manual is typeset in italics; and the
+reference lacks a page number since @TeX{} cannot know to which page a
+reference refers when that reference is to another manual.@refill
+
+Often, you will leave out the second argument when you use the long
+version of @code{@@xref}. In this case, the third argument, the topic
+description, will be used as the cross reference name in Info.@refill
+
+@noindent
+The template looks like this:
+
+@example
+@@xref@{@var{node-name}, , @var{title-or-topic}, @var{info-file-name},
+@var{printed-manual-title}@}, for details.
+@end example
+
+@noindent
+which produces
+
+@example
+*Note @var{title-or-topic}: (@var{info-file-name})@var{node-name}, for details.
+@end example
+
+@noindent
+and
+
+@quotation
+See section @var{title-or-topic} in @var{printed-manual-title}, for details.
+@end quotation
+
+@need 700
+@noindent
+For example,
+
+@example
+@@xref@{Electrical Effects, , Thunder and Lightning,
+weather, An Introduction to Meteorology@}, for details.
+@end example
+
+@noindent
+produces
+
+@example
+@group
+*Note Thunder and Lightning: (weather)Electrical Effects,
+for details.
+@end group
+@end example
+
+@noindent
+and
+
+@quotation
+See section ``Thunder and Lightning'' in @i{An Introduction to
+Meteorology}, for details.
+@end quotation
+
+On rare occasions, you may want to refer to another Info file that
+is within a single printed manual---when multiple Texinfo files are
+incorporated into the same @TeX{} run but make separate Info files.
+In this case, you need to specify only the fourth argument, and not
+the fifth.@refill
+
+@node Top Node Naming, ref, xref, Cross References
+@section Naming a `Top' Node
+@cindex Naming a `Top' Node in references
+@cindex @samp{@r{Top}} node naming for references
+
+In a cross reference, you must always name a node. This means that in
+order to refer to a whole manual, you must identify the `Top' node by
+writing it as the first argument to the @code{@@xref} command. (This
+is different from the way you write a menu entry; see @ref{Other Info
+Files, , Referring to Other Info Files}.) At the same time, to
+provide a meaningful section topic or title in the printed cross
+reference (instead of the word `Top'), you must write an appropriate
+entry for the third argument to the @code{@@xref} command.
+@refill
+
+@noindent
+Thus, to make a cross reference to @cite{The GNU Make Manual},
+write:@refill
+
+@example
+@@xref@{Top, , Overview, make, The GNU Make Manual@}.
+@end example
+
+@noindent
+which produces
+
+@example
+*Note Overview: (make)Top.
+@end example
+
+@noindent
+and
+
+@quotation
+See section ``Overview'' in @i{The GNU Make Manual}.
+@end quotation
+
+@noindent
+In this example, @samp{Top} is the name of the first node, and
+@samp{Overview} is the name of the first section of the manual.@refill
+@node ref, pxref, Top Node Naming, Cross References
+@comment node-name, next, previous, up
+@section @code{@@ref}
+@cindex Cross references using @code{@@ref}
+@cindex References using @code{@@ref}
+@findex ref
+
+@code{@@ref} is nearly the same as @code{@@xref} except that it does
+not generate a `See' in the printed output, just the reference itself.
+This makes it useful as the last part of a sentence.@refill
+
+@need 700
+@noindent
+For example,
+
+@example
+For more information, see @@ref@{Hurricanes@}.
+@end example
+
+@noindent
+produces
+
+@example
+For more information, see *Note Hurricanes.
+@end example
+
+@noindent
+and
+
+@quotation
+For more information, see Section 8.2 [Hurricanes], page 123.
+@end quotation
+
+The @code{@@ref} command sometimes leads writers to express themselves
+in a manner that is suitable for a printed manual but looks awkward
+in the Info format. Bear in mind that your audience will be using
+both the printed and the Info format.@refill
+
+@need 800
+@noindent
+For example,
+
+@example
+@group
+Sea surges are described in @@ref@{Hurricanes@}.
+@end group
+@end example
+
+@need 800
+@noindent
+produces
+
+@quotation
+Sea surges are described in Section 6.7 [Hurricanes], page 72.
+@end quotation
+
+@need 800
+@noindent
+in a printed document, and the following in Info:
+
+@example
+Sea surges are described in *Note Hurricanes::.
+@end example
+
+@quotation
+@strong{Caution:} You @emph{must} write a period or comma immediately
+after an @code{@@ref} command with two or more arguments. Otherwise,
+Info will not find the end of the cross reference entry and its
+attempt to follow the cross reference will fail. As a general rule,
+you should write a period or comma after every @code{@@ref} command.
+This looks best in both the printed and the Info output.@refill
+@end quotation
+
+@node pxref, inforef, ref, Cross References
+@comment node-name, next, previous, up
+@section @code{@@pxref}
+@cindex Cross references using @code{@@pxref}
+@cindex References using @code{@@pxref}
+@findex pxref
+
+The parenthetical reference command, @code{@@pxref}, is nearly the
+same as @code{@@xref}, but you use it @emph{only} inside parentheses
+and you do @emph{not} type a comma or period after the command's
+closing brace. The command differs from @code{@@xref} in two
+ways:@refill
+
+@enumerate
+@item
+@TeX{} typesets the reference for the printed manual with a lower case
+`see' rather than an upper case `See'.@refill
+
+@item
+The Info formatting commands automatically end the reference with a
+closing colon or period.@refill
+@end enumerate
+
+Because one type of formatting automatically inserts closing
+punctuation and the other does not, you should use @code{@@pxref}
+@emph{only} inside parentheses as part of another sentence. Also, you
+yourself should not insert punctuation after the reference, as you do
+with @code{@@xref}.@refill
+
+@code{@@pxref} is designed so that the output looks right and works
+right between parentheses both in printed output and in an Info file.
+In a printed manual, a closing comma or period should not follow a
+cross reference within parentheses; such punctuation is wrong. But in
+an Info file, suitable closing punctuation must follow the cross
+reference so Info can recognize its end. @code{@@pxref} spares you
+the need to use complicated methods to put a terminator into one form
+of the output and not the other.@refill
+
+@noindent
+With one argument, a parenthetical cross reference looks like
+this:@refill
+
+@example
+@dots{} storms cause flooding (@@pxref@{Hurricanes@}) @dots{}
+@end example
+
+@need 800
+@noindent
+which produces
+
+@example
+@group
+@dots{} storms cause flooding (*Note Hurricanes::) @dots{}
+@end group
+@end example
+
+@noindent
+and
+
+@quotation
+@dots{} storms cause flooding (see Section 6.7 [Hurricanes], page 72) @dots{}
+@end quotation
+
+With two arguments, a parenthetical cross reference has this
+template:@refill
+
+@example
+@dots{} (@@pxref@{@var{node-name}, @var{cross-reference-name}@}) @dots{}
+@end example
+
+@noindent
+which produces
+
+@example
+@dots{} (*Note @var{cross-reference-name}: @var{node-name}.) @dots{}
+@end example
+
+@noindent
+and
+
+@need 1500
+@quotation
+@dots{} (see Section @var{nnn} [@var{node-name}], page @var{ppp}) @dots{}
+@end quotation
+
+@code{@@pxref} can be used with up to five arguments just like
+@code{@@xref} (@pxref{xref, , @code{@@xref}}).@refill
+
+@quotation
+@strong{Please note:} Use @code{@@pxref} only as a parenthetical
+reference. Do not try to use @code{@@pxref} as a clause in a sentence.
+It will look bad in either the Info file, the printed output, or
+both.@refill
+
+Also, parenthetical cross references look best at the ends of sentences.
+Although you may write them in the middle of a sentence, that location
+breaks up the flow of text.@refill
+@end quotation
+
+@node inforef, , pxref, Cross References
+@comment node-name, next, previous, up
+@section @code{@@inforef}
+@cindex Cross references using @code{@@inforef}
+@cindex References using @code{@@inforef}
+@findex inforef
+
+@code{@@inforef} is used for cross references to Info files for which
+there are no printed manuals. Even in a printed manual,
+@code{@@inforef} generates a reference directing the user to look in
+an Info file.@refill
+
+The command takes either two or three arguments, in the following
+order:@refill
+
+@enumerate
+@item
+The node name.
+
+@item
+The cross reference name (optional).
+
+@item
+The Info file name.
+@end enumerate
+
+@noindent
+Separate the arguments with commas, as with @code{@@xref}. Also, you
+must terminate the reference with a comma or period after the
+@samp{@}}, as you do with @code{@@xref}.@refill
+
+@noindent
+The template is:
+
+@example
+@@inforef@{@var{node-name}, @var{cross-reference-name}, @var{info-file-name}@},
+@end example
+
+@need 800
+@noindent
+Thus,
+
+@example
+@group
+@@inforef@{Expert, Advanced Info commands, info@},
+for more information.
+@end group
+@end example
+
+@need 800
+@noindent
+produces
+
+@example
+@group
+*Note Advanced Info commands: (info)Expert,
+for more information.
+@end group
+@end example
+
+@need 800
+@noindent
+and
+
+@quotation
+See Info file @file{info}, node @samp{Expert}, for more information.
+@end quotation
+
+@need 800
+@noindent
+Similarly,
+
+@example
+@group
+@@inforef@{Expert, , info@}, for more information.
+@end group
+@end example
+
+@need 800
+@noindent
+produces
+
+@example
+*Note (info)Expert::, for more information.
+@end example
+
+@need 800
+@noindent
+and
+
+@quotation
+See Info file @file{info}, node @samp{Expert}, for more information.
+@end quotation
+
+The converse of @code{@@inforef} is @code{@@cite}, which is used to
+refer to printed works for which no Info form exists. @xref{cite, ,
+@code{@@cite}}.@refill
+
+@node Marking Text, Quotations and Examples, Cross References, Top
+@comment node-name, next, previous, up
+@chapter Marking Words and Phrases
+@cindex Paragraph, marking text within
+@cindex Marking words and phrases
+@cindex Words and phrases, marking them
+@cindex Marking text within a paragraph
+
+In Texinfo, you can mark words and phrases in a variety of ways.
+The Texinfo formatters use this information to determine how to
+highlight the text.
+You can specify, for example, whether a word or phrase is a
+defining occurrence, a metasyntactic variable, or a symbol used in a
+program. Also, you can emphasize text.@refill
+
+@menu
+* Indicating:: How to indicate definitions, files, etc.
+* Emphasis:: How to emphasize text.
+@end menu
+
+@node Indicating, Emphasis, , Marking Text
+@comment node-name, next, previous, up
+@section Indicating Definitions, Commands, etc.
+@cindex Highlighting text
+@cindex Indicating commands, definitions, etc.
+
+Texinfo has commands for indicating just what kind of object a piece of
+text refers to. For example, metasyntactic variables are marked by
+@code{@@var}, and code by @code{@@code}. Since the pieces of text are
+labelled by commands that tell what kind of object they are, it is easy
+to change the way the Texinfo formatters prepare such text. (Texinfo is
+an @emph{intentional} formatting language rather than a @emph{typesetting}
+formatting language.)@refill
+
+For example, in a printed manual,
+code is usually illustrated in a typewriter font;
+@code{@@code} tells @TeX{} to typeset this text in this font. But it
+would be easy to change the way @TeX{} highlights code to use another
+font, and this change would not effect how keystroke examples are
+highlighted. If straight typesetting commands were used in the body
+of the file and you wanted to make a change, you would need to check
+every single occurrence to make sure that you were changing code and
+not something else that should not be changed.@refill
+
+@menu
+* Useful Highlighting:: Highlighting provides useful information.
+* code:: How to indicate code.
+* kbd:: How to show keyboard input.
+* key:: How to specify keys.
+* samp:: How to show a literal sequence of characters.
+* var:: How to indicate a metasyntactic variable.
+* file:: How to indicate the name of a file.
+* dfn:: How to specify a definition.
+* cite:: How to refer to a book that is not in Info.
+@end menu
+
+@node Useful Highlighting, code, , Indicating
+@ifinfo
+@subheading Highlighting Commands are Useful
+@end ifinfo
+
+The highlighting commands can be used to generate useful information
+from the file, such as lists of functions or file names. It is
+possible, for example, to write a program in Emacs Lisp (or a keyboard
+macro) to insert an index entry after every paragraph that contains
+words or phrases marked by a specified command. You could do this to
+construct an index of functions if you had not already made the
+entries.@refill
+
+The commands serve a variety of purposes:@refill
+
+@table @code
+@item @@code@{@var{sample-code}@}
+Indicate text that is a literal example of a piece of a program.@refill
+
+@item @@kbd@{@var{keyboard-characters}@}
+Indicate keyboard input.@refill
+
+@item @@key@{@var{key-name}@}
+Indicate the conventional name for a key on a keyboard.@refill
+
+@item @@samp@{@var{text}@}
+Indicate text that is a literal example of a sequence of characters.@refill
+
+@item @@var@{@var{metasyntactic-variable}@}
+Indicate a metasyntactic variable.@refill
+
+@item @@file@{@var{file-name}@}
+Indicate the name of a file.@refill
+
+@item @@dfn@{@var{term}@}
+Indicate the introductory or defining use of a term.@refill
+
+@item @@cite@{@var{reference}@}
+Indicate the name of a book.@refill
+
+@ignore
+@item @@ctrl@{@var{ctrl-char}@}
+Use for an @sc{ascii} control character.@refill
+@end ignore
+@end table
+
+@node code, kbd, Useful Highlighting, Indicating
+@comment node-name, next, previous, up
+@subsection @code{@@code}@{@var{sample-code}@}
+@findex code
+
+Use the @code{@@code} command to indicate text that is a piece of a
+program and which consists of entire syntactic tokens. Enclose the
+text in braces.@refill
+
+Thus, you should use @code{@@code} for an expression in a program, for
+the name of a variable or function used in a program, or for a
+keyword. Also, you should use @code{@@code} for the name of a
+program, such as @code{diff}, that is a name used in the machine. (You
+should write the name of a program in the ordinary text font if you
+regard it as a new English word, such as `Emacs' or `Bison'.)@refill
+
+Use @code{@@code} for environment variables such as @code{TEXINPUTS},
+and other variables.@refill
+
+Use @code{@@code} for command names in command languages that
+resemble programming languages, such as Texinfo or the shell.
+For example, @code{@@code} and @code{@@samp} are produced by writing
+@samp{@@code@{@@@@code@}} and @samp{@@code@{@@@@samp@}} in the Texinfo
+source, respectively.@refill
+
+Note, however, that you should not use @code{@@code} for shell options
+such as @samp{-c} when such options stand alone. (Use @code{@@samp}.)
+Also, an entire shell command often looks better if written using
+@code{@@samp} rather than @code{@@code}. In this case, the rule is to
+choose the more pleasing format.@refill
+
+It is incorrect to alter the case of a word inside an @code{@@code}
+command when it appears at the beginning of a sentence. Most computer
+languages are case sensitive. In C, for example, @code{Printf} is
+different from the identifier @code{printf}, and most likely is a
+misspelling of it. Even in languages which are not case sensitive, it
+is confusing to a human reader to see identifiers spelled in different
+ways. Pick one spelling and always use that. If you do not want to
+start a sentence with a command written all in lower case, you should
+rearrange the sentence.@refill
+
+Do not use the @code{@@code} command for a string of characters shorter
+than a syntactic token. If you are writing about @samp{TEXINPU}, which
+is just a part of the name for the @code{TEXINPUTS} environment
+variable, you should use @code{@@samp}.@refill
+
+In particular, you should not use the @code{@@code} command when writing
+about the characters used in a token; do not, for example, use
+@code{@@code} when you are explaining what letters or printable symbols
+can be used in the names of functions. (Use @code{@@samp}.) Also, you
+should not use @code{@@code} to mark text that is considered input to
+programs unless the input is written in a language that is like a
+programming language. For example, you should not use @code{@@code} for
+the keystroke commands of GNU Emacs (use @code{@@kbd} instead) although
+you may use @code{@@code} for the names of the Emacs Lisp functions that
+the keystroke commands invoke.@refill
+
+In the printed manual, @code{@@code} causes @TeX{} to typeset the
+argument in a typewriter face. In the Info file, it causes the Info
+formatting commands to use single quotation marks around the text.
+
+@need 700
+For example,
+
+@example
+Use @@code@{diff@} to compare two files.
+@end example
+
+@noindent
+produces this in the printed manual:@refill
+
+@quotation
+Use @code{diff} to compare two files.
+@end quotation
+@iftex
+
+@noindent
+and this in the Info file:@refill
+
+@example
+Use `diff' to compare two files.
+@end example
+@end iftex
+
+@node kbd, key, code, Indicating
+@comment node-name, next, previous, up
+@subsection @code{@@kbd}@{@var{keyboard-characters}@}
+@findex kbd
+
+Use the @code{@@kbd} command for characters of input to be typed by
+users. For example, to refer to the characters @kbd{M-a},
+write@refill
+
+@example
+@@kbd@{M-a@}
+@end example
+
+@noindent
+and to refer to the characters @kbd{M-x shell}, write@refill
+
+@example
+@@kbd@{M-x shell@}
+@end example
+
+The @code{@@kbd} command has the same effect as @code{@@code} in Info,
+but may produce a different font in a printed manual.@refill
+
+You can embed another @@-command inside the braces of an @code{@@kbd}
+command. Here, for example, is the way to describe a command that
+would be described more verbosely as ``press an @samp{r} and then
+press the @key{RET} key'':@refill
+
+@example
+@@kbd@{r @@key@{RET@}@}
+@end example
+
+@noindent
+This produces: @kbd{r @key{RET}}
+
+You also use the @code{@@kbd} command if you are spelling out the letters
+you type; for example:@refill
+
+@example
+To give the @@code@{logout@} command,
+type the characters @@kbd@{l o g o u t @@key@{RET@}@}.
+@end example
+
+@noindent
+This produces:
+
+@quotation
+To give the @code{logout} command,
+type the characters @kbd{l o g o u t @key{RET}}.
+@end quotation
+
+(Also, this example shows that you can add spaces for clarity. If you
+really want to mention a space character as one of the characters of
+input, write @kbd{@@key@{SPC@}} for it.)@refill
+
+@node key, samp, kbd, Indicating
+@comment node-name, next, previous, up
+@subsection @code{@@key}@{@var{key-name}@}
+@findex key
+
+Use the @code{@@key} command for the conventional name for a key on a
+keyboard, as in:@refill
+
+@example
+@@key@{RET@}
+@end example
+
+You can use the @code{@@key} command within the argument of an
+@code{@@kbd} command when the sequence of characters to be typed
+includes one or more keys that are described by name.@refill
+
+@need 700
+For example, to produce @kbd{C-x @key{ESC}} you would type:@refill
+
+@example
+@@kbd@{C-x @@key@{ESC@}@}
+@end example
+
+@c bob: this next sentence looks weird, having a semi-colon followed by
+@c a colon that ends the "sentence".. --mew
+Here is a list of the recommended names for keys; they are all in
+upper case:@refill
+@cindex Recommended names for keys
+@cindex Keys, recommended names
+@cindex Names recommended for keys
+@cindex Abbreviations for keys
+
+@quotation
+@table @t
+@item SPC
+Space
+@item RET
+Return
+@item LFD
+Linefeed
+@item TAB
+Tab
+@item BS
+Backspace
+@item ESC
+Escape
+@item DEL
+Delete
+@item SFT
+Shift
+@item CTL
+Control
+@item META
+Meta
+@end table
+@end quotation
+
+There are subtleties to handling words like `meta' or `ctl' that are
+names of shift keys. When mentioning a character in which the shift
+key is used, such as @kbd{Meta-a}, use the @code{@@kbd} command alone;
+do not use the @code{@@key} command; but when you are referring to the
+shift key in isolation, use the @code{@@key} command. For example,
+write @samp{@@kbd@{Meta-a@}} to produce @kbd{Meta-a} and
+@samp{@@key@{META@}} to produce @key{META}. This is because
+@kbd{Meta-a} refers to keys that you press on a keyboard, but
+@key{META} refers to a key without implying that you press it. In
+short, use @code{@@kbd} for what you do, and use @code{@@key} for what
+you talk about: ``Press @code{@@kbd@{M-a@}} to move point to the
+beginning of the sentence. The @code{@@key@{META@}} key is often in the
+lower left of the keyboard.''@refill
+@cindex META key
+
+@node samp, var, key, Indicating
+@comment node-name, next, previous, up
+@subsection @code{@@samp}@{@var{text}@}
+@findex samp
+
+Use the @code{@@samp} command to indicate text that is a literal example
+or `sample' of a sequence of characters in a file, string, pattern, etc.
+Enclose the text in braces. The argument appears within single
+quotation marks in both the Info file and the printed manual; in
+addition, it is printed in a fixed-width font.@refill
+
+@example
+To match @@samp@{foo@} at the end of the line,
+use the regexp @@samp@{foo$@}.
+@end example
+
+@noindent
+produces
+
+@quotation
+To match @samp{foo} at the end of the line, use the regexp
+@samp{foo$}.@refill
+@end quotation
+
+Any time you are referring to single characters, you should use
+@code{@@samp} unless @code{@@kbd} is more appropriate. Use
+@code{@@samp} for the names of command-line options. Also, you may use
+@code{@@samp} for entire statements in C and for entire shell
+commands---in this case, @code{@@samp} often looks better than
+@code{@@code}. Basically, @code{@@samp} is a catchall for whatever is
+not covered by @code{@@code}, @code{@@kbd}, or @code{@@key}.@refill
+
+Only include punctuation marks within braces if they are part of the
+string you are specifying. Write punctuation marks outside the braces
+if those punctuation marks are part of the English text that surrounds
+the string. In the following sentence, for example, the commas and
+period are outside of the braces:@refill
+
+@example
+@group
+In English, the vowels are @@samp@{a@}, @@samp@{e@},
+@@samp@{i@}, @@samp@{o@}, @@samp@{u@}, and sometimes
+@@samp@{y@}.
+@end group
+@end example
+
+@noindent
+This produces:
+
+@quotation
+In English, the vowels are @samp{a}, @samp{e},
+@samp{i}, @samp{o}, @samp{u}, and sometimes
+@samp{y}.
+@end quotation
+
+@node var, file, samp, Indicating
+@comment node-name, next, previous, up
+@subsection @code{@@var}@{@var{metasyntactic-variable}@}
+@findex var
+
+Use the @code{@@var} command to indicate metasyntactic variables. A
+@dfn{metasyntactic variable} is something that stands for another piece of
+text. For example, you should use a metasyntactic variable in the
+documentation of a function to describe the arguments that are passed
+to that function.@refill
+
+Do not use @code{@@var} for the names of particular variables in
+programming languages. These are specific names from a program, so
+@code{@@code} is correct for them. For example, the Lisp variable
+@code{texinfo-tex-command} is not a metasyntactic variable; it is
+properly formatted using @code{@@code}.@refill
+
+The effect of @code{@@var} in the Info file is to change the case of
+the argument to all upper case; in the printed manual, to italicize it.
+
+@need 700
+For example,
+
+@example
+To delete file @@var@{filename@},
+type @@code@{rm @@var@{filename@}@}.
+@end example
+
+@noindent
+produces
+
+@quotation
+To delete file @var{filename}, type @code{rm @var{filename}}.
+@end quotation
+
+@noindent
+(Note that @code{@@var} may appear inside @code{@@code},
+@code{@@samp}, @code{@@file}, etc.)@refill
+
+Write a metasyntactic variable all in lower case without spaces, and
+use hyphens to make it more readable. Thus, the Texinfo source for
+the illustration of how to begin a Texinfo manual looks like
+this:@refill
+
+@example
+@group
+\input texinfo
+@@@@setfilename @@var@{info-file-name@}
+@@@@settitle @@var@{name-of-manual@}
+@end group
+@end example
+
+@noindent
+This produces:
+
+@example
+@group
+\input texinfo
+@@setfilename @var{info-file-name}
+@@settitle @var{name-of-manual}
+@end group
+@end example
+
+In some documentation styles, metasyntactic variables are shown with
+angle brackets, for example:@refill
+
+@example
+@dots{}, type rm <filename>
+@end example
+
+@noindent
+However, that is not the style that Texinfo uses. (You can, of
+course, modify the sources to @TeX{} and the Info formatting commands
+to output the @code{<@dots{}>} format if you wish.)@refill
+
+@node file, dfn, var, Indicating
+@comment node-name, next, previous, up
+@subsection @code{@@file}@{@var{file-name}@}
+@findex file
+
+Use the @code{@@file} command to indicate text that is the name of a
+file, buffer, or directory, or is the name of a node in Info. You can
+also use the command for file name suffixes. Do not use @code{@@file}
+for symbols in a programming language; use @code{@@code}.
+
+Currently, @code{@@file} is equivalent to @code{@@samp} in its effects.
+For example,@refill
+
+@example
+The @@file@{.el@} files are in
+the @@file@{/usr/local/emacs/lisp@} directory.
+@end example
+
+@noindent
+produces
+
+@quotation
+The @file{.el} files are in
+the @file{/usr/local/emacs/lisp} directory.
+@end quotation
+
+@node dfn, cite, file, Indicating
+@comment node-name, next, previous, up
+@subsection @code{@@dfn}@{@var{term}@}
+@findex dfn
+
+Use the @code{@@dfn} command to identify the introductory or defining
+use of a technical term. Use the command only in passages whose
+purpose is to introduce a term which will be used again or which the
+reader ought to know. Mere passing mention of a term for the first
+time does not deserve @code{@@dfn}. The command generates italics in
+the printed manual, and double quotation marks in the Info file. For
+example:@refill
+
+@example
+Getting rid of a file is called @@dfn@{deleting@} it.
+@end example
+
+@noindent
+produces
+
+@quotation
+Getting rid of a file is called @dfn{deleting} it.
+@end quotation
+
+As a general rule, a sentence containing the defining occurrence of a
+term should be a definition of the term. The sentence does not need
+to say explicitly that it is a definition, but it should contain the
+information of a definition---it should make the meaning clear.
+
+@node cite, , dfn, Indicating
+@comment node-name, next, previous, up
+@subsection @code{@@cite}@{@var{reference}@}
+@findex cite
+
+Use the @code{@@cite} command for the name of a book that lacks a
+companion Info file. The command produces italics in the printed
+manual, and quotation marks in the Info file.@refill
+
+(If a book is written in Texinfo, it is better to use a cross reference
+command since a reader can easily follow such a reference in Info.
+@xref{xref, , @code{@@xref}}.)@refill
+@ignore
+
+@c node ctrl, , cite, Indicating
+@comment node-name, next, previous, up
+@c subsection @code{@@ctrl}@{@var{ctrl-char}@}
+@findex ctrl
+
+The @code{@@ctrl} command is seldom used. It describes an @sc{ascii}
+control character by inserting the actual character into the Info
+file.
+
+Usually, in Texinfo, you talk what you type as keyboard entry by
+describing it with @code{@@kbd}: thus, @samp{@@kbd@{C-a@}} for
+@kbd{C-a}. Use @code{@@kbd} in this way when talking about a control
+character that is typed on the keyboard by the user. When talking
+about a control character appearing in a file or a string, do not use
+@code{@@kbd} since the control character is not typed. Also, do not
+use @samp{C-} but spell out @code{control-}, as in @samp{control-a},
+to make it easier for a reader to understand.@refill
+
+@code{@@ctrl} is an idea from the beginnings of Texinfo which may not
+really fit in to the scheme of things. But there may be times when
+you want to use the command. The pattern is
+@code{@@ctrl@{@var{ch}@}}, where @var{ch} is an @sc{ascii} character
+whose control-equivalent is wanted. For example, to specify
+@samp{control-f}, you would enter@refill
+
+@example
+@@ctrl@{f@}
+@end example
+
+@noindent
+produces
+
+@quotation
+@ctrl{f}
+@end quotation
+
+In the Info file, this generates the specified control character, output
+literally into the file. This is done so a user can copy the specified
+control character (along with whatever else he or she wants) into another
+Emacs buffer and use it. Since the `control-h',`control-i', and
+`control-j' characters are formatting characters, they should not be
+indicated with @code{@@ctrl}.@refill
+
+In a printed manual, @code{@@ctrl} generates text to describe or
+identify that control character: an uparrow followed by the character
+@var{ch}.@refill
+@end ignore
+
+@node Emphasis, , Indicating, Marking Text
+@comment node-name, next, previous, up
+@section Emphasizing Text
+@cindex Emphasizing text
+
+Usually, Texinfo changes the font to mark words in the text according to
+what category the words belong to; an example is the @code{@@code} command.
+Most often, this is the best way to mark words.
+However, sometimes you will want to emphasize text without indicating a
+category. Texinfo has two commands to do this. Also, Texinfo has
+several commands that specify the font in which @TeX{} will typeset
+text. These commands have no affect on Info and only one of them,
+the @code{@@r} command, has any regular use.@refill
+
+@menu
+* emph & strong:: How to emphasize text in Texinfo.
+* Smallcaps:: How to use the small caps font.
+* Fonts:: Various font commands for printed output.
+@end menu
+
+@node emph & strong, Smallcaps, , Emphasis
+@comment node-name, next, previous, up
+@subsection @code{@@emph}@{@var{text}@} and @code{@@strong}@{@var{text}@}
+@cindex Emphasizing text, font for
+@findex emph
+@findex strong
+
+The @code{@@emph} and @code{@@strong} commands are for emphasis;
+@code{@@strong} is stronger. In printed output, @code{@@emph}
+produces @emph{italics} and @code{@@strong} produces
+@strong{bold}.@refill
+
+@need 800
+For example,
+
+@example
+@group
+@@quotation
+@@strong@{Caution:@} @@code@{rm * .[^.]*@} removes @@emph@{all@}
+files in the directory.
+@@end quotation
+@end group
+@end example
+
+@iftex
+@noindent
+produces the following in printed output:
+
+@quotation
+@strong{Caution}: @code{rm * .[^.]*} removes @emph{all}
+files in the directory.
+@end quotation
+
+@noindent
+and the following in Info:
+@end iftex
+@ifinfo
+@noindent
+produces:
+@end ifinfo
+
+@example
+ *Caution*: `rm * .[^.]*' removes *all*
+ files in the directory.
+@end example
+
+The @code{@@strong} command is seldom used except to mark what is, in
+effect, a typographical element, such as the word `Caution' in the
+preceding example.
+
+In the Info file, both @code{@@emph} and @code{@@strong} put asterisks
+around the text.@refill
+
+@quotation
+@strong{Caution:} Do not use @code{@@emph} or @code{@@strong} with the
+word @samp{Note}; Info will mistake the combination for a cross
+reference. Use a phrase such as @strong{Please note} or
+@strong{Caution} instead.@refill
+@end quotation
+
+@node Smallcaps, Fonts, emph & strong, Emphasis
+@subsection @code{@@sc}@{@var{text}@}: The Small Caps Font
+@cindex Small caps font
+@findex sc @r{(small caps font)}
+
+@iftex
+Use the @samp{@@sc} command to set text in the printed output in @sc{a
+small caps font} and set text in the Info file in upper case letters.@refill
+@end iftex
+@ifinfo
+Use the @samp{@@sc} command to set text in the printed output in a
+small caps font and set text in the Info file in upper case letters.@refill
+@end ifinfo
+
+Write the text between braces in lower case, like this:@refill
+
+@example
+The @@sc@{acm@} and @@sc@{ieee@} are technical societies.
+@end example
+
+@noindent
+This produces:
+
+@display
+The @sc{acm} and @sc{ieee} are technical societies.
+@end display
+
+@TeX{} typesets the small caps font in a manner that prevents the
+letters from `jumping out at you on the page'. This makes small caps
+text easier to read than text in all upper case. The Info formatting
+commands set all small caps text in upper case.@refill
+
+@ifinfo
+If the text between the braces of an @code{@@sc} command is upper case,
+@TeX{} typesets in full-size capitals. Use full-size capitals
+sparingly.@refill
+@end ifinfo
+@iftex
+If the text between the braces of an @code{@@sc} command is upper case,
+@TeX{} typesets in @sc{FULL-SIZE CAPITALS}. Use full-size capitals
+sparingly.@refill
+@end iftex
+
+You may also use the small caps font for a jargon word such as
+@sc{ato} (a @sc{nasa} word meaning `abort to orbit').@refill
+
+There are subtleties to using the small caps font with a jargon word
+such as @sc{cdr}, a word used in Lisp programming. In this case, you
+should use the small caps font when the word refers to the second and
+subsequent elements of a list (the @sc{cdr} of the list), but you
+should use @samp{@@code} when the word refers to the Lisp function of
+the same spelling.@refill
+
+@node Fonts, , Smallcaps, Emphasis
+@comment node-name, next, previous, up
+@subsection Fonts for Printing, Not Info
+@cindex Fonts for printing, not for Info
+@findex i @r{(italic font)}
+@findex b @r{(bold font)}
+@findex t @r{(typewriter font)}
+@findex r @r{(Roman font)}
+
+Texinfo provides four font commands that specify font changes in the
+printed manual but have no effect in the Info file. @code{@@i}
+requests @i{italic} font (in some versions of @TeX{}, a slanted font
+is used), @code{@@b} requests @b{bold} face, @code{@@t} requests the
+@t{fixed-width}, typewriter-style font used by @code{@@code}, and @code{@@r} requests a
+@r{roman} font, which is the usual font in which text is printed. All
+four commands apply to an argument that follows, surrounded by
+braces.@refill
+
+Only the @code{@@r} command has much use: in example programs, you
+can use the @code{@@r} command to convert code comments from the
+fixed-width font to a roman font. This looks better in printed
+output.@refill
+
+@need 700
+For example,
+
+@example
+@group
+@@lisp
+(+ 2 2) ; @@r@{Add two plus two.@}
+@@end lisp
+@end group
+@end example
+
+@noindent
+produces
+
+@lisp
+(+ 2 2) ; @r{Add two plus two.}
+@end lisp
+
+If possible, you should avoid using the other three font commands. If
+you need to use one, it probably indicates a gap in the Texinfo
+language.@refill
+
+@node Quotations and Examples, Lists and Tables, Marking Text, Top
+@comment node-name, next, previous, up
+@chapter Quotations and Examples
+
+Quotations and examples are blocks of text consisting of one or more
+whole paragraphs that are set off from the bulk of the text and
+treated differently. They are usually indented.@refill
+
+In Texinfo, you always begin a quotation or example by writing an
+@@-command at the beginning of a line by itself, and end it by writing
+an @code{@@end} command that is also at the beginning of a line by
+itself. For instance, you begin an example by writing @code{@@example}
+by itself at the beginning of a line and end the example by writing
+@code{@@end example} on a line by itself, at the beginning of that
+line.@refill
+@findex end
+
+@menu
+* Block Enclosing Commands:: Use different constructs for
+ different purposes.
+* quotation:: How to write a quotation.
+* example:: How to write an example in a fixed-width font.
+* noindent:: How to prevent paragraph indentation.
+* Lisp Example:: How to illustrate Lisp code.
+* smallexample & smalllisp:: Forms for the @code{@@smallbook} option.
+* display:: How to write an example in the current font.
+* format:: How to write an example that does not narrow
+ the margins.
+* exdent:: How to undo the indentation of a line.
+* flushleft & flushright:: How to push text flushleft or flushright.
+* cartouche:: How to draw cartouches around examples.
+@end menu
+
+@node Block Enclosing Commands, quotation, , Quotations and Examples
+@section The Block Enclosing Commands
+
+Here are commands for quotations and examples:@refill
+
+@table @code
+@item @@quotation
+Indicate text that is quoted. The text is filled, indented, and
+printed in a roman font by default.@refill
+
+@item @@example
+Illustrate code, commands, and the like. The text is printed
+in a fixed-width font, and indented but not filled.@refill
+
+@item @@lisp
+Illustrate Lisp code. The text is printed in a fixed-width font,
+and indented but not filled.@refill
+
+@item @@smallexample
+Illustrate code, commands, and the like. Similar to
+@code{@@example}, except that in @TeX{} this command typesets text in
+a smaller font for the smaller @code{@@smallbook} format than for the
+8.5 by 11 inch format.@refill
+
+@item @@smalllisp
+Illustrate Lisp code. Similar to @code{@@lisp}, except that
+in @TeX{} this command typesets text in a smaller font for the smaller
+@code{@@smallbook} format than for the 8.5 by 11 inch format.@refill
+
+@item @@display
+Display illustrative text. The text is indented but not filled, and
+no font is specified (so, by default, the font is roman).@refill
+
+@item @@format
+Print illustrative text. The text is not indented and not filled
+and no font is specified (so, by default, the font is roman).@refill
+@end table
+
+The @code{@@exdent} command is used within the above constructs to
+undo the indentation of a line.
+
+The @code{@@flushleft} and @code{@@flushright} commands are used to line
+up the left or right margins of unfilled text.@refill
+
+The @code{@@noindent} command may be used after one of the above
+constructs to prevent the following text from being indented as a new
+paragraph.@refill
+
+You can use the @code{@@cartouche} command within one of the above
+constructs to highlight the example or quotation by drawing a box with
+rounded corners around it. (The @code{@@cartouche} command affects
+only the printed manual; it has no effect in the Info file; see
+@ref{cartouche, , Drawing Cartouches Around Examples}.)@refill
+
+@node quotation, example, Block Enclosing Commands, Quotations and Examples
+@comment node-name, next, previous, up
+@section @code{@@quotation}
+@cindex Quotations
+@findex quotation
+
+The text of a quotation is
+processed normally except that:@refill
+
+@itemize @bullet
+@item
+the margins are closer to the center of the page, so the whole of the
+quotation is indented;@refill
+
+@item
+the first lines of paragraphs are indented no more than other
+lines;@refill
+
+@item
+in the printed output, interparagraph spacing is reduced.@refill
+@end itemize
+
+@quotation
+This is an example of text written between an @code{@@quotation}
+command and an @code{@@end quotation} command. An @code{@@quotation}
+command is most often used to indicate text that is excerpted from
+another (real or hypothetical) printed work.@refill
+@end quotation
+
+Write an @code{@@quotation} command as text on a line by itself. This
+line will disappear from the output. Mark the end of the quotation
+with a line beginning with and containing only @code{@@end quotation}.
+The @code{@@end quotation} line will likewise disappear from the
+output. Thus, the following,@refill
+
+@example
+@@quotation
+This is
+a foo.
+@@end quotation
+@end example
+
+@noindent
+produces
+
+@quotation
+This is a foo.
+@end quotation
+
+@node example, noindent, quotation, Quotations and Examples
+@comment node-name, next, previous, up
+@section @code{@@example}
+@cindex Examples, formatting them
+@cindex Formatting examples
+@findex example
+
+The @code{@@example} command is used to indicate an example that is
+not part of the running text, such as computer input or output.@refill
+
+@example
+@group
+This is an example of text written between an
+@code{@@example} command
+and an @code{@@end example} command.
+The text is indented but not filled.
+@end group
+
+@group
+In the printed manual, the text is typeset in a
+fixed-width font, and extra spaces and blank lines are
+significant. In the Info file, an analogous result is
+obtained by indenting each line with five spaces.
+@end group
+@end example
+
+Write an @code{@@example} command at the beginning of a line by itself.
+This line will disappear from the output. Mark the end of the example
+with an @code{@@end example} command, also written at the beginning of a
+line by itself. The @code{@@end example} will disappear from the
+output.@refill
+
+@need 700
+For example,
+
+@example
+@@example
+mv foo bar
+@@end example
+@end example
+
+@noindent
+produces
+
+@example
+mv foo bar
+@end example
+
+Since the lines containing @code{@@example} and @code{@@end example}
+will disappear, you should put a blank line before the
+@code{@@example} and another blank line after the @code{@@end
+example}. (Remember that blank lines between the beginning
+@code{@@example} and the ending @code{@@end example} will appear in
+the output.)@refill
+
+@quotation
+@strong{Caution:} Do not use tabs in the lines of an example (or anywhere
+else in Texinfo, for that matter)! @TeX{} treats tabs as single
+spaces, and that is not what they look like. This is a problem with
+@TeX{}. (If necessary, in Emacs, you can use @kbd{M-x untabify} to
+convert tabs in a region to multiple spaces.)@refill
+@end quotation
+
+Examples are often, logically speaking, ``in the middle'' of a
+paragraph, and the text continues after an example should not be
+indented. The @code{@@noindent} command prevents a piece of text from
+being indented as if it were a new paragraph.
+@ifinfo
+(@xref{noindent}.)
+@end ifinfo
+
+(The @code{@@code} command is used for examples of code that are
+embedded within sentences, not set off from preceding and following
+text. @xref{code, , @code{@@code}}.)
+
+@node noindent, Lisp Example, example, Quotations and Examples
+@comment node-name, next, previous, up
+@section @code{@@noindent}
+@findex noindent
+
+An example or other inclusion can break a paragraph into segments.
+Ordinarily, the formatters indent text that follows an example as a new
+paragraph. However, you can prevent this by writing @code{@@noindent}
+at the beginning of a line by itself preceding the continuation
+text.@refill
+
+@need 750
+For example:
+
+@example
+@group
+@@example
+This is an example
+@@end example
+
+@@noindent
+This line is not indented. As you can see, the
+beginning of the line is fully flush left with the line
+that follows after it. (This whole example is between
+@@code@{@@@@display@} and @@code@{@@@@end display@}.)
+@end group
+@end example
+
+@noindent
+produces
+
+@display
+@example
+This is an example
+@end example
+@tex
+% Remove extra vskip; this is a kludge to counter the effect of display
+\vskip-3.5\baselineskip
+@end tex
+
+@noindent
+This line is not indented. As you can see, the
+beginning of the line is fully flush left with the line
+that follows after it. (This whole example is between
+@code{@@display} and @code{@@end display}.)
+@end display
+
+To adjust the number of blank lines properly in the Info file output,
+remember that the line containing @code{@@noindent} does not generate a
+blank line, and neither does the @code{@@end example} line.@refill
+
+In the Texinfo source file for this manual, each line that says
+`produces' is preceded by a line containing @code{@@noindent}.@refill
+
+Do not put braces after an @code{@@noindent} command; they are not
+necessary, since @code{@@noindent} is a command used outside of
+paragraphs (@pxref{Command Syntax}).@refill
+
+@node Lisp Example, smallexample & smalllisp, noindent, Quotations and Examples
+@comment node-name, next, previous, up
+@section @code{@@lisp}
+@cindex Lisp example
+@findex lisp
+
+The @code{@@lisp} command is used for Lisp code. It is synonymous
+with the @code{@@example} command.
+
+@lisp
+This is an example of text written between an
+@code{@@lisp} command and an @code{@@end lisp} command.
+@end lisp
+
+Use @code{@@lisp} instead of @code{@@example} so as to preserve
+information regarding the nature of the example. This is useful, for
+example, if you write a function that evaluates only and all the Lisp
+code in a Texinfo file. Then you can use the Texinfo file as a Lisp
+library.@footnote{It would be straightforward to extend Texinfo to
+work in a similar fashion for C, @sc{fortran}, or other languages.}@refill
+
+Mark the end of @code{@@lisp} with @code{@@end lisp} on a line by
+itself.@refill
+
+@node smallexample & smalllisp, display, Lisp Example, Quotations and Examples
+@comment node-name, next, previous, up
+@section @code{@@smallexample} and @code{@@smalllisp}
+@cindex Small book example
+@cindex Example for a small book
+@cindex Lisp example for a small book
+@findex smallexample
+@findex smalllisp
+
+In addition to the regular @code{@@example} and @code{@@lisp} commands,
+Texinfo has two other ``example-style'' commands. These are the
+@code{@@smallexample} and @code{@@smalllisp} commands. Both these
+commands are designed for use with the @code{@@smallbook} command that
+causes @TeX{} to produce a printed manual in a 7 by 9.25 inch format
+rather than the regular 8.5 by 11 inch format.@refill
+
+In @TeX{}, the @code{@@smallexample} and @code{@@smalllisp} commands
+typeset text in a smaller font for the smaller @code{@@smallbook}
+format than for the 8.5 by 11 inch format. Consequently, many examples
+containing long lines fit in a narrower, @code{@@smallbook} page
+without needing to be shortened. Both commands typeset in the normal
+font size when you format for the 8.5 by 11 inch size; indeed,
+in this situation, the @code{@@smallexample} and @code{@@smalllisp}
+commands are defined to be the @code{@@example} and @code{@@lisp}
+commands.@refill
+
+In Info, the @code{@@smallexample} and @code{@@smalllisp} commands are
+equivalent to the @code{@@example} and @code{@@lisp} commands, and work
+exactly the same.@refill
+
+Mark the end of @code{@@smallexample} or @code{@@smalllisp} with
+@code{@@end smallexample} or @code{@@end smalllisp},
+respectively.@refill
+
+@iftex
+Here is an example written in the small font used by the
+@code{@@smallexample} and @code{@@smalllisp} commands:
+
+@ifclear smallbook
+@display
+@tex
+% Remove extra vskip; this is a kludge to counter the effect of display
+\vskip-3\baselineskip
+{\ninett
+\dots{} to make sure that you have the freedom to
+distribute copies of free software (and charge for
+this service if you wish), that you receive source
+code or can get it if you want it, that you can
+change the software or use pieces of it in new free
+programs; and that you know you can do these things.}
+@end tex
+@end display
+@end ifclear
+@end iftex
+@ifset smallbook
+@iftex
+@smallexample
+This is an example of text written between @code{@@smallexample} and
+@code{@@end smallexample}. In Info and in an 8.5 by 11 inch manual,
+this text appears in its normal size; but in a 7 by 9.25 inch manual,
+this text appears in a smaller font.
+@end smallexample
+@end iftex
+@end ifset
+@ifinfo
+@smallexample
+This is an example of text written between @code{@@smallexample} and
+@code{@@end smallexample}. In Info and in an 8.5 by 11 inch manual,
+this text appears in its normal size; but in a 7 by 9.25 inch manual,
+this text appears in a smaller font.
+@end smallexample
+@end ifinfo
+
+The @code{@@smallexample} and @code{@@smalllisp} commands make it
+easier to prepare smaller format manuals without forcing you to edit
+examples by hand to fit them onto narrower pages.@refill
+
+As a general rule, a printed document looks better if you write all the
+examples in a chapter consistently in @code{@@example} or in
+@code{@@smallexample}. Only occasionally should you mix the two
+formats.@refill
+
+@xref{smallbook, , Printing ``Small'' Books}, for more information
+about the @code{@@smallbook} command.@refill
+
+@node display, format, smallexample & smalllisp, Quotations and Examples
+@comment node-name, next, previous, up
+@section @code{@@display}
+@cindex Display formatting
+@findex display
+
+The @code{@@display} command begins a kind of example. It is like the
+@code{@@example} command
+except that, in
+a printed manual, @code{@@display} does not select the fixed-width
+font. In fact, it does not specify the font at all, so that the text
+appears in the same font it would have appeared in without the
+@code{@@display} command.@refill
+
+@display
+This is an example of text written between an @code{@@display} command
+and an @code{@@end display} command. The @code{@@display} command
+indents the text, but does not fill it.
+@end display
+
+@node format, exdent, display, Quotations and Examples
+@comment node-name, next, previous, up
+@section @code{@@format}
+@findex format
+
+The @code{@@format} command is similar to @code{@@example} except
+that, in the printed manual, @code{@@format} does not select the
+fixed-width font and does not narrow the margins.@refill
+
+@format
+This is an example of text written between an @code{@@format} command
+and an @code{@@end format} command. As you can see
+from this example,
+the @code{@@format} command does not fill the text.
+@end format
+
+@node exdent, flushleft & flushright, format, Quotations and Examples
+@section @code{@@exdent}: Undoing a Line's Indentation
+@cindex Indentation undoing
+@findex exdent
+
+The @code{@@exdent} command removes any indentation a line might have.
+The command is written at the beginning of a line and applies only to
+the text that follows the command that is on the same line. Do not use
+braces around the text. In a printed manual, the text on an
+@code{@@exdent} line is printed in the roman font.@refill
+
+@code{@@exdent} is usually used within examples. Thus,@refill
+
+@example
+@group
+@@example
+This line follows an @@@@example command.
+@@exdent This line is exdented.
+This line follows the exdented line.
+The @@@@end example comes on the next line.
+@@end group
+@end group
+@end example
+
+@noindent
+produces
+
+@example
+@group
+This line follows an @@example command.
+@exdent This line is exdented.
+This line follows the exdented line.
+The @@end example comes on the next line.
+@end group
+@end example
+
+In practice, the @code{@@exdent} command is rarely used.
+Usually, you un-indent text by ending the example and
+returning the page to its normal width.@refill
+
+@node flushleft & flushright, cartouche, exdent, Quotations and Examples
+@section @code{@@flushleft} and @code{@@flushright}
+@findex flushleft
+@findex flushright
+
+The @code{@@flushleft} and @code{@@flushright} commands line up the
+ends of lines on the left and right margins of a page,
+but do not fill the text. The commands are written on lines of their
+own, without braces. The @code{@@flushleft} and @code{@@flushright}
+commands are ended by @code{@@end flushleft} and @code{@@end
+flushright} commands on lines of their own.@refill
+
+@need 800
+For example,
+
+@example
+@group
+@@flushleft
+This text is
+written flushleft.
+@@end flushleft
+@end group
+@end example
+
+@noindent
+produces
+
+@quotation
+@flushleft
+This text is
+written flushleft.
+@end flushleft
+@end quotation
+
+
+Flushright produces the type of indentation often used in the return
+address of letters.@refill
+
+@need 800
+@noindent
+For example,
+
+@example
+@group
+@@flushright
+Here is an example of text written
+flushright. The @@code@{@@flushright@} command
+right justifies every line but leaves the
+left end ragged.
+@@end flushright
+@end group
+@end example
+
+@noindent
+produces
+
+@flushright
+Here is an example of text written
+flushright. The @code{@@flushright} command
+right justifies every line but leaves the
+left end ragged.
+@end flushright
+
+@node cartouche, , flushleft & flushright, Quotations and Examples
+@section Drawing Cartouches Around Examples
+@findex cartouche
+@cindex Box with rounded corners
+
+In a printed manual, the @code{@@cartouche} command draws a box with
+rounded corners around its contents. You can use this command to
+further highlight an example or quotation. For instance, you could
+write a manual in which one type of example is surrounded by a cartouche
+for emphasis.@refill
+
+The @code{@@cartouche} command affects only the printed manual; it has
+no effect in the Info file.@refill
+
+@need 1500
+For example,
+
+@example
+@group
+@@example
+@@cartouche
+% pwd
+/usr/local/lib/emacs/info
+@@end cartouche
+@@end example
+@end group
+@end example
+
+@noindent
+surrounds the two-line example with a box with rounded corners, in the
+printed manual.
+
+@iftex
+In a printed manual, the example looks like this:@refill
+
+@example
+@group
+@cartouche
+% pwd
+/usr/local/lib/emacs/info
+@end cartouche
+@end group
+@end example
+@end iftex
+
+@node Lists and Tables, Indices, Quotations and Examples, Top
+@comment node-name, next, previous, up
+@chapter Making Lists and Tables
+@cindex Making lists and tables
+@cindex Lists and tables, making them
+@cindex Tables and lists, making them
+
+Texinfo has several ways of making lists and two-column tables. Lists can
+be bulleted or numbered, while two-column tables can highlight the items in
+the first column.@refill
+
+@menu
+* Introducing Lists:: Texinfo formats lists for you.
+* itemize:: How to construct a simple list.
+* enumerate:: How to construct a numbered list.
+* Two-column Tables:: How to construct a two-column table.
+@end menu
+
+@ifinfo
+@node Introducing Lists, itemize, , Lists and Tables
+@heading Introducing Lists
+@end ifinfo
+
+Texinfo automatically indents the text in lists or tables, and numbers
+an enumerated list. This last feature is useful if you modify the
+list, since you do not need to renumber it yourself.@refill
+
+Numbered lists and tables begin with the appropriate @@-command at the
+beginning of a line, and end with the corresponding @code{@@end}
+command on a line by itself. The table and itemized-list commands
+also require that you write formatting information on the same line as
+the beginning @@-command.@refill
+
+Begin an enumerated list, for example, with an @code{@@enumerate}
+command and end the list with an @code{@@end enumerate} command.
+Begin an itemized list with an @code{@@itemize} command, followed on
+the same line by a formatting command such as @code{@@bullet}, and end
+the list with an @code{@@end itemize} command.@refill
+@findex end
+
+Precede each element of a list with an @code{@@item} or @code{@@itemx}
+command.@refill
+
+@sp 1
+@noindent
+Here is an itemized list of the different kinds of table and lists:@refill
+
+@itemize @bullet
+@item
+Itemized lists with and without bullets.
+
+@item
+Enumerated lists, using numbers or letters.
+
+@item
+Two-column tables with highlighting.
+@end itemize
+
+@sp 1
+@noindent
+Here is an enumerated list with the same items:@refill
+
+@enumerate
+@item
+Itemized lists with and without bullets.
+
+@item
+Enumerated lists, using numbers or letters.
+
+@item
+Two-column tables with highlighting.
+@end enumerate
+
+@sp 1
+@noindent
+And here is a two-column table with the same items and their
+@w{@@-commands}:@refill
+
+@table @code
+@item @@itemize
+Itemized lists with and without bullets.
+
+@item @@enumerate
+Enumerated lists, using numbers or letters.
+
+@item @@table
+@itemx @@ftable
+@itemx @@vtable
+Two-column tables with highlighting.
+@end table
+
+@node itemize, enumerate, Introducing Lists, Lists and Tables
+@comment node-name, next, previous, up
+@section Making an Itemized List
+@cindex Itemization
+@findex itemize
+
+The @code{@@itemize} command produces sequences of indented
+paragraphs, with a bullet or other mark inside the left margin
+at the beginning of each paragraph for which such a mark is desired.@refill
+
+Begin an itemized list by writing @code{@@itemize} at the beginning of
+a line. Follow the command, on the same line, with a character or a
+Texinfo command that generates a mark. Usually, you will write
+@code{@@bullet} after @code{@@itemize}, but you can use
+@code{@@minus}, or any character or any special symbol that results in
+a single character in the Info file. (When you write @code{@@bullet}
+or @code{@@minus} after an @code{@@itemize} command, you may omit the
+@samp{@{@}}.)@refill
+
+Write the text of the indented paragraphs themselves after the
+@code{@@itemize}, up to another line that says @code{@@end
+itemize}.@refill
+
+Before each paragraph for which a mark in the margin is desired, write
+a line that says just @code{@@item}. Do not write any other text on this
+line.@refill
+@findex item
+
+Usually, you should put a blank line before an @code{@@item}. This
+puts a blank line in the Info file. (@TeX{} inserts the proper
+interline whitespace in either case.) Except when the entries are
+very brief, these blank lines make the list look better.@refill
+
+Here is an example of the use of @code{@@itemize}, followed by the
+output it produces. Note that @code{@@bullet} produces an @samp{*} in
+Info and a round dot in @TeX{}.@refill
+
+@example
+@group
+@@itemize @@bullet
+@@item
+Some text for foo.
+
+@@item
+Some text
+for bar.
+@@end itemize
+@end group
+@end example
+
+@noindent
+This produces:
+
+@quotation
+@itemize @bullet
+@item
+Some text for foo.
+
+@item
+Some text
+for bar.
+@end itemize
+@end quotation
+
+Itemized lists may be embedded within other itemized lists. Here is a
+list marked with dashes embedded in a list marked with bullets:@refill
+
+@example
+@group
+@@itemize @@bullet
+@@item
+First item.
+
+@@itemize @@minus
+@@item
+Inner item.
+
+@@item
+Second inner item.
+@@end itemize
+
+@@item
+Second outer item.
+@@end itemize
+@end group
+@end example
+
+@noindent
+This produces:
+
+@quotation
+@itemize @bullet
+@item
+First item.
+
+@itemize @minus
+@item
+Inner item.
+
+@item
+Second inner item.
+@end itemize
+
+@item
+Second outer item.
+@end itemize
+@end quotation
+
+@node enumerate, Two-column Tables, itemize, Lists and Tables
+@comment node-name, next, previous, up
+@section Making a Numbered or Lettered List
+@cindex Enumeration
+@findex enumerate
+
+@code{@@enumerate} is like @code{@@itemize} except that the marks in
+the left margin contain successive integers or letters.
+(@xref{itemize, , @code{@@itemize}}.)@refill
+
+Write the @code{@@enumerate} command at the beginning of a line.
+The command does not require an argument, but accepts either a number or
+a letter as an option.
+Without an argument, @code{@@enumerate} starts the list
+with the number 1. With a numeric argument, such as 3,
+the command starts the list with that number.
+With an upper or lower case letter, such as @kbd{a} or @kbd{A},
+the command starts the list with that letter.@refill
+
+Write the text of the enumerated list in the same way you write an
+itemized list: put @code{@@item} on a line of its own before the start of
+each paragraph that you want enumerated. Do not write any other text on
+the line beginning with @code{@@item}.@refill
+
+You should put a blank line between entries in the list.
+This generally makes it easier to read the Info file.@refill
+
+@need 1500
+Here is an example of @code{@@enumerate} without an argument:@refill
+
+@example
+@group
+@@enumerate
+@@item
+Underlying causes.
+
+@@item
+Proximate causes.
+@@end enumerate
+@end group
+@end example
+
+@noindent
+This produces:
+
+@enumerate
+@item
+Underlying causes.
+
+@item
+Proximate causes.
+@end enumerate
+@sp 1
+Here is an example with an argument of @kbd{3}:@refill
+@sp 1
+@example
+@group
+@@enumerate 3
+@@item
+Predisposing causes.
+
+@@item
+Precipitating causes.
+
+@@item
+Perpetuating causes.
+@@end enumerate
+@end group
+@end example
+
+@noindent
+This produces:
+
+@enumerate 3
+@item
+Predisposing causes.
+
+@item
+Precipitating causes.
+
+@item
+Perpetuating causes.
+@end enumerate
+@sp 1
+Here is a brief summary of the alternatives. The summary is constructed
+using @code{@@enumerate} with an argument of @kbd{a}.@refill
+@sp 1
+@enumerate a
+@item
+@code{@@enumerate}
+
+Without an argument, produce a numbered list, starting with the number
+1.@refill
+
+@item
+@code{@@enumerate @var{positive-integer}}
+
+With a (positive) numeric argument, start a numbered list with that
+number. You can use this to continue a list that you interrupted with
+other text.@refill
+
+@item
+@code{@@enumerate @var{upper-case-letter}}
+
+With an upper case letter as argument, start a list
+in which each item is marked
+by a letter, beginning with that upper case letter.@refill
+
+@item
+@code{@@enumerate @var{lower-case-letter}}
+
+With a lower case letter as argument, start a list
+in which each item is marked by
+a letter, beginning with that lower case letter.@refill
+@end enumerate
+
+You can also nest enumerated lists, as in an outline.@refill
+
+@node Two-column Tables, , enumerate, Lists and Tables
+@comment node-name, next, previous, up
+@section Making a Two-column Table
+@cindex Tables, making two-column
+@findex table
+
+@code{@@table} is similar to @code{@@itemize}, but the command allows
+you to specify a name or heading line for each item. (@xref{itemize,
+, @code{@@itemize}}.) The @code{@@table} command is used to produce
+two-column tables, and is especially useful for glossaries and
+explanatory exhibits.@refill
+
+@menu
+* table:: How to construct a two-column table.
+* ftable vtable:: How to construct a two-column table
+ with automatic indexing.
+* itemx:: How to put more entries in the first column.
+@end menu
+
+@ifinfo
+@node table, ftable vtable, , Two-column Tables
+@subheading Using the @code{@@table} Command
+
+Use the @code{@@table} command to produce two-column tables.@refill
+@end ifinfo
+
+Write the @code{@@table} command at the beginning of a line and follow
+it on the same line with an argument that is a Texinfo command such as
+@code{@@code}, @code{@@samp}, @code{@@var}, or @code{@@kbd}.
+Although these commands are usually followed by arguments in braces,
+in this case you use the command name without an argument because
+@code{@@item} will supply the argument. This command will be applied
+to the text that goes into the first column of each item and
+determines how it will be highlighted. For example, @code{@@samp}
+will cause the text in the first column to be highlighted with an
+@code{@@samp} command.@refill
+
+You may also choose to use the @code{@@asis} command as an argument to
+@code{@@table}. @code{@@asis} is a command that does nothing; if you use this
+command after @code{@@table}, @TeX{} and the Info formatting commands
+output the first column entries without added highlighting (`as
+is').@refill
+
+(The @code{@@table} command may work with other commands besides those
+listed here. However, you can only use commands
+that normally take arguments in braces.)@refill
+
+Begin each table entry with an @code{@@item} command at the beginning
+of a line. Write the first column text on the same line as the
+@code{@@item} command. Write the second column text on the line
+following the @code{@@item} line and on subsequent lines. (You do not
+need to type anything for an empty second column entry.) You may
+write as many lines of supporting text as you wish, even several
+paragraphs. But only text on the same line as the @code{@@item} will
+be placed in the first column.@refill
+@findex item
+
+Normally, you should put a blank line before an @code{@@item} line.
+This puts a blank like in the Info file. Except when the entries are
+very brief, a blank line looks better.@refill
+
+@need 1500
+The following table, for example, highlights the text in the first
+column with an @code{@@samp} command:@refill
+
+@example
+@group
+@@table @@samp
+@@item foo
+This is the text for
+@@samp@{foo@}.
+
+@@item bar
+Text for @@samp@{bar@}.
+@@end table
+@end group
+@end example
+
+@noindent
+This produces:
+
+@table @samp
+@item foo
+This is the text for
+@samp{foo}.
+@item bar
+Text for @samp{bar}.
+@end table
+
+If you want to list two or more named items with a single block of
+text, use the @code{@@itemx} command. (@xref{itemx, ,
+@code{@@itemx}}.)@refill
+
+@node ftable vtable, itemx, table, Two-column Tables
+@comment node-name, next, previous, up
+@subsection @code{@@ftable} and @code{@@vtable}
+@cindex Tables with indexes
+@cindex Indexing table entries automatically
+@findex ftable
+@findex vtable
+
+The @code{@@ftable} and @code{@@vtable} commands are the same as the
+@code{@@table} command except that @code{@@ftable} automatically enters
+each of the items in the first column of the table into the index of
+functions and @code{@@vtable} automatically enters each of the items in
+the first column of the table into the index of variables. This
+simplifies the task of creating indices. Only the items on the same
+line as the @code{@@item} commands are indexed, and they are indexed in
+exactly the form that they appear on that line. @xref{Indices, ,
+Creating Indices}, for more information about indices.@refill
+
+Begin a two-column table using @code{@@ftable} or @code{@@vtable} by
+writing the @@-command at the beginning of a line, followed on the same
+line by an argument that is a Texinfo command such as @code{@@code},
+exactly as you would for an @code{@@table} command; and end the table
+with an @code{@@end ftable} or @code{@@end vtable} command on a line by
+itself.
+
+@node itemx, , ftable vtable, Two-column Tables
+@comment node-name, next, previous, up
+@subsection @code{@@itemx}
+@cindex Two named items for @code{@@table}
+@findex itemx
+
+Use the @code{@@itemx} command inside a table when you have two or
+more first column entries for the same item, each of which should
+appear on a line of its own. Use @code{@@itemx} for all but the first
+entry. The @code{@@itemx} command works exactly like @code{@@item}
+except that it does not generate extra vertical space above the first
+column text.@refill
+
+@need 1000
+For example,
+
+@example
+@group
+@@table @@code
+@@item upcase
+@@itemx downcase
+These two functions accept a character or a string as
+argument, and return the corresponding upper case (lower
+case) character or string.
+@@end table
+@end group
+@end example
+
+@noindent
+This produces:
+
+@table @code
+@item upcase
+@itemx downcase
+These two functions accept a character or a string as
+argument, and return the corresponding upper case (lower
+case) character or string.@refill
+@end table
+
+@noindent
+(Note also that this example illustrates multi-line supporting text in
+a two-column table.)@refill
+
+@node Indices, Insertions, Lists and Tables, Top
+@comment node-name, next, previous, up
+@chapter Creating Indices
+@cindex Indices
+@cindex Creating indices
+
+Using Texinfo, you can generate indices without having to sort and
+collate entries manually. In an index, the entries are listed in
+alphabetical order, together with information on how to find the
+discussion of each entry. In a printed manual, this information
+consists of page numbers. In an Info file, this information is a menu
+entry leading to the first node referenced.@refill
+
+Texinfo provides several predefined kinds of index: an index
+for functions, an index for variables, an index for concepts, and so
+on. You can combine indices or use them for other than their
+canonical purpose. If you wish, you can define your own indices.@refill
+
+@menu
+* Index Entries:: Choose different words for index entries.
+* Predefined Indices:: Use different indices for different kinds
+ of entry.
+* Indexing Commands:: How to make an index entry.
+* Combining Indices:: How to combine indices.
+* New Indices:: How to define your own indices.
+@end menu
+
+@node Index Entries, Predefined Indices, , Indices
+@comment node-name, next, previous, up
+@section Making Index Entries
+@cindex Index entries, making
+@cindex Entries, making index
+
+When you are making index entries, it is good practice to think of the
+different ways people may look for something. Different people
+@emph{do not} think of the same words when they look something up. A
+helpful index will have items indexed under all the different words
+that people may use. For example, one reader may think it obvious that
+the two-letter names for indices should be listed under ``Indices,
+two-letter names'', since the word ``Index'' is the general concept.
+But another reader may remember the specific concept of two-letter
+names and search for the entry listed as ``Two letter names for
+indices''. A good index will have both entries and will help both
+readers.@refill
+
+Like typesetting, the construction of an index is a highly skilled,
+professional art, the subtleties of which are not appreciated until you
+need to do it yourself.@refill
+
+@xref{Printing Indices & Menus}, for information about printing an index
+at the end of a book or creating an index menu in an Info file.@refill
+
+@node Predefined Indices, Indexing Commands, Index Entries, Indices
+@comment node-name, next, previous, up
+@section Predefined Indices
+
+Texinfo provides six predefined indices:@refill
+
+@itemize @bullet
+@item
+A @dfn{concept index} listing concepts that are discussed.@refill
+
+@item
+A @dfn{function index} listing functions (such as entry points of
+libraries).@refill
+
+@item
+A @dfn{variables index} listing variables (such as global variables
+of libraries).@refill
+
+@item
+A @dfn{keystroke index} listing keyboard commands.@refill
+
+@item
+A @dfn{program index} listing names of programs.@refill
+
+@item
+A @dfn{data type index} listing data types (such as structures defined in
+header files).@refill
+@end itemize
+
+@noindent
+Not every manual needs all of these, and most manuals use two or three
+of them. This manual has two indices: a
+concept index and an @@-command index (that is actually the function
+index but is called a command index in the chapter heading). Two or
+more indices can be combined into one using the @code{@@synindex} or
+@code{@@syncodeindex} commands. @xref{Combining Indices}.@refill
+
+@node Indexing Commands, Combining Indices, Predefined Indices, Indices
+@comment node-name, next, previous, up
+@section Defining the Entries of an Index
+@cindex Defining indexing entries
+@cindex Index entries
+@cindex Entries for an index
+@cindex Specifying index entries
+@cindex Creating index entries
+
+The data to make an index come from many individual indexing commands
+scattered throughout the Texinfo source file. Each command says to add
+one entry to a particular index; after formatting, the index will give
+the current page number or node name as the reference.@refill
+
+An index entry consists of an indexing command at the beginning of a
+line followed, on the rest of the line, by the entry.@refill
+
+For example, this section begins with the following five entries for
+the concept index:@refill
+
+@example
+@@cindex Defining indexing entries
+@@cindex Index entries
+@@cindex Entries for an index
+@@cindex Specifying index entries
+@@cindex Creating index entries
+@end example
+
+Each predefined index has its own indexing command---@code{@@cindex}
+for the concept index, @code{@@findex} for the function index, and so
+on.@refill
+
+@cindex Capitalizing index entries
+@cindex Index entry capitalization
+The usual convention is to capitalize the first word of each index
+entry, unless that word is the name of a function, variable, or other
+such entity that should not be capitalized. Thus, if you are
+documenting Emacs Lisp, you should usually capitalize entries in
+the concept index, but not those in the function index.
+However, if your
+concept index entries are consistently short (one or two words each)
+it may look better for each regular entry to start with a lower case
+letter. Whichever convention you adapt, please be consistent!
+
+By default, entries for a concept index are printed in a small roman
+font and entries for the other indices are printed in a small
+@code{@@code} font. You may change the way part of an entry is
+printed with the usual Texinfo commands, such as @code{@@file} for
+file names and @code{@@emph} for emphasis (@pxref{Marking
+Text}).@refill
+@cindex Index font types
+
+@cindex Predefined indexing commands
+@cindex Indexing commands, predefined
+The six indexing commands for predefined indices are:
+
+@table @code
+@item @@cindex @var{concept}
+@findex cindex
+Make an entry in the concept index for @var{concept}.@refill
+
+@item @@findex @var{function}
+@findex findex
+Make an entry in the function index for @var{function}.@refill
+
+@item @@vindex @var{variable}
+@findex vindex
+Make an entry in the variable index for @var{variable}.@refill
+
+@item @@kindex @var{keystroke}
+@findex kindex
+Make an entry in the key index for @var{keystroke}.@refill
+
+@item @@pindex @var{program}
+@findex pindex
+Make an entry in the program index for @var{program}.@refill
+
+@item @@tindex @var{data type}
+@findex tindex
+Make an entry in the data type index for @var{data type}.@refill
+@end table
+
+@quotation
+@strong{Caution:} Do not use a colon in an index entry. In Info, a
+colon separates the menu entry name from the node name. An extra
+colon confuses Info.
+@xref{Menu Parts, , The Parts of a Menu},
+for more information about the structure of a menu entry.@refill
+@end quotation
+
+If you write several identical index entries in different places in a
+Texinfo file, the index in the printed manual will list all the pages to
+which those entries refer. However, the index in the Info file will
+list @strong{only} the node that references the @strong{first} of those
+index entries. Therefore, it is best to write indices in which each
+entry refers to only one place in the Texinfo file. Fortunately, this
+constraint is a feature rather than a loss since it means that the index
+will be easy to use. Otherwise, you could create an index that lists
+several pages for one entry and your reader would not know to which page
+to turn. If you have two identical entries for one topic, change the
+topics slightly, or qualify them to indicate the difference.@refill
+
+You are not actually required to use the predefined indices for their
+canonical purposes. For example, suppose you wish to index some C
+preprocessor macros. You could put them in the function index along
+with actual functions, just by writing @code{@@findex} commands for
+them; then, when you print the ``Function Index'' as an unnumbered
+chapter, you could give it the title `Function and Macro Index' and
+all will be consistent for the reader. Or you could put the macros in
+with the data types by writing @code{@@tindex} commands for them, and
+give that index a suitable title so the reader will understand.
+(@xref{Printing Indices & Menus}.)@refill
+
+@node Combining Indices, New Indices, Indexing Commands, Indices
+@comment node-name, next, previous, up
+@section Combining Indices
+@cindex Combining indices
+@cindex Indices, combining them
+
+Sometimes you will want to combine two disparate indices such as functions
+and concepts, perhaps because you have few enough of one of them that
+a separate index for them would look silly.@refill
+
+You could put functions into the concept index by writing
+@code{@@cindex} commands for them instead of @code{@@findex} commands,
+and produce a consistent manual by printing the concept index with the
+title `Function and Concept Index' and not printing the `Function
+Index' at all; but this is not a robust procedure. It works only if
+your document is never included as part of another
+document that is designed to have a separate function index; if your
+document were to be included with such a document, the functions from
+your document and those from the other would not end up together.
+Also, to make your function names appear in the right font in the
+concept index, you would need to enclose every one of them between
+the braces of @code{@@code}.@refill
+
+@menu
+* syncodeindex:: How to merge two indices, using @code{@@code}
+ font for the merged-from index.
+* synindex:: How to merge two indices, using the
+ default font of the merged-to index.
+@end menu
+
+@node syncodeindex, synindex, , Combining Indices
+@subsubsection @code{@@syncodeindex}
+@findex syncodeindex
+
+When you want to combine functions and concepts into one index, you
+should index the functions with @code{@@findex} and index the concepts
+with @code{@@cindex}, and use the @code{@@syncodeindex} command to
+redirect the function index entries into the concept index.@refill
+@findex syncodeindex
+
+The @code{@@syncodeindex} command takes two arguments; they are the name
+of the index to redirect, and the name of the index to redirect it to.
+The template looks like this:@refill
+
+@example
+@@syncodeindex @var{from} @var{to}
+@end example
+
+@cindex Predefined names for indices
+@cindex Two letter names for indices
+@cindex Indices, two letter names
+@cindex Names for indices
+For this purpose, the indices are given two-letter names:@refill
+
+@table @samp
+@item cp
+concept index
+@item fn
+function index
+@item vr
+variable index
+@item ky
+key index
+@item pg
+program index
+@item tp
+data type index
+@end table
+
+Write an @code{@@syncodeindex} command before or shortly after the
+end-of-header line at the beginning of a Texinfo file. For example,
+to merge a function index with a concept index, write the
+following:@refill
+
+@example
+@@syncodeindex fn cp
+@end example
+
+@noindent
+This will cause all entries designated for the function index to merge
+in with the concept index instead.@refill
+
+To merge both a variables index and a function index into a concept
+index, write the following:@refill
+
+@example
+@group
+@@syncodeindex vr cp
+@@syncodeindex fn cp
+@end group
+@end example
+
+@cindex Fonts for indices
+The @code{@@syncodeindex} command puts all the entries from the `from'
+index (the redirected index) into the @code{@@code} font, overriding
+whatever default font is used by the index to which the entries are
+now directed. This way, if you direct function names from a function
+index into a concept index, all the function names are printed in the
+@code{@@code} font as you would expect.@refill
+
+@node synindex, , syncodeindex, Combining Indices
+@subsubsection @code{@@synindex}
+@findex synindex
+
+The @code{@@synindex} command is nearly the same as the
+@code{@@syncodeindex} command, except that it does not put the
+`from' index entries into the @code{@@code} font; rather it puts
+them in the roman font. Thus, you use @code{@@synindex} when you
+merge a concept index into a function index.@refill
+
+@xref{Printing Indices & Menus}, for information about printing an index
+at the end of a book or creating an index menu in an Info file.@refill
+
+@node New Indices, , Combining Indices, Indices
+@section Defining New Indices
+@cindex Defining new indices
+@cindex Indices, defining new
+@cindex New index defining
+@findex defindex
+@findex defcodeindex
+
+In addition to the predefined indices, you may use the
+@code{@@defindex} and @code{@@defcodeindex} commands to define new
+indices. These commands create new indexing @@-commands with which
+you mark index entries. The @code{@@defindex }command is used like
+this:@refill
+
+@example
+@@defindex @var{name}
+@end example
+
+The name of an index should be a two letter word, such as @samp{au}.
+For example:@refill
+
+@example
+@@defindex au
+@end example
+
+This defines a new index, called the @samp{au} index. At the same
+time, it creates a new indexing command, @code{@@auindex}, that you
+can use to make index entries. Use the new indexing command just as
+you would use a predefined indexing command.@refill
+
+For example, here is a section heading followed by a concept index
+entry and two @samp{au} index entries.@refill
+
+@example
+@@section Cognitive Semantics
+@@cindex kinesthetic image schemas
+@@auindex Johnson, Mark
+@@auindex Lakoff, George
+@end example
+
+@noindent
+(Evidently, @samp{au} serves here as an abbreviation for ``author''.)
+Texinfo constructs the new indexing command by concatenating the name
+of the index with @samp{index}; thus, defining an @samp{au} index
+leads to the automatic creation of an @code{@@auindex} command.@refill
+
+Use the @code{@@printindex} command to print the index, as you do with
+the predefined indices. For example:@refill
+
+@example
+@group
+@@node Author Index, Subject Index, , Top
+@@unnumbered Author Index
+
+@@printindex au
+@end group
+@end example
+
+The @code{@@defcodeindex} is like the @code{@@defindex} command, except
+that, in the printed output, it prints entries in an @code{@@code} font
+instead of a roman font. Thus, it parallels the @code{@@findex} command
+rather than the @code{@@cindex} command.@refill
+
+You should define new indices within or right after the end-of-header
+line of a Texinfo file, before any @code{@@synindex} or
+@code{@@syncodeindex} commands (@pxref{Header}).@refill
+
+@node Insertions, Glyphs, Indices, Top
+@comment node-name, next, previous, up
+@chapter Special Insertions
+@cindex Inserting special characters and symbols
+@cindex Special insertions
+
+Texinfo provides several commands for formatting dimensions, for
+inserting single characters that have special meaning in Texinfo, such
+as braces, and for inserting special graphic symbols that do not
+correspond to characters, such as dots and bullets.@refill
+
+@iftex
+These are:
+
+@itemize @bullet
+@item
+Braces, @samp{@@} and periods.
+
+@item
+Format a dimension, such as @samp{12@dmn{pt}}.
+
+@item
+Dots and bullets.
+
+@item
+The @TeX{} logo and the copyright symbol.
+
+@item
+A minus sign.
+@end itemize
+@end iftex
+
+@menu
+* Braces Atsigns Periods:: How to insert braces, @samp{@@} and periods.
+* dmn:: How to format a dimension.
+* Dots Bullets:: How to insert dots and bullets.
+* TeX and copyright:: How to insert the @TeX{} logo
+ and the copyright symbol.
+* minus:: How to insert a minus sign.
+@end menu
+
+@node Braces Atsigns Periods, dmn, , Insertions
+@comment node-name, next, previous, up
+@section Inserting @samp{@@}, Braces, and Periods
+@cindex Inserting @@, braces, and periods
+@cindex Braces, inserting
+@cindex Periods, inserting
+@cindex Single characters, commands to insert
+@cindex Commands to insert single characters
+
+@samp{@@} and curly braces are special characters in Texinfo. To
+insert these characters so they appear in text, you must put an @samp{@@} in front
+of these characters to prevent Texinfo from misinterpreting them.@refill
+
+Periods are also special. Depending on whether the period is inside
+or at the end of a sentence, less or more space is inserted after a
+period in a typeset manual. Since it is not always possible for
+Texinfo to determine when a period ends a sentence and when it is used
+in an abbreviation, special commands are needed in some circumstances.
+(Usually, Texinfo can guess how to handle periods, so you do not need
+to use the special commands; you just enter a period as you would if
+you were using a typewriter, which means you put two spaces after the
+period, question mark, or exclamation mark that ends a
+sentence.)@refill
+
+Do not put braces after any of these commands; they are not
+necessary.@refill
+
+@menu
+* Inserting An Atsign::
+* Inserting Braces:: How to insert @samp{@{} and @samp{@}}
+* Controlling Spacing:: How to insert the right amount of space
+ after punctuation within a sentence.
+@end menu
+
+@node Inserting An Atsign, Inserting Braces, , Braces Atsigns Periods
+@comment node-name, next, previous, up
+@subsection Inserting @samp{@@} with @@@@
+@findex @@ @r{(single @samp{@@})}
+
+@code{@@@@} stands for a single @samp{@@} in either printed or Info
+output.@refill
+
+Do not put braces after an @code{@@@@} command.@refill
+
+@node Inserting Braces, Controlling Spacing, Inserting An Atsign, Braces Atsigns Periods
+@comment node-name, next, previous, up
+@subsection Inserting @samp{@{} and @samp{@}}with @@@{ and @@@}
+@findex @{ @r{(single @samp{@{})}
+@findex @} @r{(single @samp{@}})}
+
+@code{@@@{} stands for a single @samp{@{} in either printed or Info
+output.@refill
+
+@code{@@@}} stands for a single @samp{@}} in either printed or Info
+output.@refill
+
+Do not put braces after either an @code{@@@{} or an @code{@@@}}
+command.@refill
+
+@node Controlling Spacing, , Inserting Braces, Braces Atsigns Periods
+@comment node-name, next, previous, up
+@subsection Spacing After Colons and Periods
+@findex : @r{(suppress widening)}
+
+Use the @code{@@:}@: command after a period, question mark,
+exclamation mark, or colon that should not be followed by extra space.
+For example, use @code{@@:}@: after periods that end abbreviations
+which are not at the ends of sentences. @code{@@:}@: has no effect on
+the Info file output.@refill
+
+@need 700
+For example,
+
+@example
+The s.o.p.@@: has three parts @dots{}
+The s.o.p. has three parts @dots{}
+@end example
+
+@noindent
+@ifinfo
+produces
+@end ifinfo
+@iftex
+produces the following. If you look carefully at this printed output,
+you will see a little more whitespace after @samp{s.o.p.} in the second
+line.@refill
+@end iftex
+
+@quotation
+The s.o.p.@: has three parts @dots{}@*
+The s.o.p. has three parts @dots{}
+@end quotation
+
+@noindent
+@kbd{@@:} has no effect on the Info output. (@samp{s.o.p} is an acronym
+for ``Standard Operating Procedure''.)
+
+@findex . @r{(true end of sentence)}
+Use @code{@@.}@: instead of a period at the end of a sentence that
+ends with a single capital letter. Otherwise, @TeX{} will think the
+letter is an abbreviation and will not insert the correct
+end-of-sentence spacing. Here is an example:@refill
+
+@example
+Give it to M.I.B. and to M.E.W@@. Also, give it to R.J.C@@.
+Give it to M.I.B. and to M.E.W. Also, give it to R.J.C.
+@end example
+
+@noindent
+@ifinfo
+produces
+@end ifinfo
+@iftex
+produces the following. If you look carefully at this printed output,
+you will see a little more whitespace after the @samp{W} in the first
+line.@refill
+@end iftex
+
+@quotation
+Give it to M.I.B. and to M.E.W@. Also, give it to R.J.C@.@*
+Give it to M.I.B. and to M.E.W. Also, give it to R.J.C.
+@end quotation
+
+In the Info file output, @code{@@.}@: is equivalent to a simple
+@samp{.}.@refill
+
+The meanings of @code{@@:}@: and @code{@@.}@: in Texinfo are designed
+to work well with the Emacs sentence motion commands. This made it
+necessary for them to be incompatible with some other formatting
+systems that use @@-commands.@refill
+
+Do not put braces after either an @code{@@:} or an @code{@@.} command.@refill
+
+@node dmn, Dots Bullets, Braces Atsigns Periods, Insertions
+@section @code{@@dmn}@{@var{dimension}@}: Format a Dimension
+@cindex Thin space between number, dimension
+@cindex Dimension formatting
+@cindex Format a dimension
+@findex dmn
+
+At times, you may want to write @samp{12@dmn{pt}} or
+@samp{8.5@dmn{in}} with little or no space between the number and the
+abbreviation for the dimension. You can use the @code{@@dmn} command
+to do this. On seeing the command, @TeX{} inserts just enough space
+for proper typesetting; the Info formatting commands insert no space
+at all, since the Info file does not require it.@refill
+
+To use the @code{@@dmn} command, write the number and then follow it
+immediately, with no intervening space, by @code{@@dmn}, and then by
+the dimension within braces.@refill
+
+@need 700
+@noindent
+For example,
+
+@example
+A4 paper is 8.27@@dmn@{in@} wide.
+@end example
+
+@noindent
+produces
+
+@quotation
+A4 paper is 8.27@dmn{in} wide.
+@end quotation
+
+Not everyone uses this style. Instead of writing
+@w{@samp{8.27@@dmn@{in@}}} in the Texinfo file, you may write
+@w{@samp{8.27 in.}} or @w{@samp{8.27 inches}}. (In these cases, the
+formatters may insert a line break between the number and the
+dimension. Also, if you write a period after an abbreviation within a
+sentence, you should write @samp{@@:} after the period to prevent
+@TeX{} from inserting extra whitespace. @xref{Controlling Spacing, ,
+Spacing After Colons and Periods}.)@refill
+
+@node Dots Bullets, TeX and copyright, dmn, Insertions
+@comment node-name, next, previous, up
+@section Inserting Ellipsis, Dots, and Bullets
+@cindex Dots, inserting
+@cindex Bullets, inserting
+@cindex Ellipsis, inserting
+@cindex Inserting ellipsis
+@cindex Inserting dots
+@cindex Special typesetting commands
+@cindex Typesetting commands for dots, etc.
+
+An @dfn{ellipsis} (a line of dots) is not typeset as a string of
+periods, so a special command is used for ellipsis in Texinfo. The
+@code{@@bullet} command is special, too. Each of these commands is
+followed by a pair of braces, @samp{@{@}}, without any whitespace
+between the name of the command and the braces. (You need to use braces
+with these commands because you can use them next to other text; without
+the braces, the formatters would be confused. @xref{Command Syntax, ,
+@@-Command Syntax}, for further information.)@refill
+
+@menu
+* dots:: How to insert dots @dots{}
+* bullet:: How to insert a bullet.
+@end menu
+
+@node dots, bullet, , Dots Bullets
+@comment node-name, next, previous, up
+@subsection @code{@@dots}@{@}
+@findex dots
+@cindex Inserting dots
+@cindex Dots, inserting
+
+Use the @code{@@dots@{@}} command to generate an ellipsis, which is
+three dots in a row, appropriately spaced, like this: `@dots{}'. Do
+not simply write three periods in the input file; that would work for
+the Info file output, but would produce the wrong amount of space
+between the periods in the printed manual.@refill
+
+@iftex
+Here is an ellipsis: @dots{}
+
+Here are three periods in a row: ...
+
+In printed output, the three periods in a row are closer together than
+the dots in the ellipsis.
+@end iftex
+
+@node bullet, , dots, Dots Bullets
+@comment node-name, next, previous, up
+@subsection @code{@@bullet}@{@}
+@findex bullet
+
+Use the @code{@@bullet@{@}} command to generate a large round dot, or
+the closest possible thing to one. In Info, an asterisk is used.@refill
+
+Here is a bullet: @bullet{}
+
+When you use @code{@@bullet} in @code{@@itemize}, you do not need to
+type the braces, because @code{@@itemize} supplies them. @xref{itemize}.@refill
+
+@node TeX and copyright, minus, Dots Bullets, Insertions
+@comment node-name, next, previous, up
+@section Inserting @TeX{} and the Copyright Symbol
+
+The logo `@TeX{}' is typeset in a special fashion and it needs an
+@@-command. The copyright symbol, `@copyright{}', is also special.
+Each of these commands is followed by a pair of braces, @samp{@{@}},
+without any whitespace between the name of the command and the
+braces.@refill
+
+@menu
+* tex:: How to insert the @TeX{} logo.
+* copyright symbol:: How to use @code{@@copyright}@{@}.
+@end menu
+
+@node tex, copyright symbol, , TeX and copyright
+@comment node-name, next, previous, up
+@subsection @code{@@TeX}@{@}
+@findex tex (command)
+
+Use the @code{@@TeX@{@}} command to generate `@TeX{}'. In a printed
+manual, this is a special logo that is different from three ordinary
+letters. In Info, it just looks like @samp{TeX}. The
+@code{@@TeX@{@}} command is unique among Texinfo commands in that the
+@key{T} and the @key{X} are in upper case.@refill
+
+@node copyright symbol, , tex, TeX and copyright
+@comment node-name, next, previous, up
+@subsection @code{@@copyright}@{@}
+@findex copyright
+
+Use the @code{@@copyright@{@}} command to generate `@copyright{}'. In
+a printed manual, this is a @samp{c} inside a circle, and in Info,
+this is @samp{(C)}.@refill
+
+@node minus, , TeX and copyright, Insertions
+@section @code{@@minus}@{@}: Inserting a Minus Sign
+@findex minus
+
+Use the @code{@@minus@{@}} command to generate a minus sign. In a
+fixed-width font, this is a single hyphen, but in a proportional font,
+the symbol is the customary length for a minus sign---a little longer
+than a hyphen.@refill
+
+You can compare the two forms:
+
+@display
+@samp{@minus{}} is a minus sign generated with @samp{@@minus@{@}},
+
+`-' is a hyphen generated with the character @samp{-}.
+@end display
+
+@noindent
+In the fixed-width font used by Info, @code{@@minus@{@}} is the same
+as a hyphen.@refill
+
+You should not use @code{@@minus@{@}} inside @code{@@code} or
+@code{@@example} because the width distinction is not made in the
+fixed-width font they use.@refill
+
+When you use @code{@@minus} to specify the mark beginning each entry in
+an itemized list, you do not need to type the braces
+(@pxref{itemize}).@refill
+
+@node Glyphs, Breaks, Insertions, Top
+@comment node-name, next, previous, up
+@chapter Glyphs for Examples
+@cindex Glyphs
+
+In Texinfo, code is often illustrated in examples that are delimited
+by @code{@@example} and @code{@@end example}, or by @code{@@lisp} and
+@code{@@end lisp}. In such examples, you can indicate the results of
+evaluation or an expansion using @samp{@result{}} or
+@samp{@expansion{}}. Likewise, there are commands to insert glyphs
+to indicate
+printed output, error messages, equivalence of expressions, and the
+location of point.@refill
+
+The glyph-insertion commands do not need to be used within an example, but
+most often they are. Every glyph-insertion command is followed by a pair of
+left- and right-hand braces.@refill
+
+@menu
+* Glyphs Summary::
+* result:: How to show the result of expression.
+* expansion:: How to indicate an expansion.
+* Print Glyph:: How to indicate printed output.
+* Error Glyph:: How to indicate an error message.
+* Equivalence:: How to indicate equivalence.
+* Point Glyph:: How to indicate the location of point.
+@end menu
+
+@node Glyphs Summary, result, , Glyphs
+@ifinfo
+@heading Glyphs Summary
+
+Here are the different glyph commands:@refill
+@end ifinfo
+
+@table @asis
+@item @result{}
+@code{@@result@{@}} points to the result of an expression.@refill
+
+@item @expansion{}
+@code{@@expansion@{@}} shows the results of a macro expansion.@refill
+
+@item @print{}
+@code{@@print@{@}} indicates printed output.@refill
+
+@item @error{}
+@code{@@error@{@}} indicates that the following text is an error
+message.@refill
+
+@item @equiv{}
+@code{@@equiv@{@}} indicates the exact equivalence of two forms.@refill
+
+@item @point{}
+@code{@@point@{@}} shows the location of point.@refill
+@end table
+
+@node result, expansion, Glyphs Summary, Glyphs
+@section @result{}: Indicating Evaluation
+@cindex Result of an expression
+@cindex Indicating evaluation
+@cindex Evaluation glyph
+@cindex Value of an expression, indicating
+
+Use the @code{@@result@{@}} command to indicate the result of
+evaluating an expression.@refill
+
+@iftex
+The @code{@@result@{@}} command is displayed as @samp{=>} in Info and
+as @samp{@result{}} in the printed output.
+@end iftex
+@ifinfo
+The @code{@@result@{@}} command is displayed as @samp{@result{}} in Info
+and as a double stemmed arrow in the printed output.@refill
+@end ifinfo
+
+Thus, the following,
+
+@lisp
+(cdr '(1 2 3))
+ @result{} (2 3)
+@end lisp
+
+@noindent
+may be read as ``@code{(cdr '(1 2 3))} evaluates to @code{(2 3)}''.
+
+@node expansion, Print Glyph, result, Glyphs
+@section @expansion{}: Indicating an Expansion
+@cindex Expansion, indicating it
+
+When an expression is a macro call, it expands into a new expression.
+You can indicate the result of the expansion with the
+@code{@@expansion@{@}} command.@refill
+
+@iftex
+The @code{@@expansion@{@}} command is displayed as @samp{==>} in Info and
+as @samp{@expansion{}} in the printed output.
+@end iftex
+@ifinfo
+The @code{@@expansion@{@}} command is displayed as @samp{@expansion{}}
+in Info and as a long arrow with a flat base in the printed output.@refill
+@end ifinfo
+
+@need 700
+For example, the following
+
+@example
+@group
+@@lisp
+(third '(a b c))
+ @@expansion@{@} (car (cdr (cdr '(a b c))))
+ @@result@{@} c
+@@end lisp
+@end group
+@end example
+
+@noindent
+produces
+
+@lisp
+@group
+(third '(a b c))
+ @expansion{} (car (cdr (cdr '(a b c))))
+ @result{} c
+@end group
+@end lisp
+
+@noindent
+which may be read as:
+
+@quotation
+@code{(third '(a b c))} expands to @code{(car (cdr (cdr '(a b c))))};
+the result of evaluating the expression is @code{c}.
+@end quotation
+
+@noindent
+Often, as in this case, an example looks better if the
+@code{@@expansion@{@}} and @code{@@result@{@}} commands are indented
+five spaces.@refill
+
+@node Print Glyph, Error Glyph, expansion, Glyphs
+@section @print{}: Indicating Printed Output
+@cindex Printed output, indicating it
+
+Sometimes an expression will print output during its execution. You
+can indicate the printed output with the @code{@@print@{@}} command.@refill
+
+@iftex
+The @code{@@print@{@}} command is displayed as @samp{-|} in Info and
+as @samp{@print{}} in the printed output.
+@end iftex
+@ifinfo
+The @code{@@print@{@}} command is displayed as @samp{@print{}} in Info
+and similarly, as a horizontal dash butting against a vertical bar, in
+the printed output.@refill
+@end ifinfo
+
+In the following example, the printed text is indicated with
+@samp{@print{}}, and the value of the expression follows on the
+last line.@refill
+
+@lisp
+@group
+(progn (print 'foo) (print 'bar))
+ @print{} foo
+ @print{} bar
+ @result{} bar
+@end group
+@end lisp
+
+@noindent
+In a Texinfo source file, this example is written as follows:
+
+@lisp
+@group
+@@lisp
+(progn (print 'foo) (print 'bar))
+ @@print@{@} foo
+ @@print@{@} bar
+ @@result@{@} bar
+@@end lisp
+@end group
+@end lisp
+
+@node Error Glyph, Equivalence, Print Glyph, Glyphs
+@section @error{}: Indicating an Error Message
+@cindex Error message, indicating it
+
+A piece of code may cause an error when you evaluate it. You can
+designate the error message with the @code{@@error@{@}} command.@refill
+
+@iftex
+The @code{@@error@{@}} command is displayed as @samp{error-->} in Info
+and as @samp{@error{}} in the printed output.
+@end iftex
+@ifinfo
+The @code{@@error@{@}} command is displayed as @samp{@error{}} in Info
+and as the word `error' in a box in the printed output.@refill
+@end ifinfo
+
+@need 700
+Thus,
+
+@example
+@@lisp
+(+ 23 'x)
+@@error@{@} Wrong type argument: integer-or-marker-p, x
+@@end lisp
+@end example
+
+@noindent
+produces
+
+@lisp
+(+ 23 'x)
+@error{} Wrong type argument: integer-or-marker-p, x
+@end lisp
+
+@noindent
+This indicates that the following error message is printed
+when you evaluate the expression:
+
+@lisp
+Wrong type argument: integer-or-marker-p, x
+@end lisp
+
+Note that @samp{@error{}} itself is not part of the error
+message.
+
+@node Equivalence, Point Glyph, Error Glyph, Glyphs
+@section @equiv{}: Indicating Equivalence
+@cindex Equivalence, indicating it
+
+Sometimes two expressions produce identical results. You can indicate the
+exact equivalence of two forms with the @code{@@equiv@{@}} command.@refill
+
+@iftex
+The @code{@@equiv@{@}} command is displayed as @samp{==} in Info and
+as @samp{@equiv{}} in the printed output.
+@end iftex
+@ifinfo
+The @code{@@equiv@{@}} command is displayed as @samp{@equiv{}} in Info
+and as a three parallel horizontal lines in the printed output.@refill
+@end ifinfo
+
+Thus,
+
+@example
+@@lisp
+(make-sparse-keymap) @@equiv@{@} (list 'keymap)
+@@end lisp
+@end example
+
+@noindent
+produces
+
+@lisp
+(make-sparse-keymap) @equiv{} (list 'keymap)
+@end lisp
+
+@noindent
+This indicates that evaluating @code{(make-sparse-keymap)} produces
+identical results to evaluating @code{(list 'keymap)}.
+
+@c Cannot write point command here because it causes trouble with TOC.
+@node Point Glyph, , Equivalence, Glyphs
+@section Indicating Point in a Buffer
+@cindex Point, indicating it in a buffer
+
+Sometimes you need to show an example of text in an Emacs buffer. In
+such examples, the convention is to include the entire contents of the
+buffer in question between two lines of dashes containing the buffer
+name.@refill
+
+You can use the @samp{@@point@{@}} command to show the location of point
+in the text in the buffer. (The symbol for point, of course, is not
+part of the text in the buffer; it indicates the place @emph{between}
+two characters where point is located.)@refill
+
+@iftex
+The @code{@@point@{@}} command is displayed as @samp{-!-} in Info and
+as @samp{@point{}} in the printed output.
+@end iftex
+@ifinfo
+The @code{@@point@{@}} command is displayed as @samp{@point{}} in Info
+and as a small five pointed star in the printed output.@refill
+@end ifinfo
+
+The following example shows the contents of buffer @file{foo} before
+and after evaluating a Lisp command to insert the word @code{changed}.@refill
+
+@example
+@group
+---------- Buffer: foo ----------
+This is the @point{}contents of foo.
+---------- Buffer: foo ----------
+
+@end group
+@end example
+
+@example
+@group
+(insert "changed ")
+ @result{} nil
+---------- Buffer: foo ----------
+This is the changed @point{}contents of foo.
+---------- Buffer: foo ----------
+
+@end group
+@end example
+
+In a Texinfo source file, the example is written like this:@refill
+
+@example
+@@example
+---------- Buffer: foo ----------
+This is the @@point@{@}contents of foo.
+---------- Buffer: foo ----------
+
+(insert "changed ")
+ @@result@{@} nil
+---------- Buffer: foo ----------
+This is the changed @@point@{@}contents of foo.
+---------- Buffer: foo ----------
+@@end example
+@end example
+
+@node Breaks, Definition Commands, Glyphs, Top
+@comment node-name, next, previous, up
+@chapter Making and Preventing Breaks
+@cindex Making line and page breaks
+@cindex Preventing line and page breaks
+
+Usually, a Texinfo file is processed both by @TeX{} and by one of the
+Info formatting commands. Line, paragraph, or page breaks sometimes
+occur in the `wrong' place in one or other form of output. You must
+ensure that text looks right both in the printed manual and in the
+Info file.@refill
+
+For example, in a printed manual, page breaks may occur awkwardly in
+the middle of an example; to prevent this, you can hold text together
+using a grouping command that keeps the text from being split across
+two pages. Conversely, you may want to force a page break where none
+would occur normally. Fortunately, problems like these do not often
+arise. When they do, use the break, break prevention, or pagination
+commands.@refill
+
+@menu
+* Break Commands:: Cause and prevent splits.
+* Line Breaks:: How to force a single line to use two lines.
+* w:: How to prevent unwanted line breaks.
+* sp:: How to insert blank lines.
+* page:: How to force the start of a new page.
+* group:: How to prevent unwanted page breaks.
+* need:: Another way to prevent unwanted page breaks.
+@end menu
+
+@ifinfo
+@node Break Commands, Line Breaks, , Breaks
+@heading The Break Commands
+@end ifinfo
+@iftex
+@sp 1
+@end iftex
+
+The break commands create line and paragraph breaks:@refill
+
+@table @code
+@item @@*
+Force a line break.
+
+@item @@sp @var{n}
+Skip @var{n} blank lines.@refill
+@end table
+@iftex
+@sp 1
+@end iftex
+
+The line-break-prevention command holds text together all on one
+line:@refill
+
+@table @code
+@item @@w@{@var{text}@}
+Prevent @var{text} from being split and hyphenated across two lines.@refill
+@end table
+@iftex
+@sp 1
+@end iftex
+
+The pagination commands apply only to printed output, since Info
+files do not have pages.@refill
+
+@table @code
+@item @@page
+Start a new page in the printed manual.@refill
+
+@item @@group
+Hold text together that must appear on one printed page.@refill
+
+@item @@need @var{mils}
+Start a new printed page if not enough space on this one.@refill
+@end table
+
+@node Line Breaks, w, Break Commands, Breaks
+@comment node-name, next, previous, up
+@section @code{@@*}: Generate Line Breaks
+@findex * @r{(force line break)}
+@cindex Line breaks
+@cindex Breaks in a line
+
+The @code{@@*} command forces a line break in both the printed manual and
+in Info.@refill
+
+@need 700
+For example,
+
+@example
+This line @@* is broken @@*in two places.
+@end example
+
+@noindent
+produces
+
+@example
+@group
+This line
+ is broken
+in two places.
+@end group
+@end example
+
+@noindent
+(Note that the space after the first @code{@@*} command is faithfully
+carried down to the next line.)@refill
+
+@need 800
+The @code{@@*} command is often used in a file's copyright page:@refill
+
+@example
+@group
+This is edition 2.0 of the Texinfo documentation,@@*
+and is for @dots{}
+@end group
+@end example
+
+@noindent
+In this case, the @code{@@*} command keeps @TeX{} from stretching the
+line across the whole page in an ugly manner.@refill
+
+@quotation
+@strong{Please note:} Do not write braces after an @code{@@*} command;
+they are not needed.@refill
+
+Do not write an @code{@@refill} command at the end of a paragraph
+containing an @code{@@*} command; it will cause the paragraph to be
+refilled after the line break occurs, negating the effect of the line
+break.@refill
+@end quotation
+
+@node w, sp, Line Breaks, Breaks
+@comment node-name, next, previous, up
+@section @code{@@w}@{@var{text}@}: Prevent Line Breaks
+@findex w @r{(prevent line break)}
+@cindex Line breaks, preventing
+
+@code{@@w@{@var{text}@}} outputs @var{text} and prohibits line breaks
+within @var{text}.@refill
+
+You can use the @code{@@w} command to prevent @TeX{} from automatically
+hyphenating a long name or phrase that accidentally falls near the end
+of a line.@refill
+
+@example
+You can copy GNU software from @@w@{@@file@{prep.ai.mit.edu@}@}.
+@end example
+
+@noindent
+produces
+
+@quotation
+You can copy GNU software from @w{@file{prep.ai.mit.edu}}.
+@end quotation
+
+In the Texinfo file, you must write the @code{@@w} command and its
+argument (all the affected text) all on one line.@refill
+
+@quotation
+@strong{Caution:} Do not write an @code{@@refill} command at the end
+of a paragraph containing an @code{@@w} command; it will cause the
+paragraph to be refilled and may thereby negate the effect of the
+@code{@@w} command.@refill
+@end quotation
+
+@node sp, page, w, Breaks
+@comment node-name, next, previous, up
+@section @code{@@sp} @var{n}: Insert Blank Lines
+@findex sp @r{(line spacing)}
+@cindex Spaces (blank lines)
+@cindex Blank lines
+@cindex Line spacing
+
+A line beginning with and containing only @code{@@sp @var{n}}
+generates @var{n} blank lines of space in both the printed manual and
+the Info file. @code{@@sp} also forces a paragraph break. For
+example,@refill
+
+@example
+@@sp 2
+@end example
+
+@noindent
+generates two blank lines.
+
+The @code{@@sp} command is most often used in the title page.@refill
+
+@ignore
+@c node br, page, sp, Breaks
+@comment node-name, next, previous, up
+@c section @code{@@br}: Generate Paragraph Breaks
+@findex br @r{(paragraph breaks)}
+@cindex Paragraph breaks
+@cindex Breaks in a paragraph
+
+The @code{@@br} command forces a paragraph break. It inserts a blank
+line. You can use the command within or at the end of a line. If
+used within a line, the @code{@@br@{@}} command must be followed by
+left and right braces (as shown here) to mark the end of the
+command.@refill
+
+@need 700
+For example,
+
+@example
+@group
+This line @@br@{@}contains and is ended by paragraph breaks@@br
+and is followed by another line.
+@end group
+@end example
+
+@noindent
+produces
+
+@example
+@group
+This line
+
+contains and is ended by paragraph breaks
+
+and is followed by another line.
+@end group
+@end example
+
+The @code{@@br} command is seldom used.
+@end ignore
+
+@node page, group, sp, Breaks
+@comment node-name, next, previous, up
+@section @code{@@page}: Start a New Page
+@cindex Page breaks
+@findex page
+
+A line containing only @code{@@page} starts a new page in a printed
+manual. The command has no effect on Info files since they are not
+paginated. An @code{@@page} command is often used in the @code{@@titlepage}
+section of a Texinfo file to start the copyright page.@refill
+
+@node group, need, page, Breaks
+@comment node-name, next, previous, up
+@section @code{@@group}: Prevent Page Breaks
+@cindex Group (hold text together vertically)
+@cindex Holding text together vertically
+@cindex Vertically holding text together
+@findex group
+
+The @code{@@group} command (on a line by itself) is used inside an
+@code{@@example} or similar construct to begin an unsplittable vertical
+group, which will appear entirely on one page in the printed output.
+The group is terminated by a line containing only @code{@@end group}.
+These two lines produce no output of their own, and in the Info file
+output they have no effect at all.@refill
+
+@c Once said that these environments
+@c turn off vertical spacing between ``paragraphs''.
+@c Also, quotation used to work, but doesn't in texinfo-2.72
+Although @code{@@group} would make sense conceptually in a wide
+variety of contexts, its current implementation works reliably only
+within @code{@@example} and variants, and within @code{@@display},
+@code{@@format}, @code{@@flushleft} and @code{@@flushright}.
+@xref{Quotations and Examples}. (What all these commands have in
+common is that each line of input produces a line of output.) In
+other contexts, @code{@@group} can cause anomalous vertical
+spacing.@refill
+
+@need 750
+This formatting requirement means that you should write:
+
+@example
+@group
+@@example
+@@group
+@dots{}
+@@end group
+@@end example
+@end group
+@end example
+
+@noindent
+with the @code{@@group} and @code{@@end group} commands inside the
+@code{@@example} and @code{@@end example} commands.
+
+The @code{@@group} command is most often used to hold an example
+together on one page. In this Texinfo manual, more than 100 examples
+contain text that is enclosed between @code{@@group} and @code{@@end
+group}.
+
+If you forget to end a group, you may get strange and unfathomable
+error messages when you run @TeX{}. This is because @TeX{} keeps
+trying to put the rest of the Texinfo file onto the one page and does
+not start to generate error messages until it has processed
+considerable text. It is a good rule of thumb to look for a missing
+@code{@@end group} if you get incomprehensible error messages in
+@TeX{}.@refill
+
+@node need, , group, Breaks
+@comment node-name, next, previous, up
+@section @code{@@need @var{mils}}: Prevent Page Breaks
+@cindex Need space at page bottom
+@findex need
+
+A line containing only @code{@@need @var{n}} starts
+a new page in a printed manual if fewer than @var{n} mils (thousandths
+of an inch) remain on the current page. Do not use
+braces around the argument @var{n}. The @code{@@need} command has no
+effect on Info files since they are not paginated.@refill
+
+@need 800
+This paragraph is preceded by an @code{@@need} command that tells
+@TeX{} to start a new page if fewer than 800 mils (eight-tenths
+inch) remain on the page. It looks like this:@refill
+
+@example
+@group
+@@need 800
+This paragraph is preceded by @dots{}
+@end group
+@end example
+
+The @code{@@need} command is useful for preventing orphans (single
+lines at the bottoms of printed pages).@refill
+
+@node Definition Commands, Footnotes, Breaks, Top
+@chapter Definition Commands
+@cindex Definition commands
+
+The @code{@@deffn} command and the other @dfn{definition commands}
+enable you to describe functions, variables, macros, commands, user
+options, special forms and other such artifacts in a uniform
+format.@refill
+
+In the Info file, a definition causes the entity
+category---`Function', `Variable', or whatever---to appear at the
+beginning of the first line of the definition, followed by the
+entity's name and arguments. In the printed manual, the command
+causes @TeX{} to print the entity's name and its arguments on the left
+margin and print the category next to the right margin. In both
+output formats, the body of the definition is indented. Also, the
+name of the entity is entered into the appropriate index:
+@code{@@deffn} enters the name into the index of functions,
+@code{@@defvr} enters it into the index of variables, and so
+on.@refill
+
+A manual need not and should not contain more than one definition for
+a given name. An appendix containing a summary should use
+@code{@@table} rather than the definition commands.@refill
+
+@menu
+* Def Cmd Template:: How to structure a description using a
+ definition command.
+* Optional Arguments:: How to handle optional and repeated arguments.
+* deffnx:: How to group two or more `first' lines.
+* Def Cmds in Detail:: All the definition commands.
+* Def Cmd Conventions:: Conventions for writing definitions.
+* Sample Function Definition::
+@end menu
+
+@node Def Cmd Template, Optional Arguments, , Definition Commands
+@section The Template for a Definition
+@cindex Definition template
+@cindex Template for a definition
+
+The @code{@@deffn} command is used for definitions of entities that
+resemble functions. To write a definition using the @code{@@deffn}
+command, write the @code{@@deffn} command at the beginning of a line
+and follow it on the same line by the category of the entity, the name
+of the entity itself, and its arguments (if any). Then write the body
+of the definition on succeeding lines. (You may embed examples in the
+body.) Finally, end the definition with an @code{@@end deffn} command
+written on a line of its own. (The other definition commands follow
+the same format.)@refill
+
+The template for a definition looks like this:
+
+@example
+@group
+@@deffn @var{category} @var{name} @var{arguments}@dots{}
+@var{body-of-definition}
+@@end deffn
+@end group
+@end example
+
+@need 700
+@noindent
+For example,
+
+@example
+@group
+@@deffn Command forward-word count
+This command moves point forward @@var@{count@} words
+(or backward if @@var@{count@} is negative). @dots{}
+@@end deffn
+@end group
+@end example
+
+@noindent
+produces
+
+@quotation
+@deffn Command forward-word count
+This function moves point forward @var{count} words
+(or backward if @var{count} is negative). @dots{}
+@end deffn
+@end quotation
+
+Capitalize the category name like a title. If the name of the
+category contains spaces, as in the phrase `Interactive Command',
+write braces around it. For example:@refill
+
+@example
+@group
+@@deffn @{Interactive Command@} isearch-forward
+@dots{}
+@@end deffn
+@end group
+@end example
+
+@noindent
+Otherwise, the second word will be mistaken for the name of the
+entity.@refill
+
+Some of the definition commands are more general than others. The
+@code{@@deffn} command, for example, is the general definition command
+for functions and the like---for entities that may take arguments. When
+you use this command, you specify the category to which the entity
+belongs. The @code{@@deffn} command possesses three predefined,
+specialized variations, @code{@@defun}, @code{@@defmac}, and
+@code{@@defspec}, that specify the category for you: ``Function'',
+``Macro'', and ``Special Form'' respectively. The @code{@@defvr}
+command also is accompanied by several predefined, specialized
+variations for describing particular kinds of variables.@refill
+
+The template for a specialized definition, such as @code{@@defun}, is
+similar to the template for a generalized definition, except that you
+do not need to specify the category:@refill
+
+@example
+@group
+@@defun @var{name} @var{arguments}@dots{}
+@var{body-of-definition}
+@@end defun
+@end group
+@end example
+
+@noindent
+Thus,
+
+@example
+@group
+@@defun buffer-end flag
+This function returns @@code@{(point-min)@} if @@var@{flag@}
+is less than 1, @@code@{(point-max)@} otherwise.
+@dots{}
+@@end defun
+@end group
+@end example
+
+@noindent
+produces
+
+@quotation
+@defun buffer-end flag
+This function returns @code{(point-min)} if @var{flag} is less than 1,
+@code{(point-max)} otherwise. @dots{}
+@end defun
+@end quotation
+
+@noindent
+@xref{Sample Function Definition, Sample Function Definition, A Sample
+Function Definition}, for a more detailed example of a function
+definition, including the use of @code{@@example} inside the
+definition.@refill
+
+The other specialized commands work like @code{@@defun}.@refill
+
+@node Optional Arguments, deffnx, Def Cmd Template, Definition Commands
+@section Optional and Repeated Arguments
+@cindex Optional and repeated arguments
+@cindex Repeated and optional arguments
+@cindex Arguments, repeated and optional
+@cindex Syntax, optional & repeated arguments
+@cindex Meta-syntactic chars for arguments
+
+Some entities take optional or repeated arguments, which may be
+specified by a distinctive glyph that uses square brackets and
+ellipses. For @w{example}, a special form often breaks its argument list
+into separate arguments in more complicated ways than a
+straightforward function.@refill
+
+@iftex
+An argument enclosed within square brackets is optional.
+Thus, the phrase
+@samp{@code{@r{[}@var{optional-arg}@r{]}}} means that
+@var{optional-arg} is optional.
+An argument followed by an ellipsis is optional
+and may be repeated more than once.
+@c This is consistent with Emacs Lisp Reference manual
+Thus, @samp{@var{repeated-args}@dots{}} stands for zero or more arguments.
+Parentheses are used when several arguments are grouped
+into additional levels of list structure in Lisp.
+@end iftex
+@c The following looks better in Info (no `r', `samp' and `code'):
+@ifinfo
+An argument enclosed within square brackets is optional.
+Thus, [@var{optional-arg}] means that @var{optional-arg} is optional.
+An argument followed by an ellipsis is optional
+and may be repeated more than once.
+@c This is consistent with Emacs Lisp Reference manual
+Thus, @var{repeated-args}@dots{} stands for zero or more arguments.
+Parentheses are used when several arguments are grouped
+into additional levels of list structure in Lisp.
+@end ifinfo
+
+Here is the @code{@@defspec} line of an example of an imaginary
+special form:@refill
+
+@quotation
+@defspec foobar (@var{var} [@var{from} @var{to} [@var{inc}]]) @var{body}@dots{}
+@end defspec
+@tex
+\vskip \parskip
+@end tex
+@end quotation
+
+@noindent
+In this example, the arguments @var{from} and @var{to} are optional,
+but must both be present or both absent. If they are present,
+@var{inc} may optionally be specified as well. These arguments are
+grouped with the argument @var{var} into a list, to distinguish them
+from @var{body}, which includes all remaining elements of the
+form.@refill
+
+In a Texinfo source file, this @code{@@defspec} line is written like
+this (except it would not be split over two lines, as it is in this
+example).@refill
+
+@example
+@group
+@@defspec foobar (@@var@{var@} [@@var@{from@} @@var@{to@}
+ [@@var@{inc@}]]) @@var@{body@}@@dots@{@}
+@end group
+@end example
+
+@noindent
+The function is listed in the Command and Variable Index under
+@samp{foobar}.@refill
+
+@node deffnx, Def Cmds in Detail, Optional Arguments, Definition Commands
+@section Two or More `First' Lines
+@cindex Two `First' Lines for @code{@@deffn}
+@cindex Grouping two definitions together
+@cindex Definitions grouped together
+@findex deffnx
+
+To create two or more `first' or header lines for a definition, follow
+the first @code{@@deffn} line by a line beginning with @code{@@deffnx}.
+The @code{@@deffnx} command works exactly like @code{@@deffn}
+except that it does not generate extra vertical white space between it
+and the preceding line.@refill
+
+@need 1000
+For example,
+
+@example
+@group
+@@deffn @{Interactive Command@} isearch-forward
+@@deffnx @{Interactive Command@} isearch-backward
+These two search commands are similar except @dots{}
+@@end deffn
+@end group
+@end example
+
+@noindent
+produces
+
+@deffn {Interactive Command} isearch-forward
+@deffnx {Interactive Command} isearch-backward
+These two search commands are similar except @dots{}
+@end deffn
+
+Each of the other definition commands has an `x' form: @code{@@defunx},
+@code{@@defvrx}, @code{@@deftypefunx}, etc.
+
+The `x' forms work just like @code{@@itemx}; see @ref{itemx, , @code{@@itemx}}.
+
+@node Def Cmds in Detail, Def Cmd Conventions, deffnx, Definition Commands
+@section The Definition Commands
+
+Texinfo provides more than a dozen definition commands, all of which
+are described in this section.@refill
+
+The definition commands automatically enter the name of the entity in
+the appropriate index: for example, @code{@@deffn}, @code{@@defun},
+and @code{@@defmac} enter function names in the index of functions;
+@code{@@defvr} and @code{@@defvar} enter variable names in the index
+of variables.@refill
+
+Although the examples that follow mostly illustrate Lisp, the commands
+can be used for other programming languages.@refill
+
+@menu
+* Functions Commands:: Commands for functions and similar entities.
+* Variables Commands:: Commands for variables and similar entities.
+* Typed Functions:: Commands for functions in typed languages.
+* Typed Variables:: Commands for variables in typed languages.
+* Abstract Objects:: Commands for object-oriented programming.
+* Data Types:: The definition command for data types.
+@end menu
+
+@node Functions Commands, Variables Commands, , Def Cmds in Detail
+@subsection Functions and Similar Entities
+
+This section describes the commands for describing functions and similar
+entities:@refill
+
+@table @code
+@findex deffn
+@item @@deffn @var{category} @var{name} @var{arguments}@dots{}
+The @code{@@deffn} command is the general definition command for
+functions, interactive commands, and similar entities that may take
+arguments. You must choose a term to describe the category of entity
+being defined; for example, ``Function'' could be used if the entity is
+a function. The @code{@@deffn} command is written at the beginning of a
+line and is followed on the same line by the category of entity being
+described, the name of this particular entity, and its arguments, if
+any. Terminate the definition with @code{@@end deffn} on a line of its
+own.@refill
+
+@need 750
+For example, here is a definition:
+
+@example
+@group
+@@deffn Command forward-char nchars
+Move point forward @@var@{nchars@} characters.
+@@end deffn
+@end group
+@end example
+
+@noindent
+This shows a rather terse definition for a ``command'' named
+@code{forward-char} with one argument, @var{nchars}.
+
+@code{@@deffn} prints argument names such as @var{nchars} in italics or
+upper case, as if @code{@@var} had been used, because we think of these
+names as metasyntactic variables---they stand for the actual argument
+values. Within the text of the description, write an argument name
+explicitly with @code{@@var} to refer to the value of the argument. In
+the example above, we used @samp{@@var@{nchars@}} in this way.
+
+The template for @code{@@deffn} is:
+
+@example
+@group
+@@deffn @var{category} @var{name} @var{arguments}@dots{}
+@var{body-of-definition}
+@@end deffn
+@end group
+@end example
+
+@findex defun
+@item @@defun @var{name} @var{arguments}@dots{}
+The @code{@@defun} command is the definition command for functions.
+@code{@@defun} is equivalent to @samp{@@deffn Function
+@dots{}}.@refill
+
+@need 800
+@noindent
+For example,
+
+@example
+@group
+@@defun set symbol new-value
+Change the value of the symbol @@var@{symbol@}
+to @@var@{new-value@}.
+@@end defun
+@end group
+@end example
+
+@noindent
+shows a rather terse definition for a function @code{set} whose
+arguments are @var{symbol} and @var{new-value}. The argument names on
+the @code{@@defun} line automatically appear in italics or upper case as
+if they were enclosed in @code{@@var}. Terminate the definition with
+@code{@@end defun} on a line of its own.@refill
+
+The template is:
+
+@example
+@group
+@@defun @var{function-name} @var{arguments}@dots{}
+@var{body-of-definition}
+@@end defun
+@end group
+@end example
+
+@code{@@defun} creates an entry in the index of functions.
+
+@findex defmac
+@item @@defmac @var{name} @var{arguments}@dots{}
+The @code{@@defmac} command is the definition command for macros.
+@code{@@defmac} is equivalent to @samp{@@deffn Macro @dots{}} and
+works like @code{@@defun}.@refill
+
+@findex defspec
+@item @@defspec @var{name} @var{arguments}@dots{}
+The @code{@@defspec} command is the definition command for special
+forms. (In Lisp, a special form is an entity much like a function.)
+@code{@@defspec} is equivalent to @samp{@@deffn @{Special Form@}
+@dots{}} and works like @code{@@defun}.@refill
+@end table
+
+@node Variables Commands, Typed Functions, Functions Commands, Def Cmds in Detail
+@subsection Variables and Similar Entities
+
+Here are the commands for defining variables and similar
+entities:@refill
+
+@table @code
+@findex defvr
+@item @@defvr @var{category} @var{name}
+The @code{@@defvr} command is a general definition command for
+something like a variable---an entity that records a value. You must
+choose a term to describe the category of entity being defined; for
+example, ``Variable'' could be used if the entity is a variable.
+Write the @code{@@defvr} command at the beginning of a line and
+followed it on the same line by the category of the entity and the
+name of the entity.@refill
+
+Capitalize the category name like a title. If the name of the
+category contains spaces, as in the name `User Option', write braces
+around it. Otherwise, the second word will be mistaken for the name
+of the entity, for example:
+
+@example
+@group
+@@defvr @{User Option@} fill-column
+This buffer-local variable specifies
+the maximum width of filled lines.
+@dots{}
+@@end defvr
+@end group
+@end example
+
+Terminate the definition with @code{@@end defvr} on a line of its
+own.@refill
+
+The template is:
+
+@example
+@group
+@@defvr @var{category} @var{name}
+@var{body-of-definition}
+@@end defvr
+@end group
+@end example
+
+@code{@@defvr} creates an entry in the index of variables for @var{name}.
+
+@findex defvar
+@item @@defvar @var{name}
+The @code{@@defvar} command is the definition command for variables.
+@code{@@defvar} is equivalent to @samp{@@defvr Variable
+@dots{}}.@refill
+
+@need 750
+For example:
+
+@example
+@group
+@@defvar kill-ring
+@dots{}
+@@end defvar
+@end group
+@end example
+
+The template is:
+
+@example
+@group
+@@defvar @var{name}
+@var{body-of-definition}
+@@end defvar
+@end group
+@end example
+
+@code{@@defvar} creates an entry in the index of variables for
+@var{name}.@refill
+
+@findex defopt
+@item @@defopt @var{name}
+The @code{@@defopt} command is the definition command for user
+options. @code{@@defopt} is equivalent to @samp{@@defvr @{User
+Option@} @dots{}} and works like @code{@@defvar}.@refill
+@end table
+
+@node Typed Functions, Typed Variables, Variables Commands, Def Cmds in Detail
+@subsection Functions in Typed Languages
+
+The @code{@@deftypefn} command and its variations are for describing
+functions in C or any other language in which you must declare types
+of variables and functions.@refill
+
+@table @code
+@findex deftypefn
+@item @@deftypefn @var{category} @var{data-type} @var{name} @var{arguments}@dots{}
+The @code{@@deftypefn} command is the general definition command for
+functions and similar entities that may take arguments and that are
+typed. The @code{@@deftypefn} command is written at the beginning of
+a line and is followed on the same line by the category of entity
+being described, the type of the returned value, the name of this
+particular entity, and its arguments, if any.@refill
+
+@need 800
+@noindent
+For example,
+
+@example
+@group
+@@deftypefn @{Library Function@} int foobar
+ (int @@var@{foo@}, float @@var@{bar@})
+@dots{}
+@@end deftypefn
+@end group
+@end example
+
+@need 1000
+@noindent
+(where the text before the ``@dots{}'', shown above as two lines, would
+actually be a single line in a real Texinfo file) produces the following
+in Info:
+
+@smallexample
+@group
+-- Library Function: int foobar (int FOO, float BAR)
+@dots{}
+@end group
+@end smallexample
+@iftex
+
+In a printed manual, it produces:
+
+@quotation
+@deftypefn {Library Function} int foobar (int @var{foo}, float @var{bar})
+@dots{}
+@end deftypefn
+@end quotation
+@end iftex
+
+This means that @code{foobar} is a ``library function'' that returns an
+@code{int}, and its arguments are @var{foo} (an @code{int}) and
+@var{bar} (a @code{float}).@refill
+
+The argument names that you write in @code{@@deftypefn} are not subject
+to an implicit @code{@@var}---since the actual names of the arguments in
+@code{@@deftypefn} are typically scattered among data type names and
+keywords, Texinfo cannot find them without help. Instead, you must write
+@code{@@var} explicitly around the argument names. In the example
+above, the argument names are @samp{foo} and @samp{bar}.@refill
+
+The template for @code{@@deftypefn} is:@refill
+
+@example
+@group
+@@deftypefn @var{category} @var{data-type} @var{name} @var{arguments} @dots{}
+@var{body-of-description}
+@@end deftypefn
+@end group
+@end example
+
+@noindent
+Note that if the @var{category} or @var{data type} is more than one
+word then it must be enclosed in braces to make it a single argument.@refill
+
+If you are describing a procedure in a language that has packages,
+such as Ada, you might consider using @code{@@deftypefn} in a manner
+somewhat contrary to the convention described in the preceding
+paragraphs.@refill
+
+@need 800
+@noindent
+For example:
+
+@example
+@group
+@@deftypefn stacks private push
+ (@@var@{s@}:in out stack;
+ @@var@{n@}:in integer)
+@dots{}
+@@end deftypefn
+@end group
+@end example
+
+@noindent
+(The @code{@@deftypefn} arguments are shown split into three lines, but
+would be a single line in a real Texinfo file.)
+
+In this instance, the procedure is classified as belonging to the
+package @code{stacks} rather than classified as a `procedure' and its
+data type is described as @code{private}. (The name of the procedure
+is @code{push}, and its arguments are @var{s} and @var{n}.)@refill
+
+@code{@@deftypefn} creates an entry in the index of functions for
+@var{name}.@refill
+
+@findex deftypefun
+@item @@deftypefun @var{data-type} @var{name} @var{arguments}@dots{}
+The @code{@@deftypefun} command is the specialized definition command
+for functions in typed languages. The command is equivalent to
+@samp{@@deftypefn Function @dots{}}.@refill
+
+@need 800
+@noindent
+Thus,
+
+@smallexample
+@group
+@@deftypefun int foobar (int @@var@{foo@}, float @@var@{bar@})
+@dots{}
+@@end deftypefun
+@end group
+@end smallexample
+
+@noindent
+produces the following in Info:
+
+@example
+@group
+-- Function: int foobar (int FOO, float BAR)
+@dots{}
+@end group
+@end example
+@iftex
+
+@need 800
+@noindent
+and the following in a printed manual:
+
+@quotation
+@deftypefun int foobar (int @var{foo}, float @var{bar})
+@dots{}
+@end deftypefun
+@end quotation
+@end iftex
+
+@need 800
+The template is:
+
+@example
+@group
+@@deftypefun @var{type} @var{name} @var{arguments}@dots{}
+@var{body-of-description}
+@@end deftypefun
+@end group
+@end example
+
+@code{@@deftypefun} creates an entry in the index of functions for
+@var{name}.@refill
+@end table
+
+@node Typed Variables, Abstract Objects, Typed Functions, Def Cmds in Detail
+@subsection Variables in Typed Languages
+
+Variables in typed languages are handled in a manner similar to
+functions in typed languages. @xref{Typed Functions}. The general
+definition command @code{@@deftypevr} corresponds to
+@code{@@deftypefn} and the specialized definition command
+@code{@@deftypevar} corresponds to @code{@@deftypefun}.@refill
+
+@table @code
+@findex deftypevr
+@item @@deftypevr @var{category} @var{data-type} @var{name}
+The @code{@@deftypevr} command is the general definition command for
+something like a variable in a typed language---an entity that records
+a value. You must choose a term to describe the category of the
+entity being defined; for example, ``Variable'' could be used if the
+entity is a variable.@refill
+
+The @code{@@deftypevr} command is written at the beginning of a line
+and is followed on the same line by the category of the entity
+being described, the data type, and the name of this particular
+entity.@refill
+
+@need 800
+@noindent
+For example:
+
+@example
+@group
+@@deftypevr @{Global Flag@} int enable
+@dots{}
+@@end deftypevr
+@end group
+@end example
+
+@noindent
+produces the following in Info:
+
+@example
+@group
+-- Global Flag: int enable
+@dots{}
+@end group
+@end example
+@iftex
+
+@noindent
+and the following in a printed manual:
+
+@quotation
+@deftypevr {Global Flag} int enable
+@dots{}
+@end deftypevr
+@end quotation
+@end iftex
+
+@need 800
+The template is:
+
+@example
+@@deftypevr @var{category} @var{data-type} @var{name}
+@var{body-of-description}
+@@end deftypevr
+@end example
+
+@code{@@deftypevr} creates an entry in the index of variables for
+@var{name}.@refill
+
+@findex deftypevar
+@item @@deftypevar @var{data-type} @var{name}
+The @code{@@deftypevar} command is the specialized definition command
+for variables in typed languages. @code{@@deftypevar} is equivalent
+to @samp{@@deftypevr Variable @dots{}}.@refill
+
+@need 800
+@noindent
+For example:
+
+@example
+@group
+@@deftypevar int fubar
+@dots{}
+@@end deftypevar
+@end group
+@end example
+
+@noindent
+produces the following in Info:
+
+@example
+@group
+-- Variable: int fubar
+@dots{}
+@end group
+@end example
+@iftex
+
+@need 800
+@noindent
+and the following in a printed manual:
+
+@quotation
+@deftypevar int fubar
+@dots{}
+@end deftypevar
+@end quotation
+@end iftex
+
+@need 800
+@noindent
+The template is:
+
+@example
+@group
+@@deftypevar @var{data-type} @var{name}
+@var{body-of-description}
+@@end deftypevar
+@end group
+@end example
+
+@code{@@deftypevar} creates an entry in the index of variables for
+@var{name}.@refill
+@end table
+
+@node Abstract Objects, Data Types, Typed Variables, Def Cmds in Detail
+@subsection Object-Oriented Programming
+
+Here are the commands for formatting descriptions about abstract
+objects, such as are used in object-oriented programming. A class is
+a defined type of abstract object. An instance of a class is a
+particular object that has the type of the class. An instance
+variable is a variable that belongs to the class but for which each
+instance has its own value.@refill
+
+In a definition, if the name of a class is truly a name defined in the
+programming system for a class, then you should write an @code{@@code}
+around it. Otherwise, it is printed in the usual text font.@refill
+
+@table @code
+@findex defcv
+@item @@defcv @var{category} @var{class} @var{name}
+The @code{@@defcv} command is the general definition command for
+variables associated with classes in object-oriented programming. The
+@code{@@defcv} command is followed by three arguments: the category of
+thing being defined, the class to which it belongs, and its
+name. Thus,@refill
+
+@example
+@group
+@@defcv @{Class Option@} Window border-pattern
+@dots{}
+@@end defcv
+@end group
+@end example
+
+@noindent
+illustrates how you would write the first line of a definition of the
+@code{border-pattern} class option of the class @code{Window}.@refill
+
+The template is
+
+@example
+@group
+@@defcv @var{category} @var{class} @var{name}
+@dots{}
+@@end defcv
+@end group
+@end example
+
+@code{@@defcv} creates an entry in the index of variables.
+
+@findex defivar
+@item @@defivar @var{class} @var{name}
+The @code{@@defivar} command is the definition command for instance
+variables in object-oriented programming. @code{@@defivar} is
+equivalent to @samp{@@defcv @{Instance Variable@} @dots{}}@refill
+
+The template is:
+
+@example
+@group
+@@defivar @var{class} @var{instance-variable-name}
+@var{body-of-definition}
+@@end defivar
+@end group
+@end example
+
+@code{@@defivar} creates an entry in the index of variables.
+
+@findex defop
+@item @@defop @var{category} @var{class} @var{name} @var{arguments}@dots{}
+The @code{@@defop} command is the general definition command for
+entities that may resemble methods in object-oriented programming.
+These entities take arguments, as functions do, but are associated
+with particular classes of objects.@refill
+
+For example, some systems have constructs called @dfn{wrappers} that
+are associated with classes as methods are, but that act more like
+macros than like functions. You could use @code{@@defop Wrapper} to
+describe one of these.@refill
+
+Sometimes it is useful to distinguish methods and @dfn{operations}.
+You can think of an operation as the specification for a method.
+Thus, a window system might specify that all window classes have a
+method named @code{expose}; we would say that this window system
+defines an @code{expose} operation on windows in general. Typically,
+the operation has a name and also specifies the pattern of arguments;
+all methods that implement the operation must accept the same
+arguments, since applications that use the operation do so without
+knowing which method will implement it.@refill
+
+Often it makes more sense to document operations than methods. For
+example, window application developers need to know about the
+@code{expose} operation, but need not be concerned with whether a
+given class of windows has its own method to implement this operation.
+To describe this operation, you would write:@refill
+
+@example
+@@defop Operation windows expose
+@end example
+
+The @code{@@defop} command is written at the beginning of a line and
+is followed on the same line by the overall name of the category of
+operation, the name of the class of the operation, the name of the
+operation, and its arguments, if any.@refill
+
+@need 800
+@noindent
+The template is:
+
+@example
+@group
+@@defop @var{category} @var{class} @var{name} @var{arguments}@dots{}
+@var{body-of-definition}
+@@end defop
+@end group
+@end example
+
+@code{@@defop} creates an entry, such as `@code{expose} on
+@code{windows}', in the index of functions.@refill
+
+@findex defmethod
+@item @@defmethod @var{class} @var{name} @var{arguments}@dots{}
+The @code{@@defmethod} command is the definition command for methods
+in object-oriented programming. A method is a kind of function that
+implements an operation for a particular class of objects and its
+subclasses. In the Lisp Machine, methods actually were functions, but
+they were usually defined with @code{defmethod}.
+
+@code{@@defmethod} is equivalent to @samp{@@defop Method @dots{}}.
+The command is written at the beginning of a line and is followed by
+the name of the class of the method, the name of the method, and its
+arguments, if any.@refill
+
+@need 800
+@noindent
+For example,
+
+@example
+@group
+@@defmethod @code{bar-class} bar-method argument
+@dots{}
+@@end defmethod
+@end group
+@end example
+
+@noindent
+illustrates the definition for a method called @code{bar-method} of
+the class @code{bar-class}. The method takes an argument.@refill
+
+The template is:
+
+@example
+@group
+@@defmethod @var{class} @var{method-name} @var{arguments}@dots{}
+@var{body-of-definition}
+@@end defmethod
+@end group
+@end example
+
+@c !!! reworded to prevent overfull hbox --bob 26 Mar 93
+@code{@@defmethod} creates an entry in the index of functions, such as
+`@code{bar-method} on @code{bar-class}'.@refill
+@end table
+
+@node Data Types, , Abstract Objects, Def Cmds in Detail
+@subsection Data Types
+
+Here is the command for data types:@refill
+
+@table @code
+@findex deftp
+@item @@deftp @var{category} @var{name} @var{attributes}@dots{}
+The @code{@@deftp} command is the generic definition command for data
+types. The command is written at the beginning of a line and is
+followed on the same line by the category, by the name of the type
+(which is a word like @code{int} or @code{float}), and then by names of
+attributes of objects of that type. Thus, you could use this command
+for describing @code{int} or @code{float}, in which case you could use
+@code{data type} as the category. (A data type is a category of
+certain objects for purposes of deciding which operations can be
+performed on them.)@refill
+
+In Lisp, for example, @dfn{pair} names a particular data
+type, and an object of that type has two slots called the
+@sc{car} and the @sc{cdr}. Here is how you would write the first line
+of a definition of @code{pair}.@refill
+
+@example
+@group
+@@deftp @{Data type@} pair car cdr
+@dots{}
+@@end deftp
+@end group
+@end example
+
+@need 950
+The template is:
+
+@example
+@group
+@@deftp @var{category} @var{name-of-type} @var{attributes}@dots{}
+@var{body-of-definition}
+@@end deftp
+@end group
+@end example
+
+@code{@@deftp} creates an entry in the index of data types.
+@end table
+
+@node Def Cmd Conventions, Sample Function Definition, Def Cmds in Detail, Definition Commands
+@section Conventions for Writing Definitions
+@cindex Definition conventions
+@cindex Conventions for writing definitions
+
+When you write a definition using @code{@@deffn}, @code{@@defun}, or
+one of the other definition commands, please take care to use
+arguments that indicate the meaning, as with the @var{count} argument
+to the @code{forward-word} function. Also, if the name of an argument
+contains the name of a type, such as @var{integer}, take care that the
+argument actually is of that type.@refill
+
+@node Sample Function Definition, , Def Cmd Conventions, Definition Commands
+@section A Sample Function Definition
+@cindex Function definitions
+@cindex Command definitions
+@cindex Macro definitions
+@cindex Sample function definition
+
+A function definition uses the @code{@@defun} and @code{@@end defun}
+commands. The name of the function follows immediately after the
+@code{@@defun} command and it is followed, on the same line, by the
+parameter list.@refill
+
+Here is a definition from @cite{The GNU Emacs Lisp Reference Manual}.
+(@xref{Calling Functions, , Calling Functions, elisp, The GNU Emacs
+Lisp Reference Manual}.)
+
+@quotation
+@defun apply function &rest arguments
+@code{apply} calls @var{function} with @var{arguments}, just
+like @code{funcall} but with one difference: the last of
+@var{arguments} is a list of arguments to give to
+@var{function}, rather than a single argument. We also say
+that this list is @dfn{appended} to the other arguments.
+
+@code{apply} returns the result of calling @var{function}.
+As with @code{funcall}, @var{function} must either be a Lisp
+function or a primitive function; special forms and macros
+do not make sense in @code{apply}.
+
+@example
+(setq f 'list)
+ @result{} list
+(apply f 'x 'y 'z)
+@error{} Wrong type argument: listp, z
+(apply '+ 1 2 '(3 4))
+ @result{} 10
+(apply '+ '(1 2 3 4))
+ @result{} 10
+
+(apply 'append '((a b c) nil (x y z) nil))
+ @result{} (a b c x y z)
+@end example
+
+An interesting example of using @code{apply} is found in the description
+of @code{mapcar}.@refill
+@end defun
+@end quotation
+
+@need 1200
+In the Texinfo source file, this example looks like this:
+
+@example
+@group
+@@defun apply function &rest arguments
+
+@@code@{apply@} calls @@var@{function@} with
+@@var@{arguments@}, just like @@code@{funcall@} but with one
+difference: the last of @@var@{arguments@} is a list of
+arguments to give to @@var@{function@}, rather than a single
+argument. We also say that this list is @@dfn@{appended@}
+to the other arguments.
+@end group
+
+@group
+@@code@{apply@} returns the result of calling
+@@var@{function@}. As with @@code@{funcall@},
+@@var@{function@} must either be a Lisp function or a
+primitive function; special forms and macros do not make
+sense in @@code@{apply@}.
+@end group
+
+@group
+@@example
+(setq f 'list)
+ @@result@{@} list
+(apply f 'x 'y 'z)
+@@error@{@} Wrong type argument: listp, z
+(apply '+ 1 2 '(3 4))
+ @@result@{@} 10
+(apply '+ '(1 2 3 4))
+ @@result@{@} 10
+
+(apply 'append '((a b c) nil (x y z) nil))
+ @@result@{@} (a b c x y z)
+@@end example
+@end group
+
+@group
+An interesting example of using @@code@{apply@} is found
+in the description of @@code@{mapcar@}.@@refill
+@@end defun
+@end group
+@end example
+
+@noindent
+In this manual, this function is listed in the Command and Variable
+Index under @code{apply}.@refill
+
+Ordinary variables and user options are described using a format like
+that for functions except that variables do not take arguments.
+
+@node Footnotes, Conditionals, Definition Commands, Top
+@comment node-name, next, previous, up
+@chapter Footnotes
+@cindex Footnotes
+@findex footnote
+
+A @dfn{footnote} is for a reference that documents or elucidates the
+primary text.@footnote{A footnote should complement or expand upon
+the primary text, but a reader should not need to read a footnote to
+understand the primary text. For a thorough discussion of footnotes,
+see @cite{The Chicago Manual of Style}, which is published by the
+University of Chicago Press.}@refill
+
+In Texinfo, footnotes are created with the @code{@@footnote} command.
+This command is followed immediately by a left brace, then by the text
+of the footnote, and then by a terminating right brace. The template
+is:
+
+@example
+@@footnote@{@var{text}@}
+@end example
+
+Footnotes may be of any length, but are usually short.@refill
+
+For example, this clause is followed by a sample
+footnote@footnote{Here is the sample footnote.}; in the Texinfo
+source, it looks like this:@refill
+
+@example
+@dots{}a sample footnote @@footnote@{Here is the sample
+footnote.@}; in the Texinfo source@dots{}
+@end example
+
+In a printed manual or book, the reference mark for a footnote is a
+small, superscripted number; the text of the footnote is written at
+the bottom of the page, below a horizontal line.@refill
+
+In Info, the reference mark for a footnote is a pair of parentheses
+with the footnote number between them, like this: @samp{(1)}.@refill
+
+Info has two footnote styles, which determine where the text of the
+footnote is located:@refill
+
+@itemize @bullet
+@cindex @samp{@r{End}} node footnote style
+@item
+In the `End' node style, all the footnotes for a single node
+are placed at the end of that node. The footnotes are separated from
+the rest of the node by a line of dashes with the word
+@samp{Footnotes} within it. Each footnote begins with an
+@samp{(@var{n})} reference mark.@refill
+
+@need 700
+@noindent
+Here is an example of a single footnote in the end of node style:@refill
+
+@example
+@group
+ --------- Footnotes ---------
+
+(1) Here is a sample footnote.
+@end group
+@end example
+
+@cindex @samp{@r{Separate}} footnote style
+@item
+In the `Separate' node style, all the footnotes for a single
+node are placed in an automatically constructed node of
+their own. In this style, a ``footnote reference'' follows
+each @samp{(@var{n})} reference mark in the body of the
+node. The footnote reference is actually a cross reference
+which you use to reach the footnote node.@refill
+
+The name of the node containing the footnotes is constructed
+by appending @w{@samp{-Footnotes}} to the name of the node
+that contains the footnotes. (Consequently, the footnotes'
+node for the @file{Footnotes} node is
+@w{@file{Footnotes-Footnotes}}!) The footnotes' node has an
+`Up' node pointer that leads back to its parent node.@refill
+
+@noindent
+Here is how the first footnote in this manual looks after being
+formatted for Info in the separate node style:@refill
+
+@smallexample
+@group
+File: texinfo.info Node: Overview-Footnotes, Up: Overview
+
+(1) Note that the first syllable of "Texinfo" is
+pronounced like "speck", not "hex". @dots{}
+@end group
+@end smallexample
+@end itemize
+
+A Texinfo file may be formatted into an Info file with either footnote
+style.@refill
+
+@findex footnotestyle
+Use the @code{@@footnotestyle} command to specify an Info file's
+footnote style. Write this command at the beginning of a line followed
+by an argument, either @samp{end} for the end node style or
+@samp{separate} for the separate node style.
+
+@need 700
+For example,
+
+@example
+@@footnotestyle end
+@end example
+@noindent
+or
+@example
+@@footnotestyle separate
+@end example
+
+Write an @code{@@footnotestyle} command before or shortly after the
+end-of-header line at the beginning of a Texinfo file. (If you
+include the @code{@@footnotestyle} command between the start-of-header
+and end-of-header lines, the region formatting commands will format
+footnotes as specified.)@refill
+
+@c !!! changed wording to prevent overfull hbox --bob 26 Mar 93
+If you do not specify a footnote style, the formatting commands use
+their default style. Currently, @code{makeinfo} uses the `end' style,
+while @code{texinfo-format-buffer} and @code{texinfo-format-region}
+use the `separate' style.@refill
+
+@c !!! note: makeinfo's --footnote-style option overrides footnotestyle
+@ignore
+If you use @code{makeinfo} to create the Info file, the
+@samp{--footnote-style} option determines which style is used,
+@samp{end} for the end of node style or @samp{separate} for the
+separate node style. Thus, to format the Texinfo manual in the
+separate node style, you would use the following shell command:@refill
+
+@example
+makeinfo --footnote-style=separate texinfo.texi
+@end example
+
+@noindent
+To format the Texinfo manual in the end of node style, you would
+type:@refill
+
+@example
+makeinfo --footnote-style=end texinfo.texi
+@end example
+@end ignore
+@ignore
+If you use @code{texinfo-format-buffer} or
+@code{texinfo-format-region} to create the Info file, the value of the
+@code{texinfo-footnote-style} variable controls the footnote style.
+It can be either @samp{"separate"} for the separate node style or
+@samp{"end"} for the end of node style. (You can change the value of
+this variable with the @kbd{M-x edit-options} command (@pxref{Edit
+Options, , Editing Variable Values, emacs, The GNU Emacs Manual}), or
+with the @kbd{M-x set-variable} command (@pxref{Examining, , Examining
+and Setting Variables, emacs, The GNU Emacs Manual}).@refill
+
+The @code{texinfo-footnote-style} variable also controls the style if
+you use the @kbd{M-x makeinfo-region} or @kbd{M-x makeinfo-buffer}
+command in Emacs.@refill
+@end ignore
+This chapter contains two footnotes.@refill
+
+@node Conditionals, Format/Print Hardcopy, Footnotes, Top
+@comment node-name, next, previous, up
+@chapter Conditionally Visible Text
+@cindex Conditionally visible text
+@cindex Text, conditionally visible
+@cindex Visibility of conditional text
+@cindex If text conditionally visible
+@findex ifinfo
+@findex iftex
+
+Sometimes it is good to use different text for a printed manual and
+its corresponding Info file. In this case, you can use the
+@dfn{conditional commands} to specify which text is for the printed manual
+and which is for the Info file.@refill
+
+@menu
+* Conditional Commands:: How to specify text for Info or @TeX{}.
+* Using Ordinary TeX Commands:: You can use any and all @TeX{} commands.
+* set clear value:: How to designate which text to format (for
+ both Info and @TeX{}); and how to set a
+ flag to a string that you can insert.
+@end menu
+
+@node Conditional Commands, Using Ordinary TeX Commands, , Conditionals
+@ifinfo
+@heading Using @code{@@ifinfo} and @code{@@iftex}
+@end ifinfo
+
+@code{@@ifinfo} begins segments of text that should be ignored
+by @TeX{} when it
+typesets the printed manual. The segment of text appears only
+in the Info file.
+The @code{@@ifinfo} command should appear on a line by itself; end
+the Info-only text with a line containing @code{@@end ifinfo} by
+itself. At the beginning of a Texinfo file, the Info permissions are
+contained within a region marked by @code{@@ifinfo} and @code{@@end
+ifinfo}. (@xref{Info Summary and Permissions}.)@refill
+
+The @code{@@iftex} and @code{@@end iftex} commands are similar to the
+@code{@@ifinfo} and @code{@@end ifinfo} commands, except that they
+specify text that will appear in the printed manual but not in the Info
+file.@refill
+
+@need 700
+For example,
+
+@example
+@@iftex
+This text will appear only in the printed manual.
+@@end iftex
+
+@@ifinfo
+However, this text will appear only in Info.
+@@end ifinfo
+@end example
+
+@noindent
+The preceding example produces the following line:
+
+@iftex
+This text will appear only in the printed manual.
+@end iftex
+
+@ifinfo
+However, this text will appear only in Info.
+@end ifinfo
+
+@noindent
+Note how you only see one of the two lines, depending on whether you
+are reading the Info version or the printed version of this
+manual.@refill
+
+The @code{@@titlepage} command is a special variant of @code{@@iftex} that
+is used for making the title and copyright pages of the printed
+manual. (@xref{titlepage, , @code{@@titlepage}}.) @refill
+
+@node Using Ordinary TeX Commands, set clear value, Conditional Commands, Conditionals
+@comment node-name, next, previous, up
+@section Using Ordinary @TeX{} Commands
+@cindex @TeX{} commands, using ordinary
+@cindex Ordinary @TeX{} commands, using
+@cindex Commands using ordinary @TeX{}
+@cindex Plain@TeX{}
+
+Inside a region delineated by @code{@@iftex} and @code{@@end iftex},
+you can embed some Plain@TeX{} commands. Info will ignore these
+commands since they are only in that part of the file which is seen by
+@TeX{}. You can write the @TeX{} commands as you would write them in
+a normal @TeX{} file, except that you must replace the @samp{\} used
+by @TeX{} with an @samp{@@}. For example, in the @code{@@titlepage}
+section of a Texinfo file, you can use the @TeX{} command
+@code{@@vskip} to format the copyright page. (The @code{@@titlepage}
+command causes Info to ignore the region automatically, as it does
+with the @code{@@iftex} command.)@refill
+
+However, many features of Plain@TeX{} will not work, as they are
+overridden by features of Texinfo.
+
+@findex tex
+You can enter Plain@TeX{} completely, and use @samp{\} in the @TeX{}
+commands, by delineating a region with the @code{@@tex} and @code{@@end
+tex} commands. (The @code{@@tex} command also causes Info to ignore the
+region, like the @code{@@iftex}
+command.)@refill
+
+@cindex Mathematical expressions
+For example, here is a mathematical expression written in
+Plain@TeX{}:@refill
+
+@example
+@@tex
+$$ \chi^2 = \sum_@{i=1@}^N
+ \left (y_i - (a + b x_i)
+ \over \sigma_i\right)^2 $$
+@@end tex
+@end example
+
+@noindent
+The output of this example will appear only in a printed manual. If
+you are reading this in Info, you will not see anything after this
+paragraph.
+@iftex
+In a printed manual, the above expression looks like
+this:
+@end iftex
+
+@tex
+$$ \chi^2 = \sum_{i=1}^N
+ \left(y_i - (a + b x_i)
+ \over \sigma_i\right)^2 $$
+@end tex
+
+@node set clear value, , Using Ordinary TeX Commands, Conditionals
+@comment node-name, next, previous, up
+@section @code{@@set}, @code{@@clear}, and @code{@@value}
+
+You can direct the Texinfo formatting commands to format or ignore parts
+of a Texinfo file with the @code{@@set}, @code{@@clear}, @code{@@ifset},
+and @code{@@ifclear} commands.@refill
+
+In addition, you can use the @code{@@set @var{flag}} command to set the
+value of @var{flag} to a string of characters; and use
+@code{@@value@{@var{flag}@}} to insert that string. You can use
+@code{@@set}, for example, to set a date and use @code{@@value} to
+insert the date in several places in the Texinfo file.@refill
+
+@menu
+* ifset ifclear:: Format a region if a flag is set.
+* value:: Replace a flag with a string.
+* value Example:: An easy way to update edition information.
+@end menu
+
+@node ifset ifclear, value, , set clear value
+@subsection @code{@@ifset} and @code{@@ifclear}
+
+@findex ifset
+When a @var{flag} is set, the Texinfo formatting commands format text
+between subsequent pairs of @code{@@ifset @var{flag}} and @code{@@end
+ifset} commands. When the @var{flag} is cleared, the Texinfo formatting
+commands do @emph{not} format the text.
+
+Use the @code{@@set @var{flag}} command to turn on, or @dfn{set}, a
+@var{flag}; a @dfn{flag} can be any single word. The format for the
+command looks like this:@refill
+@findex set
+
+@example
+@@set @var{flag}
+@end example
+
+Write the conditionally formatted text between @code{@@ifset @var{flag}}
+and @code{@@end ifset} commands, like this:@refill
+
+@example
+@group
+@@ifset @var{flag}
+@var{conditional-text}
+@@end ifset
+@end group
+@end example
+
+For example, you can create one document that has two variants, such as
+a manual for a `large' and `small' model:@refill
+
+@example
+You can use this machine to dig up shrubs
+without hurting them.
+
+@@set large
+
+@@ifset large
+It can also dig up fully grown trees.
+@@end ifset
+
+Remember to replant promptly @dots{}
+@end example
+
+@noindent
+In the example, the formatting commands will format the text between
+@code{@@ifset large} and @code{@@end ifset} because the @code{large}
+flag is set.@refill
+
+@findex clear
+Use the @code{@@clear @var{flag}} command to turn off, or @dfn{clear},
+a flag. Clearing a flag is the opposite of setting a flag. The
+command looks like this:@refill
+
+@example
+@@clear @var{flag}
+@end example
+
+@noindent
+Write the command on a line of its own.
+
+When @var{flag} is cleared, the Texinfo formatting commands do
+@emph{not} format the text between @code{@@ifset @var{flag}} and
+@code{@@end ifset}; that text is ignored and does not appear in either
+printed or Info output.@refill
+
+For example, if you clear the flag of the preceding example by writing
+an @code{@@clear large} command after the @code{@@set large} command
+(but before the conditional text), then the Texinfo formatting commands
+ignore the text between the @code{@@ifset large} and @code{@@end ifset}
+commands. In the formatted output, that text does not appear; in both
+printed and Info output, you see only the lines that say, ``You can use
+this machine to dig up shrubs without hurting them. Remember to replant
+promptly @dots{}''.
+
+@findex ifclear
+If a flag is cleared with an @code{@@clear @var{flag}} command, then
+the formatting commands format text between subsequent pairs of
+@code{@@ifclear} and @code{@@end ifclear} commands. But if the flag
+is set with @code{@@set @var{flag}}, then the formatting commands do
+@emph{not} format text between an @code{@@ifclear} and an @code{@@end
+ifclear} command; rather, they ignore that text. An @code{@@ifclear}
+command looks like this:@refill
+
+@example
+@@ifclear @var{flag}
+@end example
+
+@need 700
+In brief, the commands are:@refill
+
+@table @code
+@item @@set @var{flag}
+Tell the Texinfo formatting commands that @var{flag} is set.@refill
+
+@item @@clear @var{flag}
+Tell the Texinfo formatting commands that @var{flag} is cleared.@refill
+
+@item @@ifset @var{flag}
+If @var{flag} is set, tell the Texinfo formatting commands to format
+the text up to the following @code{@@end ifset} command.@refill
+
+If @var{flag} is cleared, tell the Texinfo formatting commands to
+ignore text up to the following @code{@@end ifset} command.@refill
+
+@item @@ifclear @var{flag}
+If @var{flag} is set, tell the Texinfo formatting commands to ignore
+the text up to the following @code{@@end ifclear} command.@refill
+
+If @var{flag} is cleared, tell the Texinfo formatting commands to
+format the text up to the following @code{@@end ifclear}
+command.@refill
+@end table
+
+@node value, value Example, ifset ifclear, set clear value
+@subsection @code{@@value}
+@findex value
+
+You can use the @code{@@set} command to specify a value for a flag,
+which is expanded by the @code{@@value} command. The value is a string
+a characters.
+
+Write the @code{@@set} command like this:
+
+@example
+@@set foo This is a string.
+@end example
+
+@noindent
+This sets the value of @code{foo} to ``This is a string.''
+
+The Texinfo formatters replace an @code{@@value@{@var{flag}@}} command with
+the string to which @var{flag} is set.@refill
+
+Thus, when @code{foo} is set as shown above, the Texinfo formatters convert
+
+@example
+@group
+@@value@{foo@}
+@exdent @r{to}
+This is a string.
+@end group
+@end example
+
+You can write an @code{@@value} command within a paragraph; but you
+must write an @code{@@set} command on a line of its own.
+
+If you write the @code{@@set} command like this:
+
+@example
+@@set foo
+@end example
+
+@noindent
+without specifying a string, the value of @code{foo} is an empty string.
+
+If you clear a previously set flag with an @code{@@clear @var{flag}}
+command, a subsequent @code{@@value@{flag@}} command is invalid and the
+string is replaced with an error message that says @samp{@{No value for
+"@var{flag}"@}}.
+
+For example, if you set @code{foo} as follows:@refill
+
+@example
+@@set how-much very, very, very
+@end example
+
+@noindent
+then the formatters transform
+
+@example
+@group
+It is a @@value@{how-much@} wet day.
+@exdent @r{into}
+It is a very, very, very wet day.
+@end group
+@end example
+
+If you write
+
+@example
+@@clear how-much
+@end example
+
+@noindent
+then the formatters transform
+
+@example
+@group
+It is a @@value@{how-much@} wet day.
+@exdent @r{into}
+It is a @{No value for "how-much"@} wet day.
+@end group
+@end example
+
+@node value Example, , value, set clear value
+@subsection @code{@@value} Example
+
+You can use the @code{@@value} command to limit the number of places you
+need to change when you record an update to a manual.
+Here is how it is done in @cite{The GNU Make Manual}:
+
+@need 1000
+@noindent
+Set the flags:
+
+@example
+@group
+@@set EDITION 0.35 Beta
+@@set VERSION 3.63 Beta
+@@set UPDATED 14 August 1992
+@@set UPDATE-MONTH August 1992
+@end group
+@end example
+
+@need 750
+@noindent
+Write text for the first @code{@@ifinfo} section, for people reading the
+Texinfo file:
+
+@example
+@group
+This is Edition @@value@{EDITION@},
+last updated @@value@{UPDATED@},
+of @@cite@{The GNU Make Manual@},
+for @@code@{make@}, Version @@value@{VERSION@}.
+@end group
+@end example
+
+@need 1000
+@noindent
+Write text for the title page, for people reading the printed manual:
+@c List only the month and the year since that looks less fussy on a
+@c printed cover than a date that lists the day as well.
+
+@example
+@group
+@@title GNU Make
+@@subtitle A Program for Directing Recompilation
+@@subtitle Edition @@value@{EDITION@}, @dots{}
+@@subtitle @@value@{UPDATE-MONTH@}
+@end group
+@end example
+
+@noindent
+(On a printed cover, a date listing the month and the year looks less
+fussy than a date listing the day as well as the month and year.)
+
+@need 750
+@noindent
+Write text for the Top node, for people reading the Info file:
+
+@example
+@group
+This is Edition @@value@{EDITION@}
+of the @@cite@{GNU Make Manual@},
+last updated @@value@{UPDATED@}
+for @@code@{make@} Version @@value@{VERSION@}.
+@end group
+@end example
+
+@need 950
+After you format the manual, the text in the first @code{@@ifinfo}
+section looks like this:
+
+@example
+@group
+This is Edition 0.35 Beta, last updated 14 August 1992,
+of `The GNU Make Manual', for `make', Version 3.63 Beta.
+@end group
+@end example
+
+When you update the manual, change only the values of the flags; you do
+not need to rewrite the three sections.
+
+@node Format/Print Hardcopy, Create an Info File, Conditionals, Top
+@comment node-name, next, previous, up
+@chapter Format and Print Hardcopy
+@cindex Format and print hardcopy
+@cindex Hardcopy, printing it
+@cindex Making a printed manual
+@cindex Sorting indices
+@cindex Indices, sorting
+@cindex @TeX{} index sorting
+@findex texindex
+
+There are three major shell commands for making a printed manual from a
+Texinfo file: one for converting the Texinfo file into a file that will be
+printed, a second for sorting indices, and a third for printing the
+formatted document. When you use the shell commands, you can either
+work directly in the operating system shell or work within a shell
+inside GNU Emacs.@refill
+
+If you are using GNU Emacs, you can use commands provided by Texinfo
+mode instead of shell commands. In addition to the three commands to
+format a file, sort the indices, and print the result, Texinfo mode
+offers key bindings for commands to recenter the output buffer, show the
+print queue, and delete a job from the print queue.@refill
+
+@menu
+* Use TeX:: Use @TeX{} to format for hardcopy.
+* Shell Format & Print:: How to format and print a hardcopy manual
+ with shell commands.
+* Within Emacs:: How to format and print from an Emacs shell.
+* Texinfo Mode Printing:: How to format and print in Texinfo mode.
+* Compile-Command:: How to print using Emacs's compile command.
+* Requirements Summary:: @TeX{} formatting requirements summary.
+* Preparing for TeX:: What you need to do to use @TeX{}.
+* Overfull hboxes:: What are and what to do with overfull hboxes.
+* smallbook:: How to print small format books and manuals.
+* A4 Paper:: How to print on European A4 paper.
+* Cropmarks and Magnification:: How to print marks to indicate the size
+ of pages and how to print scaled up output.
+@end menu
+
+@node Use TeX, Shell Format & Print, , Format/Print Hardcopy
+@ifinfo
+@heading Use @TeX{}
+@end ifinfo
+
+The typesetting program called @TeX{} is used for formatting a Texinfo
+file. @TeX{} is a very powerful typesetting program and, if used right,
+does an exceptionally good job. @xref{Obtaining TeX, , How to Obtain
+@TeX{}}, for information on how to obtain @TeX{}.@refill
+
+The @code{makeinfo}, @code{texinfo-format-region}, and
+@code{texinfo-format-buffer} commands read the very same @@-commands
+in the Texinfo file as does @TeX{}, but process them differently to
+make an Info file; see @ref{Create an Info File}.@refill
+
+@node Shell Format & Print, Within Emacs, Use TeX, Format/Print Hardcopy
+@comment node-name, next, previous, up
+@section Format and Print Using Shell Commands
+
+@cindex DVI file
+Format the Texinfo file with the shell command @code{tex} followed by
+the name of the Texinfo file. This produces a formatted @sc{dvi} file
+as well as several auxiliary files containing indices, cross
+references, etc. The @sc{dvi} file (for @dfn{DeVice Independent}
+file) can be printed on a wide variety of printers.@refill
+
+The @code{tex} formatting command itself does not sort the indices; it
+writes an output file of unsorted index data. This is a misfeature of
+@TeX{}. Hence, to generate a printed index, you first need a sorted
+index to work from. The @code{texindex} command sorts indices. (The
+source file @file{texindex.c} comes as part of the standard GNU
+distribution and is usually installed when Emacs is installed.)@refill
+@findex texindex
+@ignore
+Usage: texindex [-k] [-T tempdir] infile [-o outfile] ...
+
+Each infile arg can optionally be followed by a `-o outfile' arg;
+for each infile that is not followed by a -o arg, the infile name with
+`s' (for `sorted') appended is used for the outfile.
+
+-T dir is the directory to put temp files in, instead of /tmp.
+-k means `keep tempfiles', for debugging.
+@end ignore
+
+The @code{tex} formatting command outputs unsorted index files under
+names that obey a standard convention. These names are the name of
+your main input file to the @code{tex} formatting command, with
+everything after the first period thrown away, and the two letter
+names of indices added at the end. For example, the raw index output
+files for the input file @file{foo.texinfo} would be @file{foo.cp},
+@file{foo.vr}, @file{foo.fn}, @file{foo.tp}, @file{foo.pg} and
+@file{foo.ky}. Those are exactly the arguments to give to
+@code{texindex}.@refill
+
+@need 1000
+Or else, you can use @samp{??} as ``wild-cards'' and give the command in
+this form:@refill
+
+@example
+texindex foo.??
+@end example
+
+@noindent
+This command will run @code{texindex} on all the unsorted index files,
+including any that you have defined yourself using @code{@@defindex}
+or @code{@@defcodeindex}. (You may execute @samp{texindex foo.??}
+even if there are similarly named files with two letter extensions
+that are not index files, such as @samp{foo.el}. The @code{texindex}
+command reports but otherwise ignores such files.)@refill
+
+For each file specified, @code{texindex} generates a sorted index file
+whose name is made by appending @samp{s} to the input file name. The
+@code{@@printindex} command knows to look for a file of that name.
+@code{texindex} does not alter the raw index output file.@refill
+
+After you have sorted the indices, you need to rerun the @code{tex}
+formatting command on the Texinfo file. This regenerates a formatted
+@sc{dvi} file with up-to-date index entries.@footnote{If you use more
+than one index and have cross references to an index other than the
+first, you must run @code{tex} @emph{three times} to get correct output:
+once to generate raw index data; again (after @code{texindex}) to output
+the text of the indices and determine their true page numbers; and a
+third time to output correct page numbers in cross references to them.
+However, cross references to indices are rare.}@refill
+
+To summarize, this is a three step process:
+
+@enumerate
+@item
+Run the @code{tex} formatting command on the Texinfo file. This
+generates the formatted @sc{dvi} file as well as the raw index files
+with two letter extensions.@refill
+
+@item
+Run the shell command @code{texindex} on the raw index files to sort
+them. This creates the corresponding sorted index files.@refill
+
+@item
+Rerun the @code{tex} formatting command on the Texinfo file. This
+regenerates a formatted @sc{dvi} file with the index entries in the
+correct order. This second run also corrects the page numbers for
+the cross references. (The tables of contents are always correct.)@refill
+@end enumerate
+
+You need not run @code{texindex} each time after you run the
+@code{tex} formatting. If you do not, on the next run, the @code{tex}
+formatting command will use whatever sorted index files happen to
+exist from the previous use of @code{texindex}. This is usually
+@sc{ok} while you are debugging.@refill
+
+@findex texi2dvi @r{(shell script)}
+Rather than type the @code{tex} and @code{texindex} commands yourself,
+you can use @code{texi2dvi}. This shell script is designed to
+simplify the @code{tex}---@code{texindex}---@code{tex} sequence by
+figuring out whether index files and @sc{dvi} files are up-to-date.
+It runs @code{texindex} and @code{tex} only when necessary.
+
+@need 1000
+The syntax for @code{texi2dvi} is like this (where @samp{%} is the
+shell prompt):@refill
+
+@example
+% texi2dvi @var{filename}@dots{}
+@end example
+
+@findex lpr @r{(@sc{dvi} print command)}
+Finally, you can print the @sc{dvi} file with the @sc{dvi} print command.
+The precise command to use depends on the system; @samp{lpr -d} is
+common. The @sc{dvi} print command may require a file name without any
+extension or with a @samp{.dvi} extension.@refill
+
+@need 1200
+The following commands, for example, sort the indices, format, and
+print the @cite{Bison Manual} (where @samp{%} is the shell
+prompt):@refill
+
+@example
+@group
+% tex bison.texinfo
+% texindex bison.??
+% tex bison.texinfo
+% lpr -d bison.dvi
+@end group
+@end example
+
+@noindent
+(Remember that the shell commands may be different at your site; but
+these are commonly used versions.)@refill
+
+@node Within Emacs, Texinfo Mode Printing, Shell Format & Print, Format/Print Hardcopy
+@comment node-name, next, previous, up
+@section From an Emacs Shell @dots{}
+@cindex Print, format from Emacs shell
+@cindex Format, print from Emacs shell
+@cindex Shell, format, print from
+@cindex Emacs shell, format, print from
+@cindex GNU Emacs shell, format, print from
+
+You can give formatting and printing commands from a shell within GNU
+Emacs. To create a shell within Emacs, type @kbd{M-x shell}. In this
+shell, you can format and print the document. @xref{Shell Format & Print, ,
+How to Format and Print Using Shell Commands}, for details.@refill
+
+You can switch to and from the shell buffer while @code{tex} is
+running and do other editing. If you are formatting a long document
+on a slow machine, this can be very convenient.@refill
+
+You can also use @code{texi2dvi} from an Emacs shell. For example,
+here is how to use @code{texi2dvi} to format and print @cite{Using and
+Porting GNU CC} from a shell within Emacs (where @samp{%} is the shell
+prompt):@refill
+
+@example
+@group
+% texi2dvi gcc.texinfo
+% lpr -d gcc.dvi
+@end group
+@end example
+@ifinfo
+
+@xref{Texinfo Mode Printing}, for more information about formatting
+and printing in Texinfo mode.@refill
+@end ifinfo
+
+@node Texinfo Mode Printing, Compile-Command, Within Emacs, Format/Print Hardcopy
+@section Formatting and Printing in Texinfo Mode
+@cindex Region printing in Texinfo mode
+@cindex Format and print in Texinfo mode
+@cindex Print and format in Texinfo mode
+
+Texinfo mode provides several predefined key commands for @TeX{}
+formatting and printing. These include commands for sorting indices,
+looking at the printer queue, killing the formatting job, and
+recentering the display of the buffer in which the operations
+occur.@refill
+
+@table @kbd
+@item C-c C-t C-r
+@itemx M-x texinfo-tex-region
+Run @TeX{} on the current region.@refill
+
+@item C-c C-t C-b
+@itemx M-x texinfo-tex-buffer
+Run @TeX{} on the current buffer.@refill
+
+@c !!! changed wording to prevent overfull hbox --bob 26 Mar 93
+@item C-c C-t C-i
+@itemx M-x texinfo-texindex
+Sort the indices of a Texinfo file that have been formatted with
+@code{texinfo-tex-region} or @code{texinfo-tex-buffer}.@refill
+
+@item C-c C-t C-p
+@itemx M-x texinfo-tex-print
+Print a @sc{dvi} file that was made with @code{texinfo-tex-region} or
+@code{texinfo-tex-buffer}.@refill
+
+@item C-c C-t C-q
+@itemx M-x texinfo-show-tex-print-queue
+Show the print queue.@refill
+
+@item C-c C-t C-d
+@itemx M-x texinfo-delete-from-tex-print-queue
+Delete a job from the print queue; you will be prompted for the job
+number shown by a preceding @kbd{C-c C-t C-q} command
+(@code{texinfo-show-tex-print-queue}).@refill
+
+@c !!! changed wording to prevent overfull hbox --bob 26 Mar 93
+@item C-c C-t C-k
+@itemx M-x texinfo-kill-tex-job
+Kill either the currently running @TeX{} job that has been started by
+@code{texinfo-tex-region} or @code{texinfo-tex-buffer}, or any other
+process running in the Texinfo shell buffer.@refill
+
+@item C-c C-t C-x
+@itemx M-x texinfo-quit-tex-job
+Quit a @TeX{} formatting job that has stopped because of an error by
+sending an @key{x} to it. When you do this, @TeX{} preserves a record
+of what it did in a @file{.log} file.@refill
+
+@item C-c C-t C-l
+@itemx M-x texinfo-recenter-tex-output-buffer
+Redisplay the shell buffer in which the @TeX{} printing and formatting
+commands are run to show its most recent output.@refill
+@end table
+
+Thus, the usual sequence of commands for formatting a buffer is as
+follows (with comments to the right):@refill
+
+@example
+@group
+C-c C-t C-b @r{Run @TeX{} on the buffer.}
+C-c C-t C-i @r{Sort the indices.}
+C-c C-t C-b @r{Rerun @TeX{} to regenerate indices.}
+C-c C-t C-p @r{Print the @sc{dvi} file.}
+C-c C-t C-q @r{Display the printer queue.}
+@end group
+@end example
+
+The Texinfo mode @TeX{} formatting commands start a subshell in Emacs
+called the @file{*texinfo-tex-shell*}. The @code{texinfo-tex-command},
+@code{texinfo-texindex-command}, and @code{tex-dvi-print-command}
+commands are all run in this shell.
+
+You can watch the commands operate in the @samp{*texinfo-tex-shell*} buffer,
+and you can switch to and from and use the @samp{*texinfo-tex-shell*} buffer
+as you would any other shell buffer.@refill
+
+@need 1500
+The formatting and print commands depend on the values of several variables.
+The default values are:@refill
+
+@sp 1
+@example
+@group
+ @r{Variable} @r{Default value}
+
+texinfo-tex-command "tex"
+texinfo-texindex-command "texindex"
+texinfo-tex-shell-cd-command "cd"
+texinfo-tex-dvi-print-command "lpr -d"
+texinfo-show-tex-queue-command "lpq"
+texinfo-delete-from-print-queue-command "lprm"
+texinfo-start-of-header "%**start"
+texinfo-end-of-header "%**end"
+texinfo-tex-trailer "@@bye"
+@end group
+@end example
+
+@c !!! changed wording to prevent overfull hbox --bob 26 Mar 93
+The default values of both the @code{texinfo-tex-command} and the
+@code{texinfo-texindex-command} variables are set in the @file{texnfo-tex.el}
+file.@refill
+
+You can change the values of these variables with the @kbd{M-x
+edit-options} command (@pxref{Edit Options, , Editing Variable Values,
+emacs, The GNU Emacs Manual}), with the @kbd{M-x set-variable} command
+(@pxref{Examining, , Examining and Setting Variables, emacs, The GNU
+Emacs Manual}), or with your @file{.emacs} initialization file
+(@pxref{Init File, , , emacs, The GNU Emacs Manual}).@refill
+
+@node Compile-Command, Requirements Summary, Texinfo Mode Printing, Format/Print Hardcopy
+@comment node-name, next, previous, up
+@section Using the Local Variables List
+@cindex Local variables
+@cindex Compile command for formatting
+@cindex Format with the compile command
+
+Yet another way to apply the @TeX{} formatting command to a Texinfo
+file is to put that command in a @dfn{local variables list} at the end
+of the Texinfo file. You can then specify the @TeX{} formatting
+command as a @code{compile-command} and have Emacs run the @TeX{}
+formatting command by typing @kbd{M-x compile}. This creates a
+special shell called the @samp{*compilation buffer*} in which Emacs
+runs the compile command. For example, at the end of the
+@file{gdb.texinfo} file, after the @code{@@bye}, you would put the
+following:@refill
+
+@example
+@@c Local Variables:
+@@c compile-command: "tex gdb.texinfo"
+@@c End:
+@end example
+
+@noindent
+This technique is most often used by programmers who also compile programs
+this way; see @ref{Compilation, , , emacs, The GNU Emacs Manual}.@refill
+
+@node Requirements Summary, Preparing for TeX, Compile-Command, Format/Print Hardcopy
+@comment node-name, next, previous, up
+@section @TeX{} Formatting Requirements Summary
+@cindex Requirements for formatting
+@cindex Formatting requirements
+
+Every Texinfo file that is to be input to @TeX{} must begin with a
+@code{\input} command and contain an @code{@@settitle} command:@refill
+
+@example
+\input texinfo
+@@settitle @var{name-of-manual}
+@end example
+
+@noindent
+The first command instructs @TeX{} to load the macros it needs to
+process a Texinfo file and the second command specifies the title of
+printed manual.@refill
+
+@need 1000
+Every Texinfo file must end with a line that terminates @TeX{}
+processing and forces out unfinished pages:@refill
+
+@example
+@@bye
+@end example
+
+Strictly speaking, these three lines are all a Texinfo file needs for
+@TeX{}, besides the body. (The @code{@@setfilename} line is the only
+line that a Texinfo file needs for Info formatting.)@refill
+
+Usually, the file's first line contains an @samp{@@c -*-texinfo-*-}
+comment that causes Emacs to switch to Texinfo mode when you edit the
+file. In addition, the beginning usually includes an
+@code{@@setfilename} for Info formatting, an @code{@@setchapternewpage}
+command, a title page, a copyright page, and permissions. Besides an
+@code{@@bye}, the end of a file usually includes indices and a table of
+contents.@refill
+
+@iftex
+For more information, see
+@ref{setchapternewpage, , @code{@@setchapternewpage}},
+@ref{Headings, ,Page Headings},
+@ref{Titlepage & Copyright Page},
+@ref{Printing Indices & Menus}, and
+@ref{Contents}.
+@end iftex
+@noindent
+@ifinfo
+For more information, see@*
+@ref{setchapternewpage, , @code{@@setchapternewpage}},@*
+@ref{Headings, ,Page Headings},@*
+@ref{Titlepage & Copyright Page},@*
+@ref{Printing Indices & Menus}, and@*
+@ref{Contents}.
+@end ifinfo
+
+@node Preparing for TeX, Overfull hboxes, Requirements Summary, Format/Print Hardcopy
+@comment node-name, next, previous, up
+@section Preparing to Use @TeX{}
+@cindex Preparing to use @TeX{}
+@cindex @TeX{} input initialization
+@cindex @code{TEXINPUTS} environment variable
+@vindex TEXINPUTS
+@cindex @b{.profile} initialization file
+@cindex @b{.cshrc} initialization file
+@cindex Initialization file for @TeX{} input
+
+@TeX{} needs to know where to find the @file{texinfo.tex} file
+that you have told it to input with the @samp{\input texinfo} command
+at the beginning of the first line. The @file{texinfo.tex} file tells
+@TeX{} how to handle @@-commands. (@file{texinfo.tex} is
+included in the standard GNU distributions.)@refill
+
+Usually, the @file{texinfo.tex} file is put in the default directory
+that contains @TeX{} macros (the @file{/usr/lib/tex/macros}
+directory) when GNU Emacs or other GNU software is installed.
+In this case, @TeX{} will
+find the file and you do not need to do anything special.
+Alternatively, you can put @file{texinfo.tex} in the directory in
+which the Texinfo source file is located, and @TeX{} will find it
+there.@refill
+
+However, you may want to specify the location of the @code{\input} file
+yourself. One way to do this is to write the complete path for the file
+after the @code{\input} command. Another way is to set the
+@code{TEXINPUTS} environment variable in your @file{.cshrc} or
+@file{.profile} file. The @code{TEXINPUTS} environment variable will tell
+@TeX{} where to find the @file{texinfo.tex} file and any other file that
+you might want @TeX{} to use.@refill
+
+Whether you use a @file{.cshrc} or @file{.profile} file depends on
+whether you use @code{csh}, @code{sh}, or @code{bash} for your shell
+command interpreter. When you use @code{csh}, it looks to the
+@file{.cshrc} file for initialization information, and when you use
+@code{sh} or @code{bash}, it looks to the @file{.profile} file.@refill
+
+@need 1000
+In a @file{.cshrc} file, you could use the following @code{csh} command
+sequence:@refill
+
+@example
+setenv TEXINPUTS .:/usr/me/mylib:/usr/lib/tex/macros
+@end example
+
+@need 1000
+In a @file{.profile} file, you could use the following @code{sh} command
+sequence:
+
+@example
+@group
+TEXINPUTS=.:/usr/me/mylib:/usr/lib/tex/macros
+export TEXINPUTS
+@end group
+@end example
+
+@noindent
+This would cause @TeX{} to look for @file{\input} file first in the current
+directory, indicated by the @samp{.}, then in a hypothetical user's
+@file{me/mylib} directory, and finally in the system library.@refill
+
+@node Overfull hboxes, smallbook, Preparing for TeX, Format/Print Hardcopy
+@comment node-name, next, previous, up
+@section Overfull ``hboxes''
+@cindex Overfull @samp{hboxes}
+@cindex @samp{hboxes}, overfull
+@cindex Final output
+
+@TeX{} is sometimes unable to typeset a line without extending it into
+the right margin. This can occur when @TeX{} comes upon what it
+interprets as a long word that it cannot hyphenate, such as an
+electronic mail network address or a very long title. When this
+happens, @TeX{} prints an error message like this:@refill
+
+@example
+Overfull \hbox (20.76302pt too wide)
+@end example
+
+@noindent
+(In @TeX{}, lines are in ``horizontal boxes'', hence the term, ``hbox''.
+The backslash, @samp{\}, is the @TeX{} equivalent of @samp{@@}.)@refill
+
+@TeX{} also provides the line number in the Texinfo source file and
+the text of the offending line, which is marked at all the places that
+@TeX{} knows how to hyphenate words.
+@xref{Debugging with TeX, , Catching Errors with @TeX{} Formatting},
+for more information about typesetting errors.@refill
+
+If the Texinfo file has an overfull hbox, you can rewrite the sentence
+so the overfull hbox does not occur, or you can decide to leave it. A
+small excursion into the right margin often does not matter and may not
+even be noticeable.@refill
+
+@cindex Black rectangle in hardcopy
+@cindex Rectangle, ugly, black in hardcopy
+However, unless told otherwise, @TeX{} will print a large, ugly, black
+rectangle beside the line that contains the overful hbox. This is so
+you will notice the location of the problem if you are correcting a
+draft.@refill
+
+@need 1000
+@findex finalout
+To prevent such a monstrosity from marring your final printout, write
+the following in the beginning of the Texinfo file on a line of its own,
+before the @code{@@titlepage} command:@refill
+
+@example
+@@finalout
+@end example
+
+@node smallbook, A4 Paper, Overfull hboxes, Format/Print Hardcopy
+@comment node-name, next, previous, up
+@section Printing ``Small'' Books
+@findex smallbook
+@cindex Small book size
+@cindex Book, printing small
+@cindex Page sizes for books
+@cindex Size of printed book
+
+By default, @TeX{} typesets pages for printing in an 8.5 by 11 inch
+format. However, you can direct @TeX{} to typeset a document in a 7 by
+9.25 inch format that is suitable for bound books by inserting the
+following command on a line by itself at the beginning of the Texinfo
+file, before the title page:@refill
+
+@example
+@@smallbook
+@end example
+
+@noindent
+(Since regular sized books are often about 7 by 9.25 inches, this
+command might better have been called the @code{@@regularbooksize}
+command, but it came to be called the @code{@@smallbook} command by
+comparison to the 8.5 by 11 inch format.)@refill
+
+If you write the @code{@@smallbook} command between the
+start-of-header and end-of-header lines, the Texinfo mode @TeX{}
+region formatting command, @code{texinfo-tex-region}, will format the
+region in ``small'' book size (@pxref{Start of Header}).@refill
+
+The Free Software Foundation distributes printed copies of @cite{The GNU
+Emacs Manual} and other manuals in the ``small'' book size.
+@xref{smallexample & smalllisp, , @code{@@smallexample} and
+@code{@@smalllisp}}, for information about commands that make it easier
+to produce examples for a smaller manual.@refill
+
+@node A4 Paper, Cropmarks and Magnification, smallbook, Format/Print Hardcopy
+@comment node-name, next, previous, up
+@section Printing on A4 Paper
+@cindex A4 paper, printing on
+@cindex Paper size, European A4
+@cindex European A4 paper
+@findex afourpaper
+
+You can tell @TeX{} to typeset a document for printing on European size
+A4 paper with the @code{@@afourpaper} command. Write the command on a
+line by itself between @code{@@iftex} and @code{@@end iftex} lines near
+the beginning of the Texinfo file, before the title page:@refill
+
+For example, this is how you would write the header for this manual:@refill
+
+@example
+@group
+\input texinfo @@c -*-texinfo-*-
+@@c %**start of header
+@@setfilename texinfo
+@@settitle Texinfo
+@@syncodeindex vr fn
+@@iftex
+@@afourpaper
+@@end iftex
+@@c %**end of header
+@end group
+@end example
+
+@node Cropmarks and Magnification, , A4 Paper, Format/Print Hardcopy
+@comment node-name, next, previous, up
+@section Cropmarks and Magnification
+
+@findex cropmarks
+@cindex Cropmarks for printing
+@cindex Printing cropmarks
+You can attempt to direct @TeX{} to print cropmarks at the corners of
+pages with the @code{@@cropmarks} command. Write the @code{@@cropmarks}
+command on a line by itself between @code{@@iftex} and @code{@@end
+iftex} lines near the beginning of the Texinfo file, before the title
+page, like this:@refill
+
+@example
+@group
+@@iftex
+@@cropmarks
+@@end iftex
+@end group
+@end example
+
+This command is mainly for printers that typeset several pages on one
+sheet of film; but you can attempt to use it to mark the corners of a
+book set to 7 by 9.25 inches with the @code{@@smallbook} command.
+(Printers will not produce cropmarks for regular sized output that is
+printed on regular sized paper.) Since different printing machines work
+in different ways, you should explore the use of this command with a
+spirit of adventure. You may have to redefine the command in the
+@file{texinfo.tex} definitions file.@refill
+
+@findex mag @r{(@TeX{} command)}
+@cindex Magnified printing
+@cindex Larger or smaller pages
+You can attempt to direct @TeX{} to typeset pages larger or smaller than
+usual with the @code{\mag} @TeX{} command. Everything that is typeset
+is scaled proportionally larger or smaller. (@code{\mag} stands for
+``magnification''.) This is @emph{not} a Texinfo @@-command, but is a
+Plain@TeX{} command that is prefixed with a backslash. You have to
+write this command between @code{@@tex} and @code{@@end tex}
+(@pxref{Using Ordinary TeX Commands, , Using Ordinary @TeX{}
+Commands}).@refill
+
+Follow the @code{\mag} command with an @samp{=} and then a number that
+is 1000 times the magnification you desire. For example, to print pages
+at 1.2 normal size, write the following near the beginning of the
+Texinfo file, before the title page:@refill
+
+@example
+@group
+@@tex
+\mag=1200
+@@end tex
+@end group
+@end example
+
+With some printing technologies, you can print normal-sized copies that
+look better than usual by using a larger-than-normal master.@refill
+
+Depending on your system, @code{\mag} may not work or may work only at
+certain magnifications. Be prepared to experiment.@refill
+
+@node Create an Info File, Install an Info File, Format/Print Hardcopy, Top
+@comment node-name, next, previous, up
+@chapter Creating an Info File
+@cindex Creating an Info file
+@cindex Info, creating an on-line file
+@cindex Formatting a file for Info
+
+@code{makeinfo} is a utility that converts a Texinfo file into an Info
+file; @code{texinfo-format-region} and @code{texinfo-format-buffer} are
+GNU Emacs functions that do the same.@refill
+
+A Texinfo file must possess an @code{@@setfilename} line near its
+beginning, otherwise the Info formatting commands will fail.@refill
+
+For information on installing the Info file in the Info system, see
+@ref{Install an Info File}.@refill
+
+@menu
+* makeinfo advantages:: @code{makeinfo} provides better error checking.
+* Invoking makeinfo:: How to run @code{makeinfo} from a shell.
+* makeinfo options:: Specify fill-column and other options.
+* Pointer Validation:: How to check that pointers point somewhere.
+* makeinfo in Emacs:: How to run @code{makeinfo} from Emacs.
+* texinfo-format commands:: Two Info formatting commands written
+ in Emacs Lisp are an alternative
+ to @code{makeinfo}.
+* Batch Formatting:: How to format for Info in Emacs Batch mode.
+* Tag and Split Files:: How tagged and split files help Info
+ to run better.
+@end menu
+
+@node makeinfo advantages, Invoking makeinfo, , Create an Info File
+@ifinfo
+@heading @code{makeinfo} Preferred
+@end ifinfo
+
+The @code{makeinfo} utility creates an Info file from a Texinfo source
+file more quickly than either of the Emacs formatting commands and
+provides better error messages. We recommend it. @code{makeinfo} is a
+C program that is independent of Emacs. You do not need to run Emacs to
+use @code{makeinfo}, which means you can use @code{makeinfo} on machines
+that are too small to run Emacs. You can run @code{makeinfo} in
+any one of three ways: from an operating system shell, from a shell
+inside Emacs, or by typing a key command in Texinfo mode in Emacs.
+@refill
+
+The @code{texinfo-format-region} and the @code{texinfo-format-buffer}
+commands are useful if you cannot run @code{makeinfo}. Also, in some
+circumstances, they format short regions or buffers more quickly than
+@code{makeinfo}.@refill
+
+@node Invoking makeinfo, makeinfo options, makeinfo advantages, Create an Info File
+@section Invoking @code{makeinfo} from a Shell
+
+To create an Info file from a Texinfo file, type @code{makeinfo}
+followed by the name of the Texinfo file. Thus, to create the Info
+file for Bison, type the following at the shell prompt (where @samp{%}
+is the prompt):@refill
+
+@example
+% makeinfo bison.texinfo
+@end example
+
+(You can run a shell inside Emacs by typing @kbd{M-x
+shell}.)@refill
+
+@ifinfo
+Sometimes you will want to specify options. For example, if you wish
+to discover which version of @code{makeinfo} you are using,
+type:@refill
+
+@example
+% makeinfo --version
+@end example
+
+@xref{makeinfo options}, for more information.
+@end ifinfo
+
+@node makeinfo options, Pointer Validation, Invoking makeinfo, Create an Info File
+@comment node-name, next, previous, up
+@section Options for @code{makeinfo}
+@cindex @code{makeinfo} options
+@cindex Options for @code{makeinfo}
+
+The @code{makeinfo} command takes a number of options. Most often,
+options are used to set the value of the fill column and specify the
+footnote style. Each command line option is a word preceded by
+@samp{--}@footnote{@samp{--} has replaced @samp{+}, the old introductory
+character, to maintain POSIX.2 compatibility without losing long-named
+options.} or a letter preceded by @samp{-}. You can use abbreviations
+for the option names as long as they are unique.@refill
+
+For example, you could use the following command to create an Info
+file for @file{bison.texinfo} in which each line is filled to only 68
+columns (where @samp{%} is the prompt):@refill
+
+@example
+% makeinfo --fill-column=68 bison.texinfo
+@end example
+
+You can write two or more options in sequence, like this:@refill
+
+@example
+% makeinfo --no-split --fill-column=70 @dots{}
+@end example
+
+@noindent
+This would keep the Info file together as one possibly very long
+file and would also set the fill column to 70.@refill
+
+@iftex
+If you wish to discover which version of @code{makeinfo}
+you are using, type:@refill
+
+@example
+% makeinfo --version
+@end example
+@end iftex
+
+The options are:@refill
+
+@need 100
+@table @code
+@item -D @var{var}
+Cause @var{var} to be defined. This is equivalent to
+@code{@@set @var{var}} in the Texinfo file.
+
+@need 150
+@item --error-limit @var{limit}
+Set the maximum number of errors that @code{makeinfo} will report
+before exiting (on the assumption that continuing would be useless).
+The default number of errors that can be reported before
+@code{makeinfo} gives up is 100.@refill
+
+@need 150
+@item --fill-column @var{width}
+Specify the maximum number of columns in a line; this is the right-hand
+edge of a line. Paragraphs that are filled will be filled to this
+width. (Filling is the process of breaking up and connecting lines so
+that lines are the same length as or shorter than the number specified
+as the fill column. Lines are broken between words.) The default value
+for @code{fill-column} is 72.
+@refill
+
+@item --footnote-style @var{style}
+Set the footnote style to @var{style}, either @samp{end} for the end
+node style or @samp{separate} for the separate node style. The value
+set by this option overrides the value set in a Texinfo file by an
+@code{@@footnotestyle} command. When the footnote style is
+@samp{separate}, @code{makeinfo} makes a new node containing the
+footnotes found in the current node. When the footnote style is
+@samp{end}, @code{makeinfo} places the footnote references at the end
+of the current node.@refill
+
+@need 150
+@item -I @var{dir}
+Add @code{dir} to the directory search list for finding files that are
+included using the @code{@@include} command. By default,
+@code{makeinfo} searches only the current directory.
+
+@need 150
+@item --no-headers
+Do not include menus or node lines in the output. This results in an
+@sc{ascii} file that you cannot read in Info since it does not contain
+the requisite nodes or menus; but you can print such a file in a
+single, typewriter-like font and produce acceptable output.
+
+@need 150
+@item --no-split
+Suppress the splitting stage of @code{makeinfo}. Normally, large
+output files (where the size is greater than 70k bytes) are split into
+smaller subfiles, each one approximately 50k bytes. If you specify
+@samp{--no-split}, @code{makeinfo} will not split up the output
+file.@refill
+
+@need 100
+@item --no-pointer-validate
+@item --no-validate
+Suppress the pointer-validation phase of @code{makeinfo}. Normally,
+after a Texinfo file is processed, some consistency checks are made to
+ensure that cross references can be resolved, etc.
+@xref{Pointer Validation}.@refill
+
+@need 150
+@item --no-warn
+Suppress the output of warning messages. This does @emph{not}
+suppress the output of error messages, only warnings. You might
+want this if the file you are creating has examples of Texinfo cross
+references within it, and the nodes that are referenced do not actually
+exist.@refill
+
+@item --no-number-footnotes
+Supress automatic footnote numbering. By default, @code{makeinfo}
+numbers each footnote sequentially in a single node, resetting the
+current footnote number to 1 at the start of each node.
+
+@need 150
+@item --output @var{file}
+@itemx -o @var{file}
+Specify that the output should be directed to @var{file} and not to the
+file name specified in the @code{@@setfilename} command found in the Texinfo
+source. @var{file} can be the special token @samp{-}, which specifies
+standard output.
+
+@need 150
+@item --paragraph-indent @var{indent}
+Set the paragraph indentation style to @var{indent}. The value set by
+this option overrides the value set in a Texinfo file by an
+@code{@@paragraphindent} command. The value of @var{indent} is
+interpreted as follows:@refill
+
+@itemize @bullet
+@item
+If the value of @var{indent} is @samp{asis}, do not change the
+existing indentation at the starts of paragraphs.@refill
+
+@item
+If the value of @var{indent} is zero, delete any existing
+indentation.@refill
+
+@item
+If the value of @var{indent} is greater than zero, indent each
+paragraph by that number of spaces.@refill
+@end itemize
+
+@need 100
+@item --reference-limit @var{limit}
+Set the value of the number of references to a node that
+@code{makeinfo} will make without reporting a warning. If a node has more
+than this number of references in it, @code{makeinfo} will make the
+references but also report a warning.@refill
+
+@need 150
+@item -U @var{var}
+Cause @var{var} to be undefined. This is equivalent to
+@code{@@clear @var{var}} in the Texinfo file.
+
+@need 100
+@item --verbose
+Cause @code{makeinfo} to display messages saying what it is doing.
+Normally, @code{makeinfo} only outputs messages if there are errors or
+warnings.@refill
+
+@need 100
+@item --version
+Report the version number of this copy of @code{makeinfo}.@refill
+@end table
+
+@node Pointer Validation, makeinfo in Emacs, makeinfo options, Create an Info File
+@section Pointer Validation
+@cindex Pointer validation with @code{makeinfo}
+@cindex Validation of pointers
+
+@c !!! changed wording to prevent overfull hbox --bob 26 Mar 93
+@code{makeinfo} will check the validity of the final Info file unless
+you suppress pointer-validation by using the
+@samp{--no-pointer-validation} option. Mostly, this means ensuring
+that nodes you have referenced really exist. Here is a complete list
+of what is checked:@refill
+
+@enumerate
+@item
+If a `Next', `Previous', or `Up' node reference is a reference to a
+node in the current file and is not an external reference such as to
+@file{(dir)}, then the referenced node must exist.@refill
+
+@item
+In every node, if the `Previous' node is different from the `Up' node,
+then the `Previous' node must also be pointed to by a `Next' node.@refill
+
+@item
+Every node except the `Top' node must have an `Up' pointer.@refill
+
+@item
+The node referenced by an `Up' pointer must contain a reference to the
+current node in some manner other than through a `Next' reference.
+This includes menu entries and cross references.@refill
+
+@item
+If the `Next' reference of a node is not the same as the `Next' reference
+of the `Up' reference, then the node referenced by the `Next' pointer
+must have a `Previous' pointer that points back to the current node.
+This rule allows the last node in a section to point to the first node
+of the next chapter.@refill
+@end enumerate
+
+@node makeinfo in Emacs, texinfo-format commands, Pointer Validation, Create an Info File
+@section Running @code{makeinfo} inside Emacs
+@cindex Running @code{makeinfo} in Emacs
+@cindex @code{makeinfo} inside Emacs
+@cindex Shell, running @code{makeinfo} in
+
+You can run @code{makeinfo} in GNU Emacs Texinfo mode by using either the
+@code{makeinfo-region} or the @code{makeinfo-buffer} commands. In
+Texinfo mode, the commands are bound to @kbd{C-c C-m C-r} and @kbd{C-c
+C-m C-b} by default.@refill
+
+@table @kbd
+@item C-c C-m C-r
+@itemx M-x makeinfo-region
+Format the current region for Info.@refill
+@findex makeinfo-region
+
+@item C-c C-m C-b
+@itemx M-x makeinfo-buffer
+Format the current buffer for Info.@refill
+@findex makeinfo-buffer
+@end table
+
+When you invoke either @code{makeinfo-region} or
+@code{makeinfo-buffer}, Emacs prompts for a file name, offering the
+name of the visited file as the default. You can edit the default
+file name in the minibuffer if you wish, before typing @key{RET} to
+start the @code{makeinfo} process.@refill
+
+The Emacs @code{makeinfo-region} and @code{makeinfo-buffer} commands
+run the @code{makeinfo} program in a temporary shell buffer. If
+@code{makeinfo} finds any errors, Emacs displays the error messages in
+the temporary buffer.@refill
+
+@cindex Errors, parsing
+@cindex Parsing errors
+@findex next-error
+You can parse the error messages by typing @kbd{C-x `}
+(@code{next-error}). This causes Emacs to go to and position the
+cursor on the line in the Texinfo source that @code{makeinfo} thinks
+caused the error. @xref{Compilation, , Running @code{make} or
+Compilers Generally, emacs, The GNU Emacs Manual}, for more
+information about using the @code{next-error} command.@refill
+
+In addition, you can kill the shell in which the @code{makeinfo}
+command is running or make the shell buffer display its most recent
+output.@refill
+
+
+@c !!! changed wording to prevent overfull hbox --bob 26 Mar 93
+@table @kbd
+@item C-c C-m C-k
+@itemx M-x makeinfo-kill-job
+@findex makeinfo-kill-job
+Kill the currently running job created by
+@code{makeinfo-region} or @code{makeinfo-buffer}.@refill
+
+@item C-c C-m C-l
+@itemx M-x makeinfo-recenter-output-buffer
+@findex makeinfo-recenter-output-buffer
+Redisplay the @code{makeinfo} shell buffer to display its most recent
+output.@refill
+@end table
+
+@noindent
+(Note that the parallel commands for killing and recentering a @TeX{}
+job are @kbd{C-c C-t C-k} and @kbd{C-c C-t C-l}. @xref{Texinfo Mode
+Printing}.)@refill
+
+You can specify options for @code{makeinfo} by setting the
+@code{makeinfo-options} variable with either the @kbd{M-x
+edit-options} or the @kbd{M-x set-variable} command, or by setting the
+variable in your @file{.emacs} initialization file.@refill
+
+For example, you could write the following in your @file{.emacs} file:@refill
+
+@example
+@group
+(setq makeinfo-options
+ "--paragraph-indent=0 --no-split
+ --fill-column=70 --verbose")
+@end group
+@end example
+
+@c If you write these three cross references using xref, you see
+@c three references to the same named manual, which looks strange.
+@iftex
+For more information, see @ref{makeinfo options, , Options for
+@code{makeinfo}}, as well as ``Editing Variable Values,''``Examining and
+Setting Variables,'' and ``Init File'' in the @cite{The GNU Emacs
+Manual}.
+@end iftex
+@noindent
+@ifinfo
+For more information, see@*
+@ref{Edit Options, , Editing Variable Values, emacs, The GNU Emacs Manual},@*
+@ref{Examining, , Examining and Setting Variables, emacs, The GNU Emacs Manual},@*
+@ref{Init File, , , emacs, The GNU Emacs Manual}, and@*
+@ref{makeinfo options, , Options for @code{makeinfo}}.
+@end ifinfo
+
+@node texinfo-format commands, Batch Formatting, makeinfo in Emacs, Create an Info File
+@comment node-name, next, previous, up
+@section The @code{texinfo-format@dots{}} Commands
+@findex texinfo-format-region
+@findex texinfo-format-buffer
+
+In GNU Emacs in Texinfo mode, you can format part or all of a Texinfo
+file with the @code{texinfo-format-region} command. This formats the
+current region and displays the formatted text in a temporary buffer
+called @samp{*Info Region*}.@refill
+
+Similarly, you can format a buffer with the
+@code{texinfo-format-buffer} command. This command creates a new
+buffer and generates the Info file in it. Typing @kbd{C-x C-s} will
+save the Info file under the name specified by the
+@code{@@setfilename} line which must be near the beginning of the
+Texinfo file.@refill
+
+@table @kbd
+@item C-c C-e C-r
+@itemx @code{texinfo-format-region}
+Format the current region for Info.
+@findex texinfo-format-region
+
+@item C-c C-e C-b
+@itemx @code{texinfo-format-buffer}
+Format the current buffer for Info.
+@findex texinfo-format-buffer
+@end table
+
+The @code{texinfo-format-region} and @code{texinfo-format-buffer}
+commands provide you with some error checking, and other functions can
+provide you with further help in finding formatting errors. These
+procedures are described in an appendix; see @ref{Catching Mistakes}.
+However, the @code{makeinfo} program is often faster and
+provides better error checking (@pxref{makeinfo in Emacs}).@refill
+
+@node Batch Formatting, Tag and Split Files, texinfo-format commands, Create an Info File
+@comment node-name, next, previous, up
+@section Batch Formatting
+@cindex Batch formatting for Info
+@cindex Info batch formatting
+
+You can format Texinfo files for Info using @code{batch-texinfo-format}
+and Emacs Batch mode. You can run Emacs in Batch mode from any shell,
+including a shell inside of Emacs. (@xref{Command Switches, , Command
+Line Switches and Arguments, emacs, The GNU Emacs Manual}.)@refill
+
+Here is the command to format all the files that end in @file{.texinfo}
+in the current directory (where @samp{%} is the shell prompt):@refill
+
+@example
+% emacs -batch -funcall batch-texinfo-format *.texinfo
+@end example
+
+@noindent
+Emacs processes all the files listed on the command line, even if an
+error occurs while attempting to format some of them.@refill
+
+Run @code{batch-texinfo-format} only with Emacs in Batch mode as shown;
+it is not interactive. It kills the Batch mode Emacs on completion.@refill
+
+@code{batch-texinfo-format} is convenient if you lack @code{makeinfo}
+and want to format several Texinfo files at once. When you use Batch
+mode, you create a new Emacs process. This frees your current Emacs, so
+you can continue working in it. (When you run
+@code{texinfo-format-region} or @code{texinfo-format-buffer}, you cannot
+use that Emacs for anything else until the command finishes.)@refill
+
+@node Tag and Split Files, , Batch Formatting, Create an Info File
+@comment node-name, next, previous, up
+@section Tag Files and Split Files
+@cindex Making a tag table automatically
+@cindex Tag table, making automatically
+
+If a Texinfo file has more than 30,000 bytes,
+@code{texinfo-format-buffer} automatically creates a tag table
+for its Info file; @code{makeinfo} always creates a tag table. With
+a @dfn{tag table}, Info can jump to new nodes more quickly than it can
+otherwise.@refill
+
+@cindex Indirect subfiles
+In addition, if the Texinfo file contains more than about 70,000
+bytes, @code{texinfo-format-buffer} and @code{makeinfo} split the
+large Info file into shorter @dfn{indirect} subfiles of about 50,000
+bytes each. Big files are split into smaller files so that Emacs does
+not need to make a large buffer to hold the whole of a large Info
+file; instead, Emacs allocates just enough memory for the small, split
+off file that is needed at the time. This way, Emacs avoids wasting
+memory when you run Info. (Before splitting was implemented, Info
+files were always kept short and @dfn{include files} were designed as
+a way to create a single, large printed manual out of the smaller Info
+files. @xref{Include Files}, for more information. Include files are
+still used for very large documents, such as @cite{The Emacs Lisp
+Reference Manual}, in which each chapter is a separate file.)@refill
+
+When a file is split, Info itself makes use of a shortened version of
+the original file that contains just the tag table and references to
+the files that were split off. The split off files are called
+@dfn{indirect} files.@refill
+
+The split off files have names that are created by appending @w{@samp{-1}},
+@w{@samp{-2}}, @w{@samp{-3}} and so on to the file name specified by the
+@code{@@setfilename} command. The shortened version of the original file
+continues to have the name specified by @code{@@setfilename}.@refill
+
+At one stage in writing this document, for example, the Info file was saved
+as @file{test-texinfo} and that file looked like this:@refill
+
+@example
+@group
+Info file: test-texinfo, -*-Text-*-
+produced by texinfo-format-buffer
+from file: new-texinfo-manual.texinfo
+
+^_
+Indirect:
+test-texinfo-1: 102
+test-texinfo-2: 50422
+test-texinfo-3: 101300
+^_^L
+Tag table:
+(Indirect)
+Node: overview^?104
+Node: info file^?1271
+Node: printed manual^?4853
+Node: conventions^?6855
+@dots{}
+@end group
+@end example
+
+@noindent
+(But @file{test-texinfo} had far more nodes than are shown here.) Each of
+the split off, indirect files, @file{test-texinfo-1},
+@file{test-texinfo-2}, and @file{test-texinfo-3}, is listed in this file
+after the line that says @samp{Indirect:}. The tag table is listed after
+the line that says @samp{Tag table:}. @refill
+
+In the list of indirect files, the number following the file name
+records the cumulative number of bytes in the preceding indirect files,
+not counting the file list itself, the tag table, or the permissions
+text in each file. In the tag table, the number following the node name
+records the location of the beginning of the node, in bytes from the
+beginning.@refill
+
+If you are using @code{texinfo-format-buffer} to create Info files,
+you may want to run the @code{Info-validate} command. (The
+@code{makeinfo} command does such a good job on its own, you do not
+need @code{Info-validate}.) However, you cannot run the @kbd{M-x
+Info-validate} node-checking command on indirect files. For
+information on how to prevent files from being split and how to
+validate the structure of the nodes, see @ref{Using
+Info-validate}.@refill
+
+@node Install an Info File, Command List, Create an Info File, Top
+@comment node-name, next, previous, up
+@chapter Installing an Info File
+@cindex Installing an Info file
+@cindex Info file installation
+@cindex @file{dir} directory for Info installation
+
+Info files are usually kept in the @file{info}
+directory. (You can find the location of this directory within Emacs
+by typing @kbd{C-h i} to enter Info and then typing @kbd{C-x C-f} to
+see the full pathname to the @file{info} directory.)
+
+@menu
+* Directory file:: The top level menu for all Info files.
+* New Info File:: Listing a new info file.
+* Other Info Directories:: How to specify Info files that are
+ located in other directories.
+@end menu
+
+@node Directory file, New Info File, , Install an Info File
+@ifinfo
+@heading The @file{dir} File
+@end ifinfo
+
+For Info to work, the @file{info} directory must contain a file that
+serves as a top level directory for the Info system. By convention,
+this file is called @file{dir}. The @file{dir} file is itself an Info
+file. It contains the top level menu for all the Info files in the
+system. The menu looks like this:@refill
+
+@example
+* Menu:
+
+* Info: (info). Documentation browsing system.
+* Emacs: (emacs). The extensible, self-documenting
+ text editor.
+* Texinfo: (texinfo). With one source file, make
+ either a printed manual using
+ TeX or an Info file.
+@dots{}
+@end example
+
+Each of these menu entries points to the `Top' node of the Info file
+that is named in parentheses. (The menu entry does not need to
+specify the `Top' node, since Info goes to the `Top' node if no node
+name is mentioned. @xref{Other Info Files, , Nodes in Other Info
+Files}.)@refill
+
+Thus, the @samp{Info} entry points to the `Top' node of the
+@file{info} file and the @samp{Emacs} entry points to the `Top' node
+of the @file{emacs} file.@refill
+
+In each of the Info files, the `Up' pointer of the `Top' node refers
+back to the @code{dir} file. For example, the line for the `Top'
+node of the Emacs manual looks like this in Info:@refill
+
+@example
+File: emacs Node: Top, Up: (DIR), Next: Distrib
+@end example
+
+@noindent
+(Note that in this case, the @file{dir} file name is written in upper
+case letters---it can be written in either upper or lower case. Info
+has a feature that it will change the case of the file name to lower
+case if it cannot find the name as written.)@refill
+
+@c !!! Can any file name be written in upper or lower case,
+@c or is dir a special case?
+@c Yes, apparently so, at least with Gillespie's Info. --rjc 24mar92
+@c
+@node New Info File, Other Info Directories, Directory file, Install an Info File
+@section Listing a New Info File
+@cindex Adding a new info file
+@cindex Listing a new info file
+@cindex New info file, listing it in @file{dir} file
+@cindex Info file, listing new one
+@cindex @file{dir} file listing
+
+To add a new Info file to your system, write a menu entry for it in the
+menu in the @file{dir} file in the @file{info} directory. Also, move
+the new Info file itself to the @file{info} directory. For example, if
+you were adding documentation for GDB, you would write the following new
+entry:@refill
+
+@example
+* GDB: (gdb). The source-level C debugger.
+@end example
+
+@noindent
+The first part of the menu entry is the menu entry name, followed by a
+colon. The second part is the name of the Info file, in parentheses,
+followed by a period. The third part is the description.@refill
+
+Conventionally, the name of an Info file has a @file{.info} extension.
+Thus, you might list the name of the file like this:
+
+@example
+* GDB: (gdb.info). The source-level C debugger.
+@end example
+
+@noindent
+However, Info will look for a file with a @file{.info} extension if it
+does not find the file under the name given in the menu. This means
+that you can refer to the file @file{gdb.info} as @file{gdb}, as shown
+in the first example. This looks better.
+
+@node Other Info Directories, , New Info File, Install an Info File
+@comment node-name, next, previous, up
+@section Info Files in Other Directories
+@cindex Installing Info in another directory
+@cindex Info installed in another directory
+@cindex Another Info directory
+
+If an Info file is not in the @file{info} directory, there are two
+ways to specify its location:@refill
+
+@itemize @bullet
+@item
+Write the pathname as the menu's second part, or;@refill
+
+@item
+Specify the @file{info} directory name in an environment variable in
+your @file{.profile} or @file{.cshrc} initialization file. (Only you
+and others with the same environment variable will be able to find Info
+files whose location is specified this way.)@refill
+@end itemize
+
+For example, to reach a test file in the @file{~bob/manuals}
+directory, you could add an entry like this to the menu in the
+@file{dir} file:@refill
+
+@example
+* Test: (~bob/manuals/info-test). Bob's own test file.
+@end example
+
+@noindent
+In this case, the absolute file name of the @file{info-test} file is
+written as the second part of the menu entry.@refill
+
+@vindex INFOPATH
+Alternatively, you can tell Info where to look by setting the
+@code{INFOPATH} environment variable in your @file{.cshrc} or
+@file{.profile} file.@refill
+
+If you use @code{sh} or @code{bash} for your shell command interpreter,
+you must set the @code{INFOPATH} environment variable in the
+@file{.profile} initialization file; but if you use @code{csh}, you must
+set the variable in the @file{.cshrc} initialization file. The two
+files require slightly different command formats.@refill
+
+@itemize @bullet
+@item
+In a @file{.cshrc} file, you could set the @code{INFOPATH}
+variable as follows:@refill
+
+@smallexample
+setenv INFOPATH .:~bob/manuals:/usr/local/emacs/info
+@end smallexample
+
+@item
+In a @file{.profile} file, you would achieve the same effect by
+writing:@refill
+
+@smallexample
+INFOPATH=.:~bob/manuals:/usr/local/emacs/info
+export INFOPATH
+@end smallexample
+@end itemize
+
+@noindent
+Either form would cause Info to look first in the current directory,
+indicated by the @samp{.}, then in the @file{~bob/manuals} directory,
+and finally in the @file{/usr/local/emacs/info} directory (which is
+a common location for the standard Info directory).@refill
+
+@c ================ Appendix starts here ================
+
+@node Command List, Tips, Install an Info File, Top
+@appendix @@-Command List
+@cindex Alphabetical @@-command list
+@cindex List of @@-commands
+@cindex @@-command list
+
+Here is an alphabetical list of the @@-commands in Texinfo. Square
+brackets, @t{[}@w{ }@t{]}, indicate optional arguments; an ellipsis,
+@samp{@dots{}}, indicates repeated text.@refill
+
+@sp 1
+@table @code
+@item @@*
+Force a line break. Do not end a paragraph that uses @code{@@*} with
+an @code{@@refill} command. @xref{Line Breaks}.@refill
+
+@item @@.
+Stands for a period that really does end a sentence (usually after an
+end-of-sentence capital letter). @xref{Controlling Spacing}.@refill
+
+@item @@:
+Indicate to @TeX{} that an immediately preceding period, question
+mark, exclamation mark, or colon does not end a sentence. Prevent
+@TeX{} from inserting extra whitespace as it does at the end of a
+sentence. The command has no effect on the Info file output.
+@xref{Controlling Spacing}.@refill
+
+@item @@@@
+Stands for @samp{@@}. @xref{Braces Atsigns Periods, , Inserting
+@samp{@@}}.@refill
+
+@item @@@{
+Stands for a left-hand brace, @samp{@{}.
+@xref{Braces Atsigns Periods, , Inserting @@ braces and periods}.@refill
+
+@item @@@}
+Stands for a right-hand brace, @samp{@}}.
+@xref{Braces Atsigns Periods, , Inserting @@ braces and periods}.@refill
+
+@item @@appendix @var{title}
+Begin an appendix. The title appears in the table
+of contents of a printed manual. In Info, the title is
+underlined with asterisks. @xref{unnumbered & appendix, , The
+@code{@@unnumbered} and @code{@@appendix} Commands}.@refill
+
+@item @@appendixsec @var{title}
+@itemx @@appendixsection @var{title}
+Begin an appendix section within an appendix. The section title appears
+in the table of contents of a printed manual. In Info, the title is
+underlined with equal signs. @code{@@appendixsection} is a longer
+spelling of the @code{@@appendixsec} command. @xref{unnumberedsec
+appendixsec heading, , Section Commands}.@refill
+
+@item @@appendixsubsec @var{title}
+Begin an appendix subsection within an appendix. The title appears
+in the table of contents of a printed manual. In Info, the title is
+underlined with hyphens. @xref{unnumberedsubsec appendixsubsec
+subheading, , Subsection Commands}.@refill
+
+@item @@appendixsubsubsec @var{title}
+Begin an appendix subsubsection within a subappendix. The title
+appears in the table of contents of a printed manual. In Info, the
+title is underlined with periods. @xref{subsubsection,, The `subsub'
+Commands}.@refill
+
+@item @@asis
+Used following @code{@@table}, @code{@@ftable}, and @code{@@vtable} to
+print the table's first column without highlighting (``as is'').
+@xref{Two-column Tables, , Making a Two-column Table}.@refill
+
+@item @@author @var{author}
+Typeset @var{author} flushleft and underline it. @xref{title
+subtitle author, , The @code{@@title} and @code{@@author}
+Commands}.@refill
+
+@item @@b@{@var{text}@}
+Print @var{text} in @b{bold} font. No effect in Info. @xref{Fonts}.@refill
+
+@ignore
+@item @@br
+Force a paragraph break. If used within a line, follow @code{@@br}
+with braces. @xref{br, , @code{@@br}}.@refill
+@end ignore
+
+@item @@bullet@{@}
+Generate a large round dot, or the closest possible
+thing to one. @xref{bullet, , @code{@@bullet}}.@refill
+
+@item @@bye
+Stop formatting a file. The formatters do not see the contents of a
+file following an @code{@@bye} command. @xref{Ending a File}.@refill
+
+@item @@c @var{comment}
+Begin a comment in Texinfo. The rest of the line does not appear in
+either the Info file or the printed manual. A synonym for
+@code{@@comment}. @xref{Conventions, , General Syntactic
+Conventions}.@refill
+
+@item @@cartouche
+Highlight an example or quotation by drawing a box with rounded
+corners around it. Pair with @code{@@end cartouche}. No effect in
+Info. @xref{cartouche, , Drawing Cartouches Around Examples}.)@refill
+
+@item @@center @var{line-of-text}
+Center the line of text following the command.
+@xref{titlefont center sp, , @code{@@center}}.@refill
+
+@item @@chapheading @var{title}
+Print a chapter-like heading in the text, but not in the table of
+contents of a printed manual. In Info, the title is underlined with
+asterisks. @xref{majorheading & chapheading, , @code{@@majorheading}
+and @code{@@chapheading}}.@refill
+
+@item @@chapter @var{title}
+Begin a chapter. The chapter title appears in the table of
+contents of a printed manual. In Info, the title is underlined with
+asterisks. @xref{chapter, , @code{@@chapter}}.@refill
+
+@item @@cindex @var{entry}
+Add @var{entry} to the index of concepts. @xref{Index Entries, ,
+Defining the Entries of an Index}.@refill
+
+@item @@cite@{@var{reference}@}
+Highlight the name of a book or other reference that lacks a
+companion Info file. @xref{cite, , @code{@@cite}}.@refill
+
+@item @@clear @var{flag}
+Unset @var{flag}, preventing the Texinfo formatting commands from
+formatting text between subsequent pairs of @code{@@ifset @var{flag}}
+and @code{@@end ifset} commands, and preventing
+@code{@@value@{@var{flag}@}} from expanding to the value to which
+@var{flag} is set.
+@xref{set clear value, , @code{@@set} @code{@@clear} @code{@@value}}.@refill
+
+@item @@code@{@var{sample-code}@}
+Highlight text that is an expression, a syntactically complete token
+of a program, or a program name. @xref{code, , @code{@@code}}.@refill
+
+@item @@comment @var{comment}
+Begin a comment in Texinfo. The rest of the line does not appear in
+either the Info file or the printed manual. A synonym for @code{@@c}.
+@xref{Conventions, , General Syntactic Conventions}.@refill
+
+@item @@contents
+Print a complete table of contents. Has no effect in Info, which uses
+menus instead. @xref{Contents, , Generating a Table of
+Contents}.@refill
+
+@item @@copyright@{@}
+Generate a copyright symbol. @xref{copyright symbol, ,
+@code{@@copyright}}.@refill
+
+@ignore
+@item @@ctrl@{@var{ctrl-char}@}
+Describe an @sc{ascii} control character. Insert actual control character
+into Info file. @xref{ctrl, , @code{@@ctrl}}.@refill
+@end ignore
+
+@item @@defcodeindex @var{index-name}
+Define a new index and its indexing command. Print entries in an
+@code{@@code} font. @xref{New Indices, , Defining New
+Indices}.@refill
+
+@item @@defcv @var{category} @var{class} @var{name}
+Format a description for a variable associated with a class in
+object-oriented programming. Takes three arguments: the category of
+thing being defined, the class to which it belongs, and its name.
+@xref{Definition Commands}.@refill
+
+@item @@deffn @var{category} @var{name} @var{arguments}@dots{}
+Format a description for a function, interactive command, or similar
+entity that may take arguments. @code{@@deffn} takes as arguments the
+category of entity being described, the name of this particular
+entity, and its arguments, if any. @xref{Definition Commands}.@refill
+
+@item @@defindex @var{index-name}
+Define a new index and its indexing command. Print entries in a roman
+font. @xref{New Indices, , Defining New Indices}.@refill
+
+@item @@defivar @var{class} @var{instance-variable-name}
+Format a description for an instance variable in object-oriented
+programming. The command is equivalent to @samp{@@defcv @{Instance
+Variable@} @dots{}}. @xref{Definition Commands}.@refill
+
+@item @@defmac @var{macro-name} @var{arguments}@dots{}
+Format a description for a macro. The command is equivalent to
+@samp{@@deffn Macro @dots{}}. @xref{Definition Commands}.@refill
+
+@item @@defmethod @var{class} @var{method-name} @var{arguments}@dots{}
+Format a description for a method in object-oriented programming. The
+command is equivalent to @samp{@@defop Method @dots{}}. Takes as
+arguments the name of the class of the method, the name of the
+method, and its arguments, if any. @xref{Definition Commands}.@refill
+
+@item @@defop @var{category} @var{class} @var{name} @var{arguments}@dots{}
+Format a description for an operation in object-oriented programming.
+@code{@@defop} takes as arguments the overall name of the category of
+operation, the name of the class of the operation, the name of the
+operation, and its arguments, if any. @xref{Definition
+Commands}.@refill
+
+@need 100
+@item @@defopt @var{option-name}
+Format a description for a user option. The command is equivalent to
+@samp{@@defvr @{User Option@} @dots{}}. @xref{Definition Commands}.@refill
+
+@need 100
+@item @@defspec @var{special-form-name} @var{arguments}@dots{}
+Format a description for a special form. The command is equivalent to
+@samp{@@deffn @{Special Form@} @dots{}}. @xref{Definition Commands}.@refill
+
+@need 200
+@item @@deftp @var{category} @var{name-of-type} @var{attributes}@dots{}
+Format a description for a data type. @code{@@deftp} takes as
+arguments the category, the name of the type (which is a word like
+@samp{int} or @samp{float}), and then the names of attributes of
+objects of that
+type. @xref{Definition Commands}.@refill
+
+@item @@deftypefn @var{classification} @var{data-type} @var{name} @var{arguments}@dots{}
+Format a description for a function or similar entity that may take
+arguments and that is typed. @code{@@deftypefn} takes as arguments
+the classification of entity being described, the type, the name of
+the entity, and its arguments, if any. @xref{Definition
+Commands}.@refill
+
+@item @@deftypefun @var{data-type} @var{function-name} @var{arguments}@dots{}
+Format a description for a function in a typed language.
+The command is equivalent to @samp{@@deftypefn Function @dots{}}.
+@xref{Definition Commands}.@refill
+
+@item @@deftypevr @var{classification} @var{data-type} @var{name}
+Format a description for something like a variable in a typed
+language---an entity that records a value. Takes as arguments the
+classification of entity being described, the type, and the name of
+the entity. @xref{Definition Commands}.@refill
+
+@item @@deftypevar @var{data-type} @var{variable-name}
+Format a description for a variable in a typed language. The command is
+equivalent to @samp{@@deftypevr Variable @dots{}}. @xref{Definition
+Commands}.@refill
+
+@item @@defun @var{function-name} @var{arguments}@dots{}
+Format a description for functions. The command is equivalent to
+@samp{@@deffn Function @dots{}}. @xref{Definition Commands}.@refill
+
+@item @@defvar @var{variable-name}
+Format a description for variables. The command is equivalent to
+@samp{@@defvr Variable @dots{}}. @xref{Definition Commands}.@refill
+
+@item @@defvr @var{category} @var{name}
+Format a description for any kind of variable. @code{@@defvr} takes
+as arguments the category of the entity and the name of the entity.
+@xref{Definition Commands}.@refill
+
+@item @@dfn@{@var{term}@}
+Highlight the introductory or defining use of a term.
+@xref{dfn, , @code{@@dfn}}.@refill
+
+@need 100
+@item @@display
+Begin a kind of example. Indent text, do not fill, do not select a
+new font. Pair with @code{@@end display}. @xref{display, ,
+@code{@@display}}.@refill
+
+@need 100
+@item @@dmn@{@var{dimension}@}
+Format a dimension. Cause @TeX{} to insert a narrow space before
+@var{dimension}. No effect in Info. Use for writing a number
+followed by an abbreviation of a dimension name, such as
+@samp{12@dmn{pt}}, written as @samp{12@@dmn@{pt@}}, with no space
+between the number and the @code{@@dmn} command. @xref{dmn, ,
+@code{@@dmn}}.@refill
+
+@need 100
+@item @@dots@{@}
+Insert an ellipsis: @samp{@dots{}}.
+@xref{dots, , @code{@@dots}}.@refill
+
+@need 100
+@item @@emph@{@var{text}@}
+Highlight @var{text}; text is displayed in @emph{italics} in printed
+output, and surrounded by asterisks in Info. @xref{Emphasis, , Emphasizing Text}.@refill
+
+@need 100
+@item @@enumerate [@var{number-or-letter}]
+Begin a numbered list, using @code{@@item} for each entry.
+Optionally, start list with @var{number-or-letter}. Pair with
+@code{@@end enumerate}. @xref{enumerate, ,
+@code{@@enumerate}}.@refill
+
+@need 100
+@item @@equiv@{@}
+Indicate to the reader the exact equivalence of two forms with a
+glyph: @samp{@equiv{}}. @xref{Equivalence}.@refill
+
+@item @@error@{@}
+Indicate to the reader with a glyph that the following text is
+an error message: @samp{@error{}}. @xref{Error Glyph}.@refill
+
+@item @@evenfooting [@var{left}] @@| [@var{center}] @@| [@var{right}]
+Specify page footings for even-numbered (left-hand) pages. Not relevant to
+Info. @xref{Custom Headings, , How to Make Your Own Headings}.@refill
+
+@item @@evenheading [@var{left}] @@| [@var{center}] @@| [@var{right}]
+Specify page headings for even-numbered (left-hand) pages. Not relevant to
+Info. @xref{Custom Headings, , How to Make Your Own Headings}.@refill
+
+@item @@everyfooting [@var{left}] @@| [@var{center}] @@| [@var{right}]
+Specify page footings for every page. Not relevant to Info. @xref{Custom
+Headings, , How to Make Your Own Headings}.@refill
+
+@item @@everyheading [@var{left}] @@| [@var{center}] @@| [@var{right}]
+Specify page headings for every page. Not relevant to Info. @xref{Custom
+Headings, , How to Make Your Own Headings}.@refill
+
+@item @@example
+Begin an example. Indent text, do not fill, and select fixed-width font.
+Pair with @code{@@end example}. @xref{example, ,
+@code{@@example}}.@refill
+
+@item @@exdent @var{line-of-text}
+Remove any indentation a line might have. @xref{exdent, ,
+Undoing the Indentation of a Line}.@refill
+
+@item @@expansion@{@}
+Indicate the result of a macro expansion to the reader with a special
+glyph: @samp{@expansion{}}.
+@xref{expansion, , @expansion{} Indicating an Expansion}.@refill
+
+@item @@file@{@var{filename}@}
+Highlight the name of a file, buffer, node, or directory. @xref{file, ,
+@code{@@file}}.@refill
+
+@item @@finalout
+Prevent @TeX{} from printing large black warning rectangles beside
+over-wide lines. @xref{Overfull hboxes}.@refill
+
+@need 100
+@item @@findex @var{entry}
+Add @var{entry} to the index of functions. @xref{Index Entries, ,
+Defining the Entries of an Index}.@refill
+
+@need 200
+@item @@flushleft
+Left justify every line but leave the right end ragged.
+Leave font as is. Pair with @code{@@end flushleft}.
+@xref{flushleft & flushright, , @code{@@flushleft} and
+@code{@@flushright}}.@refill
+
+@need 200
+@item @@flushright
+Right justify every line but leave the left end ragged.
+Leave font as is. Pair with @code{@@end flushright}.
+@xref{flushleft & flushright, , @code{@@flushleft} and
+@code{@@flushright}}.@refill
+
+@need 200
+@item @@footnote@{@var{text-of-footnote}@}
+Enter a footnote. Footnote text is printed at the bottom of the page
+by @TeX{}; Info may format in either `End' node or `Separate' node style.
+@xref{Footnotes}.@refill
+
+@item @@footnotestyle @var{style}
+Specify an Info file's footnote style, either @samp{end} for the end
+node style or @samp{separate} for the separate node style.
+@xref{Footnotes}.@refill
+
+@item @@format
+Begin a kind of example. Like @code{@@example} or @code{@@display},
+but do not narrow the margins and do not select the fixed-width font.
+Pair with @code{@@end format}. @xref{example, ,
+@code{@@example}}.@refill
+
+@item @@ftable @var{formatting-command}
+Begin a two-column table, using @code{@@item} for each entry.
+Automatically enter each of the items in the first column into the
+index of functions. Pair with @code{@@end ftable}. The same as
+@code{@@table}, except for indexing. @xref{ftable vtable, ,
+@code{@@ftable} and @code{@@vtable}}.@refill
+
+@item @@group
+Hold text together that must appear on one printed page. Pair with
+@code{@@end group}. Not relevant to Info. @xref{group, ,
+@code{@@group}}.@refill
+
+@item @@heading @var{title}
+Print an unnumbered section-like heading in the text, but not in the
+table of contents of a printed manual. In Info, the title is
+underlined with equal signs. @xref{unnumberedsec appendixsec heading,
+, Section Commands}.@refill
+
+@item @@headings @var{on-off-single-double}
+Turn page headings on or off, or specify single-sided or double-sided
+page headings for printing. @code{@@headings on} is synonymous with
+@code{@@headings double}. @xref{headings on off, , The
+@code{@@headings} Command}.@refill
+
+@item @@i@{@var{text}@}
+Print @var{text} in @i{italic} font. No effect in Info.
+@xref{Fonts}.@refill
+
+@item @@ifclear @var{flag}
+If @var{flag} is cleared, the Texinfo formatting commands format text
+between @code{@@ifclear @var{flag}} and the following @code{@@end
+ifclear} command.
+@xref{set clear value, , @code{@@set} @code{@@clear} @code{@@value}}.@refill
+
+@item @@ifinfo
+Begin a stretch of text that will be ignored by @TeX{} when it
+typesets the printed manual. The text appears only in the Info file.
+Pair with @code{@@end ifinfo}. @xref{Conditionals, , Conditionally
+Visible Text}.@refill
+
+@item @@ifset @var{flag}
+If @var{flag} is set, the Texinfo formatting commands format text
+between @code{@@ifset @var{flag}} and the following @code{@@end ifset}
+command.
+@xref{set clear value, , @code{@@set} @code{@@clear} @code{@@value}}.@refill
+
+@item @@iftex
+Begin a stretch of text that will not appear in the Info file, but
+will be processed only by @TeX{}. Pair with @code{@@end iftex}.
+@xref{Conditionals, , Conditionally Visible Text}.@refill
+
+@item @@ignore
+Begin a stretch of text that will not appear in either the Info file
+or the printed output. Pair with @code{@@end ignore}.
+@xref{Comments, , Comments and Ignored Text}.@refill
+
+@item @@include @var{filename}
+Incorporate the contents of the file @var{filename} into the Info file
+or printed document. @xref{Include Files}.@refill
+
+@item @@inforef@{@var{node-name}, [@var{entry-name}], @var{info-file-name}@}
+Make a cross reference to an Info file for which there is no printed
+manual. @xref{inforef, , Cross references using
+@code{@@inforef}}.@refill
+
+@item \input @var{macro-definitions-file}
+Use the specified macro definitions file. This command is used only
+in the first line of a Texinfo file to cause @TeX{} to make use of the
+@file{texinfo} macro definitions file. The backslash in @code{\input}
+is used instead of an @code{@@} because @TeX{} does not properly
+recognize @code{@@} until after it has read the definitions file.
+@xref{Header, , The Texinfo File Header}.@refill
+
+@item @@item
+Indicate the beginning of a marked paragraph for @code{@@itemize} and
+@code{@@enumerate}; indicate the beginning of the text of a first column
+entry for @code{@@table}, @code{@@ftable}, and @code{@@vtable}.
+@xref{Lists and Tables}.@refill
+
+@item @@itemize @var{mark-generating-character-or-command}
+Produce a sequence of indented paragraphs, with a mark inside the left
+margin at the beginning of each paragraph. Pair with @code{@@end
+itemize}. @xref{itemize, , @code{@@itemize}}.@refill
+
+@item @@itemx
+Like @code{@@item} but do not generate extra vertical space above the
+item text. @xref{itemx, , @code{@@itemx}}.@refill
+
+@item @@kbd@{@var{keyboard-characters}@}
+Indicate text that consists of characters of input to be typed by
+users. @xref{kbd, , @code{@@kbd}}.@refill
+
+@item @@key@{@var{key-name}@}
+Highlight @var{key-name}, a conventional name for a key on a keyboard.
+@xref{key, , @code{@@key}}.@refill
+
+@item @@kindex @var{entry}
+Add @var{entry} to the index of keys. @xref{Index Entries, , Defining the
+Entries of an Index}.@refill
+
+@item @@lisp
+Begin an example of Lisp code. Indent text, do not fill, and select
+fixed-width font. Pair with @code{@@end lisp}. @xref{Lisp Example, ,
+@code{@@lisp}}.@refill
+
+@item @@majorheading @var{title}
+Print a chapter-like heading in the text, but not in the table of
+contents of a printed manual. Generate more vertical whitespace before
+the heading than the @code{@@chapheading} command. In Info, the chapter
+heading line is underlined with asterisks. @xref{majorheading &
+chapheading, , @code{@@majorheading} and @code{@@chapheading}}.@refill
+
+@item @@menu
+Mark the beginning of a menu of nodes in Info. No effect in a printed
+manual. Pair with @code{@@end menu}. @xref{Menus}.@refill
+
+@item @@minus@{@}
+Generate a minus sign. @xref{minus, , @code{@@minus}}.@refill
+
+@item @@need @var{n}
+Start a new page in a printed manual if fewer than @var{n} mils
+(thousandths of an inch) remain on the current page. @xref{need, ,
+@code{@@need}}.@refill
+
+@item @@node @var{name, next, previous, up}
+Define the beginning of a new node in Info, and serve as a locator for
+references for @TeX{}. @xref{node, , @code{@@node}}.@refill
+
+@need 200
+@item @@noindent
+Prevent text from being indented as if it were a new paragraph.
+@xref{noindent, , @code{@@noindent}}.@refill
+
+@item @@oddfooting [@var{left}] @@| [@var{center}] @@| [@var{right}]
+Specify page footings for odd-numbered (right-hand) pages. Not relevant to
+Info. @xref{Custom Headings, , How to Make Your Own Headings}.@refill
+
+@item @@oddheading [@var{left}] @@| [@var{center}] @@| [@var{right}]
+Specify page headings for odd-numbered (right-hand) pages. Not relevant to
+Info. @xref{Custom Headings, , How to Make Your Own Headings}.@refill
+
+@item @@page
+Start a new page in a printed manual. No effect in Info.
+@xref{page, , @code{@@page}}.@refill
+
+@item @@paragraphindent @var{indent}
+Indent paragraphs by @var{indent} number of spaces; delete indentation
+if the value of @var{indent} is 0; and do not change indentation if
+@var{indent} is @code{asis}. @xref{paragraphindent, , Paragraph
+Indenting}.@refill
+
+@item @@pindex @var{entry}
+Add @var{entry} to the index of programs. @xref{Index Entries, , Defining
+the Entries of an Index}.@refill
+
+@item @@point@{@}
+Indicate the position of point in a buffer to the reader with a
+glyph: @samp{@point{}}. @xref{Point Glyph, , Indicating
+Point in a Buffer}.@refill
+
+@item @@print@{@}
+Indicate printed output to the reader with a glyph:
+@samp{@print{}}. @xref{Print Glyph}.@refill
+
+@item @@printindex @var{index-name}
+Print an alphabetized two-column index in a printed manual or generate
+an alphabetized menu of index entries for Info. @xref{Printing
+Indices & Menus}.@refill
+
+@item @@pxref@{@var{node-name}, [@var{entry}], [@var{topic-or-title}], [@var{info-file}], [@var{manual}]@}
+Make a reference that starts with a lower case `see' in a printed
+manual. Use within parentheses only. Do not follow command with a
+punctuation mark. The Info formatting commands automatically insert
+terminating punctuation as needed, which is why you do not need to
+insert punctuation. Only the first argument is mandatory.
+@xref{pxref, , @code{@@pxref}}.@refill
+
+@item @@quotation
+Narrow the margins to indicate text that is quoted from another real
+or imaginary work. Write command on a line of its own. Pair with
+@code{@@end quotation}. @xref{quotation, ,
+@code{@@quotation}}.@refill
+
+@need 100
+@item @@r@{@var{text}@}
+Print @var{text} in @r{roman} font. No effect in Info.
+@xref{Fonts}.@refill
+
+@need 300
+@item @@ref@{@var{node-name}, [@var{entry}], [@var{topic-or-title}], [@var{info-file}], [@var{manual}]@}
+Make a reference. In a printed manual, the reference does not start
+with a `See'. Follow command with a punctuation mark. Only the first
+argument is mandatory. @xref{ref, , @code{@@ref}}.@refill
+
+@need 300
+@item @@refill
+In Info, refill and indent the paragraph after all the other processing
+has been done. No effect on @TeX{}, which always refills. This command
+is no longer needed, since all formatters now automatically refill.
+@xref{Refilling Paragraphs}.@refill
+
+@need 300
+@item @@result@{@}
+Indicate the result of an expression to the reader with a special
+glyph: @samp{@result{}}. @xref{result, , @code{@@result}}.@refill
+
+@item @@samp@{@var{text}@}
+Highlight @var{text} that is a literal example of a sequence of
+characters. Used for single characters, for statements, and often for
+entire shell commands. @xref{samp, , @code{@@samp}}.@refill
+
+@item @@sc@{@var{text}@}
+Set @var{text} in a printed output in @sc{the small caps font} and
+set text in the Info file in uppercase letters.
+@xref{Smallcaps}.@refill
+
+@item @@section @var{title}
+Begin a section within a chapter. In a printed manual, the section
+title is numbered and appears in the table of contents. In Info, the
+title is underlined with equal signs. @xref{section, ,
+@code{@@section}}.@refill
+
+@item @@set @var{flag} [@var{string}]
+Make @var{flag} active, causing the Texinfo formatting commands to
+format text between subsequent pairs of @code{@@ifset @var{flag}} and
+@code{@@end ifset} commands. Optionally, set value of @var{flag} to
+@var{string}.
+@xref{set clear value, , @code{@@set} @code{@@clear} @code{@@value}}.@refill
+
+@item @@setchapternewpage @var{on-off-odd}
+Specify whether chapters start on new pages, and if so, whether on
+odd-numbered (right-hand) new pages. @xref{setchapternewpage, ,
+@code{@@setchapternewpage}}.@refill
+
+@item @@setfilename @var{info-file-name}
+Provide a name for the Info file. @xref{Conventions, , General
+Syntactic Conventions}.@refill
+
+@item @@settitle @var{title}
+Provide a title for page headers in a printed manual.
+@xref{Conventions, , General Syntactic Conventions}.@refill
+
+@item @@shortcontents
+Print a short table of contents. Not relevant to Info, which uses
+menus rather than tables of contents. A synonym for
+@code{@@summarycontents}. @xref{Contents, , Generating a Table of
+Contents}.@refill
+
+@need 400
+@item @@smallbook
+Cause @TeX{} to produce a printed manual in a 7 by 9.25 inch format
+rather than the regular 8.5 by 11 inch format. @xref{smallbook, ,
+Printing Small Books}. Also, see @ref{smallexample & smalllisp, ,
+@code{@@smallexample} and @code{@@smalllisp}}.@refill
+
+@need 400
+@item @@smallexample
+Indent text to indicate an example. Do not fill, select fixed-width
+font. In @code{@@smallbook} format, print text in a smaller font than
+with @code{@@example}. Pair with @code{@@end smallexample}.
+@xref{smallexample & smalllisp, , @code{@@smallexample} and
+@code{@@smalllisp}}.@refill
+
+@need 400
+@item @@smalllisp
+Begin an example of Lisp code. Indent text, do not fill, select
+fixed-width font. In @code{@@smallbook} format, print text in a
+smaller font. Pair with @code{@@end smalllisp}. @xref{smallexample &
+smalllisp, , @code{@@smallexample} and @code{@@smalllisp}}.@refill
+
+@need 700
+@item @@sp @var{n}
+Skip @var{n} blank lines. @xref{sp, , @code{@@sp}}.@refill
+
+@need 700
+@item @@strong @var{text}
+Emphasize @var{text} by typesetting it in a @strong{bold} font for the
+printed manual and by surrounding it with asterisks for Info.
+@xref{emph & strong, , Emphasizing Text}.@refill
+
+@item @@subheading @var{title}
+Print an unnumbered subsection-like heading in the text, but not in
+the table of contents of a printed manual. In Info, the title is
+underlined with hyphens. @xref{unnumberedsubsec appendixsubsec
+subheading, , @code{@@unnumberedsubsec} @code{@@appendixsubsec}
+@code{@@subheading}}.@refill
+
+@item @@subsection @var{title}
+Begin a subsection within a section. In a printed manual, the
+subsection title is numbered and appears in the table of contents. In
+Info, the title is underlined with hyphens. @xref{subsection, ,
+@code{@@subsection}}.@refill
+
+@item @@subsubheading @var{title}
+Print an unnumbered subsubsection-like heading in the text, but not in
+the table of contents of a printed manual. In Info, the title is
+underlined with periods. @xref{subsubsection, , The `subsub'
+Commands}.@refill
+
+@item @@subsubsection @var{title}
+Begin a subsubsection within a subsection. In a printed manual,
+the subsubsection title is numbered and appears in the table of
+contents. In Info, the title is underlined with periods.
+@xref{subsubsection, , The `subsub' Commands}.@refill
+
+@item @@subtitle @var{title}
+In a printed manual, set a subtitle in a normal sized font flush to
+the right-hand side of the page. Not relevant to Info, which does not
+have title pages. @xref{title subtitle author, , @code{@@title}
+@code{@@subtitle} and @code{@@author} Commands}.@refill
+
+@item @@summarycontents
+Print a short table of contents. Not relevant to Info, which uses
+menus rather than tables of contents. A synonym for
+@code{@@shortcontents}. @xref{Contents, , Generating a Table of
+Contents}.@refill
+
+@need 300
+@item @@syncodeindex @var{from-index} @var{into-index}
+Merge the index named in the first argument into the index named in
+the second argument, printing the entries from the first index in
+@code{@@code} font. @xref{Combining Indices}.@refill
+
+@need 300
+@item @@synindex @var{from-index} @var{into-index}
+Merge the index named in the first argument into the index named in
+the second argument. Do not change the font of @var{from-index}
+entries. @xref{Combining Indices}.@refill
+
+@need 100
+@item @@t@{@var{text}@}
+Print @var{text} in a @t{fixed-width}, typewriter-like font.
+No effect in Info. @xref{Fonts}.@refill
+
+@need 400
+@item @@table @var{formatting-command}
+Begin a two-column table, using @code{@@item} for each entry. Write
+each first column entry on the same line as @code{@@item}. First
+column entries are printed in the font resulting from
+@var{formatting-command}. Pair with @code{@@end table}.
+@xref{Two-column Tables, , Making a Two-column Table}.
+Also see @ref{ftable vtable, , @code{@@ftable} and @code{@@vtable}},
+and @ref{itemx, , @code{@@itemx}}.@refill
+
+@item @@TeX@{@}
+Insert the logo @TeX{}. @xref{TeX and copyright, , Inserting @TeX{}
+and @copyright{}}.@refill
+
+@item @@tex
+Enter @TeX{} completely. Pair with @code{@@end tex}. @xref{Using
+Ordinary TeX Commands, , Using Ordinary @TeX{} Commands}.@refill
+
+@item @@thischapter
+In a heading or footing, stands for the number and name of the current
+chapter, in the format `Chapter 1: Title'. @xref{Custom
+Headings, , How to Make Your Own Headings}.@refill
+
+@item @@thischaptername
+In a heading or footing, stands for the name of the current chapter.
+@xref{Custom Headings, , How to Make Your Own Headings}.@refill
+
+@item @@thisfile
+In a heading or footing, stands for the name of the current
+@code{@@include} file. Does not insert anything if not within an
+@code{@@include} file. @xref{Custom Headings, , How to Make Your Own
+Headings}.@refill
+
+@item @@thispage
+In a heading or footing, stands for the current page number.
+@xref{Custom Headings, , How to Make Your Own Headings}.@refill
+
+@ignore
+@item @@thissection
+In a heading or footing, stands for the title of the current section.
+@xref{Custom Headings, , How to Make Your Own Headings}.@refill
+@end ignore
+
+@item @@thistitle
+In a heading or footing, stands for the name of the document, as specified
+by the @code{@@settitle} command. @xref{Custom Headings, , How to
+Make Your Own Headings}.@refill
+
+@item @@tindex @var{entry}
+Add @var{entry} to the index of data types. @xref{Index Entries, ,
+Defining the Entries of an Index}.@refill
+
+@item @@title @var{title}
+In a printed manual, set a title flush to the left-hand side of the
+page in a larger than normal font and underline it with a black rule.
+Not relevant to Info, which does not have title pages. @xref{title
+subtitle author, , The @code{@@title} @code{@@subtitle} and
+@code{@@author} Commands}.@refill
+
+@need 400
+@item @@titlefont@{@var{text}@}
+In a printed manual, print @var{text} in a larger than normal font.
+Not relevant to Info, which does not have title pages.
+@xref{titlefont center sp, , The @code{@@titlefont} @code{@@center}
+and @code{@@sp} Commands}.@refill
+
+@need 300
+@item @@titlepage
+Indicate to Texinfo the beginning of the title page. Write command on
+a line of its own. Pair with @code{@@end titlepage}. Nothing between
+@code{@@titlepage} and @code{@@end titlepage} appears in Info.
+@xref{titlepage, , @code{@@titlepage}}.@refill
+
+@need 150
+@item @@today@{@}
+Insert the current date, in `1 Jan 1900' style. @xref{Custom
+Headings, , How to Make Your Own Headings}.@refill
+
+@item @@top @var{title}
+In a Texinfo file to be formatted with @code{makeinfo}, identify the
+topmost @code{@@node} line in the file, which must be written on the line
+immediately preceding the @code{@@top} command. Used for
+@code{makeinfo}'s node pointer insertion feature. The title is
+underlined with asterisks. Both the @code{@@node} line and the @code{@@top}
+line normally should be enclosed by @code{@@ifinfo} and @code{@@end
+ifinfo}. In @TeX{} and @code{texinfo-format-buffer}, the @code{@@top}
+command is merely a synonym for @code{@@unnumbered}. @xref{makeinfo
+Pointer Creation, , Creating Pointers with @code{makeinfo}}.
+
+@item @@unnumbered @var{title}
+In a printed manual, begin a chapter that appears without chapter
+numbers of any kind. The title appears in the table of contents of a
+printed manual. In Info, the title is underlined with asterisks.
+@xref{unnumbered & appendix, , @code{@@unnumbered} and
+@code{@@appendix}}.@refill
+
+@item @@unnumberedsec @var{title}
+In a printed manual, begin a section that appears without section
+numbers of any kind. The title appears in the table of contents of a
+printed manual. In Info, the title is underlined with equal signs.
+@xref{unnumberedsec appendixsec heading, , Section Commands}.@refill
+
+@item @@unnumberedsubsec @var{title}
+In a printed manual, begin an unnumbered subsection within a
+chapter. The title appears in the table of contents of a printed
+manual. In Info, the title is underlined with hyphens.
+@xref{unnumberedsubsec appendixsubsec subheading, ,
+@code{@@unnumberedsubsec} @code{@@appendixsubsec}
+@code{@@subheading}}.@refill
+
+@item @@unnumberedsubsubsec @var{title}
+In a printed manual, begin an unnumbered subsubsection within a
+chapter. The title appears in the table of contents of a printed
+manual. In Info, the title is underlined with periods.
+@xref{subsubsection, , The `subsub' Commands}.@refill
+
+@item @@value@{@var{flag}@}
+Replace @var{flag} with the value to which it is set by @code{@@set
+@var{flag}}.
+@xref{set clear value, , @code{@@set} @code{@@clear} @code{@@value}}.@refill
+
+@item @@var@{@var{metasyntactic-variable}@}
+Highlight a metasyntactic variable, which is something that stands for
+another piece of text. @xref{var, , Indicating Metasyntactic
+Variables}.@refill
+
+@need 400
+@item @@vindex @var{entry}
+Add @var{entry} to the index of variables. @xref{Index Entries, ,
+Defining the Entries of an Index}.@refill
+
+@need 400
+@item @@vskip @var{amount}
+In a printed manual, insert whitespace so as to push text on the
+remainder of the page towards the bottom of the page. Used in
+formatting the copyright page with the argument @samp{0pt plus
+1filll}. (Note spelling of @samp{filll}.) @code{@@vskip} may be used
+only in contexts ignored for Info. @xref{Copyright & Permissions, ,
+The Copyright Page and Printed Permissions}.@refill
+
+@need 400
+@item @@vtable @var{formatting-command}
+Begin a two-column table, using @code{@@item} for each entry.
+Automatically enter each of the items in the first column into the
+index of variables. Pair with @code{@@end vtable}. The same as
+@code{@@table}, except for indexing. @xref{ftable vtable, ,
+@code{@@ftable} and @code{@@vtable}}.@refill
+
+@need 400
+@item @@w@{@var{text}@}
+Prevent @var{text} from being split across two lines. Do not end a
+paragraph that uses @code{@@w} with an @code{@@refill} command.
+In the Texinfo file, keep @var{text} on one line.
+@xref{w, , @code{@@w}}.@refill
+
+@need 400
+@item @@xref@{@var{node-name}, [@var{entry}], [@var{topic-or-title}], [@var{info-file}], [@var{manual}]@}
+Make a reference that starts with `See' in a printed manual. Follow
+command with a punctuation mark. Only the first argument is
+mandatory. @xref{xref, , @code{@@xref}}.@refill
+@end table
+
+@node Tips, Sample Texinfo File, Command List, Top
+@comment node-name, next, previous, up
+@appendix Tips and Hints
+
+Here are some tips for writing Texinfo documentation:@refill
+
+@cindex Tips
+@cindex Usage tips
+@cindex Hints
+@itemize @bullet
+@item
+Write in the present tense, not in the past or the future.
+
+@item
+Write actively! For example, write ``We recommend that @dots{}'' rather
+than ``It is recommended that @dots{}''.
+
+@item
+Use 70 or 72 as your fill column. Longer lines are hard to read.
+
+@item
+Include a copyright notice and copying permissions.
+@end itemize
+
+@subsubheading Index, index, index!
+
+Write many index entries, in different ways.
+Readers like indices; they are helpful and convenient.
+
+Although it is easiest to write index entries as you write the body of
+the text, some people prefer to write entries afterwards. In either
+case, write an entry before the paragraph to which it applies. This
+way, an index entry points to the first page of a paragraph that is
+split across pages.
+
+Here are more hints we have found valuable:
+
+@itemize @bullet
+@item
+Write each index entry differently, so each entry refers to a different
+place in the document. The index of an Info file lists only one
+location for each entry.
+
+@item
+Write index entries only where a topic is discussed significantly. For
+example, it is not useful to index ``debugging information'' in a
+chapter on reporting bugs. Someone who wants to know about debugging
+information will certainly not find it in that chapter.
+
+@item
+Consistently capitalize the first word of every index entry, or else use
+lower case. According to convention, you should capitalize the first
+word of an index entry. However, this practice may make an index look
+crowded. Some writers prefer lower case. Regardless of which you
+prefer, choose one style and stick to it. Mixing the two styles looks
+bad.
+
+@item
+Always capitalize or use upper case for those words in an index for
+which this is proper, such as names of countries or acronyms.
+
+@item
+Write the indexing commands that refer to a whole section immediately
+after the section command, and write the indexing commands that refer to
+the paragraph before the paragraph.
+
+@need 1000
+In the example that follows, a blank line comes after the index
+entry for ``Leaping'':
+
+@example
+@group
+@@section The Dog and the Fox
+@@cindex Jumping, in general
+@@cindex Leaping
+
+@@cindex Dog, lazy, jumped over
+@@cindex Lazy dog jumped over
+@@cindex Fox, jumps over dog
+@@cindex Quick fox jumps over dog
+The quick brown fox jumps over the lazy dog.
+@end group
+@end example
+
+@noindent
+(Note that the example shows entries for the same concept that are
+written in different ways---@samp{Lazy dog}, and @samp{Dog, lazy}---so
+readers can look up the concept in different ways.)
+@end itemize
+
+@subsubheading Blank lines
+
+@itemize @bullet
+@item
+Insert a blank line between a sectioning command and the first following
+sentence or paragraph, or between the indexing commands associated with
+the sectioning command and the first following sentence or paragraph, as
+shown in the tip on indexing. Otherwise, a formatter may fold title and
+paragraph together.
+
+@item
+Always insert a blank line before an @code{@@table} command and after an
+@code{@@end table} command; but never insert a blank line after an
+@code{@@table} command or before an @code{@@end table} command.
+
+@need 1000
+For example,
+
+@example
+@group
+Types of fox:
+
+@@table @@samp
+@@item Quick
+Jump over lazy dogs.
+@end group
+
+@group
+@@item Brown
+Also jump over lazy dogs.
+@@end table
+
+@end group
+@group
+@@noindent
+On the other hand, @dots{}
+@end group
+@end example
+
+Insert blank lines before and after @code{@@itemize} @dots{} @code{@@end
+itemize} and @code{@@enumerate} @dots{} @code{@@end enumerate} in the
+same way.
+@end itemize
+
+@subsubheading Complete phrases
+
+Complete phrases are easier to read than @dots{}
+
+@itemize @bullet
+@item
+Write entries in an itemized list as complete sentences; or at least, as
+complete phrases. Incomplete expressions @dots{} awkward @dots{} like
+this.
+
+@item
+Write the prefatory sentence or phrase for a multi-item list or table as
+a complete expression. Do not write ``You can set:''; instead, write
+``You can set these variables:''. The former expression sounds cut off.
+@end itemize
+
+@subsubheading Editions, dates and versions
+
+Write the edition and version numbers and date in three places in every
+manual:
+
+@enumerate
+@item
+In the first @code{@@ifinfo} section, for people reading the Texinfo file.
+
+@item
+In the @code{@@titlepage} section, for people reading the printed manual.
+
+@item
+In the `Top' node, for people reading the Info file.
+@end enumerate
+
+@noindent
+Also, it helps to write a note before the first @code{@@ifinfo}
+section to explain what you are doing.
+
+@need 800
+@noindent
+For example:
+
+@example
+@group
+@@c ===> NOTE! <==
+@@c Specify the edition and version numbers and date
+@@c in *three* places:
+@@c 1. First ifinfo section 2. title page 3. top node
+@@c To find the locations, search for !!set
+@end group
+
+@group
+@@ifinfo
+@@c !!set edition, date, version
+This is Edition 4.03, January 1992,
+of the @@cite@{GDB Manual@} for GDB Version 4.3.
+@dots{}
+@end group
+@end example
+
+@noindent
+---or use @code{@@set} and @code{@@value}
+(@pxref{value Example, , @code{@@value} Example}).
+
+@subsubheading Definition Commands
+
+Definition commands are @code{@@deffn}, @code{@@defun},
+@code{@@defmac}, and the like, and enable you to write descriptions in
+a uniform format.@refill
+
+@itemize @bullet
+@item
+Write just one definition command for each entity you define with a
+definition command. The automatic indexing feature creates an index
+entry that leads the reader to the definition.
+
+@item
+Use @code{@@table} @dots{} @code{@@end table} in an appendix that
+contains a summary of functions, not @code{@@deffn} or other definition
+commands.
+@end itemize
+
+@subsubheading Capitalization
+
+@itemize @bullet
+@item
+Capitalize @samp{Texinfo}; it is a name. Do not write the @samp{x} or
+@samp{i} in upper case.
+
+@item
+Capitalize @samp{Info}; it is a name.
+
+@item
+Write @TeX{} using the @code{@@TeX@{@}} command. Note the uppercase
+@samp{T} and @samp{X}. This command causes the formatters to
+typeset the name according to the wishes of Donald Knuth, who wrote
+@TeX{}.
+@end itemize
+
+@subsubheading Spaces
+
+Do not use spaces to format a Texinfo file, except inside of
+@code{@@example} @dots{} @code{@@end example} and similar commands.
+
+@need 700
+For example, @TeX{} fills the following:
+
+@example
+@group
+ @@kbd@{C-x v@}
+ @@kbd@{M-x vc-next-action@}
+ Perform the next logical operation
+ on the version-controlled file
+ corresponding to the current buffer.
+@end group
+@end example
+
+@need 950
+@noindent
+so it looks like this:
+
+@iftex
+@quotation
+ @kbd{C-x v}
+ @kbd{M-x vc-next-action}
+ Perform the next logical operation on the version-controlled file
+ corresponding to the current buffer.
+@end quotation
+@end iftex
+@ifinfo
+@quotation
+`C-x v' `M-x vc-next-action' Perform the next logical operation on the
+version-controlled file corresponding to the current buffer.
+@end quotation
+@end ifinfo
+
+@noindent
+In this case, the text should be formatted with
+@code{@@table}, @code{@@item}, and @code{@@itemx}, to create a table.
+
+@subsubheading @@code, @@samp, @@var, and @samp{---}
+
+@itemize @bullet
+@item
+Use @code{@@code} around Lisp symbols, including command names.
+For example,
+
+@example
+The main function is @@code@{vc-next-action@}, @dots{}
+@end example
+
+@item
+Avoid putting letters such as @samp{s} immediately after an
+@samp{@@code}. Such letters look bad.
+
+@item
+Use @code{@@var} around meta-variables. Do not write angle brackets
+around them.
+
+@item
+Use three hyphens in a row, @samp{---}, to indicate a long dash. @TeX{}
+typesets these as a long dash and the Info formatters reduce three
+hyphens to two.
+@end itemize
+
+@subsubheading Periods Outside of Quotes
+
+Place periods and other punctuation marks @emph{outside} of quotations,
+unless the punctuation is part of the quotation. This practice goes against
+convention, but enables the reader to distinguish between the contents
+of the quotation and the whole passage.
+
+For example, you should write the following sentence with the period
+outside the end quotation marks:
+
+@example
+Evidently, @samp{au} is an abbreviation for ``author''.
+@end example
+
+@noindent
+since @samp{au} does @emph{not} serve as an abbreviation for
+@samp{author.} (with a period following the word).
+
+@subsubheading Introducing New Terms
+
+@itemize @bullet
+@item
+Introduce new terms so that a user who does not know them can understand
+them from context; or write a definition for the term.
+
+For example, in the following, the terms ``check in'', ``register'' and
+``delta'' are all appearing for the first time; the example sentence should be
+rewritten so they are understandable.
+
+@quotation
+The major function assists you in checking in a file to your
+version control system and registering successive sets of changes to
+it as deltas.
+@end quotation
+
+@item
+Use the @code{@@dfn} command around a word being introduced, to indicate
+that the user should not expect to know the meaning already, and should
+expect to learn the meaning from this passage.
+@end itemize
+
+@subsubheading @@pxref
+
+@c !!! maybe include this in the tips on pxref
+@ignore
+By the way, it is okay to use pxref with something else in front of
+it within the parens, as long as the pxref is followed by the close
+paren, and the material inside the parents is not part of a larger
+sentence. Also, you can use xref inside parens as part of a complete
+sentence so long as you terminate the cross reference with punctuation.
+@end ignore
+Absolutely never use @code{@@pxref} except in the special context for
+which it is designed: inside parentheses, with the closing parenthesis
+following immediately after the closing brace. One formatter
+automatically inserts closing punctuation and the other does not. This
+means that the output looks right both in printed output and in an Info
+file, but only when the command is used inside parentheses.
+
+@subsubheading Invoking from a Shell
+
+You can invoke programs such as Emacs, GCC, and GAWK from a shell.
+The documentation for each program should contain a section that
+describes this. Unfortunately, if the node names and titles for these
+sections are all different, readers find it hard to search for the
+section.@refill
+
+Name such sections with a phrase beginning with the word
+@w{`Invoking @dots{}'}, as in `Invoking Emacs'; this way
+users can find the section easily.
+
+@subsubheading @sc{ansi c} Syntax
+
+When you use @code{@@example} to describe a C function's calling
+conventions, use the @sc{ansi c} syntax, like this:@refill
+
+@example
+void dld_init (char *@@var@{path@});
+@end example
+
+@noindent
+And in the subsequent discussion, refer to the argument values by
+writing the same argument names, again highlighted with
+@code{@@var}.@refill
+
+@need 800
+Avoid the obsolete style that looks like this:@refill
+
+@example
+#include <dld.h>
+
+dld_init (path)
+char *path;
+@end example
+
+Also, it is best to avoid writing @code{#include} above the
+declaration just to indicate that the function is declared in a
+header file. The practice may give the misimpression that the
+@code{#include} belongs near the declaration of the function. Either
+state explicitly which header file holds the declaration or, better
+yet, name the header file used for a group of functions at the
+beginning of the section that describes the functions.@refill
+
+@subsubheading Bad Examples
+
+Here are several examples of bad writing to avoid:
+
+In this example, say, `` @dots{} you must @code{@@dfn}@{check
+in@} the new version.'' That flows better.
+
+@quotation
+When you are done editing the file, you must perform a
+@code{@@dfn}@{check in@}.
+@end quotation
+
+In the following example, say, ``@dots{} makes a unified interface such as VC
+mode possible.''
+
+@quotation
+SCCS, RCS and other version-control systems all perform similar
+functions in broadly similar ways (it is this resemblance which makes
+a unified control mode like this possible).
+@end quotation
+
+And in this example, you should specify what `it' refers to:
+
+@quotation
+If you are working with other people, it assists in coordinating
+everyone's changes so they do not step on each other.
+@end quotation
+
+@subsubheading And Finally @dots{}
+
+@itemize @bullet
+@item
+Pronounce @TeX{} as if the @samp{X} were a Greek `chi', as the last
+sound in the name `Bach'. But pronounce Texinfo as in `speck':
+@samp{teckinfo}.
+
+@item
+Write notes for yourself at the very end of a Texinfo file after the
+@code{@@bye}. None of the formatters process text after the
+@code{@@bye}; it is as if the text were within @code{@@ignore} @dots{}
+@code{@@end ignore}.
+@end itemize
+
+@node Sample Texinfo File, Sample Permissions, Tips, Top
+@comment node-name, next, previous, up
+@appendix A Sample Texinfo File
+@cindex Sample Texinfo file, no comments
+
+Here is a complete, short sample Texinfo file, without any commentary.
+You can see this file, with comments, in the first chapter.
+@xref{Short Sample, , A Short Sample Texinfo File}.
+
+@sp 1
+@example
+\input texinfo @@c -*-texinfo-*-
+@@c %**start of header
+@@setfilename sample.info
+@@settitle Sample Document
+@@c %**end of header
+
+@@setchapternewpage odd
+
+@@ifinfo
+This is a short example of a complete Texinfo file.
+
+Copyright 1990 Free Software Foundation, Inc.
+@@end ifinfo
+
+@@titlepage
+@@sp 10
+@@comment The title is printed in a large font.
+@@center @@titlefont@{Sample Title@}
+
+@@c The following two commands start the copyright page.
+@@page
+@@vskip 0pt plus 1filll
+Copyright @@copyright@{@} 1990 Free Software Foundation, Inc.
+@@end titlepage
+
+@@node Top, First Chapter, (dir), (dir)
+@@comment node-name, next, previous, up
+
+@@menu
+* First Chapter:: The first chapter is the
+ only chapter in this sample.
+* Concept Index:: This index has two entries.
+@@end menu
+
+@@node First Chapter, Concept Index, Top, Top
+@@comment node-name, next, previous, up
+@@chapter First Chapter
+@@cindex Sample index entry
+
+This is the contents of the first chapter.
+@@cindex Another sample index entry
+
+Here is a numbered list.
+
+@@enumerate
+@@item
+This is the first item.
+
+@@item
+This is the second item.
+@@end enumerate
+
+The @@code@{makeinfo@} and @@code@{texinfo-format-buffer@}
+commands transform a Texinfo file such as this into
+an Info file; and @@TeX@{@} typesets it for a printed
+manual.
+
+@@node Concept Index, , First Chapter, Top
+@@comment node-name, next, previous, up
+@@unnumbered Concept Index
+
+@@printindex cp
+
+@@contents
+@@bye
+@end example
+
+@node Sample Permissions, Include Files, Sample Texinfo File, Top
+@appendix Sample Permissions
+@cindex Permissions
+@cindex Copying permissions
+
+Texinfo files should contain sections that tell the readers that they
+have the right to copy and distribute the Texinfo file, the Info file,
+and the printed manual.@refill
+
+Also, if you are writing a manual about software, you should explain
+that the software is free and either include the GNU General Public
+License (GPL) or provide a reference to it. @xref{Distrib, ,
+Distribution, emacs, The GNU Emacs Manual}, for an example of the text
+that could be used in the software ``Distribution'', ``General Public
+License'', and ``NO WARRANTY'' sections of a document. @xref{Copying,
+, Texinfo Copying Conditions}, for an example of a brief explanation
+of how the copying conditions provide you with rights. @refill
+
+@menu
+* Inserting Permissions:: How to put permissions in your document.
+* ifinfo Permissions:: Sample @samp{ifinfo} copying permissions.
+* Titlepage Permissions:: Sample Titlepage copying permissions.
+@end menu
+
+@node Inserting Permissions, ifinfo Permissions, , Sample Permissions
+@ifinfo
+@appendixsec Inserting Permissions
+@end ifinfo
+
+In a Texinfo file, the first @code{@@ifinfo} section usually begins
+with a line that says what the file documents. This is what a person
+reading the unprocessed Texinfo file or using the advanced Info
+command @kbd{g *} sees first. @inforef{Expert, Advanced Info
+commands, info}, for more information. (A reader using the regular
+Info commands usually starts reading at the first node and skips
+this first section, which is not in a node.)@refill
+
+In the @code{@@ifinfo} section, the summary sentence is followed by a
+copyright notice and then by the copying permission notice. One of
+the copying permission paragraphs is enclosed in @code{@@ignore} and
+@code{@@end ignore} commands. This paragraph states that the Texinfo
+file can be processed through @TeX{} and printed, provided the printed
+manual carries the proper copying permission notice. This paragraph
+is not made part of the Info file since it is not relevant to the Info
+file; but it is a mandatory part of the Texinfo file since it permits
+people to process the Texinfo file in @TeX{} and print the
+results.@refill
+
+In the printed manual, the Free Software Foundation copying permission
+notice follows the copyright notice and publishing information and is
+located within the region delineated by the @code{@@titlepage} and
+@code{@@end titlepage} commands. The copying permission notice is exactly
+the same as the notice in the @code{@@ifinfo} section except that the
+paragraph enclosed in @code{@@ignore} and @code{@@end ignore} commands is
+not part of the notice.@refill
+
+To make it simple to insert a permission notice into each section of
+the Texinfo file, sample permission notices for each section are
+reproduced in full below.@refill
+
+Note that you may need to specify the correct name of a section
+mentioned in the permission notice. For example, in @cite{The GDB
+Manual}, the name of the section referring to the General Public
+License is called the ``GDB General Public License'', but in the
+sample shown below, that section is referred to generically as the
+``GNU General Public License''. If the Texinfo file does not carry a
+copy of the General Public License, leave out the reference to it, but
+be sure to include the rest of the sentence.@refill
+
+@node ifinfo Permissions, Titlepage Permissions, Inserting Permissions, Sample Permissions
+@comment node-name, next, previous, up
+@appendixsec @samp{ifinfo} Copying Permissions
+@cindex @samp{ifinfo} permissions
+
+In the @code{@@ifinfo} section of a Texinfo file, the standard Free
+Software Foundation permission notice reads as follows:@refill
+
+@example
+This file documents @dots{}
+
+Copyright 1992 Free Software Foundation, Inc.
+
+Permission is granted to make and distribute verbatim
+copies of this manual provided the copyright notice and
+this permission notice are preserved on all copies.
+
+@@ignore
+Permission is granted to process this file through TeX
+and print the results, provided the printed document
+carries a copying permission notice identical to this
+one except for the removal of this paragraph (this
+paragraph not being relevant to the printed manual).
+
+@@end ignore
+Permission is granted to copy and distribute modified
+versions of this manual under the conditions for
+verbatim copying, provided also that the sections
+entitled ``Copying'' and ``GNU General Public License''
+are included exactly as in the original, and provided
+that the entire resulting derived work is distributed
+under the terms of a permission notice identical to this
+one.
+
+Permission is granted to copy and distribute
+translations of this manual into another language,
+under the above conditions for modified versions,
+except that this permission notice may be stated in a
+translation approved by the Free Software Foundation.
+@end example
+
+@node Titlepage Permissions, , ifinfo Permissions, Sample Permissions
+@comment node-name, next, previous, up
+@appendixsec Titlepage Copying Permissions
+@cindex Titlepage permissions
+
+In the @code{@@titlepage} section of a Texinfo file, the standard Free
+Software Foundation copying permission notice follows the copyright
+notice and publishing information. The standard phrasing is as
+follows:@refill
+
+@example
+Permission is granted to make and distribute verbatim
+copies of this manual provided the copyright notice and
+this permission notice are preserved on all copies.
+
+Permission is granted to copy and distribute modified
+versions of this manual under the conditions for
+verbatim copying, provided also that the sections
+entitled ``Copying'' and ``GNU General Public License''
+are included exactly as in the original, and provided
+that the entire resulting derived work is distributed
+under the terms of a permission notice identical to this
+one.
+
+Permission is granted to copy and distribute
+translations of this manual into another language,
+under the above conditions for modified versions,
+except that this permission notice may be stated in a
+translation approved by the Free Software Foundation.
+@end example
+
+@node Include Files, Headings, Sample Permissions, Top
+@comment node-name, next, previous, up
+@appendix Include Files
+@cindex Include files
+
+When @TeX{} or an Info formatting command sees an @code{@@include}
+command in a Texinfo file, it processes the contents of the file named
+by the command and incorporates them into the @sc{dvi} or Info file being
+created. Index entries from the included file are incorporated into
+the indices of the output file.@refill
+
+Include files let you keep a single large document as a collection of
+conveniently small parts.@refill
+
+@menu
+* Using Include Files:: How to use the @code{@@include} command.
+* texinfo-multiple-files-update:: How to create and update nodes and
+ menus when using included files.
+* Include File Requirements:: What @code{texinfo-multiple-files-update} expects.
+* Sample Include File:: A sample outer file with included files
+ within it; and a sample included file.
+* Include Files Evolution:: How use of the @code{@@include} command
+ has changed over time.
+@end menu
+
+@node Using Include Files, texinfo-multiple-files-update, , Include Files
+@appendixsec How to Use Include Files
+@findex include
+
+To include another file within a Texinfo file, write the
+@code{@@include} command at the beginning of a line and follow it on
+the same line by the name of a file to be included. For
+example:@refill
+
+@example
+@@include buffers.texi
+@end example
+
+An included file should simply be a segment of text that you expect to
+be included as is into the overall or @dfn{outer} Texinfo file; it
+should not contain the standard beginning and end parts of a Texinfo
+file. In particular, you should not start an included file with a
+line saying @samp{\input texinfo}; if you do, that phrase is inserted
+into the output file as is. Likewise, you should not end an included
+file with an @code{@@bye} command; nothing after @code{@@bye} is
+formatted.@refill
+
+In the past, you were required to write an @code{@@setfilename} line at the
+beginning of an included file, but no longer. Now, it does not matter
+whether you write such a line. If an @code{@@setfilename} line exists
+in an included file, it is ignored.@refill
+
+Conventionally, an included file begins with an @code{@@node} line that
+is followed by an @code{@@chapter} line. Each included file is one
+chapter. This makes it easy to use the regular node and menu creating
+and updating commands to create the node pointers and menus within the
+included file. However, the simple Emacs node and menu creating and
+updating commands do not work with multiple Texinfo files. Thus you
+cannot use these commands to fill in the `Next', `Previous', and `Up'
+pointers of the @code{@@node} line that begins the included file. Also,
+you cannot use the regular commands to create a master menu for the
+whole file. Either you must insert the menus and the `Next',
+`Previous', and `Up' pointers by hand, or you must use the GNU Emacs
+Texinfo mode command, @code{texinfo-multiple-files-update}, that is
+designed for @code{@@include} files.@refill
+
+@node texinfo-multiple-files-update, Include File Requirements, Using Include Files, Include Files
+@appendixsec @code{texinfo-multiple-files-update}
+@findex texinfo-multiple-files-update
+
+@c !!! changed wording to prevent overfull hbox --bob 26 Mar 93
+GNU Emacs Texinfo mode provides a command to handle included files
+called @code{texinfo-multiple-files-update}. This command creates or
+updates `Next', `Previous', and `Up' pointers of included files as
+well as those in the outer or overall Texinfo file, and it creates or
+updates a main menu in the outer file. Depending whether you call it
+with optional arguments, the command updates only the pointers in the
+first @code{@@node} line of the included files or all of them:@refill
+
+@table @kbd
+@item M-x texinfo-multiple-files-update
+Called without any arguments:@refill
+
+@itemize @minus
+@item
+Create or update the `Next', `Previous', and `Up' pointers of the
+first @code{@@node} line in each file included in an outer or overall
+Texinfo file.@refill
+
+@item
+Create or update the `Top' level node pointers of the outer or
+overall file.@refill
+
+@item
+Create or update a main menu in the outer file.@refill
+@end itemize
+
+@item C-u M-x texinfo-multiple-files-update
+Called with @kbd{C-u} as a prefix argument:
+
+@itemize @minus{}
+@item
+Create or update pointers in the first @code{@@node} line in each
+included file.
+
+@item
+Create or update the `Top' level node pointers of the outer file.
+
+@item
+Create and insert a master menu in the outer file. The master menu
+is made from all the menus in all the included files.@refill
+@end itemize
+
+@item C-u 8 M-x texinfo-multiple-files-update
+Called with a numeric prefix argument, such as @kbd{C-u 8}:
+
+@itemize @minus
+@item
+Create or update @strong{all} the `Next', `Previous', and `Up' pointers
+of all the included files.@refill
+
+@item
+Create or update @strong{all} the menus of all the included
+files.@refill
+
+@item
+Create or update the `Top' level node pointers of the outer or
+overall file.@refill
+
+@item
+And then create a master menu in the outer file. This is similar to
+invoking @code{texinfo-master-menu} with an argument when you are
+working with just one file.@refill
+@end itemize
+@end table
+
+Note the use of the prefix argument in interactive use: with a regular
+prefix argument, just @w{@kbd{C-u}}, the
+@code{texinfo-multiple-files-update} command inserts a master menu;
+with a numeric prefix argument, such as @kbd{C-u 8}, the command
+updates @strong{every} pointer and menu in @strong{all} the files and then inserts a
+master menu.@refill
+
+@node Include File Requirements, Sample Include File, texinfo-multiple-files-update, Include Files
+@appendixsec Include File Requirements
+@cindex Include file requirements
+@cindex Requirements for include files
+
+If you plan to use the @code{texinfo-multiple-files-update} command,
+the outer Texinfo file that lists included files within it should
+contain nothing but the beginning and end parts of a Texinfo file, and
+a number of @code{@@include} commands listing the included files. It
+should not even include indices, which should be listed in an included
+file of their own.@refill
+
+Moreover, each of the included files must contain exactly one highest
+level node (conventionally, @code{@@chapter} or equivalent),
+and this node must be the first node in the included file.
+Furthermore, each of these highest level nodes in each included file
+must be at the same hierarchical level in the file structure.
+Usually, each is an @code{@@chapter}, an @code{@@appendix}, or an
+@code{@@unnumbered} node. Thus, normally, each included file contains
+one, and only one, chapter or equivalent-level node.@refill
+
+The outer file should contain only @emph{one} node, the `Top' node. It
+should @emph{not} contain any nodes besides the single `Top' node. The
+@code{texinfo-multiple-files-update} command will not process
+them.@refill
+
+@node Sample Include File, Include Files Evolution, Include File Requirements, Include Files
+@appendixsec Sample File with @code{@@include}
+@cindex Sample @code{@@include} file
+@cindex Include file sample
+@cindex @code{@@include} file sample
+
+Here is an example of a complete outer Texinfo file with @code{@@include} files
+within it before running @code{texinfo-multiple-files-update}, which
+would insert a main or master menu:@refill
+
+@example
+@group
+\input texinfo @@c -*-texinfo-*-
+@c %**start of header
+@@setfilename include-example.info
+@@settitle Include Example
+@c %**end of header
+@end group
+
+@group
+@@setchapternewpage odd
+@@titlepage
+@@sp 12
+@@center @@titlefont@{Include Example@}
+@@sp 2
+@@center by Whom Ever
+@end group
+
+@group
+@@page
+@@vskip 0pt plus 1filll
+Copyright @@copyright@{@} 1990 Free Software Foundation, Inc.
+@@end titlepage
+@end group
+
+@group
+@@ifinfo
+@@node Top, First, (dir), (dir)
+@@top Master Menu
+@@end ifinfo
+@end group
+
+@group
+@@include foo.texinfo
+@@include bar.texinfo
+@@include concept-index.texinfo
+@end group
+
+@group
+@@summarycontents
+@@contents
+
+@@bye
+@end group
+@end example
+
+An included file, such as @file{foo.texinfo}, might look like
+this:@refill
+
+@example
+@group
+@@node First, Second, , Top
+@@chapter First Chapter
+
+Contents of first chapter @dots{}
+@end group
+@end example
+
+The full contents of @file{concept-index.texinfo} might be as simple as this:
+
+@example
+@group
+@@node Concept Index, , Second, Top
+@@unnumbered Concept Index
+
+@@printindex cp
+@end group
+@end example
+
+The outer Texinfo source file for @cite{The GNU Emacs Lisp Reference
+Manual} is named @file{elisp.texi}. This outer file contains a master
+menu with 417 entries and a list of 41 @code{@@include}
+files.@refill
+
+@node Include Files Evolution, , Sample Include File, Include Files
+@comment node-name, next, previous, up
+@appendixsec Evolution of Include Files
+
+When Info was first created, it was customary to create many small
+Info files on one subject. Each Info file was formatted from its own
+Texinfo source file. This custom meant that Emacs did not need to
+make a large buffer to hold the whole of a large Info file when
+someone wanted information; instead, Emacs allocated just enough
+memory for the small Info file that contained the particular
+information sought. This way, Emacs could avoid wasting memory.@refill
+
+References from one file to another were made by referring to the file
+name as well as the node name. (@xref{Other Info Files, , Referring to
+Other Info Files}. Also, see @ref{Four and Five Arguments, ,
+@code{@@xref} with Four and Five Arguments}.)@refill
+
+Include files were designed primarily as a way to create a single,
+large printed manual out of several smaller Info files. In a printed
+manual, all the references were within the same document, so @TeX{}
+could automatically determine the references' page numbers. The Info
+formatting commands used include files only for creating joint
+indices; each of the individual Texinfo files had to be formatted for
+Info individually. (Each, therefore, required its own
+@code{@@setfilename} line.)@refill
+
+However, because large Info files are now split automatically, it is
+no longer necessary to keep them small.@refill
+
+Nowadays, multiple Texinfo files are used mostly for large documents,
+such as @cite{The GNU Emacs Lisp Reference Manual}, and for projects
+in which several different people write different sections of a
+document simultaneously.@refill
+
+In addition, the Info formatting commands have been extended to work
+with the @code{@@include} command so as to create a single large Info
+file that is split into smaller files if necessary. This means that
+you can write menus and cross references without naming the different
+Texinfo files.@refill
+
+@node Headings, Catching Mistakes, Include Files, Top
+@comment node-name, next, previous, up
+@appendix Page Headings
+@cindex Headings
+@cindex Footings
+@cindex Page numbering
+@cindex Page headings
+@cindex Formatting headings and footings
+
+Most printed manuals contain headings along the top of every page
+except the title and copyright pages. Some manuals also contain
+footings. (Headings and footings have no meaning to Info, which is
+not paginated.)@refill
+
+@menu
+* Headings Introduced:: Conventions for using page headings.
+* Heading Format:: Standard page heading formats.
+* Heading Choice:: How to specify the type of page heading.
+* Custom Headings:: How to create your own headings and footings.
+@end menu
+
+@node Headings Introduced, Heading Format, , Headings
+@ifinfo
+@heading Headings Introduced
+@end ifinfo
+
+Texinfo provides standard page heading formats for manuals that are printed
+on one side of each sheet of paper and for manuals that are printed on
+both sides of the paper. Usually, you will use one or other of these
+formats, but you can specify your own format, if you wish.@refill
+
+In addition, you can specify whether chapters should begin on a new
+page, or merely continue the same page as the previous chapter; and if
+chapters begin on new pages, you can specify whether they must be
+odd-numbered pages.@refill
+
+By convention, a book is printed on both sides of each sheet of paper.
+When you open a book, the right-hand page is odd-numbered, and
+chapters begin on right-hand pages---a preceding left-hand page is
+left blank if necessary. Reports, however, are often printed on just
+one side of paper, and chapters begin on a fresh page immediately
+following the end of the preceding chapter. In short or informal
+reports, chapters often do not begin on a new page at all, but are
+separated from the preceding text by a small amount of whitespace.@refill
+
+The @code{@@setchapternewpage} command controls whether chapters begin
+on new pages, and whether one of the standard heading formats is used.
+In addition, Texinfo has several heading and footing commands that you
+can use to generate your own heading and footing formats.@refill
+
+In Texinfo, headings and footings are single lines at the tops and
+bottoms of pages; you cannot create multiline headings or footings.
+Each header or footer line is divided into three parts: a left part, a
+middle part, and a right part. Any part, or a whole line, may be left
+blank. Text for the left part of a header or footer line is set
+flushleft; text for the middle part is centered; and, text for the
+right part is set flushright.@refill
+
+@node Heading Format, Heading Choice, Headings Introduced, Headings
+@comment node-name, next, previous, up
+@appendixsec Standard Heading Formats
+
+Texinfo provides two standard heading formats, one for manuals printed
+on one side of each sheet of paper, and the other for manuals printed
+on both sides of the paper.
+
+By default, nothing is specified for the footing of a Texinfo file,
+so the footing remains blank.@refill
+
+The standard format for single-sided printing consists of a header
+line in which the left-hand part contains the name of the chapter, the
+central part is blank, and the right-hand part contains the page
+number.@refill
+
+@need 950
+A single-sided page looks like this:
+
+@example
+@group
+ _______________________
+ | |
+ | chapter page number |
+ | |
+ | Start of text ... |
+ | ... |
+ | |
+
+@end group
+@end example
+
+The standard format for two-sided printing depends on whether the page
+number is even or odd. By convention, even-numbered pages are on the
+left- and odd-numbered pages are on the right. (@TeX{} will adjust the
+widths of the left- and right-hand margins. Usually, widths are
+correct, but during double-sided printing, it is wise to check that
+pages will bind properly---sometimes a printer will produce output in
+which the even-numbered pages have a larger right-hand margin than the
+odd-numbered pages.)@refill
+
+In the standard double-sided format, the left part of the left-hand
+(even-numbered) page contains the page number, the central part is
+blank, and the right part contains the title (specified by the
+@code{@@settitle} command). The left part of the right-hand
+(odd-numbered) page contains the name of the chapter, the central part
+is blank, and the right part contains the page number.@refill
+
+@need 750
+Two pages, side by side as in an open book, look like this:@refill
+
+@example
+@group
+ _______________________ _______________________
+ | | | |
+ | page number title | | chapter page number |
+ | | | |
+ | Start of text ... | | More text ... |
+ | ... | | ... |
+ | | | |
+
+@end group
+@end example
+
+@noindent
+The chapter name is preceded by the word @samp{Chapter}, the chapter
+number and a colon. This makes it easier to keep track of where you
+are in the manual.@refill
+
+@node Heading Choice, Custom Headings, Heading Format, Headings
+@comment node-name, next, previous, up
+@appendixsec Specifying the Type of Heading
+
+@TeX{} does not begin to generate page headings for a standard Texinfo
+file until it reaches the @code{@@end titlepage} command. Thus, the
+title and copyright pages are not numbered. The @code{@@end
+titlepage} command causes @TeX{} to begin to generate page headings
+according to a standard format specified by the
+@code{@@setchapternewpage} command that precedes the
+@code{@@titlepage} section.@refill
+
+@need 1000
+There are four possibilities:@refill
+
+@table @asis
+@item No @code{@@setchapternewpage} command
+Cause @TeX{} to specify the single-sided heading format, with chapters
+on new pages. This is the same as @code{@@setchapternewpage on}.@refill
+
+@item @code{@@setchapternewpage on}
+Specify the single-sided heading format, with chapters on new pages.@refill
+
+@item @code{@@setchapternewpage off}
+Cause @TeX{} to start a new chapter on the same page as the last page of
+the preceding chapter, after skipping some vertical whitespace. Also
+cause @TeX{} to typeset for single-sided printing. (You can override
+the headers format with the @code{@@headings double} command; see
+@ref{headings on off, , The @code{@@headings} Command}.)@refill
+
+@item @code{@@setchapternewpage odd}
+Specify the double-sided heading format, with chapters on new pages.@refill
+@end table
+
+@noindent
+Texinfo lacks an @code{@@setchapternewpage even} command.@refill
+
+@node Custom Headings, , Heading Choice, Headings
+@comment node-name, next, previous, up
+@appendixsec How to Make Your Own Headings
+
+You can use the standard headings provided with Texinfo or specify
+your own.@refill
+
+@c Following paragraph is verbose to prevent overfull hboxes.
+Texinfo provides six commands for specifying headings and
+footings. The @code{@@everyheading} command and
+@code{@@everyfooting} command generate page headers and footers
+that are the same for both even- and odd-numbered pages.
+The @code{@@evenheading} command and @code{@@evenfooting}
+command generate headers and footers for even-numbered
+(left-hand) pages; and the @code{@@oddheading} command and
+@code{@@oddfooting} command generate headers and footers for
+odd-numbered (right-hand) pages.@refill
+
+Write custom heading specifications in the Texinfo file immediately
+after the @code{@@end titlepage} command. Enclose your specifications
+between @code{@@iftex} and @code{@@end iftex} commands since the
+@code{texinfo-format-buffer} command may not recognize them. Also,
+you must cancel the predefined heading commands with the
+@code{@@headings off} command before defining your own
+specifications.@refill
+
+@need 1000
+Here is how to tell @TeX{} to place the chapter name at the left, the
+page number in the center, and the date at the right of every header
+for both even- and odd-numbered pages:@refill
+
+@example
+@group
+@@iftex
+@@headings off
+@@everyheading @@thischapter @@| @@thispage @@| @@today@{@}
+@@end iftex
+@end group
+@end example
+
+@noindent
+You need to divide the left part from the central part and the central
+part from the right had part by inserting @samp{@@|} between parts.
+Otherwise, the specification command will not be able to tell where
+the text for one part ends and the next part begins.@refill
+
+Each part can contain text or @@-commands. The text
+is printed as if the part were within an ordinary paragraph in the
+body of the page. The @@-commands replace
+themselves with the page number, date, chapter name, or
+whatever.@refill
+
+@need 950
+Here are the six heading and footing commands:@refill
+
+@findex everyheading
+@findex everyfooting
+@table @code
+@item @@everyheading @var{left} @@| @var{center} @@| @var{right}
+@itemx @@everyfooting @var{left} @@| @var{center} @@| @var{right}
+
+The `every' commands specify the format for both even- and odd-numbered
+pages. These commands are for documents that are printed on one side
+of each sheet of paper, or for documents in which you want symmetrical
+headers or footers.@refill
+
+@findex evenheading
+@findex evenfooting
+@findex oddheading
+@findex oddfooting
+@item @@evenheading @var{left} @@| @var{center} @@| @var{right}
+@itemx @@oddheading @var{left} @@| @var{center} @@| @var{right}
+
+@itemx @@evenfooting @var{left} @@| @var{center} @@| @var{right}
+@itemx @@oddfooting @var{left} @@| @var{center} @@| @var{right}
+
+The `even' and `odd' commands specify the format for even-numbered
+pages and odd-numbered pages. These commands are for books and
+manuals that are printed on both sides of each sheet of paper.@refill
+@end table
+
+Use the @samp{@@this@dots{}} series of @@-commands to
+provide the names of chapters
+and sections and the page number. You can use the
+@samp{@@this@dots{}} commands in the left, center, or right portions
+of headers and footers, or anywhere else in a Texinfo file so long as
+they are between @code{@@iftex} and @code{@@end iftex} commands.@refill
+
+@need 1000
+Here are the @samp{@@this@dots{}} commands:@refill
+
+@table @code
+@findex thispage
+@item @@thispage
+Expands to the current page number.@refill
+@c !!! Karl Berry says that `thissection' fails on page breaks.
+@ignore
+@item @@thissection
+Expands to the name of the current section.@refill
+@end ignore
+
+@findex thischaptername
+@item @@thischaptername
+Expands to the name of the current chapter.@refill
+
+@findex thischapter
+@item @@thischapter
+Expands to the number and name of the current
+chapter, in the format `Chapter 1: Title'.@refill
+
+@findex thistitle
+@item @@thistitle
+Expands to the name of the document, as specified by the
+@code{@@settitle} command.@refill
+
+@findex thisfile
+@item @@thisfile
+For @code{@@include} files only: expands to the name of the current
+@code{@@include} file. If the current Texinfo source file is not an
+@code{@@include} file, this command has no effect. This command does
+@emph{not} provide the name of the current Texinfo source file unless
+it is an @code{@@include} file. (@xref{Include Files}, for more
+information about @code{@@include} files.)@refill
+@end table
+
+@noindent
+You can also use the @code{@@today@{@}} command, which expands to the
+current date, in `1 Jan 1900' format.@refill
+@findex today
+
+Other @@-commands and text are printed in a header or footer just as
+if they were in the body of a page. It is useful to incorporate text,
+particularly when you are writing drafts:@refill
+
+@example
+@group
+@@iftex
+@@headings off
+@@everyheading @@emph@{Draft!@} @@| @@thispage @@| @@thischapter
+@@everyfooting @@| @@| Version: 0.27: @@today@{@}
+@@end iftex
+@end group
+@end example
+
+Beware of overlong titles: they may overlap another part of the
+header or footer and blot it out.@refill
+
+@node Catching Mistakes, Refilling Paragraphs, Headings, Top
+@comment node-name, next, previous, up
+@appendix Formatting Mistakes
+@cindex Structure, catching mistakes in
+@cindex Nodes, catching mistakes
+@cindex Catching mistakes
+@cindex Correcting mistakes
+@cindex Mistakes, catching
+@cindex Problems, catching
+@cindex Debugging the Texinfo structure
+
+Besides mistakes in the content of your documentation, there
+are two kinds of mistake you can make with Texinfo: you can make mistakes
+with @@-commands, and you can make mistakes with the structure of the
+nodes and chapters.@refill
+
+Emacs has two tools for catching the @@-command mistakes and two for
+catching structuring mistakes.@refill
+
+For finding problems with @@-commands, you can run @TeX{} or a region
+formatting command on the region that has a problem; indeed, you can
+run these commands on each region as you write it.@refill
+
+For finding problems with the structure of nodes and chapters, you can use
+@kbd{C-c C-s} (@code{texinfo-show-structure}) and the related @code{occur}
+command and you can use the @kbd{M-x Info-validate} command.@refill
+
+@menu
+* makeinfo preferred:: @code{makeinfo} finds errors.
+* Debugging with Info:: How to catch errors with Info formatting.
+* Debugging with TeX:: How to catch errors with @TeX{} formatting.
+* Using texinfo-show-structure:: How to use @code{texinfo-show-structure}.
+* Using occur:: How to list all lines containing a pattern.
+* Running Info-Validate:: How to find badly referenced nodes.
+@end menu
+
+@node makeinfo preferred, Debugging with Info, , Catching Mistakes
+@ifinfo
+@heading @code{makeinfo} Find Errors
+@end ifinfo
+
+@c !!! changed wording to prevent overfull hbox --bob 26 Mar 93
+The @code{makeinfo} program does an excellent job of catching errors
+and reporting them---far better than either the
+@code{texinfo-format-region} or the @code{texinfo-format-buffer}
+command. In addition, the various functions for automatically
+creating and updating node pointers and menus remove many
+opportunities for human error.@refill
+
+If you can, use the updating commands to create and insert pointers
+and menus. These prevent many errors. Then use @code{makeinfo} (or
+its Texinfo mode manifestations, @code{makeinfo-region} and
+@code{makeinfo-buffer}) to format your file and check for other
+errors. This is the best way to work with Texinfo. But if you
+cannot use @code{makeinfo}, or your problem is very puzzling, then you
+may want to use the tools described in this appendix.@refill
+
+@node Debugging with Info, Debugging with TeX, makeinfo preferred, Catching Mistakes
+@comment node-name, next, previous, up
+@appendixsec Catching Errors with Info Formatting
+@cindex Catching errors with Info formatting
+@cindex Debugging with Info formatting
+
+After you have written part of a Texinfo file, you can use the
+@code{texinfo-format-region} or the @code{makeinfo-region} command to
+see whether the region formats properly.@refill
+
+Most likely, however, you are reading this section because for some
+reason you cannot use the @code{makeinfo-region} command; therefore, the
+rest of this section presumes that you are using
+@code{texinfo-format-region}.@refill
+
+@c !!! changed wording to prevent overfull hbox --bob 26 Mar 93
+If you make a mistake with an @@-command,
+@code{texinfo-format-region} will stop processing at or after the
+error and display an error message. To see where in the buffer the
+error occurred, switch to the @samp{*Info Region*} buffer; the cursor
+will be in a position that is after the location of the error. Also,
+the text will not be formatted after the place where the error
+occurred (or more precisely, where it was detected).@refill
+
+For example, if you accidentally end a menu with the command @code{@@end
+menus} with an `s' on the end, instead of with @code{@@end menu}, you
+will see an error message that says:@refill
+
+@example
+@@end menus is not handled by texinfo
+@end example
+
+@noindent
+The cursor will stop at the point in the buffer where the error
+occurs, or not long after it. The buffer will look like this:@refill
+
+@example
+@group
+---------- Buffer: *Info Region* ----------
+* Menu:
+
+* Using texinfo-show-structure:: How to use
+ `texinfo-show-structure'
+ to catch mistakes.
+* Running Info-Validate:: How to check for
+ unreferenced nodes.
+@@end menus
+@point{}
+---------- Buffer: *Info Region* ----------
+@end group
+@end example
+
+The @code{texinfo-format-region} command sometimes provides slightly
+odd error messages. For example, the following cross reference fails to format:@refill
+
+@example
+(@@xref@{Catching Mistakes, for more info.)
+@end example
+
+@noindent
+In this case, @code{texinfo-format-region} detects the missing closing
+brace but displays a message that says @samp{Unbalanced parentheses}
+rather than @samp{Unbalanced braces}. This is because the formatting
+command looks for mismatches between braces as if they were
+parentheses.@refill
+
+Sometimes @code{texinfo-format-region} fails to detect mistakes. For
+example, in the following, the closing brace is swapped with the
+closing parenthesis:@refill
+
+@example
+(@@xref@{Catching Mistakes), for more info.@}
+@end example
+
+@noindent
+Formatting produces:
+@example
+(*Note for more info.: Catching Mistakes)
+@end example
+
+The only way for you to detect this error is to realize that the
+reference should have looked like this:@refill
+
+@example
+(*Note Catching Mistakes::, for more info.)
+@end example
+
+Incidentally, if you are reading this node in Info and type @kbd{f
+@key{RET}} (@code{Info-follow-reference}), you will generate an error
+message that says:
+
+@example
+No such node: "Catching Mistakes) The only way @dots{}
+@end example
+
+@noindent
+This is because Info perceives the example of the error as the first
+cross reference in this node and if you type a @key{RET} immediately
+after typing the Info @kbd{f} command, Info will attempt to go to the
+referenced node. If you type @kbd{f catch @key{TAB} @key{RET}}, Info
+will complete the node name of the correctly written example and take
+you to the `Catching Mistakes' node. (If you try this, you can return
+from the `Catching Mistakes' node by typing @kbd{l}
+(@code{Info-last}).)
+
+@c !!! section on using Elisp debugger ignored.
+@ignore
+Sometimes @code{texinfo-format-region} will stop long after the
+original error; this is because it does not discover the problem until
+then. In this case, you will need to backtrack.@refill
+
+@c menu
+@c * Using the Emacs Lisp Debugger:: How to use the Emacs Lisp debugger.
+@c end menu
+
+@c node Using the Emacs Lisp Debugger
+@c appendixsubsec Using the Emacs Lisp Debugger
+@c index Using the Emacs Lisp debugger
+@c index Emacs Lisp debugger
+@c index Debugger, using the Emacs Lisp
+
+If an error is especially elusive, you can turn on the Emacs Lisp
+debugger and look at the backtrace; this tells you where in the
+@code{texinfo-format-region} function the problem occurred. You can
+turn on the debugger with the command:@refill
+
+@example
+M-x set-variable @key{RET} debug-on-error @key{RET} t @key{RET}
+@end example
+
+@noindent
+and turn it off with
+
+@example
+M-x set-variable @key{RET} debug-on-error @key{RET} nil @key{RET}
+@end example
+
+Often, when you are using the debugger, it is easier to follow what is
+going on if you use the Emacs Lisp files that are not byte-compiled.
+The byte-compiled sources send octal numbers to the debugger that may
+look mysterious. To use the uncompiled source files, load
+@file{texinfmt.el} and @file{texinfo.el} with the @kbd{M-x load-file}
+command.@refill
+
+The debugger will not catch an error if @code{texinfo-format-region}
+does not detect one. In the example shown above,
+@code{texinfo-format-region} did not find the error when the whole
+list was formatted, but only when part of the list was formatted.
+When @code{texinfo-format-region} did not find an error, the debugger
+did not find one either. @refill
+
+However, when @code{texinfo-format-region} did report an error, it
+invoked the debugger. This is the backtrace it produced:@refill
+
+@example
+---------- Buffer: *Backtrace* ----------
+Signalling: (search-failed "[@},]")
+ re-search-forward("[@},]")
+ (while ...)
+ (let ...)
+ texinfo-format-parse-args()
+ (let ...)
+ texinfo-format-xref()
+ funcall(texinfo-format-xref)
+ (if ...)
+ (let ...)
+ (if ...)
+ (while ...)
+ texinfo-format-scan()
+ (save-excursion ...)
+ (let ...)
+ texinfo-format-region(103370 103631)
+* call-interactively(texinfo-format-region)
+---------- Buffer: *Backtrace* ----------
+@end example
+
+The backtrace is read from the bottom up.
+@code{texinfo-format-region} was called interactively; and it, in
+turn, called various functions, including @code{texinfo-format-scan},
+@code{texinfo-format-xref} and @code{texinfo-format-parse-args}.
+Inside the function @code{texinfo-format-parse-args}, the function
+@code{re-search-forward} was called; it was this function that could
+not find the missing right-hand brace.@refill
+
+@xref{Lisp Debug, , Debugging Emacs Lisp, emacs, The GNU Emacs
+Manual}, for more information.@refill
+@end ignore
+
+@node Debugging with TeX, Using texinfo-show-structure, Debugging with Info, Catching Mistakes
+@comment node-name, next, previous, up
+@appendixsec Catching Errors with @TeX{} Formatting
+@cindex Catching errors with @TeX{} formatting
+@cindex Debugging with @TeX{} formatting
+
+You can also catch mistakes when you format a file with @TeX{}.@refill
+
+@c !!! changed wording to prevent overfull hbox --bob 26 Mar 93
+Usually, you do this after you have run
+@code{texinfo-format-buffer} (or, better, @code{makeinfo-buffer}) on
+the same file, because @code{texinfo-format-buffer} sometimes displays
+error messages that make more sense than @TeX{}. (@xref{Debugging
+with Info}, for more information.)@refill
+
+For example, @TeX{} was run on a Texinfo file, part of which is shown
+here:@refill
+
+@example
+---------- Buffer: texinfo.texi ----------
+name of the texinfo file as an extension. The
+@@samp@{??@} are `wildcards' that cause the shell to
+substitute all the raw index files. (@@xref@{sorting
+indices, for more information about sorting
+indices.)@@refill
+---------- Buffer: texinfo.texi ----------
+@end example
+
+@noindent
+(The cross reference lacks a closing brace.)
+@TeX{} produced the following output, after which it stopped:@refill
+
+@example
+---------- Buffer: *texinfo-tex-shell* ----------
+Runaway argument?
+@{sorting indices, for more information about sorting
+indices.) @@refill @@ETC.
+! Paragraph ended before @@xref was complete.
+<to be read again>
+ @@par
+l.27
+
+?
+---------- Buffer: *texinfo-tex-shell* ----------
+@end example
+
+In this case, @TeX{} produced an accurate and
+understandable error message:
+
+@example
+Paragraph ended before @@xref was complete.
+@end example
+
+@noindent
+@samp{@@par} is an internal @TeX{} command of no relevance to Texinfo.
+@samp{l.27} means that @TeX{} detected the problem on line 27 of the
+Texinfo file. The @samp{?} is the prompt @TeX{} uses in this
+circumstance.@refill
+
+Unfortunately, @TeX{} is not always so helpful, and sometimes you must
+truly be a Sherlock Holmes to discover what went wrong.@refill
+
+In any case, if you run into a problem like this, you can do one of three
+things.@refill
+
+@enumerate
+@item
+You can tell @TeX{} to continue running and ignore just this error by
+typing @key{RET} at the @samp{?} prompt.@refill
+
+@item
+You can tell @TeX{} to continue running and to ignore all errors as best
+it can by typing @kbd{r @key{RET}} at the @samp{?} prompt.@refill
+
+This is often the best thing to do. However, beware: the one error
+may produce a cascade of additional error messages as its consequences
+are felt through the rest of the file. (To stop @TeX{} when it is
+producing such an avalanche of error messages, type @kbd{C-d} (or
+@kbd{C-c C-d}, if you are running a shell inside Emacs Version 18.))@refill
+
+@item
+You can tell @TeX{} to stop this run by typing @kbd{x @key{RET}}
+at the @samp{?} prompt.@refill
+@end enumerate
+
+Please note that if you are running @TeX{} inside Emacs, you need to
+switch to the shell buffer and line at which @TeX{} offers the @samp{?}
+prompt.@refill
+
+Sometimes @TeX{} will format a file without producing error messages even
+though there is a problem. This usually occurs if a command is not ended
+but @TeX{} is able to continue processing anyhow. For example, if you fail
+to end an itemized list with the @code{@@end itemize} command, @TeX{} will
+write a @sc{dvi} file that you can print out. The only error message that
+@TeX{} will give you is the somewhat mysterious comment that@refill
+
+@example
+(@@end occurred inside a group at level 1)
+@end example
+
+@noindent
+However, if you print the @sc{dvi} file, you will find that the text
+of the file that follows the itemized list is entirely indented as if
+it were part of the last item in the itemized list. The error message
+is the way @TeX{} says that it expected to find an @code{@@end}
+command somewhere in the file; but that it could not determine where
+it was needed.@refill
+
+Another source of notoriously hard-to-find errors is a missing
+@code{@@end group} command. If you ever are stumped by
+incomprehensible errors, look for a missing @code{@@end group} command
+first.@refill
+
+If the Texinfo file lacks header lines,
+@TeX{} may stop in the
+beginning of its run and display output that looks like the following.
+The @samp{*} indicates that @TeX{} is waiting for input.@refill
+
+@example
+This is TeX, Version 2.0 for Berkeley UNIX
+(preloaded format=plain-cm 87.10.25)
+(test.texinfo [1])
+*
+@end example
+
+@noindent
+In this case, simply type @kbd{\end @key{RET}} after the asterisk. Then
+write the header lines in the Texinfo file and run the @TeX{} command
+again. (Note the use of the backslash, @samp{\}. @TeX{} uses @samp{\}
+instead of @samp{@@}; and in this circumstance, you are working
+directly with @TeX{}, not with Texinfo.)@refill
+
+@node Using texinfo-show-structure, Using occur, Debugging with TeX, Catching Mistakes
+@comment node-name, next, previous, up
+@appendixsec Using @code{texinfo-show-structure}
+@cindex Showing the structure of a file
+@findex texinfo-show-structure
+
+It is not always easy to keep track of the nodes, chapters, sections, and
+subsections of a Texinfo file. This is especially true if you are revising
+or adding to a Texinfo file that someone else has written.@refill
+
+In GNU Emacs, in Texinfo mode, the @code{texinfo-show-structure}
+command lists all the lines that begin with the @@-commands that
+specify the structure: @code{@@chapter}, @code{@@section},
+@code{@@appendix}, and so on. With an argument (@w{@kbd{C-u}}
+as prefix argument, if interactive),
+the command also shows the @code{@@node} lines. The
+@code{texinfo-show-structure} command is bound to @kbd{C-c C-s} in
+Texinfo mode, by default.@refill
+
+The lines are displayed in a buffer called the @samp{*Occur*} buffer.
+For example, when @code{texinfo-show-structure} was run on an earlier
+version of this appendix, it produced the following:@refill
+
+@smallexample
+Lines matching "^@@\\(chapter \\|sect\\|sub\\|unnum\\|major\\|
+heading \\|appendix\\)" in buffer texinfo.texi.
+ 4:@@appendix Formatting Mistakes
+ 52:@@appendixsec Catching Errors with Info Formatting
+222:@@appendixsec Catching Errors with @@TeX@{@} Formatting
+338:@@appendixsec Using @@code@{texinfo-show-structure@}
+407:@@appendixsubsec Using @@code@{occur@}
+444:@@appendixsec Finding Badly Referenced Nodes
+513:@@appendixsubsec Running @@code@{Info-validate@}
+573:@@appendixsubsec Splitting a File Manually
+@end smallexample
+
+This says that lines 4, 52, and 222 of @file{texinfo.texi} begin with
+the @code{@@appendix}, @code{@@appendixsec}, and @code{@@appendixsec}
+commands respectively. If you move your cursor into the @samp{*Occur*}
+window, you can position the cursor over one of the lines and use the
+@kbd{C-c C-c} command (@code{occur-mode-goto-occurrence}), to jump to
+the corresponding spot in the Texinfo file. @xref{Other Repeating
+Search, , Using Occur, emacs, The GNU Emacs Manual}, for more
+information about @code{occur-mode-goto-occurrence}.@refill
+
+The first line in the @samp{*Occur*} window describes the @dfn{regular
+expression} specified by @var{texinfo-heading-pattern}. This regular
+expression is the pattern that @code{texinfo-show-structure} looks for.
+@xref{Regexps, , Using Regular Expressions, emacs, The GNU Emacs Manual},
+for more information.@refill
+
+When you invoke the @code{texinfo-show-structure} command, Emacs will
+display the structure of the whole buffer. If you want to see the
+structure of just a part of the buffer, of one chapter, for example,
+use the @kbd{C-x n} (@code{narrow-to-region}) command to mark the
+region. (@xref{Narrowing, , , emacs, The GNU Emacs Manual}.) This is
+how the example used above was generated. (To see the whole buffer
+again, use @kbd{C-x w} (@code{widen}).)@refill
+
+If you call @code{texinfo-show-structure} with a prefix argument by
+typing @w{@kbd{C-u C-c C-s}}, it will list lines beginning with
+@code{@@node} as well as the lines beginning with the @@-sign commands
+for @code{@@chapter}, @code{@@section}, and the like.@refill
+
+You can remind yourself of the structure of a Texinfo file by looking at
+the list in the @samp{*Occur*} window; and if you have mis-named a node
+or left out a section, you can correct the mistake.@refill
+
+@node Using occur, Running Info-Validate, Using texinfo-show-structure, Catching Mistakes
+@comment node-name, next, previous, up
+@appendixsec Using @code{occur}
+@cindex Occurrences, listing with @code{@@occur}
+@findex occur
+
+Sometimes the @code{texinfo-show-structure} command produces too much
+information. Perhaps you want to remind yourself of the overall structure
+of a Texinfo file, and are overwhelmed by the detailed list produced by
+@code{texinfo-show-structure}. In this case, you can use the @code{occur}
+command directly. To do this, type@refill
+
+@example
+@kbd{M-x occur}
+@end example
+
+@noindent
+and then, when prompted, type a @dfn{regexp}, a regular expression for
+the pattern you want to match. (@xref{Regexps, , Regular Expressions,
+emacs, The GNU Emacs Manual}.) The @code{occur} command works from
+the current location of the cursor in the buffer to the end of the
+buffer. If you want to run @code{occur} on the whole buffer, place
+the cursor at the beginning of the buffer.@refill
+
+For example, to see all the lines that contain the word
+@samp{@@chapter} in them, just type @samp{@@chapter}. This will
+produce a list of the chapters. It will also list all the sentences
+with @samp{@@chapter} in the middle of the line.@refill
+
+If you want to see only those lines that start with the word
+@samp{@@chapter}, type @samp{^@@chapter} when prompted by
+@code{occur}. If you want to see all the lines that end with a word
+or phrase, end the last word with a @samp{$}; for example,
+@samp{catching mistakes$}. This can be helpful when you want to see
+all the nodes that are part of the same chapter or section and
+therefore have the same `Up' pointer.@refill
+
+@xref{Other Repeating Search, , Using Occur, emacs , The GNU Emacs Manual},
+for more information.@refill
+
+@node Running Info-Validate, , Using occur, Catching Mistakes
+@comment node-name, next, previous, up
+@appendixsec Finding Badly Referenced Nodes
+@findex Info-validate
+@cindex Nodes, checking for badly referenced
+@cindex Checking for badly referenced nodes
+@cindex Looking for badly referenced nodes
+@cindex Finding badly referenced nodes
+@cindex Badly referenced nodes
+
+You can use the @code{Info-validate} command to check whether any of
+the `Next', `Previous', `Up' or other node pointers fail to point to a
+node. This command checks that every node pointer points to an
+existing node. The @code{Info-validate} command works only on Info
+files, not on Texinfo files.@refill
+
+The @code{makeinfo} program validates pointers automatically, so you
+do not need to use the @code{Info-validate} command if you are using
+@code{makeinfo}. You only may need to use @code{Info-validate} if you
+are unable to run @code{makeinfo} and instead must create an Info file
+using @code{texinfo-format-region} or @code{texinfo-format-buffer}, or
+if you write an Info file from scratch.@refill
+
+@menu
+* Using Info-validate:: How to run @code{Info-validate}.
+* Unsplit:: How to create an unsplit file.
+* Tagifying:: How to tagify a file.
+* Splitting:: How to split a file manually.
+@end menu
+
+@node Using Info-validate, Unsplit, , Running Info-Validate
+@appendixsubsec Running @code{Info-validate}
+@cindex Running @code{Info-validate}
+@cindex Info validating a large file
+@cindex Validating a large file
+
+To use @code{Info-validate}, visit the Info file you wish to check and
+type:@refill
+
+@example
+M-x Info-validate
+@end example
+
+@noindent
+(Note that the @code{Info-validate} command requires an upper case
+`I'. You may also need to create a tag table before running
+@code{Info-validate}. @xref{Tagifying}.)@refill
+
+If your file is valid, you will receive a message that says ``File appears
+valid''. However, if you have a pointer that does not point to a node,
+error messages will be displayed in a buffer called @samp{*problems in
+info file*}.@refill
+
+For example, @code{Info-validate} was run on a test file that contained
+only the first node of this manual. One of the messages said:@refill
+
+@example
+In node "Overview", invalid Next: Texinfo Mode
+@end example
+
+@noindent
+This meant that the node called @samp{Overview} had a `Next' pointer that
+did not point to anything (which was true in this case, since the test file
+had only one node in it).@refill
+
+Now suppose we add a node named @samp{Texinfo Mode} to our test case
+but we do not specify a `Previous' for this node. Then we will get
+the following error message:@refill
+
+@example
+In node "Texinfo Mode", should have Previous: Overview
+@end example
+
+@noindent
+This is because every `Next' pointer should be matched by a
+`Previous' (in the node where the `Next' points) which points back.@refill
+
+@code{Info-validate} also checks that all menu entries and cross references
+point to actual nodes.@refill
+
+Note that @code{Info-validate} requires a tag table and does not work
+with files that have been split. (The @code{texinfo-format-buffer}
+command automatically splits large files.) In order to use
+@code{Info-validate} on a large file, you must run
+@code{texinfo-format-buffer} with an argument so that it does not split
+the Info file; and you must create a tag table for the unsplit
+file.@refill
+
+@node Unsplit, Tagifying, Using Info-validate, Running Info-Validate
+@comment node-name, next, previous, up
+@appendixsubsec Creating an Unsplit File
+@cindex Creating an unsplit file
+@cindex Unsplit file creation
+
+You can run @code{Info-validate} only on a single Info file that has a
+tag table. The command will not work on the indirect subfiles that
+are generated when a master file is split. If you have a large file
+(longer than 70,000 bytes or so), you need to run the
+@code{texinfo-format-buffer} or @code{makeinfo-buffer} command in such
+a way that it does not create indirect subfiles. You will also need
+to create a tag table for the Info file. After you have done this,
+you can run @code{Info-validate} and look for badly referenced
+nodes.@refill
+
+@c !!! broke into two paragraphs to prevent overfull hbox --bob 26 Mar 93
+The first step is to create an unsplit Info file.
+
+To prevent @code{texinfo-format-buffer} from splitting a Texinfo file
+into smaller Info files, give a prefix to the @kbd{M-x
+texinfo-format-buffer} command:@refill
+
+@example
+C-u M-x texinfo-format-buffer
+@end example
+
+@noindent
+or else
+
+@example
+C-u C-c C-e C-b
+@end example
+
+@noindent
+When you do this, Texinfo will not split the file and will not create
+a tag table for it. @refill
+@cindex Making a tag table manually
+@cindex Tag table, making manually
+
+@node Tagifying, Splitting, Unsplit, Running Info-Validate
+@appendixsubsec Tagifying a File
+
+After creating an unsplit Info file, you must create a tag table for
+it. Visit the Info file you wish to tagify and type:@refill
+
+@example
+M-x Info-tagify
+@end example
+
+@noindent
+(Note the upper case @key{I} in @code{Info-tagify}.) This creates an
+Info file with a tag table that you can validate.@refill
+
+The third step is to validate the Info file:@refill
+
+@example
+M-x Info-validate
+@end example
+
+@noindent
+(Note the upper case @key{I} in @code{Info-validate}.)
+In brief, the steps are:@refill
+
+@example
+@group
+C-u M-x texinfo-format-buffer
+M-x Info-tagify
+M-x Info-validate
+@end group
+@end example
+
+@c !!! changed wording to prevent overfull hbox --bob 26 Mar 93
+After you have validated the node structure, you will be able to rerun
+@code{texinfo-format-buffer} in the normal way so it will construct a
+tag table and split the file automatically, or you can make the tag
+table and split the file manually.@refill
+
+@node Splitting, , Tagifying, Running Info-Validate
+@comment node-name, next, previous, up
+@appendixsubsec Splitting a File Manually
+@cindex Splitting an Info file manually
+@cindex Info file, splitting manually
+
+You should split a large file or else let the
+@code{texinfo-format-buffer} or @code{makeinfo-buffer} command do it
+for you automatically. (Generally you will let one of the formatting
+commands do this job for you. @xref{Create an Info File}.)@refill
+
+The split-off files are called the indirect subfiles.@refill
+
+Info files are split to save memory. With smaller files, Emacs does not
+have make such a large buffer to hold the information.@refill
+
+If an Info file has more than 30 nodes, you should also make a tag
+table for it. @xref{Using Info-validate}, for information
+about creating a tag table. (Again, tag tables are usually created
+automatically by the formatting command; you only need to create a tag
+table yourself if you are doing the job manually. Most likely, you
+will do this for a large, unsplit file on which you have run
+@code{Info-validate}.)@refill
+
+@c Info-split is autoloaded in `loaddefs.el' in Emacs 18.51
+@ignore
+Before running @code{Info-split}, you need to load the @code{info} library
+into Emacs by giving the command @kbd{M-x load-library @key{RET} info
+@key{RET}}.
+@end ignore
+
+Visit the Info file you wish to tagify and split and type the two
+commands:@refill
+
+@example
+M-x Info-tagify
+M-x Info-split
+@end example
+
+@noindent
+(Note that the @samp{I} in @samp{Info} is upper case.)@refill
+
+When you use the @code{Info-split} command, the buffer is modified into a
+(small) Info file which lists the indirect subfiles. This file should be
+saved in place of the original visited file. The indirect subfiles are
+written in the same directory the original file is in, with names generated
+by appending @samp{-} and a number to the original file name.@refill
+
+The primary file still functions as an Info file, but it contains just
+the tag table and a directory of subfiles.@refill
+
+@node Refilling Paragraphs, Command Syntax, Catching Mistakes, Top
+@comment node-name, next, previous, up
+@appendix Refilling Paragraphs
+@cindex Refilling paragraphs
+@cindex Filling paragraphs
+@findex refill
+
+The @code{@@refill} command refills and, optionally, indents the first
+line of a paragraph.@footnote{Perhaps the command should have been
+called the @code{@@refillandindent} command, but @code{@@refill} is
+shorter and the name was chosen before indenting was possible.} The
+@code{@@refill} command is no longer important, but we describe it here
+because you once needed it. You will see it in many old Texinfo
+files.@refill
+
+@c !!! changed wording to prevent overfull hbox --bob 26 Mar 93
+Without refilling, paragraphs containing long @@-constructs may look
+bad after formatting because the formatter removes @@-commands and
+shortens some lines more than others. In the past, neither
+@code{texinfo-format-region} nor
+@code{texinfo-format-buffer} refilled paragraphs
+automatically. The @code{@@refill} command had to be written at the
+end of every paragraph to cause these formatters to fill them. (Both
+@TeX{} and @code{makeinfo} have always refilled paragraphs
+automatically.) Now, all the Info formatters automatically fill and
+indent those paragraphs that need to be filled and indented.@refill
+
+@c !!! changed wording to prevent overfull hbox --bob 26 Mar 93
+The @code{@@refill} command causes both the @code{texinfo-format-region}
+command and the
+@code{texinfo-format-buffer} command to refill a paragraph in the Info file
+@emph{after} all the other processing has been done. For this reason,
+you can not use @code{@@refill} with a paragraph containing either
+@code{@@*} or @code{@@w@{ @dots{} @}} since the refilling action will
+override those two commands.@refill
+
+The @code{texinfo-format-region} and @code{texinfo-format-buffer}
+commands now automatically append @code{@@refill} to the end of each
+paragraph that should be filled. They do not append @code{@@refill} to
+the ends of paragraphs that contain @code{@@*} or @w{@code{@@w@{ @dots{}@}}}
+and therefore do not refill or indent them.@refill
+
+@node Command Syntax, Obtaining TeX, Refilling Paragraphs, Top
+@comment node-name, next, previous, up
+@appendix @@-Command Syntax
+@cindex @@-command syntax
+
+The character @samp{@@} is used to start special Texinfo commands.
+(It has the same meaning that @samp{\} has in Plain@TeX{}.) Texinfo
+has four types of @@-command:@refill
+
+@table @asis
+@item 1. Non-alphabetic commands.
+These commands consist of an @@ followed by a punctuation mark or other
+character that is not part of the alphabet. Non-alphabetic commands
+are almost always part of the text within a paragraph, and never take
+any argument. The two characters (@@ and the other one) are complete
+in themselves; none is followed by braces. The non-alphabetic
+commands are: @code{@@.}, @code{@@:}, @code{@@*}, @code{@@@@},
+@code{@@@{}, and @code{@@@}}.@refill
+
+@item 2. Alphabetic commands that do not require arguments.
+These commands start with @@ followed by a word followed by left- and
+right-hand braces. These commands insert special symbols in the
+document; they do not require arguments. For example,
+@code{@@dots@{@}} @result{} @samp{@dots{}}, @code{@@equiv@{@}}
+@result{} @samp{@equiv{}}, @code{@@TeX@{@}} @result{} `@TeX{}',
+and @code{@@bullet@{@}} @result{} @samp{@bullet{}}.@refill
+
+@item 3. Alphabetic commands that require arguments within braces.
+These commands start with @@ followed by a letter or a word, followed by an
+argument within braces. For example, the command @code{@@dfn} indicates
+the introductory or defining use of a term; it is used as follows: @samp{In
+Texinfo, @@@@-commands are @@dfn@{mark-up@} commands.}@refill
+
+@item 4. Alphabetic commands that occupy an entire line.
+These commands occupy an entire line. The line starts with @@,
+followed by the name of the command (a word); for example, @code{@@center}
+or @code{@@cindex}. If no argument is needed, the word is followed by
+the end of the line. If there is an argument, it is separated from
+the command name by a space. Braces are not used.@refill
+@end table
+
+@cindex Braces and argument syntax
+Thus, the alphabetic commands fall into classes that have
+different argument syntaxes. You cannot tell to which class a command
+belongs by the appearance of its name, but you can tell by the
+command's meaning: if the command stands for a glyph, it is in
+class 2 and does not require an argument; if it makes sense to use the
+command together with other text as part of a paragraph, the command
+is in class 3 and must be followed by an argument in braces;
+otherwise, it is in class 4 and uses the rest of the line as its
+argument.@refill
+
+The purpose of having a different syntax for commands of classes 3 and
+4 is to make Texinfo files easier to read, and also to help the GNU
+Emacs paragraph and filling commands work properly. There is only one
+exception to this rule: the command @code{@@refill}, which is always
+used at the end of a paragraph immediately following the final period
+or other punctuation character. @code{@@refill} takes no argument and
+does @emph{not} require braces. @code{@@refill} never confuses the
+Emacs paragraph commands because it cannot appear at the beginning of
+a line.@refill
+
+@node Obtaining TeX, New Features, Command Syntax, Top
+@appendix How to Obtain @TeX{}
+@cindex Obtaining @TeX{}
+@cindex @TeX{}, how to obtain
+
+@c !!! Here is information about obtaining TeX. Update it whenever.
+@c Last updated by RJC on 6 October 1992
+@c based on message from elisabet@@.u.washington.edu
+@TeX{} is freely redistributable. You can obtain @TeX{} for Unix
+systems from the University of Washington for a distribution
+fee.@refill
+
+To order a full distribution, send $200.00 for a 1/2-inch 9-track 1600
+bpi (@code{tar} or @code{cpio}) tape reel, or $210.00 for a 1/4-inch
+4-track QIC-24 (@code{tar} or @code{cpio}) cartridge, to:@refill
+
+@display
+Northwest Computing Support Center
+DR-10, Thomson Hall 35
+University of Washington
+Seattle, Washington 98195
+@end display
+
+@noindent
+Please make checks payable to the University of Washington.@refill
+
+Prepaid orders are preferred but purchase orders are acceptable;
+however, purchase orders carry an extra charge of $10.00, to pay for
+processing.@refill
+
+Overseas sites: please add to the base cost $20.00 for shipment via
+air parcel post, or $30.00 for shipment via courier.@refill
+
+Please check with the Northwest Computing Support Center at the
+University of Washington for current prices and formats:@refill
+
+@example
+@group
+@r{telephone:} (206) 543-6259
+@r{email:} elisabet@@u.washington.edu
+@end group
+@end example
+
+@node New Features, Command and Variable Index, Obtaining TeX, Top
+@appendix Second Edition Features
+
+@tex
+% Widen the space for the first column so three control-character
+% strings fit in the first column. Switched back to default .8in
+% value at end of chapter.
+\global\tableindent=1.0in
+@end tex
+
+The second edition of the Texinfo manual describes more than 20 new
+Texinfo mode commands and more than 50 previously undocumented Texinfo
+@@-commands. This edition is more than twice the length of the first
+edition.@refill
+
+Here is a brief description of the new commands.@refill
+
+@menu
+* New Texinfo Mode Commands:: The updating commands are especially useful.
+* New Commands:: Many newly described @@-commands.
+@end menu
+
+@node New Texinfo Mode Commands, New Commands, , New Features
+@appendixsec New Texinfo Mode Commands
+
+Texinfo mode provides commands and features especially designed for
+working with Texinfo files. More than 20 new commands have been
+added, including commands for automatically creating and updating
+both nodes and menus. This is a tedious task when done by hand.@refill
+
+The keybindings are intended to be somewhat mnemonic.@refill
+
+@subheading Update all nodes and menus
+
+The @code{texinfo-master-menu} command is the primary command:
+
+@table @kbd
+@item C-c C-u m
+@itemx M-x texinfo-master-menu
+Create or update a master menu.
+With @kbd{C-u} as a prefix argument,
+first create or update all nodes
+and regular menus.
+@end table
+
+@subheading Update Pointers
+
+@noindent
+Create or update `Next', `Previous', and `Up' node pointers.@refill
+
+@noindent
+@xref{Updating Nodes and Menus}.
+
+@table @kbd
+@item C-c C-u C-n
+@itemx M-x texinfo-update-node
+Update a node.
+
+@item C-c C-u C-e
+@itemx M-x texinfo-every-node-update
+Update every node in the buffer.
+@end table
+
+@subheading Update Menus
+
+@noindent
+Create or update menus.@refill
+
+@noindent
+@xref{Updating Nodes and Menus}.
+
+@table @kbd
+@item C-c C-u C-m
+@itemx M-x texinfo-make-menu
+Make or update a menu.
+
+@item C-c C-u C-a
+@itemx M-x texinfo-all-menus-update
+Make or update all the menus in a buffer.
+With @kbd{C-u} as a prefix argument,
+first update all the nodes.
+@end table
+
+@subheading Insert Title as Description
+
+@noindent
+Insert a node's chapter or section title in the space for the
+description in a menu entry line; position point so you can edit the
+insert. (This command works somewhat differently than the other
+insertion commands, which insert only a predefined string.)@refill
+
+@noindent
+@xref{Inserting, Inserting Frequently Used Commands}.
+
+@table @kbd
+@item C-c C-c C-d
+Insert title.
+@end table
+
+@subheading Format for Info
+
+@noindent
+Provide keybindings both for the Info formatting commands that are
+written in Emacs Lisp and for @code{makeinfo} that is written in
+C.@refill
+
+@noindent
+@xref{Info Formatting}.
+
+@noindent
+Use the Emacs lisp @code{texinfo-format@dots{}} commands:
+
+@table @kbd
+@item C-c C-e C-r
+Format the region.
+
+@item C-c C-e C-b
+Format the buffer.
+@end table
+
+@noindent
+Use @code{makeinfo}:
+
+@table @kbd
+@item C-c C-m C-r
+Format the region.
+
+@item C-c C-m C-b
+Format the buffer.
+
+@item C-c C-m C-l
+Recenter the @code{makeinfo} output buffer.
+
+@item C-c C-m C-k
+Kill the @code{makeinfo} formatting job.
+@end table
+
+@subheading Typeset and Print
+
+@noindent
+Typeset and print Texinfo documents from within Emacs.@refill
+
+@ifinfo
+@noindent
+@xref{Printing}.
+@end ifinfo
+@iftex
+@noindent
+@xref{Printing, , Formatting and Printing}.
+@end iftex
+
+@table @kbd
+@item C-c C-t C-r
+Run @TeX{} on the region.
+
+@item C-c C-t C-b
+Run @TeX{} on the buffer.
+
+@item C-c C-t C-i
+Run @code{texindex}.
+
+@item C-c C-t C-p
+Print the @sc{dvi} file.
+
+@item C-c C-t C-q
+Show the print queue.
+
+@item C-c C-t C-d
+Delete a job from the print queue.
+
+@item C-c C-t C-k
+Kill the current @TeX{} formatting job.
+
+@item C-c C-t C-x
+Quit a currently stopped @TeX{} formatting job.
+
+@item C-c C-t C-l
+Recenter the output buffer.
+@end table
+
+@subheading Other Updating Commands
+
+@noindent
+The ``other updating commands'' do not have standard keybindings because
+they are used less frequently.@refill
+
+@noindent
+@xref{Other Updating Commands}.
+
+@table @kbd
+@item M-x texinfo-insert-node-lines
+Insert missing @code{@@node} lines using
+section titles as node names.
+
+@item M-x texinfo-multiple-files-update
+Update a multi-file document.
+With a numeric prefix, such as @kbd{C-u 8},
+update @strong{every} pointer and
+menu in @strong{all} the files and
+then insert a master menu.
+
+@item M-x texinfo-indent-menu-description
+Indent descriptions in menus.
+
+@item M-x texinfo-sequential-node-update
+Insert node pointers in strict sequence.
+@end table
+
+@node New Commands, , New Texinfo Mode Commands, New Features
+@appendixsec New Texinfo @@-Commands
+
+The second edition of the Texinfo manual describes more than 50
+commands that were not described in the first edition. A third or so
+of these commands existed in Texinfo but were not documented in the
+manual; the others are new. Here is a listing, with brief
+descriptions of them:@refill
+
+@subheading Indexing
+
+@noindent
+Create your own index, and merge indices.@refill
+
+@noindent
+@xref{Indices}.
+
+@table @kbd
+@item @@defindex @var{index-name}
+Define a new index and its indexing command.
+See also the @code{@@defcodeindex} command.
+
+@c written verbosely to avoid overful hbox
+@item @@synindex @var{from-index} @var{into-index}
+Merge the @var{from-index} index into the @var{into-index} index.
+See also the @code{@@syncodeindex} command.
+@end table
+
+@subheading Definitions
+
+@noindent
+Describe functions, variables, macros,
+commands, user options, special forms, and other such artifacts in a
+uniform format.@refill
+
+@noindent
+@xref{Definition Commands}.
+
+@table @kbd
+@item @@deffn @var{category} @var{name} @var{arguments}@dots{}
+Format a description for functions, interactive
+commands, and similar entities.
+
+@item @@defvr, @@defop, @dots{}
+15 other related commands.
+@end table
+
+@subheading Glyphs
+
+@noindent
+Indicate the results of evaluation, expansion,
+printed output, an error message, equivalence of expressions, and the
+location of point.@refill
+
+@noindent
+@xref{Glyphs}.
+
+@table @kbd
+@item @@equiv@{@}
+@itemx @equiv{}
+Equivalence:
+
+@item @@error@{@}
+@itemx @error{}
+Error message
+
+@item @@expansion@{@}
+@itemx @expansion{}
+Macro expansion
+
+@item @@point@{@}
+@itemx @point{}
+Position of point
+
+@item @@print@{@}
+@itemx @print{}
+Printed output
+
+@item @@result@{@}
+@itemx @result{}
+Result of an expression
+@end table
+
+@subheading Page Headings
+
+@noindent
+Customize page headings.
+
+@noindent
+@xref{Headings}.
+
+@table @kbd
+@item @@headings @var{on-off-single-double}
+Headings on or off, single, or double-sided.
+
+@item @@evenfooting [@var{left}] @@| [@var{center}] @@| [@var{right}]
+Footings for even-numbered (left-hand) pages.
+
+@item @@evenheading, @@everyheading, @@oddheading, @dots{}
+Five other related commands.
+
+@item @@thischapter
+Insert name of chapter and chapter number.
+
+@item @@thischaptername, @@thisfile, @@thistitle, @@thispage
+Related commands.
+@end table
+
+@subheading Formatting
+
+@noindent
+Format blocks of text.
+
+@noindent
+@xref{Quotations and Examples}, and@*
+@ref{Lists and Tables, , Making Lists and Tables}.
+
+@table @kbd
+@item @@cartouche
+Draw rounded box surrounding text (not in Info).
+
+@item @@enumerate @var{optional-arg}
+Enumerate a list with letters or numbers.
+
+@item @@exdent @var{line-of-text}
+Remove indentation.
+
+@item @@flushleft
+Left justify.
+
+@item @@flushright
+Right justify.
+
+@item @@format
+Do not narrow nor change font.
+
+@item @@ftable @var{formatting-command}
+@itemx @@vtable @var{formatting-command}
+Two-column table with indexing.
+
+@item @@lisp
+For an example of Lisp code.
+
+@item @@smallexample
+@itemx @@smalllisp
+Like @@table and @@lisp @r{but for} @@smallbook.
+@end table
+
+@subheading Conditionals
+
+@noindent
+Conditionally format text.
+
+@noindent
+@xref{set clear value, , @code{@@set} @code{@@clear} @code{@@value}}.@refill
+
+@table @kbd
+@item @@set @var{flag} [@var{string}]
+Set a flag. Optionally, set value
+of @var{flag} to @var{string}.
+
+@item @@clear @var{flag}
+Clear a flag.
+
+@item @@value@{@var{flag}@}
+Replace with value to which @var{flag} is set.
+
+@item @@ifset @var{flag}
+Format, if @var{flag} is set.
+
+@item @@ifclear @var{flag}
+Ignore, if @var{flag} is set.
+@end table
+
+@subheading @@heading series for Titles
+
+@noindent
+Produce unnumbered headings that do not appear in a table of contents.
+
+@noindent
+@xref{Structuring}.
+
+@table @kbd
+@item @@heading @var{title}
+Unnumbered section-like heading not listed
+in the table of contents of a printed manual.
+
+@item @@chapheading, @@majorheading, @@subheading, @@subsubheading
+Related commands.
+@end table
+
+@need 1000
+@subheading Font commands
+
+@need 1000
+@noindent
+@xref{Smallcaps}, and @*
+@ref{Fonts}.
+
+@table @kbd
+@item @@r@{@var{text}@}
+Print in roman font.
+
+@item @@sc@{@var{text}@}
+Print in @sc{small caps} font.
+@end table
+
+@subheading Miscellaneous
+
+@noindent
+See @ref{title subtitle author, , @code{@@title} @code{@@subtitle} and @code{@@author} Commands},@*
+see @ref{Overfull hboxes},@*
+see @ref{Footnotes},@*
+see @ref{dmn, , Format a Dimension},@*
+see @ref{minus, , Inserting a Minus Sign},@*
+see @ref{paragraphindent, , Paragraph Indenting},@*
+see @ref{Cross Reference Commands},@*
+see @ref{title subtitle author, , @code{@@title} @code{@@subtitle} and @code{@@author}}, and@*
+see @ref{Custom Headings, , How to Make Your Own Headings}.
+
+@need 700
+@table @kbd
+@item @@author @var{author}
+Typeset author's name.
+
+@item @@finalout
+Produce cleaner printed output.
+
+@item @@footnotestyle
+Specify footnote style.
+
+@item @@dmn@{@var{dimension}@}
+Format a dimension.
+
+@item @@minus@{@}
+Generate a minus sign.
+
+@item @@paragraphindent
+Specify paragraph indentation.
+
+@item @@ref@{@var{node-name}, @r{[}@var{entry}@r{]}, @r{[}@var{topic-or-title}@r{]}, @r{[}@var{info-file}@r{]}, @r{[}@var{manual}@r{]}@}
+Make a reference. In the printed manual, the
+reference does not start with the word `see'.
+
+@item @@title @var{title}
+Typeset @var{title} in the alternative
+title page format.
+
+@item @@subtitle @var{subtitle}
+Typeset @var{subtitle} in the alternative
+title page format.
+
+@item @@today@{@}
+Insert the current date.
+@end table
+@tex
+% Switch width of first column of tables back to default value
+\global\tableindent=.8in
+@end tex
+
+@node Command and Variable Index, Concept Index, New Features, Top
+@comment node-name, next, previous, up
+@unnumbered Command and Variable Index
+
+This is an alphabetical list of all the @@-commands and several
+variables. To make the list easier to use, the commands are listed
+without their preceding @samp{@@}.@refill
+
+@printindex fn
+
+@node Concept Index, , Command and Variable Index, Top
+@comment node-name, next, previous, up
+@unnumbered Concept Index
+
+@printindex cp
+
+@summarycontents
+@contents
+@bye
diff --git a/gnu/usr.bin/texinfo/info-files/Makefile b/gnu/usr.bin/texinfo/info-files/Makefile
new file mode 100644
index 0000000..eeda5bd
--- /dev/null
+++ b/gnu/usr.bin/texinfo/info-files/Makefile
@@ -0,0 +1,14 @@
+#
+# Makefile for INFO files
+#
+
+INFOFILES= dir
+
+install:
+ ${INSTALL} -c -g ${BINGRP} -o ${BINOWN} -m 444 ${INFOFILES} \
+ ${DESTDIR}${INFODIR}
+
+clean cleandir obj:
+ @echo -n
+
+.include <bsd.prog.mk>
diff --git a/gnu/usr.bin/texinfo/info-files/dir b/gnu/usr.bin/texinfo/info-files/dir
new file mode 100644
index 0000000..6c7f900
--- /dev/null
+++ b/gnu/usr.bin/texinfo/info-files/dir
@@ -0,0 +1,54 @@
+-*- Text -*-
+This is the file .../info/dir, which contains the topmost node of the
+Info hierarchy. The first time you invoke Info you start off
+looking at that node, which is (dir)Top.
+
+File: dir Node: Top This is the top of the INFO tree
+ This (the Directory node) gives a menu of major topics.
+ Typing "d" returns here, "q" exits, "?" lists all INFO commands, "h"
+ gives a primer for first-timers, "mTexinfo<Return>" visits Texinfo topic,
+ etc.
+ --- PLEASE ADD DOCUMENTATION TO THIS TREE. (See INFO topic first.) ---
+
+* Menu: The list of major topics begins on the next line.
+
+System utilities:
+
+* AMD: (amdref). AMD Reference Manual.
+* CVS: (cvs). CVS Reference Manual.
+* CVS-CLIENT: (cvsclient). CVS client/server Reference Manual.
+* DIFF: (diff). DIFF/PATCH Reference Manual.
+* DC: (dc). The GNU desk calculator.
+* GAWK: (gawk). The GNU AWK language interpreter manual.
+* Info: (info). Manual for this documentation browsing system.
+
+* Send-PR: (send-pr). Manual for the system used to send problem
+ reports or contributions back to the FreeBSD
+ maintainers.
+
+* UUCP: (uucp). UUCP Administration manual.
+
+
+Documentation tools:
+
+* Makeinfo: (makeinfo). GNU Makeinfo guide.
+* PTX: (ptx). GNU permuted index generator.
+* Texi: (texi). GNU TexInfo guide.
+
+
+Programming & development tools:
+
+* GDB annotation: (annotate). Annotations for the GNU Debugger (GDB).
+* AS: (as-all). The GNU Assembler manual.
+* comerr: (com_err). The Common Error Description library.
+* CPP: (cpp). The GNU C pre-processor manual.
+* GCC: (gcc). The GNU C/C++ compiler manual.
+* GXX Internals: (gxxint). Guide to the internals of the GNU C++ compiler.
+* GDB: (gdb). The GNU Debugger (C & C++) manual.
+* GDB Internals: (gdbint). Guide to the internals of GDB.
+* GMP: (gmp). The GNU MP Math library.
+* History: (history). The GNU History library.
+* Readline: (readline). The GNU Readline library
+* Regex: (regex). The GNU regular expression library.
+* Renovate: (reno). The GNU C++ Renovation Project documentation.
+* STABS: (stabs). All about the stab debugging information format.
diff --git a/gnu/usr.bin/texinfo/info/Makefile b/gnu/usr.bin/texinfo/info/Makefile
new file mode 100644
index 0000000..2374d29
--- /dev/null
+++ b/gnu/usr.bin/texinfo/info/Makefile
@@ -0,0 +1,26 @@
+#
+# Bmakefile for GNU info
+#
+# $id$
+#
+
+PROG= info
+
+SRCS+= dir.c display.c dribble.c echo_area.c filesys.c info-utils.c info.c
+SRCS+= infodoc.c infomap.c m-x.c nodes.c search.c session.c signals.c
+SRCS+= terminal.c tilde.c window.c indices.c doc.c nodemenu.c
+SRCS+= footnotes.c variables.c gc.c xmalloc.c getopt1.c getopt.c
+
+CFLAGS+= -I${.CURDIR}
+CFLAGS+= -DNAMED_FUNCTIONS=1 -DSTDC_HEADERS=1 -DHAVE_STRERROR
+CFLAGS+= -DHAVE_UNISTD_H=1 -DHAVE_STRING_H=1 -DHAVE_VARARGS_H=1
+CFLAGS+= -DHAVE_SYS_FCNTL_H=1 -DHAVE_SETVBUF=1 -DHAVE_GETCWD=1 -DHAVE_BZERO=1
+CFLAGS+= -DHAVE_RINDEX=1 -DHAVE_VFPRINTF=1 -DHAVE_VSPRINTF=1
+CFLAGS+= -DHAVE_SYS_TIME_H=1 -DDEFAULT_INFOPATH='"${INFODIR}"'
+
+LDADD+= -ltermcap
+DPADD+= ${LIBTERMCAP}
+
+.include "../../Makefile.inc"
+.include <bsd.prog.mk>
+
diff --git a/gnu/usr.bin/texinfo/info/dir.c b/gnu/usr.bin/texinfo/info/dir.c
new file mode 100644
index 0000000..3820813
--- /dev/null
+++ b/gnu/usr.bin/texinfo/info/dir.c
@@ -0,0 +1,224 @@
+/* dir.c -- How to build a special "dir" node from "localdir" files. */
+
+/* This file is part of GNU Info, a program for reading online documentation
+ stored in Info format.
+
+ Copyright (C) 1993 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ Written by Brian Fox (bfox@ai.mit.edu). */
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/file.h>
+#include <sys/errno.h>
+#include "info-utils.h"
+#include "filesys.h"
+#include "tilde.h"
+
+/* The "dir" node can be built from the contents of a file called "dir",
+ with the addition of the menus of every file called "localdir" found in
+ INFOPATH. */
+
+static void add_menu_to_file_buffer (), insert_text_into_fb_at_binding ();
+
+void
+maybe_build_dir_node (dirname, from_files_named)
+ char *dirname;
+ char *from_files_named;
+{
+ FILE_BUFFER *dir_buffer;
+
+ /* See if the file has already been loaded and exists. */
+ dir_buffer = info_find_file (dirname);
+
+ /* If there is no "dir" in the current info path, we cannot build one
+ from nothing. */
+ if (!dir_buffer)
+ return;
+
+ /* If this directory has already been built, return now. */
+ if (dir_buffer->flags & N_CannotGC)
+ return;
+
+ dir_buffer->flags |= N_CannotGC;
+
+ /* For every file named FROM_FILES_NAMED in the search path, add the
+ contents of that file's menu to our "dir" node. */
+ {
+ struct stat finfo;
+ char *this_dir;
+ int namelen, path_index;
+ int update_tags = 0;
+
+ namelen = strlen (from_files_named);
+ path_index = 0;
+
+ /* Using each element of the path, check for "localdir". Do not check
+ for "localdir.info.Z" or anything else. Only files explictly named
+ "localdir" are eligible. This is a design decision. There can be
+ an info file name "localdir.info" which contains information on the
+ setting up of "localdir" files. */
+ while (this_dir = extract_colon_unit (infopath, &path_index))
+ {
+ char *fullpath;
+ int statable;
+
+ /* Expand a leading tilde if one is present. */
+ if (*this_dir == '~')
+ {
+ char *tilde_expanded_dirname;
+
+ tilde_expanded_dirname = tilde_expand_word (this_dir);
+ free (this_dir);
+ this_dir = tilde_expanded_dirname;
+ }
+
+ fullpath = (char *)xmalloc (3 + strlen (this_dir) + namelen);
+ strcpy (fullpath, this_dir);
+ if (fullpath[strlen (fullpath) - 1] != '/')
+ strcat (fullpath, "/");
+ strcat (fullpath, from_files_named);
+
+ statable = (stat (fullpath, &finfo) == 0);
+
+ if (statable && S_ISREG (finfo.st_mode))
+ {
+ long filesize;
+ char *contents;
+
+ contents = filesys_read_info_file (fullpath, &filesize, &finfo);
+
+ if (contents)
+ {
+ update_tags++;
+ add_menu_to_file_buffer (contents, filesize, dir_buffer);
+ free (contents);
+ }
+ }
+
+ free (fullpath);
+ free (this_dir);
+ }
+ if (update_tags)
+ build_tags_and_nodes (dir_buffer);
+ }
+}
+
+/* Given CONTENTS and FB (a file buffer), add the menu found in CONTENTS
+ to the menu found in FB->contents. Second argument SIZE is the total
+ size of CONTENTS. */
+static void
+add_menu_to_file_buffer (contents, size, fb)
+ char *contents;
+ long size;
+ FILE_BUFFER *fb;
+{
+ SEARCH_BINDING contents_binding, fb_binding;
+ long contents_offset, fb_offset;
+
+ contents_binding.buffer = contents;
+ contents_binding.start = 0;
+ contents_binding.end = size;
+ contents_binding.flags = S_FoldCase | S_SkipDest;
+
+ fb_binding.buffer = fb->contents;
+ fb_binding.start = 0;
+ fb_binding.end = fb->filesize;
+ fb_binding.flags = S_FoldCase | S_SkipDest;
+
+ /* Move to the start of the menus in CONTENTS and FB. */
+ contents_offset = search_forward (INFO_MENU_LABEL, &contents_binding);
+ fb_offset = search_forward (INFO_MENU_LABEL, &fb_binding);
+
+ /* If there is no menu in CONTENTS, quit now. */
+ if (contents_offset == -1)
+ return;
+
+ /* If there is no menu in FB, make one. */
+ if (fb_offset == -1)
+ {
+ /* Find the start of the second node in this file buffer. If there
+ is only one node, we will be adding the contents to the end of
+ this node. */
+ fb_offset = find_node_separator (&fb_binding);
+
+ /* If not even a single node separator, give up. */
+ if (fb_offset == -1)
+ return;
+
+ fb_binding.start = fb_offset;
+ fb_binding.start +=
+ skip_node_separator (fb_binding.buffer + fb_binding.start);
+
+ /* Try to find the next node separator. */
+ fb_offset = find_node_separator (&fb_binding);
+
+ /* If found one, consider that the start of the menu. Otherwise, the
+ start of this menu is the end of the file buffer (i.e., fb->size). */
+ if (fb_offset != -1)
+ fb_binding.start = fb_offset;
+ else
+ fb_binding.start = fb_binding.end;
+
+ insert_text_into_fb_at_binding
+ (fb, &fb_binding, INFO_MENU_LABEL, strlen (INFO_MENU_LABEL));
+
+ fb_binding.buffer = fb->contents;
+ fb_binding.start = 0;
+ fb_binding.end = fb->filesize;
+ fb_offset = search_forward (INFO_MENU_LABEL, &fb_binding);
+ if (fb_offset == -1)
+ abort ();
+ }
+
+ /* CONTENTS_OFFSET and FB_OFFSET point to the starts of the menus that
+ appear in their respective buffers. Add the remainder of CONTENTS
+ to the end of FB's menu. */
+ fb_binding.start = fb_offset;
+ fb_offset = find_node_separator (&fb_binding);
+ if (fb_offset != -1)
+ fb_binding.start = fb_offset;
+ else
+ fb_binding.start = fb_binding.end;
+
+ insert_text_into_fb_at_binding
+ (fb, &fb_binding, contents + contents_offset, size - contents_offset);
+}
+
+static void
+insert_text_into_fb_at_binding (fb, binding, text, textlen)
+ FILE_BUFFER *fb;
+ SEARCH_BINDING *binding;
+ char *text;
+ int textlen;
+{
+ char *contents;
+ long start, end;
+
+ start = binding->start;
+ end = fb->filesize;
+
+ contents = (char *)xmalloc (fb->filesize + textlen + 1);
+ memcpy (contents, fb->contents, start);
+ memcpy (contents + start, text, textlen);
+ memcpy (contents + start + textlen, fb->contents + start, end - start);
+ free (fb->contents);
+ fb->contents = contents;
+ fb->filesize += textlen;
+ fb->finfo.st_size = fb->filesize;
+}
diff --git a/gnu/usr.bin/texinfo/info/display.c b/gnu/usr.bin/texinfo/info/display.c
new file mode 100644
index 0000000..1a348fe
--- /dev/null
+++ b/gnu/usr.bin/texinfo/info/display.c
@@ -0,0 +1,561 @@
+/* display.c -- How to display Info windows. */
+
+/* This file is part of GNU Info, a program for reading online documentation
+ stored in Info format.
+
+ Copyright (C) 1993 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ Written by Brian Fox (bfox@ai.mit.edu). */
+
+#include <stdio.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include "display.h"
+
+extern int info_any_buffered_input_p (); /* Found in session.c. */
+
+static void free_display ();
+static DISPLAY_LINE **make_display ();
+
+/* An array of display lines which tell us what is currently visible on
+ the display. */
+DISPLAY_LINE **the_display = (DISPLAY_LINE **)NULL;
+
+/* Non-zero means do no output. */
+int display_inhibited = 0;
+
+/* Initialize THE_DISPLAY to WIDTH and HEIGHT, with nothing in it. */
+void
+display_initialize_display (width, height)
+ int width, height;
+{
+ free_display (the_display);
+ the_display = make_display (width, height);
+ display_clear_display (the_display);
+}
+
+/* Clear all of the lines in DISPLAY making the screen blank. */
+void
+display_clear_display (display)
+ DISPLAY_LINE **display;
+{
+ register int i;
+ register DISPLAY_LINE *display_line;
+
+ for (i = 0; display_line = display[i]; i++)
+ {
+ display[i]->text[0] = '\0';
+ display[i]->textlen = 0;
+ display[i]->inverse = 0;
+ }
+}
+
+/* Non-zero if we didn't completely redisplay a window. */
+int display_was_interrupted_p = 0;
+
+/* Update the windows pointed to by WINDOW in the_display. This actually
+ writes the text on the screen. */
+void
+display_update_display (window)
+ WINDOW *window;
+{
+ register WINDOW *win;
+
+ display_was_interrupted_p = 0;
+
+ /* For every window in the list, check contents against the display. */
+ for (win = window; win; win = win->next)
+ {
+ /* Only re-display visible windows which need updating. */
+ if (((win->flags & W_WindowVisible) == 0) ||
+ ((win->flags & W_UpdateWindow) == 0) ||
+ (win->height == 0))
+ continue;
+
+ display_update_one_window (win);
+ if (display_was_interrupted_p)
+ break;
+ }
+
+ /* Always update the echo area. */
+ display_update_one_window (the_echo_area);
+}
+
+/* Display WIN on the_display. Unlike display_update_display (), this
+ function only does one window. */
+void
+display_update_one_window (win)
+ WINDOW *win;
+{
+ register char *nodetext; /* Current character to display. */
+ register char *last_node_char; /* Position of the last character in node. */
+ register int i; /* General use index. */
+ char *printed_line; /* Buffer for a printed line. */
+ int pl_index = 0; /* Index into PRINTED_LINE. */
+ int line_index = 0; /* Number of lines done so far. */
+ DISPLAY_LINE **display = the_display;
+
+ /* If display is inhibited, that counts as an interrupted display. */
+ if (display_inhibited)
+ display_was_interrupted_p = 1;
+
+ /* If the window has no height, or display is inhibited, quit now. */
+ if (!win->height || display_inhibited)
+ return;
+
+ /* If the window's first row doesn't appear in the_screen, then it
+ cannot be displayed. This can happen when the_echo_area is the
+ window to be displayed, and the screen has shrunk to less than one
+ line. */
+ if ((win->first_row < 0) || (win->first_row > the_screen->height))
+ return;
+
+ /* Print each line in the window into our local buffer, and then
+ check the contents of that buffer against the display. If they
+ differ, update the display. */
+ printed_line = (char *)xmalloc (1 + win->width);
+
+ if (!win->node || !win->line_starts)
+ goto done_with_node_display;
+
+ nodetext = win->line_starts[win->pagetop];
+ last_node_char = win->node->contents + win->node->nodelen;
+
+ for (; nodetext < last_node_char; nodetext++)
+ {
+ char *rep, *rep_carried_over, rep_temp[2];
+ int replen;
+
+ if (isprint (*nodetext))
+ {
+ rep_temp[0] = *nodetext;
+ replen = 1;
+ rep_temp[1] = '\0';
+ rep = rep_temp;
+ }
+ else
+ {
+ if (*nodetext == '\r' || *nodetext == '\n')
+ {
+ replen = win->width - pl_index;
+ }
+ else
+ {
+ rep = printed_representation (*nodetext, pl_index);
+ replen = strlen (rep);
+ }
+ }
+
+ /* If this character can be printed without passing the width of
+ the line, then stuff it into the line. */
+ if (replen + pl_index < win->width)
+ {
+ /* Optimize if possible. */
+ if (replen == 1)
+ {
+ printed_line[pl_index++] = *rep;
+ }
+ else
+ {
+ for (i = 0; i < replen; i++)
+ printed_line[pl_index++] = rep[i];
+ }
+ }
+ else
+ {
+ DISPLAY_LINE *entry;
+
+ /* If this character cannot be printed in this line, we have
+ found the end of this line as it would appear on the screen.
+ Carefully print the end of the line, and then compare. */
+ if (*nodetext == '\n' || *nodetext == '\r' || *nodetext == '\t')
+ {
+ printed_line[pl_index] = '\0';
+ rep_carried_over = (char *)NULL;
+ }
+ else
+ {
+ /* The printed representation of this character extends into
+ the next line. Remember the offset of the last character
+ printed out of REP so that we can carry the character over
+ to the next line. */
+ for (i = 0; pl_index < (win->width - 1);)
+ printed_line[pl_index++] = rep[i++];
+
+ rep_carried_over = rep + i;
+
+ /* If printing the last character in this window couldn't
+ possibly cause the screen to scroll, place a backslash
+ in the rightmost column. */
+ if (1 + line_index + win->first_row < the_screen->height)
+ {
+ if (win->flags & W_NoWrap)
+ printed_line[pl_index++] = '$';
+ else
+ printed_line[pl_index++] = '\\';
+ }
+ printed_line[pl_index] = '\0';
+ }
+
+ /* We have the exact line as it should appear on the screen.
+ Check to see if this line matches the one already appearing
+ on the screen. */
+ entry = display[line_index + win->first_row];
+
+ /* If the screen line is inversed, then we have to clear
+ the line from the screen first. Why, I don't know. */
+ if (entry->inverse)
+ {
+ terminal_goto_xy (0, line_index + win->first_row);
+ terminal_clear_to_eol ();
+ entry->inverse = 0;
+ entry->text[0] = '\0';
+ entry->textlen = 0;
+ }
+
+ /* Find the offset where these lines differ. */
+ for (i = 0; i < pl_index; i++)
+ if (printed_line[i] != entry->text[i])
+ break;
+
+ /* If the lines are not the same length, or if they differed
+ at all, we must do some redrawing. */
+ if ((i != pl_index) || (pl_index != entry->textlen))
+ {
+ /* Move to the proper point on the terminal. */
+ terminal_goto_xy (i, line_index + win->first_row);
+
+ /* If there is any text to print, print it. */
+ if (i != pl_index)
+ terminal_put_text (printed_line + i);
+
+ /* If the printed text didn't extend all the way to the edge
+ of the window, and text was appearing between here and the
+ edge of the window, clear from here to the end of the line. */
+ if ((pl_index < win->width && pl_index < entry->textlen) ||
+ (entry->inverse))
+ terminal_clear_to_eol ();
+
+ fflush (stdout);
+
+ /* Update the display text buffer. */
+ strcpy (entry->text + i, printed_line + i);
+ entry->textlen = pl_index;
+
+ /* Lines showing node text are not in inverse. Only modelines
+ have that distinction. */
+ entry->inverse = 0;
+ }
+
+ /* We have done at least one line. Increment our screen line
+ index, and check against the bottom of the window. */
+ if (++line_index == win->height)
+ break;
+
+ /* A line has been displayed, and the screen reflects that state.
+ If there is typeahead pending, then let that typeahead be read
+ now, instead of continuing with the display. */
+ if (info_any_buffered_input_p ())
+ {
+ free (printed_line);
+ display_was_interrupted_p = 1;
+ return;
+ }
+
+ /* Reset PL_INDEX to the start of the line. */
+ pl_index = 0;
+
+ /* If there are characters from REP left to print, stuff them
+ into the buffer now. */
+ if (rep_carried_over)
+ for (; rep[pl_index]; pl_index++)
+ printed_line[pl_index] = rep[pl_index];
+
+ /* If this window has chosen not to wrap lines, skip to the end
+ of the physical line in the buffer, and start a new line here. */
+ if (pl_index && (win->flags & W_NoWrap))
+ {
+ char *begin;
+
+ pl_index = 0;
+ printed_line[0] = '\0';
+
+ begin = nodetext;
+
+ while ((nodetext < last_node_char) && (*nodetext != '\n'))
+ nodetext++;
+ }
+ }
+ }
+
+ done_with_node_display:
+ /* We have reached the end of the node or the end of the window. If it
+ is the end of the node, then clear the lines of the window from here
+ to the end of the window. */
+ for (; line_index < win->height; line_index++)
+ {
+ DISPLAY_LINE *entry = display[line_index + win->first_row];
+
+ /* If this line has text on it then make it go away. */
+ if (entry && entry->textlen)
+ {
+ entry->textlen = 0;
+ entry->text[0] = '\0';
+
+ terminal_goto_xy (0, line_index + win->first_row);
+ terminal_clear_to_eol ();
+ }
+ }
+
+ /* Finally, if this window has a modeline it might need to be redisplayed.
+ Check the window's modeline against the one in the display, and update
+ if necessary. */
+ if ((win->flags & W_InhibitMode) == 0)
+ {
+ window_make_modeline (win);
+ line_index = win->first_row + win->height;
+
+ /* This display line must both be in inverse, and have the same
+ contents. */
+ if ((!display[line_index]->inverse) ||
+ (strcmp (display[line_index]->text, win->modeline) != 0))
+ {
+ terminal_goto_xy (0, line_index);
+ terminal_begin_inverse ();
+ terminal_put_text (win->modeline);
+ terminal_end_inverse ();
+ strcpy (display[line_index]->text, win->modeline);
+ display[line_index]->inverse = 1;
+ display[line_index]->textlen = strlen (win->modeline);
+ fflush (stdout);
+ }
+ }
+
+ /* Okay, this window doesn't need updating anymore. */
+ win->flags &= ~W_UpdateWindow;
+ free (printed_line);
+ fflush (stdout);
+}
+
+/* Scroll the region of the_display starting at START, ending at END, and
+ moving the lines AMOUNT lines. If AMOUNT is less than zero, the lines
+ are moved up in the screen, otherwise down. Actually, it is possible
+ for no scrolling to take place in the case that the terminal doesn't
+ support it. This doesn't matter to us. */
+void
+display_scroll_display (start, end, amount)
+ int start, end, amount;
+{
+ register int i, last;
+ DISPLAY_LINE *temp;
+
+ /* If this terminal cannot do scrolling, give up now. */
+ if (!terminal_can_scroll)
+ return;
+
+ /* If there isn't anything displayed on the screen because it is too
+ small, quit now. */
+ if (!the_display[0])
+ return;
+
+ /* If there is typeahead pending, then don't actually do any scrolling. */
+ if (info_any_buffered_input_p ())
+ return;
+
+ /* Do it on the screen. */
+ terminal_scroll_terminal (start, end, amount);
+
+ /* Now do it in the display buffer so our contents match the screen. */
+ if (amount > 0)
+ {
+ last = end + amount;
+
+ /* Shift the lines to scroll right into place. */
+ for (i = 0; i < (end - start); i++)
+ {
+ temp = the_display[last - i];
+ the_display[last - i] = the_display[end - i];
+ the_display[end - i] = temp;
+ }
+
+ /* The lines have been shifted down in the buffer. Clear all of the
+ lines that were vacated. */
+ for (i = start; i != (start + amount); i++)
+ {
+ the_display[i]->text[0] = '\0';
+ the_display[i]->textlen = 0;
+ the_display[i]->inverse = 0;
+ }
+ }
+
+ if (amount < 0)
+ {
+ last = start + amount;
+ for (i = 0; i < (end - start); i++)
+ {
+ temp = the_display[last + i];
+ the_display[last + i] = the_display[start + i];
+ the_display[start + i] = temp;
+ }
+
+ /* The lines have been shifted up in the buffer. Clear all of the
+ lines that are left over. */
+ for (i = end + amount; i != end; i++)
+ {
+ the_display[i]->text[0] = '\0';
+ the_display[i]->textlen = 0;
+ the_display[i]->inverse = 0;
+ }
+ }
+}
+
+/* Try to scroll lines in WINDOW. OLD_PAGETOP is the pagetop of WINDOW before
+ having had its line starts recalculated. OLD_STARTS is the list of line
+ starts that used to appear in this window. OLD_COUNT is the number of lines
+ that appear in the OLD_STARTS array. */
+void
+display_scroll_line_starts (window, old_pagetop, old_starts, old_count)
+ WINDOW *window;
+ int old_pagetop, old_count;
+ char **old_starts;
+{
+ register int i, old, new; /* Indices into the line starts arrays. */
+ int last_new, last_old; /* Index of the last visible line. */
+ int old_first, new_first; /* Index of the first changed line. */
+ int unchanged_at_top = 0;
+ int already_scrolled = 0;
+
+ /* Locate the first line which was displayed on the old window. */
+ old_first = old_pagetop;
+ new_first = window->pagetop;
+
+ /* Find the last line currently visible in this window. */
+ last_new = window->pagetop + (window->height - 1);
+ if (last_new > window->line_count)
+ last_new = window->line_count - 1;
+
+ /* Find the last line which used to be currently visible in this window. */
+ last_old = old_pagetop + (window->height - 1);
+ if (last_old > old_count)
+ last_old = old_count - 1;
+
+ for (old = old_first, new = new_first;
+ old < last_old && new < last_new;
+ old++, new++)
+ if (old_starts[old] != window->line_starts[new])
+ break;
+ else
+ unchanged_at_top++;
+
+ /* Loop through the old lines looking for a match in the new lines. */
+ for (old = old_first + unchanged_at_top; old < last_old; old++)
+ {
+ for (new = new_first; new < last_new; new++)
+ if (old_starts[old] == window->line_starts[new])
+ {
+ /* Find the extent of the matching lines. */
+ for (i = 0; (old + i) < last_old; i++)
+ if (old_starts[old + i] != window->line_starts[new + i])
+ break;
+
+ /* Scroll these lines if there are enough of them. */
+ {
+ int start, end, amount;
+
+ start = (window->first_row
+ + ((old + already_scrolled) - old_pagetop));
+ amount = new - (old + already_scrolled);
+ end = window->first_row + window->height;
+
+ /* If we are shifting the block of lines down, then the last
+ AMOUNT lines will become invisible. Thus, don't bother
+ scrolling them. */
+ if (amount > 0)
+ end -= amount;
+
+ if ((end - start) > 0)
+ {
+ display_scroll_display (start, end, amount);
+
+ /* Some lines have been scrolled. Simulate the scrolling
+ by offsetting the value of the old index. */
+ old += i;
+ already_scrolled += amount;
+ }
+ }
+ }
+ }
+}
+
+/* Move the screen cursor to directly over the current character in WINDOW. */
+void
+display_cursor_at_point (window)
+ WINDOW *window;
+{
+ int vpos, hpos;
+
+ vpos = window_line_of_point (window) - window->pagetop + window->first_row;
+ hpos = window_get_cursor_column (window);
+ terminal_goto_xy (hpos, vpos);
+}
+
+/* **************************************************************** */
+/* */
+/* Functions Static to this File */
+/* */
+/* **************************************************************** */
+
+/* Make a DISPLAY_LINE ** with width and height. */
+static DISPLAY_LINE **
+make_display (width, height)
+ int width, height;
+{
+ register int i;
+ DISPLAY_LINE **display;
+
+ display = (DISPLAY_LINE **)xmalloc ((1 + height) * sizeof (DISPLAY_LINE *));
+
+ for (i = 0; i < height; i++)
+ {
+ display[i] = (DISPLAY_LINE *)xmalloc (sizeof (DISPLAY_LINE));
+ display[i]->text = (char *)xmalloc (1 + width);
+ display[i]->textlen = 0;
+ display[i]->inverse = 0;
+ }
+ display[i] = (DISPLAY_LINE *)NULL;
+ return (display);
+}
+
+/* Free the storage allocated to DISPLAY. */
+static void
+free_display (display)
+ DISPLAY_LINE **display;
+{
+ register int i;
+ register DISPLAY_LINE *display_line;
+
+ if (!display)
+ return;
+
+ for (i = 0; display_line = display[i]; i++)
+ {
+ free (display_line->text);
+ free (display_line);
+ }
+ free (display);
+}
diff --git a/gnu/usr.bin/texinfo/info/display.h b/gnu/usr.bin/texinfo/info/display.h
new file mode 100644
index 0000000..f025403
--- /dev/null
+++ b/gnu/usr.bin/texinfo/info/display.h
@@ -0,0 +1,76 @@
+/* display.h -- How the display in Info is done. */
+
+/* This file is part of GNU Info, a program for reading online documentation
+ stored in Info format.
+
+ Copyright (C) 1993 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ Written by Brian Fox (bfox@ai.mit.edu). */
+
+#ifndef _DISPLAY_H_
+#define _DISPLAY_H_
+
+#include "info-utils.h"
+#include "terminal.h"
+
+typedef struct {
+ char *text; /* Text of the line as it appears. */
+ int textlen; /* Printable Length of TEXT. */
+ int inverse; /* Non-zero means this line is inverse. */
+} DISPLAY_LINE;
+
+/* An array of display lines which tell us what is currently visible on
+ the display. */
+extern DISPLAY_LINE **the_display;
+
+/* Non-zero means do no output. */
+extern int display_inhibited;
+
+/* Non-zero if we didn't completely redisplay a window. */
+extern int display_was_interrupted_p;
+
+/* Initialize THE_DISPLAY to WIDTH and HEIGHT, with nothing in it. */
+extern void display_initialize_display ();
+
+/* Clear all of the lines in DISPLAY making the screen blank. */
+extern void display_clear_display ();
+
+/* Update the windows pointed to by WINDOWS in THE_DISPLAY. This actually
+ writes the text on the screen. */
+extern void display_update_display ();
+
+/* Display WIN on THE_DISPLAY. Unlike display_update_display (), this
+ function only does one window. */
+extern void display_update_one_window ();
+
+/* Move the screen cursor to directly over the current character in WINDOW. */
+extern void display_cursor_at_point ();
+
+/* Scroll the region of the_display starting at START, ending at END, and
+ moving the lines AMOUNT lines. If AMOUNT is less than zero, the lines
+ are moved up in the screen, otherwise down. Actually, it is possible
+ for no scrolling to take place in the case that the terminal doesn't
+ support it. This doesn't matter to us. */
+extern void display_scroll_display ();
+
+/* Try to scroll lines in WINDOW. OLD_PAGETOP is the pagetop of WINDOW before
+ having had its line starts recalculated. OLD_STARTS is the list of line
+ starts that used to appear in this window. OLD_COUNT is the number of lines
+ that appear in the OLD_STARTS array. */
+extern void display_scroll_line_starts ();
+
+#endif /* !_DISPLAY_H_ */
diff --git a/gnu/usr.bin/texinfo/info/doc.c b/gnu/usr.bin/texinfo/info/doc.c
new file mode 100644
index 0000000..b4cd81f
--- /dev/null
+++ b/gnu/usr.bin/texinfo/info/doc.c
@@ -0,0 +1,128 @@
+/* doc.c -- Generated structure containing function names and doc strings.
+
+ This file was automatically made from various source files with the
+ command "./makedoc". DO NOT EDIT THIS FILE, only "./makedoc.c".
+ Source files groveled to make this file include:
+
+ ./session.c
+ ./echo_area.c
+ ./infodoc.c
+ ./m-x.c
+ ./indices.c
+ ./nodemenu.c
+ ./footnotes.c
+ ./variables.c
+
+ An entry in the array FUNCTION_DOC_ARRAY is made for each command
+ found in the above files; each entry consists of a function pointer,
+ a string which is the user-visible name of the function,
+ and a string which documents its purpose. */
+
+#include "doc.h"
+#include "funs.h"
+
+FUNCTION_DOC function_doc_array[] = {
+
+/* Commands found in "./session.c". */
+ { info_next_line, "next-line", "Move down to the next line" },
+ { info_prev_line, "prev-line", "Move up to the previous line" },
+ { info_end_of_line, "end-of-line", "Move to the end of the line" },
+ { info_beginning_of_line, "beginning-of-line", "Move to the start of the line" },
+ { info_forward_char, "forward-char", "Move forward a character" },
+ { info_backward_char, "backward-char", "Move backward a character" },
+ { info_forward_word, "forward-word", "Move forward a word" },
+ { info_backward_word, "backward-word", "Move backward a word" },
+ { info_global_next_node, "global-next-node", "Move forwards or down through node structure" },
+ { info_global_prev_node, "global-prev-node", "Move backwards or up through node structure" },
+ { info_scroll_forward, "scroll-forward", "Scroll forward in this window" },
+ { info_scroll_backward, "scroll-backward", "Scroll backward in this window" },
+ { info_beginning_of_node, "beginning-of-node", "Move to the start of this node" },
+ { info_end_of_node, "end-of-node", "Move to the end of this node" },
+ { info_next_window, "next-window", "Select the next window" },
+ { info_prev_window, "prev-window", "Select the previous window" },
+ { info_split_window, "split-window", "Split the current window" },
+ { info_delete_window, "delete-window", "Delete the current window" },
+ { info_keep_one_window, "keep-one-window", "Delete all other windows" },
+ { info_scroll_other_window, "scroll-other-window", "Scroll the other window" },
+ { info_grow_window, "grow-window", "Grow (or shrink) this window" },
+ { info_tile_windows, "tile-windows", "Divide the available screen space among the visible windows" },
+ { info_toggle_wrap, "toggle-wrap", "Toggle the state of line wrapping in the current window" },
+ { info_next_node, "next-node", "Select the `Next' node" },
+ { info_prev_node, "prev-node", "Select the `Prev' node" },
+ { info_up_node, "up-node", "Select the `Up' node" },
+ { info_last_node, "last-node", "Select the last node in this file" },
+ { info_first_node, "first-node", "Select the first node in this file" },
+ { info_history_node, "history-node", "Select the most recently selected node" },
+ { info_last_menu_item, "last-menu-item", "Select the last item in this node's menu" },
+ { info_menu_digit, "menu-digit", "Select this menu item" },
+ { info_menu_item, "menu-item", "Read a menu item and select its node" },
+ { info_xref_item, "xref-item", "Read a footnote or cross reference and select its node" },
+ { info_find_menu, "find-menu", "Move to the start of this node's menu" },
+ { info_visit_menu, "visit-menu", "Visit as many menu items at once as possible" },
+ { info_goto_node, "goto-node", "Read a node name and select it" },
+ { info_top_node, "top-node", "Select the node `Top' in this file" },
+ { info_dir_node, "dir-node", "Select the node `(dir)'" },
+ { info_kill_node, "kill-node", "Kill this node" },
+ { info_view_file, "view-file", "Read the name of a file and select it" },
+ { info_print_node, "print-node", "Pipe the contents of this node through INFO_PRINT_COMMAND" },
+ { info_search, "search", "Read a string and search for it" },
+ { isearch_forward, "isearch-forward", "Search interactively for a string as you type it" },
+ { isearch_backward, "isearch-backward", "Search interactively for a string as you type it" },
+ { info_move_to_prev_xref, "move-to-prev-xref", "Move to the previous cross reference" },
+ { info_move_to_next_xref, "move-to-next-xref", "Move to the next cross reference" },
+ { info_select_reference_this_line, "select-reference-this-line", "Select reference or menu item appearing on this line" },
+ { info_abort_key, "abort-key", "Cancel current operation" },
+ { info_move_to_window_line, "move-to-window-line", "Move to the cursor to a specific line of the window" },
+ { info_redraw_display, "redraw-display", "Redraw the display" },
+ { info_quit, "quit", "Quit using Info" },
+ { info_do_lowercase_version, "do-lowercase-version", "" },
+ { info_add_digit_to_numeric_arg, "add-digit-to-numeric-arg", "Add this digit to the current numeric argument" },
+ { info_universal_argument, "universal-argument", "Start (or multiply by 4) the current numeric argument" },
+ { info_numeric_arg_digit_loop, "numeric-arg-digit-loop", "" },
+/* Commands found in "./echo_area.c". */
+ { ea_forward, "echo-area-forward", "Move forward a character" },
+ { ea_backward, "echo-area-backward", "Move backward a character" },
+ { ea_beg_of_line, "echo-area-beg-of-line", "Move to the start of this line" },
+ { ea_end_of_line, "echo-area-end-of-line", "Move to the end of this line" },
+ { ea_forward_word, "echo-area-forward-word", "Move forward a word" },
+ { ea_backward_word, "echo-area-backward-word", "Move backward a word" },
+ { ea_delete, "echo-area-delete", "Delete the character under the cursor" },
+ { ea_rubout, "echo-area-rubout", "Delete the character behind the cursor" },
+ { ea_abort, "echo-area-abort", "Cancel or quit operation" },
+ { ea_newline, "echo-area-newline", "Accept (or force completion of) this line" },
+ { ea_quoted_insert, "echo-area-quoted-insert", "Insert next character verbatim" },
+ { ea_insert, "echo-area-insert", "Insert this character" },
+ { ea_tab_insert, "echo-area-tab-insert", "Insert a TAB character" },
+ { ea_transpose_chars, "echo-area-transpose-chars", "Transpose characters at point" },
+ { ea_yank, "echo-area-yank", "Yank back the contents of the last kill" },
+ { ea_yank_pop, "echo-area-yank-pop", "Yank back a previous kill" },
+ { ea_kill_line, "echo-area-kill-line", "Kill to the end of the line" },
+ { ea_backward_kill_line, "echo-area-backward-kill-line", "Kill to the beginning of the line" },
+ { ea_kill_word, "echo-area-kill-word", "Kill the word following the cursor" },
+ { ea_backward_kill_word, "echo-area-backward-kill-word", "Kill the word preceding the cursor" },
+ { ea_possible_completions, "echo-area-possible-completions", "List possible completions" },
+ { ea_complete, "echo-area-complete", "Insert completion" },
+ { ea_scroll_completions_window, "echo-area-scroll-completions-window", "Scroll the completions window" },
+/* Commands found in "./infodoc.c". */
+ { info_get_help_window, "get-help-window", "Display help message" },
+ { info_get_info_help_node, "get-info-help-node", "Visit Info node `(info)Help'" },
+ { describe_key, "describe-key", "Print documentation for KEY" },
+ { info_where_is, "where-is", "Show what to type to execute a given command" },
+/* Commands found in "./m-x.c". */
+ { describe_command, "describe-command", "Read the name of an Info command and describe it" },
+ { info_execute_command, "execute-command", "Read a command name in the echo area and execute it" },
+ { set_screen_height, "set-screen-height", "Set the height of the displayed window" },
+/* Commands found in "./indices.c". */
+ { info_index_search, "index-search", "Look up a string in the index for this file" },
+ { info_next_index_match, "next-index-match", "Go to the next matching index item from the last `\\[index-search]' command" },
+ { info_index_apropos, "index-apropos", "Grovel all known info file's indices for a string and build a menu" },
+/* Commands found in "./nodemenu.c". */
+ { list_visited_nodes, "list-visited-nodes", "Make a window containing a menu of all of the currently visited nodes" },
+ { select_visited_node, "select-visited-node", "Select a node which has been previously visited in a visible window" },
+/* Commands found in "./footnotes.c". */
+ { info_show_footnotes, "show-footnotes", "Show the footnotes associated with this node in another window" },
+/* Commands found in "./variables.c". */
+ { describe_variable, "describe-variable", "Explain the use of a variable" },
+ { set_variable, "set-variable", "Set the value of an Info variable" },
+ { (VFunction *)NULL, (char *)NULL, (char *)NULL }
+};
diff --git a/gnu/usr.bin/texinfo/info/doc.h b/gnu/usr.bin/texinfo/info/doc.h
new file mode 100644
index 0000000..03d82e0
--- /dev/null
+++ b/gnu/usr.bin/texinfo/info/doc.h
@@ -0,0 +1,58 @@
+/* doc.h -- Structure associating function pointers with documentation. */
+
+/* This file is part of GNU Info, a program for reading online documentation
+ stored in Info format.
+
+ Copyright (C) 1993 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ Written by Brian Fox (bfox@ai.mit.edu). */
+
+#ifndef _DOC_H_
+#define _DOC_H_
+
+#if !defined (NULL)
+# define NULL 0x0
+#endif /* !NULL */
+
+#if !defined (__FUNCTION_DEF)
+# define __FUNCTION_DEF
+typedef int Function ();
+typedef void VFunction ();
+#endif /* _FUNCTION_DEF */
+
+typedef struct {
+ VFunction *func;
+#if defined (NAMED_FUNCTIONS)
+ char *func_name;
+#endif /* NAMED_FUNCTIONS */
+ char *doc;
+} FUNCTION_DOC;
+
+extern FUNCTION_DOC function_doc_array[];
+
+extern char *function_documentation ();
+extern char *key_documentation ();
+extern char *pretty_keyname ();
+extern char *replace_in_documentation ();
+extern void info_document_key ();
+extern void dump_map_to_message_buffer ();
+
+#if defined (NAMED_FUNCTIONS)
+extern char *function_name ();
+extern VFunction *named_function ();
+#endif /* NAMED_FUNCTIONS */
+#endif /* !_DOC_H_ */
diff --git a/gnu/usr.bin/texinfo/info/dribble.c b/gnu/usr.bin/texinfo/info/dribble.c
new file mode 100644
index 0000000..3a63a15
--- /dev/null
+++ b/gnu/usr.bin/texinfo/info/dribble.c
@@ -0,0 +1,71 @@
+/* dribble.c -- Dribble files for Info. */
+
+/* This file is part of GNU Info, a program for reading online documentation
+ stored in Info format.
+
+ Copyright (C) 1993 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ Written by Brian Fox (bfox@ai.mit.edu). */
+
+#include <stdio.h>
+#include "dribble.h"
+
+/* When non-zero, it is a stream to write all input characters to for the
+ duration of this info session. */
+FILE *info_dribble_file = (FILE *)NULL;
+
+/* Open a dribble file named NAME, perhaps closing an already open one.
+ This sets the global variable INFO_DRIBBLE_FILE to the open stream. */
+void
+open_dribble_file (name)
+ char *name;
+{
+ /* Perhaps close existing dribble file. */
+ close_dribble_file ();
+
+ info_dribble_file = fopen (name, "w");
+
+#if defined (HAVE_SETVBUF)
+ if (info_dribble_file)
+# if defined (SETVBUF_REVERSED)
+ setvbuf (info_dribble_file, _IONBF, (char *)NULL, 1);
+# else
+ setvbuf (info_dribble_file, (char *)NULL, _IONBF, 1);
+# endif /* !SETVBUF_REVERSED */
+#endif /* HAVE_SETVBUF */
+}
+
+/* If there is a dribble file already open, close it. */
+void
+close_dribble_file ()
+{
+ if (info_dribble_file)
+ {
+ fflush (info_dribble_file);
+ fclose (info_dribble_file);
+ info_dribble_file = (FILE *)NULL;
+ }
+}
+
+/* Write some output to our existing dribble file. */
+void
+dribble (byte)
+ unsigned char byte;
+{
+ if (info_dribble_file)
+ fwrite (&byte, sizeof (unsigned char), 1, info_dribble_file);
+}
diff --git a/gnu/usr.bin/texinfo/info/dribble.h b/gnu/usr.bin/texinfo/info/dribble.h
new file mode 100644
index 0000000..85bd732
--- /dev/null
+++ b/gnu/usr.bin/texinfo/info/dribble.h
@@ -0,0 +1,41 @@
+/* dribble.h -- Functions and vars declared in dribble.c. */
+
+/* This file is part of GNU Info, a program for reading online documentation
+ stored in Info format.
+
+ Copyright (C) 1993 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ Written by Brian Fox (bfox@ai.mit.edu). */
+
+#ifndef _DRIBBLE_H_
+#define _DRIBBLE_H_
+
+/* When non-zero, it is a stream to write all input characters to for the
+ duration of this info session. */
+extern FILE *info_dribble_file;
+
+/* Open a dribble file named NAME, perhaps closing an already open one.
+ This sets the global variable INFO_DRIBBLE_FILE to the open stream. */
+extern void open_dribble_file ();
+
+/* If there is a dribble file already open, close it. */
+extern void close_dribble_file ();
+
+/* Write some output to our existing dribble file. */
+extern void dribble ();
+
+#endif /* !_DRIBBLE_H_ */
diff --git a/gnu/usr.bin/texinfo/info/echo_area.c b/gnu/usr.bin/texinfo/info/echo_area.c
new file mode 100644
index 0000000..a116cc6
--- /dev/null
+++ b/gnu/usr.bin/texinfo/info/echo_area.c
@@ -0,0 +1,1500 @@
+/* echo_area.c -- How to read a line in the echo area. */
+
+/* This file is part of GNU Info, a program for reading online documentation
+ stored in Info format.
+
+ Copyright (C) 1993 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ Written by Brian Fox (bfox@ai.mit.edu). */
+
+#include "info.h"
+
+/* Non-zero means that C-g was used to quit reading input. */
+int info_aborted_echo_area = 0;
+
+/* Non-zero means that the echo area is being used to read input. */
+int echo_area_is_active = 0;
+
+/* The address of the last command executed in the echo area. */
+VFunction *ea_last_executed_command = (VFunction *)NULL;
+
+/* Non-zero means that the last command executed while reading input
+ killed some text. */
+int echo_area_last_command_was_kill = 0;
+
+/* Variables which hold on to the current state of the input line. */
+static char input_line[1 + EA_MAX_INPUT];
+static char *input_line_prompt;
+static int input_line_point;
+static int input_line_beg;
+static int input_line_end;
+static NODE input_line_node = {
+ (char *)NULL, (char *)NULL, (char *)NULL, input_line, EA_MAX_INPUT, 0
+};
+
+static void echo_area_initialize_node ();
+static void push_echo_area (), pop_echo_area ();
+static int echo_area_stack_depth (), echo_area_stack_contains_completions_p ();
+
+static void ea_kill_text ();
+
+/* Non-zero means we force the user to complete. */
+static int echo_area_must_complete_p = 0;
+static int completions_window_p ();
+
+/* If non-null, this is a window which was specifically created to display
+ possible completions output. We remember it so we can delete it when
+ appropriate. */
+static WINDOW *echo_area_completions_window = (WINDOW *)NULL;
+
+/* Variables which keep track of the window which was active prior to
+ entering the echo area. */
+static WINDOW *calling_window = (WINDOW *)NULL;
+static NODE *calling_window_node = (NODE *)NULL;
+static long calling_window_point = 0;
+static long calling_window_pagetop = 0;
+
+/* Remember the node and pertinent variables of the calling window. */
+static void
+remember_calling_window (window)
+ WINDOW *window;
+{
+ /* Only do this if the calling window is not the completions window, or,
+ if it is the completions window and there is no other window. */
+ if (!completions_window_p (window) ||
+ ((window == windows) && !(window->next)))
+ {
+ calling_window = window;
+ calling_window_node = window->node;
+ calling_window_point = window->point;
+ calling_window_pagetop = window->pagetop;
+ }
+}
+
+/* Restore the caller's window so that it shows the node that it was showing
+ on entry to info_read_xxx_echo_area (). */
+static void
+restore_calling_window ()
+{
+ register WINDOW *win, *compwin = (WINDOW *)NULL;
+
+ /* If the calling window is still visible, and it is the window that
+ we used for completions output, then restore the calling window. */
+ for (win = windows; win; win = win->next)
+ {
+ if (completions_window_p (win))
+ compwin = win;
+
+ if (win == calling_window && win == compwin)
+ {
+ window_set_node_of_window (calling_window, calling_window_node);
+ calling_window->point = calling_window_point;
+ calling_window->pagetop = calling_window_pagetop;
+ compwin = (WINDOW *)NULL;
+ break;
+ }
+ }
+
+ /* Delete the completions window if it is still present, it isn't the
+ last window on the screen, and there aren't any prior echo area reads
+ pending which created a completions window. */
+ if (compwin)
+ {
+ if ((compwin != windows || windows->next) &&
+ !echo_area_stack_contains_completions_p ())
+ {
+ WINDOW *next;
+ int pagetop, start, end, amount;
+
+ next = compwin->next;
+ if (next)
+ {
+ start = next->first_row;
+ end = start + next->height;
+ amount = - (compwin->height + 1);
+ pagetop = next->pagetop;
+ }
+
+ info_delete_window_internal (compwin);
+
+ /* This is not necessary because info_delete_window_internal ()
+ calls echo_area_inform_of_deleted_window (), which does the
+ right thing. */
+#if defined (UNNECESSARY)
+ echo_area_completions_window = (WINDOW *)NULL;
+#endif /* UNNECESSARY */
+
+ if (next)
+ {
+ display_scroll_display (start, end, amount);
+ next->pagetop = pagetop;
+ display_update_display (windows);
+ }
+ }
+ }
+}
+
+/* Set up a new input line with PROMPT. */
+static void
+initialize_input_line (prompt)
+ char *prompt;
+{
+ input_line_prompt = prompt;
+ if (prompt)
+ strcpy (input_line, prompt);
+ else
+ input_line[0] = '\0';
+
+ input_line_beg = input_line_end = input_line_point = strlen (prompt);
+}
+
+static char *
+echo_area_after_read ()
+{
+ char *return_value;
+
+ if (info_aborted_echo_area)
+ {
+ info_aborted_echo_area = 0;
+ return_value = (char *)NULL;
+ }
+ else
+ {
+ if (input_line_beg == input_line_end)
+ return_value = savestring ("");
+ else
+ {
+ int line_len = input_line_end - input_line_beg;
+ return_value = (char *) xmalloc (1 + line_len);
+ strncpy (return_value, &input_line[input_line_beg], line_len);
+ return_value[line_len] = '\0';
+ }
+ }
+ return (return_value);
+}
+
+/* Read a line of text in the echo area. Return a malloc ()'ed string,
+ or NULL if the user aborted out of this read. WINDOW is the currently
+ active window, so that we can restore it when we need to. PROMPT, if
+ non-null, is a prompt to print before reading the line. */
+char *
+info_read_in_echo_area (window, prompt)
+ WINDOW *window;
+ char *prompt;
+{
+ char *line;
+
+ /* If the echo area is already active, remember the current state. */
+ if (echo_area_is_active)
+ push_echo_area ();
+
+ /* Initialize our local variables. */
+ initialize_input_line (prompt);
+
+ /* Initialize the echo area for the first (but maybe not the last) time. */
+ echo_area_initialize_node ();
+
+ /* Save away the original node of this window, and the window itself,
+ so echo area commands can temporarily use this window. */
+ remember_calling_window (window);
+
+ /* Let the rest of Info know that the echo area is active. */
+ echo_area_is_active++;
+ active_window = the_echo_area;
+
+ /* Read characters in the echo area. */
+ info_read_and_dispatch ();
+
+ echo_area_is_active--;
+
+ /* Restore the original active window and show point in it. */
+ active_window = calling_window;
+ restore_calling_window ();
+ display_cursor_at_point (active_window);
+ fflush (stdout);
+
+ /* Get the value of the line. */
+ line = echo_area_after_read ();
+
+ /* If there is a previous loop waiting for us, restore it now. */
+ if (echo_area_is_active)
+ pop_echo_area ();
+
+ /* Return the results to the caller. */
+ return (line);
+}
+
+/* (re) Initialize the echo area node. */
+static void
+echo_area_initialize_node ()
+{
+ register int i;
+
+ for (i = input_line_end; i < sizeof (input_line); i++)
+ input_line[i] = ' ';
+
+ input_line[i - 1] = '\n';
+ window_set_node_of_window (the_echo_area, &input_line_node);
+ input_line[input_line_end] = '\n';
+}
+
+/* Prepare to read characters in the echo area. This can initialize the
+ echo area node, but its primary purpose is to side effect the input
+ line buffer contents. */
+void
+echo_area_prep_read ()
+{
+ if (the_echo_area->node != &input_line_node)
+ echo_area_initialize_node ();
+
+ the_echo_area->point = input_line_point;
+ input_line[input_line_end] = '\n';
+ display_update_one_window (the_echo_area);
+ display_cursor_at_point (active_window);
+}
+
+
+/* **************************************************************** */
+/* */
+/* Echo Area Movement Commands */
+/* */
+/* **************************************************************** */
+
+DECLARE_INFO_COMMAND (ea_forward, "Move forward a character")
+{
+ if (count < 0)
+ ea_backward (window, -count, key);
+ else
+ {
+ input_line_point += count;
+ if (input_line_point > input_line_end)
+ input_line_point = input_line_end;
+ }
+}
+
+DECLARE_INFO_COMMAND (ea_backward, "Move backward a character")
+{
+ if (count < 0)
+ ea_forward (window, -count, key);
+ else
+ {
+ input_line_point -= count;
+ if (input_line_point < input_line_beg)
+ input_line_point = input_line_beg;
+ }
+}
+
+DECLARE_INFO_COMMAND (ea_beg_of_line, "Move to the start of this line")
+{
+ input_line_point = input_line_beg;
+}
+
+DECLARE_INFO_COMMAND (ea_end_of_line, "Move to the end of this line")
+{
+ input_line_point = input_line_end;
+}
+
+#define alphabetic(c) (islower (c) || isupper (c) || isdigit (c))
+
+/* Move forward a word in the input line. */
+DECLARE_INFO_COMMAND (ea_forward_word, "Move forward a word")
+{
+ int c;
+
+ if (count < 0)
+ ea_backward_word (window, -count, key);
+ else
+ {
+ while (count--)
+ {
+ if (input_line_point == input_line_end)
+ return;
+
+ /* If we are not in a word, move forward until we are in one.
+ Then, move forward until we hit a non-alphabetic character. */
+ c = input_line[input_line_point];
+
+ if (!alphabetic (c))
+ {
+ while (++input_line_point < input_line_end)
+ {
+ c = input_line[input_line_point];
+ if (alphabetic (c))
+ break;
+ }
+ }
+
+ if (input_line_point == input_line_end)
+ return;
+
+ while (++input_line_point < input_line_end)
+ {
+ c = input_line[input_line_point];
+ if (!alphabetic (c))
+ break;
+ }
+ }
+ }
+}
+
+DECLARE_INFO_COMMAND (ea_backward_word, "Move backward a word")
+{
+ int c;
+
+ if (count < 0)
+ ea_forward_word (window, -count, key);
+ else
+ {
+ while (count--)
+ {
+ if (input_line_point == input_line_beg)
+ return;
+
+ /* Like ea_forward_word (), except that we look at the
+ characters just before point. */
+
+ c = input_line[input_line_point - 1];
+
+ if (!alphabetic (c))
+ {
+ while (--input_line_point)
+ {
+ c = input_line[input_line_point - 1];
+ if (alphabetic (c))
+ break;
+ }
+ }
+
+ while (input_line_point != input_line_beg)
+ {
+ c = input_line[input_line_point - 1];
+ if (!alphabetic (c))
+ break;
+ else
+ --input_line_point;
+ }
+ }
+ }
+}
+
+DECLARE_INFO_COMMAND (ea_delete, "Delete the character under the cursor")
+{
+ register int i;
+
+ if (count < 0)
+ ea_rubout (window, -count, key);
+ else
+ {
+ if (input_line_point == input_line_end)
+ return;
+
+ if (info_explicit_arg || count > 1)
+ {
+ int orig_point;
+
+ orig_point = input_line_point;
+ ea_forward (window, count, key);
+ ea_kill_text (orig_point, input_line_point);
+ input_line_point = orig_point;
+ }
+ else
+ {
+ for (i = input_line_point; i < input_line_end; i++)
+ input_line[i] = input_line[i + 1];
+
+ input_line_end--;
+ }
+ }
+}
+
+DECLARE_INFO_COMMAND (ea_rubout, "Delete the character behind the cursor")
+{
+ if (count < 0)
+ ea_delete (window, -count, key);
+ else
+ {
+ int start;
+
+ if (input_line_point == input_line_beg)
+ return;
+
+ start = input_line_point;
+ ea_backward (window, count, key);
+
+ if (info_explicit_arg || count > 1)
+ ea_kill_text (start, input_line_point);
+ else
+ ea_delete (window, count, key);
+ }
+}
+
+DECLARE_INFO_COMMAND (ea_abort, "Cancel or quit operation")
+{
+ /* If any text, just discard it, and restore the calling window's node.
+ If no text, quit. */
+ if (input_line_end != input_line_beg)
+ {
+ terminal_ring_bell ();
+ input_line_end = input_line_point = input_line_beg;
+ if (calling_window->node != calling_window_node)
+ restore_calling_window ();
+ }
+ else
+ info_aborted_echo_area = 1;
+}
+
+DECLARE_INFO_COMMAND (ea_newline, "Accept (or force completion of) this line")
+{
+ /* Stub does nothing. Simply here to see if it has been executed. */
+}
+
+DECLARE_INFO_COMMAND (ea_quoted_insert, "Insert next character verbatim")
+{
+ unsigned char character;
+
+ character = info_get_another_input_char ();
+ ea_insert (window, count, character);
+}
+
+DECLARE_INFO_COMMAND (ea_insert, "Insert this character")
+{
+ register int i;
+
+ if ((input_line_end + 1) == EA_MAX_INPUT)
+ {
+ terminal_ring_bell ();
+ return;
+ }
+
+ for (i = input_line_end + 1; i != input_line_point; i--)
+ input_line[i] = input_line[i - 1];
+
+ input_line[input_line_point] = key;
+ input_line_point++;
+ input_line_end++;
+}
+
+DECLARE_INFO_COMMAND (ea_tab_insert, "Insert a TAB character")
+{
+ ea_insert (window, count, '\t');
+}
+
+/* Transpose the characters at point. If point is at the end of the line,
+ then transpose the characters before point. */
+DECLARE_INFO_COMMAND (ea_transpose_chars, "Transpose characters at point")
+{
+ /* Handle conditions that would make it impossible to transpose
+ characters. */
+ if (!count || !input_line_point || (input_line_end - input_line_beg) < 2)
+ return;
+
+ while (count)
+ {
+ int t;
+ if (input_line_point == input_line_end)
+ {
+ t = input_line[input_line_point - 1];
+
+ input_line[input_line_point - 1] = input_line[input_line_point - 2];
+ input_line[input_line_point - 2] = t;
+ }
+ else
+ {
+ t = input_line[input_line_point];
+
+ input_line[input_line_point] = input_line[input_line_point - 1];
+ input_line[input_line_point - 1] = t;
+
+ if (count < 0 && input_line_point != input_line_beg)
+ input_line_point--;
+ else
+ input_line_point++;
+ }
+
+ if (count < 0)
+ count++;
+ else
+ count--;
+ }
+}
+
+/* **************************************************************** */
+/* */
+/* Echo Area Killing and Yanking */
+/* */
+/* **************************************************************** */
+
+static char **kill_ring = (char **)NULL;
+static int kill_ring_index = 0; /* Number of kills appearing in KILL_RING. */
+static int kill_ring_slots = 0; /* Number of slots allocated to KILL_RING. */
+static int kill_ring_loc = 0; /* Location of current yank pointer. */
+
+/* The largest number of kills that we remember at one time. */
+static int max_retained_kills = 15;
+
+DECLARE_INFO_COMMAND (ea_yank, "Yank back the contents of the last kill")
+{
+ register int i;
+ register char *text;
+
+ if (!kill_ring_index)
+ {
+ inform_in_echo_area ("Kill ring is empty");
+ return;
+ }
+
+ text = kill_ring[kill_ring_loc];
+
+ for (i = 0; text[i]; i++)
+ ea_insert (window, 1, text[i]);
+}
+
+/* If the last command was yank, or yank_pop, and the text just before
+ point is identical to the current kill item, then delete that text
+ from the line, rotate the index down, and yank back some other text. */
+DECLARE_INFO_COMMAND (ea_yank_pop, "Yank back a previous kill")
+{
+ register int len;
+
+ if (((ea_last_executed_command != ea_yank) &&
+ (ea_last_executed_command != ea_yank_pop)) ||
+ (kill_ring_index == 0))
+ return;
+
+ len = strlen (kill_ring[kill_ring_loc]);
+
+ /* Delete the last yanked item from the line. */
+ {
+ register int i, counter;
+
+ counter = input_line_end - input_line_point;
+
+ for (i = input_line_point - len; counter; i++, counter--)
+ input_line[i] = input_line[i + len];
+
+ input_line_end -= len;
+ input_line_point -= len;
+ }
+
+ /* Get a previous kill, and yank that. */
+ kill_ring_loc--;
+ if (kill_ring_loc < 0)
+ kill_ring_loc = kill_ring_index - 1;
+
+ ea_yank (window, count, key);
+}
+
+/* Delete the text from point to end of line. */
+DECLARE_INFO_COMMAND (ea_kill_line, "Kill to the end of the line")
+{
+ if (count < 0)
+ {
+ ea_kill_text (input_line_point, input_line_beg);
+ input_line_point = input_line_beg;
+ }
+ else
+ ea_kill_text (input_line_point, input_line_end);
+}
+
+/* Delete the text from point to beg of line. */
+DECLARE_INFO_COMMAND (ea_backward_kill_line,
+ "Kill to the beginning of the line")
+{
+ if (count < 0)
+ ea_kill_text (input_line_point, input_line_end);
+ else
+ {
+ ea_kill_text (input_line_point, input_line_beg);
+ input_line_point = input_line_beg;
+ }
+}
+
+/* Delete from point to the end of the current word. */
+DECLARE_INFO_COMMAND (ea_kill_word, "Kill the word following the cursor")
+{
+ int orig_point = input_line_point;
+
+ if (count < 0)
+ ea_backward_kill_word (window, -count, key);
+ else
+ {
+ ea_forward_word (window, count, key);
+
+ if (input_line_point != orig_point)
+ ea_kill_text (orig_point, input_line_point);
+
+ input_line_point = orig_point;
+ }
+}
+
+/* Delete from point to the start of the current word. */
+DECLARE_INFO_COMMAND (ea_backward_kill_word,
+ "Kill the word preceding the cursor")
+{
+ int orig_point = input_line_point;
+
+ if (count < 0)
+ ea_kill_word (window, -count, key);
+ else
+ {
+ ea_backward_word (window, count, key);
+
+ if (input_line_point != orig_point)
+ ea_kill_text (orig_point, input_line_point);
+ }
+}
+
+/* The way to kill something. This appends or prepends to the last
+ kill, if the last command was a kill command. If FROM is less
+ than TO, then the killed text is appended to the most recent kill,
+ otherwise it is prepended. If the last command was not a kill command,
+ then a new slot is made for this kill. */
+static void
+ea_kill_text (from, to)
+ int from, to;
+{
+ register int i, counter, distance;
+ int killing_backwards, slot;
+ char *killed_text;
+
+ killing_backwards = (from > to);
+
+ /* If killing backwards, reverse the values of FROM and TO. */
+ if (killing_backwards)
+ {
+ int temp = from;
+ from = to;
+ to = temp;
+ }
+
+ /* Remember the text that we are about to delete. */
+ distance = to - from;
+ killed_text = (char *)xmalloc (1 + distance);
+ strncpy (killed_text, &input_line[from], distance);
+ killed_text[distance] = '\0';
+
+ /* Actually delete the text from the line. */
+ counter = input_line_end - to;
+
+ for (i = from; counter; i++, counter--)
+ input_line[i] = input_line[i + distance];
+
+ input_line_end -= distance;
+
+ /* If the last command was a kill, append or prepend the killed text to
+ the last command's killed text. */
+ if (echo_area_last_command_was_kill)
+ {
+ char *old, *new;
+
+ slot = kill_ring_loc;
+ old = kill_ring[slot];
+ new = (char *)xmalloc (1 + strlen (old) + strlen (killed_text));
+
+ if (killing_backwards)
+ {
+ /* Prepend TEXT to current kill. */
+ strcpy (new, killed_text);
+ strcat (new, old);
+ }
+ else
+ {
+ /* Append TEXT to current kill. */
+ strcpy (new, old);
+ strcat (new, killed_text);
+ }
+
+ free (old);
+ free (killed_text);
+ kill_ring[slot] = new;
+ }
+ else
+ {
+ /* Try to store the kill in a new slot, unless that would cause there
+ to be too many remembered kills. */
+ slot = kill_ring_index;
+
+ if (slot == max_retained_kills)
+ slot = 0;
+
+ if (slot + 1 > kill_ring_slots)
+ kill_ring = (char **) xrealloc
+ (kill_ring,
+ (kill_ring_slots += max_retained_kills) * sizeof (char *));
+
+ if (slot != kill_ring_index)
+ free (kill_ring[slot]);
+ else
+ kill_ring_index++;
+
+ kill_ring[slot] = killed_text;
+
+ kill_ring_loc = slot;
+ }
+
+ /* Notice that the last command was a kill. */
+ echo_area_last_command_was_kill++;
+}
+
+/* **************************************************************** */
+/* */
+/* Echo Area Completion */
+/* */
+/* **************************************************************** */
+
+/* Pointer to an array of REFERENCE to complete over. */
+static REFERENCE **echo_area_completion_items = (REFERENCE **)NULL;
+
+/* Sorted array of REFERENCE * which is the possible completions found in
+ the variable echo_area_completion_items. If there is only one element,
+ it is the only possible completion. */
+static REFERENCE **completions_found = (REFERENCE **)NULL;
+static int completions_found_index = 0;
+static int completions_found_slots = 0;
+
+/* The lowest common denominator found while completing. */
+static REFERENCE *LCD_completion;
+
+/* Internal functions used by the user calls. */
+static void build_completions (), completions_must_be_rebuilt ();
+
+/* Variable which holds the output of completions. */
+static NODE *possible_completions_output_node = (NODE *)NULL;
+
+static char *compwin_name = "*Completions*";
+
+/* Return non-zero if WINDOW is a window used for completions output. */
+static int
+completions_window_p (window)
+ WINDOW *window;
+{
+ int result = 0;
+
+ if (internal_info_node_p (window->node) &&
+ (strcmp (window->node->nodename, compwin_name) == 0))
+ result = 1;
+
+ return (result);
+}
+
+/* Workhorse for completion readers. If FORCE is non-zero, the user cannot
+ exit unless the line read completes, or is empty. */
+char *
+info_read_completing_internal (window, prompt, completions, force)
+ WINDOW *window;
+ char *prompt;
+ REFERENCE **completions;
+ int force;
+{
+ char *line;
+
+ /* If the echo area is already active, remember the current state. */
+ if (echo_area_is_active)
+ push_echo_area ();
+
+ echo_area_must_complete_p = force;
+
+ /* Initialize our local variables. */
+ initialize_input_line (prompt);
+
+ /* Initialize the echo area for the first (but maybe not the last) time. */
+ echo_area_initialize_node ();
+
+ /* Save away the original node of this window, and the window itself,
+ so echo area commands can temporarily use this window. */
+ remember_calling_window (window);
+
+ /* Save away the list of items to complete over. */
+ echo_area_completion_items = completions;
+ completions_must_be_rebuilt ();
+
+ active_window = the_echo_area;
+ echo_area_is_active++;
+
+ /* Read characters in the echo area. */
+ while (1)
+ {
+ info_read_and_dispatch ();
+
+ line = echo_area_after_read ();
+
+ /* Force the completion to take place if the user hasn't accepted
+ a default or aborted, and if FORCE is active. */
+ if (force && line && *line && completions)
+ {
+ register int i;
+
+ build_completions ();
+
+ /* If there is only one completion, then make the line be that
+ completion. */
+ if (completions_found_index == 1)
+ {
+ free (line);
+ line = savestring (completions_found[0]->label);
+ break;
+ }
+
+ /* If one of the completions matches exactly, then that is okay, so
+ return the current line. */
+ for (i = 0; i < completions_found_index; i++)
+ if (stricmp (completions_found[i]->label, line) == 0)
+ {
+ free (line);
+ line = savestring (completions_found[i]->label);
+ break;
+ }
+
+ /* If no match, go back and try again. */
+ if (i == completions_found_index)
+ {
+ inform_in_echo_area ("Not complete");
+ continue;
+ }
+ }
+ break;
+ }
+ echo_area_is_active--;
+
+ /* Restore the original active window and show point in it. */
+ active_window = calling_window;
+ restore_calling_window ();
+ display_cursor_at_point (active_window);
+ fflush (stdout);
+
+ echo_area_completion_items = (REFERENCE **)NULL;
+ completions_must_be_rebuilt ();
+
+ /* If there is a previous loop waiting for us, restore it now. */
+ if (echo_area_is_active)
+ pop_echo_area ();
+
+ return (line);
+}
+
+/* Read a line in the echo area with completion over COMPLETIONS. */
+char *
+info_read_completing_in_echo_area (window, prompt, completions)
+ WINDOW *window;
+ char *prompt;
+ REFERENCE **completions;
+{
+ return (info_read_completing_internal (window, prompt, completions, 1));
+}
+
+/* Read a line in the echo area allowing completion over COMPLETIONS, but
+ not requiring it. */
+char *
+info_read_maybe_completing (window, prompt, completions)
+ WINDOW *window;
+ char *prompt;
+ REFERENCE **completions;
+{
+ return (info_read_completing_internal (window, prompt, completions, 0));
+}
+
+DECLARE_INFO_COMMAND (ea_possible_completions, "List possible completions")
+{
+ if (!echo_area_completion_items)
+ {
+ ea_insert (window, count, key);
+ return;
+ }
+
+ build_completions ();
+
+ if (!completions_found_index)
+ {
+ terminal_ring_bell ();
+ inform_in_echo_area ("No completions");
+ }
+ else if ((completions_found_index == 1) && (key != '?'))
+ {
+ inform_in_echo_area ("Sole completion");
+ }
+ else
+ {
+ register int i, l;
+ int limit, count, max_label = 0;
+
+ initialize_message_buffer ();
+ printf_to_message_buffer
+ ("There %s %d ", completions_found_index == 1 ? "is" : "are",
+ completions_found_index);
+ printf_to_message_buffer
+ ("completion%s:\n", completions_found_index == 1 ? "" : "s");
+
+ /* Find the maximum length of a label. */
+ for (i = 0; i < completions_found_index; i++)
+ {
+ int len = strlen (completions_found[i]->label);
+ if (len > max_label)
+ max_label = len;
+ }
+
+ max_label += 4;
+
+ /* Find out how many columns we should print in. */
+ limit = calling_window->width / max_label;
+ if (limit != 1 && (limit * max_label == calling_window->width))
+ limit--;
+
+ /* Avoid a possible floating exception. If max_label > width then
+ the limit will be 0 and a divide-by-zero fault will result. */
+ if (limit == 0)
+ limit = 1;
+
+ /* How many iterations of the printing loop? */
+ count = (completions_found_index + (limit - 1)) / limit;
+
+ /* Watch out for special case. If the number of completions is less
+ than LIMIT, then just do the inner printing loop. */
+ if (completions_found_index < limit)
+ count = 1;
+
+ /* Print the sorted items, up-and-down alphabetically. */
+ for (i = 0; i < count; i++)
+ {
+ register int j;
+
+ for (j = 0, l = i; j < limit; j++)
+ {
+ if (l >= completions_found_index)
+ break;
+ else
+ {
+ char *label;
+ int printed_length, k;
+
+ label = completions_found[l]->label;
+ printed_length = strlen (label);
+ printf_to_message_buffer ("%s", label);
+
+ if (j + 1 < limit)
+ {
+ for (k = 0; k < max_label - printed_length; k++)
+ printf_to_message_buffer (" ");
+ }
+ }
+ l += count;
+ }
+ printf_to_message_buffer ("\n");
+ }
+
+ /* Make a new node to hold onto possible completions. Don't destroy
+ dangling pointers. */
+ {
+ NODE *temp;
+
+ temp = message_buffer_to_node ();
+ add_gcable_pointer (temp->contents);
+ name_internal_node (temp, compwin_name);
+ possible_completions_output_node = temp;
+ }
+
+ /* Find a suitable window for displaying the completions output.
+ First choice is an existing window showing completions output.
+ If there is only one window, and it is large, make another
+ (smaller) window, and use that one. Otherwise, use the caller's
+ window. */
+ {
+ WINDOW *compwin;
+
+ compwin = get_internal_info_window (compwin_name);
+
+ if (!compwin)
+ {
+ /* If we can split the window to display most of the completion
+ items, then do so. */
+ if (calling_window->height > (count * 2))
+ {
+ int start, end, pagetop;
+
+ active_window = calling_window;
+
+ /* Perhaps we can scroll this window on redisplay. */
+ start = calling_window->first_row;
+ pagetop = calling_window->pagetop;
+
+ compwin =
+ window_make_window (possible_completions_output_node);
+ active_window = the_echo_area;
+ window_change_window_height
+ (compwin, -(compwin->height - (count + 2)));
+
+ window_adjust_pagetop (calling_window);
+ remember_calling_window (calling_window);
+
+#if defined (SPLIT_BEFORE_ACTIVE)
+ /* If the pagetop hasn't changed, scrolling the calling
+ window is a reasonable thing to do. */
+ if (pagetop == calling_window->pagetop)
+ {
+ end = start + calling_window->height;
+ display_scroll_display
+ (start, end, calling_window->prev->height + 1);
+ }
+#else /* !SPLIT_BEFORE_ACTIVE */
+ /* If the pagetop has changed, set the new pagetop here. */
+ if (pagetop != calling_window->pagetop)
+ {
+ int newtop = calling_window->pagetop;
+ calling_window->pagetop = pagetop;
+ set_window_pagetop (calling_window, newtop);
+ }
+#endif /* !SPLIT_BEFORE_ACTIVE */
+
+ echo_area_completions_window = compwin;
+ remember_window_and_node (compwin, compwin->node);
+ }
+ else
+ compwin = calling_window;
+ }
+
+ if (compwin->node != possible_completions_output_node)
+ {
+ window_set_node_of_window
+ (compwin, possible_completions_output_node);
+ remember_window_and_node (compwin, compwin->node);
+ }
+
+ display_update_display (windows);
+ }
+ }
+}
+
+DECLARE_INFO_COMMAND (ea_complete, "Insert completion")
+{
+ if (!echo_area_completion_items)
+ {
+ ea_insert (window, count, key);
+ return;
+ }
+
+ /* If KEY is SPC, and we are not forcing completion to take place, simply
+ insert the key. */
+ if (!echo_area_must_complete_p && key == SPC)
+ {
+ ea_insert (window, count, key);
+ return;
+ }
+
+ if (ea_last_executed_command == ea_complete)
+ {
+ /* If the keypress is a SPC character, and we have already tried
+ completing once, and there are several completions, then check
+ the batch of completions to see if any continue with a space.
+ If there are some, insert the space character and continue. */
+ if (key == SPC && completions_found_index > 1)
+ {
+ register int i, offset;
+
+ offset = input_line_end - input_line_beg;
+
+ for (i = 0; i < completions_found_index; i++)
+ if (completions_found[i]->label[offset] == ' ')
+ break;
+
+ if (completions_found[i])
+ ea_insert (window, 1, ' ');
+ else
+ {
+ ea_possible_completions (window, count, key);
+ return;
+ }
+ }
+ else
+ {
+ ea_possible_completions (window, count, key);
+ return;
+ }
+ }
+
+ input_line_point = input_line_end;
+ build_completions ();
+
+ if (!completions_found_index)
+ terminal_ring_bell ();
+ else if (LCD_completion->label[0] == '\0')
+ ea_possible_completions (window, count, key);
+ else
+ {
+ register int i;
+ input_line_point = input_line_end = input_line_beg;
+ for (i = 0; LCD_completion->label[i]; i++)
+ ea_insert (window, 1, LCD_completion->label[i]);
+ }
+}
+
+/* Utility REFERENCE used to store possible LCD. */
+static REFERENCE LCD_reference = { (char *)NULL, (char *)NULL, (char *)NULL };
+
+static void remove_completion_duplicates ();
+
+/* Variables which remember the state of the most recent call
+ to build_completions (). */
+static char *last_completion_request = (char *)NULL;
+static REFERENCE **last_completion_items = (REFERENCE **)NULL;
+
+/* How to tell the completion builder to reset internal state. */
+static void
+completions_must_be_rebuilt ()
+{
+ maybe_free (last_completion_request);
+ last_completion_request = (char *)NULL;
+ last_completion_items = (REFERENCE **)NULL;
+}
+
+/* Build a list of possible completions from echo_area_completion_items,
+ and the contents of input_line. */
+static void
+build_completions ()
+{
+ register int i, len;
+ register REFERENCE *entry;
+ char *request;
+ int informed_of_lengthy_job = 0;
+
+ /* If there are no items to complete over, exit immediately. */
+ if (!echo_area_completion_items)
+ {
+ completions_found_index = 0;
+ LCD_completion = (REFERENCE *)NULL;
+ return;
+ }
+
+ /* Check to see if this call to build completions is the same as the last
+ call to build completions. */
+ len = input_line_end - input_line_beg;
+ request = (char *)xmalloc (1 + len);
+ strncpy (request, &input_line[input_line_beg], len);
+ request[len] = '\0';
+
+ if (last_completion_request && last_completion_items &&
+ last_completion_items == echo_area_completion_items &&
+ (strcmp (last_completion_request, request) == 0))
+ {
+ free (request);
+ return;
+ }
+
+ maybe_free (last_completion_request);
+ last_completion_request = request;
+ last_completion_items = echo_area_completion_items;
+
+ /* Always start at the beginning of the list. */
+ completions_found_index = 0;
+ LCD_completion = (REFERENCE *)NULL;
+
+ for (i = 0; entry = echo_area_completion_items[i]; i++)
+ {
+ if (strnicmp (request, entry->label, len) == 0)
+ add_pointer_to_array (entry, completions_found_index,
+ completions_found, completions_found_slots,
+ 20, REFERENCE *);
+
+ if (!informed_of_lengthy_job && completions_found_index > 100)
+ {
+ informed_of_lengthy_job = 1;
+ window_message_in_echo_area ("Building completions...");
+ }
+ }
+
+ if (!completions_found_index)
+ return;
+
+ /* Sort and prune duplicate entries from the completions array. */
+ remove_completion_duplicates ();
+
+ /* If there is only one completion, just return that. */
+ if (completions_found_index == 1)
+ {
+ LCD_completion = completions_found[0];
+ return;
+ }
+
+ /* Find the least common denominator. */
+ {
+ long shortest = 100000;
+
+ for (i = 1; i < completions_found_index; i++)
+ {
+ register int j;
+ int c1, c2;
+
+ for (j = 0;
+ (c1 = info_tolower (completions_found[i - 1]->label[j])) &&
+ (c2 = info_tolower (completions_found[i]->label[j]));
+ j++)
+ if (c1 != c2)
+ break;
+
+ if (shortest > j)
+ shortest = j;
+ }
+
+ maybe_free (LCD_reference.label);
+ LCD_reference.label = (char *)xmalloc (1 + shortest);
+ strncpy (LCD_reference.label, completions_found[0]->label, shortest);
+ LCD_reference.label[shortest] = '\0';
+ LCD_completion = &LCD_reference;
+ }
+
+ if (informed_of_lengthy_job)
+ echo_area_initialize_node ();
+}
+
+/* Function called by qsort. */
+static int
+compare_references (entry1, entry2)
+ REFERENCE **entry1, **entry2;
+{
+ return (stricmp ((*entry1)->label, (*entry2)->label));
+}
+
+/* Prune duplicate entries from COMPLETIONS_FOUND. */
+static void
+remove_completion_duplicates ()
+{
+ register int i, j;
+ REFERENCE **temp;
+ int newlen;
+
+ if (!completions_found_index)
+ return;
+
+ /* Sort the items. */
+ qsort (completions_found, completions_found_index, sizeof (REFERENCE *),
+ compare_references);
+
+ for (i = 0, newlen = 1; i < completions_found_index - 1; i++)
+ {
+ if (strcmp (completions_found[i]->label,
+ completions_found[i + 1]->label) == 0)
+ completions_found[i] = (REFERENCE *)NULL;
+ else
+ newlen++;
+ }
+
+ /* We have marked all the dead slots. It is faster to copy the live slots
+ twice than to prune the dead slots one by one. */
+ temp = (REFERENCE **)xmalloc ((1 + newlen) * sizeof (REFERENCE *));
+ for (i = 0, j = 0; i < completions_found_index; i++)
+ if (completions_found[i])
+ temp[j++] = completions_found[i];
+
+ for (i = 0; i < newlen; i++)
+ completions_found[i] = temp[i];
+
+ completions_found[i] = (REFERENCE *)NULL;
+ completions_found_index = newlen;
+ free (temp);
+}
+
+/* Scroll the "other" window. If there is a window showing completions, scroll
+ that one, otherwise scroll the window which was active on entering the read
+ function. */
+DECLARE_INFO_COMMAND (ea_scroll_completions_window, "Scroll the completions window")
+{
+ WINDOW *compwin;
+ int old_pagetop;
+
+ compwin = get_internal_info_window (compwin_name);
+
+ if (!compwin)
+ compwin = calling_window;
+
+ old_pagetop = compwin->pagetop;
+
+ /* Let info_scroll_forward () do the work, and print any messages that
+ need to be displayed. */
+ info_scroll_forward (compwin, count, key);
+}
+
+/* Function which gets called when an Info window is deleted while the
+ echo area is active. WINDOW is the window which has just been deleted. */
+void
+echo_area_inform_of_deleted_window (window)
+ WINDOW *window;
+{
+ /* If this is the calling_window, forget what we remembered about it. */
+ if (window == calling_window)
+ {
+ if (active_window != the_echo_area)
+ remember_calling_window (active_window);
+ else
+ remember_calling_window (windows);
+ }
+
+ /* If this window was the echo_area_completions_window, then notice that
+ the window has been deleted. */
+ if (window == echo_area_completions_window)
+ echo_area_completions_window = (WINDOW *)NULL;
+}
+
+/* **************************************************************** */
+/* */
+/* Pushing and Popping the Echo Area */
+/* */
+/* **************************************************************** */
+
+/* Push and Pop the echo area. */
+typedef struct {
+ char *line;
+ char *prompt;
+ REFERENCE **comp_items;
+ int point, beg, end;
+ int must_complete;
+ NODE node;
+ WINDOW *compwin;
+} PUSHED_EA;
+
+static PUSHED_EA **pushed_echo_areas = (PUSHED_EA **)NULL;
+static int pushed_echo_areas_index = 0;
+static int pushed_echo_areas_slots = 0;
+
+/* Pushing the echo_area has a side effect of zeroing the completion_items. */
+static void
+push_echo_area ()
+{
+ PUSHED_EA *pushed;
+
+ pushed = (PUSHED_EA *)xmalloc (sizeof (PUSHED_EA));
+ pushed->line = savestring (input_line);
+ pushed->prompt = input_line_prompt;
+ pushed->point = input_line_point;
+ pushed->beg = input_line_beg;
+ pushed->end = input_line_end;
+ pushed->node = input_line_node;
+ pushed->comp_items = echo_area_completion_items;
+ pushed->must_complete = echo_area_must_complete_p;
+ pushed->compwin = echo_area_completions_window;
+
+ add_pointer_to_array (pushed, pushed_echo_areas_index, pushed_echo_areas,
+ pushed_echo_areas_slots, 4, PUSHED_EA *);
+
+ echo_area_completion_items = (REFERENCE **)NULL;
+}
+
+static void
+pop_echo_area ()
+{
+ PUSHED_EA *popped;
+
+ popped = pushed_echo_areas[--pushed_echo_areas_index];
+
+ strcpy (input_line, popped->line);
+ free (popped->line);
+ input_line_prompt = popped->prompt;
+ input_line_point = popped->point;
+ input_line_beg = popped->beg;
+ input_line_end = popped->end;
+ input_line_node = popped->node;
+ echo_area_completion_items = popped->comp_items;
+ echo_area_must_complete_p = popped->must_complete;
+ echo_area_completions_window = popped->compwin;
+ completions_must_be_rebuilt ();
+
+ /* If the completion window no longer exists, forget about it. */
+ if (echo_area_completions_window)
+ {
+ register WINDOW *win;
+
+ for (win = windows; win; win = win->next)
+ if (echo_area_completions_window == win)
+ break;
+
+ /* If the window wasn't found, then it has already been deleted. */
+ if (!win)
+ echo_area_completions_window = (WINDOW *)NULL;
+ }
+
+ free (popped);
+}
+
+static int
+echo_area_stack_depth ()
+{
+ return (pushed_echo_areas_index);
+}
+
+/* Returns non-zero if any of the prior stacked calls to read in the echo
+ area produced a completions window. */
+static int
+echo_area_stack_contains_completions_p ()
+{
+ register int i;
+
+ for (i = 0; i < pushed_echo_areas_index; i++)
+ if (pushed_echo_areas[i]->compwin)
+ return (1);
+
+ return (0);
+}
+
+/* **************************************************************** */
+/* */
+/* Error Messages While Reading in Echo Area */
+/* */
+/* **************************************************************** */
+
+#if defined (HAVE_SYS_TIME_H)
+# include <sys/time.h>
+# define HAVE_STRUCT_TIMEVAL
+#endif /* HAVE_SYS_TIME_H */
+
+static void
+pause_or_input ()
+{
+#if defined (FD_SET)
+ struct timeval timer;
+ fd_set readfds;
+ int ready;
+
+ FD_ZERO (&readfds);
+ FD_SET (fileno (stdin), &readfds);
+ timer.tv_sec = 2;
+ timer.tv_usec = 750;
+ ready = select (1, &readfds, (fd_set *)NULL, (fd_set *)NULL, &timer);
+#endif /* FD_SET */
+}
+
+/* Print MESSAGE right after the end of the current line, and wait
+ for input or 2.75 seconds, whichever comes first. Then flush the
+ informational message that was printed. */
+void
+inform_in_echo_area (message)
+ char *message;
+{
+ register int i;
+ char *text;
+
+ text = savestring (message);
+ for (i = 0; text[i] && text[i] != '\n'; i++);
+ text[i] = '\0';
+
+ echo_area_initialize_node ();
+ sprintf (&input_line[input_line_end], "%s[%s]\n",
+ echo_area_is_active ? " ": "", text);
+ free (text);
+ the_echo_area->point = input_line_point;
+ display_update_one_window (the_echo_area);
+ display_cursor_at_point (active_window);
+ fflush (stdout);
+ pause_or_input ();
+ echo_area_initialize_node ();
+}
diff --git a/gnu/usr.bin/texinfo/info/echo_area.h b/gnu/usr.bin/texinfo/info/echo_area.h
new file mode 100644
index 0000000..3b06078
--- /dev/null
+++ b/gnu/usr.bin/texinfo/info/echo_area.h
@@ -0,0 +1,63 @@
+/* echo_area.h -- Functions used in reading information from the echo area. */
+
+/* This file is part of GNU Info, a program for reading online documentation
+ stored in Info format.
+
+ Copyright (C) 1993 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ Written by Brian Fox (bfox@ai.mit.edu). */
+
+#ifndef _ECHO_AREA_H_
+#define _ECHO_AREA_H_
+
+#define EA_MAX_INPUT 256
+
+extern int echo_area_is_active, info_aborted_echo_area;
+
+/* Non-zero means that the last command executed while reading input
+ killed some text. */
+extern int echo_area_last_command_was_kill;
+
+extern void inform_in_echo_area (), echo_area_inform_of_deleted_window ();
+extern void echo_area_prep_read ();
+extern VFunction *ea_last_executed_command;
+
+/* Read a line of text in the echo area. Return a malloc ()'ed string,
+ or NULL if the user aborted out of this read. WINDOW is the currently
+ active window, so that we can restore it when we need to. PROMPT, if
+ non-null, is a prompt to print before reading the line. */
+extern char *info_read_in_echo_area ();
+
+/* Read a line in the echo area with completion over COMPLETIONS.
+ Takes arguments of WINDOW, PROMPT, and COMPLETIONS, a REFERENCE **. */
+char *info_read_completing_in_echo_area ();
+
+/* Read a line in the echo area allowing completion over COMPLETIONS, but
+ not requiring it. Takes arguments of WINDOW, PROMPT, and COMPLETIONS,
+ a REFERENCE **. */
+extern char *info_read_maybe_completing ();
+
+extern void ea_insert (), ea_quoted_insert ();
+extern void ea_beg_of_line (), ea_backward (), ea_delete (), ea_end_of_line ();
+extern void ea_forward (), ea_abort (), ea_rubout (), ea_complete ();
+extern void ea_newline (), ea_kill_line (), ea_transpose_chars ();
+extern void ea_yank (), ea_tab_insert (), ea_possible_completions ();
+extern void ea_backward_word (), ea_kill_word (), ea_forward_word ();
+extern void ea_yank_pop (), ea_backward_kill_word ();
+extern void ea_scroll_completions_window ();
+
+#endif /* _ECHO_AREA_H_ */
diff --git a/gnu/usr.bin/texinfo/info/filesys.c b/gnu/usr.bin/texinfo/info/filesys.c
new file mode 100644
index 0000000..17004a4
--- /dev/null
+++ b/gnu/usr.bin/texinfo/info/filesys.c
@@ -0,0 +1,625 @@
+/* filesys.c -- File system specific functions for hacking this system. */
+
+/* This file is part of GNU Info, a program for reading online documentation
+ stored in Info format.
+
+ Copyright (C) 1993 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ Written by Brian Fox (bfox@ai.mit.edu). */
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/file.h>
+#include <sys/errno.h>
+#include "general.h"
+#include "tilde.h"
+#include "filesys.h"
+
+#if !defined (O_RDONLY)
+#if defined (HAVE_SYS_FCNTL_H)
+#include <sys/fcntl.h>
+#else /* !HAVE_SYS_FCNTL_H */
+#include <fcntl.h>
+#endif /* !HAVE_SYS_FCNTL_H */
+#endif /* !O_RDONLY */
+
+#if !defined (errno)
+extern int errno;
+#endif /* !errno */
+
+/* Found in info-utils.c. */
+extern char *filename_non_directory ();
+
+#if !defined (BUILDING_LIBRARY)
+/* Found in session.c */
+extern int info_windows_initialized_p;
+
+/* Found in window.c. */
+extern void message_in_echo_area (), unmessage_in_echo_area ();
+#endif /* !BUILDING_LIBRARY */
+
+/* Local to this file. */
+static char *info_file_in_path (), *lookup_info_filename ();
+static void remember_info_filename (), maybe_initialize_infopath ();
+
+#if !defined (NULL)
+# define NULL 0x0
+#endif /* !NULL */
+
+typedef struct {
+ char *suffix;
+ char *decompressor;
+} COMPRESSION_ALIST;
+
+static char *info_suffixes[] = {
+ "",
+ ".info",
+ "-info",
+ (char *)NULL
+};
+
+static COMPRESSION_ALIST compress_suffixes[] = {
+ { ".Z", "uncompress" },
+ { ".Y", "unyabba" },
+ { ".gz", "gunzip" },
+ { ".z", "gunzip" },
+ { (char *)NULL, (char *)NULL }
+};
+
+/* The path on which we look for info files. You can initialize this
+ from the environment variable INFOPATH if there is one, or you can
+ call info_add_path () to add paths to the beginning or end of it.
+ You can call zap_infopath () to make the path go away. */
+char *infopath = (char *)NULL;
+static int infopath_size = 0;
+
+/* Expand the filename in PARTIAL to make a real name for this operating
+ system. This looks in INFO_PATHS in order to find the correct file.
+ If it can't find the file, it returns NULL. */
+static char *local_temp_filename = (char *)NULL;
+static int local_temp_filename_size = 0;
+
+char *
+info_find_fullpath (partial)
+ char *partial;
+{
+ int initial_character;
+ char *temp;
+
+ filesys_error_number = 0;
+
+ maybe_initialize_infopath ();
+
+ if (partial && (initial_character = *partial))
+ {
+ char *expansion;
+
+ expansion = lookup_info_filename (partial);
+
+ if (expansion)
+ return (expansion);
+
+ /* If we have the full path to this file, we still may have to add
+ various extensions to it. I guess we have to stat this file
+ after all. */
+ if (initial_character == '/')
+ temp = info_file_in_path (partial + 1, "/");
+ else if (initial_character == '~')
+ {
+ expansion = tilde_expand_word (partial);
+ if (*expansion == '/')
+ {
+ temp = info_file_in_path (expansion + 1, "/");
+ free (expansion);
+ }
+ else
+ temp = expansion;
+ }
+ else if (initial_character == '.' &&
+ (partial[1] == '/' || (partial[1] == '.' && partial[2] == '/')))
+ {
+ if (local_temp_filename_size < 1024)
+ local_temp_filename = (char *)xrealloc
+ (local_temp_filename, (local_temp_filename_size = 1024));
+#if defined (HAVE_GETCWD)
+ if (!getcwd (local_temp_filename, local_temp_filename_size))
+#else /* !HAVE_GETCWD */
+ if (!getwd (local_temp_filename))
+#endif /* !HAVE_GETCWD */
+ {
+ filesys_error_number = errno;
+ return (partial);
+ }
+
+ strcat (local_temp_filename, "/");
+ strcat (local_temp_filename, partial);
+ return (local_temp_filename);
+ }
+ else
+ temp = info_file_in_path (partial, infopath);
+
+ if (temp)
+ {
+ remember_info_filename (partial, temp);
+ if (strlen (temp) > local_temp_filename_size)
+ local_temp_filename = (char *) xrealloc
+ (local_temp_filename,
+ (local_temp_filename_size = (50 + strlen (temp))));
+ strcpy (local_temp_filename, temp);
+ free (temp);
+ return (local_temp_filename);
+ }
+ }
+ return (partial);
+}
+
+/* Scan the list of directories in PATH looking for FILENAME. If we find
+ one that is a regular file, return it as a new string. Otherwise, return
+ a NULL pointer. */
+static char *
+info_file_in_path (filename, path)
+ char *filename, *path;
+{
+ struct stat finfo;
+ char *temp_dirname;
+ int statable, dirname_index;
+
+ dirname_index = 0;
+
+ while (temp_dirname = extract_colon_unit (path, &dirname_index))
+ {
+ register int i, pre_suffix_length;
+ char *temp;
+
+ /* Expand a leading tilde if one is present. */
+ if (*temp_dirname == '~')
+ {
+ char *expanded_dirname;
+
+ expanded_dirname = tilde_expand_word (temp_dirname);
+ free (temp_dirname);
+ temp_dirname = expanded_dirname;
+ }
+
+ temp = (char *)xmalloc (30 + strlen (temp_dirname) + strlen (filename));
+ strcpy (temp, temp_dirname);
+ if (temp[(strlen (temp)) - 1] != '/')
+ strcat (temp, "/");
+ strcat (temp, filename);
+
+ pre_suffix_length = strlen (temp);
+
+ free (temp_dirname);
+
+ for (i = 0; info_suffixes[i]; i++)
+ {
+ strcpy (temp + pre_suffix_length, info_suffixes[i]);
+
+ statable = (stat (temp, &finfo) == 0);
+
+ /* If we have found a regular file, then use that. Else, if we
+ have found a directory, look in that directory for this file. */
+ if (statable)
+ {
+ if (S_ISREG (finfo.st_mode))
+ {
+ return (temp);
+ }
+ else if (S_ISDIR (finfo.st_mode))
+ {
+ char *newpath, *filename_only, *newtemp;
+
+ newpath = savestring (temp);
+ filename_only = filename_non_directory (filename);
+ newtemp = info_file_in_path (filename_only, newpath);
+
+ free (newpath);
+ if (newtemp)
+ {
+ free (temp);
+ return (newtemp);
+ }
+ }
+ }
+ else
+ {
+ /* Add various compression suffixes to the name to see if
+ the file is present in compressed format. */
+ register int j, pre_compress_suffix_length;
+
+ pre_compress_suffix_length = strlen (temp);
+
+ for (j = 0; compress_suffixes[j].suffix; j++)
+ {
+ strcpy (temp + pre_compress_suffix_length,
+ compress_suffixes[j].suffix);
+
+ statable = (stat (temp, &finfo) == 0);
+ if (statable && (S_ISREG (finfo.st_mode)))
+ return (temp);
+ }
+ }
+ }
+ free (temp);
+ }
+ return ((char *)NULL);
+}
+
+/* Given a string containing units of information separated by colons,
+ return the next one pointed to by IDX, or NULL if there are no more.
+ Advance IDX to the character after the colon. */
+char *
+extract_colon_unit (string, idx)
+ char *string;
+ int *idx;
+{
+ register int i, start;
+
+ i = start = *idx;
+ if ((i >= strlen (string)) || !string)
+ return ((char *) NULL);
+
+ while (string[i] && string[i] != ':')
+ i++;
+ if (i == start)
+ {
+ return ((char *) NULL);
+ }
+ else
+ {
+ char *value = (char *) xmalloc (1 + (i - start));
+ strncpy (value, &string[start], (i - start));
+ value[i - start] = '\0';
+ if (string[i])
+ ++i;
+ *idx = i;
+ return (value);
+ }
+}
+
+/* A structure which associates a filename with its expansion. */
+typedef struct {
+ char *filename;
+ char *expansion;
+} FILENAME_LIST;
+
+/* An array of remembered arguments and results. */
+static FILENAME_LIST **names_and_files = (FILENAME_LIST **)NULL;
+static int names_and_files_index = 0;
+static int names_and_files_slots = 0;
+
+/* Find the result for having already called info_find_fullpath () with
+ FILENAME. */
+static char *
+lookup_info_filename (filename)
+ char *filename;
+{
+ if (filename && names_and_files)
+ {
+ register int i;
+ for (i = 0; names_and_files[i]; i++)
+ {
+ if (strcmp (names_and_files[i]->filename, filename) == 0)
+ return (names_and_files[i]->expansion);
+ }
+ }
+ return (char *)NULL;;
+}
+
+/* Add a filename and its expansion to our list. */
+static void
+remember_info_filename (filename, expansion)
+ char *filename, *expansion;
+{
+ FILENAME_LIST *new;
+
+ if (names_and_files_index + 2 > names_and_files_slots)
+ {
+ int alloc_size;
+ names_and_files_slots += 10;
+
+ alloc_size = names_and_files_slots * sizeof (FILENAME_LIST *);
+
+ names_and_files =
+ (FILENAME_LIST **) xrealloc (names_and_files, alloc_size);
+ }
+
+ new = (FILENAME_LIST *)xmalloc (sizeof (FILENAME_LIST));
+ new->filename = savestring (filename);
+ new->expansion = expansion ? savestring (expansion) : (char *)NULL;
+
+ names_and_files[names_and_files_index++] = new;
+ names_and_files[names_and_files_index] = (FILENAME_LIST *)NULL;
+}
+
+static void
+maybe_initialize_infopath ()
+{
+ if (!infopath_size)
+ {
+ infopath = (char *)
+ xmalloc (infopath_size = (1 + strlen (DEFAULT_INFOPATH)));
+
+ strcpy (infopath, DEFAULT_INFOPATH);
+ }
+}
+
+/* Add PATH to the list of paths found in INFOPATH. 2nd argument says
+ whether to put PATH at the front or end of INFOPATH. */
+void
+info_add_path (path, where)
+ char *path;
+ int where;
+{
+ int len;
+
+ if (!infopath)
+ {
+ infopath = (char *)xmalloc (infopath_size = 200 + strlen (path));
+ infopath[0] = '\0';
+ }
+
+ len = strlen (path) + strlen (infopath);
+
+ if (len + 2 >= infopath_size)
+ infopath = (char *)xrealloc (infopath, (infopath_size += (2 * len) + 2));
+
+ if (!*infopath)
+ strcpy (infopath, path);
+ else if (where == INFOPATH_APPEND)
+ {
+ strcat (infopath, ":");
+ strcat (infopath, path);
+ }
+ else if (where == INFOPATH_PREPEND)
+ {
+ char *temp = savestring (infopath);
+ strcpy (infopath, path);
+ strcat (infopath, ":");
+ strcat (infopath, temp);
+ free (temp);
+ }
+}
+
+/* Make INFOPATH have absolutely nothing in it. */
+void
+zap_infopath ()
+{
+ if (infopath)
+ free (infopath);
+
+ infopath = (char *)NULL;
+ infopath_size = 0;
+}
+
+/* Read the contents of PATHNAME, returning a buffer with the contents of
+ that file in it, and returning the size of that buffer in FILESIZE.
+ FINFO is a stat struct which has already been filled in by the caller.
+ If the file cannot be read, return a NULL pointer. */
+char *
+filesys_read_info_file (pathname, filesize, finfo)
+ char *pathname;
+ long *filesize;
+ struct stat *finfo;
+{
+ *filesize = filesys_error_number = 0;
+
+ if (compressed_filename_p (pathname))
+ return (filesys_read_compressed (pathname, filesize, finfo));
+ else
+ {
+ int descriptor;
+ char *contents;
+
+ descriptor = open (pathname, O_RDONLY, 0666);
+
+ /* If the file couldn't be opened, give up. */
+ if (descriptor < 0)
+ {
+ filesys_error_number = errno;
+ return ((char *)NULL);
+ }
+
+ /* Try to read the contents of this file. */
+ contents = (char *)xmalloc (1 + finfo->st_size);
+ if ((read (descriptor, contents, finfo->st_size)) != finfo->st_size)
+ {
+ filesys_error_number = errno;
+ close (descriptor);
+ free (contents);
+ return ((char *)NULL);
+ }
+
+ close (descriptor);
+
+ *filesize = finfo->st_size;
+ return (contents);
+ }
+}
+
+/* Typically, pipe buffers are 4k. */
+#define BASIC_PIPE_BUFFER (4 * 1024)
+
+/* We use some large multiple of that. */
+#define FILESYS_PIPE_BUFFER_SIZE (16 * BASIC_PIPE_BUFFER)
+
+char *
+filesys_read_compressed (pathname, filesize, finfo)
+ char *pathname;
+ long *filesize;
+ struct stat *finfo;
+{
+ FILE *stream;
+ char *command, *decompressor;
+ char *contents = (char *)NULL;
+
+ *filesize = filesys_error_number = 0;
+
+ decompressor = filesys_decompressor_for_file (pathname);
+
+ if (!decompressor)
+ return ((char *)NULL);
+
+ command = (char *)xmalloc (10 + strlen (pathname) + strlen (decompressor));
+ sprintf (command, "%s < %s", decompressor, pathname);
+
+#if !defined (BUILDING_LIBRARY)
+ if (info_windows_initialized_p)
+ {
+ char *temp;
+
+ temp = (char *)xmalloc (5 + strlen (command));
+ sprintf (temp, "%s...", command);
+ message_in_echo_area ("%s", temp);
+ free (temp);
+ }
+#endif /* !BUILDING_LIBRARY */
+
+ stream = popen (command, "r");
+ free (command);
+
+ /* Read chunks from this file until there are none left to read. */
+ if (stream)
+ {
+ int offset, size;
+ char *chunk;
+
+ offset = size = 0;
+ chunk = (char *)xmalloc (FILESYS_PIPE_BUFFER_SIZE);
+
+ while (1)
+ {
+ int bytes_read;
+
+ bytes_read = fread (chunk, 1, FILESYS_PIPE_BUFFER_SIZE, stream);
+
+ if (bytes_read + offset >= size)
+ contents = (char *)xrealloc
+ (contents, size += (2 * FILESYS_PIPE_BUFFER_SIZE));
+
+ memcpy (contents + offset, chunk, bytes_read);
+ offset += bytes_read;
+ if (bytes_read != FILESYS_PIPE_BUFFER_SIZE)
+ break;
+ }
+
+ free (chunk);
+ pclose (stream);
+ contents = (char *)xrealloc (contents, offset + 1);
+ *filesize = offset;
+ }
+ else
+ {
+ filesys_error_number = errno;
+ }
+
+#if !defined (BUILDING_LIBARARY)
+ if (info_windows_initialized_p)
+ unmessage_in_echo_area ();
+#endif /* !BUILDING_LIBRARY */
+ return (contents);
+}
+
+/* Return non-zero if FILENAME belongs to a compressed file. */
+int
+compressed_filename_p (filename)
+ char *filename;
+{
+ char *decompressor;
+
+ /* Find the final extension of this filename, and see if it matches one
+ of our known ones. */
+ decompressor = filesys_decompressor_for_file (filename);
+
+ if (decompressor)
+ return (1);
+ else
+ return (0);
+}
+
+/* Return the command string that would be used to decompress FILENAME. */
+char *
+filesys_decompressor_for_file (filename)
+ char *filename;
+{
+ register int i;
+ char *extension = (char *)NULL;
+
+ /* Find the final extension of FILENAME, and see if it appears in our
+ list of known compression extensions. */
+ for (i = strlen (filename) - 1; i > 0; i--)
+ if (filename[i] == '.')
+ {
+ extension = filename + i;
+ break;
+ }
+
+ if (!extension)
+ return ((char *)NULL);
+
+ for (i = 0; compress_suffixes[i].suffix; i++)
+ if (strcmp (extension, compress_suffixes[i].suffix) == 0)
+ return (compress_suffixes[i].decompressor);
+
+ return ((char *)NULL);
+}
+
+/* The number of the most recent file system error. */
+int filesys_error_number = 0;
+
+#if !defined (HAVE_STRERROR)
+extern const char * const sys_errlist[];
+extern int sys_nerr;
+
+char *
+strerror (num)
+ int num;
+{
+ if (num >= sys_nerr)
+ return ("");
+ else
+ return (sys_errlist[num]);
+}
+#endif /* !HAVE_STRERROR */
+
+/* A function which returns a pointer to a static buffer containing
+ an error message for FILENAME and ERROR_NUM. */
+static char *errmsg_buf = (char *)NULL;
+static int errmsg_buf_size = 0;
+
+char *
+filesys_error_string (filename, error_num)
+ char *filename;
+ int error_num;
+{
+ int len;
+ char *result;
+
+ if (error_num == 0)
+ return ((char *)NULL);
+
+ result = strerror (error_num);
+
+ len = 4 + strlen (filename) + strlen (result);
+ if (len >= errmsg_buf_size)
+ errmsg_buf = (char *)xrealloc (errmsg_buf, (errmsg_buf_size = 2 + len));
+
+ sprintf (errmsg_buf, "%s: %s", filename, result);
+ return (errmsg_buf);
+}
+
diff --git a/gnu/usr.bin/texinfo/info/filesys.h b/gnu/usr.bin/texinfo/info/filesys.h
new file mode 100644
index 0000000..9ee4a71
--- /dev/null
+++ b/gnu/usr.bin/texinfo/info/filesys.h
@@ -0,0 +1,84 @@
+/* filesys.h -- External declarations of functions and vars in filesys.c. */
+
+/* This file is part of GNU Info, a program for reading online documentation
+ stored in Info format.
+
+ Copyright (C) 1993 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ Written by Brian Fox (bfox@ai.mit.edu). */
+
+#ifndef _FILESYS_H_
+#define _FILESYS_H_
+
+/* The path on which we look for info files. You can initialize this
+ from the environment variable INFOPATH if there is one, or you can
+ call info_add_path () to add paths to the beginning or end of it. */
+extern char *infopath;
+
+/* Make INFOPATH have absolutely nothing in it. */
+extern void zap_infopath ();
+
+/* Add PATH to the list of paths found in INFOPATH. 2nd argument says
+ whether to put PATH at the front or end of INFOPATH. */
+extern void info_add_path ();
+
+/* Defines that are passed along with the pathname to info_add_path (). */
+#define INFOPATH_PREPEND 0
+#define INFOPATH_APPEND 1
+
+/* Expand the filename in PARTIAL to make a real name for this operating
+ system. This looks in INFO_PATHS in order to find the correct file.
+ If it can't find the file, it returns NULL. */
+extern char *info_find_fullpath ();
+
+/* Read the contents of PATHNAME, returning a buffer with the contents of
+ that file in it, and returning the size of that buffer in FILESIZE.
+ FINFO is a stat struct which has already been filled in by the caller.
+ If the file cannot be read, return a NULL pointer. */
+extern char *filesys_read_info_file ();
+extern char *filesys_read_compressed ();
+
+/* Return the command string that would be used to decompress FILENAME. */
+extern char *filesys_decompressor_for_file ();
+extern int compressed_filename_p ();
+
+/* A function which returns a pointer to a static buffer containing
+ an error message for FILENAME and ERROR_NUM. */
+extern char *filesys_error_string ();
+
+/* The number of the most recent file system error. */
+extern int filesys_error_number;
+
+/* Given a string containing units of information separated by colons,
+ return the next one pointed to by IDX, or NULL if there are no more.
+ Advance IDX to the character after the colon. */
+extern char *extract_colon_unit ();
+
+/* The default value of INFOPATH. */
+#if !defined (DEFAULT_INFOPATH)
+# define DEFAULT_INFOPATH "/usr/gnu/info:/local/gnu/info:/usr/gnu/lib/info:/usr/gnu/lib/emacs/info:/usr/local/gnu/info:/usr/local/gnu/lib/info:/usr/local/gnu/lib/emacs/info:/usr/local/lib/info:/usr/local/lib/emacs/info:/usr/local/emacs/info:."
+#endif /* !DEFAULT_INFOPATH */
+
+#if !defined (S_ISREG) && defined (S_IFREG)
+# define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
+#endif /* !S_ISREG && S_IFREG */
+
+#if !defined (S_ISDIR) && defined (S_IFDIR)
+# define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
+#endif /* !S_ISDIR && S_IFDIR */
+
+#endif /* !_FILESYS_H_ */
diff --git a/gnu/usr.bin/texinfo/info/footnotes.c b/gnu/usr.bin/texinfo/info/footnotes.c
new file mode 100644
index 0000000..9fd0f95
--- /dev/null
+++ b/gnu/usr.bin/texinfo/info/footnotes.c
@@ -0,0 +1,264 @@
+/* footnotes.c -- Some functions for manipulating footnotes. */
+
+/* This file is part of GNU Info, a program for reading online documentation
+ stored in Info format.
+
+ Copyright (C) 1993 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ Written by Brian Fox (bfox@ai.mit.edu). */
+
+#include "info.h"
+
+/* Non-zero means attempt to show footnotes when displaying a new window. */
+int auto_footnotes_p = 1;
+
+static char *footnote_nodename = "*Footnotes*";
+
+#define FOOTNOTE_HEADER_FORMAT \
+ "*** Footnotes appearing in the node \"%s\" ***\n"
+
+/* Find the window currently showing footnotes. */
+static WINDOW *
+find_footnotes_window ()
+{
+ WINDOW *win;
+
+ /* Try to find an existing window first. */
+ for (win = windows; win; win = win->next)
+ if (internal_info_node_p (win->node) &&
+ (strcmp (win->node->nodename, footnote_nodename) == 0))
+ break;
+
+ return (win);
+}
+
+/* Manufacture a node containing the footnotes of this node, and
+ return the manufactured node. If NODE has no footnotes, return a
+ NULL pointer. */
+NODE *
+make_footnotes_node (node)
+ NODE *node;
+{
+ NODE *fn_node, *result = (NODE *)NULL;
+ long fn_start;
+
+ /* Make the initial assumption that the footnotes appear as simple
+ text within this windows node. */
+ fn_node = node;
+
+ /* See if this node contains the magic footnote label. */
+ fn_start =
+ info_search_in_node (FOOTNOTE_LABEL, node, 0, (WINDOW *)NULL, 1);
+
+ /* If it doesn't, check to see if it has an associated footnotes node. */
+ if (fn_start == -1)
+ {
+ REFERENCE **refs;
+
+ refs = info_xrefs_of_node (node);
+
+ if (refs)
+ {
+ register int i;
+ char *refname;
+
+ refname = (char *)xmalloc
+ (1 + strlen ("-Footnotes") + strlen (node->nodename));
+
+ strcpy (refname, node->nodename);
+ strcat (refname, "-Footnotes");
+
+ for (i = 0; refs[i]; i++)
+ if (strcmp (refs[i]->nodename, refname) == 0)
+ {
+ char *filename;
+
+ filename = node->parent;
+ if (!filename)
+ filename = node->filename;
+
+ fn_node = info_get_node (filename, refname);
+
+ if (fn_node)
+ fn_start = 0;
+
+ break;
+ }
+
+ free (refname);
+ info_free_references (refs);
+ }
+ }
+
+ /* If we never found the start of a footnotes area, quit now. */
+ if (fn_start == -1)
+ return ((NODE *)NULL);
+
+ /* Make the new node. */
+ result = (NODE *)xmalloc (sizeof (NODE));
+ result->flags = 0;
+
+ /* Get the size of the footnotes appearing within this node. */
+ {
+ char *header;
+ long text_start = fn_start;
+
+ header = (char *)xmalloc
+ (1 + strlen (node->nodename) + strlen (FOOTNOTE_HEADER_FORMAT));
+ sprintf (header, FOOTNOTE_HEADER_FORMAT, node->nodename);
+
+ /* Move the start of the displayed text to right after the first line.
+ This effectively skips either "---- footno...", or "File: foo...". */
+ while (text_start < fn_node->nodelen)
+ if (fn_node->contents[text_start++] == '\n')
+ break;
+
+ result->nodelen = strlen (header) + fn_node->nodelen - text_start;
+
+ /* Set the contents of this node. */
+ result->contents = (char *)xmalloc (1 + result->nodelen);
+ sprintf (result->contents, "%s", header);
+ memcpy (result->contents + strlen (header),
+ fn_node->contents + text_start, fn_node->nodelen - text_start);
+
+ name_internal_node (result, footnote_nodename);
+ free (header);
+ }
+
+#if defined (NOTDEF)
+ /* If the footnotes were gleaned from the node that we were called with,
+ shorten the calling node's display length. */
+ if (fn_node == node)
+ narrow_node (node, 0, fn_start);
+#endif /* NOTDEF */
+
+ return (result);
+}
+
+/* Create or delete the footnotes window depending on whether footnotes
+ exist in WINDOW's node or not. Returns FN_FOUND if footnotes were found
+ and displayed. Returns FN_UNFOUND if there were no footnotes found
+ in WINDOW's node. Returns FN_UNABLE if there were footnotes, but the
+ window to show them couldn't be made. */
+int
+info_get_or_remove_footnotes (window)
+ WINDOW *window;
+{
+ WINDOW *fn_win;
+ NODE *new_footnotes;
+
+ fn_win = find_footnotes_window ();
+
+ /* If we are in the footnotes window, change nothing. */
+ if (fn_win == window)
+ return (FN_FOUND);
+
+ /* Try to find footnotes for this window's node. */
+ new_footnotes = make_footnotes_node (window->node);
+
+ /* If there was a window showing footnotes, and there are no footnotes
+ for the current window, delete the old footnote window. */
+ if (fn_win && !new_footnotes)
+ {
+ if (windows->next)
+ info_delete_window_internal (fn_win);
+ }
+
+ /* If there are footnotes for this window's node, but no window around
+ showing footnotes, try to make a new window. */
+ if (new_footnotes && !fn_win)
+ {
+ WINDOW *old_active;
+ WINDOW *last, *win;
+
+ /* Always make this window be the last one appearing in the list. Find
+ the last window in the chain. */
+ for (win = windows, last = windows; win; last = win, win = win->next);
+
+ /* Try to split this window, and make the split window the one to
+ contain the footnotes. */
+ old_active = active_window;
+ active_window = last;
+ fn_win = window_make_window (new_footnotes);
+ active_window = old_active;
+
+ if (!fn_win)
+ {
+ free (new_footnotes->contents);
+ free (new_footnotes);
+
+ /* If we are hacking automatic footnotes, and there are footnotes
+ but we couldn't display them, print a message to that effect. */
+ if (auto_footnotes_p)
+ inform_in_echo_area ("Footnotes could not be displayed");
+ return (FN_UNABLE);
+ }
+ }
+
+ /* If there are footnotes, and there is a window to display them,
+ make that window be the number of lines appearing in the footnotes. */
+ if (new_footnotes && fn_win)
+ {
+ window_set_node_of_window (fn_win, new_footnotes);
+
+ window_change_window_height
+ (fn_win, fn_win->line_count - fn_win->height);
+
+ remember_window_and_node (fn_win, new_footnotes);
+ add_gcable_pointer (new_footnotes->contents);
+ }
+
+ if (!new_footnotes)
+ return (FN_UNFOUND);
+ else
+ return (FN_FOUND);
+}
+
+/* Show the footnotes associated with this node in another window. */
+DECLARE_INFO_COMMAND (info_show_footnotes,
+ "Show the footnotes associated with this node in another window")
+{
+ int result;
+
+ /* A negative argument means just make the window go away. */
+ if (count < 0)
+ {
+ WINDOW *fn_win = find_footnotes_window ();
+
+ /* If there is an old footnotes window, and it isn't the only window
+ on the screen, delete it. */
+ if (fn_win && windows->next)
+ info_delete_window_internal (fn_win);
+ }
+ else
+ {
+ int result;
+
+ result = info_get_or_remove_footnotes (window);
+
+ switch (result)
+ {
+ case FN_UNFOUND:
+ info_error (NO_FOOT_NODE);
+ break;
+
+ case FN_UNABLE:
+ info_error (WIN_TOO_SMALL);
+ break;
+ }
+ }
+}
diff --git a/gnu/usr.bin/texinfo/info/footnotes.h b/gnu/usr.bin/texinfo/info/footnotes.h
new file mode 100644
index 0000000..71c9d93
--- /dev/null
+++ b/gnu/usr.bin/texinfo/info/footnotes.h
@@ -0,0 +1,46 @@
+/* footnotes.h -- Some functions for manipulating footnotes. */
+
+/* This file is part of GNU Info, a program for reading online documentation
+ stored in Info format.
+
+ Copyright (C) 1993 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ Written by Brian Fox (bfox@ai.mit.edu). */
+
+#ifndef _FOOTNOTES_H_
+#define _FOOTNOTES_H_
+
+/* Magic string which indicates following text is footnotes. */
+#define FOOTNOTE_LABEL "---------- Footnotes ----------"
+
+#define FN_FOUND 0
+#define FN_UNFOUND 1
+#define FN_UNABLE 2
+
+
+/* Create or delete the footnotes window depending on whether footnotes
+ exist in WINDOW's node or not. Returns FN_FOUND if footnotes were found
+ and displayed. Returns FN_UNFOUND if there were no footnotes found
+ in WINDOW's node. Returns FN_UNABLE if there were footnotes, but the
+ window to show them couldn't be made. */
+extern int info_get_or_remove_footnotes ();
+
+/* Non-zero means attempt to show footnotes when displaying a new window. */
+extern int auto_footnotes_p;
+
+#endif /* !_FOOTNOTES_H_ */
+
diff --git a/gnu/usr.bin/texinfo/info/funs.h b/gnu/usr.bin/texinfo/info/funs.h
new file mode 100644
index 0000000..1474f0d
--- /dev/null
+++ b/gnu/usr.bin/texinfo/info/funs.h
@@ -0,0 +1,110 @@
+/* funs.h -- Generated declarations for Info commands. */
+
+/* Functions declared in "./session.c". */
+extern void info_next_line ();
+extern void info_prev_line ();
+extern void info_end_of_line ();
+extern void info_beginning_of_line ();
+extern void info_forward_char ();
+extern void info_backward_char ();
+extern void info_forward_word ();
+extern void info_backward_word ();
+extern void info_global_next_node ();
+extern void info_global_prev_node ();
+extern void info_scroll_forward ();
+extern void info_scroll_backward ();
+extern void info_beginning_of_node ();
+extern void info_end_of_node ();
+extern void info_next_window ();
+extern void info_prev_window ();
+extern void info_split_window ();
+extern void info_delete_window ();
+extern void info_keep_one_window ();
+extern void info_scroll_other_window ();
+extern void info_grow_window ();
+extern void info_tile_windows ();
+extern void info_toggle_wrap ();
+extern void info_next_node ();
+extern void info_prev_node ();
+extern void info_up_node ();
+extern void info_last_node ();
+extern void info_first_node ();
+extern void info_history_node ();
+extern void info_last_menu_item ();
+extern void info_menu_digit ();
+extern void info_menu_item ();
+extern void info_xref_item ();
+extern void info_find_menu ();
+extern void info_visit_menu ();
+extern void info_goto_node ();
+extern void info_top_node ();
+extern void info_dir_node ();
+extern void info_kill_node ();
+extern void info_view_file ();
+extern void info_print_node ();
+extern void info_search ();
+extern void isearch_forward ();
+extern void isearch_backward ();
+extern void info_move_to_prev_xref ();
+extern void info_move_to_next_xref ();
+extern void info_select_reference_this_line ();
+extern void info_abort_key ();
+extern void info_move_to_window_line ();
+extern void info_redraw_display ();
+extern void info_quit ();
+extern void info_do_lowercase_version ();
+extern void info_add_digit_to_numeric_arg ();
+extern void info_universal_argument ();
+extern void info_numeric_arg_digit_loop ();
+
+/* Functions declared in "./echo_area.c". */
+extern void ea_forward ();
+extern void ea_backward ();
+extern void ea_beg_of_line ();
+extern void ea_end_of_line ();
+extern void ea_forward_word ();
+extern void ea_backward_word ();
+extern void ea_delete ();
+extern void ea_rubout ();
+extern void ea_abort ();
+extern void ea_newline ();
+extern void ea_quoted_insert ();
+extern void ea_insert ();
+extern void ea_tab_insert ();
+extern void ea_transpose_chars ();
+extern void ea_yank ();
+extern void ea_yank_pop ();
+extern void ea_kill_line ();
+extern void ea_backward_kill_line ();
+extern void ea_kill_word ();
+extern void ea_backward_kill_word ();
+extern void ea_possible_completions ();
+extern void ea_complete ();
+extern void ea_scroll_completions_window ();
+
+/* Functions declared in "./infodoc.c". */
+extern void info_get_help_window ();
+extern void info_get_info_help_node ();
+extern void describe_key ();
+extern void info_where_is ();
+
+/* Functions declared in "./m-x.c". */
+extern void describe_command ();
+extern void info_execute_command ();
+extern void set_screen_height ();
+
+/* Functions declared in "./indices.c". */
+extern void info_index_search ();
+extern void info_next_index_match ();
+extern void info_index_apropos ();
+
+/* Functions declared in "./nodemenu.c". */
+extern void list_visited_nodes ();
+extern void select_visited_node ();
+
+/* Functions declared in "./footnotes.c". */
+extern void info_show_footnotes ();
+
+/* Functions declared in "./variables.c". */
+extern void describe_variable ();
+extern void set_variable ();
diff --git a/gnu/usr.bin/texinfo/info/gc.c b/gnu/usr.bin/texinfo/info/gc.c
new file mode 100644
index 0000000..6a50e81
--- /dev/null
+++ b/gnu/usr.bin/texinfo/info/gc.c
@@ -0,0 +1,95 @@
+/* gc.c -- Functions to remember and garbage collect unused node contents. */
+
+/* This file is part of GNU Info, a program for reading online documentation
+ stored in Info format.
+
+ Copyright (C) 1993 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ Written by Brian Fox (bfox@ai.mit.edu). */
+
+#include "info.h"
+
+/* Array of pointers to the contents of gc-able nodes. A pointer on this
+ list can be garbage collected when no info window contains a node whose
+ contents member match the pointer. */
+static char **gcable_pointers = (char **)NULL;
+static int gcable_pointers_index = 0;
+static int gcable_pointers_slots = 0;
+
+/* Add POINTER to the list of garbage collectible pointers. A pointer
+ is not actually garbage collected until no info window contains a node
+ whose contents member is equal to the pointer. */
+void
+add_gcable_pointer (pointer)
+ char *pointer;
+{
+ gc_pointers ();
+ add_pointer_to_array (pointer, gcable_pointers_index, gcable_pointers,
+ gcable_pointers_slots, 10, char *);
+}
+
+/* Grovel the list of info windows and gc-able pointers finding those
+ node->contents which are collectible, and free them. */
+void
+gc_pointers ()
+{
+ register int i, j, k;
+ INFO_WINDOW *iw;
+ char **new = (char **)NULL;
+ int new_index = 0;
+ int new_slots = 0;
+
+ if (!info_windows || !gcable_pointers_index)
+ return;
+
+ for (i = 0; iw = info_windows[i]; i++)
+ {
+ for (j = 0; j < iw->nodes_index; j++)
+ {
+ NODE *node = iw->nodes[j];
+
+ /* If this node->contents appears in our list of gcable_pointers,
+ it is not gc-able, so save it. */
+ for (k = 0; k < gcable_pointers_index; k++)
+ if (gcable_pointers[k] == node->contents)
+ {
+ add_pointer_to_array
+ (node->contents, new_index, new, new_slots, 10, char *);
+ break;
+ }
+ }
+ }
+
+ /* We have gathered all of the pointers which need to be saved. Free any
+ of the original pointers which do not appear in the new list. */
+ for (i = 0; i < gcable_pointers_index; i++)
+ {
+ for (j = 0; j < new_index; j++)
+ if (gcable_pointers[i] == new[j])
+ break;
+
+ /* If we got all the way through the new list, then the old pointer
+ can be garbage collected. */
+ if (new && !new[j])
+ free (gcable_pointers[i]);
+ }
+
+ free (gcable_pointers);
+ gcable_pointers = new;
+ gcable_pointers_slots = new_slots;
+ gcable_pointers_index = new_index;
+}
diff --git a/gnu/usr.bin/texinfo/info/gc.h b/gnu/usr.bin/texinfo/info/gc.h
new file mode 100644
index 0000000..a521ae6
--- /dev/null
+++ b/gnu/usr.bin/texinfo/info/gc.h
@@ -0,0 +1,36 @@
+/* gc.h -- Functions for garbage collecting unused node contents. */
+
+/* This file is part of GNU Info, a program for reading online documentation
+ stored in Info format.
+
+ Copyright (C) 1993 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ Written by Brian Fox (bfox@ai.mit.edu). */
+
+#ifndef _GC_H_
+#define _GC_H_
+
+/* Add POINTER to the list of garbage collectible pointers. A pointer
+ is not actually garbage collected until no info window contains a node
+ whose contents member is equal to the pointer. */
+extern void add_gcable_pointer ();
+
+/* Grovel the list of info windows and gc-able pointers finding those
+ node->contents which are collectible, and free them. */
+extern void gc_pointers ();
+
+#endif /* !_GC_H_ */
diff --git a/gnu/usr.bin/texinfo/info/general.h b/gnu/usr.bin/texinfo/info/general.h
new file mode 100644
index 0000000..605a75a
--- /dev/null
+++ b/gnu/usr.bin/texinfo/info/general.h
@@ -0,0 +1,81 @@
+/* general.h -- Some generally useful defines. */
+
+/* This file is part of GNU Info, a program for reading online documentation
+ stored in Info format.
+
+ Copyright (C) 1993 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ Written by Brian Fox (bfox@ai.mit.edu). */
+
+#if !defined (_GENERAL_H_)
+#define _GENERAL_H_
+
+extern void *xmalloc (), *xrealloc ();
+
+#if defined (HAVE_UNISTD_H)
+# include <unistd.h>
+#endif /* HAVE_UNISTD_H */
+
+#if defined (HAVE_STRING_H)
+# include <string.h>
+#else
+# include <strings.h>
+#endif /* !HAVE_STRING_H */
+
+#if !defined (savestring)
+# define savestring(x) (char *)strcpy ((char *)xmalloc (1 + strlen (x)), x)
+#endif /* !savestring */
+
+#define info_toupper(x) (islower (x) ? toupper (x) : x)
+#define info_tolower(x) (isupper (x) ? tolower (x) : x)
+
+#if !defined (whitespace)
+# define whitespace(c) ((c == ' ') || (c == '\t'))
+#endif /* !whitespace */
+
+#if !defined (whitespace_or_newline)
+# define whitespace_or_newline(c) (whitespace (c) || (c == '\n'))
+#endif /* !whitespace_or_newline */
+
+#if !defined (__FUNCTION_DEF)
+# define __FUNCTION_DEF
+typedef int Function ();
+typedef void VFunction ();
+#endif /* _FUNCTION_DEF */
+
+/* Add POINTER to the list of pointers found in ARRAY. SLOTS is the number
+ of slots that have already been allocated. INDEX is the index into the
+ array where POINTER should be added. GROW is the number of slots to grow
+ ARRAY by, in the case that it needs growing. TYPE is a cast of the type
+ of object stored in ARRAY (e.g., NODE_ENTRY *. */
+#define add_pointer_to_array(pointer, idx, array, slots, grow, type) \
+ do { \
+ if (idx + 2 >= slots) \
+ array = (type *)(xrealloc (array, (slots += grow) * sizeof (type))); \
+ array[idx++] = (type)pointer; \
+ array[idx] = (type)NULL; \
+ } while (0)
+
+#define maybe_free(x) do { if (x) free (x); } while (0)
+
+#if !defined (HAVE_BZERO)
+# define zero_mem(mem, length) memset (mem, 0, length)
+#else
+# define zero_mem(mem, length) bzero (mem, length)
+#endif /* !BZERO_MISSING */
+
+#endif /* !_GENERAL_H_ */
diff --git a/gnu/usr.bin/texinfo/info/getopt.c b/gnu/usr.bin/texinfo/info/getopt.c
new file mode 100644
index 0000000..a59a013
--- /dev/null
+++ b/gnu/usr.bin/texinfo/info/getopt.c
@@ -0,0 +1,731 @@
+/* Getopt for GNU.
+ NOTE: getopt is now part of the C library, so if you don't know what
+ "Keep this file name-space clean" means, talk to roland@gnu.ai.mit.edu
+ before changing it!
+
+ Copyright (C) 1987, 88, 89, 90, 91, 92, 1993
+ Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any
+ later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* NOTE!!! AIX requires this to be the first thing in the file.
+ Do not put ANYTHING before it! */
+#if !defined (__GNUC__) && defined (_AIX)
+ #pragma alloca
+#endif
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef __GNUC__
+#define alloca __builtin_alloca
+#else /* not __GNUC__ */
+#if defined (HAVE_ALLOCA_H) || (defined(sparc) && (defined(sun) || (!defined(USG) && !defined(SVR4) && !defined(__svr4__))))
+#include <alloca.h>
+#else
+#ifndef _AIX
+char *alloca ();
+#endif
+#endif /* alloca.h */
+#endif /* not __GNUC__ */
+
+#if !__STDC__ && !defined(const) && IN_GCC
+#define const
+#endif
+
+/* This tells Alpha OSF/1 not to define a getopt prototype in <stdio.h>. */
+#ifndef _NO_PROTO
+#define _NO_PROTO
+#endif
+
+#include <stdio.h>
+
+/* Comment out all this code if we are using the GNU C Library, and are not
+ actually compiling the library itself. This code is part of the GNU C
+ Library, but also included in many other GNU distributions. Compiling
+ and linking in this code is a waste when using the GNU C library
+ (especially if it is a shared library). Rather than having every GNU
+ program understand `configure --with-gnu-libc' and omit the object files,
+ it is simpler to just do this in the source for each such file. */
+
+#if defined (_LIBC) || !defined (__GNU_LIBRARY__)
+
+
+/* This needs to come after some library #include
+ to get __GNU_LIBRARY__ defined. */
+#ifdef __GNU_LIBRARY__
+#undef alloca
+/* Don't include stdlib.h for non-GNU C libraries because some of them
+ contain conflicting prototypes for getopt. */
+#include <stdlib.h>
+#else /* Not GNU C library. */
+#define __alloca alloca
+#endif /* GNU C library. */
+
+/* If GETOPT_COMPAT is defined, `+' as well as `--' can introduce a
+ long-named option. Because this is not POSIX.2 compliant, it is
+ being phased out. */
+/* #define GETOPT_COMPAT */
+
+/* This version of `getopt' appears to the caller like standard Unix `getopt'
+ but it behaves differently for the user, since it allows the user
+ to intersperse the options with the other arguments.
+
+ As `getopt' works, it permutes the elements of ARGV so that,
+ when it is done, all the options precede everything else. Thus
+ all application programs are extended to handle flexible argument order.
+
+ Setting the environment variable POSIXLY_CORRECT disables permutation.
+ Then the behavior is completely standard.
+
+ GNU application programs can use a third alternative mode in which
+ they can distinguish the relative order of options and other arguments. */
+
+#include "getopt.h"
+
+/* For communication from `getopt' to the caller.
+ When `getopt' finds an option that takes an argument,
+ the argument value is returned here.
+ Also, when `ordering' is RETURN_IN_ORDER,
+ each non-option ARGV-element is returned here. */
+
+char *optarg = 0;
+
+/* Index in ARGV of the next element to be scanned.
+ This is used for communication to and from the caller
+ and for communication between successive calls to `getopt'.
+
+ On entry to `getopt', zero means this is the first call; initialize.
+
+ When `getopt' returns EOF, this is the index of the first of the
+ non-option elements that the caller should itself scan.
+
+ Otherwise, `optind' communicates from one call to the next
+ how much of ARGV has been scanned so far. */
+
+/* XXX 1003.2 says this must be 1 before any call. */
+int optind = 0;
+
+/* The next char to be scanned in the option-element
+ in which the last option character we returned was found.
+ This allows us to pick up the scan where we left off.
+
+ If this is zero, or a null string, it means resume the scan
+ by advancing to the next ARGV-element. */
+
+static char *nextchar;
+
+/* Callers store zero here to inhibit the error message
+ for unrecognized options. */
+
+int opterr = 1;
+
+/* Set to an option character which was unrecognized.
+ This must be initialized on some systems to avoid linking in the
+ system's own getopt implementation. */
+
+int optopt = '?';
+
+/* Describe how to deal with options that follow non-option ARGV-elements.
+
+ If the caller did not specify anything,
+ the default is REQUIRE_ORDER if the environment variable
+ POSIXLY_CORRECT is defined, PERMUTE otherwise.
+
+ REQUIRE_ORDER means don't recognize them as options;
+ stop option processing when the first non-option is seen.
+ This is what Unix does.
+ This mode of operation is selected by either setting the environment
+ variable POSIXLY_CORRECT, or using `+' as the first character
+ of the list of option characters.
+
+ PERMUTE is the default. We permute the contents of ARGV as we scan,
+ so that eventually all the non-options are at the end. This allows options
+ to be given in any order, even with programs that were not written to
+ expect this.
+
+ RETURN_IN_ORDER is an option available to programs that were written
+ to expect options and other ARGV-elements in any order and that care about
+ the ordering of the two. We describe each non-option ARGV-element
+ as if it were the argument of an option with character code 1.
+ Using `-' as the first character of the list of option characters
+ selects this mode of operation.
+
+ The special argument `--' forces an end of option-scanning regardless
+ of the value of `ordering'. In the case of RETURN_IN_ORDER, only
+ `--' can cause `getopt' to return EOF with `optind' != ARGC. */
+
+static enum
+{
+ REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER
+} ordering;
+
+#ifdef __GNU_LIBRARY__
+/* We want to avoid inclusion of string.h with non-GNU libraries
+ because there are many ways it can cause trouble.
+ On some systems, it contains special magic macros that don't work
+ in GCC. */
+#include <string.h>
+#define my_index strchr
+#define my_bcopy(src, dst, n) memcpy ((dst), (src), (n))
+#else
+
+/* Avoid depending on library functions or files
+ whose names are inconsistent. */
+
+char *getenv ();
+
+static char *
+my_index (str, chr)
+ const char *str;
+ int chr;
+{
+ while (*str)
+ {
+ if (*str == chr)
+ return (char *) str;
+ str++;
+ }
+ return 0;
+}
+
+static void
+my_bcopy (from, to, size)
+ const char *from;
+ char *to;
+ int size;
+{
+ int i;
+ for (i = 0; i < size; i++)
+ to[i] = from[i];
+}
+#endif /* GNU C library. */
+
+/* Handle permutation of arguments. */
+
+/* Describe the part of ARGV that contains non-options that have
+ been skipped. `first_nonopt' is the index in ARGV of the first of them;
+ `last_nonopt' is the index after the last of them. */
+
+static int first_nonopt;
+static int last_nonopt;
+
+/* Exchange two adjacent subsequences of ARGV.
+ One subsequence is elements [first_nonopt,last_nonopt)
+ which contains all the non-options that have been skipped so far.
+ The other is elements [last_nonopt,optind), which contains all
+ the options processed since those non-options were skipped.
+
+ `first_nonopt' and `last_nonopt' are relocated so that they describe
+ the new indices of the non-options in ARGV after they are moved. */
+
+static void
+exchange (argv)
+ char **argv;
+{
+ int nonopts_size = (last_nonopt - first_nonopt) * sizeof (char *);
+ char **temp = (char **) __alloca (nonopts_size);
+
+ /* Interchange the two blocks of data in ARGV. */
+
+ my_bcopy ((char *) &argv[first_nonopt], (char *) temp, nonopts_size);
+ my_bcopy ((char *) &argv[last_nonopt], (char *) &argv[first_nonopt],
+ (optind - last_nonopt) * sizeof (char *));
+ my_bcopy ((char *) temp,
+ (char *) &argv[first_nonopt + optind - last_nonopt],
+ nonopts_size);
+
+ /* Update records for the slots the non-options now occupy. */
+
+ first_nonopt += (optind - last_nonopt);
+ last_nonopt = optind;
+}
+
+/* Scan elements of ARGV (whose length is ARGC) for option characters
+ given in OPTSTRING.
+
+ If an element of ARGV starts with '-', and is not exactly "-" or "--",
+ then it is an option element. The characters of this element
+ (aside from the initial '-') are option characters. If `getopt'
+ is called repeatedly, it returns successively each of the option characters
+ from each of the option elements.
+
+ If `getopt' finds another option character, it returns that character,
+ updating `optind' and `nextchar' so that the next call to `getopt' can
+ resume the scan with the following option character or ARGV-element.
+
+ If there are no more option characters, `getopt' returns `EOF'.
+ Then `optind' is the index in ARGV of the first ARGV-element
+ that is not an option. (The ARGV-elements have been permuted
+ so that those that are not options now come last.)
+
+ OPTSTRING is a string containing the legitimate option characters.
+ If an option character is seen that is not listed in OPTSTRING,
+ return '?' after printing an error message. If you set `opterr' to
+ zero, the error message is suppressed but we still return '?'.
+
+ If a char in OPTSTRING is followed by a colon, that means it wants an arg,
+ so the following text in the same ARGV-element, or the text of the following
+ ARGV-element, is returned in `optarg'. Two colons mean an option that
+ wants an optional arg; if there is text in the current ARGV-element,
+ it is returned in `optarg', otherwise `optarg' is set to zero.
+
+ If OPTSTRING starts with `-' or `+', it requests different methods of
+ handling the non-option ARGV-elements.
+ See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above.
+
+ Long-named options begin with `--' instead of `-'.
+ Their names may be abbreviated as long as the abbreviation is unique
+ or is an exact match for some defined option. If they have an
+ argument, it follows the option name in the same ARGV-element, separated
+ from the option name by a `=', or else the in next ARGV-element.
+ When `getopt' finds a long-named option, it returns 0 if that option's
+ `flag' field is nonzero, the value of the option's `val' field
+ if the `flag' field is zero.
+
+ The elements of ARGV aren't really const, because we permute them.
+ But we pretend they're const in the prototype to be compatible
+ with other systems.
+
+ LONGOPTS is a vector of `struct option' terminated by an
+ element containing a name which is zero.
+
+ LONGIND returns the index in LONGOPT of the long-named option found.
+ It is only valid when a long-named option has been found by the most
+ recent call.
+
+ If LONG_ONLY is nonzero, '-' as well as '--' can introduce
+ long-named options. */
+
+int
+_getopt_internal (argc, argv, optstring, longopts, longind, long_only)
+ int argc;
+ char *const *argv;
+ const char *optstring;
+ const struct option *longopts;
+ int *longind;
+ int long_only;
+{
+ int option_index;
+
+ optarg = 0;
+
+ /* Initialize the internal data when the first call is made.
+ Start processing options with ARGV-element 1 (since ARGV-element 0
+ is the program name); the sequence of previously skipped
+ non-option ARGV-elements is empty. */
+
+ if (optind == 0)
+ {
+ first_nonopt = last_nonopt = optind = 1;
+
+ nextchar = NULL;
+
+ /* Determine how to handle the ordering of options and nonoptions. */
+
+ if (optstring[0] == '-')
+ {
+ ordering = RETURN_IN_ORDER;
+ ++optstring;
+ }
+ else if (optstring[0] == '+')
+ {
+ ordering = REQUIRE_ORDER;
+ ++optstring;
+ }
+ else if (getenv ("POSIXLY_CORRECT") != NULL)
+ ordering = REQUIRE_ORDER;
+ else
+ ordering = PERMUTE;
+ }
+
+ if (nextchar == NULL || *nextchar == '\0')
+ {
+ if (ordering == PERMUTE)
+ {
+ /* If we have just processed some options following some non-options,
+ exchange them so that the options come first. */
+
+ if (first_nonopt != last_nonopt && last_nonopt != optind)
+ exchange ((char **) argv);
+ else if (last_nonopt != optind)
+ first_nonopt = optind;
+
+ /* Now skip any additional non-options
+ and extend the range of non-options previously skipped. */
+
+ while (optind < argc
+ && (argv[optind][0] != '-' || argv[optind][1] == '\0')
+#ifdef GETOPT_COMPAT
+ && (longopts == NULL
+ || argv[optind][0] != '+' || argv[optind][1] == '\0')
+#endif /* GETOPT_COMPAT */
+ )
+ optind++;
+ last_nonopt = optind;
+ }
+
+ /* Special ARGV-element `--' means premature end of options.
+ Skip it like a null option,
+ then exchange with previous non-options as if it were an option,
+ then skip everything else like a non-option. */
+
+ if (optind != argc && !strcmp (argv[optind], "--"))
+ {
+ optind++;
+
+ if (first_nonopt != last_nonopt && last_nonopt != optind)
+ exchange ((char **) argv);
+ else if (first_nonopt == last_nonopt)
+ first_nonopt = optind;
+ last_nonopt = argc;
+
+ optind = argc;
+ }
+
+ /* If we have done all the ARGV-elements, stop the scan
+ and back over any non-options that we skipped and permuted. */
+
+ if (optind == argc)
+ {
+ /* Set the next-arg-index to point at the non-options
+ that we previously skipped, so the caller will digest them. */
+ if (first_nonopt != last_nonopt)
+ optind = first_nonopt;
+ return EOF;
+ }
+
+ /* If we have come to a non-option and did not permute it,
+ either stop the scan or describe it to the caller and pass it by. */
+
+ if ((argv[optind][0] != '-' || argv[optind][1] == '\0')
+#ifdef GETOPT_COMPAT
+ && (longopts == NULL
+ || argv[optind][0] != '+' || argv[optind][1] == '\0')
+#endif /* GETOPT_COMPAT */
+ )
+ {
+ if (ordering == REQUIRE_ORDER)
+ return EOF;
+ optarg = argv[optind++];
+ return 1;
+ }
+
+ /* We have found another option-ARGV-element.
+ Start decoding its characters. */
+
+ nextchar = (argv[optind] + 1
+ + (longopts != NULL && argv[optind][1] == '-'));
+ }
+
+ if (longopts != NULL
+ && ((argv[optind][0] == '-'
+ && (argv[optind][1] == '-' || long_only))
+#ifdef GETOPT_COMPAT
+ || argv[optind][0] == '+'
+#endif /* GETOPT_COMPAT */
+ ))
+ {
+ const struct option *p;
+ char *s = nextchar;
+ int exact = 0;
+ int ambig = 0;
+ const struct option *pfound = NULL;
+ int indfound;
+
+ while (*s && *s != '=')
+ s++;
+
+ /* Test all options for either exact match or abbreviated matches. */
+ for (p = longopts, option_index = 0; p->name;
+ p++, option_index++)
+ if (!strncmp (p->name, nextchar, s - nextchar))
+ {
+ if (s - nextchar == strlen (p->name))
+ {
+ /* Exact match found. */
+ pfound = p;
+ indfound = option_index;
+ exact = 1;
+ break;
+ }
+ else if (pfound == NULL)
+ {
+ /* First nonexact match found. */
+ pfound = p;
+ indfound = option_index;
+ }
+ else
+ /* Second nonexact match found. */
+ ambig = 1;
+ }
+
+ if (ambig && !exact)
+ {
+ if (opterr)
+ fprintf (stderr, "%s: option `%s' is ambiguous\n",
+ argv[0], argv[optind]);
+ nextchar += strlen (nextchar);
+ optind++;
+ return '?';
+ }
+
+ if (pfound != NULL)
+ {
+ option_index = indfound;
+ optind++;
+ if (*s)
+ {
+ /* Don't test has_arg with >, because some C compilers don't
+ allow it to be used on enums. */
+ if (pfound->has_arg)
+ optarg = s + 1;
+ else
+ {
+ if (opterr)
+ {
+ if (argv[optind - 1][1] == '-')
+ /* --option */
+ fprintf (stderr,
+ "%s: option `--%s' doesn't allow an argument\n",
+ argv[0], pfound->name);
+ else
+ /* +option or -option */
+ fprintf (stderr,
+ "%s: option `%c%s' doesn't allow an argument\n",
+ argv[0], argv[optind - 1][0], pfound->name);
+ }
+ nextchar += strlen (nextchar);
+ return '?';
+ }
+ }
+ else if (pfound->has_arg == 1)
+ {
+ if (optind < argc)
+ optarg = argv[optind++];
+ else
+ {
+ if (opterr)
+ fprintf (stderr, "%s: option `%s' requires an argument\n",
+ argv[0], argv[optind - 1]);
+ nextchar += strlen (nextchar);
+ return optstring[0] == ':' ? ':' : '?';
+ }
+ }
+ nextchar += strlen (nextchar);
+ if (longind != NULL)
+ *longind = option_index;
+ if (pfound->flag)
+ {
+ *(pfound->flag) = pfound->val;
+ return 0;
+ }
+ return pfound->val;
+ }
+ /* Can't find it as a long option. If this is not getopt_long_only,
+ or the option starts with '--' or is not a valid short
+ option, then it's an error.
+ Otherwise interpret it as a short option. */
+ if (!long_only || argv[optind][1] == '-'
+#ifdef GETOPT_COMPAT
+ || argv[optind][0] == '+'
+#endif /* GETOPT_COMPAT */
+ || my_index (optstring, *nextchar) == NULL)
+ {
+ if (opterr)
+ {
+ if (argv[optind][1] == '-')
+ /* --option */
+ fprintf (stderr, "%s: unrecognized option `--%s'\n",
+ argv[0], nextchar);
+ else
+ /* +option or -option */
+ fprintf (stderr, "%s: unrecognized option `%c%s'\n",
+ argv[0], argv[optind][0], nextchar);
+ }
+ nextchar = (char *) "";
+ optind++;
+ return '?';
+ }
+ }
+
+ /* Look at and handle the next option-character. */
+
+ {
+ char c = *nextchar++;
+ char *temp = my_index (optstring, c);
+
+ /* Increment `optind' when we start to process its last character. */
+ if (*nextchar == '\0')
+ ++optind;
+
+ if (temp == NULL || c == ':')
+ {
+ if (opterr)
+ {
+#if 0
+ if (c < 040 || c >= 0177)
+ fprintf (stderr, "%s: unrecognized option, character code 0%o\n",
+ argv[0], c);
+ else
+ fprintf (stderr, "%s: unrecognized option `-%c'\n", argv[0], c);
+#else
+ /* 1003.2 specifies the format of this message. */
+ fprintf (stderr, "%s: illegal option -- %c\n", argv[0], c);
+#endif
+ }
+ optopt = c;
+ return '?';
+ }
+ if (temp[1] == ':')
+ {
+ if (temp[2] == ':')
+ {
+ /* This is an option that accepts an argument optionally. */
+ if (*nextchar != '\0')
+ {
+ optarg = nextchar;
+ optind++;
+ }
+ else
+ optarg = 0;
+ nextchar = NULL;
+ }
+ else
+ {
+ /* This is an option that requires an argument. */
+ if (*nextchar != '\0')
+ {
+ optarg = nextchar;
+ /* If we end this ARGV-element by taking the rest as an arg,
+ we must advance to the next element now. */
+ optind++;
+ }
+ else if (optind == argc)
+ {
+ if (opterr)
+ {
+#if 0
+ fprintf (stderr, "%s: option `-%c' requires an argument\n",
+ argv[0], c);
+#else
+ /* 1003.2 specifies the format of this message. */
+ fprintf (stderr, "%s: option requires an argument -- %c\n",
+ argv[0], c);
+#endif
+ }
+ optopt = c;
+ if (optstring[0] == ':')
+ c = ':';
+ else
+ c = '?';
+ }
+ else
+ /* We already incremented `optind' once;
+ increment it again when taking next ARGV-elt as argument. */
+ optarg = argv[optind++];
+ nextchar = NULL;
+ }
+ }
+ return c;
+ }
+}
+
+int
+getopt (argc, argv, optstring)
+ int argc;
+ char *const *argv;
+ const char *optstring;
+{
+ return _getopt_internal (argc, argv, optstring,
+ (const struct option *) 0,
+ (int *) 0,
+ 0);
+}
+
+#endif /* _LIBC or not __GNU_LIBRARY__. */
+
+#ifdef TEST
+
+/* Compile with -DTEST to make an executable for use in testing
+ the above definition of `getopt'. */
+
+int
+main (argc, argv)
+ int argc;
+ char **argv;
+{
+ int c;
+ int digit_optind = 0;
+
+ while (1)
+ {
+ int this_option_optind = optind ? optind : 1;
+
+ c = getopt (argc, argv, "abc:d:0123456789");
+ if (c == EOF)
+ break;
+
+ switch (c)
+ {
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ if (digit_optind != 0 && digit_optind != this_option_optind)
+ printf ("digits occur in two different argv-elements.\n");
+ digit_optind = this_option_optind;
+ printf ("option %c\n", c);
+ break;
+
+ case 'a':
+ printf ("option a\n");
+ break;
+
+ case 'b':
+ printf ("option b\n");
+ break;
+
+ case 'c':
+ printf ("option c with value `%s'\n", optarg);
+ break;
+
+ case '?':
+ break;
+
+ default:
+ printf ("?? getopt returned character code 0%o ??\n", c);
+ }
+ }
+
+ if (optind < argc)
+ {
+ printf ("non-option ARGV-elements: ");
+ while (optind < argc)
+ printf ("%s ", argv[optind++]);
+ printf ("\n");
+ }
+
+ exit (0);
+}
+
+#endif /* TEST */
diff --git a/gnu/usr.bin/texinfo/info/getopt.h b/gnu/usr.bin/texinfo/info/getopt.h
new file mode 100644
index 0000000..45541f5
--- /dev/null
+++ b/gnu/usr.bin/texinfo/info/getopt.h
@@ -0,0 +1,129 @@
+/* Declarations for getopt.
+ Copyright (C) 1989, 1990, 1991, 1992, 1993 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any
+ later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#ifndef _GETOPT_H
+#define _GETOPT_H 1
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* For communication from `getopt' to the caller.
+ When `getopt' finds an option that takes an argument,
+ the argument value is returned here.
+ Also, when `ordering' is RETURN_IN_ORDER,
+ each non-option ARGV-element is returned here. */
+
+extern char *optarg;
+
+/* Index in ARGV of the next element to be scanned.
+ This is used for communication to and from the caller
+ and for communication between successive calls to `getopt'.
+
+ On entry to `getopt', zero means this is the first call; initialize.
+
+ When `getopt' returns EOF, this is the index of the first of the
+ non-option elements that the caller should itself scan.
+
+ Otherwise, `optind' communicates from one call to the next
+ how much of ARGV has been scanned so far. */
+
+extern int optind;
+
+/* Callers store zero here to inhibit the error message `getopt' prints
+ for unrecognized options. */
+
+extern int opterr;
+
+/* Set to an option character which was unrecognized. */
+
+extern int optopt;
+
+/* Describe the long-named options requested by the application.
+ The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector
+ of `struct option' terminated by an element containing a name which is
+ zero.
+
+ The field `has_arg' is:
+ no_argument (or 0) if the option does not take an argument,
+ required_argument (or 1) if the option requires an argument,
+ optional_argument (or 2) if the option takes an optional argument.
+
+ If the field `flag' is not NULL, it points to a variable that is set
+ to the value given in the field `val' when the option is found, but
+ left unchanged if the option is not found.
+
+ To have a long-named option do something other than set an `int' to
+ a compiled-in constant, such as set a value from `optarg', set the
+ option's `flag' field to zero and its `val' field to a nonzero
+ value (the equivalent single-letter option character, if there is
+ one). For long options that have a zero `flag' field, `getopt'
+ returns the contents of the `val' field. */
+
+struct option
+{
+#if __STDC__
+ const char *name;
+#else
+ char *name;
+#endif
+ /* has_arg can't be an enum because some compilers complain about
+ type mismatches in all the code that assumes it is an int. */
+ int has_arg;
+ int *flag;
+ int val;
+};
+
+/* Names for the values of the `has_arg' field of `struct option'. */
+
+#define no_argument 0
+#define required_argument 1
+#define optional_argument 2
+
+#if __STDC__
+#if defined(__GNU_LIBRARY__)
+/* Many other libraries have conflicting prototypes for getopt, with
+ differences in the consts, in stdlib.h. To avoid compilation
+ errors, only prototype getopt for the GNU C library. */
+extern int getopt (int argc, char *const *argv, const char *shortopts);
+#else /* not __GNU_LIBRARY__ */
+extern int getopt ();
+#endif /* not __GNU_LIBRARY__ */
+extern int getopt_long (int argc, char *const *argv, const char *shortopts,
+ const struct option *longopts, int *longind);
+extern int getopt_long_only (int argc, char *const *argv,
+ const char *shortopts,
+ const struct option *longopts, int *longind);
+
+/* Internal only. Users should not call this directly. */
+extern int _getopt_internal (int argc, char *const *argv,
+ const char *shortopts,
+ const struct option *longopts, int *longind,
+ int long_only);
+#else /* not __STDC__ */
+extern int getopt ();
+extern int getopt_long ();
+extern int getopt_long_only ();
+
+extern int _getopt_internal ();
+#endif /* not __STDC__ */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _GETOPT_H */
diff --git a/gnu/usr.bin/texinfo/info/getopt1.c b/gnu/usr.bin/texinfo/info/getopt1.c
new file mode 100644
index 0000000..a32615c
--- /dev/null
+++ b/gnu/usr.bin/texinfo/info/getopt1.c
@@ -0,0 +1,176 @@
+/* getopt_long and getopt_long_only entry points for GNU getopt.
+ Copyright (C) 1987, 88, 89, 90, 91, 92, 1993
+ Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any
+ later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "getopt.h"
+
+#if !__STDC__ && !defined(const) && IN_GCC
+#define const
+#endif
+
+#include <stdio.h>
+
+/* Comment out all this code if we are using the GNU C Library, and are not
+ actually compiling the library itself. This code is part of the GNU C
+ Library, but also included in many other GNU distributions. Compiling
+ and linking in this code is a waste when using the GNU C library
+ (especially if it is a shared library). Rather than having every GNU
+ program understand `configure --with-gnu-libc' and omit the object files,
+ it is simpler to just do this in the source for each such file. */
+
+#if defined (_LIBC) || !defined (__GNU_LIBRARY__)
+
+
+/* This needs to come after some library #include
+ to get __GNU_LIBRARY__ defined. */
+#ifdef __GNU_LIBRARY__
+#include <stdlib.h>
+#else
+char *getenv ();
+#endif
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+int
+getopt_long (argc, argv, options, long_options, opt_index)
+ int argc;
+ char *const *argv;
+ const char *options;
+ const struct option *long_options;
+ int *opt_index;
+{
+ return _getopt_internal (argc, argv, options, long_options, opt_index, 0);
+}
+
+/* Like getopt_long, but '-' as well as '--' can indicate a long option.
+ If an option that starts with '-' (not '--') doesn't match a long option,
+ but does match a short option, it is parsed as a short option
+ instead. */
+
+int
+getopt_long_only (argc, argv, options, long_options, opt_index)
+ int argc;
+ char *const *argv;
+ const char *options;
+ const struct option *long_options;
+ int *opt_index;
+{
+ return _getopt_internal (argc, argv, options, long_options, opt_index, 1);
+}
+
+
+#endif /* _LIBC or not __GNU_LIBRARY__. */
+
+#ifdef TEST
+
+#include <stdio.h>
+
+int
+main (argc, argv)
+ int argc;
+ char **argv;
+{
+ int c;
+ int digit_optind = 0;
+
+ while (1)
+ {
+ int this_option_optind = optind ? optind : 1;
+ int option_index = 0;
+ static struct option long_options[] =
+ {
+ {"add", 1, 0, 0},
+ {"append", 0, 0, 0},
+ {"delete", 1, 0, 0},
+ {"verbose", 0, 0, 0},
+ {"create", 0, 0, 0},
+ {"file", 1, 0, 0},
+ {0, 0, 0, 0}
+ };
+
+ c = getopt_long (argc, argv, "abc:d:0123456789",
+ long_options, &option_index);
+ if (c == EOF)
+ break;
+
+ switch (c)
+ {
+ case 0:
+ printf ("option %s", long_options[option_index].name);
+ if (optarg)
+ printf (" with arg %s", optarg);
+ printf ("\n");
+ break;
+
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ if (digit_optind != 0 && digit_optind != this_option_optind)
+ printf ("digits occur in two different argv-elements.\n");
+ digit_optind = this_option_optind;
+ printf ("option %c\n", c);
+ break;
+
+ case 'a':
+ printf ("option a\n");
+ break;
+
+ case 'b':
+ printf ("option b\n");
+ break;
+
+ case 'c':
+ printf ("option c with value `%s'\n", optarg);
+ break;
+
+ case 'd':
+ printf ("option d with value `%s'\n", optarg);
+ break;
+
+ case '?':
+ break;
+
+ default:
+ printf ("?? getopt returned character code 0%o ??\n", c);
+ }
+ }
+
+ if (optind < argc)
+ {
+ printf ("non-option ARGV-elements: ");
+ while (optind < argc)
+ printf ("%s ", argv[optind++]);
+ printf ("\n");
+ }
+
+ exit (0);
+}
+
+#endif /* TEST */
diff --git a/gnu/usr.bin/texinfo/info/indices.c b/gnu/usr.bin/texinfo/info/indices.c
new file mode 100644
index 0000000..12029f6
--- /dev/null
+++ b/gnu/usr.bin/texinfo/info/indices.c
@@ -0,0 +1,667 @@
+/* indices.c -- Commands for dealing with an Info file Index. */
+
+/* This file is part of GNU Info, a program for reading online documentation
+ stored in Info format.
+
+ Copyright (C) 1993 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ Written by Brian Fox (bfox@ai.mit.edu). */
+
+#include "info.h"
+#include "indices.h"
+
+/* User-visible variable controls the output of info-index-next. */
+int show_index_match = 1;
+
+/* In the Info sense, an index is a menu. This variable holds the last
+ parsed index. */
+static REFERENCE **index_index = (REFERENCE **)NULL;
+
+/* The offset of the most recently selected index element. */
+static int index_offset = 0;
+
+/* Variable which holds the last string searched for. */
+static char *index_search = (char *)NULL;
+
+/* A couple of "globals" describing where the initial index was found. */
+static char *initial_index_filename = (char *)NULL;
+static char *initial_index_nodename = (char *)NULL;
+
+/* A structure associating index names with index offset ranges. */
+typedef struct {
+ char *name; /* The nodename of this index. */
+ int first; /* The index in our list of the first entry. */
+ int last; /* The index in our list of the last entry. */
+} INDEX_NAME_ASSOC;
+
+/* An array associating index nodenames with index offset ranges. */
+static INDEX_NAME_ASSOC **index_nodenames = (INDEX_NAME_ASSOC **)NULL;
+static int index_nodenames_index = 0;
+static int index_nodenames_slots = 0;
+
+/* Add the name of NODE, and the range of the associated index elements
+ (passed in ARRAY) to index_nodenames. */
+static void
+add_index_to_index_nodenames (array, node)
+ REFERENCE **array;
+ NODE *node;
+{
+ register int i, last;
+ INDEX_NAME_ASSOC *assoc;
+
+ for (last = 0; array[last]; last++);
+ assoc = (INDEX_NAME_ASSOC *)xmalloc (sizeof (INDEX_NAME_ASSOC));
+ assoc->name = savestring (node->nodename);
+
+ if (!index_nodenames_index)
+ {
+ assoc->first = 0;
+ assoc->last = last;
+ }
+ else
+ {
+ for (i = 0; index_nodenames[i + 1]; i++);
+ assoc->first = 1 + index_nodenames[i]->last;
+ assoc->last = assoc->first + last;
+ }
+ add_pointer_to_array
+ (assoc, index_nodenames_index, index_nodenames, index_nodenames_slots,
+ 10, INDEX_NAME_ASSOC *);
+}
+
+/* Find and return the indices of WINDOW's file. The indices are defined
+ as the first node in the file containing the word "Index" and any
+ immediately following nodes whose names also contain "Index". All such
+ indices are concatenated and the result returned. If WINDOW's info file
+ doesn't have any indices, a NULL pointer is returned. */
+REFERENCE **
+info_indices_of_window (window)
+ WINDOW *window;
+{
+ FILE_BUFFER *fb;
+
+ fb = file_buffer_of_window (window);
+
+ return (info_indices_of_file_buffer (fb));
+}
+
+REFERENCE **
+info_indices_of_file_buffer (file_buffer)
+ FILE_BUFFER *file_buffer;
+{
+ register int i;
+ REFERENCE **result = (REFERENCE **)NULL;
+
+ /* No file buffer, no indices. */
+ if (!file_buffer)
+ return ((REFERENCE **)NULL);
+
+ /* Reset globals describing where the index was found. */
+ maybe_free (initial_index_filename);
+ maybe_free (initial_index_nodename);
+ initial_index_filename = (char *)NULL;
+ initial_index_nodename = (char *)NULL;
+
+ if (index_nodenames)
+ {
+ for (i = 0; index_nodenames[i]; i++)
+ {
+ free (index_nodenames[i]->name);
+ free (index_nodenames[i]);
+ }
+
+ index_nodenames_index = 0;
+ index_nodenames[0] = (INDEX_NAME_ASSOC *)NULL;
+ }
+
+ /* Grovel the names of the nodes found in this file. */
+ if (file_buffer->tags)
+ {
+ TAG *tag;
+
+ for (i = 0; tag = file_buffer->tags[i]; i++)
+ {
+ if (string_in_line ("Index", tag->nodename) != -1)
+ {
+ NODE *node;
+ REFERENCE **menu;
+
+ /* Found one. Get its menu. */
+ node = info_get_node (tag->filename, tag->nodename);
+ if (!node)
+ continue;
+
+ /* Remember the filename and nodename of this index. */
+ initial_index_filename = savestring (file_buffer->filename);
+ initial_index_nodename = savestring (tag->nodename);
+
+ menu = info_menu_of_node (node);
+
+ /* If we have a menu, add this index's nodename and range
+ to our list of index_nodenames. */
+ if (menu)
+ {
+ add_index_to_index_nodenames (menu, node);
+
+ /* Concatenate the references found so far. */
+ result = info_concatenate_references (result, menu);
+ }
+ free (node);
+ }
+ }
+ }
+
+ /* If there is a result, clean it up so that every entry has a filename. */
+ for (i = 0; result && result[i]; i++)
+ if (!result[i]->filename)
+ result[i]->filename = savestring (file_buffer->filename);
+
+ return (result);
+}
+
+DECLARE_INFO_COMMAND (info_index_search,
+ "Look up a string in the index for this file")
+{
+ FILE_BUFFER *fb;
+ char *line;
+
+ /* Reset the index offset, since this is not the info-index-next command. */
+ index_offset = 0;
+
+ /* The user is selecting a new search string, so flush the old one. */
+ maybe_free (index_search);
+ index_search = (char *)NULL;
+
+ /* If this window's file is not the same as the one that we last built an
+ index for, build and remember an index now. */
+ fb = file_buffer_of_window (window);
+ if (!initial_index_filename ||
+ (strcmp (initial_index_filename, fb->filename) != 0))
+ {
+ info_free_references (index_index);
+ window_message_in_echo_area ("Finding index entries...");
+ index_index = info_indices_of_file_buffer (fb);
+ }
+
+ /* If there is no index, quit now. */
+ if (!index_index)
+ {
+ info_error ("No indices found.");
+ return;
+ }
+
+ /* Okay, there is an index. Let the user select one of the members of it. */
+ line =
+ info_read_maybe_completing (window, "Index entry: ", index_index);
+
+ window = active_window;
+
+ /* User aborted? */
+ if (!line)
+ {
+ info_abort_key (active_window, 1, 0);
+ return;
+ }
+
+ /* Empty line means move to the Index node. */
+ if (!*line)
+ {
+ free (line);
+
+ if (initial_index_filename && initial_index_nodename)
+ {
+ NODE *node;
+
+ node =
+ info_get_node (initial_index_filename, initial_index_nodename);
+ set_remembered_pagetop_and_point (window);
+ window_set_node_of_window (window, node);
+ remember_window_and_node (window, node);
+ window_clear_echo_area ();
+ return;
+ }
+ }
+
+ /* The user typed either a completed index label, or a partial string.
+ Find an exact match, or, failing that, the first index entry containing
+ the partial string. So, we just call info_next_index_match () with minor
+ manipulation of INDEX_OFFSET. */
+ {
+ int old_offset;
+
+ /* Start the search right after/before this index. */
+ if (count < 0)
+ {
+ register int i;
+ for (i = 0; index_index[i]; i++);
+ index_offset = i;
+ }
+ else
+ index_offset = -1;
+
+ old_offset == index_offset;
+
+ /* The "last" string searched for is this one. */
+ index_search = line;
+
+ /* Find it, or error. */
+ info_next_index_match (window, count, 0);
+
+ /* If the search failed, return the index offset to where it belongs. */
+ if (index_offset == old_offset)
+ index_offset = 0;
+ }
+}
+
+DECLARE_INFO_COMMAND (info_next_index_match,
+ "Go to the next matching index item from the last `\\[index-search]' command")
+{
+ register int i;
+ int partial, dir;
+ NODE *node;
+
+ /* If there is no previous search string, the user hasn't built an index
+ yet. */
+ if (!index_search)
+ {
+ info_error ("No previous index search string.");
+ return;
+ }
+
+ /* If there is no index, that is an error. */
+ if (!index_index)
+ {
+ info_error ("No index entries.");
+ return;
+ }
+
+ /* The direction of this search is controlled by the value of the
+ numeric argument. */
+ if (count < 0)
+ dir = -1;
+ else
+ dir = 1;
+
+ /* Search for the next occurence of index_search. First try to find
+ an exact match. */
+ partial = 0;
+
+ for (i = index_offset + dir; (i > -1) && (index_index[i]); i += dir)
+ if (strcmp (index_search, index_index[i]->label) == 0)
+ break;
+
+ /* If that failed, look for the next substring match. */
+ if ((i < 0) || (!index_index[i]))
+ {
+ for (i = index_offset + dir; (i > -1) && (index_index[i]); i += dir)
+ if (string_in_line (index_search, index_index[i]->label) != -1)
+ break;
+
+ if ((i > -1) && (index_index[i]))
+ partial = string_in_line (index_search, index_index[i]->label);
+ }
+
+ /* If that failed, print an error. */
+ if ((i < 0) || (!index_index[i]))
+ {
+ info_error ("No %sindex entries containing \"%s\".",
+ index_offset > 0 ? "more " : "", index_search);
+ return;
+ }
+
+ /* Okay, we found the next one. Move the offset to the current entry. */
+ index_offset = i;
+
+ /* Report to the user on what we have found. */
+ {
+ register int j;
+ char *name = "CAN'T SEE THIS";
+ char *match;
+
+ for (j = 0; index_nodenames[j]; j++)
+ {
+ if ((i >= index_nodenames[j]->first) &&
+ (i <= index_nodenames[j]->last))
+ {
+ name = index_nodenames[j]->name;
+ break;
+ }
+ }
+
+ /* If we had a partial match, indicate to the user which part of the
+ string matched. */
+ match = savestring (index_index[i]->label);
+
+ if (partial && show_index_match)
+ {
+ int j, ls, start, upper;
+
+ ls = strlen (index_search);
+ start = partial - ls;
+ upper = isupper (match[start]) ? 1 : 0;
+
+ for (j = 0; j < ls; j++)
+ if (upper)
+ match[j + start] = info_tolower (match[j + start]);
+ else
+ match[j + start] = info_toupper (match[j + start]);
+ }
+
+ {
+ char *format;
+
+ format = replace_in_documentation
+ ("Found \"%s\" in %s. (`\\[next-index-match]' tries to find next.)");
+
+ window_message_in_echo_area (format, match, name);
+ }
+
+ free (match);
+ }
+
+ /* Select the node corresponding to this index entry. */
+ node = info_get_node (index_index[i]->filename, index_index[i]->nodename);
+
+ if (!node)
+ {
+ info_error (CANT_FILE_NODE,
+ index_index[i]->filename, index_index[i]->nodename);
+ return;
+ }
+
+ set_remembered_pagetop_and_point (window);
+ window_set_node_of_window (window, node);
+ remember_window_and_node (window, node);
+
+
+ /* Try to find an occurence of LABEL in this node. */
+ {
+ long start, loc;
+
+ start = window->line_starts[1] - window->node->contents;
+ loc = info_target_search_node (node, index_index[i]->label, start);
+
+ if (loc != -1)
+ {
+ window->point = loc;
+ window_adjust_pagetop (window);
+ }
+ }
+}
+
+/* **************************************************************** */
+/* */
+/* Info APROPOS: Search every known index. */
+/* */
+/* **************************************************************** */
+
+/* For every menu item in DIR, search the indices of that file for
+ SEARCH_STRING. */
+REFERENCE **
+apropos_in_all_indices (search_string, inform)
+ char *search_string;
+ int inform;
+{
+ register int i, dir_index;
+ REFERENCE **all_indices = (REFERENCE **)NULL;
+ REFERENCE **dir_menu = (REFERENCE **)NULL;
+ NODE *dir_node;
+ int printed = 0;
+
+ dir_node = info_get_node ("dir", "Top");
+ if (dir_node)
+ dir_menu = info_menu_of_node (dir_node);
+
+ if (!dir_menu)
+ return;
+
+ /* For every menu item in DIR, get the associated node's file buffer and
+ read the indices of that file buffer. Gather all of the indices into
+ one large one. */
+ for (dir_index = 0; dir_menu[dir_index]; dir_index++)
+ {
+ REFERENCE **this_index, *this_item;
+ NODE *this_node;
+ FILE_BUFFER *this_fb;
+
+ this_item = dir_menu[dir_index];
+
+ if (!this_item->filename)
+ {
+ if (dir_node->parent)
+ this_item->filename = savestring (dir_node->parent);
+ else
+ this_item->filename = savestring (dir_node->filename);
+ }
+
+ /* Find this node. If we cannot find it, try using the label of the
+ entry as a file (i.e., "(LABEL)Top"). */
+ this_node = info_get_node (this_item->filename, this_item->nodename);
+
+ if (!this_node && this_item->nodename &&
+ (strcmp (this_item->label, this_item->nodename) == 0))
+ this_node = info_get_node (this_item->label, "Top");
+
+ if (!this_node)
+ continue;
+
+ /* Get the file buffer associated with this node. */
+ {
+ char *files_name;
+
+ files_name = this_node->parent;
+ if (!files_name)
+ files_name = this_node->filename;
+
+ this_fb = info_find_file (files_name);
+
+ if (this_fb && inform)
+ message_in_echo_area ("Scanning indices of \"%s\"...", files_name);
+
+ this_index = info_indices_of_file_buffer (this_fb);
+ free (this_node);
+
+ if (this_fb && inform)
+ unmessage_in_echo_area ();
+ }
+
+ if (this_index)
+ {
+ /* Remember the filename which contains this set of references. */
+ for (i = 0; this_index && this_index[i]; i++)
+ if (!this_index[i]->filename)
+ this_index[i]->filename = savestring (this_fb->filename);
+
+ /* Concatenate with the other indices. */
+ all_indices = info_concatenate_references (all_indices, this_index);
+ }
+ }
+
+ info_free_references (dir_menu);
+
+ /* Build a list of the references which contain SEARCH_STRING. */
+ if (all_indices)
+ {
+ REFERENCE *entry, **apropos_list = (REFERENCE **)NULL;
+ int apropos_list_index = 0;
+ int apropos_list_slots = 0;
+
+ for (i = 0; (entry = all_indices[i]); i++)
+ {
+ if (string_in_line (search_string, entry->label) != -1)
+ {
+ add_pointer_to_array
+ (entry, apropos_list_index, apropos_list, apropos_list_slots,
+ 100, REFERENCE *);
+ }
+ else
+ {
+ maybe_free (entry->label);
+ maybe_free (entry->filename);
+ maybe_free (entry->nodename);
+ free (entry);
+ }
+ }
+
+ free (all_indices);
+ all_indices = apropos_list;
+ }
+ return (all_indices);
+}
+
+#define APROPOS_NONE \
+ "No available info files reference \"%s\" in their indices."
+
+void
+info_apropos (string)
+ char *string;
+{
+ REFERENCE **apropos_list;
+
+ apropos_list = apropos_in_all_indices (string, 0);
+
+ if (!apropos_list)
+ {
+ info_error (APROPOS_NONE, string);
+ }
+ else
+ {
+ register int i;
+ REFERENCE *entry;
+
+ for (i = 0; (entry = apropos_list[i]); i++)
+ fprintf (stderr, "\"(%s)%s\" -- %s\n",
+ entry->filename, entry->nodename, entry->label);
+ }
+ info_free_references (apropos_list);
+}
+
+static char *apropos_list_nodename = "*Apropos*";
+
+DECLARE_INFO_COMMAND (info_index_apropos,
+ "Grovel all known info file's indices for a string and build a menu")
+{
+ char *line;
+
+ line = info_read_in_echo_area (window, "Index apropos: ");
+
+ window = active_window;
+
+ /* User aborted? */
+ if (!line)
+ {
+ info_abort_key (window, 1, 1);
+ return;
+ }
+
+ /* User typed something? */
+ if (*line)
+ {
+ REFERENCE **apropos_list;
+ NODE *apropos_node;
+
+ apropos_list = apropos_in_all_indices (line, 1);
+
+ if (!apropos_list)
+ {
+ info_error (APROPOS_NONE, line);
+ }
+ else
+ {
+ register int i;
+ char *line_buffer;
+
+ initialize_message_buffer ();
+ printf_to_message_buffer
+ ("\n* Menu: Nodes whoses indices contain \"%s\":\n", line);
+ line_buffer = (char *)xmalloc (500);
+
+ for (i = 0; apropos_list[i]; i++)
+ {
+ int len;
+ sprintf (line_buffer, "* (%s)%s::",
+ apropos_list[i]->filename, apropos_list[i]->nodename);
+ len = pad_to (36, line_buffer);
+ sprintf (line_buffer + len, "%s", apropos_list[i]->label);
+ printf_to_message_buffer ("%s\n", line_buffer);
+ }
+ free (line_buffer);
+ }
+
+ apropos_node = message_buffer_to_node ();
+ add_gcable_pointer (apropos_node);
+ name_internal_node (apropos_node, apropos_list_nodename);
+
+ /* Even though this is an internal node, we don't want the window
+ system to treat it specially. So we turn off the internalness
+ of it here. */
+ apropos_node->flags &= ~N_IsInternal;
+
+ /* Find/Create a window to contain this node. */
+ {
+ WINDOW *new;
+ NODE *node;
+
+ set_remembered_pagetop_and_point (window);
+
+ /* If a window is visible and showing an apropos list already,
+ re-use it. */
+ for (new = windows; new; new = new->next)
+ {
+ node = new->node;
+
+ if (internal_info_node_p (node) &&
+ (strcmp (node->nodename, apropos_list_nodename) == 0))
+ break;
+ }
+
+ /* If we couldn't find an existing window, try to use the next window
+ in the chain. */
+ if (!new && window->next)
+ new = window->next;
+
+ /* If we still don't have a window, make a new one to contain
+ the list. */
+ if (!new)
+ {
+ WINDOW *old_active;
+
+ old_active = active_window;
+ active_window = window;
+ new = window_make_window ((NODE *)NULL);
+ active_window = old_active;
+ }
+
+ /* If we couldn't make a new window, use this one. */
+ if (!new)
+ new = window;
+
+ /* Lines do not wrap in this window. */
+ new->flags |= W_NoWrap;
+
+ window_set_node_of_window (new, apropos_node);
+ remember_window_and_node (new, apropos_node);
+ active_window = new;
+ }
+ info_free_references (apropos_list);
+ }
+ free (line);
+
+ if (!info_error_was_printed)
+ window_clear_echo_area ();
+}
+
diff --git a/gnu/usr.bin/texinfo/info/indices.h b/gnu/usr.bin/texinfo/info/indices.h
new file mode 100644
index 0000000..b63a458
--- /dev/null
+++ b/gnu/usr.bin/texinfo/info/indices.h
@@ -0,0 +1,39 @@
+/* indices.h -- Functions defined in indices.c. */
+
+/* This file is part of GNU Info, a program for reading online documentation
+ stored in Info format.
+
+ Copyright (C) 1993 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ Written by Brian Fox (bfox@ai.mit.edu). */
+
+#ifndef _INDICES_H_
+#define _INDICES_H_
+
+/* User-visible variable controls the output of info-index-next. */
+extern int show_index_match;
+
+extern REFERENCE **info_indices_of_window (), **info_indices_of_file_buffer ();
+extern void info_apropos ();
+
+/* For every menu item in DIR, search the indices of that file for STRING. */
+REFERENCE **apropos_in_all_indices ();
+
+/* User visible functions declared in indices.c. */
+extern void info_index_search (), info_next_index_match ();
+
+#endif /* !_INDICES_H_ */
diff --git a/gnu/usr.bin/texinfo/info/info-utils.c b/gnu/usr.bin/texinfo/info/info-utils.c
new file mode 100644
index 0000000..56edcd6
--- /dev/null
+++ b/gnu/usr.bin/texinfo/info/info-utils.c
@@ -0,0 +1,653 @@
+/* info-utils.c -- Useful functions for manipulating Info file quirks. */
+
+/* This file is part of GNU Info, a program for reading online documentation
+ stored in Info format.
+
+ Copyright (C) 1993 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ Written by Brian Fox (bfox@ai.mit.edu). */
+
+#include <stdio.h> /* For "NULL". Yechhh! */
+#include <ctype.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include "info-utils.h"
+
+/* When non-zero, various display and input functions handle ISO Latin
+ character sets correctly. */
+int ISO_Latin_p = 0;
+
+/* Variable which holds the most recent filename parsed as a result of
+ calling info_parse_xxx (). */
+char *info_parsed_filename = (char *)NULL;
+
+/* Variable which holds the most recent nodename parsed as a result of
+ calling info_parse_xxx (). */
+char *info_parsed_nodename = (char *)NULL;
+
+/* Functions to remember a filename or nodename for later return. */
+static void save_filename (), saven_filename ();
+static void save_nodename (), saven_nodename ();
+
+/* How to get a reference (either menu or cross). */
+static REFERENCE **info_references_internal ();
+
+/* Parse the filename and nodename out of STRING. If STRING doesn't
+ contain a filename (i.e., it is NOT (FILENAME)NODENAME) then set
+ INFO_PARSED_FILENAME to NULL. If second argument NEWLINES_OKAY is
+ non-zero, it says to allow the nodename specification to cross a
+ newline boundary (i.e., only `,', `.', or `TAB' can end the spec). */
+void
+info_parse_node (string, newlines_okay)
+ char *string;
+ int newlines_okay;
+{
+ register int i = 0;
+
+ /* Default the answer. */
+ save_filename ((char *)NULL);
+ save_nodename ((char *)NULL);
+
+ /* Special case of nothing passed. Return nothing. */
+ if (!string || !*string)
+ return;
+
+ string += skip_whitespace (string);
+
+ /* Check for (FILENAME)NODENAME. */
+ if (*string == '(')
+ {
+ i = 0;
+ /* Advance past the opening paren. */
+ string++;
+
+ /* Find the closing paren. */
+ while (string[i] && string[i] != ')')
+ i++;
+
+ /* Remember parsed filename. */
+ saven_filename (string, i);
+
+ /* Point directly at the nodename. */
+ string += i;
+
+ if (*string)
+ string++;
+ }
+
+ /* Parse out nodename. */
+ i = skip_node_characters (string, newlines_okay);
+ saven_nodename (string, i);
+ canonicalize_whitespace (info_parsed_nodename);
+ if (info_parsed_nodename && !*info_parsed_nodename)
+ {
+ free (info_parsed_nodename);
+ info_parsed_nodename = (char *)NULL;
+ }
+}
+
+/* Return the node addressed by LABEL in NODE (usually one of "Prev:",
+ "Next:", "Up:", "File:", or "Node:". After a call to this function,
+ the global INFO_PARSED_NODENAME and INFO_PARSED_FILENAME contain
+ the information. */
+void
+info_parse_label (label, node)
+ char *label;
+ NODE *node;
+{
+ register int i;
+ char *nodeline;
+
+ /* Default answer to failure. */
+ save_nodename ((char *)NULL);
+ save_filename ((char *)NULL);
+
+ /* Find the label in the first line of this node. */
+ nodeline = node->contents;
+ i = string_in_line (label, nodeline);
+
+ if (i == -1)
+ return;
+
+ nodeline += i;
+ nodeline += skip_whitespace (nodeline);
+ info_parse_node (nodeline, DONT_SKIP_NEWLINES);
+}
+
+/* **************************************************************** */
+/* */
+/* Finding and Building Menus */
+/* */
+/* **************************************************************** */
+
+/* Return a NULL terminated array of REFERENCE * which represents the menu
+ found in NODE. If there is no menu in NODE, just return a NULL pointer. */
+REFERENCE **
+info_menu_of_node (node)
+ NODE *node;
+{
+ long position;
+ SEARCH_BINDING search;
+ REFERENCE **menu = (REFERENCE **)NULL;
+
+ search.buffer = node->contents;
+ search.start = 0;
+ search.end = node->nodelen;
+ search.flags = S_FoldCase;
+
+ /* Find the start of the menu. */
+ position = search_forward (INFO_MENU_LABEL, &search);
+
+ if (position == -1)
+ return ((REFERENCE **) NULL);
+
+ /* We have the start of the menu now. Glean menu items from the rest
+ of the node. */
+ search.start = position + strlen (INFO_MENU_LABEL);
+ search.start += skip_line (search.buffer + search.start);
+ search.start--;
+ menu = info_menu_items (&search);
+ return (menu);
+}
+
+/* Return a NULL terminated array of REFERENCE * which represents the cross
+ refrences found in NODE. If there are no cross references in NODE, just
+ return a NULL pointer. */
+REFERENCE **
+info_xrefs_of_node (node)
+ NODE *node;
+{
+ SEARCH_BINDING search;
+
+ search.buffer = node->contents;
+ search.start = 0;
+ search.end = node->nodelen;
+ search.flags = S_FoldCase;
+
+ return (info_xrefs (&search));
+}
+
+/* Glean menu entries from BINDING->buffer + BINDING->start until we
+ have looked at the entire contents of BINDING. Return an array
+ of REFERENCE * that represents each menu item in this range. */
+REFERENCE **
+info_menu_items (binding)
+ SEARCH_BINDING *binding;
+{
+ return (info_references_internal (INFO_MENU_ENTRY_LABEL, binding));
+}
+
+/* Glean cross references from BINDING->buffer + BINDING->start until
+ BINDING->end. Return an array of REFERENCE * that represents each
+ cross reference in this range. */
+REFERENCE **
+info_xrefs (binding)
+ SEARCH_BINDING *binding;
+{
+ return (info_references_internal (INFO_XREF_LABEL, binding));
+}
+
+/* Glean cross references or menu items from BINDING. Return an array
+ of REFERENCE * that represents the items found. */
+static REFERENCE **
+info_references_internal (label, binding)
+ char *label;
+ SEARCH_BINDING *binding;
+{
+ SEARCH_BINDING search;
+ REFERENCE **refs = (REFERENCE **)NULL;
+ int refs_index = 0, refs_slots = 0;
+ int searching_for_menu_items = 0;
+ long position;
+
+ search.buffer = binding->buffer;
+ search.start = binding->start;
+ search.end = binding->end;
+ search.flags = S_FoldCase | S_SkipDest;
+
+ searching_for_menu_items = (stricmp (label, INFO_MENU_ENTRY_LABEL) == 0);
+
+ while ((position = search_forward (label, &search)) != -1)
+ {
+ int offset, start;
+ char *refdef;
+ REFERENCE *entry;
+
+ search.start = position;
+ search.start += skip_whitespace (search.buffer + search.start);
+ start = search.start - binding->start;
+ refdef = search.buffer + search.start;
+ offset = string_in_line (":", refdef);
+
+ /* When searching for menu items, if no colon, there is no
+ menu item on this line. */
+ if (offset == -1)
+ {
+ if (searching_for_menu_items)
+ continue;
+ else
+ {
+ int temp;
+
+ temp = skip_line (refdef);
+ offset = string_in_line (":", refdef + temp);
+ if (offset == -1)
+ continue; /* Give up? */
+ else
+ offset += temp;
+ }
+ }
+
+ entry = (REFERENCE *)xmalloc (sizeof (REFERENCE));
+ entry->filename = (char *)NULL;
+ entry->nodename = (char *)NULL;
+ entry->label = (char *)xmalloc (offset);
+ strncpy (entry->label, refdef, offset - 1);
+ entry->label[offset - 1] = '\0';
+ canonicalize_whitespace (entry->label);
+
+ refdef += offset;
+ entry->start = start;
+ entry->end = refdef - binding->buffer;
+
+ /* If this reference entry continues with another ':' then the
+ nodename is the same as the label. */
+ if (*refdef == ':')
+ {
+ entry->nodename = savestring (entry->label);
+ }
+ else
+ {
+ /* This entry continues with a specific nodename. Parse the
+ nodename from the specification. */
+
+ refdef += skip_whitespace_and_newlines (refdef);
+
+ if (searching_for_menu_items)
+ info_parse_node (refdef, DONT_SKIP_NEWLINES);
+ else
+ info_parse_node (refdef, SKIP_NEWLINES);
+
+ if (info_parsed_filename)
+ entry->filename = savestring (info_parsed_filename);
+
+ if (info_parsed_nodename)
+ entry->nodename = savestring (info_parsed_nodename);
+ }
+
+ add_pointer_to_array
+ (entry, refs_index, refs, refs_slots, 50, REFERENCE *);
+ }
+ return (refs);
+}
+
+/* Get the entry associated with LABEL in MENU. Return a pointer to the
+ REFERENCE if found, or NULL. */
+REFERENCE *
+info_get_labeled_reference (label, references)
+ char *label;
+ REFERENCE **references;
+{
+ register int i;
+ REFERENCE *entry;
+
+ for (i = 0; references && (entry = references[i]); i++)
+ {
+ if (strcmp (label, entry->label) == 0)
+ return (entry);
+ }
+ return ((REFERENCE *)NULL);
+}
+
+/* A utility function for concatenating REFERENCE **. Returns a new
+ REFERENCE ** which is the concatenation of REF1 and REF2. The REF1
+ and REF2 arrays are freed, but their contents are not. */
+REFERENCE **
+info_concatenate_references (ref1, ref2)
+ REFERENCE **ref1, **ref2;
+{
+ register int i, j;
+ REFERENCE **result;
+ int size;
+
+ /* With one argument passed as NULL, simply return the other arg. */
+ if (!ref1)
+ return (ref2);
+ else if (!ref2)
+ return (ref1);
+
+ /* Get the total size of the slots that we will need. */
+ for (i = 0; ref1[i]; i++);
+ size = i;
+ for (i = 0; ref2[i]; i++);
+ size += i;
+
+ result = (REFERENCE **)xmalloc ((1 + size) * sizeof (REFERENCE *));
+
+ /* Copy the contents over. */
+ for (i = 0; ref1[i]; i++)
+ result[i] = ref1[i];
+
+ j = i;
+ for (i = 0; ref2[i]; i++)
+ result[j++] = ref2[i];
+
+ result[j] = (REFERENCE *)NULL;
+ free (ref1);
+ free (ref2);
+ return (result);
+}
+
+/* Free the data associated with REFERENCES. */
+void
+info_free_references (references)
+ REFERENCE **references;
+{
+ register int i;
+ REFERENCE *entry;
+
+ if (references)
+ {
+ for (i = 0; references && (entry = references[i]); i++)
+ {
+ maybe_free (entry->label);
+ maybe_free (entry->filename);
+ maybe_free (entry->nodename);
+
+ free (entry);
+ }
+
+ free (references);
+ }
+}
+
+/* Search for sequences of whitespace or newlines in STRING, replacing
+ all such sequences with just a single space. Remove whitespace from
+ start and end of string. */
+void
+canonicalize_whitespace (string)
+ char *string;
+{
+ register int i, j;
+ int len, whitespace_found, whitespace_loc;
+ char *temp;
+
+ if (!string)
+ return;
+
+ len = strlen (string);
+ temp = (char *)xmalloc (1 + len);
+
+ /* Search for sequences of whitespace or newlines. Replace all such
+ sequences in the string with just a single space. */
+
+ whitespace_found = 0;
+ for (i = 0, j = 0; string[i]; i++)
+ {
+ if (whitespace_or_newline (string[i]))
+ {
+ whitespace_found++;
+ whitespace_loc = i;
+ continue;
+ }
+ else
+ {
+ if (whitespace_found && whitespace_loc)
+ {
+ whitespace_found = 0;
+ temp[j++] = ' ';
+ }
+
+ temp[j++] = string[i];
+ }
+ }
+
+ /* Kill trailing whitespace. */
+ if (j && whitespace (temp[j - 1]))
+ j--;
+
+ temp[j] = '\0';
+ strcpy (string, temp);
+ free (temp);
+}
+
+/* String representation of a char returned by printed_representation (). */
+static char the_rep[10];
+
+/* Return a pointer to a string which is the printed representation
+ of CHARACTER if it were printed at HPOS. */
+char *
+printed_representation (character, hpos)
+ unsigned char character;
+ int hpos;
+{
+ register int i = 0;
+ int printable_limit;
+
+ if (ISO_Latin_p)
+ printable_limit = 160;
+ else
+ printable_limit = 127;
+
+ if (character == '\177')
+ {
+ the_rep[i++] = '^';
+ the_rep[i++] = '?';
+ }
+ else if (iscntrl (character))
+ {
+ switch (character)
+ {
+ case '\r':
+ case '\n':
+ the_rep[i++] = character;
+ break;
+
+ case '\t':
+ {
+ int tw;
+
+ tw = ((hpos + 8) & 0xf8) - hpos;
+ while (i < tw)
+ the_rep[i++] = ' ';
+ }
+ break;
+
+ default:
+ the_rep[i++] = '^';
+ the_rep[i++] = (character | 0x40);
+ }
+ }
+ else if (character > printable_limit)
+ {
+ sprintf (the_rep + i, "\\%0o", character);
+ i = strlen (the_rep);
+ }
+ else
+ the_rep[i++] = character;
+
+ the_rep[i] = '\0';
+
+ return (the_rep);
+}
+
+
+/* **************************************************************** */
+/* */
+/* Functions Static To This File */
+/* */
+/* **************************************************************** */
+
+/* Amount of space allocated to INFO_PARSED_FILENAME via xmalloc (). */
+static int parsed_filename_size = 0;
+
+/* Amount of space allocated to INFO_PARSED_NODENAME via xmalloc (). */
+static int parsed_nodename_size = 0;
+
+static void save_string (), saven_string ();
+
+/* Remember FILENAME in PARSED_FILENAME. An empty FILENAME is translated
+ to a NULL pointer in PARSED_FILENAME. */
+static void
+save_filename (filename)
+ char *filename;
+{
+ save_string (filename, &info_parsed_filename, &parsed_filename_size);
+}
+
+/* Just like save_filename (), but you pass the length of the string. */
+static void
+saven_filename (filename, len)
+ char *filename;
+ int len;
+{
+ saven_string (filename, len,
+ &info_parsed_filename, &parsed_filename_size);
+}
+
+/* Remember NODENAME in PARSED_NODENAME. An empty NODENAME is translated
+ to a NULL pointer in PARSED_NODENAME. */
+static void
+save_nodename (nodename)
+ char *nodename;
+{
+ save_string (nodename, &info_parsed_nodename, &parsed_nodename_size);
+}
+
+/* Just like save_nodename (), but you pass the length of the string. */
+static void
+saven_nodename (nodename, len)
+ char *nodename;
+ int len;
+{
+ saven_string (nodename, len,
+ &info_parsed_nodename, &parsed_nodename_size);
+}
+
+/* Remember STRING in STRING_P. STRING_P should currently have STRING_SIZE_P
+ bytes allocated to it. An empty STRING is translated to a NULL pointer
+ in STRING_P. */
+static void
+save_string (string, string_p, string_size_p)
+ char *string;
+ char **string_p;
+ int *string_size_p;
+{
+ if (!string || !*string)
+ {
+ if (*string_p)
+ free (*string_p);
+
+ *string_p = (char *)NULL;
+ *string_size_p = 0;
+ }
+ else
+ {
+ if (strlen (string) >= *string_size_p)
+ *string_p = (char *)xrealloc
+ (*string_p, (*string_size_p = 1 + strlen (string)));
+
+ strcpy (*string_p, string);
+ }
+}
+
+/* Just like save_string (), but you also pass the length of STRING. */
+static void
+saven_string (string, len, string_p, string_size_p)
+ char *string;
+ int len;
+ char **string_p;
+ int *string_size_p;
+{
+ if (!string)
+ {
+ if (*string_p)
+ free (*string_p);
+
+ *string_p = (char *)NULL;
+ *string_size_p = 0;
+ }
+ else
+ {
+ if (len >= *string_size_p)
+ *string_p = (char *)xrealloc (*string_p, (*string_size_p = 1 + len));
+
+ strncpy (*string_p, string, len);
+ (*string_p)[len] = '\0';
+ }
+}
+
+/* Return a pointer to the part of PATHNAME that simply defines the file. */
+char *
+filename_non_directory (pathname)
+ char *pathname;
+{
+ char *filename;
+
+ filename = (char *)rindex (pathname, '/');
+
+ if (filename)
+ filename++;
+ else
+ filename = pathname;
+
+ return (filename);
+}
+
+/* Return non-zero if NODE is one especially created by Info. */
+int
+internal_info_node_p (node)
+ NODE *node;
+{
+ if (node &&
+ (node->filename && !*node->filename) &&
+ !node->parent && node->nodename)
+ return (1);
+ else
+ return (0);
+}
+
+/* Make NODE appear to be one especially created by Info. */
+void
+name_internal_node (node, name)
+ NODE *node;
+ char *name;
+{
+ if (!node)
+ return;
+
+ node->filename = "";
+ node->parent = (char *)NULL;
+ node->nodename = name;
+ node->flags |= N_IsInternal;
+}
+
+/* Return the window displaying NAME, the name of an internally created
+ Info window. */
+WINDOW *
+get_internal_info_window (name)
+ char *name;
+{
+ WINDOW *win = (WINDOW *)NULL;
+
+ for (win = windows; win; win = win->next)
+ if (internal_info_node_p (win->node) &&
+ (strcmp (win->node->nodename, name) == 0))
+ break;
+
+ return (win);
+}
diff --git a/gnu/usr.bin/texinfo/info/info-utils.h b/gnu/usr.bin/texinfo/info/info-utils.h
new file mode 100644
index 0000000..6c4ec30
--- /dev/null
+++ b/gnu/usr.bin/texinfo/info/info-utils.h
@@ -0,0 +1,144 @@
+/* info-utils.h -- Exported functions and variables from info-util.c. */
+
+/* This file is part of GNU Info, a program for reading online documentation
+ stored in Info format.
+
+ Copyright (C) 1993 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ Written by Brian Fox (bfox@ai.mit.edu). */
+
+#ifndef _INFO_UTILS_H_
+#define _INFO_UTILS_H_
+
+#if !defined (HAVE_RINDEX)
+#undef index
+#undef rindex
+#define index strchr
+#define rindex strrchr
+#endif
+
+#if !defined (HAVE_BCOPY)
+#undef bcopy
+#define bcopy(source, dest, count) memcpy(dest, source, count)
+#endif
+
+#include "nodes.h"
+#include "window.h"
+#include "search.h"
+
+/* Structure which describes a node reference, such as a menu entry or
+ cross reference. Arrays of such references can be built by calling
+ info_menus_of_node () or info_xrefs_of_node (). */
+typedef struct {
+ char *label; /* User Label. */
+ char *filename; /* File where this node can be found. */
+ char *nodename; /* Name of the node. */
+ int start, end; /* Offsets within the containing node of LABEL. */
+} REFERENCE;
+
+/* When non-zero, various display and input functions handle ISO Latin
+ character sets correctly. */
+extern int ISO_Latin_p;
+
+/* Variable which holds the most recent filename parsed as a result of
+ calling info_parse_xxx (). */
+extern char *info_parsed_filename;
+
+/* Variable which holds the most recent nodename parsed as a result of
+ calling info_parse_xxx (). */
+extern char *info_parsed_nodename;
+
+/* Parse the filename and nodename out of STRING. If STRING doesn't
+ contain a filename (i.e., it is NOT (FILENAME)NODENAME) then set
+ INFO_PARSED_FILENAME to NULL. If second argument NEWLINES_OKAY is
+ non-zero, it says to allow the nodename specification to cross a
+ newline boundary (i.e., only `,', `.', or `TAB' can end the spec). */
+void info_parse_node ();
+
+/* Return a NULL terminated array of REFERENCE * which represents the menu
+ found in NODE. If there is no menu in NODE, just return a NULL pointer. */
+extern REFERENCE **info_menu_of_node ();
+
+/* Return a NULL terminated array of REFERENCE * which represents the cross
+ refrences found in NODE. If there are no cross references in NODE, just
+ return a NULL pointer. */
+extern REFERENCE **info_xrefs_of_node ();
+
+/* Glean cross references from BINDING->buffer + BINDING->start until
+ BINDING->end. Return an array of REFERENCE * that represents each
+ cross reference in this range. */
+extern REFERENCE **info_xrefs ();
+
+/* Get the entry associated with LABEL in REFERENCES. Return a pointer to
+ the reference if found, or NULL. */
+extern REFERENCE *info_get_labeled_reference ();
+
+/* Glean menu entries from BINDING->buffer + BINDING->start until we
+ have looked at the entire contents of BINDING. Return an array
+ of REFERENCE * that represents each menu item in this range. */
+extern REFERENCE **info_menu_items ();
+
+/* A utility function for concatenating REFERENCE **. Returns a new
+ REFERENCE ** which is the concatenation of REF1 and REF2. The REF1
+ and REF2 arrays are freed, but their contents are not. */
+REFERENCE **info_concatenate_references ();
+
+/* Free the data associated with REFERENCES. */
+extern void info_free_references ();
+
+/* Search for sequences of whitespace or newlines in STRING, replacing
+ all such sequences with just a single space. Remove whitespace from
+ start and end of string. */
+void canonicalize_whitespace ();
+
+/* Return a pointer to a string which is the printed representation
+ of CHARACTER if it were printed at HPOS. */
+extern char *printed_representation ();
+
+/* Return a pointer to the part of PATHNAME that simply defines the file. */
+extern char *filename_non_directory ();
+
+/* Return non-zero if NODE is one especially created by Info. */
+extern int internal_info_node_p ();
+
+/* Make NODE appear to be one especially created by Info, and give it NAME. */
+extern void name_internal_node ();
+
+/* Return the window displaying NAME, the name of an internally created
+ Info window. */
+extern WINDOW *get_internal_info_window ();
+
+/* Return the node addressed by LABEL in NODE (usually one of "Prev:",
+ "Next:", "Up:", "File:", or "Node:". After a call to this function,
+ the global INFO_PARSED_NODENAME and INFO_PARSED_FILENAME contain
+ the information. */
+extern void info_parse_label (/* label, node */);
+
+#define info_label_was_found \
+ (info_parsed_nodename != NULL || info_parsed_filename != NULL)
+
+#define info_file_label_of_node(n) info_parse_label (INFO_FILE_LABEL, n)
+#define info_next_label_of_node(n) info_parse_label (INFO_NEXT_LABEL, n)
+#define info_up_label_of_node(n) info_parse_label (INFO_UP_LABEL, n)
+#define info_prev_label_of_node(n) \
+ do { \
+ info_parse_label (INFO_PREV_LABEL, n); \
+ if (!info_label_was_found) \
+ info_parse_label (INFO_ALTPREV_LABEL, n); \
+ } while (0)
+
+#endif /* !_INFO_UTILS_H_ */
diff --git a/gnu/usr.bin/texinfo/info/info.1 b/gnu/usr.bin/texinfo/info/info.1
new file mode 100644
index 0000000..aabfcf1
--- /dev/null
+++ b/gnu/usr.bin/texinfo/info/info.1
@@ -0,0 +1,230 @@
+.TH info 1 "7th December 1990"
+.SH NAME
+info \- GNU's hypertext system
+.SH SYNOPSIS
+.B info
+[
+.B \-\-option-name option-value
+]
+.B \menu-item...
+.SH COPYRIGHT
+.if n Copyright (C) 1989, 1993 Free Software Foundation, Inc.
+.if t Copyright \(co 1989, 1993 Free Software Foundation, Inc.
+.SH DESCRIPTION
+.LP
+The GNU project has a hypertext system called
+.I Info
+which allows the same source file to be either printed as a
+paper manual, or viewed using
+.B info.
+It is possible to use the
+.B info
+program from inside Emacs, or to use the stand-alone version described here.
+This manual page gives a brief summary of its capabilities.
+
+.SH OPTIONS
+.TP
+.B \-\-directory directory-path
+Add
+.B directory-path
+to the list of directory paths searched when
+.B info
+needs to find a file. You may issue
+.B \-\-directory
+multiple times.
+Alternatively, you may specify a value for the environment variable
+.B INFOPATH;
+if
+.B \-\-directory
+is not given, the value of
+.B INFOPATH
+is used. The value of
+.B INFOPATH
+is a colon separated list of directory names. If you do not supply either
+.B INFOPATH
+or
+.B \-\-directory-path,
+.B info
+uses a default path.
+.TP
+.B \-f filename
+Specify a particular
+.B info
+file to visit. By default,
+.B info
+visits
+the file
+.B dir;
+if you use this option,
+.B info
+will start with
+.B (FILENAME)Top
+as the first file and node.
+.TP
+.B \-n nodename
+Specify a particular node to visit in the initial file that
+.B info
+loads. This is especially useful in conjunction with
+.B \-\-file.
+You may specify
+.B \-\-node
+multiple times.
+.TP
+.B -o file
+Direct output to
+.B file
+instead of starting an interactive
+.B info
+session.
+.TP
+.B \-h
+Produce a relatively brief description of the available
+.B info
+options.
+.TP
+.B \-\-version
+Print the version information of
+.B info
+and exit.
+.TP
+.B menu-item
+.B info
+treats its remaining arguments as the names of menu items.
+The first argument is a menu item in the initial node visited,
+while the second argument is a menu item in the first argument's
+node. You can easily move to the node of your choice by
+specifying the menu names which describe the path to that node.
+For example,
+
+.B info emacs buffers
+
+first selects the menu item
+.B emacs
+in the node
+.B (dir)Top,
+and then selects the menu item
+.B buffers
+in the node
+.B (emacs)Top.
+.SH COMMANDS
+When in
+.B info
+the following commands are available:
+.TP
+.B h
+Invoke the Info tutorial.
+.TP
+.B ?
+Get a short summary of
+.B info
+commands.
+.TP
+.B h
+Select the
+.B info
+node from the main directory; this is much more complete than just
+using
+.B ?.
+.TP
+.B Ctrl-g
+Abort whatever you are doing.
+.TP
+.B Ctrl-l
+Redraw the screen.
+.PP
+Selecting other nodes:
+.TP
+.B n
+Move to the "next" node of this node.
+.TP
+.B p
+Move to the "previous" node of this node.
+.TP
+.B u
+Move to this node's "up" node.
+.TP
+.B m
+Pick a menu item specified by name. Picking a menu item causes another
+node to be selected. You do not need to type a complete nodename; if
+you type a few letters and then a space or tab
+.B info
+will will try to fill in the rest of the nodename. If you ask for further
+completion without typing any more characters you'll be given a list
+of possibilities; you can also get the list with
+.B ?.
+If you type a few characters and then hit return
+.B info
+will try to do a completion, and if it is ambigous use the first possibility.
+.TP
+.B f
+Follow a cross reference. You are asked for the name of the reference,
+using command completion as for
+.B m.
+.TP
+.B l
+Move to the last node you were at.
+.PP
+Moving within a node:
+.TP
+.B Space
+Scroll forward a page.
+.TP
+.B DEL
+Scroll backward a page.
+.TP
+.B b
+Go to the beginning of this node.
+.PP
+Advanced commands:
+.TP
+.B q
+Quit
+.B info.
+.TP
+.B 1
+Pick first item in node's menu.
+.TP
+.B 2 \-\- 5
+Pick second ... fifth item in node's menu.
+.TP
+.B g
+Move to node specified by name. You may include a filename as well,
+as
+.B (FILENAME)NODENAME.
+.TP
+.B s
+Search through this
+.B info
+file for a specified string, and select the node in which
+the next occurrence is found.
+.TP
+.B M-x print-node
+Pipe the contents of the current node through the command in the
+environment variable
+.B INFO_PRINT_COMMAND.
+If the variable does not exist, the node is simply piped to
+.B lpr.
+.SH ENVIRONMENT
+.TP
+.B INFOPATHS
+A colon-separated list of directories to search for
+.B info
+files. Used if
+.B \-\-directory
+is not given.
+.TP
+.B INFO_PRINT_COMMAND
+The command used for printing.
+.SH SEE ALSO
+.BR man (1)
+.\" .BR emacs (1)
+.SH AUTHOR
+.RS
+Brian Fox, Free Software Foundation
+.br
+bfox@ai.mit.edu
+.SH MANUAL AUTHOR
+.RS
+Robert Lupton; updated by Robert J. Chassell.
+.br
+rhl@astro.princeton.edu; bob@gnu.ai.mit.edu
diff --git a/gnu/usr.bin/texinfo/info/info.c b/gnu/usr.bin/texinfo/info/info.c
new file mode 100644
index 0000000..dfbffcc
--- /dev/null
+++ b/gnu/usr.bin/texinfo/info/info.c
@@ -0,0 +1,511 @@
+/* info.c -- Display nodes of Info files in multiple windows. */
+
+/* This file is part of GNU Info, a program for reading online documentation
+ stored in Info format.
+
+ Copyright (C) 1993 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ Written by Brian Fox (bfox@ai.mit.edu). */
+
+#include "info.h"
+#include "dribble.h"
+#include "getopt.h"
+
+/* The version numbers of this version of Info. */
+int info_major_version = 2;
+int info_minor_version = 10;
+int info_patch_level = 1;
+
+/* Non-zero means search all indices for APROPOS_SEARCH_STRING. */
+static int apropos_p = 0;
+
+/* Variable containing the string to search for when apropos_p is non-zero. */
+static char *apropos_search_string = (char *)NULL;
+
+/* Non-zero means print version info only. */
+static int print_version_p = 0;
+
+/* Non-zero means print a short description of the options. */
+static int print_help_p = 0;
+
+/* Array of the names of nodes that the user specified with "--node" on the
+ command line. */
+static char **user_nodenames = (char **)NULL;
+static int user_nodenames_index = 0;
+static int user_nodenames_slots = 0;
+
+/* String specifying the first file to load. This string can only be set
+ by the user specifying "--file" on the command line. */
+static char *user_filename = (char *)NULL;
+
+/* String specifying the name of the file to dump nodes to. This value is
+ filled if the user speficies "--output" on the command line. */
+static char *user_output_filename = (char *)NULL;
+
+/* Non-zero indicates that when "--output" is specified, all of the menu
+ items of the specified nodes (and their subnodes as well) should be
+ dumped in the order encountered. This basically can print a book. */
+int dump_subnodes = 0;
+
+/* Structure describing the options that Info accepts. We pass this structure
+ to getopt_long (). If you add or otherwise change this structure, you must
+ also change the string which follows it. */
+#define APROPOS_OPTION 1
+#define DRIBBLE_OPTION 2
+#define RESTORE_OPTION 3
+static struct option long_options[] = {
+ { "apropos", 1, 0, APROPOS_OPTION },
+ { "directory", 1, 0, 'd' },
+ { "node", 1, 0, 'n' },
+ { "file", 1, 0, 'f' },
+ { "subnodes", 0, &dump_subnodes, 1 },
+ { "output", 1, 0, 'o' },
+ { "help", 0, &print_help_p, 1 },
+ { "version", 0, &print_version_p, 1 },
+ { "dribble", 1, 0, DRIBBLE_OPTION },
+ { "restore", 1, 0, RESTORE_OPTION },
+ {NULL, 0, NULL, 0}
+};
+
+/* String describing the shorthand versions of the long options found above. */
+static char *short_options = "d:n:f:o:s";
+
+/* When non-zero, the Info window system has been initialized. */
+int info_windows_initialized_p = 0;
+
+/* Some "forward" declarations. */
+static void usage (), info_short_help (), remember_info_program_name ();
+
+
+/* **************************************************************** */
+/* */
+/* Main Entry Point to the Info Program */
+/* */
+/* **************************************************************** */
+
+int
+main (argc, argv)
+ int argc;
+ char **argv;
+{
+ int getopt_long_index; /* Index returned by getopt_long (). */
+ NODE *initial_node; /* First node loaded by Info. */
+
+#if defined (NeXT) && defined (NOTDEF)
+ malloc_debug (0x0ffffffff);
+#endif /* NeXT && NOTDEF */
+
+ remember_info_program_name (argv[0]);
+
+ while (1)
+ {
+ int option_character;
+
+ option_character = getopt_long
+ (argc, argv, short_options, long_options, &getopt_long_index);
+
+ /* getopt_long () returns EOF when there are no more long options. */
+ if (option_character == EOF)
+ break;
+
+ /* If this is a long option, then get the short version of it. */
+ if (option_character == 0 && long_options[getopt_long_index].flag == 0)
+ option_character = long_options[getopt_long_index].val;
+
+ /* Case on the option that we have received. */
+ switch (option_character)
+ {
+ case 0:
+ break;
+
+ /* User wants to add a directory. */
+ case 'd':
+ info_add_path (optarg, INFOPATH_PREPEND);
+ break;
+
+ /* User is specifying a particular node. */
+ case 'n':
+ add_pointer_to_array (optarg, user_nodenames_index, user_nodenames,
+ user_nodenames_slots, 10, char *);
+ break;
+
+ /* User is specifying a particular Info file. */
+ case 'f':
+ if (user_filename)
+ free (user_filename);
+
+ user_filename = savestring (optarg);
+ break;
+
+ /* User is specifying the name of a file to output to. */
+ case 'o':
+ if (user_output_filename)
+ free (user_output_filename);
+ user_output_filename = savestring (optarg);
+ break;
+
+ /* User is specifying that she wishes to dump the subnodes of
+ the node that she is dumping. */
+ case 's':
+ dump_subnodes = 1;
+ break;
+
+ /* User has specified a string to search all indices for. */
+ case APROPOS_OPTION:
+ apropos_p = 1;
+ maybe_free (apropos_search_string);
+ apropos_search_string = savestring (optarg);
+ break;
+
+ /* User has specified a dribble file to receive keystrokes. */
+ case DRIBBLE_OPTION:
+ close_dribble_file ();
+ open_dribble_file (optarg);
+ break;
+
+ /* User has specified an alternate input stream. */
+ case RESTORE_OPTION:
+ info_set_input_from_file (optarg);
+ break;
+
+ default:
+ usage ();
+ }
+ }
+
+ /* If the user specified --version, then show the version and exit. */
+ if (print_version_p)
+ {
+ printf ("GNU Info, Version %s.\n", version_string ());
+ exit (0);
+ }
+
+ /* If the `--help' option was present, show the help and exit. */
+ if (print_help_p)
+ {
+ info_short_help ();
+ exit (0);
+ }
+
+ /* If the user hasn't specified a path for Info files, default that path
+ now. */
+ if (!infopath)
+ {
+ char *path_from_env, *getenv ();
+
+ path_from_env = getenv ("INFOPATH");
+
+ if (path_from_env)
+ info_add_path (path_from_env);
+ else
+ info_add_path (DEFAULT_INFOPATH);
+ }
+
+ /* If the user specified a particular filename, add the path of that
+ file to the contents of INFOPATH. */
+ if (user_filename)
+ {
+ char *directory_name, *temp;
+
+ directory_name = savestring (user_filename);
+ temp = filename_non_directory (directory_name);
+
+ if (temp != directory_name)
+ {
+ *temp = 0;
+ info_add_path (directory_name, INFOPATH_PREPEND);
+ }
+
+ free (directory_name);
+ }
+
+ /* If the user wants to search every known index for a given string,
+ do that now, and report the results. */
+ if (apropos_p)
+ {
+ info_apropos (apropos_search_string);
+ exit (0);
+ }
+
+ /* Get the initial Info node. It is either "(dir)Top", or what the user
+ specifed with values in user_filename and user_nodenames. */
+ if (user_nodenames)
+ initial_node = info_get_node (user_filename, user_nodenames[0]);
+ else
+ initial_node = info_get_node (user_filename, (char *)NULL);
+
+ /* If we couldn't get the initial node, this user is in trouble. */
+ if (!initial_node)
+ {
+ if (info_recent_file_error)
+ info_error (info_recent_file_error);
+ else
+ info_error
+ (CANT_FIND_NODE, user_nodenames ? user_nodenames[0] : "Top");
+ exit (1);
+ }
+
+ /* Special cases for when the user specifies multiple nodes. If we are
+ dumping to an output file, dump all of the nodes specified. Otherwise,
+ attempt to create enough windows to handle the nodes that this user wants
+ displayed. */
+ if (user_nodenames_index > 1)
+ {
+ free (initial_node);
+
+ if (user_output_filename)
+ dump_nodes_to_file
+ (user_filename, user_nodenames, user_output_filename, dump_subnodes);
+ else
+ begin_multiple_window_info_session (user_filename, user_nodenames);
+
+ exit (0);
+ }
+
+ /* If there are arguments remaining, they are the names of menu items
+ in sequential info files starting from the first one loaded. That
+ file name is either "dir", or the contents of user_filename if one
+ was specified. */
+ while (optind != argc)
+ {
+ REFERENCE **menu;
+ REFERENCE *entry;
+ NODE *node;
+ char *arg;
+
+ /* Remember the name of the menu entry we want. */
+ arg = argv[optind++];
+
+ /* Build and return a list of the menu items in this node. */
+ menu = info_menu_of_node (initial_node);
+
+ /* If there wasn't a menu item in this node, stop here, but let
+ the user continue to use Info. Perhaps they wanted this node
+ and didn't realize it. */
+ if (!menu)
+ {
+ begin_info_session_with_error
+ (initial_node, "There is no menu in this node.");
+ exit (0);
+ }
+
+ /* Find the specified menu item. */
+ entry = info_get_labeled_reference (arg, menu);
+
+ /* If the item wasn't found, search the list sloppily. Perhaps this
+ user typed "buffer" when they really meant "Buffers". */
+ if (!entry)
+ {
+ register int i;
+
+ for (i = 0; entry = menu[i]; i++)
+ if (strnicmp (entry->label, arg, strlen (arg)) == 0)
+ break;
+ }
+
+ /* If we failed to find the reference, start Info with the current
+ node anyway. It is probably a misspelling. */
+ if (!entry)
+ {
+ char *error_message = "There is no menu item \"%s\" in this node.";
+
+ info_free_references (menu);
+
+ /* If we were supposed to dump this node, complain. */
+ if (user_output_filename)
+ info_error (error_message, arg);
+ else
+ begin_info_session_with_error (initial_node, error_message, arg);
+
+ exit (0);
+ }
+
+ /* We have found the reference that the user specified. Clean it
+ up a little bit. */
+ if (!entry->filename)
+ {
+ if (initial_node->parent)
+ entry->filename = savestring (initial_node->parent);
+ else
+ entry->filename = savestring (initial_node->filename);
+ }
+
+ /* Find this node. If we can find it, then turn the initial_node
+ into this one. If we cannot find it, try using the label of the
+ entry as a file (i.e., "(LABEL)Top"). Otherwise the Info file is
+ malformed in some way, and we will just use the current value of
+ initial node. */
+ node = info_get_node (entry->filename, entry->nodename);
+
+ if (!node && entry->nodename &&
+ (strcmp (entry->label, entry->nodename) == 0))
+ node = info_get_node (entry->label, "Top");
+
+ if (node)
+ {
+ free (initial_node);
+ initial_node = node;
+ info_free_references (menu);
+ }
+ else
+ {
+ char *temp = savestring (entry->label);
+ char *error_message;
+
+ error_message = "Unable to find the node referenced by \"%s\".";
+
+ info_free_references (menu);
+
+ /* If we were trying to dump the node, then give up. Otherwise,
+ start the session with an error message. */
+ if (user_output_filename)
+ info_error (error_message, temp);
+ else
+ begin_info_session_with_error (initial_node, error_message, temp);
+
+ exit (0);
+ }
+ }
+
+ /* If the user specified that this node should be output, then do that
+ now. Otherwise, start the Info session with this node. */
+ if (user_output_filename)
+ dump_node_to_file (initial_node, user_output_filename, dump_subnodes);
+ else
+ begin_info_session (initial_node);
+
+ exit (0);
+}
+
+/* Return a string describing the current version of Info. */
+char *
+version_string ()
+{
+ static char *vstring = (char *)NULL;
+
+ if (!vstring)
+ {
+ vstring = (char *)xmalloc (50);
+ sprintf (vstring, "%d.%d", info_major_version, info_minor_version);
+ if (info_patch_level)
+ sprintf (vstring + strlen (vstring), "-p%d", info_patch_level);
+ }
+ return (vstring);
+}
+
+/* **************************************************************** */
+/* */
+/* Error Handling for Info */
+/* */
+/* **************************************************************** */
+
+static char *program_name = (char *)NULL;
+
+static void
+remember_info_program_name (fullpath)
+ char *fullpath;
+{
+ char *filename;
+
+ filename = filename_non_directory (fullpath);
+ program_name = savestring (filename);
+}
+
+/* Non-zero if an error has been signalled. */
+int info_error_was_printed = 0;
+
+/* Non-zero means ring terminal bell on errors. */
+int info_error_rings_bell_p = 1;
+
+/* Print FORMAT with ARG1 and ARG2. If the window system was initialized,
+ then the message is printed in the echo area. Otherwise, a message is
+ output to stderr. */
+void
+info_error (format, arg1, arg2)
+ char *format;
+ void *arg1, *arg2;
+{
+ info_error_was_printed = 1;
+
+ if (!info_windows_initialized_p || display_inhibited)
+ {
+ fprintf (stderr, "%s: ", program_name);
+ fprintf (stderr, format, arg1, arg2);
+ fprintf (stderr, "\n");
+ fflush (stderr);
+ }
+ else
+ {
+ if (!echo_area_is_active)
+ {
+ if (info_error_rings_bell_p)
+ terminal_ring_bell ();
+ window_message_in_echo_area (format, arg1, arg2);
+ }
+ else
+ {
+ NODE *temp;
+
+ temp = build_message_node (format, arg1, arg2);
+ if (info_error_rings_bell_p)
+ terminal_ring_bell ();
+ inform_in_echo_area (temp->contents);
+ free (temp->contents);
+ free (temp);
+ }
+ }
+}
+
+/* Produce a very brief descripton of the available options and exit with
+ an error. */
+static void
+usage ()
+{
+ fprintf (stderr,"%s\n%s\n%s\n%s\n%s\n",
+"Usage: info [-d dir-path] [-f info-file] [-o output-file] [-n node-name]...",
+" [--directory dir-path] [--file info-file] [--node node-name]...",
+" [--help] [--output output-file] [--subnodes] [--version]",
+" [--dribble dribble-file] [--restore from-file]",
+" [menu-selection ...]");
+ exit (1);
+}
+
+/* Produce a scaled down description of the available options to Info. */
+static void
+info_short_help ()
+{
+ printf ("%s", "\
+Here is a quick description of Info's options. For a more complete\n\
+description of how to use Info, type `info info options'.\n\
+\n\
+ --directory DIR Add DIR to INFOPATH.\n\
+ --file FILENAME Specify Info file to visit.\n\
+ --node NODENAME Specify nodes in first visited Info file.\n\
+ --output FILENAME Output selected nodes to FILENAME.\n\
+ --dribble FILENAME Remember user keystrokes in FILENAME.\n\
+ --restore FILENAME Read initial keystrokes from FILENAME.\n\
+ --subnodes Recursively output menu items.\n\
+ --help Get this help message.\n\
+ --version Display Info's version information.\n\
+\n\
+Remaining arguments to Info are treated as the names of menu\n\
+items in the initial node visited. You can easily move to the\n\
+node of your choice by specifying the menu names which describe\n\
+the path to that node. For example, `info emacs buffers'.\n");
+
+ exit (0);
+}
diff --git a/gnu/usr.bin/texinfo/info/info.h b/gnu/usr.bin/texinfo/info/info.h
new file mode 100644
index 0000000..09e40c2
--- /dev/null
+++ b/gnu/usr.bin/texinfo/info/info.h
@@ -0,0 +1,96 @@
+/* info.h -- Header file which includes all of the other headers. */
+
+/* This file is part of GNU Info, a program for reading online documentation
+ stored in Info format.
+
+ Copyright (C) 1993 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ Written by Brian Fox (bfox@ai.mit.edu). */
+
+#ifndef _INFO_H_
+#define _INFO_H_
+
+#include <stdio.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include "filesys.h"
+#include "display.h"
+#include "session.h"
+#include "echo_area.h"
+#include "doc.h"
+#include "footnotes.h"
+#include "gc.h"
+
+/* A structure associating the nodes visited in a particular window. */
+typedef struct {
+ WINDOW *window; /* The window that this list is attached to. */
+ NODE **nodes; /* Array of nodes visited in this window. */
+ int *pagetops; /* For each node in NODES, the pagetop. */
+ long *points; /* For each node in NODES, the point. */
+ int current; /* Index in NODES of the current node. */
+ int nodes_index; /* Index where to add the next node. */
+ int nodes_slots; /* Number of slots allocated to NODES. */
+} INFO_WINDOW;
+
+/* Array of structures describing for each window which nodes have been
+ visited in that window. */
+extern INFO_WINDOW **info_windows;
+
+/* For handling errors. If you initialize the window system, you should
+ also set info_windows_initialized_p to non-zero. It is used by the
+ info_error () function to determine how to format and output errors. */
+extern int info_windows_initialized_p;
+
+/* Non-zero if an error message has been printed. */
+extern int info_error_was_printed;
+
+/* Non-zero means ring terminal bell on errors. */
+extern int info_error_rings_bell_p;
+
+/* Print FORMAT with ARG1 and ARG2. If the window system was initialized,
+ then the message is printed in the echo area. Otherwise, a message is
+ output to stderr. */
+extern void info_error ();
+
+/* The version numbers of Info. */
+extern int info_major_version, info_minor_version, info_patch_level;
+
+/* How to get the version string for this version of Info. Returns
+ something similar to "2.9". */
+extern char *version_string ();
+
+/* Error message defines. */
+#define CANT_FIND_NODE "Cannot find the node \"%s\"."
+#define CANT_FILE_NODE "Cannot find the node \"(%s)%s\"."
+#define CANT_FIND_WIND "Cannot find a window!"
+#define CANT_FIND_POINT "Point doesn't appear within this window's node!"
+#define CANT_KILL_LAST "Cannot delete the last window."
+#define NO_MENU_NODE "No menu in this node."
+#define NO_FOOT_NODE "No footnotes in this node."
+#define NO_XREF_NODE "No cross references in this node."
+#define NO_POINTER "No \"%s\" pointer for this node."
+#define UNKNOWN_COMMAND "Unknown Info command `%c'. `?' for help."
+#define TERM_TOO_DUMB "Terminal type \"%s\" is not smart enough to run Info."
+#define AT_NODE_BOTTOM "You are already at the last page of this node."
+#define AT_NODE_TOP "You are already at the first page of this node."
+#define ONE_WINDOW "Only one window."
+#define WIN_TOO_SMALL "Resulting window would be too small."
+#define CANT_MAKE_HELP \
+"There isn't enough room to make a help window. Please delete a window."
+
+#endif /* !_INFO_H_ */
diff --git a/gnu/usr.bin/texinfo/info/infodoc.c b/gnu/usr.bin/texinfo/info/infodoc.c
new file mode 100644
index 0000000..d92d40b
--- /dev/null
+++ b/gnu/usr.bin/texinfo/info/infodoc.c
@@ -0,0 +1,689 @@
+/* infohelp.c -- Functions which build documentation nodes. */
+
+/* This file is part of GNU Info, a program for reading online documentation
+ stored in Info format.
+
+ Copyright (C) 1993 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ Written by Brian Fox (bfox@ai.mit.edu). */
+
+#include "info.h"
+
+/* **************************************************************** */
+/* */
+/* Info Help Windows */
+/* */
+/* **************************************************************** */
+
+/* The name of the node used in the help window. */
+static char *info_help_nodename = "*Info Help*";
+
+/* A node containing printed key bindings and their documentation. */
+static NODE *internal_info_help_node = (NODE *)NULL;
+
+/* The static text which appears in the internal info help node. */
+static char *info_internal_help_text[] = {
+ "Basic Commands in Info Windows",
+ "******************************",
+ "",
+ " h Invoke the Info tutorial.",
+ "",
+ "Selecting other nodes:",
+ "----------------------",
+ " n Move to the \"next\" node of this node.",
+ " p Move to the \"previous\" node of this node.",
+ " u Move \"up\" from this node.",
+ " m Pick menu item specified by name.",
+ " Picking a menu item causes another node to be selected.",
+ " f Follow a cross reference. Reads name of reference.",
+ " l Move to the last node seen in this window.",
+ " d Move to the `directory' node. Equivalent to `g(DIR)'.",
+ "",
+ "Moving within a node:",
+ "---------------------",
+ " SPC Scroll forward a page.",
+ " DEL Scroll backward a page.",
+ " b Go to the beginning of this node.",
+ " e Go to the end of this node.",
+ "",
+ "\"Advanced\" commands:",
+ "--------------------",
+ " q Quit Info.",
+ " 1 Pick first item in node's menu.",
+ " 2-9 Pick second ... ninth item in node's menu.",
+ " 0 Pick last item in node's menu.",
+ " g Move to node specified by name.",
+ " You may include a filename as well, as in (FILENAME)NODENAME.",
+ " s Search through this Info file for a specified string,",
+ " and select the node in which the next occurrence is found.",
+ (char *)NULL
+};
+
+void
+dump_map_to_message_buffer (prefix, map)
+ char *prefix;
+ Keymap map;
+{
+ register int i;
+
+ for (i = 0; i < 256; i++)
+ {
+ if (map[i].type == ISKMAP)
+ {
+ char *new_prefix, *keyname;
+
+ keyname = pretty_keyname (i);
+ new_prefix = (char *)
+ xmalloc (3 + strlen (prefix) + strlen (keyname));
+ sprintf (new_prefix, "%s%s%s ", prefix, *prefix ? " " : "", keyname);
+
+ dump_map_to_message_buffer (new_prefix, (Keymap)map[i].function);
+ free (new_prefix);
+ }
+ else if (map[i].function)
+ {
+ register int last;
+ char *doc, *name;
+
+ doc = function_documentation (map[i].function);
+ name = function_name (map[i].function);
+
+ if (!*doc)
+ continue;
+
+ /* Find out if there is a series of identical functions, as in
+ ea_insert (). */
+ for (last = i + 1; last < 256; last++)
+ if ((map[last].type != ISFUNC) ||
+ (map[last].function != map[i].function))
+ break;
+
+ if (last - 1 != i)
+ {
+ printf_to_message_buffer
+ ("%s%s .. ", prefix, pretty_keyname (i));
+ printf_to_message_buffer
+ ("%s%s\t", prefix, pretty_keyname (last - 1));
+ i = last - 1;
+ }
+ else
+ printf_to_message_buffer ("%s%s\t", prefix, pretty_keyname (i));
+
+#if defined (NAMED_FUNCTIONS)
+ /* Print the name of the function, and some padding before the
+ documentation string is printed. */
+ {
+ int length_so_far;
+ int desired_doc_start = 40; /* Must be multiple of 8. */
+
+ printf_to_message_buffer ("(%s)", name);
+ length_so_far = message_buffer_length_this_line ();
+
+ if ((desired_doc_start + strlen (doc)) >= the_screen->width)
+ printf_to_message_buffer ("\n ");
+ else
+ {
+ while (length_so_far < desired_doc_start)
+ {
+ printf_to_message_buffer ("\t");
+ length_so_far += character_width ('\t', length_so_far);
+ }
+ }
+ }
+#endif /* NAMED_FUNCTIONS */
+ printf_to_message_buffer ("%s\n", doc);
+ }
+ }
+}
+
+/* How to create internal_info_help_node. */
+static void
+create_internal_info_help_node ()
+{
+ register int i;
+
+ initialize_message_buffer ();
+
+ for (i = 0; info_internal_help_text[i]; i++)
+ printf_to_message_buffer ("%s\n", info_internal_help_text[i]);
+
+ printf_to_message_buffer ("---------------------\n\n");
+ printf_to_message_buffer ("The current search path is:\n");
+ printf_to_message_buffer (" \"%s\"\n", infopath);
+ printf_to_message_buffer ("---------------------\n\n");
+ printf_to_message_buffer ("Commands available in Info windows:\n\n");
+ dump_map_to_message_buffer ("", info_keymap);
+ printf_to_message_buffer ("---------------------\n\n");
+ printf_to_message_buffer ("Commands available in the echo area:\n\n");
+ dump_map_to_message_buffer ("", echo_area_keymap);
+
+ {
+ char *message;
+
+ message = replace_in_documentation
+ ("--- Use `\\[history-node]' or `\\[kill-node]' to exit ---\n");
+ printf_to_message_buffer ("%s", message);
+ }
+
+ internal_info_help_node = message_buffer_to_node ();
+ add_gcable_pointer (internal_info_help_node->contents);
+ name_internal_node (internal_info_help_node, info_help_nodename);
+
+ /* Even though this is an internal node, we don't want the window
+ system to treat it specially. So we turn off the internalness
+ of it here. */
+ internal_info_help_node->flags &= ~N_IsInternal;
+}
+
+/* Return a window which is the window showing help in this Info. */
+static WINDOW *
+info_find_or_create_help_window ()
+{
+ WINDOW *help_window;
+
+ help_window = get_internal_info_window (info_help_nodename);
+
+ /* If we couldn't find the help window, then make it. */
+ if (!help_window)
+ {
+ WINDOW *window, *eligible = (WINDOW *)NULL;
+ int max = 0;
+
+ for (window = windows; window; window = window->next)
+ {
+ if (window->height > max)
+ {
+ max = window->height;
+ eligible = window;
+ }
+ }
+
+ if (!eligible)
+ return ((WINDOW *)NULL);
+ else
+ {
+ /* Make a new node containing the help text. Split the largest
+ window into 2 windows, and show the help text in that window. */
+ if (!internal_info_help_node)
+ create_internal_info_help_node ();
+
+ if (eligible->height > 30)
+ {
+ active_window = eligible;
+ help_window = window_make_window (internal_info_help_node);
+ }
+ else
+ {
+ set_remembered_pagetop_and_point (active_window);
+ window_set_node_of_window
+ (active_window, internal_info_help_node);
+ help_window = active_window;
+ }
+
+ remember_window_and_node (help_window, help_window->node);
+ }
+ }
+ return (help_window);
+}
+
+/* Create or move to the help window. */
+DECLARE_INFO_COMMAND (info_get_help_window, "Display help message")
+{
+ WINDOW *help_window;
+
+ help_window = info_find_or_create_help_window ();
+ if (help_window)
+ {
+ active_window = help_window;
+ active_window->flags |= W_UpdateWindow;
+ }
+ else
+ {
+ info_error (CANT_MAKE_HELP);
+ }
+}
+
+/* Show the Info help node. This means that the "info" file is installed
+ where it can easily be found on your system. */
+DECLARE_INFO_COMMAND (info_get_info_help_node, "Visit Info node `(info)Help'")
+{
+ NODE *node;
+ char *nodename;
+
+ /* If there is a window on the screen showing the node "(info)Help" or
+ the node "(info)Help-Small-Screen", simply select that window. */
+ {
+ WINDOW *win;
+
+ for (win = windows; win; win = win->next)
+ {
+ if (win->node && win->node->filename &&
+ (stricmp
+ (filename_non_directory (win->node->filename), "info") == 0) &&
+ ((strcmp (win->node->nodename, "Help") == 0) ||
+ (strcmp (win->node->nodename, "Help-Small-Screen") == 0)))
+ {
+ active_window = win;
+ return;
+ }
+ }
+ }
+
+ /* If the current window is small, show the small screen help. */
+ if (active_window->height < 24)
+ nodename = "Help-Small-Screen";
+ else
+ nodename = "Help";
+
+ /* Try to get the info file for Info. */
+ node = info_get_node ("Info", nodename);
+
+ if (!node)
+ {
+ if (info_recent_file_error)
+ info_error (info_recent_file_error);
+ else
+ info_error (CANT_FILE_NODE, "Info", nodename);
+ }
+ else
+ {
+ /* If the current window is very large (greater than 45 lines),
+ then split it and show the help node in another window.
+ Otherwise, use the current window. */
+
+ if (active_window->height > 45)
+ active_window = window_make_window (node);
+ else
+ {
+ set_remembered_pagetop_and_point (active_window);
+ window_set_node_of_window (active_window, node);
+ }
+
+ remember_window_and_node (active_window, node);
+ }
+}
+
+/* **************************************************************** */
+/* */
+/* Groveling Info Keymaps and Docs */
+/* */
+/* **************************************************************** */
+
+/* Return the documentation associated with the Info command FUNCTION. */
+char *
+function_documentation (function)
+ VFunction *function;
+{
+ register int i;
+
+ for (i = 0; function_doc_array[i].func; i++)
+ if (function == function_doc_array[i].func)
+ break;
+
+ return (replace_in_documentation (function_doc_array[i].doc));
+}
+
+#if defined (NAMED_FUNCTIONS)
+/* Return the user-visible name of the function associated with the
+ Info command FUNCTION. */
+char *
+function_name (function)
+
+ VFunction *function;
+{
+ register int i;
+
+ for (i = 0; function_doc_array[i].func; i++)
+ if (function == function_doc_array[i].func)
+ break;
+
+ return (function_doc_array[i].func_name);
+}
+
+/* Return a pointer to the function named NAME. */
+VFunction *
+named_function (name)
+ char *name;
+{
+ register int i;
+
+ for (i = 0; function_doc_array[i].func; i++)
+ if (strcmp (function_doc_array[i].func_name, name) == 0)
+ break;
+
+ return (function_doc_array[i].func);
+}
+#endif /* NAMED_FUNCTIONS */
+
+/* Return the documentation associated with KEY in MAP. */
+char *
+key_documentation (key, map)
+ char key;
+ Keymap map;
+{
+ VFunction *function = map[key].function;
+
+ if (function)
+ return (function_documentation (function));
+ else
+ return ((char *)NULL);
+}
+
+DECLARE_INFO_COMMAND (describe_key, "Print documentation for KEY")
+{
+ char keyname[50];
+ int keyname_index = 0;
+ unsigned char keystroke;
+ char *rep;
+ Keymap map;
+
+ keyname[0] = '\0';
+ map = window->keymap;
+
+ while (1)
+ {
+ message_in_echo_area ("Describe key: %s", keyname);
+ keystroke = info_get_input_char ();
+ unmessage_in_echo_area ();
+
+ if (Meta_p (keystroke) && (!ISO_Latin_p || key < 160))
+ {
+ if (map[ESC].type != ISKMAP)
+ {
+ window_message_in_echo_area
+ ("ESC %s is undefined.", pretty_keyname (UnMeta (keystroke)));
+ return;
+ }
+
+ strcpy (keyname + keyname_index, "ESC ");
+ keyname_index = strlen (keyname);
+ keystroke = UnMeta (keystroke);
+ map = (Keymap)map[ESC].function;
+ }
+
+ /* Add the printed representation of KEYSTROKE to our keyname. */
+ rep = pretty_keyname (keystroke);
+ strcpy (keyname + keyname_index, rep);
+ keyname_index = strlen (keyname);
+
+ if (map[keystroke].function == (VFunction *)NULL)
+ {
+ message_in_echo_area ("%s is undefined.", keyname);
+ return;
+ }
+ else if (map[keystroke].type == ISKMAP)
+ {
+ map = (Keymap)map[keystroke].function;
+ strcat (keyname, " ");
+ keyname_index = strlen (keyname);
+ continue;
+ }
+ else
+ {
+ char *message, *fundoc, *funname = "";
+
+#if defined (NAMED_FUNCTIONS)
+ funname = function_name (map[keystroke].function);
+#endif /* NAMED_FUNCTIONS */
+
+ fundoc = function_documentation (map[keystroke].function);
+
+ message = (char *)xmalloc
+ (10 + strlen (keyname) + strlen (fundoc) + strlen (funname));
+
+#if defined (NAMED_FUNCTIONS)
+ sprintf (message, "%s (%s): %s.", keyname, funname, fundoc);
+#else
+ sprintf (message, "%s is defined to %s.", keyname, fundoc);
+#endif /* !NAMED_FUNCTIONS */
+
+ window_message_in_echo_area ("%s", message);
+ free (message);
+ break;
+ }
+ }
+}
+
+/* How to get the pretty printable name of a character. */
+static char rep_buffer[30];
+
+char *
+pretty_keyname (key)
+ unsigned char key;
+{
+ char *rep;
+
+ if (Meta_p (key))
+ {
+ char temp[20];
+
+ rep = pretty_keyname (UnMeta (key));
+
+ sprintf (temp, "ESC %s", rep);
+ strcpy (rep_buffer, temp);
+ rep = rep_buffer;
+ }
+ else if (Control_p (key))
+ {
+ switch (key)
+ {
+ case '\n': rep = "LFD"; break;
+ case '\t': rep = "TAB"; break;
+ case '\r': rep = "RET"; break;
+ case ESC: rep = "ESC"; break;
+
+ default:
+ sprintf (rep_buffer, "C-%c", UnControl (key));
+ rep = rep_buffer;
+ }
+ }
+ else
+ {
+ switch (key)
+ {
+ case ' ': rep = "SPC"; break;
+ case DEL: rep = "DEL"; break;
+ default:
+ rep_buffer[0] = key;
+ rep_buffer[1] = '\0';
+ rep = rep_buffer;
+ }
+ }
+ return (rep);
+}
+
+/* Replace the names of functions with the key that invokes them. */
+static char *where_is (), *where_is_internal ();
+
+char *
+replace_in_documentation (string)
+ char *string;
+{
+ register int i, start, next;
+ static char *result = (char *)NULL;
+
+ maybe_free (result);
+ result = (char *)xmalloc (1 + strlen (string));
+
+ i = next = start = 0;
+
+ /* Skip to the beginning of a replaceable function. */
+ for (i = start; string[i]; i++)
+ {
+ /* Is this the start of a replaceable function name? */
+ if (string[i] == '\\' && string[i + 1] == '[')
+ {
+ char *fun_name, *rep;
+ VFunction *function;
+
+ /* Copy in the old text. */
+ strncpy (result + next, string + start, i - start);
+ next += (i - start);
+ start = i + 2;
+
+ /* Move to the end of the function name. */
+ for (i = start; string[i] && (string[i] != ']'); i++);
+
+ fun_name = (char *)xmalloc (1 + i - start);
+ strncpy (fun_name, string + start, i - start);
+ fun_name[i - start] = '\0';
+
+ /* Find a key which invokes this function in the info_keymap. */
+ function = named_function (fun_name);
+
+ /* If the internal documentation string fails, there is a
+ serious problem with the associated command's documentation.
+ We croak so that it can be fixed immediately. */
+ if (!function)
+ abort ();
+
+ rep = where_is (info_keymap, function);
+ strcpy (result + next, rep);
+ next = strlen (result);
+
+ start = i;
+ if (string[i])
+ start++;
+ }
+ }
+ strcpy (result + next, string + start);
+ return (result);
+}
+
+/* Return a string of characters which could be typed from the keymap
+ MAP to invoke FUNCTION. */
+static char *where_is_rep = (char *)NULL;
+static int where_is_rep_index = 0;
+static int where_is_rep_size = 0;
+
+static char *
+where_is (map, function)
+ Keymap map;
+ VFunction *function;
+{
+ char *rep;
+
+ if (!where_is_rep_size)
+ where_is_rep = (char *)xmalloc (where_is_rep_size = 100);
+ where_is_rep_index = 0;
+
+ rep = where_is_internal (map, function);
+
+ /* If it couldn't be found, return "M-x Foo". */
+ if (!rep)
+ {
+ char *name;
+
+ name = function_name (function);
+
+ if (name)
+ sprintf (where_is_rep, "M-x %s", name);
+
+ rep = where_is_rep;
+ }
+ return (rep);
+}
+
+/* Return the printed rep of FUNCTION as found in MAP, or NULL. */
+static char *
+where_is_internal (map, function)
+ Keymap map;
+ VFunction *function;
+{
+ register int i;
+
+ /* If the function is directly invokable in MAP, return the representation
+ of that keystroke. */
+ for (i = 0; i < 256; i++)
+ if ((map[i].type == ISFUNC) && map[i].function == function)
+ {
+ sprintf (where_is_rep + where_is_rep_index, "%s", pretty_keyname (i));
+ return (where_is_rep);
+ }
+
+ /* Okay, search subsequent maps for this function. */
+ for (i = 0; i < 256; i++)
+ {
+ if (map[i].type == ISKMAP)
+ {
+ int saved_index = where_is_rep_index;
+ char *rep;
+
+ sprintf (where_is_rep + where_is_rep_index, "%s ",
+ pretty_keyname (i));
+
+ where_is_rep_index = strlen (where_is_rep);
+ rep = where_is_internal ((Keymap)map[i].function, function);
+
+ if (rep)
+ return (where_is_rep);
+
+ where_is_rep_index = saved_index;
+ }
+ }
+
+ return ((char *)NULL);
+}
+
+extern char *read_function_name ();
+
+DECLARE_INFO_COMMAND (info_where_is,
+ "Show what to type to execute a given command")
+{
+ char *command_name;
+
+ command_name = read_function_name ("Where is command: ", window);
+
+ if (!command_name)
+ {
+ info_abort_key (active_window, count, key);
+ return;
+ }
+
+ if (*command_name)
+ {
+ VFunction *function;
+
+ function = named_function (command_name);
+
+ if (function)
+ {
+ char *location;
+
+ location = where_is (active_window->keymap, function);
+
+ if (!location)
+ {
+ info_error ("`%s' is not on any keys", command_name);
+ }
+ else
+ {
+ if (strncmp (location, "M-x ", 4) == 0)
+ window_message_in_echo_area
+ ("%s can only be invoked via %s.", command_name, location);
+ else
+ window_message_in_echo_area
+ ("%s can be invoked via %s.", command_name, location);
+ }
+ }
+ else
+ info_error ("There is no function named `%s'", command_name);
+ }
+
+ free (command_name);
+}
+
diff --git a/gnu/usr.bin/texinfo/info/infomap.c b/gnu/usr.bin/texinfo/info/infomap.c
new file mode 100644
index 0000000..26906c5
--- /dev/null
+++ b/gnu/usr.bin/texinfo/info/infomap.c
@@ -0,0 +1,328 @@
+/* infomap.c -- Keymaps for Info. */
+
+/* This file is part of GNU Info, a program for reading online documentation
+ stored in Info format.
+
+ Copyright (C) 1993 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ Written by Brian Fox (bfox@ai.mit.edu). */
+
+#include "stdio.h"
+#include "ctype.h"
+#include "infomap.h"
+#include "funs.h"
+#include "info.h"
+
+static void add_function_key(char *, VFunction *, Keymap);
+
+extern char *term_ku, *term_kd, *term_kr, *term_kl;
+extern char *term_kP, *term_kN, *term_kh, *term_kH;
+
+/* Return a new keymap which has all the uppercase letters mapped to run
+ the function info_do_lowercase_version (). */
+Keymap
+keymap_make_keymap ()
+{
+ register int i;
+ Keymap keymap;
+
+ keymap = (Keymap)xmalloc (256 * sizeof (KEYMAP_ENTRY));
+
+ for (i = 0; i < 256; i++)
+ {
+ keymap[i].type = ISFUNC;
+ keymap[i].function = (VFunction *)NULL;
+ }
+
+ for (i = 'A'; i < ('Z' + 1); i++)
+ {
+ keymap[i].type = ISFUNC;
+ keymap[i].function = info_do_lowercase_version;
+ }
+
+ return (keymap);
+}
+
+/* Return a new keymap which is a copy of MAP. */
+Keymap
+keymap_copy_keymap (map)
+ Keymap map;
+{
+ register int i;
+ Keymap keymap;
+
+ keymap = keymap_make_keymap ();
+
+ for (i = 0; i < 256; i++)
+ {
+ keymap[i].type = map[i].type;
+ keymap[i].function = map[i].function;
+ }
+ return (keymap);
+}
+
+/* Free the keymap and it's descendents. */
+void
+keymap_discard_keymap (map)
+ Keymap (map);
+{
+ register int i;
+
+ if (!map)
+ return;
+
+ for (i = 0; i < 256; i++)
+ {
+ switch (map[i].type)
+ {
+ case ISFUNC:
+ break;
+
+ case ISKMAP:
+ keymap_discard_keymap ((Keymap)map[i].function);
+ break;
+
+ }
+ }
+}
+
+/* Initialize the standard info keymaps. */
+
+Keymap info_keymap = (Keymap)NULL;
+Keymap echo_area_keymap = (Keymap)NULL;
+
+void
+initialize_info_keymaps ()
+{
+ register int i;
+ Keymap map;
+
+ if (!info_keymap)
+ {
+ info_keymap = keymap_make_keymap ();
+ info_keymap[ESC].type = ISKMAP;
+ info_keymap[ESC].function = (VFunction *)keymap_make_keymap ();
+ info_keymap[Control ('x')].type = ISKMAP;
+ info_keymap[Control ('x')].function = (VFunction *)keymap_make_keymap ();
+ echo_area_keymap = keymap_make_keymap ();
+ echo_area_keymap[ESC].type = ISKMAP;
+ echo_area_keymap[ESC].function = (VFunction *)keymap_make_keymap ();
+ echo_area_keymap[Control ('x')].type = ISKMAP;
+ echo_area_keymap[Control ('x')].function =
+ (VFunction *)keymap_make_keymap ();
+ }
+
+ /* Bind numeric arg functions for both echo area and info window maps. */
+ for (i = '0'; i < '9' + 1; i++)
+ {
+ ((Keymap) info_keymap[ESC].function)[i].function =
+ ((Keymap) echo_area_keymap[ESC].function)[i].function =
+ info_add_digit_to_numeric_arg;
+ }
+ ((Keymap) info_keymap[ESC].function)['-'].function =
+ ((Keymap) echo_area_keymap[ESC].function)['-'].function =
+ info_add_digit_to_numeric_arg;
+
+ /* Bind the echo area routines. */
+ map = echo_area_keymap;
+
+ /* Bind the echo area insert routines. */
+ for (i = 0; i < 160; i++)
+ if (isprint (i))
+ map[i].function = ea_insert;
+
+ map[Control ('a')].function = ea_beg_of_line;
+ map[Control ('b')].function = ea_backward;
+ map[Control ('d')].function = ea_delete;
+ map[Control ('e')].function = ea_end_of_line;
+ map[Control ('f')].function = ea_forward;
+ map[Control ('g')].function = ea_abort;
+ map[Control ('h')].function = ea_rubout;
+ map[Control ('k')].function = ea_kill_line;
+ map[Control ('l')].function = info_redraw_display;
+ map[Control ('q')].function = ea_quoted_insert;
+ map[Control ('t')].function = ea_transpose_chars;
+ map[Control ('u')].function = info_universal_argument;
+ map[Control ('y')].function = ea_yank;
+
+ map[LFD].function = ea_newline;
+ map[RET].function = ea_newline;
+ map[SPC].function = ea_complete;
+ map[TAB].function = ea_complete;
+ map['?'].function = ea_possible_completions;
+ map[DEL].function = ea_rubout;
+
+ /* Bind the echo area ESC keymap. */
+ map = (Keymap)echo_area_keymap[ESC].function;
+
+ map[Control ('g')].function = ea_abort;
+ map[Control ('v')].function = ea_scroll_completions_window;
+ map['b'].function = ea_backward_word;
+ map['d'].function = ea_kill_word;
+ map['f'].function = ea_forward_word;
+#if defined (NAMED_FUNCTIONS)
+ /* map['x'].function = info_execute_command; */
+#endif /* NAMED_FUNCTIONS */
+ map['y'].function = ea_yank_pop;
+ map['?'].function = ea_possible_completions;
+ map[TAB].function = ea_tab_insert;
+ map[DEL].function = ea_backward_kill_word;
+
+ /* Bind the echo area Control-x keymap. */
+ map = (Keymap)echo_area_keymap[Control ('x')].function;
+
+ map['o'].function = info_next_window;
+ map[DEL].function = ea_backward_kill_line;
+
+ /* Bind commands for Info window keymaps. */
+ map = info_keymap;
+ map[TAB].function = info_move_to_next_xref;
+ map[LFD].function = info_select_reference_this_line;
+ map[RET].function = info_select_reference_this_line;
+ map[SPC].function = info_scroll_forward;
+ map[Control ('a')].function = info_beginning_of_line;
+ map[Control ('b')].function = info_backward_char;
+ map[Control ('e')].function = info_end_of_line;
+ map[Control ('f')].function = info_forward_char;
+ map[Control ('g')].function = info_abort_key;
+ map[Control ('h')].function = info_get_help_window;
+ map[Control ('l')].function = info_redraw_display;
+ map[Control ('n')].function = info_next_line;
+ map[Control ('p')].function = info_prev_line;
+ map[Control ('r')].function = isearch_backward;
+ map[Control ('s')].function = isearch_forward;
+ map[Control ('u')].function = info_universal_argument;
+ map[Control ('v')].function = info_scroll_forward;
+ map[','].function = info_next_index_match;
+
+ for (i = '1'; i < '9' + 1; i++)
+ map[i].function = info_menu_digit;
+ map['0'].function = info_last_menu_item;
+
+ map['<'].function = info_first_node;
+ map['>'].function = info_last_node;
+ map['?'].function = info_get_help_window;
+ map['['].function = info_global_prev_node;
+ map[']'].function = info_global_next_node;
+
+ map['b'].function = info_beginning_of_node;
+ map['d'].function = info_dir_node;
+ map['e'].function = info_end_of_node;
+ map['f'].function = info_xref_item;
+ map['g'].function = info_goto_node;
+ map['h'].function = info_get_info_help_node;
+ map['i'].function = info_index_search;
+ map['l'].function = info_history_node;
+ map['m'].function = info_menu_item;
+ map['n'].function = info_next_node;
+ map['p'].function = info_prev_node;
+ map['q'].function = info_quit;
+ map['r'].function = info_xref_item;
+ map['s'].function = info_search;
+ map['t'].function = info_top_node;
+ map['u'].function = info_up_node;
+ map[DEL].function = info_scroll_backward;
+
+ /* Bind members in the ESC map for Info windows. */
+ map = (Keymap)info_keymap[ESC].function;
+ map[Control ('f')].function = info_show_footnotes;
+ map[Control ('g')].function = info_abort_key;
+ map[TAB].function = info_move_to_prev_xref;
+ map[Control ('v')].function = info_scroll_other_window;
+ map['<'].function = info_beginning_of_node;
+ map['>'].function = info_end_of_node;
+ map['b'].function = info_backward_word;
+ map['f'].function = info_forward_word;
+ map['r'].function = info_move_to_window_line;
+ map['v'].function = info_scroll_backward;
+#if defined (NAMED_FUNCTIONS)
+ map['x'].function = info_execute_command;
+#endif /* NAMED_FUNCTIONS */
+
+ /* Bind members in the Control-X map for Info windows. */
+ map = (Keymap)info_keymap[Control ('x')].function;
+
+ map[Control ('b')].function = list_visited_nodes;
+ map[Control ('c')].function = info_quit;
+ map[Control ('f')].function = info_view_file;
+ map[Control ('g')].function = info_abort_key;
+ map[Control ('v')].function = info_view_file;
+ map['0'].function = info_delete_window;
+ map['1'].function = info_keep_one_window;
+ map['2'].function = info_split_window;
+ map['^'].function = info_grow_window;
+ map['b'].function = select_visited_node;
+ map['k'].function = info_kill_node;
+ map['o'].function = info_next_window;
+ map['t'].function = info_tile_windows;
+ map['w'].function = info_toggle_wrap;
+
+ /* Add functions for the arrow keys, PageUp, PageDown, Home, HomeDown */
+ add_function_key(term_ku, info_prev_line, info_keymap);
+ add_function_key(term_kd, info_next_line, info_keymap);
+ add_function_key(term_kl, info_backward_char, info_keymap);
+ add_function_key(term_kr, info_forward_char, info_keymap);
+ add_function_key(term_kP, info_scroll_backward, info_keymap);
+ add_function_key(term_kN, info_scroll_forward, info_keymap);
+ add_function_key(term_kh, info_beginning_of_node, info_keymap);
+ add_function_key(term_kH, info_end_of_node, info_keymap);
+}
+
+static void add_function_key(char *esc_seq, VFunction *func, Keymap map)
+{
+ char *end_str, *p;
+
+ if (!esc_seq)
+ return; /* don't add keys which don't exist */
+
+ end_str = esc_seq + strlen(esc_seq);
+
+ for (p = esc_seq; p < end_str; p++)
+ {
+ if (isupper(*p))
+ *p = tolower(*p);
+ switch (map[*p].type)
+ {
+ case ISKMAP: /* Go one level down. Also has the effect
+ that we're not overwriting a previous
+ binding if we're at the end of p */
+ map = (Keymap)map[*p].function;
+ break;
+ case ISFUNC: /* two possibilities here:
+ 1. map[*p].function == NULL means we have
+ a virgin keymap to fill;
+ 2. else this entry is already taken */
+ if (map[*p].function == NULL)
+ {
+ if (p == end_str - 1)
+ {
+ map[*p].function = func;
+ return;
+ }
+ map[*p].type = ISKMAP;
+ map[*p].function = (VFunction *)keymap_make_keymap();
+ map = (Keymap)map[*p].function;
+ } else
+ return;
+ break;
+ default: /* can't happen */
+ info_error("unknown keymap type (%d).", map[*p].type);
+ break;
+ }
+ }
+ return;
+}
diff --git a/gnu/usr.bin/texinfo/info/infomap.h b/gnu/usr.bin/texinfo/info/infomap.h
new file mode 100644
index 0000000..85e5d80
--- /dev/null
+++ b/gnu/usr.bin/texinfo/info/infomap.h
@@ -0,0 +1,82 @@
+/* infomap.h -- Description of a keymap in Info and related functions. */
+
+/* This file is part of GNU Info, a program for reading online documentation
+ stored in Info format.
+
+ Copyright (C) 1993 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ Written by Brian Fox (bfox@ai.mit.edu). */
+
+#ifndef _INFOMAP_H_
+#define _INFOMAP_H_
+
+#include "general.h"
+
+#define ESC '\033'
+#define DEL '\177'
+#define TAB '\011'
+#define RET '\r'
+#define LFD '\n'
+#define SPC ' '
+
+#define meta_character_threshold (DEL + 1)
+#define control_character_threshold (SPC)
+
+#define meta_character_bit 0x80
+#define control_character_bit 0x40
+
+#define Meta_p(c) (((c) > meta_character_threshold))
+#define Control_p(c) ((c) < control_character_threshold)
+
+#define Meta(c) ((c) | (meta_character_bit))
+#define UnMeta(c) ((c) & (~meta_character_bit))
+#define Control(c) ((toupper (c)) & (~control_character_bit))
+#define UnControl(c) (tolower ((c) | control_character_bit))
+
+/* A keymap contains one entry for each key in the ASCII set.
+ Each entry consists of a type and a pointer.
+ FUNCTION is the address of a function to run, or the
+ address of a keymap to indirect through.
+ TYPE says which kind of thing FUNCTION is. */
+typedef struct {
+ char type;
+ VFunction *function;
+} KEYMAP_ENTRY;
+
+typedef KEYMAP_ENTRY *Keymap;
+
+/* The values that TYPE can have in a keymap entry. */
+#define ISFUNC 0
+#define ISKMAP 1
+
+extern Keymap info_keymap;
+extern Keymap echo_area_keymap;
+
+/* Return a new keymap which has all the uppercase letters mapped to run
+ the function info_do_lowercase_version (). */
+extern Keymap keymap_make_keymap ();
+
+/* Return a new keymap which is a copy of MAP. */
+extern Keymap keymap_copy_keymap ();
+
+/* Free MAP and it's descendents. */
+extern void keymap_discard_keymap ();
+
+/* Initialize the info keymaps. */
+extern void initialize_info_keymaps ();
+
+#endif /* _INFOMAP_H_ */
diff --git a/gnu/usr.bin/texinfo/info/m-x.c b/gnu/usr.bin/texinfo/info/m-x.c
new file mode 100644
index 0000000..13a861f
--- /dev/null
+++ b/gnu/usr.bin/texinfo/info/m-x.c
@@ -0,0 +1,195 @@
+/* m-x.c -- Meta-X minibuffer reader. */
+
+/* This file is part of GNU Info, a program for reading online documentation
+ stored in Info format.
+
+ Copyright (C) 1993 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ Written by Brian Fox (bfox@ai.mit.edu). */
+
+#include "info.h"
+
+/* **************************************************************** */
+/* */
+/* Reading Named Commands */
+/* */
+/* **************************************************************** */
+
+/* Read the name of an Info function in the echo area and return the
+ name. A return value of NULL indicates that no function name could
+ be read. */
+char *
+read_function_name (prompt, window)
+ char *prompt;
+ WINDOW *window;
+{
+ register int i;
+ char *line;
+ REFERENCE **array = (REFERENCE **)NULL;
+ int array_index = 0, array_slots = 0;
+
+ /* Make an array of REFERENCE which actually contains the names of
+ the functions available in Info. */
+ for (i = 0; function_doc_array[i].func; i++)
+ {
+ REFERENCE *entry;
+
+ entry = (REFERENCE *)xmalloc (sizeof (REFERENCE));
+ entry->label = savestring (function_doc_array[i].func_name);
+ entry->nodename = (char *)NULL;
+ entry->filename = (char *)NULL;
+
+ add_pointer_to_array
+ (entry, array_index, array, array_slots, 200, REFERENCE *);
+ }
+
+ line = info_read_completing_in_echo_area (window, prompt, array);
+
+ info_free_references (array);
+
+ if (!echo_area_is_active)
+ window_clear_echo_area ();
+
+ return (line);
+}
+
+DECLARE_INFO_COMMAND (describe_command,
+ "Read the name of an Info command and describe it")
+{
+ char *line;
+
+ line = read_function_name ("Describe command: ", window);
+
+ if (!line)
+ {
+ info_abort_key (active_window, count, key);
+ return;
+ }
+
+ /* Describe the function named in "LINE". */
+ if (*line)
+ {
+ char *fundoc;
+ VFunction *fun;
+
+ fun = named_function (line);
+
+ if (!fun)
+ return;
+
+ window_message_in_echo_area ("%s: %s.",
+ line, function_documentation (fun));
+ }
+ free (line);
+}
+
+DECLARE_INFO_COMMAND (info_execute_command,
+ "Read a command name in the echo area and execute it")
+{
+ char *line;
+
+ /* Ask the completer to read a reference for us. */
+ if (info_explicit_arg || count != 1)
+ {
+ char *prompt;
+
+ prompt = (char *)xmalloc (20);
+ sprintf (prompt, "%d M-x ", count);
+ line = read_function_name (prompt, window);
+ }
+ else
+ line = read_function_name ("M-x ", window);
+
+ /* User aborted? */
+ if (!line)
+ {
+ info_abort_key (active_window, count, key);
+ return;
+ }
+
+ /* User accepted "default"? (There is none.) */
+ if (!*line)
+ {
+ free (line);
+ return;
+ }
+
+ /* User wants to execute a named command. Do it. */
+ {
+ VFunction *function;
+
+ if ((active_window != the_echo_area) &&
+ (strncmp (line, "echo-area-", 10) == 0))
+ {
+ free (line);
+ info_error ("Cannot execute an `echo-area' command here.");
+ return;
+ }
+
+ function = named_function (line);
+ free (line);
+
+ if (!function)
+ return;
+
+ (*function) (active_window, count, 0);
+ }
+}
+
+/* Okay, now that we have M-x, let the user set the screen height. */
+DECLARE_INFO_COMMAND (set_screen_height,
+ "Set the height of the displayed window")
+{
+ int new_height;
+
+ if (info_explicit_arg || count != 1)
+ new_height = count;
+ else
+ {
+ char prompt[80];
+ char *line;
+
+ new_height = screenheight;
+
+ sprintf (prompt, "Set screen height to (%d): ", new_height);
+
+ line = info_read_in_echo_area (window, prompt);
+
+ /* If the user aborted, do that now. */
+ if (!line)
+ {
+ info_abort_key (active_window, count, 0);
+ return;
+ }
+
+ /* Find out what the new height is supposed to be. */
+ if (*line)
+ new_height = atoi (line);
+
+ /* Clear the echo area if it isn't active. */
+ if (!echo_area_is_active)
+ window_clear_echo_area ();
+
+ free (line);
+ }
+
+ terminal_clear_screen ();
+ display_clear_display (the_display);
+ screenheight = new_height;
+ display_initialize_display (screenwidth, screenheight);
+ window_new_screen_size (screenwidth, screenheight);
+}
diff --git a/gnu/usr.bin/texinfo/info/nodemenu.c b/gnu/usr.bin/texinfo/info/nodemenu.c
new file mode 100644
index 0000000..674ea7c
--- /dev/null
+++ b/gnu/usr.bin/texinfo/info/nodemenu.c
@@ -0,0 +1,321 @@
+/* nodemenu.c -- Produce a menu of all visited nodes. */
+
+/* This file is part of GNU Info, a program for reading online documentation
+ stored in Info format.
+
+ Copyright (C) 1993 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ Written by Brian Fox (bfox@ai.mit.edu). */
+
+#include "info.h"
+
+/* Return a line describing the format of a node information line. */
+static char *
+nodemenu_format_info ()
+{
+ return ("\n\
+* Menu:\n\
+ (File)Node Lines Size Containing File\n\
+ ---------- ----- ---- ---------------");
+}
+
+/* Produce a formatted line of information about NODE. Here is what we want
+ the output listing to look like:
+
+* Menu:
+ (File)Node Lines Size Containing File
+ ---------- ----- ---- ---------------
+* (emacs)Buffers:: 48 2230 /usr/gnu/info/emacs/emacs-1
+* (autoconf)Writing configure.in:: 123 58789 /usr/gnu/info/autoconf/autoconf-1
+* (dir)Top:: 40 589 /usr/gnu/info/dir
+*/
+static char *
+format_node_info (node)
+ NODE *node;
+{
+ register int i, len;
+ char *parent, *containing_file;
+ static char *line_buffer = (char *)NULL;
+
+ if (!line_buffer)
+ line_buffer = (char *)xmalloc (1000);
+
+ if (node->parent)
+ {
+ parent = filename_non_directory (node->parent);
+ if (!parent)
+ parent = node->parent;
+ }
+ else
+ parent = (char *)NULL;
+
+ containing_file = node->filename;
+
+ if (!parent && !*containing_file)
+ sprintf (line_buffer, "* %s::", node->nodename);
+ else
+ {
+ char *file = (char *)NULL;
+
+ if (parent)
+ file = parent;
+ else
+ file = filename_non_directory (containing_file);
+
+ if (!file)
+ file = containing_file;
+
+ if (!*file)
+ file = "dir";
+
+ sprintf (line_buffer, "* (%s)%s::", file, node->nodename);
+ }
+
+ len = pad_to (36, line_buffer);
+
+ {
+ int lines = 1;
+
+ for (i = 0; i < node->nodelen; i++)
+ if (node->contents[i] == '\n')
+ lines++;
+
+ sprintf (line_buffer + len, "%d", lines);
+ }
+
+ len = pad_to (44, line_buffer);
+ sprintf (line_buffer + len, "%d", node->nodelen);
+
+ if (node->filename && *(node->filename))
+ {
+ len = pad_to (51, line_buffer);
+ sprintf (line_buffer + len, node->filename);
+ }
+
+ return (savestring (line_buffer));
+}
+
+/* Little string comparison routine for qsort (). */
+static int
+compare_strings (string1, string2)
+ char **string1, **string2;
+{
+ return (stricmp (*string1, *string2));
+}
+
+/* The name of the nodemenu node. */
+static char *nodemenu_nodename = "*Node Menu*";
+
+/* Produce an informative listing of all the visited nodes, and return it
+ in a node. If FILTER_FUNC is non-null, it is a function which filters
+ which nodes will appear in the listing. FILTER_FUNC takes an argument
+ of NODE, and returns non-zero if the node should appear in the listing. */
+NODE *
+get_visited_nodes (filter_func)
+ Function *filter_func;
+{
+ register int i, iw_index;
+ INFO_WINDOW *info_win;
+ NODE *node;
+ char **lines = (char **)NULL;
+ int lines_index = 0, lines_slots = 0;
+
+ if (!info_windows)
+ return ((NODE *)NULL);
+
+ for (iw_index = 0; info_win = info_windows[iw_index]; iw_index++)
+ {
+ for (i = 0; i < info_win->nodes_index; i++)
+ {
+ node = info_win->nodes[i];
+
+ /* We skip mentioning "*Node Menu*" nodes. */
+ if (internal_info_node_p (node) &&
+ (strcmp (node->nodename, nodemenu_nodename) == 0))
+ continue;
+
+ if (node && (!filter_func || (*filter_func) (node)))
+ {
+ char *line;
+
+ line = format_node_info (node);
+ add_pointer_to_array
+ (line, lines_index, lines, lines_slots, 20, char *);
+ }
+ }
+ }
+
+ /* Sort the array of information lines. */
+ qsort (lines, lines_index, sizeof (char *), compare_strings);
+
+ /* Delete duplicates. */
+ {
+ register int j, newlen;
+ char **temp;
+
+ for (i = 0, newlen = 1; i < lines_index - 1; i++)
+ {
+ if (strcmp (lines[i], lines[i + 1]) == 0)
+ {
+ free (lines[i]);
+ lines[i] = (char *)NULL;
+ }
+ else
+ newlen++;
+ }
+
+ /* We have free ()'d and marked all of the duplicate slots. Copy the
+ live slots rather than pruning the dead slots. */
+ temp = (char **)xmalloc ((1 + newlen) * sizeof (char *));
+ for (i = 0, j = 0; i < lines_index; i++)
+ if (lines[i])
+ temp[j++] = lines[i];
+
+ temp[j] = (char *)NULL;
+ free (lines);
+ lines = temp;
+ lines_index = newlen;
+ }
+
+ initialize_message_buffer ();
+ printf_to_message_buffer
+ ("Here is a menu of nodes you could select with info-history-node:\n");
+ printf_to_message_buffer ("%s\n", nodemenu_format_info ());
+ for (i = 0; i < lines_index; i++)
+ {
+ printf_to_message_buffer ("%s\n", lines[i]);
+ free (lines[i]);
+ }
+ free (lines);
+
+ node = message_buffer_to_node ();
+ add_gcable_pointer (node->contents);
+ return (node);
+}
+
+DECLARE_INFO_COMMAND (list_visited_nodes,
+ "Make a window containing a menu of all of the currently visited nodes")
+{
+ WINDOW *new;
+ NODE *node;
+
+ set_remembered_pagetop_and_point (window);
+
+ /* If a window is visible and showing the buffer list already, re-use it. */
+ for (new = windows; new; new = new->next)
+ {
+ node = new->node;
+
+ if (internal_info_node_p (node) &&
+ (strcmp (node->nodename, nodemenu_nodename) == 0))
+ break;
+ }
+
+ /* If we couldn't find an existing window, try to use the next window
+ in the chain. */
+ if (!new && window->next)
+ new = window->next;
+
+ /* If we still don't have a window, make a new one to contain the list. */
+ if (!new)
+ {
+ WINDOW *old_active;
+
+ old_active = active_window;
+ active_window = window;
+ new = window_make_window ((NODE *)NULL);
+ active_window = old_active;
+ }
+
+ /* If we couldn't make a new window, use this one. */
+ if (!new)
+ new = window;
+
+ /* Lines do not wrap in this window. */
+ new->flags |= W_NoWrap;
+ node = get_visited_nodes ((Function *)NULL);
+ name_internal_node (node, nodemenu_nodename);
+
+ /* Even if this is an internal node, we don't want the window
+ system to treat it specially. So we turn off the internalness
+ of it here. */
+ node->flags &= ~N_IsInternal;
+
+ /* If this window is already showing a node menu, reuse the existing node
+ slot. */
+ {
+ int remember_me = 1;
+
+#if defined (NOTDEF)
+ if (internal_info_node_p (new->node) &&
+ (strcmp (new->node->nodename, nodemenu_nodename) == 0))
+ remember_me = 0;
+#endif /* NOTDEF */
+
+ window_set_node_of_window (new, node);
+
+ if (remember_me)
+ remember_window_and_node (new, node);
+ }
+
+ active_window = new;
+}
+
+DECLARE_INFO_COMMAND (select_visited_node,
+ "Select a node which has been previously visited in a visible window")
+{
+ char *line;
+ NODE *node;
+ REFERENCE **menu;
+
+ node = get_visited_nodes ((Function *)NULL);
+
+ menu = info_menu_of_node (node);
+ free (node);
+
+ line =
+ info_read_completing_in_echo_area (window, "Select visited node: ", menu);
+
+ window = active_window;
+
+ /* User aborts, just quit. */
+ if (!line)
+ {
+ info_abort_key (window, 0, 0);
+ info_free_references (menu);
+ return;
+ }
+
+ if (*line)
+ {
+ REFERENCE *entry;
+
+ /* Find the selected label in the references. */
+ entry = info_get_labeled_reference (line, menu);
+
+ if (!entry)
+ info_error ("The reference disappeared! (%s).", line);
+ else
+ info_select_reference (window, entry);
+ }
+
+ free (line);
+ info_free_references (menu);
+
+ if (!info_error_was_printed)
+ window_clear_echo_area ();
+}
diff --git a/gnu/usr.bin/texinfo/info/nodes.c b/gnu/usr.bin/texinfo/info/nodes.c
new file mode 100644
index 0000000..2036680
--- /dev/null
+++ b/gnu/usr.bin/texinfo/info/nodes.c
@@ -0,0 +1,1167 @@
+/* nodes.c -- How to get an Info file and node. */
+
+/* This file is part of GNU Info, a program for reading online documentation
+ stored in Info format.
+
+ Copyright (C) 1993 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ Written by Brian Fox (bfox@ai.mit.edu). */
+
+#include <stdio.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <sys/file.h>
+#include <sys/errno.h>
+#include <sys/stat.h>
+#include "nodes.h"
+#include "search.h"
+#include "filesys.h"
+#include "info-utils.h"
+
+#if !defined (O_RDONLY)
+#if defined (HAVE_SYS_FCNTL_H)
+#include <sys/fcntl.h>
+#else /* !HAVE_SYS_FCNTL_H */
+#include <fcntl.h>
+#endif /* !HAVE_SYS_FCNTL_H */
+#endif /* !O_RDONLY */
+
+#if !defined (errno)
+extern int errno;
+#endif /* !errno */
+
+/* **************************************************************** */
+/* */
+/* Functions Static to this File */
+/* */
+/* **************************************************************** */
+
+static void forget_info_file (), remember_info_file ();
+static void free_file_buffer_tags (), free_info_tag ();
+static void get_nodes_of_tags_table (), get_nodes_of_info_file ();
+static void get_tags_of_indirect_tags_table ();
+static void info_reload_file_buffer_contents ();
+static char *adjust_nodestart ();
+static FILE_BUFFER *make_file_buffer ();
+static FILE_BUFFER *info_load_file_internal (), *info_find_file_internal ();
+static NODE *info_node_of_file_buffer_tags ();
+
+static long get_node_length ();
+
+/* Magic number that RMS used to decide how much a tags table pointer could
+ be off by. I feel that it should be much smaller, like on the order of
+ 4. */
+#define DEFAULT_INFO_FUDGE 1000
+
+/* Passed to *_internal functions. INFO_GET_TAGS says to do what is
+ neccessary to fill in the nodes or tags arrays in FILE_BUFFER. */
+#define INFO_NO_TAGS 0
+#define INFO_GET_TAGS 1
+
+/* **************************************************************** */
+/* */
+/* Global Variables */
+/* */
+/* **************************************************************** */
+
+/* When non-zero, this is a string describing the recent file error. */
+char *info_recent_file_error = (char *)NULL;
+
+/* The list of already loaded nodes. */
+FILE_BUFFER **info_loaded_files = (FILE_BUFFER **)NULL;
+
+/* The number of slots currently allocated to LOADED_FILES. */
+int info_loaded_files_slots = 0;
+
+/* **************************************************************** */
+/* */
+/* Public Functions for Node Manipulation */
+/* */
+/* **************************************************************** */
+
+/* Used to build "dir" menu from "localdir" files found in INFOPATH. */
+extern void maybe_build_dir_node ();
+
+/* Return a pointer to a NODE structure for the Info node (FILENAME)NODENAME.
+ FILENAME can be passed as NULL, in which case the filename of "dir" is used.
+ NODENAME can be passed as NULL, in which case the nodename of "Top" is used.
+ If the node cannot be found, return a NULL pointer. */
+NODE *
+info_get_node (filename, nodename)
+ char *filename, *nodename;
+{
+ FILE_BUFFER *file_buffer;
+ NODE *node;
+
+ file_buffer = (FILE_BUFFER *)NULL;
+ info_recent_file_error = (char *)NULL;
+
+ info_parse_node (nodename, DONT_SKIP_NEWLINES);
+ nodename = (char *)NULL;
+
+ if (info_parsed_filename)
+ filename = info_parsed_filename;
+
+ if (info_parsed_nodename)
+ nodename = info_parsed_nodename;
+
+ /* If FILENAME is not specified, it defaults to "dir". */
+ if (!filename)
+ filename = "dir";
+
+ /* If the file to be looked up is "dir", build the contents from all of
+ the "localdir"'s found in INFOPATH. */
+ if (stricmp (filename, "dir") == 0)
+ maybe_build_dir_node (filename, "localdir");
+
+ /* Find the correct info file. */
+ file_buffer = info_find_file (filename);
+
+ if (!file_buffer)
+ {
+ if (filesys_error_number)
+ info_recent_file_error =
+ filesys_error_string (filename, filesys_error_number);
+ return ((NODE *)NULL);
+ }
+
+ node = info_get_node_of_file_buffer (nodename, file_buffer);
+ /* If the node looked for was "Top", try again looking for the node under
+ a slightly different name. */
+ if (!node && (nodename == NULL || stricmp (nodename, "Top") == 0))
+ {
+ node = info_get_node_of_file_buffer ("Top", file_buffer);
+ if (!node)
+ node = info_get_node_of_file_buffer ("top", file_buffer);
+ if (!node)
+ node = info_get_node_of_file_buffer ("TOP", file_buffer);
+ }
+ return (node);
+}
+
+/* Return a pointer to a NODE structure for the Info node NODENAME in
+ FILE_BUFFER. NODENAME can be passed as NULL, in which case the
+ nodename of "Top" is used. If the node cannot be found, return a
+ NULL pointer. */
+NODE *
+info_get_node_of_file_buffer (nodename, file_buffer)
+ char *nodename;
+ FILE_BUFFER *file_buffer;
+{
+ NODE *node = (NODE *)NULL;
+
+ /* If we are unable to find the file, we have to give up. There isn't
+ anything else we can do. */
+ if (!file_buffer)
+ return ((NODE *)NULL);
+
+ /* If the file buffer was gc'ed, reload the contents now. */
+ if (!file_buffer->contents)
+ info_reload_file_buffer_contents (file_buffer);
+
+ /* If NODENAME is not specified, it defaults to "Top". */
+ if (!nodename)
+ nodename = "Top";
+
+ /* If the name of the node that we wish to find is exactly "*", then the
+ node body is the contents of the entire file. Create and return such
+ a node. */
+ if (strcmp (nodename, "*") == 0)
+ {
+ node = (NODE *)xmalloc (sizeof (NODE));
+ node->filename = file_buffer->fullpath;
+ node->parent = (char *)NULL;
+ node->nodename = savestring ("*");
+ node->contents = file_buffer->contents;
+ node->nodelen = file_buffer->filesize;
+ node->flags = 0;
+ }
+
+ /* If this is the "main" info file, it might contain a tags table. Search
+ the tags table for an entry which matches the node that we want. If
+ there is a tags table, get the file which contains this node, but don't
+ bother building a node list for it. */
+ else if (file_buffer->tags)
+ node = info_node_of_file_buffer_tags (file_buffer, nodename);
+
+ /* Return the results of our node search. */
+ return (node);
+}
+
+/* Locate the file named by FILENAME, and return the information structure
+ describing this file. The file may appear in our list of loaded files
+ already, or it may not. If it does not already appear, find the file,
+ and add it to the list of loaded files. If the file cannot be found,
+ return a NULL FILE_BUFFER *. */
+FILE_BUFFER *
+info_find_file (filename)
+ char *filename;
+{
+ return (info_find_file_internal (filename, INFO_GET_TAGS));
+}
+
+/* Load the info file FILENAME, remembering information about it in a
+ file buffer. */
+FILE_BUFFER *
+info_load_file (filename)
+ char *filename;
+{
+ return (info_load_file_internal (filename, INFO_GET_TAGS));
+}
+
+
+/* **************************************************************** */
+/* */
+/* Private Functions Implementation */
+/* */
+/* **************************************************************** */
+
+/* The workhorse for info_find_file (). Non-zero 2nd argument says to
+ try to build a tags table (or otherwise glean the nodes) for this
+ file once found. By default, we build the tags table, but when this
+ function is called by info_get_node () when we already have a valid
+ tags table describing the nodes, it is unnecessary. */
+static FILE_BUFFER *
+info_find_file_internal (filename, get_tags)
+ char *filename;
+ int get_tags;
+{
+ register int i;
+ register FILE_BUFFER *file_buffer;
+
+ /* First try to find the file in our list of already loaded files. */
+ if (info_loaded_files)
+ {
+ for (i = 0; file_buffer = info_loaded_files[i]; i++)
+ if ((strcmp (filename, file_buffer->filename) == 0) ||
+ (strcmp (filename, file_buffer->fullpath) == 0) ||
+ ((*filename != '/') &&
+ strcmp (filename,
+ filename_non_directory (file_buffer->fullpath)) == 0))
+ {
+ struct stat new_info, *old_info;
+
+ /* This file is loaded. If the filename that we want is
+ specifically "dir", then simply return the file buffer. */
+ if (stricmp (filename_non_directory (filename), "dir") == 0)
+ return (file_buffer);
+
+ /* The file appears to be already loaded, and it is not "dir".
+ Check to see if it has changed since the last time it was
+ loaded. */
+ if (stat (file_buffer->fullpath, &new_info) == -1)
+ {
+ filesys_error_number = errno;
+ return ((FILE_BUFFER *)NULL);
+ }
+
+ old_info = &file_buffer->finfo;
+
+ if ((new_info.st_size != old_info->st_size) ||
+ (new_info.st_mtime != old_info->st_mtime))
+ {
+ /* The file has changed. Forget that we ever had loaded it
+ in the first place. */
+ forget_info_file (filename);
+ break;
+ }
+ else
+ {
+ /* The info file exists, and has not changed since the last
+ time it was loaded. If the caller requested a nodes list
+ for this file, and there isn't one here, build the nodes
+ for this file_buffer. In any case, return the file_buffer
+ object. */
+ if (get_tags && !file_buffer->tags)
+ build_tags_and_nodes (file_buffer);
+
+ return (file_buffer);
+ }
+ }
+ }
+
+ /* The file wasn't loaded. Try to load it now. */
+ file_buffer = info_load_file_internal (filename, get_tags);
+
+ /* If the file was loaded, remember the name under which it was found. */
+ if (file_buffer)
+ remember_info_file (file_buffer);
+
+ return (file_buffer);
+}
+
+/* The workhorse function for info_load_file (). Non-zero second argument
+ says to build a list of tags (or nodes) for this file. This is the
+ default behaviour when info_load_file () is called, but it is not
+ necessary when loading a subfile for which we already have tags. */
+static FILE_BUFFER *
+info_load_file_internal (filename, get_tags)
+ char *filename;
+ int get_tags;
+{
+ char *fullpath, *contents;
+ long filesize;
+ struct stat finfo;
+ int retcode;
+ FILE_BUFFER *file_buffer = (FILE_BUFFER *)NULL;
+
+ /* Get the full pathname of this file, as known by the info system.
+ That is to say, search along INFOPATH and expand tildes, etc. */
+ fullpath = info_find_fullpath (filename);
+
+ /* Did we actually find the file? */
+ retcode = stat (fullpath, &finfo);
+
+ /* If the file referenced by the name returned from info_find_fullpath ()
+ doesn't exist, then try again with the last part of the filename
+ appearing in lowercase. */
+ if (retcode < 0)
+ {
+ char *lowered_name;
+ char *basename;
+
+ lowered_name = savestring (filename);
+ basename = (char *)rindex (lowered_name, '/');
+
+ if (basename)
+ basename++;
+ else
+ basename = lowered_name;
+
+ while (*basename)
+ {
+ if (isupper (*basename))
+ *basename = tolower (*basename);
+
+ basename++;
+ }
+
+ fullpath = info_find_fullpath (lowered_name);
+ free (lowered_name);
+
+ retcode = stat (fullpath, &finfo);
+ }
+
+ /* If the file wasn't found, give up, returning a NULL pointer. */
+ if (retcode < 0)
+ {
+ filesys_error_number = errno;
+ return ((FILE_BUFFER *)NULL);
+ }
+
+ /* Otherwise, try to load the file. */
+ contents = filesys_read_info_file (fullpath, &filesize, &finfo);
+
+ if (!contents)
+ return ((FILE_BUFFER *)NULL);
+
+ /* The file was found, and can be read. Allocate FILE_BUFFER and fill
+ in the various members. */
+ file_buffer = make_file_buffer ();
+ file_buffer->filename = savestring (filename);
+ file_buffer->fullpath = savestring (fullpath);
+ file_buffer->finfo = finfo;
+ file_buffer->filesize = filesize;
+ file_buffer->contents = contents;
+ if (file_buffer->filesize != file_buffer->finfo.st_size)
+ file_buffer->flags |= N_IsCompressed;
+
+ /* If requested, build the tags and nodes for this file buffer. */
+ if (get_tags)
+ build_tags_and_nodes (file_buffer);
+
+ return (file_buffer);
+}
+
+/* Grovel FILE_BUFFER->contents finding tags and nodes, and filling in the
+ various slots. This can also be used to rebuild a tag or node table. */
+void
+build_tags_and_nodes (file_buffer)
+ FILE_BUFFER *file_buffer;
+{
+ SEARCH_BINDING binding;
+ long position;
+
+ free_file_buffer_tags (file_buffer);
+ file_buffer->flags &= ~N_HasTagsTable;
+
+ /* See if there is a tags table in this info file. */
+ binding.buffer = file_buffer->contents;
+ binding.start = file_buffer->filesize;
+ binding.end = binding.start - 1000;
+ if (binding.end < 0)
+ binding.end = 0;
+ binding.flags = S_FoldCase;
+
+ position = search_backward (TAGS_TABLE_END_LABEL, &binding);
+
+ /* If there is a tag table, find the start of it, and grovel over it
+ extracting tag information. */
+ if (position != -1)
+ while (1)
+ {
+ long tags_table_begin, tags_table_end;
+
+ binding.end = position;
+ binding.start = binding.end - 5 - strlen (TAGS_TABLE_END_LABEL);
+ if (binding.start < 0)
+ binding.start = 0;
+
+ position = find_node_separator (&binding);
+
+ /* For this test, (and all others here) failure indicates a bogus
+ tags table. Grovel the file. */
+ if (position == -1)
+ break;
+
+ /* Remember the end of the tags table. */
+ binding.start = position;
+ tags_table_end = binding.start;
+ binding.end = 0;
+
+ /* Locate the start of the tags table. */
+ position = search_backward (TAGS_TABLE_BEG_LABEL, &binding);
+
+ if (position == -1)
+ break;
+
+ binding.end = position;
+ binding.start = binding.end - 5 - strlen (TAGS_TABLE_BEG_LABEL);
+ position = find_node_separator (&binding);
+
+ if (position == -1)
+ break;
+
+ /* The file contains a valid tags table. Fill the FILE_BUFFER's
+ tags member. */
+ file_buffer->flags |= N_HasTagsTable;
+ tags_table_begin = position;
+
+ /* If this isn't an indirect tags table, just remember the nodes
+ described locally in this tags table. Note that binding.end
+ is pointing to just after the beginning label. */
+ binding.start = binding.end;
+ binding.end = file_buffer->filesize;
+
+ if (!looking_at (TAGS_TABLE_IS_INDIRECT_LABEL, &binding))
+ {
+ binding.start = tags_table_begin;
+ binding.end = tags_table_end;
+ get_nodes_of_tags_table (file_buffer, &binding);
+ return;
+ }
+ else
+ {
+ /* This is an indirect tags table. Build TAGS member. */
+ SEARCH_BINDING indirect;
+
+ indirect.start = tags_table_begin;
+ indirect.end = 0;
+ indirect.buffer = binding.buffer;
+ indirect.flags = S_FoldCase;
+
+ position = search_backward (INDIRECT_TAGS_TABLE_LABEL, &indirect);
+
+ if (position == -1)
+ {
+ /* This file is malformed. Give up. */
+ return;
+ }
+
+ indirect.start = position;
+ indirect.end = tags_table_begin;
+ binding.start = tags_table_begin;
+ binding.end = tags_table_end;
+ get_tags_of_indirect_tags_table (file_buffer, &indirect, &binding);
+ return;
+ }
+ }
+
+ /* This file doesn't contain any kind of tags table. Grovel the
+ file and build node entries for it. */
+ get_nodes_of_info_file (file_buffer);
+}
+
+/* Search through FILE_BUFFER->contents building an array of TAG *,
+ one entry per each node present in the file. Store the tags in
+ FILE_BUFFER->tags, and the number of allocated slots in
+ FILE_BUFFER->tags_slots. */
+static void
+get_nodes_of_info_file (file_buffer)
+ FILE_BUFFER *file_buffer;
+{
+ long nodestart;
+ int tags_index = 0;
+ SEARCH_BINDING binding;
+
+ binding.buffer = file_buffer->contents;
+ binding.start = 0;
+ binding.end = file_buffer->filesize;
+ binding.flags = S_FoldCase;
+
+ while ((nodestart = find_node_separator (&binding)) != -1)
+ {
+ int start, end;
+ char *nodeline;
+ TAG *entry;
+
+ /* Skip past the characters just found. */
+ binding.start = nodestart;
+ binding.start += skip_node_separator (binding.buffer + binding.start);
+
+ /* Move to the start of the line defining the node. */
+ nodeline = binding.buffer + binding.start;
+
+ /* Find "Node:" */
+ start = string_in_line (INFO_NODE_LABEL, nodeline);
+
+ /* If not there, this is not the start of a node. */
+ if (start == -1)
+ continue;
+
+ /* Find the start of the nodename. */
+ start += skip_whitespace (nodeline + start);
+
+ /* Find the end of the nodename. */
+ end = start +
+ skip_node_characters (nodeline + start, DONT_SKIP_NEWLINES);
+
+ /* Okay, we have isolated the node name, and we know where the
+ node starts. Remember this information in a NODE structure. */
+ entry = (TAG *)xmalloc (sizeof (TAG));
+ entry->nodename = (char *)xmalloc (1 + (end - start));
+ strncpy (entry->nodename, nodeline + start, end - start);
+ entry->nodename[end - start] = '\0';
+ entry->nodestart = nodestart;
+ {
+ SEARCH_BINDING node_body;
+
+ node_body.buffer = binding.buffer + binding.start;
+ node_body.start = 0;
+ node_body.end = binding.end - binding.start;
+ node_body.flags = S_FoldCase;
+ entry->nodelen = get_node_length (&node_body);
+ }
+
+ entry->filename = file_buffer->fullpath;
+
+ /* Add this tag to the array of tag structures in this FILE_BUFFER. */
+ add_pointer_to_array (entry, tags_index, file_buffer->tags,
+ file_buffer->tags_slots, 100, TAG *);
+ }
+}
+
+/* Return the length of the node which starts at BINDING. */
+static long
+get_node_length (binding)
+ SEARCH_BINDING *binding;
+{
+ register int i;
+ char *body;
+
+ /* From the Info-RFC file:
+ [A node] ends with either a ^_, a ^L, or the end of file. */
+ for (i = binding->start, body = binding->buffer; i < binding->end; i++)
+ {
+ if (body[i] == INFO_FF || body[i] == INFO_COOKIE)
+ break;
+ }
+ return ((long) i - binding->start);
+}
+
+/* Build and save the array of nodes in FILE_BUFFER by searching through the
+ contents of BUFFER_BINDING for a tags table, and groveling the contents. */
+static void
+get_nodes_of_tags_table (file_buffer, buffer_binding)
+ FILE_BUFFER *file_buffer;
+ SEARCH_BINDING *buffer_binding;
+{
+ int offset, tags_index = 0;
+ SEARCH_BINDING *search;
+ long position;
+
+ search = copy_binding (buffer_binding);
+
+ /* Find the start of the tags table. */
+ position = find_tags_table (search);
+
+ /* If none, we're all done. */
+ if (position == -1)
+ return;
+
+ /* Move to one character before the start of the actual table. */
+ search->start = position;
+ search->start += skip_node_separator (search->buffer + search->start);
+ search->start += strlen (TAGS_TABLE_BEG_LABEL);
+ search->start--;
+
+ /* The tag table consists of lines containing node names and positions.
+ Do each line until we find one that doesn't contain a node name. */
+ while ((position = search_forward ("\n", search)) != -1)
+ {
+ TAG *entry;
+ char *nodedef;
+
+ /* Prepare to skip this line. */
+ search->start = position;
+ search->start++;
+
+ /* Skip past informative "(Indirect)" tags table line. */
+ if (!tags_index && looking_at (TAGS_TABLE_IS_INDIRECT_LABEL, search))
+ continue;
+
+ /* Find the label preceding the node name. */
+ offset =
+ string_in_line (INFO_NODE_LABEL, search->buffer + search->start);
+
+ /* If not there, not a defining line, so we must be out of the
+ tags table. */
+ if (offset == -1)
+ break;
+
+ /* Point to the beginning of the node definition. */
+ search->start += offset;
+ nodedef = search->buffer + search->start;
+ nodedef += skip_whitespace (nodedef);
+
+ /* Move past the node's name. */
+ for (offset = 0;
+ (nodedef[offset]) && (nodedef[offset] != INFO_TAGSEP);
+ offset++);
+
+ if (nodedef[offset] != INFO_TAGSEP)
+ continue;
+
+ entry = (TAG *)xmalloc (sizeof (TAG));
+ entry->nodename = (char *)xmalloc (1 + offset);
+ strncpy (entry->nodename, nodedef, offset);
+ entry->nodename[offset] = '\0';
+ offset++;
+ entry->nodestart = (long) atol (nodedef + offset);
+
+ /* We don't know the length of this node yet. */
+ entry->nodelen = -1;
+
+ /* The filename of this node is currently known as the same as the
+ name of this file. */
+ entry->filename = file_buffer->fullpath;
+
+ /* Add this node structure to the array of node structures in this
+ FILE_BUFFER. */
+ add_pointer_to_array (entry, tags_index, file_buffer->tags,
+ file_buffer->tags_slots, 100, TAG *);
+ }
+ free (search);
+}
+
+/* A structure used only in get_tags_of_indirect_tags_table () to hold onto
+ an intermediate value. */
+typedef struct {
+ char *filename;
+ long first_byte;
+} SUBFILE;
+
+/* Remember in FILE_BUFFER the nodenames, subfilenames, and offsets within the
+ subfiles of every node which appears in TAGS_BINDING. The 2nd argument is
+ a binding surrounding the indirect files list. */
+static void
+get_tags_of_indirect_tags_table (file_buffer, indirect_binding, tags_binding)
+ FILE_BUFFER *file_buffer;
+ SEARCH_BINDING *indirect_binding, *tags_binding;
+{
+ register int i;
+ SUBFILE **subfiles = (SUBFILE **)NULL;
+ int subfiles_index = 0, subfiles_slots = 0;
+ TAG *entry;
+
+ /* First get the list of tags from the tags table. Then lookup the
+ associated file in the indirect list for each tag, and update it. */
+ get_nodes_of_tags_table (file_buffer, tags_binding);
+
+ /* We have the list of tags in file_buffer->tags. Get the list of
+ subfiles from the indirect table. */
+ {
+ char *start, *end, *line;
+ SUBFILE *subfile;
+
+ start = indirect_binding->buffer + indirect_binding->start;
+ end = indirect_binding->buffer + indirect_binding->end;
+ line = start;
+
+ while (line < end)
+ {
+ int colon;
+
+ colon = string_in_line (":", line);
+
+ if (colon == -1)
+ break;
+
+ subfile = (SUBFILE *)xmalloc (sizeof (SUBFILE));
+ subfile->filename = (char *)xmalloc (colon);
+ strncpy (subfile->filename, line, colon - 1);
+ subfile->filename[colon - 1] = '\0';
+ subfile->first_byte = (long) atol (line + colon);
+
+ add_pointer_to_array
+ (subfile, subfiles_index, subfiles, subfiles_slots, 10, SUBFILE *);
+
+ while (*line++ != '\n');
+ }
+ }
+
+ /* If we have successfully built the indirect files table, then
+ merge the information in the two tables. */
+ if (!subfiles)
+ {
+ free_file_buffer_tags (file_buffer);
+ return;
+ }
+ else
+ {
+ register int tags_index;
+ long header_length;
+ SEARCH_BINDING binding;
+
+ /* Find the length of the header of the file containing the indirect
+ tags table. This header appears at the start of every file. We
+ want the absolute position of each node within each subfile, so
+ we subtract the start of the containing subfile from the logical
+ position of the node, and then add the length of the header in. */
+ binding.buffer = file_buffer->contents;
+ binding.start = 0;
+ binding.end = file_buffer->filesize;
+ binding.flags = S_FoldCase;
+
+ header_length = find_node_separator (&binding);
+ if (header_length == -1)
+ header_length = 0;
+
+ /* Build the file buffer's list of subfiles. */
+ {
+ char *containing_dir, *temp;
+ int len_containing_dir;
+
+ containing_dir = savestring (file_buffer->fullpath);
+ temp = (char *)rindex (containing_dir, '/');
+
+ if (temp)
+ *temp = '\0';
+
+ len_containing_dir = strlen (containing_dir);
+
+ for (i = 0; subfiles[i]; i++);
+
+ file_buffer->subfiles = (char **) xmalloc ((1 + i) * sizeof (char *));
+
+ for (i = 0; subfiles[i]; i++)
+ {
+ char *fullpath;
+
+ fullpath = (char *) xmalloc
+ (2 + strlen (subfiles[i]->filename) + len_containing_dir);
+
+ sprintf (fullpath, "%s/%s",
+ containing_dir, subfiles[i]->filename);
+
+ file_buffer->subfiles[i] = fullpath;
+ }
+ file_buffer->subfiles[i] = (char *)NULL;
+ free (containing_dir);
+ }
+
+ /* For each node in the file's tags table, remember the starting
+ position. */
+ for (tags_index = 0;
+ entry = file_buffer->tags[tags_index];
+ tags_index++)
+ {
+ for (i = 0;
+ subfiles[i] && entry->nodestart >= subfiles[i]->first_byte;
+ i++);
+
+ /* If the Info file containing the indirect tags table is
+ malformed, then give up. */
+ if (!i)
+ {
+ /* The Info file containing the indirect tags table is
+ malformed. Give up. */
+ for (i = 0; subfiles[i]; i++)
+ {
+ free (subfiles[i]->filename);
+ free (subfiles[i]);
+ free (file_buffer->subfiles[i]);
+ }
+ file_buffer->subfiles = (char **)NULL;
+ free_file_buffer_tags (file_buffer);
+ return;
+ }
+
+ /* SUBFILES[i] is the index of the first subfile whose logical
+ first byte is greater than the logical offset of this node's
+ starting position. This means that the subfile directly
+ preceding this one is the one containing the node. */
+
+ entry->filename = file_buffer->subfiles[i - 1];
+ entry->nodestart -= subfiles[i -1]->first_byte;
+ entry->nodestart += header_length;
+ entry->nodelen = -1;
+ }
+
+ /* We have successfully built the tags table. Remember that it
+ was indirect. */
+ file_buffer->flags |= N_TagsIndirect;
+ }
+
+ /* Free the structures assigned to SUBFILES. Free the names as well
+ as the structures themselves, then finally, the array. */
+ for (i = 0; subfiles[i]; i++)
+ {
+ free (subfiles[i]->filename);
+ free (subfiles[i]);
+ }
+ free (subfiles);
+}
+
+/* Return the node from FILE_BUFFER which matches NODENAME by searching
+ the tags table in FILE_BUFFER. If the node could not be found, return
+ a NULL pointer. */
+static NODE *
+info_node_of_file_buffer_tags (file_buffer, nodename)
+ FILE_BUFFER *file_buffer;
+ char *nodename;
+{
+ register int i;
+ TAG *tag;
+
+ for (i = 0; tag = file_buffer->tags[i]; i++)
+ if (strcmp (nodename, tag->nodename) == 0)
+ {
+ FILE_BUFFER *subfile;
+
+ subfile = info_find_file_internal (tag->filename, INFO_NO_TAGS);
+
+ if (!subfile)
+ return ((NODE *)NULL);
+
+ if (!subfile->contents)
+ info_reload_file_buffer_contents (subfile);
+
+ if (!subfile->contents)
+ return ((NODE *)NULL);
+
+ /* If we were able to find this file and load it, then return
+ the node within it. */
+ {
+ NODE *node;
+
+ node = (NODE *)xmalloc (sizeof (NODE));
+ node->filename = (subfile->fullpath);
+ node->nodename = tag->nodename;
+ node->contents = subfile->contents + tag->nodestart;
+ node->flags = 0;
+ node->parent = (char *)NULL;
+
+ if (file_buffer->flags & N_HasTagsTable)
+ {
+ node->flags |= N_HasTagsTable;
+
+ if (file_buffer->flags & N_TagsIndirect)
+ {
+ node->flags |= N_TagsIndirect;
+ node->parent = file_buffer->fullpath;
+ }
+ }
+
+ if (subfile->flags & N_IsCompressed)
+ node->flags |= N_IsCompressed;
+
+ /* If TAG->nodelen hasn't been calculated yet, then we aren't
+ in a position to trust the entry pointer. Adjust things so
+ that ENTRY->nodestart gets the exact address of the start of
+ the node separator which starts this node, and NODE->contents
+ gets the address of the line defining this node. If we cannot
+ do that, the node isn't really here. */
+ if (tag->nodelen == -1)
+ {
+ int min, max;
+ char *node_sep;
+ SEARCH_BINDING node_body;
+ char *buff_end;
+
+ min = max = DEFAULT_INFO_FUDGE;
+
+ if (tag->nodestart < DEFAULT_INFO_FUDGE)
+ min = tag->nodestart;
+
+ if (DEFAULT_INFO_FUDGE >
+ (subfile->filesize - tag->nodestart))
+ max = subfile->filesize - tag->nodestart;
+
+ /* NODE_SEP gets the address of the separator which defines
+ this node, or (char *)NULL if the node wasn't found.
+ NODE->contents is side-effected to point to right after
+ the separator. */
+ node_sep = adjust_nodestart (node, min, max);
+ if (node_sep == (char *)NULL)
+ {
+ free (node);
+ return ((NODE *)NULL);
+ }
+ /* Readjust tag->nodestart. */
+ tag->nodestart = node_sep - subfile->contents;
+
+ /* Calculate the length of the current node. */
+ buff_end = subfile->contents + subfile->filesize;
+
+ node_body.buffer = node->contents;
+ node_body.start = 0;
+ node_body.end = buff_end - node_body.buffer;
+ node_body.flags = 0;
+ tag->nodelen = get_node_length (&node_body);
+ }
+ else
+ {
+ /* Since we know the length of this node, we have already
+ adjusted tag->nodestart to point to the exact start of
+ it. Simply skip the node separator. */
+ node->contents += skip_node_separator (node->contents);
+ }
+
+ node->nodelen = tag->nodelen;
+ return (node);
+ }
+ }
+
+ /* There was a tag table for this file, and the node wasn't found.
+ Return NULL, since this file doesn't contain the desired node. */
+ return ((NODE *)NULL);
+}
+
+/* **************************************************************** */
+/* */
+/* Managing file_buffers, nodes, and tags. */
+/* */
+/* **************************************************************** */
+
+static FILE_BUFFER *
+make_file_buffer ()
+{
+ FILE_BUFFER *file_buffer;
+
+ file_buffer = (FILE_BUFFER *)xmalloc (sizeof (FILE_BUFFER));
+ file_buffer->filename = file_buffer->fullpath = (char *)NULL;
+ file_buffer->contents = (char *)NULL;
+ file_buffer->tags = (TAG **)NULL;
+ file_buffer->subfiles = (char **)NULL;
+ file_buffer->tags_slots = 0;
+ file_buffer->flags = 0;
+
+ return (file_buffer);
+}
+
+/* Add FILE_BUFFER to our list of already loaded info files. */
+static void
+remember_info_file (file_buffer)
+ FILE_BUFFER *file_buffer;
+{
+ int i;
+
+ for (i = 0; info_loaded_files && info_loaded_files[i]; i++)
+ ;
+
+ add_pointer_to_array (file_buffer, i, info_loaded_files,
+ info_loaded_files_slots, 10, FILE_BUFFER *);
+}
+
+/* Forget the contents, tags table, nodes list, and names of FILENAME. */
+static void
+forget_info_file (filename)
+ char *filename;
+{
+ register int i;
+ FILE_BUFFER *file_buffer;
+
+ if (!info_loaded_files)
+ return;
+
+ for (i = 0; file_buffer = info_loaded_files[i]; i++)
+ if ((strcmp (filename, file_buffer->filename) == 0) ||
+ (strcmp (filename, file_buffer->fullpath) == 0))
+ {
+ free (file_buffer->filename);
+ free (file_buffer->fullpath);
+
+ if (file_buffer->contents)
+ free (file_buffer->contents);
+
+ /* Note that free_file_buffer_tags () also kills the subfiles
+ list, since the subfiles list is only of use in conjunction
+ with tags. */
+ free_file_buffer_tags (file_buffer);
+
+ while (info_loaded_files[i] = info_loaded_files[++i])
+ ;
+
+ break;
+ }
+}
+
+/* Free the tags (if any) associated with FILE_BUFFER. */
+static void
+free_file_buffer_tags (file_buffer)
+ FILE_BUFFER *file_buffer;
+{
+ register int i;
+
+ if (file_buffer->tags)
+ {
+ register TAG *tag;
+
+ for (i = 0; tag = file_buffer->tags[i]; i++)
+ free_info_tag (tag);
+
+ free (file_buffer->tags);
+ file_buffer->tags = (TAG **)NULL;
+ file_buffer->tags_slots = 0;
+ }
+
+ if (file_buffer->subfiles)
+ {
+ for (i = 0; file_buffer->subfiles[i]; i++)
+ free (file_buffer->subfiles[i]);
+
+ free (file_buffer->subfiles);
+ file_buffer->subfiles = (char **)NULL;
+ }
+}
+
+/* Free the data associated with TAG, as well as TAG itself. */
+static void
+free_info_tag (tag)
+ TAG *tag;
+{
+ free (tag->nodename);
+
+ /* We don't free tag->filename, because that filename is part of the
+ subfiles list for the containing FILE_BUFFER. free_info_tags ()
+ will free the subfiles when it is appropriate. */
+
+ free (tag);
+}
+
+/* Load the contents of FILE_BUFFER->contents. This function is called
+ when a file buffer was loaded, and then in order to conserve memory, the
+ file buffer's contents were freed and the pointer was zero'ed. Note that
+ the file was already loaded at least once successfully, so the tags and/or
+ nodes members are still correctly filled. */
+static void
+info_reload_file_buffer_contents (fb)
+ FILE_BUFFER *fb;
+{
+ fb->flags &= ~N_IsCompressed;
+
+ /* Let the filesystem do all the work for us. */
+ fb->contents =
+ filesys_read_info_file (fb->fullpath, &(fb->filesize), &(fb->finfo));
+ if (fb->filesize != fb->finfo.st_size)
+ fb->flags |= N_IsCompressed;
+}
+
+/* Return the actual starting memory location of NODE, side-effecting
+ NODE->contents. MIN and MAX are bounds for a search if one is necessary.
+ Because of the way that tags are implemented, the physical nodestart may
+ not actually be where the tag says it is. If that is the case, but the
+ node was found anyway, set N_UpdateTags in NODE->flags. If the node is
+ found, return non-zero. NODE->contents is returned positioned right after
+ the node separator that precedes this node, while the return value is
+ position directly on the separator that precedes this node. If the node
+ could not be found, return a NULL pointer. */
+static char *
+adjust_nodestart (node, min, max)
+ NODE *node;
+ int min, max;
+{
+ long position;
+ SEARCH_BINDING node_body;
+
+ /* Define the node body. */
+ node_body.buffer = node->contents;
+ node_body.start = 0;
+ node_body.end = max;
+ node_body.flags = 0;
+
+ /* Try the optimal case first. Who knows? This file may actually be
+ formatted (mostly) correctly. */
+ if (node_body.buffer[0] != INFO_COOKIE && min > 2)
+ node_body.buffer -= 3;
+
+ position = find_node_separator (&node_body);
+
+ /* If we found a node start, then check it out. */
+ if (position != -1)
+ {
+ int sep_len;
+
+ sep_len = skip_node_separator (node->contents);
+
+ /* If we managed to skip a node separator, then check for this node
+ being the right one. */
+ if (sep_len != 0)
+ {
+ char *nodedef, *nodestart;
+ int offset;
+
+ nodestart = node_body.buffer + position + sep_len;
+ nodedef = nodestart;
+ offset = string_in_line (INFO_NODE_LABEL, nodedef);
+
+ if (offset != -1)
+ {
+ nodedef += offset;
+ nodedef += skip_whitespace (nodedef);
+ offset = skip_node_characters (nodedef, DONT_SKIP_NEWLINES);
+ if ((offset == strlen (node->nodename)) &&
+ (strncmp (node->nodename, nodedef, offset) == 0))
+ {
+ node->contents = nodestart;
+ return (node_body.buffer + position);
+ }
+ }
+ }
+ }
+
+ /* Oh well, I guess we have to try to find it in a larger area. */
+ node_body.buffer = node->contents - min;
+ node_body.start = 0;
+ node_body.end = min + max;
+ node_body.flags = 0;
+
+ position = find_node_in_binding (node->nodename, &node_body);
+
+ /* If the node couldn't be found, we lose big. */
+ if (position == -1)
+ return ((char *)NULL);
+
+ /* Otherwise, the node was found, but the tags table could need updating
+ (if we used a tag to get here, that is). Set the flag in NODE->flags. */
+ node->contents = node_body.buffer + position;
+ node->contents += skip_node_separator (node->contents);
+ if (node->flags & N_HasTagsTable)
+ node->flags |= N_UpdateTags;
+ return (node_body.buffer + position);
+}
diff --git a/gnu/usr.bin/texinfo/info/nodes.h b/gnu/usr.bin/texinfo/info/nodes.h
new file mode 100644
index 0000000..1b8cee3
--- /dev/null
+++ b/gnu/usr.bin/texinfo/info/nodes.h
@@ -0,0 +1,164 @@
+/* nodes.h -- How we represent nodes internally. */
+
+/* This file is part of GNU Info, a program for reading online documentation
+ stored in Info format.
+
+ Copyright (C) 1993 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ Written by Brian Fox (bfox@ai.mit.edu). */
+
+#ifndef _NODES_H_
+#define _NODES_H_
+
+#include "general.h"
+
+/* **************************************************************** */
+/* */
+/* User Code Interface */
+/* */
+/* **************************************************************** */
+
+/* Callers generally only want the node itself. This structure is used
+ to pass node information around. None of the information in this
+ structure should ever be directly freed. The structure itself can
+ be passed to free (). Note that NODE->parent is non-null if this
+ node's file is a subfile. In that case, NODE->parent is the logical
+ name of the file containing this node. Both names are given as full
+ paths, so you might have: node->filename = "/usr/gnu/info/emacs-1",
+ with node->parent = "/usr/gnu/info/emacs". */
+typedef struct {
+ char *filename; /* The physical file containing this node. */
+ char *parent; /* Non-null is the logical file name. */
+ char *nodename; /* The name of this node. */
+ char *contents; /* Characters appearing in this node. */
+ long nodelen; /* The length of the CONTENTS member. */
+ int flags; /* See immediately below. */
+} NODE;
+
+/* Defines that can appear in NODE->flags. All informative. */
+#define N_HasTagsTable 0x01 /* This node was found through a tags table. */
+#define N_TagsIndirect 0x02 /* The tags table was an indirect one. */
+#define N_UpdateTags 0x04 /* The tags table is out of date. */
+#define N_IsCompressed 0x08 /* The file is compressed on disk. */
+#define N_IsInternal 0x10 /* This node was made by Info. */
+#define N_CannotGC 0x20 /* File buffer cannot be gc'ed. */
+
+/* **************************************************************** */
+/* */
+/* Internal Data Structures */
+/* */
+/* **************************************************************** */
+
+/* Some defines describing details about Info file contents. */
+
+/* String Constants. */
+#define INFO_FILE_LABEL "File:"
+#define INFO_NODE_LABEL "Node:"
+#define INFO_PREV_LABEL "Prev:"
+#define INFO_ALTPREV_LABEL "Previous:"
+#define INFO_NEXT_LABEL "Next:"
+#define INFO_UP_LABEL "Up:"
+#define INFO_MENU_LABEL "\n* Menu:"
+#define INFO_MENU_ENTRY_LABEL "\n* "
+#define INFO_XREF_LABEL "*Note"
+#define TAGS_TABLE_END_LABEL "\nEnd Tag Table"
+#define TAGS_TABLE_BEG_LABEL "Tag Table:\n"
+#define INDIRECT_TAGS_TABLE_LABEL "Indirect:\n"
+#define TAGS_TABLE_IS_INDIRECT_LABEL "(Indirect)"
+
+/* Character Constants. */
+#define INFO_COOKIE '\037'
+#define INFO_FF '\014'
+#define INFO_TAGSEP '\177'
+
+/* For each logical file that we have loaded, we keep a list of the names
+ of the nodes that are found in that file. A pointer to a node in an
+ info file is called a "tag". For split files, the tag pointer is
+ "indirect"; that is, the pointer also contains the name of the split
+ file where the node can be found. For non-split files, the filename
+ member in the structure below simply contains the name of the current
+ file. The following structure describes a single node within a file. */
+typedef struct {
+ char *filename; /* The file where this node can be found. */
+ char *nodename; /* The node pointed to by this tag. */
+ long nodestart; /* The offset of the start of this node. */
+ long nodelen; /* The length of this node. */
+} TAG;
+
+/* The following structure is used to remember information about the contents
+ of Info files that we have loaded at least once before. The FINFO member
+ is present so that we can reload the file if it has been modified since
+ last being loaded. All of the arrays appearing within this structure
+ are NULL terminated, and each array which can change size has a
+ corresponding SLOTS member which says how many slots have been allocated
+ (with malloc ()) for this array. */
+typedef struct {
+ char *filename; /* The filename used to find this file. */
+ char *fullpath; /* The full pathname of this info file. */
+ struct stat finfo; /* Information about this file. */
+ char *contents; /* The contents of this particular file. */
+ long filesize; /* The number of bytes this file expands to. */
+ char **subfiles; /* If non-null, the list of subfiles. */
+ TAG **tags; /* If non-null, the indirect tags table. */
+ int tags_slots; /* Number of slots allocated for TAGS. */
+ int flags; /* Various flags. Mimics of N_* flags. */
+} FILE_BUFFER;
+
+/* **************************************************************** */
+/* */
+/* Externally Visible Functions */
+/* */
+/* **************************************************************** */
+
+/* Array of FILE_BUFFER * which represents the currently loaded info files. */
+extern FILE_BUFFER **info_loaded_files;
+
+/* The number of slots currently allocated to INFO_LOADED_FILES. */
+extern int info_loaded_files_slots;
+
+/* Locate the file named by FILENAME, and return the information structure
+ describing this file. The file may appear in our list of loaded files
+ already, or it may not. If it does not already appear, find the file,
+ and add it to the list of loaded files. If the file cannot be found,
+ return a NULL FILE_BUFFER *. */
+extern FILE_BUFFER *info_find_file ();
+
+/* Force load the file named FILENAME, and return the information structure
+ describing this file. Even if the file was already loaded, this loads
+ a new buffer, rebuilds tags and nodes, and returns a new FILE_BUFFER *. */
+extern FILE_BUFFER *info_load_file ();
+
+/* Return a pointer to a NODE structure for the Info node (FILENAME)NODENAME.
+ FILENAME can be passed as NULL, in which case the filename of "dir" is used.
+ NODENAME can be passed as NULL, in which case the nodename of "Top" is used.
+ If the node cannot be found, return a NULL pointer. */
+extern NODE *info_get_node ();
+
+/* Return a pointer to a NODE structure for the Info node NODENAME in
+ FILE_BUFFER. NODENAME can be passed as NULL, in which case the
+ nodename of "Top" is used. If the node cannot be found, return a
+ NULL pointer. */
+extern NODE *info_get_node_of_file_buffer ();
+
+/* Grovel FILE_BUFFER->contents finding tags and nodes, and filling in the
+ various slots. This can also be used to rebuild a tag or node table. */
+extern void build_tags_and_nodes ();
+
+/* When non-zero, this is a string describing the most recent file error. */
+extern char *info_recent_file_error;
+
+#endif /* !_NODES_H_ */
diff --git a/gnu/usr.bin/texinfo/info/search.c b/gnu/usr.bin/texinfo/info/search.c
new file mode 100644
index 0000000..d214f9d
--- /dev/null
+++ b/gnu/usr.bin/texinfo/info/search.c
@@ -0,0 +1,566 @@
+/* search.c -- How to search large bodies of text. */
+
+/* This file is part of GNU Info, a program for reading online documentation
+ stored in Info format.
+
+ Copyright (C) 1993 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ Written by Brian Fox (bfox@ai.mit.edu). */
+
+#include <ctype.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include "general.h"
+#include "search.h"
+#include "nodes.h"
+
+#if !defined (NULL)
+# define NULL 0x0
+#endif /* !NULL */
+
+/* The search functions take two arguments:
+
+ 1) a string to search for, and
+
+ 2) a pointer to a SEARCH_BINDING which contains the buffer, start,
+ and end of the search.
+
+ They return a long, which is the offset from the start of the buffer
+ at which the match was found. An offset of -1 indicates failure. */
+
+/* A function which makes a binding with buffer and bounds. */
+SEARCH_BINDING *
+make_binding (buffer, start, end)
+ char *buffer;
+ long start, end;
+{
+ SEARCH_BINDING *binding;
+
+ binding = (SEARCH_BINDING *)xmalloc (sizeof (SEARCH_BINDING));
+ binding->buffer = buffer;
+ binding->start = start;
+ binding->end = end;
+ binding->flags = 0;
+
+ return (binding);
+}
+
+/* Make a copy of BINDING without duplicating the data. */
+SEARCH_BINDING *
+copy_binding (binding)
+ SEARCH_BINDING *binding;
+{
+ SEARCH_BINDING *copy;
+
+ copy = make_binding (binding->buffer, binding->start, binding->end);
+ copy->flags = binding->flags;
+ return (copy);
+}
+
+
+/* **************************************************************** */
+/* */
+/* The Actual Searching Functions */
+/* */
+/* **************************************************************** */
+
+/* Search forwards or backwards for the text delimited by BINDING.
+ The search is forwards if BINDING->start is greater than BINDING->end. */
+long
+search (string, binding)
+ char *string;
+ SEARCH_BINDING *binding;
+{
+ long result;
+
+ /* If the search is backwards, then search backwards, otherwise forwards. */
+ if (binding->start > binding->end)
+ result = search_backward (string, binding);
+ else
+ result = search_forward (string, binding);
+
+ return (result);
+}
+
+/* Search forwards for STRING through the text delimited in BINDING. */
+long
+search_forward (string, binding)
+ char *string;
+ SEARCH_BINDING *binding;
+{
+ register int c, i, len;
+ register char *buff, *end;
+ char *alternate = (char *)NULL;
+
+ len = strlen (string);
+
+ /* We match characters in the search buffer against STRING and ALTERNATE.
+ ALTERNATE is a case reversed version of STRING; this is cheaper than
+ case folding each character before comparison. Alternate is only
+ used if the case folding bit is turned on in the passed BINDING. */
+
+ if (binding->flags & S_FoldCase)
+ {
+ alternate = savestring (string);
+
+ for (i = 0; i < len; i++)
+ {
+ if (islower (alternate[i]))
+ alternate[i] = toupper (alternate[i]);
+ else if (isupper (alternate[i]))
+ alternate[i] = tolower (alternate[i]);
+ }
+ }
+
+ buff = binding->buffer + binding->start;
+ end = binding->buffer + binding->end + 1;
+
+ while (buff < (end - len))
+ {
+ for (i = 0; i < len; i++)
+ {
+ c = buff[i];
+
+ if ((c != string[i]) && (!alternate || c != alternate[i]))
+ break;
+ }
+
+ if (!string[i])
+ {
+ if (alternate)
+ free (alternate);
+ if (binding->flags & S_SkipDest)
+ buff += len;
+ return ((long) (buff - binding->buffer));
+ }
+
+ buff++;
+ }
+
+ if (alternate)
+ free (alternate);
+
+ return ((long) -1);
+}
+
+/* Search for STRING backwards through the text delimited in BINDING. */
+long
+search_backward (input_string, binding)
+ char *input_string;
+ SEARCH_BINDING *binding;
+{
+ register int c, i, len;
+ register char *buff, *end;
+ char *string;
+ char *alternate = (char *)NULL;
+
+ len = strlen (input_string);
+
+ /* Reverse the characters in the search string. */
+ string = (char *)xmalloc (1 + len);
+ for (c = 0, i = len - 1; input_string[c]; c++, i--)
+ string[i] = input_string[c];
+
+ string[c] = '\0';
+
+ /* We match characters in the search buffer against STRING and ALTERNATE.
+ ALTERNATE is a case reversed version of STRING; this is cheaper than
+ case folding each character before comparison. ALTERNATE is only
+ used if the case folding bit is turned on in the passed BINDING. */
+
+ if (binding->flags & S_FoldCase)
+ {
+ alternate = savestring (string);
+
+ for (i = 0; i < len; i++)
+ {
+ if (islower (alternate[i]))
+ alternate[i] = toupper (alternate[i]);
+ else if (isupper (alternate[i]))
+ alternate[i] = tolower (alternate[i]);
+ }
+ }
+
+ buff = binding->buffer + binding->start;
+ end = binding->buffer + binding->end;
+
+ while (buff > end + len)
+ {
+ for (i = 0; i < len; i++)
+ {
+ c = *(buff - i);
+
+ if (c != string[i] && (alternate && c != alternate[i]))
+ break;
+ }
+
+ if (!string[i])
+ {
+ free (string);
+ if (alternate)
+ free (alternate);
+
+ if (binding->flags & S_SkipDest)
+ buff -= len;
+ return ((long) (1 + (buff - binding->buffer)));
+ }
+
+ buff--;
+ }
+
+ free (string);
+ if (alternate)
+ free (alternate);
+
+ return ((long) -1);
+}
+
+/* Find STRING in LINE, returning the offset of the end of the string.
+ Return an offset of -1 if STRING does not appear in LINE. The search
+ is bound by the end of the line (i.e., either NEWLINE or 0). */
+int
+string_in_line (string, line)
+ char *string, *line;
+{
+ register int end;
+ SEARCH_BINDING binding;
+
+ /* Find the end of the line. */
+ for (end = 0; line[end] && line[end] != '\n'; end++);
+
+ /* Search for STRING within these confines. */
+ binding.buffer = line;
+ binding.start = 0;
+ binding.end = end;
+ binding.flags = S_FoldCase | S_SkipDest;
+
+ return (search_forward (string, &binding));
+}
+
+/* Return non-zero if STRING is the first text to appear at BINDING. */
+int
+looking_at (string, binding)
+ char *string;
+ SEARCH_BINDING *binding;
+{
+ long search_end;
+
+ search_end = search (string, binding);
+
+ /* If the string was not found, SEARCH_END is -1. If the string was found,
+ but not right away, SEARCH_END is != binding->start. Otherwise, the
+ string was found at binding->start. */
+ return (search_end == binding->start);
+}
+
+/* **************************************************************** */
+/* */
+/* Small String Searches */
+/* */
+/* **************************************************************** */
+
+/* Function names that start with "skip" are passed a string, and return
+ an offset from the start of that string. Function names that start
+ with "find" are passed a SEARCH_BINDING, and return an absolute position
+ marker of the item being searched for. "Find" functions return a value
+ of -1 if the item being looked for couldn't be found. */
+
+/* Return the index of the first non-whitespace character in STRING. */
+int
+skip_whitespace (string)
+ char *string;
+{
+ register int i;
+
+ for (i = 0; string && whitespace (string[i]); i++);
+ return (i);
+}
+
+/* Return the index of the first non-whitespace or newline character in
+ STRING. */
+int
+skip_whitespace_and_newlines (string)
+ char *string;
+{
+ register int i;
+
+ for (i = 0; string && (whitespace (string[i]) || string[i] == '\n'); i++);
+ return (i);
+}
+
+/* Return the index of the first whitespace character in STRING. */
+int
+skip_non_whitespace (string)
+ char *string;
+{
+ register int i;
+
+ for (i = 0; string && !whitespace (string[i]); i++);
+ return (i);
+}
+
+/* Return the index of the first non-node character in STRING. Note that
+ this function contains quite a bit of hair to ignore periods in some
+ special cases. This is because we here at GNU ship some info files which
+ contain nodenames that contain periods. No such nodename can start with
+ a period, or continue with whitespace, newline, or ')' immediately following
+ the period. If second argument NEWLINES_OKAY is non-zero, newlines should
+ be skipped while parsing out the nodename specification. */
+int
+skip_node_characters (string, newlines_okay)
+ char *string;
+ int newlines_okay;
+{
+ register int c, i = 0;
+ int paren_seen = 0;
+ int paren = 0;
+
+ /* Handle special case. This is when another function has parsed out the
+ filename component of the node name, and we just want to parse out the
+ nodename proper. In that case, a period at the start of the nodename
+ indicates an empty nodename. */
+ if (string && *string == '.')
+ return (0);
+
+ if (string && *string == '(')
+ {
+ paren++;
+ paren_seen++;
+ i++;
+ }
+
+ for (; string && (c = string[i]); i++)
+ {
+ if (paren)
+ {
+ if (c == '(')
+ paren++;
+ else if (c == ')')
+ paren--;
+
+ continue;
+ }
+
+ /* If the character following the close paren is a space or period,
+ then this node name has no more characters associated with it. */
+ if (c == '\t' ||
+ c == ',' ||
+ c == INFO_TAGSEP ||
+ ((!newlines_okay) && (c == '\n')) ||
+ ((paren_seen && string[i - 1] == ')') &&
+ (c == ' ' || c == '.')) ||
+ (c == '.' &&
+ ((!string[i + 1]) ||
+ (whitespace_or_newline (string[i + 1])) ||
+ (string[i + 1] == ')'))))
+ break;
+ }
+ return (i);
+}
+
+/* Unix doesn't have stricmp () functions. */
+int
+stricmp (string1, string2)
+ char *string1, *string2;
+{
+ char ch1, ch2;
+
+ for (;;)
+ {
+ ch1 = *string1++;
+ ch2 = *string2++;
+
+ if (!(ch1 | ch2))
+ return (0);
+
+ ch1 = info_toupper (ch1);
+ ch2 = info_toupper (ch2);
+
+ if (ch1 != ch2)
+ return (ch1 - ch2);
+ }
+}
+
+/* Compare at most COUNT characters from string1 to string2. Case
+ doesn't matter. */
+int
+strnicmp (string1, string2, count)
+ char *string1, *string2;
+ int count;
+{
+ register char ch1, ch2;
+
+ while (count)
+ {
+ ch1 = *string1++;
+ ch2 = *string2++;
+
+ ch1 = info_toupper (ch1);
+ ch2 = info_toupper (ch2);
+
+ if (ch1 == ch2)
+ count--;
+ else
+ break;
+ }
+ return (count);
+}
+
+/* **************************************************************** */
+/* */
+/* Searching FILE_BUFFER's */
+/* */
+/* **************************************************************** */
+
+/* Return the absolute position of the first occurence of a node separator in
+ BINDING-buffer. The search starts at BINDING->start. Return -1 if no node
+ separator was found. */
+long
+find_node_separator (binding)
+ SEARCH_BINDING *binding;
+{
+ register long i;
+ char *body;
+
+ body = binding->buffer;
+
+ /* A node is started by [^L]^_[^L]\n. That is to say, the C-l's are
+ optional, but the DELETE and NEWLINE are not. This separator holds
+ true for all separated elements in an Info file, including the tags
+ table (if present) and the indirect tags table (if present). */
+ for (i = binding->start; i < binding->end - 1; i++)
+ if (((body[i] == INFO_FF && body[i + 1] == INFO_COOKIE) &&
+ (body[i + 2] == '\n' ||
+ (body[i + 2] == INFO_FF && body[i + 3] == '\n'))) ||
+ ((body[i] == INFO_COOKIE) &&
+ (body[i + 1] == '\n' ||
+ (body[i + 1] == INFO_FF && body[i + 2] == '\n'))))
+ return (i);
+ return (-1);
+}
+
+/* Return the length of the node separator characters that BODY is
+ currently pointing at. */
+int
+skip_node_separator (body)
+ char *body;
+{
+ register int i;
+
+ i = 0;
+
+ if (body[i] == INFO_FF)
+ i++;
+
+ if (body[i++] != INFO_COOKIE)
+ return (0);
+
+ if (body[i] == INFO_FF)
+ i++;
+
+ if (body[i++] != '\n')
+ return (0);
+
+ return (i);
+}
+
+/* Return the number of characters from STRING to the start of
+ the next line. */
+int
+skip_line (string)
+ char *string;
+{
+ register int i;
+
+ for (i = 0; string && string[i] && string[i] != '\n'; i++);
+
+ if (string[i] == '\n')
+ i++;
+
+ return (i);
+}
+
+/* Return the absolute position of the beginning of a tags table in this
+ binding starting the search at binding->start. */
+long
+find_tags_table (binding)
+ SEARCH_BINDING *binding;
+{
+ SEARCH_BINDING search;
+ long position;
+
+ search.buffer = binding->buffer;
+ search.start = binding->start;
+ search.end = binding->end;
+ search.flags = S_FoldCase;
+
+ while ((position = find_node_separator (&search)) != -1 )
+ {
+ search.start = position;
+ search.start += skip_node_separator (search.buffer + search.start);
+
+ if (looking_at (TAGS_TABLE_BEG_LABEL, &search))
+ return (position);
+ }
+ return (-1);
+}
+
+/* Return the absolute position of the node named NODENAME in BINDING.
+ This is a brute force search, and we wish to avoid it when possible.
+ This function is called when a tag (indirect or otherwise) doesn't
+ really point to the right node. It returns the absolute position of
+ the separator preceding the node. */
+long
+find_node_in_binding (nodename, binding)
+ char *nodename;
+ SEARCH_BINDING *binding;
+{
+ register long position;
+ register int offset, namelen;
+ SEARCH_BINDING search;
+
+ namelen = strlen (nodename);
+
+ search.buffer = binding->buffer;
+ search.start = binding->start;
+ search.end = binding->end;
+ search.flags = 0;
+
+ while ((position = find_node_separator (&search)) != -1)
+ {
+ search.start = position;
+ search.start += skip_node_separator (search.buffer + search.start);
+
+ offset = string_in_line (INFO_NODE_LABEL, search.buffer + search.start);
+
+ if (offset == -1)
+ continue;
+
+ search.start += offset;
+ search.start += skip_whitespace (search.buffer + search.start);
+ offset = skip_node_characters
+ (search.buffer + search.start, DONT_SKIP_NEWLINES);
+
+ /* Notice that this is an exact match. You cannot grovel through
+ the buffer with this function looking for random nodes. */
+ if ((offset == namelen) &&
+ (search.buffer[search.start] == nodename[0]) &&
+ (strncmp (search.buffer + search.start, nodename, offset) == 0))
+ return (position);
+ }
+ return (-1);
+}
diff --git a/gnu/usr.bin/texinfo/info/search.h b/gnu/usr.bin/texinfo/info/search.h
new file mode 100644
index 0000000..cc1cada
--- /dev/null
+++ b/gnu/usr.bin/texinfo/info/search.h
@@ -0,0 +1,78 @@
+/* search.h -- Structure used to search large bodies of text, with bounds. */
+
+/* This file is part of GNU Info, a program for reading online documentation
+ stored in Info format.
+
+ Copyright (C) 1993 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ Written by Brian Fox (bfox@ai.mit.edu). */
+
+/* The search functions take two arguments:
+
+ 1) a string to search for, and
+
+ 2) a pointer to a SEARCH_BINDING which contains the buffer, start,
+ and end of the search.
+
+ They return a long, which is the offset from the start of the buffer
+ at which the match was found. An offset of -1 indicates failure. */
+
+#ifndef _SEARCH_H_
+#define _SEARCH_H_
+
+typedef struct {
+ char *buffer; /* The buffer of text to search. */
+ long start; /* Offset of the start of the search. */
+ long end; /* Offset of the end of the searh. */
+ int flags; /* Flags controlling the type of search. */
+} SEARCH_BINDING;
+
+#define S_FoldCase 0x01 /* Set means fold case in searches. */
+#define S_SkipDest 0x02 /* Set means return pointing after the dest. */
+
+SEARCH_BINDING *make_binding (), *copy_binding ();
+extern long search_forward (), search_backward (), search ();
+extern int looking_at ();
+
+/* Note that STRING_IN_LINE () always returns the offset of the 1st character
+ after the string. */
+extern int string_in_line ();
+
+/* Unix doesn't have stricmp () functions. */
+/* strcmp (), but caseless. */
+extern int stricmp ();
+
+/* Compare at most COUNT characters from STRING1 to STRING2. Case
+ doesn't matter. */
+extern int strnicmp ();
+
+/* Function names that start with "skip" are passed a string, and return
+ an offset from the start of that string. Function names that start
+ with "find" are passed a SEARCH_BINDING, and return an absolute position
+ marker of the item being searched for. "Find" functions return a value
+ of -1 if the item being looked for couldn't be found. */
+extern int skip_whitespace (), skip_non_whitespace ();
+extern int skip_whitespace_and_newlines (), skip_line ();
+extern int skip_node_characters (), skip_node_separator ();
+#define DONT_SKIP_NEWLINES 0
+#define SKIP_NEWLINES 1
+
+extern long find_node_separator (), find_tags_table ();
+extern long find_node_in_binding ();
+
+#endif /* !_SEARCH_H_ */
+
diff --git a/gnu/usr.bin/texinfo/info/session.c b/gnu/usr.bin/texinfo/info/session.c
new file mode 100644
index 0000000..b1e4297
--- /dev/null
+++ b/gnu/usr.bin/texinfo/info/session.c
@@ -0,0 +1,4168 @@
+/* session.c -- The user windowing interface to Info. */
+
+/* This file is part of GNU Info, a program for reading online documentation
+ stored in Info format.
+
+ Copyright (C) 1993 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ Written by Brian Fox (bfox@ai.mit.edu). */
+
+#include "info.h"
+#include <sys/file.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+#include <stdlib.h>
+
+#if defined (HAVE_SYS_TIME_H)
+# include <sys/time.h>
+# define HAVE_STRUCT_TIMEVAL
+#endif /* HAVE_SYS_TIME_H */
+
+static void info_clear_pending_input (), info_set_pending_input ();
+static void info_handle_pointer ();
+
+/* **************************************************************** */
+/* */
+/* Running an Info Session */
+/* */
+/* **************************************************************** */
+
+/* The place that we are reading input from. */
+static FILE *info_input_stream = (FILE *)NULL;
+
+/* The last executed command. */
+VFunction *info_last_executed_command = (VFunction *)NULL;
+
+/* Becomes non-zero when 'q' is typed to an Info window. */
+int quit_info_immediately = 0;
+
+/* Array of structures describing for each window which nodes have been
+ visited in that window. */
+INFO_WINDOW **info_windows = (INFO_WINDOW **)NULL;
+
+/* Where to add the next window, if we need to add one. */
+static int info_windows_index = 0;
+
+/* Number of slots allocated to INFO_WINDOWS. */
+static int info_windows_slots = 0;
+
+void remember_window_and_node (), forget_window_and_nodes ();
+void initialize_info_session (), info_session ();
+void display_startup_message_and_start ();
+
+/* Begin an info session finding the nodes specified by FILENAME and NODENAMES.
+ For each loaded node, create a new window. Always split the largest of the
+ available windows. */
+void
+begin_multiple_window_info_session (filename, nodenames)
+ char *filename;
+ char **nodenames;
+{
+ register int i;
+ WINDOW *window = (WINDOW *)NULL;
+
+ for (i = 0; nodenames[i]; i++)
+ {
+ NODE *node;
+
+ node = info_get_node (filename, nodenames[i]);
+
+ if (!node)
+ break;
+
+ /* If this is the first node, initialize the info session. */
+ if (!window)
+ {
+ initialize_info_session (node);
+ window = active_window;
+ }
+ else
+ {
+ /* Find the largest window in WINDOWS, and make that be the active
+ one. Then split it and add our window and node to the list
+ of remembered windows and nodes. Then tile the windows. */
+ register WINDOW *win, *largest = (WINDOW *)NULL;
+ int max_height = 0;
+
+ for (win = windows; win; win = win->next)
+ if (win->height > max_height)
+ {
+ max_height = win->height;
+ largest = win;
+ }
+
+ if (!largest)
+ {
+ display_update_display (windows);
+ info_error (CANT_FIND_WIND);
+ info_session ();
+ exit (0);
+ }
+
+ active_window = largest;
+ window = window_make_window (node);
+ if (window)
+ {
+ window_tile_windows (TILE_INTERNALS);
+ remember_window_and_node (window, node);
+ }
+ else
+ {
+ display_update_display (windows);
+ info_error (WIN_TOO_SMALL);
+ info_session ();
+ exit (0);
+ }
+ }
+ }
+ display_startup_message_and_start ();
+}
+
+/* Start an info session with INITIAL_NODE, and an error message in the echo
+ area made from FORMAT and ARG. */
+void
+begin_info_session_with_error (initial_node, format, arg)
+ NODE *initial_node;
+ char *format;
+ void *arg;
+{
+ initialize_info_session (initial_node);
+ info_error (format, arg, (void *)NULL);
+ info_session ();
+}
+
+/* Start an info session with INITIAL_NODE. */
+void
+begin_info_session (initial_node)
+ NODE *initial_node;
+{
+ initialize_info_session (initial_node);
+ display_startup_message_and_start ();
+}
+
+void
+display_startup_message_and_start ()
+{
+ char *format;
+
+ format = replace_in_documentation
+ ("Welcome to Info version %s. Type \"\\[get-help-window]\" for help.");
+
+ window_message_in_echo_area (format, version_string ());
+ info_session ();
+}
+
+/* Run an info session with an already initialized window and node. */
+void
+info_session ()
+{
+ terminal_prep_terminal ();
+ display_update_display (windows);
+ info_last_executed_command = (VFunction *)NULL;
+ info_read_and_dispatch ();
+ terminal_unprep_terminal ();
+ close_dribble_file ();
+}
+
+/* Here is a window-location dependent event loop. Called from the
+ functions info_session (), and from read_xxx_in_echo_area (). */
+void
+info_read_and_dispatch ()
+{
+ unsigned char key;
+ int done;
+ done = 0;
+
+ while (!done && !quit_info_immediately)
+ {
+ int lk;
+
+ /* If we haven't just gone up or down a line, there is no
+ goal column for this window. */
+ if ((info_last_executed_command != info_next_line) &&
+ (info_last_executed_command != info_prev_line))
+ active_window->goal_column = -1;
+
+ if (echo_area_is_active)
+ {
+ lk = echo_area_last_command_was_kill;
+ echo_area_prep_read ();
+ }
+
+ if (!info_any_buffered_input_p ())
+ display_update_display (windows);
+
+ display_cursor_at_point (active_window);
+ info_initialize_numeric_arg ();
+
+ initialize_keyseq ();
+ key = info_get_input_char ();
+
+ /* No errors yet. We just read a character, that's all. Only clear
+ the echo_area if it is not currently active. */
+ if (!echo_area_is_active)
+ window_clear_echo_area ();
+
+ info_error_was_printed = 0;
+
+ /* Do the selected command. */
+ info_dispatch_on_key (key, active_window->keymap);
+
+ if (echo_area_is_active)
+ {
+ /* Echo area commands that do killing increment the value of
+ ECHO_AREA_LAST_COMMAND_WAS_KILL. Thus, if there is no
+ change in the value of this variable, the last command
+ executed was not a kill command. */
+ if (lk == echo_area_last_command_was_kill)
+ echo_area_last_command_was_kill = 0;
+
+ if (ea_last_executed_command == ea_newline ||
+ info_aborted_echo_area)
+ {
+ ea_last_executed_command = (VFunction *)NULL;
+ done = 1;
+ }
+
+ if (info_last_executed_command == info_quit)
+ quit_info_immediately = 1;
+ }
+ else if (info_last_executed_command == info_quit)
+ done = 1;
+ }
+}
+
+/* Found in signals.c */
+extern void initialize_info_signal_handler ();
+
+/* Initialize the first info session by starting the terminal, window,
+ and display systems. */
+void
+initialize_info_session (node)
+ NODE *node;
+{
+ char *getenv (), *term_name;
+
+ term_name = getenv ("TERM");
+ terminal_initialize_terminal (term_name);
+
+ if (terminal_is_dumb_p)
+ {
+ if (!term_name)
+ term_name = "dumb";
+
+ info_error (TERM_TOO_DUMB, term_name);
+ exit (1);
+ }
+ terminal_clear_screen ();
+ initialize_info_keymaps ();
+ window_initialize_windows (screenwidth, screenheight);
+ initialize_info_signal_handler ();
+ display_initialize_display (screenwidth, screenheight);
+ info_set_node_of_window (active_window, node);
+
+ /* Tell the window system how to notify us when a window needs to be
+ asynchronously deleted (e.g., user resizes window very small). */
+ window_deletion_notifier = forget_window_and_nodes;
+
+ /* If input has not been redirected yet, make it come from STDIN. */
+ if (!info_input_stream)
+ info_input_stream = stdin;
+
+ info_windows_initialized_p = 1;
+}
+
+/* Tell Info that input is coming from the file FILENAME. */
+void
+info_set_input_from_file (filename)
+ char *filename;
+{
+ FILE *stream;
+
+ stream = fopen (filename, "r");
+
+ if (!stream)
+ return;
+
+ if (info_input_stream != stdin)
+ fclose (info_input_stream);
+
+ info_input_stream = stream;
+
+ if (stream != stdin)
+ display_inhibited = 1;
+}
+
+/* Return the INFO_WINDOW containing WINDOW, or NULL if there isn't one. */
+static INFO_WINDOW *
+get_info_window_of_window (window)
+ WINDOW *window;
+{
+ register int i;
+ INFO_WINDOW *info_win = (INFO_WINDOW *)NULL;
+
+ for (i = 0; info_windows && (info_win = info_windows[i]); i++)
+ if (info_win->window == window)
+ break;
+
+ return (info_win);
+}
+
+/* Reset the remembered pagetop and point of WINDOW to WINDOW's current
+ values if the window and node are the same as the current one being
+ displayed. */
+void
+set_remembered_pagetop_and_point (window)
+ WINDOW *window;
+{
+ INFO_WINDOW *info_win;
+
+ info_win = get_info_window_of_window (window);
+
+ if (!info_win)
+ return;
+
+ if (info_win->nodes_index &&
+ (info_win->nodes[info_win->current] == window->node))
+ {
+ info_win->pagetops[info_win->current] = window->pagetop;
+ info_win->points[info_win->current] = window->point;
+ }
+}
+
+void
+remember_window_and_node (window, node)
+ WINDOW *window;
+ NODE *node;
+{
+ INFO_WINDOW *info_win;
+
+ /* See if we already have this window in our list. */
+ info_win = get_info_window_of_window (window);
+
+ /* If the window wasn't already on our list, then make a new entry. */
+ if (!info_win)
+ {
+ info_win = (INFO_WINDOW *)xmalloc (sizeof (INFO_WINDOW));
+ info_win->window = window;
+ info_win->nodes = (NODE **)NULL;
+ info_win->pagetops = (int *)NULL;
+ info_win->points = (long *)NULL;
+ info_win->current = 0;
+ info_win->nodes_index = 0;
+ info_win->nodes_slots = 0;
+
+ add_pointer_to_array (info_win, info_windows_index, info_windows,
+ info_windows_slots, 10, INFO_WINDOW *);
+ }
+
+ /* If this node, the current pagetop, and the current point are the
+ same as the last saved node and pagetop, don't really add this to
+ the list of history nodes. */
+ {
+ int ni = info_win->nodes_index - 1;
+
+ if ((ni != -1) &&
+ (info_win->nodes[ni]->contents == node->contents) &&
+ (info_win->pagetops[ni] == window->pagetop) &&
+ (info_win->points[ni] == window->point))
+ return;
+ }
+
+ /* Remember this node, the currently displayed pagetop, and the current
+ location of point in this window. Because we are updating pagetops
+ and points as well as nodes, it is more efficient to avoid the
+ add_pointer_to_array macro here. */
+ if (info_win->nodes_index + 2 >= info_win->nodes_slots)
+ {
+ info_win->nodes = (NODE **)
+ xrealloc (info_win->nodes,
+ (info_win->nodes_slots += 20) * sizeof (NODE *));
+
+ info_win->pagetops = (int *)
+ xrealloc (info_win->pagetops, info_win->nodes_slots * sizeof (int));
+
+ info_win->points = (long *)
+ xrealloc (info_win->points, info_win->nodes_slots * sizeof (long));
+ }
+
+ info_win->nodes[info_win->nodes_index] = node;
+ info_win->pagetops[info_win->nodes_index] = window->pagetop;
+ info_win->points[info_win->nodes_index] = window->point;
+ info_win->current = info_win->nodes_index++;
+ info_win->nodes[info_win->nodes_index] = (NODE *)NULL;
+ info_win->pagetops[info_win->nodes_index] = 0;
+ info_win->points[info_win->nodes_index] = 0;
+}
+
+#define DEBUG_FORGET_WINDOW_AND_NODES
+#if defined (DEBUG_FORGET_WINDOW_AND_NODES)
+static void
+consistency_check_info_windows ()
+{
+ register int i;
+ INFO_WINDOW *info_win;
+
+ for (i = 0; i < info_windows_index; i++)
+ {
+ WINDOW *win;
+
+ for (win = windows; win; win = win->next)
+ if (win == info_windows[i]->window)
+ break;
+
+ if (!win)
+ abort ();
+ }
+}
+#endif /* DEBUG_FORGET_WINDOW_AND_NODES */
+
+/* Remove WINDOW and its associated list of nodes from INFO_WINDOWS. */
+void
+forget_window_and_nodes (window)
+ WINDOW *window;
+{
+ register int i;
+ INFO_WINDOW *info_win = (INFO_WINDOW *)NULL;
+
+ for (i = 0; info_windows && (info_win = info_windows[i]); i++)
+ if (info_win->window == window)
+ break;
+
+ /* If we found the window to forget, then do so. */
+ if (info_win)
+ {
+ while (i < info_windows_index)
+ info_windows[i] = info_windows[++i];
+
+ info_windows_index--;
+ info_windows[info_windows_index] = (INFO_WINDOW *)NULL;
+
+ if (info_win->nodes)
+ {
+ for (i = 0; info_win->nodes[i]; i++)
+ if (internal_info_node_p (info_win->nodes[i]))
+ free (info_win->nodes[i]);
+ free (info_win->nodes);
+
+ maybe_free (info_win->pagetops);
+ maybe_free (info_win->points);
+ }
+
+ free (info_win);
+ }
+#if defined (DEBUG_FORGET_WINDOW_AND_NODES)
+ consistency_check_info_windows ();
+#endif /* DEBUG_FORGET_WINDOW_AND_NODES */
+}
+
+/* Set WINDOW to show NODE. Remember the new window in our list of Info
+ windows. If we are doing automatic footnote display, also try to display
+ the footnotes for this window. */
+void
+info_set_node_of_window (window, node)
+ WINDOW *window;
+ NODE *node;
+{
+ /* Put this node into the window. */
+ window_set_node_of_window (window, node);
+
+ /* Remember this node and window in our list of info windows. */
+ remember_window_and_node (window, node);
+
+ /* If doing auto-footnote display/undisplay, show the footnotes belonging
+ to this window's node. */
+ if (auto_footnotes_p)
+ info_get_or_remove_footnotes (window);
+}
+
+
+/* **************************************************************** */
+/* */
+/* Info Movement Commands */
+/* */
+/* **************************************************************** */
+
+/* Change the pagetop of WINDOW to DESIRED_TOP, perhaps scrolling the screen
+ to do so. */
+void
+set_window_pagetop (window, desired_top)
+ WINDOW *window;
+ int desired_top;
+{
+ int point_line, old_pagetop;
+
+ if (desired_top < 0)
+ desired_top = 0;
+ else if (desired_top > window->line_count)
+ desired_top = window->line_count - 1;
+
+ if (window->pagetop == desired_top)
+ return;
+
+ old_pagetop = window->pagetop;
+ window->pagetop = desired_top;
+
+ /* Make sure that point appears in this window. */
+ point_line = window_line_of_point (window);
+ if ((point_line < window->pagetop) ||
+ ((point_line - window->pagetop) > window->height - 1))
+ window->point =
+ window->line_starts[window->pagetop] - window->node->contents;
+
+ window->flags |= W_UpdateWindow;
+
+ /* Find out which direction to scroll, and scroll the window in that
+ direction. Do this only if there would be a savings in redisplay
+ time. This is true if the amount to scroll is less than the height
+ of the window, and if the number of lines scrolled would be greater
+ than 10 % of the window's height. */
+ if (old_pagetop < desired_top)
+ {
+ int start, end, amount;
+
+ amount = desired_top - old_pagetop;
+
+ if ((amount >= window->height) ||
+ (((window->height - amount) * 10) < window->height))
+ return;
+
+ start = amount + window->first_row;
+ end = window->height + window->first_row;
+
+ display_scroll_display (start, end, -amount);
+ }
+ else
+ {
+ int start, end, amount;
+
+ amount = old_pagetop - desired_top;
+
+ if ((amount >= window->height) ||
+ (((window->height - amount) * 10) < window->height))
+ return;
+
+ start = window->first_row;
+ end = (window->first_row + window->height) - amount;
+ display_scroll_display (start, end, amount);
+ }
+}
+
+/* Immediately make WINDOW->point visible on the screen, and move the
+ terminal cursor there. */
+static void
+info_show_point (window)
+ WINDOW *window;
+{
+ int old_pagetop;
+
+ old_pagetop = window->pagetop;
+ window_adjust_pagetop (window);
+ if (old_pagetop != window->pagetop)
+ {
+ int new_pagetop;
+
+ new_pagetop = window->pagetop;
+ window->pagetop = old_pagetop;
+ set_window_pagetop (window, new_pagetop);
+ }
+
+ if (window->flags & W_UpdateWindow)
+ display_update_one_window (window);
+
+ display_cursor_at_point (window);
+}
+
+/* Move WINDOW->point from OLD line index to NEW line index. */
+static void
+move_to_new_line (old, new, window)
+ int old, new;
+ WINDOW *window;
+{
+ if (old == -1)
+ {
+ info_error (CANT_FIND_POINT);
+ }
+ else
+ {
+ int goal;
+
+ if (new >= window->line_count || new < 0)
+ return;
+
+ goal = window_get_goal_column (window);
+ window->goal_column = goal;
+
+ window->point = window->line_starts[new] - window->node->contents;
+ window->point += window_chars_to_goal (window->line_starts[new], goal);
+ info_show_point (window);
+ }
+}
+
+/* Move WINDOW's point down to the next line if possible. */
+DECLARE_INFO_COMMAND (info_next_line, "Move down to the next line")
+{
+ int old_line, new_line;
+
+ if (count < 0)
+ info_prev_line (window, -count, key);
+ else
+ {
+ old_line = window_line_of_point (window);
+ new_line = old_line + count;
+ move_to_new_line (old_line, new_line, window);
+ }
+}
+
+/* Move WINDOW's point up to the previous line if possible. */
+DECLARE_INFO_COMMAND (info_prev_line, "Move up to the previous line")
+{
+ int old_line, new_line;
+
+ if (count < 0)
+ info_next_line (window, -count, key);
+ else
+ {
+ old_line = window_line_of_point (window);
+ new_line = old_line - count;
+ move_to_new_line (old_line, new_line, window);
+ }
+}
+
+/* Move WINDOW's point to the end of the true line. */
+DECLARE_INFO_COMMAND (info_end_of_line, "Move to the end of the line")
+{
+ register int point, len;
+ register char *buffer;
+
+ buffer = window->node->contents;
+ len = window->node->nodelen;
+
+ for (point = window->point;
+ (point < len) && (buffer[point] != '\n');
+ point++);
+
+ if (point != window->point)
+ {
+ window->point = point;
+ info_show_point (window);
+ }
+}
+
+/* Move WINDOW's point to the beginning of the true line. */
+DECLARE_INFO_COMMAND (info_beginning_of_line, "Move to the start of the line")
+{
+ register int point;
+ register char *buffer;
+
+ buffer = window->node->contents;
+ point = window->point;
+
+ for (; (point) && (buffer[point - 1] != '\n'); point--);
+
+ /* If at a line start alreay, do nothing. */
+ if (point != window->point)
+ {
+ window->point = point;
+ info_show_point (window);
+ }
+}
+
+/* Move point forward in the node. */
+DECLARE_INFO_COMMAND (info_forward_char, "Move forward a character")
+{
+ if (count < 0)
+ info_backward_char (window, -count, key);
+ else
+ {
+ window->point += count;
+
+ if (window->point >= window->node->nodelen)
+ window->point = window->node->nodelen - 1;
+
+ info_show_point (window);
+ }
+}
+
+/* Move point backward in the node. */
+DECLARE_INFO_COMMAND (info_backward_char, "Move backward a character")
+{
+ if (count < 0)
+ info_forward_char (window, -count, key);
+ else
+ {
+ window->point -= count;
+
+ if (window->point < 0)
+ window->point = 0;
+
+ info_show_point (window);
+ }
+}
+
+#define alphabetic(c) (islower (c) || isupper (c) || isdigit (c))
+
+/* Move forward a word in this node. */
+DECLARE_INFO_COMMAND (info_forward_word, "Move forward a word")
+{
+ long point;
+ char *buffer;
+ int end, c;
+
+ if (count < 0)
+ {
+ info_backward_word (window, -count, key);
+ return;
+ }
+
+ point = window->point;
+ buffer = window->node->contents;
+ end = window->node->nodelen;
+
+ while (count)
+ {
+ if (point + 1 >= end)
+ return;
+
+ /* If we are not in a word, move forward until we are in one.
+ Then, move forward until we hit a non-alphabetic character. */
+ c = buffer[point];
+
+ if (!alphabetic (c))
+ {
+ while (++point < end)
+ {
+ c = buffer[point];
+ if (alphabetic (c))
+ break;
+ }
+ }
+
+ if (point >= end) return;
+
+ while (++point < end)
+ {
+ c = buffer[point];
+ if (!alphabetic (c))
+ break;
+ }
+ --count;
+ }
+ window->point = point;
+ info_show_point (window);
+}
+
+DECLARE_INFO_COMMAND (info_backward_word, "Move backward a word")
+{
+ long point;
+ char *buffer;
+ int c;
+
+ if (count < 0)
+ {
+ info_forward_word (window, -count, key);
+ return;
+ }
+
+ buffer = window->node->contents;
+ point = window->point;
+
+ while (count)
+ {
+ if (point == 0)
+ break;
+
+ /* Like info_forward_word (), except that we look at the
+ characters just before point. */
+
+ c = buffer[point - 1];
+
+ if (!alphabetic (c))
+ {
+ while (--point)
+ {
+ c = buffer[point - 1];
+ if (alphabetic (c))
+ break;
+ }
+ }
+
+ while (point)
+ {
+ c = buffer[point - 1];
+ if (!alphabetic (c))
+ break;
+ else
+ --point;
+ }
+ --count;
+ }
+ window->point = point;
+ info_show_point (window);
+}
+
+/* Here is a list of time counter names which correspond to ordinal numbers.
+ It is used to print "once" instead of "1". */
+static char *counter_names[] = {
+ "not at all", "once", "twice", "three", "four", "five", "six",
+ (char *)NULL
+};
+
+/* Buffer used to return values from times_description (). */
+static char td_buffer[50];
+
+/* Function returns a static string fully describing the number of times
+ present in COUNT. */
+static char *
+times_description (count)
+ int count;
+{
+ register int i;
+
+ td_buffer[0] = '\0';
+
+ for (i = 0; counter_names[i]; i++)
+ if (count == i)
+ break;
+
+ if (counter_names[i])
+ sprintf (td_buffer, "%s%s", counter_names[i], count > 2 ? " times" : "");
+ else
+ sprintf (td_buffer, "%d times", count);
+
+ return (td_buffer);
+}
+
+/* Variable controlling the behaviour of default scrolling when you are
+ already at the bottom of a node. Possible values are defined in session.h.
+ The meanings are:
+
+ IS_Continuous Try to get first menu item, or failing that, the
+ "Next:" pointer, or failing that, the "Up:" and
+ "Next:" of the up.
+ IS_NextOnly Try to get "Next:" menu item.
+ IS_PageOnly Simply give up at the bottom of a node. */
+
+int info_scroll_behaviour = IS_Continuous;
+
+/* Choices used by the completer when reading a value for the user-visible
+ variable "scroll-behaviour". */
+char *info_scroll_choices[] = {
+ "Continuous", "Next Only", "Page Only", (char *)NULL
+};
+
+/* Move to 1st menu item, Next, Up/Next, or error in this window. */
+static void
+forward_move_node_structure (window, behaviour)
+ WINDOW *window;
+ int behaviour;
+{
+ switch (behaviour)
+ {
+ case IS_PageOnly:
+ info_error (AT_NODE_BOTTOM);
+ break;
+
+ case IS_NextOnly:
+ info_next_label_of_node (window->node);
+ if (!info_parsed_nodename && !info_parsed_filename)
+ info_error ("No \"Next\" pointer for this node.");
+ else
+ {
+ window_message_in_echo_area ("Following \"Next\" node...");
+ info_handle_pointer ("Next", window);
+ }
+ break;
+
+ case IS_Continuous:
+ {
+ /* First things first. If this node contains a menu, move down
+ into the menu. */
+ {
+ REFERENCE **menu;
+
+ menu = info_menu_of_node (window->node);
+
+ if (menu)
+ {
+ info_free_references (menu);
+ window_message_in_echo_area ("Selecting first menu item...");
+ info_menu_digit (window, 1, '1');
+ return;
+ }
+ }
+
+ /* Okay, this node does not contain a menu. If it contains a
+ "Next:" pointer, use that. */
+ info_next_label_of_node (window->node);
+ if (info_label_was_found)
+ {
+ window_message_in_echo_area ("Selecting \"Next\" node...");
+ info_handle_pointer ("Next", window);
+ return;
+ }
+
+ /* Okay, there wasn't a "Next:" for this node. Move "Up:" until we
+ can move "Next:". If that isn't possible, complain that there
+ are no more nodes. */
+ {
+ int up_counter, old_current;
+ INFO_WINDOW *info_win;
+
+ /* Remember the current node and location. */
+ info_win = get_info_window_of_window (window);
+ old_current = info_win->current;
+
+ /* Back up through the "Up:" pointers until we have found a "Next:"
+ that isn't the same as the first menu item found in that node. */
+ up_counter = 0;
+ while (!info_error_was_printed)
+ {
+ info_up_label_of_node (window->node);
+ if (info_label_was_found)
+ {
+ info_handle_pointer ("Up", window);
+ if (info_error_was_printed)
+ continue;
+
+ up_counter++;
+
+ info_next_label_of_node (window->node);
+
+ /* If no "Next" pointer, keep backing up. */
+ if (!info_label_was_found)
+ continue;
+
+ /* If this node's first menu item is the same as this node's
+ Next pointer, keep backing up. */
+ if (!info_parsed_filename)
+ {
+ REFERENCE **menu;
+ char *next_nodename;
+
+ /* Remember the name of the Next node, since reading
+ the menu can overwrite the contents of the
+ info_parsed_xxx strings. */
+ next_nodename = savestring (info_parsed_nodename);
+
+ menu = info_menu_of_node (window->node);
+ if (menu &&
+ (strcmp
+ (menu[0]->nodename, next_nodename) == 0))
+ {
+ info_free_references (menu);
+ free (next_nodename);
+ continue;
+ }
+ else
+ {
+ /* Restore the world to where it was before
+ reading the menu contents. */
+ info_free_references (menu);
+ free (next_nodename);
+ info_next_label_of_node (window->node);
+ }
+ }
+
+ /* This node has a "Next" pointer, and it is not the
+ same as the first menu item found in this node. */
+ window_message_in_echo_area
+ ("Moving \"Up\" %s, then \"Next\".",
+ times_description (up_counter));
+
+ info_handle_pointer ("Next", window);
+ return;
+ }
+ else
+ {
+ /* No more "Up" pointers. Print an error, and call it
+ quits. */
+ register int i;
+
+ for (i = 0; i < up_counter; i++)
+ {
+ info_win->nodes_index--;
+ free (info_win->nodes[info_win->nodes_index]);
+ info_win->nodes[info_win->nodes_index] = (NODE *)NULL;
+ }
+ info_win->current = old_current;
+ window->node = info_win->nodes[old_current];
+ window->pagetop = info_win->pagetops[old_current];
+ window->point = info_win->points[old_current];
+ recalculate_line_starts (window);
+ window->flags |= W_UpdateWindow;
+ info_error ("No more nodes.");
+ }
+ }
+ }
+ break;
+ }
+ }
+}
+
+/* Move Prev, Up or error in WINDOW depending on BEHAVIOUR. */
+static void
+backward_move_node_structure (window, behaviour)
+ WINDOW *window;
+ int behaviour;
+{
+ switch (behaviour)
+ {
+ case IS_PageOnly:
+ info_error (AT_NODE_TOP);
+ break;
+
+ case IS_NextOnly:
+ info_prev_label_of_node (window->node);
+ if (!info_parsed_nodename && !info_parsed_filename)
+ info_error ("No \"Prev\" for this node.");
+ else
+ {
+ window_message_in_echo_area ("Moving \"Prev\" in this window.");
+ info_handle_pointer ("Prev", window);
+ }
+ break;
+
+ case IS_Continuous:
+ info_prev_label_of_node (window->node);
+
+ if (!info_parsed_nodename && !info_parsed_filename)
+ {
+ info_up_label_of_node (window->node);
+ if (!info_parsed_nodename && !info_parsed_filename)
+ info_error ("No \"Prev\" or \"Up\" for this node.");
+ else
+ {
+ window_message_in_echo_area ("Moving \"Up\" in this window.");
+ info_handle_pointer ("Up", window);
+ }
+ }
+ else
+ {
+ REFERENCE **menu;
+ int inhibit_menu_traversing = 0;
+
+ /* Watch out! If this node's Prev is the same as the Up, then
+ move Up. Otherwise, we could move Prev, and then to the last
+ menu item in the Prev. This would cause the user to loop
+ through a subsection of the info file. */
+ if (!info_parsed_filename && info_parsed_nodename)
+ {
+ char *pnode;
+
+ pnode = savestring (info_parsed_nodename);
+ info_up_label_of_node (window->node);
+
+ if (!info_parsed_filename && info_parsed_nodename &&
+ strcmp (info_parsed_nodename, pnode) == 0)
+ {
+ /* The nodes are the same. Inhibit moving to the last
+ menu item. */
+ free (pnode);
+ inhibit_menu_traversing = 1;
+ }
+ else
+ {
+ free (pnode);
+ info_prev_label_of_node (window->node);
+ }
+ }
+
+ /* Move to the previous node. If this node now contains a menu,
+ and we have not inhibited movement to it, move to the node
+ corresponding to the last menu item. */
+ window_message_in_echo_area ("Moving \"Prev\" in this window.");
+ info_handle_pointer ("Prev", window);
+
+ if (!inhibit_menu_traversing)
+ {
+ while (!info_error_was_printed &&
+ (menu = info_menu_of_node (window->node)))
+ {
+ info_free_references (menu);
+ window_message_in_echo_area
+ ("Moving to \"Prev\"'s last menu item.");
+ info_menu_digit (window, 1, '0');
+ }
+ }
+ }
+ break;
+ }
+}
+
+/* Move continuously forward through the node structure of this info file. */
+DECLARE_INFO_COMMAND (info_global_next_node,
+ "Move forwards or down through node structure")
+{
+ if (count < 0)
+ info_global_prev_node (window, -count, key);
+ else
+ {
+ while (count && !info_error_was_printed)
+ {
+ forward_move_node_structure (window, IS_Continuous);
+ count--;
+ }
+ }
+}
+
+/* Move continuously backward through the node structure of this info file. */
+DECLARE_INFO_COMMAND (info_global_prev_node,
+ "Move backwards or up through node structure")
+{
+ if (count < 0)
+ info_global_next_node (window, -count, key);
+ else
+ {
+ while (count && !info_error_was_printed)
+ {
+ backward_move_node_structure (window, IS_Continuous);
+ count--;
+ }
+ }
+}
+
+/* Show the next screen of WINDOW's node. */
+DECLARE_INFO_COMMAND (info_scroll_forward, "Scroll forward in this window")
+{
+ if (count < 0)
+ info_scroll_backward (window, -count, key);
+ else
+ {
+ int desired_top;
+
+ /* Without an explicit numeric argument, scroll the bottom two
+ lines to the top of this window, Or, if at bottom of window,
+ and the user wishes to scroll through nodes get the "Next" node
+ for this window. */
+ if (!info_explicit_arg && count == 1)
+ {
+ desired_top = window->pagetop + (window->height - 2);
+
+ /* If there are no more lines to scroll here, error, or get
+ another node, depending on INFO_SCROLL_BEHAVIOUR. */
+ if (desired_top > window->line_count)
+ {
+ int behaviour = info_scroll_behaviour;
+
+ /* Here is a hack. If the key being used is not SPC, do the
+ PageOnly behaviour. */
+ if (key != SPC && key != DEL)
+ behaviour = IS_PageOnly;
+
+ forward_move_node_structure (window, behaviour);
+ return;
+ }
+ }
+ else
+ desired_top = window->pagetop + count;
+
+ if (desired_top >= window->line_count)
+ desired_top = window->line_count - 2;
+
+ if (window->pagetop > desired_top)
+ return;
+ else
+ set_window_pagetop (window, desired_top);
+ }
+}
+
+/* Show the previous screen of WINDOW's node. */
+DECLARE_INFO_COMMAND (info_scroll_backward, "Scroll backward in this window")
+{
+ if (count < 0)
+ info_scroll_forward (window, -count, key);
+ else
+ {
+ int desired_top;
+
+ /* Without an explicit numeric argument, scroll the top two lines
+ to the bottom of this window, or move to the previous, or Up'th
+ node. */
+ if (!info_explicit_arg && count == 1)
+ {
+ desired_top = window->pagetop - (window->height - 2);
+
+ if ((desired_top < 0) && (window->pagetop == 0))
+ {
+ int behaviour = info_scroll_behaviour;
+
+ /* Same kind of hack as in info_scroll_forward. If the key
+ used to invoke this command is not DEL, do only the PageOnly
+ behaviour. */
+ if (key != DEL && key != SPC)
+ behaviour = IS_PageOnly;
+
+ backward_move_node_structure (window, behaviour);
+ return;
+ }
+ }
+ else
+ desired_top = window->pagetop - count;
+
+ if (desired_top < 0)
+ desired_top = 0;
+
+ set_window_pagetop (window, desired_top);
+ }
+}
+
+/* Move to the beginning of the node. */
+DECLARE_INFO_COMMAND (info_beginning_of_node, "Move to the start of this node")
+{
+ window->pagetop = window->point = 0;
+ window->flags |= W_UpdateWindow;
+}
+
+/* Move to the end of the node. */
+DECLARE_INFO_COMMAND (info_end_of_node, "Move to the end of this node")
+{
+ window->point = window->node->nodelen - 1;
+ info_show_point (window);
+}
+
+/* **************************************************************** */
+/* */
+/* Commands for Manipulating Windows */
+/* */
+/* **************************************************************** */
+
+/* Make the next window in the chain be the active window. */
+DECLARE_INFO_COMMAND (info_next_window, "Select the next window")
+{
+ if (count < 0)
+ {
+ info_prev_window (window, -count, key);
+ return;
+ }
+
+ /* If no other window, error now. */
+ if (!windows->next && !echo_area_is_active)
+ {
+ info_error (ONE_WINDOW);
+ return;
+ }
+
+ while (count--)
+ {
+ if (window->next)
+ window = window->next;
+ else
+ {
+ if (window == the_echo_area || !echo_area_is_active)
+ window = windows;
+ else
+ window = the_echo_area;
+ }
+ }
+
+ if (active_window != window)
+ {
+ if (auto_footnotes_p)
+ info_get_or_remove_footnotes (window);
+
+ window->flags |= W_UpdateWindow;
+ active_window = window;
+ }
+}
+
+/* Make the previous window in the chain be the active window. */
+DECLARE_INFO_COMMAND (info_prev_window, "Select the previous window")
+{
+ if (count < 0)
+ {
+ info_next_window (window, -count, key);
+ return;
+ }
+
+ /* Only one window? */
+
+ if (!windows->next && !echo_area_is_active)
+ {
+ info_error (ONE_WINDOW);
+ return;
+ }
+
+ while (count--)
+ {
+ /* If we are in the echo area, or if the echo area isn't active and we
+ are in the first window, find the last window in the chain. */
+ if (window == the_echo_area ||
+ (window == windows && !echo_area_is_active))
+ {
+ register WINDOW *win, *last;
+
+ for (win = windows; win; win = win->next)
+ last = win;
+
+ window = last;
+ }
+ else
+ {
+ if (window == windows)
+ window = the_echo_area;
+ else
+ window = window->prev;
+ }
+ }
+
+ if (active_window != window)
+ {
+ if (auto_footnotes_p)
+ info_get_or_remove_footnotes (window);
+
+ window->flags |= W_UpdateWindow;
+ active_window = window;
+ }
+}
+
+/* Split WINDOW into two windows, both showing the same node. If we
+ are automatically tiling windows, re-tile after the split. */
+DECLARE_INFO_COMMAND (info_split_window, "Split the current window")
+{
+ WINDOW *split, *old_active;
+ int pagetop;
+
+ /* Remember the current pagetop of the window being split. If it doesn't
+ change, we can scroll its contents around after the split. */
+ pagetop = window->pagetop;
+
+ /* Make the new window. */
+ old_active = active_window;
+ active_window = window;
+ split = window_make_window (window->node);
+ active_window = old_active;
+
+ if (!split)
+ {
+ info_error (WIN_TOO_SMALL);
+ }
+ else
+ {
+#if defined (SPLIT_BEFORE_ACTIVE)
+ /* Try to scroll the old window into its new postion. */
+ if (pagetop == window->pagetop)
+ {
+ int start, end, amount;
+
+ start = split->first_row;
+ end = start + window->height;
+ amount = split->height + 1;
+ display_scroll_display (start, end, amount);
+ }
+#else /* !SPLIT_BEFORE_ACTIVE */
+ /* Make sure point still appears in the active window. */
+ info_show_point (window);
+#endif /* !SPLIT_BEFORE_ACTIVE */
+
+ /* If the window just split was one internal to Info, try to display
+ something else in it. */
+ if (internal_info_node_p (split->node))
+ {
+ register int i, j;
+ INFO_WINDOW *iw;
+ NODE *node = (NODE *)NULL;
+ char *filename;
+
+ for (i = 0; iw = info_windows[i]; i++)
+ {
+ for (j = 0; j < iw->nodes_index; j++)
+ if (!internal_info_node_p (iw->nodes[j]))
+ {
+ if (iw->nodes[j]->parent)
+ filename = iw->nodes[j]->parent;
+ else
+ filename = iw->nodes[j]->filename;
+
+ node = info_get_node (filename, iw->nodes[j]->nodename);
+ if (node)
+ {
+ window_set_node_of_window (split, node);
+ i = info_windows_index - 1;
+ break;
+ }
+ }
+ }
+ }
+ split->pagetop = window->pagetop;
+
+ if (auto_tiling_p)
+ window_tile_windows (DONT_TILE_INTERNALS);
+ else
+ window_adjust_pagetop (split);
+
+ remember_window_and_node (split, split->node);
+ }
+}
+
+/* Delete WINDOW, forgetting the list of last visited nodes. If we are
+ automatically displaying footnotes, show or remove the footnotes
+ window. If we are automatically tiling windows, re-tile after the
+ deletion. */
+DECLARE_INFO_COMMAND (info_delete_window, "Delete the current window")
+{
+ if (!windows->next)
+ {
+ info_error (CANT_KILL_LAST);
+ }
+ else if (window->flags & W_WindowIsPerm)
+ {
+ info_error ("Cannot delete a permanent window");
+ }
+ else
+ {
+ info_delete_window_internal (window);
+
+ if (auto_footnotes_p)
+ info_get_or_remove_footnotes (active_window);
+
+ if (auto_tiling_p)
+ window_tile_windows (DONT_TILE_INTERNALS);
+ }
+}
+
+/* Do the physical deletion of WINDOW, and forget this window and
+ associated nodes. */
+void
+info_delete_window_internal (window)
+ WINDOW *window;
+{
+ if (windows->next && ((window->flags & W_WindowIsPerm) == 0))
+ {
+ /* We not only delete the window from the display, we forget it from
+ our list of remembered windows. */
+ forget_window_and_nodes (window);
+ window_delete_window (window);
+
+ if (echo_area_is_active)
+ echo_area_inform_of_deleted_window (window);
+ }
+}
+
+/* Just keep WINDOW, deleting all others. */
+DECLARE_INFO_COMMAND (info_keep_one_window, "Delete all other windows")
+{
+ int num_deleted; /* The number of windows we deleted. */
+ int pagetop, start, end;
+
+ /* Remember a few things about this window. We may be able to speed up
+ redisplay later by scrolling its contents. */
+ pagetop = window->pagetop;
+ start = window->first_row;
+ end = start + window->height;
+
+ num_deleted = 0;
+
+ while (1)
+ {
+ WINDOW *win;
+
+ /* Find an eligible window and delete it. If no eligible windows
+ are found, we are done. A window is eligible for deletion if
+ is it not permanent, and it is not WINDOW. */
+ for (win = windows; win; win = win->next)
+ if (win != window && ((win->flags & W_WindowIsPerm) == 0))
+ break;
+
+ if (!win)
+ break;
+
+ info_delete_window_internal (win);
+ num_deleted++;
+ }
+
+ /* Scroll the contents of this window into the right place so that the
+ user doesn't have to wait any longer than necessary for redisplay. */
+ if (num_deleted)
+ {
+ int amount;
+
+ amount = (window->first_row - start);
+ amount -= (window->pagetop - pagetop);
+ display_scroll_display (start, end, amount);
+ }
+
+ window->flags |= W_UpdateWindow;
+}
+
+/* Scroll the "other" window of WINDOW. */
+DECLARE_INFO_COMMAND (info_scroll_other_window, "Scroll the other window")
+{
+ WINDOW *other;
+
+ /* If only one window, give up. */
+ if (!windows->next)
+ {
+ info_error (ONE_WINDOW);
+ return;
+ }
+
+ other = window->next;
+
+ if (!other)
+ other = window->prev;
+
+ info_scroll_forward (other, count, key);
+}
+
+/* Change the size of WINDOW by AMOUNT. */
+DECLARE_INFO_COMMAND (info_grow_window, "Grow (or shrink) this window")
+{
+ window_change_window_height (window, count);
+}
+
+/* When non-zero, tiling takes place automatically when info_split_window
+ is called. */
+int auto_tiling_p = 0;
+
+/* Tile all of the visible windows. */
+DECLARE_INFO_COMMAND (info_tile_windows,
+ "Divide the available screen space among the visible windows")
+{
+ window_tile_windows (TILE_INTERNALS);
+}
+
+/* Toggle the state of this window's wrapping of lines. */
+DECLARE_INFO_COMMAND (info_toggle_wrap,
+ "Toggle the state of line wrapping in the current window")
+{
+ window_toggle_wrap (window);
+}
+
+/* **************************************************************** */
+/* */
+/* Info Node Commands */
+/* */
+/* **************************************************************** */
+
+/* Using WINDOW for various defaults, select the node referenced by ENTRY
+ in it. If the node is selected, the window and node are remembered. */
+void
+info_select_reference (window, entry)
+ WINDOW *window;
+ REFERENCE *entry;
+{
+ NODE *node;
+ char *filename, *nodename, *file_system_error;
+
+ file_system_error = (char *)NULL;
+
+ filename = entry->filename;
+ if (!filename)
+ filename = window->node->parent;
+ if (!filename)
+ filename = window->node->filename;
+
+ if (filename)
+ filename = savestring (filename);
+
+ if (entry->nodename)
+ nodename = savestring (entry->nodename);
+ else
+ nodename = savestring ("Top");
+
+ node = info_get_node (filename, nodename);
+
+ /* Try something a little weird. If the node couldn't be found, and the
+ reference was of the form "foo::", see if the entry->label can be found
+ as a file, with a node of "Top". */
+ if (!node)
+ {
+ if (info_recent_file_error)
+ file_system_error = savestring (info_recent_file_error);
+
+ if (entry->nodename && (strcmp (entry->nodename, entry->label) == 0))
+ {
+ node = info_get_node (entry->label, "Top");
+ if (!node && info_recent_file_error)
+ {
+ maybe_free (file_system_error);
+ file_system_error = savestring (info_recent_file_error);
+ }
+ }
+ }
+
+ if (!node)
+ {
+ if (file_system_error)
+ info_error (file_system_error);
+ else
+ info_error (CANT_FIND_NODE, nodename);
+ }
+
+ maybe_free (file_system_error);
+ maybe_free (filename);
+ maybe_free (nodename);
+
+ if (node)
+ {
+ set_remembered_pagetop_and_point (window);
+ info_set_node_of_window (window, node);
+ }
+}
+
+/* Parse the node specification in LINE using WINDOW to default the filename.
+ Select the parsed node in WINDOW and remember it, or error if the node
+ couldn't be found. */
+static void
+info_parse_and_select (line, window)
+ char *line;
+ WINDOW *window;
+{
+ REFERENCE entry;
+
+ info_parse_node (line, DONT_SKIP_NEWLINES);
+
+ entry.nodename = info_parsed_nodename;
+ entry.filename = info_parsed_filename;
+ entry.label = "*info-parse-and-select*";
+
+ info_select_reference (window, &entry);
+}
+
+/* Given that the values of INFO_PARSED_FILENAME and INFO_PARSED_NODENAME
+ are previously filled, try to get the node represented by them into
+ WINDOW. The node should have been pointed to by the LABEL pointer of
+ WINDOW->node. */
+static void
+info_handle_pointer (label, window)
+ char *label;
+ WINDOW *window;
+{
+ if (info_parsed_filename || info_parsed_nodename)
+ {
+ char *filename, *nodename;
+ NODE *node;
+
+ filename = nodename = (char *)NULL;
+
+ if (info_parsed_filename)
+ filename = savestring (info_parsed_filename);
+ else
+ {
+ if (window->node->parent)
+ filename = savestring (window->node->parent);
+ else if (window->node->filename)
+ filename = savestring (window->node->filename);
+ }
+
+ if (info_parsed_nodename)
+ nodename = savestring (info_parsed_nodename);
+ else
+ nodename = savestring ("Top");
+
+ node = info_get_node (filename, nodename);
+
+ if (node)
+ {
+ INFO_WINDOW *info_win;
+
+ info_win = get_info_window_of_window (window);
+ if (info_win)
+ {
+ info_win->pagetops[info_win->current] = window->pagetop;
+ info_win->points[info_win->current] = window->point;
+ }
+ set_remembered_pagetop_and_point (window);
+ info_set_node_of_window (window, node);
+ }
+ else
+ {
+ if (info_recent_file_error)
+ info_error (info_recent_file_error);
+ else
+ info_error (CANT_FILE_NODE, filename, nodename);
+ }
+
+ free (filename);
+ free (nodename);
+ }
+ else
+ {
+ info_error (NO_POINTER, label);
+ }
+}
+
+/* Make WINDOW display the "Next:" node of the node currently being
+ displayed. */
+DECLARE_INFO_COMMAND (info_next_node, "Select the `Next' node")
+{
+ info_next_label_of_node (window->node);
+ info_handle_pointer ("Next", window);
+}
+
+/* Make WINDOW display the "Prev:" node of the node currently being
+ displayed. */
+DECLARE_INFO_COMMAND (info_prev_node, "Select the `Prev' node")
+{
+ info_prev_label_of_node (window->node);
+ info_handle_pointer ("Prev", window);
+}
+
+/* Make WINDOW display the "Up:" node of the node currently being
+ displayed. */
+DECLARE_INFO_COMMAND (info_up_node, "Select the `Up' node")
+{
+ info_up_label_of_node (window->node);
+ info_handle_pointer ("Up", window);
+}
+
+/* Make WINDOW display the last node of this info file. */
+DECLARE_INFO_COMMAND (info_last_node, "Select the last node in this file")
+{
+ register int i;
+ FILE_BUFFER *fb = file_buffer_of_window (window);
+ NODE *node = (NODE *)NULL;
+
+ if (fb && fb->tags)
+ {
+ for (i = 0; fb->tags[i]; i++);
+ node = info_get_node (fb->filename, fb->tags[i - 1]->nodename);
+ }
+
+ if (!node)
+ info_error ("This window has no additional nodes");
+ else
+ {
+ set_remembered_pagetop_and_point (window);
+ info_set_node_of_window (window, node);
+ }
+}
+
+/* Make WINDOW display the first node of this info file. */
+DECLARE_INFO_COMMAND (info_first_node, "Select the first node in this file")
+{
+ FILE_BUFFER *fb = file_buffer_of_window (window);
+ NODE *node = (NODE *)NULL;
+
+ if (fb && fb->tags)
+ node = info_get_node (fb->filename, fb->tags[0]->nodename);
+
+ if (!node)
+ info_error ("This window has no additional nodes");
+ else
+ {
+ set_remembered_pagetop_and_point (window);
+ info_set_node_of_window (window, node);
+ }
+}
+
+/* Make WINDOW display the previous node displayed in this window. */
+DECLARE_INFO_COMMAND (info_history_node,
+ "Select the most recently selected node")
+{
+ INFO_WINDOW *info_win;
+
+ /* Find the INFO_WINDOW which contains WINDOW. */
+ info_win = get_info_window_of_window (window);
+
+ if (!info_win)
+ {
+ info_error ("Requested window is not present!");
+ return;
+ }
+
+ set_remembered_pagetop_and_point (window);
+ if (!info_win->current)
+ {
+ if (info_win->nodes_index > 1)
+ {
+ window_message_in_echo_area
+ ("Now wrapped around to beginning of history.");
+ info_win->current = info_win->nodes_index;
+ }
+ else
+ {
+ info_error ("No earlier nodes in this window.");
+ return;
+ }
+ }
+
+ info_win->current--;
+ window_set_node_of_window (window, info_win->nodes[info_win->current]);
+ window->pagetop = info_win->pagetops[info_win->current];
+ window->point = info_win->points[info_win->current];
+ window->flags |= W_UpdateWindow;
+ if (auto_footnotes_p)
+ info_get_or_remove_footnotes (window);
+}
+
+/* Select the last menu item in WINDOW->node. */
+DECLARE_INFO_COMMAND (info_last_menu_item,
+ "Select the last item in this node's menu")
+{
+ info_menu_digit (window, 1, '0');
+}
+
+/* Use KEY (a digit) to select the Nth menu item in WINDOW->node. */
+DECLARE_INFO_COMMAND (info_menu_digit, "Select this menu item")
+{
+ register int i, item;
+ register REFERENCE *entry, **menu;
+
+ menu = info_menu_of_node (window->node);
+
+ if (!menu)
+ {
+ info_error (NO_MENU_NODE);
+ return;
+ }
+
+ /* We have the menu. See if there are this many items in it. */
+ item = key - '0';
+
+ /* Special case. Item "0" is the last item in this menu. */
+ if (item == 0)
+ for (i = 0; menu[i + 1]; i++);
+ else
+ {
+ for (i = 0; entry = menu[i]; i++)
+ if (i == item - 1)
+ break;
+ }
+
+ if (menu[i])
+ info_select_reference (window, menu[i]);
+ else
+ info_error ("There aren't %d items in this menu.", item);
+
+ info_free_references (menu);
+ return;
+}
+
+/* Read a menu or followed reference from the user defaulting to the
+ reference found on the current line, and select that node. The
+ reading is done with completion. BUILDER is the function used
+ to build the list of references. ASK_P is non-zero if the user
+ should be prompted, or zero to select the default item. */
+static void
+info_menu_or_ref_item (window, count, key, builder, ask_p)
+ WINDOW *window;
+ int count;
+ unsigned char key;
+ REFERENCE **(*builder) ();
+ int ask_p;
+{
+ REFERENCE **menu, *entry, *defentry = (REFERENCE *)NULL;
+ char *line;
+
+ menu = (*builder) (window->node);
+
+ if (!menu)
+ {
+ if (builder == info_menu_of_node)
+ info_error (NO_MENU_NODE);
+ else
+ info_error (NO_XREF_NODE);
+ return;
+ }
+
+ /* Default the selected reference to the one which is on the line that
+ point is in. */
+ {
+ REFERENCE **refs = (REFERENCE **)NULL;
+ int point_line;
+
+ point_line = window_line_of_point (window);
+
+ if (point_line != -1)
+ {
+ SEARCH_BINDING binding;
+
+ binding.start = 0;
+ binding.buffer = window->line_starts[point_line];
+ if (window->line_starts[point_line + 1])
+ binding.end = window->line_starts[point_line + 1] - binding.buffer;
+ else
+ binding.end =
+ (window->node->contents + window->node->nodelen) - binding.buffer;
+ binding.flags = 0;
+
+ if (builder == info_menu_of_node)
+ {
+ if (point_line)
+ {
+ binding.buffer--;
+ binding.end++;
+
+ refs = info_menu_items (&binding);
+ }
+ }
+ else
+ refs = info_xrefs (&binding);
+
+ if (refs)
+ {
+ if ((strcmp (refs[0]->label, "Menu") != 0) ||
+ (builder == info_xrefs_of_node))
+ {
+ defentry = (REFERENCE *)xmalloc (sizeof (REFERENCE));
+ defentry->label = savestring (refs[0]->label);
+ defentry->filename = refs[0]->filename;
+ defentry->nodename = refs[0]->nodename;
+
+ if (defentry->filename)
+ defentry->filename = savestring (defentry->filename);
+ if (defentry->nodename)
+ defentry->nodename = savestring (defentry->nodename);
+ }
+ info_free_references (refs);
+ }
+ }
+ }
+
+ /* If we are going to ask the user a question, do it now. */
+ if (ask_p)
+ {
+ char *prompt;
+
+ /* Build the prompt string. */
+ if (defentry)
+ prompt = (char *)xmalloc (20 + strlen (defentry->label));
+ else
+ prompt = (char *)xmalloc (20);
+
+ if (builder == info_menu_of_node)
+ {
+ if (defentry)
+ sprintf (prompt, "Menu item (%s): ", defentry->label);
+ else
+ sprintf (prompt, "Menu item: ");
+ }
+ else
+ {
+ if (defentry)
+ sprintf (prompt, "Follow xref (%s): ", defentry->label);
+ else
+ sprintf (prompt, "Follow xref: ");
+ }
+
+ line = info_read_completing_in_echo_area (window, prompt, menu);
+ free (prompt);
+
+ window = active_window;
+
+ /* User aborts, just quit. */
+ if (!line)
+ {
+ maybe_free (defentry);
+ info_free_references (menu);
+ info_abort_key (window, 0, 0);
+ return;
+ }
+
+ /* If we had a default and the user accepted it, use that. */
+ if (!*line)
+ {
+ free (line);
+ if (defentry)
+ line = savestring (defentry->label);
+ else
+ line = (char *)NULL;
+ }
+ }
+ else
+ {
+ /* Not going to ask any questions. If we have a default entry, use
+ that, otherwise return. */
+ if (!defentry)
+ return;
+ else
+ line = savestring (defentry->label);
+ }
+
+ if (line)
+ {
+ /* Find the selected label in the references. */
+ entry = info_get_labeled_reference (line, menu);
+
+ if (!entry && defentry)
+ info_error ("The reference disappeared! (%s).", line);
+ else
+ {
+ NODE *orig;
+
+ orig = window->node;
+ info_select_reference (window, entry);
+ if ((builder == info_xrefs_of_node) && (window->node != orig))
+ {
+ long offset;
+ long start;
+
+ if (window->line_count > 0)
+ start = window->line_starts[1] - window->node->contents;
+ else
+ start = 0;
+
+ offset =
+ info_target_search_node (window->node, entry->label, start);
+
+ if (offset != -1)
+ {
+ window->point = offset;
+ window_adjust_pagetop (window);
+ }
+ }
+ }
+
+ free (line);
+ if (defentry)
+ {
+ free (defentry->label);
+ maybe_free (defentry->filename);
+ maybe_free (defentry->nodename);
+ free (defentry);
+ }
+ }
+
+ info_free_references (menu);
+
+ if (!info_error_was_printed)
+ window_clear_echo_area ();
+}
+
+/* Read a line (with completion) which is the name of a menu item,
+ and select that item. */
+DECLARE_INFO_COMMAND (info_menu_item, "Read a menu item and select its node")
+{
+ info_menu_or_ref_item (window, count, key, info_menu_of_node, 1);
+}
+
+/* Read a line (with completion) which is the name of a reference to
+ follow, and select the node. */
+DECLARE_INFO_COMMAND
+ (info_xref_item, "Read a footnote or cross reference and select its node")
+{
+ info_menu_or_ref_item (window, count, key, info_xrefs_of_node, 1);
+}
+
+/* Position the cursor at the start of this node's menu. */
+DECLARE_INFO_COMMAND (info_find_menu, "Move to the start of this node's menu")
+{
+ SEARCH_BINDING binding;
+ long position;
+
+ binding.buffer = window->node->contents;
+ binding.start = 0;
+ binding.end = window->node->nodelen;
+ binding.flags = S_FoldCase | S_SkipDest;
+
+ position = search (INFO_MENU_LABEL, &binding);
+
+ if (position == -1)
+ info_error (NO_MENU_NODE);
+ else
+ {
+ window->point = position;
+ window_adjust_pagetop (window);
+ window->flags |= W_UpdateWindow;
+ }
+}
+
+/* Visit as many menu items as is possible, each in a separate window. */
+DECLARE_INFO_COMMAND (info_visit_menu,
+ "Visit as many menu items at once as possible")
+{
+ register int i;
+ REFERENCE *entry, **menu;
+
+ menu = info_menu_of_node (window->node);
+
+ if (!menu)
+ info_error (NO_MENU_NODE);
+
+ for (i = 0; (!info_error_was_printed) && (entry = menu[i]); i++)
+ {
+ WINDOW *new;
+
+ new = window_make_window (window->node);
+ window_tile_windows (TILE_INTERNALS);
+
+ if (!new)
+ info_error (WIN_TOO_SMALL);
+ else
+ {
+ active_window = new;
+ info_select_reference (new, entry);
+ }
+ }
+}
+
+/* Read a line of input which is a node name, and go to that node. */
+DECLARE_INFO_COMMAND (info_goto_node, "Read a node name and select it")
+{
+ char *line;
+ NODE *node;
+
+#define GOTO_COMPLETES
+#if defined (GOTO_COMPLETES)
+ /* Build a completion list of all of the known nodes. */
+ {
+ register int fbi, i;
+ FILE_BUFFER *current;
+ REFERENCE **items = (REFERENCE **)NULL;
+ int items_index = 0;
+ int items_slots = 0;
+
+ current = file_buffer_of_window (window);
+
+ for (fbi = 0; info_loaded_files && info_loaded_files[fbi]; fbi++)
+ {
+ FILE_BUFFER *fb;
+ REFERENCE *entry;
+ int this_is_the_current_fb;
+
+ fb = info_loaded_files[fbi];
+ this_is_the_current_fb = (current == fb);
+
+ entry = (REFERENCE *)xmalloc (sizeof (REFERENCE));
+ entry->filename = entry->nodename = (char *)NULL;
+ entry->label = (char *)xmalloc (4 + strlen (fb->filename));
+ sprintf (entry->label, "(%s)*", fb->filename);
+
+ add_pointer_to_array
+ (entry, items_index, items, items_slots, 10, REFERENCE *);
+
+ if (fb->tags)
+ {
+ for (i = 0; fb->tags[i]; i++)
+ {
+ entry = (REFERENCE *)xmalloc (sizeof (REFERENCE));
+ entry->filename = entry->nodename = (char *)NULL;
+ entry->label = (char *) xmalloc
+ (4 + strlen (fb->filename) + strlen (fb->tags[i]->nodename));
+ sprintf (entry->label, "(%s)%s",
+ fb->filename, fb->tags[i]->nodename);
+
+ add_pointer_to_array
+ (entry, items_index, items, items_slots, 100, REFERENCE *);
+ }
+
+ if (this_is_the_current_fb)
+ {
+ for (i = 0; fb->tags[i]; i++)
+ {
+ entry = (REFERENCE *)xmalloc (sizeof (REFERENCE));
+ entry->filename = entry->nodename = (char *)NULL;
+ entry->label = savestring (fb->tags[i]->nodename);
+ add_pointer_to_array (entry, items_index, items,
+ items_slots, 100, REFERENCE *);
+ }
+ }
+ }
+ }
+ line = info_read_maybe_completing (window, "Goto Node: ", items);
+ info_free_references (items);
+ }
+#else /* !GOTO_COMPLETES */
+ line = info_read_in_echo_area (window, "Goto Node: ");
+#endif /* !GOTO_COMPLETES */
+
+ /* If the user aborted, quit now. */
+ if (!line)
+ {
+ info_abort_key (window, 0, 0);
+ return;
+ }
+
+ canonicalize_whitespace (line);
+
+ if (*line)
+ info_parse_and_select (line, window);
+
+ free (line);
+ if (!info_error_was_printed)
+ window_clear_echo_area ();
+}
+
+/* Move to the "Top" node in this file. */
+DECLARE_INFO_COMMAND (info_top_node, "Select the node `Top' in this file")
+{
+ info_parse_and_select ("Top", window);
+}
+
+/* Move to the node "(dir)Top". */
+DECLARE_INFO_COMMAND (info_dir_node, "Select the node `(dir)'")
+{
+ info_parse_and_select ("(dir)Top", window);
+}
+
+/* Try to delete the current node appearing in this window, showing the most
+ recently selected node in this window. */
+DECLARE_INFO_COMMAND (info_kill_node, "Kill this node")
+{
+ register int iw, i;
+ register INFO_WINDOW *info_win;
+ char *nodename = (char *)NULL;
+ NODE *temp = (NODE *)NULL;
+
+ /* Read the name of a node to kill. The list of available nodes comes
+ from the nodes appearing in the current window configuration. */
+ {
+ REFERENCE **menu = (REFERENCE **)NULL;
+ int menu_index = 0, menu_slots = 0;
+ char *default_nodename, *prompt;
+
+ for (iw = 0; info_win = info_windows[iw]; iw++)
+ {
+ REFERENCE *entry;
+
+ entry = (REFERENCE *)xmalloc (sizeof (REFERENCE));
+ entry->label = savestring (info_win->window->node->nodename);
+ entry->filename = entry->nodename = (char *)NULL;
+
+ add_pointer_to_array
+ (entry, menu_index, menu, menu_slots, 10, REFERENCE *);
+ }
+
+ default_nodename = savestring (active_window->node->nodename);
+ prompt = (char *)xmalloc (40 + strlen (default_nodename));
+ sprintf (prompt, "Kill node (%s): ", default_nodename);
+
+ nodename = info_read_completing_in_echo_area (window, prompt, menu);
+ free (prompt);
+ info_free_references (menu);
+ if (nodename && !*nodename)
+ {
+ free (nodename);
+ nodename = default_nodename;
+ }
+ else
+ free (default_nodename);
+ }
+
+ /* If there is no nodename to kill, quit now. */
+ if (!nodename)
+ {
+ info_abort_key (window, 0, 0);
+ return;
+ }
+
+ /* If there is a nodename, find it in our window list. */
+ for (iw = 0; info_win = info_windows[iw]; iw++)
+ if (strcmp (nodename, info_win->nodes[info_win->current]->nodename) == 0)
+ break;
+
+ if (!info_win)
+ {
+ if (*nodename)
+ info_error ("Cannot kill the node `%s'", nodename);
+ else
+ window_clear_echo_area ();
+
+ return;
+ }
+
+ /* If there are no more nodes left anywhere to view, complain and exit. */
+ if (info_windows_index == 1 && info_windows[0]->nodes_index == 1)
+ {
+ info_error ("Cannot kill the last node");
+ return;
+ }
+
+ /* INFO_WIN contains the node that the user wants to stop viewing.
+ Delete this node from the list of nodes previously shown in this
+ window. */
+ for (i = info_win->current; i < info_win->nodes_index; i++)
+ info_win->nodes[i] = info_win->nodes[i++];
+
+ /* There is one less node in this window's history list. */
+ info_win->nodes_index--;
+
+ /* Make this window show the most recent history node. */
+ info_win->current = info_win->nodes_index - 1;
+
+ /* If there aren't any nodes left in this window, steal one from the
+ next window. */
+ if (info_win->current < 0)
+ {
+ INFO_WINDOW *stealer;
+ int which, pagetop;
+ long point;
+
+ if (info_windows[iw + 1])
+ stealer = info_windows[iw + 1];
+ else
+ stealer = info_windows[0];
+
+ /* If the node being displayed in the next window is not the most
+ recently loaded one, get the most recently loaded one. */
+ if ((stealer->nodes_index - 1) != stealer->current)
+ which = stealer->nodes_index - 1;
+
+ /* Else, if there is another node behind the stealers current node,
+ use that one. */
+ else if (stealer->current > 0)
+ which = stealer->current - 1;
+
+ /* Else, just use the node appearing in STEALER's window. */
+ else
+ which = stealer->current;
+
+ /* Copy this node. */
+ {
+ NODE *copy;
+
+ temp = stealer->nodes[which];
+ point = stealer->points[which];
+ pagetop = stealer->pagetops[which];
+
+ copy = (NODE *)xmalloc (sizeof (NODE));
+ copy->filename = temp->filename;
+ copy->parent = temp->parent;
+ copy->nodename = temp->nodename;
+ copy->contents = temp->contents;
+ copy->nodelen = temp->nodelen;
+ copy->flags = temp->flags;
+
+ temp = copy;
+ }
+
+ window_set_node_of_window (info_win->window, temp);
+ window->point = point;
+ window->pagetop = pagetop;
+ remember_window_and_node (info_win->window, temp);
+ }
+ else
+ {
+ temp = info_win->nodes[info_win->current];
+ window_set_node_of_window (info_win->window, temp);
+ }
+ if (!info_error_was_printed)
+ window_clear_echo_area ();
+}
+
+/* Read the name of a file and select the entire file. */
+DECLARE_INFO_COMMAND (info_view_file, "Read the name of a file and select it")
+{
+ char *line;
+
+ line = info_read_in_echo_area (window, "Find file: ");
+ if (!line)
+ {
+ info_abort_key (active_window, 1, 0);
+ return;
+ }
+
+ if (*line)
+ {
+ NODE *node;
+
+ node = info_get_node (line, "*");
+ if (!node)
+ {
+ if (info_recent_file_error)
+ info_error (info_recent_file_error);
+ else
+ info_error ("Cannot find \"%s\".", line);
+ }
+ else
+ {
+ set_remembered_pagetop_and_point (active_window);
+ info_set_node_of_window (window, node);
+ }
+ free (line);
+ }
+
+ if (!info_error_was_printed)
+ window_clear_echo_area ();
+}
+
+/* **************************************************************** */
+/* */
+/* Dumping and Printing Nodes */
+/* */
+/* **************************************************************** */
+
+#define VERBOSE_NODE_DUMPING
+static void write_node_to_stream ();
+static void dump_node_to_stream ();
+static void initialize_dumping ();
+
+/* Dump the nodes specified by FILENAME and NODENAMES to the file named
+ in OUTPUT_FILENAME. If DUMP_SUBNODES is non-zero, recursively dump
+ the nodes which appear in the menu of each node dumped. */
+void
+dump_nodes_to_file (filename, nodenames, output_filename, dump_subnodes)
+ char *filename;
+ char **nodenames;
+ char *output_filename;
+ int dump_subnodes;
+{
+ register int i;
+ FILE *output_stream;
+
+ /* Get the stream to print the nodes to. Special case of an output
+ filename of "-" means to dump the nodes to stdout. */
+ if (strcmp (output_filename, "-") == 0)
+ output_stream = stdout;
+ else
+ output_stream = fopen (output_filename, "w");
+
+ if (!output_stream)
+ {
+ info_error ("Could not create output file \"%s\".", output_filename);
+ return;
+ }
+
+ /* Print each node to stream. */
+ initialize_dumping ();
+ for (i = 0; nodenames[i]; i++)
+ dump_node_to_stream (filename, nodenames[i], output_stream, dump_subnodes);
+
+ if (output_stream != stdout)
+ fclose (output_stream);
+
+#if defined (VERBOSE_NODE_DUMPING)
+ info_error ("Done.");
+#endif /* VERBOSE_NODE_DUMPING */
+}
+
+/* A place to remember already dumped nodes. */
+static char **dumped_already = (char **)NULL;
+static int dumped_already_index = 0;
+static int dumped_already_slots = 0;
+
+static void
+initialize_dumping ()
+{
+ dumped_already_index = 0;
+}
+
+/* Get and print the node specified by FILENAME and NODENAME to STREAM.
+ If DUMP_SUBNODES is non-zero, recursively dump the nodes which appear
+ in the menu of each node dumped. */
+static void
+dump_node_to_stream (filename, nodename, stream, dump_subnodes)
+ char *filename, *nodename;
+ FILE *stream;
+ int dump_subnodes;
+{
+ register int i;
+ NODE *node;
+
+ node = info_get_node (filename, nodename);
+
+ if (!node)
+ {
+ if (info_recent_file_error)
+ info_error (info_recent_file_error);
+ else
+ {
+ if (filename && *nodename != '(')
+ info_error
+ (CANT_FILE_NODE, filename_non_directory (filename), nodename);
+ else
+ info_error (CANT_FIND_NODE, nodename);
+ }
+ return;
+ }
+
+ /* If we have already dumped this node, don't dump it again. */
+ for (i = 0; i < dumped_already_index; i++)
+ if (strcmp (node->nodename, dumped_already[i]) == 0)
+ {
+ free (node);
+ return;
+ }
+ add_pointer_to_array (node->nodename, dumped_already_index, dumped_already,
+ dumped_already_slots, 50, char *);
+
+#if defined (VERBOSE_NODE_DUMPING)
+ /* Maybe we should print some information about the node being output. */
+ if (node->filename)
+ info_error ("Writing node \"(%s)%s\"...",
+ filename_non_directory (node->filename), node->nodename);
+ else
+ info_error ("Writing node \"%s\"...", node->nodename);
+#endif /* VERBOSE_NODE_DUMPING */
+
+ write_node_to_stream (node, stream);
+
+ /* If we are dumping subnodes, get the list of menu items in this node,
+ and dump each one recursively. */
+ if (dump_subnodes)
+ {
+ REFERENCE **menu = (REFERENCE **)NULL;
+
+ /* If this node is an Index, do not dump the menu references. */
+ if (string_in_line ("Index", node->nodename) == -1)
+ menu = info_menu_of_node (node);
+
+ if (menu)
+ {
+ for (i = 0; menu[i]; i++)
+ {
+ /* We don't dump Info files which are different than the
+ current one. */
+ if (!menu[i]->filename)
+ dump_node_to_stream
+ (filename, menu[i]->nodename, stream, dump_subnodes);
+ }
+ info_free_references (menu);
+ }
+ }
+
+ free (node);
+}
+
+/* Dump NODE to FILENAME. If DUMP_SUBNODES is non-zero, recursively dump
+ the nodes which appear in the menu of each node dumped. */
+void
+dump_node_to_file (node, filename, dump_subnodes)
+ NODE *node;
+ char *filename;
+ int dump_subnodes;
+{
+ FILE *output_stream;
+ char *nodes_filename;
+
+ /* Get the stream to print this node to. Special case of an output
+ filename of "-" means to dump the nodes to stdout. */
+ if (strcmp (filename, "-") == 0)
+ output_stream = stdout;
+ else
+ output_stream = fopen (filename, "w");
+
+ if (!output_stream)
+ {
+ info_error ("Could not create output file \"%s\".", filename);
+ return;
+ }
+
+ if (node->parent)
+ nodes_filename = node->parent;
+ else
+ nodes_filename = node->filename;
+
+ initialize_dumping ();
+ dump_node_to_stream
+ (nodes_filename, node->nodename, output_stream, dump_subnodes);
+
+ if (output_stream != stdout)
+ fclose (output_stream);
+
+#if defined (VERBOSE_NODE_DUMPING)
+ info_error ("Done.");
+#endif /* VERBOSE_NODE_DUMPING */
+}
+
+#if !defined (DEFAULT_INFO_PRINT_COMMAND)
+# define DEFAULT_INFO_PRINT_COMMAND "lpr"
+#endif /* !DEFAULT_INFO_PRINT_COMMAND */
+
+DECLARE_INFO_COMMAND (info_print_node,
+ "Pipe the contents of this node through INFO_PRINT_COMMAND")
+{
+ print_node (window->node);
+}
+
+/* Print NODE on a printer piping it into INFO_PRINT_COMMAND. */
+void
+print_node (node)
+ NODE *node;
+{
+ char *print_command, *getenv ();
+ FILE *printer_pipe;
+
+ print_command = getenv ("INFO_PRINT_COMMAND");
+
+ if (!print_command || !*print_command)
+ print_command = DEFAULT_INFO_PRINT_COMMAND;
+
+ printer_pipe = popen (print_command, "w");
+
+ if (!printer_pipe)
+ {
+ info_error ("Cannot open pipe to \"%s\".", print_command);
+ return;
+ }
+
+#if defined (VERBOSE_NODE_DUMPING)
+ /* Maybe we should print some information about the node being output. */
+ if (node->filename)
+ info_error ("Printing node \"(%s)%s\"...",
+ filename_non_directory (node->filename), node->nodename);
+ else
+ info_error ("Printing node \"%s\"...", node->nodename);
+#endif /* VERBOSE_NODE_DUMPING */
+
+ write_node_to_stream (node, printer_pipe);
+ pclose (printer_pipe);
+
+#if defined (VERBOSE_NODE_DUMPING)
+ info_error ("Done.");
+#endif /* VERBOSE_NODE_DUMPING */
+}
+
+static void
+write_node_to_stream (node, stream)
+ NODE *node;
+ FILE *stream;
+{
+ fwrite (node->contents, 1, node->nodelen, stream);
+}
+
+/* **************************************************************** */
+/* */
+/* Info Searching Commands */
+/* */
+/* **************************************************************** */
+
+/* Variable controlling the garbage collection of files briefly visited
+ during searches. Such files are normally gc'ed, unless they were
+ compressed to begin with. If this variable is non-zero, it says
+ to gc even those file buffer contents which had to be uncompressed. */
+int gc_compressed_files = 0;
+
+static void info_gc_file_buffers ();
+
+static char *search_string = (char *)NULL;
+static int search_string_index = 0;
+static int search_string_size = 0;
+static int isearch_is_active = 0;
+
+/* Return the file buffer which belongs to WINDOW's node. */
+FILE_BUFFER *
+file_buffer_of_window (window)
+ WINDOW *window;
+{
+ /* If this window has no node, then it has no file buffer. */
+ if (!window->node)
+ return ((FILE_BUFFER *)NULL);
+
+ if (window->node->parent)
+ return (info_find_file (window->node->parent));
+
+ if (window->node->filename)
+ return (info_find_file (window->node->filename));
+
+ return ((FILE_BUFFER *)NULL);
+}
+
+/* Search for STRING in NODE starting at START. Return -1 if the string
+ was not found, or the location of the string if it was. If WINDOW is
+ passed as non-null, set the window's node to be NODE, its point to be
+ the found string, and readjust the window's pagetop. Final argument
+ DIR says which direction to search in. If it is positive, search
+ forward, else backwards. */
+long
+info_search_in_node (string, node, start, window, dir)
+ char *string;
+ NODE *node;
+ long start;
+ WINDOW *window;
+ int dir;
+{
+ SEARCH_BINDING binding;
+ long offset;
+
+ binding.buffer = node->contents;
+ binding.start = start;
+ binding.end = node->nodelen;
+ binding.flags = S_FoldCase;
+
+ if (dir < 0)
+ {
+ binding.end = 0;
+ binding.flags |= S_SkipDest;
+ }
+
+ if (binding.start < 0)
+ return (-1);
+
+ /* For incremental searches, we always wish to skip past the string. */
+ if (isearch_is_active)
+ binding.flags |= S_SkipDest;
+
+ offset = search (string, &binding);
+
+ if (offset != -1 && window)
+ {
+ set_remembered_pagetop_and_point (window);
+ if (window->node != node)
+ window_set_node_of_window (window, node);
+ window->point = offset;
+ window_adjust_pagetop (window);
+ }
+ return (offset);
+}
+
+/* Search NODE, looking for the largest possible match of STRING. Start the
+ search at START. Return the absolute position of the match, or -1, if
+ no part of the string could be found. */
+long
+info_target_search_node (node, string, start)
+ NODE *node;
+ char *string;
+ long start;
+{
+ register int i;
+ long offset;
+ char *target;
+
+ target = savestring (string);
+ i = strlen (target);
+
+ /* Try repeatedly searching for this string while removing words from
+ the end of it. */
+ while (i)
+ {
+ target[i] = '\0';
+ offset = info_search_in_node (target, node, start, (WINDOW *)NULL, 1);
+
+ if (offset != -1)
+ break;
+
+ /* Delete the last word from TARGET. */
+ for (; i && (!whitespace (target[i]) && (target[i] != ',')); i--);
+ }
+ free (target);
+ return (offset);
+}
+
+/* Search for STRING starting in WINDOW at point. If the string is found
+ in this node, set point to that position. Otherwise, get the file buffer
+ associated with WINDOW's node, and search through each node in that file.
+ If the search fails, return non-zero, else zero. Side-effect window
+ leaving the node and point where the string was found current. */
+static char *last_searched_for_string = (char *)NULL;
+static int
+info_search_internal (string, window, dir)
+ char *string;
+ WINDOW *window;
+ int dir;
+{
+ register int i;
+ FILE_BUFFER *file_buffer;
+ char *initial_nodename;
+ long ret, start = 0;
+
+ file_buffer = file_buffer_of_window (window);
+ initial_nodename = window->node->nodename;
+
+ if ((info_last_executed_command == info_search) &&
+ (last_searched_for_string) &&
+ (strcmp (last_searched_for_string, string) == 0))
+ {
+ ret = info_search_in_node
+ (string, window->node, window->point + dir, window, dir);
+ }
+ else
+ {
+ ret = info_search_in_node
+ (string, window->node, window->point, window, dir);
+ }
+
+ maybe_free (last_searched_for_string);
+ last_searched_for_string = savestring (string);
+
+ if (ret != -1)
+ {
+ /* We won! */
+ if (!echo_area_is_active && !isearch_is_active)
+ window_clear_echo_area ();
+ return (0);
+ }
+
+ /* The string wasn't found in the current node. Search through the
+ window's file buffer, iff the current node is not "*". */
+ if (!file_buffer || (strcmp (initial_nodename, "*") == 0))
+ return (-1);
+
+ /* If this file has tags, search through every subfile, starting at
+ this node's subfile and node. Otherwise, search through the
+ file's node list. */
+ if (file_buffer->tags)
+ {
+ register int current_tag, number_of_tags;
+ char *last_subfile;
+ TAG *tag;
+
+ /* Find number of tags and current tag. */
+ last_subfile = (char *)NULL;
+ for (i = 0; file_buffer->tags[i]; i++)
+ if (strcmp (initial_nodename, file_buffer->tags[i]->nodename) == 0)
+ {
+ current_tag = i;
+ last_subfile = file_buffer->tags[i]->filename;
+ }
+
+ number_of_tags = i;
+
+ /* If there is no last_subfile, our tag wasn't found. */
+ if (!last_subfile)
+ return (-1);
+
+ /* Search through subsequent nodes, wrapping around to the top
+ of the info file until we find the string or return to this
+ window's node and point. */
+ while (1)
+ {
+ NODE *node;
+
+ /* Allow C-g to quit the search, failing it if pressed. */
+ return_if_control_g (-1);
+
+ current_tag += dir;
+
+ if (current_tag < 0)
+ current_tag = number_of_tags - 1;
+ else if (current_tag == number_of_tags)
+ current_tag = 0;
+
+ tag = file_buffer->tags[current_tag];
+
+ if (!echo_area_is_active && (last_subfile != tag->filename))
+ {
+ window_message_in_echo_area
+ ("Searching subfile \"%s\"...",
+ filename_non_directory (tag->filename));
+
+ last_subfile = tag->filename;
+ }
+
+ node = info_get_node (file_buffer->filename, tag->nodename);
+
+ if (!node)
+ {
+ /* If not doing i-search... */
+ if (!echo_area_is_active)
+ {
+ if (info_recent_file_error)
+ info_error (info_recent_file_error);
+ else
+ info_error (CANT_FILE_NODE,
+ filename_non_directory (file_buffer->filename),
+ tag->nodename);
+ }
+ return (-1);
+ }
+
+ if (dir < 0)
+ start = tag->nodelen;
+
+ ret =
+ info_search_in_node (string, node, start, window, dir);
+
+ /* Did we find the string in this node? */
+ if (ret != -1)
+ {
+ /* Yes! We win. */
+ remember_window_and_node (window, node);
+ if (!echo_area_is_active)
+ window_clear_echo_area ();
+ return (0);
+ }
+
+ /* No. Free this node, and make sure that we haven't passed
+ our starting point. */
+ free (node);
+
+ if (strcmp (initial_nodename, tag->nodename) == 0)
+ return (-1);
+ }
+ }
+ return (-1);
+}
+
+DECLARE_INFO_COMMAND (info_search, "Read a string and search for it")
+{
+ char *line, *prompt;
+ int result, old_pagetop;
+ int direction;
+
+ if (count < 0)
+ direction = -1;
+ else
+ direction = 1;
+
+ /* Read a string from the user, defaulting the search to SEARCH_STRING. */
+ if (!search_string)
+ {
+ search_string = (char *)xmalloc (search_string_size = 100);
+ search_string[0] = '\0';
+ }
+
+ prompt = (char *)xmalloc (50 + strlen (search_string));
+
+ sprintf (prompt, "%s for string [%s]: ",
+ direction < 0 ? "Search backward" : "Search",
+ search_string);
+
+ line = info_read_in_echo_area (window, prompt);
+ free (prompt);
+
+ if (!line)
+ {
+ info_abort_key ();
+ return;
+ }
+
+ if (*line)
+ {
+ if (strlen (line) + 1 > search_string_size)
+ search_string = (char *)
+ xrealloc (search_string, (search_string_size += 50 + strlen (line)));
+
+ strcpy (search_string, line);
+ search_string_index = strlen (line);
+ free (line);
+ }
+
+ old_pagetop = active_window->pagetop;
+ result = info_search_internal (search_string, active_window, direction);
+
+ if (result != 0 && !info_error_was_printed)
+ info_error ("Search failed.");
+ else if (old_pagetop != active_window->pagetop)
+ {
+ int new_pagetop;
+
+ new_pagetop = active_window->pagetop;
+ active_window->pagetop = old_pagetop;
+ set_window_pagetop (active_window, new_pagetop);
+ if (auto_footnotes_p)
+ info_get_or_remove_footnotes (active_window);
+ }
+
+ /* Perhaps free the unreferenced file buffers that were searched, but
+ not retained. */
+ info_gc_file_buffers ();
+}
+
+/* **************************************************************** */
+/* */
+/* Incremental Searching */
+/* */
+/* **************************************************************** */
+
+static void incremental_search ();
+
+DECLARE_INFO_COMMAND (isearch_forward,
+ "Search interactively for a string as you type it")
+{
+ incremental_search (window, count, key);
+}
+
+DECLARE_INFO_COMMAND (isearch_backward,
+ "Search interactively for a string as you type it")
+{
+ incremental_search (window, -count, key);
+}
+
+/* Incrementally search for a string as it is typed. */
+/* The last accepted incremental search string. */
+static char *last_isearch_accepted = (char *)NULL;
+
+/* The current incremental search string. */
+static char *isearch_string = (char *)NULL;
+static int isearch_string_index = 0;
+static int isearch_string_size = 0;
+static unsigned char isearch_terminate_search_key = ESC;
+
+/* Structure defining the current state of an incremental search. */
+typedef struct {
+ WINDOW_STATE_DECL; /* The node, pagetop and point. */
+ int search_index; /* Offset of the last char in the search string. */
+ int direction; /* The direction that this search is heading in. */
+ int failing; /* Whether or not this search failed. */
+} SEARCH_STATE;
+
+/* Array of search states. */
+static SEARCH_STATE **isearch_states = (SEARCH_STATE **)NULL;
+static int isearch_states_index = 0;
+static int isearch_states_slots = 0;
+
+/* Push the state of this search. */
+static void
+push_isearch (window, search_index, direction, failing)
+ WINDOW *window;
+ int search_index, direction, failing;
+{
+ SEARCH_STATE *state;
+
+ state = (SEARCH_STATE *)xmalloc (sizeof (SEARCH_STATE));
+ window_get_state (window, state);
+ state->search_index = search_index;
+ state->direction = direction;
+ state->failing = failing;
+
+ add_pointer_to_array (state, isearch_states_index, isearch_states,
+ isearch_states_slots, 20, SEARCH_STATE *);
+}
+
+/* Pop the state of this search to WINDOW, SEARCH_INDEX, and DIRECTION. */
+static void
+pop_isearch (window, search_index, direction, failing)
+ WINDOW *window;
+ int *search_index, *direction, *failing;
+{
+ SEARCH_STATE *state;
+
+ if (isearch_states_index)
+ {
+ isearch_states_index--;
+ state = isearch_states[isearch_states_index];
+ window_set_state (window, state);
+ *search_index = state->search_index;
+ *direction = state->direction;
+ *failing = state->failing;
+
+ free (state);
+ isearch_states[isearch_states_index] = (SEARCH_STATE *)NULL;
+ }
+}
+
+/* Free the memory used by isearch_states. */
+static void
+free_isearch_states ()
+{
+ register int i;
+
+ for (i = 0; i < isearch_states_index; i++)
+ {
+ free (isearch_states[i]);
+ isearch_states[i] = (SEARCH_STATE *)NULL;
+ }
+ isearch_states_index = 0;
+}
+
+/* Display the current search in the echo area. */
+static void
+show_isearch_prompt (dir, string, failing_p)
+ int dir;
+ unsigned char *string;
+ int failing_p;
+{
+ register int i;
+ char *prefix, *prompt, *p_rep;
+ int prompt_len, p_rep_index, p_rep_size;
+
+ if (dir < 0)
+ prefix = "I-search backward: ";
+ else
+ prefix = "I-search: ";
+
+ p_rep_index = p_rep_size = 0;
+ p_rep = (char *)NULL;
+ for (i = 0; string[i]; i++)
+ {
+ char *rep;
+
+ switch (string[i])
+ {
+ case ' ': rep = " "; break;
+ case LFD: rep = "\\n"; break;
+ case TAB: rep = "\\t"; break;
+ default:
+ rep = pretty_keyname (string[i]);
+ }
+ if ((p_rep_index + strlen (rep) + 1) >= p_rep_size)
+ p_rep = (char *)xrealloc (p_rep, p_rep_size += 100);
+
+ strcpy (p_rep + p_rep_index, rep);
+ p_rep_index += strlen (rep);
+ }
+
+ prompt_len = strlen (prefix) + p_rep_index + 20;
+ prompt = (char *)xmalloc (prompt_len);
+ sprintf (prompt, "%s%s%s", failing_p ? "Failing " : "", prefix,
+ p_rep ? p_rep : "");
+
+ window_message_in_echo_area ("%s", prompt);
+ maybe_free (p_rep);
+ free (prompt);
+ display_cursor_at_point (active_window);
+}
+
+static void
+incremental_search (window, count, ignore)
+ WINDOW *window;
+ int count;
+ unsigned char ignore;
+{
+ unsigned char key;
+ int last_search_result, search_result, dir;
+ SEARCH_STATE mystate, orig_state;
+
+ if (count < 0)
+ dir = -1;
+ else
+ dir = 1;
+
+ last_search_result = search_result = 0;
+
+ window_get_state (window, &orig_state);
+
+ isearch_string_index = 0;
+ if (!isearch_string_size)
+ isearch_string = (char *)xmalloc (isearch_string_size = 50);
+
+ /* Show the search string in the echo area. */
+ isearch_string[isearch_string_index] = '\0';
+ show_isearch_prompt (dir, isearch_string, search_result);
+
+ isearch_is_active = 1;
+
+ while (isearch_is_active)
+ {
+ VFunction *func = (VFunction *)NULL;
+ int quoted = 0;
+
+ /* If a recent display was interrupted, then do the redisplay now if
+ it is convenient. */
+ if (!info_any_buffered_input_p () && display_was_interrupted_p)
+ {
+ display_update_one_window (window);
+ display_cursor_at_point (active_window);
+ }
+
+ /* Read a character and dispatch on it. */
+ key = info_get_input_char ();
+ window_get_state (window, &mystate);
+
+ if (key == DEL)
+ {
+ /* User wants to delete one level of search? */
+ if (!isearch_states_index)
+ {
+ terminal_ring_bell ();
+ continue;
+ }
+ else
+ {
+ pop_isearch
+ (window, &isearch_string_index, &dir, &search_result);
+ isearch_string[isearch_string_index] = '\0';
+ show_isearch_prompt (dir, isearch_string, search_result);
+ goto after_search;
+ }
+ }
+ else if (key == Control ('q'))
+ {
+ key = info_get_input_char ();
+ quoted = 1;
+ }
+
+ /* We are about to search again, or quit. Save the current search. */
+ push_isearch (window, isearch_string_index, dir, search_result);
+
+ if (quoted)
+ goto insert_and_search;
+
+ if (!Meta_p (key) || (ISO_Latin_p && key < 160))
+ {
+ func = window->keymap[key].function;
+
+ /* If this key invokes an incremental search, then this means that
+ we will either search again in the same direction, search
+ again in the reverse direction, or insert the last search
+ string that was accepted through incremental searching. */
+ if (func == isearch_forward || func == isearch_backward)
+ {
+ if ((func == isearch_forward && dir > 0) ||
+ (func == isearch_backward && dir < 0))
+ {
+ /* If the user has typed no characters, then insert the
+ last successful search into the current search string. */
+ if (isearch_string_index == 0)
+ {
+ /* Of course, there must be something to insert. */
+ if (last_isearch_accepted)
+ {
+ if (strlen (last_isearch_accepted) + 1 >=
+ isearch_string_size)
+ isearch_string = (char *)
+ xrealloc (isearch_string,
+ isearch_string_size += 10 +
+ strlen (last_isearch_accepted));
+ strcpy (isearch_string, last_isearch_accepted);
+ isearch_string_index = strlen (isearch_string);
+ goto search_now;
+ }
+ else
+ continue;
+ }
+ else
+ {
+ /* Search again in the same direction. This means start
+ from a new place if the last search was successful. */
+ if (search_result == 0)
+ window->point += dir;
+ }
+ }
+ else
+ {
+ /* Reverse the direction of the search. */
+ dir = -dir;
+ }
+ }
+ else if (isprint (key) || func == (VFunction *)NULL)
+ {
+ insert_and_search:
+
+ if (isearch_string_index + 2 >= isearch_string_size)
+ isearch_string = (char *)xrealloc
+ (isearch_string, isearch_string_size += 100);
+
+ isearch_string[isearch_string_index++] = key;
+ isearch_string[isearch_string_index] = '\0';
+ goto search_now;
+ }
+ else if (func == info_abort_key)
+ {
+ /* If C-g pressed, and the search is failing, pop the search
+ stack back to the last unfailed search. */
+ if (isearch_states_index && (search_result != 0))
+ {
+ terminal_ring_bell ();
+ while (isearch_states_index && (search_result != 0))
+ pop_isearch
+ (window, &isearch_string_index, &dir, &search_result);
+ isearch_string[isearch_string_index] = '\0';
+ show_isearch_prompt (dir, isearch_string, search_result);
+ continue;
+ }
+ else
+ goto exit_search;
+ }
+ else
+ goto exit_search;
+ }
+ else
+ {
+ exit_search:
+ /* The character is not printable, or it has a function which is
+ non-null. Exit the search, remembering the search string. If
+ the key is not the same as the isearch_terminate_search_key,
+ then push it into pending input. */
+ if (isearch_string_index && func != info_abort_key)
+ {
+ maybe_free (last_isearch_accepted);
+ last_isearch_accepted = savestring (isearch_string);
+ }
+
+ if (key != isearch_terminate_search_key)
+ info_set_pending_input (key);
+
+ if (func == info_abort_key)
+ {
+ if (isearch_states_index)
+ window_set_state (window, &orig_state);
+ }
+
+ if (!echo_area_is_active)
+ window_clear_echo_area ();
+
+ if (auto_footnotes_p)
+ info_get_or_remove_footnotes (active_window);
+
+ isearch_is_active = 0;
+ continue;
+ }
+
+ /* Search for the contents of isearch_string. */
+ search_now:
+ show_isearch_prompt (dir, isearch_string, search_result);
+
+ if (search_result == 0)
+ {
+ /* Check to see if the current search string is right here. If
+ we are looking at it, then don't bother calling the search
+ function. */
+ if (((dir < 0) &&
+ (strnicmp (window->node->contents + window->point,
+ isearch_string, isearch_string_index) == 0)) ||
+ ((dir > 0) &&
+ ((window->point - isearch_string_index) >= 0) &&
+ (strnicmp (window->node->contents +
+ (window->point - (isearch_string_index - 1)),
+ isearch_string, isearch_string_index) == 0)))
+ {
+ if (dir > 0)
+ window->point++;
+ }
+ else
+ search_result = info_search_internal (isearch_string, window, dir);
+ }
+
+ /* If this search failed, and we didn't already have a failed search,
+ then ring the terminal bell. */
+ if (search_result != 0 && last_search_result == 0)
+ terminal_ring_bell ();
+
+ after_search:
+ show_isearch_prompt (dir, isearch_string, search_result);
+
+ if (search_result == 0)
+ {
+ if ((mystate.node == window->node) &&
+ (mystate.pagetop != window->pagetop))
+ {
+ int newtop = window->pagetop;
+ window->pagetop = mystate.pagetop;
+ set_window_pagetop (window, newtop);
+ }
+ display_update_one_window (window);
+ display_cursor_at_point (window);
+ }
+
+ last_search_result = search_result;
+ }
+
+ /* Free the memory used to remember each search state. */
+ free_isearch_states ();
+
+ /* Perhaps GC some file buffers. */
+ info_gc_file_buffers ();
+
+ /* After searching, leave the window in the correct state. */
+ if (!echo_area_is_active)
+ window_clear_echo_area ();
+}
+
+/* GC some file buffers. A file buffer can be gc-ed if there we have
+ no nodes in INFO_WINDOWS that reference this file buffer's contents.
+ Garbage collecting a file buffer means to free the file buffers
+ contents. */
+static void
+info_gc_file_buffers ()
+{
+ register int fb_index, iw_index, i;
+ register FILE_BUFFER *fb;
+ register INFO_WINDOW *iw;
+
+ if (!info_loaded_files)
+ return;
+
+ for (fb_index = 0; fb = info_loaded_files[fb_index]; fb_index++)
+ {
+ int fb_referenced_p = 0;
+
+ /* If already gc-ed, do nothing. */
+ if (!fb->contents)
+ continue;
+
+ /* If this file had to be uncompressed, check to see if we should
+ gc it. This means that the user-variable "gc-compressed-files"
+ is non-zero. */
+ if ((fb->flags & N_IsCompressed) && !gc_compressed_files)
+ continue;
+
+ /* If this file's contents are not gc-able, move on. */
+ if (fb->flags & N_CannotGC)
+ continue;
+
+ /* Check each INFO_WINDOW to see if it has any nodes which reference
+ this file. */
+ for (iw_index = 0; iw = info_windows[iw_index]; iw_index++)
+ {
+ for (i = 0; iw->nodes && iw->nodes[i]; i++)
+ {
+ if ((strcmp (fb->fullpath, iw->nodes[i]->filename) == 0) ||
+ (strcmp (fb->filename, iw->nodes[i]->filename) == 0))
+ {
+ fb_referenced_p = 1;
+ break;
+ }
+ }
+ }
+
+ /* If this file buffer wasn't referenced, free its contents. */
+ if (!fb_referenced_p)
+ {
+ free (fb->contents);
+ fb->contents = (char *)NULL;
+ }
+ }
+}
+
+/* **************************************************************** */
+/* */
+/* Traversing and Selecting References */
+/* */
+/* **************************************************************** */
+
+/* Move to the next or previous cross reference in this node. */
+static void
+info_move_to_xref (window, count, key, dir)
+ WINDOW *window;
+ int count;
+ unsigned char key;
+ int dir;
+{
+ long firstmenu, firstxref;
+ long nextmenu, nextxref;
+ long placement = -1;
+ long start = 0;
+ NODE *node = window->node;
+
+ if (dir < 0)
+ start = node->nodelen;
+
+ /* This search is only allowed to fail if there is no menu or cross
+ reference in the current node. Otherwise, the first menu or xref
+ found is moved to. */
+
+ firstmenu = info_search_in_node
+ (INFO_MENU_ENTRY_LABEL, node, start, (WINDOW *)NULL, dir);
+
+ /* FIRSTMENU may point directly to the line defining the menu. Skip that
+ and go directly to the first item. */
+
+ if (firstmenu != -1)
+ {
+ char *text = node->contents + firstmenu;
+
+ if (strncmp (text, INFO_MENU_LABEL, strlen (INFO_MENU_LABEL)) == 0)
+ firstmenu = info_search_in_node
+ (INFO_MENU_ENTRY_LABEL, node, firstmenu + dir, (WINDOW *)NULL, dir);
+ }
+
+ firstxref =
+ info_search_in_node (INFO_XREF_LABEL, node, start, (WINDOW *)NULL, dir);
+
+ if (firstmenu == -1 && firstxref == -1)
+ {
+ info_error ("No cross references in this node.");
+ return;
+ }
+
+ /* There is at least one cross reference or menu entry in this node.
+ Try hard to find the next available one. */
+
+ nextmenu = info_search_in_node
+ (INFO_MENU_ENTRY_LABEL, node, window->point + dir, (WINDOW *)NULL, dir);
+
+ nextxref = info_search_in_node
+ (INFO_XREF_LABEL, node, window->point + dir, (WINDOW *)NULL, dir);
+
+ /* Ignore "Menu:" as a menu item. */
+ if (nextmenu != -1)
+ {
+ char *text = node->contents + nextmenu;
+
+ if (strncmp (text, INFO_MENU_LABEL, strlen (INFO_MENU_LABEL)) == 0)
+ nextmenu = info_search_in_node
+ (INFO_MENU_ENTRY_LABEL, node, nextmenu + dir, (WINDOW *)NULL, dir);
+ }
+
+ /* If there is both a next menu entry, and a next xref entry, choose the
+ one which occurs first. Otherwise, select the one which actually
+ appears in this node following point. */
+ if (nextmenu != -1 && nextxref != -1)
+ {
+ if (((dir == 1) && (nextmenu < nextxref)) ||
+ ((dir == -1) && (nextmenu > nextxref)))
+ placement = nextmenu + 1;
+ else
+ placement = nextxref;
+ }
+ else if (nextmenu != -1)
+ placement = nextmenu + 1;
+ else if (nextxref != -1)
+ placement = nextxref;
+
+ /* If there was neither a menu or xref entry appearing in this node after
+ point, choose the first menu or xref entry appearing in this node. */
+ if (placement == -1)
+ {
+ if (firstmenu != -1 && firstxref != -1)
+ {
+ if (((dir == 1) && (firstmenu < firstxref)) ||
+ ((dir == -1) && (firstmenu > firstxref)))
+ placement = firstmenu + 1;
+ else
+ placement = firstxref;
+ }
+ else if (firstmenu != -1)
+ placement = firstmenu + 1;
+ else
+ placement = firstxref;
+ }
+ window->point = placement;
+ window_adjust_pagetop (window);
+ window->flags |= W_UpdateWindow;
+}
+
+DECLARE_INFO_COMMAND (info_move_to_prev_xref,
+ "Move to the previous cross reference")
+{
+ if (count < 0)
+ info_move_to_prev_xref (window, -count, key);
+ else
+ info_move_to_xref (window, count, key, -1);
+}
+
+DECLARE_INFO_COMMAND (info_move_to_next_xref,
+ "Move to the next cross reference")
+{
+ if (count < 0)
+ info_move_to_next_xref (window, -count, key);
+ else
+ info_move_to_xref (window, count, key, 1);
+}
+
+/* Select the menu item or reference that appears on this line. */
+DECLARE_INFO_COMMAND (info_select_reference_this_line,
+ "Select reference or menu item appearing on this line")
+{
+ char *line;
+ NODE *orig;
+
+ line = window->line_starts[window_line_of_point (window)];
+ orig = window->node;
+
+ /* If this line contains a menu item, select that one. */
+ if (strncmp ("* ", line, 2) == 0)
+ info_menu_or_ref_item (window, count, key, info_menu_of_node, 0);
+ else
+ info_menu_or_ref_item (window, count, key, info_xrefs_of_node, 0);
+}
+
+/* **************************************************************** */
+/* */
+/* Miscellaneous Info Commands */
+/* */
+/* **************************************************************** */
+
+/* What to do when C-g is pressed in a window. */
+DECLARE_INFO_COMMAND (info_abort_key, "Cancel current operation")
+{
+ /* If error printing doesn't oridinarily ring the bell, do it now,
+ since C-g always rings the bell. Otherwise, let the error printer
+ do it. */
+ if (!info_error_rings_bell_p)
+ terminal_ring_bell ();
+ info_error ("Quit");
+
+ info_initialize_numeric_arg ();
+ info_clear_pending_input ();
+ info_last_executed_command = (VFunction *)NULL;
+}
+
+/* Move the cursor to the desired line of the window. */
+DECLARE_INFO_COMMAND (info_move_to_window_line,
+ "Move to the cursor to a specific line of the window")
+{
+ int line;
+
+ /* With no numeric argument of any kind, default to the center line. */
+ if (!info_explicit_arg && count == 1)
+ line = (window->height / 2) + window->pagetop;
+ else
+ {
+ if (count < 0)
+ line = (window->height + count) + window->pagetop;
+ else
+ line = window->pagetop + count;
+ }
+
+ /* If the line doesn't appear in this window, make it do so. */
+ if ((line - window->pagetop) >= window->height)
+ line = window->pagetop + (window->height - 1);
+
+ /* If the line is too small, make it fit. */
+ if (line < window->pagetop)
+ line = window->pagetop;
+
+ /* If the selected line is past the bottom of the node, force it back. */
+ if (line >= window->line_count)
+ line = window->line_count - 1;
+
+ window->point = (window->line_starts[line] - window->node->contents);
+}
+
+/* Clear the screen and redraw its contents. Given a numeric argument,
+ move the line the cursor is on to the COUNT'th line of the window. */
+DECLARE_INFO_COMMAND (info_redraw_display, "Redraw the display")
+{
+ if ((!info_explicit_arg && count == 1) || echo_area_is_active)
+ {
+ terminal_clear_screen ();
+ display_clear_display (the_display);
+ window_mark_chain (windows, W_UpdateWindow);
+ display_update_display (windows);
+ }
+ else
+ {
+ int desired_line, point_line;
+ int new_pagetop;
+
+ point_line = window_line_of_point (window) - window->pagetop;
+
+ if (count < 0)
+ desired_line = window->height + count;
+ else
+ desired_line = count;
+
+ if (desired_line < 0)
+ desired_line = 0;
+
+ if (desired_line >= window->height)
+ desired_line = window->height - 1;
+
+ if (desired_line == point_line)
+ return;
+
+ new_pagetop = window->pagetop + (point_line - desired_line);
+
+ set_window_pagetop (window, new_pagetop);
+ }
+}
+/* This command does nothing. It is the fact that a key is bound to it
+ that has meaning. See the code at the top of info_session (). */
+DECLARE_INFO_COMMAND (info_quit, "Quit using Info")
+{}
+
+
+/* **************************************************************** */
+/* */
+/* Reading Keys and Dispatching on Them */
+/* */
+/* **************************************************************** */
+
+/* Declaration only. Special cased in info_dispatch_on_key (). */
+DECLARE_INFO_COMMAND (info_do_lowercase_version, "")
+{}
+
+static void
+dispatch_error (keyseq)
+ char *keyseq;
+{
+ char *rep;
+
+ rep = pretty_keyseq (keyseq);
+
+ if (!echo_area_is_active)
+ info_error ("Unknown command (%s).", rep);
+ else
+ {
+ char *temp;
+
+ temp = (char *)xmalloc (1 + strlen (rep) + strlen ("\"\" is invalid"));
+
+ sprintf (temp, "\"%s\" is invalid", rep);
+ terminal_ring_bell ();
+ inform_in_echo_area (temp);
+ free (temp);
+ }
+}
+
+/* Keeping track of key sequences. */
+static char *info_keyseq = (char *)NULL;
+static char keyseq_rep[100];
+static int info_keyseq_index = 0;
+static int info_keyseq_size = 0;
+static int info_keyseq_displayed_p = 0;
+
+/* Initialize the length of the current key sequence. */
+void
+initialize_keyseq ()
+{
+ info_keyseq_index = 0;
+ info_keyseq_displayed_p = 0;
+}
+
+/* Add CHARACTER to the current key sequence. */
+void
+add_char_to_keyseq (character)
+ char character;
+{
+ if (info_keyseq_index + 2 >= info_keyseq_size)
+ info_keyseq = (char *)xrealloc (info_keyseq, info_keyseq_size += 10);
+
+ info_keyseq[info_keyseq_index++] = character;
+ info_keyseq[info_keyseq_index] = '\0';
+}
+
+/* Return the pretty printable string which represents KEYSEQ. */
+char *
+pretty_keyseq (keyseq)
+ char *keyseq;
+{
+ register int i;
+
+ keyseq_rep[0] = '\0';
+
+ for (i = 0; keyseq[i]; i++)
+ {
+ sprintf (keyseq_rep + strlen (keyseq_rep), "%s%s",
+ strlen (keyseq_rep) ? " " : "",
+ pretty_keyname (keyseq[i]));
+ }
+
+ return (keyseq_rep);
+}
+
+/* Display the current value of info_keyseq. If argument EXPECTING is
+ non-zero, input is expected to be read after the key sequence is
+ displayed, so add an additional prompting character to the sequence. */
+void
+display_info_keyseq (expecting_future_input)
+ int expecting_future_input;
+{
+ char *rep;
+
+ rep = pretty_keyseq (info_keyseq);
+ if (expecting_future_input)
+ strcat (rep, "-");
+
+ if (echo_area_is_active)
+ inform_in_echo_area (rep);
+ else
+ {
+ window_message_in_echo_area (rep);
+ display_cursor_at_point (active_window);
+ }
+ info_keyseq_displayed_p = 1;
+}
+
+/* Called by interactive commands to read a keystroke. */
+unsigned char
+info_get_another_input_char ()
+{
+ int ready = 0;
+
+ /* If there isn't any input currently available, then wait a
+ moment looking for input. If we don't get it fast enough,
+ prompt a little bit with the current key sequence. */
+ if (!info_keyseq_displayed_p &&
+ !info_any_buffered_input_p () &&
+ !info_input_pending_p ())
+ {
+#if defined (FD_SET)
+ struct timeval timer;
+ fd_set readfds;
+
+ FD_ZERO (&readfds);
+ FD_SET (fileno (info_input_stream), &readfds);
+ timer.tv_sec = 0;
+ timer.tv_usec = 0;
+ ready = select (1, &readfds, (fd_set *)NULL, (fd_set *)NULL, &timer);
+#endif /* FD_SET */
+ }
+
+ if (!ready)
+ display_info_keyseq (1);
+
+ return (info_get_input_char ());
+}
+
+/* Do the command associated with KEY in MAP. If the associated command is
+ really a keymap, then read another key, and dispatch into that map. */
+void
+info_dispatch_on_key (key, map)
+ unsigned char key;
+ Keymap map;
+{
+ if (Meta_p (key) && (!ISO_Latin_p || map[key].function != ea_insert))
+ {
+ if (map[ESC].type == ISKMAP)
+ {
+ map = (Keymap)map[ESC].function;
+ add_char_to_keyseq (ESC);
+ key = UnMeta (key);
+ info_dispatch_on_key (key, map);
+ }
+ else
+ {
+ dispatch_error (info_keyseq);
+ }
+ return;
+ }
+
+ switch (map[key].type)
+ {
+ case ISFUNC:
+ {
+ VFunction *func;
+
+ func = map[key].function;
+ if (func != (VFunction *)NULL)
+ {
+ /* Special case info_do_lowercase_version (). */
+ if (func == info_do_lowercase_version)
+ {
+ info_dispatch_on_key (tolower (key), map);
+ return;
+ }
+
+ add_char_to_keyseq (key);
+
+ if (info_keyseq_displayed_p)
+ display_info_keyseq (0);
+
+ {
+ WINDOW *where;
+
+ where = active_window;
+ (*map[key].function)
+ (active_window, info_numeric_arg * info_numeric_arg_sign, key);
+
+ /* If we have input pending, then the last command was a prefix
+ command. Don't change the value of the last function vars.
+ Otherwise, remember the last command executed in the var
+ appropriate to the window in which it was executed. */
+ if (!info_input_pending_p ())
+ {
+ if (where == the_echo_area)
+ ea_last_executed_command = map[key].function;
+ else
+ info_last_executed_command = map[key].function;
+ }
+ }
+ }
+ else
+ {
+ add_char_to_keyseq (key);
+ dispatch_error (info_keyseq);
+ return;
+ }
+ }
+ break;
+
+ case ISKMAP:
+ add_char_to_keyseq (key);
+ if (map[key].function != (VFunction *)NULL)
+ {
+ unsigned char newkey;
+
+ newkey = info_get_another_input_char ();
+ info_dispatch_on_key (newkey, (Keymap)map[key].function);
+ }
+ else
+ {
+ dispatch_error (info_keyseq);
+ return;
+ }
+ break;
+ }
+}
+
+/* **************************************************************** */
+/* */
+/* Numeric Arguments */
+/* */
+/* **************************************************************** */
+
+/* Handle C-u style numeric args, as well as M--, and M-digits. */
+
+/* Non-zero means that an explicit argument has been passed to this
+ command, as in C-u C-v. */
+int info_explicit_arg = 0;
+
+/* The sign of the numeric argument. */
+int info_numeric_arg_sign = 1;
+
+/* The value of the argument itself. */
+int info_numeric_arg = 1;
+
+/* Add the current digit to the argument in progress. */
+DECLARE_INFO_COMMAND (info_add_digit_to_numeric_arg,
+ "Add this digit to the current numeric argument")
+{
+ info_numeric_arg_digit_loop (window, 0, key);
+}
+
+/* C-u, universal argument. Multiply the current argument by 4.
+ Read a key. If the key has nothing to do with arguments, then
+ dispatch on it. If the key is the abort character then abort. */
+DECLARE_INFO_COMMAND (info_universal_argument,
+ "Start (or multiply by 4) the current numeric argument")
+{
+ info_numeric_arg *= 4;
+ info_numeric_arg_digit_loop (window, 0, 0);
+}
+
+/* Create a default argument. */
+void
+info_initialize_numeric_arg ()
+{
+ info_numeric_arg = info_numeric_arg_sign = 1;
+ info_explicit_arg = 0;
+}
+
+DECLARE_INFO_COMMAND (info_numeric_arg_digit_loop, "")
+{
+ unsigned char pure_key;
+ Keymap keymap = window->keymap;
+
+ while (1)
+ {
+ if (key)
+ pure_key = key;
+ else
+ {
+ if (display_was_interrupted_p && !info_any_buffered_input_p ())
+ display_update_display (windows);
+
+ if (active_window != the_echo_area)
+ display_cursor_at_point (active_window);
+
+ pure_key = key = info_get_another_input_char ();
+
+ if (Meta_p (key))
+ add_char_to_keyseq (ESC);
+
+ add_char_to_keyseq (UnMeta (key));
+ }
+
+ if (Meta_p (key))
+ key = UnMeta (key);
+
+ if (keymap[key].type == ISFUNC &&
+ keymap[key].function == info_universal_argument)
+ {
+ info_numeric_arg *= 4;
+ key = 0;
+ continue;
+ }
+
+ if (isdigit (key))
+ {
+ if (info_explicit_arg)
+ info_numeric_arg = (info_numeric_arg * 10) + (key - '0');
+ else
+ info_numeric_arg = (key - '0');
+ info_explicit_arg = 1;
+ }
+ else
+ {
+ if (key == '-' && !info_explicit_arg)
+ {
+ info_numeric_arg_sign = -1;
+ info_numeric_arg = 1;
+ }
+ else
+ {
+ info_keyseq_index--;
+ info_dispatch_on_key (pure_key, keymap);
+ return;
+ }
+ }
+ key = 0;
+ }
+}
+
+/* **************************************************************** */
+/* */
+/* Input Character Buffering */
+/* */
+/* **************************************************************** */
+
+/* Character waiting to be read next. */
+static int pending_input_character = 0;
+
+/* How to make there be no pending input. */
+static void
+info_clear_pending_input ()
+{
+ pending_input_character = 0;
+}
+
+/* How to set the pending input character. */
+static void
+info_set_pending_input (key)
+ unsigned char key;
+{
+ pending_input_character = key;
+}
+
+/* How to see if there is any pending input. */
+unsigned char
+info_input_pending_p ()
+{
+ return (pending_input_character);
+}
+
+/* Largest number of characters that we can read in advance. */
+#define MAX_INFO_INPUT_BUFFERING 512
+
+static int pop_index = 0, push_index = 0;
+static unsigned char info_input_buffer[MAX_INFO_INPUT_BUFFERING];
+
+/* Add KEY to the buffer of characters to be read. */
+static void
+info_push_typeahead (key)
+ unsigned char key;
+{
+ /* Flush all pending input in the case of C-g pressed. */
+ if (key == Control ('g'))
+ {
+ push_index = pop_index;
+ info_set_pending_input (Control ('g'));
+ }
+ else
+ {
+ info_input_buffer[push_index++] = key;
+ if (push_index >= sizeof (info_input_buffer))
+ push_index = 0;
+ }
+}
+
+/* Return the amount of space available in INFO_INPUT_BUFFER for new chars. */
+static int
+info_input_buffer_space_available ()
+{
+ if (pop_index > push_index)
+ return (pop_index - push_index);
+ else
+ return (sizeof (info_input_buffer - (push_index - pop_index)));
+}
+
+/* Get a key from the buffer of characters to be read.
+ Return the key in KEY.
+ Result is non-zero if there was a key, or 0 if there wasn't. */
+static int
+info_get_key_from_typeahead (key)
+ unsigned char *key;
+{
+ if (push_index == pop_index)
+ return (0);
+
+ *key = info_input_buffer[pop_index++];
+
+ if (pop_index >= sizeof (info_input_buffer))
+ pop_index = 0;
+
+ return (1);
+}
+
+int
+info_any_buffered_input_p ()
+{
+ info_gather_typeahead ();
+ return (push_index != pop_index);
+}
+
+/* Push KEY into the *front* of the input buffer. Returns non-zero if
+ successful, zero if there is no space left in the buffer. */
+static int
+info_replace_key_to_typeahead (key)
+ unsigned char key;
+{
+ if (info_input_buffer_space_available ())
+ {
+ pop_index--;
+ if (pop_index < 0)
+ pop_index = sizeof (info_input_buffer) - 1;
+ info_input_buffer[pop_index] = key;
+ return (1);
+ }
+ return (0);
+}
+
+/* If characters are available to be read, then read them and stuff them into
+ info_input_buffer. Otherwise, do nothing. */
+void
+info_gather_typeahead ()
+{
+ int tty, space_avail;
+ long chars_avail;
+ unsigned char input[MAX_INFO_INPUT_BUFFERING];
+
+ tty = fileno (info_input_stream);
+ chars_avail = 0;
+
+ space_avail = info_input_buffer_space_available ();
+
+ /* If we can just find out how many characters there are to read, do so. */
+#if defined (FIONREAD)
+ {
+ ioctl (tty, FIONREAD, &chars_avail);
+
+ if (chars_avail > space_avail)
+ chars_avail = space_avail;
+
+ if (chars_avail)
+ read (tty, &input[0], chars_avail);
+ }
+#else /* !FIONREAD */
+# if defined (O_NDELAY)
+ {
+ int flags;
+
+ flags = fcntl (tty, F_GETFL, 0);
+
+ fcntl (tty, F_SETFL, (flags | O_NDELAY));
+ chars_avail = read (tty, &input[0], space_avail);
+ fcntl (tty, F_SETFL, flags);
+
+ if (chars_avail == -1)
+ chars_avail = 0;
+ }
+# endif /* O_NDELAY */
+#endif /* !FIONREAD */
+
+ /* Store the input characters just read into our input buffer. */
+ {
+ register int i;
+
+ for (i = 0; i < chars_avail; i++)
+ info_push_typeahead (input[i]);
+ }
+}
+
+/* How to read a single character. */
+unsigned char
+info_get_input_char ()
+{
+ unsigned char keystroke;
+
+ info_gather_typeahead ();
+
+ if (pending_input_character)
+ {
+ keystroke = pending_input_character;
+ pending_input_character = 0;
+ }
+ else if (info_get_key_from_typeahead (&keystroke) == 0)
+ {
+ int rawkey;
+
+ rawkey = getc (info_input_stream);
+ keystroke = rawkey;
+
+ if (rawkey == EOF)
+ {
+ if (info_input_stream != stdin)
+ {
+ fclose (info_input_stream);
+ info_input_stream = stdin;
+ display_inhibited = 0;
+ display_update_display (windows);
+ display_cursor_at_point (active_window);
+ rawkey = getc (info_input_stream);
+ keystroke = rawkey;
+ }
+
+ if (rawkey == EOF)
+ {
+ terminal_unprep_terminal ();
+ close_dribble_file ();
+ exit (0);
+ }
+ }
+ }
+
+ if (info_dribble_file)
+ dribble (keystroke);
+
+ return (keystroke);
+}
diff --git a/gnu/usr.bin/texinfo/info/session.h b/gnu/usr.bin/texinfo/info/session.h
new file mode 100644
index 0000000..08042dd
--- /dev/null
+++ b/gnu/usr.bin/texinfo/info/session.h
@@ -0,0 +1,146 @@
+/* session.h -- Functions found in session.c. */
+
+/* This file is part of GNU Info, a program for reading online documentation
+ stored in Info format.
+
+ Copyright (C) 1993 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ Written by Brian Fox (bfox@ai.mit.edu). */
+
+#ifndef _SESSION_H_
+#define _SESSION_H_
+
+#include "general.h"
+#include "dribble.h"
+
+/* All commands that can be invoked from within info_session () receive
+ arguments in the same way. This simple define declares the header
+ of a function named NAME, with associated documentation DOC. The
+ documentation string is groveled out of the source files by the
+ utility program `builddoc', which is also responsible for making
+ the documentation/function-pointer maps. */
+#define DECLARE_INFO_COMMAND(name, doc) \
+void name (window, count, key) WINDOW *window; int count; unsigned char key;
+
+/* Variables found in session.h. */
+extern VFunction *info_last_executed_command;
+
+/* Variable controlling the garbage collection of files briefly visited
+ during searches. Such files are normally gc'ed, unless they were
+ compressed to begin with. If this variable is non-zero, it says
+ to gc even those file buffer contents which had to be uncompressed. */
+extern int gc_compressed_files;
+
+/* When non-zero, tiling takes place automatically when info_split_window
+ is called. */
+extern int auto_tiling_p;
+
+/* Variable controlling the behaviour of default scrolling when you are
+ already at the bottom of a node. */
+extern int info_scroll_behaviour;
+extern char *info_scroll_choices[];
+
+/* Values for info_scroll_behaviour. */
+#define IS_Continuous 0 /* Try to get first menu item, or failing that, the
+ "Next:" pointer, or failing that, the "Up:" and
+ "Next:" of the up. */
+#define IS_NextOnly 1 /* Try to get "Next:" menu item. */
+#define IS_PageOnly 2 /* Simply give up at the bottom of a node. */
+
+/* Utility functions found in session.c */
+extern void info_dispatch_on_key ();
+extern unsigned char info_get_input_char (), info_get_another_input_char ();
+extern unsigned char info_input_pending_p ();
+extern void remember_window_and_node (), set_remembered_pagetop_and_point ();
+extern void set_window_pagetop (), info_set_node_of_window ();
+extern char *pretty_keyseq ();
+extern void initialize_keyseq (), add_char_to_keyseq ();
+extern void info_gather_typeahead ();
+extern FILE_BUFFER *file_buffer_of_window ();
+extern long info_search_in_node (), info_target_search_node ();
+extern void info_select_reference ();
+extern int info_any_buffered_input_p ();
+extern void print_node ();
+extern void dump_node_to_file (), dump_nodes_to_file ();
+
+/* Do the physical deletion of WINDOW, and forget this window and
+ associated nodes. */
+extern void info_delete_window_internal ();
+
+/* Tell Info that input is coming from the file FILENAME. */
+extern void info_set_input_from_file ();
+
+#define return_if_control_g(val) \
+ do { \
+ info_gather_typeahead (); \
+ if (info_input_pending_p () == Control ('g')) \
+ return (val); \
+ } while (0)
+
+/* The names of the functions that run an info session. */
+
+/* Starting an info session. */
+extern void begin_multiple_window_info_session (), begin_info_session ();
+extern void begin_info_session_with_error (), info_session ();
+extern void info_read_and_dispatch ();
+
+/* Moving the point within a node. */
+extern void info_next_line (), info_prev_line ();
+extern void info_end_of_line (), info_beginning_of_line ();
+extern void info_forward_char (), info_backward_char ();
+extern void info_forward_word (), info_backward_word ();
+extern void info_beginning_of_node (), info_end_of_node ();
+extern void info_move_to_prev_xref (), info_move_to_next_xref ();
+
+/* Scrolling text within a window. */
+extern void info_scroll_forward (), info_scroll_backward ();
+extern void info_redraw_display (), info_toggle_wrap ();
+extern void info_move_to_window_line ();
+
+/* Manipulating multiple windows. */
+extern void info_split_window (), info_delete_window ();
+extern void info_keep_one_window (), info_grow_window ();
+extern void info_scroll_other_window (), info_tile_windows ();
+extern void info_next_window (), info_prev_window ();
+
+/* Selecting nodes. */
+extern void info_next_node (), info_prev_node (), info_up_node ();
+extern void info_last_node (), info_first_node (), info_history_node ();
+extern void info_goto_node (), info_top_node (), info_dir_node ();
+extern void info_global_next_node (), info_global_prev_node ();
+extern void info_kill_node (), info_view_file ();
+
+/* Selecting cross references. */
+extern void info_menu_digit (), info_menu_item (), info_xref_item ();
+extern void info_find_menu (), info_select_reference_this_line ();
+
+/* Hacking numeric arguments. */
+extern int info_explicit_arg, info_numeric_arg, info_numeric_arg_sign;
+
+extern void info_add_digit_to_numeric_arg (), info_universal_argument ();
+extern void info_initialize_numeric_arg (), info_numeric_arg_digit_loop ();
+
+/* Searching commands. */
+extern void info_search (), isearch_forward (), isearch_backward ();
+
+/* Dumping and printing nodes. */
+extern void info_print_node ();
+
+/* Miscellaneous commands. */
+extern void info_abort_key (), info_quit (), info_do_lowercase_version ();
+
+#endif /* _SESSION_H_ */
diff --git a/gnu/usr.bin/texinfo/info/signals.c b/gnu/usr.bin/texinfo/info/signals.c
new file mode 100644
index 0000000..7184f6a
--- /dev/null
+++ b/gnu/usr.bin/texinfo/info/signals.c
@@ -0,0 +1,189 @@
+/* signals.c -- Install and maintain Info signal handlers. */
+
+/* This file is part of GNU Info, a program for reading online documentation
+ stored in Info format.
+
+ Copyright (C) 1993 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ Written by Brian Fox (bfox@ai.mit.edu). */
+
+#include "info.h"
+#include "signals.h"
+
+/* **************************************************************** */
+/* */
+/* Pretending That We Have POSIX Signals */
+/* */
+/* **************************************************************** */
+
+#if !defined (_POSIX_VERSION)
+/* Perform OPERATION on NEWSET, perhaps leaving information in OLDSET. */
+static void
+sigprocmask (operation, newset, oldset)
+ int operation, *newset, *oldset;
+{
+ switch (operation)
+ {
+ case SIG_UNBLOCK:
+#if defined (HAVE_SIGSETMASK)
+ sigsetmask (sigblock (0) & ~(*newset));
+#endif /* HAVE_SIGSETMASK */
+ break;
+
+ case SIG_BLOCK:
+ *oldset = sigblock (*newset);
+ break;
+
+ case SIG_SETMASK:
+#if defined (HAVE_SIGSETMASK)
+ sigsetmask (*newset);
+#endif /* HAVE_SIGSETMASK */
+ break;
+
+ default:
+ abort ();
+ }
+}
+#endif /* !_POSIX_VERSION */
+
+/* **************************************************************** */
+/* */
+/* Signal Handling for Info */
+/* */
+/* **************************************************************** */
+
+typedef void SigHandlerType;
+typedef SigHandlerType SigHandler ();
+
+static SigHandlerType info_signal_handler ();
+static SigHandler *old_TSTP, *old_TTOU, *old_TTIN;
+static SigHandler *old_WINCH, *old_INT, *old_CONT;
+
+void
+initialize_info_signal_handler ()
+{
+#if defined (SIGTSTP)
+ old_TSTP = (SigHandler *) signal (SIGTSTP, info_signal_handler);
+ old_TTOU = (SigHandler *) signal (SIGTTOU, info_signal_handler);
+ old_TTIN = (SigHandler *) signal (SIGTTIN, info_signal_handler);
+#endif /* SIGTSTP */
+
+#if defined (SIGWINCH)
+ old_WINCH = (SigHandler *) signal (SIGWINCH, info_signal_handler);
+#if defined (SIGCONT)
+ old_CONT = (SigHandler *) signal (SIGCONT, info_signal_handler);
+#endif /* SIGCONT */
+#endif /* SIGWINCH */
+
+#if defined (SIGINT)
+ old_INT = (SigHandler *) signal (SIGINT, info_signal_handler);
+#endif
+}
+
+static void
+redisplay_after_signal ()
+{
+ terminal_clear_screen ();
+ display_clear_display (the_display);
+ window_mark_chain (windows, W_UpdateWindow);
+ display_update_display (windows);
+ display_cursor_at_point (active_window);
+ fflush (stdout);
+}
+
+static SigHandlerType
+info_signal_handler (sig)
+ int sig;
+{
+ SigHandler **old_signal_handler;
+
+ switch (sig)
+ {
+#if defined (SIGTSTP)
+ case SIGTSTP:
+ case SIGTTOU:
+ case SIGTTIN:
+#endif
+#if defined (SIGINT)
+ case SIGINT:
+#endif
+ {
+#if defined (SIGTSTP)
+ if (sig == SIGTSTP)
+ old_signal_handler = &old_TSTP;
+ if (sig == SIGTTOU)
+ old_signal_handler = &old_TTOU;
+ if (sig == SIGTTIN)
+ old_signal_handler = &old_TTIN;
+#endif /* SIGTSTP */
+ if (sig == SIGINT)
+ old_signal_handler = &old_INT;
+
+ /* For stop signals, restore the terminal IO, leave the cursor
+ at the bottom of the window, and stop us. */
+ terminal_goto_xy (0, screenheight - 1);
+ terminal_clear_to_eol ();
+ fflush (stdout);
+ terminal_unprep_terminal ();
+ signal (sig, *old_signal_handler);
+ UNBLOCK_SIGNAL (sig);
+ kill (getpid (), sig);
+
+ /* The program is returning now. Restore our signal handler,
+ turn on terminal handling, redraw the screen, and place the
+ cursor where it belongs. */
+ terminal_prep_terminal ();
+ *old_signal_handler = (SigHandler *) signal (sig, info_signal_handler);
+ redisplay_after_signal ();
+ fflush (stdout);
+ }
+ break;
+
+#if defined (SIGWINCH) && defined(SIGCONT)
+ case SIGCONT:
+ if(old_CONT)
+ (void)(old_CONT)(sig);
+ /* pretend a SIGWINCH in case the terminal window size has changed
+ while we've been asleep */
+ /* FALLTROUGH */
+#endif /* defined (SIGWINCH) && defined(SIGCONT) */
+
+#if defined (SIGWINCH)
+ case SIGWINCH:
+ {
+ /* Turn off terminal IO, tell our parent that the window has changed,
+ then reinitialize the terminal and rebuild our windows. */
+ old_signal_handler = &old_WINCH;
+ terminal_goto_xy (0, 0);
+ fflush (stdout);
+ terminal_unprep_terminal ();
+ signal (sig, *old_signal_handler);
+ UNBLOCK_SIGNAL (sig);
+ kill (getpid (), sig);
+
+ /* After our old signal handler returns... */
+ terminal_get_screen_size ();
+ terminal_prep_terminal ();
+ display_initialize_display (screenwidth, screenheight);
+ window_new_screen_size (screenwidth, screenheight, (VFunction *)NULL);
+ *old_signal_handler = (SigHandler *) signal (sig, info_signal_handler);
+ redisplay_after_signal ();
+ }
+ break;
+#endif /* SIGWINCH */
+ }
+}
diff --git a/gnu/usr.bin/texinfo/info/signals.h b/gnu/usr.bin/texinfo/info/signals.h
new file mode 100644
index 0000000..8fb77f8
--- /dev/null
+++ b/gnu/usr.bin/texinfo/info/signals.h
@@ -0,0 +1,85 @@
+/* signals.h -- Header to include system dependent signal definitions. */
+
+/* This file is part of GNU Info, a program for reading online documentation
+ stored in Info format.
+
+ Copyright (C) 1993 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ Written by Brian Fox (bfox@ai.mit.edu). */
+
+#ifndef _SIGNALS_H_
+#define _SIGNALS_H_
+
+#include <signal.h>
+
+#define HAVE_SIGSETMASK
+
+#if !defined (_POSIX_VERSION) && !defined (sigmask)
+# define sigmask(x) (1 << ((x)-1))
+#endif /* !POSIX && !sigmask */
+
+#if !defined (_POSIX_VERSION)
+# if !defined (SIG_BLOCK)
+# define SIG_UNBLOCK 1
+# define SIG_BLOCK 2
+# define SIG_SETMASK 3
+# endif /* SIG_BLOCK */
+
+/* Type of a signal set. */
+# define sigset_t int
+
+/* Make SET have no signals in it. */
+# define sigemptyset(set) (*(set) = (sigset_t)0x0)
+
+/* Make SET have the full range of signal specifications possible. */
+# define sigfillset(set) (*(set) = (sigset_t)0xffffffffff)
+
+/* Add SIG to the contents of SET. */
+# define sigaddset(set, sig) *(set) |= sigmask (sig)
+
+/* Delete SIG from the contents of SET. */
+# define sigdelset(set, sig) *(set) &= ~(sigmask (sig))
+
+/* Tell if SET contains SIG. */
+# define sigismember(set, sig) (*(set) & (sigmask (sig)))
+
+/* Suspend the process until the reception of one of the signals
+ not present in SET. */
+# define sigsuspend(set) sigpause (*(set))
+#endif /* !_POSIX_VERSION */
+
+/* These definitions are used both in POSIX and non-POSIX implementations. */
+
+#define BLOCK_SIGNAL(sig) \
+ do { \
+ sigset_t nvar, ovar; \
+ sigemptyset (&nvar); \
+ sigemptyset (&ovar); \
+ sigaddset (&nvar, sig); \
+ sigprocmask (SIG_BLOCK, &nvar, &ovar); \
+ } while (0)
+
+#define UNBLOCK_SIGNAL(sig) \
+ do { \
+ sigset_t nvar, ovar; \
+ sigemptyset (&ovar); \
+ sigemptyset (&nvar); \
+ sigaddset (&nvar, sig); \
+ sigprocmask (SIG_UNBLOCK, &nvar, &ovar); \
+ } while (0)
+
+#endif /* !_SIGNALS_H_ */
diff --git a/gnu/usr.bin/texinfo/info/termdep.h b/gnu/usr.bin/texinfo/info/termdep.h
new file mode 100644
index 0000000..f4b6634
--- /dev/null
+++ b/gnu/usr.bin/texinfo/info/termdep.h
@@ -0,0 +1,64 @@
+/* termdep.h -- System things that terminal.c depends on. */
+
+/* This file is part of GNU Info, a program for reading online documentation
+ stored in Info format.
+
+ Copyright (C) 1993 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ Written by Brian Fox (bfox@ai.mit.edu). */
+
+#if defined (HAVE_SYS_FCNTL_H)
+#include <sys/fcntl.h>
+#else
+#include <fcntl.h>
+#endif /* !HAVE_SYS_FCNTL_H */
+
+#if defined (HAVE_TERMIO_H)
+#include <termio.h>
+#include <string.h>
+#if defined (HAVE_SYS_PTEM_H)
+#if !defined (M_XENIX)
+#include <sys/stream.h>
+#include <sys/ptem.h>
+#undef TIOCGETC
+#else /* M_XENIX */
+#define tchars tc
+#endif /* M_XENIX */
+#endif /* HAVE_SYS_PTEM_H */
+#else /* !HAVE_TERMIO_H */
+#include <sys/file.h>
+#include <sgtty.h>
+#include <strings.h>
+#endif /* !HAVE_TERMIO_H */
+
+#if defined (HAVE_SYS_TTOLD_H)
+#include <sys/ttold.h>
+#endif /* HAVE_SYS_TTOLD_H */
+
+#if !defined (HAVE_RINDEX)
+#undef index
+#undef rindex
+#define index strchr
+#define rindex strrchr
+#endif
+
+#if !defined (HAVE_BCOPY)
+#undef bcopy
+#define bcopy(source, dest, count) memcpy(dest, source, count)
+#endif
+
+/* eof */
diff --git a/gnu/usr.bin/texinfo/info/terminal.c b/gnu/usr.bin/texinfo/info/terminal.c
new file mode 100644
index 0000000..3c92337
--- /dev/null
+++ b/gnu/usr.bin/texinfo/info/terminal.c
@@ -0,0 +1,768 @@
+/* terminal.c -- How to handle the physical terminal for Info. */
+
+/* This file is part of GNU Info, a program for reading online documentation
+ stored in Info format.
+
+ This file has appeared in prior works by the Free Software Foundation;
+ thus it carries copyright dates from 1988 through 1993.
+
+ Copyright (C) 1988, 1989, 1990, 1991, 1992, 1993 Free Software
+ Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ Written by Brian Fox (bfox@ai.mit.edu). */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include "terminal.h"
+#include "termdep.h"
+
+extern void *xmalloc (), *xrealloc ();
+
+/* The Unix termcap interface code. */
+
+extern int tgetnum (), tgetflag (), tgetent ();
+extern char *tgetstr (), *tgoto ();
+extern char *getenv ();
+extern void tputs ();
+
+/* Function "hooks". If you make one of these point to a function, that
+ function is called when appropriate instead of its namesake. Your
+ function is called with exactly the same arguments that were passed
+ to the namesake function. */
+VFunction *terminal_begin_inverse_hook = (VFunction *)NULL;
+VFunction *terminal_end_inverse_hook = (VFunction *)NULL;
+VFunction *terminal_prep_terminal_hook = (VFunction *)NULL;
+VFunction *terminal_unprep_terminal_hook = (VFunction *)NULL;
+VFunction *terminal_up_line_hook = (VFunction *)NULL;
+VFunction *terminal_down_line_hook = (VFunction *)NULL;
+VFunction *terminal_clear_screen_hook = (VFunction *)NULL;
+VFunction *terminal_clear_to_eol_hook = (VFunction *)NULL;
+VFunction *terminal_get_screen_size_hook = (VFunction *)NULL;
+VFunction *terminal_goto_xy_hook = (VFunction *)NULL;
+VFunction *terminal_initialize_terminal_hook = (VFunction *)NULL;
+VFunction *terminal_new_terminal_hook = (VFunction *)NULL;
+VFunction *terminal_put_text_hook = (VFunction *)NULL;
+VFunction *terminal_ring_bell_hook = (VFunction *)NULL;
+VFunction *terminal_write_chars_hook = (VFunction *)NULL;
+VFunction *terminal_scroll_terminal_hook = (VFunction *)NULL;
+
+/* **************************************************************** */
+/* */
+/* Terminal and Termcap */
+/* */
+/* **************************************************************** */
+
+/* On Solaris2, sys/types.h #includes sys/reg.h, which #defines PC.
+ Unfortunately, PC is a global variable used by the termcap library. */
+#undef PC
+
+/* TERMCAP requires these variables, whether we access them or not. */
+char PC;
+char *BC, *UP;
+short ospeed;
+
+/* A buffer which holds onto the current terminal description, and a pointer
+ used to float within it. */
+static char *term_buffer = (char *)NULL;
+static char *term_string_buffer = (char *)NULL;
+
+/* Some strings to control terminal actions. These are output by tputs (). */
+static char *term_goto, *term_clreol, *term_cr, *term_clrpag;
+static char *term_begin_use, *term_end_use;
+static char *term_AL, *term_DL, *term_al, *term_dl;
+
+/* How to go up a line. */
+static char *term_up;
+
+/* How to go down a line. */
+static char *term_dn;
+
+/* An audible bell, if the terminal can be made to make noise. */
+static char *audible_bell;
+
+/* A visible bell, if the terminal can be made to flash the screen. */
+static char *visible_bell;
+
+/* The string to write to turn on the meta key, if this term has one. */
+static char *term_mm;
+
+/* The string to write to turn off the meta key, if this term has one. */
+static char *term_mo;
+
+/* The string to turn on inverse mode, if this term has one. */
+static char *term_invbeg;
+
+/* The string to turn off inverse mode, if this term has one. */
+static char *term_invend;
+
+/* The string to turn on keypad transmit mode, if this term has one. */
+static char *term_ks;
+
+/* The string to turn off keypad transmit mode, if this term has one. */
+static char *term_ke;
+
+static void
+output_character_function (c)
+ int c;
+{
+ putc (c, stdout);
+}
+
+/* Macro to send STRING to the terminal. */
+#define send_to_terminal(string) \
+ do { \
+ if (string) \
+ tputs (string, 1, output_character_function); \
+ } while (0)
+
+/* Tell the terminal that we will be doing cursor addressable motion. */
+static void
+terminal_begin_using_terminal ()
+{
+ send_to_terminal (term_begin_use);
+ if (term_ks)
+ send_to_terminal(term_ks);
+}
+
+/* Tell the terminal that we will not be doing any more cursor addressable
+ motion. */
+static void
+terminal_end_using_terminal ()
+{
+ if (term_ke)
+ send_to_terminal(term_ke);
+ send_to_terminal (term_end_use);
+}
+
+/* **************************************************************** */
+/* */
+/* Necessary Terminal Functions */
+/* */
+/* **************************************************************** */
+
+/* The functions and variables on this page implement the user visible
+ portion of the terminal interface. */
+
+/* The width and height of the terminal. */
+int screenwidth, screenheight;
+
+/* Non-zero means this terminal can't really do anything. */
+int terminal_is_dumb_p = 0;
+
+/* Non-zero means that this terminal has a meta key. */
+int terminal_has_meta_p = 0;
+
+/* Non-zero means that this terminal can produce a visible bell. */
+int terminal_has_visible_bell_p = 0;
+
+/* Non-zero means to use that visible bell if at all possible. */
+int terminal_use_visible_bell_p = 0;
+
+/* Non-zero means that the terminal can do scrolling. */
+int terminal_can_scroll = 0;
+
+/* The key sequences output by the arrow keys, if this terminal has any. */
+/* Also use PageUp, PageDown, Home, End, if available. */
+char *term_ku, *term_kd, *term_kr, *term_kl;
+char *term_kP, *term_kN, *term_kh, *term_kH;
+
+/* Move the cursor to the terminal location of X and Y. */
+void
+terminal_goto_xy (x, y)
+ int x, y;
+{
+ if (terminal_goto_xy_hook)
+ (*terminal_goto_xy_hook) (x, y);
+ else
+ {
+ if (term_goto)
+ tputs (tgoto (term_goto, x, y), 1, output_character_function);
+ }
+}
+
+/* Print STRING to the terminal at the current position. */
+void
+terminal_put_text (string)
+ char *string;
+{
+ if (terminal_put_text_hook)
+ (*terminal_put_text_hook) (string);
+ else
+ {
+ printf ("%s", string);
+ }
+}
+
+/* Print NCHARS from STRING to the terminal at the current position. */
+void
+terminal_write_chars (string, nchars)
+ char *string;
+ int nchars;
+{
+ if (terminal_write_chars_hook)
+ (*terminal_write_chars_hook) (string, nchars);
+ else
+ {
+ if (nchars)
+ fwrite (string, 1, nchars, stdout);
+ }
+}
+
+/* Clear from the current position of the cursor to the end of the line. */
+void
+terminal_clear_to_eol ()
+{
+ if (terminal_clear_to_eol_hook)
+ (*terminal_clear_to_eol_hook) ();
+ else
+ {
+ send_to_terminal (term_clreol);
+ }
+}
+
+/* Clear the entire terminal screen. */
+void
+terminal_clear_screen ()
+{
+ if (terminal_clear_screen_hook)
+ (*terminal_clear_screen_hook) ();
+ else
+ {
+ send_to_terminal (term_clrpag);
+ }
+}
+
+/* Move the cursor up one line. */
+void
+terminal_up_line ()
+{
+ if (terminal_up_line_hook)
+ (*terminal_up_line_hook) ();
+ else
+ {
+ send_to_terminal (term_up);
+ }
+}
+
+/* Move the cursor down one line. */
+void
+terminal_down_line ()
+{
+ if (terminal_down_line_hook)
+ (*terminal_down_line_hook) ();
+ else
+ {
+ send_to_terminal (term_dn);
+ }
+}
+
+/* Turn on reverse video if possible. */
+void
+terminal_begin_inverse ()
+{
+ if (terminal_begin_inverse_hook)
+ (*terminal_begin_inverse_hook) ();
+ else
+ {
+ send_to_terminal (term_invbeg);
+ }
+}
+
+/* Turn off reverse video if possible. */
+void
+terminal_end_inverse ()
+{
+ if (terminal_end_inverse_hook)
+ (*terminal_end_inverse_hook) ();
+ else
+ {
+ send_to_terminal (term_invend);
+ }
+}
+
+/* Ring the terminal bell. The bell is run visibly if it both has one and
+ terminal_use_visible_bell_p is non-zero. */
+void
+terminal_ring_bell ()
+{
+ if (terminal_ring_bell_hook)
+ (*terminal_ring_bell_hook) ();
+ else
+ {
+ if (terminal_has_visible_bell_p && terminal_use_visible_bell_p)
+ send_to_terminal (visible_bell);
+ else
+ send_to_terminal (audible_bell);
+ }
+}
+
+/* At the line START, delete COUNT lines from the terminal display. */
+static void
+terminal_delete_lines (start, count)
+ int start, count;
+{
+ int lines;
+
+ /* Normalize arguments. */
+ if (start < 0)
+ start = 0;
+
+ lines = screenheight - start;
+ terminal_goto_xy (0, start);
+ if (term_DL)
+ tputs (tgoto (term_DL, 0, count), lines, output_character_function);
+ else
+ {
+ while (count--)
+ tputs (term_dl, lines, output_character_function);
+ }
+
+ fflush (stdout);
+}
+
+/* At the line START, insert COUNT lines in the terminal display. */
+static void
+terminal_insert_lines (start, count)
+ int start, count;
+{
+ int lines;
+
+ /* Normalize arguments. */
+ if (start < 0)
+ start = 0;
+
+ lines = screenheight - start;
+ terminal_goto_xy (0, start);
+
+ if (term_AL)
+ tputs (tgoto (term_AL, 0, count), lines, output_character_function);
+ else
+ {
+ while (count--)
+ tputs (term_al, lines, output_character_function);
+ }
+
+ fflush (stdout);
+}
+
+/* Scroll an area of the terminal, starting with the region from START
+ to END, AMOUNT lines. If AMOUNT is negative, the lines are scrolled
+ towards the top of the screen, else they are scrolled towards the
+ bottom of the screen. */
+void
+terminal_scroll_terminal (start, end, amount)
+ int start, end, amount;
+{
+ if (!terminal_can_scroll)
+ return;
+
+ /* Any scrolling at all? */
+ if (amount == 0)
+ return;
+
+ if (terminal_scroll_terminal_hook)
+ (*terminal_scroll_terminal_hook) (start, end, amount);
+ else
+ {
+ /* If we are scrolling down, delete AMOUNT lines at END. Then insert
+ AMOUNT lines at START. */
+ if (amount > 0)
+ {
+ terminal_delete_lines (end, amount);
+ terminal_insert_lines (start, amount);
+ }
+
+ /* If we are scrolling up, delete AMOUNT lines before START. This
+ actually does the upwards scroll. Then, insert AMOUNT lines
+ after the already scrolled region (i.e., END - AMOUNT). */
+ if (amount < 0)
+ {
+ int abs_amount = -amount;
+ terminal_delete_lines (start - abs_amount, abs_amount);
+ terminal_insert_lines (end - abs_amount, abs_amount);
+ }
+ }
+}
+
+/* Re-initialize the terminal considering that the TERM/TERMCAP variable
+ has changed. */
+void
+terminal_new_terminal (terminal_name)
+ char *terminal_name;
+{
+ if (terminal_new_terminal_hook)
+ (*terminal_new_terminal_hook) (terminal_name);
+ else
+ {
+ terminal_initialize_terminal (terminal_name);
+ }
+}
+
+/* Set the global variables SCREENWIDTH and SCREENHEIGHT. */
+void
+terminal_get_screen_size ()
+{
+ if (terminal_get_screen_size_hook)
+ (*terminal_get_screen_size_hook) ();
+ else
+ {
+ screenwidth = screenheight = 0;
+
+#if defined (TIOCGWINSZ)
+ {
+ struct winsize window_size;
+
+ if (ioctl (fileno (stdout), TIOCGWINSZ, &window_size) == 0)
+ {
+ screenwidth = (int) window_size.ws_col;
+ screenheight = (int) window_size.ws_row;
+ }
+ }
+#endif /* TIOCGWINSZ */
+
+ /* Environment variable COLUMNS overrides setting of "co". */
+ if (screenwidth <= 0)
+ {
+ char *sw = getenv ("COLUMNS");
+
+ if (sw)
+ screenwidth = atoi (sw);
+
+ if (screenwidth <= 0)
+ screenwidth = tgetnum ("co");
+ }
+
+ /* Environment variable LINES overrides setting of "li". */
+ if (screenheight <= 0)
+ {
+ char *sh = getenv ("LINES");
+
+ if (sh)
+ screenheight = atoi (sh);
+
+ if (screenheight <= 0)
+ screenheight = tgetnum ("li");
+ }
+
+ /* If all else fails, default to 80x24 terminal. */
+ if (screenwidth <= 0)
+ screenwidth = 80;
+
+ if (screenheight <= 0)
+ screenheight = 24;
+ }
+}
+
+/* Initialize the terminal which is known as TERMINAL_NAME. If this terminal
+ doesn't have cursor addressability, TERMINAL_IS_DUMB_P becomes non-zero.
+ The variables SCREENHEIGHT and SCREENWIDTH are set to the dimensions that
+ this terminal actually has. The variable TERMINAL_HAS_META_P becomes non-
+ zero if this terminal supports a Meta key. Finally, the terminal screen is
+ cleared. */
+void
+terminal_initialize_terminal (terminal_name)
+ char *terminal_name;
+{
+ char *term, *buffer;
+
+ terminal_is_dumb_p = 0;
+
+ if (terminal_initialize_terminal_hook)
+ {
+ (*terminal_initialize_terminal_hook) (terminal_name);
+ return;
+ }
+
+ term = terminal_name ? terminal_name : getenv ("TERM");
+
+ if (!term_string_buffer)
+ term_string_buffer = (char *)xmalloc (2048);
+
+ if (!term_buffer)
+ term_buffer = (char *)xmalloc (2048);
+
+ buffer = term_string_buffer;
+
+ term_clrpag = term_cr = term_clreol = (char *)NULL;
+
+ if (!term)
+ term = "dumb";
+
+ if (tgetent (term_buffer, term) <= 0)
+ {
+ terminal_is_dumb_p = 1;
+ screenwidth = 80;
+ screenheight = 24;
+ term_cr = "\r";
+ term_up = term_dn = audible_bell = visible_bell = (char *)NULL;
+ term_ku = term_kd = term_kl = term_kr = (char *)NULL;
+ term_kP = term_kN = term_kh = term_kH = (char *)NULL;
+ return;
+ }
+
+ BC = tgetstr ("pc", &buffer);
+ PC = BC ? *BC : 0;
+
+#if defined (TIOCGETP)
+ {
+ struct sgttyb sg;
+
+ if (ioctl (fileno (stdout), TIOCGETP, &sg) != -1)
+ ospeed = sg.sg_ospeed;
+ else
+ ospeed = B9600;
+ }
+#else
+ ospeed = B9600;
+#endif /* !TIOCGETP */
+
+ term_cr = tgetstr ("cr", &buffer);
+ term_clreol = tgetstr ("ce", &buffer);
+ term_clrpag = tgetstr ("cl", &buffer);
+ term_goto = tgetstr ("cm", &buffer);
+
+ /* Find out about this terminals scrolling capability. */
+ term_AL = tgetstr ("AL", &buffer);
+ term_DL = tgetstr ("DL", &buffer);
+ term_al = tgetstr ("al", &buffer);
+ term_dl = tgetstr ("dl", &buffer);
+
+ terminal_can_scroll = ((term_AL || term_al) && (term_DL || term_dl));
+
+ term_invbeg = tgetstr ("mr", &buffer);
+ if (term_invbeg)
+ term_invend = tgetstr ("me", &buffer);
+ else
+ term_invend = (char *)NULL;
+
+ if (!term_cr)
+ term_cr = "\r";
+
+ terminal_get_screen_size ();
+
+ term_up = tgetstr ("up", &buffer);
+ term_dn = tgetstr ("dn", &buffer);
+ visible_bell = tgetstr ("vb", &buffer);
+ terminal_has_visible_bell_p = (visible_bell != (char *)NULL);
+ audible_bell = tgetstr ("bl", &buffer);
+ if (!audible_bell)
+ audible_bell = "\007";
+ term_begin_use = tgetstr ("ti", &buffer);
+ term_end_use = tgetstr ("te", &buffer);
+
+ /* Check to see if this terminal has a meta key. */
+ terminal_has_meta_p = (tgetflag ("km") || tgetflag ("MT"));
+ if (terminal_has_meta_p)
+ {
+ term_mm = tgetstr ("mm", &buffer);
+ term_mo = tgetstr ("mo", &buffer);
+ }
+ else
+ {
+ term_mm = (char *)NULL;
+ term_mo = (char *)NULL;
+ }
+
+ /* Attempt to find the arrow keys. */
+ term_ku = tgetstr ("ku", &buffer);
+ term_kd = tgetstr ("kd", &buffer);
+ term_kr = tgetstr ("kr", &buffer);
+ term_kl = tgetstr ("kl", &buffer);
+ term_kP = tgetstr ("kP", &buffer);
+ term_kN = tgetstr ("kN", &buffer);
+ term_kh = tgetstr ("kh", &buffer);
+ term_kH = tgetstr ("kH", &buffer);
+
+ /* Enable keypad and cursor keys if ks defined */
+ term_ks = tgetstr ("ks", &buffer);
+ term_ke = tgetstr ("ke", &buffer);
+
+ /* If this terminal is not cursor addressable, then it is really dumb. */
+ if (!term_goto)
+ terminal_is_dumb_p = 1;
+
+ terminal_begin_using_terminal ();
+}
+
+/* **************************************************************** */
+/* */
+/* How to Read Characters From the Terminal */
+/* */
+/* **************************************************************** */
+
+#if defined (TIOCGETC)
+/* A buffer containing the terminal interrupt characters upon entry
+ to Info. */
+struct tchars original_tchars;
+#endif
+
+#if defined (TIOCGLTC)
+/* A buffer containing the local terminal mode characters upon entry
+ to Info. */
+struct ltchars original_ltchars;
+#endif
+
+#if defined (HAVE_TERMIO_H)
+/* A buffer containing the terminal mode flags upon entry to info. */
+struct termio original_termio, ttybuff;
+#else /* !HAVE_TERMIO_H */
+/* Buffers containing the terminal mode flags upon entry to info. */
+int original_tty_flags = 0;
+int original_lmode;
+struct sgttyb ttybuff;
+#endif /* !HAVE_TERMIO_H */
+
+/* Prepare to start using the terminal to read characters singly. */
+void
+terminal_prep_terminal ()
+{
+ int tty;
+
+ if (terminal_prep_terminal_hook)
+ {
+ (*terminal_prep_terminal_hook) ();
+ return;
+ }
+
+ tty = fileno (stdin);
+
+#if defined (HAVE_TERMIO_H)
+ ioctl (tty, TCGETA, &original_termio);
+ ioctl (tty, TCGETA, &ttybuff);
+ ttybuff.c_iflag &= (~ISTRIP & ~INLCR & ~IGNCR & ~ICRNL & ~IXON);
+ ttybuff.c_oflag &= (~ONLCR & ~OCRNL);
+ ttybuff.c_lflag &= (~ICANON & ~ECHO);
+
+ ttybuff.c_cc[VMIN] = 1;
+ ttybuff.c_cc[VTIME] = 0;
+
+ if (ttybuff.c_cc[VINTR] = '\177')
+ ttybuff.c_cc[VINTR] = -1;
+
+ if (ttybuff.c_cc[VQUIT] = '\177')
+ ttybuff.c_cc[VQUIT] = -1;
+
+ ioctl (tty, TCSETA, &ttybuff);
+
+#else /* !HAVE_TERMIO_H */
+
+ ioctl (tty, TIOCGETP, &ttybuff);
+
+ if (!original_tty_flags)
+ original_tty_flags = ttybuff.sg_flags;
+
+ /* Make this terminal pass 8 bits around while we are using it. */
+#if defined (PASS8)
+ ttybuff.sg_flags |= PASS8;
+#endif /* PASS8 */
+
+#if defined (TIOCLGET) && defined (LPASS8)
+ {
+ int flags;
+ ioctl (tty, TIOCLGET, &flags);
+ original_lmode = flags;
+ flags |= LPASS8;
+ ioctl (tty, TIOCLSET, &flags);
+ }
+#endif /* TIOCLGET && LPASS8 */
+
+#if defined (TIOCGETC)
+ {
+ struct tchars temp;
+
+ ioctl (tty, TIOCGETC, &original_tchars);
+ temp = original_tchars;
+
+ /* C-s and C-q. */
+ temp.t_startc = temp.t_stopc = -1;
+
+ /* Often set to C-d. */
+ temp.t_eofc = -1;
+
+ /* If the a quit or interrupt character conflicts with one of our
+ commands, then make it go away. */
+ if (temp.t_intrc == '\177')
+ temp.t_intrc = -1;
+
+ if (temp.t_quitc == '\177')
+ temp.t_quitc = -1;
+
+ ioctl (tty, TIOCSETC, &temp);
+ }
+#endif /* TIOCGETC */
+
+#if defined (TIOCGLTC)
+ {
+ struct ltchars temp;
+
+ ioctl (tty, TIOCGLTC, &original_ltchars);
+ temp = original_ltchars;
+
+ /* Make the interrupt keys go away. Just enough to make people happy. */
+ temp.t_lnextc = -1; /* C-v. */
+ temp.t_dsuspc = -1; /* C-y. */
+ temp.t_flushc = -1; /* C-o. */
+ ioctl (tty, TIOCSLTC, &temp);
+ }
+#endif /* TIOCGLTC */
+
+ ttybuff.sg_flags &= ~ECHO;
+ ttybuff.sg_flags |= CBREAK;
+ ioctl (tty, TIOCSETN, &ttybuff);
+#endif /* !HAVE_TERMIO_H */
+ terminal_begin_using_terminal();
+}
+
+/* Restore the tty settings back to what they were before we started using
+ this terminal. */
+void
+terminal_unprep_terminal ()
+{
+ int tty;
+
+ if (terminal_unprep_terminal_hook)
+ {
+ (*terminal_unprep_terminal_hook) ();
+ return;
+ }
+
+ tty = fileno (stdin);
+
+#if defined (HAVE_TERMIO_H)
+ ioctl (tty, TCSETA, &original_termio);
+#else /* !HAVE_TERMIO_H */
+ ioctl (tty, TIOCGETP, &ttybuff);
+ ttybuff.sg_flags = original_tty_flags;
+ ioctl (tty, TIOCSETN, &ttybuff);
+
+#if defined (TIOCGETC)
+ ioctl (tty, TIOCSETC, &original_tchars);
+#endif /* TIOCGETC */
+
+#if defined (TIOCGLTC)
+ ioctl (tty, TIOCSLTC, &original_ltchars);
+#endif /* TIOCGLTC */
+
+#if defined (TIOCLGET) && defined (LPASS8)
+ ioctl (tty, TIOCLSET, &original_lmode);
+#endif /* TIOCLGET && LPASS8 */
+
+#endif /* !HAVE_TERMIO_H */
+ terminal_end_using_terminal ();
+}
+
diff --git a/gnu/usr.bin/texinfo/info/terminal.h b/gnu/usr.bin/texinfo/info/terminal.h
new file mode 100644
index 0000000..a86a23c
--- /dev/null
+++ b/gnu/usr.bin/texinfo/info/terminal.h
@@ -0,0 +1,126 @@
+/* terminal.h -- The external interface to terminal I/O. */
+
+/* This file is part of GNU Info, a program for reading online documentation
+ stored in Info format.
+
+ Copyright (C) 1993 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ Written by Brian Fox (bfox@ai.mit.edu). */
+
+#ifndef _TERMINAL_H_
+#define _TERMINAL_H_
+
+/* We use the following data type to talk about pointers to functions. */
+#if !defined (__FUNCTION_DEF)
+# define __FUNCTION_DEF
+typedef int Function ();
+typedef void VFunction ();
+#endif /* _FUNCTION_DEF */
+
+/* For almost every function externally visible from terminal.c, there is
+ a corresponding "hook" function which can be bound in order to replace
+ the functionality of the one found in terminal.c. This is how we go
+ about implemented X window display. */
+
+/* The width and height of the terminal. */
+extern int screenwidth, screenheight;
+
+/* Non-zero means this terminal can't really do anything. */
+extern int terminal_is_dumb_p;
+
+/* Non-zero means that this terminal has a meta key. */
+extern int terminal_has_meta_p;
+
+/* Non-zero means that this terminal can produce a visible bell. */
+extern int terminal_has_visible_bell_p;
+
+/* Non-zero means to use that visible bell if at all possible. */
+extern int terminal_use_visible_bell_p;
+
+/* Non-zero means that this terminal can scroll lines up and down. */
+extern int terminal_can_scroll;
+
+/* Initialize the terminal which is known as TERMINAL_NAME. If this terminal
+ doesn't have cursor addressability, TERMINAL_IS_DUMB_P becomes non-zero.
+ The variables SCREENHEIGHT and SCREENWIDTH are set to the dimensions that
+ this terminal actually has. The variable TERMINAL_HAS_META_P becomes non-
+ zero if this terminal supports a Meta key. */
+extern void terminal_initialize_terminal ();
+extern VFunction *terminal_initialize_terminal_hook;
+
+/* Return the current screen width and height in the variables
+ SCREENWIDTH and SCREENHEIGHT. */
+extern void terminal_get_screen_size ();
+extern VFunction *terminal_get_screen_size_hook;
+
+/* Save and restore tty settings. */
+extern void terminal_prep_terminal (), terminal_unprep_terminal ();
+extern VFunction *terminal_prep_terminal_hook, *terminal_unprep_terminal_hook;
+
+/* Re-initialize the terminal to TERMINAL_NAME. */
+extern void terminal_new_terminal ();
+extern VFunction *terminal_new_terminal_hook;
+
+/* Move the cursor to the terminal location of X and Y. */
+extern void terminal_goto_xy ();
+extern VFunction *terminal_goto_xy_hook;
+
+/* Print STRING to the terminal at the current position. */
+extern void terminal_put_text ();
+extern VFunction *terminal_put_text_hook;
+
+/* Print NCHARS from STRING to the terminal at the current position. */
+extern void terminal_write_chars ();
+extern VFunction *terminal_write_chars_hook;
+
+/* Clear from the current position of the cursor to the end of the line. */
+extern void terminal_clear_to_eol ();
+extern VFunction *terminal_clear_to_eol_hook;
+
+/* Clear the entire terminal screen. */
+extern void terminal_clear_screen ();
+extern VFunction *terminal_clear_screen_hook;
+
+/* Move the cursor up one line. */
+extern void terminal_up_line ();
+extern VFunction *terminal_up_line_hook;
+
+/* Move the cursor down one line. */
+extern void terminal_down_line ();
+extern VFunction *terminal_down_line_hook;
+
+/* Turn on reverse video if possible. */
+extern void terminal_begin_inverse ();
+extern VFunction *terminal_begin_inverse_hook;
+
+/* Turn off reverse video if possible. */
+extern void terminal_end_inverse ();
+extern VFunction *terminal_end_inverse_hook;
+
+/* Scroll an area of the terminal, starting with the region from START
+ to END, AMOUNT lines. If AMOUNT is negative, the lines are scrolled
+ towards the top of the screen, else they are scrolled towards the
+ bottom of the screen. */
+extern void terminal_scroll_terminal ();
+extern VFunction *terminal_scroll_terminal_hook;
+
+/* Ring the terminal bell. The bell is run visibly if it both has one and
+ terminal_use_visible_bell_p is non-zero. */
+extern void terminal_ring_bell ();
+extern VFunction *terminal_ring_bell_hook;
+
+#endif /* !_TERMINAL_H_ */
diff --git a/gnu/usr.bin/texinfo/info/tilde.c b/gnu/usr.bin/texinfo/info/tilde.c
new file mode 100644
index 0000000..c01951b
--- /dev/null
+++ b/gnu/usr.bin/texinfo/info/tilde.c
@@ -0,0 +1,379 @@
+/* tilde.c -- Tilde expansion code (~/foo := $HOME/foo). */
+
+/* This file is part of GNU Info, a program for reading online documentation
+ stored in Info format.
+
+ This file has appeared in prior works by the Free Software Foundation;
+ thus it carries copyright dates from 1988 through 1993.
+
+ Copyright (C) 1988, 1989, 1990, 1991, 1992, 1993 Free Software
+ Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ Written by Brian Fox (bfox@ai.mit.edu). */
+
+#if defined (__GNUC__)
+# define alloca __builtin_alloca
+#else /* !__GNUC__ */
+# if defined (_AIX)
+ #pragma alloca
+# else /* !_AIX */
+# if defined (HAVE_ALLOCA_H)
+# include <alloca.h>
+# endif /* HAVE_ALLOCA_H */
+# endif /* !AIX */
+#endif /* !__GNUC__ */
+
+#include "tilde.h"
+#include <pwd.h>
+
+#if !defined (savestring)
+#define savestring(x) (char *)strcpy (xmalloc (1 + strlen (x)), (x))
+#endif /* !savestring */
+
+#if !defined (NULL)
+# define NULL 0x0
+#endif
+
+#if defined (TEST) || defined (STATIC_MALLOC)
+static char *xmalloc (), *xrealloc ();
+#else
+extern char *xmalloc (), *xrealloc ();
+#endif /* TEST || STATIC_MALLOC */
+
+/* The default value of tilde_additional_prefixes. This is set to
+ whitespace preceding a tilde so that simple programs which do not
+ perform any word separation get desired behaviour. */
+static char *default_prefixes[] =
+ { " ~", "\t~", (char *)NULL };
+
+/* The default value of tilde_additional_suffixes. This is set to
+ whitespace or newline so that simple programs which do not
+ perform any word separation get desired behaviour. */
+static char *default_suffixes[] =
+ { " ", "\n", (char *)NULL };
+
+/* If non-null, this contains the address of a function to call if the
+ standard meaning for expanding a tilde fails. The function is called
+ with the text (sans tilde, as in "foo"), and returns a malloc()'ed string
+ which is the expansion, or a NULL pointer if there is no expansion. */
+Function *tilde_expansion_failure_hook = (Function *)NULL;
+
+/* When non-null, this is a NULL terminated array of strings which
+ are duplicates for a tilde prefix. Bash uses this to expand
+ `=~' and `:~'. */
+char **tilde_additional_prefixes = default_prefixes;
+
+/* When non-null, this is a NULL terminated array of strings which match
+ the end of a username, instead of just "/". Bash sets this to
+ `:' and `=~'. */
+char **tilde_additional_suffixes = default_suffixes;
+
+/* Find the start of a tilde expansion in STRING, and return the index of
+ the tilde which starts the expansion. Place the length of the text
+ which identified this tilde starter in LEN, excluding the tilde itself. */
+static int
+tilde_find_prefix (string, len)
+ char *string;
+ int *len;
+{
+ register int i, j, string_len;
+ register char **prefixes = tilde_additional_prefixes;
+
+ string_len = strlen (string);
+ *len = 0;
+
+ if (!*string || *string == '~')
+ return (0);
+
+ if (prefixes)
+ {
+ for (i = 0; i < string_len; i++)
+ {
+ for (j = 0; prefixes[j]; j++)
+ {
+ if (strncmp (string + i, prefixes[j], strlen (prefixes[j])) == 0)
+ {
+ *len = strlen (prefixes[j]) - 1;
+ return (i + *len);
+ }
+ }
+ }
+ }
+ return (string_len);
+}
+
+/* Find the end of a tilde expansion in STRING, and return the index of
+ the character which ends the tilde definition. */
+static int
+tilde_find_suffix (string)
+ char *string;
+{
+ register int i, j, string_len;
+ register char **suffixes = tilde_additional_suffixes;
+
+ string_len = strlen (string);
+
+ for (i = 0; i < string_len; i++)
+ {
+ if (string[i] == '/' || !string[i])
+ break;
+
+ for (j = 0; suffixes && suffixes[j]; j++)
+ {
+ if (strncmp (string + i, suffixes[j], strlen (suffixes[j])) == 0)
+ return (i);
+ }
+ }
+ return (i);
+}
+
+/* Return a new string which is the result of tilde expanding STRING. */
+char *
+tilde_expand (string)
+ char *string;
+{
+ char *result, *tilde_expand_word ();
+ int result_size, result_index;
+
+ result_size = result_index = 0;
+ result = (char *)NULL;
+
+ /* Scan through STRING expanding tildes as we come to them. */
+ while (1)
+ {
+ register int start, end;
+ char *tilde_word, *expansion;
+ int len;
+
+ /* Make START point to the tilde which starts the expansion. */
+ start = tilde_find_prefix (string, &len);
+
+ /* Copy the skipped text into the result. */
+ if ((result_index + start + 1) > result_size)
+ result = (char *)xrealloc (result, 1 + (result_size += (start + 20)));
+
+ strncpy (result + result_index, string, start);
+ result_index += start;
+
+ /* Advance STRING to the starting tilde. */
+ string += start;
+
+ /* Make END be the index of one after the last character of the
+ username. */
+ end = tilde_find_suffix (string);
+
+ /* If both START and END are zero, we are all done. */
+ if (!start && !end)
+ break;
+
+ /* Expand the entire tilde word, and copy it into RESULT. */
+ tilde_word = (char *)xmalloc (1 + end);
+ strncpy (tilde_word, string, end);
+ tilde_word[end] = '\0';
+ string += end;
+
+ expansion = tilde_expand_word (tilde_word);
+ free (tilde_word);
+
+ len = strlen (expansion);
+ if ((result_index + len + 1) > result_size)
+ result = (char *)xrealloc (result, 1 + (result_size += (len + 20)));
+
+ strcpy (result + result_index, expansion);
+ result_index += len;
+ free (expansion);
+ }
+
+ result[result_index] = '\0';
+
+ return (result);
+}
+
+/* Do the work of tilde expansion on FILENAME. FILENAME starts with a
+ tilde. If there is no expansion, call tilde_expansion_failure_hook. */
+char *
+tilde_expand_word (filename)
+ char *filename;
+{
+ char *dirname;
+
+ dirname = filename ? savestring (filename) : (char *)NULL;
+
+ if (dirname && *dirname == '~')
+ {
+ char *temp_name;
+ if (!dirname[1] || dirname[1] == '/')
+ {
+ /* Prepend $HOME to the rest of the string. */
+ char *temp_home = (char *)getenv ("HOME");
+
+ /* If there is no HOME variable, look up the directory in
+ the password database. */
+ if (!temp_home)
+ {
+/* extern struct passwd *getpwuid (); */
+ struct passwd *entry;
+
+ entry = getpwuid (getuid ());
+ if (entry)
+ temp_home = entry->pw_dir;
+ }
+
+ temp_name = (char *)alloca (1 + strlen (&dirname[1])
+ + (temp_home ? strlen (temp_home) : 0));
+ temp_name[0] = '\0';
+ if (temp_home)
+ strcpy (temp_name, temp_home);
+ strcat (temp_name, &dirname[1]);
+ free (dirname);
+ dirname = savestring (temp_name);
+ }
+ else
+ {
+ struct passwd *getpwnam (), *user_entry;
+ char *username = (char *)alloca (257);
+ int i, c;
+
+ for (i = 1; c = dirname[i]; i++)
+ {
+ if (c == '/')
+ break;
+ else
+ username[i - 1] = c;
+ }
+ username[i - 1] = '\0';
+
+ if (!(user_entry = getpwnam (username)))
+ {
+ /* If the calling program has a special syntax for
+ expanding tildes, and we couldn't find a standard
+ expansion, then let them try. */
+ if (tilde_expansion_failure_hook)
+ {
+ char *expansion;
+
+ expansion =
+ (char *)(*tilde_expansion_failure_hook) (username);
+
+ if (expansion)
+ {
+ temp_name = (char *)alloca (1 + strlen (expansion)
+ + strlen (&dirname[i]));
+ strcpy (temp_name, expansion);
+ strcat (temp_name, &dirname[i]);
+ free (expansion);
+ goto return_name;
+ }
+ }
+ /* We shouldn't report errors. */
+ }
+ else
+ {
+ temp_name = (char *)alloca (1 + strlen (user_entry->pw_dir)
+ + strlen (&dirname[i]));
+ strcpy (temp_name, user_entry->pw_dir);
+ strcat (temp_name, &dirname[i]);
+ return_name:
+ free (dirname);
+ dirname = savestring (temp_name);
+ }
+ endpwent ();
+ }
+ }
+ return (dirname);
+}
+
+
+#if defined (TEST)
+#undef NULL
+#include <stdio.h>
+
+main (argc, argv)
+ int argc;
+ char **argv;
+{
+ char *result, line[512];
+ int done = 0;
+
+ while (!done)
+ {
+ printf ("~expand: ");
+ fflush (stdout);
+
+ if (!gets (line))
+ strcpy (line, "done");
+
+ if ((strcmp (line, "done") == 0) ||
+ (strcmp (line, "quit") == 0) ||
+ (strcmp (line, "exit") == 0))
+ {
+ done = 1;
+ break;
+ }
+
+ result = tilde_expand (line);
+ printf (" --> %s\n", result);
+ free (result);
+ }
+ exit (0);
+}
+
+static void memory_error_and_abort ();
+
+static char *
+xmalloc (bytes)
+ int bytes;
+{
+ char *temp = (char *)malloc (bytes);
+
+ if (!temp)
+ memory_error_and_abort ();
+ return (temp);
+}
+
+static char *
+xrealloc (pointer, bytes)
+ char *pointer;
+ int bytes;
+{
+ char *temp;
+
+ if (!pointer)
+ temp = (char *)malloc (bytes);
+ else
+ temp = (char *)realloc (pointer, bytes);
+
+ if (!temp)
+ memory_error_and_abort ();
+
+ return (temp);
+}
+
+static void
+memory_error_and_abort ()
+{
+ fprintf (stderr, "readline: Out of virtual memory!\n");
+ abort ();
+}
+
+/*
+ * Local variables:
+ * compile-command: "gcc -g -DTEST -o tilde tilde.c"
+ * end:
+ */
+#endif /* TEST */
+
diff --git a/gnu/usr.bin/texinfo/info/tilde.h b/gnu/usr.bin/texinfo/info/tilde.h
new file mode 100644
index 0000000..b48fc19
--- /dev/null
+++ b/gnu/usr.bin/texinfo/info/tilde.h
@@ -0,0 +1,62 @@
+/* tilde.h: Externally available variables and function in libtilde.a. */
+
+/* This file is part of GNU Info, a program for reading online documentation
+ stored in Info format.
+
+ This file has appeared in prior works by the Free Software Foundation;
+ thus it carries copyright dates from 1988 through 1993.
+
+ Copyright (C) 1988, 1989, 1990, 1991, 1992, 1993 Free Software
+ Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ Written by Brian Fox (bfox@ai.mit.edu). */
+
+#ifndef _TILDE_H_
+#define _TILDE_H_
+
+/* Function pointers can be declared as (Function *)foo. */
+#if !defined (__FUNCTION_DEF)
+# define __FUNCTION_DEF
+typedef int Function ();
+typedef void VFunction ();
+#endif /* _FUNCTION_DEF */
+
+/* If non-null, this contains the address of a function to call if the
+ standard meaning for expanding a tilde fails. The function is called
+ with the text (sans tilde, as in "foo"), and returns a malloc()'ed string
+ which is the expansion, or a NULL pointer if there is no expansion. */
+extern Function *tilde_expansion_failure_hook;
+
+/* When non-null, this is a NULL terminated array of strings which
+ are duplicates for a tilde prefix. Bash uses this to expand
+ `=~' and `:~'. */
+extern char **tilde_additional_prefixes;
+
+/* When non-null, this is a NULL terminated array of strings which match
+ the end of a username, instead of just "/". Bash sets this to
+ `:' and `=~'. */
+extern char **tilde_additional_suffixes;
+
+/* Return a new string which is the result of tilde expanding STRING. */
+extern char *tilde_expand ();
+
+/* Do the work of tilde expansion on FILENAME. FILENAME starts with a
+ tilde. If there is no expansion, call tilde_expansion_failure_hook. */
+extern char *tilde_expand_word ();
+
+#endif
+
diff --git a/gnu/usr.bin/texinfo/info/variables.c b/gnu/usr.bin/texinfo/info/variables.c
new file mode 100644
index 0000000..b70af83
--- /dev/null
+++ b/gnu/usr.bin/texinfo/info/variables.c
@@ -0,0 +1,272 @@
+/* variables.c -- How to manipulate user visible variables in Info. */
+
+/* This file is part of GNU Info, a program for reading online documentation
+ stored in Info format.
+
+ Copyright (C) 1993 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ Written by Brian Fox (bfox@ai.mit.edu). */
+
+#include "info.h"
+#include "variables.h"
+
+/* **************************************************************** */
+/* */
+/* User Visible Variables in Info */
+/* */
+/* **************************************************************** */
+
+/* Choices used by the completer when reading a zero/non-zero value for
+ a variable. */
+static char *on_off_choices[] = { "Off", "On", (char *)NULL };
+
+VARIABLE_ALIST info_variables[] = {
+ { "automatic-footnotes",
+ "When \"On\", footnotes appear and disappear automatically",
+ &auto_footnotes_p, (char **)on_off_choices },
+
+ { "automatic-tiling",
+ "When \"On\", creating or deleting a window resizes other windows",
+ &auto_tiling_p, (char **)on_off_choices },
+
+ { "visible-bell",
+ "When \"On\", flash the screen instead of ringing the bell",
+ &terminal_use_visible_bell_p, (char **)on_off_choices },
+
+ { "errors-ring-bell",
+ "When \"On\", errors cause the bell to ring",
+ &info_error_rings_bell_p, (char **)on_off_choices },
+
+ { "gc-compressed-files",
+ "When \"On\", Info garbage collects files which had to be uncompressed",
+ &gc_compressed_files, (char **)on_off_choices },
+ { "show-index-match",
+ "When \"On\", the portion of the matched search string is highlighted",
+ &show_index_match, (char **)on_off_choices },
+
+ { "scroll-behaviour",
+ "Controls what happens when scrolling is requested at the end of a node",
+ &info_scroll_behaviour, (char **)info_scroll_choices },
+
+ { "scroll-step",
+ "The number lines to scroll when the cursor moves out of the window",
+ &window_scroll_step, (char **)NULL },
+
+ { "ISO-Latin",
+ "When \"On\", Info accepts and displays ISO Latin characters",
+ &ISO_Latin_p, (char **)on_off_choices },
+
+ { (char *)NULL, (char *)NULL, (int *)NULL, (char **)NULL }
+};
+
+DECLARE_INFO_COMMAND (describe_variable, "Explain the use of a variable")
+{
+ VARIABLE_ALIST *var;
+ char *description;
+
+ /* Get the variable's name. */
+ var = read_variable_name ("Describe variable: ", window);
+
+ if (!var)
+ return;
+
+ description = (char *)xmalloc (20 + strlen (var->name) + strlen (var->doc));
+
+ if (var->choices)
+ sprintf (description, "%s (%s): %s.",
+ var->name, var->choices[*(var->value)], var->doc);
+ else
+ sprintf (description, "%s (%d): %s.", var->name, *(var->value), var->doc);
+
+ window_message_in_echo_area ("%s", description);
+ free (description);
+}
+
+DECLARE_INFO_COMMAND (set_variable, "Set the value of an Info variable")
+{
+ VARIABLE_ALIST *var;
+ char *line;
+
+ /* Get the variable's name and value. */
+ var = read_variable_name ("Set variable: ", window);
+
+ if (!var)
+ return;
+
+ /* Read a new value for this variable. */
+ {
+ char prompt[100];
+
+ if (!var->choices)
+ {
+ int potential_value;
+
+ if (info_explicit_arg || count != 1)
+ potential_value = count;
+ else
+ potential_value = *(var->value);
+
+ sprintf (prompt, "Set %s to value (%d): ",
+ var->name, potential_value);
+ line = info_read_in_echo_area (active_window, prompt);
+
+ /* If no error was printed, clear the echo area. */
+ if (!info_error_was_printed)
+ window_clear_echo_area ();
+
+ /* User aborted? */
+ if (!line)
+ return;
+
+ /* If the user specified a value, get that, otherwise, we are done. */
+ canonicalize_whitespace (line);
+ if (*line)
+ *(var->value) = atoi (line);
+ else
+ *(var->value) = potential_value;
+
+ free (line);
+ }
+ else
+ {
+ register int i;
+ REFERENCE **array = (REFERENCE **)NULL;
+ int array_index = 0;
+ int array_slots = 0;
+
+ for (i = 0; var->choices[i]; i++)
+ {
+ REFERENCE *entry;
+
+ entry = (REFERENCE *)xmalloc (sizeof (REFERENCE));
+ entry->label = savestring (var->choices[i]);
+ entry->nodename = (char *)NULL;
+ entry->filename = (char *)NULL;
+
+ add_pointer_to_array
+ (entry, array_index, array, array_slots, 10, REFERENCE *);
+ }
+
+ sprintf (prompt, "Set %s to value (%s): ",
+ var->name, var->choices[*(var->value)]);
+
+ /* Ask the completer to read a variable value for us. */
+ line = info_read_completing_in_echo_area (window, prompt, array);
+
+ info_free_references (array);
+
+ if (!echo_area_is_active)
+ window_clear_echo_area ();
+
+ /* User aborted? */
+ if (!line)
+ {
+ info_abort_key (active_window, 0, 0);
+ return;
+ }
+
+ /* User accepted default choice? If so, no change. */
+ if (!*line)
+ {
+ free (line);
+ return;
+ }
+
+ /* Find the choice in our list of choices. */
+ for (i = 0; var->choices[i]; i++)
+ if (strcmp (var->choices[i], line) == 0)
+ break;
+
+ if (var->choices[i])
+ *(var->value) = i;
+ }
+ }
+}
+
+/* Read the name of an Info variable in the echo area and return the
+ address of a VARIABLE_ALIST member. A return value of NULL indicates
+ that no variable could be read. */
+VARIABLE_ALIST *
+read_variable_name (prompt, window)
+ char *prompt;
+ WINDOW *window;
+{
+ register int i;
+ char *line;
+ REFERENCE **variables;
+
+ /* Get the completion array of variable names. */
+ variables = make_variable_completions_array ();
+
+ /* Ask the completer to read a variable for us. */
+ line =
+ info_read_completing_in_echo_area (window, prompt, variables);
+
+ info_free_references (variables);
+
+ if (!echo_area_is_active)
+ window_clear_echo_area ();
+
+ /* User aborted? */
+ if (!line)
+ {
+ info_abort_key (active_window, 0, 0);
+ return ((VARIABLE_ALIST *)NULL);
+ }
+
+ /* User accepted "default"? (There is none.) */
+ if (!*line)
+ {
+ free (line);
+ return ((VARIABLE_ALIST *)NULL);
+ }
+
+ /* Find the variable in our list of variables. */
+ for (i = 0; info_variables[i].name; i++)
+ if (strcmp (info_variables[i].name, line) == 0)
+ break;
+
+ if (!info_variables[i].name)
+ return ((VARIABLE_ALIST *)NULL);
+ else
+ return (&(info_variables[i]));
+}
+
+/* Make an array of REFERENCE which actually contains the names of the
+ variables available in Info. */
+REFERENCE **
+make_variable_completions_array ()
+{
+ register int i;
+ REFERENCE **array = (REFERENCE **)NULL;
+ int array_index = 0, array_slots = 0;
+
+ for (i = 0; info_variables[i].name; i++)
+ {
+ REFERENCE *entry;
+
+ entry = (REFERENCE *)xmalloc (sizeof (REFERENCE));
+ entry->label = savestring (info_variables[i].name);
+ entry->nodename = (char *)NULL;
+ entry->filename = (char *)NULL;
+
+ add_pointer_to_array
+ (entry, array_index, array, array_slots, 200, REFERENCE *);
+ }
+
+ return (array);
+}
diff --git a/gnu/usr.bin/texinfo/info/variables.h b/gnu/usr.bin/texinfo/info/variables.h
new file mode 100644
index 0000000..ce40fa5
--- /dev/null
+++ b/gnu/usr.bin/texinfo/info/variables.h
@@ -0,0 +1,64 @@
+/* variables.h -- Description of user visible variables in Info. */
+
+/* This file is part of GNU Info, a program for reading online documentation
+ stored in Info format.
+
+ Copyright (C) 1993 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ Written by Brian Fox (bfox@ai.mit.edu). */
+
+#ifndef _VARIABLES_H_
+#define _VARIABLES_H_
+
+/* A variable (in the Info sense) is an integer value with a user-visible
+ name. You may supply an array of strings to complete over when the
+ variable is set; in that case, the variable is set to the index of the
+ string that the user chose. If you supply a null list, the user can
+ set the variable to a numeric value. */
+
+/* Structure describing a user visible variable. */
+typedef struct {
+ char *name; /* Polite name. */
+ char *doc; /* Documentation string. */
+ int *value; /* Address of value. */
+ char **choices; /* Array of strings or NULL if numeric only. */
+} VARIABLE_ALIST;
+
+/* Read the name of an Info variable in the echo area and return the
+ address of a VARIABLE_ALIST member. A return value of NULL indicates
+ that no variable could be read. */
+extern VARIABLE_ALIST *read_variable_name ();
+
+/* Make an array of REFERENCE which actually contains the names of the
+ variables available in Info. */
+extern REFERENCE **make_variable_completions_array ();
+
+/* Set the value of an info variable. */
+extern void set_variable ();
+
+/* The list of user-visible variables. */
+extern int auto_footnotes_p;
+extern int auto_tiling_p;
+extern int terminal_use_visible_bell_p;
+extern int info_error_rings_bell_p;
+extern int gc_compressed_files;
+extern int show_index_match;
+extern int info_scroll_behaviour;
+extern int window_scroll_step;
+extern int ISO_Latin_p;
+
+#endif /* _VARIABLES_H_ */
diff --git a/gnu/usr.bin/texinfo/info/window.c b/gnu/usr.bin/texinfo/info/window.c
new file mode 100644
index 0000000..b114986
--- /dev/null
+++ b/gnu/usr.bin/texinfo/info/window.c
@@ -0,0 +1,1478 @@
+/* window.c -- Windows in Info. */
+
+/* This file is part of GNU Info, a program for reading online documentation
+ stored in Info format.
+
+ Copyright (C) 1993 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ Written by Brian Fox (bfox@ai.mit.edu). */
+
+#include <stdio.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include "nodes.h"
+#include "window.h"
+#include "display.h"
+#include "info-utils.h"
+#include "infomap.h"
+
+/* The window which describes the screen. */
+WINDOW *the_screen = (WINDOW *)NULL;
+
+/* The window which describes the echo area. */
+WINDOW *the_echo_area = (WINDOW *)NULL;
+
+/* The list of windows in Info. */
+WINDOW *windows = (WINDOW *)NULL;
+
+/* Pointer to the active window in WINDOW_LIST. */
+WINDOW *active_window = (WINDOW *)NULL;
+
+/* The size of the echo area in Info. It never changes, irregardless of the
+ size of the screen. */
+#define ECHO_AREA_HEIGHT 1
+
+/* Macro returns the amount of space that the echo area truly requires relative
+ to the entire screen. */
+#define echo_area_required (1 + the_echo_area->height)
+
+/* Initalize the window system by creating THE_SCREEN and THE_ECHO_AREA.
+ Create the first window ever.
+ You pass the dimensions of the total screen size. */
+void
+window_initialize_windows (width, height)
+ int width, height;
+{
+ the_screen = (WINDOW *)xmalloc (sizeof (WINDOW));
+ the_echo_area = (WINDOW *)xmalloc (sizeof (WINDOW));
+ windows = (WINDOW *)xmalloc (sizeof (WINDOW));
+ active_window = windows;
+
+ zero_mem (the_screen, sizeof (WINDOW));
+ zero_mem (the_echo_area, sizeof (WINDOW));
+ zero_mem (active_window, sizeof (WINDOW));
+
+ /* None of these windows has a goal column yet. */
+ the_echo_area->goal_column = -1;
+ active_window->goal_column = -1;
+ the_screen->goal_column = -1;
+
+ /* The active and echo_area windows are visible.
+ The echo_area is permanent.
+ The screen is permanent. */
+ active_window->flags = W_WindowVisible;
+ the_echo_area->flags = W_WindowIsPerm | W_InhibitMode | W_WindowVisible;
+ the_screen->flags = W_WindowIsPerm;
+
+ /* The height of the echo area never changes. It is statically set right
+ here, and it must be at least 1 line for display. The size of the
+ initial window cannot be the same size as the screen, since the screen
+ includes the echo area. So, we make the height of the initial window
+ equal to the screen's displayable region minus the height of the echo
+ area. */
+ the_echo_area->height = ECHO_AREA_HEIGHT;
+ active_window->height = the_screen->height - 1 - the_echo_area->height;
+ window_new_screen_size (width, height, (VFunction *)NULL);
+
+ /* The echo area uses a different keymap than normal info windows. */
+ the_echo_area->keymap = echo_area_keymap;
+ active_window->keymap = info_keymap;
+}
+
+/* Given that the size of the screen has changed to WIDTH and HEIGHT
+ from whatever it was before (found in the_screen->height, ->width),
+ change the size (and possibly location) of each window in the screen.
+ If a window would become too small, call the function DELETER on it,
+ after deleting the window from our chain of windows. If DELETER is NULL,
+ nothing extra is done. The last window can never be deleted, but it can
+ become invisible. */
+
+/* If non-null, a function to call with WINDOW as argument when the function
+ window_new_screen_size () has deleted WINDOW. */
+VFunction *window_deletion_notifier = (VFunction *)NULL;
+
+void
+window_new_screen_size (width, height)
+ int width, height;
+{
+ register WINDOW *win;
+ int delta_height, delta_each, delta_leftover;
+ int numwins;
+
+ /* If no change, do nothing. */
+ if (width == the_screen->width && height == the_screen->height)
+ return;
+
+ /* If the new window height is too small, make it be zero. */
+ if (height < (WINDOW_MIN_SIZE + the_echo_area->height))
+ height = 0;
+ if (width < 0)
+ width = 0;
+
+ /* Find out how many windows will change. */
+ for (numwins = 0, win = windows; win; win = win->next, numwins++);
+
+ /* See if some windows will need to be deleted. This is the case if
+ the screen is getting smaller, and the available space divided by
+ the number of windows is less than WINDOW_MIN_SIZE. In that case,
+ delete some windows and try again until there is either enough
+ space to divy up among the windows, or until there is only one
+ window left. */
+ while ((height - echo_area_required) / numwins <= WINDOW_MIN_SIZE)
+ {
+ /* If only one window, make the size of it be zero, and return
+ immediately. */
+ if (!windows->next)
+ {
+ windows->height = 0;
+ maybe_free (windows->line_starts);
+ windows->line_starts = (char **)NULL;
+ windows->line_count = 0;
+ break;
+ }
+
+ /* If we have some temporary windows, delete one of them. */
+ for (win = windows; win; win = win->next)
+ if (win->flags & W_TempWindow)
+ break;
+
+ /* Otherwise, delete the first window, and try again. */
+ if (!win)
+ win = windows;
+
+ if (window_deletion_notifier)
+ (*window_deletion_notifier) (win);
+
+ window_delete_window (win);
+ numwins--;
+ }
+
+ /* The screen has changed height and width. */
+ delta_height = height - the_screen->height; /* This is how much. */
+ the_screen->height = height; /* This is the new height. */
+ the_screen->width = width; /* This is the new width. */
+
+ /* Set the start of the echo area. */
+ the_echo_area->first_row = height - the_echo_area->height;
+ the_echo_area->width = width;
+
+ /* Check to see if the screen can really be changed this way. */
+ if ((!windows->next) && ((windows->height == 0) && (delta_height < 0)))
+ return;
+
+ /* Divide the change in height among the available windows. */
+ delta_each = delta_height / numwins;
+ delta_leftover = delta_height - (delta_each * numwins);
+
+ /* Change the height of each window in the chain by delta_each. Change
+ the height of the last window in the chain by delta_each and by the
+ leftover amount of change. Change the width of each window to be
+ WIDTH. */
+ for (win = windows; win; win = win->next)
+ {
+ if ((win->width != width) && ((win->flags & W_InhibitMode) == 0))
+ {
+ win->width = width;
+ maybe_free (win->modeline);
+ win->modeline = (char *)xmalloc (1 + width);
+ }
+
+ win->height += delta_each;
+
+ /* If the previous height of this window was zero, it was the only
+ window, and it was not visible. Thus we need to compensate for
+ the echo_area. */
+ if (win->height == delta_each)
+ win->height -= (1 + the_echo_area->height);
+
+ /* If this is not the first window in the chain, then change the
+ first row of it. We cannot just add delta_each to the first row,
+ since this window's first row is the sum of the collective increases
+ that have gone before it. So we just add one to the location of the
+ previous window's modeline. */
+ if (win->prev)
+ win->first_row = (win->prev->first_row + win->prev->height) + 1;
+
+ /* The last window in the chain gets the extra space (or shrinkage). */
+ if (!win->next)
+ win->height += delta_leftover;
+
+ if (win->node)
+ recalculate_line_starts (win);
+
+ win->flags |= W_UpdateWindow;
+ }
+
+ /* If the screen got smaller, check over the windows just shrunk to
+ keep them within bounds. Some of the windows may have gotten smaller
+ than WINDOW_MIN_HEIGHT in which case some of the other windows are
+ larger than the available display space in the screen. Because of our
+ intial test above, we know that there is enough space for all of the
+ windows. */
+ if ((delta_each < 0) && ((windows->height != 0) && windows->next))
+ {
+ int avail;
+
+ avail = the_screen->height - (numwins + the_echo_area->height);
+ win = windows;
+
+ while (win)
+ {
+ if ((win->height < WINDOW_MIN_HEIGHT) ||
+ (win->height > avail))
+ {
+ WINDOW *lastwin;
+
+ /* Split the space among the available windows. */
+ delta_each = avail / numwins;
+ delta_leftover = avail - (delta_each * numwins);
+
+ for (win = windows; win; win = win->next)
+ {
+ lastwin = win;
+ if (win->prev)
+ win->first_row =
+ (win->prev->first_row + win->prev->height) + 1;
+ win->height = delta_each;
+ }
+
+ /* Give the leftover space (if any) to the last window. */
+ lastwin->height += delta_leftover;
+ break;
+ }
+ else
+ win= win->next;
+ }
+ }
+}
+
+/* Make a new window showing NODE, and return that window structure.
+ If NODE is passed as NULL, then show the node showing in the active
+ window. If the window could not be made return a NULL pointer. The
+ active window is not changed.*/
+WINDOW *
+window_make_window (node)
+ NODE *node;
+{
+ WINDOW *window;
+
+ if (!node)
+ node = active_window->node;
+
+ /* If there isn't enough room to make another window, return now. */
+ if ((active_window->height / 2) < WINDOW_MIN_SIZE)
+ return ((WINDOW *)NULL);
+
+ /* Make and initialize the new window.
+ The fudging about with -1 and +1 is because the following window in the
+ chain cannot start at window->height, since that is where the modeline
+ for the previous window is displayed. The inverse adjustment is made
+ in window_delete_window (). */
+ window = (WINDOW *)xmalloc (sizeof (WINDOW));
+ window->width = the_screen->width;
+ window->height = (active_window->height / 2) - 1;
+#if defined (SPLIT_BEFORE_ACTIVE)
+ window->first_row = active_window->first_row;
+#else
+ window->first_row = active_window->first_row +
+ (active_window->height - window->height);
+#endif
+ window->keymap = info_keymap;
+ window->goal_column = -1;
+ window->modeline = (char *)xmalloc (1 + window->width);
+ window->line_starts = (char **)NULL;
+ window->flags = W_UpdateWindow | W_WindowVisible;
+ window_set_node_of_window (window, node);
+
+ /* Adjust the height of the old active window. */
+ active_window->height -= (window->height + 1);
+#if defined (SPLIT_BEFORE_ACTIVE)
+ active_window->first_row += (window->height + 1);
+#endif
+ active_window->flags |= W_UpdateWindow;
+
+ /* Readjust the new and old windows so that their modelines and contents
+ will be displayed correctly. */
+#if defined (NOTDEF)
+ /* We don't have to do this for WINDOW since window_set_node_of_window ()
+ already did. */
+ window_adjust_pagetop (window);
+ window_make_modeline (window);
+#endif /* NOTDEF */
+
+ /* We do have to readjust the existing active window. */
+ window_adjust_pagetop (active_window);
+ window_make_modeline (active_window);
+
+#if defined (SPLIT_BEFORE_ACTIVE)
+ /* This window is just before the active one. The active window gets
+ bumped down one. The active window is not changed. */
+ window->next = active_window;
+
+ window->prev = active_window->prev;
+ active_window->prev = window;
+
+ if (window->prev)
+ window->prev->next = window;
+ else
+ windows = window;
+#else
+ /* This window is just after the active one. Which window is active is
+ not changed. */
+ window->prev = active_window;
+ window->next = active_window->next;
+ active_window->next = window;
+ if (window->next)
+ window->next->prev = window;
+#endif /* !SPLIT_BEFORE_ACTIVE */
+ return (window);
+}
+
+/* These useful macros make it possible to read the code in
+ window_change_window_height (). */
+#define grow_me_shrinking_next(me, next, diff) \
+ do { \
+ me->height += diff; \
+ next->height -= diff; \
+ next->first_row += diff; \
+ window_adjust_pagetop (next); \
+ } while (0)
+
+#define grow_me_shrinking_prev(me, prev, diff) \
+ do { \
+ me->height += diff; \
+ prev->height -= diff; \
+ me->first_row -=diff; \
+ window_adjust_pagetop (prev); \
+ } while (0)
+
+#define shrink_me_growing_next(me, next, diff) \
+ do { \
+ me->height -= diff; \
+ next->height += diff; \
+ next->first_row -= diff; \
+ window_adjust_pagetop (next); \
+ } while (0)
+
+#define shrink_me_growing_prev(me, prev, diff) \
+ do { \
+ me->height -= diff; \
+ prev->height += diff; \
+ me->first_row += diff; \
+ window_adjust_pagetop (prev); \
+ } while (0)
+
+/* Change the height of WINDOW by AMOUNT. This also automagically adjusts
+ the previous and next windows in the chain. If there is only one user
+ window, then no change takes place. */
+void
+window_change_window_height (window, amount)
+ WINDOW *window;
+ int amount;
+{
+ register WINDOW *win, *prev, *next;
+
+ /* If there is only one window, or if the amount of change is zero,
+ return immediately. */
+ if (!windows->next || amount == 0)
+ return;
+
+ /* Find this window in our chain. */
+ for (win = windows; win; win = win->next)
+ if (win == window)
+ break;
+
+ /* If the window is isolated (i.e., doesn't appear in our window list,
+ then quit now. */
+ if (!win)
+ return;
+
+ /* Change the height of this window by AMOUNT, if that is possible.
+ It can be impossible if there isn't enough available room on the
+ screen, or if the resultant window would be too small. */
+
+ prev = window->prev;
+ next = window->next;
+
+ /* WINDOW decreasing in size? */
+ if (amount < 0)
+ {
+ int abs_amount = -amount; /* It is easier to deal with this way. */
+
+ /* If the resultant window would be too small, stop here. */
+ if ((window->height - abs_amount) < WINDOW_MIN_HEIGHT)
+ return;
+
+ /* If we have two neighboring windows, choose the smaller one to get
+ larger. */
+ if (next && prev)
+ {
+ if (prev->height < next->height)
+ shrink_me_growing_prev (window, prev, abs_amount);
+ else
+ shrink_me_growing_next (window, next, abs_amount);
+ }
+ else if (next)
+ shrink_me_growing_next (window, next, abs_amount);
+ else
+ shrink_me_growing_prev (window, prev, abs_amount);
+ }
+
+ /* WINDOW increasing in size? */
+ if (amount > 0)
+ {
+ int total_avail, next_avail = 0, prev_avail = 0;
+
+ if (next)
+ next_avail = next->height - WINDOW_MIN_SIZE;
+
+ if (prev)
+ prev_avail = prev->height - WINDOW_MIN_SIZE;
+
+ total_avail = next_avail + prev_avail;
+
+ /* If there isn't enough space available to grow this window, give up. */
+ if (amount > total_avail)
+ return;
+
+ /* If there aren't two neighboring windows, or if one of the neighbors
+ is larger than the other one by at least AMOUNT, grow that one. */
+ if ((next && !prev) || ((next_avail - amount) >= prev_avail))
+ grow_me_shrinking_next (window, next, amount);
+ else if ((prev && !next) || ((prev_avail - amount) >= next_avail))
+ grow_me_shrinking_prev (window, prev, amount);
+ else
+ {
+ int change;
+
+ /* This window has two neighbors. They both must be shrunk in to
+ make enough space for WINDOW to grow. Make them both the same
+ size. */
+ if (prev_avail > next_avail)
+ {
+ change = prev_avail - next_avail;
+ grow_me_shrinking_prev (window, prev, change);
+ amount -= change;
+ }
+ else
+ {
+ change = next_avail - prev_avail;
+ grow_me_shrinking_next (window, next, change);
+ amount -= change;
+ }
+
+ /* Both neighbors are the same size. Split the difference in
+ AMOUNT between them. */
+ while (amount)
+ {
+ window->height++;
+ amount--;
+
+ /* Odd numbers grow next, even grow prev. */
+ if (amount & 1)
+ {
+ prev->height--;
+ window->first_row--;
+ }
+ else
+ {
+ next->height--;
+ next->first_row++;
+ }
+ }
+ window_adjust_pagetop (prev);
+ window_adjust_pagetop (next);
+ }
+ }
+ if (prev)
+ prev->flags |= W_UpdateWindow;
+
+ if (next)
+ next->flags |= W_UpdateWindow;
+
+ window->flags |= W_UpdateWindow;
+ window_adjust_pagetop (window);
+}
+
+/* Tile all of the windows currently displayed in the global variable
+ WINDOWS. If argument STYLE is TILE_INTERNALS, tile windows displaying
+ internal nodes as well, otherwise do not change the height of such
+ windows. */
+void
+window_tile_windows (style)
+ int style;
+{
+ WINDOW *win, *last_adjusted;
+ int numwins, avail, per_win_height, leftover;
+ int do_internals;
+
+ numwins = avail = 0;
+ do_internals = (style == TILE_INTERNALS);
+
+ for (win = windows; win; win = win->next)
+ if (do_internals || !win->node ||
+ (win->node->flags & N_IsInternal) == 0)
+ {
+ avail += win->height;
+ numwins++;
+ }
+
+ if (numwins <= 1 || !the_screen->height)
+ return;
+
+ /* Find the size for each window. Divide the size of the usable portion
+ of the screen by the number of windows. */
+ per_win_height = avail / numwins;
+ leftover = avail - (per_win_height * numwins);
+
+ last_adjusted = (WINDOW *)NULL;
+ for (win = windows; win; win = win->next)
+ {
+ if (do_internals || !win->node ||
+ (win->node->flags & N_IsInternal) == 0)
+ {
+ last_adjusted = win;
+ win->height = per_win_height;
+ }
+ }
+
+ if (last_adjusted)
+ last_adjusted->height += leftover;
+
+ /* Readjust the first_row of every window in the chain. */
+ for (win = windows; win; win = win->next)
+ {
+ if (win->prev)
+ win->first_row = win->prev->first_row + win->prev->height + 1;
+
+ window_adjust_pagetop (win);
+ win->flags |= W_UpdateWindow;
+ }
+}
+
+/* Toggle the state of line wrapping in WINDOW. This can do a bit of fancy
+ redisplay. */
+void
+window_toggle_wrap (window)
+ WINDOW *window;
+{
+ if (window->flags & W_NoWrap)
+ window->flags &= ~W_NoWrap;
+ else
+ window->flags |= W_NoWrap;
+
+ if (window != the_echo_area)
+ {
+ char **old_starts;
+ int old_lines, old_pagetop;
+
+ old_starts = window->line_starts;
+ old_lines = window->line_count;
+ old_pagetop = window->pagetop;
+
+ calculate_line_starts (window);
+
+ /* Make sure that point appears within this window. */
+ window_adjust_pagetop (window);
+
+ /* If the pagetop hasn't changed maybe we can do some scrolling now
+ to speed up the display. Many of the line starts will be the same,
+ so scrolling here is a very good optimization.*/
+ if (old_pagetop == window->pagetop)
+ display_scroll_line_starts
+ (window, old_pagetop, old_starts, old_lines);
+ maybe_free (old_starts);
+ }
+ window->flags |= W_UpdateWindow;
+}
+
+/* Set WINDOW to display NODE. */
+void
+window_set_node_of_window (window, node)
+ WINDOW *window;
+ NODE *node;
+{
+ window->node = node;
+ window->pagetop = 0;
+ window->point = 0;
+ recalculate_line_starts (window);
+ window->flags |= W_UpdateWindow;
+ window_adjust_pagetop (window);
+ window_make_modeline (window);
+}
+
+/* Delete WINDOW from the list of known windows. If this window was the
+ active window, make the next window in the chain be the active window.
+ If the active window is the next or previous window, choose that window
+ as the recipient of the extra space. Otherwise, prefer the next window. */
+void
+window_delete_window (window)
+ WINDOW *window;
+{
+ WINDOW *next, *prev, *window_to_fix;
+
+ next = window->next;
+ prev = window->prev;
+
+ /* You cannot delete the only window or a permanent window. */
+ if ((!next && !prev) || (window->flags & W_WindowIsPerm))
+ return;
+
+ if (next)
+ next->prev = prev;
+
+ if (!prev)
+ windows = next;
+ else
+ prev->next = next;
+
+ if (window->line_starts)
+ free (window->line_starts);
+
+ if (window->modeline)
+ free (window->modeline);
+
+ if (window == active_window)
+ {
+ /* If there isn't a next window, then there must be a previous one,
+ since we cannot delete the last window. If there is a next window,
+ prefer to use that as the active window. */
+ if (next)
+ active_window = next;
+ else
+ active_window = prev;
+ }
+
+ if (next && active_window == next)
+ window_to_fix = next;
+ else if (prev && active_window == prev)
+ window_to_fix = prev;
+ else if (next)
+ window_to_fix = next;
+ else if (prev)
+ window_to_fix = prev;
+ else
+ window_to_fix = windows;
+
+ if (window_to_fix->first_row > window->first_row)
+ {
+ int diff;
+
+ /* Try to adjust the visible part of the node so that as little
+ text as possible has to move. */
+ diff = window_to_fix->first_row - window->first_row;
+ window_to_fix->first_row = window->first_row;
+
+ window_to_fix->pagetop -= diff;
+ if (window_to_fix->pagetop < 0)
+ window_to_fix->pagetop = 0;
+ }
+
+ /* The `+ 1' is to offset the difference between the first_row locations.
+ See the code in window_make_window (). */
+ window_to_fix->height += window->height + 1;
+ window_to_fix->flags |= W_UpdateWindow;
+
+ free (window);
+}
+
+/* For every window in CHAIN, set the flags member to have FLAG set. */
+void
+window_mark_chain (chain, flag)
+ WINDOW *chain;
+ int flag;
+{
+ register WINDOW *win;
+
+ for (win = chain; win; win = win->next)
+ win->flags |= flag;
+}
+
+/* For every window in CHAIN, clear the flags member of FLAG. */
+void
+window_unmark_chain (chain, flag)
+ WINDOW *chain;
+ int flag;
+{
+ register WINDOW *win;
+
+ for (win = chain; win; win = win->next)
+ win->flags &= ~flag;
+}
+
+/* Return the number of characters it takes to display CHARACTER on the
+ screen at HPOS. */
+int
+character_width (character, hpos)
+ int character, hpos;
+{
+ int printable_limit = 127;
+ int width = 1;
+
+ if (ISO_Latin_p)
+ printable_limit = 160;
+
+ if (character > printable_limit)
+ width = 3;
+ else if (iscntrl (character))
+ {
+ switch (character)
+ {
+ case '\r':
+ case '\n':
+ width = the_screen->width - hpos;
+ break;
+ case '\t':
+ width = ((hpos + 8) & 0xf8) - hpos;
+ break;
+ default:
+ width = 2;
+ }
+ }
+ else if (character == DEL)
+ width = 2;
+
+ return (width);
+}
+
+/* Return the number of characters it takes to display STRING on the screen
+ at HPOS. */
+int
+string_width (string, hpos)
+ char *string;
+ int hpos;
+{
+ register int i, width, this_char_width;
+
+ for (width = 0, i = 0; string[i]; i++)
+ {
+ this_char_width = character_width (string[i], hpos);
+ width += this_char_width;
+ hpos += this_char_width;
+ }
+ return (width);
+}
+
+/* Quickly guess the approximate number of lines to that NODE would
+ take to display. This really only counts carriage returns. */
+int
+window_physical_lines (node)
+ NODE *node;
+{
+ register int i, lines;
+ char *contents;
+
+ if (!node)
+ return (0);
+
+ contents = node->contents;
+ for (i = 0, lines = 1; i < node->nodelen; i++)
+ if (contents[i] == '\n')
+ lines++;
+
+ return (lines);
+}
+
+/* Calculate a list of line starts for the node belonging to WINDOW. The line
+ starts are pointers to the actual text within WINDOW->NODE. */
+void
+calculate_line_starts (window)
+ WINDOW *window;
+{
+ register int i, hpos;
+ char **line_starts = (char **)NULL;
+ int line_starts_index = 0, line_starts_slots = 0;
+ int bump_index;
+ NODE *node;
+
+ window->line_starts = (char **)NULL;
+ window->line_count = 0;
+ node = window->node;
+
+ if (!node)
+ return;
+
+ /* Grovel the node starting at the top, and for each line calculate the
+ width of the characters appearing in that line. Add each line start
+ to our array. */
+ i = 0;
+ hpos = 0;
+ bump_index = 0;
+
+ while (i < node->nodelen)
+ {
+ char *line = node->contents + i;
+ unsigned int cwidth, c;
+
+ add_pointer_to_array (line, line_starts_index, line_starts,
+ line_starts_slots, 100, char *);
+ if (bump_index)
+ {
+ i++;
+ bump_index = 0;
+ }
+
+ while (1)
+ {
+ c = node->contents[i];
+ cwidth = character_width (c, hpos);
+
+ /* If this character fits within this line, just do the next one. */
+ if ((hpos + cwidth) < window->width)
+ {
+ i++;
+ hpos += cwidth;
+ continue;
+ }
+ else
+ {
+ /* If this character would position the cursor at the start of
+ the next printed screen line, then do the next line. */
+ if (c == '\n' || c == '\r' || c == '\t')
+ {
+ i++;
+ hpos = 0;
+ break;
+ }
+ else
+ {
+ /* This character passes the window width border. Postion
+ the cursor after the printed character, but remember this
+ line start as where this character is. A bit tricky. */
+
+ /* If this window doesn't wrap lines, proceed to the next
+ physical line here. */
+ if (window->flags & W_NoWrap)
+ {
+ hpos = 0;
+ while (i < node->nodelen && node->contents[i] != '\n')
+ i++;
+
+ if (node->contents[i] == '\n')
+ i++;
+ }
+ else
+ {
+ hpos = the_screen->width - hpos;
+ bump_index++;
+ }
+ break;
+ }
+ }
+ }
+ }
+ window->line_starts = line_starts;
+ window->line_count = line_starts_index;
+}
+
+/* Given WINDOW, recalculate the line starts for the node it displays. */
+void
+recalculate_line_starts (window)
+ WINDOW *window;
+{
+ maybe_free (window->line_starts);
+ calculate_line_starts (window);
+}
+
+/* Global variable control redisplay of scrolled windows. If non-zero, it
+ is the desired number of lines to scroll the window in order to make
+ point visible. A user might set this to 1 for smooth scrolling. If
+ set to zero, the line containing point is centered within the window. */
+int window_scroll_step = 0;
+
+/* Adjust the pagetop of WINDOW such that the cursor point will be visible. */
+void
+window_adjust_pagetop (window)
+ WINDOW *window;
+{
+ register int line = 0;
+ char *contents;
+
+ if (!window->node)
+ return;
+
+ contents = window->node->contents;
+
+ /* Find the first printed line start which is after WINDOW->point. */
+ for (line = 0; line < window->line_count; line++)
+ {
+ char *line_start;
+
+ line_start = window->line_starts[line];
+
+ if ((line_start - contents) > window->point)
+ break;
+ }
+
+ /* The line index preceding the line start which is past point is the
+ one containing point. */
+ line--;
+
+ /* If this line appears in the current displayable page, do nothing.
+ Otherwise, adjust the top of the page to make this line visible. */
+ if ((line < window->pagetop) ||
+ (line - window->pagetop > (window->height - 1)))
+ {
+ /* The user-settable variable "scroll-step" is used to attempt
+ to make point visible, iff it is non-zero. If that variable
+ is zero, then the line containing point is centered within
+ the window. */
+ if (window_scroll_step < window->height)
+ {
+ if ((line < window->pagetop) &&
+ ((window->pagetop - window_scroll_step) <= line))
+ window->pagetop -= window_scroll_step;
+ else if ((line - window->pagetop > (window->height - 1)) &&
+ ((line - (window->pagetop + window_scroll_step)
+ < window->height)))
+ window->pagetop += window_scroll_step;
+ else
+ window->pagetop = line - ((window->height - 1) / 2);
+ }
+ else
+ window->pagetop = line - ((window->height - 1) / 2);
+
+ if (window->pagetop < 0)
+ window->pagetop = 0;
+ window->flags |= W_UpdateWindow;
+ }
+}
+
+/* Return the index of the line containing point. */
+int
+window_line_of_point (window)
+ WINDOW *window;
+{
+ register int i, start = 0;
+
+ /* Try to optimize. Check to see if point is past the pagetop for
+ this window, and if so, start searching forward from there. */
+ if ((window->pagetop > -1 && window->pagetop < window->line_count) &&
+ (window->line_starts[window->pagetop] - window->node->contents)
+ <= window->point)
+ start = window->pagetop;
+
+ for (i = start; i < window->line_count; i++)
+ {
+ if ((window->line_starts[i] - window->node->contents) > window->point)
+ break;
+ }
+
+ return (i - 1);
+}
+
+/* Get and return the goal column for this window. */
+int
+window_get_goal_column (window)
+ WINDOW *window;
+{
+ if (!window->node)
+ return (-1);
+
+ if (window->goal_column != -1)
+ return (window->goal_column);
+
+ /* Okay, do the work. Find the printed offset of the cursor
+ in this window. */
+ return (window_get_cursor_column (window));
+}
+
+/* Get and return the printed column offset of the cursor in this window. */
+int
+window_get_cursor_column (window)
+ WINDOW *window;
+{
+ int i, hpos, end;
+ char *line;
+
+ i = window_line_of_point (window);
+
+ if (i < 0)
+ return (-1);
+
+ line = window->line_starts[i];
+ end = window->point - (line - window->node->contents);
+
+ for (hpos = 0, i = 0; i < end; i++)
+ hpos += character_width (line[i], hpos);
+
+ return (hpos);
+}
+
+/* Count the number of characters in LINE that precede the printed column
+ offset of GOAL. */
+int
+window_chars_to_goal (line, goal)
+ char *line;
+ int goal;
+{
+ register int i, check, hpos;
+
+ for (hpos = 0, i = 0; line[i] != '\n'; i++)
+ {
+
+ check = hpos + character_width (line[i], hpos);
+
+ if (check > goal)
+ break;
+
+ hpos = check;
+ }
+ return (i);
+}
+
+/* Create a modeline for WINDOW, and store it in window->modeline. */
+void
+window_make_modeline (window)
+ WINDOW *window;
+{
+ register int i;
+ char *modeline;
+ char location_indicator[4];
+ int lines_remaining;
+
+ /* Only make modelines for those windows which have one. */
+ if (window->flags & W_InhibitMode)
+ return;
+
+ /* Find the number of lines actually displayed in this window. */
+ lines_remaining = window->line_count - window->pagetop;
+
+ if (window->pagetop == 0)
+ {
+ if (lines_remaining <= window->height)
+ strcpy (location_indicator, "All");
+ else
+ strcpy (location_indicator, "Top");
+ }
+ else
+ {
+ if (lines_remaining <= window->height)
+ strcpy (location_indicator, "Bot");
+ else
+ {
+ float pt, lc;
+ int percentage;
+
+ pt = (float)window->pagetop;
+ lc = (float)window->line_count;
+
+ percentage = 100 * (pt / lc);
+
+ sprintf (location_indicator, "%2d%%", percentage);
+ }
+ }
+
+ /* Calculate the maximum size of the information to stick in MODELINE. */
+ {
+ int modeline_len = 0;
+ char *parent = (char *)NULL, *filename = "*no file*";
+ char *nodename = "*no node*";
+ char *update_message = (char *)NULL;
+ NODE *node = window->node;
+
+ if (node)
+ {
+ if (node->nodename)
+ nodename = node->nodename;
+
+ if (node->parent)
+ {
+ parent = filename_non_directory (node->parent);
+ modeline_len += strlen ("Subfile: ") + strlen (node->filename);
+ }
+
+ if (node->filename)
+ filename = filename_non_directory (node->filename);
+
+ if (node->flags & N_UpdateTags)
+ update_message = "--*** Tags out of Date ***";
+ }
+
+ if (update_message)
+ modeline_len += strlen (update_message);
+ modeline_len += strlen (filename);
+ modeline_len += strlen (nodename);
+ modeline_len += 4; /* strlen (location_indicator). */
+
+ /* 10 for the decimal representation of the number of lines in this
+ node, and the remainder of the text that can appear in the line. */
+ modeline_len += 10 + strlen ("-----Info: (), lines ----, ");
+ modeline_len += window->width;
+
+ modeline = (char *)xmalloc (1 + modeline_len);
+
+ /* Special internal windows have no filename. */
+ if (!parent && !*filename)
+ sprintf (modeline, "-%s---Info: %s, %d lines --%s--",
+ (window->flags & W_NoWrap) ? "$" : "-",
+ nodename, window->line_count, location_indicator);
+ else
+ sprintf (modeline, "-%s%s-Info: (%s)%s, %d lines --%s--",
+ (window->flags & W_NoWrap) ? "$" : "-",
+ (node && (node->flags & N_IsCompressed)) ? "zz" : "--",
+ parent ? parent : filename,
+ nodename, window->line_count, location_indicator);
+
+ if (parent)
+ sprintf (modeline + strlen (modeline), " Subfile: %s", filename);
+
+ if (update_message)
+ sprintf (modeline + strlen (modeline), "%s", update_message);
+
+ i = strlen (modeline);
+
+ if (i >= window->width)
+ modeline[window->width] = '\0';
+ else
+ {
+ while (i < window->width)
+ modeline[i++] = '-';
+ modeline[i] = '\0';
+ }
+
+ strcpy (window->modeline, modeline);
+ free (modeline);
+ }
+}
+
+/* Make WINDOW start displaying at PERCENT percentage of its node. */
+void
+window_goto_percentage (window, percent)
+ WINDOW *window;
+ int percent;
+{
+ int desired_line;
+
+ if (!percent)
+ desired_line = 0;
+ else
+ desired_line =
+ (int) ((float)window->line_count * ((float)percent / 100.0));
+
+ window->pagetop = desired_line;
+ window->point =
+ window->line_starts[window->pagetop] - window->node->contents;
+ window->flags |= W_UpdateWindow;
+ window_make_modeline (window);
+}
+
+/* Get the state of WINDOW, and save it in STATE. */
+void
+window_get_state (window, state)
+ WINDOW *window;
+ WINDOW_STATE *state;
+{
+ state->node = window->node;
+ state->pagetop = window->pagetop;
+ state->point = window->point;
+}
+
+/* Set the node, pagetop, and point of WINDOW. */
+void
+window_set_state (window, state)
+ WINDOW *window;
+ WINDOW_STATE *state;
+{
+ if (window->node != state->node)
+ window_set_node_of_window (window, state->node);
+ window->pagetop = state->pagetop;
+ window->point = state->point;
+}
+
+
+/* **************************************************************** */
+/* */
+/* Manipulating Home-Made Nodes */
+/* */
+/* **************************************************************** */
+
+/* A place to buffer echo area messages. */
+static NODE *echo_area_node = (NODE *)NULL;
+
+/* Make the node of the_echo_area be an empty one. */
+static void
+free_echo_area ()
+{
+ if (echo_area_node)
+ {
+ maybe_free (echo_area_node->contents);
+ free (echo_area_node);
+ }
+
+ echo_area_node = (NODE *)NULL;
+ window_set_node_of_window (the_echo_area, echo_area_node);
+}
+
+/* Clear the echo area, removing any message that is already present.
+ The echo area is cleared immediately. */
+void
+window_clear_echo_area ()
+{
+ free_echo_area ();
+ display_update_one_window (the_echo_area);
+}
+
+/* Make a message appear in the echo area, built from FORMAT, ARG1 and ARG2.
+ The arguments are treated similar to printf () arguments, but not all of
+ printf () hair is present. The message appears immediately. If there was
+ already a message appearing in the echo area, it is removed. */
+void
+window_message_in_echo_area (format, arg1, arg2)
+ char *format;
+ void *arg1, *arg2;
+{
+ free_echo_area ();
+ echo_area_node = build_message_node (format, arg1, arg2);
+ window_set_node_of_window (the_echo_area, echo_area_node);
+ display_update_one_window (the_echo_area);
+}
+
+/* Place a temporary message in the echo area built from FORMAT, ARG1
+ and ARG2. The message appears immediately, but does not destroy
+ any existing message. A future call to unmessage_in_echo_area ()
+ restores the old contents. */
+static NODE **old_echo_area_nodes = (NODE **)NULL;
+static int old_echo_area_nodes_index = 0;
+static int old_echo_area_nodes_slots = 0;
+
+void
+message_in_echo_area (format, arg1, arg2)
+ char *format;
+ void *arg1, *arg2;
+{
+ if (echo_area_node)
+ {
+ add_pointer_to_array (echo_area_node, old_echo_area_nodes_index,
+ old_echo_area_nodes, old_echo_area_nodes_slots,
+ 4, NODE *);
+ }
+ echo_area_node = (NODE *)NULL;
+ window_message_in_echo_area (format, arg1, arg2);
+}
+
+void
+unmessage_in_echo_area ()
+{
+ free_echo_area ();
+
+ if (old_echo_area_nodes_index)
+ echo_area_node = old_echo_area_nodes[--old_echo_area_nodes_index];
+
+ window_set_node_of_window (the_echo_area, echo_area_node);
+ display_update_one_window (the_echo_area);
+}
+
+/* A place to build a message. */
+static char *message_buffer = (char *)NULL;
+static int message_buffer_index = 0;
+static int message_buffer_size = 0;
+
+/* Ensure that there is enough space to stuff LENGTH characters into
+ MESSAGE_BUFFER. */
+static void
+message_buffer_resize (length)
+ int length;
+{
+ if (!message_buffer)
+ {
+ message_buffer_size = length + 1;
+ message_buffer = (char *)xmalloc (message_buffer_size);
+ message_buffer_index = 0;
+ }
+
+ while (message_buffer_size <= message_buffer_index + length)
+ message_buffer = (char *)
+ xrealloc (message_buffer,
+ message_buffer_size += 100 + (2 * length));
+}
+
+/* Format MESSAGE_BUFFER with the results of printing FORMAT with ARG1 and
+ ARG2. */
+static void
+build_message_buffer (format, arg1, arg2)
+ char *format;
+ void *arg1, *arg2;
+{
+ register int i, len;
+ void *args[2];
+ int arg_index = 0;
+
+ args[0] = arg1;
+ args[1] = arg2;
+
+ len = strlen (format);
+
+ message_buffer_resize (len);
+
+ for (i = 0; format[i]; i++)
+ {
+ if (format[i] != '%')
+ {
+ message_buffer[message_buffer_index++] = format[i];
+ len--;
+ }
+ else
+ {
+ char c;
+
+ c = format[++i];
+
+ switch (c)
+ {
+ case '%': /* Insert a percent sign. */
+ message_buffer_resize (len + 1);
+ message_buffer[message_buffer_index++] = '%';
+ break;
+
+ case 's': /* Insert the current arg as a string. */
+ {
+ char *string;
+ int string_len;
+
+ string = (char *)args[arg_index++];
+ string_len = strlen (string);
+
+ message_buffer_resize (len + string_len);
+ sprintf
+ (message_buffer + message_buffer_index, "%s", string);
+ message_buffer_index += string_len;
+ }
+ break;
+
+ case 'd': /* Insert the current arg as an integer. */
+ {
+ int integer;
+
+ integer = (int)args[arg_index++];
+
+ message_buffer_resize (len + 32);
+ sprintf
+ (message_buffer + message_buffer_index, "%d", integer);
+ message_buffer_index = strlen (message_buffer);
+ }
+ break;
+
+ case 'c': /* Insert the current arg as a character. */
+ {
+ int character;
+
+ character = (int)args[arg_index++];
+
+ message_buffer_resize (len + 1);
+ message_buffer[message_buffer_index++] = character;
+ }
+ break;
+
+ default:
+ abort ();
+ }
+ }
+ }
+ message_buffer[message_buffer_index] = '\0';
+}
+
+/* Build a new node which has FORMAT printed with ARG1 and ARG2 as the
+ contents. */
+NODE *
+build_message_node (format, arg1, arg2)
+ char *format;
+ void *arg1, *arg2;
+{
+ NODE *node;
+
+ message_buffer_index = 0;
+ build_message_buffer (format, arg1, arg2);
+
+ node = message_buffer_to_node ();
+ return (node);
+}
+
+/* Convert the contents of the message buffer to a node. */
+NODE *
+message_buffer_to_node ()
+{
+ NODE *node;
+
+ node = (NODE *)xmalloc (sizeof (NODE));
+ node->filename = (char *)NULL;
+ node->parent = (char *)NULL;
+ node->nodename = (char *)NULL;
+ node->flags = 0;
+
+ /* Make sure that this buffer ends with a newline. */
+ node->nodelen = 1 + strlen (message_buffer);
+ node->contents = (char *)xmalloc (1 + node->nodelen);
+ strcpy (node->contents, message_buffer);
+ node->contents[node->nodelen - 1] = '\n';
+ node->contents[node->nodelen] = '\0';
+ return (node);
+}
+
+/* Useful functions can be called from outside of window.c. */
+void
+initialize_message_buffer ()
+{
+ message_buffer_index = 0;
+}
+
+/* Print FORMAT with ARG1,2 to the end of the current message buffer. */
+void
+printf_to_message_buffer (format, arg1, arg2)
+ char *format;
+ void *arg1, *arg2;
+{
+ build_message_buffer (format, arg1, arg2);
+}
+
+/* Return the current horizontal position of the "cursor" on the most
+ recently output message buffer line. */
+int
+message_buffer_length_this_line ()
+{
+ register int i;
+
+ if (!message_buffer_index)
+ return (0);
+
+ for (i = message_buffer_index; i && message_buffer[i - 1] != '\n'; i--);
+
+ return (string_width (message_buffer + i, 0));
+}
+
+/* Pad STRING to COUNT characters by inserting blanks. */
+int
+pad_to (count, string)
+ int count;
+ char *string;
+{
+ register int i;
+
+ i = strlen (string);
+
+ if (i >= count)
+ string[i++] = ' ';
+ else
+ {
+ while (i < count)
+ string[i++] = ' ';
+ }
+ string[i] = '\0';
+
+ return (i);
+}
diff --git a/gnu/usr.bin/texinfo/info/window.h b/gnu/usr.bin/texinfo/info/window.h
new file mode 100644
index 0000000..3e82570
--- /dev/null
+++ b/gnu/usr.bin/texinfo/info/window.h
@@ -0,0 +1,229 @@
+/* window.h -- Structure and flags used in manipulating Info windows. */
+
+/* This file is part of GNU Info, a program for reading online documentation
+ stored in Info format.
+
+ Copyright (C) 1993 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ Written by Brian Fox (bfox@ai.mit.edu). */
+
+#ifndef _WINDOW_H_
+#define _WINDOW_H_
+
+#include "nodes.h"
+#include "infomap.h"
+
+/* Smallest number of visible lines in a window. The actual height is
+ always one more than this number because each window has a modeline. */
+#define WINDOW_MIN_HEIGHT 2
+
+/* Smallest number of screen lines that can be used to fully present a
+ window. This number includes the modeline of the window. */
+#define WINDOW_MIN_SIZE (WINDOW_MIN_HEIGHT + 1)
+
+/* The exact same elements are used within the WINDOW_STATE structure and a
+ subsection of the WINDOW structure. We could define a structure which
+ contains this elements, and include that structure in each of WINDOW_STATE
+ and WINDOW. But that would lead references in the code such as
+ window->state->node which we would like to avoid. Instead, we #define the
+ elements here, and simply include the define in both data structures. Thus,
+ if you need to change window state information, here is where you would
+ do it. NB> The last element does NOT end with a semi-colon. */
+#define WINDOW_STATE_DECL \
+ NODE *node; /* The node displayed in this window. */ \
+ int pagetop; /* LINE_STARTS[PAGETOP] is first line in WINDOW. */ \
+ long point /* Offset within NODE of the cursor position. */
+
+/* Structure which defines a window. Windows are doubly linked, next
+ and prev. The list of windows is kept on WINDOWS. The structure member
+ window->height is the total height of the window. The position location
+ (0, window->height + window->first_row) is the first character of this
+ windows modeline. The number of lines that can be displayed in a window
+ is equal to window->height - 1. */
+typedef struct __window__ {
+ struct __window__ *next; /* Next window in this chain. */
+ struct __window__ *prev; /* Previous window in this chain. */
+ int width; /* Width of this window. */
+ int height; /* Height of this window. */
+ int first_row; /* Offset of the first line in the_screen. */
+ int goal_column; /* The column we would like the cursor to appear in. */
+ Keymap keymap; /* Keymap used to read commands in this window. */
+ WINDOW_STATE_DECL; /* Node, pagetop and point. */
+ char *modeline; /* Calculated text of the modeline for this window. */
+ char **line_starts; /* Array of printed line starts for this node. */
+ int line_count; /* Number of lines appearing in LINE_STARTS. */
+ int flags; /* See below for details. */
+} WINDOW;
+
+typedef struct {
+ WINDOW_STATE_DECL; /* What gets saved. */
+} WINDOW_STATE;
+
+#define W_UpdateWindow 0x01 /* WINDOW needs updating. */
+#define W_WindowIsPerm 0x02 /* This WINDOW is a permanent object. */
+#define W_WindowVisible 0x04 /* This WINDOW is currently visible. */
+#define W_InhibitMode 0x08 /* This WINDOW has no modeline. */
+#define W_NoWrap 0x10 /* Lines do not wrap in this window. */
+#define W_InputWindow 0x20 /* Window accepts input. */
+#define W_TempWindow 0x40 /* Window is less important. */
+
+extern WINDOW *windows; /* List of visible Info windows. */
+extern WINDOW *active_window; /* The currently active window. */
+extern WINDOW *the_screen; /* The Info screen is just another window. */
+extern WINDOW *the_echo_area; /* THE_ECHO_AREA is a window in THE_SCREEN. */
+
+/* Global variable control redisplay of scrolled windows. If non-zero, it
+ is the desired number of lines to scroll the window in order to make
+ point visible. A user might set this to 1 for smooth scrolling. If
+ set to zero, the line containing point is centered within the window. */
+extern int window_scroll_step;
+
+ /* Make the modeline member for WINDOW. */
+extern void window_make_modeline ();
+
+/* Initalize the window system by creating THE_SCREEN and THE_ECHO_AREA.
+ Create the first window ever, and make it permanent.
+ You pass WIDTH and HEIGHT; the dimensions of the total screen size. */
+extern void window_initialize_windows ();
+
+/* Make a new window showing NODE, and return that window structure.
+ The new window is made to be the active window. If NODE is passed
+ as NULL, then show the node showing in the active window. If the
+ window could not be made return a NULL pointer. The active window
+ is not changed.*/
+extern WINDOW *window_make_window ();
+
+/* Delete WINDOW from the list of known windows. If this window was the
+ active window, make the next window in the chain be the active window,
+ or the previous window in the chain if there is no next window. */
+extern void window_delete_window ();
+
+/* A function to call when the screen changes size, and some windows have
+ to get deleted. The function is called with the window to be deleted
+ as an argument, and it can't do anything about the window getting deleted;
+ it can only clean up dangling references to that window. */
+extern VFunction *window_deletion_notifier;
+
+/* Set WINDOW to display NODE. */
+extern void window_set_node_of_window ();
+
+/* Tell the window system that the size of the screen has changed. This
+ causes lots of interesting things to happen. The permanent windows
+ are resized, as well as every visible window. You pass WIDTH and HEIGHT;
+ the dimensions of the total screen size. */
+extern void window_new_screen_size ();
+
+/* Change the height of WINDOW by AMOUNT. This also automagically adjusts
+ the previous and next windows in the chain. If there is only one user
+ window, then no change takes place. */
+extern void window_change_window_height ();
+
+/* Adjust the pagetop of WINDOW such that the cursor point will be visible. */
+extern void window_adjust_pagetop ();
+
+/* Tile all of the windows currently displayed in the global variable
+ WINDOWS. If argument DO_INTERNALS is non-zero, tile windows displaying
+ internal nodes as well. */
+#define DONT_TILE_INTERNALS 0
+#define TILE_INTERNALS 1
+extern void window_tile_windows ();
+
+/* Toggle the state of line wrapping in WINDOW. This can do a bit of fancy
+ redisplay. */
+extern void window_toggle_wrap ();
+
+/* For every window in CHAIN, set the flags member to have FLAG set. */
+extern void window_mark_chain ();
+
+/* For every window in CHAIN, clear the flags member of FLAG. */
+extern void window_unmark_chain ();
+
+/* Make WINDOW start displaying at PERCENT percentage of its node. */
+extern void window_goto_percentage ();
+
+/* Build a new node which has FORMAT printed with ARG1 and ARG2 as the
+ contents. */
+extern NODE *build_message_node ();
+
+/* Useful functions can be called from outside of window.c. */
+extern void initialize_message_buffer ();
+
+/* Print FORMAT with ARG1,2 to the end of the current message buffer. */
+extern void printf_to_message_buffer ();
+
+/* Convert the contents of the message buffer to a node. */
+extern NODE *message_buffer_to_node ();
+
+/* Return the length of the most recently printed line in message buffer. */
+extern int message_buffer_length_this_line ();
+
+/* Pad STRING to COUNT characters by inserting blanks. */
+extern int pad_to ();
+
+/* Make a message appear in the echo area, built from FORMAT, ARG1 and ARG2.
+ The arguments are treated similar to printf () arguments, but not all of
+ printf () hair is present. The message appears immediately. If there was
+ already a message appearing in the echo area, it is removed. */
+extern void window_message_in_echo_area ();
+
+/* Place a temporary message in the echo area built from FORMAT, ARG1
+ and ARG2. The message appears immediately, but does not destroy
+ any existing message. A future call to unmessage_in_echo_area ()
+ restores the old contents. */
+extern void message_in_echo_area ();
+extern void unmessage_in_echo_area ();
+
+/* Clear the echo area, removing any message that is already present.
+ The echo area is cleared immediately. */
+extern void window_clear_echo_area ();
+
+/* Quickly guess the approximate number of lines to that NODE would
+ take to display. This really only counts carriage returns. */
+extern int window_physical_lines ();
+
+/* Calculate a list of line starts for the node belonging to WINDOW. The line
+ starts are pointers to the actual text within WINDOW->NODE. */
+extern void calculate_line_starts ();
+
+/* Given WINDOW, recalculate the line starts for the node it displays. */
+extern void recalculate_line_starts ();
+
+/* Return the number of characters it takes to display CHARACTER on the
+ screen at HPOS. */
+extern int character_width ();
+
+/* Return the number of characters it takes to display STRING on the
+ screen at HPOS. */
+extern int string_width ();
+
+/* Return the index of the line containing point. */
+extern int window_line_of_point ();
+
+/* Get and return the goal column for this window. */
+extern int window_get_goal_column ();
+
+/* Get and return the printed column offset of the cursor in this window. */
+extern int window_get_cursor_column ();
+
+/* Get and Set the node, pagetop, and point of WINDOW. */
+extern void window_get_state (), window_set_state ();
+
+/* Count the number of characters in LINE that precede the printed column
+ offset of GOAL. */
+extern int window_chars_to_goal ();
+
+#endif /* !_WINDOW_H_ */
diff --git a/gnu/usr.bin/texinfo/info/xmalloc.c b/gnu/usr.bin/texinfo/info/xmalloc.c
new file mode 100644
index 0000000..6ebb84c
--- /dev/null
+++ b/gnu/usr.bin/texinfo/info/xmalloc.c
@@ -0,0 +1,78 @@
+/* xmalloc.c -- safe versions of malloc and realloc */
+
+/* This file is part of GNU Info, a program for reading online documentation
+ stored in Info format.
+
+ This file has appeared in prior works by the Free Software Foundation;
+ thus it carries copyright dates from 1988 through 1993.
+
+ Copyright (C) 1988, 1989, 1990, 1991, 1992, 1993 Free Software
+ Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ Written by Brian Fox (bfox@ai.mit.edu). */
+
+#if !defined (ALREADY_HAVE_XMALLOC)
+#include <stdio.h>
+
+static void memory_error_and_abort ();
+
+/* **************************************************************** */
+/* */
+/* Memory Allocation and Deallocation. */
+/* */
+/* **************************************************************** */
+
+/* Return a pointer to free()able block of memory large enough
+ to hold BYTES number of bytes. If the memory cannot be allocated,
+ print an error message and abort. */
+void *
+xmalloc (bytes)
+ int bytes;
+{
+ void *temp = (void *)malloc (bytes);
+
+ if (!temp)
+ memory_error_and_abort ("xmalloc");
+ return (temp);
+}
+
+void *
+xrealloc (pointer, bytes)
+ void *pointer;
+ int bytes;
+{
+ void *temp;
+
+ if (!pointer)
+ temp = (void *)malloc (bytes);
+ else
+ temp = (void *)realloc (pointer, bytes);
+
+ if (!temp)
+ memory_error_and_abort ("xrealloc");
+
+ return (temp);
+}
+
+static void
+memory_error_and_abort (fname)
+ char *fname;
+{
+ fprintf (stderr, "%s: Out of virtual memory!\n", fname);
+ abort ();
+}
+#endif /* !ALREADY_HAVE_XMALLOC */
diff --git a/gnu/usr.bin/texinfo/makedoc/Makefile b/gnu/usr.bin/texinfo/makedoc/Makefile
new file mode 100644
index 0000000..d97ec09
--- /dev/null
+++ b/gnu/usr.bin/texinfo/makedoc/Makefile
@@ -0,0 +1,20 @@
+#
+# Bmakefile for GNU info
+#
+# $Id: Makefile,v 1.2 1994/09/15 13:10:41 jkh Exp $
+#
+
+PROG= makedoc
+NOMAN=yes
+SRCS+= makedoc.c xmalloc.c
+
+CFLAGS+= -I${.CURDIR}/../info -I${.CURDIR}
+CFLAGS+= -DNAMED_FUNCTIONS=1 -DSTDC_HEADERS=1
+CFLAGS+= -DHAVE_UNISTD_H=1 -DHAVE_STRING_H=1 -DHAVE_VARARGS_H=1
+CFLAGS+= -DHAVE_SYS_FCNTL_H=1 -DHAVE_SETVBUF=1 -DHAVE_GETCWD=1 -DHAVE_BZERO=1
+CFLAGS+= -DHAVE_RINDEX=1 -DHAVE_VFPRINTF=1 -DHAVE_VSPRINTF=1
+CFLAGS+= -DHAVE_SYS_TIME_H=1 -DDEFAULT_INFOPATH='"${INFODIR}"'
+
+.include "../../Makefile.inc"
+.include <bsd.prog.mk>
+
diff --git a/gnu/usr.bin/texinfo/makedoc/makedoc.c b/gnu/usr.bin/texinfo/makedoc/makedoc.c
new file mode 100644
index 0000000..ddf19b7
--- /dev/null
+++ b/gnu/usr.bin/texinfo/makedoc/makedoc.c
@@ -0,0 +1,477 @@
+/* makedoc.c -- Make DOC.C and FUNS.H from input files. */
+
+/* This file is part of GNU Info, a program for reading online documentation
+ stored in Info format.
+
+ Copyright (C) 1993 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ Written by Brian Fox (bfox@ai.mit.edu). */
+
+/* This program grovels the contents of the source files passed as arguments
+ and writes out a file of function pointers and documentation strings, and
+ a header file which describes the contents. This only does the functions
+ declared with DECLARE_INFO_COMMAND. */
+
+#include <stdio.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <sys/file.h>
+#include <sys/stat.h>
+#include "general.h"
+
+#if !defined (O_RDONLY)
+#if defined (HAVE_SYS_FCNTL_H)
+#include <sys/fcntl.h>
+#else /* !HAVE_SYS_FCNTL_H */
+#include <fcntl.h>
+#endif /* !HAVE_SYS_FCNTL_H */
+#endif /* !O_RDONLY */
+
+extern void *xmalloc (), *xrealloc ();
+static void fatal_file_error ();
+
+/* Name of the header file which receives the declarations of functions. */
+static char *funs_filename = "funs.h";
+
+/* Name of the documentation to function pointer file. */
+static char *doc_filename = "doc.c";
+
+static char *doc_header[] = {
+ "/* doc.c -- Generated structure containing function names and doc strings.",
+ "",
+ " This file was automatically made from various source files with the",
+ " command \"%s\". DO NOT EDIT THIS FILE, only \"%s.c\".",
+ (char *)NULL
+};
+
+static char *doc_header_1[] = {
+ " An entry in the array FUNCTION_DOC_ARRAY is made for each command",
+ " found in the above files; each entry consists of a function pointer,",
+#if defined (NAMED_FUNCTIONS)
+ " a string which is the user-visible name of the function,",
+#endif /* NAMED_FUNCTIONS */
+ " and a string which documents its purpose. */",
+ "",
+ "#include \"doc.h\"",
+ "#include \"funs.h\"",
+ "",
+ "FUNCTION_DOC function_doc_array[] = {",
+ "",
+ (char *)NULL
+};
+
+/* How to remember the locations of the functions found so that Emacs
+ can use the information in a tag table. */
+typedef struct {
+ char *name; /* Name of the tag. */
+ int line; /* Line number at which it appears. */
+ long char_offset; /* Character offset at which it appears. */
+} EMACS_TAG;
+
+typedef struct {
+ char *filename; /* Name of the file containing entries. */
+ long entrylen; /* Total number of characters in tag block. */
+ EMACS_TAG **entries; /* Entries found in FILENAME. */
+ int entries_index;
+ int entries_slots;
+} EMACS_TAG_BLOCK;
+
+EMACS_TAG_BLOCK **emacs_tags = (EMACS_TAG_BLOCK **)NULL;
+int emacs_tags_index = 0;
+int emacs_tags_slots = 0;
+
+#define DECLARATION_STRING "\nDECLARE_INFO_COMMAND"
+
+static void process_one_file ();
+static void maybe_dump_tags ();
+static FILE *must_fopen ();
+
+int
+main (argc, argv)
+ int argc;
+ char **argv;
+{
+ register int i;
+ int tags_only = 0;
+ FILE *funs_stream, *doc_stream;
+
+ for (i = 1; i < argc; i++)
+ if (strcmp (argv[i], "-tags") == 0)
+ {
+ tags_only++;
+ break;
+ }
+
+ if (tags_only)
+ {
+ funs_filename = "/dev/null";
+ doc_filename = "/dev/null";
+ }
+
+ funs_stream = must_fopen (funs_filename, "w");
+ doc_stream = must_fopen (doc_filename, "w");
+
+ fprintf (funs_stream,
+ "/* %s -- Generated declarations for Info commands. */\n",
+ funs_filename);
+
+ for (i = 0; doc_header[i]; i++)
+ {
+ fprintf (doc_stream, doc_header[i], argv[0], argv[0]);
+ fprintf (doc_stream, "\n");
+ }
+
+ fprintf (doc_stream,
+ " Source files groveled to make this file include:\n\n");
+
+ for (i = 1; i < argc; i++)
+ fprintf (doc_stream, "\t%s\n", argv[i]);
+
+ fprintf (doc_stream, "\n");
+
+ for (i = 0; doc_header_1[i]; i++)
+ fprintf (doc_stream, "%s\n", doc_header_1[i]);
+
+
+ for (i = 1; i < argc; i++)
+ {
+ char *curfile;
+ curfile = argv[i];
+
+ if (*curfile == '-')
+ continue;
+
+ fprintf (doc_stream, "/* Commands found in \"%s\". */\n", curfile);
+ fprintf (funs_stream, "\n/* Functions declared in \"%s\". */\n",
+ curfile);
+
+ process_one_file (curfile, doc_stream, funs_stream);
+ }
+
+ fprintf (doc_stream,
+ " { (VFunction *)NULL, (char *)NULL, (char *)NULL }\n};\n");
+
+ fclose (funs_stream);
+ fclose (doc_stream);
+
+ if (tags_only)
+ maybe_dump_tags (stdout);
+ exit (0);
+}
+
+/* Dumping out the contents of an Emacs tags table. */
+static void
+maybe_dump_tags (stream)
+ FILE *stream;
+{
+ register int i;
+
+ /* Print out the information for each block. */
+ for (i = 0; i < emacs_tags_index; i++)
+ {
+ register int j;
+ register EMACS_TAG_BLOCK *block;
+ register EMACS_TAG *etag;
+ long block_len;
+
+ block_len = 0;
+ block = emacs_tags[i];
+
+ /* Calculate the length of the dumped block first. */
+ for (j = 0; j < block->entries_index; j++)
+ {
+ char digits[30];
+ etag = block->entries[j];
+ block_len += 3 + strlen (etag->name);
+ sprintf (digits, "%d,%d", etag->line, etag->char_offset);
+ block_len += strlen (digits);
+ }
+
+ /* Print out the defining line. */
+ fprintf (stream, "\f\n%s,%d\n", block->filename, block_len);
+
+ /* Print out the individual tags. */
+ for (j = 0; j < block->entries_index; j++)
+ {
+ etag = block->entries[j];
+
+ fprintf (stream, "%s,\177%d,%d\n",
+ etag->name, etag->line, etag->char_offset);
+ }
+ }
+}
+
+/* Keeping track of names, line numbers and character offsets of functions
+ found in source files. */
+static EMACS_TAG_BLOCK *
+make_emacs_tag_block (filename)
+ char *filename;
+{
+ EMACS_TAG_BLOCK *block;
+
+ block = (EMACS_TAG_BLOCK *)xmalloc (sizeof (EMACS_TAG_BLOCK));
+ block->filename = savestring (filename);
+ block->entrylen = 0;
+ block->entries = (EMACS_TAG **)NULL;
+ block->entries_index = 0;
+ block->entries_slots = 0;
+ return (block);
+}
+
+static void
+add_tag_to_block (block, name, line, char_offset)
+ EMACS_TAG_BLOCK *block;
+ char *name;
+ int line;
+ long char_offset;
+{
+ EMACS_TAG *tag;
+
+ tag = (EMACS_TAG *)xmalloc (sizeof (EMACS_TAG));
+ tag->name = name;
+ tag->line = line;
+ tag->char_offset = char_offset;
+ add_pointer_to_array (tag, block->entries_index, block->entries,
+ block->entries_slots, 50, EMACS_TAG *);
+}
+
+/* Read the file represented by FILENAME into core, and search it for Info
+ function declarations. Output the declarations in various forms to the
+ DOC_STREAM and FUNS_STREAM. */
+static void
+process_one_file (filename, doc_stream, funs_stream)
+ char *filename;
+ FILE *doc_stream, *funs_stream;
+{
+ int descriptor, decl_len;
+ char *buffer, *decl_str;
+ struct stat finfo;
+ long offset;
+ EMACS_TAG_BLOCK *block;
+
+ if (stat (filename, &finfo) == -1)
+ fatal_file_error (filename);
+
+ descriptor = open (filename, O_RDONLY, 0666);
+
+ if (descriptor == -1)
+ fatal_file_error (filename);
+
+ buffer = (char *)xmalloc (1 + finfo.st_size);
+ read (descriptor, buffer, finfo.st_size);
+ close (descriptor);
+
+ offset = 0;
+ decl_str = DECLARATION_STRING;
+ decl_len = strlen (decl_str);
+
+ block = make_emacs_tag_block (filename);
+
+ while (1)
+ {
+ long point = 0;
+ long line_start = 0;
+ int line_number = 0;
+
+ char *func, *doc;
+#if defined (NAMED_FUNCTIONS)
+ char *func_name;
+#endif /* NAMED_FUNCTIONS */
+
+ for (; offset < (finfo.st_size - decl_len); offset++)
+ {
+ if (buffer[offset] == '\n')
+ {
+ line_number++;
+ line_start = offset + 1;
+ }
+
+ if (strncmp (buffer + offset, decl_str, decl_len) == 0)
+ {
+ offset += decl_len;
+ point = offset;
+ break;
+ }
+ }
+
+ if (!point)
+ break;
+
+ /* Skip forward until we find the open paren. */
+ while (point < finfo.st_size)
+ {
+ if (buffer[point] == '\n')
+ {
+ line_number++;
+ line_start = point + 1;
+ }
+ else if (buffer[point] == '(')
+ break;
+
+ point++;
+ }
+
+ while (point++ < finfo.st_size)
+ {
+ if (!whitespace_or_newline (buffer[point]))
+ break;
+ else if (buffer[point] == '\n')
+ {
+ line_number++;
+ line_start = point + 1;
+ }
+ }
+
+ if (point >= finfo.st_size)
+ break;
+
+ /* Now looking at name of function. Get it. */
+ for (offset = point; buffer[offset] != ','; offset++);
+ func = (char *)xmalloc (1 + (offset - point));
+ strncpy (func, buffer + point, offset - point);
+ func[offset - point] = '\0';
+
+ /* Remember this tag in the current block. */
+ {
+ char *tag_name;
+
+ tag_name = (char *)xmalloc (1 + (offset - line_start));
+ strncpy (tag_name, buffer + line_start, offset - line_start);
+ tag_name[offset - line_start] = '\0';
+ add_tag_to_block (block, tag_name, line_number, point);
+ }
+
+#if defined (NAMED_FUNCTIONS)
+ /* Generate the user-visible function name from the function's name. */
+ {
+ register int i;
+ char *name_start;
+
+ name_start = func;
+
+ if (strncmp (name_start, "info_", 5) == 0)
+ name_start += 5;
+
+ func_name = savestring (name_start);
+
+ /* Fix up "ea" commands. */
+ if (strncmp (func_name, "ea_", 3) == 0)
+ {
+ char *temp_func_name;
+
+ temp_func_name = (char *)xmalloc (10 + strlen (func_name));
+ strcpy (temp_func_name, "echo_area_");
+ strcat (temp_func_name, func_name + 3);
+ free (func_name);
+ func_name = temp_func_name;
+ }
+
+ for (i = 0; func_name[i]; i++)
+ if (func_name[i] == '_')
+ func_name[i] = '-';
+ }
+#endif /* NAMED_FUNCTIONS */
+
+ /* Find doc string. */
+ point = offset + 1;
+
+ while (point < finfo.st_size)
+ {
+ if (buffer[point] == '\n')
+ {
+ line_number++;
+ line_start = point + 1;
+ }
+
+ if (buffer[point] == '"')
+ break;
+ else
+ point++;
+ }
+
+ offset = point + 1;
+
+ while (offset < finfo.st_size)
+ {
+ if (buffer[offset] == '\n')
+ {
+ line_number++;
+ line_start = offset + 1;
+ }
+
+ if (buffer[offset] == '\\')
+ offset += 2;
+ else if (buffer[offset] == '"')
+ break;
+ else
+ offset++;
+ }
+
+ offset++;
+ if (offset >= finfo.st_size)
+ break;
+
+ doc = (char *)xmalloc (1 + (offset - point));
+ strncpy (doc, buffer + point, offset - point);
+ doc[offset - point] = '\0';
+
+#if defined (NAMED_FUNCTIONS)
+ fprintf (doc_stream, " { %s, \"%s\", %s },\n", func, func_name, doc);
+ free (func_name);
+#else /* !NAMED_FUNCTIONS */
+ fprintf (doc_stream, " { %s, %s },\n", func, doc);
+#endif /* !NAMED_FUNCTIONS */
+
+ fprintf (funs_stream, "extern void %s ();\n", func);
+ free (func);
+ free (doc);
+ }
+ free (buffer);
+
+ /* If we created any tags, remember this file on our global list. Otherwise,
+ free the memory already allocated to it. */
+ if (block->entries)
+ add_pointer_to_array (block, emacs_tags_index, emacs_tags,
+ emacs_tags_slots, 10, EMACS_TAG_BLOCK *);
+ else
+ {
+ free (block->filename);
+ free (block);
+ }
+}
+
+static void
+fatal_file_error (filename)
+ char *filename;
+{
+ fprintf (stderr, "Couldn't manipulate the file %s.\n", filename);
+ exit (2);
+}
+
+static FILE *
+must_fopen (filename, mode)
+ char *filename, *mode;
+{
+ FILE *stream;
+
+ stream = fopen (filename, mode);
+ if (!stream)
+ fatal_file_error (filename);
+
+ return (stream);
+}
+
diff --git a/gnu/usr.bin/texinfo/makedoc/xmalloc.c b/gnu/usr.bin/texinfo/makedoc/xmalloc.c
new file mode 100644
index 0000000..6ebb84c
--- /dev/null
+++ b/gnu/usr.bin/texinfo/makedoc/xmalloc.c
@@ -0,0 +1,78 @@
+/* xmalloc.c -- safe versions of malloc and realloc */
+
+/* This file is part of GNU Info, a program for reading online documentation
+ stored in Info format.
+
+ This file has appeared in prior works by the Free Software Foundation;
+ thus it carries copyright dates from 1988 through 1993.
+
+ Copyright (C) 1988, 1989, 1990, 1991, 1992, 1993 Free Software
+ Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ Written by Brian Fox (bfox@ai.mit.edu). */
+
+#if !defined (ALREADY_HAVE_XMALLOC)
+#include <stdio.h>
+
+static void memory_error_and_abort ();
+
+/* **************************************************************** */
+/* */
+/* Memory Allocation and Deallocation. */
+/* */
+/* **************************************************************** */
+
+/* Return a pointer to free()able block of memory large enough
+ to hold BYTES number of bytes. If the memory cannot be allocated,
+ print an error message and abort. */
+void *
+xmalloc (bytes)
+ int bytes;
+{
+ void *temp = (void *)malloc (bytes);
+
+ if (!temp)
+ memory_error_and_abort ("xmalloc");
+ return (temp);
+}
+
+void *
+xrealloc (pointer, bytes)
+ void *pointer;
+ int bytes;
+{
+ void *temp;
+
+ if (!pointer)
+ temp = (void *)malloc (bytes);
+ else
+ temp = (void *)realloc (pointer, bytes);
+
+ if (!temp)
+ memory_error_and_abort ("xrealloc");
+
+ return (temp);
+}
+
+static void
+memory_error_and_abort (fname)
+ char *fname;
+{
+ fprintf (stderr, "%s: Out of virtual memory!\n", fname);
+ abort ();
+}
+#endif /* !ALREADY_HAVE_XMALLOC */
diff --git a/gnu/usr.bin/texinfo/makeinfo/Makefile b/gnu/usr.bin/texinfo/makeinfo/Makefile
new file mode 100644
index 0000000..e102200
--- /dev/null
+++ b/gnu/usr.bin/texinfo/makeinfo/Makefile
@@ -0,0 +1,22 @@
+#
+# Bmakefile for GNU info
+#
+# $Id: Makefile,v 1.2 1994/09/15 13:11:36 jkh Exp $
+#
+
+PROG= makeinfo
+NOMAN=yes
+SRCS+= makeinfo.c getopt1.c getopt.c
+
+.PATH: ${.CURDIR}/../info
+
+CFLAGS+= -I${.CURDIR}/../info -I${.CURDIR}
+CFLAGS+= -DNAMED_FUNCTIONS=1 -DSTDC_HEADERS=1
+CFLAGS+= -DHAVE_UNISTD_H=1 -DHAVE_STRING_H=1 -DHAVE_VARARGS_H=1
+CFLAGS+= -DHAVE_SYS_FCNTL_H=1 -DHAVE_SETVBUF=1 -DHAVE_GETCWD=1 -DHAVE_BZERO=1
+CFLAGS+= -DHAVE_RINDEX=1 -DHAVE_VFPRINTF=1 -DHAVE_VSPRINTF=1
+CFLAGS+= -DHAVE_SYS_TIME_H=1 -DDEFAULT_INFOPATH='"${INFODIR}"'
+
+.include "../../Makefile.inc"
+.include <bsd.prog.mk>
+
diff --git a/gnu/usr.bin/texinfo/makeinfo/makeinfo.c b/gnu/usr.bin/texinfo/makeinfo/makeinfo.c
new file mode 100644
index 0000000..1e292922
--- /dev/null
+++ b/gnu/usr.bin/texinfo/makeinfo/makeinfo.c
@@ -0,0 +1,7549 @@
+/* Makeinfo -- convert texinfo format files into info files.
+
+ Copyright (C) 1987, 1992, 1993 Free Software Foundation, Inc.
+
+ This file is part of GNU Info.
+
+ Makeinfo is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY. No author or distributor accepts
+ responsibility to anyone for the consequences of using it or for
+ whether it serves any particular purpose or works at all, unless he
+ says so in writing. Refer to the GNU Emacs General Public License
+ for full details.
+
+ Everyone is granted permission to copy, modify and redistribute
+ Makeinfo, but only under the conditions described in the GNU Emacs
+ General Public License. A copy of this license is supposed to
+ have been given to you along with GNU Emacs so you can know your
+ rights and responsibilities. It should be in a file named COPYING.
+ Among other things, the copyright notice and this notice must be
+ preserved on all copies. */
+
+/* This is Makeinfo version 1.55. If you change the version number of
+ Makeinfo, please change it here and at the lines reading:
+
+ int major_version = 1;
+ int minor_version = 55;
+
+ in the code below.
+
+ Makeinfo is authored by Brian Fox (bfox@ai.mit.edu). */
+
+/* You can change some of the behaviour of Makeinfo by changing the
+ following defines: */
+
+/* Define INDENT_PARAGRAPHS_IN_TABLE if you want the paragraphs which
+ appear within an @table, @ftable, or @itemize environment to have
+ standard paragraph indentation. Without this, such paragraphs have
+ no starting indentation. */
+/* #define INDENT_PARAGRAPHS_IN_TABLE */
+
+/* Define DEFAULT_INDENTATION_INCREMENT as an integer which is the amount
+ that @example should increase indentation by. This incremement is used
+ for all insertions which indent the enclosed text. */
+#define DEFAULT_INDENTATION_INCREMENT 5
+
+/* Define PARAGRAPH_START_INDENT to be the amount of indentation that
+ the first lines of paragraphs receive by default, where no other
+ value has been specified. Users can change this value on the command
+ line, with the +paragraph-indent option, or within the texinfo file,
+ with the @paragraphindent command. */
+#define PARAGRAPH_START_INDENT 3
+
+/* Define DEFAULT_PARAGRAPH_SPACING as the number of blank lines that you
+ wish to appear between paragraphs. A value of 1 creates a single blank
+ line between paragraphs. Paragraphs are defined by 2 or more consecutive
+ newlines in the input file (i.e., one or more blank lines). */
+#define DEFAULT_PARAGRAPH_SPACING 1
+
+/* **************************************************************** */
+/* */
+/* Include File Declarations */
+/* */
+/* **************************************************************** */
+
+/* Indent #pragma so that older Cpp's don't try to parse it. */
+#if defined (_AIX)
+ # pragma alloca
+#endif /* _AIX */
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <ctype.h>
+#include <sys/stat.h>
+#include <ctype.h>
+#include <pwd.h>
+#include <errno.h>
+#if defined (HAVE_VARARGS_H)
+#include <varargs.h>
+#endif /* HAVE_VARARGS_H */
+#include "getopt.h"
+
+#if defined (VMS)
+#include <perror.h>
+#endif
+
+#if defined (HAVE_STRING_H)
+#include <string.h>
+#else
+#include <strings.h>
+#endif /* !HAVE_STRING_H */
+
+#if defined (TM_IN_SYS_TIME)
+#include <sys/time.h>
+#else
+#include <time.h>
+#endif /* !TM_IN_SYS_TIME */
+
+#if defined (HAVE_SYS_FCNTL_H)
+#include <sys/fcntl.h>
+#else
+#include <fcntl.h>
+#endif /* !HAVE_SYS_FCNTL_H */
+
+#include <sys/file.h>
+
+#if defined (__GNUC__)
+#define alloca __builtin_alloca
+#else
+#if defined(HAVE_ALLOCA_H)
+#include <alloca.h>
+#else /* !HAVE_ALLOCA_H */
+#if !defined (_AIX)
+extern char *alloca ();
+#endif /* !_AIX */
+#endif /* !HAVE_ALLOCA_H */
+#endif /* !__GNUC__ */
+
+void *xmalloc (), *xrealloc ();
+static void isolate_nodename ();
+
+/* Non-zero means that we are currently hacking the insides of an
+ insertion which would use a fixed width font. */
+static int in_fixed_width_font = 0;
+
+/* Non-zero means that start_paragraph () MUST be called before we pay
+ any attention to close_paragraph () calls. */
+int must_start_paragraph = 0;
+
+/* Some systems don't declare this function in pwd.h. */
+struct passwd *getpwnam ();
+
+
+/* **************************************************************** */
+/* */
+/* Global Defines */
+/* */
+/* **************************************************************** */
+
+/* Error levels */
+#define NO_ERROR 0
+#define SYNTAX 2
+#define FATAL 4
+
+/* How to allocate permanent storage for STRING. */
+#define savestring(x) \
+ ((char *)strcpy ((char *)xmalloc (1 + ((x) ? strlen (x) : 0)), \
+ (x) ? (x) : ""))
+
+/* C's standard macros don't check to make sure that the characters being
+ changed are within range. So I have to check explicitly. */
+
+/* GNU Library doesn't have toupper(). Until GNU gets this fixed, I will
+ have to do it. */
+#ifndef toupper
+#define toupper(c) ((c) - 32)
+#endif
+
+#define coerce_to_upper(c) ((islower(c) ? toupper(c) : (c)))
+#define coerce_to_lower(c) ((isupper(c) ? tolower(c) : (c)))
+
+#define control_character_bit 0x40 /* %01000000, must be off. */
+#define meta_character_bit 0x080/* %10000000, must be on. */
+#define CTL(c) ((c) & (~control_character_bit))
+#define UNCTL(c) coerce_to_upper(((c)|control_character_bit))
+#define META(c) ((c) | (meta_character_bit))
+#define UNMETA(c) ((c) & (~meta_character_bit))
+
+#define whitespace(c) (((c) == '\t') || ((c) == ' '))
+#define sentence_ender(c) ((c) == '.' || (c) == '?' || (c) == '!')
+#define cr_or_whitespace(c) (((c) == '\t') || ((c) == ' ') || ((c) == '\n'))
+
+#ifndef isletter
+#define isletter(c) (((c) >= 'A' && (c) <= 'Z') || ((c) >= 'a' && (c) <= 'z'))
+#endif
+
+#ifndef isupper
+#define isupper(c) ((c) >= 'A' && (c) <= 'Z')
+#endif
+
+#ifndef isdigit
+#define isdigit(c) ((c) >= '0' && (c) <= '9')
+#endif
+
+#ifndef digit_value
+#define digit_value(c) ((c) - '0')
+#endif
+
+#define member(c, s) (strchr (s, c) != NULL)
+
+#define COMMAND_PREFIX '@'
+
+/* Stuff for splitting large files. */
+#define SPLIT_SIZE_THRESHOLD 70000 /* What's good enough for Stallman... */
+#define DEFAULT_SPLIT_SIZE 50000 /* Is probably good enough for me. */
+int splitting = 1; /* Always true for now. */
+
+typedef int FUNCTION (); /* So I can say FUNCTION *foo; */
+
+
+/* **************************************************************** */
+/* */
+/* Global Variables */
+/* */
+/* **************************************************************** */
+
+/* Global pointer to argv[0]. */
+char *progname;
+
+/* The current input file state. */
+char *input_filename;
+char *input_text;
+int size_of_input_text;
+int input_text_offset;
+int line_number;
+
+#define curchar() input_text[input_text_offset]
+
+#define command_char(c) ((!whitespace(c)) && \
+ ((c) != '\n') && \
+ ((c) != '{') && \
+ ((c) != '}') && \
+ ((c) != '='))
+
+#define skip_whitespace() while (input_text_offset != size_of_input_text \
+ && whitespace(curchar()))\
+ input_text_offset++
+
+/* Return non-zero if STRING is the text at input_text + input_text_offset,
+ else zero. */
+#define looking_at(string) \
+ (strncmp (input_text + input_text_offset, string, strlen (string)) == 0)
+
+/* And writing to the output. */
+
+/* The output file name. */
+char *output_filename = (char *)NULL;
+char *pretty_output_filename;
+
+/* Name of the output file that the user elected to pass on the command line.
+ Such a name overrides any name found with the @setfilename command. */
+char *command_output_filename = (char *)NULL;
+
+/* A colon separated list of directories to search for files included
+ with @include. This can be controlled with the `-I' option to makeinfo. */
+char *include_files_path = (char *)NULL;
+
+/* Current output stream. */
+FILE *output_stream;
+
+/* Position in the output file. */
+int output_position;
+
+/* Output paragraph buffer. */
+unsigned char *output_paragraph;
+
+/* Offset into OUTPUT_PARAGRAPH. */
+int output_paragraph_offset;
+
+/* The output paragraph "cursor" horizontal position. */
+int output_column = 0;
+
+/* Non-zero means output_paragraph contains text. */
+int paragraph_is_open = 0;
+
+#define INITIAL_PARAGRAPH_SPACE 5000
+int paragraph_buffer_len = INITIAL_PARAGRAPH_SPACE;
+
+/* Filling.. */
+/* Non-zero indicates that filling will take place on long lines. */
+int filling_enabled = 1;
+
+/* Non-zero means that words are not to be split, even in long lines. This
+ gets changed for cm_w (). */
+int non_splitting_words = 0;
+
+/* Non-zero indicates that filling a line also indents the new line. */
+int indented_fill = 0;
+
+/* The column at which long lines are broken. */
+int fill_column = 72;
+
+/* The amount of indentation to apply at the start of each line. */
+int current_indent = 0;
+
+/* The amount of indentation to add at the starts of paragraphs.
+ 0 means don't change existing indentation at paragraph starts.
+ > 0 is amount to indent new paragraphs by.
+ < 0 means indent to column zero by removing indentation if necessary.
+
+ This is normally zero, but some people prefer paragraph starts to be
+ somewhat more indented than paragraph bodies. A pretty value for
+ this is 3. */
+int paragraph_start_indent = PARAGRAPH_START_INDENT;
+
+/* Non-zero means that the use of paragraph_start_indent is inhibited.
+ @example uses this to line up the left columns of the example text.
+ A negative value for this variable is incremented each time it is used.
+ @noindent uses this to inhibit indentation for a single paragraph. */
+int inhibit_paragraph_indentation = 0;
+
+/* Indentation that is pending insertion. We have this for hacking lines
+ which look blank, but contain whitespace. We want to treat those as
+ blank lines. */
+int pending_indent = 0;
+
+/* The amount that indentation increases/decreases by. */
+int default_indentation_increment = DEFAULT_INDENTATION_INCREMENT;
+
+/* Non-zero indicates that indentation is temporarily turned off. */
+int no_indent = 1;
+
+/* Non-zero means forcing output text to be flushright. */
+int force_flush_right = 0;
+
+/* Non-zero means that the footnote style for this document was set on
+ the command line, which overrides any other settings. */
+int footnote_style_preset = 0;
+
+/* Non-zero means that we automatically number footnotes that have no
+ specified marker. */
+int number_footnotes = 1;
+
+/* The current footnote number in this node. Each time a new node is
+ started this is reset to 1. */
+int current_footnote_number = 1;
+
+/* Command name in the process of being hacked. */
+char *command;
+
+/* The index in our internal command table of the currently
+ executing command. */
+int command_index;
+
+/* A stack of file information records. If a new file is read in with
+ "@input", we remember the old input file state on this stack. */
+typedef struct fstack
+{
+ struct fstack *next;
+ char *filename;
+ char *text;
+ int size;
+ int offset;
+ int line_number;
+} FSTACK;
+
+FSTACK *filestack = (FSTACK *) NULL;
+
+/* Stuff for nodes. */
+/* The current nodes node name. */
+char *current_node = (char *)NULL;
+
+/* The current nodes section level. */
+int current_section = 0;
+
+/* The filename of the current input file. This is never freed. */
+char *node_filename = (char *)NULL;
+
+/* What we remember for each node. */
+typedef struct tentry
+{
+ struct tentry *next_ent;
+ char *node; /* name of this node. */
+ char *prev; /* name of "Prev:" for this node. */
+ char *next; /* name of "Next:" for this node. */
+ char *up; /* name of "Up:" for this node. */
+ int position; /* output file position of this node. */
+ int line_no; /* defining line in source file. */
+ char *filename; /* The file that this node was found in. */
+ int touched; /* non-zero means this node has been referenced. */
+ int flags; /* Room for growth. Right now, contains 1 bit. */
+} TAG_ENTRY;
+
+/* If node-a has a "Next" for node-b, but node-b has no "Prev" for node-a,
+ we turn on this flag bit in node-b's tag entry. This means that when
+ it is time to validate node-b, we don't report an additional error
+ if there was no "Prev" field. */
+#define PREV_ERROR 0x1
+#define NEXT_ERROR 0x2
+#define UP_ERROR 0x4
+#define NO_WARN 0x8
+#define IS_TOP 0x10
+
+TAG_ENTRY *tag_table = (TAG_ENTRY *) NULL;
+
+#define HAVE_MACROS
+#if defined (HAVE_MACROS)
+/* Macro definitions for user-defined commands. */
+typedef struct {
+ char *name; /* Name of the macro. */
+ char *definition; /* Definition text. */
+ char *filename; /* File where this macro is defined. */
+ int lineno; /* Line number within FILENAME. */
+} MACRO_DEF;
+
+void add_macro (), execute_macro ();
+MACRO_DEF *find_macro (), *delete_macro ();
+#endif /* HAVE_MACROS */
+
+/* Menu reference, *note reference, and validation hacking. */
+
+/* The various references that we know about. */
+enum reftype
+{
+ menu_reference, followed_reference
+};
+
+/* A structure to remember references with. A reference to a node is
+ either an entry in a menu, or a cross-reference made with [px]ref. */
+typedef struct node_ref
+{
+ struct node_ref *next;
+ char *node; /* Name of node referred to. */
+ char *containing_node; /* Name of node containing this reference. */
+ int line_no; /* Line number where the reference occurs. */
+ int section; /* Section level where the reference occurs. */
+ char *filename; /* Name of file where the reference occurs. */
+ enum reftype type; /* Type of reference, either menu or note. */
+} NODE_REF;
+
+/* The linked list of such structures. */
+NODE_REF *node_references = (NODE_REF *) NULL;
+
+/* Flag which tells us whether to examine menu lines or not. */
+int in_menu = 0;
+
+/* Flags controlling the operation of the program. */
+
+/* Default is to notify users of bad choices. */
+int print_warnings = 1;
+
+/* Default is to check node references. */
+int validating = 1;
+
+/* Non-zero means do not output "Node: Foo" for node separations. */
+int no_headers = 0;
+
+/* Number of errors that we tolerate on a given fileset. */
+int max_error_level = 100;
+
+/* Maximum number of references to a single node before complaining. */
+int reference_warning_limit = 1000;
+
+/* Non-zero means print out information about what is going on when it
+ is going on. */
+int verbose_mode = 0;
+
+/* The list of commands that we hack in texinfo. Each one
+ has an associated function. When the command is encountered in the
+ text, the associated function is called with START as the argument.
+ If the function expects arguments in braces, it remembers itself on
+ the stack. When the corresponding close brace is encountered, the
+ function is called with END as the argument. */
+
+#define START 0
+#define END 1
+
+typedef struct brace_element
+{
+ struct brace_element *next;
+ FUNCTION *proc;
+ int pos, line;
+} BRACE_ELEMENT;
+
+BRACE_ELEMENT *brace_stack = (BRACE_ELEMENT *) NULL;
+
+/* Forward declarations. */
+
+int insert_self (), cm_ignore_line ();
+
+int
+ cm_tex (), cm_asterisk (), cm_dots (), cm_bullet (), cm_TeX (),
+ cm_copyright (), cm_code (), cm_samp (), cm_file (), cm_kbd (),
+ cm_key (), cm_ctrl (), cm_var (), cm_dfn (), cm_emph (), cm_strong (),
+ cm_cite (), cm_italic (), cm_bold (), cm_roman (), cm_title (), cm_w (),
+ cm_refill (), cm_titlefont ();
+
+int
+ cm_chapter (), cm_unnumbered (), cm_appendix (), cm_top (),
+ cm_section (), cm_unnumberedsec (), cm_appendixsec (),
+ cm_subsection (), cm_unnumberedsubsec (), cm_appendixsubsec (),
+ cm_subsubsection (), cm_unnumberedsubsubsec (), cm_appendixsubsubsec (),
+ cm_heading (), cm_chapheading (), cm_subheading (), cm_subsubheading (),
+ cm_majorheading (), cm_raisesections (), cm_lowersections ();
+
+/* All @defxxx commands map to cm_defun (). */
+int cm_defun ();
+
+int
+ cm_node (), cm_menu (), cm_xref (), cm_ftable (), cm_vtable (), cm_pxref (),
+ cm_inforef (), cm_quotation (), cm_display (), cm_itemize (),
+ cm_enumerate (), cm_table (), cm_itemx (), cm_noindent (), cm_setfilename (),
+ cm_br (), cm_sp (), cm_page (), cm_group (), cm_center (), cm_include (),
+ cm_bye (), cm_item (), cm_end (), cm_infoinclude (), cm_ifinfo (),
+ cm_kindex (), cm_cindex (), cm_findex (), cm_pindex (), cm_vindex (),
+ cm_tindex (), cm_asis (), cm_synindex (), cm_printindex (), cm_minus (),
+ cm_footnote (), cm_force_abbreviated_whitespace (), cm_example (),
+ cm_smallexample (), cm_lisp (), cm_format (), cm_exdent (), cm_defindex (),
+ cm_defcodeindex (), cm_sc (), cm_result (), cm_expansion (), cm_equiv (),
+ cm_print (), cm_error (), cm_point (), cm_today (), cm_flushleft (),
+ cm_flushright (), cm_smalllisp (), cm_finalout (), cm_math (),
+ cm_cartouche (), cm_ignore_sentence_ender ();
+
+/* Conditionals. */
+int cm_set (), cm_clear (), cm_ifset (), cm_ifclear (), cm_value ();
+
+#if defined (HAVE_MACROS)
+/* Define a user-defined command which is simple substitution. */
+int cm_macro (), cm_unmacro ();
+#endif /* HAVE_MACROS */
+
+/* Options. */
+int cm_paragraphindent (), cm_footnotestyle ();
+
+/* Internals. */
+int do_nothing (), command_name_condition ();
+int misplaced_brace (), cm_obsolete ();
+
+typedef struct
+{
+ char *name;
+ FUNCTION *proc;
+ int argument_in_braces;
+} COMMAND;
+
+/* Stuff for defining commands on the fly. */
+COMMAND **user_command_array = (COMMAND **) NULL;
+int user_command_array_len = 0;
+
+#define NO_BRACE_ARGS 0
+#define BRACE_ARGS 1
+
+static COMMAND CommandTable[] = {
+ { "!", cm_ignore_sentence_ender, NO_BRACE_ARGS },
+ { "'", insert_self, NO_BRACE_ARGS },
+ { "*", cm_asterisk, NO_BRACE_ARGS },
+ { ".", cm_ignore_sentence_ender, NO_BRACE_ARGS },
+ { ":", cm_force_abbreviated_whitespace, NO_BRACE_ARGS },
+ { "?", cm_ignore_sentence_ender, NO_BRACE_ARGS },
+ { "|", do_nothing, NO_BRACE_ARGS },
+ { "@", insert_self, NO_BRACE_ARGS },
+ { " ", insert_self, NO_BRACE_ARGS },
+ { "\n", insert_self, NO_BRACE_ARGS },
+ { "TeX", cm_TeX, BRACE_ARGS },
+ { "`", insert_self, NO_BRACE_ARGS },
+ { "appendix", cm_appendix, NO_BRACE_ARGS },
+ { "appendixsection", cm_appendixsec, NO_BRACE_ARGS },
+ { "appendixsec", cm_appendixsec, NO_BRACE_ARGS },
+ { "appendixsubsec", cm_appendixsubsec, NO_BRACE_ARGS },
+ { "appendixsubsubsec", cm_appendixsubsubsec, NO_BRACE_ARGS },
+ { "asis", cm_asis, BRACE_ARGS },
+ { "b", cm_bold, BRACE_ARGS },
+ { "br", cm_br, NO_BRACE_ARGS },
+ { "bullet", cm_bullet, BRACE_ARGS },
+ { "bye", cm_bye, NO_BRACE_ARGS },
+ { "c", cm_ignore_line, NO_BRACE_ARGS },
+ { "cartouche", cm_cartouche, NO_BRACE_ARGS },
+ { "center", cm_center, NO_BRACE_ARGS },
+ { "chapheading", cm_chapheading, NO_BRACE_ARGS },
+ { "chapter", cm_chapter, NO_BRACE_ARGS },
+ { "cindex", cm_cindex, NO_BRACE_ARGS },
+ { "cite", cm_cite, BRACE_ARGS },
+ { "clear", cm_clear, NO_BRACE_ARGS },
+ { "code", cm_code, BRACE_ARGS },
+ { "comment", cm_ignore_line, NO_BRACE_ARGS },
+ { "contents", do_nothing, NO_BRACE_ARGS },
+ { "copyright", cm_copyright, BRACE_ARGS },
+ { "ctrl", cm_ctrl, BRACE_ARGS },
+ { "defcodeindex", cm_defcodeindex, NO_BRACE_ARGS },
+ { "defindex", cm_defindex, NO_BRACE_ARGS },
+ { "dfn", cm_dfn, BRACE_ARGS },
+
+/* The `def' commands. */
+ { "deffn", cm_defun, NO_BRACE_ARGS },
+ { "deffnx", cm_defun, NO_BRACE_ARGS },
+ { "defun", cm_defun, NO_BRACE_ARGS },
+ { "defunx", cm_defun, NO_BRACE_ARGS },
+ { "defmac", cm_defun, NO_BRACE_ARGS },
+ { "defmacx", cm_defun, NO_BRACE_ARGS },
+ { "defspec", cm_defun, NO_BRACE_ARGS },
+ { "defspecx", cm_defun, NO_BRACE_ARGS },
+ { "defvr", cm_defun, NO_BRACE_ARGS },
+ { "defvrx", cm_defun, NO_BRACE_ARGS },
+ { "defvar", cm_defun, NO_BRACE_ARGS },
+ { "defvarx", cm_defun, NO_BRACE_ARGS },
+ { "defopt", cm_defun, NO_BRACE_ARGS },
+ { "defoptx", cm_defun, NO_BRACE_ARGS },
+ { "deftypefn", cm_defun, NO_BRACE_ARGS },
+ { "deftypefnx", cm_defun, NO_BRACE_ARGS },
+ { "deftypefun", cm_defun, NO_BRACE_ARGS },
+ { "deftypefunx", cm_defun, NO_BRACE_ARGS },
+ { "deftypevr", cm_defun, NO_BRACE_ARGS },
+ { "deftypevrx", cm_defun, NO_BRACE_ARGS },
+ { "deftypevar", cm_defun, NO_BRACE_ARGS },
+ { "deftypevarx", cm_defun, NO_BRACE_ARGS },
+ { "defcv", cm_defun, NO_BRACE_ARGS },
+ { "defcvx", cm_defun, NO_BRACE_ARGS },
+ { "defivar", cm_defun, NO_BRACE_ARGS },
+ { "defivarx", cm_defun, NO_BRACE_ARGS },
+ { "defop", cm_defun, NO_BRACE_ARGS },
+ { "defopx", cm_defun, NO_BRACE_ARGS },
+ { "defmethod", cm_defun, NO_BRACE_ARGS },
+ { "defmethodx", cm_defun, NO_BRACE_ARGS },
+ { "deftypemethod", cm_defun, NO_BRACE_ARGS },
+ { "deftypemethodx", cm_defun, NO_BRACE_ARGS },
+ { "deftp", cm_defun, NO_BRACE_ARGS },
+ { "deftpx", cm_defun, NO_BRACE_ARGS },
+/* The end of the `def' commands. */
+
+ { "display", cm_display, NO_BRACE_ARGS },
+ { "dots", cm_dots, BRACE_ARGS },
+ { "dmn", do_nothing, BRACE_ARGS },
+ { "emph", cm_emph, BRACE_ARGS },
+ { "end", cm_end, NO_BRACE_ARGS },
+ { "enumerate", cm_enumerate, NO_BRACE_ARGS },
+ { "equiv", cm_equiv, BRACE_ARGS },
+ { "error", cm_error, BRACE_ARGS },
+ { "example", cm_example, NO_BRACE_ARGS },
+ { "exdent", cm_exdent, NO_BRACE_ARGS },
+ { "expansion", cm_expansion, BRACE_ARGS },
+ { "file", cm_file, BRACE_ARGS },
+ { "findex", cm_findex, NO_BRACE_ARGS },
+ { "finalout", do_nothing, NO_BRACE_ARGS },
+ { "flushleft", cm_flushleft, NO_BRACE_ARGS },
+ { "flushright", cm_flushright, NO_BRACE_ARGS },
+ { "format", cm_format, NO_BRACE_ARGS },
+ { "ftable", cm_ftable, NO_BRACE_ARGS },
+ { "group", cm_group, NO_BRACE_ARGS },
+ { "heading", cm_heading, NO_BRACE_ARGS },
+ { "headings", cm_ignore_line, NO_BRACE_ARGS },
+ { "i", cm_italic, BRACE_ARGS },
+ { "iappendix", cm_appendix, NO_BRACE_ARGS },
+ { "iappendixsection", cm_appendixsec, NO_BRACE_ARGS },
+ { "iappendixsec", cm_appendixsec, NO_BRACE_ARGS },
+ { "iappendixsubsec", cm_appendixsubsec, NO_BRACE_ARGS },
+ { "iappendixsubsubsec", cm_appendixsubsubsec, NO_BRACE_ARGS },
+ { "ichapter", cm_chapter, NO_BRACE_ARGS },
+ { "ifclear", cm_ifclear, NO_BRACE_ARGS },
+ { "ifinfo", cm_ifinfo, NO_BRACE_ARGS },
+ { "ifset", cm_ifset, NO_BRACE_ARGS },
+ { "iftex", command_name_condition, NO_BRACE_ARGS },
+ { "ignore", command_name_condition, NO_BRACE_ARGS },
+ { "include", cm_include, NO_BRACE_ARGS },
+ { "inforef", cm_inforef, BRACE_ARGS },
+ { "input", cm_include, NO_BRACE_ARGS },
+ { "isection", cm_section, NO_BRACE_ARGS },
+ { "isubsection", cm_subsection, NO_BRACE_ARGS },
+ { "isubsubsection", cm_subsubsection, NO_BRACE_ARGS },
+ { "item", cm_item, NO_BRACE_ARGS },
+ { "itemize", cm_itemize, NO_BRACE_ARGS },
+ { "itemx", cm_itemx, NO_BRACE_ARGS },
+ { "iunnumbered", cm_unnumbered, NO_BRACE_ARGS },
+ { "iunnumberedsec", cm_unnumberedsec, NO_BRACE_ARGS },
+ { "iunnumberedsubsec", cm_unnumberedsubsec, NO_BRACE_ARGS },
+ { "iunnumberedsubsubsec", cm_unnumberedsubsubsec, NO_BRACE_ARGS },
+ { "kbd", cm_kbd, BRACE_ARGS },
+ { "key", cm_key, BRACE_ARGS },
+ { "kindex", cm_kindex, NO_BRACE_ARGS },
+ { "lowersections", cm_lowersections, NO_BRACE_ARGS },
+ { "lisp", cm_lisp, NO_BRACE_ARGS },
+ { "macro", cm_macro, NO_BRACE_ARGS },
+ { "majorheading", cm_majorheading, NO_BRACE_ARGS },
+ { "math", cm_math, BRACE_ARGS },
+ { "menu", cm_menu, NO_BRACE_ARGS },
+ { "minus", cm_minus, BRACE_ARGS },
+ { "need", cm_ignore_line, NO_BRACE_ARGS },
+ { "node", cm_node, NO_BRACE_ARGS },
+ { "noindent", cm_noindent, NO_BRACE_ARGS },
+ { "nwnode", cm_node, NO_BRACE_ARGS },
+ { "overfullrule", cm_ignore_line, NO_BRACE_ARGS },
+ { "page", do_nothing, NO_BRACE_ARGS },
+ { "pindex", cm_pindex, NO_BRACE_ARGS },
+ { "point", cm_point, BRACE_ARGS },
+ { "print", cm_print, BRACE_ARGS },
+ { "printindex", cm_printindex, NO_BRACE_ARGS },
+ { "pxref", cm_pxref, BRACE_ARGS },
+ { "quotation", cm_quotation, NO_BRACE_ARGS },
+ { "r", cm_roman, BRACE_ARGS },
+ { "raisesections", cm_raisesections, NO_BRACE_ARGS },
+ { "ref", cm_xref, BRACE_ARGS },
+ { "refill", cm_refill, NO_BRACE_ARGS },
+ { "result", cm_result, BRACE_ARGS },
+ { "samp", cm_samp, BRACE_ARGS },
+ { "sc", cm_sc, BRACE_ARGS },
+ { "section", cm_section, NO_BRACE_ARGS },
+ { "set", cm_set, NO_BRACE_ARGS },
+ { "setchapternewpage", cm_ignore_line, NO_BRACE_ARGS },
+ { "setchapterstyle", cm_ignore_line, NO_BRACE_ARGS },
+ { "setfilename", cm_setfilename, NO_BRACE_ARGS },
+ { "settitle", cm_ignore_line, NO_BRACE_ARGS },
+ { "shortcontents", do_nothing, NO_BRACE_ARGS },
+ { "shorttitlepage", command_name_condition, NO_BRACE_ARGS },
+ { "smallbook", cm_ignore_line, NO_BRACE_ARGS },
+ { "smallexample", cm_smallexample, NO_BRACE_ARGS },
+ { "smalllisp", cm_smalllisp, NO_BRACE_ARGS },
+ { "sp", cm_sp, NO_BRACE_ARGS },
+ { "strong", cm_strong, BRACE_ARGS },
+ { "subheading", cm_subheading, NO_BRACE_ARGS },
+ { "subsection", cm_subsection, NO_BRACE_ARGS },
+ { "subsubheading", cm_subsubheading, NO_BRACE_ARGS },
+ { "subsubsection", cm_subsubsection, NO_BRACE_ARGS },
+ { "summarycontents", do_nothing, NO_BRACE_ARGS },
+ { "syncodeindex", cm_synindex, NO_BRACE_ARGS },
+ { "synindex", cm_synindex, NO_BRACE_ARGS },
+ { "t", cm_title, BRACE_ARGS },
+ { "table", cm_table, NO_BRACE_ARGS },
+ { "tex", command_name_condition, NO_BRACE_ARGS },
+ { "tindex", cm_tindex, NO_BRACE_ARGS },
+ { "titlefont", cm_titlefont, BRACE_ARGS },
+ { "titlepage", command_name_condition, NO_BRACE_ARGS },
+ { "titlespec", command_name_condition, NO_BRACE_ARGS },
+ { "today", cm_today, BRACE_ARGS },
+ { "top", cm_top, NO_BRACE_ARGS },
+ { "unmacro", cm_unmacro, NO_BRACE_ARGS },
+ { "unnumbered", cm_unnumbered, NO_BRACE_ARGS },
+ { "unnumberedsec", cm_unnumberedsec, NO_BRACE_ARGS },
+ { "unnumberedsubsec", cm_unnumberedsubsec, NO_BRACE_ARGS },
+ { "unnumberedsubsubsec", cm_unnumberedsubsubsec, NO_BRACE_ARGS },
+ { "value", cm_value, BRACE_ARGS },
+ { "var", cm_var, BRACE_ARGS },
+ { "vindex", cm_vindex, NO_BRACE_ARGS },
+ { "vtable", cm_vtable, NO_BRACE_ARGS },
+ { "w", cm_w, BRACE_ARGS },
+ { "xref", cm_xref, BRACE_ARGS },
+ { "{", insert_self, NO_BRACE_ARGS },
+ { "}", insert_self, NO_BRACE_ARGS },
+
+ /* Some obsoleted commands. */
+ { "infotop", cm_obsolete, NO_BRACE_ARGS },
+ { "infounnumbered", cm_obsolete, NO_BRACE_ARGS },
+ { "infounnumberedsec", cm_obsolete, NO_BRACE_ARGS },
+ { "infounnumberedsubsec", cm_obsolete, NO_BRACE_ARGS },
+ { "infounnumberedsubsubsec", cm_obsolete, NO_BRACE_ARGS },
+ { "infoappendix", cm_obsolete, NO_BRACE_ARGS },
+ { "infoappendixsec", cm_obsolete, NO_BRACE_ARGS },
+ { "infoappendixsubsec", cm_obsolete, NO_BRACE_ARGS },
+ { "infoappendixsubsubsec", cm_obsolete, NO_BRACE_ARGS },
+ { "infochapter", cm_obsolete, NO_BRACE_ARGS },
+ { "infosection", cm_obsolete, NO_BRACE_ARGS },
+ { "infosubsection", cm_obsolete, NO_BRACE_ARGS },
+ { "infosubsubsection", cm_obsolete, NO_BRACE_ARGS },
+
+ /* Now @include does what this was supposed to. */
+ { "infoinclude", cm_infoinclude, NO_BRACE_ARGS },
+ { "footnote", cm_footnote, NO_BRACE_ARGS}, /* self-arg eater */
+ { "footnotestyle", cm_footnotestyle, NO_BRACE_ARGS },
+ { "paragraphindent", cm_paragraphindent, NO_BRACE_ARGS },
+
+ {(char *) NULL, (FUNCTION *) NULL}, NO_BRACE_ARGS};
+
+int major_version = 1;
+int minor_version = 55;
+
+struct option long_options[] =
+{
+ { "error-limit", 1, 0, 'e' }, /* formerly -el */
+ { "fill-column", 1, 0, 'f' }, /* formerly -fc */
+ { "footnote-style", 1, 0, 's' }, /* formerly -ft */
+ { "no-headers", 0, &no_headers, 1 }, /* Do not output Node: foo */
+ { "no-pointer-validate", 0, &validating, 0 }, /* formerly -nv */
+ { "no-validate", 0, &validating, 0 }, /* formerly -nv */
+ { "no-split", 0, &splitting, 0 }, /* formerly -ns */
+ { "no-warn", 0, &print_warnings, 0 }, /* formerly -nw */
+ { "number-footnotes", 0, &number_footnotes, 1 },
+ { "no-number-footnotes", 0, &number_footnotes, 0 },
+ { "output", 1, 0, 'o' },
+ { "paragraph-indent", 1, 0, 'p' }, /* formerly -pi */
+ { "reference-limit", 1, 0, 'r' }, /* formerly -rl */
+ { "verbose", 0, &verbose_mode, 1 }, /* formerly -verbose */
+ { "version", 0, 0, 'V' },
+ {NULL, 0, NULL, 0}
+};
+
+/* Values for calling handle_variable_internal (). */
+#define SET 1
+#define CLEAR 2
+#define IFSET 3
+#define IFCLEAR 4
+
+/* **************************************************************** */
+/* */
+/* Main () Start of code */
+/* */
+/* **************************************************************** */
+
+/* For each file mentioned in the command line, process it, turning
+ texinfo commands into wonderfully formatted output text. */
+main (argc, argv)
+ int argc;
+ char **argv;
+{
+ extern int errors_printed;
+ char *filename_part ();
+ int c, ind;
+
+ /* The name of this program is the last filename in argv[0]. */
+ progname = filename_part (argv[0]);
+
+ /* Parse argument flags from the input line. */
+ while ((c = getopt_long
+ (argc, argv, "D:U:I:f:o:p:e:r:s:V", long_options, &ind))
+ != EOF)
+ {
+ if (c == 0 && long_options[ind].flag == 0)
+ c = long_options[ind].val;
+
+ switch (c)
+ {
+ /* User specified variable to set or clear? */
+ case 'D':
+ case 'U':
+ handle_variable_internal ((c == 'D') ? SET : CLEAR, optarg);
+ break;
+
+ /* User specified include file path? */
+ case 'I':
+ if (!include_files_path)
+ include_files_path = savestring (".");
+
+ include_files_path = (char *)
+ xrealloc (include_files_path,
+ 2 + strlen (include_files_path) + strlen (optarg));
+ strcat (include_files_path, ":");
+ strcat (include_files_path, optarg);
+ break;
+
+ /* User specified fill_column? */
+ case 'f':
+ if (sscanf (optarg, "%d", &fill_column) != 1)
+ usage ();
+ break;
+
+ /* User specified output file? */
+ case 'o':
+ command_output_filename = savestring (optarg);
+ break;
+
+ /* User specified paragraph indent (paragraph_start_index)? */
+ case 'p':
+ if (set_paragraph_indent (optarg) < 0)
+ usage ();
+ break;
+
+ /* User specified error level? */
+ case 'e':
+ if (sscanf (optarg, "%d", &max_error_level) != 1)
+ usage ();
+ break;
+
+ /* User specified reference warning limit? */
+ case 'r':
+ if (sscanf (optarg, "%d", &reference_warning_limit) != 1)
+ usage ();
+ break;
+
+ /* User specified footnote style? */
+ case 's':
+ if (set_footnote_style (optarg) < 0)
+ usage ();
+ footnote_style_preset = 1;
+ break;
+
+ /* User requested version info? */
+ case 'V':
+ print_version_info ();
+ exit (NO_ERROR);
+ break;
+
+ case '?':
+ usage ();
+ }
+ }
+
+ if (optind == argc)
+ usage ();
+ else if (verbose_mode)
+ print_version_info ();
+
+ /* Remaining arguments are file names of texinfo files.
+ Convert them, one by one. */
+ while (optind != argc)
+ convert (argv[optind++]);
+
+ if (errors_printed)
+ exit (SYNTAX);
+ else
+ exit (NO_ERROR);
+}
+
+/* Display the version info of this invocation of Makeinfo. */
+print_version_info ()
+{
+ fprintf (stderr, "This is GNU Makeinfo version %d.%d.\n",
+ major_version, minor_version);
+}
+
+/* **************************************************************** */
+/* */
+/* Generic Utilities */
+/* */
+/* **************************************************************** */
+
+/* Just like malloc, but kills the program in case of fatal error. */
+void *
+xmalloc (nbytes)
+ int nbytes;
+{
+ void *temp = (void *) malloc (nbytes);
+
+ if (nbytes && temp == (void *)NULL)
+ memory_error ("xmalloc", nbytes);
+
+ return (temp);
+}
+
+/* Like realloc (), but barfs if there isn't enough memory. */
+void *
+xrealloc (pointer, nbytes)
+ void *pointer;
+ int nbytes;
+{
+ void *temp;
+
+ if (!pointer)
+ temp = (void *)xmalloc (nbytes);
+ else
+ temp = (void *)realloc (pointer, nbytes);
+
+ if (nbytes && !temp)
+ memory_error ("xrealloc", nbytes);
+
+ return (temp);
+}
+
+memory_error (callers_name, bytes_wanted)
+ char *callers_name;
+ int bytes_wanted;
+{
+ char printable_string[80];
+
+ sprintf (printable_string,
+ "Virtual memory exhausted in %s ()! Needed %d bytes.",
+ callers_name, bytes_wanted);
+
+ error (printable_string);
+ abort ();
+}
+
+/* Tell the user how to use this program. */
+usage ()
+{
+ fprintf (stderr, "Usage: %s [options] texinfo-file...\n\
+\n\
+This program accepts as input files of texinfo commands and text\n\
+and outputs a file suitable for reading with GNU Info.\n\
+\n\
+The options are:\n\
+`-I DIR' to add DIR to the directory search list for including\n\
+ files with the `@include' command.\n\
+-D VAR to define a variable, as with `@set'.\n\
+-U VAR to undefine a variable, as with `@clear'.\n\
+`--no-validate' to suppress node cross reference validation.\n\
+`--no-warn' to suppress warning messages (errors are still output).\n\
+`--no-split' to suppress the splitting of large files.\n\
+`--no-headers' to suppress the output of Node: Foo headers.\n\
+`--verbose' to print information about what is being done.\n\
+`--version' to print the version number of Makeinfo.\n\
+`--output FILE' or `-o FILE'\n\
+ to specify the output file. When you specify the\n\
+ output file in this way, any `@setfilename' in the\n\
+ input file is ignored.\n\
+`--paragraph-indent NUM'\n\
+ to set the paragraph indent to NUM (default %d).\n\
+`--fill-column NUM' to set the filling column to NUM (default %d).\n\
+`--error-limit NUM' to set the error limit to NUM (default %d).\n\
+`--reference-limit NUM'\n\
+ to set the reference warning limit to NUM (default %d).\n\
+`--footnote-style STYLE'\n\
+ to set the footnote style to STYLE. STYLE should\n\
+ either be `separate' to place footnotes in their own\n\
+ node, or `end', to place the footnotes at the end of\n\
+ the node in which they are defined (the default).\n\n",
+ progname, paragraph_start_indent,
+ fill_column, max_error_level, reference_warning_limit);
+ exit (FATAL);
+}
+
+/* **************************************************************** */
+/* */
+/* Manipulating Lists */
+/* */
+/* **************************************************************** */
+
+typedef struct generic_list {
+ struct generic_list *next;
+} GENERIC_LIST;
+
+/* Reverse the chain of structures in LIST. Output the new head
+ of the chain. You should always assign the output value of this
+ function to something, or you will lose the chain. */
+GENERIC_LIST *
+reverse_list (list)
+ register GENERIC_LIST *list;
+{
+ register GENERIC_LIST *next;
+ register GENERIC_LIST *prev = (GENERIC_LIST *) NULL;
+
+ while (list)
+ {
+ next = list->next;
+ list->next = prev;
+ prev = list;
+ list = next;
+ }
+ return (prev);
+}
+
+
+/* **************************************************************** */
+/* */
+/* Pushing and Popping Files */
+/* */
+/* **************************************************************** */
+
+/* Find and load the file named FILENAME. Return a pointer to
+ the loaded file, or NULL if it can't be loaded. */
+char *
+find_and_load (filename)
+ char *filename;
+{
+ struct stat fileinfo;
+ int file = -1, n, i, count = 0;
+ char *fullpath, *result, *get_file_info_in_path ();
+
+ result = fullpath = (char *)NULL;
+
+ fullpath = get_file_info_in_path (filename, include_files_path, &fileinfo);
+
+ if (!fullpath)
+ goto error_exit;
+
+ filename = fullpath;
+
+ file = open (filename, O_RDONLY);
+ if (file < 0)
+ goto error_exit;
+
+ /* Load the file. */
+ result = (char *)xmalloc (1 + fileinfo.st_size);
+
+ /* VMS stat lies about the st_size value. The actual number of
+ readable bytes is always less than this value. The arcane
+ mysteries of VMS/RMS are too much to probe, so this hack
+ suffices to make things work. */
+#if defined (VMS)
+ while ((n = read (file, result + count, fileinfo.st_size)) > 0)
+ count += n;
+ if (n == -1)
+#else /* !VMS */
+ count = fileinfo.st_size;
+ if (read (file, result, fileinfo.st_size) != fileinfo.st_size)
+#endif /* !VMS */
+ error_exit:
+ {
+ if (result)
+ free (result);
+
+ if (fullpath)
+ free (fullpath);
+
+ if (file != -1)
+ close (file);
+
+ return ((char *) NULL);
+ }
+ close (file);
+
+ /* Set the globals to the new file. */
+ input_text = result;
+ size_of_input_text = count;
+ input_filename = savestring (fullpath);
+ node_filename = savestring (fullpath);
+ input_text_offset = 0;
+ line_number = 1;
+ /* Not strictly necessary. This magic prevents read_token () from doing
+ extra unnecessary work each time it is called (that is a lot of times).
+ The SIZE_OF_INPUT_TEXT is one past the actual end of the text. */
+ input_text[size_of_input_text] = '\n';
+ return (result);
+}
+
+/* Save the state of the current input file. */
+pushfile ()
+{
+ FSTACK *newstack = (FSTACK *) xmalloc (sizeof (FSTACK));
+ newstack->filename = input_filename;
+ newstack->text = input_text;
+ newstack->size = size_of_input_text;
+ newstack->offset = input_text_offset;
+ newstack->line_number = line_number;
+ newstack->next = filestack;
+
+ filestack = newstack;
+ push_node_filename ();
+}
+
+/* Make the current file globals be what is on top of the file stack. */
+popfile ()
+{
+ extern int executing_string;
+ FSTACK *temp = filestack;
+
+ if (!filestack)
+ abort (); /* My fault. I wonder what I did? */
+
+ /* Make sure that commands with braces have been satisfied. */
+ if (!executing_string)
+ discard_braces ();
+
+ /* Get the top of the stack into the globals. */
+ input_filename = filestack->filename;
+ input_text = filestack->text;
+ size_of_input_text = filestack->size;
+ input_text_offset = filestack->offset;
+ line_number = filestack->line_number;
+
+ /* Pop the stack. */
+ filestack = filestack->next;
+ free (temp);
+ pop_node_filename ();
+}
+
+/* Flush all open files on the file stack. */
+flush_file_stack ()
+{
+ while (filestack)
+ {
+ free (input_filename);
+ free (input_text);
+ popfile ();
+ }
+}
+
+int node_filename_stack_index = 0;
+int node_filename_stack_size = 0;
+char **node_filename_stack = (char **)NULL;
+
+push_node_filename ()
+{
+ if (node_filename_stack_index + 1 > node_filename_stack_size)
+ {
+ if (!node_filename_stack)
+ node_filename_stack =
+ (char **)xmalloc ((node_filename_stack_size += 10)
+ * sizeof (char *));
+ else
+ node_filename_stack =
+ (char **)xrealloc (node_filename_stack,
+ (node_filename_stack_size + 10)
+ * sizeof (char *));
+ }
+
+ node_filename_stack[node_filename_stack_index] = node_filename;
+ node_filename_stack_index++;
+}
+
+pop_node_filename ()
+{
+ node_filename = node_filename_stack[--node_filename_stack_index];
+}
+
+/* Return just the simple part of the filename; i.e. the
+ filename without the path information, or extensions.
+ This conses up a new string. */
+char *
+filename_part (filename)
+ char *filename;
+{
+ char *basename;
+
+ basename = strrchr (filename, '/');
+ if (!basename)
+ basename = filename;
+ else
+ basename++;
+
+ basename = savestring (basename);
+#if defined (REMOVE_OUTPUT_EXTENSIONS)
+
+ /* See if there is an extension to remove. If so, remove it. */
+ {
+ char *temp;
+
+ temp = strrchr (basename, '.');
+ if (temp)
+ *temp = '\0';
+ }
+#endif /* REMOVE_OUTPUT_EXTENSIONS */
+ return (basename);
+}
+
+/* Return the pathname part of filename. This can be NULL. */
+char *
+pathname_part (filename)
+ char *filename;
+{
+ char *expand_filename ();
+ char *result = (char *) NULL;
+ register int i;
+
+ filename = expand_filename (filename, "");
+
+ i = strlen (filename) - 1;
+
+ while (i && filename[i] != '/')
+ i--;
+ if (filename[i] == '/')
+ i++;
+
+ if (i)
+ {
+ result = (char *)xmalloc (1 + i);
+ strncpy (result, filename, i);
+ result[i] = '\0';
+ }
+ free (filename);
+ return (result);
+}
+
+/* Return the expansion of FILENAME. */
+char *
+expand_filename (filename, input_name)
+ char *filename, *input_name;
+{
+ char *full_pathname ();
+ filename = full_pathname (filename);
+
+ if (filename[0] == '.')
+ return (filename);
+
+ if (filename[0] != '/' && input_name[0] == '/')
+ {
+ /* Make it so that relative names work. */
+ char *result;
+ int i = strlen (input_name) - 1;
+
+ result = (char *)xmalloc (1 + strlen (input_name) + strlen (filename));
+ strcpy (result, input_name);
+
+ while (result[i] != '/' && i)
+ i--;
+
+ if (result[i] == '/')
+ i++;
+
+ strcpy (&result[i], filename);
+ free (filename);
+ return (result);
+ }
+ return (filename);
+}
+
+/* Return the full path to FILENAME. */
+char *
+full_pathname (filename)
+ char *filename;
+{
+ int initial_character;
+
+ if (filename && (initial_character = *filename))
+ {
+ if (initial_character == '/')
+ return (savestring (filename));
+ if (initial_character != '~')
+ {
+ return (savestring (filename));
+ }
+ else
+ {
+ if (filename[1] == '/')
+ {
+ /* Return the concatenation of HOME and the rest of the string. */
+ char *temp_home;
+ char *temp_name;
+
+ temp_home = (char *) getenv ("HOME");
+ temp_name = (char *)xmalloc (strlen (&filename[2])
+ + 1
+ + temp_home ? strlen (temp_home)
+ : 0);
+ if (temp_home)
+ strcpy (temp_name, temp_home);
+
+ strcat (temp_name, &filename[2]);
+ return (temp_name);
+ }
+ else
+ {
+ struct passwd *user_entry;
+ int i, c;
+ char *username = (char *)xmalloc (257);
+ char *temp_name;
+
+ for (i = 1; c = filename[i]; i++)
+ {
+ if (c == '/')
+ break;
+ else
+ username[i - 1] = c;
+ }
+ if (c)
+ username[i - 1] = '\0';
+
+ user_entry = getpwnam (username);
+
+ if (!user_entry)
+ return (savestring (filename));
+
+ temp_name = (char *)xmalloc (1 + strlen (user_entry->pw_dir)
+ + strlen (&filename[i]));
+ strcpy (temp_name, user_entry->pw_dir);
+ strcat (temp_name, &filename[i]);
+ return (temp_name);
+ }
+ }
+ }
+ else
+ {
+ return (savestring (filename));
+ }
+}
+
+/* **************************************************************** */
+/* */
+/* Error Handling */
+/* */
+/* **************************************************************** */
+
+/* Number of errors encountered. */
+int errors_printed = 0;
+
+/* Print the last error gotten from the file system. */
+fs_error (filename)
+ char *filename;
+{
+ remember_error ();
+ perror (filename);
+ return (0);
+}
+
+/* Print an error message, and return false. */
+#if defined (HAVE_VARARGS_H) && defined (HAVE_VFPRINTF)
+
+int
+error (va_alist)
+ va_dcl
+{
+ char *format;
+ va_list args;
+
+ remember_error ();
+ va_start (args);
+ format = va_arg (args, char *);
+ vfprintf (stderr, format, args);
+ va_end (args);
+ fprintf (stderr, "\n");
+}
+
+/* Just like error (), but print the line number as well. */
+int
+line_error (va_alist)
+ va_dcl
+{
+ char *format;
+ va_list args;
+
+ remember_error ();
+ va_start (args);
+ format = va_arg (args, char *);
+ fprintf (stderr, "%s:%d: ", input_filename, line_number);
+ vfprintf (stderr, format, args);
+ fprintf (stderr, ".\n");
+ va_end (args);
+ return ((int) 0);
+}
+
+int
+warning (va_alist)
+ va_dcl
+{
+ char *format;
+ va_list args;
+
+ va_start (args);
+ format = va_arg (args, char *);
+ if (print_warnings)
+ {
+ fprintf (stderr, "%s:%d: Warning: ", input_filename, line_number);
+ vfprintf (stderr, format, args);
+ fprintf (stderr, ".\n");
+ }
+ va_end (args);
+ return ((int) 0);
+}
+
+#else /* !(HAVE_VARARGS_H && HAVE_VFPRINTF) */
+
+int
+error (format, arg1, arg2, arg3, arg4, arg5)
+ char *format;
+{
+ remember_error ();
+ fprintf (stderr, format, arg1, arg2, arg3, arg4, arg5);
+ fprintf (stderr, "\n");
+ return ((int) 0);
+}
+
+/* Just like error (), but print the line number as well. */
+int
+line_error (format, arg1, arg2, arg3, arg4, arg5)
+ char *format;
+{
+ remember_error ();
+ fprintf (stderr, "%s:%d: ", input_filename, line_number);
+ fprintf (stderr, format, arg1, arg2, arg3, arg4, arg5);
+ fprintf (stderr, ".\n");
+ return ((int) 0);
+}
+
+int
+warning (format, arg1, arg2, arg3, arg4, arg5)
+ char *format;
+{
+ if (print_warnings)
+ {
+ fprintf (stderr, "%s:%d: Warning: ", input_filename, line_number);
+ fprintf (stderr, format, arg1, arg2, arg3, arg4, arg5);
+ fprintf (stderr, ".\n");
+ }
+ return ((int) 0);
+}
+
+#endif /* !(HAVE_VARARGS_H && HAVE_VFPRINTF) */
+
+/* Remember that an error has been printed. If this is the first
+ error printed, then tell them which program is printing them.
+ If more than max_error_level have been printed, then exit the
+ program. */
+remember_error ()
+{
+ errors_printed++;
+ if (max_error_level && (errors_printed > max_error_level))
+ {
+ fprintf (stderr, "Too many errors! Gave up.\n");
+ flush_file_stack ();
+ cm_bye ();
+ exit (1);
+ }
+}
+
+/* **************************************************************** */
+/* */
+/* Hacking Tokens and Strings */
+/* */
+/* **************************************************************** */
+
+/* Return the next token as a string pointer. We cons the
+ string. */
+char *
+read_token ()
+{
+ int i, character;
+ char *result;
+
+ /* If the first character to be read is self-delimiting, then that
+ is the command itself. */
+ character = curchar ();
+ if (self_delimiting (character))
+ {
+ input_text_offset++;
+ result = savestring (" ");
+ *result = character;
+ return (result);
+ }
+
+ for (i = 0; ((input_text_offset != size_of_input_text)
+ && (character = curchar ())
+ && command_char (character));
+ i++, input_text_offset++);
+ result = (char *)xmalloc (i + 1);
+ memcpy (result, &input_text[input_text_offset - i], i);
+ result[i] = '\0';
+ return (result);
+}
+
+/* Return non-zero if CHARACTER is self-delimiting. */
+int
+self_delimiting (character)
+ int character;
+{
+ return (member (character, "{}:.@*'`,!?; \n"));
+}
+
+/* Clear whitespace from the front and end of string. */
+canon_white (string)
+ char *string;
+{
+ int len = strlen (string);
+ int x;
+
+ if (!len)
+ return;
+
+ for (x = 0; x < len; x++)
+ {
+ if (!cr_or_whitespace (string[x]))
+ {
+ strcpy (string, string + x);
+ break;
+ }
+ }
+ len = strlen (string);
+ if (len)
+ len--;
+ while (len > -1 && cr_or_whitespace (string[len]))
+ len--;
+ string[len + 1] = '\0';
+}
+
+/* Bash STRING, replacing all whitespace with just one space. */
+fix_whitespace (string)
+ char *string;
+{
+ char *temp = (char *)xmalloc (strlen (string) + 1);
+ int string_index = 0;
+ int temp_index = 0;
+ int c;
+
+ canon_white (string);
+
+ while (string[string_index])
+ {
+ c = temp[temp_index++] = string[string_index++];
+
+ if (c == ' ' || c == '\n' || c == '\t')
+ {
+ temp[temp_index - 1] = ' ';
+ while ((c = string[string_index]) && (c == ' ' ||
+ c == '\t' ||
+ c == '\n'))
+ string_index++;
+ }
+ }
+ temp[temp_index] = '\0';
+ strcpy (string, temp);
+ free (temp);
+}
+
+/* Discard text until the desired string is found. The string is
+ included in the discarded text. */
+discard_until (string)
+ char *string;
+{
+ int temp = search_forward (string, input_text_offset);
+
+ int tt = (temp < 0) ? size_of_input_text : temp + strlen (string);
+ int from = input_text_offset;
+
+ /* Find out what line we are on. */
+ while (from != tt)
+ if (input_text[from++] == '\n')
+ line_number++;
+
+ if (temp < 0)
+ {
+ input_text_offset = size_of_input_text - strlen (string);
+
+ if (strcmp (string, "\n") != 0)
+ {
+ line_error ("Expected `%s'", string);
+ return;
+ }
+ }
+ else
+ input_text_offset = temp;
+
+ input_text_offset += strlen (string);
+}
+
+/* Read characters from the file until we are at MATCH.
+ Place the characters read into STRING.
+ On exit input_text_offset is after the match string.
+ Return the offset where the string starts. */
+int
+get_until (match, string)
+ char *match, **string;
+{
+ int len, current_point, x, new_point, tem;
+
+ current_point = x = input_text_offset;
+ new_point = search_forward (match, input_text_offset);
+
+ if (new_point < 0)
+ new_point = size_of_input_text;
+ len = new_point - current_point;
+
+ /* Keep track of which line number we are at. */
+ tem = new_point + (strlen (match) - 1);
+ while (x != tem)
+ if (input_text[x++] == '\n')
+ line_number++;
+
+ *string = (char *)xmalloc (len + 1);
+
+ memcpy (*string, &input_text[current_point], len);
+ (*string)[len] = '\0';
+
+ /* Now leave input_text_offset in a consistent state. */
+ input_text_offset = tem;
+
+ if (input_text_offset > size_of_input_text)
+ input_text_offset = size_of_input_text;
+
+ return (new_point);
+}
+
+/* Read characters from the file until we are at MATCH or end of line.
+ Place the characters read into STRING. */
+get_until_in_line (match, string)
+ char *match, **string;
+{
+ int real_bottom, temp;
+
+ real_bottom = size_of_input_text;
+ temp = search_forward ("\n", input_text_offset);
+
+ if (temp < 0)
+ temp = size_of_input_text;
+
+ size_of_input_text = temp;
+ get_until (match, string);
+ size_of_input_text = real_bottom;
+}
+
+get_rest_of_line (string)
+ char **string;
+{
+ get_until ("\n", string);
+ canon_white (*string);
+
+ if (curchar () == '\n') /* as opposed to the end of the file... */
+ {
+ line_number++;
+ input_text_offset++;
+ }
+}
+
+/* Backup the input pointer to the previous character, keeping track
+ of the current line number. */
+backup_input_pointer ()
+{
+ if (input_text_offset)
+ {
+ input_text_offset--;
+ if (curchar () == '\n')
+ line_number--;
+ }
+}
+
+/* Read characters from the file until we are at MATCH or closing brace.
+ Place the characters read into STRING. */
+get_until_in_braces (match, string)
+ char *match, **string;
+{
+ int i, brace = 0;
+ int match_len = strlen (match);
+ char *temp;
+
+ for (i = input_text_offset; i < size_of_input_text; i++)
+ {
+ if (input_text[i] == '{')
+ brace++;
+ else if (input_text[i] == '}')
+ brace--;
+ else if (input_text[i] == '\n')
+ line_number++;
+
+ if (brace < 0 ||
+ (brace == 0 && strncmp (input_text + i, match, match_len) == 0))
+ break;
+ }
+
+ match_len = i - input_text_offset;
+ temp = (char *)xmalloc (2 + match_len);
+ strncpy (temp, input_text + input_text_offset, match_len);
+ temp[match_len] = '\0';
+ input_text_offset = i;
+ *string = temp;
+}
+
+/* **************************************************************** */
+/* */
+/* Converting the File */
+/* */
+/* **************************************************************** */
+
+/* Convert the file named by NAME. The output is saved on the file
+ named as the argument to the @setfilename command. */
+static char *suffixes[] = {
+ "",
+ ".texinfo",
+ ".texi",
+ ".txinfo",
+ (char *)NULL
+};
+
+convert (name)
+ char *name;
+{
+ char *real_output_filename, *expand_filename (), *filename_part ();
+ char *filename = (char *)xmalloc (strlen (name) + 50);
+ register int i;
+
+ init_tag_table ();
+ init_indices ();
+ init_internals ();
+ init_paragraph ();
+
+ /* Try to load the file specified by NAME. If the file isn't found, and
+ there is no suffix in NAME, then try NAME.texinfo, and NAME.texi. */
+ for (i = 0; suffixes[i]; i++)
+ {
+ strcpy (filename, name);
+ strcat (filename, suffixes[i]);
+
+ if (find_and_load (filename))
+ break;
+
+ if (!suffixes[i][0] && strrchr (filename, '.'))
+ {
+ fs_error (filename);
+ free (filename);
+ return;
+ }
+ }
+
+ if (!suffixes[i])
+ {
+ fs_error (name);
+ free (filename);
+ return;
+ }
+
+ input_filename = filename;
+
+ /* Search this file looking for the special string which starts conversion.
+ Once found, we may truly begin. */
+
+ input_text_offset = search_forward ("@setfilename", 0);
+
+ if (input_text_offset < 0)
+ {
+ if (!command_output_filename)
+ {
+ error ("No `@setfilename' found in `%s'", name);
+ goto finished;
+ }
+ }
+ else
+ input_text_offset += strlen ("@setfilename");
+
+ real_output_filename = (char *)NULL;
+
+ if (!command_output_filename)
+ get_until ("\n", &output_filename);
+ else
+ {
+ if (input_text_offset != -1)
+ discard_until ("\n");
+ else
+ input_text_offset = 0;
+
+ real_output_filename = output_filename = command_output_filename;
+ command_output_filename = (char *)NULL;
+ }
+
+ canon_white (output_filename);
+ printf ("Making info file `%s' from `%s'.\n", output_filename, name);
+
+ if (verbose_mode)
+ fprintf (stderr, " The input file contains %d characters.\n",
+ size_of_input_text);
+
+ if (real_output_filename &&
+ strcmp (real_output_filename, "-") == 0)
+ {
+ output_stream = stdout;
+ }
+ else
+ {
+ if (!real_output_filename)
+ real_output_filename = expand_filename (output_filename, name);
+
+ output_stream = fopen (real_output_filename, "w");
+ }
+
+ if (output_stream == NULL)
+ {
+ fs_error (real_output_filename);
+ goto finished;
+ }
+
+ /* Make the displayable filename from output_filename. Only the base
+ portion of the filename need be displayed. */
+ pretty_output_filename = filename_part (output_filename);
+
+ /* For this file only, count the number of newlines from the top of
+ the file to here. This way, we keep track of line numbers for
+ error reporting. Line_number starts at 1, since the user isn't
+ zero-based. */
+ {
+ int temp = 0;
+ line_number = 1;
+ while (temp != input_text_offset)
+ if (input_text[temp++] == '\n')
+ line_number++;
+ }
+
+ if (!no_headers)
+ {
+ add_word_args ("This is Info file %s, produced by Makeinfo-%d.%d from ",
+ output_filename, major_version, minor_version);
+ add_word_args ("the input file %s.\n", input_filename);
+ }
+
+ close_paragraph ();
+ reader_loop ();
+
+finished:
+ close_paragraph ();
+ flush_file_stack ();
+ if (output_stream != NULL)
+ {
+ output_pending_notes ();
+ free_pending_notes ();
+ if (tag_table != NULL)
+ {
+ tag_table = (TAG_ENTRY *) reverse_list (tag_table);
+ if (!no_headers)
+ write_tag_table ();
+ }
+
+ if (output_stream != stdout)
+ fclose (output_stream);
+
+ /* If validating, then validate the entire file right now. */
+ if (validating)
+ validate_file (real_output_filename, tag_table);
+
+ /* This used to test && !errors_printed.
+ But some files might have legit warnings. So split anyway. */
+ if (splitting)
+ split_file (real_output_filename, 0);
+ }
+}
+
+free_and_clear (pointer)
+ char **pointer;
+{
+ if ((*pointer) != (char *) NULL)
+ {
+ free (*pointer);
+ *pointer = (char *) NULL;
+ }
+}
+
+ /* Initialize some state. */
+init_internals ()
+{
+ free_and_clear (&current_node);
+ free_and_clear (&output_filename);
+ free_and_clear (&command);
+ free_and_clear (&input_filename);
+ free_node_references ();
+ init_insertion_stack ();
+ init_brace_stack ();
+ command_index = 0;
+ in_menu = 0;
+}
+
+init_paragraph ()
+{
+ free_and_clear (&output_paragraph);
+ output_paragraph = (unsigned char *)xmalloc (paragraph_buffer_len);
+ output_position = 0;
+ output_paragraph[0] = '\0';
+ output_paragraph_offset = 0;
+ output_column = 0;
+ paragraph_is_open = 0;
+ current_indent = 0;
+}
+
+/* Okay, we are ready to start the conversion. Call the reader on
+ some text, and fill the text as it is output. Handle commands by
+ remembering things like open braces and the current file position on a
+ stack, and when the corresponding close brace is found, you can call
+ the function with the proper arguments. */
+reader_loop ()
+{
+ int character;
+ int done = 0;
+ int dash_count = 0;
+
+ while (!done)
+ {
+ if (input_text_offset >= size_of_input_text)
+ {
+ if (filestack)
+ {
+ free (input_filename);
+ free (input_text);
+ popfile ();
+ }
+ else
+ break;
+ }
+
+ character = curchar ();
+
+ if (!in_fixed_width_font &&
+ (character == '\'' || character == '`') &&
+ input_text[input_text_offset + 1] == character)
+ {
+ input_text_offset++;
+ character = '"';
+ }
+
+ if (character == '-')
+ {
+ dash_count++;
+ if (dash_count == 2 && !in_fixed_width_font)
+ {
+ input_text_offset++;
+ continue;
+ }
+ }
+ else
+ {
+ dash_count = 0;
+ }
+
+ /* If this is a whitespace character, then check to see if the line
+ is blank. If so, advance to the carriage return. */
+ if (whitespace (character))
+ {
+ register int i = input_text_offset + 1;
+
+ while (i < size_of_input_text && whitespace (input_text[i]))
+ i++;
+
+ if (i == size_of_input_text || input_text[i] == '\n')
+ {
+ if (i == size_of_input_text)
+ i--;
+
+ input_text_offset = i;
+ character = curchar ();
+ }
+ }
+
+ if (character == '\n')
+ {
+ line_number++;
+
+ /* Check for a menu entry here, since the "escape sequence"
+ that begins menu entrys is "\n* ". */
+ if (in_menu && input_text_offset + 1 < size_of_input_text)
+ {
+ char *glean_node_from_menu (), *tem;
+
+ /* Note that the value of TEM is discarded, since it is
+ gauranteed to be NULL when glean_node_from_menu () is
+ called with a non-zero argument. */
+ tem = glean_node_from_menu (1);
+ }
+ }
+
+ switch (character)
+ {
+ case COMMAND_PREFIX:
+ read_command ();
+ if (strcmp (command, "bye") == 0)
+ {
+ done = 1;
+ continue;
+ }
+ break;
+
+ case '{':
+
+ /* Special case. I'm not supposed to see this character by itself.
+ If I do, it means there is a syntax error in the input text.
+ Report the error here, but remember this brace on the stack so
+ you can ignore its partner. */
+
+ line_error ("Misplaced `{'");
+ remember_brace (misplaced_brace);
+
+ /* Don't advance input_text_offset since this happens in
+ remember_brace ().
+ input_text_offset++;
+ */
+ break;
+
+ case '}':
+ pop_and_call_brace ();
+ input_text_offset++;
+ break;
+
+ default:
+ add_char (character);
+ input_text_offset++;
+ }
+ }
+}
+
+/* Find the command corresponding to STRING. If the command
+ is found, return a pointer to the data structure. Otherwise
+ return (-1). */
+COMMAND *
+get_command_entry (string)
+ char *string;
+{
+ register int i;
+
+ for (i = 0; CommandTable[i].name; i++)
+ if (strcmp (CommandTable[i].name, string) == 0)
+ return (&CommandTable[i]);
+
+ /* This command is not in our predefined command table. Perhaps
+ it is a user defined command. */
+ for (i = 0; i < user_command_array_len; i++)
+ if (user_command_array[i] &&
+ (strcmp (user_command_array[i]->name, string) == 0))
+ return (user_command_array[i]);
+
+ /* Nope, we never heard of this command. */
+ return ((COMMAND *) -1);
+}
+
+/* input_text_offset is right at the command prefix character.
+ Read the next token to determine what to do. */
+read_command ()
+{
+ COMMAND *entry;
+ input_text_offset++;
+ free_and_clear (&command);
+ command = read_token ();
+
+#if defined (HAVE_MACROS)
+ /* Check to see if this command is a macro. If so, execute it here. */
+ {
+ MACRO_DEF *def;
+
+ def = find_macro (command);
+
+ if (def)
+ {
+ execute_macro (def);
+ return;
+ }
+ }
+#endif /* HAVE_MACROS */
+
+ entry = get_command_entry (command);
+
+ if ((int) entry == -1)
+ {
+ line_error ("Unknown info command `%s'", command);
+ return;
+ }
+
+ if (entry->argument_in_braces)
+ remember_brace (entry->proc);
+
+ (*(entry->proc)) (START);
+}
+
+/* Return the string which invokes PROC; a pointer to a function. */
+char *
+find_proc_name (proc)
+ FUNCTION *proc;
+{
+ register int i;
+
+ for (i = 0; CommandTable[i].name; i++)
+ if (proc == CommandTable[i].proc)
+ return (CommandTable[i].name);
+ return ("NO_NAME!");
+}
+
+init_brace_stack ()
+{
+ brace_stack = (BRACE_ELEMENT *) NULL;
+}
+
+remember_brace (proc)
+ FUNCTION *proc;
+{
+ if (curchar () != '{')
+ line_error ("@%s expected `{..}'", command);
+ else
+ input_text_offset++;
+ remember_brace_1 (proc, output_paragraph_offset);
+}
+
+/* Remember the current output position here. Save PROC
+ along with it so you can call it later. */
+remember_brace_1 (proc, position)
+ FUNCTION *proc;
+ int position;
+{
+ BRACE_ELEMENT *new = (BRACE_ELEMENT *) xmalloc (sizeof (BRACE_ELEMENT));
+ new->next = brace_stack;
+ new->proc = proc;
+ new->pos = position;
+ new->line = line_number;
+ brace_stack = new;
+}
+
+/* Pop the top of the brace stack, and call the associated function
+ with the args END and POS. */
+pop_and_call_brace ()
+{
+ BRACE_ELEMENT *temp;
+ FUNCTION *proc;
+ int pos;
+
+ if (brace_stack == (BRACE_ELEMENT *) NULL)
+ return (line_error ("Unmatched close brace"));
+
+ pos = brace_stack->pos;
+ proc = brace_stack->proc;
+ temp = brace_stack->next;
+ free (brace_stack);
+ brace_stack = temp;
+
+ return ((*proc) (END, pos, output_paragraph_offset));
+}
+
+/* You call discard_braces () when you shouldn't have any braces on the stack.
+ I used to think that this happens for commands that don't take arguments
+ in braces, but that was wrong because of things like @code{foo @@}. So now
+ I only detect it at the beginning of nodes. */
+discard_braces ()
+{
+ int temp_line_number = line_number;
+ char *proc_name;
+
+ if (!brace_stack)
+ return;
+
+ while (brace_stack)
+ {
+ line_number = brace_stack->line;
+ proc_name = find_proc_name (brace_stack->proc);
+ line_error ("@%s missing close brace", proc_name);
+ line_number = temp_line_number;
+ pop_and_call_brace ();
+ }
+}
+
+get_char_len (character)
+ int character;
+{
+ /* Return the printed length of the character. */
+ int len;
+
+ switch (character)
+ {
+ case '\t':
+ len = (output_column + 8) & 0xf7;
+ if (len > fill_column)
+ len = fill_column - output_column;
+ else
+ len = len - output_column;
+ break;
+
+ case '\n':
+ len = fill_column - output_column;
+ break;
+
+ default:
+ if (character < ' ')
+ len = 2;
+ else
+ len = 1;
+ }
+ return (len);
+}
+
+#if defined (HAVE_VARARGS_H) && defined (HAVE_VSPRINTF)
+
+add_word_args (va_alist)
+ va_dcl
+{
+ char buffer[1000];
+ char *format;
+ va_list args;
+
+ va_start (args);
+ format = va_arg (args, char *);
+ vsprintf (buffer, format, args);
+ va_end (args);
+ add_word (buffer);
+}
+
+#else /* !(HAVE_VARARGS_H && HAVE_VSPRINTF) */
+
+add_word_args (format, arg1, arg2, arg3, arg4, arg5)
+ char *format;
+{
+ char buffer[1000];
+ sprintf (buffer, format, arg1, arg2, arg3, arg4, arg5);
+ add_word (buffer);
+}
+
+#endif /* !(HAVE_VARARGS_H && HAVE_VSPRINTF) */
+
+/* Add STRING to output_paragraph. */
+add_word (string)
+ char *string;
+{
+ while (*string)
+ add_char (*string++);
+}
+
+/* Non-zero if the last character inserted has the syntax class of NEWLINE. */
+int last_char_was_newline = 1;
+
+/* The actual last inserted character. Note that this may be something
+ other than NEWLINE even if last_char_was_newline is 1. */
+int last_inserted_character = 0;
+
+/* Non-zero means that a newline character has already been
+ inserted, so close_paragraph () should insert one less. */
+int line_already_broken = 0;
+
+/* When non-zero we have finished an insertion (see end_insertion ()) and we
+ want to ignore false continued paragraph closings. */
+int insertion_paragraph_closed = 0;
+
+/* Add the character to the current paragraph. If filling_enabled is
+ non-zero, then do filling as well. */
+add_char (character)
+ int character;
+{
+ /* If we are avoiding outputting headers, and we are currently
+ in a menu, then simply return. */
+ if (no_headers && in_menu)
+ return;
+
+ /* If we are adding a character now, then we don't have to
+ ignore close_paragraph () calls any more. */
+ if (must_start_paragraph && character != '\n')
+ {
+ must_start_paragraph = 0;
+ line_already_broken = 0; /* The line is no longer broken. */
+ if (current_indent > output_column)
+ {
+ indent (current_indent - output_column);
+ output_column = current_indent;
+ }
+ }
+
+ if (non_splitting_words && member (character, " \t\n"))
+ character = ' ' | 0x80;
+
+ insertion_paragraph_closed = 0;
+
+ switch (character)
+ {
+ case '\n':
+ if (!filling_enabled)
+ {
+ insert ('\n');
+
+ if (force_flush_right)
+ {
+ close_paragraph ();
+ /* Hack to force single blank lines out in this mode. */
+ flush_output ();
+ }
+
+ output_column = 0;
+
+ if (!no_indent && paragraph_is_open)
+ indent (output_column = current_indent);
+ break;
+ }
+ else /* CHARACTER is newline, and filling is enabled. */
+ {
+ if (sentence_ender (last_inserted_character))
+ {
+ insert (' ');
+ output_column++;
+ last_inserted_character = character;
+ }
+ }
+
+ if (last_char_was_newline)
+ {
+ close_paragraph ();
+ pending_indent = 0;
+ }
+ else
+ {
+ last_char_was_newline = 1;
+ insert (' ');
+ output_column++;
+ }
+ break;
+
+ default:
+ {
+ int len = get_char_len (character);
+ int suppress_insert = 0;
+
+ if ((character == ' ') && (last_char_was_newline))
+ {
+ if (!paragraph_is_open)
+ {
+ pending_indent++;
+ return;
+ }
+ }
+
+ if (!paragraph_is_open)
+ {
+ start_paragraph ();
+
+ /* If the paragraph is supposed to be indented a certain way,
+ then discard all of the pending whitespace. Otherwise, we
+ let the whitespace stay. */
+ if (!paragraph_start_indent)
+ indent (pending_indent);
+ pending_indent = 0;
+ }
+
+ if ((output_column += len) > fill_column)
+ {
+ if (filling_enabled)
+ {
+ int temp = output_paragraph_offset;
+ while (--temp > 0 && output_paragraph[temp] != '\n')
+ {
+ /* If we have found a space, we have the place to break
+ the line. */
+ if (output_paragraph[temp] == ' ')
+ {
+ /* Remove trailing whitespace from output. */
+ while (temp && whitespace (output_paragraph[temp - 1]))
+ temp--;
+
+ output_paragraph[temp++] = '\n';
+
+ /* We have correctly broken the line where we want
+ to. What we don't want is spaces following where
+ we have decided to break the line. We get rid of
+ them. */
+ {
+ int t1 = temp;
+
+ for (;; t1++)
+ {
+ if (t1 == output_paragraph_offset)
+ {
+ if (whitespace (character))
+ suppress_insert = 1;
+ break;
+ }
+ if (!whitespace (output_paragraph[t1]))
+ break;
+ }
+
+ if (t1 != temp)
+ {
+ strncpy ((char *) &output_paragraph[temp],
+ (char *) &output_paragraph[t1],
+ (output_paragraph_offset - t1));
+ output_paragraph_offset -= (t1 - temp);
+ }
+ }
+
+ /* Filled, but now indent if that is right. */
+ if (indented_fill && current_indent)
+ {
+ int buffer_len = ((output_paragraph_offset - temp)
+ + current_indent);
+ char *temp_buffer = (char *)xmalloc (buffer_len);
+ int indentation = 0;
+
+ /* We have to shift any markers that are in
+ front of the wrap point. */
+ {
+ register BRACE_ELEMENT *stack = brace_stack;
+
+ while (stack)
+ {
+ if (stack->pos >= temp)
+ stack->pos += current_indent;
+ stack = stack->next;
+ }
+ }
+
+ while (current_indent > 0 &&
+ indentation != current_indent)
+ temp_buffer[indentation++] = ' ';
+
+ strncpy ((char *) &temp_buffer[current_indent],
+ (char *) &output_paragraph[temp],
+ buffer_len - current_indent);
+
+ if (output_paragraph_offset + buffer_len
+ >= paragraph_buffer_len)
+ {
+ unsigned char *tt = xrealloc
+ (output_paragraph,
+ (paragraph_buffer_len += buffer_len));
+ output_paragraph = tt;
+ }
+ strncpy ((char *) &output_paragraph[temp],
+ temp_buffer, buffer_len);
+ output_paragraph_offset += current_indent;
+ free (temp_buffer);
+ }
+ output_column = 0;
+ while (temp < output_paragraph_offset)
+ output_column +=
+ get_char_len (output_paragraph[temp++]);
+ output_column += len;
+ break;
+ }
+ }
+ }
+ }
+
+ if (!suppress_insert)
+ {
+ insert (character);
+ last_inserted_character = character;
+ }
+ last_char_was_newline = 0;
+ line_already_broken = 0;
+ }
+ }
+}
+
+/* Insert CHARACTER into OUTPUT_PARAGRAPH. */
+insert (character)
+ int character;
+{
+ output_paragraph[output_paragraph_offset++] = character;
+ if (output_paragraph_offset == paragraph_buffer_len)
+ {
+ output_paragraph =
+ xrealloc (output_paragraph, (paragraph_buffer_len += 100));
+ }
+}
+
+/* Remove upto COUNT characters of whitespace from the
+ the current output line. If COUNT is less than zero,
+ then remove until none left. */
+kill_self_indent (count)
+ int count;
+{
+ /* Handle infinite case first. */
+ if (count < 0)
+ {
+ output_column = 0;
+ while (output_paragraph_offset)
+ {
+ if (whitespace (output_paragraph[output_paragraph_offset - 1]))
+ output_paragraph_offset--;
+ else
+ break;
+ }
+ }
+ else
+ {
+ while (output_paragraph_offset && count--)
+ if (whitespace (output_paragraph[output_paragraph_offset - 1]))
+ output_paragraph_offset--;
+ else
+ break;
+ }
+}
+
+/* Non-zero means do not honor calls to flush_output (). */
+static int flushing_ignored = 0;
+
+/* Prevent calls to flush_output () from having any effect. */
+inhibit_output_flushing ()
+{
+ flushing_ignored++;
+}
+
+/* Allow calls to flush_output () to write the paragraph data. */
+uninhibit_output_flushing ()
+{
+ flushing_ignored--;
+}
+
+flush_output ()
+{
+ register int i;
+
+ if (!output_paragraph_offset || flushing_ignored)
+ return;
+
+ for (i = 0; i < output_paragraph_offset; i++)
+ {
+ if (output_paragraph[i] == (unsigned char)(' ' | 0x80) ||
+ output_paragraph[i] == (unsigned char)('\t' | 0x80) ||
+ output_paragraph[i] == (unsigned char)('\n' | 0x80) ||
+ sentence_ender (UNMETA (output_paragraph[i])))
+ output_paragraph[i] &= 0x7f;
+ }
+
+ fwrite (output_paragraph, 1, output_paragraph_offset, output_stream);
+
+ output_position += output_paragraph_offset;
+ output_paragraph_offset = 0;
+}
+
+/* How to close a paragraph controlling the number of lines between
+ this one and the last one. */
+
+/* Paragraph spacing is controlled by this variable. It is the number of
+ blank lines that you wish to appear between paragraphs. A value of
+ 1 creates a single blank line between paragraphs. */
+int paragraph_spacing = DEFAULT_PARAGRAPH_SPACING;
+
+/* Close the current paragraph, leaving no blank lines between them. */
+close_single_paragraph ()
+{
+ close_paragraph_with_lines (0);
+}
+
+/* Close a paragraph after an insertion has ended. */
+close_insertion_paragraph ()
+{
+ if (!insertion_paragraph_closed)
+ {
+ /* Close the current paragraph, breaking the line. */
+ close_single_paragraph ();
+
+ /* Start a new paragraph here, inserting whatever indention is correct
+ for the now current insertion level (one above the one that we are
+ ending). */
+ start_paragraph ();
+
+ /* Tell close_paragraph () that the previous line has already been
+ broken, so it should insert one less newline. */
+ line_already_broken = 1;
+
+ /* Let functions such as add_char () know that we have already found a
+ newline. */
+ ignore_blank_line ();
+ }
+ else
+ {
+ /* If the insertion paragraph is closed already, then we are seeing
+ two `@end' commands in a row. Note that the first one we saw was
+ handled in the first part of this if-then-else clause, and at that
+ time start_paragraph () was called, partially to handle the proper
+ indentation of the current line. However, the indentation level
+ may have just changed again, so we may have to outdent the current
+ line to the new indentation level. */
+ if (current_indent < output_column)
+ kill_self_indent (output_column - current_indent);
+ }
+
+ insertion_paragraph_closed = 1;
+}
+
+close_paragraph_with_lines (lines)
+ int lines;
+{
+ int old_spacing = paragraph_spacing;
+ paragraph_spacing = lines;
+ close_paragraph ();
+ paragraph_spacing = old_spacing;
+}
+
+/* Close the currently open paragraph. */
+close_paragraph ()
+{
+ register int i;
+
+ /* The insertion paragraph is no longer closed. */
+ insertion_paragraph_closed = 0;
+
+ if (paragraph_is_open && !must_start_paragraph)
+ {
+ register int tindex, c;
+
+ tindex = output_paragraph_offset;
+
+ /* Back up to last non-newline/space character, forcing all such
+ subsequent characters to be newlines. This isn't strictly
+ necessary, but a couple of functions use the presence of a newline
+ to make decisions. */
+ for (tindex = output_paragraph_offset - 1; tindex >= 0; --tindex)
+ {
+ c = output_paragraph[tindex];
+
+ if (c == ' '|| c == '\n')
+ output_paragraph[tindex] = '\n';
+ else
+ break;
+ }
+
+ /* All trailing whitespace is ignored. */
+ output_paragraph_offset = ++tindex;
+
+ /* Break the line if that is appropriate. */
+ if (paragraph_spacing >= 0)
+ insert ('\n');
+
+ /* Add as many blank lines as is specified in PARAGRAPH_SPACING. */
+ if (!force_flush_right)
+ {
+ for (i = 0; i < (paragraph_spacing - line_already_broken); i++)
+ insert ('\n');
+ }
+
+ /* If we are doing flush right indentation, then do it now
+ on the paragraph (really a single line). */
+ if (force_flush_right)
+ do_flush_right_indentation ();
+
+ flush_output ();
+ paragraph_is_open = 0;
+ no_indent = 0;
+ output_column = 0;
+ }
+ ignore_blank_line ();
+}
+
+/* Make the last line just read look as if it were only a newline. */
+ignore_blank_line ()
+{
+ last_inserted_character = '\n';
+ last_char_was_newline = 1;
+}
+
+/* Align the end of the text in output_paragraph with fill_column. */
+do_flush_right_indentation ()
+{
+ char *temp;
+ int temp_len;
+
+ kill_self_indent (-1);
+
+ if (output_paragraph[0] != '\n')
+ {
+ output_paragraph[output_paragraph_offset] = '\0';
+
+ if (output_paragraph_offset < fill_column)
+ {
+ register int i;
+
+ if (fill_column >= paragraph_buffer_len)
+ output_paragraph =
+ xrealloc (output_paragraph,
+ (paragraph_buffer_len += fill_column));
+
+ temp_len = strlen ((char *)output_paragraph);
+ temp = (char *)xmalloc (temp_len + 1);
+ memcpy (temp, (char *)output_paragraph, temp_len);
+
+ for (i = 0; i < fill_column - output_paragraph_offset; i++)
+ output_paragraph[i] = ' ';
+
+ memcpy ((char *)output_paragraph + i, temp, temp_len);
+ free (temp);
+ output_paragraph_offset = fill_column;
+ }
+ }
+}
+
+/* Begin a new paragraph. */
+start_paragraph ()
+{
+ /* First close existing one. */
+ if (paragraph_is_open)
+ close_paragraph ();
+
+ /* In either case, the insertion paragraph is no longer closed. */
+ insertion_paragraph_closed = 0;
+
+ /* However, the paragraph is open! */
+ paragraph_is_open = 1;
+
+ /* If we MUST_START_PARAGRAPH, that simply means that start_paragraph ()
+ had to be called before we would allow any other paragraph operations
+ to have an effect. */
+ if (!must_start_paragraph)
+ {
+ int amount_to_indent = 0;
+
+ /* If doing indentation, then insert the appropriate amount. */
+ if (!no_indent)
+ {
+ if (inhibit_paragraph_indentation)
+ {
+ amount_to_indent = current_indent;
+ if (inhibit_paragraph_indentation < 0)
+ inhibit_paragraph_indentation++;
+ }
+ else if (paragraph_start_indent < 0)
+ amount_to_indent = current_indent;
+ else
+ amount_to_indent = current_indent + paragraph_start_indent;
+
+ if (amount_to_indent >= output_column)
+ {
+ amount_to_indent -= output_column;
+ indent (amount_to_indent);
+ output_column += amount_to_indent;
+ }
+ }
+ }
+ else
+ must_start_paragraph = 0;
+}
+
+/* Insert the indentation specified by AMOUNT. */
+indent (amount)
+ int amount;
+{
+ register BRACE_ELEMENT *elt = brace_stack;
+
+ /* For every START_POS saved within the brace stack which will be affected
+ by this indentation, bump that start pos forward. */
+ while (elt)
+ {
+ if (elt->pos >= output_paragraph_offset)
+ elt->pos += amount;
+ elt = elt->next;
+ }
+
+ while (--amount >= 0)
+ insert (' ');
+}
+
+/* Search forward for STRING in input_text.
+ FROM says where where to start. */
+search_forward (string, from)
+ char *string;
+ int from;
+{
+ int len = strlen (string);
+
+ while (from < size_of_input_text)
+ {
+ if (strncmp (input_text + from, string, len) == 0)
+ return (from);
+ from++;
+ }
+ return (-1);
+}
+
+/* Whoops, Unix doesn't have stricmp. */
+
+/* Case independent string compare. */
+stricmp (string1, string2)
+ char *string1, *string2;
+{
+ char ch1, ch2;
+
+ for (;;)
+ {
+ ch1 = *string1++;
+ ch2 = *string2++;
+
+ if (!(ch1 | ch2))
+ return (0);
+
+ ch1 = coerce_to_upper (ch1);
+ ch2 = coerce_to_upper (ch2);
+
+ if (ch1 != ch2)
+ return (ch1 - ch2);
+ }
+}
+
+enum insertion_type { menu, quotation, lisp, smalllisp, example,
+ smallexample, display, itemize, format, enumerate, cartouche, table,
+ ftable, vtable, group, ifinfo, flushleft, flushright, ifset, ifclear, deffn,
+ defun, defmac, defspec, defvr, defvar, defopt, deftypefn,
+ deftypefun, deftypevr, deftypevar, defcv, defivar, defop, defmethod,
+ deftypemethod, deftp, bad_type };
+
+char *insertion_type_names[] = { "menu", "quotation", "lisp",
+ "smalllisp", "example", "smallexample", "display", "itemize",
+ "format", "enumerate", "cartouche", "table", "ftable", "vtable", "group",
+ "ifinfo", "flushleft", "flushright", "ifset", "ifclear", "deffn",
+ "defun", "defmac", "defspec", "defvr", "defvar", "defopt",
+ "deftypefn", "deftypefun", "deftypevr", "deftypevar", "defcv",
+ "defivar", "defop", "defmethod", "deftypemethod", "deftp",
+ "bad_type" };
+
+int insertion_level = 0;
+typedef struct istack_elt
+{
+ struct istack_elt *next;
+ char *item_function;
+ int line_number;
+ int filling_enabled;
+ int indented_fill;
+ enum insertion_type insertion;
+ int inhibited;
+} INSERTION_ELT;
+
+INSERTION_ELT *insertion_stack = (INSERTION_ELT *) NULL;
+
+init_insertion_stack ()
+{
+ insertion_stack = (INSERTION_ELT *) NULL;
+}
+
+/* Return the type of the current insertion. */
+enum insertion_type
+current_insertion_type ()
+{
+ if (!insertion_level)
+ return (bad_type);
+ else
+ return (insertion_stack->insertion);
+}
+
+/* Return a pointer to the string which is the function to wrap around
+ items. */
+char *
+current_item_function ()
+{
+ register int level, done;
+ register INSERTION_ELT *elt;
+
+ level = insertion_level;
+ elt = insertion_stack;
+ done = 0;
+
+ /* Skip down through the stack until we find a non-conditional insertion. */
+ while (!done)
+ {
+ switch (elt->insertion)
+ {
+ case ifinfo:
+ case ifset:
+ case ifclear:
+ case cartouche:
+ elt = elt->next;
+ level--;
+ break;
+
+ default:
+ done = 1;
+ }
+ }
+
+ if (!level)
+ return ((char *) NULL);
+ else
+ return (elt->item_function);
+}
+
+char *
+get_item_function ()
+{
+ char *item_function;
+ get_rest_of_line (&item_function);
+ backup_input_pointer ();
+ canon_white (item_function);
+ return (item_function);
+}
+
+ /* Push the state of the current insertion on the stack. */
+push_insertion (type, item_function)
+ enum insertion_type type;
+ char *item_function;
+{
+ INSERTION_ELT *new = (INSERTION_ELT *) xmalloc (sizeof (INSERTION_ELT));
+
+ new->item_function = item_function;
+ new->filling_enabled = filling_enabled;
+ new->indented_fill = indented_fill;
+ new->insertion = type;
+ new->line_number = line_number;
+ new->inhibited = inhibit_paragraph_indentation;
+ new->next = insertion_stack;
+ insertion_stack = new;
+ insertion_level++;
+}
+
+ /* Pop the value on top of the insertion stack into the
+ global variables. */
+pop_insertion ()
+{
+ INSERTION_ELT *temp = insertion_stack;
+
+ if (temp == (INSERTION_ELT *) NULL)
+ return;
+
+ inhibit_paragraph_indentation = temp->inhibited;
+ filling_enabled = temp->filling_enabled;
+ indented_fill = temp->indented_fill;
+ free_and_clear (&(temp->item_function));
+ insertion_stack = insertion_stack->next;
+ free (temp);
+ insertion_level--;
+}
+
+ /* Return a pointer to the print name of this
+ enumerated type. */
+char *
+insertion_type_pname (type)
+ enum insertion_type type;
+{
+ if ((int) type < (int) bad_type)
+ return (insertion_type_names[(int) type]);
+ else
+ return ("Broken-Type in insertion_type_pname");
+}
+
+/* Return the insertion_type associated with NAME.
+ If the type is not one of the known ones, return BAD_TYPE. */
+enum insertion_type
+find_type_from_name (name)
+ char *name;
+{
+ int index = 0;
+ while (index < (int) bad_type)
+ {
+ if (strcmp (name, insertion_type_names[index]) == 0)
+ return (enum insertion_type) index;
+ index++;
+ }
+ return (bad_type);
+}
+
+do_nothing ()
+{
+}
+
+int
+defun_insertion (type)
+ enum insertion_type type;
+{
+ return
+ ((type == deffn)
+ || (type == defun)
+ || (type == defmac)
+ || (type == defspec)
+ || (type == defvr)
+ || (type == defvar)
+ || (type == defopt)
+ || (type == deftypefn)
+ || (type == deftypefun)
+ || (type == deftypevr)
+ || (type == deftypevar)
+ || (type == defcv)
+ || (type == defivar)
+ || (type == defop)
+ || (type == defmethod)
+ || (type == deftypemethod)
+ || (type == deftp));
+}
+
+/* MAX_NS is the maximum nesting level for enumerations. I picked 100
+ which seemed reasonable. This doesn't control the number of items,
+ just the number of nested lists. */
+#define max_stack_depth 100
+#define ENUM_DIGITS 1
+#define ENUM_ALPHA 2
+typedef struct {
+ int enumtype;
+ int enumval;
+} DIGIT_ALPHA;
+
+DIGIT_ALPHA enumstack[max_stack_depth];
+int enumstack_offset = 0;
+int current_enumval = 1;
+int current_enumtype = ENUM_DIGITS;
+char *enumeration_arg = (char *)NULL;
+
+start_enumerating (at, type)
+ int at, type;
+{
+ if ((enumstack_offset + 1) == max_stack_depth)
+ {
+ line_error ("Enumeration stack overflow");
+ return;
+ }
+ enumstack[enumstack_offset].enumtype = current_enumtype;
+ enumstack[enumstack_offset].enumval = current_enumval;
+ enumstack_offset++;
+ current_enumval = at;
+ current_enumtype = type;
+}
+
+stop_enumerating ()
+{
+ --enumstack_offset;
+ if (enumstack_offset < 0)
+ enumstack_offset = 0;
+
+ current_enumval = enumstack[enumstack_offset].enumval;
+ current_enumtype = enumstack[enumstack_offset].enumtype;
+}
+
+/* Place a letter or digits into the output stream. */
+enumerate_item ()
+{
+ char temp[10];
+
+ if (current_enumtype == ENUM_ALPHA)
+ {
+ if (current_enumval == ('z' + 1) || current_enumval == ('Z' + 1))
+ {
+ current_enumval = ((current_enumval - 1) == 'z' ? 'a' : 'A');
+ warning ("Lettering overflow, restarting at %c", current_enumval);
+ }
+ sprintf (temp, "%c. ", current_enumval);
+ }
+ else
+ sprintf (temp, "%d. ", current_enumval);
+
+ indent (output_column += (current_indent - strlen (temp)));
+ add_word (temp);
+ current_enumval++;
+}
+
+/* This is where the work for all the "insertion" style
+ commands is done. A huge switch statement handles the
+ various setups, and generic code is on both sides. */
+begin_insertion (type)
+ enum insertion_type type;
+{
+ int no_discard = 0;
+
+ if (defun_insertion (type))
+ {
+ push_insertion (type, savestring (""));
+ no_discard++;
+ }
+ else
+ push_insertion (type, get_item_function ());
+
+ switch (type)
+ {
+ case menu:
+ if (!no_headers)
+ close_paragraph ();
+
+ filling_enabled = no_indent = 0;
+ inhibit_paragraph_indentation = 1;
+
+ if (!no_headers)
+ add_word ("* Menu:\n");
+
+ in_menu++;
+ no_discard++;
+ break;
+
+ /* I think @quotation is meant to do filling.
+ If you don't want filling, then use @example. */
+ case quotation:
+ close_single_paragraph ();
+ last_char_was_newline = no_indent = 0;
+ indented_fill = filling_enabled = 1;
+ inhibit_paragraph_indentation = 1;
+ current_indent += default_indentation_increment;
+ break;
+
+ case display:
+ case example:
+ case smallexample:
+ case lisp:
+ case smalllisp:
+ /* Just like @example, but no indentation. */
+ case format:
+
+ close_single_paragraph ();
+ inhibit_paragraph_indentation = 1;
+ in_fixed_width_font++;
+ filling_enabled = 0;
+ last_char_was_newline = 0;
+
+ if (type != format)
+ current_indent += default_indentation_increment;
+
+ break;
+
+ case table:
+ case ftable:
+ case vtable:
+ case itemize:
+ close_single_paragraph ();
+ current_indent += default_indentation_increment;
+ filling_enabled = indented_fill = 1;
+#if defined (INDENT_PARAGRAPHS_IN_TABLE)
+ inhibit_paragraph_indentation = 0;
+#else
+ inhibit_paragraph_indentation = 1;
+#endif /* !INDENT_PARAGRAPHS_IN_TABLE */
+
+ /* Make things work for losers who forget the itemize syntax. */
+ if (type == itemize)
+ {
+ if (!(*insertion_stack->item_function))
+ {
+ free (insertion_stack->item_function);
+ insertion_stack->item_function = savestring ("@bullet");
+ }
+ }
+ break;
+
+ case enumerate:
+ close_single_paragraph ();
+ no_indent = 0;
+#if defined (INDENT_PARAGRAPHS_IN_TABLE)
+ inhibit_paragraph_indentation = 0;
+#else
+ inhibit_paragraph_indentation = 1;
+#endif /* !INDENT_PARAGRAPHS_IN_TABLE */
+
+ current_indent += default_indentation_increment;
+ filling_enabled = indented_fill = 1;
+
+ if (isdigit (*enumeration_arg))
+ start_enumerating (atoi (enumeration_arg), ENUM_DIGITS);
+ else
+ start_enumerating (*enumeration_arg, ENUM_ALPHA);
+ break;
+
+ /* Does nothing special in makeinfo. */
+ case group:
+ /* Only close the paragraph if we are not inside of an @example. */
+ if (!insertion_stack->next ||
+ insertion_stack->next->insertion != example)
+ close_single_paragraph ();
+ break;
+
+ /* Insertions that are no-ops in info, but do something in TeX. */
+ case ifinfo:
+ case ifset:
+ case ifclear:
+ case cartouche:
+ if (in_menu)
+ no_discard++;
+ break;
+
+ case deffn:
+ case defun:
+ case defmac:
+ case defspec:
+ case defvr:
+ case defvar:
+ case defopt:
+ case deftypefn:
+ case deftypefun:
+ case deftypevr:
+ case deftypevar:
+ case defcv:
+ case defivar:
+ case defop:
+ case defmethod:
+ case deftypemethod:
+ case deftp:
+ inhibit_paragraph_indentation = 1;
+ filling_enabled = indented_fill = 1;
+ current_indent += default_indentation_increment;
+ no_indent = 0;
+ break;
+
+ case flushleft:
+ close_single_paragraph ();
+ inhibit_paragraph_indentation = 1;
+ filling_enabled = indented_fill = no_indent = 0;
+ break;
+
+ case flushright:
+ close_single_paragraph ();
+ filling_enabled = indented_fill = no_indent = 0;
+ inhibit_paragraph_indentation = 1;
+ force_flush_right++;
+ break;
+ }
+
+ if (!no_discard)
+ discard_until ("\n");
+}
+
+/* Try to end the insertion with the specified TYPE.
+ TYPE, with a value of bad_type, gets translated to match
+ the value currently on top of the stack.
+ Otherwise, if TYPE doesn't match the top of the insertion stack,
+ give error. */
+end_insertion (type)
+ enum insertion_type type;
+{
+ enum insertion_type temp_type;
+
+ if (!insertion_level)
+ return;
+
+ temp_type = current_insertion_type ();
+
+ if (type == bad_type)
+ type = temp_type;
+
+ if (type != temp_type)
+ {
+ line_error
+ ("`%cend' expected `%s', but saw `%s'.", COMMAND_PREFIX,
+ insertion_type_pname (temp_type), insertion_type_pname (type));
+ return;
+ }
+
+ pop_insertion ();
+
+ switch (type)
+ {
+ /* Insertions which have no effect on paragraph formatting. */
+ case ifinfo:
+ case ifset:
+ case ifclear:
+ break;
+
+ case menu:
+ in_menu--; /* No longer hacking menus. */
+ if (!no_headers)
+ close_insertion_paragraph ();
+ break;
+
+ case enumerate:
+ stop_enumerating ();
+ close_insertion_paragraph ();
+ current_indent -= default_indentation_increment;
+ break;
+
+ case flushleft:
+ case group:
+ case cartouche:
+ close_insertion_paragraph ();
+ break;
+
+ case format:
+ case display:
+ case example:
+ case smallexample:
+ case lisp:
+ case smalllisp:
+ case quotation:
+
+ /* @quotation is the only one of the above without a fixed width
+ font. */
+ if (type != quotation)
+ in_fixed_width_font--;
+
+ /* @format is the only fixed_width insertion without a change
+ in indentation. */
+ if (type != format)
+ current_indent -= default_indentation_increment;
+
+ /* The ending of one of these insertions always marks the
+ start of a new paragraph. */
+ close_insertion_paragraph ();
+ break;
+
+ case table:
+ case ftable:
+ case vtable:
+ case itemize:
+ current_indent -= default_indentation_increment;
+ break;
+
+ case flushright:
+ force_flush_right--;
+ close_insertion_paragraph ();
+ break;
+
+ /* Handle the @defun style insertions with a default clause. */
+ default:
+ current_indent -= default_indentation_increment;
+ close_insertion_paragraph ();
+ break;
+ }
+}
+
+/* Insertions cannot cross certain boundaries, such as node beginnings. In
+ code that creates such boundaries, you should call discard_insertions ()
+ before doing anything else. It prints the errors for you, and cleans up
+ the insertion stack. */
+discard_insertions ()
+{
+ int real_line_number = line_number;
+ while (insertion_stack)
+ {
+ if (insertion_stack->insertion == ifinfo ||
+ insertion_stack->insertion == ifset ||
+ insertion_stack->insertion == ifclear ||
+ insertion_stack->insertion == cartouche)
+ break;
+ else
+ {
+ char *offender = (char *)
+ insertion_type_pname (insertion_stack->insertion);
+
+ line_number = insertion_stack->line_number;
+ line_error ("This `%s' doesn't have a matching `%cend %s'", offender,
+ COMMAND_PREFIX, offender);
+ pop_insertion ();
+ }
+ }
+ line_number = real_line_number;
+}
+
+/* The actual commands themselves. */
+
+/* Commands which insert themselves. */
+insert_self ()
+{
+ add_word (command);
+}
+
+/* Force a line break in the output. */
+cm_asterisk ()
+{
+ close_single_paragraph ();
+#if !defined (ASTERISK_NEW_PARAGRAPH)
+ cm_noindent ();
+#endif /* ASTERISK_NEW_PARAGRAPH */
+}
+
+/* Insert ellipsis. */
+cm_dots (arg)
+ int arg;
+{
+ if (arg == START)
+ add_word ("...");
+}
+
+cm_bullet (arg)
+ int arg;
+{
+ if (arg == START)
+ add_char ('*');
+}
+
+cm_minus (arg)
+ int arg;
+{
+ if (arg == START)
+ add_char ('-');
+}
+
+/* Insert "TeX". */
+cm_TeX (arg)
+ int arg;
+{
+ if (arg == START)
+ add_word ("TeX");
+}
+
+cm_copyright (arg)
+ int arg;
+{
+ if (arg == START)
+ add_word ("(C)");
+}
+
+cm_today (arg)
+ int arg;
+{
+ static char * months [12] =
+ { "January", "February", "March", "April", "May", "June", "July",
+ "August", "September", "October", "November", "December" };
+ if (arg == START)
+ {
+ long timer = (time (0));
+ struct tm *ts = (localtime (&timer));
+ add_word_args
+ ("%d %s %d",
+ (ts -> tm_mday),
+ (months [ts -> tm_mon]),
+ ((ts -> tm_year) + 1900));
+ }
+}
+
+cm_code (arg)
+ int arg;
+{
+ extern int printing_index;
+
+ if (printing_index)
+ return;
+
+ if (arg == START)
+ {
+ in_fixed_width_font++;
+ add_char ('`');
+ }
+ else
+ {
+ add_word ("'");
+ in_fixed_width_font--;
+ }
+}
+
+cm_samp (arg)
+ int arg;
+{
+ cm_code (arg);
+}
+
+cm_file (arg)
+ int arg;
+{
+ cm_code (arg);
+}
+
+cm_kbd (arg)
+ int arg;
+{
+ cm_code (arg);
+}
+
+cm_key (arg)
+ int arg;
+{
+}
+
+/* Convert the character at position into CTL. */
+cm_ctrl (arg, position)
+ int arg, position;
+{
+ if (arg == END)
+ output_paragraph[position - 1] = CTL (output_paragraph[position]);
+}
+
+/* Small Caps in makeinfo just does all caps. */
+cm_sc (arg, start_pos, end_pos)
+ int arg, start_pos, end_pos;
+{
+ if (arg == END)
+ {
+ while (start_pos < end_pos)
+ {
+ output_paragraph[start_pos] =
+ coerce_to_upper (output_paragraph[start_pos]);
+ start_pos++;
+ }
+ }
+}
+
+/* @var in makeinfo just uppercases the text. */
+cm_var (arg, start_pos, end_pos)
+ int arg, start_pos, end_pos;
+{
+ if (arg == END)
+ {
+ while (start_pos < end_pos)
+ {
+ output_paragraph[start_pos] =
+ coerce_to_upper (output_paragraph[start_pos]);
+ start_pos++;
+ }
+ }
+}
+
+cm_dfn (arg, position)
+ int arg, position;
+{
+ add_char ('"');
+}
+
+cm_emph (arg)
+ int arg;
+{
+ add_char ('*');
+}
+
+cm_strong (arg, position)
+ int arg, position;
+{
+ cm_emph (arg);
+}
+
+cm_cite (arg, position)
+ int arg, position;
+{
+ if (arg == START)
+ add_word ("`");
+ else
+ add_word ("'");
+}
+
+/* Current text is italicized. */
+cm_italic (arg, start, end)
+ int arg, start, end;
+{
+}
+
+/* Current text is highlighted. */
+cm_bold (arg, start, end)
+ int arg, start, end;
+{
+ cm_italic (arg);
+}
+
+/* Current text is in roman font. */
+cm_roman (arg, start, end)
+ int arg, start, end;
+{
+}
+
+/* Current text is in roman font. */
+cm_titlefont (arg, start, end)
+ int arg, start, end;
+{
+}
+
+/* Italicize titles. */
+cm_title (arg, start, end)
+ int arg, start, end;
+{
+ cm_italic (arg);
+}
+
+/* @refill is a NOP. */
+cm_refill ()
+{
+}
+
+/* Prevent the argument from being split across two lines. */
+cm_w (arg, start, end)
+ int arg, start, end;
+{
+ if (arg == START)
+ non_splitting_words++;
+ else
+ non_splitting_words--;
+}
+
+
+/* Explain that this command is obsolete, thus the user shouldn't
+ do anything with it. */
+cm_obsolete (arg, start, end)
+ int arg, start, end;
+{
+ if (arg == START)
+ warning ("The command `@%s' is obsolete", command);
+}
+
+/* Insert the text following input_text_offset up to the end of the line
+ in a new, separate paragraph. Directly underneath it, insert a
+ line of WITH_CHAR, the same length of the inserted text. */
+insert_and_underscore (with_char)
+ int with_char;
+{
+ int len, i, old_no_indent;
+ int starting_pos, ending_pos;
+ char *temp;
+
+ close_paragraph ();
+ filling_enabled = indented_fill = 0;
+ old_no_indent = no_indent;
+ no_indent = 1;
+ get_rest_of_line (&temp);
+
+ starting_pos = output_position + output_paragraph_offset;
+ execute_string ("%s\n", temp);
+ ending_pos = output_position + output_paragraph_offset;
+ free (temp);
+
+ len = (ending_pos - starting_pos) - 1;
+ for (i = 0; i < len; i++)
+ add_char (with_char);
+ insert ('\n');
+ close_paragraph ();
+ filling_enabled = 1;
+ no_indent = old_no_indent;
+}
+
+/* Here is a structure which associates sectioning commands with
+ an integer, hopefully to reflect the `depth' of the current
+ section. */
+struct {
+ char *name;
+ int level;
+} section_alist[] = {
+ { "unnumberedsubsubsec", 5 },
+ { "unnumberedsubsec", 4 },
+ { "unnumberedsec", 3 },
+ { "unnumbered", 2 },
+ { "appendixsubsubsec", 5 },
+ { "appendixsubsec", 4 },
+ { "appendixsec", 3 },
+ { "appendixsection", 3 },
+ { "appendix", 2 },
+ { "subsubsec", 5 },
+ { "subsubsection", 5 },
+ { "subsection", 4 },
+ { "section", 3 },
+ { "chapter", 2 },
+ { "top", 1 },
+
+ { (char *)NULL, 0 }
+};
+
+/* Amount to offset the name of sectioning commands to levels by. */
+int section_alist_offset = 0;
+
+/* Shift the meaning of @section to @chapter. */
+cm_raisesections ()
+{
+ discard_until ("\n");
+ section_alist_offset--;
+}
+
+/* Shift the meaning of @chapter to @section. */
+cm_lowersections ()
+{
+ discard_until ("\n");
+ section_alist_offset++;
+}
+
+/* Return an integer which identifies the type section present in TEXT. */
+int
+what_section (text)
+ char *text;
+{
+ register int i, j;
+ char *t;
+
+ find_section_command:
+ for (j = 0; text[j] && cr_or_whitespace (text[j]); j++);
+ if (text[j] != '@')
+ return (-1);
+
+ text = text + j + 1;
+
+ /* We skip @c, @comment, and @?index commands. */
+ if ((strncmp (text, "comment", strlen ("comment")) == 0) ||
+ (text[0] == 'c' && cr_or_whitespace (text[1])) ||
+ (strcmp (text + 1, "index") == 0))
+ {
+ while (*text++ != '\n');
+ goto find_section_command;
+ }
+
+ /* Handle italicized sectioning commands. */
+ if (*text == 'i')
+ text++;
+
+ for (j = 0; text[j] && !cr_or_whitespace (text[j]); j++);
+
+ for (i = 0; t = section_alist[i].name; i++)
+ {
+ if (j == strlen (t) && strncmp (t, text, j) == 0)
+ {
+ int return_val;
+
+ return_val = (section_alist[i].level + section_alist_offset);
+
+ if (return_val < 0)
+ return_val = 0;
+ else if (return_val > 5)
+ return_val = 5;
+ return (return_val);
+ }
+ }
+ return (-1);
+}
+
+/* Treat this just like @unnumbered. The only difference is
+ in node defaulting. */
+cm_top ()
+{
+ static int top_encountered = 0;
+ cm_unnumbered ();
+
+ /* It is an error to have more than one @top. */
+ if (top_encountered)
+ {
+ TAG_ENTRY *tag = tag_table;
+
+ line_error ("There already is a node having @top as a section");
+
+ while (tag != (TAG_ENTRY *)NULL)
+ {
+ if ((tag->flags & IS_TOP))
+ {
+ int old_line_number = line_number;
+ char *old_input_filename = input_filename;
+
+ line_number = tag->line_no;
+ input_filename = tag->filename;
+ line_error ("Here is the @top node.");
+ input_filename = old_input_filename;
+ line_number = old_line_number;
+ return;
+ }
+ tag = tag->next_ent;
+ }
+ }
+ else
+ {
+ top_encountered = 1;
+
+ /* The most recently defined node is the top node. */
+ if (tag_table)
+ tag_table->flags |= IS_TOP;
+
+ /* Now set the logical hierarchical level of the Top node. */
+ {
+ int orig_offset = input_text_offset;
+
+ input_text_offset = search_forward ("\n@node", orig_offset);
+
+ if (input_text_offset > 0)
+ {
+ int this_section;
+
+ /* Move to the end of this line, and find out what the
+ sectioning command is here. */
+ while (input_text[input_text_offset] != '\n')
+ input_text_offset++;
+
+ if (input_text_offset < size_of_input_text)
+ input_text_offset++;
+
+ this_section = what_section (input_text + input_text_offset);
+
+ /* If we found a sectioning command, then give the top section
+ a level of this section - 1. */
+ if (this_section != -1)
+ {
+ register int i;
+
+ for (i = 0; section_alist[i].name; i++)
+ if (strcmp (section_alist[i].name, "Top") == 0)
+ {
+ section_alist[i].level = this_section - 1;
+ break;
+ }
+ }
+ }
+ input_text_offset = orig_offset;
+ }
+ }
+}
+
+/* Organized by level commands. That is, "*" == chapter, "=" == section. */
+char *scoring_characters = "*=-.";
+
+void
+sectioning_underscore (command)
+ char *command;
+{
+ char character;
+ int level;
+
+ level = what_section (command);
+ level -= 2;
+
+ if (level < 0)
+ level = 0;
+
+ character = scoring_characters[level];
+
+ insert_and_underscore (character);
+}
+
+/* The remainder of the text on this line is a chapter heading. */
+cm_chapter ()
+{
+ sectioning_underscore ("@chapter");
+}
+
+/* The remainder of the text on this line is a section heading. */
+cm_section ()
+{
+ sectioning_underscore ("@section");
+}
+
+/* The remainder of the text on this line is a subsection heading. */
+cm_subsection ()
+{
+ sectioning_underscore ("@subsection");
+}
+
+/* The remainder of the text on this line is a subsubsection heading. */
+cm_subsubsection ()
+{
+ sectioning_underscore ("@subsubsection");
+}
+
+/* The remainder of the text on this line is an unnumbered heading. */
+cm_unnumbered ()
+{
+ cm_chapter ();
+}
+
+/* The remainder of the text on this line is an unnumbered section heading. */
+cm_unnumberedsec ()
+{
+ cm_section ();
+}
+
+/* The remainder of the text on this line is an unnumbered
+ subsection heading. */
+cm_unnumberedsubsec ()
+{
+ cm_subsection ();
+}
+
+/* The remainder of the text on this line is an unnumbered
+ subsubsection heading. */
+cm_unnumberedsubsubsec ()
+{
+ cm_subsubsection ();
+}
+
+/* The remainder of the text on this line is an appendix heading. */
+cm_appendix ()
+{
+ cm_chapter ();
+}
+
+/* The remainder of the text on this line is an appendix section heading. */
+cm_appendixsec ()
+{
+ cm_section ();
+}
+
+/* The remainder of the text on this line is an appendix subsection heading. */
+cm_appendixsubsec ()
+{
+ cm_subsection ();
+}
+
+/* The remainder of the text on this line is an appendix
+ subsubsection heading. */
+cm_appendixsubsubsec ()
+{
+ cm_subsubsection ();
+}
+
+/* Compatibility functions substitute for chapter, section, etc. */
+cm_majorheading ()
+{
+ cm_chapheading ();
+}
+
+cm_chapheading ()
+{
+ cm_chapter ();
+}
+
+cm_heading ()
+{
+ cm_section ();
+}
+
+cm_subheading ()
+{
+ cm_subsection ();
+}
+
+cm_subsubheading ()
+{
+ cm_subsubsection ();
+}
+
+
+/* **************************************************************** */
+/* */
+/* Adding nodes, and making tags */
+/* */
+/* **************************************************************** */
+
+/* Start a new tag table. */
+init_tag_table ()
+{
+ while (tag_table != (TAG_ENTRY *) NULL)
+ {
+ TAG_ENTRY *temp = tag_table;
+ free (temp->node);
+ free (temp->prev);
+ free (temp->next);
+ free (temp->up);
+ tag_table = tag_table->next_ent;
+ free (temp);
+ }
+}
+
+write_tag_table ()
+{
+ return (write_tag_table_internal (0)); /* Not indirect. */
+}
+
+write_tag_table_indirect ()
+{
+ return (write_tag_table_internal (1));
+}
+
+/* Write out the contents of the existing tag table.
+ INDIRECT_P says how to format the output. */
+write_tag_table_internal (indirect_p)
+ int indirect_p;
+{
+ TAG_ENTRY *node = tag_table;
+ int old_indent = no_indent;
+
+ no_indent = 1;
+ filling_enabled = 0;
+ must_start_paragraph = 0;
+ close_paragraph ();
+
+ if (!indirect_p)
+ {
+ no_indent = 1;
+ insert ('\n');
+ }
+
+ add_word_args ("\037\nTag Table:\n%s", indirect_p ? "(Indirect)\n" : "");
+
+ while (node != (TAG_ENTRY *) NULL)
+ {
+ add_word_args ("Node: %s\177%d\n", node->node, node->position);
+ node = node->next_ent;
+ }
+
+ add_word ("\037\nEnd Tag Table\n");
+ flush_output ();
+ no_indent = old_indent;
+}
+
+char *
+get_node_token ()
+{
+ char *string;
+
+ get_until_in_line (",", &string);
+
+ if (curchar () == ',')
+ input_text_offset++;
+
+ canon_white (string);
+
+ /* Allow things like @@nodename. */
+ normalize_node_name (string);
+
+ return (string);
+}
+
+/* Given a node name in STRING, remove double @ signs, replacing them
+ with just one. Convert "top" and friends into "Top". */
+normalize_node_name (string)
+ char *string;
+{
+ register int i, l = strlen (string);
+
+ for (i = 0; i < l; i++)
+ {
+ if (string[i] == '@' && string[i + 1] == '@')
+ {
+ strncpy (string + i, string + i + 1, l - i);
+ l--;
+ }
+ }
+ if (stricmp (string, "Top") == 0)
+ strcpy (string, "Top");
+}
+
+/* Look up NAME in the tag table, and return the associated
+ tag_entry. If the node is not in the table return NULL. */
+TAG_ENTRY *
+find_node (name)
+ char *name;
+{
+ TAG_ENTRY *tag = tag_table;
+
+ while (tag != (TAG_ENTRY *) NULL)
+ {
+ if (strcmp (tag->node, name) == 0)
+ return (tag);
+ tag = tag->next_ent;
+ }
+ return ((TAG_ENTRY *) NULL);
+}
+
+/* Remember NODE and associates. */
+remember_node (node, prev, next, up, position, line_no, no_warn)
+ char *node, *prev, *next, *up;
+ int position, line_no, no_warn;
+{
+ /* Check for existence of this tag already. */
+ if (validating)
+ {
+ register TAG_ENTRY *tag = find_node (node);
+ if (tag)
+ {
+ line_error ("Node `%s' multiply defined (%d is first definition)",
+ node, tag->line_no);
+ return;
+ }
+ }
+
+ /* First, make this the current node. */
+ current_node = node;
+
+ /* Now add it to the list. */
+ {
+ TAG_ENTRY *new = (TAG_ENTRY *) xmalloc (sizeof (TAG_ENTRY));
+ new->node = node;
+ new->prev = prev;
+ new->next = next;
+ new->up = up;
+ new->position = position;
+ new->line_no = line_no;
+ new->filename = node_filename;
+ new->touched = 0; /* not yet referenced. */
+ new->flags = 0;
+ if (no_warn)
+ new->flags |= NO_WARN;
+ new->next_ent = tag_table;
+ tag_table = new;
+ }
+}
+
+/* The order is: nodename, nextnode, prevnode, upnode.
+ If all of the NEXT, PREV, and UP fields are empty, they are defaulted.
+ You must follow a node command which has those fields defaulted
+ with a sectioning command (e.g. @chapter) giving the "level" of that node.
+ It is an error not to do so.
+ The defaults come from the menu in this nodes parent. */
+cm_node ()
+{
+ char *node, *prev, *next, *up;
+ int new_node_pos, defaulting, this_section, no_warn = 0;
+ extern int already_outputting_pending_notes;
+
+ if (strcmp (command, "nwnode") == 0)
+ no_warn = 1;
+
+ /* Get rid of unmatched brace arguments from previous commands. */
+ discard_braces ();
+
+ /* There also might be insertions left lying around that haven't been
+ ended yet. Do that also. */
+ discard_insertions ();
+
+ if (!already_outputting_pending_notes)
+ {
+ close_paragraph ();
+ output_pending_notes ();
+ free_pending_notes ();
+ }
+
+ filling_enabled = indented_fill = 0;
+ new_node_pos = output_position;
+ current_footnote_number = 1;
+
+ node = get_node_token ();
+ next = get_node_token ();
+ prev = get_node_token ();
+ up = get_node_token ();
+
+ no_indent = 1;
+ if (!no_headers)
+ add_word_args ("\037\nFile: %s, Node: %s", pretty_output_filename, node);
+
+ /* Check for defaulting of this node's next, prev, and up fields. */
+ defaulting = ((strlen (next) == 0) &&
+ (strlen (prev) == 0) &&
+ (strlen (up) == 0));
+
+ this_section = what_section (input_text + input_text_offset);
+
+ /* If we are defaulting, then look at the immediately following
+ sectioning command (error if none) to determine the node's
+ level. Find the node that contains the menu mentioning this node
+ that is one level up (error if not found). That node is the "Up"
+ of this node. Default the "Next" and "Prev" from the menu. */
+ if (defaulting)
+ {
+ NODE_REF *last_ref = (NODE_REF *)NULL;
+ NODE_REF *ref = node_references;
+
+ if (this_section < 0)
+ {
+ char *polite_section_name = "top";
+ int i;
+
+ for (i = 0; section_alist[i].name; i++)
+ if (section_alist[i].level == current_section + 1)
+ {
+ polite_section_name = section_alist[i].name;
+ break;
+ }
+
+ line_error
+ ("Node `%s' requires a sectioning command (e.g. @%s)",
+ node, polite_section_name);
+ }
+ else
+ {
+ if (stricmp (node, "Top") == 0)
+ {
+ /* Default the NEXT pointer to be the first menu item in
+ this node, if there is a menu in this node. */
+ {
+ int orig_offset, orig_size;
+ char *glean_node_from_menu ();
+
+ orig_offset = input_text_offset;
+ orig_size = search_forward ("\n@node ", orig_offset);
+
+ if (orig_size < 0)
+ orig_size = size_of_input_text;
+
+ input_text_offset = search_forward ("\n@menu", orig_offset);
+ if (input_text_offset > -1)
+ {
+ char *nodename_from_menu = (char *)NULL;
+
+ input_text_offset =
+ search_forward ("\n* ", input_text_offset);
+
+ if (input_text_offset != -1)
+ nodename_from_menu = glean_node_from_menu (0);
+
+ if (nodename_from_menu)
+ {
+ free (next);
+ next = nodename_from_menu;
+ prev = savestring ("(DIR)");
+ up = savestring ("(DIR)");
+ }
+ }
+ input_text_offset = orig_offset;
+ }
+ }
+
+ while (ref)
+ {
+ if (ref->section == (this_section - 1) &&
+ ref->type == menu_reference &&
+ strcmp (ref->node, node) == 0)
+ {
+ char *containing_node = ref->containing_node;
+
+ free (up);
+ up = savestring (containing_node);
+
+ if (last_ref &&
+ last_ref->type == menu_reference &&
+ (strcmp (last_ref->containing_node,
+ containing_node) == 0))
+ {
+ free (next);
+ next = savestring (last_ref->node);
+ }
+
+ while ((ref->section == this_section - 1) &&
+ (ref->next) &&
+ (ref->next->type != menu_reference))
+ ref = ref->next;
+
+ if (ref->next && ref->type == menu_reference &&
+ (strcmp (ref->next->containing_node,
+ containing_node) == 0))
+ {
+ free (prev);
+ prev = savestring (ref->next->node);
+ }
+ else if (!ref->next &&
+ stricmp (ref->containing_node, "Top") == 0)
+ {
+ free (prev);
+ prev = savestring (ref->containing_node);
+ }
+ break;
+ }
+ last_ref = ref;
+ ref = ref->next;
+ }
+ }
+ }
+
+ if (!no_headers)
+ {
+ if (*next)
+ add_word_args (", Next: %s", next);
+
+ if (*prev)
+ add_word_args (", Prev: %s", prev);
+
+ if (*up)
+ add_word_args (", Up: %s", up);
+ }
+
+ close_paragraph ();
+ no_indent = 0;
+
+ if (!*node)
+ {
+ line_error ("No node name specified for `@%s' command", command);
+ free (node);
+ free (next);
+ free (prev);
+ free (up);
+ }
+ else
+ {
+ if (!*next) { free (next); next = (char *)NULL; }
+ if (!*prev) { free (prev); prev = (char *)NULL; }
+ if (!*up) { free (up); up = (char *)NULL; }
+ remember_node (node, prev, next, up, new_node_pos, line_number, no_warn);
+ }
+
+ /* Change the section only if there was a sectioning command. */
+ if (this_section >= 0)
+ current_section = this_section;
+
+ filling_enabled = 1;
+}
+
+/* Validation of an info file.
+ Scan through the list of tag entrys touching the Prev, Next, and Up
+ elements of each. It is an error not to be able to touch one of them,
+ except in the case of external node references, such as "(DIR)".
+
+ If the Prev is different from the Up,
+ then the Prev node must have a Next pointing at this node.
+
+ Every node except Top must have an Up.
+ The Up node must contain some sort of reference, other than a Next,
+ to this node.
+
+ If the Next is different from the Next of the Up,
+ then the Next node must have a Prev pointing at this node. */
+validate_file (filename, tag_table)
+ char *filename;
+ TAG_ENTRY *tag_table;
+{
+ char *old_input_filename = input_filename;
+ TAG_ENTRY *tags = tag_table;
+
+ while (tags != (TAG_ENTRY *) NULL)
+ {
+ register TAG_ENTRY *temp_tag;
+
+ input_filename = tags->filename;
+ line_number = tags->line_no;
+
+ /* If this is a "no warn" node, don't validate it in any way. */
+ if (tags->flags & NO_WARN)
+ {
+ tags = tags->next_ent;
+ continue;
+ }
+
+ /* If this node has a Next, then make sure that the Next exists. */
+ if (tags->next)
+ {
+ validate (tags->next, tags->line_no, "Next");
+
+ /* If the Next node exists, and there is no Up, then make
+ sure that the Prev of the Next points back. */
+ if (temp_tag = find_node (tags->next))
+ {
+ char *prev;
+
+ if (temp_tag->flags & NO_WARN)
+ {
+ /* Do nothing if we aren't supposed to issue warnings
+ about this node. */
+ }
+ else
+ {
+ prev = temp_tag->prev;
+ if (!prev || (strcmp (prev, tags->node) != 0))
+ {
+ line_error ("Node `%s''s Next field not pointed back to",
+ tags->node);
+ line_number = temp_tag->line_no;
+ input_filename = temp_tag->filename;
+ line_error
+ ("This node (`%s') is the one with the bad `Prev'",
+ temp_tag->node);
+ input_filename = tags->filename;
+ line_number = tags->line_no;
+ temp_tag->flags |= PREV_ERROR;
+ }
+ }
+ }
+ }
+
+ /* Validate the Prev field if there is one, and we haven't already
+ complained about it in some way. You don't have to have a Prev
+ field at this stage. */
+ if (!(tags->flags & PREV_ERROR) && tags->prev)
+ {
+ int valid = validate (tags->prev, tags->line_no, "Prev");
+
+ if (!valid)
+ tags->flags |= PREV_ERROR;
+ else
+ {
+ /* If the Prev field is not the same as the Up field,
+ then the node pointed to by the Prev field must have
+ a Next field which points to this node. */
+ if (tags->up && (strcmp (tags->prev, tags->up) != 0))
+ {
+ temp_tag = find_node (tags->prev);
+
+ /* If we aren't supposed to issue warnings about the
+ target node, do nothing. */
+ if (!temp_tag || (temp_tag->flags & NO_WARN))
+ {
+ /* Do nothing. */
+ }
+ else
+ {
+ if (!temp_tag->next ||
+ (strcmp (temp_tag->next, tags->node) != 0))
+ {
+ line_error
+ ("Node `%s''s Prev field not pointed back to",
+ tags->node);
+ line_number = temp_tag->line_no;
+ input_filename = temp_tag->filename;
+ line_error
+ ("This node (`%s') is the one with the bad `Next'",
+ temp_tag->node);
+ input_filename = tags->filename;
+ line_number = tags->line_no;
+ temp_tag->flags |= NEXT_ERROR;
+ }
+ }
+ }
+ }
+ }
+
+ if (!tags->up && (stricmp (tags->node, "Top") != 0))
+ line_error ("Node `%s' is missing an \"Up\" field", tags->node);
+ else if (tags->up)
+ {
+ int valid = validate (tags->up, tags->line_no, "Up");
+
+ /* If node X has Up: Y, then warn if Y fails to have a menu item
+ or note pointing at X, if Y isn't of the form "(Y)". */
+ if (valid && *tags->up != '(')
+ {
+ NODE_REF *nref, *tref, *list;
+ NODE_REF *find_node_reference ();
+
+ tref = (NODE_REF *) NULL;
+ list = node_references;
+
+ for (;;)
+ {
+ if (!(nref = find_node_reference (tags->node, list)))
+ break;
+
+ if (strcmp (nref->containing_node, tags->up) == 0)
+ {
+ if (nref->type != menu_reference)
+ {
+ tref = nref;
+ list = nref->next;
+ }
+ else
+ break;
+ }
+ list = nref->next;
+ }
+
+ if (!nref)
+ {
+ temp_tag = find_node (tags->up);
+ line_number = temp_tag->line_no;
+ filename = temp_tag->filename;
+ if (!tref)
+ line_error (
+"`%s' has an Up field of `%s', but `%s' has no menu item for `%s'",
+ tags->node, tags->up, tags->up, tags->node);
+ line_number = tags->line_no;
+ filename = tags->filename;
+ }
+ }
+ }
+ tags = tags->next_ent;
+ }
+
+ validate_other_references (node_references);
+ /* We have told the user about the references which didn't exist.
+ Now tell him about the nodes which aren't referenced. */
+
+ tags = tag_table;
+ while (tags != (TAG_ENTRY *) NULL)
+ {
+ /* If this node is a "no warn" node, do nothing. */
+ if (tags->flags & NO_WARN)
+ {
+ tags = tags->next_ent;
+ continue;
+ }
+
+ /* Special hack. If the node in question appears to have
+ been referenced more than REFERENCE_WARNING_LIMIT times,
+ give a warning. */
+ if (tags->touched > reference_warning_limit)
+ {
+ input_filename = tags->filename;
+ line_number = tags->line_no;
+ warning ("Node `%s' has been referenced %d times",
+ tags->node, tags->touched);
+ }
+
+ if (tags->touched == 0)
+ {
+ input_filename = tags->filename;
+ line_number = tags->line_no;
+
+ /* Notice that the node "Top" is special, and doesn't have to
+ be referenced. */
+ if (stricmp (tags->node, "Top") != 0)
+ warning ("Unreferenced node `%s'", tags->node);
+ }
+ tags = tags->next_ent;
+ }
+ input_filename = old_input_filename;
+}
+
+/* Return 1 if tag correctly validated, or 0 if not. */
+validate (tag, line, label)
+ char *tag;
+ int line;
+ char *label;
+{
+ TAG_ENTRY *result;
+
+ /* If there isn't a tag to verify, or if the tag is in another file,
+ then it must be okay. */
+ if (!tag || !*tag || *tag == '(')
+ return (1);
+
+ /* Otherwise, the tag must exist. */
+ result = find_node (tag);
+
+ if (!result)
+ {
+ line_number = line;
+ line_error (
+"Validation error. `%s' field points to node `%s', which doesn't exist",
+ label, tag);
+ return (0);
+ }
+ result->touched++;
+ return (1);
+}
+
+/* Split large output files into a series of smaller files. Each file
+ is pointed to in the tag table, which then gets written out as the
+ original file. The new files have the same name as the original file
+ with a "-num" attached. SIZE is the largest number of bytes to allow
+ in any single split file. */
+split_file (filename, size)
+ char *filename;
+ int size;
+{
+ char *root_filename, *root_pathname;
+ char *the_file, *filename_part ();
+ struct stat fileinfo;
+ char *the_header;
+ int header_size;
+
+ /* Can only do this to files with tag tables. */
+ if (!tag_table)
+ return;
+
+ if (size == 0)
+ size = DEFAULT_SPLIT_SIZE;
+
+ if ((stat (filename, &fileinfo) != 0) ||
+ (fileinfo.st_size < SPLIT_SIZE_THRESHOLD))
+ return;
+
+ the_file = find_and_load (filename);
+ if (!the_file)
+ return;
+
+ root_filename = filename_part (filename);
+ root_pathname = pathname_part (filename);
+
+ if (!root_pathname)
+ root_pathname = savestring ("");
+
+ /* Start splitting the file. Walk along the tag table
+ outputting sections of the file. When we have written
+ all of the nodes in the tag table, make the top-level
+ pointer file, which contains indirect pointers and
+ tags for the nodes. */
+ {
+ int which_file = 1;
+ TAG_ENTRY *tags = tag_table;
+ char *indirect_info = (char *)NULL;
+
+ /* Remember the `header' of this file. The first tag in the file is
+ the bottom of the header; the top of the file is the start. */
+ the_header = (char *)xmalloc (1 + (header_size = tags->position));
+ memcpy (the_header, the_file, header_size);
+
+ while (tags)
+ {
+ int file_top, file_bot, limit;
+
+ /* Have to include the Control-_. */
+ file_top = file_bot = tags->position;
+ limit = file_top + size;
+
+ /* If the rest of this file is only one node, then
+ that is the entire subfile. */
+ if (!tags->next_ent)
+ {
+ int i = tags->position + 1;
+ char last_char = the_file[i];
+
+ while (i < fileinfo.st_size)
+ {
+ if ((the_file[i] == '\037') &&
+ ((last_char == '\n') ||
+ (last_char == '\014')))
+ break;
+ else
+ last_char = the_file[i];
+ i++;
+ }
+ file_bot = i;
+ tags = tags->next_ent;
+ goto write_region;
+ }
+
+ /* Otherwise, find the largest number of nodes that can fit in
+ this subfile. */
+ for (; tags; tags = tags->next_ent)
+ {
+ if (!tags->next_ent)
+ {
+ /* This entry is the last node. Search forward for the end
+ of this node, and that is the end of this file. */
+ int i = tags->position + 1;
+ char last_char = the_file[i];
+
+ while (i < fileinfo.st_size)
+ {
+ if ((the_file[i] == '\037') &&
+ ((last_char == '\n') ||
+ (last_char == '\014')))
+ break;
+ else
+ last_char = the_file[i];
+ i++;
+ }
+ file_bot = i;
+
+ if (file_bot < limit)
+ {
+ tags = tags->next_ent;
+ goto write_region;
+ }
+ else
+ {
+ /* Here we want to write out everything before the last
+ node, and then write the last node out in a file
+ by itself. */
+ file_bot = tags->position;
+ goto write_region;
+ }
+ }
+
+ if (tags->next_ent->position > limit)
+ {
+ if (tags->position == file_top)
+ tags = tags->next_ent;
+
+ file_bot = tags->position;
+
+ write_region:
+ {
+ int fd;
+ char *split_filename;
+
+ split_filename = (char *) xmalloc
+ (10 + strlen (root_pathname) + strlen (root_filename));
+ sprintf
+ (split_filename,
+ "%s%s-%d", root_pathname, root_filename, which_file);
+
+ fd = open
+ (split_filename, O_WRONLY | O_TRUNC | O_CREAT, 0666);
+
+ if ((fd < 0) ||
+ (write (fd, the_header, header_size) != header_size) ||
+ (write (fd, the_file + file_top, file_bot - file_top)
+ != (file_bot - file_top)) ||
+ ((close (fd)) < 0))
+ {
+ perror (split_filename);
+ if (fd != -1)
+ close (fd);
+ exit (FATAL);
+ }
+
+ if (!indirect_info)
+ {
+ indirect_info = the_file + file_top;
+ sprintf (indirect_info, "\037\nIndirect:\n");
+ indirect_info += strlen (indirect_info);
+ }
+
+ sprintf (indirect_info, "%s-%d: %d\n",
+ root_filename, which_file, file_top);
+
+ free (split_filename);
+ indirect_info += strlen (indirect_info);
+ which_file++;
+ break;
+ }
+ }
+ }
+ }
+
+ /* We have sucessfully created the subfiles. Now write out the
+ original again. We must use `output_stream', or
+ write_tag_table_indirect () won't know where to place the output. */
+ output_stream = fopen (filename, "w");
+ if (!output_stream)
+ {
+ perror (filename);
+ exit (FATAL);
+ }
+
+ {
+ int distance = indirect_info - the_file;
+ fwrite (the_file, 1, distance, output_stream);
+
+ /* Inhibit newlines. */
+ paragraph_is_open = 0;
+
+ write_tag_table_indirect ();
+ fclose (output_stream);
+ free (the_header);
+ free (the_file);
+ return;
+ }
+ }
+}
+
+/* Some menu hacking. This is used to remember menu references while
+ reading the input file. After the output file has been written, if
+ validation is on, then we use the contents of NODE_REFERENCES as a
+ list of nodes to validate. */
+char *
+reftype_type_string (type)
+ enum reftype type;
+{
+ switch (type)
+ {
+ case menu_reference:
+ return ("Menu");
+ case followed_reference:
+ return ("Followed-Reference");
+ default:
+ return ("Internal-bad-reference-type");
+ }
+}
+
+/* Remember this node name for later validation use. */
+remember_node_reference (node, line, type)
+ char *node;
+ int line;
+ enum reftype type;
+{
+ NODE_REF *temp = (NODE_REF *) xmalloc (sizeof (NODE_REF));
+
+ temp->next = node_references;
+ temp->node = savestring (node);
+ temp->line_no = line;
+ temp->section = current_section;
+ temp->type = type;
+ temp->containing_node = savestring (current_node);
+ temp->filename = node_filename;
+
+ node_references = temp;
+}
+
+validate_other_references (ref_list)
+ register NODE_REF *ref_list;
+{
+ char *old_input_filename = input_filename;
+
+ while (ref_list != (NODE_REF *) NULL)
+ {
+ input_filename = ref_list->filename;
+ validate (ref_list->node, ref_list->line_no,
+ reftype_type_string (ref_list->type));
+ ref_list = ref_list->next;
+ }
+ input_filename = old_input_filename;
+}
+
+/* Find NODE in REF_LIST. */
+NODE_REF *
+find_node_reference (node, ref_list)
+ char *node;
+ register NODE_REF *ref_list;
+{
+ while (ref_list)
+ {
+ if (strcmp (node, ref_list->node) == 0)
+ break;
+ ref_list = ref_list->next;
+ }
+ return (ref_list);
+}
+
+free_node_references ()
+{
+ register NODE_REF *list, *temp;
+
+ list = node_references;
+
+ while (list)
+ {
+ temp = list;
+ free (list->node);
+ free (list->containing_node);
+ list = list->next;
+ free (temp);
+ }
+ node_references = (NODE_REF *) NULL;
+}
+
+ /* This function gets called at the start of every line while inside of
+ a menu. It checks to see if the line starts with "* ", and if so,
+ remembers the node reference that this menu refers to.
+ input_text_offset is at the \n just before the line start. */
+#define menu_starter "* "
+char *
+glean_node_from_menu (remember_reference)
+ int remember_reference;
+{
+ int i, orig_offset = input_text_offset;
+ char *nodename;
+
+ if (strncmp (&input_text[input_text_offset + 1],
+ menu_starter,
+ strlen (menu_starter)) != 0)
+ return ((char *)NULL);
+ else
+ input_text_offset += strlen (menu_starter) + 1;
+
+ get_until_in_line (":", &nodename);
+ if (curchar () == ':')
+ input_text_offset++;
+ canon_white (nodename);
+
+ if (curchar () == ':')
+ goto save_node;
+
+ free (nodename);
+ get_rest_of_line (&nodename);
+
+ /* Special hack: If the nodename follows the menu item name,
+ then we have to read the rest of the line in order to find
+ out what the nodename is. But we still have to read the
+ line later, in order to process any formatting commands that
+ might be present. So un-count the carriage return that has just
+ been counted. */
+ line_number--;
+
+ isolate_nodename (nodename);
+
+save_node:
+ input_text_offset = orig_offset;
+ normalize_node_name (nodename);
+ i = strlen (nodename);
+ if (i && nodename[i - 1] == ':')
+ nodename[i - 1] = '\0';
+
+ if (remember_reference)
+ {
+ remember_node_reference (nodename, line_number, menu_reference);
+ free (nodename);
+ return ((char *)NULL);
+ }
+ else
+ return (nodename);
+}
+
+static void
+isolate_nodename (nodename)
+ char *nodename;
+{
+ register int i, c;
+ int paren_seen, paren;
+
+ if (!nodename)
+ return;
+
+ canon_white (nodename);
+ paren_seen = paren = i = 0;
+
+ if (*nodename == '.' || !*nodename)
+ {
+ *nodename = '\0';
+ return;
+ }
+
+ if (*nodename == '(')
+ {
+ paren++;
+ paren_seen++;
+ i++;
+ }
+
+ for (; c = nodename[i]; i++)
+ {
+ if (paren)
+ {
+ if (c == '(')
+ paren++;
+ else if (c == ')')
+ paren--;
+
+ continue;
+ }
+
+ /* If the character following the close paren is a space, then this
+ node has no more characters associated with it. */
+ if (c == '\t' ||
+ c == '\n' ||
+ c == ',' ||
+ ((paren_seen && nodename[i - 1] == ')') &&
+ (c == ' ' || c == '.')) ||
+ (c == '.' &&
+ ((!nodename[i + 1] ||
+ (cr_or_whitespace (nodename[i + 1])) ||
+ (nodename[i + 1] == ')')))))
+ break;
+ }
+ nodename[i] = '\0';
+}
+
+cm_menu ()
+{
+ begin_insertion (menu);
+}
+
+
+/* **************************************************************** */
+/* */
+/* Cross Reference Hacking */
+/* */
+/* **************************************************************** */
+
+char *
+get_xref_token ()
+{
+ char *string;
+
+ get_until_in_braces (",", &string);
+ if (curchar () == ',')
+ input_text_offset++;
+ fix_whitespace (string);
+ return (string);
+}
+
+int px_ref_flag = 0; /* Controls initial output string. */
+
+/* Make a cross reference. */
+cm_xref (arg)
+{
+ if (arg == START)
+ {
+ char *arg1, *arg2, *arg3, *arg4, *arg5;
+
+ arg1 = get_xref_token ();
+ arg2 = get_xref_token ();
+ arg3 = get_xref_token ();
+ arg4 = get_xref_token ();
+ arg5 = get_xref_token ();
+
+ add_word_args ("%s", px_ref_flag ? "*note " : "*Note ");
+
+ if (*arg5 || *arg4)
+ {
+ char *node_name;
+
+ if (!*arg2)
+ {
+ if (*arg3)
+ node_name = arg3;
+ else
+ node_name = arg1;
+ }
+ else
+ node_name = arg2;
+
+ execute_string ("%s: (%s)%s", node_name, arg4, arg1);
+ return;
+ }
+ else
+ remember_node_reference (arg1, line_number, followed_reference);
+
+ if (*arg3)
+ {
+ if (!*arg2)
+ execute_string ("%s: %s", arg3, arg1);
+ else
+ execute_string ("%s: %s", arg2, arg1);
+ return;
+ }
+
+ if (*arg2)
+ execute_string ("%s: %s", arg2, arg1);
+ else
+ execute_string ("%s::", arg1);
+ }
+ else
+ {
+
+ /* Check to make sure that the next non-whitespace character is either
+ a period or a comma. input_text_offset is pointing at the "}" which
+ ended the xref or pxref command. */
+ int temp = input_text_offset + 1;
+
+ if (output_paragraph[output_paragraph_offset - 2] == ':' &&
+ output_paragraph[output_paragraph_offset - 1] == ':')
+ return;
+ while (temp < size_of_input_text)
+ {
+ if (cr_or_whitespace (input_text[temp]))
+ temp++;
+ else
+ {
+ if (input_text[temp] == '.' ||
+ input_text[temp] == ',' ||
+ input_text[temp] == '\t')
+ return;
+ else
+ {
+ line_error (
+ "Cross-reference must be terminated with a period or a comma");
+ return;
+ }
+ }
+ }
+ }
+}
+
+cm_pxref (arg)
+ int arg;
+{
+ if (arg == START)
+ {
+ px_ref_flag++;
+ cm_xref (arg);
+ px_ref_flag--;
+ }
+ else
+ add_char ('.');
+}
+
+cm_inforef (arg)
+ int arg;
+{
+ if (arg == START)
+ {
+ char *node, *pname, *file;
+
+ node = get_xref_token ();
+ pname = get_xref_token ();
+ file = get_xref_token ();
+
+ execute_string ("*note %s: (%s)%s", pname, file, node);
+ }
+}
+
+/* **************************************************************** */
+/* */
+/* Insertion Command Stubs */
+/* */
+/* **************************************************************** */
+
+cm_quotation ()
+{
+ begin_insertion (quotation);
+}
+
+cm_example ()
+{
+ begin_insertion (example);
+}
+
+cm_smallexample ()
+{
+ begin_insertion (smallexample);
+}
+
+cm_lisp ()
+{
+ begin_insertion (lisp);
+}
+
+cm_smalllisp ()
+{
+ begin_insertion (smalllisp);
+}
+
+/* @cartouche/@end cartouche draws box with rounded corners in
+ TeX output. Right now, just a NOP insertion. */
+cm_cartouche ()
+{
+ begin_insertion (cartouche);
+}
+
+cm_format ()
+{
+ begin_insertion (format);
+}
+
+cm_display ()
+{
+ begin_insertion (display);
+}
+
+cm_itemize ()
+{
+ begin_insertion (itemize);
+}
+
+cm_enumerate ()
+{
+ do_enumeration (enumerate, "1");
+}
+
+/* Start an enumeration insertion of type TYPE. If the user supplied
+ no argument on the line, then use DEFAULT_STRING as the initial string. */
+do_enumeration (type, default_string)
+ int type;
+ char *default_string;
+{
+ get_until_in_line (".", &enumeration_arg);
+ canon_white (enumeration_arg);
+
+ if (!*enumeration_arg)
+ {
+ free (enumeration_arg);
+ enumeration_arg = savestring (default_string);
+ }
+
+ if (!isdigit (*enumeration_arg) && !isletter (*enumeration_arg))
+ {
+ warning ("%s requires a letter or a digit", insertion_type_pname (type));
+
+ switch (type)
+ {
+ case enumerate:
+ default_string = "1";
+ break;
+ }
+ enumeration_arg = savestring (default_string);
+ }
+ begin_insertion (type);
+}
+
+cm_table ()
+{
+ begin_insertion (table);
+}
+
+cm_ftable ()
+{
+ begin_insertion (ftable);
+}
+
+cm_vtable ()
+{
+ begin_insertion (vtable);
+}
+
+cm_group ()
+{
+ begin_insertion (group);
+}
+
+cm_ifinfo ()
+{
+ begin_insertion (ifinfo);
+}
+
+/* Begin an insertion where the lines are not filled or indented. */
+cm_flushleft ()
+{
+ begin_insertion (flushleft);
+}
+
+/* Begin an insertion where the lines are not filled, and each line is
+ forced to the right-hand side of the page. */
+cm_flushright ()
+{
+ begin_insertion (flushright);
+}
+
+
+/* **************************************************************** */
+/* */
+/* Conditional Handling */
+/* */
+/* **************************************************************** */
+
+/* A structure which contains `defined' variables. */
+typedef struct _defines {
+ struct _defines *next;
+ char *name;
+ char *value;
+} DEFINE;
+
+/* The linked list of `set' defines. */
+DEFINE *defines = (DEFINE *)NULL;
+
+/* Add NAME to the list of `set' defines. */
+set (name, value)
+ char *name;
+ char *value;
+{
+ DEFINE *temp;
+
+ for (temp = defines; temp; temp = temp->next)
+ if (strcmp (name, temp->name) == 0)
+ {
+ free (temp->value);
+ temp->value = savestring (value);
+ return;
+ }
+
+ temp = (DEFINE *)xmalloc (sizeof (DEFINE));
+ temp->next = defines;
+ temp->name = savestring (name);
+ temp->value = savestring (value);
+ defines = temp;
+}
+
+/* Remove NAME from the list of `set' defines. */
+clear (name)
+ char *name;
+{
+ register DEFINE *temp, *last;
+
+ last = (DEFINE *)NULL;
+ temp = defines;
+
+ while (temp)
+ {
+ if (strcmp (temp->name, name) == 0)
+ {
+ if (last)
+ last->next = temp->next;
+ else
+ defines = temp->next;
+
+ free (temp->name);
+ free (temp->value);
+ free (temp);
+ break;
+ }
+ last = temp;
+ temp = temp->next;
+ }
+}
+
+/* Return the value of NAME. The return value is NULL if NAME is unset. */
+char *
+set_p (name)
+ char *name;
+{
+ register DEFINE *temp;
+
+ for (temp = defines; temp; temp = temp->next)
+ if (strcmp (temp->name, name) == 0)
+ return (temp->value);
+
+ return ((char *)NULL);
+}
+
+/* Conditionally parse based on the current command name. */
+command_name_condition ()
+{
+ char *discarder;
+
+ discarder = (char *)xmalloc (8 + strlen (command));
+
+ sprintf (discarder, "\n@end %s", command);
+ discard_until (discarder);
+ discard_until ("\n");
+
+ free (discarder);
+}
+
+/* Create a variable whose name appears as the first word on this line. */
+cm_set ()
+{
+ handle_variable (SET);
+}
+
+/* Remove a variable whose name appears as the first word on this line. */
+cm_clear ()
+{
+ handle_variable (CLEAR);
+}
+
+cm_ifset ()
+{
+ handle_variable (IFSET);
+}
+
+cm_ifclear ()
+{
+ handle_variable (IFCLEAR);
+}
+
+cm_value (arg, start_pos, end_pos)
+ int arg, start_pos, end_pos;
+{
+ if (arg == END)
+ {
+ char *name, *value;
+ name = (char *)&output_paragraph[start_pos];
+ output_paragraph[end_pos] = '\0';
+ name = savestring (name);
+ value = set_p (name);
+ output_column -= end_pos - start_pos;
+ output_paragraph_offset = start_pos;
+
+ if (value)
+ execute_string ("%s", value);
+ else
+ add_word_args ("{No Value For \"%s\"}", name);
+
+ free (name);
+ }
+}
+
+/* Set, clear, or conditionalize based on ACTION. */
+handle_variable (action)
+ int action;
+{
+ char *name;
+
+ get_rest_of_line (&name);
+ backup_input_pointer ();
+ canon_white (name);
+ handle_variable_internal (action, name);
+ free (name);
+}
+
+handle_variable_internal (action, name)
+ int action;
+ char *name;
+{
+ char *temp;
+ int delimiter, additional_text_present = 0;
+
+ /* Only the first word of NAME is a valid tag. */
+ temp = name;
+ delimiter = 0;
+ while (*temp && (delimiter || !whitespace (*temp)))
+ {
+#if defined (SET_WITH_EQUAL)
+ if (*temp == '"' || *temp == '\'')
+ {
+ if (*temp == delimiter)
+ delimiter = 0;
+ else
+ delimiter = *temp;
+ }
+#endif /* SET_WITH_EQUAL */
+ temp++;
+ }
+
+ if (*temp)
+ additional_text_present++;
+
+ *temp = '\0';
+
+ if (!*name)
+ line_error ("@%s requires a name", command);
+ else
+ {
+ switch (action)
+ {
+ case SET:
+ {
+ char *value;
+
+#if defined (SET_WITH_EQUAL)
+ /* Allow a value to be saved along with a variable. The value is
+ the text following an `=' sign in NAME, if any is present. */
+
+ for (value = name; *value && *value != '='; value++);
+
+ if (*value)
+ *value++ = '\0';
+
+ if (*value == '"' || *value == '\'')
+ {
+ value++;
+ value[strlen (value) - 1] = '\0';
+ }
+
+#else /* !SET_WITH_EQUAL */
+ /* The VALUE of NAME is the remainder of the line sans
+ whitespace. */
+ if (additional_text_present)
+ {
+ value = temp + 1;
+ canon_white (value);
+ }
+ else
+ value = "";
+#endif /* !SET_WITH_VALUE */
+
+ set (name, value);
+ }
+ break;
+
+ case CLEAR:
+ clear (name);
+ break;
+
+ case IFSET:
+ case IFCLEAR:
+ /* If IFSET and NAME is not set, or if IFCLEAR and NAME is set,
+ read lines from the the file until we reach a matching
+ "@end CONDITION". This means that we only take note of
+ "@ifset/clear" and "@end" commands. */
+ {
+ char condition[8];
+ int condition_len;
+
+ if (action == IFSET)
+ strcpy (condition, "ifset");
+ else
+ strcpy (condition, "ifclear");
+
+ condition_len = strlen (condition);
+
+ if ((action == IFSET && !set_p (name)) ||
+ (action == IFCLEAR && set_p (name)))
+ {
+ int level = 0, done = 0;
+
+ while (!done)
+ {
+ char *freeable_line, *line;
+
+ get_rest_of_line (&freeable_line);
+
+ for (line = freeable_line; whitespace (*line); line++);
+
+ if (*line == COMMAND_PREFIX &&
+ (strncmp (line + 1, condition, condition_len) == 0))
+ level++;
+ else if (strncmp (line, "@end", 4) == 0)
+ {
+ char *cname = line + 4;
+ char *temp;
+
+ while (*cname && whitespace (*cname))
+ cname++;
+ temp = cname;
+
+ while (*temp && !whitespace (*temp))
+ temp++;
+ *temp = '\0';
+
+ if (strcmp (cname, condition) == 0)
+ {
+ if (!level)
+ {
+ done = 1;
+ }
+ else
+ level--;
+ }
+ }
+ free (freeable_line);
+ }
+ /* We found the end of a false @ifset/ifclear. If we are
+ in a menu, back up over the newline that ends the ifset,
+ since that newline may also begin the next menu entry. */
+ break;
+ }
+ else
+ {
+ if (action == IFSET)
+ begin_insertion (ifset);
+ else
+ begin_insertion (ifclear);
+ }
+ }
+ break;
+ }
+ }
+}
+
+/* **************************************************************** */
+/* */
+/* @itemx, @item */
+/* */
+/* **************************************************************** */
+
+/* Non-zero means a string is in execution, as opposed to a file. */
+int executing_string = 0;
+
+/* Execute the string produced by formatting the ARGs with FORMAT. This
+ is like submitting a new file with @include. */
+#if defined (HAVE_VARARGS_H) && defined(HAVE_VSPRINTF)
+
+execute_string (va_alist)
+ va_dcl
+{
+ static char temp_string[4000];
+ char *format;
+ va_list args;
+
+ va_start (args);
+ format = va_arg (args, char *);
+ vsprintf (temp_string, format, args);
+ va_end (args);
+
+#else /* !(HAVE_VARARGS_H && HAVE_VSPRINTF) */
+
+execute_string (format, arg1, arg2, arg3, arg4, arg5)
+ char *format;
+{
+ static char temp_string[4000];
+ sprintf (temp_string, format, arg1, arg2, arg3, arg4, arg5);
+
+#endif /* !(HAVE_VARARGS_H && HAVE_VSPRINTF) */
+
+ strcat (temp_string, "@bye\n");
+ pushfile ();
+ input_text_offset = 0;
+ input_text = temp_string;
+ input_filename = savestring (input_filename);
+ size_of_input_text = strlen (temp_string);
+
+ executing_string++;
+ reader_loop ();
+
+ popfile ();
+ executing_string--;
+
+ free_and_clear (&command);
+ command = savestring ("not bye");
+}
+
+int itemx_flag = 0;
+
+cm_itemx ()
+{
+ itemx_flag++;
+ cm_item ();
+ itemx_flag--;
+}
+
+cm_item ()
+{
+ char *rest_of_line, *item_func;
+
+ /* Can only hack "@item" while inside of an insertion. */
+ if (insertion_level)
+ {
+ INSERTION_ELT *stack = insertion_stack;
+ int original_input_text_offset;
+
+ skip_whitespace ();
+ original_input_text_offset = input_text_offset;
+
+ get_rest_of_line (&rest_of_line);
+ canon_white (rest_of_line);
+ item_func = current_item_function ();
+
+ /* Okay, do the right thing depending on which insertion function
+ is active. */
+
+ switch_top:
+ switch (stack->insertion)
+ {
+ case ifinfo:
+ case ifset:
+ case ifclear:
+ case cartouche:
+ stack = stack->next;
+ if (!stack)
+ goto no_insertion;
+ else
+ goto switch_top;
+ break;
+
+ case menu:
+ case quotation:
+ case example:
+ case smallexample:
+ case lisp:
+ case format:
+ case display:
+ case group:
+ line_error ("The `@%s' command is meaningless within a `@%s' block",
+ command,
+ insertion_type_pname (current_insertion_type ()));
+ break;
+
+ case itemize:
+ case enumerate:
+ if (itemx_flag)
+ {
+ line_error ("@itemx is not meaningful inside of a `%s' block",
+ insertion_type_pname (current_insertion_type ()));
+ }
+ else
+ {
+ start_paragraph ();
+ kill_self_indent (-1);
+ filling_enabled = indented_fill = 1;
+
+ if (current_insertion_type () == itemize)
+ {
+ indent (output_column = current_indent - 2);
+
+ /* I need some way to determine whether this command
+ takes braces or not. I believe the user can type
+ either "@bullet" or "@bullet{}". Of course, they
+ can also type "o" or "#" or whatever else they want. */
+ if (item_func && *item_func)
+ {
+ if (*item_func == '@')
+ if (item_func[strlen (item_func) - 1] != '}')
+ execute_string ("%s{}", item_func);
+ else
+ execute_string ("%s", item_func);
+ else
+ execute_string ("%s", item_func);
+ }
+ insert (' ');
+ output_column++;
+ }
+ else
+ enumerate_item ();
+
+ /* Special hack. This makes close paragraph ignore you until
+ the start_paragraph () function has been called. */
+ must_start_paragraph = 1;
+
+ /* Ultra special hack. It appears that some people incorrectly
+ place text directly after the @item, instead of on a new line
+ by itself. This happens to work in TeX, so I make it work
+ here. */
+ if (*rest_of_line)
+ {
+ line_number--;
+ input_text_offset = original_input_text_offset;
+ }
+ }
+ break;
+
+ case table:
+ case ftable:
+ case vtable:
+ {
+ /* Get rid of extra characters. */
+ kill_self_indent (-1);
+
+ /* close_paragraph () almost does what we want. The problem
+ is when paragraph_is_open, and last_char_was_newline, and
+ the last newline has been turned into a space, because
+ filling_enabled. I handle it here. */
+ if (last_char_was_newline && filling_enabled && paragraph_is_open)
+ insert ('\n');
+ close_paragraph ();
+
+#if defined (INDENT_PARAGRAPHS_IN_TABLE)
+ /* Indent on a new line, but back up one indentation level. */
+ {
+ int t;
+
+ t = inhibit_paragraph_indentation;
+ inhibit_paragraph_indentation = 1;
+ /* At this point, inserting any non-whitespace character will
+ force the existing indentation to be output. */
+ add_char ('i');
+ inhibit_paragraph_indentation = t;
+ }
+#else /* !INDENT_PARAGRAPHS_IN_TABLE */
+ add_char ('i');
+#endif /* !INDENT_PARAGRAPHS_IN_TABLE */
+
+ output_paragraph_offset--;
+ kill_self_indent (default_indentation_increment + 1);
+
+ /* Add item's argument to the line. */
+ filling_enabled = 0;
+ if (item_func && *item_func)
+ execute_string ("%s{%s}", item_func, rest_of_line);
+ else
+ execute_string ("%s", rest_of_line);
+
+ if (current_insertion_type () == ftable)
+ execute_string ("@findex %s\n", rest_of_line);
+
+ if (current_insertion_type () == vtable)
+ execute_string ("@vindex %s\n", rest_of_line);
+
+ /* Start a new line, and let start_paragraph ()
+ do the indenting of it for you. */
+ close_single_paragraph ();
+ indented_fill = filling_enabled = 1;
+ }
+ }
+ free (rest_of_line);
+ }
+ else
+ {
+ no_insertion:
+ line_error ("@%s found outside of an insertion block", command);
+ }
+}
+
+
+/* **************************************************************** */
+/* */
+/* Defun and Friends */
+/* */
+/* **************************************************************** */
+
+#define DEFUN_SELF_DELIMITING(c) \
+ (((c) == '(') \
+ || ((c) == ')') \
+ || ((c) == '[') \
+ || ((c) == ']'))
+
+struct token_accumulator
+{
+ unsigned int length;
+ unsigned int index;
+ char **tokens;
+};
+
+void
+initialize_token_accumulator (accumulator)
+ struct token_accumulator *accumulator;
+{
+ (accumulator->length) = 0;
+ (accumulator->index) = 0;
+ (accumulator->tokens) = NULL;
+}
+
+void
+accumulate_token (accumulator, token)
+ struct token_accumulator *accumulator;
+ char *token;
+{
+ if ((accumulator->index) >= (accumulator->length))
+ {
+ (accumulator->length) += 10;
+ (accumulator->tokens) = (char **) xrealloc
+ (accumulator->tokens, (accumulator->length * sizeof (char *)));
+ }
+ accumulator->tokens[accumulator->index] = token;
+ accumulator->index += 1;
+}
+
+char *
+copy_substring (start, end)
+ char *start;
+ char *end;
+{
+ char *result, *scan, *scan_result;
+
+ result = (char *) xmalloc ((end - start) + 1);
+ scan_result = result;
+ scan = start;
+
+ while (scan < end)
+ *scan_result++ = *scan++;
+
+ *scan_result = '\0';
+ return (result);
+}
+
+/* Given `string' pointing at an open brace, skip forward and return a
+ pointer to just past the matching close brace. */
+int
+scan_group_in_string (string_pointer)
+ char **string_pointer;
+{
+ register int c;
+ register char *scan_string;
+ register unsigned int level = 1;
+
+ scan_string = (*string_pointer) + 1;
+
+ while (1)
+ {
+ if (level == 0)
+ {
+ (*string_pointer) = scan_string;
+ return (1);
+ }
+ c = (*scan_string++);
+ if (c == '\0')
+ {
+ /* Tweak line_number to compensate for fact that
+ we gobbled the whole line before coming here. */
+ line_number -= 1;
+ line_error ("Missing `}' in @def arg");
+ line_number += 1;
+ (*string_pointer) = (scan_string - 1);
+ return (0);
+ }
+ if (c == '{')
+ level += 1;
+ if (c == '}')
+ level -= 1;
+ }
+}
+
+/* Return a list of tokens from the contents of `string'.
+ Commands and brace-delimited groups count as single tokens.
+ Contiguous whitespace characters are converted to a token
+ consisting of a single space. */
+char **
+args_from_string (string)
+ char *string;
+{
+ struct token_accumulator accumulator;
+ register char *scan_string = string;
+ char *token_start, *token_end;
+
+ initialize_token_accumulator (&accumulator);
+
+ while ((*scan_string) != '\0')
+ {
+ /* Replace arbitrary whitespace by a single space. */
+ if (whitespace (*scan_string))
+ {
+ scan_string += 1;
+ while (whitespace (*scan_string))
+ scan_string += 1;
+ accumulate_token ((&accumulator), (savestring (" ")));
+ continue;
+ }
+
+ /* Commands count as single tokens. */
+ if ((*scan_string) == COMMAND_PREFIX)
+ {
+ token_start = scan_string;
+ scan_string += 1;
+ if (self_delimiting (*scan_string))
+ scan_string += 1;
+ else
+ {
+ register int c;
+ while (1)
+ {
+ c = *scan_string++;
+
+ if ((c == '\0') || (c == '{') || (whitespace (c)))
+ {
+ scan_string -= 1;
+ break;
+ }
+ }
+
+ if (*scan_string == '{')
+ {
+ char *s = scan_string;
+ (void) scan_group_in_string (&s);
+ scan_string = s;
+ }
+ }
+ token_end = scan_string;
+ }
+
+ /* Parentheses and brackets are self-delimiting. */
+ else if (DEFUN_SELF_DELIMITING (*scan_string))
+ {
+ token_start = scan_string;
+ scan_string += 1;
+ token_end = scan_string;
+ }
+
+ /* Open brace introduces a group that is a single token. */
+ else if (*scan_string == '{')
+ {
+ char *s = scan_string;
+ int balanced = scan_group_in_string (&s);
+
+ token_start = scan_string + 1;
+ scan_string = s;
+ token_end = balanced ? (scan_string - 1) : scan_string;
+ }
+
+ /* Otherwise a token is delimited by whitespace, parentheses,
+ brackets, or braces. A token is also ended by a command. */
+ else
+ {
+ token_start = scan_string;
+
+ while (1)
+ {
+ register int c;
+
+ c = *scan_string++;
+
+ if (!c ||
+ (whitespace (c) || DEFUN_SELF_DELIMITING (c) ||
+ c == '{' || c == '}'))
+ {
+ scan_string--;
+ break;
+ }
+
+ /* If we encounter a command imbedded within a token,
+ then end the token. */
+ if (c == COMMAND_PREFIX)
+ {
+ scan_string--;
+ break;
+ }
+ }
+ token_end = scan_string;
+ }
+
+ accumulate_token
+ (&accumulator, copy_substring (token_start, token_end));
+ }
+ accumulate_token (&accumulator, NULL);
+ return (accumulator.tokens);
+}
+
+void
+process_defun_args (defun_args, auto_var_p)
+ char **defun_args;
+ int auto_var_p;
+{
+ int pending_space = 0;
+
+ while (1)
+ {
+ char *defun_arg = *defun_args++;
+
+ if (defun_arg == NULL)
+ break;
+
+ if (defun_arg[0] == ' ')
+ {
+ pending_space = 1;
+ continue;
+ }
+
+ if (pending_space)
+ {
+ add_char (' ');
+ pending_space = 0;
+ }
+
+ if (DEFUN_SELF_DELIMITING (defun_arg[0]))
+ add_char (defun_arg[0]);
+ else if (defun_arg[0] == '&')
+ add_word (defun_arg);
+ else if (defun_arg[0] == COMMAND_PREFIX)
+ execute_string ("%s", defun_arg);
+ else if (auto_var_p)
+ execute_string ("@var{%s}", defun_arg);
+ else
+ add_word (defun_arg);
+ }
+}
+
+char *
+next_nonwhite_defun_arg (arg_pointer)
+ char ***arg_pointer;
+{
+ char **scan = (*arg_pointer);
+ char *arg = (*scan++);
+
+ if ((arg != 0) && (*arg == ' '))
+ arg = *scan++;
+
+ if (arg == 0)
+ scan -= 1;
+
+ *arg_pointer = scan;
+
+ return ((arg == 0) ? "" : arg);
+}
+
+/* Make the defun type insertion.
+ TYPE says which insertion this is.
+ X_P says not to start a new insertion if non-zero. */
+void
+defun_internal (type, x_p)
+ enum insertion_type type;
+ int x_p;
+{
+ enum insertion_type base_type;
+ char **defun_args, **scan_args;
+ char *category, *defined_name, *type_name, *type_name2;
+
+ {
+ char *line;
+ get_rest_of_line (&line);
+ defun_args = (args_from_string (line));
+ free (line);
+ }
+
+ scan_args = defun_args;
+
+ switch (type)
+ {
+ case defun:
+ category = "Function";
+ base_type = deffn;
+ break;
+ case defmac:
+ category = "Macro";
+ base_type = deffn;
+ break;
+ case defspec:
+ category = "Special Form";
+ base_type = deffn;
+ break;
+ case defvar:
+ category = "Variable";
+ base_type = defvr;
+ break;
+ case defopt:
+ category = "User Option";
+ base_type = defvr;
+ break;
+ case deftypefun:
+ category = "Function";
+ base_type = deftypefn;
+ break;
+ case deftypevar:
+ category = "Variable";
+ base_type = deftypevr;
+ break;
+ case defivar:
+ category = "Instance Variable";
+ base_type = defcv;
+ break;
+ case defmethod:
+ category = "Method";
+ base_type = defop;
+ break;
+ case deftypemethod:
+ category = "Method";
+ base_type = deftypemethod;
+ break;
+ default:
+ category = next_nonwhite_defun_arg (&scan_args);
+ base_type = type;
+ break;
+ }
+
+ if ((base_type == deftypefn)
+ || (base_type == deftypevr)
+ || (base_type == defcv)
+ || (base_type == defop)
+ || (base_type == deftypemethod))
+ type_name = next_nonwhite_defun_arg (&scan_args);
+
+ if (base_type == deftypemethod)
+ type_name2 = next_nonwhite_defun_arg (&scan_args);
+
+ defined_name = next_nonwhite_defun_arg (&scan_args);
+
+ /* This hack exists solely for the purposes of formatting the texinfo
+ manual. I couldn't think of a better way. The token might be
+ a simple @@ followed immediately by more text. If this is the case,
+ then the next defun arg is part of this one, and we should concatenate
+ them. */
+ if (*scan_args && **scan_args && !whitespace (**scan_args) &&
+ (strcmp (defined_name, "@@") == 0))
+ {
+ char *tem = (char *)xmalloc (3 + strlen (scan_args[0]));
+
+ sprintf (tem, "@@%s", scan_args[0]);
+
+ free (scan_args[0]);
+ scan_args[0] = tem;
+ scan_args++;
+ defined_name = tem;
+ }
+
+ if (!x_p)
+ begin_insertion (type);
+
+ /* Write the definition header line.
+ This should start at the normal indentation. */
+ current_indent -= default_indentation_increment;
+ start_paragraph ();
+
+ switch (base_type)
+ {
+ case deffn:
+ case defvr:
+ case deftp:
+ execute_string (" -- %s: %s", category, defined_name);
+ break;
+ case deftypefn:
+ case deftypevr:
+ execute_string (" -- %s: %s %s", category, type_name, defined_name);
+ break;
+ case defcv:
+ execute_string (" -- %s of %s: %s", category, type_name, defined_name);
+ break;
+ case defop:
+ execute_string (" -- %s on %s: %s", category, type_name, defined_name);
+ break;
+ case deftypemethod:
+ execute_string (" -- %s on %s: %s %s", category, type_name, type_name2,
+ defined_name);
+ break;
+ }
+ current_indent += default_indentation_increment;
+
+ /* Now process the function arguments, if any.
+ If these carry onto the next line, they should be indented by two
+ increments to distinguish them from the body of the definition,
+ which is indented by one increment. */
+ current_indent += default_indentation_increment;
+
+ switch (base_type)
+ {
+ case deffn:
+ case defop:
+ process_defun_args (scan_args, 1);
+ break;
+ case deftp:
+ case deftypefn:
+ case deftypemethod:
+ process_defun_args (scan_args, 0);
+ break;
+ }
+ current_indent -= default_indentation_increment;
+ close_single_paragraph ();
+
+ /* Make an entry in the appropriate index. */
+ switch (base_type)
+ {
+ case deffn:
+ case deftypefn:
+ execute_string ("@findex %s\n", defined_name);
+ break;
+ case defvr:
+ case deftypevr:
+ case defcv:
+ execute_string ("@vindex %s\n", defined_name);
+ break;
+ case defop:
+ case deftypemethod:
+ execute_string ("@findex %s on %s\n", defined_name, type_name);
+ break;
+ case deftp:
+ execute_string ("@tindex %s\n", defined_name);
+ break;
+ }
+
+ /* Deallocate the token list. */
+ scan_args = defun_args;
+ while (1)
+ {
+ char * arg = (*scan_args++);
+ if (arg == NULL)
+ break;
+ free (arg);
+ }
+ free (defun_args);
+}
+
+/* Add an entry for a function, macro, special form, variable, or option.
+ If the name of the calling command ends in `x', then this is an extra
+ entry included in the body of an insertion of the same type. */
+cm_defun ()
+{
+ int x_p;
+ enum insertion_type type;
+ char *temp = savestring (command);
+
+ x_p = (command[strlen (command) - 1] == 'x');
+
+ if (x_p)
+ temp[strlen (temp) - 1] = '\0';
+
+ type = find_type_from_name (temp);
+ free (temp);
+
+ /* If we are adding to an already existing insertion, then make sure
+ that we are already in an insertion of type TYPE. */
+ if (x_p &&
+ (!insertion_level || insertion_stack->insertion != type))
+ {
+ line_error ("Must be in a `%s' insertion in order to use `%s'x",
+ command, command);
+ discard_until ("\n");
+ return;
+ }
+
+ defun_internal (type, x_p);
+}
+
+/* End existing insertion block. */
+cm_end ()
+{
+ char *temp;
+ enum insertion_type type;
+
+ if (!insertion_level)
+ {
+ line_error ("Unmatched `@%s'", command);
+ return;
+ }
+
+ get_rest_of_line (&temp);
+ canon_white (temp);
+
+ if (strlen (temp) == 0)
+ line_error ("`@%s' needs something after it", command);
+
+ type = find_type_from_name (temp);
+
+ if (type == bad_type)
+ {
+ line_error ("Bad argument to `%s', `%s', using `%s'",
+ command, temp, insertion_type_pname (current_insertion_type ()));
+ }
+ end_insertion (type);
+ free (temp);
+}
+
+
+/* **************************************************************** */
+/* */
+/* Other Random Commands */
+/* */
+/* **************************************************************** */
+
+/* This says to inhibit the indentation of the next paragraph, but
+ not of following paragraphs. */
+cm_noindent ()
+{
+ if (!inhibit_paragraph_indentation)
+ inhibit_paragraph_indentation = -1;
+}
+
+/* I don't know exactly what to do with this. Should I allow
+ someone to switch filenames in the middle of output? Since the
+ file could be partially written, this doesn't seem to make sense.
+ Another option: ignore it, since they don't *really* want to
+ switch files. Finally, complain, or at least warn. */
+cm_setfilename ()
+{
+ char *filename;
+ get_rest_of_line (&filename);
+ /* warning ("`@%s %s' encountered and ignored", command, filename); */
+ free (filename);
+}
+
+cm_ignore_line ()
+{
+ discard_until ("\n");
+}
+
+/* @br can be immediately followed by `{}', so we have to read those here.
+ It should simply close the paragraph. */
+cm_br ()
+{
+ if (looking_at ("{}"))
+ input_text_offset += 2;
+
+ if (curchar () == '\n')
+ {
+ input_text_offset++;
+ line_number++;
+ }
+
+ close_paragraph ();
+}
+
+ /* Insert the number of blank lines passed as argument. */
+cm_sp ()
+{
+ int lines;
+ char *line;
+
+ get_rest_of_line (&line);
+
+ if (sscanf (line, "%d", &lines) != 1)
+ {
+ line_error ("%csp requires a positive numeric argument", COMMAND_PREFIX);
+ }
+ else
+ {
+ if (lines < 0)
+ lines = 0;
+
+ while (lines--)
+ add_char ('\n');
+ }
+ free (line);
+}
+
+/* Start a new line with just this text on it.
+ Then center the line of text.
+ This always ends the current paragraph. */
+cm_center ()
+{
+ register int i, start, length;
+ int fudge_factor = 1;
+ unsigned char *line;
+
+ close_paragraph ();
+ filling_enabled = indented_fill = 0;
+ cm_noindent ();
+ start = output_paragraph_offset;
+ inhibit_output_flushing ();
+ get_rest_of_line ((char **)&line);
+ execute_string ((char *)line);
+ free (line);
+ uninhibit_output_flushing ();
+
+ i = output_paragraph_offset - 1;
+ while (i > (start - 1) && output_paragraph[i] == '\n')
+ i--;
+
+ output_paragraph_offset = ++i;
+ length = output_paragraph_offset - start;
+
+ if (length < (fill_column - fudge_factor))
+ {
+ line = (unsigned char *)xmalloc (1 + length);
+ memcpy (line, (char *)(output_paragraph + start), length);
+
+ i = (fill_column - fudge_factor - length) / 2;
+ output_paragraph_offset = start;
+
+ while (i--)
+ insert (' ');
+
+ for (i = 0; i < length; i++)
+ insert (line[i]);
+
+ free (line);
+ }
+
+ insert ('\n');
+ close_paragraph ();
+ filling_enabled = 1;
+}
+
+/* Show what an expression returns. */
+cm_result (arg)
+ int arg;
+{
+ if (arg == END)
+ add_word ("=>");
+}
+
+/* What an expression expands to. */
+cm_expansion (arg)
+ int arg;
+{
+ if (arg == END)
+ add_word ("==>");
+}
+
+/* Indicates two expressions are equivalent. */
+cm_equiv (arg)
+ int arg;
+{
+ if (arg == END)
+ add_word ("==");
+}
+
+/* What an expression may print. */
+cm_print (arg)
+ int arg;
+{
+ if (arg == END)
+ add_word ("-|");
+}
+
+/* An error signaled. */
+cm_error (arg)
+ int arg;
+{
+ if (arg == END)
+ add_word ("error-->");
+}
+
+/* The location of point in an example of a buffer. */
+cm_point (arg)
+ int arg;
+{
+ if (arg == END)
+ add_word ("-!-");
+}
+
+/* Start a new line with just this text on it.
+ The text is outdented one level if possible. */
+cm_exdent ()
+{
+ char *line;
+ int i = current_indent;
+
+ if (current_indent)
+ current_indent -= default_indentation_increment;
+
+ get_rest_of_line (&line);
+ close_single_paragraph ();
+ execute_string ("%s", line);
+ current_indent = i;
+ free (line);
+ close_single_paragraph ();
+}
+
+cm_include ()
+{
+ cm_infoinclude ();
+}
+
+/* Remember this file, and move onto the next. */
+cm_infoinclude ()
+{
+ char *filename;
+
+ close_paragraph ();
+ get_rest_of_line (&filename);
+ pushfile ();
+
+ /* In verbose mode we print info about including another file. */
+ if (verbose_mode)
+ {
+ register int i = 0;
+ register FSTACK *stack = filestack;
+
+ for (i = 0, stack = filestack; stack; stack = stack->next, i++);
+
+ i *= 2;
+
+ printf ("%*s", i, "");
+ printf ("%c%s %s\n", COMMAND_PREFIX, command, filename);
+ fflush (stdout);
+ }
+
+ if (!find_and_load (filename))
+ {
+ extern const char * const sys_errlist[];
+ extern int errno, sys_nerr;
+ popfile ();
+
+ /* Cannot "@include foo", in line 5 of "/wh/bar". */
+ line_error ("`%c%s %s': %s", COMMAND_PREFIX, command, filename,
+ ((errno < sys_nerr) ?
+ sys_errlist[errno] : "Unknown file system error"));
+ }
+ free (filename);
+}
+
+/* The other side of a malformed expression. */
+misplaced_brace ()
+{
+ line_error ("Misplaced `}'");
+}
+
+/* Don't let the filling algorithm insert extra whitespace here. */
+cm_force_abbreviated_whitespace ()
+{
+}
+
+/* Do not let this character signify the end of a sentence, though
+ if it was seen without the command prefix it normally would. We
+ do this by turning on the 8th bit of the character. */
+cm_ignore_sentence_ender ()
+{
+ add_char (META ((*command)));
+}
+
+/* Signals end of processing. Easy to make this happen. */
+cm_bye ()
+{
+ input_text_offset = size_of_input_text;
+}
+
+cm_asis ()
+{
+}
+
+cm_math ()
+{
+}
+
+
+/* **************************************************************** */
+/* */
+/* Indexing Stuff */
+/* */
+/* **************************************************************** */
+
+
+/* An index element... */
+typedef struct index_elt
+{
+ struct index_elt *next;
+ char *entry; /* The index entry itself. */
+ char *node; /* The node from whence it came. */
+ int code; /* Non-zero means add `@code{...}' when
+ printing this element. */
+ int defining_line; /* Line number where this entry was written. */
+} INDEX_ELT;
+
+/* A list of short-names for each index, and the index to that index in our
+ index array, the_indices. In addition, for each index, it is remembered
+ whether that index is a code index or not. Code indices have @code{}
+ inserted around the first word when they are printed with printindex. */
+typedef struct
+{
+ char *name;
+ int index;
+ int code;
+} INDEX_ALIST;
+
+INDEX_ALIST **name_index_alist = (INDEX_ALIST **) NULL;
+
+/* An array of pointers. Each one is for a different index. The
+ "synindex" command changes which array slot is pointed to by a
+ given "index". */
+INDEX_ELT **the_indices = (INDEX_ELT **) NULL;
+
+/* The number of defined indices. */
+int defined_indices = 0;
+
+/* We predefine these. */
+#define program_index 0
+#define function_index 1
+#define concept_index 2
+#define variable_index 3
+#define datatype_index 4
+#define key_index 5
+
+init_indices ()
+{
+ int i;
+
+ /* Create the default data structures. */
+
+ /* Initialize data space. */
+ if (!the_indices)
+ {
+ the_indices = (INDEX_ELT **) xmalloc ((1 + defined_indices) *
+ sizeof (INDEX_ELT *));
+ the_indices[defined_indices] = (INDEX_ELT *) NULL;
+
+ name_index_alist = (INDEX_ALIST **) xmalloc ((1 + defined_indices) *
+ sizeof (INDEX_ALIST *));
+ name_index_alist[defined_indices] = (INDEX_ALIST *) NULL;
+ }
+
+ /* If there were existing indices, get rid of them now. */
+ for (i = 0; i < defined_indices; i++)
+ undefindex (name_index_alist[i]->name);
+
+ /* Add the default indices. */
+ defindex ("pg", 0);
+ defindex ("fn", 1); /* "fn" is a code index. */
+ defindex ("cp", 0);
+ defindex ("vr", 0);
+ defindex ("tp", 0);
+ defindex ("ky", 0);
+
+}
+
+/* Find which element in the known list of indices has this name.
+ Returns -1 if NAME isn't found. */
+int
+find_index_offset (name)
+ char *name;
+{
+ register int i;
+ for (i = 0; i < defined_indices; i++)
+ if (name_index_alist[i] &&
+ strcmp (name, name_index_alist[i]->name) == 0)
+ return (name_index_alist[i]->index);
+ return (-1);
+}
+
+/* Return a pointer to the entry of (name . index) for this name.
+ Return NULL if the index doesn't exist. */
+INDEX_ALIST *
+find_index (name)
+ char *name;
+{
+ int offset = find_index_offset (name);
+ if (offset > -1)
+ return (name_index_alist[offset]);
+ else
+ return ((INDEX_ALIST *) NULL);
+}
+
+/* Given an index name, return the offset in the_indices of this index,
+ or -1 if there is no such index. */
+translate_index (name)
+ char *name;
+{
+ INDEX_ALIST *which = find_index (name);
+
+ if (which)
+ return (which->index);
+ else
+ return (-1);
+}
+
+/* Return the index list which belongs to NAME. */
+INDEX_ELT *
+index_list (name)
+ char *name;
+{
+ int which = translate_index (name);
+ if (which < 0)
+ return ((INDEX_ELT *) - 1);
+ else
+ return (the_indices[which]);
+}
+
+/* Please release me, let me go... */
+free_index (index)
+ INDEX_ELT *index;
+{
+ INDEX_ELT *temp;
+
+ while ((temp = index) != (INDEX_ELT *) NULL)
+ {
+ free (temp->entry);
+ free (temp->node);
+ index = index->next;
+ free (temp);
+ }
+}
+
+/* Flush an index by name. */
+undefindex (name)
+ char *name;
+{
+ int i;
+ int which = find_index_offset (name);
+
+ if (which < 0)
+ return (which);
+
+ i = name_index_alist[which]->index;
+
+
+ free_index (the_indices[i]);
+ the_indices[i] = (INDEX_ELT *) NULL;
+
+ free (name_index_alist[which]->name);
+ free (name_index_alist[which]);
+ name_index_alist[which] = (INDEX_ALIST *) NULL;
+}
+
+/* Define an index known as NAME. We assign the slot number.
+ CODE if non-zero says to make this a code index. */
+defindex (name, code)
+ char *name;
+ int code;
+{
+ register int i, slot;
+
+ /* If it already exists, flush it. */
+ undefindex (name);
+
+ /* Try to find an empty slot. */
+ slot = -1;
+ for (i = 0; i < defined_indices; i++)
+ if (!name_index_alist[i])
+ {
+ slot = i;
+ break;
+ }
+
+ if (slot < 0)
+ {
+ /* No such luck. Make space for another index. */
+ slot = defined_indices;
+ defined_indices++;
+
+ name_index_alist = (INDEX_ALIST **)
+ xrealloc ((char *)name_index_alist,
+ (1 + defined_indices) * sizeof (INDEX_ALIST *));
+ the_indices = (INDEX_ELT **)
+ xrealloc ((char *)the_indices,
+ (1 + defined_indices) * sizeof (INDEX_ELT *));
+ }
+
+ /* We have a slot. Start assigning. */
+ name_index_alist[slot] = (INDEX_ALIST *) xmalloc (sizeof (INDEX_ALIST));
+ name_index_alist[slot]->name = savestring (name);
+ name_index_alist[slot]->index = slot;
+ name_index_alist[slot]->code = code;
+
+ the_indices[slot] = (INDEX_ELT *) NULL;
+}
+
+/* Add the arguments to the current index command to the index NAME. */
+index_add_arg (name)
+ char *name;
+{
+ int which;
+ char *index_entry;
+ INDEX_ALIST *tem;
+
+ tem = find_index (name);
+
+ which = tem ? tem->index : -1;
+
+ get_rest_of_line (&index_entry);
+ ignore_blank_line ();
+
+ if (which < 0)
+ {
+ line_error ("Unknown index reference `%s'", name);
+ free (index_entry);
+ }
+ else
+ {
+ INDEX_ELT *new = (INDEX_ELT *) xmalloc (sizeof (INDEX_ELT));
+ new->next = the_indices[which];
+ new->entry = index_entry;
+ new->node = current_node;
+ new->code = tem->code;
+ new->defining_line = line_number - 1;
+ the_indices[which] = new;
+ }
+}
+
+#define INDEX_COMMAND_SUFFIX "index"
+
+/* The function which user defined index commands call. */
+gen_index ()
+{
+ char *name = savestring (command);
+ if (strlen (name) >= strlen ("index"))
+ name[strlen (name) - strlen ("index")] = '\0';
+ index_add_arg (name);
+ free (name);
+}
+
+/* Define a new index command. Arg is name of index. */
+cm_defindex ()
+{
+ gen_defindex (0);
+}
+
+cm_defcodeindex ()
+{
+ gen_defindex (1);
+}
+
+gen_defindex (code)
+ int code;
+{
+ char *name;
+ get_rest_of_line (&name);
+
+ if (find_index (name))
+ {
+ line_error ("Index `%s' already exists", name);
+ free (name);
+ return;
+ }
+ else
+ {
+ char *temp = (char *) alloca (1 + strlen (name) + strlen ("index"));
+ sprintf (temp, "%sindex", name);
+ define_user_command (temp, gen_index, 0);
+ defindex (name, code);
+ free (name);
+ }
+}
+
+/* Append LIST2 to LIST1. Return the head of the list. */
+INDEX_ELT *
+index_append (head, tail)
+ INDEX_ELT *head, *tail;
+{
+ register INDEX_ELT *t_head = head;
+
+ if (!t_head)
+ return (tail);
+
+ while (t_head->next)
+ t_head = t_head->next;
+ t_head->next = tail;
+ return (head);
+}
+
+/* Expects 2 args, on the same line. Both are index abbreviations.
+ Make the first one be a synonym for the second one, i.e. make the
+ first one have the same index as the second one. */
+cm_synindex ()
+{
+ int redirector, redirectee;
+ char *temp;
+
+ skip_whitespace ();
+ get_until_in_line (" ", &temp);
+ redirectee = find_index_offset (temp);
+ skip_whitespace ();
+ free_and_clear (&temp);
+ get_until_in_line (" ", &temp);
+ redirector = find_index_offset (temp);
+ free (temp);
+ if (redirector < 0 || redirectee < 0)
+ {
+ line_error ("Unknown index reference");
+ }
+ else
+ {
+ /* I think that we should let the user make indices synonymous to
+ each other without any lossage of info. This means that one can
+ say @synindex cp dt anywhere in the file, and things that used to
+ be in cp will go into dt. */
+ INDEX_ELT *i1 = the_indices[redirectee], *i2 = the_indices[redirector];
+
+ if (i1 || i2)
+ {
+ if (i1)
+ the_indices[redirectee] = index_append (i1, i2);
+ else
+ the_indices[redirectee] = index_append (i2, i1);
+ }
+
+ name_index_alist[redirectee]->index =
+ name_index_alist[redirector]->index;
+ }
+}
+
+cm_pindex () /* Pinhead index. */
+{
+ index_add_arg ("pg");
+}
+
+cm_vindex () /* Variable index. */
+{
+ index_add_arg ("vr");
+}
+
+cm_kindex () /* Key index. */
+{
+ index_add_arg ("ky");
+}
+
+cm_cindex () /* Concept index. */
+{
+ index_add_arg ("cp");
+}
+
+cm_findex () /* Function index. */
+{
+ index_add_arg ("fn");
+}
+
+cm_tindex () /* Data Type index. */
+{
+ index_add_arg ("tp");
+}
+
+/* Sorting the index. */
+index_element_compare (element1, element2)
+ INDEX_ELT **element1, **element2;
+{
+ /* This needs to ignore leading non-text characters. */
+ return (stricmp ((*element1)->entry, (*element2)->entry));
+}
+
+/* Sort the index passed in INDEX, returning an array of
+ pointers to elements. The array is terminated with a NULL
+ pointer. We call qsort because it's supposed to be fast.
+ I think this looks bad. */
+INDEX_ELT **
+sort_index (index)
+ INDEX_ELT *index;
+{
+ INDEX_ELT *temp = index;
+ INDEX_ELT **array;
+ int count = 0;
+
+ while (temp != (INDEX_ELT *) NULL)
+ {
+ count++;
+ temp = temp->next;
+ }
+
+ /* We have the length. Make an array. */
+
+ array = (INDEX_ELT **) xmalloc ((count + 1) * sizeof (INDEX_ELT *));
+ count = 0;
+ temp = index;
+
+ while (temp != (INDEX_ELT *) NULL)
+ {
+ array[count++] = temp;
+ temp = temp->next;
+ }
+ array[count] = (INDEX_ELT *) NULL; /* terminate the array. */
+
+ /* Sort the array. */
+ qsort (array, count, sizeof (INDEX_ELT *), index_element_compare);
+
+ return (array);
+}
+
+/* Non-zero means that we are in the middle of printing an index. */
+int printing_index = 0;
+
+/* Takes one arg, a short name of an index to print.
+ Outputs a menu of the sorted elements of the index. */
+cm_printindex ()
+{
+ int item;
+ INDEX_ELT *index;
+ INDEX_ELT **array;
+ char *index_name;
+ int old_inhibitions = inhibit_paragraph_indentation;
+ int previous_filling_enabled_value = filling_enabled;
+
+ close_paragraph ();
+ get_rest_of_line (&index_name);
+
+ index = index_list (index_name);
+ if ((int) index == -1)
+ {
+ line_error ("Unknown index name `%s'", index_name);
+ free (index_name);
+ return;
+ }
+ else
+ free (index_name);
+
+ array = sort_index (index);
+
+ filling_enabled = 0;
+ inhibit_paragraph_indentation = 1;
+ close_paragraph ();
+ add_word ("* Menu:\n\n");
+
+ printing_index = 1;
+ for (item = 0; (index = array[item]); item++)
+ {
+ int real_line_number = line_number;
+
+ /* Let errors generated while making the index entry point back
+ at the line which contains the entry. */
+ line_number = index->defining_line;
+
+ /* If this particular entry should be printed as a "code" index,
+ then wrap the entry with "@code{...}". */
+ if (index->code)
+ execute_string ("* @code{%s}: ", index->entry);
+ else
+ execute_string ("* %s: ", index->entry);
+
+ /* Pad the front of the destination nodename so that
+ the output looks nice. */
+ if (fill_column > 40 && output_column < 40)
+ indent (40 - output_column);
+
+ execute_string ("%s.\n", index->node);
+
+ line_number = real_line_number;
+ flush_output ();
+ }
+
+ printing_index = 0;
+ free (array);
+ close_single_paragraph ();
+ filling_enabled = previous_filling_enabled_value;
+ inhibit_paragraph_indentation = old_inhibitions;
+}
+
+
+/* **************************************************************** */
+/* */
+/* Making User Defined Commands */
+/* */
+/* **************************************************************** */
+
+define_user_command (name, proc, needs_braces_p)
+ char *name;
+ FUNCTION *proc;
+ int needs_braces_p;
+{
+ int slot = user_command_array_len;
+ user_command_array_len++;
+
+ if (!user_command_array)
+ user_command_array = (COMMAND **) xmalloc (1 * sizeof (COMMAND *));
+
+ user_command_array = (COMMAND **) xrealloc (user_command_array,
+ (1 + user_command_array_len) *
+ sizeof (COMMAND *));
+
+ user_command_array[slot] = (COMMAND *) xmalloc (sizeof (COMMAND));
+ user_command_array[slot]->name = savestring (name);
+ user_command_array[slot]->proc = proc;
+ user_command_array[slot]->argument_in_braces = needs_braces_p;
+}
+
+/* Make ALIAS run the named FUNCTION. Copies properties from FUNCTION. */
+define_alias (alias, function)
+ char *alias, *function;
+{
+}
+
+/* Set the paragraph indentation variable to the value specified in STRING.
+ Values can be:
+ `asis': Don't change existing indentation.
+ `none': Remove existing indentation.
+ NUM: Indent NUM spaces at the starts of paragraphs.
+ Note that if NUM is zero, we assume `none'.
+
+ Returns 0 if successful, or non-zero if STRING isn't one of the above. */
+int
+set_paragraph_indent (string)
+ char *string;
+{
+ if (strcmp (string, "asis") == 0)
+ paragraph_start_indent = 0;
+ else if (strcmp (string, "none") == 0)
+ paragraph_start_indent = -1;
+ else
+ {
+ if (sscanf (string, "%d", &paragraph_start_indent) != 1)
+ return (-1);
+ else
+ {
+ if (paragraph_start_indent == 0)
+ paragraph_start_indent = -1;
+ }
+ }
+ return (0);
+}
+
+cm_paragraphindent ()
+{
+ char *arg;
+
+ get_rest_of_line (&arg);
+ if (set_paragraph_indent (arg) != 0)
+ line_error ("Bad argument to @paragraphindent");
+
+ free (arg);
+}
+
+/* Some support for footnotes. */
+
+/* Footnotes are a new construct in Info. We don't know the best method
+ of implementing them for sure, so we present two possiblities.
+
+ SeparateNode:
+ Make them look like followed references, with the reference
+ destinations in a makeinfo manufactured node or,
+
+ EndNode:
+ Make them appear at the bottom of the node that they originally
+ appeared in. */
+#define SeparateNode 0
+#define EndNode 1
+
+int footnote_style = EndNode;
+int first_footnote_this_node = 1;
+int footnote_count = 0;
+
+/* Set the footnote style based on he style identifier in STRING. */
+int
+set_footnote_style (string)
+ char *string;
+{
+ if ((stricmp (string, "separate") == 0) ||
+ (stricmp (string, "MN") == 0))
+ footnote_style = SeparateNode;
+ else if ((stricmp (string, "end") == 0) ||
+ (stricmp (string, "EN") == 0))
+ footnote_style = EndNode;
+ else
+ return (-1);
+
+ return (0);
+}
+
+cm_footnotestyle ()
+{
+ char *arg;
+
+ get_rest_of_line (&arg);
+
+ if (set_footnote_style (arg) != 0)
+ line_error ("Bad argument to @footnotestyle");
+
+ free (arg);
+}
+
+typedef struct fn
+{
+ struct fn *next;
+ char *marker;
+ char *note;
+} FN;
+
+FN *pending_notes = (FN *) NULL;
+
+/* A method for remembering footnotes. Note that this list gets output
+ at the end of the current node. */
+remember_note (marker, note)
+ char *marker, *note;
+{
+ FN *temp = (FN *) xmalloc (sizeof (FN));
+
+ temp->marker = savestring (marker);
+ temp->note = savestring (note);
+ temp->next = pending_notes;
+ pending_notes = temp;
+ footnote_count++;
+}
+
+/* How to get rid of existing footnotes. */
+free_pending_notes ()
+{
+ FN *temp;
+
+ while ((temp = pending_notes) != (FN *) NULL)
+ {
+ free (temp->marker);
+ free (temp->note);
+ pending_notes = pending_notes->next;
+ free (temp);
+ }
+ first_footnote_this_node = 1;
+ footnote_count = 0;
+}
+
+/* What to do when you see a @footnote construct. */
+
+ /* Handle a "footnote".
+ footnote *{this is a footnote}
+ where "*" is the marker character for this note. */
+cm_footnote ()
+{
+ char *marker;
+ char *note;
+
+ get_until ("{", &marker);
+ canon_white (marker);
+
+ /* Read the argument in braces. */
+ if (curchar () != '{')
+ {
+ line_error ("`@%s' expected more than just `%s'. It needs something in `{...}'", command, marker);
+ free (marker);
+ return;
+ }
+ else
+ {
+ int braces = 1;
+ int temp = ++input_text_offset;
+ int len;
+
+ while (braces)
+ {
+ if (temp == size_of_input_text)
+ {
+ line_error ("No closing brace for footnote `%s'", marker);
+ return;
+ }
+
+ if (input_text[temp] == '{')
+ braces++;
+ else if (input_text[temp] == '}')
+ braces--;
+ else if (input_text[temp] == '\n')
+ line_number ++;
+
+ temp++;
+ }
+
+ len = (temp - input_text_offset) - 1;
+ note = (char *)xmalloc (len + 1);
+ strncpy (note, &input_text[input_text_offset], len);
+ note[len] = '\0';
+ input_text_offset = temp;
+ }
+
+ if (!current_node || !*current_node)
+ {
+ line_error ("Footnote defined without parent node");
+ free (marker);
+ free (note);
+ return;
+ }
+
+ if (!*marker)
+ {
+ free (marker);
+
+ if (number_footnotes)
+ {
+ marker = (char *)xmalloc (10);
+ sprintf (marker, "%d", current_footnote_number);
+ current_footnote_number++;
+ }
+ else
+ marker = savestring ("*");
+ }
+
+ remember_note (marker, note);
+
+ /* Your method should at least insert MARKER. */
+ switch (footnote_style)
+ {
+ case SeparateNode:
+ add_word_args ("(%s)", marker);
+ if (first_footnote_this_node)
+ {
+ char *temp_string;
+
+ temp_string = (char *)
+ xmalloc ((strlen (current_node)) + (strlen ("-Footnotes")) + 1);
+
+ add_word_args (" (*note %s-Footnotes::)", current_node);
+ strcpy (temp_string, current_node);
+ strcat (temp_string, "-Footnotes");
+ remember_node_reference (temp_string, line_number, followed_reference);
+ free (temp_string);
+ first_footnote_this_node = 0;
+ }
+ break;
+
+ case EndNode:
+ add_word_args ("(%s)", marker);
+ break;
+
+ default:
+ break;
+ }
+ free (marker);
+ free (note);
+}
+
+/* Non-zero means that we are currently in the process of outputting
+ footnotes. */
+int already_outputting_pending_notes = 0;
+
+/* Output the footnotes. We are at the end of the current node. */
+output_pending_notes ()
+{
+ FN *footnote = pending_notes;
+
+ if (!pending_notes)
+ return;
+
+ switch (footnote_style)
+ {
+
+ case SeparateNode:
+ {
+ char *old_current_node = current_node;
+ char *old_command = savestring (command);
+
+ already_outputting_pending_notes++;
+ execute_string ("@node %s-Footnotes,,,%s\n", current_node, current_node);
+ already_outputting_pending_notes--;
+ current_node = old_current_node;
+ free (command);
+ command = old_command;
+ }
+ break;
+
+ case EndNode:
+ close_paragraph ();
+ in_fixed_width_font++;
+ execute_string ("---------- Footnotes ----------\n\n");
+ in_fixed_width_font--;
+ break;
+ }
+
+ /* Handle the footnotes in reverse order. */
+ {
+ FN **array = (FN **) xmalloc ((footnote_count + 1) * sizeof (FN *));
+
+ array[footnote_count] = (FN *) NULL;
+
+ while (--footnote_count > -1)
+ {
+ array[footnote_count] = footnote;
+ footnote = footnote->next;
+ }
+
+ filling_enabled = 1;
+ indented_fill = 1;
+
+ while (footnote = array[++footnote_count])
+ {
+
+ switch (footnote_style)
+ {
+ case SeparateNode:
+ case EndNode:
+ execute_string ("(%s) %s", footnote->marker, footnote->note);
+ close_paragraph ();
+ break;
+ }
+ }
+ close_paragraph ();
+ free (array);
+ }
+}
+
+
+/* **************************************************************** */
+/* */
+/* User definable Macros (text substitution) */
+/* */
+/* **************************************************************** */
+
+#if defined (HAVE_MACROS)
+
+/* Array of macros and definitions. */
+MACRO_DEF **macro_list = (MACRO_DEF **)NULL;
+
+int macro_list_len = 0; /* Number of elements. */
+int macro_list_size = 0; /* Number of slots in total. */
+
+/* Return the macro definition of NAME or NULL if NAME is not defined. */
+MACRO_DEF *
+find_macro (name)
+ char *name;
+{
+ register int i;
+ register MACRO_DEF *def;
+
+ def = (MACRO_DEF *)NULL;
+ for (i = 0; macro_list && (def = macro_list[i]); i++)
+ if (strcmp (def->name, name) == 0)
+ break;
+
+ return (def);
+}
+
+/* Add the macro NAME with DEFINITION to macro_list. FILENAME is
+ the name of the file where this definition can be found, and
+ LINENO is the line number within that file. If a macro already
+ exists with NAME, then a warning is produced, and that previous
+ definition is overwritten. */
+void
+add_macro (name, definition, filename, lineno)
+ char *name, *definition;
+ char *filename;
+ int lineno;
+{
+ register MACRO_DEF *def;
+
+ def = find_macro (name);
+
+ if (!def)
+ {
+ if (macro_list_len + 2 >= macro_list_size)
+ macro_list = (MACRO_DEF **)xrealloc
+ (macro_list, ((macro_list_size += 10) * sizeof (MACRO_DEF *)));
+
+ macro_list[macro_list_len] = (MACRO_DEF *)xmalloc (sizeof (MACRO_DEF));
+ macro_list[macro_list_len + 1] = (MACRO_DEF *)NULL;
+
+ def = macro_list[macro_list_len];
+ macro_list_len += 1;
+ def->name = savestring (name);
+ }
+ else
+ {
+ char *temp_filename = input_filename;
+ int temp_line = line_number;
+
+ warning ("The macro `%s' is previously defined.", name);
+
+ input_filename = def->filename;
+ line_number = def->lineno;
+
+ warning ("Here is the previous definition of `%s'.", name);
+
+ input_filename = temp_filename;
+ line_number = temp_line;
+
+ free (def->filename);
+ free (def->definition);
+ }
+
+ def->filename = savestring (filename);
+ def->lineno = lineno;
+ def->definition = savestring (definition);
+}
+
+
+/* Delete the macro with name NAME. The macro is deleted from the list,
+ but it is also returned. If there was no macro defined, NULL is
+ returned. */
+MACRO_DEF *
+delete_macro (name)
+ char *name;
+{
+ register int i;
+ register MACRO_DEF *def;
+
+ def = (MACRO_DEF *)NULL;
+ for (i = 0; macro_list && (def = macro_list[i]); i++)
+ if (strcmp (def->name, name) == 0)
+ {
+ memcpy (macro_list + i, macro_list + i + 1,
+ ((macro_list_len + 1) - i) * sizeof (MACRO_DEF *));
+ break;
+ }
+ return (def);
+}
+
+/* Execute the macro passed in DEF, a pointer to a MACRO_DEF. */
+void
+execute_macro (def)
+ MACRO_DEF *def;
+{
+
+ if (def != (MACRO_DEF *)NULL)
+ {
+ char *line, *string;
+
+ get_until ("\n", &line);
+
+ if (curchar () == '\n') /* as opposed to the end of the file... */
+ {
+ line_number++;
+ input_text_offset++;
+ }
+ string = (char *)xmalloc (1 + strlen (def->definition) + strlen (line));
+ strcpy (string, def->definition);
+ strcat (string, line);
+ free (line);
+
+ execute_string ("%s\n", string);
+ free (string);
+ }
+}
+
+int
+cm_macro ()
+{
+ register int i;
+ char *line, *name, *expansion;
+
+ get_rest_of_line (&line);
+ canon_white (line);
+
+ for (i = 0; line[i] && !whitespace (line[i]); i++);
+ name = (char *)xmalloc (i);
+ strncpy (name, line, i);
+ name[i] = '\0';
+
+ while (whitespace (line[i]))
+ i++;
+
+ add_macro (name, line + i, input_filename, line_number - 1);
+ free (line);
+ free (name);
+}
+
+int
+cm_unmacro ()
+{
+ register int i;
+ char *line, *name;
+ MACRO_DEF *def;
+
+ get_rest_of_line (&line);
+ canon_white (line);
+
+ for (i = 0; line[i] && !whitespace (line[i]); i++);
+ name = (char *)xmalloc (i);
+ strncpy (name, line, i);
+ name[i] = '\0';
+
+ def = delete_macro (name);
+
+ if (def)
+ {
+ free (def->filename);
+ free (def->name);
+ free (def->definition);
+ free (def);
+ }
+
+ free (line);
+ free (name);
+}
+#endif /* HAVE_MACROS */
+
+/* **************************************************************** */
+/* */
+/* Looking For Include Files */
+/* */
+/* **************************************************************** */
+
+/* Given a string containing units of information separated by colons,
+ return the next one pointed to by INDEX, or NULL if there are no more.
+ Advance INDEX to the character after the colon. */
+char *
+extract_colon_unit (string, index)
+ char *string;
+ int *index;
+{
+ int i, start;
+
+ i = *index;
+
+ if (!string || (i >= strlen (string)))
+ return ((char *)NULL);
+
+ /* Each call to this routine leaves the index pointing at a colon if
+ there is more to the path. If I is > 0, then increment past the
+ `:'. If I is 0, then the path has a leading colon. Trailing colons
+ are handled OK by the `else' part of the if statement; an empty
+ string is returned in that case. */
+ if (i && string[i] == ':')
+ i++;
+
+ start = i;
+
+ while (string[i] && string[i] != ':') i++;
+
+ *index = i;
+
+ if (i == start)
+ {
+ if (string[i])
+ (*index)++;
+
+ /* Return "" in the case of a trailing `:'. */
+ return (savestring (""));
+ }
+ else
+ {
+ char *value;
+
+ value = (char *)xmalloc (1 + (i - start));
+ strncpy (value, &string[start], (i - start));
+ value [i - start] = '\0';
+
+ return (value);
+ }
+}
+
+/* Return the full pathname for FILENAME by searching along PATH.
+ When found, return the stat () info for FILENAME in FINFO.
+ If PATH is NULL, only the current directory is searched.
+ If the file could not be found, return a NULL pointer. */
+char *
+get_file_info_in_path (filename, path, finfo)
+ char *filename, *path;
+ struct stat *finfo;
+{
+ char *dir;
+ int result, index = 0;
+
+ if (path == (char *)NULL)
+ path = ".";
+
+ /* Handle absolute pathnames. "./foo", "/foo", "../foo". */
+ if (*filename == '/' ||
+ (*filename == '.' &&
+ (filename[1] == '/' ||
+ (filename[1] == '.' && filename[2] == '/'))))
+ {
+ if (stat (filename, finfo) == 0)
+ return (savestring (filename));
+ else
+ return ((char *)NULL);
+ }
+
+ while (dir = extract_colon_unit (path, &index))
+ {
+ char *fullpath;
+
+ if (!*dir)
+ {
+ free (dir);
+ dir = savestring (".");
+ }
+
+ fullpath = (char *)xmalloc (2 + strlen (dir) + strlen (filename));
+ sprintf (fullpath, "%s/%s", dir, filename);
+ free (dir);
+
+ result = stat (fullpath, finfo);
+
+ if (result == 0)
+ return (fullpath);
+ else
+ free (fullpath);
+ }
+ return ((char *)NULL);
+}
diff --git a/gnu/usr.bin/texinfo/misc/Makefile b/gnu/usr.bin/texinfo/misc/Makefile
new file mode 100644
index 0000000..c53561d
--- /dev/null
+++ b/gnu/usr.bin/texinfo/misc/Makefile
@@ -0,0 +1,96 @@
+# Generated automatically from Makefile.in by configure.
+# Makefile for GNU Texindex.
+# Copyright (C) 1990, 1991, 1992 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+#### Start of system configuration section. ####
+
+srcdir = .
+VPATH = $(srcdir):$(common)
+
+common = $(srcdir)/../libtxi
+
+CC = gcc
+INSTALL = /usr/bin/install -c
+INSTALL_PROGRAM = $(INSTALL)
+INSTALL_DATA = $(INSTALL) -m 644
+
+LN = ln
+RM = rm -f
+TAR = tar
+MKDIR = mkdir
+
+DEFS = -DSTDC_HEADERS=1 -DHAVE_UNISTD_H=1 -DHAVE_STRING_H=1 -DHAVE_VARARGS_H=1 -DHAVE_SYS_TIME_H=1 -DHAVE_SYS_FCNTL_H=1 -DHAVE_SETVBUF=1 -DHAVE_GETCWD=1 -DHAVE_BZERO=1 -DHAVE_RINDEX=1 -DHAVE_VFPRINTF=1 -DHAVE_VSPRINTF=1
+LIBS = -L../libtxi -ltxi
+LOADLIBES = $(LIBS)
+
+SHELL = /bin/sh
+
+CFLAGS = -O2
+LDFLAGS = -O2
+
+prefix = /usr/local
+exec_prefix = $(prefix)
+bindir = $(exec_prefix)/bin
+# Prefix for each installed program, normally empty or `g'.
+binprefix =
+libdir = $(prefix)/lib
+# Prefix for each installed man page, normally empty or `g'.
+manprefix =
+mandir = $(prefix)/man/man1
+manext = 1
+infodir = $(prefix)/info
+
+#### End of system configuration section. ####
+
+all: texindex
+sub-all: all
+
+.c.o:
+ $(CC) -c $(CPPFLAGS) $(DEFS) -I. -I$(srcdir) -I$(common) $(CFLAGS) $<
+
+
+install: all
+ $(INSTALL_PROGRAM) texindex $(bindir)/texindex
+ $(INSTALL_PROGRAM) $(srcdir)/texi2dvi $(bindir)/texi2dvi
+
+uninstall:
+ rm -f $(bindir)/texindex $(bindir)/texi2dvi
+
+Makefile: Makefile.in ../config.status
+ cd ..; sh config.status
+
+TAGS:
+ etags *.c *.h $(common)/getopt*.c $(common)/getopt.h
+
+clean:
+ rm -f *.o a.out core core.* texindex
+
+mostlyclean: clean
+
+distclean: clean
+ rm -f Makefile config.status
+
+realclean: distclean
+ rm -f TAGS
+
+texindex: texindex.o ../libtxi/libtxi.a
+ $(CC) $(LDFLAGS) -o texindex texindex.o $(LOADLIBES)
+
+texindex.o: texindex.c $(common)/getopt.h
+
+# Prevent GNU make v3 from overflowing arg limit on SysV.
+.NOEXPORT:
diff --git a/gnu/usr.bin/texinfo/misc/Makefile.in b/gnu/usr.bin/texinfo/misc/Makefile.in
new file mode 100644
index 0000000..2d8f769
--- /dev/null
+++ b/gnu/usr.bin/texinfo/misc/Makefile.in
@@ -0,0 +1,95 @@
+# Makefile for GNU Texindex.
+# Copyright (C) 1990, 1991, 1992 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+#### Start of system configuration section. ####
+
+srcdir = @srcdir@
+VPATH = $(srcdir):$(common)
+
+common = $(srcdir)/../libtxi
+
+CC = @CC@
+INSTALL = @INSTALL@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_DATA = @INSTALL_DATA@
+
+LN = ln
+RM = rm -f
+TAR = tar
+MKDIR = mkdir
+
+DEFS = @DEFS@
+LIBS = -L../libtxi -ltxi @LIBS@
+LOADLIBES = $(LIBS)
+
+SHELL = /bin/sh
+
+CFLAGS = -g
+LDFLAGS = -g
+
+prefix = /usr/local
+exec_prefix = $(prefix)
+bindir = $(exec_prefix)/bin
+# Prefix for each installed program, normally empty or `g'.
+binprefix =
+libdir = $(prefix)/lib
+# Prefix for each installed man page, normally empty or `g'.
+manprefix =
+mandir = $(prefix)/man/man1
+manext = 1
+infodir = $(prefix)/info
+
+#### End of system configuration section. ####
+
+all: texindex
+sub-all: all
+
+.c.o:
+ $(CC) -c $(CPPFLAGS) $(DEFS) -I. -I$(srcdir) -I$(common) $(CFLAGS) $<
+
+
+install: all
+ $(INSTALL_PROGRAM) texindex $(bindir)/texindex
+ $(INSTALL_PROGRAM) $(srcdir)/texi2dvi $(bindir)/texi2dvi
+
+uninstall:
+ rm -f $(bindir)/texindex $(bindir)/texi2dvi
+
+Makefile: Makefile.in ../config.status
+ cd ..; sh config.status
+
+TAGS:
+ etags *.c *.h $(common)/getopt*.c $(common)/getopt.h
+
+clean:
+ rm -f *.o a.out core core.* texindex
+
+mostlyclean: clean
+
+distclean: clean
+ rm -f Makefile config.status
+
+realclean: distclean
+ rm -f TAGS
+
+texindex: texindex.o ../libtxi/libtxi.a
+ $(CC) $(LDFLAGS) -o texindex texindex.o $(LOADLIBES)
+
+texindex.o: texindex.c $(common)/getopt.h
+
+# Prevent GNU make v3 from overflowing arg limit on SysV.
+.NOEXPORT:
diff --git a/gnu/usr.bin/texinfo/misc/NEWS b/gnu/usr.bin/texinfo/misc/NEWS
new file mode 100644
index 0000000..00de163
--- /dev/null
+++ b/gnu/usr.bin/texinfo/misc/NEWS
@@ -0,0 +1,171 @@
+This release of Info is version 2.8. Please read the file README.
+
+Changes since 2.5 beta:
+
+Note that versions 2.6 and 2.7 Beta were only released to a select group.
+
+* "info-" removed from the front of M-x commands.
+
+* Automatic footnote display. When you enter a node which contains
+ footnotes, and the variable "automatic-footnotes" is "On", Info pops
+ up a window containing the footnotes. Likewise, when you leave that
+ node, the window containing the footnotes goes away.
+
+* Cleaner built in documentation, and documentation functions.
+
+ Use:
+ o `M-x describe-variable' to read a variable's documenation
+ o `M-x describe-key' to find out what a particular keystroke does.
+ o `M-x describe-function' to read a function's documentation.
+ o `M-x where-is' to find out what keys invoke a particular function.
+
+* Info can "tile" the displayed windows (via "M-x tile-windows"). If
+ the variable "automatic-tiling" is "On", then splitting a window or
+ deleting a window causes the remaining windows to be retiled.
+
+* You can save every keystroke you type in a "dribble file" by using the
+ `--dribble FILENAME' option. You can initially read keystrokes from an
+ alternate input stream with `--restore FILENAME', or by redirecting
+ input on the command line `info < old-dribble'.
+
+* New behaviour of menu items. If the label is the same as the
+ target node name, and the node couldn't be found in the current file,
+ treat the label as a file name. For example, a menu entry in "DIR"
+ might contain:
+
+ * Emacs:: Cool text-editor.
+
+ Info would not find the node "(dir)Emacs", so just plain "(emacs)"
+ would be tried.
+
+* New variable "ISO-Latin" allows you to use European machines with
+ 8-bit character sets.
+
+* Cleanups in echo area reading, and redisplay. Cleanups in handling the
+ window which shows possible completions.
+
+* Info can now read files that have been compressed. An array in filesys.c
+ maps extensions to programs that can decompress stdin, and write the results
+ to stdout. Currently, ".Z"/uncompress, ".z"/gunzip, and ".Y"/unyabba are
+ supported. The modeline for a compressed file shows "zz" in it.
+
+* There is a new variable "gc-compressed-files" which, if non-zero, says
+ it is okay to reclaim the file buffer space allocated to a file which
+ was compressed, if, and only if, that file's contents do not appear in
+ any history node.
+
+* New file `nodemenu.c' implements a few functions for manipulating
+ previously visited nodes. `C-x C-b' (list-visited-nodes) produces a
+ menu of the nodes that could be reached by info-history-node in some
+ window. `C-x b' (select-visited-node) is similar, but reads one of
+ the node names with completion.
+
+* Keystroke `M-r' (move_to_screen_line) allows the user to place the cursor at
+ the start of a specific screen line. Without a numeric argument, place the
+ cursor on the center line; with an arg, place the cursor on that line.
+
+* Interruptible display implemented. Basic display speedups and hacks.
+* The message "*** Tags Out of Date ***" now means what it says.
+* Index searching with `,' (info-index-next) has been improved.
+* When scrolling with C-v, C-M-v, or M-v, only "Page Only" scrolling
+ will happen.
+
+* Continous scrolling (along with `]' (info-global-next) and `['
+ (info-global-prev) works better. `]' and `[' accept numeric
+ arguments, moving that many nodes in that case.
+
+* `C-x w' (info-toggle-wrap) controls how lines wider than the width
+ of the screen are displayed. If a line is too long, a `$' is
+ displayed in the rightmost column of the window.
+
+* There are some new variables for controlling the behaviour of Info
+ interactively. The current list of variables is as follows:
+
+ Variable Name Default Value Description
+ ------------- ------------- -----------
+ `automatic-footnotes' On When "On", footnotes appear and
+ disappear automatically.
+
+ `automatic-tiling' Off When "On", creating of deleting a
+ window resizes other windows.
+
+ `visible-bell' Off If non-zero, try to use a visible bell.
+
+ `errors-ring-bell' On If non-zero, errors cause a ring.
+
+ `show-index-match' On If non-zero, the portion of the string
+ matched is highlighted by changing its
+ case.
+
+ `scroll-behaviour' Continuous One of "Continuous", "Next Only", or
+ "Page Only". "Page Only" prevents you from
+ scrolling past the bottom or top of a node.
+ "Next Only" causes the Next or Prev node to
+ be selected when you scroll past the bottom
+ or top of a node. "Continous" moves
+ linearly through the files hierchichal
+ structure.
+
+ `scroll-step' 0 Controls how scrolling is done for you when
+ the cursor moves out of the current window.
+ Non-zero means it is the number of lines
+ you would like the screen to shift. A
+ value of 0 means to center the line
+ containing the cursor in the window.
+
+ `gc-compressed-files' Off If non-zero means it is okay to reclaim the
+ file buffer space allocated to a file which
+ was compressed, if, and only if, that
+ file's contents do not appear in the node
+ list of any window.
+
+ `ISO-Latin' Off Non-zero means that you are using an ISO
+ Latin character set. By default, standard
+ ASCII characters are assumed.
+________________________________________
+This release of Info is version 2.5 beta.
+
+Changes since 2.4 beta:
+
+* Index (i) and (,) commands fully implemented.
+* "configure" script now shipped with Info.
+* New function "set-variable" allows users to set various variables.
+* User-settable behaviour on end or beginning of node scrolling. This
+ supercedes the SPC and DEL changes in 2.3 beta.
+
+________________________________________
+This release of Info is version 2.4 beta.
+
+Changes since 2.3 beta:
+
+* info-last-node now means move to the last node of this info file.
+* info-history-node means move backwards through this window's node history.
+* info-first-node moves to the first node in the Info file. This node is
+ not necessarily "Top"!
+* SPC and DEL can select the Next or Prev node after printing an informative
+ message when pressed at the end/beg of a node.
+
+----------------------------------------
+This release of Info is version 2.3 beta.
+
+Changes since 2.2 beta:
+
+* M-x command lines if NAMED_COMMANDS is #defined. Variable in Makefile.
+* Screen height changes made quite robust.
+* Interactive function "set-screen-height" implements user height changes.
+* Scrolling on some terminals is faster now.
+* C-l with numeric arguement is fixed.
+
+----------------------------------------
+This release of Info is version 2.2 beta.
+
+Changes since 2.0:
+
+* C-g can now interrupt multi-file searches.
+* Incremental search is fully implemented.
+* Loading large tag tables is much faster now.
+* makedoc.c replaces shell script, speeding incremental builds.
+* Scrolling in redisplay is implemented.
+* Recursive uses of the echo area made more robust.
+* Garbage collection of unreferenced nodes.
+
diff --git a/gnu/usr.bin/texinfo/misc/README b/gnu/usr.bin/texinfo/misc/README
new file mode 100644
index 0000000..12cfa62
--- /dev/null
+++ b/gnu/usr.bin/texinfo/misc/README
@@ -0,0 +1,54 @@
+ Please Emacs, use -*- text -*- mode when editing this file.
+
+ * The file RELEASE contains information about what has changed
+ since the last release.
+
+ * The file INSTALL contains instructions on how to install Info.
+ (Type "./configure" and then "make".)
+
+This is the README file GNU Info version 2.8. This marks the first
+non-beta release.
+
+Thu Jan 21 14:50:52 1993
+
+----------------------------------------
+Version 2.7 beta, Wed Dec 30 02:02:38 1992
+Version 2.6 beta, Tue Dec 22 03:58:07 1992
+Version 2.5 beta, Tue Dec 8 14:50:35 1992
+Version 2.4 beta, Sat Nov 28 14:34:02 1992
+Version 2.3 beta, Fri Nov 27 01:04:13 1992
+Version 2.2 beta, Tue Nov 24 09:36:08 1992
+Version 2.1 beta, Tue Nov 17 23:29:36 1992
+
+Info 2.0 is a complete rewrite of the original standalone Info I wrote
+in 1987, the first program I wrote for rms. That program was
+something like my second Unix program ever, and my die-hard machine
+language coding habits tended to show through. I found the original
+Info hard to read and maintain, and thus decided to write this one.
+
+The rewrite consists of about 12,000 lines of code written in about 12
+days. I believe this version of Info to be in much better shape than
+the original Info, and the only reason it is in Beta test is because
+of its short life span.
+
+Info 2.0 is substantially different from its original standalone
+predecessor. It appears almost identical to the GNU Emacs version,
+but has the advantages of smaller size, ease of portability, and a
+built in library which can be used in other programs (to get or
+display documentation from Info files, for example).
+
+I eagerly await responses to this newer version of Info; comments on
+its portability, ease of use and user interface, code quality, and
+general usefulness are all of interest to me, and I will appreciate
+any comments that you would care to make.
+
+A full listing of the commands available in Info can be gotten by
+typing `?' while within an Info window. This produces a node in a
+window which can be viewed just like any Info node.
+
+So, please send your comments, bug reports, and suggestions to
+
+ bfox@ai.mit.edu
+
+Thanks for beta testing this software.
+
diff --git a/gnu/usr.bin/texinfo/misc/deref.c b/gnu/usr.bin/texinfo/misc/deref.c
new file mode 100644
index 0000000..c15bc1a
--- /dev/null
+++ b/gnu/usr.bin/texinfo/misc/deref.c
@@ -0,0 +1,238 @@
+/*
+ * deref.c
+
+ * compile command: gcc -g -o deref deref.c
+
+ * execute command: deref filename.texi > newfile.texi
+
+ * To: bob@gnu.ai.mit.edu
+ * Subject: another tool
+ * Date: 18 Dec 91 16:03:13 EST (Wed)
+ * From: gatech!skeeve!arnold@eddie.mit.edu (Arnold D. Robbins)
+ *
+ * Here is deref.c. It turns texinfo cross references back into the
+ * one argument form. It has the same limitations as fixref; one xref per
+ * line and can't cross lines. You can use it to find references that do
+ * cross a line boundary this way:
+ *
+ * deref < manual > /dev/null 2>errs
+ *
+ * (This assumes bash or /bin/sh.) The file errs will have list of lines
+ * where deref could not find matching braces.
+ *
+ * A gawk manual processed by deref goes through makeinfo without complaint.
+ * Compile with gcc and you should be set.
+ *
+ * Enjoy,
+ *
+ * Arnold
+ * -----------
+ */
+
+/*
+ * deref.c
+ *
+ * Make all texinfo references into the one argument form.
+ *
+ * Arnold Robbins
+ * arnold@skeeve.atl.ga.us
+ * December, 1991
+ *
+ * Copyright, 1991, Arnold Robbins
+ */
+
+/*
+ * LIMITATIONS:
+ * One texinfo cross reference per line.
+ * Cross references may not cross newlines.
+ * Use of fgets for input (to be fixed).
+ */
+
+#include <stdio.h>
+#include <ctype.h>
+#include <errno.h>
+
+/* for gcc on the 3B1, delete if this gives you grief */
+extern int fclose (FILE * fp);
+extern int fprintf (FILE * fp, const char *str,...);
+
+extern char *strerror (int errno);
+extern char *strchr (char *cp, int ch);
+extern int strncmp (const char *s1, const char *s2, int count);
+
+extern int errno;
+
+void process (FILE * fp);
+void repair (char *line, char *ref, int toffset);
+
+int Errs = 0;
+char *Name = "stdin";
+int Line = 0;
+char *Me;
+
+/* main --- handle arguments, global vars for errors */
+
+int
+main (int argc, char **argv)
+{
+ FILE *fp;
+
+ Me = argv[0];
+
+ if (argc == 1)
+ process (stdin);
+ else
+ for (argc--, argv++; *argv != NULL; argc--, argv++)
+ {
+ if (argv[0][0] == '-' && argv[0][1] == '\0')
+ {
+ Name = "stdin";
+ Line = 0;
+ process (stdin);
+ }
+ else if ((fp = fopen (*argv, "r")) != NULL)
+ {
+ Name = *argv;
+ Line = 0;
+ process (fp);
+ fclose (fp);
+ }
+ else
+ {
+ fprintf (stderr, "%s: can not open: %s\n",
+ *argv, strerror (errno));
+ Errs++;
+ }
+ }
+ return Errs != 0;
+}
+
+/* isref --- decide if we've seen a texinfo cross reference */
+
+int
+isref (char *cp)
+{
+ if (strncmp (cp, "@ref{", 5) == 0)
+ return 5;
+ if (strncmp (cp, "@xref{", 6) == 0)
+ return 6;
+ if (strncmp (cp, "@pxref{", 7) == 0)
+ return 7;
+ return 0;
+}
+
+/* process --- read files, look for references, fix them up */
+
+void
+process (FILE * fp)
+{
+ char buf[BUFSIZ];
+ char *cp;
+ int count;
+
+ while (fgets (buf, sizeof buf, fp) != NULL)
+ {
+ Line++;
+ cp = strchr (buf, '@');
+ if (cp == NULL)
+ {
+ fputs (buf, stdout);
+ continue;
+ }
+ do
+ {
+ count = isref (cp);
+ if (count == 0)
+ {
+ cp++;
+ cp = strchr (cp, '@');
+ if (cp == NULL)
+ {
+ fputs (buf, stdout);
+ goto next;
+ }
+ continue;
+ }
+ /* got one */
+ repair (buf, cp, count);
+ break;
+ }
+ while (cp != NULL);
+ next:;
+ }
+}
+
+/* repair --- turn all texinfo cross references into the one argument form */
+
+void
+repair (char *line, char *ref, int toffset)
+{
+ int braces = 1; /* have seen first left brace */
+ char *cp;
+
+ ref += toffset;
+
+ /* output line up to and including left brace in reference */
+ for (cp = line; cp <= ref; cp++)
+ putchar (*cp);
+
+ /* output node name */
+ for (; *cp && *cp != '}' && *cp != ',' && *cp != '\n'; cp++)
+ putchar (*cp);
+
+ if (*cp != '}')
+ { /* could have been one arg xref */
+ /* skip to matching right brace */
+ for (; braces > 0; cp++)
+ {
+ switch (*cp)
+ {
+ case '@':
+ cp++; /* blindly skip next character */
+ break;
+ case '{':
+ braces++;
+ break;
+ case '}':
+ braces--;
+ break;
+ case '\n':
+ case '\0':
+ Errs++;
+ fprintf (stderr,
+ "%s: %s: %d: mismatched braces\n",
+ Me, Name, Line);
+ goto out;
+ default:
+ break;
+ }
+ }
+ out:
+ ;
+ }
+
+ putchar ('}');
+ if (*cp == '}')
+ cp++;
+
+ /* now the rest of the line */
+ for (; *cp; cp++)
+ putchar (*cp);
+ return;
+}
+
+/* strerror --- return error string, delete if in your library */
+
+char *
+strerror (int errno)
+{
+ static char buf[100];
+ extern int sys_nerr;
+ extern char *sys_errlist[];
+
+ if (errno < sys_nerr && errno >= 0)
+ return sys_errlist[errno];
+
+ sprintf (buf, "unknown error %d", errno);
+ return buf;
+}
diff --git a/gnu/usr.bin/texinfo/misc/fixfonts b/gnu/usr.bin/texinfo/misc/fixfonts
new file mode 100755
index 0000000..ee2ea71
--- /dev/null
+++ b/gnu/usr.bin/texinfo/misc/fixfonts
@@ -0,0 +1,84 @@
+#!/bin/sh
+# Make links named `lcircle10' for all TFM and GF/PK files, if no
+# lcircle10 files already exist.
+
+# Don't override definition of prefix and/or libdir if they are
+# already defined in the environment.
+if test "z${prefix}" = "z" ; then
+ prefix=/usr/local
+else
+ # prefix may contain references to other variables, thanks to make.
+ eval prefix=\""${prefix}"\"
+fi
+
+if test "z${libdir}" = "z" ; then
+ libdir="${prefix}/lib/tex"
+else
+ # libdir may contain references to other variables, thanks to make.
+ eval libdir=\""${libdir}"\"
+fi
+
+texlibdir="${libdir}"
+texfontdir="${texlibdir}/fonts"
+
+# Directories for the different font formats, in case they're not all
+# stored in one place.
+textfmdir="${textfmdir-${texfontdir}}"
+texpkdir="${texpkdir-${texfontdir}}"
+texgfdir="${texgfdir-${texfontdir}}"
+
+test "z${TMPDIR}" = "z" && TMPDIR="/tmp"
+
+tempfile="${TMPDIR}/circ$$"
+tempfile2="${TMPDIR}/circ2$$"
+
+# EXIT SIGHUP SIGINT SIGQUIT SIGTERM
+#trap 'rm -f "${tempfile}" "${tempfile2}"' 0 1 2 3 15
+
+# Find all the fonts with names that include `circle'.
+(cd "${texfontdir}"; find . -name '*circle*' -print > "${tempfile}")
+
+# If they have lcircle10.tfm, assume everything is there, and quit.
+if grep 'lcircle10\.tfm' "${tempfile}" > /dev/null 2>&1 ; then
+ echo "Found lcircle10.tfm."
+ exit 0
+fi
+
+# No TFM file for lcircle. Make a link to circle10.tfm if it exists,
+# and then make a link to the bitmap files.
+grep 'circle10\.tfm' "${tempfile}" > "${tempfile2}" \
+ || {
+ echo "I can't find any circle fonts in ${texfontdir}.
+If it isn't installed somewhere else, you need to get the Metafont sources
+from somewhere, e.g., labrea.stanford.edu:pub/tex/latex/circle10.mf, and
+run Metafont on them."
+ exit 1
+ }
+
+# We have circle10.tfm. (If we have it more than once, take the first
+# one.) Make the link.
+tempfile2_line1="`sed -ne '1p;q' \"${tempfile2}\"`"
+ln "${tempfile2_line1}" "${textfmdir}/lcircle10.tfm"
+echo "Linked to ${tempfile2_line1}."
+
+# Now make a link for the PK files, if any.
+(cd "${texpkdir}"
+ for f in `grep 'circle10.*pk' "${tempfile}"` ; do
+ set - `echo "$f" \
+ | sed -ne '/\//!s/^/.\//;s/\(.*\)\/\([^\/][^\/]*\)$/\1 \2/;p'`
+ ln "$f" "${1}/l${2}"
+ echo "Linked to $f."
+ done
+)
+
+# And finally for the GF files.
+(cd "${texgfdir}"
+ for f in `grep 'circle10.*gf' "${tempfile}"` ; do
+ set - `echo "$f" \
+ | sed -ne '/\//!s/^/.\//;s/\(.*\)\/\([^\/][^\/]*\)$/\1 \2/;p'`
+ ln "$f" "${1}/l${2}"
+ echo "Linked to $f."
+ done
+)
+
+# eof
diff --git a/gnu/usr.bin/texinfo/misc/mkinstalldirs b/gnu/usr.bin/texinfo/misc/mkinstalldirs
new file mode 100755
index 0000000..0e29377
--- /dev/null
+++ b/gnu/usr.bin/texinfo/misc/mkinstalldirs
@@ -0,0 +1,35 @@
+#!/bin/sh
+# Make directory hierarchy.
+# Written by Noah Friedman <friedman@prep.ai.mit.edu>
+# Public domain.
+
+defaultIFS='
+'
+IFS="${IFS-${defaultIFS}}"
+
+errstatus=0
+
+for file in ${1+"$@"} ; do
+ oIFS="${IFS}"
+ # Some sh's can't handle IFS=/ for some reason.
+ IFS='%'
+ set - `echo ${file} | sed -e 's@/@%@g' -e 's@^%@/@'`
+ IFS="${oIFS}"
+
+ pathcomp=''
+
+ for d in ${1+"$@"} ; do
+ pathcomp="${pathcomp}${d}"
+
+ if test ! -d "${pathcomp}"; then
+ echo "mkdir $pathcomp" 1>&2
+ mkdir "${pathcomp}" || errstatus=$?
+ fi
+
+ pathcomp="${pathcomp}/"
+ done
+done
+
+exit $errstatus
+
+# eof
diff --git a/gnu/usr.bin/texinfo/misc/tex3patch b/gnu/usr.bin/texinfo/misc/tex3patch
new file mode 100755
index 0000000..1708c75
--- /dev/null
+++ b/gnu/usr.bin/texinfo/misc/tex3patch
@@ -0,0 +1,71 @@
+#!/bin/sh
+# Auxiliary script to work around TeX 3.0 bug. ---- tex3patch ----
+# patches texinfo.tex in current directory, or in directory given as arg.
+
+ANYVERSION=no
+
+for arg in $1 $2
+do
+ case $arg in
+ --dammit | -d ) ANYVERSION=yes ;;
+
+ * ) dir=$arg
+ esac
+done
+
+if [ -z "$dir" ]; then
+ dir='.'
+fi
+
+if [ \( 2 -lt $# \) -o \
+ \( ! -f $dir/texinfo.tex \) ]; then
+ echo "To patch texinfo.tex for peaceful coexistence with Unix TeX 3.0,"
+ echo "run $0"
+ echo "with no arguments in the same directory as texinfo.tex; or run"
+ echo " $0 DIRECTORY"
+ echo "(where DIRECTORY is a path leading to texinfo.tex)."
+ exit
+fi
+
+if [ -z "$TMPDIR" ]; then
+ TMPDIR=/tmp
+fi
+
+echo "Checking for \`dummy.tfm'"
+
+( cd $TMPDIR; tex '\relax \batchmode \font\foo=dummy \bye' )
+
+grep -s '3.0' $TMPDIR/texput.log
+if [ 1 = "$?" -a "$ANYVERSION" != "yes" ]; then
+ echo "You probably do not need this patch,"
+ echo "since your TeX does not seem to be version 3.0."
+ echo "If you insist on applying the patch, run $0"
+ echo "again with the option \`--dammit'"
+ exit
+fi
+
+grep -s 'file not found' $TMPDIR/texput.log
+if [ 0 = $? ]; then
+ echo "This patch requires the dummy font metric file \`dummy.tfm',"
+ echo "which does not seem to be part of your TeX installation."
+ echo "Please get your TeX maintainer to install \`dummy.tfm',"
+ echo "then run this script again."
+ exit
+fi
+rm $TMPDIR/texput.log
+
+echo "Patching $dir/texinfo.tex"
+
+sed -e 's/%%*\\font\\nullfont/\\font\\nullfont/' \
+ $dir/texinfo.tex >$TMPDIR/texinfo.tex
+mv $dir/texinfo.tex $dir/texinfo.tex-distrib; mv $TMPDIR/texinfo.tex $dir
+
+if [ 0 = $? ]; then
+ echo "Patched $dir/texinfo.tex to avoid TeX 3.0 bug."
+ echo "The original version is saved as $dir/texinfo.tex-distrib."
+else
+ echo "Patch failed. Sorry."
+fi
+----------------------------------------tex3patch ends
+
+
diff --git a/gnu/usr.bin/texinfo/misc/texi2dvi b/gnu/usr.bin/texinfo/misc/texi2dvi
new file mode 100755
index 0000000..12281e5
--- /dev/null
+++ b/gnu/usr.bin/texinfo/misc/texi2dvi
@@ -0,0 +1,263 @@
+#!/bin/sh
+# texi2dvi -- smartly produce DVI files from texinfo sources
+#
+# Copyright (C) 1992, 1993 Free Software Foundation.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, you can either send email to this
+# program's author (see below) or write to:
+#
+# Free Software Foundation, Inc.
+# 675 Mass Ave.
+# Cambridge, MA 02139, USA.
+#
+# Please send bug reports, etc. to bug-texinfo@prep.ai.mit.edu
+# If possible, please send a copy of the output of the script called with
+# the `--debug' option when making a bug report.
+#
+# Version 0.4
+# Last modified 26-Mar-93
+#
+
+# Please note that in the interest of general portability, some common
+# bourne shell constructs were avoided because they weren't guaranteed to
+# be available in some earlier implementations. I've tried to make this as
+# portable as possible.
+#
+# Among the more interesting lossages I noticed with some bourne shells
+# are:
+# 1) Some don't have an `unset' builtin
+# 2) In some implementations the `shift' builtin can't take a
+# numerical argument.
+
+progname=`basename $0`
+
+usage="Usage: ${progname} {-D} {-h} [file1] {file2} {...}
+ {--debug} {--help}
+
+ Options in braces are optional. Those in brackets are required.
+"
+
+if test $# -eq 0 ; then
+ echo "${usage}" 1>&2;
+ exit 1
+fi
+
+backup_extension=".bak"
+texindex="texindex"
+tex="tex"
+bq="\`" # To prevent hairy quoting and escaping later.
+eq="'"
+orig_pwd="`pwd`"
+
+if test "z${TEXINDEX}" != "z" ; then
+ texindex="${TEXINDEX}"
+fi
+
+if test "z${TEX}" != "z" ; then
+ tex="${TEX}"
+fi
+
+# Save this so we can construct a new TEXINPUTS path for each file to be
+# processed.
+TEXINPUTS_orig="${TEXINPUTS}"
+export TEXINPUTS
+
+# Parse command line options
+
+# "unset" option variables to make sure they weren't accidentally
+# exported
+debug=""
+
+# If you add new commands be sure to change the wildcards below to make
+# sure they are unambiguous (i.e. only match one possible long option)
+# Be sure to show at least one instance of the full long option name to
+# document what the long option is canonically called.
+while test $# -gt 0 ; do
+ case z$1 in
+ z-D | z--debug | z--d* )
+ debug="t"
+ shift
+ ;;
+ z-h | z--help | z--h* )
+ echo "${usage}" 1>&2
+ exit 1
+ ;;
+ z-- )
+ shift
+ break
+ ;;
+ z-* )
+ echo "${progname}: ${bq}${1}${eq} is not a valid option." 1>&2
+ echo "" 1>&2
+ echo "${usage}" 1>&2
+ exit 1
+ ;;
+ * )
+ break
+ ;;
+ esac
+done
+
+# See if there are any command line args left (which will be interpreted as
+# filename arguments)
+if test $# -eq 0 ; then
+ echo "${progname}: at least one file name is required as an argument." 1>&2
+ echo "" 1>&2
+ echo "${usage}" 1>&2
+ exit 1
+fi
+
+test "z${debug}" = "zt" && set -x
+
+# Texify files
+for command_line_filename in ${1+"$@"} ; do
+ # Roughly equivalent to `dirname ...`, but more portable
+ directory="`echo ${command_line_filename} | sed 's/\/[^\/]*$//'`"
+ filename_texi="`basename ${command_line_filename}`"
+ # Strip off the last extension part (probably .texinfo or .texi)
+ filename_noext="`echo ${filename_texi} | sed 's/\.[^.]*$//'`"
+
+ # If directory and file are the same, then it's probably because there's
+ # no pathname component. Set dirname to `.', the current directory.
+ if test "z${directory}" = "z${command_line_filename}" ; then
+ directory="."
+ fi
+
+ # Source file might @include additional texinfo sources. Put `.' and
+ # directory where source file(s) reside in TEXINPUTS before anything
+ # else. `.' goes first to ensure that any old .aux, .cps, etc. files in
+ # ${directory} don't get used in preference to fresher files in `.'.
+ TEXINPUTS=".:${directory}:${TEXINPUTS_orig}"
+
+ # "Unset" variables that might have values from previous iterations and
+ # which won't be completely reset later.
+ definite_index_files=""
+
+ # See if file exists here. If it doesn't we're in trouble since, even
+ # though the user may be able to reenter a valid filename at the tex
+ # prompt (assuming they're attending the terminal), this script won't be
+ # able to find the right index files and so forth.
+ if test ! -r "${command_line_filename}" ; then
+ echo "${progname}: ${command_line_filename}: No such file or permission denied." 1>&2
+ continue;
+ fi
+
+ # Find all files having root filename with a two-letter extension,
+ # determine whether they're really index files, and save them. Foo.aux
+ # is actually the cross-references file, but we need to keep track of
+ # that too.
+ possible_index_files="`eval echo ${filename_noext}.?? ${filename_noext}.aux`"
+ for this_file in ${possible_index_files} ; do
+ # If file is empty, forget it.
+ if test ! -s "${this_file}" ; then
+ continue;
+ fi
+
+ # Examine first character of file. If it's not a backslash or
+ # single quote, then it's definitely not an index or xref file.
+ first_character="`sed -n '1s/^\(.\).*$/\1/p;q' ${this_file}`"
+ if test "${first_character}" = "\\" -o "${first_character}" = "'" ; then
+ definite_index_files="${definite_index_files} ${this_file}"
+ fi
+ done
+ orig_index_files="${definite_index_files}"
+ orig_index_files_sans_aux="`echo ${definite_index_files} \
+ | sed 's/'${filename_noext}'\.aux//;
+ s/^[ ]*//;s/[ ]*$//;'`"
+
+ # Now save copies of original index files so we have some means of
+ # comparison later.
+ for index_file_to_save in ${orig_index_files} ; do
+ cp "${index_file_to_save}" "${index_file_to_save}${backup_extension}"
+ done
+
+ # Run texindex on current index files. If they already exist, and
+ # after running TeX a first time the index files don't change, then
+ # there's no reason to run TeX again. But we won't know that if the
+ # index files are out of date or nonexistent.
+ if test "${orig_index_files_sans_aux}" ; then
+ ${texindex} ${orig_index_files_sans_aux}
+ fi
+
+ if ${tex} ${command_line_filename} ; then # TeX run first time
+ definite_index_files=""
+ # Get list of new index files
+ possible_index_files="`eval echo ${filename_noext}.?? ${filename_noext}.aux`"
+ for this_file in ${possible_index_files} ; do
+ # If file is empty, forget it.
+ if test ! -s ${this_file} ; then
+ continue;
+ fi
+
+ # Examine first character of file. If it's not a backslash or
+ # single quote, then it's definitely not an index or xref file.
+ first_character="`sed -n '1s/^\(.\).*$/\1/p;q' ${this_file}`"
+ if test "${first_character}" = "\\" -o "${first_character}" = "'" ; then
+ definite_index_files="${definite_index_files} ${this_file}"
+ fi
+ done
+ new_index_files="${definite_index_files}"
+ new_index_files_sans_aux="`echo ${definite_index_files} \
+ | sed 's/'${filename_noext}'\.aux//;
+ s/^[ ]*//;s/[ ]*$//;'`"
+
+ # If old and new list don't at least have the same file list, then one
+ # file or another has definitely changed.
+ if test "${orig_index_files}" != "${new_index_files}" ; then
+ index_files_changed_p=t
+ else
+ # File list is the same. We must compare each file until we find a
+ # difference.
+ index_files_changed_p=""
+ for this_file in ${new_index_files} ; do
+ # cmp -s will return nonzero exit status if files differ.
+ cmp -s "${this_file}" "${this_file}${backup_extension}"
+ if test $? -ne 0 ; then
+ # We only need to keep comparing until we find *one* that
+ # differs, because we'll have to run texindex & tex no
+ # matter what.
+ index_files_changed_p=t
+ break
+ fi
+ done
+ fi
+
+ # If index files have changed since TeX has been run, or if the aux
+ # file wasn't present originally, run texindex and TeX again.
+ if test "${index_files_changed_p}" ; then
+ retval=0
+ if test "${new_index_files_sans_aux}" ; then
+ ${texindex} ${new_index_files_sans_aux}
+ retval=$?
+ fi
+ if test ${retval} -eq 0 ; then
+ ${tex} "${command_line_filename}"
+ fi
+ fi
+ fi
+
+ # Generate list of files to delete, then call rm once with the entire
+ # list. This is significantly faster than multiple executions of rm.
+ file_list=""
+ for file in ${orig_index_files} ; do
+ file_list="${file_list} ${file}${backup_extension}"
+ done
+ if test "${file_list}" ; then
+ rm -f ${file_list}
+ fi
+done
+
+#
+# eof
+#
diff --git a/gnu/usr.bin/texinfo/texindex/Makefile b/gnu/usr.bin/texinfo/texindex/Makefile
new file mode 100644
index 0000000..aee14df
--- /dev/null
+++ b/gnu/usr.bin/texinfo/texindex/Makefile
@@ -0,0 +1,21 @@
+#
+# Bmakefile for GNU info
+#
+# $Id: Makefile,v 1.2 1994/09/15 13:12:23 jkh Exp $
+#
+
+PROG= texindex
+NOMAN=yes
+SRCS+= texindex.c getopt1.c getopt.c
+.PATH: ${.CURDIR}/../info
+
+CFLAGS+= -I${.CURDIR}/../info -I${.CURDIR}
+CFLAGS+= -DNAMED_FUNCTIONS=1 -DSTDC_HEADERS=1
+CFLAGS+= -DHAVE_UNISTD_H=1 -DHAVE_STRING_H=1 -DHAVE_VARARGS_H=1
+CFLAGS+= -DHAVE_SYS_FCNTL_H=1 -DHAVE_SETVBUF=1 -DHAVE_GETCWD=1 -DHAVE_BZERO=1
+CFLAGS+= -DHAVE_RINDEX=1 -DHAVE_VFPRINTF=1 -DHAVE_VSPRINTF=1
+CFLAGS+= -DHAVE_SYS_TIME_H=1 -DDEFAULT_INFOPATH='"${INFODIR}"'
+
+.include "../../Makefile.inc"
+.include <bsd.prog.mk>
+
diff --git a/gnu/usr.bin/texinfo/texindex/texindex.c b/gnu/usr.bin/texinfo/texindex/texindex.c
new file mode 100644
index 0000000..f7b0aef
--- /dev/null
+++ b/gnu/usr.bin/texinfo/texindex/texindex.c
@@ -0,0 +1,1700 @@
+/* Prepare TeX index dribble output into an actual index.
+
+ Version 1.45
+
+ Copyright (C) 1987, 1991, 1992 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+
+#include <stdio.h>
+#include <ctype.h>
+#include <errno.h>
+#include "getopt.h"
+
+#if defined (STDC_HEADERS)
+# include <string.h>
+# include <stdlib.h>
+# if !defined (bzero)
+# define bzero(p, n) memset((p), '\0', (n))
+# endif /* !bzero */
+#else /* !STDC_HEADERS */
+extern int errno;
+char *getenv (), *malloc (), *realloc ();
+void bzero ();
+#endif /* !STDC_HEADERS */
+
+#if defined (HAVE_UNISTD_H)
+# include <unistd.h>
+#else /* !HAVE_UNISTD_H */
+long lseek ();
+#endif /* !HAVE_UNISTD_H */
+
+char *mktemp ();
+
+#if defined (VMS)
+# if !defined (VAX11C)
+# define noshare
+# endif /* !VAX11C */
+# include <perror.h>
+extern noshare int sys_nerr;
+extern noshare char *sys_errlist[];
+
+# include <file.h>
+
+# define TI_NO_ERROR ((1 << 28) | 1)
+# define TI_FATAL_ERROR ((1 << 28) | 4)
+# define unlink delete
+
+#else /* !VMS */
+
+extern int sys_nerr;
+extern const char * const sys_errlist[];
+
+# if defined (HAVE_SYS_FCNTL_H)
+# include <sys/types.h>
+# include <sys/fcntl.h>
+# endif /* HAVE_SYS_FCNTL_H */
+
+# if defined (_AIX) || !defined (_POSIX_VERSION)
+# include <sys/file.h>
+# else /* !AIX && _POSIX_VERSION */
+# if !defined (HAVE_SYS_FCNTL_H)
+# include <fcntl.h>
+# endif /* !HAVE_FCNTL_H */
+# endif /* !_AIX && _POSIX_VERSION */
+# define TI_NO_ERROR 0
+# define TI_FATAL_ERROR 1
+#endif /* !VMS */
+
+#if !defined (SEEK_SET)
+# define SEEK_SET 0
+# define SEEK_CUR 1
+# define SEEK_END 2
+#endif /* !SEEK_SET */
+
+/* When sorting in core, this structure describes one line
+ and the position and length of its first keyfield. */
+struct lineinfo
+{
+ char *text; /* The actual text of the line. */
+ union {
+ char *text; /* The start of the key (for textual comparison). */
+ long number; /* The numeric value (for numeric comparison). */
+ } key;
+ long keylen; /* Length of KEY field. */
+};
+
+/* This structure describes a field to use as a sort key. */
+struct keyfield
+{
+ int startwords; /* Number of words to skip. */
+ int startchars; /* Number of additional chars to skip. */
+ int endwords; /* Number of words to ignore at end. */
+ int endchars; /* Ditto for characters of last word. */
+ char ignore_blanks; /* Non-zero means ignore spaces and tabs. */
+ char fold_case; /* Non-zero means case doesn't matter. */
+ char reverse; /* Non-zero means compare in reverse order. */
+ char numeric; /* Non-zeros means field is ASCII numeric. */
+ char positional; /* Sort according to file position. */
+ char braced; /* Count balanced-braced groupings as fields. */
+};
+
+/* Vector of keyfields to use. */
+struct keyfield keyfields[3];
+
+/* Number of keyfields stored in that vector. */
+int num_keyfields = 3;
+
+/* Vector of input file names, terminated with a null pointer. */
+char **infiles;
+
+/* Vector of corresponding output file names, or NULL, meaning default it
+ (add an `s' to the end). */
+char **outfiles;
+
+/* Length of `infiles'. */
+int num_infiles;
+
+/* Pointer to the array of pointers to lines being sorted. */
+char **linearray;
+
+/* The allocated length of `linearray'. */
+long nlines;
+
+/* Directory to use for temporary files. On Unix, it ends with a slash. */
+char *tempdir;
+
+/* Start of filename to use for temporary files. */
+char *tempbase;
+
+/* Number of last temporary file. */
+int tempcount;
+
+/* Number of last temporary file already deleted.
+ Temporary files are deleted by `flush_tempfiles' in order of creation. */
+int last_deleted_tempcount;
+
+/* During in-core sort, this points to the base of the data block
+ which contains all the lines of data. */
+char *text_base;
+
+/* Additional command switches .*/
+
+/* Nonzero means do not delete tempfiles -- for debugging. */
+int keep_tempfiles;
+
+/* The name this program was run with. */
+char *program_name;
+
+/* Forward declarations of functions in this file. */
+
+void decode_command ();
+void sort_in_core ();
+void sort_offline ();
+char **parsefile ();
+char *find_field ();
+char *find_pos ();
+long find_value ();
+char *find_braced_pos ();
+char *find_braced_end ();
+void writelines ();
+int compare_field ();
+int compare_full ();
+long readline ();
+int merge_files ();
+int merge_direct ();
+void pfatal_with_name ();
+void fatal ();
+void error ();
+void *xmalloc (), *xrealloc ();
+char *concat ();
+char *maketempname ();
+void flush_tempfiles ();
+char *tempcopy ();
+
+#define MAX_IN_CORE_SORT 500000
+
+void
+main (argc, argv)
+ int argc;
+ char **argv;
+{
+ int i;
+
+ tempcount = 0;
+ last_deleted_tempcount = 0;
+ program_name = argv[0];
+
+ /* Describe the kind of sorting to do. */
+ /* The first keyfield uses the first braced field and folds case. */
+ keyfields[0].braced = 1;
+ keyfields[0].fold_case = 1;
+ keyfields[0].endwords = -1;
+ keyfields[0].endchars = -1;
+
+ /* The second keyfield uses the second braced field, numerically. */
+ keyfields[1].braced = 1;
+ keyfields[1].numeric = 1;
+ keyfields[1].startwords = 1;
+ keyfields[1].endwords = -1;
+ keyfields[1].endchars = -1;
+
+ /* The third keyfield (which is ignored while discarding duplicates)
+ compares the whole line. */
+ keyfields[2].endwords = -1;
+ keyfields[2].endchars = -1;
+
+ decode_command (argc, argv);
+
+ tempbase = mktemp (concat ("txiXXXXXX", "", ""));
+
+ /* Process input files completely, one by one. */
+
+ for (i = 0; i < num_infiles; i++)
+ {
+ int desc;
+ long ptr;
+ char *outfile;
+
+ desc = open (infiles[i], O_RDONLY, 0);
+ if (desc < 0)
+ pfatal_with_name (infiles[i]);
+ lseek (desc, 0L, SEEK_END);
+ ptr = lseek (desc, 0L, SEEK_CUR);
+
+ close (desc);
+
+ outfile = outfiles[i];
+ if (!outfile)
+ {
+ outfile = concat (infiles[i], "s", "");
+ }
+
+ if (ptr < MAX_IN_CORE_SORT)
+ /* Sort a small amount of data. */
+ sort_in_core (infiles[i], ptr, outfile);
+ else
+ sort_offline (infiles[i], ptr, outfile);
+ }
+
+ flush_tempfiles (tempcount);
+ exit (TI_NO_ERROR);
+}
+
+void
+usage ()
+{
+ fprintf (stderr, "\
+Usage: %s [-k] infile [-o outfile] ...\n", program_name);
+ exit (1);
+}
+
+/* Decode the command line arguments to set the parameter variables
+ and set up the vector of keyfields and the vector of input files. */
+
+void
+decode_command (argc, argv)
+ int argc;
+ char **argv;
+{
+ int optc;
+ char **ip;
+ char **op;
+
+ /* Store default values into parameter variables. */
+
+ tempdir = getenv ("TMPDIR");
+#ifdef VMS
+ if (tempdir == NULL)
+ tempdir = "sys$scratch:";
+#else
+ if (tempdir == NULL)
+ tempdir = "/tmp/";
+ else
+ tempdir = concat (tempdir, "/", "");
+#endif
+
+ keep_tempfiles = 0;
+
+ /* Allocate ARGC input files, which must be enough. */
+
+ infiles = (char **) xmalloc (argc * sizeof (char *));
+ outfiles = (char **) xmalloc (argc * sizeof (char *));
+ ip = infiles;
+ op = outfiles;
+
+ while ((optc = getopt (argc, argv, "-ko:")) != EOF)
+ {
+ switch (optc)
+ {
+ case 1: /* Non-option filename. */
+ *ip++ = optarg;
+ *op++ = NULL;
+ break;
+
+ case 'k':
+ keep_tempfiles = 1;
+ break;
+
+ case 'o':
+ if (op > outfiles)
+ *(op - 1) = optarg;
+ break;
+
+ default:
+ usage ();
+ }
+ }
+
+ /* Record number of keyfields and terminate list of filenames. */
+ num_infiles = ip - infiles;
+ *ip = 0;
+ if (num_infiles == 0)
+ usage ();
+}
+
+/* Return a name for a temporary file. */
+
+char *
+maketempname (count)
+ int count;
+{
+ char tempsuffix[10];
+ sprintf (tempsuffix, "%d", count);
+ return concat (tempdir, tempbase, tempsuffix);
+}
+
+/* Delete all temporary files up to TO_COUNT. */
+
+void
+flush_tempfiles (to_count)
+ int to_count;
+{
+ if (keep_tempfiles)
+ return;
+ while (last_deleted_tempcount < to_count)
+ unlink (maketempname (++last_deleted_tempcount));
+}
+
+/* Copy the input file open on IDESC into a temporary file
+ and return the temporary file name. */
+
+#define BUFSIZE 1024
+
+char *
+tempcopy (idesc)
+ int idesc;
+{
+ char *outfile = maketempname (++tempcount);
+ int odesc;
+ char buffer[BUFSIZE];
+
+ odesc = open (outfile, O_WRONLY | O_CREAT, 0666);
+
+ if (odesc < 0)
+ pfatal_with_name (outfile);
+
+ while (1)
+ {
+ int nread = read (idesc, buffer, BUFSIZE);
+ write (odesc, buffer, nread);
+ if (!nread)
+ break;
+ }
+
+ close (odesc);
+
+ return outfile;
+}
+
+/* Compare LINE1 and LINE2 according to the specified set of keyfields. */
+
+int
+compare_full (line1, line2)
+ char **line1, **line2;
+{
+ int i;
+
+ /* Compare using the first keyfield;
+ if that does not distinguish the lines, try the second keyfield;
+ and so on. */
+
+ for (i = 0; i < num_keyfields; i++)
+ {
+ long length1, length2;
+ char *start1 = find_field (&keyfields[i], *line1, &length1);
+ char *start2 = find_field (&keyfields[i], *line2, &length2);
+ int tem = compare_field (&keyfields[i], start1, length1, *line1 - text_base,
+ start2, length2, *line2 - text_base);
+ if (tem)
+ {
+ if (keyfields[i].reverse)
+ return -tem;
+ return tem;
+ }
+ }
+
+ return 0; /* Lines match exactly. */
+}
+
+/* Compare LINE1 and LINE2, described by structures
+ in which the first keyfield is identified in advance.
+ For positional sorting, assumes that the order of the lines in core
+ reflects their nominal order. */
+
+int
+compare_prepared (line1, line2)
+ struct lineinfo *line1, *line2;
+{
+ int i;
+ int tem;
+ char *text1, *text2;
+
+ /* Compare using the first keyfield, which has been found for us already. */
+ if (keyfields->positional)
+ {
+ if (line1->text - text_base > line2->text - text_base)
+ tem = 1;
+ else
+ tem = -1;
+ }
+ else if (keyfields->numeric)
+ tem = line1->key.number - line2->key.number;
+ else
+ tem = compare_field (keyfields, line1->key.text, line1->keylen, 0,
+ line2->key.text, line2->keylen, 0);
+ if (tem)
+ {
+ if (keyfields->reverse)
+ return -tem;
+ return tem;
+ }
+
+ text1 = line1->text;
+ text2 = line2->text;
+
+ /* Compare using the second keyfield;
+ if that does not distinguish the lines, try the third keyfield;
+ and so on. */
+
+ for (i = 1; i < num_keyfields; i++)
+ {
+ long length1, length2;
+ char *start1 = find_field (&keyfields[i], text1, &length1);
+ char *start2 = find_field (&keyfields[i], text2, &length2);
+ int tem = compare_field (&keyfields[i], start1, length1, text1 - text_base,
+ start2, length2, text2 - text_base);
+ if (tem)
+ {
+ if (keyfields[i].reverse)
+ return -tem;
+ return tem;
+ }
+ }
+
+ return 0; /* Lines match exactly. */
+}
+
+/* Like compare_full but more general.
+ You can pass any strings, and you can say how many keyfields to use.
+ POS1 and POS2 should indicate the nominal positional ordering of
+ the two lines in the input. */
+
+int
+compare_general (str1, str2, pos1, pos2, use_keyfields)
+ char *str1, *str2;
+ long pos1, pos2;
+ int use_keyfields;
+{
+ int i;
+
+ /* Compare using the first keyfield;
+ if that does not distinguish the lines, try the second keyfield;
+ and so on. */
+
+ for (i = 0; i < use_keyfields; i++)
+ {
+ long length1, length2;
+ char *start1 = find_field (&keyfields[i], str1, &length1);
+ char *start2 = find_field (&keyfields[i], str2, &length2);
+ int tem = compare_field (&keyfields[i], start1, length1, pos1,
+ start2, length2, pos2);
+ if (tem)
+ {
+ if (keyfields[i].reverse)
+ return -tem;
+ return tem;
+ }
+ }
+
+ return 0; /* Lines match exactly. */
+}
+
+/* Find the start and length of a field in STR according to KEYFIELD.
+ A pointer to the starting character is returned, and the length
+ is stored into the int that LENGTHPTR points to. */
+
+char *
+find_field (keyfield, str, lengthptr)
+ struct keyfield *keyfield;
+ char *str;
+ long *lengthptr;
+{
+ char *start;
+ char *end;
+ char *(*fun) ();
+
+ if (keyfield->braced)
+ fun = find_braced_pos;
+ else
+ fun = find_pos;
+
+ start = (*fun) (str, keyfield->startwords, keyfield->startchars,
+ keyfield->ignore_blanks);
+ if (keyfield->endwords < 0)
+ {
+ if (keyfield->braced)
+ end = find_braced_end (start);
+ else
+ {
+ end = start;
+ while (*end && *end != '\n')
+ end++;
+ }
+ }
+ else
+ {
+ end = (*fun) (str, keyfield->endwords, keyfield->endchars, 0);
+ if (end - str < start - str)
+ end = start;
+ }
+ *lengthptr = end - start;
+ return start;
+}
+
+/* Return a pointer to a specified place within STR,
+ skipping (from the beginning) WORDS words and then CHARS chars.
+ If IGNORE_BLANKS is nonzero, we skip all blanks
+ after finding the specified word. */
+
+char *
+find_pos (str, words, chars, ignore_blanks)
+ char *str;
+ int words, chars;
+ int ignore_blanks;
+{
+ int i;
+ char *p = str;
+
+ for (i = 0; i < words; i++)
+ {
+ char c;
+ /* Find next bunch of nonblanks and skip them. */
+ while ((c = *p) == ' ' || c == '\t')
+ p++;
+ while ((c = *p) && c != '\n' && !(c == ' ' || c == '\t'))
+ p++;
+ if (!*p || *p == '\n')
+ return p;
+ }
+
+ while (*p == ' ' || *p == '\t')
+ p++;
+
+ for (i = 0; i < chars; i++)
+ {
+ if (!*p || *p == '\n')
+ break;
+ p++;
+ }
+ return p;
+}
+
+/* Like find_pos but assumes that each field is surrounded by braces
+ and that braces within fields are balanced. */
+
+char *
+find_braced_pos (str, words, chars, ignore_blanks)
+ char *str;
+ int words, chars;
+ int ignore_blanks;
+{
+ int i;
+ int bracelevel;
+ char *p = str;
+ char c;
+
+ for (i = 0; i < words; i++)
+ {
+ bracelevel = 1;
+ while ((c = *p++) != '{' && c != '\n' && c)
+ /* Do nothing. */ ;
+ if (c != '{')
+ return p - 1;
+ while (bracelevel)
+ {
+ c = *p++;
+ if (c == '{')
+ bracelevel++;
+ if (c == '}')
+ bracelevel--;
+ if (c == 0 || c == '\n')
+ return p - 1;
+ }
+ }
+
+ while ((c = *p++) != '{' && c != '\n' && c)
+ /* Do nothing. */ ;
+
+ if (c != '{')
+ return p - 1;
+
+ if (ignore_blanks)
+ while ((c = *p) == ' ' || c == '\t')
+ p++;
+
+ for (i = 0; i < chars; i++)
+ {
+ if (!*p || *p == '\n')
+ break;
+ p++;
+ }
+ return p;
+}
+
+/* Find the end of the balanced-brace field which starts at STR.
+ The position returned is just before the closing brace. */
+
+char *
+find_braced_end (str)
+ char *str;
+{
+ int bracelevel;
+ char *p = str;
+ char c;
+
+ bracelevel = 1;
+ while (bracelevel)
+ {
+ c = *p++;
+ if (c == '{')
+ bracelevel++;
+ if (c == '}')
+ bracelevel--;
+ if (c == 0 || c == '\n')
+ return p - 1;
+ }
+ return p - 1;
+}
+
+long
+find_value (start, length)
+ char *start;
+ long length;
+{
+ while (length != 0L)
+ {
+ if (isdigit (*start))
+ return atol (start);
+ length--;
+ start++;
+ }
+ return 0l;
+}
+
+/* Vector used to translate characters for comparison.
+ This is how we make all alphanumerics follow all else,
+ and ignore case in the first sorting. */
+int char_order[256];
+
+void
+init_char_order ()
+{
+ int i;
+ for (i = 1; i < 256; i++)
+ char_order[i] = i;
+
+ for (i = '0'; i <= '9'; i++)
+ char_order[i] += 512;
+
+ for (i = 'a'; i <= 'z'; i++)
+ {
+ char_order[i] = 512 + i;
+ char_order[i + 'A' - 'a'] = 512 + i;
+ }
+}
+
+/* Compare two fields (each specified as a start pointer and a character count)
+ according to KEYFIELD.
+ The sign of the value reports the relation between the fields. */
+
+int
+compare_field (keyfield, start1, length1, pos1, start2, length2, pos2)
+ struct keyfield *keyfield;
+ char *start1;
+ long length1;
+ long pos1;
+ char *start2;
+ long length2;
+ long pos2;
+{
+ if (keyfields->positional)
+ {
+ if (pos1 > pos2)
+ return 1;
+ else
+ return -1;
+ }
+ if (keyfield->numeric)
+ {
+ long value = find_value (start1, length1) - find_value (start2, length2);
+ if (value > 0)
+ return 1;
+ if (value < 0)
+ return -1;
+ return 0;
+ }
+ else
+ {
+ char *p1 = start1;
+ char *p2 = start2;
+ char *e1 = start1 + length1;
+ char *e2 = start2 + length2;
+
+ while (1)
+ {
+ int c1, c2;
+
+ if (p1 == e1)
+ c1 = 0;
+ else
+ c1 = *p1++;
+ if (p2 == e2)
+ c2 = 0;
+ else
+ c2 = *p2++;
+
+ if (char_order[c1] != char_order[c2])
+ return char_order[c1] - char_order[c2];
+ if (!c1)
+ break;
+ }
+
+ /* Strings are equal except possibly for case. */
+ p1 = start1;
+ p2 = start2;
+ while (1)
+ {
+ int c1, c2;
+
+ if (p1 == e1)
+ c1 = 0;
+ else
+ c1 = *p1++;
+ if (p2 == e2)
+ c2 = 0;
+ else
+ c2 = *p2++;
+
+ if (c1 != c2)
+ /* Reverse sign here so upper case comes out last. */
+ return c2 - c1;
+ if (!c1)
+ break;
+ }
+
+ return 0;
+ }
+}
+
+/* A `struct linebuffer' is a structure which holds a line of text.
+ `readline' reads a line from a stream into a linebuffer
+ and works regardless of the length of the line. */
+
+struct linebuffer
+{
+ long size;
+ char *buffer;
+};
+
+/* Initialize LINEBUFFER for use. */
+
+void
+initbuffer (linebuffer)
+ struct linebuffer *linebuffer;
+{
+ linebuffer->size = 200;
+ linebuffer->buffer = (char *) xmalloc (200);
+}
+
+/* Read a line of text from STREAM into LINEBUFFER.
+ Return the length of the line. */
+
+long
+readline (linebuffer, stream)
+ struct linebuffer *linebuffer;
+ FILE *stream;
+{
+ char *buffer = linebuffer->buffer;
+ char *p = linebuffer->buffer;
+ char *end = p + linebuffer->size;
+
+ while (1)
+ {
+ int c = getc (stream);
+ if (p == end)
+ {
+ buffer = (char *) xrealloc (buffer, linebuffer->size *= 2);
+ p += buffer - linebuffer->buffer;
+ end += buffer - linebuffer->buffer;
+ linebuffer->buffer = buffer;
+ }
+ if (c < 0 || c == '\n')
+ {
+ *p = 0;
+ break;
+ }
+ *p++ = c;
+ }
+
+ return p - buffer;
+}
+
+/* Sort an input file too big to sort in core. */
+
+void
+sort_offline (infile, nfiles, total, outfile)
+ char *infile;
+ int nfiles;
+ long total;
+ char *outfile;
+{
+ /* More than enough. */
+ int ntemps = 2 * (total + MAX_IN_CORE_SORT - 1) / MAX_IN_CORE_SORT;
+ char **tempfiles = (char **) xmalloc (ntemps * sizeof (char *));
+ FILE *istream = fopen (infile, "r");
+ int i;
+ struct linebuffer lb;
+ long linelength;
+ int failure = 0;
+
+ initbuffer (&lb);
+
+ /* Read in one line of input data. */
+
+ linelength = readline (&lb, istream);
+
+ if (lb.buffer[0] != '\\' && lb.buffer[0] != '@')
+ {
+ error ("%s: not a texinfo index file", infile);
+ return;
+ }
+
+ /* Split up the input into `ntemps' temporary files, or maybe fewer,
+ and put the new files' names into `tempfiles' */
+
+ for (i = 0; i < ntemps; i++)
+ {
+ char *outname = maketempname (++tempcount);
+ FILE *ostream = fopen (outname, "w");
+ long tempsize = 0;
+
+ if (!ostream)
+ pfatal_with_name (outname);
+ tempfiles[i] = outname;
+
+ /* Copy lines into this temp file as long as it does not make file
+ "too big" or until there are no more lines. */
+
+ while (tempsize + linelength + 1 <= MAX_IN_CORE_SORT)
+ {
+ tempsize += linelength + 1;
+ fputs (lb.buffer, ostream);
+ putc ('\n', ostream);
+
+ /* Read another line of input data. */
+
+ linelength = readline (&lb, istream);
+ if (!linelength && feof (istream))
+ break;
+
+ if (lb.buffer[0] != '\\' && lb.buffer[0] != '@')
+ {
+ error ("%s: not a texinfo index file", infile);
+ failure = 1;
+ goto fail;
+ }
+ }
+ fclose (ostream);
+ if (feof (istream))
+ break;
+ }
+
+ free (lb.buffer);
+
+fail:
+ /* Record number of temp files we actually needed. */
+
+ ntemps = i;
+
+ /* Sort each tempfile into another tempfile.
+ Delete the first set of tempfiles and put the names of the second
+ into `tempfiles'. */
+
+ for (i = 0; i < ntemps; i++)
+ {
+ char *newtemp = maketempname (++tempcount);
+ sort_in_core (&tempfiles[i], MAX_IN_CORE_SORT, newtemp);
+ if (!keep_tempfiles)
+ unlink (tempfiles[i]);
+ tempfiles[i] = newtemp;
+ }
+
+ if (failure)
+ return;
+
+ /* Merge the tempfiles together and indexify. */
+
+ merge_files (tempfiles, ntemps, outfile);
+}
+
+/* Sort INFILE, whose size is TOTAL,
+ assuming that is small enough to be done in-core,
+ then indexify it and send the output to OUTFILE (or to stdout). */
+
+void
+sort_in_core (infile, total, outfile)
+ char *infile;
+ long total;
+ char *outfile;
+{
+ char **nextline;
+ char *data = (char *) xmalloc (total + 1);
+ char *file_data;
+ long file_size;
+ int i;
+ FILE *ostream = stdout;
+ struct lineinfo *lineinfo;
+
+ /* Read the contents of the file into the moby array `data'. */
+
+ int desc = open (infile, O_RDONLY, 0);
+
+ if (desc < 0)
+ fatal ("failure reopening %s", infile);
+ for (file_size = 0;;)
+ {
+ i = read (desc, data + file_size, total - file_size);
+ if (i <= 0)
+ break;
+ file_size += i;
+ }
+ file_data = data;
+ data[file_size] = 0;
+
+ close (desc);
+
+ if (file_size > 0 && data[0] != '\\' && data[0] != '@')
+ {
+ error ("%s: not a texinfo index file", infile);
+ return;
+ }
+
+ init_char_order ();
+
+ /* Sort routines want to know this address. */
+
+ text_base = data;
+
+ /* Create the array of pointers to lines, with a default size
+ frequently enough. */
+
+ nlines = total / 50;
+ if (!nlines)
+ nlines = 2;
+ linearray = (char **) xmalloc (nlines * sizeof (char *));
+
+ /* `nextline' points to the next free slot in this array.
+ `nlines' is the allocated size. */
+
+ nextline = linearray;
+
+ /* Parse the input file's data, and make entries for the lines. */
+
+ nextline = parsefile (infile, nextline, file_data, file_size);
+ if (nextline == 0)
+ {
+ error ("%s: not a texinfo index file", infile);
+ return;
+ }
+
+ /* Sort the lines. */
+
+ /* If we have enough space, find the first keyfield of each line in advance.
+ Make a `struct lineinfo' for each line, which records the keyfield
+ as well as the line, and sort them. */
+
+ lineinfo = (struct lineinfo *) malloc ((nextline - linearray) * sizeof (struct lineinfo));
+
+ if (lineinfo)
+ {
+ struct lineinfo *lp;
+ char **p;
+
+ for (lp = lineinfo, p = linearray; p != nextline; lp++, p++)
+ {
+ lp->text = *p;
+ lp->key.text = find_field (keyfields, *p, &lp->keylen);
+ if (keyfields->numeric)
+ lp->key.number = find_value (lp->key.text, lp->keylen);
+ }
+
+ qsort (lineinfo, nextline - linearray, sizeof (struct lineinfo), compare_prepared);
+
+ for (lp = lineinfo, p = linearray; p != nextline; lp++, p++)
+ *p = lp->text;
+
+ free (lineinfo);
+ }
+ else
+ qsort (linearray, nextline - linearray, sizeof (char *), compare_full);
+
+ /* Open the output file. */
+
+ if (outfile)
+ {
+ ostream = fopen (outfile, "w");
+ if (!ostream)
+ pfatal_with_name (outfile);
+ }
+
+ writelines (linearray, nextline - linearray, ostream);
+ if (outfile)
+ fclose (ostream);
+
+ free (linearray);
+ free (data);
+}
+
+/* Parse an input string in core into lines.
+ DATA is the input string, and SIZE is its length.
+ Data goes in LINEARRAY starting at NEXTLINE.
+ The value returned is the first entry in LINEARRAY still unused.
+ Value 0 means input file contents are invalid. */
+
+char **
+parsefile (filename, nextline, data, size)
+ char *filename;
+ char **nextline;
+ char *data;
+ long size;
+{
+ char *p, *end;
+ char **line = nextline;
+
+ p = data;
+ end = p + size;
+ *end = 0;
+
+ while (p != end)
+ {
+ if (p[0] != '\\' && p[0] != '@')
+ return 0;
+
+ *line = p;
+ while (*p && *p != '\n')
+ p++;
+ if (p != end)
+ p++;
+
+ line++;
+ if (line == linearray + nlines)
+ {
+ char **old = linearray;
+ linearray = (char **) xrealloc (linearray, sizeof (char *) * (nlines *= 4));
+ line += linearray - old;
+ }
+ }
+
+ return line;
+}
+
+/* Indexification is a filter applied to the sorted lines
+ as they are being written to the output file.
+ Multiple entries for the same name, with different page numbers,
+ get combined into a single entry with multiple page numbers.
+ The first braced field, which is used for sorting, is discarded.
+ However, its first character is examined, folded to lower case,
+ and if it is different from that in the previous line fed to us
+ a \initial line is written with one argument, the new initial.
+
+ If an entry has four braced fields, then the second and third
+ constitute primary and secondary names.
+ In this case, each change of primary name
+ generates a \primary line which contains only the primary name,
+ and in between these are \secondary lines which contain
+ just a secondary name and page numbers. */
+
+/* The last primary name we wrote a \primary entry for.
+ If only one level of indexing is being done, this is the last name seen. */
+char *lastprimary;
+/* Length of storage allocated for lastprimary. */
+int lastprimarylength;
+
+/* Similar, for the secondary name. */
+char *lastsecondary;
+int lastsecondarylength;
+
+/* Zero if we are not in the middle of writing an entry.
+ One if we have written the beginning of an entry but have not
+ yet written any page numbers into it.
+ Greater than one if we have written the beginning of an entry
+ plus at least one page number. */
+int pending;
+
+/* The initial (for sorting purposes) of the last primary entry written.
+ When this changes, a \initial {c} line is written */
+
+char *lastinitial;
+
+int lastinitiallength;
+
+/* When we need a string of length 1 for the value of lastinitial,
+ store it here. */
+
+char lastinitial1[2];
+
+/* Initialize static storage for writing an index. */
+
+void
+init_index ()
+{
+ pending = 0;
+ lastinitial = lastinitial1;
+ lastinitial1[0] = 0;
+ lastinitial1[1] = 0;
+ lastinitiallength = 0;
+ lastprimarylength = 100;
+ lastprimary = (char *) xmalloc (lastprimarylength + 1);
+ bzero (lastprimary, lastprimarylength + 1);
+ lastsecondarylength = 100;
+ lastsecondary = (char *) xmalloc (lastsecondarylength + 1);
+ bzero (lastsecondary, lastsecondarylength + 1);
+}
+
+/* Indexify. Merge entries for the same name,
+ insert headers for each initial character, etc. */
+
+void
+indexify (line, ostream)
+ char *line;
+ FILE *ostream;
+{
+ char *primary, *secondary, *pagenumber;
+ int primarylength, secondarylength = 0, pagelength;
+ int nosecondary;
+ int initiallength;
+ char *initial;
+ char initial1[2];
+ register char *p;
+
+ /* First, analyze the parts of the entry fed to us this time. */
+
+ p = find_braced_pos (line, 0, 0, 0);
+ if (*p == '{')
+ {
+ initial = p;
+ /* Get length of inner pair of braces starting at `p',
+ including that inner pair of braces. */
+ initiallength = find_braced_end (p + 1) + 1 - p;
+ }
+ else
+ {
+ initial = initial1;
+ initial1[0] = *p;
+ initial1[1] = 0;
+ initiallength = 1;
+
+ if (initial1[0] >= 'a' && initial1[0] <= 'z')
+ initial1[0] -= 040;
+ }
+
+ pagenumber = find_braced_pos (line, 1, 0, 0);
+ pagelength = find_braced_end (pagenumber) - pagenumber;
+ if (pagelength == 0)
+ abort ();
+
+ primary = find_braced_pos (line, 2, 0, 0);
+ primarylength = find_braced_end (primary) - primary;
+
+ secondary = find_braced_pos (line, 3, 0, 0);
+ nosecondary = !*secondary;
+ if (!nosecondary)
+ secondarylength = find_braced_end (secondary) - secondary;
+
+ /* If the primary is different from before, make a new primary entry. */
+ if (strncmp (primary, lastprimary, primarylength))
+ {
+ /* Close off current secondary entry first, if one is open. */
+ if (pending)
+ {
+ fputs ("}\n", ostream);
+ pending = 0;
+ }
+
+ /* If this primary has a different initial, include an entry for
+ the initial. */
+ if (initiallength != lastinitiallength ||
+ strncmp (initial, lastinitial, initiallength))
+ {
+ fprintf (ostream, "\\initial {");
+ fwrite (initial, 1, initiallength, ostream);
+ fprintf (ostream, "}\n", initial);
+ if (initial == initial1)
+ {
+ lastinitial = lastinitial1;
+ *lastinitial1 = *initial1;
+ }
+ else
+ {
+ lastinitial = initial;
+ }
+ lastinitiallength = initiallength;
+ }
+
+ /* Make the entry for the primary. */
+ if (nosecondary)
+ fputs ("\\entry {", ostream);
+ else
+ fputs ("\\primary {", ostream);
+ fwrite (primary, primarylength, 1, ostream);
+ if (nosecondary)
+ {
+ fputs ("}{", ostream);
+ pending = 1;
+ }
+ else
+ fputs ("}\n", ostream);
+
+ /* Record name of most recent primary. */
+ if (lastprimarylength < primarylength)
+ {
+ lastprimarylength = primarylength + 100;
+ lastprimary = (char *) xrealloc (lastprimary,
+ 1 + lastprimarylength);
+ }
+ strncpy (lastprimary, primary, primarylength);
+ lastprimary[primarylength] = 0;
+
+ /* There is no current secondary within this primary, now. */
+ lastsecondary[0] = 0;
+ }
+
+ /* Should not have an entry with no subtopic following one with a subtopic. */
+
+ if (nosecondary && *lastsecondary)
+ error ("entry %s follows an entry with a secondary name", line);
+
+ /* Start a new secondary entry if necessary. */
+ if (!nosecondary && strncmp (secondary, lastsecondary, secondarylength))
+ {
+ if (pending)
+ {
+ fputs ("}\n", ostream);
+ pending = 0;
+ }
+
+ /* Write the entry for the secondary. */
+ fputs ("\\secondary {", ostream);
+ fwrite (secondary, secondarylength, 1, ostream);
+ fputs ("}{", ostream);
+ pending = 1;
+
+ /* Record name of most recent secondary. */
+ if (lastsecondarylength < secondarylength)
+ {
+ lastsecondarylength = secondarylength + 100;
+ lastsecondary = (char *) xrealloc (lastsecondary,
+ 1 + lastsecondarylength);
+ }
+ strncpy (lastsecondary, secondary, secondarylength);
+ lastsecondary[secondarylength] = 0;
+ }
+
+ /* Here to add one more page number to the current entry. */
+ if (pending++ != 1)
+ fputs (", ", ostream); /* Punctuate first, if this is not the first. */
+ fwrite (pagenumber, pagelength, 1, ostream);
+}
+
+/* Close out any unfinished output entry. */
+
+void
+finish_index (ostream)
+ FILE *ostream;
+{
+ if (pending)
+ fputs ("}\n", ostream);
+ free (lastprimary);
+ free (lastsecondary);
+}
+
+/* Copy the lines in the sorted order.
+ Each line is copied out of the input file it was found in. */
+
+void
+writelines (linearray, nlines, ostream)
+ char **linearray;
+ int nlines;
+ FILE *ostream;
+{
+ char **stop_line = linearray + nlines;
+ char **next_line;
+
+ init_index ();
+
+ /* Output the text of the lines, and free the buffer space. */
+
+ for (next_line = linearray; next_line != stop_line; next_line++)
+ {
+ /* If -u was specified, output the line only if distinct from previous one. */
+ if (next_line == linearray
+ /* Compare previous line with this one, using only the
+ explicitly specd keyfields. */
+ || compare_general (*(next_line - 1), *next_line, 0L, 0L, num_keyfields - 1))
+ {
+ char *p = *next_line;
+ char c;
+
+ while ((c = *p++) && c != '\n')
+ /* Do nothing. */ ;
+ *(p - 1) = 0;
+ indexify (*next_line, ostream);
+ }
+ }
+
+ finish_index (ostream);
+}
+
+/* Assume (and optionally verify) that each input file is sorted;
+ merge them and output the result.
+ Returns nonzero if any input file fails to be sorted.
+
+ This is the high-level interface that can handle an unlimited
+ number of files. */
+
+#define MAX_DIRECT_MERGE 10
+
+int
+merge_files (infiles, nfiles, outfile)
+ char **infiles;
+ int nfiles;
+ char *outfile;
+{
+ char **tempfiles;
+ int ntemps;
+ int i;
+ int value = 0;
+ int start_tempcount = tempcount;
+
+ if (nfiles <= MAX_DIRECT_MERGE)
+ return merge_direct (infiles, nfiles, outfile);
+
+ /* Merge groups of MAX_DIRECT_MERGE input files at a time,
+ making a temporary file to hold each group's result. */
+
+ ntemps = (nfiles + MAX_DIRECT_MERGE - 1) / MAX_DIRECT_MERGE;
+ tempfiles = (char **) xmalloc (ntemps * sizeof (char *));
+ for (i = 0; i < ntemps; i++)
+ {
+ int nf = MAX_DIRECT_MERGE;
+ if (i + 1 == ntemps)
+ nf = nfiles - i * MAX_DIRECT_MERGE;
+ tempfiles[i] = maketempname (++tempcount);
+ value |= merge_direct (&infiles[i * MAX_DIRECT_MERGE], nf, tempfiles[i]);
+ }
+
+ /* All temporary files that existed before are no longer needed
+ since their contents have been merged into our new tempfiles.
+ So delete them. */
+ flush_tempfiles (start_tempcount);
+
+ /* Now merge the temporary files we created. */
+
+ merge_files (tempfiles, ntemps, outfile);
+
+ free (tempfiles);
+
+ return value;
+}
+
+/* Assume (and optionally verify) that each input file is sorted;
+ merge them and output the result.
+ Returns nonzero if any input file fails to be sorted.
+
+ This version of merging will not work if the number of
+ input files gets too high. Higher level functions
+ use it only with a bounded number of input files. */
+
+int
+merge_direct (infiles, nfiles, outfile)
+ char **infiles;
+ int nfiles;
+ char *outfile;
+{
+ struct linebuffer *lb1, *lb2;
+ struct linebuffer **thisline, **prevline;
+ FILE **streams;
+ int i;
+ int nleft;
+ int lossage = 0;
+ int *file_lossage;
+ struct linebuffer *prev_out = 0;
+ FILE *ostream = stdout;
+
+ if (outfile)
+ {
+ ostream = fopen (outfile, "w");
+ }
+ if (!ostream)
+ pfatal_with_name (outfile);
+
+ init_index ();
+
+ if (nfiles == 0)
+ {
+ if (outfile)
+ fclose (ostream);
+ return 0;
+ }
+
+ /* For each file, make two line buffers.
+ Also, for each file, there is an element of `thisline'
+ which points at any time to one of the file's two buffers,
+ and an element of `prevline' which points to the other buffer.
+ `thisline' is supposed to point to the next available line from the file,
+ while `prevline' holds the last file line used,
+ which is remembered so that we can verify that the file is properly sorted. */
+
+ /* lb1 and lb2 contain one buffer each per file. */
+ lb1 = (struct linebuffer *) xmalloc (nfiles * sizeof (struct linebuffer));
+ lb2 = (struct linebuffer *) xmalloc (nfiles * sizeof (struct linebuffer));
+
+ /* thisline[i] points to the linebuffer holding the next available line in file i,
+ or is zero if there are no lines left in that file. */
+ thisline = (struct linebuffer **)
+ xmalloc (nfiles * sizeof (struct linebuffer *));
+ /* prevline[i] points to the linebuffer holding the last used line
+ from file i. This is just for verifying that file i is properly
+ sorted. */
+ prevline = (struct linebuffer **)
+ xmalloc (nfiles * sizeof (struct linebuffer *));
+ /* streams[i] holds the input stream for file i. */
+ streams = (FILE **) xmalloc (nfiles * sizeof (FILE *));
+ /* file_lossage[i] is nonzero if we already know file i is not
+ properly sorted. */
+ file_lossage = (int *) xmalloc (nfiles * sizeof (int));
+
+ /* Allocate and initialize all that storage. */
+
+ for (i = 0; i < nfiles; i++)
+ {
+ initbuffer (&lb1[i]);
+ initbuffer (&lb2[i]);
+ thisline[i] = &lb1[i];
+ prevline[i] = &lb2[i];
+ file_lossage[i] = 0;
+ streams[i] = fopen (infiles[i], "r");
+ if (!streams[i])
+ pfatal_with_name (infiles[i]);
+
+ readline (thisline[i], streams[i]);
+ }
+
+ /* Keep count of number of files not at eof. */
+ nleft = nfiles;
+
+ while (nleft)
+ {
+ struct linebuffer *best = 0;
+ struct linebuffer *exch;
+ int bestfile = -1;
+ int i;
+
+ /* Look at the next avail line of each file; choose the least one. */
+
+ for (i = 0; i < nfiles; i++)
+ {
+ if (thisline[i] &&
+ (!best ||
+ 0 < compare_general (best->buffer, thisline[i]->buffer,
+ (long) bestfile, (long) i, num_keyfields)))
+ {
+ best = thisline[i];
+ bestfile = i;
+ }
+ }
+
+ /* Output that line, unless it matches the previous one and we
+ don't want duplicates. */
+
+ if (!(prev_out &&
+ !compare_general (prev_out->buffer,
+ best->buffer, 0L, 1L, num_keyfields - 1)))
+ indexify (best->buffer, ostream);
+ prev_out = best;
+
+ /* Now make the line the previous of its file, and fetch a new
+ line from that file. */
+
+ exch = prevline[bestfile];
+ prevline[bestfile] = thisline[bestfile];
+ thisline[bestfile] = exch;
+
+ while (1)
+ {
+ /* If the file has no more, mark it empty. */
+
+ if (feof (streams[bestfile]))
+ {
+ thisline[bestfile] = 0;
+ /* Update the number of files still not empty. */
+ nleft--;
+ break;
+ }
+ readline (thisline[bestfile], streams[bestfile]);
+ if (thisline[bestfile]->buffer[0] || !feof (streams[bestfile]))
+ break;
+ }
+ }
+
+ finish_index (ostream);
+
+ /* Free all storage and close all input streams. */
+
+ for (i = 0; i < nfiles; i++)
+ {
+ fclose (streams[i]);
+ free (lb1[i].buffer);
+ free (lb2[i].buffer);
+ }
+ free (file_lossage);
+ free (lb1);
+ free (lb2);
+ free (thisline);
+ free (prevline);
+ free (streams);
+
+ if (outfile)
+ fclose (ostream);
+
+ return lossage;
+}
+
+/* Print error message and exit. */
+
+void
+fatal (s1, s2)
+ char *s1, *s2;
+{
+ error (s1, s2);
+ exit (TI_FATAL_ERROR);
+}
+
+/* Print error message. S1 is printf control string, S2 is arg for it. */
+
+void
+error (s1, s2)
+ char *s1, *s2;
+{
+ printf ("%s: ", program_name);
+ printf (s1, s2);
+ printf ("\n");
+}
+
+void
+perror_with_name (name)
+ char *name;
+{
+ char *s;
+
+ if (errno < sys_nerr)
+ s = concat ("", sys_errlist[errno], " for %s");
+ else
+ s = "cannot open %s";
+ error (s, name);
+}
+
+void
+pfatal_with_name (name)
+ char *name;
+{
+ char *s;
+
+ if (errno < sys_nerr)
+ s = concat ("", sys_errlist[errno], " for %s");
+ else
+ s = "cannot open %s";
+ fatal (s, name);
+}
+
+/* Return a newly-allocated string whose contents concatenate those of
+ S1, S2, S3. */
+
+char *
+concat (s1, s2, s3)
+ char *s1, *s2, *s3;
+{
+ int len1 = strlen (s1), len2 = strlen (s2), len3 = strlen (s3);
+ char *result = (char *) xmalloc (len1 + len2 + len3 + 1);
+
+ strcpy (result, s1);
+ strcpy (result + len1, s2);
+ strcpy (result + len1 + len2, s3);
+ *(result + len1 + len2 + len3) = 0;
+
+ return result;
+}
+
+/* Just like malloc, but kills the program in case of fatal error. */
+void *
+xmalloc (nbytes)
+ int nbytes;
+{
+ void *temp = (void *) malloc (nbytes);
+
+ if (nbytes && temp == (void *)NULL)
+ memory_error ("xmalloc", nbytes);
+
+ return (temp);
+}
+
+/* Like realloc (), but barfs if there isn't enough memory. */
+void *
+xrealloc (pointer, nbytes)
+ void *pointer;
+ int nbytes;
+{
+ void *temp;
+
+ if (!pointer)
+ temp = (void *)xmalloc (nbytes);
+ else
+ temp = (void *)realloc (pointer, nbytes);
+
+ if (nbytes && !temp)
+ memory_error ("xrealloc", nbytes);
+
+ return (temp);
+}
+
+memory_error (callers_name, bytes_wanted)
+ char *callers_name;
+ int bytes_wanted;
+{
+ char printable_string[80];
+
+ sprintf (printable_string,
+ "Virtual memory exhausted in %s ()! Needed %d bytes.",
+ callers_name, bytes_wanted);
+
+ error (printable_string);
+ abort ();
+}
+
+#ifndef STDC_HEADERS
+void
+bzero (b, length)
+ register char *b;
+ register int length;
+{
+#ifdef VMS
+ short zero = 0;
+ long max_str = 65535;
+
+ while (length > max_str)
+ {
+ (void) LIB$MOVC5 (&zero, &zero, &zero, &max_str, b);
+ length -= max_str;
+ b += max_str;
+ }
+ (void) LIB$MOVC5 (&zero, &zero, &zero, &length, b);
+#else
+ while (length-- > 0)
+ *b++ = 0;
+#endif /* not VMS */
+}
+#endif /* not STDC_HEADERS */
OpenPOWER on IntegriCloud